summary refs log tree commit diff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile5
-rw-r--r--drivers/acpi/blacklist.c381
-rw-r--r--drivers/acpi/bus.c13
-rw-r--r--drivers/acpi/ec.c26
-rw-r--r--drivers/acpi/fan.c40
-rw-r--r--drivers/acpi/osl.c173
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/processor_idle.c34
-rw-r--r--drivers/acpi/processor_throttling.c4
-rw-r--r--drivers/acpi/system.c13
-rw-r--r--drivers/ata/Kconfig9
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c72
-rw-r--r--drivers/ata/ata_generic.c51
-rw-r--r--drivers/ata/ata_piix.c393
-rw-r--r--drivers/ata/libata-acpi.c117
-rw-r--r--drivers/ata/libata-core.c809
-rw-r--r--drivers/ata/libata-eh.c299
-rw-r--r--drivers/ata/libata-scsi.c51
-rw-r--r--drivers/ata/libata-sff.c199
-rw-r--r--drivers/ata/libata.h6
-rw-r--r--drivers/ata/pata_acpi.c67
-rw-r--r--drivers/ata/pata_ali.c2
-rw-r--r--drivers/ata/pata_amd.c128
-rw-r--r--drivers/ata/pata_bf54x.c41
-rw-r--r--drivers/ata/pata_cs5520.c2
-rw-r--r--drivers/ata/pata_hpt37x.c7
-rw-r--r--drivers/ata/pata_icside.c3
-rw-r--r--drivers/ata/pata_it821x.c35
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c26
-rw-r--r--drivers/ata/pata_legacy.c912
-rw-r--r--drivers/ata/pata_mpc52xx.c2
-rw-r--r--drivers/ata/pata_ninja32.c214
-rw-r--r--drivers/ata/pata_pcmcia.c101
-rw-r--r--drivers/ata/pata_pdc2027x.c2
-rw-r--r--drivers/ata/pata_pdc202xx_old.c5
-rw-r--r--drivers/ata/pata_qdi.c30
-rw-r--r--drivers/ata/pata_scc.c30
-rw-r--r--drivers/ata/pata_serverworks.c9
-rw-r--r--drivers/ata/pata_via.c3
-rw-r--r--drivers/ata/pata_winbond.c30
-rw-r--r--drivers/ata/pdc_adma.c5
-rw-r--r--drivers/ata/sata_fsl.c5
-rw-r--r--drivers/ata/sata_inic162x.c2
-rw-r--r--drivers/ata/sata_mv.c3
-rw-r--r--drivers/ata/sata_nv.c25
-rw-r--r--drivers/ata/sata_promise.c98
-rw-r--r--drivers/ata/sata_promise.h2
-rw-r--r--drivers/ata/sata_qstor.c15
-rw-r--r--drivers/ata/sata_sil.c10
-rw-r--r--drivers/ata/sata_sil24.c30
-rw-r--r--drivers/ata/sata_sx4.c15
-rw-r--r--drivers/atm/ambassador.c3
-rw-r--r--drivers/atm/he.c14
-rw-r--r--drivers/base/Makefile3
-rw-r--r--drivers/base/attribute_container.c23
-rw-r--r--drivers/base/base.h64
-rw-r--r--drivers/base/bus.c540
-rw-r--r--drivers/base/class.c319
-rw-r--r--drivers/base/core.c596
-rw-r--r--drivers/base/cpu.c2
-rw-r--r--drivers/base/dd.c164
-rw-r--r--drivers/base/driver.c216
-rw-r--r--drivers/base/firmware.c26
-rw-r--r--drivers/base/hypervisor.c12
-rw-r--r--drivers/base/init.c10
-rw-r--r--drivers/base/memory.c2
-rw-r--r--drivers/base/module.c94
-rw-r--r--drivers/base/node.c2
-rw-r--r--drivers/base/platform.c239
-rw-r--r--drivers/base/power/Makefile9
-rw-r--r--drivers/base/power/main.c502
-rw-r--r--drivers/base/power/power.h19
-rw-r--r--drivers/base/power/shutdown.c48
-rw-r--r--drivers/base/sys.c49
-rw-r--r--drivers/block/DAC960.c11
-rw-r--r--drivers/block/Kconfig11
-rw-r--r--drivers/block/aoe/aoeblk.c51
-rw-r--r--drivers/block/aoe/aoechr.c7
-rw-r--r--drivers/block/cciss.c26
-rw-r--r--drivers/block/cpqarray.c36
-rw-r--r--drivers/block/floppy.c16
-rw-r--r--drivers/block/nbd.c23
-rw-r--r--drivers/block/paride/pg.c6
-rw-r--r--drivers/block/paride/pt.c12
-rw-r--r--drivers/block/pktcdvd.c27
-rw-r--r--drivers/block/ps3disk.c12
-rw-r--r--drivers/block/sunvdc.c11
-rw-r--r--drivers/block/sx8.c58
-rw-r--r--drivers/block/ub.c10
-rw-r--r--drivers/block/viodasd.c15
-rw-r--r--drivers/block/xen-blkfront.c10
-rw-r--r--drivers/block/xsysace.c9
-rw-r--r--drivers/cdrom/Makefile1
-rw-r--r--drivers/cdrom/gdrom.c867
-rw-r--r--drivers/cdrom/viocd.c15
-rw-r--r--drivers/char/Kconfig10
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/agp/ali-agp.c2
-rw-r--r--drivers/char/agp/backend.c3
-rw-r--r--drivers/char/agp/generic.c3
-rw-r--r--drivers/char/agp/i460-agp.c2
-rw-r--r--drivers/char/agp/intel-agp.c22
-rw-r--r--drivers/char/drm/drm_pciids.h1
-rw-r--r--drivers/char/hpet.c126
-rw-r--r--drivers/char/hvc_console.c80
-rw-r--r--drivers/char/hvcs.c78
-rw-r--r--drivers/char/hw_random/amd-rng.c12
-rw-r--r--drivers/char/hw_random/core.c24
-rw-r--r--drivers/char/hw_random/geode-rng.c12
-rw-r--r--drivers/char/hw_random/intel-rng.c15
-rw-r--r--drivers/char/hw_random/omap-rng.c13
-rw-r--r--drivers/char/hw_random/pasemi-rng.c16
-rw-r--r--drivers/char/hw_random/via-rng.c19
-rw-r--r--drivers/char/nozomi.c1993
-rw-r--r--drivers/char/rtc.c253
-rw-r--r--drivers/connector/cn_queue.c2
-rw-r--r--drivers/connector/connector.c40
-rw-r--r--drivers/cpufreq/cpufreq.c14
-rw-r--r--drivers/cpuidle/sysfs.c21
-rw-r--r--drivers/crypto/Kconfig80
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/geode-aes.c298
-rw-r--r--drivers/crypto/geode-aes.h44
-rw-r--r--drivers/crypto/hifn_795x.c2838
-rw-r--r--drivers/crypto/padlock-aes.c24
-rw-r--r--drivers/dma/dmaengine.c43
-rw-r--r--drivers/edac/edac_device_sysfs.c49
-rw-r--r--drivers/edac/edac_mc_sysfs.c40
-rw-r--r--drivers/edac/edac_module.c2
-rw-r--r--drivers/edac/edac_pci_sysfs.c35
-rw-r--r--drivers/firewire/fw-sbp2.c6
-rw-r--r--drivers/firmware/dmi-id.c2
-rw-r--r--drivers/firmware/dmi_scan.c34
-rw-r--r--drivers/firmware/edd.c25
-rw-r--r--drivers/firmware/efivars.c130
-rw-r--r--drivers/hid/Makefile2
-rw-r--r--drivers/hid/hid-core.c12
-rw-r--r--drivers/hid/hid-input-quirks.c423
-rw-r--r--drivers/hid/hid-input.c295
-rw-r--r--drivers/hid/usbhid/Kconfig5
-rw-r--r--drivers/hid/usbhid/hid-quirks.c118
-rw-r--r--drivers/hid/usbhid/hid-tmff.c7
-rw-r--r--drivers/hid/usbhid/usbkbd.c8
-rw-r--r--drivers/hid/usbhid/usbmouse.c8
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c226
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c85
-rw-r--r--drivers/i2c/busses/Kconfig35
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-amd756.c5
-rw-r--r--drivers/i2c/busses/i2c-au1550.c177
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c3
-rw-r--r--drivers/i2c/busses/i2c-davinci.c1
-rw-r--r--drivers/i2c/busses/i2c-i801.c163
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c191
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.h8
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c1
-rw-r--r--drivers/i2c/busses/i2c-ixp4xx.c178
-rw-r--r--drivers/i2c/busses/i2c-mpc.c29
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c32
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c1
-rw-r--r--drivers/i2c/busses/i2c-omap.c2
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c3
-rw-r--r--drivers/i2c/busses/i2c-piix4.c41
-rw-r--r--drivers/i2c/busses/i2c-pxa.c189
-rw-r--r--drivers/i2c/busses/i2c-sibyte.c29
-rw-r--r--drivers/i2c/busses/i2c-stub.c15
-rw-r--r--drivers/i2c/busses/i2c-viapro.c11
-rw-r--r--drivers/i2c/chips/Kconfig58
-rw-r--r--drivers/i2c/chips/Makefile4
-rw-r--r--drivers/i2c/chips/ds1337.c410
-rw-r--r--drivers/i2c/chips/ds1374.c267
-rw-r--r--drivers/i2c/chips/eeprom.c2
-rw-r--r--drivers/i2c/chips/isp1301_omap.c8
-rw-r--r--drivers/i2c/chips/m41t00.c413
-rw-r--r--drivers/i2c/chips/max6875.c2
-rw-r--r--drivers/i2c/chips/pcf8574.c8
-rw-r--r--drivers/i2c/chips/pcf8575.c214
-rw-r--r--drivers/i2c/chips/pcf8591.c2
-rw-r--r--drivers/i2c/chips/tps65010.c2
-rw-r--r--drivers/i2c/chips/tsl2550.c21
-rw-r--r--drivers/i2c/i2c-core.c352
-rw-r--r--drivers/i2c/i2c-dev.c29
-rw-r--r--drivers/ide/Kconfig58
-rw-r--r--drivers/ide/Makefile58
-rw-r--r--drivers/ide/arm/Makefile4
-rw-r--r--drivers/ide/arm/bast-ide.c2
-rw-r--r--drivers/ide/arm/icside.c25
-rw-r--r--drivers/ide/arm/ide_arm.c17
-rw-r--r--drivers/ide/arm/rapide.c33
-rw-r--r--drivers/ide/cris/Makefile2
-rw-r--r--drivers/ide/cris/ide-cris.c31
-rw-r--r--drivers/ide/h8300/Makefile2
-rw-r--r--drivers/ide/h8300/ide-h8300.c27
-rw-r--r--drivers/ide/ide-acpi.c16
-rw-r--r--drivers/ide/ide-cd.c67
-rw-r--r--drivers/ide/ide-disk.c435
-rw-r--r--drivers/ide/ide-dma.c128
-rw-r--r--drivers/ide/ide-floppy.c123
-rw-r--r--drivers/ide/ide-generic.c8
-rw-r--r--drivers/ide/ide-io.c364
-rw-r--r--drivers/ide/ide-iops.c77
-rw-r--r--drivers/ide/ide-lib.c228
-rw-r--r--drivers/ide/ide-pnp.c24
-rw-r--r--drivers/ide/ide-probe.c201
-rw-r--r--drivers/ide/ide-proc.c12
-rw-r--r--drivers/ide/ide-scan-pci.c121
-rw-r--r--drivers/ide/ide-tape.c143
-rw-r--r--drivers/ide/ide-taskfile.c621
-rw-r--r--drivers/ide/ide.c203
-rw-r--r--drivers/ide/legacy/Makefile19
-rw-r--r--drivers/ide/legacy/ali14xx.c5
-rw-r--r--drivers/ide/legacy/buddha.c44
-rw-r--r--drivers/ide/legacy/dtc2278.c5
-rw-r--r--drivers/ide/legacy/falconide.c22
-rw-r--r--drivers/ide/legacy/gayle.c43
-rw-r--r--drivers/ide/legacy/ht6560b.c5
-rw-r--r--drivers/ide/legacy/ide-cs.c2
-rw-r--r--drivers/ide/legacy/ide_platform.c55
-rw-r--r--drivers/ide/legacy/macide.c52
-rw-r--r--drivers/ide/legacy/q40ide.c24
-rw-r--r--drivers/ide/legacy/qd65xx.c5
-rw-r--r--drivers/ide/legacy/umc8672.c5
-rw-r--r--drivers/ide/mips/au1xxx-ide.c38
-rw-r--r--drivers/ide/mips/swarm.c1
-rw-r--r--drivers/ide/pci/Makefile4
-rw-r--r--drivers/ide/pci/aec62xx.c13
-rw-r--r--drivers/ide/pci/alim15x3.c3
-rw-r--r--drivers/ide/pci/amd74xx.c1
-rw-r--r--drivers/ide/pci/atiixp.c74
-rw-r--r--drivers/ide/pci/cmd640.c16
-rw-r--r--drivers/ide/pci/cmd64x.c124
-rw-r--r--drivers/ide/pci/cs5520.c20
-rw-r--r--drivers/ide/pci/cs5530.c2
-rw-r--r--drivers/ide/pci/cs5535.c2
-rw-r--r--drivers/ide/pci/cy82c693.c64
-rw-r--r--drivers/ide/pci/delkin_cb.c2
-rw-r--r--drivers/ide/pci/hpt34x.c12
-rw-r--r--drivers/ide/pci/hpt366.c203
-rw-r--r--drivers/ide/pci/it8213.c21
-rw-r--r--drivers/ide/pci/it821x.c37
-rw-r--r--drivers/ide/pci/pdc202xx_new.c75
-rw-r--r--drivers/ide/pci/pdc202xx_old.c35
-rw-r--r--drivers/ide/pci/piix.c17
-rw-r--r--drivers/ide/pci/sc1200.c178
-rw-r--r--drivers/ide/pci/scc_pata.c14
-rw-r--r--drivers/ide/pci/serverworks.c42
-rw-r--r--drivers/ide/pci/sgiioc4.c50
-rw-r--r--drivers/ide/pci/siimage.c44
-rw-r--r--drivers/ide/pci/sis5513.c99
-rw-r--r--drivers/ide/pci/sl82c105.c111
-rw-r--r--drivers/ide/pci/slc90e66.c14
-rw-r--r--drivers/ide/pci/tc86c001.c3
-rw-r--r--drivers/ide/pci/triflex.c2
-rw-r--r--drivers/ide/pci/trm290.c9
-rw-r--r--drivers/ide/pci/via82cxxx.c1
-rw-r--r--drivers/ide/ppc/Makefile3
-rw-r--r--drivers/ide/ppc/mpc8xx.c18
-rw-r--r--drivers/ide/ppc/pmac.c97
-rw-r--r--drivers/ide/setup-pci.c151
-rw-r--r--drivers/ieee1394/Makefile1
-rw-r--r--drivers/ieee1394/init_ohci1394_dma.c285
-rw-r--r--drivers/ieee1394/nodemgr.c314
-rw-r--r--drivers/ieee1394/sbp2.c6
-rw-r--r--drivers/infiniband/core/addr.c12
-rw-r--r--drivers/infiniband/core/cm.c306
-rw-r--r--drivers/infiniband/core/cma.c67
-rw-r--r--drivers/infiniband/core/fmr_pool.c33
-rw-r--r--drivers/infiniband/core/mad.c26
-rw-r--r--drivers/infiniband/core/mad_priv.h3
-rw-r--r--drivers/infiniband/core/mad_rmpp.c2
-rw-r--r--drivers/infiniband/core/multicast.c55
-rw-r--r--drivers/infiniband/core/smi.h18
-rw-r--r--drivers/infiniband/core/sysfs.c39
-rw-r--r--drivers/infiniband/core/ucm.c37
-rw-r--r--drivers/infiniband/core/ucma.c92
-rw-r--r--drivers/infiniband/core/user_mad.c115
-rw-r--r--drivers/infiniband/hw/cxgb3/Makefile3
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c4
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_wr.h5
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c6
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_mem.c7
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c7
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c29
-rw-r--r--drivers/infiniband/hw/ehca/ehca_av.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h23
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c38
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c28
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c180
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c112
-rw-r--r--drivers/infiniband/hw/ehca/ehca_sqp.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_common.h35
-rw-r--r--drivers/infiniband/hw/ipath/ipath_cq.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_debug.h4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c197
-rw-r--r--drivers/infiniband/hw/ipath/ipath_eeprom.c23
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c94
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c14
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c395
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6120.c439
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c67
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c81
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h204
-rw-r--r--drivers/infiniband/hw/ipath/ipath_keys.c5
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mad.c123
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c18
-rw-r--r--drivers/infiniband/hw/ipath/ipath_registers.h33
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c13
-rw-r--r--drivers/infiniband/hw/ipath/ipath_srq.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_stats.c24
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c390
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c55
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h12
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c9
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h13
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c6
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c40
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h184
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c376
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_fs.c4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c8
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c60
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c8
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c18
-rw-r--r--drivers/infiniband/ulp/iser/Kconfig4
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c16
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c6
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c8
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c130
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h5
-rw-r--r--drivers/input/misc/sparcspkr.c4
-rw-r--r--drivers/input/mouse/pc110pad.c7
-rw-r--r--drivers/input/touchscreen/corgi_ts.c8
-rw-r--r--drivers/isdn/capi/capi.c6
-rw-r--r--drivers/isdn/capi/capidrv.c9
-rw-r--r--drivers/isdn/gigaset/gigaset.h6
-rw-r--r--drivers/kvm/Kconfig54
-rw-r--r--drivers/kvm/Makefile10
-rw-r--r--drivers/kvm/i8259.c450
-rw-r--r--drivers/kvm/ioapic.c388
-rw-r--r--drivers/kvm/irq.c98
-rw-r--r--drivers/kvm/irq.h165
-rw-r--r--drivers/kvm/kvm.h796
-rw-r--r--drivers/kvm/kvm_main.c3628
-rw-r--r--drivers/kvm/kvm_svm.h45
-rw-r--r--drivers/kvm/lapic.c1080
-rw-r--r--drivers/kvm/mmu.c1498
-rw-r--r--drivers/kvm/paging_tmpl.h511
-rw-r--r--drivers/kvm/segment_descriptor.h17
-rw-r--r--drivers/kvm/svm.c1754
-rw-r--r--drivers/kvm/svm.h324
-rw-r--r--drivers/kvm/vmx.c2566
-rw-r--r--drivers/kvm/vmx.h310
-rw-r--r--drivers/kvm/x86_emulate.c1662
-rw-r--r--drivers/kvm/x86_emulate.h155
-rw-r--r--drivers/lguest/core.c46
-rw-r--r--drivers/lguest/hypercalls.c106
-rw-r--r--drivers/lguest/interrupts_and_traps.c149
-rw-r--r--drivers/lguest/lg.h154
-rw-r--r--drivers/lguest/lguest_user.c147
-rw-r--r--drivers/lguest/page_tables.c179
-rw-r--r--drivers/lguest/segments.c48
-rw-r--r--drivers/lguest/x86/core.c137
-rw-r--r--drivers/macintosh/adb.c2
-rw-r--r--drivers/macintosh/mediabay.c3
-rw-r--r--drivers/macintosh/therm_windtunnel.c5
-rw-r--r--drivers/macintosh/via-pmu.c2
-rw-r--r--drivers/md/dm.c4
-rw-r--r--drivers/md/md.c31
-rw-r--r--drivers/media/Kconfig22
-rw-r--r--drivers/media/common/Kconfig2
-rw-r--r--drivers/media/common/ir-functions.c3
-rw-r--r--drivers/media/common/ir-keymaps.c146
-rw-r--r--drivers/media/common/saa7146_fops.c9
-rw-r--r--drivers/media/common/saa7146_vbi.c10
-rw-r--r--drivers/media/common/saa7146_video.c8
-rw-r--r--drivers/media/dvb/b2c2/flexcop.c1
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c76
-rw-r--r--drivers/media/dvb/bt8xx/bt878.h6
-rw-r--r--drivers/media/dvb/bt8xx/dst.c19
-rw-r--r--drivers/media/dvb/bt8xx/dst_common.h5
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c6
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h43
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ringbuffer.c5
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.c7
-rw-r--r--drivers/media/dvb/dvb-usb/au6610.c6
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c436
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.h7
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c5
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c149
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c3
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.h3
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h18
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.c6
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.c16
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.h1
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.c6
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.h9
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.c15
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.h2
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c5
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.h5
-rw-r--r--drivers/media/dvb/frontends/Kconfig16
-rw-r--r--drivers/media/dvb/frontends/Makefile5
-rw-r--r--drivers/media/dvb/frontends/dib0070.c13
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c10
-rw-r--r--drivers/media/dvb/frontends/dib7000m.c9
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c18
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.h5
-rw-r--r--drivers/media/dvb/frontends/mt2266.c204
-rw-r--r--drivers/media/dvb/frontends/mt312.c257
-rw-r--r--drivers/media/dvb/frontends/mt312.h15
-rw-r--r--drivers/media/dvb/frontends/mt352.c8
-rw-r--r--drivers/media/dvb/frontends/or51132.c6
-rw-r--r--drivers/media/dvb/frontends/or51211.c6
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c97
-rw-r--r--drivers/media/dvb/frontends/s5h1409.h11
-rw-r--r--drivers/media/dvb/frontends/tda18271-common.c653
-rw-r--r--drivers/media/dvb/frontends/tda18271-fe.c1225
-rw-r--r--drivers/media/dvb/frontends/tda18271-priv.h212
-rw-r--r--drivers/media/dvb/frontends/tda18271-tables.c1285
-rw-r--r--drivers/media/dvb/frontends/tda18271.h78
-rw-r--r--drivers/media/dvb/frontends/tda827x.c367
-rw-r--r--drivers/media/dvb/frontends/tda827x.h7
-rw-r--r--drivers/media/dvb/frontends/ves1820.c4
-rw-r--r--drivers/media/dvb/frontends/xc5000.c964
-rw-r--r--drivers/media/dvb/frontends/xc5000.h62
-rw-r--r--drivers/media/dvb/frontends/xc5000_priv.h (renamed from drivers/i2c/busses/i2c-au1550.h)28
-rw-r--r--drivers/media/dvb/frontends/zl10353.c327
-rw-r--r--drivers/media/dvb/frontends/zl10353.h9
-rw-r--r--drivers/media/dvb/frontends/zl10353_priv.h23
-rw-r--r--drivers/media/dvb/ttpci/Kconfig37
-rw-r--r--drivers/media/dvb/ttpci/Makefile12
-rw-r--r--drivers/media/dvb/ttpci/av7110.c3
-rw-r--r--drivers/media/dvb/ttpci/av7110.h7
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c16
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.h3
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c4
-rw-r--r--drivers/media/radio/Kconfig10
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/dsbr100.c18
-rw-r--r--drivers/media/radio/radio-gemtek.c6
-rw-r--r--drivers/media/radio/radio-maestro.c2
-rw-r--r--drivers/media/radio/radio-sf16fmi.c2
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c3
-rw-r--r--drivers/media/radio/radio-si470x.c1432
-rw-r--r--drivers/media/video/Kconfig52
-rw-r--r--drivers/media/video/Makefile10
-rw-r--r--drivers/media/video/bt8xx/Kconfig2
-rw-r--r--drivers/media/video/bt8xx/Makefile2
-rw-r--r--drivers/media/video/bt8xx/bttv-audio-hook.c382
-rw-r--r--drivers/media/video/bt8xx/bttv-audio-hook.h23
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c444
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c2374
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c5
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c14
-rw-r--r--drivers/media/video/bt8xx/bttv-vbi.c58
-rw-r--r--drivers/media/video/bt8xx/bttv.h5
-rw-r--r--drivers/media/video/bt8xx/bttvp.h20
-rw-r--r--drivers/media/video/bw-qcam.c10
-rw-r--r--drivers/media/video/cs5345.c168
-rw-r--r--drivers/media/video/cs53l32a.c78
-rw-r--r--drivers/media/video/cx2341x.c313
-rw-r--r--drivers/media/video/cx23885/Kconfig4
-rw-r--r--drivers/media/video/cx23885/Makefile2
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c135
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c296
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c179
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c98
-rw-r--r--drivers/media/video/cx23885/cx23885-reg.h13
-rw-r--r--drivers/media/video/cx23885/cx23885-vbi.c258
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c1557
-rw-r--r--drivers/media/video/cx23885/cx23885.h168
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c123
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c695
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h1
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c5
-rw-r--r--drivers/media/video/cx25840/cx25840-vbi.c2
-rw-r--r--drivers/media/video/cx88/Kconfig1
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c2
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c92
-rw-r--r--drivers/media/video/cx88/cx88-cards.c120
-rw-r--r--drivers/media/video/cx88/cx88-core.c4
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c33
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c27
-rw-r--r--drivers/media/video/cx88/cx88-input.c6
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c39
-rw-r--r--drivers/media/video/cx88/cx88-vbi.c10
-rw-r--r--drivers/media/video/cx88/cx88-video.c58
-rw-r--r--drivers/media/video/cx88/cx88.h11
-rw-r--r--drivers/media/video/dpc7146.c19
-rw-r--r--drivers/media/video/em28xx/Kconfig17
-rw-r--r--drivers/media/video/em28xx/Makefile6
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c489
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c688
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c88
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c81
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c52
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c2622
-rw-r--r--drivers/media/video/em28xx/em28xx.h166
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c157
-rw-r--r--drivers/media/video/et61x251/et61x251_sensor.h8
-rw-r--r--drivers/media/video/ir-kbd-i2c.c3
-rw-r--r--drivers/media/video/ivtv/Kconfig2
-rw-r--r--drivers/media/video/ivtv/Makefile5
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c173
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h27
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c117
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h26
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c52
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c24
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c119
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.h1
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c127
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c95
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-routing.c25
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c25
-rw-r--r--drivers/media/video/ivtv/ivtv-version.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c1094
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.h12
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c6
-rw-r--r--drivers/media/video/ks0127.c1
-rw-r--r--drivers/media/video/m52790.c168
-rw-r--r--drivers/media/video/meye.c2
-rw-r--r--drivers/media/video/msp3400-driver.c238
-rw-r--r--drivers/media/video/msp3400-kthreads.c166
-rw-r--r--drivers/media/video/mt20xx.c2
-rw-r--r--drivers/media/video/mxb.c40
-rw-r--r--drivers/media/video/pvrusb2/Kconfig37
-rw-r--r--drivers/media/video/pvrusb2/Makefile2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-audio.c62
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.c55
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.h5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c97
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debug.h39
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c177
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c217
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.h119
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-eeprom.c1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c75
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.h1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h80
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c1301
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h144
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c10
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-main.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c7
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c60
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c7
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-video-v4l.c55
-rw-r--r--drivers/media/video/saa7115.c80
-rw-r--r--drivers/media/video/saa7127.c148
-rw-r--r--drivers/media/video/saa7134/Kconfig13
-rw-r--r--drivers/media/video/saa7134/Makefile1
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c16
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c614
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c35
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c19
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c293
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c15
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c63
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c1046
-rw-r--r--drivers/media/video/saa7134/saa7134-ts.c8
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c79
-rw-r--r--drivers/media/video/saa7134/saa7134-vbi.c8
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c1536
-rw-r--r--drivers/media/video/saa7134/saa7134.h34
-rw-r--r--drivers/media/video/sn9c102/Makefile1
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c4
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h2
-rw-r--r--drivers/media/video/sn9c102/sn9c102_mt9v111.c259
-rw-r--r--drivers/media/video/stk-sensor.c578
-rw-r--r--drivers/media/video/stk-webcam.c1465
-rw-r--r--drivers/media/video/stk-webcam.h138
-rw-r--r--drivers/media/video/tda7432.c232
-rw-r--r--drivers/media/video/tda8290.c901
-rw-r--r--drivers/media/video/tda8290.h31
-rw-r--r--drivers/media/video/tda9875.c167
-rw-r--r--drivers/media/video/tda9887.c305
-rw-r--r--drivers/media/video/tda9887.h38
-rw-r--r--drivers/media/video/tea5761.c2
-rw-r--r--drivers/media/video/tea5767.c92
-rw-r--r--drivers/media/video/tea5767.h19
-rw-r--r--drivers/media/video/tlv320aic23b.c134
-rw-r--r--drivers/media/video/tuner-core.c748
-rw-r--r--drivers/media/video/tuner-driver.h99
-rw-r--r--drivers/media/video/tuner-i2c.h57
-rw-r--r--drivers/media/video/tuner-simple.c17
-rw-r--r--drivers/media/video/tuner-types.c12
-rw-r--r--drivers/media/video/tuner-xc2028-types.h128
-rw-r--r--drivers/media/video/tuner-xc2028.c1213
-rw-r--r--drivers/media/video/tuner-xc2028.h63
-rw-r--r--drivers/media/video/tvaudio.c504
-rw-r--r--drivers/media/video/tveeprom.c504
-rw-r--r--drivers/media/video/upd64031a.c111
-rw-r--r--drivers/media/video/upd64083.c103
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.c18
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.h1
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c330
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c60
-rw-r--r--drivers/media/video/usbvision/usbvision.h8
-rw-r--r--drivers/media/video/v4l2-common.c32
-rw-r--r--drivers/media/video/v4l2-int-device.c6
-rw-r--r--drivers/media/video/videobuf-core.c357
-rw-r--r--drivers/media/video/videobuf-dma-sg.c23
-rw-r--r--drivers/media/video/videobuf-dvb.c2
-rw-r--r--drivers/media/video/videobuf-vmalloc.c2
-rw-r--r--drivers/media/video/videodev.c8
-rw-r--r--drivers/media/video/vino.c22
-rw-r--r--drivers/media/video/vivi.c706
-rw-r--r--drivers/media/video/vp27smpx.c113
-rw-r--r--drivers/media/video/wm8739.c137
-rw-r--r--drivers/media/video/wm8775.c140
-rw-r--r--drivers/media/video/zr364xx.c2
-rw-r--r--drivers/message/fusion/mptbase.c94
-rw-r--r--drivers/message/fusion/mptbase.h2
-rw-r--r--drivers/message/fusion/mptsas.c2
-rw-r--r--drivers/message/fusion/mptscsih.c2
-rw-r--r--drivers/message/i2o/i2o_block.c20
-rw-r--r--drivers/message/i2o/i2o_scsi.c2
-rw-r--r--drivers/mfd/ucb1x00-assabet.c17
-rw-r--r--drivers/mfd/ucb1x00-core.c14
-rw-r--r--drivers/mfd/ucb1x00.h4
-rw-r--r--drivers/misc/ibmasm/command.c12
-rw-r--r--drivers/misc/ibmasm/ibmasm.h10
-rw-r--r--drivers/misc/tifm_7xx1.c4
-rw-r--r--drivers/misc/tifm_core.c24
-rw-r--r--drivers/mmc/card/block.c24
-rw-r--r--drivers/mmc/card/queue.c4
-rw-r--r--drivers/mmc/host/omap.c2
-rw-r--r--drivers/mmc/host/pxamci.c61
-rw-r--r--drivers/mmc/host/pxamci.h2
-rw-r--r--drivers/mtd/mtdchar.c12
-rw-r--r--drivers/net/3c501.c232
-rw-r--r--drivers/net/3c507.c15
-rw-r--r--drivers/net/3c515.c2
-rw-r--r--drivers/net/7990.c8
-rw-r--r--drivers/net/Kconfig87
-rw-r--r--drivers/net/Makefile6
-rw-r--r--drivers/net/a2065.c10
-rw-r--r--drivers/net/amd8111e.c4
-rw-r--r--drivers/net/at1700.c5
-rw-r--r--drivers/net/b44.c36
-rw-r--r--drivers/net/bnx2.c1333
-rw-r--r--drivers/net/bnx2.h175
-rw-r--r--drivers/net/bnx2_fw.h7034
-rw-r--r--drivers/net/bnx2_fw2.h8416
-rw-r--r--drivers/net/bnx2x.c9064
-rw-r--r--drivers/net/bnx2x.h1071
-rw-r--r--drivers/net/bnx2x_fw_defs.h198
-rw-r--r--drivers/net/bnx2x_hsi.h2176
-rw-r--r--drivers/net/bnx2x_init.h564
-rw-r--r--drivers/net/bnx2x_init_values.h6368
-rw-r--r--drivers/net/bnx2x_reg.h4394
-rw-r--r--drivers/net/bonding/bond_main.c2
-rw-r--r--drivers/net/can/Kconfig25
-rw-r--r--drivers/net/can/Makefile5
-rw-r--r--drivers/net/can/vcan.c169
-rw-r--r--drivers/net/cassini.c4
-rw-r--r--drivers/net/chelsio/common.h2
-rw-r--r--drivers/net/chelsio/cxgb2.c4
-rw-r--r--drivers/net/chelsio/espi.c2
-rw-r--r--drivers/net/chelsio/espi.h1
-rw-r--r--drivers/net/chelsio/sge.c4
-rw-r--r--drivers/net/chelsio/sge.h2
-rw-r--r--drivers/net/chelsio/subr.c9
-rw-r--r--drivers/net/cpmac.c3
-rw-r--r--drivers/net/cxgb3/adapter.h1
-rw-r--r--drivers/net/cxgb3/common.h4
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c264
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c19
-rw-r--r--drivers/net/cxgb3/firmware_exports.h20
-rw-r--r--drivers/net/cxgb3/l2t.c2
-rw-r--r--drivers/net/cxgb3/regs.h270
-rw-r--r--drivers/net/cxgb3/sge.c124
-rw-r--r--drivers/net/cxgb3/t3_hw.c198
-rw-r--r--drivers/net/cxgb3/version.h4
-rw-r--r--drivers/net/cxgb3/xgmac.c10
-rw-r--r--drivers/net/declance.c6
-rw-r--r--drivers/net/dm9000.c3
-rw-r--r--drivers/net/e100.c204
-rw-r--r--drivers/net/e1000/e1000_ethtool.c86
-rw-r--r--drivers/net/e1000/e1000_hw.h88
-rw-r--r--drivers/net/e1000/e1000_main.c228
-rw-r--r--drivers/net/e1000e/82571.c11
-rw-r--r--drivers/net/e1000e/defines.h1
-rw-r--r--drivers/net/e1000e/e1000.h1
-rw-r--r--drivers/net/e1000e/ethtool.c89
-rw-r--r--drivers/net/e1000e/hw.h86
-rw-r--r--drivers/net/e1000e/lib.c39
-rw-r--r--drivers/net/e1000e/netdev.c61
-rw-r--r--drivers/net/e1000e/param.c7
-rw-r--r--drivers/net/e1000e/phy.c3
-rw-r--r--drivers/net/eepro100.c92
-rw-r--r--drivers/net/eexpress.c12
-rw-r--r--drivers/net/enc28j60.c1600
-rw-r--r--drivers/net/enc28j60_hw.h309
-rw-r--r--drivers/net/forcedeth.c46
-rw-r--r--drivers/net/gianfar_sysfs.c50
-rw-r--r--drivers/net/hamradio/6pack.c2
-rw-r--r--drivers/net/hamradio/mkiss.c2
-rw-r--r--drivers/net/hamradio/scc.c8
-rw-r--r--drivers/net/hp100.c2
-rw-r--r--drivers/net/ibm_newemac/core.c14
-rw-r--r--drivers/net/ibmlana.c192
-rw-r--r--drivers/net/ibmveth.c12
-rw-r--r--drivers/net/igb/Makefile37
-rw-r--r--drivers/net/igb/e1000_82575.c1269
-rw-r--r--drivers/net/igb/e1000_82575.h150
-rw-r--r--drivers/net/igb/e1000_defines.h772
-rw-r--r--drivers/net/igb/e1000_hw.h599
-rw-r--r--drivers/net/igb/e1000_mac.c1505
-rw-r--r--drivers/net/igb/e1000_mac.h98
-rw-r--r--drivers/net/igb/e1000_nvm.c605
-rw-r--r--drivers/net/igb/e1000_nvm.h40
-rw-r--r--drivers/net/igb/e1000_phy.c1807
-rw-r--r--drivers/net/igb/e1000_phy.h98
-rw-r--r--drivers/net/igb/e1000_regs.h270
-rw-r--r--drivers/net/igb/igb.h300
-rw-r--r--drivers/net/igb/igb_ethtool.c1927
-rw-r--r--drivers/net/igb/igb_main.c4138
-rw-r--r--drivers/net/ipg.c286
-rw-r--r--drivers/net/ipg.h99
-rw-r--r--drivers/net/irda/Kconfig141
-rw-r--r--drivers/net/irda/Makefile17
-rw-r--r--drivers/net/irda/act200l.c297
-rw-r--r--drivers/net/irda/actisys.c288
-rw-r--r--drivers/net/irda/ep7211_ir.c125
-rw-r--r--drivers/net/irda/esi.c149
-rw-r--r--drivers/net/irda/girbil.c250
-rw-r--r--drivers/net/irda/irport.c1123
-rw-r--r--drivers/net/irda/irport.h80
-rw-r--r--drivers/net/irda/litelink.c179
-rw-r--r--drivers/net/irda/ma600.c354
-rw-r--r--drivers/net/irda/mcp2120.c240
-rw-r--r--drivers/net/irda/old_belkin.c164
-rw-r--r--drivers/net/irda/smsc-ircc2.c17
-rw-r--r--drivers/net/irda/tekram.c282
-rw-r--r--drivers/net/irda/via-ircc.c12
-rw-r--r--drivers/net/iseries_veth.c19
-rw-r--r--drivers/net/ixgb/ixgb_hw.c82
-rw-r--r--drivers/net/ixgb/ixgb_hw.h25
-rw-r--r--drivers/net/ixgb/ixgb_ids.h4
-rw-r--r--drivers/net/ixgb/ixgb_main.c10
-rw-r--r--drivers/net/ixgbe/ixgbe.h8
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c156
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c12
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c3
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c29
-rw-r--r--drivers/net/ixgbe/ixgbe_phy.h1
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h65
-rw-r--r--drivers/net/loopback.c2
-rw-r--r--drivers/net/lp486e.c9
-rw-r--r--drivers/net/mac89x0.c2
-rw-r--r--drivers/net/mace.c10
-rw-r--r--drivers/net/macvlan.c28
-rw-r--r--drivers/net/mlx4/fw.c2
-rw-r--r--drivers/net/myri10ge/myri10ge.c16
-rw-r--r--drivers/net/netconsole.c10
-rw-r--r--drivers/net/netxen/netxen_nic.h34
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c28
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c57
-rw-r--r--drivers/net/netxen/netxen_nic_hw.h18
-rw-r--r--drivers/net/netxen/netxen_nic_init.c103
-rw-r--r--drivers/net/netxen/netxen_nic_isr.c15
-rw-r--r--drivers/net/netxen/netxen_nic_main.c43
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c64
-rw-r--r--drivers/net/netxen/netxen_nic_phan_reg.h15
-rw-r--r--drivers/net/niu.c8
-rw-r--r--drivers/net/ns83820.c12
-rw-r--r--drivers/net/pasemi_mac.c934
-rw-r--r--drivers/net/pasemi_mac.h365
-rw-r--r--drivers/net/pcmcia/axnet_cs.c16
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c7
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c4
-rw-r--r--drivers/net/pcnet32.c2
-rw-r--r--drivers/net/plip.c10
-rw-r--r--drivers/net/ppp_deflate.c4
-rw-r--r--drivers/net/ppp_generic.c2
-rw-r--r--drivers/net/ppp_synctty.c12
-rw-r--r--drivers/net/pppoe.c2
-rw-r--r--drivers/net/pppol2tp.c2
-rw-r--r--drivers/net/qla3xxx.c46
-rw-r--r--drivers/net/qla3xxx.h55
-rw-r--r--drivers/net/r6040.c1096
-rw-r--r--drivers/net/rrunner.c2
-rw-r--r--drivers/net/s2io-regs.h16
-rw-r--r--drivers/net/s2io.c536
-rw-r--r--drivers/net/s2io.h26
-rw-r--r--drivers/net/sgiseeq.c245
-rw-r--r--drivers/net/shaper.c603
-rw-r--r--drivers/net/sis190.c21
-rw-r--r--drivers/net/sis900.c6
-rw-r--r--drivers/net/sk98lin/skgemib.c2
-rw-r--r--drivers/net/sk98lin/skgepnmi.c14
-rw-r--r--drivers/net/sk98lin/skgesirq.c2
-rw-r--r--drivers/net/skfp/hwmtm.c4
-rw-r--r--drivers/net/skfp/smt.c2
-rw-r--r--drivers/net/sky2.c117
-rw-r--r--drivers/net/sky2.h13
-rw-r--r--drivers/net/slhc.c16
-rw-r--r--drivers/net/slip.c367
-rw-r--r--drivers/net/smc9194.c2
-rw-r--r--drivers/net/smc91x.c19
-rw-r--r--drivers/net/smc91x.h24
-rw-r--r--drivers/net/sundance.c26
-rw-r--r--drivers/net/sungem.c10
-rw-r--r--drivers/net/sungem.h8
-rw-r--r--drivers/net/sunhme.c51
-rw-r--r--drivers/net/sunhme.h12
-rw-r--r--drivers/net/sunvnet.c10
-rw-r--r--drivers/net/tehuti.c10
-rw-r--r--drivers/net/tg3.c400
-rw-r--r--drivers/net/tg3.h16
-rw-r--r--drivers/net/tokenring/olympic.c10
-rw-r--r--drivers/net/tokenring/olympic.h18
-rw-r--r--drivers/net/tokenring/smctr.c4
-rw-r--r--drivers/net/tulip/de4x5.c4
-rw-r--r--drivers/net/tulip/dmfe.c6
-rw-r--r--drivers/net/tun.c17
-rw-r--r--drivers/net/ucc_geth.c3
-rw-r--r--drivers/net/usb/dm9601.c53
-rw-r--r--drivers/net/via-rhine.c2
-rw-r--r--drivers/net/wan/cosa.c5
-rw-r--r--drivers/net/wan/farsync.c11
-rw-r--r--drivers/net/wan/hdlc_ppp.c2
-rw-r--r--drivers/net/wan/hdlc_raw_eth.c2
-rw-r--r--drivers/net/wan/lmc/lmc_main.c6
-rw-r--r--drivers/net/wan/lmc/lmc_media.c8
-rw-r--r--drivers/net/wan/lmc/lmc_proto.c2
-rw-r--r--drivers/net/wan/lmc/lmc_proto.h2
-rw-r--r--drivers/net/wan/pc300_drv.c8
-rw-r--r--drivers/net/wan/pc300_tty.c12
-rw-r--r--drivers/net/wan/sbni.c4
-rw-r--r--drivers/net/wan/sdla.c5
-rw-r--r--drivers/net/wan/wanxl.c4
-rw-r--r--drivers/net/wireless/Kconfig73
-rw-r--r--drivers/net/wireless/Makefile8
-rw-r--r--drivers/net/wireless/adm8211.c11
-rw-r--r--drivers/net/wireless/airo.c1243
-rw-r--r--drivers/net/wireless/ath5k/Makefile2
-rw-r--r--drivers/net/wireless/ath5k/ath5k.h1173
-rw-r--r--drivers/net/wireless/ath5k/base.c2974
-rw-r--r--drivers/net/wireless/ath5k/base.h179
-rw-r--r--drivers/net/wireless/ath5k/debug.c469
-rw-r--r--drivers/net/wireless/ath5k/debug.h216
-rw-r--r--drivers/net/wireless/ath5k/hw.c4351
-rw-r--r--drivers/net/wireless/ath5k/hw.h588
-rw-r--r--drivers/net/wireless/ath5k/initvals.c1347
-rw-r--r--drivers/net/wireless/ath5k/phy.c2071
-rw-r--r--drivers/net/wireless/ath5k/reg.h1987
-rw-r--r--drivers/net/wireless/ath5k/regdom.c121
-rw-r--r--drivers/net/wireless/ath5k/regdom.h500
-rw-r--r--drivers/net/wireless/atmel.c33
-rw-r--r--drivers/net/wireless/b43/Kconfig58
-rw-r--r--drivers/net/wireless/b43/Makefile12
-rw-r--r--drivers/net/wireless/b43/b43.h151
-rw-r--r--drivers/net/wireless/b43/debugfs.c9
-rw-r--r--drivers/net/wireless/b43/dma.c155
-rw-r--r--drivers/net/wireless/b43/dma.h50
-rw-r--r--drivers/net/wireless/b43/leds.c10
-rw-r--r--drivers/net/wireless/b43/lo.c72
-rw-r--r--drivers/net/wireless/b43/main.c1167
-rw-r--r--drivers/net/wireless/b43/main.h5
-rw-r--r--drivers/net/wireless/b43/nphy.c489
-rw-r--r--drivers/net/wireless/b43/nphy.h932
-rw-r--r--drivers/net/wireless/b43/phy.c1010
-rw-r--r--drivers/net/wireless/b43/phy.h103
-rw-r--r--drivers/net/wireless/b43/pio.c652
-rw-r--r--drivers/net/wireless/b43/pio.h153
-rw-r--r--drivers/net/wireless/b43/tables.c112
-rw-r--r--drivers/net/wireless/b43/tables.h12
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c2476
-rw-r--r--drivers/net/wireless/b43/tables_nphy.h159
-rw-r--r--drivers/net/wireless/b43/wa.c674
-rw-r--r--drivers/net/wireless/b43/wa.h7
-rw-r--r--drivers/net/wireless/b43/xmit.c201
-rw-r--r--drivers/net/wireless/b43/xmit.h200
-rw-r--r--drivers/net/wireless/b43legacy/Kconfig16
-rw-r--r--drivers/net/wireless/b43legacy/Makefile29
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h39
-rw-r--r--drivers/net/wireless/b43legacy/debugfs.c2
-rw-r--r--drivers/net/wireless/b43legacy/ilt.c2
-rw-r--r--drivers/net/wireless/b43legacy/leds.c417
-rw-r--r--drivers/net/wireless/b43legacy/leds.h61
-rw-r--r--drivers/net/wireless/b43legacy/main.c394
-rw-r--r--drivers/net/wireless/b43legacy/main.h2
-rw-r--r--drivers/net/wireless/b43legacy/phy.c75
-rw-r--r--drivers/net/wireless/b43legacy/phy.h16
-rw-r--r--drivers/net/wireless/b43legacy/radio.c36
-rw-r--r--drivers/net/wireless/b43legacy/radio.h4
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.c205
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.h59
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c32
-rw-r--r--drivers/net/wireless/bcm43xx/Kconfig9
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h6
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c40
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.c6
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.c6
-rw-r--r--drivers/net/wireless/hostap/hostap_80211.h34
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_rx.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c72
-rw-r--r--drivers/net/wireless/hostap/hostap_common.h34
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c15
-rw-r--r--drivers/net/wireless/hostap/hostap_download.c22
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c30
-rw-r--r--drivers/net/wireless/hostap/hostap_info.c9
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c69
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c6
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c16
-rw-r--r--drivers/net/wireless/hostap/hostap_wlan.h202
-rw-r--r--drivers/net/wireless/ipw2100.c13
-rw-r--r--drivers/net/wireless/ipw2200.c177
-rw-r--r--drivers/net/wireless/ipw2200.h190
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig180
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-commands.h (renamed from drivers/net/wireless/iwlwifi/iwl-commands.h)1014
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-debug.h (renamed from drivers/net/wireless/iwlwifi/iwl-debug.h)76
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h616
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-io.h431
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c348
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.h69
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c727
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h950
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-commands.h2651
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-debug.h152
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h2062
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-io.h431
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c1534
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.h121
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c1551
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.h1199
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-channel.h161
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h336
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hw.h537
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h470
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-priv.h308
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h61
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c3328
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c3914
-rw-r--r--drivers/net/wireless/iwlwifi/iwlwifi.h708
-rw-r--r--drivers/net/wireless/libertas/11d.c154
-rw-r--r--drivers/net/wireless/libertas/11d.h26
-rw-r--r--drivers/net/wireless/libertas/README40
-rw-r--r--drivers/net/wireless/libertas/assoc.c458
-rw-r--r--drivers/net/wireless/libertas/assoc.h32
-rw-r--r--drivers/net/wireless/libertas/cmd.c1407
-rw-r--r--drivers/net/wireless/libertas/cmd.h61
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c662
-rw-r--r--drivers/net/wireless/libertas/debugfs.c1495
-rw-r--r--drivers/net/wireless/libertas/debugfs.h12
-rw-r--r--drivers/net/wireless/libertas/decl.h102
-rw-r--r--drivers/net/wireless/libertas/defs.h67
-rw-r--r--drivers/net/wireless/libertas/dev.h179
-rw-r--r--drivers/net/wireless/libertas/ethtool.c114
-rw-r--r--drivers/net/wireless/libertas/host.h392
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h147
-rw-r--r--drivers/net/wireless/libertas/if_cs.c88
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c88
-rw-r--r--drivers/net/wireless/libertas/if_sdio.h4
-rw-r--r--drivers/net/wireless/libertas/if_usb.c729
-rw-r--r--drivers/net/wireless/libertas/if_usb.h109
-rw-r--r--drivers/net/wireless/libertas/join.c313
-rw-r--r--drivers/net/wireless/libertas/join.h38
-rw-r--r--drivers/net/wireless/libertas/main.c1438
-rw-r--r--drivers/net/wireless/libertas/rx.c226
-rw-r--r--drivers/net/wireless/libertas/scan.c1192
-rw-r--r--drivers/net/wireless/libertas/scan.h94
-rw-r--r--drivers/net/wireless/libertas/tx.c253
-rw-r--r--drivers/net/wireless/libertas/types.h25
-rw-r--r--drivers/net/wireless/libertas/wext.c867
-rw-r--r--drivers/net/wireless/libertas/wext.h14
-rw-r--r--drivers/net/wireless/orinoco.c544
-rw-r--r--drivers/net/wireless/orinoco.h12
-rw-r--r--drivers/net/wireless/p54common.c14
-rw-r--r--drivers/net/wireless/p54pci.c93
-rw-r--r--drivers/net/wireless/p54pci.h4
-rw-r--r--drivers/net/wireless/prism54/isl_38xx.h10
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c16
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.h3
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.h38
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.c4
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.h2
-rw-r--r--drivers/net/wireless/ray_cs.c69
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c271
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h24
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c225
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c239
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h17
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h241
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c100
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c231
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c435
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dump.h121
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c5
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c87
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c104
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00rfkill.c39
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00ring.h50
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c156
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h24
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c495
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h14
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c270
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h14
-rw-r--r--drivers/net/wireless/rtl8180.h151
-rw-r--r--drivers/net/wireless/rtl8180_dev.c1051
-rw-r--r--drivers/net/wireless/rtl8180_grf5101.c179
-rw-r--r--drivers/net/wireless/rtl8180_grf5101.h28
-rw-r--r--drivers/net/wireless/rtl8180_max2820.c150
-rw-r--r--drivers/net/wireless/rtl8180_max2820.h28
-rw-r--r--drivers/net/wireless/rtl8180_rtl8225.c779
-rw-r--r--drivers/net/wireless/rtl8180_rtl8225.h23
-rw-r--r--drivers/net/wireless/rtl8180_sa2400.c201
-rw-r--r--drivers/net/wireless/rtl8180_sa2400.h36
-rw-r--r--drivers/net/wireless/rtl8187.h4
-rw-r--r--drivers/net/wireless/rtl8187_dev.c69
-rw-r--r--drivers/net/wireless/rtl8187_rtl8225.c52
-rw-r--r--drivers/net/wireless/rtl8187_rtl8225.h9
-rw-r--r--drivers/net/wireless/rtl818x.h29
-rw-r--r--drivers/net/wireless/wavelan.c36
-rw-r--r--drivers/net/wireless/wavelan.p.h1
-rw-r--r--drivers/net/wireless/wavelan_cs.c43
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h3
-rw-r--r--drivers/net/wireless/zd1211rw/Kconfig7
-rw-r--r--drivers/net/wireless/zd1211rw/Makefile3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c126
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h60
-rw-r--r--drivers/net/wireless/zd1211rw/zd_def.h5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.c196
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.h49
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c1559
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h117
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.c264
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.h45
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.c5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al2230.c5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al7230b.c5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_rf2959.c5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_uw2453.c7
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c289
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h36
-rw-r--r--drivers/net/xen-netfront.c2
-rw-r--r--drivers/parisc/led.c2
-rw-r--r--drivers/parisc/pdc_stable.c194
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c4
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c39
-rw-r--r--drivers/pci/hotplug/rpadlpar_sysfs.c113
-rw-r--r--drivers/pci/pci-driver.c59
-rw-r--r--drivers/pci/probe.c11
-rw-r--r--drivers/pcmcia/ds.c3
-rw-r--r--drivers/pcmcia/pxa2xx_base.c1
-rw-r--r--drivers/pnp/pnpbios/bioscalls.c5
-rw-r--r--drivers/power/apm_power.c116
-rw-r--r--drivers/power/power_supply_core.c74
-rw-r--r--drivers/rapidio/rio.h4
-rw-r--r--drivers/rtc/Kconfig2
-rw-r--r--drivers/rtc/interface.c22
-rw-r--r--drivers/rtc/rtc-ds1672.c2
-rw-r--r--drivers/rtc/rtc-isl1208.c2
-rw-r--r--drivers/rtc/rtc-max6900.c2
-rw-r--r--drivers/rtc/rtc-pcf8563.c2
-rw-r--r--drivers/rtc/rtc-pcf8583.c2
-rw-r--r--drivers/rtc/rtc-sa1100.c31
-rw-r--r--drivers/rtc/rtc-sh.c24
-rw-r--r--drivers/rtc/rtc-x1205.c2
-rw-r--r--drivers/s390/block/Makefile4
-rw-r--r--drivers/s390/block/dasd.c1693
-rw-r--r--drivers/s390/block/dasd_3370_erp.c84
-rw-r--r--drivers/s390/block/dasd_3990_erp.c360
-rw-r--r--drivers/s390/block/dasd_9336_erp.c41
-rw-r--r--drivers/s390/block/dasd_9343_erp.c21
-rw-r--r--drivers/s390/block/dasd_alias.c903
-rw-r--r--drivers/s390/block/dasd_devmap.c94
-rw-r--r--drivers/s390/block/dasd_diag.c107
-rw-r--r--drivers/s390/block/dasd_eckd.c789
-rw-r--r--drivers/s390/block/dasd_eckd.h125
-rw-r--r--drivers/s390/block/dasd_eer.c11
-rw-r--r--drivers/s390/block/dasd_erp.c25
-rw-r--r--drivers/s390/block/dasd_fba.c119
-rw-r--r--drivers/s390/block/dasd_genhd.c76
-rw-r--r--drivers/s390/block/dasd_int.h209
-rw-r--r--drivers/s390/block/dasd_ioctl.c172
-rw-r--r--drivers/s390/block/dasd_proc.c23
-rw-r--r--drivers/s390/block/dcssblk.c2
-rw-r--r--drivers/s390/char/Makefile2
-rw-r--r--drivers/s390/char/monwriter.c2
-rw-r--r--drivers/s390/char/raw3270.c4
-rw-r--r--drivers/s390/char/sclp.h4
-rw-r--r--drivers/s390/char/sclp_chp.c200
-rw-r--r--drivers/s390/char/sclp_cmd.c398
-rw-r--r--drivers/s390/char/sclp_config.c4
-rw-r--r--drivers/s390/char/sclp_cpi.c246
-rw-r--r--drivers/s390/char/sclp_cpi_sys.c400
-rw-r--r--drivers/s390/char/sclp_cpi_sys.h15
-rw-r--r--drivers/s390/char/sclp_info.c116
-rw-r--r--drivers/s390/char/sclp_rw.c2
-rw-r--r--drivers/s390/char/tape_3590.c2
-rw-r--r--drivers/s390/char/tape_block.c13
-rw-r--r--drivers/s390/char/tape_core.c2
-rw-r--r--drivers/s390/char/tape_proc.c2
-rw-r--r--drivers/s390/char/vmlogrdr.c2
-rw-r--r--drivers/s390/char/vmur.c2
-rw-r--r--drivers/s390/char/zcore.c2
-rw-r--r--drivers/s390/cio/airq.c171
-rw-r--r--drivers/s390/cio/airq.h10
-rw-r--r--drivers/s390/cio/blacklist.c2
-rw-r--r--drivers/s390/cio/ccwgroup.c25
-rw-r--r--drivers/s390/cio/chsc.c121
-rw-r--r--drivers/s390/cio/cio.c106
-rw-r--r--drivers/s390/cio/cio.h89
-rw-r--r--drivers/s390/cio/cio_debug.h22
-rw-r--r--drivers/s390/cio/css.c198
-rw-r--r--drivers/s390/cio/css.h78
-rw-r--r--drivers/s390/cio/device.c157
-rw-r--r--drivers/s390/cio/device.h5
-rw-r--r--drivers/s390/cio/device_fsm.c124
-rw-r--r--drivers/s390/cio/device_id.c9
-rw-r--r--drivers/s390/cio/device_ops.c2
-rw-r--r--drivers/s390/cio/device_pgid.c6
-rw-r--r--drivers/s390/cio/device_status.c13
-rw-r--r--drivers/s390/cio/io_sch.h163
-rw-r--r--drivers/s390/cio/ioasm.h66
-rw-r--r--drivers/s390/cio/qdio.c38
-rw-r--r--drivers/s390/cio/qdio.h2
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/s390/net/lcs.c2
-rw-r--r--drivers/s390/net/netiucv.c19
-rw-r--r--drivers/s390/net/qeth_main.c6
-rw-r--r--drivers/s390/net/qeth_proc.c4
-rw-r--r--drivers/s390/net/smsgiucv.c2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c2
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c17
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c6
-rw-r--r--drivers/s390/scsi/zfcp_def.h22
-rw-r--r--drivers/s390/scsi/zfcp_erp.c16
-rw-r--r--drivers/s390/scsi/zfcp_ext.h3
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c84
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c2
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c24
-rw-r--r--drivers/s390/scsi/zfcp_sysfs_driver.c27
-rw-r--r--drivers/scsi/.gitignore2
-rw-r--r--drivers/scsi/3w-9xxx.c2
-rw-r--r--drivers/scsi/3w-xxxx.c1
-rw-r--r--drivers/scsi/53c700.c11
-rw-r--r--drivers/scsi/BusLogic.c3
-rw-r--r--drivers/scsi/Kconfig34
-rw-r--r--drivers/scsi/Makefile5
-rw-r--r--drivers/scsi/NCR5380.c23
-rw-r--r--drivers/scsi/NCR53c406a.c1
-rw-r--r--drivers/scsi/a100u2w.c1
-rw-r--r--drivers/scsi/a2091.c36
-rw-r--r--drivers/scsi/a3000.c15
-rw-r--r--drivers/scsi/aacraid/aachba.c400
-rw-r--r--drivers/scsi/aacraid/aacraid.h335
-rw-r--r--drivers/scsi/aacraid/commctrl.c89
-rw-r--r--drivers/scsi/aacraid/comminit.c4
-rw-r--r--drivers/scsi/aacraid/commsup.c394
-rw-r--r--drivers/scsi/aacraid/dpcsup.c10
-rw-r--r--drivers/scsi/aacraid/linit.c243
-rw-r--r--drivers/scsi/aacraid/rx.c6
-rw-r--r--drivers/scsi/advansys.c14
-rw-r--r--drivers/scsi/aha152x.c38
-rw-r--r--drivers/scsi/aha1542.c49
-rw-r--r--drivers/scsi/aha1740.c3
-rw-r--r--drivers/scsi/aic7xxx/Makefile45
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h5
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c9
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm_pci.c33
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h4
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c3
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c16
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm_pci.c33
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_pci.c2
-rw-r--r--drivers/scsi/aic7xxx_old.c12
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dev.c6
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dump.c4
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.h3
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c190
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c6
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sds.c389
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sds.h121
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c50
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c12
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c7
-rw-r--r--drivers/scsi/atari_NCR5380.c24
-rw-r--r--drivers/scsi/atp870u.c102
-rw-r--r--drivers/scsi/ch.c215
-rw-r--r--drivers/scsi/constants.c3
-rw-r--r--drivers/scsi/dc395x.c17
-rw-r--r--drivers/scsi/dpt_i2o.c6
-rw-r--r--drivers/scsi/eata.c5
-rw-r--r--drivers/scsi/eata_pio.c13
-rw-r--r--drivers/scsi/fd_mcs.c36
-rw-r--r--drivers/scsi/gdth.c22
-rw-r--r--drivers/scsi/hosts.c29
-rw-r--r--drivers/scsi/hptiop.c596
-rw-r--r--drivers/scsi/hptiop.h124
-rw-r--r--drivers/scsi/ibmmca.c1
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c156
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c2
-rw-r--r--drivers/scsi/ide-scsi.c83
-rw-r--r--drivers/scsi/imm.c13
-rw-r--r--drivers/scsi/in2000.c10
-rw-r--r--drivers/scsi/initio.c9
-rw-r--r--drivers/scsi/ipr.c11
-rw-r--r--drivers/scsi/ips.c326
-rw-r--r--drivers/scsi/ips.h32
-rw-r--r--drivers/scsi/iscsi_tcp.c2074
-rw-r--r--drivers/scsi/iscsi_tcp.h134
-rw-r--r--drivers/scsi/libiscsi.c1091
-rw-r--r--drivers/scsi/libsas/Kconfig9
-rw-r--r--drivers/scsi/libsas/Makefile4
-rw-r--r--drivers/scsi/libsas/sas_ata.c16
-rw-r--r--drivers/scsi/libsas/sas_discover.c2
-rw-r--r--drivers/scsi/libsas/sas_expander.c35
-rw-r--r--drivers/scsi/libsas/sas_host_smp.c274
-rw-r--r--drivers/scsi/libsas/sas_internal.h16
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c11
-rw-r--r--drivers/scsi/libsas/sas_task.c36
-rw-r--r--drivers/scsi/libsrp.c27
-rw-r--r--drivers/scsi/lpfc/lpfc.h53
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c217
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h33
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c304
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c157
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c623
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c372
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h112
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c429
-rw-r--r--drivers/scsi/lpfc/lpfc_logmsg.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c32
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c1
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c160
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c56
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c534
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h12
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c93
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.h2
-rw-r--r--drivers/scsi/mac53c94.c1
-rw-r--r--drivers/scsi/megaraid.c3
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c7
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c573
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h18
-rw-r--r--drivers/scsi/mesh.c1
-rw-r--r--drivers/scsi/ncr53c8xx.c5
-rw-r--r--drivers/scsi/nsp32.c1
-rw-r--r--drivers/scsi/pcmcia/Kconfig3
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c54
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c1
-rw-r--r--drivers/scsi/ppa.c12
-rw-r--r--drivers/scsi/psi240i.c689
-rw-r--r--drivers/scsi/psi240i.h315
-rw-r--r--drivers/scsi/psi_chip.h195
-rw-r--r--drivers/scsi/qla1280.c5
-rw-r--r--drivers/scsi/qla2xxx/Makefile2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c54
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c37
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h19
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h52
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c175
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h30
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h51
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c97
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c120
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c430
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c46
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c82
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c18
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c4
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c11
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c22
-rw-r--r--drivers/scsi/qlogicfas.c1
-rw-r--r--drivers/scsi/qlogicpti.c31
-rw-r--r--drivers/scsi/scsi.c284
-rw-r--r--drivers/scsi/scsi_debug.c199
-rw-r--r--drivers/scsi/scsi_devinfo.c34
-rw-r--r--drivers/scsi/scsi_error.c162
-rw-r--r--drivers/scsi/scsi_ioctl.c26
-rw-r--r--drivers/scsi/scsi_lib.c536
-rw-r--r--drivers/scsi/scsi_netlink.c21
-rw-r--r--drivers/scsi/scsi_proc.c110
-rw-r--r--drivers/scsi/scsi_scan.c36
-rw-r--r--drivers/scsi/scsi_sysfs.c1
-rw-r--r--drivers/scsi/scsi_tgt_if.c2
-rw-r--r--drivers/scsi/scsi_tgt_lib.c45
-rw-r--r--drivers/scsi/scsi_transport_fc.c102
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c332
-rw-r--r--drivers/scsi/scsi_transport_sas.c41
-rw-r--r--drivers/scsi/scsi_transport_spi.c258
-rw-r--r--drivers/scsi/scsi_transport_srp.c13
-rw-r--r--drivers/scsi/scsicam.c35
-rw-r--r--drivers/scsi/sd.c48
-rw-r--r--drivers/scsi/seagate.c1667
-rw-r--r--drivers/scsi/sg.c36
-rw-r--r--drivers/scsi/sgiwd93.c65
-rw-r--r--drivers/scsi/sr.c60
-rw-r--r--drivers/scsi/sr.h4
-rw-r--r--drivers/scsi/sr_ioctl.c48
-rw-r--r--drivers/scsi/st.c9
-rw-r--r--drivers/scsi/stex.c1
-rw-r--r--drivers/scsi/sun3_NCR5380.c24
-rw-r--r--drivers/scsi/sym53c416.c17
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c23
-rw-r--r--drivers/scsi/tmscsim.c6
-rw-r--r--drivers/scsi/u14-34f.c5
-rw-r--r--drivers/scsi/ultrastor.c16
-rw-r--r--drivers/scsi/wd33c93.c10
-rw-r--r--drivers/scsi/wd7000.c13
-rw-r--r--drivers/serial/21285.c2
-rw-r--r--drivers/serial/bfin_5xx.c6
-rw-r--r--drivers/serial/icom.c24
-rw-r--r--drivers/serial/icom.h2
-rw-r--r--drivers/serial/sh-sci.c6
-rw-r--r--drivers/serial/sh-sci.h48
-rw-r--r--drivers/spi/Kconfig1
-rw-r--r--drivers/spi/omap2_mcspi.c6
-rw-r--r--drivers/spi/pxa2xx_spi.c139
-rw-r--r--drivers/spi/spi.c26
-rw-r--r--drivers/ssb/b43_pci_bridge.c2
-rw-r--r--drivers/ssb/main.c10
-rw-r--r--drivers/ssb/pci.c276
-rw-r--r--drivers/ssb/pcmcia.c71
-rw-r--r--drivers/uio/uio.c95
-rw-r--r--drivers/usb/Kconfig1
-rw-r--r--drivers/usb/core/driver.c8
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/host/ohci-hcd.c2
-rw-r--r--drivers/usb/host/ohci-omap.c2
-rw-r--r--drivers/usb/host/ohci-pnx4008.c5
-rw-r--r--drivers/usb/host/ohci-pxa27x.c13
-rw-r--r--drivers/usb/storage/freecom.c14
-rw-r--r--drivers/usb/storage/isd200.c66
-rw-r--r--drivers/usb/storage/protocol.c126
-rw-r--r--drivers/usb/storage/scsiglue.c24
-rw-r--r--drivers/usb/storage/sddr09.c9
-rw-r--r--drivers/usb/storage/shuttle_usbat.c68
-rw-r--r--drivers/usb/storage/transport.c45
-rw-r--r--drivers/usb/storage/transport.h2
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/atmel_lcdfb.c2
-rw-r--r--drivers/video/bf54x-lq043fb.c6
-rw-r--r--drivers/video/console/Kconfig2
-rw-r--r--drivers/video/matrox/matroxfb_maven.c2
-rw-r--r--drivers/video/omap/lcd_h3.c2
-rw-r--r--drivers/video/vermilion/vermilion.c15
-rw-r--r--drivers/w1/masters/ds2482.c2
-rw-r--r--drivers/watchdog/Kconfig10
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/alim1535_wdt.c20
-rw-r--r--drivers/watchdog/alim7101_wdt.c18
-rw-r--r--drivers/watchdog/ar7_wdt.c2
-rw-r--r--drivers/watchdog/bfin_wdt.c2
-rw-r--r--drivers/watchdog/it8712f_wdt.c2
-rw-r--r--drivers/watchdog/mpc5200_wdt.c2
-rw-r--r--drivers/watchdog/mtx-1_wdt.c2
-rw-r--r--drivers/watchdog/sbc60xxwdt.c18
-rw-r--r--drivers/watchdog/scx200_wdt.c10
-rw-r--r--drivers/watchdog/txx9wdt.c276
-rw-r--r--drivers/watchdog/w83877f_wdt.c18
-rw-r--r--drivers/watchdog/w83977f_wdt.c18
-rw-r--r--drivers/watchdog/wdt.c30
-rw-r--r--drivers/watchdog/wdt977.c18
1384 files changed, 169659 insertions, 87900 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index f4076d9e9902..08d4ae201597 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -90,8 +90,6 @@ source "drivers/dca/Kconfig"
 
 source "drivers/auxdisplay/Kconfig"
 
-source "drivers/kvm/Kconfig"
-
 source "drivers/uio/Kconfig"
 
 source "drivers/virtio/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 8cb37e3557d4..0ee9a8a4095e 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -38,7 +38,7 @@ obj-$(CONFIG_SCSI)		+= scsi/
 obj-$(CONFIG_ATA)		+= ata/
 obj-$(CONFIG_FUSION)		+= message/
 obj-$(CONFIG_FIREWIRE)		+= firewire/
-obj-$(CONFIG_IEEE1394)		+= ieee1394/
+obj-y				+= ieee1394/
 obj-$(CONFIG_UIO)		+= uio/
 obj-y				+= cdrom/
 obj-y				+= auxdisplay/
@@ -47,7 +47,6 @@ obj-$(CONFIG_SPI)		+= spi/
 obj-$(CONFIG_PCCARD)		+= pcmcia/
 obj-$(CONFIG_DIO)		+= dio/
 obj-$(CONFIG_SBUS)		+= sbus/
-obj-$(CONFIG_KVM)		+= kvm/
 obj-$(CONFIG_ZORRO)		+= zorro/
 obj-$(CONFIG_MAC)		+= macintosh/
 obj-$(CONFIG_ATA_OVER_ETH)	+= block/aoe/
@@ -73,7 +72,7 @@ obj-$(CONFIG_ISDN)		+= isdn/
 obj-$(CONFIG_EDAC)		+= edac/
 obj-$(CONFIG_MCA)		+= mca/
 obj-$(CONFIG_EISA)		+= eisa/
-obj-$(CONFIG_LGUEST_GUEST)	+= lguest/
+obj-y				+= lguest/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_CPU_IDLE)		+= cpuidle/
 obj-$(CONFIG_MMC)		+= mmc/
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 3ec110ce00c8..8809654d6cc9 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -3,6 +3,7 @@
  *
  *  Check to see if the given machine has a known bad ACPI BIOS
  *  or if the BIOS is too old.
+ *  Check given machine against acpi_osi_dmi_table[].
  *
  *  Copyright (C) 2004 Len Brown <len.brown@intel.com>
  *  Copyright (C) 2002 Andy Grover <andrew.grover@intel.com>
@@ -50,6 +51,8 @@ struct acpi_blacklist_item {
 	u32 is_critical_error;
 };
 
+static struct dmi_system_id acpi_osi_dmi_table[] __initdata;
+
 /*
  * POLICY: If *anything* doesn't work, put it on the blacklist.
  *	   If they are critical errors, mark it critical, and abort driver load.
@@ -165,5 +168,383 @@ int __init acpi_blacklisted(void)
 
 	blacklisted += blacklist_by_year();
 
+	dmi_check_system(acpi_osi_dmi_table);
+
 	return blacklisted;
 }
+#ifdef CONFIG_DMI
+static int __init dmi_enable_osi_linux(const struct dmi_system_id *d)
+{
+	acpi_dmi_osi_linux(1, d);	/* enable */
+	return 0;
+}
+static int __init dmi_disable_osi_linux(const struct dmi_system_id *d)
+{
+	acpi_dmi_osi_linux(0, d);	/* disable */
+	return 0;
+}
+static int __init dmi_unknown_osi_linux(const struct dmi_system_id *d)
+{
+	acpi_dmi_osi_linux(-1, d);	/* unknown */
+	return 0;
+}
+
+/*
+ * Most BIOS that invoke OSI(Linux) do nothing with it.
+ * But some cause Linux to break.
+ * Only a couple use it to make Linux run better.
+ *
+ * Thus, Linux should continue to disable OSI(Linux) by default,
+ * should continue to discourage BIOS writers from using it, and
+ * should whitelist the few existing systems that require it.
+ *
+ * If it appears clear a vendor isn't using OSI(Linux)
+ * for anything constructive, blacklist them by name to disable
+ * unnecessary dmesg warnings on all of their products.
+ */
+
+static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
+	/*
+	 * Disable OSI(Linux) warnings on all "Acer, inc."
+	 *
+	 * _OSI(Linux) disables the latest Windows BIOS code:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"),
+	 * _OSI(Linux) effect unknown:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"),
+	 */
+	{
+	.callback = dmi_disable_osi_linux,
+	.ident = "Acer, inc.",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Acer, inc."),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "Acer"
+	 *
+	 * _OSI(Linux) effect unknown:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
+	 */
+	{
+	.callback = dmi_unknown_osi_linux,
+	.ident = "Acer",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "Apple Computer, Inc."
+	 *
+	 * _OSI(Linux) confirmed to be a NOP:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
+	 * _OSI(Linux) effect unknown:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
+	 */
+	{
+	.callback = dmi_disable_osi_linux,
+	.ident = "Apple",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "BenQ"
+	 *
+	 * _OSI(Linux) confirmed to be a NOP:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Joybook S31"),
+	 */
+	{
+	.callback = dmi_disable_osi_linux,
+	.ident = "BenQ",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "BenQ"),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "Clevo Co."
+	 *
+	 * _OSI(Linux) confirmed to be a NOP:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "M570RU"),
+	 */
+	{
+	.callback = dmi_disable_osi_linux,
+	.ident = "Clevo",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Clevo Co."),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "COMPAL"
+	 *
+	 * _OSI(Linux) confirmed to be a NOP:
+	 * DMI_MATCH(DMI_BOARD_NAME, "HEL8X"),
+	 * _OSI(Linux) unknown effect:
+	 * DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
+	 */
+	{
+	.callback = dmi_unknown_osi_linux,
+	.ident = "Compal",
+	.matches = {
+		     DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
+		},
+	},
+	{ /* OSI(Linux) touches USB, breaks suspend to disk */
+	.callback = dmi_disable_osi_linux,
+	.ident = "Dell Dimension 5150",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM051"),
+		},
+	},
+	{ /* OSI(Linux) is a NOP */
+	.callback = dmi_disable_osi_linux,
+	.ident = "Dell",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"),
+		},
+	},
+	{ /* OSI(Linux) effect unknown */
+	.callback = dmi_unknown_osi_linux,
+	.ident = "Dell",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"),
+		},
+	},
+	{ /* OSI(Linux) effect unknown */
+	.callback = dmi_unknown_osi_linux,
+	.ident = "Dell",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"),
+		},
+	},
+	{ /* OSI(Linux) effect unknown */
+	.callback = dmi_unknown_osi_linux,
+	.ident = "Dell",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"),
+		},
+	},
+	{ /* OSI(Linux) touches USB */
+	.callback = dmi_disable_osi_linux,
+	.ident = "Dell",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"),
+		},
+	},
+	{ /* OSI(Linux) is a NOP */
+	.callback = dmi_disable_osi_linux,
+	.ident = "Dell Vostro 1000",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "Vostro   1000"),
+		},
+	},
+	{ /* OSI(Linux) effect unknown */
+	.callback = dmi_unknown_osi_linux,
+	.ident = "Dell",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"),
+		},
+	},
+	{ /* OSI(Linux) effect unknown */
+	.callback = dmi_unknown_osi_linux,
+	.ident = "Dialogue Flybook V5",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Dialogue Technology Corporation"),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "Flybook V5"),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "FUJITSU SIEMENS"
+	 *
+	 * _OSI(Linux) disables latest Windows BIOS code:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2510"),
+	 * _OSI(Linux) confirmed to be a NOP:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1536"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1556"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 1546"),
+	 * _OSI(Linux) unknown effect:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo M1425"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo Si 1520"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),
+	 */
+	{
+	.callback = dmi_disable_osi_linux,
+	.ident = "Fujitsu Siemens",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "Hewlett-Packard"
+	 *
+	 * _OSI(Linux) confirmed to be a NOP:
+	 * .ident = "HP Pavilion tx 1000"
+	 * DMI_MATCH(DMI_BOARD_NAME, "30BF"),
+	 * .ident = "HP Pavilion dv2000"
+	 * DMI_MATCH(DMI_BOARD_NAME, "30B5"),
+	 * .ident = "HP Pavilion dv5000",
+	 * DMI_MATCH(DMI_BOARD_NAME, "30A7"),
+	 * .ident = "HP Pavilion dv6300 30BC",
+	 * DMI_MATCH(DMI_BOARD_NAME, "30BC"),
+	 * .ident = "HP Pavilion dv6000",
+	 * DMI_MATCH(DMI_BOARD_NAME, "30B7"),
+	 * DMI_MATCH(DMI_BOARD_NAME, "30B8"),
+	 * .ident = "HP Pavilion dv9000",
+	 * DMI_MATCH(DMI_BOARD_NAME, "30B9"),
+	 * .ident = "HP Pavilion dv9500",
+	 * DMI_MATCH(DMI_BOARD_NAME, "30CB"),
+	 * .ident = "HP/Compaq Presario C500",
+	 * DMI_MATCH(DMI_BOARD_NAME, "30C6"),
+	 * .ident = "HP/Compaq Presario F500",
+	 * DMI_MATCH(DMI_BOARD_NAME, "30D3"),
+	 * _OSI(Linux) unknown effect:
+	 * .ident = "HP Pavilion dv6500",
+	 * DMI_MATCH(DMI_BOARD_NAME, "30D0"),
+	 */
+	{
+	.callback = dmi_disable_osi_linux,
+	.ident = "Hewlett-Packard",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+		},
+	},
+	/*
+	 * Lenovo has a mix of systems OSI(Linux) situations
+	 * and thus we can not wildcard the vendor.
+	 *
+	 * _OSI(Linux) helps sound
+	 * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
+	 * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
+	 * _OSI(Linux) is a NOP:
+	 * DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
+	 */
+	{
+	.callback = dmi_enable_osi_linux,
+	.ident = "Lenovo ThinkPad R61",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"),
+		},
+	},
+	{
+	.callback = dmi_enable_osi_linux,
+	.ident = "Lenovo ThinkPad T61",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"),
+		},
+	},
+	{
+	.callback = dmi_unknown_osi_linux,
+	.ident = "Lenovo 3000 V100",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "LENOVO3000 V100"),
+		},
+	},
+	{
+	.callback = dmi_disable_osi_linux,
+	.ident = "Lenovo 3000 N100",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+		     DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "LG Electronics"
+	 *
+	 * _OSI(Linux) confirmed to be a NOP:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"),
+	 */
+	{
+	.callback = dmi_disable_osi_linux,
+	.ident = "LG",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
+		},
+	},
+	/* NEC - OSI(Linux) effect unknown */
+	{
+	.callback = dmi_unknown_osi_linux,
+	.ident = "NEC VERSA M360",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "NEC Computers SAS"),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "NEC VERSA M360"),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "Samsung Electronics"
+	 *
+	 * OSI(Linux) disables PNP0C32 and other BIOS code for Windows:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "R40P/R41P"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "R59P/R60P/R61P"),
+	 */
+	{
+	.callback = dmi_disable_osi_linux,
+	.ident = "Samsung",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "Sony Corporation"
+	 *
+	 * _OSI(Linux) is a NOP:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ650N"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ38GP_C"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-TZ21MN_N"),
+	 * _OSI(Linux) unknown effect:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"),
+	 */
+	{
+	.callback = dmi_unknown_osi_linux,
+	.ident = "Sony",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+		},
+	},
+	/*
+	 * Disable OSI(Linux) warnings on all "TOSHIBA"
+	 *
+	 * _OSI(Linux) breaks sound (bugzilla 7787):
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P100"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P105"),
+	 * _OSI(Linux) is a NOP:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A100"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A210"),
+	 * _OSI(Linux) unknown effect:
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A135"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A200"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P205"),
+	 * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U305"),
+	 */
+	{
+	.callback = dmi_disable_osi_linux,
+	.ident = "Toshiba",
+	.matches = {
+		     DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+		},
+	},
+	{}
+};
+
+#endif /* CONFIG_DMI */
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index d7a115c362d1..1b4cf984b081 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -200,7 +200,7 @@ int acpi_bus_set_power(acpi_handle handle, int state)
 	 * Get device's current power state
 	 */
 	acpi_bus_get_power(device->handle, &device->power.state);
-	if (state == device->power.state) {
+	if ((state == device->power.state) && !device->flags.force_power_state) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
 				  state));
 		return 0;
@@ -743,7 +743,7 @@ static int __init acpi_bus_init(void)
 	return -ENODEV;
 }
 
-decl_subsys(acpi, NULL, NULL);
+struct kobject *acpi_kobj;
 
 static int __init acpi_init(void)
 {
@@ -755,10 +755,11 @@ static int __init acpi_init(void)
 		return -ENODEV;
 	}
 
-	result = firmware_register(&acpi_subsys);
-	if (result < 0)
-		printk(KERN_WARNING "%s: firmware_register error: %d\n",
-			__FUNCTION__, result);
+	acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
+	if (!acpi_kobj) {
+		printk(KERN_WARNING "%s: kset create error\n", __FUNCTION__);
+		acpi_kobj = NULL;
+	}
 
 	result = acpi_bus_init();
 
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 97dc16155a55..987b967c7467 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -26,6 +26,9 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
+/* Uncomment next line to get verbose print outs*/
+/* #define DEBUG */
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -47,9 +50,6 @@
 #undef PREFIX
 #define PREFIX				"ACPI: EC: "
 
-/* Uncomment next line to get verbose print outs*/
-/* #define DEBUG */
-
 /* EC status register */
 #define ACPI_EC_FLAG_OBF	0x01	/* Output buffer full */
 #define ACPI_EC_FLAG_IBF	0x02	/* Input buffer full */
@@ -82,6 +82,7 @@ enum {
 	EC_FLAGS_ADDRESS,		/* Address is being written */
 	EC_FLAGS_NO_WDATA_GPE,		/* Don't expect WDATA GPE event */
 	EC_FLAGS_WDATA,			/* Data is being written */
+	EC_FLAGS_NO_OBF1_GPE,		/* Don't expect GPE before read */
 };
 
 static int acpi_ec_remove(struct acpi_device *device, int type);
@@ -138,26 +139,26 @@ static struct acpi_ec {
 static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
 {
 	u8 x = inb(ec->command_addr);
-	pr_debug(PREFIX "---> status = 0x%2x\n", x);
+	pr_debug(PREFIX "---> status = 0x%2.2x\n", x);
 	return x;
 }
 
 static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
 {
 	u8 x = inb(ec->data_addr);
-	pr_debug(PREFIX "---> data = 0x%2x\n", x);
+	pr_debug(PREFIX "---> data = 0x%2.2x\n", x);
 	return inb(ec->data_addr);
 }
 
 static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
 {
-	pr_debug(PREFIX "<--- command = 0x%2x\n", command);
+	pr_debug(PREFIX "<--- command = 0x%2.2x\n", command);
 	outb(command, ec->command_addr);
 }
 
 static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
 {
-	pr_debug(PREFIX "<--- data = 0x%2x\n", data);
+	pr_debug(PREFIX "<--- data = 0x%2.2x\n", data);
 	outb(data, ec->data_addr);
 }
 
@@ -179,6 +180,10 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
 static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
 {
 	int ret = 0;
+
+	if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
+		     test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
+		force_poll = 1;
 	if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
 		     test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
 		force_poll = 1;
@@ -192,7 +197,12 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
 			goto end;
 		clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
 		if (acpi_ec_check_status(ec, event)) {
-			if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
+			if (event == ACPI_EC_EVENT_OBF_1) {
+				/* miss OBF_1 GPE, don't expect it */
+				pr_info(PREFIX "missing OBF confirmation, "
+					"don't expect it any longer.\n");
+				set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags);
+			} else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
 				/* miss address GPE, don't expect it anymore */
 				pr_info(PREFIX "missing address confirmation, "
 					"don't expect it any longer.\n");
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index a5a5532db268..a6e149d692cb 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -47,6 +47,8 @@ MODULE_LICENSE("GPL");
 
 static int acpi_fan_add(struct acpi_device *device);
 static int acpi_fan_remove(struct acpi_device *device, int type);
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
+static int acpi_fan_resume(struct acpi_device *device);
 
 static const struct acpi_device_id fan_device_ids[] = {
 	{"PNP0C0B", 0},
@@ -61,6 +63,8 @@ static struct acpi_driver acpi_fan_driver = {
 	.ops = {
 		.add = acpi_fan_add,
 		.remove = acpi_fan_remove,
+		.suspend = acpi_fan_suspend,
+		.resume = acpi_fan_resume,
 		},
 };
 
@@ -191,6 +195,10 @@ static int acpi_fan_add(struct acpi_device *device)
 		goto end;
 	}
 
+	device->flags.force_power_state = 1;
+	acpi_bus_set_power(device->handle, state);
+	device->flags.force_power_state = 0;
+
 	result = acpi_fan_add_fs(device);
 	if (result)
 		goto end;
@@ -216,6 +224,38 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
 	return 0;
 }
 
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
+{
+	if (!device)
+		return -EINVAL;
+
+	acpi_bus_set_power(device->handle, ACPI_STATE_D0);
+
+	return AE_OK;
+}
+
+static int acpi_fan_resume(struct acpi_device *device)
+{
+	int result = 0;
+	int power_state = 0;
+
+	if (!device)
+		return -EINVAL;
+
+	result = acpi_bus_get_power(device->handle, &power_state);
+	if (result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				  "Error reading fan power state\n"));
+		return result;
+	}
+
+	device->flags.force_power_state = 1;
+	acpi_bus_set_power(device->handle, power_state);
+	device->flags.force_power_state = 0;
+
+	return result;
+}
+
 static int __init acpi_fan_init(void)
 {
 	int result = 0;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index e3a673a00845..e53fb516f9d4 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -77,11 +77,55 @@ static struct workqueue_struct *kacpi_notify_wq;
 #define	OSI_STRING_LENGTH_MAX 64	/* arbitrary */
 static char osi_additional_string[OSI_STRING_LENGTH_MAX];
 
-static int osi_linux;		/* disable _OSI(Linux) by default */
+/*
+ * "Ode to _OSI(Linux)"
+ *
+ * osi_linux -- Control response to BIOS _OSI(Linux) query.
+ *
+ * As Linux evolves, the features that it supports change.
+ * So an OSI string such as "Linux" is not specific enough
+ * to be useful across multiple versions of Linux.  It
+ * doesn't identify any particular feature, interface,
+ * or even any particular version of Linux...
+ *
+ * Unfortunately, Linux-2.6.22 and earlier responded "yes"
+ * to a BIOS _OSI(Linux) query.  When
+ * a reference mobile BIOS started using it, its use
+ * started to spread to many vendor platforms.
+ * As it is not supportable, we need to halt that spread.
+ *
+ * Today, most BIOS references to _OSI(Linux) are noise --
+ * they have no functional effect and are just dead code
+ * carried over from the reference BIOS.
+ *
+ * The next most common case is that _OSI(Linux) harms Linux,
+ * usually by causing the BIOS to follow paths that are
+ * not tested during Windows validation.
+ *
+ * Finally, there is a short list of platforms
+ * where OSI(Linux) benefits Linux.
+ *
+ * In Linux-2.6.23, OSI(Linux) is first disabled by default.
+ * DMI is used to disable the dmesg warning about OSI(Linux)
+ * on platforms where it is known to have no effect.
+ * But a dmesg warning remains for systems where
+ * we do not know if OSI(Linux) is good or bad for the system.
+ * DMI is also used to enable OSI(Linux) for the machines
+ * that are known to need it.
+ *
+ * BIOS writers should NOT query _OSI(Linux) on future systems.
+ * It will be ignored by default, and to get Linux to
+ * not ignore it will require a kernel source update to
+ * add a DMI entry, or a boot-time "acpi_osi=Linux" invocation.
+ */
+#define OSI_LINUX_ENABLE 0
 
-#ifdef CONFIG_DMI
-static struct __initdata dmi_system_id acpi_osl_dmi_table[];
-#endif
+struct osi_linux {
+	unsigned int	enable:1;
+	unsigned int	dmi:1;
+	unsigned int	cmdline:1;
+	unsigned int	known:1;
+} osi_linux = { OSI_LINUX_ENABLE, 0, 0, 0};
 
 static void __init acpi_request_region (struct acpi_generic_address *addr,
 	unsigned int length, char *desc)
@@ -133,7 +177,6 @@ device_initcall(acpi_reserve_resources);
 
 acpi_status __init acpi_os_initialize(void)
 {
-	dmi_check_system(acpi_osl_dmi_table);
 	return AE_OK;
 }
 
@@ -964,13 +1007,37 @@ static int __init acpi_os_name_setup(char *str)
 
 __setup("acpi_os_name=", acpi_os_name_setup);
 
-static void enable_osi_linux(int enable) {
+static void __init set_osi_linux(unsigned int enable)
+{
+	if (osi_linux.enable != enable) {
+		osi_linux.enable = enable;
+		printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
+			enable ? "Add": "Delet");
+	}
+	return;
+}
 
-	if (osi_linux != enable)
-		printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n",
-			enable ? "En": "Dis");
+static void __init acpi_cmdline_osi_linux(unsigned int enable)
+{
+	osi_linux.cmdline = 1;	/* cmdline set the default */
+	set_osi_linux(enable);
+
+	return;
+}
+
+void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
+{
+	osi_linux.dmi = 1;	/* DMI knows that this box asks OSI(Linux) */
+
+	printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
+
+	if (enable == -1)
+		return;
+
+	osi_linux.known = 1;	/* DMI knows which OSI(Linux) default needed */
+
+	set_osi_linux(enable);
 
-	osi_linux = enable;
 	return;
 }
 
@@ -987,12 +1054,12 @@ static int __init acpi_osi_setup(char *str)
 		printk(KERN_INFO PREFIX "_OSI method disabled\n");
 		acpi_gbl_create_osi_method = FALSE;
 	} else if (!strcmp("!Linux", str)) {
-		enable_osi_linux(0);
+		acpi_cmdline_osi_linux(0);	/* !enable */
 	} else if (*str == '!') {
 		if (acpi_osi_invalidate(++str) == AE_OK)
 			printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
 	} else if (!strcmp("Linux", str)) {
-		enable_osi_linux(1);
+		acpi_cmdline_osi_linux(1);	/* enable */
 	} else if (*osi_additional_string == '\0') {
 		strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX);
 		printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
@@ -1141,6 +1208,34 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
 	return (AE_OK);
 }
 
+/**
+ *	acpi_dmi_dump - dump DMI slots needed for blacklist entry
+ *
+ *	Returns 0 on success
+ */
+int acpi_dmi_dump(void)
+{
+
+	if (!dmi_available)
+		return -1;
+
+	printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
+		dmi_get_slot(DMI_SYS_VENDOR));
+	printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
+		dmi_get_slot(DMI_PRODUCT_NAME));
+	printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
+		dmi_get_slot(DMI_PRODUCT_VERSION));
+	printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
+		dmi_get_slot(DMI_BOARD_NAME));
+	printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
+		dmi_get_slot(DMI_BIOS_VENDOR));
+	printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
+		dmi_get_slot(DMI_BIOS_DATE));
+
+	return 0;
+}
+
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_os_validate_interface
@@ -1160,13 +1255,29 @@ acpi_os_validate_interface (char *interface)
 	if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX))
 		return AE_OK;
 	if (!strcmp("Linux", interface)) {
-		printk(KERN_WARNING PREFIX
-			"System BIOS is requesting _OSI(Linux)\n");
-		printk(KERN_WARNING PREFIX
-			"If \"acpi_osi=Linux\" works better,\n"
-			"Please send dmidecode "
-			"to linux-acpi@vger.kernel.org\n");
-		if(osi_linux)
+
+		printk(KERN_NOTICE PREFIX
+			"BIOS _OSI(Linux) query %s%s\n",
+			osi_linux.enable ? "honored" : "ignored",
+			osi_linux.cmdline ? " via cmdline" :
+			osi_linux.dmi ? " via DMI" : "");
+
+		if (!osi_linux.dmi) {
+			if (acpi_dmi_dump())
+				printk(KERN_NOTICE PREFIX
+					"[please extract dmidecode output]\n");
+			printk(KERN_NOTICE PREFIX
+				"Please send DMI info above to "
+				"linux-acpi@vger.kernel.org\n");
+		}
+		if (!osi_linux.known && !osi_linux.cmdline) {
+			printk(KERN_NOTICE PREFIX
+				"If \"acpi_osi=%sLinux\" works better, "
+				"please notify linux-acpi@vger.kernel.org\n",
+				osi_linux.enable ? "!" : "");
+		}
+
+		if (osi_linux.enable)
 			return AE_OK;
 	}
 	return AE_SUPPORT;
@@ -1198,28 +1309,4 @@ acpi_os_validate_address (
     return AE_OK;
 }
 
-#ifdef CONFIG_DMI
-static int dmi_osi_linux(const struct dmi_system_id *d)
-{
-	printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
-	enable_osi_linux(1);
-	return 0;
-}
-
-static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
-	/*
-	 * Boxes that need _OSI(Linux)
-	 */
-	{
-	 .callback = dmi_osi_linux,
-	 .ident = "Intel Napa CRB",
-	 .matches = {
-		     DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
-		     DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
-		     },
-	 },
-	{}
-};
-#endif /* CONFIG_DMI */
-
 #endif
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index c9f526e55392..5400ea173f6f 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -911,7 +911,7 @@ __setup("acpi_irq_balance", acpi_irq_balance_set);
 
 /* FIXME: we will remove this interface after all drivers call pci_disable_device */
 static struct sysdev_class irqrouter_sysdev_class = {
-	set_kset_name("irqrouter"),
+	.name = "irqrouter",
 	.resume = irqrouter_resume,
 };
 
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 2235f4e02d26..eb1f82f79153 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -357,6 +357,26 @@ int acpi_processor_resume(struct acpi_device * device)
 	return 0;
 }
 
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+static int tsc_halts_in_c(int state)
+{
+	switch (boot_cpu_data.x86_vendor) {
+	case X86_VENDOR_AMD:
+		/*
+		 * AMD Fam10h TSC will tick in all
+		 * C/P/S0/S1 states when this bit is set.
+		 */
+		if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
+			return 0;
+		/*FALL THROUGH*/
+	case X86_VENDOR_INTEL:
+		/* Several cases known where TSC halts in C2 too */
+	default:
+		return state > ACPI_STATE_C1;
+	}
+}
+#endif
+
 #ifndef CONFIG_CPU_IDLE
 static void acpi_processor_idle(void)
 {
@@ -516,7 +536,8 @@ static void acpi_processor_idle(void)
 
 #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
 		/* TSC halts in C2, so notify users */
-		mark_tsc_unstable("possible TSC halt in C2");
+		if (tsc_halts_in_c(ACPI_STATE_C2))
+			mark_tsc_unstable("possible TSC halt in C2");
 #endif
 		/* Compute time (ticks) that we were actually asleep */
 		sleep_ticks = ticks_elapsed(t1, t2);
@@ -534,6 +555,7 @@ static void acpi_processor_idle(void)
 		break;
 
 	case ACPI_STATE_C3:
+		acpi_unlazy_tlb(smp_processor_id());
 		/*
 		 * Must be done before busmaster disable as we might
 		 * need to access HPET !
@@ -579,7 +601,8 @@ static void acpi_processor_idle(void)
 
 #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
 		/* TSC halts in C3, so notify users */
-		mark_tsc_unstable("TSC halts in C3");
+		if (tsc_halts_in_c(ACPI_STATE_C3))
+			mark_tsc_unstable("TSC halts in C3");
 #endif
 		/* Compute time (ticks) that we were actually asleep */
 		sleep_ticks = ticks_elapsed(t1, t2);
@@ -1423,6 +1446,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 		return 0;
 	}
 
+	acpi_unlazy_tlb(smp_processor_id());
 	/*
 	 * Must be done before busmaster disable as we might need to
 	 * access HPET !
@@ -1443,7 +1467,8 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 
 #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
 	/* TSC could halt in idle, so notify users */
-	mark_tsc_unstable("TSC halts in idle");;
+	if (tsc_halts_in_c(cx->type))
+		mark_tsc_unstable("TSC halts in idle");;
 #endif
 	sleep_ticks = ticks_elapsed(t1, t2);
 
@@ -1554,7 +1579,8 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 
 #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
 	/* TSC could halt in idle, so notify users */
-	mark_tsc_unstable("TSC halts in idle");
+	if (tsc_halts_in_c(ACPI_STATE_C3))
+		mark_tsc_unstable("TSC halts in idle");
 #endif
 	sleep_ticks = ticks_elapsed(t1, t2);
 	/* Tell the scheduler how much we idled: */
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 6742d7bc4777..1685b40abda7 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -775,12 +775,12 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
 		acpi_processor_get_throttling_states(pr) ||
 		acpi_processor_get_platform_limit(pr))
 	{
-		if (acpi_processor_get_fadt_info(pr))
-			return 0;
 		pr->throttling.acpi_processor_get_throttling =
 		    &acpi_processor_get_throttling_fadt;
 		pr->throttling.acpi_processor_set_throttling =
 		    &acpi_processor_set_throttling_fadt;
+		if (acpi_processor_get_fadt_info(pr))
+			return 0;
 	} else {
 		pr->throttling.acpi_processor_get_throttling =
 		    &acpi_processor_get_throttling_ptc;
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index edee2806e37b..5ffe0ea18967 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -58,7 +58,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
                               FS Interface (/sys)
    -------------------------------------------------------------------------- */
 static LIST_HEAD(acpi_table_attr_list);
-static struct kobject tables_kobj;
+static struct kobject *tables_kobj;
 
 struct acpi_table_attr {
 	struct bin_attribute attr;
@@ -135,11 +135,9 @@ static int acpi_system_sysfs_init(void)
 	int table_index = 0;
 	int result;
 
-	tables_kobj.parent = &acpi_subsys.kobj;
-	kobject_set_name(&tables_kobj, "tables");
-	result = kobject_register(&tables_kobj);
-	if (result)
-		return result;
+	tables_kobj = kobject_create_and_add("tables", acpi_kobj);
+	if (!tables_kobj)
+		return -ENOMEM;
 
 	do {
 		result = acpi_get_table_by_index(table_index, &table_header);
@@ -153,7 +151,7 @@ static int acpi_system_sysfs_init(void)
 
 			acpi_table_attr_init(table_attr, table_header);
 			result =
-			    sysfs_create_bin_file(&tables_kobj,
+			    sysfs_create_bin_file(tables_kobj,
 						  &table_attr->attr);
 			if (result) {
 				kfree(table_attr);
@@ -163,6 +161,7 @@ static int acpi_system_sysfs_init(void)
 					      &acpi_table_attr_list);
 		}
 	} while (!result);
+	kobject_uevent(tables_kobj, KOBJ_ADD);
 
 	return 0;
 }
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 75939dd06295..ae19c9b30d15 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -459,6 +459,15 @@ config PATA_NETCELL
 
 	  If unsure, say N.
 
+config PATA_NINJA32
+	tristate "Ninja32/Delkin Cardbus ATA support (Experimental)"
+	depends on PCI && EXPERIMENTAL
+	help
+	  This option enables support for the Ninja32, Delkin and
+	  possibly other brands of Cardbus ATA adapter
+
+	  If unsure, say N.
+
 config PATA_NS87410
 	tristate "Nat Semi NS87410 PATA support (Experimental)"
 	depends on PCI && EXPERIMENTAL
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index ebcee64dd5e2..701651e37c89 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_PATA_IT821X)	+= pata_it821x.o
 obj-$(CONFIG_PATA_IT8213)	+= pata_it8213.o
 obj-$(CONFIG_PATA_JMICRON)	+= pata_jmicron.o
 obj-$(CONFIG_PATA_NETCELL)	+= pata_netcell.o
+obj-$(CONFIG_PATA_NINJA32)	+= pata_ninja32.o
 obj-$(CONFIG_PATA_NS87410)	+= pata_ns87410.o
 obj-$(CONFIG_PATA_NS87415)	+= pata_ns87415.o
 obj-$(CONFIG_PATA_OPTI)		+= pata_opti.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 54f38c21dd95..6f089b899a1a 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -198,18 +198,18 @@ enum {
 };
 
 struct ahci_cmd_hdr {
-	u32			opts;
-	u32			status;
-	u32			tbl_addr;
-	u32			tbl_addr_hi;
-	u32			reserved[4];
+	__le32			opts;
+	__le32			status;
+	__le32			tbl_addr;
+	__le32			tbl_addr_hi;
+	__le32			reserved[4];
 };
 
 struct ahci_sg {
-	u32			addr;
-	u32			addr_hi;
-	u32			reserved;
-	u32			flags_size;
+	__le32			addr;
+	__le32			addr_hi;
+	__le32			reserved;
+	__le32			flags_size;
 };
 
 struct ahci_host_priv {
@@ -597,6 +597,20 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
 	return __ahci_port_base(ap->host, ap->port_no);
 }
 
+static void ahci_enable_ahci(void __iomem *mmio)
+{
+	u32 tmp;
+
+	/* turn on AHCI_EN */
+	tmp = readl(mmio + HOST_CTL);
+	if (!(tmp & HOST_AHCI_EN)) {
+		tmp |= HOST_AHCI_EN;
+		writel(tmp, mmio + HOST_CTL);
+		tmp = readl(mmio + HOST_CTL);	/* flush && sanity check */
+		WARN_ON(!(tmp & HOST_AHCI_EN));
+	}
+}
+
 /**
  *	ahci_save_initial_config - Save and fixup initial config values
  *	@pdev: target PCI device
@@ -619,6 +633,9 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
 	u32 cap, port_map;
 	int i;
 
+	/* make sure AHCI mode is enabled before accessing CAP */
+	ahci_enable_ahci(mmio);
+
 	/* Values prefixed with saved_ are written back to host after
 	 * reset.  Values without are used for driver operation.
 	 */
@@ -1036,19 +1053,17 @@ static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
 static int ahci_reset_controller(struct ata_host *host)
 {
 	struct pci_dev *pdev = to_pci_dev(host->dev);
+	struct ahci_host_priv *hpriv = host->private_data;
 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
 	u32 tmp;
 
 	/* we must be in AHCI mode, before using anything
 	 * AHCI-specific, such as HOST_RESET.
 	 */
-	tmp = readl(mmio + HOST_CTL);
-	if (!(tmp & HOST_AHCI_EN)) {
-		tmp |= HOST_AHCI_EN;
-		writel(tmp, mmio + HOST_CTL);
-	}
+	ahci_enable_ahci(mmio);
 
 	/* global controller reset */
+	tmp = readl(mmio + HOST_CTL);
 	if ((tmp & HOST_RESET) == 0) {
 		writel(tmp | HOST_RESET, mmio + HOST_CTL);
 		readl(mmio + HOST_CTL); /* flush */
@@ -1067,8 +1082,7 @@ static int ahci_reset_controller(struct ata_host *host)
 	}
 
 	/* turn on AHCI mode */
-	writel(HOST_AHCI_EN, mmio + HOST_CTL);
-	(void) readl(mmio + HOST_CTL);	/* flush */
+	ahci_enable_ahci(mmio);
 
 	/* some registers might be cleared on reset.  restore initial values */
 	ahci_restore_initial_config(host);
@@ -1078,8 +1092,10 @@ static int ahci_reset_controller(struct ata_host *host)
 
 		/* configure PCS */
 		pci_read_config_word(pdev, 0x92, &tmp16);
-		tmp16 |= 0xf;
-		pci_write_config_word(pdev, 0x92, tmp16);
+		if ((tmp16 & hpriv->port_map) != hpriv->port_map) {
+			tmp16 |= hpriv->port_map;
+			pci_write_config_word(pdev, 0x92, tmp16);
+		}
 	}
 
 	return 0;
@@ -1480,35 +1496,31 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
 {
 	struct scatterlist *sg;
-	struct ahci_sg *ahci_sg;
-	unsigned int n_sg = 0;
+	struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
+	unsigned int si;
 
 	VPRINTK("ENTER\n");
 
 	/*
 	 * Next, the S/G list.
 	 */
-	ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		dma_addr_t addr = sg_dma_address(sg);
 		u32 sg_len = sg_dma_len(sg);
 
-		ahci_sg->addr = cpu_to_le32(addr & 0xffffffff);
-		ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
-		ahci_sg->flags_size = cpu_to_le32(sg_len - 1);
-
-		ahci_sg++;
-		n_sg++;
+		ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff);
+		ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+		ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1);
 	}
 
-	return n_sg;
+	return si;
 }
 
 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);
+	int is_atapi = ata_is_atapi(qc->tf.protocol);
 	void *cmd_tbl;
 	u32 opts;
 	const u32 cmd_fis_len = 5; /* five dwords */
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 90329982bef7..20534202fc79 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -26,7 +26,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "ata_generic"
-#define DRV_VERSION "0.2.13"
+#define DRV_VERSION "0.2.15"
 
 /*
  *	A generic parallel ATA driver using libata
@@ -48,27 +48,47 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
 	struct ata_port *ap = link->ap;
 	int dma_enabled = 0;
 	struct ata_device *dev;
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	/* Bits 5 and 6 indicate if DMA is active on master/slave */
 	if (ap->ioaddr.bmdma_addr)
 		dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
 
+	if (pdev->vendor == PCI_VENDOR_ID_CENATEK)
+		dma_enabled = 0xFF;
+
 	ata_link_for_each_dev(dev, link) {
-		if (ata_dev_enabled(dev)) {
-			/* We don't really care */
-			dev->pio_mode = XFER_PIO_0;
-			dev->dma_mode = XFER_MW_DMA_0;
-			/* We do need the right mode information for DMA or PIO
-			   and this comes from the current configuration flags */
-			if (dma_enabled & (1 << (5 + dev->devno))) {
-				ata_id_to_dma_mode(dev, XFER_MW_DMA_0);
-				dev->flags &= ~ATA_DFLAG_PIO;
-			} else {
-				ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
-				dev->xfer_mode = XFER_PIO_0;
-				dev->xfer_shift = ATA_SHIFT_PIO;
-				dev->flags |= ATA_DFLAG_PIO;
+		if (!ata_dev_enabled(dev))
+			continue;
+
+		/* We don't really care */
+		dev->pio_mode = XFER_PIO_0;
+		dev->dma_mode = XFER_MW_DMA_0;
+		/* We do need the right mode information for DMA or PIO
+		   and this comes from the current configuration flags */
+		if (dma_enabled & (1 << (5 + dev->devno))) {
+			unsigned int xfer_mask = ata_id_xfermask(dev->id);
+			const char *name;
+
+			if (xfer_mask & (ATA_MASK_MWDMA | ATA_MASK_UDMA))
+				name = ata_mode_string(xfer_mask);
+			else {
+				/* SWDMA perhaps? */
+				name = "DMA";
+				xfer_mask |= ata_xfer_mode2mask(XFER_MW_DMA_0);
 			}
+
+			ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
+				       name);
+
+			dev->xfer_mode = ata_xfer_mask2mode(xfer_mask);
+			dev->xfer_shift = ata_xfer_mode2shift(dev->xfer_mode);
+			dev->flags &= ~ATA_DFLAG_PIO;
+		} else {
+			ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
+			dev->xfer_mode = XFER_PIO_0;
+			dev->xfer_shift = ATA_SHIFT_PIO;
+			dev->flags |= ATA_DFLAG_PIO;
 		}
 	}
 	return 0;
@@ -185,6 +205,7 @@ static struct pci_device_id ata_generic[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_HINT,   PCI_DEVICE_ID_HINT_VXPROII_IDE), },
 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561), },
 	{ PCI_DEVICE(PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558), },
+	{ PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE), },
 	{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), },
 	{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
 	{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),  },
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index b406b39b878e..a65c8ae5c461 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -101,39 +101,21 @@ enum {
 	ICH5_PMR		= 0x90, /* port mapping register */
 	ICH5_PCS		= 0x92,	/* port control and status */
 	PIIX_SCC		= 0x0A, /* sub-class code register */
+	PIIX_SIDPR_BAR		= 5,
+	PIIX_SIDPR_LEN		= 16,
+	PIIX_SIDPR_IDX		= 0,
+	PIIX_SIDPR_DATA		= 4,
 
-	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_SIDPR		= (1 << 29), /* SATA idx/data pair regs */
 
 	PIIX_PATA_FLAGS		= ATA_FLAG_SLAVE_POSS,
 	PIIX_SATA_FLAGS		= ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR,
 
-	/* combined mode.  if set, PATA is channel 0.
-	 * if clear, PATA is channel 1.
-	 */
-	PIIX_PORT_ENABLED	= (1 << 0),
-	PIIX_PORT_PRESENT	= (1 << 4),
-
 	PIIX_80C_PRI		= (1 << 5) | (1 << 4),
 	PIIX_80C_SEC		= (1 << 7) | (1 << 6),
 
-	/* controller IDs */
-	piix_pata_mwdma		= 0,	/* PIIX3 MWDMA only */
-	piix_pata_33,			/* PIIX4 at 33Mhz */
-	ich_pata_33,			/* ICH up to UDMA 33 only */
-	ich_pata_66,			/* ICH up to 66 Mhz */
-	ich_pata_100,			/* ICH up to UDMA 100 */
-	ich5_sata,
-	ich6_sata,
-	ich6_sata_ahci,
-	ich6m_sata_ahci,
-	ich8_sata_ahci,
-	ich8_2port_sata,
-	ich8m_apple_sata_ahci,		/* locks up on second port enable */
-	tolapai_sata_ahci,
-	piix_pata_vmw,			/* PIIX4 for VMware, spurious DMA_ERR */
-
 	/* constants for mapping table */
 	P0			= 0,  /* port 0 */
 	P1			= 1,  /* port 1 */
@@ -149,6 +131,24 @@ enum {
 	PIIX_HOST_BROKEN_SUSPEND = (1 << 24),
 };
 
+enum piix_controller_ids {
+	/* controller IDs */
+	piix_pata_mwdma,	/* PIIX3 MWDMA only */
+	piix_pata_33,		/* PIIX4 at 33Mhz */
+	ich_pata_33,		/* ICH up to UDMA 33 only */
+	ich_pata_66,		/* ICH up to 66 Mhz */
+	ich_pata_100,		/* ICH up to UDMA 100 */
+	ich5_sata,
+	ich6_sata,
+	ich6_sata_ahci,
+	ich6m_sata_ahci,
+	ich8_sata_ahci,
+	ich8_2port_sata,
+	ich8m_apple_sata_ahci,	/* locks up on second port enable */
+	tolapai_sata_ahci,
+	piix_pata_vmw,			/* PIIX4 for VMware, spurious DMA_ERR */
+};
+
 struct piix_map_db {
 	const u32 mask;
 	const u16 port_enable;
@@ -157,6 +157,7 @@ struct piix_map_db {
 
 struct piix_host_priv {
 	const int *map;
+	void __iomem *sidpr;
 };
 
 static int piix_init_one(struct pci_dev *pdev,
@@ -167,6 +168,9 @@ static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev);
 static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev);
 static int ich_pata_cable_detect(struct ata_port *ap);
 static u8 piix_vmw_bmdma_status(struct ata_port *ap);
+static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val);
+static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val);
+static void piix_sidpr_error_handler(struct ata_port *ap);
 #ifdef CONFIG_PM
 static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
 static int piix_pci_device_resume(struct pci_dev *pdev);
@@ -321,7 +325,6 @@ static const struct ata_port_operations piix_pata_ops = {
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.cable_detect		= ata_cable_40wire,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 
@@ -353,7 +356,6 @@ static const struct ata_port_operations ich_pata_ops = {
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.cable_detect		= ich_pata_cable_detect,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 
@@ -380,7 +382,6 @@ static const struct ata_port_operations piix_sata_ops = {
 	.error_handler		= ata_bmdma_error_handler,
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 
-	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
 
@@ -419,6 +420,35 @@ static const struct ata_port_operations piix_vmw_ops = {
 	.port_start		= ata_port_start,
 };
 
+static const struct ata_port_operations piix_sidpr_sata_ops = {
+	.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,
+
+	.bmdma_setup		= ata_bmdma_setup,
+	.bmdma_start		= ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.data_xfer		= ata_data_xfer,
+
+	.scr_read		= piix_sidpr_scr_read,
+	.scr_write		= piix_sidpr_scr_write,
+
+	.freeze			= ata_bmdma_freeze,
+	.thaw			= ata_bmdma_thaw,
+	.error_handler		= piix_sidpr_error_handler,
+	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+
+	.irq_clear		= ata_bmdma_irq_clear,
+	.irq_on			= ata_irq_on,
+
+	.port_start		= ata_port_start,
+};
+
 static const struct piix_map_db ich5_map_db = {
 	.mask = 0x7,
 	.port_enable = 0x3,
@@ -526,7 +556,6 @@ static const struct piix_map_db *piix_map_db_table[] = {
 static struct ata_port_info piix_port_info[] = {
 	[piix_pata_mwdma] = 	/* PIIX3 MWDMA only */
 	{
-		.sht		= &piix_sht,
 		.flags		= PIIX_PATA_FLAGS,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
@@ -535,7 +564,6 @@ static struct ata_port_info piix_port_info[] = {
 
 	[piix_pata_33] =	/* PIIX4 at 33MHz */
 	{
-		.sht		= &piix_sht,
 		.flags		= PIIX_PATA_FLAGS,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
@@ -545,7 +573,6 @@ static struct ata_port_info piix_port_info[] = {
 
 	[ich_pata_33] = 	/* ICH0 - ICH at 33Mhz*/
 	{
-		.sht		= &piix_sht,
 		.flags		= PIIX_PATA_FLAGS,
 		.pio_mask 	= 0x1f,	/* pio 0-4 */
 		.mwdma_mask	= 0x06, /* Check: maybe 0x07  */
@@ -555,7 +582,6 @@ static struct ata_port_info piix_port_info[] = {
 
 	[ich_pata_66] = 	/* ICH controllers up to 66MHz */
 	{
-		.sht		= &piix_sht,
 		.flags		= PIIX_PATA_FLAGS,
 		.pio_mask 	= 0x1f,	/* pio 0-4 */
 		.mwdma_mask	= 0x06, /* MWDMA0 is broken on chip */
@@ -565,7 +591,6 @@ static struct ata_port_info piix_port_info[] = {
 
 	[ich_pata_100] =
 	{
-		.sht		= &piix_sht,
 		.flags		= PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x06, /* mwdma1-2 */
@@ -575,7 +600,6 @@ static struct ata_port_info piix_port_info[] = {
 
 	[ich5_sata] =
 	{
-		.sht		= &piix_sht,
 		.flags		= PIIX_SATA_FLAGS,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
@@ -585,8 +609,7 @@ static struct ata_port_info piix_port_info[] = {
 
 	[ich6_sata] =
 	{
-		.sht		= &piix_sht,
-		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR,
+		.flags		= PIIX_SATA_FLAGS,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= ATA_UDMA6,
@@ -595,9 +618,7 @@ static struct ata_port_info piix_port_info[] = {
 
 	[ich6_sata_ahci] =
 	{
-		.sht		= &piix_sht,
-		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-				  PIIX_FLAG_AHCI,
+		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_AHCI,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= ATA_UDMA6,
@@ -606,9 +627,7 @@ static struct ata_port_info piix_port_info[] = {
 
 	[ich6m_sata_ahci] =
 	{
-		.sht		= &piix_sht,
-		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-				  PIIX_FLAG_AHCI,
+		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_AHCI,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= ATA_UDMA6,
@@ -617,9 +636,8 @@ static struct ata_port_info piix_port_info[] = {
 
 	[ich8_sata_ahci] =
 	{
-		.sht		= &piix_sht,
-		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-				  PIIX_FLAG_AHCI,
+		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_AHCI |
+				  PIIX_FLAG_SIDPR,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= ATA_UDMA6,
@@ -628,9 +646,8 @@ static struct ata_port_info piix_port_info[] = {
 
 	[ich8_2port_sata] =
 	{
-		.sht		= &piix_sht,
-		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-				  PIIX_FLAG_AHCI,
+		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_AHCI |
+				  PIIX_FLAG_SIDPR,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= ATA_UDMA6,
@@ -639,9 +656,7 @@ static struct ata_port_info piix_port_info[] = {
 
 	[tolapai_sata_ahci] =
 	{
-		.sht		= &piix_sht,
-		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-				  PIIX_FLAG_AHCI,
+		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_AHCI,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= ATA_UDMA6,
@@ -650,9 +665,8 @@ static struct ata_port_info piix_port_info[] = {
 
 	[ich8m_apple_sata_ahci] =
 	{
-		.sht		= &piix_sht,
-		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
-				  PIIX_FLAG_AHCI,
+		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_AHCI |
+				  PIIX_FLAG_SIDPR,
 		.pio_mask	= 0x1f,	/* pio0-4 */
 		.mwdma_mask	= 0x07, /* mwdma0-2 */
 		.udma_mask	= ATA_UDMA6,
@@ -1001,6 +1015,180 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 	do_pata_set_dmamode(ap, adev, 1);
 }
 
+/*
+ * Serial ATA Index/Data Pair Superset Registers access
+ *
+ * Beginning from ICH8, there's a sane way to access SCRs using index
+ * and data register pair located at BAR5.  This creates an
+ * interesting problem of mapping two SCRs to one port.
+ *
+ * Although they have separate SCRs, the master and slave aren't
+ * independent enough to be treated as separate links - e.g. softreset
+ * resets both.  Also, there's no protocol defined for hard resetting
+ * singled device sharing the virtual port (no defined way to acquire
+ * device signature).  This is worked around by merging the SCR values
+ * into one sensible value and requesting follow-up SRST after
+ * hardreset.
+ *
+ * SCR merging is perfomed in nibbles which is the unit contents in
+ * SCRs are organized.  If two values are equal, the value is used.
+ * When they differ, merge table which lists precedence of possible
+ * values is consulted and the first match or the last entry when
+ * nothing matches is used.  When there's no merge table for the
+ * specific nibble, value from the first port is used.
+ */
+static const int piix_sidx_map[] = {
+	[SCR_STATUS]	= 0,
+	[SCR_ERROR]	= 2,
+	[SCR_CONTROL]	= 1,
+};
+
+static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg)
+{
+	struct ata_port *ap = dev->link->ap;
+	struct piix_host_priv *hpriv = ap->host->private_data;
+
+	iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg],
+		  hpriv->sidpr + PIIX_SIDPR_IDX);
+}
+
+static int piix_sidpr_read(struct ata_device *dev, unsigned int reg)
+{
+	struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
+
+	piix_sidpr_sel(dev, reg);
+	return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
+}
+
+static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val)
+{
+	struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
+
+	piix_sidpr_sel(dev, reg);
+	iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
+}
+
+u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
+{
+	u32 val = 0;
+	int i, mi;
+
+	for (i = 0, mi = 0; i < 32 / 4; i++) {
+		u8 c0 = (val0 >> (i * 4)) & 0xf;
+		u8 c1 = (val1 >> (i * 4)) & 0xf;
+		u8 merged = c0;
+		const int *cur;
+
+		/* if no merge preference, assume the first value */
+		cur = merge_tbl[mi];
+		if (!cur)
+			goto done;
+		mi++;
+
+		/* if two values equal, use it */
+		if (c0 == c1)
+			goto done;
+
+		/* choose the first match or the last from the merge table */
+		while (*cur != -1) {
+			if (c0 == *cur || c1 == *cur)
+				break;
+			cur++;
+		}
+		if (*cur == -1)
+			cur--;
+		merged = *cur;
+	done:
+		val |= merged << (i * 4);
+	}
+
+	return val;
+}
+
+static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val)
+{
+	const int * const sstatus_merge_tbl[] = {
+		/* DET */ (const int []){ 1, 3, 0, 4, 3, -1 },
+		/* SPD */ (const int []){ 2, 1, 0, -1 },
+		/* IPM */ (const int []){ 6, 2, 1, 0, -1 },
+		NULL,
+	};
+	const int * const scontrol_merge_tbl[] = {
+		/* DET */ (const int []){ 1, 0, 4, 0, -1 },
+		/* SPD */ (const int []){ 0, 2, 1, 0, -1 },
+		/* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 },
+		NULL,
+	};
+	u32 v0, v1;
+
+	if (reg >= ARRAY_SIZE(piix_sidx_map))
+		return -EINVAL;
+
+	if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) {
+		*val = piix_sidpr_read(&ap->link.device[0], reg);
+		return 0;
+	}
+
+	v0 = piix_sidpr_read(&ap->link.device[0], reg);
+	v1 = piix_sidpr_read(&ap->link.device[1], reg);
+
+	switch (reg) {
+	case SCR_STATUS:
+		*val = piix_merge_scr(v0, v1, sstatus_merge_tbl);
+		break;
+	case SCR_ERROR:
+		*val = v0 | v1;
+		break;
+	case SCR_CONTROL:
+		*val = piix_merge_scr(v0, v1, scontrol_merge_tbl);
+		break;
+	}
+
+	return 0;
+}
+
+static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val)
+{
+	if (reg >= ARRAY_SIZE(piix_sidx_map))
+		return -EINVAL;
+
+	piix_sidpr_write(&ap->link.device[0], reg, val);
+
+	if (ap->flags & ATA_FLAG_SLAVE_POSS)
+		piix_sidpr_write(&ap->link.device[1], reg, val);
+
+	return 0;
+}
+
+static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class,
+				unsigned long deadline)
+{
+	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+	int rc;
+
+	/* do hardreset */
+	rc = sata_link_hardreset(link, timing, deadline);
+	if (rc) {
+		ata_link_printk(link, KERN_ERR,
+				"COMRESET failed (errno=%d)\n", rc);
+		return rc;
+	}
+
+	/* TODO: phy layer with polling, timeouts, etc. */
+	if (ata_link_offline(link)) {
+		*class = ATA_DEV_NONE;
+		return 0;
+	}
+
+	return -EAGAIN;
+}
+
+static void piix_sidpr_error_handler(struct ata_port *ap)
+{
+	ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
+			   piix_sidpr_hardreset, ata_std_postreset);
+}
+
 #ifdef CONFIG_PM
 static int piix_broken_suspend(void)
 {
@@ -1034,6 +1222,13 @@ static int piix_broken_suspend(void)
 			},
 		},
 		{
+			.ident = "TECRA M6",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M6"),
+			},
+		},
+		{
 			.ident = "TECRA M7",
 			.matches = {
 				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
@@ -1048,6 +1243,13 @@ static int piix_broken_suspend(void)
 			},
 		},
 		{
+			.ident = "Satellite R20",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite R20"),
+			},
+		},
+		{
 			.ident = "Satellite R25",
 			.matches = {
 				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
@@ -1253,10 +1455,10 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
 	return no_piix_dma;
 }
 
-static void __devinit piix_init_pcs(struct pci_dev *pdev,
-				    struct ata_port_info *pinfo,
+static void __devinit piix_init_pcs(struct ata_host *host,
 				    const struct piix_map_db *map_db)
 {
+	struct pci_dev *pdev = to_pci_dev(host->dev);
 	u16 pcs, new_pcs;
 
 	pci_read_config_word(pdev, ICH5_PCS, &pcs);
@@ -1270,11 +1472,10 @@ static void __devinit piix_init_pcs(struct pci_dev *pdev,
 	}
 }
 
-static void __devinit piix_init_sata_map(struct pci_dev *pdev,
-					 struct ata_port_info *pinfo,
-					 const struct piix_map_db *map_db)
+static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
+					       struct ata_port_info *pinfo,
+					       const struct piix_map_db *map_db)
 {
-	struct piix_host_priv *hpriv = pinfo[0].private_data;
 	const int *map;
 	int i, invalid_map = 0;
 	u8 map_value;
@@ -1298,7 +1499,6 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
 		case IDE:
 			WARN_ON((i & 1) || map[i + 1] != IDE);
 			pinfo[i / 2] = piix_port_info[ich_pata_100];
-			pinfo[i / 2].private_data = hpriv;
 			i++;
 			printk(" IDE IDE");
 			break;
@@ -1316,7 +1516,33 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
 		dev_printk(KERN_ERR, &pdev->dev,
 			   "invalid MAP value %u\n", map_value);
 
-	hpriv->map = map;
+	return map;
+}
+
+static void __devinit piix_init_sidpr(struct ata_host *host)
+{
+	struct pci_dev *pdev = to_pci_dev(host->dev);
+	struct piix_host_priv *hpriv = host->private_data;
+	int i;
+
+	/* check for availability */
+	for (i = 0; i < 4; i++)
+		if (hpriv->map[i] == IDE)
+			return;
+
+	if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
+		return;
+
+	if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 ||
+	    pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN)
+		return;
+
+	if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME))
+		return;
+
+	hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
+	host->ports[0]->ops = &piix_sidpr_sata_ops;
+	host->ports[1]->ops = &piix_sidpr_sata_ops;
 }
 
 static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
@@ -1375,8 +1601,10 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	struct device *dev = &pdev->dev;
 	struct ata_port_info port_info[2];
 	const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
-	struct piix_host_priv *hpriv;
 	unsigned long port_flags;
+	struct ata_host *host;
+	struct piix_host_priv *hpriv;
+	int rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev,
@@ -1386,17 +1614,31 @@ 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_flags = port_info[0].flags;
+
+	/* enable device and prepare host */
+	rc = pcim_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	/* SATA map init can change port_info, do it before prepping host */
 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
 	if (!hpriv)
 		return -ENOMEM;
 
-	port_info[0] = piix_port_info[ent->driver_data];
-	port_info[1] = piix_port_info[ent->driver_data];
-	port_info[0].private_data = hpriv;
-	port_info[1].private_data = hpriv;
+	if (port_flags & ATA_FLAG_SATA)
+		hpriv->map = piix_init_sata_map(pdev, port_info,
+					piix_map_db_table[ent->driver_data]);
 
-	port_flags = port_info[0].flags;
+	rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
+	if (rc)
+		return rc;
+	host->private_data = hpriv;
 
+	/* initialize controller */
 	if (port_flags & PIIX_FLAG_AHCI) {
 		u8 tmp;
 		pci_read_config_byte(pdev, PIIX_SCC, &tmp);
@@ -1407,12 +1649,9 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		}
 	}
 
-	/* Initialize SATA map */
 	if (port_flags & ATA_FLAG_SATA) {
-		piix_init_sata_map(pdev, port_info,
-				   piix_map_db_table[ent->driver_data]);
-		piix_init_pcs(pdev, port_info,
-			      piix_map_db_table[ent->driver_data]);
+		piix_init_pcs(host, piix_map_db_table[ent->driver_data]);
+		piix_init_sidpr(host);
 	}
 
 	/* apply IOCFG bit18 quirk */
@@ -1431,12 +1670,14 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 		/* 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;
+		host->ports[0]->mwdma_mask = 0;
+		host->ports[0]->udma_mask = 0;
+		host->ports[1]->mwdma_mask = 0;
+		host->ports[1]->udma_mask = 0;
 	}
-	return ata_pci_init_one(pdev, ppi);
+
+	pci_set_master(pdev);
+	return ata_pci_activate_sff_host(host, ata_interrupt, &piix_sht);
 }
 
 static int __init piix_init(void)
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 7bf4befd96bc..9e8ec19260af 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -442,40 +442,77 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf)
 }
 
 /**
+ * ata_acpi_gtm_xfermode - determine xfermode from GTM parameter
+ * @dev: target device
+ * @gtm: GTM parameter to use
+ *
+ * Determine xfermask for @dev from @gtm.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * Determined xfermask.
+ */
+unsigned long ata_acpi_gtm_xfermask(struct ata_device *dev,
+				    const struct ata_acpi_gtm *gtm)
+{
+	unsigned long xfer_mask = 0;
+	unsigned int type;
+	int unit;
+	u8 mode;
+
+	/* we always use the 0 slot for crap hardware */
+	unit = dev->devno;
+	if (!(gtm->flags & 0x10))
+		unit = 0;
+
+	/* PIO */
+	mode = ata_timing_cycle2mode(ATA_SHIFT_PIO, gtm->drive[unit].pio);
+	xfer_mask |= ata_xfer_mode2mask(mode);
+
+	/* See if we have MWDMA or UDMA data. We don't bother with
+	 * MWDMA if UDMA is available as this means the BIOS set UDMA
+	 * and our error changedown if it works is UDMA to PIO anyway.
+	 */
+	if (!(gtm->flags & (1 << (2 * unit))))
+		type = ATA_SHIFT_MWDMA;
+	else
+		type = ATA_SHIFT_UDMA;
+
+	mode = ata_timing_cycle2mode(type, gtm->drive[unit].dma);
+	xfer_mask |= ata_xfer_mode2mask(mode);
+
+	return xfer_mask;
+}
+EXPORT_SYMBOL_GPL(ata_acpi_gtm_xfermask);
+
+/**
  * ata_acpi_cbl_80wire		-	Check for 80 wire cable
  * @ap: Port to check
+ * @gtm: GTM data to use
  *
- * Return 1 if the ACPI mode data for this port indicates the BIOS selected
- * an 80wire mode.
+ * Return 1 if the @gtm indicates the BIOS selected an 80wire mode.
  */
-
-int ata_acpi_cbl_80wire(struct ata_port *ap)
+int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm)
 {
-	const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap);
-	int valid = 0;
+	struct ata_device *dev;
 
-	if (!gtm)
-		return 0;
+	ata_link_for_each_dev(dev, &ap->link) {
+		unsigned long xfer_mask, udma_mask;
+
+		if (!ata_dev_enabled(dev))
+			continue;
+
+		xfer_mask = ata_acpi_gtm_xfermask(dev, gtm);
+		ata_unpack_xfermask(xfer_mask, NULL, NULL, &udma_mask);
+
+		if (udma_mask & ~ATA_UDMA_MASK_40C)
+			return 1;
+	}
 
-	/* Split timing, DMA enabled */
-	if ((gtm->flags & 0x11) == 0x11 && gtm->drive[0].dma < 55)
-		valid |= 1;
-	if ((gtm->flags & 0x14) == 0x14 && gtm->drive[1].dma < 55)
-		valid |= 2;
-	/* Shared timing, DMA enabled */
-	if ((gtm->flags & 0x11) == 0x01 && gtm->drive[0].dma < 55)
-		valid |= 1;
-	if ((gtm->flags & 0x14) == 0x04 && gtm->drive[0].dma < 55)
-		valid |= 2;
-
-	/* Drive check */
-	if ((valid & 1) && ata_dev_enabled(&ap->link.device[0]))
-		return 1;
-	if ((valid & 2) && ata_dev_enabled(&ap->link.device[1]))
-		return 1;
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire);
 
 static void ata_acpi_gtf_to_tf(struct ata_device *dev,
@@ -776,6 +813,36 @@ void ata_acpi_on_resume(struct ata_port *ap)
 }
 
 /**
+ * ata_acpi_set_state - set the port power state
+ * @ap: target ATA port
+ * @state: state, on/off
+ *
+ * This function executes the _PS0/_PS3 ACPI method to set the power state.
+ * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
+ */
+void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
+{
+	struct ata_device *dev;
+
+	if (!ap->acpi_handle || (ap->flags & ATA_FLAG_ACPI_SATA))
+		return;
+
+	/* channel first and then drives for power on and vica versa
+	   for power off */
+	if (state.event == PM_EVENT_ON)
+		acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D0);
+
+	ata_link_for_each_dev(dev, &ap->link) {
+		if (dev->acpi_handle && ata_dev_enabled(dev))
+			acpi_bus_set_power(dev->acpi_handle,
+				state.event == PM_EVENT_ON ?
+					ACPI_STATE_D0 : ACPI_STATE_D3);
+	}
+	if (state.event != PM_EVENT_ON)
+		acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D3);
+}
+
+/**
  * ata_acpi_on_devcfg - ATA ACPI hook called on device donfiguration
  * @dev: target ATA device
  *
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 6380726f7538..bdbd55af7022 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -119,6 +119,10 @@ int libata_noacpi = 0;
 module_param_named(noacpi, libata_noacpi, int, 0444);
 MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set");
 
+int libata_allow_tpm = 0;
+module_param_named(allow_tpm, libata_allow_tpm, int, 0444);
+MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands");
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
 MODULE_LICENSE("GPL");
@@ -450,9 +454,9 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
  *	RETURNS:
  *	Packed xfer_mask.
  */
-static unsigned int ata_pack_xfermask(unsigned int pio_mask,
-				      unsigned int mwdma_mask,
-				      unsigned int udma_mask)
+unsigned long ata_pack_xfermask(unsigned long pio_mask,
+				unsigned long mwdma_mask,
+				unsigned long udma_mask)
 {
 	return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
 		((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
@@ -469,10 +473,8 @@ static unsigned int ata_pack_xfermask(unsigned int pio_mask,
  *	Unpack @xfer_mask into @pio_mask, @mwdma_mask and @udma_mask.
  *	Any NULL distination masks will be ignored.
  */
-static void ata_unpack_xfermask(unsigned int xfer_mask,
-				unsigned int *pio_mask,
-				unsigned int *mwdma_mask,
-				unsigned int *udma_mask)
+void ata_unpack_xfermask(unsigned long xfer_mask, unsigned long *pio_mask,
+			 unsigned long *mwdma_mask, unsigned long *udma_mask)
 {
 	if (pio_mask)
 		*pio_mask = (xfer_mask & ATA_MASK_PIO) >> ATA_SHIFT_PIO;
@@ -486,9 +488,9 @@ static const struct ata_xfer_ent {
 	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 },
+	{ ATA_SHIFT_PIO, ATA_NR_PIO_MODES, XFER_PIO_0 },
+	{ ATA_SHIFT_MWDMA, ATA_NR_MWDMA_MODES, XFER_MW_DMA_0 },
+	{ ATA_SHIFT_UDMA, ATA_NR_UDMA_MODES, XFER_UDMA_0 },
 	{ -1, },
 };
 
@@ -503,9 +505,9 @@ static const struct ata_xfer_ent {
  *	None.
  *
  *	RETURNS:
- *	Matching XFER_* value, 0 if no match found.
+ *	Matching XFER_* value, 0xff if no match found.
  */
-static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
+u8 ata_xfer_mask2mode(unsigned long xfer_mask)
 {
 	int highbit = fls(xfer_mask) - 1;
 	const struct ata_xfer_ent *ent;
@@ -513,7 +515,7 @@ static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
 	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;
+	return 0xff;
 }
 
 /**
@@ -528,13 +530,14 @@ static u8 ata_xfer_mask2mode(unsigned int xfer_mask)
  *	RETURNS:
  *	Matching xfer_mask, 0 if no match found.
  */
-static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
+unsigned long 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 ((2 << (ent->shift + xfer_mode - ent->base)) - 1)
+				& ~((1 << ent->shift) - 1);
 	return 0;
 }
 
@@ -550,7 +553,7 @@ static unsigned int ata_xfer_mode2mask(u8 xfer_mode)
  *	RETURNS:
  *	Matching xfer_shift, -1 if no match found.
  */
-static int ata_xfer_mode2shift(unsigned int xfer_mode)
+int ata_xfer_mode2shift(unsigned long xfer_mode)
 {
 	const struct ata_xfer_ent *ent;
 
@@ -574,7 +577,7 @@ static int ata_xfer_mode2shift(unsigned int xfer_mode)
  *	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)
+const char *ata_mode_string(unsigned long xfer_mask)
 {
 	static const char * const xfer_mode_str[] = {
 		"PIO0",
@@ -947,8 +950,8 @@ unsigned int ata_dev_try_classify(struct ata_device *dev, int present,
 	if (r_err)
 		*r_err = err;
 
-	/* see if device passed diags: if master then continue and warn later */
-	if (err == 0 && dev->devno == 0)
+	/* see if device passed diags: continue and warn later */
+	if (err == 0)
 		/* diagnostic fail : do nothing _YET_ */
 		dev->horkage |= ATA_HORKAGE_DIAGNOSTIC;
 	else if (err == 1)
@@ -1286,48 +1289,6 @@ static int ata_hpa_resize(struct ata_device *dev)
 }
 
 /**
- *	ata_id_to_dma_mode	-	Identify DMA mode from id block
- *	@dev: device to identify
- *	@unknown: mode to assume if we cannot tell
- *
- *	Set up the timing values for the device based upon the identify
- *	reported values for the DMA mode. This function is used by drivers
- *	which rely upon firmware configured modes, but wish to report the
- *	mode correctly when possible.
- *
- *	In addition we emit similarly formatted messages to the default
- *	ata_dev_set_mode handler, in order to provide consistency of
- *	presentation.
- */
-
-void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown)
-{
-	unsigned int mask;
-	u8 mode;
-
-	/* Pack the DMA modes */
-	mask = ((dev->id[63] >> 8) << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA;
-	if (dev->id[53] & 0x04)
-		mask |= ((dev->id[88] >> 8) << ATA_SHIFT_UDMA) & ATA_MASK_UDMA;
-
-	/* Select the mode in use */
-	mode = ata_xfer_mask2mode(mask);
-
-	if (mode != 0) {
-		ata_dev_printk(dev, KERN_INFO, "configured for %s\n",
-		       ata_mode_string(mask));
-	} else {
-		/* SWDMA perhaps ? */
-		mode = unknown;
-		ata_dev_printk(dev, KERN_INFO, "configured for DMA\n");
-	}
-
-	/* Configure the device reporting */
-	dev->xfer_mode = mode;
-	dev->xfer_shift = ata_xfer_mode2shift(mode);
-}
-
-/**
  *	ata_noop_dev_select - Select device 0/1 on ATA bus
  *	@ap: ATA channel to manipulate
  *	@device: ATA device (numbered from zero) to select
@@ -1464,9 +1425,9 @@ static inline void ata_dump_id(const u16 *id)
  *	RETURNS:
  *	Computed xfermask
  */
-static unsigned int ata_id_xfermask(const u16 *id)
+unsigned long ata_id_xfermask(const u16 *id)
 {
-	unsigned int pio_mask, mwdma_mask, udma_mask;
+	unsigned long pio_mask, mwdma_mask, udma_mask;
 
 	/* Usual case. Word 53 indicates word 64 is valid */
 	if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
@@ -1519,7 +1480,7 @@ static unsigned int ata_id_xfermask(const u16 *id)
 }
 
 /**
- *	ata_port_queue_task - Queue port_task
+ *	ata_pio_queue_task - Queue port_task
  *	@ap: The ata_port to queue port_task for
  *	@fn: workqueue function to be scheduled
  *	@data: data for @fn to use
@@ -1531,16 +1492,15 @@ static unsigned int ata_id_xfermask(const u16 *id)
  *	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
+ *	port_task and EH.  ata_pio_queue_task() may be ignored for EH
  *	synchronization.
  *
  *	LOCKING:
  *	Inherited from caller.
  */
-void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data,
-			 unsigned long delay)
+static void ata_pio_queue_task(struct ata_port *ap, void *data,
+			       unsigned long delay)
 {
-	PREPARE_DELAYED_WORK(&ap->port_task, fn);
 	ap->port_task_data = data;
 
 	/* may fail if ata_port_flush_task() in progress */
@@ -2090,7 +2050,7 @@ int ata_dev_configure(struct ata_device *dev)
 	struct ata_eh_context *ehc = &dev->link->eh_context;
 	int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
 	const u16 *id = dev->id;
-	unsigned int xfer_mask;
+	unsigned long xfer_mask;
 	char revbuf[7];		/* XYZ-99\0 */
 	char fwrevbuf[ATA_ID_FW_REV_LEN+1];
 	char modelbuf[ATA_ID_PROD_LEN+1];
@@ -2161,8 +2121,14 @@ int ata_dev_configure(struct ata_device *dev)
 					       "supports DRM functions and may "
 					       "not be fully accessable.\n");
 			snprintf(revbuf, 7, "CFA");
-		} else
+		} else {
 			snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
+			/* Warn the user if the device has TPM extensions */
+			if (ata_id_has_tpm(id))
+				ata_dev_printk(dev, KERN_WARNING,
+					       "supports DRM functions and may "
+					       "not be fully accessable.\n");
+		}
 
 		dev->n_sectors = ata_id_n_sectors(id);
 
@@ -2295,19 +2261,8 @@ int ata_dev_configure(struct ata_device *dev)
 			dev->flags |= ATA_DFLAG_DIPM;
 	}
 
-	if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
-		/* Let the user know. We don't want to disallow opens for
-		   rescue purposes, or in case the vendor is just a blithering
-		   idiot */
-		if (print_info) {
-			ata_dev_printk(dev, KERN_WARNING,
-"Drive reports diagnostics failure. This may indicate a drive\n");
-			ata_dev_printk(dev, KERN_WARNING,
-"fault or invalid emulation. Contact drive vendor for information.\n");
-		}
-	}
-
-	/* limit bridge transfers to udma5, 200 sectors */
+	/* Limit PATA drive on SATA cable bridge transfers to udma5,
+	   200 sectors */
 	if (ata_dev_knobble(dev)) {
 		if (ata_msg_drv(ap) && print_info)
 			ata_dev_printk(dev, KERN_INFO,
@@ -2336,6 +2291,21 @@ int ata_dev_configure(struct ata_device *dev)
 	if (ap->ops->dev_config)
 		ap->ops->dev_config(dev);
 
+	if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
+		/* Let the user know. We don't want to disallow opens for
+		   rescue purposes, or in case the vendor is just a blithering
+		   idiot. Do this after the dev_config call as some controllers
+		   with buggy firmware may want to avoid reporting false device
+		   bugs */
+
+		if (print_info) {
+			ata_dev_printk(dev, KERN_WARNING,
+"Drive reports diagnostics failure. This may indicate a drive\n");
+			ata_dev_printk(dev, KERN_WARNING,
+"fault or invalid emulation. Contact drive vendor for information.\n");
+		}
+	}
+
 	if (ata_msg_probe(ap))
 		ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
 			__FUNCTION__, ata_chk_status(ap));
@@ -2387,6 +2357,18 @@ int ata_cable_unknown(struct ata_port *ap)
 }
 
 /**
+ *	ata_cable_ignore	-	return ignored PATA cable.
+ *	@ap: port
+ *
+ *	Helper method for drivers which don't use cable type to limit
+ *	transfer mode.
+ */
+int ata_cable_ignore(struct ata_port *ap)
+{
+	return ATA_CBL_PATA_IGN;
+}
+
+/**
  *	ata_cable_sata	-	return SATA cable type
  *	@ap: port
  *
@@ -2781,38 +2763,33 @@ int sata_set_spd(struct ata_link *link)
  */
 
 static const struct ata_timing ata_timing[] = {
+/*	{ XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960,   0 }, */
+	{ XFER_PIO_0,     70, 290, 240, 600, 165, 150, 600,   0 },
+	{ XFER_PIO_1,     50, 290,  93, 383, 125, 100, 383,   0 },
+	{ XFER_PIO_2,     30, 290,  40, 330, 100,  90, 240,   0 },
+	{ XFER_PIO_3,     30,  80,  70, 180,  80,  70, 180,   0 },
+	{ XFER_PIO_4,     25,  70,  25, 120,  70,  25, 120,   0 },
+	{ XFER_PIO_5,     15,  65,  25, 100,  65,  25, 100,   0 },
+	{ XFER_PIO_6,     10,  55,  20,  80,  55,  20,  80,   0 },
 
-	{ XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
-	{ XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
-	{ XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
-	{ XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
+	{ XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 960,   0 },
+	{ XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 480,   0 },
+	{ XFER_SW_DMA_2,  60,   0,   0,   0, 120, 120, 240,   0 },
 
-	{ XFER_MW_DMA_4,  25,   0,   0,   0,  55,  20,  80,   0 },
+	{ XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 480,   0 },
+	{ XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 150,   0 },
+	{ XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 120,   0 },
 	{ XFER_MW_DMA_3,  25,   0,   0,   0,  65,  25, 100,   0 },
-	{ XFER_UDMA_2,     0,   0,   0,   0,   0,   0,   0,  60 },
-	{ XFER_UDMA_1,     0,   0,   0,   0,   0,   0,   0,  80 },
-	{ XFER_UDMA_0,     0,   0,   0,   0,   0,   0,   0, 120 },
+	{ XFER_MW_DMA_4,  25,   0,   0,   0,  55,  20,  80,   0 },
 
 /*	{ XFER_UDMA_SLOW,  0,   0,   0,   0,   0,   0,   0, 150 }, */
-
-	{ XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 120,   0 },
-	{ XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 150,   0 },
-	{ XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 480,   0 },
-
-	{ XFER_SW_DMA_2,  60,   0,   0,   0, 120, 120, 240,   0 },
-	{ XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 480,   0 },
-	{ XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 960,   0 },
-
-	{ XFER_PIO_6,     10,  55,  20,  80,  55,  20,  80,   0 },
-	{ XFER_PIO_5,     15,  65,  25, 100,  65,  25, 100,   0 },
-	{ XFER_PIO_4,     25,  70,  25, 120,  70,  25, 120,   0 },
-	{ XFER_PIO_3,     30,  80,  70, 180,  80,  70, 180,   0 },
-
-	{ XFER_PIO_2,     30, 290,  40, 330, 100,  90, 240,   0 },
-	{ XFER_PIO_1,     50, 290,  93, 383, 125, 100, 383,   0 },
-	{ XFER_PIO_0,     70, 290, 240, 600, 165, 150, 600,   0 },
-
-/*	{ XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960,   0 }, */
+	{ XFER_UDMA_0,     0,   0,   0,   0,   0,   0,   0, 120 },
+	{ XFER_UDMA_1,     0,   0,   0,   0,   0,   0,   0,  80 },
+	{ XFER_UDMA_2,     0,   0,   0,   0,   0,   0,   0,  60 },
+	{ XFER_UDMA_3,     0,   0,   0,   0,   0,   0,   0,  45 },
+	{ XFER_UDMA_4,     0,   0,   0,   0,   0,   0,   0,  30 },
+	{ XFER_UDMA_5,     0,   0,   0,   0,   0,   0,   0,  20 },
+	{ XFER_UDMA_6,     0,   0,   0,   0,   0,   0,   0,  15 },
 
 	{ 0xFF }
 };
@@ -2845,14 +2822,16 @@ void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
 	if (what & ATA_TIMING_UDMA   ) m->udma    = max(a->udma,    b->udma);
 }
 
-static const struct ata_timing *ata_timing_find_mode(unsigned short speed)
+const struct ata_timing *ata_timing_find_mode(u8 xfer_mode)
 {
-	const struct ata_timing *t;
+	const struct ata_timing *t = ata_timing;
+
+	while (xfer_mode > t->mode)
+		t++;
 
-	for (t = ata_timing; t->mode != speed; t++)
-		if (t->mode == 0xFF)
-			return NULL;
-	return t;
+	if (xfer_mode == t->mode)
+		return t;
+	return NULL;
 }
 
 int ata_timing_compute(struct ata_device *adev, unsigned short speed,
@@ -2927,6 +2906,57 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
 }
 
 /**
+ *	ata_timing_cycle2mode - find xfer mode for the specified cycle duration
+ *	@xfer_shift: ATA_SHIFT_* value for transfer type to examine.
+ *	@cycle: cycle duration in ns
+ *
+ *	Return matching xfer mode for @cycle.  The returned mode is of
+ *	the transfer type specified by @xfer_shift.  If @cycle is too
+ *	slow for @xfer_shift, 0xff is returned.  If @cycle is faster
+ *	than the fastest known mode, the fasted mode is returned.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	Matching xfer_mode, 0xff if no match found.
+ */
+u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle)
+{
+	u8 base_mode = 0xff, last_mode = 0xff;
+	const struct ata_xfer_ent *ent;
+	const struct ata_timing *t;
+
+	for (ent = ata_xfer_tbl; ent->shift >= 0; ent++)
+		if (ent->shift == xfer_shift)
+			base_mode = ent->base;
+
+	for (t = ata_timing_find_mode(base_mode);
+	     t && ata_xfer_mode2shift(t->mode) == xfer_shift; t++) {
+		unsigned short this_cycle;
+
+		switch (xfer_shift) {
+		case ATA_SHIFT_PIO:
+		case ATA_SHIFT_MWDMA:
+			this_cycle = t->cycle;
+			break;
+		case ATA_SHIFT_UDMA:
+			this_cycle = t->udma;
+			break;
+		default:
+			return 0xff;
+		}
+
+		if (cycle > this_cycle)
+			break;
+
+		last_mode = t->mode;
+	}
+
+	return last_mode;
+}
+
+/**
  *	ata_down_xfermask_limit - adjust dev xfer masks downward
  *	@dev: Device to adjust xfer masks
  *	@sel: ATA_DNXFER_* selector
@@ -2944,8 +2974,8 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
 int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
 {
 	char buf[32];
-	unsigned int orig_mask, xfer_mask;
-	unsigned int pio_mask, mwdma_mask, udma_mask;
+	unsigned long orig_mask, xfer_mask;
+	unsigned long pio_mask, mwdma_mask, udma_mask;
 	int quiet, highbit;
 
 	quiet = !!(sel & ATA_DNXFER_QUIET);
@@ -3039,7 +3069,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
 
 	/* Early MWDMA devices do DMA but don't allow DMA mode setting.
 	   Don't fail an MWDMA0 set IFF the device indicates it is in MWDMA0 */
-	if (dev->xfer_shift == ATA_SHIFT_MWDMA && 
+	if (dev->xfer_shift == ATA_SHIFT_MWDMA &&
 	    dev->dma_mode == XFER_MW_DMA_0 &&
 	    (dev->id[63] >> 8) & 1)
 		err_mask &= ~AC_ERR_DEV;
@@ -3089,7 +3119,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 
 	/* step 1: calculate xfer_mask */
 	ata_link_for_each_dev(dev, link) {
-		unsigned int pio_mask, dma_mask;
+		unsigned long pio_mask, dma_mask;
 		unsigned int mode_mask;
 
 		if (!ata_dev_enabled(dev))
@@ -3115,7 +3145,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 		dev->dma_mode = ata_xfer_mask2mode(dma_mask);
 
 		found = 1;
-		if (dev->dma_mode)
+		if (dev->dma_mode != 0xff)
 			used_dma = 1;
 	}
 	if (!found)
@@ -3126,7 +3156,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 		if (!ata_dev_enabled(dev))
 			continue;
 
-		if (!dev->pio_mode) {
+		if (dev->pio_mode == 0xff) {
 			ata_dev_printk(dev, KERN_WARNING, "no PIO support\n");
 			rc = -EINVAL;
 			goto out;
@@ -3140,7 +3170,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 
 	/* step 3: set host DMA timings */
 	ata_link_for_each_dev(dev, link) {
-		if (!ata_dev_enabled(dev) || !dev->dma_mode)
+		if (!ata_dev_enabled(dev) || dev->dma_mode == 0xff)
 			continue;
 
 		dev->xfer_mode = dev->dma_mode;
@@ -3173,31 +3203,6 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 }
 
 /**
- *	ata_set_mode - Program timings and issue SET FEATURES - XFER
- *	@link: link on which timings will be programmed
- *	@r_failed_dev: out paramter for failed device
- *
- *	Set ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
- *	ata_set_mode() fails, pointer to the failing device is
- *	returned in @r_failed_dev.
- *
- *	LOCKING:
- *	PCI/etc. bus probe sem.
- *
- *	RETURNS:
- *	0 on success, negative errno otherwise
- */
-int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
-{
-	struct ata_port *ap = link->ap;
-
-	/* has private set_mode? */
-	if (ap->ops->set_mode)
-		return ap->ops->set_mode(link, r_failed_dev);
-	return ata_do_set_mode(link, r_failed_dev);
-}
-
-/**
  *	ata_tf_to_host - issue ATA taskfile to host controller
  *	@ap: port to which command is being issued
  *	@tf: ATA taskfile register set
@@ -4363,7 +4368,14 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
 	tf.feature = SETFEATURES_XFER;
 	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_POLLING;
 	tf.protocol = ATA_PROT_NODATA;
-	tf.nsect = dev->xfer_mode;
+	/* If we are using IORDY we must send the mode setting command */
+	if (ata_pio_need_iordy(dev))
+		tf.nsect = dev->xfer_mode;
+	/* If the device has IORDY and the controller does not - turn it off */
+ 	else if (ata_id_has_iordy(dev->id))
+		tf.nsect = 0x01;
+	else /* In the ancient relic department - skip all of this */
+		return 0;
 
 	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
 
@@ -4462,17 +4474,13 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
 void ata_sg_clean(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	struct scatterlist *sg = qc->__sg;
+	struct scatterlist *sg = qc->sg;
 	int dir = qc->dma_dir;
 	void *pad_buf = NULL;
 
-	WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
 	WARN_ON(sg == NULL);
 
-	if (qc->flags & ATA_QCFLAG_SINGLE)
-		WARN_ON(qc->n_elem > 1);
-
-	VPRINTK("unmapping %u sg elements\n", qc->n_elem);
+	VPRINTK("unmapping %u sg elements\n", qc->mapped_n_elem);
 
 	/* if we padded the buffer out to 32-bit bound, and data
 	 * xfer direction is from-device, we must copy from the
@@ -4481,31 +4489,20 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
 	if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE))
 		pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
 
-	if (qc->flags & ATA_QCFLAG_SG) {
-		if (qc->n_elem)
-			dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
-		/* restore last sg */
-		sg_last(sg, qc->orig_n_elem)->length += qc->pad_len;
-		if (pad_buf) {
-			struct scatterlist *psg = &qc->pad_sgent;
-			void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
-			memcpy(addr + psg->offset, pad_buf, qc->pad_len);
-			kunmap_atomic(addr, KM_IRQ0);
-		}
-	} else {
-		if (qc->n_elem)
-			dma_unmap_single(ap->dev,
-				sg_dma_address(&sg[0]), sg_dma_len(&sg[0]),
-				dir);
-		/* restore sg */
-		sg->length += qc->pad_len;
-		if (pad_buf)
-			memcpy(qc->buf_virt + sg->length - qc->pad_len,
-			       pad_buf, qc->pad_len);
+	if (qc->mapped_n_elem)
+		dma_unmap_sg(ap->dev, sg, qc->mapped_n_elem, dir);
+	/* restore last sg */
+	if (qc->last_sg)
+		*qc->last_sg = qc->saved_last_sg;
+	if (pad_buf) {
+		struct scatterlist *psg = &qc->extra_sg[1];
+		void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
+		memcpy(addr + psg->offset, pad_buf, qc->pad_len);
+		kunmap_atomic(addr, KM_IRQ0);
 	}
 
 	qc->flags &= ~ATA_QCFLAG_DMAMAP;
-	qc->__sg = NULL;
+	qc->sg = NULL;
 }
 
 /**
@@ -4523,13 +4520,10 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct scatterlist *sg;
-	unsigned int idx;
+	unsigned int si, pi;
 
-	WARN_ON(qc->__sg == NULL);
-	WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
-
-	idx = 0;
-	ata_for_each_sg(sg, qc) {
+	pi = 0;
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		u32 addr, offset;
 		u32 sg_len, len;
 
@@ -4546,18 +4540,17 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
 			if ((offset + sg_len) > 0x10000)
 				len = 0x10000 - offset;
 
-			ap->prd[idx].addr = cpu_to_le32(addr);
-			ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
-			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+			ap->prd[pi].addr = cpu_to_le32(addr);
+			ap->prd[pi].flags_len = cpu_to_le32(len & 0xffff);
+			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
 
-			idx++;
+			pi++;
 			sg_len -= len;
 			addr += len;
 		}
 	}
 
-	if (idx)
-		ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+	ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
 /**
@@ -4577,13 +4570,10 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct scatterlist *sg;
-	unsigned int idx;
-
-	WARN_ON(qc->__sg == NULL);
-	WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+	unsigned int si, pi;
 
-	idx = 0;
-	ata_for_each_sg(sg, qc) {
+	pi = 0;
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		u32 addr, offset;
 		u32 sg_len, len, blen;
 
@@ -4601,25 +4591,24 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc)
 				len = 0x10000 - offset;
 
 			blen = len & 0xffff;
-			ap->prd[idx].addr = cpu_to_le32(addr);
+			ap->prd[pi].addr = cpu_to_le32(addr);
 			if (blen == 0) {
 			   /* Some PATA chipsets like the CS5530 can't
 			      cope with 0x0000 meaning 64K as the spec says */
-				ap->prd[idx].flags_len = cpu_to_le32(0x8000);
+				ap->prd[pi].flags_len = cpu_to_le32(0x8000);
 				blen = 0x8000;
-				ap->prd[++idx].addr = cpu_to_le32(addr + 0x8000);
+				ap->prd[++pi].addr = cpu_to_le32(addr + 0x8000);
 			}
-			ap->prd[idx].flags_len = cpu_to_le32(blen);
-			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+			ap->prd[pi].flags_len = cpu_to_le32(blen);
+			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
 
-			idx++;
+			pi++;
 			sg_len -= len;
 			addr += len;
 		}
 	}
 
-	if (idx)
-		ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+	ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
 /**
@@ -4669,8 +4658,8 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
  */
 static int atapi_qc_may_overflow(struct ata_queued_cmd *qc)
 {
-	if (qc->tf.protocol != ATA_PROT_ATAPI &&
-	    qc->tf.protocol != ATA_PROT_ATAPI_DMA)
+	if (qc->tf.protocol != ATAPI_PROT_PIO &&
+	    qc->tf.protocol != ATAPI_PROT_DMA)
 		return 0;
 
 	if (qc->tf.flags & ATA_TFLAG_WRITE)
@@ -4756,33 +4745,6 @@ void ata_dumb_qc_prep(struct ata_queued_cmd *qc)
 void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
 
 /**
- *	ata_sg_init_one - Associate command with memory buffer
- *	@qc: Command to be associated
- *	@buf: Memory buffer
- *	@buflen: Length of memory buffer, in bytes.
- *
- *	Initialize the data-related elements of queued_cmd @qc
- *	to point to a single memory buffer, @buf of byte length @buflen.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host lock)
- */
-
-void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
-{
-	qc->flags |= ATA_QCFLAG_SINGLE;
-
-	qc->__sg = &qc->sgent;
-	qc->n_elem = 1;
-	qc->orig_n_elem = 1;
-	qc->buf_virt = buf;
-	qc->nbytes = buflen;
-	qc->cursg = qc->__sg;
-
-	sg_init_one(&qc->sgent, buf, buflen);
-}
-
-/**
  *	ata_sg_init - Associate command with scatter-gather table.
  *	@qc: Command to be associated
  *	@sg: Scatter-gather table.
@@ -4795,84 +4757,103 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
  *	LOCKING:
  *	spin_lock_irqsave(host lock)
  */
-
 void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
 		 unsigned int n_elem)
 {
-	qc->flags |= ATA_QCFLAG_SG;
-	qc->__sg = sg;
+	qc->sg = sg;
 	qc->n_elem = n_elem;
-	qc->orig_n_elem = n_elem;
-	qc->cursg = qc->__sg;
+	qc->cursg = qc->sg;
 }
 
-/**
- *	ata_sg_setup_one - DMA-map the memory buffer associated with a command.
- *	@qc: Command with memory buffer to be mapped.
- *
- *	DMA-map the memory buffer associated with queued_cmd @qc.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host lock)
- *
- *	RETURNS:
- *	Zero on success, negative on error.
- */
-
-static int ata_sg_setup_one(struct ata_queued_cmd *qc)
+static unsigned int ata_sg_setup_extra(struct ata_queued_cmd *qc,
+				       unsigned int *n_elem_extra,
+				       unsigned int *nbytes_extra)
 {
 	struct ata_port *ap = qc->ap;
-	int dir = qc->dma_dir;
-	struct scatterlist *sg = qc->__sg;
-	dma_addr_t dma_address;
-	int trim_sg = 0;
+	unsigned int n_elem = qc->n_elem;
+	struct scatterlist *lsg, *copy_lsg = NULL, *tsg = NULL, *esg = NULL;
+
+	*n_elem_extra = 0;
+	*nbytes_extra = 0;
+
+	/* needs padding? */
+	qc->pad_len = qc->nbytes & 3;
+
+	if (likely(!qc->pad_len))
+		return n_elem;
+
+	/* locate last sg and save it */
+	lsg = sg_last(qc->sg, n_elem);
+	qc->last_sg = lsg;
+	qc->saved_last_sg = *lsg;
+
+	sg_init_table(qc->extra_sg, ARRAY_SIZE(qc->extra_sg));
 
-	/* we must lengthen transfers to end on a 32-bit boundary */
-	qc->pad_len = sg->length & 3;
 	if (qc->pad_len) {
+		struct scatterlist *psg = &qc->extra_sg[1];
 		void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
-		struct scatterlist *psg = &qc->pad_sgent;
+		unsigned int offset;
 
 		WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
 
 		memset(pad_buf, 0, ATA_DMA_PAD_SZ);
 
-		if (qc->tf.flags & ATA_TFLAG_WRITE)
-			memcpy(pad_buf, qc->buf_virt + sg->length - qc->pad_len,
-			       qc->pad_len);
+		/* psg->page/offset are used to copy to-be-written
+		 * data in this function or read data in ata_sg_clean.
+		 */
+		offset = lsg->offset + lsg->length - qc->pad_len;
+		sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT),
+			    qc->pad_len, offset_in_page(offset));
+
+		if (qc->tf.flags & ATA_TFLAG_WRITE) {
+			void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
+			memcpy(pad_buf, addr + psg->offset, qc->pad_len);
+			kunmap_atomic(addr, KM_IRQ0);
+		}
 
 		sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
 		sg_dma_len(psg) = ATA_DMA_PAD_SZ;
-		/* trim sg */
-		sg->length -= qc->pad_len;
-		if (sg->length == 0)
-			trim_sg = 1;
 
-		DPRINTK("padding done, sg->length=%u pad_len=%u\n",
-			sg->length, qc->pad_len);
-	}
+		/* Trim the last sg entry and chain the original and
+		 * padding sg lists.
+		 *
+		 * Because chaining consumes one sg entry, one extra
+		 * sg entry is allocated and the last sg entry is
+		 * copied to it if the length isn't zero after padded
+		 * amount is removed.
+		 *
+		 * If the last sg entry is completely replaced by
+		 * padding sg entry, the first sg entry is skipped
+		 * while chaining.
+		 */
+		lsg->length -= qc->pad_len;
+		if (lsg->length) {
+			copy_lsg = &qc->extra_sg[0];
+			tsg = &qc->extra_sg[0];
+		} else {
+			n_elem--;
+			tsg = &qc->extra_sg[1];
+		}
 
-	if (trim_sg) {
-		qc->n_elem--;
-		goto skip_map;
-	}
+		esg = &qc->extra_sg[1];
 
-	dma_address = dma_map_single(ap->dev, qc->buf_virt,
-				     sg->length, dir);
-	if (dma_mapping_error(dma_address)) {
-		/* restore sg */
-		sg->length += qc->pad_len;
-		return -1;
+		(*n_elem_extra)++;
+		(*nbytes_extra) += 4 - qc->pad_len;
 	}
 
-	sg_dma_address(sg) = dma_address;
-	sg_dma_len(sg) = sg->length;
+	if (copy_lsg)
+		sg_set_page(copy_lsg, sg_page(lsg), lsg->length, lsg->offset);
 
-skip_map:
-	DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
-		qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+	sg_chain(lsg, 1, tsg);
+	sg_mark_end(esg);
 
-	return 0;
+	/* sglist can't start with chaining sg entry, fast forward */
+	if (qc->sg == lsg) {
+		qc->sg = tsg;
+		qc->cursg = tsg;
+	}
+
+	return n_elem;
 }
 
 /**
@@ -4888,75 +4869,30 @@ skip_map:
  *	Zero on success, negative on error.
  *
  */
-
 static int ata_sg_setup(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	struct scatterlist *sg = qc->__sg;
-	struct scatterlist *lsg = sg_last(qc->__sg, qc->n_elem);
-	int n_elem, pre_n_elem, dir, trim_sg = 0;
+	unsigned int n_elem, n_elem_extra, nbytes_extra;
 
 	VPRINTK("ENTER, ata%u\n", ap->print_id);
-	WARN_ON(!(qc->flags & ATA_QCFLAG_SG));
 
-	/* we must lengthen transfers to end on a 32-bit boundary */
-	qc->pad_len = lsg->length & 3;
-	if (qc->pad_len) {
-		void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ);
-		struct scatterlist *psg = &qc->pad_sgent;
-		unsigned int offset;
-
-		WARN_ON(qc->dev->class != ATA_DEV_ATAPI);
+	n_elem = ata_sg_setup_extra(qc, &n_elem_extra, &nbytes_extra);
 
-		memset(pad_buf, 0, ATA_DMA_PAD_SZ);
-
-		/*
-		 * psg->page/offset are used to copy to-be-written
-		 * data in this function or read data in ata_sg_clean.
-		 */
-		offset = lsg->offset + lsg->length - qc->pad_len;
-		sg_init_table(psg, 1);
-		sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT),
-				qc->pad_len, offset_in_page(offset));
-
-		if (qc->tf.flags & ATA_TFLAG_WRITE) {
-			void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
-			memcpy(pad_buf, addr + psg->offset, qc->pad_len);
-			kunmap_atomic(addr, KM_IRQ0);
+	if (n_elem) {
+		n_elem = dma_map_sg(ap->dev, qc->sg, n_elem, qc->dma_dir);
+		if (n_elem < 1) {
+			/* restore last sg */
+			if (qc->last_sg)
+				*qc->last_sg = qc->saved_last_sg;
+			return -1;
 		}
-
-		sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
-		sg_dma_len(psg) = ATA_DMA_PAD_SZ;
-		/* trim last sg */
-		lsg->length -= qc->pad_len;
-		if (lsg->length == 0)
-			trim_sg = 1;
-
-		DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n",
-			qc->n_elem - 1, lsg->length, qc->pad_len);
-	}
-
-	pre_n_elem = qc->n_elem;
-	if (trim_sg && pre_n_elem)
-		pre_n_elem--;
-
-	if (!pre_n_elem) {
-		n_elem = 0;
-		goto skip_map;
-	}
-
-	dir = qc->dma_dir;
-	n_elem = dma_map_sg(ap->dev, sg, pre_n_elem, dir);
-	if (n_elem < 1) {
-		/* restore last sg */
-		lsg->length += qc->pad_len;
-		return -1;
+		DPRINTK("%d sg elements mapped\n", n_elem);
 	}
 
-	DPRINTK("%d sg elements mapped\n", n_elem);
-
-skip_map:
-	qc->n_elem = n_elem;
+	qc->n_elem = qc->mapped_n_elem = n_elem;
+	qc->n_elem += n_elem_extra;
+	qc->nbytes += nbytes_extra;
+	qc->flags |= ATA_QCFLAG_DMAMAP;
 
 	return 0;
 }
@@ -4985,63 +4921,77 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
 
 /**
  *	ata_data_xfer - Transfer data by PIO
- *	@adev: device to target
+ *	@dev: device to target
  *	@buf: data buffer
  *	@buflen: buffer length
- *	@write_data: read/write
+ *	@rw: read/write
  *
  *	Transfer data from/to the device data register by PIO.
  *
  *	LOCKING:
  *	Inherited from caller.
+ *
+ *	RETURNS:
+ *	Bytes consumed.
  */
-void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
-		   unsigned int buflen, int write_data)
+unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf,
+			   unsigned int buflen, int rw)
 {
-	struct ata_port *ap = adev->link->ap;
+	struct ata_port *ap = dev->link->ap;
+	void __iomem *data_addr = ap->ioaddr.data_addr;
 	unsigned int words = buflen >> 1;
 
 	/* Transfer multiple of 2 bytes */
-	if (write_data)
-		iowrite16_rep(ap->ioaddr.data_addr, buf, words);
+	if (rw == READ)
+		ioread16_rep(data_addr, buf, words);
 	else
-		ioread16_rep(ap->ioaddr.data_addr, buf, words);
+		iowrite16_rep(data_addr, buf, words);
 
 	/* Transfer trailing 1 byte, if any. */
 	if (unlikely(buflen & 0x01)) {
-		u16 align_buf[1] = { 0 };
+		__le16 align_buf[1] = { 0 };
 		unsigned char *trailing_buf = buf + buflen - 1;
 
-		if (write_data) {
-			memcpy(align_buf, trailing_buf, 1);
-			iowrite16(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr);
-		} else {
-			align_buf[0] = cpu_to_le16(ioread16(ap->ioaddr.data_addr));
+		if (rw == READ) {
+			align_buf[0] = cpu_to_le16(ioread16(data_addr));
 			memcpy(trailing_buf, align_buf, 1);
+		} else {
+			memcpy(align_buf, trailing_buf, 1);
+			iowrite16(le16_to_cpu(align_buf[0]), data_addr);
 		}
+		words++;
 	}
+
+	return words << 1;
 }
 
 /**
  *	ata_data_xfer_noirq - Transfer data by PIO
- *	@adev: device to target
+ *	@dev: device to target
  *	@buf: data buffer
  *	@buflen: buffer length
- *	@write_data: read/write
+ *	@rw: read/write
  *
  *	Transfer data from/to the device data register by PIO. Do the
  *	transfer with interrupts disabled.
  *
  *	LOCKING:
  *	Inherited from caller.
+ *
+ *	RETURNS:
+ *	Bytes consumed.
  */
-void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
-			 unsigned int buflen, int write_data)
+unsigned int ata_data_xfer_noirq(struct ata_device *dev, unsigned char *buf,
+				 unsigned int buflen, int rw)
 {
 	unsigned long flags;
+	unsigned int consumed;
+
 	local_irq_save(flags);
-	ata_data_xfer(adev, buf, buflen, write_data);
+	consumed = ata_data_xfer(dev, buf, buflen, rw);
 	local_irq_restore(flags);
+
+	return consumed;
 }
 
 
@@ -5152,13 +5102,13 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
 	ata_altstatus(ap); /* flush */
 
 	switch (qc->tf.protocol) {
-	case ATA_PROT_ATAPI:
+	case ATAPI_PROT_PIO:
 		ap->hsm_task_state = HSM_ST;
 		break;
-	case ATA_PROT_ATAPI_NODATA:
+	case ATAPI_PROT_NODATA:
 		ap->hsm_task_state = HSM_ST_LAST;
 		break;
-	case ATA_PROT_ATAPI_DMA:
+	case ATAPI_PROT_DMA:
 		ap->hsm_task_state = HSM_ST_LAST;
 		/* initiate bmdma */
 		ap->ops->bmdma_start(qc);
@@ -5300,12 +5250,15 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
 	bytes = (bc_hi << 8) | bc_lo;
 
 	/* shall be cleared to zero, indicating xfer of data */
-	if (ireason & (1 << 0))
+	if (unlikely(ireason & (1 << 0)))
 		goto err_out;
 
 	/* make sure transfer direction matches expected */
 	i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
-	if (do_write != i_write)
+	if (unlikely(do_write != i_write))
+		goto err_out;
+
+	if (unlikely(!bytes))
 		goto err_out;
 
 	VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes);
@@ -5341,7 +5294,7 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *q
 		    (qc->tf.flags & ATA_TFLAG_WRITE))
 		    return 1;
 
-		if (is_atapi_taskfile(&qc->tf) &&
+		if (ata_is_atapi(qc->tf.protocol) &&
 		    !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
 			return 1;
 	}
@@ -5506,7 +5459,7 @@ fsm_start:
 
 	case HSM_ST:
 		/* complete command or read/write the data register */
-		if (qc->tf.protocol == ATA_PROT_ATAPI) {
+		if (qc->tf.protocol == ATAPI_PROT_PIO) {
 			/* ATAPI PIO protocol */
 			if ((status & ATA_DRQ) == 0) {
 				/* No more data to transfer or device error.
@@ -5664,7 +5617,7 @@ fsm_start:
 		msleep(2);
 		status = ata_busy_wait(ap, ATA_BUSY, 10);
 		if (status & ATA_BUSY) {
-			ata_port_queue_task(ap, ata_pio_task, qc, ATA_SHORT_PAUSE);
+			ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE);
 			return;
 		}
 	}
@@ -5805,6 +5758,22 @@ static void fill_result_tf(struct ata_queued_cmd *qc)
 	ap->ops->tf_read(ap, &qc->result_tf);
 }
 
+static void ata_verify_xfer(struct ata_queued_cmd *qc)
+{
+	struct ata_device *dev = qc->dev;
+
+	if (ata_tag_internal(qc->tag))
+		return;
+
+	if (ata_is_nodata(qc->tf.protocol))
+		return;
+
+	if ((dev->mwdma_mask || dev->udma_mask) && ata_is_pio(qc->tf.protocol))
+		return;
+
+	dev->flags &= ~ATA_DFLAG_DUBIOUS_XFER;
+}
+
 /**
  *	ata_qc_complete - Complete an active ATA command
  *	@qc: Command to complete
@@ -5876,6 +5845,9 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
 			break;
 		}
 
+		if (unlikely(dev->flags & ATA_DFLAG_DUBIOUS_XFER))
+			ata_verify_xfer(qc);
+
 		__ata_qc_complete(qc);
 	} else {
 		if (qc->flags & ATA_QCFLAG_EH_SCHEDULED)
@@ -5938,30 +5910,6 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active,
 	return nr_done;
 }
 
-static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
-{
-	struct ata_port *ap = qc->ap;
-
-	switch (qc->tf.protocol) {
-	case ATA_PROT_NCQ:
-	case ATA_PROT_DMA:
-	case ATA_PROT_ATAPI_DMA:
-		return 1;
-
-	case ATA_PROT_ATAPI:
-	case ATA_PROT_PIO:
-		if (ap->flags & ATA_FLAG_PIO_DMA)
-			return 1;
-
-		/* fall through */
-
-	default:
-		return 0;
-	}
-
-	/* never reached */
-}
-
 /**
  *	ata_qc_issue - issue taskfile to device
  *	@qc: command to issue to device
@@ -5978,6 +5926,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct ata_link *link = qc->dev->link;
+	u8 prot = qc->tf.protocol;
 
 	/* Make sure only one non-NCQ command is outstanding.  The
 	 * check is skipped for old EH because it reuses active qc to
@@ -5985,7 +5934,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
 	 */
 	WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag));
 
-	if (qc->tf.protocol == ATA_PROT_NCQ) {
+	if (ata_is_ncq(prot)) {
 		WARN_ON(link->sactive & (1 << qc->tag));
 
 		if (!link->sactive)
@@ -6001,17 +5950,18 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
 	qc->flags |= ATA_QCFLAG_ACTIVE;
 	ap->qc_active |= 1 << qc->tag;
 
-	if (ata_should_dma_map(qc)) {
-		if (qc->flags & ATA_QCFLAG_SG) {
-			if (ata_sg_setup(qc))
-				goto sg_err;
-		} else if (qc->flags & ATA_QCFLAG_SINGLE) {
-			if (ata_sg_setup_one(qc))
-				goto sg_err;
-		}
-	} else {
-		qc->flags &= ~ATA_QCFLAG_DMAMAP;
-	}
+	/* We guarantee to LLDs that they will have at least one
+	 * non-zero sg if the command is a data command.
+	 */
+	BUG_ON(ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes));
+
+	/* ata_sg_setup() may update nbytes */
+	qc->raw_nbytes = qc->nbytes;
+
+	if (ata_is_dma(prot) || (ata_is_pio(prot) &&
+				 (ap->flags & ATA_FLAG_PIO_DMA)))
+		if (ata_sg_setup(qc))
+			goto sg_err;
 
 	/* if device is sleeping, schedule softreset and abort the link */
 	if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) {
@@ -6029,7 +5979,6 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
 	return;
 
 sg_err:
-	qc->flags &= ~ATA_QCFLAG_DMAMAP;
 	qc->err_mask |= AC_ERR_SYSTEM;
 err:
 	ata_qc_complete(qc);
@@ -6064,11 +6013,11 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 		switch (qc->tf.protocol) {
 		case ATA_PROT_PIO:
 		case ATA_PROT_NODATA:
-		case ATA_PROT_ATAPI:
-		case ATA_PROT_ATAPI_NODATA:
+		case ATAPI_PROT_PIO:
+		case ATAPI_PROT_NODATA:
 			qc->tf.flags |= ATA_TFLAG_POLLING;
 			break;
-		case ATA_PROT_ATAPI_DMA:
+		case ATAPI_PROT_DMA:
 			if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
 				/* see ata_dma_blacklisted() */
 				BUG();
@@ -6091,7 +6040,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 		ap->hsm_task_state = HSM_ST_LAST;
 
 		if (qc->tf.flags & ATA_TFLAG_POLLING)
-			ata_port_queue_task(ap, ata_pio_task, qc, 0);
+			ata_pio_queue_task(ap, qc, 0);
 
 		break;
 
@@ -6113,7 +6062,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 		if (qc->tf.flags & ATA_TFLAG_WRITE) {
 			/* PIO data out protocol */
 			ap->hsm_task_state = HSM_ST_FIRST;
-			ata_port_queue_task(ap, ata_pio_task, qc, 0);
+			ata_pio_queue_task(ap, qc, 0);
 
 			/* always send first data block using
 			 * the ata_pio_task() codepath.
@@ -6123,7 +6072,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 			ap->hsm_task_state = HSM_ST;
 
 			if (qc->tf.flags & ATA_TFLAG_POLLING)
-				ata_port_queue_task(ap, ata_pio_task, qc, 0);
+				ata_pio_queue_task(ap, qc, 0);
 
 			/* if polling, ata_pio_task() handles the rest.
 			 * otherwise, interrupt handler takes over from here.
@@ -6132,8 +6081,8 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 
 		break;
 
-	case ATA_PROT_ATAPI:
-	case ATA_PROT_ATAPI_NODATA:
+	case ATAPI_PROT_PIO:
+	case ATAPI_PROT_NODATA:
 		if (qc->tf.flags & ATA_TFLAG_POLLING)
 			ata_qc_set_polling(qc);
 
@@ -6144,10 +6093,10 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 		/* send cdb by polling if no cdb interrupt */
 		if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) ||
 		    (qc->tf.flags & ATA_TFLAG_POLLING))
-			ata_port_queue_task(ap, ata_pio_task, qc, 0);
+			ata_pio_queue_task(ap, qc, 0);
 		break;
 
-	case ATA_PROT_ATAPI_DMA:
+	case ATAPI_PROT_DMA:
 		WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
 
 		ap->ops->tf_load(ap, &qc->tf);	 /* load tf registers */
@@ -6156,7 +6105,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
 
 		/* send cdb by polling if no cdb interrupt */
 		if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
-			ata_port_queue_task(ap, ata_pio_task, qc, 0);
+			ata_pio_queue_task(ap, qc, 0);
 		break;
 
 	default:
@@ -6200,15 +6149,15 @@ inline unsigned int ata_host_intr(struct ata_port *ap,
 		 */
 
 		/* Check the ATA_DFLAG_CDB_INTR flag is enough here.
-		 * The flag was turned on only for atapi devices.
-		 * No need to check is_atapi_taskfile(&qc->tf) again.
+		 * The flag was turned on only for atapi devices.  No
+		 * need to check ata_is_atapi(qc->tf.protocol) again.
 		 */
 		if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
 			goto idle_irq;
 		break;
 	case HSM_ST_LAST:
 		if (qc->tf.protocol == ATA_PROT_DMA ||
-		    qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+		    qc->tf.protocol == ATAPI_PROT_DMA) {
 			/* check status of DMA engine */
 			host_stat = ap->ops->bmdma_status(ap);
 			VPRINTK("ata%u: host_stat 0x%X\n",
@@ -6250,7 +6199,7 @@ inline unsigned int ata_host_intr(struct ata_port *ap,
 	ata_hsm_move(ap, qc, status, 0);
 
 	if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
-				       qc->tf.protocol == ATA_PROT_ATAPI_DMA))
+				       qc->tf.protocol == ATAPI_PROT_DMA))
 		ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
 
 	return 1;	/* irq handled */
@@ -6772,7 +6721,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
 	ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
 #endif
 
-	INIT_DELAYED_WORK(&ap->port_task, NULL);
+	INIT_DELAYED_WORK(&ap->port_task, ata_pio_task);
 	INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
 	INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
 	INIT_LIST_HEAD(&ap->eh_done_q);
@@ -7589,7 +7538,6 @@ EXPORT_SYMBOL_GPL(ata_host_register);
 EXPORT_SYMBOL_GPL(ata_host_activate);
 EXPORT_SYMBOL_GPL(ata_host_detach);
 EXPORT_SYMBOL_GPL(ata_sg_init);
-EXPORT_SYMBOL_GPL(ata_sg_init_one);
 EXPORT_SYMBOL_GPL(ata_hsm_move);
 EXPORT_SYMBOL_GPL(ata_qc_complete);
 EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
@@ -7601,6 +7549,13 @@ EXPORT_SYMBOL_GPL(ata_std_dev_select);
 EXPORT_SYMBOL_GPL(sata_print_link_status);
 EXPORT_SYMBOL_GPL(ata_tf_to_fis);
 EXPORT_SYMBOL_GPL(ata_tf_from_fis);
+EXPORT_SYMBOL_GPL(ata_pack_xfermask);
+EXPORT_SYMBOL_GPL(ata_unpack_xfermask);
+EXPORT_SYMBOL_GPL(ata_xfer_mask2mode);
+EXPORT_SYMBOL_GPL(ata_xfer_mode2mask);
+EXPORT_SYMBOL_GPL(ata_xfer_mode2shift);
+EXPORT_SYMBOL_GPL(ata_mode_string);
+EXPORT_SYMBOL_GPL(ata_id_xfermask);
 EXPORT_SYMBOL_GPL(ata_check_status);
 EXPORT_SYMBOL_GPL(ata_altstatus);
 EXPORT_SYMBOL_GPL(ata_exec_command);
@@ -7643,7 +7598,6 @@ EXPORT_SYMBOL_GPL(ata_wait_register);
 EXPORT_SYMBOL_GPL(ata_busy_sleep);
 EXPORT_SYMBOL_GPL(ata_wait_after_reset);
 EXPORT_SYMBOL_GPL(ata_wait_ready);
-EXPORT_SYMBOL_GPL(ata_port_queue_task);
 EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
@@ -7662,18 +7616,20 @@ EXPORT_SYMBOL_GPL(ata_host_resume);
 #endif /* CONFIG_PM */
 EXPORT_SYMBOL_GPL(ata_id_string);
 EXPORT_SYMBOL_GPL(ata_id_c_string);
-EXPORT_SYMBOL_GPL(ata_id_to_dma_mode);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
 
 EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
+EXPORT_SYMBOL_GPL(ata_timing_find_mode);
 EXPORT_SYMBOL_GPL(ata_timing_compute);
 EXPORT_SYMBOL_GPL(ata_timing_merge);
+EXPORT_SYMBOL_GPL(ata_timing_cycle2mode);
 
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL_GPL(pci_test_config_bits);
 EXPORT_SYMBOL_GPL(ata_pci_init_sff_host);
 EXPORT_SYMBOL_GPL(ata_pci_init_bmdma);
 EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host);
+EXPORT_SYMBOL_GPL(ata_pci_activate_sff_host);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
 #ifdef CONFIG_PM
@@ -7715,4 +7671,5 @@ EXPORT_SYMBOL_GPL(ata_dev_try_classify);
 EXPORT_SYMBOL_GPL(ata_cable_40wire);
 EXPORT_SYMBOL_GPL(ata_cable_80wire);
 EXPORT_SYMBOL_GPL(ata_cable_unknown);
+EXPORT_SYMBOL_GPL(ata_cable_ignore);
 EXPORT_SYMBOL_GPL(ata_cable_sata);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 21a81cd148e4..4e31071acc02 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -46,9 +46,26 @@
 #include "libata.h"
 
 enum {
+	/* speed down verdicts */
 	ATA_EH_SPDN_NCQ_OFF		= (1 << 0),
 	ATA_EH_SPDN_SPEED_DOWN		= (1 << 1),
 	ATA_EH_SPDN_FALLBACK_TO_PIO	= (1 << 2),
+	ATA_EH_SPDN_KEEP_ERRORS		= (1 << 3),
+
+	/* error flags */
+	ATA_EFLAG_IS_IO			= (1 << 0),
+	ATA_EFLAG_DUBIOUS_XFER		= (1 << 1),
+
+	/* error categories */
+	ATA_ECAT_NONE			= 0,
+	ATA_ECAT_ATA_BUS		= 1,
+	ATA_ECAT_TOUT_HSM		= 2,
+	ATA_ECAT_UNK_DEV		= 3,
+	ATA_ECAT_DUBIOUS_NONE		= 4,
+	ATA_ECAT_DUBIOUS_ATA_BUS	= 5,
+	ATA_ECAT_DUBIOUS_TOUT_HSM	= 6,
+	ATA_ECAT_DUBIOUS_UNK_DEV	= 7,
+	ATA_ECAT_NR			= 8,
 };
 
 /* Waiting in ->prereset can never be reliable.  It's sometimes nice
@@ -213,12 +230,13 @@ void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
 	if (offset < 0)
 		ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start);
 	else
-		ata_port_desc(ap, "%s 0x%llx", name, start + offset);
+		ata_port_desc(ap, "%s 0x%llx", name,
+				start + (unsigned long long)offset);
 }
 
 #endif /* CONFIG_PCI */
 
-static void ata_ering_record(struct ata_ering *ering, int is_io,
+static void ata_ering_record(struct ata_ering *ering, unsigned int eflags,
 			     unsigned int err_mask)
 {
 	struct ata_ering_entry *ent;
@@ -229,11 +247,20 @@ static void ata_ering_record(struct ata_ering *ering, int is_io,
 	ering->cursor %= ATA_ERING_SIZE;
 
 	ent = &ering->ring[ering->cursor];
-	ent->is_io = is_io;
+	ent->eflags = eflags;
 	ent->err_mask = err_mask;
 	ent->timestamp = get_jiffies_64();
 }
 
+static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering)
+{
+	struct ata_ering_entry *ent = &ering->ring[ering->cursor];
+
+	if (ent->err_mask)
+		return ent;
+	return NULL;
+}
+
 static void ata_ering_clear(struct ata_ering *ering)
 {
 	memset(ering, 0, sizeof(*ering));
@@ -445,9 +472,20 @@ void ata_scsi_error(struct Scsi_Host *host)
 		spin_lock_irqsave(ap->lock, flags);
 
 		__ata_port_for_each_link(link, ap) {
+			struct ata_eh_context *ehc = &link->eh_context;
+			struct ata_device *dev;
+
 			memset(&link->eh_context, 0, sizeof(link->eh_context));
 			link->eh_context.i = link->eh_info;
 			memset(&link->eh_info, 0, sizeof(link->eh_info));
+
+			ata_link_for_each_dev(dev, link) {
+				int devno = dev->devno;
+
+				ehc->saved_xfer_mode[devno] = dev->xfer_mode;
+				if (ata_ncq_enabled(dev))
+					ehc->saved_ncq_enabled |= 1 << devno;
+			}
 		}
 
 		ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
@@ -1260,10 +1298,10 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
 
 	/* is it pointless to prefer PIO for "safety reasons"? */
 	if (ap->flags & ATA_FLAG_PIO_DMA) {
-		tf.protocol = ATA_PROT_ATAPI_DMA;
+		tf.protocol = ATAPI_PROT_DMA;
 		tf.feature |= ATAPI_PKT_DMA;
 	} else {
-		tf.protocol = ATA_PROT_ATAPI;
+		tf.protocol = ATAPI_PROT_PIO;
 		tf.lbam = SCSI_SENSE_BUFFERSIZE;
 		tf.lbah = 0;
 	}
@@ -1451,20 +1489,29 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
 	return action;
 }
 
-static int ata_eh_categorize_error(int is_io, unsigned int err_mask)
+static int ata_eh_categorize_error(unsigned int eflags, unsigned int err_mask,
+				   int *xfer_ok)
 {
+	int base = 0;
+
+	if (!(eflags & ATA_EFLAG_DUBIOUS_XFER))
+		*xfer_ok = 1;
+
+	if (!*xfer_ok)
+		base = ATA_ECAT_DUBIOUS_NONE;
+
 	if (err_mask & AC_ERR_ATA_BUS)
-		return 1;
+		return base + ATA_ECAT_ATA_BUS;
 
 	if (err_mask & AC_ERR_TIMEOUT)
-		return 2;
+		return base + ATA_ECAT_TOUT_HSM;
 
-	if (is_io) {
+	if (eflags & ATA_EFLAG_IS_IO) {
 		if (err_mask & AC_ERR_HSM)
-			return 2;
+			return base + ATA_ECAT_TOUT_HSM;
 		if ((err_mask &
 		     (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV)
-			return 3;
+			return base + ATA_ECAT_UNK_DEV;
 	}
 
 	return 0;
@@ -1472,18 +1519,22 @@ static int ata_eh_categorize_error(int is_io, unsigned int err_mask)
 
 struct speed_down_verdict_arg {
 	u64 since;
-	int nr_errors[4];
+	int xfer_ok;
+	int nr_errors[ATA_ECAT_NR];
 };
 
 static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
 {
 	struct speed_down_verdict_arg *arg = void_arg;
-	int cat = ata_eh_categorize_error(ent->is_io, ent->err_mask);
+	int cat;
 
 	if (ent->timestamp < arg->since)
 		return -1;
 
+	cat = ata_eh_categorize_error(ent->eflags, ent->err_mask,
+				      &arg->xfer_ok);
 	arg->nr_errors[cat]++;
+
 	return 0;
 }
 
@@ -1495,22 +1546,48 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
  *	whether NCQ needs to be turned off, transfer speed should be
  *	stepped down, or falling back to PIO is necessary.
  *
- *	Cat-1 is ATA_BUS error for any command.
+ *	ECAT_ATA_BUS	: ATA_BUS error for any command
+ *
+ *	ECAT_TOUT_HSM	: TIMEOUT for any command or HSM violation for
+ *			  IO commands
+ *
+ *	ECAT_UNK_DEV	: Unknown DEV error for IO commands
+ *
+ *	ECAT_DUBIOUS_*	: Identical to above three but occurred while
+ *			  data transfer hasn't been verified.
+ *
+ *	Verdicts are
+ *
+ *	NCQ_OFF		: Turn off NCQ.
+ *
+ *	SPEED_DOWN	: Speed down transfer speed but don't fall back
+ *			  to PIO.
+ *
+ *	FALLBACK_TO_PIO	: Fall back to PIO.
+ *
+ *	Even if multiple verdicts are returned, only one action is
+ *	taken per error.  An action triggered by non-DUBIOUS errors
+ *	clears ering, while one triggered by DUBIOUS_* errors doesn't.
+ *	This is to expedite speed down decisions right after device is
+ *	initially configured.
  *
- *	Cat-2 is TIMEOUT for any command or HSM violation for known
- *	supported commands.
+ *	The followings are speed down rules.  #1 and #2 deal with
+ *	DUBIOUS errors.
  *
- *	Cat-3 is is unclassified DEV error for known supported
- *	command.
+ *	1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors
+ *	   occurred during last 5 mins, SPEED_DOWN and FALLBACK_TO_PIO.
  *
- *	NCQ needs to be turned off if there have been more than 3
- *	Cat-2 + Cat-3 errors during last 10 minutes.
+ *	2. If more than one DUBIOUS_TOUT_HSM or DUBIOUS_UNK_DEV errors
+ *	   occurred during last 5 mins, NCQ_OFF.
  *
- *	Speed down is necessary if there have been more than 3 Cat-1 +
- *	Cat-2 errors or 10 Cat-3 errors during last 10 minutes.
+ *	3. If more than 8 ATA_BUS, TOUT_HSM or UNK_DEV errors
+ *	   ocurred during last 5 mins, FALLBACK_TO_PIO
  *
- *	Falling back to PIO mode is necessary if there have been more
- *	than 10 Cat-1 + Cat-2 + Cat-3 errors during last 5 minutes.
+ *	4. If more than 3 TOUT_HSM or UNK_DEV errors occurred
+ *	   during last 10 mins, NCQ_OFF.
+ *
+ *	5. If more than 3 ATA_BUS or TOUT_HSM errors, or more than 6
+ *	   UNK_DEV errors occurred during last 10 mins, SPEED_DOWN.
  *
  *	LOCKING:
  *	Inherited from caller.
@@ -1525,23 +1602,38 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
 	struct speed_down_verdict_arg arg;
 	unsigned int verdict = 0;
 
-	/* scan past 10 mins of error history */
+	/* scan past 5 mins of error history */
 	memset(&arg, 0, sizeof(arg));
-	arg.since = j64 - min(j64, j10mins);
+	arg.since = j64 - min(j64, j5mins);
 	ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg);
 
-	if (arg.nr_errors[2] + arg.nr_errors[3] > 3)
-		verdict |= ATA_EH_SPDN_NCQ_OFF;
-	if (arg.nr_errors[1] + arg.nr_errors[2] > 3 || arg.nr_errors[3] > 10)
-		verdict |= ATA_EH_SPDN_SPEED_DOWN;
+	if (arg.nr_errors[ATA_ECAT_DUBIOUS_ATA_BUS] +
+	    arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] > 1)
+		verdict |= ATA_EH_SPDN_SPEED_DOWN |
+			ATA_EH_SPDN_FALLBACK_TO_PIO | ATA_EH_SPDN_KEEP_ERRORS;
 
-	/* scan past 3 mins of error history */
+	if (arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] +
+	    arg.nr_errors[ATA_ECAT_DUBIOUS_UNK_DEV] > 1)
+		verdict |= ATA_EH_SPDN_NCQ_OFF | ATA_EH_SPDN_KEEP_ERRORS;
+
+	if (arg.nr_errors[ATA_ECAT_ATA_BUS] +
+	    arg.nr_errors[ATA_ECAT_TOUT_HSM] +
+	    arg.nr_errors[ATA_ECAT_UNK_DEV] > 6)
+		verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO;
+
+	/* scan past 10 mins of error history */
 	memset(&arg, 0, sizeof(arg));
-	arg.since = j64 - min(j64, j5mins);
+	arg.since = j64 - min(j64, j10mins);
 	ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg);
 
-	if (arg.nr_errors[1] + arg.nr_errors[2] + arg.nr_errors[3] > 10)
-		verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO;
+	if (arg.nr_errors[ATA_ECAT_TOUT_HSM] +
+	    arg.nr_errors[ATA_ECAT_UNK_DEV] > 3)
+		verdict |= ATA_EH_SPDN_NCQ_OFF;
+
+	if (arg.nr_errors[ATA_ECAT_ATA_BUS] +
+	    arg.nr_errors[ATA_ECAT_TOUT_HSM] > 3 ||
+	    arg.nr_errors[ATA_ECAT_UNK_DEV] > 6)
+		verdict |= ATA_EH_SPDN_SPEED_DOWN;
 
 	return verdict;
 }
@@ -1549,7 +1641,7 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
 /**
  *	ata_eh_speed_down - record error and speed down if necessary
  *	@dev: Failed device
- *	@is_io: Did the device fail during normal IO?
+ *	@eflags: mask of ATA_EFLAG_* flags
  *	@err_mask: err_mask of the error
  *
  *	Record error and examine error history to determine whether
@@ -1563,18 +1655,20 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
  *	RETURNS:
  *	Determined recovery action.
  */
-static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
-				      unsigned int err_mask)
+static unsigned int ata_eh_speed_down(struct ata_device *dev,
+				unsigned int eflags, unsigned int err_mask)
 {
+	struct ata_link *link = dev->link;
+	int xfer_ok = 0;
 	unsigned int verdict;
 	unsigned int action = 0;
 
 	/* don't bother if Cat-0 error */
-	if (ata_eh_categorize_error(is_io, err_mask) == 0)
+	if (ata_eh_categorize_error(eflags, err_mask, &xfer_ok) == 0)
 		return 0;
 
 	/* record error and determine whether speed down is necessary */
-	ata_ering_record(&dev->ering, is_io, err_mask);
+	ata_ering_record(&dev->ering, eflags, err_mask);
 	verdict = ata_eh_speed_down_verdict(dev);
 
 	/* turn off NCQ? */
@@ -1590,7 +1684,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
 	/* speed down? */
 	if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
 		/* speed down SATA link speed if possible */
-		if (sata_down_spd_limit(dev->link) == 0) {
+		if (sata_down_spd_limit(link) == 0) {
 			action |= ATA_EH_HARDRESET;
 			goto done;
 		}
@@ -1618,10 +1712,10 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
 	}
 
 	/* Fall back to PIO?  Slowing down to PIO is meaningless for
-	 * SATA.  Consider it only for PATA.
+	 * SATA ATA devices.  Consider it only for PATA and SATAPI.
 	 */
 	if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) &&
-	    (dev->link->ap->cbl != ATA_CBL_SATA) &&
+	    (link->ap->cbl != ATA_CBL_SATA || dev->class == ATA_DEV_ATAPI) &&
 	    (dev->xfer_shift != ATA_SHIFT_PIO)) {
 		if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) {
 			dev->spdn_cnt = 0;
@@ -1633,7 +1727,8 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
 	return 0;
  done:
 	/* device has been slowed down, blow error history */
-	ata_ering_clear(&dev->ering);
+	if (!(verdict & ATA_EH_SPDN_KEEP_ERRORS))
+		ata_ering_clear(&dev->ering);
 	return action;
 }
 
@@ -1653,8 +1748,8 @@ static void ata_eh_link_autopsy(struct ata_link *link)
 	struct ata_port *ap = link->ap;
 	struct ata_eh_context *ehc = &link->eh_context;
 	struct ata_device *dev;
-	unsigned int all_err_mask = 0;
-	int tag, is_io = 0;
+	unsigned int all_err_mask = 0, eflags = 0;
+	int tag;
 	u32 serror;
 	int rc;
 
@@ -1713,15 +1808,15 @@ static void ata_eh_link_autopsy(struct ata_link *link)
 		ehc->i.dev = qc->dev;
 		all_err_mask |= qc->err_mask;
 		if (qc->flags & ATA_QCFLAG_IO)
-			is_io = 1;
+			eflags |= ATA_EFLAG_IS_IO;
 	}
 
 	/* enforce default EH actions */
 	if (ap->pflags & ATA_PFLAG_FROZEN ||
 	    all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
 		ehc->i.action |= ATA_EH_SOFTRESET;
-	else if ((is_io && all_err_mask) ||
-		 (!is_io && (all_err_mask & ~AC_ERR_DEV)))
+	else if (((eflags & ATA_EFLAG_IS_IO) && all_err_mask) ||
+		 (!(eflags & ATA_EFLAG_IS_IO) && (all_err_mask & ~AC_ERR_DEV)))
 		ehc->i.action |= ATA_EH_REVALIDATE;
 
 	/* If we have offending qcs and the associated failed device,
@@ -1743,8 +1838,11 @@ static void ata_eh_link_autopsy(struct ata_link *link)
 		      ata_dev_enabled(link->device))))
 	    dev = link->device;
 
-	if (dev)
-		ehc->i.action |= ata_eh_speed_down(dev, is_io, all_err_mask);
+	if (dev) {
+		if (dev->flags & ATA_DFLAG_DUBIOUS_XFER)
+			eflags |= ATA_EFLAG_DUBIOUS_XFER;
+		ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask);
+	}
 
 	DPRINTK("EXIT\n");
 }
@@ -1880,8 +1978,8 @@ static void ata_eh_link_report(struct ata_link *link)
 				[ATA_PROT_PIO]		= "pio",
 				[ATA_PROT_DMA]		= "dma",
 				[ATA_PROT_NCQ]		= "ncq",
-				[ATA_PROT_ATAPI]	= "pio",
-				[ATA_PROT_ATAPI_DMA]	= "dma",
+				[ATAPI_PROT_PIO]	= "pio",
+				[ATAPI_PROT_DMA]	= "dma",
 			};
 
 			snprintf(data_buf, sizeof(data_buf), " %s %u %s",
@@ -1889,7 +1987,7 @@ static void ata_eh_link_report(struct ata_link *link)
 				 dma_str[qc->dma_dir]);
 		}
 
-		if (is_atapi_taskfile(&qc->tf))
+		if (ata_is_atapi(qc->tf.protocol))
 			snprintf(cdb_buf, sizeof(cdb_buf),
 				 "cdb %02x %02x %02x %02x %02x %02x %02x %02x  "
 				 "%02x %02x %02x %02x %02x %02x %02x %02x\n         ",
@@ -2329,6 +2427,58 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
 	return rc;
 }
 
+/**
+ *	ata_set_mode - Program timings and issue SET FEATURES - XFER
+ *	@link: link on which timings will be programmed
+ *	@r_failed_dev: out paramter for failed device
+ *
+ *	Set ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
+ *	ata_set_mode() fails, pointer to the failing device is
+ *	returned in @r_failed_dev.
+ *
+ *	LOCKING:
+ *	PCI/etc. bus probe sem.
+ *
+ *	RETURNS:
+ *	0 on success, negative errno otherwise
+ */
+int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
+{
+	struct ata_port *ap = link->ap;
+	struct ata_device *dev;
+	int rc;
+
+	/* if data transfer is verified, clear DUBIOUS_XFER on ering top */
+	ata_link_for_each_dev(dev, link) {
+		if (!(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) {
+			struct ata_ering_entry *ent;
+
+			ent = ata_ering_top(&dev->ering);
+			if (ent)
+				ent->eflags &= ~ATA_EFLAG_DUBIOUS_XFER;
+		}
+	}
+
+	/* has private set_mode? */
+	if (ap->ops->set_mode)
+		rc = ap->ops->set_mode(link, r_failed_dev);
+	else
+		rc = ata_do_set_mode(link, r_failed_dev);
+
+	/* if transfer mode has changed, set DUBIOUS_XFER on device */
+	ata_link_for_each_dev(dev, link) {
+		struct ata_eh_context *ehc = &link->eh_context;
+		u8 saved_xfer_mode = ehc->saved_xfer_mode[dev->devno];
+		u8 saved_ncq = !!(ehc->saved_ncq_enabled & (1 << dev->devno));
+
+		if (dev->xfer_mode != saved_xfer_mode ||
+		    ata_ncq_enabled(dev) != saved_ncq)
+			dev->flags |= ATA_DFLAG_DUBIOUS_XFER;
+	}
+
+	return rc;
+}
+
 static int ata_link_nr_enabled(struct ata_link *link)
 {
 	struct ata_device *dev;
@@ -2375,6 +2525,24 @@ static int ata_eh_skip_recovery(struct ata_link *link)
 	return 1;
 }
 
+static int ata_eh_schedule_probe(struct ata_device *dev)
+{
+	struct ata_eh_context *ehc = &dev->link->eh_context;
+
+	if (!(ehc->i.probe_mask & (1 << dev->devno)) ||
+	    (ehc->did_probe_mask & (1 << dev->devno)))
+		return 0;
+
+	ata_eh_detach_dev(dev);
+	ata_dev_init(dev);
+	ehc->did_probe_mask |= (1 << dev->devno);
+	ehc->i.action |= ATA_EH_SOFTRESET;
+	ehc->saved_xfer_mode[dev->devno] = 0;
+	ehc->saved_ncq_enabled &= ~(1 << dev->devno);
+
+	return 1;
+}
+
 static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
 {
 	struct ata_eh_context *ehc = &dev->link->eh_context;
@@ -2406,16 +2574,9 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
 		if (ata_link_offline(dev->link))
 			ata_eh_detach_dev(dev);
 
-		/* probe if requested */
-		if ((ehc->i.probe_mask & (1 << dev->devno)) &&
-		    !(ehc->did_probe_mask & (1 << dev->devno))) {
-			ata_eh_detach_dev(dev);
-			ata_dev_init(dev);
-
+		/* schedule probe if necessary */
+		if (ata_eh_schedule_probe(dev))
 			ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
-			ehc->did_probe_mask |= (1 << dev->devno);
-			ehc->i.action |= ATA_EH_SOFTRESET;
-		}
 
 		return 1;
 	} else {
@@ -2492,14 +2653,9 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 			if (dev->flags & ATA_DFLAG_DETACH)
 				ata_eh_detach_dev(dev);
 
-			if (!ata_dev_enabled(dev) &&
-			    ((ehc->i.probe_mask & (1 << dev->devno)) &&
-			     !(ehc->did_probe_mask & (1 << dev->devno)))) {
-				ata_eh_detach_dev(dev);
-				ata_dev_init(dev);
-				ehc->did_probe_mask |= (1 << dev->devno);
-				ehc->i.action |= ATA_EH_SOFTRESET;
-			}
+			/* schedule probe if necessary */
+			if (!ata_dev_enabled(dev))
+				ata_eh_schedule_probe(dev);
 		}
 	}
 
@@ -2747,6 +2903,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap)
 	if (ap->ops->port_suspend)
 		rc = ap->ops->port_suspend(ap, ap->pm_mesg);
 
+	ata_acpi_set_state(ap, PMSG_SUSPEND);
  out:
 	/* report result */
 	spin_lock_irqsave(ap->lock, flags);
@@ -2792,6 +2949,8 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
 
 	WARN_ON(!(ap->pflags & ATA_PFLAG_SUSPENDED));
 
+	ata_acpi_set_state(ap, PMSG_ON);
+
 	if (ap->ops->port_resume)
 		rc = ap->ops->port_resume(ap);
 
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 14daf4848f09..c02c490122dc 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -517,7 +517,7 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
 		qc->scsicmd = cmd;
 		qc->scsidone = done;
 
-		qc->__sg = scsi_sglist(cmd);
+		qc->sg = scsi_sglist(cmd);
 		qc->n_elem = scsi_sg_count(cmd);
 	} else {
 		cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
@@ -839,7 +839,14 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
 	if (dev->class == ATA_DEV_ATAPI) {
 		struct request_queue *q = sdev->request_queue;
 		blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
-	}
+
+		/* set the min alignment */
+		blk_queue_update_dma_alignment(sdev->request_queue,
+					       ATA_DMA_PAD_SZ - 1);
+	} else
+		/* ATA devices must be sector aligned */
+		blk_queue_update_dma_alignment(sdev->request_queue,
+					       ATA_SECT_SIZE - 1);
 
 	if (dev->class == ATA_DEV_ATA)
 		sdev->manage_start_stop = 1;
@@ -878,7 +885,7 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
 	if (dev)
 		ata_scsi_dev_config(sdev, dev);
 
-	return 0;	/* scsi layer doesn't check return value, sigh */
+	return 0;
 }
 
 /**
@@ -2210,7 +2217,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
 
 		/* sector size */
 		ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8);
-		ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE);
+		ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff);
 	} else {
 		/* sector count, 64-bit */
 		ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7));
@@ -2224,7 +2231,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
 
 		/* sector size */
 		ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8);
-		ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE);
+		ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff);
 	}
 
 	return 0;
@@ -2331,7 +2338,7 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
 	DPRINTK("ATAPI request sense\n");
 
 	/* FIXME: is this needed? */
-	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 
 	ap->ops->tf_read(ap, &qc->tf);
 
@@ -2341,7 +2348,9 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
 
 	ata_qc_reinit(qc);
 
-	ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
+	/* setup sg table and init transfer direction */
+	sg_init_one(&qc->sgent, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+	ata_sg_init(qc, &qc->sgent, 1);
 	qc->dma_dir = DMA_FROM_DEVICE;
 
 	memset(&qc->cdb, 0, qc->dev->cdb_len);
@@ -2352,10 +2361,10 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
 	qc->tf.command = ATA_CMD_PACKET;
 
 	if (ata_pio_use_silly(ap)) {
-		qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+		qc->tf.protocol = ATAPI_PROT_DMA;
 		qc->tf.feature |= ATAPI_PKT_DMA;
 	} else {
-		qc->tf.protocol = ATA_PROT_ATAPI;
+		qc->tf.protocol = ATAPI_PROT_PIO;
 		qc->tf.lbam = SCSI_SENSE_BUFFERSIZE;
 		qc->tf.lbah = 0;
 	}
@@ -2526,12 +2535,12 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
 	if (using_pio || nodata) {
 		/* no data, or PIO data xfer */
 		if (nodata)
-			qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
+			qc->tf.protocol = ATAPI_PROT_NODATA;
 		else
-			qc->tf.protocol = ATA_PROT_ATAPI;
+			qc->tf.protocol = ATAPI_PROT_PIO;
 	} else {
 		/* DMA data xfer */
-		qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+		qc->tf.protocol = ATAPI_PROT_DMA;
 		qc->tf.feature |= ATAPI_PKT_DMA;
 
 		if (atapi_dmadir && (scmd->sc_data_direction != DMA_TO_DEVICE))
@@ -2690,6 +2699,24 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
 	if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN)
 		goto invalid_fld;
 
+	/*
+	 * Filter TPM commands by default. These provide an
+	 * essentially uncontrolled encrypted "back door" between
+	 * applications and the disk. Set libata.allow_tpm=1 if you
+	 * have a real reason for wanting to use them. This ensures
+	 * that installed software cannot easily mess stuff up without
+	 * user intent. DVR type users will probably ship with this enabled
+	 * for movie content management.
+	 *
+	 * Note that for ATA8 we can issue a DCS change and DCS freeze lock
+	 * for this and should do in future but that it is not sufficient as
+	 * DCS is an optional feature set. Thus we also do the software filter
+	 * so that we comply with the TC consortium stated goal that the user
+	 * can turn off TC features of their system.
+	 */
+	if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm)
+		goto invalid_fld;
+
 	/* We may not issue DMA commands if no DMA mode is set */
 	if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0)
 		goto invalid_fld;
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index b7ac80b4b1fb..60cd4b179766 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -147,7 +147,9 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
  *	@tf: ATA taskfile register set for storing input
  *
  *	Reads ATA taskfile registers for currently-selected device
- *	into @tf.
+ *	into @tf. Assumes the device has a fully SFF compliant task file
+ *	layout and behaviour. If you device does not (eg has a different
+ *	status method) then you will need to provide a replacement tf_read
  *
  *	LOCKING:
  *	Inherited from caller.
@@ -156,7 +158,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 
-	tf->command = ata_chk_status(ap);
+	tf->command = ata_check_status(ap);
 	tf->feature = ioread8(ioaddr->error_addr);
 	tf->nsect = ioread8(ioaddr->nsect_addr);
 	tf->lbal = ioread8(ioaddr->lbal_addr);
@@ -415,7 +417,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
 	ap->hsm_task_state = HSM_ST_IDLE;
 
 	if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
-		   qc->tf.protocol == ATA_PROT_ATAPI_DMA)) {
+		   qc->tf.protocol == ATAPI_PROT_DMA)) {
 		u8 host_stat;
 
 		host_stat = ap->ops->bmdma_status(ap);
@@ -549,7 +551,7 @@ int ata_pci_init_bmdma(struct ata_host *host)
 		return rc;
 
 	/* request and iomap DMA region */
-	rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME);
+	rc = pcim_iomap_regions(pdev, 1 << 4, dev_driver_string(gdev));
 	if (rc) {
 		dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n");
 		return -ENOMEM;
@@ -619,7 +621,8 @@ int ata_pci_init_sff_host(struct ata_host *host)
 			continue;
 		}
 
-		rc = pcim_iomap_regions(pdev, 0x3 << base, DRV_NAME);
+		rc = pcim_iomap_regions(pdev, 0x3 << base,
+					dev_driver_string(gdev));
 		if (rc) {
 			dev_printk(KERN_WARNING, gdev,
 				   "failed to request/iomap BARs for port %d "
@@ -711,6 +714,99 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev,
 }
 
 /**
+ *	ata_pci_activate_sff_host - start SFF host, request IRQ and register it
+ *	@host: target SFF ATA host
+ *	@irq_handler: irq_handler used when requesting IRQ(s)
+ *	@sht: scsi_host_template to use when registering the host
+ *
+ *	This is the counterpart of ata_host_activate() for SFF ATA
+ *	hosts.  This separate helper is necessary because SFF hosts
+ *	use two separate interrupts in legacy mode.
+ *
+ *	LOCKING:
+ *	Inherited from calling layer (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int ata_pci_activate_sff_host(struct ata_host *host,
+			      irq_handler_t irq_handler,
+			      struct scsi_host_template *sht)
+{
+	struct device *dev = host->dev;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	const char *drv_name = dev_driver_string(host->dev);
+	int legacy_mode = 0, rc;
+
+	rc = ata_host_start(host);
+	if (rc)
+		return rc;
+
+	if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		u8 tmp8, mask;
+
+		/* 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;
+#if defined(CONFIG_NO_ATA_LEGACY)
+		/* Some platforms with PCI limits cannot address compat
+		   port space. In that case we punt if their firmware has
+		   left a device in compatibility mode */
+		if (legacy_mode) {
+			printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
+			return -EOPNOTSUPP;
+		}
+#endif
+	}
+
+	if (!devres_open_group(dev, NULL, GFP_KERNEL))
+		return -ENOMEM;
+
+	if (!legacy_mode && pdev->irq) {
+		rc = devm_request_irq(dev, pdev->irq, irq_handler,
+				      IRQF_SHARED, drv_name, host);
+		if (rc)
+			goto out;
+
+		ata_port_desc(host->ports[0], "irq %d", pdev->irq);
+		ata_port_desc(host->ports[1], "irq %d", pdev->irq);
+	} else if (legacy_mode) {
+		if (!ata_port_is_dummy(host->ports[0])) {
+			rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
+					      irq_handler, IRQF_SHARED,
+					      drv_name, host);
+			if (rc)
+				goto out;
+
+			ata_port_desc(host->ports[0], "irq %d",
+				      ATA_PRIMARY_IRQ(pdev));
+		}
+
+		if (!ata_port_is_dummy(host->ports[1])) {
+			rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
+					      irq_handler, IRQF_SHARED,
+					      drv_name, host);
+			if (rc)
+				goto out;
+
+			ata_port_desc(host->ports[1], "irq %d",
+				      ATA_SECONDARY_IRQ(pdev));
+		}
+	}
+
+	rc = ata_host_register(host, sht);
+ out:
+	if (rc == 0)
+		devres_remove_group(dev, NULL);
+	else
+		devres_release_group(dev, NULL);
+
+	return rc;
+}
+
+/**
  *	ata_pci_init_one - Initialize/register PCI IDE host controller
  *	@pdev: Controller to be initialized
  *	@ppi: array of port_info, must be enough for two ports
@@ -739,8 +835,6 @@ int ata_pci_init_one(struct pci_dev *pdev,
 	struct device *dev = &pdev->dev;
 	const struct ata_port_info *pi = NULL;
 	struct ata_host *host = NULL;
-	u8 mask;
-	int legacy_mode = 0;
 	int i, rc;
 
 	DPRINTK("ENTER\n");
@@ -762,95 +856,24 @@ int ata_pci_init_one(struct pci_dev *pdev,
 	if (!devres_open_group(dev, NULL, GFP_KERNEL))
 		return -ENOMEM;
 
-	/* 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 = pcim_enable_device(pdev);
 	if (rc)
-		goto err_out;
+		goto out;
 
-	if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-		u8 tmp8;
-
-		/* 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;
-#if defined(CONFIG_NO_ATA_LEGACY)
-		/* Some platforms with PCI limits cannot address compat
-		   port space. In that case we punt if their firmware has
-		   left a device in compatibility mode */
-		if (legacy_mode) {
-			printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n");
-			rc = -EOPNOTSUPP;
-			goto err_out;
-		}
-#endif
-	}
-
-	/* prepare host */
+	/* prepare and activate SFF host */
 	rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
 	if (rc)
-		goto err_out;
+		goto out;
 
 	pci_set_master(pdev);
+	rc = ata_pci_activate_sff_host(host, pi->port_ops->irq_handler,
+				       pi->sht);
+ out:
+	if (rc == 0)
+		devres_remove_group(&pdev->dev, NULL);
+	else
+		devres_release_group(&pdev->dev, NULL);
 
-	/* start host and request IRQ */
-	rc = ata_host_start(host);
-	if (rc)
-		goto err_out;
-
-	if (!legacy_mode && pdev->irq) {
-		/* We may have no IRQ assigned in which case we can poll. This
-		   shouldn't happen on a sane system but robustness is cheap
-		   in this case */
-		rc = devm_request_irq(dev, pdev->irq, pi->port_ops->irq_handler,
-				      IRQF_SHARED, DRV_NAME, host);
-		if (rc)
-			goto err_out;
-
-		ata_port_desc(host->ports[0], "irq %d", pdev->irq);
-		ata_port_desc(host->ports[1], "irq %d", pdev->irq);
-	} else if (legacy_mode) {
-		if (!ata_port_is_dummy(host->ports[0])) {
-			rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
-					      pi->port_ops->irq_handler,
-					      IRQF_SHARED, DRV_NAME, host);
-			if (rc)
-				goto err_out;
-
-			ata_port_desc(host->ports[0], "irq %d",
-				      ATA_PRIMARY_IRQ(pdev));
-		}
-
-		if (!ata_port_is_dummy(host->ports[1])) {
-			rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
-					      pi->port_ops->irq_handler,
-					      IRQF_SHARED, DRV_NAME, host);
-			if (rc)
-				goto err_out;
-
-			ata_port_desc(host->ports[1], "irq %d",
-				      ATA_SECONDARY_IRQ(pdev));
-		}
-	}
-
-	/* register */
-	rc = ata_host_register(host, pi->sht);
-	if (rc)
-		goto err_out;
-
-	devres_remove_group(dev, NULL);
-	return 0;
-
-err_out:
-	devres_release_group(dev, NULL);
 	return rc;
 }
 
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index bbe59c2fd1e2..409ffb9af163 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -60,6 +60,7 @@ extern int atapi_dmadir;
 extern int atapi_passthru16;
 extern int libata_fua;
 extern int libata_noacpi;
+extern int libata_allow_tpm;
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
 extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
 			   u64 block, u32 n_block, unsigned int tf_flags,
@@ -85,7 +86,6 @@ extern int ata_dev_configure(struct ata_device *dev);
 extern int sata_down_spd_limit(struct ata_link *link);
 extern int sata_set_spd_needed(struct ata_link *link);
 extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
-extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 extern void ata_sg_clean(struct ata_queued_cmd *qc);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
 extern void ata_qc_issue(struct ata_queued_cmd *qc);
@@ -113,6 +113,7 @@ extern int ata_acpi_on_suspend(struct ata_port *ap);
 extern void ata_acpi_on_resume(struct ata_port *ap);
 extern int ata_acpi_on_devcfg(struct ata_device *dev);
 extern void ata_acpi_on_disable(struct ata_device *dev);
+extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);
 #else
 static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { }
 static inline void ata_acpi_associate(struct ata_host *host) { }
@@ -121,6 +122,8 @@ static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
 static inline void ata_acpi_on_resume(struct ata_port *ap) { }
 static inline int ata_acpi_on_devcfg(struct ata_device *dev) { return 0; }
 static inline void ata_acpi_on_disable(struct ata_device *dev) { }
+static inline void ata_acpi_set_state(struct ata_port *ap,
+				      pm_message_t state) { }
 #endif
 
 /* libata-scsi.c */
@@ -183,6 +186,7 @@ extern void ata_eh_report(struct ata_port *ap);
 extern int ata_eh_reset(struct ata_link *link, int classify,
 			ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
 			ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
+extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 			  ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 			  ata_postreset_fn_t postreset,
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index e4542ab9c7f8..244098a80ce4 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -81,17 +81,6 @@ static void pacpi_error_handler(struct ata_port *ap)
 				  NULL, ata_std_postreset);
 }
 
-/* Welcome to ACPI, bring a bucket */
-static const unsigned int pio_cycle[7] = {
-	600, 383, 240, 180, 120, 100, 80
-};
-static const unsigned int mwdma_cycle[5] = {
-	480, 150, 120, 100, 80
-};
-static const unsigned int udma_cycle[7] = {
-	120, 80, 60, 45, 30, 20, 15
-};
-
 /**
  *	pacpi_discover_modes	-	filter non ACPI modes
  *	@adev: ATA device
@@ -103,56 +92,20 @@ static const unsigned int udma_cycle[7] = {
 
 static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev)
 {
-	int unit = adev->devno;
 	struct pata_acpi *acpi = ap->private_data;
-	int i;
-	u32 t;
-	unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO);
-
 	struct ata_acpi_gtm probe;
+	unsigned int xfer_mask;
 
 	probe = acpi->gtm;
 
-	/* We always use the 0 slot for crap hardware */
-	if (!(probe.flags & 0x10))
-		unit = 0;
-
 	ata_acpi_gtm(ap, &probe);
 
-	/* Start by scanning for PIO modes */
-	for (i = 0; i < 7; i++) {
-		t = probe.drive[unit].pio;
-		if (t <= pio_cycle[i]) {
-			mask |= (2 << (ATA_SHIFT_PIO + i)) - 1;
-			break;
-		}
-	}
+	xfer_mask = ata_acpi_gtm_xfermask(adev, &probe);
 
-	/* See if we have MWDMA or UDMA data. We don't bother with MWDMA
-	   if UDMA is availabe as this means the BIOS set UDMA and our
-	   error changedown if it works is UDMA to PIO anyway */
-	if (probe.flags & (1 << (2 * unit))) {
-		/* MWDMA */
-		for (i = 0; i < 5; i++) {
-			t = probe.drive[unit].dma;
-			if (t <= mwdma_cycle[i]) {
-				mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1;
-				break;
-			}
-		}
-	} else {
-		/* UDMA */
-		for (i = 0; i < 7; i++) {
-			t = probe.drive[unit].dma;
-			if (t <= udma_cycle[i]) {
-				mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1;
-				break;
-			}
-		}
-	}
-	if (mask & (0xF8 << ATA_SHIFT_UDMA))
+	if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA))
 		ap->cbl = ATA_CBL_PATA80;
-	return mask;
+
+	return xfer_mask;
 }
 
 /**
@@ -180,12 +133,14 @@ static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
 	int unit = adev->devno;
 	struct pata_acpi *acpi = ap->private_data;
+	const struct ata_timing *t;
 
 	if (!(acpi->gtm.flags & 0x10))
 		unit = 0;
 
 	/* Now stuff the nS values into the structure */
-	acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0];
+	t = ata_timing_find_mode(adev->pio_mode);
+	acpi->gtm.drive[unit].pio = t->cycle;
 	ata_acpi_stm(ap, &acpi->gtm);
 	/* See what mode we actually got */
 	ata_acpi_gtm(ap, &acpi->gtm);
@@ -201,16 +156,18 @@ static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 {
 	int unit = adev->devno;
 	struct pata_acpi *acpi = ap->private_data;
+	const struct ata_timing *t;
 
 	if (!(acpi->gtm.flags & 0x10))
 		unit = 0;
 
 	/* Now stuff the nS values into the structure */
+	t = ata_timing_find_mode(adev->dma_mode);
 	if (adev->dma_mode >= XFER_UDMA_0) {
-		acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0];
+		acpi->gtm.drive[unit].dma = t->udma;
 		acpi->gtm.flags |= (1 << (2 * unit));
 	} else {
-		acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0];
+		acpi->gtm.drive[unit].dma = t->cycle;
 		acpi->gtm.flags &= ~(1 << (2 * unit));
 	}
 	ata_acpi_stm(ap, &acpi->gtm);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 8caf9afc8b90..7e68edf3c0f3 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -64,7 +64,7 @@ static int ali_cable_override(struct pci_dev *pdev)
 	if (pdev->subsystem_vendor == 0x10CF && pdev->subsystem_device == 0x10AF)
 	   	return 1;
 	/* Mitac 8317 (Winbook-A) and relatives */
-	if (pdev->subsystem_vendor == 0x1071  && pdev->subsystem_device == 0x8317)
+	if (pdev->subsystem_vendor == 0x1071 && pdev->subsystem_device == 0x8317)
 		return 1;
 	/* Systems by DMI */
 	if (dmi_check_system(cable_dmi_table))
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 3cc27b514654..761a66608d7b 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -220,6 +220,62 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 	timing_setup(ap, adev, 0x40, adev->dma_mode, 4);
 }
 
+/* Both host-side and drive-side detection results are worthless on NV
+ * PATAs.  Ignore them and just follow what BIOS configured.  Both the
+ * current configuration in PCI config reg and ACPI GTM result are
+ * cached during driver attach and are consulted to select transfer
+ * mode.
+ */
+static unsigned long nv_mode_filter(struct ata_device *dev,
+				    unsigned long xfer_mask)
+{
+	static const unsigned int udma_mask_map[] =
+		{ ATA_UDMA2, ATA_UDMA1, ATA_UDMA0, 0,
+		  ATA_UDMA3, ATA_UDMA4, ATA_UDMA5, ATA_UDMA6 };
+	struct ata_port *ap = dev->link->ap;
+	char acpi_str[32] = "";
+	u32 saved_udma, udma;
+	const struct ata_acpi_gtm *gtm;
+	unsigned long bios_limit = 0, acpi_limit = 0, limit;
+
+	/* find out what BIOS configured */
+	udma = saved_udma = (unsigned long)ap->host->private_data;
+
+	if (ap->port_no == 0)
+		udma >>= 16;
+	if (dev->devno == 0)
+		udma >>= 8;
+
+	if ((udma & 0xc0) == 0xc0)
+		bios_limit = ata_pack_xfermask(0, 0, udma_mask_map[udma & 0x7]);
+
+	/* consult ACPI GTM too */
+	gtm = ata_acpi_init_gtm(ap);
+	if (gtm) {
+		acpi_limit = ata_acpi_gtm_xfermask(dev, gtm);
+
+		snprintf(acpi_str, sizeof(acpi_str), " (%u:%u:0x%x)",
+			 gtm->drive[0].dma, gtm->drive[1].dma, gtm->flags);
+	}
+
+	/* be optimistic, EH can take care of things if something goes wrong */
+	limit = bios_limit | acpi_limit;
+
+	/* If PIO or DMA isn't configured at all, don't limit.  Let EH
+	 * handle it.
+	 */
+	if (!(limit & ATA_MASK_PIO))
+		limit |= ATA_MASK_PIO;
+	if (!(limit & (ATA_MASK_MWDMA | ATA_MASK_UDMA)))
+		limit |= ATA_MASK_MWDMA | ATA_MASK_UDMA;
+
+	ata_port_printk(ap, KERN_DEBUG, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, "
+			"BIOS=0x%lx (0x%x) ACPI=0x%lx%s\n",
+			xfer_mask, limit, xfer_mask & limit, bios_limit,
+			saved_udma, acpi_limit, acpi_str);
+
+	return xfer_mask & limit;
+}
 
 /**
  *	nv_probe_init	-	cable detection
@@ -252,31 +308,6 @@ static void nv_error_handler(struct ata_port *ap)
 			       ata_std_postreset);
 }
 
-static int nv_cable_detect(struct ata_port *ap)
-{
-	static const u8 bitmask[2] = {0x03, 0x0C};
-	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	u8 ata66;
-	u16 udma;
-	int cbl;
-
-	pci_read_config_byte(pdev, 0x52, &ata66);
-	if (ata66 & bitmask[ap->port_no])
-		cbl = ATA_CBL_PATA80;
-	else
-		cbl = ATA_CBL_PATA40;
-
- 	/* We now have to double check because the Nvidia boxes BIOS
- 	   doesn't always set the cable bits but does set mode bits */
- 	pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
- 	if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
-		cbl = ATA_CBL_PATA80;
-	/* And a triple check across suspend/resume with ACPI around */
-	if (ata_acpi_cbl_80wire(ap))
-		cbl = ATA_CBL_PATA80;
-	return cbl;
-}
-
 /**
  *	nv100_set_piomode	-	set initial PIO mode data
  *	@ap: ATA interface
@@ -314,6 +345,14 @@ static void nv133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
 	timing_setup(ap, adev, 0x50, adev->dma_mode, 4);
 }
 
+static void nv_host_stop(struct ata_host *host)
+{
+	u32 udma = (unsigned long)host->private_data;
+
+	/* restore PCI config register 0x60 */
+	pci_write_config_dword(to_pci_dev(host->dev), 0x60, udma);
+}
+
 static struct scsi_host_template amd_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
@@ -478,7 +517,8 @@ static struct ata_port_operations nv100_port_ops = {
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= nv_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
-	.cable_detect	= nv_cable_detect,
+	.cable_detect	= ata_cable_ignore,
+	.mode_filter	= nv_mode_filter,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -495,6 +535,7 @@ static struct ata_port_operations nv100_port_ops = {
 	.irq_on		= ata_irq_on,
 
 	.port_start	= ata_sff_port_start,
+	.host_stop	= nv_host_stop,
 };
 
 static struct ata_port_operations nv133_port_ops = {
@@ -511,7 +552,8 @@ static struct ata_port_operations nv133_port_ops = {
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= nv_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
-	.cable_detect	= nv_cable_detect,
+	.cable_detect	= ata_cable_ignore,
+	.mode_filter	= nv_mode_filter,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
@@ -528,6 +570,7 @@ static struct ata_port_operations nv133_port_ops = {
 	.irq_on		= ata_irq_on,
 
 	.port_start	= ata_sff_port_start,
+	.host_stop	= nv_host_stop,
 };
 
 static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -614,7 +657,8 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 			.port_ops = &amd100_port_ops
 		}
 	};
-	const struct ata_port_info *ppi[] = { NULL, NULL };
+	struct ata_port_info pi;
+	const struct ata_port_info *ppi[] = { &pi, NULL };
 	static int printed_version;
 	int type = id->driver_data;
 	u8 fifo;
@@ -628,6 +672,19 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (type == 1 && pdev->revision > 0x7)
 		type = 2;
 
+	/* Serenade ? */
+	if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
+			 pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
+		type = 6;	/* UDMA 100 only */
+
+	/*
+	 * Okay, type is determined now.  Apply type-specific workarounds.
+	 */
+	pi = info[type];
+
+	if (type < 3)
+		ata_pci_clear_simplex(pdev);
+
 	/* Check for AMD7411 */
 	if (type == 3)
 		/* FIFO is broken */
@@ -635,16 +692,17 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	else
 		pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
 
-	/* Serenade ? */
-	if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
-			 pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
-		type = 6;	/* UDMA 100 only */
+	/* Cable detection on Nvidia chips doesn't work too well,
+	 * cache BIOS programmed UDMA mode.
+	 */
+	if (type == 7 || type == 8) {
+		u32 udma;
 
-	if (type < 3)
-		ata_pci_clear_simplex(pdev);
+		pci_read_config_dword(pdev, 0x60, &udma);
+		pi.private_data = (void *)(unsigned long)udma;
+	}
 
 	/* And fire it up */
-	ppi[0] = &info[type];
 	return ata_pci_init_one(pdev, ppi);
 }
 
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index 7842cc487359..a32e3c44a606 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -832,6 +832,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
 {
 	unsigned short config = WDSIZE_16;
 	struct scatterlist *sg;
+	unsigned int si;
 
 	pr_debug("in atapi dma setup\n");
 	/* Program the ATA_CTRL register with dir */
@@ -839,7 +840,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
 		/* fill the ATAPI DMA controller */
 		set_dma_config(CH_ATAPI_TX, config);
 		set_dma_x_modify(CH_ATAPI_TX, 2);
-		ata_for_each_sg(sg, qc) {
+		for_each_sg(qc->sg, sg, qc->n_elem, si) {
 			set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg));
 			set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1);
 		}
@@ -848,7 +849,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
 		/* fill the ATAPI DMA controller */
 		set_dma_config(CH_ATAPI_RX, config);
 		set_dma_x_modify(CH_ATAPI_RX, 2);
-		ata_for_each_sg(sg, qc) {
+		for_each_sg(qc->sg, sg, qc->n_elem, si) {
 			set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));
 			set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);
 		}
@@ -867,6 +868,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
 	struct ata_port *ap = qc->ap;
 	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
 	struct scatterlist *sg;
+	unsigned int si;
 
 	pr_debug("in atapi dma start\n");
 	if (!(ap->udma_mask || ap->mwdma_mask))
@@ -881,7 +883,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
 		 * data cache is enabled. Otherwise, this loop
 		 * is an empty loop and optimized out.
 		 */
-		ata_for_each_sg(sg, qc) {
+		for_each_sg(qc->sg, sg, qc->n_elem, si) {
 			flush_dcache_range(sg_dma_address(sg),
 				sg_dma_address(sg) + sg_dma_len(sg));
 		}
@@ -910,7 +912,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
 	ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
 
 		/* Set transfer length to buffer len */
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
 	}
 
@@ -932,6 +934,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct scatterlist *sg;
+	unsigned int si;
 
 	pr_debug("in atapi dma stop\n");
 	if (!(ap->udma_mask || ap->mwdma_mask))
@@ -950,7 +953,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
 			 * data cache is enabled. Otherwise, this loop
 			 * is an empty loop and optimized out.
 			 */
-			ata_for_each_sg(sg, qc) {
+			for_each_sg(qc->sg, sg, qc->n_elem, si) {
 				invalidate_dcache_range(
 					sg_dma_address(sg),
 					sg_dma_address(sg)
@@ -1167,34 +1170,36 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
  *	Note: Original code is ata_data_xfer().
  */
 
-static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf,
-			   unsigned int buflen, int write_data)
+static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf,
+				   unsigned int buflen, int rw)
 {
-	struct ata_port *ap = adev->link->ap;
-	unsigned int words = buflen >> 1;
-	unsigned short *buf16 = (u16 *) buf;
+	struct ata_port *ap = dev->link->ap;
 	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	unsigned int words = buflen >> 1;
+	unsigned short *buf16 = (u16 *)buf;
 
 	/* Transfer multiple of 2 bytes */
-	if (write_data) {
-		write_atapi_data(base, words, buf16);
-	} else {
+	if (rw == READ)
 		read_atapi_data(base, words, buf16);
-	}
+	else
+		write_atapi_data(base, words, buf16);
 
 	/* Transfer trailing 1 byte, if any. */
 	if (unlikely(buflen & 0x01)) {
 		unsigned short align_buf[1] = { 0 };
 		unsigned char *trailing_buf = buf + buflen - 1;
 
-		if (write_data) {
-			memcpy(align_buf, trailing_buf, 1);
-			write_atapi_data(base, 1, align_buf);
-		} else {
+		if (rw == READ) {
 			read_atapi_data(base, 1, align_buf);
 			memcpy(trailing_buf, align_buf, 1);
+		} else {
+			memcpy(align_buf, trailing_buf, 1);
+			write_atapi_data(base, 1, align_buf);
 		}
+		words++;
 	}
+
+	return words << 1;
 }
 
 /**
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 33f7f0843f4f..d4590f546c49 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -198,7 +198,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
 	};
 	const struct ata_port_info *ppi[2];
 	u8 pcicfg;
-	void *iomap[5];
+	void __iomem *iomap[5];
 	struct ata_host *host;
 	struct ata_ioports *ioaddr;
 	int i, rc;
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index c79f066c2bc9..68eb34929cec 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -847,15 +847,16 @@ static u32 hpt374_read_freq(struct pci_dev *pdev)
 	u32 freq;
 	unsigned long io_base = pci_resource_start(pdev, 4);
 	if (PCI_FUNC(pdev->devfn) & 1) {
-		struct pci_dev *pdev_0 = pci_get_slot(pdev->bus, pdev->devfn - 1);
+		struct pci_dev *pdev_0;
+
+		pdev_0 = pci_get_slot(pdev->bus, pdev->devfn - 1);
 		/* Someone hot plugged the controller on us ? */
 		if (pdev_0 == NULL)
 			return 0;
 		io_base = pci_resource_start(pdev_0, 4);
 		freq = inl(io_base + 0x90);
 		pci_dev_put(pdev_0);
-	}
-	else
+	} else
 		freq = inl(io_base + 0x90);
 	return freq;
 }
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
index 842fe08a3c13..5b8586dac63b 100644
--- a/drivers/ata/pata_icside.c
+++ b/drivers/ata/pata_icside.c
@@ -224,6 +224,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
 	struct pata_icside_state *state = ap->host->private_data;
 	struct scatterlist *sg, *rsg = state->sg;
 	unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE;
+	unsigned int si;
 
 	/*
 	 * We are simplex; BUG if we try to fiddle with DMA
@@ -234,7 +235,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
 	/*
 	 * Copy ATAs scattered sg list into a contiguous array of sg
 	 */
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		memcpy(rsg, sg, sizeof(*sg));
 		rsg++;
 	}
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index ca9aae09daed..109ddd42c266 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -430,7 +430,7 @@ static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc)
 			return ata_qc_issue_prot(qc);
 	}
 	printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command);
-	return AC_ERR_INVALID;
+	return AC_ERR_DEV;
 }
 
 /**
@@ -516,6 +516,37 @@ static void it821x_dev_config(struct ata_device *adev)
 			printk("(%dK stripe)", adev->id[146]);
 		printk(".\n");
 	}
+	/* This is a controller firmware triggered funny, don't
+	   report the drive faulty! */
+	adev->horkage &= ~ATA_HORKAGE_DIAGNOSTIC;
+}
+
+/**
+ *	it821x_ident_hack	-	Hack identify data up
+ *	@ap: Port
+ *
+ *	Walk the devices on this firmware driven port and slightly
+ *	mash the identify data to stop us and common tools trying to
+ *	use features not firmware supported. The firmware itself does
+ *	some masking (eg SMART) but not enough.
+ *
+ *	This is a bit of an abuse of the cable method, but it is the
+ *	only method called at the right time. We could modify the libata
+ *	core specifically for ident hacking but while we have one offender
+ *	it seems better to keep the fallout localised.
+ */
+
+static int it821x_ident_hack(struct ata_port *ap)
+{
+	struct ata_device *adev;
+	ata_link_for_each_dev(adev, &ap->link) {
+		if (ata_dev_enabled(adev)) {
+			adev->id[84] &= ~(1 << 6);	/* No FUA */
+			adev->id[85] &= ~(1 << 10);	/* No HPA */
+			adev->id[76] = 0;		/* No NCQ/AN etc */
+		}
+	}
+	return ata_cable_unknown(ap);
 }
 
 
@@ -634,7 +665,7 @@ static struct ata_port_operations it821x_smart_port_ops = {
 	.thaw		= ata_bmdma_thaw,
 	.error_handler	= ata_bmdma_error_handler,
 	.post_internal_cmd = ata_bmdma_post_internal_cmd,
-	.cable_detect	= ata_cable_unknown,
+	.cable_detect	= it821x_ident_hack,
 
 	.bmdma_setup 	= ata_bmdma_setup,
 	.bmdma_start 	= ata_bmdma_start,
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 120b5bfa7ce6..030878fedeb5 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -42,13 +42,13 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
 	return 0;
 }
 
-static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
-				unsigned int buflen, int write_data)
+static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev,
+				unsigned char *buf, unsigned int buflen, int rw)
 {
 	unsigned int i;
 	unsigned int words = buflen >> 1;
 	u16 *buf16 = (u16 *) buf;
-	struct ata_port *ap = adev->link->ap;
+	struct ata_port *ap = dev->link->ap;
 	void __iomem *mmio = ap->ioaddr.data_addr;
 	struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
 
@@ -59,30 +59,32 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
 	udelay(100);
 
 	/* Transfer multiple of 2 bytes */
-	if (write_data) {
-		for (i = 0; i < words; i++)
-			writew(buf16[i], mmio);
-	} else {
+	if (rw == READ)
 		for (i = 0; i < words; i++)
 			buf16[i] = readw(mmio);
-	}
+	else
+		for (i = 0; i < words; i++)
+			writew(buf16[i], mmio);
 
 	/* Transfer trailing 1 byte, if any. */
 	if (unlikely(buflen & 0x01)) {
 		u16 align_buf[1] = { 0 };
 		unsigned char *trailing_buf = buf + buflen - 1;
 
-		if (write_data) {
-			memcpy(align_buf, trailing_buf, 1);
-			writew(align_buf[0], mmio);
-		} else {
+		if (rw == READ) {
 			align_buf[0] = readw(mmio);
 			memcpy(trailing_buf, align_buf, 1);
+		} else {
+			memcpy(align_buf, trailing_buf, 1);
+			writew(align_buf[0], mmio);
 		}
+		words++;
 	}
 
 	udelay(100);
 	*data->cs0_cfg |= 0x01;
+
+	return words << 1;
 }
 
 static struct scsi_host_template ixp4xx_sht = {
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 17159b5e1e43..333dc15f8ccf 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -28,7 +28,6 @@
  *
  *  Unsupported but docs exist:
  *	Appian/Adaptec AIC25VL01/Cirrus Logic PD7220
- *	Winbond W83759A
  *
  *  This driver handles legacy (that is "ISA/VLB side") IDE ports found
  *  on PC class systems. There are three hybrid devices that are exceptions
@@ -36,7 +35,7 @@
  *  the MPIIX where the tuning is PCI side but the IDE is "ISA side".
  *
  *  Specific support is included for the ht6560a/ht6560b/opti82c611a/
- *  opti82c465mv/promise 20230c/20630
+ *  opti82c465mv/promise 20230c/20630/winbond83759A
  *
  *  Use the autospeed and pio_mask options with:
  *	Appian ADI/2 aka CLPD7220 or AIC25VL01.
@@ -47,9 +46,6 @@
  *  For now use autospeed and pio_mask as above with the W83759A. This may
  *  change.
  *
- *  TODO
- *	Merge existing pata_qdi driver
- *
  */
 
 #include <linux/kernel.h>
@@ -64,12 +60,13 @@
 #include <linux/platform_device.h>
 
 #define DRV_NAME "pata_legacy"
-#define DRV_VERSION "0.5.5"
+#define DRV_VERSION "0.6.5"
 
 #define NR_HOST 6
 
-static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
-static int legacy_irq[NR_HOST] = { 14, 15, 11, 10, 8, 12 };
+static int all;
+module_param(all, int, 0444);
+MODULE_PARM_DESC(all, "Grab all legacy port devices, even if PCI(0=off, 1=on)");
 
 struct legacy_data {
 	unsigned long timing;
@@ -80,21 +77,107 @@ struct legacy_data {
 
 };
 
+enum controller {
+	BIOS = 0,
+	SNOOP = 1,
+	PDC20230 = 2,
+	HT6560A = 3,
+	HT6560B = 4,
+	OPTI611A = 5,
+	OPTI46X = 6,
+	QDI6500 = 7,
+	QDI6580 = 8,
+	QDI6580DP = 9,		/* Dual channel mode is different */
+	W83759A = 10,
+
+	UNKNOWN = -1
+};
+
+
+struct legacy_probe {
+	unsigned char *name;
+	unsigned long port;
+	unsigned int irq;
+	unsigned int slot;
+	enum controller type;
+	unsigned long private;
+};
+
+struct legacy_controller {
+	const char *name;
+	struct ata_port_operations *ops;
+	unsigned int pio_mask;
+	unsigned int flags;
+	int (*setup)(struct platform_device *, struct legacy_probe *probe,
+		struct legacy_data *data);
+};
+
+static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
+
+static struct legacy_probe probe_list[NR_HOST];
 static struct legacy_data legacy_data[NR_HOST];
 static struct ata_host *legacy_host[NR_HOST];
 static int nr_legacy_host;
 
 
-static int probe_all;			/* Set to check all ISA port ranges */
-static int ht6560a;			/* HT 6560A on primary 1, secondary 2, both 3 */
-static int ht6560b;			/* HT 6560A on primary 1, secondary 2, both 3 */
-static int opti82c611a;			/* Opti82c611A on primary 1, secondary 2, both 3 */
-static int opti82c46x;			/* Opti 82c465MV present (pri/sec autodetect) */
-static int autospeed;			/* Chip present which snoops speed changes */
-static int pio_mask = 0x1F;		/* PIO range for autospeed devices */
+static int probe_all;		/* Set to check all ISA port ranges */
+static int ht6560a;		/* HT 6560A on primary 1, second 2, both 3 */
+static int ht6560b;		/* HT 6560A on primary 1, second 2, both 3 */
+static int opti82c611a;		/* Opti82c611A on primary 1, sec 2, both 3 */
+static int opti82c46x;		/* Opti 82c465MV present(pri/sec autodetect) */
+static int qdi;			/* Set to probe QDI controllers */
+static int winbond;		/* Set to probe Winbond controllers,
+					give I/O port if non stdanard */
+static int autospeed;		/* Chip present which snoops speed changes */
+static int pio_mask = 0x1F;	/* PIO range for autospeed devices */
 static int iordy_mask = 0xFFFFFFFF;	/* Use iordy if available */
 
 /**
+ *	legacy_probe_add	-	Add interface to probe list
+ *	@port: Controller port
+ *	@irq: IRQ number
+ *	@type: Controller type
+ *	@private: Controller specific info
+ *
+ *	Add an entry into the probe list for ATA controllers. This is used
+ *	to add the default ISA slots and then to build up the table
+ *	further according to other ISA/VLB/Weird device scans
+ *
+ *	An I/O port list is used to keep ordering stable and sane, as we
+ *	don't have any good way to talk about ordering otherwise
+ */
+
+static int legacy_probe_add(unsigned long port, unsigned int irq,
+				enum controller type, unsigned long private)
+{
+	struct legacy_probe *lp = &probe_list[0];
+	int i;
+	struct legacy_probe *free = NULL;
+
+	for (i = 0; i < NR_HOST; i++) {
+		if (lp->port == 0 && free == NULL)
+			free = lp;
+		/* Matching port, or the correct slot for ordering */
+		if (lp->port == port || legacy_port[i] == port) {
+			free = lp;
+			break;
+		}
+		lp++;
+	}
+	if (free == NULL) {
+		printk(KERN_ERR "pata_legacy: Too many interfaces.\n");
+		return -1;
+	}
+	/* Fill in the entry for later probing */
+	free->port = port;
+	free->irq = irq;
+	free->type = type;
+	free->private = private;
+	return 0;
+}
+
+
+/**
  *	legacy_set_mode		-	mode setting
  *	@link: IDE link
  *	@unused: Device that failed when error is returned
@@ -113,7 +196,8 @@ static int legacy_set_mode(struct ata_link *link, struct ata_device **unused)
 
 	ata_link_for_each_dev(dev, link) {
 		if (ata_dev_enabled(dev)) {
-			ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
+			ata_dev_printk(dev, KERN_INFO,
+						"configured for PIO\n");
 			dev->pio_mode = XFER_PIO_0;
 			dev->xfer_mode = XFER_PIO_0;
 			dev->xfer_shift = ATA_SHIFT_PIO;
@@ -171,7 +255,7 @@ static struct ata_port_operations simple_port_ops = {
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations legacy_port_ops = {
@@ -198,15 +282,16 @@ static struct ata_port_operations legacy_port_ops = {
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
  *	Promise 20230C and 20620 support
  *
- *	This controller supports PIO0 to PIO2. We set PIO timings conservatively to
- *	allow for 50MHz Vesa Local Bus. The 20620 DMA support is weird being DMA to
- *	controller and PIO'd to the host and not supported.
+ *	This controller supports PIO0 to PIO2. We set PIO timings
+ *	conservatively to allow for 50MHz Vesa Local Bus. The 20620 DMA
+ *	support is weird being DMA to controller and PIO'd to the host
+ *	and not supported.
  */
 
 static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -221,8 +306,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
 	local_irq_save(flags);
 
 	/* Unlock the control interface */
-	do
-	{
+	do {
 		inb(0x1F5);
 		outb(inb(0x1F2) | 0x80, 0x1F2);
 		inb(0x1F2);
@@ -231,7 +315,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
 		inb(0x1F2);
 		inb(0x1F2);
 	}
-	while((inb(0x1F2) & 0x80) && --tries);
+	while ((inb(0x1F2) & 0x80) && --tries);
 
 	local_irq_restore(flags);
 
@@ -249,13 +333,14 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
 
 }
 
-static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+static unsigned int pdc_data_xfer_vlb(struct ata_device *dev,
+			unsigned char *buf, unsigned int buflen, int rw)
 {
-	struct ata_port *ap = adev->link->ap;
-	int slop = buflen & 3;
-	unsigned long flags;
+	if (ata_id_has_dword_io(dev->id)) {
+		struct ata_port *ap = dev->link->ap;
+		int slop = buflen & 3;
+		unsigned long flags;
 
-	if (ata_id_has_dword_io(adev->id)) {
 		local_irq_save(flags);
 
 		/* Perform the 32bit I/O synchronization sequence */
@@ -264,26 +349,27 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig
 		ioread8(ap->ioaddr.nsect_addr);
 
 		/* Now the data */
-
-		if (write_data)
-			iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
-		else
+		if (rw == READ)
 			ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+		else
+			iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
 
 		if (unlikely(slop)) {
-			__le32 pad = 0;
-			if (write_data) {
-				memcpy(&pad, buf + buflen - slop, slop);
-				iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
-			} else {
+			u32 pad;
+			if (rw == READ) {
 				pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
 				memcpy(buf + buflen - slop, &pad, slop);
+			} else {
+				memcpy(&pad, buf + buflen - slop, slop);
+				iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
 			}
+			buflen += 4 - slop;
 		}
 		local_irq_restore(flags);
-	}
-	else
-		ata_data_xfer_noirq(adev, buf, buflen, write_data);
+	} else
+		buflen = ata_data_xfer_noirq(dev, buf, buflen, rw);
+
+	return buflen;
 }
 
 static struct ata_port_operations pdc20230_port_ops = {
@@ -310,14 +396,14 @@ static struct ata_port_operations pdc20230_port_ops = {
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
  *	Holtek 6560A support
  *
- *	This controller supports PIO0 to PIO2 (no IORDY even though higher timings
- *	can be loaded).
+ *	This controller supports PIO0 to PIO2 (no IORDY even though higher
+ *	timings can be loaded).
  */
 
 static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -364,14 +450,14 @@ static struct ata_port_operations ht6560a_port_ops = {
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
  *	Holtek 6560B support
  *
- *	This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO setting
- *	unless we see an ATAPI device in which case we force it off.
+ *	This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO
+ *	setting unless we see an ATAPI device in which case we force it off.
  *
  *	FIXME: need to implement 2nd channel support.
  */
@@ -398,7 +484,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
 	if (adev->class != ATA_DEV_ATA) {
 		u8 rconf = inb(0x3E6);
 		if (rconf & 0x24) {
-			rconf &= ~ 0x24;
+			rconf &= ~0x24;
 			outb(rconf, 0x3E6);
 		}
 	}
@@ -423,13 +509,13 @@ static struct ata_port_operations ht6560b_port_ops = {
 	.qc_prep 	= ata_qc_prep,
 	.qc_issue	= ata_qc_issue_prot,
 
-	.data_xfer	= ata_data_xfer,	/* FIXME: Check 32bit and noirq */
+	.data_xfer	= ata_data_xfer,    /* FIXME: Check 32bit and noirq */
 
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
@@ -462,7 +548,8 @@ static u8 opti_syscfg(u8 reg)
  *	This controller supports PIO0 to PIO3.
  */
 
-static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void opti82c611a_set_piomode(struct ata_port *ap,
+						struct ata_device *adev)
 {
 	u8 active, recover, setup;
 	struct ata_timing t;
@@ -549,7 +636,7 @@ static struct ata_port_operations opti82c611a_port_ops = {
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
@@ -681,77 +768,398 @@ static struct ata_port_operations opti82c46x_port_ops = {
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
+static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	struct ata_timing t;
+	struct legacy_data *qdi = ap->host->private_data;
+	int active, recovery;
+	u8 timing;
+
+	/* Get the timing data in cycles */
+	ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+	if (qdi->fast) {
+		active = 8 - FIT(t.active, 1, 8);
+		recovery = 18 - FIT(t.recover, 3, 18);
+	} else {
+		active = 9 - FIT(t.active, 2, 9);
+		recovery = 15 - FIT(t.recover, 0, 15);
+	}
+	timing = (recovery << 4) | active | 0x08;
+
+	qdi->clock[adev->devno] = timing;
+
+	outb(timing, qdi->timing);
+}
 
 /**
- *	legacy_init_one		-	attach a legacy interface
- *	@port: port number
- *	@io: I/O port start
- *	@ctrl: control port
+ *	qdi6580dp_set_piomode		-	PIO setup for dual channel
+ *	@ap: Port
+ *	@adev: Device
  *	@irq: interrupt line
  *
- *	Register an ISA bus IDE interface. Such interfaces are PIO and we
- *	assume do not support IRQ sharing.
+ *	In dual channel mode the 6580 has one clock per channel and we have
+ *	to software clockswitch in qc_issue_prot.
  */
 
-static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq)
+static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
-	struct legacy_data *ld = &legacy_data[nr_legacy_host];
-	struct ata_host *host;
-	struct ata_port *ap;
-	struct platform_device *pdev;
-	struct ata_port_operations *ops = &legacy_port_ops;
-	void __iomem *io_addr, *ctrl_addr;
-	int pio_modes = pio_mask;
-	u32 mask = (1 << port);
-	u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY;
-	int ret;
+	struct ata_timing t;
+	struct legacy_data *qdi = ap->host->private_data;
+	int active, recovery;
+	u8 timing;
 
-	pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
+	/* Get the timing data in cycles */
+	ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+	if (qdi->fast) {
+		active = 8 - FIT(t.active, 1, 8);
+		recovery = 18 - FIT(t.recover, 3, 18);
+	} else {
+		active = 9 - FIT(t.active, 2, 9);
+		recovery = 15 - FIT(t.recover, 0, 15);
+	}
+	timing = (recovery << 4) | active | 0x08;
 
-	ret = -EBUSY;
-	if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL ||
-	    devm_request_region(&pdev->dev, ctrl, 1, "pata_legacy") == NULL)
-		goto fail;
+	qdi->clock[adev->devno] = timing;
 
-	ret = -ENOMEM;
-	io_addr = devm_ioport_map(&pdev->dev, io, 8);
-	ctrl_addr = devm_ioport_map(&pdev->dev, ctrl, 1);
-	if (!io_addr || !ctrl_addr)
-		goto fail;
+	outb(timing, qdi->timing + 2 * ap->port_no);
+	/* Clear the FIFO */
+	if (adev->class != ATA_DEV_ATA)
+		outb(0x5F, qdi->timing + 3);
+}
 
-	if (ht6560a & mask) {
-		ops = &ht6560a_port_ops;
-		pio_modes = 0x07;
-		iordy = ATA_FLAG_NO_IORDY;
-	}
-	if (ht6560b & mask) {
-		ops = &ht6560b_port_ops;
-		pio_modes = 0x1F;
-	}
-	if (opti82c611a & mask) {
-		ops = &opti82c611a_port_ops;
-		pio_modes = 0x0F;
+/**
+ *	qdi6580_set_piomode		-	PIO setup for single channel
+ *	@ap: Port
+ *	@adev: Device
+ *
+ *	In single channel mode the 6580 has one clock per device and we can
+ *	avoid the requirement to clock switch. We also have to load the timing
+ *	into the right clock according to whether we are master or slave.
+ */
+
+static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	struct ata_timing t;
+	struct legacy_data *qdi = ap->host->private_data;
+	int active, recovery;
+	u8 timing;
+
+	/* Get the timing data in cycles */
+	ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+	if (qdi->fast) {
+		active = 8 - FIT(t.active, 1, 8);
+		recovery = 18 - FIT(t.recover, 3, 18);
+	} else {
+		active = 9 - FIT(t.active, 2, 9);
+		recovery = 15 - FIT(t.recover, 0, 15);
 	}
-	if (opti82c46x & mask) {
-		ops = &opti82c46x_port_ops;
-		pio_modes = 0x0F;
+	timing = (recovery << 4) | active | 0x08;
+	qdi->clock[adev->devno] = timing;
+	outb(timing, qdi->timing + 2 * adev->devno);
+	/* Clear the FIFO */
+	if (adev->class != ATA_DEV_ATA)
+		outb(0x5F, qdi->timing + 3);
+}
+
+/**
+ *	qdi_qc_issue_prot	-	command issue
+ *	@qc: command pending
+ *
+ *	Called when the libata layer is about to issue a command. We wrap
+ *	this interface so that we can load the correct ATA timings.
+ */
+
+static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_device *adev = qc->dev;
+	struct legacy_data *qdi = ap->host->private_data;
+
+	if (qdi->clock[adev->devno] != qdi->last) {
+		if (adev->pio_mode) {
+			qdi->last = qdi->clock[adev->devno];
+			outb(qdi->clock[adev->devno], qdi->timing +
+							2 * ap->port_no);
+		}
 	}
+	return ata_qc_issue_prot(qc);
+}
 
-	/* Probe for automatically detectable controllers */
+static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf,
+					unsigned int buflen, int rw)
+{
+	struct ata_port *ap = adev->link->ap;
+	int slop = buflen & 3;
 
-	if (io == 0x1F0 && ops == &legacy_port_ops) {
-		unsigned long flags;
+	if (ata_id_has_dword_io(adev->id)) {
+		if (rw == WRITE)
+			iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+		else
+			ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
 
-		local_irq_save(flags);
+		if (unlikely(slop)) {
+			u32 pad;
+			if (rw == WRITE) {
+				memcpy(&pad, buf + buflen - slop, slop);
+				pad = le32_to_cpu(pad);
+				iowrite32(pad, ap->ioaddr.data_addr);
+			} else {
+				pad = ioread32(ap->ioaddr.data_addr);
+				pad = cpu_to_le32(pad);
+				memcpy(buf + buflen - slop, &pad, slop);
+			}
+		}
+		return (buflen + 3) & ~3;
+	} else
+		return ata_data_xfer(adev, buf, buflen, rw);
+}
+
+static int qdi_port(struct platform_device *dev,
+			struct legacy_probe *lp, struct legacy_data *ld)
+{
+	if (devm_request_region(&dev->dev, lp->private, 4, "qdi") == NULL)
+		return -EBUSY;
+	ld->timing = lp->private;
+	return 0;
+}
+
+static struct ata_port_operations qdi6500_port_ops = {
+	.set_piomode	= qdi6500_set_piomode,
+
+	.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,
+
+	.freeze		= ata_bmdma_freeze,
+	.thaw		= ata_bmdma_thaw,
+	.error_handler	= ata_bmdma_error_handler,
+	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
+
+	.qc_prep 	= ata_qc_prep,
+	.qc_issue	= qdi_qc_issue_prot,
+
+	.data_xfer	= vlb32_data_xfer,
+
+	.irq_handler	= ata_interrupt,
+	.irq_clear	= ata_bmdma_irq_clear,
+	.irq_on		= ata_irq_on,
+
+	.port_start	= ata_sff_port_start,
+};
+
+static struct ata_port_operations qdi6580_port_ops = {
+	.set_piomode	= qdi6580_set_piomode,
+
+	.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,
+
+	.freeze		= ata_bmdma_freeze,
+	.thaw		= ata_bmdma_thaw,
+	.error_handler	= ata_bmdma_error_handler,
+	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
+
+	.qc_prep 	= ata_qc_prep,
+	.qc_issue	= ata_qc_issue_prot,
+
+	.data_xfer	= vlb32_data_xfer,
+
+	.irq_handler	= ata_interrupt,
+	.irq_clear	= ata_bmdma_irq_clear,
+	.irq_on		= ata_irq_on,
+
+	.port_start	= ata_sff_port_start,
+};
+
+static struct ata_port_operations qdi6580dp_port_ops = {
+	.set_piomode	= qdi6580dp_set_piomode,
+
+	.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,
+
+	.freeze		= ata_bmdma_freeze,
+	.thaw		= ata_bmdma_thaw,
+	.error_handler	= ata_bmdma_error_handler,
+	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
+
+	.qc_prep 	= ata_qc_prep,
+	.qc_issue	= qdi_qc_issue_prot,
+
+	.data_xfer	= vlb32_data_xfer,
+
+	.irq_handler	= ata_interrupt,
+	.irq_clear	= ata_bmdma_irq_clear,
+	.irq_on		= ata_irq_on,
+
+	.port_start	= ata_sff_port_start,
+};
+
+static DEFINE_SPINLOCK(winbond_lock);
+
+static void winbond_writecfg(unsigned long port, u8 reg, u8 val)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&winbond_lock, flags);
+	outb(reg, port + 0x01);
+	outb(val, port + 0x02);
+	spin_unlock_irqrestore(&winbond_lock, flags);
+}
+
+static u8 winbond_readcfg(unsigned long port, u8 reg)
+{
+	u8 val;
+
+	unsigned long flags;
+	spin_lock_irqsave(&winbond_lock, flags);
+	outb(reg, port + 0x01);
+	val = inb(port + 0x02);
+	spin_unlock_irqrestore(&winbond_lock, flags);
+
+	return val;
+}
+
+static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	struct ata_timing t;
+	struct legacy_data *winbond = ap->host->private_data;
+	int active, recovery;
+	u8 reg;
+	int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2);
+
+	reg = winbond_readcfg(winbond->timing, 0x81);
+
+	/* Get the timing data in cycles */
+	if (reg & 0x40)		/* Fast VLB bus, assume 50MHz */
+		ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
+	else
+		ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+	active = (FIT(t.active, 3, 17) - 1) & 0x0F;
+	recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F;
+	timing = (active << 4) | recovery;
+	winbond_writecfg(winbond->timing, timing, reg);
+
+	/* Load the setup timing */
+
+	reg = 0x35;
+	if (adev->class != ATA_DEV_ATA)
+		reg |= 0x08;	/* FIFO off */
+	if (!ata_pio_need_iordy(adev))
+		reg |= 0x02;	/* IORDY off */
+	reg |= (FIT(t.setup, 0, 3) << 6);
+	winbond_writecfg(winbond->timing, timing + 1, reg);
+}
+
+static int winbond_port(struct platform_device *dev,
+			struct legacy_probe *lp, struct legacy_data *ld)
+{
+	if (devm_request_region(&dev->dev, lp->private, 4, "winbond") == NULL)
+		return -EBUSY;
+	ld->timing = lp->private;
+	return 0;
+}
+
+static struct ata_port_operations winbond_port_ops = {
+	.set_piomode	= winbond_set_piomode,
+
+	.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,
+
+	.freeze		= ata_bmdma_freeze,
+	.thaw		= ata_bmdma_thaw,
+	.error_handler	= ata_bmdma_error_handler,
+	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
+
+	.qc_prep 	= ata_qc_prep,
+	.qc_issue	= ata_qc_issue_prot,
+
+	.data_xfer	= vlb32_data_xfer,
+
+	.irq_clear	= ata_bmdma_irq_clear,
+	.irq_on		= ata_irq_on,
 
+	.port_start	= ata_sff_port_start,
+};
+
+static struct legacy_controller controllers[] = {
+	{"BIOS",	&legacy_port_ops, 	0x1F,
+						ATA_FLAG_NO_IORDY,	NULL },
+	{"Snooping", 	&simple_port_ops, 	0x1F,
+						0	       ,	NULL },
+	{"PDC20230",	&pdc20230_port_ops,	0x7,
+						ATA_FLAG_NO_IORDY,	NULL },
+	{"HT6560A",	&ht6560a_port_ops,	0x07,
+						ATA_FLAG_NO_IORDY,	NULL },
+	{"HT6560B",	&ht6560b_port_ops,	0x1F,
+						ATA_FLAG_NO_IORDY,	NULL },
+	{"OPTI82C611A",	&opti82c611a_port_ops,	0x0F,
+						0	       ,	NULL },
+	{"OPTI82C46X",	&opti82c46x_port_ops,	0x0F,
+						0	       ,	NULL },
+	{"QDI6500",	&qdi6500_port_ops,	0x07,
+					ATA_FLAG_NO_IORDY,	qdi_port },
+	{"QDI6580",	&qdi6580_port_ops,	0x1F,
+					0	       ,	qdi_port },
+	{"QDI6580DP",	&qdi6580dp_port_ops,	0x1F,
+					0	       ,	qdi_port },
+	{"W83759A",	&winbond_port_ops,	0x1F,
+					0	       ,	winbond_port }
+};
+
+/**
+ *	probe_chip_type		-	Discover controller
+ *	@probe: Probe entry to check
+ *
+ *	Probe an ATA port and identify the type of controller. We don't
+ *	check if the controller appears to be driveless at this point.
+ */
+
+static __init int probe_chip_type(struct legacy_probe *probe)
+{
+	int mask = 1 << probe->slot;
+
+	if (winbond && (probe->port == 0x1F0 || probe->port == 0x170)) {
+		u8 reg = winbond_readcfg(winbond, 0x81);
+		reg |= 0x80;	/* jumpered mode off */
+		winbond_writecfg(winbond, 0x81, reg);
+		reg = winbond_readcfg(winbond, 0x83);
+		reg |= 0xF0;	/* local control */
+		winbond_writecfg(winbond, 0x83, reg);
+		reg = winbond_readcfg(winbond, 0x85);
+		reg |= 0xF0;	/* programmable timing */
+		winbond_writecfg(winbond, 0x85, reg);
+
+		reg = winbond_readcfg(winbond, 0x81);
+
+		if (reg & mask)
+			return W83759A;
+	}
+	if (probe->port == 0x1F0) {
+		unsigned long flags;
+		local_irq_save(flags);
 		/* Probes */
-		inb(0x1F5);
 		outb(inb(0x1F2) | 0x80, 0x1F2);
+		inb(0x1F5);
 		inb(0x1F2);
 		inb(0x3F6);
 		inb(0x3F6);
@@ -760,29 +1168,83 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
 
 		if ((inb(0x1F2) & 0x80) == 0) {
 			/* PDC20230c or 20630 ? */
-			printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n");
-				pio_modes = 0x07;
-			ops = &pdc20230_port_ops;
-			iordy = ATA_FLAG_NO_IORDY;
+			printk(KERN_INFO  "PDC20230-C/20630 VLB ATA controller"
+							" detected.\n");
 			udelay(100);
 			inb(0x1F5);
+			local_irq_restore(flags);
+			return PDC20230;
 		} else {
 			outb(0x55, 0x1F2);
 			inb(0x1F2);
 			inb(0x1F2);
-			if (inb(0x1F2) == 0x00) {
-				printk(KERN_INFO "PDC20230-B VLB ATA controller detected.\n");
-			}
+			if (inb(0x1F2) == 0x00)
+				printk(KERN_INFO "PDC20230-B VLB ATA "
+						     "controller detected.\n");
+			local_irq_restore(flags);
+			return BIOS;
 		}
 		local_irq_restore(flags);
 	}
 
+	if (ht6560a & mask)
+		return HT6560A;
+	if (ht6560b & mask)
+		return HT6560B;
+	if (opti82c611a & mask)
+		return OPTI611A;
+	if (opti82c46x & mask)
+		return OPTI46X;
+	if (autospeed & mask)
+		return SNOOP;
+	return BIOS;
+}
+
+
+/**
+ *	legacy_init_one		-	attach a legacy interface
+ *	@pl: probe record
+ *
+ *	Register an ISA bus IDE interface. Such interfaces are PIO and we
+ *	assume do not support IRQ sharing.
+ */
+
+static __init int legacy_init_one(struct legacy_probe *probe)
+{
+	struct legacy_controller *controller = &controllers[probe->type];
+	int pio_modes = controller->pio_mask;
+	unsigned long io = probe->port;
+	u32 mask = (1 << probe->slot);
+	struct ata_port_operations *ops = controller->ops;
+	struct legacy_data *ld = &legacy_data[probe->slot];
+	struct ata_host *host = NULL;
+	struct ata_port *ap;
+	struct platform_device *pdev;
+	struct ata_device *dev;
+	void __iomem *io_addr, *ctrl_addr;
+	u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY;
+	int ret;
 
-	/* Chip does mode setting by command snooping */
-	if (ops == &legacy_port_ops && (autospeed & mask))
-		ops = &simple_port_ops;
+	iordy |= controller->flags;
+
+	pdev = platform_device_register_simple(DRV_NAME, probe->slot, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	ret = -EBUSY;
+	if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL ||
+	    devm_request_region(&pdev->dev, io + 0x0206, 1,
+							"pata_legacy") == NULL)
+		goto fail;
 
 	ret = -ENOMEM;
+	io_addr = devm_ioport_map(&pdev->dev, io, 8);
+	ctrl_addr = devm_ioport_map(&pdev->dev, io + 0x0206, 1);
+	if (!io_addr || !ctrl_addr)
+		goto fail;
+	if (controller->setup)
+		if (controller->setup(pdev, probe, ld) < 0)
+			goto fail;
 	host = ata_host_alloc(&pdev->dev, 1);
 	if (!host)
 		goto fail;
@@ -795,19 +1257,29 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
 	ap->ioaddr.altstatus_addr = ctrl_addr;
 	ap->ioaddr.ctl_addr = ctrl_addr;
 	ata_std_ports(&ap->ioaddr);
-	ap->private_data = ld;
+	ap->host->private_data = ld;
 
-	ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl);
+	ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, io + 0x0206);
 
-	ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
+	ret = ata_host_activate(host, probe->irq, ata_interrupt, 0,
+								&legacy_sht);
 	if (ret)
 		goto fail;
-
-	legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
 	ld->platform_dev = pdev;
-	return 0;
 
+	/* Nothing found means we drop the port as its probably not there */
+
+	ret = -ENODEV;
+	ata_link_for_each_dev(dev, &ap->link) {
+		if (!ata_dev_absent(dev)) {
+			legacy_host[probe->slot] = host;
+			ld->platform_dev = pdev;
+			return 0;
+		}
+	}
 fail:
+	if (host)
+		ata_host_detach(host);
 	platform_device_unregister(pdev);
 	return ret;
 }
@@ -818,13 +1290,15 @@ fail:
  *	@master: set this if we find an ATA master
  *	@master: set this if we find an ATA secondary
  *
- *	A small number of vendors implemented early PCI ATA interfaces on bridge logic
- *	without the ATA interface being PCI visible. Where we have a matching PCI driver
- *	we must skip the relevant device here. If we don't know about it then the legacy
- *	driver is the right driver anyway.
+ *	A small number of vendors implemented early PCI ATA interfaces
+ *	on bridge logic without the ATA interface being PCI visible.
+ *	Where we have a matching PCI driver we must skip the relevant
+ *	device here. If we don't know about it then the legacy driver
+ *	is the right driver anyway.
  */
 
-static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *secondary)
+static void __init legacy_check_special_cases(struct pci_dev *p, int *primary,
+								int *secondary)
 {
 	/* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */
 	if (p->vendor == 0x1078 && p->device == 0x0000) {
@@ -840,7 +1314,8 @@ static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *sec
 	if (p->vendor == 0x8086 && p->device == 0x1234) {
 		u16 r;
 		pci_read_config_word(p, 0x6C, &r);
-		if (r & 0x8000) {	/* ATA port enabled */
+		if (r & 0x8000) {
+			/* ATA port enabled */
 			if (r & 0x4000)
 				*secondary = 1;
 			else
@@ -850,6 +1325,114 @@ static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *sec
 	}
 }
 
+static __init void probe_opti_vlb(void)
+{
+	/* If an OPTI 82C46X is present find out where the channels are */
+	static const char *optis[4] = {
+		"3/463MV", "5MV",
+		"5MVA", "5MVB"
+	};
+	u8 chans = 1;
+	u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6;
+
+	opti82c46x = 3;	/* Assume master and slave first */
+	printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n",
+								optis[ctrl]);
+	if (ctrl == 3)
+		chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1;
+	ctrl = opti_syscfg(0xAC);
+	/* Check enabled and this port is the 465MV port. On the
+	   MVB we may have two channels */
+	if (ctrl & 8) {
+		if (chans == 2) {
+			legacy_probe_add(0x1F0, 14, OPTI46X, 0);
+			legacy_probe_add(0x170, 15, OPTI46X, 0);
+		}
+		if (ctrl & 4)
+			legacy_probe_add(0x170, 15, OPTI46X, 0);
+		else
+			legacy_probe_add(0x1F0, 14, OPTI46X, 0);
+	} else
+		legacy_probe_add(0x1F0, 14, OPTI46X, 0);
+}
+
+static __init void qdi65_identify_port(u8 r, u8 res, unsigned long port)
+{
+	static const unsigned long ide_port[2] = { 0x170, 0x1F0 };
+	/* Check card type */
+	if ((r & 0xF0) == 0xC0) {
+		/* QD6500: single channel */
+		if (r & 8)
+			/* Disabled ? */
+			return;
+		legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01),
+								QDI6500, port);
+	}
+	if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) {
+		/* QD6580: dual channel */
+		if (!request_region(port + 2 , 2, "pata_qdi")) {
+			release_region(port, 2);
+			return;
+		}
+		res = inb(port + 3);
+		/* Single channel mode ? */
+		if (res & 1)
+			legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01),
+								QDI6580, port);
+		else { /* Dual channel mode */
+			legacy_probe_add(0x1F0, 14, QDI6580DP, port);
+			/* port + 0x02, r & 0x04 */
+			legacy_probe_add(0x170, 15, QDI6580DP, port + 2);
+		}
+		release_region(port + 2, 2);
+	}
+}
+
+static __init void probe_qdi_vlb(void)
+{
+	unsigned long flags;
+	static const unsigned long qd_port[2] = { 0x30, 0xB0 };
+	int i;
+
+	/*
+	 *	Check each possible QD65xx base address
+	 */
+
+	for (i = 0; i < 2; i++) {
+		unsigned long port = qd_port[i];
+		u8 r, res;
+
+
+		if (request_region(port, 2, "pata_qdi")) {
+			/* Check for a card */
+			local_irq_save(flags);
+			/* I have no h/w that needs this delay but it
+			   is present in the historic code */
+			r = inb(port);
+			udelay(1);
+			outb(0x19, port);
+			udelay(1);
+			res = inb(port);
+			udelay(1);
+			outb(r, port);
+			udelay(1);
+			local_irq_restore(flags);
+
+			/* Fail */
+			if (res == 0x19) {
+				release_region(port, 2);
+				continue;
+			}
+			/* Passes the presence test */
+			r = inb(port + 1);
+			udelay(1);
+			/* Check port agrees with port set */
+			if ((r & 2) >> 1 == i)
+				qdi65_identify_port(r, res, port);
+			release_region(port, 2);
+		}
+	}
+}
 
 /**
  *	legacy_init		-	attach legacy interfaces
@@ -867,15 +1450,17 @@ static __init int legacy_init(void)
 	int ct = 0;
 	int primary = 0;
 	int secondary = 0;
-	int last_port = NR_HOST;
+	int pci_present = 0;
+	struct legacy_probe *pl = &probe_list[0];
+	int slot = 0;
 
 	struct pci_dev *p = NULL;
 
 	for_each_pci_dev(p) {
 		int r;
-		/* Check for any overlap of the system ATA mappings. Native mode controllers
-		   stuck on these addresses or some devices in 'raid' mode won't be found by
-		   the storage class test */
+		/* Check for any overlap of the system ATA mappings. Native
+		   mode controllers stuck on these addresses or some devices
+		   in 'raid' mode won't be found by the storage class test */
 		for (r = 0; r < 6; r++) {
 			if (pci_resource_start(p, r) == 0x1f0)
 				primary = 1;
@@ -885,49 +1470,39 @@ static __init int legacy_init(void)
 		/* Check for special cases */
 		legacy_check_special_cases(p, &primary, &secondary);
 
-		/* If PCI bus is present then don't probe for tertiary legacy ports */
-		if (probe_all == 0)
-			last_port = 2;
+		/* If PCI bus is present then don't probe for tertiary
+		   legacy ports */
+		pci_present = 1;
 	}
 
-	/* If an OPTI 82C46X is present find out where the channels are */
-	if (opti82c46x) {
-		static const char *optis[4] = {
-			"3/463MV", "5MV",
-			"5MVA", "5MVB"
-		};
-		u8 chans = 1;
-		u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6;
-
-		opti82c46x = 3;	/* Assume master and slave first */
-		printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", optis[ctrl]);
-		if (ctrl == 3)
-			chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1;
-		ctrl = opti_syscfg(0xAC);
-		/* Check enabled and this port is the 465MV port. On the
-		   MVB we may have two channels */
-		if (ctrl & 8) {
-			if (ctrl & 4)
-				opti82c46x = 2;	/* Slave */
-			else
-				opti82c46x = 1;	/* Master */
-			if (chans == 2)
-				opti82c46x = 3; /* Master and Slave */
-		}	/* Slave only */
-		else if (chans == 1)
-			opti82c46x = 1;
+	if (winbond == 1)
+		winbond = 0x130;	/* Default port, alt is 1B0 */
+
+	if (primary == 0 || all)
+		legacy_probe_add(0x1F0, 14, UNKNOWN, 0);
+	if (secondary == 0 || all)
+		legacy_probe_add(0x170, 15, UNKNOWN, 0);
+
+	if (probe_all || !pci_present) {
+		/* ISA/VLB extra ports */
+		legacy_probe_add(0x1E8, 11, UNKNOWN, 0);
+		legacy_probe_add(0x168, 10, UNKNOWN, 0);
+		legacy_probe_add(0x1E0, 8, UNKNOWN, 0);
+		legacy_probe_add(0x160, 12, UNKNOWN, 0);
 	}
 
-	for (i = 0; i < last_port; i++) {
-		/* Skip primary if we have seen a PCI one */
-		if (i == 0 && primary == 1)
-			continue;
-		/* Skip secondary if we have seen a PCI one */
-		if (i == 1 && secondary == 1)
+	if (opti82c46x)
+		probe_opti_vlb();
+	if (qdi)
+		probe_qdi_vlb();
+
+	for (i = 0; i < NR_HOST; i++, pl++) {
+		if (pl->port == 0)
 			continue;
-		if (legacy_init_one(i, legacy_port[i],
-				   legacy_port[i] + 0x0206,
-				   legacy_irq[i]) == 0)
+		if (pl->type == UNKNOWN)
+			pl->type = probe_chip_type(pl);
+		pl->slot = slot++;
+		if (legacy_init_one(pl) == 0)
 			ct++;
 	}
 	if (ct != 0)
@@ -941,11 +1516,8 @@ static __exit void legacy_exit(void)
 
 	for (i = 0; i < nr_legacy_host; i++) {
 		struct legacy_data *ld = &legacy_data[i];
-
 		ata_host_detach(legacy_host[i]);
 		platform_device_unregister(ld->platform_dev);
-		if (ld->timing)
-			release_region(ld->timing, 2);
 	}
 }
 
@@ -960,9 +1532,9 @@ module_param(ht6560a, int, 0);
 module_param(ht6560b, int, 0);
 module_param(opti82c611a, int, 0);
 module_param(opti82c46x, int, 0);
+module_param(qdi, int, 0);
 module_param(pio_mask, int, 0);
 module_param(iordy_mask, int, 0);
 
 module_init(legacy_init);
 module_exit(legacy_exit);
-
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 1a7ca37168b2..5413ebfa72e5 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -364,7 +364,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
 {
 	unsigned int ipb_freq;
 	struct resource res_mem;
-	int ata_irq = NO_IRQ;
+	int ata_irq;
 	struct mpc52xx_ata __iomem *ata_regs;
 	struct mpc52xx_ata_priv *priv;
 	int rv;
diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c
new file mode 100644
index 000000000000..1c1b83541d13
--- /dev/null
+++ b/drivers/ata/pata_ninja32.c
@@ -0,0 +1,214 @@
+/*
+ * pata_ninja32.c 	- Ninja32 PATA for new ATA layer
+ *			  (C) 2007 Red Hat Inc
+ *			  Alan Cox <alan@redhat.com>
+ *
+ * Note: The controller like many controllers has shared timings for
+ * PIO and DMA. We thus flip to the DMA timings in dma_start and flip back
+ * in the dma_stop function. Thus we actually don't need a set_dmamode
+ * method as the PIO method is always called and will set the right PIO
+ * timing parameters.
+ *
+ * The Ninja32 Cardbus is not a generic SFF controller. Instead it is
+ * laid out as follows off BAR 0. This is based upon Mark Lord's delkin
+ * driver and the extensive analysis done by the BSD developers, notably
+ * ITOH Yasufumi.
+ *
+ *	Base + 0x00 IRQ Status
+ *	Base + 0x01 IRQ control
+ *	Base + 0x02 Chipset control
+ *	Base + 0x04 VDMA and reset control + wait bits
+ *	Base + 0x08 BMIMBA
+ *	Base + 0x0C DMA Length
+ *	Base + 0x10 Taskfile
+ *	Base + 0x18 BMDMA Status ?
+ *	Base + 0x1C
+ *	Base + 0x1D Bus master control
+ *		bit 0 = enable
+ *		bit 1 = 0 write/1 read
+ *		bit 2 = 1 sgtable
+ *		bit 3 = go
+ *		bit 4-6 wait bits
+ *		bit 7 = done
+ *	Base + 0x1E AltStatus
+ *	Base + 0x1F timing register
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_ninja32"
+#define DRV_VERSION "0.0.1"
+
+
+/**
+ *	ninja32_set_piomode	-	set initial PIO mode data
+ *	@ap: ATA interface
+ *	@adev: ATA device
+ *
+ *	Called to do the PIO mode setup. Our timing registers are shared
+ *	but we want to set the PIO timing by default.
+ */
+
+static void ninja32_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	static u16 pio_timing[5] = {
+		0xd6, 0x85, 0x44, 0x33, 0x13
+	};
+	iowrite8(pio_timing[adev->pio_mode - XFER_PIO_0],
+		 ap->ioaddr.bmdma_addr + 0x1f);
+	ap->private_data = adev;
+}
+
+
+static void ninja32_dev_select(struct ata_port *ap, unsigned int device)
+{
+	struct ata_device *adev = &ap->link.device[device];
+	if (ap->private_data != adev) {
+		iowrite8(0xd6, ap->ioaddr.bmdma_addr + 0x1f);
+		ata_std_dev_select(ap, device);
+		ninja32_set_piomode(ap, adev);
+	}
+}
+
+static struct scsi_host_template ninja32_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations ninja32_port_ops = {
+	.set_piomode	= ninja32_set_piomode,
+	.mode_filter	= ata_pci_default_filter,
+
+	.tf_load	= ata_tf_load,
+	.tf_read	= ata_tf_read,
+	.check_status 	= ata_check_status,
+	.exec_command	= ata_exec_command,
+	.dev_select 	= ninja32_dev_select,
+
+	.freeze		= ata_bmdma_freeze,
+	.thaw		= ata_bmdma_thaw,
+	.error_handler	= ata_bmdma_error_handler,
+	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
+
+	.bmdma_setup 	= ata_bmdma_setup,
+	.bmdma_start 	= ata_bmdma_start,
+	.bmdma_stop	= ata_bmdma_stop,
+	.bmdma_status 	= ata_bmdma_status,
+
+	.qc_prep 	= ata_qc_prep,
+	.qc_issue	= ata_qc_issue_prot,
+
+	.data_xfer	= ata_data_xfer,
+
+	.irq_handler	= ata_interrupt,
+	.irq_clear	= ata_bmdma_irq_clear,
+	.irq_on		= ata_irq_on,
+
+	.port_start	= ata_sff_port_start,
+};
+
+static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct ata_host *host;
+	struct ata_port *ap;
+	void __iomem *base;
+	int rc;
+
+	host = ata_host_alloc(&dev->dev, 1);
+	if (!host)
+		return -ENOMEM;
+	ap = host->ports[0];
+
+	/* Set up the PCI device */
+	rc = pcim_enable_device(dev);
+	if (rc)
+		return rc;
+	rc = pcim_iomap_regions(dev, 1 << 0, DRV_NAME);
+	if (rc == -EBUSY)
+		pcim_pin_device(dev);
+	if (rc)
+		return rc;
+
+	host->iomap = pcim_iomap_table(dev);
+	rc = pci_set_dma_mask(dev, ATA_DMA_MASK);
+	if (rc)
+		return rc;
+	rc = pci_set_consistent_dma_mask(dev, ATA_DMA_MASK);
+	if (rc)
+		return rc;
+	pci_set_master(dev);
+
+	/* Set up the register mappings */
+	base = host->iomap[0];
+	if (!base)
+		return -ENOMEM;
+	ap->ops = &ninja32_port_ops;
+	ap->pio_mask = 0x1F;
+	ap->flags |= ATA_FLAG_SLAVE_POSS;
+
+	ap->ioaddr.cmd_addr = base + 0x10;
+	ap->ioaddr.ctl_addr = base + 0x1E;
+	ap->ioaddr.altstatus_addr = base + 0x1E;
+	ap->ioaddr.bmdma_addr = base;
+	ata_std_ports(&ap->ioaddr);
+
+	iowrite8(0x05, base + 0x01);	/* Enable interrupt lines */
+	iowrite8(0xB3, base + 0x02);	/* Burst, ?? setup */
+	iowrite8(0x00, base + 0x04);	/* WAIT0 ? */
+	/* FIXME: Should we disable them at remove ? */
+	return ata_host_activate(host, dev->irq, ata_interrupt,
+				 IRQF_SHARED, &ninja32_sht);
+}
+
+static const struct pci_device_id ninja32[] = {
+	{ 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ },
+};
+
+static struct pci_driver ninja32_pci_driver = {
+	.name 		= DRV_NAME,
+	.id_table	= ninja32,
+	.probe 		= ninja32_init_one,
+	.remove		= ata_pci_remove_one
+};
+
+static int __init ninja32_init(void)
+{
+	return pci_register_driver(&ninja32_pci_driver);
+}
+
+static void __exit ninja32_exit(void)
+{
+	pci_unregister_driver(&ninja32_pci_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Ninja32 ATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ninja32);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ninja32_init);
+module_exit(ninja32_exit);
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index fd36099428a4..3e7f6a9da28b 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@
 
 
 #define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.3.2"
+#define DRV_VERSION "0.3.3"
 
 /*
  *	Private data structure to glue stuff together
@@ -86,6 +86,47 @@ static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_d
 	return ata_do_set_mode(link, r_failed_dev);
 }
 
+/**
+ *	pcmcia_set_mode_8bit	-	PCMCIA specific mode setup
+ *	@link: link
+ *	@r_failed_dev: Return pointer for failed device
+ *
+ *	For the simple emulated 8bit stuff the less we do the better.
+ */
+
+static int pcmcia_set_mode_8bit(struct ata_link *link,
+				struct ata_device **r_failed_dev)
+{
+	return 0;
+}
+
+/**
+ *	ata_data_xfer_8bit	 -	Transfer data by 8bit PIO
+ *	@dev: device to target
+ *	@buf: data buffer
+ *	@buflen: buffer length
+ *	@rw: read/write
+ *
+ *	Transfer data from/to the device data register by 8 bit PIO.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+static unsigned int ata_data_xfer_8bit(struct ata_device *dev,
+				unsigned char *buf, unsigned int buflen, int rw)
+{
+	struct ata_port *ap = dev->link->ap;
+
+	if (rw == READ)
+		ioread8_rep(ap->ioaddr.data_addr, buf, buflen);
+	else
+		iowrite8_rep(ap->ioaddr.data_addr, buf, buflen);
+
+	return buflen;
+}
+
+
 static struct scsi_host_template pcmcia_sht = {
 	.module			= THIS_MODULE,
 	.name			= DRV_NAME,
@@ -129,6 +170,31 @@ static struct ata_port_operations pcmcia_port_ops = {
 	.port_start	= ata_sff_port_start,
 };
 
+static struct ata_port_operations pcmcia_8bit_port_ops = {
+	.set_mode	= pcmcia_set_mode_8bit,
+	.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,
+
+	.freeze		= ata_bmdma_freeze,
+	.thaw		= ata_bmdma_thaw,
+	.error_handler	= ata_bmdma_error_handler,
+	.post_internal_cmd = ata_bmdma_post_internal_cmd,
+	.cable_detect	= ata_cable_40wire,
+
+	.qc_prep 	= ata_qc_prep,
+	.qc_issue	= ata_qc_issue_prot,
+
+	.data_xfer	= ata_data_xfer_8bit,
+
+	.irq_clear	= ata_bmdma_irq_clear,
+	.irq_on		= ata_irq_on,
+
+	.port_start	= ata_sff_port_start,
+};
+
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
@@ -153,9 +219,12 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
 		cistpl_cftable_entry_t dflt;
 	} *stk = NULL;
 	cistpl_cftable_entry_t *cfg;
-	int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM;
+	int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p;
 	unsigned long io_base, ctl_base;
 	void __iomem *io_addr, *ctl_addr;
+	int n_ports = 1;
+
+	struct ata_port_operations *ops = &pcmcia_port_ops;
 
 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (info == NULL)
@@ -282,27 +351,32 @@ next_entry:
 	/* FIXME: Could be more ports at base + 0x10 but we only deal with
 	   one right now */
 	if (pdev->io.NumPorts1 >= 0x20)
-		printk(KERN_WARNING DRV_NAME ": second channel not yet supported.\n");
+		n_ports = 2;
 
+	if (pdev->manf_id == 0x0097 && pdev->card_id == 0x1620)
+		ops = &pcmcia_8bit_port_ops;
 	/*
 	 *	Having done the PCMCIA plumbing the ATA side is relatively
 	 *	sane.
 	 */
 	ret = -ENOMEM;
-	host = ata_host_alloc(&pdev->dev, 1);
+	host = ata_host_alloc(&pdev->dev, n_ports);
 	if (!host)
 		goto failed;
-	ap = host->ports[0];
 
-	ap->ops = &pcmcia_port_ops;
-	ap->pio_mask = 1;		/* ISA so PIO 0 cycles */
-	ap->flags |= ATA_FLAG_SLAVE_POSS;
-	ap->ioaddr.cmd_addr = io_addr;
-	ap->ioaddr.altstatus_addr = ctl_addr;
-	ap->ioaddr.ctl_addr = ctl_addr;
-	ata_std_ports(&ap->ioaddr);
+	for (p = 0; p < n_ports; p++) {
+		ap = host->ports[p];
 
-	ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base);
+		ap->ops = ops;
+		ap->pio_mask = 1;		/* ISA so PIO 0 cycles */
+		ap->flags |= ATA_FLAG_SLAVE_POSS;
+		ap->ioaddr.cmd_addr = io_addr + 0x10 * p;
+		ap->ioaddr.altstatus_addr = ctl_addr + 0x10 * p;
+		ap->ioaddr.ctl_addr = ctl_addr + 0x10 * p;
+		ata_std_ports(&ap->ioaddr);
+
+		ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base);
+	}
 
 	/* activate */
 	ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
@@ -360,6 +434,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
 	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
 	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
 	PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),	/* SanDisk CFA */
+	PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), 	/* TI emulated */
 	PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),	/* Toshiba */
 	PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
 	PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000),	/* Samsung */
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 2622577521a1..028af5dbeed6 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -348,7 +348,7 @@ static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long
 	ata_id_c_string(pair->id, model_num, ATA_ID_PROD,
 			  ATA_ID_PROD_LEN + 1);
 	/* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */
-	if (strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6)
+	if (strstr(model_num, "Maxtor") == NULL && pair->dma_mode == XFER_UDMA_6)
 		mask &= ~ (1 << (6 + ATA_SHIFT_UDMA));
 
 	return ata_pci_default_filter(adev, mask);
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 6c9689b59b06..3ed866723e0c 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -168,8 +168,7 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
 	pdc202xx_set_dmamode(ap, qc->dev);
 
 	/* Cases the state machine will not complete correctly without help */
-	if ((tf->flags & ATA_TFLAG_LBA48) ||  tf->protocol == ATA_PROT_ATAPI_DMA)
-	{
+	if ((tf->flags & ATA_TFLAG_LBA48) ||  tf->protocol == ATAPI_PROT_DMA) {
 		len = qc->nbytes / 2;
 
 		if (tf->flags & ATA_TFLAG_WRITE)
@@ -208,7 +207,7 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
 	void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no);
 
 	/* Cases the state machine will not complete correctly */
-	if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) {
+	if (tf->protocol == ATAPI_PROT_DMA || (tf->flags & ATA_TFLAG_LBA48)) {
 		iowrite32(0, atapi_reg);
 		iowrite8(ioread8(clock) & ~sel66, clock);
 	}
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index a4c0e502cb42..9f308ed76cc8 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -124,29 +124,33 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
 	return ata_qc_issue_prot(qc);
 }
 
-static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+static unsigned int qdi_data_xfer(struct ata_device *dev, unsigned char *buf,
+				  unsigned int buflen, int rw)
 {
-	struct ata_port *ap = adev->link->ap;
-	int slop = buflen & 3;
+	if (ata_id_has_dword_io(dev->id)) {
+		struct ata_port *ap = dev->link->ap;
+		int slop = buflen & 3;
 
-	if (ata_id_has_dword_io(adev->id)) {
-		if (write_data)
-			iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
-		else
+		if (rw == READ)
 			ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+		else
+			iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
 
 		if (unlikely(slop)) {
-			__le32 pad = 0;
-			if (write_data) {
-				memcpy(&pad, buf + buflen - slop, slop);
-				iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
-			} else {
+			u32 pad;
+			if (rw == READ) {
 				pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
 				memcpy(buf + buflen - slop, &pad, slop);
+			} else {
+				memcpy(&pad, buf + buflen - slop, slop);
+				iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
 			}
+			buflen += 4 - slop;
 		}
 	} else
-		ata_data_xfer(adev, buf, buflen, write_data);
+		buflen = ata_data_xfer(dev, buf, buflen, rw);
+
+	return buflen;
 }
 
 static struct scsi_host_template qdi_sht = {
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index ea2ef9fc15be..55055b27524c 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -768,45 +768,47 @@ static u8 scc_bmdma_status (struct ata_port *ap)
 
 /**
  *	scc_data_xfer - Transfer data by PIO
- *	@adev: device for this I/O
+ *	@dev: device for this I/O
  *	@buf: data buffer
  *	@buflen: buffer length
- *	@write_data: read/write
+ *	@rw: read/write
  *
  *	Note: Original code is ata_data_xfer().
  */
 
-static void scc_data_xfer (struct ata_device *adev, unsigned char *buf,
-			   unsigned int buflen, int write_data)
+static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf,
+				   unsigned int buflen, int rw)
 {
-	struct ata_port *ap = adev->link->ap;
+	struct ata_port *ap = dev->link->ap;
 	unsigned int words = buflen >> 1;
 	unsigned int i;
 	u16 *buf16 = (u16 *) buf;
 	void __iomem *mmio = ap->ioaddr.data_addr;
 
 	/* Transfer multiple of 2 bytes */
-	if (write_data) {
-		for (i = 0; i < words; i++)
-			out_be32(mmio, cpu_to_le16(buf16[i]));
-	} else {
+	if (rw == READ)
 		for (i = 0; i < words; i++)
 			buf16[i] = le16_to_cpu(in_be32(mmio));
-	}
+	else
+		for (i = 0; i < words; i++)
+			out_be32(mmio, cpu_to_le16(buf16[i]));
 
 	/* Transfer trailing 1 byte, if any. */
 	if (unlikely(buflen & 0x01)) {
 		u16 align_buf[1] = { 0 };
 		unsigned char *trailing_buf = buf + buflen - 1;
 
-		if (write_data) {
-			memcpy(align_buf, trailing_buf, 1);
-			out_be32(mmio, cpu_to_le16(align_buf[0]));
-		} else {
+		if (rw == READ) {
 			align_buf[0] = le16_to_cpu(in_be32(mmio));
 			memcpy(trailing_buf, align_buf, 1);
+		} else {
+			memcpy(align_buf, trailing_buf, 1);
+			out_be32(mmio, cpu_to_le16(align_buf[0]));
 		}
+		words++;
 	}
+
+	return words << 1;
 }
 
 /**
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 8bed88873720..9c523fbf529e 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -41,7 +41,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_serverworks"
-#define DRV_VERSION "0.4.2"
+#define DRV_VERSION "0.4.3"
 
 #define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
 #define SVWKS_CSB6_REVISION	0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
@@ -102,7 +102,7 @@ static int osb4_cable(struct ata_port *ap) {
 }
 
 /**
- *	csb4_cable	-	CSB5/6 cable detect
+ *	csb_cable	-	CSB5/6 cable detect
  *	@ap: ATA port to check
  *
  *	Serverworks default arrangement is to use the drive side detection
@@ -110,7 +110,7 @@ static int osb4_cable(struct ata_port *ap) {
  */
 
 static int csb_cable(struct ata_port *ap) {
-	return ATA_CBL_PATA80;
+	return ATA_CBL_PATA_UNK;
 }
 
 struct sv_cable_table {
@@ -231,7 +231,6 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo
 	return ata_pci_default_filter(adev, mask);
 }
 
-
 /**
  *	serverworks_set_piomode	-	set initial PIO mode data
  *	@ap: ATA interface
@@ -243,7 +242,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo
 static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
 	static const u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-	int offset = 1 + (2 * ap->port_no) - adev->devno;
+	int offset = 1 + 2 * ap->port_no - adev->devno;
 	int devbits = (2 * ap->port_no + adev->devno) * 4;
 	u16 csb5_pio;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 453d72bf2598..39627ab684bf 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -185,7 +185,8 @@ static int via_cable_detect(struct ata_port *ap) {
 	if (ata66 & (0x10100000 >> (16 * ap->port_no)))
 		return ATA_CBL_PATA80;
 	/* Check with ACPI so we can spot BIOS reported SATA bridges */
-	if (ata_acpi_cbl_80wire(ap))
+	if (ata_acpi_init_gtm(ap) &&
+	    ata_acpi_cbl_80wire(ap, ata_acpi_init_gtm(ap)))
 		return ATA_CBL_PATA80;
 	return ATA_CBL_PATA40;
 }
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 7116a9e7a8b2..99c92eda217b 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -92,29 +92,33 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
 }
 
 
-static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+static unsigned int winbond_data_xfer(struct ata_device *dev,
+			unsigned char *buf, unsigned int buflen, int rw)
 {
-	struct ata_port *ap = adev->link->ap;
+	struct ata_port *ap = dev->link->ap;
 	int slop = buflen & 3;
 
-	if (ata_id_has_dword_io(adev->id)) {
-		if (write_data)
-			iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
-		else
+	if (ata_id_has_dword_io(dev->id)) {
+		if (rw == READ)
 			ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
+		else
+			iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
 
 		if (unlikely(slop)) {
-			__le32 pad = 0;
-			if (write_data) {
-				memcpy(&pad, buf + buflen - slop, slop);
-				iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
-			} else {
+			u32 pad;
+			if (rw == READ) {
 				pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
 				memcpy(buf + buflen - slop, &pad, slop);
+			} else {
+				memcpy(&pad, buf + buflen - slop, slop);
+				iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
 			}
+			buflen += 4 - slop;
 		}
 	} else
-		ata_data_xfer(adev, buf, buflen, write_data);
+		buflen = ata_data_xfer(dev, buf, buflen, rw);
+
+	return buflen;
 }
 
 static struct scsi_host_template winbond_sht = {
@@ -191,7 +195,7 @@ static __init int winbond_init_one(unsigned long port)
 	reg = winbond_readcfg(port, 0x81);
 
 	if (!(reg & 0x03))		/* Disabled */
-		return 0;
+		return -ENODEV;
 
 	for (i = 0; i < 2 ; i ++) {
 		unsigned long cmd_port = 0x1F0 - (0x80 * i);
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index bd4c2a3c88d7..8e1b7e9c0ae4 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -321,8 +321,9 @@ static int adma_fill_sg(struct ata_queued_cmd *qc)
 	u8  *buf = pp->pkt, *last_buf = NULL;
 	int i = (2 + buf[3]) * 8;
 	u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0);
+	unsigned int si;
 
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		u32 addr;
 		u32 len;
 
@@ -455,7 +456,7 @@ static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
 		adma_packet_start(qc);
 		return 0;
 
-	case ATA_PROT_ATAPI_DMA:
+	case ATAPI_PROT_DMA:
 		BUG();
 		break;
 
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index d015b4adcfe0..922d7b2efba8 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -333,13 +333,14 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
 	struct prde *prd_ptr_to_indirect_ext = NULL;
 	unsigned indirect_ext_segment_sz = 0;
 	dma_addr_t indirect_ext_segment_paddr;
+	unsigned int si;
 
 	VPRINTK("SATA FSL : cd = 0x%x, prd = 0x%x\n", cmd_desc, prd);
 
 	indirect_ext_segment_paddr = cmd_desc_paddr +
 	    SATA_FSL_CMD_DESC_OFFSET_TO_PRDT + SATA_FSL_MAX_PRD_DIRECT * 16;
 
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		dma_addr_t sg_addr = sg_dma_address(sg);
 		u32 sg_len = sg_dma_len(sg);
 
@@ -417,7 +418,7 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc)
 	}
 
 	/* setup "ACMD - atapi command" in cmd. desc. if this is ATAPI cmd */
-	if (is_atapi_taskfile(&qc->tf)) {
+	if (ata_is_atapi(qc->tf.protocol)) {
 		desc_info |= ATAPI_CMD;
 		memset((void *)&cd->acmd, 0, 32);
 		memcpy((void *)&cd->acmd, qc->cdb, qc->dev->cdb_len);
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 323c087e8cc1..96e614a1c169 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -585,7 +585,7 @@ static struct ata_port_operations inic_port_ops = {
 };
 
 static struct ata_port_info inic_port_info = {
-	/* For some reason, ATA_PROT_ATAPI is broken on this
+	/* For some reason, ATAPI_PROT_PIO is broken on this
 	 * controller, and no, PIO_POLLING does't fix it.  It somehow
 	 * manages to report the wrong ireason and ignoring ireason
 	 * results in machine lock up.  Tell libata to always prefer
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 37b850ae0845..7e72463a90eb 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -1136,9 +1136,10 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
 	struct mv_port_priv *pp = qc->ap->private_data;
 	struct scatterlist *sg;
 	struct mv_sg *mv_sg, *last_sg = NULL;
+	unsigned int si;
 
 	mv_sg = pp->sg_tbl;
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		dma_addr_t addr = sg_dma_address(sg);
 		u32 sg_len = sg_dma_len(sg);
 
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index ed5dc7cb50cd..a0f98fdab7a0 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1336,21 +1336,18 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc,
 static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
 {
 	struct nv_adma_port_priv *pp = qc->ap->private_data;
-	unsigned int idx;
 	struct nv_adma_prd *aprd;
 	struct scatterlist *sg;
+	unsigned int si;
 
 	VPRINTK("ENTER\n");
 
-	idx = 0;
-
-	ata_for_each_sg(sg, qc) {
-		aprd = (idx < 5) ? &cpb->aprd[idx] :
-			       &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)];
-		nv_adma_fill_aprd(qc, sg, idx, aprd);
-		idx++;
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
+		aprd = (si < 5) ? &cpb->aprd[si] :
+			       &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (si-5)];
+		nv_adma_fill_aprd(qc, sg, si, aprd);
 	}
-	if (idx > 5)
+	if (si > 5)
 		cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag)));
 	else
 		cpb->next_aprd = cpu_to_le64(0);
@@ -1995,17 +1992,14 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct scatterlist *sg;
-	unsigned int idx;
 	struct nv_swncq_port_priv *pp = ap->private_data;
 	struct ata_prd *prd;
-
-	WARN_ON(qc->__sg == NULL);
-	WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+	unsigned int si, idx;
 
 	prd = pp->prd + ATA_MAX_PRD * qc->tag;
 
 	idx = 0;
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		u32 addr, offset;
 		u32 sg_len, len;
 
@@ -2027,8 +2021,7 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
 		}
 	}
 
-	if (idx)
-		prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+	prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
 static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap,
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 7914def54fa3..a07d319f6e8c 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -450,19 +450,19 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
 	struct pdc_port_priv *pp = ap->private_data;
 	u8 *buf = pp->pkt;
 	u32 *buf32 = (u32 *) buf;
-	unsigned int dev_sel, feature, nbytes;
+	unsigned int dev_sel, feature;
 
 	/* set control bits (byte 0), zero delay seq id (byte 3),
 	 * and seq id (byte 2)
 	 */
 	switch (qc->tf.protocol) {
-	case ATA_PROT_ATAPI_DMA:
+	case ATAPI_PROT_DMA:
 		if (!(qc->tf.flags & ATA_TFLAG_WRITE))
 			buf32[0] = cpu_to_le32(PDC_PKT_READ);
 		else
 			buf32[0] = 0;
 		break;
-	case ATA_PROT_ATAPI_NODATA:
+	case ATAPI_PROT_NODATA:
 		buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
 		break;
 	default:
@@ -473,45 +473,37 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
 	buf32[2] = 0;				/* no next-packet */
 
 	/* select drive */
-	if (sata_scr_valid(&ap->link)) {
+	if (sata_scr_valid(&ap->link))
 		dev_sel = PDC_DEVICE_SATA;
-	} else {
-		dev_sel = ATA_DEVICE_OBS;
-		if (qc->dev->devno != 0)
-			dev_sel |= ATA_DEV1;
-	}
+	else
+		dev_sel = qc->tf.device;
+
 	buf[12] = (1 << 5) | ATA_REG_DEVICE;
 	buf[13] = dev_sel;
 	buf[14] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_CLEAR_BSY;
 	buf[15] = dev_sel; /* once more, waiting for BSY to clear */
 
 	buf[16] = (1 << 5) | ATA_REG_NSECT;
-	buf[17] = 0x00;
+	buf[17] = qc->tf.nsect;
 	buf[18] = (1 << 5) | ATA_REG_LBAL;
-	buf[19] = 0x00;
+	buf[19] = qc->tf.lbal;
 
 	/* set feature and byte counter registers */
-	if (qc->tf.protocol != ATA_PROT_ATAPI_DMA) {
+	if (qc->tf.protocol != ATAPI_PROT_DMA)
 		feature = PDC_FEATURE_ATAPI_PIO;
-		/* set byte counter register to real transfer byte count */
-		nbytes = qc->nbytes;
-		if (nbytes > 0xffff)
-			nbytes = 0xffff;
-	} else {
+	else
 		feature = PDC_FEATURE_ATAPI_DMA;
-		/* set byte counter register to 0 */
-		nbytes = 0;
-	}
+
 	buf[20] = (1 << 5) | ATA_REG_FEATURE;
 	buf[21] = feature;
 	buf[22] = (1 << 5) | ATA_REG_BYTEL;
-	buf[23] = nbytes & 0xFF;
+	buf[23] = qc->tf.lbam;
 	buf[24] = (1 << 5) | ATA_REG_BYTEH;
-	buf[25] = (nbytes >> 8) & 0xFF;
+	buf[25] = qc->tf.lbah;
 
 	/* send ATAPI packet command 0xA0 */
 	buf[26] = (1 << 5) | ATA_REG_CMD;
-	buf[27] = ATA_CMD_PACKET;
+	buf[27] = qc->tf.command;
 
 	/* select drive and check DRQ */
 	buf[28] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_WAIT_DRDY;
@@ -541,17 +533,15 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	struct scatterlist *sg;
-	unsigned int idx;
 	const u32 SG_COUNT_ASIC_BUG = 41*4;
+	unsigned int si, idx;
+	u32 len;
 
 	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
 		return;
 
-	WARN_ON(qc->__sg == NULL);
-	WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
-
 	idx = 0;
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		u32 addr, offset;
 		u32 sg_len, len;
 
@@ -578,29 +568,27 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc)
 		}
 	}
 
-	if (idx) {
-		u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len);
+	len = le32_to_cpu(ap->prd[idx - 1].flags_len);
 
-		if (len > SG_COUNT_ASIC_BUG) {
-			u32 addr;
+	if (len > SG_COUNT_ASIC_BUG) {
+		u32 addr;
 
-			VPRINTK("Splitting last PRD.\n");
+		VPRINTK("Splitting last PRD.\n");
 
-			addr = le32_to_cpu(ap->prd[idx - 1].addr);
-			ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);
-			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
+		addr = le32_to_cpu(ap->prd[idx - 1].addr);
+		ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);
+		VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
 
-			addr = addr + len - SG_COUNT_ASIC_BUG;
-			len = SG_COUNT_ASIC_BUG;
-			ap->prd[idx].addr = cpu_to_le32(addr);
-			ap->prd[idx].flags_len = cpu_to_le32(len);
-			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+		addr = addr + len - SG_COUNT_ASIC_BUG;
+		len = SG_COUNT_ASIC_BUG;
+		ap->prd[idx].addr = cpu_to_le32(addr);
+		ap->prd[idx].flags_len = cpu_to_le32(len);
+		VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
 
-			idx++;
-		}
-
-		ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+		idx++;
 	}
+
+	ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
 }
 
 static void pdc_qc_prep(struct ata_queued_cmd *qc)
@@ -627,14 +615,14 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
 		pdc_pkt_footer(&qc->tf, pp->pkt, i);
 		break;
 
-	case ATA_PROT_ATAPI:
+	case ATAPI_PROT_PIO:
 		pdc_fill_sg(qc);
 		break;
 
-	case ATA_PROT_ATAPI_DMA:
+	case ATAPI_PROT_DMA:
 		pdc_fill_sg(qc);
 		/*FALLTHROUGH*/
-	case ATA_PROT_ATAPI_NODATA:
+	case ATAPI_PROT_NODATA:
 		pdc_atapi_pkt(qc);
 		break;
 
@@ -754,8 +742,8 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap,
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
 	case ATA_PROT_NODATA:
-	case ATA_PROT_ATAPI_DMA:
-	case ATA_PROT_ATAPI_NODATA:
+	case ATAPI_PROT_DMA:
+	case ATAPI_PROT_NODATA:
 		qc->err_mask |= ac_err_mask(ata_wait_idle(ap));
 		ata_qc_complete(qc);
 		handled = 1;
@@ -900,7 +888,7 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc)
 static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
 {
 	switch (qc->tf.protocol) {
-	case ATA_PROT_ATAPI_NODATA:
+	case ATAPI_PROT_NODATA:
 		if (qc->dev->flags & ATA_DFLAG_CDB_INTR)
 			break;
 		/*FALLTHROUGH*/
@@ -908,7 +896,7 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
 		if (qc->tf.flags & ATA_TFLAG_POLLING)
 			break;
 		/*FALLTHROUGH*/
-	case ATA_PROT_ATAPI_DMA:
+	case ATAPI_PROT_DMA:
 	case ATA_PROT_DMA:
 		pdc_packet_start(qc);
 		return 0;
@@ -922,16 +910,14 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
 
 static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
 {
-	WARN_ON(tf->protocol == ATA_PROT_DMA ||
-		tf->protocol == ATA_PROT_ATAPI_DMA);
+	WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA);
 	ata_tf_load(ap, tf);
 }
 
 static void pdc_exec_command_mmio(struct ata_port *ap,
 				  const struct ata_taskfile *tf)
 {
-	WARN_ON(tf->protocol == ATA_PROT_DMA ||
-		tf->protocol == ATA_PROT_ATAPI_DMA);
+	WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA);
 	ata_exec_command(ap, tf);
 }
 
diff --git a/drivers/ata/sata_promise.h b/drivers/ata/sata_promise.h
index 6ee5e190262d..00d6000e546f 100644
--- a/drivers/ata/sata_promise.h
+++ b/drivers/ata/sata_promise.h
@@ -46,7 +46,7 @@ static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
 					  unsigned int devno, u8 *buf)
 {
 	u8 dev_reg;
-	u32 *buf32 = (u32 *) buf;
+	__le32 *buf32 = (__le32 *) buf;
 
 	/* set control bits (byte 0), zero delay seq id (byte 3),
 	 * and seq id (byte 2)
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index c68b241805fd..91cc12c82040 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -287,14 +287,10 @@ static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
 	struct scatterlist *sg;
 	struct ata_port *ap = qc->ap;
 	struct qs_port_priv *pp = ap->private_data;
-	unsigned int nelem;
 	u8 *prd = pp->pkt + QS_CPB_BYTES;
+	unsigned int si;
 
-	WARN_ON(qc->__sg == NULL);
-	WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
-
-	nelem = 0;
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		u64 addr;
 		u32 len;
 
@@ -306,12 +302,11 @@ static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
 		*(__le32 *)prd = cpu_to_le32(len);
 		prd += sizeof(u64);
 
-		VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem,
+		VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", si,
 					(unsigned long long)addr, len);
-		nelem++;
 	}
 
-	return nelem;
+	return si;
 }
 
 static void qs_qc_prep(struct ata_queued_cmd *qc)
@@ -376,7 +371,7 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
 		qs_packet_start(qc);
 		return 0;
 
-	case ATA_PROT_ATAPI_DMA:
+	case ATAPI_PROT_DMA:
 		BUG();
 		break;
 
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index f5119bf40c24..0b8191b52f97 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -416,15 +416,14 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
 		 */
 
 		/* Check the ATA_DFLAG_CDB_INTR flag is enough here.
-		 * The flag was turned on only for atapi devices.
-		 * No need to check is_atapi_taskfile(&qc->tf) again.
+		 * The flag was turned on only for atapi devices.  No
+		 * need to check ata_is_atapi(qc->tf.protocol) again.
 		 */
 		if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
 			goto err_hsm;
 		break;
 	case HSM_ST_LAST:
-		if (qc->tf.protocol == ATA_PROT_DMA ||
-		    qc->tf.protocol == ATA_PROT_ATAPI_DMA) {
+		if (ata_is_dma(qc->tf.protocol)) {
 			/* clear DMA-Start bit */
 			ap->ops->bmdma_stop(qc);
 
@@ -451,8 +450,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
 	/* kick HSM in the ass */
 	ata_hsm_move(ap, qc, status, 0);
 
-	if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
-				       qc->tf.protocol == ATA_PROT_ATAPI_DMA))
+	if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol))
 		ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2);
 
 	return;
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 864c1c1b8511..b4b1f91ea693 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -813,8 +813,9 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
 {
 	struct scatterlist *sg;
 	struct sil24_sge *last_sge = NULL;
+	unsigned int si;
 
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		sge->addr = cpu_to_le64(sg_dma_address(sg));
 		sge->cnt = cpu_to_le32(sg_dma_len(sg));
 		sge->flags = 0;
@@ -823,8 +824,7 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
 		sge++;
 	}
 
-	if (likely(last_sge))
-		last_sge->flags = cpu_to_le32(SGE_TRM);
+	last_sge->flags = cpu_to_le32(SGE_TRM);
 }
 
 static int sil24_qc_defer(struct ata_queued_cmd *qc)
@@ -852,9 +852,7 @@ static int sil24_qc_defer(struct ata_queued_cmd *qc)
 	 *   set.
 	 *
  	 */
-	int is_excl = (prot == ATA_PROT_ATAPI ||
-		       prot == ATA_PROT_ATAPI_NODATA ||
-		       prot == ATA_PROT_ATAPI_DMA ||
+	int is_excl = (ata_is_atapi(prot) ||
 		       (qc->flags & ATA_QCFLAG_RESULT_TF));
 
 	if (unlikely(ap->excl_link)) {
@@ -885,35 +883,21 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
 
 	cb = &pp->cmd_block[sil24_tag(qc->tag)];
 
-	switch (qc->tf.protocol) {
-	case ATA_PROT_PIO:
-	case ATA_PROT_DMA:
-	case ATA_PROT_NCQ:
-	case ATA_PROT_NODATA:
+	if (!ata_is_atapi(qc->tf.protocol)) {
 		prb = &cb->ata.prb;
 		sge = cb->ata.sge;
-		break;
-
-	case ATA_PROT_ATAPI:
-	case ATA_PROT_ATAPI_DMA:
-	case ATA_PROT_ATAPI_NODATA:
+	} else {
 		prb = &cb->atapi.prb;
 		sge = cb->atapi.sge;
 		memset(cb->atapi.cdb, 0, 32);
 		memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len);
 
-		if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
+		if (ata_is_data(qc->tf.protocol)) {
 			if (qc->tf.flags & ATA_TFLAG_WRITE)
 				ctrl = PRB_CTRL_PACKET_WRITE;
 			else
 				ctrl = PRB_CTRL_PACKET_READ;
 		}
-		break;
-
-	default:
-		prb = NULL;	/* shut up, gcc */
-		sge = NULL;
-		BUG();
 	}
 
 	prb->ctrl = cpu_to_le16(ctrl);
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 4d857185f33b..e3d56bc6726d 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -334,7 +334,7 @@ static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
 {
 	u32 addr;
 	unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
-	u32 *buf32 = (u32 *) buf;
+	__le32 *buf32 = (__le32 *) buf;
 
 	/* output ATA packet S/G table */
 	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
@@ -356,7 +356,7 @@ static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
 {
 	u32 addr;
 	unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
-	u32 *buf32 = (u32 *) buf;
+	__le32 *buf32 = (__le32 *) buf;
 
 	/* output Host DMA packet S/G table */
 	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
@@ -377,7 +377,7 @@ static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
 					    unsigned int portno)
 {
 	unsigned int i, dw;
-	u32 *buf32 = (u32 *) buf;
+	__le32 *buf32 = (__le32 *) buf;
 	u8 dev_reg;
 
 	unsigned int dimm_sg = PDC_20621_DIMM_BASE +
@@ -429,7 +429,8 @@ static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
 				     unsigned int portno)
 {
 	unsigned int dw;
-	u32 tmp, *buf32 = (u32 *) buf;
+	u32 tmp;
+	__le32 *buf32 = (__le32 *) buf;
 
 	unsigned int host_sg = PDC_20621_DIMM_BASE +
 			       (PDC_DIMM_WINDOW_STEP * portno) +
@@ -473,7 +474,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
 	void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR];
 	void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR];
 	unsigned int portno = ap->port_no;
-	unsigned int i, idx, total_len = 0, sgt_len;
+	unsigned int i, si, idx, total_len = 0, sgt_len;
 	u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
 
 	WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP));
@@ -487,7 +488,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
 	 * Build S/G table
 	 */
 	idx = 0;
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		buf[idx++] = cpu_to_le32(sg_dma_address(sg));
 		buf[idx++] = cpu_to_le32(sg_dma_len(sg));
 		total_len += sg_dma_len(sg);
@@ -700,7 +701,7 @@ static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
 		pdc20621_packet_start(qc);
 		return 0;
 
-	case ATA_PROT_ATAPI_DMA:
+	case ATAPI_PROT_DMA:
 		BUG();
 		break;
 
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index b34b3829f6a9..7b44a5965155 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -2163,7 +2163,6 @@ static int __devinit amb_init (amb_dev * dev)
 static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev) 
 {
       unsigned char pool;
-      memset (dev, 0, sizeof(amb_dev));
       
       // set up known dev items straight away
       dev->pci_dev = pci_dev; 
@@ -2253,7 +2252,7 @@ static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_
 		goto out_disable;
 	}
 
-	dev = kmalloc (sizeof(amb_dev), GFP_KERNEL);
+	dev = kzalloc(sizeof(amb_dev), GFP_KERNEL);
 	if (!dev) {
 		PRINTK (KERN_ERR, "out of memory!");
 		err = -ENOMEM;
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 3b64a99772ea..2e3395b7e8c1 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -1,5 +1,3 @@
-/* $Id: he.c,v 1.18 2003/05/06 22:57:15 chas Exp $ */
-
 /*
 
   he.c
@@ -99,10 +97,6 @@
 #define HPRINTK(fmt,args...)	do { } while (0)
 #endif /* HE_DEBUG */
 
-/* version definition */
-
-static char *version = "$Id: he.c,v 1.18 2003/05/06 22:57:15 chas Exp $";
-
 /* declarations */
 
 static int he_open(struct atm_vcc *vcc);
@@ -366,7 +360,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
 	struct he_dev *he_dev = NULL;
 	int err = 0;
 
-	printk(KERN_INFO "he: %s\n", version);
+	printk(KERN_INFO "ATM he driver\n");
 
 	if (pci_enable_device(pci_dev))
 		return -EIO;
@@ -1643,6 +1637,8 @@ he_stop(struct he_dev *he_dev)
 
 	if (he_dev->rbpl_base) {
 #ifdef USE_RBPL_POOL
+		int i;
+
 		for (i = 0; i < CONFIG_RBPL_SIZE; ++i) {
 			void *cpuaddr = he_dev->rbpl_virt[i].virt;
 			dma_addr_t dma_handle = he_dev->rbpl_base[i].phys;
@@ -1665,6 +1661,8 @@ he_stop(struct he_dev *he_dev)
 #ifdef USE_RBPS
 	if (he_dev->rbps_base) {
 #ifdef USE_RBPS_POOL
+		int i;
+
 		for (i = 0; i < CONFIG_RBPS_SIZE; ++i) {
 			void *cpuaddr = he_dev->rbps_virt[i].virt;
 			dma_addr_t dma_handle = he_dev->rbps_base[i].phys;
@@ -2933,7 +2931,7 @@ he_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
 
 	left = *pos;
 	if (!left--)
-		return sprintf(page, "%s\n", version);
+		return sprintf(page, "ATM he driver\n");
 
 	if (!left--)
 		return sprintf(page, "%s%s\n\n",
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index b39ea3f59c9b..63e09c015ca0 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -11,6 +11,9 @@ obj-$(CONFIG_FW_LOADER)	+= firmware_class.o
 obj-$(CONFIG_NUMA)	+= node.o
 obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
 obj-$(CONFIG_SMP)	+= topology.o
+ifeq ($(CONFIG_SYSFS),y)
+obj-$(CONFIG_MODULES)	+= module.o
+endif
 obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index 7370d7cf5988..3b43e8a9f87e 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -61,7 +61,7 @@ attribute_container_classdev_to_container(struct class_device *classdev)
 }
 EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container);
 
-static struct list_head attribute_container_list;
+static LIST_HEAD(attribute_container_list);
 
 static DEFINE_MUTEX(attribute_container_mutex);
 
@@ -320,9 +320,14 @@ attribute_container_add_attrs(struct class_device *classdev)
 	struct class_device_attribute **attrs =	cont->attrs;
 	int i, error;
 
-	if (!attrs)
+	BUG_ON(attrs && cont->grp);
+
+	if (!attrs && !cont->grp)
 		return 0;
 
+	if (cont->grp)
+		return sysfs_create_group(&classdev->kobj, cont->grp);
+
 	for (i = 0; attrs[i]; i++) {
 		error = class_device_create_file(classdev, attrs[i]);
 		if (error)
@@ -378,9 +383,14 @@ attribute_container_remove_attrs(struct class_device *classdev)
 	struct class_device_attribute **attrs =	cont->attrs;
 	int i;
 
-	if (!attrs)
+	if (!attrs && !cont->grp)
 		return;
 
+	if (cont->grp) {
+		sysfs_remove_group(&classdev->kobj, cont->grp);
+		return ;
+	}
+
 	for (i = 0; attrs[i]; i++)
 		class_device_remove_file(classdev, attrs[i]);
 }
@@ -429,10 +439,3 @@ attribute_container_find_class_device(struct attribute_container *cont,
 	return cdev;
 }
 EXPORT_SYMBOL_GPL(attribute_container_find_class_device);
-
-int __init
-attribute_container_init(void)
-{
-	INIT_LIST_HEAD(&attribute_container_list);
-	return 0;
-}
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 10b2fb6c9ce6..c0444146c09a 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -1,6 +1,42 @@
 
-/* initialisation functions */
+/**
+ * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
+ *
+ * @subsys - the struct kset that defines this bus.  This is the main kobject
+ * @drivers_kset - the list of drivers associated with this bus
+ * @devices_kset - the list of devices associated with this bus
+ * @klist_devices - the klist to iterate over the @devices_kset
+ * @klist_drivers - the klist to iterate over the @drivers_kset
+ * @bus_notifier - the bus notifier list for anything that cares about things
+ * on this bus.
+ * @bus - pointer back to the struct bus_type that this structure is associated
+ * with.
+ *
+ * This structure is the one that is the actual kobject allowing struct
+ * bus_type to be statically allocated safely.  Nothing outside of the driver
+ * core should ever touch these fields.
+ */
+struct bus_type_private {
+	struct kset subsys;
+	struct kset *drivers_kset;
+	struct kset *devices_kset;
+	struct klist klist_devices;
+	struct klist klist_drivers;
+	struct blocking_notifier_head bus_notifier;
+	unsigned int drivers_autoprobe:1;
+	struct bus_type *bus;
+};
+
+struct driver_private {
+	struct kobject kobj;
+	struct klist klist_devices;
+	struct klist_node knode_bus;
+	struct module_kobject *mkobj;
+	struct device_driver *driver;
+};
+#define to_driver(obj) container_of(obj, struct driver_private, kobj)
 
+/* initialisation functions */
 extern int devices_init(void);
 extern int buses_init(void);
 extern int classes_init(void);
@@ -13,17 +49,16 @@ static inline int hypervisor_init(void) { return 0; }
 extern int platform_bus_init(void);
 extern int system_bus_init(void);
 extern int cpu_dev_init(void);
-extern int attribute_container_init(void);
 
-extern int bus_add_device(struct device * dev);
-extern void bus_attach_device(struct device * dev);
-extern void bus_remove_device(struct device * dev);
+extern int bus_add_device(struct device *dev);
+extern void bus_attach_device(struct device *dev);
+extern void bus_remove_device(struct device *dev);
 
-extern int bus_add_driver(struct device_driver *);
-extern void bus_remove_driver(struct device_driver *);
+extern int bus_add_driver(struct device_driver *drv);
+extern void bus_remove_driver(struct device_driver *drv);
 
-extern void driver_detach(struct device_driver * drv);
-extern int driver_probe_device(struct device_driver *, struct device *);
+extern void driver_detach(struct device_driver *drv);
+extern int driver_probe_device(struct device_driver *drv, struct device *dev);
 
 extern void sysdev_shutdown(void);
 extern int sysdev_suspend(pm_message_t state);
@@ -44,4 +79,13 @@ extern char *make_class_name(const char *name, struct kobject *kobj);
 
 extern int devres_release_all(struct device *dev);
 
-extern struct kset devices_subsys;
+extern struct kset *devices_kset;
+
+#if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS)
+extern void module_add_driver(struct module *mod, struct device_driver *drv);
+extern void module_remove_driver(struct device_driver *drv);
+#else
+static inline void module_add_driver(struct module *mod,
+				     struct device_driver *drv) { }
+static inline void module_remove_driver(struct device_driver *drv) { }
+#endif
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 9a19b071c573..055989e94799 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007 Novell Inc.
  *
  * This file is released under the GPLv2
  *
@@ -17,14 +19,13 @@
 #include "power/power.h"
 
 #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
-#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj)
+#define to_bus(obj) container_of(obj, struct bus_type_private, subsys.kobj)
 
 /*
  * sysfs bindings for drivers
  */
 
 #define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr)
-#define to_driver(obj) container_of(obj, struct device_driver, kobj)
 
 
 static int __must_check bus_rescan_devices_helper(struct device *dev,
@@ -32,37 +33,40 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
 
 static struct bus_type *bus_get(struct bus_type *bus)
 {
-	return bus ? container_of(kset_get(&bus->subsys),
-				struct bus_type, subsys) : NULL;
+	if (bus) {
+		kset_get(&bus->p->subsys);
+		return bus;
+	}
+	return NULL;
 }
 
 static void bus_put(struct bus_type *bus)
 {
-	kset_put(&bus->subsys);
+	if (bus)
+		kset_put(&bus->p->subsys);
 }
 
-static ssize_t
-drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr,
+			     char *buf)
 {
-	struct driver_attribute * drv_attr = to_drv_attr(attr);
-	struct device_driver * drv = to_driver(kobj);
+	struct driver_attribute *drv_attr = to_drv_attr(attr);
+	struct driver_private *drv_priv = to_driver(kobj);
 	ssize_t ret = -EIO;
 
 	if (drv_attr->show)
-		ret = drv_attr->show(drv, buf);
+		ret = drv_attr->show(drv_priv->driver, buf);
 	return ret;
 }
 
-static ssize_t
-drv_attr_store(struct kobject * kobj, struct attribute * attr,
-	       const char * buf, size_t count)
+static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr,
+			      const char *buf, size_t count)
 {
-	struct driver_attribute * drv_attr = to_drv_attr(attr);
-	struct device_driver * drv = to_driver(kobj);
+	struct driver_attribute *drv_attr = to_drv_attr(attr);
+	struct driver_private *drv_priv = to_driver(kobj);
 	ssize_t ret = -EIO;
 
 	if (drv_attr->store)
-		ret = drv_attr->store(drv, buf, count);
+		ret = drv_attr->store(drv_priv->driver, buf, count);
 	return ret;
 }
 
@@ -71,22 +75,12 @@ static struct sysfs_ops driver_sysfs_ops = {
 	.store	= drv_attr_store,
 };
 
-
-static void driver_release(struct kobject * kobj)
+static void driver_release(struct kobject *kobj)
 {
-	/*
-	 * Yes this is an empty release function, it is this way because struct
-	 * device is always a static object, not a dynamic one.  Yes, this is
-	 * not nice and bad, but remember, drivers are code, reference counted
-	 * by the module count, not a device, which is really data.  And yes,
-	 * in the future I do want to have all drivers be created dynamically,
-	 * and am working toward that goal, but it will take a bit longer...
-	 *
-	 * But do not let this example give _anyone_ the idea that they can
-	 * create a release function without any code in it at all, to do that
-	 * is almost always wrong.  If you have any questions about this,
-	 * please send an email to <greg@kroah.com>
-	 */
+	struct driver_private *drv_priv = to_driver(kobj);
+
+	pr_debug("driver: '%s': %s\n", kobject_name(kobj), __FUNCTION__);
+	kfree(drv_priv);
 }
 
 static struct kobj_type driver_ktype = {
@@ -94,34 +88,30 @@ static struct kobj_type driver_ktype = {
 	.release	= driver_release,
 };
 
-
 /*
  * sysfs bindings for buses
  */
-
-
-static ssize_t
-bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,
+			     char *buf)
 {
-	struct bus_attribute * bus_attr = to_bus_attr(attr);
-	struct bus_type * bus = to_bus(kobj);
+	struct bus_attribute *bus_attr = to_bus_attr(attr);
+	struct bus_type_private *bus_priv = to_bus(kobj);
 	ssize_t ret = 0;
 
 	if (bus_attr->show)
-		ret = bus_attr->show(bus, buf);
+		ret = bus_attr->show(bus_priv->bus, buf);
 	return ret;
 }
 
-static ssize_t
-bus_attr_store(struct kobject * kobj, struct attribute * attr,
-	       const char * buf, size_t count)
+static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
+			      const char *buf, size_t count)
 {
-	struct bus_attribute * bus_attr = to_bus_attr(attr);
-	struct bus_type * bus = to_bus(kobj);
+	struct bus_attribute *bus_attr = to_bus_attr(attr);
+	struct bus_type_private *bus_priv = to_bus(kobj);
 	ssize_t ret = 0;
 
 	if (bus_attr->store)
-		ret = bus_attr->store(bus, buf, count);
+		ret = bus_attr->store(bus_priv->bus, buf, count);
 	return ret;
 }
 
@@ -130,24 +120,26 @@ static struct sysfs_ops bus_sysfs_ops = {
 	.store	= bus_attr_store,
 };
 
-int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
+int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
 {
 	int error;
 	if (bus_get(bus)) {
-		error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
+		error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
 		bus_put(bus);
 	} else
 		error = -EINVAL;
 	return error;
 }
+EXPORT_SYMBOL_GPL(bus_create_file);
 
-void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
+void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
 {
 	if (bus_get(bus)) {
-		sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
+		sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr);
 		bus_put(bus);
 	}
 }
+EXPORT_SYMBOL_GPL(bus_remove_file);
 
 static struct kobj_type bus_ktype = {
 	.sysfs_ops	= &bus_sysfs_ops,
@@ -166,20 +158,11 @@ static struct kset_uevent_ops bus_uevent_ops = {
 	.filter = bus_uevent_filter,
 };
 
-static decl_subsys(bus, &bus_ktype, &bus_uevent_ops);
+static struct kset *bus_kset;
 
 
 #ifdef CONFIG_HOTPLUG
 /* Manually detach a device from its associated driver. */
-static int driver_helper(struct device *dev, void *data)
-{
-	const char *name = data;
-
-	if (strcmp(name, dev->bus_id) == 0)
-		return 1;
-	return 0;
-}
-
 static ssize_t driver_unbind(struct device_driver *drv,
 			     const char *buf, size_t count)
 {
@@ -187,7 +170,7 @@ static ssize_t driver_unbind(struct device_driver *drv,
 	struct device *dev;
 	int err = -ENODEV;
 
-	dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+	dev = bus_find_device_by_name(bus, NULL, buf);
 	if (dev && dev->driver == drv) {
 		if (dev->parent)	/* Needed for USB */
 			down(&dev->parent->sem);
@@ -214,7 +197,7 @@ static ssize_t driver_bind(struct device_driver *drv,
 	struct device *dev;
 	int err = -ENODEV;
 
-	dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+	dev = bus_find_device_by_name(bus, NULL, buf);
 	if (dev && dev->driver == NULL) {
 		if (dev->parent)	/* Needed for USB */
 			down(&dev->parent->sem);
@@ -224,10 +207,13 @@ static ssize_t driver_bind(struct device_driver *drv,
 		if (dev->parent)
 			up(&dev->parent->sem);
 
-		if (err > 0) 		/* success */
+		if (err > 0) {
+			/* success */
 			err = count;
-		else if (err == 0)	/* driver didn't accept device */
+		} else if (err == 0) {
+			/* driver didn't accept device */
 			err = -ENODEV;
+		}
 	}
 	put_device(dev);
 	bus_put(bus);
@@ -237,16 +223,16 @@ static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
 
 static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
 {
-	return sprintf(buf, "%d\n", bus->drivers_autoprobe);
+	return sprintf(buf, "%d\n", bus->p->drivers_autoprobe);
 }
 
 static ssize_t store_drivers_autoprobe(struct bus_type *bus,
 				       const char *buf, size_t count)
 {
 	if (buf[0] == '0')
-		bus->drivers_autoprobe = 0;
+		bus->p->drivers_autoprobe = 0;
 	else
-		bus->drivers_autoprobe = 1;
+		bus->p->drivers_autoprobe = 1;
 	return count;
 }
 
@@ -255,7 +241,7 @@ static ssize_t store_drivers_probe(struct bus_type *bus,
 {
 	struct device *dev;
 
-	dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+	dev = bus_find_device_by_name(bus, NULL, buf);
 	if (!dev)
 		return -ENODEV;
 	if (bus_rescan_devices_helper(dev, NULL) != 0)
@@ -264,49 +250,49 @@ static ssize_t store_drivers_probe(struct bus_type *bus,
 }
 #endif
 
-static struct device * next_device(struct klist_iter * i)
+static struct device *next_device(struct klist_iter *i)
 {
-	struct klist_node * n = klist_next(i);
+	struct klist_node *n = klist_next(i);
 	return n ? container_of(n, struct device, knode_bus) : NULL;
 }
 
 /**
- *	bus_for_each_dev - device iterator.
- *	@bus:	bus type.
- *	@start:	device to start iterating from.
- *	@data:	data for the callback.
- *	@fn:	function to be called for each device.
+ * bus_for_each_dev - device iterator.
+ * @bus: bus type.
+ * @start: device to start iterating from.
+ * @data: data for the callback.
+ * @fn: function to be called for each device.
  *
- *	Iterate over @bus's list of devices, and call @fn for each,
- *	passing it @data. If @start is not NULL, we use that device to
- *	begin iterating from.
+ * Iterate over @bus's list of devices, and call @fn for each,
+ * passing it @data. If @start is not NULL, we use that device to
+ * begin iterating from.
  *
- *	We check the return of @fn each time. If it returns anything
- *	other than 0, we break out and return that value.
+ * We check the return of @fn each time. If it returns anything
+ * other than 0, we break out and return that value.
  *
- *	NOTE: The device that returns a non-zero value is not retained
- *	in any way, nor is its refcount incremented. If the caller needs
- *	to retain this data, it should do, and increment the reference
- *	count in the supplied callback.
+ * NOTE: The device that returns a non-zero value is not retained
+ * in any way, nor is its refcount incremented. If the caller needs
+ * to retain this data, it should do, and increment the reference
+ * count in the supplied callback.
  */
-
-int bus_for_each_dev(struct bus_type * bus, struct device * start,
-		     void * data, int (*fn)(struct device *, void *))
+int bus_for_each_dev(struct bus_type *bus, struct device *start,
+		     void *data, int (*fn)(struct device *, void *))
 {
 	struct klist_iter i;
-	struct device * dev;
+	struct device *dev;
 	int error = 0;
 
 	if (!bus)
 		return -EINVAL;
 
-	klist_iter_init_node(&bus->klist_devices, &i,
+	klist_iter_init_node(&bus->p->klist_devices, &i,
 			     (start ? &start->knode_bus : NULL));
 	while ((dev = next_device(&i)) && !error)
 		error = fn(dev, data);
 	klist_iter_exit(&i);
 	return error;
 }
+EXPORT_SYMBOL_GPL(bus_for_each_dev);
 
 /**
  * bus_find_device - device iterator for locating a particular device.
@@ -323,9 +309,9 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start,
  * if it does.  If the callback returns non-zero, this function will
  * return to the caller and not iterate over any more devices.
  */
-struct device * bus_find_device(struct bus_type *bus,
-				struct device *start, void *data,
-				int (*match)(struct device *, void *))
+struct device *bus_find_device(struct bus_type *bus,
+			       struct device *start, void *data,
+			       int (*match)(struct device *dev, void *data))
 {
 	struct klist_iter i;
 	struct device *dev;
@@ -333,7 +319,7 @@ struct device * bus_find_device(struct bus_type *bus,
 	if (!bus)
 		return NULL;
 
-	klist_iter_init_node(&bus->klist_devices, &i,
+	klist_iter_init_node(&bus->p->klist_devices, &i,
 			     (start ? &start->knode_bus : NULL));
 	while ((dev = next_device(&i)))
 		if (match(dev, data) && get_device(dev))
@@ -341,51 +327,83 @@ struct device * bus_find_device(struct bus_type *bus,
 	klist_iter_exit(&i);
 	return dev;
 }
+EXPORT_SYMBOL_GPL(bus_find_device);
+
+static int match_name(struct device *dev, void *data)
+{
+	const char *name = data;
 
+	if (strcmp(name, dev->bus_id) == 0)
+		return 1;
+	return 0;
+}
 
-static struct device_driver * next_driver(struct klist_iter * i)
+/**
+ * bus_find_device_by_name - device iterator for locating a particular device of a specific name
+ * @bus: bus type
+ * @start: Device to begin with
+ * @name: name of the device to match
+ *
+ * This is similar to the bus_find_device() function above, but it handles
+ * searching by a name automatically, no need to write another strcmp matching
+ * function.
+ */
+struct device *bus_find_device_by_name(struct bus_type *bus,
+				       struct device *start, const char *name)
 {
-	struct klist_node * n = klist_next(i);
-	return n ? container_of(n, struct device_driver, knode_bus) : NULL;
+	return bus_find_device(bus, start, (void *)name, match_name);
+}
+EXPORT_SYMBOL_GPL(bus_find_device_by_name);
+
+static struct device_driver *next_driver(struct klist_iter *i)
+{
+	struct klist_node *n = klist_next(i);
+	struct driver_private *drv_priv;
+
+	if (n) {
+		drv_priv = container_of(n, struct driver_private, knode_bus);
+		return drv_priv->driver;
+	}
+	return NULL;
 }
 
 /**
- *	bus_for_each_drv - driver iterator
- *	@bus:	bus we're dealing with.
- *	@start:	driver to start iterating on.
- *	@data:	data to pass to the callback.
- *	@fn:	function to call for each driver.
+ * bus_for_each_drv - driver iterator
+ * @bus: bus we're dealing with.
+ * @start: driver to start iterating on.
+ * @data: data to pass to the callback.
+ * @fn: function to call for each driver.
  *
- *	This is nearly identical to the device iterator above.
- *	We iterate over each driver that belongs to @bus, and call
- *	@fn for each. If @fn returns anything but 0, we break out
- *	and return it. If @start is not NULL, we use it as the head
- *	of the list.
+ * This is nearly identical to the device iterator above.
+ * We iterate over each driver that belongs to @bus, and call
+ * @fn for each. If @fn returns anything but 0, we break out
+ * and return it. If @start is not NULL, we use it as the head
+ * of the list.
  *
- *	NOTE: we don't return the driver that returns a non-zero
- *	value, nor do we leave the reference count incremented for that
- *	driver. If the caller needs to know that info, it must set it
- *	in the callback. It must also be sure to increment the refcount
- *	so it doesn't disappear before returning to the caller.
+ * NOTE: we don't return the driver that returns a non-zero
+ * value, nor do we leave the reference count incremented for that
+ * driver. If the caller needs to know that info, it must set it
+ * in the callback. It must also be sure to increment the refcount
+ * so it doesn't disappear before returning to the caller.
  */
-
-int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
-		     void * data, int (*fn)(struct device_driver *, void *))
+int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
+		     void *data, int (*fn)(struct device_driver *, void *))
 {
 	struct klist_iter i;
-	struct device_driver * drv;
+	struct device_driver *drv;
 	int error = 0;
 
 	if (!bus)
 		return -EINVAL;
 
-	klist_iter_init_node(&bus->klist_drivers, &i,
-			     start ? &start->knode_bus : NULL);
+	klist_iter_init_node(&bus->p->klist_drivers, &i,
+			     start ? &start->p->knode_bus : NULL);
 	while ((drv = next_driver(&i)) && !error)
 		error = fn(drv, data);
 	klist_iter_exit(&i);
 	return error;
 }
+EXPORT_SYMBOL_GPL(bus_for_each_drv);
 
 static int device_add_attrs(struct bus_type *bus, struct device *dev)
 {
@@ -396,7 +414,7 @@ static int device_add_attrs(struct bus_type *bus, struct device *dev)
 		return 0;
 
 	for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
-		error = device_create_file(dev,&bus->dev_attrs[i]);
+		error = device_create_file(dev, &bus->dev_attrs[i]);
 		if (error) {
 			while (--i >= 0)
 				device_remove_file(dev, &bus->dev_attrs[i]);
@@ -406,13 +424,13 @@ static int device_add_attrs(struct bus_type *bus, struct device *dev)
 	return error;
 }
 
-static void device_remove_attrs(struct bus_type * bus, struct device * dev)
+static void device_remove_attrs(struct bus_type *bus, struct device *dev)
 {
 	int i;
 
 	if (bus->dev_attrs) {
 		for (i = 0; attr_name(bus->dev_attrs[i]); i++)
-			device_remove_file(dev,&bus->dev_attrs[i]);
+			device_remove_file(dev, &bus->dev_attrs[i]);
 	}
 }
 
@@ -420,7 +438,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev)
 static int make_deprecated_bus_links(struct device *dev)
 {
 	return sysfs_create_link(&dev->kobj,
-				 &dev->bus->subsys.kobj, "bus");
+				 &dev->bus->p->subsys.kobj, "bus");
 }
 
 static void remove_deprecated_bus_links(struct device *dev)
@@ -433,28 +451,28 @@ static inline void remove_deprecated_bus_links(struct device *dev) { }
 #endif
 
 /**
- *	bus_add_device - add device to bus
- *	@dev:	device being added
+ * bus_add_device - add device to bus
+ * @dev: device being added
  *
- *	- Add the device to its bus's list of devices.
- *	- Create link to device's bus.
+ * - Add the device to its bus's list of devices.
+ * - Create link to device's bus.
  */
-int bus_add_device(struct device * dev)
+int bus_add_device(struct device *dev)
 {
-	struct bus_type * bus = bus_get(dev->bus);
+	struct bus_type *bus = bus_get(dev->bus);
 	int error = 0;
 
 	if (bus) {
-		pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
+		pr_debug("bus: '%s': add device %s\n", bus->name, dev->bus_id);
 		error = device_add_attrs(bus, dev);
 		if (error)
 			goto out_put;
-		error = sysfs_create_link(&bus->devices.kobj,
+		error = sysfs_create_link(&bus->p->devices_kset->kobj,
 						&dev->kobj, dev->bus_id);
 		if (error)
 			goto out_id;
 		error = sysfs_create_link(&dev->kobj,
-				&dev->bus->subsys.kobj, "subsystem");
+				&dev->bus->p->subsys.kobj, "subsystem");
 		if (error)
 			goto out_subsys;
 		error = make_deprecated_bus_links(dev);
@@ -466,7 +484,7 @@ int bus_add_device(struct device * dev)
 out_deprecated:
 	sysfs_remove_link(&dev->kobj, "subsystem");
 out_subsys:
-	sysfs_remove_link(&bus->devices.kobj, dev->bus_id);
+	sysfs_remove_link(&bus->p->devices_kset->kobj, dev->bus_id);
 out_id:
 	device_remove_attrs(bus, dev);
 out_put:
@@ -475,56 +493,58 @@ out_put:
 }
 
 /**
- *	bus_attach_device - add device to bus
- *	@dev:	device tried to attach to a driver
+ * bus_attach_device - add device to bus
+ * @dev: device tried to attach to a driver
  *
- *	- Add device to bus's list of devices.
- *	- Try to attach to driver.
+ * - Add device to bus's list of devices.
+ * - Try to attach to driver.
  */
-void bus_attach_device(struct device * dev)
+void bus_attach_device(struct device *dev)
 {
 	struct bus_type *bus = dev->bus;
 	int ret = 0;
 
 	if (bus) {
 		dev->is_registered = 1;
-		if (bus->drivers_autoprobe)
+		if (bus->p->drivers_autoprobe)
 			ret = device_attach(dev);
 		WARN_ON(ret < 0);
 		if (ret >= 0)
-			klist_add_tail(&dev->knode_bus, &bus->klist_devices);
+			klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
 		else
 			dev->is_registered = 0;
 	}
 }
 
 /**
- *	bus_remove_device - remove device from bus
- *	@dev:	device to be removed
+ * bus_remove_device - remove device from bus
+ * @dev: device to be removed
  *
- *	- Remove symlink from bus's directory.
- *	- Delete device from bus's list.
- *	- Detach from its driver.
- *	- Drop reference taken in bus_add_device().
+ * - Remove symlink from bus's directory.
+ * - Delete device from bus's list.
+ * - Detach from its driver.
+ * - Drop reference taken in bus_add_device().
  */
-void bus_remove_device(struct device * dev)
+void bus_remove_device(struct device *dev)
 {
 	if (dev->bus) {
 		sysfs_remove_link(&dev->kobj, "subsystem");
 		remove_deprecated_bus_links(dev);
-		sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
+		sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
+				  dev->bus_id);
 		device_remove_attrs(dev->bus, dev);
 		if (dev->is_registered) {
 			dev->is_registered = 0;
 			klist_del(&dev->knode_bus);
 		}
-		pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
+		pr_debug("bus: '%s': remove device %s\n",
+			 dev->bus->name, dev->bus_id);
 		device_release_driver(dev);
 		bus_put(dev->bus);
 	}
 }
 
-static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv)
+static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv)
 {
 	int error = 0;
 	int i;
@@ -533,19 +553,19 @@ static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv)
 		for (i = 0; attr_name(bus->drv_attrs[i]); i++) {
 			error = driver_create_file(drv, &bus->drv_attrs[i]);
 			if (error)
-				goto Err;
+				goto err;
 		}
 	}
- Done:
+done:
 	return error;
- Err:
+err:
 	while (--i >= 0)
 		driver_remove_file(drv, &bus->drv_attrs[i]);
-	goto Done;
+	goto done;
 }
 
-
-static void driver_remove_attrs(struct bus_type * bus, struct device_driver * drv)
+static void driver_remove_attrs(struct bus_type *bus,
+				struct device_driver *drv)
 {
 	int i;
 
@@ -616,39 +636,46 @@ static ssize_t driver_uevent_store(struct device_driver *drv,
 	enum kobject_action action;
 
 	if (kobject_action_type(buf, count, &action) == 0)
-		kobject_uevent(&drv->kobj, action);
+		kobject_uevent(&drv->p->kobj, action);
 	return count;
 }
 static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
 
 /**
- *	bus_add_driver - Add a driver to the bus.
- *	@drv:	driver.
- *
+ * bus_add_driver - Add a driver to the bus.
+ * @drv: driver.
  */
 int bus_add_driver(struct device_driver *drv)
 {
-	struct bus_type * bus = bus_get(drv->bus);
+	struct bus_type *bus;
+	struct driver_private *priv;
 	int error = 0;
 
+	bus = bus_get(drv->bus);
 	if (!bus)
 		return -EINVAL;
 
-	pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
-	error = kobject_set_name(&drv->kobj, "%s", drv->name);
-	if (error)
-		goto out_put_bus;
-	drv->kobj.kset = &bus->drivers;
-	error = kobject_register(&drv->kobj);
+	pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	klist_init(&priv->klist_devices, NULL, NULL);
+	priv->driver = drv;
+	drv->p = priv;
+	priv->kobj.kset = bus->p->drivers_kset;
+	error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
+				     "%s", drv->name);
 	if (error)
 		goto out_put_bus;
 
-	if (drv->bus->drivers_autoprobe) {
+	if (drv->bus->p->drivers_autoprobe) {
 		error = driver_attach(drv);
 		if (error)
 			goto out_unregister;
 	}
-	klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
+	klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
 	module_add_driver(drv->owner, drv);
 
 	error = driver_create_file(drv, &driver_attr_uevent);
@@ -669,24 +696,24 @@ int bus_add_driver(struct device_driver *drv)
 			__FUNCTION__, drv->name);
 	}
 
+	kobject_uevent(&priv->kobj, KOBJ_ADD);
 	return error;
 out_unregister:
-	kobject_unregister(&drv->kobj);
+	kobject_put(&priv->kobj);
 out_put_bus:
 	bus_put(bus);
 	return error;
 }
 
 /**
- *	bus_remove_driver - delete driver from bus's knowledge.
- *	@drv:	driver.
+ * bus_remove_driver - delete driver from bus's knowledge.
+ * @drv: driver.
  *
- *	Detach the driver from the devices it controls, and remove
- *	it from its bus's list of drivers. Finally, we drop the reference
- *	to the bus we took in bus_add_driver().
+ * Detach the driver from the devices it controls, and remove
+ * it from its bus's list of drivers. Finally, we drop the reference
+ * to the bus we took in bus_add_driver().
  */
-
-void bus_remove_driver(struct device_driver * drv)
+void bus_remove_driver(struct device_driver *drv)
 {
 	if (!drv->bus)
 		return;
@@ -694,18 +721,17 @@ void bus_remove_driver(struct device_driver * drv)
 	remove_bind_files(drv);
 	driver_remove_attrs(drv->bus, drv);
 	driver_remove_file(drv, &driver_attr_uevent);
-	klist_remove(&drv->knode_bus);
-	pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
+	klist_remove(&drv->p->knode_bus);
+	pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name);
 	driver_detach(drv);
 	module_remove_driver(drv);
-	kobject_unregister(&drv->kobj);
+	kobject_put(&drv->p->kobj);
 	bus_put(drv->bus);
 }
 
-
 /* Helper for bus_rescan_devices's iter */
 static int __must_check bus_rescan_devices_helper(struct device *dev,
-						void *data)
+						  void *data)
 {
 	int ret = 0;
 
@@ -727,10 +753,11 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
  * attached and rescan it against existing drivers to see if it matches
  * any by calling device_attach() for the unbound devices.
  */
-int bus_rescan_devices(struct bus_type * bus)
+int bus_rescan_devices(struct bus_type *bus)
 {
 	return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
 }
+EXPORT_SYMBOL_GPL(bus_rescan_devices);
 
 /**
  * device_reprobe - remove driver for a device and probe for a new driver
@@ -755,55 +782,55 @@ int device_reprobe(struct device *dev)
 EXPORT_SYMBOL_GPL(device_reprobe);
 
 /**
- *	find_bus - locate bus by name.
- *	@name:	name of bus.
+ * find_bus - locate bus by name.
+ * @name: name of bus.
  *
- *	Call kset_find_obj() to iterate over list of buses to
- *	find a bus by name. Return bus if found.
+ * Call kset_find_obj() to iterate over list of buses to
+ * find a bus by name. Return bus if found.
  *
- *	Note that kset_find_obj increments bus' reference count.
+ * Note that kset_find_obj increments bus' reference count.
  */
 #if 0
-struct bus_type * find_bus(char * name)
+struct bus_type *find_bus(char *name)
 {
-	struct kobject * k = kset_find_obj(&bus_subsys.kset, name);
+	struct kobject *k = kset_find_obj(bus_kset, name);
 	return k ? to_bus(k) : NULL;
 }
 #endif  /*  0  */
 
 
 /**
- *	bus_add_attrs - Add default attributes for this bus.
- *	@bus:	Bus that has just been registered.
+ * bus_add_attrs - Add default attributes for this bus.
+ * @bus: Bus that has just been registered.
  */
 
-static int bus_add_attrs(struct bus_type * bus)
+static int bus_add_attrs(struct bus_type *bus)
 {
 	int error = 0;
 	int i;
 
 	if (bus->bus_attrs) {
 		for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
-			error = bus_create_file(bus,&bus->bus_attrs[i]);
+			error = bus_create_file(bus, &bus->bus_attrs[i]);
 			if (error)
-				goto Err;
+				goto err;
 		}
 	}
- Done:
+done:
 	return error;
- Err:
+err:
 	while (--i >= 0)
-		bus_remove_file(bus,&bus->bus_attrs[i]);
-	goto Done;
+		bus_remove_file(bus, &bus->bus_attrs[i]);
+	goto done;
 }
 
-static void bus_remove_attrs(struct bus_type * bus)
+static void bus_remove_attrs(struct bus_type *bus)
 {
 	int i;
 
 	if (bus->bus_attrs) {
 		for (i = 0; attr_name(bus->bus_attrs[i]); i++)
-			bus_remove_file(bus,&bus->bus_attrs[i]);
+			bus_remove_file(bus, &bus->bus_attrs[i]);
 	}
 }
 
@@ -827,32 +854,42 @@ static ssize_t bus_uevent_store(struct bus_type *bus,
 	enum kobject_action action;
 
 	if (kobject_action_type(buf, count, &action) == 0)
-		kobject_uevent(&bus->subsys.kobj, action);
+		kobject_uevent(&bus->p->subsys.kobj, action);
 	return count;
 }
 static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
 
 /**
- *	bus_register - register a bus with the system.
- *	@bus:	bus.
+ * bus_register - register a bus with the system.
+ * @bus: bus.
  *
- *	Once we have that, we registered the bus with the kobject
- *	infrastructure, then register the children subsystems it has:
- *	the devices and drivers that belong to the bus.
+ * Once we have that, we registered the bus with the kobject
+ * infrastructure, then register the children subsystems it has:
+ * the devices and drivers that belong to the bus.
  */
-int bus_register(struct bus_type * bus)
+int bus_register(struct bus_type *bus)
 {
 	int retval;
+	struct bus_type_private *priv;
+
+	priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
 
-	BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
+	priv->bus = bus;
+	bus->p = priv;
 
-	retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name);
+	BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
+
+	retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
 	if (retval)
 		goto out;
 
-	bus->subsys.kobj.kset = &bus_subsys;
+	priv->subsys.kobj.kset = bus_kset;
+	priv->subsys.kobj.ktype = &bus_ktype;
+	priv->drivers_autoprobe = 1;
 
-	retval = subsystem_register(&bus->subsys);
+	retval = kset_register(&priv->subsys);
 	if (retval)
 		goto out;
 
@@ -860,23 +897,23 @@ int bus_register(struct bus_type * bus)
 	if (retval)
 		goto bus_uevent_fail;
 
-	kobject_set_name(&bus->devices.kobj, "devices");
-	bus->devices.kobj.parent = &bus->subsys.kobj;
-	retval = kset_register(&bus->devices);
-	if (retval)
+	priv->devices_kset = kset_create_and_add("devices", NULL,
+						 &priv->subsys.kobj);
+	if (!priv->devices_kset) {
+		retval = -ENOMEM;
 		goto bus_devices_fail;
+	}
 
-	kobject_set_name(&bus->drivers.kobj, "drivers");
-	bus->drivers.kobj.parent = &bus->subsys.kobj;
-	bus->drivers.ktype = &driver_ktype;
-	retval = kset_register(&bus->drivers);
-	if (retval)
+	priv->drivers_kset = kset_create_and_add("drivers", NULL,
+						 &priv->subsys.kobj);
+	if (!priv->drivers_kset) {
+		retval = -ENOMEM;
 		goto bus_drivers_fail;
+	}
 
-	klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
-	klist_init(&bus->klist_drivers, NULL, NULL);
+	klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
+	klist_init(&priv->klist_drivers, NULL, NULL);
 
-	bus->drivers_autoprobe = 1;
 	retval = add_probe_files(bus);
 	if (retval)
 		goto bus_probe_files_fail;
@@ -885,66 +922,73 @@ int bus_register(struct bus_type * bus)
 	if (retval)
 		goto bus_attrs_fail;
 
-	pr_debug("bus type '%s' registered\n", bus->name);
+	pr_debug("bus: '%s': registered\n", bus->name);
 	return 0;
 
 bus_attrs_fail:
 	remove_probe_files(bus);
 bus_probe_files_fail:
-	kset_unregister(&bus->drivers);
+	kset_unregister(bus->p->drivers_kset);
 bus_drivers_fail:
-	kset_unregister(&bus->devices);
+	kset_unregister(bus->p->devices_kset);
 bus_devices_fail:
 	bus_remove_file(bus, &bus_attr_uevent);
 bus_uevent_fail:
-	subsystem_unregister(&bus->subsys);
+	kset_unregister(&bus->p->subsys);
+	kfree(bus->p);
 out:
 	return retval;
 }
+EXPORT_SYMBOL_GPL(bus_register);
 
 /**
- *	bus_unregister - remove a bus from the system
- *	@bus:	bus.
+ * bus_unregister - remove a bus from the system
+ * @bus: bus.
  *
- *	Unregister the child subsystems and the bus itself.
- *	Finally, we call bus_put() to release the refcount
+ * Unregister the child subsystems and the bus itself.
+ * Finally, we call bus_put() to release the refcount
  */
-void bus_unregister(struct bus_type * bus)
+void bus_unregister(struct bus_type *bus)
 {
-	pr_debug("bus %s: unregistering\n", bus->name);
+	pr_debug("bus: '%s': unregistering\n", bus->name);
 	bus_remove_attrs(bus);
 	remove_probe_files(bus);
-	kset_unregister(&bus->drivers);
-	kset_unregister(&bus->devices);
+	kset_unregister(bus->p->drivers_kset);
+	kset_unregister(bus->p->devices_kset);
 	bus_remove_file(bus, &bus_attr_uevent);
-	subsystem_unregister(&bus->subsys);
+	kset_unregister(&bus->p->subsys);
+	kfree(bus->p);
 }
+EXPORT_SYMBOL_GPL(bus_unregister);
 
 int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
 {
-	return blocking_notifier_chain_register(&bus->bus_notifier, nb);
+	return blocking_notifier_chain_register(&bus->p->bus_notifier, nb);
 }
 EXPORT_SYMBOL_GPL(bus_register_notifier);
 
 int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb)
 {
-	return blocking_notifier_chain_unregister(&bus->bus_notifier, nb);
+	return blocking_notifier_chain_unregister(&bus->p->bus_notifier, nb);
 }
 EXPORT_SYMBOL_GPL(bus_unregister_notifier);
 
-int __init buses_init(void)
+struct kset *bus_get_kset(struct bus_type *bus)
 {
-	return subsystem_register(&bus_subsys);
+	return &bus->p->subsys;
 }
+EXPORT_SYMBOL_GPL(bus_get_kset);
 
+struct klist *bus_get_device_klist(struct bus_type *bus)
+{
+	return &bus->p->klist_devices;
+}
+EXPORT_SYMBOL_GPL(bus_get_device_klist);
 
-EXPORT_SYMBOL_GPL(bus_for_each_dev);
-EXPORT_SYMBOL_GPL(bus_find_device);
-EXPORT_SYMBOL_GPL(bus_for_each_drv);
-
-EXPORT_SYMBOL_GPL(bus_register);
-EXPORT_SYMBOL_GPL(bus_unregister);
-EXPORT_SYMBOL_GPL(bus_rescan_devices);
-
-EXPORT_SYMBOL_GPL(bus_create_file);
-EXPORT_SYMBOL_GPL(bus_remove_file);
+int __init buses_init(void)
+{
+	bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
+	if (!bus_kset)
+		return -ENOMEM;
+	return 0;
+}
diff --git a/drivers/base/class.c b/drivers/base/class.c
index a863bb091e11..9d915376c313 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -17,16 +17,17 @@
 #include <linux/kdev_t.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/genhd.h>
 #include "base.h"
 
 #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
 #define to_class(obj) container_of(obj, struct class, subsys.kobj)
 
-static ssize_t
-class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr,
+			       char *buf)
 {
-	struct class_attribute * class_attr = to_class_attr(attr);
-	struct class * dc = to_class(kobj);
+	struct class_attribute *class_attr = to_class_attr(attr);
+	struct class *dc = to_class(kobj);
 	ssize_t ret = -EIO;
 
 	if (class_attr->show)
@@ -34,12 +35,11 @@ class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 	return ret;
 }
 
-static ssize_t
-class_attr_store(struct kobject * kobj, struct attribute * attr,
-		 const char * buf, size_t count)
+static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,
+				const char *buf, size_t count)
 {
-	struct class_attribute * class_attr = to_class_attr(attr);
-	struct class * dc = to_class(kobj);
+	struct class_attribute *class_attr = to_class_attr(attr);
+	struct class *dc = to_class(kobj);
 	ssize_t ret = -EIO;
 
 	if (class_attr->store)
@@ -47,7 +47,7 @@ class_attr_store(struct kobject * kobj, struct attribute * attr,
 	return ret;
 }
 
-static void class_release(struct kobject * kobj)
+static void class_release(struct kobject *kobj)
 {
 	struct class *class = to_class(kobj);
 
@@ -71,20 +71,20 @@ static struct kobj_type class_ktype = {
 };
 
 /* Hotplug events for classes go to the class_obj subsys */
-static decl_subsys(class, &class_ktype, NULL);
+static struct kset *class_kset;
 
 
-int class_create_file(struct class * cls, const struct class_attribute * attr)
+int class_create_file(struct class *cls, const struct class_attribute *attr)
 {
 	int error;
-	if (cls) {
+	if (cls)
 		error = sysfs_create_file(&cls->subsys.kobj, &attr->attr);
-	} else
+	else
 		error = -EINVAL;
 	return error;
 }
 
-void class_remove_file(struct class * cls, const struct class_attribute * attr)
+void class_remove_file(struct class *cls, const struct class_attribute *attr)
 {
 	if (cls)
 		sysfs_remove_file(&cls->subsys.kobj, &attr->attr);
@@ -93,48 +93,48 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr)
 static struct class *class_get(struct class *cls)
 {
 	if (cls)
-		return container_of(kset_get(&cls->subsys), struct class, subsys);
+		return container_of(kset_get(&cls->subsys),
+				    struct class, subsys);
 	return NULL;
 }
 
-static void class_put(struct class * cls)
+static void class_put(struct class *cls)
 {
 	if (cls)
 		kset_put(&cls->subsys);
 }
 
-
-static int add_class_attrs(struct class * cls)
+static int add_class_attrs(struct class *cls)
 {
 	int i;
 	int error = 0;
 
 	if (cls->class_attrs) {
 		for (i = 0; attr_name(cls->class_attrs[i]); i++) {
-			error = class_create_file(cls,&cls->class_attrs[i]);
+			error = class_create_file(cls, &cls->class_attrs[i]);
 			if (error)
-				goto Err;
+				goto error;
 		}
 	}
- Done:
+done:
 	return error;
- Err:
+error:
 	while (--i >= 0)
-		class_remove_file(cls,&cls->class_attrs[i]);
-	goto Done;
+		class_remove_file(cls, &cls->class_attrs[i]);
+	goto done;
 }
 
-static void remove_class_attrs(struct class * cls)
+static void remove_class_attrs(struct class *cls)
 {
 	int i;
 
 	if (cls->class_attrs) {
 		for (i = 0; attr_name(cls->class_attrs[i]); i++)
-			class_remove_file(cls,&cls->class_attrs[i]);
+			class_remove_file(cls, &cls->class_attrs[i]);
 	}
 }
 
-int class_register(struct class * cls)
+int class_register(struct class *cls)
 {
 	int error;
 
@@ -149,9 +149,16 @@ int class_register(struct class * cls)
 	if (error)
 		return error;
 
-	cls->subsys.kobj.kset = &class_subsys;
+#if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK)
+	/* let the block class directory show up in the root of sysfs */
+	if (cls != &block_class)
+		cls->subsys.kobj.kset = class_kset;
+#else
+	cls->subsys.kobj.kset = class_kset;
+#endif
+	cls->subsys.kobj.ktype = &class_ktype;
 
-	error = subsystem_register(&cls->subsys);
+	error = kset_register(&cls->subsys);
 	if (!error) {
 		error = add_class_attrs(class_get(cls));
 		class_put(cls);
@@ -159,11 +166,11 @@ int class_register(struct class * cls)
 	return error;
 }
 
-void class_unregister(struct class * cls)
+void class_unregister(struct class *cls)
 {
 	pr_debug("device class '%s': unregistering\n", cls->name);
 	remove_class_attrs(cls);
-	subsystem_unregister(&cls->subsys);
+	kset_unregister(&cls->subsys);
 }
 
 static void class_create_release(struct class *cls)
@@ -241,8 +248,8 @@ void class_destroy(struct class *cls)
 
 /* Class Device Stuff */
 
-int class_device_create_file(struct class_device * class_dev,
-			     const struct class_device_attribute * attr)
+int class_device_create_file(struct class_device *class_dev,
+			     const struct class_device_attribute *attr)
 {
 	int error = -EINVAL;
 	if (class_dev)
@@ -250,8 +257,8 @@ int class_device_create_file(struct class_device * class_dev,
 	return error;
 }
 
-void class_device_remove_file(struct class_device * class_dev,
-			      const struct class_device_attribute * attr)
+void class_device_remove_file(struct class_device *class_dev,
+			      const struct class_device_attribute *attr)
 {
 	if (class_dev)
 		sysfs_remove_file(&class_dev->kobj, &attr->attr);
@@ -273,12 +280,11 @@ void class_device_remove_bin_file(struct class_device *class_dev,
 		sysfs_remove_bin_file(&class_dev->kobj, attr);
 }
 
-static ssize_t
-class_device_attr_show(struct kobject * kobj, struct attribute * attr,
-		       char * buf)
+static ssize_t class_device_attr_show(struct kobject *kobj,
+				      struct attribute *attr, char *buf)
 {
-	struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
-	struct class_device * cd = to_class_dev(kobj);
+	struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
+	struct class_device *cd = to_class_dev(kobj);
 	ssize_t ret = 0;
 
 	if (class_dev_attr->show)
@@ -286,12 +292,12 @@ class_device_attr_show(struct kobject * kobj, struct attribute * attr,
 	return ret;
 }
 
-static ssize_t
-class_device_attr_store(struct kobject * kobj, struct attribute * attr,
-			const char * buf, size_t count)
+static ssize_t class_device_attr_store(struct kobject *kobj,
+				       struct attribute *attr,
+				       const char *buf, size_t count)
 {
-	struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
-	struct class_device * cd = to_class_dev(kobj);
+	struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
+	struct class_device *cd = to_class_dev(kobj);
 	ssize_t ret = 0;
 
 	if (class_dev_attr->store)
@@ -304,10 +310,10 @@ static struct sysfs_ops class_dev_sysfs_ops = {
 	.store	= class_device_attr_store,
 };
 
-static void class_dev_release(struct kobject * kobj)
+static void class_dev_release(struct kobject *kobj)
 {
 	struct class_device *cd = to_class_dev(kobj);
-	struct class * cls = cd->class;
+	struct class *cls = cd->class;
 
 	pr_debug("device class '%s': release.\n", cd->class_id);
 
@@ -316,8 +322,8 @@ static void class_dev_release(struct kobject * kobj)
 	else if (cls->release)
 		cls->release(cd);
 	else {
-		printk(KERN_ERR "Class Device '%s' does not have a release() function, "
-			"it is broken and must be fixed.\n",
+		printk(KERN_ERR "Class Device '%s' does not have a release() "
+			"function, it is broken and must be fixed.\n",
 			cd->class_id);
 		WARN_ON(1);
 	}
@@ -428,7 +434,8 @@ static int class_uevent(struct kset *kset, struct kobject *kobj,
 			add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
 
 		if (dev->driver)
-			add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
+			add_uevent_var(env, "PHYSDEVDRIVER=%s",
+				       dev->driver->name);
 	}
 
 	if (class_dev->uevent) {
@@ -452,43 +459,49 @@ static struct kset_uevent_ops class_uevent_ops = {
 	.uevent =	class_uevent,
 };
 
-static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops);
-
+/*
+ * DO NOT copy how this is created, kset_create_and_add() should be
+ * called, but this is a hold-over from the old-way and will be deleted
+ * entirely soon.
+ */
+static struct kset class_obj_subsys = {
+	.uevent_ops = &class_uevent_ops,
+};
 
-static int class_device_add_attrs(struct class_device * cd)
+static int class_device_add_attrs(struct class_device *cd)
 {
 	int i;
 	int error = 0;
-	struct class * cls = cd->class;
+	struct class *cls = cd->class;
 
 	if (cls->class_dev_attrs) {
 		for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {
 			error = class_device_create_file(cd,
-							 &cls->class_dev_attrs[i]);
+						&cls->class_dev_attrs[i]);
 			if (error)
-				goto Err;
+				goto err;
 		}
 	}
- Done:
+done:
 	return error;
- Err:
+err:
 	while (--i >= 0)
-		class_device_remove_file(cd,&cls->class_dev_attrs[i]);
-	goto Done;
+		class_device_remove_file(cd, &cls->class_dev_attrs[i]);
+	goto done;
 }
 
-static void class_device_remove_attrs(struct class_device * cd)
+static void class_device_remove_attrs(struct class_device *cd)
 {
 	int i;
-	struct class * cls = cd->class;
+	struct class *cls = cd->class;
 
 	if (cls->class_dev_attrs) {
 		for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)
-			class_device_remove_file(cd,&cls->class_dev_attrs[i]);
+			class_device_remove_file(cd, &cls->class_dev_attrs[i]);
 	}
 }
 
-static int class_device_add_groups(struct class_device * cd)
+static int class_device_add_groups(struct class_device *cd)
 {
 	int i;
 	int error = 0;
@@ -498,7 +511,8 @@ static int class_device_add_groups(struct class_device * cd)
 			error = sysfs_create_group(&cd->kobj, cd->groups[i]);
 			if (error) {
 				while (--i >= 0)
-					sysfs_remove_group(&cd->kobj, cd->groups[i]);
+					sysfs_remove_group(&cd->kobj,
+							   cd->groups[i]);
 				goto out;
 			}
 		}
@@ -507,14 +521,12 @@ out:
 	return error;
 }
 
-static void class_device_remove_groups(struct class_device * cd)
+static void class_device_remove_groups(struct class_device *cd)
 {
 	int i;
-	if (cd->groups) {
-		for (i = 0; cd->groups[i]; i++) {
+	if (cd->groups)
+		for (i = 0; cd->groups[i]; i++)
 			sysfs_remove_group(&cd->kobj, cd->groups[i]);
-		}
-	}
 }
 
 static ssize_t show_dev(struct class_device *class_dev, char *buf)
@@ -537,8 +549,8 @@ static struct class_device_attribute class_uevent_attr =
 
 void class_device_initialize(struct class_device *class_dev)
 {
-	kobj_set_kset_s(class_dev, class_obj_subsys);
-	kobject_init(&class_dev->kobj);
+	class_dev->kobj.kset = &class_obj_subsys;
+	kobject_init(&class_dev->kobj, &class_device_ktype);
 	INIT_LIST_HEAD(&class_dev->node);
 }
 
@@ -566,16 +578,13 @@ int class_device_add(struct class_device *class_dev)
 		 class_dev->class_id);
 
 	/* first, register with generic layer. */
-	error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
-	if (error)
-		goto out2;
-
 	if (parent_class_dev)
 		class_dev->kobj.parent = &parent_class_dev->kobj;
 	else
 		class_dev->kobj.parent = &parent_class->subsys.kobj;
 
-	error = kobject_add(&class_dev->kobj);
+	error = kobject_add(&class_dev->kobj, class_dev->kobj.parent,
+			    "%s", class_dev->class_id);
 	if (error)
 		goto out2;
 
@@ -642,7 +651,7 @@ int class_device_add(struct class_device *class_dev)
  out3:
 	kobject_del(&class_dev->kobj);
  out2:
-	if(parent_class_dev)
+	if (parent_class_dev)
 		class_device_put(parent_class_dev);
 	class_put(parent_class);
  out1:
@@ -659,9 +668,11 @@ int class_device_register(struct class_device *class_dev)
 /**
  * class_device_create - creates a class device and registers it with sysfs
  * @cls: pointer to the struct class that this device should be registered to.
- * @parent: pointer to the parent struct class_device of this new device, if any.
+ * @parent: pointer to the parent struct class_device of this new device, if
+ * any.
  * @devt: the dev_t for the char device to be added.
- * @device: a pointer to a struct device that is assiociated with this class device.
+ * @device: a pointer to a struct device that is assiociated with this class
+ * device.
  * @fmt: string for the class device's name
  *
  * This function can be used by char device classes.  A struct
@@ -785,7 +796,7 @@ void class_device_destroy(struct class *cls, dev_t devt)
 		class_device_unregister(class_dev);
 }
 
-struct class_device * class_device_get(struct class_device *class_dev)
+struct class_device *class_device_get(struct class_device *class_dev)
 {
 	if (class_dev)
 		return to_class_dev(kobject_get(&class_dev->kobj));
@@ -798,6 +809,139 @@ void class_device_put(struct class_device *class_dev)
 		kobject_put(&class_dev->kobj);
 }
 
+/**
+ * class_for_each_device - device iterator
+ * @class: the class we're iterating
+ * @data: data for the callback
+ * @fn: function to be called for each device
+ *
+ * Iterate over @class's list of devices, and call @fn for each,
+ * passing it @data.
+ *
+ * We check the return of @fn each time. If it returns anything
+ * other than 0, we break out and return that value.
+ *
+ * Note, we hold class->sem in this function, so it can not be
+ * re-acquired in @fn, otherwise it will self-deadlocking. For
+ * example, calls to add or remove class members would be verboten.
+ */
+int class_for_each_device(struct class *class, void *data,
+			   int (*fn)(struct device *, void *))
+{
+	struct device *dev;
+	int error = 0;
+
+	if (!class)
+		return -EINVAL;
+	down(&class->sem);
+	list_for_each_entry(dev, &class->devices, node) {
+		dev = get_device(dev);
+		if (dev) {
+			error = fn(dev, data);
+			put_device(dev);
+		} else
+			error = -ENODEV;
+		if (error)
+			break;
+	}
+	up(&class->sem);
+
+	return error;
+}
+EXPORT_SYMBOL_GPL(class_for_each_device);
+
+/**
+ * class_find_device - device iterator for locating a particular device
+ * @class: the class we're iterating
+ * @data: data for the match function
+ * @match: function to check device
+ *
+ * This is similar to the class_for_each_dev() function above, but it
+ * returns a reference to a device that is 'found' for later use, as
+ * determined by the @match callback.
+ *
+ * The callback should return 0 if the device doesn't match and non-zero
+ * if it does.  If the callback returns non-zero, this function will
+ * return to the caller and not iterate over any more devices.
+ *
+ * Note, you will need to drop the reference with put_device() after use.
+ *
+ * We hold class->sem in this function, so it can not be
+ * re-acquired in @match, otherwise it will self-deadlocking. For
+ * example, calls to add or remove class members would be verboten.
+ */
+struct device *class_find_device(struct class *class, void *data,
+				   int (*match)(struct device *, void *))
+{
+	struct device *dev;
+	int found = 0;
+
+	if (!class)
+		return NULL;
+
+	down(&class->sem);
+	list_for_each_entry(dev, &class->devices, node) {
+		dev = get_device(dev);
+		if (dev) {
+			if (match(dev, data)) {
+				found = 1;
+				break;
+			} else
+				put_device(dev);
+		} else
+			break;
+	}
+	up(&class->sem);
+
+	return found ? dev : NULL;
+}
+EXPORT_SYMBOL_GPL(class_find_device);
+
+/**
+ * class_find_child - device iterator for locating a particular class_device
+ * @class: the class we're iterating
+ * @data: data for the match function
+ * @match: function to check class_device
+ *
+ * This function returns a reference to a class_device that is 'found' for
+ * later use, as determined by the @match callback.
+ *
+ * The callback should return 0 if the class_device doesn't match and non-zero
+ * if it does.  If the callback returns non-zero, this function will
+ * return to the caller and not iterate over any more class_devices.
+ *
+ * Note, you will need to drop the reference with class_device_put() after use.
+ *
+ * We hold class->sem in this function, so it can not be
+ * re-acquired in @match, otherwise it will self-deadlocking. For
+ * example, calls to add or remove class members would be verboten.
+ */
+struct class_device *class_find_child(struct class *class, void *data,
+				   int (*match)(struct class_device *, void *))
+{
+	struct class_device *dev;
+	int found = 0;
+
+	if (!class)
+		return NULL;
+
+	down(&class->sem);
+	list_for_each_entry(dev, &class->children, node) {
+		dev = class_device_get(dev);
+		if (dev) {
+			if (match(dev, data)) {
+				found = 1;
+				break;
+			} else
+				class_device_put(dev);
+		} else
+			break;
+	}
+	up(&class->sem);
+
+	return found ? dev : NULL;
+}
+EXPORT_SYMBOL_GPL(class_find_child);
 
 int class_interface_register(struct class_interface *class_intf)
 {
@@ -829,7 +973,7 @@ int class_interface_register(struct class_interface *class_intf)
 
 void class_interface_unregister(struct class_interface *class_intf)
 {
-	struct class * parent = class_intf->class;
+	struct class *parent = class_intf->class;
 	struct class_device *class_dev;
 	struct device *dev;
 
@@ -853,15 +997,14 @@ void class_interface_unregister(struct class_interface *class_intf)
 
 int __init classes_init(void)
 {
-	int retval;
-
-	retval = subsystem_register(&class_subsys);
-	if (retval)
-		return retval;
+	class_kset = kset_create_and_add("class", NULL, NULL);
+	if (!class_kset)
+		return -ENOMEM;
 
 	/* ick, this is ugly, the things we go through to keep from showing up
 	 * in sysfs... */
 	kset_init(&class_obj_subsys);
+	kobject_set_name(&class_obj_subsys.kobj, "class_obj");
 	if (!class_obj_subsys.kobj.parent)
 		class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
 	return 0;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2683eac30c68..b1727876182c 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -18,18 +18,26 @@
 #include <linux/string.h>
 #include <linux/kdev_t.h>
 #include <linux/notifier.h>
-
+#include <linux/genhd.h>
 #include <asm/semaphore.h>
 
 #include "base.h"
 #include "power/power.h"
 
-int (*platform_notify)(struct device * dev) = NULL;
-int (*platform_notify_remove)(struct device * dev) = NULL;
+int (*platform_notify)(struct device *dev) = NULL;
+int (*platform_notify_remove)(struct device *dev) = NULL;
 
-/*
- * sysfs bindings for devices.
- */
+#ifdef CONFIG_BLOCK
+static inline int device_is_not_partition(struct device *dev)
+{
+	return !(dev->type == &part_type);
+}
+#else
+static inline int device_is_not_partition(struct device *dev)
+{
+	return 1;
+}
+#endif
 
 /**
  * dev_driver_string - Return a device's driver name, if at all possible
@@ -51,11 +59,11 @@ EXPORT_SYMBOL(dev_driver_string);
 #define to_dev(obj) container_of(obj, struct device, kobj)
 #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
 
-static ssize_t
-dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
+			     char *buf)
 {
-	struct device_attribute * dev_attr = to_dev_attr(attr);
-	struct device * dev = to_dev(kobj);
+	struct device_attribute *dev_attr = to_dev_attr(attr);
+	struct device *dev = to_dev(kobj);
 	ssize_t ret = -EIO;
 
 	if (dev_attr->show)
@@ -63,12 +71,11 @@ dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 	return ret;
 }
 
-static ssize_t
-dev_attr_store(struct kobject * kobj, struct attribute * attr,
-	       const char * buf, size_t count)
+static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr,
+			      const char *buf, size_t count)
 {
-	struct device_attribute * dev_attr = to_dev_attr(attr);
-	struct device * dev = to_dev(kobj);
+	struct device_attribute *dev_attr = to_dev_attr(attr);
+	struct device *dev = to_dev(kobj);
 	ssize_t ret = -EIO;
 
 	if (dev_attr->store)
@@ -90,9 +97,9 @@ static struct sysfs_ops dev_sysfs_ops = {
  *	reaches 0. We forward the call to the device's release
  *	method, which should handle actually freeing the structure.
  */
-static void device_release(struct kobject * kobj)
+static void device_release(struct kobject *kobj)
 {
-	struct device * dev = to_dev(kobj);
+	struct device *dev = to_dev(kobj);
 
 	if (dev->release)
 		dev->release(dev);
@@ -101,8 +108,8 @@ static void device_release(struct kobject * kobj)
 	else if (dev->class && dev->class->dev_release)
 		dev->class->dev_release(dev);
 	else {
-		printk(KERN_ERR "Device '%s' does not have a release() function, "
-			"it is broken and must be fixed.\n",
+		printk(KERN_ERR "Device '%s' does not have a release() "
+			"function, it is broken and must be fixed.\n",
 			dev->bus_id);
 		WARN_ON(1);
 	}
@@ -185,7 +192,8 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
 		add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
 
 		if (dev->driver)
-			add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
+			add_uevent_var(env, "PHYSDEVDRIVER=%s",
+				       dev->driver->name);
 	}
 #endif
 
@@ -193,15 +201,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
 	if (dev->bus && dev->bus->uevent) {
 		retval = dev->bus->uevent(dev, env);
 		if (retval)
-			pr_debug ("%s: bus uevent() returned %d\n",
-				  __FUNCTION__, retval);
+			pr_debug("device: '%s': %s: bus uevent() returned %d\n",
+				 dev->bus_id, __FUNCTION__, retval);
 	}
 
 	/* have the class specific function add its stuff */
 	if (dev->class && dev->class->dev_uevent) {
 		retval = dev->class->dev_uevent(dev, env);
 		if (retval)
-			pr_debug("%s: class uevent() returned %d\n",
+			pr_debug("device: '%s': %s: class uevent() "
+				 "returned %d\n", dev->bus_id,
 				 __FUNCTION__, retval);
 	}
 
@@ -209,7 +218,8 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
 	if (dev->type && dev->type->uevent) {
 		retval = dev->type->uevent(dev, env);
 		if (retval)
-			pr_debug("%s: dev_type uevent() returned %d\n",
+			pr_debug("device: '%s': %s: dev_type uevent() "
+				 "returned %d\n", dev->bus_id,
 				 __FUNCTION__, retval);
 	}
 
@@ -325,7 +335,8 @@ static int device_add_groups(struct device *dev,
 			error = sysfs_create_group(&dev->kobj, groups[i]);
 			if (error) {
 				while (--i >= 0)
-					sysfs_remove_group(&dev->kobj, groups[i]);
+					sysfs_remove_group(&dev->kobj,
+							   groups[i]);
 				break;
 			}
 		}
@@ -401,20 +412,15 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
 static struct device_attribute devt_attr =
 	__ATTR(dev, S_IRUGO, show_dev, NULL);
 
-/*
- *	devices_subsys - structure to be registered with kobject core.
- */
-
-decl_subsys(devices, &device_ktype, &device_uevent_ops);
-
+/* kset to create /sys/devices/  */
+struct kset *devices_kset;
 
 /**
- *	device_create_file - create sysfs attribute file for device.
- *	@dev:	device.
- *	@attr:	device attribute descriptor.
+ * device_create_file - create sysfs attribute file for device.
+ * @dev: device.
+ * @attr: device attribute descriptor.
  */
-
-int device_create_file(struct device * dev, struct device_attribute * attr)
+int device_create_file(struct device *dev, struct device_attribute *attr)
 {
 	int error = 0;
 	if (get_device(dev)) {
@@ -425,12 +431,11 @@ int device_create_file(struct device * dev, struct device_attribute * attr)
 }
 
 /**
- *	device_remove_file - remove sysfs attribute file.
- *	@dev:	device.
- *	@attr:	device attribute descriptor.
+ * device_remove_file - remove sysfs attribute file.
+ * @dev: device.
+ * @attr: device attribute descriptor.
  */
-
-void device_remove_file(struct device * dev, struct device_attribute * attr)
+void device_remove_file(struct device *dev, struct device_attribute *attr)
 {
 	if (get_device(dev)) {
 		sysfs_remove_file(&dev->kobj, &attr->attr);
@@ -511,22 +516,20 @@ static void klist_children_put(struct klist_node *n)
 	put_device(dev);
 }
 
-
 /**
- *	device_initialize - init device structure.
- *	@dev:	device.
+ * device_initialize - init device structure.
+ * @dev: device.
  *
- *	This prepares the device for use by other layers,
- *	including adding it to the device hierarchy.
- *	It is the first half of device_register(), if called by
- *	that, though it can also be called separately, so one
- *	may use @dev's fields (e.g. the refcount).
+ * This prepares the device for use by other layers,
+ * including adding it to the device hierarchy.
+ * It is the first half of device_register(), if called by
+ * that, though it can also be called separately, so one
+ * may use @dev's fields (e.g. the refcount).
  */
-
 void device_initialize(struct device *dev)
 {
-	kobj_set_kset_s(dev, devices_subsys);
-	kobject_init(&dev->kobj);
+	dev->kobj.kset = devices_kset;
+	kobject_init(&dev->kobj, &device_ktype);
 	klist_init(&dev->klist_children, klist_children_get,
 		   klist_children_put);
 	INIT_LIST_HEAD(&dev->dma_pools);
@@ -539,36 +542,39 @@ void device_initialize(struct device *dev)
 }
 
 #ifdef CONFIG_SYSFS_DEPRECATED
-static struct kobject * get_device_parent(struct device *dev,
-					  struct device *parent)
+static struct kobject *get_device_parent(struct device *dev,
+					 struct device *parent)
 {
-	/*
-	 * Set the parent to the class, not the parent device
-	 * for topmost devices in class hierarchy.
-	 * This keeps sysfs from having a symlink to make old
-	 * udevs happy
-	 */
+	/* class devices without a parent live in /sys/class/<classname>/ */
 	if (dev->class && (!parent || parent->class != dev->class))
 		return &dev->class->subsys.kobj;
+	/* all other devices keep their parent */
 	else if (parent)
 		return &parent->kobj;
 
 	return NULL;
 }
+
+static inline void cleanup_device_parent(struct device *dev) {}
+static inline void cleanup_glue_dir(struct device *dev,
+				    struct kobject *glue_dir) {}
 #else
 static struct kobject *virtual_device_parent(struct device *dev)
 {
 	static struct kobject *virtual_dir = NULL;
 
 	if (!virtual_dir)
-		virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual");
+		virtual_dir = kobject_create_and_add("virtual",
+						     &devices_kset->kobj);
 
 	return virtual_dir;
 }
 
-static struct kobject * get_device_parent(struct device *dev,
-					  struct device *parent)
+static struct kobject *get_device_parent(struct device *dev,
+					 struct device *parent)
 {
+	int retval;
+
 	if (dev->class) {
 		struct kobject *kobj = NULL;
 		struct kobject *parent_kobj;
@@ -576,8 +582,8 @@ static struct kobject * get_device_parent(struct device *dev,
 
 		/*
 		 * If we have no parent, we live in "virtual".
-		 * Class-devices with a bus-device as parent, live
-		 * in a class-directory to prevent namespace collisions.
+		 * Class-devices with a non class-device as parent, live
+		 * in a "glue" directory to prevent namespace collisions.
 		 */
 		if (parent == NULL)
 			parent_kobj = virtual_device_parent(dev);
@@ -598,25 +604,45 @@ static struct kobject * get_device_parent(struct device *dev,
 			return kobj;
 
 		/* or create a new class-directory at the parent device */
-		return kobject_kset_add_dir(&dev->class->class_dirs,
-					    parent_kobj, dev->class->name);
+		k = kobject_create();
+		if (!k)
+			return NULL;
+		k->kset = &dev->class->class_dirs;
+		retval = kobject_add(k, parent_kobj, "%s", dev->class->name);
+		if (retval < 0) {
+			kobject_put(k);
+			return NULL;
+		}
+		/* do not emit an uevent for this simple "glue" directory */
+		return k;
 	}
 
 	if (parent)
 		return &parent->kobj;
 	return NULL;
 }
+
+static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir)
+{
+	/* see if we live in a "glue" directory */
+	if (!dev->class || glue_dir->kset != &dev->class->class_dirs)
+		return;
+
+	kobject_put(glue_dir);
+}
+
+static void cleanup_device_parent(struct device *dev)
+{
+	cleanup_glue_dir(dev, dev->kobj.parent);
+}
 #endif
 
-static int setup_parent(struct device *dev, struct device *parent)
+static void setup_parent(struct device *dev, struct device *parent)
 {
 	struct kobject *kobj;
 	kobj = get_device_parent(dev, parent);
-	if (IS_ERR(kobj))
-		return PTR_ERR(kobj);
 	if (kobj)
 		dev->kobj.parent = kobj;
-	return 0;
 }
 
 static int device_add_class_symlinks(struct device *dev)
@@ -625,65 +651,76 @@ static int device_add_class_symlinks(struct device *dev)
 
 	if (!dev->class)
 		return 0;
+
 	error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
 				  "subsystem");
 	if (error)
 		goto out;
-	/*
-	 * If this is not a "fake" compatible device, then create the
-	 * symlink from the class to the device.
-	 */
-	if (dev->kobj.parent != &dev->class->subsys.kobj) {
+
+#ifdef CONFIG_SYSFS_DEPRECATED
+	/* stacked class devices need a symlink in the class directory */
+	if (dev->kobj.parent != &dev->class->subsys.kobj &&
+	    device_is_not_partition(dev)) {
 		error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
 					  dev->bus_id);
 		if (error)
 			goto out_subsys;
 	}
-	if (dev->parent) {
-#ifdef CONFIG_SYSFS_DEPRECATED
-		{
-			struct device *parent = dev->parent;
-			char *class_name;
-
-			/*
-			 * In old sysfs stacked class devices had 'device'
-			 * link pointing to real device instead of parent
-			 */
-			while (parent->class && !parent->bus && parent->parent)
-				parent = parent->parent;
-
-			error = sysfs_create_link(&dev->kobj,
-						  &parent->kobj,
-						  "device");
-			if (error)
-				goto out_busid;
 
-			class_name = make_class_name(dev->class->name,
-							&dev->kobj);
-			if (class_name)
-				error = sysfs_create_link(&dev->parent->kobj,
-							&dev->kobj, class_name);
-			kfree(class_name);
-			if (error)
-				goto out_device;
-		}
-#else
-		error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+	if (dev->parent && device_is_not_partition(dev)) {
+		struct device *parent = dev->parent;
+		char *class_name;
+
+		/*
+		 * stacked class devices have the 'device' link
+		 * pointing to the bus device instead of the parent
+		 */
+		while (parent->class && !parent->bus && parent->parent)
+			parent = parent->parent;
+
+		error = sysfs_create_link(&dev->kobj,
+					  &parent->kobj,
 					  "device");
 		if (error)
 			goto out_busid;
-#endif
+
+		class_name = make_class_name(dev->class->name,
+						&dev->kobj);
+		if (class_name)
+			error = sysfs_create_link(&dev->parent->kobj,
+						&dev->kobj, class_name);
+		kfree(class_name);
+		if (error)
+			goto out_device;
 	}
 	return 0;
 
-#ifdef CONFIG_SYSFS_DEPRECATED
 out_device:
-	if (dev->parent)
+	if (dev->parent && device_is_not_partition(dev))
 		sysfs_remove_link(&dev->kobj, "device");
-#endif
 out_busid:
-	if (dev->kobj.parent != &dev->class->subsys.kobj)
+	if (dev->kobj.parent != &dev->class->subsys.kobj &&
+	    device_is_not_partition(dev))
 		sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#else
+	/* link in the class directory pointing to the device */
+	error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+				  dev->bus_id);
+	if (error)
+		goto out_subsys;
+
+	if (dev->parent && device_is_not_partition(dev)) {
+		error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+					  "device");
+		if (error)
+			goto out_busid;
+	}
+	return 0;
+
+out_busid:
+	sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#endif
+
 out_subsys:
 	sysfs_remove_link(&dev->kobj, "subsystem");
 out:
@@ -694,8 +731,9 @@ static void device_remove_class_symlinks(struct device *dev)
 {
 	if (!dev->class)
 		return;
-	if (dev->parent) {
+
 #ifdef CONFIG_SYSFS_DEPRECATED
+	if (dev->parent && device_is_not_partition(dev)) {
 		char *class_name;
 
 		class_name = make_class_name(dev->class->name, &dev->kobj);
@@ -703,45 +741,59 @@ static void device_remove_class_symlinks(struct device *dev)
 			sysfs_remove_link(&dev->parent->kobj, class_name);
 			kfree(class_name);
 		}
-#endif
 		sysfs_remove_link(&dev->kobj, "device");
 	}
-	if (dev->kobj.parent != &dev->class->subsys.kobj)
+
+	if (dev->kobj.parent != &dev->class->subsys.kobj &&
+	    device_is_not_partition(dev))
 		sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#else
+	if (dev->parent && device_is_not_partition(dev))
+		sysfs_remove_link(&dev->kobj, "device");
+
+	sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+#endif
+
 	sysfs_remove_link(&dev->kobj, "subsystem");
 }
 
 /**
- *	device_add - add device to device hierarchy.
- *	@dev:	device.
+ * device_add - add device to device hierarchy.
+ * @dev: device.
  *
- *	This is part 2 of device_register(), though may be called
- *	separately _iff_ device_initialize() has been called separately.
+ * This is part 2 of device_register(), though may be called
+ * separately _iff_ device_initialize() has been called separately.
  *
- *	This adds it to the kobject hierarchy via kobject_add(), adds it
- *	to the global and sibling lists for the device, then
- *	adds it to the other relevant subsystems of the driver model.
+ * This adds it to the kobject hierarchy via kobject_add(), adds it
+ * to the global and sibling lists for the device, then
+ * adds it to the other relevant subsystems of the driver model.
  */
 int device_add(struct device *dev)
 {
 	struct device *parent = NULL;
 	struct class_interface *class_intf;
-	int error = -EINVAL;
+	int error;
+
+	error = pm_sleep_lock();
+	if (error) {
+		dev_warn(dev, "Suspicious %s during suspend\n", __FUNCTION__);
+		dump_stack();
+		return error;
+	}
 
 	dev = get_device(dev);
-	if (!dev || !strlen(dev->bus_id))
+	if (!dev || !strlen(dev->bus_id)) {
+		error = -EINVAL;
 		goto Error;
+	}
 
-	pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
+	pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__);
 
 	parent = get_device(dev->parent);
-	error = setup_parent(dev, parent);
-	if (error)
-		goto Error;
+	setup_parent(dev, parent);
 
 	/* first, register with generic layer. */
-	kobject_set_name(&dev->kobj, "%s", dev->bus_id);
-	error = kobject_add(&dev->kobj);
+	error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
 	if (error)
 		goto Error;
 
@@ -751,7 +803,7 @@ int device_add(struct device *dev)
 
 	/* notify clients of device entry (new way) */
 	if (dev->bus)
-		blocking_notifier_call_chain(&dev->bus->bus_notifier,
+		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
 					     BUS_NOTIFY_ADD_DEVICE, dev);
 
 	error = device_create_file(dev, &uevent_attr);
@@ -795,13 +847,14 @@ int device_add(struct device *dev)
 	}
  Done:
 	put_device(dev);
+	pm_sleep_unlock();
 	return error;
  BusError:
 	device_pm_remove(dev);
 	dpm_sysfs_remove(dev);
  PMError:
 	if (dev->bus)
-		blocking_notifier_call_chain(&dev->bus->bus_notifier,
+		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
 					     BUS_NOTIFY_DEL_DEVICE, dev);
 	device_remove_attrs(dev);
  AttrsError:
@@ -809,124 +862,84 @@ int device_add(struct device *dev)
  SymlinkError:
 	if (MAJOR(dev->devt))
 		device_remove_file(dev, &devt_attr);
-
-	if (dev->class) {
-		sysfs_remove_link(&dev->kobj, "subsystem");
-		/* If this is not a "fake" compatible device, remove the
-		 * symlink from the class to the device. */
-		if (dev->kobj.parent != &dev->class->subsys.kobj)
-			sysfs_remove_link(&dev->class->subsys.kobj,
-					  dev->bus_id);
-		if (parent) {
-#ifdef CONFIG_SYSFS_DEPRECATED
-			char *class_name = make_class_name(dev->class->name,
-							   &dev->kobj);
-			if (class_name)
-				sysfs_remove_link(&dev->parent->kobj,
-						  class_name);
-			kfree(class_name);
-#endif
-			sysfs_remove_link(&dev->kobj, "device");
-		}
-	}
  ueventattrError:
 	device_remove_file(dev, &uevent_attr);
  attrError:
 	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
 	kobject_del(&dev->kobj);
  Error:
+	cleanup_device_parent(dev);
 	if (parent)
 		put_device(parent);
 	goto Done;
 }
 
-
 /**
- *	device_register - register a device with the system.
- *	@dev:	pointer to the device structure
+ * device_register - register a device with the system.
+ * @dev: pointer to the device structure
  *
- *	This happens in two clean steps - initialize the device
- *	and add it to the system. The two steps can be called
- *	separately, but this is the easiest and most common.
- *	I.e. you should only call the two helpers separately if
- *	have a clearly defined need to use and refcount the device
- *	before it is added to the hierarchy.
+ * This happens in two clean steps - initialize the device
+ * and add it to the system. The two steps can be called
+ * separately, but this is the easiest and most common.
+ * I.e. you should only call the two helpers separately if
+ * have a clearly defined need to use and refcount the device
+ * before it is added to the hierarchy.
  */
-
 int device_register(struct device *dev)
 {
 	device_initialize(dev);
 	return device_add(dev);
 }
 
-
 /**
- *	get_device - increment reference count for device.
- *	@dev:	device.
+ * get_device - increment reference count for device.
+ * @dev: device.
  *
- *	This simply forwards the call to kobject_get(), though
- *	we do take care to provide for the case that we get a NULL
- *	pointer passed in.
+ * This simply forwards the call to kobject_get(), though
+ * we do take care to provide for the case that we get a NULL
+ * pointer passed in.
  */
-
-struct device * get_device(struct device * dev)
+struct device *get_device(struct device *dev)
 {
 	return dev ? to_dev(kobject_get(&dev->kobj)) : NULL;
 }
 
-
 /**
- *	put_device - decrement reference count.
- *	@dev:	device in question.
+ * put_device - decrement reference count.
+ * @dev: device in question.
  */
-void put_device(struct device * dev)
+void put_device(struct device *dev)
 {
+	/* might_sleep(); */
 	if (dev)
 		kobject_put(&dev->kobj);
 }
 
-
 /**
- *	device_del - delete device from system.
- *	@dev:	device.
+ * device_del - delete device from system.
+ * @dev: device.
  *
- *	This is the first part of the device unregistration
- *	sequence. This removes the device from the lists we control
- *	from here, has it removed from the other driver model
- *	subsystems it was added to in device_add(), and removes it
- *	from the kobject hierarchy.
+ * This is the first part of the device unregistration
+ * sequence. This removes the device from the lists we control
+ * from here, has it removed from the other driver model
+ * subsystems it was added to in device_add(), and removes it
+ * from the kobject hierarchy.
  *
- *	NOTE: this should be called manually _iff_ device_add() was
- *	also called manually.
+ * NOTE: this should be called manually _iff_ device_add() was
+ * also called manually.
  */
-
-void device_del(struct device * dev)
+void device_del(struct device *dev)
 {
-	struct device * parent = dev->parent;
+	struct device *parent = dev->parent;
 	struct class_interface *class_intf;
 
+	device_pm_remove(dev);
 	if (parent)
 		klist_del(&dev->knode_parent);
 	if (MAJOR(dev->devt))
 		device_remove_file(dev, &devt_attr);
 	if (dev->class) {
-		sysfs_remove_link(&dev->kobj, "subsystem");
-		/* If this is not a "fake" compatible device, remove the
-		 * symlink from the class to the device. */
-		if (dev->kobj.parent != &dev->class->subsys.kobj)
-			sysfs_remove_link(&dev->class->subsys.kobj,
-					  dev->bus_id);
-		if (parent) {
-#ifdef CONFIG_SYSFS_DEPRECATED
-			char *class_name = make_class_name(dev->class->name,
-							   &dev->kobj);
-			if (class_name)
-				sysfs_remove_link(&dev->parent->kobj,
-						  class_name);
-			kfree(class_name);
-#endif
-			sysfs_remove_link(&dev->kobj, "device");
-		}
+		device_remove_class_symlinks(dev);
 
 		down(&dev->class->sem);
 		/* notify any interfaces that the device is now gone */
@@ -936,31 +949,6 @@ void device_del(struct device * dev)
 		/* remove the device from the class list */
 		list_del_init(&dev->node);
 		up(&dev->class->sem);
-
-		/* If we live in a parent class-directory, unreference it */
-		if (dev->kobj.parent->kset == &dev->class->class_dirs) {
-			struct device *d;
-			int other = 0;
-
-			/*
-			 * if we are the last child of our class, delete
-			 * our class-directory at this parent
-			 */
-			down(&dev->class->sem);
-			list_for_each_entry(d, &dev->class->devices, node) {
-				if (d == dev)
-					continue;
-				if (d->kobj.parent == dev->kobj.parent) {
-					other = 1;
-					break;
-				}
-			}
-			if (!other)
-				kobject_del(dev->kobj.parent);
-
-			kobject_put(dev->kobj.parent);
-			up(&dev->class->sem);
-		}
 	}
 	device_remove_file(dev, &uevent_attr);
 	device_remove_attrs(dev);
@@ -979,57 +967,55 @@ void device_del(struct device * dev)
 	if (platform_notify_remove)
 		platform_notify_remove(dev);
 	if (dev->bus)
-		blocking_notifier_call_chain(&dev->bus->bus_notifier,
+		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
 					     BUS_NOTIFY_DEL_DEVICE, dev);
-	device_pm_remove(dev);
 	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
+	cleanup_device_parent(dev);
 	kobject_del(&dev->kobj);
-	if (parent)
-		put_device(parent);
+	put_device(parent);
 }
 
 /**
- *	device_unregister - unregister device from system.
- *	@dev:	device going away.
+ * device_unregister - unregister device from system.
+ * @dev: device going away.
  *
- *	We do this in two parts, like we do device_register(). First,
- *	we remove it from all the subsystems with device_del(), then
- *	we decrement the reference count via put_device(). If that
- *	is the final reference count, the device will be cleaned up
- *	via device_release() above. Otherwise, the structure will
- *	stick around until the final reference to the device is dropped.
+ * We do this in two parts, like we do device_register(). First,
+ * we remove it from all the subsystems with device_del(), then
+ * we decrement the reference count via put_device(). If that
+ * is the final reference count, the device will be cleaned up
+ * via device_release() above. Otherwise, the structure will
+ * stick around until the final reference to the device is dropped.
  */
-void device_unregister(struct device * dev)
+void device_unregister(struct device *dev)
 {
-	pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id);
+	pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__);
 	device_del(dev);
 	put_device(dev);
 }
 
-
-static struct device * next_device(struct klist_iter * i)
+static struct device *next_device(struct klist_iter *i)
 {
-	struct klist_node * n = klist_next(i);
+	struct klist_node *n = klist_next(i);
 	return n ? container_of(n, struct device, knode_parent) : NULL;
 }
 
 /**
- *	device_for_each_child - device child iterator.
- *	@parent: parent struct device.
- *	@data:	data for the callback.
- *	@fn:	function to be called for each device.
+ * device_for_each_child - device child iterator.
+ * @parent: parent struct device.
+ * @data: data for the callback.
+ * @fn: function to be called for each device.
  *
- *	Iterate over @parent's child devices, and call @fn for each,
- *	passing it @data.
+ * Iterate over @parent's child devices, and call @fn for each,
+ * passing it @data.
  *
- *	We check the return of @fn each time. If it returns anything
- *	other than 0, we break out and return that value.
+ * We check the return of @fn each time. If it returns anything
+ * other than 0, we break out and return that value.
  */
-int device_for_each_child(struct device * parent, void * data,
-		     int (*fn)(struct device *, void *))
+int device_for_each_child(struct device *parent, void *data,
+			  int (*fn)(struct device *dev, void *data))
 {
 	struct klist_iter i;
-	struct device * child;
+	struct device *child;
 	int error = 0;
 
 	klist_iter_init(&parent->klist_children, &i);
@@ -1054,8 +1040,8 @@ int device_for_each_child(struct device * parent, void * data,
  * current device can be obtained, this function will return to the caller
  * and not iterate over any more devices.
  */
-struct device * device_find_child(struct device *parent, void *data,
-				  int (*match)(struct device *, void *))
+struct device *device_find_child(struct device *parent, void *data,
+				 int (*match)(struct device *dev, void *data))
 {
 	struct klist_iter i;
 	struct device *child;
@@ -1073,7 +1059,10 @@ struct device * device_find_child(struct device *parent, void *data,
 
 int __init devices_init(void)
 {
-	return subsystem_register(&devices_subsys);
+	devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
+	if (!devices_kset)
+		return -ENOMEM;
+	return 0;
 }
 
 EXPORT_SYMBOL_GPL(device_for_each_child);
@@ -1094,7 +1083,7 @@ EXPORT_SYMBOL_GPL(device_remove_file);
 
 static void device_create_release(struct device *dev)
 {
-	pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id);
+	pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__);
 	kfree(dev);
 }
 
@@ -1156,14 +1145,11 @@ error:
 EXPORT_SYMBOL_GPL(device_create);
 
 /**
- * device_destroy - removes a device that was created with device_create()
+ * find_device - finds a device that was created with device_create()
  * @class: pointer to the struct class that this device was registered with
  * @devt: the dev_t of the device that was previously registered
- *
- * This call unregisters and cleans up a device that was created with a
- * call to device_create().
  */
-void device_destroy(struct class *class, dev_t devt)
+static struct device *find_device(struct class *class, dev_t devt)
 {
 	struct device *dev = NULL;
 	struct device *dev_tmp;
@@ -1176,12 +1162,54 @@ void device_destroy(struct class *class, dev_t devt)
 		}
 	}
 	up(&class->sem);
+	return dev;
+}
 
+/**
+ * device_destroy - removes a device that was created with device_create()
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
+ *
+ * This call unregisters and cleans up a device that was created with a
+ * call to device_create().
+ */
+void device_destroy(struct class *class, dev_t devt)
+{
+	struct device *dev;
+
+	dev = find_device(class, devt);
 	if (dev)
 		device_unregister(dev);
 }
 EXPORT_SYMBOL_GPL(device_destroy);
 
+#ifdef CONFIG_PM_SLEEP
+/**
+ * destroy_suspended_device - asks the PM core to remove a suspended device
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
+ *
+ * This call notifies the PM core of the necessity to unregister a suspended
+ * device created with a call to device_create() (devices cannot be
+ * unregistered directly while suspended, since the PM core holds their
+ * semaphores at that time).
+ *
+ * It can only be called within the scope of a system sleep transition.  In
+ * practice this means it has to be directly or indirectly invoked either by
+ * a suspend or resume method, or by the PM core (e.g. via
+ * disable_nonboot_cpus() or enable_nonboot_cpus()).
+ */
+void destroy_suspended_device(struct class *class, dev_t devt)
+{
+	struct device *dev;
+
+	dev = find_device(class, devt);
+	if (dev)
+		device_pm_schedule_removal(dev);
+}
+EXPORT_SYMBOL_GPL(destroy_suspended_device);
+#endif /* CONFIG_PM_SLEEP */
+
 /**
  * device_rename - renames a device
  * @dev: the pointer to the struct device to be renamed
@@ -1198,7 +1226,8 @@ int device_rename(struct device *dev, char *new_name)
 	if (!dev)
 		return -EINVAL;
 
-	pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name);
+	pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id,
+		 __FUNCTION__, new_name);
 
 #ifdef CONFIG_SYSFS_DEPRECATED
 	if ((dev->class) && (dev->parent))
@@ -1279,8 +1308,7 @@ static int device_move_class_links(struct device *dev,
 					  class_name);
 		if (error)
 			sysfs_remove_link(&dev->kobj, "device");
-	}
-	else
+	} else
 		error = 0;
 out:
 	kfree(class_name);
@@ -1311,16 +1339,13 @@ int device_move(struct device *dev, struct device *new_parent)
 		return -EINVAL;
 
 	new_parent = get_device(new_parent);
-	new_parent_kobj = get_device_parent (dev, new_parent);
-	if (IS_ERR(new_parent_kobj)) {
-		error = PTR_ERR(new_parent_kobj);
-		put_device(new_parent);
-		goto out;
-	}
-	pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
-		 new_parent ? new_parent->bus_id : "<NULL>");
+	new_parent_kobj = get_device_parent(dev, new_parent);
+
+	pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id,
+		 __FUNCTION__, new_parent ? new_parent->bus_id : "<NULL>");
 	error = kobject_move(&dev->kobj, new_parent_kobj);
 	if (error) {
+		cleanup_glue_dir(dev, new_parent_kobj);
 		put_device(new_parent);
 		goto out;
 	}
@@ -1343,6 +1368,7 @@ int device_move(struct device *dev, struct device *new_parent)
 				klist_add_tail(&dev->knode_parent,
 					       &old_parent->klist_children);
 		}
+		cleanup_glue_dir(dev, new_parent_kobj);
 		put_device(new_parent);
 		goto out;
 	}
@@ -1352,5 +1378,23 @@ out:
 	put_device(dev);
 	return error;
 }
-
 EXPORT_SYMBOL_GPL(device_move);
+
+/**
+ * device_shutdown - call ->shutdown() on each device to shutdown.
+ */
+void device_shutdown(void)
+{
+	struct device *dev, *devn;
+
+	list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list,
+				kobj.entry) {
+		if (dev->bus && dev->bus->shutdown) {
+			dev_dbg(dev, "shutdown\n");
+			dev->bus->shutdown(dev);
+		} else if (dev->driver && dev->driver->shutdown) {
+			dev_dbg(dev, "shutdown\n");
+			dev->driver->shutdown(dev);
+		}
+	}
+}
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 40545071e3c9..c5885f5ce0ac 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -14,7 +14,7 @@
 #include "base.h"
 
 struct sysdev_class cpu_sysdev_class = {
-	set_kset_name("cpu"),
+	.name = "cpu",
 };
 EXPORT_SYMBOL(cpu_sysdev_class);
 
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 7ac474db88c5..a5cde94bb982 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -1,18 +1,20 @@
 /*
- *	drivers/base/dd.c - The core device/driver interactions.
+ * drivers/base/dd.c - The core device/driver interactions.
  *
- * 	This file contains the (sometimes tricky) code that controls the
- *	interactions between devices and drivers, which primarily includes
- *	driver binding and unbinding.
+ * This file contains the (sometimes tricky) code that controls the
+ * interactions between devices and drivers, which primarily includes
+ * driver binding and unbinding.
  *
- *	All of this code used to exist in drivers/base/bus.c, but was
- *	relocated to here in the name of compartmentalization (since it wasn't
- *	strictly code just for the 'struct bus_type'.
+ * All of this code used to exist in drivers/base/bus.c, but was
+ * relocated to here in the name of compartmentalization (since it wasn't
+ * strictly code just for the 'struct bus_type'.
  *
- *	Copyright (c) 2002-5 Patrick Mochel
- *	Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2002-5 Patrick Mochel
+ * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007 Novell Inc.
  *
- *	This file is released under the GPLv2
+ * This file is released under the GPLv2
  */
 
 #include <linux/device.h>
@@ -23,8 +25,6 @@
 #include "base.h"
 #include "power/power.h"
 
-#define to_drv(node) container_of(node, struct device_driver, kobj.entry)
-
 
 static void driver_bound(struct device *dev)
 {
@@ -34,27 +34,27 @@ static void driver_bound(struct device *dev)
 		return;
 	}
 
-	pr_debug("bound device '%s' to driver '%s'\n",
-		 dev->bus_id, dev->driver->name);
+	pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->bus_id,
+		 __FUNCTION__, dev->driver->name);
 
 	if (dev->bus)
-		blocking_notifier_call_chain(&dev->bus->bus_notifier,
+		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
 					     BUS_NOTIFY_BOUND_DRIVER, dev);
 
-	klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
+	klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices);
 }
 
 static int driver_sysfs_add(struct device *dev)
 {
 	int ret;
 
-	ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj,
+	ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
 			  kobject_name(&dev->kobj));
 	if (ret == 0) {
-		ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj,
+		ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
 					"driver");
 		if (ret)
-			sysfs_remove_link(&dev->driver->kobj,
+			sysfs_remove_link(&dev->driver->p->kobj,
 					kobject_name(&dev->kobj));
 	}
 	return ret;
@@ -65,24 +65,24 @@ static void driver_sysfs_remove(struct device *dev)
 	struct device_driver *drv = dev->driver;
 
 	if (drv) {
-		sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
+		sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj));
 		sysfs_remove_link(&dev->kobj, "driver");
 	}
 }
 
 /**
- *	device_bind_driver - bind a driver to one device.
- *	@dev:	device.
+ * device_bind_driver - bind a driver to one device.
+ * @dev: device.
  *
- *	Allow manual attachment of a driver to a device.
- *	Caller must have already set @dev->driver.
+ * Allow manual attachment of a driver to a device.
+ * Caller must have already set @dev->driver.
  *
- *	Note that this does not modify the bus reference count
- *	nor take the bus's rwsem. Please verify those are accounted
- *	for before calling this. (It is ok to call with no other effort
- *	from a driver's probe() method.)
+ * Note that this does not modify the bus reference count
+ * nor take the bus's rwsem. Please verify those are accounted
+ * for before calling this. (It is ok to call with no other effort
+ * from a driver's probe() method.)
  *
- *	This function must be called with @dev->sem held.
+ * This function must be called with @dev->sem held.
  */
 int device_bind_driver(struct device *dev)
 {
@@ -93,6 +93,7 @@ int device_bind_driver(struct device *dev)
 		driver_bound(dev);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(device_bind_driver);
 
 static atomic_t probe_count = ATOMIC_INIT(0);
 static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
@@ -102,8 +103,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
 	int ret = 0;
 
 	atomic_inc(&probe_count);
-	pr_debug("%s: Probing driver %s with device %s\n",
-		 drv->bus->name, drv->name, dev->bus_id);
+	pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
+		 drv->bus->name, __FUNCTION__, drv->name, dev->bus_id);
 	WARN_ON(!list_empty(&dev->devres_head));
 
 	dev->driver = drv;
@@ -125,8 +126,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
 
 	driver_bound(dev);
 	ret = 1;
-	pr_debug("%s: Bound Device %s to Driver %s\n",
-		 drv->bus->name, dev->bus_id, drv->name);
+	pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
+		 drv->bus->name, __FUNCTION__, dev->bus_id, drv->name);
 	goto done;
 
 probe_failed:
@@ -183,7 +184,7 @@ int driver_probe_done(void)
  * This function must be called with @dev->sem held.  When called for a
  * USB interface, @dev->parent->sem must be held as well.
  */
-int driver_probe_device(struct device_driver * drv, struct device * dev)
+int driver_probe_device(struct device_driver *drv, struct device *dev)
 {
 	int ret = 0;
 
@@ -192,8 +193,8 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
 	if (drv->bus->match && !drv->bus->match(dev, drv))
 		goto done;
 
-	pr_debug("%s: Matched Device %s with Driver %s\n",
-		 drv->bus->name, dev->bus_id, drv->name);
+	pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
+		 drv->bus->name, __FUNCTION__, dev->bus_id, drv->name);
 
 	ret = really_probe(dev, drv);
 
@@ -201,27 +202,27 @@ done:
 	return ret;
 }
 
-static int __device_attach(struct device_driver * drv, void * data)
+static int __device_attach(struct device_driver *drv, void *data)
 {
-	struct device * dev = data;
+	struct device *dev = data;
 	return driver_probe_device(drv, dev);
 }
 
 /**
- *	device_attach - try to attach device to a driver.
- *	@dev:	device.
+ * device_attach - try to attach device to a driver.
+ * @dev: device.
  *
- *	Walk the list of drivers that the bus has and call
- *	driver_probe_device() for each pair. If a compatible
- *	pair is found, break out and return.
+ * Walk the list of drivers that the bus has and call
+ * driver_probe_device() for each pair. If a compatible
+ * pair is found, break out and return.
  *
- *	Returns 1 if the device was bound to a driver;
- *	0 if no matching device was found;
- *	-ENODEV if the device is not registered.
+ * Returns 1 if the device was bound to a driver;
+ * 0 if no matching device was found;
+ * -ENODEV if the device is not registered.
  *
- *	When called for a USB interface, @dev->parent->sem must be held.
+ * When called for a USB interface, @dev->parent->sem must be held.
  */
-int device_attach(struct device * dev)
+int device_attach(struct device *dev)
 {
 	int ret = 0;
 
@@ -240,10 +241,11 @@ int device_attach(struct device * dev)
 	up(&dev->sem);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(device_attach);
 
-static int __driver_attach(struct device * dev, void * data)
+static int __driver_attach(struct device *dev, void *data)
 {
-	struct device_driver * drv = data;
+	struct device_driver *drv = data;
 
 	/*
 	 * Lock device and try to bind to it. We drop the error
@@ -268,35 +270,35 @@ static int __driver_attach(struct device * dev, void * data)
 }
 
 /**
- *	driver_attach - try to bind driver to devices.
- *	@drv:	driver.
+ * driver_attach - try to bind driver to devices.
+ * @drv: driver.
  *
- *	Walk the list of devices that the bus has on it and try to
- *	match the driver with each one.  If driver_probe_device()
- *	returns 0 and the @dev->driver is set, we've found a
- *	compatible pair.
+ * Walk the list of devices that the bus has on it and try to
+ * match the driver with each one.  If driver_probe_device()
+ * returns 0 and the @dev->driver is set, we've found a
+ * compatible pair.
  */
-int driver_attach(struct device_driver * drv)
+int driver_attach(struct device_driver *drv)
 {
 	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
 }
+EXPORT_SYMBOL_GPL(driver_attach);
 
 /*
- *	__device_release_driver() must be called with @dev->sem held.
- *	When called for a USB interface, @dev->parent->sem must be held as well.
+ * __device_release_driver() must be called with @dev->sem held.
+ * When called for a USB interface, @dev->parent->sem must be held as well.
  */
-static void __device_release_driver(struct device * dev)
+static void __device_release_driver(struct device *dev)
 {
-	struct device_driver * drv;
+	struct device_driver *drv;
 
-	drv = get_driver(dev->driver);
+	drv = dev->driver;
 	if (drv) {
 		driver_sysfs_remove(dev);
 		sysfs_remove_link(&dev->kobj, "driver");
-		klist_remove(&dev->knode_driver);
 
 		if (dev->bus)
-			blocking_notifier_call_chain(&dev->bus->bus_notifier,
+			blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
 						     BUS_NOTIFY_UNBIND_DRIVER,
 						     dev);
 
@@ -306,18 +308,18 @@ static void __device_release_driver(struct device * dev)
 			drv->remove(dev);
 		devres_release_all(dev);
 		dev->driver = NULL;
-		put_driver(drv);
+		klist_remove(&dev->knode_driver);
 	}
 }
 
 /**
- *	device_release_driver - manually detach device from driver.
- *	@dev:	device.
+ * device_release_driver - manually detach device from driver.
+ * @dev: device.
  *
- *	Manually detach device from driver.
- *	When called for a USB interface, @dev->parent->sem must be held.
+ * Manually detach device from driver.
+ * When called for a USB interface, @dev->parent->sem must be held.
  */
-void device_release_driver(struct device * dev)
+void device_release_driver(struct device *dev)
 {
 	/*
 	 * If anyone calls device_release_driver() recursively from
@@ -328,26 +330,26 @@ void device_release_driver(struct device * dev)
 	__device_release_driver(dev);
 	up(&dev->sem);
 }
-
+EXPORT_SYMBOL_GPL(device_release_driver);
 
 /**
  * driver_detach - detach driver from all devices it controls.
  * @drv: driver.
  */
-void driver_detach(struct device_driver * drv)
+void driver_detach(struct device_driver *drv)
 {
-	struct device * dev;
+	struct device *dev;
 
 	for (;;) {
-		spin_lock(&drv->klist_devices.k_lock);
-		if (list_empty(&drv->klist_devices.k_list)) {
-			spin_unlock(&drv->klist_devices.k_lock);
+		spin_lock(&drv->p->klist_devices.k_lock);
+		if (list_empty(&drv->p->klist_devices.k_list)) {
+			spin_unlock(&drv->p->klist_devices.k_lock);
 			break;
 		}
-		dev = list_entry(drv->klist_devices.k_list.prev,
+		dev = list_entry(drv->p->klist_devices.k_list.prev,
 				struct device, knode_driver.n_node);
 		get_device(dev);
-		spin_unlock(&drv->klist_devices.k_lock);
+		spin_unlock(&drv->p->klist_devices.k_lock);
 
 		if (dev->parent)	/* Needed for USB */
 			down(&dev->parent->sem);
@@ -360,9 +362,3 @@ void driver_detach(struct device_driver * drv)
 		put_device(dev);
 	}
 }
-
-EXPORT_SYMBOL_GPL(device_bind_driver);
-EXPORT_SYMBOL_GPL(device_release_driver);
-EXPORT_SYMBOL_GPL(device_attach);
-EXPORT_SYMBOL_GPL(driver_attach);
-
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index eb11475293ed..a35f04121a00 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007 Novell Inc.
  *
  * This file is released under the GPLv2
  *
@@ -15,46 +17,42 @@
 #include "base.h"
 
 #define to_dev(node) container_of(node, struct device, driver_list)
-#define to_drv(obj) container_of(obj, struct device_driver, kobj)
 
 
-static struct device * next_device(struct klist_iter * i)
+static struct device *next_device(struct klist_iter *i)
 {
-	struct klist_node * n = klist_next(i);
+	struct klist_node *n = klist_next(i);
 	return n ? container_of(n, struct device, knode_driver) : NULL;
 }
 
 /**
- *	driver_for_each_device - Iterator for devices bound to a driver.
- *	@drv:	Driver we're iterating.
- *	@start: Device to begin with
- *	@data:	Data to pass to the callback.
- *	@fn:	Function to call for each device.
+ * driver_for_each_device - Iterator for devices bound to a driver.
+ * @drv: Driver we're iterating.
+ * @start: Device to begin with
+ * @data: Data to pass to the callback.
+ * @fn: Function to call for each device.
  *
- *	Iterate over the @drv's list of devices calling @fn for each one.
+ * Iterate over the @drv's list of devices calling @fn for each one.
  */
-
-int driver_for_each_device(struct device_driver * drv, struct device * start, 
-			   void * data, int (*fn)(struct device *, void *))
+int driver_for_each_device(struct device_driver *drv, struct device *start,
+			   void *data, int (*fn)(struct device *, void *))
 {
 	struct klist_iter i;
-	struct device * dev;
+	struct device *dev;
 	int error = 0;
 
 	if (!drv)
 		return -EINVAL;
 
-	klist_iter_init_node(&drv->klist_devices, &i,
+	klist_iter_init_node(&drv->p->klist_devices, &i,
 			     start ? &start->knode_driver : NULL);
 	while ((dev = next_device(&i)) && !error)
 		error = fn(dev, data);
 	klist_iter_exit(&i);
 	return error;
 }
-
 EXPORT_SYMBOL_GPL(driver_for_each_device);
 
-
 /**
  * driver_find_device - device iterator for locating a particular device.
  * @drv: The device's driver
@@ -70,9 +68,9 @@ EXPORT_SYMBOL_GPL(driver_for_each_device);
  * if it does.  If the callback returns non-zero, this function will
  * return to the caller and not iterate over any more devices.
  */
-struct device * driver_find_device(struct device_driver *drv,
-				   struct device * start, void * data,
-				   int (*match)(struct device *, void *))
+struct device *driver_find_device(struct device_driver *drv,
+				  struct device *start, void *data,
+				  int (*match)(struct device *dev, void *data))
 {
 	struct klist_iter i;
 	struct device *dev;
@@ -80,7 +78,7 @@ struct device * driver_find_device(struct device_driver *drv,
 	if (!drv)
 		return NULL;
 
-	klist_iter_init_node(&drv->klist_devices, &i,
+	klist_iter_init_node(&drv->p->klist_devices, &i,
 			     (start ? &start->knode_driver : NULL));
 	while ((dev = next_device(&i)))
 		if (match(dev, data) && get_device(dev))
@@ -91,111 +89,179 @@ struct device * driver_find_device(struct device_driver *drv,
 EXPORT_SYMBOL_GPL(driver_find_device);
 
 /**
- *	driver_create_file - create sysfs file for driver.
- *	@drv:	driver.
- *	@attr:	driver attribute descriptor.
+ * driver_create_file - create sysfs file for driver.
+ * @drv: driver.
+ * @attr: driver attribute descriptor.
  */
-
-int driver_create_file(struct device_driver * drv, struct driver_attribute * attr)
+int driver_create_file(struct device_driver *drv,
+		       struct driver_attribute *attr)
 {
 	int error;
 	if (get_driver(drv)) {
-		error = sysfs_create_file(&drv->kobj, &attr->attr);
+		error = sysfs_create_file(&drv->p->kobj, &attr->attr);
 		put_driver(drv);
 	} else
 		error = -EINVAL;
 	return error;
 }
-
+EXPORT_SYMBOL_GPL(driver_create_file);
 
 /**
- *	driver_remove_file - remove sysfs file for driver.
- *	@drv:	driver.
- *	@attr:	driver attribute descriptor.
+ * driver_remove_file - remove sysfs file for driver.
+ * @drv: driver.
+ * @attr: driver attribute descriptor.
  */
-
-void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr)
+void driver_remove_file(struct device_driver *drv,
+			struct driver_attribute *attr)
 {
 	if (get_driver(drv)) {
-		sysfs_remove_file(&drv->kobj, &attr->attr);
+		sysfs_remove_file(&drv->p->kobj, &attr->attr);
 		put_driver(drv);
 	}
 }
-
+EXPORT_SYMBOL_GPL(driver_remove_file);
 
 /**
- *	get_driver - increment driver reference count.
- *	@drv:	driver.
+ * driver_add_kobj - add a kobject below the specified driver
+ *
+ * You really don't want to do this, this is only here due to one looney
+ * iseries driver, go poke those developers if you are annoyed about
+ * this...
  */
-struct device_driver * get_driver(struct device_driver * drv)
+int driver_add_kobj(struct device_driver *drv, struct kobject *kobj,
+		    const char *fmt, ...)
 {
-	return drv ? to_drv(kobject_get(&drv->kobj)) : NULL;
+	va_list args;
+	char *name;
+
+	va_start(args, fmt);
+	name = kvasprintf(GFP_KERNEL, fmt, args);
+	va_end(args);
+
+	if (!name)
+		return -ENOMEM;
+
+	return kobject_add(kobj, &drv->p->kobj, "%s", name);
 }
+EXPORT_SYMBOL_GPL(driver_add_kobj);
+
+/**
+ * get_driver - increment driver reference count.
+ * @drv: driver.
+ */
+struct device_driver *get_driver(struct device_driver *drv)
+{
+	if (drv) {
+		struct driver_private *priv;
+		struct kobject *kobj;
 
+		kobj = kobject_get(&drv->p->kobj);
+		priv = to_driver(kobj);
+		return priv->driver;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(get_driver);
 
 /**
- *	put_driver - decrement driver's refcount.
- *	@drv:	driver.
+ * put_driver - decrement driver's refcount.
+ * @drv: driver.
  */
-void put_driver(struct device_driver * drv)
+void put_driver(struct device_driver *drv)
+{
+	kobject_put(&drv->p->kobj);
+}
+EXPORT_SYMBOL_GPL(put_driver);
+
+static int driver_add_groups(struct device_driver *drv,
+			     struct attribute_group **groups)
 {
-	kobject_put(&drv->kobj);
+	int error = 0;
+	int i;
+
+	if (groups) {
+		for (i = 0; groups[i]; i++) {
+			error = sysfs_create_group(&drv->p->kobj, groups[i]);
+			if (error) {
+				while (--i >= 0)
+					sysfs_remove_group(&drv->p->kobj,
+							   groups[i]);
+				break;
+			}
+		}
+	}
+	return error;
+}
+
+static void driver_remove_groups(struct device_driver *drv,
+				 struct attribute_group **groups)
+{
+	int i;
+
+	if (groups)
+		for (i = 0; groups[i]; i++)
+			sysfs_remove_group(&drv->p->kobj, groups[i]);
 }
 
 /**
- *	driver_register - register driver with bus
- *	@drv:	driver to register
+ * driver_register - register driver with bus
+ * @drv: driver to register
  *
- *	We pass off most of the work to the bus_add_driver() call,
- *	since most of the things we have to do deal with the bus
- *	structures.
+ * We pass off most of the work to the bus_add_driver() call,
+ * since most of the things we have to do deal with the bus
+ * structures.
  */
-int driver_register(struct device_driver * drv)
+int driver_register(struct device_driver *drv)
 {
+	int ret;
+
 	if ((drv->bus->probe && drv->probe) ||
 	    (drv->bus->remove && drv->remove) ||
-	    (drv->bus->shutdown && drv->shutdown)) {
-		printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
-	}
-	klist_init(&drv->klist_devices, NULL, NULL);
-	return bus_add_driver(drv);
+	    (drv->bus->shutdown && drv->shutdown))
+		printk(KERN_WARNING "Driver '%s' needs updating - please use "
+			"bus_type methods\n", drv->name);
+	ret = bus_add_driver(drv);
+	if (ret)
+		return ret;
+	ret = driver_add_groups(drv, drv->groups);
+	if (ret)
+		bus_remove_driver(drv);
+	return ret;
 }
+EXPORT_SYMBOL_GPL(driver_register);
 
 /**
- *	driver_unregister - remove driver from system.
- *	@drv:	driver.
+ * driver_unregister - remove driver from system.
+ * @drv: driver.
  *
- *	Again, we pass off most of the work to the bus-level call.
+ * Again, we pass off most of the work to the bus-level call.
  */
-
-void driver_unregister(struct device_driver * drv)
+void driver_unregister(struct device_driver *drv)
 {
+	driver_remove_groups(drv, drv->groups);
 	bus_remove_driver(drv);
 }
+EXPORT_SYMBOL_GPL(driver_unregister);
 
 /**
- *	driver_find - locate driver on a bus by its name.
- *	@name:	name of the driver.
- *	@bus:	bus to scan for the driver.
+ * driver_find - locate driver on a bus by its name.
+ * @name: name of the driver.
+ * @bus: bus to scan for the driver.
  *
- *	Call kset_find_obj() to iterate over list of drivers on
- *	a bus to find driver by name. Return driver if found.
+ * Call kset_find_obj() to iterate over list of drivers on
+ * a bus to find driver by name. Return driver if found.
  *
- *	Note that kset_find_obj increments driver's reference count.
+ * Note that kset_find_obj increments driver's reference count.
  */
 struct device_driver *driver_find(const char *name, struct bus_type *bus)
 {
-	struct kobject *k = kset_find_obj(&bus->drivers, name);
-	if (k)
-		return to_drv(k);
+	struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
+	struct driver_private *priv;
+
+	if (k) {
+		priv = to_driver(k);
+		return priv->driver;
+	}
 	return NULL;
 }
-
-EXPORT_SYMBOL_GPL(driver_register);
-EXPORT_SYMBOL_GPL(driver_unregister);
-EXPORT_SYMBOL_GPL(get_driver);
-EXPORT_SYMBOL_GPL(put_driver);
 EXPORT_SYMBOL_GPL(driver_find);
-
-EXPORT_SYMBOL_GPL(driver_create_file);
-EXPORT_SYMBOL_GPL(driver_remove_file);
diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c
index 90c862932169..113815556809 100644
--- a/drivers/base/firmware.c
+++ b/drivers/base/firmware.c
@@ -3,11 +3,11 @@
  *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007 Novell Inc.
  *
  * This file is released under the GPLv2
- *
  */
-
 #include <linux/kobject.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -15,23 +15,13 @@
 
 #include "base.h"
 
-static decl_subsys(firmware, NULL, NULL);
-
-int firmware_register(struct kset *s)
-{
-	kobj_set_kset_s(s, firmware_subsys);
-	return subsystem_register(s);
-}
-
-void firmware_unregister(struct kset *s)
-{
-	subsystem_unregister(s);
-}
+struct kobject *firmware_kobj;
+EXPORT_SYMBOL_GPL(firmware_kobj);
 
 int __init firmware_init(void)
 {
-	return subsystem_register(&firmware_subsys);
+	firmware_kobj = kobject_create_and_add("firmware", NULL);
+	if (!firmware_kobj)
+		return -ENOMEM;
+	return 0;
 }
-
-EXPORT_SYMBOL_GPL(firmware_register);
-EXPORT_SYMBOL_GPL(firmware_unregister);
diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c
index 7080b413ddc9..6428cba3aadd 100644
--- a/drivers/base/hypervisor.c
+++ b/drivers/base/hypervisor.c
@@ -2,19 +2,23 @@
  * hypervisor.c - /sys/hypervisor subsystem.
  *
  * Copyright (C) IBM Corp. 2006
+ * Copyright (C) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2007 Novell Inc.
  *
  * This file is released under the GPLv2
  */
 
 #include <linux/kobject.h>
 #include <linux/device.h>
-
 #include "base.h"
 
-decl_subsys(hypervisor, NULL, NULL);
-EXPORT_SYMBOL_GPL(hypervisor_subsys);
+struct kobject *hypervisor_kobj;
+EXPORT_SYMBOL_GPL(hypervisor_kobj);
 
 int __init hypervisor_init(void)
 {
-	return subsystem_register(&hypervisor_subsys);
+	hypervisor_kobj = kobject_create_and_add("hypervisor", NULL);
+	if (!hypervisor_kobj)
+		return -ENOMEM;
+	return 0;
 }
diff --git a/drivers/base/init.c b/drivers/base/init.c
index 37138154f9e8..7bd9b6a5b01f 100644
--- a/drivers/base/init.c
+++ b/drivers/base/init.c
@@ -1,10 +1,8 @@
 /*
- *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
  *
  * This file is released under the GPLv2
- *
  */
 
 #include <linux/device.h>
@@ -14,12 +12,11 @@
 #include "base.h"
 
 /**
- *	driver_init - initialize driver model.
+ * driver_init - initialize driver model.
  *
- *	Call the driver model init functions to initialize their
- *	subsystems. Called early from init/main.c.
+ * Call the driver model init functions to initialize their
+ * subsystems. Called early from init/main.c.
  */
-
 void __init driver_init(void)
 {
 	/* These are the core pieces */
@@ -36,5 +33,4 @@ void __init driver_init(void)
 	system_bus_init();
 	cpu_dev_init();
 	memory_dev_init();
-	attribute_container_init();
 }
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 7868707c7eda..7ae413fdd5fc 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -26,7 +26,7 @@
 #define MEMORY_CLASS_NAME	"memory"
 
 static struct sysdev_class memory_sysdev_class = {
-	set_kset_name(MEMORY_CLASS_NAME),
+	.name = MEMORY_CLASS_NAME,
 };
 
 static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
diff --git a/drivers/base/module.c b/drivers/base/module.c
new file mode 100644
index 000000000000..103be9cacb05
--- /dev/null
+++ b/drivers/base/module.c
@@ -0,0 +1,94 @@
+/*
+ * module.c - module sysfs fun for drivers
+ *
+ * This file is released under the GPLv2
+ *
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include "base.h"
+
+static char *make_driver_name(struct device_driver *drv)
+{
+	char *driver_name;
+
+	driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,
+			      GFP_KERNEL);
+	if (!driver_name)
+		return NULL;
+
+	sprintf(driver_name, "%s:%s", drv->bus->name, drv->name);
+	return driver_name;
+}
+
+static void module_create_drivers_dir(struct module_kobject *mk)
+{
+	if (!mk || mk->drivers_dir)
+		return;
+
+	mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj);
+}
+
+void module_add_driver(struct module *mod, struct device_driver *drv)
+{
+	char *driver_name;
+	int no_warn;
+	struct module_kobject *mk = NULL;
+
+	if (!drv)
+		return;
+
+	if (mod)
+		mk = &mod->mkobj;
+	else if (drv->mod_name) {
+		struct kobject *mkobj;
+
+		/* Lookup built-in module entry in /sys/modules */
+		mkobj = kset_find_obj(module_kset, drv->mod_name);
+		if (mkobj) {
+			mk = container_of(mkobj, struct module_kobject, kobj);
+			/* remember our module structure */
+			drv->p->mkobj = mk;
+			/* kset_find_obj took a reference */
+			kobject_put(mkobj);
+		}
+	}
+
+	if (!mk)
+		return;
+
+	/* Don't check return codes; these calls are idempotent */
+	no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module");
+	driver_name = make_driver_name(drv);
+	if (driver_name) {
+		module_create_drivers_dir(mk);
+		no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,
+					    driver_name);
+		kfree(driver_name);
+	}
+}
+
+void module_remove_driver(struct device_driver *drv)
+{
+	struct module_kobject *mk = NULL;
+	char *driver_name;
+
+	if (!drv)
+		return;
+
+	sysfs_remove_link(&drv->p->kobj, "module");
+
+	if (drv->owner)
+		mk = &drv->owner->mkobj;
+	else if (drv->p->mkobj)
+		mk = drv->p->mkobj;
+	if (mk && mk->drivers_dir) {
+		driver_name = make_driver_name(drv);
+		if (driver_name) {
+			sysfs_remove_link(mk->drivers_dir, driver_name);
+			kfree(driver_name);
+		}
+	}
+}
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 88eeed72b5d6..e59861f18ce5 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -15,7 +15,7 @@
 #include <linux/device.h>
 
 static struct sysdev_class node_class = {
-	set_kset_name("node"),
+	.name = "node",
 };
 
 
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index fb5609241482..efaf282c438c 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -20,7 +20,8 @@
 
 #include "base.h"
 
-#define to_platform_driver(drv)	(container_of((drv), struct platform_driver, driver))
+#define to_platform_driver(drv)	(container_of((drv), struct platform_driver, \
+				 driver))
 
 struct device platform_bus = {
 	.bus_id		= "platform",
@@ -28,14 +29,13 @@ struct device platform_bus = {
 EXPORT_SYMBOL_GPL(platform_bus);
 
 /**
- *	platform_get_resource - get a resource for a device
- *	@dev: platform device
- *	@type: resource type
- *	@num: resource index
+ * platform_get_resource - get a resource for a device
+ * @dev: platform device
+ * @type: resource type
+ * @num: resource index
  */
-struct resource *
-platform_get_resource(struct platform_device *dev, unsigned int type,
-		      unsigned int num)
+struct resource *platform_get_resource(struct platform_device *dev,
+				       unsigned int type, unsigned int num)
 {
 	int i;
 
@@ -43,8 +43,7 @@ platform_get_resource(struct platform_device *dev, unsigned int type,
 		struct resource *r = &dev->resource[i];
 
 		if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
-				 IORESOURCE_IRQ|IORESOURCE_DMA))
-		    == type)
+				 IORESOURCE_IRQ|IORESOURCE_DMA)) == type)
 			if (num-- == 0)
 				return r;
 	}
@@ -53,9 +52,9 @@ platform_get_resource(struct platform_device *dev, unsigned int type,
 EXPORT_SYMBOL_GPL(platform_get_resource);
 
 /**
- *	platform_get_irq - get an IRQ for a device
- *	@dev: platform device
- *	@num: IRQ number index
+ * platform_get_irq - get an IRQ for a device
+ * @dev: platform device
+ * @num: IRQ number index
  */
 int platform_get_irq(struct platform_device *dev, unsigned int num)
 {
@@ -66,14 +65,13 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
 EXPORT_SYMBOL_GPL(platform_get_irq);
 
 /**
- *	platform_get_resource_byname - get a resource for a device by name
- *	@dev: platform device
- *	@type: resource type
- *	@name: resource name
+ * platform_get_resource_byname - get a resource for a device by name
+ * @dev: platform device
+ * @type: resource type
+ * @name: resource name
  */
-struct resource *
-platform_get_resource_byname(struct platform_device *dev, unsigned int type,
-		      char *name)
+struct resource *platform_get_resource_byname(struct platform_device *dev,
+					      unsigned int type, char *name)
 {
 	int i;
 
@@ -90,22 +88,23 @@ platform_get_resource_byname(struct platform_device *dev, unsigned int type,
 EXPORT_SYMBOL_GPL(platform_get_resource_byname);
 
 /**
- *	platform_get_irq - get an IRQ for a device
- *	@dev: platform device
- *	@name: IRQ name
+ * platform_get_irq - get an IRQ for a device
+ * @dev: platform device
+ * @name: IRQ name
  */
 int platform_get_irq_byname(struct platform_device *dev, char *name)
 {
-	struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
+	struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ,
+							  name);
 
 	return r ? r->start : -ENXIO;
 }
 EXPORT_SYMBOL_GPL(platform_get_irq_byname);
 
 /**
- *	platform_add_devices - add a numbers of platform devices
- *	@devs: array of platform devices to add
- *	@num: number of platform devices in array
+ * platform_add_devices - add a numbers of platform devices
+ * @devs: array of platform devices to add
+ * @num: number of platform devices in array
  */
 int platform_add_devices(struct platform_device **devs, int num)
 {
@@ -130,12 +129,11 @@ struct platform_object {
 };
 
 /**
- *	platform_device_put
- *	@pdev:	platform device to free
+ * platform_device_put
+ * @pdev: platform device to free
  *
- *	Free all memory associated with a platform device.  This function
- *	must _only_ be externally called in error cases.  All other usage
- *	is a bug.
+ * Free all memory associated with a platform device.  This function must
+ * _only_ be externally called in error cases.  All other usage is a bug.
  */
 void platform_device_put(struct platform_device *pdev)
 {
@@ -146,7 +144,8 @@ EXPORT_SYMBOL_GPL(platform_device_put);
 
 static void platform_device_release(struct device *dev)
 {
-	struct platform_object *pa = container_of(dev, struct platform_object, pdev.dev);
+	struct platform_object *pa = container_of(dev, struct platform_object,
+						  pdev.dev);
 
 	kfree(pa->pdev.dev.platform_data);
 	kfree(pa->pdev.resource);
@@ -154,12 +153,12 @@ static void platform_device_release(struct device *dev)
 }
 
 /**
- *	platform_device_alloc
- *	@name:	base name of the device we're adding
- *	@id:    instance id
+ * platform_device_alloc
+ * @name: base name of the device we're adding
+ * @id: instance id
  *
- *	Create a platform device object which can have other objects attached
- *	to it, and which will have attached objects freed when it is released.
+ * Create a platform device object which can have other objects attached
+ * to it, and which will have attached objects freed when it is released.
  */
 struct platform_device *platform_device_alloc(const char *name, int id)
 {
@@ -179,16 +178,17 @@ struct platform_device *platform_device_alloc(const char *name, int id)
 EXPORT_SYMBOL_GPL(platform_device_alloc);
 
 /**
- *	platform_device_add_resources
- *	@pdev:	platform device allocated by platform_device_alloc to add resources to
- *	@res:   set of resources that needs to be allocated for the device
- *	@num:	number of resources
+ * platform_device_add_resources
+ * @pdev: platform device allocated by platform_device_alloc to add resources to
+ * @res: set of resources that needs to be allocated for the device
+ * @num: number of resources
  *
- *	Add a copy of the resources to the platform device.  The memory
- *	associated with the resources will be freed when the platform
- *	device is released.
+ * Add a copy of the resources to the platform device.  The memory
+ * associated with the resources will be freed when the platform device is
+ * released.
  */
-int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num)
+int platform_device_add_resources(struct platform_device *pdev,
+				  struct resource *res, unsigned int num)
 {
 	struct resource *r;
 
@@ -203,16 +203,17 @@ int platform_device_add_resources(struct platform_device *pdev, struct resource
 EXPORT_SYMBOL_GPL(platform_device_add_resources);
 
 /**
- *	platform_device_add_data
- *	@pdev:	platform device allocated by platform_device_alloc to add resources to
- *	@data:	platform specific data for this platform device
- *	@size:	size of platform specific data
+ * platform_device_add_data
+ * @pdev: platform device allocated by platform_device_alloc to add resources to
+ * @data: platform specific data for this platform device
+ * @size: size of platform specific data
  *
- *	Add a copy of platform specific data to the platform device's platform_data
- *	pointer.  The memory associated with the platform data will be freed
- *	when the platform device is released.
+ * Add a copy of platform specific data to the platform device's
+ * platform_data pointer.  The memory associated with the platform data
+ * will be freed when the platform device is released.
  */
-int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size)
+int platform_device_add_data(struct platform_device *pdev, const void *data,
+			     size_t size)
 {
 	void *d;
 
@@ -226,11 +227,11 @@ int platform_device_add_data(struct platform_device *pdev, const void *data, siz
 EXPORT_SYMBOL_GPL(platform_device_add_data);
 
 /**
- *	platform_device_add - add a platform device to device hierarchy
- *	@pdev:	platform device we're adding
+ * platform_device_add - add a platform device to device hierarchy
+ * @pdev: platform device we're adding
  *
- *	This is part 2 of platform_device_register(), though may be called
- *	separately _iff_ pdev was allocated by platform_device_alloc().
+ * This is part 2 of platform_device_register(), though may be called
+ * separately _iff_ pdev was allocated by platform_device_alloc().
  */
 int platform_device_add(struct platform_device *pdev)
 {
@@ -289,13 +290,12 @@ int platform_device_add(struct platform_device *pdev)
 EXPORT_SYMBOL_GPL(platform_device_add);
 
 /**
- *	platform_device_del - remove a platform-level device
- *	@pdev:	platform device we're removing
+ * platform_device_del - remove a platform-level device
+ * @pdev: platform device we're removing
  *
- *	Note that this function will also release all memory- and port-based
- *	resources owned by the device (@dev->resource).  This function
- *	must _only_ be externally called in error cases.  All other usage
- *	is a bug.
+ * Note that this function will also release all memory- and port-based
+ * resources owned by the device (@dev->resource).  This function must
+ * _only_ be externally called in error cases.  All other usage is a bug.
  */
 void platform_device_del(struct platform_device *pdev)
 {
@@ -314,11 +314,10 @@ void platform_device_del(struct platform_device *pdev)
 EXPORT_SYMBOL_GPL(platform_device_del);
 
 /**
- *	platform_device_register - add a platform-level device
- *	@pdev:	platform device we're adding
- *
+ * platform_device_register - add a platform-level device
+ * @pdev: platform device we're adding
  */
-int platform_device_register(struct platform_device * pdev)
+int platform_device_register(struct platform_device *pdev)
 {
 	device_initialize(&pdev->dev);
 	return platform_device_add(pdev);
@@ -326,14 +325,14 @@ int platform_device_register(struct platform_device * pdev)
 EXPORT_SYMBOL_GPL(platform_device_register);
 
 /**
- *	platform_device_unregister - unregister a platform-level device
- *	@pdev:	platform device we're unregistering
+ * platform_device_unregister - unregister a platform-level device
+ * @pdev: platform device we're unregistering
  *
- *	Unregistration is done in 2 steps. First we release all resources
- *	and remove it from the subsystem, then we drop reference count by
- *	calling platform_device_put().
+ * Unregistration is done in 2 steps. First we release all resources
+ * and remove it from the subsystem, then we drop reference count by
+ * calling platform_device_put().
  */
-void platform_device_unregister(struct platform_device * pdev)
+void platform_device_unregister(struct platform_device *pdev)
 {
 	platform_device_del(pdev);
 	platform_device_put(pdev);
@@ -341,27 +340,29 @@ void platform_device_unregister(struct platform_device * pdev)
 EXPORT_SYMBOL_GPL(platform_device_unregister);
 
 /**
- *	platform_device_register_simple
- *	@name:  base name of the device we're adding
- *	@id:    instance id
- *	@res:   set of resources that needs to be allocated for the device
- *	@num:	number of resources
+ * platform_device_register_simple
+ * @name: base name of the device we're adding
+ * @id: instance id
+ * @res: set of resources that needs to be allocated for the device
+ * @num: number of resources
  *
- *	This function creates a simple platform device that requires minimal
- *	resource and memory management. Canned release function freeing
- *	memory allocated for the device allows drivers using such devices
- *	to be unloaded without waiting for the last reference to the device
- *	to be dropped.
+ * This function creates a simple platform device that requires minimal
+ * resource and memory management. Canned release function freeing memory
+ * allocated for the device allows drivers using such devices to be
+ * unloaded without waiting for the last reference to the device to be
+ * dropped.
  *
- *	This interface is primarily intended for use with legacy drivers
- *	which probe hardware directly.  Because such drivers create sysfs
- *	device nodes themselves, rather than letting system infrastructure
- *	handle such device enumeration tasks, they don't fully conform to
- *	the Linux driver model.  In particular, when such drivers are built
- *	as modules, they can't be "hotplugged".
+ * This interface is primarily intended for use with legacy drivers which
+ * probe hardware directly.  Because such drivers create sysfs device nodes
+ * themselves, rather than letting system infrastructure handle such device
+ * enumeration tasks, they don't fully conform to the Linux driver model.
+ * In particular, when such drivers are built as modules, they can't be
+ * "hotplugged".
  */
-struct platform_device *platform_device_register_simple(char *name, int id,
-							struct resource *res, unsigned int num)
+struct platform_device *platform_device_register_simple(const char *name,
+							int id,
+							struct resource *res,
+							unsigned int num)
 {
 	struct platform_device *pdev;
 	int retval;
@@ -436,8 +437,8 @@ static int platform_drv_resume(struct device *_dev)
 }
 
 /**
- *	platform_driver_register
- *	@drv: platform driver structure
+ * platform_driver_register
+ * @drv: platform driver structure
  */
 int platform_driver_register(struct platform_driver *drv)
 {
@@ -457,8 +458,8 @@ int platform_driver_register(struct platform_driver *drv)
 EXPORT_SYMBOL_GPL(platform_driver_register);
 
 /**
- *	platform_driver_unregister
- *	@drv: platform driver structure
+ * platform_driver_unregister
+ * @drv: platform driver structure
  */
 void platform_driver_unregister(struct platform_driver *drv)
 {
@@ -497,12 +498,12 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,
 	 * if the probe was successful, and make sure any forced probes of
 	 * new devices fail.
 	 */
-	spin_lock(&platform_bus_type.klist_drivers.k_lock);
+	spin_lock(&platform_bus_type.p->klist_drivers.k_lock);
 	drv->probe = NULL;
-	if (code == 0 && list_empty(&drv->driver.klist_devices.k_list))
+	if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
 		retval = -ENODEV;
 	drv->driver.probe = platform_drv_probe_fail;
-	spin_unlock(&platform_bus_type.klist_drivers.k_lock);
+	spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
 
 	if (code != retval)
 		platform_driver_unregister(drv);
@@ -516,8 +517,8 @@ EXPORT_SYMBOL_GPL(platform_driver_probe);
  * (b) sysfs attribute lets new-style coldplug recover from hotplug events
  *     mishandled before system is fully running:  "modprobe $(cat modalias)"
  */
-static ssize_t
-modalias_show(struct device *dev, struct device_attribute *a, char *buf)
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+			     char *buf)
 {
 	struct platform_device	*pdev = to_platform_device(dev);
 	int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
@@ -538,26 +539,24 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
 	return 0;
 }
 
-
 /**
- *	platform_match - bind platform device to platform driver.
- *	@dev:	device.
- *	@drv:	driver.
+ * platform_match - bind platform device to platform driver.
+ * @dev: device.
+ * @drv: driver.
  *
- *	Platform device IDs are assumed to be encoded like this:
- *	"<name><instance>", where <name> is a short description of the
- *	type of device, like "pci" or "floppy", and <instance> is the
- *	enumerated instance of the device, like '0' or '42'.
- *	Driver IDs are simply "<name>".
- *	So, extract the <name> from the platform_device structure,
- *	and compare it against the name of the driver. Return whether
- *	they match or not.
+ * Platform device IDs are assumed to be encoded like this:
+ * "<name><instance>", where <name> is a short description of the type of
+ * device, like "pci" or "floppy", and <instance> is the enumerated
+ * instance of the device, like '0' or '42'.  Driver IDs are simply
+ * "<name>".  So, extract the <name> from the platform_device structure,
+ * and compare it against the name of the driver. Return whether they match
+ * or not.
  */
-
-static int platform_match(struct device * dev, struct device_driver * drv)
+static int platform_match(struct device *dev, struct device_driver *drv)
 {
-	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+	struct platform_device *pdev;
 
+	pdev = container_of(dev, struct platform_device, dev);
 	return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
 }
 
@@ -574,9 +573,10 @@ static int platform_suspend(struct device *dev, pm_message_t mesg)
 static int platform_suspend_late(struct device *dev, pm_message_t mesg)
 {
 	struct platform_driver *drv = to_platform_driver(dev->driver);
-	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+	struct platform_device *pdev;
 	int ret = 0;
 
+	pdev = container_of(dev, struct platform_device, dev);
 	if (dev->driver && drv->suspend_late)
 		ret = drv->suspend_late(pdev, mesg);
 
@@ -586,16 +586,17 @@ static int platform_suspend_late(struct device *dev, pm_message_t mesg)
 static int platform_resume_early(struct device *dev)
 {
 	struct platform_driver *drv = to_platform_driver(dev->driver);
-	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+	struct platform_device *pdev;
 	int ret = 0;
 
+	pdev = container_of(dev, struct platform_device, dev);
 	if (dev->driver && drv->resume_early)
 		ret = drv->resume_early(pdev);
 
 	return ret;
 }
 
-static int platform_resume(struct device * dev)
+static int platform_resume(struct device *dev)
 {
 	int ret = 0;
 
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 44504e6618fb..de28dfd3b96c 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,11 +1,6 @@
-obj-y			:= shutdown.o
 obj-$(CONFIG_PM)	+= sysfs.o
 obj-$(CONFIG_PM_SLEEP)	+= main.o
 obj-$(CONFIG_PM_TRACE)	+= trace.o
 
-ifeq ($(CONFIG_DEBUG_DRIVER),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
-ifeq ($(CONFIG_PM_VERBOSE),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
+ccflags-$(CONFIG_PM_VERBOSE)   += -DDEBUG
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 691ffb64cc37..200ed5fafd50 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -24,20 +24,45 @@
 #include <linux/mutex.h>
 #include <linux/pm.h>
 #include <linux/resume-trace.h>
+#include <linux/rwsem.h>
 
 #include "../base.h"
 #include "power.h"
 
+/*
+ * The entries in the dpm_active list are in a depth first order, simply
+ * because children are guaranteed to be discovered after parents, and
+ * are inserted at the back of the list on discovery.
+ *
+ * All the other lists are kept in the same order, for consistency.
+ * However the lists aren't always traversed in the same order.
+ * Semaphores must be acquired from the top (i.e., front) down
+ * and released in the opposite order.  Devices must be suspended
+ * from the bottom (i.e., end) up and resumed in the opposite order.
+ * That way no parent will be suspended while it still has an active
+ * child.
+ *
+ * Since device_pm_add() may be called with a device semaphore held,
+ * we must never try to acquire a device semaphore while holding
+ * dpm_list_mutex.
+ */
+
 LIST_HEAD(dpm_active);
+static LIST_HEAD(dpm_locked);
 static LIST_HEAD(dpm_off);
 static LIST_HEAD(dpm_off_irq);
+static LIST_HEAD(dpm_destroy);
 
-static DEFINE_MUTEX(dpm_mtx);
 static DEFINE_MUTEX(dpm_list_mtx);
 
-int (*platform_enable_wakeup)(struct device *dev, int is_on);
+static DECLARE_RWSEM(pm_sleep_rwsem);
 
+int (*platform_enable_wakeup)(struct device *dev, int is_on);
 
+/**
+ *	device_pm_add - add a device to the list of active devices
+ *	@dev:	Device to be added to the list
+ */
 void device_pm_add(struct device *dev)
 {
 	pr_debug("PM: Adding info for %s:%s\n",
@@ -48,8 +73,36 @@ void device_pm_add(struct device *dev)
 	mutex_unlock(&dpm_list_mtx);
 }
 
+/**
+ *	device_pm_remove - remove a device from the list of active devices
+ *	@dev:	Device to be removed from the list
+ *
+ *	This function also removes the device's PM-related sysfs attributes.
+ */
 void device_pm_remove(struct device *dev)
 {
+	/*
+	 * If this function is called during a suspend, it will be blocked,
+	 * because we're holding the device's semaphore at that time, which may
+	 * lead to a deadlock.  In that case we want to print a warning.
+	 * However, it may also be called by unregister_dropped_devices() with
+	 * the device's semaphore released, in which case the warning should
+	 * not be printed.
+	 */
+	if (down_trylock(&dev->sem)) {
+		if (down_read_trylock(&pm_sleep_rwsem)) {
+			/* No suspend in progress, wait on dev->sem */
+			down(&dev->sem);
+			up_read(&pm_sleep_rwsem);
+		} else {
+			/* Suspend in progress, we may deadlock */
+			dev_warn(dev, "Suspicious %s during suspend\n",
+				__FUNCTION__);
+			dump_stack();
+			/* The user has been warned ... */
+			down(&dev->sem);
+		}
+	}
 	pr_debug("PM: Removing info for %s:%s\n",
 		 dev->bus ? dev->bus->name : "No Bus",
 		 kobject_name(&dev->kobj));
@@ -57,25 +110,124 @@ void device_pm_remove(struct device *dev)
 	dpm_sysfs_remove(dev);
 	list_del_init(&dev->power.entry);
 	mutex_unlock(&dpm_list_mtx);
+	up(&dev->sem);
+}
+
+/**
+ *	device_pm_schedule_removal - schedule the removal of a suspended device
+ *	@dev:	Device to destroy
+ *
+ *	Moves the device to the dpm_destroy list for further processing by
+ *	unregister_dropped_devices().
+ */
+void device_pm_schedule_removal(struct device *dev)
+{
+	pr_debug("PM: Preparing for removal: %s:%s\n",
+		dev->bus ? dev->bus->name : "No Bus",
+		kobject_name(&dev->kobj));
+	mutex_lock(&dpm_list_mtx);
+	list_move_tail(&dev->power.entry, &dpm_destroy);
+	mutex_unlock(&dpm_list_mtx);
+}
+
+/**
+ *	pm_sleep_lock - mutual exclusion for registration and suspend
+ *
+ *	Returns 0 if no suspend is underway and device registration
+ *	may proceed, otherwise -EBUSY.
+ */
+int pm_sleep_lock(void)
+{
+	if (down_read_trylock(&pm_sleep_rwsem))
+		return 0;
+
+	return -EBUSY;
+}
+
+/**
+ *	pm_sleep_unlock - mutual exclusion for registration and suspend
+ *
+ *	This routine undoes the effect of device_pm_add_lock
+ *	when a device's registration is complete.
+ */
+void pm_sleep_unlock(void)
+{
+	up_read(&pm_sleep_rwsem);
 }
 
 
 /*------------------------- Resume routines -------------------------*/
 
 /**
- *	resume_device - Restore state for one device.
+ *	resume_device_early - Power on one device (early resume).
  *	@dev:	Device.
  *
+ *	Must be called with interrupts disabled.
  */
-
-static int resume_device(struct device * dev)
+static int resume_device_early(struct device *dev)
 {
 	int error = 0;
 
 	TRACE_DEVICE(dev);
 	TRACE_RESUME(0);
 
-	down(&dev->sem);
+	if (dev->bus && dev->bus->resume_early) {
+		dev_dbg(dev, "EARLY resume\n");
+		error = dev->bus->resume_early(dev);
+	}
+
+	TRACE_RESUME(error);
+	return error;
+}
+
+/**
+ *	dpm_power_up - Power on all regular (non-sysdev) devices.
+ *
+ *	Walk the dpm_off_irq list and power each device up. This
+ *	is used for devices that required they be powered down with
+ *	interrupts disabled. As devices are powered on, they are moved
+ *	to the dpm_off list.
+ *
+ *	Must be called with interrupts disabled and only one CPU running.
+ */
+static void dpm_power_up(void)
+{
+
+	while (!list_empty(&dpm_off_irq)) {
+		struct list_head *entry = dpm_off_irq.next;
+		struct device *dev = to_device(entry);
+
+		list_move_tail(entry, &dpm_off);
+		resume_device_early(dev);
+	}
+}
+
+/**
+ *	device_power_up - Turn on all devices that need special attention.
+ *
+ *	Power on system devices, then devices that required we shut them down
+ *	with interrupts disabled.
+ *
+ *	Must be called with interrupts disabled.
+ */
+void device_power_up(void)
+{
+	sysdev_resume();
+	dpm_power_up();
+}
+EXPORT_SYMBOL_GPL(device_power_up);
+
+/**
+ *	resume_device - Restore state for one device.
+ *	@dev:	Device.
+ *
+ */
+static int resume_device(struct device *dev)
+{
+	int error = 0;
+
+	TRACE_DEVICE(dev);
+	TRACE_RESUME(0);
 
 	if (dev->bus && dev->bus->resume) {
 		dev_dbg(dev,"resuming\n");
@@ -92,126 +244,94 @@ static int resume_device(struct device * dev)
 		error = dev->class->resume(dev);
 	}
 
-	up(&dev->sem);
-
 	TRACE_RESUME(error);
 	return error;
 }
 
-
-static int resume_device_early(struct device * dev)
-{
-	int error = 0;
-
-	TRACE_DEVICE(dev);
-	TRACE_RESUME(0);
-	if (dev->bus && dev->bus->resume_early) {
-		dev_dbg(dev,"EARLY resume\n");
-		error = dev->bus->resume_early(dev);
-	}
-	TRACE_RESUME(error);
-	return error;
-}
-
-/*
- * Resume the devices that have either not gone through
- * the late suspend, or that did go through it but also
- * went through the early resume
+/**
+ *	dpm_resume - Resume every device.
+ *
+ *	Resume the devices that have either not gone through
+ *	the late suspend, or that did go through it but also
+ *	went through the early resume.
+ *
+ *	Take devices from the dpm_off_list, resume them,
+ *	and put them on the dpm_locked list.
  */
 static void dpm_resume(void)
 {
 	mutex_lock(&dpm_list_mtx);
 	while(!list_empty(&dpm_off)) {
-		struct list_head * entry = dpm_off.next;
-		struct device * dev = to_device(entry);
-
-		get_device(dev);
-		list_move_tail(entry, &dpm_active);
+		struct list_head *entry = dpm_off.next;
+		struct device *dev = to_device(entry);
 
+		list_move_tail(entry, &dpm_locked);
 		mutex_unlock(&dpm_list_mtx);
 		resume_device(dev);
 		mutex_lock(&dpm_list_mtx);
-		put_device(dev);
 	}
 	mutex_unlock(&dpm_list_mtx);
 }
 
-
 /**
- *	device_resume - Restore state of each device in system.
+ *	unlock_all_devices - Release each device's semaphore
  *
- *	Walk the dpm_off list, remove each entry, resume the device,
- *	then add it to the dpm_active list.
+ *	Go through the dpm_off list.  Put each device on the dpm_active
+ *	list and unlock it.
  */
-
-void device_resume(void)
+static void unlock_all_devices(void)
 {
-	might_sleep();
-	mutex_lock(&dpm_mtx);
-	dpm_resume();
-	mutex_unlock(&dpm_mtx);
-}
-
-EXPORT_SYMBOL_GPL(device_resume);
+	mutex_lock(&dpm_list_mtx);
+	while (!list_empty(&dpm_locked)) {
+		struct list_head *entry = dpm_locked.prev;
+		struct device *dev = to_device(entry);
 
+		list_move(entry, &dpm_active);
+		up(&dev->sem);
+	}
+	mutex_unlock(&dpm_list_mtx);
+}
 
 /**
- *	dpm_power_up - Power on some devices.
- *
- *	Walk the dpm_off_irq list and power each device up. This
- *	is used for devices that required they be powered down with
- *	interrupts disabled. As devices are powered on, they are moved
- *	to the dpm_active list.
+ *	unregister_dropped_devices - Unregister devices scheduled for removal
  *
- *	Interrupts must be disabled when calling this.
+ *	Unregister all devices on the dpm_destroy list.
  */
-
-static void dpm_power_up(void)
+static void unregister_dropped_devices(void)
 {
-	while(!list_empty(&dpm_off_irq)) {
-		struct list_head * entry = dpm_off_irq.next;
-		struct device * dev = to_device(entry);
+	mutex_lock(&dpm_list_mtx);
+	while (!list_empty(&dpm_destroy)) {
+		struct list_head *entry = dpm_destroy.next;
+		struct device *dev = to_device(entry);
 
-		list_move_tail(entry, &dpm_off);
-		resume_device_early(dev);
+		up(&dev->sem);
+		mutex_unlock(&dpm_list_mtx);
+		/* This also removes the device from the list */
+		device_unregister(dev);
+		mutex_lock(&dpm_list_mtx);
 	}
+	mutex_unlock(&dpm_list_mtx);
 }
 
-
 /**
- *	device_power_up - Turn on all devices that need special attention.
+ *	device_resume - Restore state of each device in system.
  *
- *	Power on system devices then devices that required we shut them down
- *	with interrupts disabled.
- *	Called with interrupts disabled.
+ *	Resume all the devices, unlock them all, and allow new
+ *	devices to be registered once again.
  */
-
-void device_power_up(void)
+void device_resume(void)
 {
-	sysdev_resume();
-	dpm_power_up();
+	might_sleep();
+	dpm_resume();
+	unlock_all_devices();
+	unregister_dropped_devices();
+	up_write(&pm_sleep_rwsem);
 }
-
-EXPORT_SYMBOL_GPL(device_power_up);
+EXPORT_SYMBOL_GPL(device_resume);
 
 
 /*------------------------- Suspend routines -------------------------*/
 
-/*
- * The entries in the dpm_active list are in a depth first order, simply
- * because children are guaranteed to be discovered after parents, and
- * are inserted at the back of the list on discovery.
- *
- * All list on the suspend path are done in reverse order, so we operate
- * on the leaves of the device tree (or forests, depending on how you want
- * to look at it ;) first. As nodes are removed from the back of the list,
- * they are inserted into the front of their destintation lists.
- *
- * Things are the reverse on the resume path - iterations are done in
- * forward order, and nodes are inserted at the back of their destination
- * lists. This way, the ancestors will be accessed before their descendents.
- */
-
 static inline char *suspend_verb(u32 event)
 {
 	switch (event) {
@@ -222,7 +342,6 @@ static inline char *suspend_verb(u32 event)
 	}
 }
 
-
 static void
 suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
 {
@@ -232,16 +351,73 @@ suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
 }
 
 /**
- *	suspend_device - Save state of one device.
+ *	suspend_device_late - Shut down one device (late suspend).
  *	@dev:	Device.
  *	@state:	Power state device is entering.
+ *
+ *	This is called with interrupts off and only a single CPU running.
  */
+static int suspend_device_late(struct device *dev, pm_message_t state)
+{
+	int error = 0;
 
-static int suspend_device(struct device * dev, pm_message_t state)
+	if (dev->bus && dev->bus->suspend_late) {
+		suspend_device_dbg(dev, state, "LATE ");
+		error = dev->bus->suspend_late(dev, state);
+		suspend_report_result(dev->bus->suspend_late, error);
+	}
+	return error;
+}
+
+/**
+ *	device_power_down - Shut down special devices.
+ *	@state:		Power state to enter.
+ *
+ *	Power down devices that require interrupts to be disabled
+ *	and move them from the dpm_off list to the dpm_off_irq list.
+ *	Then power down system devices.
+ *
+ *	Must be called with interrupts disabled and only one CPU running.
+ */
+int device_power_down(pm_message_t state)
+{
+	int error = 0;
+
+	while (!list_empty(&dpm_off)) {
+		struct list_head *entry = dpm_off.prev;
+		struct device *dev = to_device(entry);
+
+		list_del_init(&dev->power.entry);
+		error = suspend_device_late(dev, state);
+		if (error) {
+			printk(KERN_ERR "Could not power down device %s: "
+					"error %d\n",
+					kobject_name(&dev->kobj), error);
+			if (list_empty(&dev->power.entry))
+				list_add(&dev->power.entry, &dpm_off);
+			break;
+		}
+		if (list_empty(&dev->power.entry))
+			list_add(&dev->power.entry, &dpm_off_irq);
+	}
+
+	if (!error)
+		error = sysdev_suspend(state);
+	if (error)
+		dpm_power_up();
+	return error;
+}
+EXPORT_SYMBOL_GPL(device_power_down);
+
+/**
+ *	suspend_device - Save state of one device.
+ *	@dev:	Device.
+ *	@state:	Power state device is entering.
+ */
+int suspend_device(struct device *dev, pm_message_t state)
 {
 	int error = 0;
 
-	down(&dev->sem);
 	if (dev->power.power_state.event) {
 		dev_dbg(dev, "PM: suspend %d-->%d\n",
 			dev->power.power_state.event, state.event);
@@ -264,123 +440,105 @@ static int suspend_device(struct device * dev, pm_message_t state)
 		error = dev->bus->suspend(dev, state);
 		suspend_report_result(dev->bus->suspend, error);
 	}
-	up(&dev->sem);
-	return error;
-}
-
-
-/*
- * This is called with interrupts off, only a single CPU
- * running. We can't acquire a mutex or semaphore (and we don't
- * need the protection)
- */
-static int suspend_device_late(struct device *dev, pm_message_t state)
-{
-	int error = 0;
-
-	if (dev->bus && dev->bus->suspend_late) {
-		suspend_device_dbg(dev, state, "LATE ");
-		error = dev->bus->suspend_late(dev, state);
-		suspend_report_result(dev->bus->suspend_late, error);
-	}
 	return error;
 }
 
 /**
- *	device_suspend - Save state and stop all devices in system.
- *	@state:		Power state to put each device in.
+ *	dpm_suspend - Suspend every device.
+ *	@state:	Power state to put each device in.
  *
- *	Walk the dpm_active list, call ->suspend() for each device, and move
- *	it to the dpm_off list.
+ *	Walk the dpm_locked list.  Suspend each device and move it
+ *	to the dpm_off list.
  *
  *	(For historical reasons, if it returns -EAGAIN, that used to mean
  *	that the device would be called again with interrupts disabled.
  *	These days, we use the "suspend_late()" callback for that, so we
  *	print a warning and consider it an error).
- *
- *	If we get a different error, try and back out.
- *
- *	If we hit a failure with any of the devices, call device_resume()
- *	above to bring the suspended devices back to life.
- *
  */
-
-int device_suspend(pm_message_t state)
+static int dpm_suspend(pm_message_t state)
 {
 	int error = 0;
 
-	might_sleep();
-	mutex_lock(&dpm_mtx);
 	mutex_lock(&dpm_list_mtx);
-	while (!list_empty(&dpm_active) && error == 0) {
-		struct list_head * entry = dpm_active.prev;
-		struct device * dev = to_device(entry);
+	while (!list_empty(&dpm_locked)) {
+		struct list_head *entry = dpm_locked.prev;
+		struct device *dev = to_device(entry);
 
-		get_device(dev);
+		list_del_init(&dev->power.entry);
 		mutex_unlock(&dpm_list_mtx);
-
 		error = suspend_device(dev, state);
-
-		mutex_lock(&dpm_list_mtx);
-
-		/* Check if the device got removed */
-		if (!list_empty(&dev->power.entry)) {
-			/* Move it to the dpm_off list */
-			if (!error)
-				list_move(&dev->power.entry, &dpm_off);
-		}
-		if (error)
+		if (error) {
 			printk(KERN_ERR "Could not suspend device %s: "
-				"error %d%s\n",
-				kobject_name(&dev->kobj), error,
-				error == -EAGAIN ? " (please convert to suspend_late)" : "");
-		put_device(dev);
+					"error %d%s\n",
+					kobject_name(&dev->kobj),
+					error,
+					(error == -EAGAIN ?
+					" (please convert to suspend_late)" :
+					""));
+			mutex_lock(&dpm_list_mtx);
+			if (list_empty(&dev->power.entry))
+				list_add(&dev->power.entry, &dpm_locked);
+			mutex_unlock(&dpm_list_mtx);
+			break;
+		}
+		mutex_lock(&dpm_list_mtx);
+		if (list_empty(&dev->power.entry))
+			list_add(&dev->power.entry, &dpm_off);
 	}
 	mutex_unlock(&dpm_list_mtx);
-	if (error)
-		dpm_resume();
 
-	mutex_unlock(&dpm_mtx);
 	return error;
 }
 
-EXPORT_SYMBOL_GPL(device_suspend);
-
 /**
- *	device_power_down - Shut down special devices.
- *	@state:		Power state to enter.
+ *	lock_all_devices - Acquire every device's semaphore
  *
- *	Walk the dpm_off_irq list, calling ->power_down() for each device that
- *	couldn't power down the device with interrupts enabled. When we're
- *	done, power down system devices.
+ *	Go through the dpm_active list. Carefully lock each device's
+ *	semaphore and put it in on the dpm_locked list.
  */
-
-int device_power_down(pm_message_t state)
+static void lock_all_devices(void)
 {
-	int error = 0;
-	struct device * dev;
+	mutex_lock(&dpm_list_mtx);
+	while (!list_empty(&dpm_active)) {
+		struct list_head *entry = dpm_active.next;
+		struct device *dev = to_device(entry);
 
-	while (!list_empty(&dpm_off)) {
-		struct list_head * entry = dpm_off.prev;
+		/* Required locking order is dev->sem first,
+		 * then dpm_list_mutex.  Hence this awkward code.
+		 */
+		get_device(dev);
+		mutex_unlock(&dpm_list_mtx);
+		down(&dev->sem);
+		mutex_lock(&dpm_list_mtx);
 
-		dev = to_device(entry);
-		error = suspend_device_late(dev, state);
-		if (error)
-			goto Error;
-		list_move(&dev->power.entry, &dpm_off_irq);
+		if (list_empty(entry))
+			up(&dev->sem);		/* Device was removed */
+		else
+			list_move_tail(entry, &dpm_locked);
+		put_device(dev);
 	}
+	mutex_unlock(&dpm_list_mtx);
+}
+
+/**
+ *	device_suspend - Save state and stop all devices in system.
+ *
+ *	Prevent new devices from being registered, then lock all devices
+ *	and suspend them.
+ */
+int device_suspend(pm_message_t state)
+{
+	int error;
 
-	error = sysdev_suspend(state);
- Done:
+	might_sleep();
+	down_write(&pm_sleep_rwsem);
+	lock_all_devices();
+	error = dpm_suspend(state);
+	if (error)
+		device_resume();
 	return error;
- Error:
-	printk(KERN_ERR "Could not power down device %s: "
-		"error %d\n", kobject_name(&dev->kobj), error);
-	dpm_power_up();
-	goto Done;
 }
-
-EXPORT_SYMBOL_GPL(device_power_down);
+EXPORT_SYMBOL_GPL(device_suspend);
 
 void __suspend_report_result(const char *function, void *fn, int ret)
 {
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 379da4e958e0..6f0dfca8ebdd 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -1,10 +1,3 @@
-/*
- * shutdown.c
- */
-
-extern void device_shutdown(void);
-
-
 #ifdef CONFIG_PM_SLEEP
 
 /*
@@ -20,6 +13,9 @@ static inline struct device *to_device(struct list_head *entry)
 
 extern void device_pm_add(struct device *);
 extern void device_pm_remove(struct device *);
+extern void device_pm_schedule_removal(struct device *);
+extern int pm_sleep_lock(void);
+extern void pm_sleep_unlock(void);
 
 #else /* CONFIG_PM_SLEEP */
 
@@ -32,6 +28,15 @@ static inline void device_pm_remove(struct device *dev)
 {
 }
 
+static inline int pm_sleep_lock(void)
+{
+	return 0;
+}
+
+static inline void pm_sleep_unlock(void)
+{
+}
+
 #endif
 
 #ifdef CONFIG_PM
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
deleted file mode 100644
index 56e8eaaac012..000000000000
--- a/drivers/base/power/shutdown.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * shutdown.c - power management functions for the device tree.
- *
- * Copyright (c) 2002-3 Patrick Mochel
- *		 2002-3 Open Source Development Lab
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <asm/semaphore.h>
-
-#include "../base.h"
-#include "power.h"
-
-#define to_dev(node) container_of(node, struct device, kobj.entry)
-
-
-/**
- * We handle system devices differently - we suspend and shut them
- * down last and resume them first. That way, we don't do anything stupid like
- * shutting down the interrupt controller before any devices..
- *
- * Note that there are not different stages for power management calls -
- * they only get one called once when interrupts are disabled.
- */
-
-
-/**
- * device_shutdown - call ->shutdown() on each device to shutdown.
- */
-void device_shutdown(void)
-{
-	struct device * dev, *devn;
-
-	list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.list,
-				kobj.entry) {
-		if (dev->bus && dev->bus->shutdown) {
-			dev_dbg(dev, "shutdown\n");
-			dev->bus->shutdown(dev);
-		} else if (dev->driver && dev->driver->shutdown) {
-			dev_dbg(dev, "shutdown\n");
-			dev->driver->shutdown(dev);
-		}
-	}
-}
-
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index ac7ff6d0c6e5..2f79c55acdcc 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -25,8 +25,6 @@
 
 #include "base.h"
 
-extern struct kset devices_subsys;
-
 #define to_sysdev(k) container_of(k, struct sys_device, kobj)
 #define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr)
 
@@ -128,18 +126,17 @@ void sysdev_class_remove_file(struct sysdev_class *c,
 }
 EXPORT_SYMBOL_GPL(sysdev_class_remove_file);
 
-/*
- * declare system_subsys
- */
-static decl_subsys(system, &ktype_sysdev_class, NULL);
+static struct kset *system_kset;
 
 int sysdev_class_register(struct sysdev_class * cls)
 {
 	pr_debug("Registering sysdev class '%s'\n",
 		 kobject_name(&cls->kset.kobj));
 	INIT_LIST_HEAD(&cls->drivers);
-	cls->kset.kobj.parent = &system_subsys.kobj;
-	cls->kset.kobj.kset = &system_subsys;
+	cls->kset.kobj.parent = &system_kset->kobj;
+	cls->kset.kobj.ktype = &ktype_sysdev_class;
+	cls->kset.kobj.kset = system_kset;
+	kobject_set_name(&cls->kset.kobj, cls->name);
 	return kset_register(&cls->kset);
 }
 
@@ -228,20 +225,15 @@ int sysdev_register(struct sys_device * sysdev)
 	if (!cls)
 		return -EINVAL;
 
+	pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj));
+
 	/* Make sure the kset is set */
 	sysdev->kobj.kset = &cls->kset;
 
-	/* But make sure we point to the right type for sysfs translation */
-	sysdev->kobj.ktype = &ktype_sysdev;
-	error = kobject_set_name(&sysdev->kobj, "%s%d",
-			 kobject_name(&cls->kset.kobj), sysdev->id);
-	if (error)
-		return error;
-
-	pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj));
-
 	/* Register the object */
-	error = kobject_register(&sysdev->kobj);
+	error = kobject_init_and_add(&sysdev->kobj, &ktype_sysdev, NULL,
+				     "%s%d", kobject_name(&cls->kset.kobj),
+				     sysdev->id);
 
 	if (!error) {
 		struct sysdev_driver * drv;
@@ -258,6 +250,7 @@ int sysdev_register(struct sys_device * sysdev)
 		}
 		mutex_unlock(&sysdev_drivers_lock);
 	}
+	kobject_uevent(&sysdev->kobj, KOBJ_ADD);
 	return error;
 }
 
@@ -272,7 +265,7 @@ void sysdev_unregister(struct sys_device * sysdev)
 	}
 	mutex_unlock(&sysdev_drivers_lock);
 
-	kobject_unregister(&sysdev->kobj);
+	kobject_put(&sysdev->kobj);
 }
 
 
@@ -298,8 +291,7 @@ void sysdev_shutdown(void)
 	pr_debug("Shutting Down System Devices\n");
 
 	mutex_lock(&sysdev_drivers_lock);
-	list_for_each_entry_reverse(cls, &system_subsys.list,
-				    kset.kobj.entry) {
+	list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
 		struct sys_device * sysdev;
 
 		pr_debug("Shutting down type '%s':\n",
@@ -361,9 +353,7 @@ int sysdev_suspend(pm_message_t state)
 
 	pr_debug("Suspending System Devices\n");
 
-	list_for_each_entry_reverse(cls, &system_subsys.list,
-				    kset.kobj.entry) {
-
+	list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
 		pr_debug("Suspending type '%s':\n",
 			 kobject_name(&cls->kset.kobj));
 
@@ -414,8 +404,7 @@ aux_driver:
 	}
 
 	/* resume other classes */
-	list_for_each_entry_continue(cls, &system_subsys.list,
-					kset.kobj.entry) {
+	list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) {
 		list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
 			pr_debug(" %s\n", kobject_name(&err_dev->kobj));
 			__sysdev_resume(err_dev);
@@ -440,7 +429,7 @@ int sysdev_resume(void)
 
 	pr_debug("Resuming System Devices\n");
 
-	list_for_each_entry(cls, &system_subsys.list, kset.kobj.entry) {
+	list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) {
 		struct sys_device * sysdev;
 
 		pr_debug("Resuming type '%s':\n",
@@ -458,8 +447,10 @@ int sysdev_resume(void)
 
 int __init system_bus_init(void)
 {
-	system_subsys.kobj.parent = &devices_subsys.kobj;
-	return subsystem_register(&system_subsys);
+	system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
+	if (!system_kset)
+		return -ENOMEM;
+	return 0;
 }
 
 EXPORT_SYMBOL_GPL(sysdev_register);
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 9030c373ce67..cd03473f3547 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -3455,19 +3455,12 @@ static inline bool DAC960_ProcessCompletedRequest(DAC960_Command_T *Command,
 						 bool SuccessfulIO)
 {
 	struct request *Request = Command->Request;
-	int UpToDate;
-
-	UpToDate = 0;
-	if (SuccessfulIO)
-		UpToDate = 1;
+	int Error = SuccessfulIO ? 0 : -EIO;
 
 	pci_unmap_sg(Command->Controller->PCIDevice, Command->cmd_sglist,
 		Command->SegmentCount, Command->DmaDirection);
 
-	 if (!end_that_request_first(Request, UpToDate, Command->BlockCount)) {
-		add_disk_randomness(Request->rq_disk);
- 	 	end_that_request_last(Request, UpToDate);
-
+	 if (!__blk_end_request(Request, Error, Command->BlockCount << 9)) {
 		if (Command->Completion) {
 			complete(Command->Completion);
 			Command->Completion = NULL;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 4d0119ea9e35..f2122855d4ec 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -105,6 +105,17 @@ config PARIDE
 	  "MicroSolutions backpack protocol", "DataStor Commuter protocol"
 	  etc.).
 
+config GDROM
+	tristate "SEGA Dreamcast GD-ROM drive"
+	depends on SH_DREAMCAST
+	help
+	  A standard SEGA Dreamcast comes with a modified CD ROM drive called a
+	  "GD-ROM" by SEGA to signify it is capable of reading special disks
+	  with up to 1 GB of data. This drive will also read standard CD ROM
+	  disks. Select this option to access any disks in your GD ROM drive.
+	  Most users will want to say "Y" here.
+	  You can also build this as a module which will be called gdrom.ko
+
 source "drivers/block/paride/Kconfig"
 
 config BLK_CPQ_DA
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index ad00b3d94711..826d12381e21 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -15,8 +15,10 @@
 
 static struct kmem_cache *buf_pool_cache;
 
-static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
+static ssize_t aoedisk_show_state(struct device *dev,
+				  struct device_attribute *attr, char *page)
 {
+	struct gendisk *disk = dev_to_disk(dev);
 	struct aoedev *d = disk->private_data;
 
 	return snprintf(page, PAGE_SIZE,
@@ -26,50 +28,47 @@ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
 			(d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
 	/* I'd rather see nopen exported so we can ditch closewait */
 }
-static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page)
+static ssize_t aoedisk_show_mac(struct device *dev,
+				struct device_attribute *attr, char *page)
 {
+	struct gendisk *disk = dev_to_disk(dev);
 	struct aoedev *d = disk->private_data;
 
 	return snprintf(page, PAGE_SIZE, "%012llx\n",
 			(unsigned long long)mac_addr(d->addr));
 }
-static ssize_t aoedisk_show_netif(struct gendisk * disk, char *page)
+static ssize_t aoedisk_show_netif(struct device *dev,
+				  struct device_attribute *attr, char *page)
 {
+	struct gendisk *disk = dev_to_disk(dev);
 	struct aoedev *d = disk->private_data;
 
 	return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name);
 }
 /* firmware version */
-static ssize_t aoedisk_show_fwver(struct gendisk * disk, char *page)
+static ssize_t aoedisk_show_fwver(struct device *dev,
+				  struct device_attribute *attr, char *page)
 {
+	struct gendisk *disk = dev_to_disk(dev);
 	struct aoedev *d = disk->private_data;
 
 	return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver);
 }
 
-static struct disk_attribute disk_attr_state = {
-	.attr = {.name = "state", .mode = S_IRUGO },
-	.show = aoedisk_show_state
-};
-static struct disk_attribute disk_attr_mac = {
-	.attr = {.name = "mac", .mode = S_IRUGO },
-	.show = aoedisk_show_mac
-};
-static struct disk_attribute disk_attr_netif = {
-	.attr = {.name = "netif", .mode = S_IRUGO },
-	.show = aoedisk_show_netif
-};
-static struct disk_attribute disk_attr_fwver = {
-	.attr = {.name = "firmware-version", .mode = S_IRUGO },
-	.show = aoedisk_show_fwver
+static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL);
+static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL);
+static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL);
+static struct device_attribute dev_attr_firmware_version = {
+	.attr = { .name = "firmware-version", .mode = S_IRUGO, .owner = THIS_MODULE },
+	.show = aoedisk_show_fwver,
 };
 
 static struct attribute *aoe_attrs[] = {
-	&disk_attr_state.attr,
-	&disk_attr_mac.attr,
-	&disk_attr_netif.attr,
-	&disk_attr_fwver.attr,
-	NULL
+	&dev_attr_state.attr,
+	&dev_attr_mac.attr,
+	&dev_attr_netif.attr,
+	&dev_attr_firmware_version.attr,
+	NULL,
 };
 
 static const struct attribute_group attr_group = {
@@ -79,12 +78,12 @@ static const struct attribute_group attr_group = {
 static int
 aoedisk_add_sysfs(struct aoedev *d)
 {
-	return sysfs_create_group(&d->gd->kobj, &attr_group);
+	return sysfs_create_group(&d->gd->dev.kobj, &attr_group);
 }
 void
 aoedisk_rm_sysfs(struct aoedev *d)
 {
-	sysfs_remove_group(&d->gd->kobj, &attr_group);
+	sysfs_remove_group(&d->gd->dev.kobj, &attr_group);
 }
 
 static int
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index 39e563ea0878..d5480e34cb22 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -259,9 +259,8 @@ aoechr_init(void)
 		return PTR_ERR(aoe_class);
 	}
 	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
-		class_device_create(aoe_class, NULL,
-					MKDEV(AOE_MAJOR, chardevs[i].minor),
-					NULL, chardevs[i].name);
+		device_create(aoe_class, NULL,
+			      MKDEV(AOE_MAJOR, chardevs[i].minor), chardevs[i].name);
 
 	return 0;
 }
@@ -272,7 +271,7 @@ aoechr_exit(void)
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
-		class_device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
+		device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
 	class_destroy(aoe_class);
 	unregister_chrdev(AOE_MAJOR, "aoechr");
 }
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 509b6490413b..855ce8e5efba 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1187,17 +1187,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 	}
 }
 
-static inline void complete_buffers(struct bio *bio, int status)
-{
-	while (bio) {
-		struct bio *xbh = bio->bi_next;
-
-		bio->bi_next = NULL;
-		bio_endio(bio, status ? 0 : -EIO);
-		bio = xbh;
-	}
-}
-
 static void cciss_check_queues(ctlr_info_t *h)
 {
 	int start_queue = h->next_to_run;
@@ -1263,21 +1252,14 @@ static void cciss_softirq_done(struct request *rq)
 		pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
 	}
 
-	complete_buffers(rq->bio, (rq->errors == 0));
-
-	if (blk_fs_request(rq)) {
-		const int rw = rq_data_dir(rq);
-
-		disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors);
-	}
-
 #ifdef CCISS_DEBUG
 	printk("Done with %p\n", rq);
 #endif				/* CCISS_DEBUG */
 
-	add_disk_randomness(rq->rq_disk);
+	if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, blk_rq_bytes(rq)))
+		BUG();
+
 	spin_lock_irqsave(&h->lock, flags);
-	end_that_request_last(rq, (rq->errors == 0));
 	cmd_free(h, cmd, 1);
 	cciss_check_queues(h);
 	spin_unlock_irqrestore(&h->lock, flags);
@@ -2542,9 +2524,7 @@ after_error_processing:
 		resend_cciss_cmd(h, cmd);
 		return;
 	}
-	cmd->rq->data_len = 0;
 	cmd->rq->completion_data = cmd;
-	blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE);
 	blk_complete_request(cmd->rq);
 }
 
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index c8132d958795..69199185ff4b 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -167,7 +167,6 @@ static void start_io(ctlr_info_t *h);
 
 static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c);
 static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c);
-static inline void complete_buffers(struct bio *bio, int ok);
 static inline void complete_command(cmdlist_t *cmd, int timeout);
 
 static irqreturn_t do_ida_intr(int irq, void *dev_id);
@@ -980,26 +979,13 @@ static void start_io(ctlr_info_t *h)
 	}
 }
 
-static inline void complete_buffers(struct bio *bio, int ok)
-{
-	struct bio *xbh;
-
-	while (bio) {
-		xbh = bio->bi_next;
-		bio->bi_next = NULL;
-		
-		bio_endio(bio, ok ? 0 : -EIO);
-
-		bio = xbh;
-	}
-}
 /*
  * Mark all buffers that cmd was responsible for
  */
 static inline void complete_command(cmdlist_t *cmd, int timeout)
 {
 	struct request *rq = cmd->rq;
-	int ok=1;
+	int error = 0;
 	int i, ddir;
 
 	if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
@@ -1011,16 +997,17 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
 	if (cmd->req.hdr.rcode & RCODE_FATAL) {
 		printk(KERN_WARNING "Fatal error on ida/c%dd%d\n",
 				cmd->ctlr, cmd->hdr.unit);
-		ok = 0;
+		error = -EIO;
 	}
 	if (cmd->req.hdr.rcode & RCODE_INVREQ) {
 				printk(KERN_WARNING "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",
 				cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd,
 				cmd->req.hdr.blk, cmd->req.hdr.blk_cnt,
 				cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
-		ok = 0;	
+		error = -EIO;
 	}
-	if (timeout) ok = 0;
+	if (timeout)
+		error = -EIO;
 	/* unmap the DMA mapping for all the scatter gather elements */
 	if (cmd->req.hdr.cmd == IDA_READ)
 		ddir = PCI_DMA_FROMDEVICE;
@@ -1030,18 +1017,9 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
                 pci_unmap_page(hba[cmd->ctlr]->pci_dev, cmd->req.sg[i].addr,
 				cmd->req.sg[i].size, ddir);
 
-	complete_buffers(rq->bio, ok);
-
-	if (blk_fs_request(rq)) {
-		const int rw = rq_data_dir(rq);
-
-		disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors);
-	}
-
-	add_disk_randomness(rq->rq_disk);
-
 	DBGPX(printk("Done with %p\n", rq););
-	end_that_request_last(rq, ok ? 1 : -EIO);
+	if (__blk_end_request(rq, error, blk_rq_bytes(rq)))
+		BUG();
 }
 
 /*
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 639ed14bb08d..32c79a55511b 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -2287,21 +2287,19 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
  * =============================
  */
 
-static void floppy_end_request(struct request *req, int uptodate)
+static void floppy_end_request(struct request *req, int error)
 {
 	unsigned int nr_sectors = current_count_sectors;
+	unsigned int drive = (unsigned long)req->rq_disk->private_data;
 
 	/* current_count_sectors can be zero if transfer failed */
-	if (!uptodate)
+	if (error)
 		nr_sectors = req->current_nr_sectors;
-	if (end_that_request_first(req, uptodate, nr_sectors))
+	if (__blk_end_request(req, error, nr_sectors << 9))
 		return;
-	add_disk_randomness(req->rq_disk);
-	floppy_off((long)req->rq_disk->private_data);
-	blkdev_dequeue_request(req);
-	end_that_request_last(req, uptodate);
 
 	/* We're done with the request */
+	floppy_off(drive);
 	current_req = NULL;
 }
 
@@ -2332,7 +2330,7 @@ static void request_done(int uptodate)
 
 		/* unlock chained buffers */
 		spin_lock_irqsave(q->queue_lock, flags);
-		floppy_end_request(req, 1);
+		floppy_end_request(req, 0);
 		spin_unlock_irqrestore(q->queue_lock, flags);
 	} else {
 		if (rq_data_dir(req) == WRITE) {
@@ -2346,7 +2344,7 @@ static void request_done(int uptodate)
 			DRWE->last_error_generation = DRS->generation;
 		}
 		spin_lock_irqsave(q->queue_lock, flags);
-		floppy_end_request(req, 0);
+		floppy_end_request(req, -EIO);
 		spin_unlock_irqrestore(q->queue_lock, flags);
 	}
 }
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index b4c0888aedc3..ae3106045ee5 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -100,17 +100,15 @@ static const char *nbdcmd_to_ascii(int cmd)
 
 static void nbd_end_request(struct request *req)
 {
-	int uptodate = (req->errors == 0) ? 1 : 0;
+	int error = req->errors ? -EIO : 0;
 	struct request_queue *q = req->q;
 	unsigned long flags;
 
 	dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name,
-			req, uptodate? "done": "failed");
+			req, error ? "failed" : "done");
 
 	spin_lock_irqsave(q->queue_lock, flags);
-	if (!end_that_request_first(req, uptodate, req->nr_sectors)) {
-		end_that_request_last(req, uptodate);
-	}
+	__blk_end_request(req, error, req->nr_sectors << 9);
 	spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
@@ -375,14 +373,17 @@ harderror:
 	return NULL;
 }
 
-static ssize_t pid_show(struct gendisk *disk, char *page)
+static ssize_t pid_show(struct device *dev,
+			struct device_attribute *attr, char *buf)
 {
-	return sprintf(page, "%ld\n",
+	struct gendisk *disk = dev_to_disk(dev);
+
+	return sprintf(buf, "%ld\n",
 		(long) ((struct nbd_device *)disk->private_data)->pid);
 }
 
-static struct disk_attribute pid_attr = {
-	.attr = { .name = "pid", .mode = S_IRUGO },
+static struct device_attribute pid_attr = {
+	.attr = { .name = "pid", .mode = S_IRUGO, .owner = THIS_MODULE },
 	.show = pid_show,
 };
 
@@ -394,7 +395,7 @@ static int nbd_do_it(struct nbd_device *lo)
 	BUG_ON(lo->magic != LO_MAGIC);
 
 	lo->pid = current->pid;
-	ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
+	ret = sysfs_create_file(&lo->disk->dev.kobj, &pid_attr.attr);
 	if (ret) {
 		printk(KERN_ERR "nbd: sysfs_create_file failed!");
 		return ret;
@@ -403,7 +404,7 @@ static int nbd_do_it(struct nbd_device *lo)
 	while ((req = nbd_read_stat(lo)) != NULL)
 		nbd_end_request(req);
 
-	sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr);
+	sysfs_remove_file(&lo->disk->dev.kobj, &pid_attr.attr);
 	return 0;
 }
 
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index d89e7d32a3b6..ab86e23ddc69 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -676,8 +676,8 @@ static int __init pg_init(void)
 	for (unit = 0; unit < PG_UNITS; unit++) {
 		struct pg *dev = &devices[unit];
 		if (dev->present)
-			class_device_create(pg_class, NULL, MKDEV(major, unit),
-					NULL, "pg%u", unit);
+			device_create(pg_class, NULL, MKDEV(major, unit),
+				      "pg%u", unit);
 	}
 	err = 0;
 	goto out;
@@ -695,7 +695,7 @@ static void __exit pg_exit(void)
 	for (unit = 0; unit < PG_UNITS; unit++) {
 		struct pg *dev = &devices[unit];
 		if (dev->present)
-			class_device_destroy(pg_class, MKDEV(major, unit));
+			device_destroy(pg_class, MKDEV(major, unit));
 	}
 	class_destroy(pg_class);
 	unregister_chrdev(major, name);
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index b91accf12656..76096cad798f 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -972,10 +972,10 @@ static int __init pt_init(void)
 
 	for (unit = 0; unit < PT_UNITS; unit++)
 		if (pt[unit].present) {
-			class_device_create(pt_class, NULL, MKDEV(major, unit),
-					NULL, "pt%d", unit);
-			class_device_create(pt_class, NULL, MKDEV(major, unit + 128),
-					NULL, "pt%dn", unit);
+			device_create(pt_class, NULL, MKDEV(major, unit),
+				      "pt%d", unit);
+			device_create(pt_class, NULL, MKDEV(major, unit + 128),
+				      "pt%dn", unit);
 		}
 	goto out;
 
@@ -990,8 +990,8 @@ static void __exit pt_exit(void)
 	int unit;
 	for (unit = 0; unit < PT_UNITS; unit++)
 		if (pt[unit].present) {
-			class_device_destroy(pt_class, MKDEV(major, unit));
-			class_device_destroy(pt_class, MKDEV(major, unit + 128));
+			device_destroy(pt_class, MKDEV(major, unit));
+			device_destroy(pt_class, MKDEV(major, unit + 128));
 		}
 	class_destroy(pt_class);
 	unregister_chrdev(major, name);
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 3535ef896677..e9de1712e5a0 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -110,17 +110,18 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
 					struct kobj_type* ktype)
 {
 	struct pktcdvd_kobj *p;
+	int error;
+
 	p = kzalloc(sizeof(*p), GFP_KERNEL);
 	if (!p)
 		return NULL;
-	kobject_set_name(&p->kobj, "%s", name);
-	p->kobj.parent = parent;
-	p->kobj.ktype = ktype;
 	p->pd = pd;
-	if (kobject_register(&p->kobj) != 0) {
+	error = kobject_init_and_add(&p->kobj, ktype, parent, "%s", name);
+	if (error) {
 		kobject_put(&p->kobj);
 		return NULL;
 	}
+	kobject_uevent(&p->kobj, KOBJ_ADD);
 	return p;
 }
 /*
@@ -129,7 +130,7 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd,
 static void pkt_kobj_remove(struct pktcdvd_kobj *p)
 {
 	if (p)
-		kobject_unregister(&p->kobj);
+		kobject_put(&p->kobj);
 }
 /*
  * default release function for pktcdvd kernel objects.
@@ -301,18 +302,16 @@ static struct kobj_type kobj_pkt_type_wqueue = {
 static void pkt_sysfs_dev_new(struct pktcdvd_device *pd)
 {
 	if (class_pktcdvd) {
-		pd->clsdev = class_device_create(class_pktcdvd,
-					NULL, pd->pkt_dev,
-					NULL, "%s", pd->name);
-		if (IS_ERR(pd->clsdev))
-			pd->clsdev = NULL;
+		pd->dev = device_create(class_pktcdvd, NULL, pd->pkt_dev, "%s", pd->name);
+		if (IS_ERR(pd->dev))
+			pd->dev = NULL;
 	}
-	if (pd->clsdev) {
+	if (pd->dev) {
 		pd->kobj_stat = pkt_kobj_create(pd, "stat",
-					&pd->clsdev->kobj,
+					&pd->dev->kobj,
 					&kobj_pkt_type_stat);
 		pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue",
-					&pd->clsdev->kobj,
+					&pd->dev->kobj,
 					&kobj_pkt_type_wqueue);
 	}
 }
@@ -322,7 +321,7 @@ static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd)
 	pkt_kobj_remove(pd->kobj_stat);
 	pkt_kobj_remove(pd->kobj_wqueue);
 	if (class_pktcdvd)
-		class_device_destroy(class_pktcdvd, pd->pkt_dev);
+		device_destroy(class_pktcdvd, pd->pkt_dev);
 }
 
 
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index e354bfc070e1..7483f947f0e9 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -229,7 +229,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
 	struct ps3_storage_device *dev = data;
 	struct ps3disk_private *priv;
 	struct request *req;
-	int res, read, uptodate;
+	int res, read, error;
 	u64 tag, status;
 	unsigned long num_sectors;
 	const char *op;
@@ -270,21 +270,17 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
 	if (status) {
 		dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
 			__LINE__, op, status);
-		uptodate = 0;
+		error = -EIO;
 	} else {
 		dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__,
 			__LINE__, op);
-		uptodate = 1;
+		error = 0;
 		if (read)
 			ps3disk_scatter_gather(dev, req, 0);
 	}
 
 	spin_lock(&priv->lock);
-	if (!end_that_request_first(req, uptodate, num_sectors)) {
-		add_disk_randomness(req->rq_disk);
-		blkdev_dequeue_request(req);
-		end_that_request_last(req, uptodate);
-	}
+	__blk_end_request(req, error, num_sectors << 9);
 	priv->req = NULL;
 	ps3disk_do_request(dev, priv->queue);
 	spin_unlock(&priv->lock);
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index fac4c6cd04f7..66e30155b0ab 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -212,12 +212,9 @@ static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc)
 	vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD);
 }
 
-static void vdc_end_request(struct request *req, int uptodate, int num_sectors)
+static void vdc_end_request(struct request *req, int error, int num_sectors)
 {
-	if (end_that_request_first(req, uptodate, num_sectors))
-		return;
-	add_disk_randomness(req->rq_disk);
-	end_that_request_last(req, uptodate);
+	__blk_end_request(req, error, num_sectors << 9);
 }
 
 static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
@@ -242,7 +239,7 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
 
 	rqe->req = NULL;
 
-	vdc_end_request(req, !desc->status, desc->size >> 9);
+	vdc_end_request(req, (desc->status ? -EIO : 0), desc->size >> 9);
 
 	if (blk_queue_stopped(port->disk->queue))
 		blk_start_queue(port->disk->queue);
@@ -456,7 +453,7 @@ static void do_vdc_request(struct request_queue *q)
 
 		blkdev_dequeue_request(req);
 		if (__send_request(req) < 0)
-			vdc_end_request(req, 0, req->hard_nr_sectors);
+			vdc_end_request(req, -EIO, req->hard_nr_sectors);
 	}
 }
 
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 52dc5e131718..cd5674b63faf 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -744,16 +744,14 @@ static unsigned int carm_fill_get_fw_ver(struct carm_host *host,
 
 static inline void carm_end_request_queued(struct carm_host *host,
 					   struct carm_request *crq,
-					   int uptodate)
+					   int error)
 {
 	struct request *req = crq->rq;
 	int rc;
 
-	rc = end_that_request_first(req, uptodate, req->hard_nr_sectors);
+	rc = __blk_end_request(req, error, blk_rq_bytes(req));
 	assert(rc == 0);
 
-	end_that_request_last(req, uptodate);
-
 	rc = carm_put_request(host, crq);
 	assert(rc == 0);
 }
@@ -793,9 +791,9 @@ static inline void carm_round_robin(struct carm_host *host)
 }
 
 static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq,
-			int is_ok)
+			       int error)
 {
-	carm_end_request_queued(host, crq, is_ok);
+	carm_end_request_queued(host, crq, error);
 	if (max_queue == 1)
 		carm_round_robin(host);
 	else if ((host->n_msgs <= CARM_MSG_LOW_WATER) &&
@@ -873,14 +871,14 @@ queue_one_request:
 	sg = &crq->sg[0];
 	n_elem = blk_rq_map_sg(q, rq, sg);
 	if (n_elem <= 0) {
-		carm_end_rq(host, crq, 0);
+		carm_end_rq(host, crq, -EIO);
 		return;		/* request with no s/g entries? */
 	}
 
 	/* map scatterlist to PCI bus addresses */
 	n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir);
 	if (n_elem <= 0) {
-		carm_end_rq(host, crq, 0);
+		carm_end_rq(host, crq, -EIO);
 		return;		/* request with no s/g entries? */
 	}
 	crq->n_elem = n_elem;
@@ -941,7 +939,7 @@ queue_one_request:
 
 static void carm_handle_array_info(struct carm_host *host,
 				   struct carm_request *crq, u8 *mem,
-				   int is_ok)
+				   int error)
 {
 	struct carm_port *port;
 	u8 *msg_data = mem + sizeof(struct carm_array_info);
@@ -952,9 +950,9 @@ static void carm_handle_array_info(struct carm_host *host,
 
 	DPRINTK("ENTER\n");
 
-	carm_end_rq(host, crq, is_ok);
+	carm_end_rq(host, crq, error);
 
-	if (!is_ok)
+	if (error)
 		goto out;
 	if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST)
 		goto out;
@@ -1001,7 +999,7 @@ out:
 
 static void carm_handle_scan_chan(struct carm_host *host,
 				  struct carm_request *crq, u8 *mem,
-				  int is_ok)
+				  int error)
 {
 	u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET;
 	unsigned int i, dev_count = 0;
@@ -1009,9 +1007,9 @@ static void carm_handle_scan_chan(struct carm_host *host,
 
 	DPRINTK("ENTER\n");
 
-	carm_end_rq(host, crq, is_ok);
+	carm_end_rq(host, crq, error);
 
-	if (!is_ok) {
+	if (error) {
 		new_state = HST_ERROR;
 		goto out;
 	}
@@ -1033,23 +1031,23 @@ out:
 }
 
 static void carm_handle_generic(struct carm_host *host,
-				struct carm_request *crq, int is_ok,
+				struct carm_request *crq, int error,
 				int cur_state, int next_state)
 {
 	DPRINTK("ENTER\n");
 
-	carm_end_rq(host, crq, is_ok);
+	carm_end_rq(host, crq, error);
 
 	assert(host->state == cur_state);
-	if (is_ok)
-		host->state = next_state;
-	else
+	if (error)
 		host->state = HST_ERROR;
+	else
+		host->state = next_state;
 	schedule_work(&host->fsm_task);
 }
 
 static inline void carm_handle_rw(struct carm_host *host,
-				  struct carm_request *crq, int is_ok)
+				  struct carm_request *crq, int error)
 {
 	int pci_dir;
 
@@ -1062,7 +1060,7 @@ static inline void carm_handle_rw(struct carm_host *host,
 
 	pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir);
 
-	carm_end_rq(host, crq, is_ok);
+	carm_end_rq(host, crq, error);
 }
 
 static inline void carm_handle_resp(struct carm_host *host,
@@ -1071,7 +1069,7 @@ static inline void carm_handle_resp(struct carm_host *host,
 	u32 handle = le32_to_cpu(ret_handle_le);
 	unsigned int msg_idx;
 	struct carm_request *crq;
-	int is_ok = (status == RMSG_OK);
+	int error = (status == RMSG_OK) ? 0 : -EIO;
 	u8 *mem;
 
 	VPRINTK("ENTER, handle == 0x%x\n", handle);
@@ -1090,7 +1088,7 @@ static inline void carm_handle_resp(struct carm_host *host,
 	/* fast path */
 	if (likely(crq->msg_type == CARM_MSG_READ ||
 		   crq->msg_type == CARM_MSG_WRITE)) {
-		carm_handle_rw(host, crq, is_ok);
+		carm_handle_rw(host, crq, error);
 		return;
 	}
 
@@ -1100,7 +1098,7 @@ static inline void carm_handle_resp(struct carm_host *host,
 	case CARM_MSG_IOCTL: {
 		switch (crq->msg_subtype) {
 		case CARM_IOC_SCAN_CHAN:
-			carm_handle_scan_chan(host, crq, mem, is_ok);
+			carm_handle_scan_chan(host, crq, mem, error);
 			break;
 		default:
 			/* unknown / invalid response */
@@ -1112,21 +1110,21 @@ static inline void carm_handle_resp(struct carm_host *host,
 	case CARM_MSG_MISC: {
 		switch (crq->msg_subtype) {
 		case MISC_ALLOC_MEM:
-			carm_handle_generic(host, crq, is_ok,
+			carm_handle_generic(host, crq, error,
 					    HST_ALLOC_BUF, HST_SYNC_TIME);
 			break;
 		case MISC_SET_TIME:
-			carm_handle_generic(host, crq, is_ok,
+			carm_handle_generic(host, crq, error,
 					    HST_SYNC_TIME, HST_GET_FW_VER);
 			break;
 		case MISC_GET_FW_VER: {
 			struct carm_fw_ver *ver = (struct carm_fw_ver *)
 				mem + sizeof(struct carm_msg_get_fw_ver);
-			if (is_ok) {
+			if (!error) {
 				host->fw_ver = le32_to_cpu(ver->version);
 				host->flags |= (ver->features & FL_FW_VER_MASK);
 			}
-			carm_handle_generic(host, crq, is_ok,
+			carm_handle_generic(host, crq, error,
 					    HST_GET_FW_VER, HST_PORT_SCAN);
 			break;
 		}
@@ -1140,7 +1138,7 @@ static inline void carm_handle_resp(struct carm_host *host,
 	case CARM_MSG_ARRAY: {
 		switch (crq->msg_subtype) {
 		case CARM_ARRAY_INFO:
-			carm_handle_array_info(host, crq, mem, is_ok);
+			carm_handle_array_info(host, crq, mem, error);
 			break;
 		default:
 			/* unknown / invalid response */
@@ -1159,7 +1157,7 @@ static inline void carm_handle_resp(struct carm_host *host,
 err_out:
 	printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n",
 	       pci_name(host->pdev), crq->msg_type, crq->msg_subtype);
-	carm_end_rq(host, crq, 0);
+	carm_end_rq(host, crq, -EIO);
 }
 
 static inline void carm_handle_responses(struct carm_host *host)
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 08e909dc7944..c6179d6ac6e4 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -808,16 +808,16 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 
 static void ub_end_rq(struct request *rq, unsigned int scsi_status)
 {
-	int uptodate;
+	int error;
 
 	if (scsi_status == 0) {
-		uptodate = 1;
+		error = 0;
 	} else {
-		uptodate = 0;
+		error = -EIO;
 		rq->errors = scsi_status;
 	}
-	end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
-	end_that_request_last(rq, uptodate);
+	if (__blk_end_request(rq, error, blk_rq_bytes(rq)))
+		BUG();
 }
 
 static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index ab5d404faa11..9e61fca46117 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -229,13 +229,10 @@ static struct block_device_operations viodasd_fops = {
 /*
  * End a request
  */
-static void viodasd_end_request(struct request *req, int uptodate,
+static void viodasd_end_request(struct request *req, int error,
 		int num_sectors)
 {
-	if (end_that_request_first(req, uptodate, num_sectors))
-		return;
-	add_disk_randomness(req->rq_disk);
-	end_that_request_last(req, uptodate);
+	__blk_end_request(req, error, num_sectors << 9);
 }
 
 /*
@@ -374,12 +371,12 @@ static void do_viodasd_request(struct request_queue *q)
 		blkdev_dequeue_request(req);
 		/* check that request contains a valid command */
 		if (!blk_fs_request(req)) {
-			viodasd_end_request(req, 0, req->hard_nr_sectors);
+			viodasd_end_request(req, -EIO, req->hard_nr_sectors);
 			continue;
 		}
 		/* Try sending the request */
 		if (send_request(req) != 0)
-			viodasd_end_request(req, 0, req->hard_nr_sectors);
+			viodasd_end_request(req, -EIO, req->hard_nr_sectors);
 	}
 }
 
@@ -591,7 +588,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
 	num_req_outstanding--;
 	spin_unlock_irqrestore(&viodasd_spinlock, irq_flags);
 
-	error = event->xRc != HvLpEvent_Rc_Good;
+	error = (event->xRc == HvLpEvent_Rc_Good) ? 0 : -EIO;
 	if (error) {
 		const struct vio_error_entry *err;
 		err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
@@ -601,7 +598,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
 	}
 	qlock = req->q->queue_lock;
 	spin_lock_irqsave(qlock, irq_flags);
-	viodasd_end_request(req, !error, num_sect);
+	viodasd_end_request(req, error, num_sect);
 	spin_unlock_irqrestore(qlock, irq_flags);
 
 	/* Finally, try to get more requests off of this device's queue */
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 2bdebcb3ff16..8afce67c0aa5 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -452,7 +452,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 	RING_IDX i, rp;
 	unsigned long flags;
 	struct blkfront_info *info = (struct blkfront_info *)dev_id;
-	int uptodate;
+	int error;
 
 	spin_lock_irqsave(&blkif_io_lock, flags);
 
@@ -477,13 +477,13 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 
 		add_id_to_freelist(info, id);
 
-		uptodate = (bret->status == BLKIF_RSP_OKAY);
+		error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
 		switch (bret->operation) {
 		case BLKIF_OP_WRITE_BARRIER:
 			if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
 				printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
 				       info->gd->disk_name);
-				uptodate = -EOPNOTSUPP;
+				error = -EOPNOTSUPP;
 				info->feature_barrier = 0;
 				xlvbd_barrier(info);
 			}
@@ -494,10 +494,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 				dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
 					"request: %x\n", bret->status);
 
-			ret = end_that_request_first(req, uptodate,
-				req->hard_nr_sectors);
+			ret = __blk_end_request(req, error, blk_rq_bytes(req));
 			BUG_ON(ret);
-			end_that_request_last(req, uptodate);
 			break;
 		default:
 			BUG();
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 82effce97c51..78ebfffc77e3 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -483,7 +483,6 @@ static void ace_fsm_dostate(struct ace_device *ace)
 	u32 status;
 	u16 val;
 	int count;
-	int i;
 
 #if defined(DEBUG)
 	dev_dbg(ace->dev, "fsm_state=%i, id_req_count=%i\n",
@@ -688,7 +687,6 @@ static void ace_fsm_dostate(struct ace_device *ace)
 		}
 
 		/* Transfer the next buffer */
-		i = 16;
 		if (ace->fsm_task == ACE_TASK_WRITE)
 			ace->reg_ops->dataout(ace);
 		else
@@ -702,8 +700,8 @@ static void ace_fsm_dostate(struct ace_device *ace)
 		}
 
 		/* bio finished; is there another one? */
-		i = ace->req->current_nr_sectors;
-		if (end_that_request_first(ace->req, 1, i)) {
+		if (__blk_end_request(ace->req, 0,
+					blk_rq_cur_bytes(ace->req))) {
 			/* dev_dbg(ace->dev, "next block; h=%li c=%i\n",
 			 *      ace->req->hard_nr_sectors,
 			 *      ace->req->current_nr_sectors);
@@ -718,9 +716,6 @@ static void ace_fsm_dostate(struct ace_device *ace)
 		break;
 
 	case ACE_FSM_STATE_REQ_COMPLETE:
-		/* Complete the block request */
-		blkdev_dequeue_request(ace->req);
-		end_that_request_last(ace->req, 1);
 		ace->req = NULL;
 
 		/* Finished request; go to idle state */
diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile
index 774c180a4e11..ecf85fda0fc1 100644
--- a/drivers/cdrom/Makefile
+++ b/drivers/cdrom/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_PARIDE_PCD)	+=		cdrom.o
 obj-$(CONFIG_CDROM_PKTCDVD)	+=		cdrom.o
 
 obj-$(CONFIG_VIOCD)		+= viocd.o      cdrom.o
+obj-$(CONFIG_GDROM)		+= gdrom.o      cdrom.o
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
new file mode 100644
index 000000000000..4e2bbcccc064
--- /dev/null
+++ b/drivers/cdrom/gdrom.c
@@ -0,0 +1,867 @@
+/* GD ROM driver for the SEGA Dreamcast
+ * copyright Adrian McMenamin, 2007
+ * With thanks to Marcus Comstedt and Nathan Keynes
+ * for work in reversing PIO and DMA
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/cdrom.h>
+#include <linux/genhd.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <scsi/scsi.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/delay.h>
+#include <asm/mach/dma.h>
+#include <asm/mach/sysasic.h>
+
+#define GDROM_DEV_NAME "gdrom"
+#define GD_SESSION_OFFSET 150
+
+/* GD Rom commands */
+#define GDROM_COM_SOFTRESET 0x08
+#define GDROM_COM_EXECDIAG 0x90
+#define GDROM_COM_PACKET 0xA0
+#define GDROM_COM_IDDEV 0xA1
+
+/* GD Rom registers */
+#define GDROM_BASE_REG			0xA05F7000
+#define GDROM_ALTSTATUS_REG		(GDROM_BASE_REG + 0x18)
+#define GDROM_DATA_REG			(GDROM_BASE_REG + 0x80)
+#define GDROM_ERROR_REG		(GDROM_BASE_REG + 0x84)
+#define GDROM_INTSEC_REG		(GDROM_BASE_REG + 0x88)
+#define GDROM_SECNUM_REG		(GDROM_BASE_REG + 0x8C)
+#define GDROM_BCL_REG			(GDROM_BASE_REG + 0x90)
+#define GDROM_BCH_REG			(GDROM_BASE_REG + 0x94)
+#define GDROM_DSEL_REG			(GDROM_BASE_REG + 0x98)
+#define GDROM_STATUSCOMMAND_REG	(GDROM_BASE_REG + 0x9C)
+#define GDROM_RESET_REG		(GDROM_BASE_REG + 0x4E4)
+
+#define GDROM_DMA_STARTADDR_REG	(GDROM_BASE_REG + 0x404)
+#define GDROM_DMA_LENGTH_REG		(GDROM_BASE_REG + 0x408)
+#define GDROM_DMA_DIRECTION_REG	(GDROM_BASE_REG + 0x40C)
+#define GDROM_DMA_ENABLE_REG		(GDROM_BASE_REG + 0x414)
+#define GDROM_DMA_STATUS_REG		(GDROM_BASE_REG + 0x418)
+#define GDROM_DMA_WAIT_REG		(GDROM_BASE_REG + 0x4A0)
+#define GDROM_DMA_ACCESS_CTRL_REG	(GDROM_BASE_REG + 0x4B8)
+
+#define GDROM_HARD_SECTOR	2048
+#define BLOCK_LAYER_SECTOR	512
+#define GD_TO_BLK		4
+
+#define GDROM_DEFAULT_TIMEOUT	(HZ * 7)
+
+static const struct {
+	int sense_key;
+	const char * const text;
+} sense_texts[] = {
+	{NO_SENSE, "OK"},
+	{RECOVERED_ERROR, "Recovered from error"},
+	{NOT_READY, "Device not ready"},
+	{MEDIUM_ERROR, "Disk not ready"},
+	{HARDWARE_ERROR, "Hardware error"},
+	{ILLEGAL_REQUEST, "Command has failed"},
+	{UNIT_ATTENTION, "Device needs attention - disk may have been changed"},
+	{DATA_PROTECT, "Data protection error"},
+	{ABORTED_COMMAND, "Command aborted"},
+};
+
+static struct platform_device *pd;
+static int gdrom_major;
+static DECLARE_WAIT_QUEUE_HEAD(command_queue);
+static DECLARE_WAIT_QUEUE_HEAD(request_queue);
+
+static DEFINE_SPINLOCK(gdrom_lock);
+static void gdrom_readdisk_dma(struct work_struct *work);
+static DECLARE_WORK(work, gdrom_readdisk_dma);
+static LIST_HEAD(gdrom_deferred);
+
+struct gdromtoc {
+	unsigned int entry[99];
+	unsigned int first, last;
+	unsigned int leadout;
+};
+
+static struct gdrom_unit {
+	struct gendisk *disk;
+	struct cdrom_device_info *cd_info;
+	int status;
+	int pending;
+	int transfer;
+	char disk_type;
+	struct gdromtoc *toc;
+	struct request_queue *gdrom_rq;
+} gd;
+
+struct gdrom_id {
+	char mid;
+	char modid;
+	char verid;
+	char padA[13];
+	char mname[16];
+	char modname[16];
+	char firmver[16];
+	char padB[16];
+};
+
+static int gdrom_getsense(short *bufstring);
+static int gdrom_packetcommand(struct cdrom_device_info *cd_info,
+	struct packet_command *command);
+static int gdrom_hardreset(struct cdrom_device_info *cd_info);
+
+static bool gdrom_is_busy(void)
+{
+	return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) != 0;
+}
+
+static bool gdrom_data_request(void)
+{
+	return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) == 8;
+}
+
+static bool gdrom_wait_clrbusy(void)
+{
+	unsigned long timeout = jiffies + GDROM_DEFAULT_TIMEOUT;
+	while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) &&
+		(time_before(jiffies, timeout)))
+		cpu_relax();
+	return time_before(jiffies, timeout + 1);
+}
+
+static bool gdrom_wait_busy_sleeps(void)
+{
+	unsigned long timeout;
+	/* Wait to get busy first */
+	timeout = jiffies + GDROM_DEFAULT_TIMEOUT;
+	while (!gdrom_is_busy() && time_before(jiffies, timeout))
+		cpu_relax();
+	/* Now wait for busy to clear */
+	return gdrom_wait_clrbusy();
+}
+
+static void gdrom_identifydevice(void *buf)
+{
+	int c;
+	short *data = buf;
+	/* If the device won't clear it has probably
+	* been hit by a serious failure - but we'll
+	* try to return a sense key even so */
+	if (!gdrom_wait_clrbusy()) {
+		gdrom_getsense(NULL);
+		return;
+	}
+	ctrl_outb(GDROM_COM_IDDEV, GDROM_STATUSCOMMAND_REG);
+	if (!gdrom_wait_busy_sleeps()) {
+		gdrom_getsense(NULL);
+		return;
+	}
+	/* now read in the data */
+	for (c = 0; c < 40; c++)
+		data[c] = ctrl_inw(GDROM_DATA_REG);
+}
+
+static void gdrom_spicommand(void *spi_string, int buflen)
+{
+	short *cmd = spi_string;
+	unsigned long timeout;
+
+	/* ensure IRQ_WAIT is set */
+	ctrl_outb(0x08, GDROM_ALTSTATUS_REG);
+	/* specify how many bytes we expect back */
+	ctrl_outb(buflen & 0xFF, GDROM_BCL_REG);
+	ctrl_outb((buflen >> 8) & 0xFF, GDROM_BCH_REG);
+	/* other parameters */
+	ctrl_outb(0, GDROM_INTSEC_REG);
+	ctrl_outb(0, GDROM_SECNUM_REG);
+	ctrl_outb(0, GDROM_ERROR_REG);
+	/* Wait until we can go */
+	if (!gdrom_wait_clrbusy()) {
+		gdrom_getsense(NULL);
+		return;
+	}
+	timeout = jiffies + GDROM_DEFAULT_TIMEOUT;
+	ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+	while (!gdrom_data_request() && time_before(jiffies, timeout))
+		cpu_relax();
+	if (!time_before(jiffies, timeout + 1)) {
+		gdrom_getsense(NULL);
+		return;
+	}
+	outsw(PHYSADDR(GDROM_DATA_REG), cmd, 6);
+}
+
+
+/* gdrom_command_executediagnostic:
+ * Used to probe for presence of working GDROM
+ * Restarts GDROM device and then applies standard ATA 3
+ * Execute Diagnostic Command: a return of '1' indicates device 0
+ * present and device 1 absent
+ */
+static char gdrom_execute_diagnostic(void)
+{
+	gdrom_hardreset(gd.cd_info);
+	if (!gdrom_wait_clrbusy())
+		return 0;
+	ctrl_outb(GDROM_COM_EXECDIAG, GDROM_STATUSCOMMAND_REG);
+	if (!gdrom_wait_busy_sleeps())
+		return 0;
+	return ctrl_inb(GDROM_ERROR_REG);
+}
+
+/*
+ * Prepare disk command
+ * byte 0 = 0x70
+ * byte 1 = 0x1f
+ */
+static int gdrom_preparedisk_cmd(void)
+{
+	struct packet_command *spin_command;
+	spin_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+	if (!spin_command)
+		return -ENOMEM;
+	spin_command->cmd[0] = 0x70;
+	spin_command->cmd[2] = 0x1f;
+	spin_command->buflen = 0;
+	gd.pending = 1;
+	gdrom_packetcommand(gd.cd_info, spin_command);
+	/* 60 second timeout */
+	wait_event_interruptible_timeout(command_queue, gd.pending == 0,
+		GDROM_DEFAULT_TIMEOUT);
+	gd.pending = 0;
+	kfree(spin_command);
+	if (gd.status & 0x01) {
+		/* log an error */
+		gdrom_getsense(NULL);
+		return -EIO;
+	}
+	return 0;
+}
+
+/*
+ * Read TOC command
+ * byte 0 = 0x14
+ * byte 1 = session
+ * byte 3 = sizeof TOC >> 8  ie upper byte
+ * byte 4 = sizeof TOC & 0xff ie lower byte
+ */
+static int gdrom_readtoc_cmd(struct gdromtoc *toc, int session)
+{
+	int tocsize;
+	struct packet_command *toc_command;
+	int err = 0;
+
+	toc_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+	if (!toc_command)
+		return -ENOMEM;
+	tocsize = sizeof(struct gdromtoc);
+	toc_command->cmd[0] = 0x14;
+	toc_command->cmd[1] = session;
+	toc_command->cmd[3] = tocsize >> 8;
+	toc_command->cmd[4] = tocsize & 0xff;
+	toc_command->buflen = tocsize;
+	if (gd.pending) {
+		err = -EBUSY;
+		goto cleanup_readtoc_final;
+	}
+	gd.pending = 1;
+	gdrom_packetcommand(gd.cd_info, toc_command);
+	wait_event_interruptible_timeout(command_queue, gd.pending == 0,
+		GDROM_DEFAULT_TIMEOUT);
+	if (gd.pending) {
+		err = -EINVAL;
+		goto cleanup_readtoc;
+	}
+	insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2);
+	if (gd.status & 0x01)
+		err = -EINVAL;
+
+cleanup_readtoc:
+	gd.pending = 0;
+cleanup_readtoc_final:
+	kfree(toc_command);
+	return err;
+}
+
+/* TOC helpers */
+static int get_entry_lba(int track)
+{
+	return (cpu_to_be32(track & 0xffffff00) - GD_SESSION_OFFSET);
+}
+
+static int get_entry_q_ctrl(int track)
+{
+	return (track & 0x000000f0) >> 4;
+}
+
+static int get_entry_track(int track)
+{
+	return (track & 0x0000ff00) >> 8;
+}
+
+static int gdrom_get_last_session(struct cdrom_device_info *cd_info,
+	struct cdrom_multisession *ms_info)
+{
+	int fentry, lentry, track, data, tocuse, err;
+	if (!gd.toc)
+		return -ENOMEM;
+	tocuse = 1;
+	/* Check if GD-ROM */
+	err = gdrom_readtoc_cmd(gd.toc, 1);
+	/* Not a GD-ROM so check if standard CD-ROM */
+	if (err) {
+		tocuse = 0;
+		err = gdrom_readtoc_cmd(gd.toc, 0);
+		if (err) {
+			printk(KERN_INFO "GDROM: Could not get CD "
+				"table of contents\n");
+			return -ENXIO;
+		}
+	}
+
+	fentry = get_entry_track(gd.toc->first);
+	lentry = get_entry_track(gd.toc->last);
+	/* Find the first data track */
+	track = get_entry_track(gd.toc->last);
+	do {
+		data = gd.toc->entry[track - 1];
+		if (get_entry_q_ctrl(data))
+			break;	/* ie a real data track */
+		track--;
+	} while (track >= fentry);
+
+	if ((track > 100) || (track < get_entry_track(gd.toc->first))) {
+		printk(KERN_INFO "GDROM: No data on the last "
+			"session of the CD\n");
+		gdrom_getsense(NULL);
+		return -ENXIO;
+	}
+
+	ms_info->addr_format = CDROM_LBA;
+	ms_info->addr.lba = get_entry_lba(data);
+	ms_info->xa_flag = 1;
+	return 0;
+}
+
+static int gdrom_open(struct cdrom_device_info *cd_info, int purpose)
+{
+	/* spin up the disk */
+	return gdrom_preparedisk_cmd();
+}
+
+/* this function is required even if empty */
+static void gdrom_release(struct cdrom_device_info *cd_info)
+{
+}
+
+static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)
+{
+	/* read the sense key */
+	char sense = ctrl_inb(GDROM_ERROR_REG);
+	sense &= 0xF0;
+	if (sense == 0)
+		return CDS_DISC_OK;
+	if (sense == 0x20)
+		return CDS_DRIVE_NOT_READY;
+	/* default */
+	return CDS_NO_INFO;
+}
+
+static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore)
+{
+	/* check the sense key */
+	return (ctrl_inb(GDROM_ERROR_REG) & 0xF0) == 0x60;
+}
+
+/* reset the G1 bus */
+static int gdrom_hardreset(struct cdrom_device_info *cd_info)
+{
+	int count;
+	ctrl_outl(0x1fffff, GDROM_RESET_REG);
+	for (count = 0xa0000000; count < 0xa0200000; count += 4)
+		ctrl_inl(count);
+	return 0;
+}
+
+/* keep the function looking like the universal
+ * CD Rom specification  - returning int */
+static int gdrom_packetcommand(struct cdrom_device_info *cd_info,
+	struct packet_command *command)
+{
+	gdrom_spicommand(&command->cmd, command->buflen);
+	return 0;
+}
+
+/* Get Sense SPI command
+ * From Marcus Comstedt
+ * cmd = 0x13
+ * cmd + 4 = length of returned buffer
+ * Returns 5 16 bit words
+ */
+static int gdrom_getsense(short *bufstring)
+{
+	struct packet_command *sense_command;
+	short sense[5];
+	int sense_key;
+	int err = -EIO;
+
+	sense_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+	if (!sense_command)
+		return -ENOMEM;
+	sense_command->cmd[0] = 0x13;
+	sense_command->cmd[4] = 10;
+	sense_command->buflen = 10;
+	/* even if something is pending try to get
+	* the sense key if possible */
+	if (gd.pending && !gdrom_wait_clrbusy()) {
+		err = -EBUSY;
+		goto cleanup_sense_final;
+	}
+	gd.pending = 1;
+	gdrom_packetcommand(gd.cd_info, sense_command);
+	wait_event_interruptible_timeout(command_queue, gd.pending == 0,
+		GDROM_DEFAULT_TIMEOUT);
+	if (gd.pending)
+		goto cleanup_sense;
+	insw(PHYSADDR(GDROM_DATA_REG), &sense, sense_command->buflen/2);
+	if (sense[1] & 40) {
+		printk(KERN_INFO "GDROM: Drive not ready - command aborted\n");
+		goto cleanup_sense;
+	}
+	sense_key = sense[1] & 0x0F;
+	if (sense_key < ARRAY_SIZE(sense_texts))
+		printk(KERN_INFO "GDROM: %s\n", sense_texts[sense_key].text);
+	else
+		printk(KERN_ERR "GDROM: Unknown sense key: %d\n", sense_key);
+	if (bufstring) /* return addional sense data */
+		memcpy(bufstring, &sense[4], 2);
+	if (sense_key < 2)
+		err = 0;
+
+cleanup_sense:
+	gd.pending = 0;
+cleanup_sense_final:
+	kfree(sense_command);
+	return err;
+}
+
+static struct cdrom_device_ops gdrom_ops = {
+	.open			= gdrom_open,
+	.release		= gdrom_release,
+	.drive_status		= gdrom_drivestatus,
+	.media_changed		= gdrom_mediachanged,
+	.get_last_session	= gdrom_get_last_session,
+	.reset			= gdrom_hardreset,
+	.capability		= CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
+				  CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R,
+	.n_minors		= 1,
+};
+
+static int gdrom_bdops_open(struct inode *inode, struct file *file)
+{
+	return cdrom_open(gd.cd_info, inode, file);
+}
+
+static int gdrom_bdops_release(struct inode *inode, struct file *file)
+{
+	return cdrom_release(gd.cd_info, file);
+}
+
+static int gdrom_bdops_mediachanged(struct gendisk *disk)
+{
+	return cdrom_media_changed(gd.cd_info);
+}
+
+static int gdrom_bdops_ioctl(struct inode *inode, struct file *file,
+	unsigned cmd, unsigned long arg)
+{
+	return cdrom_ioctl(file, gd.cd_info, inode, cmd, arg);
+}
+
+static struct block_device_operations gdrom_bdops = {
+	.owner			= THIS_MODULE,
+	.open			= gdrom_bdops_open,
+	.release		= gdrom_bdops_release,
+	.media_changed		= gdrom_bdops_mediachanged,
+	.ioctl			= gdrom_bdops_ioctl,
+};
+
+static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
+{
+	gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+	if (gd.pending != 1)
+		return IRQ_HANDLED;
+	gd.pending = 0;
+	wake_up_interruptible(&command_queue);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t gdrom_dma_interrupt(int irq, void *dev_id)
+{
+	gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+	if (gd.transfer != 1)
+		return IRQ_HANDLED;
+	gd.transfer = 0;
+	wake_up_interruptible(&request_queue);
+	return IRQ_HANDLED;
+}
+
+static int __devinit gdrom_set_interrupt_handlers(void)
+{
+	int err;
+
+	err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt,
+		IRQF_DISABLED, "gdrom_command", &gd);
+	if (err)
+		return err;
+	err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt,
+		IRQF_DISABLED, "gdrom_dma", &gd);
+	if (err)
+		free_irq(HW_EVENT_GDROM_CMD, &gd);
+	return err;
+}
+
+/* Implement DMA read using SPI command
+ * 0 -> 0x30
+ * 1 -> mode
+ * 2 -> block >> 16
+ * 3 -> block >> 8
+ * 4 -> block
+ * 8 -> sectors >> 16
+ * 9 -> sectors >> 8
+ * 10 -> sectors
+ */
+static void gdrom_readdisk_dma(struct work_struct *work)
+{
+	int err, block, block_cnt;
+	struct packet_command *read_command;
+	struct list_head *elem, *next;
+	struct request *req;
+	unsigned long timeout;
+
+	if (list_empty(&gdrom_deferred))
+		return;
+	read_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+	if (!read_command)
+		return; /* get more memory later? */
+	read_command->cmd[0] = 0x30;
+	read_command->cmd[1] = 0x20;
+	spin_lock(&gdrom_lock);
+	list_for_each_safe(elem, next, &gdrom_deferred) {
+		req = list_entry(elem, struct request, queuelist);
+		spin_unlock(&gdrom_lock);
+		block = req->sector/GD_TO_BLK + GD_SESSION_OFFSET;
+		block_cnt = req->nr_sectors/GD_TO_BLK;
+		ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG);
+		ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
+		ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
+		ctrl_outl(1, GDROM_DMA_ENABLE_REG);
+		read_command->cmd[2] = (block >> 16) & 0xFF;
+		read_command->cmd[3] = (block >> 8) & 0xFF;
+		read_command->cmd[4] = block & 0xFF;
+		read_command->cmd[8] = (block_cnt >> 16) & 0xFF;
+		read_command->cmd[9] = (block_cnt >> 8) & 0xFF;
+		read_command->cmd[10] = block_cnt & 0xFF;
+		/* set for DMA */
+		ctrl_outb(1, GDROM_ERROR_REG);
+		/* other registers */
+		ctrl_outb(0, GDROM_SECNUM_REG);
+		ctrl_outb(0, GDROM_BCL_REG);
+		ctrl_outb(0, GDROM_BCH_REG);
+		ctrl_outb(0, GDROM_DSEL_REG);
+		ctrl_outb(0, GDROM_INTSEC_REG);
+		/* Wait for registers to reset after any previous activity */
+		timeout = jiffies + HZ / 2;
+		while (gdrom_is_busy() && time_before(jiffies, timeout))
+			cpu_relax();
+		ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+		timeout = jiffies + HZ / 2;
+		/* Wait for packet command to finish */
+		while (gdrom_is_busy() && time_before(jiffies, timeout))
+			cpu_relax();
+		gd.pending = 1;
+		gd.transfer = 1;
+		outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
+		timeout = jiffies + HZ / 2;
+		/* Wait for any pending DMA to finish */
+		while (ctrl_inb(GDROM_DMA_STATUS_REG) &&
+			time_before(jiffies, timeout))
+			cpu_relax();
+		/* start transfer */
+		ctrl_outb(1, GDROM_DMA_STATUS_REG);
+		wait_event_interruptible_timeout(request_queue,
+			gd.transfer == 0, GDROM_DEFAULT_TIMEOUT);
+		err = gd.transfer;
+		gd.transfer = 0;
+		gd.pending = 0;
+		/* now seek to take the request spinlock
+		* before handling ending the request */
+		spin_lock(&gdrom_lock);
+		list_del_init(&req->queuelist);
+		end_dequeued_request(req, 1 - err);
+	}
+	spin_unlock(&gdrom_lock);
+	kfree(read_command);
+}
+
+static void gdrom_request_handler_dma(struct request *req)
+{
+	/* dequeue, add to list of deferred work
+	* and then schedule workqueue */
+	blkdev_dequeue_request(req);
+	list_add_tail(&req->queuelist, &gdrom_deferred);
+	schedule_work(&work);
+}
+
+static void gdrom_request(struct request_queue *rq)
+{
+	struct request *req;
+
+	while ((req = elv_next_request(rq)) != NULL) {
+		if (!blk_fs_request(req)) {
+			printk(KERN_DEBUG "GDROM: Non-fs request ignored\n");
+			end_request(req, 0);
+		}
+		if (rq_data_dir(req) != READ) {
+			printk(KERN_NOTICE "GDROM: Read only device -");
+			printk(" write request ignored\n");
+			end_request(req, 0);
+		}
+		if (req->nr_sectors)
+			gdrom_request_handler_dma(req);
+		else
+			end_request(req, 0);
+	}
+}
+
+/* Print string identifying GD ROM device */
+static int __devinit gdrom_outputversion(void)
+{
+	struct gdrom_id *id;
+	char *model_name, *manuf_name, *firmw_ver;
+	int err = -ENOMEM;
+
+	/* query device ID */
+	id = kzalloc(sizeof(struct gdrom_id), GFP_KERNEL);
+	if (!id)
+		return err;
+	gdrom_identifydevice(id);
+	model_name = kstrndup(id->modname, 16, GFP_KERNEL);
+	if (!model_name)
+		goto free_id;
+	manuf_name = kstrndup(id->mname, 16, GFP_KERNEL);
+	if (!manuf_name)
+		goto free_model_name;
+	firmw_ver = kstrndup(id->firmver, 16, GFP_KERNEL);
+	if (!firmw_ver)
+		goto free_manuf_name;
+	printk(KERN_INFO "GDROM: %s from %s with firmware %s\n",
+		model_name, manuf_name, firmw_ver);
+	err = 0;
+	kfree(firmw_ver);
+free_manuf_name:
+	kfree(manuf_name);
+free_model_name:
+	kfree(model_name);
+free_id:
+	kfree(id);
+	return err;
+}
+
+/* set the default mode for DMA transfer */
+static int __devinit gdrom_init_dma_mode(void)
+{
+	ctrl_outb(0x13, GDROM_ERROR_REG);
+	ctrl_outb(0x22, GDROM_INTSEC_REG);
+	if (!gdrom_wait_clrbusy())
+		return -EBUSY;
+	ctrl_outb(0xEF, GDROM_STATUSCOMMAND_REG);
+	if (!gdrom_wait_busy_sleeps())
+		return -EBUSY;
+	/* Memory protection setting for GDROM DMA
+	* Bits 31 - 16 security: 0x8843
+	* Bits 15 and 7 reserved (0)
+	* Bits 14 - 8 start of transfer range in 1 MB blocks OR'ed with 0x80
+	* Bits 6 - 0 end of transfer range in 1 MB blocks OR'ed with 0x80
+	* (0x40 | 0x80) = start range at 0x0C000000
+	* (0x7F | 0x80) = end range at 0x0FFFFFFF */
+	ctrl_outl(0x8843407F, GDROM_DMA_ACCESS_CTRL_REG);
+	ctrl_outl(9, GDROM_DMA_WAIT_REG); /* DMA word setting */
+	return 0;
+}
+
+static void __devinit probe_gdrom_setupcd(void)
+{
+	gd.cd_info->ops = &gdrom_ops;
+	gd.cd_info->capacity = 1;
+	strcpy(gd.cd_info->name, GDROM_DEV_NAME);
+	gd.cd_info->mask = CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|
+		CDC_SELECT_DISC;
+}
+
+static void __devinit probe_gdrom_setupdisk(void)
+{
+	gd.disk->major = gdrom_major;
+	gd.disk->first_minor = 1;
+	gd.disk->minors = 1;
+	strcpy(gd.disk->disk_name, GDROM_DEV_NAME);
+}
+
+static int __devinit probe_gdrom_setupqueue(void)
+{
+	blk_queue_hardsect_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
+	/* using DMA so memory will need to be contiguous */
+	blk_queue_max_hw_segments(gd.gdrom_rq, 1);
+	/* set a large max size to get most from DMA */
+	blk_queue_max_segment_size(gd.gdrom_rq, 0x40000);
+	gd.disk->queue = gd.gdrom_rq;
+	return gdrom_init_dma_mode();
+}
+
+/*
+ * register this as a block device and as compliant with the
+ * universal CD Rom driver interface
+ */
+static int __devinit probe_gdrom(struct platform_device *devptr)
+{
+	int err;
+	/* Start the device */
+	if (gdrom_execute_diagnostic() != 1) {
+		printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed.\n");
+		return -ENODEV;
+	}
+	/* Print out firmware ID */
+	if (gdrom_outputversion())
+		return -ENOMEM;
+	/* Register GDROM */
+	gdrom_major = register_blkdev(0, GDROM_DEV_NAME);
+	if (gdrom_major <= 0)
+		return gdrom_major;
+	printk(KERN_INFO "GDROM: Registered with major number %d\n",
+		gdrom_major);
+	/* Specify basic properties of drive */
+	gd.cd_info = kzalloc(sizeof(struct cdrom_device_info), GFP_KERNEL);
+	if (!gd.cd_info) {
+		err = -ENOMEM;
+		goto probe_fail_no_mem;
+	}
+	probe_gdrom_setupcd();
+	gd.disk = alloc_disk(1);
+	if (!gd.disk) {
+		err = -ENODEV;
+		goto probe_fail_no_disk;
+	}
+	probe_gdrom_setupdisk();
+	if (register_cdrom(gd.cd_info)) {
+		err = -ENODEV;
+		goto probe_fail_cdrom_register;
+	}
+	gd.disk->fops = &gdrom_bdops;
+	/* latch on to the interrupt */
+	err = gdrom_set_interrupt_handlers();
+	if (err)
+		goto probe_fail_cmdirq_register;
+	gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock);
+	if (!gd.gdrom_rq)
+		goto probe_fail_requestq;
+
+	err = probe_gdrom_setupqueue();
+	if (err)
+		goto probe_fail_toc;
+
+	gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL);
+	if (!gd.toc)
+		goto probe_fail_toc;
+	add_disk(gd.disk);
+	return 0;
+
+probe_fail_toc:
+	blk_cleanup_queue(gd.gdrom_rq);
+probe_fail_requestq:
+	free_irq(HW_EVENT_GDROM_DMA, &gd);
+	free_irq(HW_EVENT_GDROM_CMD, &gd);
+probe_fail_cmdirq_register:
+probe_fail_cdrom_register:
+	del_gendisk(gd.disk);
+probe_fail_no_disk:
+	kfree(gd.cd_info);
+	unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
+	gdrom_major = 0;
+probe_fail_no_mem:
+	printk(KERN_WARNING "GDROM: Probe failed - error is 0x%X\n", err);
+	return err;
+}
+
+static int __devexit remove_gdrom(struct platform_device *devptr)
+{
+	flush_scheduled_work();
+	blk_cleanup_queue(gd.gdrom_rq);
+	free_irq(HW_EVENT_GDROM_CMD, &gd);
+	free_irq(HW_EVENT_GDROM_DMA, &gd);
+	del_gendisk(gd.disk);
+	if (gdrom_major)
+		unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
+	return unregister_cdrom(gd.cd_info);
+}
+
+static struct platform_driver gdrom_driver = {
+	.probe = probe_gdrom,
+	.remove = __devexit_p(remove_gdrom),
+	.driver = {
+			.name = GDROM_DEV_NAME,
+	},
+};
+
+static int __init init_gdrom(void)
+{
+	int rc;
+	gd.toc = NULL;
+	rc = platform_driver_register(&gdrom_driver);
+	if (rc)
+		return rc;
+	pd = platform_device_register_simple(GDROM_DEV_NAME, -1, NULL, 0);
+	if (IS_ERR(pd)) {
+		platform_driver_unregister(&gdrom_driver);
+		return PTR_ERR(pd);
+	}
+	return 0;
+}
+
+static void __exit exit_gdrom(void)
+{
+	platform_device_unregister(pd);
+	platform_driver_unregister(&gdrom_driver);
+	kfree(gd.toc);
+}
+
+module_init(init_gdrom);
+module_exit(exit_gdrom);
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
+MODULE_DESCRIPTION("SEGA Dreamcast GD-ROM Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index d8bb44b98a6a..8473b9f1da96 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -289,7 +289,7 @@ static int send_request(struct request *req)
 	return 0;
 }
 
-static void viocd_end_request(struct request *req, int uptodate)
+static void viocd_end_request(struct request *req, int error)
 {
 	int nsectors = req->hard_nr_sectors;
 
@@ -302,11 +302,8 @@ static void viocd_end_request(struct request *req, int uptodate)
 	if (!nsectors)
 		nsectors = 1;
 
-	if (end_that_request_first(req, uptodate, nsectors))
+	if (__blk_end_request(req, error, nsectors << 9))
 		BUG();
-	add_disk_randomness(req->rq_disk);
-	blkdev_dequeue_request(req);
-	end_that_request_last(req, uptodate);
 }
 
 static int rwreq;
@@ -317,11 +314,11 @@ static void do_viocd_request(struct request_queue *q)
 
 	while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) {
 		if (!blk_fs_request(req))
-			viocd_end_request(req, 0);
+			viocd_end_request(req, -EIO);
 		else if (send_request(req) < 0) {
 			printk(VIOCD_KERN_WARNING
 					"unable to send message to OS/400!");
-			viocd_end_request(req, 0);
+			viocd_end_request(req, -EIO);
 		} else
 			rwreq++;
 	}
@@ -532,9 +529,9 @@ return_complete:
 					"with rc %d:0x%04X: %s\n",
 					req, event->xRc,
 					bevent->sub_result, err->msg);
-			viocd_end_request(req, 0);
+			viocd_end_request(req, -EIO);
 		} else
-			viocd_end_request(req, 1);
+			viocd_end_request(req, 0);
 
 		/* restart handling of incoming requests */
 		spin_unlock_irqrestore(&viocd_reqlock, flags);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 2e3a0d4bc4c2..466629594776 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -373,6 +373,16 @@ config ISTALLION
 	  To compile this driver as a module, choose M here: the
 	  module will be called istallion.
 
+config NOZOMI
+	tristate "HSDPA Broadband Wireless Data Card - Globe Trotter"
+	depends on PCI && EXPERIMENTAL
+	help
+	  If you have a HSDPA driver Broadband Wireless Data Card -
+	  Globe Trotter PCMCIA card, say Y here.
+
+	  To compile this driver as a module, choose M here, the module
+	  will be called nozomi.
+
 config A2232
 	tristate "Commodore A2232 serial support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 07304d50e0cb..96fc01eddefe 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_SERIAL167)		+= serial167.o
 obj-$(CONFIG_CYCLADES)		+= cyclades.o
 obj-$(CONFIG_STALLION)		+= stallion.o
 obj-$(CONFIG_ISTALLION)		+= istallion.o
+obj-$(CONFIG_NOZOMI)		+= nozomi.o
 obj-$(CONFIG_DIGIEPCA)		+= epca.o
 obj-$(CONFIG_SPECIALIX)		+= specialix.o
 obj-$(CONFIG_MOXA_INTELLIO)	+= moxa.o
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index aa5ddb716ffb..1ffb381130c3 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -145,7 +145,6 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge)
 	void *addr = agp_generic_alloc_page(agp_bridge);
 	u32 temp;
 
-	global_flush_tlb();
 	if (!addr)
 		return NULL;
 
@@ -162,7 +161,6 @@ static void ali_destroy_page(void * addr, int flags)
 		if (flags & AGP_PAGE_DESTROY_UNMAP) {
 			global_cache_flush();	/* is this really needed?  --hch */
 			agp_generic_destroy_page(addr, flags);
-			global_flush_tlb();
 		} else
 			agp_generic_destroy_page(addr, flags);
 	}
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 832ded20fe70..2720882e66fe 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -147,7 +147,6 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
 			printk(KERN_ERR PFX "unable to get memory for scratch page.\n");
 			return -ENOMEM;
 		}
-		flush_agp_mappings();
 
 		bridge->scratch_page_real = virt_to_gart(addr);
 		bridge->scratch_page =
@@ -191,7 +190,6 @@ err_out:
 	if (bridge->driver->needs_scratch_page) {
 		bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
 						 AGP_PAGE_DESTROY_UNMAP);
-		flush_agp_mappings();
 		bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
 						 AGP_PAGE_DESTROY_FREE);
 	}
@@ -219,7 +217,6 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
 	    bridge->driver->needs_scratch_page) {
 		bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
 						 AGP_PAGE_DESTROY_UNMAP);
-		flush_agp_mappings();
 		bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
 						 AGP_PAGE_DESTROY_FREE);
 	}
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 64b2f6d7059d..1a4674ce0c71 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -197,7 +197,6 @@ void agp_free_memory(struct agp_memory *curr)
 		for (i = 0; i < curr->page_count; i++) {
 			curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP);
 		}
-		flush_agp_mappings();
 		for (i = 0; i < curr->page_count; i++) {
 			curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE);
 		}
@@ -267,8 +266,6 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
 	}
 	new->bridge = bridge;
 
-	flush_agp_mappings();
-
 	return new;
 }
 EXPORT_SYMBOL(agp_allocate_memory);
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index e72a83e2bad5..76f581c85a7d 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -527,7 +527,6 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge)
 
 	if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
 		page = agp_generic_alloc_page(agp_bridge);
-		global_flush_tlb();
 	} else
 		/* Returning NULL would cause problems */
 		/* AK: really dubious code. */
@@ -539,7 +538,6 @@ static void i460_destroy_page (void *page, int flags)
 {
 	if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
 		agp_generic_destroy_page(page, flags);
-		global_flush_tlb();
 	}
 }
 
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index d87961993ccf..189efb6ef970 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -10,6 +10,8 @@
 #include <linux/agp_backend.h>
 #include "agp.h"
 
+#define PCI_DEVICE_ID_INTEL_E7221_HB	0x2588
+#define PCI_DEVICE_ID_INTEL_E7221_IG	0x258a
 #define PCI_DEVICE_ID_INTEL_82946GZ_HB      0x2970
 #define PCI_DEVICE_ID_INTEL_82946GZ_IG      0x2972
 #define PCI_DEVICE_ID_INTEL_82965G_1_HB     0x2980
@@ -208,13 +210,11 @@ static void *i8xx_alloc_pages(void)
 	if (page == NULL)
 		return NULL;
 
-	if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) {
-		change_page_attr(page, 4, PAGE_KERNEL);
-		global_flush_tlb();
+	if (set_pages_uc(page, 4) < 0) {
+		set_pages_wb(page, 4);
 		__free_pages(page, 2);
 		return NULL;
 	}
-	global_flush_tlb();
 	get_page(page);
 	atomic_inc(&agp_bridge->current_memory_agp);
 	return page_address(page);
@@ -228,8 +228,7 @@ static void i8xx_destroy_pages(void *addr)
 		return;
 
 	page = virt_to_page(addr);
-	change_page_attr(page, 4, PAGE_KERNEL);
-	global_flush_tlb();
+	set_pages_wb(page, 4);
 	put_page(page);
 	__free_pages(page, 2);
 	atomic_dec(&agp_bridge->current_memory_agp);
@@ -339,7 +338,6 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
 
 	switch (pg_count) {
 	case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge);
-		global_flush_tlb();
 		break;
 	case 4:
 		/* kludge to get 4 physical pages for ARGB cursor */
@@ -402,7 +400,6 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
 		else {
 			agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
 							     AGP_PAGE_DESTROY_UNMAP);
-			global_flush_tlb();
 			agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
 							     AGP_PAGE_DESTROY_FREE);
 		}
@@ -526,7 +523,8 @@ static void intel_i830_init_gtt_entries(void)
 			break;
 		case I915_GMCH_GMS_STOLEN_48M:
 			/* Check it's really I915G */
-			if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
+			if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB ||
+			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
@@ -538,7 +536,8 @@ static void intel_i830_init_gtt_entries(void)
 			break;
 		case I915_GMCH_GMS_STOLEN_64M:
 			/* Check it's really I915G */
-			if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
+			if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB ||
+			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
@@ -1854,6 +1853,8 @@ static const struct intel_driver_description {
 	{ PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, 0, "865",
 		&intel_845_driver, &intel_830_driver },
 	{ PCI_DEVICE_ID_INTEL_82875_HB, 0, 0, "i875", &intel_845_driver, NULL },
+	{ PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, 0, "E7221 (i915)",
+		NULL, &intel_915_driver },
 	{ PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, 0, "915G",
 		NULL, &intel_915_driver },
 	{ PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, 0, "915GM",
@@ -2059,6 +2060,7 @@ static struct pci_device_id agp_intel_pci_table[] = {
 	ID(PCI_DEVICE_ID_INTEL_82875_HB),
 	ID(PCI_DEVICE_ID_INTEL_7505_0),
 	ID(PCI_DEVICE_ID_INTEL_7205_0),
+	ID(PCI_DEVICE_ID_INTEL_E7221_HB),
 	ID(PCI_DEVICE_ID_INTEL_82915G_HB),
 	ID(PCI_DEVICE_ID_INTEL_82915GM_HB),
 	ID(PCI_DEVICE_ID_INTEL_82945G_HB),
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index f3593974496c..43d3c42df360 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -297,6 +297,7 @@
 	{0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+	{0x8086, 0x258a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
 	{0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 4c16778e3f84..465ad35ed38f 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -600,63 +600,6 @@ static int hpet_is_known(struct hpet_data *hdp)
 	return 0;
 }
 
-EXPORT_SYMBOL(hpet_alloc);
-EXPORT_SYMBOL(hpet_register);
-EXPORT_SYMBOL(hpet_unregister);
-EXPORT_SYMBOL(hpet_control);
-
-int hpet_register(struct hpet_task *tp, int periodic)
-{
-	unsigned int i;
-	u64 mask;
-	struct hpet_timer __iomem *timer;
-	struct hpet_dev *devp;
-	struct hpets *hpetp;
-
-	switch (periodic) {
-	case 1:
-		mask = Tn_PER_INT_CAP_MASK;
-		break;
-	case 0:
-		mask = 0;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	tp->ht_opaque = NULL;
-
-	spin_lock_irq(&hpet_task_lock);
-	spin_lock(&hpet_lock);
-
-	for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
-		for (timer = hpetp->hp_hpet->hpet_timers, i = 0;
-		     i < hpetp->hp_ntimer; i++, timer++) {
-			if ((readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK)
-			    != mask)
-				continue;
-
-			devp = &hpetp->hp_dev[i];
-
-			if (devp->hd_flags & HPET_OPEN || devp->hd_task) {
-				devp = NULL;
-				continue;
-			}
-
-			tp->ht_opaque = devp;
-			devp->hd_task = tp;
-			break;
-		}
-
-	spin_unlock(&hpet_lock);
-	spin_unlock_irq(&hpet_task_lock);
-
-	if (tp->ht_opaque)
-		return 0;
-	else
-		return -EBUSY;
-}
-
 static inline int hpet_tpcheck(struct hpet_task *tp)
 {
 	struct hpet_dev *devp;
@@ -706,24 +649,6 @@ int hpet_unregister(struct hpet_task *tp)
 	return 0;
 }
 
-int hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
-{
-	struct hpet_dev *devp;
-	int err;
-
-	if ((err = hpet_tpcheck(tp)))
-		return err;
-
-	spin_lock_irq(&hpet_lock);
-	devp = tp->ht_opaque;
-	if (devp->hd_task != tp) {
-		spin_unlock_irq(&hpet_lock);
-		return -ENXIO;
-	}
-	spin_unlock_irq(&hpet_lock);
-	return hpet_ioctl_common(devp, cmd, arg, 1);
-}
-
 static ctl_table hpet_table[] = {
 	{
 	 .ctl_name = CTL_UNNUMBERED,
@@ -806,14 +731,14 @@ static unsigned long hpet_calibrate(struct hpets *hpetp)
 
 int hpet_alloc(struct hpet_data *hdp)
 {
-	u64 cap, mcfg;
+	u64 cap, mcfg, hpet_config;
 	struct hpet_dev *devp;
-	u32 i, ntimer;
+	u32 i, ntimer, irq;
 	struct hpets *hpetp;
 	size_t siz;
 	struct hpet __iomem *hpet;
 	static struct hpets *last = NULL;
-	unsigned long period;
+	unsigned long period, irq_bitmap;
 	unsigned long long temp;
 
 	/*
@@ -840,11 +765,47 @@ int hpet_alloc(struct hpet_data *hdp)
 	hpetp->hp_hpet_phys = hdp->hd_phys_address;
 
 	hpetp->hp_ntimer = hdp->hd_nirqs;
+	hpet = hpetp->hp_hpet;
 
-	for (i = 0; i < hdp->hd_nirqs; i++)
-		hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i];
+	/* Assign IRQs statically for legacy devices */
+	hpetp->hp_dev[0].hd_hdwirq = hdp->hd_irq[0];
+	hpetp->hp_dev[1].hd_hdwirq = hdp->hd_irq[1];
 
-	hpet = hpetp->hp_hpet;
+	/* Assign IRQs dynamically for the others */
+	for (i = 2, devp = &hpetp->hp_dev[2]; i < hdp->hd_nirqs; i++, devp++) {
+		struct hpet_timer __iomem *timer;
+
+		timer = &hpet->hpet_timers[devp - hpetp->hp_dev];
+
+		/* Check if there's already an IRQ assigned to the timer */
+		if (hdp->hd_irq[i]) {
+			hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i];
+			continue;
+		}
+
+		hpet_config = readq(&timer->hpet_config);
+		irq_bitmap = (hpet_config & Tn_INT_ROUTE_CAP_MASK)
+			>> Tn_INT_ROUTE_CAP_SHIFT;
+		if (!irq_bitmap)
+			irq = 0;        /* No valid IRQ Assignable */
+		else {
+			irq = find_first_bit(&irq_bitmap, 32);
+			do {
+				hpet_config |= irq << Tn_INT_ROUTE_CNF_SHIFT;
+				writeq(hpet_config, &timer->hpet_config);
+
+				/*
+				 * Verify whether we have written a valid
+				 * IRQ number by reading it back again
+				 */
+				hpet_config = readq(&timer->hpet_config);
+				if (irq == (hpet_config & Tn_INT_ROUTE_CNF_MASK)
+						>> Tn_INT_ROUTE_CNF_SHIFT)
+					break;  /* Success */
+			} while ((irq = (find_next_bit(&irq_bitmap, 32, irq))));
+		}
+		hpetp->hp_dev[i].hd_hdwirq = irq;
+	}
 
 	cap = readq(&hpet->hpet_cap);
 
@@ -875,7 +836,8 @@ int hpet_alloc(struct hpet_data *hdp)
 		hpetp->hp_which, hdp->hd_phys_address,
 		hpetp->hp_ntimer > 1 ? "s" : "");
 	for (i = 0; i < hpetp->hp_ntimer; i++)
-		printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
+		printk("%s %d", i > 0 ? "," : "",
+				hpetp->hp_dev[i].hd_hdwirq);
 	printk("\n");
 
 	printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n",
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 8252f8668538..480fae29c9b2 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -27,7 +27,7 @@
 #include <linux/init.h>
 #include <linux/kbd_kern.h>
 #include <linux/kernel.h>
-#include <linux/kobject.h>
+#include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -89,7 +89,7 @@ struct hvc_struct {
 	int irq_requested;
 	int irq;
 	struct list_head next;
-	struct kobject kobj; /* ref count & hvc_struct lifetime */
+	struct kref kref; /* ref count & hvc_struct lifetime */
 };
 
 /* dynamic list of hvc_struct instances */
@@ -110,7 +110,7 @@ static int last_hvc = -1;
 
 /*
  * Do not call this function with either the hvc_structs_lock or the hvc_struct
- * lock held.  If successful, this function increments the kobject reference
+ * lock held.  If successful, this function increments the kref reference
  * count against the target hvc_struct so it should be released when finished.
  */
 static struct hvc_struct *hvc_get_by_index(int index)
@@ -123,7 +123,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
 	list_for_each_entry(hp, &hvc_structs, next) {
 		spin_lock_irqsave(&hp->lock, flags);
 		if (hp->index == index) {
-			kobject_get(&hp->kobj);
+			kref_get(&hp->kref);
 			spin_unlock_irqrestore(&hp->lock, flags);
 			spin_unlock(&hvc_structs_lock);
 			return hp;
@@ -242,6 +242,23 @@ static int __init hvc_console_init(void)
 }
 console_initcall(hvc_console_init);
 
+/* callback when the kboject ref count reaches zero. */
+static void destroy_hvc_struct(struct kref *kref)
+{
+	struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
+	unsigned long flags;
+
+	spin_lock(&hvc_structs_lock);
+
+	spin_lock_irqsave(&hp->lock, flags);
+	list_del(&(hp->next));
+	spin_unlock_irqrestore(&hp->lock, flags);
+
+	spin_unlock(&hvc_structs_lock);
+
+	kfree(hp);
+}
+
 /*
  * hvc_instantiate() is an early console discovery method which locates
  * consoles * prior to the vio subsystem discovering them.  Hotplugged
@@ -261,7 +278,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
 	/* make sure no no tty has been registered in this index */
 	hp = hvc_get_by_index(index);
 	if (hp) {
-		kobject_put(&hp->kobj);
+		kref_put(&hp->kref, destroy_hvc_struct);
 		return -1;
 	}
 
@@ -318,9 +335,8 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 	unsigned long flags;
 	int irq = 0;
 	int rc = 0;
-	struct kobject *kobjp;
 
-	/* Auto increments kobject reference if found. */
+	/* Auto increments kref reference if found. */
 	if (!(hp = hvc_get_by_index(tty->index)))
 		return -ENODEV;
 
@@ -341,8 +357,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 	if (irq)
 		hp->irq_requested = 1;
 
-	kobjp = &hp->kobj;
-
 	spin_unlock_irqrestore(&hp->lock, flags);
 	/* check error, fallback to non-irq */
 	if (irq)
@@ -352,7 +366,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 	 * If the request_irq() fails and we return an error.  The tty layer
 	 * will call hvc_close() after a failed open but we don't want to clean
 	 * up there so we'll clean up here and clear out the previously set
-	 * tty fields and return the kobject reference.
+	 * tty fields and return the kref reference.
 	 */
 	if (rc) {
 		spin_lock_irqsave(&hp->lock, flags);
@@ -360,7 +374,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 		hp->irq_requested = 0;
 		spin_unlock_irqrestore(&hp->lock, flags);
 		tty->driver_data = NULL;
-		kobject_put(kobjp);
+		kref_put(&hp->kref, destroy_hvc_struct);
 		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
 	}
 	/* Force wakeup of the polling thread */
@@ -372,7 +386,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
 static void hvc_close(struct tty_struct *tty, struct file * filp)
 {
 	struct hvc_struct *hp;
-	struct kobject *kobjp;
 	int irq = 0;
 	unsigned long flags;
 
@@ -382,7 +395,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
 	/*
 	 * No driver_data means that this close was issued after a failed
 	 * hvc_open by the tty layer's release_dev() function and we can just
-	 * exit cleanly because the kobject reference wasn't made.
+	 * exit cleanly because the kref reference wasn't made.
 	 */
 	if (!tty->driver_data)
 		return;
@@ -390,7 +403,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
 	hp = tty->driver_data;
 	spin_lock_irqsave(&hp->lock, flags);
 
-	kobjp = &hp->kobj;
 	if (--hp->count == 0) {
 		if (hp->irq_requested)
 			irq = hp->irq;
@@ -417,7 +429,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
 		spin_unlock_irqrestore(&hp->lock, flags);
 	}
 
-	kobject_put(kobjp);
+	kref_put(&hp->kref, destroy_hvc_struct);
 }
 
 static void hvc_hangup(struct tty_struct *tty)
@@ -426,7 +438,6 @@ static void hvc_hangup(struct tty_struct *tty)
 	unsigned long flags;
 	int irq = 0;
 	int temp_open_count;
-	struct kobject *kobjp;
 
 	if (!hp)
 		return;
@@ -443,7 +454,6 @@ static void hvc_hangup(struct tty_struct *tty)
 		return;
 	}
 
-	kobjp = &hp->kobj;
 	temp_open_count = hp->count;
 	hp->count = 0;
 	hp->n_outbuf = 0;
@@ -457,7 +467,7 @@ static void hvc_hangup(struct tty_struct *tty)
 		free_irq(irq, hp);
 	while(temp_open_count) {
 		--temp_open_count;
-		kobject_put(kobjp);
+		kref_put(&hp->kref, destroy_hvc_struct);
 	}
 }
 
@@ -729,27 +739,6 @@ static const struct tty_operations hvc_ops = {
 	.chars_in_buffer = hvc_chars_in_buffer,
 };
 
-/* callback when the kboject ref count reaches zero. */
-static void destroy_hvc_struct(struct kobject *kobj)
-{
-	struct hvc_struct *hp = container_of(kobj, struct hvc_struct, kobj);
-	unsigned long flags;
-
-	spin_lock(&hvc_structs_lock);
-
-	spin_lock_irqsave(&hp->lock, flags);
-	list_del(&(hp->next));
-	spin_unlock_irqrestore(&hp->lock, flags);
-
-	spin_unlock(&hvc_structs_lock);
-
-	kfree(hp);
-}
-
-static struct kobj_type hvc_kobj_type = {
-	.release = destroy_hvc_struct,
-};
-
 struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
 					struct hv_ops *ops, int outbuf_size)
 {
@@ -776,8 +765,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
 	hp->outbuf_size = outbuf_size;
 	hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
 
-	kobject_init(&hp->kobj);
-	hp->kobj.ktype = &hvc_kobj_type;
+	kref_init(&hp->kref);
 
 	spin_lock_init(&hp->lock);
 	spin_lock(&hvc_structs_lock);
@@ -806,12 +794,10 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
 int __devexit hvc_remove(struct hvc_struct *hp)
 {
 	unsigned long flags;
-	struct kobject *kobjp;
 	struct tty_struct *tty;
 
 	spin_lock_irqsave(&hp->lock, flags);
 	tty = hp->tty;
-	kobjp = &hp->kobj;
 
 	if (hp->index < MAX_NR_HVC_CONSOLES)
 		vtermnos[hp->index] = -1;
@@ -821,12 +807,12 @@ int __devexit hvc_remove(struct hvc_struct *hp)
 	spin_unlock_irqrestore(&hp->lock, flags);
 
 	/*
-	 * We 'put' the instance that was grabbed when the kobject instance
-	 * was initialized using kobject_init().  Let the last holder of this
-	 * kobject cause it to be removed, which will probably be the tty_hangup
+	 * We 'put' the instance that was grabbed when the kref instance
+	 * was initialized using kref_init().  Let the last holder of this
+	 * kref cause it to be removed, which will probably be the tty_hangup
 	 * below.
 	 */
-	kobject_put(kobjp);
+	kref_put(&hp->kref, destroy_hvc_struct);
 
 	/*
 	 * This function call will auto chain call hvc_hangup.  The tty should
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 69d8866de783..fd7559084b82 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -57,11 +57,7 @@
  * rescanning partner information upon a user's request.
  *
  * Each vty-server, prior to being exposed to this driver is reference counted
- * using the 2.6 Linux kernel kobject construct.  This kobject is also used by
- * the vio bus to provide a vio device sysfs entry that this driver attaches
- * device specific attributes to, including partner information.  The vio bus
- * framework also provides a sysfs entry for each vio driver.  The hvcs driver
- * provides driver attributes in this entry.
+ * using the 2.6 Linux kernel kref construct.
  *
  * For direction on installation and usage of this driver please reference
  * Documentation/powerpc/hvcs.txt.
@@ -71,7 +67,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
-#include <linux/kobject.h>
+#include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/list.h>
 #include <linux/major.h>
@@ -293,12 +289,12 @@ struct hvcs_struct {
 	int chars_in_buffer;
 
 	/*
-	 * Any variable below the kobject is valid before a tty is connected and
+	 * Any variable below the kref is valid before a tty is connected and
 	 * stays valid after the tty is disconnected.  These shouldn't be
 	 * whacked until the koject refcount reaches zero though some entries
 	 * may be changed via sysfs initiatives.
 	 */
-	struct kobject kobj; /* ref count & hvcs_struct lifetime */
+	struct kref kref; /* ref count & hvcs_struct lifetime */
 	int connected; /* is the vty-server currently connected to a vty? */
 	uint32_t p_unit_address; /* partner unit address */
 	uint32_t p_partition_ID; /* partner partition ID */
@@ -307,8 +303,8 @@ struct hvcs_struct {
 	struct vio_dev *vdev;
 };
 
-/* Required to back map a kobject to its containing object */
-#define from_kobj(kobj) container_of(kobj, struct hvcs_struct, kobj)
+/* Required to back map a kref to its containing object */
+#define from_kref(k) container_of(k, struct hvcs_struct, kref)
 
 static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs);
 static DEFINE_SPINLOCK(hvcs_structs_lock);
@@ -334,7 +330,6 @@ static void hvcs_partner_free(struct hvcs_struct *hvcsd);
 static int hvcs_enable_device(struct hvcs_struct *hvcsd,
 		uint32_t unit_address, unsigned int irq, struct vio_dev *dev);
 
-static void destroy_hvcs_struct(struct kobject *kobj);
 static int hvcs_open(struct tty_struct *tty, struct file *filp);
 static void hvcs_close(struct tty_struct *tty, struct file *filp);
 static void hvcs_hangup(struct tty_struct * tty);
@@ -703,10 +698,10 @@ static void hvcs_return_index(int index)
 		hvcs_index_list[index] = -1;
 }
 
-/* callback when the kboject ref count reaches zero */
-static void destroy_hvcs_struct(struct kobject *kobj)
+/* callback when the kref ref count reaches zero */
+static void destroy_hvcs_struct(struct kref *kref)
 {
-	struct hvcs_struct *hvcsd = from_kobj(kobj);
+	struct hvcs_struct *hvcsd = from_kref(kref);
 	struct vio_dev *vdev;
 	unsigned long flags;
 
@@ -743,10 +738,6 @@ static void destroy_hvcs_struct(struct kobject *kobj)
 	kfree(hvcsd);
 }
 
-static struct kobj_type hvcs_kobj_type = {
-	.release = destroy_hvcs_struct,
-};
-
 static int hvcs_get_index(void)
 {
 	int i;
@@ -791,9 +782,7 @@ static int __devinit hvcs_probe(
 
 	spin_lock_init(&hvcsd->lock);
 	/* Automatically incs the refcount the first time */
-	kobject_init(&hvcsd->kobj);
-	/* Set up the callback for terminating the hvcs_struct's life */
-	hvcsd->kobj.ktype = &hvcs_kobj_type;
+	kref_init(&hvcsd->kref);
 
 	hvcsd->vdev = dev;
 	dev->dev.driver_data = hvcsd;
@@ -844,7 +833,6 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
 {
 	struct hvcs_struct *hvcsd = dev->dev.driver_data;
 	unsigned long flags;
-	struct kobject *kobjp;
 	struct tty_struct *tty;
 
 	if (!hvcsd)
@@ -856,15 +844,13 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
 
 	tty = hvcsd->tty;
 
-	kobjp = &hvcsd->kobj;
-
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
 
 	/*
 	 * Let the last holder of this object cause it to be removed, which
 	 * would probably be tty_hangup below.
 	 */
-	kobject_put (kobjp);
+	kref_put(&hvcsd->kref, destroy_hvcs_struct);
 
 	/*
 	 * The hangup is a scheduled function which will auto chain call
@@ -1086,7 +1072,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
 }
 
 /*
- * This always increments the kobject ref count if the call is successful.
+ * This always increments the kref ref count if the call is successful.
  * Please remember to dec when you are done with the instance.
  *
  * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
@@ -1103,7 +1089,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
 		list_for_each_entry(hvcsd, &hvcs_structs, next) {
 			spin_lock_irqsave(&hvcsd->lock, flags);
 			if (hvcsd->index == index) {
-				kobject_get(&hvcsd->kobj);
+				kref_get(&hvcsd->kref);
 				spin_unlock_irqrestore(&hvcsd->lock, flags);
 				spin_unlock(&hvcs_structs_lock);
 				return hvcsd;
@@ -1129,14 +1115,13 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
 	unsigned int irq;
 	struct vio_dev *vdev;
 	unsigned long unit_address;
-	struct kobject *kobjp;
 
 	if (tty->driver_data)
 		goto fast_open;
 
 	/*
 	 * Is there a vty-server that shares the same index?
-	 * This function increments the kobject index.
+	 * This function increments the kref index.
 	 */
 	if (!(hvcsd = hvcs_get_by_index(tty->index))) {
 		printk(KERN_WARNING "HVCS: open failed, no device associated"
@@ -1181,7 +1166,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
 	 * and will grab the spinlock and free the connection if it fails.
 	 */
 	if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
-		kobject_put(&hvcsd->kobj);
+		kref_put(&hvcsd->kref, destroy_hvcs_struct);
 		printk(KERN_WARNING "HVCS: enable device failed.\n");
 		return rc;
 	}
@@ -1192,17 +1177,11 @@ fast_open:
 	hvcsd = tty->driver_data;
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
-	if (!kobject_get(&hvcsd->kobj)) {
-		spin_unlock_irqrestore(&hvcsd->lock, flags);
-		printk(KERN_ERR "HVCS: Kobject of open"
-			" hvcs doesn't exist.\n");
-		return -EFAULT; /* Is this the right return value? */
-	}
-
+	kref_get(&hvcsd->kref);
 	hvcsd->open_count++;
-
 	hvcsd->todo_mask |= HVCS_SCHED_READ;
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
+
 open_success:
 	hvcs_kick();
 
@@ -1212,9 +1191,8 @@ open_success:
 	return 0;
 
 error_release:
-	kobjp = &hvcsd->kobj;
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
-	kobject_put(&hvcsd->kobj);
+	kref_put(&hvcsd->kref, destroy_hvcs_struct);
 
 	printk(KERN_WARNING "HVCS: partner connect failed.\n");
 	return retval;
@@ -1224,7 +1202,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
 {
 	struct hvcs_struct *hvcsd;
 	unsigned long flags;
-	struct kobject *kobjp;
 	int irq = NO_IRQ;
 
 	/*
@@ -1245,7 +1222,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
 	hvcsd = tty->driver_data;
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
-	kobjp = &hvcsd->kobj;
 	if (--hvcsd->open_count == 0) {
 
 		vio_disable_interrupts(hvcsd->vdev);
@@ -1270,7 +1246,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
 		tty->driver_data = NULL;
 
 		free_irq(irq, hvcsd);
-		kobject_put(kobjp);
+		kref_put(&hvcsd->kref, destroy_hvcs_struct);
 		return;
 	} else if (hvcsd->open_count < 0) {
 		printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
@@ -1279,7 +1255,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
 	}
 
 	spin_unlock_irqrestore(&hvcsd->lock, flags);
-	kobject_put(kobjp);
+	kref_put(&hvcsd->kref, destroy_hvcs_struct);
 }
 
 static void hvcs_hangup(struct tty_struct * tty)
@@ -1287,21 +1263,17 @@ static void hvcs_hangup(struct tty_struct * tty)
 	struct hvcs_struct *hvcsd = tty->driver_data;
 	unsigned long flags;
 	int temp_open_count;
-	struct kobject *kobjp;
 	int irq = NO_IRQ;
 
 	spin_lock_irqsave(&hvcsd->lock, flags);
-	/* Preserve this so that we know how many kobject refs to put */
+	/* Preserve this so that we know how many kref refs to put */
 	temp_open_count = hvcsd->open_count;
 
 	/*
-	 * Don't kobject put inside the spinlock because the destruction
+	 * Don't kref put inside the spinlock because the destruction
 	 * callback may use the spinlock and it may get called before the
-	 * spinlock has been released.  Get a pointer to the kobject and
-	 * kobject_put on that after releasing the spinlock.
+	 * spinlock has been released.
 	 */
-	kobjp = &hvcsd->kobj;
-
 	vio_disable_interrupts(hvcsd->vdev);
 
 	hvcsd->todo_mask = 0;
@@ -1324,7 +1296,7 @@ static void hvcs_hangup(struct tty_struct * tty)
 	free_irq(irq, hvcsd);
 
 	/*
-	 * We need to kobject_put() for every open_count we have since the
+	 * We need to kref_put() for every open_count we have since the
 	 * tty_hangup() function doesn't invoke a close per open connection on a
 	 * non-console device.
 	 */
@@ -1335,7 +1307,7 @@ static void hvcs_hangup(struct tty_struct * tty)
 		 * NOTE:  If this hangup was signaled from user space then the
 		 * final put will never happen.
 		 */
-		kobject_put(kobjp);
+		kref_put(&hvcsd->kref, destroy_hvcs_struct);
 	}
 }
 
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 556fd81fa815..c422e870dc52 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -28,6 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 
@@ -52,11 +53,18 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
 static struct pci_dev *amd_pdev;
 
 
-static int amd_rng_data_present(struct hwrng *rng)
+static int amd_rng_data_present(struct hwrng *rng, int wait)
 {
 	u32 pmbase = (u32)rng->priv;
+	int data, i;
 
-      	return !!(inl(pmbase + 0xF4) & 1);
+	for (i = 0; i < 20; i++) {
+		data = !!(inl(pmbase + 0xF4) & 1);
+		if (data || !wait)
+			break;
+		udelay(10);
+	}
+	return data;
 }
 
 static int amd_rng_data_read(struct hwrng *rng, u32 *data)
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 26a860adcb38..0118b9817a95 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -66,11 +66,11 @@ static inline void hwrng_cleanup(struct hwrng *rng)
 		rng->cleanup(rng);
 }
 
-static inline int hwrng_data_present(struct hwrng *rng)
+static inline int hwrng_data_present(struct hwrng *rng, int wait)
 {
 	if (!rng->data_present)
 		return 1;
-	return rng->data_present(rng);
+	return rng->data_present(rng, wait);
 }
 
 static inline int hwrng_data_read(struct hwrng *rng, u32 *data)
@@ -94,8 +94,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
 {
 	u32 data;
 	ssize_t ret = 0;
-	int i, err = 0;
-	int data_present;
+	int err = 0;
 	int bytes_read;
 
 	while (size) {
@@ -107,21 +106,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
 			err = -ENODEV;
 			goto out;
 		}
-		if (filp->f_flags & O_NONBLOCK) {
-			data_present = hwrng_data_present(current_rng);
-		} else {
-			/* Some RNG require some time between data_reads to gather
-			 * new entropy. Poll it.
-			 */
-			for (i = 0; i < 20; i++) {
-				data_present = hwrng_data_present(current_rng);
-				if (data_present)
-					break;
-				udelay(10);
-			}
-		}
+
 		bytes_read = 0;
-		if (data_present)
+		if (hwrng_data_present(current_rng,
+				       !(filp->f_flags & O_NONBLOCK)))
 			bytes_read = hwrng_data_read(current_rng, &data);
 		mutex_unlock(&rng_mutex);
 
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
index 8e8658dcd2e3..fed4ef5569f5 100644
--- a/drivers/char/hw_random/geode-rng.c
+++ b/drivers/char/hw_random/geode-rng.c
@@ -28,6 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 
@@ -61,11 +62,18 @@ static int geode_rng_data_read(struct hwrng *rng, u32 *data)
 	return 4;
 }
 
-static int geode_rng_data_present(struct hwrng *rng)
+static int geode_rng_data_present(struct hwrng *rng, int wait)
 {
 	void __iomem *mem = (void __iomem *)rng->priv;
+	int data, i;
 
-	return !!(readl(mem + GEODE_RNG_STATUS_REG));
+	for (i = 0; i < 20; i++) {
+		data = !!(readl(mem + GEODE_RNG_STATUS_REG));
+		if (data || !wait)
+			break;
+		udelay(10);
+	}
+	return data;
 }
 
 
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index 753f46052b87..5cc651ef75eb 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/stop_machine.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 
@@ -162,11 +163,19 @@ static inline u8 hwstatus_set(void __iomem *mem,
 	return hwstatus_get(mem);
 }
 
-static int intel_rng_data_present(struct hwrng *rng)
+static int intel_rng_data_present(struct hwrng *rng, int wait)
 {
 	void __iomem *mem = (void __iomem *)rng->priv;
-
-	return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT);
+	int data, i;
+
+	for (i = 0; i < 20; i++) {
+		data = !!(readb(mem + INTEL_RNG_STATUS) &
+			  INTEL_RNG_DATA_PRESENT);
+		if (data || !wait)
+			break;
+		udelay(10);
+	}
+	return data;
 }
 
 static int intel_rng_data_read(struct hwrng *rng, u32 *data)
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index 3f35a1c562b1..7e319951fa41 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -29,6 +29,7 @@
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 
@@ -65,9 +66,17 @@ static void omap_rng_write_reg(int reg, u32 val)
 }
 
 /* REVISIT: Does the status bit really work on 16xx? */
-static int omap_rng_data_present(struct hwrng *rng)
+static int omap_rng_data_present(struct hwrng *rng, int wait)
 {
-	return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1;
+	int data, i;
+
+	for (i = 0; i < 20; i++) {
+		data = omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1;
+		if (data || !wait)
+			break;
+		udelay(10);
+	}
+	return data;
 }
 
 static int omap_rng_data_read(struct hwrng *rng, u32 *data)
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
index 24ae3073991f..6d50e9bc700b 100644
--- a/drivers/char/hw_random/pasemi-rng.c
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -23,6 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/of_platform.h>
 #include <asm/io.h>
 
@@ -41,12 +42,19 @@
 
 #define MODULE_NAME "pasemi_rng"
 
-static int pasemi_rng_data_present(struct hwrng *rng)
+static int pasemi_rng_data_present(struct hwrng *rng, int wait)
 {
 	void __iomem *rng_regs = (void __iomem *)rng->priv;
-
-	return (in_le32(rng_regs + SDCRNG_CTL_REG)
-		& SDCRNG_CTL_FVLD_M) ? 1 : 0;
+	int data, i;
+
+	for (i = 0; i < 20; i++) {
+		data = (in_le32(rng_regs + SDCRNG_CTL_REG)
+			& SDCRNG_CTL_FVLD_M) ? 1 : 0;
+		if (data || !wait)
+			break;
+		udelay(10);
+	}
+	return data;
 }
 
 static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index ec435cb25c4f..868e39fd42e4 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/hw_random.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/msr.h>
 #include <asm/cpufeature.h>
@@ -77,10 +78,11 @@ static inline u32 xstore(u32 *addr, u32 edx_in)
 	return eax_out;
 }
 
-static int via_rng_data_present(struct hwrng *rng)
+static int via_rng_data_present(struct hwrng *rng, int wait)
 {
 	u32 bytes_out;
 	u32 *via_rng_datum = (u32 *)(&rng->priv);
+	int i;
 
 	/* We choose the recommended 1-byte-per-instruction RNG rate,
 	 * for greater randomness at the expense of speed.  Larger
@@ -95,12 +97,15 @@ static int via_rng_data_present(struct hwrng *rng)
 	 * completes.
 	 */
 
-	*via_rng_datum = 0; /* paranoia, not really necessary */
-	bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1);
-	bytes_out &= VIA_XSTORE_CNT_MASK;
-	if (bytes_out == 0)
-		return 0;
-	return 1;
+	for (i = 0; i < 20; i++) {
+		*via_rng_datum = 0; /* paranoia, not really necessary */
+		bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1);
+		bytes_out &= VIA_XSTORE_CNT_MASK;
+		if (bytes_out || !wait)
+			break;
+		udelay(10);
+	}
+	return bytes_out ? 1 : 0;
 }
 
 static int via_rng_data_read(struct hwrng *rng, u32 *data)
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
new file mode 100644
index 000000000000..6076e662886a
--- /dev/null
+++ b/drivers/char/nozomi.c
@@ -0,0 +1,1993 @@
+/*
+ * nozomi.c  -- HSDPA driver Broadband Wireless Data Card - Globe Trotter
+ *
+ * Written by: Ulf Jakobsson,
+ *             Jan �erfeldt,
+ *             Stefan Thomasson,
+ *
+ * Maintained by: Paul Hardwick (p.hardwick@option.com)
+ *
+ * Patches:
+ *          Locking code changes for Vodafone by Sphere Systems Ltd,
+ *                              Andrew Bird (ajb@spheresystems.co.uk )
+ *                              & Phil Sanderson
+ *
+ * Source has been ported from an implementation made by Filip Aben @ Option
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Copyright (c) 2005,2006 Option Wireless Sweden AB
+ * Copyright (c) 2006 Sphere Systems Ltd
+ * Copyright (c) 2006 Option Wireless n/v
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * --------------------------------------------------------------------------
+ */
+
+/*
+ * CHANGELOG
+ * Version 2.1d
+ * 11-November-2007 Jiri Slaby, Frank Seidel
+ * - Big rework of multicard support by Jiri
+ * - Major cleanups (semaphore to mutex, endianess, no major reservation)
+ * - Optimizations
+ *
+ * Version 2.1c
+ * 30-October-2007 Frank Seidel
+ * - Completed multicard support
+ * - Minor cleanups
+ *
+ * Version 2.1b
+ * 07-August-2007 Frank Seidel
+ * - Minor cleanups
+ * - theoretical multicard support
+ *
+ * Version 2.1
+ * 03-July-2006 Paul Hardwick
+ *
+ * - Stability Improvements. Incorporated spinlock wraps patch.
+ * - Updated for newer 2.6.14+ kernels (tty_buffer_request_room)
+ * - using __devexit macro for tty
+ *
+ *
+ * Version 2.0
+ * 08-feb-2006 15:34:10:Ulf
+ *
+ * -Fixed issue when not waking up line disipine layer, could probably result
+ *  in better uplink performance for 2.4.
+ *
+ * -Fixed issue with big endian during initalization, now proper toggle flags
+ *  are handled between preloader and maincode.
+ *
+ * -Fixed flow control issue.
+ *
+ * -Added support for setting DTR.
+ *
+ * -For 2.4 kernels, removing temporary buffer that's not needed.
+ *
+ * -Reading CTS only for modem port (only port that supports it).
+ *
+ * -Return 0 in write_room instead of netative value, it's not handled in
+ *  upper layer.
+ *
+ * --------------------------------------------------------------------------
+ * Version 1.0
+ *
+ * First version of driver, only tested with card of type F32_2.
+ * Works fine with 2.4 and 2.6 kernels.
+ * Driver also support big endian architecture.
+ */
+
+/* Enable this to have a lot of debug printouts */
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/interrupt.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/kfifo.h>
+#include <linux/uaccess.h>
+#include <asm/byteorder.h>
+
+#include <linux/delay.h>
+
+
+#define VERSION_STRING DRIVER_DESC " 2.1d (build date: " \
+					__DATE__ " " __TIME__ ")"
+
+/*    Macros definitions */
+
+/* Default debug printout level */
+#define NOZOMI_DEBUG_LEVEL 0x00
+
+#define P_BUF_SIZE 128
+#define NFO(_err_flag_, args...)				\
+do {								\
+	char tmp[P_BUF_SIZE];					\
+	snprintf(tmp, sizeof(tmp), ##args);			\
+	printk(_err_flag_ "[%d] %s(): %s\n", __LINE__,		\
+		__FUNCTION__, tmp);				\
+} while (0)
+
+#define DBG1(args...) D_(0x01, ##args)
+#define DBG2(args...) D_(0x02, ##args)
+#define DBG3(args...) D_(0x04, ##args)
+#define DBG4(args...) D_(0x08, ##args)
+#define DBG5(args...) D_(0x10, ##args)
+#define DBG6(args...) D_(0x20, ##args)
+#define DBG7(args...) D_(0x40, ##args)
+#define DBG8(args...) D_(0x80, ##args)
+
+#ifdef DEBUG
+/* Do we need this settable at runtime? */
+static int debug = NOZOMI_DEBUG_LEVEL;
+
+#define D(lvl, args...)  do {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \
+				while (0)
+#define D_(lvl, args...) D(lvl, ##args)
+
+/* These printouts are always printed */
+
+#else
+static int debug;
+#define D_(lvl, args...)
+#endif
+
+/* TODO: rewrite to optimize macros... */
+
+#define TMP_BUF_MAX 256
+
+#define DUMP(buf__,len__) \
+  do {  \
+    char tbuf[TMP_BUF_MAX] = {0};\
+    if (len__ > 1) {\
+	snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\
+	if (tbuf[len__-2] == '\r') {\
+		tbuf[len__-2] = 'r';\
+	} \
+	DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\
+    } else {\
+	DBG1("SENDING: '%s' (%d)", tbuf, len__);\
+    } \
+} while (0)
+
+/*    Defines */
+#define NOZOMI_NAME		"nozomi"
+#define NOZOMI_NAME_TTY		"nozomi_tty"
+#define DRIVER_DESC		"Nozomi driver"
+
+#define NTTY_TTY_MAXMINORS	256
+#define NTTY_FIFO_BUFFER_SIZE	8192
+
+/* Must be power of 2 */
+#define FIFO_BUFFER_SIZE_UL	8192
+
+/* Size of tmp send buffer to card */
+#define SEND_BUF_MAX		1024
+#define RECEIVE_BUF_MAX		4
+
+
+/* Define all types of vendors and devices to support */
+#define VENDOR1		0x1931	/* Vendor Option */
+#define DEVICE1		0x000c	/* HSDPA card */
+
+#define R_IIR		0x0000	/* Interrupt Identity Register */
+#define R_FCR		0x0000	/* Flow Control Register */
+#define R_IER		0x0004	/* Interrupt Enable Register */
+
+#define CONFIG_MAGIC	0xEFEFFEFE
+#define TOGGLE_VALID	0x0000
+
+/* Definition of interrupt tokens */
+#define MDM_DL1		0x0001
+#define MDM_UL1		0x0002
+#define MDM_DL2		0x0004
+#define MDM_UL2		0x0008
+#define DIAG_DL1	0x0010
+#define DIAG_DL2	0x0020
+#define DIAG_UL		0x0040
+#define APP1_DL		0x0080
+#define APP1_UL		0x0100
+#define APP2_DL		0x0200
+#define APP2_UL		0x0400
+#define CTRL_DL		0x0800
+#define CTRL_UL		0x1000
+#define RESET		0x8000
+
+#define MDM_DL		(MDM_DL1  | MDM_DL2)
+#define MDM_UL		(MDM_UL1  | MDM_UL2)
+#define DIAG_DL		(DIAG_DL1 | DIAG_DL2)
+
+/* modem signal definition */
+#define CTRL_DSR	0x0001
+#define CTRL_DCD	0x0002
+#define CTRL_RI		0x0004
+#define CTRL_CTS	0x0008
+
+#define CTRL_DTR	0x0001
+#define CTRL_RTS	0x0002
+
+#define MAX_PORT		4
+#define NOZOMI_MAX_PORTS	5
+#define NOZOMI_MAX_CARDS	(NTTY_TTY_MAXMINORS / MAX_PORT)
+
+/*    Type definitions */
+
+/*
+ * There are two types of nozomi cards,
+ * one with 2048 memory and with 8192 memory
+ */
+enum card_type {
+	F32_2 = 2048,	/* 512 bytes downlink + uplink * 2 -> 2048 */
+	F32_8 = 8192,	/* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */
+};
+
+/* Two different toggle channels exist */
+enum channel_type {
+	CH_A = 0,
+	CH_B = 1,
+};
+
+/* Port definition for the card regarding flow control */
+enum ctrl_port_type {
+	CTRL_CMD	= 0,
+	CTRL_MDM	= 1,
+	CTRL_DIAG	= 2,
+	CTRL_APP1	= 3,
+	CTRL_APP2	= 4,
+	CTRL_ERROR	= -1,
+};
+
+/* Ports that the nozomi has */
+enum port_type {
+	PORT_MDM	= 0,
+	PORT_DIAG	= 1,
+	PORT_APP1	= 2,
+	PORT_APP2	= 3,
+	PORT_CTRL	= 4,
+	PORT_ERROR	= -1,
+};
+
+#ifdef __BIG_ENDIAN
+/* Big endian */
+
+struct toggles {
+	unsigned enabled:5;	/*
+				 * Toggle fields are valid if enabled is 0,
+				 * else A-channels must always be used.
+				 */
+	unsigned diag_dl:1;
+	unsigned mdm_dl:1;
+	unsigned mdm_ul:1;
+} __attribute__ ((packed));
+
+/* Configuration table to read at startup of card */
+/* Is for now only needed during initialization phase */
+struct config_table {
+	u32 signature;
+	u16 product_information;
+	u16 version;
+	u8 pad3[3];
+	struct toggles toggle;
+	u8 pad1[4];
+	u16 dl_mdm_len1;	/*
+				 * If this is 64, it can hold
+				 * 60 bytes + 4 that is length field
+				 */
+	u16 dl_start;
+
+	u16 dl_diag_len1;
+	u16 dl_mdm_len2;	/*
+				 * If this is 64, it can hold
+				 * 60 bytes + 4 that is length field
+				 */
+	u16 dl_app1_len;
+
+	u16 dl_diag_len2;
+	u16 dl_ctrl_len;
+	u16 dl_app2_len;
+	u8 pad2[16];
+	u16 ul_mdm_len1;
+	u16 ul_start;
+	u16 ul_diag_len;
+	u16 ul_mdm_len2;
+	u16 ul_app1_len;
+	u16 ul_app2_len;
+	u16 ul_ctrl_len;
+} __attribute__ ((packed));
+
+/* This stores all control downlink flags */
+struct ctrl_dl {
+	u8 port;
+	unsigned reserved:4;
+	unsigned CTS:1;
+	unsigned RI:1;
+	unsigned DCD:1;
+	unsigned DSR:1;
+} __attribute__ ((packed));
+
+/* This stores all control uplink flags */
+struct ctrl_ul {
+	u8 port;
+	unsigned reserved:6;
+	unsigned RTS:1;
+	unsigned DTR:1;
+} __attribute__ ((packed));
+
+#else
+/* Little endian */
+
+/* This represents the toggle information */
+struct toggles {
+	unsigned mdm_ul:1;
+	unsigned mdm_dl:1;
+	unsigned diag_dl:1;
+	unsigned enabled:5;	/*
+				 * Toggle fields are valid if enabled is 0,
+				 * else A-channels must always be used.
+				 */
+} __attribute__ ((packed));
+
+/* Configuration table to read at startup of card */
+struct config_table {
+	u32 signature;
+	u16 version;
+	u16 product_information;
+	struct toggles toggle;
+	u8 pad1[7];
+	u16 dl_start;
+	u16 dl_mdm_len1;	/*
+				 * If this is 64, it can hold
+				 * 60 bytes + 4 that is length field
+				 */
+	u16 dl_mdm_len2;
+	u16 dl_diag_len1;
+	u16 dl_diag_len2;
+	u16 dl_app1_len;
+	u16 dl_app2_len;
+	u16 dl_ctrl_len;
+	u8 pad2[16];
+	u16 ul_start;
+	u16 ul_mdm_len2;
+	u16 ul_mdm_len1;
+	u16 ul_diag_len;
+	u16 ul_app1_len;
+	u16 ul_app2_len;
+	u16 ul_ctrl_len;
+} __attribute__ ((packed));
+
+/* This stores all control downlink flags */
+struct ctrl_dl {
+	unsigned DSR:1;
+	unsigned DCD:1;
+	unsigned RI:1;
+	unsigned CTS:1;
+	unsigned reserverd:4;
+	u8 port;
+} __attribute__ ((packed));
+
+/* This stores all control uplink flags */
+struct ctrl_ul {
+	unsigned DTR:1;
+	unsigned RTS:1;
+	unsigned reserved:6;
+	u8 port;
+} __attribute__ ((packed));
+#endif
+
+/* This holds all information that is needed regarding a port */
+struct port {
+	u8 update_flow_control;
+	struct ctrl_ul ctrl_ul;
+	struct ctrl_dl ctrl_dl;
+	struct kfifo *fifo_ul;
+	void __iomem *dl_addr[2];
+	u32 dl_size[2];
+	u8 toggle_dl;
+	void __iomem *ul_addr[2];
+	u32 ul_size[2];
+	u8 toggle_ul;
+	u16 token_dl;
+
+	struct tty_struct *tty;
+	int tty_open_count;
+	/* mutex to ensure one access patch to this port */
+	struct mutex tty_sem;
+	wait_queue_head_t tty_wait;
+	struct async_icount tty_icount;
+};
+
+/* Private data one for each card in the system */
+struct nozomi {
+	void __iomem *base_addr;
+	unsigned long flip;
+
+	/* Pointers to registers */
+	void __iomem *reg_iir;
+	void __iomem *reg_fcr;
+	void __iomem *reg_ier;
+
+	u16 last_ier;
+	enum card_type card_type;
+	struct config_table config_table;	/* Configuration table */
+	struct pci_dev *pdev;
+	struct port port[NOZOMI_MAX_PORTS];
+	u8 *send_buf;
+
+	spinlock_t spin_mutex;	/* secures access to registers and tty */
+
+	unsigned int index_start;
+	u32 open_ttys;
+};
+
+/* This is a data packet that is read or written to/from card */
+struct buffer {
+	u32 size;		/* size is the length of the data buffer */
+	u8 *data;
+} __attribute__ ((packed));
+
+/*    Global variables */
+static struct pci_device_id nozomi_pci_tbl[] = {
+	{PCI_DEVICE(VENDOR1, DEVICE1)},
+	{},
+};
+
+MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl);
+
+static struct nozomi *ndevs[NOZOMI_MAX_CARDS];
+static struct tty_driver *ntty_driver;
+
+/*
+ * find card by tty_index
+ */
+static inline struct nozomi *get_dc_by_tty(const struct tty_struct *tty)
+{
+	return tty ? ndevs[tty->index / MAX_PORT] : NULL;
+}
+
+static inline struct port *get_port_by_tty(const struct tty_struct *tty)
+{
+	struct nozomi *ndev = get_dc_by_tty(tty);
+	return ndev ? &ndev->port[tty->index % MAX_PORT] : NULL;
+}
+
+/*
+ * TODO:
+ * -Optimize
+ * -Rewrite cleaner
+ */
+
+static void read_mem32(u32 *buf, const void __iomem *mem_addr_start,
+			u32 size_bytes)
+{
+	u32 i = 0;
+	const u32 *ptr = (__force u32 *) mem_addr_start;
+	u16 *buf16;
+
+	if (unlikely(!ptr || !buf))
+		goto out;
+
+	/* shortcut for extremely often used cases */
+	switch (size_bytes) {
+	case 2:	/* 2 bytes */
+		buf16 = (u16 *) buf;
+		*buf16 = __le16_to_cpu(readw((void __iomem *)ptr));
+		goto out;
+		break;
+	case 4:	/* 4 bytes */
+		*(buf) = __le32_to_cpu(readl((void __iomem *)ptr));
+		goto out;
+		break;
+	}
+
+	while (i < size_bytes) {
+		if (size_bytes - i == 2) {
+			/* Handle 2 bytes in the end */
+			buf16 = (u16 *) buf;
+			*(buf16) = __le16_to_cpu(readw((void __iomem *)ptr));
+			i += 2;
+		} else {
+			/* Read 4 bytes */
+			*(buf) = __le32_to_cpu(readl((void __iomem *)ptr));
+			i += 4;
+		}
+		buf++;
+		ptr++;
+	}
+out:
+	return;
+}
+
+/*
+ * TODO:
+ * -Optimize
+ * -Rewrite cleaner
+ */
+static u32 write_mem32(void __iomem *mem_addr_start, u32 *buf,
+			u32 size_bytes)
+{
+	u32 i = 0;
+	u32 *ptr = (__force u32 *) mem_addr_start;
+	u16 *buf16;
+
+	if (unlikely(!ptr || !buf))
+		return 0;
+
+	/* shortcut for extremely often used cases */
+	switch (size_bytes) {
+	case 2:	/* 2 bytes */
+		buf16 = (u16 *) buf;
+		writew(__cpu_to_le16(*buf16), (void __iomem *)ptr);
+		return 2;
+		break;
+	case 1: /*
+		 * also needs to write 4 bytes in this case
+		 * so falling through..
+		 */
+	case 4: /* 4 bytes */
+		writel(__cpu_to_le32(*buf), (void __iomem *)ptr);
+		return 4;
+		break;
+	}
+
+	while (i < size_bytes) {
+		if (size_bytes - i == 2) {
+			/* 2 bytes */
+			buf16 = (u16 *) buf;
+			writew(__cpu_to_le16(*buf16), (void __iomem *)ptr);
+			i += 2;
+		} else {
+			/* 4 bytes */
+			writel(__cpu_to_le32(*buf), (void __iomem *)ptr);
+			i += 4;
+		}
+		buf++;
+		ptr++;
+	}
+	return i;
+}
+
+/* Setup pointers to different channels and also setup buffer sizes. */
+static void setup_memory(struct nozomi *dc)
+{
+	void __iomem *offset = dc->base_addr + dc->config_table.dl_start;
+	/* The length reported is including the length field of 4 bytes,
+	 * hence subtract with 4.
+	 */
+	const u16 buff_offset = 4;
+
+	/* Modem port dl configuration */
+	dc->port[PORT_MDM].dl_addr[CH_A] = offset;
+	dc->port[PORT_MDM].dl_addr[CH_B] =
+				(offset += dc->config_table.dl_mdm_len1);
+	dc->port[PORT_MDM].dl_size[CH_A] =
+				dc->config_table.dl_mdm_len1 - buff_offset;
+	dc->port[PORT_MDM].dl_size[CH_B] =
+				dc->config_table.dl_mdm_len2 - buff_offset;
+
+	/* Diag port dl configuration */
+	dc->port[PORT_DIAG].dl_addr[CH_A] =
+				(offset += dc->config_table.dl_mdm_len2);
+	dc->port[PORT_DIAG].dl_size[CH_A] =
+				dc->config_table.dl_diag_len1 - buff_offset;
+	dc->port[PORT_DIAG].dl_addr[CH_B] =
+				(offset += dc->config_table.dl_diag_len1);
+	dc->port[PORT_DIAG].dl_size[CH_B] =
+				dc->config_table.dl_diag_len2 - buff_offset;
+
+	/* App1 port dl configuration */
+	dc->port[PORT_APP1].dl_addr[CH_A] =
+				(offset += dc->config_table.dl_diag_len2);
+	dc->port[PORT_APP1].dl_size[CH_A] =
+				dc->config_table.dl_app1_len - buff_offset;
+
+	/* App2 port dl configuration */
+	dc->port[PORT_APP2].dl_addr[CH_A] =
+				(offset += dc->config_table.dl_app1_len);
+	dc->port[PORT_APP2].dl_size[CH_A] =
+				dc->config_table.dl_app2_len - buff_offset;
+
+	/* Ctrl dl configuration */
+	dc->port[PORT_CTRL].dl_addr[CH_A] =
+				(offset += dc->config_table.dl_app2_len);
+	dc->port[PORT_CTRL].dl_size[CH_A] =
+				dc->config_table.dl_ctrl_len - buff_offset;
+
+	offset = dc->base_addr + dc->config_table.ul_start;
+
+	/* Modem Port ul configuration */
+	dc->port[PORT_MDM].ul_addr[CH_A] = offset;
+	dc->port[PORT_MDM].ul_size[CH_A] =
+				dc->config_table.ul_mdm_len1 - buff_offset;
+	dc->port[PORT_MDM].ul_addr[CH_B] =
+				(offset += dc->config_table.ul_mdm_len1);
+	dc->port[PORT_MDM].ul_size[CH_B] =
+				dc->config_table.ul_mdm_len2 - buff_offset;
+
+	/* Diag port ul configuration */
+	dc->port[PORT_DIAG].ul_addr[CH_A] =
+				(offset += dc->config_table.ul_mdm_len2);
+	dc->port[PORT_DIAG].ul_size[CH_A] =
+				dc->config_table.ul_diag_len - buff_offset;
+
+	/* App1 port ul configuration */
+	dc->port[PORT_APP1].ul_addr[CH_A] =
+				(offset += dc->config_table.ul_diag_len);
+	dc->port[PORT_APP1].ul_size[CH_A] =
+				dc->config_table.ul_app1_len - buff_offset;
+
+	/* App2 port ul configuration */
+	dc->port[PORT_APP2].ul_addr[CH_A] =
+				(offset += dc->config_table.ul_app1_len);
+	dc->port[PORT_APP2].ul_size[CH_A] =
+				dc->config_table.ul_app2_len - buff_offset;
+
+	/* Ctrl ul configuration */
+	dc->port[PORT_CTRL].ul_addr[CH_A] =
+				(offset += dc->config_table.ul_app2_len);
+	dc->port[PORT_CTRL].ul_size[CH_A] =
+				dc->config_table.ul_ctrl_len - buff_offset;
+}
+
+/* Dump config table under initalization phase */
+#ifdef DEBUG
+static void dump_table(const struct nozomi *dc)
+{
+	DBG3("signature: 0x%08X", dc->config_table.signature);
+	DBG3("version: 0x%04X", dc->config_table.version);
+	DBG3("product_information: 0x%04X", \
+				dc->config_table.product_information);
+	DBG3("toggle enabled: %d", dc->config_table.toggle.enabled);
+	DBG3("toggle up_mdm: %d", dc->config_table.toggle.mdm_ul);
+	DBG3("toggle dl_mdm: %d", dc->config_table.toggle.mdm_dl);
+	DBG3("toggle dl_dbg: %d", dc->config_table.toggle.diag_dl);
+
+	DBG3("dl_start: 0x%04X", dc->config_table.dl_start);
+	DBG3("dl_mdm_len0: 0x%04X, %d", dc->config_table.dl_mdm_len1,
+	   dc->config_table.dl_mdm_len1);
+	DBG3("dl_mdm_len1: 0x%04X, %d", dc->config_table.dl_mdm_len2,
+	   dc->config_table.dl_mdm_len2);
+	DBG3("dl_diag_len0: 0x%04X, %d", dc->config_table.dl_diag_len1,
+	   dc->config_table.dl_diag_len1);
+	DBG3("dl_diag_len1: 0x%04X, %d", dc->config_table.dl_diag_len2,
+	   dc->config_table.dl_diag_len2);
+	DBG3("dl_app1_len: 0x%04X, %d", dc->config_table.dl_app1_len,
+	   dc->config_table.dl_app1_len);
+	DBG3("dl_app2_len: 0x%04X, %d", dc->config_table.dl_app2_len,
+	   dc->config_table.dl_app2_len);
+	DBG3("dl_ctrl_len: 0x%04X, %d", dc->config_table.dl_ctrl_len,
+	   dc->config_table.dl_ctrl_len);
+	DBG3("ul_start: 0x%04X, %d", dc->config_table.ul_start,
+	   dc->config_table.ul_start);
+	DBG3("ul_mdm_len[0]: 0x%04X, %d", dc->config_table.ul_mdm_len1,
+	   dc->config_table.ul_mdm_len1);
+	DBG3("ul_mdm_len[1]: 0x%04X, %d", dc->config_table.ul_mdm_len2,
+	   dc->config_table.ul_mdm_len2);
+	DBG3("ul_diag_len: 0x%04X, %d", dc->config_table.ul_diag_len,
+	   dc->config_table.ul_diag_len);
+	DBG3("ul_app1_len: 0x%04X, %d", dc->config_table.ul_app1_len,
+	   dc->config_table.ul_app1_len);
+	DBG3("ul_app2_len: 0x%04X, %d", dc->config_table.ul_app2_len,
+	   dc->config_table.ul_app2_len);
+	DBG3("ul_ctrl_len: 0x%04X, %d", dc->config_table.ul_ctrl_len,
+	   dc->config_table.ul_ctrl_len);
+}
+#else
+static __inline__ void dump_table(const struct nozomi *dc) { }
+#endif
+
+/*
+ * Read configuration table from card under intalization phase
+ * Returns 1 if ok, else 0
+ */
+static int nozomi_read_config_table(struct nozomi *dc)
+{
+	read_mem32((u32 *) &dc->config_table, dc->base_addr + 0,
+						sizeof(struct config_table));
+
+	if (dc->config_table.signature != CONFIG_MAGIC) {
+		dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n",
+			dc->config_table.signature, CONFIG_MAGIC);
+		return 0;
+	}
+
+	if ((dc->config_table.version == 0)
+	    || (dc->config_table.toggle.enabled == TOGGLE_VALID)) {
+		int i;
+		DBG1("Second phase, configuring card");
+
+		setup_memory(dc);
+
+		dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul;
+		dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl;
+		dc->port[PORT_DIAG].toggle_dl = dc->config_table.toggle.diag_dl;
+		DBG1("toggle ports: MDM UL:%d MDM DL:%d, DIAG DL:%d",
+		   dc->port[PORT_MDM].toggle_ul,
+		   dc->port[PORT_MDM].toggle_dl, dc->port[PORT_DIAG].toggle_dl);
+
+		dump_table(dc);
+
+		for (i = PORT_MDM; i < MAX_PORT; i++) {
+			dc->port[i].fifo_ul =
+			    kfifo_alloc(FIFO_BUFFER_SIZE_UL, GFP_ATOMIC, NULL);
+			memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl));
+			memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul));
+		}
+
+		/* Enable control channel */
+		dc->last_ier = dc->last_ier | CTRL_DL;
+		writew(dc->last_ier, dc->reg_ier);
+
+		dev_info(&dc->pdev->dev, "Initialization OK!\n");
+		return 1;
+	}
+
+	if ((dc->config_table.version > 0)
+	    && (dc->config_table.toggle.enabled != TOGGLE_VALID)) {
+		u32 offset = 0;
+		DBG1("First phase: pushing upload buffers, clearing download");
+
+		dev_info(&dc->pdev->dev, "Version of card: %d\n",
+			 dc->config_table.version);
+
+		/* Here we should disable all I/O over F32. */
+		setup_memory(dc);
+
+		/*
+		 * We should send ALL channel pair tokens back along
+		 * with reset token
+		 */
+
+		/* push upload modem buffers */
+		write_mem32(dc->port[PORT_MDM].ul_addr[CH_A],
+			(u32 *) &offset, 4);
+		write_mem32(dc->port[PORT_MDM].ul_addr[CH_B],
+			(u32 *) &offset, 4);
+
+		writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr);
+
+		DBG1("First phase done");
+	}
+
+	return 1;
+}
+
+/* Enable uplink interrupts  */
+static void enable_transmit_ul(enum port_type port, struct nozomi *dc)
+{
+	u16 mask[NOZOMI_MAX_PORTS] = \
+			{MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL};
+
+	if (port < NOZOMI_MAX_PORTS) {
+		dc->last_ier |= mask[port];
+		writew(dc->last_ier, dc->reg_ier);
+	} else {
+		dev_err(&dc->pdev->dev, "Called with wrong port?\n");
+	}
+}
+
+/* Disable uplink interrupts  */
+static void disable_transmit_ul(enum port_type port, struct nozomi *dc)
+{
+	u16 mask[NOZOMI_MAX_PORTS] = \
+			{~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL};
+
+	if (port < NOZOMI_MAX_PORTS) {
+		dc->last_ier &= mask[port];
+		writew(dc->last_ier, dc->reg_ier);
+	} else {
+		dev_err(&dc->pdev->dev, "Called with wrong port?\n");
+	}
+}
+
+/* Enable downlink interrupts */
+static void enable_transmit_dl(enum port_type port, struct nozomi *dc)
+{
+	u16 mask[NOZOMI_MAX_PORTS] = \
+			{MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL};
+
+	if (port < NOZOMI_MAX_PORTS) {
+		dc->last_ier |= mask[port];
+		writew(dc->last_ier, dc->reg_ier);
+	} else {
+		dev_err(&dc->pdev->dev, "Called with wrong port?\n");
+	}
+}
+
+/* Disable downlink interrupts */
+static void disable_transmit_dl(enum port_type port, struct nozomi *dc)
+{
+	u16 mask[NOZOMI_MAX_PORTS] = \
+			{~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL};
+
+	if (port < NOZOMI_MAX_PORTS) {
+		dc->last_ier &= mask[port];
+		writew(dc->last_ier, dc->reg_ier);
+	} else {
+		dev_err(&dc->pdev->dev, "Called with wrong port?\n");
+	}
+}
+
+/*
+ * Return 1 - send buffer to card and ack.
+ * Return 0 - don't ack, don't send buffer to card.
+ */
+static int send_data(enum port_type index, struct nozomi *dc)
+{
+	u32 size = 0;
+	struct port *port = &dc->port[index];
+	u8 toggle = port->toggle_ul;
+	void __iomem *addr = port->ul_addr[toggle];
+	u32 ul_size = port->ul_size[toggle];
+	struct tty_struct *tty = port->tty;
+
+	/* Get data from tty and place in buf for now */
+	size = __kfifo_get(port->fifo_ul, dc->send_buf,
+			   ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX);
+
+	if (size == 0) {
+		DBG4("No more data to send, disable link:");
+		return 0;
+	}
+
+	/* DUMP(buf, size); */
+
+	/* Write length + data */
+	write_mem32(addr, (u32 *) &size, 4);
+	write_mem32(addr + 4, (u32 *) dc->send_buf, size);
+
+	if (tty)
+		tty_wakeup(tty);
+
+	return 1;
+}
+
+/* If all data has been read, return 1, else 0 */
+static int receive_data(enum port_type index, struct nozomi *dc)
+{
+	u8 buf[RECEIVE_BUF_MAX] = { 0 };
+	int size;
+	u32 offset = 4;
+	struct port *port = &dc->port[index];
+	void __iomem *addr = port->dl_addr[port->toggle_dl];
+	struct tty_struct *tty = port->tty;
+	int i;
+
+	if (unlikely(!tty)) {
+		DBG1("tty not open for port: %d?", index);
+		return 1;
+	}
+
+	read_mem32((u32 *) &size, addr, 4);
+	/*  DBG1( "%d bytes port: %d", size, index); */
+
+	if (test_bit(TTY_THROTTLED, &tty->flags)) {
+		DBG1("No room in tty, don't read data, don't ack interrupt, "
+			"disable interrupt");
+
+		/* disable interrupt in downlink... */
+		disable_transmit_dl(index, dc);
+		return 0;
+	}
+
+	if (unlikely(size == 0)) {
+		dev_err(&dc->pdev->dev, "size == 0?\n");
+		return 1;
+	}
+
+	tty_buffer_request_room(tty, size);
+
+	while (size > 0) {
+		read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX);
+
+		if (size == 1) {
+			tty_insert_flip_char(tty, buf[0], TTY_NORMAL);
+			size = 0;
+		} else if (size < RECEIVE_BUF_MAX) {
+			size -= tty_insert_flip_string(tty, (char *) buf, size);
+		} else {
+			i = tty_insert_flip_string(tty, \
+						(char *) buf, RECEIVE_BUF_MAX);
+			size -= i;
+			offset += i;
+		}
+	}
+
+	set_bit(index, &dc->flip);
+
+	return 1;
+}
+
+/* Debug for interrupts */
+#ifdef DEBUG
+static char *interrupt2str(u16 interrupt)
+{
+	static char buf[TMP_BUF_MAX];
+	char *p = buf;
+
+	interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL;
+	interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"MDM_DL2 ") : NULL;
+
+	interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"MDM_UL1 ") : NULL;
+	interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"MDM_UL2 ") : NULL;
+
+	interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"DIAG_DL1 ") : NULL;
+	interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"DIAG_DL2 ") : NULL;
+
+	interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"DIAG_UL ") : NULL;
+
+	interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"APP1_DL ") : NULL;
+	interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"APP2_DL ") : NULL;
+
+	interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"APP1_UL ") : NULL;
+	interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"APP2_UL ") : NULL;
+
+	interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"CTRL_DL ") : NULL;
+	interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"CTRL_UL ") : NULL;
+
+	interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf),
+					"RESET ") : NULL;
+
+	return buf;
+}
+#endif
+
+/*
+ * Receive flow control
+ * Return 1 - If ok, else 0
+ */
+static int receive_flow_control(struct nozomi *dc)
+{
+	enum port_type port = PORT_MDM;
+	struct ctrl_dl ctrl_dl;
+	struct ctrl_dl old_ctrl;
+	u16 enable_ier = 0;
+
+	read_mem32((u32 *) &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2);
+
+	switch (ctrl_dl.port) {
+	case CTRL_CMD:
+		DBG1("The Base Band sends this value as a response to a "
+			"request for IMSI detach sent over the control "
+			"channel uplink (see section 7.6.1).");
+		break;
+	case CTRL_MDM:
+		port = PORT_MDM;
+		enable_ier = MDM_DL;
+		break;
+	case CTRL_DIAG:
+		port = PORT_DIAG;
+		enable_ier = DIAG_DL;
+		break;
+	case CTRL_APP1:
+		port = PORT_APP1;
+		enable_ier = APP1_DL;
+		break;
+	case CTRL_APP2:
+		port = PORT_APP2;
+		enable_ier = APP2_DL;
+		break;
+	default:
+		dev_err(&dc->pdev->dev,
+			"ERROR: flow control received for non-existing port\n");
+		return 0;
+	};
+
+	DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl),
+	   *((u16 *)&ctrl_dl));
+
+	old_ctrl = dc->port[port].ctrl_dl;
+	dc->port[port].ctrl_dl = ctrl_dl;
+
+	if (old_ctrl.CTS == 1 && ctrl_dl.CTS == 0) {
+		DBG1("Disable interrupt (0x%04X) on port: %d",
+			enable_ier, port);
+		disable_transmit_ul(port, dc);
+
+	} else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) {
+
+		if (__kfifo_len(dc->port[port].fifo_ul)) {
+			DBG1("Enable interrupt (0x%04X) on port: %d",
+				enable_ier, port);
+			DBG1("Data in buffer [%d], enable transmit! ",
+				__kfifo_len(dc->port[port].fifo_ul));
+			enable_transmit_ul(port, dc);
+		} else {
+			DBG1("No data in buffer...");
+		}
+	}
+
+	if (*(u16 *)&old_ctrl == *(u16 *)&ctrl_dl) {
+		DBG1(" No change in mctrl");
+		return 1;
+	}
+	/* Update statistics */
+	if (old_ctrl.CTS != ctrl_dl.CTS)
+		dc->port[port].tty_icount.cts++;
+	if (old_ctrl.DSR != ctrl_dl.DSR)
+		dc->port[port].tty_icount.dsr++;
+	if (old_ctrl.RI != ctrl_dl.RI)
+		dc->port[port].tty_icount.rng++;
+	if (old_ctrl.DCD != ctrl_dl.DCD)
+		dc->port[port].tty_icount.dcd++;
+
+	wake_up_interruptible(&dc->port[port].tty_wait);
+
+	DBG1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)",
+	   port,
+	   dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts,
+	   dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr);
+
+	return 1;
+}
+
+static enum ctrl_port_type port2ctrl(enum port_type port,
+					const struct nozomi *dc)
+{
+	switch (port) {
+	case PORT_MDM:
+		return CTRL_MDM;
+	case PORT_DIAG:
+		return CTRL_DIAG;
+	case PORT_APP1:
+		return CTRL_APP1;
+	case PORT_APP2:
+		return CTRL_APP2;
+	default:
+		dev_err(&dc->pdev->dev,
+			"ERROR: send flow control " \
+			"received for non-existing port\n");
+	};
+	return CTRL_ERROR;
+}
+
+/*
+ * Send flow control, can only update one channel at a time
+ * Return 0 - If we have updated all flow control
+ * Return 1 - If we need to update more flow control, ack current enable more
+ */
+static int send_flow_control(struct nozomi *dc)
+{
+	u32 i, more_flow_control_to_be_updated = 0;
+	u16 *ctrl;
+
+	for (i = PORT_MDM; i < MAX_PORT; i++) {
+		if (dc->port[i].update_flow_control) {
+			if (more_flow_control_to_be_updated) {
+				/* We have more flow control to be updated */
+				return 1;
+			}
+			dc->port[i].ctrl_ul.port = port2ctrl(i, dc);
+			ctrl = (u16 *)&dc->port[i].ctrl_ul;
+			write_mem32(dc->port[PORT_CTRL].ul_addr[0], \
+				(u32 *) ctrl, 2);
+			dc->port[i].update_flow_control = 0;
+			more_flow_control_to_be_updated = 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Handle donlink data, ports that are handled are modem and diagnostics
+ * Return 1 - ok
+ * Return 0 - toggle fields are out of sync
+ */
+static int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle,
+			u16 read_iir, u16 mask1, u16 mask2)
+{
+	if (*toggle == 0 && read_iir & mask1) {
+		if (receive_data(port, dc)) {
+			writew(mask1, dc->reg_fcr);
+			*toggle = !(*toggle);
+		}
+
+		if (read_iir & mask2) {
+			if (receive_data(port, dc)) {
+				writew(mask2, dc->reg_fcr);
+				*toggle = !(*toggle);
+			}
+		}
+	} else if (*toggle == 1 && read_iir & mask2) {
+		if (receive_data(port, dc)) {
+			writew(mask2, dc->reg_fcr);
+			*toggle = !(*toggle);
+		}
+
+		if (read_iir & mask1) {
+			if (receive_data(port, dc)) {
+				writew(mask1, dc->reg_fcr);
+				*toggle = !(*toggle);
+			}
+		}
+	} else {
+		dev_err(&dc->pdev->dev, "port out of sync!, toggle:%d\n",
+			*toggle);
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * Handle uplink data, this is currently for the modem port
+ * Return 1 - ok
+ * Return 0 - toggle field are out of sync
+ */
+static int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir)
+{
+	u8 *toggle = &(dc->port[port].toggle_ul);
+
+	if (*toggle == 0 && read_iir & MDM_UL1) {
+		dc->last_ier &= ~MDM_UL;
+		writew(dc->last_ier, dc->reg_ier);
+		if (send_data(port, dc)) {
+			writew(MDM_UL1, dc->reg_fcr);
+			dc->last_ier = dc->last_ier | MDM_UL;
+			writew(dc->last_ier, dc->reg_ier);
+			*toggle = !*toggle;
+		}
+
+		if (read_iir & MDM_UL2) {
+			dc->last_ier &= ~MDM_UL;
+			writew(dc->last_ier, dc->reg_ier);
+			if (send_data(port, dc)) {
+				writew(MDM_UL2, dc->reg_fcr);
+				dc->last_ier = dc->last_ier | MDM_UL;
+				writew(dc->last_ier, dc->reg_ier);
+				*toggle = !*toggle;
+			}
+		}
+
+	} else if (*toggle == 1 && read_iir & MDM_UL2) {
+		dc->last_ier &= ~MDM_UL;
+		writew(dc->last_ier, dc->reg_ier);
+		if (send_data(port, dc)) {
+			writew(MDM_UL2, dc->reg_fcr);
+			dc->last_ier = dc->last_ier | MDM_UL;
+			writew(dc->last_ier, dc->reg_ier);
+			*toggle = !*toggle;
+		}
+
+		if (read_iir & MDM_UL1) {
+			dc->last_ier &= ~MDM_UL;
+			writew(dc->last_ier, dc->reg_ier);
+			if (send_data(port, dc)) {
+				writew(MDM_UL1, dc->reg_fcr);
+				dc->last_ier = dc->last_ier | MDM_UL;
+				writew(dc->last_ier, dc->reg_ier);
+				*toggle = !*toggle;
+			}
+		}
+	} else {
+		writew(read_iir & MDM_UL, dc->reg_fcr);
+		dev_err(&dc->pdev->dev, "port out of sync!\n");
+		return 0;
+	}
+	return 1;
+}
+
+static irqreturn_t interrupt_handler(int irq, void *dev_id)
+{
+	struct nozomi *dc = dev_id;
+	unsigned int a;
+	u16 read_iir;
+
+	if (!dc)
+		return IRQ_NONE;
+
+	spin_lock(&dc->spin_mutex);
+	read_iir = readw(dc->reg_iir);
+
+	/* Card removed */
+	if (read_iir == (u16)-1)
+		goto none;
+	/*
+	 * Just handle interrupt enabled in IER
+	 * (by masking with dc->last_ier)
+	 */
+	read_iir &= dc->last_ier;
+
+	if (read_iir == 0)
+		goto none;
+
+
+	DBG4("%s irq:0x%04X, prev:0x%04X", interrupt2str(read_iir), read_iir,
+		dc->last_ier);
+
+	if (read_iir & RESET) {
+		if (unlikely(!nozomi_read_config_table(dc))) {
+			dc->last_ier = 0x0;
+			writew(dc->last_ier, dc->reg_ier);
+			dev_err(&dc->pdev->dev, "Could not read status from "
+				"card, we should disable interface\n");
+		} else {
+			writew(RESET, dc->reg_fcr);
+		}
+		/* No more useful info if this was the reset interrupt. */
+		goto exit_handler;
+	}
+	if (read_iir & CTRL_UL) {
+		DBG1("CTRL_UL");
+		dc->last_ier &= ~CTRL_UL;
+		writew(dc->last_ier, dc->reg_ier);
+		if (send_flow_control(dc)) {
+			writew(CTRL_UL, dc->reg_fcr);
+			dc->last_ier = dc->last_ier | CTRL_UL;
+			writew(dc->last_ier, dc->reg_ier);
+		}
+	}
+	if (read_iir & CTRL_DL) {
+		receive_flow_control(dc);
+		writew(CTRL_DL, dc->reg_fcr);
+	}
+	if (read_iir & MDM_DL) {
+		if (!handle_data_dl(dc, PORT_MDM,
+				&(dc->port[PORT_MDM].toggle_dl), read_iir,
+				MDM_DL1, MDM_DL2)) {
+			dev_err(&dc->pdev->dev, "MDM_DL out of sync!\n");
+			goto exit_handler;
+		}
+	}
+	if (read_iir & MDM_UL) {
+		if (!handle_data_ul(dc, PORT_MDM, read_iir)) {
+			dev_err(&dc->pdev->dev, "MDM_UL out of sync!\n");
+			goto exit_handler;
+		}
+	}
+	if (read_iir & DIAG_DL) {
+		if (!handle_data_dl(dc, PORT_DIAG,
+				&(dc->port[PORT_DIAG].toggle_dl), read_iir,
+				DIAG_DL1, DIAG_DL2)) {
+			dev_err(&dc->pdev->dev, "DIAG_DL out of sync!\n");
+			goto exit_handler;
+		}
+	}
+	if (read_iir & DIAG_UL) {
+		dc->last_ier &= ~DIAG_UL;
+		writew(dc->last_ier, dc->reg_ier);
+		if (send_data(PORT_DIAG, dc)) {
+			writew(DIAG_UL, dc->reg_fcr);
+			dc->last_ier = dc->last_ier | DIAG_UL;
+			writew(dc->last_ier, dc->reg_ier);
+		}
+	}
+	if (read_iir & APP1_DL) {
+		if (receive_data(PORT_APP1, dc))
+			writew(APP1_DL, dc->reg_fcr);
+	}
+	if (read_iir & APP1_UL) {
+		dc->last_ier &= ~APP1_UL;
+		writew(dc->last_ier, dc->reg_ier);
+		if (send_data(PORT_APP1, dc)) {
+			writew(APP1_UL, dc->reg_fcr);
+			dc->last_ier = dc->last_ier | APP1_UL;
+			writew(dc->last_ier, dc->reg_ier);
+		}
+	}
+	if (read_iir & APP2_DL) {
+		if (receive_data(PORT_APP2, dc))
+			writew(APP2_DL, dc->reg_fcr);
+	}
+	if (read_iir & APP2_UL) {
+		dc->last_ier &= ~APP2_UL;
+		writew(dc->last_ier, dc->reg_ier);
+		if (send_data(PORT_APP2, dc)) {
+			writew(APP2_UL, dc->reg_fcr);
+			dc->last_ier = dc->last_ier | APP2_UL;
+			writew(dc->last_ier, dc->reg_ier);
+		}
+	}
+
+exit_handler:
+	spin_unlock(&dc->spin_mutex);
+	for (a = 0; a < NOZOMI_MAX_PORTS; a++)
+		if (test_and_clear_bit(a, &dc->flip))
+			tty_flip_buffer_push(dc->port[a].tty);
+	return IRQ_HANDLED;
+none:
+	spin_unlock(&dc->spin_mutex);
+	return IRQ_NONE;
+}
+
+static void nozomi_get_card_type(struct nozomi *dc)
+{
+	int i;
+	u32 size = 0;
+
+	for (i = 0; i < 6; i++)
+		size += pci_resource_len(dc->pdev, i);
+
+	/* Assume card type F32_8 if no match */
+	dc->card_type = size == 2048 ? F32_2 : F32_8;
+
+	dev_info(&dc->pdev->dev, "Card type is: %d\n", dc->card_type);
+}
+
+static void nozomi_setup_private_data(struct nozomi *dc)
+{
+	void __iomem *offset = dc->base_addr + dc->card_type / 2;
+	unsigned int i;
+
+	dc->reg_fcr = (void __iomem *)(offset + R_FCR);
+	dc->reg_iir = (void __iomem *)(offset + R_IIR);
+	dc->reg_ier = (void __iomem *)(offset + R_IER);
+	dc->last_ier = 0;
+	dc->flip = 0;
+
+	dc->port[PORT_MDM].token_dl = MDM_DL;
+	dc->port[PORT_DIAG].token_dl = DIAG_DL;
+	dc->port[PORT_APP1].token_dl = APP1_DL;
+	dc->port[PORT_APP2].token_dl = APP2_DL;
+
+	for (i = 0; i < MAX_PORT; i++)
+		init_waitqueue_head(&dc->port[i].tty_wait);
+}
+
+static ssize_t card_type_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
+
+	return sprintf(buf, "%d\n", dc->card_type);
+}
+static DEVICE_ATTR(card_type, 0444, card_type_show, NULL);
+
+static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev));
+
+	return sprintf(buf, "%u\n", dc->open_ttys);
+}
+static DEVICE_ATTR(open_ttys, 0444, open_ttys_show, NULL);
+
+static void make_sysfs_files(struct nozomi *dc)
+{
+	if (device_create_file(&dc->pdev->dev, &dev_attr_card_type))
+		dev_err(&dc->pdev->dev,
+			"Could not create sysfs file for card_type\n");
+	if (device_create_file(&dc->pdev->dev, &dev_attr_open_ttys))
+		dev_err(&dc->pdev->dev,
+			"Could not create sysfs file for open_ttys\n");
+}
+
+static void remove_sysfs_files(struct nozomi *dc)
+{
+	device_remove_file(&dc->pdev->dev, &dev_attr_card_type);
+	device_remove_file(&dc->pdev->dev, &dev_attr_open_ttys);
+}
+
+/* Allocate memory for one device */
+static int __devinit nozomi_card_init(struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	resource_size_t start;
+	int ret;
+	struct nozomi *dc = NULL;
+	int ndev_idx;
+	int i;
+
+	dev_dbg(&pdev->dev, "Init, new card found\n");
+
+	for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++)
+		if (!ndevs[ndev_idx])
+			break;
+
+	if (ndev_idx >= ARRAY_SIZE(ndevs)) {
+		dev_err(&pdev->dev, "no free tty range for this card left\n");
+		ret = -EIO;
+		goto err;
+	}
+
+	dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL);
+	if (unlikely(!dc)) {
+		dev_err(&pdev->dev, "Could not allocate memory\n");
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
+	dc->pdev = pdev;
+
+	/* Find out what card type it is */
+	nozomi_get_card_type(dc);
+
+	ret = pci_enable_device(dc->pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to enable PCI Device\n");
+		goto err_free;
+	}
+
+	start = pci_resource_start(dc->pdev, 0);
+	if (start == 0) {
+		dev_err(&pdev->dev, "No I/O address for card detected\n");
+		ret = -ENODEV;
+		goto err_disable_device;
+	}
+
+	ret = pci_request_regions(dc->pdev, NOZOMI_NAME);
+	if (ret) {
+		dev_err(&pdev->dev, "I/O address 0x%04x already in use\n",
+			(int) /* nozomi_private.io_addr */ 0);
+		goto err_disable_device;
+	}
+
+	dc->base_addr = ioremap(start, dc->card_type);
+	if (!dc->base_addr) {
+		dev_err(&pdev->dev, "Unable to map card MMIO\n");
+		ret = -ENODEV;
+		goto err_rel_regs;
+	}
+
+	dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL);
+	if (!dc->send_buf) {
+		dev_err(&pdev->dev, "Could not allocate send buffer?\n");
+		ret = -ENOMEM;
+		goto err_free_sbuf;
+	}
+
+	spin_lock_init(&dc->spin_mutex);
+
+	nozomi_setup_private_data(dc);
+
+	/* Disable all interrupts */
+	dc->last_ier = 0;
+	writew(dc->last_ier, dc->reg_ier);
+
+	ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED,
+			NOZOMI_NAME, dc);
+	if (unlikely(ret)) {
+		dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq);
+		goto err_free_sbuf;
+	}
+
+	DBG1("base_addr: %p", dc->base_addr);
+
+	make_sysfs_files(dc);
+
+	dc->index_start = ndev_idx * MAX_PORT;
+	ndevs[ndev_idx] = dc;
+
+	for (i = 0; i < MAX_PORT; i++) {
+		mutex_init(&dc->port[i].tty_sem);
+		dc->port[i].tty_open_count = 0;
+		dc->port[i].tty = NULL;
+		tty_register_device(ntty_driver, dc->index_start + i,
+							&pdev->dev);
+	}
+
+	/* Enable  RESET interrupt. */
+	dc->last_ier = RESET;
+	writew(dc->last_ier, dc->reg_ier);
+
+	pci_set_drvdata(pdev, dc);
+
+	return 0;
+
+err_free_sbuf:
+	kfree(dc->send_buf);
+	iounmap(dc->base_addr);
+err_rel_regs:
+	pci_release_regions(pdev);
+err_disable_device:
+	pci_disable_device(pdev);
+err_free:
+	kfree(dc);
+err:
+	return ret;
+}
+
+static void __devexit tty_exit(struct nozomi *dc)
+{
+	unsigned int i;
+
+	DBG1(" ");
+
+	flush_scheduled_work();
+
+	for (i = 0; i < MAX_PORT; ++i)
+		if (dc->port[i].tty && \
+				list_empty(&dc->port[i].tty->hangup_work.entry))
+			tty_hangup(dc->port[i].tty);
+
+	while (dc->open_ttys)
+		msleep(1);
+
+	for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i)
+		tty_unregister_device(ntty_driver, i);
+}
+
+/* Deallocate memory for one device */
+static void __devexit nozomi_card_exit(struct pci_dev *pdev)
+{
+	int i;
+	struct ctrl_ul ctrl;
+	struct nozomi *dc = pci_get_drvdata(pdev);
+
+	/* Disable all interrupts */
+	dc->last_ier = 0;
+	writew(dc->last_ier, dc->reg_ier);
+
+	tty_exit(dc);
+
+	/* Send 0x0001, command card to resend the reset token.  */
+	/* This is to get the reset when the module is reloaded. */
+	ctrl.port = 0x00;
+	ctrl.reserved = 0;
+	ctrl.RTS = 0;
+	ctrl.DTR = 1;
+	DBG1("sending flow control 0x%04X", *((u16 *)&ctrl));
+
+	/* Setup dc->reg addresses to we can use defines here */
+	write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2);
+	writew(CTRL_UL, dc->reg_fcr);	/* push the token to the card. */
+
+	remove_sysfs_files(dc);
+
+	free_irq(pdev->irq, dc);
+
+	for (i = 0; i < MAX_PORT; i++)
+		if (dc->port[i].fifo_ul)
+			kfifo_free(dc->port[i].fifo_ul);
+
+	kfree(dc->send_buf);
+
+	iounmap(dc->base_addr);
+
+	pci_release_regions(pdev);
+
+	pci_disable_device(pdev);
+
+	ndevs[dc->index_start / MAX_PORT] = NULL;
+
+	kfree(dc);
+}
+
+static void set_rts(const struct tty_struct *tty, int rts)
+{
+	struct port *port = get_port_by_tty(tty);
+
+	port->ctrl_ul.RTS = rts;
+	port->update_flow_control = 1;
+	enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty));
+}
+
+static void set_dtr(const struct tty_struct *tty, int dtr)
+{
+	struct port *port = get_port_by_tty(tty);
+
+	DBG1("SETTING DTR index: %d, dtr: %d", tty->index, dtr);
+
+	port->ctrl_ul.DTR = dtr;
+	port->update_flow_control = 1;
+	enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty));
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * TTY code
+ * ----------------------------------------------------------------------------
+ */
+
+/* Called when the userspace process opens the tty, /dev/noz*.  */
+static int ntty_open(struct tty_struct *tty, struct file *file)
+{
+	struct port *port = get_port_by_tty(tty);
+	struct nozomi *dc = get_dc_by_tty(tty);
+	unsigned long flags;
+
+	if (!port || !dc)
+		return -ENODEV;
+
+	if (mutex_lock_interruptible(&port->tty_sem))
+		return -ERESTARTSYS;
+
+	port->tty_open_count++;
+	dc->open_ttys++;
+
+	/* Enable interrupt downlink for channel */
+	if (port->tty_open_count == 1) {
+		tty->low_latency = 1;
+		tty->driver_data = port;
+		port->tty = tty;
+		DBG1("open: %d", port->token_dl);
+		spin_lock_irqsave(&dc->spin_mutex, flags);
+		dc->last_ier = dc->last_ier | port->token_dl;
+		writew(dc->last_ier, dc->reg_ier);
+		spin_unlock_irqrestore(&dc->spin_mutex, flags);
+	}
+
+	mutex_unlock(&port->tty_sem);
+
+	return 0;
+}
+
+/* Called when the userspace process close the tty, /dev/noz*. */
+static void ntty_close(struct tty_struct *tty, struct file *file)
+{
+	struct nozomi *dc = get_dc_by_tty(tty);
+	struct port *port = tty->driver_data;
+	unsigned long flags;
+
+	if (!dc || !port)
+		return;
+
+	if (mutex_lock_interruptible(&port->tty_sem))
+		return;
+
+	if (!port->tty_open_count)
+		goto exit;
+
+	dc->open_ttys--;
+	port->tty_open_count--;
+
+	if (port->tty_open_count == 0) {
+		DBG1("close: %d", port->token_dl);
+		spin_lock_irqsave(&dc->spin_mutex, flags);
+		dc->last_ier &= ~(port->token_dl);
+		writew(dc->last_ier, dc->reg_ier);
+		spin_unlock_irqrestore(&dc->spin_mutex, flags);
+	}
+
+exit:
+	mutex_unlock(&port->tty_sem);
+}
+
+/*
+ * called when the userspace process writes to the tty (/dev/noz*).
+ * Data is inserted into a fifo, which is then read and transfered to the modem.
+ */
+static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
+		      int count)
+{
+	int rval = -EINVAL;
+	struct nozomi *dc = get_dc_by_tty(tty);
+	struct port *port = tty->driver_data;
+	unsigned long flags;
+
+	/* DBG1( "WRITEx: %d, index = %d", count, index); */
+
+	if (!dc || !port)
+		return -ENODEV;
+
+	if (unlikely(!mutex_trylock(&port->tty_sem))) {
+		/*
+		 * must test lock as tty layer wraps calls
+		 * to this function with BKL
+		 */
+		dev_err(&dc->pdev->dev, "Would have deadlocked - "
+			"return EAGAIN\n");
+		return -EAGAIN;
+	}
+
+	if (unlikely(!port->tty_open_count)) {
+		DBG1(" ");
+		goto exit;
+	}
+
+	rval = __kfifo_put(port->fifo_ul, (unsigned char *)buffer, count);
+
+	/* notify card */
+	if (unlikely(dc == NULL)) {
+		DBG1("No device context?");
+		goto exit;
+	}
+
+	spin_lock_irqsave(&dc->spin_mutex, flags);
+	/* CTS is only valid on the modem channel */
+	if (port == &(dc->port[PORT_MDM])) {
+		if (port->ctrl_dl.CTS) {
+			DBG4("Enable interrupt");
+			enable_transmit_ul(tty->index % MAX_PORT, dc);
+		} else {
+			dev_err(&dc->pdev->dev,
+				"CTS not active on modem port?\n");
+		}
+	} else {
+		enable_transmit_ul(tty->index % MAX_PORT, dc);
+	}
+	spin_unlock_irqrestore(&dc->spin_mutex, flags);
+
+exit:
+	mutex_unlock(&port->tty_sem);
+	return rval;
+}
+
+/*
+ * Calculate how much is left in device
+ * This method is called by the upper tty layer.
+ *   #according to sources N_TTY.c it expects a value >= 0 and
+ *    does not check for negative values.
+ */
+static int ntty_write_room(struct tty_struct *tty)
+{
+	struct port *port = tty->driver_data;
+	int room = 0;
+	struct nozomi *dc = get_dc_by_tty(tty);
+
+	if (!dc || !port)
+		return 0;
+	if (!mutex_trylock(&port->tty_sem))
+		return 0;
+
+	if (!port->tty_open_count)
+		goto exit;
+
+	room = port->fifo_ul->size - __kfifo_len(port->fifo_ul);
+
+exit:
+	mutex_unlock(&port->tty_sem);
+	return room;
+}
+
+/* Gets io control parameters */
+static int ntty_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct port *port = tty->driver_data;
+	struct ctrl_dl *ctrl_dl = &port->ctrl_dl;
+	struct ctrl_ul *ctrl_ul = &port->ctrl_ul;
+
+	return	(ctrl_ul->RTS ? TIOCM_RTS : 0) |
+		(ctrl_ul->DTR ? TIOCM_DTR : 0) |
+		(ctrl_dl->DCD ? TIOCM_CAR : 0) |
+		(ctrl_dl->RI  ? TIOCM_RNG : 0) |
+		(ctrl_dl->DSR ? TIOCM_DSR : 0) |
+		(ctrl_dl->CTS ? TIOCM_CTS : 0);
+}
+
+/* Sets io controls parameters */
+static int ntty_tiocmset(struct tty_struct *tty, struct file *file,
+	unsigned int set, unsigned int clear)
+{
+	if (set & TIOCM_RTS)
+		set_rts(tty, 1);
+	else if (clear & TIOCM_RTS)
+		set_rts(tty, 0);
+
+	if (set & TIOCM_DTR)
+		set_dtr(tty, 1);
+	else if (clear & TIOCM_DTR)
+		set_dtr(tty, 0);
+
+	return 0;
+}
+
+static int ntty_cflags_changed(struct port *port, unsigned long flags,
+		struct async_icount *cprev)
+{
+	struct async_icount cnow = port->tty_icount;
+	int ret;
+
+	ret =	((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
+		((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
+		((flags & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) ||
+		((flags & TIOCM_CTS) && (cnow.cts != cprev->cts));
+
+	*cprev = cnow;
+
+	return ret;
+}
+
+static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp)
+{
+	struct async_icount cnow = port->tty_icount;
+	struct serial_icounter_struct icount;
+
+	icount.cts = cnow.cts;
+	icount.dsr = cnow.dsr;
+	icount.rng = cnow.rng;
+	icount.dcd = cnow.dcd;
+	icount.rx = cnow.rx;
+	icount.tx = cnow.tx;
+	icount.frame = cnow.frame;
+	icount.overrun = cnow.overrun;
+	icount.parity = cnow.parity;
+	icount.brk = cnow.brk;
+	icount.buf_overrun = cnow.buf_overrun;
+
+	return copy_to_user(argp, &icount, sizeof(icount));
+}
+
+static int ntty_ioctl(struct tty_struct *tty, struct file *file,
+		      unsigned int cmd, unsigned long arg)
+{
+	struct port *port = tty->driver_data;
+	void __user *argp = (void __user *)arg;
+	int rval = -ENOIOCTLCMD;
+
+	DBG1("******** IOCTL, cmd: %d", cmd);
+
+	switch (cmd) {
+	case TIOCMIWAIT: {
+		struct async_icount cprev = port->tty_icount;
+
+		rval = wait_event_interruptible(port->tty_wait,
+				ntty_cflags_changed(port, arg, &cprev));
+		break;
+	} case TIOCGICOUNT:
+		rval = ntty_ioctl_tiocgicount(port, argp);
+		break;
+	default:
+		DBG1("ERR: 0x%08X, %d", cmd, cmd);
+		break;
+	};
+
+	return rval;
+}
+
+/*
+ * Called by the upper tty layer when tty buffers are ready
+ * to receive data again after a call to throttle.
+ */
+static void ntty_unthrottle(struct tty_struct *tty)
+{
+	struct nozomi *dc = get_dc_by_tty(tty);
+	unsigned long flags;
+
+	DBG1("UNTHROTTLE");
+	spin_lock_irqsave(&dc->spin_mutex, flags);
+	enable_transmit_dl(tty->index % MAX_PORT, dc);
+	set_rts(tty, 1);
+
+	spin_unlock_irqrestore(&dc->spin_mutex, flags);
+}
+
+/*
+ * Called by the upper tty layer when the tty buffers are almost full.
+ * The driver should stop send more data.
+ */
+static void ntty_throttle(struct tty_struct *tty)
+{
+	struct nozomi *dc = get_dc_by_tty(tty);
+	unsigned long flags;
+
+	DBG1("THROTTLE");
+	spin_lock_irqsave(&dc->spin_mutex, flags);
+	set_rts(tty, 0);
+	spin_unlock_irqrestore(&dc->spin_mutex, flags);
+}
+
+/* just to discard single character writes */
+static void ntty_put_char(struct tty_struct *tty, unsigned char c)
+{
+	/* FIXME !!! */
+	DBG2("PUT CHAR Function: %c", c);
+}
+
+/* Returns number of chars in buffer, called by tty layer */
+static s32 ntty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct port *port = tty->driver_data;
+	struct nozomi *dc = get_dc_by_tty(tty);
+	s32 rval;
+
+	if (unlikely(!dc || !port)) {
+		rval = -ENODEV;
+		goto exit_in_buffer;
+	}
+
+	if (unlikely(!port->tty_open_count)) {
+		dev_err(&dc->pdev->dev, "No tty open?\n");
+		rval = -ENODEV;
+		goto exit_in_buffer;
+	}
+
+	rval = __kfifo_len(port->fifo_ul);
+
+exit_in_buffer:
+	return rval;
+}
+
+static struct tty_operations tty_ops = {
+	.ioctl = ntty_ioctl,
+	.open = ntty_open,
+	.close = ntty_close,
+	.write = ntty_write,
+	.write_room = ntty_write_room,
+	.unthrottle = ntty_unthrottle,
+	.throttle = ntty_throttle,
+	.chars_in_buffer = ntty_chars_in_buffer,
+	.put_char = ntty_put_char,
+	.tiocmget = ntty_tiocmget,
+	.tiocmset = ntty_tiocmset,
+};
+
+/* Module initialization */
+static struct pci_driver nozomi_driver = {
+	.name = NOZOMI_NAME,
+	.id_table = nozomi_pci_tbl,
+	.probe = nozomi_card_init,
+	.remove = __devexit_p(nozomi_card_exit),
+};
+
+static __init int nozomi_init(void)
+{
+	int ret;
+
+	printk(KERN_INFO "Initializing %s\n", VERSION_STRING);
+
+	ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS);
+	if (!ntty_driver)
+		return -ENOMEM;
+
+	ntty_driver->owner = THIS_MODULE;
+	ntty_driver->driver_name = NOZOMI_NAME_TTY;
+	ntty_driver->name = "noz";
+	ntty_driver->major = 0;
+	ntty_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	ntty_driver->subtype = SERIAL_TYPE_NORMAL;
+	ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	ntty_driver->init_termios = tty_std_termios;
+	ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \
+						HUPCL | CLOCAL;
+	ntty_driver->init_termios.c_ispeed = 115200;
+	ntty_driver->init_termios.c_ospeed = 115200;
+	tty_set_operations(ntty_driver, &tty_ops);
+
+	ret = tty_register_driver(ntty_driver);
+	if (ret) {
+		printk(KERN_ERR "Nozomi: failed to register ntty driver\n");
+		goto free_tty;
+	}
+
+	ret = pci_register_driver(&nozomi_driver);
+	if (ret) {
+		printk(KERN_ERR "Nozomi: can't register pci driver\n");
+		goto unr_tty;
+	}
+
+	return 0;
+unr_tty:
+	tty_unregister_driver(ntty_driver);
+free_tty:
+	put_tty_driver(ntty_driver);
+	return ret;
+}
+
+static __exit void nozomi_exit(void)
+{
+	printk(KERN_INFO "Unloading %s\n", DRIVER_DESC);
+	pci_unregister_driver(&nozomi_driver);
+	tty_unregister_driver(ntty_driver);
+	put_tty_driver(ntty_driver);
+}
+
+module_init(nozomi_init);
+module_exit(nozomi_exit);
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 0c66b802736a..78b151c4d20f 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -1,5 +1,5 @@
 /*
- *	Real Time Clock interface for Linux	
+ *	Real Time Clock interface for Linux
  *
  *	Copyright (C) 1996 Paul Gortmaker
  *
@@ -17,7 +17,7 @@
  *	has been received. If a RTC interrupt has already happened,
  *	it will output an unsigned long and then block. The output value
  *	contains the interrupt status in the low byte and the number of
- *	interrupts since the last read in the remaining high bytes. The 
+ *	interrupts since the last read in the remaining high bytes. The
  *	/dev/rtc interface can also be used with the select(2) call.
  *
  *	This program is free software; you can redistribute it and/or
@@ -104,12 +104,14 @@ static int rtc_has_irq = 1;
 
 #ifndef CONFIG_HPET_EMULATE_RTC
 #define is_hpet_enabled()			0
-#define hpet_set_alarm_time(hrs, min, sec) 	0
-#define hpet_set_periodic_freq(arg) 		0
-#define hpet_mask_rtc_irq_bit(arg) 		0
-#define hpet_set_rtc_irq_bit(arg) 		0
-#define hpet_rtc_timer_init() 			do { } while (0)
-#define hpet_rtc_dropped_irq() 			0
+#define hpet_set_alarm_time(hrs, min, sec)	0
+#define hpet_set_periodic_freq(arg)		0
+#define hpet_mask_rtc_irq_bit(arg)		0
+#define hpet_set_rtc_irq_bit(arg)		0
+#define hpet_rtc_timer_init()			do { } while (0)
+#define hpet_rtc_dropped_irq()			0
+#define hpet_register_irq_handler(h)		0
+#define hpet_unregister_irq_handler(h)		0
 #ifdef RTC_IRQ
 static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
 {
@@ -147,7 +149,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file,
 static unsigned int rtc_poll(struct file *file, poll_table *wait);
 #endif
 
-static void get_rtc_alm_time (struct rtc_time *alm_tm);
+static void get_rtc_alm_time(struct rtc_time *alm_tm);
 #ifdef RTC_IRQ
 static void set_rtc_irq_bit_locked(unsigned char bit);
 static void mask_rtc_irq_bit_locked(unsigned char bit);
@@ -185,9 +187,9 @@ static int rtc_proc_open(struct inode *inode, struct file *file);
  * rtc_status but before mod_timer is called, which would then reenable the
  * timer (but you would need to have an awful timing before you'd trip on it)
  */
-static unsigned long rtc_status = 0;	/* bitmapped status byte.	*/
-static unsigned long rtc_freq = 0;	/* Current periodic IRQ rate	*/
-static unsigned long rtc_irq_data = 0;	/* our output to the world	*/
+static unsigned long rtc_status;	/* bitmapped status byte.	*/
+static unsigned long rtc_freq;		/* Current periodic IRQ rate	*/
+static unsigned long rtc_irq_data;	/* our output to the world	*/
 static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */
 
 #ifdef RTC_IRQ
@@ -195,7 +197,7 @@ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */
  * rtc_task_lock nests inside rtc_lock.
  */
 static DEFINE_SPINLOCK(rtc_task_lock);
-static rtc_task_t *rtc_callback = NULL;
+static rtc_task_t *rtc_callback;
 #endif
 
 /*
@@ -205,7 +207,7 @@ static rtc_task_t *rtc_callback = NULL;
 
 static unsigned long epoch = 1900;	/* year corresponding to 0x00	*/
 
-static const unsigned char days_in_mo[] = 
+static const unsigned char days_in_mo[] =
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
 /*
@@ -242,7 +244,7 @@ irqreturn_t rtc_interrupt(int irq, void *dev_id)
 	 *	the last read in the remainder of rtc_irq_data.
 	 */
 
-	spin_lock (&rtc_lock);
+	spin_lock(&rtc_lock);
 	rtc_irq_data += 0x100;
 	rtc_irq_data &= ~0xff;
 	if (is_hpet_enabled()) {
@@ -259,16 +261,16 @@ irqreturn_t rtc_interrupt(int irq, void *dev_id)
 	if (rtc_status & RTC_TIMER_ON)
 		mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
 
-	spin_unlock (&rtc_lock);
+	spin_unlock(&rtc_lock);
 
 	/* Now do the rest of the actions */
 	spin_lock(&rtc_task_lock);
 	if (rtc_callback)
 		rtc_callback->func(rtc_callback->private_data);
 	spin_unlock(&rtc_task_lock);
-	wake_up_interruptible(&rtc_wait);	
+	wake_up_interruptible(&rtc_wait);
 
-	kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
+	kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
 
 	return IRQ_HANDLED;
 }
@@ -335,7 +337,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long data;
 	ssize_t retval;
-	
+
 	if (rtc_has_irq == 0)
 		return -EIO;
 
@@ -358,11 +360,11 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
 		 * confusing. And no, xchg() is not the answer. */
 
 		__set_current_state(TASK_INTERRUPTIBLE);
-		
-		spin_lock_irq (&rtc_lock);
+
+		spin_lock_irq(&rtc_lock);
 		data = rtc_irq_data;
 		rtc_irq_data = 0;
-		spin_unlock_irq (&rtc_lock);
+		spin_unlock_irq(&rtc_lock);
 
 		if (data != 0)
 			break;
@@ -378,10 +380,13 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
 		schedule();
 	} while (1);
 
-	if (count == sizeof(unsigned int))
-		retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int);
-	else
-		retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long);
+	if (count == sizeof(unsigned int)) {
+		retval = put_user(data,
+				  (unsigned int __user *)buf) ?: sizeof(int);
+	} else {
+		retval = put_user(data,
+				  (unsigned long __user *)buf) ?: sizeof(long);
+	}
 	if (!retval)
 		retval = count;
  out:
@@ -394,7 +399,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
 
 static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 {
-	struct rtc_time wtime; 
+	struct rtc_time wtime;
 
 #ifdef RTC_IRQ
 	if (rtc_has_irq == 0) {
@@ -426,35 +431,41 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 	}
 	case RTC_PIE_OFF:	/* Mask periodic int. enab. bit	*/
 	{
-		unsigned long flags; /* can be called from isr via rtc_control() */
-		spin_lock_irqsave (&rtc_lock, flags);
+		/* can be called from isr via rtc_control() */
+		unsigned long flags;
+
+		spin_lock_irqsave(&rtc_lock, flags);
 		mask_rtc_irq_bit_locked(RTC_PIE);
 		if (rtc_status & RTC_TIMER_ON) {
 			rtc_status &= ~RTC_TIMER_ON;
 			del_timer(&rtc_irq_timer);
 		}
-		spin_unlock_irqrestore (&rtc_lock, flags);
+		spin_unlock_irqrestore(&rtc_lock, flags);
+
 		return 0;
 	}
 	case RTC_PIE_ON:	/* Allow periodic ints		*/
 	{
-		unsigned long flags; /* can be called from isr via rtc_control() */
+		/* can be called from isr via rtc_control() */
+		unsigned long flags;
+
 		/*
 		 * We don't really want Joe User enabling more
 		 * than 64Hz of interrupts on a multi-user machine.
 		 */
 		if (!kernel && (rtc_freq > rtc_max_user_freq) &&
-			(!capable(CAP_SYS_RESOURCE)))
+						(!capable(CAP_SYS_RESOURCE)))
 			return -EACCES;
 
-		spin_lock_irqsave (&rtc_lock, flags);
+		spin_lock_irqsave(&rtc_lock, flags);
 		if (!(rtc_status & RTC_TIMER_ON)) {
 			mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq +
 					2*HZ/100);
 			rtc_status |= RTC_TIMER_ON;
 		}
 		set_rtc_irq_bit_locked(RTC_PIE);
-		spin_unlock_irqrestore (&rtc_lock, flags);
+		spin_unlock_irqrestore(&rtc_lock, flags);
+
 		return 0;
 	}
 	case RTC_UIE_OFF:	/* Mask ints from RTC updates.	*/
@@ -477,7 +488,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 		 */
 		memset(&wtime, 0, sizeof(struct rtc_time));
 		get_rtc_alm_time(&wtime);
-		break; 
+		break;
 	}
 	case RTC_ALM_SET:	/* Store a time into the alarm */
 	{
@@ -505,16 +516,21 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 			 */
 		}
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
-		    RTC_ALWAYS_BCD)
-		{
-			if (sec < 60) BIN_TO_BCD(sec);
-			else sec = 0xff;
-
-			if (min < 60) BIN_TO_BCD(min);
-			else min = 0xff;
-
-			if (hrs < 24) BIN_TO_BCD(hrs);
-			else hrs = 0xff;
+							RTC_ALWAYS_BCD) {
+			if (sec < 60)
+				BIN_TO_BCD(sec);
+			else
+				sec = 0xff;
+
+			if (min < 60)
+				BIN_TO_BCD(min);
+			else
+				min = 0xff;
+
+			if (hrs < 24)
+				BIN_TO_BCD(hrs);
+			else
+				hrs = 0xff;
 		}
 		CMOS_WRITE(hrs, RTC_HOURS_ALARM);
 		CMOS_WRITE(min, RTC_MINUTES_ALARM);
@@ -563,11 +579,12 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 
 		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
 			return -EINVAL;
-			
+
 		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
 			return -EINVAL;
 
-		if ((yrs -= epoch) > 255)    /* They are unsigned */
+		yrs -= epoch;
+		if (yrs > 255)		/* They are unsigned */
 			return -EINVAL;
 
 		spin_lock_irq(&rtc_lock);
@@ -635,9 +652,10 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 	{
 		int tmp = 0;
 		unsigned char val;
-		unsigned long flags; /* can be called from isr via rtc_control() */
+		/* can be called from isr via rtc_control() */
+		unsigned long flags;
 
-		/* 
+		/*
 		 * The max we can do is 8192Hz.
 		 */
 		if ((arg < 2) || (arg > 8192))
@@ -646,7 +664,8 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 		 * We don't really want Joe User generating more
 		 * than 64Hz of interrupts on a multi-user machine.
 		 */
-		if (!kernel && (arg > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
+		if (!kernel && (arg > rtc_max_user_freq) &&
+					!capable(CAP_SYS_RESOURCE))
 			return -EACCES;
 
 		while (arg > (1<<tmp))
@@ -674,11 +693,11 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 #endif
 	case RTC_EPOCH_READ:	/* Read the epoch.	*/
 	{
-		return put_user (epoch, (unsigned long __user *)arg);
+		return put_user(epoch, (unsigned long __user *)arg);
 	}
 	case RTC_EPOCH_SET:	/* Set the epoch.	*/
 	{
-		/* 
+		/*
 		 * There were no RTC clocks before 1900.
 		 */
 		if (arg < 1900)
@@ -693,7 +712,8 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
 	default:
 		return -ENOTTY;
 	}
-	return copy_to_user((void __user *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+	return copy_to_user((void __user *)arg,
+			    &wtime, sizeof wtime) ? -EFAULT : 0;
 }
 
 static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
@@ -712,26 +732,25 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
  * needed here. Or anywhere else in this driver. */
 static int rtc_open(struct inode *inode, struct file *file)
 {
-	spin_lock_irq (&rtc_lock);
+	spin_lock_irq(&rtc_lock);
 
-	if(rtc_status & RTC_IS_OPEN)
+	if (rtc_status & RTC_IS_OPEN)
 		goto out_busy;
 
 	rtc_status |= RTC_IS_OPEN;
 
 	rtc_irq_data = 0;
-	spin_unlock_irq (&rtc_lock);
+	spin_unlock_irq(&rtc_lock);
 	return 0;
 
 out_busy:
-	spin_unlock_irq (&rtc_lock);
+	spin_unlock_irq(&rtc_lock);
 	return -EBUSY;
 }
 
-static int rtc_fasync (int fd, struct file *filp, int on)
-
+static int rtc_fasync(int fd, struct file *filp, int on)
 {
-	return fasync_helper (fd, filp, on, &rtc_async_queue);
+	return fasync_helper(fd, filp, on, &rtc_async_queue);
 }
 
 static int rtc_release(struct inode *inode, struct file *file)
@@ -762,16 +781,16 @@ static int rtc_release(struct inode *inode, struct file *file)
 	}
 	spin_unlock_irq(&rtc_lock);
 
-	if (file->f_flags & FASYNC) {
-		rtc_fasync (-1, file, 0);
-	}
+	if (file->f_flags & FASYNC)
+		rtc_fasync(-1, file, 0);
 no_irq:
 #endif
 
-	spin_lock_irq (&rtc_lock);
+	spin_lock_irq(&rtc_lock);
 	rtc_irq_data = 0;
 	rtc_status &= ~RTC_IS_OPEN;
-	spin_unlock_irq (&rtc_lock);
+	spin_unlock_irq(&rtc_lock);
+
 	return 0;
 }
 
@@ -786,9 +805,9 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait)
 
 	poll_wait(file, &rtc_wait, wait);
 
-	spin_lock_irq (&rtc_lock);
+	spin_lock_irq(&rtc_lock);
 	l = rtc_irq_data;
-	spin_unlock_irq (&rtc_lock);
+	spin_unlock_irq(&rtc_lock);
 
 	if (l != 0)
 		return POLLIN | POLLRDNORM;
@@ -796,14 +815,6 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait)
 }
 #endif
 
-/*
- * exported stuffs
- */
-
-EXPORT_SYMBOL(rtc_register);
-EXPORT_SYMBOL(rtc_unregister);
-EXPORT_SYMBOL(rtc_control);
-
 int rtc_register(rtc_task_t *task)
 {
 #ifndef RTC_IRQ
@@ -829,6 +840,7 @@ int rtc_register(rtc_task_t *task)
 	return 0;
 #endif
 }
+EXPORT_SYMBOL(rtc_register);
 
 int rtc_unregister(rtc_task_t *task)
 {
@@ -845,7 +857,7 @@ int rtc_unregister(rtc_task_t *task)
 		return -ENXIO;
 	}
 	rtc_callback = NULL;
-	
+
 	/* disable controls */
 	if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) {
 		tmp = CMOS_READ(RTC_CONTROL);
@@ -865,6 +877,7 @@ int rtc_unregister(rtc_task_t *task)
 	return 0;
 #endif
 }
+EXPORT_SYMBOL(rtc_unregister);
 
 int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
 {
@@ -883,7 +896,7 @@ int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
 	return rtc_do_ioctl(cmd, arg, 1);
 #endif
 }
-
+EXPORT_SYMBOL(rtc_control);
 
 /*
  *	The various file operations we support.
@@ -910,11 +923,11 @@ static struct miscdevice rtc_dev = {
 
 #ifdef CONFIG_PROC_FS
 static const struct file_operations rtc_proc_fops = {
-	.owner = THIS_MODULE,
-	.open = rtc_proc_open,
-	.read  = seq_read,
-	.llseek = seq_lseek,
-	.release = single_release,
+	.owner		= THIS_MODULE,
+	.open		= rtc_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
 };
 #endif
 
@@ -965,7 +978,7 @@ static int __init rtc_init(void)
 #ifdef CONFIG_SPARC32
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
-			if(strcmp(edev->prom_node->name, "rtc") == 0) {
+			if (strcmp(edev->prom_node->name, "rtc") == 0) {
 				rtc_port = edev->resource[0].start;
 				rtc_irq = edev->irqs[0];
 				goto found;
@@ -986,7 +999,8 @@ found:
 	 * XXX Interrupt pin #7 in Espresso is shared between RTC and
 	 * PCI Slot 2 INTA# (and some INTx# in Slot 1).
 	 */
-	if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) {
+	if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc",
+			(void *)&rtc_port)) {
 		rtc_has_irq = 0;
 		printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq);
 		return -EIO;
@@ -1015,16 +1029,26 @@ no_irq:
 
 #ifdef RTC_IRQ
 	if (is_hpet_enabled()) {
+		int err;
+
 		rtc_int_handler_ptr = hpet_rtc_interrupt;
+		err = hpet_register_irq_handler(rtc_interrupt);
+		if (err != 0) {
+			printk(KERN_WARNING "hpet_register_irq_handler failed "
+					"in rtc_init().");
+			return err;
+		}
 	} else {
 		rtc_int_handler_ptr = rtc_interrupt;
 	}
 
-	if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) {
+	if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED,
+			"rtc", NULL)) {
 		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
 		rtc_has_irq = 0;
 		printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
 		rtc_release_region();
+
 		return -EIO;
 	}
 	hpet_rtc_timer_init();
@@ -1036,6 +1060,7 @@ no_irq:
 	if (misc_register(&rtc_dev)) {
 #ifdef RTC_IRQ
 		free_irq(RTC_IRQ, NULL);
+		hpet_unregister_irq_handler(rtc_interrupt);
 		rtc_has_irq = 0;
 #endif
 		rtc_release_region();
@@ -1052,21 +1077,21 @@ no_irq:
 
 #if defined(__alpha__) || defined(__mips__)
 	rtc_freq = HZ;
-	
+
 	/* Each operating system on an Alpha uses its own epoch.
 	   Let's try to guess which one we are using now. */
-	
+
 	if (rtc_is_updating() != 0)
 		msleep(20);
-	
+
 	spin_lock_irq(&rtc_lock);
 	year = CMOS_READ(RTC_YEAR);
 	ctrl = CMOS_READ(RTC_CONTROL);
 	spin_unlock_irq(&rtc_lock);
-	
+
 	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 		BCD_TO_BIN(year);       /* This should never happen... */
-	
+
 	if (year < 20) {
 		epoch = 2000;
 		guess = "SRM (post-2000)";
@@ -1087,7 +1112,8 @@ no_irq:
 #endif
 	}
 	if (guess)
-		printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch);
+		printk(KERN_INFO "rtc: %s epoch (%lu) detected\n",
+			guess, epoch);
 #endif
 #ifdef RTC_IRQ
 	if (rtc_has_irq == 0)
@@ -1096,8 +1122,12 @@ no_irq:
 	spin_lock_irq(&rtc_lock);
 	rtc_freq = 1024;
 	if (!hpet_set_periodic_freq(rtc_freq)) {
-		/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
-		CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
+		/*
+		 * Initialize periodic frequency to CMOS reset default,
+		 * which is 1024Hz
+		 */
+		CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06),
+			   RTC_FREQ_SELECT);
 	}
 	spin_unlock_irq(&rtc_lock);
 no_irq2:
@@ -1110,20 +1140,22 @@ no_irq2:
 	return 0;
 }
 
-static void __exit rtc_exit (void)
+static void __exit rtc_exit(void)
 {
 	cleanup_sysctl();
-	remove_proc_entry ("driver/rtc", NULL);
+	remove_proc_entry("driver/rtc", NULL);
 	misc_deregister(&rtc_dev);
 
 #ifdef CONFIG_SPARC32
 	if (rtc_has_irq)
-		free_irq (rtc_irq, &rtc_port);
+		free_irq(rtc_irq, &rtc_port);
 #else
 	rtc_release_region();
 #ifdef RTC_IRQ
-	if (rtc_has_irq)
-		free_irq (RTC_IRQ, NULL);
+	if (rtc_has_irq) {
+		free_irq(RTC_IRQ, NULL);
+		hpet_unregister_irq_handler(hpet_rtc_interrupt);
+	}
 #endif
 #endif /* CONFIG_SPARC32 */
 }
@@ -1133,14 +1165,14 @@ module_exit(rtc_exit);
 
 #ifdef RTC_IRQ
 /*
- * 	At IRQ rates >= 4096Hz, an interrupt may get lost altogether.
+ *	At IRQ rates >= 4096Hz, an interrupt may get lost altogether.
  *	(usually during an IDE disk interrupt, with IRQ unmasking off)
  *	Since the interrupt handler doesn't get called, the IRQ status
  *	byte doesn't get read, and the RTC stops generating interrupts.
  *	A timer is set, and will call this function if/when that happens.
  *	To get it out of this stalled state, we just read the status.
  *	At least a jiffy of interrupts (rtc_freq/HZ) will have been lost.
- *	(You *really* shouldn't be trying to use a non-realtime system 
+ *	(You *really* shouldn't be trying to use a non-realtime system
  *	for something that requires a steady > 1KHz signal anyways.)
  */
 
@@ -1148,7 +1180,7 @@ static void rtc_dropped_irq(unsigned long data)
 {
 	unsigned long freq;
 
-	spin_lock_irq (&rtc_lock);
+	spin_lock_irq(&rtc_lock);
 
 	if (hpet_rtc_dropped_irq()) {
 		spin_unlock_irq(&rtc_lock);
@@ -1167,13 +1199,15 @@ static void rtc_dropped_irq(unsigned long data)
 
 	spin_unlock_irq(&rtc_lock);
 
-	if (printk_ratelimit())
-		printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq);
+	if (printk_ratelimit()) {
+		printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
+			freq);
+	}
 
 	/* Now we have new data */
 	wake_up_interruptible(&rtc_wait);
 
-	kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
+	kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
 }
 #endif
 
@@ -1277,7 +1311,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
 	 * can take just over 2ms. We wait 20ms. There is no need to
 	 * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
 	 * If you need to know *exactly* when a second has started, enable
-	 * periodic update complete interrupts, (via ioctl) and then 
+	 * periodic update complete interrupts, (via ioctl) and then
 	 * immediately read /dev/rtc which will block until you get the IRQ.
 	 * Once the read clears, read the RTC time (again via ioctl). Easy.
 	 */
@@ -1307,8 +1341,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
 	ctrl = CMOS_READ(RTC_CONTROL);
 	spin_unlock_irqrestore(&rtc_lock, flags);
 
-	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	{
+	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 		BCD_TO_BIN(rtc_tm->tm_sec);
 		BCD_TO_BIN(rtc_tm->tm_min);
 		BCD_TO_BIN(rtc_tm->tm_hour);
@@ -1326,7 +1359,8 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
 	 * Account for differences between how the RTC uses the values
 	 * and how they are defined in a struct rtc_time;
 	 */
-	if ((rtc_tm->tm_year += (epoch - 1900)) <= 69)
+	rtc_tm->tm_year += epoch - 1900;
+	if (rtc_tm->tm_year <= 69)
 		rtc_tm->tm_year += 100;
 
 	rtc_tm->tm_mon--;
@@ -1347,8 +1381,7 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm)
 	ctrl = CMOS_READ(RTC_CONTROL);
 	spin_unlock_irq(&rtc_lock);
 
-	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	{
+	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 		BCD_TO_BIN(alm_tm->tm_sec);
 		BCD_TO_BIN(alm_tm->tm_min);
 		BCD_TO_BIN(alm_tm->tm_hour);
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index 12ceed54ab18..5732ca3259f9 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -104,7 +104,6 @@ int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id
 		return -EINVAL;
 	}
 
-	cbq->nls = dev->nls;
 	cbq->seq = 0;
 	cbq->group = cbq->id.id.idx;
 
@@ -146,7 +145,6 @@ struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *nls)
 	spin_lock_init(&dev->queue_lock);
 
 	dev->nls = nls;
-	dev->netlink_groups = 0;
 
 	dev->cn_queue = create_workqueue(dev->name);
 	if (!dev->cn_queue) {
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index bf9716b75513..fea2d3ed9cbd 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -88,6 +88,7 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
 			if (cn_cb_equal(&__cbq->id.id, &msg->id)) {
 				found = 1;
 				group = __cbq->group;
+				break;
 			}
 		}
 		spin_unlock_bh(&dev->cbdev->queue_lock);
@@ -181,33 +182,14 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
 }
 
 /*
- * Skb receive helper - checks skb and msg size and calls callback
- * helper.
- */
-static int __cn_rx_skb(struct sk_buff *skb, struct nlmsghdr *nlh)
-{
-	u32 pid, uid, seq, group;
-	struct cn_msg *msg;
-
-	pid = NETLINK_CREDS(skb)->pid;
-	uid = NETLINK_CREDS(skb)->uid;
-	seq = nlh->nlmsg_seq;
-	group = NETLINK_CB((skb)).dst_group;
-	msg = NLMSG_DATA(nlh);
-
-	return cn_call_callback(msg, (void (*)(void *))kfree_skb, skb);
-}
-
-/*
  * Main netlink receiving function.
  *
- * It checks skb and netlink header sizes and calls the skb receive
- * helper with a shared skb.
+ * It checks skb, netlink header and msg sizes, and calls callback helper.
  */
 static void cn_rx_skb(struct sk_buff *__skb)
 {
+	struct cn_msg *msg;
 	struct nlmsghdr *nlh;
-	u32 len;
 	int err;
 	struct sk_buff *skb;
 
@@ -223,11 +205,8 @@ static void cn_rx_skb(struct sk_buff *__skb)
 			return;
 		}
 
-		len = NLMSG_ALIGN(nlh->nlmsg_len);
-		if (len > skb->len)
-			len = skb->len;
-
-		err = __cn_rx_skb(skb, nlh);
+		msg = NLMSG_DATA(nlh);
+		err = cn_call_callback(msg, (void (*)(void *))kfree_skb, skb);
 		if (err < 0)
 			kfree_skb(skb);
 	}
@@ -441,8 +420,7 @@ static int __devinit cn_init(void)
 
 	dev->cbdev = cn_queue_alloc_dev("cqueue", dev->nls);
 	if (!dev->cbdev) {
-		if (dev->nls->sk_socket)
-			sock_release(dev->nls->sk_socket);
+		netlink_kernel_release(dev->nls);
 		return -EINVAL;
 	}
 	
@@ -452,8 +430,7 @@ static int __devinit cn_init(void)
 	if (err) {
 		cn_already_initialized = 0;
 		cn_queue_free_dev(dev->cbdev);
-		if (dev->nls->sk_socket)
-			sock_release(dev->nls->sk_socket);
+		netlink_kernel_release(dev->nls);
 		return -EINVAL;
 	}
 
@@ -468,8 +445,7 @@ static void __devexit cn_fini(void)
 
 	cn_del_callback(&dev->id);
 	cn_queue_free_dev(dev->cbdev);
-	if (dev->nls->sk_socket)
-		sock_release(dev->nls->sk_socket);
+	netlink_kernel_release(dev->nls);
 }
 
 subsys_initcall(cn_init);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 79581fab82d6..b730d6709529 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -828,11 +828,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
 	memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
 
 	/* prepare interface data */
-	policy->kobj.parent = &sys_dev->kobj;
-	policy->kobj.ktype = &ktype_cpufreq;
-	kobject_set_name(&policy->kobj, "cpufreq");
-
-	ret = kobject_register(&policy->kobj);
+	ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
+				   "cpufreq");
 	if (ret) {
 		unlock_policy_rwsem_write(cpu);
 		goto err_out_driver_exit;
@@ -902,6 +899,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
 		goto err_out_unregister;
 	}
 
+	kobject_uevent(&policy->kobj, KOBJ_ADD);
 	module_put(cpufreq_driver->owner);
 	dprintk("initialization complete\n");
 	cpufreq_debug_enable_ratelimit();
@@ -915,7 +913,7 @@ err_out_unregister:
 		cpufreq_cpu_data[j] = NULL;
 	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-	kobject_unregister(&policy->kobj);
+	kobject_put(&policy->kobj);
 	wait_for_completion(&policy->kobj_unregister);
 
 err_out_driver_exit:
@@ -1032,8 +1030,6 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev)
 
 	unlock_policy_rwsem_write(cpu);
 
-	kobject_unregister(&data->kobj);
-
 	kobject_put(&data->kobj);
 
 	/* we need to make sure that the underlying kobj is actually
@@ -1608,7 +1604,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
 	memcpy(&policy->cpuinfo, &data->cpuinfo,
 				sizeof(struct cpufreq_cpuinfo));
 
-	if (policy->min > data->min && policy->min > policy->max) {
+	if (policy->min > data->max || policy->max < data->min) {
 		ret = -EINVAL;
 		goto error_out;
 	}
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 0f3515e77d4b..088ea74edd34 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -277,7 +277,7 @@ static struct kobj_type ktype_state_cpuidle = {
 
 static void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
 {
-	kobject_unregister(&device->kobjs[i]->kobj);
+	kobject_put(&device->kobjs[i]->kobj);
 	wait_for_completion(&device->kobjs[i]->kobj_unregister);
 	kfree(device->kobjs[i]);
 	device->kobjs[i] = NULL;
@@ -300,14 +300,13 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device)
 		kobj->state = &device->states[i];
 		init_completion(&kobj->kobj_unregister);
 
-		kobj->kobj.parent = &device->kobj;
-		kobj->kobj.ktype = &ktype_state_cpuidle;
-		kobject_set_name(&kobj->kobj, "state%d", i);
-		ret = kobject_register(&kobj->kobj);
+		ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj,
+					   "state%d", i);
 		if (ret) {
 			kfree(kobj);
 			goto error_state;
 		}
+		kobject_uevent(&kobj->kobj, KOBJ_ADD);
 		device->kobjs[i] = kobj;
 	}
 
@@ -339,12 +338,14 @@ int cpuidle_add_sysfs(struct sys_device *sysdev)
 {
 	int cpu = sysdev->id;
 	struct cpuidle_device *dev;
+	int error;
 
 	dev = per_cpu(cpuidle_devices, cpu);
-	dev->kobj.parent = &sysdev->kobj;
-	dev->kobj.ktype = &ktype_cpuidle;
-	kobject_set_name(&dev->kobj, "%s", "cpuidle");
-	return kobject_register(&dev->kobj);
+	error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &sysdev->kobj,
+				     "cpuidle");
+	if (!error)
+		kobject_uevent(&dev->kobj, KOBJ_ADD);
+	return error;
 }
 
 /**
@@ -357,5 +358,5 @@ void cpuidle_remove_sysfs(struct sys_device *sysdev)
 	struct cpuidle_device *dev;
 
 	dev = per_cpu(cpuidle_devices, cpu);
-	kobject_unregister(&dev->kobj);
+	kobject_put(&dev->kobj);
 }
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index ddd3a259cea1..6b658d84d521 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -48,8 +48,6 @@ config CRYPTO_DEV_PADLOCK_SHA
 	  If unsure say M. The compiled module will be
 	  called padlock-sha.ko
 
-source "arch/s390/crypto/Kconfig"
-
 config CRYPTO_DEV_GEODE
 	tristate "Support for the Geode LX AES engine"
 	depends on X86_32 && PCI
@@ -83,4 +81,82 @@ config ZCRYPT_MONOLITHIC
 	  that contains all parts of the crypto device driver (ap bus,
 	  request router and all the card drivers).
 
+config CRYPTO_SHA1_S390
+	tristate "SHA1 digest algorithm"
+	depends on S390
+	select CRYPTO_ALGAPI
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+config CRYPTO_SHA256_S390
+	tristate "SHA256 digest algorithm"
+	depends on S390
+	select CRYPTO_ALGAPI
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  SHA256 secure hash standard (DFIPS 180-2).
+
+	  This version of SHA implements a 256 bit hash with 128 bits of
+	  security against collision attacks.
+
+config CRYPTO_DES_S390
+	tristate "DES and Triple DES cipher algorithms"
+	depends on S390
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  This us the s390 hardware accelerated implementation of the
+	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+config CRYPTO_AES_S390
+	tristate "AES cipher algorithms"
+	depends on S390
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	help
+	  This is the s390 hardware accelerated implementation of the
+	  AES cipher algorithms (FIPS-197). AES uses the Rijndael
+	  algorithm.
+
+	  Rijndael appears to be consistently a very good performer in
+	  both hardware and software across a wide range of computing
+	  environments regardless of its use in feedback or non-feedback
+	  modes. Its key setup time is excellent, and its key agility is
+	  good. Rijndael's very low memory requirements make it very well
+	  suited for restricted-space environments, in which it also
+	  demonstrates excellent performance. Rijndael's operations are
+	  among the easiest to defend against power and timing attacks.
+
+	  On s390 the System z9-109 currently only supports the key size
+	  of 128 bit.
+
+config S390_PRNG
+	tristate "Pseudo random number generator device driver"
+	depends on S390
+	default "m"
+	help
+	  Select this option if you want to use the s390 pseudo random number
+	  generator. The PRNG is part of the cryptographic processor functions
+	  and uses triple-DES to generate secure random numbers like the
+	  ANSI X9.17 standard. The PRNG is usable via the char device
+	  /dev/prandom.
+
+config CRYPTO_DEV_HIFN_795X
+	tristate "Driver HIFN 795x crypto accelerator chips"
+	select CRYPTO_DES
+	select CRYPTO_ALGAPI
+	select CRYPTO_BLKCIPHER
+	select HW_RANDOM if CRYPTO_DEV_HIFN_795X_RNG
+	depends on PCI
+	help
+	  This option allows you to have support for HIFN 795x crypto adapters.
+
+config CRYPTO_DEV_HIFN_795X_RNG
+	bool "HIFN 795x random number generator"
+	depends on CRYPTO_DEV_HIFN_795X
+	help
+	  Select this option if you want to enable the random number generator
+	  on the HIFN 795x crypto adapters.
+
 endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index d070030f7d7e..c0327f0dadc5 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
+obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 711e246e1ef0..4801162919d9 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -13,44 +13,13 @@
 #include <linux/crypto.h>
 #include <linux/spinlock.h>
 #include <crypto/algapi.h>
+#include <crypto/aes.h>
 
 #include <asm/io.h>
 #include <asm/delay.h>
 
 #include "geode-aes.h"
 
-/* Register definitions */
-
-#define AES_CTRLA_REG  0x0000
-
-#define AES_CTRL_START     0x01
-#define AES_CTRL_DECRYPT   0x00
-#define AES_CTRL_ENCRYPT   0x02
-#define AES_CTRL_WRKEY     0x04
-#define AES_CTRL_DCA       0x08
-#define AES_CTRL_SCA       0x10
-#define AES_CTRL_CBC       0x20
-
-#define AES_INTR_REG  0x0008
-
-#define AES_INTRA_PENDING (1 << 16)
-#define AES_INTRB_PENDING (1 << 17)
-
-#define AES_INTR_PENDING  (AES_INTRA_PENDING | AES_INTRB_PENDING)
-#define AES_INTR_MASK     0x07
-
-#define AES_SOURCEA_REG   0x0010
-#define AES_DSTA_REG      0x0014
-#define AES_LENA_REG      0x0018
-#define AES_WRITEKEY0_REG 0x0030
-#define AES_WRITEIV0_REG  0x0040
-
-/*  A very large counter that is used to gracefully bail out of an
- *  operation in case of trouble
- */
-
-#define AES_OP_TIMEOUT    0x50000
-
 /* Static structures */
 
 static void __iomem * _iobase;
@@ -87,9 +56,10 @@ do_crypt(void *src, void *dst, int len, u32 flags)
 	/* Start the operation */
 	iowrite32(AES_CTRL_START | flags, _iobase + AES_CTRLA_REG);
 
-	do
+	do {
 		status = ioread32(_iobase + AES_INTR_REG);
-	while(!(status & AES_INTRA_PENDING) && --counter);
+		cpu_relax();
+	} while(!(status & AES_INTRA_PENDING) && --counter);
 
 	/* Clear the event */
 	iowrite32((status & 0xFF) | AES_INTRA_PENDING, _iobase + AES_INTR_REG);
@@ -101,6 +71,7 @@ geode_aes_crypt(struct geode_aes_op *op)
 {
 	u32 flags = 0;
 	unsigned long iflags;
+	int ret;
 
 	if (op->len == 0)
 		return 0;
@@ -129,7 +100,8 @@ geode_aes_crypt(struct geode_aes_op *op)
 		_writefield(AES_WRITEKEY0_REG, op->key);
 	}
 
-	do_crypt(op->src, op->dst, op->len, flags);
+	ret = do_crypt(op->src, op->dst, op->len, flags);
+	BUG_ON(ret);
 
 	if (op->mode == AES_MODE_CBC)
 		_readfield(AES_WRITEIV0_REG, op->iv);
@@ -141,18 +113,103 @@ geode_aes_crypt(struct geode_aes_op *op)
 
 /* CRYPTO-API Functions */
 
-static int
-geode_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int len)
+static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key,
+		unsigned int len)
 {
 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	unsigned int ret;
 
-	if (len != AES_KEY_LENGTH) {
+	op->keylen = len;
+
+	if (len == AES_KEYSIZE_128) {
+		memcpy(op->key, key, len);
+		return 0;
+	}
+
+	if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) {
+		/* not supported at all */
 		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
 		return -EINVAL;
 	}
 
-	memcpy(op->key, key, len);
-	return 0;
+	/*
+	 * The requested key size is not supported by HW, do a fallback
+	 */
+	op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+	op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+
+	ret = crypto_cipher_setkey(op->fallback.cip, key, len);
+	if (ret) {
+		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+		tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK);
+	}
+	return ret;
+}
+
+static int geode_setkey_blk(struct crypto_tfm *tfm, const u8 *key,
+		unsigned int len)
+{
+	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+	unsigned int ret;
+
+	op->keylen = len;
+
+	if (len == AES_KEYSIZE_128) {
+		memcpy(op->key, key, len);
+		return 0;
+	}
+
+	if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) {
+		/* not supported at all */
+		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+
+	/*
+	 * The requested key size is not supported by HW, do a fallback
+	 */
+	op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+	op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+
+	ret = crypto_blkcipher_setkey(op->fallback.blk, key, len);
+	if (ret) {
+		tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+		tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK);
+	}
+	return ret;
+}
+
+static int fallback_blk_dec(struct blkcipher_desc *desc,
+		struct scatterlist *dst, struct scatterlist *src,
+		unsigned int nbytes)
+{
+	unsigned int ret;
+	struct crypto_blkcipher *tfm;
+	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+
+	tfm = desc->tfm;
+	desc->tfm = op->fallback.blk;
+
+	ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
+
+	desc->tfm = tfm;
+	return ret;
+}
+static int fallback_blk_enc(struct blkcipher_desc *desc,
+		struct scatterlist *dst, struct scatterlist *src,
+		unsigned int nbytes)
+{
+	unsigned int ret;
+	struct crypto_blkcipher *tfm;
+	struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+
+	tfm = desc->tfm;
+	desc->tfm = op->fallback.blk;
+
+	ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+
+	desc->tfm = tfm;
+	return ret;
 }
 
 static void
@@ -160,8 +217,10 @@ geode_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 
-	if ((out == NULL) || (in == NULL))
+	if (unlikely(op->keylen != AES_KEYSIZE_128)) {
+		crypto_cipher_encrypt_one(op->fallback.cip, out, in);
 		return;
+	}
 
 	op->src = (void *) in;
 	op->dst = (void *) out;
@@ -179,8 +238,10 @@ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 
-	if ((out == NULL) || (in == NULL))
+	if (unlikely(op->keylen != AES_KEYSIZE_128)) {
+		crypto_cipher_decrypt_one(op->fallback.cip, out, in);
 		return;
+	}
 
 	op->src = (void *) in;
 	op->dst = (void *) out;
@@ -192,24 +253,50 @@ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 	geode_aes_crypt(op);
 }
 
+static int fallback_init_cip(struct crypto_tfm *tfm)
+{
+	const char *name = tfm->__crt_alg->cra_name;
+	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+	op->fallback.cip = crypto_alloc_cipher(name, 0,
+				CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+	if (IS_ERR(op->fallback.cip)) {
+		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+		return PTR_ERR(op->fallback.blk);
+	}
+
+	return 0;
+}
+
+static void fallback_exit_cip(struct crypto_tfm *tfm)
+{
+	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+	crypto_free_cipher(op->fallback.cip);
+	op->fallback.cip = NULL;
+}
 
 static struct crypto_alg geode_alg = {
-	.cra_name               =       "aes",
-	.cra_driver_name	=       "geode-aes-128",
-	.cra_priority           =       300,
-	.cra_alignmask          =       15,
-	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_name			=	"aes",
+	.cra_driver_name	=	"geode-aes",
+	.cra_priority		=	300,
+	.cra_alignmask		=	15,
+	.cra_flags			=	CRYPTO_ALG_TYPE_CIPHER |
+							CRYPTO_ALG_NEED_FALLBACK,
+	.cra_init			=	fallback_init_cip,
+	.cra_exit			=	fallback_exit_cip,
 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(geode_alg.cra_list),
-	.cra_u			=	{
-		.cipher = {
-			.cia_min_keysize	=  AES_KEY_LENGTH,
-			.cia_max_keysize	=  AES_KEY_LENGTH,
-			.cia_setkey		=  geode_setkey,
-			.cia_encrypt		=  geode_encrypt,
-			.cia_decrypt		=  geode_decrypt
+	.cra_module			=	THIS_MODULE,
+	.cra_list			=	LIST_HEAD_INIT(geode_alg.cra_list),
+	.cra_u				=	{
+		.cipher	=	{
+			.cia_min_keysize	=	AES_MIN_KEY_SIZE,
+			.cia_max_keysize	=	AES_MAX_KEY_SIZE,
+			.cia_setkey			=	geode_setkey_cip,
+			.cia_encrypt		=	geode_encrypt,
+			.cia_decrypt		=	geode_decrypt
 		}
 	}
 };
@@ -223,8 +310,12 @@ geode_cbc_decrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	int err, ret;
 
+	if (unlikely(op->keylen != AES_KEYSIZE_128))
+		return fallback_blk_dec(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
+	op->iv = walk.iv;
 
 	while((nbytes = walk.nbytes)) {
 		op->src = walk.src.virt.addr,
@@ -233,13 +324,9 @@ geode_cbc_decrypt(struct blkcipher_desc *desc,
 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
 		op->dir = AES_DIR_DECRYPT;
 
-		memcpy(op->iv, walk.iv, AES_IV_LENGTH);
-
 		ret = geode_aes_crypt(op);
 
-		memcpy(walk.iv, op->iv, AES_IV_LENGTH);
 		nbytes -= ret;
-
 		err = blkcipher_walk_done(desc, &walk, nbytes);
 	}
 
@@ -255,8 +342,12 @@ geode_cbc_encrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	int err, ret;
 
+	if (unlikely(op->keylen != AES_KEYSIZE_128))
+		return fallback_blk_enc(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
+	op->iv = walk.iv;
 
 	while((nbytes = walk.nbytes)) {
 		op->src = walk.src.virt.addr,
@@ -265,8 +356,6 @@ geode_cbc_encrypt(struct blkcipher_desc *desc,
 		op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE);
 		op->dir = AES_DIR_ENCRYPT;
 
-		memcpy(op->iv, walk.iv, AES_IV_LENGTH);
-
 		ret = geode_aes_crypt(op);
 		nbytes -= ret;
 		err = blkcipher_walk_done(desc, &walk, nbytes);
@@ -275,22 +364,49 @@ geode_cbc_encrypt(struct blkcipher_desc *desc,
 	return err;
 }
 
+static int fallback_init_blk(struct crypto_tfm *tfm)
+{
+	const char *name = tfm->__crt_alg->cra_name;
+	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+	op->fallback.blk = crypto_alloc_blkcipher(name, 0,
+			CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+	if (IS_ERR(op->fallback.blk)) {
+		printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+		return PTR_ERR(op->fallback.blk);
+	}
+
+	return 0;
+}
+
+static void fallback_exit_blk(struct crypto_tfm *tfm)
+{
+	struct geode_aes_op *op = crypto_tfm_ctx(tfm);
+
+	crypto_free_blkcipher(op->fallback.blk);
+	op->fallback.blk = NULL;
+}
+
 static struct crypto_alg geode_cbc_alg = {
 	.cra_name		=	"cbc(aes)",
-	.cra_driver_name	=	"cbc-aes-geode-128",
+	.cra_driver_name	=	"cbc-aes-geode",
 	.cra_priority		=	400,
-	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_flags			=	CRYPTO_ALG_TYPE_BLKCIPHER |
+							CRYPTO_ALG_NEED_FALLBACK,
+	.cra_init			=	fallback_init_blk,
+	.cra_exit			=	fallback_exit_blk,
 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
 	.cra_alignmask		=	15,
-	.cra_type		=	&crypto_blkcipher_type,
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(geode_cbc_alg.cra_list),
-	.cra_u			=	{
-		.blkcipher = {
-			.min_keysize		=	AES_KEY_LENGTH,
-			.max_keysize		=	AES_KEY_LENGTH,
-			.setkey			=	geode_setkey,
+	.cra_type			=	&crypto_blkcipher_type,
+	.cra_module			=	THIS_MODULE,
+	.cra_list			=	LIST_HEAD_INIT(geode_cbc_alg.cra_list),
+	.cra_u				=	{
+		.blkcipher	=	{
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey			=	geode_setkey_blk,
 			.encrypt		=	geode_cbc_encrypt,
 			.decrypt		=	geode_cbc_decrypt,
 			.ivsize			=	AES_IV_LENGTH,
@@ -307,6 +423,9 @@ geode_ecb_decrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	int err, ret;
 
+	if (unlikely(op->keylen != AES_KEYSIZE_128))
+		return fallback_blk_dec(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 
@@ -334,6 +453,9 @@ geode_ecb_encrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	int err, ret;
 
+	if (unlikely(op->keylen != AES_KEYSIZE_128))
+		return fallback_blk_enc(desc, dst, src, nbytes);
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 
@@ -353,28 +475,31 @@ geode_ecb_encrypt(struct blkcipher_desc *desc,
 }
 
 static struct crypto_alg geode_ecb_alg = {
-	.cra_name		=	"ecb(aes)",
-	.cra_driver_name	=	"ecb-aes-geode-128",
+	.cra_name			=	"ecb(aes)",
+	.cra_driver_name	=	"ecb-aes-geode",
 	.cra_priority		=	400,
-	.cra_flags		=	CRYPTO_ALG_TYPE_BLKCIPHER,
+	.cra_flags			=	CRYPTO_ALG_TYPE_BLKCIPHER |
+							CRYPTO_ALG_NEED_FALLBACK,
+	.cra_init			=	fallback_init_blk,
+	.cra_exit			=	fallback_exit_blk,
 	.cra_blocksize		=	AES_MIN_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct geode_aes_op),
 	.cra_alignmask		=	15,
-	.cra_type		=	&crypto_blkcipher_type,
-	.cra_module		=	THIS_MODULE,
-	.cra_list		=	LIST_HEAD_INIT(geode_ecb_alg.cra_list),
-	.cra_u			=	{
-		.blkcipher = {
-			.min_keysize		=	AES_KEY_LENGTH,
-			.max_keysize		=	AES_KEY_LENGTH,
-			.setkey			=	geode_setkey,
+	.cra_type			=	&crypto_blkcipher_type,
+	.cra_module			=	THIS_MODULE,
+	.cra_list			=	LIST_HEAD_INIT(geode_ecb_alg.cra_list),
+	.cra_u				=	{
+		.blkcipher	=	{
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey			=	geode_setkey_blk,
 			.encrypt		=	geode_ecb_encrypt,
 			.decrypt		=	geode_ecb_decrypt,
 		}
 	}
 };
 
-static void
+static void __devexit
 geode_aes_remove(struct pci_dev *dev)
 {
 	crypto_unregister_alg(&geode_alg);
@@ -389,7 +514,7 @@ geode_aes_remove(struct pci_dev *dev)
 }
 
 
-static int
+static int __devinit
 geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	int ret;
@@ -397,7 +522,7 @@ geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	if ((ret = pci_enable_device(dev)))
 		return ret;
 
-	if ((ret = pci_request_regions(dev, "geode-aes-128")))
+	if ((ret = pci_request_regions(dev, "geode-aes")))
 		goto eenable;
 
 	_iobase = pci_iomap(dev, 0, 0);
@@ -472,7 +597,6 @@ geode_aes_exit(void)
 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
 MODULE_DESCRIPTION("Geode LX Hardware AES driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("aes");
 
 module_init(geode_aes_init);
 module_exit(geode_aes_exit);
diff --git a/drivers/crypto/geode-aes.h b/drivers/crypto/geode-aes.h
index f47968671ae7..f1855b50da48 100644
--- a/drivers/crypto/geode-aes.h
+++ b/drivers/crypto/geode-aes.h
@@ -9,9 +9,9 @@
 #ifndef _GEODE_AES_H_
 #define _GEODE_AES_H_
 
-#define AES_KEY_LENGTH 16
+/* driver logic flags */
 #define AES_IV_LENGTH  16
-
+#define AES_KEY_LENGTH 16
 #define AES_MIN_BLOCK_SIZE 16
 
 #define AES_MODE_ECB 0
@@ -22,6 +22,38 @@
 
 #define AES_FLAGS_HIDDENKEY (1 << 0)
 
+/* Register definitions */
+
+#define AES_CTRLA_REG  0x0000
+
+#define AES_CTRL_START     0x01
+#define AES_CTRL_DECRYPT   0x00
+#define AES_CTRL_ENCRYPT   0x02
+#define AES_CTRL_WRKEY     0x04
+#define AES_CTRL_DCA       0x08
+#define AES_CTRL_SCA       0x10
+#define AES_CTRL_CBC       0x20
+
+#define AES_INTR_REG  0x0008
+
+#define AES_INTRA_PENDING (1 << 16)
+#define AES_INTRB_PENDING (1 << 17)
+
+#define AES_INTR_PENDING  (AES_INTRA_PENDING | AES_INTRB_PENDING)
+#define AES_INTR_MASK     0x07
+
+#define AES_SOURCEA_REG   0x0010
+#define AES_DSTA_REG      0x0014
+#define AES_LENA_REG      0x0018
+#define AES_WRITEKEY0_REG 0x0030
+#define AES_WRITEIV0_REG  0x0040
+
+/*  A very large counter that is used to gracefully bail out of an
+ *  operation in case of trouble
+ */
+
+#define AES_OP_TIMEOUT    0x50000
+
 struct geode_aes_op {
 
 	void *src;
@@ -33,7 +65,13 @@ struct geode_aes_op {
 	int len;
 
 	u8 key[AES_KEY_LENGTH];
-	u8 iv[AES_IV_LENGTH];
+	u8 *iv;
+
+	union {
+		struct crypto_blkcipher *blk;
+		struct crypto_cipher *cip;
+	} fallback;
+	u32 keylen;
 };
 
 #endif
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
new file mode 100644
index 000000000000..dfbf24c4033c
--- /dev/null
+++ b/drivers/crypto/hifn_795x.c
@@ -0,0 +1,2838 @@
+/*
+ * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 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.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mod_devicetable.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/crypto.h>
+#include <linux/hw_random.h>
+#include <linux/ktime.h>
+
+#include <crypto/algapi.h>
+#include <crypto/des.h>
+
+#include <asm/kmap_types.h>
+
+#undef dprintk
+
+#define HIFN_TEST
+//#define HIFN_DEBUG
+
+#ifdef HIFN_DEBUG
+#define dprintk(f, a...) 	printk(f, ##a)
+#else
+#define dprintk(f, a...)	do {} while (0)
+#endif
+
+static char hifn_pll_ref[sizeof("extNNN")] = "ext";
+module_param_string(hifn_pll_ref, hifn_pll_ref, sizeof(hifn_pll_ref), 0444);
+MODULE_PARM_DESC(hifn_pll_ref,
+		 "PLL reference clock (pci[freq] or ext[freq], default ext)");
+
+static atomic_t hifn_dev_number;
+
+#define ACRYPTO_OP_DECRYPT	0
+#define ACRYPTO_OP_ENCRYPT	1
+#define ACRYPTO_OP_HMAC		2
+#define ACRYPTO_OP_RNG		3
+
+#define ACRYPTO_MODE_ECB		0
+#define ACRYPTO_MODE_CBC		1
+#define ACRYPTO_MODE_CFB		2
+#define ACRYPTO_MODE_OFB		3
+
+#define ACRYPTO_TYPE_AES_128	0
+#define ACRYPTO_TYPE_AES_192	1
+#define ACRYPTO_TYPE_AES_256	2
+#define ACRYPTO_TYPE_3DES	3
+#define ACRYPTO_TYPE_DES	4
+
+#define PCI_VENDOR_ID_HIFN		0x13A3
+#define PCI_DEVICE_ID_HIFN_7955		0x0020
+#define	PCI_DEVICE_ID_HIFN_7956		0x001d
+
+/* I/O region sizes */
+
+#define HIFN_BAR0_SIZE			0x1000
+#define HIFN_BAR1_SIZE			0x2000
+#define HIFN_BAR2_SIZE			0x8000
+
+/* DMA registres */
+
+#define HIFN_DMA_CRA 			0x0C	/* DMA Command Ring Address */
+#define HIFN_DMA_SDRA 			0x1C	/* DMA Source Data Ring Address */
+#define HIFN_DMA_RRA			0x2C	/* DMA Result Ring Address */
+#define HIFN_DMA_DDRA			0x3C	/* DMA Destination Data Ring Address */
+#define HIFN_DMA_STCTL			0x40	/* DMA Status and Control */
+#define HIFN_DMA_INTREN 		0x44	/* DMA Interrupt Enable */
+#define HIFN_DMA_CFG1			0x48	/* DMA Configuration #1 */
+#define HIFN_DMA_CFG2			0x6C	/* DMA Configuration #2 */
+#define HIFN_CHIP_ID			0x98	/* Chip ID */
+
+/*
+ * Processing Unit Registers (offset from BASEREG0)
+ */
+#define	HIFN_0_PUDATA		0x00	/* Processing Unit Data */
+#define	HIFN_0_PUCTRL		0x04	/* Processing Unit Control */
+#define	HIFN_0_PUISR		0x08	/* Processing Unit Interrupt Status */
+#define	HIFN_0_PUCNFG		0x0c	/* Processing Unit Configuration */
+#define	HIFN_0_PUIER		0x10	/* Processing Unit Interrupt Enable */
+#define	HIFN_0_PUSTAT		0x14	/* Processing Unit Status/Chip ID */
+#define	HIFN_0_FIFOSTAT		0x18	/* FIFO Status */
+#define	HIFN_0_FIFOCNFG		0x1c	/* FIFO Configuration */
+#define	HIFN_0_SPACESIZE	0x20	/* Register space size */
+
+/* Processing Unit Control Register (HIFN_0_PUCTRL) */
+#define	HIFN_PUCTRL_CLRSRCFIFO	0x0010	/* clear source fifo */
+#define	HIFN_PUCTRL_STOP	0x0008	/* stop pu */
+#define	HIFN_PUCTRL_LOCKRAM	0x0004	/* lock ram */
+#define	HIFN_PUCTRL_DMAENA	0x0002	/* enable dma */
+#define	HIFN_PUCTRL_RESET	0x0001	/* Reset processing unit */
+
+/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */
+#define	HIFN_PUISR_CMDINVAL	0x8000	/* Invalid command interrupt */
+#define	HIFN_PUISR_DATAERR	0x4000	/* Data error interrupt */
+#define	HIFN_PUISR_SRCFIFO	0x2000	/* Source FIFO ready interrupt */
+#define	HIFN_PUISR_DSTFIFO	0x1000	/* Destination FIFO ready interrupt */
+#define	HIFN_PUISR_DSTOVER	0x0200	/* Destination overrun interrupt */
+#define	HIFN_PUISR_SRCCMD	0x0080	/* Source command interrupt */
+#define	HIFN_PUISR_SRCCTX	0x0040	/* Source context interrupt */
+#define	HIFN_PUISR_SRCDATA	0x0020	/* Source data interrupt */
+#define	HIFN_PUISR_DSTDATA	0x0010	/* Destination data interrupt */
+#define	HIFN_PUISR_DSTRESULT	0x0004	/* Destination result interrupt */
+
+/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */
+#define	HIFN_PUCNFG_DRAMMASK	0xe000	/* DRAM size mask */
+#define	HIFN_PUCNFG_DSZ_256K	0x0000	/* 256k dram */
+#define	HIFN_PUCNFG_DSZ_512K	0x2000	/* 512k dram */
+#define	HIFN_PUCNFG_DSZ_1M	0x4000	/* 1m dram */
+#define	HIFN_PUCNFG_DSZ_2M	0x6000	/* 2m dram */
+#define	HIFN_PUCNFG_DSZ_4M	0x8000	/* 4m dram */
+#define	HIFN_PUCNFG_DSZ_8M	0xa000	/* 8m dram */
+#define	HIFN_PUNCFG_DSZ_16M	0xc000	/* 16m dram */
+#define	HIFN_PUCNFG_DSZ_32M	0xe000	/* 32m dram */
+#define	HIFN_PUCNFG_DRAMREFRESH	0x1800	/* DRAM refresh rate mask */
+#define	HIFN_PUCNFG_DRFR_512	0x0000	/* 512 divisor of ECLK */
+#define	HIFN_PUCNFG_DRFR_256	0x0800	/* 256 divisor of ECLK */
+#define	HIFN_PUCNFG_DRFR_128	0x1000	/* 128 divisor of ECLK */
+#define	HIFN_PUCNFG_TCALLPHASES	0x0200	/* your guess is as good as mine... */
+#define	HIFN_PUCNFG_TCDRVTOTEM	0x0100	/* your guess is as good as mine... */
+#define	HIFN_PUCNFG_BIGENDIAN	0x0080	/* DMA big endian mode */
+#define	HIFN_PUCNFG_BUS32	0x0040	/* Bus width 32bits */
+#define	HIFN_PUCNFG_BUS16	0x0000	/* Bus width 16 bits */
+#define	HIFN_PUCNFG_CHIPID	0x0020	/* Allow chipid from PUSTAT */
+#define	HIFN_PUCNFG_DRAM	0x0010	/* Context RAM is DRAM */
+#define	HIFN_PUCNFG_SRAM	0x0000	/* Context RAM is SRAM */
+#define	HIFN_PUCNFG_COMPSING	0x0004	/* Enable single compression context */
+#define	HIFN_PUCNFG_ENCCNFG	0x0002	/* Encryption configuration */
+
+/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */
+#define	HIFN_PUIER_CMDINVAL	0x8000	/* Invalid command interrupt */
+#define	HIFN_PUIER_DATAERR	0x4000	/* Data error interrupt */
+#define	HIFN_PUIER_SRCFIFO	0x2000	/* Source FIFO ready interrupt */
+#define	HIFN_PUIER_DSTFIFO	0x1000	/* Destination FIFO ready interrupt */
+#define	HIFN_PUIER_DSTOVER	0x0200	/* Destination overrun interrupt */
+#define	HIFN_PUIER_SRCCMD	0x0080	/* Source command interrupt */
+#define	HIFN_PUIER_SRCCTX	0x0040	/* Source context interrupt */
+#define	HIFN_PUIER_SRCDATA	0x0020	/* Source data interrupt */
+#define	HIFN_PUIER_DSTDATA	0x0010	/* Destination data interrupt */
+#define	HIFN_PUIER_DSTRESULT	0x0004	/* Destination result interrupt */
+
+/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */
+#define	HIFN_PUSTAT_CMDINVAL	0x8000	/* Invalid command interrupt */
+#define	HIFN_PUSTAT_DATAERR	0x4000	/* Data error interrupt */
+#define	HIFN_PUSTAT_SRCFIFO	0x2000	/* Source FIFO ready interrupt */
+#define	HIFN_PUSTAT_DSTFIFO	0x1000	/* Destination FIFO ready interrupt */
+#define	HIFN_PUSTAT_DSTOVER	0x0200	/* Destination overrun interrupt */
+#define	HIFN_PUSTAT_SRCCMD	0x0080	/* Source command interrupt */
+#define	HIFN_PUSTAT_SRCCTX	0x0040	/* Source context interrupt */
+#define	HIFN_PUSTAT_SRCDATA	0x0020	/* Source data interrupt */
+#define	HIFN_PUSTAT_DSTDATA	0x0010	/* Destination data interrupt */
+#define	HIFN_PUSTAT_DSTRESULT	0x0004	/* Destination result interrupt */
+#define	HIFN_PUSTAT_CHIPREV	0x00ff	/* Chip revision mask */
+#define	HIFN_PUSTAT_CHIPENA	0xff00	/* Chip enabled mask */
+#define	HIFN_PUSTAT_ENA_2	0x1100	/* Level 2 enabled */
+#define	HIFN_PUSTAT_ENA_1	0x1000	/* Level 1 enabled */
+#define	HIFN_PUSTAT_ENA_0	0x3000	/* Level 0 enabled */
+#define	HIFN_PUSTAT_REV_2	0x0020	/* 7751 PT6/2 */
+#define	HIFN_PUSTAT_REV_3	0x0030	/* 7751 PT6/3 */
+
+/* FIFO Status Register (HIFN_0_FIFOSTAT) */
+#define	HIFN_FIFOSTAT_SRC	0x7f00	/* Source FIFO available */
+#define	HIFN_FIFOSTAT_DST	0x007f	/* Destination FIFO available */
+
+/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */
+#define	HIFN_FIFOCNFG_THRESHOLD	0x0400	/* must be written as 1 */
+
+/*
+ * DMA Interface Registers (offset from BASEREG1)
+ */
+#define	HIFN_1_DMA_CRAR		0x0c	/* DMA Command Ring Address */
+#define	HIFN_1_DMA_SRAR		0x1c	/* DMA Source Ring Address */
+#define	HIFN_1_DMA_RRAR		0x2c	/* DMA Result Ring Address */
+#define	HIFN_1_DMA_DRAR		0x3c	/* DMA Destination Ring Address */
+#define	HIFN_1_DMA_CSR		0x40	/* DMA Status and Control */
+#define	HIFN_1_DMA_IER		0x44	/* DMA Interrupt Enable */
+#define	HIFN_1_DMA_CNFG		0x48	/* DMA Configuration */
+#define	HIFN_1_PLL		0x4c	/* 795x: PLL config */
+#define	HIFN_1_7811_RNGENA	0x60	/* 7811: rng enable */
+#define	HIFN_1_7811_RNGCFG	0x64	/* 7811: rng config */
+#define	HIFN_1_7811_RNGDAT	0x68	/* 7811: rng data */
+#define	HIFN_1_7811_RNGSTS	0x6c	/* 7811: rng status */
+#define	HIFN_1_7811_MIPSRST	0x94	/* 7811: MIPS reset */
+#define	HIFN_1_REVID		0x98	/* Revision ID */
+#define	HIFN_1_UNLOCK_SECRET1	0xf4
+#define	HIFN_1_UNLOCK_SECRET2	0xfc
+#define	HIFN_1_PUB_RESET	0x204	/* Public/RNG Reset */
+#define	HIFN_1_PUB_BASE		0x300	/* Public Base Address */
+#define	HIFN_1_PUB_OPLEN	0x304	/* Public Operand Length */
+#define	HIFN_1_PUB_OP		0x308	/* Public Operand */
+#define	HIFN_1_PUB_STATUS	0x30c	/* Public Status */
+#define	HIFN_1_PUB_IEN		0x310	/* Public Interrupt enable */
+#define	HIFN_1_RNG_CONFIG	0x314	/* RNG config */
+#define	HIFN_1_RNG_DATA		0x318	/* RNG data */
+#define	HIFN_1_PUB_MEM		0x400	/* start of Public key memory */
+#define	HIFN_1_PUB_MEMEND	0xbff	/* end of Public key memory */
+
+/* DMA Status and Control Register (HIFN_1_DMA_CSR) */
+#define	HIFN_DMACSR_D_CTRLMASK	0xc0000000	/* Destinition Ring Control */
+#define	HIFN_DMACSR_D_CTRL_NOP	0x00000000	/* Dest. Control: no-op */
+#define	HIFN_DMACSR_D_CTRL_DIS	0x40000000	/* Dest. Control: disable */
+#define	HIFN_DMACSR_D_CTRL_ENA	0x80000000	/* Dest. Control: enable */
+#define	HIFN_DMACSR_D_ABORT	0x20000000	/* Destinition Ring PCIAbort */
+#define	HIFN_DMACSR_D_DONE	0x10000000	/* Destinition Ring Done */
+#define	HIFN_DMACSR_D_LAST	0x08000000	/* Destinition Ring Last */
+#define	HIFN_DMACSR_D_WAIT	0x04000000	/* Destinition Ring Waiting */
+#define	HIFN_DMACSR_D_OVER	0x02000000	/* Destinition Ring Overflow */
+#define	HIFN_DMACSR_R_CTRL	0x00c00000	/* Result Ring Control */
+#define	HIFN_DMACSR_R_CTRL_NOP	0x00000000	/* Result Control: no-op */
+#define	HIFN_DMACSR_R_CTRL_DIS	0x00400000	/* Result Control: disable */
+#define	HIFN_DMACSR_R_CTRL_ENA	0x00800000	/* Result Control: enable */
+#define	HIFN_DMACSR_R_ABORT	0x00200000	/* Result Ring PCI Abort */
+#define	HIFN_DMACSR_R_DONE	0x00100000	/* Result Ring Done */
+#define	HIFN_DMACSR_R_LAST	0x00080000	/* Result Ring Last */
+#define	HIFN_DMACSR_R_WAIT	0x00040000	/* Result Ring Waiting */
+#define	HIFN_DMACSR_R_OVER	0x00020000	/* Result Ring Overflow */
+#define	HIFN_DMACSR_S_CTRL	0x0000c000	/* Source Ring Control */
+#define	HIFN_DMACSR_S_CTRL_NOP	0x00000000	/* Source Control: no-op */
+#define	HIFN_DMACSR_S_CTRL_DIS	0x00004000	/* Source Control: disable */
+#define	HIFN_DMACSR_S_CTRL_ENA	0x00008000	/* Source Control: enable */
+#define	HIFN_DMACSR_S_ABORT	0x00002000	/* Source Ring PCI Abort */
+#define	HIFN_DMACSR_S_DONE	0x00001000	/* Source Ring Done */
+#define	HIFN_DMACSR_S_LAST	0x00000800	/* Source Ring Last */
+#define	HIFN_DMACSR_S_WAIT	0x00000400	/* Source Ring Waiting */
+#define	HIFN_DMACSR_ILLW	0x00000200	/* Illegal write (7811 only) */
+#define	HIFN_DMACSR_ILLR	0x00000100	/* Illegal read (7811 only) */
+#define	HIFN_DMACSR_C_CTRL	0x000000c0	/* Command Ring Control */
+#define	HIFN_DMACSR_C_CTRL_NOP	0x00000000	/* Command Control: no-op */
+#define	HIFN_DMACSR_C_CTRL_DIS	0x00000040	/* Command Control: disable */
+#define	HIFN_DMACSR_C_CTRL_ENA	0x00000080	/* Command Control: enable */
+#define	HIFN_DMACSR_C_ABORT	0x00000020	/* Command Ring PCI Abort */
+#define	HIFN_DMACSR_C_DONE	0x00000010	/* Command Ring Done */
+#define	HIFN_DMACSR_C_LAST	0x00000008	/* Command Ring Last */
+#define	HIFN_DMACSR_C_WAIT	0x00000004	/* Command Ring Waiting */
+#define	HIFN_DMACSR_PUBDONE	0x00000002	/* Public op done (7951 only) */
+#define	HIFN_DMACSR_ENGINE	0x00000001	/* Command Ring Engine IRQ */
+
+/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */
+#define	HIFN_DMAIER_D_ABORT	0x20000000	/* Destination Ring PCIAbort */
+#define	HIFN_DMAIER_D_DONE	0x10000000	/* Destination Ring Done */
+#define	HIFN_DMAIER_D_LAST	0x08000000	/* Destination Ring Last */
+#define	HIFN_DMAIER_D_WAIT	0x04000000	/* Destination Ring Waiting */
+#define	HIFN_DMAIER_D_OVER	0x02000000	/* Destination Ring Overflow */
+#define	HIFN_DMAIER_R_ABORT	0x00200000	/* Result Ring PCI Abort */
+#define	HIFN_DMAIER_R_DONE	0x00100000	/* Result Ring Done */
+#define	HIFN_DMAIER_R_LAST	0x00080000	/* Result Ring Last */
+#define	HIFN_DMAIER_R_WAIT	0x00040000	/* Result Ring Waiting */
+#define	HIFN_DMAIER_R_OVER	0x00020000	/* Result Ring Overflow */
+#define	HIFN_DMAIER_S_ABORT	0x00002000	/* Source Ring PCI Abort */
+#define	HIFN_DMAIER_S_DONE	0x00001000	/* Source Ring Done */
+#define	HIFN_DMAIER_S_LAST	0x00000800	/* Source Ring Last */
+#define	HIFN_DMAIER_S_WAIT	0x00000400	/* Source Ring Waiting */
+#define	HIFN_DMAIER_ILLW	0x00000200	/* Illegal write (7811 only) */
+#define	HIFN_DMAIER_ILLR	0x00000100	/* Illegal read (7811 only) */
+#define	HIFN_DMAIER_C_ABORT	0x00000020	/* Command Ring PCI Abort */
+#define	HIFN_DMAIER_C_DONE	0x00000010	/* Command Ring Done */
+#define	HIFN_DMAIER_C_LAST	0x00000008	/* Command Ring Last */
+#define	HIFN_DMAIER_C_WAIT	0x00000004	/* Command Ring Waiting */
+#define	HIFN_DMAIER_PUBDONE	0x00000002	/* public op done (7951 only) */
+#define	HIFN_DMAIER_ENGINE	0x00000001	/* Engine IRQ */
+
+/* DMA Configuration Register (HIFN_1_DMA_CNFG) */
+#define	HIFN_DMACNFG_BIGENDIAN	0x10000000	/* big endian mode */
+#define	HIFN_DMACNFG_POLLFREQ	0x00ff0000	/* Poll frequency mask */
+#define	HIFN_DMACNFG_UNLOCK	0x00000800
+#define	HIFN_DMACNFG_POLLINVAL	0x00000700	/* Invalid Poll Scalar */
+#define	HIFN_DMACNFG_LAST	0x00000010	/* Host control LAST bit */
+#define	HIFN_DMACNFG_MODE	0x00000004	/* DMA mode */
+#define	HIFN_DMACNFG_DMARESET	0x00000002	/* DMA Reset # */
+#define	HIFN_DMACNFG_MSTRESET	0x00000001	/* Master Reset # */
+
+/* PLL configuration register */
+#define HIFN_PLL_REF_CLK_HBI	0x00000000	/* HBI reference clock */
+#define HIFN_PLL_REF_CLK_PLL	0x00000001	/* PLL reference clock */
+#define HIFN_PLL_BP		0x00000002	/* Reference clock bypass */
+#define HIFN_PLL_PK_CLK_HBI	0x00000000	/* PK engine HBI clock */
+#define HIFN_PLL_PK_CLK_PLL	0x00000008	/* PK engine PLL clock */
+#define HIFN_PLL_PE_CLK_HBI	0x00000000	/* PE engine HBI clock */
+#define HIFN_PLL_PE_CLK_PLL	0x00000010	/* PE engine PLL clock */
+#define HIFN_PLL_RESERVED_1	0x00000400	/* Reserved bit, must be 1 */
+#define HIFN_PLL_ND_SHIFT	11		/* Clock multiplier shift */
+#define HIFN_PLL_ND_MULT_2	0x00000000	/* PLL clock multiplier 2 */
+#define HIFN_PLL_ND_MULT_4	0x00000800	/* PLL clock multiplier 4 */
+#define HIFN_PLL_ND_MULT_6	0x00001000	/* PLL clock multiplier 6 */
+#define HIFN_PLL_ND_MULT_8	0x00001800	/* PLL clock multiplier 8 */
+#define HIFN_PLL_ND_MULT_10	0x00002000	/* PLL clock multiplier 10 */
+#define HIFN_PLL_ND_MULT_12	0x00002800	/* PLL clock multiplier 12 */
+#define HIFN_PLL_IS_1_8		0x00000000	/* charge pump (mult. 1-8) */
+#define HIFN_PLL_IS_9_12	0x00010000	/* charge pump (mult. 9-12) */
+
+#define HIFN_PLL_FCK_MAX	266		/* Maximum PLL frequency */
+
+/* Public key reset register (HIFN_1_PUB_RESET) */
+#define	HIFN_PUBRST_RESET	0x00000001	/* reset public/rng unit */
+
+/* Public base address register (HIFN_1_PUB_BASE) */
+#define	HIFN_PUBBASE_ADDR	0x00003fff	/* base address */
+
+/* Public operand length register (HIFN_1_PUB_OPLEN) */
+#define	HIFN_PUBOPLEN_MOD_M	0x0000007f	/* modulus length mask */
+#define	HIFN_PUBOPLEN_MOD_S	0		/* modulus length shift */
+#define	HIFN_PUBOPLEN_EXP_M	0x0003ff80	/* exponent length mask */
+#define	HIFN_PUBOPLEN_EXP_S	7		/* exponent lenght shift */
+#define	HIFN_PUBOPLEN_RED_M	0x003c0000	/* reducend length mask */
+#define	HIFN_PUBOPLEN_RED_S	18		/* reducend length shift */
+
+/* Public operation register (HIFN_1_PUB_OP) */
+#define	HIFN_PUBOP_AOFFSET_M	0x0000007f	/* A offset mask */
+#define	HIFN_PUBOP_AOFFSET_S	0		/* A offset shift */
+#define	HIFN_PUBOP_BOFFSET_M	0x00000f80	/* B offset mask */
+#define	HIFN_PUBOP_BOFFSET_S	7		/* B offset shift */
+#define	HIFN_PUBOP_MOFFSET_M	0x0003f000	/* M offset mask */
+#define	HIFN_PUBOP_MOFFSET_S	12		/* M offset shift */
+#define	HIFN_PUBOP_OP_MASK	0x003c0000	/* Opcode: */
+#define	HIFN_PUBOP_OP_NOP	0x00000000	/*  NOP */
+#define	HIFN_PUBOP_OP_ADD	0x00040000	/*  ADD */
+#define	HIFN_PUBOP_OP_ADDC	0x00080000	/*  ADD w/carry */
+#define	HIFN_PUBOP_OP_SUB	0x000c0000	/*  SUB */
+#define	HIFN_PUBOP_OP_SUBC	0x00100000	/*  SUB w/carry */
+#define	HIFN_PUBOP_OP_MODADD	0x00140000	/*  Modular ADD */
+#define	HIFN_PUBOP_OP_MODSUB	0x00180000	/*  Modular SUB */
+#define	HIFN_PUBOP_OP_INCA	0x001c0000	/*  INC A */
+#define	HIFN_PUBOP_OP_DECA	0x00200000	/*  DEC A */
+#define	HIFN_PUBOP_OP_MULT	0x00240000	/*  MULT */
+#define	HIFN_PUBOP_OP_MODMULT	0x00280000	/*  Modular MULT */
+#define	HIFN_PUBOP_OP_MODRED	0x002c0000	/*  Modular RED */
+#define	HIFN_PUBOP_OP_MODEXP	0x00300000	/*  Modular EXP */
+
+/* Public status register (HIFN_1_PUB_STATUS) */
+#define	HIFN_PUBSTS_DONE	0x00000001	/* operation done */
+#define	HIFN_PUBSTS_CARRY	0x00000002	/* carry */
+
+/* Public interrupt enable register (HIFN_1_PUB_IEN) */
+#define	HIFN_PUBIEN_DONE	0x00000001	/* operation done interrupt */
+
+/* Random number generator config register (HIFN_1_RNG_CONFIG) */
+#define	HIFN_RNGCFG_ENA		0x00000001	/* enable rng */
+
+#define HIFN_NAMESIZE			32
+#define HIFN_MAX_RESULT_ORDER		5
+
+#define	HIFN_D_CMD_RSIZE		24*4
+#define	HIFN_D_SRC_RSIZE		80*4
+#define	HIFN_D_DST_RSIZE		80*4
+#define	HIFN_D_RES_RSIZE		24*4
+
+#define HIFN_QUEUE_LENGTH		HIFN_D_CMD_RSIZE-5
+
+#define AES_MIN_KEY_SIZE		16
+#define AES_MAX_KEY_SIZE		32
+
+#define HIFN_DES_KEY_LENGTH		8
+#define HIFN_3DES_KEY_LENGTH		24
+#define HIFN_MAX_CRYPT_KEY_LENGTH	AES_MAX_KEY_SIZE
+#define HIFN_IV_LENGTH			8
+#define HIFN_AES_IV_LENGTH		16
+#define	HIFN_MAX_IV_LENGTH		HIFN_AES_IV_LENGTH
+
+#define HIFN_MAC_KEY_LENGTH		64
+#define HIFN_MD5_LENGTH			16
+#define HIFN_SHA1_LENGTH		20
+#define HIFN_MAC_TRUNC_LENGTH		12
+
+#define	HIFN_MAX_COMMAND		(8 + 8 + 8 + 64 + 260)
+#define	HIFN_MAX_RESULT			(8 + 4 + 4 + 20 + 4)
+#define HIFN_USED_RESULT		12
+
+struct hifn_desc
+{
+	volatile u32		l;
+	volatile u32		p;
+};
+
+struct hifn_dma {
+	struct hifn_desc	cmdr[HIFN_D_CMD_RSIZE+1];
+	struct hifn_desc	srcr[HIFN_D_SRC_RSIZE+1];
+	struct hifn_desc	dstr[HIFN_D_DST_RSIZE+1];
+	struct hifn_desc	resr[HIFN_D_RES_RSIZE+1];
+
+	u8			command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND];
+	u8			result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT];
+
+	u64			test_src, test_dst;
+
+	/*
+	 *  Our current positions for insertion and removal from the descriptor
+	 *  rings.
+	 */
+	volatile int		cmdi, srci, dsti, resi;
+	volatile int		cmdu, srcu, dstu, resu;
+	int			cmdk, srck, dstk, resk;
+};
+
+#define HIFN_FLAG_CMD_BUSY	(1<<0)
+#define HIFN_FLAG_SRC_BUSY	(1<<1)
+#define HIFN_FLAG_DST_BUSY	(1<<2)
+#define HIFN_FLAG_RES_BUSY	(1<<3)
+#define HIFN_FLAG_OLD_KEY	(1<<4)
+
+#define HIFN_DEFAULT_ACTIVE_NUM	5
+
+struct hifn_device
+{
+	char			name[HIFN_NAMESIZE];
+
+	int			irq;
+
+	struct pci_dev		*pdev;
+	void __iomem		*bar[3];
+
+	unsigned long		result_mem;
+	dma_addr_t		dst;
+
+	void			*desc_virt;
+	dma_addr_t		desc_dma;
+
+	u32			dmareg;
+
+	void 			*sa[HIFN_D_RES_RSIZE];
+
+	spinlock_t		lock;
+
+	void 			*priv;
+
+	u32			flags;
+	int			active, started;
+	struct delayed_work	work;
+	unsigned long		reset;
+	unsigned long		success;
+	unsigned long		prev_success;
+
+	u8			snum;
+
+	struct tasklet_struct	tasklet;
+
+	struct crypto_queue 	queue;
+	struct list_head	alg_list;
+
+	unsigned int		pk_clk_freq;
+
+#ifdef CRYPTO_DEV_HIFN_795X_RNG
+	unsigned int		rng_wait_time;
+	ktime_t			rngtime;
+	struct hwrng		rng;
+#endif
+};
+
+#define	HIFN_D_LENGTH			0x0000ffff
+#define	HIFN_D_NOINVALID		0x01000000
+#define	HIFN_D_MASKDONEIRQ		0x02000000
+#define	HIFN_D_DESTOVER			0x04000000
+#define	HIFN_D_OVER			0x08000000
+#define	HIFN_D_LAST			0x20000000
+#define	HIFN_D_JUMP			0x40000000
+#define	HIFN_D_VALID			0x80000000
+
+struct hifn_base_command
+{
+	volatile u16		masks;
+	volatile u16		session_num;
+	volatile u16		total_source_count;
+	volatile u16		total_dest_count;
+};
+
+#define	HIFN_BASE_CMD_COMP		0x0100	/* enable compression engine */
+#define	HIFN_BASE_CMD_PAD		0x0200	/* enable padding engine */
+#define	HIFN_BASE_CMD_MAC		0x0400	/* enable MAC engine */
+#define	HIFN_BASE_CMD_CRYPT		0x0800	/* enable crypt engine */
+#define	HIFN_BASE_CMD_DECODE		0x2000
+#define	HIFN_BASE_CMD_SRCLEN_M		0xc000
+#define	HIFN_BASE_CMD_SRCLEN_S		14
+#define	HIFN_BASE_CMD_DSTLEN_M		0x3000
+#define	HIFN_BASE_CMD_DSTLEN_S		12
+#define	HIFN_BASE_CMD_LENMASK_HI	0x30000
+#define	HIFN_BASE_CMD_LENMASK_LO	0x0ffff
+
+/*
+ * Structure to help build up the command data structure.
+ */
+struct hifn_crypt_command
+{
+	volatile u16 		masks;
+	volatile u16 		header_skip;
+	volatile u16 		source_count;
+	volatile u16 		reserved;
+};
+
+#define	HIFN_CRYPT_CMD_ALG_MASK		0x0003		/* algorithm: */
+#define	HIFN_CRYPT_CMD_ALG_DES		0x0000		/*   DES */
+#define	HIFN_CRYPT_CMD_ALG_3DES		0x0001		/*   3DES */
+#define	HIFN_CRYPT_CMD_ALG_RC4		0x0002		/*   RC4 */
+#define	HIFN_CRYPT_CMD_ALG_AES		0x0003		/*   AES */
+#define	HIFN_CRYPT_CMD_MODE_MASK	0x0018		/* Encrypt mode: */
+#define	HIFN_CRYPT_CMD_MODE_ECB		0x0000		/*   ECB */
+#define	HIFN_CRYPT_CMD_MODE_CBC		0x0008		/*   CBC */
+#define	HIFN_CRYPT_CMD_MODE_CFB		0x0010		/*   CFB */
+#define	HIFN_CRYPT_CMD_MODE_OFB		0x0018		/*   OFB */
+#define	HIFN_CRYPT_CMD_CLR_CTX		0x0040		/* clear context */
+#define	HIFN_CRYPT_CMD_KSZ_MASK		0x0600		/* AES key size: */
+#define	HIFN_CRYPT_CMD_KSZ_128		0x0000		/*  128 bit */
+#define	HIFN_CRYPT_CMD_KSZ_192		0x0200		/*  192 bit */
+#define	HIFN_CRYPT_CMD_KSZ_256		0x0400		/*  256 bit */
+#define	HIFN_CRYPT_CMD_NEW_KEY		0x0800		/* expect new key */
+#define	HIFN_CRYPT_CMD_NEW_IV		0x1000		/* expect new iv */
+#define	HIFN_CRYPT_CMD_SRCLEN_M		0xc000
+#define	HIFN_CRYPT_CMD_SRCLEN_S		14
+
+/*
+ * Structure to help build up the command data structure.
+ */
+struct hifn_mac_command
+{
+	volatile u16 		masks;
+	volatile u16 		header_skip;
+	volatile u16 		source_count;
+	volatile u16 		reserved;
+};
+
+#define	HIFN_MAC_CMD_ALG_MASK		0x0001
+#define	HIFN_MAC_CMD_ALG_SHA1		0x0000
+#define	HIFN_MAC_CMD_ALG_MD5		0x0001
+#define	HIFN_MAC_CMD_MODE_MASK		0x000c
+#define	HIFN_MAC_CMD_MODE_HMAC		0x0000
+#define	HIFN_MAC_CMD_MODE_SSL_MAC	0x0004
+#define	HIFN_MAC_CMD_MODE_HASH		0x0008
+#define	HIFN_MAC_CMD_MODE_FULL		0x0004
+#define	HIFN_MAC_CMD_TRUNC		0x0010
+#define	HIFN_MAC_CMD_RESULT		0x0020
+#define	HIFN_MAC_CMD_APPEND		0x0040
+#define	HIFN_MAC_CMD_SRCLEN_M		0xc000
+#define	HIFN_MAC_CMD_SRCLEN_S		14
+
+/*
+ * MAC POS IPsec initiates authentication after encryption on encodes
+ * and before decryption on decodes.
+ */
+#define	HIFN_MAC_CMD_POS_IPSEC		0x0200
+#define	HIFN_MAC_CMD_NEW_KEY		0x0800
+
+struct hifn_comp_command
+{
+	volatile u16 		masks;
+	volatile u16 		header_skip;
+	volatile u16 		source_count;
+	volatile u16 		reserved;
+};
+
+#define	HIFN_COMP_CMD_SRCLEN_M		0xc000
+#define	HIFN_COMP_CMD_SRCLEN_S		14
+#define	HIFN_COMP_CMD_ONE		0x0100	/* must be one */
+#define	HIFN_COMP_CMD_CLEARHIST		0x0010	/* clear history */
+#define	HIFN_COMP_CMD_UPDATEHIST	0x0008	/* update history */
+#define	HIFN_COMP_CMD_LZS_STRIP0	0x0004	/* LZS: strip zero */
+#define	HIFN_COMP_CMD_MPPC_RESTART	0x0004	/* MPPC: restart */
+#define	HIFN_COMP_CMD_ALG_MASK		0x0001	/* compression mode: */
+#define	HIFN_COMP_CMD_ALG_MPPC		0x0001	/*   MPPC */
+#define	HIFN_COMP_CMD_ALG_LZS		0x0000	/*   LZS */
+
+struct hifn_base_result
+{
+	volatile u16 		flags;
+	volatile u16 		session;
+	volatile u16 		src_cnt;		/* 15:0 of source count */
+	volatile u16 		dst_cnt;		/* 15:0 of dest count */
+};
+
+#define	HIFN_BASE_RES_DSTOVERRUN	0x0200	/* destination overrun */
+#define	HIFN_BASE_RES_SRCLEN_M		0xc000	/* 17:16 of source count */
+#define	HIFN_BASE_RES_SRCLEN_S		14
+#define	HIFN_BASE_RES_DSTLEN_M		0x3000	/* 17:16 of dest count */
+#define	HIFN_BASE_RES_DSTLEN_S		12
+
+struct hifn_comp_result
+{
+	volatile u16 		flags;
+	volatile u16 		crc;
+};
+
+#define	HIFN_COMP_RES_LCB_M		0xff00	/* longitudinal check byte */
+#define	HIFN_COMP_RES_LCB_S		8
+#define	HIFN_COMP_RES_RESTART		0x0004	/* MPPC: restart */
+#define	HIFN_COMP_RES_ENDMARKER		0x0002	/* LZS: end marker seen */
+#define	HIFN_COMP_RES_SRC_NOTZERO	0x0001	/* source expired */
+
+struct hifn_mac_result
+{
+	volatile u16 		flags;
+	volatile u16 		reserved;
+	/* followed by 0, 6, 8, or 10 u16's of the MAC, then crypt */
+};
+
+#define	HIFN_MAC_RES_MISCOMPARE		0x0002	/* compare failed */
+#define	HIFN_MAC_RES_SRC_NOTZERO	0x0001	/* source expired */
+
+struct hifn_crypt_result
+{
+	volatile u16 		flags;
+	volatile u16 		reserved;
+};
+
+#define	HIFN_CRYPT_RES_SRC_NOTZERO	0x0001	/* source expired */
+
+#ifndef HIFN_POLL_FREQUENCY
+#define	HIFN_POLL_FREQUENCY	0x1
+#endif
+
+#ifndef HIFN_POLL_SCALAR
+#define	HIFN_POLL_SCALAR	0x0
+#endif
+
+#define	HIFN_MAX_SEGLEN 	0xffff		/* maximum dma segment len */
+#define	HIFN_MAX_DMALEN		0x3ffff		/* maximum dma length */
+
+struct hifn_crypto_alg
+{
+	struct list_head	entry;
+	struct crypto_alg	alg;
+	struct hifn_device	*dev;
+};
+
+#define ASYNC_SCATTERLIST_CACHE	16
+
+#define ASYNC_FLAGS_MISALIGNED	(1<<0)
+
+struct ablkcipher_walk
+{
+	struct scatterlist	cache[ASYNC_SCATTERLIST_CACHE];
+	u32			flags;
+	int			num;
+};
+
+struct hifn_context
+{
+	u8			key[HIFN_MAX_CRYPT_KEY_LENGTH], *iv;
+	struct hifn_device	*dev;
+	unsigned int		keysize, ivsize;
+	u8			op, type, mode, unused;
+	struct ablkcipher_walk	walk;
+	atomic_t		sg_num;
+};
+
+#define crypto_alg_to_hifn(a)	container_of(a, struct hifn_crypto_alg, alg)
+
+static inline u32 hifn_read_0(struct hifn_device *dev, u32 reg)
+{
+	u32 ret;
+
+	ret = readl((char *)(dev->bar[0]) + reg);
+
+	return ret;
+}
+
+static inline u32 hifn_read_1(struct hifn_device *dev, u32 reg)
+{
+	u32 ret;
+
+	ret = readl((char *)(dev->bar[1]) + reg);
+
+	return ret;
+}
+
+static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val)
+{
+	writel(val, (char *)(dev->bar[0]) + reg);
+}
+
+static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val)
+{
+	writel(val, (char *)(dev->bar[1]) + reg);
+}
+
+static void hifn_wait_puc(struct hifn_device *dev)
+{
+	int i;
+	u32 ret;
+
+	for (i=10000; i > 0; --i) {
+		ret = hifn_read_0(dev, HIFN_0_PUCTRL);
+		if (!(ret & HIFN_PUCTRL_RESET))
+			break;
+
+		udelay(1);
+	}
+
+	if (!i)
+		dprintk("%s: Failed to reset PUC unit.\n", dev->name);
+}
+
+static void hifn_reset_puc(struct hifn_device *dev)
+{
+	hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA);
+	hifn_wait_puc(dev);
+}
+
+static void hifn_stop_device(struct hifn_device *dev)
+{
+	hifn_write_1(dev, HIFN_1_DMA_CSR,
+		HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS |
+		HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS);
+	hifn_write_0(dev, HIFN_0_PUIER, 0);
+	hifn_write_1(dev, HIFN_1_DMA_IER, 0);
+}
+
+static void hifn_reset_dma(struct hifn_device *dev, int full)
+{
+	hifn_stop_device(dev);
+
+	/*
+	 * Setting poll frequency and others to 0.
+	 */
+	hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
+			HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
+	mdelay(1);
+
+	/*
+	 * Reset DMA.
+	 */
+	if (full) {
+		hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE);
+		mdelay(1);
+	} else {
+		hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE |
+				HIFN_DMACNFG_MSTRESET);
+		hifn_reset_puc(dev);
+	}
+
+	hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
+			HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
+
+	hifn_reset_puc(dev);
+}
+
+static u32 hifn_next_signature(u_int32_t a, u_int cnt)
+{
+	int i;
+	u32 v;
+
+	for (i = 0; i < cnt; i++) {
+
+		/* get the parity */
+		v = a & 0x80080125;
+		v ^= v >> 16;
+		v ^= v >> 8;
+		v ^= v >> 4;
+		v ^= v >> 2;
+		v ^= v >> 1;
+
+		a = (v & 1) ^ (a << 1);
+	}
+
+	return a;
+}
+
+static struct pci2id {
+	u_short		pci_vendor;
+	u_short		pci_prod;
+	char		card_id[13];
+} pci2id[] = {
+	{
+		PCI_VENDOR_ID_HIFN,
+		PCI_DEVICE_ID_HIFN_7955,
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00 }
+	},
+	{
+		PCI_VENDOR_ID_HIFN,
+		PCI_DEVICE_ID_HIFN_7956,
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x00, 0x00, 0x00, 0x00, 0x00 }
+	}
+};
+
+#ifdef CRYPTO_DEV_HIFN_795X_RNG
+static int hifn_rng_data_present(struct hwrng *rng, int wait)
+{
+	struct hifn_device *dev = (struct hifn_device *)rng->priv;
+	s64 nsec;
+
+	nsec = ktime_to_ns(ktime_sub(ktime_get(), dev->rngtime));
+	nsec -= dev->rng_wait_time;
+	if (nsec <= 0)
+		return 1;
+	if (!wait)
+		return 0;
+	ndelay(nsec);
+	return 1;
+}
+
+static int hifn_rng_data_read(struct hwrng *rng, u32 *data)
+{
+	struct hifn_device *dev = (struct hifn_device *)rng->priv;
+
+	*data = hifn_read_1(dev, HIFN_1_RNG_DATA);
+	dev->rngtime = ktime_get();
+	return 4;
+}
+
+static int hifn_register_rng(struct hifn_device *dev)
+{
+	/*
+	 * We must wait at least 256 Pk_clk cycles between two reads of the rng.
+	 */
+	dev->rng_wait_time	= DIV_ROUND_UP(NSEC_PER_SEC, dev->pk_clk_freq) *
+				  256;
+
+	dev->rng.name		= dev->name;
+	dev->rng.data_present	= hifn_rng_data_present,
+	dev->rng.data_read	= hifn_rng_data_read,
+	dev->rng.priv		= (unsigned long)dev;
+
+	return hwrng_register(&dev->rng);
+}
+
+static void hifn_unregister_rng(struct hifn_device *dev)
+{
+	hwrng_unregister(&dev->rng);
+}
+#else
+#define hifn_register_rng(dev)		0
+#define hifn_unregister_rng(dev)
+#endif
+
+static int hifn_init_pubrng(struct hifn_device *dev)
+{
+	int i;
+
+	hifn_write_1(dev, HIFN_1_PUB_RESET, hifn_read_1(dev, HIFN_1_PUB_RESET) |
+			HIFN_PUBRST_RESET);
+
+	for (i=100; i > 0; --i) {
+		mdelay(1);
+
+		if ((hifn_read_1(dev, HIFN_1_PUB_RESET) & HIFN_PUBRST_RESET) == 0)
+			break;
+	}
+
+	if (!i)
+		dprintk("Chip %s: Failed to initialise public key engine.\n",
+				dev->name);
+	else {
+		hifn_write_1(dev, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE);
+		dev->dmareg |= HIFN_DMAIER_PUBDONE;
+		hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+
+		dprintk("Chip %s: Public key engine has been sucessfully "
+				"initialised.\n", dev->name);
+	}
+
+	/*
+	 * Enable RNG engine.
+	 */
+
+	hifn_write_1(dev, HIFN_1_RNG_CONFIG,
+			hifn_read_1(dev, HIFN_1_RNG_CONFIG) | HIFN_RNGCFG_ENA);
+	dprintk("Chip %s: RNG engine has been successfully initialised.\n",
+			dev->name);
+
+#ifdef CRYPTO_DEV_HIFN_795X_RNG
+	/* First value must be discarded */
+	hifn_read_1(dev, HIFN_1_RNG_DATA);
+	dev->rngtime = ktime_get();
+#endif
+	return 0;
+}
+
+static int hifn_enable_crypto(struct hifn_device *dev)
+{
+	u32 dmacfg, addr;
+	char *offtbl = NULL;
+	int i;
+
+	for (i = 0; i < sizeof(pci2id)/sizeof(pci2id[0]); i++) {
+		if (pci2id[i].pci_vendor == dev->pdev->vendor &&
+				pci2id[i].pci_prod == dev->pdev->device) {
+			offtbl = pci2id[i].card_id;
+			break;
+		}
+	}
+
+	if (offtbl == NULL) {
+		dprintk("Chip %s: Unknown card!\n", dev->name);
+		return -ENODEV;
+	}
+
+	dmacfg = hifn_read_1(dev, HIFN_1_DMA_CNFG);
+
+	hifn_write_1(dev, HIFN_1_DMA_CNFG,
+			HIFN_DMACNFG_UNLOCK | HIFN_DMACNFG_MSTRESET |
+			HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE);
+	mdelay(1);
+	addr = hifn_read_1(dev, HIFN_1_UNLOCK_SECRET1);
+	mdelay(1);
+	hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, 0);
+	mdelay(1);
+
+	for (i=0; i<12; ++i) {
+		addr = hifn_next_signature(addr, offtbl[i] + 0x101);
+		hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, addr);
+
+		mdelay(1);
+	}
+	hifn_write_1(dev, HIFN_1_DMA_CNFG, dmacfg);
+
+	dprintk("Chip %s: %s.\n", dev->name, pci_name(dev->pdev));
+
+	return 0;
+}
+
+static void hifn_init_dma(struct hifn_device *dev)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	u32 dptr = dev->desc_dma;
+	int i;
+
+	for (i=0; i<HIFN_D_CMD_RSIZE; ++i)
+		dma->cmdr[i].p = __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, command_bufs[i][0]));
+	for (i=0; i<HIFN_D_RES_RSIZE; ++i)
+		dma->resr[i].p = __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, result_bufs[i][0]));
+
+	/*
+	 * Setup LAST descriptors.
+	 */
+	dma->cmdr[HIFN_D_CMD_RSIZE].p = __cpu_to_le32(dptr +
+			offsetof(struct hifn_dma, cmdr[0]));
+	dma->srcr[HIFN_D_SRC_RSIZE].p = __cpu_to_le32(dptr +
+			offsetof(struct hifn_dma, srcr[0]));
+	dma->dstr[HIFN_D_DST_RSIZE].p = __cpu_to_le32(dptr +
+			offsetof(struct hifn_dma, dstr[0]));
+	dma->resr[HIFN_D_RES_RSIZE].p = __cpu_to_le32(dptr +
+			offsetof(struct hifn_dma, resr[0]));
+
+	dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0;
+	dma->cmdi = dma->srci = dma->dsti = dma->resi = 0;
+	dma->cmdk = dma->srck = dma->dstk = dma->resk = 0;
+}
+
+/*
+ * Initialize the PLL. We need to know the frequency of the reference clock
+ * to calculate the optimal multiplier. For PCI we assume 66MHz, since that
+ * allows us to operate without the risk of overclocking the chip. If it
+ * actually uses 33MHz, the chip will operate at half the speed, this can be
+ * overriden by specifying the frequency as module parameter (pci33).
+ *
+ * Unfortunately the PCI clock is not very suitable since the HIFN needs a
+ * stable clock and the PCI clock frequency may vary, so the default is the
+ * external clock. There is no way to find out its frequency, we default to
+ * 66MHz since according to Mike Ham of HiFn, almost every board in existence
+ * has an external crystal populated at 66MHz.
+ */
+static void hifn_init_pll(struct hifn_device *dev)
+{
+	unsigned int freq, m;
+	u32 pllcfg;
+
+	pllcfg = HIFN_1_PLL | HIFN_PLL_RESERVED_1;
+
+	if (strncmp(hifn_pll_ref, "ext", 3) == 0)
+		pllcfg |= HIFN_PLL_REF_CLK_PLL;
+	else
+		pllcfg |= HIFN_PLL_REF_CLK_HBI;
+
+	if (hifn_pll_ref[3] != '\0')
+		freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10);
+	else {
+		freq = 66;
+		printk(KERN_INFO "hifn795x: assuming %uMHz clock speed, "
+				 "override with hifn_pll_ref=%.3s<frequency>\n",
+		       freq, hifn_pll_ref);
+	}
+
+	m = HIFN_PLL_FCK_MAX / freq;
+
+	pllcfg |= (m / 2 - 1) << HIFN_PLL_ND_SHIFT;
+	if (m <= 8)
+		pllcfg |= HIFN_PLL_IS_1_8;
+	else
+		pllcfg |= HIFN_PLL_IS_9_12;
+
+	/* Select clock source and enable clock bypass */
+	hifn_write_1(dev, HIFN_1_PLL, pllcfg |
+		     HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI | HIFN_PLL_BP);
+
+	/* Let the chip lock to the input clock */
+	mdelay(10);
+
+	/* Disable clock bypass */
+	hifn_write_1(dev, HIFN_1_PLL, pllcfg |
+		     HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI);
+
+	/* Switch the engines to the PLL */
+	hifn_write_1(dev, HIFN_1_PLL, pllcfg |
+		     HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL);
+
+	/*
+	 * The Fpk_clk runs at half the total speed. Its frequency is needed to
+	 * calculate the minimum time between two reads of the rng. Since 33MHz
+	 * is actually 33.333... we overestimate the frequency here, resulting
+	 * in slightly larger intervals.
+	 */
+	dev->pk_clk_freq = 1000000 * (freq + 1) * m / 2;
+}
+
+static void hifn_init_registers(struct hifn_device *dev)
+{
+	u32 dptr = dev->desc_dma;
+
+	/* Initialization magic... */
+	hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA);
+	hifn_write_0(dev, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD);
+	hifn_write_0(dev, HIFN_0_PUIER, HIFN_PUIER_DSTOVER);
+
+	/* write all 4 ring address registers */
+	hifn_write_1(dev, HIFN_1_DMA_CRAR, __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, cmdr[0])));
+	hifn_write_1(dev, HIFN_1_DMA_SRAR, __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, srcr[0])));
+	hifn_write_1(dev, HIFN_1_DMA_DRAR, __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, dstr[0])));
+	hifn_write_1(dev, HIFN_1_DMA_RRAR, __cpu_to_le32(dptr +
+				offsetof(struct hifn_dma, resr[0])));
+
+	mdelay(2);
+#if 0
+	hifn_write_1(dev, HIFN_1_DMA_CSR,
+	    HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS |
+	    HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS |
+	    HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST |
+	    HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER |
+	    HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST |
+	    HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER |
+	    HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST |
+	    HIFN_DMACSR_S_WAIT |
+	    HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST |
+	    HIFN_DMACSR_C_WAIT |
+	    HIFN_DMACSR_ENGINE |
+	    HIFN_DMACSR_PUBDONE);
+#else
+	hifn_write_1(dev, HIFN_1_DMA_CSR,
+	    HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA |
+	    HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA |
+	    HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST |
+	    HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER |
+	    HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST |
+	    HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER |
+	    HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST |
+	    HIFN_DMACSR_S_WAIT |
+	    HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST |
+	    HIFN_DMACSR_C_WAIT |
+	    HIFN_DMACSR_ENGINE |
+	    HIFN_DMACSR_PUBDONE);
+#endif
+	hifn_read_1(dev, HIFN_1_DMA_CSR);
+
+	dev->dmareg |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT |
+	    HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER |
+	    HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT |
+	    HIFN_DMAIER_ENGINE;
+	dev->dmareg &= ~HIFN_DMAIER_C_WAIT;
+
+	hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+	hifn_read_1(dev, HIFN_1_DMA_IER);
+#if 0
+	hifn_write_0(dev, HIFN_0_PUCNFG, HIFN_PUCNFG_ENCCNFG |
+		    HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES |
+		    HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 |
+		    HIFN_PUCNFG_DRAM);
+#else
+	hifn_write_0(dev, HIFN_0_PUCNFG, 0x10342);
+#endif
+	hifn_init_pll(dev);
+
+	hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
+	hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET |
+	    HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST |
+	    ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) |
+	    ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL));
+}
+
+static int hifn_setup_base_command(struct hifn_device *dev, u8 *buf,
+		unsigned dlen, unsigned slen, u16 mask, u8 snum)
+{
+	struct hifn_base_command *base_cmd;
+	u8 *buf_pos = buf;
+
+	base_cmd = (struct hifn_base_command *)buf_pos;
+	base_cmd->masks = __cpu_to_le16(mask);
+	base_cmd->total_source_count =
+		__cpu_to_le16(slen & HIFN_BASE_CMD_LENMASK_LO);
+	base_cmd->total_dest_count =
+		__cpu_to_le16(dlen & HIFN_BASE_CMD_LENMASK_LO);
+
+	dlen >>= 16;
+	slen >>= 16;
+	base_cmd->session_num = __cpu_to_le16(snum |
+	    ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) |
+	    ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M));
+
+	return sizeof(struct hifn_base_command);
+}
+
+static int hifn_setup_crypto_command(struct hifn_device *dev,
+		u8 *buf, unsigned dlen, unsigned slen,
+		u8 *key, int keylen, u8 *iv, int ivsize, u16 mode)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	struct hifn_crypt_command *cry_cmd;
+	u8 *buf_pos = buf;
+	u16 cmd_len;
+
+	cry_cmd = (struct hifn_crypt_command *)buf_pos;
+
+	cry_cmd->source_count = __cpu_to_le16(dlen & 0xffff);
+	dlen >>= 16;
+	cry_cmd->masks = __cpu_to_le16(mode |
+			((dlen << HIFN_CRYPT_CMD_SRCLEN_S) &
+			 HIFN_CRYPT_CMD_SRCLEN_M));
+	cry_cmd->header_skip = 0;
+	cry_cmd->reserved = 0;
+
+	buf_pos += sizeof(struct hifn_crypt_command);
+
+	dma->cmdu++;
+	if (dma->cmdu > 1) {
+		dev->dmareg |= HIFN_DMAIER_C_WAIT;
+		hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+	}
+
+	if (keylen) {
+		memcpy(buf_pos, key, keylen);
+		buf_pos += keylen;
+	}
+	if (ivsize) {
+		memcpy(buf_pos, iv, ivsize);
+		buf_pos += ivsize;
+	}
+
+	cmd_len = buf_pos - buf;
+
+	return cmd_len;
+}
+
+static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page,
+		unsigned int offset, unsigned int size)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	int idx;
+	dma_addr_t addr;
+
+	addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_TODEVICE);
+
+	idx = dma->srci;
+
+	dma->srcr[idx].p = __cpu_to_le32(addr);
+	dma->srcr[idx].l = __cpu_to_le32(size) | HIFN_D_VALID |
+			HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST;
+
+	if (++idx == HIFN_D_SRC_RSIZE) {
+		dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID |
+				HIFN_D_JUMP |
+				HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+		idx = 0;
+	}
+
+	dma->srci = idx;
+	dma->srcu++;
+
+	if (!(dev->flags & HIFN_FLAG_SRC_BUSY)) {
+		hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA);
+		dev->flags |= HIFN_FLAG_SRC_BUSY;
+	}
+
+	return size;
+}
+
+static void hifn_setup_res_desc(struct hifn_device *dev)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+	dma->resr[dma->resi].l = __cpu_to_le32(HIFN_USED_RESULT |
+			HIFN_D_VALID | HIFN_D_LAST);
+	/*
+	 * dma->resr[dma->resi].l = __cpu_to_le32(HIFN_MAX_RESULT | HIFN_D_VALID |
+	 *					HIFN_D_LAST | HIFN_D_NOINVALID);
+	 */
+
+	if (++dma->resi == HIFN_D_RES_RSIZE) {
+		dma->resr[HIFN_D_RES_RSIZE].l = __cpu_to_le32(HIFN_D_VALID |
+				HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | HIFN_D_LAST);
+		dma->resi = 0;
+	}
+
+	dma->resu++;
+
+	if (!(dev->flags & HIFN_FLAG_RES_BUSY)) {
+		hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA);
+		dev->flags |= HIFN_FLAG_RES_BUSY;
+	}
+}
+
+static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page,
+		unsigned offset, unsigned size)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	int idx;
+	dma_addr_t addr;
+
+	addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_FROMDEVICE);
+
+	idx = dma->dsti;
+	dma->dstr[idx].p = __cpu_to_le32(addr);
+	dma->dstr[idx].l = __cpu_to_le32(size |	HIFN_D_VALID |
+			HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST);
+
+	if (++idx == HIFN_D_DST_RSIZE) {
+		dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID |
+				HIFN_D_JUMP | HIFN_D_MASKDONEIRQ |
+				HIFN_D_LAST | HIFN_D_NOINVALID);
+		idx = 0;
+	}
+	dma->dsti = idx;
+	dma->dstu++;
+
+	if (!(dev->flags & HIFN_FLAG_DST_BUSY)) {
+		hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA);
+		dev->flags |= HIFN_FLAG_DST_BUSY;
+	}
+}
+
+static int hifn_setup_dma(struct hifn_device *dev, struct page *spage, unsigned int soff,
+		struct page *dpage, unsigned int doff, unsigned int nbytes, void *priv,
+		struct hifn_context *ctx)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	int cmd_len, sa_idx;
+	u8 *buf, *buf_pos;
+	u16 mask;
+
+	dprintk("%s: spage: %p, soffset: %u, dpage: %p, doffset: %u, nbytes: %u, priv: %p, ctx: %p.\n",
+			dev->name, spage, soff, dpage, doff, nbytes, priv, ctx);
+
+	sa_idx = dma->resi;
+
+	hifn_setup_src_desc(dev, spage, soff, nbytes);
+
+	buf_pos = buf = dma->command_bufs[dma->cmdi];
+
+	mask = 0;
+	switch (ctx->op) {
+		case ACRYPTO_OP_DECRYPT:
+			mask = HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE;
+			break;
+		case ACRYPTO_OP_ENCRYPT:
+			mask = HIFN_BASE_CMD_CRYPT;
+			break;
+		case ACRYPTO_OP_HMAC:
+			mask = HIFN_BASE_CMD_MAC;
+			break;
+		default:
+			goto err_out;
+	}
+
+	buf_pos += hifn_setup_base_command(dev, buf_pos, nbytes,
+			nbytes, mask, dev->snum);
+
+	if (ctx->op == ACRYPTO_OP_ENCRYPT || ctx->op == ACRYPTO_OP_DECRYPT) {
+		u16 md = 0;
+
+		if (ctx->keysize)
+			md |= HIFN_CRYPT_CMD_NEW_KEY;
+		if (ctx->iv && ctx->mode != ACRYPTO_MODE_ECB)
+			md |= HIFN_CRYPT_CMD_NEW_IV;
+
+		switch (ctx->mode) {
+			case ACRYPTO_MODE_ECB:
+				md |= HIFN_CRYPT_CMD_MODE_ECB;
+				break;
+			case ACRYPTO_MODE_CBC:
+				md |= HIFN_CRYPT_CMD_MODE_CBC;
+				break;
+			case ACRYPTO_MODE_CFB:
+				md |= HIFN_CRYPT_CMD_MODE_CFB;
+				break;
+			case ACRYPTO_MODE_OFB:
+				md |= HIFN_CRYPT_CMD_MODE_OFB;
+				break;
+			default:
+				goto err_out;
+		}
+
+		switch (ctx->type) {
+			case ACRYPTO_TYPE_AES_128:
+				if (ctx->keysize != 16)
+					goto err_out;
+				md |= HIFN_CRYPT_CMD_KSZ_128 |
+					HIFN_CRYPT_CMD_ALG_AES;
+				break;
+			case ACRYPTO_TYPE_AES_192:
+				if (ctx->keysize != 24)
+					goto err_out;
+				md |= HIFN_CRYPT_CMD_KSZ_192 |
+					HIFN_CRYPT_CMD_ALG_AES;
+				break;
+			case ACRYPTO_TYPE_AES_256:
+				if (ctx->keysize != 32)
+					goto err_out;
+				md |= HIFN_CRYPT_CMD_KSZ_256 |
+					HIFN_CRYPT_CMD_ALG_AES;
+				break;
+			case ACRYPTO_TYPE_3DES:
+				if (ctx->keysize != 24)
+					goto err_out;
+				md |= HIFN_CRYPT_CMD_ALG_3DES;
+				break;
+			case ACRYPTO_TYPE_DES:
+				if (ctx->keysize != 8)
+					goto err_out;
+				md |= HIFN_CRYPT_CMD_ALG_DES;
+				break;
+			default:
+				goto err_out;
+		}
+
+		buf_pos += hifn_setup_crypto_command(dev, buf_pos,
+				nbytes, nbytes, ctx->key, ctx->keysize,
+				ctx->iv, ctx->ivsize, md);
+	}
+
+	dev->sa[sa_idx] = priv;
+
+	cmd_len = buf_pos - buf;
+	dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID |
+			HIFN_D_LAST | HIFN_D_MASKDONEIRQ);
+
+	if (++dma->cmdi == HIFN_D_CMD_RSIZE) {
+		dma->cmdr[dma->cmdi].l = __cpu_to_le32(HIFN_MAX_COMMAND |
+			HIFN_D_VALID | HIFN_D_LAST |
+			HIFN_D_MASKDONEIRQ | HIFN_D_JUMP);
+		dma->cmdi = 0;
+	} else
+		dma->cmdr[dma->cmdi-1].l |= __cpu_to_le32(HIFN_D_VALID);
+
+	if (!(dev->flags & HIFN_FLAG_CMD_BUSY)) {
+		hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA);
+		dev->flags |= HIFN_FLAG_CMD_BUSY;
+	}
+
+	hifn_setup_dst_desc(dev, dpage, doff, nbytes);
+	hifn_setup_res_desc(dev);
+
+	return 0;
+
+err_out:
+	return -EINVAL;
+}
+
+static int ablkcipher_walk_init(struct ablkcipher_walk *w,
+		int num, gfp_t gfp_flags)
+{
+	int i;
+
+	num = min(ASYNC_SCATTERLIST_CACHE, num);
+	sg_init_table(w->cache, num);
+
+	w->num = 0;
+	for (i=0; i<num; ++i) {
+		struct page *page = alloc_page(gfp_flags);
+		struct scatterlist *s;
+
+		if (!page)
+			break;
+
+		s = &w->cache[i];
+
+		sg_set_page(s, page, PAGE_SIZE, 0);
+		w->num++;
+	}
+
+	return i;
+}
+
+static void ablkcipher_walk_exit(struct ablkcipher_walk *w)
+{
+	int i;
+
+	for (i=0; i<w->num; ++i) {
+		struct scatterlist *s = &w->cache[i];
+
+		__free_page(sg_page(s));
+
+		s->length = 0;
+	}
+
+	w->num = 0;
+}
+
+static int ablkcipher_add(void *daddr, unsigned int *drestp, struct scatterlist *src,
+		unsigned int size, unsigned int *nbytesp)
+{
+	unsigned int copy, drest = *drestp, nbytes = *nbytesp;
+	int idx = 0;
+	void *saddr;
+
+	if (drest < size || size > nbytes)
+		return -EINVAL;
+
+	while (size) {
+		copy = min(drest, src->length);
+
+		saddr = kmap_atomic(sg_page(src), KM_SOFTIRQ1);
+		memcpy(daddr, saddr + src->offset, copy);
+		kunmap_atomic(saddr, KM_SOFTIRQ1);
+
+		size -= copy;
+		drest -= copy;
+		nbytes -= copy;
+		daddr += copy;
+
+		dprintk("%s: copy: %u, size: %u, drest: %u, nbytes: %u.\n",
+				__func__, copy, size, drest, nbytes);
+
+		src++;
+		idx++;
+	}
+
+	*nbytesp = nbytes;
+	*drestp = drest;
+
+	return idx;
+}
+
+static int ablkcipher_walk(struct ablkcipher_request *req,
+		struct ablkcipher_walk *w)
+{
+	unsigned blocksize =
+		crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req));
+	unsigned alignmask =
+		crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req));
+	struct scatterlist *src, *dst, *t;
+	void *daddr;
+	unsigned int nbytes = req->nbytes, offset, copy, diff;
+	int idx, tidx, err;
+
+	tidx = idx = 0;
+	offset = 0;
+	while (nbytes) {
+		if (idx >= w->num && (w->flags & ASYNC_FLAGS_MISALIGNED))
+			return -EINVAL;
+
+		src = &req->src[idx];
+		dst = &req->dst[idx];
+
+		dprintk("\n%s: slen: %u, dlen: %u, soff: %u, doff: %u, offset: %u, "
+				"blocksize: %u, nbytes: %u.\n",
+				__func__, src->length, dst->length, src->offset,
+				dst->offset, offset, blocksize, nbytes);
+
+		if (src->length & (blocksize - 1) ||
+				src->offset & (alignmask - 1) ||
+				dst->length & (blocksize - 1) ||
+				dst->offset & (alignmask - 1) ||
+				offset) {
+			unsigned slen = src->length - offset;
+			unsigned dlen = PAGE_SIZE;
+
+			t = &w->cache[idx];
+
+			daddr = kmap_atomic(sg_page(t), KM_SOFTIRQ0);
+			err = ablkcipher_add(daddr, &dlen, src, slen, &nbytes);
+			if (err < 0)
+				goto err_out_unmap;
+
+			idx += err;
+
+			copy = slen & ~(blocksize - 1);
+			diff = slen & (blocksize - 1);
+
+			if (dlen < nbytes) {
+				/*
+				 * Destination page does not have enough space
+				 * to put there additional blocksized chunk,
+				 * so we mark that page as containing only
+				 * blocksize aligned chunks:
+				 * 	t->length = (slen & ~(blocksize - 1));
+				 * and increase number of bytes to be processed
+				 * in next chunk:
+				 * 	nbytes += diff;
+				 */
+				nbytes += diff;
+
+				/*
+				 * Temporary of course...
+				 * Kick author if you will catch this one.
+				 */
+				printk(KERN_ERR "%s: dlen: %u, nbytes: %u,"
+					"slen: %u, offset: %u.\n",
+					__func__, dlen, nbytes, slen, offset);
+				printk(KERN_ERR "%s: please contact author to fix this "
+					"issue, generally you should not catch "
+					"this path under any condition but who "
+					"knows how did you use crypto code.\n"
+					"Thank you.\n",	__func__);
+				BUG();
+			} else {
+				copy += diff + nbytes;
+
+				src = &req->src[idx];
+
+				err = ablkcipher_add(daddr + slen, &dlen, src, nbytes, &nbytes);
+				if (err < 0)
+					goto err_out_unmap;
+
+				idx += err;
+			}
+
+			t->length = copy;
+			t->offset = offset;
+
+			kunmap_atomic(daddr, KM_SOFTIRQ0);
+		} else {
+			nbytes -= src->length;
+			idx++;
+		}
+
+		tidx++;
+	}
+
+	return tidx;
+
+err_out_unmap:
+	kunmap_atomic(daddr, KM_SOFTIRQ0);
+	return err;
+}
+
+static int hifn_setup_session(struct ablkcipher_request *req)
+{
+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hifn_device *dev = ctx->dev;
+	struct page *spage, *dpage;
+	unsigned long soff, doff, flags;
+	unsigned int nbytes = req->nbytes, idx = 0, len;
+	int err = -EINVAL, sg_num;
+	struct scatterlist *src, *dst, *t;
+	unsigned blocksize =
+		crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req));
+	unsigned alignmask =
+		crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req));
+
+	if (ctx->iv && !ctx->ivsize && ctx->mode != ACRYPTO_MODE_ECB)
+		goto err_out_exit;
+
+	ctx->walk.flags = 0;
+
+	while (nbytes) {
+		src = &req->src[idx];
+		dst = &req->dst[idx];
+
+		if (src->length & (blocksize - 1) ||
+				src->offset & (alignmask - 1) ||
+				dst->length & (blocksize - 1) ||
+				dst->offset & (alignmask - 1)) {
+			ctx->walk.flags |= ASYNC_FLAGS_MISALIGNED;
+		}
+
+		nbytes -= src->length;
+		idx++;
+	}
+
+	if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
+		err = ablkcipher_walk_init(&ctx->walk, idx, GFP_ATOMIC);
+		if (err < 0)
+			return err;
+	}
+
+	nbytes = req->nbytes;
+	idx = 0;
+
+	sg_num = ablkcipher_walk(req, &ctx->walk);
+
+	atomic_set(&ctx->sg_num, sg_num);
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->started + sg_num > HIFN_QUEUE_LENGTH) {
+		err = -EAGAIN;
+		goto err_out;
+	}
+
+	dev->snum++;
+	dev->started += sg_num;
+
+	while (nbytes) {
+		src = &req->src[idx];
+		dst = &req->dst[idx];
+		t = &ctx->walk.cache[idx];
+
+		if (t->length) {
+			spage = dpage = sg_page(t);
+			soff = doff = 0;
+			len = t->length;
+		} else {
+			spage = sg_page(src);
+			soff = src->offset;
+
+			dpage = sg_page(dst);
+			doff = dst->offset;
+
+			len = dst->length;
+		}
+
+		idx++;
+
+		err = hifn_setup_dma(dev, spage, soff, dpage, doff, nbytes,
+				req, ctx);
+		if (err)
+			goto err_out;
+
+		nbytes -= len;
+	}
+
+	dev->active = HIFN_DEFAULT_ACTIVE_NUM;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+
+err_out:
+	spin_unlock_irqrestore(&dev->lock, flags);
+err_out_exit:
+	if (err && printk_ratelimit())
+		dprintk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, "
+				"type: %u, err: %d.\n",
+			dev->name, ctx->iv, ctx->ivsize,
+			ctx->key, ctx->keysize,
+			ctx->mode, ctx->op, ctx->type, err);
+
+	return err;
+}
+
+static int hifn_test(struct hifn_device *dev, int encdec, u8 snum)
+{
+	int n, err;
+	u8 src[16];
+	struct hifn_context ctx;
+	u8 fips_aes_ecb_from_zero[16] = {
+		0x66, 0xE9, 0x4B, 0xD4,
+		0xEF, 0x8A, 0x2C, 0x3B,
+		0x88, 0x4C, 0xFA, 0x59,
+		0xCA, 0x34, 0x2B, 0x2E};
+
+	memset(src, 0, sizeof(src));
+	memset(ctx.key, 0, sizeof(ctx.key));
+
+	ctx.dev = dev;
+	ctx.keysize = 16;
+	ctx.ivsize = 0;
+	ctx.iv = NULL;
+	ctx.op = (encdec)?ACRYPTO_OP_ENCRYPT:ACRYPTO_OP_DECRYPT;
+	ctx.mode = ACRYPTO_MODE_ECB;
+	ctx.type = ACRYPTO_TYPE_AES_128;
+	atomic_set(&ctx.sg_num, 1);
+
+	err = hifn_setup_dma(dev,
+			virt_to_page(src), offset_in_page(src),
+			virt_to_page(src), offset_in_page(src),
+			sizeof(src), NULL, &ctx);
+	if (err)
+		goto err_out;
+
+	msleep(200);
+
+	dprintk("%s: decoded: ", dev->name);
+	for (n=0; n<sizeof(src); ++n)
+		dprintk("%02x ", src[n]);
+	dprintk("\n");
+	dprintk("%s: FIPS   : ", dev->name);
+	for (n=0; n<sizeof(fips_aes_ecb_from_zero); ++n)
+		dprintk("%02x ", fips_aes_ecb_from_zero[n]);
+	dprintk("\n");
+
+	if (!memcmp(src, fips_aes_ecb_from_zero, sizeof(fips_aes_ecb_from_zero))) {
+		printk(KERN_INFO "%s: AES 128 ECB test has been successfully "
+				"passed.\n", dev->name);
+		return 0;
+	}
+
+err_out:
+	printk(KERN_INFO "%s: AES 128 ECB test has been failed.\n", dev->name);
+	return -1;
+}
+
+static int hifn_start_device(struct hifn_device *dev)
+{
+	int err;
+
+	hifn_reset_dma(dev, 1);
+
+	err = hifn_enable_crypto(dev);
+	if (err)
+		return err;
+
+	hifn_reset_puc(dev);
+
+	hifn_init_dma(dev);
+
+	hifn_init_registers(dev);
+
+	hifn_init_pubrng(dev);
+
+	return 0;
+}
+
+static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset,
+		struct scatterlist *dst, unsigned int size, unsigned int *nbytesp)
+{
+	unsigned int srest = *srestp, nbytes = *nbytesp, copy;
+	void *daddr;
+	int idx = 0;
+
+	if (srest < size || size > nbytes)
+		return -EINVAL;
+
+	while (size) {
+
+		copy = min(dst->length, srest);
+
+		daddr = kmap_atomic(sg_page(dst), KM_IRQ0);
+		memcpy(daddr + dst->offset + offset, saddr, copy);
+		kunmap_atomic(daddr, KM_IRQ0);
+
+		nbytes -= copy;
+		size -= copy;
+		srest -= copy;
+		saddr += copy;
+		offset = 0;
+
+		dprintk("%s: copy: %u, size: %u, srest: %u, nbytes: %u.\n",
+				__func__, copy, size, srest, nbytes);
+
+		dst++;
+		idx++;
+	}
+
+	*nbytesp = nbytes;
+	*srestp = srest;
+
+	return idx;
+}
+
+static void hifn_process_ready(struct ablkcipher_request *req, int error)
+{
+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hifn_device *dev;
+
+	dprintk("%s: req: %p, ctx: %p.\n", __func__, req, ctx);
+
+	dev = ctx->dev;
+	dprintk("%s: req: %p, started: %d, sg_num: %d.\n",
+		__func__, req, dev->started, atomic_read(&ctx->sg_num));
+
+	if (--dev->started < 0)
+		BUG();
+
+	if (atomic_dec_and_test(&ctx->sg_num)) {
+		unsigned int nbytes = req->nbytes;
+		int idx = 0, err;
+		struct scatterlist *dst, *t;
+		void *saddr;
+
+		if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) {
+			while (nbytes) {
+				t = &ctx->walk.cache[idx];
+				dst = &req->dst[idx];
+
+				dprintk("\n%s: sg_page(t): %p, t->length: %u, "
+					"sg_page(dst): %p, dst->length: %u, "
+					"nbytes: %u.\n",
+					__func__, sg_page(t), t->length,
+					sg_page(dst), dst->length, nbytes);
+
+				if (!t->length) {
+					nbytes -= dst->length;
+					idx++;
+					continue;
+				}
+
+				saddr = kmap_atomic(sg_page(t), KM_IRQ1);
+
+				err = ablkcipher_get(saddr, &t->length, t->offset,
+						dst, nbytes, &nbytes);
+				if (err < 0) {
+					kunmap_atomic(saddr, KM_IRQ1);
+					break;
+				}
+
+				idx += err;
+				kunmap_atomic(saddr, KM_IRQ1);
+			}
+
+			ablkcipher_walk_exit(&ctx->walk);
+		}
+
+		req->base.complete(&req->base, error);
+	}
+}
+
+static void hifn_check_for_completion(struct hifn_device *dev, int error)
+{
+	int i;
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+	for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
+		struct hifn_desc *d = &dma->resr[i];
+
+		if (!(d->l & __cpu_to_le32(HIFN_D_VALID)) && dev->sa[i]) {
+			dev->success++;
+			dev->reset = 0;
+			hifn_process_ready(dev->sa[i], error);
+			dev->sa[i] = NULL;
+		}
+
+		if (d->l & __cpu_to_le32(HIFN_D_DESTOVER | HIFN_D_OVER))
+			if (printk_ratelimit())
+				printk("%s: overflow detected [d: %u, o: %u] "
+						"at %d resr: l: %08x, p: %08x.\n",
+					dev->name,
+					!!(d->l & __cpu_to_le32(HIFN_D_DESTOVER)),
+					!!(d->l & __cpu_to_le32(HIFN_D_OVER)),
+					i, d->l, d->p);
+	}
+}
+
+static void hifn_clear_rings(struct hifn_device *dev)
+{
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	int i, u;
+
+	dprintk("%s: ring cleanup 1: i: %d.%d.%d.%d, u: %d.%d.%d.%d, "
+			"k: %d.%d.%d.%d.\n",
+			dev->name,
+			dma->cmdi, dma->srci, dma->dsti, dma->resi,
+			dma->cmdu, dma->srcu, dma->dstu, dma->resu,
+			dma->cmdk, dma->srck, dma->dstk, dma->resk);
+
+	i = dma->resk; u = dma->resu;
+	while (u != 0) {
+		if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID))
+			break;
+
+		if (i != HIFN_D_RES_RSIZE)
+			u--;
+
+		if (++i == (HIFN_D_RES_RSIZE + 1))
+			i = 0;
+	}
+	dma->resk = i; dma->resu = u;
+
+	i = dma->srck; u = dma->srcu;
+	while (u != 0) {
+		if (i == HIFN_D_SRC_RSIZE)
+			i = 0;
+		if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID))
+			break;
+		i++, u--;
+	}
+	dma->srck = i; dma->srcu = u;
+
+	i = dma->cmdk; u = dma->cmdu;
+	while (u != 0) {
+		if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID))
+			break;
+		if (i != HIFN_D_CMD_RSIZE)
+			u--;
+		if (++i == (HIFN_D_CMD_RSIZE + 1))
+			i = 0;
+	}
+	dma->cmdk = i; dma->cmdu = u;
+
+	i = dma->dstk; u = dma->dstu;
+	while (u != 0) {
+		if (i == HIFN_D_DST_RSIZE)
+			i = 0;
+		if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID))
+			break;
+		i++, u--;
+	}
+	dma->dstk = i; dma->dstu = u;
+
+	dprintk("%s: ring cleanup 2: i: %d.%d.%d.%d, u: %d.%d.%d.%d, "
+			"k: %d.%d.%d.%d.\n",
+			dev->name,
+			dma->cmdi, dma->srci, dma->dsti, dma->resi,
+			dma->cmdu, dma->srcu, dma->dstu, dma->resu,
+			dma->cmdk, dma->srck, dma->dstk, dma->resk);
+}
+
+static void hifn_work(struct work_struct *work)
+{
+	struct delayed_work *dw = container_of(work, struct delayed_work, work);
+	struct hifn_device *dev = container_of(dw, struct hifn_device, work);
+	unsigned long flags;
+	int reset = 0;
+	u32 r = 0;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->active == 0) {
+		struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+
+		if (dma->cmdu == 0 && (dev->flags & HIFN_FLAG_CMD_BUSY)) {
+			dev->flags &= ~HIFN_FLAG_CMD_BUSY;
+			r |= HIFN_DMACSR_C_CTRL_DIS;
+		}
+		if (dma->srcu == 0 && (dev->flags & HIFN_FLAG_SRC_BUSY)) {
+			dev->flags &= ~HIFN_FLAG_SRC_BUSY;
+			r |= HIFN_DMACSR_S_CTRL_DIS;
+		}
+		if (dma->dstu == 0 && (dev->flags & HIFN_FLAG_DST_BUSY)) {
+			dev->flags &= ~HIFN_FLAG_DST_BUSY;
+			r |= HIFN_DMACSR_D_CTRL_DIS;
+		}
+		if (dma->resu == 0 && (dev->flags & HIFN_FLAG_RES_BUSY)) {
+			dev->flags &= ~HIFN_FLAG_RES_BUSY;
+			r |= HIFN_DMACSR_R_CTRL_DIS;
+		}
+		if (r)
+			hifn_write_1(dev, HIFN_1_DMA_CSR, r);
+	} else
+		dev->active--;
+
+	if (dev->prev_success == dev->success && dev->started)
+		reset = 1;
+	dev->prev_success = dev->success;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (reset) {
+		dprintk("%s: r: %08x, active: %d, started: %d, "
+				"success: %lu: reset: %d.\n",
+			dev->name, r, dev->active, dev->started,
+			dev->success, reset);
+
+		if (++dev->reset >= 5) {
+			dprintk("%s: really hard reset.\n", dev->name);
+			hifn_reset_dma(dev, 1);
+			hifn_stop_device(dev);
+			hifn_start_device(dev);
+			dev->reset = 0;
+		}
+
+		spin_lock_irqsave(&dev->lock, flags);
+		hifn_check_for_completion(dev, -EBUSY);
+		hifn_clear_rings(dev);
+		dev->started = 0;
+		spin_unlock_irqrestore(&dev->lock, flags);
+	}
+
+	schedule_delayed_work(&dev->work, HZ);
+}
+
+static irqreturn_t hifn_interrupt(int irq, void *data)
+{
+	struct hifn_device *dev = (struct hifn_device *)data;
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	u32 dmacsr, restart;
+
+	dmacsr = hifn_read_1(dev, HIFN_1_DMA_CSR);
+
+	dprintk("%s: 1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], "
+			"i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n",
+		dev->name, dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi,
+		dma->cmdu, dma->srcu, dma->dstu, dma->resu,
+		dma->cmdi, dma->srci, dma->dsti, dma->resi);
+
+	if ((dmacsr & dev->dmareg) == 0)
+		return IRQ_NONE;
+
+	hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & dev->dmareg);
+
+	if (dmacsr & HIFN_DMACSR_ENGINE)
+		hifn_write_0(dev, HIFN_0_PUISR, hifn_read_0(dev, HIFN_0_PUISR));
+	if (dmacsr & HIFN_DMACSR_PUBDONE)
+		hifn_write_1(dev, HIFN_1_PUB_STATUS,
+			hifn_read_1(dev, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE);
+
+	restart = dmacsr & (HIFN_DMACSR_R_OVER | HIFN_DMACSR_D_OVER);
+	if (restart) {
+		u32 puisr = hifn_read_0(dev, HIFN_0_PUISR);
+
+		if (printk_ratelimit())
+			printk("%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n",
+				dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER),
+				!!(dmacsr & HIFN_DMACSR_D_OVER),
+				puisr, !!(puisr & HIFN_PUISR_DSTOVER));
+		if (!!(puisr & HIFN_PUISR_DSTOVER))
+			hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER);
+		hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & (HIFN_DMACSR_R_OVER |
+					HIFN_DMACSR_D_OVER));
+	}
+
+	restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT |
+			HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT);
+	if (restart) {
+		if (printk_ratelimit())
+			printk("%s: abort: c: %d, s: %d, d: %d, r: %d.\n",
+				dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT),
+				!!(dmacsr & HIFN_DMACSR_S_ABORT),
+				!!(dmacsr & HIFN_DMACSR_D_ABORT),
+				!!(dmacsr & HIFN_DMACSR_R_ABORT));
+		hifn_reset_dma(dev, 1);
+		hifn_init_dma(dev);
+		hifn_init_registers(dev);
+	}
+
+	if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) {
+		dprintk("%s: wait on command.\n", dev->name);
+		dev->dmareg &= ~(HIFN_DMAIER_C_WAIT);
+		hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg);
+	}
+
+	tasklet_schedule(&dev->tasklet);
+	hifn_clear_rings(dev);
+
+	return IRQ_HANDLED;
+}
+
+static void hifn_flush(struct hifn_device *dev)
+{
+	unsigned long flags;
+	struct crypto_async_request *async_req;
+	struct hifn_context *ctx;
+	struct ablkcipher_request *req;
+	struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt;
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	for (i=0; i<HIFN_D_RES_RSIZE; ++i) {
+		struct hifn_desc *d = &dma->resr[i];
+
+		if (dev->sa[i]) {
+			hifn_process_ready(dev->sa[i],
+				(d->l & __cpu_to_le32(HIFN_D_VALID))?-ENODEV:0);
+		}
+	}
+
+	while ((async_req = crypto_dequeue_request(&dev->queue))) {
+		ctx = crypto_tfm_ctx(async_req->tfm);
+		req = container_of(async_req, struct ablkcipher_request, base);
+
+		hifn_process_ready(req, -ENODEV);
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static int hifn_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
+		unsigned int len)
+{
+	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+	struct hifn_context *ctx = crypto_tfm_ctx(tfm);
+	struct hifn_device *dev = ctx->dev;
+
+	if (len > HIFN_MAX_CRYPT_KEY_LENGTH) {
+		crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
+		return -1;
+	}
+
+	if (len == HIFN_DES_KEY_LENGTH) {
+		u32 tmp[DES_EXPKEY_WORDS];
+		int ret = des_ekey(tmp, key);
+		
+		if (unlikely(ret == 0) && (tfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+			tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
+			return -EINVAL;
+		}
+	}
+
+	dev->flags &= ~HIFN_FLAG_OLD_KEY;
+
+	memcpy(ctx->key, key, len);
+	ctx->keysize = len;
+
+	return 0;
+}
+
+static int hifn_handle_req(struct ablkcipher_request *req)
+{
+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hifn_device *dev = ctx->dev;
+	int err = -EAGAIN;
+
+	if (dev->started + DIV_ROUND_UP(req->nbytes, PAGE_SIZE) <= HIFN_QUEUE_LENGTH)
+		err = hifn_setup_session(req);
+
+	if (err == -EAGAIN) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&dev->lock, flags);
+		err = ablkcipher_enqueue_request(&dev->queue, req);
+		spin_unlock_irqrestore(&dev->lock, flags);
+	}
+
+	return err;
+}
+
+static int hifn_setup_crypto_req(struct ablkcipher_request *req, u8 op,
+		u8 type, u8 mode)
+{
+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	unsigned ivsize;
+
+	ivsize = crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(req));
+
+	if (req->info && mode != ACRYPTO_MODE_ECB) {
+		if (type == ACRYPTO_TYPE_AES_128)
+			ivsize = HIFN_AES_IV_LENGTH;
+		else if (type == ACRYPTO_TYPE_DES)
+			ivsize = HIFN_DES_KEY_LENGTH;
+		else if (type == ACRYPTO_TYPE_3DES)
+			ivsize = HIFN_3DES_KEY_LENGTH;
+	}
+
+	if (ctx->keysize != 16 && type == ACRYPTO_TYPE_AES_128) {
+		if (ctx->keysize == 24)
+			type = ACRYPTO_TYPE_AES_192;
+		else if (ctx->keysize == 32)
+			type = ACRYPTO_TYPE_AES_256;
+	}
+
+	ctx->op = op;
+	ctx->mode = mode;
+	ctx->type = type;
+	ctx->iv = req->info;
+	ctx->ivsize = ivsize;
+
+	/*
+	 * HEAVY TODO: needs to kick Herbert XU to write documentation.
+	 * HEAVY TODO: needs to kick Herbert XU to write documentation.
+	 * HEAVY TODO: needs to kick Herbert XU to write documentation.
+	 */
+
+	return hifn_handle_req(req);
+}
+
+static int hifn_process_queue(struct hifn_device *dev)
+{
+	struct crypto_async_request *async_req;
+	struct hifn_context *ctx;
+	struct ablkcipher_request *req;
+	unsigned long flags;
+	int err = 0;
+
+	while (dev->started < HIFN_QUEUE_LENGTH) {
+		spin_lock_irqsave(&dev->lock, flags);
+		async_req = crypto_dequeue_request(&dev->queue);
+		spin_unlock_irqrestore(&dev->lock, flags);
+
+		if (!async_req)
+			break;
+
+		ctx = crypto_tfm_ctx(async_req->tfm);
+		req = container_of(async_req, struct ablkcipher_request, base);
+
+		err = hifn_handle_req(req);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+static int hifn_setup_crypto(struct ablkcipher_request *req, u8 op,
+		u8 type, u8 mode)
+{
+	int err;
+	struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hifn_device *dev = ctx->dev;
+
+	err = hifn_setup_crypto_req(req, op, type, mode);
+	if (err)
+		return err;
+
+	if (dev->started < HIFN_QUEUE_LENGTH &&	dev->queue.qlen)
+		err = hifn_process_queue(dev);
+
+	return err;
+}
+
+/*
+ * AES ecryption functions.
+ */
+static inline int hifn_encrypt_aes_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_encrypt_aes_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_encrypt_aes_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_encrypt_aes_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * AES decryption functions.
+ */
+static inline int hifn_decrypt_aes_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_decrypt_aes_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_decrypt_aes_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_decrypt_aes_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * DES ecryption functions.
+ */
+static inline int hifn_encrypt_des_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_encrypt_des_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_encrypt_des_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_encrypt_des_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * DES decryption functions.
+ */
+static inline int hifn_decrypt_des_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_decrypt_des_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_decrypt_des_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_decrypt_des_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * 3DES ecryption functions.
+ */
+static inline int hifn_encrypt_3des_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_encrypt_3des_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_encrypt_3des_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_encrypt_3des_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB);
+}
+
+/*
+ * 3DES decryption functions.
+ */
+static inline int hifn_decrypt_3des_ecb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB);
+}
+static inline int hifn_decrypt_3des_cbc(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC);
+}
+static inline int hifn_decrypt_3des_cfb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB);
+}
+static inline int hifn_decrypt_3des_ofb(struct ablkcipher_request *req)
+{
+	return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT,
+			ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB);
+}
+
+struct hifn_alg_template
+{
+	char name[CRYPTO_MAX_ALG_NAME];
+	char drv_name[CRYPTO_MAX_ALG_NAME];
+	unsigned int bsize;
+	struct ablkcipher_alg ablkcipher;
+};
+
+static struct hifn_alg_template hifn_alg_templates[] = {
+	/*
+	 * 3DES ECB, CBC, CFB and OFB modes.
+	 */
+	{
+		.name = "cfb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_3des_cfb,
+			.decrypt	=	hifn_decrypt_3des_cfb,
+		},
+	},
+	{
+		.name = "ofb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_3des_ofb,
+			.decrypt	=	hifn_decrypt_3des_ofb,
+		},
+	},
+	{
+		.name = "cbc(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_3des_cbc,
+			.decrypt	=	hifn_decrypt_3des_cbc,
+		},
+	},
+	{
+		.name = "ecb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_3DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_3des_ecb,
+			.decrypt	=	hifn_decrypt_3des_ecb,
+		},
+	},
+
+	/*
+	 * DES ECB, CBC, CFB and OFB modes.
+	 */
+	{
+		.name = "cfb(des)", .drv_name = "hifn-des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_des_cfb,
+			.decrypt	=	hifn_decrypt_des_cfb,
+		},
+	},
+	{
+		.name = "ofb(des)", .drv_name = "hifn-des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_des_ofb,
+			.decrypt	=	hifn_decrypt_des_ofb,
+		},
+	},
+	{
+		.name = "cbc(des)", .drv_name = "hifn-des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_des_cbc,
+			.decrypt	=	hifn_decrypt_des_cbc,
+		},
+	},
+	{
+		.name = "ecb(des)", .drv_name = "hifn-des", .bsize = 8,
+		.ablkcipher = {
+			.min_keysize	=	HIFN_DES_KEY_LENGTH,
+			.max_keysize	=	HIFN_DES_KEY_LENGTH,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_des_ecb,
+			.decrypt	=	hifn_decrypt_des_ecb,
+		},
+	},
+
+	/*
+	 * AES ECB, CBC, CFB and OFB modes.
+	 */
+	{
+		.name = "ecb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+		.ablkcipher = {
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_aes_ecb,
+			.decrypt	=	hifn_decrypt_aes_ecb,
+		},
+	},
+	{
+		.name = "cbc(aes)", .drv_name = "hifn-aes", .bsize = 16,
+		.ablkcipher = {
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_aes_cbc,
+			.decrypt	=	hifn_decrypt_aes_cbc,
+		},
+	},
+	{
+		.name = "cfb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+		.ablkcipher = {
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_aes_cfb,
+			.decrypt	=	hifn_decrypt_aes_cfb,
+		},
+	},
+	{
+		.name = "ofb(aes)", .drv_name = "hifn-aes", .bsize = 16,
+		.ablkcipher = {
+			.min_keysize	=	AES_MIN_KEY_SIZE,
+			.max_keysize	=	AES_MAX_KEY_SIZE,
+			.setkey		=	hifn_setkey,
+			.encrypt	=	hifn_encrypt_aes_ofb,
+			.decrypt	=	hifn_decrypt_aes_ofb,
+		},
+	},
+};
+
+static int hifn_cra_init(struct crypto_tfm *tfm)
+{
+	struct crypto_alg *alg = tfm->__crt_alg;
+	struct hifn_crypto_alg *ha = crypto_alg_to_hifn(alg);
+	struct hifn_context *ctx = crypto_tfm_ctx(tfm);
+
+	ctx->dev = ha->dev;
+
+	return 0;
+}
+
+static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t)
+{
+	struct hifn_crypto_alg *alg;
+	int err;
+
+	alg = kzalloc(sizeof(struct hifn_crypto_alg), GFP_KERNEL);
+	if (!alg)
+		return -ENOMEM;
+
+	snprintf(alg->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s", t->name);
+	snprintf(alg->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", t->drv_name);
+
+	alg->alg.cra_priority = 300;
+	alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
+	alg->alg.cra_blocksize = t->bsize;
+	alg->alg.cra_ctxsize = sizeof(struct hifn_context);
+	alg->alg.cra_alignmask = 15;
+	if (t->bsize == 8)
+		alg->alg.cra_alignmask = 3;
+	alg->alg.cra_type = &crypto_ablkcipher_type;
+	alg->alg.cra_module = THIS_MODULE;
+	alg->alg.cra_u.ablkcipher = t->ablkcipher;
+	alg->alg.cra_init = hifn_cra_init;
+
+	alg->dev = dev;
+
+	list_add_tail(&alg->entry, &dev->alg_list);
+
+	err = crypto_register_alg(&alg->alg);
+	if (err) {
+		list_del(&alg->entry);
+		kfree(alg);
+	}
+
+	return err;
+}
+
+static void hifn_unregister_alg(struct hifn_device *dev)
+{
+	struct hifn_crypto_alg *a, *n;
+
+	list_for_each_entry_safe(a, n, &dev->alg_list, entry) {
+		list_del(&a->entry);
+		crypto_unregister_alg(&a->alg);
+		kfree(a);
+	}
+}
+
+static int hifn_register_alg(struct hifn_device *dev)
+{
+	int i, err;
+
+	for (i=0; i<ARRAY_SIZE(hifn_alg_templates); ++i) {
+		err = hifn_alg_alloc(dev, &hifn_alg_templates[i]);
+		if (err)
+			goto err_out_exit;
+	}
+
+	return 0;
+
+err_out_exit:
+	hifn_unregister_alg(dev);
+	return err;
+}
+
+static void hifn_tasklet_callback(unsigned long data)
+{
+	struct hifn_device *dev = (struct hifn_device *)data;
+
+	/*
+	 * This is ok to call this without lock being held,
+	 * althogh it modifies some parameters used in parallel,
+	 * (like dev->success), but they are used in process
+	 * context or update is atomic (like setting dev->sa[i] to NULL).
+	 */
+	hifn_check_for_completion(dev, 0);
+}
+
+static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int err, i;
+	struct hifn_device *dev;
+	char name[8];
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+	pci_set_master(pdev);
+
+	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (err)
+		goto err_out_disable_pci_device;
+
+	snprintf(name, sizeof(name), "hifn%d",
+			atomic_inc_return(&hifn_dev_number)-1);
+
+	err = pci_request_regions(pdev, name);
+	if (err)
+		goto err_out_disable_pci_device;
+
+	if (pci_resource_len(pdev, 0) < HIFN_BAR0_SIZE ||
+	    pci_resource_len(pdev, 1) < HIFN_BAR1_SIZE ||
+	    pci_resource_len(pdev, 2) < HIFN_BAR2_SIZE) {
+		dprintk("%s: Broken hardware - I/O regions are too small.\n",
+				pci_name(pdev));
+		err = -ENODEV;
+		goto err_out_free_regions;
+	}
+
+	dev = kzalloc(sizeof(struct hifn_device) + sizeof(struct crypto_alg),
+			GFP_KERNEL);
+	if (!dev) {
+		err = -ENOMEM;
+		goto err_out_free_regions;
+	}
+
+	INIT_LIST_HEAD(&dev->alg_list);
+
+	snprintf(dev->name, sizeof(dev->name), "%s", name);
+	spin_lock_init(&dev->lock);
+
+	for (i=0; i<3; ++i) {
+		unsigned long addr, size;
+
+		addr = pci_resource_start(pdev, i);
+		size = pci_resource_len(pdev, i);
+
+		dev->bar[i] = ioremap_nocache(addr, size);
+		if (!dev->bar[i])
+			goto err_out_unmap_bars;
+	}
+
+	dev->result_mem = __get_free_pages(GFP_KERNEL, HIFN_MAX_RESULT_ORDER);
+	if (!dev->result_mem) {
+		dprintk("Failed to allocate %d pages for result_mem.\n",
+				HIFN_MAX_RESULT_ORDER);
+		goto err_out_unmap_bars;
+	}
+	memset((void *)dev->result_mem, 0, PAGE_SIZE*(1<<HIFN_MAX_RESULT_ORDER));
+
+	dev->dst = pci_map_single(pdev, (void *)dev->result_mem,
+			PAGE_SIZE << HIFN_MAX_RESULT_ORDER, PCI_DMA_FROMDEVICE);
+
+	dev->desc_virt = pci_alloc_consistent(pdev, sizeof(struct hifn_dma),
+			&dev->desc_dma);
+	if (!dev->desc_virt) {
+		dprintk("Failed to allocate descriptor rings.\n");
+		goto err_out_free_result_pages;
+	}
+	memset(dev->desc_virt, 0, sizeof(struct hifn_dma));
+
+	dev->pdev = pdev;
+	dev->irq = pdev->irq;
+
+	for (i=0; i<HIFN_D_RES_RSIZE; ++i)
+		dev->sa[i] = NULL;
+
+	pci_set_drvdata(pdev, dev);
+
+	tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev);
+
+	crypto_init_queue(&dev->queue, 1);
+
+	err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev);
+	if (err) {
+		dprintk("Failed to request IRQ%d: err: %d.\n", dev->irq, err);
+		dev->irq = 0;
+		goto err_out_free_desc;
+	}
+
+	err = hifn_start_device(dev);
+	if (err)
+		goto err_out_free_irq;
+
+	err = hifn_test(dev, 1, 0);
+	if (err)
+		goto err_out_stop_device;
+
+	err = hifn_register_rng(dev);
+	if (err)
+		goto err_out_stop_device;
+
+	err = hifn_register_alg(dev);
+	if (err)
+		goto err_out_unregister_rng;
+
+	INIT_DELAYED_WORK(&dev->work, hifn_work);
+	schedule_delayed_work(&dev->work, HZ);
+
+	dprintk("HIFN crypto accelerator card at %s has been "
+			"successfully registered as %s.\n",
+			pci_name(pdev), dev->name);
+
+	return 0;
+
+err_out_unregister_rng:
+	hifn_unregister_rng(dev);
+err_out_stop_device:
+	hifn_reset_dma(dev, 1);
+	hifn_stop_device(dev);
+err_out_free_irq:
+	free_irq(dev->irq, dev->name);
+	tasklet_kill(&dev->tasklet);
+err_out_free_desc:
+	pci_free_consistent(pdev, sizeof(struct hifn_dma),
+			dev->desc_virt, dev->desc_dma);
+
+err_out_free_result_pages:
+	pci_unmap_single(pdev, dev->dst, PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
+			PCI_DMA_FROMDEVICE);
+	free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
+
+err_out_unmap_bars:
+	for (i=0; i<3; ++i)
+		if (dev->bar[i])
+			iounmap(dev->bar[i]);
+
+err_out_free_regions:
+	pci_release_regions(pdev);
+
+err_out_disable_pci_device:
+	pci_disable_device(pdev);
+
+	return err;
+}
+
+static void hifn_remove(struct pci_dev *pdev)
+{
+	int i;
+	struct hifn_device *dev;
+
+	dev = pci_get_drvdata(pdev);
+
+	if (dev) {
+		cancel_delayed_work(&dev->work);
+		flush_scheduled_work();
+
+		hifn_unregister_rng(dev);
+		hifn_unregister_alg(dev);
+		hifn_reset_dma(dev, 1);
+		hifn_stop_device(dev);
+
+		free_irq(dev->irq, dev->name);
+		tasklet_kill(&dev->tasklet);
+
+		hifn_flush(dev);
+
+		pci_free_consistent(pdev, sizeof(struct hifn_dma),
+				dev->desc_virt, dev->desc_dma);
+		pci_unmap_single(pdev, dev->dst,
+				PAGE_SIZE << HIFN_MAX_RESULT_ORDER,
+				PCI_DMA_FROMDEVICE);
+		free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER);
+		for (i=0; i<3; ++i)
+			if (dev->bar[i])
+				iounmap(dev->bar[i]);
+
+		kfree(dev);
+	}
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static struct pci_device_id hifn_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7955) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7956) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, hifn_pci_tbl);
+
+static struct pci_driver hifn_pci_driver = {
+	.name     = "hifn795x",
+	.id_table = hifn_pci_tbl,
+	.probe    = hifn_probe,
+	.remove   = __devexit_p(hifn_remove),
+};
+
+static int __devinit hifn_init(void)
+{
+	unsigned int freq;
+	int err;
+
+	if (strncmp(hifn_pll_ref, "ext", 3) &&
+	    strncmp(hifn_pll_ref, "pci", 3)) {
+		printk(KERN_ERR "hifn795x: invalid hifn_pll_ref clock, "
+				"must be pci or ext");
+		return -EINVAL;
+	}
+
+	/*
+	 * For the 7955/7956 the reference clock frequency must be in the
+	 * range of 20MHz-100MHz. For the 7954 the upper bound is 66.67MHz,
+	 * but this chip is currently not supported.
+	 */
+	if (hifn_pll_ref[3] != '\0') {
+		freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10);
+		if (freq < 20 || freq > 100) {
+			printk(KERN_ERR "hifn795x: invalid hifn_pll_ref "
+					"frequency, must be in the range "
+					"of 20-100");
+			return -EINVAL;
+		}
+	}
+
+	err = pci_register_driver(&hifn_pci_driver);
+	if (err < 0) {
+		dprintk("Failed to register PCI driver for %s device.\n",
+				hifn_pci_driver.name);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip "
+			"has been successfully registered.\n");
+
+	return 0;
+}
+
+static void __devexit hifn_fini(void)
+{
+	pci_unregister_driver(&hifn_pci_driver);
+
+	printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip "
+			"has been successfully unregistered.\n");
+}
+
+module_init(hifn_init);
+module_exit(hifn_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Driver for HIFN 795x crypto accelerator chip.");
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index 5f7e71810489..2f3ad3f7dfea 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -44,6 +44,7 @@
  */
 
 #include <crypto/algapi.h>
+#include <crypto/aes.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -53,9 +54,6 @@
 #include <asm/byteorder.h>
 #include "padlock.h"
 
-#define AES_MIN_KEY_SIZE	16	/* in uint8_t units */
-#define AES_MAX_KEY_SIZE	32	/* ditto */
-#define AES_BLOCK_SIZE		16	/* ditto */
 #define AES_EXTENDED_KEY_SIZE	64	/* in uint32_t units */
 #define AES_EXTENDED_KEY_SIZE_B	(AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
 
@@ -419,6 +417,11 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 /* ====== Encryption/decryption routines ====== */
 
 /* These are the real call to PadLock. */
+static inline void padlock_reset_key(void)
+{
+	asm volatile ("pushfl; popfl");
+}
+
 static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key,
 				  void *control_word)
 {
@@ -439,8 +442,6 @@ static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword)
 static inline void aes_crypt(const u8 *in, u8 *out, u32 *key,
 			     struct cword *cword)
 {
-	asm volatile ("pushfl; popfl");
-
 	/* padlock_xcrypt requires at least two blocks of data. */
 	if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) &
 		       (PAGE_SIZE - 1)))) {
@@ -459,7 +460,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
 		return;
 	}
 
-	asm volatile ("pushfl; popfl");		/* enforce key reload. */
 	asm volatile ("test $1, %%cl;"
 		      "je 1f;"
 		      "lea -1(%%ecx), %%eax;"
@@ -476,8 +476,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
 static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
 				     u8 *iv, void *control_word, u32 count)
 {
-	/* Enforce key reload. */
-	asm volatile ("pushfl; popfl");
 	/* rep xcryptcbc */
 	asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"
 		      : "+S" (input), "+D" (output), "+a" (iv)
@@ -488,12 +486,14 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 	struct aes_ctx *ctx = aes_ctx(tfm);
+	padlock_reset_key();
 	aes_crypt(in, out, ctx->E, &ctx->cword.encrypt);
 }
 
 static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 {
 	struct aes_ctx *ctx = aes_ctx(tfm);
+	padlock_reset_key();
 	aes_crypt(in, out, ctx->D, &ctx->cword.decrypt);
 }
 
@@ -526,6 +526,8 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	int err;
 
+	padlock_reset_key();
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 
@@ -548,6 +550,8 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	int err;
 
+	padlock_reset_key();
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 
@@ -592,6 +596,8 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	int err;
 
+	padlock_reset_key();
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 
@@ -616,6 +622,8 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
 	struct blkcipher_walk walk;
 	int err;
 
+	padlock_reset_key();
+
 	blkcipher_walk_init(&walk, dst, src, nbytes);
 	err = blkcipher_walk_virt(desc, &walk);
 
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index d59b2f417306..bcf52df30339 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -41,12 +41,12 @@
  * the definition of dma_event_callback in dmaengine.h.
  *
  * Each device has a kref, which is initialized to 1 when the device is
- * registered. A kref_get is done for each class_device registered.  When the
- * class_device is released, the coresponding kref_put is done in the release
+ * registered. A kref_get is done for each device registered.  When the
+ * device is released, the coresponding kref_put is done in the release
  * method. Every time one of the device's channels is allocated to a client,
  * a kref_get occurs.  When the channel is freed, the coresponding kref_put
  * happens. The device's release function does a completion, so
- * unregister_device does a remove event, class_device_unregister, a kref_put
+ * unregister_device does a remove event, device_unregister, a kref_put
  * for the first reference, then waits on the completion for all other
  * references to finish.
  *
@@ -77,9 +77,9 @@ static LIST_HEAD(dma_client_list);
 
 /* --- sysfs implementation --- */
 
-static ssize_t show_memcpy_count(struct class_device *cd, char *buf)
+static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+	struct dma_chan *chan = to_dma_chan(dev);
 	unsigned long count = 0;
 	int i;
 
@@ -89,9 +89,10 @@ static ssize_t show_memcpy_count(struct class_device *cd, char *buf)
 	return sprintf(buf, "%lu\n", count);
 }
 
-static ssize_t show_bytes_transferred(struct class_device *cd, char *buf)
+static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr,
+				      char *buf)
 {
-	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+	struct dma_chan *chan = to_dma_chan(dev);
 	unsigned long count = 0;
 	int i;
 
@@ -101,9 +102,9 @@ static ssize_t show_bytes_transferred(struct class_device *cd, char *buf)
 	return sprintf(buf, "%lu\n", count);
 }
 
-static ssize_t show_in_use(struct class_device *cd, char *buf)
+static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+	struct dma_chan *chan = to_dma_chan(dev);
 	int in_use = 0;
 
 	if (unlikely(chan->slow_ref) &&
@@ -119,7 +120,7 @@ static ssize_t show_in_use(struct class_device *cd, char *buf)
 	return sprintf(buf, "%d\n", in_use);
 }
 
-static struct class_device_attribute dma_class_attrs[] = {
+static struct device_attribute dma_attrs[] = {
 	__ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL),
 	__ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL),
 	__ATTR(in_use, S_IRUGO, show_in_use, NULL),
@@ -128,16 +129,16 @@ static struct class_device_attribute dma_class_attrs[] = {
 
 static void dma_async_device_cleanup(struct kref *kref);
 
-static void dma_class_dev_release(struct class_device *cd)
+static void dma_dev_release(struct device *dev)
 {
-	struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+	struct dma_chan *chan = to_dma_chan(dev);
 	kref_put(&chan->device->refcount, dma_async_device_cleanup);
 }
 
 static struct class dma_devclass = {
-	.name            = "dma",
-	.class_dev_attrs = dma_class_attrs,
-	.release = dma_class_dev_release,
+	.name		= "dma",
+	.dev_attrs	= dma_attrs,
+	.dev_release	= dma_dev_release,
 };
 
 /* --- client and device registration --- */
@@ -377,12 +378,12 @@ int dma_async_device_register(struct dma_device *device)
 			continue;
 
 		chan->chan_id = chancnt++;
-		chan->class_dev.class = &dma_devclass;
-		chan->class_dev.dev = NULL;
-		snprintf(chan->class_dev.class_id, BUS_ID_SIZE, "dma%dchan%d",
+		chan->dev.class = &dma_devclass;
+		chan->dev.parent = NULL;
+		snprintf(chan->dev.bus_id, BUS_ID_SIZE, "dma%dchan%d",
 		         device->dev_id, chan->chan_id);
 
-		rc = class_device_register(&chan->class_dev);
+		rc = device_register(&chan->dev);
 		if (rc) {
 			chancnt--;
 			free_percpu(chan->local);
@@ -411,7 +412,7 @@ err_out:
 		if (chan->local == NULL)
 			continue;
 		kref_put(&device->refcount, dma_async_device_cleanup);
-		class_device_unregister(&chan->class_dev);
+		device_unregister(&chan->dev);
 		chancnt--;
 		free_percpu(chan->local);
 	}
@@ -445,7 +446,7 @@ void dma_async_device_unregister(struct dma_device *device)
 
 	list_for_each_entry(chan, &device->channels, device_node) {
 		dma_clients_notify_removed(chan);
-		class_device_unregister(&chan->class_dev);
+		device_unregister(&chan->dev);
 		dma_chan_release(chan);
 	}
 
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
index 70b837f23c43..53764577035f 100644
--- a/drivers/edac/edac_device_sysfs.c
+++ b/drivers/edac/edac_device_sysfs.c
@@ -246,16 +246,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 
 	/* Init the devices's kobject */
 	memset(&edac_dev->kobj, 0, sizeof(struct kobject));
-	edac_dev->kobj.ktype = &ktype_device_ctrl;
-
-	/* set this new device under the edac_class kobject */
-	edac_dev->kobj.parent = &edac_class->kset.kobj;
-
-	/* generate sysfs "..../edac/<name>"   */
-	debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name);
-	err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name);
-	if (err)
-		goto err_out;
 
 	/* Record which module 'owns' this control structure
 	 * and bump the ref count of the module
@@ -268,12 +258,15 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 	}
 
 	/* register */
-	err = kobject_register(&edac_dev->kobj);
+	err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl,
+				   &edac_class->kset.kobj,
+				   "%s", edac_dev->name);
 	if (err) {
 		debugf1("%s()Failed to register '.../edac/%s'\n",
 			__func__, edac_dev->name);
 		goto err_kobj_reg;
 	}
+	kobject_uevent(&edac_dev->kobj, KOBJ_ADD);
 
 	/* At this point, to 'free' the control struct,
 	 * edac_device_unregister_sysfs_main_kobj() must be used
@@ -310,7 +303,7 @@ void edac_device_unregister_sysfs_main_kobj(
 	 *   a) module_put() this module
 	 *   b) 'kfree' the memory
 	 */
-	kobject_unregister(&edac_dev->kobj);
+	kobject_put(&edac_dev->kobj);
 }
 
 /* edac_dev -> instance information */
@@ -533,12 +526,6 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
 
 	/* init this block's kobject */
 	memset(&block->kobj, 0, sizeof(struct kobject));
-	block->kobj.parent = &instance->kobj;
-	block->kobj.ktype = &ktype_block_ctrl;
-
-	err = kobject_set_name(&block->kobj, "%s", block->name);
-	if (err)
-		return err;
 
 	/* bump the main kobject's reference count for this controller
 	 * and this instance is dependant on the main
@@ -550,7 +537,9 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
 	}
 
 	/* Add this block's kobject */
-	err = kobject_register(&block->kobj);
+	err = kobject_init_and_add(&block->kobj, &ktype_block_ctrl,
+				   &instance->kobj,
+				   "%s", block->name);
 	if (err) {
 		debugf1("%s() Failed to register instance '%s'\n",
 			__func__, block->name);
@@ -579,12 +568,13 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
 				goto err_on_attrib;
 		}
 	}
+	kobject_uevent(&block->kobj, KOBJ_ADD);
 
 	return 0;
 
 	/* Error unwind stack */
 err_on_attrib:
-	kobject_unregister(&block->kobj);
+	kobject_put(&block->kobj);
 
 err_out:
 	return err;
@@ -615,7 +605,7 @@ static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev,
 	/* unregister this block's kobject, SEE:
 	 *	edac_device_ctrl_block_release() callback operation
 	 */
-	kobject_unregister(&block->kobj);
+	kobject_put(&block->kobj);
 }
 
 /* instance ctor/dtor code */
@@ -637,15 +627,8 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
 	/* Init the instance's kobject */
 	memset(&instance->kobj, 0, sizeof(struct kobject));
 
-	/* set this new device under the edac_device main kobject */
-	instance->kobj.parent = &edac_dev->kobj;
-	instance->kobj.ktype = &ktype_instance_ctrl;
 	instance->ctl = edac_dev;
 
-	err = kobject_set_name(&instance->kobj, "%s", instance->name);
-	if (err)
-		goto err_out;
-
 	/* bump the main kobject's reference count for this controller
 	 * and this instance is dependant on the main
 	 */
@@ -655,8 +638,9 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
 		goto err_out;
 	}
 
-	/* Formally register this instance's kobject */
-	err = kobject_register(&instance->kobj);
+	/* Formally register this instance's kobject under the edac_device */
+	err = kobject_init_and_add(&instance->kobj, &ktype_instance_ctrl,
+				   &edac_dev->kobj, "%s", instance->name);
 	if (err != 0) {
 		debugf2("%s() Failed to register instance '%s'\n",
 			__func__, instance->name);
@@ -679,6 +663,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
 			goto err_release_instance_kobj;
 		}
 	}
+	kobject_uevent(&instance->kobj, KOBJ_ADD);
 
 	debugf4("%s() Registered instance %d '%s' kobject\n",
 		__func__, idx, instance->name);
@@ -687,7 +672,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
 
 	/* error unwind stack */
 err_release_instance_kobj:
-	kobject_unregister(&instance->kobj);
+	kobject_put(&instance->kobj);
 
 err_out:
 	return err;
@@ -712,7 +697,7 @@ static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev,
 	/* unregister this instance's kobject, SEE:
 	 *	edac_device_ctrl_instance_release() for callback operation
 	 */
-	kobject_unregister(&instance->kobj);
+	kobject_put(&instance->kobj);
 }
 
 /*
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 3706b2bc0987..9aac88027fb3 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -380,13 +380,6 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
 	/* generate ..../edac/mc/mc<id>/csrow<index>   */
 	memset(&csrow->kobj, 0, sizeof(csrow->kobj));
 	csrow->mci = mci;	/* include container up link */
-	csrow->kobj.parent = kobj_mci;
-	csrow->kobj.ktype = &ktype_csrow;
-
-	/* name this instance of csrow<id> */
-	err = kobject_set_name(&csrow->kobj, "csrow%d", index);
-	if (err)
-		goto err_out;
 
 	/* bump the mci instance's kobject's ref count */
 	kobj = kobject_get(&mci->edac_mci_kobj);
@@ -396,12 +389,13 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
 	}
 
 	/* Instanstiate the csrow object */
-	err = kobject_register(&csrow->kobj);
+	err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci,
+				   "csrow%d", index);
 	if (err)
 		goto err_release_top_kobj;
 
 	/* At this point, to release a csrow kobj, one must
-	 * call the kobject_unregister and allow that tear down
+	 * call the kobject_put and allow that tear down
 	 * to work the releasing
 	 */
 
@@ -412,11 +406,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
 		err = edac_create_channel_files(&csrow->kobj, chan);
 		if (err) {
 			/* special case the unregister here */
-			kobject_unregister(&csrow->kobj);
+			kobject_put(&csrow->kobj);
 			goto err_out;
 		}
 	}
-
+	kobject_uevent(&csrow->kobj, KOBJ_ADD);
 	return 0;
 
 	/* error unwind stack */
@@ -744,7 +738,6 @@ static struct kobj_type ktype_mc_set_attribs = {
  */
 static struct kset mc_kset = {
 	.kobj = {.ktype = &ktype_mc_set_attribs },
-	.ktype = &ktype_mci,
 };
 
 
@@ -765,14 +758,6 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
 	/* Init the mci's kobject */
 	memset(kobj_mci, 0, sizeof(*kobj_mci));
 
-	/* this instance become part of the mc_kset */
-	kobj_mci->kset = &mc_kset;
-
-	/* set the name of the mc<id> object */
-	err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx);
-	if (err)
-		goto fail_out;
-
 	/* Record which module 'owns' this control structure
 	 * and bump the ref count of the module
 	 */
@@ -784,13 +769,18 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
 		goto fail_out;
 	}
 
+	/* this instance become part of the mc_kset */
+	kobj_mci->kset = &mc_kset;
+
 	/* register the mc<id> kobject to the mc_kset */
-	err = kobject_register(kobj_mci);
+	err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL,
+				   "mc%d", mci->mc_idx);
 	if (err) {
 		debugf1("%s()Failed to register '.../edac/mc%d'\n",
 			__func__, mci->mc_idx);
 		goto kobj_reg_fail;
 	}
+	kobject_uevent(kobj_mci, KOBJ_ADD);
 
 	/* At this point, to 'free' the control struct,
 	 * edac_mc_unregister_sysfs_main_kobj() must be used
@@ -818,7 +808,7 @@ fail_out:
 void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
 {
 	/* delete the kobj from the mc_kset */
-	kobject_unregister(&mci->edac_mci_kobj);
+	kobject_put(&mci->edac_mci_kobj);
 }
 
 #define EDAC_DEVICE_SYMLINK	"device"
@@ -933,7 +923,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 fail1:
 	for (i--; i >= 0; i--) {
 		if (csrow->nr_pages > 0) {
-			kobject_unregister(&mci->csrows[i].kobj);
+			kobject_put(&mci->csrows[i].kobj);
 		}
 	}
 
@@ -960,7 +950,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 	for (i = 0; i < mci->nr_csrows; i++) {
 		if (mci->csrows[i].nr_pages > 0) {
 			debugf0("%s()  unreg csrow-%d\n", __func__, i);
-			kobject_unregister(&mci->csrows[i].kobj);
+			kobject_put(&mci->csrows[i].kobj);
 		}
 	}
 
@@ -977,7 +967,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 	debugf0("%s()  unregister this mci kobj\n", __func__);
 
 	/* unregister this instance's kobject */
-	kobject_unregister(&mci->edac_mci_kobj);
+	kobject_put(&mci->edac_mci_kobj);
 }
 
 
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
index e0c4a4086055..7e1374afd967 100644
--- a/drivers/edac/edac_module.c
+++ b/drivers/edac/edac_module.c
@@ -31,7 +31,7 @@ struct workqueue_struct *edac_workqueue;
  *	need to export to other files in this modules
  */
 static struct sysdev_class edac_class = {
-	set_kset_name("edac"),
+	.name = "edac",
 };
 static int edac_class_valid;
 
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
index 69f5dddabddf..5b075da99145 100644
--- a/drivers/edac/edac_pci_sysfs.c
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -162,14 +162,6 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
 
 	debugf0("%s()\n", __func__);
 
-	/* Set the parent and the instance's ktype */
-	pci->kobj.parent = &edac_pci_top_main_kobj;
-	pci->kobj.ktype = &ktype_pci_instance;
-
-	err = kobject_set_name(&pci->kobj, "pci%d", idx);
-	if (err)
-		return err;
-
 	/* First bump the ref count on the top main kobj, which will
 	 * track the number of PCI instances we have, and thus nest
 	 * properly on keeping the module loaded
@@ -181,7 +173,8 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
 	}
 
 	/* And now register this new kobject under the main kobj */
-	err = kobject_register(&pci->kobj);
+	err = kobject_init_and_add(&pci->kobj, &ktype_pci_instance,
+				   &edac_pci_top_main_kobj, "pci%d", idx);
 	if (err != 0) {
 		debugf2("%s() failed to register instance pci%d\n",
 			__func__, idx);
@@ -189,6 +182,7 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
 		goto error_out;
 	}
 
+	kobject_uevent(&pci->kobj, KOBJ_ADD);
 	debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
 
 	return 0;
@@ -211,7 +205,7 @@ void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci)
 	 * function release the main reference count and then
 	 * kfree the memory
 	 */
-	kobject_unregister(&pci->kobj);
+	kobject_put(&pci->kobj);
 }
 
 /***************************** EDAC PCI sysfs root **********************/
@@ -364,14 +358,6 @@ int edac_pci_main_kobj_setup(void)
 		goto decrement_count_fail;
 	}
 
-	/* Need the kobject hook ups, and name setting */
-	edac_pci_top_main_kobj.ktype = &ktype_edac_pci_main_kobj;
-	edac_pci_top_main_kobj.parent = &edac_class->kset.kobj;
-
-	err = kobject_set_name(&edac_pci_top_main_kobj, "pci");
-	if (err)
-		goto decrement_count_fail;
-
 	/* Bump the reference count on this module to ensure the
 	 * modules isn't unloaded until we deconstruct the top
 	 * level main kobj for EDAC PCI
@@ -383,23 +369,24 @@ int edac_pci_main_kobj_setup(void)
 	}
 
 	/* Instanstiate the pci object */
-	/* FIXME: maybe new sysdev_create_subdir() */
-	err = kobject_register(&edac_pci_top_main_kobj);
+	err = kobject_init_and_add(&edac_pci_top_main_kobj, &ktype_edac_pci_main_kobj,
+				   &edac_class->kset.kobj, "pci");
 	if (err) {
 		debugf1("Failed to register '.../edac/pci'\n");
-		goto kobject_register_fail;
+		goto kobject_init_and_add_fail;
 	}
 
 	/* At this point, to 'release' the top level kobject
 	 * for EDAC PCI, then edac_pci_main_kobj_teardown()
 	 * must be used, for resources to be cleaned up properly
 	 */
+	kobject_uevent(&edac_pci_top_main_kobj, KOBJ_ADD);
 	debugf1("Registered '.../edac/pci' kobject\n");
 
 	return 0;
 
 	/* Error unwind statck */
-kobject_register_fail:
+kobject_init_and_add_fail:
 	module_put(THIS_MODULE);
 
 decrement_count_fail:
@@ -424,9 +411,9 @@ static void edac_pci_main_kobj_teardown(void)
 	 * main kobj
 	 */
 	if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
-		debugf0("%s() called kobject_unregister on main kobj\n",
+		debugf0("%s() called kobject_put on main kobj\n",
 			__func__);
-		kobject_unregister(&edac_pci_top_main_kobj);
+		kobject_put(&edac_pci_top_main_kobj);
 	}
 }
 
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 624ff3e082f6..c2169d215bf7 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -1238,6 +1238,12 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
 
 	sdev->allow_restart = 1;
 
+	/*
+	 * Update the dma alignment (minimum alignment requirements for
+	 * start and end of DMA transfers) to be a sector
+	 */
+	blk_queue_update_dma_alignment(sdev->request_queue, 511);
+
 	if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36)
 		sdev->inquiry_len = 36;
 
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index bc132d8f79cb..313c99cbdc62 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -173,8 +173,6 @@ static struct device *dmi_dev;
 	if (dmi_get_system_info(_field)) \
 		sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
 
-extern int dmi_available;
-
 /* In a separate function to keep gcc 3.2 happy - do NOT merge this in
    dmi_id_init! */
 static void __init dmi_id_init_attr_table(void)
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 0cdadea7a40e..9008ed5ef4ce 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -8,6 +8,8 @@
 #include <linux/slab.h>
 #include <asm/dmi.h>
 
+static char dmi_empty_string[] = "        ";
+
 static char * __init dmi_string(const struct dmi_header *dm, u8 s)
 {
 	const u8 *bp = ((u8 *) dm) + dm->length;
@@ -21,11 +23,16 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
 		}
 
 		if (*bp != 0) {
-			str = dmi_alloc(strlen(bp) + 1);
+			size_t len = strlen(bp)+1;
+			size_t cmp_len = len > 8 ? 8 : len;
+
+			if (!memcmp(bp, dmi_empty_string, cmp_len))
+				return dmi_empty_string;
+			str = dmi_alloc(len);
 			if (str != NULL)
 				strcpy(str, bp);
 			else
-				printk(KERN_ERR "dmi_string: out of memory.\n");
+				printk(KERN_ERR "dmi_string: cannot allocate %Zu bytes.\n", len);
 		}
 	}
 
@@ -175,12 +182,23 @@ static void __init dmi_save_devices(const struct dmi_header *dm)
 	}
 }
 
+static struct dmi_device empty_oem_string_dev = {
+	.name = dmi_empty_string,
+};
+
 static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
 {
 	int i, count = *(u8 *)(dm + 1);
 	struct dmi_device *dev;
 
 	for (i = 1; i <= count; i++) {
+		char *devname = dmi_string(dm, i);
+
+		if (!strcmp(devname, dmi_empty_string)) {
+			list_add(&empty_oem_string_dev.list, &dmi_devices);
+			continue;
+		}
+
 		dev = dmi_alloc(sizeof(*dev));
 		if (!dev) {
 			printk(KERN_ERR
@@ -189,7 +207,7 @@ static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
 		}
 
 		dev->type = DMI_DEV_TYPE_OEM_STRING;
-		dev->name = dmi_string(dm, i);
+		dev->name = devname;
 		dev->device_data = NULL;
 
 		list_add(&dev->list, &dmi_devices);
@@ -331,9 +349,11 @@ void __init dmi_scan_machine(void)
 			rc = dmi_present(q);
 			if (!rc) {
 				dmi_available = 1;
+				dmi_iounmap(p, 0x10000);
 				return;
 			}
 		}
+		dmi_iounmap(p, 0x10000);
 	}
  out:	printk(KERN_INFO "DMI not present or invalid.\n");
 }
@@ -470,3 +490,11 @@ int dmi_get_year(int field)
 	return year;
 }
 
+/**
+ *	dmi_get_slot - return dmi_ident[slot]
+ *	@slot:	index into dmi_ident[]
+ */
+char *dmi_get_slot(int slot)
+{
+	return(dmi_ident[slot]);
+}
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index 6942e065e609..d168223db159 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -631,7 +631,7 @@ static struct kobj_type edd_ktype = {
 	.default_attrs	= def_attrs,
 };
 
-static decl_subsys(edd, &edd_ktype, NULL);
+static struct kset *edd_kset;
 
 
 /**
@@ -693,7 +693,7 @@ edd_create_symlink_to_pcidev(struct edd_device *edev)
 static inline void
 edd_device_unregister(struct edd_device *edev)
 {
-	kobject_unregister(&edev->kobj);
+	kobject_put(&edev->kobj);
 }
 
 static void edd_populate_dir(struct edd_device * edev)
@@ -721,12 +721,13 @@ edd_device_register(struct edd_device *edev, int i)
 	if (!edev)
 		return 1;
 	edd_dev_set_info(edev, i);
-	kobject_set_name(&edev->kobj, "int13_dev%02x",
-			 0x80 + i);
-	kobj_set_kset_s(edev,edd_subsys);
-	error = kobject_register(&edev->kobj);
-	if (!error)
+	edev->kobj.kset = edd_kset;
+	error = kobject_init_and_add(&edev->kobj, &edd_ktype, NULL,
+				     "int13_dev%02x", 0x80 + i);
+	if (!error) {
 		edd_populate_dir(edev);
+		kobject_uevent(&edev->kobj, KOBJ_ADD);
+	}
 	return error;
 }
 
@@ -755,9 +756,9 @@ edd_init(void)
 		return 1;
 	}
 
-	rc = firmware_register(&edd_subsys);
-	if (rc)
-		return rc;
+	edd_kset = kset_create_and_add("edd", NULL, firmware_kobj);
+	if (!edd_kset)
+		return -ENOMEM;
 
 	for (i = 0; i < edd_num_devices() && !rc; i++) {
 		edev = kzalloc(sizeof (*edev), GFP_KERNEL);
@@ -773,7 +774,7 @@ edd_init(void)
 	}
 
 	if (rc)
-		firmware_unregister(&edd_subsys);
+		kset_unregister(edd_kset);
 	return rc;
 }
 
@@ -787,7 +788,7 @@ edd_exit(void)
 		if ((edev = edd_devices[i]))
 			edd_device_unregister(edev);
 	}
-	firmware_unregister(&edd_subsys);
+	kset_unregister(edd_kset);
 }
 
 late_initcall(edd_init);
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 858a7b95933b..f4f709d1370b 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -129,13 +129,6 @@ struct efivar_attribute {
 };
 
 
-#define EFI_ATTR(_name, _mode, _show, _store) \
-struct subsys_attribute efi_attr_##_name = { \
-	.attr = {.name = __stringify(_name), .mode = _mode}, \
-	.show = _show, \
-	.store = _store, \
-};
-
 #define EFIVAR_ATTR(_name, _mode, _show, _store) \
 struct efivar_attribute efivar_attr_##_name = { \
 	.attr = {.name = __stringify(_name), .mode = _mode}, \
@@ -143,13 +136,6 @@ struct efivar_attribute efivar_attr_##_name = { \
 	.store = _store, \
 };
 
-#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \
-struct subsys_attribute var_subsys_attr_##_name = { \
-	.attr = {.name = __stringify(_name), .mode = _mode}, \
-	.show = _show, \
-	.store = _store, \
-};
-
 #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
 #define to_efivar_entry(obj)  container_of(obj, struct efivar_entry, kobj)
 
@@ -408,21 +394,16 @@ static struct kobj_type efivar_ktype = {
 	.default_attrs = def_attrs,
 };
 
-static ssize_t
-dummy(struct kset *kset, char *buf)
-{
-	return -ENODEV;
-}
-
 static inline void
 efivar_unregister(struct efivar_entry *var)
 {
-	kobject_unregister(&var->kobj);
+	kobject_put(&var->kobj);
 }
 
 
-static ssize_t
-efivar_create(struct kset *kset, const char *buf, size_t count)
+static ssize_t efivar_create(struct kobject *kobj,
+			     struct bin_attribute *bin_attr,
+			     char *buf, loff_t pos, size_t count)
 {
 	struct efi_variable *new_var = (struct efi_variable *)buf;
 	struct efivar_entry *search_efivar, *n;
@@ -479,8 +460,9 @@ efivar_create(struct kset *kset, const char *buf, size_t count)
 	return count;
 }
 
-static ssize_t
-efivar_delete(struct kset *kset, const char *buf, size_t count)
+static ssize_t efivar_delete(struct kobject *kobj,
+			     struct bin_attribute *bin_attr,
+			     char *buf, loff_t pos, size_t count)
 {
 	struct efi_variable *del_var = (struct efi_variable *)buf;
 	struct efivar_entry *search_efivar, *n;
@@ -537,25 +519,26 @@ efivar_delete(struct kset *kset, const char *buf, size_t count)
 	return count;
 }
 
-static VAR_SUBSYS_ATTR(new_var, 0200, dummy, efivar_create);
-static VAR_SUBSYS_ATTR(del_var, 0200, dummy, efivar_delete);
+static struct bin_attribute var_subsys_attr_new_var = {
+	.attr = {.name = "new_var", .mode = 0200},
+	.write = efivar_create,
+};
 
-static struct subsys_attribute *var_subsys_attrs[] = {
-	&var_subsys_attr_new_var,
-	&var_subsys_attr_del_var,
-	NULL,
+static struct bin_attribute var_subsys_attr_del_var = {
+	.attr = {.name = "del_var", .mode = 0200},
+	.write = efivar_delete,
 };
 
 /*
  * Let's not leave out systab information that snuck into
  * the efivars driver
  */
-static ssize_t
-systab_read(struct kset *kset, char *buf)
+static ssize_t systab_show(struct kobject *kobj,
+			   struct kobj_attribute *attr, char *buf)
 {
 	char *str = buf;
 
-	if (!kset || !buf)
+	if (!kobj || !buf)
 		return -EINVAL;
 
 	if (efi.mps != EFI_INVALID_TABLE_ADDR)
@@ -576,15 +559,21 @@ systab_read(struct kset *kset, char *buf)
 	return str - buf;
 }
 
-static EFI_ATTR(systab, 0400, systab_read, NULL);
+static struct kobj_attribute efi_attr_systab =
+			__ATTR(systab, 0400, systab_show, NULL);
 
-static struct subsys_attribute *efi_subsys_attrs[] = {
-	&efi_attr_systab,
+static struct attribute *efi_subsys_attrs[] = {
+	&efi_attr_systab.attr,
 	NULL,	/* maybe more in the future? */
 };
 
-static decl_subsys(vars, &efivar_ktype, NULL);
-static decl_subsys(efi, NULL, NULL);
+static struct attribute_group efi_subsys_attr_group = {
+	.attrs = efi_subsys_attrs,
+};
+
+
+static struct kset *vars_kset;
+static struct kobject *efi_kobj;
 
 /*
  * efivar_create_sysfs_entry()
@@ -628,15 +617,16 @@ efivar_create_sysfs_entry(unsigned long variable_name_size,
 	*(short_name + strlen(short_name)) = '-';
 	efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
 
-	kobject_set_name(&new_efivar->kobj, "%s", short_name);
-	kobj_set_kset_s(new_efivar, vars_subsys);
-	i = kobject_register(&new_efivar->kobj);
+	new_efivar->kobj.kset = vars_kset;
+	i = kobject_init_and_add(&new_efivar->kobj, &efivar_ktype, NULL,
+				 "%s", short_name);
 	if (i) {
 		kfree(short_name);
 		kfree(new_efivar);
 		return 1;
 	}
 
+	kobject_uevent(&new_efivar->kobj, KOBJ_ADD);
 	kfree(short_name);
 	short_name = NULL;
 
@@ -660,9 +650,8 @@ efivars_init(void)
 	efi_status_t status = EFI_NOT_FOUND;
 	efi_guid_t vendor_guid;
 	efi_char16_t *variable_name;
-	struct subsys_attribute *attr;
 	unsigned long variable_name_size = 1024;
-	int i, error = 0;
+	int error = 0;
 
 	if (!efi_enabled)
 		return -ENODEV;
@@ -676,23 +665,18 @@ efivars_init(void)
 	printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
 	       EFIVARS_DATE);
 
-	/*
-	 * For now we'll register the efi subsys within this driver
-	 */
-
-	error = firmware_register(&efi_subsys);
-
-	if (error) {
-		printk(KERN_ERR "efivars: Firmware registration failed with error %d.\n", error);
+	/* For now we'll register the efi directory at /sys/firmware/efi */
+	efi_kobj = kobject_create_and_add("efi", firmware_kobj);
+	if (!efi_kobj) {
+		printk(KERN_ERR "efivars: Firmware registration failed.\n");
+		error = -ENOMEM;
 		goto out_free;
 	}
 
-	kobj_set_kset_s(&vars_subsys, efi_subsys);
-
-	error = subsystem_register(&vars_subsys);
-
-	if (error) {
-		printk(KERN_ERR "efivars: Subsystem registration failed with error %d.\n", error);
+	vars_kset = kset_create_and_add("vars", NULL, efi_kobj);
+	if (!vars_kset) {
+		printk(KERN_ERR "efivars: Subsystem registration failed.\n");
+		error = -ENOMEM;
 		goto out_firmware_unregister;
 	}
 
@@ -727,28 +711,28 @@ efivars_init(void)
 	 * Now add attributes to allow creation of new vars
 	 * and deletion of existing ones...
 	 */
-
-	for (i = 0; (attr = var_subsys_attrs[i]) && !error; i++) {
-		if (attr->show && attr->store)
-			error = subsys_create_file(&vars_subsys, attr);
-	}
+	error = sysfs_create_bin_file(&vars_kset->kobj,
+				      &var_subsys_attr_new_var);
+	if (error)
+		printk(KERN_ERR "efivars: unable to create new_var sysfs file"
+			" due to error %d\n", error);
+	error = sysfs_create_bin_file(&vars_kset->kobj,
+				      &var_subsys_attr_del_var);
+	if (error)
+		printk(KERN_ERR "efivars: unable to create del_var sysfs file"
+			" due to error %d\n", error);
 
 	/* Don't forget the systab entry */
-
-	for (i = 0; (attr = efi_subsys_attrs[i]) && !error; i++) {
-		if (attr->show)
-			error = subsys_create_file(&efi_subsys, attr);
-	}
-
+	error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
 	if (error)
 		printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d.\n", error);
 	else
 		goto out_free;
 
-	subsystem_unregister(&vars_subsys);
+	kset_unregister(vars_kset);
 
 out_firmware_unregister:
-	firmware_unregister(&efi_subsys);
+	kobject_put(efi_kobj);
 
 out_free:
 	kfree(variable_name);
@@ -768,8 +752,8 @@ efivars_exit(void)
 		efivar_unregister(entry);
 	}
 
-	subsystem_unregister(&vars_subsys);
-	firmware_unregister(&efi_subsys);
+	kset_unregister(vars_kset);
+	kobject_put(efi_kobj);
 }
 
 module_init(efivars_init);
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 1ac5103f7c93..275dc522c738 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -1,7 +1,7 @@
 #
 # Makefile for the HID driver
 #
-hid-objs			:= hid-core.o hid-input.o
+hid-objs			:= hid-core.o hid-input.o hid-input-quirks.o
 
 obj-$(CONFIG_HID)		+= hid.o
 
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 2884b036495a..d73a768e176e 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -26,6 +26,7 @@
 #include <linux/input.h>
 #include <linux/wait.h>
 #include <linux/vmalloc.h>
+#include <linux/sched.h>
 
 #include <linux/hid.h>
 #include <linux/hiddev.h>
@@ -758,7 +759,9 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
 {
 	u64 x;
 
-	WARN_ON(n > 32);
+	if (n > 32)
+		printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n",
+				n, current->comm);
 
 	report += offset >> 3;  /* adjust byte index */
 	offset &= 7;            /* now only need bit offset into one byte */
@@ -780,8 +783,13 @@ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u3
 	__le64 x;
 	u64 m = (1ULL << n) - 1;
 
-	WARN_ON(n > 32);
+	if (n > 32)
+		printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n",
+				n, current->comm);
 
+	if (value > m)
+		printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n",
+				value, current->comm);
 	WARN_ON(value > m);
 	value &= m;
 
diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c
new file mode 100644
index 000000000000..a870ba58faa3
--- /dev/null
+++ b/drivers/hid/hid-input-quirks.c
@@ -0,0 +1,423 @@
+/*
+ *  HID-input usage mapping quirks
+ *
+ *  This is used to handle HID-input mappings for devices violating
+ *  HUT 1.12 specification.
+ *
+ * Copyright (c) 2007-2008 Jiri Kosina
+ */
+
+/*
+ * 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
+ */
+
+#include <linux/input.h>
+#include <linux/hid.h>
+
+#define map_abs(c)      do { usage->code = c; usage->type = EV_ABS; *bit = input->absbit; *max = ABS_MAX; } while (0)
+#define map_rel(c)      do { usage->code = c; usage->type = EV_REL; *bit = input->relbit; *max = REL_MAX; } while (0)
+#define map_key(c)      do { usage->code = c; usage->type = EV_KEY; *bit = input->keybit; *max = KEY_MAX; } while (0)
+#define map_led(c)      do { usage->code = c; usage->type = EV_LED; *bit = input->ledbit; *max = LED_MAX; } while (0)
+
+#define map_abs_clear(c)        do { map_abs(c); clear_bit(c, *bit); } while (0)
+#define map_key_clear(c)        do { map_key(c); clear_bit(c, *bit); } while (0)
+
+static int quirk_belkin_wkbd(struct hid_usage *usage, struct input_dev *input,
+			      unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+		case 0x03a: map_key_clear(KEY_SOUND);		break;
+		case 0x03b: map_key_clear(KEY_CAMERA);		break;
+		case 0x03c: map_key_clear(KEY_DOCUMENTS);	break;
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+static int quirk_cherry_cymotion(struct hid_usage *usage, struct input_dev *input,
+			      unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+		case 0x301: map_key_clear(KEY_PROG1);		break;
+		case 0x302: map_key_clear(KEY_PROG2);		break;
+		case 0x303: map_key_clear(KEY_PROG3);		break;
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+static int quirk_logitech_ultrax_remote(struct hid_usage *usage, struct input_dev *input,
+			      unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
+		return 0;
+
+	set_bit(EV_REP, input->evbit);
+	switch(usage->hid & HID_USAGE) {
+		/* Reported on Logitech Ultra X Media Remote */
+		case 0x004: map_key_clear(KEY_AGAIN);		break;
+		case 0x00d: map_key_clear(KEY_HOME);		break;
+		case 0x024: map_key_clear(KEY_SHUFFLE);		break;
+		case 0x025: map_key_clear(KEY_TV);		break;
+		case 0x026: map_key_clear(KEY_MENU);		break;
+		case 0x031: map_key_clear(KEY_AUDIO);		break;
+		case 0x032: map_key_clear(KEY_TEXT);		break;
+		case 0x033: map_key_clear(KEY_LAST);		break;
+		case 0x047: map_key_clear(KEY_MP3);		break;
+		case 0x048: map_key_clear(KEY_DVD);		break;
+		case 0x049: map_key_clear(KEY_MEDIA);		break;
+		case 0x04a: map_key_clear(KEY_VIDEO);		break;
+		case 0x04b: map_key_clear(KEY_ANGLE);		break;
+		case 0x04c: map_key_clear(KEY_LANGUAGE);	break;
+		case 0x04d: map_key_clear(KEY_SUBTITLE);	break;
+		case 0x051: map_key_clear(KEY_RED);		break;
+		case 0x052: map_key_clear(KEY_CLOSE);		break;
+
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+static int quirk_chicony_tactical_pad(struct hid_usage *usage, struct input_dev *input,
+			      unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+		return 0;
+
+	set_bit(EV_REP, input->evbit);
+	switch (usage->hid & HID_USAGE) {
+		case 0xff01: map_key_clear(BTN_1);		break;
+		case 0xff02: map_key_clear(BTN_2);		break;
+		case 0xff03: map_key_clear(BTN_3);		break;
+		case 0xff04: map_key_clear(BTN_4);		break;
+		case 0xff05: map_key_clear(BTN_5);		break;
+		case 0xff06: map_key_clear(BTN_6);		break;
+		case 0xff07: map_key_clear(BTN_7);		break;
+		case 0xff08: map_key_clear(BTN_8);		break;
+		case 0xff09: map_key_clear(BTN_9);		break;
+		case 0xff0a: map_key_clear(BTN_A);		break;
+		case 0xff0b: map_key_clear(BTN_B);		break;
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+static int quirk_microsoft_ergonomy_kb(struct hid_usage *usage, struct input_dev *input,
+			      unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+		return 0;
+
+	switch(usage->hid & HID_USAGE) {
+		case 0xfd06: map_key_clear(KEY_CHAT);		break;
+		case 0xfd07: map_key_clear(KEY_PHONE);		break;
+		case 0xff05:
+			set_bit(EV_REP, input->evbit);
+			map_key_clear(KEY_F13);
+			set_bit(KEY_F14, input->keybit);
+			set_bit(KEY_F15, input->keybit);
+			set_bit(KEY_F16, input->keybit);
+			set_bit(KEY_F17, input->keybit);
+			set_bit(KEY_F18, input->keybit);
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+static int quirk_microsoft_presenter_8k(struct hid_usage *usage, struct input_dev *input,
+			      unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+		return 0;
+
+	set_bit(EV_REP, input->evbit);
+	switch(usage->hid & HID_USAGE) {
+		case 0xfd08: map_key_clear(KEY_FORWARD);	break;
+		case 0xfd09: map_key_clear(KEY_BACK);		break;
+		case 0xfd0b: map_key_clear(KEY_PLAYPAUSE);	break;
+		case 0xfd0e: map_key_clear(KEY_CLOSE);		break;
+		case 0xfd0f: map_key_clear(KEY_PLAY);		break;
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+static int quirk_petalynx_remote(struct hid_usage *usage, struct input_dev *input,
+			      unsigned long **bit, int *max)
+{
+	if (((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) &&
+			((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER))
+		return 0;
+
+	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR)
+		switch(usage->hid & HID_USAGE) {
+			case 0x05a: map_key_clear(KEY_TEXT);		break;
+			case 0x05b: map_key_clear(KEY_RED);		break;
+			case 0x05c: map_key_clear(KEY_GREEN);		break;
+			case 0x05d: map_key_clear(KEY_YELLOW);		break;
+			case 0x05e: map_key_clear(KEY_BLUE);		break;
+			default:
+				return 0;
+		}
+
+	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER)
+		switch(usage->hid & HID_USAGE) {
+			case 0x0f6: map_key_clear(KEY_NEXT);            break;
+			case 0x0fa: map_key_clear(KEY_BACK);            break;
+			default:
+				return 0;
+		}
+	return 1;
+}
+
+static int quirk_logitech_wireless(struct hid_usage *usage, struct input_dev *input,
+			      unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+		case 0x1001: map_key_clear(KEY_MESSENGER);	break;
+		case 0x1003: map_key_clear(KEY_SOUND);		break;
+		case 0x1004: map_key_clear(KEY_VIDEO);		break;
+		case 0x1005: map_key_clear(KEY_AUDIO);		break;
+		case 0x100a: map_key_clear(KEY_DOCUMENTS);	break;
+		case 0x1011: map_key_clear(KEY_PREVIOUSSONG);	break;
+		case 0x1012: map_key_clear(KEY_NEXTSONG);	break;
+		case 0x1013: map_key_clear(KEY_CAMERA);		break;
+		case 0x1014: map_key_clear(KEY_MESSENGER);	break;
+		case 0x1015: map_key_clear(KEY_RECORD);		break;
+		case 0x1016: map_key_clear(KEY_PLAYER);		break;
+		case 0x1017: map_key_clear(KEY_EJECTCD);	break;
+		case 0x1018: map_key_clear(KEY_MEDIA);		break;
+		case 0x1019: map_key_clear(KEY_PROG1);		break;
+		case 0x101a: map_key_clear(KEY_PROG2);		break;
+		case 0x101b: map_key_clear(KEY_PROG3);		break;
+		case 0x101f: map_key_clear(KEY_ZOOMIN);		break;
+		case 0x1020: map_key_clear(KEY_ZOOMOUT);	break;
+		case 0x1021: map_key_clear(KEY_ZOOMRESET);	break;
+		case 0x1023: map_key_clear(KEY_CLOSE);		break;
+		case 0x1027: map_key_clear(KEY_MENU);		break;
+		/* this one is marked as 'Rotate' */
+		case 0x1028: map_key_clear(KEY_ANGLE);		break;
+		case 0x1029: map_key_clear(KEY_SHUFFLE);	break;
+		case 0x102a: map_key_clear(KEY_BACK);		break;
+		case 0x102b: map_key_clear(KEY_CYCLEWINDOWS);	break;
+		case 0x1041: map_key_clear(KEY_BATTERY);	break;
+		case 0x1042: map_key_clear(KEY_WORDPROCESSOR);	break;
+		case 0x1043: map_key_clear(KEY_SPREADSHEET);	break;
+		case 0x1044: map_key_clear(KEY_PRESENTATION);	break;
+		case 0x1045: map_key_clear(KEY_UNDO);		break;
+		case 0x1046: map_key_clear(KEY_REDO);		break;
+		case 0x1047: map_key_clear(KEY_PRINT);		break;
+		case 0x1048: map_key_clear(KEY_SAVE);		break;
+		case 0x1049: map_key_clear(KEY_PROG1);		break;
+		case 0x104a: map_key_clear(KEY_PROG2);		break;
+		case 0x104b: map_key_clear(KEY_PROG3);		break;
+		case 0x104c: map_key_clear(KEY_PROG4);		break;
+
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+static int quirk_cherry_genius_29e(struct hid_usage *usage, struct input_dev *input,
+			      unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+		case 0x156: map_key_clear(KEY_WORDPROCESSOR);	break;
+		case 0x157: map_key_clear(KEY_SPREADSHEET);	break;
+		case 0x158: map_key_clear(KEY_PRESENTATION);	break;
+		case 0x15c: map_key_clear(KEY_STOP);		break;
+
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
+			      unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+		return 0;
+
+	switch (usage->hid & HID_USAGE) {
+		case 0x230: map_key(BTN_MOUSE);			break;
+		case 0x231: map_rel(REL_WHEEL);			break;
+		/* 
+		 * this keyboard has a scrollwheel implemented in
+		 * totally broken way. We map this usage temporarily
+		 * to HWHEEL and handle it in the event quirk handler
+		 */
+		case 0x232: map_rel(REL_HWHEEL);		break;
+
+		default:
+			return 0;
+	}
+	return 1;
+}
+
+#define VENDOR_ID_BELKIN			0x1020
+#define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD	0x0006
+
+#define VENDOR_ID_CHERRY			0x046a
+#define DEVICE_ID_CHERRY_CYMOTION		0x0023
+
+#define VENDOR_ID_CHICONY			0x04f2
+#define DEVICE_ID_CHICONY_TACTICAL_PAD		0x0418
+
+#define VENDOR_ID_EZKEY				0x0518
+#define DEVICE_ID_BTC_8193			0x0002
+
+#define VENDOR_ID_LOGITECH			0x046d
+#define DEVICE_ID_LOGITECH_RECEIVER		0xc101
+#define DEVICE_ID_S510_RECEIVER			0xc50c
+#define DEVICE_ID_S510_RECEIVER_2		0xc517
+#define DEVICE_ID_MX3000_RECEIVER		0xc513
+
+#define VENDOR_ID_MICROSOFT			0x045e
+#define DEVICE_ID_MS4K				0x00db
+#define DEVICE_ID_MS6K				0x00f9
+#define DEVICE_IS_MS_PRESENTER_8K_BT		0x0701
+#define DEVICE_ID_MS_PRESENTER_8K_USB		0x0713
+
+#define VENDOR_ID_MONTEREY			0x0566
+#define DEVICE_ID_GENIUS_KB29E			0x3004
+
+#define VENDOR_ID_PETALYNX			0x18b1
+#define DEVICE_ID_PETALYNX_MAXTER_REMOTE	0x0037
+
+static const struct hid_input_blacklist {
+	__u16 idVendor;
+	__u16 idProduct;
+	int (*quirk)(struct hid_usage *, struct input_dev *, unsigned long **, int *);
+} hid_input_blacklist[] = {
+	{ VENDOR_ID_BELKIN, DEVICE_ID_BELKIN_WIRELESS_KEYBOARD, quirk_belkin_wkbd },
+
+	{ VENDOR_ID_CHERRY, DEVICE_ID_CHERRY_CYMOTION, quirk_cherry_cymotion },
+
+	{ VENDOR_ID_CHICONY, DEVICE_ID_CHICONY_TACTICAL_PAD, quirk_chicony_tactical_pad },
+
+	{ VENDOR_ID_EZKEY, DEVICE_ID_BTC_8193, quirk_btc_8193 },
+
+	{ VENDOR_ID_LOGITECH, DEVICE_ID_LOGITECH_RECEIVER, quirk_logitech_ultrax_remote },
+	{ VENDOR_ID_LOGITECH, DEVICE_ID_S510_RECEIVER, quirk_logitech_wireless },
+	{ VENDOR_ID_LOGITECH, DEVICE_ID_S510_RECEIVER_2, quirk_logitech_wireless },
+	{ VENDOR_ID_LOGITECH, DEVICE_ID_MX3000_RECEIVER, quirk_logitech_wireless },
+
+	{ VENDOR_ID_MICROSOFT, DEVICE_ID_MS4K, quirk_microsoft_ergonomy_kb },
+	{ VENDOR_ID_MICROSOFT, DEVICE_ID_MS6K, quirk_microsoft_ergonomy_kb },
+	{ VENDOR_ID_MICROSOFT, DEVICE_IS_MS_PRESENTER_8K_BT, quirk_microsoft_presenter_8k },
+	{ VENDOR_ID_MICROSOFT, DEVICE_ID_MS_PRESENTER_8K_USB, quirk_microsoft_presenter_8k },
+
+	{ VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e },
+
+	{ VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote },
+	
+	{ 0, 0, 0 }
+};
+
+int hidinput_mapping_quirks(struct hid_usage *usage, 
+				   struct input_dev *input, 
+				   unsigned long **bit, int *max)
+{
+	struct hid_device *device = input_get_drvdata(input);
+	int i = 0;
+	
+	while (hid_input_blacklist[i].quirk) {
+		if (hid_input_blacklist[i].idVendor == device->vendor &&
+				hid_input_blacklist[i].idProduct == device->product)
+			return hid_input_blacklist[i].quirk(usage, input, bit, max);
+		i++;
+	}
+	return 0;
+}
+
+void hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
+{
+	struct input_dev *input;
+
+	input = field->hidinput->input;
+
+	if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
+		|| ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
+		if (value) hid->quirks |=  HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
+		else       hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
+		return;
+	}
+
+	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) &&
+			(usage->type == EV_REL) &&
+			(usage->code == REL_WHEEL)) {
+		hid->delayed_value = value;
+		return;
+	}
+
+	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) &&
+			(usage->hid == 0x000100b8)) {
+		input_event(input, EV_REL, value ? REL_HWHEEL : REL_WHEEL, hid->delayed_value);
+		return;
+	}
+
+	if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
+		input_event(input, usage->type, usage->code, -value);
+		return;
+	}
+
+	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
+		input_event(input, usage->type, REL_HWHEEL, value);
+		return;
+	}
+
+	if ((hid->quirks & HID_QUIRK_APPLE_HAS_FN) && hidinput_apple_event(hid, input, usage, value))
+		return;
+
+	/* Handling MS keyboards special buttons */
+	if (hid->quirks & HID_QUIRK_MICROSOFT_KEYS && 
+			usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
+		int key = 0;
+		static int last_key = 0;
+		switch (value) {
+			case 0x01: key = KEY_F14; break;
+			case 0x02: key = KEY_F15; break;
+			case 0x04: key = KEY_F16; break;
+			case 0x08: key = KEY_F17; break;
+			case 0x10: key = KEY_F18; break;
+			default: break;
+		}
+		if (key) {
+			input_event(input, usage->type, key, 1);
+			last_key = key;
+		} else {
+			input_event(input, usage->type, last_key, 0);
+		}
+	}
+
+	/* handle the temporary quirky mapping to HWHEEL */
+	if (hid->quirks & HID_QUIRK_HWHEEL_WHEEL_INVERT &&
+			usage->type == EV_REL && usage->code == REL_HWHEEL) {
+		input_event(input, usage->type, REL_WHEEL, -value);
+		return;
+	}
+}
+
+
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 0b27da7d7497..5325d98b4328 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -34,10 +34,10 @@
 #include <linux/hid.h>
 #include <linux/hid-debug.h>
 
-static int hid_pb_fnmode = 1;
-module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644);
+static int hid_apple_fnmode = 1;
+module_param_named(pb_fnmode, hid_apple_fnmode, int, 0644);
 MODULE_PARM_DESC(pb_fnmode,
-		"Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
+		"Mode of fn key on Apple keyboards (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
 
 #define unk	KEY_UNKNOWN
 
@@ -86,10 +86,6 @@ static const struct {
 #define map_abs_clear(c)	do { map_abs(c); clear_bit(c, bit); } while (0)
 #define map_key_clear(c)	do { map_key(c); clear_bit(c, bit); } while (0)
 
-/* hardware needing special handling due to colliding MSVENDOR page usages */
-#define IS_CHICONY_TACTICAL_PAD(x) (x->vendor == 0x04f2 && device->product == 0x0418)
-#define IS_MS_KB(x) (x->vendor == 0x045e && (x->product == 0x00db || x->product == 0x00f9))
-
 #ifdef CONFIG_USB_HIDINPUT_POWERBOOK
 
 struct hidinput_key_translation {
@@ -98,20 +94,36 @@ struct hidinput_key_translation {
 	u8 flags;
 };
 
-#define POWERBOOK_FLAG_FKEY 0x01
+#define APPLE_FLAG_FKEY 0x01
+
+static struct hidinput_key_translation apple_fn_keys[] = {
+	{ KEY_F1,       KEY_BRIGHTNESSDOWN,     APPLE_FLAG_FKEY },
+	{ KEY_F2,       KEY_BRIGHTNESSUP,       APPLE_FLAG_FKEY },
+	{ KEY_F3,       KEY_CYCLEWINDOWS,       APPLE_FLAG_FKEY }, /* Exposé */
+	{ KEY_F4,       KEY_FN_F4,              APPLE_FLAG_FKEY }, /* Dashboard */
+	{ KEY_F5,       KEY_FN_F5 },
+	{ KEY_F6,       KEY_FN_F6 },
+	{ KEY_F7,       KEY_BACK,               APPLE_FLAG_FKEY },
+	{ KEY_F8,       KEY_PLAYPAUSE,          APPLE_FLAG_FKEY },
+	{ KEY_F9,       KEY_FORWARD,            APPLE_FLAG_FKEY },
+	{ KEY_F10,      KEY_MUTE,               APPLE_FLAG_FKEY },
+	{ KEY_F11,      KEY_VOLUMEDOWN,         APPLE_FLAG_FKEY },
+	{ KEY_F12,      KEY_VOLUMEUP,           APPLE_FLAG_FKEY },
+	{ }
+};
 
 static struct hidinput_key_translation powerbook_fn_keys[] = {
 	{ KEY_BACKSPACE, KEY_DELETE },
-	{ KEY_F1,       KEY_BRIGHTNESSDOWN,     POWERBOOK_FLAG_FKEY },
-	{ KEY_F2,       KEY_BRIGHTNESSUP,       POWERBOOK_FLAG_FKEY },
-	{ KEY_F3,       KEY_MUTE,               POWERBOOK_FLAG_FKEY },
-	{ KEY_F4,       KEY_VOLUMEDOWN,         POWERBOOK_FLAG_FKEY },
-	{ KEY_F5,       KEY_VOLUMEUP,           POWERBOOK_FLAG_FKEY },
-	{ KEY_F6,       KEY_NUMLOCK,            POWERBOOK_FLAG_FKEY },
-	{ KEY_F7,       KEY_SWITCHVIDEOMODE,    POWERBOOK_FLAG_FKEY },
-	{ KEY_F8,       KEY_KBDILLUMTOGGLE,     POWERBOOK_FLAG_FKEY },
-	{ KEY_F9,       KEY_KBDILLUMDOWN,       POWERBOOK_FLAG_FKEY },
-	{ KEY_F10,      KEY_KBDILLUMUP,         POWERBOOK_FLAG_FKEY },
+	{ KEY_F1,       KEY_BRIGHTNESSDOWN,     APPLE_FLAG_FKEY },
+	{ KEY_F2,       KEY_BRIGHTNESSUP,       APPLE_FLAG_FKEY },
+	{ KEY_F3,       KEY_MUTE,               APPLE_FLAG_FKEY },
+	{ KEY_F4,       KEY_VOLUMEDOWN,         APPLE_FLAG_FKEY },
+	{ KEY_F5,       KEY_VOLUMEUP,           APPLE_FLAG_FKEY },
+	{ KEY_F6,       KEY_NUMLOCK,            APPLE_FLAG_FKEY },
+	{ KEY_F7,       KEY_SWITCHVIDEOMODE,    APPLE_FLAG_FKEY },
+	{ KEY_F8,       KEY_KBDILLUMTOGGLE,     APPLE_FLAG_FKEY },
+	{ KEY_F9,       KEY_KBDILLUMDOWN,       APPLE_FLAG_FKEY },
+	{ KEY_F10,      KEY_KBDILLUMUP,         APPLE_FLAG_FKEY },
 	{ KEY_UP,       KEY_PAGEUP },
 	{ KEY_DOWN,     KEY_PAGEDOWN },
 	{ KEY_LEFT,     KEY_HOME },
@@ -142,7 +154,7 @@ static struct hidinput_key_translation powerbook_numlock_keys[] = {
 	{ }
 };
 
-static struct hidinput_key_translation powerbook_iso_keyboard[] = {
+static struct hidinput_key_translation apple_iso_keyboard[] = {
 	{ KEY_GRAVE,    KEY_102ND },
 	{ KEY_102ND,    KEY_GRAVE },
 	{ }
@@ -160,39 +172,42 @@ static struct hidinput_key_translation *find_translation(struct hidinput_key_tra
 	return NULL;
 }
 
-static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
 		struct hid_usage *usage, __s32 value)
 {
 	struct hidinput_key_translation *trans;
 
 	if (usage->code == KEY_FN) {
-		if (value) hid->quirks |=  HID_QUIRK_POWERBOOK_FN_ON;
-		else       hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
+		if (value) hid->quirks |=  HID_QUIRK_APPLE_FN_ON;
+		else       hid->quirks &= ~HID_QUIRK_APPLE_FN_ON;
 
 		input_event(input, usage->type, usage->code, value);
 
 		return 1;
 	}
 
-	if (hid_pb_fnmode) {
+	if (hid_apple_fnmode) {
 		int do_translate;
 
-		trans = find_translation(powerbook_fn_keys, usage->code);
+		trans = find_translation((hid->product < 0x220 ||
+					  hid->product >= 0x300) ?
+					 powerbook_fn_keys : apple_fn_keys,
+					 usage->code);
 		if (trans) {
-			if (test_bit(usage->code, hid->pb_pressed_fn))
+			if (test_bit(usage->code, hid->apple_pressed_fn))
 				do_translate = 1;
-			else if (trans->flags & POWERBOOK_FLAG_FKEY)
+			else if (trans->flags & APPLE_FLAG_FKEY)
 				do_translate =
-					(hid_pb_fnmode == 2 &&  (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
-					(hid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
+					(hid_apple_fnmode == 2 &&  (hid->quirks & HID_QUIRK_APPLE_FN_ON)) ||
+					(hid_apple_fnmode == 1 && !(hid->quirks & HID_QUIRK_APPLE_FN_ON));
 			else
-				do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
+				do_translate = (hid->quirks & HID_QUIRK_APPLE_FN_ON);
 
 			if (do_translate) {
 				if (value)
-					set_bit(usage->code, hid->pb_pressed_fn);
+					set_bit(usage->code, hid->apple_pressed_fn);
 				else
-					clear_bit(usage->code, hid->pb_pressed_fn);
+					clear_bit(usage->code, hid->apple_pressed_fn);
 
 				input_event(input, usage->type, trans->to, value);
 
@@ -217,8 +232,8 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
 		}
 	}
 
-	if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) {
-		trans = find_translation(powerbook_iso_keyboard, usage->code);
+	if (hid->quirks & HID_QUIRK_APPLE_ISO_KEYBOARD) {
+		trans = find_translation(apple_iso_keyboard, usage->code);
 		if (trans) {
 			input_event(input, usage->type, trans->to, value);
 			return 1;
@@ -228,31 +243,35 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
 	return 0;
 }
 
-static void hidinput_pb_setup(struct input_dev *input)
+static void hidinput_apple_setup(struct input_dev *input)
 {
 	struct hidinput_key_translation *trans;
 
 	set_bit(KEY_NUMLOCK, input->keybit);
 
 	/* Enable all needed keys */
+	for (trans = apple_fn_keys; trans->from; trans++)
+		set_bit(trans->to, input->keybit);
+
 	for (trans = powerbook_fn_keys; trans->from; trans++)
 		set_bit(trans->to, input->keybit);
 
 	for (trans = powerbook_numlock_keys; trans->from; trans++)
 		set_bit(trans->to, input->keybit);
 
-	for (trans = powerbook_iso_keyboard; trans->from; trans++)
+	for (trans = apple_iso_keyboard; trans->from; trans++)
 		set_bit(trans->to, input->keybit);
 
 }
 #else
-static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
-		struct hid_usage *usage, __s32 value)
+inline int hidinput_apple_event(struct hid_device *hid,
+				       struct input_dev *input,
+				       struct hid_usage *usage, __s32 value)
 {
 	return 0;
 }
 
-static inline void hidinput_pb_setup(struct input_dev *input)
+static inline void hidinput_apple_setup(struct input_dev *input)
 {
 }
 #endif
@@ -343,7 +362,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 {
 	struct input_dev *input = hidinput->input;
 	struct hid_device *device = input_get_drvdata(input);
-	int max = 0, code;
+	int max = 0, code, ret;
 	unsigned long *bit = NULL;
 
 	field->hidinput = hidinput;
@@ -362,6 +381,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 		goto ignore;
 	}
 
+	/* handle input mappings for quirky devices */
+	ret = hidinput_mapping_quirks(usage, input, &bit, &max);
+	if (ret)
+		goto mapped;
+
 	switch (usage->hid & HID_USAGE_PAGE) {
 
 		case HID_UP_UNDEFINED:
@@ -549,14 +573,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 				case 0x000: goto ignore;
 				case 0x034: map_key_clear(KEY_SLEEP);		break;
 				case 0x036: map_key_clear(BTN_MISC);		break;
-				/*
-				 * The next three are reported by Belkin wireless
-				 * keyboard (1020:0006). These values are "reserved"
-				 * in HUT 1.12.
-				 */
-				case 0x03a: map_key_clear(KEY_SOUND);           break;
-				case 0x03b: map_key_clear(KEY_CAMERA);          break;
-				case 0x03c: map_key_clear(KEY_DOCUMENTS);       break;
 
 				case 0x040: map_key_clear(KEY_MENU);		break;
 				case 0x045: map_key_clear(KEY_RADIO);		break;
@@ -602,10 +618,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 				case 0x0e9: map_key_clear(KEY_VOLUMEUP);	break;
 				case 0x0ea: map_key_clear(KEY_VOLUMEDOWN);	break;
 
-				/* reserved in HUT 1.12. Reported on Petalynx remote */
-				case 0x0f6: map_key_clear(KEY_NEXT);		break;
-				case 0x0fa: map_key_clear(KEY_BACK);		break;
-
 				case 0x182: map_key_clear(KEY_BOOKMARKS);	break;
 				case 0x183: map_key_clear(KEY_CONFIG);		break;
 				case 0x184: map_key_clear(KEY_WORDPROCESSOR);	break;
@@ -665,51 +677,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 				case 0x28b: map_key_clear(KEY_FORWARDMAIL);	break;
 				case 0x28c: map_key_clear(KEY_SEND);		break;
 
-				/* Reported on a Cherry Cymotion keyboard */
-				case 0x301: map_key_clear(KEY_PROG1);		break;
-				case 0x302: map_key_clear(KEY_PROG2);		break;
-				case 0x303: map_key_clear(KEY_PROG3);		break;
-
-				/* Reported on certain Logitech wireless keyboards */
-				case 0x1001: map_key_clear(KEY_MESSENGER);	break;
-				case 0x1003: map_key_clear(KEY_SOUND);		break;
-				case 0x1004: map_key_clear(KEY_VIDEO);		break;
-				case 0x1005: map_key_clear(KEY_AUDIO);		break;
-				case 0x100a: map_key_clear(KEY_DOCUMENTS);	break;
-				case 0x1011: map_key_clear(KEY_PREVIOUSSONG);	break;
-				case 0x1012: map_key_clear(KEY_NEXTSONG);	break;
-				case 0x1013: map_key_clear(KEY_CAMERA);		break;
-				case 0x1014: map_key_clear(KEY_MESSENGER);	break;
-				case 0x1015: map_key_clear(KEY_RECORD);		break;
-				case 0x1016: map_key_clear(KEY_PLAYER);		break;
-				case 0x1017: map_key_clear(KEY_EJECTCD);	break;
-				case 0x1018: map_key_clear(KEY_MEDIA);          break;
-				case 0x1019: map_key_clear(KEY_PROG1);		break;
-				case 0x101a: map_key_clear(KEY_PROG2);		break;
-				case 0x101b: map_key_clear(KEY_PROG3);		break;
-				case 0x101f: map_key_clear(KEY_ZOOMIN);		break;
-				case 0x1020: map_key_clear(KEY_ZOOMOUT);	break;
-				case 0x1021: map_key_clear(KEY_ZOOMRESET);	break;
-				case 0x1023: map_key_clear(KEY_CLOSE);		break;
-				case 0x1027: map_key_clear(KEY_MENU);           break;
-				/* this one is marked as 'Rotate' */
-				case 0x1028: map_key_clear(KEY_ANGLE);		break;
-				case 0x1029: map_key_clear(KEY_SHUFFLE);	break;
-				case 0x102a: map_key_clear(KEY_BACK);           break;
-				case 0x102b: map_key_clear(KEY_CYCLEWINDOWS);   break;
-				case 0x1041: map_key_clear(KEY_BATTERY);	break;
-				case 0x1042: map_key_clear(KEY_WORDPROCESSOR);	break;
-				case 0x1043: map_key_clear(KEY_SPREADSHEET);	break;
-				case 0x1044: map_key_clear(KEY_PRESENTATION);	break;
-				case 0x1045: map_key_clear(KEY_UNDO);		break;
-				case 0x1046: map_key_clear(KEY_REDO);		break;
-				case 0x1047: map_key_clear(KEY_PRINT);		break;
-				case 0x1048: map_key_clear(KEY_SAVE);		break;
-				case 0x1049: map_key_clear(KEY_PROG1);		break;
-				case 0x104a: map_key_clear(KEY_PROG2);		break;
-				case 0x104b: map_key_clear(KEY_PROG3);		break;
-				case 0x104c: map_key_clear(KEY_PROG4);		break;
-
 				default:    goto ignore;
 			}
 			break;
@@ -736,63 +703,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 
 		case HID_UP_MSVENDOR:
 
-			/* Unfortunately, there are multiple devices which
-			 * emit usages from MSVENDOR page that require different
-			 * handling. If this list grows too much in the future,
-			 * more general handling will have to be introduced here
-			 * (i.e. another blacklist).
-			 */
-
-			/* Chicony Chicony KU-0418 tactical pad */
-			if (IS_CHICONY_TACTICAL_PAD(device)) {
-				set_bit(EV_REP, input->evbit);
-				switch(usage->hid & HID_USAGE) {
-					case 0xff01: map_key_clear(BTN_1);		break;
-					case 0xff02: map_key_clear(BTN_2);		break;
-					case 0xff03: map_key_clear(BTN_3);		break;
-					case 0xff04: map_key_clear(BTN_4);		break;
-					case 0xff05: map_key_clear(BTN_5);		break;
-					case 0xff06: map_key_clear(BTN_6);		break;
-					case 0xff07: map_key_clear(BTN_7);		break;
-					case 0xff08: map_key_clear(BTN_8);		break;
-					case 0xff09: map_key_clear(BTN_9);		break;
-					case 0xff0a: map_key_clear(BTN_A);		break;
-					case 0xff0b: map_key_clear(BTN_B);		break;
-					default:    goto ignore;
-				}
-
-			/* Microsoft Natural Ergonomic Keyboard 4000 */
-			} else if (IS_MS_KB(device)) {
-				switch(usage->hid & HID_USAGE) {
-					case 0xfd06:
-						map_key_clear(KEY_CHAT);
-						break;
-					case 0xfd07:
-						map_key_clear(KEY_PHONE);
-						break;
-					case 0xff05:
-						set_bit(EV_REP, input->evbit);
-						map_key_clear(KEY_F13);
-						set_bit(KEY_F14, input->keybit);
-						set_bit(KEY_F15, input->keybit);
-						set_bit(KEY_F16, input->keybit);
-						set_bit(KEY_F17, input->keybit);
-						set_bit(KEY_F18, input->keybit);
-					default:	goto ignore;
-				}
-			} else {
-				goto ignore;
-			}
-			break;
+			goto ignore;
 
-		case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */
+		case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */
 
 			set_bit(EV_REP, input->evbit);
 			switch(usage->hid & HID_USAGE) {
 				case 0x003:
-					/* The fn key on Apple PowerBooks */
+					/* The fn key on Apple USB keyboards */
 					map_key_clear(KEY_FN);
-					hidinput_pb_setup(input);
+					hidinput_apple_setup(input);
 					break;
 
 				default:    goto ignore;
@@ -800,38 +720,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 			break;
 
 		case HID_UP_LOGIVENDOR:
-			set_bit(EV_REP, input->evbit);
-			switch(usage->hid & HID_USAGE) {
-				/* Reported on Logitech Ultra X Media Remote */
-				case 0x004: map_key_clear(KEY_AGAIN);		break;
-				case 0x00d: map_key_clear(KEY_HOME);		break;
-				case 0x024: map_key_clear(KEY_SHUFFLE);		break;
-				case 0x025: map_key_clear(KEY_TV);		break;
-				case 0x026: map_key_clear(KEY_MENU);		break;
-				case 0x031: map_key_clear(KEY_AUDIO);		break;
-				case 0x032: map_key_clear(KEY_TEXT);		break;
-				case 0x033: map_key_clear(KEY_LAST);		break;
-				case 0x047: map_key_clear(KEY_MP3);		break;
-				case 0x048: map_key_clear(KEY_DVD);		break;
-				case 0x049: map_key_clear(KEY_MEDIA);		break;
-				case 0x04a: map_key_clear(KEY_VIDEO);		break;
-				case 0x04b: map_key_clear(KEY_ANGLE);		break;
-				case 0x04c: map_key_clear(KEY_LANGUAGE);	break;
-				case 0x04d: map_key_clear(KEY_SUBTITLE);	break;
-				case 0x051: map_key_clear(KEY_RED);		break;
-				case 0x052: map_key_clear(KEY_CLOSE);		break;
-
-				/* Reported on Petalynx Maxter remote */
-				case 0x05a: map_key_clear(KEY_TEXT);		break;
-				case 0x05b: map_key_clear(KEY_RED);		break;
-				case 0x05c: map_key_clear(KEY_GREEN);		break;
-				case 0x05d: map_key_clear(KEY_YELLOW);		break;
-				case 0x05e: map_key_clear(KEY_BLUE);		break;
-
-				default:    goto ignore;
-			}
-			break;
 
+			goto ignore;
+		
 		case HID_UP_PID:
 
 			switch(usage->hid & HID_USAGE) {
@@ -858,6 +749,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 			break;
 	}
 
+mapped:
 	if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
 		if (usage->hid == HID_GD_Z)
 			map_rel(REL_HWHEEL);
@@ -867,9 +759,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 			map_key(BTN_1);
 	}
 
-	if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
-		 (usage->type == EV_REL) && (usage->code == REL_WHEEL))
-			set_bit(REL_HWHEEL, bit);
+	if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5 |
+			HID_QUIRK_2WHEEL_MOUSE_HACK_B8)) && (usage->type == EV_REL) &&
+			(usage->code == REL_WHEEL))
+		set_bit(REL_HWHEEL, bit);
 
 	if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
 		|| ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
@@ -960,25 +853,8 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
 	if (!usage->type)
 		return;
 
-	if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
-		|| ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
-		if (value) hid->quirks |=  HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
-		else       hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
-		return;
-	}
-
-	if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
-		input_event(input, usage->type, usage->code, -value);
-		return;
-	}
-
-	if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
-		input_event(input, usage->type, REL_HWHEEL, value);
-		return;
-	}
-
-	if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
-		return;
+	/* handle input events for quirky devices */
+	hidinput_event_quirks(hid, field, usage, value);
 
 	if (usage->hat_min < usage->hat_max || usage->hat_dir) {
 		int hat_dir = usage->hat_dir;
@@ -1039,25 +915,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
 		return;
 	}
 
-	/* Handling MS keyboards special buttons */
-	if (IS_MS_KB(hid) && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
-		int key = 0;
-		static int last_key = 0;
-		switch (value) {
-			case 0x01: key = KEY_F14; break;
-			case 0x02: key = KEY_F15; break;
-			case 0x04: key = KEY_F16; break;
-			case 0x08: key = KEY_F17; break;
-			case 0x10: key = KEY_F18; break;
-			default: break;
-		}
-		if (key) {
-			input_event(input, usage->type, key, 1);
-			last_key = key;
-		} else {
-			input_event(input, usage->type, last_key, 0);
-		}
-	}
 	/* report the usage code as scancode if the key status has changed */
 	if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
 		input_event(input, EV_MSC, MSC_SCAN, usage->hid);
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index c557d7040a69..7160fa65d79b 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -25,12 +25,13 @@ comment "Input core support is needed for USB HID input layer or HIDBP support"
 	depends on USB_HID && INPUT=n
 
 config USB_HIDINPUT_POWERBOOK
-	bool "Enable support for iBook/PowerBook/MacBook/MacBookPro special keys"
+	bool "Enable support for Apple laptop/aluminum USB special keys"
 	default n
 	depends on USB_HID
 	help
 	  Say Y here if you want support for the special keys (Fn, Numlock) on
-	  Apple iBooks, PowerBooks, MacBooks and MacBook Pros.
+	  Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB
+	  keyboards.
 
 	  If unsure, say N.
 
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index a2552856476b..b77b61e0cd7b 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -19,6 +19,7 @@
 
 #define USB_VENDOR_ID_A4TECH		0x09da
 #define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
+#define USB_DEVICE_ID_A4TECH_X5_005D	0x000a
 
 #define USB_VENDOR_ID_AASHIMA		0x06d6
 #define USB_DEVICE_ID_AASHIMA_GAMEPAD	0x0025
@@ -28,6 +29,9 @@
 #define USB_DEVICE_ID_ACECAD_FLAIR	0x0004
 #define USB_DEVICE_ID_ACECAD_302	0x0008
 
+#define USB_VENDOR_ID_ADS_TECH 		0x06e1
+#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X	0xa155
+
 #define USB_VENDOR_ID_AIPTEK		0x08ca
 #define USB_DEVICE_ID_AIPTEK_01		0x0001
 #define USB_DEVICE_ID_AIPTEK_10		0x0010
@@ -59,6 +63,9 @@
 #define USB_DEVICE_ID_APPLE_GEYSER4_ANSI	0x021a
 #define USB_DEVICE_ID_APPLE_GEYSER4_ISO	0x021b
 #define USB_DEVICE_ID_APPLE_GEYSER4_JIS	0x021c
+#define USB_DEVICE_ID_APPLE_ALU_ANSI	0x0220
+#define USB_DEVICE_ID_APPLE_ALU_ISO	0x0221
+#define USB_DEVICE_ID_APPLE_ALU_JIS	0x0222
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
 #define USB_DEVICE_ID_APPLE_IRCONTROL4	0x8242
@@ -94,6 +101,9 @@
 #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST	0x1500
 #define USB_DEVICE_ID_CODEMERCS_IOW_LAST	0x15ff
 
+#define USB_VENDOR_ID_CYGNAL		0x10c4
+#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X	0x818a
+
 #define USB_VENDOR_ID_CYPRESS		0x04b4
 #define USB_DEVICE_ID_CYPRESS_MOUSE	0x0001
 #define USB_DEVICE_ID_CYPRESS_HIDCOM	0x5500
@@ -114,6 +124,9 @@
 #define USB_VENDOR_ID_ESSENTIAL_REALITY	0x0d7f
 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
+#define USB_VENDOR_ID_EZKEY 		0x0518
+#define USB_DEVICE_ID_BTC_8193		0x0002
+
 #define USB_VENDOR_ID_GAMERON		0x0810
 #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR	0x0001
 
@@ -134,6 +147,9 @@
 #define USB_DEVICE_ID_GOGOPEN		0x00ce
 #define USB_DEVICE_ID_PENPOWER		0x00f4
 
+#define USB_VENDOR_ID_GRETAGMACBETH	0x0971
+#define USB_DEVICE_ID_GRETAGMACBETH_HUEY	0x2005
+
 #define USB_VENDOR_ID_GRIFFIN		0x077d
 #define USB_DEVICE_ID_POWERMATE		0x0410
 #define USB_DEVICE_ID_SOUNDKNOB		0x04AA
@@ -278,7 +294,9 @@
 #define USB_DEVICE_ID_LOGITECH_HARMONY_62 0xc14d
 #define USB_DEVICE_ID_LOGITECH_HARMONY_63 0xc14e
 #define USB_DEVICE_ID_LOGITECH_HARMONY_64 0xc14f
+#define USB_DEVICE_ID_LOGITECH_EXTREME_3D	0xc215
 #define USB_DEVICE_ID_LOGITECH_WHEEL	0xc294
+#define USB_DEVICE_ID_LOGITECH_ELITE_KBD	0xc30a
 #define USB_DEVICE_ID_LOGITECH_KBD	0xc311
 #define USB_DEVICE_ID_S510_RECEIVER	0xc50c
 #define USB_DEVICE_ID_S510_RECEIVER_2	0xc517
@@ -296,6 +314,12 @@
 
 #define USB_VENDOR_ID_MICROSOFT		0x045e
 #define USB_DEVICE_ID_SIDEWINDER_GV	0x003b
+#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
+#define USB_DEVICE_ID_MS_NE4K		0x00db
+#define USB_DEVICE_ID_MS_LK6K		0x00f9
+
+#define USB_VENDOR_ID_MONTEREY		0x0566
+#define USB_DEVICE_ID_GENIUS_KB29E	0x3004
 
 #define USB_VENDOR_ID_NCR		0x0404
 #define USB_DEVICE_ID_NCR_FIRST		0x0300
@@ -324,6 +348,9 @@
 #define USB_VENDOR_ID_SAITEK		0x06a3
 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
 
+#define USB_VENDOR_ID_SAMSUNG		0x0419
+#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE	0x0001
+
 #define USB_VENDOR_ID_SONY			0x054c
 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
 
@@ -368,6 +395,7 @@ static const struct hid_blacklist {
 } hid_blacklist[] = {
 
 	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
+	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D, HID_QUIRK_2WHEEL_MOUSE_HACK_B8 },
 	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
 
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
@@ -390,6 +418,9 @@ static const struct hid_blacklist {
 	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
 	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
 
+	{ USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT },
+
+	{ USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
@@ -402,6 +433,7 @@ static const struct hid_blacklist {
 	{ USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
 	{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
@@ -423,6 +455,7 @@ static const struct hid_blacklist {
 	{ USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
@@ -516,14 +549,18 @@ static const struct hid_blacklist {
 	{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
 
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
 
+	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K, HID_QUIRK_MICROSOFT_KEYS },
+	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K, HID_QUIRK_MICROSOFT_KEYS },
+
 	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
 
 	{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
 	{ USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
 
-	{ USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+	{ USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER | HID_QUIRK_HIDDEV },
 
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
@@ -531,7 +568,9 @@ static const struct hid_blacklist {
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
+	{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
 	{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
@@ -540,19 +579,22 @@ static const struct hid_blacklist {
 
 	{ USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
 
 	{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS },
@@ -638,10 +680,14 @@ static const struct hid_rdesc_blacklist {
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
 
+	{ USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER },
+
 	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS },
 
 	{ USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX },
 
+	{ USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE },
+
 	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
 	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
 
@@ -884,6 +930,8 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
 	return quirks;
 }
 
+EXPORT_SYMBOL_GPL(usbhid_lookup_quirk);
+
 /*
  * Cherry Cymotion keyboard have an invalid HID report descriptor,
  * that needs fixing before we can parse it.
@@ -914,6 +962,33 @@ static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
 	}
 }
 
+/*
+ * Samsung IrDA remote controller (reports as Cypress USB Mouse).
+ *
+ * Vendor specific report #4 has a size of 48 bit,
+ * and therefore is not accepted when inspecting the descriptors.
+ * As a workaround we reinterpret the report as:
+ *   Variable type, count 6, size 8 bit, log. maximum 255
+ * The burden to reconstruct the data is moved into user space.
+ */
+static void usbhid_fixup_samsung_irda_descriptor(unsigned char *rdesc,
+						  int rsize)
+{
+	if (rsize >= 182 && rdesc[175] == 0x25
+			 && rdesc[176] == 0x40
+			 && rdesc[177] == 0x75
+			 && rdesc[178] == 0x30
+			 && rdesc[179] == 0x95
+			 && rdesc[180] == 0x01
+			 && rdesc[182] == 0x40) {
+		printk(KERN_INFO "Fixing up Samsung IrDA report descriptor\n");
+		rdesc[176] = 0xff;
+		rdesc[178] = 0x08;
+		rdesc[180] = 0x06;
+		rdesc[182] = 0x42;
+	}
+}
+
 /* Petalynx Maxter Remote has maximum for consumer page set too low */
 static void usbhid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize)
 {
@@ -965,6 +1040,14 @@ static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize)
 	}
 }
 
+static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rsize)
+{
+	if (rsize >= 30 && rdesc[29] == 0x05
+			&& rdesc[30] == 0x09) {
+		printk(KERN_INFO "Fixing up button/consumer in HID report descriptor\n");
+		rdesc[30] = 0x0c;
+	}
+}
 
 static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
 {
@@ -982,6 +1065,13 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned
 
 	if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS)
 		usbhid_fixup_macbook_descriptor(rdesc, rsize);
+
+	if (quirks & HID_QUIRK_RDESC_BUTTON_CONSUMER)
+		usbhid_fixup_button_consumer_descriptor(rdesc, rsize);
+
+	if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE)
+		usbhid_fixup_samsung_irda_descriptor(rdesc, rsize);
+
 }
 
 /**
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
index 69882a726e99..144578b1a00c 100644
--- a/drivers/hid/usbhid/hid-tmff.c
+++ b/drivers/hid/usbhid/hid-tmff.c
@@ -137,7 +137,8 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
 int hid_tmff_init(struct hid_device *hid)
 {
 	struct tmff_device *tmff;
-	struct list_head *pos;
+	struct hid_report *report;
+	struct list_head *report_list;
 	struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
 	struct input_dev *input_dev = hidinput->input;
 	const signed short *ff_bits = ff_joystick;
@@ -149,8 +150,8 @@ int hid_tmff_init(struct hid_device *hid)
 		return -ENOMEM;
 
 	/* Find the report to use */
-	list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
-		struct hid_report *report = (struct hid_report *)pos;
+	report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	list_for_each_entry(report, report_list, list) {
 		int fieldnum;
 
 		for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) {
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index 775a1ef28a29..5d9dbb47e4a8 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -235,6 +235,14 @@ static int usb_kbd_probe(struct usb_interface *iface,
 	if (!usb_endpoint_is_int_in(endpoint))
 		return -ENODEV;
 
+#ifdef CONFIG_USB_HID
+	if (usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
+				le16_to_cpu(dev->descriptor.idProduct))
+			& HID_QUIRK_IGNORE) {
+		return -ENODEV;
+	}
+#endif
+
 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index f8ad6910d3d9..df0d96d989de 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -131,6 +131,14 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
 	if (!usb_endpoint_is_int_in(endpoint))
 		return -ENODEV;
 
+#ifdef CONFIG_USB_HID
+	if (usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
+				le16_to_cpu(dev->descriptor.idProduct))
+			& (HID_QUIRK_IGNORE|HID_QUIRK_IGNORE_MOUSE)) {
+		return -ENODEV;
+	}
+#endif
+
 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index a37cb6b8593c..35812823787b 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -1,7 +1,7 @@
-/* ------------------------------------------------------------------------- */
-/* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters		     */
-/* ------------------------------------------------------------------------- */
-/*   Copyright (C) 1995-2000 Simon G. Vogl
+/* -------------------------------------------------------------------------
+ * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
+ * -------------------------------------------------------------------------
+ *   Copyright (C) 1995-2000 Simon G. Vogl
 
     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
@@ -15,8 +15,8 @@
 
     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.		     */
-/* ------------------------------------------------------------------------- */
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ------------------------------------------------------------------------- */
 
 /* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
    <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
@@ -60,26 +60,26 @@ MODULE_PARM_DESC(i2c_debug,
 
 /* --- setting states on the bus with the right timing: ---------------	*/
 
-#define setsda(adap,val) adap->setsda(adap->data, val)
-#define setscl(adap,val) adap->setscl(adap->data, val)
-#define getsda(adap) adap->getsda(adap->data)
-#define getscl(adap) adap->getscl(adap->data)
+#define setsda(adap, val)	adap->setsda(adap->data, val)
+#define setscl(adap, val)	adap->setscl(adap->data, val)
+#define getsda(adap)		adap->getsda(adap->data)
+#define getscl(adap)		adap->getscl(adap->data)
 
 static inline void sdalo(struct i2c_algo_bit_data *adap)
 {
-	setsda(adap,0);
+	setsda(adap, 0);
 	udelay((adap->udelay + 1) / 2);
 }
 
 static inline void sdahi(struct i2c_algo_bit_data *adap)
 {
-	setsda(adap,1);
+	setsda(adap, 1);
 	udelay((adap->udelay + 1) / 2);
 }
 
 static inline void scllo(struct i2c_algo_bit_data *adap)
 {
-	setscl(adap,0);
+	setscl(adap, 0);
 	udelay(adap->udelay / 2);
 }
 
@@ -91,22 +91,21 @@ static int sclhi(struct i2c_algo_bit_data *adap)
 {
 	unsigned long start;
 
-	setscl(adap,1);
+	setscl(adap, 1);
 
 	/* Not all adapters have scl sense line... */
 	if (!adap->getscl)
 		goto done;
 
-	start=jiffies;
-	while (! getscl(adap) ) {	
- 		/* the hw knows how to read the clock line,
- 		 * so we wait until it actually gets high.
- 		 * This is safer as some chips may hold it low
- 		 * while they are processing data internally. 
- 		 */
-		if (time_after_eq(jiffies, start+adap->timeout)) {
+	start = jiffies;
+	while (!getscl(adap)) {
+		/* This hw knows how to read the clock line, so we wait
+		 * until it actually gets high.  This is safer as some
+		 * chips may hold it low ("clock stretching") while they
+		 * are processing data internally.
+		 */
+		if (time_after_eq(jiffies, start + adap->timeout))
 			return -ETIMEDOUT;
-		}
 		cond_resched();
 	}
 #ifdef DEBUG
@@ -118,11 +117,11 @@ static int sclhi(struct i2c_algo_bit_data *adap)
 done:
 	udelay(adap->udelay);
 	return 0;
-} 
+}
 
 
 /* --- other auxiliary functions --------------------------------------	*/
-static void i2c_start(struct i2c_algo_bit_data *adap) 
+static void i2c_start(struct i2c_algo_bit_data *adap)
 {
 	/* assert: scl, sda are high */
 	setsda(adap, 0);
@@ -130,7 +129,7 @@ static void i2c_start(struct i2c_algo_bit_data *adap)
 	scllo(adap);
 }
 
-static void i2c_repstart(struct i2c_algo_bit_data *adap) 
+static void i2c_repstart(struct i2c_algo_bit_data *adap)
 {
 	/* assert: scl is low */
 	sdahi(adap);
@@ -141,18 +140,18 @@ static void i2c_repstart(struct i2c_algo_bit_data *adap)
 }
 
 
-static void i2c_stop(struct i2c_algo_bit_data *adap) 
+static void i2c_stop(struct i2c_algo_bit_data *adap)
 {
 	/* assert: scl is low */
 	sdalo(adap);
-	sclhi(adap); 
+	sclhi(adap);
 	setsda(adap, 1);
 	udelay(adap->udelay);
 }
 
 
 
-/* send a byte without start cond., look for arbitration, 
+/* send a byte without start cond., look for arbitration,
    check ackn. from slave */
 /* returns:
  * 1 if the device acknowledged
@@ -167,27 +166,33 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
 
 	/* assert: scl is low */
-	for ( i=7 ; i>=0 ; i-- ) {
+	for (i = 7; i >= 0; i--) {
 		sb = (c >> i) & 1;
-		setsda(adap,sb);
+		setsda(adap, sb);
 		udelay((adap->udelay + 1) / 2);
-		if (sclhi(adap)<0) { /* timed out */
+		if (sclhi(adap) < 0) { /* timed out */
 			bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
 				"timeout at bit #%d\n", (int)c, i);
 			return -ETIMEDOUT;
-		};
-		/* do arbitration here: 
-		 * if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
+		}
+		/* FIXME do arbitration here:
+		 * if (sb && !getsda(adap)) -> ouch! Get out of here.
+		 *
+		 * Report a unique code, so higher level code can retry
+		 * the whole (combined) message and *NOT* issue STOP.
 		 */
 		scllo(adap);
 	}
 	sdahi(adap);
-	if (sclhi(adap)<0){ /* timeout */
+	if (sclhi(adap) < 0) { /* timeout */
 		bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
 			"timeout at ack\n", (int)c);
 		return -ETIMEDOUT;
-	};
-	/* read ack: SDA should be pulled down by slave */
+	}
+
+	/* read ack: SDA should be pulled down by slave, or it may
+	 * NAK (usually to report problems with the data we wrote).
+	 */
 	ack = !getsda(adap);    /* ack: sda is pulled low -> success */
 	bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
 		ack ? "A" : "NA");
@@ -198,24 +203,24 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
 }
 
 
-static int i2c_inb(struct i2c_adapter *i2c_adap) 
+static int i2c_inb(struct i2c_adapter *i2c_adap)
 {
 	/* read byte via i2c port, without start/stop sequence	*/
 	/* acknowledge is sent in i2c_read.			*/
 	int i;
-	unsigned char indata=0;
+	unsigned char indata = 0;
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
 
 	/* assert: scl is low */
 	sdahi(adap);
-	for (i=0;i<8;i++) {
-		if (sclhi(adap)<0) { /* timeout */
+	for (i = 0; i < 8; i++) {
+		if (sclhi(adap) < 0) { /* timeout */
 			bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
 				"#%d\n", 7 - i);
 			return -ETIMEDOUT;
-		};
+		}
 		indata *= 2;
-		if ( getsda(adap) ) 
+		if (getsda(adap))
 			indata |= 0x01;
 		setscl(adap, 0);
 		udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
@@ -228,66 +233,67 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
  * Sanity check for the adapter hardware - check the reaction of
  * the bus lines only if it seems to be idle.
  */
-static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
-	int scl,sda;
+static int test_bus(struct i2c_algo_bit_data *adap, char *name)
+{
+	int scl, sda;
 
-	if (adap->getscl==NULL)
+	if (adap->getscl == NULL)
 		pr_info("%s: Testing SDA only, SCL is not readable\n", name);
 
-	sda=getsda(adap);
-	scl=(adap->getscl==NULL?1:getscl(adap));
-	if (!scl || !sda ) {
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!scl || !sda) {
 		printk(KERN_WARNING "%s: bus seems to be busy\n", name);
 		goto bailout;
 	}
 
 	sdalo(adap);
-	sda=getsda(adap);
-	scl=(adap->getscl==NULL?1:getscl(adap));
-	if ( 0 != sda ) {
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (sda) {
 		printk(KERN_WARNING "%s: SDA stuck high!\n", name);
 		goto bailout;
 	}
-	if ( 0 == scl ) {
+	if (!scl) {
 		printk(KERN_WARNING "%s: SCL unexpected low "
 		       "while pulling SDA low!\n", name);
 		goto bailout;
-	}		
+	}
 
 	sdahi(adap);
-	sda=getsda(adap);
-	scl=(adap->getscl==NULL?1:getscl(adap));
-	if ( 0 == sda ) {
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!sda) {
 		printk(KERN_WARNING "%s: SDA stuck low!\n", name);
 		goto bailout;
 	}
-	if ( 0 == scl ) {
+	if (!scl) {
 		printk(KERN_WARNING "%s: SCL unexpected low "
 		       "while pulling SDA high!\n", name);
 		goto bailout;
 	}
 
 	scllo(adap);
-	sda=getsda(adap);
-	scl=(adap->getscl==NULL?0:getscl(adap));
-	if ( 0 != scl ) {
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 0 : getscl(adap);
+	if (scl) {
 		printk(KERN_WARNING "%s: SCL stuck high!\n", name);
 		goto bailout;
 	}
-	if ( 0 == sda ) {
+	if (!sda) {
 		printk(KERN_WARNING "%s: SDA unexpected low "
 		       "while pulling SCL low!\n", name);
 		goto bailout;
 	}
-	
+
 	sclhi(adap);
-	sda=getsda(adap);
-	scl=(adap->getscl==NULL?1:getscl(adap));
-	if ( 0 == scl ) {
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!scl) {
 		printk(KERN_WARNING "%s: SCL stuck low!\n", name);
 		goto bailout;
 	}
-	if ( 0 == sda ) {
+	if (!sda) {
 		printk(KERN_WARNING "%s: SDA unexpected low "
 		       "while pulling SCL high!\n", name);
 		goto bailout;
@@ -314,9 +320,10 @@ static int try_address(struct i2c_adapter *i2c_adap,
 		       unsigned char addr, int retries)
 {
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-	int i,ret = -1;
-	for (i=0;i<=retries;i++) {
-		ret = i2c_outb(i2c_adap,addr);
+	int i, ret = -1;
+
+	for (i = 0; i <= retries; i++) {
+		ret = i2c_outb(i2c_adap, addr);
 		if (ret == 1 || i == retries)
 			break;
 		bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
@@ -338,20 +345,38 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 {
 	const unsigned char *temp = msg->buf;
 	int count = msg->len;
-	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; 
+	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
 	int retval;
-	int wrcount=0;
+	int wrcount = 0;
 
 	while (count > 0) {
 		retval = i2c_outb(i2c_adap, *temp);
-		if ((retval>0) || (nak_ok && (retval==0)))  { /* ok or ignored NAK */
-			count--; 
+
+		/* OK/ACK; or ignored NAK */
+		if ((retval > 0) || (nak_ok && (retval == 0))) {
+			count--;
 			temp++;
 			wrcount++;
-		} else { /* arbitration or no acknowledge */
-			dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n");
-			return (retval<0)? retval : -EFAULT;
-			        /* got a better one ?? */
+
+		/* A slave NAKing the master means the slave didn't like
+		 * something about the data it saw.  For example, maybe
+		 * the SMBus PEC was wrong.
+		 */
+		} else if (retval == 0) {
+			dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");
+			return -EIO;
+
+		/* Timeout; or (someday) lost arbitration
+		 *
+		 * FIXME Lost ARB implies retrying the transaction from
+		 * the first message, after the "winning" master issues
+		 * its STOP.  As a rule, upper layer code has no reason
+		 * to know or care about this ... it is *NOT* an error.
+		 */
+		} else {
+			dev_err(&i2c_adap->dev, "sendbytes: error %d\n",
+					retval);
+			return retval;
 		}
 	}
 	return wrcount;
@@ -376,14 +401,14 @@ static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
 static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 {
 	int inval;
-	int rdcount=0;   	/* counts bytes read */
+	int rdcount = 0;	/* counts bytes read */
 	unsigned char *temp = msg->buf;
 	int count = msg->len;
 	const unsigned flags = msg->flags;
 
 	while (count > 0) {
 		inval = i2c_inb(i2c_adap);
-		if (inval>=0) {
+		if (inval >= 0) {
 			*temp = inval;
 			rdcount++;
 		} else {   /* read timed out */
@@ -431,7 +456,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
  * returns:
  *  0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
  * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
- *	-ETIMEDOUT, for example if the lines are stuck...) 
+ *	-ETIMEDOUT, for example if the lines are stuck...)
  */
 static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 {
@@ -443,10 +468,10 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 	int ret, retries;
 
 	retries = nak_ok ? 0 : i2c_adap->retries;
-	
-	if ( (flags & I2C_M_TEN)  ) { 
+
+	if (flags & I2C_M_TEN) {
 		/* a ten bit address */
-		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
+		addr = 0xf0 | ((msg->addr >> 7) & 0x03);
 		bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
 		/* try extended address code...*/
 		ret = try_address(i2c_adap, addr, retries);
@@ -456,33 +481,33 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 			return -EREMOTEIO;
 		}
 		/* the remaining 8 bit address */
-		ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
+		ret = i2c_outb(i2c_adap, msg->addr & 0x7f);
 		if ((ret != 1) && !nak_ok) {
 			/* the chip did not ack / xmission error occurred */
 			dev_err(&i2c_adap->dev, "died at 2nd address code\n");
 			return -EREMOTEIO;
 		}
-		if ( flags & I2C_M_RD ) {
+		if (flags & I2C_M_RD) {
 			bit_dbg(3, &i2c_adap->dev, "emitting repeated "
 				"start condition\n");
 			i2c_repstart(adap);
 			/* okay, now switch into reading mode */
 			addr |= 0x01;
 			ret = try_address(i2c_adap, addr, retries);
-			if ((ret!=1) && !nak_ok) {
+			if ((ret != 1) && !nak_ok) {
 				dev_err(&i2c_adap->dev,
 					"died at repeated address code\n");
 				return -EREMOTEIO;
 			}
 		}
 	} else {		/* normal 7bit address	*/
-		addr = ( msg->addr << 1 );
-		if (flags & I2C_M_RD )
+		addr = msg->addr << 1;
+		if (flags & I2C_M_RD)
 			addr |= 1;
-		if (flags & I2C_M_REV_DIR_ADDR )
+		if (flags & I2C_M_REV_DIR_ADDR)
 			addr ^= 1;
 		ret = try_address(i2c_adap, addr, retries);
-		if ((ret!=1) && !nak_ok)
+		if ((ret != 1) && !nak_ok)
 			return -EREMOTEIO;
 	}
 
@@ -494,15 +519,14 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
 {
 	struct i2c_msg *pmsg;
 	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
-	
-	int i,ret;
+	int i, ret;
 	unsigned short nak_ok;
 
 	bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
 	i2c_start(adap);
-	for (i=0;i<num;i++) {
+	for (i = 0; i < num; i++) {
 		pmsg = &msgs[i];
-		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; 
+		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
 			if (i) {
 				bit_dbg(3, &i2c_adap->dev, "emitting "
@@ -517,7 +541,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
 				goto bailout;
 			}
 		}
-		if (pmsg->flags & I2C_M_RD ) {
+		if (pmsg->flags & I2C_M_RD) {
 			/* read bytes into buffer*/
 			ret = readbytes(i2c_adap, pmsg);
 			if (ret >= 1)
@@ -551,7 +575,7 @@ bailout:
 
 static u32 bit_func(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
 	       I2C_FUNC_SMBUS_READ_BLOCK_DATA |
 	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
 	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
@@ -565,8 +589,8 @@ static const struct i2c_algorithm i2c_bit_algo = {
 	.functionality	= bit_func,
 };
 
-/* 
- * registering functions to load algorithms at runtime 
+/*
+ * registering functions to load algorithms at runtime
  */
 static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
 {
@@ -574,7 +598,7 @@ static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
 
 	if (bit_test) {
 		int ret = test_bus(bit_adap, adap->name);
-		if (ret<0)
+		if (ret < 0)
 			return -ENODEV;
 	}
 
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index ab2e6f3498b4..8907b0191677 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -203,35 +203,6 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
 /* ----- Utility functions
  */
 
-static inline int try_address(struct i2c_algo_pcf_data *adap,
-		       unsigned char addr, int retries)
-{
-	int i, status, ret = -1;
-	int wfp;
-	for (i=0;i<retries;i++) {
-		i2c_outb(adap, addr);
-		i2c_start(adap);
-		status = get_pcf(adap, 1);
-		if ((wfp = wait_for_pin(adap, &status)) >= 0) {
-			if ((status & I2C_PCF_LRB) == 0) { 
-				i2c_stop(adap);
-				break;	/* success! */
-			}
-		}
-		if (wfp == -EINTR) {
-			/* arbitration lost */
-			udelay(adap->udelay);
-			return -EINTR;
-		}
-		i2c_stop(adap);
-		udelay(adap->udelay);
-	}
-	DEB2(if (i) printk(KERN_DEBUG "i2c-algo-pcf.o: needed %d retries for %d\n",i,
-	                   addr));
-	return ret;
-}
-
-
 static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
                          int count, int last)
 {
@@ -321,47 +292,19 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
 }
 
 
-static inline int pcf_doAddress(struct i2c_algo_pcf_data *adap,
-                                struct i2c_msg *msg, int retries) 
+static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
+			 struct i2c_msg *msg)
 {
 	unsigned short flags = msg->flags;
 	unsigned char addr;
-	int ret;
-	if ( (flags & I2C_M_TEN)  ) { 
-		/* a ten bit address */
-		addr = 0xf0 | (( msg->addr >> 7) & 0x03);
-		DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
-		/* try extended address code...*/
-		ret = try_address(adap, addr, retries);
-		if (ret!=1) {
-			printk(KERN_ERR "died at extended address code.\n");
-			return -EREMOTEIO;
-		}
-		/* the remaining 8 bit address */
-		i2c_outb(adap,msg->addr & 0x7f);
-/* Status check comes here */
-		if (ret != 1) {
-			printk(KERN_ERR "died at 2nd address code.\n");
-			return -EREMOTEIO;
-		}
-		if ( flags & I2C_M_RD ) {
-			i2c_repstart(adap);
-			/* okay, now switch into reading mode */
-			addr |= 0x01;
-			ret = try_address(adap, addr, retries);
-			if (ret!=1) {
-				printk(KERN_ERR "died at extended address code.\n");
-				return -EREMOTEIO;
-			}
-		}
-	} else {		/* normal 7bit address	*/
-		addr = ( msg->addr << 1 );
-		if (flags & I2C_M_RD )
-			addr |= 1;
-		if (flags & I2C_M_REV_DIR_ADDR )
-			addr ^= 1;
-		i2c_outb(adap, addr);
-	}
+
+	addr = msg->addr << 1;
+	if (flags & I2C_M_RD)
+		addr |= 1;
+	if (flags & I2C_M_REV_DIR_ADDR)
+		addr ^= 1;
+	i2c_outb(adap, addr);
+
 	return 0;
 }
 
@@ -390,7 +333,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
 		     pmsg->flags & I2C_M_RD ? "read" : "write",
                      pmsg->len, pmsg->addr, i + 1, num);)
     
-		ret = pcf_doAddress(adap, pmsg, i2c_adap->retries);
+		ret = pcf_doAddress(adap, pmsg);
 
 		/* Send START */
 		if (i == 0) {
@@ -453,7 +396,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
 static u32 pcf_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | 
-	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; 
+	       I2C_FUNC_PROTOCOL_MANGLING;
 }
 
 /* -----exported algorithm data: -------------------------------------	*/
@@ -475,9 +418,7 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap)
 
 	/* register new adapter to i2c module... */
 	adap->algo = &pcf_algo;
-
-	adap->timeout = 100;		/* default values, should	*/
-	adap->retries = 3;		/* be replaced by defines	*/
+	adap->timeout = 100;
 
 	if ((rval = pcf_init_8584(pcf_adap)))
 		return rval;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c466c6cfc2e5..b61f56b6f311 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -182,7 +182,8 @@ config I2C_I801
 	  will be called i2c-i801.
 
 config I2C_I810
-	tristate "Intel 810/815"
+	tristate "Intel 810/815 (DEPRECATED)"
+	default n
 	depends on PCI
 	select I2C_ALGOBIT
 	help
@@ -195,6 +196,8 @@ config I2C_I810
 	    i815
 	    i845G
 
+	  This driver is deprecated in favor of the i810fb and intelfb drivers.
+
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-i810.
 
@@ -259,20 +262,6 @@ config I2C_IOP3XX
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-iop3xx.
 
-config I2C_IXP4XX
-	tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
-	depends on ARCH_IXP4XX
-	select I2C_ALGOBIT
-	help
-	  Say Y here if you have an Intel IXP4xx(420,421,422,425) based 
-	  system and are using GPIO lines for an I2C bus.
-
-	  This support is also available as a module. If so, the module
-	  will be called i2c-ixp4xx.
-
-	  This driver is deprecated and will be dropped soon. Use i2c-gpio
-	  instead.
-
 config I2C_IXP2000
 	tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
 	depends on ARCH_IXP2000
@@ -396,7 +385,8 @@ config I2C_PASEMI
 	  Supports the PA Semi PWRficient on-chip SMBus interfaces.
 
 config I2C_PROSAVAGE
-	tristate "S3/VIA (Pro)Savage"
+	tristate "S3/VIA (Pro)Savage (DEPRECATED)"
+	default n
 	depends on PCI
 	select I2C_ALGOBIT
 	help
@@ -407,6 +397,8 @@ config I2C_PROSAVAGE
 	    S3/VIA KM266/VT8375 aka ProSavage8
 	    S3/VIA KM133/VT8365 aka Savage4
 
+	  This driver is deprecated in favor of the savagefb driver.
+
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-prosavage.
 
@@ -418,13 +410,16 @@ config I2C_S3C2410
 	  Samsung S3C2410 based System-on-Chip devices.
 
 config I2C_SAVAGE4
-	tristate "S3 Savage 4"
-	depends on PCI && EXPERIMENTAL
+	tristate "S3 Savage 4 (DEPRECATED)"
+	default n
+	depends on PCI
 	select I2C_ALGOBIT
 	help
 	  If you say yes to this option, support will be included for the 
 	  S3 Savage 4 I2C interface.
 
+	  This driver is deprecated in favor of the savagefb driver.
+
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-savage4.
 
@@ -611,7 +606,7 @@ config I2C_VIAPRO
 	    VT8231
 	    VT8233/A
 	    VT8235
-	    VT8237R/A
+	    VT8237R/A/S
 	    VT8251
 	    CX700
 
@@ -648,7 +643,7 @@ config I2C_PCA_ISA
 
 config I2C_MV64XXX
 	tristate "Marvell mv64xxx I2C Controller"
-	depends on MV64X60 && EXPERIMENTAL
+	depends on (MV64X60 || ARCH_ORION) && EXPERIMENTAL
 	help
 	  If you say yes to this option, support will be included for the
 	  built-in I2C interface on the Marvell 64xxx line of host bridges.
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 81d43c27cf93..ea7068f1eb6b 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_I2C_I810)		+= i2c-i810.o
 obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
-obj-$(CONFIG_I2C_IXP4XX)	+= i2c-ixp4xx.o
 obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
 obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 7490dc1771ae..573abe440842 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -334,6 +334,10 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
 	int error;
 	u8 temp;
 	
+	/* driver_data might come from user-space, so check it */
+	if (id->driver_data > ARRAY_SIZE(chipname))
+		return -EINVAL;
+
 	if (amd756_ioport) {
 		dev_err(&pdev->dev, "Only one device supported "
 		       "(you have a strange motherboard, btw)\n");
@@ -405,6 +409,7 @@ static struct pci_driver amd756_driver = {
 	.id_table	= amd756_ids,
 	.probe		= amd756_probe,
 	.remove		= __devexit_p(amd756_remove),
+	.dynids.use_driver_data = 1,
 };
 
 static int __init amd756_init(void)
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index 2f684166c43d..1953b26da56a 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -30,14 +30,22 @@
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
+#include <linux/slab.h>
 
 #include <asm/mach-au1x00/au1xxx.h>
 #include <asm/mach-au1x00/au1xxx_psc.h>
 
-#include "i2c-au1550.h"
+struct i2c_au1550_data {
+	u32	psc_base;
+	int	xfer_timeout;
+	int	ack_timeout;
+	struct i2c_adapter adap;
+	struct resource *ioarea;
+};
 
 static int
 wait_xfer_done(struct i2c_au1550_data *adap)
@@ -105,7 +113,7 @@ wait_master_done(struct i2c_au1550_data *adap)
 }
 
 static int
-do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
+do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
 {
 	volatile psc_smb_t	*sp;
 	u32			stat;
@@ -134,6 +142,10 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
 	if (rd)
 		addr |= 1;
 
+	/* zero-byte xfers stop immediately */
+	if (q)
+		addr |= PSC_SMBTXRX_STP;
+
 	/* Put byte into fifo, start up master.
 	*/
 	sp->psc_smbtxrx = addr;
@@ -142,7 +154,7 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
 	au_sync();
 	if (wait_ack(adap))
 		return -EIO;
-	return 0;
+	return (q) ? wait_master_done(adap) : 0;
 }
 
 static u32
@@ -262,7 +274,8 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
 
 	for (i = 0; !err && i < num; i++) {
 		p = &msgs[i];
-		err = do_address(adap, p->addr, p->flags & I2C_M_RD);
+		err = do_address(adap, p->addr, p->flags & I2C_M_RD,
+				 (p->len == 0));
 		if (err || !p->len)
 			continue;
 		if (p->flags & I2C_M_RD)
@@ -294,18 +307,48 @@ static const struct i2c_algorithm au1550_algo = {
  * Prior to calling us, the 50MHz clock frequency and routing
  * must have been set up for the PSC indicated by the adapter.
  */
-int
-i2c_au1550_add_bus(struct i2c_adapter *i2c_adap)
+static int __devinit
+i2c_au1550_probe(struct platform_device *pdev)
 {
-	struct i2c_au1550_data *adap = i2c_adap->algo_data;
-	volatile psc_smb_t	*sp;
-	u32	stat;
+	struct i2c_au1550_data *priv;
+	volatile psc_smb_t *sp;
+	struct resource *r;
+	u32 stat;
+	int ret;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	priv->ioarea = request_mem_region(r->start, r->end - r->start + 1,
+					  pdev->name);
+	if (!priv->ioarea) {
+		ret = -EBUSY;
+		goto out_mem;
+	}
 
-	i2c_adap->algo = &au1550_algo;
+	priv->psc_base = r->start;
+	priv->xfer_timeout = 200;
+	priv->ack_timeout = 200;
+
+	priv->adap.id = I2C_HW_AU1550_PSC;
+	priv->adap.nr = pdev->id;
+	priv->adap.algo = &au1550_algo;
+	priv->adap.algo_data = priv;
+	priv->adap.dev.parent = &pdev->dev;
+	strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
 
 	/* Now, set up the PSC for SMBus PIO mode.
 	*/
-	sp = (volatile psc_smb_t *)(adap->psc_base);
+	sp = (volatile psc_smb_t *)priv->psc_base;
 	sp->psc_ctrl = PSC_CTRL_DISABLE;
 	au_sync();
 	sp->psc_sel = PSC_SEL_PS_SMBUSMODE;
@@ -343,87 +386,87 @@ i2c_au1550_add_bus(struct i2c_adapter *i2c_adap)
 		au_sync();
 	} while ((stat & PSC_SMBSTAT_DR) == 0);
 
-	return i2c_add_adapter(i2c_adap);
-}
+	ret = i2c_add_numbered_adapter(&priv->adap);
+	if (ret == 0) {
+		platform_set_drvdata(pdev, priv);
+		return 0;
+	}
 
+	/* disable the PSC */
+	sp->psc_smbcfg = 0;
+	sp->psc_ctrl = PSC_CTRL_DISABLE;
+	au_sync();
 
-int
-i2c_au1550_del_bus(struct i2c_adapter *adap)
+	release_resource(priv->ioarea);
+	kfree(priv->ioarea);
+out_mem:
+	kfree(priv);
+out:
+	return ret;
+}
+
+static int __devexit
+i2c_au1550_remove(struct platform_device *pdev)
 {
-	return i2c_del_adapter(adap);
+	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
+
+	platform_set_drvdata(pdev, NULL);
+	i2c_del_adapter(&priv->adap);
+	sp->psc_smbcfg = 0;
+	sp->psc_ctrl = PSC_CTRL_DISABLE;
+	au_sync();
+	release_resource(priv->ioarea);
+	kfree(priv->ioarea);
+	kfree(priv);
+	return 0;
 }
 
 static int
-pb1550_reg(struct i2c_client *client)
+i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state)
 {
+	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
+
+	sp->psc_ctrl = PSC_CTRL_SUSPEND;
+	au_sync();
 	return 0;
 }
 
 static int
-pb1550_unreg(struct i2c_client *client)
+i2c_au1550_resume(struct platform_device *pdev)
 {
+	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base;
+
+	sp->psc_ctrl = PSC_CTRL_ENABLE;
+	au_sync();
+	while (!(sp->psc_smbstat & PSC_SMBSTAT_SR))
+		au_sync();
 	return 0;
 }
 
-static struct i2c_au1550_data pb1550_i2c_info = {
-	SMBUS_PSC_BASE, 200, 200
-};
-
-static struct i2c_adapter pb1550_board_adapter = {
-	name:              "pb1550 adapter",
-	id:                I2C_HW_AU1550_PSC,
-	algo:              NULL,
-	algo_data:         &pb1550_i2c_info,
-	client_register:   pb1550_reg,
-	client_unregister: pb1550_unreg,
+static struct platform_driver au1xpsc_smbus_driver = {
+	.driver = {
+		.name	= "au1xpsc_smbus",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= i2c_au1550_probe,
+	.remove		= __devexit_p(i2c_au1550_remove),
+	.suspend	= i2c_au1550_suspend,
+	.resume		= i2c_au1550_resume,
 };
 
-/* BIG hack to support the control interface on the Wolfson WM8731
- * audio codec on the Pb1550 board.  We get an address and two data
- * bytes to write, create an i2c message, and send it across the
- * i2c transfer function.  We do this here because we have access to
- * the i2c adapter structure.
- */
-static struct i2c_msg wm_i2c_msg;  /* We don't want this stuff on the stack */
-static	u8 i2cbuf[2];
-
-int
-pb1550_wm_codec_write(u8 addr, u8 reg, u8 val)
-{
-	wm_i2c_msg.addr = addr;
-	wm_i2c_msg.flags = 0;
-	wm_i2c_msg.buf = i2cbuf;
-	wm_i2c_msg.len = 2;
-	i2cbuf[0] = reg;
-	i2cbuf[1] = val;
-
-	return pb1550_board_adapter.algo->master_xfer(&pb1550_board_adapter, &wm_i2c_msg, 1);
-}
-
 static int __init
 i2c_au1550_init(void)
 {
-	printk(KERN_INFO "Au1550 I2C: ");
-
-	/* This is where we would set up a 50MHz clock source
-	 * and routing.  On the Pb1550, the SMBus is PSC2, which
-	 * uses a shared clock with USB.  This has been already
-	 * configured by Yamon as a 48MHz clock, close enough
-	 * for our work.
-	 */
-        if (i2c_au1550_add_bus(&pb1550_board_adapter) < 0) {
-		printk("failed to initialize.\n");
-                return -ENODEV;
-	}
-
-	printk("initialized.\n");
-	return 0;
+	return platform_driver_register(&au1xpsc_smbus_driver);
 }
 
 static void __exit
 i2c_au1550_exit(void)
 {
-	i2c_au1550_del_bus(&pb1550_board_adapter);
+	platform_driver_unregister(&au1xpsc_smbus_driver);
 }
 
 MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 67224a424aba..7dbdaeb707a9 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -550,6 +550,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
 
 	p_adap = &iface->adap;
 	p_adap->id = I2C_HW_BLACKFIN;
+	p_adap->nr = dev->id;
 	strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
 	p_adap->algo = &bfin_twi_algorithm;
 	p_adap->algo_data = iface;
@@ -576,7 +577,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
 	bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
 	SSYNC();
 
-	rc = i2c_add_adapter(p_adap);
+	rc = i2c_add_numbered_adapter(p_adap);
 	if (rc < 0)
 		free_irq(iface->irq, iface);
 	else
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 67679882ebef..cce5a614758d 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -510,7 +510,6 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 
 	/* FIXME */
 	adap->timeout = 1;
-	adap->retries = 1;
 
 	adap->nr = pdev->id;
 	r = i2c_add_numbered_adapter(adap);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index ac27e5f84ebe..aa9157913b9a 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -4,6 +4,7 @@
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
     <mdsxyz123@yahoo.com>
+    Copyright (C) 2007         Jean Delvare <khali@linux-fr.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
@@ -21,25 +22,34 @@
 */
 
 /*
-    SUPPORTED DEVICES	PCI ID
-    82801AA		2413
-    82801AB		2423
-    82801BA		2443
-    82801CA/CAM		2483
-    82801DB		24C3   (HW PEC supported)
-    82801EB		24D3   (HW PEC supported)
-    6300ESB		25A4
-    ICH6		266A
-    ICH7		27DA
-    ESB2		269B
-    ICH8		283E
-    ICH9		2930
-    Tolapai		5032
-    This driver supports several versions of Intel's I/O Controller Hubs (ICH).
-    For SMBus support, they are similar to the PIIX4 and are part
-    of Intel's '810' and other chipsets.
-    See the file Documentation/i2c/busses/i2c-i801 for details.
-    I2C Block Read and Process Call are not supported.
+  Supports the following Intel I/O Controller Hubs (ICH):
+
+                                  I/O                     Block   I2C
+                                  region  SMBus   Block   proc.   block
+  Chip name             PCI ID    size    PEC     buffer  call    read
+  ----------------------------------------------------------------------
+  82801AA  (ICH)        0x2413     16      no      no      no      no
+  82801AB  (ICH0)       0x2423     16      no      no      no      no
+  82801BA  (ICH2)       0x2443     16      no      no      no      no
+  82801CA  (ICH3)       0x2483     32     soft     no      no      no
+  82801DB  (ICH4)       0x24c3     32     hard     yes     no      no
+  82801E   (ICH5)       0x24d3     32     hard     yes     yes     yes
+  6300ESB               0x25a4     32     hard     yes     yes     yes
+  82801F   (ICH6)       0x266a     32     hard     yes     yes     yes
+  6310ESB/6320ESB       0x269b     32     hard     yes     yes     yes
+  82801G   (ICH7)       0x27da     32     hard     yes     yes     yes
+  82801H   (ICH8)       0x283e     32     hard     yes     yes     yes
+  82801I   (ICH9)       0x2930     32     hard     yes     yes     yes
+  Tolapai               0x5032     32     hard     yes     ?       ?
+
+  Features supported by this driver:
+  Software PEC                     no
+  Hardware PEC                     yes
+  Block buffer                     yes
+  Block process call transaction   no
+  I2C block read transaction       yes  (doesn't use the block buffer)
+
+  See the file Documentation/i2c/busses/i2c-i801 for details.
 */
 
 /* Note: we assume there can only be one I801, with one SMBus interface */
@@ -62,9 +72,9 @@
 #define SMBHSTDAT0	(5 + i801_smba)
 #define SMBHSTDAT1	(6 + i801_smba)
 #define SMBBLKDAT	(7 + i801_smba)
-#define SMBPEC		(8 + i801_smba)	/* ICH4 only */
-#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 only */
-#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 only */
+#define SMBPEC		(8 + i801_smba)		/* ICH3 and later */
+#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 and later */
+#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 and later */
 
 /* PCI Address Constants */
 #define SMBBAR		4
@@ -91,13 +101,13 @@
 #define I801_BYTE		0x04
 #define I801_BYTE_DATA		0x08
 #define I801_WORD_DATA		0x0C
-#define I801_PROC_CALL		0x10	/* later chips only, unimplemented */
+#define I801_PROC_CALL		0x10	/* unimplemented */
 #define I801_BLOCK_DATA		0x14
-#define I801_I2C_BLOCK_DATA	0x18	/* unimplemented */
+#define I801_I2C_BLOCK_DATA	0x18	/* ICH5 and later */
 #define I801_BLOCK_LAST		0x34
-#define I801_I2C_BLOCK_LAST	0x38	/* unimplemented */
+#define I801_I2C_BLOCK_LAST	0x38	/* ICH5 and later */
 #define I801_START		0x40
-#define I801_PEC_EN		0x80	/* ICH4 only */
+#define I801_PEC_EN		0x80	/* ICH3 and later */
 
 /* I801 Hosts Status register bits */
 #define SMBHSTSTS_BYTE_DONE	0x80
@@ -113,7 +123,12 @@ static unsigned long i801_smba;
 static unsigned char i801_original_hstcfg;
 static struct pci_driver i801_driver;
 static struct pci_dev *I801_dev;
-static int isich4;
+
+#define FEATURE_SMBUS_PEC	(1 << 0)
+#define FEATURE_BLOCK_BUFFER	(1 << 1)
+#define FEATURE_BLOCK_PROC	(1 << 2)
+#define FEATURE_I2C_BLOCK_READ	(1 << 3)
+static unsigned int i801_features;
 
 static int i801_transaction(int xact)
 {
@@ -242,7 +257,8 @@ static int i801_block_transaction_by_block(union i2c_smbus_data *data,
 }
 
 static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
-					       char read_write, int hwpec)
+					       char read_write, int command,
+					       int hwpec)
 {
 	int i, len;
 	int smbcmd;
@@ -259,16 +275,24 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
 	}
 
 	for (i = 1; i <= len; i++) {
-		if (i == len && read_write == I2C_SMBUS_READ)
-			smbcmd = I801_BLOCK_LAST;
-		else
-			smbcmd = I801_BLOCK_DATA;
+		if (i == len && read_write == I2C_SMBUS_READ) {
+			if (command == I2C_SMBUS_I2C_BLOCK_DATA)
+				smbcmd = I801_I2C_BLOCK_LAST;
+			else
+				smbcmd = I801_BLOCK_LAST;
+		} else {
+			if (command == I2C_SMBUS_I2C_BLOCK_DATA
+			 && read_write == I2C_SMBUS_READ)
+				smbcmd = I801_I2C_BLOCK_DATA;
+			else
+				smbcmd = I801_BLOCK_DATA;
+		}
 		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
 
 		dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
-			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
+			"ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i,
 			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
-			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
+			inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT));
 
 		/* Make sure the SMBus host is ready to start transmitting */
 		temp = inb_p(SMBHSTSTS);
@@ -332,7 +356,8 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
 			dev_dbg(&I801_dev->dev, "Error: no response!\n");
 		}
 
-		if (i == 1 && read_write == I2C_SMBUS_READ) {
+		if (i == 1 && read_write == I2C_SMBUS_READ
+		 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
 			len = inb_p(SMBHSTDAT0);
 			if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
 				return -1;
@@ -353,9 +378,9 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
 				temp);
 		}
 		dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, "
-			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
+			"ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i,
 			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
-			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
+			inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT));
 
 		if (result < 0)
 			return result;
@@ -384,33 +409,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
 			pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
 			pci_write_config_byte(I801_dev, SMBHSTCFG,
 					      hostc | SMBHSTCFG_I2C_EN);
-		} else {
+		} else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) {
 			dev_err(&I801_dev->dev,
-				"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
+				"I2C block read is unsupported!\n");
 			return -1;
 		}
 	}
 
-	if (read_write == I2C_SMBUS_WRITE) {
+	if (read_write == I2C_SMBUS_WRITE
+	 || command == I2C_SMBUS_I2C_BLOCK_DATA) {
 		if (data->block[0] < 1)
 			data->block[0] = 1;
 		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
 			data->block[0] = I2C_SMBUS_BLOCK_MAX;
 	} else {
-		data->block[0] = 32;	/* max for reads */
+		data->block[0] = 32;	/* max for SMBus block reads */
 	}
 
-	if (isich4 && i801_set_block_buffer_mode() == 0 )
+	if ((i801_features & FEATURE_BLOCK_BUFFER)
+	 && !(command == I2C_SMBUS_I2C_BLOCK_DATA
+	      && read_write == I2C_SMBUS_READ)
+	 && i801_set_block_buffer_mode() == 0)
 		result = i801_block_transaction_by_block(data, read_write,
 							 hwpec);
 	else
 		result = i801_block_transaction_byte_by_byte(data, read_write,
-							     hwpec);
+							     command, hwpec);
 
 	if (result == 0 && hwpec)
 		i801_wait_hwpec();
 
-	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+	if (command == I2C_SMBUS_I2C_BLOCK_DATA
+	 && read_write == I2C_SMBUS_WRITE) {
 		/* restore saved configuration register value */
 		pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
 	}
@@ -426,7 +456,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
 	int block = 0;
 	int ret, xact = 0;
 
-	hwpec = isich4 && (flags & I2C_CLIENT_PEC)
+	hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
 		&& size != I2C_SMBUS_QUICK
 		&& size != I2C_SMBUS_I2C_BLOCK_DATA;
 
@@ -462,12 +492,23 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
 		xact = I801_WORD_DATA;
 		break;
 	case I2C_SMBUS_BLOCK_DATA:
-	case I2C_SMBUS_I2C_BLOCK_DATA:
 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
 		       SMBHSTADD);
 		outb_p(command, SMBHSTCMD);
 		block = 1;
 		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		/* NB: page 240 of ICH5 datasheet shows that the R/#W
+		 * bit should be cleared here, even when reading */
+		outb_p((addr & 0x7f) << 1, SMBHSTADD);
+		if (read_write == I2C_SMBUS_READ) {
+			/* NB: page 240 of ICH5 datasheet also shows
+			 * that DATA1 is the cmd field when reading */
+			outb_p(command, SMBHSTDAT1);
+		} else
+			outb_p(command, SMBHSTCMD);
+		block = 1;
+		break;
 	case I2C_SMBUS_PROC_CALL:
 	default:
 		dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
@@ -487,7 +528,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
 	/* Some BIOSes don't like it when PEC is enabled at reboot or resume
 	   time, so we forcibly disable it after every transaction. Turn off
 	   E32B for the same reason. */
-	if (hwpec)
+	if (hwpec || block)
 		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
 		       SMBAUXCTL);
 
@@ -514,9 +555,11 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
 static u32 i801_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-	    I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
-	     | (isich4 ? I2C_FUNC_SMBUS_PEC : 0);
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
+	       ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+	       ((i801_features & FEATURE_I2C_BLOCK_READ) ?
+		I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
 }
 
 static const struct i2c_algorithm smbus_algorithm = {
@@ -556,8 +599,8 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
 	int err;
 
 	I801_dev = dev;
+	i801_features = 0;
 	switch (dev->device) {
-	case PCI_DEVICE_ID_INTEL_82801DB_3:
 	case PCI_DEVICE_ID_INTEL_82801EB_3:
 	case PCI_DEVICE_ID_INTEL_ESB_4:
 	case PCI_DEVICE_ID_INTEL_ICH6_16:
@@ -565,11 +608,13 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
 	case PCI_DEVICE_ID_INTEL_ESB2_17:
 	case PCI_DEVICE_ID_INTEL_ICH8_5:
 	case PCI_DEVICE_ID_INTEL_ICH9_6:
+		i801_features |= FEATURE_I2C_BLOCK_READ;
+		/* fall through */
+	case PCI_DEVICE_ID_INTEL_82801DB_3:
 	case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
-		isich4 = 1;
+		i801_features |= FEATURE_SMBUS_PEC;
+		i801_features |= FEATURE_BLOCK_BUFFER;
 		break;
-	default:
-		isich4 = 0;
 	}
 
 	err = pci_enable_device(dev);
@@ -610,6 +655,11 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
 	else
 		dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
 
+	/* Clear special mode bits */
+	if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
+		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
+		       SMBAUXCTL);
+
 	/* set up the sysfs linkage to our parent device */
 	i801_adapter.dev.parent = &dev->dev;
 
@@ -678,9 +728,8 @@ static void __exit i2c_i801_exit(void)
 	pci_unregister_driver(&i801_driver);
 }
 
-MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
-		"Philip Edelbrock <phil@netroedge.com>, "
-		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, "
+	      "Jean Delvare <khali@linux-fr.org>");
 MODULE_DESCRIPTION("I801 SMBus driver");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 9b43ff7270d0..7c7eb0cfeceb 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -6,7 +6,7 @@
  * Copyright (c) 2003, 2004 Zultys Technologies.
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  *
- * Based on original work by 
+ * Based on original work by
  * 	Ian DaSilva  <idasilva@mvista.com>
  *      Armin Kuster <akuster@mvista.com>
  * 	Matt Porter  <mporter@mvista.com>
@@ -86,8 +86,8 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
 	       KERN_DEBUG "  sts      = 0x%02x, extsts = 0x%02x\n"
 	       KERN_DEBUG "  clkdiv   = 0x%02x, xfrcnt = 0x%02x\n"
 	       KERN_DEBUG "  xtcntlss = 0x%02x, directcntl = 0x%02x\n",
-		in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), 
-		in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), 
+		in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts),
+		in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt),
 		in_8(&iic->xtcntlss), in_8(&iic->directcntl));
 }
 #  define DUMP_REGS(h,dev)	dump_iic_regs((h),(dev))
@@ -125,7 +125,7 @@ static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable)
 {
 	out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0);
 }
- 
+
 /*
  * Initialize IIC interface.
  */
@@ -134,7 +134,7 @@ static void iic_dev_init(struct ibm_iic_private* dev)
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 
 	DBG("%d: init\n", dev->idx);
-	
+
 	/* Clear master address */
 	out_8(&iic->lmadr, 0);
 	out_8(&iic->hmadr, 0);
@@ -160,7 +160,7 @@ static void iic_dev_init(struct ibm_iic_private* dev)
 
 	/* Clear control register */
 	out_8(&iic->cntl, 0);
-	
+
 	/* Enable interrupts if possible */
 	iic_interrupt_mode(dev, dev->irq >= 0);
 
@@ -171,7 +171,7 @@ static void iic_dev_init(struct ibm_iic_private* dev)
 	DUMP_REGS("iic_init", dev);
 }
 
-/* 
+/*
  * Reset IIC interface
  */
 static void iic_dev_reset(struct ibm_iic_private* dev)
@@ -179,42 +179,42 @@ static void iic_dev_reset(struct ibm_iic_private* dev)
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 	int i;
 	u8 dc;
-	
+
 	DBG("%d: soft reset\n", dev->idx);
 	DUMP_REGS("reset", dev);
-	
+
     	/* Place chip in the reset state */
 	out_8(&iic->xtcntlss, XTCNTLSS_SRST);
-	
+
 	/* Check if bus is free */
-	dc = in_8(&iic->directcntl);	
+	dc = in_8(&iic->directcntl);
 	if (!DIRCTNL_FREE(dc)){
 		DBG("%d: trying to regain bus control\n", dev->idx);
-	
+
 		/* Try to set bus free state */
-		out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);	
-	
+		out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+
 		/* Wait until we regain bus control */
 		for (i = 0; i < 100; ++i){
 			dc = in_8(&iic->directcntl);
 			if (DIRCTNL_FREE(dc))
 				break;
-			
+
 			/* Toggle SCL line */
 			dc ^= DIRCNTL_SCC;
 			out_8(&iic->directcntl, dc);
 			udelay(10);
 			dc ^= DIRCNTL_SCC;
 			out_8(&iic->directcntl, dc);
-			
+
 			/* be nice */
 			cond_resched();
 		}
 	}
-	
+
 	/* Remove reset */
 	out_8(&iic->xtcntlss, 0);
-	
+
 	/* Reinitialize interface */
 	iic_dev_init(dev);
 }
@@ -324,14 +324,14 @@ static irqreturn_t iic_handler(int irq, void *dev_id)
 {
 	struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
-	
-	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", 
+
+	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n",
 	     dev->idx, in_8(&iic->sts), in_8(&iic->extsts));
-	
+
 	/* Acknowledge IRQ and wakeup iic_wait_for_tc */
 	out_8(&iic->sts, STS_IRQA | STS_SCMP);
 	wake_up_interruptible(&dev->wq);
-	
+
 	return IRQ_HANDLED;
 }
 
@@ -341,19 +341,19 @@ static irqreturn_t iic_handler(int irq, void *dev_id)
  */
 static int iic_xfer_result(struct ibm_iic_private* dev)
 {
-	volatile struct iic_regs __iomem *iic = dev->vaddr;	
-	
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+
 	if (unlikely(in_8(&iic->sts) & STS_ERR)){
-		DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx, 
+		DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx,
 			in_8(&iic->extsts));
-				
+
 		/* Clear errors and possible pending IRQs */
-		out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | 
+		out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD |
 			EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA);
-			
+
 		/* Flush master data buffer */
 		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
-		
+
 		/* Is bus free?
 		 * If error happened during combined xfer
 		 * IIC interface is usually stuck in some strange
@@ -376,11 +376,11 @@ static void iic_abort_xfer(struct ibm_iic_private* dev)
 {
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 	unsigned long x;
-	
+
 	DBG("%d: iic_abort_xfer\n", dev->idx);
-	
+
 	out_8(&iic->cntl, CNTL_HMT);
-	
+
 	/*
 	 * Wait for the abort command to complete.
 	 * It's not worth to be optimized, just poll (timeout >= 1 tick)
@@ -405,13 +405,13 @@ static void iic_abort_xfer(struct ibm_iic_private* dev)
  * Returns the number of transferred bytes or error (<0)
  */
 static int iic_wait_for_tc(struct ibm_iic_private* dev){
-	
+
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 	int ret = 0;
-	
+
 	if (dev->irq >= 0){
 		/* Interrupt mode */
-		ret = wait_event_interruptible_timeout(dev->wq, 
+		ret = wait_event_interruptible_timeout(dev->wq,
 			!(in_8(&iic->sts) & STS_PT), dev->adap.timeout * HZ);
 
 		if (unlikely(ret < 0))
@@ -424,37 +424,37 @@ static int iic_wait_for_tc(struct ibm_iic_private* dev){
 	else {
 		/* Polling mode */
 		unsigned long x = jiffies + dev->adap.timeout * HZ;
-		
+
 		while (in_8(&iic->sts) & STS_PT){
 			if (unlikely(time_after(jiffies, x))){
 				DBG("%d: poll timeout\n", dev->idx);
 				ret = -ETIMEDOUT;
 				break;
 			}
-		
+
 			if (unlikely(signal_pending(current))){
 				DBG("%d: poll interrupted\n", dev->idx);
 				ret = -ERESTARTSYS;
 				break;
 			}
 			schedule();
-		}	
+		}
 	}
-	
+
 	if (unlikely(ret < 0))
 		iic_abort_xfer(dev);
 	else
 		ret = iic_xfer_result(dev);
-	
+
 	DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret);
-	
+
 	return ret;
 }
 
 /*
  * Low level master transfer routine
  */
-static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, 
+static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
 			  int combined_xfer)
 {
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
@@ -465,48 +465,48 @@ static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
 	u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT;
 	if (pm->flags & I2C_M_RD)
 		cntl |= CNTL_RW;
-	
+
 	loops = (len + 3) / 4;
 	for (i = 0; i < loops; ++i, len -= 4){
 		int count = len > 4 ? 4 : len;
 		u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT);
-		
+
 		if (!(cntl & CNTL_RW))
 			for (j = 0; j < count; ++j)
 				out_8((void __iomem *)&iic->mdbuf, *buf++);
-		
+
 		if (i < loops - 1)
 			cmd |= CNTL_CHT;
 		else if (combined_xfer)
 			cmd |= CNTL_RPST;
-		
+
 		DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd);
-		
+
 		/* Start transfer */
 		out_8(&iic->cntl, cmd);
-		
+
 		/* Wait for completion */
 		ret = iic_wait_for_tc(dev);
 
 		if (unlikely(ret < 0))
 			break;
 		else if (unlikely(ret != count)){
-			DBG("%d: xfer_bytes, requested %d, transfered %d\n", 
+			DBG("%d: xfer_bytes, requested %d, transfered %d\n",
 				dev->idx, count, ret);
-			
+
 			/* If it's not a last part of xfer, abort it */
 			if (combined_xfer || (i < loops - 1))
     				iic_abort_xfer(dev);
-				
+
 			ret = -EREMOTEIO;
-			break;				
+			break;
 		}
-		
+
 		if (cntl & CNTL_RW)
 			for (j = 0; j < count; ++j)
 				*buf++ = in_8((void __iomem *)&iic->mdbuf);
 	}
-	
+
 	return ret > 0 ? 0 : ret;
 }
 
@@ -517,10 +517,10 @@ static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg)
 {
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 	u16 addr = msg->addr;
-	
-	DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, 
+
+	DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx,
 		addr, msg->flags & I2C_M_TEN ? 10 : 7);
-	
+
 	if (msg->flags & I2C_M_TEN){
 	    out_8(&iic->cntl, CNTL_AMD);
 	    out_8(&iic->lmadr, addr);
@@ -537,15 +537,15 @@ static inline int iic_invalid_address(const struct i2c_msg* p)
 	return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f));
 }
 
-static inline int iic_address_neq(const struct i2c_msg* p1, 
+static inline int iic_address_neq(const struct i2c_msg* p1,
 				  const struct i2c_msg* p2)
 {
-	return (p1->addr != p2->addr) 
+	return (p1->addr != p2->addr)
 		|| ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN));
-} 
+}
 
 /*
- * Generic master transfer entrypoint. 
+ * Generic master transfer entrypoint.
  * Returns the number of processed messages or error (<0)
  */
 static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
@@ -553,20 +553,20 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
     	struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap));
 	volatile struct iic_regs __iomem *iic = dev->vaddr;
 	int i, ret = 0;
-	
+
 	DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num);
-	
+
 	if (!num)
 		return 0;
-	
+
 	/* Check the sanity of the passed messages.
 	 * Uhh, generic i2c layer is more suitable place for such code...
 	 */
 	if (unlikely(iic_invalid_address(&msgs[0]))){
-		DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx, 
+		DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx,
 			msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7);
 		return -EINVAL;
-	}		
+	}
 	for (i = 0; i < num; ++i){
 		if (unlikely(msgs[i].len <= 0)){
 			if (num == 1 && !msgs[0].len){
@@ -576,7 +576,7 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 				 */
 				return iic_smbus_quick(dev, &msgs[0]);
 			}
-			DBG("%d: invalid len %d in msg[%d]\n", dev->idx, 
+			DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
 				msgs[i].len, i);
 			return -EINVAL;
 		}
@@ -585,34 +585,34 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 			return -EINVAL;
 		}
 	}
-	
+
 	/* Check bus state */
 	if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){
 		DBG("%d: iic_xfer, bus is not free\n", dev->idx);
-		
+
 		/* Usually it means something serious has happend.
 		 * We *cannot* have unfinished previous transfer
 		 * so it doesn't make any sense to try to stop it.
-		 * Probably we were not able to recover from the 
+		 * Probably we were not able to recover from the
 		 * previous error.
 		 * The only *reasonable* thing I can think of here
 		 * is soft reset.  --ebs
 		 */
 		iic_dev_reset(dev);
-		
+
 		if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
 			DBG("%d: iic_xfer, bus is still not free\n", dev->idx);
 			return -EREMOTEIO;
 		}
-	} 
+	}
 	else {
 		/* Flush master data buffer (just in case) */
 		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
 	}
-	
+
 	/* Load slave address */
 	iic_address(dev, &msgs[0]);
-	
+
 	/* Do real transfer */
     	for (i = 0; i < num && !ret; ++i)
 		ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1);
@@ -648,7 +648,7 @@ static inline u8 iic_clckdiv(unsigned int opb)
 
 	/* Convert to MHz */
 	opb /= 1000000;
-	
+
 	if (opb < 20 || opb > 150){
 		printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n",
 			opb);
@@ -666,7 +666,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
 	struct i2c_adapter* adap;
 	struct ocp_func_iic_data* iic_data = ocp->def->additions;
 	int ret;
-	
+
 	if (!iic_data)
 		printk(KERN_WARNING"ibm-iic%d: missing additional data!\n",
 			ocp->def->index);
@@ -679,7 +679,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
 
 	dev->idx = ocp->def->index;
 	ocp_set_drvdata(ocp, dev);
-	
+
 	if (!request_mem_region(ocp->def->paddr, sizeof(struct iic_regs),
 				"ibm_iic")) {
 		ret = -EBUSY;
@@ -692,7 +692,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
 		ret = -ENXIO;
 		goto fail2;
 	}
-	
+
 	init_waitqueue_head(&dev->wq);
 
 	dev->irq = iic_force_poll ? -1 : ocp->def->irq;
@@ -702,29 +702,29 @@ static int __devinit iic_probe(struct ocp_device *ocp){
 		 */
 		iic_interrupt_mode(dev, 0);
 		if (request_irq(dev->irq, iic_handler, 0, "IBM IIC", dev)){
-			printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n", 
+			printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n",
 				dev->idx, dev->irq);
-			/* Fallback to the polling mode */	
+			/* Fallback to the polling mode */
 			dev->irq = -1;
 		}
 	}
-	
+
 	if (dev->irq < 0)
-		printk(KERN_WARNING "ibm-iic%d: using polling mode\n", 
+		printk(KERN_WARNING "ibm-iic%d: using polling mode\n",
 			dev->idx);
-		
+
 	/* Board specific settings */
 	dev->fast_mode = iic_force_fast ? 1 : (iic_data ? iic_data->fast_mode : 0);
-	
-	/* clckdiv is the same for *all* IIC interfaces, 
+
+	/* clckdiv is the same for *all* IIC interfaces,
 	 * but I'd rather make a copy than introduce another global. --ebs
 	 */
 	dev->clckdiv = iic_clckdiv(ocp_sys_info.opb_bus_freq);
 	DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
-	
+
 	/* Initialize IIC interface */
 	iic_dev_init(dev);
-	
+
 	/* Register it with i2c layer */
 	adap = &dev->adap;
 	adap->dev.parent = &ocp->dev;
@@ -736,7 +736,6 @@ static int __devinit iic_probe(struct ocp_device *ocp){
 	adap->client_register = NULL;
 	adap->client_unregister = NULL;
 	adap->timeout = 1;
-	adap->retries = 1;
 
 	/*
 	 * If "dev->idx" is negative we consider it as zero.
@@ -750,24 +749,24 @@ static int __devinit iic_probe(struct ocp_device *ocp){
 			dev->idx);
 		goto fail;
 	}
-	
+
 	printk(KERN_INFO "ibm-iic%d: using %s mode\n", dev->idx,
 		dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
 
 	return 0;
 
-fail:	
+fail:
 	if (dev->irq >= 0){
 		iic_interrupt_mode(dev, 0);
 		free_irq(dev->irq, dev);
-	}	
+	}
 
 	iounmap(dev->vaddr);
-fail2:	
+fail2:
 	release_mem_region(ocp->def->paddr, sizeof(struct iic_regs));
 fail1:
 	ocp_set_drvdata(ocp, NULL);
-	kfree(dev);	
+	kfree(dev);
 	return ret;
 }
 
@@ -783,13 +782,13 @@ static void __devexit iic_remove(struct ocp_device *ocp)
 			dev->idx);
 		/* That's *very* bad, just shutdown IRQ ... */
 		if (dev->irq >= 0){
-		    iic_interrupt_mode(dev, 0);	
+		    iic_interrupt_mode(dev, 0);
 		    free_irq(dev->irq, dev);
 		    dev->irq = -1;
 		}
 	} else {
 		if (dev->irq >= 0){
-		    iic_interrupt_mode(dev, 0);	
+		    iic_interrupt_mode(dev, 0);
 		    free_irq(dev->irq, dev);
 		}
 		iounmap(dev->vaddr);
@@ -798,7 +797,7 @@ static void __devexit iic_remove(struct ocp_device *ocp)
 	}
 }
 
-static struct ocp_device_id ibm_iic_ids[] __devinitdata = 
+static struct ocp_device_id ibm_iic_ids[] __devinitdata =
 {
 	{ .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IIC },
 	{ .vendor = OCP_VENDOR_INVALID }
diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h
index 59d7b437f7ff..fdaa48292cb6 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.h
+++ b/drivers/i2c/busses/i2c-ibm_iic.h
@@ -2,11 +2,11 @@
  * drivers/i2c/busses/i2c-ibm_iic.h
  *
  * Support for the IIC peripheral on IBM PPC 4xx
- * 
+ *
  * Copyright (c) 2003 Zultys Technologies.
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  *
- * Based on original work by 
+ * Based on original work by
  * 	Ian DaSilva  <idasilva@mvista.com>
  *      Armin Kuster <akuster@mvista.com>
  * 	Matt Porter  <mporter@mvista.com>
@@ -22,7 +22,7 @@
 #ifndef __I2C_IBM_IIC_H_
 #define __I2C_IBM_IIC_H_
 
-#include <linux/i2c.h> 
+#include <linux/i2c.h>
 
 struct iic_regs {
 	u16 mdbuf;
@@ -58,7 +58,7 @@ struct ibm_iic_private {
 #define CNTL_TCT_MASK	0x30
 #define CNTL_TCT_SHIFT	4
 #define CNTL_RPST	0x08
-#define CNTL_CHT	0x04 
+#define CNTL_CHT	0x04
 #define CNTL_RW		0x02
 #define CNTL_PT		0x01
 
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index c70146e4c2c0..ab41400c883e 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -490,7 +490,6 @@ iop3xx_i2c_probe(struct platform_device *pdev)
 	 * Default values...should these come in from board code?
 	 */
 	new_adapter->timeout = 100;	
-	new_adapter->retries = 3;
 	new_adapter->algo = &iop3xx_i2c_algo;
 
 	init_waitqueue_head(&adapter_data->waitq);
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
deleted file mode 100644
index 069ed7f3b395..000000000000
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * drivers/i2c/busses/i2c-ixp4xx.c
- *
- * Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have
- * an on board I2C controller but provide 16 GPIO pins that are often
- * used to create an I2C bus. This driver provides an i2c_adapter 
- * interface that plugs in under algo_bit and drives the GPIO pins
- * as instructed by the alogorithm driver.
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (c) 2003-2004 MontaVista Software Inc.
- *
- * This file is licensed under the terms of the GNU General Public 
- * License version 2. This program is licensed "as is" without any 
- * warranty of any kind, whether express or implied.
- *
- * NOTE: Since different platforms will use different GPIO pins for
- *       I2C, this driver uses an IXP4xx-specific platform_data
- *       pointer to pass the GPIO numbers to the driver. This 
- *       allows us to support all the different IXP4xx platforms
- *       w/o having to put #ifdefs in this driver.
- *
- *       See arch/arm/mach-ixp4xx/ixdp425.c for an example of building a 
- *       device list and filling in the ixp4xx_i2c_pins data structure 
- *       that is passed as the platform_data to this driver.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include <asm/hardware.h>	/* Pick up IXP4xx-specific bits */
-
-static inline int ixp4xx_scl_pin(void *data)
-{
-	return ((struct ixp4xx_i2c_pins*)data)->scl_pin;
-}
-
-static inline int ixp4xx_sda_pin(void *data)
-{
-	return ((struct ixp4xx_i2c_pins*)data)->sda_pin;
-}
-
-static void ixp4xx_bit_setscl(void *data, int val)
-{
-	gpio_line_set(ixp4xx_scl_pin(data), 0);
-	gpio_line_config(ixp4xx_scl_pin(data),
-		val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT );
-}
-
-static void ixp4xx_bit_setsda(void *data, int val)
-{
-	gpio_line_set(ixp4xx_sda_pin(data), 0);
-	gpio_line_config(ixp4xx_sda_pin(data),
-		val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT );
-}
-
-static int ixp4xx_bit_getscl(void *data)
-{
-	int scl;
-
-	gpio_line_config(ixp4xx_scl_pin(data), IXP4XX_GPIO_IN );
-	gpio_line_get(ixp4xx_scl_pin(data), &scl);
-
-	return scl;
-}	
-
-static int ixp4xx_bit_getsda(void *data)
-{
-	int sda;
-
-	gpio_line_config(ixp4xx_sda_pin(data), IXP4XX_GPIO_IN );
-	gpio_line_get(ixp4xx_sda_pin(data), &sda);
-
-	return sda;
-}	
-
-struct ixp4xx_i2c_data {
-	struct ixp4xx_i2c_pins *gpio_pins;
-	struct i2c_adapter adapter;
-	struct i2c_algo_bit_data algo_data;
-};
-
-static int ixp4xx_i2c_remove(struct platform_device *plat_dev)
-{
-	struct ixp4xx_i2c_data *drv_data = platform_get_drvdata(plat_dev);
-
-	platform_set_drvdata(plat_dev, NULL);
-
-	i2c_del_adapter(&drv_data->adapter);
-
-	kfree(drv_data);
-
-	return 0;
-}
-
-static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
-{
-	int err;
-	struct ixp4xx_i2c_pins *gpio = plat_dev->dev.platform_data;
-	struct ixp4xx_i2c_data *drv_data = 
-		kzalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL);
-
-	if(!drv_data)
-		return -ENOMEM;
-
-	drv_data->gpio_pins = gpio;
-
-	/*
-	 * We could make a lot of these structures static, but
-	 * certain platforms may have multiple GPIO-based I2C
-	 * buses for various device domains, so we need per-device
-	 * algo_data->data. 
-	 */
-	drv_data->algo_data.data = gpio;
-	drv_data->algo_data.setsda = ixp4xx_bit_setsda;
-	drv_data->algo_data.setscl = ixp4xx_bit_setscl;
-	drv_data->algo_data.getsda = ixp4xx_bit_getsda;
-	drv_data->algo_data.getscl = ixp4xx_bit_getscl;
-	drv_data->algo_data.udelay = 10;
-	drv_data->algo_data.timeout = 100;
-
-	drv_data->adapter.id = I2C_HW_B_IXP4XX;
-	drv_data->adapter.class = I2C_CLASS_HWMON;
-	strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
-		sizeof(drv_data->adapter.name));
-	drv_data->adapter.algo_data = &drv_data->algo_data;
-
-	drv_data->adapter.dev.parent = &plat_dev->dev;
-
-	gpio_line_config(gpio->scl_pin, IXP4XX_GPIO_IN);
-	gpio_line_config(gpio->sda_pin, IXP4XX_GPIO_IN);
-	gpio_line_set(gpio->scl_pin, 0);
-	gpio_line_set(gpio->sda_pin, 0);
-
-	err = i2c_bit_add_bus(&drv_data->adapter);
-	if (err) {
-		printk(KERN_ERR "ERROR: Could not install %s\n", plat_dev->dev.bus_id);
-
-		kfree(drv_data);
-		return err;
-	}
-
-	platform_set_drvdata(plat_dev, drv_data);
-
-	return 0;
-}
-
-static struct platform_driver ixp4xx_i2c_driver = {
-	.probe		= ixp4xx_i2c_probe,
-	.remove		= ixp4xx_i2c_remove,
-	.driver		= {
-		.name	= "IXP4XX-I2C",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init ixp4xx_i2c_init(void)
-{
-	return platform_driver_register(&ixp4xx_i2c_driver);
-}
-
-static void __exit ixp4xx_i2c_exit(void)
-{
-	platform_driver_unregister(&ixp4xx_i2c_driver);
-}
-
-module_init(ixp4xx_i2c_init);
-module_exit(ixp4xx_i2c_exit);
-
-MODULE_DESCRIPTION("GPIO-based I2C adapter for IXP4xx systems");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
-
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index d8de4ac88b7d..bbe787b243b7 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -180,7 +180,7 @@ static void mpc_i2c_stop(struct mpc_i2c *i2c)
 static int mpc_write(struct mpc_i2c *i2c, int target,
 		     const u8 * data, int length, int restart)
 {
-	int i;
+	int i, result;
 	unsigned timeout = i2c->adap.timeout;
 	u32 flags = restart ? CCR_RSTA : 0;
 
@@ -192,15 +192,17 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
 	/* Write target byte */
 	writeb((target << 1), i2c->base + MPC_I2C_DR);
 
-	if (i2c_wait(i2c, timeout, 1) < 0)
-		return -1;
+	result = i2c_wait(i2c, timeout, 1);
+	if (result < 0)
+		return result;
 
 	for (i = 0; i < length; i++) {
 		/* Write data byte */
 		writeb(data[i], i2c->base + MPC_I2C_DR);
 
-		if (i2c_wait(i2c, timeout, 1) < 0)
-			return -1;
+		result = i2c_wait(i2c, timeout, 1);
+		if (result < 0)
+			return result;
 	}
 
 	return 0;
@@ -210,7 +212,7 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
 		    u8 * data, int length, int restart)
 {
 	unsigned timeout = i2c->adap.timeout;
-	int i;
+	int i, result;
 	u32 flags = restart ? CCR_RSTA : 0;
 
 	/* Start with MEN */
@@ -221,8 +223,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
 	/* Write target address byte - this time with the read flag set */
 	writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
 
-	if (i2c_wait(i2c, timeout, 1) < 0)
-		return -1;
+	result = i2c_wait(i2c, timeout, 1);
+	if (result < 0)
+		return result;
 
 	if (length) {
 		if (length == 1)
@@ -234,8 +237,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
 	}
 
 	for (i = 0; i < length; i++) {
-		if (i2c_wait(i2c, timeout, 0) < 0)
-			return -1;
+		result = i2c_wait(i2c, timeout, 0);
+		if (result < 0)
+			return result;
 
 		/* Generate txack on next to last byte */
 		if (i == length - 2)
@@ -309,7 +313,6 @@ static struct i2c_adapter mpc_ops = {
 	.algo = &mpc_algo,
 	.class = I2C_CLASS_HWMON,
 	.timeout = 1,
-	.retries = 1
 };
 
 static int fsl_i2c_probe(struct platform_device *pdev)
@@ -321,9 +324,9 @@ static int fsl_i2c_probe(struct platform_device *pdev)
 
 	pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
 
-	if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) {
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
-	}
 
 	i2c->irq = platform_get_irq(pdev, 0);
 	if (i2c->irq < 0) {
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index bb7bf68a7fb6..036e6a883e67 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -1,6 +1,6 @@
 /*
- * Driver for the i2c controller on the Marvell line of host bridges for MIPS
- * and PPC (e.g, gt642[46]0, mv643[46]0, mv644[46]0).
+ * Driver for the i2c controller on the Marvell line of host bridges
+ * (e.g, gt642[46]0, mv643[46]0, mv644[46]0, and Orion SoC family).
  *
  * Author: Mark A. Greer <mgreer@mvista.com>
  *
@@ -14,7 +14,7 @@
 #include <linux/spinlock.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
-#include <linux/mv643xx.h>
+#include <linux/mv643xx_i2c.h>
 #include <linux/platform_device.h>
 
 #include <asm/io.h>
@@ -86,6 +86,7 @@ struct mv64xxx_i2c_data {
 	u32			cntl_bits;
 	void __iomem		*reg_base;
 	u32			reg_base_p;
+	u32			reg_size;
 	u32			addr1;
 	u32			addr2;
 	u32			bytes_left;
@@ -463,17 +464,20 @@ static int __devinit
 mv64xxx_i2c_map_regs(struct platform_device *pd,
 	struct mv64xxx_i2c_data *drv_data)
 {
-	struct resource	*r;
+	int size;
+	struct resource	*r = platform_get_resource(pd, IORESOURCE_MEM, 0);
 
-	if ((r = platform_get_resource(pd, IORESOURCE_MEM, 0)) &&
-		request_mem_region(r->start, MV64XXX_I2C_REG_BLOCK_SIZE,
-			drv_data->adapter.name)) {
+	if (!r)
+		return -ENODEV;
 
-		drv_data->reg_base = ioremap(r->start,
-			MV64XXX_I2C_REG_BLOCK_SIZE);
-		drv_data->reg_base_p = r->start;
-	} else
-		return -ENOMEM;
+	size = r->end - r->start + 1;
+
+	if (!request_mem_region(r->start, size, drv_data->adapter.name))
+		return -EBUSY;
+
+	drv_data->reg_base = ioremap(r->start, size);
+	drv_data->reg_base_p = r->start;
+	drv_data->reg_size = size;
 
 	return 0;
 }
@@ -483,8 +487,7 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
 {
 	if (drv_data->reg_base) {
 		iounmap(drv_data->reg_base);
-		release_mem_region(drv_data->reg_base_p,
-			MV64XXX_I2C_REG_BLOCK_SIZE);
+		release_mem_region(drv_data->reg_base_p, drv_data->reg_size);
 	}
 
 	drv_data->reg_base = NULL;
@@ -529,7 +532,6 @@ mv64xxx_i2c_probe(struct platform_device *pd)
 	drv_data->adapter.owner = THIS_MODULE;
 	drv_data->adapter.class = I2C_CLASS_HWMON;
 	drv_data->adapter.timeout = pdata->timeout;
-	drv_data->adapter.retries = pdata->retries;
 	drv_data->adapter.nr = pd->id;
 	platform_set_drvdata(pd, drv_data);
 	i2c_set_adapdata(&drv_data->adapter, drv_data);
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 1bf590c74166..3dac920e53ea 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -351,6 +351,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
 	pci_set_drvdata(dev, smbuses);
 
 	switch(dev->device) {
+	case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS:
 	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
 	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
 		smbuses[0].blockops = 1;
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index f2552b19ea60..da6639707ea3 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -362,8 +362,6 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
 	omap_i2c_enable_clocks(dev);
 
-	/* REVISIT: initialize and use adap->retries. This is an optional
-	 * feature */
 	if ((r = omap_i2c_wait_for_bb(dev)) < 0)
 		goto out;
 
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index ca18e0be4901..1603c81e39d4 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -368,6 +368,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
 	smbus->adapter.class = I2C_CLASS_HWMON;
 	smbus->adapter.algo = &smbus_algorithm;
 	smbus->adapter.algo_data = smbus;
+	smbus->adapter.nr = PCI_FUNC(dev->devfn);
 
 	/* set up the sysfs linkage to our parent device */
 	smbus->adapter.dev.parent = &dev->dev;
@@ -375,7 +376,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
 	reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
 		  (CLK_100K_DIV & CTL_CLK_M)));
 
-	error = i2c_add_adapter(&smbus->adapter);
+	error = i2c_add_numbered_adapter(&smbus->adapter);
 	if (error)
 		goto out_release_region;
 
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 167e4137ee21..9bbe96cef719 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -121,10 +121,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 {
 	unsigned char temp;
 
-	/* match up the function */
-	if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data)
-		return -ENODEV;
-
 	dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev));
 
 	/* Don't access SMBus on IBM systems which get corrupted eeproms */
@@ -389,28 +385,21 @@ static struct i2c_adapter piix4_adapter = {
 };
 
 static struct pci_device_id piix4_ids[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3),
-	  .driver_data = 3 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3),
-	  .driver_data = 3 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3),
-	  .driver_data = 0 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_OSB4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_CSB5) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_CSB6) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_HT1000SB) },
 	{ 0, }
 };
 
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 6426a61f8d4d..2598d29fd7a4 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -65,6 +65,7 @@ struct pxa_i2c {
 	unsigned long		iosize;
 
 	int			irq;
+	int			use_pio;
 };
 
 #define _IBMR(i2c)	((i2c)->reg_base + 0)
@@ -163,6 +164,7 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
 #define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0)
 
 static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id);
 
 static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
 {
@@ -554,6 +556,71 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
 	writel(icr, _ICR(i2c));
 }
 
+static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c)
+{
+	/* make timeout the same as for interrupt based functions */
+	long timeout = 2 * DEF_TIMEOUT;
+
+	/*
+	 * Wait for the bus to become free.
+	 */
+	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+		udelay(1000);
+		show_state(i2c);
+	}
+
+	if (timeout <= 0) {
+		show_state(i2c);
+		dev_err(&i2c->adap.dev,
+			"i2c_pxa: timeout waiting for bus free\n");
+		return I2C_RETRY;
+	}
+
+	/*
+	 * Set master mode.
+	 */
+	writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
+
+	return 0;
+}
+
+static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
+			       struct i2c_msg *msg, int num)
+{
+	unsigned long timeout = 500000; /* 5 seconds */
+	int ret = 0;
+
+	ret = i2c_pxa_pio_set_master(i2c);
+	if (ret)
+		goto out;
+
+	i2c->msg = msg;
+	i2c->msg_num = num;
+	i2c->msg_idx = 0;
+	i2c->msg_ptr = 0;
+	i2c->irqlogidx = 0;
+
+	i2c_pxa_start_message(i2c);
+
+	while (timeout-- && i2c->msg_num > 0) {
+		i2c_pxa_handler(0, i2c);
+		udelay(10);
+	}
+
+	i2c_pxa_stop_message(i2c);
+
+	/*
+	 * We place the return code in i2c->msg_idx.
+	 */
+	ret = i2c->msg_idx;
+
+out:
+	if (timeout == 0)
+		i2c_pxa_scream_blue_murder(i2c, "timeout");
+
+	return ret;
+}
+
 /*
  * We are protected by the adapter bus mutex.
  */
@@ -610,6 +677,35 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
 	return ret;
 }
 
+static int i2c_pxa_pio_xfer(struct i2c_adapter *adap,
+			    struct i2c_msg msgs[], int num)
+{
+	struct pxa_i2c *i2c = adap->algo_data;
+	int ret, i;
+
+	/* If the I2C controller is disabled we need to reset it
+	  (probably due to a suspend/resume destroying state). We do
+	  this here as we can then avoid worrying about resuming the
+	  controller before its users. */
+	if (!(readl(_ICR(i2c)) & ICR_IUE))
+		i2c_pxa_reset(i2c);
+
+	for (i = adap->retries; i >= 0; i--) {
+		ret = i2c_pxa_do_pio_xfer(i2c, msgs, num);
+		if (ret != I2C_RETRY)
+			goto out;
+
+		if (i2c_debug)
+			dev_dbg(&adap->dev, "Retrying transmission\n");
+		udelay(100);
+	}
+	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+	ret = -EREMOTEIO;
+ out:
+	i2c_pxa_set_slave(i2c, ret);
+	return ret;
+}
+
 /*
  * i2c_pxa_master_complete - complete the message and wake up.
  */
@@ -621,7 +717,8 @@ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret)
 	i2c->msg_num = 0;
 	if (ret)
 		i2c->msg_idx = ret;
-	wake_up(&i2c->wait);
+	if (!i2c->use_pio)
+		wake_up(&i2c->wait);
 }
 
 static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
@@ -840,6 +937,37 @@ static const struct i2c_algorithm i2c_pxa_algorithm = {
 	.functionality	= i2c_pxa_functionality,
 };
 
+static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
+	.master_xfer	= i2c_pxa_pio_xfer,
+	.functionality	= i2c_pxa_functionality,
+};
+
+static void i2c_pxa_enable(struct platform_device *dev)
+{
+	if (cpu_is_pxa27x()) {
+		switch (dev->id) {
+		case 0:
+			pxa_gpio_mode(GPIO117_I2CSCL_MD);
+			pxa_gpio_mode(GPIO118_I2CSDA_MD);
+			break;
+		case 1:
+			local_irq_disable();
+			PCFR |= PCFR_PI2CEN;
+			local_irq_enable();
+			break;
+		}
+	}
+}
+
+static void i2c_pxa_disable(struct platform_device *dev)
+{
+	if (cpu_is_pxa27x() && dev->id == 1) {
+		local_irq_disable();
+		PCFR &= ~PCFR_PI2CEN;
+		local_irq_enable();
+	}
+}
+
 #define res_len(r)		((r)->end - (r)->start + 1)
 static int i2c_pxa_probe(struct platform_device *dev)
 {
@@ -864,7 +992,6 @@ static int i2c_pxa_probe(struct platform_device *dev)
 	}
 
 	i2c->adap.owner   = THIS_MODULE;
-	i2c->adap.algo    = &i2c_pxa_algorithm;
 	i2c->adap.retries = 5;
 
 	spin_lock_init(&i2c->lock);
@@ -899,34 +1026,28 @@ static int i2c_pxa_probe(struct platform_device *dev)
 #endif
 
 	clk_enable(i2c->clk);
-#ifdef CONFIG_PXA27x
-	switch (dev->id) {
-	case 0:
-		pxa_gpio_mode(GPIO117_I2CSCL_MD);
-		pxa_gpio_mode(GPIO118_I2CSDA_MD);
-		break;
-	case 1:
-		local_irq_disable();
-		PCFR |= PCFR_PI2CEN;
-		local_irq_enable();
-	}
-#endif
+	i2c_pxa_enable(dev);
 
-	ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
-			  i2c->adap.name, i2c);
-	if (ret)
-		goto ereqirq;
+	if (plat) {
+		i2c->adap.class = plat->class;
+		i2c->use_pio = plat->use_pio;
+	}
 
+	if (i2c->use_pio) {
+		i2c->adap.algo = &i2c_pxa_pio_algorithm;
+	} else {
+		i2c->adap.algo = &i2c_pxa_algorithm;
+		ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
+				  i2c->adap.name, i2c);
+		if (ret)
+			goto ereqirq;
+	}
 
 	i2c_pxa_reset(i2c);
 
 	i2c->adap.algo_data = i2c;
 	i2c->adap.dev.parent = &dev->dev;
 
-	if (plat) {
-		i2c->adap.class = plat->class;
-	}
-
 	/*
 	 * If "dev->id" is negative we consider it as zero.
 	 * The reason to do so is to avoid sysfs names that only make
@@ -952,17 +1073,11 @@ static int i2c_pxa_probe(struct platform_device *dev)
 	return 0;
 
 eadapt:
-	free_irq(irq, i2c);
+	if (!i2c->use_pio)
+		free_irq(irq, i2c);
 ereqirq:
 	clk_disable(i2c->clk);
-
-#ifdef CONFIG_PXA27x
-	if (dev->id == 1) {
-		local_irq_disable();
-		PCFR &= ~PCFR_PI2CEN;
-		local_irq_enable();
-	}
-#endif
+	i2c_pxa_disable(dev);
 eremap:
 	clk_put(i2c->clk);
 eclk:
@@ -979,18 +1094,12 @@ static int i2c_pxa_remove(struct platform_device *dev)
 	platform_set_drvdata(dev, NULL);
 
 	i2c_del_adapter(&i2c->adap);
-	free_irq(i2c->irq, i2c);
+	if (!i2c->use_pio)
+		free_irq(i2c->irq, i2c);
 
 	clk_disable(i2c->clk);
 	clk_put(i2c->clk);
-
-#ifdef CONFIG_PXA27x
-	if (dev->id == 1) {
-		local_irq_disable();
-		PCFR &= ~PCFR_PI2CEN;
-		local_irq_enable();
-	}
-#endif
+	i2c_pxa_disable(dev);
 
 	release_mem_region(i2c->iobase, i2c->iosize);
 	kfree(i2c);
diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
index 503a134ec803..8fbbdb4c2f35 100644
--- a/drivers/i2c/busses/i2c-sibyte.c
+++ b/drivers/i2c/busses/i2c-sibyte.c
@@ -36,14 +36,6 @@ struct i2c_algo_sibyte_data {
 /* ----- global defines ----------------------------------------------- */
 #define SMB_CSR(a,r) ((long)(a->reg_base + r))
 
-/* ----- global variables --------------------------------------------- */
-
-/* module parameters:
- */
-static int bit_scan;	/* have a look at what's hanging 'round */
-module_param(bit_scan, int, 0);
-MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
-
 
 static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
 		      unsigned short flags, char read_write,
@@ -140,9 +132,8 @@ static const struct i2c_algorithm i2c_sibyte_algo = {
 /*
  * registering functions to load algorithms at runtime
  */
-int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
 {
-	int i;
 	struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
 
 	/* register new adapter to i2c module... */
@@ -152,24 +143,6 @@ int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
 	csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
 	csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
 
-	/* scan bus */
-	if (bit_scan) {
-		union i2c_smbus_data data;
-		int rc;
-		printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
-		       i2c_adap->name);
-		for (i = 0x00; i < 0x7f; i++) {
-			/* XXXKW is this a realistic probe? */
-			rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
-					I2C_SMBUS_BYTE_DATA, &data);
-			if (!rc) {
-				printk("(%02x)",i);
-			} else
-				printk(".");
-		}
-		printk("\n");
-	}
-
 	return i2c_add_adapter(i2c_adap);
 }
 
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index 84df29da1ddc..c2a9f8c94f5e 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -1,8 +1,8 @@
 /*
-    i2c-stub.c - Part of lm_sensors, Linux kernel modules for hardware
-              monitoring
+    i2c-stub.c - I2C/SMBus chip emulator
 
     Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
+    Copyright (C) 2007 Jean Delvare <khali@linux-fr.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
@@ -37,8 +37,8 @@ MODULE_PARM_DESC(chip_addr,
 
 struct stub_chip {
 	u8 pointer;
-	u8 bytes[256];
-	u16 words[256];
+	u16 words[256];		/* Byte operations use the LSB as per SMBus
+				   specification */
 };
 
 static struct stub_chip *stub_chips;
@@ -75,7 +75,7 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
 					"wrote 0x%02x.\n",
 					addr, command);
 		} else {
-			data->byte = chip->bytes[chip->pointer++];
+			data->byte = chip->words[chip->pointer++] & 0xff;
 			dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
 					"read  0x%02x.\n",
 					addr, data->byte);
@@ -86,12 +86,13 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
 
 	case I2C_SMBUS_BYTE_DATA:
 		if (read_write == I2C_SMBUS_WRITE) {
-			chip->bytes[command] = data->byte;
+			chip->words[command] &= 0xff00;
+			chip->words[command] |= data->byte;
 			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
 					"wrote 0x%02x at 0x%02x.\n",
 					addr, data->byte, command);
 		} else {
-			data->byte = chip->bytes[command];
+			data->byte = chip->words[command] & 0xff;
 			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
 					"read  0x%02x at 0x%02x.\n",
 					addr, data->byte, command);
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index c9ce77f13c0e..77b13d027f86 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -4,7 +4,7 @@
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
     Mark D. Studebaker <mdsxyz123@yahoo.com>
-    Copyright (C) 2005 - 2007  Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2005 - 2008  Jean Delvare <khali@linux-fr.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
@@ -35,6 +35,7 @@
    VT8235             0x3177             yes
    VT8237R            0x3227             yes
    VT8237A            0x3337             yes
+   VT8237S            0x3372             yes
    VT8251             0x3287             yes
    CX700              0x8324             yes
 
@@ -318,6 +319,10 @@ static int __devinit vt596_probe(struct pci_dev *pdev,
 	unsigned char temp;
 	int error = -ENODEV;
 
+	/* driver_data might come from user-space, so check it */
+	if (id->driver_data & 1 || id->driver_data > 0xff)
+		return -EINVAL;
+
 	/* Determine the address of the SMBus areas */
 	if (force_addr) {
 		vt596_smba = force_addr & 0xfff0;
@@ -389,6 +394,7 @@ found:
 	case PCI_DEVICE_ID_VIA_8251:
 	case PCI_DEVICE_ID_VIA_8237:
 	case PCI_DEVICE_ID_VIA_8237A:
+	case PCI_DEVICE_ID_VIA_8237S:
 	case PCI_DEVICE_ID_VIA_8235:
 	case PCI_DEVICE_ID_VIA_8233A:
 	case PCI_DEVICE_ID_VIA_8233_0:
@@ -440,6 +446,8 @@ static struct pci_device_id vt596_ids[] = {
 	  .driver_data = SMBBA3 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
 	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S),
+	  .driver_data = SMBBA3 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
 	  .driver_data = SMBBA1 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
@@ -455,6 +463,7 @@ static struct pci_driver vt596_driver = {
 	.name		= "vt596_smbus",
 	.id_table	= vt596_ids,
 	.probe		= vt596_probe,
+	.dynids.use_driver_data = 1,
 };
 
 static int __init i2c_vt596_init(void)
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 2e1c24f671cf..bd7082c2443d 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -4,32 +4,6 @@
 
 menu "Miscellaneous I2C Chip support"
 
-config SENSORS_DS1337
-	tristate "Dallas DS1337 and DS1339 Real Time Clock (DEPRECATED)"
-	depends on EXPERIMENTAL
-	help
-	  If you say yes here you get support for Dallas Semiconductor
-	  DS1337 and DS1339 real-time clock chips.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called ds1337.
-
-	  This driver is deprecated and will be dropped soon. Use
-	  rtc-ds1307 instead.
-
-config SENSORS_DS1374
-	tristate "Dallas DS1374 Real Time Clock (DEPRECATED)"
-	depends on EXPERIMENTAL
-	help
-	  If you say yes here you get support for Dallas Semiconductor
-	  DS1374 real-time clock chips.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called ds1374.
-
-	  This driver is deprecated and will be dropped soon. Use
-	  rtc-ds1374 instead.
-
 config DS1682
 	tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
 	depends on EXPERIMENTAL
@@ -57,7 +31,7 @@ config SENSORS_PCF8574
 	default n
 	help
 	  If you say yes here you get support for Philips PCF8574 and 
-	  PCF8574A chips.
+	  PCF8574A chips. These chips are 8-bit I/O expanders for the I2C bus.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called pcf8574.
@@ -65,6 +39,20 @@ config SENSORS_PCF8574
 	  These devices are hard to detect and rarely found on mainstream
 	  hardware.  If unsure, say N.
 
+config PCF8575
+	tristate "Philips PCF8575"
+	default n
+	help
+	  If you say yes here you get support for Philips PCF8575 chip.
+	  This chip is a 16-bit I/O expander for the I2C bus.  Several other
+	  chip manufacturers sell equivalent chips, e.g. Texas Instruments.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called pcf8575.
+
+	  This device is hard to detect and is rarely found on mainstream
+	  hardware.  If unsure, say N.
+
 config SENSORS_PCA9539
 	tristate "Philips PCA9539 16-bit I/O port"
 	depends on EXPERIMENTAL
@@ -100,12 +88,8 @@ config ISP1301_OMAP
 	  This driver can also be built as a module.  If so, the module
 	  will be called isp1301_omap.
 
-# NOTE:  This isn't really OMAP-specific, except for the current
-# interface location in  <include/asm-arm/arch-omap/tps65010.h>
-# and having mostly OMAP-specific board support
 config TPS65010
 	tristate "TPS6501x Power Management chips"
-	depends on ARCH_OMAP
 	default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
 	help
 	  If you say yes here you get support for the TPS6501x series of
@@ -116,18 +100,6 @@ config TPS65010
 	  This driver can also be built as a module.  If so, the module
 	  will be called tps65010.
 
-config SENSORS_M41T00
-	tristate "ST M41T00 RTC chip (DEPRECATED)"
-	depends on PPC32
-	help
-	  If you say yes here you get support for the ST M41T00 RTC chip.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called m41t00.
-
-	  This driver is deprecated and will be dropped soon. Use
-	  rtc-ds1307 or rtc-m41t80 instead.
-
 config SENSORS_MAX6875
 	tristate "Maxim MAX6875 Power supply supervisor"
 	depends on EXPERIMENTAL
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index ca924e105959..501f00cea782 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -2,14 +2,12 @@
 # Makefile for miscellaneous I2C chip drivers.
 #
 
-obj-$(CONFIG_SENSORS_DS1337)	+= ds1337.o
-obj-$(CONFIG_SENSORS_DS1374)	+= ds1374.o
 obj-$(CONFIG_DS1682)		+= ds1682.o
 obj-$(CONFIG_SENSORS_EEPROM)	+= eeprom.o
 obj-$(CONFIG_SENSORS_MAX6875)	+= max6875.o
-obj-$(CONFIG_SENSORS_M41T00)	+= m41t00.o
 obj-$(CONFIG_SENSORS_PCA9539)	+= pca9539.o
 obj-$(CONFIG_SENSORS_PCF8574)	+= pcf8574.o
+obj-$(CONFIG_PCF8575)		+= pcf8575.o
 obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
 obj-$(CONFIG_ISP1301_OMAP)	+= isp1301_omap.o
 obj-$(CONFIG_TPS65010)		+= tps65010.o
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
deleted file mode 100644
index ec17d6b684a2..000000000000
--- a/drivers/i2c/chips/ds1337.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- *  linux/drivers/i2c/chips/ds1337.c
- *
- *  Copyright (C) 2005 James Chapman <jchapman@katalix.com>
- *
- *	based on linux/drivers/acorn/char/pcf8583.c
- *  Copyright (C) 2000 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/string.h>
-#include <linux/rtc.h>		/* get the user-level API */
-#include <linux/bcd.h>
-#include <linux/list.h>
-
-/* Device registers */
-#define DS1337_REG_HOUR		2
-#define DS1337_REG_DAY		3
-#define DS1337_REG_DATE		4
-#define DS1337_REG_MONTH	5
-#define DS1337_REG_CONTROL	14
-#define DS1337_REG_STATUS	15
-
-/* FIXME - how do we export these interface constants? */
-#define DS1337_GET_DATE		0
-#define DS1337_SET_DATE		1
-
-/*
- * Functions declaration
- */
-static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD_1(ds1337);
-
-static int ds1337_attach_adapter(struct i2c_adapter *adapter);
-static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);
-static void ds1337_init_client(struct i2c_client *client);
-static int ds1337_detach_client(struct i2c_client *client);
-static int ds1337_command(struct i2c_client *client, unsigned int cmd,
-			  void *arg);
-
-/*
- * Driver data (common to all clients)
- */
-static struct i2c_driver ds1337_driver = {
-	.driver = {
-		.name	= "ds1337",
-	},
-	.attach_adapter	= ds1337_attach_adapter,
-	.detach_client	= ds1337_detach_client,
-	.command	= ds1337_command,
-};
-
-/*
- * Client data (each client gets its own)
- */
-struct ds1337_data {
-	struct i2c_client client;
-	struct list_head list;
-};
-
-/*
- * Internal variables
- */
-static LIST_HEAD(ds1337_clients);
-
-static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value)
-{
-	s32 tmp = i2c_smbus_read_byte_data(client, reg);
-
-	if (tmp < 0)
-		return -EIO;
-
-	*value = tmp;
-
-	return 0;
-}
-
-/*
- * Chip access functions
- */
-static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt)
-{
-	int result;
-	u8 buf[7];
-	u8 val;
-	struct i2c_msg msg[2];
-	u8 offs = 0;
-
-	if (!dt) {
-		dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
-		return -EINVAL;
-	}
-
-	msg[0].addr = client->addr;
-	msg[0].flags = 0;
-	msg[0].len = 1;
-	msg[0].buf = &offs;
-
-	msg[1].addr = client->addr;
-	msg[1].flags = I2C_M_RD;
-	msg[1].len = sizeof(buf);
-	msg[1].buf = &buf[0];
-
-	result = i2c_transfer(client->adapter, msg, 2);
-
-	dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n",
-		__FUNCTION__, result, buf[0], buf[1], buf[2], buf[3],
-		buf[4], buf[5], buf[6]);
-
-	if (result == 2) {
-		dt->tm_sec = BCD2BIN(buf[0]);
-		dt->tm_min = BCD2BIN(buf[1]);
-		val = buf[2] & 0x3f;
-		dt->tm_hour = BCD2BIN(val);
-		dt->tm_wday = BCD2BIN(buf[3]) - 1;
-		dt->tm_mday = BCD2BIN(buf[4]);
-		val = buf[5] & 0x7f;
-		dt->tm_mon = BCD2BIN(val) - 1;
-		dt->tm_year = BCD2BIN(buf[6]);
-		if (buf[5] & 0x80)
-			dt->tm_year += 100;
-
-		dev_dbg(&client->dev, "%s: secs=%d, mins=%d, "
-			"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
-			__FUNCTION__, dt->tm_sec, dt->tm_min,
-			dt->tm_hour, dt->tm_mday,
-			dt->tm_mon, dt->tm_year, dt->tm_wday);
-
-		return 0;
-	}
-
-	dev_err(&client->dev, "error reading data! %d\n", result);
-	return -EIO;
-}
-
-static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt)
-{
-	int result;
-	u8 buf[8];
-	u8 val;
-	struct i2c_msg msg[1];
-
-	if (!dt) {
-		dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__);
-		return -EINVAL;
-	}
-
-	dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
-		"mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__,
-		dt->tm_sec, dt->tm_min, dt->tm_hour,
-		dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday);
-
-	buf[0] = 0;		/* reg offset */
-	buf[1] = BIN2BCD(dt->tm_sec);
-	buf[2] = BIN2BCD(dt->tm_min);
-	buf[3] = BIN2BCD(dt->tm_hour);
-	buf[4] = BIN2BCD(dt->tm_wday + 1);
-	buf[5] = BIN2BCD(dt->tm_mday);
-	buf[6] = BIN2BCD(dt->tm_mon + 1);
-	val = dt->tm_year;
-	if (val >= 100) {
-		val -= 100;
-		buf[6] |= (1 << 7);
-	}
-	buf[7] = BIN2BCD(val);
-
-	msg[0].addr = client->addr;
-	msg[0].flags = 0;
-	msg[0].len = sizeof(buf);
-	msg[0].buf = &buf[0];
-
-	result = i2c_transfer(client->adapter, msg, 1);
-	if (result == 1)
-		return 0;
-
-	dev_err(&client->dev, "error writing data! %d\n", result);
-	return -EIO;
-}
-
-static int ds1337_command(struct i2c_client *client, unsigned int cmd,
-			  void *arg)
-{
-	dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
-
-	switch (cmd) {
-	case DS1337_GET_DATE:
-		return ds1337_get_datetime(client, arg);
-
-	case DS1337_SET_DATE:
-		return ds1337_set_datetime(client, arg);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-/*
- * Public API for access to specific device. Useful for low-level
- * RTC access from kernel code.
- */
-int ds1337_do_command(int bus, int cmd, void *arg)
-{
-	struct list_head *walk;
-	struct list_head *tmp;
-	struct ds1337_data *data;
-
-	list_for_each_safe(walk, tmp, &ds1337_clients) {
-		data = list_entry(walk, struct ds1337_data, list);
-		if (data->client.adapter->nr == bus)
-			return ds1337_command(&data->client, cmd, arg);
-	}
-
-	return -ENODEV;
-}
-
-static int ds1337_attach_adapter(struct i2c_adapter *adapter)
-{
-	return i2c_probe(adapter, &addr_data, ds1337_detect);
-}
-
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind)
-{
-	struct i2c_client *new_client;
-	struct ds1337_data *data;
-	int err = 0;
-	const char *name = "";
-
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-				     I2C_FUNC_I2C))
-		goto exit;
-
-	if (!(data = kzalloc(sizeof(struct ds1337_data), GFP_KERNEL))) {
-		err = -ENOMEM;
-		goto exit;
-	}
-	INIT_LIST_HEAD(&data->list);
-
-	/* The common I2C client data is placed right before the
-	 * DS1337-specific data. 
-	 */
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
-	new_client->adapter = adapter;
-	new_client->driver = &ds1337_driver;
-	new_client->flags = 0;
-
-	/*
-	 * Now we do the remaining detection. A negative kind means that
-	 * the driver was loaded with no force parameter (default), so we
-	 * must both detect and identify the chip. A zero kind means that
-	 * the driver was loaded with the force parameter, the detection
-	 * step shall be skipped. A positive kind means that the driver
-	 * was loaded with the force parameter and a given kind of chip is
-	 * requested, so both the detection and the identification steps
-	 * are skipped.
-	 *
-	 * For detection, we read registers that are most likely to cause
-	 * detection failure, i.e. those that have more bits with fixed
-	 * or reserved values.
-	 */
-
-	/* Default to an DS1337 if forced */
-	if (kind == 0)
-		kind = ds1337;
-
-	if (kind < 0) {		/* detection and identification */
-		u8 data;
-
-		/* Check that status register bits 6-2 are zero */
-		if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) ||
-		    (data & 0x7c))
-			goto exit_free;
-
-		/* Check for a valid day register value */
-		if ((ds1337_read(new_client, DS1337_REG_DAY, &data) < 0) ||
-		    (data == 0) || (data & 0xf8))
-			goto exit_free;
-
-		/* Check for a valid date register value */
-		if ((ds1337_read(new_client, DS1337_REG_DATE, &data) < 0) ||
-		    (data == 0) || (data & 0xc0) || ((data & 0x0f) > 9) ||
-		    (data >= 0x32))
-			goto exit_free;
-
-		/* Check for a valid month register value */
-		if ((ds1337_read(new_client, DS1337_REG_MONTH, &data) < 0) ||
-		    (data == 0) || (data & 0x60) || ((data & 0x0f) > 9) ||
-		    ((data >= 0x13) && (data <= 0x19)))
-			goto exit_free;
-
-		/* Check that control register bits 6-5 are zero */
-		if ((ds1337_read(new_client, DS1337_REG_CONTROL, &data) < 0) ||
-		    (data & 0x60))
-			goto exit_free;
-
-		kind = ds1337;
-	}
-
-	if (kind == ds1337)
-		name = "ds1337";
-
-	/* We can fill in the remaining client fields */
-	strlcpy(new_client->name, name, I2C_NAME_SIZE);
-
-	/* Tell the I2C layer a new client has arrived */
-	if ((err = i2c_attach_client(new_client)))
-		goto exit_free;
-
-	/* Initialize the DS1337 chip */
-	ds1337_init_client(new_client);
-
-	/* Add client to local list */
-	list_add(&data->list, &ds1337_clients);
-
-	return 0;
-
-exit_free:
-	kfree(data);
-exit:
-	return err;
-}
-
-static void ds1337_init_client(struct i2c_client *client)
-{
-	u8 status, control;
-
-	/* On some boards, the RTC isn't configured by boot firmware.
-	 * Handle that case by starting/configuring the RTC now.
-	 */
-	status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
-	control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
-
-	if ((status & 0x80) || (control & 0x80)) {
-		/* RTC not running */
-		u8 buf[1+16];	/* First byte is interpreted as address */
-		struct i2c_msg msg[1];
-
-		dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__);
-
-		/* Initialize all, including STATUS and CONTROL to zero */
-		memset(buf, 0, sizeof(buf));
-
-		/* Write valid values in the date/time registers */
-		buf[1+DS1337_REG_DAY] = 1;
-		buf[1+DS1337_REG_DATE] = 1;
-		buf[1+DS1337_REG_MONTH] = 1;
-
-		msg[0].addr = client->addr;
-		msg[0].flags = 0;
-		msg[0].len = sizeof(buf);
-		msg[0].buf = &buf[0];
-
-		i2c_transfer(client->adapter, msg, 1);
-	} else {
-		/* Running: ensure that device is set in 24-hour mode */
-		s32 val;
-
-		val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);
-		if ((val >= 0) && (val & (1 << 6)))
-			i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,
-						  val & 0x3f);
-	}
-}
-
-static int ds1337_detach_client(struct i2c_client *client)
-{
-	int err;
-	struct ds1337_data *data = i2c_get_clientdata(client);
-
-	if ((err = i2c_detach_client(client)))
-		return err;
-
-	list_del(&data->list);
-	kfree(data);
-	return 0;
-}
-
-static int __init ds1337_init(void)
-{
-	return i2c_add_driver(&ds1337_driver);
-}
-
-static void __exit ds1337_exit(void)
-{
-	i2c_del_driver(&ds1337_driver);
-}
-
-MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
-MODULE_DESCRIPTION("DS1337 RTC driver");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL_GPL(ds1337_do_command);
-
-module_init(ds1337_init);
-module_exit(ds1337_exit);
diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c
deleted file mode 100644
index 8a2ff0c114d9..000000000000
--- a/drivers/i2c/chips/ds1374.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * drivers/i2c/chips/ds1374.c
- *
- * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock
- *
- * Author: Randy Vinson <rvinson@mvista.com>
- *
- * Based on the m41t00.c by Mark Greer <mgreer@mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-/*
- * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
- * interface and the SMBus interface of the i2c subsystem.
- * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
- * recommened in .../Documentation/i2c/writing-clients section
- * "Sending and receiving", using SMBus level communication is preferred.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/rtc.h>
-#include <linux/bcd.h>
-#include <linux/mutex.h>
-#include <linux/workqueue.h>
-
-#define DS1374_REG_TOD0		0x00
-#define DS1374_REG_TOD1		0x01
-#define DS1374_REG_TOD2		0x02
-#define DS1374_REG_TOD3		0x03
-#define DS1374_REG_WDALM0	0x04
-#define DS1374_REG_WDALM1	0x05
-#define DS1374_REG_WDALM2	0x06
-#define DS1374_REG_CR		0x07
-#define DS1374_REG_SR		0x08
-#define DS1374_REG_SR_OSF	0x80
-#define DS1374_REG_TCR		0x09
-
-#define	DS1374_DRV_NAME		"ds1374"
-
-static DEFINE_MUTEX(ds1374_mutex);
-
-static struct i2c_driver ds1374_driver;
-static struct i2c_client *save_client;
-
-static unsigned short ignore[] = { I2C_CLIENT_END };
-static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END };
-
-static struct i2c_client_address_data addr_data = {
-	.normal_i2c = normal_addr,
-	.probe = ignore,
-	.ignore = ignore,
-};
-
-static ulong ds1374_read_rtc(void)
-{
-	ulong time = 0;
-	int reg = DS1374_REG_WDALM0;
-
-	while (reg--) {
-		s32 tmp;
-		if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) {
-			dev_warn(&save_client->dev,
-				 "can't read from rtc chip\n");
-			return 0;
-		}
-		time = (time << 8) | (tmp & 0xff);
-	}
-	return time;
-}
-
-static void ds1374_write_rtc(ulong time)
-{
-	int reg;
-
-	for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) {
-		if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff)
-		    < 0) {
-			dev_warn(&save_client->dev,
-				 "can't write to rtc chip\n");
-			break;
-		}
-		time = time >> 8;
-	}
-}
-
-static void ds1374_check_rtc_status(void)
-{
-	s32 tmp;
-
-	tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR);
-	if (tmp < 0) {
-		dev_warn(&save_client->dev,
-			 "can't read status from rtc chip\n");
-		return;
-	}
-	if (tmp & DS1374_REG_SR_OSF) {
-		dev_warn(&save_client->dev,
-			 "oscillator discontinuity flagged, time unreliable\n");
-		tmp &= ~DS1374_REG_SR_OSF;
-		tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR,
-						tmp & 0xff);
-		if (tmp < 0)
-			dev_warn(&save_client->dev,
-				 "can't clear discontinuity notification\n");
-	}
-}
-
-ulong ds1374_get_rtc_time(void)
-{
-	ulong t1, t2;
-	int limit = 10;		/* arbitrary retry limit */
-
-	mutex_lock(&ds1374_mutex);
-
-	/*
-	 * Since the reads are being performed one byte at a time using
-	 * the SMBus vs a 4-byte i2c transfer, there is a chance that a
-	 * carry will occur during the read. To detect this, 2 reads are
-	 * performed and compared.
-	 */
-	do {
-		t1 = ds1374_read_rtc();
-		t2 = ds1374_read_rtc();
-	} while (t1 != t2 && limit--);
-
-	mutex_unlock(&ds1374_mutex);
-
-	if (t1 != t2) {
-		dev_warn(&save_client->dev,
-			 "can't get consistent time from rtc chip\n");
-		t1 = 0;
-	}
-
-	return t1;
-}
-
-static ulong new_time;
-
-static void ds1374_set_work(struct work_struct *work)
-{
-	ulong t1, t2;
-	int limit = 10;		/* arbitrary retry limit */
-
-	t1 = new_time;
-
-	mutex_lock(&ds1374_mutex);
-
-	/*
-	 * Since the writes are being performed one byte at a time using
-	 * the SMBus vs a 4-byte i2c transfer, there is a chance that a
-	 * carry will occur during the write. To detect this, the write
-	 * value is read back and compared.
-	 */
-	do {
-		ds1374_write_rtc(t1);
-		t2 = ds1374_read_rtc();
-	} while (t1 != t2 && limit--);
-
-	mutex_unlock(&ds1374_mutex);
-
-	if (t1 != t2)
-		dev_warn(&save_client->dev,
-			 "can't confirm time set from rtc chip\n");
-}
-
-static struct workqueue_struct *ds1374_workqueue;
-
-static DECLARE_WORK(ds1374_work, ds1374_set_work);
-
-int ds1374_set_rtc_time(ulong nowtime)
-{
-	new_time = nowtime;
-
-	if (in_interrupt())
-		queue_work(ds1374_workqueue, &ds1374_work);
-	else
-		ds1374_set_work(NULL);
-
-	return 0;
-}
-
-/*
- *****************************************************************************
- *
- *	Driver Interface
- *
- *****************************************************************************
- */
-static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind)
-{
-	struct i2c_client *client;
-	int rc;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (!client)
-		return -ENOMEM;
-
-	strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE);
-	client->addr = addr;
-	client->adapter = adap;
-	client->driver = &ds1374_driver;
-
-	ds1374_workqueue = create_singlethread_workqueue("ds1374");
-	if (!ds1374_workqueue) {
-		kfree(client);
-		return -ENOMEM;	/* most expected reason */
-	}
-
-	if ((rc = i2c_attach_client(client)) != 0) {
-		kfree(client);
-		return rc;
-	}
-
-	save_client = client;
-
-	ds1374_check_rtc_status();
-
-	return 0;
-}
-
-static int ds1374_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, ds1374_probe);
-}
-
-static int ds1374_detach(struct i2c_client *client)
-{
-	int rc;
-
-	if ((rc = i2c_detach_client(client)) == 0) {
-		kfree(i2c_get_clientdata(client));
-		destroy_workqueue(ds1374_workqueue);
-	}
-	return rc;
-}
-
-static struct i2c_driver ds1374_driver = {
-	.driver = {
-		.name	= DS1374_DRV_NAME,
-	},
-	.id = I2C_DRIVERID_DS1374,
-	.attach_adapter = ds1374_attach,
-	.detach_client = ds1374_detach,
-};
-
-static int __init ds1374_init(void)
-{
-	return i2c_add_driver(&ds1374_driver);
-}
-
-static void __exit ds1374_exit(void)
-{
-	i2c_del_driver(&ds1374_driver);
-}
-
-module_init(ds1374_init);
-module_exit(ds1374_exit);
-
-MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>");
-MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index 1a7eeebac506..fde297b21ad7 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -35,7 +35,7 @@
 #include <linux/mutex.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
+static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
 					0x55, 0x56, 0x57, I2C_CLIENT_END };
 
 /* Insmod parameters */
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index b767603a07ba..2a3160153f54 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -100,7 +100,7 @@ struct isp1301 {
 
 #if	defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
 
-#include <asm/arch/tps65010.h>
+#include <linux/i2c/tps65010.h>
 
 #else
 
@@ -259,12 +259,6 @@ static inline const char *state_name(struct isp1301 *isp)
 	return state_string(isp->otg.state);
 }
 
-#ifdef	VERBOSE
-#define	dev_vdbg			dev_dbg
-#else
-#define	dev_vdbg(dev, fmt, arg...)	do{}while(0)
-#endif
-
 /*-------------------------------------------------------------------------*/
 
 /* NOTE:  some of this ISP1301 setup is specific to H2 boards;
diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
deleted file mode 100644
index 3fcb646e2073..000000000000
--- a/drivers/i2c/chips/m41t00.c
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * I2C client/driver for the ST M41T00 family of i2c rtc chips.
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * 2005, 2006 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-/*
- * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
- * interface and the SMBus interface of the i2c subsystem.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/rtc.h>
-#include <linux/bcd.h>
-#include <linux/workqueue.h>
-#include <linux/platform_device.h>
-#include <linux/m41t00.h>
-#include <asm/time.h>
-#include <asm/rtc.h>
-
-static struct i2c_driver m41t00_driver;
-static struct i2c_client *save_client;
-
-static unsigned short ignore[] = { I2C_CLIENT_END };
-static unsigned short normal_addr[] = { I2C_CLIENT_END, I2C_CLIENT_END };
-
-static struct i2c_client_address_data addr_data = {
-	.normal_i2c	= normal_addr,
-	.probe		= ignore,
-	.ignore		= ignore,
-};
-
-struct m41t00_chip_info {
-	u8	type;
-	char	*name;
-	u8	read_limit;
-	u8	sec;		/* Offsets for chip regs */
-	u8	min;
-	u8	hour;
-	u8	day;
-	u8	mon;
-	u8	year;
-	u8	alarm_mon;
-	u8	alarm_hour;
-	u8	sqw;
-	u8	sqw_freq;
-};
-
-static struct m41t00_chip_info m41t00_chip_info_tbl[] = {
-	{
-		.type		= M41T00_TYPE_M41T00,
-		.name		= "m41t00",
-		.read_limit	= 5,
-		.sec		= 0,
-		.min		= 1,
-		.hour		= 2,
-		.day		= 4,
-		.mon		= 5,
-		.year		= 6,
-	},
-	{
-		.type		= M41T00_TYPE_M41T81,
-		.name		= "m41t81",
-		.read_limit	= 1,
-		.sec		= 1,
-		.min		= 2,
-		.hour		= 3,
-		.day		= 5,
-		.mon		= 6,
-		.year		= 7,
-		.alarm_mon	= 0xa,
-		.alarm_hour	= 0xc,
-		.sqw		= 0x13,
-	},
-	{
-		.type		= M41T00_TYPE_M41T85,
-		.name		= "m41t85",
-		.read_limit	= 1,
-		.sec		= 1,
-		.min		= 2,
-		.hour		= 3,
-		.day		= 5,
-		.mon		= 6,
-		.year		= 7,
-		.alarm_mon	= 0xa,
-		.alarm_hour	= 0xc,
-		.sqw		= 0x13,
-	},
-};
-static struct m41t00_chip_info *m41t00_chip;
-
-ulong
-m41t00_get_rtc_time(void)
-{
-	s32 sec, min, hour, day, mon, year;
-	s32 sec1, min1, hour1, day1, mon1, year1;
-	u8 reads = 0;
-	u8 buf[8], msgbuf[1] = { 0 }; /* offset into rtc's regs */
-	struct i2c_msg msgs[] = {
-		{
-			.addr	= save_client->addr,
-			.flags	= 0,
-			.len	= 1,
-			.buf	= msgbuf,
-		},
-		{
-			.addr	= save_client->addr,
-			.flags	= I2C_M_RD,
-			.len	= 8,
-			.buf	= buf,
-		},
-	};
-
-	sec = min = hour = day = mon = year = 0;
-
-	do {
-		if (i2c_transfer(save_client->adapter, msgs, 2) < 0)
-			goto read_err;
-
-		sec1 = sec;
-		min1 = min;
-		hour1 = hour;
-		day1 = day;
-		mon1 = mon;
-		year1 = year;
-
-		sec = buf[m41t00_chip->sec] & 0x7f;
-		min = buf[m41t00_chip->min] & 0x7f;
-		hour = buf[m41t00_chip->hour] & 0x3f;
-		day = buf[m41t00_chip->day] & 0x3f;
-		mon = buf[m41t00_chip->mon] & 0x1f;
-		year = buf[m41t00_chip->year];
-	} while ((++reads < m41t00_chip->read_limit) && ((sec != sec1)
-			|| (min != min1) || (hour != hour1) || (day != day1)
-			|| (mon != mon1) || (year != year1)));
-
-	if ((m41t00_chip->read_limit > 1) && ((sec != sec1) || (min != min1)
-			|| (hour != hour1) || (day != day1) || (mon != mon1)
-			|| (year != year1)))
-		goto read_err;
-
-	sec = BCD2BIN(sec);
-	min = BCD2BIN(min);
-	hour = BCD2BIN(hour);
-	day = BCD2BIN(day);
-	mon = BCD2BIN(mon);
-	year = BCD2BIN(year);
-
-	year += 1900;
-	if (year < 1970)
-		year += 100;
-
-	return mktime(year, mon, day, hour, min, sec);
-
-read_err:
-	dev_err(&save_client->dev, "m41t00_get_rtc_time: Read error\n");
-	return 0;
-}
-EXPORT_SYMBOL_GPL(m41t00_get_rtc_time);
-
-static void
-m41t00_set(void *arg)
-{
-	struct rtc_time	tm;
-	int nowtime = *(int *)arg;
-	s32 sec, min, hour, day, mon, year;
-	u8 wbuf[9], *buf = &wbuf[1], msgbuf[1] = { 0 };
-	struct i2c_msg msgs[] = {
-		{
-			.addr	= save_client->addr,
-			.flags	= 0,
-			.len	= 1,
-			.buf	= msgbuf,
-		},
-		{
-			.addr	= save_client->addr,
-			.flags	= I2C_M_RD,
-			.len	= 8,
-			.buf	= buf,
-		},
-	};
-
-	to_tm(nowtime, &tm);
-	tm.tm_year = (tm.tm_year - 1900) % 100;
-
-	sec = BIN2BCD(tm.tm_sec);
-	min = BIN2BCD(tm.tm_min);
-	hour = BIN2BCD(tm.tm_hour);
-	day = BIN2BCD(tm.tm_mday);
-	mon = BIN2BCD(tm.tm_mon);
-	year = BIN2BCD(tm.tm_year);
-
-	/* Read reg values into buf[0..7]/wbuf[1..8] */
-	if (i2c_transfer(save_client->adapter, msgs, 2) < 0) {
-		dev_err(&save_client->dev, "m41t00_set: Read error\n");
-		return;
-	}
-
-	wbuf[0] = 0; /* offset into rtc's regs */
-	buf[m41t00_chip->sec] = (buf[m41t00_chip->sec] & ~0x7f) | (sec & 0x7f);
-	buf[m41t00_chip->min] = (buf[m41t00_chip->min] & ~0x7f) | (min & 0x7f);
-	buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f);
-	buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f);
-	buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f);
-	buf[m41t00_chip->year] = year;
-
-	if (i2c_master_send(save_client, wbuf, 9) < 0)
-		dev_err(&save_client->dev, "m41t00_set: Write error\n");
-}
-
-static ulong new_time;
-/* well, isn't this API just _lovely_? */
-static void
-m41t00_barf(struct work_struct *unusable)
-{
-	m41t00_set(&new_time);
-}
-
-static struct workqueue_struct *m41t00_wq;
-static DECLARE_WORK(m41t00_work, m41t00_barf);
-
-int
-m41t00_set_rtc_time(ulong nowtime)
-{
-	new_time = nowtime;
-
-	if (in_interrupt())
-		queue_work(m41t00_wq, &m41t00_work);
-	else
-		m41t00_set(&new_time);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(m41t00_set_rtc_time);
-
-/*
- *****************************************************************************
- *
- *	platform_data Driver Interface
- *
- *****************************************************************************
- */
-static int __init
-m41t00_platform_probe(struct platform_device *pdev)
-{
-	struct m41t00_platform_data *pdata;
-	int i;
-
-	if (pdev && (pdata = pdev->dev.platform_data)) {
-		normal_addr[0] = pdata->i2c_addr;
-
-		for (i=0; i<ARRAY_SIZE(m41t00_chip_info_tbl); i++)
-			if (m41t00_chip_info_tbl[i].type == pdata->type) {
-				m41t00_chip = &m41t00_chip_info_tbl[i];
-				m41t00_chip->sqw_freq = pdata->sqw_freq;
-				return 0;
-			}
-	}
-	return -ENODEV;
-}
-
-static int __exit
-m41t00_platform_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-
-static struct platform_driver m41t00_platform_driver = {
-	.probe  = m41t00_platform_probe,
-	.remove = m41t00_platform_remove,
-	.driver = {
-		.owner = THIS_MODULE,
-		.name  = M41T00_DRV_NAME,
-	},
-};
-
-/*
- *****************************************************************************
- *
- *	Driver Interface
- *
- *****************************************************************************
- */
-static int
-m41t00_probe(struct i2c_adapter *adap, int addr, int kind)
-{
-	struct i2c_client *client;
-	int rc;
-
-	if (!i2c_check_functionality(adap, I2C_FUNC_I2C
-			| I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (!client)
-		return -ENOMEM;
-
-	strlcpy(client->name, m41t00_chip->name, I2C_NAME_SIZE);
-	client->addr = addr;
-	client->adapter = adap;
-	client->driver = &m41t00_driver;
-
-	if ((rc = i2c_attach_client(client)))
-		goto attach_err;
-
-	if (m41t00_chip->type != M41T00_TYPE_M41T00) {
-		/* If asked, disable SQW, set SQW frequency & re-enable */
-		if (m41t00_chip->sqw_freq)
-			if (((rc = i2c_smbus_read_byte_data(client,
-					m41t00_chip->alarm_mon)) < 0)
-			 || ((rc = i2c_smbus_write_byte_data(client,
-					m41t00_chip->alarm_mon, rc & ~0x40)) <0)
-			 || ((rc = i2c_smbus_write_byte_data(client,
-					m41t00_chip->sqw,
-					m41t00_chip->sqw_freq)) < 0)
-			 || ((rc = i2c_smbus_write_byte_data(client,
-					m41t00_chip->alarm_mon, rc | 0x40)) <0))
-				goto sqw_err;
-
-		/* Make sure HT (Halt Update) bit is cleared */
-		if ((rc = i2c_smbus_read_byte_data(client,
-				m41t00_chip->alarm_hour)) < 0)
-			goto ht_err;
-
-		if (rc & 0x40)
-			if ((rc = i2c_smbus_write_byte_data(client,
-					m41t00_chip->alarm_hour, rc & ~0x40))<0)
-				goto ht_err;
-	}
-
-	/* Make sure ST (stop) bit is cleared */
-	if ((rc = i2c_smbus_read_byte_data(client, m41t00_chip->sec)) < 0)
-		goto st_err;
-
-	if (rc & 0x80)
-		if ((rc = i2c_smbus_write_byte_data(client, m41t00_chip->sec,
-				rc & ~0x80)) < 0)
-			goto st_err;
-
-	m41t00_wq = create_singlethread_workqueue(m41t00_chip->name);
-	save_client = client;
-	return 0;
-
-st_err:
-	dev_err(&client->dev, "m41t00_probe: Can't clear ST bit\n");
-	goto attach_err;
-ht_err:
-	dev_err(&client->dev, "m41t00_probe: Can't clear HT bit\n");
-	goto attach_err;
-sqw_err:
-	dev_err(&client->dev, "m41t00_probe: Can't set SQW Frequency\n");
-attach_err:
-	kfree(client);
-	return rc;
-}
-
-static int
-m41t00_attach(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, m41t00_probe);
-}
-
-static int
-m41t00_detach(struct i2c_client *client)
-{
-	int rc;
-
-	if ((rc = i2c_detach_client(client)) == 0) {
-		kfree(client);
-		destroy_workqueue(m41t00_wq);
-	}
-	return rc;
-}
-
-static struct i2c_driver m41t00_driver = {
-	.driver = {
-		.name	= M41T00_DRV_NAME,
-	},
-	.id		= I2C_DRIVERID_STM41T00,
-	.attach_adapter	= m41t00_attach,
-	.detach_client	= m41t00_detach,
-};
-
-static int __init
-m41t00_init(void)
-{
-	int rc;
-
-	if (!(rc = platform_driver_register(&m41t00_platform_driver)))
-		rc = i2c_add_driver(&m41t00_driver);
-	return rc;
-}
-
-static void __exit
-m41t00_exit(void)
-{
-	i2c_del_driver(&m41t00_driver);
-	platform_driver_unregister(&m41t00_platform_driver);
-}
-
-module_init(m41t00_init);
-module_exit(m41t00_exit);
-
-MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
-MODULE_DESCRIPTION("ST Microelectronics M41T00 RTC I2C Client Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
index 64692f666372..fb7ea5637eca 100644
--- a/drivers/i2c/chips/max6875.c
+++ b/drivers/i2c/chips/max6875.c
@@ -34,7 +34,7 @@
 #include <linux/mutex.h>
 
 /* Do not scan - the MAX6875 access method will write to some EEPROM chips */
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD_1(max6875);
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
index 21c6dd69193c..b3b830ccf209 100644
--- a/drivers/i2c/chips/pcf8574.c
+++ b/drivers/i2c/chips/pcf8574.c
@@ -41,9 +41,11 @@
 #include <linux/i2c.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-					0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-					I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = {
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+	I2C_CLIENT_END
+};
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
diff --git a/drivers/i2c/chips/pcf8575.c b/drivers/i2c/chips/pcf8575.c
new file mode 100644
index 000000000000..3ea08ac0bfa3
--- /dev/null
+++ b/drivers/i2c/chips/pcf8575.c
@@ -0,0 +1,214 @@
+/*
+  pcf8575.c
+
+  About the PCF8575 chip: the PCF8575 is a 16-bit I/O expander for the I2C bus
+  produced by a.o. Philips Semiconductors.
+
+  Copyright (C) 2006 Michael Hennerich, Analog Devices Inc.
+  <hennerich@blackfin.uclinux.org>
+  Based on pcf8574.c.
+
+  Copyright (c) 2007 Bart Van Assche <bart.vanassche@gmail.com>.
+  Ported this driver from ucLinux to the mainstream Linux kernel.
+
+  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/i2c.h>
+#include <linux/slab.h>  /* kzalloc() */
+#include <linux/sysfs.h> /* sysfs_create_group() */
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = {
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+	I2C_CLIENT_END
+};
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+
+/* Each client has this additional data */
+struct pcf8575_data {
+	struct i2c_client client;
+	int write;		/* last written value, or error code */
+};
+
+static int pcf8575_attach_adapter(struct i2c_adapter *adapter);
+static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind);
+static int pcf8575_detach_client(struct i2c_client *client);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver pcf8575_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "pcf8575",
+	},
+	.attach_adapter	= pcf8575_attach_adapter,
+	.detach_client	= pcf8575_detach_client,
+};
+
+/* following are the sysfs callback functions */
+static ssize_t show_read(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	u16 val;
+	u8 iopin_state[2];
+
+	i2c_master_recv(client, iopin_state, 2);
+
+	val = iopin_state[0];
+	val |= iopin_state[1] << 8;
+
+	return sprintf(buf, "%u\n", val);
+}
+
+static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
+
+static ssize_t show_write(struct device *dev, struct device_attribute *attr,
+			  char *buf)
+{
+	struct pcf8575_data *data = dev_get_drvdata(dev);
+	if (data->write < 0)
+		return data->write;
+	return sprintf(buf, "%d\n", data->write);
+}
+
+static ssize_t set_write(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pcf8575_data *data = i2c_get_clientdata(client);
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+	u8 iopin_state[2];
+
+	if (val > 0xffff)
+		return -EINVAL;
+
+	data->write = val;
+
+	iopin_state[0] = val & 0xFF;
+	iopin_state[1] = val >> 8;
+
+	i2c_master_send(client, iopin_state, 2);
+
+	return count;
+}
+
+static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
+
+static struct attribute *pcf8575_attributes[] = {
+	&dev_attr_read.attr,
+	&dev_attr_write.attr,
+	NULL
+};
+
+static const struct attribute_group pcf8575_attr_group = {
+	.attrs = pcf8575_attributes,
+};
+
+/*
+ * Real code
+ */
+
+static int pcf8575_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_probe(adapter, &addr_data, pcf8575_detect);
+}
+
+/* This function is called by i2c_probe */
+static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct pcf8575_data *data;
+	int err = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+		goto exit;
+
+	/* OK. For now, we presume we have a valid client. We now create the
+	   client structure, even though we cannot fill it completely yet. */
+	data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL);
+	if (!data) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client = &data->client;
+	i2c_set_clientdata(client, data);
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &pcf8575_driver;
+	strlcpy(client->name, "pcf8575", I2C_NAME_SIZE);
+	data->write = -EAGAIN;
+
+	/* This is the place to detect whether the chip at the specified
+	   address really is a PCF8575 chip. However, there is no method known
+	   to detect whether an I2C chip is a PCF8575 or any other I2C chip. */
+
+	/* Tell the I2C layer a new client has arrived */
+	err = i2c_attach_client(client);
+	if (err)
+		goto exit_free;
+
+	/* Register sysfs hooks */
+	err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group);
+	if (err)
+		goto exit_detach;
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int pcf8575_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group);
+
+	err = i2c_detach_client(client);
+	if (err)
+		return err;
+
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static int __init pcf8575_init(void)
+{
+	return i2c_add_driver(&pcf8575_driver);
+}
+
+static void __exit pcf8575_exit(void)
+{
+	i2c_del_driver(&pcf8575_driver);
+}
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>, "
+	      "Bart Van Assche <bart.vanassche@gmail.com>");
+MODULE_DESCRIPTION("pcf8575 driver");
+MODULE_LICENSE("GPL");
+
+module_init(pcf8575_init);
+module_exit(pcf8575_exit);
diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
index 4dc36376eb32..865f4409c06b 100644
--- a/drivers/i2c/chips/pcf8591.c
+++ b/drivers/i2c/chips/pcf8591.c
@@ -27,7 +27,7 @@
 #include <linux/mutex.h>
 
 /* Addresses to scan */
-static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
 					0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
 
 /* Insmod parameters */
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index e320994b981c..4154a9108859 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -31,7 +31,7 @@
 #include <linux/seq_file.h>
 #include <linux/mutex.h>
 
-#include <asm/arch/tps65010.h>
+#include <linux/i2c/tps65010.h>
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c
index 3de4b19ba08f..a10fd2791a69 100644
--- a/drivers/i2c/chips/tsl2550.c
+++ b/drivers/i2c/chips/tsl2550.c
@@ -432,11 +432,32 @@ static int __devexit tsl2550_remove(struct i2c_client *client)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+
+static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	return tsl2550_set_power_state(client, 0);
+}
+
+static int tsl2550_resume(struct i2c_client *client)
+{
+	return tsl2550_set_power_state(client, 1);
+}
+
+#else
+
+#define tsl2550_suspend		NULL
+#define tsl2550_resume		NULL
+
+#endif /* CONFIG_PM */
+
 static struct i2c_driver tsl2550_driver = {
 	.driver = {
 		.name	= TSL2550_DRV_NAME,
 		.owner	= THIS_MODULE,
 	},
+	.suspend = tsl2550_suspend,
+	.resume	= tsl2550_resume,
 	.probe	= tsl2550_probe,
 	.remove	= __devexit_p(tsl2550_remove),
 };
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index b5e13e405e72..96da22e9a5a4 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -33,14 +33,15 @@
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/completion.h>
+#include <linux/hardirq.h>
+#include <linux/irqflags.h>
 #include <asm/uaccess.h>
+#include <asm/semaphore.h>
 
 #include "i2c-core.h"
 
 
-static LIST_HEAD(adapters);
-static LIST_HEAD(drivers);
-static DEFINE_MUTEX(core_lists);
+static DEFINE_MUTEX(core_lock);
 static DEFINE_IDR(i2c_adapter_idr);
 
 #define is_newstyle_driver(d) ((d)->probe || (d)->remove)
@@ -198,6 +199,25 @@ static struct bus_type i2c_bus_type = {
 	.resume		= i2c_device_resume,
 };
 
+
+/**
+ * i2c_verify_client - return parameter as i2c_client, or NULL
+ * @dev: device, probably from some driver model iterator
+ *
+ * When traversing the driver model tree, perhaps using driver model
+ * iterators like @device_for_each_child(), you can't assume very much
+ * about the nodes you find.  Use this function to avoid oopses caused
+ * by wrongly treating some non-I2C device as an i2c_client.
+ */
+struct i2c_client *i2c_verify_client(struct device *dev)
+{
+	return (dev->bus == &i2c_bus_type)
+			? to_i2c_client(dev)
+			: NULL;
+}
+EXPORT_SYMBOL(i2c_verify_client);
+
+
 /**
  * i2c_new_device - instantiate an i2c device for use with a new style driver
  * @adap: the adapter managing the device
@@ -276,6 +296,50 @@ void i2c_unregister_device(struct i2c_client *client)
 EXPORT_SYMBOL_GPL(i2c_unregister_device);
 
 
+static int dummy_nop(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct i2c_driver dummy_driver = {
+	.driver.name	= "dummy",
+	.probe		= dummy_nop,
+	.remove		= dummy_nop,
+};
+
+/**
+ * i2c_new_dummy - return a new i2c device bound to a dummy driver
+ * @adapter: the adapter managing the device
+ * @address: seven bit address to be used
+ * @type: optional label used for i2c_client.name
+ * Context: can sleep
+ *
+ * This returns an I2C client bound to the "dummy" driver, intended for use
+ * with devices that consume multiple addresses.  Examples of such chips
+ * include various EEPROMS (like 24c04 and 24c08 models).
+ *
+ * These dummy devices have two main uses.  First, most I2C and SMBus calls
+ * except i2c_transfer() need a client handle; the dummy will be that handle.
+ * And second, this prevents the specified address from being bound to a
+ * different driver.
+ *
+ * This returns the new i2c client, which should be saved for later use with
+ * i2c_unregister_device(); or NULL to indicate an error.
+ */
+struct i2c_client *
+i2c_new_dummy(struct i2c_adapter *adapter, u16 address, const char *type)
+{
+	struct i2c_board_info info = {
+		.driver_name	= "dummy",
+		.addr		= address,
+	};
+
+	if (type)
+		strlcpy(info.type, type, sizeof info.type);
+	return i2c_new_device(adapter, &info);
+}
+EXPORT_SYMBOL_GPL(i2c_new_dummy);
+
 /* ------------------------------------------------------------------------- */
 
 /* I2C bus adapters -- one roots each I2C or SMBUS segment */
@@ -320,18 +384,27 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
 	mutex_unlock(&__i2c_board_lock);
 }
 
+static int i2c_do_add_adapter(struct device_driver *d, void *data)
+{
+	struct i2c_driver *driver = to_i2c_driver(d);
+	struct i2c_adapter *adap = data;
+
+	if (driver->attach_adapter) {
+		/* We ignore the return code; if it fails, too bad */
+		driver->attach_adapter(adap);
+	}
+	return 0;
+}
+
 static int i2c_register_adapter(struct i2c_adapter *adap)
 {
-	int res = 0;
-	struct list_head   *item;
-	struct i2c_driver  *driver;
+	int res = 0, dummy;
 
 	mutex_init(&adap->bus_lock);
 	mutex_init(&adap->clist_lock);
 	INIT_LIST_HEAD(&adap->clients);
 
-	mutex_lock(&core_lists);
-	list_add_tail(&adap->list, &adapters);
+	mutex_lock(&core_lock);
 
 	/* Add the adapter to the driver core.
 	 * If the parent pointer is not set up,
@@ -356,19 +429,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 		i2c_scan_static_board_info(adap);
 
 	/* let legacy drivers scan this bus for matching devices */
-	list_for_each(item,&drivers) {
-		driver = list_entry(item, struct i2c_driver, list);
-		if (driver->attach_adapter)
-			/* We ignore the return code; if it fails, too bad */
-			driver->attach_adapter(adap);
-	}
+	dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
+				 i2c_do_add_adapter);
 
 out_unlock:
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 	return res;
 
 out_list:
-	list_del(&adap->list);
 	idr_remove(&i2c_adapter_idr, adap->nr);
 	goto out_unlock;
 }
@@ -394,11 +462,11 @@ retry:
 	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
 		return -ENOMEM;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 	/* "above" here means "above or equal to", sigh */
 	res = idr_get_new_above(&i2c_adapter_idr, adapter,
 				__i2c_first_dynamic_bus_num, &id);
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 
 	if (res < 0) {
 		if (res == -EAGAIN)
@@ -443,7 +511,7 @@ retry:
 	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
 		return -ENOMEM;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 	/* "above" here means "above or equal to", sigh;
 	 * we need the "equal to" result to force the result
 	 */
@@ -452,7 +520,7 @@ retry:
 		status = -EBUSY;
 		idr_remove(&i2c_adapter_idr, id);
 	}
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 	if (status == -EAGAIN)
 		goto retry;
 
@@ -462,6 +530,21 @@ retry:
 }
 EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
 
+static int i2c_do_del_adapter(struct device_driver *d, void *data)
+{
+	struct i2c_driver *driver = to_i2c_driver(d);
+	struct i2c_adapter *adapter = data;
+	int res;
+
+	if (!driver->detach_adapter)
+		return 0;
+	res = driver->detach_adapter(adapter);
+	if (res)
+		dev_err(&adapter->dev, "detach_adapter failed (%d) "
+			"for driver [%s]\n", res, driver->driver.name);
+	return res;
+}
+
 /**
  * i2c_del_adapter - unregister I2C adapter
  * @adap: the adapter being unregistered
@@ -473,35 +556,24 @@ EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
 	struct list_head  *item, *_n;
-	struct i2c_adapter *adap_from_list;
-	struct i2c_driver *driver;
 	struct i2c_client *client;
 	int res = 0;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 
 	/* First make sure that this adapter was ever added */
-	list_for_each_entry(adap_from_list, &adapters, list) {
-		if (adap_from_list == adap)
-			break;
-	}
-	if (adap_from_list != adap) {
+	if (idr_find(&i2c_adapter_idr, adap->nr) != adap) {
 		pr_debug("i2c-core: attempting to delete unregistered "
 			 "adapter [%s]\n", adap->name);
 		res = -EINVAL;
 		goto out_unlock;
 	}
 
-	list_for_each(item,&drivers) {
-		driver = list_entry(item, struct i2c_driver, list);
-		if (driver->detach_adapter)
-			if ((res = driver->detach_adapter(adap))) {
-				dev_err(&adap->dev, "detach_adapter failed "
-					"for driver [%s]\n",
-					driver->driver.name);
-				goto out_unlock;
-			}
-	}
+	/* Tell drivers about this removal */
+	res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
+			       i2c_do_del_adapter);
+	if (res)
+		goto out_unlock;
 
 	/* detach any active clients. This must be done first, because
 	 * it can fail; in which case we give up. */
@@ -529,7 +601,6 @@ int i2c_del_adapter(struct i2c_adapter *adap)
 	/* clean up the sysfs representation */
 	init_completion(&adap->dev_released);
 	device_unregister(&adap->dev);
-	list_del(&adap->list);
 
 	/* wait for sysfs to drop all references */
 	wait_for_completion(&adap->dev_released);
@@ -540,7 +611,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
 	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
 
  out_unlock:
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 	return res;
 }
 EXPORT_SYMBOL(i2c_del_adapter);
@@ -583,21 +654,23 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
 	if (res)
 		return res;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 
-	list_add_tail(&driver->list,&drivers);
 	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
 
 	/* legacy drivers scan i2c busses directly */
 	if (driver->attach_adapter) {
 		struct i2c_adapter *adapter;
 
-		list_for_each_entry(adapter, &adapters, list) {
+		down(&i2c_adapter_class.sem);
+		list_for_each_entry(adapter, &i2c_adapter_class.devices,
+				    dev.node) {
 			driver->attach_adapter(adapter);
 		}
+		up(&i2c_adapter_class.sem);
 	}
 
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 	return 0;
 }
 EXPORT_SYMBOL(i2c_register_driver);
@@ -609,11 +682,11 @@ EXPORT_SYMBOL(i2c_register_driver);
  */
 void i2c_del_driver(struct i2c_driver *driver)
 {
-	struct list_head   *item1, *item2, *_n;
+	struct list_head   *item2, *_n;
 	struct i2c_client  *client;
 	struct i2c_adapter *adap;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 
 	/* new-style driver? */
 	if (is_newstyle_driver(driver))
@@ -623,8 +696,8 @@ void i2c_del_driver(struct i2c_driver *driver)
 	 * attached. If so, detach them to be able to kill the driver
 	 * afterwards.
 	 */
-	list_for_each(item1,&adapters) {
-		adap = list_entry(item1, struct i2c_adapter, list);
+	down(&i2c_adapter_class.sem);
+	list_for_each_entry(adap, &i2c_adapter_class.devices, dev.node) {
 		if (driver->detach_adapter) {
 			if (driver->detach_adapter(adap)) {
 				dev_err(&adap->dev, "detach_adapter failed "
@@ -648,40 +721,31 @@ void i2c_del_driver(struct i2c_driver *driver)
 			}
 		}
 	}
+	up(&i2c_adapter_class.sem);
 
  unregister:
 	driver_unregister(&driver->driver);
-	list_del(&driver->list);
 	pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
 
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 }
 EXPORT_SYMBOL(i2c_del_driver);
 
 /* ------------------------------------------------------------------------- */
 
-static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
+static int __i2c_check_addr(struct device *dev, void *addrp)
 {
-	struct list_head   *item;
-	struct i2c_client  *client;
+	struct i2c_client	*client = i2c_verify_client(dev);
+	int			addr = *(int *)addrp;
 
-	list_for_each(item,&adapter->clients) {
-		client = list_entry(item, struct i2c_client, list);
-		if (client->addr == addr)
-			return -EBUSY;
-	}
+	if (client && client->addr == addr)
+		return -EBUSY;
 	return 0;
 }
 
 static int i2c_check_addr(struct i2c_adapter *adapter, int addr)
 {
-	int rval;
-
-	mutex_lock(&adapter->clist_lock);
-	rval = __i2c_check_addr(adapter, addr);
-	mutex_unlock(&adapter->clist_lock);
-
-	return rval;
+	return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr);
 }
 
 int i2c_attach_client(struct i2c_client *client)
@@ -689,15 +753,6 @@ int i2c_attach_client(struct i2c_client *client)
 	struct i2c_adapter *adapter = client->adapter;
 	int res = 0;
 
-	mutex_lock(&adapter->clist_lock);
-	if (__i2c_check_addr(client->adapter, client->addr)) {
-		res = -EBUSY;
-		goto out_unlock;
-	}
-	list_add_tail(&client->list,&adapter->clients);
-
-	client->usage_count = 0;
-
 	client->dev.parent = &client->adapter->dev;
 	client->dev.bus = &i2c_bus_type;
 
@@ -712,13 +767,17 @@ int i2c_attach_client(struct i2c_client *client)
 
 	snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
 		"%d-%04x", i2c_adapter_id(adapter), client->addr);
-	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
-		client->name, client->dev.bus_id);
 	res = device_register(&client->dev);
 	if (res)
-		goto out_list;
+		goto out_err;
+
+	mutex_lock(&adapter->clist_lock);
+	list_add_tail(&client->list, &adapter->clients);
 	mutex_unlock(&adapter->clist_lock);
 
+	dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
+		client->name, client->dev.bus_id);
+
 	if (adapter->client_register)  {
 		if (adapter->client_register(client)) {
 			dev_dbg(&adapter->dev, "client_register "
@@ -729,12 +788,9 @@ int i2c_attach_client(struct i2c_client *client)
 
 	return 0;
 
-out_list:
-	list_del(&client->list);
+out_err:
 	dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
 		"(%d)\n", client->name, client->addr, res);
-out_unlock:
-	mutex_unlock(&adapter->clist_lock);
 	return res;
 }
 EXPORT_SYMBOL(i2c_attach_client);
@@ -744,12 +800,6 @@ int i2c_detach_client(struct i2c_client *client)
 	struct i2c_adapter *adapter = client->adapter;
 	int res = 0;
 
-	if (client->usage_count > 0) {
-		dev_warn(&client->dev, "Client [%s] still busy, "
-			 "can't detach\n", client->name);
-		return -EBUSY;
-	}
-
 	if (adapter->client_unregister)  {
 		res = adapter->client_unregister(client);
 		if (res) {
@@ -762,9 +812,10 @@ int i2c_detach_client(struct i2c_client *client)
 
 	mutex_lock(&adapter->clist_lock);
 	list_del(&client->list);
+	mutex_unlock(&adapter->clist_lock);
+
 	init_completion(&client->released);
 	device_unregister(&client->dev);
-	mutex_unlock(&adapter->clist_lock);
 	wait_for_completion(&client->released);
 
  out:
@@ -772,72 +823,58 @@ int i2c_detach_client(struct i2c_client *client)
 }
 EXPORT_SYMBOL(i2c_detach_client);
 
-static int i2c_inc_use_client(struct i2c_client *client)
+/**
+ * i2c_use_client - increments the reference count of the i2c client structure
+ * @client: the client being referenced
+ *
+ * Each live reference to a client should be refcounted. The driver model does
+ * that automatically as part of driver binding, so that most drivers don't
+ * need to do this explicitly: they hold a reference until they're unbound
+ * from the device.
+ *
+ * A pointer to the client with the incremented reference counter is returned.
+ */
+struct i2c_client *i2c_use_client(struct i2c_client *client)
 {
-
-	if (!try_module_get(client->driver->driver.owner))
-		return -ENODEV;
-	if (!try_module_get(client->adapter->owner)) {
-		module_put(client->driver->driver.owner);
-		return -ENODEV;
-	}
-
-	return 0;
+	get_device(&client->dev);
+	return client;
 }
+EXPORT_SYMBOL(i2c_use_client);
 
-static void i2c_dec_use_client(struct i2c_client *client)
+/**
+ * i2c_release_client - release a use of the i2c client structure
+ * @client: the client being no longer referenced
+ *
+ * Must be called when a user of a client is finished with it.
+ */
+void i2c_release_client(struct i2c_client *client)
 {
-	module_put(client->driver->driver.owner);
-	module_put(client->adapter->owner);
+	put_device(&client->dev);
 }
+EXPORT_SYMBOL(i2c_release_client);
 
-int i2c_use_client(struct i2c_client *client)
-{
-	int ret;
-
-	ret = i2c_inc_use_client(client);
-	if (ret)
-		return ret;
-
-	client->usage_count++;
-
-	return 0;
-}
-EXPORT_SYMBOL(i2c_use_client);
+struct i2c_cmd_arg {
+	unsigned	cmd;
+	void		*arg;
+};
 
-int i2c_release_client(struct i2c_client *client)
+static int i2c_cmd(struct device *dev, void *_arg)
 {
-	if (!client->usage_count) {
-		pr_debug("i2c-core: %s used one too many times\n",
-			 __FUNCTION__);
-		return -EPERM;
-	}
-
-	client->usage_count--;
-	i2c_dec_use_client(client);
+	struct i2c_client	*client = i2c_verify_client(dev);
+	struct i2c_cmd_arg	*arg = _arg;
 
+	if (client && client->driver && client->driver->command)
+		client->driver->command(client, arg->cmd, arg->arg);
 	return 0;
 }
-EXPORT_SYMBOL(i2c_release_client);
 
 void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
 {
-	struct list_head  *item;
-	struct i2c_client *client;
+	struct i2c_cmd_arg	cmd_arg;
 
-	mutex_lock(&adap->clist_lock);
-	list_for_each(item,&adap->clients) {
-		client = list_entry(item, struct i2c_client, list);
-		if (!try_module_get(client->driver->driver.owner))
-			continue;
-		if (NULL != client->driver->command) {
-			mutex_unlock(&adap->clist_lock);
-			client->driver->command(client,cmd,arg);
-			mutex_lock(&adap->clist_lock);
-		}
-		module_put(client->driver->driver.owner);
-       }
-       mutex_unlock(&adap->clist_lock);
+	cmd_arg.cmd = cmd;
+	cmd_arg.arg = arg;
+	device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd);
 }
 EXPORT_SYMBOL(i2c_clients_command);
 
@@ -848,11 +885,24 @@ static int __init i2c_init(void)
 	retval = bus_register(&i2c_bus_type);
 	if (retval)
 		return retval;
-	return class_register(&i2c_adapter_class);
+	retval = class_register(&i2c_adapter_class);
+	if (retval)
+		goto bus_err;
+	retval = i2c_add_driver(&dummy_driver);
+	if (retval)
+		goto class_err;
+	return 0;
+
+class_err:
+	class_unregister(&i2c_adapter_class);
+bus_err:
+	bus_unregister(&i2c_bus_type);
+	return retval;
 }
 
 static void __exit i2c_exit(void)
 {
+	i2c_del_driver(&dummy_driver);
 	class_unregister(&i2c_adapter_class);
 	bus_unregister(&i2c_bus_type);
 }
@@ -879,7 +929,15 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
 		}
 #endif
 
-		mutex_lock_nested(&adap->bus_lock, adap->level);
+		if (in_atomic() || irqs_disabled()) {
+			ret = mutex_trylock(&adap->bus_lock);
+			if (!ret)
+				/* I2C activity is ongoing. */
+				return -EAGAIN;
+		} else {
+			mutex_lock_nested(&adap->bus_lock, adap->level);
+		}
+
 		ret = adap->algo->master_xfer(adap,msgs,num);
 		mutex_unlock(&adap->bus_lock);
 
@@ -978,7 +1036,7 @@ static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
 }
 
 int i2c_probe(struct i2c_adapter *adapter,
-	      struct i2c_client_address_data *address_data,
+	      const struct i2c_client_address_data *address_data,
 	      int (*found_proc) (struct i2c_adapter *, int, int))
 {
 	int i, err;
@@ -987,7 +1045,7 @@ int i2c_probe(struct i2c_adapter *adapter,
 	/* Force entries are done first, and are not affected by ignore
 	   entries */
 	if (address_data->forces) {
-		unsigned short **forces = address_data->forces;
+		const unsigned short * const *forces = address_data->forces;
 		int kind;
 
 		for (kind = 0; forces[kind]; kind++) {
@@ -1085,7 +1143,6 @@ i2c_new_probed_device(struct i2c_adapter *adap,
 		return NULL;
 	}
 
-	mutex_lock(&adap->clist_lock);
 	for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
 		/* Check address validity */
 		if (addr_list[i] < 0x03 || addr_list[i] > 0x77) {
@@ -1095,7 +1152,7 @@ i2c_new_probed_device(struct i2c_adapter *adap,
 		}
 
 		/* Check address availability */
-		if (__i2c_check_addr(adap, addr_list[i])) {
+		if (i2c_check_addr(adap, addr_list[i])) {
 			dev_dbg(&adap->dev, "Address 0x%02x already in "
 				"use, not probing\n", addr_list[i]);
 			continue;
@@ -1123,7 +1180,6 @@ i2c_new_probed_device(struct i2c_adapter *adap,
 				break;
 		}
 	}
-	mutex_unlock(&adap->clist_lock);
 
 	if (addr_list[i] == I2C_CLIENT_END) {
 		dev_dbg(&adap->dev, "Probing failed, no device found\n");
@@ -1139,12 +1195,12 @@ struct i2c_adapter* i2c_get_adapter(int id)
 {
 	struct i2c_adapter *adapter;
 
-	mutex_lock(&core_lists);
+	mutex_lock(&core_lock);
 	adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
 	if (adapter && !try_module_get(adapter->owner))
 		adapter = NULL;
 
-	mutex_unlock(&core_lists);
+	mutex_unlock(&core_lock);
 	return adapter;
 }
 EXPORT_SYMBOL(i2c_get_adapter);
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index df540d5dfaf4..393e679d9faa 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -182,27 +182,22 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c
 	return ret;
 }
 
+static int i2cdev_check(struct device *dev, void *addrp)
+{
+	struct i2c_client *client = i2c_verify_client(dev);
+
+	if (!client || client->addr != *(unsigned int *)addrp)
+		return 0;
+
+	return dev->driver ? -EBUSY : 0;
+}
+
 /* This address checking function differs from the one in i2c-core
    in that it considers an address with a registered device, but no
-   bound driver, as NOT busy. */
+   driver bound to it, as NOT busy. */
 static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
 {
-	struct list_head *item;
-	struct i2c_client *client;
-	int res = 0;
-
-	mutex_lock(&adapter->clist_lock);
-	list_for_each(item, &adapter->clients) {
-		client = list_entry(item, struct i2c_client, list);
-		if (client->addr == addr) {
-			if (client->driver)
-				res = -EBUSY;
-			break;
-		}
-	}
-	mutex_unlock(&adapter->clist_lock);
-
-	return res;
+	return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
 }
 
 static int i2cdev_ioctl(struct inode *inode, struct file *file,
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index fb06555708a8..64df55e20ab5 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -325,7 +325,7 @@ config BLK_DEV_PLATFORM
 	  If unsure, say N.
 
 config BLK_DEV_CMD640
-	bool "CMD640 chipset bugfix/support"
+	tristate "CMD640 chipset bugfix/support"
 	depends on X86
 	---help---
 	  The CMD-Technologies CMD640 IDE chip is used on many common 486 and
@@ -359,9 +359,8 @@ config BLK_DEV_CMD640_ENHANCED
 	  Otherwise say N.
 
 config BLK_DEV_IDEPNP
-	bool "PNP EIDE support"
+	tristate "PNP EIDE support"
 	depends on PNP
-	select IDE_GENERIC
 	help
 	  If you have a PnP (Plug and Play) compatible EIDE card and
 	  would like the kernel to automatically detect and activate
@@ -374,19 +373,20 @@ comment "PCI IDE chipsets support"
 config BLK_DEV_IDEPCI
 	bool
 
-config IDEPCI_SHARE_IRQ
-	bool "Sharing PCI IDE interrupts support"
-	depends on BLK_DEV_IDEPCI
+config IDEPCI_PCIBUS_ORDER
+	bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)"
+	depends on BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+	default y
 	help
-	  Some ATA/IDE chipsets have hardware support which allows for
-	  sharing a single IRQ with other cards. To enable support for
-	  this in the ATA/IDE driver, say Y here.
+	  Probe IDE PCI devices in the order in which they appear on the
+	  PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device)
+	  instead of the order in which IDE PCI host drivers are loaded.
 
-	  It is safe to say Y to this question, in most cases.
-	  If unsure, say N.
+	  Please note that this method of assuring stable naming of
+	  IDE devices is unreliable and use other means for achieving
+	  it (i.e. udev).
 
-config IDEPCI_PCIBUS_ORDER
-	def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+	  If in doubt, say N.
 
 # TODO: split it on per host driver config options (or module parameters)
 config BLK_DEV_OFFBOARD
@@ -707,7 +707,6 @@ config BLK_DEV_SVWKS
 config BLK_DEV_SGIIOC4
 	tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
 	depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
-	select IDEPCI_SHARE_IRQ
 	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
@@ -801,7 +800,7 @@ config BLK_DEV_CELLEB
 endif
 
 config BLK_DEV_IDE_PMAC
-	bool "Builtin PowerMac IDE support"
+	tristate "Builtin PowerMac IDE support"
 	depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
 	help
 	  This driver provides support for the built-in IDE controller on
@@ -855,8 +854,9 @@ config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
        depends on BLK_DEV_IDE_AU1XXX
 
 config IDE_ARM
-	def_bool ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
-	select IDE_GENERIC
+	tristate "ARM IDE support"
+	depends on ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+	default y
 
 config BLK_DEV_IDE_ICSIDE
 	tristate "ICS IDE interface support"
@@ -888,10 +888,9 @@ config BLK_DEV_IDE_BAST
 	  Simtec BAST or the Thorcom VR1000
 
 config ETRAX_IDE
-	bool "ETRAX IDE support"
+	tristate "ETRAX IDE support"
 	depends on CRIS && BROKEN
 	select BLK_DEV_IDEDMA
-	select IDE_GENERIC
 	help
 	  Enables the ETRAX IDE driver.
 
@@ -923,17 +922,15 @@ config ETRAX_IDE_G27_RESET
 endchoice
 
 config IDE_H8300
-	bool "H8300 IDE support"
+	tristate "H8300 IDE support"
 	depends on H8300
-	select IDE_GENERIC
 	default y
 	help
 	  Enables the H8300 IDE driver.
 
 config BLK_DEV_GAYLE
-	bool "Amiga Gayle IDE interface support"
+	tristate "Amiga Gayle IDE interface support"
 	depends on AMIGA
-	select IDE_GENERIC
 	help
 	  This is the IDE driver for the Amiga Gayle IDE interface. It supports
 	  both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
@@ -963,9 +960,8 @@ config BLK_DEV_IDEDOUBLER
 	  runtime using the "ide=doubler" kernel boot parameter.
 
 config BLK_DEV_BUDDHA
-	bool "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
+	tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
 	depends on ZORRO && EXPERIMENTAL
-	select IDE_GENERIC
 	help
 	  This is the IDE driver for the IDE interfaces on the Buddha, 
 	  Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
@@ -976,9 +972,8 @@ config BLK_DEV_BUDDHA
 	  to one of its IDE interfaces.
 
 config BLK_DEV_FALCON_IDE
-	bool "Falcon IDE interface support"
+	tristate "Falcon IDE interface support"
 	depends on ATARI
-	select IDE_GENERIC
 	help
 	  This is the IDE driver for the builtin IDE interface on the Atari
 	  Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
@@ -986,9 +981,8 @@ config BLK_DEV_FALCON_IDE
 	  interface.
 
 config BLK_DEV_MAC_IDE
-	bool "Macintosh Quadra/Powerbook IDE interface support"
+	tristate "Macintosh Quadra/Powerbook IDE interface support"
 	depends on MAC
-	select IDE_GENERIC
 	help
 	  This is the IDE driver for the builtin IDE interface on some m68k
 	  Macintosh models. It supports both the `Quadra style' (used in
@@ -1000,18 +994,16 @@ config BLK_DEV_MAC_IDE
 	  builtin IDE interface.
 
 config BLK_DEV_Q40IDE
-	bool "Q40/Q60 IDE interface support"
+	tristate "Q40/Q60 IDE interface support"
 	depends on Q40
-	select IDE_GENERIC
 	help
 	  Enable the on-board IDE controller in the Q40/Q60.  This should
 	  normally be on; disable it only if you are running a custom hard
 	  drive subsystem through an expansion card.
 
 config BLK_DEV_MPC8xx_IDE
-	bool "MPC8xx IDE support"
+	tristate "MPC8xx IDE support"
 	depends on 8xx && (LWMON || IVMS8 || IVML24 || TQM8xxL) && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
-	select IDE_GENERIC
 	help
 	  This option provides support for IDE on Motorola MPC8xx Systems.
 	  Please see 'Type of MPC8xx IDE interface' for details.
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index b181fc672057..0d2da89d15cf 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -7,41 +7,37 @@
 # Note : at this point, these files are compiled on all systems.
 # In the future, some of these should be built conditionally.
 #
-# First come modules that register themselves with the core
+# link order is important here
 
 EXTRA_CFLAGS				+= -Idrivers/ide
 
-obj-$(CONFIG_BLK_DEV_IDE)		+= pci/
-
 ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o
 
-ide-core-$(CONFIG_BLK_DEV_CMD640)	+= pci/cmd640.o
-
-# Core IDE code - must come before legacy
+# core IDE code
 ide-core-$(CONFIG_BLK_DEV_IDEPCI)	+= setup-pci.o
 ide-core-$(CONFIG_BLK_DEV_IDEDMA)	+= ide-dma.o
 ide-core-$(CONFIG_IDE_PROC_FS)		+= ide-proc.o
-ide-core-$(CONFIG_BLK_DEV_IDEPNP)	+= ide-pnp.o
 ide-core-$(CONFIG_BLK_DEV_IDEACPI)	+= ide-acpi.o
 
-# built-in only drivers from arm/
-ide-core-$(CONFIG_IDE_ARM)		+= arm/ide_arm.o
+obj-$(CONFIG_BLK_DEV_IDE)		+= ide-core.o
 
-# built-in only drivers from legacy/
-ide-core-$(CONFIG_BLK_DEV_BUDDHA)	+= legacy/buddha.o
-ide-core-$(CONFIG_BLK_DEV_FALCON_IDE)	+= legacy/falconide.o
-ide-core-$(CONFIG_BLK_DEV_GAYLE)	+= legacy/gayle.o
-ide-core-$(CONFIG_BLK_DEV_MAC_IDE)	+= legacy/macide.o
-ide-core-$(CONFIG_BLK_DEV_Q40IDE)	+= legacy/q40ide.o
+ifeq ($(CONFIG_IDE_ARM), y)
+	ide-arm-core-y += arm/ide_arm.o
+	obj-y += ide-arm-core.o
+endif
 
-# built-in only drivers from ppc/
-ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ppc/mpc8xx.o
-ide-core-$(CONFIG_BLK_DEV_IDE_PMAC)	+= ppc/pmac.o
+obj-$(CONFIG_BLK_DEV_IDE)		+= legacy/ pci/
 
-# built-in only drivers from h8300/
-ide-core-$(CONFIG_IDE_H8300)		+= h8300/ide-h8300.o
+obj-$(CONFIG_IDEPCI_PCIBUS_ORDER)	+= ide-scan-pci.o
 
-obj-$(CONFIG_BLK_DEV_IDE)		+= ide-core.o
+ifeq ($(CONFIG_BLK_DEV_CMD640), y)
+	cmd640-core-y += pci/cmd640.o
+	obj-y += cmd640-core.o
+endif
+
+obj-$(CONFIG_BLK_DEV_IDE)		+= cris/ ppc/
+obj-$(CONFIG_BLK_DEV_IDEPNP)		+= ide-pnp.o
+obj-$(CONFIG_IDE_H8300)			+= h8300/
 obj-$(CONFIG_IDE_GENERIC)		+= ide-generic.o
 
 obj-$(CONFIG_BLK_DEV_IDEDISK)		+= ide-disk.o
@@ -49,6 +45,20 @@ obj-$(CONFIG_BLK_DEV_IDECD)		+= ide-cd.o
 obj-$(CONFIG_BLK_DEV_IDETAPE)		+= ide-tape.o
 obj-$(CONFIG_BLK_DEV_IDEFLOPPY)		+= ide-floppy.o
 
-obj-$(CONFIG_BLK_DEV_IDE)		+= legacy/ arm/ mips/
-obj-$(CONFIG_BLK_DEV_HD)		+= legacy/
-obj-$(CONFIG_ETRAX_IDE)		+= cris/
+ifeq ($(CONFIG_BLK_DEV_IDECS), y)
+	ide-cs-core-y += legacy/ide-cs.o
+	obj-y += ide-cs-core.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_PLATFORM), y)
+	ide-platform-core-y += legacy/ide_platform.o
+	obj-y += ide-platform-core.o
+endif
+
+obj-$(CONFIG_BLK_DEV_IDE)		+= arm/ mips/
+
+# old hd driver must be last
+ifeq ($(CONFIG_BLK_DEV_HD), y)
+	hd-core-y += legacy/hd.o
+	obj-y += hd-core.o
+endif
diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
index 6a78f0755f26..5f63ad216862 100644
--- a/drivers/ide/arm/Makefile
+++ b/drivers/ide/arm/Makefile
@@ -3,4 +3,8 @@ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
 obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
 obj-$(CONFIG_BLK_DEV_IDE_BAST)		+= bast-ide.o
 
+ifeq ($(CONFIG_IDE_ARM), m)
+	obj-m += ide_arm.o
+endif
+
 EXTRA_CFLAGS	:= -Idrivers/ide
diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
index 48db6167bb90..45bf9c825f2b 100644
--- a/drivers/ide/arm/bast-ide.c
+++ b/drivers/ide/arm/bast-ide.c
@@ -45,7 +45,7 @@ bastide_register(unsigned int base, unsigned int aux, int irq,
 	hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
 	hw.irq = irq;
 
-	ide_register_hw(&hw, NULL, 0, hwif);
+	ide_register_hw(&hw, NULL, hwif);
 
 	return 0;
 }
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index 93f71fcfc04d..8a5c7205b77c 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -272,8 +272,6 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
 	case XFER_SW_DMA_0:
 		cycle_time = 480;
 		break;
-	default:
-		return;
 	}
 
 	/*
@@ -289,26 +287,10 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
 		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
 }
 
-static void icside_dma_host_off(ide_drive_t *drive)
+static void icside_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
-static void icside_dma_off_quietly(ide_drive_t *drive)
-{
-	drive->using_dma = 0;
-}
-
-static void icside_dma_host_on(ide_drive_t *drive)
-{
-}
-
-static int icside_dma_on(ide_drive_t *drive)
-{
-	drive->using_dma = 1;
-
-	return 0;
-}
-
 static int icside_dma_end(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
@@ -424,10 +406,7 @@ static void icside_dma_init(ide_hwif_t *hwif)
 	hwif->dmatable_dma	= 0;
 	hwif->set_dma_mode	= icside_set_dma_mode;
 
-	hwif->dma_host_off	= icside_dma_host_off;
-	hwif->dma_off_quietly	= icside_dma_off_quietly;
-	hwif->dma_host_on	= icside_dma_host_on;
-	hwif->ide_dma_on	= icside_dma_on;
+	hwif->dma_host_set	= icside_dma_host_set;
 	hwif->dma_setup		= icside_dma_setup;
 	hwif->dma_exec_cmd	= icside_dma_exec_cmd;
 	hwif->dma_start		= icside_dma_start;
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
index 8957cbadf5c2..60f2497542c0 100644
--- a/drivers/ide/arm/ide_arm.c
+++ b/drivers/ide/arm/ide_arm.c
@@ -24,12 +24,25 @@
 # define IDE_ARM_IRQ	IRQ_HARDDISK
 #endif
 
-void __init ide_arm_init(void)
+static int __init ide_arm_init(void)
 {
+	ide_hwif_t *hwif;
 	hw_regs_t hw;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
 	memset(&hw, 0, sizeof(hw));
 	ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
 	hw.irq = IDE_ARM_IRQ;
-	ide_register_hw(&hw, NULL, 1, NULL);
+
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif) {
+		ide_init_port_hw(hwif, &hw);
+		idx[0] = hwif->index;
+
+		ide_device_add(idx);
+	}
+
+	return 0;
 }
+
+module_init(ide_arm_init);
diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
index 0775a3afef48..e6b56d1d48f4 100644
--- a/drivers/ide/arm/rapide.c
+++ b/drivers/ide/arm/rapide.c
@@ -13,26 +13,18 @@
 
 #include <asm/ecard.h>
 
-static ide_hwif_t *
-rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int irq)
+static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base,
+			       void __iomem *ctrl, unsigned int sz, int irq)
 {
 	unsigned long port = (unsigned long)base;
-	ide_hwif_t *hwif = ide_find_port(port);
 	int i;
 
-	if (hwif == NULL)
-		goto out;
-
 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hwif->io_ports[i] = port;
+		hw->io_ports[i] = port;
 		port += sz;
 	}
-	hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
-	hwif->irq = irq;
-	hwif->mmio = 1;
-	default_hwif_mmiops(hwif);
-out:
-	return hwif;
+	hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+	hw->irq = irq;
 }
 
 static int __devinit
@@ -42,6 +34,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
 	void __iomem *base;
 	int ret;
 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+	hw_regs_t hw;
 
 	ret = ecard_request_resources(ec);
 	if (ret)
@@ -53,11 +46,17 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
 		goto release;
 	}
 
-	hwif = rapide_locate_hwif(base, base + 0x818, 1 << 6, ec->irq);
+	hwif = ide_find_port((unsigned long)base);
 	if (hwif) {
-		hwif->hwif_data = base;
-		hwif->gendev.parent = &ec->dev;
-		hwif->noprobe = 0;
+		memset(&hw, 0, sizeof(hw));
+		rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq);
+		hw.chipset = ide_generic;
+		hw.dev = &ec->dev;
+
+		ide_init_port_hw(hwif, &hw);
+
+		hwif->mmio = 1;
+		default_hwif_mmiops(hwif);
 
 		idx[0] = hwif->index;
 
diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile
index 6176e8d6b2e6..20b95960531f 100644
--- a/drivers/ide/cris/Makefile
+++ b/drivers/ide/cris/Makefile
@@ -1,3 +1,3 @@
 EXTRA_CFLAGS				+= -Idrivers/ide
 
-obj-y					+= ide-cris.o
+obj-$(CONFIG_IDE_ETRAX)			+= ide-cris.o
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 476e0d65ed43..8c3294c4d23e 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -673,9 +673,8 @@ static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int);
 static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int);
 static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
 static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
-static int cris_dma_on (ide_drive_t *drive);
 
-static void cris_dma_off(ide_drive_t *drive)
+static void cris_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
@@ -747,8 +746,6 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
 			strobe = ATA_DMA2_STROBE;
 			hold = ATA_DMA2_HOLD;
 			break;
-		default:
-			return;
 	}
 
 	if (speed >= XFER_UDMA_0)
@@ -757,13 +754,11 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
 		cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
 }
 
-void __init
-init_e100_ide (void)
+static int __init init_e100_ide(void)
 {
 	hw_regs_t hw;
-	int ide_offsets[IDE_NR_PORTS];
-	int h;
-	int i;
+	int ide_offsets[IDE_NR_PORTS], h, i;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
 	printk("ide: ETRAX FS built-in ATA DMA controller\n");
 
@@ -780,9 +775,11 @@ init_e100_ide (void)
 		                ide_offsets,
 		                0, 0, cris_ide_ack_intr,
 		                ide_default_irq(0));
-		ide_register_hw(&hw, NULL, 1, &hwif);
+		hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
 		if (hwif == NULL)
 			continue;
+		ide_init_port_data(hwif, hwif->index);
+		ide_init_port_hw(hwif, &hw);
 		hwif->mmio = 1;
 		hwif->chipset = ide_etrax100;
 		hwif->set_pio_mode = &cris_set_pio_mode;
@@ -791,6 +788,7 @@ init_e100_ide (void)
 		hwif->ata_output_data = &cris_ide_output_data;
 		hwif->atapi_input_bytes = &cris_atapi_input_bytes;
 		hwif->atapi_output_bytes = &cris_atapi_output_bytes;
+		hwif->dma_host_set = &cris_dma_host_set;
 		hwif->ide_dma_end = &cris_dma_end;
 		hwif->dma_setup = &cris_dma_setup;
 		hwif->dma_exec_cmd = &cris_dma_exec_cmd;
@@ -801,9 +799,6 @@ init_e100_ide (void)
 		hwif->OUTBSYNC = &cris_ide_outbsync;
 		hwif->INB = &cris_ide_inb;
 		hwif->INW = &cris_ide_inw;
-		hwif->dma_host_off = &cris_dma_off;
-		hwif->dma_host_on = &cris_dma_on;
-		hwif->dma_off_quietly = &cris_dma_off;
 		hwif->cbl = ATA_CBL_PATA40;
 		hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
 		hwif->pio_mask = ATA_PIO4,
@@ -811,6 +806,8 @@ init_e100_ide (void)
 		hwif->drives[1].autotune = 1;
 		hwif->ultra_mask = cris_ultra_mask;
 		hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
+
+		idx[h] = hwif->index;
 	}
 
 	/* Reset pulse */
@@ -823,14 +820,12 @@ init_e100_ide (void)
 	cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD);
 	cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD);
 	cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0);
-}
 
-static int cris_dma_on (ide_drive_t *drive)
-{
+	ide_device_add(idx);
+
 	return 0;
 }
 
-
 static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16)));
 
 /*
@@ -1062,3 +1057,5 @@ static void cris_dma_start(ide_drive_t *drive)
 		LED_DISK_READ(1);
 	}
 }
+
+module_init(init_e100_ide);
diff --git a/drivers/ide/h8300/Makefile b/drivers/ide/h8300/Makefile
new file mode 100644
index 000000000000..5eba16f423f4
--- /dev/null
+++ b/drivers/ide/h8300/Makefile
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_IDE_H8300)			+= ide-h8300.o
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
index 4a49b5c59acb..4f6d0191cf6c 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -84,11 +84,12 @@ static inline void hwif_setup(ide_hwif_t *hwif)
 	hwif->INSL  = NULL;
 }
 
-void __init h8300_ide_init(void)
+static int __init h8300_ide_init(void)
 {
 	hw_regs_t hw;
 	ide_hwif_t *hwif;
-	int idx;
+	int index;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
 	if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300"))
 		goto out_busy;
@@ -100,16 +101,28 @@ void __init h8300_ide_init(void)
 	hw_setup(&hw);
 
 	/* register if */
-	idx = ide_register_hw(&hw, NULL, 1, &hwif);
-	if (idx == -1) {
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif == NULL) {
 		printk(KERN_ERR "ide-h8300: IDE I/F register failed\n");
-		return;
+		return -ENOENT;
 	}
 
+	index = hwif->index;
+	ide_init_port_data(hwif, index);
+	ide_init_port_hw(hwif, &hw);
 	hwif_setup(hwif);
-	printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", idx);
-	return;
+	printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", index);
+
+	idx[0] = index;
+
+	ide_device_add(idx);
+
+	return 0;
 
 out_busy:
 	printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n");
+
+	return -EBUSY;
 }
+
+module_init(h8300_ide_init);
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 899d56536e80..e888fc35b27c 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -383,27 +383,19 @@ static int taskfile_load_raw(ide_drive_t *drive,
 	       gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
 
 	memset(&args, 0, sizeof(ide_task_t));
-	args.command_type = IDE_DRIVE_TASK_NO_DATA;
-	args.data_phase   = TASKFILE_NO_DATA;
-	args.handler      = &task_no_data_intr;
 
 	/* convert gtf to IDE Taskfile */
-	args.tfRegister[1] = gtf->tfa[0];	/* 0x1f1 */
-	args.tfRegister[2] = gtf->tfa[1];	/* 0x1f2 */
-	args.tfRegister[3] = gtf->tfa[2];	/* 0x1f3 */
-	args.tfRegister[4] = gtf->tfa[3];	/* 0x1f4 */
-	args.tfRegister[5] = gtf->tfa[4];	/* 0x1f5 */
-	args.tfRegister[6] = gtf->tfa[5];	/* 0x1f6 */
-	args.tfRegister[7] = gtf->tfa[6];	/* 0x1f7 */
+	memcpy(&args.tf_array[7], &gtf->tfa, 7);
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
 	if (ide_noacpitfs) {
 		DEBPRINT("_GTF execution disabled\n");
 		return err;
 	}
 
-	err = ide_raw_taskfile(drive, &args, NULL);
+	err = ide_no_data_taskfile(drive, &args);
 	if (err)
-		printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
+		printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
 		       __FUNCTION__, err);
 
 	return err;
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index c7d77f0ad892..74c6087ada38 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -655,9 +655,9 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
 					BUG();
 			} else {
 				spin_lock_irqsave(&ide_lock, flags);
-				end_that_request_chunk(failed, 0,
-							failed->data_len);
-				end_that_request_last(failed, 0);
+				if (__blk_end_request(failed, -EIO,
+						      failed->data_len))
+					BUG();
 				spin_unlock_irqrestore(&ide_lock, flags);
 			}
 		} else
@@ -917,19 +917,13 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
 	if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY))
 		return startstop;
 
+	/* FIXME: for Virtual DMA we must check harder */
 	if (info->dma)
 		info->dma = !hwif->dma_setup(drive);
 
 	/* Set up the controller registers. */
-	/* FIXME: for Virtual DMA we must check harder */
-	HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG);
-	HWIF(drive)->OUTB(0, IDE_IREASON_REG);
-	HWIF(drive)->OUTB(0, IDE_SECTOR_REG);
-
-	HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG);
-	HWIF(drive)->OUTB(xferlen >> 8  , IDE_BCOUNTH_REG);
-	if (IDE_CONTROL_REG)
-		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+	ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL |
+			   IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma);
  
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
 		/* waiting for CDB interrupt, not DMA yet. */
@@ -1653,6 +1647,17 @@ static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
 	return 1;
 }
 
+/*
+ * Called from blk_end_request_callback() after the data of the request
+ * is completed and before the request is completed.
+ * By returning value '1', blk_end_request_callback() returns immediately
+ * without completing the request.
+ */
+static int cdrom_newpc_intr_dummy_cb(struct request *rq)
+{
+	return 1;
+}
+
 typedef void (xfer_func_t)(ide_drive_t *, void *, u32);
 
 /*
@@ -1691,9 +1696,13 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 			return ide_error(drive, "dma error", stat);
 		}
 
-		end_that_request_chunk(rq, 1, rq->data_len);
-		rq->data_len = 0;
-		goto end_request;
+		spin_lock_irqsave(&ide_lock, flags);
+		if (__blk_end_request(rq, 0, rq->data_len))
+			BUG();
+		HWGROUP(drive)->rq = NULL;
+		spin_unlock_irqrestore(&ide_lock, flags);
+
+		return ide_stopped;
 	}
 
 	/*
@@ -1711,8 +1720,15 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 	/*
 	 * If DRQ is clear, the command has completed.
 	 */
-	if ((stat & DRQ_STAT) == 0)
-		goto end_request;
+	if ((stat & DRQ_STAT) == 0) {
+		spin_lock_irqsave(&ide_lock, flags);
+		if (__blk_end_request(rq, 0, 0))
+			BUG();
+		HWGROUP(drive)->rq = NULL;
+		spin_unlock_irqrestore(&ide_lock, flags);
+
+		return ide_stopped;
+	}
 
 	/*
 	 * check which way to transfer data
@@ -1765,7 +1781,14 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 		rq->data_len -= blen;
 
 		if (rq->bio)
-			end_that_request_chunk(rq, 1, blen);
+			/*
+			 * The request can't be completed until DRQ is cleared.
+			 * So complete the data, but don't complete the request
+			 * using the dummy function for the callback feature
+			 * of blk_end_request_callback().
+			 */
+			blk_end_request_callback(rq, 0, blen,
+						 cdrom_newpc_intr_dummy_cb);
 		else
 			rq->data += blen;
 	}
@@ -1786,14 +1809,6 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
 
 	ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL);
 	return ide_started;
-
-end_request:
-	spin_lock_irqsave(&ide_lock, flags);
-	blkdev_dequeue_request(rq);
-	end_that_request_last(rq, 1);
-	HWGROUP(drive)->rq = NULL;
-	spin_unlock_irqrestore(&ide_lock, flags);
-	return ide_stopped;
 }
 
 static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index b1781908e1f2..717e114ced52 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -129,6 +129,50 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
 	return 0;	/* lba_capacity value may be bad */
 }
 
+static const u8 ide_rw_cmds[] = {
+	WIN_MULTREAD,
+	WIN_MULTWRITE,
+	WIN_MULTREAD_EXT,
+	WIN_MULTWRITE_EXT,
+	WIN_READ,
+	WIN_WRITE,
+	WIN_READ_EXT,
+	WIN_WRITE_EXT,
+	WIN_READDMA,
+	WIN_WRITEDMA,
+	WIN_READDMA_EXT,
+	WIN_WRITEDMA_EXT,
+};
+
+static const u8 ide_data_phases[] = {
+	TASKFILE_MULTI_IN,
+	TASKFILE_MULTI_OUT,
+	TASKFILE_IN,
+	TASKFILE_OUT,
+	TASKFILE_IN_DMA,
+	TASKFILE_OUT_DMA,
+};
+
+static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma)
+{
+	u8 index, lba48, write;
+
+	lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0;
+	write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0;
+
+	if (dma)
+		index = drive->vdma ? 4 : 8;
+	else
+		index = drive->mult_count ? 0 : 4;
+
+	task->tf.command = ide_rw_cmds[index + lba48 + write];
+
+	if (dma)
+		index = 8; /* fixup index */
+
+	task->data_phase = ide_data_phases[index / 2 + write];
+}
+
 /*
  * __ide_do_rw_disk() issues READ and WRITE commands to a disk,
  * using LBA if supported, or CHS otherwise, to address sectors.
@@ -137,11 +181,11 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	unsigned int dma	= drive->using_dma;
+	u16 nsectors		= (u16)rq->nr_sectors;
 	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
-	task_ioreg_t command	= WIN_NOP;
-	ata_nsector_t		nsectors;
-
-	nsectors.all		= (u16) rq->nr_sectors;
+	ide_task_t		task;
+	struct ide_taskfile	*tf = &task.tf;
+	ide_startstop_t		rc;
 
 	if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
 		if (block + rq->nr_sectors > 1ULL << 28)
@@ -155,121 +199,71 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
 		ide_map_sg(drive, rq);
 	}
 
-	if (IDE_CONTROL_REG)
-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-
-	/* FIXME: SELECT_MASK(drive, 0) ? */
+	memset(&task, 0, sizeof(task));
+	task.tf_flags = IDE_TFLAG_NO_SELECT_MASK;  /* FIXME? */
+	task.tf_flags |= (IDE_TFLAG_TF | IDE_TFLAG_DEVICE);
 
 	if (drive->select.b.lba) {
 		if (lba48) {
-			task_ioreg_t tasklets[10];
-
 			pr_debug("%s: LBA=0x%012llx\n", drive->name,
 					(unsigned long long)block);
 
-			tasklets[0] = 0;
-			tasklets[1] = 0;
-			tasklets[2] = nsectors.b.low;
-			tasklets[3] = nsectors.b.high;
-			tasklets[4] = (task_ioreg_t) block;
-			tasklets[5] = (task_ioreg_t) (block>>8);
-			tasklets[6] = (task_ioreg_t) (block>>16);
-			tasklets[7] = (task_ioreg_t) (block>>24);
-			if (sizeof(block) == 4) {
-				tasklets[8] = (task_ioreg_t) 0;
-				tasklets[9] = (task_ioreg_t) 0;
-			} else {
-				tasklets[8] = (task_ioreg_t)((u64)block >> 32);
-				tasklets[9] = (task_ioreg_t)((u64)block >> 40);
+			tf->hob_nsect = (nsectors >> 8) & 0xff;
+			tf->hob_lbal  = (u8)(block >> 24);
+			if (sizeof(block) != 4) {
+				tf->hob_lbam = (u8)((u64)block >> 32);
+				tf->hob_lbah = (u8)((u64)block >> 40);
 			}
-#ifdef DEBUG
-			printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
-				drive->name, tasklets[3], tasklets[2],
-				tasklets[9], tasklets[8], tasklets[7],
-				tasklets[6], tasklets[5], tasklets[4]);
-#endif
-			hwif->OUTB(tasklets[1], IDE_FEATURE_REG);
-			hwif->OUTB(tasklets[3], IDE_NSECTOR_REG);
-			hwif->OUTB(tasklets[7], IDE_SECTOR_REG);
-			hwif->OUTB(tasklets[8], IDE_LCYL_REG);
-			hwif->OUTB(tasklets[9], IDE_HCYL_REG);
-
-			hwif->OUTB(tasklets[0], IDE_FEATURE_REG);
-			hwif->OUTB(tasklets[2], IDE_NSECTOR_REG);
-			hwif->OUTB(tasklets[4], IDE_SECTOR_REG);
-			hwif->OUTB(tasklets[5], IDE_LCYL_REG);
-			hwif->OUTB(tasklets[6], IDE_HCYL_REG);
-			hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG);
+
+			tf->nsect  = nsectors & 0xff;
+			tf->lbal   = (u8) block;
+			tf->lbam   = (u8)(block >>  8);
+			tf->lbah   = (u8)(block >> 16);
+
+			task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
 		} else {
-			hwif->OUTB(0x00, IDE_FEATURE_REG);
-			hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
-			hwif->OUTB(block, IDE_SECTOR_REG);
-			hwif->OUTB(block>>=8, IDE_LCYL_REG);
-			hwif->OUTB(block>>=8, IDE_HCYL_REG);
-			hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+			tf->nsect  = nsectors & 0xff;
+			tf->lbal   = block;
+			tf->lbam   = block >>= 8;
+			tf->lbah   = block >>= 8;
+			tf->device = (block >> 8) & 0xf;
 		}
 	} else {
 		unsigned int sect,head,cyl,track;
 		track = (int)block / drive->sect;
 		sect  = (int)block % drive->sect + 1;
-		hwif->OUTB(sect, IDE_SECTOR_REG);
 		head  = track % drive->head;
 		cyl   = track / drive->head;
 
 		pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect);
 
-		hwif->OUTB(0x00, IDE_FEATURE_REG);
-		hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG);
-		hwif->OUTB(cyl, IDE_LCYL_REG);
-		hwif->OUTB(cyl>>8, IDE_HCYL_REG);
-		hwif->OUTB(head|drive->select.all,IDE_SELECT_REG);
+		tf->nsect  = nsectors & 0xff;
+		tf->lbal   = sect;
+		tf->lbam   = cyl;
+		tf->lbah   = cyl >> 8;
+		tf->device = head;
 	}
 
-	if (dma) {
-		if (!hwif->dma_setup(drive)) {
-			if (rq_data_dir(rq)) {
-				command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
-				if (drive->vdma)
-					command = lba48 ? WIN_WRITE_EXT: WIN_WRITE;
-			} else {
-				command = lba48 ? WIN_READDMA_EXT : WIN_READDMA;
-				if (drive->vdma)
-					command = lba48 ? WIN_READ_EXT: WIN_READ;
-			}
-			hwif->dma_exec_cmd(drive, command);
-			hwif->dma_start(drive);
-			return ide_started;
-		}
-		/* fallback to PIO */
-		ide_init_sg_cmd(drive, rq);
-	}
-
-	if (rq_data_dir(rq) == READ) {
-
-		if (drive->mult_count) {
-			hwif->data_phase = TASKFILE_MULTI_IN;
-			command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD;
-		} else {
-			hwif->data_phase = TASKFILE_IN;
-			command = lba48 ? WIN_READ_EXT : WIN_READ;
-		}
+	if (rq_data_dir(rq))
+		task.tf_flags |= IDE_TFLAG_WRITE;
 
-		ide_execute_command(drive, command, &task_in_intr, WAIT_CMD, NULL);
-		return ide_started;
-	} else {
-		if (drive->mult_count) {
-			hwif->data_phase = TASKFILE_MULTI_OUT;
-			command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
-		} else {
-			hwif->data_phase = TASKFILE_OUT;
-			command = lba48 ? WIN_WRITE_EXT : WIN_WRITE;
-		}
+	ide_tf_set_cmd(drive, &task, dma);
+	if (!dma)
+		hwif->data_phase = task.data_phase;
+	task.rq = rq;
 
-		/* FIXME: ->OUTBSYNC ? */
-		hwif->OUTB(command, IDE_COMMAND_REG);
+	rc = do_rw_taskfile(drive, &task);
 
-		return pre_task_out_intr(drive, rq);
+	if (rc == ide_stopped && dma) {
+		/* fallback to PIO */
+		task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK;
+		ide_tf_set_cmd(drive, &task, 0);
+		hwif->data_phase = task.data_phase;
+		ide_init_sg_cmd(drive, rq);
+		rc = do_rw_taskfile(drive, &task);
 	}
+
+	return rc;
 }
 
 /*
@@ -307,57 +301,29 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s
  * Queries for true maximum capacity of the drive.
  * Returns maximum LBA address (> 0) of the drive, 0 if failed.
  */
-static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48)
 {
 	ide_task_t args;
-	unsigned long addr = 0;
+	struct ide_taskfile *tf = &args.tf;
+	u64 addr = 0;
 
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
-	args.handler				= &task_no_data_intr;
+	if (lba48)
+		tf->command = WIN_READ_NATIVE_MAX_EXT;
+	else
+		tf->command = WIN_READ_NATIVE_MAX;
+	tf->device  = ATA_LBA;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+	if (lba48)
+		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
 	/* submit command request */
-	ide_raw_taskfile(drive, &args, NULL);
+	ide_no_data_taskfile(drive, &args);
 
 	/* if OK, compute maximum address value */
-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-		addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
-		     | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
-		     | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
-		     | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
-		addr++;	/* since the return value is (maxlba - 1), we add 1 */
-	}
-	return addr;
-}
+	if ((tf->status & 0x01) == 0)
+		addr = ide_get_lba_addr(tf, lba48) + 1;
 
-static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
-{
-	ide_task_t args;
-	unsigned long long addr = 0;
-
-	/* Create IDE/ATA command request structure */
-	memset(&args, 0, sizeof(ide_task_t));
-
-	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
-	args.handler				= &task_no_data_intr;
-        /* submit command request */
-        ide_raw_taskfile(drive, &args, NULL);
-
-	/* if OK, compute maximum address value */
-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-		u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
-			   (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |
-			    args.hobRegister[IDE_SECTOR_OFFSET];
-		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
-			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
-			    (args.tfRegister[IDE_SECTOR_OFFSET]);
-		addr = ((__u64)high << 24) | low;
-		addr++;	/* since the return value is (maxlba - 1), we add 1 */
-	}
 	return addr;
 }
 
@@ -365,67 +331,37 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive
  * Sets maximum virtual LBA address of the drive.
  * Returns new maximum virtual LBA address (> 0) or 0 on failure.
  */
-static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
-{
-	ide_task_t args;
-	unsigned long addr_set = 0;
-	
-	addr_req--;
-	/* Create IDE/ATA command request structure */
-	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
-	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>  8) & 0xff);
-	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
-	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
-	args.handler				= &task_no_data_intr;
-	/* submit command request */
-	ide_raw_taskfile(drive, &args, NULL);
-	/* if OK, read new maximum address value */
-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-		addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
-			 | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
-			 | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
-			 | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
-		addr_set++;
-	}
-	return addr_set;
-}
-
-static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
+static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48)
 {
 	ide_task_t args;
-	unsigned long long addr_set = 0;
+	struct ide_taskfile *tf = &args.tf;
+	u64 addr_set = 0;
 
 	addr_req--;
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
-	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
-	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
-	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;
-	args.hobRegister[IDE_SECTOR_OFFSET]	= (addr_req >>= 8) & 0xff;
-	args.hobRegister[IDE_LCYL_OFFSET]	= (addr_req >>= 8) & 0xff;
-	args.hobRegister[IDE_HCYL_OFFSET]	= (addr_req >>= 8) & 0xff;
-	args.hobRegister[IDE_SELECT_OFFSET]	= 0x40;
-	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
-	args.handler				= &task_no_data_intr;
+	tf->lbal     = (addr_req >>  0) & 0xff;
+	tf->lbam     = (addr_req >>= 8) & 0xff;
+	tf->lbah     = (addr_req >>= 8) & 0xff;
+	if (lba48) {
+		tf->hob_lbal = (addr_req >>= 8) & 0xff;
+		tf->hob_lbam = (addr_req >>= 8) & 0xff;
+		tf->hob_lbah = (addr_req >>= 8) & 0xff;
+		tf->command  = WIN_SET_MAX_EXT;
+	} else {
+		tf->device   = (addr_req >>= 8) & 0x0f;
+		tf->command  = WIN_SET_MAX;
+	}
+	tf->device |= ATA_LBA;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+	if (lba48)
+		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB);
 	/* submit command request */
-	ide_raw_taskfile(drive, &args, NULL);
+	ide_no_data_taskfile(drive, &args);
 	/* if OK, compute maximum address value */
-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-		u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) |
-			   (args.hobRegister[IDE_LCYL_OFFSET] <<  8) |
-			    args.hobRegister[IDE_SECTOR_OFFSET];
-		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
-			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
-			    (args.tfRegister[IDE_SECTOR_OFFSET]);
-		addr_set = ((__u64)high << 24) | low;
-		addr_set++;
-	}
+	if ((tf->status & 0x01) == 0)
+		addr_set = ide_get_lba_addr(tf, lba48) + 1;
+
 	return addr_set;
 }
 
@@ -471,10 +407,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
 	int lba48 = idedisk_supports_lba48(drive->id);
 
 	capacity = drive->capacity64;
-	if (lba48)
-		set_max = idedisk_read_native_max_address_ext(drive);
-	else
-		set_max = idedisk_read_native_max_address(drive);
+
+	set_max = idedisk_read_native_max_address(drive, lba48);
 
 	if (ide_in_drive_list(drive->id, hpa_list)) {
 		/*
@@ -495,10 +429,8 @@ static void idedisk_check_hpa(ide_drive_t *drive)
 			 capacity, sectors_to_MB(capacity),
 			 set_max, sectors_to_MB(set_max));
 
-	if (lba48)
-		set_max = idedisk_set_max_address_ext(drive, set_max);
-	else
-		set_max = idedisk_set_max_address(drive, set_max);
+	set_max = idedisk_set_max_address(drive, set_max, lba48);
+
 	if (set_max) {
 		drive->capacity64 = set_max;
 		printk(KERN_INFO "%s: Host Protected Area disabled.\n",
@@ -556,32 +488,32 @@ static sector_t idedisk_capacity (ide_drive_t *drive)
 static int smart_enable(ide_drive_t *drive)
 {
 	ide_task_t args;
+	struct ide_taskfile *tf = &args.tf;
 
 	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_ENABLE;
-	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
-	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
-	args.handler				= &task_no_data_intr;
-	return ide_raw_taskfile(drive, &args, NULL);
+	tf->feature = SMART_ENABLE;
+	tf->lbam    = SMART_LCYL_PASS;
+	tf->lbah    = SMART_HCYL_PASS;
+	tf->command = WIN_SMART;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+	return ide_no_data_taskfile(drive, &args);
 }
 
 static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
 {
 	ide_task_t args;
+	struct ide_taskfile *tf = &args.tf;
 
 	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_FEATURE_OFFSET]	= sub_cmd;
-	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
-	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
-	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
-	args.command_type			= IDE_DRIVE_TASK_IN;
-	args.data_phase				= TASKFILE_IN;
-	args.handler				= &task_in_intr;
+	tf->feature = sub_cmd;
+	tf->nsect   = 0x01;
+	tf->lbam    = SMART_LCYL_PASS;
+	tf->lbah    = SMART_HCYL_PASS;
+	tf->command = WIN_SMART;
+	args.tf_flags	= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+	args.data_phase	= TASKFILE_IN;
 	(void) smart_enable(drive);
-	return ide_raw_taskfile(drive, &args, buf);
+	return ide_raw_taskfile(drive, &args, buf, 1);
 }
 
 static int proc_idedisk_read_cache
@@ -659,19 +591,20 @@ static ide_proc_entry_t idedisk_proc[] = {
 static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
 {
 	ide_drive_t *drive = q->queuedata;
+	ide_task_t task;
 
-	memset(rq->cmd, 0, sizeof(rq->cmd));
-
+	memset(&task, 0, sizeof(task));
 	if (ide_id_has_flush_cache_ext(drive->id) &&
 	    (drive->capacity64 >= (1UL << 28)))
-		rq->cmd[0] = WIN_FLUSH_CACHE_EXT;
+		task.tf.command = WIN_FLUSH_CACHE_EXT;
 	else
-		rq->cmd[0] = WIN_FLUSH_CACHE;
+		task.tf.command = WIN_FLUSH_CACHE;
+	task.tf_flags	= IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE;
+	task.data_phase	= TASKFILE_NO_DATA;
 
-
-	rq->cmd_type = REQ_TYPE_ATA_TASK;
+	rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
 	rq->cmd_flags |= REQ_SOFTBARRIER;
-	rq->buffer = rq->cmd;
+	rq->special = &task;
 }
 
 /*
@@ -687,8 +620,10 @@ static int set_multcount(ide_drive_t *drive, int arg)
 
 	if (drive->special.b.set_multmode)
 		return -EBUSY;
+
 	ide_init_drive_cmd (&rq);
-	rq.cmd_type = REQ_TYPE_ATA_CMD;
+	rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+
 	drive->mult_req = arg;
 	drive->special.b.set_multmode = 1;
 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
@@ -753,12 +688,11 @@ static int write_cache(ide_drive_t *drive, int arg)
 
 	if (ide_id_has_flush_cache(drive->id)) {
 		memset(&args, 0, sizeof(ide_task_t));
-		args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?
+		args.tf.feature = arg ?
 			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
-		args.command_type		= IDE_DRIVE_TASK_NO_DATA;
-		args.handler			= &task_no_data_intr;
-		err = ide_raw_taskfile(drive, &args, NULL);
+		args.tf.command = WIN_SETFEATURES;
+		args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+		err = ide_no_data_taskfile(drive, &args);
 		if (err == 0)
 			drive->wcache = arg;
 	}
@@ -774,12 +708,11 @@ static int do_idedisk_flushcache (ide_drive_t *drive)
 
 	memset(&args, 0, sizeof(ide_task_t));
 	if (ide_id_has_flush_cache_ext(drive->id))
-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;
+		args.tf.command = WIN_FLUSH_CACHE_EXT;
 	else
-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;
-	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
-	args.handler				= &task_no_data_intr;
-	return ide_raw_taskfile(drive, &args, NULL);
+		args.tf.command = WIN_FLUSH_CACHE;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+	return ide_no_data_taskfile(drive, &args);
 }
 
 static int set_acoustic (ide_drive_t *drive, int arg)
@@ -790,13 +723,11 @@ static int set_acoustic (ide_drive_t *drive, int arg)
 		return -EINVAL;
 
 	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ? SETFEATURES_EN_AAM :
-							  SETFEATURES_DIS_AAM;
-	args.tfRegister[IDE_NSECTOR_OFFSET]	= arg;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
-	args.command_type = IDE_DRIVE_TASK_NO_DATA;
-	args.handler	  = &task_no_data_intr;
-	ide_raw_taskfile(drive, &args, NULL);
+	args.tf.feature = arg ? SETFEATURES_EN_AAM : SETFEATURES_DIS_AAM;
+	args.tf.nsect   = arg;
+	args.tf.command = WIN_SETFEATURES;
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+	ide_no_data_taskfile(drive, &args);
 	drive->acoustic = arg;
 	return 0;
 }
@@ -832,7 +763,6 @@ static void idedisk_add_settings(ide_drive_t *drive)
 	ide_add_setting(drive,	"bios_head",	SETTING_RW,	TYPE_BYTE,	0,	255,			1,	1,	&drive->bios_head,	NULL);
 	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	TYPE_BYTE,	0,	63,			1,	1,	&drive->bios_sect,	NULL);
 	ide_add_setting(drive,	"address",	SETTING_RW,	TYPE_BYTE,	0,	2,			1,	1,	&drive->addressing,	set_lba_addressing);
-	ide_add_setting(drive,	"bswap",	SETTING_READ,	TYPE_BYTE,	0,	1,			1,	1,	&drive->bswap,		NULL);
 	ide_add_setting(drive,	"multcount",	SETTING_RW,	TYPE_BYTE,	0,	id->max_multsect,	1,	1,	&drive->mult_count,	set_multcount);
 	ide_add_setting(drive,	"nowerr",	SETTING_RW,	TYPE_BYTE,	0,	1,			1,	1,	&drive->nowerr,		set_nowerr);
 	ide_add_setting(drive,	"lun",		SETTING_RW,	TYPE_INT,	0,	7,			1,	1,	&drive->lun,		NULL);
@@ -1041,6 +971,17 @@ static ide_driver_t idedisk_driver = {
 #endif
 };
 
+static int idedisk_set_doorlock(ide_drive_t *drive, int on)
+{
+	ide_task_t task;
+
+	memset(&task, 0, sizeof(task));
+	task.tf.command = on ? WIN_DOORLOCK : WIN_DOORUNLOCK;
+	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+
+	return ide_no_data_taskfile(drive, &task);
+}
+
 static int idedisk_open(struct inode *inode, struct file *filp)
 {
 	struct gendisk *disk = inode->i_bdev->bd_disk;
@@ -1055,18 +996,13 @@ static int idedisk_open(struct inode *inode, struct file *filp)
 	idkp->openers++;
 
 	if (drive->removable && idkp->openers == 1) {
-		ide_task_t args;
-		memset(&args, 0, sizeof(ide_task_t));
-		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
-		args.command_type = IDE_DRIVE_TASK_NO_DATA;
-		args.handler	  = &task_no_data_intr;
 		check_disk_change(inode->i_bdev);
 		/*
 		 * Ignore the return code from door_lock,
 		 * since the open() has already succeeded,
 		 * and the door_lock is irrelevant at this point.
 		 */
-		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
+		if (drive->doorlocking && idedisk_set_doorlock(drive, 1))
 			drive->doorlocking = 0;
 	}
 	return 0;
@@ -1082,12 +1018,7 @@ static int idedisk_release(struct inode *inode, struct file *filp)
 		ide_cacheflush_p(drive);
 
 	if (drive->removable && idkp->openers == 1) {
-		ide_task_t args;
-		memset(&args, 0, sizeof(ide_task_t));
-		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
-		args.command_type = IDE_DRIVE_TASK_NO_DATA;
-		args.handler	  = &task_no_data_intr;
-		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
+		if (drive->doorlocking && idedisk_set_doorlock(drive, 0))
 			drive->doorlocking = 0;
 	}
 
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 4703837bf1fc..5bf32038dc43 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -153,13 +153,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
 		if (!dma_stat) {
 			struct request *rq = HWGROUP(drive)->rq;
 
-			if (rq->rq_disk) {
-				ide_driver_t *drv;
-
-				drv = *(ide_driver_t **)rq->rq_disk->private_data;
-				drv->end_request(drive, 1, rq->nr_sectors);
-			} else
-				ide_end_request(drive, 1, rq->nr_sectors);
+			task_end_request(drive, rq, stat);
 			return ide_stopped;
 		}
 		printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
@@ -408,23 +402,29 @@ static int dma_timer_expiry (ide_drive_t *drive)
 }
 
 /**
- *	ide_dma_host_off	-	Generic DMA kill
+ *	ide_dma_host_set	-	Enable/disable DMA on a host
  *	@drive: drive to control
  *
- *	Perform the generic IDE controller DMA off operation. This
- *	works for most IDE bus mastering controllers
+ *	Enable/disable DMA on an IDE controller following generic
+ *	bus-mastering IDE controller behaviour.
  */
 
-void ide_dma_host_off(ide_drive_t *drive)
+void ide_dma_host_set(ide_drive_t *drive, int on)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u8 unit			= (drive->select.b.unit & 0x01);
 	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-	hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
+	if (on)
+		dma_stat |= (1 << (5 + unit));
+	else
+		dma_stat &= ~(1 << (5 + unit));
+
+	hwif->OUTB(dma_stat, hwif->dma_status);
 }
 
-EXPORT_SYMBOL(ide_dma_host_off);
+EXPORT_SYMBOL_GPL(ide_dma_host_set);
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 /**
  *	ide_dma_off_quietly	-	Generic DMA kill
@@ -438,11 +438,10 @@ void ide_dma_off_quietly(ide_drive_t *drive)
 	drive->using_dma = 0;
 	ide_toggle_bounce(drive, 0);
 
-	drive->hwif->dma_host_off(drive);
+	drive->hwif->dma_host_set(drive, 0);
 }
 
 EXPORT_SYMBOL(ide_dma_off_quietly);
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 /**
  *	ide_dma_off	-	disable DMA on a device
@@ -455,56 +454,29 @@ EXPORT_SYMBOL(ide_dma_off_quietly);
 void ide_dma_off(ide_drive_t *drive)
 {
 	printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-	drive->hwif->dma_off_quietly(drive);
+	ide_dma_off_quietly(drive);
 }
 
 EXPORT_SYMBOL(ide_dma_off);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
- *	ide_dma_host_on	-	Enable DMA on a host
- *	@drive: drive to enable for DMA
- *
- *	Enable DMA on an IDE controller following generic bus mastering
- *	IDE controller behaviour
- */
-
-void ide_dma_host_on(ide_drive_t *drive)
-{
-	if (drive->using_dma) {
-		ide_hwif_t *hwif	= HWIF(drive);
-		u8 unit			= (drive->select.b.unit & 0x01);
-		u8 dma_stat		= hwif->INB(hwif->dma_status);
-
-		hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
-	}
-}
-
-EXPORT_SYMBOL(ide_dma_host_on);
-
-/**
- *	__ide_dma_on		-	Enable DMA on a device
+ *	ide_dma_on		-	Enable DMA on a device
  *	@drive: drive to enable DMA on
  *
  *	Enable IDE DMA for a device on this IDE controller.
  */
- 
-int __ide_dma_on (ide_drive_t *drive)
-{
-	/* consult the list of known "bad" drives */
-	if (__ide_dma_bad_drive(drive))
-		return 1;
 
+void ide_dma_on(ide_drive_t *drive)
+{
 	drive->using_dma = 1;
 	ide_toggle_bounce(drive, 1);
 
-	drive->hwif->dma_host_on(drive);
-
-	return 0;
+	drive->hwif->dma_host_set(drive, 1);
 }
 
-EXPORT_SYMBOL(__ide_dma_on);
+EXPORT_SYMBOL(ide_dma_on);
 
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
  *	ide_dma_setup	-	begin a DMA phase
  *	@drive: target device
@@ -759,6 +731,7 @@ EXPORT_SYMBOL_GPL(ide_find_dma_mode);
 
 static int ide_tune_dma(ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = drive->hwif;
 	u8 speed;
 
 	if (noautodma || drive->nodma || (drive->id->capability & 1) == 0)
@@ -771,15 +744,21 @@ static int ide_tune_dma(ide_drive_t *drive)
 	if (ide_id_dma_bug(drive))
 		return 0;
 
-	if (drive->hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+	if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
 		return config_drive_for_dma(drive);
 
 	speed = ide_max_dma_mode(drive);
 
-	if (!speed)
-		return 0;
+	if (!speed) {
+		 /* is this really correct/needed? */
+		if ((hwif->host_flags & IDE_HFLAG_CY82C693) &&
+		    ide_dma_good_drive(drive))
+			return 1;
+		else
+			return 0;
+	}
 
-	if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+	if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
 		return 0;
 
 	if (ide_set_dma_mode(drive, speed))
@@ -824,25 +803,23 @@ err_out:
 
 int ide_set_dma(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = drive->hwif;
 	int rc;
 
+	/*
+	 * Force DMAing for the beginning of the check.
+	 * Some chipsets appear to do interesting
+	 * things, if not checked and cleared.
+	 *   PARANOIA!!!
+	 */
+	ide_dma_off_quietly(drive);
+
 	rc = ide_dma_check(drive);
+	if (rc)
+		return rc;
 
-	switch(rc) {
-	case -1: /* DMA needs to be disabled */
-		hwif->dma_off_quietly(drive);
-		return -1;
-	case  0: /* DMA needs to be enabled */
-		return hwif->ide_dma_on(drive);
-	case  1: /* DMA setting cannot be changed */
-		break;
-	default:
-		BUG();
-		break;
-	}
+	ide_dma_on(drive);
 
-	return rc;
+	return 0;
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
@@ -968,11 +945,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
 
 	hwif->dma_base = base;
 
-	if (hwif->mate)
-		hwif->dma_master = hwif->channel ? hwif->mate->dma_base : base;
-	else
-		hwif->dma_master = base;
-
 	if (!(hwif->dma_command))
 		hwif->dma_command	= hwif->dma_base;
 	if (!(hwif->dma_vendor1))
@@ -984,14 +956,8 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
 	if (!(hwif->dma_prdtable))
 		hwif->dma_prdtable	= (hwif->dma_base + 4);
 
-	if (!hwif->dma_off_quietly)
-		hwif->dma_off_quietly = &ide_dma_off_quietly;
-	if (!hwif->dma_host_off)
-		hwif->dma_host_off = &ide_dma_host_off;
-	if (!hwif->ide_dma_on)
-		hwif->ide_dma_on = &__ide_dma_on;
-	if (!hwif->dma_host_on)
-		hwif->dma_host_on = &ide_dma_host_on;
+	if (!hwif->dma_host_set)
+		hwif->dma_host_set = &ide_dma_host_set;
 	if (!hwif->dma_setup)
 		hwif->dma_setup = &ide_dma_setup;
 	if (!hwif->dma_exec_cmd)
@@ -1014,8 +980,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
 		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
 	}
 	printk("\n");
-
-	BUG_ON(!hwif->dma_master);
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_dma);
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 04a357808f2e..ff8232ef9659 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -369,27 +369,6 @@ typedef struct ide_floppy_obj {
 #define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602
 #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603
 
-#if 0
-/*
- *	Special requests for our block device strategy routine.
- */
-#define	IDEFLOPPY_FIRST_RQ	90
-
-/*
- * 	IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue.
- */
-#define	IDEFLOPPY_PC_RQ		90
-
-#define IDEFLOPPY_LAST_RQ	90
-
-/*
- *	A macro which can be used to check if a given request command
- *	originated in the driver or in the buffer cache layer.
- */
-#define IDEFLOPPY_RQ_CMD(cmd) 	((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ))
-
-#endif
-
 /*
  *	Error codes which are returned in rq->errors to the higher part
  *	of the driver.
@@ -793,9 +772,8 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
 {
 	idefloppy_pc_t *pc;
 	struct request *rq;
-	atapi_error_t error;
 
-	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+	(void)drive->hwif->INB(IDE_ERROR_REG);
 	pc = idefloppy_next_pc_storage(drive);
 	rq = idefloppy_next_rq_storage(drive);
 	idefloppy_create_request_sense_cmd(pc);
@@ -809,12 +787,12 @@ static void idefloppy_retry_pc (ide_drive_t *drive)
 static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	atapi_status_t status;
-	atapi_bcount_t bcount;
-	atapi_ireason_t ireason;
+	ide_hwif_t *hwif = drive->hwif;
 	idefloppy_pc_t *pc = floppy->pc;
 	struct request *rq = pc->rq;
 	unsigned int temp;
+	u16 bcount;
+	u8 stat, ireason;
 
 	debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n",
 		__FUNCTION__);
@@ -830,16 +808,16 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 	}
 
 	/* Clear the interrupt */
-	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+	stat = drive->hwif->INB(IDE_STATUS_REG);
 
-	if (!status.b.drq) {			/* No more interrupts */
+	if ((stat & DRQ_STAT) == 0) {		/* No more interrupts */
 		debug_log(KERN_INFO "Packet command completed, %d bytes "
 			"transferred\n", pc->actually_transferred);
 		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
 		local_irq_enable_in_hardirq();
 
-		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
+		if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
 			/* Error detected */
 			debug_log(KERN_INFO "ide-floppy: %s: I/O error\n",
 				drive->name);
@@ -870,32 +848,32 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 	}
 
 	/* Get the number of bytes to transfer */
-	bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG);
-	bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
+		  hwif->INB(IDE_BCOUNTL_REG);
 	/* on this interrupt */
-	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
+	ireason = hwif->INB(IDE_IREASON_REG);
 
-	if (ireason.b.cod) {
+	if (ireason & CD) {
 		printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n");
 		return ide_do_reset(drive);
 	}
-	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+	if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
 		/* Hopefully, we will never get here */
 		printk(KERN_ERR "ide-floppy: We wanted to %s, ",
-			ireason.b.io ? "Write":"Read");
+				(ireason & IO) ? "Write" : "Read");
 		printk(KERN_ERR "but the floppy wants us to %s !\n",
-			ireason.b.io ? "Read":"Write");
+				(ireason & IO) ? "Read" : "Write");
 		return ide_do_reset(drive);
 	}
 	if (!test_bit(PC_WRITING, &pc->flags)) {
 		/* Reading - Check that we have enough space */
-		temp = pc->actually_transferred + bcount.all;
+		temp = pc->actually_transferred + bcount;
 		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
 				printk(KERN_ERR "ide-floppy: The floppy wants "
 					"to send us more data than expected "
 					"- discarding data\n");
-				idefloppy_discard_data(drive,bcount.all);
+				idefloppy_discard_data(drive, bcount);
 				BUG_ON(HWGROUP(drive)->handler != NULL);
 				ide_set_handler(drive,
 						&idefloppy_pc_intr,
@@ -911,23 +889,21 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
 	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->buffer != NULL)
 			/* Write the current buffer */
-			HWIF(drive)->atapi_output_bytes(drive,
-						pc->current_position,
-						bcount.all);
+			hwif->atapi_output_bytes(drive, pc->current_position,
+						 bcount);
 		else
-			idefloppy_output_buffers(drive, pc, bcount.all);
+			idefloppy_output_buffers(drive, pc, bcount);
 	} else {
 		if (pc->buffer != NULL)
 			/* Read the current buffer */
-			HWIF(drive)->atapi_input_bytes(drive,
-						pc->current_position,
-						bcount.all);
+			hwif->atapi_input_bytes(drive, pc->current_position,
+						bcount);
 		else
-			idefloppy_input_buffers(drive, pc, bcount.all);
+			idefloppy_input_buffers(drive, pc, bcount);
 	}
 	/* Update the current position */
-	pc->actually_transferred += bcount.all;
-	pc->current_position += bcount.all;
+	pc->actually_transferred += bcount;
+	pc->current_position += bcount;
 
 	BUG_ON(HWGROUP(drive)->handler != NULL);
 	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
@@ -943,15 +919,15 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive)
 {
 	ide_startstop_t startstop;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	atapi_ireason_t ireason;
+	u8 ireason;
 
 	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
 		printk(KERN_ERR "ide-floppy: Strange, packet command "
 				"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
-	if (!ireason.b.cod || ireason.b.io) {
+	ireason = drive->hwif->INB(IDE_IREASON_REG);
+	if ((ireason & CD) == 0 || (ireason & IO)) {
 		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
 				"issuing a packet command\n");
 		return ide_do_reset(drive);
@@ -991,15 +967,15 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	ide_startstop_t startstop;
-	atapi_ireason_t ireason;
+	u8 ireason;
 
 	if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
 		printk(KERN_ERR "ide-floppy: Strange, packet command "
 				"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
-	if (!ireason.b.cod || ireason.b.io) {
+	ireason = drive->hwif->INB(IDE_IREASON_REG);
+	if ((ireason & CD) == 0 || (ireason & IO)) {
 		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
 				"while issuing a packet command\n");
 		return ide_do_reset(drive);
@@ -1041,21 +1017,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 	ide_hwif_t *hwif = drive->hwif;
-	atapi_feature_t feature;
-	atapi_bcount_t bcount;
 	ide_handler_t *pkt_xfer_routine;
-
-#if 0 /* Accessing floppy->pc is not valid here, the previous pc may be gone
-         and have lived on another thread's stack; that stack may have become
-         unmapped meanwhile (CONFIG_DEBUG_PAGEALLOC). */
-#if IDEFLOPPY_DEBUG_BUGS
-	if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD &&
-	    pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) {
-		printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - "
-			"Two request sense in serial were issued\n");
-	}
-#endif /* IDEFLOPPY_DEBUG_BUGS */
-#endif
+	u16 bcount;
+	u8 dma;
 
 	if (floppy->failed_pc == NULL &&
 	    pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD)
@@ -1093,25 +1057,20 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p
 	/* We haven't transferred any data yet */
 	pc->actually_transferred = 0;
 	pc->current_position = pc->buffer;
-	bcount.all = min(pc->request_transfer, 63 * 1024);
+	bcount = min(pc->request_transfer, 63 * 1024);
 
 	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags))
 		ide_dma_off(drive);
 
-	feature.all = 0;
+	dma = 0;
 
 	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		feature.b.dma = !hwif->dma_setup(drive);
+		dma = !hwif->dma_setup(drive);
 
-	if (IDE_CONTROL_REG)
-		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
-	/* Use PIO/DMA */
-	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
-	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
-	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
-	HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
+	ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
+			   IDE_TFLAG_OUT_DEVICE, bcount, dma);
 
-	if (feature.b.dma) {	/* Begin DMA, if necessary */
+	if (dma) {	/* Begin DMA, if necessary */
 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 		hwif->dma_start(drive);
 	}
@@ -1665,14 +1624,14 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg)
 		/* Else assume format_unit has finished, and we're
 		** at 0x10000 */
 	} else {
-		atapi_status_t status;
 		unsigned long flags;
+		u8 stat;
 
 		local_irq_save(flags);
-		status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+		stat = drive->hwif->INB(IDE_STATUS_REG);
 		local_irq_restore(flags);
 
-		progress_indication = !status.b.dsc ? 0 : 0x10000;
+		progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000;
 	}
 	if (put_user(progress_indication, arg))
 		return (-EFAULT);
diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c
index 0f72b98d727f..bb30c29f6ec0 100644
--- a/drivers/ide/ide-generic.c
+++ b/drivers/ide/ide-generic.c
@@ -14,10 +14,16 @@
 
 static int __init ide_generic_init(void)
 {
+	u8 idx[MAX_HWIFS];
+	int i;
+
 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
 		ide_get_lock(NULL, NULL); /* for atari only */
 
-	(void)ideprobe_init();
+	for (i = 0; i < MAX_HWIFS; i++)
+		idx[i] = ide_hwifs[i].present ? 0xff : i;
+
+	ide_device_add_all(idx);
 
 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
 		ide_release_lock();	/* for atari only */
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index bef781fec500..e6bb9cf24e3d 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -58,15 +58,19 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
 			     int uptodate, unsigned int nr_bytes, int dequeue)
 {
 	int ret = 1;
+	int error = 0;
+
+	if (uptodate <= 0)
+		error = uptodate ? uptodate : -EIO;
 
 	/*
 	 * if failfast is set on a request, override number of sectors and
 	 * complete the whole request right now
 	 */
-	if (blk_noretry_request(rq) && end_io_error(uptodate))
+	if (blk_noretry_request(rq) && error)
 		nr_bytes = rq->hard_nr_sectors << 9;
 
-	if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
+	if (!blk_fs_request(rq) && error && !rq->errors)
 		rq->errors = -EIO;
 
 	/*
@@ -75,17 +79,12 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
 	 */
 	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
 		drive->state = 0;
-		HWGROUP(drive)->hwif->ide_dma_on(drive);
+		ide_dma_on(drive);
 	}
 
-	if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
-		add_disk_randomness(rq->rq_disk);
-		if (dequeue) {
-			if (!list_empty(&rq->queuelist))
-				blkdev_dequeue_request(rq);
+	if (!__blk_end_request(rq, error, nr_bytes)) {
+		if (dequeue)
 			HWGROUP(drive)->rq = NULL;
-		}
-		end_that_request_last(rq, uptodate);
 		ret = 0;
 	}
 
@@ -189,18 +188,14 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
 			return ide_stopped;
 		}
 		if (ide_id_has_flush_cache_ext(drive->id))
-			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT;
+			args->tf.command = WIN_FLUSH_CACHE_EXT;
 		else
-			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE;
-		args->command_type = IDE_DRIVE_TASK_NO_DATA;
-		args->handler	   = &task_no_data_intr;
-		return do_rw_taskfile(drive, args);
+			args->tf.command = WIN_FLUSH_CACHE;
+		goto out_do_tf;
 
 	case idedisk_pm_standby:	/* Suspend step 2 (standby) */
-		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1;
-		args->command_type = IDE_DRIVE_TASK_NO_DATA;
-		args->handler	   = &task_no_data_intr;
-		return do_rw_taskfile(drive, args);
+		args->tf.command = WIN_STANDBYNOW1;
+		goto out_do_tf;
 
 	case idedisk_pm_restore_pio:	/* Resume step 1 (restore PIO) */
 		ide_set_max_pio(drive);
@@ -214,10 +209,8 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
 		return ide_stopped;
 
 	case idedisk_pm_idle:		/* Resume step 2 (idle) */
-		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE;
-		args->command_type = IDE_DRIVE_TASK_NO_DATA;
-		args->handler = task_no_data_intr;
-		return do_rw_taskfile(drive, args);
+		args->tf.command = WIN_IDLEIMMEDIATE;
+		goto out_do_tf;
 
 	case ide_pm_restore_dma:	/* Resume step 3 (restore DMA) */
 		/*
@@ -225,9 +218,8 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
 		 * we could be smarter and check for current xfer_speed
 		 * in struct drive etc...
 		 */
-		if (drive->hwif->ide_dma_on == NULL)
+		if (drive->hwif->dma_host_set == NULL)
 			break;
-		drive->hwif->dma_off_quietly(drive);
 		/*
 		 * TODO: respect ->using_dma setting
 		 */
@@ -236,6 +228,11 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
 	}
 	pm->pm_step = ide_pm_state_completed;
 	return ide_stopped;
+
+out_do_tf:
+	args->tf_flags	 = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+	args->data_phase = TASKFILE_NO_DATA;
+	return do_rw_taskfile(drive, args);
 }
 
 /**
@@ -292,12 +289,54 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
 		drive->blocked = 0;
 		blk_start_queue(drive->queue);
 	}
-	blkdev_dequeue_request(rq);
 	HWGROUP(drive)->rq = NULL;
-	end_that_request_last(rq, 1);
+	if (__blk_end_request(rq, 0, 0))
+		BUG();
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	struct ide_taskfile *tf = &task->tf;
+
+	if (task->tf_flags & IDE_TFLAG_IN_DATA) {
+		u16 data = hwif->INW(IDE_DATA_REG);
+
+		tf->data = data & 0xff;
+		tf->hob_data = (data >> 8) & 0xff;
+	}
+
+	/* be sure we're looking at the low order bits */
+	hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
+
+	if (task->tf_flags & IDE_TFLAG_IN_NSECT)
+		tf->nsect  = hwif->INB(IDE_NSECTOR_REG);
+	if (task->tf_flags & IDE_TFLAG_IN_LBAL)
+		tf->lbal   = hwif->INB(IDE_SECTOR_REG);
+	if (task->tf_flags & IDE_TFLAG_IN_LBAM)
+		tf->lbam   = hwif->INB(IDE_LCYL_REG);
+	if (task->tf_flags & IDE_TFLAG_IN_LBAH)
+		tf->lbah   = hwif->INB(IDE_HCYL_REG);
+	if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
+		tf->device = hwif->INB(IDE_SELECT_REG);
+
+	if (task->tf_flags & IDE_TFLAG_LBA48) {
+		hwif->OUTB(drive->ctl | 0x80, IDE_CONTROL_REG);
+
+		if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
+			tf->hob_feature = hwif->INB(IDE_FEATURE_REG);
+		if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
+			tf->hob_nsect   = hwif->INB(IDE_NSECTOR_REG);
+		if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
+			tf->hob_lbal    = hwif->INB(IDE_SECTOR_REG);
+		if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
+			tf->hob_lbam    = hwif->INB(IDE_LCYL_REG);
+		if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
+			tf->hob_lbah    = hwif->INB(IDE_HCYL_REG);
+	}
+}
+
 /**
  *	ide_end_drive_cmd	-	end an explicit drive command
  *	@drive: command 
@@ -314,7 +353,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
  
 void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
 {
-	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long flags;
 	struct request *rq;
 
@@ -322,61 +360,18 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
 	rq = HWGROUP(drive)->rq;
 	spin_unlock_irqrestore(&ide_lock, flags);
 
-	if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
-		u8 *args = (u8 *) rq->buffer;
-		if (rq->errors == 0)
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-
-		if (args) {
-			args[0] = stat;
-			args[1] = err;
-			args[2] = hwif->INB(IDE_NSECTOR_REG);
-		}
-	} else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
-		u8 *args = (u8 *) rq->buffer;
-		if (rq->errors == 0)
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
-
-		if (args) {
-			args[0] = stat;
-			args[1] = err;
-			/* be sure we're looking at the low order bits */
-			hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
-			args[2] = hwif->INB(IDE_NSECTOR_REG);
-			args[3] = hwif->INB(IDE_SECTOR_REG);
-			args[4] = hwif->INB(IDE_LCYL_REG);
-			args[5] = hwif->INB(IDE_HCYL_REG);
-			args[6] = hwif->INB(IDE_SELECT_REG);
-		}
-	} else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
 		ide_task_t *args = (ide_task_t *) rq->special;
 		if (rq->errors == 0)
 			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 			
 		if (args) {
-			if (args->tf_in_flags.b.data) {
-				u16 data				= hwif->INW(IDE_DATA_REG);
-				args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
-				args->hobRegister[IDE_DATA_OFFSET]	= (data >> 8) & 0xFF;
-			}
-			args->tfRegister[IDE_ERROR_OFFSET]   = err;
-			/* be sure we're looking at the low order bits */
-			hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
-			args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
-			args->tfRegister[IDE_SECTOR_OFFSET]  = hwif->INB(IDE_SECTOR_REG);
-			args->tfRegister[IDE_LCYL_OFFSET]    = hwif->INB(IDE_LCYL_REG);
-			args->tfRegister[IDE_HCYL_OFFSET]    = hwif->INB(IDE_HCYL_REG);
-			args->tfRegister[IDE_SELECT_OFFSET]  = hwif->INB(IDE_SELECT_REG);
-			args->tfRegister[IDE_STATUS_OFFSET]  = stat;
-
-			if (drive->addressing == 1) {
-				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
-				args->hobRegister[IDE_FEATURE_OFFSET]	= hwif->INB(IDE_FEATURE_REG);
-				args->hobRegister[IDE_NSECTOR_OFFSET]	= hwif->INB(IDE_NSECTOR_REG);
-				args->hobRegister[IDE_SECTOR_OFFSET]	= hwif->INB(IDE_SECTOR_REG);
-				args->hobRegister[IDE_LCYL_OFFSET]	= hwif->INB(IDE_LCYL_REG);
-				args->hobRegister[IDE_HCYL_OFFSET]	= hwif->INB(IDE_HCYL_REG);
-			}
+			struct ide_taskfile *tf = &args->tf;
+
+			tf->error = err;
+			tf->status = stat;
+
+			ide_tf_read(drive, args);
 		}
 	} else if (blk_pm_request(rq)) {
 		struct request_pm_state *pm = rq->data;
@@ -391,10 +386,10 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
 	}
 
 	spin_lock_irqsave(&ide_lock, flags);
-	blkdev_dequeue_request(rq);
 	HWGROUP(drive)->rq = NULL;
 	rq->errors = err;
-	end_that_request_last(rq, !rq->errors);
+	if (__blk_end_request(rq, (rq->errors ? -EIO : 0), 0))
+		BUG();
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
@@ -615,90 +610,26 @@ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg)
 		return __ide_abort(drive, rq);
 }
 
-/**
- *	ide_cmd		-	issue a simple drive command
- *	@drive: drive the command is for
- *	@cmd: command byte
- *	@nsect: sector byte
- *	@handler: handler for the command completion
- *
- *	Issue a simple drive command with interrupts.
- *	The drive must be selected beforehand.
- */
-
-static void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect,
-		ide_handler_t *handler)
+static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
-	ide_hwif_t *hwif = HWIF(drive);
-	if (IDE_CONTROL_REG)
-		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(drive,0);
-	hwif->OUTB(nsect,IDE_NSECTOR_REG);
-	ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL);
+	tf->nsect   = drive->sect;
+	tf->lbal    = drive->sect;
+	tf->lbam    = drive->cyl;
+	tf->lbah    = drive->cyl >> 8;
+	tf->device  = ((drive->head - 1) | drive->select.all) & ~ATA_LBA;
+	tf->command = WIN_SPECIFY;
 }
 
-/**
- *	drive_cmd_intr		- 	drive command completion interrupt
- *	@drive: drive the completion interrupt occurred on
- *
- *	drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
- *	We do any necessary data reading and then wait for the drive to
- *	go non busy. At that point we may read the error data and complete
- *	the request
- */
- 
-static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
+static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
-	struct request *rq = HWGROUP(drive)->rq;
-	ide_hwif_t *hwif = HWIF(drive);
-	u8 *args = (u8 *) rq->buffer;
-	u8 stat = hwif->INB(IDE_STATUS_REG);
-	int retries = 10;
-
-	local_irq_enable_in_hardirq();
-	if (rq->cmd_type == REQ_TYPE_ATA_CMD &&
-	    (stat & DRQ_STAT) && args && args[3]) {
-		u8 io_32bit = drive->io_32bit;
-		drive->io_32bit = 0;
-		hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
-		drive->io_32bit = io_32bit;
-		while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
-			udelay(100);
-	}
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "drive_cmd", stat);
-		/* calls ide_end_drive_cmd */
-	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
-	return ide_stopped;
+	tf->nsect   = drive->sect;
+	tf->command = WIN_RESTORE;
 }
 
-static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task)
+static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
 {
-	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
-	task->tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
-	task->tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
-	task->tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
-	task->tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
-	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
-
-	task->handler = &set_geometry_intr;
-}
-
-static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task)
-{
-	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
-	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
-
-	task->handler = &recal_intr;
-}
-
-static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task)
-{
-	task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
-	task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
-
-	task->handler = &set_multmode_intr;
+	tf->nsect   = drive->mult_req;
+	tf->command = WIN_SETMULT;
 }
 
 static ide_startstop_t ide_disk_special(ide_drive_t *drive)
@@ -707,19 +638,19 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
 	ide_task_t args;
 
 	memset(&args, 0, sizeof(ide_task_t));
-	args.command_type = IDE_DRIVE_TASK_NO_DATA;
+	args.data_phase = TASKFILE_NO_DATA;
 
 	if (s->b.set_geometry) {
 		s->b.set_geometry = 0;
-		ide_init_specify_cmd(drive, &args);
+		ide_tf_set_specify_cmd(drive, &args.tf);
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
-		ide_init_restore_cmd(drive, &args);
+		ide_tf_set_restore_cmd(drive, &args.tf);
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->mult_req > drive->id->max_multsect)
 			drive->mult_req = drive->id->max_multsect;
-		ide_init_setmult_cmd(drive, &args);
+		ide_tf_set_setmult_cmd(drive, &args.tf);
 	} else if (s->all) {
 		int special = s->all;
 		s->all = 0;
@@ -727,6 +658,9 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
 		return ide_stopped;
 	}
 
+	args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE |
+			IDE_TFLAG_CUSTOM_HANDLER;
+
 	do_rw_taskfile(drive, &args);
 
 	return ide_started;
@@ -801,7 +735,7 @@ static ide_startstop_t do_special (ide_drive_t *drive)
 
 			if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
 				if (keep_dma)
-					hwif->ide_dma_on(drive);
+					ide_dma_on(drive);
 			}
 		}
 
@@ -861,13 +795,10 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
 		struct request *rq)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
- 		ide_task_t *args = rq->special;
- 
-		if (!args)
-			goto done;
+	ide_task_t *task = rq->special;
 
-		hwif->data_phase = args->data_phase;
+	if (task) {
+		hwif->data_phase = task->data_phase;
 
 		switch (hwif->data_phase) {
 		case TASKFILE_MULTI_OUT:
@@ -880,57 +811,9 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
 			break;
 		}
 
-		if (args->tf_out_flags.all != 0) 
-			return flagged_taskfile(drive, args);
-		return do_rw_taskfile(drive, args);
-	} else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
-		u8 *args = rq->buffer;
- 
-		if (!args)
-			goto done;
-#ifdef DEBUG
- 		printk("%s: DRIVE_TASK_CMD ", drive->name);
- 		printk("cmd=0x%02x ", args[0]);
- 		printk("fr=0x%02x ", args[1]);
- 		printk("ns=0x%02x ", args[2]);
- 		printk("sc=0x%02x ", args[3]);
- 		printk("lcyl=0x%02x ", args[4]);
- 		printk("hcyl=0x%02x ", args[5]);
- 		printk("sel=0x%02x\n", args[6]);
-#endif
- 		hwif->OUTB(args[1], IDE_FEATURE_REG);
- 		hwif->OUTB(args[3], IDE_SECTOR_REG);
- 		hwif->OUTB(args[4], IDE_LCYL_REG);
- 		hwif->OUTB(args[5], IDE_HCYL_REG);
- 		hwif->OUTB((args[6] & 0xEF)|drive->select.all, IDE_SELECT_REG);
- 		ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
- 		return ide_started;
- 	} else if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
- 		u8 *args = rq->buffer;
-
-		if (!args)
-			goto done;
-#ifdef DEBUG
- 		printk("%s: DRIVE_CMD ", drive->name);
- 		printk("cmd=0x%02x ", args[0]);
- 		printk("sc=0x%02x ", args[1]);
- 		printk("fr=0x%02x ", args[2]);
- 		printk("xx=0x%02x\n", args[3]);
-#endif
- 		if (args[0] == WIN_SMART) {
- 			hwif->OUTB(0x4f, IDE_LCYL_REG);
- 			hwif->OUTB(0xc2, IDE_HCYL_REG);
- 			hwif->OUTB(args[2],IDE_FEATURE_REG);
- 			hwif->OUTB(args[1],IDE_SECTOR_REG);
- 			ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
- 			return ide_started;
- 		}
- 		hwif->OUTB(args[2],IDE_FEATURE_REG);
- 		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
- 		return ide_started;
- 	}
-
-done:
+		return do_rw_taskfile(drive, task);
+	}
+
  	/*
  	 * NULL is actually a valid way of waiting for
  	 * all current requests to be flushed from the queue.
@@ -970,8 +853,7 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
 		if (rc)
 			printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
 		SELECT_DRIVE(drive);
-		if (IDE_CONTROL_REG)
-			HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+		ide_set_irq(drive, 1);
 		rc = ide_wait_not_busy(HWIF(drive), 100000);
 		if (rc)
 			printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
@@ -1003,6 +885,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 
 	/* bail early if we've exceeded max_failures */
 	if (drive->max_failures && (drive->failures > drive->max_failures)) {
+		rq->cmd_flags |= REQ_FAILED;
 		goto kill_rq;
 	}
 
@@ -1034,9 +917,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
 		if (drive->current_speed == 0xff)
 			ide_config_drive_speed(drive, drive->desired_speed);
 
-		if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
-		    rq->cmd_type == REQ_TYPE_ATA_TASK ||
-		    rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+		if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
 			return execute_drive_cmd(drive, rq);
 		else if (blk_pm_request(rq)) {
 			struct request_pm_state *pm = rq->data;
@@ -1244,11 +1125,13 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
 		}
 	again:
 		hwif = HWIF(drive);
-		if (hwgroup->hwif->sharing_irq &&
-		    hwif != hwgroup->hwif &&
-		    hwif->io_ports[IDE_CONTROL_OFFSET]) {
-			/* set nIEN for previous hwif */
-			SELECT_INTERRUPT(drive);
+		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) {
+			/*
+			 * set nIEN for previous hwif, drives in the
+			 * quirk_list may not like intr setups/cleanups
+			 */
+			if (drive->quirk_list != 1)
+				ide_set_irq(drive, 0);
 		}
 		hwgroup->hwif = hwif;
 		hwgroup->drive = drive;
@@ -1361,7 +1244,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
 	 */
 	drive->retry_pio++;
 	drive->state = DMA_PIO_RETRY;
-	hwif->dma_off_quietly(drive);
+	ide_dma_off_quietly(drive);
 
 	/*
 	 * un-busy drive etc (hwgroup->busy is cleared on return) and
@@ -1454,12 +1337,8 @@ void ide_timer_expiry (unsigned long data)
 			 */
 			spin_unlock(&ide_lock);
 			hwif  = HWIF(drive);
-#if DISABLE_IRQ_NOSYNC
-			disable_irq_nosync(hwif->irq);
-#else
 			/* disable_irq_nosync ?? */
 			disable_irq(hwif->irq);
-#endif /* DISABLE_IRQ_NOSYNC */
 			/* local CPU only,
 			 * as if we were handling an interrupt */
 			local_irq_disable();
@@ -1710,7 +1589,6 @@ irqreturn_t ide_intr (int irq, void *dev_id)
 void ide_init_drive_cmd (struct request *rq)
 {
 	memset(rq, 0, sizeof(*rq));
-	rq->cmd_type = REQ_TYPE_ATA_CMD;
 	rq->ref_count = 1;
 }
 
@@ -1785,3 +1663,19 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
 }
 
 EXPORT_SYMBOL(ide_do_drive_cmd);
+
+void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma)
+{
+	ide_task_t task;
+
+	memset(&task, 0, sizeof(task));
+	task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
+			IDE_TFLAG_OUT_FEATURE | tf_flags;
+	task.tf.feature = dma;		/* Use PIO/DMA */
+	task.tf.lbam    = bcount & 0xff;
+	task.tf.lbah    = (bcount >> 8) & 0xff;
+
+	ide_tf_load(drive, &task);
+}
+
+EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index bb9693dabe41..e2a7e95e1636 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -158,14 +158,6 @@ void default_hwif_mmiops (ide_hwif_t *hwif)
 
 EXPORT_SYMBOL(default_hwif_mmiops);
 
-u32 ide_read_24 (ide_drive_t *drive)
-{
-	u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
-	u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
-	u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
-	return (hcyl<<16)|(lcyl<<8)|sect;
-}
-
 void SELECT_DRIVE (ide_drive_t *drive)
 {
 	if (HWIF(drive)->selectproc)
@@ -175,26 +167,12 @@ void SELECT_DRIVE (ide_drive_t *drive)
 
 EXPORT_SYMBOL(SELECT_DRIVE);
 
-void SELECT_INTERRUPT (ide_drive_t *drive)
-{
-	if (HWIF(drive)->intrproc)
-		HWIF(drive)->intrproc(drive);
-	else
-		HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);
-}
-
 void SELECT_MASK (ide_drive_t *drive, int mask)
 {
 	if (HWIF(drive)->maskproc)
 		HWIF(drive)->maskproc(drive, mask);
 }
 
-void QUIRK_LIST (ide_drive_t *drive)
-{
-	if (HWIF(drive)->quirkproc)
-		drive->quirk_list = HWIF(drive)->quirkproc(drive);
-}
-
 /*
  * Some localbus EIDE interfaces require a special access sequence
  * when using 32-bit I/O instructions to transfer data.  We call this
@@ -449,7 +427,6 @@ int drive_is_ready (ide_drive_t *drive)
 	udelay(1);
 #endif
 
-#ifdef CONFIG_IDEPCI_SHARE_IRQ
 	/*
 	 * We do a passive status test under shared PCI interrupts on
 	 * cards that truly share the ATA side interrupt, but may also share
@@ -459,7 +436,6 @@ int drive_is_ready (ide_drive_t *drive)
 	if (IDE_CONTROL_REG)
 		stat = hwif->INB(IDE_ALTSTATUS_REG);
 	else
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
 		/* Note: this may clear a pending IRQ!! */
 		stat = hwif->INB(IDE_STATUS_REG);
 
@@ -642,9 +618,9 @@ no_80w:
 
 int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
 {
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
+	if (args->tf.command == WIN_SETFEATURES &&
+	    args->tf.nsect > XFER_UDMA_2 &&
+	    args->tf.feature == SETFEATURES_XFER) {
 		if (eighty_ninty_three(drive) == 0) {
 			printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
 					    "be set\n", drive->name);
@@ -662,9 +638,9 @@ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
  */
 int set_transfer (ide_drive_t *drive, ide_task_t *args)
 {
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
+	if (args->tf.command == WIN_SETFEATURES &&
+	    args->tf.nsect >= XFER_SW_DMA_0 &&
+	    args->tf.feature == SETFEATURES_XFER &&
 	    (drive->id->dma_ultra ||
 	     drive->id->dma_mword ||
 	     drive->id->dma_1word))
@@ -712,8 +688,7 @@ int ide_driveid_update(ide_drive_t *drive)
 	 */
 
 	SELECT_MASK(drive, 1);
-	if (IDE_CONTROL_REG)
-		hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
+	ide_set_irq(drive, 1);
 	msleep(50);
 	hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
 	timeout = jiffies + WAIT_WORSTCASE;
@@ -766,8 +741,8 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 //		msleep(50);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->ide_dma_on)	/* check if host supports DMA */
-		hwif->dma_host_off(drive);
+	if (hwif->dma_host_set)	/* check if host supports DMA */
+		hwif->dma_host_set(drive, 0);
 #endif
 
 	/* Skip setting PIO flow-control modes on pre-EIDE drives */
@@ -796,13 +771,12 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 	SELECT_DRIVE(drive);
 	SELECT_MASK(drive, 0);
 	udelay(1);
-	if (IDE_CONTROL_REG)
-		hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+	ide_set_irq(drive, 0);
 	hwif->OUTB(speed, IDE_NSECTOR_REG);
 	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
 	hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
-	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	if (drive->quirk_list == 2)
+		ide_set_irq(drive, 1);
 
 	error = __ide_wait_stat(drive, drive->ready_stat,
 				BUSY_STAT|DRQ_STAT|ERR_STAT,
@@ -823,10 +797,11 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
 
  skip:
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0)
-		hwif->dma_host_on(drive);
-	else if (hwif->ide_dma_on)	/* check if host supports DMA */
-		hwif->dma_off_quietly(drive);
+	if ((speed >= XFER_SW_DMA_0 || (hwif->host_flags & IDE_HFLAG_VDMA)) &&
+	    drive->using_dma)
+		hwif->dma_host_set(drive, 1);
+	else if (hwif->dma_host_set)	/* check if host supports DMA */
+		ide_dma_off_quietly(drive);
 #endif
 
 	switch(speed) {
@@ -902,8 +877,9 @@ EXPORT_SYMBOL(ide_set_handler);
  *	handler and IRQ setup do not race. All IDE command kick off
  *	should go via this function or do equivalent locking.
  */
- 
-void ide_execute_command(ide_drive_t *drive, task_ioreg_t cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry)
+
+void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
+			 unsigned timeout, ide_expiry_t *expiry)
 {
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
@@ -1035,10 +1011,10 @@ static void check_dma_crc(ide_drive_t *drive)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->crc_count) {
-		drive->hwif->dma_off_quietly(drive);
+		ide_dma_off_quietly(drive);
 		ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));
 		if (drive->current_speed >= XFER_SW_DMA_0)
-			(void) HWIF(drive)->ide_dma_on(drive);
+			ide_dma_on(drive);
 	} else
 		ide_dma_off(drive);
 #endif
@@ -1051,8 +1027,7 @@ static void ide_disk_pre_reset(ide_drive_t *drive)
 	drive->special.all = 0;
 	drive->special.b.set_geometry = legacy;
 	drive->special.b.recalibrate  = legacy;
-	if (OK_TO_RESET_CONTROLLER)
-		drive->mult_count = 0;
+	drive->mult_count = 0;
 	if (!drive->keep_settings && !drive->using_dma)
 		drive->mult_req = 0;
 	if (drive->mult_req != drive->mult_count)
@@ -1137,7 +1112,6 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
 	for (unit = 0; unit < MAX_DRIVES; ++unit)
 		pre_reset(&hwif->drives[unit]);
 
-#if OK_TO_RESET_CONTROLLER
 	if (!IDE_CONTROL_REG) {
 		spin_unlock_irqrestore(&ide_lock, flags);
 		return ide_stopped;
@@ -1174,11 +1148,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
 	 * state when the disks are reset this way. At least, the Winbond
 	 * 553 documentation says that
 	 */
-	if (hwif->resetproc != NULL) {
+	if (hwif->resetproc)
 		hwif->resetproc(drive);
-	}
-	
-#endif	/* OK_TO_RESET_CONTROLLER */
 
 	spin_unlock_irqrestore(&ide_lock, flags);
 	return ide_started;
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 062d3bcb2471..9b44fbdfe41f 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -441,6 +441,12 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
 	 * case could happen iff the transfer mode has already been set on
 	 * the device by ide-proc.c::set_xfer_rate()).
 	 */
+	if (rate < XFER_PIO_0) {
+		if (hwif->host_flags & IDE_HFLAG_ABUSE_SET_DMA_MODE)
+			return ide_set_dma_mode(drive, rate);
+		else
+			return ide_config_drive_speed(drive, rate);
+	}
 
 	return ide_set_dma_mode(drive, rate);
 }
@@ -448,8 +454,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
 static void ide_dump_opcode(ide_drive_t *drive)
 {
 	struct request *rq;
-	u8 opcode = 0;
-	int found = 0;
+	ide_task_t *task = NULL;
 
 	spin_lock(&ide_lock);
 	rq = NULL;
@@ -458,164 +463,129 @@ static void ide_dump_opcode(ide_drive_t *drive)
 	spin_unlock(&ide_lock);
 	if (!rq)
 		return;
-	if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
-	    rq->cmd_type == REQ_TYPE_ATA_TASK) {
-		char *args = rq->buffer;
-		if (args) {
-			opcode = args[0];
-			found = 1;
-		}
-	} else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-		ide_task_t *args = rq->special;
-		if (args) {
-			task_struct_t *tf = (task_struct_t *) args->tfRegister;
-			opcode = tf->command;
-			found = 1;
-		}
-	}
+
+	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
+		task = rq->special;
 
 	printk("ide: failed opcode was: ");
-	if (!found)
-		printk("unknown\n");
+	if (task == NULL)
+		printk(KERN_CONT "unknown\n");
 	else
-		printk("0x%02x\n", opcode);
+		printk(KERN_CONT "0x%02x\n", task->tf.command);
 }
 
-static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
+u64 ide_get_lba_addr(struct ide_taskfile *tf, int lba48)
 {
-	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long flags;
-	u8 err = 0;
+	u32 high, low;
 
-	local_irq_save(flags);
-	printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
-	if (stat & BUSY_STAT)
-		printk("Busy ");
-	else {
-		if (stat & READY_STAT)	printk("DriveReady ");
-		if (stat & WRERR_STAT)	printk("DeviceFault ");
-		if (stat & SEEK_STAT)	printk("SeekComplete ");
-		if (stat & DRQ_STAT)	printk("DataRequest ");
-		if (stat & ECC_STAT)	printk("CorrectedError ");
-		if (stat & INDEX_STAT)	printk("Index ");
-		if (stat & ERR_STAT)	printk("Error ");
+	if (lba48)
+		high = (tf->hob_lbah << 16) | (tf->hob_lbam << 8) |
+			tf->hob_lbal;
+	else
+		high = tf->device & 0xf;
+	low  = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal;
+
+	return ((u64)high << 24) | low;
+}
+EXPORT_SYMBOL_GPL(ide_get_lba_addr);
+
+static void ide_dump_sector(ide_drive_t *drive)
+{
+	ide_task_t task;
+	struct ide_taskfile *tf = &task.tf;
+	int lba48 = (drive->addressing == 1) ? 1 : 0;
+
+	memset(&task, 0, sizeof(task));
+	if (lba48)
+		task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_HOB_LBA |
+				IDE_TFLAG_LBA48;
+	else
+		task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE;
+
+	ide_tf_read(drive, &task);
+
+	if (lba48 || (tf->device & ATA_LBA))
+		printk(", LBAsect=%llu",
+			(unsigned long long)ide_get_lba_addr(tf, lba48));
+	else
+		printk(", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam,
+					 tf->device & 0xf, tf->lbal);
+}
+
+static void ide_dump_ata_error(ide_drive_t *drive, u8 err)
+{
+	printk("{ ");
+	if (err & ABRT_ERR)	printk("DriveStatusError ");
+	if (err & ICRC_ERR)
+		printk((err & ABRT_ERR) ? "BadCRC " : "BadSector ");
+	if (err & ECC_ERR)	printk("UncorrectableError ");
+	if (err & ID_ERR)	printk("SectorIdNotFound ");
+	if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
+	if (err & MARK_ERR)	printk("AddrMarkNotFound ");
+	printk("}");
+	if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
+	    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
+		ide_dump_sector(drive);
+		if (HWGROUP(drive) && HWGROUP(drive)->rq)
+			printk(", sector=%llu",
+			       (unsigned long long)HWGROUP(drive)->rq->sector);
 	}
+	printk("\n");
+}
+
+static void ide_dump_atapi_error(ide_drive_t *drive, u8 err)
+{
+	printk("{ ");
+	if (err & ILI_ERR)	printk("IllegalLengthIndication ");
+	if (err & EOM_ERR)	printk("EndOfMedia ");
+	if (err & ABRT_ERR)	printk("AbortedCommand ");
+	if (err & MCR_ERR)	printk("MediaChangeRequested ");
+	if (err & LFS_ERR)	printk("LastFailedSense=0x%02x ",
+				       (err & LFS_ERR) >> 4);
 	printk("}\n");
-	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
-		err = hwif->INB(IDE_ERROR_REG);
-		printk("%s: %s: error=0x%02x { ", drive->name, msg, err);
-		if (err & ABRT_ERR)	printk("DriveStatusError ");
-		if (err & ICRC_ERR)
-			printk((err & ABRT_ERR) ? "BadCRC " : "BadSector ");
-		if (err & ECC_ERR)	printk("UncorrectableError ");
-		if (err & ID_ERR)	printk("SectorIdNotFound ");
-		if (err & TRK0_ERR)	printk("TrackZeroNotFound ");
-		if (err & MARK_ERR)	printk("AddrMarkNotFound ");
-		printk("}");
-		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
-		    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-			if (drive->addressing == 1) {
-				__u64 sectors = 0;
-				u32 low = 0, high = 0;
-				hwif->OUTB(drive->ctl&~0x80, IDE_CONTROL_REG);
-				low = ide_read_24(drive);
-				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
-				high = ide_read_24(drive);
-				sectors = ((__u64)high << 24) | low;
-				printk(", LBAsect=%llu, high=%d, low=%d",
-				       (unsigned long long) sectors,
-				       high, low);
-			} else {
-				u8 cur = hwif->INB(IDE_SELECT_REG);
-				if (cur & 0x40) {	/* using LBA? */
-					printk(", LBAsect=%ld", (unsigned long)
-					 ((cur&0xf)<<24)
-					 |(hwif->INB(IDE_HCYL_REG)<<16)
-					 |(hwif->INB(IDE_LCYL_REG)<<8)
-					 | hwif->INB(IDE_SECTOR_REG));
-				} else {
-					printk(", CHS=%d/%d/%d",
-					 (hwif->INB(IDE_HCYL_REG)<<8) +
-					  hwif->INB(IDE_LCYL_REG),
-					  cur & 0xf,
-					  hwif->INB(IDE_SECTOR_REG));
-				}
-			}
-			if (HWGROUP(drive) && HWGROUP(drive)->rq)
-				printk(", sector=%llu",
-					(unsigned long long)HWGROUP(drive)->rq->sector);
-		}
-		printk("\n");
-	}
-	ide_dump_opcode(drive);
-	local_irq_restore(flags);
-	return err;
 }
 
 /**
- *	ide_dump_atapi_status       -       print human readable atapi status
+ *	ide_dump_status		-	translate ATA/ATAPI error
  *	@drive: drive that status applies to
  *	@msg: text message to print
  *	@stat: status byte to decode
  *
  *	Error reporting, in human readable form (luxurious, but a memory hog).
+ *	Combines the drive name, message and status byte to provide a
+ *	user understandable explanation of the device error.
  */
 
-static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat)
+u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
 {
 	unsigned long flags;
+	u8 err = 0;
 
-	atapi_status_t status;
-	atapi_error_t error;
-
-	status.all = stat;
-	error.all = 0;
 	local_irq_save(flags);
 	printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
-	if (status.b.bsy)
+	if (stat & BUSY_STAT)
 		printk("Busy ");
 	else {
-		if (status.b.drdy)	printk("DriveReady ");
-		if (status.b.df)	printk("DeviceFault ");
-		if (status.b.dsc)	printk("SeekComplete ");
-		if (status.b.drq)	printk("DataRequest ");
-		if (status.b.corr)	printk("CorrectedError ");
-		if (status.b.idx)	printk("Index ");
-		if (status.b.check)	printk("Error ");
+		if (stat & READY_STAT)	printk("DriveReady ");
+		if (stat & WRERR_STAT)	printk("DeviceFault ");
+		if (stat & SEEK_STAT)	printk("SeekComplete ");
+		if (stat & DRQ_STAT)	printk("DataRequest ");
+		if (stat & ECC_STAT)	printk("CorrectedError ");
+		if (stat & INDEX_STAT)	printk("Index ");
+		if (stat & ERR_STAT)	printk("Error ");
 	}
 	printk("}\n");
-	if (status.b.check && !status.b.bsy) {
-		error.all = HWIF(drive)->INB(IDE_ERROR_REG);
-		printk("%s: %s: error=0x%02x { ", drive->name, msg, error.all);
-		if (error.b.ili)	printk("IllegalLengthIndication ");
-		if (error.b.eom)	printk("EndOfMedia ");
-		if (error.b.abrt)	printk("AbortedCommand ");
-		if (error.b.mcr)	printk("MediaChangeRequested ");
-		if (error.b.sense_key)	printk("LastFailedSense=0x%02x ",
-						error.b.sense_key);
-		printk("}\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		err = drive->hwif->INB(IDE_ERROR_REG);
+		printk("%s: %s: error=0x%02x ", drive->name, msg, err);
+		if (drive->media == ide_disk)
+			ide_dump_ata_error(drive, err);
+		else
+			ide_dump_atapi_error(drive, err);
 	}
 	ide_dump_opcode(drive);
 	local_irq_restore(flags);
-	return error.all;
-}
-
-/**
- *	ide_dump_status		-	translate ATA/ATAPI error
- *	@drive: drive the error occured on
- *	@msg: information string
- *	@stat: status byte
- *
- *	Error reporting, in human readable form (luxurious, but a memory hog).
- *	Combines the drive name, message and status byte to provide a
- *	user understandable explanation of the device error.
- */
-
-u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
-{
-	if (drive->media == ide_disk)
-		return ide_dump_ata_status(drive, msg, stat);
-	return ide_dump_atapi_status(drive, msg, stat);
+	return err;
 }
 
 EXPORT_SYMBOL(ide_dump_status);
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index e245521af7b5..cbbb0f75be92 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -31,7 +31,6 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
 {
 	hw_regs_t hw;
 	ide_hwif_t *hwif;
-	int index;
 
 	if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0)))
 		return -1;
@@ -41,11 +40,19 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
 				pnp_port_start(dev, 1));
 	hw.irq = pnp_irq(dev, 0);
 
-	index = ide_register_hw(&hw, NULL, 1, &hwif);
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif) {
+		u8 index = hwif->index;
+		u8 idx[4] = { index, 0xff, 0xff, 0xff };
+
+		ide_init_port_data(hwif, index);
+		ide_init_port_hw(hwif, &hw);
 
-	if (index != -1) {
-	    	printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
+		printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
 		pnp_set_drvdata(dev,hwif);
+
+		ide_device_add(idx);
+
 		return 0;
 	}
 
@@ -68,12 +75,15 @@ static struct pnp_driver idepnp_driver = {
 	.remove		= idepnp_remove,
 };
 
-void __init pnpide_init(void)
+static int __init pnpide_init(void)
 {
-	pnp_register_driver(&idepnp_driver);
+	return pnp_register_driver(&idepnp_driver);
 }
 
-void __exit pnpide_exit(void)
+static void __exit pnpide_exit(void)
 {
 	pnp_unregister_driver(&idepnp_driver);
 }
+
+module_init(pnpide_init);
+module_exit(pnpide_exit);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 2994523be7bf..edf650b20c67 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -95,10 +95,10 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
 #ifdef CONFIG_IDEDISK_MULTI_MODE
 		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
 		id->multsect_valid = id->multsect ? 1 : 0;
-		drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
+		drive->mult_req = id->multsect_valid ? id->max_multsect : 0;
 		drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
 #else	/* original, pre IDE-NFG, per request of AC */
-		drive->mult_req = INITIAL_MULT_COUNT;
+		drive->mult_req = 0;
 		if (drive->mult_req > id->max_multsect)
 			drive->mult_req = id->max_multsect;
 		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
@@ -234,7 +234,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
 
 	drive->media = ide_disk;
 	printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
-	QUIRK_LIST(drive);
+
 	return;
 
 err_misc:
@@ -350,22 +350,19 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
 	 * the irq handler isn't expecting.
 	 */
 	if (IDE_CONTROL_REG) {
-		u8 ctl = drive->ctl | 2;
 		if (!hwif->irq) {
 			autoprobe = 1;
 			cookie = probe_irq_on();
-			/* enable device irq */
-			ctl &= ~2;
 		}
-		hwif->OUTB(ctl, IDE_CONTROL_REG);
+		ide_set_irq(drive, autoprobe);
 	}
 
 	retval = actual_try_to_identify(drive, cmd);
 
 	if (autoprobe) {
 		int irq;
-		/* mask device irq */
-		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+
+		ide_set_irq(drive, 0);
 		/* clear drive IRQ */
 		(void) hwif->INB(IDE_STATUS_REG);
 		udelay(5);
@@ -385,6 +382,20 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd)
 	return retval;
 }
 
+static int ide_busy_sleep(ide_hwif_t *hwif)
+{
+	unsigned long timeout = jiffies + WAIT_WORSTCASE;
+	u8 stat;
+
+	do {
+		msleep(50);
+		stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+		if ((stat & BUSY_STAT) == 0)
+			return 0;
+	} while (time_before(jiffies, timeout));
+
+	return 1;
+}
 
 /**
  *	do_probe		-	probe an IDE device
@@ -453,7 +464,6 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 		if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
 			((drive->autotune == IDE_TUNE_DEFAULT) ||
 			(drive->autotune == IDE_TUNE_AUTO))) {
-			unsigned long timeout;
 			printk("%s: no response (status = 0x%02x), "
 				"resetting drive\n", drive->name,
 				hwif->INB(IDE_STATUS_REG));
@@ -461,10 +471,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 			hwif->OUTB(drive->select.all, IDE_SELECT_REG);
 			msleep(50);
 			hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
-			timeout = jiffies;
-			while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) &&
-			       time_before(jiffies, timeout + WAIT_WORSTCASE))
-				msleep(50);
+			(void)ide_busy_sleep(hwif);
 			rc = try_to_identify(drive, cmd);
 		}
 		if (rc == 1)
@@ -492,20 +499,16 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 static void enable_nest (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	unsigned long timeout;
 
 	printk("%s: enabling %s -- ", hwif->name, drive->id->model);
 	SELECT_DRIVE(drive);
 	msleep(50);
 	hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
-	timeout = jiffies + WAIT_WORSTCASE;
-	do {
-		if (time_after(jiffies, timeout)) {
-			printk("failed (timeout)\n");
-			return;
-		}
-		msleep(50);
-	} while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT);
+
+	if (ide_busy_sleep(hwif)) {
+		printk(KERN_CONT "failed (timeout)\n");
+		return;
+	}
 
 	msleep(50);
 
@@ -653,8 +656,7 @@ static int wait_hwif_ready(ide_hwif_t *hwif)
 		/* Ignore disks that we will not probe for later. */
 		if (!drive->noprobe || drive->present) {
 			SELECT_DRIVE(drive);
-			if (IDE_CONTROL_REG)
-				hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+			ide_set_irq(drive, 1);
 			mdelay(2);
 			rc = ide_wait_not_busy(hwif, 35000);
 			if (rc)
@@ -673,19 +675,18 @@ out:
 
 /**
  *	ide_undecoded_slave	-	look for bad CF adapters
- *	@hwif: interface
+ *	@drive1: drive
  *
  *	Analyse the drives on the interface and attempt to decide if we
  *	have the same drive viewed twice. This occurs with crap CF adapters
  *	and PCMCIA sometimes.
  */
 
-void ide_undecoded_slave(ide_hwif_t *hwif)
+void ide_undecoded_slave(ide_drive_t *drive1)
 {
-	ide_drive_t *drive0 = &hwif->drives[0];
-	ide_drive_t *drive1 = &hwif->drives[1];
+	ide_drive_t *drive0 = &drive1->hwif->drives[0];
 
-	if (drive0->present == 0 || drive1->present == 0)
+	if ((drive1->dn & 1) == 0 || drive0->present == 0)
 		return;
 
 	/* If the models don't match they are not the same product */
@@ -788,18 +789,11 @@ static void probe_hwif(ide_hwif_t *hwif)
 		}
 	}
 	if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) {
-		unsigned long timeout = jiffies + WAIT_WORSTCASE;
-		u8 stat;
-
 		printk(KERN_WARNING "%s: reset\n", hwif->name);
 		hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
 		udelay(10);
 		hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		do {
-			msleep(50);
-			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
-		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
-
+		(void)ide_busy_sleep(hwif);
 	}
 	local_irq_restore(flags);
 	/*
@@ -814,8 +808,12 @@ static void probe_hwif(ide_hwif_t *hwif)
 		return;
 	}
 
-	if (hwif->fixup)
-		hwif->fixup(hwif);
+	for (unit = 0; unit < MAX_DRIVES; unit++) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if (drive->present && hwif->quirkproc)
+			hwif->quirkproc(drive);
+	}
 
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
@@ -830,16 +828,8 @@ static void probe_hwif(ide_hwif_t *hwif)
 
 			drive->nice1 = 1;
 
-			if (hwif->ide_dma_on) {
-				/*
-				 * Force DMAing for the beginning of the check.
-				 * Some chipsets appear to do interesting
-				 * things, if not checked and cleared.
-				 *   PARANOIA!!!
-				 */
-				hwif->dma_off_quietly(drive);
+			if (hwif->dma_host_set)
 				ide_set_dma(drive);
-			}
 		}
 	}
 
@@ -853,25 +843,6 @@ static void probe_hwif(ide_hwif_t *hwif)
 	}
 }
 
-static int hwif_init(ide_hwif_t *hwif);
-static void hwif_register_devices(ide_hwif_t *hwif);
-
-static int probe_hwif_init(ide_hwif_t *hwif)
-{
-	probe_hwif(hwif);
-
-	if (!hwif_init(hwif)) {
-		printk(KERN_INFO "%s: failed to initialize IDE interface\n",
-				 hwif->name);
-		return -1;
-	}
-
-	if (hwif->present)
-		hwif_register_devices(hwif);
-
-	return 0;
-}
-
 #if MAX_HWIFS > 1
 /*
  * save_match() is used to simplify logic in init_irq() below.
@@ -968,11 +939,6 @@ static int ide_init_queue(ide_drive_t *drive)
  * Much of the code is for correctly detecting/handling irq sharing
  * and irq serialization situations.  This is somewhat complex because
  * it handles static as well as dynamic (PCMCIA) IDE interfaces.
- *
- * The IRQF_DISABLED in sa_flags means ide_intr() is always entered with
- * interrupts completely disabled.  This can be bad for interrupt latency,
- * but anything else has led to problems on some machines.  We re-enable
- * interrupts as much as we can safely do in most places.
  */
 static int init_irq (ide_hwif_t *hwif)
 {
@@ -1055,17 +1021,13 @@ static int init_irq (ide_hwif_t *hwif)
 	 * Allocate the irq, if not already obtained for another hwif
 	 */
 	if (!match || match->irq != hwif->irq) {
-		int sa = IRQF_DISABLED;
+		int sa = 0;
 #if defined(__mc68000__) || defined(CONFIG_APUS)
 		sa = IRQF_SHARED;
 #endif /* __mc68000__ || CONFIG_APUS */
 
-		if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
+		if (IDE_CHIPSET_IS_PCI(hwif->chipset))
 			sa = IRQF_SHARED;
-#ifndef CONFIG_IDEPCI_SHARE_IRQ
-			sa |= IRQF_DISABLED;
-#endif /* CONFIG_IDEPCI_SHARE_IRQ */
-		}
 
 		if (hwif->io_ports[IDE_CONTROL_OFFSET])
 			/* clear nIEN */
@@ -1173,7 +1135,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data)
 {
 	struct gendisk *p = data;
 	*part &= (1 << PARTN_BITS) - 1;
-	return &p->kobj;
+	return &p->dev.kobj;
 }
 
 static int exact_lock(dev_t dev, void *data)
@@ -1373,54 +1335,63 @@ static void hwif_register_devices(ide_hwif_t *hwif)
 	}
 }
 
-int ideprobe_init (void)
+int ide_device_add_all(u8 *idx)
 {
-	unsigned int index;
-	int probe[MAX_HWIFS];
-
-	memset(probe, 0, MAX_HWIFS * sizeof(int));
-	for (index = 0; index < MAX_HWIFS; ++index)
-		probe[index] = !ide_hwifs[index].present;
-
-	for (index = 0; index < MAX_HWIFS; ++index)
-		if (probe[index])
-			probe_hwif(&ide_hwifs[index]);
-	for (index = 0; index < MAX_HWIFS; ++index)
-		if (probe[index])
-			hwif_init(&ide_hwifs[index]);
-	for (index = 0; index < MAX_HWIFS; ++index) {
-		if (probe[index]) {
-			ide_hwif_t *hwif = &ide_hwifs[index];
-			if (!hwif->present)
-				continue;
-			if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
-				hwif->chipset = ide_generic;
-			hwif_register_devices(hwif);
+	ide_hwif_t *hwif;
+	int i, rc = 0;
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (idx[i] == 0xff)
+			continue;
+
+		probe_hwif(&ide_hwifs[idx[i]]);
+	}
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (idx[i] == 0xff)
+			continue;
+
+		hwif = &ide_hwifs[idx[i]];
+
+		if (hwif_init(hwif) == 0) {
+			printk(KERN_INFO "%s: failed to initialize IDE "
+					 "interface\n", hwif->name);
+			rc = -1;
+			continue;
 		}
 	}
-	for (index = 0; index < MAX_HWIFS; ++index)
-		if (probe[index])
-			ide_proc_register_port(&ide_hwifs[index]);
-	return 0;
-}
 
-EXPORT_SYMBOL_GPL(ideprobe_init);
+	for (i = 0; i < MAX_HWIFS; i++) {
+		if (idx[i] == 0xff)
+			continue;
 
-int ide_device_add(u8 idx[4])
-{
-	int i, rc = 0;
+		hwif = &ide_hwifs[idx[i]];
 
-	for (i = 0; i < 4; i++) {
-		if (idx[i] != 0xff)
-			rc |= probe_hwif_init(&ide_hwifs[idx[i]]);
+		if (hwif->present) {
+			if (hwif->chipset == ide_unknown ||
+			    hwif->chipset == ide_forced)
+				hwif->chipset = ide_generic;
+			hwif_register_devices(hwif);
+		}
 	}
 
-	for (i = 0; i < 4; i++) {
+	for (i = 0; i < MAX_HWIFS; i++) {
 		if (idx[i] != 0xff)
 			ide_proc_register_port(&ide_hwifs[idx[i]]);
 	}
 
 	return rc;
 }
+EXPORT_SYMBOL_GPL(ide_device_add_all);
+
+int ide_device_add(u8 idx[4])
+{
+	u8 idx_all[MAX_HWIFS];
+	int i;
 
+	for (i = 0; i < MAX_HWIFS; i++)
+		idx_all[i] = (i < 4) ? idx[i] : 0xff;
+
+	return ide_device_add_all(idx_all);
+}
 EXPORT_SYMBOL_GPL(ide_device_add);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index a4007d30da52..aa663e7f46f2 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -346,14 +346,20 @@ static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int va
 
 static int set_xfer_rate (ide_drive_t *drive, int arg)
 {
+	ide_task_t task;
 	int err;
 
 	if (arg < 0 || arg > 70)
 		return -EINVAL;
 
-	err = ide_wait_cmd(drive,
-			WIN_SETFEATURES, (u8) arg,
-			SETFEATURES_XFER, 0, NULL);
+	memset(&task, 0, sizeof(task));
+	task.tf.command = WIN_SETFEATURES;
+	task.tf.feature = SETFEATURES_XFER;
+	task.tf.nsect   = (u8)arg;
+	task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT |
+			IDE_TFLAG_IN_NSECT;
+
+	err = ide_no_data_taskfile(drive, &task);
 
 	if (!err && arg) {
 		ide_set_xfer_rate(drive, (u8) arg);
diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
new file mode 100644
index 000000000000..7ffa332d77ce
--- /dev/null
+++ b/drivers/ide/ide-scan-pci.c
@@ -0,0 +1,121 @@
+/*
+ * support for probing IDE PCI devices in the PCI bus order
+ *
+ * Copyright (c) 1998-2000  Andre Hedrick <andre@linux-ide.org>
+ * Copyright (c) 1995-1998  Mark Lord
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ide.h>
+
+/*
+ *	Module interfaces
+ */
+
+static int pre_init = 1;		/* Before first ordered IDE scan */
+static LIST_HEAD(ide_pci_drivers);
+
+/*
+ *	__ide_pci_register_driver	-	attach IDE driver
+ *	@driver: pci driver
+ *	@module: owner module of the driver
+ *
+ *	Registers a driver with the IDE layer. The IDE layer arranges that
+ *	boot time setup is done in the expected device order and then
+ *	hands the controllers off to the core PCI code to do the rest of
+ *	the work.
+ *
+ *	Returns are the same as for pci_register_driver
+ */
+
+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
+			      const char *mod_name)
+{
+	if (!pre_init)
+		return __pci_register_driver(driver, module, mod_name);
+	driver->driver.owner = module;
+	list_add_tail(&driver->node, &ide_pci_drivers);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
+
+/**
+ *	ide_scan_pcidev		-	find an IDE driver for a device
+ *	@dev: PCI device to check
+ *
+ *	Look for an IDE driver to handle the device we are considering.
+ *	This is only used during boot up to get the ordering correct. After
+ *	boot up the pci layer takes over the job.
+ */
+
+static int __init ide_scan_pcidev(struct pci_dev *dev)
+{
+	struct list_head *l;
+	struct pci_driver *d;
+
+	list_for_each(l, &ide_pci_drivers) {
+		d = list_entry(l, struct pci_driver, node);
+		if (d->id_table) {
+			const struct pci_device_id *id =
+				pci_match_id(d->id_table, dev);
+
+			if (id != NULL && d->probe(dev, id) >= 0) {
+				dev->driver = d;
+				pci_dev_get(dev);
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ *	ide_scan_pcibus		-	perform the initial IDE driver scan
+ *
+ *	Perform the initial bus rather than driver ordered scan of the
+ *	PCI drivers. After this all IDE pci handling becomes standard
+ *	module ordering not traditionally ordered.
+ */
+
+int __init ide_scan_pcibus(void)
+{
+	struct pci_dev *dev = NULL;
+	struct pci_driver *d;
+	struct list_head *l, *n;
+
+	pre_init = 0;
+	if (!ide_scan_direction)
+		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
+			ide_scan_pcidev(dev);
+	else
+		while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID,
+						     dev)))
+			ide_scan_pcidev(dev);
+
+	/*
+	 *	Hand the drivers over to the PCI layer now we
+	 *	are post init.
+	 */
+
+	list_for_each_safe(l, n, &ide_pci_drivers) {
+		list_del(l);
+		d = list_entry(l, struct pci_driver, node);
+		if (__pci_register_driver(d, d->driver.owner,
+					  d->driver.mod_name))
+			printk(KERN_ERR "%s: failed to register %s driver\n",
+					__FUNCTION__, d->driver.mod_name);
+	}
+
+	return 0;
+}
+
+static int __init ide_scan_pci(void)
+{
+	return ide_scan_pcibus();
+}
+
+module_init(ide_scan_pci);
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 7b9181b5469d..d71a584f0765 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -615,16 +615,6 @@ typedef struct os_dat_s {
 /*************************** End of tunable parameters ***********************/
 
 /*
- *	Debugging/Performance analysis
- *
- *	I/O trace support
- */
-#define USE_IOTRACE	0
-#if USE_IOTRACE
-#define IO_IDETAPE_FIFO	500
-#endif
-
-/*
  *	Read/Write error simulation
  */
 #define SIMULATE_ERRORS			0
@@ -1700,6 +1690,11 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
 	if (error)
 		tape->failed_pc = NULL;
 
+	if (!blk_special_request(rq)) {
+		ide_end_request(drive, uptodate, nr_sects);
+		return 0;
+	}
+
 	spin_lock_irqsave(&tape->spinlock, flags);
 
 	/* The request was a pipelined data transfer request */
@@ -1818,9 +1813,8 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc;
 	struct request *rq;
-	atapi_error_t error;
 
-	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
+	(void)drive->hwif->INB(IDE_ERROR_REG);
 	pc = idetape_next_pc_storage(drive);
 	rq = idetape_next_rq_storage(drive);
 	idetape_create_request_sense_cmd(pc);
@@ -1858,15 +1852,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
 	idetape_tape_t *tape = drive->driver_data;
-	atapi_status_t status;
-	atapi_bcount_t bcount;
-	atapi_ireason_t ireason;
 	idetape_pc_t *pc = tape->pc;
-
 	unsigned int temp;
 #if SIMULATE_ERRORS
 	static int error_sim_count = 0;
 #endif
+	u16 bcount;
+	u8 stat, ireason;
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
@@ -1875,10 +1867,10 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 #endif /* IDETAPE_DEBUG_LOG */	
 
 	/* Clear the interrupt */
-	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+	stat = hwif->INB(IDE_STATUS_REG);
 
 	if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->ide_dma_end(drive) || status.b.check) {
+		if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -1912,7 +1904,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 	}
 
 	/* No more interrupts */
-	if (!status.b.drq) {
+	if ((stat & DRQ_STAT) == 0) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
 			printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
@@ -1927,12 +1919,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 		    (++error_sim_count % 100) == 0) {
 			printk(KERN_INFO "ide-tape: %s: simulating error\n",
 				tape->name);
-			status.b.check = 1;
+			stat |= ERR_STAT;
 		}
 #endif
-		if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
-			status.b.check = 0;
-		if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {	/* Error detected */
+		if ((stat & ERR_STAT) && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
+			stat &= ~ERR_STAT;
+		if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) {
+			/* Error detected */
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
 				printk(KERN_INFO "ide-tape: %s: I/O error\n",
@@ -1951,7 +1944,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 		}
 		pc->error = 0;
 		if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
-		    !status.b.dsc) {
+		    (stat & SEEK_STAT) == 0) {
 			/* Media access command */
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
@@ -1973,30 +1966,30 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 		return ide_do_reset(drive);
 	}
 	/* Get the number of bytes to transfer on this interrupt. */
-	bcount.b.high = hwif->INB(IDE_BCOUNTH_REG);
-	bcount.b.low = hwif->INB(IDE_BCOUNTL_REG);
+	bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
+		  hwif->INB(IDE_BCOUNTL_REG);
 
-	ireason.all = hwif->INB(IDE_IREASON_REG);
+	ireason = hwif->INB(IDE_IREASON_REG);
 
-	if (ireason.b.cod) {
+	if (ireason & CD) {
 		printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n");
 		return ide_do_reset(drive);
 	}
-	if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) {
+	if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) {
 		/* Hopefully, we will never get here */
 		printk(KERN_ERR "ide-tape: We wanted to %s, ",
-			ireason.b.io ? "Write":"Read");
+				(ireason & IO) ? "Write" : "Read");
 		printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
-			ireason.b.io ? "Read":"Write");
+				(ireason & IO) ? "Read" : "Write");
 		return ide_do_reset(drive);
 	}
 	if (!test_bit(PC_WRITING, &pc->flags)) {
 		/* Reading - Check that we have enough space */
-		temp = pc->actually_transferred + bcount.all;
+		temp = pc->actually_transferred + bcount;
 		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
 				printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
-				idetape_discard_data(drive, bcount.all);
+				idetape_discard_data(drive, bcount);
 				ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
 				return ide_started;
 			}
@@ -2008,23 +2001,26 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive)
 	}
 	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->bh != NULL)
-			idetape_output_buffers(drive, pc, bcount.all);
+			idetape_output_buffers(drive, pc, bcount);
 		else
 			/* Write the current buffer */
-			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
+			hwif->atapi_output_bytes(drive, pc->current_position,
+						 bcount);
 	} else {
 		if (pc->bh != NULL)
-			idetape_input_buffers(drive, pc, bcount.all);
+			idetape_input_buffers(drive, pc, bcount);
 		else
 			/* Read the current buffer */
-			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
+			hwif->atapi_input_bytes(drive, pc->current_position,
+						bcount);
 	}
 	/* Update the current position */
-	pc->actually_transferred += bcount.all;
-	pc->current_position += bcount.all;
+	pc->actually_transferred += bcount;
+	pc->current_position += bcount;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
+		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
+				 "on that interrupt\n", pc->c[0], bcount);
 #endif
 	/* And set the interrupt handler again */
 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
@@ -2078,28 +2074,28 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
 	ide_hwif_t *hwif = drive->hwif;
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
-	atapi_ireason_t ireason;
 	int retries = 100;
 	ide_startstop_t startstop;
+	u8 ireason;
 
 	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
 		printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all = hwif->INB(IDE_IREASON_REG);
-	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
+	ireason = hwif->INB(IDE_IREASON_REG);
+	while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) {
 		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
 				"a packet command, retrying\n");
 		udelay(100);
-		ireason.all = hwif->INB(IDE_IREASON_REG);
+		ireason = hwif->INB(IDE_IREASON_REG);
 		if (retries == 0) {
 			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
 					"issuing a packet command, ignoring\n");
-			ireason.b.cod = 1;
-			ireason.b.io = 0;
+			ireason |= CD;
+			ireason &= ~IO;
 		}
 	}
-	if (!ireason.b.cod || ireason.b.io) {
+	if ((ireason & CD) == 0 || (ireason & IO)) {
 		printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
 				"a packet command\n");
 		return ide_do_reset(drive);
@@ -2120,8 +2116,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
 {
 	ide_hwif_t *hwif = drive->hwif;
 	idetape_tape_t *tape = drive->driver_data;
-	atapi_bcount_t bcount;
 	int dma_ok = 0;
+	u16 bcount;
 
 #if IDETAPE_DEBUG_BUGS
 	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
@@ -2170,7 +2166,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
 	pc->actually_transferred = 0;
 	pc->current_position = pc->buffer;
 	/* Request to transfer the entire buffer at once */
-	bcount.all = pc->request_transfer;
+	bcount = pc->request_transfer;
 
 	if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
 		printk(KERN_WARNING "ide-tape: DMA disabled, "
@@ -2180,12 +2176,9 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape
 	if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
 		dma_ok = !hwif->dma_setup(drive);
 
-	if (IDE_CONTROL_REG)
-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-	hwif->OUTB(dma_ok ? 1 : 0, IDE_FEATURE_REG);	/* Use PIO/DMA */
-	hwif->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
-	hwif->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
-	hwif->OUTB(drive->select.all, IDE_SELECT_REG);
+	ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
+			   IDE_TFLAG_OUT_DEVICE, bcount, dma_ok);
+
 	if (dma_ok)			/* Will begin DMA later */
 		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
@@ -2295,11 +2288,11 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = tape->pc;
-	atapi_status_t status;
+	u8 stat;
 
-	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
-	if (status.b.dsc) {
-		if (status.b.check) {
+	stat = drive->hwif->INB(IDE_STATUS_REG);
+	if (stat & SEEK_STAT) {
+		if (stat & ERR_STAT) {
 			/* Error detected */
 			if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD)
 				printk(KERN_ERR "ide-tape: %s: I/O error, ",
@@ -2417,7 +2410,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_pc_t *pc = NULL;
 	struct request *postponed_rq = tape->postponed_rq;
-	atapi_status_t status;
+	u8 stat;
 
 #if IDETAPE_DEBUG_LOG
 #if 0
@@ -2465,7 +2458,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
 	 * If the tape is still busy, postpone our request and service
 	 * the other device meanwhile.
 	 */
-	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+	stat = drive->hwif->INB(IDE_STATUS_REG);
 
 	if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2))
 		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
@@ -2481,7 +2474,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 	calculate_speeds(drive);
 	if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
-	    !status.b.dsc) {
+	    (stat & SEEK_STAT) == 0) {
 		if (postponed_rq == NULL) {
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
@@ -2502,9 +2495,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
 	}
 	if (rq->cmd[0] & REQ_IDETAPE_READ) {
 		tape->buffer_head++;
-#if USE_IOTRACE
-		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
 		tape->postpone_cnt = 0;
 		pc = idetape_next_pc_storage(drive);
 		idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
@@ -2512,9 +2502,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
 	}
 	if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
 		tape->buffer_head++;
-#if USE_IOTRACE
-		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
 		tape->postpone_cnt = 0;
 		pc = idetape_next_pc_storage(drive);
 		idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special);
@@ -3241,9 +3228,6 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks)
 	idetape_switch_buffers(tape, new_stage);
 	idetape_add_stage_tail(drive, new_stage);
 	tape->pipeline_head++;
-#if USE_IOTRACE
-	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
 	calculate_speeds(drive);
 
 	/*
@@ -3493,9 +3477,6 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks)
 		idetape_remove_stage_head(drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 		tape->pipeline_head++;
-#if USE_IOTRACE
-		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
-#endif
 		calculate_speeds(drive);
 	}
 #if IDETAPE_DEBUG_BUGS
@@ -4724,10 +4705,8 @@ static void ide_tape_release(struct kref *kref)
 
 	drive->dsc_overlap = 0;
 	drive->driver_data = NULL;
-	class_device_destroy(idetape_sysfs_class,
-			MKDEV(IDETAPE_MAJOR, tape->minor));
-	class_device_destroy(idetape_sysfs_class,
-			MKDEV(IDETAPE_MAJOR, tape->minor + 128));
+	device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor));
+	device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128));
 	idetape_devs[tape->minor] = NULL;
 	g->private_data = NULL;
 	put_disk(g);
@@ -4884,10 +4863,10 @@ static int ide_tape_probe(ide_drive_t *drive)
 
 	idetape_setup(drive, tape, minor);
 
-	class_device_create(idetape_sysfs_class, NULL,
-			MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name);
-	class_device_create(idetape_sysfs_class, NULL,
-			MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name);
+	device_create(idetape_sysfs_class, &drive->gendev,
+		      MKDEV(IDETAPE_MAJOR, minor), "%s", tape->name);
+	device_create(idetape_sysfs_class, &drive->gendev,
+			MKDEV(IDETAPE_MAJOR, minor + 128), "n%s", tape->name);
 
 	g->fops = &idetape_block_ops;
 	ide_register_region(g);
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 2b60f1b0437e..5eb6fa15dc4d 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -35,93 +35,81 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static void ata_bswap_data (void *buffer, int wcount)
+void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
 {
-	u16 *p = buffer;
-
-	while (wcount--) {
-		*p = *p << 8 | *p >> 8; p++;
-		*p = *p << 8 | *p >> 8; p++;
-	}
-}
-
-static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount)
-{
-	HWIF(drive)->ata_input_data(drive, buffer, wcount);
-	if (drive->bswap)
-		ata_bswap_data(buffer, wcount);
-}
+	ide_hwif_t *hwif = drive->hwif;
+	struct ide_taskfile *tf = &task->tf;
+	u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
+
+	if (task->tf_flags & IDE_TFLAG_FLAGGED)
+		HIHI = 0xFF;
+
+#ifdef DEBUG
+	printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
+		"lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
+		drive->name, tf->feature, tf->nsect, tf->lbal,
+		tf->lbam, tf->lbah, tf->device, tf->command);
+	printk("%s: hob: nsect 0x%02x lbal 0x%02x "
+		"lbam 0x%02x lbah 0x%02x\n",
+		drive->name, tf->hob_nsect, tf->hob_lbal,
+		tf->hob_lbam, tf->hob_lbah);
+#endif
 
-static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount)
-{
-	if (drive->bswap) {
-		ata_bswap_data(buffer, wcount);
-		HWIF(drive)->ata_output_data(drive, buffer, wcount);
-		ata_bswap_data(buffer, wcount);
-	} else {
-		HWIF(drive)->ata_output_data(drive, buffer, wcount);
-	}
+	ide_set_irq(drive, 1);
+
+	if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0)
+		SELECT_MASK(drive, 0);
+
+	if (task->tf_flags & IDE_TFLAG_OUT_DATA)
+		hwif->OUTW((tf->hob_data << 8) | tf->data, IDE_DATA_REG);
+
+	if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
+		hwif->OUTB(tf->hob_feature, IDE_FEATURE_REG);
+	if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
+		hwif->OUTB(tf->hob_nsect, IDE_NSECTOR_REG);
+	if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
+		hwif->OUTB(tf->hob_lbal, IDE_SECTOR_REG);
+	if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
+		hwif->OUTB(tf->hob_lbam, IDE_LCYL_REG);
+	if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
+		hwif->OUTB(tf->hob_lbah, IDE_HCYL_REG);
+
+	if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
+		hwif->OUTB(tf->feature, IDE_FEATURE_REG);
+	if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
+		hwif->OUTB(tf->nsect, IDE_NSECTOR_REG);
+	if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
+		hwif->OUTB(tf->lbal, IDE_SECTOR_REG);
+	if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
+		hwif->OUTB(tf->lbam, IDE_LCYL_REG);
+	if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
+		hwif->OUTB(tf->lbah, IDE_HCYL_REG);
+
+	if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
+		hwif->OUTB((tf->device & HIHI) | drive->select.all, IDE_SELECT_REG);
 }
 
 int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
 {
 	ide_task_t args;
+
 	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tf.nsect = 0x01;
 	if (drive->media == ide_disk)
-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_IDENTIFY;
+		args.tf.command = WIN_IDENTIFY;
 	else
-		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_PIDENTIFY;
-	args.command_type = IDE_DRIVE_TASK_IN;
-	args.data_phase   = TASKFILE_IN;
-	args.handler	  = &task_in_intr;
-	return ide_raw_taskfile(drive, &args, buf);
+		args.tf.command = WIN_PIDENTIFY;
+	args.tf_flags	= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
+	args.data_phase	= TASKFILE_IN;
+	return ide_raw_taskfile(drive, &args, buf, 1);
 }
 
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+static int inline task_dma_ok(ide_task_t *task)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
-	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
-	u8 HIHI			= (drive->addressing == 1) ? 0xE0 : 0xEF;
-
-	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
-	if (IDE_CONTROL_REG) {
-		/* clear nIEN */
-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-	}
-	SELECT_MASK(drive, 0);
-
-	if (drive->addressing == 1) {
-		hwif->OUTB(hobfile->feature, IDE_FEATURE_REG);
-		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
-		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
-		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
-		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
-	}
-
-	hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
-	hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
-	hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
-	hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
-	hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
-
-	hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
-
-	if (task->handler != NULL) {
-		if (task->prehandler != NULL) {
-			hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
-			ndelay(400);	/* FIXME */
-			return task->prehandler(drive, task->rq);
-		}
-		ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
-		return ide_started;
-	}
+	if (blk_fs_request(task->rq) || (task->tf_flags & IDE_TFLAG_FLAGGED))
+		return 1;
 
-	if (!drive->using_dma)
-		return ide_stopped;
-
-	switch (taskfile->command) {
+	switch (task->tf.command) {
 		case WIN_WRITEDMA_ONCE:
 		case WIN_WRITEDMA:
 		case WIN_WRITEDMA_EXT:
@@ -129,24 +117,79 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
 		case WIN_READDMA:
 		case WIN_READDMA_EXT:
 		case WIN_IDENTIFY_DMA:
-			if (!hwif->dma_setup(drive)) {
-				hwif->dma_exec_cmd(drive, taskfile->command);
-				hwif->dma_start(drive);
-				return ide_started;
-			}
-			break;
-		default:
-			if (task->handler == NULL)
-				return ide_stopped;
+			return 1;
 	}
 
-	return ide_stopped;
+	return 0;
 }
 
+static ide_startstop_t task_no_data_intr(ide_drive_t *);
+static ide_startstop_t set_geometry_intr(ide_drive_t *);
+static ide_startstop_t recal_intr(ide_drive_t *);
+static ide_startstop_t set_multmode_intr(ide_drive_t *);
+static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
+static ide_startstop_t task_in_intr(ide_drive_t *);
+
+ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct ide_taskfile *tf = &task->tf;
+	ide_handler_t *handler = NULL;
+
+	if (task->data_phase == TASKFILE_MULTI_IN ||
+	    task->data_phase == TASKFILE_MULTI_OUT) {
+		if (!drive->mult_count) {
+			printk(KERN_ERR "%s: multimode not set!\n",
+					drive->name);
+			return ide_stopped;
+		}
+	}
+
+	if (task->tf_flags & IDE_TFLAG_FLAGGED)
+		task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
+
+	if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0)
+		ide_tf_load(drive, task);
+
+	switch (task->data_phase) {
+	case TASKFILE_MULTI_OUT:
+	case TASKFILE_OUT:
+		hwif->OUTBSYNC(drive, tf->command, IDE_COMMAND_REG);
+		ndelay(400);	/* FIXME */
+		return pre_task_out_intr(drive, task->rq);
+	case TASKFILE_MULTI_IN:
+	case TASKFILE_IN:
+		handler = task_in_intr;
+		/* fall-through */
+	case TASKFILE_NO_DATA:
+		if (handler == NULL)
+			handler = task_no_data_intr;
+		/* WIN_{SPECIFY,RESTORE,SETMULT} use custom handlers */
+		if (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) {
+			switch (tf->command) {
+			case WIN_SPECIFY: handler = set_geometry_intr;	break;
+			case WIN_RESTORE: handler = recal_intr;		break;
+			case WIN_SETMULT: handler = set_multmode_intr;	break;
+			}
+		}
+		ide_execute_command(drive, tf->command, handler,
+				    WAIT_WORSTCASE, NULL);
+		return ide_started;
+	default:
+		if (task_dma_ok(task) == 0 || drive->using_dma == 0 ||
+		    hwif->dma_setup(drive))
+			return ide_stopped;
+		hwif->dma_exec_cmd(drive, tf->command);
+		hwif->dma_start(drive);
+		return ide_started;
+	}
+}
+EXPORT_SYMBOL_GPL(do_rw_taskfile);
+
 /*
  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  */
-ide_startstop_t set_multmode_intr (ide_drive_t *drive)
+static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	u8 stat;
@@ -164,7 +207,7 @@ ide_startstop_t set_multmode_intr (ide_drive_t *drive)
 /*
  * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
  */
-ide_startstop_t set_geometry_intr (ide_drive_t *drive)
+static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	int retries = 5;
@@ -187,7 +230,7 @@ ide_startstop_t set_geometry_intr (ide_drive_t *drive)
 /*
  * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
  */
-ide_startstop_t recal_intr (ide_drive_t *drive)
+static ide_startstop_t recal_intr(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	u8 stat;
@@ -200,7 +243,7 @@ ide_startstop_t recal_intr (ide_drive_t *drive)
 /*
  * Handler for commands without a data phase
  */
-ide_startstop_t task_no_data_intr (ide_drive_t *drive)
+static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
 {
 	ide_task_t *args	= HWGROUP(drive)->rq->special;
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -217,9 +260,7 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive)
 	return ide_stopped;
 }
 
-EXPORT_SYMBOL(task_no_data_intr);
-
-static u8 wait_drive_not_busy(ide_drive_t *drive)
+u8 wait_drive_not_busy(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	int retries;
@@ -227,8 +268,7 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
 
 	/*
 	 * Last sector was transfered, wait until drive is ready.
-	 * This can take up to 10 usec, but we will wait max 1 ms
-	 * (drive_cmd_intr() waits that long).
+	 * This can take up to 10 usec, but we will wait max 1 ms.
 	 */
 	for (retries = 0; retries < 100; retries++) {
 		if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
@@ -283,9 +323,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
 
 	/* do the actual data transfer */
 	if (write)
-		taskfile_output_data(drive, buf, SECTOR_WORDS);
+		hwif->ata_output_data(drive, buf, SECTOR_WORDS);
 	else
-		taskfile_input_data(drive, buf, SECTOR_WORDS);
+		hwif->ata_input_data(drive, buf, SECTOR_WORDS);
 
 	kunmap_atomic(buf, KM_BIO_SRC_IRQ);
 #ifdef CONFIG_HIGHMEM
@@ -305,9 +345,18 @@ static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
 static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
 				     unsigned int write)
 {
+	u8 saved_io_32bit = drive->io_32bit;
+
 	if (rq->bio)	/* fs request */
 		rq->errors = 0;
 
+	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+		ide_task_t *task = rq->special;
+
+		if (task->tf_flags & IDE_TFLAG_IO_16BIT)
+			drive->io_32bit = 0;
+	}
+
 	touch_softlockup_watchdog();
 
 	switch (drive->hwif->data_phase) {
@@ -319,6 +368,8 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
 		ide_pio_sector(drive, write);
 		break;
 	}
+
+	drive->io_32bit = saved_io_32bit;
 }
 
 static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
@@ -356,40 +407,35 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
 	return ide_error(drive, s, stat);
 }
 
-static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
+void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
 {
-	HWIF(drive)->cursg = NULL;
-
 	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-		ide_task_t *task = rq->special;
+		u8 err = drive->hwif->INB(IDE_ERROR_REG);
 
-		if (task->tf_out_flags.all) {
-			u8 err = drive->hwif->INB(IDE_ERROR_REG);
-			ide_end_drive_cmd(drive, stat, err);
-			return;
-		}
+		ide_end_drive_cmd(drive, stat, err);
+		return;
 	}
 
 	if (rq->rq_disk) {
 		ide_driver_t *drv;
 
 		drv = *(ide_driver_t **)rq->rq_disk->private_data;;
-		drv->end_request(drive, 1, rq->hard_nr_sectors);
+		drv->end_request(drive, 1, rq->nr_sectors);
 	} else
-		ide_end_request(drive, 1, rq->hard_nr_sectors);
+		ide_end_request(drive, 1, rq->nr_sectors);
 }
 
 /*
  * Handler for command with PIO data-in phase (Read/Read Multiple).
  */
-ide_startstop_t task_in_intr (ide_drive_t *drive)
+static ide_startstop_t task_in_intr(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = drive->hwif;
 	struct request *rq = HWGROUP(drive)->rq;
 	u8 stat = hwif->INB(IDE_STATUS_REG);
 
 	/* new way for dealing with premature shared PCI interrupts */
-	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+	if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
 		if (stat & (ERR_STAT | DRQ_STAT))
 			return task_error(drive, rq, __FUNCTION__, stat);
 		/* No data yet, so wait for another IRQ. */
@@ -402,7 +448,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
 	/* If it was the last datablock check status and finish transfer. */
 	if (!hwif->nleft) {
 		stat = wait_drive_not_busy(drive);
-		if (!OK_STAT(stat, 0, BAD_R_STAT))
+		if (!OK_STAT(stat, 0, BAD_STAT))
 			return task_error(drive, rq, __FUNCTION__, stat);
 		task_end_request(drive, rq, stat);
 		return ide_stopped;
@@ -413,7 +459,6 @@ ide_startstop_t task_in_intr (ide_drive_t *drive)
 
 	return ide_started;
 }
-EXPORT_SYMBOL(task_in_intr);
 
 /*
  * Handler for command with PIO data-out phase (Write/Write Multiple).
@@ -443,11 +488,11 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive)
 	return ide_started;
 }
 
-ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
+static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
 {
 	ide_startstop_t startstop;
 
-	if (ide_wait_stat(&startstop, drive, DATA_READY,
+	if (ide_wait_stat(&startstop, drive, DRQ_STAT,
 			  drive->bad_wstat, WAIT_DRQ)) {
 		printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
 				drive->name,
@@ -464,9 +509,8 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
 
 	return ide_started;
 }
-EXPORT_SYMBOL(pre_task_out_intr);
 
-static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
+int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
 {
 	struct request rq;
 
@@ -481,36 +525,27 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
 	 * if we would find a solution to transfer any size.
 	 * To support special commands like READ LONG.
 	 */
-	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {
-		if (data_size == 0)
-			rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
-		else
-			rq.nr_sectors = data_size / SECTOR_SIZE;
-
-		if (!rq.nr_sectors) {
-			printk(KERN_ERR "%s: in/out command without data\n",
-					drive->name);
-			return -EFAULT;
-		}
+	rq.hard_nr_sectors = rq.nr_sectors = nsect;
+	rq.hard_cur_sectors = rq.current_nr_sectors = nsect;
 
-		rq.hard_nr_sectors = rq.nr_sectors;
-		rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
+	if (task->tf_flags & IDE_TFLAG_WRITE)
+		rq.cmd_flags |= REQ_RW;
 
-		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-			rq.cmd_flags |= REQ_RW;
-	}
+	rq.special = task;
+	task->rq = &rq;
 
-	rq.special = args;
-	args->rq = &rq;
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
+EXPORT_SYMBOL(ide_raw_taskfile);
+
+int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task)
 {
-	return ide_diag_taskfile(drive, args, 0, buf);
-}
+	task->data_phase = TASKFILE_NO_DATA;
 
-EXPORT_SYMBOL(ide_raw_taskfile);
+	return ide_raw_taskfile(drive, task, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(ide_no_data_taskfile);
 
 #ifdef CONFIG_IDE_TASK_IOCTL
 int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
@@ -519,13 +554,12 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 	ide_task_t		args;
 	u8 *outbuf		= NULL;
 	u8 *inbuf		= NULL;
-	task_ioreg_t *argsptr	= args.tfRegister;
-	task_ioreg_t *hobsptr	= args.hobRegister;
+	u8 *data_buf		= NULL;
 	int err			= 0;
 	int tasksize		= sizeof(struct ide_task_request_s);
 	unsigned int taskin	= 0;
 	unsigned int taskout	= 0;
-	u8 io_32bit		= drive->io_32bit;
+	u16 nsect		= 0;
 	char __user *buf = (char __user *)arg;
 
 //	printk("IDE Taskfile ...\n");
@@ -572,24 +606,52 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 	}
 
 	memset(&args, 0, sizeof(ide_task_t));
-	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
-	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);
 
-	args.tf_in_flags  = req_task->in_flags;
-	args.tf_out_flags = req_task->out_flags;
-	args.data_phase   = req_task->data_phase;
-	args.command_type = req_task->req_cmd;
+	memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
+	memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
+
+	args.data_phase = req_task->data_phase;
+
+	args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
+			IDE_TFLAG_IN_TF;
+	if (drive->addressing == 1)
+		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
+
+	if (req_task->out_flags.all) {
+		args.tf_flags |= IDE_TFLAG_FLAGGED;
+
+		if (req_task->out_flags.b.data)
+			args.tf_flags |= IDE_TFLAG_OUT_DATA;
+
+		if (req_task->out_flags.b.nsector_hob)
+			args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT;
+		if (req_task->out_flags.b.sector_hob)
+			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL;
+		if (req_task->out_flags.b.lcyl_hob)
+			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM;
+		if (req_task->out_flags.b.hcyl_hob)
+			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH;
+
+		if (req_task->out_flags.b.error_feature)
+			args.tf_flags |= IDE_TFLAG_OUT_FEATURE;
+		if (req_task->out_flags.b.nsector)
+			args.tf_flags |= IDE_TFLAG_OUT_NSECT;
+		if (req_task->out_flags.b.sector)
+			args.tf_flags |= IDE_TFLAG_OUT_LBAL;
+		if (req_task->out_flags.b.lcyl)
+			args.tf_flags |= IDE_TFLAG_OUT_LBAM;
+		if (req_task->out_flags.b.hcyl)
+			args.tf_flags |= IDE_TFLAG_OUT_LBAH;
+	} else {
+		args.tf_flags |= IDE_TFLAG_OUT_TF;
+		if (args.tf_flags & IDE_TFLAG_LBA48)
+			args.tf_flags |= IDE_TFLAG_OUT_HOB;
+	}
+
+	if (req_task->in_flags.b.data)
+		args.tf_flags |= IDE_TFLAG_IN_DATA;
 
-	drive->io_32bit = 0;
 	switch(req_task->data_phase) {
-		case TASKFILE_OUT_DMAQ:
-		case TASKFILE_OUT_DMA:
-			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
-			break;
-		case TASKFILE_IN_DMAQ:
-		case TASKFILE_IN_DMA:
-			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
-			break;
 		case TASKFILE_MULTI_OUT:
 			if (!drive->mult_count) {
 				/* (hs): give up if multcount is not set */
@@ -601,9 +663,11 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 			}
 			/* fall through */
 		case TASKFILE_OUT:
-			args.prehandler = &pre_task_out_intr;
-			args.handler = &task_out_intr;
-			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
+			/* fall through */
+		case TASKFILE_OUT_DMAQ:
+		case TASKFILE_OUT_DMA:
+			nsect = taskout / SECTOR_SIZE;
+			data_buf = outbuf;
 			break;
 		case TASKFILE_MULTI_IN:
 			if (!drive->mult_count) {
@@ -616,22 +680,46 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 			}
 			/* fall through */
 		case TASKFILE_IN:
-			args.handler = &task_in_intr;
-			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
+			/* fall through */
+		case TASKFILE_IN_DMAQ:
+		case TASKFILE_IN_DMA:
+			nsect = taskin / SECTOR_SIZE;
+			data_buf = inbuf;
 			break;
 		case TASKFILE_NO_DATA:
-			args.handler = &task_no_data_intr;
-			err = ide_diag_taskfile(drive, &args, 0, NULL);
 			break;
 		default:
 			err = -EFAULT;
 			goto abort;
 	}
 
-	memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);
-	memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);
-	req_task->in_flags  = args.tf_in_flags;
-	req_task->out_flags = args.tf_out_flags;
+	if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
+		nsect = 0;
+	else if (!nsect) {
+		nsect = (args.tf.hob_nsect << 8) | args.tf.nsect;
+
+		if (!nsect) {
+			printk(KERN_ERR "%s: in/out command without data\n",
+					drive->name);
+			err = -EFAULT;
+			goto abort;
+		}
+	}
+
+	if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE)
+		args.tf_flags |= IDE_TFLAG_WRITE;
+
+	err = ide_raw_taskfile(drive, &args, data_buf, nsect);
+
+	memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2);
+	memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE);
+
+	if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) &&
+	    req_task->in_flags.all == 0) {
+		req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
+		if (drive->addressing == 1)
+			req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
+	}
 
 	if (copy_to_user(buf, req_task, tasksize)) {
 		err = -EFAULT;
@@ -658,40 +746,24 @@ abort:
 
 //	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
 
-	drive->io_32bit = io_32bit;
-
 	return err;
 }
 #endif
 
-int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
-{
-	struct request rq;
-	u8 buffer[4];
-
-	if (!buf)
-		buf = buffer;
-	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
-	ide_init_drive_cmd(&rq);
-	rq.buffer = buf;
-	*buf++ = cmd;
-	*buf++ = nsect;
-	*buf++ = feature;
-	*buf++ = sectors;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
 int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 {
-	int err = 0;
-	u8 args[4], *argbuf = args;
-	u8 xfer_rate = 0;
-	int argsize = 4;
+	u8 *buf = NULL;
+	int bufsize = 0, err = 0;
+	u8 args[4], xfer_rate = 0;
 	ide_task_t tfargs;
+	struct ide_taskfile *tf = &tfargs.tf;
 
 	if (NULL == (void *) arg) {
 		struct request rq;
+
 		ide_init_drive_cmd(&rq);
+		rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+
 		return ide_do_drive_cmd(drive, &rq, ide_wait);
 	}
 
@@ -699,27 +771,40 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 		return -EFAULT;
 
 	memset(&tfargs, 0, sizeof(ide_task_t));
-	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
-	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
-	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
-	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
-	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
-	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
-	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+	tf->feature = args[2];
+	if (args[0] == WIN_SMART) {
+		tf->nsect = args[3];
+		tf->lbal  = args[1];
+		tf->lbam  = 0x4f;
+		tf->lbah  = 0xc2;
+		tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
+	} else {
+		tf->nsect = args[1];
+		tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
+				  IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
+	}
+	tf->command = args[0];
+	tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
 
 	if (args[3]) {
-		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
-		argbuf = kzalloc(argsize, GFP_KERNEL);
-		if (argbuf == NULL)
+		tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
+		bufsize = SECTOR_WORDS * 4 * args[3];
+		buf = kzalloc(bufsize, GFP_KERNEL);
+		if (buf == NULL)
 			return -ENOMEM;
 	}
+
 	if (set_transfer(drive, &tfargs)) {
 		xfer_rate = args[1];
 		if (ide_ata66_check(drive, &tfargs))
 			goto abort;
 	}
 
-	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+	err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
+
+	args[0] = tf->status;
+	args[1] = tf->error;
+	args[2] = tf->nsect;
 
 	if (!err && xfer_rate) {
 		/* active-retuning-calls future */
@@ -727,142 +812,38 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 		ide_driveid_update(drive);
 	}
 abort:
-	if (copy_to_user((void __user *)arg, argbuf, argsize))
+	if (copy_to_user((void __user *)arg, &args, 4))
 		err = -EFAULT;
-	if (argsize > 4)
-		kfree(argbuf);
+	if (buf) {
+		if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
+			err = -EFAULT;
+		kfree(buf);
+	}
 	return err;
 }
 
-static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf)
-{
-	struct request rq;
-
-	ide_init_drive_cmd(&rq);
-	rq.cmd_type = REQ_TYPE_ATA_TASK;
-	rq.buffer = buf;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
 int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 {
 	void __user *p = (void __user *)arg;
 	int err = 0;
-	u8 args[7], *argbuf = args;
-	int argsize = 7;
+	u8 args[7];
+	ide_task_t task;
 
 	if (copy_from_user(args, p, 7))
 		return -EFAULT;
-	err = ide_wait_cmd_task(drive, argbuf);
-	if (copy_to_user(p, argbuf, argsize))
-		err = -EFAULT;
-	return err;
-}
-
-/*
- * NOTICE: This is additions from IBM to provide a discrete interface,
- * for selective taskregister access operations.  Nice JOB Klaus!!!
- * Glad to be able to work and co-develop this with you and IBM.
- */
-ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
-	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;
-
-	if (task->data_phase == TASKFILE_MULTI_IN ||
-	    task->data_phase == TASKFILE_MULTI_OUT) {
-		if (!drive->mult_count) {
-			printk(KERN_ERR "%s: multimode not set!\n", drive->name);
-			return ide_stopped;
-		}
-	}
 
-	/*
-	 * (ks) Check taskfile in flags.
-	 * If set, then execute as it is defined.
-	 * If not set, then define default settings.
-	 * The default values are:
-	 *	read all taskfile registers (except data)
-	 *	read the hob registers (sector, nsector, lcyl, hcyl)
-	 */
-	if (task->tf_in_flags.all == 0) {
-		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
-		if (drive->addressing == 1)
-			task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);
-        }
-
-	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */
-	if (IDE_CONTROL_REG)
-		/* clear nIEN */
-		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
-	SELECT_MASK(drive, 0);
-
-	if (task->tf_out_flags.b.data) {
-		u16 data =  taskfile->data + (hobfile->data << 8);
-		hwif->OUTW(data, IDE_DATA_REG);
-	}
-
-	/* (ks) send hob registers first */
-	if (task->tf_out_flags.b.nsector_hob)
-		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);
-	if (task->tf_out_flags.b.sector_hob)
-		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);
-	if (task->tf_out_flags.b.lcyl_hob)
-		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);
-	if (task->tf_out_flags.b.hcyl_hob)
-		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);
-
-	/* (ks) Send now the standard registers */
-	if (task->tf_out_flags.b.error_feature)
-		hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);
-	/* refers to number of sectors to transfer */
-	if (task->tf_out_flags.b.nsector)
-		hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to sector offset or start sector */
-	if (task->tf_out_flags.b.sector)
-		hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);
-	if (task->tf_out_flags.b.lcyl)
-		hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);
-	if (task->tf_out_flags.b.hcyl)
-		hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);
-
-        /*
-	 * (ks) In the flagged taskfile approch, we will use all specified
-	 * registers and the register value will not be changed, except the
-	 * select bit (master/slave) in the drive_head register. We must make
-	 * sure that the desired drive is selected.
-	 */
-	hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
-	switch(task->data_phase) {
+	memset(&task, 0, sizeof(task));
+	memcpy(&task.tf_array[7], &args[1], 6);
+	task.tf.command = args[0];
+	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
 
-   	        case TASKFILE_OUT_DMAQ:
-		case TASKFILE_OUT_DMA:
-		case TASKFILE_IN_DMAQ:
-		case TASKFILE_IN_DMA:
-			if (!drive->using_dma)
-				break;
+	err = ide_no_data_taskfile(drive, &task);
 
-			if (!hwif->dma_setup(drive)) {
-				hwif->dma_exec_cmd(drive, taskfile->command);
-				hwif->dma_start(drive);
-				return ide_started;
-			}
-			break;
+	args[0] = task.tf.command;
+	memcpy(&args[1], &task.tf_array[7], 6);
 
-	        default:
- 			if (task->handler == NULL)
-				return ide_stopped;
-
-			/* Issue the command */
-			if (task->prehandler) {
-				hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
-				ndelay(400);	/* FIXME */
-				return task->prehandler(drive, task->rq);
-			}
-			ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
-			return ide_started;
-	}
+	if (copy_to_user(p, args, 7))
+		err = -EFAULT;
 
-	return ide_stopped;
+	return err;
 }
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 54943da6e4e5..97894abd9ebc 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -95,7 +95,7 @@ DEFINE_MUTEX(ide_cfg_mtx);
  __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
 
 #ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
+int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
 #endif
 
 int noautodma = 0;
@@ -116,7 +116,7 @@ EXPORT_SYMBOL(ide_hwifs);
 /*
  * Do not even *think* about calling this!
  */
-static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
+void ide_init_port_data(ide_hwif_t *hwif, unsigned int index)
 {
 	unsigned int unit;
 
@@ -159,6 +159,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
 		init_completion(&drive->gendev_rel_comp);
 	}
 }
+EXPORT_SYMBOL_GPL(ide_init_port_data);
 
 static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
 {
@@ -177,8 +178,6 @@ static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
 #endif
 }
 
-extern void ide_arm_init(void);
-
 /*
  * init_ide_data() sets reasonable default values into all fields
  * of all instances of the hwifs and drives, but only on the first call.
@@ -210,16 +209,13 @@ static void __init init_ide_data (void)
 	/* Initialise all interface structures */
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		hwif = &ide_hwifs[index];
-		init_hwif_data(hwif, index);
+		ide_init_port_data(hwif, index);
 		init_hwif_default(hwif, index);
 #if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI)
 		hwif->irq =
 			ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
 #endif
 	}
-#ifdef CONFIG_IDE_ARM
-	ide_arm_init();
-#endif
 }
 
 /**
@@ -414,8 +410,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
 	hwif->cds			= tmp_hwif->cds;
 #endif
 
-	hwif->fixup			= tmp_hwif->fixup;
-
 	hwif->set_pio_mode		= tmp_hwif->set_pio_mode;
 	hwif->set_dma_mode		= tmp_hwif->set_dma_mode;
 	hwif->mdma_filter		= tmp_hwif->mdma_filter;
@@ -424,7 +418,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
 	hwif->reset_poll		= tmp_hwif->reset_poll;
 	hwif->pre_reset			= tmp_hwif->pre_reset;
 	hwif->resetproc			= tmp_hwif->resetproc;
-	hwif->intrproc			= tmp_hwif->intrproc;
 	hwif->maskproc			= tmp_hwif->maskproc;
 	hwif->quirkproc			= tmp_hwif->quirkproc;
 	hwif->busproc			= tmp_hwif->busproc;
@@ -434,16 +427,13 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
 	hwif->atapi_input_bytes		= tmp_hwif->atapi_input_bytes;
 	hwif->atapi_output_bytes	= tmp_hwif->atapi_output_bytes;
 
+	hwif->dma_host_set		= tmp_hwif->dma_host_set;
 	hwif->dma_setup			= tmp_hwif->dma_setup;
 	hwif->dma_exec_cmd		= tmp_hwif->dma_exec_cmd;
 	hwif->dma_start			= tmp_hwif->dma_start;
 	hwif->ide_dma_end		= tmp_hwif->ide_dma_end;
-	hwif->ide_dma_on		= tmp_hwif->ide_dma_on;
-	hwif->dma_off_quietly		= tmp_hwif->dma_off_quietly;
 	hwif->ide_dma_test_irq		= tmp_hwif->ide_dma_test_irq;
 	hwif->ide_dma_clear_irq		= tmp_hwif->ide_dma_clear_irq;
-	hwif->dma_host_on		= tmp_hwif->dma_host_on;
-	hwif->dma_host_off		= tmp_hwif->dma_host_off;
 	hwif->dma_lost_irq		= tmp_hwif->dma_lost_irq;
 	hwif->dma_timeout		= tmp_hwif->dma_timeout;
 
@@ -468,7 +458,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
 #endif
 
 	hwif->dma_base			= tmp_hwif->dma_base;
-	hwif->dma_master		= tmp_hwif->dma_master;
 	hwif->dma_command		= tmp_hwif->dma_command;
 	hwif->dma_vendor1		= tmp_hwif->dma_vendor1;
 	hwif->dma_status		= tmp_hwif->dma_status;
@@ -602,7 +591,6 @@ void ide_unregister(unsigned int index)
 		(void) ide_release_dma(hwif);
 
 		hwif->dma_base = 0;
-		hwif->dma_master = 0;
 		hwif->dma_command = 0;
 		hwif->dma_vendor1 = 0;
 		hwif->dma_status = 0;
@@ -617,7 +605,7 @@ void ide_unregister(unsigned int index)
 	tmp_hwif = *hwif;
 
 	/* restore hwif data to pristine status */
-	init_hwif_data(hwif, index);
+	ide_init_port_data(hwif, index);
 	init_hwif_default(hwif, index);
 
 	ide_hwif_restore(hwif, &tmp_hwif);
@@ -683,24 +671,34 @@ void ide_setup_ports (	hw_regs_t *hw,
  */
 }
 
+void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw)
+{
+	memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
+	hwif->irq = hw->irq;
+	hwif->noprobe = 0;
+	hwif->chipset = hw->chipset;
+	hwif->gendev.parent = hw->dev;
+	hwif->ack_intr = hw->ack_intr;
+}
+EXPORT_SYMBOL_GPL(ide_init_port_hw);
+
 /**
  *	ide_register_hw		-	register IDE interface
  *	@hw: hardware registers
- *	@fixup: fixup function
- *	@initializing: set while initializing built-in drivers
+ *	@quirkproc: quirkproc function
  *	@hwifp: pointer to returned hwif
  *
  *	Register an IDE interface, specifying exactly the registers etc.
- *	Set init=1 iff calling before probes have taken place.
  *
  *	Returns -1 on error.
  */
 
-int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
-		    int initializing, ide_hwif_t **hwifp)
+int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *),
+		    ide_hwif_t **hwifp)
 {
 	int index, retry = 1;
 	ide_hwif_t *hwif;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
 	do {
 		for (index = 0; index < MAX_HWIFS; ++index) {
@@ -712,8 +710,7 @@ int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
 			hwif = &ide_hwifs[index];
 			if (hwif->hold)
 				continue;
-			if ((!hwif->present && !hwif->mate && !initializing) ||
-			    (!hwif->io_ports[IDE_DATA_OFFSET] && initializing))
+			if (!hwif->present && hwif->mate == NULL)
 				goto found;
 		}
 		for (index = 0; index < MAX_HWIFS; index++)
@@ -724,29 +721,23 @@ found:
 	if (hwif->present)
 		ide_unregister(index);
 	else if (!hwif->hold) {
-		init_hwif_data(hwif, index);
+		ide_init_port_data(hwif, index);
 		init_hwif_default(hwif, index);
 	}
 	if (hwif->present)
 		return -1;
-	memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
-	hwif->irq = hw->irq;
-	hwif->noprobe = 0;
-	hwif->fixup = fixup;
-	hwif->chipset = hw->chipset;
-	hwif->gendev.parent = hw->dev;
-	hwif->ack_intr = hw->ack_intr;
 
-	if (initializing == 0) {
-		u8 idx[4] = { index, 0xff, 0xff, 0xff };
+	ide_init_port_hw(hwif, hw);
+	hwif->quirkproc = quirkproc;
 
-		ide_device_add(idx);
-	}
+	idx[0] = index;
+
+	ide_device_add(idx);
 
 	if (hwifp)
 		*hwifp = hwif;
 
-	return (initializing || hwif->present) ? index : -1;
+	return hwif->present ? index : -1;
 }
 
 EXPORT_SYMBOL(ide_register_hw);
@@ -839,7 +830,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
 	if (!drive->id || !(drive->id->capability & 1))
 		goto out;
 
-	if (hwif->ide_dma_on == NULL)
+	if (hwif->dma_host_set == NULL)
 		goto out;
 
 	err = -EBUSY;
@@ -854,8 +845,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
 	err = 0;
 
 	if (arg) {
-		hwif->dma_off_quietly(drive);
-		if (ide_set_dma(drive) || hwif->ide_dma_on(drive))
+		if (ide_set_dma(drive))
 			err = -EIO;
 	} else
 		ide_dma_off(drive);
@@ -888,7 +878,10 @@ int set_pio_mode(ide_drive_t *drive, int arg)
 
 	if (drive->special.b.set_tune)
 		return -EBUSY;
+
 	ide_init_drive_cmd(&rq);
+	rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+
 	drive->tune_req = (u8) arg;
 	drive->special.b.set_tune = 1;
 	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
@@ -1070,7 +1063,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
 			ide_init_hwif_ports(&hw, (unsigned long) args[0],
 					    (unsigned long) args[1], NULL);
 			hw.irq = args[2];
-			if (ide_register_hw(&hw, NULL, 0, NULL) == -1)
+			if (ide_register_hw(&hw, NULL, NULL) == -1)
 				return -EIO;
 			return 0;
 		}
@@ -1231,26 +1224,12 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m
 	return 0;	/* zero = nothing matched */
 }
 
-#ifdef CONFIG_BLK_DEV_ALI14XX
 extern int probe_ali14xx;
-extern int ali14xx_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_UMC8672
 extern int probe_umc8672;
-extern int umc8672_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_DTC2278
 extern int probe_dtc2278;
-extern int dtc2278_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_HT6560B
 extern int probe_ht6560b;
-extern int ht6560b_init(void);
-#endif
-#ifdef CONFIG_BLK_DEV_QD65XX
 extern int probe_qd65xx;
-extern int qd65xx_init(void);
-#endif
+extern int cmd640_vlb;
 
 static int __initdata is_chipset_set[MAX_HWIFS];
 
@@ -1327,7 +1306,7 @@ static int __init ide_setup(char *s)
 	if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
 		const char *hd_words[] = {
 			"none", "noprobe", "nowerr", "cdrom", "nodma",
-			"autotune", "noautotune", "minus8", "swapdata", "bswap",
+			"autotune", "noautotune", "-8", "-9", "-10",
 			"noflush", "remap", "remap63", "scsi", NULL };
 		unit = s[2] - 'a';
 		hw   = unit / MAX_DRIVES;
@@ -1363,10 +1342,6 @@ static int __init ide_setup(char *s)
 			case -7: /* "noautotune" */
 				drive->autotune = IDE_TUNE_NOAUTO;
 				goto obsolete_option;
-			case -9: /* "swapdata" */
-			case -10: /* "bswap" */
-				drive->bswap = 1;
-				goto done;
 			case -11: /* noflush */
 				drive->noflush = 1;
 				goto done;
@@ -1466,11 +1441,8 @@ static int __init ide_setup(char *s)
 #endif
 #ifdef CONFIG_BLK_DEV_CMD640
 			case -14: /* "cmd640_vlb" */
-			{
-				extern int cmd640_vlb; /* flag for cmd640.c */
 				cmd640_vlb = 1;
 				goto done;
-			}
 #endif
 #ifdef CONFIG_BLK_DEV_HT6560B
 			case -13: /* "ht6560b" */
@@ -1560,79 +1532,6 @@ done:
 	return 1;
 }
 
-extern void __init pnpide_init(void);
-extern void __exit pnpide_exit(void);
-extern void __init h8300_ide_init(void);
-
-/*
- * probe_for_hwifs() finds/initializes "known" IDE interfaces
- */
-static void __init probe_for_hwifs (void)
-{
-#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-	ide_scan_pcibus(ide_scan_direction);
-#endif
-
-#ifdef CONFIG_ETRAX_IDE
-	{
-		extern void init_e100_ide(void);
-		init_e100_ide();
-	}
-#endif /* CONFIG_ETRAX_IDE */
-#ifdef CONFIG_BLK_DEV_CMD640
-	{
-		extern void ide_probe_for_cmd640x(void);
-		ide_probe_for_cmd640x();
-	}
-#endif /* CONFIG_BLK_DEV_CMD640 */
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	{
-		extern int pmac_ide_probe(void);
-		(void)pmac_ide_probe();
-	}
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#ifdef CONFIG_BLK_DEV_GAYLE
-	{
-		extern void gayle_init(void);
-		gayle_init();
-	}
-#endif /* CONFIG_BLK_DEV_GAYLE */
-#ifdef CONFIG_BLK_DEV_FALCON_IDE
-	{
-		extern void falconide_init(void);
-		falconide_init();
-	}
-#endif /* CONFIG_BLK_DEV_FALCON_IDE */
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-	{
-		extern void macide_init(void);
-		macide_init();
-	}
-#endif /* CONFIG_BLK_DEV_MAC_IDE */
-#ifdef CONFIG_BLK_DEV_Q40IDE
-	{
-		extern void q40ide_init(void);
-		q40ide_init();
-	}
-#endif /* CONFIG_BLK_DEV_Q40IDE */
-#ifdef CONFIG_BLK_DEV_BUDDHA
-	{
-		extern void buddha_init(void);
-		buddha_init();
-	}
-#endif /* CONFIG_BLK_DEV_BUDDHA */
-#ifdef CONFIG_BLK_DEV_IDEPNP
-	pnpide_init();
-#endif
-#ifdef CONFIG_H8300
-	h8300_ide_init();
-#endif
-}
-
-/*
- * Probe module
- */
-
 EXPORT_SYMBOL(ide_lock);
 
 static int ide_bus_match(struct device *dev, struct device_driver *drv)
@@ -1779,30 +1678,6 @@ static int __init ide_init(void)
 
 	proc_ide_create();
 
-#ifdef CONFIG_BLK_DEV_ALI14XX
-	if (probe_ali14xx)
-		(void)ali14xx_init();
-#endif
-#ifdef CONFIG_BLK_DEV_UMC8672
-	if (probe_umc8672)
-		(void)umc8672_init();
-#endif
-#ifdef CONFIG_BLK_DEV_DTC2278
-	if (probe_dtc2278)
-		(void)dtc2278_init();
-#endif
-#ifdef CONFIG_BLK_DEV_HT6560B
-	if (probe_ht6560b)
-		(void)ht6560b_init();
-#endif
-#ifdef CONFIG_BLK_DEV_QD65XX
-	if (probe_qd65xx)
-		(void)qd65xx_init();
-#endif
-
-	/* Probe for special PCI and other "known" interface chipsets. */
-	probe_for_hwifs();
-
 	return 0;
 }
 
@@ -1838,10 +1713,6 @@ void __exit cleanup_module (void)
 	for (index = 0; index < MAX_HWIFS; ++index)
 		ide_unregister(index);
 
-#ifdef CONFIG_BLK_DEV_IDEPNP
-	pnpide_exit();
-#endif
-
 	proc_ide_destroy();
 
 	bus_unregister(&ide_bus_type);
diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
index 409822349f10..7043ec7d1e05 100644
--- a/drivers/ide/legacy/Makefile
+++ b/drivers/ide/legacy/Makefile
@@ -1,15 +1,24 @@
 
+# link order is important here
+
 obj-$(CONFIG_BLK_DEV_ALI14XX)		+= ali14xx.o
+obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
 obj-$(CONFIG_BLK_DEV_DTC2278)		+= dtc2278.o
 obj-$(CONFIG_BLK_DEV_HT6560B)		+= ht6560b.o
 obj-$(CONFIG_BLK_DEV_QD65XX)		+= qd65xx.o
-obj-$(CONFIG_BLK_DEV_UMC8672)		+= umc8672.o
 
-obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
+obj-$(CONFIG_BLK_DEV_GAYLE)		+= gayle.o
+obj-$(CONFIG_BLK_DEV_FALCON_IDE)	+= falconide.o
+obj-$(CONFIG_BLK_DEV_MAC_IDE)		+= macide.o
+obj-$(CONFIG_BLK_DEV_Q40IDE)		+= q40ide.o
+obj-$(CONFIG_BLK_DEV_BUDDHA)		+= buddha.o
 
-obj-$(CONFIG_BLK_DEV_PLATFORM)		+= ide_platform.o
+ifeq ($(CONFIG_BLK_DEV_IDECS), m)
+	obj-m += ide-cs.o
+endif
 
-# Last of all
-obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
+ifeq ($(CONFIG_BLK_DEV_PLATFORM), m)
+	obj-m += ide_platform.o
+endif
 
 EXTRA_CFLAGS	:= -Idrivers/ide
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index 38c3a6d63f30..5ec0be4cbad7 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -231,8 +231,7 @@ int probe_ali14xx = 0;
 module_param_named(probe, probe_ali14xx, bool, 0);
 MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets");
 
-/* Can be called directly from ide.c. */
-int __init ali14xx_init(void)
+static int __init ali14xx_init(void)
 {
 	if (probe_ali14xx == 0)
 		goto out;
@@ -248,9 +247,7 @@ out:
 	return -ENODEV;
 }
 
-#ifdef MODULE
 module_init(ali14xx_init);
-#endif
 
 MODULE_AUTHOR("see local file");
 MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets");
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
index 4a0be251a05f..74d28e058f55 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/legacy/buddha.c
@@ -112,6 +112,7 @@ typedef enum BuddhaType_Enum {
     BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
 } BuddhaType;
 
+static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
 
     /*
      *  Check and acknowledge the interrupt status
@@ -143,11 +144,11 @@ static int xsurf_ack_intr(ide_hwif_t *hwif)
      *  Probe for a Buddha or Catweasel IDE interface
      */
 
-void __init buddha_init(void)
+static int __init buddha_init(void)
 {
 	hw_regs_t hw;
 	ide_hwif_t *hwif;
-	int i, index;
+	int i;
 
 	struct zorro_dev *z = NULL;
 	u_long buddha_board = 0;
@@ -156,6 +157,8 @@ void __init buddha_init(void)
 
 	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
 		unsigned long board;
+		u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+
 		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
 			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
 			type=BOARD_BUDDHA;
@@ -195,7 +198,10 @@ fail_base2:
 		/* X-Surf doesn't have this.  IRQs are always on */
 		if (type != BOARD_XSURF)
 			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
-		
+
+		printk(KERN_INFO "ide: %s IDE controller\n",
+				 buddha_board_name[type]);
+
 		for(i=0;i<buddha_num_hwifs;i++) {
 			if(type != BOARD_XSURF) {
 				ide_setup_ports(&hw, (buddha_board+buddha_bases[i]),
@@ -213,23 +219,23 @@ fail_base2:
 						IRQ_AMIGA_PORTS);
 			}	
 
-			index = ide_register_hw(&hw, NULL, 1, &hwif);
-			if (index != -1) {
+			hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+			if (hwif) {
+				u8 index = hwif->index;
+
+				ide_init_port_data(hwif, index);
+				ide_init_port_hw(hwif, &hw);
+
 				hwif->mmio = 1;
-				printk("ide%d: ", index);
-				switch(type) {
-				case BOARD_BUDDHA:
-					printk("Buddha");
-					break;
-				case BOARD_CATWEASEL:
-					printk("Catweasel");
-					break;
-				case BOARD_XSURF:
-					printk("X-Surf");
-					break;
-				}
-				printk(" IDE interface\n");	    
-			}		      
+
+				idx[i] = index;
+			}
 		}
+
+		ide_device_add(idx);
 	}
+
+	return 0;
 }
+
+module_init(buddha_init);
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 24a845d45bd2..13eee6da2806 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -150,8 +150,7 @@ int probe_dtc2278 = 0;
 module_param_named(probe, probe_dtc2278, bool, 0);
 MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets");
 
-/* Can be called directly from ide.c. */
-int __init dtc2278_init(void)
+static int __init dtc2278_init(void)
 {
 	if (probe_dtc2278 == 0)
 		return -ENODEV;
@@ -163,9 +162,7 @@ int __init dtc2278_init(void)
 	return 0;
 }
 
-#ifdef MODULE
 module_init(dtc2278_init);
-#endif
 
 MODULE_AUTHOR("See Local File");
 MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets");
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index 7d7936f1b900..2860956bdcb0 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -62,19 +62,31 @@ EXPORT_SYMBOL(falconide_intr_lock);
      *  Probe for a Falcon IDE interface
      */
 
-void __init falconide_init(void)
+static int __init falconide_init(void)
 {
     if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) {
 	hw_regs_t hw;
-	int index;
+
+	printk(KERN_INFO "ide: Falcon IDE controller\n");
 
 	ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets,
 			0, 0, NULL,
 //			falconide_iops,
 			IRQ_MFP_IDE);
-	index = ide_register_hw(&hw, NULL, 1, NULL);
 
-	if (index != -1)
-	    printk("ide%d: Falcon IDE interface\n", index);
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif) {
+		u8 index = hwif->index;
+		u8 idx[4] = { index, 0xff, 0xff, 0xff };
+
+		ide_init_port_data(hwif, index);
+		ide_init_port_hw(hwif, &hw);
+
+		ide_device_add(idx);
+	}
     }
+
+    return 0;
 }
+
+module_init(falconide_init);
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index 53331ee1e957..492fa047efc0 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -110,12 +110,13 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
      *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
      */
 
-void __init gayle_init(void)
+static int __init gayle_init(void)
 {
     int a4000, i;
+    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
     if (!MACH_IS_AMIGA)
-	return;
+	return -ENODEV;
 
     if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE))
 	goto found;
@@ -125,15 +126,21 @@ void __init gayle_init(void)
 			  NULL))
 	goto found;
 #endif
-    return;
+    return -ENODEV;
 
 found:
+	printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
+			 a4000 ? 4000 : 1200,
+#ifdef CONFIG_BLK_DEV_IDEDOUBLER
+			 ide_doubler ? ", IDE doubler" :
+#endif
+			 "");
+
     for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
 	unsigned long base, ctrlport, irqport;
 	ide_ack_intr_t *ack_intr;
 	hw_regs_t hw;
 	ide_hwif_t *hwif;
-	int index;
 	unsigned long phys_base, res_start, res_n;
 
 	if (a4000) {
@@ -165,21 +172,23 @@ found:
 //			&gayle_iops,
 			IRQ_AMIGA_PORTS);
 
-	index = ide_register_hw(&hw, NULL, 1, &hwif);
-	if (index != -1) {
+	hwif = ide_find_port(base);
+	if (hwif) {
+	    u8 index = hwif->index;
+
+	    ide_init_port_data(hwif, index);
+	    ide_init_port_hw(hwif, &hw);
+
 	    hwif->mmio = 1;
-	    switch (i) {
-		case 0:
-		    printk("ide%d: Gayle IDE interface (A%d style)\n", index,
-			   a4000 ? 4000 : 1200);
-		    break;
-#ifdef CONFIG_BLK_DEV_IDEDOUBLER
-		case 1:
-		    printk("ide%d: IDE doubler\n", index);
-		    break;
-#endif /* CONFIG_BLK_DEV_IDEDOUBLER */
-	    }
+
+	    idx[i] = index;
 	} else
 	    release_mem_region(res_start, res_n);
     }
+
+    ide_device_add(idx);
+
+    return 0;
 }
+
+module_init(gayle_init);
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index a4245d13f11b..8da5031a6d05 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -307,8 +307,7 @@ int probe_ht6560b = 0;
 module_param_named(probe, probe_ht6560b, bool, 0);
 MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
 
-/* Can be called directly from ide.c. */
-int __init ht6560b_init(void)
+static int __init ht6560b_init(void)
 {
 	ide_hwif_t *hwif, *mate;
 	static u8 idx[4] = { 0, 1, 0xff, 0xff };
@@ -369,9 +368,7 @@ release_region:
 	return -ENODEV;
 }
 
-#ifdef MODULE
 module_init(ht6560b_init);
-#endif
 
 MODULE_AUTHOR("See Local File");
 MODULE_DESCRIPTION("HT-6560B EIDE-controller support");
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 03715c058664..f4ea15b32969 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -153,7 +153,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq
     hw.irq = irq;
     hw.chipset = ide_pci;
     hw.dev = &handle->dev;
-    return ide_register_hw(&hw, &ide_undecoded_slave, 0, NULL);
+    return ide_register_hw(&hw, &ide_undecoded_slave, NULL);
 }
 
 /*======================================================================
diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
index 7bb79f53dac8..69a0fb0e564f 100644
--- a/drivers/ide/legacy/ide_platform.c
+++ b/drivers/ide/legacy/ide_platform.c
@@ -28,39 +28,27 @@ static struct {
 	int index;
 } hwif_prop;
 
-static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base,
-	    void __iomem *ctrl, struct pata_platform_info *pdata, int irq,
-	    int mmio)
+static void __devinit plat_ide_setup_ports(hw_regs_t *hw,
+					   void __iomem *base,
+					   void __iomem *ctrl,
+					   struct pata_platform_info *pdata,
+					   int irq)
 {
 	unsigned long port = (unsigned long)base;
-	ide_hwif_t *hwif = ide_find_port(port);
 	int i;
 
-	if (hwif == NULL)
-		goto out;
-
-	hwif->io_ports[IDE_DATA_OFFSET] = port;
+	hw->io_ports[IDE_DATA_OFFSET] = port;
 
 	port += (1 << pdata->ioport_shift);
 	for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET;
 	     i++, port += (1 << pdata->ioport_shift))
-		hwif->io_ports[i] = port;
-
-	hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+		hw->io_ports[i] = port;
 
-	hwif->irq = irq;
+	hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
 
-	hwif->chipset = ide_generic;
+	hw->irq = irq;
 
-	if (mmio) {
-		hwif->mmio = 1;
-		default_hwif_mmiops(hwif);
-	}
-
-	hwif_prop.hwif = hwif;
-	hwif_prop.index = hwif->index;
-out:
-	return hwif;
+	hw->chipset = ide_generic;
 }
 
 static int __devinit plat_ide_probe(struct platform_device *pdev)
@@ -71,6 +59,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 	int ret = 0;
 	int mmio = 0;
+	hw_regs_t hw;
 
 	pdata = pdev->dev.platform_data;
 
@@ -106,15 +95,27 @@ static int __devinit plat_ide_probe(struct platform_device *pdev)
 			res_alt->start, res_alt->end - res_alt->start + 1);
 	}
 
-	hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase,
-	         hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio);
-
+	hwif = ide_find_port((unsigned long)hwif_prop.plat_ide_mapbase);
 	if (!hwif) {
 		ret = -ENODEV;
 		goto out;
 	}
-	hwif->gendev.parent = &pdev->dev;
-	hwif->noprobe = 0;
+
+	memset(&hw, 0, sizeof(hw));
+	plat_ide_setup_ports(&hw, hwif_prop.plat_ide_mapbase,
+			     hwif_prop.plat_ide_alt_mapbase,
+			     pdata, res_irq->start);
+	hw.dev = &pdev->dev;
+
+	ide_init_port_hw(hwif, &hw);
+
+	if (mmio) {
+		hwif->mmio = 1;
+		default_hwif_mmiops(hwif);
+	}
+
+	hwif_prop.hwif = hwif;
+	hwif_prop.index = hwif->index;
 
 	idx[0] = hwif->index;
 
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index 5c6aa77c2370..782d4c76c0e5 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -77,15 +77,17 @@ int macide_ack_intr(ide_hwif_t* hwif)
 	return 0;
 }
 
+static const char *mac_ide_name[] =
+	{ "Quadra", "Powerbook", "Powerbook Baboon" };
+
 /*
  * Probe for a Macintosh IDE interface
  */
 
-void __init macide_init(void)
+static int __init macide_init(void)
 {
 	hw_regs_t hw;
 	ide_hwif_t *hwif;
-	int index = -1;
 
 	switch (macintosh_config->ide_type) {
 	case MAC_IDE_QUADRA:
@@ -93,48 +95,50 @@ void __init macide_init(void)
 				0, 0, macide_ack_intr,
 //				quadra_ide_iops,
 				IRQ_NUBUS_F);
-		index = ide_register_hw(&hw, NULL, 1, &hwif);
 		break;
 	case MAC_IDE_PB:
 		ide_setup_ports(&hw, IDE_BASE, macide_offsets,
 				0, 0, macide_ack_intr,
 //				macide_pb_iops,
 				IRQ_NUBUS_C);
-		index = ide_register_hw(&hw, NULL, 1, &hwif);
 		break;
 	case MAC_IDE_BABOON:
 		ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
 				0, 0, NULL,
 //				macide_baboon_iops,
 				IRQ_BABOON_1);
-		index = ide_register_hw(&hw, NULL, 1, &hwif);
-		if (index == -1) break;
-		if (macintosh_config->ident == MAC_MODEL_PB190) {
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "ide: Macintosh %s IDE controller\n",
+			 mac_ide_name[macintosh_config->ide_type - 1]);
 
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif) {
+		u8 index = hwif->index;
+		u8 idx[4] = { index, 0xff, 0xff, 0xff };
+
+		ide_init_port_data(hwif, index);
+		ide_init_port_hw(hwif, &hw);
+
+		if (macintosh_config->ide_type == MAC_IDE_BABOON &&
+		    macintosh_config->ident == MAC_MODEL_PB190) {
 			/* Fix breakage in ide-disk.c: drive capacity	*/
 			/* is not initialized for drives without a 	*/
 			/* hardware ID, and we can't get that without	*/
 			/* probing the drive which freezes a 190.	*/
-
-			ide_drive_t *drive = &ide_hwifs[index].drives[0];
+			ide_drive_t *drive = &hwif->drives[0];
 			drive->capacity64 = drive->cyl*drive->head*drive->sect;
-
 		}
-		break;
-
-	default:
-	    return;
-	}
 
-        if (index != -1) {
 		hwif->mmio = 1;
-		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
-			printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_PB)
-			printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index);
-		else if (macintosh_config->ide_type == MAC_IDE_BABOON)
-			printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index);
-		else
-			printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index);
+
+		ide_device_add(idx);
 	}
+
+	return 0;
 }
+
+module_init(macide_init);
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index 6ea46a6723e2..f5329730df99 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -111,15 +111,17 @@ static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
  *  Probe for Q40 IDE interfaces
  */
 
-void __init q40ide_init(void)
+static int __init q40ide_init(void)
 {
     int i;
     ide_hwif_t *hwif;
-    int index;
     const char *name;
+    u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
     if (!MACH_IS_Q40)
-      return ;
+      return -ENODEV;
+
+    printk(KERN_INFO "ide: Q40 IDE controller\n");
 
     for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
 	hw_regs_t hw;
@@ -141,10 +143,20 @@ void __init q40ide_init(void)
 			0, NULL,
 //			m68kide_iops,
 			q40ide_default_irq(pcide_bases[i]));
-	index = ide_register_hw(&hw, NULL, 1, &hwif);
-	// **FIXME**
-	if (index != -1)
+
+	hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]);
+	if (hwif) {
+		ide_init_port_data(hwif, hwif->index);
+		ide_init_port_hw(hwif, &hw);
 		hwif->mmio = 1;
+
+		idx[i] = hwif->index;
+	}
     }
+
+    ide_device_add(idx);
+
+    return 0;
 }
 
+module_init(q40ide_init);
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 912e73853faa..2bac4c1a6532 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -478,8 +478,7 @@ int probe_qd65xx = 0;
 module_param_named(probe, probe_qd65xx, bool, 0);
 MODULE_PARM_DESC(probe, "probe for QD65xx chipsets");
 
-/* Can be called directly from ide.c. */
-int __init qd65xx_init(void)
+static int __init qd65xx_init(void)
 {
 	if (probe_qd65xx == 0)
 		return -ENODEV;
@@ -492,9 +491,7 @@ int __init qd65xx_init(void)
 	return 0;
 }
 
-#ifdef MODULE
 module_init(qd65xx_init);
-#endif
 
 MODULE_AUTHOR("Samuel Thibault");
 MODULE_DESCRIPTION("support of qd65xx vlb ide chipset");
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index 79577b916874..a1ae1ae6699d 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -169,8 +169,7 @@ int probe_umc8672 = 0;
 module_param_named(probe, probe_umc8672, bool, 0);
 MODULE_PARM_DESC(probe, "probe for UMC8672 chipset");
 
-/* Can be called directly from ide.c. */
-int __init umc8672_init(void)
+static int __init umc8672_init(void)
 {
 	if (probe_umc8672 == 0)
 		goto out;
@@ -181,9 +180,7 @@ out:
 	return -ENODEV;;
 }
 
-#ifdef MODULE
 module_init(umc8672_init);
-#endif
 
 MODULE_AUTHOR("Wolfram Podien");
 MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset");
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index a4ce3ba15d61..2d3e5115b834 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -198,8 +198,6 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
 
 		break;
 #endif
-	default:
-		return;
 	}
 
 	au_writel(mem_sttime,MEM_STTIME2);
@@ -397,26 +395,10 @@ static int auide_dma_test_irq(ide_drive_t *drive)
 	return 0;
 }
 
-static void auide_dma_host_on(ide_drive_t *drive)
-{
-}
-
-static int auide_dma_on(ide_drive_t *drive)
-{
-	drive->using_dma = 1;
-
-	return 0;
-}
-
-static void auide_dma_host_off(ide_drive_t *drive)
+static void auide_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
-static void auide_dma_off_quietly(ide_drive_t *drive)
-{
-	drive->using_dma = 0;
-}
-
 static void auide_dma_lost_irq(ide_drive_t *drive)
 {
 	printk(KERN_ERR "%s: IRQ lost\n", drive->name);
@@ -643,12 +625,13 @@ static int au_ide_probe(struct device *dev)
 	/* FIXME:  This might possibly break PCMCIA IDE devices */
 
 	hwif                            = &ide_hwifs[pdev->id];
-	hwif->irq			= ahwif->irq;
-	hwif->chipset                   = ide_au1xxx;
 
 	memset(&hw, 0, sizeof(hw));
 	auide_setup_ports(&hw, ahwif);
-	memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
+	hw.irq = ahwif->irq;
+	hw.chipset = ide_au1xxx;
+
+	ide_init_port_hw(hwif, &hw);
 
 	hwif->ultra_mask                = 0x0;  /* Disable Ultra DMA */
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
@@ -662,7 +645,6 @@ static int au_ide_probe(struct device *dev)
 	hwif->pio_mask = ATA_PIO4;
 	hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
 
-	hwif->noprobe = 0;
 	hwif->drives[0].unmask          = 1;
 	hwif->drives[1].unmask          = 1;
 
@@ -684,29 +666,25 @@ static int au_ide_probe(struct device *dev)
 	hwif->set_dma_mode		= &auide_set_dma_mode;
 
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-	hwif->dma_off_quietly		= &auide_dma_off_quietly;
 	hwif->dma_timeout		= &auide_dma_timeout;
 
 	hwif->mdma_filter		= &auide_mdma_filter;
 
+	hwif->dma_host_set		= &auide_dma_host_set;
 	hwif->dma_exec_cmd              = &auide_dma_exec_cmd;
 	hwif->dma_start                 = &auide_dma_start;
 	hwif->ide_dma_end               = &auide_dma_end;
 	hwif->dma_setup                 = &auide_dma_setup;
 	hwif->ide_dma_test_irq          = &auide_dma_test_irq;
-	hwif->dma_host_off		= &auide_dma_host_off;
-	hwif->dma_host_on		= &auide_dma_host_on;
 	hwif->dma_lost_irq		= &auide_dma_lost_irq;
-	hwif->ide_dma_on                = &auide_dma_on;
-#else /* !CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
+#endif
 	hwif->channel                   = 0;
-	hwif->hold                      = 1;
 	hwif->select_data               = 0;    /* no chipset-specific code */
 	hwif->config_data               = 0;    /* no chipset-specific code */
 
 	hwif->drives[0].autotune        = 1;    /* 1=autotune, 2=noautotune, 0=default */
 	hwif->drives[1].autotune	= 1;
-#endif
+
 	hwif->drives[0].no_io_32bit	= 1;
 	hwif->drives[1].no_io_32bit	= 1;
 
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 521edd41b572..8b3959dfa2b7 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -117,6 +117,7 @@ static int __devinit swarm_ide_probe(struct device *dev)
 	default_hwif_mmiops(hwif);
 	/* Prevent resource map manipulation.  */
 	hwif->mmio = 1;
+	hwif->chipset = ide_generic;
 	hwif->noprobe = 0;
 
 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index 95d1ea8f1f14..94803253e8af 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -36,4 +36,8 @@ obj-$(CONFIG_BLK_DEV_VIA82CXXX)		+= via82cxxx.o
 # Must appear at the end of the block
 obj-$(CONFIG_BLK_DEV_GENERIC)          += generic.o
 
+ifeq ($(CONFIG_BLK_DEV_CMD640), m)
+	obj-m += cmd640.o
+endif
+
 EXTRA_CFLAGS	:= -Idrivers/ide
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index 44268504ae43..7f4d1857d555 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -202,6 +202,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
 		.host_flags	= IDE_HFLAG_SERIALIZE |
 				  IDE_HFLAG_NO_ATAPI_DMA |
+				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
 				  IDE_HFLAG_OFF_BOARD,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
@@ -211,6 +212,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
 		.init_chipset	= init_chipset_aec62xx,
 		.init_hwif	= init_hwif_aec62xx,
 		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
+				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
 				  IDE_HFLAG_OFF_BOARD,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
@@ -220,7 +222,8 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
 		.init_chipset	= init_chipset_aec62xx,
 		.init_hwif	= init_hwif_aec62xx,
 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA,
+		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
+				  IDE_HFLAG_ABUSE_SET_DMA_MODE,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 		.udma_mask	= ATA_UDMA4,
@@ -228,7 +231,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
 		.name		= "AEC6280",
 		.init_chipset	= init_chipset_aec62xx,
 		.init_hwif	= init_hwif_aec62xx,
-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
+				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
+				  IDE_HFLAG_OFF_BOARD,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 		.udma_mask	= ATA_UDMA5,
@@ -237,7 +242,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
 		.init_chipset	= init_chipset_aec62xx,
 		.init_hwif	= init_hwif_aec62xx,
 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
+				  IDE_HFLAG_ABUSE_SET_DMA_MODE |
+				  IDE_HFLAG_OFF_BOARD,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 		.udma_mask	= ATA_UDMA5,
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index ce293936af4b..49aa82e412b6 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -402,9 +402,6 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
 	u8 tmpbyte		= 0x00;
 	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
 
-	if (speed < XFER_PIO_0)
-		return;
-
 	if (speed == XFER_UDMA_6)
 		speed1 = 0x47;
 
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 8d4125ec252c..cee51fdafcf6 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -266,6 +266,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
 #define IDE_HFLAGS_AMD \
 	(IDE_HFLAG_PIO_NO_BLACKLIST | \
 	 IDE_HFLAG_PIO_NO_DOWNGRADE | \
+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
 	 IDE_HFLAG_POST_SET_MODE | \
 	 IDE_HFLAG_IO_32BIT | \
 	 IDE_HFLAG_UNMASK_IRQS | \
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index ef8e0164ef7a..491871984aaa 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/atiixp.c	Version 0.03	Aug 3 2007
+ *  linux/drivers/ide/pci/atiixp.c	Version 0.05	Nov 9 2007
  *
  *  Copyright (C) 2003 ATI Inc. <hyu@ati.com>
  *  Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
@@ -43,47 +43,8 @@ static atiixp_ide_timing mdma_timing[] = {
 	{ 0x02, 0x00 },
 };
 
-static int save_mdma_mode[4];
-
 static DEFINE_SPINLOCK(atiixp_lock);
 
-static void atiixp_dma_host_on(ide_drive_t *drive)
-{
-	struct pci_dev *dev = drive->hwif->pci_dev;
-	unsigned long flags;
-	u16 tmp16;
-
-	spin_lock_irqsave(&atiixp_lock, flags);
-
-	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
-	if (save_mdma_mode[drive->dn])
-		tmp16 &= ~(1 << drive->dn);
-	else
-		tmp16 |= (1 << drive->dn);
-	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
-
-	spin_unlock_irqrestore(&atiixp_lock, flags);
-
-	ide_dma_host_on(drive);
-}
-
-static void atiixp_dma_host_off(ide_drive_t *drive)
-{
-	struct pci_dev *dev = drive->hwif->pci_dev;
-	unsigned long flags;
-	u16 tmp16;
-
-	spin_lock_irqsave(&atiixp_lock, flags);
-
-	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
-	tmp16 &= ~(1 << drive->dn);
-	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
-
-	spin_unlock_irqrestore(&atiixp_lock, flags);
-
-	ide_dma_host_off(drive);
-}
-
 /**
  *	atiixp_set_pio_mode	-	set host controller for PIO mode
  *	@drive: drive
@@ -132,29 +93,33 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
 	int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
 	u32 tmp32;
 	u16 tmp16;
-
-	if (speed < XFER_MW_DMA_0)
-		return;
+	u16 udma_ctl = 0;
 
 	spin_lock_irqsave(&atiixp_lock, flags);
 
-	save_mdma_mode[drive->dn] = 0;
+	pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl);
+
 	if (speed >= XFER_UDMA_0) {
 		pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16);
 		tmp16 &= ~(0x07 << (drive->dn * 4));
 		tmp16 |= ((speed & 0x07) << (drive->dn * 4));
 		pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16);
-	} else {
-		if ((speed >= XFER_MW_DMA_0) && (speed <= XFER_MW_DMA_2)) {
-			save_mdma_mode[drive->dn] = speed;
-			pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
-			tmp32 &= ~(0xff << timing_shift);
-			tmp32 |= (mdma_timing[speed & 0x03].recover_width << timing_shift) |
-				(mdma_timing[speed & 0x03].command_width << (timing_shift + 4));
-			pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
-		}
+
+		udma_ctl |= (1 << drive->dn);
+	} else if (speed >= XFER_MW_DMA_0) {
+		u8 i = speed & 0x03;
+
+		pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32);
+		tmp32 &= ~(0xff << timing_shift);
+		tmp32 |= (mdma_timing[i].recover_width << timing_shift) |
+			 (mdma_timing[i].command_width << (timing_shift + 4));
+		pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32);
+
+		udma_ctl &= ~(1 << drive->dn);
 	}
 
+	pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl);
+
 	spin_unlock_irqrestore(&atiixp_lock, flags);
 }
 
@@ -184,9 +149,6 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
 		hwif->cbl = ATA_CBL_PATA80;
 	else
 		hwif->cbl = ATA_CBL_PATA40;
-
-	hwif->dma_host_on = &atiixp_dma_host_on;
-	hwif->dma_host_off = &atiixp_dma_host_off;
 }
 
 static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index 4aa48104e0c1..da3565e0071f 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -706,9 +706,9 @@ static int pci_conf2(void)
 }
 
 /*
- * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
+ * Probe for a cmd640 chipset, and initialize it if found.
  */
-int __init ide_probe_for_cmd640x (void)
+static int __init cmd640x_init(void)
 {
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 	int second_port_toggled = 0;
@@ -717,6 +717,7 @@ int __init ide_probe_for_cmd640x (void)
 	const char *bus_type, *port2;
 	unsigned int index;
 	u8 b, cfr;
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
 
 	if (cmd640_vlb && probe_for_cmd640_vlb()) {
 		bus_type = "VLB";
@@ -769,6 +770,8 @@ int __init ide_probe_for_cmd640x (void)
 	cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 
+	idx[0] = cmd_hwif0->index;
+
 	/*
 	 * Ensure compatibility by always using the slowest timings
 	 * for access to the drive's command register block,
@@ -826,6 +829,8 @@ int __init ide_probe_for_cmd640x (void)
 		cmd_hwif1->pio_mask = ATA_PIO5;
 		cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+
+		idx[1] = cmd_hwif1->index;
 	}
 	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
 		cmd_hwif0->serialized ? "" : "not ", port2);
@@ -872,6 +877,13 @@ int __init ide_probe_for_cmd640x (void)
 #ifdef CMD640_DUMP_REGS
 	cmd640_dump_regs();
 #endif
+
+	ide_device_add(idx);
+
 	return 1;
 }
 
+module_param_named(probe_vlb, cmd640_vlb, bool, 0);
+MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset");
+
+module_init(cmd640x_init);
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index bc553337b1be..cd4eb9def151 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/cmd64x.c		Version 1.52	Dec 24, 2007
+ * linux/drivers/ide/pci/cmd64x.c		Version 1.53	Dec 24, 2007
  *
  * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
  *           Due to massive hardware bugs, UltraDMA is only supported
@@ -22,8 +22,6 @@
 
 #include <asm/io.h>
 
-#define DISPLAY_CMD64X_TIMINGS
-
 #define CMD_DEBUG 0
 
 #if CMD_DEBUG
@@ -37,11 +35,6 @@
  */
 #define CFR		0x50
 #define   CFR_INTR_CH0		0x04
-#define CNTRL		0x51
-#define   CNTRL_ENA_1ST 	0x04
-#define   CNTRL_ENA_2ND 	0x08
-#define   CNTRL_DIS_RA0 	0x40
-#define   CNTRL_DIS_RA1 	0x80
 
 #define	CMDTIM		0x52
 #define	ARTTIM0		0x53
@@ -60,108 +53,13 @@
 #define MRDMODE		0x71
 #define   MRDMODE_INTR_CH0	0x04
 #define   MRDMODE_INTR_CH1	0x08
-#define   MRDMODE_BLK_CH0	0x10
-#define   MRDMODE_BLK_CH1	0x20
-#define BMIDESR0	0x72
 #define UDIDETCR0	0x73
 #define DTPR0		0x74
 #define BMIDECR1	0x78
 #define BMIDECSR	0x79
-#define BMIDESR1	0x7A
 #define UDIDETCR1	0x7B
 #define DTPR1		0x7C
 
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static u8 cmd64x_proc = 0;
-
-#define CMD_MAX_DEVS		5
-
-static struct pci_dev *cmd_devs[CMD_MAX_DEVS];
-static int n_cmd_devs;
-
-static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
-{
-	char *p = buf;
-	u8 reg72 = 0, reg73 = 0;			/* primary */
-	u8 reg7a = 0, reg7b = 0;			/* secondary */
-	u8 reg50 = 1, reg51 = 1, reg57 = 0, reg71 = 0;	/* extra */
-
-	p += sprintf(p, "\nController: %d\n", index);
-	p += sprintf(p, "PCI-%x Chipset.\n", dev->device);
-
-	(void) pci_read_config_byte(dev, CFR,       &reg50);
-	(void) pci_read_config_byte(dev, CNTRL,     &reg51);
-	(void) pci_read_config_byte(dev, ARTTIM23,  &reg57);
-	(void) pci_read_config_byte(dev, MRDMODE,   &reg71);
-	(void) pci_read_config_byte(dev, BMIDESR0,  &reg72);
-	(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
-	(void) pci_read_config_byte(dev, BMIDESR1,  &reg7a);
-	(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
-
-	/* PCI0643/6 originally didn't have the primary channel enable bit */
-	if ((dev->device == PCI_DEVICE_ID_CMD_643) ||
-	    (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 3))
-		reg51 |= CNTRL_ENA_1ST;
-
-	p += sprintf(p, "---------------- Primary Channel "
-			"---------------- Secondary Channel ------------\n");
-	p += sprintf(p, "                 %s                         %s\n",
-		 (reg51 & CNTRL_ENA_1ST) ? "enabled " : "disabled",
-		 (reg51 & CNTRL_ENA_2ND) ? "enabled " : "disabled");
-	p += sprintf(p, "---------------- drive0 --------- drive1 "
-			"-------- drive0 --------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:     %s              %s"
-			"             %s              %s\n",
-		(reg72 & 0x20) ? "yes" : "no ", (reg72 & 0x40) ? "yes" : "no ",
-		(reg7a & 0x20) ? "yes" : "no ", (reg7a & 0x40) ? "yes" : "no ");
-	p += sprintf(p, "UltraDMA mode:   %s (%c)          %s (%c)",
-		( reg73 & 0x01) ? " on" : "off",
-		((reg73 & 0x30) == 0x30) ? ((reg73 & 0x04) ? '3' : '0') :
-		((reg73 & 0x30) == 0x20) ? ((reg73 & 0x04) ? '3' : '1') :
-		((reg73 & 0x30) == 0x10) ? ((reg73 & 0x04) ? '4' : '2') :
-		((reg73 & 0x30) == 0x00) ? ((reg73 & 0x04) ? '5' : '2') : '?',
-		( reg73 & 0x02) ? " on" : "off",
-		((reg73 & 0xC0) == 0xC0) ? ((reg73 & 0x08) ? '3' : '0') :
-		((reg73 & 0xC0) == 0x80) ? ((reg73 & 0x08) ? '3' : '1') :
-		((reg73 & 0xC0) == 0x40) ? ((reg73 & 0x08) ? '4' : '2') :
-		((reg73 & 0xC0) == 0x00) ? ((reg73 & 0x08) ? '5' : '2') : '?');
-	p += sprintf(p, "         %s (%c)          %s (%c)\n",
-		( reg7b & 0x01) ? " on" : "off",
-		((reg7b & 0x30) == 0x30) ? ((reg7b & 0x04) ? '3' : '0') :
-		((reg7b & 0x30) == 0x20) ? ((reg7b & 0x04) ? '3' : '1') :
-		((reg7b & 0x30) == 0x10) ? ((reg7b & 0x04) ? '4' : '2') :
-		((reg7b & 0x30) == 0x00) ? ((reg7b & 0x04) ? '5' : '2') : '?',
-		( reg7b & 0x02) ? " on" : "off",
-		((reg7b & 0xC0) == 0xC0) ? ((reg7b & 0x08) ? '3' : '0') :
-		((reg7b & 0xC0) == 0x80) ? ((reg7b & 0x08) ? '3' : '1') :
-		((reg7b & 0xC0) == 0x40) ? ((reg7b & 0x08) ? '4' : '2') :
-		((reg7b & 0xC0) == 0x00) ? ((reg7b & 0x08) ? '5' : '2') : '?');
-	p += sprintf(p, "Interrupt:       %s, %s                 %s, %s\n",
-		(reg71 & MRDMODE_BLK_CH0  ) ? "blocked" : "enabled",
-		(reg50 & CFR_INTR_CH0	  ) ? "pending" : "clear  ",
-		(reg71 & MRDMODE_BLK_CH1  ) ? "blocked" : "enabled",
-		(reg57 & ARTTIM23_INTR_CH1) ? "pending" : "clear  ");
-
-	return (char *)p;
-}
-
-static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	int i;
-
-	for (i = 0; i < n_cmd_devs; i++) {
-		struct pci_dev *dev	= cmd_devs[i];
-		p = print_cmd64x_get_info(p, dev, i);
-	}
-	return p-buffer;	/* => must be less than 4k! */
-}
-
-#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
-
 static u8 quantize_timing(int timing, int quant)
 {
 	return (timing + quant - 1) / quant;
@@ -322,8 +220,6 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
 	case XFER_MW_DMA_0:
 		program_cycle_times(drive, 480, 215);
 		break;
-	default:
-		return;
 	}
 
 	if (speed >= XFER_SW_DMA_0)
@@ -333,14 +229,15 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
 static int cmd648_ide_dma_end (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long base	= hwif->dma_base - (hwif->channel * 8);
 	int err			= __ide_dma_end(drive);
 	u8  irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
 						  MRDMODE_INTR_CH0;
-	u8  mrdmode		= inb(hwif->dma_master + 0x01);
+	u8  mrdmode		= inb(base + 1);
 
 	/* clear the interrupt bit */
 	outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
-	     hwif->dma_master + 0x01);
+	     base + 1);
 
 	return err;
 }
@@ -365,10 +262,11 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive)
 static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
+	unsigned long base	= hwif->dma_base - (hwif->channel * 8);
 	u8 irq_mask		= hwif->channel ? MRDMODE_INTR_CH1 :
 						  MRDMODE_INTR_CH0;
 	u8 dma_stat		= inb(hwif->dma_status);
-	u8 mrdmode		= inb(hwif->dma_master + 0x01);
+	u8 mrdmode		= inb(base + 1);
 
 #ifdef DEBUG
 	printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n",
@@ -472,16 +370,6 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
 	mrdmode &= ~0x30;
 	(void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02));
 
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
-
-	cmd_devs[n_cmd_devs++] = dev;
-
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		ide_pci_create_host_proc("cmd64x", cmd64x_get_info);
-	}
-#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_IDE_PROC_FS */
-
 	return 0;
 }
 
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 0466462fd21b..6ec00b8d7ec1 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -71,7 +71,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
 	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *pdev = hwif->pci_dev;
 	int controller = drive->dn > 1 ? 1 : 0;
-	u8 reg;
 
 	/* FIXME: if DMA = 1 do we need to set the DMA bit here ? */
 
@@ -91,11 +90,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
 	pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1),
 		(cs5520_pio_clocks[pio].recovery << 4) |
 		(cs5520_pio_clocks[pio].assert));
-		
-	/* Set the DMA enable/disable flag */
-	reg = inb(hwif->dma_base + 0x02 + 8*controller);
-	reg |= 1<<((drive->dn&1)+5);
-	outb(reg, hwif->dma_base + 0x02 + 8*controller);
 }
 
 static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
@@ -109,13 +103,14 @@ static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
  *	We wrap the DMA activate to set the vdma flag. This is needed
  *	so that the IDE DMA layer issues PIO not DMA commands over the
  *	DMA channel
+ *
+ *	ATAPI is harder so disable it for now using IDE_HFLAG_NO_ATAPI_DMA
  */
- 
-static int cs5520_dma_on(ide_drive_t *drive)
+
+static void cs5520_dma_host_set(ide_drive_t *drive, int on)
 {
-	/* ATAPI is harder so leave it for now */
-	drive->vdma = 1;
-	return 0;
+	drive->vdma = on;
+	ide_dma_host_set(drive, on);
 }
 
 static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
@@ -126,7 +121,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
 	if (hwif->dma_base == 0)
 		return;
 
-	hwif->ide_dma_on = &cs5520_dma_on;
+	hwif->dma_host_set = &cs5520_dma_host_set;
 }
 
 #define DECLARE_CS_DEV(name_str)				\
@@ -137,6 +132,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
 				  IDE_HFLAG_CS5520 |		\
 				  IDE_HFLAG_VDMA |		\
 				  IDE_HFLAG_NO_ATAPI_DMA |	\
+				  IDE_HFLAG_ABUSE_SET_DMA_MODE |\
 				  IDE_HFLAG_BOOTABLE,		\
 		.pio_mask	= ATA_PIO4,			\
 	}
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index 547690395eee..df5966b33460 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -116,8 +116,6 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
 		case XFER_MW_DMA_0:	timings = 0x00077771; break;
 		case XFER_MW_DMA_1:	timings = 0x00012121; break;
 		case XFER_MW_DMA_2:	timings = 0x00002020; break;
-		default:
-			return;
 	}
 	basereg = CS5530_BASEREG(drive->hwif);
 	reg = inl(basereg + 4);			/* get drive0 config register */
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index ddcbeba671e1..50b3d7791f55 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -190,7 +190,7 @@ static const struct ide_port_info cs5535_chipset __devinitdata = {
 	.name		= "CS5535",
 	.init_hwif	= init_hwif_cs5535,
 	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE |
-			  IDE_HFLAG_BOOTABLE,
+			  IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_BOOTABLE,
 	.pio_mask	= ATA_PIO4,
 	.mwdma_mask	= ATA_MWDMA2,
 	.udma_mask	= ATA_UDMA4,
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 1cd4e9cb0521..3ec4c659a37d 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/cy82c693.c		Version 0.42	Oct 23, 2007
+ * linux/drivers/ide/pci/cy82c693.c		Version 0.44	Nov 8, 2007
  *
  *  Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
  *  Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
@@ -176,17 +176,12 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
  * set DMA mode a specific channel for CY82C693
  */
 
-static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
+static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode)
 {
-	u8 index = 0, data = 0;
+	ide_hwif_t *hwif = drive->hwif;
+	u8 single = (mode & 0x10) >> 4, index = 0, data = 0;
 
-	if (mode>2)	/* make sure we set a valid mode */
-		mode = 2;
-			   
-	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
-		mode = drive->id->tDMA;
-	
-	index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+	index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0;
 
 #if CY82C693_DEBUG_LOGS
 	/* for debug let's show the previous values */
@@ -199,7 +194,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
 		(data&0x3), ((data>>2)&1));
 #endif /* CY82C693_DEBUG_LOGS */
 
-	data = (u8)mode|(u8)(single<<2);
+	data = (mode & 3) | (single << 2);
 
 	outb(index, CY82_INDEX_PORT);
 	outb(data, CY82_DATA_PORT);
@@ -207,7 +202,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
 #if CY82C693_DEBUG_INFO
 	printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n",
 		drive->name, HWIF(drive)->channel, drive->select.b.unit,
-		mode, single);
+		mode & 3, single);
 #endif /* CY82C693_DEBUG_INFO */
 
 	/* 
@@ -230,39 +225,6 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single)
 #endif /* CY82C693_DEBUG_INFO */
 }
 
-/* 
- * used to set DMA mode for CY82C693 (single and multi modes)
- */
-static int cy82c693_ide_dma_on (ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "dma_on: %s\n", drive->name);
-#endif /* CY82C693_DEBUG_INFO */
-
-	if (id != NULL) {		
-		/* Enable DMA on any drive that has DMA
-		 * (multi or single) enabled
-		 */
-		if (id->field_valid & 2) {	/* regular DMA */
-			int mmode, smode;
-
-			mmode = id->dma_mword & (id->dma_mword >> 8);
-			smode = id->dma_1word & (id->dma_1word >> 8);
-			       		      
-			if (mmode != 0) {
-				/* enable multi */
-				cy82c693_dma_enable(drive, (mmode >> 1), 0);
-			} else if (smode != 0) {
-				/* enable single */
-				cy82c693_dma_enable(drive, (smode >> 1), 1);
-			}
-		}
-	}
-        return __ide_dma_on(drive);
-}
-
 static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	ide_hwif_t *hwif = HWIF(drive);
@@ -429,11 +391,7 @@ static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const c
 static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
 {
 	hwif->set_pio_mode = &cy82c693_set_pio_mode;
-
-	if (hwif->dma_base == 0)
-		return;
-
-	hwif->ide_dma_on = &cy82c693_ide_dma_on;
+	hwif->set_dma_mode = &cy82c693_set_dma_mode;
 }
 
 static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
@@ -454,11 +412,11 @@ static const struct ide_port_info cy82c693_chipset __devinitdata = {
 	.init_iops	= init_iops_cy82c693,
 	.init_hwif	= init_hwif_cy82c693,
 	.chipset	= ide_cy82c693,
-	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_CY82C693 |
 			  IDE_HFLAG_BOOTABLE,
 	.pio_mask	= ATA_PIO4,
-	.swdma_mask	= ATA_SWDMA2_ONLY,
-	.mwdma_mask	= ATA_MWDMA2_ONLY,
+	.swdma_mask	= ATA_SWDMA2,
+	.mwdma_mask	= ATA_MWDMA2,
 };
 
 static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
index 83829081640a..26aa492071bb 100644
--- a/drivers/ide/pci/delkin_cb.c
+++ b/drivers/ide/pci/delkin_cb.c
@@ -80,7 +80,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
 	hw.irq = dev->irq;
 	hw.chipset = ide_pci;		/* this enables IRQ sharing */
 
-	rc = ide_register_hw(&hw, &ide_undecoded_slave, 0, &hwif);
+	rc = ide_register_hw(&hw, &ide_undecoded_slave, &hwif);
 	if (rc < 0) {
 		printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
 		pci_disable_device(dev);
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index ae6307fae4f9..dfba0d13fcd3 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -129,14 +129,18 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
 	hwif->set_dma_mode = &hpt34x_set_mode;
 }
 
+#define IDE_HFLAGS_HPT34X \
+	(IDE_HFLAG_NO_ATAPI_DMA | \
+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
+	 IDE_HFLAG_NO_AUTODMA)
+
 static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
 	{ /* 0 */
 		.name		= "HPT343",
 		.init_chipset	= init_chipset_hpt34x,
 		.init_hwif	= init_hwif_hpt34x,
 		.extra		= 16,
-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
-				  IDE_HFLAG_NO_AUTODMA,
+		.host_flags	= IDE_HFLAGS_HPT34X,
 		.pio_mask	= ATA_PIO5,
 	},
 	{ /* 1 */
@@ -144,9 +148,7 @@ static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
 		.init_chipset	= init_chipset_hpt34x,
 		.init_hwif	= init_hwif_hpt34x,
 		.extra		= 16,
-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA |
-				  IDE_HFLAG_NO_AUTODMA |
-				  IDE_HFLAG_OFF_BOARD,
+		.host_flags	= IDE_HFLAGS_HPT34X | IDE_HFLAG_OFF_BOARD,
 		.pio_mask	= ATA_PIO5,
 #ifdef CONFIG_HPT34X_AUTODMA
 		.swdma_mask	= ATA_SWDMA2,
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index 9fce25bdec8a..12685939a813 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/hpt366.c		Version 1.22	Dec 4, 2007
+ * linux/drivers/ide/pci/hpt366.c		Version 1.30	Dec 12, 2007
  *
  * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
@@ -88,7 +88,7 @@
  * - rename all the register related variables consistently
  * - move all the interrupt twiddling code from the speedproc handlers into
  *   init_hwif_hpt366(), also grouping all the DMA related code together there
- * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
+ * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and
  *   separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
  *   when setting an UltraDMA mode
  * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
@@ -458,6 +458,13 @@ enum ata_clock {
 	NUM_ATA_CLOCKS
 };
 
+struct hpt_timings {
+	u32 pio_mask;
+	u32 dma_mask;
+	u32 ultra_mask;
+	u32 *clock_table[NUM_ATA_CLOCKS];
+};
+
 /*
  *	Hold all the HighPoint chip information in one place.
  */
@@ -468,7 +475,8 @@ struct hpt_info {
 	u8 udma_mask;		/* Allowed UltraDMA modes mask. */
 	u8 dpll_clk;		/* DPLL clock in MHz */
 	u8 pci_clk;		/* PCI  clock in MHz */
-	u32 **settings; 	/* Chipset settings table */
+	struct hpt_timings *timings; /* Chipset timing data */
+	u8 clock;		/* ATA clock selected */
 };
 
 /* Supported HighPoint chips */
@@ -486,20 +494,30 @@ enum {
 	HPT371N
 };
 
-static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
-	twenty_five_base_hpt36x,
-	thirty_three_base_hpt36x,
-	forty_base_hpt36x,
-	NULL,
-	NULL
+static struct hpt_timings hpt36x_timings = {
+	.pio_mask	= 0xc1f8ffff,
+	.dma_mask	= 0x303800ff,
+	.ultra_mask	= 0x30070000,
+	.clock_table	= {
+		[ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x,
+		[ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x,
+		[ATA_CLOCK_40MHZ] = forty_base_hpt36x,
+		[ATA_CLOCK_50MHZ] = NULL,
+		[ATA_CLOCK_66MHZ] = NULL
+	}
 };
 
-static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
-	NULL,
-	thirty_three_base_hpt37x,
-	NULL,
-	fifty_base_hpt37x,
-	sixty_six_base_hpt37x
+static struct hpt_timings hpt37x_timings = {
+	.pio_mask	= 0xcfc3ffff,
+	.dma_mask	= 0x31c001ff,
+	.ultra_mask	= 0x303c0000,
+	.clock_table	= {
+		[ATA_CLOCK_25MHZ] = NULL,
+		[ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x,
+		[ATA_CLOCK_40MHZ] = NULL,
+		[ATA_CLOCK_50MHZ] = fifty_base_hpt37x,
+		[ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x
+	}
 };
 
 static const struct hpt_info hpt36x __devinitdata = {
@@ -507,7 +525,7 @@ static const struct hpt_info hpt36x __devinitdata = {
 	.chip_type	= HPT36x,
 	.udma_mask	= HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2,
 	.dpll_clk	= 0,	/* no DPLL */
-	.settings	= hpt36x_settings
+	.timings	= &hpt36x_timings
 };
 
 static const struct hpt_info hpt370 __devinitdata = {
@@ -515,7 +533,7 @@ static const struct hpt_info hpt370 __devinitdata = {
 	.chip_type	= HPT370,
 	.udma_mask	= HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
 	.dpll_clk	= 48,
-	.settings	= hpt37x_settings
+	.timings	= &hpt37x_timings
 };
 
 static const struct hpt_info hpt370a __devinitdata = {
@@ -523,7 +541,7 @@ static const struct hpt_info hpt370a __devinitdata = {
 	.chip_type	= HPT370A,
 	.udma_mask	= HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
 	.dpll_clk	= 48,
-	.settings	= hpt37x_settings
+	.timings	= &hpt37x_timings
 };
 
 static const struct hpt_info hpt374 __devinitdata = {
@@ -531,7 +549,7 @@ static const struct hpt_info hpt374 __devinitdata = {
 	.chip_type	= HPT374,
 	.udma_mask	= ATA_UDMA5,
 	.dpll_clk	= 48,
-	.settings	= hpt37x_settings
+	.timings	= &hpt37x_timings
 };
 
 static const struct hpt_info hpt372 __devinitdata = {
@@ -539,7 +557,7 @@ static const struct hpt_info hpt372 __devinitdata = {
 	.chip_type	= HPT372,
 	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 	.dpll_clk	= 55,
-	.settings	= hpt37x_settings
+	.timings	= &hpt37x_timings
 };
 
 static const struct hpt_info hpt372a __devinitdata = {
@@ -547,7 +565,7 @@ static const struct hpt_info hpt372a __devinitdata = {
 	.chip_type	= HPT372A,
 	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 	.dpll_clk	= 66,
-	.settings	= hpt37x_settings
+	.timings	= &hpt37x_timings
 };
 
 static const struct hpt_info hpt302 __devinitdata = {
@@ -555,7 +573,7 @@ static const struct hpt_info hpt302 __devinitdata = {
 	.chip_type	= HPT302,
 	.udma_mask	= HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 	.dpll_clk	= 66,
-	.settings	= hpt37x_settings
+	.timings	= &hpt37x_timings
 };
 
 static const struct hpt_info hpt371 __devinitdata = {
@@ -563,7 +581,7 @@ static const struct hpt_info hpt371 __devinitdata = {
 	.chip_type	= HPT371,
 	.udma_mask	= HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 	.dpll_clk	= 66,
-	.settings	= hpt37x_settings
+	.timings	= &hpt37x_timings
 };
 
 static const struct hpt_info hpt372n __devinitdata = {
@@ -571,7 +589,7 @@ static const struct hpt_info hpt372n __devinitdata = {
 	.chip_type	= HPT372N,
 	.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 	.dpll_clk	= 77,
-	.settings	= hpt37x_settings
+	.timings	= &hpt37x_timings
 };
 
 static const struct hpt_info hpt302n __devinitdata = {
@@ -579,7 +597,7 @@ static const struct hpt_info hpt302n __devinitdata = {
 	.chip_type	= HPT302N,
 	.udma_mask	= HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 	.dpll_clk	= 77,
-	.settings	= hpt37x_settings
+	.timings	= &hpt37x_timings
 };
 
 static const struct hpt_info hpt371n __devinitdata = {
@@ -587,7 +605,7 @@ static const struct hpt_info hpt371n __devinitdata = {
 	.chip_type	= HPT371N,
 	.udma_mask	= HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 	.dpll_clk	= 77,
-	.settings	= hpt37x_settings
+	.timings	= &hpt37x_timings
 };
 
 static int check_in_drive_list(ide_drive_t *drive, const char **list)
@@ -675,94 +693,50 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
 	for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
 		if (xfer_speeds[i] == speed)
 			break;
-	/*
-	 * NOTE: info->settings only points to the pointer
-	 * to the list of the actual register values
-	 */
-	return (*info->settings)[i];
+
+	return info->timings->clock_table[info->clock][i];
 }
 
-static void hpt36x_set_mode(ide_drive_t *drive, const u8 speed)
+static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev  *dev	= hwif->pci_dev;
+	struct pci_dev  *dev	= HWIF(drive)->pci_dev;
 	struct hpt_info	*info	= pci_get_drvdata(dev);
-	u8  itr_addr		= drive->dn ? 0x44 : 0x40;
+	struct hpt_timings *t	= info->timings;
+	u8  itr_addr		= 0x40 + (drive->dn * 4);
 	u32 old_itr		= 0;
-	u32 itr_mask, new_itr;
-
-	itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
-		  (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
-
-	new_itr = get_speed_setting(speed, info);
+	u32 new_itr		= get_speed_setting(speed, info);
+	u32 itr_mask		= speed < XFER_MW_DMA_0 ? t->pio_mask :
+				 (speed < XFER_UDMA_0   ? t->dma_mask :
+							  t->ultra_mask);
 
+	pci_read_config_dword(dev, itr_addr, &old_itr);
+	new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask);
 	/*
 	 * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
 	 * to avoid problems handling I/O errors later
 	 */
-	pci_read_config_dword(dev, itr_addr, &old_itr);
-	new_itr  = (new_itr & ~itr_mask) | (old_itr & itr_mask);
 	new_itr &= ~0xc0000000;
 
 	pci_write_config_dword(dev, itr_addr, new_itr);
 }
 
-static void hpt37x_set_mode(ide_drive_t *drive, const u8 speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev  *dev	= hwif->pci_dev;
-	struct hpt_info	*info	= pci_get_drvdata(dev);
-	u8  itr_addr		= 0x40 + (drive->dn * 4);
-	u32 old_itr		= 0;
-	u32 itr_mask, new_itr;
-
-	itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
-		  (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
-
-	new_itr = get_speed_setting(speed, info);
-
-	pci_read_config_dword(dev, itr_addr, &old_itr);
-	new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
-	
-	if (speed < XFER_MW_DMA_0)
-		new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-	pci_write_config_dword(dev, itr_addr, new_itr);
-}
-
-static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct hpt_info	*info	= pci_get_drvdata(hwif->pci_dev);
-
-	if (info->chip_type >= HPT370)
-		hpt37x_set_mode(drive, speed);
-	else	/* hpt368: hpt_minimum_revision(dev, 2) */
-		hpt36x_set_mode(drive, speed);
-}
-
 static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
 }
 
-static int hpt3xx_quirkproc(ide_drive_t *drive)
+static void hpt3xx_quirkproc(ide_drive_t *drive)
 {
 	struct hd_driveid *id	= drive->id;
 	const  char **list	= quirk_drives;
 
 	while (*list)
-		if (strstr(id->model, *list++))
-			return 1;
-	return 0;
-}
-
-static void hpt3xx_intrproc(ide_drive_t *drive)
-{
-	if (drive->quirk_list)
-		return;
+		if (strstr(id->model, *list++)) {
+			drive->quirk_list = 1;
+			return;
+		}
 
-	/* drives in the quirk_list may not like intr setups/cleanups */
-	outb(drive->ctl | 2, IDE_CONTROL_REG);
+	drive->quirk_list = 0;
 }
 
 static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
@@ -914,32 +888,33 @@ static int hpt374_ide_dma_end(ide_drive_t *drive)
 
 static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
 {
-	u8 scr2 = inb(hwif->dma_master + 0x7b);
+	unsigned long base = hwif->extra_base;
+	u8 scr2 = inb(base + 0x6b);
 
 	if ((scr2 & 0x7f) == mode)
 		return;
 
 	/* Tristate the bus */
-	outb(0x80, hwif->dma_master + 0x73);
-	outb(0x80, hwif->dma_master + 0x77);
+	outb(0x80, base + 0x63);
+	outb(0x80, base + 0x67);
 
 	/* Switch clock and reset channels */
-	outb(mode, hwif->dma_master + 0x7b);
-	outb(0xc0, hwif->dma_master + 0x79);
+	outb(mode, base + 0x6b);
+	outb(0xc0, base + 0x69);
 
 	/*
 	 * Reset the state machines.
 	 * NOTE: avoid accidentally enabling the disabled channels.
 	 */
-	outb(inb(hwif->dma_master + 0x70) | 0x32, hwif->dma_master + 0x70);
-	outb(inb(hwif->dma_master + 0x74) | 0x32, hwif->dma_master + 0x74);
+	outb(inb(base + 0x60) | 0x32, base + 0x60);
+	outb(inb(base + 0x64) | 0x32, base + 0x64);
 
 	/* Complete reset */
-	outb(0x00, hwif->dma_master + 0x79);
+	outb(0x00, base + 0x69);
 
 	/* Reconnect channels to bus */
-	outb(0x00, hwif->dma_master + 0x73);
-	outb(0x00, hwif->dma_master + 0x77);
+	outb(0x00, base + 0x63);
+	outb(0x00, base + 0x67);
 }
 
 /**
@@ -1210,7 +1185,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
 	 * We also  don't like using  the DPLL because this causes glitches
 	 * on PRST-/SRST- when the state engine gets reset...
 	 */
-	if (chip_type >= HPT374 || info->settings[clock] == NULL) {
+	if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) {
 		u16 f_low, delta = pci_clk < 50 ? 2 : 4;
 		int adjust;
 
@@ -1226,7 +1201,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
 			clock = ATA_CLOCK_50MHZ;
 		}
 
-		if (info->settings[clock] == NULL) {
+		if (info->timings->clock_table[clock] == NULL) {
 			printk(KERN_ERR "%s: unknown bus timing!\n", name);
 			kfree(info);
 			return -EIO;
@@ -1267,15 +1242,10 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
 		printk("%s: using %d MHz PCI clock\n", name, pci_clk);
 	}
 
-	/*
-	 * Advance the table pointer to a slot which points to the list
-	 * of the register values settings matching the clock being used.
-	 */
-	info->settings += clock;
-
 	/* Store the clock frequencies. */
 	info->dpll_clk	= dpll_clk;
 	info->pci_clk	= pci_clk;
+	info->clock	= clock;
 
 	/* Point to this chip's own instance of the hpt_info structure. */
 	pci_set_drvdata(dev, info);
@@ -1320,8 +1290,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 
 	hwif->set_pio_mode	= &hpt3xx_set_pio_mode;
 	hwif->set_dma_mode	= &hpt3xx_set_mode;
+
 	hwif->quirkproc		= &hpt3xx_quirkproc;
-	hwif->intrproc		= &hpt3xx_intrproc;
 	hwif->maskproc		= &hpt3xx_maskproc;
 	hwif->busproc		= &hpt3xx_busproc;
 
@@ -1494,6 +1464,11 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
 	return 0;
 }
 
+#define IDE_HFLAGS_HPT3XX \
+	(IDE_HFLAG_NO_ATAPI_DMA | \
+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
+	 IDE_HFLAG_OFF_BOARD)
+
 static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
 	{	/* 0 */
 		.name		= "HPT36x",
@@ -1508,9 +1483,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
 		 */
 		.enablebits	= {{0x50,0x10,0x10}, {0x54,0x04,0x04}},
 		.extra		= 240,
-		.host_flags	= IDE_HFLAG_SINGLE |
-				  IDE_HFLAG_NO_ATAPI_DMA |
-				  IDE_HFLAG_OFF_BOARD,
+		.host_flags	= IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 	},{	/* 1 */
@@ -1520,7 +1493,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
 		.init_dma	= init_dma_hpt366,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.extra		= 240,
-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+		.host_flags	= IDE_HFLAGS_HPT3XX,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 	},{	/* 2 */
@@ -1530,7 +1503,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
 		.init_dma	= init_dma_hpt366,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.extra		= 240,
-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+		.host_flags	= IDE_HFLAGS_HPT3XX,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 	},{	/* 3 */
@@ -1540,7 +1513,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
 		.init_dma	= init_dma_hpt366,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.extra		= 240,
-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+		.host_flags	= IDE_HFLAGS_HPT3XX,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 	},{	/* 4 */
@@ -1551,7 +1524,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.udma_mask	= ATA_UDMA5,
 		.extra		= 240,
-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+		.host_flags	= IDE_HFLAGS_HPT3XX,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 	},{	/* 5 */
@@ -1561,7 +1534,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
 		.init_dma	= init_dma_hpt366,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.extra		= 240,
-		.host_flags	= IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
+		.host_flags	= IDE_HFLAGS_HPT3XX,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 	}
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index 90b52ed37bfc..2a0f45c4f4c4 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -101,24 +101,11 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
 	pci_read_config_byte(dev, 0x54, &reg54);
 	pci_read_config_byte(dev, 0x55, &reg55);
 
-	switch(speed) {
-		case XFER_UDMA_6:
-		case XFER_UDMA_4:
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_5:
-		case XFER_UDMA_3:
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_SW_DMA_2:
-			break;
-		default:
-			return;
-	}
-
 	if (speed >= XFER_UDMA_0) {
+		u8 udma = speed - XFER_UDMA_0;
+
+		u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
+
 		if (!(reg48 & u_flag))
 			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
 		if (speed >= XFER_UDMA_5) {
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 99b7d763b6c7..e610a5340fdc 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -431,33 +431,29 @@ static u8 __devinit ata66_it821x(ide_hwif_t *hwif)
 }
 
 /**
- *	it821x_fixup	-	post init callback
- *	@hwif: interface
+ *	it821x_quirkproc	-	post init callback
+ *	@drive: drive
  *
- *	This callback is run after the drives have been probed but
+ *	This callback is run after the drive has been probed but
  *	before anything gets attached. It allows drivers to do any
  *	final tuning that is needed, or fixups to work around bugs.
  */
 
-static void __devinit it821x_fixups(ide_hwif_t *hwif)
+static void __devinit it821x_quirkproc(ide_drive_t *drive)
 {
-	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-	int i;
+	struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif);
+	struct hd_driveid *id = drive->id;
+	u16 *idbits = (u16 *)drive->id;
 
-	if(!itdev->smart) {
+	if (!itdev->smart) {
 		/*
 		 *	If we are in pass through mode then not much
 		 *	needs to be done, but we do bother to clear the
 		 *	IRQ mask as we may well be in PIO (eg rev 0x10)
 		 *	for now and we know unmasking is safe on this chipset.
 		 */
-		for (i = 0; i < 2; i++) {
-			ide_drive_t *drive = &hwif->drives[i];
-			if(drive->present)
-				drive->unmask = 1;
-		}
-		return;
-	}
+		drive->unmask = 1;
+	} else {
 	/*
 	 *	Perform fixups on smart mode. We need to "lose" some
 	 *	capabilities the firmware lacks but does not filter, and
@@ -465,16 +461,6 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif)
 	 *	in RAID mode.
 	 */
 
-	for(i = 0; i < 2; i++) {
-		ide_drive_t *drive = &hwif->drives[i];
-		struct hd_driveid *id;
-		u16 *idbits;
-
-		if(!drive->present)
-			continue;
-		id = drive->id;
-		idbits = (u16 *)drive->id;
-
 		/* Check for RAID v native */
 		if(strstr(id->model, "Integrated Technology Express")) {
 			/* In raid mode the ident block is slightly buggy
@@ -537,6 +523,8 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
 	struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL);
 	u8 conf;
 
+	hwif->quirkproc = &it821x_quirkproc;
+
 	if (idev == NULL) {
 		printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
 		return;
@@ -633,7 +621,6 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
 		.name		= name_str,		\
 		.init_chipset	= init_chipset_it821x,	\
 		.init_hwif	= init_hwif_it821x,	\
-		.fixup	 	= it821x_fixups,	\
 		.host_flags	= IDE_HFLAG_BOOTABLE,	\
 		.pio_mask	= ATA_PIO4,		\
 	}
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index 2b4f44e45a1a..89d2363a1ebd 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -146,7 +146,7 @@ static struct udma_timing {
 	{ 0x1a, 0x01, 0xcb },	/* UDMA mode 6 */
 };
 
-static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
+static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u8 adj			= (drive->dn & 1) ? 0x08 : 0x00;
@@ -162,45 +162,18 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
 	if (max_dma_rate(hwif->pci_dev) == 4) {
 		u8 mode = speed & 0x07;
 
-		switch (speed) {
-			case XFER_UDMA_6:
-			case XFER_UDMA_5:
-			case XFER_UDMA_4:
-			case XFER_UDMA_3:
-			case XFER_UDMA_2:
-			case XFER_UDMA_1:
-			case XFER_UDMA_0:
-				set_indexed_reg(hwif, 0x10 + adj,
-						udma_timings[mode].reg10);
-				set_indexed_reg(hwif, 0x11 + adj,
-						udma_timings[mode].reg11);
-				set_indexed_reg(hwif, 0x12 + adj,
-						udma_timings[mode].reg12);
-				break;
-
-			case XFER_MW_DMA_2:
-			case XFER_MW_DMA_1:
-			case XFER_MW_DMA_0:
-				set_indexed_reg(hwif, 0x0e + adj,
-						mwdma_timings[mode].reg0e);
-				set_indexed_reg(hwif, 0x0f + adj,
-						mwdma_timings[mode].reg0f);
-				break;
-			case XFER_PIO_4:
-			case XFER_PIO_3:
-			case XFER_PIO_2:
-			case XFER_PIO_1:
-			case XFER_PIO_0:
-				set_indexed_reg(hwif, 0x0c + adj,
-						pio_timings[mode].reg0c);
-				set_indexed_reg(hwif, 0x0d + adj,
-						pio_timings[mode].reg0d);
-				set_indexed_reg(hwif, 0x13 + adj,
-						pio_timings[mode].reg13);
-				break;
-			default:
-				printk(KERN_ERR "pdc202xx_new: "
-				       "Unknown speed %d ignored\n", speed);
+		if (speed >= XFER_UDMA_0) {
+			set_indexed_reg(hwif, 0x10 + adj,
+					udma_timings[mode].reg10);
+			set_indexed_reg(hwif, 0x11 + adj,
+					udma_timings[mode].reg11);
+			set_indexed_reg(hwif, 0x12 + adj,
+					udma_timings[mode].reg12);
+		} else {
+			set_indexed_reg(hwif, 0x0e + adj,
+					mwdma_timings[mode].reg0e);
+			set_indexed_reg(hwif, 0x0f + adj,
+					mwdma_timings[mode].reg0f);
 		}
 	} else if (speed == XFER_UDMA_2) {
 		/* Set tHOLD bit to 0 if using UDMA mode 2 */
@@ -212,7 +185,14 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
 
 static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pdcnew_set_mode(drive, XFER_PIO_0 + pio);
+	ide_hwif_t *hwif = drive->hwif;
+	u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
+
+	if (max_dma_rate(hwif->pci_dev) == 4) {
+		set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c);
+		set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d);
+		set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13);
+	}
 }
 
 static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
@@ -223,14 +203,17 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
 		return ATA_CBL_PATA80;
 }
 
-static int pdcnew_quirkproc(ide_drive_t *drive)
+static void pdcnew_quirkproc(ide_drive_t *drive)
 {
 	const char **list, *model = drive->id->model;
 
 	for (list = pdc_quirk_drives; *list != NULL; list++)
-		if (strstr(model, *list) != NULL)
-			return 2;
-	return 0;
+		if (strstr(model, *list) != NULL) {
+			drive->quirk_list = 2;
+			return;
+		}
+
+	drive->quirk_list = 0;
 }
 
 static void pdcnew_reset(ide_drive_t *drive)
@@ -466,7 +449,7 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
 static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
 {
 	hwif->set_pio_mode = &pdcnew_set_pio_mode;
-	hwif->set_dma_mode = &pdcnew_set_mode;
+	hwif->set_dma_mode = &pdcnew_set_dma_mode;
 
 	hwif->quirkproc = &pdcnew_quirkproc;
 	hwif->resetproc = &pdcnew_reset;
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index e09742e2ba59..3a1e081fe390 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -162,7 +162,7 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
  */
 static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
 {
-	unsigned long clock_reg = hwif->dma_master + 0x11;
+	unsigned long clock_reg = hwif->extra_base + 0x01;
 	u8 clock = inb(clock_reg);
 
 	outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg);
@@ -170,20 +170,23 @@ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif)
 
 static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
 {
-	unsigned long clock_reg = hwif->dma_master + 0x11;
+	unsigned long clock_reg = hwif->extra_base + 0x01;
 	u8 clock = inb(clock_reg);
 
 	outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
 }
 
-static int pdc202xx_quirkproc (ide_drive_t *drive)
+static void pdc202xx_quirkproc(ide_drive_t *drive)
 {
 	const char **list, *model = drive->id->model;
 
 	for (list = pdc_quirk_drives; *list != NULL; list++)
-		if (strstr(model, *list) != NULL)
-			return 2;
-	return 0;
+		if (strstr(model, *list) != NULL) {
+			drive->quirk_list = 2;
+			return;
+		}
+
+	drive->quirk_list = 0;
 }
 
 static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
@@ -193,7 +196,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
 	if (drive->media != ide_disk || drive->addressing == 1) {
 		struct request *rq	= HWGROUP(drive)->rq;
 		ide_hwif_t *hwif	= HWIF(drive);
-		unsigned long high_16   = hwif->dma_master;
+		unsigned long high_16	= hwif->extra_base - 16;
 		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
 		u32 word_count	= 0;
 		u8 clock = inb(high_16 + 0x11);
@@ -212,7 +215,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
 {
 	if (drive->media != ide_disk || drive->addressing == 1) {
 		ide_hwif_t *hwif	= HWIF(drive);
-		unsigned long high_16	= hwif->dma_master;
+		unsigned long high_16	= hwif->extra_base - 16;
 		unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x20);
 		u8 clock		= 0;
 
@@ -228,7 +231,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
 static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
-	unsigned long high_16	= hwif->dma_master;
+	unsigned long high_16	= hwif->extra_base - 16;
 	u8 dma_stat		= inb(hwif->dma_status);
 	u8 sc1d			= inb(high_16 + 0x001d);
 
@@ -271,7 +274,7 @@ static void pdc202xx_dma_timeout(ide_drive_t *drive)
 
 static void pdc202xx_reset_host (ide_hwif_t *hwif)
 {
-	unsigned long high_16	= hwif->dma_master;
+	unsigned long high_16	= hwif->extra_base - 16;
 	u8 udma_speed_flag	= inb(high_16 | 0x001f);
 
 	outb(udma_speed_flag | 0x10, high_16 | 0x001f);
@@ -375,6 +378,11 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
 	}
 }
 
+#define IDE_HFLAGS_PDC202XX \
+	(IDE_HFLAG_ERROR_STOPS_FIFO | \
+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
+	 IDE_HFLAG_OFF_BOARD)
+
 #define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
 	{ \
 		.name		= name_str, \
@@ -382,9 +390,7 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
 		.init_hwif	= init_hwif_pdc202xx, \
 		.init_dma	= init_dma_pdc202xx, \
 		.extra		= 48, \
-		.host_flags	= IDE_HFLAG_ERROR_STOPS_FIFO | \
-				  extra_flags | \
-				  IDE_HFLAG_OFF_BOARD, \
+		.host_flags	= IDE_HFLAGS_PDC202XX | extra_flags, \
 		.pio_mask	= ATA_PIO4, \
 		.mwdma_mask	= ATA_MWDMA2, \
 		.udma_mask	= udma, \
@@ -397,8 +403,7 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
 		.init_hwif	= init_hwif_pdc202xx,
 		.init_dma	= init_dma_pdc202xx,
 		.extra		= 16,
-		.host_flags	= IDE_HFLAG_ERROR_STOPS_FIFO |
-				  IDE_HFLAG_OFF_BOARD,
+		.host_flags	= IDE_HFLAGS_PDC202XX,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 		.udma_mask	= ATA_UDMA2,
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index 27781d294cea..bd6d3f77d30c 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -203,20 +203,11 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
 	pci_read_config_byte(dev, 0x54, &reg54);
 	pci_read_config_byte(dev, 0x55, &reg55);
 
-	switch(speed) {
-		case XFER_UDMA_4:
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_5:
-		case XFER_UDMA_3:
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_SW_DMA_2:	break;
-		default:		return;
-	}
-
 	if (speed >= XFER_UDMA_0) {
+		u8 udma = speed - XFER_UDMA_0;
+
+		u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4);
+
 		if (!(reg48 & u_flag))
 			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
 		if (speed == XFER_UDMA_5) {
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 707d5ff66b03..32fdf53379f5 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -135,59 +135,29 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
 	unsigned short		pci_clock;
 	unsigned int		basereg = hwif->channel ? 0x50 : 0x40;
 
+	static const u32 udma_timing[3][3] = {
+		{ 0x00921250, 0x00911140, 0x00911030 },
+		{ 0x00932470, 0x00922260, 0x00922140 },
+		{ 0x009436a1, 0x00933481, 0x00923261 },
+	};
+
+	static const u32 mwdma_timing[3][3] = {
+		{ 0x00077771, 0x00012121, 0x00002020 },
+		{ 0x000bbbb2, 0x00024241, 0x00013131 },
+		{ 0x000ffff3, 0x00035352, 0x00015151 },
+	};
+
 	pci_clock = sc1200_get_pci_clock();
 
 	/*
 	 * Note that each DMA mode has several timings associated with it.
 	 * The correct timing depends on the fast PCI clock freq.
 	 */
-	timings = 0;
-	switch (mode) {
-		case XFER_UDMA_0:
-			switch (pci_clock) {
-				case PCI_CLK_33:	timings = 0x00921250;	break;
-				case PCI_CLK_48:	timings = 0x00932470;	break;
-				case PCI_CLK_66:	timings = 0x009436a1;	break;
-			}
-			break;
-		case XFER_UDMA_1:
-			switch (pci_clock) {
-				case PCI_CLK_33:	timings = 0x00911140;	break;
-				case PCI_CLK_48:	timings = 0x00922260;	break;
-				case PCI_CLK_66:	timings = 0x00933481;	break;
-			}
-			break;
-		case XFER_UDMA_2:
-			switch (pci_clock) {
-				case PCI_CLK_33:	timings = 0x00911030;	break;
-				case PCI_CLK_48:	timings = 0x00922140;	break;
-				case PCI_CLK_66:	timings = 0x00923261;	break;
-			}
-			break;
-		case XFER_MW_DMA_0:
-			switch (pci_clock) {
-				case PCI_CLK_33:	timings = 0x00077771;	break;
-				case PCI_CLK_48:	timings = 0x000bbbb2;	break;
-				case PCI_CLK_66:	timings = 0x000ffff3;	break;
-			}
-			break;
-		case XFER_MW_DMA_1:
-			switch (pci_clock) {
-				case PCI_CLK_33:	timings = 0x00012121;	break;
-				case PCI_CLK_48:	timings = 0x00024241;	break;
-				case PCI_CLK_66:	timings = 0x00035352;	break;
-			}
-			break;
-		case XFER_MW_DMA_2:
-			switch (pci_clock) {
-				case PCI_CLK_33:	timings = 0x00002020;	break;
-				case PCI_CLK_48:	timings = 0x00013131;	break;
-				case PCI_CLK_66:	timings = 0x00015151;	break;
-			}
-			break;
-		default:
-			return;
-	}
+
+	if (mode >= XFER_UDMA_0)
+		timings =  udma_timing[pci_clock][mode - XFER_UDMA_0];
+	else
+		timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0];
 
 	if (unit == 0) {			/* are we configuring drive0? */
 		pci_read_config_dword(hwif->pci_dev, basereg+4, &reg);
@@ -250,9 +220,9 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
 	}
 	if (mode != -1) {
 		printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
-		hwif->dma_off_quietly(drive);
-		if (ide_set_dma_mode(drive, mode) == 0)
-			hwif->dma_host_on(drive);
+		ide_dma_off_quietly(drive);
+		if (ide_set_dma_mode(drive, mode) == 0 && drive->using_dma)
+			hwif->dma_host_set(drive, 1);
 		return;
 	}
 
@@ -260,66 +230,39 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
 }
 
 #ifdef CONFIG_PM
-static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
-{
-	int	h;
-
-	for (h = 0; h < MAX_HWIFS; h++) {
-		ide_hwif_t *hwif = &ide_hwifs[h];
-		if (prev) {
-			if (hwif == prev)
-				prev = NULL;	// found previous, now look for next match
-		} else {
-			if (hwif && hwif->pci_dev == dev)
-				return hwif;	// found next match
-		}
-	}
-	return NULL;	// not found
-}
-
-typedef struct sc1200_saved_state_s {
-	__u32		regs[4];
-} sc1200_saved_state_t;
-
+struct sc1200_saved_state {
+	u32 regs[8];
+};
 
 static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
 {
-	ide_hwif_t		*hwif = NULL;
-
 	printk("SC1200: suspend(%u)\n", state.event);
 
+	/*
+	 * we only save state when going from full power to less
+	 */
 	if (state.event == PM_EVENT_ON) {
-		// we only save state when going from full power to less
-
-		//
-		// Loop over all interfaces that are part of this PCI device:
-		//
-		while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
-			sc1200_saved_state_t	*ss;
-			unsigned int		basereg, r;
-			//
-			// allocate a permanent save area, if not already allocated
-			//
-			ss = (sc1200_saved_state_t *)hwif->config_data;
-			if (ss == NULL) {
-				ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL);
-				if (ss == NULL)
-					return -ENOMEM;
-				hwif->config_data = (unsigned long)ss;
-			}
-			ss = (sc1200_saved_state_t *)hwif->config_data;
-			//
-			// Save timing registers:  this may be unnecessary if 
-			// BIOS also does it
-			//
-			basereg = hwif->channel ? 0x50 : 0x40;
-			for (r = 0; r < 4; ++r) {
-				pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]);
-			}
+		struct sc1200_saved_state *ss;
+		unsigned int r;
+
+		/*
+		 * allocate a permanent save area, if not already allocated
+		 */
+		ss = (struct sc1200_saved_state *)pci_get_drvdata(dev);
+		if (ss == NULL) {
+			ss = kmalloc(sizeof(*ss), GFP_KERNEL);
+			if (ss == NULL)
+				return -ENOMEM;
+			pci_set_drvdata(dev, ss);
 		}
-	}
 
-	/* You don't need to iterate over disks -- sysfs should have done that for you already */ 
+		/*
+		 * save timing registers
+		 * (this may be unnecessary if BIOS also does it)
+		 */
+		for (r = 0; r < 8; r++)
+			pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]);
+	}
 
 	pci_disable_device(dev);
 	pci_set_power_state(dev, pci_choose_state(dev, state));
@@ -328,30 +271,25 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
 
 static int sc1200_resume (struct pci_dev *dev)
 {
-	ide_hwif_t	*hwif = NULL;
-	int		i;
+	struct sc1200_saved_state *ss;
+	unsigned int r;
+	int i;
 
 	i = pci_enable_device(dev);
 	if (i)
 		return i;
 
-	//
-	// loop over all interfaces that are part of this pci device:
-	//
-	while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
-		unsigned int		basereg, r;
-		sc1200_saved_state_t	*ss = (sc1200_saved_state_t *)hwif->config_data;
-
-		//
-		// Restore timing registers:  this may be unnecessary if BIOS also does it
-		//
-		basereg = hwif->channel ? 0x50 : 0x40;
-		if (ss != NULL) {
-			for (r = 0; r < 4; ++r) {
-				pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
-			}
-		}
+	ss = (struct sc1200_saved_state *)pci_get_drvdata(dev);
+
+	/*
+	 * restore timing registers
+	 * (this may be unnecessary if BIOS also does it)
+	 */
+	if (ss) {
+		for (r = 0; r < 8; r++)
+			pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]);
 	}
+
 	return 0;
 }
 #endif
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index ebb7132b9b84..24a85bbcd2a6 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -254,19 +254,7 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
 		offset = 0; /* 100MHz */
 	}
 
-	switch (speed) {
-	case XFER_UDMA_6:
-	case XFER_UDMA_5:
-	case XFER_UDMA_4:
-	case XFER_UDMA_3:
-	case XFER_UDMA_2:
-	case XFER_UDMA_1:
-	case XFER_UDMA_0:
-		idx = speed - XFER_UDMA_0;
-		break;
-	default:
-		return;
-	}
+	idx = speed - XFER_UDMA_0;
 
 	jcactsel = JCACTSELtbl[offset][idx];
 	if (is_slave) {
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index a7280311357b..877c09bf4829 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -164,25 +164,12 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
 	ultra_timing	&= ~(0x0F << (4*unit));
 	ultra_enable	&= ~(0x01 << drive->dn);
 
-	switch(speed) {
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
-			break;
-
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			dma_timing   |= dma_modes[2];
-			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
-			ultra_enable |= (0x01 << drive->dn);
-		default:
-			break;
-	}
+	if (speed >= XFER_UDMA_0) {
+		dma_timing   |= dma_modes[2];
+		ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit));
+		ultra_enable |= (0x01 << drive->dn);
+	} else if (speed >= XFER_MW_DMA_0)
+		dma_timing   |= dma_modes[speed - XFER_MW_DMA_0];
 
 	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
 	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
@@ -366,12 +353,17 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
 	}
 }
 
+#define IDE_HFLAGS_SVWKS \
+	(IDE_HFLAG_LEGACY_IRQS | \
+	 IDE_HFLAG_ABUSE_SET_DMA_MODE | \
+	 IDE_HFLAG_BOOTABLE)
+
 static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
 	{	/* 0 */
 		.name		= "SvrWks OSB4",
 		.init_chipset	= init_chipset_svwks,
 		.init_hwif	= init_hwif_svwks,
-		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
+		.host_flags	= IDE_HFLAGS_SVWKS,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 		.udma_mask	= 0x00, /* UDMA is problematic on OSB4 */
@@ -379,7 +371,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
 		.name		= "SvrWks CSB5",
 		.init_chipset	= init_chipset_svwks,
 		.init_hwif	= init_hwif_svwks,
-		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
+		.host_flags	= IDE_HFLAGS_SVWKS,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 		.udma_mask	= ATA_UDMA5,
@@ -387,7 +379,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
 		.name		= "SvrWks CSB6",
 		.init_chipset	= init_chipset_svwks,
 		.init_hwif	= init_hwif_svwks,
-		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
+		.host_flags	= IDE_HFLAGS_SVWKS,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 		.udma_mask	= ATA_UDMA5,
@@ -395,8 +387,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
 		.name		= "SvrWks CSB6",
 		.init_chipset	= init_chipset_svwks,
 		.init_hwif	= init_hwif_svwks,
-		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE |
-				  IDE_HFLAG_BOOTABLE,
+		.host_flags	= IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 		.udma_mask	= ATA_UDMA5,
@@ -404,8 +395,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
 		.name		= "SvrWks HT1000",
 		.init_chipset	= init_chipset_svwks,
 		.init_hwif	= init_hwif_svwks,
-		.host_flags	= IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE |
-				  IDE_HFLAG_BOOTABLE,
+		.host_flags	= IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE,
 		.pio_mask	= ATA_PIO4,
 		.mwdma_mask	= ATA_MWDMA2,
 		.udma_mask	= ATA_UDMA5,
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index de820aa58cd0..9e0be7d54980 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -277,21 +277,6 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
 	return dma_stat;
 }
 
-static int
-sgiioc4_ide_dma_on(ide_drive_t * drive)
-{
-	drive->using_dma = 1;
-
-	return 0;
-}
-
-static void sgiioc4_dma_off_quietly(ide_drive_t *drive)
-{
-	drive->using_dma = 0;
-
-	drive->hwif->dma_host_off(drive);
-}
-
 static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
 }
@@ -303,13 +288,10 @@ sgiioc4_ide_dma_test_irq(ide_drive_t * drive)
 	return sgiioc4_checkirq(HWIF(drive));
 }
 
-static void sgiioc4_dma_host_on(ide_drive_t * drive)
-{
-}
-
-static void sgiioc4_dma_host_off(ide_drive_t * drive)
+static void sgiioc4_dma_host_set(ide_drive_t *drive, int on)
 {
-	sgiioc4_clearirq(drive);
+	if (!on)
+		sgiioc4_clearirq(drive);
 }
 
 static void
@@ -582,7 +564,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
 	hwif->pre_reset = NULL;	/* No HBA specific pre_set needed */
 	hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine,
 						clear interrupts */
-	hwif->intrproc = NULL;	/* Enable or Disable interrupt from drive */
 	hwif->maskproc = &sgiioc4_maskproc;	/* Mask on/off NIEN register */
 	hwif->quirkproc = NULL;
 	hwif->busproc = NULL;
@@ -594,14 +575,11 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
 
 	hwif->mwdma_mask = ATA_MWDMA2_ONLY;
 
+	hwif->dma_host_set = &sgiioc4_dma_host_set;
 	hwif->dma_setup = &sgiioc4_ide_dma_setup;
 	hwif->dma_start = &sgiioc4_ide_dma_start;
 	hwif->ide_dma_end = &sgiioc4_ide_dma_end;
-	hwif->ide_dma_on = &sgiioc4_ide_dma_on;
-	hwif->dma_off_quietly = &sgiioc4_dma_off_quietly;
 	hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
-	hwif->dma_host_on = &sgiioc4_dma_host_on;
-	hwif->dma_host_off = &sgiioc4_dma_host_off;
 	hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
 	hwif->dma_timeout = &ide_dma_timeout;
 }
@@ -615,6 +593,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
 	ide_hwif_t *hwif;
 	int h;
 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+	hw_regs_t hw;
 
 	/*
 	 * Find an empty HWIF; if none available, return -ENOMEM.
@@ -654,21 +633,16 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
 		return -ENOMEM;
 	}
 
-	if (hwif->io_ports[IDE_DATA_OFFSET] != cmd_base) {
-		hw_regs_t hw;
-
-		/* Initialize the IO registers */
-		memset(&hw, 0, sizeof(hw));
-		sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
-		memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-	}
+	/* Initialize the IO registers */
+	memset(&hw, 0, sizeof(hw));
+	sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
+	hw.irq = dev->irq;
+	hw.chipset = ide_pci;
+	hw.dev = &dev->dev;
+	ide_init_port_hw(hwif, &hw);
 
-	hwif->irq = dev->irq;
-	hwif->chipset = ide_pci;
 	hwif->pci_dev = dev;
 	hwif->channel = 0;	/* Single Channel chip */
-	hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
 
 	/* The IOC4 uses MMIO rather than Port IO. */
 	default_hwif_mmiops(hwif);
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 5709c252543b..908f37b4e0ee 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -278,27 +278,14 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
 
 	scsc = is_sata(hwif) ? 1 : scsc;
 
-	switch(speed) {
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			multi = dma[speed - XFER_MW_DMA_0];
-			mode |= ((unit) ? 0x20 : 0x02);
-			break;
-		case XFER_UDMA_6:
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			multi = dma[2];
-			ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
-					   (ultra5[speed - XFER_UDMA_0]));
-			mode |= ((unit) ? 0x30 : 0x03);
-			break;
-		default:
-			return;
+	if (speed >= XFER_UDMA_0) {
+		multi = dma[2];
+		ultra |= (scsc ? ultra6[speed - XFER_UDMA_0] :
+				 ultra5[speed - XFER_UDMA_0]);
+		mode |= (unit ? 0x30 : 0x03);
+	} else {
+		multi = dma[speed - XFER_MW_DMA_0];
+		mode |= (unit ? 0x20 : 0x02);
 	}
 
 	if (hwif->mmio) {
@@ -726,9 +713,6 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
 	const char *s = &drive->id->model[0];
 	unsigned len;
 
-	if (!drive->present)
-		return 0;
-
 	len = strnlen(s, sizeof(drive->id->model));
 
 	if ((len > 4) && (!memcmp(s, "ST", 2))) {
@@ -743,18 +727,20 @@ static int is_dev_seagate_sata(ide_drive_t *drive)
 }
 
 /**
- *	siimage_fixup		-	post probe fixups
- *	@hwif: interface to fix up
+ *	sil_quirkproc		-	post probe fixups
+ *	@drive: drive
  *
  *	Called after drive probe we use this to decide whether the
  *	Seagate fixup must be applied. This used to be in init_iops but
  *	that can occur before we know what drives are present.
  */
 
-static void __devinit siimage_fixup(ide_hwif_t *hwif)
+static void __devinit sil_quirkproc(ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = drive->hwif;
+
 	/* Try and raise the rqsize */
-	if (!is_sata(hwif) || !is_dev_seagate_sata(&hwif->drives[0]))
+	if (!is_sata(hwif) || !is_dev_seagate_sata(drive))
 		hwif->rqsize = 128;
 }
 
@@ -817,6 +803,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
 
 	hwif->set_pio_mode = &sil_set_pio_mode;
 	hwif->set_dma_mode = &sil_set_dma_mode;
+	hwif->quirkproc = &sil_quirkproc;
 
 	if (sata) {
 		static int first = 1;
@@ -855,7 +842,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
 		.init_chipset	= init_chipset_siimage,	\
 		.init_iops	= init_iops_siimage,	\
 		.init_hwif	= init_hwif_siimage,	\
-		.fixup		= siimage_fixup,	\
 		.host_flags	= IDE_HFLAG_BOOTABLE,	\
 		.pio_mask	= ATA_PIO4,		\
 		.mwdma_mask	= ATA_MWDMA2,		\
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index d90b42917775..85d36996e6af 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -305,59 +305,56 @@ static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
 	sis_program_timings(drive, XFER_PIO_0 + pio);
 }
 
-static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
+static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
+	struct pci_dev *dev = drive->hwif->pci_dev;
+	u32 regdw = 0;
+	u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
 
-	/* Config chip for mode */
-	switch(speed) {
-		case XFER_UDMA_6:
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			if (chipset_family >= ATA_133) {
-				u32 regdw = 0;
-				u8 drive_pci = sis_ata133_get_base(drive);
-
-				pci_read_config_dword(dev, drive_pci, &regdw);
-				regdw |= 0x04;
-				regdw &= 0xfffff00f;
-				/* check if ATA133 enable */
-				if (regdw & 0x08) {
-					regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4;
-					regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8;
-				} else {
-					regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4;
-					regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8;
-				}
-				pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
-			} else {
-				u8 drive_pci = 0x40 + drive->dn * 2, reg = 0;
-
-				pci_read_config_byte(dev, drive_pci+1, &reg);
-				/* Force the UDMA bit on if we want to use UDMA */
-				reg |= 0x80;
-				/* clean reg cycle time bits */
-				reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family]))
-					 << cycle_time_offset[chipset_family]);
-				/* set reg cycle time bits */
-				reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0]
-					<< cycle_time_offset[chipset_family];
-				pci_write_config_byte(dev, drive_pci+1, reg);
-			}
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			sis_program_timings(drive, speed);
-			break;
-		default:
-			break;
-	}
+	pci_read_config_dword(dev, drive_pci, &regdw);
+
+	regdw |= 0x04;
+	regdw &= 0xfffff00f;
+	/* check if ATA133 enable */
+	clk = (regdw & 0x08) ? ATA_133 : ATA_100;
+	idx = mode - XFER_UDMA_0;
+	regdw |= cycle_time_value[clk][idx] << 4;
+	regdw |= cvs_time_value[clk][idx] << 8;
+
+	pci_write_config_dword(dev, drive_pci, regdw);
+}
+
+static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode)
+{
+	struct pci_dev *dev = drive->hwif->pci_dev;
+	u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family;
+
+	pci_read_config_byte(dev, drive_pci + 1, &reg);
+
+	/* force the UDMA bit on if we want to use UDMA */
+	reg |= 0x80;
+	/* clean reg cycle time bits */
+	reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]);
+	/* set reg cycle time bits */
+	reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i];
+
+	pci_write_config_byte(dev, drive_pci + 1, reg);
+}
+
+static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode)
+{
+	if (chipset_family >= ATA_133)	/* ATA_133 */
+		sis_ata133_program_udma_timings(drive, mode);
+	else				/* ATA_33/66/100a/100/133a */
+		sis_ata33_program_udma_timings(drive, mode);
+}
+
+static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
+{
+	if (speed >= XFER_UDMA_0)
+		sis_program_udma_timings(drive, speed);
+	else
+		sis_program_timings(drive, speed);
 }
 
 static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 147d783f7529..c7a125b66c29 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -13,6 +13,7 @@
  *  -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
  *
  * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
  */
 
 #include <linux/types.h>
@@ -90,14 +91,8 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
 	drive->drive_data &= 0xffff0000;
 	drive->drive_data |= drv_ctrl;
 
-	if (!drive->using_dma) {
-		/*
-		 * If we are actually using MW DMA, then we can not
-		 * reprogram the interface drive control register.
-		 */
-		pci_write_config_word(dev, reg,  drv_ctrl);
-		pci_read_config_word (dev, reg, &drv_ctrl);
-	}
+	pci_write_config_word(dev, reg,  drv_ctrl);
+	pci_read_config_word (dev, reg, &drv_ctrl);
 
 	printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
 			  ide_xfer_verbose(pio + XFER_PIO_0),
@@ -115,33 +110,14 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
  	DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n",
 	     drive->name, ide_xfer_verbose(speed)));
 
-	switch (speed) {
-	case XFER_MW_DMA_2:
-	case XFER_MW_DMA_1:
-	case XFER_MW_DMA_0:
-		drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
+	drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0];
 
-		/*
-		 * Store the DMA timings so that we can actually program
-		 * them when DMA will be turned on...
-		 */
-		drive->drive_data &= 0x0000ffff;
-		drive->drive_data |= (unsigned long)drv_ctrl << 16;
-
-		/*
-		 * If we are already using DMA, we just reprogram
-		 * the drive control register.
-		 */
-		if (drive->using_dma) {
-			struct pci_dev *dev	= HWIF(drive)->pci_dev;
-			int reg 		= 0x44 + drive->dn * 4;
-
-			pci_write_config_word(dev, reg, drv_ctrl);
-		}
-		break;
-	default:
-		return;
-	}
+	/*
+	 * Store the DMA timings so that we can actually program
+	 * them when DMA will be turned on...
+	 */
+	drive->drive_data &= 0x0000ffff;
+	drive->drive_data |= (unsigned long)drv_ctrl << 16;
 }
 
 /*
@@ -209,6 +185,11 @@ static void sl82c105_dma_start(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
+	int reg 		= 0x44 + drive->dn * 4;
+
+	DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
+
+	pci_write_config_word(dev, reg, drive->drive_data >> 16);
 
 	sl82c105_reset_host(dev);
 	ide_dma_start(drive);
@@ -222,64 +203,24 @@ static void sl82c105_dma_timeout(ide_drive_t *drive)
 	ide_dma_timeout(drive);
 }
 
-static int sl82c105_ide_dma_on(ide_drive_t *drive)
-{
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	int rc, reg 		= 0x44 + drive->dn * 4;
-
-	DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
-
-	rc = __ide_dma_on(drive);
-	if (rc == 0) {
-		pci_write_config_word(dev, reg, drive->drive_data >> 16);
-
-		printk(KERN_INFO "%s: DMA enabled\n", drive->name);
-	}
-	return rc;
-}
-
-static void sl82c105_dma_off_quietly(ide_drive_t *drive)
+static int sl82c105_dma_end(ide_drive_t *drive)
 {
 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
 	int reg 		= 0x44 + drive->dn * 4;
+	int ret;
 
-	DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name));
+	DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name));
 
-	pci_write_config_word(dev, reg, drive->drive_data);
+	ret = __ide_dma_end(drive);
 
-	ide_dma_off_quietly(drive);
-}
+	pci_write_config_word(dev, reg, drive->drive_data);
 
-/*
- * Ok, that is nasty, but we must make sure the DMA timings
- * won't be used for a PIO access. The solution here is
- * to make sure the 16 bits mode is diabled on the channel
- * when DMA is enabled, thus causing the chip to use PIO0
- * timings for those operations.
- */
-static void sl82c105_selectproc(ide_drive_t *drive)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	u32 val, old, mask;
-
-	//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
-
-	mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16;
-	old = val = (u32)pci_get_drvdata(dev);
-	if (drive->using_dma)
-		val &= ~mask;
-	else
-		val |= mask;
-	if (old != val) {
-		pci_write_config_dword(dev, 0x40, val);	
-		pci_set_drvdata(dev, (void *)val);
-	}
+	return ret;
 }
 
 /*
  * ATA reset will clear the 16 bits mode in the control
- * register, we need to update our cache
+ * register, we need to reprogram it
  */
 static void sl82c105_resetproc(ide_drive_t *drive)
 {
@@ -289,7 +230,8 @@ static void sl82c105_resetproc(ide_drive_t *drive)
 	DBG(("sl82c105_resetproc(drive:%s)\n", drive->name));
 
 	pci_read_config_dword(dev, 0x40, &val);
-	pci_set_drvdata(dev, (void *)val);
+	val |= (CTRL_P1F16 | CTRL_P0F16);
+	pci_write_config_dword(dev, 0x40, val);
 }
 
 /*
@@ -342,7 +284,6 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
 	pci_read_config_dword(dev, 0x40, &val);
 	val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
 	pci_write_config_dword(dev, 0x40, val);
-	pci_set_drvdata(dev, (void *)val);
 
 	return dev->irq;
 }
@@ -358,7 +299,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
 
 	hwif->set_pio_mode	= &sl82c105_set_pio_mode;
 	hwif->set_dma_mode	= &sl82c105_set_dma_mode;
-	hwif->selectproc	= &sl82c105_selectproc;
 	hwif->resetproc 	= &sl82c105_resetproc;
 
 	if (!hwif->dma_base)
@@ -377,10 +317,9 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
 
 	hwif->mwdma_mask = ATA_MWDMA2;
 
-	hwif->ide_dma_on		= &sl82c105_ide_dma_on;
-	hwif->dma_off_quietly		= &sl82c105_dma_off_quietly;
 	hwif->dma_lost_irq		= &sl82c105_dma_lost_irq;
 	hwif->dma_start			= &sl82c105_dma_start;
+	hwif->ide_dma_end		= &sl82c105_dma_end;
 	hwif->dma_timeout		= &sl82c105_dma_timeout;
 
 	if (hwif->mate)
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index eb4445b229ed..dbbb46819a2d 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -91,19 +91,9 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
 	pci_read_config_word(dev, 0x48, &reg48);
 	pci_read_config_word(dev, 0x4a, &reg4a);
 
-	switch(speed) {
-		case XFER_UDMA_4:	u_speed = 4 << (drive->dn * 4); break;
-		case XFER_UDMA_3:	u_speed = 3 << (drive->dn * 4); break;
-		case XFER_UDMA_2:	u_speed = 2 << (drive->dn * 4); break;
-		case XFER_UDMA_1:	u_speed = 1 << (drive->dn * 4); break;
-		case XFER_UDMA_0:	u_speed = 0 << (drive->dn * 4); break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_SW_DMA_2:	break;
-		default:		return;
-	}
-
 	if (speed >= XFER_UDMA_0) {
+		u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4);
+
 		if (!(reg48 & u_flag))
 			pci_write_config_word(dev, 0x48, reg48|u_flag);
 		/* FIXME: (reg4a & a_speed) ? */
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
index a66ebd14664e..e1faf6c2fe16 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/pci/tc86c001.c
@@ -222,7 +222,8 @@ static const struct ide_port_info tc86c001_chipset __devinitdata = {
 	.name		= "TC86C001",
 	.init_chipset	= init_chipset_tc86c001,
 	.init_hwif	= init_hwif_tc86c001,
-	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD,
+	.host_flags	= IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD |
+			  IDE_HFLAG_ABUSE_SET_DMA_MODE,
 	.pio_mask	= ATA_PIO4,
 	.mwdma_mask	= ATA_MWDMA2,
 	.udma_mask	= ATA_UDMA4,
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index a227c41d23a3..ae52a96a1cf9 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -81,8 +81,6 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
 		case XFER_PIO_0:
 			timing = 0x0808;
 			break;
-		default:
-			return;
 	}
 
 	triflex_timings &= ~(0xFFFF << (16 * unit));
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index 0151d7fdfb8a..04cd893e1ab0 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -241,11 +241,7 @@ static int trm290_ide_dma_test_irq (ide_drive_t *drive)
 	return (status == 0x00ff);
 }
 
-static void trm290_dma_host_on(ide_drive_t *drive)
-{
-}
-
-static void trm290_dma_host_off(ide_drive_t *drive)
+static void trm290_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
@@ -289,8 +285,7 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
 
 	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
 
-	hwif->dma_host_off	= &trm290_dma_host_off;
-	hwif->dma_host_on	= &trm290_dma_host_on;
+	hwif->dma_host_set	= &trm290_dma_host_set;
 	hwif->dma_setup 	= &trm290_dma_setup;
 	hwif->dma_exec_cmd	= &trm290_dma_exec_cmd;
 	hwif->dma_start 	= &trm290_dma_start;
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index a0d3c16b68ec..4b32c90f4896 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -439,6 +439,7 @@ static const struct ide_port_info via82cxxx_chipset __devinitdata = {
 	.enablebits	= { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
 	.host_flags	= IDE_HFLAG_PIO_NO_BLACKLIST |
 			  IDE_HFLAG_PIO_NO_DOWNGRADE |
+			  IDE_HFLAG_ABUSE_SET_DMA_MODE |
 			  IDE_HFLAG_POST_SET_MODE |
 			  IDE_HFLAG_IO_32BIT |
 			  IDE_HFLAG_BOOTABLE,
diff --git a/drivers/ide/ppc/Makefile b/drivers/ide/ppc/Makefile
new file mode 100644
index 000000000000..65af5848b28c
--- /dev/null
+++ b/drivers/ide/ppc/Makefile
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_BLK_DEV_IDE_PMAC)		+= pmac.o
+obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= mpc8xx.o
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index 5f0da35ab5ad..3fd5d45b5e0e 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -838,3 +838,21 @@ void m8xx_ide_init(void)
 	ppc_ide_md.default_io_base      = m8xx_ide_default_io_base;
 	ppc_ide_md.ide_init_hwif        = m8xx_ide_init_hwif_ports;
 }
+
+static int __init mpc8xx_ide_probe(void)
+{
+	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+
+#ifdef IDE0_BASE_OFFSET
+	idx[0] = 0;
+#ifdef IDE1_BASE_OFFSET
+	idx[1] = 1;
+#endif
+#endif
+
+	ide_device_add(idx);
+
+	return 0;
+}
+
+module_init(mpc8xx_ide_probe);
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 7f7a59885777..736d12c8e68a 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -438,13 +438,8 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw,
 		if (data_port == pmac_ide[ix].regbase)
 			break;
 
-	if (ix >= MAX_HWIFS) {
-		/* Probably a PCI interface... */
-		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
-			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-		return;
-	}
+	if (ix >= MAX_HWIFS)
+		return;		/* not an IDE PMAC interface */
 
 	for (i = 0; i < 8; ++i)
 		hw->io_ports[i] = data_port + i * 0x10;
@@ -833,38 +828,20 @@ static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
 	tl[0] = *timings;
 	tl[1] = *timings2;
 
-	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-		case XFER_UDMA_6:
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:
-		case XFER_UDMA_3:
-		case XFER_UDMA_2:
-		case XFER_UDMA_1:
-		case XFER_UDMA_0:
-			if (pmif->kind == controller_kl_ata4)
-				ret = set_timings_udma_ata4(&tl[0], speed);
-			else if (pmif->kind == controller_un_ata6
-				 || pmif->kind == controller_k2_ata6)
-				ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
-			else if (pmif->kind == controller_sh_ata6)
-				ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
-			else
-				ret = 1;
-			break;
-		case XFER_MW_DMA_2:
-		case XFER_MW_DMA_1:
-		case XFER_MW_DMA_0:
-			set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
-			break;
-		case XFER_SW_DMA_2:
-		case XFER_SW_DMA_1:
-		case XFER_SW_DMA_0:
-			return;
+	if (speed >= XFER_UDMA_0) {
+		if (pmif->kind == controller_kl_ata4)
+			ret = set_timings_udma_ata4(&tl[0], speed);
+		else if (pmif->kind == controller_un_ata6
+			 || pmif->kind == controller_k2_ata6)
+			ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
+		else if (pmif->kind == controller_sh_ata6)
+			ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
+		else
+			ret = -1;
+	} else
+		set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-		default:
-			ret = 1;
-	}
 	if (ret)
 		return;
 
@@ -1035,12 +1012,11 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
  * rare machines unfortunately, but it's better this way.
  */
 static int
-pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
+pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw)
 {
 	struct device_node *np = pmif->node;
 	const int *bidp;
 	u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
-	hw_regs_t hw;
 
 	pmif->cable_80 = 0;
 	pmif->broken_dma = pmif->broken_dma_warn = 0;
@@ -1126,11 +1102,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 	/* Tell common code _not_ to mess with resources */
 	hwif->mmio = 1;
 	hwif->hwif_data = pmif;
-	memset(&hw, 0, sizeof(hw));
-	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, &hwif->irq);
-	memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-	hwif->chipset = ide_pmac;
-	hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || pmif->mediabay;
+	hw->chipset = ide_pmac;
+	ide_init_port_hw(hwif, hw);
+	hwif->noprobe = pmif->mediabay;
 	hwif->hold = pmif->mediabay;
 	hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
 	hwif->drives[0].unmask = 1;
@@ -1159,8 +1133,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 		hwif->noprobe = 0;
 #endif /* CONFIG_PMAC_MEDIABAY */
 
-	hwif->sg_max_nents = MAX_DCMDS;
-
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	/* has a DBDMA controller channel */
 	if (pmif->dma_regs)
@@ -1186,6 +1158,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
 	ide_hwif_t *hwif;
 	pmac_ide_hwif_t *pmif;
 	int i, rc;
+	hw_regs_t hw;
 
 	i = 0;
 	while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0
@@ -1228,7 +1201,6 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
 	regbase = (unsigned long) base;
 
 	hwif->pci_dev = mdev->bus->pdev;
-	hwif->gendev.parent = &mdev->ofdev.dev;
 
 	pmif->mdev = mdev;
 	pmif->node = mdev->ofdev.node;
@@ -1246,7 +1218,12 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 	dev_set_drvdata(&mdev->ofdev.dev, hwif);
 
-	rc = pmac_ide_setup_device(pmif, hwif);
+	memset(&hw, 0, sizeof(hw));
+	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL);
+	hw.irq = irq;
+	hw.dev = &mdev->ofdev.dev;
+
+	rc = pmac_ide_setup_device(pmif, hwif, &hw);
 	if (rc != 0) {
 		/* The inteface is released to the common IDE layer */
 		dev_set_drvdata(&mdev->ofdev.dev, NULL);
@@ -1305,6 +1282,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 	void __iomem *base;
 	unsigned long rbase, rlen;
 	int i, rc;
+	hw_regs_t hw;
 
 	np = pci_device_to_OF_node(pdev);
 	if (np == NULL) {
@@ -1338,7 +1316,6 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 	}
 
 	hwif->pci_dev = pdev;
-	hwif->gendev.parent = &pdev->dev;
 	pmif->mdev = NULL;
 	pmif->node = np;
 
@@ -1355,7 +1332,12 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	pci_set_drvdata(pdev, hwif);
 
-	rc = pmac_ide_setup_device(pmif, hwif);
+	memset(&hw, 0, sizeof(hw));
+	pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL);
+	hw.irq = pdev->irq;
+	hw.dev = &pdev->dev;
+
+	rc = pmac_ide_setup_device(pmif, hwif, &hw);
 	if (rc != 0) {
 		/* The inteface is released to the common IDE layer */
 		pci_set_drvdata(pdev, NULL);
@@ -1721,11 +1703,7 @@ pmac_ide_dma_test_irq (ide_drive_t *drive)
 	return 1;
 }
 
-static void pmac_ide_dma_host_off(ide_drive_t *drive)
-{
-}
-
-static void pmac_ide_dma_host_on(ide_drive_t *drive)
+static void pmac_ide_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
@@ -1771,15 +1749,14 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 		return;
 	}
 
-	hwif->dma_off_quietly = &ide_dma_off_quietly;
-	hwif->ide_dma_on = &__ide_dma_on;
+	hwif->sg_max_nents = MAX_DCMDS;
+
+	hwif->dma_host_set = &pmac_ide_dma_host_set;
 	hwif->dma_setup = &pmac_ide_dma_setup;
 	hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd;
 	hwif->dma_start = &pmac_ide_dma_start;
 	hwif->ide_dma_end = &pmac_ide_dma_end;
 	hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq;
-	hwif->dma_host_off = &pmac_ide_dma_host_off;
-	hwif->dma_host_on = &pmac_ide_dma_host_on;
 	hwif->dma_timeout = &ide_dma_timeout;
 	hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
 
@@ -1809,3 +1786,5 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 }
 
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+
+module_init(pmac_ide_probe);
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index d2cd5a3d38f8..676c66e72881 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -165,13 +165,17 @@ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_
 
 		dma_base = pci_resource_start(dev, baridx);
 
-		if (dma_base == 0)
+		if (dma_base == 0) {
 			printk(KERN_ERR "%s: DMA base is invalid\n", d->name);
+			return 0;
+		}
 	}
 
-	if ((d->host_flags & IDE_HFLAG_CS5520) == 0 && dma_base) {
+	if (hwif->channel)
+		dma_base += 8;
+
+	if ((d->host_flags & IDE_HFLAG_CS5520) == 0) {
 		u8 simplex_stat = 0;
-		dma_base += hwif->channel ? 8 : 0;
 
 		switch(dev->device) {
 			case PCI_DEVICE_ID_AL_M5219:
@@ -359,6 +363,8 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
 	unsigned long ctl = 0, base = 0;
 	ide_hwif_t *hwif;
 	u8 bootable = (d->host_flags & IDE_HFLAG_BOOTABLE) ? 1 : 0;
+	u8 oldnoprobe = 0;
+	struct hw_regs_s hw;
 
 	if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
 		/*  Possibly we should fail if these checks report true */
@@ -381,26 +387,25 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port
 	}
 	if ((hwif = ide_match_hwif(base, bootable, d->name)) == NULL)
 		return NULL;	/* no room in ide_hwifs[] */
-	if (hwif->io_ports[IDE_DATA_OFFSET] != base ||
-	    hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
-		hw_regs_t hw;
-
-		memset(&hw, 0, sizeof(hw));
-#ifndef CONFIG_IDE_ARCH_OBSOLETE_INIT
-		ide_std_init_ports(&hw, base, ctl | 2);
-#else
-		ide_init_hwif_ports(&hw, base, ctl | 2, NULL);
-#endif
-		memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
-		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-	}
-	hwif->chipset = d->chipset ? d->chipset : ide_pci;
+
+	memset(&hw, 0, sizeof(hw));
+	hw.irq = hwif->irq ? hwif->irq : irq;
+	hw.dev = &dev->dev;
+	hw.chipset = d->chipset ? d->chipset : ide_pci;
+	ide_std_init_ports(&hw, base, ctl | 2);
+
+	if (hwif->io_ports[IDE_DATA_OFFSET] == base &&
+	    hwif->io_ports[IDE_CONTROL_OFFSET] == (ctl | 2))
+		oldnoprobe = hwif->noprobe;
+
+	ide_init_port_hw(hwif, &hw);
+
+	hwif->noprobe = oldnoprobe;
+
 	hwif->pci_dev = dev;
 	hwif->cds = d;
 	hwif->channel = port;
 
-	if (!hwif->irq)
-		hwif->irq = irq;
 	if (mate) {
 		hwif->mate = mate;
 		mate->mate = hwif;
@@ -535,12 +540,8 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
 		if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
 			continue;
 
-		/* setup proper ancestral information */
-		hwif->gendev.parent = &dev->dev;
-
 		*(idx + port) = hwif->index;
 
-		
 		if (d->init_iops)
 			d->init_iops(hwif);
 
@@ -551,8 +552,6 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int
 		    (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
 			hwif->irq = port ? 15 : 14;
 
-		hwif->fixup = d->fixup;
-
 		hwif->host_flags = d->host_flags;
 		hwif->pio_mask = d->pio_mask;
 
@@ -699,105 +698,3 @@ out:
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
-
-#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
-/*
- *	Module interfaces
- */
-
-static int pre_init = 1;		/* Before first ordered IDE scan */
-static LIST_HEAD(ide_pci_drivers);
-
-/*
- *	__ide_pci_register_driver	-	attach IDE driver
- *	@driver: pci driver
- *	@module: owner module of the driver
- *
- *	Registers a driver with the IDE layer. The IDE layer arranges that
- *	boot time setup is done in the expected device order and then
- *	hands the controllers off to the core PCI code to do the rest of
- *	the work.
- *
- *	Returns are the same as for pci_register_driver
- */
-
-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
-			      const char *mod_name)
-{
-	if (!pre_init)
-		return __pci_register_driver(driver, module, mod_name);
-	driver->driver.owner = module;
-	list_add_tail(&driver->node, &ide_pci_drivers);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
-
-/**
- *	ide_scan_pcidev		-	find an IDE driver for a device
- *	@dev: PCI device to check
- *
- *	Look for an IDE driver to handle the device we are considering.
- *	This is only used during boot up to get the ordering correct. After
- *	boot up the pci layer takes over the job.
- */
-
-static int __init ide_scan_pcidev(struct pci_dev *dev)
-{
-	struct list_head *l;
-	struct pci_driver *d;
-
-	list_for_each(l, &ide_pci_drivers) {
-		d = list_entry(l, struct pci_driver, node);
-		if (d->id_table) {
-			const struct pci_device_id *id =
-				pci_match_id(d->id_table, dev);
-
-			if (id != NULL && d->probe(dev, id) >= 0) {
-				dev->driver = d;
-				pci_dev_get(dev);
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-/**
- *	ide_scan_pcibus		-	perform the initial IDE driver scan
- *	@scan_direction: set for reverse order scanning
- *
- *	Perform the initial bus rather than driver ordered scan of the
- *	PCI drivers. After this all IDE pci handling becomes standard
- *	module ordering not traditionally ordered.
- */
- 	
-void __init ide_scan_pcibus (int scan_direction)
-{
-	struct pci_dev *dev = NULL;
-	struct pci_driver *d;
-	struct list_head *l, *n;
-
-	pre_init = 0;
-	if (!scan_direction)
-		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
-			ide_scan_pcidev(dev);
-	else
-		while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID,
-						     dev)))
-			ide_scan_pcidev(dev);
-
-	/*
-	 *	Hand the drivers over to the PCI layer now we
-	 *	are post init.
-	 */
-
-	list_for_each_safe(l, n, &ide_pci_drivers) {
-		list_del(l);
-		d = list_entry(l, struct pci_driver, node);
-		if (__pci_register_driver(d, d->driver.owner,
-					  d->driver.mod_name))
-			printk(KERN_ERR "%s: failed to register %s driver\n",
-					__FUNCTION__, d->driver.mod_name);
-	}
-}
-#endif
diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
index 489c133664d5..1f8153b57503 100644
--- a/drivers/ieee1394/Makefile
+++ b/drivers/ieee1394/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
 obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
 obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
 
+obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
diff --git a/drivers/ieee1394/init_ohci1394_dma.c b/drivers/ieee1394/init_ohci1394_dma.c
new file mode 100644
index 000000000000..ddaab6eb8ace
--- /dev/null
+++ b/drivers/ieee1394/init_ohci1394_dma.c
@@ -0,0 +1,285 @@
+/*
+ * init_ohci1394_dma.c - Initializes physical DMA on all OHCI 1394 controllers
+ *
+ * Copyright (C) 2006-2007      Bernhard Kaindl <bk@suse.de>
+ *
+ * Derived from drivers/ieee1394/ohci1394.c and arch/x86/kernel/early-quirks.c
+ * this file has functions to:
+ * - scan the PCI very early on boot for all OHCI 1394-compliant controllers
+ * - reset and initialize them and make them join the IEEE1394 bus and
+ * - enable physical DMA on them to allow remote debugging
+ *
+ * All code and data is marked as __init and __initdata, respective as
+ * during boot, all OHCI1394 controllers may be claimed by the firewire
+ * stack and at this point, this code should not touch them anymore.
+ *
+ * To use physical DMA after the initialization of the firewire stack,
+ * be sure that the stack enables it and (re-)attach after the bus reset
+ * which may be caused by the firewire stack initialization.
+ *
+ * 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/interrupt.h>	/* for ohci1394.h */
+#include <linux/delay.h>
+#include <linux/pci.h>		/* for PCI defines */
+#include <linux/init_ohci1394_dma.h>
+#include <asm/pci-direct.h>	/* for direct PCI config space access */
+#include <asm/fixmap.h>
+
+#include "ieee1394_types.h"
+#include "ohci1394.h"
+
+int __initdata init_ohci1394_dma_early;
+
+/* Reads a PHY register of an OHCI-1394 controller */
+static inline u8 __init get_phy_reg(struct ti_ohci *ohci, u8 addr)
+{
+	int i;
+	quadlet_t r;
+
+	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
+
+	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+		if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000)
+			break;
+		mdelay(1);
+	}
+	r = reg_read(ohci, OHCI1394_PhyControl);
+
+	return (r & 0x00ff0000) >> 16;
+}
+
+/* Writes to a PHY register of an OHCI-1394 controller */
+static inline void __init set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
+{
+	int i;
+
+	reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
+
+	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+		u32 r = reg_read(ohci, OHCI1394_PhyControl);
+		if (!(r & 0x00004000))
+			break;
+		mdelay(1);
+	}
+}
+
+/* Resets an OHCI-1394 controller (for sane state before initialization) */
+static inline void __init init_ohci1394_soft_reset(struct ti_ohci *ohci) {
+	int i;
+
+	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
+
+	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+		if (!(reg_read(ohci, OHCI1394_HCControlSet)
+				   & OHCI1394_HCControl_softReset))
+			break;
+		mdelay(1);
+	}
+}
+
+/* Basic OHCI-1394 register and port inititalization */
+static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
+{
+	quadlet_t bus_options;
+	int num_ports, i;
+
+	/* Put some defaults to these undefined bus options */
+	bus_options = reg_read(ohci, OHCI1394_BusOptions);
+	bus_options |=  0x60000000; /* Enable CMC and ISC */
+	bus_options &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
+	bus_options &= ~0x18000000; /* Disable PMC and BMC */
+	reg_write(ohci, OHCI1394_BusOptions, bus_options);
+
+	/* Set the bus number */
+	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
+
+	/* Enable posted writes */
+	reg_write(ohci, OHCI1394_HCControlSet,
+			OHCI1394_HCControl_postedWriteEnable);
+
+	/* Clear link control register */
+	reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
+
+	/* enable phys */
+	reg_write(ohci, OHCI1394_LinkControlSet,
+			OHCI1394_LinkControl_RcvPhyPkt);
+
+	/* Don't accept phy packets into AR request context */
+	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
+
+	/* Clear the Isochonouys interrupt masks */
+	reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
+
+	/* Accept asyncronous transfer requests from all nodes for now */
+	reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
+
+	/* Specify asyncronous transfer retries */
+	reg_write(ohci, OHCI1394_ATRetries,
+		  OHCI1394_MAX_AT_REQ_RETRIES |
+		  (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
+		  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
+
+	/* We don't want hardware swapping */
+	reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
+
+	/* Enable link */
+	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
+
+	/* If anything is connected to a port, make sure it is enabled */
+	num_ports = get_phy_reg(ohci, 2) & 0xf;
+	for (i = 0; i < num_ports; i++) {
+		unsigned int status;
+
+		set_phy_reg(ohci, 7, i);
+		status = get_phy_reg(ohci, 8);
+
+		if (status & 0x20)
+			set_phy_reg(ohci, 8, status & ~1);
+	}
+}
+
+/**
+ * init_ohci1394_wait_for_busresets - wait until bus resets are completed
+ *
+ * OHCI1394 initialization itself and any device going on- or offline
+ * and any cable issue cause a IEEE1394 bus reset. The OHCI1394 spec
+ * specifies that physical DMA is disabled on each bus reset and it
+ * has to be enabled after each bus reset when needed. We resort
+ * to polling here because on early boot, we have no interrupts.
+ */
+static inline void __init init_ohci1394_wait_for_busresets(struct ti_ohci *ohci)
+{
+	int i, events;
+
+	for (i=0; i < 9; i++) {
+		mdelay(200);
+		events = reg_read(ohci, OHCI1394_IntEventSet);
+		if (events & OHCI1394_busReset)
+			reg_write(ohci, OHCI1394_IntEventClear,
+					OHCI1394_busReset);
+	}
+}
+
+/**
+ * init_ohci1394_enable_physical_dma - Enable physical DMA for remote debugging
+ * This enables remote DMA access over IEEE1394 from every host for the low
+ * 4GB of address space. DMA accesses above 4GB are not available currently.
+ */
+static inline void __init init_ohci1394_enable_physical_dma(struct ti_ohci *hci)
+{
+	reg_write(hci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
+	reg_write(hci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
+	reg_write(hci, OHCI1394_PhyUpperBound, 0xffff0000);
+}
+
+/**
+ * init_ohci1394_reset_and_init_dma - init controller and enable DMA
+ * This initializes the given controller and enables physical DMA engine in it.
+ */
+static inline void __init init_ohci1394_reset_and_init_dma(struct ti_ohci *ohci)
+{
+	/* Start off with a soft reset, clears everything to a sane state. */
+	init_ohci1394_soft_reset(ohci);
+
+	/* Accessing some registers without LPS enabled may cause lock up */
+	reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
+
+	/* Disable and clear interrupts */
+	reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
+	reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
+
+	mdelay(50); /* Wait 50msec to make sure we have full link enabled */
+
+	init_ohci1394_initialize(ohci);
+	/*
+	 * The initialization causes at least one IEEE1394 bus reset. Enabling
+	 * physical DMA only works *after* *all* bus resets have calmed down:
+	 */
+	init_ohci1394_wait_for_busresets(ohci);
+
+	/* We had to wait and do this now if we want to debug early problems */
+	init_ohci1394_enable_physical_dma(ohci);
+}
+
+/**
+ * init_ohci1394_controller - Map the registers of the controller and init DMA
+ * This maps the registers of the specified controller and initializes it
+ */
+static inline void __init init_ohci1394_controller(int num, int slot, int func)
+{
+	unsigned long ohci_base;
+	struct ti_ohci ohci;
+
+	printk(KERN_INFO "init_ohci1394_dma: initializing OHCI-1394"
+			 " at %02x:%02x.%x\n", num, slot, func);
+
+	ohci_base = read_pci_config(num, slot, func, PCI_BASE_ADDRESS_0+(0<<2))
+						   & PCI_BASE_ADDRESS_MEM_MASK;
+
+	set_fixmap_nocache(FIX_OHCI1394_BASE, ohci_base);
+
+	ohci.registers = (void *)fix_to_virt(FIX_OHCI1394_BASE);
+
+	init_ohci1394_reset_and_init_dma(&ohci);
+}
+
+/**
+ * debug_init_ohci1394_dma - scan for OHCI1394 controllers and init DMA on them
+ * Scans the whole PCI space for OHCI1394 controllers and inits DMA on them
+ */
+void __init init_ohci1394_dma_on_all_controllers(void)
+{
+	int num, slot, func;
+
+	if (!early_pci_allowed())
+		return;
+
+	/* Poor man's PCI discovery, the only thing we can do at early boot */
+	for (num = 0; num < 32; num++) {
+		for (slot = 0; slot < 32; slot++) {
+			for (func = 0; func < 8; func++) {
+				u32 class = read_pci_config(num,slot,func,
+							PCI_CLASS_REVISION);
+				if ((class == 0xffffffff))
+					continue; /* No device at this func */
+
+				if (class>>8 != PCI_CLASS_SERIAL_FIREWIRE_OHCI)
+					continue; /* Not an OHCI-1394 device */
+
+				init_ohci1394_controller(num, slot, func);
+				break; /* Assume one controller per device */
+			}
+		}
+	}
+	printk(KERN_INFO "init_ohci1394_dma: finished initializing OHCI DMA\n");
+}
+
+/**
+ * setup_init_ohci1394_early - enables early OHCI1394 DMA initialization
+ */
+static int __init setup_ohci1394_dma(char *opt)
+{
+	if (!strcmp(opt, "early"))
+		init_ohci1394_dma_early = 1;
+	return 0;
+}
+
+/* passing ohci1394_dma=early on boot causes early OHCI1394 DMA initialization */
+early_param("ohci1394_dma", setup_ohci1394_dma);
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 90dc75be3418..511e4321c6b6 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -727,33 +727,31 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
 
 static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
 
+static int __match_ne(struct device *dev, void *data)
+{
+	struct unit_directory *ud;
+	struct node_entry *ne = (struct node_entry *)data;
+
+	ud = container_of(dev, struct unit_directory, unit_dev);
+	return ud->ne == ne;
+}
+
 static void nodemgr_remove_uds(struct node_entry *ne)
 {
 	struct device *dev;
-	struct unit_directory *tmp, *ud;
-
-	/* Iteration over nodemgr_ud_class.devices has to be protected by
-	 * nodemgr_ud_class.sem, but device_unregister() will eventually
-	 * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time,
-	 * release the semaphore, and then unregister the ud. Since this code
-	 * may be called from other contexts besides the knodemgrds, protect the
-	 * gap after release of the semaphore by nodemgr_serialize_remove_uds.
+	struct unit_directory *ud;
+
+	/* Use class_find device to iterate the devices. Since this code
+	 * may be called from other contexts besides the knodemgrds,
+	 * protect it by nodemgr_serialize_remove_uds.
 	 */
 	mutex_lock(&nodemgr_serialize_remove_uds);
 	for (;;) {
-		ud = NULL;
-		down(&nodemgr_ud_class.sem);
-		list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
-			tmp = container_of(dev, struct unit_directory,
-					   unit_dev);
-			if (tmp->ne == ne) {
-				ud = tmp;
-				break;
-			}
-		}
-		up(&nodemgr_ud_class.sem);
-		if (ud == NULL)
+		dev = class_find_device(&nodemgr_ud_class, ne, __match_ne);
+		if (!dev)
 			break;
+		ud = container_of(dev, struct unit_directory, unit_dev);
+		put_device(dev);
 		device_unregister(&ud->unit_dev);
 		device_unregister(&ud->device);
 	}
@@ -882,45 +880,66 @@ fail_alloc:
 	return NULL;
 }
 
+static int __match_ne_guid(struct device *dev, void *data)
+{
+	struct node_entry *ne;
+	u64 *guid = (u64 *)data;
+
+	ne = container_of(dev, struct node_entry, node_dev);
+	return ne->guid == *guid;
+}
 
 static struct node_entry *find_entry_by_guid(u64 guid)
 {
 	struct device *dev;
-	struct node_entry *ne, *ret_ne = NULL;
-
-	down(&nodemgr_ne_class.sem);
-	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
-		ne = container_of(dev, struct node_entry, node_dev);
+	struct node_entry *ne;
 
-		if (ne->guid == guid) {
-			ret_ne = ne;
-			break;
-		}
-	}
-	up(&nodemgr_ne_class.sem);
+	dev = class_find_device(&nodemgr_ne_class, &guid, __match_ne_guid);
+	if (!dev)
+		return NULL;
+	ne = container_of(dev, struct node_entry, node_dev);
+	put_device(dev);
 
-	return ret_ne;
+	return ne;
 }
 
+struct match_nodeid_param {
+	struct hpsb_host *host;
+	nodeid_t nodeid;
+};
+
+static int __match_ne_nodeid(struct device *dev, void *data)
+{
+	int found = 0;
+	struct node_entry *ne;
+	struct match_nodeid_param *param = (struct match_nodeid_param *)data;
+
+	if (!dev)
+		goto ret;
+	ne = container_of(dev, struct node_entry, node_dev);
+	if (ne->host == param->host && ne->nodeid == param->nodeid)
+		found = 1;
+ret:
+	return found;
+}
 
 static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
 					       nodeid_t nodeid)
 {
 	struct device *dev;
-	struct node_entry *ne, *ret_ne = NULL;
+	struct node_entry *ne;
+	struct match_nodeid_param param;
 
-	down(&nodemgr_ne_class.sem);
-	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
-		ne = container_of(dev, struct node_entry, node_dev);
+	param.host = host;
+	param.nodeid = nodeid;
 
-		if (ne->host == host && ne->nodeid == nodeid) {
-			ret_ne = ne;
-			break;
-		}
-	}
-	up(&nodemgr_ne_class.sem);
+	dev = class_find_device(&nodemgr_ne_class, &param, __match_ne_nodeid);
+	if (!dev)
+		return NULL;
+	ne = container_of(dev, struct node_entry, node_dev);
+	put_device(dev);
 
-	return ret_ne;
+	return ne;
 }
 
 
@@ -1370,107 +1389,109 @@ static void nodemgr_node_scan(struct host_info *hi, int generation)
 	}
 }
 
-
-static void nodemgr_suspend_ne(struct node_entry *ne)
+static int __nodemgr_driver_suspend(struct device *dev, void *data)
 {
-	struct device *dev;
 	struct unit_directory *ud;
 	struct device_driver *drv;
+	struct node_entry *ne = (struct node_entry *)data;
 	int error;
 
-	HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
-		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
+	ud = container_of(dev, struct unit_directory, unit_dev);
+	if (ud->ne == ne) {
+		drv = get_driver(ud->device.driver);
+		if (drv) {
+			error = 1; /* release if suspend is not implemented */
+			if (drv->suspend) {
+				down(&ud->device.sem);
+				error = drv->suspend(&ud->device, PMSG_SUSPEND);
+				up(&ud->device.sem);
+			}
+			if (error)
+				device_release_driver(&ud->device);
+			put_driver(drv);
+		}
+	}
 
-	ne->in_limbo = 1;
-	WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
+	return 0;
+}
 
-	down(&nodemgr_ud_class.sem);
-	list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
-		ud = container_of(dev, struct unit_directory, unit_dev);
-		if (ud->ne != ne)
-			continue;
+static int __nodemgr_driver_resume(struct device *dev, void *data)
+{
+	struct unit_directory *ud;
+	struct device_driver *drv;
+	struct node_entry *ne = (struct node_entry *)data;
 
+	ud = container_of(dev, struct unit_directory, unit_dev);
+	if (ud->ne == ne) {
 		drv = get_driver(ud->device.driver);
-		if (!drv)
-			continue;
-
-		error = 1; /* release if suspend is not implemented */
-		if (drv->suspend) {
-			down(&ud->device.sem);
-			error = drv->suspend(&ud->device, PMSG_SUSPEND);
-			up(&ud->device.sem);
+		if (drv) {
+			if (drv->resume) {
+				down(&ud->device.sem);
+				drv->resume(&ud->device);
+				up(&ud->device.sem);
+			}
+			put_driver(drv);
 		}
-		if (error)
-			device_release_driver(&ud->device);
-		put_driver(drv);
 	}
-	up(&nodemgr_ud_class.sem);
-}
 
+	return 0;
+}
 
-static void nodemgr_resume_ne(struct node_entry *ne)
+static void nodemgr_suspend_ne(struct node_entry *ne)
 {
-	struct device *dev;
-	struct unit_directory *ud;
-	struct device_driver *drv;
+	HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
+		   NODE_BUS_ARGS(ne->host, ne->nodeid),
+		   (unsigned long long)ne->guid);
 
-	ne->in_limbo = 0;
-	device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
+	ne->in_limbo = 1;
+	WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
 
-	down(&nodemgr_ud_class.sem);
-	list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
-		ud = container_of(dev, struct unit_directory, unit_dev);
-		if (ud->ne != ne)
-			continue;
+	class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_suspend);
+}
 
-		drv = get_driver(ud->device.driver);
-		if (!drv)
-			continue;
 
-		if (drv->resume) {
-			down(&ud->device.sem);
-			drv->resume(&ud->device);
-			up(&ud->device.sem);
-		}
-		put_driver(drv);
-	}
-	up(&nodemgr_ud_class.sem);
+static void nodemgr_resume_ne(struct node_entry *ne)
+{
+	ne->in_limbo = 0;
+	device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
 
+	class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_resume);
 	HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
 		   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
 }
 
-
-static void nodemgr_update_pdrv(struct node_entry *ne)
+static int __nodemgr_update_pdrv(struct device *dev, void *data)
 {
-	struct device *dev;
 	struct unit_directory *ud;
 	struct device_driver *drv;
 	struct hpsb_protocol_driver *pdrv;
+	struct node_entry *ne = (struct node_entry *)data;
 	int error;
 
-	down(&nodemgr_ud_class.sem);
-	list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
-		ud = container_of(dev, struct unit_directory, unit_dev);
-		if (ud->ne != ne)
-			continue;
-
+	ud = container_of(dev, struct unit_directory, unit_dev);
+	if (ud->ne == ne) {
 		drv = get_driver(ud->device.driver);
-		if (!drv)
-			continue;
-
-		error = 0;
-		pdrv = container_of(drv, struct hpsb_protocol_driver, driver);
-		if (pdrv->update) {
-			down(&ud->device.sem);
-			error = pdrv->update(ud);
-			up(&ud->device.sem);
+		if (drv) {
+			error = 0;
+			pdrv = container_of(drv, struct hpsb_protocol_driver,
+					    driver);
+			if (pdrv->update) {
+				down(&ud->device.sem);
+				error = pdrv->update(ud);
+				up(&ud->device.sem);
+			}
+			if (error)
+				device_release_driver(&ud->device);
+			put_driver(drv);
 		}
-		if (error)
-			device_release_driver(&ud->device);
-		put_driver(drv);
 	}
-	up(&nodemgr_ud_class.sem);
+
+	return 0;
+}
+
+static void nodemgr_update_pdrv(struct node_entry *ne)
+{
+	class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_update_pdrv);
 }
 
 
@@ -1529,13 +1550,31 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge
 	put_device(dev);
 }
 
+struct probe_param {
+	struct host_info *hi;
+	int generation;
+};
+
+static int __nodemgr_node_probe(struct device *dev, void *data)
+{
+	struct probe_param *param = (struct probe_param *)data;
+	struct node_entry *ne;
+
+	ne = container_of(dev, struct node_entry, node_dev);
+	if (!ne->needs_probe)
+		nodemgr_probe_ne(param->hi, ne, param->generation);
+	if (ne->needs_probe)
+		nodemgr_probe_ne(param->hi, ne, param->generation);
+	return 0;
+}
 
 static void nodemgr_node_probe(struct host_info *hi, int generation)
 {
 	struct hpsb_host *host = hi->host;
-	struct device *dev;
-	struct node_entry *ne;
+	struct probe_param param;
 
+	param.hi = hi;
+	param.generation = generation;
 	/* Do some processing of the nodes we've probed. This pulls them
 	 * into the sysfs layer if needed, and can result in processing of
 	 * unit-directories, or just updating the node and it's
@@ -1545,19 +1584,7 @@ static void nodemgr_node_probe(struct host_info *hi, int generation)
 	 * while probes are time-consuming. (Well, those probes need some
 	 * improvement...) */
 
-	down(&nodemgr_ne_class.sem);
-	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
-		ne = container_of(dev, struct node_entry, node_dev);
-		if (!ne->needs_probe)
-			nodemgr_probe_ne(hi, ne, generation);
-	}
-	list_for_each_entry(dev, &nodemgr_ne_class.devices, node) {
-		ne = container_of(dev, struct node_entry, node_dev);
-		if (ne->needs_probe)
-			nodemgr_probe_ne(hi, ne, generation);
-	}
-	up(&nodemgr_ne_class.sem);
-
+	class_for_each_device(&nodemgr_ne_class, &param, __nodemgr_node_probe);
 
 	/* If we had a bus reset while we were scanning the bus, it is
 	 * possible that we did not probe all nodes.  In that case, we
@@ -1757,6 +1784,22 @@ exit:
 	return 0;
 }
 
+struct host_iter_param {
+	void *data;
+	int (*cb)(struct hpsb_host *, void *);
+};
+
+static int __nodemgr_for_each_host(struct device *dev, void *data)
+{
+	struct hpsb_host *host;
+	struct host_iter_param *hip = (struct host_iter_param *)data;
+	int error = 0;
+
+	host = container_of(dev, struct hpsb_host, host_dev);
+	error = hip->cb(host, hip->data);
+
+	return error;
+}
 /**
  * nodemgr_for_each_host - call a function for each IEEE 1394 host
  * @data: an address to supply to the callback
@@ -1771,18 +1814,13 @@ exit:
  */
 int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
 {
-	struct device *dev;
-	struct hpsb_host *host;
-	int error = 0;
-
-	down(&hpsb_host_class.sem);
-	list_for_each_entry(dev, &hpsb_host_class.devices, node) {
-		host = container_of(dev, struct hpsb_host, host_dev);
+	struct host_iter_param hip;
+	int error;
 
-		if ((error = cb(host, data)))
-			break;
-	}
-	up(&hpsb_host_class.sem);
+	hip.cb = cb;
+	hip.data = data;
+	error = class_for_each_device(&hpsb_host_class, &hip,
+				      __nodemgr_for_each_host);
 
 	return error;
 }
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index b83d254bc86e..1eda11abeb1e 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -1963,6 +1963,12 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
 	lu->sdev = sdev;
 	sdev->allow_restart = 1;
 
+	/*
+	 * Update the dma alignment (minimum alignment requirements for
+	 * start and end of DMA transfers) to be a sector
+	 */
+	blk_queue_update_dma_alignment(sdev->request_queue, 511);
+
 	if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36)
 		sdev->inquiry_len = 36;
 	return 0;
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 5381c80de10a..a58ad8a470f9 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -110,7 +110,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
 	__be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
 	int ret;
 
-	dev = ip_dev_find(ip);
+	dev = ip_dev_find(&init_net, ip);
 	if (!dev)
 		return -EADDRNOTAVAIL;
 
@@ -158,7 +158,7 @@ static void addr_send_arp(struct sockaddr_in *dst_in)
 
 	memset(&fl, 0, sizeof fl);
 	fl.nl_u.ip4_u.daddr = dst_ip;
-	if (ip_route_output_key(&rt, &fl))
+	if (ip_route_output_key(&init_net, &rt, &fl))
 		return;
 
 	neigh_event_send(rt->u.dst.neighbour, NULL);
@@ -179,7 +179,7 @@ static int addr_resolve_remote(struct sockaddr_in *src_in,
 	memset(&fl, 0, sizeof fl);
 	fl.nl_u.ip4_u.daddr = dst_ip;
 	fl.nl_u.ip4_u.saddr = src_ip;
-	ret = ip_route_output_key(&rt, &fl);
+	ret = ip_route_output_key(&init_net, &rt, &fl);
 	if (ret)
 		goto out;
 
@@ -261,15 +261,15 @@ static int addr_resolve_local(struct sockaddr_in *src_in,
 	__be32 dst_ip = dst_in->sin_addr.s_addr;
 	int ret;
 
-	dev = ip_dev_find(dst_ip);
+	dev = ip_dev_find(&init_net, dst_ip);
 	if (!dev)
 		return -EADDRNOTAVAIL;
 
-	if (ZERONET(src_ip)) {
+	if (ipv4_is_zeronet(src_ip)) {
 		src_in->sin_family = dst_in->sin_family;
 		src_in->sin_addr.s_addr = dst_ip;
 		ret = rdma_copy_addr(addr, dev, dev->dev_addr);
-	} else if (LOOPBACK(src_ip)) {
+	} else if (ipv4_is_loopback(src_ip)) {
 		ret = rdma_translate_ip((struct sockaddr *)dst_in, addr);
 		if (!ret)
 			memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN);
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 2e39236d189f..c0150147d347 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2006 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2004-2007 Intel Corporation.  All rights reserved.
  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
  * Copyright (c) 2004, 2005 Voltaire Corporation.  All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
@@ -37,12 +37,14 @@
 
 #include <linux/completion.h>
 #include <linux/dma-mapping.h>
+#include <linux/device.h>
 #include <linux/err.h>
 #include <linux/idr.h>
 #include <linux/interrupt.h>
 #include <linux/random.h>
 #include <linux/rbtree.h>
 #include <linux/spinlock.h>
+#include <linux/sysfs.h>
 #include <linux/workqueue.h>
 
 #include <rdma/ib_cache.h>
@@ -78,17 +80,94 @@ static struct ib_cm {
 	struct workqueue_struct *wq;
 } cm;
 
+/* Counter indexes ordered by attribute ID */
+enum {
+	CM_REQ_COUNTER,
+	CM_MRA_COUNTER,
+	CM_REJ_COUNTER,
+	CM_REP_COUNTER,
+	CM_RTU_COUNTER,
+	CM_DREQ_COUNTER,
+	CM_DREP_COUNTER,
+	CM_SIDR_REQ_COUNTER,
+	CM_SIDR_REP_COUNTER,
+	CM_LAP_COUNTER,
+	CM_APR_COUNTER,
+	CM_ATTR_COUNT,
+	CM_ATTR_ID_OFFSET = 0x0010,
+};
+
+enum {
+	CM_XMIT,
+	CM_XMIT_RETRIES,
+	CM_RECV,
+	CM_RECV_DUPLICATES,
+	CM_COUNTER_GROUPS
+};
+
+static char const counter_group_names[CM_COUNTER_GROUPS]
+				     [sizeof("cm_rx_duplicates")] = {
+	"cm_tx_msgs", "cm_tx_retries",
+	"cm_rx_msgs", "cm_rx_duplicates"
+};
+
+struct cm_counter_group {
+	struct kobject obj;
+	atomic_long_t counter[CM_ATTR_COUNT];
+};
+
+struct cm_counter_attribute {
+	struct attribute attr;
+	int index;
+};
+
+#define CM_COUNTER_ATTR(_name, _index) \
+struct cm_counter_attribute cm_##_name##_counter_attr = { \
+	.attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \
+	.index = _index \
+}
+
+static CM_COUNTER_ATTR(req, CM_REQ_COUNTER);
+static CM_COUNTER_ATTR(mra, CM_MRA_COUNTER);
+static CM_COUNTER_ATTR(rej, CM_REJ_COUNTER);
+static CM_COUNTER_ATTR(rep, CM_REP_COUNTER);
+static CM_COUNTER_ATTR(rtu, CM_RTU_COUNTER);
+static CM_COUNTER_ATTR(dreq, CM_DREQ_COUNTER);
+static CM_COUNTER_ATTR(drep, CM_DREP_COUNTER);
+static CM_COUNTER_ATTR(sidr_req, CM_SIDR_REQ_COUNTER);
+static CM_COUNTER_ATTR(sidr_rep, CM_SIDR_REP_COUNTER);
+static CM_COUNTER_ATTR(lap, CM_LAP_COUNTER);
+static CM_COUNTER_ATTR(apr, CM_APR_COUNTER);
+
+static struct attribute *cm_counter_default_attrs[] = {
+	&cm_req_counter_attr.attr,
+	&cm_mra_counter_attr.attr,
+	&cm_rej_counter_attr.attr,
+	&cm_rep_counter_attr.attr,
+	&cm_rtu_counter_attr.attr,
+	&cm_dreq_counter_attr.attr,
+	&cm_drep_counter_attr.attr,
+	&cm_sidr_req_counter_attr.attr,
+	&cm_sidr_rep_counter_attr.attr,
+	&cm_lap_counter_attr.attr,
+	&cm_apr_counter_attr.attr,
+	NULL
+};
+
 struct cm_port {
 	struct cm_device *cm_dev;
 	struct ib_mad_agent *mad_agent;
+	struct kobject port_obj;
 	u8 port_num;
+	struct cm_counter_group counter_group[CM_COUNTER_GROUPS];
 };
 
 struct cm_device {
 	struct list_head list;
 	struct ib_device *device;
+	struct kobject dev_obj;
 	u8 ack_delay;
-	struct cm_port port[0];
+	struct cm_port *port[0];
 };
 
 struct cm_av {
@@ -278,7 +357,7 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
 	list_for_each_entry(cm_dev, &cm.device_list, list) {
 		if (!ib_find_cached_gid(cm_dev->device, &path->sgid,
 					&p, NULL)) {
-			port = &cm_dev->port[p-1];
+			port = cm_dev->port[p-1];
 			break;
 		}
 	}
@@ -1270,6 +1349,9 @@ static void cm_dup_req_handler(struct cm_work *work,
 	struct ib_mad_send_buf *msg = NULL;
 	int ret;
 
+	atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+			counter[CM_REQ_COUNTER]);
+
 	/* Quick state check to discard duplicate REQs. */
 	if (cm_id_priv->id.state == IB_CM_REQ_RCVD)
 		return;
@@ -1616,6 +1698,8 @@ static void cm_dup_rep_handler(struct cm_work *work)
 	if (!cm_id_priv)
 		return;
 
+	atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+			counter[CM_REP_COUNTER]);
 	ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg);
 	if (ret)
 		goto deref;
@@ -1781,6 +1865,8 @@ static int cm_rtu_handler(struct cm_work *work)
 	if (cm_id_priv->id.state != IB_CM_REP_SENT &&
 	    cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) {
 		spin_unlock_irq(&cm_id_priv->lock);
+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+				counter[CM_RTU_COUNTER]);
 		goto out;
 	}
 	cm_id_priv->id.state = IB_CM_ESTABLISHED;
@@ -1958,6 +2044,8 @@ static int cm_dreq_handler(struct cm_work *work)
 	cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id,
 				   dreq_msg->local_comm_id);
 	if (!cm_id_priv) {
+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+				counter[CM_DREQ_COUNTER]);
 		cm_issue_drep(work->port, work->mad_recv_wc);
 		return -EINVAL;
 	}
@@ -1977,6 +2065,8 @@ static int cm_dreq_handler(struct cm_work *work)
 	case IB_CM_MRA_REP_RCVD:
 		break;
 	case IB_CM_TIMEWAIT:
+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+				counter[CM_DREQ_COUNTER]);
 		if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
 			goto unlock;
 
@@ -1988,6 +2078,10 @@ static int cm_dreq_handler(struct cm_work *work)
 		if (ib_post_send_mad(msg, NULL))
 			cm_free_msg(msg);
 		goto deref;
+	case IB_CM_DREQ_RCVD:
+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+				counter[CM_DREQ_COUNTER]);
+		goto unlock;
 	default:
 		goto unlock;
 	}
@@ -2339,10 +2433,20 @@ static int cm_mra_handler(struct cm_work *work)
 		if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER ||
 		    cm_id_priv->id.lap_state != IB_CM_LAP_SENT ||
 		    ib_modify_mad(cm_id_priv->av.port->mad_agent,
-				  cm_id_priv->msg, timeout))
+				  cm_id_priv->msg, timeout)) {
+			if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD)
+				atomic_long_inc(&work->port->
+						counter_group[CM_RECV_DUPLICATES].
+						counter[CM_MRA_COUNTER]);
 			goto out;
+		}
 		cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD;
 		break;
+	case IB_CM_MRA_REQ_RCVD:
+	case IB_CM_MRA_REP_RCVD:
+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+				counter[CM_MRA_COUNTER]);
+		/* fall through */
 	default:
 		goto out;
 	}
@@ -2502,6 +2606,8 @@ static int cm_lap_handler(struct cm_work *work)
 	case IB_CM_LAP_IDLE:
 		break;
 	case IB_CM_MRA_LAP_SENT:
+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+				counter[CM_LAP_COUNTER]);
 		if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg))
 			goto unlock;
 
@@ -2515,6 +2621,10 @@ static int cm_lap_handler(struct cm_work *work)
 		if (ib_post_send_mad(msg, NULL))
 			cm_free_msg(msg);
 		goto deref;
+	case IB_CM_LAP_RCVD:
+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+				counter[CM_LAP_COUNTER]);
+		goto unlock;
 	default:
 		goto unlock;
 	}
@@ -2796,6 +2906,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
 	cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv);
 	if (cur_cm_id_priv) {
 		spin_unlock_irq(&cm.lock);
+		atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES].
+				counter[CM_SIDR_REQ_COUNTER]);
 		goto out; /* Duplicate message. */
 	}
 	cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
@@ -2990,6 +3102,27 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent,
 			    struct ib_mad_send_wc *mad_send_wc)
 {
 	struct ib_mad_send_buf *msg = mad_send_wc->send_buf;
+	struct cm_port *port;
+	u16 attr_index;
+
+	port = mad_agent->context;
+	attr_index = be16_to_cpu(((struct ib_mad_hdr *)
+				  msg->mad)->attr_id) - CM_ATTR_ID_OFFSET;
+
+	/*
+	 * If the send was in response to a received message (context[0] is not
+	 * set to a cm_id), and is not a REJ, then it is a send that was
+	 * manually retried.
+	 */
+	if (!msg->context[0] && (attr_index != CM_REJ_COUNTER))
+		msg->retries = 1;
+
+	atomic_long_add(1 + msg->retries,
+			&port->counter_group[CM_XMIT].counter[attr_index]);
+	if (msg->retries)
+		atomic_long_add(msg->retries,
+				&port->counter_group[CM_XMIT_RETRIES].
+				counter[attr_index]);
 
 	switch (mad_send_wc->status) {
 	case IB_WC_SUCCESS:
@@ -3148,8 +3281,10 @@ EXPORT_SYMBOL(ib_cm_notify);
 static void cm_recv_handler(struct ib_mad_agent *mad_agent,
 			    struct ib_mad_recv_wc *mad_recv_wc)
 {
+	struct cm_port *port = mad_agent->context;
 	struct cm_work *work;
 	enum ib_cm_event_type event;
+	u16 attr_id;
 	int paths = 0;
 
 	switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) {
@@ -3194,6 +3329,10 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
 		return;
 	}
 
+	attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id);
+	atomic_long_inc(&port->counter_group[CM_RECV].
+			counter[attr_id - CM_ATTR_ID_OFFSET]);
+
 	work = kmalloc(sizeof *work + sizeof(struct ib_sa_path_rec) * paths,
 		       GFP_KERNEL);
 	if (!work) {
@@ -3204,7 +3343,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent,
 	INIT_DELAYED_WORK(&work->work, cm_work_handler);
 	work->cm_event.event = event;
 	work->mad_recv_wc = mad_recv_wc;
-	work->port = (struct cm_port *)mad_agent->context;
+	work->port = port;
 	queue_delayed_work(cm.wq, &work->work, 0);
 }
 
@@ -3379,6 +3518,108 @@ static void cm_get_ack_delay(struct cm_device *cm_dev)
 		cm_dev->ack_delay = attr.local_ca_ack_delay;
 }
 
+static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr,
+			       char *buf)
+{
+	struct cm_counter_group *group;
+	struct cm_counter_attribute *cm_attr;
+
+	group = container_of(obj, struct cm_counter_group, obj);
+	cm_attr = container_of(attr, struct cm_counter_attribute, attr);
+
+	return sprintf(buf, "%ld\n",
+		       atomic_long_read(&group->counter[cm_attr->index]));
+}
+
+static struct sysfs_ops cm_counter_ops = {
+	.show = cm_show_counter
+};
+
+static struct kobj_type cm_counter_obj_type = {
+	.sysfs_ops = &cm_counter_ops,
+	.default_attrs = cm_counter_default_attrs
+};
+
+static void cm_release_port_obj(struct kobject *obj)
+{
+	struct cm_port *cm_port;
+
+	printk(KERN_ERR "free cm port\n");
+
+	cm_port = container_of(obj, struct cm_port, port_obj);
+	kfree(cm_port);
+}
+
+static struct kobj_type cm_port_obj_type = {
+	.release = cm_release_port_obj
+};
+
+static void cm_release_dev_obj(struct kobject *obj)
+{
+	struct cm_device *cm_dev;
+
+	printk(KERN_ERR "free cm dev\n");
+
+	cm_dev = container_of(obj, struct cm_device, dev_obj);
+	kfree(cm_dev);
+}
+
+static struct kobj_type cm_dev_obj_type = {
+	.release = cm_release_dev_obj
+};
+
+struct class cm_class = {
+	.name    = "infiniband_cm",
+};
+EXPORT_SYMBOL(cm_class);
+
+static void cm_remove_fs_obj(struct kobject *obj)
+{
+	kobject_put(obj->parent);
+	kobject_put(obj);
+}
+
+static int cm_create_port_fs(struct cm_port *port)
+{
+	int i, ret;
+
+	ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type,
+				   kobject_get(&port->cm_dev->dev_obj),
+				   "%d", port->port_num);
+	if (ret) {
+		kfree(port);
+		return ret;
+	}
+
+	for (i = 0; i < CM_COUNTER_GROUPS; i++) {
+		ret = kobject_init_and_add(&port->counter_group[i].obj,
+					   &cm_counter_obj_type,
+					   kobject_get(&port->port_obj),
+					   "%s", counter_group_names[i]);
+		if (ret)
+			goto error;
+	}
+
+	return 0;
+
+error:
+	while (i--)
+		cm_remove_fs_obj(&port->counter_group[i].obj);
+	cm_remove_fs_obj(&port->port_obj);
+	return ret;
+
+}
+
+static void cm_remove_port_fs(struct cm_port *port)
+{
+	int i;
+
+	for (i = 0; i < CM_COUNTER_GROUPS; i++)
+		cm_remove_fs_obj(&port->counter_group[i].obj);
+
+	cm_remove_fs_obj(&port->port_obj);
+}
+
 static void cm_add_one(struct ib_device *device)
 {
 	struct cm_device *cm_dev;
@@ -3397,7 +3638,7 @@ static void cm_add_one(struct ib_device *device)
 	if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
 		return;
 
-	cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) *
+	cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) *
 			 device->phys_port_cnt, GFP_KERNEL);
 	if (!cm_dev)
 		return;
@@ -3405,11 +3646,27 @@ static void cm_add_one(struct ib_device *device)
 	cm_dev->device = device;
 	cm_get_ack_delay(cm_dev);
 
+	ret = kobject_init_and_add(&cm_dev->dev_obj, &cm_dev_obj_type,
+				   &cm_class.subsys.kobj, "%s", device->name);
+	if (ret) {
+		kfree(cm_dev);
+		return;
+	}
+
 	set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
 	for (i = 1; i <= device->phys_port_cnt; i++) {
-		port = &cm_dev->port[i-1];
+		port = kzalloc(sizeof *port, GFP_KERNEL);
+		if (!port)
+			goto error1;
+
+		cm_dev->port[i-1] = port;
 		port->cm_dev = cm_dev;
 		port->port_num = i;
+
+		ret = cm_create_port_fs(port);
+		if (ret)
+			goto error1;
+
 		port->mad_agent = ib_register_mad_agent(device, i,
 							IB_QPT_GSI,
 							&reg_req,
@@ -3418,11 +3675,11 @@ static void cm_add_one(struct ib_device *device)
 							cm_recv_handler,
 							port);
 		if (IS_ERR(port->mad_agent))
-			goto error1;
+			goto error2;
 
 		ret = ib_modify_port(device, i, 0, &port_modify);
 		if (ret)
-			goto error2;
+			goto error3;
 	}
 	ib_set_client_data(device, &cm_client, cm_dev);
 
@@ -3431,17 +3688,20 @@ static void cm_add_one(struct ib_device *device)
 	write_unlock_irqrestore(&cm.device_lock, flags);
 	return;
 
-error2:
+error3:
 	ib_unregister_mad_agent(port->mad_agent);
+error2:
+	cm_remove_port_fs(port);
 error1:
 	port_modify.set_port_cap_mask = 0;
 	port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
 	while (--i) {
-		port = &cm_dev->port[i-1];
+		port = cm_dev->port[i-1];
 		ib_modify_port(device, port->port_num, 0, &port_modify);
 		ib_unregister_mad_agent(port->mad_agent);
+		cm_remove_port_fs(port);
 	}
-	kfree(cm_dev);
+	cm_remove_fs_obj(&cm_dev->dev_obj);
 }
 
 static void cm_remove_one(struct ib_device *device)
@@ -3463,11 +3723,12 @@ static void cm_remove_one(struct ib_device *device)
 	write_unlock_irqrestore(&cm.device_lock, flags);
 
 	for (i = 1; i <= device->phys_port_cnt; i++) {
-		port = &cm_dev->port[i-1];
+		port = cm_dev->port[i-1];
 		ib_modify_port(device, port->port_num, 0, &port_modify);
 		ib_unregister_mad_agent(port->mad_agent);
+		cm_remove_port_fs(port);
 	}
-	kfree(cm_dev);
+	cm_remove_fs_obj(&cm_dev->dev_obj);
 }
 
 static int __init ib_cm_init(void)
@@ -3488,17 +3749,25 @@ static int __init ib_cm_init(void)
 	idr_pre_get(&cm.local_id_table, GFP_KERNEL);
 	INIT_LIST_HEAD(&cm.timewait_list);
 
-	cm.wq = create_workqueue("ib_cm");
-	if (!cm.wq)
+	ret = class_register(&cm_class);
+	if (ret)
 		return -ENOMEM;
 
+	cm.wq = create_workqueue("ib_cm");
+	if (!cm.wq) {
+		ret = -ENOMEM;
+		goto error1;
+	}
+
 	ret = ib_register_client(&cm_client);
 	if (ret)
-		goto error;
+		goto error2;
 
 	return 0;
-error:
+error2:
 	destroy_workqueue(cm.wq);
+error1:
+	class_unregister(&cm_class);
 	return ret;
 }
 
@@ -3519,6 +3788,7 @@ static void __exit ib_cm_cleanup(void)
 	}
 
 	ib_unregister_client(&cm_client);
+	class_unregister(&cm_class);
 	idr_destroy(&cm.local_id_table);
 }
 
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 0751697ef984..1eff1b2c0e08 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -488,7 +488,8 @@ void rdma_destroy_qp(struct rdma_cm_id *id)
 }
 EXPORT_SYMBOL(rdma_destroy_qp);
 
-static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
+static int cma_modify_qp_rtr(struct rdma_id_private *id_priv,
+			     struct rdma_conn_param *conn_param)
 {
 	struct ib_qp_attr qp_attr;
 	int qp_attr_mask, ret;
@@ -514,13 +515,16 @@ static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
 	if (ret)
 		goto out;
 
+	if (conn_param)
+		qp_attr.max_dest_rd_atomic = conn_param->responder_resources;
 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
 out:
 	mutex_unlock(&id_priv->qp_mutex);
 	return ret;
 }
 
-static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
+static int cma_modify_qp_rts(struct rdma_id_private *id_priv,
+			     struct rdma_conn_param *conn_param)
 {
 	struct ib_qp_attr qp_attr;
 	int qp_attr_mask, ret;
@@ -536,6 +540,8 @@ static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
 	if (ret)
 		goto out;
 
+	if (conn_param)
+		qp_attr.max_rd_atomic = conn_param->initiator_depth;
 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
 out:
 	mutex_unlock(&id_priv->qp_mutex);
@@ -624,7 +630,8 @@ static inline int cma_zero_addr(struct sockaddr *addr)
 	struct in6_addr *ip6;
 
 	if (addr->sa_family == AF_INET)
-		return ZERONET(((struct sockaddr_in *) addr)->sin_addr.s_addr);
+		return ipv4_is_zeronet(
+			((struct sockaddr_in *)addr)->sin_addr.s_addr);
 	else {
 		ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
 		return (ip6->s6_addr32[0] | ip6->s6_addr32[1] |
@@ -634,7 +641,7 @@ static inline int cma_zero_addr(struct sockaddr *addr)
 
 static inline int cma_loopback_addr(struct sockaddr *addr)
 {
-	return LOOPBACK(((struct sockaddr_in *) addr)->sin_addr.s_addr);
+	return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr);
 }
 
 static inline int cma_any_addr(struct sockaddr *addr)
@@ -866,11 +873,11 @@ static int cma_rep_recv(struct rdma_id_private *id_priv)
 {
 	int ret;
 
-	ret = cma_modify_qp_rtr(id_priv);
+	ret = cma_modify_qp_rtr(id_priv, NULL);
 	if (ret)
 		goto reject;
 
-	ret = cma_modify_qp_rts(id_priv);
+	ret = cma_modify_qp_rts(id_priv, NULL);
 	if (ret)
 		goto reject;
 
@@ -1122,8 +1129,10 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
 	cm_id->cm_handler = cma_ib_handler;
 
 	ret = conn_id->id.event_handler(&conn_id->id, &event);
-	if (!ret)
+	if (!ret) {
+		cma_enable_remove(conn_id);
 		goto out;
+	}
 
 	/* Destroy the CM ID by returning a non-zero value. */
 	conn_id->cm_id.ib = NULL;
@@ -1262,6 +1271,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
 	struct net_device *dev = NULL;
 	struct rdma_cm_event event;
 	int ret;
+	struct ib_device_attr attr;
 
 	listen_id = cm_id->context;
 	if (cma_disable_remove(listen_id, CMA_LISTEN))
@@ -1279,7 +1289,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
 	atomic_inc(&conn_id->dev_remove);
 	conn_id->state = CMA_CONNECT;
 
-	dev = ip_dev_find(iw_event->local_addr.sin_addr.s_addr);
+	dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr);
 	if (!dev) {
 		ret = -EADDRNOTAVAIL;
 		cma_enable_remove(conn_id);
@@ -1311,10 +1321,19 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
 	sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
 	*sin = iw_event->remote_addr;
 
+	ret = ib_query_device(conn_id->id.device, &attr);
+	if (ret) {
+		cma_enable_remove(conn_id);
+		rdma_destroy_id(new_cm_id);
+		goto out;
+	}
+
 	memset(&event, 0, sizeof event);
 	event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
 	event.param.conn.private_data = iw_event->private_data;
 	event.param.conn.private_data_len = iw_event->private_data_len;
+	event.param.conn.initiator_depth = attr.max_qp_init_rd_atom;
+	event.param.conn.responder_resources = attr.max_qp_rd_atom;
 	ret = conn_id->id.event_handler(&conn_id->id, &event);
 	if (ret) {
 		/* User wants to destroy the CM ID */
@@ -2272,7 +2291,7 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
 	sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
 	cm_id->remote_addr = *sin;
 
-	ret = cma_modify_qp_rtr(id_priv);
+	ret = cma_modify_qp_rtr(id_priv, conn_param);
 	if (ret)
 		goto out;
 
@@ -2335,25 +2354,15 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
 			 struct rdma_conn_param *conn_param)
 {
 	struct ib_cm_rep_param rep;
-	struct ib_qp_attr qp_attr;
-	int qp_attr_mask, ret;
-
-	if (id_priv->id.qp) {
-		ret = cma_modify_qp_rtr(id_priv);
-		if (ret)
-			goto out;
+	int ret;
 
-		qp_attr.qp_state = IB_QPS_RTS;
-		ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, &qp_attr,
-					 &qp_attr_mask);
-		if (ret)
-			goto out;
+	ret = cma_modify_qp_rtr(id_priv, conn_param);
+	if (ret)
+		goto out;
 
-		qp_attr.max_rd_atomic = conn_param->initiator_depth;
-		ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
-		if (ret)
-			goto out;
-	}
+	ret = cma_modify_qp_rts(id_priv, conn_param);
+	if (ret)
+		goto out;
 
 	memset(&rep, 0, sizeof rep);
 	rep.qp_num = id_priv->qp_num;
@@ -2378,7 +2387,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
 	struct iw_cm_conn_param iw_param;
 	int ret;
 
-	ret = cma_modify_qp_rtr(id_priv);
+	ret = cma_modify_qp_rtr(id_priv, conn_param);
 	if (ret)
 		return ret;
 
@@ -2598,11 +2607,9 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
 		/* IPv6 address is an SA assigned MGID. */
 		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
 	} else {
-		ip_ib_mc_map(sin->sin_addr.s_addr, mc_map);
+		ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
 		if (id_priv->id.ps == RDMA_PS_UDP)
 			mc_map[7] = 0x01;	/* Use RDMA CM signature */
-		mc_map[8] = ib_addr_get_pkey(dev_addr) >> 8;
-		mc_map[9] = (unsigned char) ib_addr_get_pkey(dev_addr);
 		*mgid = *(union ib_gid *) (mc_map + 4);
 	}
 }
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index e8d5f6b64998..6c7aa59794d4 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -139,7 +139,7 @@ static inline struct ib_pool_fmr *ib_fmr_cache_lookup(struct ib_fmr_pool *pool,
 static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
 {
 	int                 ret;
-	struct ib_pool_fmr *fmr;
+	struct ib_pool_fmr *fmr, *next;
 	LIST_HEAD(unmap_list);
 	LIST_HEAD(fmr_list);
 
@@ -158,6 +158,20 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
 #endif
 	}
 
+	/*
+	 * The free_list may hold FMRs that have been put there
+	 * because they haven't reached the max_remap count.
+	 * Invalidate their mapping as well.
+	 */
+	list_for_each_entry_safe(fmr, next, &pool->free_list, list) {
+		if (fmr->remap_count == 0)
+			continue;
+		hlist_del_init(&fmr->cache_node);
+		fmr->remap_count = 0;
+		list_add_tail(&fmr->fmr->list, &fmr_list);
+		list_move(&fmr->list, &unmap_list);
+	}
+
 	list_splice(&pool->dirty_list, &unmap_list);
 	INIT_LIST_HEAD(&pool->dirty_list);
 	pool->dirty_len = 0;
@@ -182,8 +196,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
 	struct ib_fmr_pool *pool = pool_ptr;
 
 	do {
-		if (pool->dirty_len >= pool->dirty_watermark ||
-		    atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
+		if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) {
 			ib_fmr_batch_release(pool);
 
 			atomic_inc(&pool->flush_ser);
@@ -194,8 +207,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr)
 		}
 
 		set_current_state(TASK_INTERRUPTIBLE);
-		if (pool->dirty_len < pool->dirty_watermark &&
-		    atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
+		if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 &&
 		    !kthread_should_stop())
 			schedule();
 		__set_current_state(TASK_RUNNING);
@@ -369,11 +381,6 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
 
 	i = 0;
 	list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) {
-		if (fmr->remap_count) {
-			INIT_LIST_HEAD(&fmr_list);
-			list_add_tail(&fmr->fmr->list, &fmr_list);
-			ib_unmap_fmr(&fmr_list);
-		}
 		ib_dealloc_fmr(fmr->fmr);
 		list_del(&fmr->list);
 		kfree(fmr);
@@ -511,8 +518,10 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
 			list_add_tail(&fmr->list, &pool->free_list);
 		} else {
 			list_add_tail(&fmr->list, &pool->dirty_list);
-			++pool->dirty_len;
-			wake_up_process(pool->thread);
+			if (++pool->dirty_len >= pool->dirty_watermark) {
+				atomic_inc(&pool->req_ser);
+				wake_up_process(pool->thread);
+			}
 		}
 	}
 
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 6f4287716ab1..fbe16d5250a4 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -701,7 +701,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
 	}
 
 	/* Check to post send on QP or process locally */
-	if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD)
+	if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD &&
+	    smi_check_local_returning_smp(smp, device) == IB_SMI_DISCARD)
 		goto out;
 
 	local = kmalloc(sizeof *local, GFP_ATOMIC);
@@ -752,8 +753,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
 		port_priv = ib_get_mad_port(mad_agent_priv->agent.device,
 					    mad_agent_priv->agent.port_num);
 		if (port_priv) {
-			mad_priv->mad.mad.mad_hdr.tid =
-				((struct ib_mad *)smp)->mad_hdr.tid;
+			memcpy(&mad_priv->mad.mad, smp, sizeof(struct ib_mad));
 			recv_mad_agent = find_mad_agent(port_priv,
 						        &mad_priv->mad.mad);
 		}
@@ -1100,7 +1100,9 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
 		mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid;
 		/* Timeout will be updated after send completes */
 		mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms);
-		mad_send_wr->retries = send_buf->retries;
+		mad_send_wr->max_retries = send_buf->retries;
+		mad_send_wr->retries_left = send_buf->retries;
+		send_buf->retries = 0;
 		/* Reference for work request to QP + response */
 		mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0);
 		mad_send_wr->status = IB_WC_SUCCESS;
@@ -1931,15 +1933,6 @@ local:
 	if (port_priv->device->process_mad) {
 		int ret;
 
-		if (!response) {
-			printk(KERN_ERR PFX "No memory for response MAD\n");
-			/*
-			 * Is it better to assume that
-			 * it wouldn't be processed ?
-			 */
-			goto out;
-		}
-
 		ret = port_priv->device->process_mad(port_priv->device, 0,
 						     port_priv->port_num,
 						     wc, &recv->grh,
@@ -2282,8 +2275,6 @@ static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv)
 
 	/* Empty wait list to prevent receives from finding a request */
 	list_splice_init(&mad_agent_priv->wait_list, &cancel_list);
-	/* Empty local completion list as well */
-	list_splice_init(&mad_agent_priv->local_list, &cancel_list);
 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
 
 	/* Report all cancelled requests */
@@ -2445,9 +2436,12 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr)
 {
 	int ret;
 
-	if (!mad_send_wr->retries--)
+	if (!mad_send_wr->retries_left)
 		return -ETIMEDOUT;
 
+	mad_send_wr->retries_left--;
+	mad_send_wr->send_buf.retries++;
+
 	mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
 
 	if (mad_send_wr->mad_agent_priv->agent.rmpp_version) {
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index 9be5cc00a3a9..8b75010016ec 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -131,7 +131,8 @@ struct ib_mad_send_wr_private {
 	struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG];
 	__be64 tid;
 	unsigned long timeout;
-	int retries;
+	int max_retries;
+	int retries_left;
 	int retry;
 	int refcount;
 	enum ib_wc_status status;
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
index d43bc62005b3..a5e2a310f312 100644
--- a/drivers/infiniband/core/mad_rmpp.c
+++ b/drivers/infiniband/core/mad_rmpp.c
@@ -684,7 +684,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
 
 	if (seg_num > mad_send_wr->last_ack) {
 		adjust_last_ack(mad_send_wr, seg_num);
-		mad_send_wr->retries = mad_send_wr->send_buf.retries;
+		mad_send_wr->retries_left = mad_send_wr->max_retries;
 	}
 	mad_send_wr->newwin = newwin;
 	if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) {
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index 1bc1fe605282..107f170c57cd 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -73,11 +73,20 @@ struct mcast_device {
 };
 
 enum mcast_state {
-	MCAST_IDLE,
 	MCAST_JOINING,
 	MCAST_MEMBER,
+	MCAST_ERROR,
+};
+
+enum mcast_group_state {
+	MCAST_IDLE,
 	MCAST_BUSY,
-	MCAST_ERROR
+	MCAST_GROUP_ERROR,
+	MCAST_PKEY_EVENT
+};
+
+enum {
+	MCAST_INVALID_PKEY_INDEX = 0xFFFF
 };
 
 struct mcast_member;
@@ -93,9 +102,10 @@ struct mcast_group {
 	struct mcast_member	*last_join;
 	int			members[3];
 	atomic_t		refcount;
-	enum mcast_state	state;
+	enum mcast_group_state	state;
 	struct ib_sa_query	*query;
 	int			query_id;
+	u16			pkey_index;
 };
 
 struct mcast_member {
@@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member,
 static void process_group_error(struct mcast_group *group)
 {
 	struct mcast_member *member;
-	int ret;
+	int ret = 0;
+	u16 pkey_index;
+
+	if (group->state == MCAST_PKEY_EVENT)
+		ret = ib_find_pkey(group->port->dev->device,
+				   group->port->port_num,
+				   be16_to_cpu(group->rec.pkey), &pkey_index);
 
 	spin_lock_irq(&group->lock);
+	if (group->state == MCAST_PKEY_EVENT && !ret &&
+	    group->pkey_index == pkey_index)
+		goto out;
+
 	while (!list_empty(&group->active_list)) {
 		member = list_entry(group->active_list.next,
 				    struct mcast_member, list);
@@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group)
 	}
 
 	group->rec.join_state = 0;
+out:
 	group->state = MCAST_BUSY;
 	spin_unlock_irq(&group->lock);
 }
@@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work)
 retest:
 	spin_lock_irq(&group->lock);
 	while (!list_empty(&group->pending_list) ||
-	       (group->state == MCAST_ERROR)) {
+	       (group->state != MCAST_BUSY)) {
 
-		if (group->state == MCAST_ERROR) {
+		if (group->state != MCAST_BUSY) {
 			spin_unlock_irq(&group->lock);
 			process_group_error(group);
 			goto retest;
@@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec,
 			 void *context)
 {
 	struct mcast_group *group = context;
+	u16 pkey_index = MCAST_INVALID_PKEY_INDEX;
 
 	if (status)
 		process_join_error(group, status);
 	else {
+		ib_find_pkey(group->port->dev->device, group->port->port_num,
+			     be16_to_cpu(rec->pkey), &pkey_index);
+
 		spin_lock_irq(&group->port->lock);
 		group->rec = *rec;
+		if (group->state == MCAST_BUSY &&
+		    group->pkey_index == MCAST_INVALID_PKEY_INDEX)
+			group->pkey_index = pkey_index;
 		if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) {
 			rb_erase(&group->node, &group->port->table);
 			mcast_insert(group->port, group, 1);
@@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port,
 
 	group->port = port;
 	group->rec.mgid = *mgid;
+	group->pkey_index = MCAST_INVALID_PKEY_INDEX;
 	INIT_LIST_HEAD(&group->pending_list);
 	INIT_LIST_HEAD(&group->active_list);
 	INIT_WORK(&group->work, mcast_work_handler);
@@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num,
 }
 EXPORT_SYMBOL(ib_init_ah_from_mcmember);
 
-static void mcast_groups_lost(struct mcast_port *port)
+static void mcast_groups_event(struct mcast_port *port,
+			       enum mcast_group_state state)
 {
 	struct mcast_group *group;
 	struct rb_node *node;
@@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port)
 			atomic_inc(&group->refcount);
 			queue_work(mcast_wq, &group->work);
 		}
-		group->state = MCAST_ERROR;
+		if (group->state != MCAST_GROUP_ERROR)
+			group->state = state;
 		spin_unlock(&group->lock);
 	}
 	spin_unlock_irqrestore(&port->lock, flags);
@@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler,
 				struct ib_event *event)
 {
 	struct mcast_device *dev;
+	int index;
 
 	dev = container_of(handler, struct mcast_device, event_handler);
+	index = event->element.port_num - dev->start_port;
 
 	switch (event->event) {
 	case IB_EVENT_PORT_ERR:
 	case IB_EVENT_LID_CHANGE:
 	case IB_EVENT_SM_CHANGE:
 	case IB_EVENT_CLIENT_REREGISTER:
-		mcast_groups_lost(&dev->port[event->element.port_num -
-					     dev->start_port]);
+		mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR);
+		break;
+	case IB_EVENT_PKEY_CHANGE:
+		mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT);
 		break;
 	default:
 		break;
diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h
index 1cfc2984434f..aff96bac49b4 100644
--- a/drivers/infiniband/core/smi.h
+++ b/drivers/infiniband/core/smi.h
@@ -59,7 +59,8 @@ extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
 					      u8 node_type, int port_num);
 
 /*
- * Return 1 if the SMP should be handled by the local SMA/SM via process_mad
+ * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
+ * via process_mad
  */
 static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
 						  struct ib_device *device)
@@ -71,4 +72,19 @@ static inline enum smi_action smi_check_local_smp(struct ib_smp *smp,
 		(smp->hop_ptr == smp->hop_cnt + 1)) ?
 		IB_SMI_HANDLE : IB_SMI_DISCARD);
 }
+
+/*
+ * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM
+ * via process_mad
+ */
+static inline enum smi_action smi_check_local_returning_smp(struct ib_smp *smp,
+						   struct ib_device *device)
+{
+	/* C14-13:3 -- We're at the end of the DR segment of path */
+	/* C14-13:4 -- Hop Pointer == 0 -> give to SM */
+	return ((device->process_mad &&
+		ib_get_smp_direction(smp) &&
+		!smp->hop_ptr) ? IB_SMI_HANDLE : IB_SMI_DISCARD);
+}
+
 #endif	/* __SMI_H_ */
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 3d4050681325..c864ef70fdf9 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -508,19 +508,10 @@ static int add_port(struct ib_device *device, int port_num)
 
 	p->ibdev      = device;
 	p->port_num   = port_num;
-	p->kobj.ktype = &port_type;
 
-	p->kobj.parent = kobject_get(&device->ports_parent);
-	if (!p->kobj.parent) {
-		ret = -EBUSY;
-		goto err;
-	}
-
-	ret = kobject_set_name(&p->kobj, "%d", port_num);
-	if (ret)
-		goto err_put;
-
-	ret = kobject_register(&p->kobj);
+	ret = kobject_init_and_add(&p->kobj, &port_type,
+				   kobject_get(device->ports_parent),
+				   "%d", port_num);
 	if (ret)
 		goto err_put;
 
@@ -549,6 +540,7 @@ static int add_port(struct ib_device *device, int port_num)
 
 	list_add_tail(&p->kobj.entry, &device->port_list);
 
+	kobject_uevent(&p->kobj, KOBJ_ADD);
 	return 0;
 
 err_free_pkey:
@@ -570,9 +562,7 @@ err_remove_pma:
 	sysfs_remove_group(&p->kobj, &pma_group);
 
 err_put:
-	kobject_put(&device->ports_parent);
-
-err:
+	kobject_put(device->ports_parent);
 	kfree(p);
 	return ret;
 }
@@ -694,16 +684,9 @@ int ib_device_register_sysfs(struct ib_device *device)
 			goto err_unregister;
 	}
 
-	device->ports_parent.parent = kobject_get(&class_dev->kobj);
-	if (!device->ports_parent.parent) {
-		ret = -EBUSY;
-		goto err_unregister;
-	}
-	ret = kobject_set_name(&device->ports_parent, "ports");
-	if (ret)
-		goto err_put;
-	ret = kobject_register(&device->ports_parent);
-	if (ret)
+	device->ports_parent = kobject_create_and_add("ports",
+					kobject_get(&class_dev->kobj));
+	if (!device->ports_parent)
 		goto err_put;
 
 	if (device->node_type == RDMA_NODE_IB_SWITCH) {
@@ -731,7 +714,7 @@ err_put:
 			sysfs_remove_group(p, &pma_group);
 			sysfs_remove_group(p, &port->pkey_group);
 			sysfs_remove_group(p, &port->gid_group);
-			kobject_unregister(p);
+			kobject_put(p);
 		}
 	}
 
@@ -755,10 +738,10 @@ void ib_device_unregister_sysfs(struct ib_device *device)
 		sysfs_remove_group(p, &pma_group);
 		sysfs_remove_group(p, &port->pkey_group);
 		sysfs_remove_group(p, &port->gid_group);
-		kobject_unregister(p);
+		kobject_put(p);
 	}
 
-	kobject_unregister(&device->ports_parent);
+	kobject_put(device->ports_parent);
 	class_device_unregister(&device->class_dev);
 }
 
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index 424983f5b1ee..4291ab42a5b9 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -106,6 +106,9 @@ enum {
 	IB_UCM_MAX_DEVICES = 32
 };
 
+/* ib_cm and ib_user_cm modules share /sys/class/infiniband_cm */
+extern struct class cm_class;
+
 #define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR)
 
 static void ib_ucm_add_one(struct ib_device *device);
@@ -1199,7 +1202,7 @@ static int ib_ucm_close(struct inode *inode, struct file *filp)
 	return 0;
 }
 
-static void ib_ucm_release_class_dev(struct class_device *class_dev)
+static void ucm_release_class_dev(struct class_device *class_dev)
 {
 	struct ib_ucm_device *dev;
 
@@ -1217,11 +1220,6 @@ static const struct file_operations ucm_fops = {
 	.poll    = ib_ucm_poll,
 };
 
-static struct class ucm_class = {
-	.name    = "infiniband_cm",
-	.release = ib_ucm_release_class_dev
-};
-
 static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
 {
 	struct ib_ucm_device *dev;
@@ -1257,9 +1255,10 @@ static void ib_ucm_add_one(struct ib_device *device)
 	if (cdev_add(&ucm_dev->dev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1))
 		goto err;
 
-	ucm_dev->class_dev.class = &ucm_class;
+	ucm_dev->class_dev.class = &cm_class;
 	ucm_dev->class_dev.dev = device->dma_device;
 	ucm_dev->class_dev.devt = ucm_dev->dev.dev;
+	ucm_dev->class_dev.release = ucm_release_class_dev;
 	snprintf(ucm_dev->class_dev.class_id, BUS_ID_SIZE, "ucm%d",
 		 ucm_dev->devnum);
 	if (class_device_register(&ucm_dev->class_dev))
@@ -1306,40 +1305,34 @@ static int __init ib_ucm_init(void)
 				     "infiniband_cm");
 	if (ret) {
 		printk(KERN_ERR "ucm: couldn't register device number\n");
-		goto err;
+		goto error1;
 	}
 
-	ret = class_register(&ucm_class);
-	if (ret) {
-		printk(KERN_ERR "ucm: couldn't create class infiniband_cm\n");
-		goto err_chrdev;
-	}
-
-	ret = class_create_file(&ucm_class, &class_attr_abi_version);
+	ret = class_create_file(&cm_class, &class_attr_abi_version);
 	if (ret) {
 		printk(KERN_ERR "ucm: couldn't create abi_version attribute\n");
-		goto err_class;
+		goto error2;
 	}
 
 	ret = ib_register_client(&ucm_client);
 	if (ret) {
 		printk(KERN_ERR "ucm: couldn't register client\n");
-		goto err_class;
+		goto error3;
 	}
 	return 0;
 
-err_class:
-	class_unregister(&ucm_class);
-err_chrdev:
+error3:
+	class_remove_file(&cm_class, &class_attr_abi_version);
+error2:
 	unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
-err:
+error1:
 	return ret;
 }
 
 static void __exit ib_ucm_cleanup(void)
 {
 	ib_unregister_client(&ucm_client);
-	class_unregister(&ucm_class);
+	class_remove_file(&cm_class, &class_attr_abi_version);
 	unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES);
 	idr_destroy(&ctx_id_table);
 }
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 90d675ad9ec8..15937eb38aae 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -31,6 +31,7 @@
  */
 
 #include <linux/completion.h>
+#include <linux/file.h>
 #include <linux/mutex.h>
 #include <linux/poll.h>
 #include <linux/idr.h>
@@ -991,6 +992,96 @@ out:
 	return ret;
 }
 
+static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2)
+{
+	/* Acquire mutex's based on pointer comparison to prevent deadlock. */
+	if (file1 < file2) {
+		mutex_lock(&file1->mut);
+		mutex_lock(&file2->mut);
+	} else {
+		mutex_lock(&file2->mut);
+		mutex_lock(&file1->mut);
+	}
+}
+
+static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2)
+{
+	if (file1 < file2) {
+		mutex_unlock(&file2->mut);
+		mutex_unlock(&file1->mut);
+	} else {
+		mutex_unlock(&file1->mut);
+		mutex_unlock(&file2->mut);
+	}
+}
+
+static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file)
+{
+	struct ucma_event *uevent, *tmp;
+
+	list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list)
+		if (uevent->ctx == ctx)
+			list_move_tail(&uevent->list, &file->event_list);
+}
+
+static ssize_t ucma_migrate_id(struct ucma_file *new_file,
+			       const char __user *inbuf,
+			       int in_len, int out_len)
+{
+	struct rdma_ucm_migrate_id cmd;
+	struct rdma_ucm_migrate_resp resp;
+	struct ucma_context *ctx;
+	struct file *filp;
+	struct ucma_file *cur_file;
+	int ret = 0;
+
+	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+		return -EFAULT;
+
+	/* Get current fd to protect against it being closed */
+	filp = fget(cmd.fd);
+	if (!filp)
+		return -ENOENT;
+
+	/* Validate current fd and prevent destruction of id. */
+	ctx = ucma_get_ctx(filp->private_data, cmd.id);
+	if (IS_ERR(ctx)) {
+		ret = PTR_ERR(ctx);
+		goto file_put;
+	}
+
+	cur_file = ctx->file;
+	if (cur_file == new_file) {
+		resp.events_reported = ctx->events_reported;
+		goto response;
+	}
+
+	/*
+	 * Migrate events between fd's, maintaining order, and avoiding new
+	 * events being added before existing events.
+	 */
+	ucma_lock_files(cur_file, new_file);
+	mutex_lock(&mut);
+
+	list_move_tail(&ctx->list, &new_file->ctx_list);
+	ucma_move_events(ctx, new_file);
+	ctx->file = new_file;
+	resp.events_reported = ctx->events_reported;
+
+	mutex_unlock(&mut);
+	ucma_unlock_files(cur_file, new_file);
+
+response:
+	if (copy_to_user((void __user *)(unsigned long)cmd.response,
+			 &resp, sizeof(resp)))
+		ret = -EFAULT;
+
+	ucma_put_ctx(ctx);
+file_put:
+	fput(filp);
+	return ret;
+}
+
 static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
 				   const char __user *inbuf,
 				   int in_len, int out_len) = {
@@ -1012,6 +1103,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
 	[RDMA_USER_CM_CMD_NOTIFY]	= ucma_notify,
 	[RDMA_USER_CM_CMD_JOIN_MCAST]	= ucma_join_multicast,
 	[RDMA_USER_CM_CMD_LEAVE_MCAST]	= ucma_leave_multicast,
+	[RDMA_USER_CM_CMD_MIGRATE_ID]	= ucma_migrate_id
 };
 
 static ssize_t ucma_write(struct file *filp, const char __user *buf,
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index b53eac4611de..4e915104ac4c 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2008 Cisco. 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
@@ -42,7 +43,7 @@
 #include <linux/cdev.h>
 #include <linux/dma-mapping.h>
 #include <linux/poll.h>
-#include <linux/rwsem.h>
+#include <linux/mutex.h>
 #include <linux/kref.h>
 #include <linux/compat.h>
 
@@ -94,7 +95,7 @@ struct ib_umad_port {
 	struct class_device   *sm_class_dev;
 	struct semaphore       sm_sem;
 
-	struct rw_semaphore    mutex;
+	struct mutex	       file_mutex;
 	struct list_head       file_list;
 
 	struct ib_device      *ib_dev;
@@ -110,11 +111,11 @@ struct ib_umad_device {
 };
 
 struct ib_umad_file {
+	struct mutex		mutex;
 	struct ib_umad_port    *port;
 	struct list_head	recv_list;
 	struct list_head	send_list;
 	struct list_head	port_list;
-	spinlock_t		recv_lock;
 	spinlock_t		send_lock;
 	wait_queue_head_t	recv_wait;
 	struct ib_mad_agent    *agent[IB_UMAD_MAX_AGENTS];
@@ -156,7 +157,7 @@ static int hdr_size(struct ib_umad_file *file)
 		sizeof (struct ib_user_mad_hdr_old);
 }
 
-/* caller must hold port->mutex at least for reading */
+/* caller must hold file->mutex */
 static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
 {
 	return file->agents_dead ? NULL : file->agent[id];
@@ -168,32 +169,30 @@ static int queue_packet(struct ib_umad_file *file,
 {
 	int ret = 1;
 
-	down_read(&file->port->mutex);
+	mutex_lock(&file->mutex);
 
 	for (packet->mad.hdr.id = 0;
 	     packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
 	     packet->mad.hdr.id++)
 		if (agent == __get_agent(file, packet->mad.hdr.id)) {
-			spin_lock_irq(&file->recv_lock);
 			list_add_tail(&packet->list, &file->recv_list);
-			spin_unlock_irq(&file->recv_lock);
 			wake_up_interruptible(&file->recv_wait);
 			ret = 0;
 			break;
 		}
 
-	up_read(&file->port->mutex);
+	mutex_unlock(&file->mutex);
 
 	return ret;
 }
 
 static void dequeue_send(struct ib_umad_file *file,
 			 struct ib_umad_packet *packet)
- {
+{
 	spin_lock_irq(&file->send_lock);
 	list_del(&packet->list);
 	spin_unlock_irq(&file->send_lock);
- }
+}
 
 static void send_handler(struct ib_mad_agent *agent,
 			 struct ib_mad_send_wc *send_wc)
@@ -341,10 +340,10 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
 	if (count < hdr_size(file))
 		return -EINVAL;
 
-	spin_lock_irq(&file->recv_lock);
+	mutex_lock(&file->mutex);
 
 	while (list_empty(&file->recv_list)) {
-		spin_unlock_irq(&file->recv_lock);
+		mutex_unlock(&file->mutex);
 
 		if (filp->f_flags & O_NONBLOCK)
 			return -EAGAIN;
@@ -353,13 +352,13 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
 					     !list_empty(&file->recv_list)))
 			return -ERESTARTSYS;
 
-		spin_lock_irq(&file->recv_lock);
+		mutex_lock(&file->mutex);
 	}
 
 	packet = list_entry(file->recv_list.next, struct ib_umad_packet, list);
 	list_del(&packet->list);
 
-	spin_unlock_irq(&file->recv_lock);
+	mutex_unlock(&file->mutex);
 
 	if (packet->recv_wc)
 		ret = copy_recv_mad(file, buf, packet, count);
@@ -368,9 +367,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
 
 	if (ret < 0) {
 		/* Requeue packet */
-		spin_lock_irq(&file->recv_lock);
+		mutex_lock(&file->mutex);
 		list_add(&packet->list, &file->recv_list);
-		spin_unlock_irq(&file->recv_lock);
+		mutex_unlock(&file->mutex);
 	} else {
 		if (packet->recv_wc)
 			ib_free_recv_mad(packet->recv_wc);
@@ -481,7 +480,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
 		goto err;
 	}
 
-	down_read(&file->port->mutex);
+	mutex_lock(&file->mutex);
 
 	agent = __get_agent(file, packet->mad.hdr.id);
 	if (!agent) {
@@ -577,7 +576,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
 	if (ret)
 		goto err_send;
 
-	up_read(&file->port->mutex);
+	mutex_unlock(&file->mutex);
 	return count;
 
 err_send:
@@ -587,7 +586,7 @@ err_msg:
 err_ah:
 	ib_destroy_ah(ah);
 err_up:
-	up_read(&file->port->mutex);
+	mutex_unlock(&file->mutex);
 err:
 	kfree(packet);
 	return ret;
@@ -613,11 +612,12 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
 {
 	struct ib_user_mad_reg_req ureq;
 	struct ib_mad_reg_req req;
-	struct ib_mad_agent *agent;
+	struct ib_mad_agent *agent = NULL;
 	int agent_id;
 	int ret;
 
-	down_write(&file->port->mutex);
+	mutex_lock(&file->port->file_mutex);
+	mutex_lock(&file->mutex);
 
 	if (!file->port->ib_dev) {
 		ret = -EPIPE;
@@ -666,13 +666,13 @@ found:
 				      send_handler, recv_handler, file);
 	if (IS_ERR(agent)) {
 		ret = PTR_ERR(agent);
+		agent = NULL;
 		goto out;
 	}
 
 	if (put_user(agent_id,
 		     (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) {
 		ret = -EFAULT;
-		ib_unregister_mad_agent(agent);
 		goto out;
 	}
 
@@ -690,7 +690,13 @@ found:
 	ret = 0;
 
 out:
-	up_write(&file->port->mutex);
+	mutex_unlock(&file->mutex);
+
+	if (ret && agent)
+		ib_unregister_mad_agent(agent);
+
+	mutex_unlock(&file->port->file_mutex);
+
 	return ret;
 }
 
@@ -703,7 +709,8 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
 	if (get_user(id, arg))
 		return -EFAULT;
 
-	down_write(&file->port->mutex);
+	mutex_lock(&file->port->file_mutex);
+	mutex_lock(&file->mutex);
 
 	if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
 		ret = -EINVAL;
@@ -714,11 +721,13 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
 	file->agent[id] = NULL;
 
 out:
-	up_write(&file->port->mutex);
+	mutex_unlock(&file->mutex);
 
 	if (agent)
 		ib_unregister_mad_agent(agent);
 
+	mutex_unlock(&file->port->file_mutex);
+
 	return ret;
 }
 
@@ -726,12 +735,12 @@ static long ib_umad_enable_pkey(struct ib_umad_file *file)
 {
 	int ret = 0;
 
-	down_write(&file->port->mutex);
+	mutex_lock(&file->mutex);
 	if (file->already_used)
 		ret = -EINVAL;
 	else
 		file->use_pkey_index = 1;
-	up_write(&file->port->mutex);
+	mutex_unlock(&file->mutex);
 
 	return ret;
 }
@@ -783,7 +792,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
 	if (!port)
 		return -ENXIO;
 
-	down_write(&port->mutex);
+	mutex_lock(&port->file_mutex);
 
 	if (!port->ib_dev) {
 		ret = -ENXIO;
@@ -797,7 +806,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
 		goto out;
 	}
 
-	spin_lock_init(&file->recv_lock);
+	mutex_init(&file->mutex);
 	spin_lock_init(&file->send_lock);
 	INIT_LIST_HEAD(&file->recv_list);
 	INIT_LIST_HEAD(&file->send_list);
@@ -809,7 +818,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
 	list_add_tail(&file->port_list, &port->file_list);
 
 out:
-	up_write(&port->mutex);
+	mutex_unlock(&port->file_mutex);
 	return ret;
 }
 
@@ -821,7 +830,8 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
 	int already_dead;
 	int i;
 
-	down_write(&file->port->mutex);
+	mutex_lock(&file->port->file_mutex);
+	mutex_lock(&file->mutex);
 
 	already_dead = file->agents_dead;
 	file->agents_dead = 1;
@@ -834,14 +844,14 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
 
 	list_del(&file->port_list);
 
-	downgrade_write(&file->port->mutex);
+	mutex_unlock(&file->mutex);
 
 	if (!already_dead)
 		for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
 			if (file->agent[i])
 				ib_unregister_mad_agent(file->agent[i]);
 
-	up_read(&file->port->mutex);
+	mutex_unlock(&file->port->file_mutex);
 
 	kfree(file);
 	kref_put(&dev->ref, ib_umad_release_dev);
@@ -914,10 +924,10 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp)
 	};
 	int ret = 0;
 
-	down_write(&port->mutex);
+	mutex_lock(&port->file_mutex);
 	if (port->ib_dev)
 		ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props);
-	up_write(&port->mutex);
+	mutex_unlock(&port->file_mutex);
 
 	up(&port->sm_sem);
 
@@ -981,7 +991,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
 	port->ib_dev   = device;
 	port->port_num = port_num;
 	init_MUTEX(&port->sm_sem);
-	init_rwsem(&port->mutex);
+	mutex_init(&port->file_mutex);
 	INIT_LIST_HEAD(&port->file_list);
 
 	port->dev = cdev_alloc();
@@ -1052,6 +1062,7 @@ err_cdev:
 static void ib_umad_kill_port(struct ib_umad_port *port)
 {
 	struct ib_umad_file *file;
+	int already_dead;
 	int id;
 
 	class_set_devdata(port->class_dev,    NULL);
@@ -1067,42 +1078,22 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
 	umad_port[port->dev_num] = NULL;
 	spin_unlock(&port_lock);
 
-	down_write(&port->mutex);
+	mutex_lock(&port->file_mutex);
 
 	port->ib_dev = NULL;
 
-	/*
-	 * Now go through the list of files attached to this port and
-	 * unregister all of their MAD agents.  We need to hold
-	 * port->mutex while doing this to avoid racing with
-	 * ib_umad_close(), but we can't hold the mutex for writing
-	 * while calling ib_unregister_mad_agent(), since that might
-	 * deadlock by calling back into queue_packet().  So we
-	 * downgrade our lock to a read lock, and then drop and
-	 * reacquire the write lock for the next iteration.
-	 *
-	 * We do list_del_init() on the file's list_head so that the
-	 * list_del in ib_umad_close() is still OK, even after the
-	 * file is removed from the list.
-	 */
-	while (!list_empty(&port->file_list)) {
-		file = list_entry(port->file_list.next, struct ib_umad_file,
-				  port_list);
-
+	list_for_each_entry(file, &port->file_list, port_list) {
+		mutex_lock(&file->mutex);
+		already_dead = file->agents_dead;
 		file->agents_dead = 1;
-		list_del_init(&file->port_list);
-
-		downgrade_write(&port->mutex);
+		mutex_unlock(&file->mutex);
 
 		for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
 			if (file->agent[id])
 				ib_unregister_mad_agent(file->agent[id]);
-
-		up_read(&port->mutex);
-		down_write(&port->mutex);
 	}
 
-	up_write(&port->mutex);
+	mutex_unlock(&port->file_mutex);
 
 	clear_bit(port->dev_num, dev_map);
 }
diff --git a/drivers/infiniband/hw/cxgb3/Makefile b/drivers/infiniband/hw/cxgb3/Makefile
index 36b98989b15e..7e7b5a66f042 100644
--- a/drivers/infiniband/hw/cxgb3/Makefile
+++ b/drivers/infiniband/hw/cxgb3/Makefile
@@ -1,5 +1,4 @@
-EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/cxgb3 \
-		-I$(TOPDIR)/drivers/infiniband/hw/cxgb3/core
+EXTRA_CFLAGS += -Idrivers/net/cxgb3
 
 obj-$(CONFIG_INFINIBAND_CXGB3) += iw_cxgb3.o
 
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index eec6a30840ca..03c5ff62889a 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -179,7 +179,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq)
 	setup.size = 1UL << cq->size_log2;
 	setup.credits = 65535;
 	setup.credit_thres = 1;
-	if (rdev_p->t3cdev_p->type == T3B)
+	if (rdev_p->t3cdev_p->type != T3A)
 		setup.ovfl_mode = 0;
 	else
 		setup.ovfl_mode = 1;
@@ -584,7 +584,7 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
 {
 	u32 i, nr_wqe, copy_len;
 	u8 *copy_data;
-	u8 wr_len, utx_len;	/* lenght in 8 byte flit */
+	u8 wr_len, utx_len;	/* length in 8 byte flit */
 	enum t3_wr_flags flag;
 	__be64 *wqe;
 	u64 utx_cmd;
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
index c84d4ac49355..969d4d928455 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -315,7 +315,7 @@ struct t3_rdma_init_wr {
 	__be32 ird;
 	__be64 qp_dma_addr;	/* 7 */
 	__be32 qp_dma_size;	/* 8 */
-	u32 irs;
+	__be32 irs;
 };
 
 struct t3_genbit {
@@ -324,7 +324,8 @@ struct t3_genbit {
 };
 
 enum rdma_init_wr_flags {
-	RECVS_POSTED = 1,
+	RECVS_POSTED = (1<<0),
+	PRIV_QP = (1<<1),
 };
 
 union t3_wr {
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 20ba372dd182..e9a08fa3dffe 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -332,7 +332,7 @@ static struct rtable *find_route(struct t3cdev *dev, __be32 local_ip,
 			  }
 	};
 
-	if (ip_route_output_flow(&rt, &fl, NULL, 0))
+	if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0))
 		return NULL;
 	return rt;
 }
@@ -1118,7 +1118,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
 	     status2errno(rpl->status));
 	connect_reply_upcall(ep, status2errno(rpl->status));
 	state_set(&ep->com, DEAD);
-	if (ep->com.tdev->type == T3B && act_open_has_tid(rpl->status))
+	if (ep->com.tdev->type != T3A && act_open_has_tid(rpl->status))
 		release_tid(ep->com.tdev, GET_TID(rpl), NULL);
 	cxgb3_free_atid(ep->com.tdev, ep->atid);
 	dst_release(ep->dst);
@@ -1249,7 +1249,7 @@ static void reject_cr(struct t3cdev *tdev, u32 hwtid, __be32 peer_ip,
 	skb_trim(skb, sizeof(struct cpl_tid_release));
 	skb_get(skb);
 
-	if (tdev->type == T3B)
+	if (tdev->type != T3A)
 		release_tid(tdev, hwtid, skb);
 	else {
 		struct cpl_pass_accept_rpl *rpl;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c
index a6c2c4ba29e6..73bfd1656f86 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_mem.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c
@@ -122,6 +122,13 @@ int build_phys_page_list(struct ib_phys_buf *buffer_list,
 		*total_size += buffer_list[i].size;
 		if (i > 0)
 			mask |= buffer_list[i].addr;
+		else
+			mask |= buffer_list[i].addr & PAGE_MASK;
+		if (i != num_phys_buf - 1)
+			mask |= buffer_list[i].addr + buffer_list[i].size;
+		else
+			mask |= (buffer_list[i].addr + buffer_list[i].size +
+				PAGE_SIZE - 1) & PAGE_MASK;
 	}
 
 	if (*total_size > 0xFFFFFFFFULL)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index b5436ca92e68..df1838f8f94d 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -39,6 +39,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -645,7 +646,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
 	if (err)
 		goto err;
 
-	if (udata && t3b_device(rhp)) {
+	if (udata && !t3a_device(rhp)) {
 		uresp.pbl_addr = (mhp->attr.pbl_addr -
 	                         rhp->rdev.rnic_info.pbl_base) >> 3;
 		PDBG("%s user resp pbl_addr 0x%x\n", __FUNCTION__,
@@ -1053,7 +1054,9 @@ static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
 	struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
 
 	PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
+	rtnl_lock();
 	lldev->ethtool_ops->get_drvinfo(lldev, &info);
+	rtnl_unlock();
 	return sprintf(buf, "%s\n", info.fw_version);
 }
 
@@ -1065,7 +1068,9 @@ static ssize_t show_hca(struct class_device *cdev, char *buf)
 	struct net_device *lldev = dev->rdev.t3cdev_p->lldev;
 
 	PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev);
+	rtnl_lock();
 	lldev->ethtool_ops->get_drvinfo(lldev, &info);
+	rtnl_unlock();
 	return sprintf(buf, "%s\n", info.driver);
 }
 
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index dd89b6b91f9c..ea2cdd73dd85 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -208,36 +208,19 @@ static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list,
 static int iwch_build_rdma_recv(struct iwch_dev *rhp, union t3_wr *wqe,
 				struct ib_recv_wr *wr)
 {
-	int i, err = 0;
-	u32 pbl_addr[4];
-	u8 page_size[4];
+	int i;
 	if (wr->num_sge > T3_MAX_SGE)
 		return -EINVAL;
-	err = iwch_sgl2pbl_map(rhp, wr->sg_list, wr->num_sge, pbl_addr,
-			       page_size);
-	if (err)
-		return err;
-	wqe->recv.pagesz[0] = page_size[0];
-	wqe->recv.pagesz[1] = page_size[1];
-	wqe->recv.pagesz[2] = page_size[2];
-	wqe->recv.pagesz[3] = page_size[3];
 	wqe->recv.num_sgle = cpu_to_be32(wr->num_sge);
 	for (i = 0; i < wr->num_sge; i++) {
 		wqe->recv.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey);
 		wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length);
-
-		/* to in the WQE == the offset into the page */
-		wqe->recv.sgl[i].to = cpu_to_be64(((u32) wr->sg_list[i].addr) %
-				(1UL << (12 + page_size[i])));
-
-		/* pbl_addr is the adapters address in the PBL */
-		wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_addr[i]);
+		wqe->recv.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr);
 	}
 	for (; i < T3_MAX_SGE; i++) {
 		wqe->recv.sgl[i].stag = 0;
 		wqe->recv.sgl[i].len = 0;
 		wqe->recv.sgl[i].to = 0;
-		wqe->recv.pbl_addr[i] = 0;
 	}
 	return 0;
 }
@@ -659,6 +642,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 	cxio_flush_rq(&qhp->wq, &rchp->cq, count);
 	spin_unlock(&qhp->lock);
 	spin_unlock_irqrestore(&rchp->lock, *flag);
+	(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
 
 	/* locking heirarchy: cq lock first, then qp lock. */
 	spin_lock_irqsave(&schp->lock, *flag);
@@ -668,6 +652,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 	cxio_flush_sq(&qhp->wq, &schp->cq, count);
 	spin_unlock(&qhp->lock);
 	spin_unlock_irqrestore(&schp->lock, *flag);
+	(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
 
 	/* deref */
 	if (atomic_dec_and_test(&qhp->refcnt))
@@ -678,7 +663,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 
 static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)
 {
-	if (t3b_device(qhp->rhp))
+	if (qhp->ibqp.uobject)
 		cxio_set_wq_in_error(&qhp->wq);
 	else
 		__flush_qp(qhp, flag);
@@ -732,6 +717,7 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,
 	init_attr.qp_dma_addr = qhp->wq.dma_addr;
 	init_attr.qp_dma_size = (1UL << qhp->wq.size_log2);
 	init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0;
+	init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0;
 	init_attr.irs = qhp->ep->rcv_seq;
 	PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d "
 	     "flags 0x%x qpcaps 0x%x\n", __FUNCTION__,
@@ -847,10 +833,11 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,
 				disconnect = 1;
 				ep = qhp->ep;
 			}
+			flush_qp(qhp, &flag);
 			break;
 		case IWCH_QP_STATE_TERMINATE:
 			qhp->attr.state = IWCH_QP_STATE_TERMINATE;
-			if (t3b_device(qhp->rhp))
+			if (qhp->ibqp.uobject)
 				cxio_set_wq_in_error(&qhp->wq);
 			if (!internal)
 				terminate = 1;
diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c
index f7782c882ab4..194c1c30cf63 100644
--- a/drivers/infiniband/hw/ehca/ehca_av.c
+++ b/drivers/infiniband/hw/ehca/ehca_av.c
@@ -1,7 +1,7 @@
 /*
  *  IBM eServer eHCA Infiniband device driver for Linux on POWER
  *
- *  adress vector functions
+ *  address vector functions
  *
  *  Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
  *           Khadija Souissi <souissik@de.ibm.com>
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 74d2b72a11d8..f281d16040f5 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -94,7 +94,11 @@ struct ehca_sma_attr {
 
 struct ehca_sport {
 	struct ib_cq *ibcq_aqp1;
-	struct ib_qp *ibqp_aqp1;
+	struct ib_qp *ibqp_sqp[2];
+	/* lock to serialze modify_qp() calls for sqp in normal
+	 * and irq path (when event PORT_ACTIVE is received first time)
+	 */
+	spinlock_t mod_sqp_lock;
 	enum ib_port_state port_state;
 	struct ehca_sma_attr saved_attr;
 };
@@ -141,6 +145,14 @@ enum ehca_ext_qp_type {
 	EQPT_SRQ       = 3,
 };
 
+/* struct to cache modify_qp()'s parms for GSI/SMI qp */
+struct ehca_mod_qp_parm {
+	int mask;
+	struct ib_qp_attr attr;
+};
+
+#define EHCA_MOD_QP_PARM_MAX 4
+
 struct ehca_qp {
 	union {
 		struct ib_qp ib_qp;
@@ -164,10 +176,18 @@ struct ehca_qp {
 	struct ehca_cq *recv_cq;
 	unsigned int sqerr_purgeflag;
 	struct hlist_node list_entries;
+	/* array to cache modify_qp()'s parms for GSI/SMI qp */
+	struct ehca_mod_qp_parm *mod_qp_parm;
+	int mod_qp_parm_idx;
 	/* mmap counter for resources mapped into user space */
 	u32 mm_count_squeue;
 	u32 mm_count_rqueue;
 	u32 mm_count_galpa;
+	/* unsolicited ack circumvention */
+	int unsol_ack_circ;
+	int mtu_shift;
+	u32 message_count;
+	u32 packet_count;
 };
 
 #define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
@@ -323,6 +343,7 @@ extern int ehca_port_act_time;
 extern int ehca_use_hp_mr;
 extern int ehca_scaling_code;
 extern int ehca_lock_hcalls;
+extern int ehca_nr_ports;
 
 struct ipzu_queue_resp {
 	u32 qe_size;      /* queue entry size */
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 79c25f51c21e..0467c158d4a9 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -246,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
 		} else {
 			if (h_ret != H_PAGE_REGISTERED) {
 				ehca_err(device, "Registration of page failed "
-					 "ehca_cq=%p cq_num=%x h_ret=%li"
+					 "ehca_cq=%p cq_num=%x h_ret=%li "
 					 "counter=%i act_pages=%i",
 					 my_cq, my_cq->cq_number,
 					 h_ret, counter, param.act_pages);
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 3f617b27b954..863b34fa9ff9 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -62,6 +62,7 @@
 #define NEQE_PORT_NUMBER       EHCA_BMASK_IBM( 8, 15)
 #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
 #define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16, 16)
+#define NEQE_SPECIFIC_EVENT    EHCA_BMASK_IBM(16, 23)
 
 #define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52, 63)
 #define ERROR_DATA_TYPE        EHCA_BMASK_IBM( 0,  7)
@@ -354,17 +355,34 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
 {
 	u8 ec   = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
 	u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
+	u8 spec_event;
+	struct ehca_sport *sport = &shca->sport[port - 1];
+	unsigned long flags;
 
 	switch (ec) {
 	case 0x30: /* port availability change */
 		if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
-			shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
+			int suppress_event;
+			/* replay modify_qp for sqps */
+			spin_lock_irqsave(&sport->mod_sqp_lock, flags);
+			suppress_event = !sport->ibqp_sqp[IB_QPT_GSI];
+			if (sport->ibqp_sqp[IB_QPT_SMI])
+				ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]);
+			if (!suppress_event)
+				ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]);
+			spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
+
+			/* AQP1 was destroyed, ignore this event */
+			if (suppress_event)
+				break;
+
+			sport->port_state = IB_PORT_ACTIVE;
 			dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
 					    "is active");
 			ehca_query_sma_attr(shca, port,
-					    &shca->sport[port - 1].saved_attr);
+					    &sport->saved_attr);
 		} else {
-			shca->sport[port - 1].port_state = IB_PORT_DOWN;
+			sport->port_state = IB_PORT_DOWN;
 			dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
 					    "is inactive");
 		}
@@ -378,11 +396,11 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
 			ehca_warn(&shca->ib_device, "disruptive port "
 				  "%d configuration change", port);
 
-			shca->sport[port - 1].port_state = IB_PORT_DOWN;
+			sport->port_state = IB_PORT_DOWN;
 			dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
 					    "is inactive");
 
-			shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
+			sport->port_state = IB_PORT_ACTIVE;
 			dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
 					    "is active");
 		} else
@@ -394,6 +412,16 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
 	case 0x33:  /* trace stopped */
 		ehca_err(&shca->ib_device, "Traced stopped.");
 		break;
+	case 0x34: /* util async event */
+		spec_event = EHCA_BMASK_GET(NEQE_SPECIFIC_EVENT, eqe);
+		if (spec_event == 0x80) /* client reregister required */
+			dispatch_port_event(shca, port,
+					    IB_EVENT_CLIENT_REREGISTER,
+					    "client reregister req.");
+		else
+			ehca_warn(&shca->ib_device, "Unknown util async "
+				  "event %x on port %x", spec_event, port);
+		break;
 	default:
 		ehca_err(&shca->ib_device, "Unknown event code: %x on %s.",
 			 ec, shca->ib_device.name);
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index 5485799cdc8d..c469bfde2708 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -200,4 +200,6 @@ void ehca_free_fw_ctrlblock(void *ptr);
 #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
 #endif
 
+void ehca_recover_sqp(struct ib_qp *sqp);
+
 #endif
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 6a56d86a2951..84c9b7b8669b 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -90,7 +90,8 @@ MODULE_PARM_DESC(hw_level,
 		 "hardware level"
 		 " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)");
 MODULE_PARM_DESC(nr_ports,
-		 "number of connected ports (default: 2)");
+		 "number of connected ports (-1: autodetect, 1: port one only, "
+		 "2: two ports (default)");
 MODULE_PARM_DESC(use_hp_mr,
 		 "high performance MRs (0: no (default), 1: yes)");
 MODULE_PARM_DESC(port_act_time,
@@ -511,7 +512,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
 	}
 	sport->ibcq_aqp1 = ibcq;
 
-	if (sport->ibqp_aqp1) {
+	if (sport->ibqp_sqp[IB_QPT_GSI]) {
 		ehca_err(&shca->ib_device, "AQP1 QP is already created.");
 		ret = -EPERM;
 		goto create_aqp1;
@@ -537,7 +538,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
 		ret = PTR_ERR(ibqp);
 		goto create_aqp1;
 	}
-	sport->ibqp_aqp1 = ibqp;
+	sport->ibqp_sqp[IB_QPT_GSI] = ibqp;
 
 	return 0;
 
@@ -550,7 +551,7 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport)
 {
 	int ret;
 
-	ret = ib_destroy_qp(sport->ibqp_aqp1);
+	ret = ib_destroy_qp(sport->ibqp_sqp[IB_QPT_GSI]);
 	if (ret) {
 		ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret);
 		return ret;
@@ -590,6 +591,11 @@ static struct attribute_group ehca_drv_attr_grp = {
 	.attrs = ehca_drv_attrs
 };
 
+static struct attribute_group *ehca_drv_attr_groups[] = {
+	&ehca_drv_attr_grp,
+	NULL,
+};
+
 #define EHCA_RESOURCE_ATTR(name)                                           \
 static ssize_t  ehca_show_##name(struct device *dev,                       \
 				 struct device_attribute *attr,            \
@@ -688,7 +694,7 @@ static int __devinit ehca_probe(struct of_device *dev,
 	struct ehca_shca *shca;
 	const u64 *handle;
 	struct ib_pd *ibpd;
-	int ret;
+	int ret, i;
 
 	handle = of_get_property(dev->node, "ibm,hca-handle", NULL);
 	if (!handle) {
@@ -709,6 +715,8 @@ static int __devinit ehca_probe(struct of_device *dev,
 		return -ENOMEM;
 	}
 	mutex_init(&shca->modify_mutex);
+	for (i = 0; i < ARRAY_SIZE(shca->sport); i++)
+		spin_lock_init(&shca->sport[i].mod_sqp_lock);
 
 	shca->ofdev = dev;
 	shca->ipz_hca_handle.handle = *handle;
@@ -899,6 +907,9 @@ static struct of_platform_driver ehca_driver = {
 	.match_table = ehca_device_table,
 	.probe       = ehca_probe,
 	.remove      = ehca_remove,
+	.driver	     = {
+		.groups = ehca_drv_attr_groups,
+	},
 };
 
 void ehca_poll_eqs(unsigned long data)
@@ -926,7 +937,7 @@ void ehca_poll_eqs(unsigned long data)
 				ehca_process_eq(shca, 0);
 		}
 	}
-	mod_timer(&poll_eqs_timer, jiffies + HZ);
+	mod_timer(&poll_eqs_timer, round_jiffies(jiffies + HZ));
 	spin_unlock(&shca_list_lock);
 }
 
@@ -957,10 +968,6 @@ int __init ehca_module_init(void)
 		goto module_init2;
 	}
 
-	ret = sysfs_create_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp);
-	if (ret) /* only complain; we can live without attributes */
-		ehca_gen_err("Cannot create driver attributes  ret=%d", ret);
-
 	if (ehca_poll_all_eqs != 1) {
 		ehca_gen_err("WARNING!!!");
 		ehca_gen_err("It is possible to lose interrupts.");
@@ -986,7 +993,6 @@ void __exit ehca_module_exit(void)
 	if (ehca_poll_all_eqs == 1)
 		del_timer_sync(&poll_eqs_timer);
 
-	sysfs_remove_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp);
 	ibmebus_unregister_driver(&ehca_driver);
 
 	ehca_destroy_slab_caches();
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index eff5fb55604b..1012f15a7140 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -592,10 +592,8 @@ static struct ehca_qp *internal_create_qp(
 		goto create_qp_exit1;
 	}
 
-	if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
-		parms.sigtype = HCALL_SIGT_EVERY;
-	else
-		parms.sigtype = HCALL_SIGT_BY_WQE;
+	/* Always signal by WQE so we can hide circ. WQEs */
+	parms.sigtype = HCALL_SIGT_BY_WQE;
 
 	/* UD_AV CIRCUMVENTION */
 	max_send_sge = init_attr->cap.max_send_sge;
@@ -618,6 +616,10 @@ static struct ehca_qp *internal_create_qp(
 	parms.squeue.max_sge = max_send_sge;
 	parms.rqueue.max_sge = max_recv_sge;
 
+	/* RC QPs need one more SWQE for unsolicited ack circumvention */
+	if (qp_type == IB_QPT_RC)
+		parms.squeue.max_wr++;
+
 	if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) {
 		if (HAS_SQ(my_qp))
 			ehca_determine_small_queue(
@@ -650,6 +652,8 @@ static struct ehca_qp *internal_create_qp(
 			parms.squeue.act_nr_sges = 1;
 			parms.rqueue.act_nr_sges = 1;
 		}
+		/* hide the extra WQE */
+		parms.squeue.act_nr_wqes--;
 		break;
 	case IB_QPT_UD:
 	case IB_QPT_GSI:
@@ -729,12 +733,31 @@ static struct ehca_qp *internal_create_qp(
 	init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
 	my_qp->init_attr = *init_attr;
 
+	if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
+		shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] =
+			&my_qp->ib_qp;
+		if (ehca_nr_ports < 0) {
+			/* alloc array to cache subsequent modify qp parms
+			 * for autodetect mode
+			 */
+			my_qp->mod_qp_parm =
+				kzalloc(EHCA_MOD_QP_PARM_MAX *
+					sizeof(*my_qp->mod_qp_parm),
+					GFP_KERNEL);
+			if (!my_qp->mod_qp_parm) {
+				ehca_err(pd->device,
+					 "Could not alloc mod_qp_parm");
+				goto create_qp_exit4;
+			}
+		}
+	}
+
 	/* NOTE: define_apq0() not supported yet */
 	if (qp_type == IB_QPT_GSI) {
 		h_ret = ehca_define_sqp(shca, my_qp, init_attr);
 		if (h_ret != H_SUCCESS) {
 			ret = ehca2ib_return_code(h_ret);
-			goto create_qp_exit4;
+			goto create_qp_exit5;
 		}
 	}
 
@@ -743,7 +766,7 @@ static struct ehca_qp *internal_create_qp(
 		if (ret) {
 			ehca_err(pd->device,
 				 "Couldn't assign qp to send_cq ret=%i", ret);
-			goto create_qp_exit4;
+			goto create_qp_exit5;
 		}
 	}
 
@@ -769,12 +792,18 @@ static struct ehca_qp *internal_create_qp(
 		if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
 			ehca_err(pd->device, "Copy to udata failed");
 			ret = -EINVAL;
-			goto create_qp_exit4;
+			goto create_qp_exit6;
 		}
 	}
 
 	return my_qp;
 
+create_qp_exit6:
+	ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num);
+
+create_qp_exit5:
+	kfree(my_qp->mod_qp_parm);
+
 create_qp_exit4:
 	if (HAS_RQ(my_qp))
 		ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
@@ -858,7 +887,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
 				update_mask,
 				mqpcb, my_qp->galpas.kernel);
 	if (hret != H_SUCCESS) {
-		ehca_err(pd->device, "Could not modify SRQ to INIT"
+		ehca_err(pd->device, "Could not modify SRQ to INIT "
 			 "ehca_qp=%p qp_num=%x h_ret=%li",
 			 my_qp, my_qp->real_qp_num, hret);
 		goto create_srq2;
@@ -872,7 +901,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
 				update_mask,
 				mqpcb, my_qp->galpas.kernel);
 	if (hret != H_SUCCESS) {
-		ehca_err(pd->device, "Could not enable SRQ"
+		ehca_err(pd->device, "Could not enable SRQ "
 			 "ehca_qp=%p qp_num=%x h_ret=%li",
 			 my_qp, my_qp->real_qp_num, hret);
 		goto create_srq2;
@@ -886,7 +915,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
 				update_mask,
 				mqpcb, my_qp->galpas.kernel);
 	if (hret != H_SUCCESS) {
-		ehca_err(pd->device, "Could not modify SRQ to RTR"
+		ehca_err(pd->device, "Could not modify SRQ to RTR "
 			 "ehca_qp=%p qp_num=%x h_ret=%li",
 			 my_qp, my_qp->real_qp_num, hret);
 		goto create_srq2;
@@ -992,7 +1021,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
 	unsigned long flags = 0;
 
 	/* do query_qp to obtain current attr values */
-	mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+	mqpcb = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
 	if (!mqpcb) {
 		ehca_err(ibqp->device, "Could not get zeroed page for mqpcb "
 			 "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num);
@@ -1180,6 +1209,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
 		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
 	}
 	if (attr_mask & IB_QP_PORT) {
+		struct ehca_sport *sport;
+		struct ehca_qp *aqp1;
 		if (attr->port_num < 1 || attr->port_num > shca->num_ports) {
 			ret = -EINVAL;
 			ehca_err(ibqp->device, "Invalid port=%x. "
@@ -1188,6 +1219,29 @@ static int internal_modify_qp(struct ib_qp *ibqp,
 				 shca->num_ports);
 			goto modify_qp_exit2;
 		}
+		sport = &shca->sport[attr->port_num - 1];
+		if (!sport->ibqp_sqp[IB_QPT_GSI]) {
+			/* should not occur */
+			ret = -EFAULT;
+			ehca_err(ibqp->device, "AQP1 was not created for "
+				 "port=%x", attr->port_num);
+			goto modify_qp_exit2;
+		}
+		aqp1 = container_of(sport->ibqp_sqp[IB_QPT_GSI],
+				    struct ehca_qp, ib_qp);
+		if (ibqp->qp_type != IB_QPT_GSI &&
+		    ibqp->qp_type != IB_QPT_SMI &&
+		    aqp1->mod_qp_parm) {
+			/*
+			 * firmware will reject this modify_qp() because
+			 * port is not activated/initialized fully
+			 */
+			ret = -EFAULT;
+			ehca_warn(ibqp->device, "Couldn't modify qp port=%x: "
+				  "either port is being activated (try again) "
+				  "or cabling issue", attr->port_num);
+			goto modify_qp_exit2;
+		}
 		mqpcb->prim_phys_port = attr->port_num;
 		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1);
 	}
@@ -1244,6 +1298,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
 	}
 
 	if (attr_mask & IB_QP_PATH_MTU) {
+		/* store ld(MTU) */
+		my_qp->mtu_shift = attr->path_mtu + 7;
 		mqpcb->path_mtu = attr->path_mtu;
 		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1);
 	}
@@ -1467,6 +1523,8 @@ modify_qp_exit1:
 int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
 		   struct ib_udata *udata)
 {
+	struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
+					      ib_device);
 	struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
 	struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
 					     ib_pd);
@@ -1479,9 +1537,100 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
 		return -EINVAL;
 	}
 
+	/* The if-block below caches qp_attr to be modified for GSI and SMI
+	 * qps during the initialization by ib_mad. When the respective port
+	 * is activated, ie we got an event PORT_ACTIVE, we'll replay the
+	 * cached modify calls sequence, see ehca_recover_sqs() below.
+	 * Why that is required:
+	 * 1) If one port is connected, older code requires that port one
+	 *    to be connected and module option nr_ports=1 to be given by
+	 *    user, which is very inconvenient for end user.
+	 * 2) Firmware accepts modify_qp() only if respective port has become
+	 *    active. Older code had a wait loop of 30sec create_qp()/
+	 *    define_aqp1(), which is not appropriate in practice. This
+	 *    code now removes that wait loop, see define_aqp1(), and always
+	 *    reports all ports to ib_mad resp. users. Only activated ports
+	 *    will then usable for the users.
+	 */
+	if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) {
+		int port = my_qp->init_attr.port_num;
+		struct ehca_sport *sport = &shca->sport[port - 1];
+		unsigned long flags;
+		spin_lock_irqsave(&sport->mod_sqp_lock, flags);
+		/* cache qp_attr only during init */
+		if (my_qp->mod_qp_parm) {
+			struct ehca_mod_qp_parm *p;
+			if (my_qp->mod_qp_parm_idx >= EHCA_MOD_QP_PARM_MAX) {
+				ehca_err(&shca->ib_device,
+					 "mod_qp_parm overflow state=%x port=%x"
+					 " type=%x", attr->qp_state,
+					 my_qp->init_attr.port_num,
+					 ibqp->qp_type);
+				spin_unlock_irqrestore(&sport->mod_sqp_lock,
+						       flags);
+				return -EINVAL;
+			}
+			p = &my_qp->mod_qp_parm[my_qp->mod_qp_parm_idx];
+			p->mask = attr_mask;
+			p->attr = *attr;
+			my_qp->mod_qp_parm_idx++;
+			ehca_dbg(&shca->ib_device,
+				 "Saved qp_attr for state=%x port=%x type=%x",
+				 attr->qp_state, my_qp->init_attr.port_num,
+				 ibqp->qp_type);
+			spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
+			return 0;
+		}
+		spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
+	}
+
 	return internal_modify_qp(ibqp, attr, attr_mask, 0);
 }
 
+void ehca_recover_sqp(struct ib_qp *sqp)
+{
+	struct ehca_qp *my_sqp = container_of(sqp, struct ehca_qp, ib_qp);
+	int port = my_sqp->init_attr.port_num;
+	struct ib_qp_attr attr;
+	struct ehca_mod_qp_parm *qp_parm;
+	int i, qp_parm_idx, ret;
+	unsigned long flags, wr_cnt;
+
+	if (!my_sqp->mod_qp_parm)
+		return;
+	ehca_dbg(sqp->device, "SQP port=%x qp_num=%x", port, sqp->qp_num);
+
+	qp_parm = my_sqp->mod_qp_parm;
+	qp_parm_idx = my_sqp->mod_qp_parm_idx;
+	for (i = 0; i < qp_parm_idx; i++) {
+		attr = qp_parm[i].attr;
+		ret = internal_modify_qp(sqp, &attr, qp_parm[i].mask, 0);
+		if (ret) {
+			ehca_err(sqp->device, "Could not modify SQP port=%x "
+				 "qp_num=%x ret=%x", port, sqp->qp_num, ret);
+			goto free_qp_parm;
+		}
+		ehca_dbg(sqp->device, "SQP port=%x qp_num=%x in state=%x",
+			 port, sqp->qp_num, attr.qp_state);
+	}
+
+	/* re-trigger posted recv wrs */
+	wr_cnt =  my_sqp->ipz_rqueue.current_q_offset /
+		my_sqp->ipz_rqueue.qe_size;
+	if (wr_cnt) {
+		spin_lock_irqsave(&my_sqp->spinlock_r, flags);
+		hipz_update_rqa(my_sqp, wr_cnt);
+		spin_unlock_irqrestore(&my_sqp->spinlock_r, flags);
+		ehca_dbg(sqp->device, "doorbell port=%x qp_num=%x wr_cnt=%lx",
+			 port, sqp->qp_num, wr_cnt);
+	}
+
+free_qp_parm:
+	kfree(qp_parm);
+	/* this prevents subsequent calls to modify_qp() to cache qp_attr */
+	my_sqp->mod_qp_parm = NULL;
+}
+
 int ehca_query_qp(struct ib_qp *qp,
 		  struct ib_qp_attr *qp_attr,
 		  int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
@@ -1769,6 +1918,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
 	struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device);
 	struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
 					     ib_pd);
+	struct ehca_sport *sport = &shca->sport[my_qp->init_attr.port_num - 1];
 	u32 cur_pid = current->tgid;
 	u32 qp_num = my_qp->real_qp_num;
 	int ret;
@@ -1815,6 +1965,14 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
 	port_num = my_qp->init_attr.port_num;
 	qp_type  = my_qp->init_attr.qp_type;
 
+	if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) {
+		spin_lock_irqsave(&sport->mod_sqp_lock, flags);
+		kfree(my_qp->mod_qp_parm);
+		my_qp->mod_qp_parm = NULL;
+		shca->sport[port_num - 1].ibqp_sqp[qp_type] = NULL;
+		spin_unlock_irqrestore(&sport->mod_sqp_lock, flags);
+	}
+
 	/* no support for IB_QPT_SMI yet */
 	if (qp_type == IB_QPT_GSI) {
 		struct ib_event event;
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index ea91360835d3..3aacc8cf1e44 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -50,6 +50,9 @@
 #include "hcp_if.h"
 #include "hipz_fns.h"
 
+/* in RC traffic, insert an empty RDMA READ every this many packets */
+#define ACK_CIRC_THRESHOLD 2000000
+
 static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
 				  struct ehca_wqe *wqe_p,
 				  struct ib_recv_wr *recv_wr)
@@ -81,7 +84,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
 	if (ehca_debug_level) {
 		ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
 			     ipz_rqueue);
-		ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
+		ehca_dmp(wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
 	}
 
 	return 0;
@@ -135,7 +138,8 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
 
 static inline int ehca_write_swqe(struct ehca_qp *qp,
 				  struct ehca_wqe *wqe_p,
-				  const struct ib_send_wr *send_wr)
+				  const struct ib_send_wr *send_wr,
+				  int hidden)
 {
 	u32 idx;
 	u64 dma_length;
@@ -176,7 +180,9 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
 
 	wqe_p->wr_flag = 0;
 
-	if (send_wr->send_flags & IB_SEND_SIGNALED)
+	if ((send_wr->send_flags & IB_SEND_SIGNALED ||
+	    qp->init_attr.sq_sig_type == IB_SIGNAL_ALL_WR)
+	    && !hidden)
 		wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM;
 
 	if (send_wr->opcode == IB_WR_SEND_WITH_IMM ||
@@ -199,7 +205,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
 
 		wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8;
 		wqe_p->local_ee_context_qkey = remote_qkey;
-		if (!send_wr->wr.ud.ah) {
+		if (unlikely(!send_wr->wr.ud.ah)) {
 			ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp);
 			return -EINVAL;
 		}
@@ -255,6 +261,15 @@ static inline int ehca_write_swqe(struct ehca_qp *qp,
 		} /* eof idx */
 		wqe_p->u.nud.atomic_1st_op_dma_len = dma_length;
 
+		/* unsolicited ack circumvention */
+		if (send_wr->opcode == IB_WR_RDMA_READ) {
+			/* on RDMA read, switch on and reset counters */
+			qp->message_count = qp->packet_count = 0;
+			qp->unsol_ack_circ = 1;
+		} else
+			/* else estimate #packets */
+			qp->packet_count += (dma_length >> qp->mtu_shift) + 1;
+
 		break;
 
 	default:
@@ -355,13 +370,49 @@ static inline void map_ib_wc_status(u32 cqe_status,
 		*wc_status = IB_WC_SUCCESS;
 }
 
+static inline int post_one_send(struct ehca_qp *my_qp,
+			 struct ib_send_wr *cur_send_wr,
+			 struct ib_send_wr **bad_send_wr,
+			 int hidden)
+{
+	struct ehca_wqe *wqe_p;
+	int ret;
+	u64 start_offset = my_qp->ipz_squeue.current_q_offset;
+
+	/* get pointer next to free WQE */
+	wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
+	if (unlikely(!wqe_p)) {
+		/* too many posted work requests: queue overflow */
+		if (bad_send_wr)
+			*bad_send_wr = cur_send_wr;
+		ehca_err(my_qp->ib_qp.device, "Too many posted WQEs "
+			 "qp_num=%x", my_qp->ib_qp.qp_num);
+		return -ENOMEM;
+	}
+	/* write a SEND WQE into the QUEUE */
+	ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, hidden);
+	/*
+	 * if something failed,
+	 * reset the free entry pointer to the start value
+	 */
+	if (unlikely(ret)) {
+		my_qp->ipz_squeue.current_q_offset = start_offset;
+		if (bad_send_wr)
+			*bad_send_wr = cur_send_wr;
+		ehca_err(my_qp->ib_qp.device, "Could not write WQE "
+			 "qp_num=%x", my_qp->ib_qp.qp_num);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 int ehca_post_send(struct ib_qp *qp,
 		   struct ib_send_wr *send_wr,
 		   struct ib_send_wr **bad_send_wr)
 {
 	struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
 	struct ib_send_wr *cur_send_wr;
-	struct ehca_wqe *wqe_p;
 	int wqe_cnt = 0;
 	int ret = 0;
 	unsigned long flags;
@@ -369,37 +420,33 @@ int ehca_post_send(struct ib_qp *qp,
 	/* LOCK the QUEUE */
 	spin_lock_irqsave(&my_qp->spinlock_s, flags);
 
+	/* Send an empty extra RDMA read if:
+	 *  1) there has been an RDMA read on this connection before
+	 *  2) no RDMA read occurred for ACK_CIRC_THRESHOLD link packets
+	 *  3) we can be sure that any previous extra RDMA read has been
+	 *     processed so we don't overflow the SQ
+	 */
+	if (unlikely(my_qp->unsol_ack_circ &&
+		     my_qp->packet_count > ACK_CIRC_THRESHOLD &&
+		     my_qp->message_count > my_qp->init_attr.cap.max_send_wr)) {
+		/* insert an empty RDMA READ to fix up the remote QP state */
+		struct ib_send_wr circ_wr;
+		memset(&circ_wr, 0, sizeof(circ_wr));
+		circ_wr.opcode = IB_WR_RDMA_READ;
+		post_one_send(my_qp, &circ_wr, NULL, 1); /* ignore retcode */
+		wqe_cnt++;
+		ehca_dbg(qp->device, "posted circ wr  qp_num=%x", qp->qp_num);
+		my_qp->message_count = my_qp->packet_count = 0;
+	}
+
 	/* loop processes list of send reqs */
 	for (cur_send_wr = send_wr; cur_send_wr != NULL;
 	     cur_send_wr = cur_send_wr->next) {
-		u64 start_offset = my_qp->ipz_squeue.current_q_offset;
-		/* get pointer next to free WQE */
-		wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
-		if (unlikely(!wqe_p)) {
-			/* too many posted work requests: queue overflow */
-			if (bad_send_wr)
-				*bad_send_wr = cur_send_wr;
-			if (wqe_cnt == 0) {
-				ret = -ENOMEM;
-				ehca_err(qp->device, "Too many posted WQEs "
-					 "qp_num=%x", qp->qp_num);
-			}
-			goto post_send_exit0;
-		}
-		/* write a SEND WQE into the QUEUE */
-		ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr);
-		/*
-		 * if something failed,
-		 * reset the free entry pointer to the start value
-		 */
+		ret = post_one_send(my_qp, cur_send_wr, bad_send_wr, 0);
 		if (unlikely(ret)) {
-			my_qp->ipz_squeue.current_q_offset = start_offset;
-			*bad_send_wr = cur_send_wr;
-			if (wqe_cnt == 0) {
-				ret = -EINVAL;
-				ehca_err(qp->device, "Could not write WQE "
-					 "qp_num=%x", qp->qp_num);
-			}
+			/* if one or more WQEs were successful, don't fail */
+			if (wqe_cnt)
+				ret = 0;
 			goto post_send_exit0;
 		}
 		wqe_cnt++;
@@ -410,6 +457,7 @@ int ehca_post_send(struct ib_qp *qp,
 post_send_exit0:
 	iosync(); /* serialize GAL register access */
 	hipz_update_sqa(my_qp, wqe_cnt);
+	my_qp->message_count += wqe_cnt;
 	spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
 	return ret;
 }
diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
index f0792e5fbd02..79e72b25b252 100644
--- a/drivers/infiniband/hw/ehca/ehca_sqp.c
+++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
@@ -40,11 +40,8 @@
  */
 
 
-#include <linux/module.h>
-#include <linux/err.h>
 #include "ehca_classes.h"
 #include "ehca_tools.h"
-#include "ehca_qes.h"
 #include "ehca_iverbs.h"
 #include "hcp_if.h"
 
@@ -93,6 +90,9 @@ u64 ehca_define_sqp(struct ehca_shca *shca,
 		return H_PARAMETER;
 	}
 
+	if (ehca_nr_ports < 0) /* autodetect mode */
+		return H_SUCCESS;
+
 	for (counter = 0;
 	     shca->sport[port - 1].port_state != IB_PORT_ACTIVE &&
 		     counter < ehca_port_act_time;
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
index 851df8a75e79..414621095540 100644
--- a/drivers/infiniband/hw/ipath/ipath_common.h
+++ b/drivers/infiniband/hw/ipath/ipath_common.h
@@ -82,6 +82,16 @@
 #define IPATH_IB_LINK_EXTERNAL	7 /* normal, disable local loopback */
 
 /*
+ * These 3 values (SDR and DDR may be ORed for auto-speed
+ * negotiation) are used for the 3rd argument to path_f_set_ib_cfg
+ * with cmd IPATH_IB_CFG_SPD_ENB, by direct calls or via sysfs.  They
+ * are also the the possible values for ipath_link_speed_enabled and active
+ * The values were chosen to match values used within the IB spec.
+ */
+#define IPATH_IB_SDR 1
+#define IPATH_IB_DDR 2
+
+/*
  * stats maintained by the driver.  For now, at least, this is global
  * to all minor devices.
  */
@@ -433,8 +443,9 @@ struct ipath_user_info {
 #define IPATH_CMD_UNUSED_2	26
 #define IPATH_CMD_PIOAVAILUPD	27	/* force an update of PIOAvail reg */
 #define IPATH_CMD_POLL_TYPE	28	/* set the kind of polling we want */
+#define IPATH_CMD_ARMLAUNCH_CTRL	29 /* armlaunch detection control */
 
-#define IPATH_CMD_MAX		28
+#define IPATH_CMD_MAX		29
 
 /*
  * Poll types
@@ -477,6 +488,8 @@ struct ipath_cmd {
 		__u64 port_info;
 		/* enable/disable receipt of packets */
 		__u32 recv_ctrl;
+		/* enable/disable armlaunch errors (non-zero to enable) */
+		__u32 armlaunch_ctrl;
 		/* partition key to set */
 		__u16 part_key;
 		/* user address of __u32 bitmask of active slaves */
@@ -579,7 +592,7 @@ struct ipath_flash {
 struct infinipath_counters {
 	__u64 LBIntCnt;
 	__u64 LBFlowStallCnt;
-	__u64 Reserved1;
+	__u64 TxSDmaDescCnt;	/* was Reserved1 */
 	__u64 TxUnsupVLErrCnt;
 	__u64 TxDataPktCnt;
 	__u64 TxFlowPktCnt;
@@ -615,12 +628,26 @@ struct infinipath_counters {
 	__u64 RxP6HdrEgrOvflCnt;
 	__u64 RxP7HdrEgrOvflCnt;
 	__u64 RxP8HdrEgrOvflCnt;
-	__u64 Reserved6;
-	__u64 Reserved7;
+	__u64 RxP9HdrEgrOvflCnt;	/* was Reserved6 */
+	__u64 RxP10HdrEgrOvflCnt;	/* was Reserved7 */
+	__u64 RxP11HdrEgrOvflCnt;	/* new for IBA7220 */
+	__u64 RxP12HdrEgrOvflCnt;	/* new for IBA7220 */
+	__u64 RxP13HdrEgrOvflCnt;	/* new for IBA7220 */
+	__u64 RxP14HdrEgrOvflCnt;	/* new for IBA7220 */
+	__u64 RxP15HdrEgrOvflCnt;	/* new for IBA7220 */
+	__u64 RxP16HdrEgrOvflCnt;	/* new for IBA7220 */
 	__u64 IBStatusChangeCnt;
 	__u64 IBLinkErrRecoveryCnt;
 	__u64 IBLinkDownedCnt;
 	__u64 IBSymbolErrCnt;
+	/* The following are new for IBA7220 */
+	__u64 RxVL15DroppedPktCnt;
+	__u64 RxOtherLocalPhyErrCnt;
+	__u64 PcieRetryBufDiagQwordCnt;
+	__u64 ExcessBufferOvflCnt;
+	__u64 LocalLinkIntegrityErrCnt;
+	__u64 RxVlErrCnt;
+	__u64 RxDlidFltrCnt;
 };
 
 /*
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
index d1380c7a1703..a03bd28d9b48 100644
--- a/drivers/infiniband/hw/ipath/ipath_cq.c
+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
@@ -421,7 +421,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
 	else
 		n = head - tail;
 	if (unlikely((u32)cqe < n)) {
-		ret = -EOVERFLOW;
+		ret = -EINVAL;
 		goto bail_unlock;
 	}
 	for (n = 0; tail != head; n++) {
diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h
index 19c56e6491eb..d6f69532d83f 100644
--- a/drivers/infiniband/hw/ipath/ipath_debug.h
+++ b/drivers/infiniband/hw/ipath/ipath_debug.h
@@ -55,7 +55,7 @@
 #define __IPATH_PKTDBG      0x80	/* print packet data */
 /* print process startup (init)/exit messages */
 #define __IPATH_PROCDBG     0x100
-/* print mmap/nopage stuff, not using VDBG any more */
+/* print mmap/fault stuff, not using VDBG any more */
 #define __IPATH_MMDBG       0x200
 #define __IPATH_ERRPKTDBG   0x400
 #define __IPATH_USER_SEND   0x1000	/* use user mode send */
@@ -81,7 +81,7 @@
 #define __IPATH_VERBDBG   0x0	/* very verbose debug */
 #define __IPATH_PKTDBG    0x0	/* print packet data */
 #define __IPATH_PROCDBG   0x0	/* process startup (init)/exit messages */
-/* print mmap/nopage stuff, not using VDBG any more */
+/* print mmap/fault stuff, not using VDBG any more */
 #define __IPATH_MMDBG     0x0
 #define __IPATH_EPKTDBG   0x0	/* print ethernet packet data */
 #define __IPATH_IPATHDBG  0x0	/* Ethernet (IPATH) table dump on */
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 1f152ded1e3c..d5ff6ca2db30 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -121,6 +121,9 @@ static struct pci_driver ipath_driver = {
 	.probe = ipath_init_one,
 	.remove = __devexit_p(ipath_remove_one),
 	.id_table = ipath_pci_tbl,
+	.driver = {
+		.groups = ipath_driver_attr_groups,
+	},
 };
 
 static void ipath_check_status(struct work_struct *work)
@@ -331,6 +334,8 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
 		udelay(1);
 	}
 
+	ipath_disable_armlaunch(dd);
+
 	writeq(0, piobuf); /* length 0, no dwords actually sent */
 	ipath_flush_wc();
 
@@ -362,6 +367,7 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd)
 done:
 	/* disarm piobuf, so it's available again */
 	ipath_disarm_piobufs(dd, pbnum, 1);
+	ipath_enable_armlaunch(dd);
 }
 
 static int __devinit ipath_init_one(struct pci_dev *pdev,
@@ -800,31 +806,37 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
 			  unsigned cnt)
 {
 	unsigned i, last = first + cnt;
-	u64 sendctrl, sendorig;
+	unsigned long flags;
 
 	ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first);
-	sendorig = dd->ipath_sendctrl;
 	for (i = first; i < last; i++) {
-		sendctrl = sendorig  | INFINIPATH_S_DISARM |
-			(i << INFINIPATH_S_DISARMPIOBUF_SHIFT);
+		spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+		/*
+		 * The disarm-related bits are write-only, so it
+		 * is ok to OR them in with our copy of sendctrl
+		 * while we hold the lock.
+		 */
 		ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-				 sendctrl);
+			dd->ipath_sendctrl | INFINIPATH_S_DISARM |
+			(i << INFINIPATH_S_DISARMPIOBUF_SHIFT));
+		/* can't disarm bufs back-to-back per iba7220 spec */
+		ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+		spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 	}
 
 	/*
-	 * Write it again with current value, in case ipath_sendctrl changed
-	 * while we were looping; no critical bits that would require
-	 * locking.
-	 *
-	 * disable PIOAVAILUPD, then re-enable, reading scratch in
+	 * Disable PIOAVAILUPD, then re-enable, reading scratch in
 	 * between.  This seems to avoid a chip timing race that causes
-	 * pioavail updates to memory to stop.
+	 * pioavail updates to memory to stop.  We xor as we don't
+	 * know the state of the bit when we're called.
 	 */
+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-			 sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD);
-	sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+		dd->ipath_sendctrl ^ INFINIPATH_S_PIOBUFAVAILUPD);
+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
 			 dd->ipath_sendctrl);
+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 }
 
 /**
@@ -1000,12 +1012,10 @@ static void get_rhf_errstring(u32 err, char *msg, size_t len)
  * ipath_get_egrbuf - get an eager buffer
  * @dd: the infinipath device
  * @bufnum: the eager buffer to get
- * @err: unused
  *
  * must only be called if ipath_pd[port] is known to be allocated
  */
-static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum,
-				     int err)
+static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum)
 {
 	return dd->ipath_port0_skbinfo ?
 		(void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL;
@@ -1097,13 +1107,14 @@ static void ipath_rcv_hdrerr(struct ipath_devdata *dd,
 
 /*
  * ipath_kreceive - receive a packet
- * @dd: the infinipath device
+ * @pd: the infinipath port
  *
  * called from interrupt handler for errors or receive interrupt
  */
-void ipath_kreceive(struct ipath_devdata *dd)
+void ipath_kreceive(struct ipath_portdata *pd)
 {
 	u64 *rc;
+	struct ipath_devdata *dd = pd->port_dd;
 	void *ebuf;
 	const u32 rsize = dd->ipath_rcvhdrentsize;	/* words */
 	const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize;	/* words */
@@ -1118,8 +1129,8 @@ void ipath_kreceive(struct ipath_devdata *dd)
 		goto bail;
 	}
 
-	l = dd->ipath_port0head;
-	hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr);
+	l = pd->port_head;
+	hdrqtail = ipath_get_rcvhdrtail(pd);
 	if (l == hdrqtail)
 		goto bail;
 
@@ -1128,7 +1139,7 @@ reloop:
 		u32 qp;
 		u8 *bthbytes;
 
-		rc = (u64 *) (dd->ipath_pd[0]->port_rcvhdrq + (l << 2));
+		rc = (u64 *) (pd->port_rcvhdrq + (l << 2));
 		hdr = (struct ipath_message_header *)&rc[1];
 		/*
 		 * could make a network order version of IPATH_KD_QP, and
@@ -1153,7 +1164,7 @@ reloop:
 			etail = ipath_hdrget_index((__le32 *) rc);
 			if (tlen > sizeof(*hdr) ||
 			    etype == RCVHQ_RCV_TYPE_NON_KD)
-				ebuf = ipath_get_egrbuf(dd, etail, 0);
+				ebuf = ipath_get_egrbuf(dd, etail);
 		}
 
 		/*
@@ -1188,7 +1199,7 @@ reloop:
 				  be32_to_cpu(hdr->bth[0]) & 0xff);
 		else {
 			/*
-			 * error packet, type of error	unknown.
+			 * error packet, type of error unknown.
 			 * Probably type 3, but we don't know, so don't
 			 * even try to print the opcode, etc.
 			 */
@@ -1238,7 +1249,7 @@ reloop:
 		 * earlier packets, we "almost" guarantee we have covered
 		 * that case.
 		 */
-		u32 hqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
+		u32 hqtail = ipath_get_rcvhdrtail(pd);
 		if (hqtail != hdrqtail) {
 			hdrqtail = hqtail;
 			reloop = 1; /* loop 1 extra time at most */
@@ -1248,7 +1259,7 @@ reloop:
 
 	pkttot += i;
 
-	dd->ipath_port0head = l;
+	pd->port_head = l;
 
 	if (pkttot > ipath_stats.sps_maxpkts_call)
 		ipath_stats.sps_maxpkts_call = pkttot;
@@ -1332,14 +1343,9 @@ static void ipath_update_pio_bufs(struct ipath_devdata *dd)
 		/*
 		 * Chip Errata: bug 6641; even and odd qwords>3 are swapped
 		 */
-		if (i > 3) {
-			if (i & 1)
-				piov = le64_to_cpu(
-					dd->ipath_pioavailregs_dma[i - 1]);
-			else
-				piov = le64_to_cpu(
-					dd->ipath_pioavailregs_dma[i + 1]);
-		} else
+		if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
+			piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i ^ 1]);
+		else
 			piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i]);
 		pchg = _IPATH_ALL_CHECKBITS &
 			~(dd->ipath_pioavailshadow[i] ^ piov);
@@ -1598,7 +1604,8 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
 
 	/* clear for security and sanity on each use */
 	memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size);
-	memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
+	if (pd->port_rcvhdrtail_kvaddr)
+		memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
 
 	/*
 	 * tell chip each time we init it, even if we are re-using previous
@@ -1614,77 +1621,6 @@ bail:
 	return ret;
 }
 
-int ipath_waitfor_complete(struct ipath_devdata *dd, ipath_kreg reg_id,
-			   u64 bits_to_wait_for, u64 * valp)
-{
-	unsigned long timeout;
-	u64 lastval, val;
-	int ret;
-
-	lastval = ipath_read_kreg64(dd, reg_id);
-	/* wait a ridiculously long time */
-	timeout = jiffies + msecs_to_jiffies(5);
-	do {
-		val = ipath_read_kreg64(dd, reg_id);
-		/* set so they have something, even on failures. */
-		*valp = val;
-		if ((val & bits_to_wait_for) == bits_to_wait_for) {
-			ret = 0;
-			break;
-		}
-		if (val != lastval)
-			ipath_cdbg(VERBOSE, "Changed from %llx to %llx, "
-				   "waiting for %llx bits\n",
-				   (unsigned long long) lastval,
-				   (unsigned long long) val,
-				   (unsigned long long) bits_to_wait_for);
-		cond_resched();
-		if (time_after(jiffies, timeout)) {
-			ipath_dbg("Didn't get bits %llx in register 0x%x, "
-				  "got %llx\n",
-				  (unsigned long long) bits_to_wait_for,
-				  reg_id, (unsigned long long) *valp);
-			ret = -ENODEV;
-			break;
-		}
-	} while (1);
-
-	return ret;
-}
-
-/**
- * ipath_waitfor_mdio_cmdready - wait for last command to complete
- * @dd: the infinipath device
- *
- * Like ipath_waitfor_complete(), but we wait for the CMDVALID bit to go
- * away indicating the last command has completed.  It doesn't return data
- */
-int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd)
-{
-	unsigned long timeout;
-	u64 val;
-	int ret;
-
-	/* wait a ridiculously long time */
-	timeout = jiffies + msecs_to_jiffies(5);
-	do {
-		val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_mdio);
-		if (!(val & IPATH_MDIO_CMDVALID)) {
-			ret = 0;
-			break;
-		}
-		cond_resched();
-		if (time_after(jiffies, timeout)) {
-			ipath_dbg("CMDVALID stuck in mdio reg? (%llx)\n",
-				  (unsigned long long) val);
-			ret = -ENODEV;
-			break;
-		}
-	} while (1);
-
-	return ret;
-}
-
 
 /*
  * Flush all sends that might be in the ready to send state, as well as any
@@ -2053,6 +1989,8 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val)
  */
 void ipath_shutdown_device(struct ipath_devdata *dd)
 {
+	unsigned long flags;
+
 	ipath_dbg("Shutting down the device\n");
 
 	dd->ipath_flags |= IPATH_LINKUNK;
@@ -2073,9 +2011,13 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
 	 * gracefully stop all sends allowing any in progress to trickle out
 	 * first.
 	 */
-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL);
+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+	dd->ipath_sendctrl = 0;
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
 	/* flush it */
 	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+
 	/*
 	 * enough for anything that's going to trickle out to have actually
 	 * done so.
@@ -2217,25 +2159,15 @@ static int __init infinipath_init(void)
 		goto bail_unit;
 	}
 
-	ret = ipath_driver_create_group(&ipath_driver.driver);
-	if (ret < 0) {
-		printk(KERN_ERR IPATH_DRV_NAME ": Unable to create driver "
-		       "sysfs entries: error %d\n", -ret);
-		goto bail_pci;
-	}
-
 	ret = ipath_init_ipathfs();
 	if (ret < 0) {
 		printk(KERN_ERR IPATH_DRV_NAME ": Unable to create "
 		       "ipathfs: error %d\n", -ret);
-		goto bail_group;
+		goto bail_pci;
 	}
 
 	goto bail;
 
-bail_group:
-	ipath_driver_remove_group(&ipath_driver.driver);
-
 bail_pci:
 	pci_unregister_driver(&ipath_driver);
 
@@ -2250,8 +2182,6 @@ static void __exit infinipath_cleanup(void)
 {
 	ipath_exit_ipathfs();
 
-	ipath_driver_remove_group(&ipath_driver.driver);
-
 	ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
 	pci_unregister_driver(&ipath_driver);
 
@@ -2344,5 +2274,34 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv)
 	}
 	return 0;
 }
+
+/*
+ * Disable and enable the armlaunch error.  Used for PIO bandwidth testing on
+ * the 7220, which is count-based, rather than trigger-based.  Safe for the
+ * driver check, since it's at init.   Not completely safe when used for
+ * user-mode checking, since some error checking can be lost, but not
+ * particularly risky, and only has problematic side-effects in the face of
+ * very buggy user code.  There is no reference counting, but that's also
+ * fine, given the intended use.
+ */
+void ipath_enable_armlaunch(struct ipath_devdata *dd)
+{
+	dd->ipath_lasterror &= ~INFINIPATH_E_SPIOARMLAUNCH;
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
+		INFINIPATH_E_SPIOARMLAUNCH);
+	dd->ipath_errormask |= INFINIPATH_E_SPIOARMLAUNCH;
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
+		dd->ipath_errormask);
+}
+
+void ipath_disable_armlaunch(struct ipath_devdata *dd)
+{
+	/* so don't re-enable if already set */
+	dd->ipath_maskederrs &= ~INFINIPATH_E_SPIOARMLAUNCH;
+	dd->ipath_errormask &= ~INFINIPATH_E_SPIOARMLAUNCH;
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
+		dd->ipath_errormask);
+}
+
 module_init(infinipath_init);
 module_exit(infinipath_cleanup);
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
index e7c25dbbcdc9..e28a42f53769 100644
--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
+++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
@@ -510,10 +510,10 @@ int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset,
 {
 	int ret;
 
-	ret = down_interruptible(&dd->ipath_eep_sem);
+	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
 	if (!ret) {
 		ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len);
-		up(&dd->ipath_eep_sem);
+		mutex_unlock(&dd->ipath_eep_lock);
 	}
 
 	return ret;
@@ -524,10 +524,10 @@ int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset,
 {
 	int ret;
 
-	ret = down_interruptible(&dd->ipath_eep_sem);
+	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
 	if (!ret) {
 		ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len);
-		up(&dd->ipath_eep_sem);
+		mutex_unlock(&dd->ipath_eep_lock);
 	}
 
 	return ret;
@@ -574,7 +574,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
 	struct ipath_devdata *dd0 = ipath_lookup(0);
 
 	if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) {
-		u8 *bguid, oguid;
+		u8 oguid;
 		dd->ipath_guid = dd0->ipath_guid;
 		bguid = (u8 *) & dd->ipath_guid;
 
@@ -616,9 +616,9 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
 		goto bail;
 	}
 
-	down(&dd->ipath_eep_sem);
+	mutex_lock(&dd->ipath_eep_lock);
 	eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len);
-	up(&dd->ipath_eep_sem);
+	mutex_unlock(&dd->ipath_eep_lock);
 
 	if (eep_stat) {
 		ipath_dev_err(dd, "Failed reading GUID from eeprom\n");
@@ -674,7 +674,6 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
 		 * elsewhere for backward-compatibility.
 		 */
 		char *snp = dd->ipath_serial;
-		int len;
 		memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
 		snp[sizeof ifp->if_sprefix] = '\0';
 		len = strlen(snp);
@@ -764,14 +763,14 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
 	/* Grab semaphore and read current EEPROM. If we get an
 	 * error, let go, but if not, keep it until we finish write.
 	 */
-	ret = down_interruptible(&dd->ipath_eep_sem);
+	ret = mutex_lock_interruptible(&dd->ipath_eep_lock);
 	if (ret) {
 		ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n");
 		goto free_bail;
 	}
 	ret = ipath_eeprom_internal_read(dd, 0, buf, len);
 	if (ret) {
-		up(&dd->ipath_eep_sem);
+		mutex_unlock(&dd->ipath_eep_lock);
 		ipath_dev_err(dd, "Unable read EEPROM for logging\n");
 		goto free_bail;
 	}
@@ -779,7 +778,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
 
 	csum = flash_csum(ifp, 0);
 	if (csum != ifp->if_csum) {
-		up(&dd->ipath_eep_sem);
+		mutex_unlock(&dd->ipath_eep_lock);
 		ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
 				csum, ifp->if_csum);
 		ret = 1;
@@ -849,7 +848,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
 		csum = flash_csum(ifp, 1);
 		ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1);
 	}
-	up(&dd->ipath_eep_sem);
+	mutex_unlock(&dd->ipath_eep_lock);
 	if (ret)
 		ipath_dev_err(dd, "Failed updating EEPROM\n");
 
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 5de3243a47c3..7e025c8e01b6 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -169,7 +169,7 @@ static int ipath_get_base_info(struct file *fp,
 		kinfo->spi_piocnt = dd->ipath_pbufsport;
 		kinfo->spi_piobufbase = (u64) pd->port_piobufs;
 		kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
-			dd->ipath_palign * pd->port_port;
+			dd->ipath_ureg_align * pd->port_port;
 	} else if (master) {
 		kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) +
 				    (dd->ipath_pbufsport % subport_cnt);
@@ -186,7 +186,7 @@ static int ipath_get_base_info(struct file *fp,
 	}
 	if (shared) {
 		kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase +
-			dd->ipath_palign * pd->port_port;
+			dd->ipath_ureg_align * pd->port_port;
 		kinfo->spi_port_rcvegrbuf = kinfo->spi_rcv_egrbufs;
 		kinfo->spi_port_rcvhdr_base = kinfo->spi_rcvhdr_base;
 		kinfo->spi_port_rcvhdr_tailaddr = kinfo->spi_rcvhdr_tailaddr;
@@ -742,11 +742,12 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
 		 * updated and correct itself, even in the face of software
 		 * bugs.
 		 */
-		*(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0;
-		set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
+		if (pd->port_rcvhdrtail_kvaddr)
+			ipath_clear_rcvhdrtail(pd);
+		set_bit(dd->ipath_r_portenable_shift + pd->port_port,
 			&dd->ipath_rcvctrl);
 	} else
-		clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
+		clear_bit(dd->ipath_r_portenable_shift + pd->port_port,
 			  &dd->ipath_rcvctrl);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
 			 dd->ipath_rcvctrl);
@@ -881,7 +882,7 @@ static int ipath_create_user_egr(struct ipath_portdata *pd)
 
 	egrcnt = dd->ipath_rcvegrcnt;
 	/* TID number offset for this port */
-	egroff = pd->port_port * egrcnt;
+	egroff = (pd->port_port - 1) * egrcnt + dd->ipath_p0_rcvegrcnt;
 	egrsize = dd->ipath_rcvegrbufsize;
 	ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid "
 		   "offset %x, egrsize %u\n", egrcnt, egroff, egrsize);
@@ -1049,11 +1050,6 @@ static int mmap_piobufs(struct vm_area_struct *vma,
 
 	phys = dd->ipath_physaddr + piobufs;
 
-	/*
-	 * Don't mark this as non-cached, or we don't get the
-	 * write combining behavior we want on the PIO buffers!
-	 */
-
 #if defined(__powerpc__)
 	/* There isn't a generic way to specify writethrough mappings */
 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
@@ -1120,33 +1116,24 @@ bail:
 }
 
 /*
- * ipath_file_vma_nopage - handle a VMA page fault.
+ * ipath_file_vma_fault - handle a VMA page fault.
  */
-static struct page *ipath_file_vma_nopage(struct vm_area_struct *vma,
-					  unsigned long address, int *type)
+static int ipath_file_vma_fault(struct vm_area_struct *vma,
+					struct vm_fault *vmf)
 {
-	unsigned long offset = address - vma->vm_start;
-	struct page *page = NOPAGE_SIGBUS;
-	void *pageptr;
+	struct page *page;
 
-	/*
-	 * Convert the vmalloc address into a struct page.
-	 */
-	pageptr = (void *)(offset + (vma->vm_pgoff << PAGE_SHIFT));
-	page = vmalloc_to_page(pageptr);
+	page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT));
 	if (!page)
-		goto out;
-
-	/* Increment the reference count. */
+		return VM_FAULT_SIGBUS;
 	get_page(page);
-	if (type)
-		*type = VM_FAULT_MINOR;
-out:
-	return page;
+	vmf->page = page;
+
+	return 0;
 }
 
 static struct vm_operations_struct ipath_file_vm_ops = {
-	.nopage = ipath_file_vma_nopage,
+	.fault = ipath_file_vma_fault,
 };
 
 static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
@@ -1284,7 +1271,7 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
 		goto bail;
 	}
 
-	ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
+	ureg = dd->ipath_uregbase + dd->ipath_ureg_align * pd->port_port;
 	if (!pd->port_subport_cnt) {
 		/* port is not shared */
 		piocnt = dd->ipath_pbufsport;
@@ -1400,7 +1387,10 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
 	pollflag = ipath_poll_hdrqfull(pd);
 
 	head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
-	tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
+	if (pd->port_rcvhdrtail_kvaddr)
+		tail = ipath_get_rcvhdrtail(pd);
+	else
+		tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
 
 	if (head != tail)
 		pollflag |= POLLIN | POLLRDNORM;
@@ -1410,7 +1400,7 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
 		/* flush waiting flag so we don't miss an event */
 		wmb();
 
-		set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
+		set_bit(pd->port_port + dd->ipath_r_intravail_shift,
 			&dd->ipath_rcvctrl);
 
 		ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
@@ -1790,6 +1780,7 @@ static int find_shared_port(struct file *fp,
 			}
 			port_fp(fp) = pd;
 			subport_fp(fp) = pd->port_cnt++;
+			pd->port_subpid[subport_fp(fp)] = current->pid;
 			tidcursor_fp(fp) = 0;
 			pd->active_slaves |= 1 << subport_fp(fp);
 			ipath_cdbg(PROC,
@@ -1920,8 +1911,7 @@ static int ipath_do_user_init(struct file *fp,
 	 */
 	head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
 	ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
-	dd->ipath_lastegrheads[pd->port_port] = -1;
-	dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
+	pd->port_lastrcvhdrqtail = -1;
 	ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
 		pd->port_port, head32);
 	pd->port_tidcursor = 0;	/* start at beginning after open */
@@ -1941,11 +1931,13 @@ static int ipath_do_user_init(struct file *fp,
 	 * We explictly set the in-memory copy to 0 beforehand, so we don't
 	 * have to wait to be sure the DMA update has happened.
 	 */
-	*(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0ULL;
-	set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
+	if (pd->port_rcvhdrtail_kvaddr)
+		ipath_clear_rcvhdrtail(pd);
+	set_bit(dd->ipath_r_portenable_shift + pd->port_port,
 		&dd->ipath_rcvctrl);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
-			 dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
+			dd->ipath_rcvctrl &
+			~(1ULL << dd->ipath_r_tailupd_shift));
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
 			 dd->ipath_rcvctrl);
 	/* Notify any waiting slaves */
@@ -2022,6 +2014,7 @@ static int ipath_close(struct inode *in, struct file *fp)
 		 * the slave(s) don't wait for receive data forever.
 		 */
 		pd->active_slaves &= ~(1 << fd->subport);
+		pd->port_subpid[fd->subport] = 0;
 		mutex_unlock(&ipath_mutex);
 		goto bail;
 	}
@@ -2054,9 +2047,9 @@ static int ipath_close(struct inode *in, struct file *fp)
 	if (dd->ipath_kregbase) {
 		int i;
 		/* atomically clear receive enable port and intr avail. */
-		clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
+		clear_bit(dd->ipath_r_portenable_shift + port,
 			  &dd->ipath_rcvctrl);
-		clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
+		clear_bit(pd->port_port + dd->ipath_r_intravail_shift,
 			  &dd->ipath_rcvctrl);
 		ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
 			dd->ipath_rcvctrl);
@@ -2149,11 +2142,15 @@ static int ipath_get_slave_info(struct ipath_portdata *pd,
 
 static int ipath_force_pio_avail_update(struct ipath_devdata *dd)
 {
-	u64 reg = dd->ipath_sendctrl;
+	unsigned long flags;
 
-	clear_bit(IPATH_S_PIOBUFAVAILUPD, &reg);
-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, reg);
+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+		dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
 	return 0;
 }
@@ -2227,6 +2224,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
 		dest = &cmd.cmd.poll_type;
 		src = &ucmd->cmd.poll_type;
 		break;
+	case IPATH_CMD_ARMLAUNCH_CTRL:
+		copy = sizeof(cmd.cmd.armlaunch_ctrl);
+		dest = &cmd.cmd.armlaunch_ctrl;
+		src = &ucmd->cmd.armlaunch_ctrl;
+		break;
 	default:
 		ret = -EINVAL;
 		goto bail;
@@ -2302,6 +2304,12 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
 	case IPATH_CMD_POLL_TYPE:
 		pd->poll_type = cmd.cmd.poll_type;
 		break;
+	case IPATH_CMD_ARMLAUNCH_CTRL:
+		if (cmd.cmd.armlaunch_ctrl)
+			ipath_enable_armlaunch(pd->port_dd);
+		else
+			ipath_disable_armlaunch(pd->port_dd);
+		break;
 	}
 
 	if (ret >= 0)
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index 262c25db05cd..23faba9d21eb 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -108,21 +108,16 @@ static const struct file_operations atomic_stats_ops = {
 	.read = atomic_stats_read,
 };
 
-#define NUM_COUNTERS sizeof(struct infinipath_counters) / sizeof(u64)
-
 static ssize_t atomic_counters_read(struct file *file, char __user *buf,
 				    size_t count, loff_t *ppos)
 {
-	u64 counters[NUM_COUNTERS];
-	u16 i;
+	struct infinipath_counters counters;
 	struct ipath_devdata *dd;
 
 	dd = file->f_path.dentry->d_inode->i_private;
+	dd->ipath_f_read_counters(dd, &counters);
 
-	for (i = 0; i < NUM_COUNTERS; i++)
-		counters[i] = ipath_snap_cntr(dd, i);
-
-	return simple_read_from_buffer(buf, count, ppos, counters,
+	return simple_read_from_buffer(buf, count, ppos, &counters,
 				       sizeof counters);
 }
 
@@ -243,8 +238,7 @@ static int create_device_files(struct super_block *sb,
 
 	snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
 	ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
-			  (struct file_operations *) &simple_dir_operations,
-			  dd);
+			  &simple_dir_operations, dd);
 	if (ret) {
 		printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret);
 		goto bail;
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index ddbebe4bdb27..9e2ced3cdc5e 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -148,10 +148,57 @@ struct _infinipath_do_not_use_kernel_regs {
 	unsigned long long ReservedSW2[4];
 };
 
-#define IPATH_KREG_OFFSET(field) (offsetof(struct \
-    _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
+struct _infinipath_do_not_use_counters {
+	__u64 LBIntCnt;
+	__u64 LBFlowStallCnt;
+	__u64 Reserved1;
+	__u64 TxUnsupVLErrCnt;
+	__u64 TxDataPktCnt;
+	__u64 TxFlowPktCnt;
+	__u64 TxDwordCnt;
+	__u64 TxLenErrCnt;
+	__u64 TxMaxMinLenErrCnt;
+	__u64 TxUnderrunCnt;
+	__u64 TxFlowStallCnt;
+	__u64 TxDroppedPktCnt;
+	__u64 RxDroppedPktCnt;
+	__u64 RxDataPktCnt;
+	__u64 RxFlowPktCnt;
+	__u64 RxDwordCnt;
+	__u64 RxLenErrCnt;
+	__u64 RxMaxMinLenErrCnt;
+	__u64 RxICRCErrCnt;
+	__u64 RxVCRCErrCnt;
+	__u64 RxFlowCtrlErrCnt;
+	__u64 RxBadFormatCnt;
+	__u64 RxLinkProblemCnt;
+	__u64 RxEBPCnt;
+	__u64 RxLPCRCErrCnt;
+	__u64 RxBufOvflCnt;
+	__u64 RxTIDFullErrCnt;
+	__u64 RxTIDValidErrCnt;
+	__u64 RxPKeyMismatchCnt;
+	__u64 RxP0HdrEgrOvflCnt;
+	__u64 RxP1HdrEgrOvflCnt;
+	__u64 RxP2HdrEgrOvflCnt;
+	__u64 RxP3HdrEgrOvflCnt;
+	__u64 RxP4HdrEgrOvflCnt;
+	__u64 RxP5HdrEgrOvflCnt;
+	__u64 RxP6HdrEgrOvflCnt;
+	__u64 RxP7HdrEgrOvflCnt;
+	__u64 RxP8HdrEgrOvflCnt;
+	__u64 Reserved6;
+	__u64 Reserved7;
+	__u64 IBStatusChangeCnt;
+	__u64 IBLinkErrRecoveryCnt;
+	__u64 IBLinkDownedCnt;
+	__u64 IBSymbolErrCnt;
+};
+
+#define IPATH_KREG_OFFSET(field) (offsetof( \
+	struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
 #define IPATH_CREG_OFFSET(field) (offsetof( \
-    struct infinipath_counters, field) / sizeof(u64))
+	struct _infinipath_do_not_use_counters, field) / sizeof(u64))
 
 static const struct ipath_kregs ipath_ht_kregs = {
 	.kr_control = IPATH_KREG_OFFSET(Control),
@@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_ht_cregs = {
 #define INFINIPATH_HWE_HTAPLL_RFSLIP        0x1000000000000000ULL
 #define INFINIPATH_HWE_SERDESPLLFAILED      0x2000000000000000ULL
 
+#define IBA6110_IBCS_LINKTRAININGSTATE_MASK 0xf
+#define IBA6110_IBCS_LINKSTATE_SHIFT 4
+
 /* kr_extstatus bits */
 #define INFINIPATH_EXTS_FREQSEL 0x2
 #define INFINIPATH_EXTS_SERDESSEL 0x4
@@ -296,6 +346,12 @@ static const struct ipath_cregs ipath_ht_cregs = {
 #define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL
 #define INFINIPATH_RT_BUFSIZE_SHIFT 48
 
+#define INFINIPATH_R_INTRAVAIL_SHIFT 16
+#define INFINIPATH_R_TAILUPD_SHIFT 31
+
+/* kr_xgxsconfig bits */
+#define INFINIPATH_XGXS_RESET          0x7ULL
+
 /*
  * masks and bits that are different in different chips, or present only
  * in one
@@ -652,7 +708,6 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
 			      "with ID %u\n", boardrev);
 		snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
 			 boardrev);
-		ret = 1;
 		break;
 	}
 	if (n)
@@ -686,6 +741,13 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
 			      dd->ipath_htspeed);
 	ret = 0;
 
+	/*
+	 * set here, not in ipath_init_*_funcs because we have to do
+	 * it after we can read chip registers.
+	 */
+	dd->ipath_ureg_align =
+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
+
 bail:
 	return ret;
 }
@@ -969,7 +1031,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
 	do {
 		u8 cap_type;
 
-		/* the HT capability type byte is 3 bytes after the
+		/*
+		 * The HT capability type byte is 3 bytes after the
 		 * capability byte.
 		 */
 		if (pci_read_config_byte(pdev, pos + 3, &cap_type)) {
@@ -982,6 +1045,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
 	} while ((pos = pci_find_next_capability(pdev, pos,
 						 PCI_CAP_ID_HT)));
 
+	dd->ipath_flags |= IPATH_SWAP_PIOBUFS;
+
 bail:
 	return ret;
 }
@@ -1074,11 +1139,55 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
 
 static void ipath_init_ht_variables(struct ipath_devdata *dd)
 {
+	/*
+	 * setup the register offsets, since they are different for each
+	 * chip
+	 */
+	dd->ipath_kregs = &ipath_ht_kregs;
+	dd->ipath_cregs = &ipath_ht_cregs;
+
 	dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
 	dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
 	dd->ipath_gpio_sda = IPATH_GPIO_SDA;
 	dd->ipath_gpio_scl = IPATH_GPIO_SCL;
 
+	/*
+	 * Fill in data for field-values that change in newer chips.
+	 * We dynamically specify only the mask for LINKTRAININGSTATE
+	 * and only the shift for LINKSTATE, as they are the only ones
+	 * that change.  Also precalculate the 3 link states of interest
+	 * and the combined mask.
+	 */
+	dd->ibcs_ls_shift = IBA6110_IBCS_LINKSTATE_SHIFT;
+	dd->ibcs_lts_mask = IBA6110_IBCS_LINKTRAININGSTATE_MASK;
+	dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
+		dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
+	dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+		(INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
+	dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+		(INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
+	dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+		(INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
+
+	/*
+	 * Fill in data for ibcc field-values that change in newer chips.
+	 * We dynamically specify only the mask for LINKINITCMD
+	 * and only the shift for LINKCMD and MAXPKTLEN, as they are
+	 * the only ones that change.
+	 */
+	dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
+	dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
+	dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
+
+	/* Fill in shifts for RcvCtrl. */
+	dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
+	dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
+	dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
+	dd->ipath_r_portcfg_shift = 0; /* Not on IBA6110 */
+
 	dd->ipath_i_bitsextant =
 		(INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
 		(INFINIPATH_I_RCVAVAIL_MASK <<
@@ -1135,6 +1244,8 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
 
 	dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
 	dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+	dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
+	dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
 
 	/*
 	 * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
@@ -1148,9 +1259,17 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
 		INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
 		INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT;
 
-	dd->ipath_eep_st_masks[2].errs_to_log =
-		INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
+	dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_RESET;
 
+	dd->delay_mult = 2; /* SDR, 4X, can't change */
+
+	dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
+	dd->ipath_link_speed_supported = IPATH_IB_SDR;
+	dd->ipath_link_width_enabled = IB_WIDTH_4X;
+	dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
+	/* these can't change for this chip, so set once */
+	dd->ipath_link_width_active = dd->ipath_link_width_enabled;
+	dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
 }
 
 /**
@@ -1205,14 +1324,16 @@ static void ipath_ht_init_hwerrors(struct ipath_devdata *dd)
 	val &= ~INFINIPATH_HWE_HTCMISCERR4;
 
 	/*
-	 * PLL ignored because MDIO interface has a logic problem
-	 * for reads, on Comstock and Ponderosa.  BRINGUP
+	 * PLL ignored because unused MDIO interface has a logic problem
 	 */
 	if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9)
 		val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
 	dd->ipath_hwerrmask = val;
 }
 
+
+
+
 /**
  * ipath_ht_bringup_serdes - bring up the serdes
  * @dd: the infinipath device
@@ -1284,16 +1405,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
 	}
 
 	val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
-	if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
-	     INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
-		val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK <<
-			 INFINIPATH_XGXS_MDIOADDR_SHIFT);
-		/*
-		 * we use address 3
-		 */
-		val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
-		change = 1;
-	}
 	if (val & INFINIPATH_XGXS_RESET) {
 		/* normally true after boot */
 		val &= ~INFINIPATH_XGXS_RESET;
@@ -1329,21 +1440,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
 		   (unsigned long long)
 		   ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
 
-	if (!ipath_waitfor_mdio_cmdready(dd)) {
-		ipath_write_kreg(dd, dd->ipath_kregs->kr_mdio,
-				 ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
-						IPATH_MDIO_CTRL_XGXS_REG_8,
-						0));
-		if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
-					   IPATH_MDIO_DATAVALID, &val))
-			ipath_dbg("Never got MDIO data for XGXS status "
-				  "read\n");
-		else
-			ipath_cdbg(VERBOSE, "MDIO Read reg8, "
-				   "'bank' 31 %x\n", (u32) val);
-	} else
-		ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
-
 	return ret;		/* for now, say we always succeeded */
 }
 
@@ -1396,6 +1492,7 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd,
 			pa |= lenvalid | INFINIPATH_RT_VALID;
 		}
 	}
+
 	writeq(pa, tidptr);
 }
 
@@ -1526,8 +1623,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
 	}
 
 	ipath_get_eeprom_info(dd);
-	if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
-		dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {
+	if (dd->ipath_boardrev == 5) {
 		/*
 		 * Later production QHT7040 has same changes as QHT7140, so
 		 * can use GPIO interrupts.  They have serial #'s starting
@@ -1602,6 +1698,210 @@ static void ipath_ht_free_irq(struct ipath_devdata *dd)
 	dd->ipath_intconfig = 0;
 }
 
+static struct ipath_message_header *
+ipath_ht_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
+{
+	return (struct ipath_message_header *)
+		&rhf_addr[sizeof(u64) / sizeof(u32)];
+}
+
+static void ipath_ht_config_ports(struct ipath_devdata *dd, ushort cfgports)
+{
+	dd->ipath_portcnt =
+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
+	dd->ipath_p0_rcvegrcnt =
+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
+}
+
+static void ipath_ht_read_counters(struct ipath_devdata *dd,
+				   struct infinipath_counters *cntrs)
+{
+	cntrs->LBIntCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
+	cntrs->LBFlowStallCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
+	cntrs->TxSDmaDescCnt = 0;
+	cntrs->TxUnsupVLErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
+	cntrs->TxDataPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
+	cntrs->TxFlowPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
+	cntrs->TxDwordCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
+	cntrs->TxLenErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
+	cntrs->TxMaxMinLenErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
+	cntrs->TxUnderrunCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
+	cntrs->TxFlowStallCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
+	cntrs->TxDroppedPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
+	cntrs->RxDroppedPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
+	cntrs->RxDataPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
+	cntrs->RxFlowPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
+	cntrs->RxDwordCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
+	cntrs->RxLenErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
+	cntrs->RxMaxMinLenErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
+	cntrs->RxICRCErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
+	cntrs->RxVCRCErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
+	cntrs->RxFlowCtrlErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
+	cntrs->RxBadFormatCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
+	cntrs->RxLinkProblemCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
+	cntrs->RxEBPCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
+	cntrs->RxLPCRCErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
+	cntrs->RxBufOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
+	cntrs->RxTIDFullErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
+	cntrs->RxTIDValidErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
+	cntrs->RxPKeyMismatchCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
+	cntrs->RxP0HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
+	cntrs->RxP1HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
+	cntrs->RxP2HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
+	cntrs->RxP3HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
+	cntrs->RxP4HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
+	cntrs->RxP5HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP5HdrEgrOvflCnt));
+	cntrs->RxP6HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP6HdrEgrOvflCnt));
+	cntrs->RxP7HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP7HdrEgrOvflCnt));
+	cntrs->RxP8HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP8HdrEgrOvflCnt));
+	cntrs->RxP9HdrEgrOvflCnt = 0;
+	cntrs->RxP10HdrEgrOvflCnt = 0;
+	cntrs->RxP11HdrEgrOvflCnt = 0;
+	cntrs->RxP12HdrEgrOvflCnt = 0;
+	cntrs->RxP13HdrEgrOvflCnt = 0;
+	cntrs->RxP14HdrEgrOvflCnt = 0;
+	cntrs->RxP15HdrEgrOvflCnt = 0;
+	cntrs->RxP16HdrEgrOvflCnt = 0;
+	cntrs->IBStatusChangeCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
+	cntrs->IBLinkErrRecoveryCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
+	cntrs->IBLinkDownedCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
+	cntrs->IBSymbolErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
+	cntrs->RxVL15DroppedPktCnt = 0;
+	cntrs->RxOtherLocalPhyErrCnt = 0;
+	cntrs->PcieRetryBufDiagQwordCnt = 0;
+	cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
+	cntrs->LocalLinkIntegrityErrCnt =
+		(dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
+		dd->ipath_lli_errs : dd->ipath_lli_errors;
+	cntrs->RxVlErrCnt = 0;
+	cntrs->RxDlidFltrCnt = 0;
+}
+
+
+/* no interrupt fallback for these chips */
+static int ipath_ht_nointr_fallback(struct ipath_devdata *dd)
+{
+	return 0;
+}
+
+
+/*
+ * reset the XGXS (between serdes and IBC).  Slightly less intrusive
+ * than resetting the IBC or external link state, and useful in some
+ * cases to cause some retraining.  To do this right, we reset IBC
+ * as well.
+ */
+static void ipath_ht_xgxs_reset(struct ipath_devdata *dd)
+{
+	u64 val, prev_val;
+
+	prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+	val = prev_val | INFINIPATH_XGXS_RESET;
+	prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+			 dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
+	ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+			 dd->ipath_control);
+}
+
+
+static int ipath_ht_get_ib_cfg(struct ipath_devdata *dd, int which)
+{
+	int ret;
+
+	switch (which) {
+	case IPATH_IB_CFG_LWID:
+		ret = dd->ipath_link_width_active;
+		break;
+	case IPATH_IB_CFG_SPD:
+		ret = dd->ipath_link_speed_active;
+		break;
+	case IPATH_IB_CFG_LWID_ENB:
+		ret = dd->ipath_link_width_enabled;
+		break;
+	case IPATH_IB_CFG_SPD_ENB:
+		ret = dd->ipath_link_speed_enabled;
+		break;
+	default:
+		ret =  -ENOTSUPP;
+		break;
+	}
+	return ret;
+}
+
+
+/* we assume range checking is already done, if needed */
+static int ipath_ht_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
+{
+	int ret = 0;
+
+	if (which == IPATH_IB_CFG_LWID_ENB)
+		dd->ipath_link_width_enabled = val;
+	else if (which == IPATH_IB_CFG_SPD_ENB)
+		dd->ipath_link_speed_enabled = val;
+	else
+		ret = -ENOTSUPP;
+	return ret;
+}
+
+
+static void ipath_ht_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
+{
+}
+
+
+static int ipath_ht_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
+{
+	ipath_setup_ht_setextled(dd, ipath_ib_linkstate(dd, ibcs),
+		ipath_ib_linktrstate(dd, ibcs));
+	return 0;
+}
+
+
 /**
  * ipath_init_iba6110_funcs - set up the chip-specific function pointers
  * @dd: the infinipath device
@@ -1626,22 +1926,19 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
 	dd->ipath_f_setextled = ipath_setup_ht_setextled;
 	dd->ipath_f_get_base_info = ipath_ht_get_base_info;
 	dd->ipath_f_free_irq = ipath_ht_free_irq;
-
-	/*
-	 * initialize chip-specific variables
-	 */
 	dd->ipath_f_tidtemplate = ipath_ht_tidtemplate;
+	dd->ipath_f_intr_fallback = ipath_ht_nointr_fallback;
+	dd->ipath_f_get_msgheader = ipath_ht_get_msgheader;
+	dd->ipath_f_config_ports = ipath_ht_config_ports;
+	dd->ipath_f_read_counters = ipath_ht_read_counters;
+	dd->ipath_f_xgxs_reset = ipath_ht_xgxs_reset;
+	dd->ipath_f_get_ib_cfg = ipath_ht_get_ib_cfg;
+	dd->ipath_f_set_ib_cfg = ipath_ht_set_ib_cfg;
+	dd->ipath_f_config_jint = ipath_ht_config_jint;
+	dd->ipath_f_ib_updown = ipath_ht_ib_updown;
 
 	/*
-	 * setup the register offsets, since they are different for each
-	 * chip
-	 */
-	dd->ipath_kregs = &ipath_ht_kregs;
-	dd->ipath_cregs = &ipath_ht_cregs;
-
-	/*
-	 * do very early init that is needed before ipath_f_bus is
-	 * called
+	 * initialize chip-specific variables
 	 */
 	ipath_init_ht_variables(dd);
 }
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index 0103d6f4847b..c7a2f50824c0 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -145,10 +145,57 @@ struct _infinipath_do_not_use_kernel_regs {
 	unsigned long long Reserved12;
 };
 
-#define IPATH_KREG_OFFSET(field) (offsetof(struct \
-    _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
+struct _infinipath_do_not_use_counters {
+	__u64 LBIntCnt;
+	__u64 LBFlowStallCnt;
+	__u64 Reserved1;
+	__u64 TxUnsupVLErrCnt;
+	__u64 TxDataPktCnt;
+	__u64 TxFlowPktCnt;
+	__u64 TxDwordCnt;
+	__u64 TxLenErrCnt;
+	__u64 TxMaxMinLenErrCnt;
+	__u64 TxUnderrunCnt;
+	__u64 TxFlowStallCnt;
+	__u64 TxDroppedPktCnt;
+	__u64 RxDroppedPktCnt;
+	__u64 RxDataPktCnt;
+	__u64 RxFlowPktCnt;
+	__u64 RxDwordCnt;
+	__u64 RxLenErrCnt;
+	__u64 RxMaxMinLenErrCnt;
+	__u64 RxICRCErrCnt;
+	__u64 RxVCRCErrCnt;
+	__u64 RxFlowCtrlErrCnt;
+	__u64 RxBadFormatCnt;
+	__u64 RxLinkProblemCnt;
+	__u64 RxEBPCnt;
+	__u64 RxLPCRCErrCnt;
+	__u64 RxBufOvflCnt;
+	__u64 RxTIDFullErrCnt;
+	__u64 RxTIDValidErrCnt;
+	__u64 RxPKeyMismatchCnt;
+	__u64 RxP0HdrEgrOvflCnt;
+	__u64 RxP1HdrEgrOvflCnt;
+	__u64 RxP2HdrEgrOvflCnt;
+	__u64 RxP3HdrEgrOvflCnt;
+	__u64 RxP4HdrEgrOvflCnt;
+	__u64 RxP5HdrEgrOvflCnt;
+	__u64 RxP6HdrEgrOvflCnt;
+	__u64 RxP7HdrEgrOvflCnt;
+	__u64 RxP8HdrEgrOvflCnt;
+	__u64 Reserved6;
+	__u64 Reserved7;
+	__u64 IBStatusChangeCnt;
+	__u64 IBLinkErrRecoveryCnt;
+	__u64 IBLinkDownedCnt;
+	__u64 IBSymbolErrCnt;
+};
+
+#define IPATH_KREG_OFFSET(field) (offsetof( \
+	struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64))
 #define IPATH_CREG_OFFSET(field) (offsetof( \
-    struct infinipath_counters, field) / sizeof(u64))
+	struct _infinipath_do_not_use_counters, field) / sizeof(u64))
 
 static const struct ipath_kregs ipath_pe_kregs = {
 	.kr_control = IPATH_KREG_OFFSET(Control),
@@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_pe_cregs = {
 #define INFINIPATH_HWE_PCIE0PLLFAILED       0x0800000000000000ULL
 #define INFINIPATH_HWE_SERDESPLLFAILED      0x1000000000000000ULL
 
+#define IBA6120_IBCS_LINKTRAININGSTATE_MASK 0xf
+#define IBA6120_IBCS_LINKSTATE_SHIFT 4
+
 /* kr_extstatus bits */
 #define INFINIPATH_EXTS_FREQSEL 0x2
 #define INFINIPATH_EXTS_SERDESSEL 0x4
@@ -296,6 +346,9 @@ static const struct ipath_cregs ipath_pe_cregs = {
 #define IPATH_GPIO_SCL (1ULL << \
 	(_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
 
+#define INFINIPATH_R_INTRAVAIL_SHIFT 16
+#define INFINIPATH_R_TAILUPD_SHIFT 31
+
 /* 6120 specific hardware errors... */
 static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
 	INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
@@ -320,10 +373,28 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
 		        INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \
 		        << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
 
-static int ipath_pe_txe_recover(struct ipath_devdata *);
 static void ipath_pe_put_tid_2(struct ipath_devdata *, u64 __iomem *,
 			       u32, unsigned long);
 
+/*
+ * On platforms using this chip, and not having ordered WC stores, we
+ * can get TXE parity errors due to speculative reads to the PIO buffers,
+ * and this, due to a chip bug can result in (many) false parity error
+ * reports.  So it's a debug print on those, and an info print on systems
+ * where the speculative reads don't occur.
+ */
+static void ipath_pe_txe_recover(struct ipath_devdata *dd)
+{
+	if (ipath_unordered_wc())
+		ipath_dbg("Recovering from TXE PIO parity error\n");
+	else {
+		++ipath_stats.sps_txeparity;
+		dev_info(&dd->pcidev->dev,
+			"Recovering from TXE PIO parity error\n");
+	}
+}
+
+
 /**
  * ipath_pe_handle_hwerrors - display hardware errors.
  * @dd: the infinipath device
@@ -403,35 +474,11 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
 		 * occur if a processor speculative read is done to the PIO
 		 * buffer while we are sending a packet, for example.
 		 */
-		if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd))
+		if (hwerrs & TXE_PIO_PARITY) {
+			ipath_pe_txe_recover(dd);
 			hwerrs &= ~TXE_PIO_PARITY;
-		if (hwerrs) {
-			/*
-			 * if any set that we aren't ignoring only make the
-			 * complaint once, in case it's stuck or recurring,
-			 * and we get here multiple times
-			 * Force link down, so switch knows, and
-			 * LEDs are turned off
-			 */
-			if (dd->ipath_flags & IPATH_INITTED) {
-				ipath_set_linkstate(dd, IPATH_IB_LINKDOWN);
-				ipath_setup_pe_setextled(dd,
-					INFINIPATH_IBCS_L_STATE_DOWN,
-					INFINIPATH_IBCS_LT_STATE_DISABLED);
-				ipath_dev_err(dd, "Fatal Hardware Error (freeze "
-					      "mode), no longer usable, SN %.16s\n",
-						  dd->ipath_serial);
-				isfatal = 1;
-			}
-			/*
-			 * Mark as having had an error for driver, and also
-			 * for /sys and status word mapped to user programs.
-			 * This marks unit as not usable, until reset
-			 */
-			*dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
-			*dd->ipath_statusp |= IPATH_STATUS_HWERROR;
-			dd->ipath_flags &= ~IPATH_INITTED;
-		} else {
+		}
+		if (!hwerrs) {
 			static u32 freeze_cnt;
 
 			freeze_cnt++;
@@ -485,7 +532,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
 
 	if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) {
 		/*
-		 * If it occurs, it is left masked since the eternal
+		 * If it occurs, it is left masked since the external
 		 * interface is unused
 		 */
 		dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED;
@@ -563,6 +610,14 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
 			dd->ipath_f_put_tid = ipath_pe_put_tid_2;
 	}
 
+
+	/*
+	 * set here, not in ipath_init_*_funcs because we have to do
+	 * it after we can read chip registers.
+	 */
+	dd->ipath_ureg_align =
+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign);
+
 	return ret;
 }
 
@@ -667,17 +722,8 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
 
 	val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
 	prev_val = val;
-	if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
-	     INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
-		val &=
-			~(INFINIPATH_XGXS_MDIOADDR_MASK <<
-			  INFINIPATH_XGXS_MDIOADDR_SHIFT);
-		/* MDIO address 3 */
-		val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
-	}
-	if (val & INFINIPATH_XGXS_RESET) {
+	if (val & INFINIPATH_XGXS_RESET)
 		val &= ~INFINIPATH_XGXS_RESET;
-	}
 	if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
 	     INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
 		/* need to compensate for Tx inversion in partner */
@@ -707,21 +753,6 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
 		   (unsigned long long)
 		   ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig));
 
-	if (!ipath_waitfor_mdio_cmdready(dd)) {
-		ipath_write_kreg(
-			dd, dd->ipath_kregs->kr_mdio,
-			ipath_mdio_req(IPATH_MDIO_CMD_READ, 31,
-				       IPATH_MDIO_CTRL_XGXS_REG_8, 0));
-		if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio,
-					   IPATH_MDIO_DATAVALID, &val))
-			ipath_dbg("Never got MDIO data for XGXS "
-				  "status read\n");
-		else
-			ipath_cdbg(VERBOSE, "MDIO Read reg8, "
-				   "'bank' 31 %x\n", (u32) val);
-	} else
-		ipath_dbg("Never got MDIO cmdready for XGXS status read\n");
-
 	return ret;
 }
 
@@ -902,12 +933,27 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd,
 	else
 		ipath_dev_err(dd, "Can't find PCI Express "
 			      "capability!\n");
+
+	dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X;
+	dd->ipath_link_speed_supported = IPATH_IB_SDR;
+	dd->ipath_link_width_enabled = IB_WIDTH_4X;
+	dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported;
+	/* these can't change for this chip, so set once */
+	dd->ipath_link_width_active = dd->ipath_link_width_enabled;
+	dd->ipath_link_speed_active = dd->ipath_link_speed_enabled;
 	return 0;
 }
 
 static void ipath_init_pe_variables(struct ipath_devdata *dd)
 {
 	/*
+	 * setup the register offsets, since they are different for each
+	 * chip
+	 */
+	dd->ipath_kregs = &ipath_pe_kregs;
+	dd->ipath_cregs = &ipath_pe_cregs;
+
+	/*
 	 * bits for selecting i2c direction and values,
 	 * used for I2C serial flash
 	 */
@@ -916,6 +962,43 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
 	dd->ipath_gpio_sda = IPATH_GPIO_SDA;
 	dd->ipath_gpio_scl = IPATH_GPIO_SCL;
 
+	/*
+	 * Fill in data for field-values that change in newer chips.
+	 * We dynamically specify only the mask for LINKTRAININGSTATE
+	 * and only the shift for LINKSTATE, as they are the only ones
+	 * that change.  Also precalculate the 3 link states of interest
+	 * and the combined mask.
+	 */
+	dd->ibcs_ls_shift = IBA6120_IBCS_LINKSTATE_SHIFT;
+	dd->ibcs_lts_mask = IBA6120_IBCS_LINKTRAININGSTATE_MASK;
+	dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK <<
+		dd->ibcs_ls_shift) | dd->ibcs_lts_mask;
+	dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+		(INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift);
+	dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+		(INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift);
+	dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP <<
+		INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) |
+		(INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift);
+
+	/*
+	 * Fill in data for ibcc field-values that change in newer chips.
+	 * We dynamically specify only the mask for LINKINITCMD
+	 * and only the shift for LINKCMD and MAXPKTLEN, as they are
+	 * the only ones that change.
+	 */
+	dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK;
+	dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT;
+	dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
+
+	/* Fill in shifts for RcvCtrl. */
+	dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT;
+	dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT;
+	dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT;
+	dd->ipath_r_portcfg_shift = 0; /* Not on IBA6120 */
+
 	/* variables for sanity checking interrupt and errors */
 	dd->ipath_hwe_bitsextant =
 		(INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
@@ -963,6 +1046,8 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
 
 	dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
 	dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+	dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT;
+	dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT;
 
 	/*
 	 * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
@@ -984,6 +1069,7 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
 		INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
 
 
+	dd->delay_mult = 2; /* SDR, 4X, can't change */
 }
 
 /* setup the MSI stuff again after a reset.  I'd like to just call
@@ -1289,6 +1375,9 @@ static int ipath_pe_early_init(struct ipath_devdata *dd)
 	 */
 	dd->ipath_rcvhdrentsize = 24;
 	dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
+	dd->ipath_rhf_offset = 0;
+	dd->ipath_egrtidbase = (u64 __iomem *)
+		((char __iomem *) dd->ipath_kregbase + dd->ipath_rcvegrbase);
 
 	/*
 	 * To truly support a 4KB MTU (for usermode), we need to
@@ -1359,34 +1448,204 @@ static void ipath_pe_free_irq(struct ipath_devdata *dd)
 	dd->ipath_irq = 0;
 }
 
+
+static struct ipath_message_header *
+ipath_pe_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr)
+{
+	return (struct ipath_message_header *)
+		&rhf_addr[sizeof(u64) / sizeof(u32)];
+}
+
+static void ipath_pe_config_ports(struct ipath_devdata *dd, ushort cfgports)
+{
+	dd->ipath_portcnt =
+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
+	dd->ipath_p0_rcvegrcnt =
+		ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);
+}
+
+static void ipath_pe_read_counters(struct ipath_devdata *dd,
+				   struct infinipath_counters *cntrs)
+{
+	cntrs->LBIntCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt));
+	cntrs->LBFlowStallCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt));
+	cntrs->TxSDmaDescCnt = 0;
+	cntrs->TxUnsupVLErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt));
+	cntrs->TxDataPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt));
+	cntrs->TxFlowPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt));
+	cntrs->TxDwordCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt));
+	cntrs->TxLenErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt));
+	cntrs->TxMaxMinLenErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt));
+	cntrs->TxUnderrunCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt));
+	cntrs->TxFlowStallCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt));
+	cntrs->TxDroppedPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt));
+	cntrs->RxDroppedPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt));
+	cntrs->RxDataPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt));
+	cntrs->RxFlowPktCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt));
+	cntrs->RxDwordCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt));
+	cntrs->RxLenErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt));
+	cntrs->RxMaxMinLenErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt));
+	cntrs->RxICRCErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt));
+	cntrs->RxVCRCErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt));
+	cntrs->RxFlowCtrlErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt));
+	cntrs->RxBadFormatCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt));
+	cntrs->RxLinkProblemCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt));
+	cntrs->RxEBPCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt));
+	cntrs->RxLPCRCErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt));
+	cntrs->RxBufOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt));
+	cntrs->RxTIDFullErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt));
+	cntrs->RxTIDValidErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt));
+	cntrs->RxPKeyMismatchCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt));
+	cntrs->RxP0HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt));
+	cntrs->RxP1HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt));
+	cntrs->RxP2HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt));
+	cntrs->RxP3HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt));
+	cntrs->RxP4HdrEgrOvflCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt));
+	cntrs->RxP5HdrEgrOvflCnt = 0;
+	cntrs->RxP6HdrEgrOvflCnt = 0;
+	cntrs->RxP7HdrEgrOvflCnt = 0;
+	cntrs->RxP8HdrEgrOvflCnt = 0;
+	cntrs->RxP9HdrEgrOvflCnt = 0;
+	cntrs->RxP10HdrEgrOvflCnt = 0;
+	cntrs->RxP11HdrEgrOvflCnt = 0;
+	cntrs->RxP12HdrEgrOvflCnt = 0;
+	cntrs->RxP13HdrEgrOvflCnt = 0;
+	cntrs->RxP14HdrEgrOvflCnt = 0;
+	cntrs->RxP15HdrEgrOvflCnt = 0;
+	cntrs->RxP16HdrEgrOvflCnt = 0;
+	cntrs->IBStatusChangeCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt));
+	cntrs->IBLinkErrRecoveryCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt));
+	cntrs->IBLinkDownedCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt));
+	cntrs->IBSymbolErrCnt =
+		ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt));
+	cntrs->RxVL15DroppedPktCnt = 0;
+	cntrs->RxOtherLocalPhyErrCnt = 0;
+	cntrs->PcieRetryBufDiagQwordCnt = 0;
+	cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs;
+	cntrs->LocalLinkIntegrityErrCnt = dd->ipath_lli_errs;
+	cntrs->RxVlErrCnt = 0;
+	cntrs->RxDlidFltrCnt = 0;
+}
+
+
+/* no interrupt fallback for these chips */
+static int ipath_pe_nointr_fallback(struct ipath_devdata *dd)
+{
+	return 0;
+}
+
+
 /*
- * On platforms using this chip, and not having ordered WC stores, we
- * can get TXE parity errors due to speculative reads to the PIO buffers,
- * and this, due to a chip bug can result in (many) false parity error
- * reports.  So it's a debug print on those, and an info print on systems
- * where the speculative reads don't occur.
- * Because we can get lots of false errors, we have no upper limit
- * on recovery attempts on those platforms.
+ * reset the XGXS (between serdes and IBC).  Slightly less intrusive
+ * than resetting the IBC or external link state, and useful in some
+ * cases to cause some retraining.  To do this right, we reset IBC
+ * as well.
  */
-static int ipath_pe_txe_recover(struct ipath_devdata *dd)
+static void ipath_pe_xgxs_reset(struct ipath_devdata *dd)
 {
-	if (ipath_unordered_wc())
-		ipath_dbg("Recovering from TXE PIO parity error\n");
-	else {
-		int cnt = ++ipath_stats.sps_txeparity;
-		if (cnt >= IPATH_MAX_PARITY_ATTEMPTS)  {
-			if (cnt == IPATH_MAX_PARITY_ATTEMPTS)
-				ipath_dev_err(dd,
-					"Too many attempts to recover from "
-					"TXE parity, giving up\n");
-			return 0;
-		}
-		dev_info(&dd->pcidev->dev,
-			"Recovering from TXE PIO parity error\n");
+	u64 val, prev_val;
+
+	prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+	val = prev_val | INFINIPATH_XGXS_RESET;
+	prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+			 dd->ipath_control & ~INFINIPATH_C_LINKENABLE);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
+	ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+			 dd->ipath_control);
+}
+
+
+static int ipath_pe_get_ib_cfg(struct ipath_devdata *dd, int which)
+{
+	int ret;
+
+	switch (which) {
+	case IPATH_IB_CFG_LWID:
+		ret = dd->ipath_link_width_active;
+		break;
+	case IPATH_IB_CFG_SPD:
+		ret = dd->ipath_link_speed_active;
+		break;
+	case IPATH_IB_CFG_LWID_ENB:
+		ret = dd->ipath_link_width_enabled;
+		break;
+	case IPATH_IB_CFG_SPD_ENB:
+		ret = dd->ipath_link_speed_enabled;
+		break;
+	default:
+		ret =  -ENOTSUPP;
+		break;
 	}
-	return 1;
+	return ret;
+}
+
+
+/* we assume range checking is already done, if needed */
+static int ipath_pe_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val)
+{
+	int ret = 0;
+
+	if (which == IPATH_IB_CFG_LWID_ENB)
+		dd->ipath_link_width_enabled = val;
+	else if (which == IPATH_IB_CFG_SPD_ENB)
+		dd->ipath_link_speed_enabled = val;
+	else
+		ret = -ENOTSUPP;
+	return ret;
 }
 
+static void ipath_pe_config_jint(struct ipath_devdata *dd, u16 a, u16 b)
+{
+}
+
+
+static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs)
+{
+	ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs),
+		ipath_ib_linktrstate(dd, ibcs));
+	return 0;
+}
+
+
 /**
  * ipath_init_iba6120_funcs - set up the chip-specific function pointers
  * @dd: the infinipath device
@@ -1407,7 +1666,7 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
 	dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
 	dd->ipath_f_clear_tids = ipath_pe_clear_tids;
 	/*
-	 * this may get changed after we read the chip revision,
+	 * _f_put_tid may get changed after we read the chip revision,
 	 * but we start with the safe version for all revs
 	 */
 	dd->ipath_f_put_tid = ipath_pe_put_tid;
@@ -1415,17 +1674,19 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
 	dd->ipath_f_setextled = ipath_setup_pe_setextled;
 	dd->ipath_f_get_base_info = ipath_pe_get_base_info;
 	dd->ipath_f_free_irq = ipath_pe_free_irq;
-
-	/* initialize chip-specific variables */
 	dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;
+	dd->ipath_f_intr_fallback = ipath_pe_nointr_fallback;
+	dd->ipath_f_xgxs_reset = ipath_pe_xgxs_reset;
+	dd->ipath_f_get_msgheader = ipath_pe_get_msgheader;
+	dd->ipath_f_config_ports = ipath_pe_config_ports;
+	dd->ipath_f_read_counters = ipath_pe_read_counters;
+	dd->ipath_f_get_ib_cfg = ipath_pe_get_ib_cfg;
+	dd->ipath_f_set_ib_cfg = ipath_pe_set_ib_cfg;
+	dd->ipath_f_config_jint = ipath_pe_config_jint;
+	dd->ipath_f_ib_updown = ipath_pe_ib_updown;
 
-	/*
-	 * setup the register offsets, since they are different for each
-	 * chip
-	 */
-	dd->ipath_kregs = &ipath_pe_kregs;
-	dd->ipath_cregs = &ipath_pe_cregs;
 
+	/* initialize chip-specific variables */
 	ipath_init_pe_variables(dd);
 }
 
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 9dd0bacf8461..4471674975cd 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -91,7 +91,7 @@ static int create_port0_egr(struct ipath_devdata *dd)
 	struct ipath_skbinfo *skbinfo;
 	int ret;
 
-	egrcnt = dd->ipath_rcvegrcnt;
+	egrcnt = dd->ipath_p0_rcvegrcnt;
 
 	skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt);
 	if (skbinfo == NULL) {
@@ -244,8 +244,7 @@ static int init_chip_first(struct ipath_devdata *dd,
 	 * cfgports.  We do still check and report a difference, if
 	 * not same (should be impossible).
 	 */
-	dd->ipath_portcnt =
-		ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
+	dd->ipath_f_config_ports(dd, ipath_cfgports);
 	if (!ipath_cfgports)
 		dd->ipath_cfgports = dd->ipath_portcnt;
 	else if (ipath_cfgports <= dd->ipath_portcnt) {
@@ -272,22 +271,7 @@ static int init_chip_first(struct ipath_devdata *dd,
 		goto done;
 	}
 
-	dd->ipath_lastegrheads = kzalloc(sizeof(*dd->ipath_lastegrheads)
-					 * dd->ipath_cfgports,
-					 GFP_KERNEL);
-	dd->ipath_lastrcvhdrqtails =
-		kzalloc(sizeof(*dd->ipath_lastrcvhdrqtails)
-			* dd->ipath_cfgports, GFP_KERNEL);
-
-	if (!dd->ipath_lastegrheads || !dd->ipath_lastrcvhdrqtails) {
-		ipath_dev_err(dd, "Unable to allocate head arrays, "
-			      "failing\n");
-		ret = -ENOMEM;
-		goto done;
-	}
-
 	pd = create_portdata0(dd);
-
 	if (!pd) {
 		ipath_dev_err(dd, "Unable to allocate portdata for port "
 			      "0, failing\n");
@@ -345,10 +329,10 @@ static int init_chip_first(struct ipath_devdata *dd,
 		       dd->ipath_piobcnt2k, dd->ipath_pio2kbase);
 
 	spin_lock_init(&dd->ipath_tid_lock);
-
+	spin_lock_init(&dd->ipath_sendctrl_lock);
 	spin_lock_init(&dd->ipath_gpio_lock);
 	spin_lock_init(&dd->ipath_eep_st_lock);
-	sema_init(&dd->ipath_eep_sem, 1);
+	mutex_init(&dd->ipath_eep_lock);
 
 done:
 	*pdp = pd;
@@ -372,9 +356,9 @@ static int init_chip_reset(struct ipath_devdata *dd,
 	*pdp = dd->ipath_pd[0];
 	/* ensure chip does no sends or receives while we re-initialize */
 	dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U;
-	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0);
-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0);
-	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, dd->ipath_control);
 
 	rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);
 	if (dd->ipath_portcnt != rtmp)
@@ -487,6 +471,7 @@ static void enable_chip(struct ipath_devdata *dd,
 			struct ipath_portdata *pd, int reinit)
 {
 	u32 val;
+	unsigned long flags;
 	int i;
 
 	if (!reinit)
@@ -495,19 +480,21 @@ static void enable_chip(struct ipath_devdata *dd,
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
 			 dd->ipath_rcvctrl);
 
+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
 	/* Enable PIO send, and update of PIOavail regs to memory. */
 	dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE |
 		INFINIPATH_S_PIOBUFAVAILUPD;
-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-			 dd->ipath_sendctrl);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
 	/*
 	 * enable port 0 receive, and receive interrupt.  other ports
 	 * done as user opens and inits them.
 	 */
-	dd->ipath_rcvctrl = INFINIPATH_R_TAILUPD |
-		(1ULL << INFINIPATH_R_PORTENABLE_SHIFT) |
-		(1ULL << INFINIPATH_R_INTRAVAIL_SHIFT);
+	dd->ipath_rcvctrl = (1ULL << dd->ipath_r_tailupd_shift) |
+		(1ULL << dd->ipath_r_portenable_shift) |
+		(1ULL << dd->ipath_r_intravail_shift);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
 			 dd->ipath_rcvctrl);
 
@@ -523,12 +510,11 @@ static void enable_chip(struct ipath_devdata *dd,
 	 */
 	val = ipath_read_ureg32(dd, ur_rcvegrindextail, 0);
 	(void)ipath_write_ureg(dd, ur_rcvegrindexhead, val, 0);
-	dd->ipath_port0head = ipath_read_ureg32(dd, ur_rcvhdrtail, 0);
 
 	/* Initialize so we interrupt on next packet received */
 	(void)ipath_write_ureg(dd, ur_rcvhdrhead,
 			       dd->ipath_rhdrhead_intr_off |
-			       dd->ipath_port0head, 0);
+			       dd->ipath_pd[0]->port_head, 0);
 
 	/*
 	 * by now pioavail updates to memory should have occurred, so
@@ -542,12 +528,8 @@ static void enable_chip(struct ipath_devdata *dd,
 		/*
 		 * Chip Errata bug 6641; even and odd qwords>3 are swapped.
 		 */
-		if (i > 3) {
-			if (i & 1)
-				val = dd->ipath_pioavailregs_dma[i - 1];
-			else
-				val = dd->ipath_pioavailregs_dma[i + 1];
-		}
+		if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS))
+			val = dd->ipath_pioavailregs_dma[i ^ 1];
 		else
 			val = dd->ipath_pioavailregs_dma[i];
 		dd->ipath_pioavailshadow[i] = le64_to_cpu(val);
@@ -690,12 +672,13 @@ done:
  */
 int ipath_init_chip(struct ipath_devdata *dd, int reinit)
 {
-	int ret = 0, i;
+	int ret = 0;
 	u32 val32, kpiobufs;
 	u32 piobufs, uports;
 	u64 val;
 	struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
 	gfp_t gfp_flags = GFP_USER | __GFP_COMP;
+	unsigned long flags;
 
 	ret = init_housekeeping(dd, &pd, reinit);
 	if (ret)
@@ -746,7 +729,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
 		kpiobufs = ipath_kpiobufs;
 
 	if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) {
-		i = (int) piobufs -
+		int i = (int) piobufs -
 			(int) (uports * IPATH_MIN_USER_PORT_BUFCNT);
 		if (i < 0)
 			i = 0;
@@ -827,8 +810,12 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,
 			 ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL);
-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-			 INFINIPATH_S_PIOENABLE);
+
+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+	dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE;
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
 	/*
 	 * before error clears, since we expect serdes pll errors during
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index c61f9da2964a..92e58c921522 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -683,7 +683,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
 		for (i = 0; i < dd->ipath_cfgports; i++) {
 			struct ipath_portdata *pd = dd->ipath_pd[i];
 			if (i == 0) {
-				hd = dd->ipath_port0head;
+				hd = pd->port_head;
 				tl = (u32) le64_to_cpu(
 					*dd->ipath_hdrqtailptr);
 			} else if (pd && pd->port_cnt &&
@@ -693,7 +693,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
 				 * except kernel
 				 */
 				tl = *(u64 *) pd->port_rcvhdrtail_kvaddr;
-				if (tl == dd->ipath_lastrcvhdrqtails[i])
+				if (tl == pd->port_lastrcvhdrqtail)
 					continue;
 				hd = ipath_read_ureg32(dd, ur_rcvhdrhead,
 						       i);
@@ -703,7 +703,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
 			    (!hd && tl == dd->ipath_hdrqlast)) {
 				if (i == 0)
 					chkerrpkts = 1;
-				dd->ipath_lastrcvhdrqtails[i] = tl;
+				pd->port_lastrcvhdrqtail = tl;
 				pd->port_hdrqfull++;
 				/* flush hdrqfull so that poll() sees it */
 				wmb();
@@ -712,6 +712,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
 		}
 	}
 	if (errs & INFINIPATH_E_RRCVEGRFULL) {
+		struct ipath_portdata *pd = dd->ipath_pd[0];
+
 		/*
 		 * since this is of less importance and not likely to
 		 * happen without also getting hdrfull, only count
@@ -719,7 +721,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
 		 * vs user)
 		 */
 		ipath_stats.sps_etidfull++;
-		if (dd->ipath_port0head !=
+		if (pd->port_head !=
 		    (u32) le64_to_cpu(*dd->ipath_hdrqtailptr))
 			chkerrpkts = 1;
 	}
@@ -795,6 +797,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
 {
 	int i, im;
 	__le64 val;
+	unsigned long flags;
 
 	/* disable error interrupts, to avoid confusion */
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
@@ -813,11 +816,14 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
 			 dd->ipath_control);
 
 	/* ensure pio avail updates continue */
+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
 		 dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
 	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-		 dd->ipath_sendctrl);
+			 dd->ipath_sendctrl);
+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
 	/*
 	 * We just enabled pioavailupdate, so dma copy is almost certainly
@@ -825,8 +831,8 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
 	 */
 	for (i = 0; i < dd->ipath_pioavregs; i++) {
 		/* deal with 6110 chip bug */
-		im = i > 3 ? ((i&1) ? i-1 : i+1) : i;
-		val = ipath_read_kreg64(dd, (0x1000/sizeof(u64))+im);
+		im = i > 3 ? i ^ 1 : i;
+		val = ipath_read_kreg64(dd, (0x1000 / sizeof(u64)) + im);
 		dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i]
 			= le64_to_cpu(val);
 	}
@@ -849,7 +855,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd)
 
 /* this is separate to allow for better optimization of ipath_intr() */
 
-static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
+static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp)
 {
 	/*
 	 * sometimes happen during driver init and unload, don't want
@@ -877,7 +883,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
 				dd->ipath_f_free_irq(dd);
 			}
 		}
-		if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) {
+		if (ipath_read_ireg(dd, dd->ipath_kregs->kr_intmask)) {
 			ipath_dev_err(dd, "%u unexpected interrupts, "
 				      "disabling interrupts completely\n",
 				      *unexpectp);
@@ -892,7 +898,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
 			  "ignoring\n");
 }
 
-static void ipath_bad_regread(struct ipath_devdata *dd)
+static noinline void ipath_bad_regread(struct ipath_devdata *dd)
 {
 	static int allbits;
 
@@ -920,31 +926,9 @@ static void ipath_bad_regread(struct ipath_devdata *dd)
 	}
 }
 
-static void handle_port_pioavail(struct ipath_devdata *dd)
-{
-	u32 i;
-	/*
-	 * start from port 1, since for now port 0  is never using
-	 * wait_event for PIO
-	 */
-	for (i = 1; dd->ipath_portpiowait && i < dd->ipath_cfgports; i++) {
-		struct ipath_portdata *pd = dd->ipath_pd[i];
-
-		if (pd && pd->port_cnt &&
-		    dd->ipath_portpiowait & (1U << i)) {
-			clear_bit(i, &dd->ipath_portpiowait);
-			if (test_bit(IPATH_PORT_WAITING_PIO,
-				     &pd->port_flag)) {
-				clear_bit(IPATH_PORT_WAITING_PIO,
-					  &pd->port_flag);
-				wake_up_interruptible(&pd->port_wait);
-			}
-		}
-	}
-}
-
 static void handle_layer_pioavail(struct ipath_devdata *dd)
 {
+	unsigned long flags;
 	int ret;
 
 	ret = ipath_ib_piobufavail(dd->verbs_dev);
@@ -953,9 +937,12 @@ static void handle_layer_pioavail(struct ipath_devdata *dd)
 
 	return;
 set:
-	set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+	dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
 			 dd->ipath_sendctrl);
+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 }
 
 /*
@@ -969,7 +956,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
 	int i;
 	int rcvdint = 0;
 
-	/* test_bit below needs this... */
+	/*
+	 * test_and_clear_bit(IPATH_PORT_WAITING_RCV) and
+	 * test_and_clear_bit(IPATH_PORT_WAITING_URG) below
+	 * would both like timely updates of the bits so that
+	 * we don't pass them by unnecessarily.  the rmb()
+	 * here ensures that we see them promptly -- the
+	 * corresponding wmb()'s are in ipath_poll_urgent()
+	 * and ipath_poll_next()...
+	 */
 	rmb();
 	portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
 		 dd->ipath_i_rcvavail_mask)
@@ -980,7 +975,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
 		if (portr & (1 << i) && pd && pd->port_cnt) {
 			if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
 					       &pd->port_flag)) {
-				clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
+				clear_bit(i + dd->ipath_r_intravail_shift,
 					  &dd->ipath_rcvctrl);
 				wake_up_interruptible(&pd->port_wait);
 				rcvdint = 1;
@@ -1039,7 +1034,7 @@ irqreturn_t ipath_intr(int irq, void *data)
 		goto bail;
 	}
 
-	istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
+	istat = ipath_read_ireg(dd, dd->ipath_kregs->kr_intstatus);
 
 	if (unlikely(!istat)) {
 		ipath_stats.sps_nullintr++;
@@ -1180,7 +1175,7 @@ irqreturn_t ipath_intr(int irq, void *data)
 	 * for receive are at the bottom.
 	 */
 	if (chk0rcv) {
-		ipath_kreceive(dd);
+		ipath_kreceive(dd->ipath_pd[0]);
 		istat &= ~port0rbits;
 	}
 
@@ -1191,12 +1186,14 @@ irqreturn_t ipath_intr(int irq, void *data)
 		handle_urcv(dd, istat);
 
 	if (istat & INFINIPATH_I_SPIOBUFAVAIL) {
-		clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+		unsigned long flags;
+
+		spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+		dd->ipath_sendctrl &= ~INFINIPATH_S_PIOINTBUFAVAIL;
 		ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
 				 dd->ipath_sendctrl);
-
-		if (dd->ipath_portpiowait)
-			handle_port_pioavail(dd);
+		ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+		spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 
 		handle_layer_pioavail(dd);
 	}
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 8786dd7922e4..4cc0f95ea877 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -41,6 +41,7 @@
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <rdma/ib_verbs.h>
 
@@ -140,6 +141,11 @@ struct ipath_portdata {
 	u32 port_pionowait;
 	/* total number of rcvhdrqfull errors */
 	u32 port_hdrqfull;
+	/*
+	 * Used to suppress multiple instances of same
+	 * port staying stuck at same point.
+	 */
+	u32 port_lastrcvhdrqtail;
 	/* saved total number of rcvhdrqfull errors for poll edge trigger */
 	u32 port_hdrqfull_poll;
 	/* total number of polled urgent packets */
@@ -148,6 +154,7 @@ struct ipath_portdata {
 	u32 port_urgent_poll;
 	/* pid of process using this port */
 	pid_t port_pid;
+	pid_t port_subpid[INFINIPATH_MAX_SUBPORT];
 	/* same size as task_struct .comm[] */
 	char port_comm[16];
 	/* pkeys set by this use of this port */
@@ -166,6 +173,8 @@ struct ipath_portdata {
 	u32 active_slaves;
 	/* Type of packets or conditions we want to poll for */
 	u16 poll_type;
+	/* port rcvhdrq head offset */
+	u32 port_head;
 };
 
 struct sk_buff;
@@ -182,6 +191,22 @@ struct ipath_skbinfo {
 	dma_addr_t phys;
 };
 
+/*
+ * Possible IB config parameters for ipath_f_get/set_ib_cfg()
+ */
+#define IPATH_IB_CFG_LIDLMC 0 /* Get/set LID (LS16b) and Mask (MS16b) */
+#define IPATH_IB_CFG_HRTBT 1 /* Get/set Heartbeat off/enable/auto */
+#define IPATH_IB_HRTBT_ON 3 /* Heartbeat enabled, sent every 100msec */
+#define IPATH_IB_HRTBT_OFF 0 /* Heartbeat off */
+#define IPATH_IB_CFG_LWID_ENB 2 /* Get/set allowed Link-width */
+#define IPATH_IB_CFG_LWID 3 /* Get currently active Link-width */
+#define IPATH_IB_CFG_SPD_ENB 4 /* Get/set allowed Link speeds */
+#define IPATH_IB_CFG_SPD 5 /* Get current Link spd */
+#define IPATH_IB_CFG_RXPOL_ENB 6 /* Get/set Auto-RX-polarity enable */
+#define IPATH_IB_CFG_LREV_ENB 7 /* Get/set Auto-Lane-reversal enable */
+#define IPATH_IB_CFG_LINKLATENCY 8 /* Get Auto-Lane-reversal enable */
+
+
 struct ipath_devdata {
 	struct list_head ipath_list;
 
@@ -222,6 +247,8 @@ struct ipath_devdata {
 	struct _ipath_layer ipath_layer;
 	/* setup intr */
 	int (*ipath_f_intrsetup)(struct ipath_devdata *);
+	/* fallback to alternate interrupt type if possible */
+	int (*ipath_f_intr_fallback)(struct ipath_devdata *);
 	/* setup on-chip bus config */
 	int (*ipath_f_bus)(struct ipath_devdata *, struct pci_dev *);
 	/* hard reset chip */
@@ -244,6 +271,18 @@ struct ipath_devdata {
 	int (*ipath_f_get_base_info)(struct ipath_portdata *, void *);
 	/* free irq */
 	void (*ipath_f_free_irq)(struct ipath_devdata *);
+	struct ipath_message_header *(*ipath_f_get_msgheader)
+					(struct ipath_devdata *, __le32 *);
+	void (*ipath_f_config_ports)(struct ipath_devdata *, ushort);
+	int (*ipath_f_get_ib_cfg)(struct ipath_devdata *, int);
+	int (*ipath_f_set_ib_cfg)(struct ipath_devdata *, int, u32);
+	void (*ipath_f_config_jint)(struct ipath_devdata *, u16 , u16);
+	void (*ipath_f_read_counters)(struct ipath_devdata *,
+					struct infinipath_counters *);
+	void (*ipath_f_xgxs_reset)(struct ipath_devdata *);
+	/* per chip actions needed for IB Link up/down changes */
+	int (*ipath_f_ib_updown)(struct ipath_devdata *, int, u64);
+
 	struct ipath_ibdev *verbs_dev;
 	struct timer_list verbs_timer;
 	/* total dwords sent (summed from counter) */
@@ -313,22 +352,12 @@ struct ipath_devdata {
 	 * supports, less gives more pio bufs/port, etc.
 	 */
 	u32 ipath_cfgports;
-	/* port0 rcvhdrq head offset */
-	u32 ipath_port0head;
 	/* count of port 0 hdrqfull errors */
 	u32 ipath_p0_hdrqfull;
+	/* port 0 number of receive eager buffers */
+	u32 ipath_p0_rcvegrcnt;
 
 	/*
-	 * (*cfgports) used to suppress multiple instances of same
-	 * port staying stuck at same point
-	 */
-	u32 *ipath_lastrcvhdrqtails;
-	/*
-	 * (*cfgports) used to suppress multiple instances of same
-	 * port staying stuck at same point
-	 */
-	u32 *ipath_lastegrheads;
-	/*
 	 * index of last piobuffer we used.  Speeds up searching, by
 	 * starting at this point.  Doesn't matter if multiple cpu's use and
 	 * update, last updater is only write that matters.  Whenever it
@@ -367,14 +396,15 @@ struct ipath_devdata {
 	unsigned long ipath_wc_len;
 	/* ref count for each pkey */
 	atomic_t ipath_pkeyrefs[4];
-	/* shadow copy of all exptids physaddr; used only by funcsim */
-	u64 *ipath_tidsimshadow;
 	/* shadow copy of struct page *'s for exp tid pages */
 	struct page **ipath_pageshadow;
 	/* shadow copy of dma handles for exp tid pages */
 	dma_addr_t *ipath_physshadow;
-	/* lock to workaround chip bug 9437 */
+	u64 __iomem *ipath_egrtidbase;
+	/* lock to workaround chip bug 9437 and others */
+	spinlock_t ipath_kernel_tid_lock;
 	spinlock_t ipath_tid_lock;
+	spinlock_t ipath_sendctrl_lock;
 
 	/*
 	 * IPATH_STATUS_*,
@@ -395,6 +425,8 @@ struct ipath_devdata {
 	void *ipath_dummy_hdrq;	/* used after port close */
 	dma_addr_t ipath_dummy_hdrq_phys;
 
+	unsigned long ipath_ureg_align; /* user register alignment */
+
 	/*
 	 * Shadow copies of registers; size indicates read access size.
 	 * Most of them are readonly, but some are write-only register,
@@ -456,8 +488,6 @@ struct ipath_devdata {
 	unsigned long ipath_rcvctrl;
 	/* shadow kr_sendctrl */
 	unsigned long ipath_sendctrl;
-	/* ports waiting for PIOavail intr */
-	unsigned long ipath_portpiowait;
 	unsigned long ipath_lastcancel; /* to not count armlaunch after cancel */
 
 	/* value we put in kr_rcvhdrcnt */
@@ -550,12 +580,26 @@ struct ipath_devdata {
 	u8 ipath_minrev;
 	/* board rev, from ipath_revision */
 	u8 ipath_boardrev;
+
+	u8 ipath_r_portenable_shift;
+	u8 ipath_r_intravail_shift;
+	u8 ipath_r_tailupd_shift;
+	u8 ipath_r_portcfg_shift;
+
 	/* unit # of this chip, if present */
 	int ipath_unit;
 	/* saved for restore after reset */
 	u8 ipath_pci_cacheline;
 	/* LID mask control */
 	u8 ipath_lmc;
+	/* link width supported */
+	u8 ipath_link_width_supported;
+	/* link speed supported */
+	u8 ipath_link_speed_supported;
+	u8 ipath_link_width_enabled;
+	u8 ipath_link_speed_enabled;
+	u8 ipath_link_width_active;
+	u8 ipath_link_speed_active;
 	/* Rx Polarity inversion (compensate for ~tx on partner) */
 	u8 ipath_rx_pol_inv;
 
@@ -590,6 +634,8 @@ struct ipath_devdata {
 	 */
 	u32 ipath_i_rcvavail_mask;
 	u32 ipath_i_rcvurg_mask;
+	u16 ipath_i_rcvurg_shift;
+	u16 ipath_i_rcvavail_shift;
 
 	/*
 	 * Register bits for selecting i2c direction and values, used for
@@ -603,6 +649,29 @@ struct ipath_devdata {
 	/* lock for doing RMW of shadows/regs for ExtCtrl and GPIO */
 	spinlock_t ipath_gpio_lock;
 
+	/*
+	 * IB link and linktraining states and masks that vary per chip in
+	 * some way.  Set at init, to avoid each IB status change interrupt
+	 */
+	u8 ibcs_ls_shift;
+	u8 ibcs_lts_mask;
+	u32 ibcs_mask;
+	u32 ib_init;
+	u32 ib_arm;
+	u32 ib_active;
+
+	u16 ipath_rhf_offset; /* offset of RHF within receive header entry */
+
+	/*
+	 * shift/mask for linkcmd, linkinitcmd, maxpktlen in ibccontol
+	 * reg. Changes for IBA7220
+	 */
+	u8 ibcc_lic_mask; /* LinkInitCmd */
+	u8 ibcc_lc_shift; /* LinkCmd */
+	u8 ibcc_mpl_shift; /* Maxpktlen */
+
+	u8 delay_mult;
+
 	/* used to override LED behavior */
 	u8 ipath_led_override;  /* Substituted for normal value, if non-zero */
 	u16 ipath_led_override_timeoff; /* delta to next timer event */
@@ -616,7 +685,7 @@ struct ipath_devdata {
 	/* control access to actual counters, timer */
 	spinlock_t ipath_eep_st_lock;
 	/* control high-level access to EEPROM */
-	struct semaphore ipath_eep_sem;
+	struct mutex ipath_eep_lock;
 	/* Below inc'd by ipath_snap_cntrs(), locked by ipath_eep_st_lock */
 	uint64_t ipath_traffic_wds;
 	/* active time is kept in seconds, but logged in hours */
@@ -630,6 +699,10 @@ struct ipath_devdata {
 	 * each of the counters to increment.
 	 */
 	struct ipath_eep_log_mask ipath_eep_st_masks[IPATH_EEP_LOG_CNT];
+
+	/* interrupt mitigation reload register info */
+	u16 ipath_jint_idle_ticks;	/* idle clock ticks */
+	u16 ipath_jint_max_packets;	/* max packets across all ports */
 };
 
 /* Private data for file operations */
@@ -690,7 +763,7 @@ void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
 
 int ipath_parse_ushort(const char *str, unsigned short *valp);
 
-void ipath_kreceive(struct ipath_devdata *);
+void ipath_kreceive(struct ipath_portdata *);
 int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned);
 int ipath_reset_device(int);
 void ipath_get_faststats(unsigned long);
@@ -698,6 +771,8 @@ int ipath_set_linkstate(struct ipath_devdata *, u8);
 int ipath_set_mtu(struct ipath_devdata *, u16);
 int ipath_set_lid(struct ipath_devdata *, u32, u8);
 int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
+void ipath_enable_armlaunch(struct ipath_devdata *);
+void ipath_disable_armlaunch(struct ipath_devdata *);
 
 /* for use in system calls, where we want to know device type, etc. */
 #define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd
@@ -744,9 +819,15 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
 		 * are 64bit */
 #define IPATH_32BITCOUNTERS 0x20000
 		/* can miss port0 rx interrupts */
+		/* Interrupt register is 64 bits */
+#define IPATH_INTREG_64     0x40000
 #define IPATH_DISABLED      0x80000 /* administratively disabled */
 		/* Use GPIO interrupts for new counters */
 #define IPATH_GPIO_ERRINTRS 0x100000
+#define IPATH_SWAP_PIOBUFS  0x200000
+		/* Suppress heartbeat, even if turning off loopback */
+#define IPATH_NO_HRTBT      0x1000000
+#define IPATH_HAS_MULT_IB_SPEED 0x8000000
 
 /* Bits in GPIO for the added interrupts */
 #define IPATH_GPIO_PORT0_BIT 2
@@ -758,8 +839,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
 /* portdata flag bit offsets */
 		/* waiting for a packet to arrive */
 #define IPATH_PORT_WAITING_RCV   2
-		/* waiting for a PIO buffer to be available */
-#define IPATH_PORT_WAITING_PIO   3
 		/* master has not finished initializing */
 #define IPATH_PORT_MASTER_UNINIT 4
 		/* waiting for an urgent packet to arrive */
@@ -767,8 +846,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
 
 /* free up any allocated data at closes */
 void ipath_free_data(struct ipath_portdata *dd);
-int ipath_waitfor_mdio_cmdready(struct ipath_devdata *);
-int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *);
 u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *);
 void ipath_init_iba6120_funcs(struct ipath_devdata *);
 void ipath_init_iba6110_funcs(struct ipath_devdata *);
@@ -792,33 +869,6 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val);
  */
 #define IPATH_DFLT_RCVHDRSIZE 9
 
-#define IPATH_MDIO_CMD_WRITE   1
-#define IPATH_MDIO_CMD_READ    2
-#define IPATH_MDIO_CLD_DIV     25	/* to get 2.5 Mhz mdio clock */
-#define IPATH_MDIO_CMDVALID    0x40000000	/* bit 30 */
-#define IPATH_MDIO_DATAVALID   0x80000000	/* bit 31 */
-#define IPATH_MDIO_CTRL_STD    0x0
-
-static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data)
-{
-	return (((u64) IPATH_MDIO_CLD_DIV) << 32) |
-		(cmd << 26) |
-		(dev << 21) |
-		(reg << 16) |
-		(data & 0xFFFF);
-}
-
-		/* signal and fifo status, in bank 31 */
-#define IPATH_MDIO_CTRL_XGXS_REG_8  0x8
-		/* controls loopback, redundancy */
-#define IPATH_MDIO_CTRL_8355_REG_1  0x10
-		/* premph, encdec, etc. */
-#define IPATH_MDIO_CTRL_8355_REG_2  0x11
-		/* Kchars, etc. */
-#define IPATH_MDIO_CTRL_8355_REG_6  0x15
-#define IPATH_MDIO_CTRL_8355_REG_9  0x18
-#define IPATH_MDIO_CTRL_8355_REG_10 0x1D
-
 int ipath_get_user_pages(unsigned long, size_t, struct page **);
 void ipath_release_user_pages(struct page **, size_t);
 void ipath_release_user_pages_on_close(struct page **, size_t);
@@ -863,7 +913,7 @@ static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd,
 	return readl(regno + (u64 __iomem *)
 		     (dd->ipath_uregbase +
 		      (char __iomem *)dd->ipath_kregbase +
-		      dd->ipath_palign * port));
+		      dd->ipath_ureg_align * port));
 }
 
 /**
@@ -880,7 +930,7 @@ static inline void ipath_write_ureg(const struct ipath_devdata *dd,
 {
 	u64 __iomem *ubase = (u64 __iomem *)
 		(dd->ipath_uregbase + (char __iomem *) dd->ipath_kregbase +
-		 dd->ipath_palign * port);
+		 dd->ipath_ureg_align * port);
 	if (dd->ipath_kregbase)
 		writeq(value, &ubase[regno]);
 }
@@ -930,6 +980,53 @@ static inline u32 ipath_read_creg32(const struct ipath_devdata *dd,
 		      (char __iomem *)dd->ipath_kregbase));
 }
 
+static inline void ipath_write_creg(const struct ipath_devdata *dd,
+				    ipath_creg regno, u64 value)
+{
+	if (dd->ipath_kregbase)
+		writeq(value, regno + (u64 __iomem *)
+		       (dd->ipath_cregbase +
+			(char __iomem *)dd->ipath_kregbase));
+}
+
+static inline void ipath_clear_rcvhdrtail(const struct ipath_portdata *pd)
+{
+	*((u64 *) pd->port_rcvhdrtail_kvaddr) = 0ULL;
+}
+
+static inline u32 ipath_get_rcvhdrtail(const struct ipath_portdata *pd)
+{
+	return (u32) le64_to_cpu(*((volatile __le64 *)
+				pd->port_rcvhdrtail_kvaddr));
+}
+
+static inline u64 ipath_read_ireg(const struct ipath_devdata *dd, ipath_kreg r)
+{
+	return (dd->ipath_flags & IPATH_INTREG_64) ?
+		ipath_read_kreg64(dd, r) : ipath_read_kreg32(dd, r);
+}
+
+/*
+ * from contents of IBCStatus (or a saved copy), return linkstate
+ * Report ACTIVE_DEFER as ACTIVE, because we treat them the same
+ * everywhere, anyway (and should be, for almost all purposes).
+ */
+static inline u32 ipath_ib_linkstate(struct ipath_devdata *dd, u64 ibcs)
+{
+	u32 state = (u32)(ibcs >> dd->ibcs_ls_shift) &
+		INFINIPATH_IBCS_LINKSTATE_MASK;
+	if (state == INFINIPATH_IBCS_L_STATE_ACT_DEFER)
+		state = INFINIPATH_IBCS_L_STATE_ACTIVE;
+	return state;
+}
+
+/* from contents of IBCStatus (or a saved copy), return linktrainingstate */
+static inline u32 ipath_ib_linktrstate(struct ipath_devdata *dd, u64 ibcs)
+{
+	return (u32)(ibcs >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
+		dd->ibcs_lts_mask;
+}
+
 /*
  * sysfs interface.
  */
@@ -938,8 +1035,7 @@ struct device_driver;
 
 extern const char ib_ipath_version[];
 
-int ipath_driver_create_group(struct device_driver *);
-void ipath_driver_remove_group(struct device_driver *);
+extern struct attribute_group *ipath_driver_attr_groups[];
 
 int ipath_device_create_group(struct device *, struct ipath_devdata *);
 void ipath_device_remove_group(struct device *, struct ipath_devdata *);
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
index 85a4aefc6c03..8f32b17a5eed 100644
--- a/drivers/infiniband/hw/ipath/ipath_keys.c
+++ b/drivers/infiniband/hw/ipath/ipath_keys.c
@@ -128,9 +128,8 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
 	int ret;
 
 	/*
-	 * We use LKEY == zero to mean a physical kmalloc() address.
-	 * This is a bit of a hack since we rely on dma_map_single()
-	 * being reversible by calling bus_to_virt().
+	 * We use LKEY == zero for kernel virtual addresses
+	 * (see ipath_get_dma_mr and ipath_dma.c).
 	 */
 	if (sge->lkey == 0) {
 		struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
index 3d1432d1e3f4..d98d5f103700 100644
--- a/drivers/infiniband/hw/ipath/ipath_mad.c
+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
@@ -934,6 +934,7 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp,
 	struct ib_pma_portsamplescontrol *p =
 		(struct ib_pma_portsamplescontrol *)pmp->data;
 	struct ipath_ibdev *dev = to_idev(ibdev);
+	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
 	unsigned long flags;
 	u8 port_select = p->port_select;
 
@@ -955,7 +956,10 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp,
 	p->counter_width = 4;	/* 32 bit counters */
 	p->counter_mask0_9 = COUNTER_MASK0_9;
 	spin_lock_irqsave(&dev->pending_lock, flags);
-	p->sample_status = dev->pma_sample_status;
+	if (crp->cr_psstat)
+		p->sample_status = ipath_read_creg32(dev->dd, crp->cr_psstat);
+	else
+		p->sample_status = dev->pma_sample_status;
 	p->sample_start = cpu_to_be32(dev->pma_sample_start);
 	p->sample_interval = cpu_to_be32(dev->pma_sample_interval);
 	p->tag = cpu_to_be16(dev->pma_tag);
@@ -975,8 +979,9 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp,
 	struct ib_pma_portsamplescontrol *p =
 		(struct ib_pma_portsamplescontrol *)pmp->data;
 	struct ipath_ibdev *dev = to_idev(ibdev);
+	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
 	unsigned long flags;
-	u32 start;
+	u8 status;
 	int ret;
 
 	if (pmp->attr_mod != 0 ||
@@ -986,59 +991,67 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp,
 		goto bail;
 	}
 
-	start = be32_to_cpu(p->sample_start);
-	if (start != 0) {
-		spin_lock_irqsave(&dev->pending_lock, flags);
-		if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_DONE) {
-			dev->pma_sample_status =
-				IB_PMA_SAMPLE_STATUS_STARTED;
-			dev->pma_sample_start = start;
-			dev->pma_sample_interval =
-				be32_to_cpu(p->sample_interval);
-			dev->pma_tag = be16_to_cpu(p->tag);
-			if (p->counter_select[0])
-				dev->pma_counter_select[0] =
-					p->counter_select[0];
-			if (p->counter_select[1])
-				dev->pma_counter_select[1] =
-					p->counter_select[1];
-			if (p->counter_select[2])
-				dev->pma_counter_select[2] =
-					p->counter_select[2];
-			if (p->counter_select[3])
-				dev->pma_counter_select[3] =
-					p->counter_select[3];
-			if (p->counter_select[4])
-				dev->pma_counter_select[4] =
-					p->counter_select[4];
-		}
-		spin_unlock_irqrestore(&dev->pending_lock, flags);
+	spin_lock_irqsave(&dev->pending_lock, flags);
+	if (crp->cr_psstat)
+		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
+	else
+		status = dev->pma_sample_status;
+	if (status == IB_PMA_SAMPLE_STATUS_DONE) {
+		dev->pma_sample_start = be32_to_cpu(p->sample_start);
+		dev->pma_sample_interval = be32_to_cpu(p->sample_interval);
+		dev->pma_tag = be16_to_cpu(p->tag);
+		dev->pma_counter_select[0] = p->counter_select[0];
+		dev->pma_counter_select[1] = p->counter_select[1];
+		dev->pma_counter_select[2] = p->counter_select[2];
+		dev->pma_counter_select[3] = p->counter_select[3];
+		dev->pma_counter_select[4] = p->counter_select[4];
+		if (crp->cr_psstat) {
+			ipath_write_creg(dev->dd, crp->cr_psinterval,
+					 dev->pma_sample_interval);
+			ipath_write_creg(dev->dd, crp->cr_psstart,
+					 dev->pma_sample_start);
+		} else
+			dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_STARTED;
 	}
+	spin_unlock_irqrestore(&dev->pending_lock, flags);
+
 	ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port);
 
 bail:
 	return ret;
 }
 
-static u64 get_counter(struct ipath_ibdev *dev, __be16 sel)
+static u64 get_counter(struct ipath_ibdev *dev,
+		       struct ipath_cregs const *crp,
+		       __be16 sel)
 {
 	u64 ret;
 
 	switch (sel) {
 	case IB_PMA_PORT_XMIT_DATA:
-		ret = dev->ipath_sword;
+		ret = (crp->cr_psxmitdatacount) ?
+			ipath_read_creg32(dev->dd, crp->cr_psxmitdatacount) :
+			dev->ipath_sword;
 		break;
 	case IB_PMA_PORT_RCV_DATA:
-		ret = dev->ipath_rword;
+		ret = (crp->cr_psrcvdatacount) ?
+			ipath_read_creg32(dev->dd, crp->cr_psrcvdatacount) :
+			dev->ipath_rword;
 		break;
 	case IB_PMA_PORT_XMIT_PKTS:
-		ret = dev->ipath_spkts;
+		ret = (crp->cr_psxmitpktscount) ?
+			ipath_read_creg32(dev->dd, crp->cr_psxmitpktscount) :
+			dev->ipath_spkts;
 		break;
 	case IB_PMA_PORT_RCV_PKTS:
-		ret = dev->ipath_rpkts;
+		ret = (crp->cr_psrcvpktscount) ?
+			ipath_read_creg32(dev->dd, crp->cr_psrcvpktscount) :
+			dev->ipath_rpkts;
 		break;
 	case IB_PMA_PORT_XMIT_WAIT:
-		ret = dev->ipath_xmit_wait;
+		ret = (crp->cr_psxmitwaitcount) ?
+			ipath_read_creg32(dev->dd, crp->cr_psxmitwaitcount) :
+			dev->ipath_xmit_wait;
 		break;
 	default:
 		ret = 0;
@@ -1053,14 +1066,21 @@ static int recv_pma_get_portsamplesresult(struct ib_perf *pmp,
 	struct ib_pma_portsamplesresult *p =
 		(struct ib_pma_portsamplesresult *)pmp->data;
 	struct ipath_ibdev *dev = to_idev(ibdev);
+	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
+	u8 status;
 	int i;
 
 	memset(pmp->data, 0, sizeof(pmp->data));
 	p->tag = cpu_to_be16(dev->pma_tag);
-	p->sample_status = cpu_to_be16(dev->pma_sample_status);
+	if (crp->cr_psstat)
+		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
+	else
+		status = dev->pma_sample_status;
+	p->sample_status = cpu_to_be16(status);
 	for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
-		p->counter[i] = cpu_to_be32(
-			get_counter(dev, dev->pma_counter_select[i]));
+		p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
+		    cpu_to_be32(
+			get_counter(dev, crp, dev->pma_counter_select[i]));
 
 	return reply((struct ib_smp *) pmp);
 }
@@ -1071,16 +1091,23 @@ static int recv_pma_get_portsamplesresult_ext(struct ib_perf *pmp,
 	struct ib_pma_portsamplesresult_ext *p =
 		(struct ib_pma_portsamplesresult_ext *)pmp->data;
 	struct ipath_ibdev *dev = to_idev(ibdev);
+	struct ipath_cregs const *crp = dev->dd->ipath_cregs;
+	u8 status;
 	int i;
 
 	memset(pmp->data, 0, sizeof(pmp->data));
 	p->tag = cpu_to_be16(dev->pma_tag);
-	p->sample_status = cpu_to_be16(dev->pma_sample_status);
+	if (crp->cr_psstat)
+		status = ipath_read_creg32(dev->dd, crp->cr_psstat);
+	else
+		status = dev->pma_sample_status;
+	p->sample_status = cpu_to_be16(status);
 	/* 64 bits */
 	p->extended_width = __constant_cpu_to_be32(0x80000000);
 	for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++)
-		p->counter[i] = cpu_to_be64(
-			get_counter(dev, dev->pma_counter_select[i]));
+		p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 :
+		    cpu_to_be64(
+			get_counter(dev, crp, dev->pma_counter_select[i]));
 
 	return reply((struct ib_smp *) pmp);
 }
@@ -1113,6 +1140,8 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp,
 		dev->z_local_link_integrity_errors;
 	cntrs.excessive_buffer_overrun_errors -=
 		dev->z_excessive_buffer_overrun_errors;
+	cntrs.vl15_dropped -= dev->z_vl15_dropped;
+	cntrs.vl15_dropped += dev->n_vl15_dropped;
 
 	memset(pmp->data, 0, sizeof(pmp->data));
 
@@ -1156,10 +1185,10 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp,
 		cntrs.excessive_buffer_overrun_errors = 0xFUL;
 	p->lli_ebor_errors = (cntrs.local_link_integrity_errors << 4) |
 		cntrs.excessive_buffer_overrun_errors;
-	if (dev->n_vl15_dropped > 0xFFFFUL)
+	if (cntrs.vl15_dropped > 0xFFFFUL)
 		p->vl15_dropped = __constant_cpu_to_be16(0xFFFF);
 	else
-		p->vl15_dropped = cpu_to_be16((u16)dev->n_vl15_dropped);
+		p->vl15_dropped = cpu_to_be16((u16)cntrs.vl15_dropped);
 	if (cntrs.port_xmit_data > 0xFFFFFFFFUL)
 		p->port_xmit_data = __constant_cpu_to_be32(0xFFFFFFFF);
 	else
@@ -1262,8 +1291,10 @@ static int recv_pma_set_portcounters(struct ib_perf *pmp,
 		dev->z_excessive_buffer_overrun_errors =
 			cntrs.excessive_buffer_overrun_errors;
 
-	if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED)
+	if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) {
 		dev->n_vl15_dropped = 0;
+		dev->z_vl15_dropped = cntrs.vl15_dropped;
+	}
 
 	if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA)
 		dev->z_port_xmit_data = cntrs.port_xmit_data;
@@ -1434,7 +1465,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
 		 * before checking for other consumers.
 		 * Just tell the caller to process it normally.
 		 */
-		ret = IB_MAD_RESULT_FAILURE;
+		ret = IB_MAD_RESULT_SUCCESS;
 		goto bail;
 	default:
 		smp->status |= IB_SMP_UNSUP_METHOD;
@@ -1516,7 +1547,7 @@ static int process_perf(struct ib_device *ibdev, u8 port_num,
 		 * before checking for other consumers.
 		 * Just tell the caller to process it normally.
 		 */
-		ret = IB_MAD_RESULT_FAILURE;
+		ret = IB_MAD_RESULT_SUCCESS;
 		goto bail;
 	default:
 		pmp->status |= IB_SMP_UNSUP_METHOD;
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index b997ff88401b..80dc623cee40 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -387,8 +387,8 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
 	struct ib_wc wc;
 	int ret = 0;
 
-	ipath_dbg("QP%d/%d in error state\n",
-		  qp->ibqp.qp_num, qp->remote_qpn);
+	ipath_dbg("QP%d/%d in error state (%d)\n",
+		  qp->ibqp.qp_num, qp->remote_qpn, err);
 
 	spin_lock(&dev->pending_lock);
 	/* XXX What if its already removed by the timeout code? */
@@ -855,8 +855,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
 	 * See ipath_mmap() for details.
 	 */
 	if (udata && udata->outlen >= sizeof(__u64)) {
-		int err;
-
 		if (!qp->r_rq.wq) {
 			__u64 offset = 0;
 
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 120a61b03bc4..459e46e2c016 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -647,6 +647,7 @@ static void send_rc_ack(struct ipath_qp *qp)
 
 queue_ack:
 	spin_lock_irqsave(&qp->s_lock, flags);
+	dev->n_rc_qacks++;
 	qp->s_flags |= IPATH_S_ACK_PENDING;
 	qp->s_nak_state = qp->r_nak_state;
 	qp->s_ack_psn = qp->r_ack_psn;
@@ -798,11 +799,13 @@ bail:
 
 static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
 {
-	if (qp->s_wait_credit) {
-		qp->s_wait_credit = 0;
-		tasklet_hi_schedule(&qp->s_task);
+	if (qp->s_last_psn != psn) {
+		qp->s_last_psn = psn;
+		if (qp->s_wait_credit) {
+			qp->s_wait_credit = 0;
+			tasklet_hi_schedule(&qp->s_task);
+		}
 	}
-	qp->s_last_psn = psn;
 }
 
 /**
@@ -1653,13 +1656,6 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
 	case OP(SEND_FIRST):
 		if (!ipath_get_rwqe(qp, 0)) {
 		rnr_nak:
-			/*
-			 * A RNR NAK will ACK earlier sends and RDMA writes.
-			 * Don't queue the NAK if a RDMA read or atomic
-			 * is pending though.
-			 */
-			if (qp->r_nak_state)
-				goto done;
 			qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
 			qp->r_ack_psn = qp->r_psn;
 			goto send_ack;
diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h
index 708eba3165d7..6d2a17f9c1da 100644
--- a/drivers/infiniband/hw/ipath/ipath_registers.h
+++ b/drivers/infiniband/hw/ipath/ipath_registers.h
@@ -82,8 +82,7 @@
 
 /* kr_rcvctrl bits */
 #define INFINIPATH_R_PORTENABLE_SHIFT 0
-#define INFINIPATH_R_INTRAVAIL_SHIFT 16
-#define INFINIPATH_R_TAILUPD   0x80000000
+#define INFINIPATH_R_QPMAP_ENABLE (1ULL << 38)
 
 /* kr_intstatus, kr_intclear, kr_intmask bits */
 #define INFINIPATH_I_RCVURG_SHIFT 0
@@ -272,20 +271,6 @@
 #define INFINIPATH_EXTC_LEDGBLOK_ON          0x00000002ULL
 #define INFINIPATH_EXTC_LEDGBLERR_OFF        0x00000001ULL
 
-/* kr_mdio bits */
-#define INFINIPATH_MDIO_CLKDIV_MASK 0x7FULL
-#define INFINIPATH_MDIO_CLKDIV_SHIFT 32
-#define INFINIPATH_MDIO_COMMAND_MASK 0x7ULL
-#define INFINIPATH_MDIO_COMMAND_SHIFT 26
-#define INFINIPATH_MDIO_DEVADDR_MASK 0x1FULL
-#define INFINIPATH_MDIO_DEVADDR_SHIFT 21
-#define INFINIPATH_MDIO_REGADDR_MASK 0x1FULL
-#define INFINIPATH_MDIO_REGADDR_SHIFT 16
-#define INFINIPATH_MDIO_DATA_MASK 0xFFFFULL
-#define INFINIPATH_MDIO_DATA_SHIFT 0
-#define INFINIPATH_MDIO_CMDVALID    0x0000000040000000ULL
-#define INFINIPATH_MDIO_RDDATAVALID 0x0000000080000000ULL
-
 /* kr_partitionkey bits */
 #define INFINIPATH_PKEY_SIZE 16
 #define INFINIPATH_PKEY_MASK 0xFFFF
@@ -303,8 +288,6 @@
 
 /* kr_xgxsconfig bits */
 #define INFINIPATH_XGXS_RESET          0x7ULL
-#define INFINIPATH_XGXS_MDIOADDR_MASK  0xfULL
-#define INFINIPATH_XGXS_MDIOADDR_SHIFT 4
 #define INFINIPATH_XGXS_RX_POL_SHIFT 19
 #define INFINIPATH_XGXS_RX_POL_MASK 0xfULL
 
@@ -470,6 +453,20 @@ struct ipath_cregs {
 	ipath_creg cr_unsupvlcnt;
 	ipath_creg cr_wordrcvcnt;
 	ipath_creg cr_wordsendcnt;
+	ipath_creg cr_vl15droppedpktcnt;
+	ipath_creg cr_rxotherlocalphyerrcnt;
+	ipath_creg cr_excessbufferovflcnt;
+	ipath_creg cr_locallinkintegrityerrcnt;
+	ipath_creg cr_rxvlerrcnt;
+	ipath_creg cr_rxdlidfltrcnt;
+	ipath_creg cr_psstat;
+	ipath_creg cr_psstart;
+	ipath_creg cr_psinterval;
+	ipath_creg cr_psrcvdatacount;
+	ipath_creg cr_psrcvpktscount;
+	ipath_creg cr_psxmitdatacount;
+	ipath_creg cr_psxmitpktscount;
+	ipath_creg cr_psxmitwaitcount;
 };
 
 #endif				/* _IPATH_REGISTERS_H */
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index 54c61a972de2..a59bdbd0ed87 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -98,11 +98,15 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
 		while (qp->s_rnr_timeout >= nqp->s_rnr_timeout) {
 			qp->s_rnr_timeout -= nqp->s_rnr_timeout;
 			l = l->next;
-			if (l->next == &dev->rnrwait)
+			if (l->next == &dev->rnrwait) {
+				nqp = NULL;
 				break;
+			}
 			nqp = list_entry(l->next, struct ipath_qp,
 					 timerwait);
 		}
+		if (nqp)
+			nqp->s_rnr_timeout -= qp->s_rnr_timeout;
 		list_add(&qp->timerwait, l);
 	}
 	spin_unlock_irqrestore(&dev->pending_lock, flags);
@@ -479,9 +483,14 @@ done:
 
 static void want_buffer(struct ipath_devdata *dd)
 {
-	set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+	unsigned long flags;
+
+	spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+	dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL;
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
 			 dd->ipath_sendctrl);
+	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+	spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
 }
 
 /**
diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c
index 2fef36f4b675..f772102e4713 100644
--- a/drivers/infiniband/hw/ipath/ipath_srq.c
+++ b/drivers/infiniband/hw/ipath/ipath_srq.c
@@ -94,8 +94,8 @@ bail:
 /**
  * ipath_create_srq - create a shared receive queue
  * @ibpd: the protection domain of the SRQ to create
- * @attr: the attributes of the SRQ
- * @udata: not used by the InfiniPath verbs driver
+ * @srq_init_attr: the attributes of the SRQ
+ * @udata: data from libipathverbs when creating a user SRQ
  */
 struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
 				struct ib_srq_init_attr *srq_init_attr,
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
index f0271415cd5b..d2725cd11bdc 100644
--- a/drivers/infiniband/hw/ipath/ipath_stats.c
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
@@ -133,15 +133,16 @@ bail:
 static void ipath_qcheck(struct ipath_devdata *dd)
 {
 	static u64 last_tot_hdrqfull;
+	struct ipath_portdata *pd = dd->ipath_pd[0];
 	size_t blen = 0;
 	char buf[128];
 
 	*buf = 0;
-	if (dd->ipath_pd[0]->port_hdrqfull != dd->ipath_p0_hdrqfull) {
+	if (pd->port_hdrqfull != dd->ipath_p0_hdrqfull) {
 		blen = snprintf(buf, sizeof buf, "port 0 hdrqfull %u",
-				dd->ipath_pd[0]->port_hdrqfull -
+				pd->port_hdrqfull -
 				dd->ipath_p0_hdrqfull);
-		dd->ipath_p0_hdrqfull = dd->ipath_pd[0]->port_hdrqfull;
+		dd->ipath_p0_hdrqfull = pd->port_hdrqfull;
 	}
 	if (ipath_stats.sps_etidfull != dd->ipath_last_tidfull) {
 		blen += snprintf(buf + blen, sizeof buf - blen,
@@ -173,7 +174,7 @@ static void ipath_qcheck(struct ipath_devdata *dd)
 	if (blen)
 		ipath_dbg("%s\n", buf);
 
-	if (dd->ipath_port0head != (u32)
+	if (pd->port_head != (u32)
 	    le64_to_cpu(*dd->ipath_hdrqtailptr)) {
 		if (dd->ipath_lastport0rcv_cnt ==
 		    ipath_stats.sps_port0pkts) {
@@ -181,7 +182,7 @@ static void ipath_qcheck(struct ipath_devdata *dd)
 				   "port0 hd=%llx tl=%x; port0pkts %llx\n",
 				   (unsigned long long)
 				   le64_to_cpu(*dd->ipath_hdrqtailptr),
-				   dd->ipath_port0head,
+				   pd->port_head,
 				   (unsigned long long)
 				   ipath_stats.sps_port0pkts);
 		}
@@ -237,7 +238,7 @@ static void ipath_chk_errormask(struct ipath_devdata *dd)
 void ipath_get_faststats(unsigned long opaque)
 {
 	struct ipath_devdata *dd = (struct ipath_devdata *) opaque;
-	u32 val;
+	int i;
 	static unsigned cnt;
 	unsigned long flags;
 	u64 traffic_wds;
@@ -321,12 +322,11 @@ void ipath_get_faststats(unsigned long opaque)
 
 	/* limit qfull messages to ~one per minute per port */
 	if ((++cnt & 0x10)) {
-		for (val = dd->ipath_cfgports - 1; ((int)val) >= 0;
-		     val--) {
-			if (dd->ipath_lastegrheads[val] != -1)
-				dd->ipath_lastegrheads[val] = -1;
-			if (dd->ipath_lastrcvhdrqtails[val] != -1)
-				dd->ipath_lastrcvhdrqtails[val] = -1;
+		for (i = (int) dd->ipath_cfgports; --i >= 0; ) {
+			struct ipath_portdata *pd = dd->ipath_pd[i];
+
+			if (pd && pd->port_lastrcvhdrqtail != -1)
+				pd->port_lastrcvhdrqtail = -1;
 		}
 	}
 
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index e1ad7cfc21fd..56dfc8a2344c 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -363,6 +363,60 @@ static ssize_t show_unit(struct device *dev,
 	return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit);
 }
 
+static ssize_t show_jint_max_packets(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_max_packets);
+}
+
+static ssize_t store_jint_max_packets(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf,
+				      size_t count)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	u16 v = 0;
+	int ret;
+
+	ret = ipath_parse_ushort(buf, &v);
+	if (ret < 0)
+		ipath_dev_err(dd, "invalid jint_max_packets.\n");
+	else
+		dd->ipath_f_config_jint(dd, dd->ipath_jint_idle_ticks, v);
+
+	return ret;
+}
+
+static ssize_t show_jint_idle_ticks(struct device *dev,
+				    struct device_attribute *attr,
+				    char *buf)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_idle_ticks);
+}
+
+static ssize_t store_jint_idle_ticks(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf,
+				     size_t count)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	u16 v = 0;
+	int ret;
+
+	ret = ipath_parse_ushort(buf, &v);
+	if (ret < 0)
+		ipath_dev_err(dd, "invalid jint_idle_ticks.\n");
+	else
+		dd->ipath_f_config_jint(dd, v, dd->ipath_jint_max_packets);
+
+	return ret;
+}
+
 #define DEVICE_COUNTER(name, attr) \
 	static ssize_t show_counter_##name(struct device *dev, \
 					   struct device_attribute *attr, \
@@ -670,6 +724,257 @@ static ssize_t show_logged_errs(struct device *dev,
 	return count;
 }
 
+/*
+ * New sysfs entries to control various IB config. These all turn into
+ * accesses via ipath_f_get/set_ib_cfg.
+ *
+ * Get/Set heartbeat enable. Or of 1=enabled, 2=auto
+ */
+static ssize_t show_hrtbt_enb(struct device *dev,
+			 struct device_attribute *attr,
+			 char *buf)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret;
+
+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_HRTBT);
+	if (ret >= 0)
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+	return ret;
+}
+
+static ssize_t store_hrtbt_enb(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf,
+			  size_t count)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret, r;
+	u16 val;
+
+	ret = ipath_parse_ushort(buf, &val);
+	if (ret >= 0 && val > 3)
+		ret = -EINVAL;
+	if (ret < 0) {
+		ipath_dev_err(dd, "attempt to set invalid Heartbeat enable\n");
+		goto bail;
+	}
+
+	/*
+	 * Set the "intentional" heartbeat enable per either of
+	 * "Enable" and "Auto", as these are normally set together.
+	 * This bit is consulted when leaving loopback mode,
+	 * because entering loopback mode overrides it and automatically
+	 * disables heartbeat.
+	 */
+	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT, val);
+	if (r < 0)
+		ret = r;
+	else if (val == IPATH_IB_HRTBT_OFF)
+		dd->ipath_flags |= IPATH_NO_HRTBT;
+	else
+		dd->ipath_flags &= ~IPATH_NO_HRTBT;
+
+bail:
+	return ret;
+}
+
+/*
+ * Get/Set Link-widths enabled. Or of 1=1x, 2=4x (this is human/IB centric,
+ * _not_ the particular encoding of any given chip)
+ */
+static ssize_t show_lwid_enb(struct device *dev,
+			 struct device_attribute *attr,
+			 char *buf)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret;
+
+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB);
+	if (ret >= 0)
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+	return ret;
+}
+
+static ssize_t store_lwid_enb(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf,
+			  size_t count)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret, r;
+	u16 val;
+
+	ret = ipath_parse_ushort(buf, &val);
+	if (ret >= 0 && (val == 0 || val > 3))
+		ret = -EINVAL;
+	if (ret < 0) {
+		ipath_dev_err(dd,
+			"attempt to set invalid Link Width (enable)\n");
+		goto bail;
+	}
+
+	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB, val);
+	if (r < 0)
+		ret = r;
+
+bail:
+	return ret;
+}
+
+/* Get current link width */
+static ssize_t show_lwid(struct device *dev,
+			 struct device_attribute *attr,
+			 char *buf)
+
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret;
+
+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID);
+	if (ret >= 0)
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+	return ret;
+}
+
+/*
+ * Get/Set Link-speeds enabled. Or of 1=SDR 2=DDR.
+ */
+static ssize_t show_spd_enb(struct device *dev,
+			 struct device_attribute *attr,
+			 char *buf)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret;
+
+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB);
+	if (ret >= 0)
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+	return ret;
+}
+
+static ssize_t store_spd_enb(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf,
+			  size_t count)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret, r;
+	u16 val;
+
+	ret = ipath_parse_ushort(buf, &val);
+	if (ret >= 0 && (val == 0 || val > (IPATH_IB_SDR | IPATH_IB_DDR)))
+		ret = -EINVAL;
+	if (ret < 0) {
+		ipath_dev_err(dd,
+			"attempt to set invalid Link Speed (enable)\n");
+		goto bail;
+	}
+
+	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB, val);
+	if (r < 0)
+		ret = r;
+
+bail:
+	return ret;
+}
+
+/* Get current link speed */
+static ssize_t show_spd(struct device *dev,
+			 struct device_attribute *attr,
+			 char *buf)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret;
+
+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD);
+	if (ret >= 0)
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+	return ret;
+}
+
+/*
+ * Get/Set RX polarity-invert enable. 0=no, 1=yes.
+ */
+static ssize_t show_rx_polinv_enb(struct device *dev,
+			 struct device_attribute *attr,
+			 char *buf)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret;
+
+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB);
+	if (ret >= 0)
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+	return ret;
+}
+
+static ssize_t store_rx_polinv_enb(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf,
+			  size_t count)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret, r;
+	u16 val;
+
+	ret = ipath_parse_ushort(buf, &val);
+	if (ret < 0 || val > 1)
+		goto invalid;
+
+	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB, val);
+	if (r < 0) {
+		ret = r;
+		goto bail;
+	}
+
+	goto bail;
+invalid:
+	ipath_dev_err(dd, "attempt to set invalid Rx Polarity (enable)\n");
+bail:
+	return ret;
+}
+/*
+ * Get/Set RX lane-reversal enable. 0=no, 1=yes.
+ */
+static ssize_t show_lanerev_enb(struct device *dev,
+			 struct device_attribute *attr,
+			 char *buf)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret;
+
+	ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB);
+	if (ret >= 0)
+		ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret);
+	return ret;
+}
+
+static ssize_t store_lanerev_enb(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf,
+			  size_t count)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	int ret, r;
+	u16 val;
+
+	ret = ipath_parse_ushort(buf, &val);
+	if (ret >= 0 && val > 1) {
+		ret = -EINVAL;
+		ipath_dev_err(dd,
+			"attempt to set invalid Lane reversal (enable)\n");
+		goto bail;
+	}
+
+	r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB, val);
+	if (r < 0)
+		ret = r;
+
+bail:
+	return ret;
+}
+
 static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL);
 static DRIVER_ATTR(version, S_IRUGO, show_version, NULL);
 
@@ -683,6 +988,11 @@ static struct attribute_group driver_attr_group = {
 	.attrs = driver_attributes
 };
 
+struct attribute_group *ipath_driver_attr_groups[] = {
+	&driver_attr_group,
+	NULL,
+};
+
 static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid);
 static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc);
 static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid);
@@ -701,6 +1011,10 @@ static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL);
 static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv);
 static DEVICE_ATTR(led_override, S_IWUSR, NULL, store_led_override);
 static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
+static DEVICE_ATTR(jint_max_packets, S_IWUSR | S_IRUGO,
+		   show_jint_max_packets, store_jint_max_packets);
+static DEVICE_ATTR(jint_idle_ticks, S_IWUSR | S_IRUGO,
+		   show_jint_idle_ticks, store_jint_idle_ticks);
 
 static struct attribute *dev_attributes[] = {
 	&dev_attr_guid.attr,
@@ -727,6 +1041,34 @@ static struct attribute_group dev_attr_group = {
 	.attrs = dev_attributes
 };
 
+static DEVICE_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb,
+		   store_hrtbt_enb);
+static DEVICE_ATTR(link_width_enable, S_IWUSR | S_IRUGO, show_lwid_enb,
+		   store_lwid_enb);
+static DEVICE_ATTR(link_width, S_IRUGO, show_lwid, NULL);
+static DEVICE_ATTR(link_speed_enable, S_IWUSR | S_IRUGO, show_spd_enb,
+		   store_spd_enb);
+static DEVICE_ATTR(link_speed, S_IRUGO, show_spd, NULL);
+static DEVICE_ATTR(rx_pol_inv_enable, S_IWUSR | S_IRUGO, show_rx_polinv_enb,
+		   store_rx_polinv_enb);
+static DEVICE_ATTR(rx_lane_rev_enable, S_IWUSR | S_IRUGO, show_lanerev_enb,
+		   store_lanerev_enb);
+
+static struct attribute *dev_ibcfg_attributes[] = {
+	&dev_attr_hrtbt_enable.attr,
+	&dev_attr_link_width_enable.attr,
+	&dev_attr_link_width.attr,
+	&dev_attr_link_speed_enable.attr,
+	&dev_attr_link_speed.attr,
+	&dev_attr_rx_pol_inv_enable.attr,
+	&dev_attr_rx_lane_rev_enable.attr,
+	NULL
+};
+
+static struct attribute_group dev_ibcfg_attr_group = {
+	.attrs = dev_ibcfg_attributes
+};
+
 /**
  * ipath_expose_reset - create a device reset file
  * @dev: the device structure
@@ -753,24 +1095,9 @@ int ipath_expose_reset(struct device *dev)
 	return ret;
 }
 
-int ipath_driver_create_group(struct device_driver *drv)
-{
-	int ret;
-
-	ret = sysfs_create_group(&drv->kobj, &driver_attr_group);
-
-	return ret;
-}
-
-void ipath_driver_remove_group(struct device_driver *drv)
-{
-	sysfs_remove_group(&drv->kobj, &driver_attr_group);
-}
-
 int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
 {
 	int ret;
-	char unit[5];
 
 	ret = sysfs_create_group(&dev->kobj, &dev_attr_group);
 	if (ret)
@@ -780,11 +1107,26 @@ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd)
 	if (ret)
 		goto bail_attrs;
 
-	snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit);
-	ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, unit);
-	if (ret == 0)
-		goto bail;
+	if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
+		ret = device_create_file(dev, &dev_attr_jint_idle_ticks);
+		if (ret)
+			goto bail_counter;
+		ret = device_create_file(dev, &dev_attr_jint_max_packets);
+		if (ret)
+			goto bail_idle;
 
+		ret = sysfs_create_group(&dev->kobj, &dev_ibcfg_attr_group);
+		if (ret)
+			goto bail_max;
+	}
+
+	return 0;
+
+bail_max:
+	device_remove_file(dev, &dev_attr_jint_max_packets);
+bail_idle:
+	device_remove_file(dev, &dev_attr_jint_idle_ticks);
+bail_counter:
 	sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
 bail_attrs:
 	sysfs_remove_group(&dev->kobj, &dev_attr_group);
@@ -794,12 +1136,14 @@ bail:
 
 void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd)
 {
-	char unit[5];
+	sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
 
-	snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit);
-	sysfs_remove_link(&dev->driver->kobj, unit);
+	if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) {
+		sysfs_remove_group(&dev->kobj, &dev_ibcfg_attr_group);
+		device_remove_file(dev, &dev_attr_jint_idle_ticks);
+		device_remove_file(dev, &dev_attr_jint_max_packets);
+	}
 
-	sysfs_remove_group(&dev->kobj, &dev_counter_attr_group);
 	sysfs_remove_group(&dev->kobj, &dev_attr_group);
 
 	device_remove_file(dev, &dev_attr_reset);
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index b3df6f3c705e..de67eed08ed0 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -301,8 +301,6 @@ int ipath_make_ud_req(struct ipath_qp *qp)
 
 	/* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */
 	qp->s_hdrwords = 7;
-	if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
-		qp->s_hdrwords++;
 	qp->s_cur_size = wqe->length;
 	qp->s_cur_sge = &qp->s_sge;
 	qp->s_wqe = wqe;
@@ -327,6 +325,7 @@ int ipath_make_ud_req(struct ipath_qp *qp)
 		ohdr = &qp->s_hdr.u.oth;
 	}
 	if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+		qp->s_hdrwords++;
 		ohdr->u.ud.imm_data = wqe->wr.imm_data;
 		bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
 	} else
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index c4c998446c7b..32d8f882e56c 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -943,7 +943,7 @@ bail:
  * ipath_verbs_send - send a packet
  * @qp: the QP to send on
  * @hdr: the packet header
- * @hdrwords: the number of words in the header
+ * @hdrwords: the number of 32-bit words in the header
  * @ss: the SGE to send
  * @len: the length of the packet in bytes
  */
@@ -955,7 +955,10 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
 	int ret;
 	u32 dwords = (len + 3) >> 2;
 
-	/* +1 is for the qword padding of pbc */
+	/*
+	 * Calculate the send buffer trigger address.
+	 * The +1 counts for the pbc control dword following the pbc length.
+	 */
 	plen = hdrwords + dwords + 1;
 
 	/* Drop non-VL15 packets if we are not in the active state */
@@ -1130,20 +1133,34 @@ static int ipath_query_device(struct ib_device *ibdev,
 	return 0;
 }
 
-const u8 ipath_cvt_physportstate[16] = {
-	[INFINIPATH_IBCS_LT_STATE_DISABLED] = 3,
-	[INFINIPATH_IBCS_LT_STATE_LINKUP] = 5,
-	[INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = 2,
-	[INFINIPATH_IBCS_LT_STATE_POLLQUIET] = 2,
-	[INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = 1,
-	[INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = 1,
-	[INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] = 4,
-	[INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] = 4,
-	[INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] = 4,
-	[INFINIPATH_IBCS_LT_STATE_CFGIDLE] = 4,
-	[INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] = 6,
-	[INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] = 6,
-	[INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6,
+const u8 ipath_cvt_physportstate[32] = {
+	[INFINIPATH_IBCS_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED,
+	[INFINIPATH_IBCS_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP,
+	[INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL,
+	[INFINIPATH_IBCS_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL,
+	[INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP,
+	[INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP,
+	[INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] =
+		IB_PHYSPORTSTATE_CFG_TRAIN,
+	[INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] =
+		IB_PHYSPORTSTATE_CFG_TRAIN,
+	[INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] =
+		IB_PHYSPORTSTATE_CFG_TRAIN,
+	[INFINIPATH_IBCS_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_TRAIN,
+	[INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] =
+		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+	[INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] =
+		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+	[INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] =
+		IB_PHYSPORTSTATE_LINK_ERR_RECOVER,
+	[0x10] = IB_PHYSPORTSTATE_CFG_TRAIN,
+	[0x11] = IB_PHYSPORTSTATE_CFG_TRAIN,
+	[0x12] = IB_PHYSPORTSTATE_CFG_TRAIN,
+	[0x13] = IB_PHYSPORTSTATE_CFG_TRAIN,
+	[0x14] = IB_PHYSPORTSTATE_CFG_TRAIN,
+	[0x15] = IB_PHYSPORTSTATE_CFG_TRAIN,
+	[0x16] = IB_PHYSPORTSTATE_CFG_TRAIN,
+	[0x17] = IB_PHYSPORTSTATE_CFG_TRAIN
 };
 
 u32 ipath_get_cr_errpkey(struct ipath_devdata *dd)
@@ -1168,8 +1185,9 @@ static int ipath_query_port(struct ib_device *ibdev,
 	ibcstat = dd->ipath_lastibcstat;
 	props->state = ((ibcstat >> 4) & 0x3) + 1;
 	/* See phys_state_show() */
-	props->phys_state = ipath_cvt_physportstate[
-		dd->ipath_lastibcstat & 0xf];
+	props->phys_state = /* MEA: assumes shift == 0 */
+		ipath_cvt_physportstate[dd->ipath_lastibcstat &
+		dd->ibcs_lts_mask];
 	props->port_cap_flags = dev->port_cap_flags;
 	props->gid_tbl_len = 1;
 	props->max_msg_sz = 0x80000000;
@@ -1641,6 +1659,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
 		cntrs.local_link_integrity_errors;
 	idev->z_excessive_buffer_overrun_errors =
 		cntrs.excessive_buffer_overrun_errors;
+	idev->z_vl15_dropped = cntrs.vl15_dropped;
 
 	/*
 	 * The system image GUID is supposed to be the same for all
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index 6ccb54f104a3..3d59736b49b2 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -554,6 +554,7 @@ struct ipath_ibdev {
 	u32 z_pkey_violations;			/* starting count for PMA */
 	u32 z_local_link_integrity_errors;	/* starting count for PMA */
 	u32 z_excessive_buffer_overrun_errors;	/* starting count for PMA */
+	u32 z_vl15_dropped;			/* starting count for PMA */
 	u32 n_rc_resends;
 	u32 n_rc_acks;
 	u32 n_rc_qacks;
@@ -598,6 +599,7 @@ struct ipath_verbs_counters {
 	u64 port_rcv_packets;
 	u32 local_link_integrity_errors;
 	u32 excessive_buffer_overrun_errors;
+	u32 vl15_dropped;
 };
 
 static inline struct ipath_mr *to_imr(struct ib_mr *ibmr)
@@ -830,7 +832,17 @@ unsigned ipath_get_pkey(struct ipath_devdata *, unsigned);
 
 extern const enum ib_wc_opcode ib_ipath_wc_opcode[];
 
+/*
+ * Below converts HCA-specific LinkTrainingState to IB PhysPortState
+ * values.
+ */
 extern const u8 ipath_cvt_physportstate[];
+#define IB_PHYSPORTSTATE_SLEEP 1
+#define IB_PHYSPORTSTATE_POLL 2
+#define IB_PHYSPORTSTATE_DISABLED 3
+#define IB_PHYSPORTSTATE_CFG_TRAIN 4
+#define IB_PHYSPORTSTATE_LINKUP 5
+#define IB_PHYSPORTSTATE_LINK_ERR_RECOVER 6
 
 extern const int ib_ipath_state_ops[];
 
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 9d32c49cc651..7950aa6e8184 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -313,6 +313,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
 	struct mlx4_ib_srq *srq;
 	int is_send;
 	int is_error;
+	u32 g_mlpath_rqpn;
 	u16 wqe_ctr;
 
 	cqe = next_cqe_sw(cq);
@@ -426,10 +427,10 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
 
 		wc->slid	   = be16_to_cpu(cqe->rlid);
 		wc->sl		   = cqe->sl >> 4;
-		wc->src_qp	   = be32_to_cpu(cqe->g_mlpath_rqpn) & 0xffffff;
-		wc->dlid_path_bits = (be32_to_cpu(cqe->g_mlpath_rqpn) >> 24) & 0x7f;
-		wc->wc_flags      |= be32_to_cpu(cqe->g_mlpath_rqpn) & 0x80000000 ?
-			IB_WC_GRH : 0;
+		g_mlpath_rqpn	   = be32_to_cpu(cqe->g_mlpath_rqpn);
+		wc->src_qp	   = g_mlpath_rqpn & 0xffffff;
+		wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f;
+		wc->wc_flags	  |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0;
 		wc->pkey_index     = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f;
 	}
 
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index 15aa32eb78b6..7bbdd1f4e6c7 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -60,13 +60,12 @@
 enum {
 	MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
 	MTHCA_FLAG_SRQ        = 1 << 2,
-	MTHCA_FLAG_MSI        = 1 << 3,
-	MTHCA_FLAG_MSI_X      = 1 << 4,
-	MTHCA_FLAG_NO_LAM     = 1 << 5,
-	MTHCA_FLAG_FMR        = 1 << 6,
-	MTHCA_FLAG_MEMFREE    = 1 << 7,
-	MTHCA_FLAG_PCIE       = 1 << 8,
-	MTHCA_FLAG_SINAI_OPT  = 1 << 9
+	MTHCA_FLAG_MSI_X      = 1 << 3,
+	MTHCA_FLAG_NO_LAM     = 1 << 4,
+	MTHCA_FLAG_FMR        = 1 << 5,
+	MTHCA_FLAG_MEMFREE    = 1 << 6,
+	MTHCA_FLAG_PCIE       = 1 << 7,
+	MTHCA_FLAG_SINAI_OPT  = 1 << 8
 };
 
 enum {
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index b29de51b7f35..b60eb5df96e8 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -827,8 +827,7 @@ int mthca_init_eq_table(struct mthca_dev *dev)
 	if (err)
 		goto err_out_free;
 
-	if (dev->mthca_flags & MTHCA_FLAG_MSI ||
-	    dev->mthca_flags & MTHCA_FLAG_MSI_X) {
+	if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
 		dev->eq_table.clr_mask = 0;
 	} else {
 		dev->eq_table.clr_mask =
@@ -839,8 +838,7 @@ int mthca_init_eq_table(struct mthca_dev *dev)
 
 	dev->eq_table.arm_mask = 0;
 
-	intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ?
-		128 : dev->eq_table.inta_pin;
+	intr = dev->eq_table.inta_pin;
 
 	err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE,
 			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 60de6f93869e..5cf8250d4e16 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -65,14 +65,9 @@ static int msi_x = 1;
 module_param(msi_x, int, 0444);
 MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
 
-static int msi = 0;
-module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)");
-
 #else /* CONFIG_PCI_MSI */
 
 #define msi_x (0)
-#define msi   (0)
 
 #endif /* CONFIG_PCI_MSI */
 
@@ -816,13 +811,11 @@ static int mthca_setup_hca(struct mthca_dev *dev)
 
 	err = mthca_NOP(dev, &status);
 	if (err || status) {
-		if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) {
+		if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
 			mthca_warn(dev, "NOP command failed to generate interrupt "
 				   "(IRQ %d).\n",
-				   dev->mthca_flags & MTHCA_FLAG_MSI_X ?
-				   dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
-				   dev->pdev->irq);
-			mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n");
+				   dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector);
+			mthca_warn(dev, "Trying again with MSI-X disabled.\n");
 		} else {
 			mthca_err(dev, "NOP command failed to generate interrupt "
 				  "(IRQ %d), aborting.\n",
@@ -1005,7 +998,7 @@ static struct {
 			   .flags     = 0 },
 	[ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200),
 			   .flags     = MTHCA_FLAG_PCIE },
-	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 2, 0),
+	[ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 3, 0),
 			   .flags     = MTHCA_FLAG_MEMFREE |
 					MTHCA_FLAG_PCIE },
 	[SINAI]        = { .latest_fw = MTHCA_FW_VER(1, 2, 0),
@@ -1128,29 +1121,12 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
 
 	if (msi_x && !mthca_enable_msi_x(mdev))
 		mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
-	else if (msi) {
-		static int warned;
-
-		if (!warned) {
-			printk(KERN_WARNING PFX "WARNING: MSI support will be "
-			       "removed from the ib_mthca driver in January 2008.\n");
-			printk(KERN_WARNING "    If you are using MSI and cannot "
-			       "switch to MSI-X, please tell "
-			       "<general@lists.openfabrics.org>.\n");
-			++warned;
-		}
-
-		if (!pci_enable_msi(pdev))
-			mdev->mthca_flags |= MTHCA_FLAG_MSI;
-	}
 
 	err = mthca_setup_hca(mdev);
-	if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) {
+	if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) {
 		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 			pci_disable_msix(pdev);
-		if (mdev->mthca_flags & MTHCA_FLAG_MSI)
-			pci_disable_msi(pdev);
-		mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI);
+		mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X;
 
 		err = mthca_setup_hca(mdev);
 	}
@@ -1192,8 +1168,6 @@ err_cleanup:
 err_close:
 	if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 		pci_disable_msix(pdev);
-	if (mdev->mthca_flags & MTHCA_FLAG_MSI)
-		pci_disable_msi(pdev);
 
 	mthca_close_hca(mdev);
 
@@ -1246,8 +1220,6 @@ static void __mthca_remove_one(struct pci_dev *pdev)
 
 		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 			pci_disable_msix(pdev);
-		if (mdev->mthca_flags & MTHCA_FLAG_MSI)
-			pci_disable_msi(pdev);
 
 		ib_dealloc_device(&mdev->ib_dev);
 		mthca_release_regions(pdev, mdev->mthca_flags &
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index eb7edab0e836..fe250c60607d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -56,42 +56,43 @@
 /* constants */
 
 enum {
-	IPOIB_PACKET_SIZE         = 2048,
-	IPOIB_BUF_SIZE 		  = IPOIB_PACKET_SIZE + IB_GRH_BYTES,
+	IPOIB_PACKET_SIZE	  = 2048,
+	IPOIB_BUF_SIZE		  = IPOIB_PACKET_SIZE + IB_GRH_BYTES,
 
-	IPOIB_ENCAP_LEN 	  = 4,
+	IPOIB_ENCAP_LEN		  = 4,
 
-	IPOIB_CM_MTU              = 0x10000 - 0x10, /* padding to align header to 16 */
-	IPOIB_CM_BUF_SIZE         = IPOIB_CM_MTU  + IPOIB_ENCAP_LEN,
-	IPOIB_CM_HEAD_SIZE 	  = IPOIB_CM_BUF_SIZE % PAGE_SIZE,
-	IPOIB_CM_RX_SG            = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE,
-	IPOIB_RX_RING_SIZE 	  = 128,
-	IPOIB_TX_RING_SIZE 	  = 64,
+	IPOIB_CM_MTU		  = 0x10000 - 0x10, /* padding to align header to 16 */
+	IPOIB_CM_BUF_SIZE	  = IPOIB_CM_MTU  + IPOIB_ENCAP_LEN,
+	IPOIB_CM_HEAD_SIZE	  = IPOIB_CM_BUF_SIZE % PAGE_SIZE,
+	IPOIB_CM_RX_SG		  = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE,
+	IPOIB_RX_RING_SIZE	  = 128,
+	IPOIB_TX_RING_SIZE	  = 64,
 	IPOIB_MAX_QUEUE_SIZE	  = 8192,
 	IPOIB_MIN_QUEUE_SIZE	  = 2,
+	IPOIB_CM_MAX_CONN_QP	  = 4096,
 
-	IPOIB_NUM_WC 		  = 4,
+	IPOIB_NUM_WC		  = 4,
 
 	IPOIB_MAX_PATH_REC_QUEUE  = 3,
-	IPOIB_MAX_MCAST_QUEUE     = 3,
-
-	IPOIB_FLAG_OPER_UP 	  = 0,
-	IPOIB_FLAG_INITIALIZED    = 1,
-	IPOIB_FLAG_ADMIN_UP 	  = 2,
-	IPOIB_PKEY_ASSIGNED 	  = 3,
-	IPOIB_PKEY_STOP 	  = 4,
-	IPOIB_FLAG_SUBINTERFACE   = 5,
-	IPOIB_MCAST_RUN 	  = 6,
-	IPOIB_STOP_REAPER         = 7,
-	IPOIB_MCAST_STARTED       = 8,
-	IPOIB_FLAG_ADMIN_CM 	  = 9,
+	IPOIB_MAX_MCAST_QUEUE	  = 3,
+
+	IPOIB_FLAG_OPER_UP	  = 0,
+	IPOIB_FLAG_INITIALIZED	  = 1,
+	IPOIB_FLAG_ADMIN_UP	  = 2,
+	IPOIB_PKEY_ASSIGNED	  = 3,
+	IPOIB_PKEY_STOP		  = 4,
+	IPOIB_FLAG_SUBINTERFACE	  = 5,
+	IPOIB_MCAST_RUN		  = 6,
+	IPOIB_STOP_REAPER	  = 7,
+	IPOIB_MCAST_STARTED	  = 8,
+	IPOIB_FLAG_ADMIN_CM	  = 9,
 	IPOIB_FLAG_UMCAST	  = 10,
 
 	IPOIB_MAX_BACKOFF_SECONDS = 16,
 
-	IPOIB_MCAST_FLAG_FOUND 	  = 0,	/* used in set_multicast_list */
+	IPOIB_MCAST_FLAG_FOUND	  = 0,	/* used in set_multicast_list */
 	IPOIB_MCAST_FLAG_SENDONLY = 1,
-	IPOIB_MCAST_FLAG_BUSY 	  = 2,	/* joining or already joined */
+	IPOIB_MCAST_FLAG_BUSY	  = 2,	/* joining or already joined */
 	IPOIB_MCAST_FLAG_ATTACHED = 3,
 };
 
@@ -117,7 +118,7 @@ struct ipoib_pseudoheader {
 struct ipoib_mcast {
 	struct ib_sa_mcmember_rec mcmember;
 	struct ib_sa_multicast	 *mc;
-	struct ipoib_ah          *ah;
+	struct ipoib_ah		 *ah;
 
 	struct rb_node    rb_node;
 	struct list_head  list;
@@ -186,27 +187,29 @@ enum ipoib_cm_state {
 };
 
 struct ipoib_cm_rx {
-	struct ib_cm_id     *id;
-	struct ib_qp        *qp;
-	struct list_head     list;
-	struct net_device   *dev;
-	unsigned long        jiffies;
-	enum ipoib_cm_state  state;
+	struct ib_cm_id	       *id;
+	struct ib_qp	       *qp;
+	struct ipoib_cm_rx_buf *rx_ring;
+	struct list_head	list;
+	struct net_device      *dev;
+	unsigned long		jiffies;
+	enum ipoib_cm_state	state;
+	int			recv_count;
 };
 
 struct ipoib_cm_tx {
-	struct ib_cm_id     *id;
-	struct ib_qp        *qp;
+	struct ib_cm_id	    *id;
+	struct ib_qp	    *qp;
 	struct list_head     list;
 	struct net_device   *dev;
 	struct ipoib_neigh  *neigh;
 	struct ipoib_path   *path;
 	struct ipoib_tx_buf *tx_ring;
-	unsigned             tx_head;
-	unsigned             tx_tail;
-	unsigned long        flags;
-	u32                  mtu;
-	struct ib_wc         ibwc[IPOIB_NUM_WC];
+	unsigned	     tx_head;
+	unsigned	     tx_tail;
+	unsigned long	     flags;
+	u32		     mtu;
+	struct ib_wc	     ibwc[IPOIB_NUM_WC];
 };
 
 struct ipoib_cm_rx_buf {
@@ -215,25 +218,28 @@ struct ipoib_cm_rx_buf {
 };
 
 struct ipoib_cm_dev_priv {
-	struct ib_srq  	       *srq;
+	struct ib_srq	       *srq;
 	struct ipoib_cm_rx_buf *srq_ring;
-	struct ib_cm_id        *id;
-	struct list_head        passive_ids;   /* state: LIVE */
-	struct list_head        rx_error_list; /* state: ERROR */
-	struct list_head        rx_flush_list; /* state: FLUSH, drain not started */
-	struct list_head        rx_drain_list; /* state: FLUSH, drain started */
-	struct list_head        rx_reap_list;  /* state: FLUSH, drain done */
+	struct ib_cm_id	       *id;
+	struct list_head	passive_ids;   /* state: LIVE */
+	struct list_head	rx_error_list; /* state: ERROR */
+	struct list_head	rx_flush_list; /* state: FLUSH, drain not started */
+	struct list_head	rx_drain_list; /* state: FLUSH, drain started */
+	struct list_head	rx_reap_list;  /* state: FLUSH, drain done */
 	struct work_struct      start_task;
 	struct work_struct      reap_task;
 	struct work_struct      skb_task;
 	struct work_struct      rx_reap_task;
 	struct delayed_work     stale_task;
 	struct sk_buff_head     skb_queue;
-	struct list_head        start_list;
-	struct list_head        reap_list;
-	struct ib_wc            ibwc[IPOIB_NUM_WC];
-	struct ib_sge           rx_sge[IPOIB_CM_RX_SG];
+	struct list_head	start_list;
+	struct list_head	reap_list;
+	struct ib_wc		ibwc[IPOIB_NUM_WC];
+	struct ib_sge		rx_sge[IPOIB_CM_RX_SG];
 	struct ib_recv_wr       rx_wr;
+	int			nonsrq_conn_qp;
+	int			max_cm_mtu;
+	int			num_frags;
 };
 
 /*
@@ -269,30 +275,30 @@ struct ipoib_dev_priv {
 	struct work_struct pkey_event_task;
 
 	struct ib_device *ca;
-	u8            	  port;
-	u16           	  pkey;
-	u16               pkey_index;
-	struct ib_pd  	 *pd;
-	struct ib_mr  	 *mr;
-	struct ib_cq  	 *cq;
-	struct ib_qp  	 *qp;
-	u32           	  qkey;
+	u8		  port;
+	u16		  pkey;
+	u16		  pkey_index;
+	struct ib_pd	 *pd;
+	struct ib_mr	 *mr;
+	struct ib_cq	 *cq;
+	struct ib_qp	 *qp;
+	u32		  qkey;
 
 	union ib_gid local_gid;
-	u16          local_lid;
+	u16	     local_lid;
 
 	unsigned int admin_mtu;
 	unsigned int mcast_mtu;
 
 	struct ipoib_rx_buf *rx_ring;
 
-	spinlock_t           tx_lock;
+	spinlock_t	     tx_lock;
 	struct ipoib_tx_buf *tx_ring;
-	unsigned             tx_head;
-	unsigned             tx_tail;
-	struct ib_sge        tx_sge;
+	unsigned	     tx_head;
+	unsigned	     tx_tail;
+	struct ib_sge	     tx_sge;
 	struct ib_send_wr    tx_wr;
-	unsigned             tx_outstanding;
+	unsigned	     tx_outstanding;
 
 	struct ib_wc ibwc[IPOIB_NUM_WC];
 
@@ -317,10 +323,10 @@ struct ipoib_dev_priv {
 
 struct ipoib_ah {
 	struct net_device *dev;
-	struct ib_ah      *ah;
+	struct ib_ah	  *ah;
 	struct list_head   list;
-	struct kref        ref;
-	unsigned           last_send;
+	struct kref	   ref;
+	unsigned	   last_send;
 };
 
 struct ipoib_path {
@@ -331,11 +337,11 @@ struct ipoib_path {
 
 	struct list_head      neigh_list;
 
-	int                   query_id;
+	int		      query_id;
 	struct ib_sa_query   *query;
 	struct completion     done;
 
-	struct rb_node        rb_node;
+	struct rb_node	      rb_node;
 	struct list_head      list;
 };
 
@@ -344,7 +350,7 @@ struct ipoib_neigh {
 #ifdef CONFIG_INFINIBAND_IPOIB_CM
 	struct ipoib_cm_tx *cm;
 #endif
-	union ib_gid        dgid;
+	union ib_gid	    dgid;
 	struct sk_buff_head queue;
 
 	struct neighbour   *neighbour;
@@ -455,12 +461,14 @@ void ipoib_drain_cq(struct net_device *dev);
 
 #ifdef CONFIG_INFINIBAND_IPOIB_CM
 
-#define IPOIB_FLAGS_RC          0x80
-#define IPOIB_FLAGS_UC          0x40
+#define IPOIB_FLAGS_RC		0x80
+#define IPOIB_FLAGS_UC		0x40
 
 /* We don't support UC connections at the moment */
 #define IPOIB_CM_SUPPORTED(ha)   (ha[0] & (IPOIB_FLAGS_RC))
 
+extern int ipoib_max_conn_qp;
+
 static inline int ipoib_cm_admin_enabled(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -491,6 +499,18 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t
 	neigh->cm = tx;
 }
 
+static inline int ipoib_cm_has_srq(struct net_device *dev)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	return !!priv->cm.srq;
+}
+
+static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	return priv->cm.max_cm_mtu;
+}
+
 void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx);
 int ipoib_cm_dev_open(struct net_device *dev);
 void ipoib_cm_dev_stop(struct net_device *dev);
@@ -500,7 +520,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev);
 struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path,
 				    struct ipoib_neigh *neigh);
 void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx);
-void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
+void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
 			   unsigned int mtu);
 void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc);
 void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc);
@@ -508,6 +528,8 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc);
 
 struct ipoib_cm_tx;
 
+#define ipoib_max_conn_qp 0
+
 static inline int ipoib_cm_admin_enabled(struct net_device *dev)
 {
 	return 0;
@@ -533,6 +555,16 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t
 {
 }
 
+static inline int ipoib_cm_has_srq(struct net_device *dev)
+{
+	return 0;
+}
+
+static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev)
+{
+	return 0;
+}
+
 static inline
 void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx)
 {
@@ -582,7 +614,7 @@ int ipoib_cm_add_mode_attr(struct net_device *dev)
 	return 0;
 }
 
-static inline void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
+static inline void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
 					 unsigned int mtu)
 {
 	dev_kfree_skb_any(skb);
@@ -624,12 +656,12 @@ extern struct ib_sa_client ipoib_sa_client;
 extern int ipoib_debug_level;
 
 #define ipoib_dbg(priv, format, arg...)			\
-	do {					        \
+	do {						\
 		if (ipoib_debug_level > 0)			\
 			ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
 	} while (0)
 #define ipoib_dbg_mcast(priv, format, arg...)		\
-	do {					        \
+	do {						\
 		if (mcast_debug_level > 0)		\
 			ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
 	} while (0)
@@ -642,7 +674,7 @@ extern int ipoib_debug_level;
 
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
 #define ipoib_dbg_data(priv, format, arg...)		\
-	do {					        \
+	do {						\
 		if (data_debug_level > 0)		\
 			ipoib_printk(KERN_DEBUG, priv, format , ## arg); \
 	} while (0)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 059cf92b60a5..1818f958c250 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -39,6 +39,15 @@
 #include <linux/icmpv6.h>
 #include <linux/delay.h>
 
+#include "ipoib.h"
+
+int ipoib_max_conn_qp = 128;
+
+module_param_named(max_nonsrq_conn_qp, ipoib_max_conn_qp, int, 0444);
+MODULE_PARM_DESC(max_nonsrq_conn_qp,
+		 "Max number of connected-mode QPs per interface "
+		 "(applied only if shared receive queue is not available)");
+
 #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA
 static int data_debug_level;
 
@@ -47,8 +56,6 @@ MODULE_PARM_DESC(cm_data_debug_level,
 		 "Enable data path debug tracing for connected mode if > 0");
 #endif
 
-#include "ipoib.h"
-
 #define IPOIB_CM_IETF_ID 0x1000000000000000ULL
 
 #define IPOIB_CM_RX_UPDATE_TIME (256 * HZ)
@@ -81,7 +88,7 @@ static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, int frags,
 		ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE);
 }
 
-static int ipoib_cm_post_receive(struct net_device *dev, int id)
+static int ipoib_cm_post_receive_srq(struct net_device *dev, int id)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ib_recv_wr *bad_wr;
@@ -89,13 +96,13 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
 
 	priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV;
 
-	for (i = 0; i < IPOIB_CM_RX_SG; ++i)
+	for (i = 0; i < priv->cm.num_frags; ++i)
 		priv->cm.rx_sge[i].addr = priv->cm.srq_ring[id].mapping[i];
 
 	ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr);
 	if (unlikely(ret)) {
 		ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret);
-		ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+		ipoib_cm_dma_unmap_rx(priv, priv->cm.num_frags - 1,
 				      priv->cm.srq_ring[id].mapping);
 		dev_kfree_skb_any(priv->cm.srq_ring[id].skb);
 		priv->cm.srq_ring[id].skb = NULL;
@@ -104,7 +111,33 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
 	return ret;
 }
 
-static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int frags,
+static int ipoib_cm_post_receive_nonsrq(struct net_device *dev,
+					struct ipoib_cm_rx *rx, int id)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	struct ib_recv_wr *bad_wr;
+	int i, ret;
+
+	priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV;
+
+	for (i = 0; i < IPOIB_CM_RX_SG; ++i)
+		priv->cm.rx_sge[i].addr = rx->rx_ring[id].mapping[i];
+
+	ret = ib_post_recv(rx->qp, &priv->cm.rx_wr, &bad_wr);
+	if (unlikely(ret)) {
+		ipoib_warn(priv, "post recv failed for buf %d (%d)\n", id, ret);
+		ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+				      rx->rx_ring[id].mapping);
+		dev_kfree_skb_any(rx->rx_ring[id].skb);
+		rx->rx_ring[id].skb = NULL;
+	}
+
+	return ret;
+}
+
+static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev,
+					     struct ipoib_cm_rx_buf *rx_ring,
+					     int id, int frags,
 					     u64 mapping[IPOIB_CM_RX_SG])
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -141,7 +174,7 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int
 			goto partial_error;
 	}
 
-	priv->cm.srq_ring[id].skb = skb;
+	rx_ring[id].skb = skb;
 	return skb;
 
 partial_error:
@@ -155,7 +188,23 @@ partial_error:
 	return NULL;
 }
 
-static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv* priv)
+static void ipoib_cm_free_rx_ring(struct net_device *dev,
+				  struct ipoib_cm_rx_buf *rx_ring)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	int i;
+
+	for (i = 0; i < ipoib_recvq_size; ++i)
+		if (rx_ring[i].skb) {
+			ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
+					      rx_ring[i].mapping);
+			dev_kfree_skb_any(rx_ring[i].skb);
+		}
+
+	kfree(rx_ring);
+}
+
+static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv *priv)
 {
 	struct ib_send_wr *bad_wr;
 	struct ipoib_cm_rx *p;
@@ -208,12 +257,18 @@ static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev,
 		.qp_type = IB_QPT_RC,
 		.qp_context = p,
 	};
+
+	if (!ipoib_cm_has_srq(dev)) {
+		attr.cap.max_recv_wr  = ipoib_recvq_size;
+		attr.cap.max_recv_sge = IPOIB_CM_RX_SG;
+	}
+
 	return ib_create_qp(priv->pd, &attr);
 }
 
 static int ipoib_cm_modify_rx_qp(struct net_device *dev,
-				  struct ib_cm_id *cm_id, struct ib_qp *qp,
-				  unsigned psn)
+				 struct ib_cm_id *cm_id, struct ib_qp *qp,
+				 unsigned psn)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ib_qp_attr qp_attr;
@@ -266,6 +321,60 @@ static int ipoib_cm_modify_rx_qp(struct net_device *dev,
 	return 0;
 }
 
+static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_id,
+				   struct ipoib_cm_rx *rx)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	int ret;
+	int i;
+
+	rx->rx_ring = kcalloc(ipoib_recvq_size, sizeof *rx->rx_ring, GFP_KERNEL);
+	if (!rx->rx_ring)
+		return -ENOMEM;
+
+	spin_lock_irq(&priv->lock);
+
+	if (priv->cm.nonsrq_conn_qp >= ipoib_max_conn_qp) {
+		spin_unlock_irq(&priv->lock);
+		ib_send_cm_rej(cm_id, IB_CM_REJ_NO_QP, NULL, 0, NULL, 0);
+		ret = -EINVAL;
+		goto err_free;
+	} else
+		++priv->cm.nonsrq_conn_qp;
+
+	spin_unlock_irq(&priv->lock);
+
+	for (i = 0; i < ipoib_recvq_size; ++i) {
+		if (!ipoib_cm_alloc_rx_skb(dev, rx->rx_ring, i, IPOIB_CM_RX_SG - 1,
+					   rx->rx_ring[i].mapping)) {
+			ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
+				ret = -ENOMEM;
+				goto err_count;
+			}
+		ret = ipoib_cm_post_receive_nonsrq(dev, rx, i);
+		if (ret) {
+			ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq "
+				   "failed for buf %d\n", i);
+			ret = -EIO;
+			goto err_count;
+		}
+	}
+
+	rx->recv_count = ipoib_recvq_size;
+
+	return 0;
+
+err_count:
+	spin_lock_irq(&priv->lock);
+	--priv->cm.nonsrq_conn_qp;
+	spin_unlock_irq(&priv->lock);
+
+err_free:
+	ipoib_cm_free_rx_ring(dev, rx->rx_ring);
+
+	return ret;
+}
+
 static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id,
 			     struct ib_qp *qp, struct ib_cm_req_event_param *req,
 			     unsigned psn)
@@ -281,7 +390,7 @@ static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id,
 	rep.private_data_len = sizeof data;
 	rep.flow_control = 0;
 	rep.rnr_retry_count = req->rnr_retry_count;
-	rep.srq = 1;
+	rep.srq = ipoib_cm_has_srq(dev);
 	rep.qp_num = qp->qp_num;
 	rep.starting_psn = psn;
 	return ib_send_cm_rep(cm_id, &rep);
@@ -317,6 +426,12 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even
 	if (ret)
 		goto err_modify;
 
+	if (!ipoib_cm_has_srq(dev)) {
+		ret = ipoib_cm_nonsrq_init_rx(dev, cm_id, p);
+		if (ret)
+			goto err_modify;
+	}
+
 	spin_lock_irq(&priv->lock);
 	queue_delayed_work(ipoib_workqueue,
 			   &priv->cm.stale_task, IPOIB_CM_RX_DELAY);
@@ -401,12 +516,14 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
 void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	struct ipoib_cm_rx_buf *rx_ring;
 	unsigned int wr_id = wc->wr_id & ~(IPOIB_OP_CM | IPOIB_OP_RECV);
 	struct sk_buff *skb, *newskb;
 	struct ipoib_cm_rx *p;
 	unsigned long flags;
 	u64 mapping[IPOIB_CM_RX_SG];
 	int frags;
+	int has_srq;
 
 	ipoib_dbg_data(priv, "cm recv completion: id %d, status: %d\n",
 		       wr_id, wc->status);
@@ -424,18 +541,32 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 		return;
 	}
 
-	skb  = priv->cm.srq_ring[wr_id].skb;
+	p = wc->qp->qp_context;
+
+	has_srq = ipoib_cm_has_srq(dev);
+	rx_ring = has_srq ? priv->cm.srq_ring : p->rx_ring;
+
+	skb = rx_ring[wr_id].skb;
 
 	if (unlikely(wc->status != IB_WC_SUCCESS)) {
 		ipoib_dbg(priv, "cm recv error "
 			   "(status=%d, wrid=%d vend_err %x)\n",
 			   wc->status, wr_id, wc->vendor_err);
 		++dev->stats.rx_dropped;
-		goto repost;
+		if (has_srq)
+			goto repost;
+		else {
+			if (!--p->recv_count) {
+				spin_lock_irqsave(&priv->lock, flags);
+				list_move(&p->list, &priv->cm.rx_reap_list);
+				spin_unlock_irqrestore(&priv->lock, flags);
+				queue_work(ipoib_workqueue, &priv->cm.rx_reap_task);
+			}
+			return;
+		}
 	}
 
 	if (unlikely(!(wr_id & IPOIB_CM_RX_UPDATE_MASK))) {
-		p = wc->qp->qp_context;
 		if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
 			spin_lock_irqsave(&priv->lock, flags);
 			p->jiffies = jiffies;
@@ -450,7 +581,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 	frags = PAGE_ALIGN(wc->byte_len - min(wc->byte_len,
 					      (unsigned)IPOIB_CM_HEAD_SIZE)) / PAGE_SIZE;
 
-	newskb = ipoib_cm_alloc_rx_skb(dev, wr_id, frags, mapping);
+	newskb = ipoib_cm_alloc_rx_skb(dev, rx_ring, wr_id, frags, mapping);
 	if (unlikely(!newskb)) {
 		/*
 		 * If we can't allocate a new RX buffer, dump
@@ -461,8 +592,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 		goto repost;
 	}
 
-	ipoib_cm_dma_unmap_rx(priv, frags, priv->cm.srq_ring[wr_id].mapping);
-	memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
+	ipoib_cm_dma_unmap_rx(priv, frags, rx_ring[wr_id].mapping);
+	memcpy(rx_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping);
 
 	ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
 		       wc->byte_len, wc->slid);
@@ -483,9 +614,17 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
 	netif_receive_skb(skb);
 
 repost:
-	if (unlikely(ipoib_cm_post_receive(dev, wr_id)))
-		ipoib_warn(priv, "ipoib_cm_post_receive failed "
-			   "for buf %d\n", wr_id);
+	if (has_srq) {
+		if (unlikely(ipoib_cm_post_receive_srq(dev, wr_id)))
+			ipoib_warn(priv, "ipoib_cm_post_receive_srq failed "
+				   "for buf %d\n", wr_id);
+	} else {
+		if (unlikely(ipoib_cm_post_receive_nonsrq(dev, p, wr_id))) {
+			--p->recv_count;
+			ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq failed "
+				   "for buf %d\n", wr_id);
+		}
+	}
 }
 
 static inline int post_send(struct ipoib_dev_priv *priv,
@@ -495,10 +634,10 @@ static inline int post_send(struct ipoib_dev_priv *priv,
 {
 	struct ib_send_wr *bad_wr;
 
-	priv->tx_sge.addr             = addr;
-	priv->tx_sge.length           = len;
+	priv->tx_sge.addr	= addr;
+	priv->tx_sge.length	= len;
 
-	priv->tx_wr.wr_id 	      = wr_id | IPOIB_OP_CM;
+	priv->tx_wr.wr_id	= wr_id | IPOIB_OP_CM;
 
 	return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr);
 }
@@ -540,7 +679,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
 	tx_req->mapping = addr;
 
 	if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
-			        addr, skb->len))) {
+			       addr, skb->len))) {
 		ipoib_warn(priv, "post_send failed\n");
 		++dev->stats.tx_errors;
 		ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
@@ -657,10 +796,33 @@ err_cm:
 	return ret;
 }
 
+static void ipoib_cm_free_rx_reap_list(struct net_device *dev)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	struct ipoib_cm_rx *rx, *n;
+	LIST_HEAD(list);
+
+	spin_lock_irq(&priv->lock);
+	list_splice_init(&priv->cm.rx_reap_list, &list);
+	spin_unlock_irq(&priv->lock);
+
+	list_for_each_entry_safe(rx, n, &list, list) {
+		ib_destroy_cm_id(rx->id);
+		ib_destroy_qp(rx->qp);
+		if (!ipoib_cm_has_srq(dev)) {
+			ipoib_cm_free_rx_ring(priv->dev, rx->rx_ring);
+			spin_lock_irq(&priv->lock);
+			--priv->cm.nonsrq_conn_qp;
+			spin_unlock_irq(&priv->lock);
+		}
+		kfree(rx);
+	}
+}
+
 void ipoib_cm_dev_stop(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	struct ipoib_cm_rx *p, *n;
+	struct ipoib_cm_rx *p;
 	unsigned long begin;
 	LIST_HEAD(list);
 	int ret;
@@ -706,15 +868,9 @@ void ipoib_cm_dev_stop(struct net_device *dev)
 		spin_lock_irq(&priv->lock);
 	}
 
-	list_splice_init(&priv->cm.rx_reap_list, &list);
-
 	spin_unlock_irq(&priv->lock);
 
-	list_for_each_entry_safe(p, n, &list, list) {
-		ib_destroy_cm_id(p->id);
-		ib_destroy_qp(p->qp);
-		kfree(p);
-	}
+	ipoib_cm_free_rx_reap_list(dev);
 
 	cancel_delayed_work(&priv->cm.stale_task);
 }
@@ -799,7 +955,7 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_
 		.sq_sig_type		= IB_SIGNAL_ALL_WR,
 		.qp_type		= IB_QPT_RC,
 		.qp_context		= tx
-        };
+	};
 
 	return ib_create_qp(priv->pd, &attr);
 }
@@ -816,28 +972,28 @@ static int ipoib_cm_send_req(struct net_device *dev,
 	data.qpn = cpu_to_be32(priv->qp->qp_num);
 	data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE);
 
-	req.primary_path 	      = pathrec;
-	req.alternate_path 	      = NULL;
-	req.service_id                = cpu_to_be64(IPOIB_CM_IETF_ID | qpn);
-	req.qp_num 		      = qp->qp_num;
-	req.qp_type 		      = qp->qp_type;
-	req.private_data 	      = &data;
-	req.private_data_len 	      = sizeof data;
-	req.flow_control 	      = 0;
+	req.primary_path		= pathrec;
+	req.alternate_path		= NULL;
+	req.service_id			= cpu_to_be64(IPOIB_CM_IETF_ID | qpn);
+	req.qp_num			= qp->qp_num;
+	req.qp_type			= qp->qp_type;
+	req.private_data		= &data;
+	req.private_data_len		= sizeof data;
+	req.flow_control		= 0;
 
-	req.starting_psn              = 0; /* FIXME */
+	req.starting_psn		= 0; /* FIXME */
 
 	/*
 	 * Pick some arbitrary defaults here; we could make these
 	 * module parameters if anyone cared about setting them.
 	 */
-	req.responder_resources	      = 4;
-	req.remote_cm_response_timeout = 20;
-	req.local_cm_response_timeout  = 20;
-	req.retry_count 	      = 0; /* RFC draft warns against retries */
-	req.rnr_retry_count 	      = 0; /* RFC draft warns against retries */
-	req.max_cm_retries 	      = 15;
-	req.srq 	              = 1;
+	req.responder_resources		= 4;
+	req.remote_cm_response_timeout	= 20;
+	req.local_cm_response_timeout	= 20;
+	req.retry_count			= 0; /* RFC draft warns against retries */
+	req.rnr_retry_count		= 0; /* RFC draft warns against retries */
+	req.max_cm_retries		= 15;
+	req.srq				= ipoib_cm_has_srq(dev);
 	return ib_send_cm_req(id, &req);
 }
 
@@ -1150,7 +1306,7 @@ static void ipoib_cm_skb_reap(struct work_struct *work)
 	spin_unlock_irq(&priv->tx_lock);
 }
 
-void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
+void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
 			   unsigned int mtu)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -1166,20 +1322,8 @@ void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
 
 static void ipoib_cm_rx_reap(struct work_struct *work)
 {
-	struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
-						   cm.rx_reap_task);
-	struct ipoib_cm_rx *p, *n;
-	LIST_HEAD(list);
-
-	spin_lock_irq(&priv->lock);
-	list_splice_init(&priv->cm.rx_reap_list, &list);
-	spin_unlock_irq(&priv->lock);
-
-	list_for_each_entry_safe(p, n, &list, list) {
-		ib_destroy_cm_id(p->id);
-		ib_destroy_qp(p->qp);
-		kfree(p);
-	}
+	ipoib_cm_free_rx_reap_list(container_of(work, struct ipoib_dev_priv,
+						cm.rx_reap_task)->dev);
 }
 
 static void ipoib_cm_stale_task(struct work_struct *work)
@@ -1212,7 +1356,7 @@ static void ipoib_cm_stale_task(struct work_struct *work)
 }
 
 
-static ssize_t show_mode(struct device *d, struct device_attribute *attr, 
+static ssize_t show_mode(struct device *d, struct device_attribute *attr,
 			 char *buf)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(d));
@@ -1255,16 +1399,40 @@ int ipoib_cm_add_mode_attr(struct net_device *dev)
 	return device_create_file(&dev->dev, &dev_attr_mode);
 }
 
-int ipoib_cm_dev_init(struct net_device *dev)
+static void ipoib_cm_create_srq(struct net_device *dev, int max_sge)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct ib_srq_init_attr srq_init_attr = {
 		.attr = {
 			.max_wr  = ipoib_recvq_size,
-			.max_sge = IPOIB_CM_RX_SG
+			.max_sge = max_sge
 		}
 	};
-	int ret, i;
+
+	priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr);
+	if (IS_ERR(priv->cm.srq)) {
+		if (PTR_ERR(priv->cm.srq) != -ENOSYS)
+			printk(KERN_WARNING "%s: failed to allocate SRQ, error %ld\n",
+			       priv->ca->name, PTR_ERR(priv->cm.srq));
+		priv->cm.srq = NULL;
+		return;
+	}
+
+	priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring,
+				    GFP_KERNEL);
+	if (!priv->cm.srq_ring) {
+		printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n",
+		       priv->ca->name, ipoib_recvq_size);
+		ib_destroy_srq(priv->cm.srq);
+		priv->cm.srq = NULL;
+	}
+}
+
+int ipoib_cm_dev_init(struct net_device *dev)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+	int i, ret;
+	struct ib_device_attr attr;
 
 	INIT_LIST_HEAD(&priv->cm.passive_ids);
 	INIT_LIST_HEAD(&priv->cm.reap_list);
@@ -1281,43 +1449,53 @@ int ipoib_cm_dev_init(struct net_device *dev)
 
 	skb_queue_head_init(&priv->cm.skb_queue);
 
-	priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr);
-	if (IS_ERR(priv->cm.srq)) {
-		ret = PTR_ERR(priv->cm.srq);
-		priv->cm.srq = NULL;
+	ret = ib_query_device(priv->ca, &attr);
+	if (ret) {
+		printk(KERN_WARNING "ib_query_device() failed with %d\n", ret);
 		return ret;
 	}
 
-	priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring,
-				    GFP_KERNEL);
-	if (!priv->cm.srq_ring) {
-		printk(KERN_WARNING "%s: failed to allocate CM ring (%d entries)\n",
-		       priv->ca->name, ipoib_recvq_size);
-		ipoib_cm_dev_cleanup(dev);
-		return -ENOMEM;
+	ipoib_dbg(priv, "max_srq_sge=%d\n", attr.max_srq_sge);
+
+	attr.max_srq_sge = min_t(int, IPOIB_CM_RX_SG, attr.max_srq_sge);
+	ipoib_cm_create_srq(dev, attr.max_srq_sge);
+	if (ipoib_cm_has_srq(dev)) {
+		priv->cm.max_cm_mtu = attr.max_srq_sge * PAGE_SIZE - 0x10;
+		priv->cm.num_frags  = attr.max_srq_sge;
+		ipoib_dbg(priv, "max_cm_mtu = 0x%x, num_frags=%d\n",
+			  priv->cm.max_cm_mtu, priv->cm.num_frags);
+	} else {
+		priv->cm.max_cm_mtu = IPOIB_CM_MTU;
+		priv->cm.num_frags  = IPOIB_CM_RX_SG;
 	}
 
-	for (i = 0; i < IPOIB_CM_RX_SG; ++i)
+	for (i = 0; i < priv->cm.num_frags; ++i)
 		priv->cm.rx_sge[i].lkey	= priv->mr->lkey;
 
 	priv->cm.rx_sge[0].length = IPOIB_CM_HEAD_SIZE;
-	for (i = 1; i < IPOIB_CM_RX_SG; ++i)
+	for (i = 1; i < priv->cm.num_frags; ++i)
 		priv->cm.rx_sge[i].length = PAGE_SIZE;
 	priv->cm.rx_wr.next = NULL;
 	priv->cm.rx_wr.sg_list = priv->cm.rx_sge;
-	priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG;
+	priv->cm.rx_wr.num_sge = priv->cm.num_frags;
+
+	if (ipoib_cm_has_srq(dev)) {
+		for (i = 0; i < ipoib_recvq_size; ++i) {
+			if (!ipoib_cm_alloc_rx_skb(dev, priv->cm.srq_ring, i,
+						   priv->cm.num_frags - 1,
+						   priv->cm.srq_ring[i].mapping)) {
+				ipoib_warn(priv, "failed to allocate "
+					   "receive buffer %d\n", i);
+				ipoib_cm_dev_cleanup(dev);
+				return -ENOMEM;
+			}
 
-	for (i = 0; i < ipoib_recvq_size; ++i) {
-		if (!ipoib_cm_alloc_rx_skb(dev, i, IPOIB_CM_RX_SG - 1,
-					   priv->cm.srq_ring[i].mapping)) {
-			ipoib_warn(priv, "failed to allocate receive buffer %d\n", i);
-			ipoib_cm_dev_cleanup(dev);
-			return -ENOMEM;
-		}
-		if (ipoib_cm_post_receive(dev, i)) {
-			ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i);
-			ipoib_cm_dev_cleanup(dev);
-			return -EIO;
+			if (ipoib_cm_post_receive_srq(dev, i)) {
+				ipoib_warn(priv, "ipoib_cm_post_receive_srq "
+					   "failed for buf %d\n", i);
+				ipoib_cm_dev_cleanup(dev);
+				return -EIO;
+			}
 		}
 	}
 
@@ -1328,7 +1506,7 @@ int ipoib_cm_dev_init(struct net_device *dev)
 void ipoib_cm_dev_cleanup(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	int i, ret;
+	int ret;
 
 	if (!priv->cm.srq)
 		return;
@@ -1342,13 +1520,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev)
 	priv->cm.srq = NULL;
 	if (!priv->cm.srq_ring)
 		return;
-	for (i = 0; i < ipoib_recvq_size; ++i)
-		if (priv->cm.srq_ring[i].skb) {
-			ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1,
-					      priv->cm.srq_ring[i].mapping);
-			dev_kfree_skb_any(priv->cm.srq_ring[i].skb);
-			priv->cm.srq_ring[i].skb = NULL;
-		}
-	kfree(priv->cm.srq_ring);
+
+	ipoib_cm_free_rx_ring(dev, priv->cm.srq_ring);
 	priv->cm.srq_ring = NULL;
 }
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
index 44c174182a82..8b882bbd1d05 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
@@ -124,7 +124,7 @@ static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr)
 	return 0;
 }
 
-static struct seq_operations ipoib_mcg_seq_ops = {
+static const struct seq_operations ipoib_mcg_seq_ops = {
 	.start = ipoib_mcg_seq_start,
 	.next  = ipoib_mcg_seq_next,
 	.stop  = ipoib_mcg_seq_stop,
@@ -230,7 +230,7 @@ static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr)
 	return 0;
 }
 
-static struct seq_operations ipoib_path_seq_ops = {
+static const struct seq_operations ipoib_path_seq_ops = {
 	.start = ipoib_path_seq_start,
 	.next  = ipoib_path_seq_next,
 	.stop  = ipoib_path_seq_stop,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 5063dd509ad2..52bc2bd5799a 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -345,12 +345,12 @@ static inline int post_send(struct ipoib_dev_priv *priv,
 {
 	struct ib_send_wr *bad_wr;
 
-	priv->tx_sge.addr             = addr;
-	priv->tx_sge.length           = len;
+	priv->tx_sge.addr	      = addr;
+	priv->tx_sge.length	      = len;
 
-	priv->tx_wr.wr_id 	      = wr_id;
+	priv->tx_wr.wr_id	      = wr_id;
 	priv->tx_wr.wr.ud.remote_qpn  = qpn;
-	priv->tx_wr.wr.ud.ah 	      = address;
+	priv->tx_wr.wr.ud.ah	      = address;
 
 	return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr);
 }
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index c9f6077b615e..a082466f4a83 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -182,17 +182,20 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 
 	/* dev->mtu > 2K ==> connected mode */
-	if (ipoib_cm_admin_enabled(dev) && new_mtu <= IPOIB_CM_MTU) {
+	if (ipoib_cm_admin_enabled(dev)) {
+		if (new_mtu > ipoib_cm_max_mtu(dev))
+			return -EINVAL;
+
 		if (new_mtu > priv->mcast_mtu)
 			ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n",
 				   priv->mcast_mtu);
+
 		dev->mtu = new_mtu;
 		return 0;
 	}
 
-	if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) {
+	if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN)
 		return -EINVAL;
-	}
 
 	priv->admin_mtu = new_mtu;
 
@@ -474,8 +477,8 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid)
 	INIT_LIST_HEAD(&path->neigh_list);
 
 	memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid));
-	path->pathrec.sgid          = priv->local_gid;
-	path->pathrec.pkey          = cpu_to_be16(priv->pkey);
+	path->pathrec.sgid	    = priv->local_gid;
+	path->pathrec.pkey	    = cpu_to_be16(priv->pkey);
 	path->pathrec.numb_path     = 1;
 	path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class;
 
@@ -669,16 +672,6 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
 		return NETDEV_TX_LOCKED;
 
-	/*
-	 * Check if our queue is stopped.  Since we have the LLTX bit
-	 * set, we can't rely on netif_stop_queue() preventing our
-	 * xmit function from being called with a full queue.
-	 */
-	if (unlikely(netif_queue_stopped(dev))) {
-		spin_unlock_irqrestore(&priv->tx_lock, flags);
-		return NETDEV_TX_BUSY;
-	}
-
 	if (likely(skb->dst && skb->dst->neighbour)) {
 		if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
 			ipoib_path_lookup(skb, dev);
@@ -950,34 +943,34 @@ static void ipoib_setup(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
 
-	dev->open 		 = ipoib_open;
-	dev->stop 		 = ipoib_stop;
-	dev->change_mtu 	 = ipoib_change_mtu;
-	dev->hard_start_xmit 	 = ipoib_start_xmit;
-	dev->tx_timeout 	 = ipoib_timeout;
-	dev->header_ops 	 = &ipoib_header_ops;
-	dev->set_multicast_list  = ipoib_set_mcast_list;
-	dev->neigh_setup         = ipoib_neigh_setup_dev;
+	dev->open		 = ipoib_open;
+	dev->stop		 = ipoib_stop;
+	dev->change_mtu		 = ipoib_change_mtu;
+	dev->hard_start_xmit	 = ipoib_start_xmit;
+	dev->tx_timeout		 = ipoib_timeout;
+	dev->header_ops		 = &ipoib_header_ops;
+	dev->set_multicast_list	 = ipoib_set_mcast_list;
+	dev->neigh_setup	 = ipoib_neigh_setup_dev;
 
 	netif_napi_add(dev, &priv->napi, ipoib_poll, 100);
 
-	dev->watchdog_timeo 	 = HZ;
+	dev->watchdog_timeo	 = HZ;
 
-	dev->flags              |= IFF_BROADCAST | IFF_MULTICAST;
+	dev->flags		|= IFF_BROADCAST | IFF_MULTICAST;
 
 	/*
 	 * We add in INFINIBAND_ALEN to allow for the destination
 	 * address "pseudoheader" for skbs without neighbour struct.
 	 */
-	dev->hard_header_len 	 = IPOIB_ENCAP_LEN + INFINIBAND_ALEN;
-	dev->addr_len 		 = INFINIBAND_ALEN;
-	dev->type 		 = ARPHRD_INFINIBAND;
-	dev->tx_queue_len 	 = ipoib_sendq_size * 2;
-	dev->features            = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX;
+	dev->hard_header_len	 = IPOIB_ENCAP_LEN + INFINIBAND_ALEN;
+	dev->addr_len		 = INFINIBAND_ALEN;
+	dev->type		 = ARPHRD_INFINIBAND;
+	dev->tx_queue_len	 = ipoib_sendq_size * 2;
+	dev->features		 = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX;
 
 	/* MTU will be reset when mcast join happens */
-	dev->mtu 		 = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN;
-	priv->mcast_mtu 	 = priv->admin_mtu = dev->mtu;
+	dev->mtu		 = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN;
+	priv->mcast_mtu		 = priv->admin_mtu = dev->mtu;
 
 	memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN);
 
@@ -1268,6 +1261,9 @@ static int __init ipoib_init_module(void)
 	ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size);
 	ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE);
 	ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE);
+#ifdef CONFIG_INFINIBAND_IPOIB_CM
+	ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP);
+#endif
 
 	ret = ipoib_register_debugfs();
 	if (ret)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 9bcfc7ad6aa6..2628339e3a99 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -702,7 +702,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
 
 out:
 	if (mcast && mcast->ah) {
-		if (skb->dst            &&
+		if (skb->dst		&&
 		    skb->dst->neighbour &&
 		    !*to_ipoib_neigh(skb->dst->neighbour)) {
 			struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour,
@@ -710,7 +710,7 @@ out:
 
 			if (neigh) {
 				kref_get(&mcast->ah->ref);
-				neigh->ah  	= mcast->ah;
+				neigh->ah	= mcast->ah;
 				list_add_tail(&neigh->list, &mcast->neigh_list);
 			}
 		}
@@ -788,10 +788,6 @@ void ipoib_mcast_restart_task(struct work_struct *work)
 
 		memcpy(mgid.raw, mclist->dmi_addr + 4, sizeof mgid);
 
-		/* Add in the P_Key */
-		mgid.raw[4] = (priv->pkey >> 8) & 0xff;
-		mgid.raw[5] = priv->pkey & 0xff;
-
 		mcast = __ipoib_mcast_find(dev, &mgid);
 		if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
 			struct ipoib_mcast *nmcast;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 3c6e45db0ab5..433e99ac227b 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -172,8 +172,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
 
 	size = ipoib_sendq_size + ipoib_recvq_size + 1;
 	ret = ipoib_cm_dev_init(dev);
-	if (!ret)
-		size += ipoib_recvq_size + 1 /* 1 extra for rx_drain_qp */;
+	if (!ret) {
+		if (ipoib_cm_has_srq(dev))
+			size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */
+		else
+			size += ipoib_recvq_size * ipoib_max_conn_qp;
+	}
 
 	priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
 	if (IS_ERR(priv->cq)) {
@@ -197,12 +201,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
 	priv->dev->dev_addr[2] = (priv->qp->qp_num >>  8) & 0xff;
 	priv->dev->dev_addr[3] = (priv->qp->qp_num      ) & 0xff;
 
-	priv->tx_sge.lkey 	= priv->mr->lkey;
+	priv->tx_sge.lkey	= priv->mr->lkey;
 
-	priv->tx_wr.opcode 	= IB_WR_SEND;
-	priv->tx_wr.sg_list 	= &priv->tx_sge;
-	priv->tx_wr.num_sge 	= 1;
-	priv->tx_wr.send_flags 	= IB_SEND_SIGNALED;
+	priv->tx_wr.opcode	= IB_WR_SEND;
+	priv->tx_wr.sg_list	= &priv->tx_sge;
+	priv->tx_wr.num_sge	= 1;
+	priv->tx_wr.send_flags	= IB_SEND_SIGNALED;
 
 	return 0;
 
diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig
index fe604c8d2996..77dedba829e6 100644
--- a/drivers/infiniband/ulp/iser/Kconfig
+++ b/drivers/infiniband/ulp/iser/Kconfig
@@ -8,5 +8,5 @@ config INFINIBAND_ISER
           that speak iSCSI over iSER over InfiniBand.
 
 	  The iSER protocol is defined by IETF.
-	  See <http://www.ietf.org/internet-drafts/draft-ietf-ips-iser-05.txt>
-	  and <http://www.infinibandta.org/members/spec/iser_annex_060418.pdf>
+	  See <http://www.ietf.org/rfc/rfc5046.txt>
+	  and <http://www.infinibandta.org/members/spec/Annex_iSER.PDF>
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index bad8dacafd10..be1b9fbd416d 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -129,7 +129,7 @@ error:
  * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
  *
  **/
-static void
+static int
 iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
 {
 	struct iscsi_iser_conn     *iser_conn  = ctask->conn->dd_data;
@@ -138,6 +138,7 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
 	iser_ctask->command_sent = 0;
 	iser_ctask->iser_conn    = iser_conn;
 	iser_ctask_rdma_init(iser_ctask);
+	return 0;
 }
 
 /**
@@ -220,12 +221,6 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
 	debug_scsi("ctask deq [cid %d itt 0x%x]\n",
 		   conn->id, ctask->itt);
 
-	/*
-	 * serialize with TMF AbortTask
-	 */
-	if (ctask->mtask)
-		return error;
-
 	/* Send the cmd PDU */
 	if (!iser_ctask->command_sent) {
 		error = iser_send_command(conn, ctask);
@@ -406,6 +401,7 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit,
 		ctask      = session->cmds[i];
 		iser_ctask = ctask->dd_data;
 		ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header;
+		ctask->hdr_max = sizeof(iser_ctask->desc.iscsi_header);
 	}
 
 	for (i = 0; i < session->mgmtpool_max; i++) {
@@ -551,11 +547,13 @@ static struct scsi_host_template iscsi_iser_sht = {
 	.module                 = THIS_MODULE,
 	.name                   = "iSCSI Initiator over iSER, v." DRV_VER,
 	.queuecommand           = iscsi_queuecommand,
+	.change_queue_depth	= iscsi_change_queue_depth,
 	.can_queue		= ISCSI_DEF_XMIT_CMDS_MAX - 1,
 	.sg_tablesize           = ISCSI_ISER_SG_TABLESIZE,
 	.max_sectors		= 1024,
 	.cmd_per_lun            = ISCSI_MAX_CMD_PER_LUN,
 	.eh_abort_handler       = iscsi_eh_abort,
+	.eh_device_reset_handler= iscsi_eh_device_reset,
 	.eh_host_reset_handler	= iscsi_eh_host_reset,
 	.use_clustering         = DISABLE_CLUSTERING,
 	.proc_name              = "iscsi_iser",
@@ -582,7 +580,9 @@ static struct iscsi_transport iscsi_iser_transport = {
 				  ISCSI_PERSISTENT_ADDRESS |
 				  ISCSI_TARGET_NAME | ISCSI_TPGT |
 				  ISCSI_USERNAME | ISCSI_PASSWORD |
-				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
+				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
+				  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
+				  ISCSI_PING_TMO | ISCSI_RECV_TMO,
 	.host_param_mask	= ISCSI_HOST_HWADDRESS |
 				  ISCSI_HOST_NETDEV_NAME |
 				  ISCSI_HOST_INITIATOR_NAME,
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index a6f2303ed14a..83247f1fdf72 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -561,7 +561,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
 	if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
 	        itt = get_itt(hdr->itt); /* mask out cid and age bits */
 		if (!(itt < session->cmds_max))
-			iser_err("itt can't be matched to task!!!"
+			iser_err("itt can't be matched to task!!! "
 				 "conn %p opcode %d cmds_max %d itt %d\n",
 				 conn->iscsi_conn,opcode,session->cmds_max,itt);
 		/* use the mapping given with the cmds array indexed by itt */
@@ -621,9 +621,7 @@ void iser_snd_completion(struct iser_desc *tx_desc)
 			struct iscsi_session *session = conn->session;
 
 			spin_lock(&conn->session->lock);
-			list_del(&mtask->running);
-			__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
-				    sizeof(void*));
+			iscsi_free_mgmt_task(conn, mtask);
 			spin_unlock(&session->lock);
 		}
 	}
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 654a4dce0236..714b8db02b29 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -105,7 +105,7 @@ pd_err:
 }
 
 /**
- * iser_free_device_ib_res - destory/dealloc/dereg the DMA MR,
+ * iser_free_device_ib_res - destroy/dealloc/dereg the DMA MR,
  * CQ and PD created with the device associated with the adapator.
  */
 static void iser_free_device_ib_res(struct iser_device *device)
@@ -475,13 +475,11 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve
 		iser_disconnected_handler(cma_id);
 		break;
 	case RDMA_CM_EVENT_DEVICE_REMOVAL:
+		iser_err("Device removal is currently unsupported\n");
 		BUG();
 		break;
-	case RDMA_CM_EVENT_CONNECT_RESPONSE:
-		BUG();
-		break;
-	case RDMA_CM_EVENT_CONNECT_REQUEST:
 	default:
+		iser_err("Unexpected RDMA CM event (%d)\n", event->event);
 		break;
 	}
 	return ret;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index bdb6f8517401..195ce7c12319 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -272,7 +272,8 @@ static void srp_path_rec_completion(int status,
 
 	target->status = status;
 	if (status)
-		printk(KERN_ERR PFX "Got failed path rec status %d\n", status);
+		shost_printk(KERN_ERR, target->scsi_host,
+			     PFX "Got failed path rec status %d\n", status);
 	else
 		target->path = *pathrec;
 	complete(&target->done);
@@ -303,7 +304,8 @@ static int srp_lookup_path(struct srp_target_port *target)
 	wait_for_completion(&target->done);
 
 	if (target->status < 0)
-		printk(KERN_WARNING PFX "Path record query failed\n");
+		shost_printk(KERN_WARNING, target->scsi_host,
+			     PFX "Path record query failed\n");
 
 	return target->status;
 }
@@ -379,9 +381,10 @@ static int srp_send_req(struct srp_target_port *target)
 	 * the second 8 bytes to the local node GUID.
 	 */
 	if (srp_target_is_topspin(target)) {
-		printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround "
-		       "activated for target GUID %016llx\n",
-		       (unsigned long long) be64_to_cpu(target->ioc_guid));
+		shost_printk(KERN_DEBUG, target->scsi_host,
+			     PFX "Topspin/Cisco initiator port ID workaround "
+			     "activated for target GUID %016llx\n",
+			     (unsigned long long) be64_to_cpu(target->ioc_guid));
 		memset(req->priv.initiator_port_id, 0, 8);
 		memcpy(req->priv.initiator_port_id + 8,
 		       &target->srp_host->dev->dev->node_guid, 8);
@@ -400,7 +403,8 @@ static void srp_disconnect_target(struct srp_target_port *target)
 
 	init_completion(&target->done);
 	if (ib_send_cm_dreq(target->cm_id, NULL, 0)) {
-		printk(KERN_DEBUG PFX "Sending CM DREQ failed\n");
+		shost_printk(KERN_DEBUG, target->scsi_host,
+			     PFX "Sending CM DREQ failed\n");
 		return;
 	}
 	wait_for_completion(&target->done);
@@ -568,7 +572,8 @@ static int srp_reconnect_target(struct srp_target_port *target)
 	return ret;
 
 err:
-	printk(KERN_ERR PFX "reconnect failed (%d), removing target port.\n", ret);
+	shost_printk(KERN_ERR, target->scsi_host,
+		     PFX "reconnect failed (%d), removing target port.\n", ret);
 
 	/*
 	 * We couldn't reconnect, so kill our target port off.
@@ -683,8 +688,9 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
 
 	if (scmnd->sc_data_direction != DMA_FROM_DEVICE &&
 	    scmnd->sc_data_direction != DMA_TO_DEVICE) {
-		printk(KERN_WARNING PFX "Unhandled data direction %d\n",
-		       scmnd->sc_data_direction);
+		shost_printk(KERN_WARNING, target->scsi_host,
+			     PFX "Unhandled data direction %d\n",
+			     scmnd->sc_data_direction);
 		return -EINVAL;
 	}
 
@@ -786,8 +792,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
 	} else {
 		scmnd = req->scmnd;
 		if (!scmnd)
-			printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n",
-			       (unsigned long long) rsp->tag);
+			shost_printk(KERN_ERR, target->scsi_host,
+				     "Null scmnd for RSP w/tag %016llx\n",
+				     (unsigned long long) rsp->tag);
 		scmnd->result = rsp->status;
 
 		if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
@@ -831,7 +838,8 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
 	if (0) {
 		int i;
 
-		printk(KERN_ERR PFX "recv completion, opcode 0x%02x\n", opcode);
+		shost_printk(KERN_ERR, target->scsi_host,
+			     PFX "recv completion, opcode 0x%02x\n", opcode);
 
 		for (i = 0; i < wc->byte_len; ++i) {
 			if (i % 8 == 0)
@@ -852,11 +860,13 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
 
 	case SRP_T_LOGOUT:
 		/* XXX Handle target logout */
-		printk(KERN_WARNING PFX "Got target logout request\n");
+		shost_printk(KERN_WARNING, target->scsi_host,
+			     PFX "Got target logout request\n");
 		break;
 
 	default:
-		printk(KERN_WARNING PFX "Unhandled SRP opcode 0x%02x\n", opcode);
+		shost_printk(KERN_WARNING, target->scsi_host,
+			     PFX "Unhandled SRP opcode 0x%02x\n", opcode);
 		break;
 	}
 
@@ -872,9 +882,10 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
 	ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
 	while (ib_poll_cq(cq, 1, &wc) > 0) {
 		if (wc.status) {
-			printk(KERN_ERR PFX "failed %s status %d\n",
-			       wc.wr_id & SRP_OP_RECV ? "receive" : "send",
-			       wc.status);
+			shost_printk(KERN_ERR, target->scsi_host,
+				     PFX "failed %s status %d\n",
+				     wc.wr_id & SRP_OP_RECV ? "receive" : "send",
+				     wc.status);
 			target->qp_in_error = 1;
 			break;
 		}
@@ -930,13 +941,18 @@ static int srp_post_recv(struct srp_target_port *target)
  * req_lim and tx_head.  Lock cannot be dropped between call here and
  * call to __srp_post_send().
  */
-static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target)
+static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
+					enum srp_request_type req_type)
 {
+	s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2;
+
 	if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE)
 		return NULL;
 
-	if (unlikely(target->req_lim < 1))
+	if (target->req_lim < min) {
 		++target->zero_req_lim;
+		return NULL;
+	}
 
 	return target->tx_ring[target->tx_head & SRP_SQ_SIZE];
 }
@@ -993,7 +1009,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
 		return 0;
 	}
 
-	iu = __srp_get_tx_iu(target);
+	iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL);
 	if (!iu)
 		goto err;
 
@@ -1022,12 +1038,13 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
 
 	len = srp_map_data(scmnd, target, req);
 	if (len < 0) {
-		printk(KERN_ERR PFX "Failed to map data\n");
+		shost_printk(KERN_ERR, target->scsi_host,
+			     PFX "Failed to map data\n");
 		goto err;
 	}
 
 	if (__srp_post_recv(target)) {
-		printk(KERN_ERR PFX "Recv failed\n");
+		shost_printk(KERN_ERR, target->scsi_host, PFX "Recv failed\n");
 		goto err_unmap;
 	}
 
@@ -1035,7 +1052,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd,
 				      DMA_TO_DEVICE);
 
 	if (__srp_post_send(target, iu, len)) {
-		printk(KERN_ERR PFX "Send failed\n");
+		shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
 		goto err_unmap;
 	}
 
@@ -1090,6 +1107,7 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
 			       struct ib_cm_event *event,
 			       struct srp_target_port *target)
 {
+	struct Scsi_Host *shost = target->scsi_host;
 	struct ib_class_port_info *cpi;
 	int opcode;
 
@@ -1115,19 +1133,22 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
 			memcpy(target->path.dgid.raw,
 			       event->param.rej_rcvd.ari, 16);
 
-			printk(KERN_DEBUG PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
-			       (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix),
-			       (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id));
+			shost_printk(KERN_DEBUG, shost,
+				     PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
+				     (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix),
+				     (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id));
 
 			target->status = SRP_PORT_REDIRECT;
 		} else {
-			printk(KERN_WARNING "  REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
+			shost_printk(KERN_WARNING, shost,
+				     "  REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
 			target->status = -ECONNRESET;
 		}
 		break;
 
 	case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:
-		printk(KERN_WARNING "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
+		shost_printk(KERN_WARNING, shost,
+			    "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
 		target->status = -ECONNRESET;
 		break;
 
@@ -1138,20 +1159,21 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
 			u32 reason = be32_to_cpu(rej->reason);
 
 			if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)
-				printk(KERN_WARNING PFX
-				       "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
+				shost_printk(KERN_WARNING, shost,
+					     PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
 			else
-				printk(KERN_WARNING PFX
-				       "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
+				shost_printk(KERN_WARNING, shost,
+					    PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
 		} else
-			printk(KERN_WARNING "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
-			       " opcode 0x%02x\n", opcode);
+			shost_printk(KERN_WARNING, shost,
+				     "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
+				     " opcode 0x%02x\n", opcode);
 		target->status = -ECONNRESET;
 		break;
 
 	default:
-		printk(KERN_WARNING "  REJ reason 0x%x\n",
-		       event->param.rej_rcvd.reason);
+		shost_printk(KERN_WARNING, shost, "  REJ reason 0x%x\n",
+			     event->param.rej_rcvd.reason);
 		target->status = -ECONNRESET;
 	}
 }
@@ -1166,7 +1188,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
 
 	switch (event->event) {
 	case IB_CM_REQ_ERROR:
-		printk(KERN_DEBUG PFX "Sending CM REQ failed\n");
+		shost_printk(KERN_DEBUG, target->scsi_host,
+			     PFX "Sending CM REQ failed\n");
 		comp = 1;
 		target->status = -ECONNRESET;
 		break;
@@ -1184,7 +1207,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
 			target->scsi_host->can_queue = min(target->req_lim,
 							   target->scsi_host->can_queue);
 		} else {
-			printk(KERN_WARNING PFX "Unhandled RSP opcode %#x\n", opcode);
+			shost_printk(KERN_WARNING, target->scsi_host,
+				    PFX "Unhandled RSP opcode %#x\n", opcode);
 			target->status = -ECONNRESET;
 			break;
 		}
@@ -1230,20 +1254,23 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
 		break;
 
 	case IB_CM_REJ_RECEIVED:
-		printk(KERN_DEBUG PFX "REJ received\n");
+		shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
 		comp = 1;
 
 		srp_cm_rej_handler(cm_id, event, target);
 		break;
 
 	case IB_CM_DREQ_RECEIVED:
-		printk(KERN_WARNING PFX "DREQ received - connection closed\n");
+		shost_printk(KERN_WARNING, target->scsi_host,
+			     PFX "DREQ received - connection closed\n");
 		if (ib_send_cm_drep(cm_id, NULL, 0))
-			printk(KERN_ERR PFX "Sending CM DREP failed\n");
+			shost_printk(KERN_ERR, target->scsi_host,
+				     PFX "Sending CM DREP failed\n");
 		break;
 
 	case IB_CM_TIMEWAIT_EXIT:
-		printk(KERN_ERR PFX "connection closed\n");
+		shost_printk(KERN_ERR, target->scsi_host,
+			     PFX "connection closed\n");
 
 		comp = 1;
 		target->status = 0;
@@ -1255,7 +1282,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
 		break;
 
 	default:
-		printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event);
+		shost_printk(KERN_WARNING, target->scsi_host,
+			     PFX "Unhandled CM event %d\n", event->event);
 		break;
 	}
 
@@ -1283,7 +1311,7 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
 
 	init_completion(&req->done);
 
-	iu = __srp_get_tx_iu(target);
+	iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT);
 	if (!iu)
 		goto out;
 
@@ -1332,7 +1360,7 @@ static int srp_abort(struct scsi_cmnd *scmnd)
 	struct srp_request *req;
 	int ret = SUCCESS;
 
-	printk(KERN_ERR "SRP abort called\n");
+	shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
 
 	if (target->qp_in_error)
 		return FAILED;
@@ -1362,7 +1390,7 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
 	struct srp_target_port *target = host_to_target(scmnd->device->host);
 	struct srp_request *req, *tmp;
 
-	printk(KERN_ERR "SRP reset_device called\n");
+	shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
 
 	if (target->qp_in_error)
 		return FAILED;
@@ -1389,7 +1417,7 @@ static int srp_reset_host(struct scsi_cmnd *scmnd)
 	struct srp_target_port *target = host_to_target(scmnd->device->host);
 	int ret = FAILED;
 
-	printk(KERN_ERR PFX "SRP reset_host called\n");
+	shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n");
 
 	if (!srp_reconnect_target(target))
 		ret = SUCCESS;
@@ -1814,8 +1842,9 @@ static ssize_t srp_create_target(struct class_device *class_dev,
 
 	ib_get_cached_gid(host->dev->dev, host->port, 0, &target->path.sgid);
 
-	printk(KERN_DEBUG PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
-	       "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+	shost_printk(KERN_DEBUG, target->scsi_host, PFX
+		     "new target: id_ext %016llx ioc_guid %016llx pkey %04x "
+		     "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
 	       (unsigned long long) be64_to_cpu(target->id_ext),
 	       (unsigned long long) be64_to_cpu(target->ioc_guid),
 	       be16_to_cpu(target->path.pkey),
@@ -1842,7 +1871,8 @@ static ssize_t srp_create_target(struct class_device *class_dev,
 	target->qp_in_error = 0;
 	ret = srp_connect_target(target);
 	if (ret) {
-		printk(KERN_ERR PFX "Connection failed\n");
+		shost_printk(KERN_ERR, target->scsi_host,
+			     PFX "Connection failed\n");
 		goto err_cm_id;
 	}
 
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index e3573e7038c4..4a3c1f37e4c2 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -79,6 +79,11 @@ enum srp_target_state {
 	SRP_TARGET_REMOVED
 };
 
+enum srp_request_type {
+	SRP_REQ_NORMAL,
+	SRP_REQ_TASK_MGMT,
+};
+
 struct srp_device {
 	struct list_head	dev_list;
 	struct ib_device       *dev;
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index a3637d870880..fed3c375ccf3 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -195,7 +195,7 @@ static struct of_platform_driver ebus_beep_driver = {
 	.name		= "beep",
 	.match_table	= ebus_beep_match,
 	.probe		= ebus_beep_probe,
-	.remove		= sparcspkr_remove,
+	.remove		= __devexit_p(sparcspkr_remove),
 	.shutdown	= sparcspkr_shutdown,
 };
 
@@ -236,7 +236,7 @@ static struct of_platform_driver isa_beep_driver = {
 	.name		= "beep",
 	.match_table	= isa_beep_match,
 	.probe		= isa_beep_probe,
-	.remove		= sparcspkr_remove,
+	.remove		= __devexit_p(sparcspkr_remove),
 	.shutdown	= sparcspkr_shutdown,
 };
 
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
index 8991ab0b4fe3..61cff8374e6c 100644
--- a/drivers/input/mouse/pc110pad.c
+++ b/drivers/input/mouse/pc110pad.c
@@ -39,6 +39,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -62,8 +63,10 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr)
 	int value     = inb_p(pc110pad_io);
 	int handshake = inb_p(pc110pad_io + 2);
 
-	outb_p(handshake |  1, pc110pad_io + 2);
-	outb_p(handshake & ~1, pc110pad_io + 2);
+	outb(handshake |  1, pc110pad_io + 2);
+	udelay(2);
+	outb(handshake & ~1, pc110pad_io + 2);
+	udelay(2);
 	inb_p(0x64);
 
 	pc110pad_data[pc110pad_count++] = value;
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index b1b2e07bf080..99d92f5c93d6 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -74,10 +74,10 @@ extern unsigned int get_clk_frequency_khz(int info);
 
 static unsigned long calc_waittime(struct corgi_ts *corgi_ts)
 {
-	unsigned long hsync_len = corgi_ts->machinfo->get_hsync_len();
+	unsigned long hsync_invperiod = corgi_ts->machinfo->get_hsync_invperiod();
 
-	if (hsync_len)
-		return get_clk_frequency_khz(0)*1000/hsync_len;
+	if (hsync_invperiod)
+		return get_clk_frequency_khz(0)*1000/hsync_invperiod;
 	else
 		return 0;
 }
@@ -114,7 +114,7 @@ static int sync_receive_data_send_cmd(struct corgi_ts *corgi_ts, int doRecive, i
 			if (timer2-timer1 > wait_time) {
 				/* too slow - timeout, try again */
 				corgi_ts->machinfo->wait_hsync();
-				/* get OSCR */
+				/* get CCNT */
 				CCNT(timer1);
 				/* Wait after HSync */
 				CCNT(timer2);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index f449daef3eed..23ae66c76d47 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1544,11 +1544,11 @@ static int __init capi_init(void)
 		return PTR_ERR(capi_class);
 	}
 
-	class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
+	device_create(capi_class, NULL, MKDEV(capi_major, 0), "capi");
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 	if (capinc_tty_init() < 0) {
-		class_device_destroy(capi_class, MKDEV(capi_major, 0));
+		device_destroy(capi_class, MKDEV(capi_major, 0));
 		class_destroy(capi_class);
 		unregister_chrdev(capi_major, "capi20");
 		return -ENOMEM;
@@ -1576,7 +1576,7 @@ static void __exit capi_exit(void)
 {
 	proc_exit();
 
-	class_device_destroy(capi_class, MKDEV(capi_major, 0));
+	device_destroy(capi_class, MKDEV(capi_major, 0));
 	class_destroy(capi_class);
 	unregister_chrdev(capi_major, "capi20");
 
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 48c1775ef5b3..cb42b690b45e 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -2332,13 +2332,14 @@ static int __init capidrv_init(void)
 
 static void __exit capidrv_exit(void)
 {
-	char rev[10];
+	char rev[32];
 	char *p;
 
 	if ((p = strchr(revision, ':')) != 0) {
-		strcpy(rev, p + 1);
-		p = strchr(rev, '$');
-		*p = 0;
+		strncpy(rev, p + 1, sizeof(rev));
+		rev[sizeof(rev)-1] = 0;
+		if ((p = strchr(rev, '$')) != 0)
+			*p = 0;
 	} else {
 		strcpy(rev, " ??? ");
 	}
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index a0317abaeb11..02bdaf22d7ea 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -106,12 +106,6 @@ enum debuglevel {
 					 activated */
 };
 
-/* missing from linux/device.h ... */
-#ifndef dev_notice
-#define dev_notice(dev, format, arg...)		\
-	dev_printk(KERN_NOTICE , dev , format , ## arg)
-#endif
-
 /* Kernel message macros for situations where dev_printk and friends cannot be
  * used for lack of reliable access to a device structure.
  * linux/usb.h already contains these but in an obsolete form which clutters
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
deleted file mode 100644
index 656920636cb2..000000000000
--- a/drivers/kvm/Kconfig
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# KVM configuration
-#
-menuconfig VIRTUALIZATION
-	bool "Virtualization"
-	depends on X86
-	default y
-	---help---
-	  Say Y here to get to see options for using your Linux host to run other
-	  operating systems inside virtual machines (guests).
-	  This option alone does not add any kernel code.
-
-	  If you say N, all options in this submenu will be skipped and disabled.
-
-if VIRTUALIZATION
-
-config KVM
-	tristate "Kernel-based Virtual Machine (KVM) support"
-	depends on X86 && EXPERIMENTAL
-	select PREEMPT_NOTIFIERS
-	select ANON_INODES
-	---help---
-	  Support hosting fully virtualized guest machines using hardware
-	  virtualization extensions.  You will need a fairly recent
-	  processor equipped with virtualization extensions. You will also
-	  need to select one or more of the processor modules below.
-
-	  This module provides access to the hardware capabilities through
-	  a character device node named /dev/kvm.
-
-	  To compile this as a module, choose M here: the module
-	  will be called kvm.
-
-	  If unsure, say N.
-
-config KVM_INTEL
-	tristate "KVM for Intel processors support"
-	depends on KVM
-	---help---
-	  Provides support for KVM on Intel processors equipped with the VT
-	  extensions.
-
-config KVM_AMD
-	tristate "KVM for AMD processors support"
-	depends on KVM
-	---help---
-	  Provides support for KVM on AMD processors equipped with the AMD-V
-	  (SVM) extensions.
-
-# OK, it's a little counter-intuitive to do this, but it puts it neatly under
-# the virtualization menu.
-source drivers/lguest/Kconfig
-
-endif # VIRTUALIZATION
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile
deleted file mode 100644
index e5a8f4d3e973..000000000000
--- a/drivers/kvm/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile for Kernel-based Virtual Machine module
-#
-
-kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o lapic.o ioapic.o
-obj-$(CONFIG_KVM) += kvm.o
-kvm-intel-objs = vmx.o
-obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
-kvm-amd-objs = svm.o
-obj-$(CONFIG_KVM_AMD) += kvm-amd.o
diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c
deleted file mode 100644
index a679157bc599..000000000000
--- a/drivers/kvm/i8259.c
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * 8259 interrupt controller emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2007 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- * Authors:
- *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
- *   Port from Qemu.
- */
-#include <linux/mm.h>
-#include "irq.h"
-
-/*
- * set irq level. If an edge is detected, then the IRR is set to 1
- */
-static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level)
-{
-	int mask;
-	mask = 1 << irq;
-	if (s->elcr & mask)	/* level triggered */
-		if (level) {
-			s->irr |= mask;
-			s->last_irr |= mask;
-		} else {
-			s->irr &= ~mask;
-			s->last_irr &= ~mask;
-		}
-	else	/* edge triggered */
-		if (level) {
-			if ((s->last_irr & mask) == 0)
-				s->irr |= mask;
-			s->last_irr |= mask;
-		} else
-			s->last_irr &= ~mask;
-}
-
-/*
- * return the highest priority found in mask (highest = smallest
- * number). Return 8 if no irq
- */
-static inline int get_priority(struct kvm_kpic_state *s, int mask)
-{
-	int priority;
-	if (mask == 0)
-		return 8;
-	priority = 0;
-	while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
-		priority++;
-	return priority;
-}
-
-/*
- * return the pic wanted interrupt. return -1 if none
- */
-static int pic_get_irq(struct kvm_kpic_state *s)
-{
-	int mask, cur_priority, priority;
-
-	mask = s->irr & ~s->imr;
-	priority = get_priority(s, mask);
-	if (priority == 8)
-		return -1;
-	/*
-	 * compute current priority. If special fully nested mode on the
-	 * master, the IRQ coming from the slave is not taken into account
-	 * for the priority computation.
-	 */
-	mask = s->isr;
-	if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
-		mask &= ~(1 << 2);
-	cur_priority = get_priority(s, mask);
-	if (priority < cur_priority)
-		/*
-		 * higher priority found: an irq should be generated
-		 */
-		return (priority + s->priority_add) & 7;
-	else
-		return -1;
-}
-
-/*
- * raise irq to CPU if necessary. must be called every time the active
- * irq may change
- */
-static void pic_update_irq(struct kvm_pic *s)
-{
-	int irq2, irq;
-
-	irq2 = pic_get_irq(&s->pics[1]);
-	if (irq2 >= 0) {
-		/*
-		 * if irq request by slave pic, signal master PIC
-		 */
-		pic_set_irq1(&s->pics[0], 2, 1);
-		pic_set_irq1(&s->pics[0], 2, 0);
-	}
-	irq = pic_get_irq(&s->pics[0]);
-	if (irq >= 0)
-		s->irq_request(s->irq_request_opaque, 1);
-	else
-		s->irq_request(s->irq_request_opaque, 0);
-}
-
-void kvm_pic_update_irq(struct kvm_pic *s)
-{
-	pic_update_irq(s);
-}
-
-void kvm_pic_set_irq(void *opaque, int irq, int level)
-{
-	struct kvm_pic *s = opaque;
-
-	pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
-	pic_update_irq(s);
-}
-
-/*
- * acknowledge interrupt 'irq'
- */
-static inline void pic_intack(struct kvm_kpic_state *s, int irq)
-{
-	if (s->auto_eoi) {
-		if (s->rotate_on_auto_eoi)
-			s->priority_add = (irq + 1) & 7;
-	} else
-		s->isr |= (1 << irq);
-	/*
-	 * We don't clear a level sensitive interrupt here
-	 */
-	if (!(s->elcr & (1 << irq)))
-		s->irr &= ~(1 << irq);
-}
-
-int kvm_pic_read_irq(struct kvm_pic *s)
-{
-	int irq, irq2, intno;
-
-	irq = pic_get_irq(&s->pics[0]);
-	if (irq >= 0) {
-		pic_intack(&s->pics[0], irq);
-		if (irq == 2) {
-			irq2 = pic_get_irq(&s->pics[1]);
-			if (irq2 >= 0)
-				pic_intack(&s->pics[1], irq2);
-			else
-				/*
-				 * spurious IRQ on slave controller
-				 */
-				irq2 = 7;
-			intno = s->pics[1].irq_base + irq2;
-			irq = irq2 + 8;
-		} else
-			intno = s->pics[0].irq_base + irq;
-	} else {
-		/*
-		 * spurious IRQ on host controller
-		 */
-		irq = 7;
-		intno = s->pics[0].irq_base + irq;
-	}
-	pic_update_irq(s);
-
-	return intno;
-}
-
-static void pic_reset(void *opaque)
-{
-	struct kvm_kpic_state *s = opaque;
-
-	s->last_irr = 0;
-	s->irr = 0;
-	s->imr = 0;
-	s->isr = 0;
-	s->priority_add = 0;
-	s->irq_base = 0;
-	s->read_reg_select = 0;
-	s->poll = 0;
-	s->special_mask = 0;
-	s->init_state = 0;
-	s->auto_eoi = 0;
-	s->rotate_on_auto_eoi = 0;
-	s->special_fully_nested_mode = 0;
-	s->init4 = 0;
-}
-
-static void pic_ioport_write(void *opaque, u32 addr, u32 val)
-{
-	struct kvm_kpic_state *s = opaque;
-	int priority, cmd, irq;
-
-	addr &= 1;
-	if (addr == 0) {
-		if (val & 0x10) {
-			pic_reset(s);	/* init */
-			/*
-			 * deassert a pending interrupt
-			 */
-			s->pics_state->irq_request(s->pics_state->
-						   irq_request_opaque, 0);
-			s->init_state = 1;
-			s->init4 = val & 1;
-			if (val & 0x02)
-				printk(KERN_ERR "single mode not supported");
-			if (val & 0x08)
-				printk(KERN_ERR
-				       "level sensitive irq not supported");
-		} else if (val & 0x08) {
-			if (val & 0x04)
-				s->poll = 1;
-			if (val & 0x02)
-				s->read_reg_select = val & 1;
-			if (val & 0x40)
-				s->special_mask = (val >> 5) & 1;
-		} else {
-			cmd = val >> 5;
-			switch (cmd) {
-			case 0:
-			case 4:
-				s->rotate_on_auto_eoi = cmd >> 2;
-				break;
-			case 1:	/* end of interrupt */
-			case 5:
-				priority = get_priority(s, s->isr);
-				if (priority != 8) {
-					irq = (priority + s->priority_add) & 7;
-					s->isr &= ~(1 << irq);
-					if (cmd == 5)
-						s->priority_add = (irq + 1) & 7;
-					pic_update_irq(s->pics_state);
-				}
-				break;
-			case 3:
-				irq = val & 7;
-				s->isr &= ~(1 << irq);
-				pic_update_irq(s->pics_state);
-				break;
-			case 6:
-				s->priority_add = (val + 1) & 7;
-				pic_update_irq(s->pics_state);
-				break;
-			case 7:
-				irq = val & 7;
-				s->isr &= ~(1 << irq);
-				s->priority_add = (irq + 1) & 7;
-				pic_update_irq(s->pics_state);
-				break;
-			default:
-				break;	/* no operation */
-			}
-		}
-	} else
-		switch (s->init_state) {
-		case 0:		/* normal mode */
-			s->imr = val;
-			pic_update_irq(s->pics_state);
-			break;
-		case 1:
-			s->irq_base = val & 0xf8;
-			s->init_state = 2;
-			break;
-		case 2:
-			if (s->init4)
-				s->init_state = 3;
-			else
-				s->init_state = 0;
-			break;
-		case 3:
-			s->special_fully_nested_mode = (val >> 4) & 1;
-			s->auto_eoi = (val >> 1) & 1;
-			s->init_state = 0;
-			break;
-		}
-}
-
-static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1)
-{
-	int ret;
-
-	ret = pic_get_irq(s);
-	if (ret >= 0) {
-		if (addr1 >> 7) {
-			s->pics_state->pics[0].isr &= ~(1 << 2);
-			s->pics_state->pics[0].irr &= ~(1 << 2);
-		}
-		s->irr &= ~(1 << ret);
-		s->isr &= ~(1 << ret);
-		if (addr1 >> 7 || ret != 2)
-			pic_update_irq(s->pics_state);
-	} else {
-		ret = 0x07;
-		pic_update_irq(s->pics_state);
-	}
-
-	return ret;
-}
-
-static u32 pic_ioport_read(void *opaque, u32 addr1)
-{
-	struct kvm_kpic_state *s = opaque;
-	unsigned int addr;
-	int ret;
-
-	addr = addr1;
-	addr &= 1;
-	if (s->poll) {
-		ret = pic_poll_read(s, addr1);
-		s->poll = 0;
-	} else
-		if (addr == 0)
-			if (s->read_reg_select)
-				ret = s->isr;
-			else
-				ret = s->irr;
-		else
-			ret = s->imr;
-	return ret;
-}
-
-static void elcr_ioport_write(void *opaque, u32 addr, u32 val)
-{
-	struct kvm_kpic_state *s = opaque;
-	s->elcr = val & s->elcr_mask;
-}
-
-static u32 elcr_ioport_read(void *opaque, u32 addr1)
-{
-	struct kvm_kpic_state *s = opaque;
-	return s->elcr;
-}
-
-static int picdev_in_range(struct kvm_io_device *this, gpa_t addr)
-{
-	switch (addr) {
-	case 0x20:
-	case 0x21:
-	case 0xa0:
-	case 0xa1:
-	case 0x4d0:
-	case 0x4d1:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-static void picdev_write(struct kvm_io_device *this,
-			 gpa_t addr, int len, const void *val)
-{
-	struct kvm_pic *s = this->private;
-	unsigned char data = *(unsigned char *)val;
-
-	if (len != 1) {
-		if (printk_ratelimit())
-			printk(KERN_ERR "PIC: non byte write\n");
-		return;
-	}
-	switch (addr) {
-	case 0x20:
-	case 0x21:
-	case 0xa0:
-	case 0xa1:
-		pic_ioport_write(&s->pics[addr >> 7], addr, data);
-		break;
-	case 0x4d0:
-	case 0x4d1:
-		elcr_ioport_write(&s->pics[addr & 1], addr, data);
-		break;
-	}
-}
-
-static void picdev_read(struct kvm_io_device *this,
-			gpa_t addr, int len, void *val)
-{
-	struct kvm_pic *s = this->private;
-	unsigned char data = 0;
-
-	if (len != 1) {
-		if (printk_ratelimit())
-			printk(KERN_ERR "PIC: non byte read\n");
-		return;
-	}
-	switch (addr) {
-	case 0x20:
-	case 0x21:
-	case 0xa0:
-	case 0xa1:
-		data = pic_ioport_read(&s->pics[addr >> 7], addr);
-		break;
-	case 0x4d0:
-	case 0x4d1:
-		data = elcr_ioport_read(&s->pics[addr & 1], addr);
-		break;
-	}
-	*(unsigned char *)val = data;
-}
-
-/*
- * callback when PIC0 irq status changed
- */
-static void pic_irq_request(void *opaque, int level)
-{
-	struct kvm *kvm = opaque;
-	struct kvm_vcpu *vcpu = kvm->vcpus[0];
-
-	pic_irqchip(kvm)->output = level;
-	if (vcpu)
-		kvm_vcpu_kick(vcpu);
-}
-
-struct kvm_pic *kvm_create_pic(struct kvm *kvm)
-{
-	struct kvm_pic *s;
-	s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
-	if (!s)
-		return NULL;
-	s->pics[0].elcr_mask = 0xf8;
-	s->pics[1].elcr_mask = 0xde;
-	s->irq_request = pic_irq_request;
-	s->irq_request_opaque = kvm;
-	s->pics[0].pics_state = s;
-	s->pics[1].pics_state = s;
-
-	/*
-	 * Initialize PIO device
-	 */
-	s->dev.read = picdev_read;
-	s->dev.write = picdev_write;
-	s->dev.in_range = picdev_in_range;
-	s->dev.private = s;
-	kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev);
-	return s;
-}
diff --git a/drivers/kvm/ioapic.c b/drivers/kvm/ioapic.c
deleted file mode 100644
index c7992e667fdb..000000000000
--- a/drivers/kvm/ioapic.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- *  Copyright (C) 2001  MandrakeSoft S.A.
- *
- *    MandrakeSoft S.A.
- *    43, rue d'Aboukir
- *    75002 Paris - France
- *    http://www.linux-mandrake.com/
- *    http://www.mandrakesoft.com/
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- *  This library 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
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- *  Yunhong Jiang <yunhong.jiang@intel.com>
- *  Yaozu (Eddie) Dong <eddie.dong@intel.com>
- *  Based on Xen 3.1 code.
- */
-
-#include "kvm.h"
-#include <linux/kvm.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/smp.h>
-#include <linux/hrtimer.h>
-#include <linux/io.h>
-#include <asm/processor.h>
-#include <asm/msr.h>
-#include <asm/page.h>
-#include <asm/current.h>
-#include <asm/apicdef.h>
-#include <asm/io_apic.h>
-#include "irq.h"
-/* #define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
-#define ioapic_debug(fmt, arg...)
-static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq);
-
-static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
-					  unsigned long addr,
-					  unsigned long length)
-{
-	unsigned long result = 0;
-
-	switch (ioapic->ioregsel) {
-	case IOAPIC_REG_VERSION:
-		result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16)
-			  | (IOAPIC_VERSION_ID & 0xff));
-		break;
-
-	case IOAPIC_REG_APIC_ID:
-	case IOAPIC_REG_ARB_ID:
-		result = ((ioapic->id & 0xf) << 24);
-		break;
-
-	default:
-		{
-			u32 redir_index = (ioapic->ioregsel - 0x10) >> 1;
-			u64 redir_content;
-
-			ASSERT(redir_index < IOAPIC_NUM_PINS);
-
-			redir_content = ioapic->redirtbl[redir_index].bits;
-			result = (ioapic->ioregsel & 0x1) ?
-			    (redir_content >> 32) & 0xffffffff :
-			    redir_content & 0xffffffff;
-			break;
-		}
-	}
-
-	return result;
-}
-
-static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
-{
-	union ioapic_redir_entry *pent;
-
-	pent = &ioapic->redirtbl[idx];
-
-	if (!pent->fields.mask) {
-		ioapic_deliver(ioapic, idx);
-		if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
-			pent->fields.remote_irr = 1;
-	}
-	if (!pent->fields.trig_mode)
-		ioapic->irr &= ~(1 << idx);
-}
-
-static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
-{
-	unsigned index;
-
-	switch (ioapic->ioregsel) {
-	case IOAPIC_REG_VERSION:
-		/* Writes are ignored. */
-		break;
-
-	case IOAPIC_REG_APIC_ID:
-		ioapic->id = (val >> 24) & 0xf;
-		break;
-
-	case IOAPIC_REG_ARB_ID:
-		break;
-
-	default:
-		index = (ioapic->ioregsel - 0x10) >> 1;
-
-		ioapic_debug("change redir index %x val %x", index, val);
-		if (index >= IOAPIC_NUM_PINS)
-			return;
-		if (ioapic->ioregsel & 1) {
-			ioapic->redirtbl[index].bits &= 0xffffffff;
-			ioapic->redirtbl[index].bits |= (u64) val << 32;
-		} else {
-			ioapic->redirtbl[index].bits &= ~0xffffffffULL;
-			ioapic->redirtbl[index].bits |= (u32) val;
-			ioapic->redirtbl[index].fields.remote_irr = 0;
-		}
-		if (ioapic->irr & (1 << index))
-			ioapic_service(ioapic, index);
-		break;
-	}
-}
-
-static void ioapic_inj_irq(struct kvm_ioapic *ioapic,
-			   struct kvm_lapic *target,
-			   u8 vector, u8 trig_mode, u8 delivery_mode)
-{
-	ioapic_debug("irq %d trig %d deliv %d", vector, trig_mode,
-		     delivery_mode);
-
-	ASSERT((delivery_mode == dest_Fixed) ||
-	       (delivery_mode == dest_LowestPrio));
-
-	kvm_apic_set_irq(target, vector, trig_mode);
-}
-
-static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
-				       u8 dest_mode)
-{
-	u32 mask = 0;
-	int i;
-	struct kvm *kvm = ioapic->kvm;
-	struct kvm_vcpu *vcpu;
-
-	ioapic_debug("dest %d dest_mode %d", dest, dest_mode);
-
-	if (dest_mode == 0) {	/* Physical mode. */
-		if (dest == 0xFF) {	/* Broadcast. */
-			for (i = 0; i < KVM_MAX_VCPUS; ++i)
-				if (kvm->vcpus[i] && kvm->vcpus[i]->apic)
-					mask |= 1 << i;
-			return mask;
-		}
-		for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-			vcpu = kvm->vcpus[i];
-			if (!vcpu)
-				continue;
-			if (kvm_apic_match_physical_addr(vcpu->apic, dest)) {
-				if (vcpu->apic)
-					mask = 1 << i;
-				break;
-			}
-		}
-	} else if (dest != 0)	/* Logical mode, MDA non-zero. */
-		for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-			vcpu = kvm->vcpus[i];
-			if (!vcpu)
-				continue;
-			if (vcpu->apic &&
-			    kvm_apic_match_logical_addr(vcpu->apic, dest))
-				mask |= 1 << vcpu->vcpu_id;
-		}
-	ioapic_debug("mask %x", mask);
-	return mask;
-}
-
-static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
-{
-	u8 dest = ioapic->redirtbl[irq].fields.dest_id;
-	u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode;
-	u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode;
-	u8 vector = ioapic->redirtbl[irq].fields.vector;
-	u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode;
-	u32 deliver_bitmask;
-	struct kvm_lapic *target;
-	struct kvm_vcpu *vcpu;
-	int vcpu_id;
-
-	ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
-		     "vector=%x trig_mode=%x",
-		     dest, dest_mode, delivery_mode, vector, trig_mode);
-
-	deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode);
-	if (!deliver_bitmask) {
-		ioapic_debug("no target on destination");
-		return;
-	}
-
-	switch (delivery_mode) {
-	case dest_LowestPrio:
-		target =
-		    kvm_apic_round_robin(ioapic->kvm, vector, deliver_bitmask);
-		if (target != NULL)
-			ioapic_inj_irq(ioapic, target, vector,
-				       trig_mode, delivery_mode);
-		else
-			ioapic_debug("null round robin: "
-				     "mask=%x vector=%x delivery_mode=%x",
-				     deliver_bitmask, vector, dest_LowestPrio);
-		break;
-	case dest_Fixed:
-		for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
-			if (!(deliver_bitmask & (1 << vcpu_id)))
-				continue;
-			deliver_bitmask &= ~(1 << vcpu_id);
-			vcpu = ioapic->kvm->vcpus[vcpu_id];
-			if (vcpu) {
-				target = vcpu->apic;
-				ioapic_inj_irq(ioapic, target, vector,
-					       trig_mode, delivery_mode);
-			}
-		}
-		break;
-
-		/* TODO: NMI */
-	default:
-		printk(KERN_WARNING "Unsupported delivery mode %d\n",
-		       delivery_mode);
-		break;
-	}
-}
-
-void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
-{
-	u32 old_irr = ioapic->irr;
-	u32 mask = 1 << irq;
-	union ioapic_redir_entry entry;
-
-	if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
-		entry = ioapic->redirtbl[irq];
-		level ^= entry.fields.polarity;
-		if (!level)
-			ioapic->irr &= ~mask;
-		else {
-			ioapic->irr |= mask;
-			if ((!entry.fields.trig_mode && old_irr != ioapic->irr)
-			    || !entry.fields.remote_irr)
-				ioapic_service(ioapic, irq);
-		}
-	}
-}
-
-static int get_eoi_gsi(struct kvm_ioapic *ioapic, int vector)
-{
-	int i;
-
-	for (i = 0; i < IOAPIC_NUM_PINS; i++)
-		if (ioapic->redirtbl[i].fields.vector == vector)
-			return i;
-	return -1;
-}
-
-void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
-{
-	struct kvm_ioapic *ioapic = kvm->vioapic;
-	union ioapic_redir_entry *ent;
-	int gsi;
-
-	gsi = get_eoi_gsi(ioapic, vector);
-	if (gsi == -1) {
-		printk(KERN_WARNING "Can't find redir item for %d EOI\n",
-		       vector);
-		return;
-	}
-
-	ent = &ioapic->redirtbl[gsi];
-	ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
-
-	ent->fields.remote_irr = 0;
-	if (!ent->fields.mask && (ioapic->irr & (1 << gsi)))
-		ioapic_deliver(ioapic, gsi);
-}
-
-static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr)
-{
-	struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
-
-	return ((addr >= ioapic->base_address &&
-		 (addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
-}
-
-static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
-			     void *val)
-{
-	struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
-	u32 result;
-
-	ioapic_debug("addr %lx", (unsigned long)addr);
-	ASSERT(!(addr & 0xf));	/* check alignment */
-
-	addr &= 0xff;
-	switch (addr) {
-	case IOAPIC_REG_SELECT:
-		result = ioapic->ioregsel;
-		break;
-
-	case IOAPIC_REG_WINDOW:
-		result = ioapic_read_indirect(ioapic, addr, len);
-		break;
-
-	default:
-		result = 0;
-		break;
-	}
-	switch (len) {
-	case 8:
-		*(u64 *) val = result;
-		break;
-	case 1:
-	case 2:
-	case 4:
-		memcpy(val, (char *)&result, len);
-		break;
-	default:
-		printk(KERN_WARNING "ioapic: wrong length %d\n", len);
-	}
-}
-
-static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
-			      const void *val)
-{
-	struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
-	u32 data;
-
-	ioapic_debug("ioapic_mmio_write addr=%lx len=%d val=%p\n",
-		     addr, len, val);
-	ASSERT(!(addr & 0xf));	/* check alignment */
-	if (len == 4 || len == 8)
-		data = *(u32 *) val;
-	else {
-		printk(KERN_WARNING "ioapic: Unsupported size %d\n", len);
-		return;
-	}
-
-	addr &= 0xff;
-	switch (addr) {
-	case IOAPIC_REG_SELECT:
-		ioapic->ioregsel = data;
-		break;
-
-	case IOAPIC_REG_WINDOW:
-		ioapic_write_indirect(ioapic, data);
-		break;
-
-	default:
-		break;
-	}
-}
-
-int kvm_ioapic_init(struct kvm *kvm)
-{
-	struct kvm_ioapic *ioapic;
-	int i;
-
-	ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
-	if (!ioapic)
-		return -ENOMEM;
-	kvm->vioapic = ioapic;
-	for (i = 0; i < IOAPIC_NUM_PINS; i++)
-		ioapic->redirtbl[i].fields.mask = 1;
-	ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
-	ioapic->dev.read = ioapic_mmio_read;
-	ioapic->dev.write = ioapic_mmio_write;
-	ioapic->dev.in_range = ioapic_in_range;
-	ioapic->dev.private = ioapic;
-	ioapic->kvm = kvm;
-	kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev);
-	return 0;
-}
diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c
deleted file mode 100644
index 7628c7ff628f..000000000000
--- a/drivers/kvm/irq.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * irq.c: API for in kernel interrupt controller
- * Copyright (c) 2007, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- * Authors:
- *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
- *
- */
-
-#include <linux/module.h>
-
-#include "kvm.h"
-#include "irq.h"
-
-/*
- * check if there is pending interrupt without
- * intack.
- */
-int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
-{
-	struct kvm_pic *s;
-
-	if (kvm_apic_has_interrupt(v) == -1) {	/* LAPIC */
-		if (kvm_apic_accept_pic_intr(v)) {
-			s = pic_irqchip(v->kvm);	/* PIC */
-			return s->output;
-		} else
-			return 0;
-	}
-	return 1;
-}
-EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
-
-/*
- * Read pending interrupt vector and intack.
- */
-int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
-{
-	struct kvm_pic *s;
-	int vector;
-
-	vector = kvm_get_apic_interrupt(v);	/* APIC */
-	if (vector == -1) {
-		if (kvm_apic_accept_pic_intr(v)) {
-			s = pic_irqchip(v->kvm);
-			s->output = 0;		/* PIC */
-			vector = kvm_pic_read_irq(s);
-		}
-	}
-	return vector;
-}
-EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
-
-static void vcpu_kick_intr(void *info)
-{
-#ifdef DEBUG
-	struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
-	printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu);
-#endif
-}
-
-void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
-{
-	int ipi_pcpu = vcpu->cpu;
-
-	if (waitqueue_active(&vcpu->wq)) {
-		wake_up_interruptible(&vcpu->wq);
-		++vcpu->stat.halt_wakeup;
-	}
-	if (vcpu->guest_mode)
-		smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0);
-}
-
-void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
-{
-	kvm_inject_apic_timer_irqs(vcpu);
-	/* TODO: PIT, RTC etc. */
-}
-EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
-
-void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
-{
-	kvm_apic_timer_intr_post(vcpu, vec);
-	/* TODO: PIT, RTC etc. */
-}
-EXPORT_SYMBOL_GPL(kvm_timer_intr_post);
diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h
deleted file mode 100644
index 11fc014e2b30..000000000000
--- a/drivers/kvm/irq.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * irq.h: in kernel interrupt controller related definitions
- * Copyright (c) 2007, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- * Authors:
- *   Yaozu (Eddie) Dong <Eddie.dong@intel.com>
- *
- */
-
-#ifndef __IRQ_H
-#define __IRQ_H
-
-#include "kvm.h"
-
-typedef void irq_request_func(void *opaque, int level);
-
-struct kvm_kpic_state {
-	u8 last_irr;	/* edge detection */
-	u8 irr;		/* interrupt request register */
-	u8 imr;		/* interrupt mask register */
-	u8 isr;		/* interrupt service register */
-	u8 priority_add;	/* highest irq priority */
-	u8 irq_base;
-	u8 read_reg_select;
-	u8 poll;
-	u8 special_mask;
-	u8 init_state;
-	u8 auto_eoi;
-	u8 rotate_on_auto_eoi;
-	u8 special_fully_nested_mode;
-	u8 init4;		/* true if 4 byte init */
-	u8 elcr;		/* PIIX edge/trigger selection */
-	u8 elcr_mask;
-	struct kvm_pic *pics_state;
-};
-
-struct kvm_pic {
-	struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */
-	irq_request_func *irq_request;
-	void *irq_request_opaque;
-	int output;		/* intr from master PIC */
-	struct kvm_io_device dev;
-};
-
-struct kvm_pic *kvm_create_pic(struct kvm *kvm);
-void kvm_pic_set_irq(void *opaque, int irq, int level);
-int kvm_pic_read_irq(struct kvm_pic *s);
-int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
-int kvm_cpu_has_interrupt(struct kvm_vcpu *v);
-void kvm_pic_update_irq(struct kvm_pic *s);
-
-#define IOAPIC_NUM_PINS  KVM_IOAPIC_NUM_PINS
-#define IOAPIC_VERSION_ID 0x11	/* IOAPIC version */
-#define IOAPIC_EDGE_TRIG  0
-#define IOAPIC_LEVEL_TRIG 1
-
-#define IOAPIC_DEFAULT_BASE_ADDRESS  0xfec00000
-#define IOAPIC_MEM_LENGTH            0x100
-
-/* Direct registers. */
-#define IOAPIC_REG_SELECT  0x00
-#define IOAPIC_REG_WINDOW  0x10
-#define IOAPIC_REG_EOI     0x40	/* IA64 IOSAPIC only */
-
-/* Indirect registers. */
-#define IOAPIC_REG_APIC_ID 0x00	/* x86 IOAPIC only */
-#define IOAPIC_REG_VERSION 0x01
-#define IOAPIC_REG_ARB_ID  0x02	/* x86 IOAPIC only */
-
-struct kvm_ioapic {
-	u64 base_address;
-	u32 ioregsel;
-	u32 id;
-	u32 irr;
-	u32 pad;
-	union ioapic_redir_entry {
-		u64 bits;
-		struct {
-			u8 vector;
-			u8 delivery_mode:3;
-			u8 dest_mode:1;
-			u8 delivery_status:1;
-			u8 polarity:1;
-			u8 remote_irr:1;
-			u8 trig_mode:1;
-			u8 mask:1;
-			u8 reserve:7;
-			u8 reserved[4];
-			u8 dest_id;
-		} fields;
-	} redirtbl[IOAPIC_NUM_PINS];
-	struct kvm_io_device dev;
-	struct kvm *kvm;
-};
-
-struct kvm_lapic {
-	unsigned long base_address;
-	struct kvm_io_device dev;
-	struct {
-		atomic_t pending;
-		s64 period;	/* unit: ns */
-		u32 divide_count;
-		ktime_t last_update;
-		struct hrtimer dev;
-	} timer;
-	struct kvm_vcpu *vcpu;
-	struct page *regs_page;
-	void *regs;
-};
-
-#ifdef DEBUG
-#define ASSERT(x)  							\
-do {									\
-	if (!(x)) {							\
-		printk(KERN_EMERG "assertion failed %s: %d: %s\n",	\
-		       __FILE__, __LINE__, #x);				\
-		BUG();							\
-	}								\
-} while (0)
-#else
-#define ASSERT(x) do { } while (0)
-#endif
-
-void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
-int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
-int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
-int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
-int kvm_create_lapic(struct kvm_vcpu *vcpu);
-void kvm_lapic_reset(struct kvm_vcpu *vcpu);
-void kvm_free_apic(struct kvm_lapic *apic);
-u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
-void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
-void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
-struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
-				       unsigned long bitmap);
-u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
-void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
-int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
-void kvm_ioapic_update_eoi(struct kvm *kvm, int vector);
-int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
-int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig);
-void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
-int kvm_ioapic_init(struct kvm *kvm);
-void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
-int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
-int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
-void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
-void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
-void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
-void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
-void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu);
-
-#endif
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
deleted file mode 100644
index 3b0bc4bda5f2..000000000000
--- a/drivers/kvm/kvm.h
+++ /dev/null
@@ -1,796 +0,0 @@
-#ifndef __KVM_H
-#define __KVM_H
-
-/*
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- */
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/preempt.h>
-#include <asm/signal.h>
-
-#include <linux/kvm.h>
-#include <linux/kvm_para.h>
-
-#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1)
-#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD))
-#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS|0xFFFFFF0000000000ULL)
-
-#define KVM_GUEST_CR0_MASK \
-	(X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE \
-	 | X86_CR0_NW | X86_CR0_CD)
-#define KVM_VM_CR0_ALWAYS_ON \
-	(X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE | X86_CR0_TS \
-	 | X86_CR0_MP)
-#define KVM_GUEST_CR4_MASK \
-	(X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE)
-#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE)
-#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE)
-
-#define INVALID_PAGE (~(hpa_t)0)
-#define UNMAPPED_GVA (~(gpa_t)0)
-
-#define KVM_MAX_VCPUS 4
-#define KVM_ALIAS_SLOTS 4
-#define KVM_MEMORY_SLOTS 8
-#define KVM_NUM_MMU_PAGES 1024
-#define KVM_MIN_FREE_MMU_PAGES 5
-#define KVM_REFILL_PAGES 25
-#define KVM_MAX_CPUID_ENTRIES 40
-
-#define DE_VECTOR 0
-#define NM_VECTOR 7
-#define DF_VECTOR 8
-#define TS_VECTOR 10
-#define NP_VECTOR 11
-#define SS_VECTOR 12
-#define GP_VECTOR 13
-#define PF_VECTOR 14
-
-#define SELECTOR_TI_MASK (1 << 2)
-#define SELECTOR_RPL_MASK 0x03
-
-#define IOPL_SHIFT 12
-
-#define KVM_PIO_PAGE_OFFSET 1
-
-/*
- * vcpu->requests bit members
- */
-#define KVM_TLB_FLUSH 0
-
-/*
- * Address types:
- *
- *  gva - guest virtual address
- *  gpa - guest physical address
- *  gfn - guest frame number
- *  hva - host virtual address
- *  hpa - host physical address
- *  hfn - host frame number
- */
-
-typedef unsigned long  gva_t;
-typedef u64            gpa_t;
-typedef unsigned long  gfn_t;
-
-typedef unsigned long  hva_t;
-typedef u64            hpa_t;
-typedef unsigned long  hfn_t;
-
-#define NR_PTE_CHAIN_ENTRIES 5
-
-struct kvm_pte_chain {
-	u64 *parent_ptes[NR_PTE_CHAIN_ENTRIES];
-	struct hlist_node link;
-};
-
-/*
- * kvm_mmu_page_role, below, is defined as:
- *
- *   bits 0:3 - total guest paging levels (2-4, or zero for real mode)
- *   bits 4:7 - page table level for this shadow (1-4)
- *   bits 8:9 - page table quadrant for 2-level guests
- *   bit   16 - "metaphysical" - gfn is not a real page (huge page/real mode)
- *   bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde
- */
-union kvm_mmu_page_role {
-	unsigned word;
-	struct {
-		unsigned glevels : 4;
-		unsigned level : 4;
-		unsigned quadrant : 2;
-		unsigned pad_for_nice_hex_output : 6;
-		unsigned metaphysical : 1;
-		unsigned hugepage_access : 3;
-	};
-};
-
-struct kvm_mmu_page {
-	struct list_head link;
-	struct hlist_node hash_link;
-
-	/*
-	 * The following two entries are used to key the shadow page in the
-	 * hash table.
-	 */
-	gfn_t gfn;
-	union kvm_mmu_page_role role;
-
-	u64 *spt;
-	unsigned long slot_bitmap; /* One bit set per slot which has memory
-				    * in this shadow page.
-				    */
-	int multimapped;         /* More than one parent_pte? */
-	int root_count;          /* Currently serving as active root */
-	union {
-		u64 *parent_pte;               /* !multimapped */
-		struct hlist_head parent_ptes; /* multimapped, kvm_pte_chain */
-	};
-};
-
-struct kvm_vcpu;
-extern struct kmem_cache *kvm_vcpu_cache;
-
-/*
- * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level
- * 32-bit).  The kvm_mmu structure abstracts the details of the current mmu
- * mode.
- */
-struct kvm_mmu {
-	void (*new_cr3)(struct kvm_vcpu *vcpu);
-	int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err);
-	void (*free)(struct kvm_vcpu *vcpu);
-	gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva);
-	hpa_t root_hpa;
-	int root_level;
-	int shadow_root_level;
-
-	u64 *pae_root;
-};
-
-#define KVM_NR_MEM_OBJS 20
-
-struct kvm_mmu_memory_cache {
-	int nobjs;
-	void *objects[KVM_NR_MEM_OBJS];
-};
-
-/*
- * We don't want allocation failures within the mmu code, so we preallocate
- * enough memory for a single page fault in a cache.
- */
-struct kvm_guest_debug {
-	int enabled;
-	unsigned long bp[4];
-	int singlestep;
-};
-
-enum {
-	VCPU_REGS_RAX = 0,
-	VCPU_REGS_RCX = 1,
-	VCPU_REGS_RDX = 2,
-	VCPU_REGS_RBX = 3,
-	VCPU_REGS_RSP = 4,
-	VCPU_REGS_RBP = 5,
-	VCPU_REGS_RSI = 6,
-	VCPU_REGS_RDI = 7,
-#ifdef CONFIG_X86_64
-	VCPU_REGS_R8 = 8,
-	VCPU_REGS_R9 = 9,
-	VCPU_REGS_R10 = 10,
-	VCPU_REGS_R11 = 11,
-	VCPU_REGS_R12 = 12,
-	VCPU_REGS_R13 = 13,
-	VCPU_REGS_R14 = 14,
-	VCPU_REGS_R15 = 15,
-#endif
-	NR_VCPU_REGS
-};
-
-enum {
-	VCPU_SREG_CS,
-	VCPU_SREG_DS,
-	VCPU_SREG_ES,
-	VCPU_SREG_FS,
-	VCPU_SREG_GS,
-	VCPU_SREG_SS,
-	VCPU_SREG_TR,
-	VCPU_SREG_LDTR,
-};
-
-struct kvm_pio_request {
-	unsigned long count;
-	int cur_count;
-	struct page *guest_pages[2];
-	unsigned guest_page_offset;
-	int in;
-	int port;
-	int size;
-	int string;
-	int down;
-	int rep;
-};
-
-struct kvm_stat {
-	u32 pf_fixed;
-	u32 pf_guest;
-	u32 tlb_flush;
-	u32 invlpg;
-
-	u32 exits;
-	u32 io_exits;
-	u32 mmio_exits;
-	u32 signal_exits;
-	u32 irq_window_exits;
-	u32 halt_exits;
-	u32 halt_wakeup;
-	u32 request_irq_exits;
-	u32 irq_exits;
-	u32 light_exits;
-	u32 efer_reload;
-};
-
-struct kvm_io_device {
-	void (*read)(struct kvm_io_device *this,
-		     gpa_t addr,
-		     int len,
-		     void *val);
-	void (*write)(struct kvm_io_device *this,
-		      gpa_t addr,
-		      int len,
-		      const void *val);
-	int (*in_range)(struct kvm_io_device *this, gpa_t addr);
-	void (*destructor)(struct kvm_io_device *this);
-
-	void             *private;
-};
-
-static inline void kvm_iodevice_read(struct kvm_io_device *dev,
-				     gpa_t addr,
-				     int len,
-				     void *val)
-{
-	dev->read(dev, addr, len, val);
-}
-
-static inline void kvm_iodevice_write(struct kvm_io_device *dev,
-				      gpa_t addr,
-				      int len,
-				      const void *val)
-{
-	dev->write(dev, addr, len, val);
-}
-
-static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, gpa_t addr)
-{
-	return dev->in_range(dev, addr);
-}
-
-static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
-{
-	if (dev->destructor)
-		dev->destructor(dev);
-}
-
-/*
- * It would be nice to use something smarter than a linear search, TBD...
- * Thankfully we dont expect many devices to register (famous last words :),
- * so until then it will suffice.  At least its abstracted so we can change
- * in one place.
- */
-struct kvm_io_bus {
-	int                   dev_count;
-#define NR_IOBUS_DEVS 6
-	struct kvm_io_device *devs[NR_IOBUS_DEVS];
-};
-
-void kvm_io_bus_init(struct kvm_io_bus *bus);
-void kvm_io_bus_destroy(struct kvm_io_bus *bus);
-struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr);
-void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
-			     struct kvm_io_device *dev);
-
-struct kvm_vcpu {
-	struct kvm *kvm;
-	struct preempt_notifier preempt_notifier;
-	int vcpu_id;
-	struct mutex mutex;
-	int   cpu;
-	u64 host_tsc;
-	struct kvm_run *run;
-	int interrupt_window_open;
-	int guest_mode;
-	unsigned long requests;
-	unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
-	DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS);
-	unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
-	unsigned long rip;      /* needs vcpu_load_rsp_rip() */
-
-	unsigned long cr0;
-	unsigned long cr2;
-	unsigned long cr3;
-	gpa_t para_state_gpa;
-	struct page *para_state_page;
-	gpa_t hypercall_gpa;
-	unsigned long cr4;
-	unsigned long cr8;
-	u64 pdptrs[4]; /* pae */
-	u64 shadow_efer;
-	u64 apic_base;
-	struct kvm_lapic *apic;    /* kernel irqchip context */
-#define VCPU_MP_STATE_RUNNABLE          0
-#define VCPU_MP_STATE_UNINITIALIZED     1
-#define VCPU_MP_STATE_INIT_RECEIVED     2
-#define VCPU_MP_STATE_SIPI_RECEIVED     3
-#define VCPU_MP_STATE_HALTED            4
-	int mp_state;
-	int sipi_vector;
-	u64 ia32_misc_enable_msr;
-
-	struct kvm_mmu mmu;
-
-	struct kvm_mmu_memory_cache mmu_pte_chain_cache;
-	struct kvm_mmu_memory_cache mmu_rmap_desc_cache;
-	struct kvm_mmu_memory_cache mmu_page_cache;
-	struct kvm_mmu_memory_cache mmu_page_header_cache;
-
-	gfn_t last_pt_write_gfn;
-	int   last_pt_write_count;
-
-	struct kvm_guest_debug guest_debug;
-
-	struct i387_fxsave_struct host_fx_image;
-	struct i387_fxsave_struct guest_fx_image;
-	int fpu_active;
-	int guest_fpu_loaded;
-
-	int mmio_needed;
-	int mmio_read_completed;
-	int mmio_is_write;
-	int mmio_size;
-	unsigned char mmio_data[8];
-	gpa_t mmio_phys_addr;
-	gva_t mmio_fault_cr2;
-	struct kvm_pio_request pio;
-	void *pio_data;
-	wait_queue_head_t wq;
-
-	int sigset_active;
-	sigset_t sigset;
-
-	struct kvm_stat stat;
-
-	struct {
-		int active;
-		u8 save_iopl;
-		struct kvm_save_segment {
-			u16 selector;
-			unsigned long base;
-			u32 limit;
-			u32 ar;
-		} tr, es, ds, fs, gs;
-	} rmode;
-	int halt_request; /* real mode on Intel only */
-
-	int cpuid_nent;
-	struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES];
-};
-
-struct kvm_mem_alias {
-	gfn_t base_gfn;
-	unsigned long npages;
-	gfn_t target_gfn;
-};
-
-struct kvm_memory_slot {
-	gfn_t base_gfn;
-	unsigned long npages;
-	unsigned long flags;
-	struct page **phys_mem;
-	unsigned long *dirty_bitmap;
-};
-
-struct kvm {
-	struct mutex lock; /* protects everything except vcpus */
-	int naliases;
-	struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
-	int nmemslots;
-	struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS];
-	/*
-	 * Hash table of struct kvm_mmu_page.
-	 */
-	struct list_head active_mmu_pages;
-	int n_free_mmu_pages;
-	struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
-	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
-	unsigned long rmap_overflow;
-	struct list_head vm_list;
-	struct file *filp;
-	struct kvm_io_bus mmio_bus;
-	struct kvm_io_bus pio_bus;
-	struct kvm_pic *vpic;
-	struct kvm_ioapic *vioapic;
-	int round_robin_prev_vcpu;
-};
-
-static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
-{
-	return kvm->vpic;
-}
-
-static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
-{
-	return kvm->vioapic;
-}
-
-static inline int irqchip_in_kernel(struct kvm *kvm)
-{
-	return pic_irqchip(kvm) != 0;
-}
-
-struct descriptor_table {
-	u16 limit;
-	unsigned long base;
-} __attribute__((packed));
-
-struct kvm_x86_ops {
-	int (*cpu_has_kvm_support)(void);          /* __init */
-	int (*disabled_by_bios)(void);             /* __init */
-	void (*hardware_enable)(void *dummy);      /* __init */
-	void (*hardware_disable)(void *dummy);
-	void (*check_processor_compatibility)(void *rtn);
-	int (*hardware_setup)(void);               /* __init */
-	void (*hardware_unsetup)(void);            /* __exit */
-
-	/* Create, but do not attach this VCPU */
-	struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id);
-	void (*vcpu_free)(struct kvm_vcpu *vcpu);
-	void (*vcpu_reset)(struct kvm_vcpu *vcpu);
-
-	void (*prepare_guest_switch)(struct kvm_vcpu *vcpu);
-	void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
-	void (*vcpu_put)(struct kvm_vcpu *vcpu);
-	void (*vcpu_decache)(struct kvm_vcpu *vcpu);
-
-	int (*set_guest_debug)(struct kvm_vcpu *vcpu,
-			       struct kvm_debug_guest *dbg);
-	void (*guest_debug_pre)(struct kvm_vcpu *vcpu);
-	int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
-	int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
-	u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
-	void (*get_segment)(struct kvm_vcpu *vcpu,
-			    struct kvm_segment *var, int seg);
-	void (*set_segment)(struct kvm_vcpu *vcpu,
-			    struct kvm_segment *var, int seg);
-	void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
-	void (*decache_cr4_guest_bits)(struct kvm_vcpu *vcpu);
-	void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
-	void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
-	void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
-	void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
-	void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
-	void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
-	void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
-	void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt);
-	unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr);
-	void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value,
-		       int *exception);
-	void (*cache_regs)(struct kvm_vcpu *vcpu);
-	void (*decache_regs)(struct kvm_vcpu *vcpu);
-	unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
-	void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
-
-	void (*tlb_flush)(struct kvm_vcpu *vcpu);
-	void (*inject_page_fault)(struct kvm_vcpu *vcpu,
-				  unsigned long addr, u32 err_code);
-
-	void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code);
-
-	void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
-	int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
-	void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
-	void (*patch_hypercall)(struct kvm_vcpu *vcpu,
-				unsigned char *hypercall_addr);
-	int (*get_irq)(struct kvm_vcpu *vcpu);
-	void (*set_irq)(struct kvm_vcpu *vcpu, int vec);
-	void (*inject_pending_irq)(struct kvm_vcpu *vcpu);
-	void (*inject_pending_vectors)(struct kvm_vcpu *vcpu,
-				       struct kvm_run *run);
-};
-
-extern struct kvm_x86_ops *kvm_x86_ops;
-
-/* The guest did something we don't support. */
-#define pr_unimpl(vcpu, fmt, ...)					\
- do {									\
-	if (printk_ratelimit())						\
-		printk(KERN_ERR "kvm: %i: cpu%i " fmt,			\
-		       current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__); \
- } while(0)
-
-#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
-#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
-
-int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id);
-void kvm_vcpu_uninit(struct kvm_vcpu *vcpu);
-
-int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size,
-		  struct module *module);
-void kvm_exit_x86(void);
-
-int kvm_mmu_module_init(void);
-void kvm_mmu_module_exit(void);
-
-void kvm_mmu_destroy(struct kvm_vcpu *vcpu);
-int kvm_mmu_create(struct kvm_vcpu *vcpu);
-int kvm_mmu_setup(struct kvm_vcpu *vcpu);
-
-int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
-void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
-void kvm_mmu_zap_all(struct kvm *kvm);
-
-hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
-#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
-#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
-static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
-hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva);
-struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva);
-
-extern hpa_t bad_page_address;
-
-struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
-struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
-void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
-
-enum emulation_result {
-	EMULATE_DONE,       /* no further processing */
-	EMULATE_DO_MMIO,      /* kvm_run filled with mmio request */
-	EMULATE_FAIL,         /* can't emulate this instruction */
-};
-
-int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
-			unsigned long cr2, u16 error_code);
-void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
-void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
-void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
-void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
-		   unsigned long *rflags);
-
-unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
-void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
-		     unsigned long *rflags);
-int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
-int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
-
-struct x86_emulate_ctxt;
-
-int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
-		     int size, unsigned port);
-int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
-			   int size, unsigned long count, int down,
-			    gva_t address, int rep, unsigned port);
-void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
-int kvm_emulate_halt(struct kvm_vcpu *vcpu);
-int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
-int emulate_clts(struct kvm_vcpu *vcpu);
-int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr,
-		    unsigned long *dest);
-int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr,
-		    unsigned long value);
-
-void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
-void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0);
-void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
-void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
-unsigned long get_cr8(struct kvm_vcpu *vcpu);
-void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
-void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
-
-int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
-int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data);
-
-void fx_init(struct kvm_vcpu *vcpu);
-
-void kvm_resched(struct kvm_vcpu *vcpu);
-void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);
-void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
-void kvm_flush_remote_tlbs(struct kvm *kvm);
-
-int emulator_read_std(unsigned long addr,
-                      void *val,
-		      unsigned int bytes,
-		      struct kvm_vcpu *vcpu);
-int emulator_write_emulated(unsigned long addr,
-			    const void *val,
-			    unsigned int bytes,
-			    struct kvm_vcpu *vcpu);
-
-unsigned long segment_base(u16 selector);
-
-void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
-		       const u8 *new, int bytes);
-int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
-void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
-int kvm_mmu_load(struct kvm_vcpu *vcpu);
-void kvm_mmu_unload(struct kvm_vcpu *vcpu);
-
-int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
-
-static inline void kvm_guest_enter(void)
-{
-	current->flags |= PF_VCPU;
-}
-
-static inline void kvm_guest_exit(void)
-{
-	current->flags &= ~PF_VCPU;
-}
-
-static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
-				     u32 error_code)
-{
-	return vcpu->mmu.page_fault(vcpu, gva, error_code);
-}
-
-static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
-{
-	if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
-		__kvm_mmu_free_some_pages(vcpu);
-}
-
-static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu)
-{
-	if (likely(vcpu->mmu.root_hpa != INVALID_PAGE))
-		return 0;
-
-	return kvm_mmu_load(vcpu);
-}
-
-static inline int is_long_mode(struct kvm_vcpu *vcpu)
-{
-#ifdef CONFIG_X86_64
-	return vcpu->shadow_efer & EFER_LME;
-#else
-	return 0;
-#endif
-}
-
-static inline int is_pae(struct kvm_vcpu *vcpu)
-{
-	return vcpu->cr4 & X86_CR4_PAE;
-}
-
-static inline int is_pse(struct kvm_vcpu *vcpu)
-{
-	return vcpu->cr4 & X86_CR4_PSE;
-}
-
-static inline int is_paging(struct kvm_vcpu *vcpu)
-{
-	return vcpu->cr0 & X86_CR0_PG;
-}
-
-static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot)
-{
-	return slot - kvm->memslots;
-}
-
-static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
-{
-	struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT);
-
-	return (struct kvm_mmu_page *)page_private(page);
-}
-
-static inline u16 read_fs(void)
-{
-	u16 seg;
-	asm ("mov %%fs, %0" : "=g"(seg));
-	return seg;
-}
-
-static inline u16 read_gs(void)
-{
-	u16 seg;
-	asm ("mov %%gs, %0" : "=g"(seg));
-	return seg;
-}
-
-static inline u16 read_ldt(void)
-{
-	u16 ldt;
-	asm ("sldt %0" : "=g"(ldt));
-	return ldt;
-}
-
-static inline void load_fs(u16 sel)
-{
-	asm ("mov %0, %%fs" : : "rm"(sel));
-}
-
-static inline void load_gs(u16 sel)
-{
-	asm ("mov %0, %%gs" : : "rm"(sel));
-}
-
-#ifndef load_ldt
-static inline void load_ldt(u16 sel)
-{
-	asm ("lldt %0" : : "rm"(sel));
-}
-#endif
-
-static inline void get_idt(struct descriptor_table *table)
-{
-	asm ("sidt %0" : "=m"(*table));
-}
-
-static inline void get_gdt(struct descriptor_table *table)
-{
-	asm ("sgdt %0" : "=m"(*table));
-}
-
-static inline unsigned long read_tr_base(void)
-{
-	u16 tr;
-	asm ("str %0" : "=g"(tr));
-	return segment_base(tr);
-}
-
-#ifdef CONFIG_X86_64
-static inline unsigned long read_msr(unsigned long msr)
-{
-	u64 value;
-
-	rdmsrl(msr, value);
-	return value;
-}
-#endif
-
-static inline void fx_save(struct i387_fxsave_struct *image)
-{
-	asm ("fxsave (%0)":: "r" (image));
-}
-
-static inline void fx_restore(struct i387_fxsave_struct *image)
-{
-	asm ("fxrstor (%0)":: "r" (image));
-}
-
-static inline void fpu_init(void)
-{
-	asm ("finit");
-}
-
-static inline u32 get_rdx_init_val(void)
-{
-	return 0x600; /* P6 family */
-}
-
-#define ASM_VMX_VMCLEAR_RAX       ".byte 0x66, 0x0f, 0xc7, 0x30"
-#define ASM_VMX_VMLAUNCH          ".byte 0x0f, 0x01, 0xc2"
-#define ASM_VMX_VMRESUME          ".byte 0x0f, 0x01, 0xc3"
-#define ASM_VMX_VMPTRLD_RAX       ".byte 0x0f, 0xc7, 0x30"
-#define ASM_VMX_VMREAD_RDX_RAX    ".byte 0x0f, 0x78, 0xd0"
-#define ASM_VMX_VMWRITE_RAX_RDX   ".byte 0x0f, 0x79, 0xd0"
-#define ASM_VMX_VMWRITE_RSP_RDX   ".byte 0x0f, 0x79, 0xd4"
-#define ASM_VMX_VMXOFF            ".byte 0x0f, 0x01, 0xc4"
-#define ASM_VMX_VMXON_RAX         ".byte 0xf3, 0x0f, 0xc7, 0x30"
-
-#define MSR_IA32_TIME_STAMP_COUNTER		0x010
-
-#define TSS_IOPB_BASE_OFFSET 0x66
-#define TSS_BASE_SIZE 0x68
-#define TSS_IOPB_SIZE (65536 / 8)
-#define TSS_REDIRECTION_SIZE (256 / 8)
-#define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1)
-
-#endif
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
deleted file mode 100644
index 47c10b8f89b3..000000000000
--- a/drivers/kvm/kvm_main.c
+++ /dev/null
@@ -1,3628 +0,0 @@
-/*
- * Kernel-based Virtual Machine driver for Linux
- *
- * This module enables machines with Intel VT-x extensions to run virtual
- * machines without emulation or binary translation.
- *
- * Copyright (C) 2006 Qumranet, Inc.
- *
- * Authors:
- *   Avi Kivity   <avi@qumranet.com>
- *   Yaniv Kamay  <yaniv@qumranet.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "kvm.h"
-#include "x86_emulate.h"
-#include "segment_descriptor.h"
-#include "irq.h"
-
-#include <linux/kvm.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/percpu.h>
-#include <linux/gfp.h>
-#include <linux/mm.h>
-#include <linux/miscdevice.h>
-#include <linux/vmalloc.h>
-#include <linux/reboot.h>
-#include <linux/debugfs.h>
-#include <linux/highmem.h>
-#include <linux/file.h>
-#include <linux/sysdev.h>
-#include <linux/cpu.h>
-#include <linux/sched.h>
-#include <linux/cpumask.h>
-#include <linux/smp.h>
-#include <linux/anon_inodes.h>
-#include <linux/profile.h>
-
-#include <asm/processor.h>
-#include <asm/msr.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/desc.h>
-
-MODULE_AUTHOR("Qumranet");
-MODULE_LICENSE("GPL");
-
-static DEFINE_SPINLOCK(kvm_lock);
-static LIST_HEAD(vm_list);
-
-static cpumask_t cpus_hardware_enabled;
-
-struct kvm_x86_ops *kvm_x86_ops;
-struct kmem_cache *kvm_vcpu_cache;
-EXPORT_SYMBOL_GPL(kvm_vcpu_cache);
-
-static __read_mostly struct preempt_ops kvm_preempt_ops;
-
-#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
-
-static struct kvm_stats_debugfs_item {
-	const char *name;
-	int offset;
-	struct dentry *dentry;
-} debugfs_entries[] = {
-	{ "pf_fixed", STAT_OFFSET(pf_fixed) },
-	{ "pf_guest", STAT_OFFSET(pf_guest) },
-	{ "tlb_flush", STAT_OFFSET(tlb_flush) },
-	{ "invlpg", STAT_OFFSET(invlpg) },
-	{ "exits", STAT_OFFSET(exits) },
-	{ "io_exits", STAT_OFFSET(io_exits) },
-	{ "mmio_exits", STAT_OFFSET(mmio_exits) },
-	{ "signal_exits", STAT_OFFSET(signal_exits) },
-	{ "irq_window", STAT_OFFSET(irq_window_exits) },
-	{ "halt_exits", STAT_OFFSET(halt_exits) },
-	{ "halt_wakeup", STAT_OFFSET(halt_wakeup) },
-	{ "request_irq", STAT_OFFSET(request_irq_exits) },
-	{ "irq_exits", STAT_OFFSET(irq_exits) },
-	{ "light_exits", STAT_OFFSET(light_exits) },
-	{ "efer_reload", STAT_OFFSET(efer_reload) },
-	{ NULL }
-};
-
-static struct dentry *debugfs_dir;
-
-#define MAX_IO_MSRS 256
-
-#define CR0_RESERVED_BITS						\
-	(~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
-			  | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
-			  | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
-#define CR4_RESERVED_BITS						\
-	(~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
-			  | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE	\
-			  | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR	\
-			  | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
-
-#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
-#define EFER_RESERVED_BITS 0xfffffffffffff2fe
-
-#ifdef CONFIG_X86_64
-// LDT or TSS descriptor in the GDT. 16 bytes.
-struct segment_descriptor_64 {
-	struct segment_descriptor s;
-	u32 base_higher;
-	u32 pad_zero;
-};
-
-#endif
-
-static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
-			   unsigned long arg);
-
-unsigned long segment_base(u16 selector)
-{
-	struct descriptor_table gdt;
-	struct segment_descriptor *d;
-	unsigned long table_base;
-	typedef unsigned long ul;
-	unsigned long v;
-
-	if (selector == 0)
-		return 0;
-
-	asm ("sgdt %0" : "=m"(gdt));
-	table_base = gdt.base;
-
-	if (selector & 4) {           /* from ldt */
-		u16 ldt_selector;
-
-		asm ("sldt %0" : "=g"(ldt_selector));
-		table_base = segment_base(ldt_selector);
-	}
-	d = (struct segment_descriptor *)(table_base + (selector & ~7));
-	v = d->base_low | ((ul)d->base_mid << 16) | ((ul)d->base_high << 24);
-#ifdef CONFIG_X86_64
-	if (d->system == 0
-	    && (d->type == 2 || d->type == 9 || d->type == 11))
-		v |= ((ul)((struct segment_descriptor_64 *)d)->base_higher) << 32;
-#endif
-	return v;
-}
-EXPORT_SYMBOL_GPL(segment_base);
-
-static inline int valid_vcpu(int n)
-{
-	return likely(n >= 0 && n < KVM_MAX_VCPUS);
-}
-
-void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
-{
-	if (!vcpu->fpu_active || vcpu->guest_fpu_loaded)
-		return;
-
-	vcpu->guest_fpu_loaded = 1;
-	fx_save(&vcpu->host_fx_image);
-	fx_restore(&vcpu->guest_fx_image);
-}
-EXPORT_SYMBOL_GPL(kvm_load_guest_fpu);
-
-void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
-{
-	if (!vcpu->guest_fpu_loaded)
-		return;
-
-	vcpu->guest_fpu_loaded = 0;
-	fx_save(&vcpu->guest_fx_image);
-	fx_restore(&vcpu->host_fx_image);
-}
-EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
-
-/*
- * Switches to specified vcpu, until a matching vcpu_put()
- */
-static void vcpu_load(struct kvm_vcpu *vcpu)
-{
-	int cpu;
-
-	mutex_lock(&vcpu->mutex);
-	cpu = get_cpu();
-	preempt_notifier_register(&vcpu->preempt_notifier);
-	kvm_x86_ops->vcpu_load(vcpu, cpu);
-	put_cpu();
-}
-
-static void vcpu_put(struct kvm_vcpu *vcpu)
-{
-	preempt_disable();
-	kvm_x86_ops->vcpu_put(vcpu);
-	preempt_notifier_unregister(&vcpu->preempt_notifier);
-	preempt_enable();
-	mutex_unlock(&vcpu->mutex);
-}
-
-static void ack_flush(void *_completed)
-{
-}
-
-void kvm_flush_remote_tlbs(struct kvm *kvm)
-{
-	int i, cpu;
-	cpumask_t cpus;
-	struct kvm_vcpu *vcpu;
-
-	cpus_clear(cpus);
-	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-		vcpu = kvm->vcpus[i];
-		if (!vcpu)
-			continue;
-		if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests))
-			continue;
-		cpu = vcpu->cpu;
-		if (cpu != -1 && cpu != raw_smp_processor_id())
-			cpu_set(cpu, cpus);
-	}
-	smp_call_function_mask(cpus, ack_flush, NULL, 1);
-}
-
-int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
-{
-	struct page *page;
-	int r;
-
-	mutex_init(&vcpu->mutex);
-	vcpu->cpu = -1;
-	vcpu->mmu.root_hpa = INVALID_PAGE;
-	vcpu->kvm = kvm;
-	vcpu->vcpu_id = id;
-	if (!irqchip_in_kernel(kvm) || id == 0)
-		vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
-	else
-		vcpu->mp_state = VCPU_MP_STATE_UNINITIALIZED;
-	init_waitqueue_head(&vcpu->wq);
-
-	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-	if (!page) {
-		r = -ENOMEM;
-		goto fail;
-	}
-	vcpu->run = page_address(page);
-
-	page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-	if (!page) {
-		r = -ENOMEM;
-		goto fail_free_run;
-	}
-	vcpu->pio_data = page_address(page);
-
-	r = kvm_mmu_create(vcpu);
-	if (r < 0)
-		goto fail_free_pio_data;
-
-	return 0;
-
-fail_free_pio_data:
-	free_page((unsigned long)vcpu->pio_data);
-fail_free_run:
-	free_page((unsigned long)vcpu->run);
-fail:
-	return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(kvm_vcpu_init);
-
-void kvm_vcpu_uninit(struct kvm_vcpu *vcpu)
-{
-	kvm_mmu_destroy(vcpu);
-	if (vcpu->apic)
-		hrtimer_cancel(&vcpu->apic->timer.dev);
-	kvm_free_apic(vcpu->apic);
-	free_page((unsigned long)vcpu->pio_data);
-	free_page((unsigned long)vcpu->run);
-}
-EXPORT_SYMBOL_GPL(kvm_vcpu_uninit);
-
-static struct kvm *kvm_create_vm(void)
-{
-	struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
-
-	if (!kvm)
-		return ERR_PTR(-ENOMEM);
-
-	kvm_io_bus_init(&kvm->pio_bus);
-	mutex_init(&kvm->lock);
-	INIT_LIST_HEAD(&kvm->active_mmu_pages);
-	kvm_io_bus_init(&kvm->mmio_bus);
-	spin_lock(&kvm_lock);
-	list_add(&kvm->vm_list, &vm_list);
-	spin_unlock(&kvm_lock);
-	return kvm;
-}
-
-/*
- * Free any memory in @free but not in @dont.
- */
-static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
-				  struct kvm_memory_slot *dont)
-{
-	int i;
-
-	if (!dont || free->phys_mem != dont->phys_mem)
-		if (free->phys_mem) {
-			for (i = 0; i < free->npages; ++i)
-				if (free->phys_mem[i])
-					__free_page(free->phys_mem[i]);
-			vfree(free->phys_mem);
-		}
-
-	if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
-		vfree(free->dirty_bitmap);
-
-	free->phys_mem = NULL;
-	free->npages = 0;
-	free->dirty_bitmap = NULL;
-}
-
-static void kvm_free_physmem(struct kvm *kvm)
-{
-	int i;
-
-	for (i = 0; i < kvm->nmemslots; ++i)
-		kvm_free_physmem_slot(&kvm->memslots[i], NULL);
-}
-
-static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i)
-		if (vcpu->pio.guest_pages[i]) {
-			__free_page(vcpu->pio.guest_pages[i]);
-			vcpu->pio.guest_pages[i] = NULL;
-		}
-}
-
-static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
-{
-	vcpu_load(vcpu);
-	kvm_mmu_unload(vcpu);
-	vcpu_put(vcpu);
-}
-
-static void kvm_free_vcpus(struct kvm *kvm)
-{
-	unsigned int i;
-
-	/*
-	 * Unpin any mmu pages first.
-	 */
-	for (i = 0; i < KVM_MAX_VCPUS; ++i)
-		if (kvm->vcpus[i])
-			kvm_unload_vcpu_mmu(kvm->vcpus[i]);
-	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-		if (kvm->vcpus[i]) {
-			kvm_x86_ops->vcpu_free(kvm->vcpus[i]);
-			kvm->vcpus[i] = NULL;
-		}
-	}
-
-}
-
-static void kvm_destroy_vm(struct kvm *kvm)
-{
-	spin_lock(&kvm_lock);
-	list_del(&kvm->vm_list);
-	spin_unlock(&kvm_lock);
-	kvm_io_bus_destroy(&kvm->pio_bus);
-	kvm_io_bus_destroy(&kvm->mmio_bus);
-	kfree(kvm->vpic);
-	kfree(kvm->vioapic);
-	kvm_free_vcpus(kvm);
-	kvm_free_physmem(kvm);
-	kfree(kvm);
-}
-
-static int kvm_vm_release(struct inode *inode, struct file *filp)
-{
-	struct kvm *kvm = filp->private_data;
-
-	kvm_destroy_vm(kvm);
-	return 0;
-}
-
-static void inject_gp(struct kvm_vcpu *vcpu)
-{
-	kvm_x86_ops->inject_gp(vcpu, 0);
-}
-
-/*
- * Load the pae pdptrs.  Return true is they are all valid.
- */
-static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
-{
-	gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
-	unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
-	int i;
-	u64 *pdpt;
-	int ret;
-	struct page *page;
-	u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)];
-
-	mutex_lock(&vcpu->kvm->lock);
-	page = gfn_to_page(vcpu->kvm, pdpt_gfn);
-	if (!page) {
-		ret = 0;
-		goto out;
-	}
-
-	pdpt = kmap_atomic(page, KM_USER0);
-	memcpy(pdpte, pdpt+offset, sizeof(pdpte));
-	kunmap_atomic(pdpt, KM_USER0);
-
-	for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
-		if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) {
-			ret = 0;
-			goto out;
-		}
-	}
-	ret = 1;
-
-	memcpy(vcpu->pdptrs, pdpte, sizeof(vcpu->pdptrs));
-out:
-	mutex_unlock(&vcpu->kvm->lock);
-
-	return ret;
-}
-
-void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
-{
-	if (cr0 & CR0_RESERVED_BITS) {
-		printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
-		       cr0, vcpu->cr0);
-		inject_gp(vcpu);
-		return;
-	}
-
-	if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
-		printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n");
-		inject_gp(vcpu);
-		return;
-	}
-
-	if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) {
-		printk(KERN_DEBUG "set_cr0: #GP, set PG flag "
-		       "and a clear PE flag\n");
-		inject_gp(vcpu);
-		return;
-	}
-
-	if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
-#ifdef CONFIG_X86_64
-		if ((vcpu->shadow_efer & EFER_LME)) {
-			int cs_db, cs_l;
-
-			if (!is_pae(vcpu)) {
-				printk(KERN_DEBUG "set_cr0: #GP, start paging "
-				       "in long mode while PAE is disabled\n");
-				inject_gp(vcpu);
-				return;
-			}
-			kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
-			if (cs_l) {
-				printk(KERN_DEBUG "set_cr0: #GP, start paging "
-				       "in long mode while CS.L == 1\n");
-				inject_gp(vcpu);
-				return;
-
-			}
-		} else
-#endif
-		if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->cr3)) {
-			printk(KERN_DEBUG "set_cr0: #GP, pdptrs "
-			       "reserved bits\n");
-			inject_gp(vcpu);
-			return;
-		}
-
-	}
-
-	kvm_x86_ops->set_cr0(vcpu, cr0);
-	vcpu->cr0 = cr0;
-
-	mutex_lock(&vcpu->kvm->lock);
-	kvm_mmu_reset_context(vcpu);
-	mutex_unlock(&vcpu->kvm->lock);
-	return;
-}
-EXPORT_SYMBOL_GPL(set_cr0);
-
-void lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
-{
-	set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f));
-}
-EXPORT_SYMBOL_GPL(lmsw);
-
-void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
-{
-	if (cr4 & CR4_RESERVED_BITS) {
-		printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n");
-		inject_gp(vcpu);
-		return;
-	}
-
-	if (is_long_mode(vcpu)) {
-		if (!(cr4 & X86_CR4_PAE)) {
-			printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while "
-			       "in long mode\n");
-			inject_gp(vcpu);
-			return;
-		}
-	} else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & X86_CR4_PAE)
-		   && !load_pdptrs(vcpu, vcpu->cr3)) {
-		printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
-		inject_gp(vcpu);
-		return;
-	}
-
-	if (cr4 & X86_CR4_VMXE) {
-		printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n");
-		inject_gp(vcpu);
-		return;
-	}
-	kvm_x86_ops->set_cr4(vcpu, cr4);
-	vcpu->cr4 = cr4;
-	mutex_lock(&vcpu->kvm->lock);
-	kvm_mmu_reset_context(vcpu);
-	mutex_unlock(&vcpu->kvm->lock);
-}
-EXPORT_SYMBOL_GPL(set_cr4);
-
-void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
-{
-	if (is_long_mode(vcpu)) {
-		if (cr3 & CR3_L_MODE_RESERVED_BITS) {
-			printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
-			inject_gp(vcpu);
-			return;
-		}
-	} else {
-		if (is_pae(vcpu)) {
-			if (cr3 & CR3_PAE_RESERVED_BITS) {
-				printk(KERN_DEBUG
-				       "set_cr3: #GP, reserved bits\n");
-				inject_gp(vcpu);
-				return;
-			}
-			if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) {
-				printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
-				       "reserved bits\n");
-				inject_gp(vcpu);
-				return;
-			}
-		} else {
-			if (cr3 & CR3_NONPAE_RESERVED_BITS) {
-				printk(KERN_DEBUG
-				       "set_cr3: #GP, reserved bits\n");
-				inject_gp(vcpu);
-				return;
-			}
-		}
-	}
-
-	mutex_lock(&vcpu->kvm->lock);
-	/*
-	 * Does the new cr3 value map to physical memory? (Note, we
-	 * catch an invalid cr3 even in real-mode, because it would
-	 * cause trouble later on when we turn on paging anyway.)
-	 *
-	 * A real CPU would silently accept an invalid cr3 and would
-	 * attempt to use it - with largely undefined (and often hard
-	 * to debug) behavior on the guest side.
-	 */
-	if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT)))
-		inject_gp(vcpu);
-	else {
-		vcpu->cr3 = cr3;
-		vcpu->mmu.new_cr3(vcpu);
-	}
-	mutex_unlock(&vcpu->kvm->lock);
-}
-EXPORT_SYMBOL_GPL(set_cr3);
-
-void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
-{
-	if (cr8 & CR8_RESERVED_BITS) {
-		printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8);
-		inject_gp(vcpu);
-		return;
-	}
-	if (irqchip_in_kernel(vcpu->kvm))
-		kvm_lapic_set_tpr(vcpu, cr8);
-	else
-		vcpu->cr8 = cr8;
-}
-EXPORT_SYMBOL_GPL(set_cr8);
-
-unsigned long get_cr8(struct kvm_vcpu *vcpu)
-{
-	if (irqchip_in_kernel(vcpu->kvm))
-		return kvm_lapic_get_cr8(vcpu);
-	else
-		return vcpu->cr8;
-}
-EXPORT_SYMBOL_GPL(get_cr8);
-
-u64 kvm_get_apic_base(struct kvm_vcpu *vcpu)
-{
-	if (irqchip_in_kernel(vcpu->kvm))
-		return vcpu->apic_base;
-	else
-		return vcpu->apic_base;
-}
-EXPORT_SYMBOL_GPL(kvm_get_apic_base);
-
-void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data)
-{
-	/* TODO: reserve bits check */
-	if (irqchip_in_kernel(vcpu->kvm))
-		kvm_lapic_set_base(vcpu, data);
-	else
-		vcpu->apic_base = data;
-}
-EXPORT_SYMBOL_GPL(kvm_set_apic_base);
-
-void fx_init(struct kvm_vcpu *vcpu)
-{
-	unsigned after_mxcsr_mask;
-
-	/* Initialize guest FPU by resetting ours and saving into guest's */
-	preempt_disable();
-	fx_save(&vcpu->host_fx_image);
-	fpu_init();
-	fx_save(&vcpu->guest_fx_image);
-	fx_restore(&vcpu->host_fx_image);
-	preempt_enable();
-
-	vcpu->cr0 |= X86_CR0_ET;
-	after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space);
-	vcpu->guest_fx_image.mxcsr = 0x1f80;
-	memset((void *)&vcpu->guest_fx_image + after_mxcsr_mask,
-	       0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask);
-}
-EXPORT_SYMBOL_GPL(fx_init);
-
-/*
- * Allocate some memory and give it an address in the guest physical address
- * space.
- *
- * Discontiguous memory is allowed, mostly for framebuffers.
- */
-static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
-					  struct kvm_memory_region *mem)
-{
-	int r;
-	gfn_t base_gfn;
-	unsigned long npages;
-	unsigned long i;
-	struct kvm_memory_slot *memslot;
-	struct kvm_memory_slot old, new;
-
-	r = -EINVAL;
-	/* General sanity checks */
-	if (mem->memory_size & (PAGE_SIZE - 1))
-		goto out;
-	if (mem->guest_phys_addr & (PAGE_SIZE - 1))
-		goto out;
-	if (mem->slot >= KVM_MEMORY_SLOTS)
-		goto out;
-	if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr)
-		goto out;
-
-	memslot = &kvm->memslots[mem->slot];
-	base_gfn = mem->guest_phys_addr >> PAGE_SHIFT;
-	npages = mem->memory_size >> PAGE_SHIFT;
-
-	if (!npages)
-		mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES;
-
-	mutex_lock(&kvm->lock);
-
-	new = old = *memslot;
-
-	new.base_gfn = base_gfn;
-	new.npages = npages;
-	new.flags = mem->flags;
-
-	/* Disallow changing a memory slot's size. */
-	r = -EINVAL;
-	if (npages && old.npages && npages != old.npages)
-		goto out_unlock;
-
-	/* Check for overlaps */
-	r = -EEXIST;
-	for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
-		struct kvm_memory_slot *s = &kvm->memslots[i];
-
-		if (s == memslot)
-			continue;
-		if (!((base_gfn + npages <= s->base_gfn) ||
-		      (base_gfn >= s->base_gfn + s->npages)))
-			goto out_unlock;
-	}
-
-	/* Deallocate if slot is being removed */
-	if (!npages)
-		new.phys_mem = NULL;
-
-	/* Free page dirty bitmap if unneeded */
-	if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES))
-		new.dirty_bitmap = NULL;
-
-	r = -ENOMEM;
-
-	/* Allocate if a slot is being created */
-	if (npages && !new.phys_mem) {
-		new.phys_mem = vmalloc(npages * sizeof(struct page *));
-
-		if (!new.phys_mem)
-			goto out_unlock;
-
-		memset(new.phys_mem, 0, npages * sizeof(struct page *));
-		for (i = 0; i < npages; ++i) {
-			new.phys_mem[i] = alloc_page(GFP_HIGHUSER
-						     | __GFP_ZERO);
-			if (!new.phys_mem[i])
-				goto out_unlock;
-			set_page_private(new.phys_mem[i],0);
-		}
-	}
-
-	/* Allocate page dirty bitmap if needed */
-	if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
-		unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8;
-
-		new.dirty_bitmap = vmalloc(dirty_bytes);
-		if (!new.dirty_bitmap)
-			goto out_unlock;
-		memset(new.dirty_bitmap, 0, dirty_bytes);
-	}
-
-	if (mem->slot >= kvm->nmemslots)
-		kvm->nmemslots = mem->slot + 1;
-
-	*memslot = new;
-
-	kvm_mmu_slot_remove_write_access(kvm, mem->slot);
-	kvm_flush_remote_tlbs(kvm);
-
-	mutex_unlock(&kvm->lock);
-
-	kvm_free_physmem_slot(&old, &new);
-	return 0;
-
-out_unlock:
-	mutex_unlock(&kvm->lock);
-	kvm_free_physmem_slot(&new, &old);
-out:
-	return r;
-}
-
-/*
- * Get (and clear) the dirty memory log for a memory slot.
- */
-static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
-				      struct kvm_dirty_log *log)
-{
-	struct kvm_memory_slot *memslot;
-	int r, i;
-	int n;
-	unsigned long any = 0;
-
-	mutex_lock(&kvm->lock);
-
-	r = -EINVAL;
-	if (log->slot >= KVM_MEMORY_SLOTS)
-		goto out;
-
-	memslot = &kvm->memslots[log->slot];
-	r = -ENOENT;
-	if (!memslot->dirty_bitmap)
-		goto out;
-
-	n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
-
-	for (i = 0; !any && i < n/sizeof(long); ++i)
-		any = memslot->dirty_bitmap[i];
-
-	r = -EFAULT;
-	if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
-		goto out;
-
-	/* If nothing is dirty, don't bother messing with page tables. */
-	if (any) {
-		kvm_mmu_slot_remove_write_access(kvm, log->slot);
-		kvm_flush_remote_tlbs(kvm);
-		memset(memslot->dirty_bitmap, 0, n);
-	}
-
-	r = 0;
-
-out:
-	mutex_unlock(&kvm->lock);
-	return r;
-}
-
-/*
- * Set a new alias region.  Aliases map a portion of physical memory into
- * another portion.  This is useful for memory windows, for example the PC
- * VGA region.
- */
-static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
-					 struct kvm_memory_alias *alias)
-{
-	int r, n;
-	struct kvm_mem_alias *p;
-
-	r = -EINVAL;
-	/* General sanity checks */
-	if (alias->memory_size & (PAGE_SIZE - 1))
-		goto out;
-	if (alias->guest_phys_addr & (PAGE_SIZE - 1))
-		goto out;
-	if (alias->slot >= KVM_ALIAS_SLOTS)
-		goto out;
-	if (alias->guest_phys_addr + alias->memory_size
-	    < alias->guest_phys_addr)
-		goto out;
-	if (alias->target_phys_addr + alias->memory_size
-	    < alias->target_phys_addr)
-		goto out;
-
-	mutex_lock(&kvm->lock);
-
-	p = &kvm->aliases[alias->slot];
-	p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
-	p->npages = alias->memory_size >> PAGE_SHIFT;
-	p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
-
-	for (n = KVM_ALIAS_SLOTS; n > 0; --n)
-		if (kvm->aliases[n - 1].npages)
-			break;
-	kvm->naliases = n;
-
-	kvm_mmu_zap_all(kvm);
-
-	mutex_unlock(&kvm->lock);
-
-	return 0;
-
-out:
-	return r;
-}
-
-static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
-{
-	int r;
-
-	r = 0;
-	switch (chip->chip_id) {
-	case KVM_IRQCHIP_PIC_MASTER:
-		memcpy (&chip->chip.pic,
-			&pic_irqchip(kvm)->pics[0],
-			sizeof(struct kvm_pic_state));
-		break;
-	case KVM_IRQCHIP_PIC_SLAVE:
-		memcpy (&chip->chip.pic,
-			&pic_irqchip(kvm)->pics[1],
-			sizeof(struct kvm_pic_state));
-		break;
-	case KVM_IRQCHIP_IOAPIC:
-		memcpy (&chip->chip.ioapic,
-			ioapic_irqchip(kvm),
-			sizeof(struct kvm_ioapic_state));
-		break;
-	default:
-		r = -EINVAL;
-		break;
-	}
-	return r;
-}
-
-static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
-{
-	int r;
-
-	r = 0;
-	switch (chip->chip_id) {
-	case KVM_IRQCHIP_PIC_MASTER:
-		memcpy (&pic_irqchip(kvm)->pics[0],
-			&chip->chip.pic,
-			sizeof(struct kvm_pic_state));
-		break;
-	case KVM_IRQCHIP_PIC_SLAVE:
-		memcpy (&pic_irqchip(kvm)->pics[1],
-			&chip->chip.pic,
-			sizeof(struct kvm_pic_state));
-		break;
-	case KVM_IRQCHIP_IOAPIC:
-		memcpy (ioapic_irqchip(kvm),
-			&chip->chip.ioapic,
-			sizeof(struct kvm_ioapic_state));
-		break;
-	default:
-		r = -EINVAL;
-		break;
-	}
-	kvm_pic_update_irq(pic_irqchip(kvm));
-	return r;
-}
-
-static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
-{
-	int i;
-	struct kvm_mem_alias *alias;
-
-	for (i = 0; i < kvm->naliases; ++i) {
-		alias = &kvm->aliases[i];
-		if (gfn >= alias->base_gfn
-		    && gfn < alias->base_gfn + alias->npages)
-			return alias->target_gfn + gfn - alias->base_gfn;
-	}
-	return gfn;
-}
-
-static struct kvm_memory_slot *__gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
-{
-	int i;
-
-	for (i = 0; i < kvm->nmemslots; ++i) {
-		struct kvm_memory_slot *memslot = &kvm->memslots[i];
-
-		if (gfn >= memslot->base_gfn
-		    && gfn < memslot->base_gfn + memslot->npages)
-			return memslot;
-	}
-	return NULL;
-}
-
-struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
-{
-	gfn = unalias_gfn(kvm, gfn);
-	return __gfn_to_memslot(kvm, gfn);
-}
-
-struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
-{
-	struct kvm_memory_slot *slot;
-
-	gfn = unalias_gfn(kvm, gfn);
-	slot = __gfn_to_memslot(kvm, gfn);
-	if (!slot)
-		return NULL;
-	return slot->phys_mem[gfn - slot->base_gfn];
-}
-EXPORT_SYMBOL_GPL(gfn_to_page);
-
-/* WARNING: Does not work on aliased pages. */
-void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
-{
-	struct kvm_memory_slot *memslot;
-
-	memslot = __gfn_to_memslot(kvm, gfn);
-	if (memslot && memslot->dirty_bitmap) {
-		unsigned long rel_gfn = gfn - memslot->base_gfn;
-
-		/* avoid RMW */
-		if (!test_bit(rel_gfn, memslot->dirty_bitmap))
-			set_bit(rel_gfn, memslot->dirty_bitmap);
-	}
-}
-
-int emulator_read_std(unsigned long addr,
-			     void *val,
-			     unsigned int bytes,
-			     struct kvm_vcpu *vcpu)
-{
-	void *data = val;
-
-	while (bytes) {
-		gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
-		unsigned offset = addr & (PAGE_SIZE-1);
-		unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset);
-		unsigned long pfn;
-		struct page *page;
-		void *page_virt;
-
-		if (gpa == UNMAPPED_GVA)
-			return X86EMUL_PROPAGATE_FAULT;
-		pfn = gpa >> PAGE_SHIFT;
-		page = gfn_to_page(vcpu->kvm, pfn);
-		if (!page)
-			return X86EMUL_UNHANDLEABLE;
-		page_virt = kmap_atomic(page, KM_USER0);
-
-		memcpy(data, page_virt + offset, tocopy);
-
-		kunmap_atomic(page_virt, KM_USER0);
-
-		bytes -= tocopy;
-		data += tocopy;
-		addr += tocopy;
-	}
-
-	return X86EMUL_CONTINUE;
-}
-EXPORT_SYMBOL_GPL(emulator_read_std);
-
-static int emulator_write_std(unsigned long addr,
-			      const void *val,
-			      unsigned int bytes,
-			      struct kvm_vcpu *vcpu)
-{
-	pr_unimpl(vcpu, "emulator_write_std: addr %lx n %d\n", addr, bytes);
-	return X86EMUL_UNHANDLEABLE;
-}
-
-/*
- * Only apic need an MMIO device hook, so shortcut now..
- */
-static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
-						gpa_t addr)
-{
-	struct kvm_io_device *dev;
-
-	if (vcpu->apic) {
-		dev = &vcpu->apic->dev;
-		if (dev->in_range(dev, addr))
-			return dev;
-	}
-	return NULL;
-}
-
-static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
-						gpa_t addr)
-{
-	struct kvm_io_device *dev;
-
-	dev = vcpu_find_pervcpu_dev(vcpu, addr);
-	if (dev == NULL)
-		dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
-	return dev;
-}
-
-static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
-					       gpa_t addr)
-{
-	return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr);
-}
-
-static int emulator_read_emulated(unsigned long addr,
-				  void *val,
-				  unsigned int bytes,
-				  struct kvm_vcpu *vcpu)
-{
-	struct kvm_io_device *mmio_dev;
-	gpa_t                 gpa;
-
-	if (vcpu->mmio_read_completed) {
-		memcpy(val, vcpu->mmio_data, bytes);
-		vcpu->mmio_read_completed = 0;
-		return X86EMUL_CONTINUE;
-	} else if (emulator_read_std(addr, val, bytes, vcpu)
-		   == X86EMUL_CONTINUE)
-		return X86EMUL_CONTINUE;
-
-	gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
-	if (gpa == UNMAPPED_GVA)
-		return X86EMUL_PROPAGATE_FAULT;
-
-	/*
-	 * Is this MMIO handled locally?
-	 */
-	mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
-	if (mmio_dev) {
-		kvm_iodevice_read(mmio_dev, gpa, bytes, val);
-		return X86EMUL_CONTINUE;
-	}
-
-	vcpu->mmio_needed = 1;
-	vcpu->mmio_phys_addr = gpa;
-	vcpu->mmio_size = bytes;
-	vcpu->mmio_is_write = 0;
-
-	return X86EMUL_UNHANDLEABLE;
-}
-
-static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
-			       const void *val, int bytes)
-{
-	struct page *page;
-	void *virt;
-
-	if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT))
-		return 0;
-	page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
-	if (!page)
-		return 0;
-	mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
-	virt = kmap_atomic(page, KM_USER0);
-	kvm_mmu_pte_write(vcpu, gpa, val, bytes);
-	memcpy(virt + offset_in_page(gpa), val, bytes);
-	kunmap_atomic(virt, KM_USER0);
-	return 1;
-}
-
-static int emulator_write_emulated_onepage(unsigned long addr,
-					   const void *val,
-					   unsigned int bytes,
-					   struct kvm_vcpu *vcpu)
-{
-	struct kvm_io_device *mmio_dev;
-	gpa_t                 gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
-
-	if (gpa == UNMAPPED_GVA) {
-		kvm_x86_ops->inject_page_fault(vcpu, addr, 2);
-		return X86EMUL_PROPAGATE_FAULT;
-	}
-
-	if (emulator_write_phys(vcpu, gpa, val, bytes))
-		return X86EMUL_CONTINUE;
-
-	/*
-	 * Is this MMIO handled locally?
-	 */
-	mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
-	if (mmio_dev) {
-		kvm_iodevice_write(mmio_dev, gpa, bytes, val);
-		return X86EMUL_CONTINUE;
-	}
-
-	vcpu->mmio_needed = 1;
-	vcpu->mmio_phys_addr = gpa;
-	vcpu->mmio_size = bytes;
-	vcpu->mmio_is_write = 1;
-	memcpy(vcpu->mmio_data, val, bytes);
-
-	return X86EMUL_CONTINUE;
-}
-
-int emulator_write_emulated(unsigned long addr,
-				   const void *val,
-				   unsigned int bytes,
-				   struct kvm_vcpu *vcpu)
-{
-	/* Crossing a page boundary? */
-	if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
-		int rc, now;
-
-		now = -addr & ~PAGE_MASK;
-		rc = emulator_write_emulated_onepage(addr, val, now, vcpu);
-		if (rc != X86EMUL_CONTINUE)
-			return rc;
-		addr += now;
-		val += now;
-		bytes -= now;
-	}
-	return emulator_write_emulated_onepage(addr, val, bytes, vcpu);
-}
-EXPORT_SYMBOL_GPL(emulator_write_emulated);
-
-static int emulator_cmpxchg_emulated(unsigned long addr,
-				     const void *old,
-				     const void *new,
-				     unsigned int bytes,
-				     struct kvm_vcpu *vcpu)
-{
-	static int reported;
-
-	if (!reported) {
-		reported = 1;
-		printk(KERN_WARNING "kvm: emulating exchange as write\n");
-	}
-	return emulator_write_emulated(addr, new, bytes, vcpu);
-}
-
-static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
-{
-	return kvm_x86_ops->get_segment_base(vcpu, seg);
-}
-
-int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
-{
-	return X86EMUL_CONTINUE;
-}
-
-int emulate_clts(struct kvm_vcpu *vcpu)
-{
-	kvm_x86_ops->set_cr0(vcpu, vcpu->cr0 & ~X86_CR0_TS);
-	return X86EMUL_CONTINUE;
-}
-
-int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, unsigned long *dest)
-{
-	struct kvm_vcpu *vcpu = ctxt->vcpu;
-
-	switch (dr) {
-	case 0 ... 3:
-		*dest = kvm_x86_ops->get_dr(vcpu, dr);
-		return X86EMUL_CONTINUE;
-	default:
-		pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr);
-		return X86EMUL_UNHANDLEABLE;
-	}
-}
-
-int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
-{
-	unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
-	int exception;
-
-	kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
-	if (exception) {
-		/* FIXME: better handling */
-		return X86EMUL_UNHANDLEABLE;
-	}
-	return X86EMUL_CONTINUE;
-}
-
-void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
-{
-	static int reported;
-	u8 opcodes[4];
-	unsigned long rip = vcpu->rip;
-	unsigned long rip_linear;
-
-	rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
-
-	if (reported)
-		return;
-
-	emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu);
-
-	printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
-	       context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
-	reported = 1;
-}
-EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
-
-struct x86_emulate_ops emulate_ops = {
-	.read_std            = emulator_read_std,
-	.write_std           = emulator_write_std,
-	.read_emulated       = emulator_read_emulated,
-	.write_emulated      = emulator_write_emulated,
-	.cmpxchg_emulated    = emulator_cmpxchg_emulated,
-};
-
-int emulate_instruction(struct kvm_vcpu *vcpu,
-			struct kvm_run *run,
-			unsigned long cr2,
-			u16 error_code)
-{
-	struct x86_emulate_ctxt emulate_ctxt;
-	int r;
-	int cs_db, cs_l;
-
-	vcpu->mmio_fault_cr2 = cr2;
-	kvm_x86_ops->cache_regs(vcpu);
-
-	kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
-
-	emulate_ctxt.vcpu = vcpu;
-	emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
-	emulate_ctxt.cr2 = cr2;
-	emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM)
-		? X86EMUL_MODE_REAL : cs_l
-		? X86EMUL_MODE_PROT64 :	cs_db
-		? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
-
-	if (emulate_ctxt.mode == X86EMUL_MODE_PROT64) {
-		emulate_ctxt.cs_base = 0;
-		emulate_ctxt.ds_base = 0;
-		emulate_ctxt.es_base = 0;
-		emulate_ctxt.ss_base = 0;
-	} else {
-		emulate_ctxt.cs_base = get_segment_base(vcpu, VCPU_SREG_CS);
-		emulate_ctxt.ds_base = get_segment_base(vcpu, VCPU_SREG_DS);
-		emulate_ctxt.es_base = get_segment_base(vcpu, VCPU_SREG_ES);
-		emulate_ctxt.ss_base = get_segment_base(vcpu, VCPU_SREG_SS);
-	}
-
-	emulate_ctxt.gs_base = get_segment_base(vcpu, VCPU_SREG_GS);
-	emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS);
-
-	vcpu->mmio_is_write = 0;
-	vcpu->pio.string = 0;
-	r = x86_emulate_memop(&emulate_ctxt, &emulate_ops);
-	if (vcpu->pio.string)
-		return EMULATE_DO_MMIO;
-
-	if ((r || vcpu->mmio_is_write) && run) {
-		run->exit_reason = KVM_EXIT_MMIO;
-		run->mmio.phys_addr = vcpu->mmio_phys_addr;
-		memcpy(run->mmio.data, vcpu->mmio_data, 8);
-		run->mmio.len = vcpu->mmio_size;
-		run->mmio.is_write = vcpu->mmio_is_write;
-	}
-
-	if (r) {
-		if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
-			return EMULATE_DONE;
-		if (!vcpu->mmio_needed) {
-			kvm_report_emulation_failure(vcpu, "mmio");
-			return EMULATE_FAIL;
-		}
-		return EMULATE_DO_MMIO;
-	}
-
-	kvm_x86_ops->decache_regs(vcpu);
-	kvm_x86_ops->set_rflags(vcpu, emulate_ctxt.eflags);
-
-	if (vcpu->mmio_is_write) {
-		vcpu->mmio_needed = 0;
-		return EMULATE_DO_MMIO;
-	}
-
-	return EMULATE_DONE;
-}
-EXPORT_SYMBOL_GPL(emulate_instruction);
-
-/*
- * The vCPU has executed a HLT instruction with in-kernel mode enabled.
- */
-static void kvm_vcpu_block(struct kvm_vcpu *vcpu)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue(&vcpu->wq, &wait);
-
-	/*
-	 * We will block until either an interrupt or a signal wakes us up
-	 */
-	while (!kvm_cpu_has_interrupt(vcpu)
-	       && !signal_pending(current)
-	       && vcpu->mp_state != VCPU_MP_STATE_RUNNABLE
-	       && vcpu->mp_state != VCPU_MP_STATE_SIPI_RECEIVED) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		vcpu_put(vcpu);
-		schedule();
-		vcpu_load(vcpu);
-	}
-
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&vcpu->wq, &wait);
-}
-
-int kvm_emulate_halt(struct kvm_vcpu *vcpu)
-{
-	++vcpu->stat.halt_exits;
-	if (irqchip_in_kernel(vcpu->kvm)) {
-		vcpu->mp_state = VCPU_MP_STATE_HALTED;
-		kvm_vcpu_block(vcpu);
-		if (vcpu->mp_state != VCPU_MP_STATE_RUNNABLE)
-			return -EINTR;
-		return 1;
-	} else {
-		vcpu->run->exit_reason = KVM_EXIT_HLT;
-		return 0;
-	}
-}
-EXPORT_SYMBOL_GPL(kvm_emulate_halt);
-
-int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
-{
-	unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
-
-	kvm_x86_ops->cache_regs(vcpu);
-	ret = -KVM_EINVAL;
-#ifdef CONFIG_X86_64
-	if (is_long_mode(vcpu)) {
-		nr = vcpu->regs[VCPU_REGS_RAX];
-		a0 = vcpu->regs[VCPU_REGS_RDI];
-		a1 = vcpu->regs[VCPU_REGS_RSI];
-		a2 = vcpu->regs[VCPU_REGS_RDX];
-		a3 = vcpu->regs[VCPU_REGS_RCX];
-		a4 = vcpu->regs[VCPU_REGS_R8];
-		a5 = vcpu->regs[VCPU_REGS_R9];
-	} else
-#endif
-	{
-		nr = vcpu->regs[VCPU_REGS_RBX] & -1u;
-		a0 = vcpu->regs[VCPU_REGS_RAX] & -1u;
-		a1 = vcpu->regs[VCPU_REGS_RCX] & -1u;
-		a2 = vcpu->regs[VCPU_REGS_RDX] & -1u;
-		a3 = vcpu->regs[VCPU_REGS_RSI] & -1u;
-		a4 = vcpu->regs[VCPU_REGS_RDI] & -1u;
-		a5 = vcpu->regs[VCPU_REGS_RBP] & -1u;
-	}
-	switch (nr) {
-	default:
-		run->hypercall.nr = nr;
-		run->hypercall.args[0] = a0;
-		run->hypercall.args[1] = a1;
-		run->hypercall.args[2] = a2;
-		run->hypercall.args[3] = a3;
-		run->hypercall.args[4] = a4;
-		run->hypercall.args[5] = a5;
-		run->hypercall.ret = ret;
-		run->hypercall.longmode = is_long_mode(vcpu);
-		kvm_x86_ops->decache_regs(vcpu);
-		return 0;
-	}
-	vcpu->regs[VCPU_REGS_RAX] = ret;
-	kvm_x86_ops->decache_regs(vcpu);
-	return 1;
-}
-EXPORT_SYMBOL_GPL(kvm_hypercall);
-
-static u64 mk_cr_64(u64 curr_cr, u32 new_val)
-{
-	return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
-}
-
-void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
-{
-	struct descriptor_table dt = { limit, base };
-
-	kvm_x86_ops->set_gdt(vcpu, &dt);
-}
-
-void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
-{
-	struct descriptor_table dt = { limit, base };
-
-	kvm_x86_ops->set_idt(vcpu, &dt);
-}
-
-void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
-		   unsigned long *rflags)
-{
-	lmsw(vcpu, msw);
-	*rflags = kvm_x86_ops->get_rflags(vcpu);
-}
-
-unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
-{
-	kvm_x86_ops->decache_cr4_guest_bits(vcpu);
-	switch (cr) {
-	case 0:
-		return vcpu->cr0;
-	case 2:
-		return vcpu->cr2;
-	case 3:
-		return vcpu->cr3;
-	case 4:
-		return vcpu->cr4;
-	default:
-		vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr);
-		return 0;
-	}
-}
-
-void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
-		     unsigned long *rflags)
-{
-	switch (cr) {
-	case 0:
-		set_cr0(vcpu, mk_cr_64(vcpu->cr0, val));
-		*rflags = kvm_x86_ops->get_rflags(vcpu);
-		break;
-	case 2:
-		vcpu->cr2 = val;
-		break;
-	case 3:
-		set_cr3(vcpu, val);
-		break;
-	case 4:
-		set_cr4(vcpu, mk_cr_64(vcpu->cr4, val));
-		break;
-	default:
-		vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr);
-	}
-}
-
-/*
- * Register the para guest with the host:
- */
-static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
-{
-	struct kvm_vcpu_para_state *para_state;
-	hpa_t para_state_hpa, hypercall_hpa;
-	struct page *para_state_page;
-	unsigned char *hypercall;
-	gpa_t hypercall_gpa;
-
-	printk(KERN_DEBUG "kvm: guest trying to enter paravirtual mode\n");
-	printk(KERN_DEBUG ".... para_state_gpa: %08Lx\n", para_state_gpa);
-
-	/*
-	 * Needs to be page aligned:
-	 */
-	if (para_state_gpa != PAGE_ALIGN(para_state_gpa))
-		goto err_gp;
-
-	para_state_hpa = gpa_to_hpa(vcpu, para_state_gpa);
-	printk(KERN_DEBUG ".... para_state_hpa: %08Lx\n", para_state_hpa);
-	if (is_error_hpa(para_state_hpa))
-		goto err_gp;
-
-	mark_page_dirty(vcpu->kvm, para_state_gpa >> PAGE_SHIFT);
-	para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT);
-	para_state = kmap(para_state_page);
-
-	printk(KERN_DEBUG "....  guest version: %d\n", para_state->guest_version);
-	printk(KERN_DEBUG "....           size: %d\n", para_state->size);
-
-	para_state->host_version = KVM_PARA_API_VERSION;
-	/*
-	 * We cannot support guests that try to register themselves
-	 * with a newer API version than the host supports:
-	 */
-	if (para_state->guest_version > KVM_PARA_API_VERSION) {
-		para_state->ret = -KVM_EINVAL;
-		goto err_kunmap_skip;
-	}
-
-	hypercall_gpa = para_state->hypercall_gpa;
-	hypercall_hpa = gpa_to_hpa(vcpu, hypercall_gpa);
-	printk(KERN_DEBUG ".... hypercall_hpa: %08Lx\n", hypercall_hpa);
-	if (is_error_hpa(hypercall_hpa)) {
-		para_state->ret = -KVM_EINVAL;
-		goto err_kunmap_skip;
-	}
-
-	printk(KERN_DEBUG "kvm: para guest successfully registered.\n");
-	vcpu->para_state_page = para_state_page;
-	vcpu->para_state_gpa = para_state_gpa;
-	vcpu->hypercall_gpa = hypercall_gpa;
-
-	mark_page_dirty(vcpu->kvm, hypercall_gpa >> PAGE_SHIFT);
-	hypercall = kmap_atomic(pfn_to_page(hypercall_hpa >> PAGE_SHIFT),
-				KM_USER1) + (hypercall_hpa & ~PAGE_MASK);
-	kvm_x86_ops->patch_hypercall(vcpu, hypercall);
-	kunmap_atomic(hypercall, KM_USER1);
-
-	para_state->ret = 0;
-err_kunmap_skip:
-	kunmap(para_state_page);
-	return 0;
-err_gp:
-	return 1;
-}
-
-int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
-{
-	u64 data;
-
-	switch (msr) {
-	case 0xc0010010: /* SYSCFG */
-	case 0xc0010015: /* HWCR */
-	case MSR_IA32_PLATFORM_ID:
-	case MSR_IA32_P5_MC_ADDR:
-	case MSR_IA32_P5_MC_TYPE:
-	case MSR_IA32_MC0_CTL:
-	case MSR_IA32_MCG_STATUS:
-	case MSR_IA32_MCG_CAP:
-	case MSR_IA32_MC0_MISC:
-	case MSR_IA32_MC0_MISC+4:
-	case MSR_IA32_MC0_MISC+8:
-	case MSR_IA32_MC0_MISC+12:
-	case MSR_IA32_MC0_MISC+16:
-	case MSR_IA32_UCODE_REV:
-	case MSR_IA32_PERF_STATUS:
-	case MSR_IA32_EBL_CR_POWERON:
-		/* MTRR registers */
-	case 0xfe:
-	case 0x200 ... 0x2ff:
-		data = 0;
-		break;
-	case 0xcd: /* fsb frequency */
-		data = 3;
-		break;
-	case MSR_IA32_APICBASE:
-		data = kvm_get_apic_base(vcpu);
-		break;
-	case MSR_IA32_MISC_ENABLE:
-		data = vcpu->ia32_misc_enable_msr;
-		break;
-#ifdef CONFIG_X86_64
-	case MSR_EFER:
-		data = vcpu->shadow_efer;
-		break;
-#endif
-	default:
-		pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
-		return 1;
-	}
-	*pdata = data;
-	return 0;
-}
-EXPORT_SYMBOL_GPL(kvm_get_msr_common);
-
-/*
- * Reads an msr value (of 'msr_index') into 'pdata'.
- * Returns 0 on success, non-0 otherwise.
- * Assumes vcpu_load() was already called.
- */
-int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
-{
-	return kvm_x86_ops->get_msr(vcpu, msr_index, pdata);
-}
-
-#ifdef CONFIG_X86_64
-
-static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
-{
-	if (efer & EFER_RESERVED_BITS) {
-		printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n",
-		       efer);
-		inject_gp(vcpu);
-		return;
-	}
-
-	if (is_paging(vcpu)
-	    && (vcpu->shadow_efer & EFER_LME) != (efer & EFER_LME)) {
-		printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n");
-		inject_gp(vcpu);
-		return;
-	}
-
-	kvm_x86_ops->set_efer(vcpu, efer);
-
-	efer &= ~EFER_LMA;
-	efer |= vcpu->shadow_efer & EFER_LMA;
-
-	vcpu->shadow_efer = efer;
-}
-
-#endif
-
-int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
-{
-	switch (msr) {
-#ifdef CONFIG_X86_64
-	case MSR_EFER:
-		set_efer(vcpu, data);
-		break;
-#endif
-	case MSR_IA32_MC0_STATUS:
-		pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
-		       __FUNCTION__, data);
-		break;
-	case MSR_IA32_MCG_STATUS:
-		pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
-			__FUNCTION__, data);
-		break;
-	case MSR_IA32_UCODE_REV:
-	case MSR_IA32_UCODE_WRITE:
-	case 0x200 ... 0x2ff: /* MTRRs */
-		break;
-	case MSR_IA32_APICBASE:
-		kvm_set_apic_base(vcpu, data);
-		break;
-	case MSR_IA32_MISC_ENABLE:
-		vcpu->ia32_misc_enable_msr = data;
-		break;
-	/*
-	 * This is the 'probe whether the host is KVM' logic:
-	 */
-	case MSR_KVM_API_MAGIC:
-		return vcpu_register_para(vcpu, data);
-
-	default:
-		pr_unimpl(vcpu, "unhandled wrmsr: 0x%x\n", msr);
-		return 1;
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(kvm_set_msr_common);
-
-/*
- * Writes msr value into into the appropriate "register".
- * Returns 0 on success, non-0 otherwise.
- * Assumes vcpu_load() was already called.
- */
-int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
-{
-	return kvm_x86_ops->set_msr(vcpu, msr_index, data);
-}
-
-void kvm_resched(struct kvm_vcpu *vcpu)
-{
-	if (!need_resched())
-		return;
-	cond_resched();
-}
-EXPORT_SYMBOL_GPL(kvm_resched);
-
-void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
-{
-	int i;
-	u32 function;
-	struct kvm_cpuid_entry *e, *best;
-
-	kvm_x86_ops->cache_regs(vcpu);
-	function = vcpu->regs[VCPU_REGS_RAX];
-	vcpu->regs[VCPU_REGS_RAX] = 0;
-	vcpu->regs[VCPU_REGS_RBX] = 0;
-	vcpu->regs[VCPU_REGS_RCX] = 0;
-	vcpu->regs[VCPU_REGS_RDX] = 0;
-	best = NULL;
-	for (i = 0; i < vcpu->cpuid_nent; ++i) {
-		e = &vcpu->cpuid_entries[i];
-		if (e->function == function) {
-			best = e;
-			break;
-		}
-		/*
-		 * Both basic or both extended?
-		 */
-		if (((e->function ^ function) & 0x80000000) == 0)
-			if (!best || e->function > best->function)
-				best = e;
-	}
-	if (best) {
-		vcpu->regs[VCPU_REGS_RAX] = best->eax;
-		vcpu->regs[VCPU_REGS_RBX] = best->ebx;
-		vcpu->regs[VCPU_REGS_RCX] = best->ecx;
-		vcpu->regs[VCPU_REGS_RDX] = best->edx;
-	}
-	kvm_x86_ops->decache_regs(vcpu);
-	kvm_x86_ops->skip_emulated_instruction(vcpu);
-}
-EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
-
-static int pio_copy_data(struct kvm_vcpu *vcpu)
-{
-	void *p = vcpu->pio_data;
-	void *q;
-	unsigned bytes;
-	int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1;
-
-	q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE,
-		 PAGE_KERNEL);
-	if (!q) {
-		free_pio_guest_pages(vcpu);
-		return -ENOMEM;
-	}
-	q += vcpu->pio.guest_page_offset;
-	bytes = vcpu->pio.size * vcpu->pio.cur_count;
-	if (vcpu->pio.in)
-		memcpy(q, p, bytes);
-	else
-		memcpy(p, q, bytes);
-	q -= vcpu->pio.guest_page_offset;
-	vunmap(q);
-	free_pio_guest_pages(vcpu);
-	return 0;
-}
-
-static int complete_pio(struct kvm_vcpu *vcpu)
-{
-	struct kvm_pio_request *io = &vcpu->pio;
-	long delta;
-	int r;
-
-	kvm_x86_ops->cache_regs(vcpu);
-
-	if (!io->string) {
-		if (io->in)
-			memcpy(&vcpu->regs[VCPU_REGS_RAX], vcpu->pio_data,
-			       io->size);
-	} else {
-		if (io->in) {
-			r = pio_copy_data(vcpu);
-			if (r) {
-				kvm_x86_ops->cache_regs(vcpu);
-				return r;
-			}
-		}
-
-		delta = 1;
-		if (io->rep) {
-			delta *= io->cur_count;
-			/*
-			 * The size of the register should really depend on
-			 * current address size.
-			 */
-			vcpu->regs[VCPU_REGS_RCX] -= delta;
-		}
-		if (io->down)
-			delta = -delta;
-		delta *= io->size;
-		if (io->in)
-			vcpu->regs[VCPU_REGS_RDI] += delta;
-		else
-			vcpu->regs[VCPU_REGS_RSI] += delta;
-	}
-
-	kvm_x86_ops->decache_regs(vcpu);
-
-	io->count -= io->cur_count;
-	io->cur_count = 0;
-
-	return 0;
-}
-
-static void kernel_pio(struct kvm_io_device *pio_dev,
-		       struct kvm_vcpu *vcpu,
-		       void *pd)
-{
-	/* TODO: String I/O for in kernel device */
-
-	mutex_lock(&vcpu->kvm->lock);
-	if (vcpu->pio.in)
-		kvm_iodevice_read(pio_dev, vcpu->pio.port,
-				  vcpu->pio.size,
-				  pd);
-	else
-		kvm_iodevice_write(pio_dev, vcpu->pio.port,
-				   vcpu->pio.size,
-				   pd);
-	mutex_unlock(&vcpu->kvm->lock);
-}
-
-static void pio_string_write(struct kvm_io_device *pio_dev,
-			     struct kvm_vcpu *vcpu)
-{
-	struct kvm_pio_request *io = &vcpu->pio;
-	void *pd = vcpu->pio_data;
-	int i;
-
-	mutex_lock(&vcpu->kvm->lock);
-	for (i = 0; i < io->cur_count; i++) {
-		kvm_iodevice_write(pio_dev, io->port,
-				   io->size,
-				   pd);
-		pd += io->size;
-	}
-	mutex_unlock(&vcpu->kvm->lock);
-}
-
-int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
-		  int size, unsigned port)
-{
-	struct kvm_io_device *pio_dev;
-
-	vcpu->run->exit_reason = KVM_EXIT_IO;
-	vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
-	vcpu->run->io.size = vcpu->pio.size = size;
-	vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
-	vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = 1;
-	vcpu->run->io.port = vcpu->pio.port = port;
-	vcpu->pio.in = in;
-	vcpu->pio.string = 0;
-	vcpu->pio.down = 0;
-	vcpu->pio.guest_page_offset = 0;
-	vcpu->pio.rep = 0;
-
-	kvm_x86_ops->cache_regs(vcpu);
-	memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
-	kvm_x86_ops->decache_regs(vcpu);
-
-	kvm_x86_ops->skip_emulated_instruction(vcpu);
-
-	pio_dev = vcpu_find_pio_dev(vcpu, port);
-	if (pio_dev) {
-		kernel_pio(pio_dev, vcpu, vcpu->pio_data);
-		complete_pio(vcpu);
-		return 1;
-	}
-	return 0;
-}
-EXPORT_SYMBOL_GPL(kvm_emulate_pio);
-
-int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
-		  int size, unsigned long count, int down,
-		  gva_t address, int rep, unsigned port)
-{
-	unsigned now, in_page;
-	int i, ret = 0;
-	int nr_pages = 1;
-	struct page *page;
-	struct kvm_io_device *pio_dev;
-
-	vcpu->run->exit_reason = KVM_EXIT_IO;
-	vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
-	vcpu->run->io.size = vcpu->pio.size = size;
-	vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
-	vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = count;
-	vcpu->run->io.port = vcpu->pio.port = port;
-	vcpu->pio.in = in;
-	vcpu->pio.string = 1;
-	vcpu->pio.down = down;
-	vcpu->pio.guest_page_offset = offset_in_page(address);
-	vcpu->pio.rep = rep;
-
-	if (!count) {
-		kvm_x86_ops->skip_emulated_instruction(vcpu);
-		return 1;
-	}
-
-	if (!down)
-		in_page = PAGE_SIZE - offset_in_page(address);
-	else
-		in_page = offset_in_page(address) + size;
-	now = min(count, (unsigned long)in_page / size);
-	if (!now) {
-		/*
-		 * String I/O straddles page boundary.  Pin two guest pages
-		 * so that we satisfy atomicity constraints.  Do just one
-		 * transaction to avoid complexity.
-		 */
-		nr_pages = 2;
-		now = 1;
-	}
-	if (down) {
-		/*
-		 * String I/O in reverse.  Yuck.  Kill the guest, fix later.
-		 */
-		pr_unimpl(vcpu, "guest string pio down\n");
-		inject_gp(vcpu);
-		return 1;
-	}
-	vcpu->run->io.count = now;
-	vcpu->pio.cur_count = now;
-
-	if (vcpu->pio.cur_count == vcpu->pio.count)
-		kvm_x86_ops->skip_emulated_instruction(vcpu);
-
-	for (i = 0; i < nr_pages; ++i) {
-		mutex_lock(&vcpu->kvm->lock);
-		page = gva_to_page(vcpu, address + i * PAGE_SIZE);
-		if (page)
-			get_page(page);
-		vcpu->pio.guest_pages[i] = page;
-		mutex_unlock(&vcpu->kvm->lock);
-		if (!page) {
-			inject_gp(vcpu);
-			free_pio_guest_pages(vcpu);
-			return 1;
-		}
-	}
-
-	pio_dev = vcpu_find_pio_dev(vcpu, port);
-	if (!vcpu->pio.in) {
-		/* string PIO write */
-		ret = pio_copy_data(vcpu);
-		if (ret >= 0 && pio_dev) {
-			pio_string_write(pio_dev, vcpu);
-			complete_pio(vcpu);
-			if (vcpu->pio.count == 0)
-				ret = 1;
-		}
-	} else if (pio_dev)
-		pr_unimpl(vcpu, "no string pio read support yet, "
-		       "port %x size %d count %ld\n",
-			port, size, count);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(kvm_emulate_pio_string);
-
-/*
- * Check if userspace requested an interrupt window, and that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
-static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
-					  struct kvm_run *kvm_run)
-{
-	return (!vcpu->irq_summary &&
-		kvm_run->request_interrupt_window &&
-		vcpu->interrupt_window_open &&
-		(kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF));
-}
-
-static void post_kvm_run_save(struct kvm_vcpu *vcpu,
-			      struct kvm_run *kvm_run)
-{
-	kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
-	kvm_run->cr8 = get_cr8(vcpu);
-	kvm_run->apic_base = kvm_get_apic_base(vcpu);
-	if (irqchip_in_kernel(vcpu->kvm))
-		kvm_run->ready_for_interrupt_injection = 1;
-	else
-		kvm_run->ready_for_interrupt_injection =
-					(vcpu->interrupt_window_open &&
-					 vcpu->irq_summary == 0);
-}
-
-static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	int r;
-
-	if (unlikely(vcpu->mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) {
-		printk("vcpu %d received sipi with vector # %x\n",
-		       vcpu->vcpu_id, vcpu->sipi_vector);
-		kvm_lapic_reset(vcpu);
-		kvm_x86_ops->vcpu_reset(vcpu);
-		vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
-	}
-
-preempted:
-	if (vcpu->guest_debug.enabled)
-		kvm_x86_ops->guest_debug_pre(vcpu);
-
-again:
-	r = kvm_mmu_reload(vcpu);
-	if (unlikely(r))
-		goto out;
-
-	preempt_disable();
-
-	kvm_x86_ops->prepare_guest_switch(vcpu);
-	kvm_load_guest_fpu(vcpu);
-
-	local_irq_disable();
-
-	if (signal_pending(current)) {
-		local_irq_enable();
-		preempt_enable();
-		r = -EINTR;
-		kvm_run->exit_reason = KVM_EXIT_INTR;
-		++vcpu->stat.signal_exits;
-		goto out;
-	}
-
-	if (irqchip_in_kernel(vcpu->kvm))
-		kvm_x86_ops->inject_pending_irq(vcpu);
-	else if (!vcpu->mmio_read_completed)
-		kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run);
-
-	vcpu->guest_mode = 1;
-	kvm_guest_enter();
-
-	if (vcpu->requests)
-		if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
-			kvm_x86_ops->tlb_flush(vcpu);
-
-	kvm_x86_ops->run(vcpu, kvm_run);
-
-	vcpu->guest_mode = 0;
-	local_irq_enable();
-
-	++vcpu->stat.exits;
-
-	/*
-	 * We must have an instruction between local_irq_enable() and
-	 * kvm_guest_exit(), so the timer interrupt isn't delayed by
-	 * the interrupt shadow.  The stat.exits increment will do nicely.
-	 * But we need to prevent reordering, hence this barrier():
-	 */
-	barrier();
-
-	kvm_guest_exit();
-
-	preempt_enable();
-
-	/*
-	 * Profile KVM exit RIPs:
-	 */
-	if (unlikely(prof_on == KVM_PROFILING)) {
-		kvm_x86_ops->cache_regs(vcpu);
-		profile_hit(KVM_PROFILING, (void *)vcpu->rip);
-	}
-
-	r = kvm_x86_ops->handle_exit(kvm_run, vcpu);
-
-	if (r > 0) {
-		if (dm_request_for_irq_injection(vcpu, kvm_run)) {
-			r = -EINTR;
-			kvm_run->exit_reason = KVM_EXIT_INTR;
-			++vcpu->stat.request_irq_exits;
-			goto out;
-		}
-		if (!need_resched()) {
-			++vcpu->stat.light_exits;
-			goto again;
-		}
-	}
-
-out:
-	if (r > 0) {
-		kvm_resched(vcpu);
-		goto preempted;
-	}
-
-	post_kvm_run_save(vcpu, kvm_run);
-
-	return r;
-}
-
-
-static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	int r;
-	sigset_t sigsaved;
-
-	vcpu_load(vcpu);
-
-	if (unlikely(vcpu->mp_state == VCPU_MP_STATE_UNINITIALIZED)) {
-		kvm_vcpu_block(vcpu);
-		vcpu_put(vcpu);
-		return -EAGAIN;
-	}
-
-	if (vcpu->sigset_active)
-		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
-
-	/* re-sync apic's tpr */
-	if (!irqchip_in_kernel(vcpu->kvm))
-		set_cr8(vcpu, kvm_run->cr8);
-
-	if (vcpu->pio.cur_count) {
-		r = complete_pio(vcpu);
-		if (r)
-			goto out;
-	}
-
-	if (vcpu->mmio_needed) {
-		memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
-		vcpu->mmio_read_completed = 1;
-		vcpu->mmio_needed = 0;
-		r = emulate_instruction(vcpu, kvm_run,
-					vcpu->mmio_fault_cr2, 0);
-		if (r == EMULATE_DO_MMIO) {
-			/*
-			 * Read-modify-write.  Back to userspace.
-			 */
-			r = 0;
-			goto out;
-		}
-	}
-
-	if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) {
-		kvm_x86_ops->cache_regs(vcpu);
-		vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret;
-		kvm_x86_ops->decache_regs(vcpu);
-	}
-
-	r = __vcpu_run(vcpu, kvm_run);
-
-out:
-	if (vcpu->sigset_active)
-		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
-
-	vcpu_put(vcpu);
-	return r;
-}
-
-static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu,
-				   struct kvm_regs *regs)
-{
-	vcpu_load(vcpu);
-
-	kvm_x86_ops->cache_regs(vcpu);
-
-	regs->rax = vcpu->regs[VCPU_REGS_RAX];
-	regs->rbx = vcpu->regs[VCPU_REGS_RBX];
-	regs->rcx = vcpu->regs[VCPU_REGS_RCX];
-	regs->rdx = vcpu->regs[VCPU_REGS_RDX];
-	regs->rsi = vcpu->regs[VCPU_REGS_RSI];
-	regs->rdi = vcpu->regs[VCPU_REGS_RDI];
-	regs->rsp = vcpu->regs[VCPU_REGS_RSP];
-	regs->rbp = vcpu->regs[VCPU_REGS_RBP];
-#ifdef CONFIG_X86_64
-	regs->r8 = vcpu->regs[VCPU_REGS_R8];
-	regs->r9 = vcpu->regs[VCPU_REGS_R9];
-	regs->r10 = vcpu->regs[VCPU_REGS_R10];
-	regs->r11 = vcpu->regs[VCPU_REGS_R11];
-	regs->r12 = vcpu->regs[VCPU_REGS_R12];
-	regs->r13 = vcpu->regs[VCPU_REGS_R13];
-	regs->r14 = vcpu->regs[VCPU_REGS_R14];
-	regs->r15 = vcpu->regs[VCPU_REGS_R15];
-#endif
-
-	regs->rip = vcpu->rip;
-	regs->rflags = kvm_x86_ops->get_rflags(vcpu);
-
-	/*
-	 * Don't leak debug flags in case they were set for guest debugging
-	 */
-	if (vcpu->guest_debug.enabled && vcpu->guest_debug.singlestep)
-		regs->rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
-
-	vcpu_put(vcpu);
-
-	return 0;
-}
-
-static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu,
-				   struct kvm_regs *regs)
-{
-	vcpu_load(vcpu);
-
-	vcpu->regs[VCPU_REGS_RAX] = regs->rax;
-	vcpu->regs[VCPU_REGS_RBX] = regs->rbx;
-	vcpu->regs[VCPU_REGS_RCX] = regs->rcx;
-	vcpu->regs[VCPU_REGS_RDX] = regs->rdx;
-	vcpu->regs[VCPU_REGS_RSI] = regs->rsi;
-	vcpu->regs[VCPU_REGS_RDI] = regs->rdi;
-	vcpu->regs[VCPU_REGS_RSP] = regs->rsp;
-	vcpu->regs[VCPU_REGS_RBP] = regs->rbp;
-#ifdef CONFIG_X86_64
-	vcpu->regs[VCPU_REGS_R8] = regs->r8;
-	vcpu->regs[VCPU_REGS_R9] = regs->r9;
-	vcpu->regs[VCPU_REGS_R10] = regs->r10;
-	vcpu->regs[VCPU_REGS_R11] = regs->r11;
-	vcpu->regs[VCPU_REGS_R12] = regs->r12;
-	vcpu->regs[VCPU_REGS_R13] = regs->r13;
-	vcpu->regs[VCPU_REGS_R14] = regs->r14;
-	vcpu->regs[VCPU_REGS_R15] = regs->r15;
-#endif
-
-	vcpu->rip = regs->rip;
-	kvm_x86_ops->set_rflags(vcpu, regs->rflags);
-
-	kvm_x86_ops->decache_regs(vcpu);
-
-	vcpu_put(vcpu);
-
-	return 0;
-}
-
-static void get_segment(struct kvm_vcpu *vcpu,
-			struct kvm_segment *var, int seg)
-{
-	return kvm_x86_ops->get_segment(vcpu, var, seg);
-}
-
-static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
-				    struct kvm_sregs *sregs)
-{
-	struct descriptor_table dt;
-	int pending_vec;
-
-	vcpu_load(vcpu);
-
-	get_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
-	get_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
-	get_segment(vcpu, &sregs->es, VCPU_SREG_ES);
-	get_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
-	get_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
-	get_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
-
-	get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
-	get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
-
-	kvm_x86_ops->get_idt(vcpu, &dt);
-	sregs->idt.limit = dt.limit;
-	sregs->idt.base = dt.base;
-	kvm_x86_ops->get_gdt(vcpu, &dt);
-	sregs->gdt.limit = dt.limit;
-	sregs->gdt.base = dt.base;
-
-	kvm_x86_ops->decache_cr4_guest_bits(vcpu);
-	sregs->cr0 = vcpu->cr0;
-	sregs->cr2 = vcpu->cr2;
-	sregs->cr3 = vcpu->cr3;
-	sregs->cr4 = vcpu->cr4;
-	sregs->cr8 = get_cr8(vcpu);
-	sregs->efer = vcpu->shadow_efer;
-	sregs->apic_base = kvm_get_apic_base(vcpu);
-
-	if (irqchip_in_kernel(vcpu->kvm)) {
-		memset(sregs->interrupt_bitmap, 0,
-		       sizeof sregs->interrupt_bitmap);
-		pending_vec = kvm_x86_ops->get_irq(vcpu);
-		if (pending_vec >= 0)
-			set_bit(pending_vec, (unsigned long *)sregs->interrupt_bitmap);
-	} else
-		memcpy(sregs->interrupt_bitmap, vcpu->irq_pending,
-		       sizeof sregs->interrupt_bitmap);
-
-	vcpu_put(vcpu);
-
-	return 0;
-}
-
-static void set_segment(struct kvm_vcpu *vcpu,
-			struct kvm_segment *var, int seg)
-{
-	return kvm_x86_ops->set_segment(vcpu, var, seg);
-}
-
-static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
-				    struct kvm_sregs *sregs)
-{
-	int mmu_reset_needed = 0;
-	int i, pending_vec, max_bits;
-	struct descriptor_table dt;
-
-	vcpu_load(vcpu);
-
-	dt.limit = sregs->idt.limit;
-	dt.base = sregs->idt.base;
-	kvm_x86_ops->set_idt(vcpu, &dt);
-	dt.limit = sregs->gdt.limit;
-	dt.base = sregs->gdt.base;
-	kvm_x86_ops->set_gdt(vcpu, &dt);
-
-	vcpu->cr2 = sregs->cr2;
-	mmu_reset_needed |= vcpu->cr3 != sregs->cr3;
-	vcpu->cr3 = sregs->cr3;
-
-	set_cr8(vcpu, sregs->cr8);
-
-	mmu_reset_needed |= vcpu->shadow_efer != sregs->efer;
-#ifdef CONFIG_X86_64
-	kvm_x86_ops->set_efer(vcpu, sregs->efer);
-#endif
-	kvm_set_apic_base(vcpu, sregs->apic_base);
-
-	kvm_x86_ops->decache_cr4_guest_bits(vcpu);
-
-	mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
-	vcpu->cr0 = sregs->cr0;
-	kvm_x86_ops->set_cr0(vcpu, sregs->cr0);
-
-	mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
-	kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
-	if (!is_long_mode(vcpu) && is_pae(vcpu))
-		load_pdptrs(vcpu, vcpu->cr3);
-
-	if (mmu_reset_needed)
-		kvm_mmu_reset_context(vcpu);
-
-	if (!irqchip_in_kernel(vcpu->kvm)) {
-		memcpy(vcpu->irq_pending, sregs->interrupt_bitmap,
-		       sizeof vcpu->irq_pending);
-		vcpu->irq_summary = 0;
-		for (i = 0; i < ARRAY_SIZE(vcpu->irq_pending); ++i)
-			if (vcpu->irq_pending[i])
-				__set_bit(i, &vcpu->irq_summary);
-	} else {
-		max_bits = (sizeof sregs->interrupt_bitmap) << 3;
-		pending_vec = find_first_bit(
-			(const unsigned long *)sregs->interrupt_bitmap,
-			max_bits);
-		/* Only pending external irq is handled here */
-		if (pending_vec < max_bits) {
-			kvm_x86_ops->set_irq(vcpu, pending_vec);
-			printk("Set back pending irq %d\n", pending_vec);
-		}
-	}
-
-	set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
-	set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
-	set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
-	set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
-	set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
-	set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
-
-	set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
-	set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
-
-	vcpu_put(vcpu);
-
-	return 0;
-}
-
-void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
-{
-	struct kvm_segment cs;
-
-	get_segment(vcpu, &cs, VCPU_SREG_CS);
-	*db = cs.db;
-	*l = cs.l;
-}
-EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits);
-
-/*
- * List of msr numbers which we expose to userspace through KVM_GET_MSRS
- * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST.
- *
- * This list is modified at module load time to reflect the
- * capabilities of the host cpu.
- */
-static u32 msrs_to_save[] = {
-	MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
-	MSR_K6_STAR,
-#ifdef CONFIG_X86_64
-	MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
-#endif
-	MSR_IA32_TIME_STAMP_COUNTER,
-};
-
-static unsigned num_msrs_to_save;
-
-static u32 emulated_msrs[] = {
-	MSR_IA32_MISC_ENABLE,
-};
-
-static __init void kvm_init_msr_list(void)
-{
-	u32 dummy[2];
-	unsigned i, j;
-
-	for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) {
-		if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0)
-			continue;
-		if (j < i)
-			msrs_to_save[j] = msrs_to_save[i];
-		j++;
-	}
-	num_msrs_to_save = j;
-}
-
-/*
- * Adapt set_msr() to msr_io()'s calling convention
- */
-static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
-{
-	return kvm_set_msr(vcpu, index, *data);
-}
-
-/*
- * Read or write a bunch of msrs. All parameters are kernel addresses.
- *
- * @return number of msrs set successfully.
- */
-static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,
-		    struct kvm_msr_entry *entries,
-		    int (*do_msr)(struct kvm_vcpu *vcpu,
-				  unsigned index, u64 *data))
-{
-	int i;
-
-	vcpu_load(vcpu);
-
-	for (i = 0; i < msrs->nmsrs; ++i)
-		if (do_msr(vcpu, entries[i].index, &entries[i].data))
-			break;
-
-	vcpu_put(vcpu);
-
-	return i;
-}
-
-/*
- * Read or write a bunch of msrs. Parameters are user addresses.
- *
- * @return number of msrs set successfully.
- */
-static int msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs __user *user_msrs,
-		  int (*do_msr)(struct kvm_vcpu *vcpu,
-				unsigned index, u64 *data),
-		  int writeback)
-{
-	struct kvm_msrs msrs;
-	struct kvm_msr_entry *entries;
-	int r, n;
-	unsigned size;
-
-	r = -EFAULT;
-	if (copy_from_user(&msrs, user_msrs, sizeof msrs))
-		goto out;
-
-	r = -E2BIG;
-	if (msrs.nmsrs >= MAX_IO_MSRS)
-		goto out;
-
-	r = -ENOMEM;
-	size = sizeof(struct kvm_msr_entry) * msrs.nmsrs;
-	entries = vmalloc(size);
-	if (!entries)
-		goto out;
-
-	r = -EFAULT;
-	if (copy_from_user(entries, user_msrs->entries, size))
-		goto out_free;
-
-	r = n = __msr_io(vcpu, &msrs, entries, do_msr);
-	if (r < 0)
-		goto out_free;
-
-	r = -EFAULT;
-	if (writeback && copy_to_user(user_msrs->entries, entries, size))
-		goto out_free;
-
-	r = n;
-
-out_free:
-	vfree(entries);
-out:
-	return r;
-}
-
-/*
- * Translate a guest virtual address to a guest physical address.
- */
-static int kvm_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
-				    struct kvm_translation *tr)
-{
-	unsigned long vaddr = tr->linear_address;
-	gpa_t gpa;
-
-	vcpu_load(vcpu);
-	mutex_lock(&vcpu->kvm->lock);
-	gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr);
-	tr->physical_address = gpa;
-	tr->valid = gpa != UNMAPPED_GVA;
-	tr->writeable = 1;
-	tr->usermode = 0;
-	mutex_unlock(&vcpu->kvm->lock);
-	vcpu_put(vcpu);
-
-	return 0;
-}
-
-static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
-				    struct kvm_interrupt *irq)
-{
-	if (irq->irq < 0 || irq->irq >= 256)
-		return -EINVAL;
-	if (irqchip_in_kernel(vcpu->kvm))
-		return -ENXIO;
-	vcpu_load(vcpu);
-
-	set_bit(irq->irq, vcpu->irq_pending);
-	set_bit(irq->irq / BITS_PER_LONG, &vcpu->irq_summary);
-
-	vcpu_put(vcpu);
-
-	return 0;
-}
-
-static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
-				      struct kvm_debug_guest *dbg)
-{
-	int r;
-
-	vcpu_load(vcpu);
-
-	r = kvm_x86_ops->set_guest_debug(vcpu, dbg);
-
-	vcpu_put(vcpu);
-
-	return r;
-}
-
-static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
-				    unsigned long address,
-				    int *type)
-{
-	struct kvm_vcpu *vcpu = vma->vm_file->private_data;
-	unsigned long pgoff;
-	struct page *page;
-
-	pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
-	if (pgoff == 0)
-		page = virt_to_page(vcpu->run);
-	else if (pgoff == KVM_PIO_PAGE_OFFSET)
-		page = virt_to_page(vcpu->pio_data);
-	else
-		return NOPAGE_SIGBUS;
-	get_page(page);
-	if (type != NULL)
-		*type = VM_FAULT_MINOR;
-
-	return page;
-}
-
-static struct vm_operations_struct kvm_vcpu_vm_ops = {
-	.nopage = kvm_vcpu_nopage,
-};
-
-static int kvm_vcpu_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	vma->vm_ops = &kvm_vcpu_vm_ops;
-	return 0;
-}
-
-static int kvm_vcpu_release(struct inode *inode, struct file *filp)
-{
-	struct kvm_vcpu *vcpu = filp->private_data;
-
-	fput(vcpu->kvm->filp);
-	return 0;
-}
-
-static struct file_operations kvm_vcpu_fops = {
-	.release        = kvm_vcpu_release,
-	.unlocked_ioctl = kvm_vcpu_ioctl,
-	.compat_ioctl   = kvm_vcpu_ioctl,
-	.mmap           = kvm_vcpu_mmap,
-};
-
-/*
- * Allocates an inode for the vcpu.
- */
-static int create_vcpu_fd(struct kvm_vcpu *vcpu)
-{
-	int fd, r;
-	struct inode *inode;
-	struct file *file;
-
-	r = anon_inode_getfd(&fd, &inode, &file,
-			     "kvm-vcpu", &kvm_vcpu_fops, vcpu);
-	if (r)
-		return r;
-	atomic_inc(&vcpu->kvm->filp->f_count);
-	return fd;
-}
-
-/*
- * Creates some virtual cpus.  Good luck creating more than one.
- */
-static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
-{
-	int r;
-	struct kvm_vcpu *vcpu;
-
-	if (!valid_vcpu(n))
-		return -EINVAL;
-
-	vcpu = kvm_x86_ops->vcpu_create(kvm, n);
-	if (IS_ERR(vcpu))
-		return PTR_ERR(vcpu);
-
-	preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops);
-
-	/* We do fxsave: this must be aligned. */
-	BUG_ON((unsigned long)&vcpu->host_fx_image & 0xF);
-
-	vcpu_load(vcpu);
-	r = kvm_mmu_setup(vcpu);
-	vcpu_put(vcpu);
-	if (r < 0)
-		goto free_vcpu;
-
-	mutex_lock(&kvm->lock);
-	if (kvm->vcpus[n]) {
-		r = -EEXIST;
-		mutex_unlock(&kvm->lock);
-		goto mmu_unload;
-	}
-	kvm->vcpus[n] = vcpu;
-	mutex_unlock(&kvm->lock);
-
-	/* Now it's all set up, let userspace reach it */
-	r = create_vcpu_fd(vcpu);
-	if (r < 0)
-		goto unlink;
-	return r;
-
-unlink:
-	mutex_lock(&kvm->lock);
-	kvm->vcpus[n] = NULL;
-	mutex_unlock(&kvm->lock);
-
-mmu_unload:
-	vcpu_load(vcpu);
-	kvm_mmu_unload(vcpu);
-	vcpu_put(vcpu);
-
-free_vcpu:
-	kvm_x86_ops->vcpu_free(vcpu);
-	return r;
-}
-
-static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu)
-{
-	u64 efer;
-	int i;
-	struct kvm_cpuid_entry *e, *entry;
-
-	rdmsrl(MSR_EFER, efer);
-	entry = NULL;
-	for (i = 0; i < vcpu->cpuid_nent; ++i) {
-		e = &vcpu->cpuid_entries[i];
-		if (e->function == 0x80000001) {
-			entry = e;
-			break;
-		}
-	}
-	if (entry && (entry->edx & (1 << 20)) && !(efer & EFER_NX)) {
-		entry->edx &= ~(1 << 20);
-		printk(KERN_INFO "kvm: guest NX capability removed\n");
-	}
-}
-
-static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
-				    struct kvm_cpuid *cpuid,
-				    struct kvm_cpuid_entry __user *entries)
-{
-	int r;
-
-	r = -E2BIG;
-	if (cpuid->nent > KVM_MAX_CPUID_ENTRIES)
-		goto out;
-	r = -EFAULT;
-	if (copy_from_user(&vcpu->cpuid_entries, entries,
-			   cpuid->nent * sizeof(struct kvm_cpuid_entry)))
-		goto out;
-	vcpu->cpuid_nent = cpuid->nent;
-	cpuid_fix_nx_cap(vcpu);
-	return 0;
-
-out:
-	return r;
-}
-
-static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
-{
-	if (sigset) {
-		sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP));
-		vcpu->sigset_active = 1;
-		vcpu->sigset = *sigset;
-	} else
-		vcpu->sigset_active = 0;
-	return 0;
-}
-
-/*
- * fxsave fpu state.  Taken from x86_64/processor.h.  To be killed when
- * we have asm/x86/processor.h
- */
-struct fxsave {
-	u16	cwd;
-	u16	swd;
-	u16	twd;
-	u16	fop;
-	u64	rip;
-	u64	rdp;
-	u32	mxcsr;
-	u32	mxcsr_mask;
-	u32	st_space[32];	/* 8*16 bytes for each FP-reg = 128 bytes */
-#ifdef CONFIG_X86_64
-	u32	xmm_space[64];	/* 16*16 bytes for each XMM-reg = 256 bytes */
-#else
-	u32	xmm_space[32];	/* 8*16 bytes for each XMM-reg = 128 bytes */
-#endif
-};
-
-static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
-{
-	struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;
-
-	vcpu_load(vcpu);
-
-	memcpy(fpu->fpr, fxsave->st_space, 128);
-	fpu->fcw = fxsave->cwd;
-	fpu->fsw = fxsave->swd;
-	fpu->ftwx = fxsave->twd;
-	fpu->last_opcode = fxsave->fop;
-	fpu->last_ip = fxsave->rip;
-	fpu->last_dp = fxsave->rdp;
-	memcpy(fpu->xmm, fxsave->xmm_space, sizeof fxsave->xmm_space);
-
-	vcpu_put(vcpu);
-
-	return 0;
-}
-
-static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
-{
-	struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;
-
-	vcpu_load(vcpu);
-
-	memcpy(fxsave->st_space, fpu->fpr, 128);
-	fxsave->cwd = fpu->fcw;
-	fxsave->swd = fpu->fsw;
-	fxsave->twd = fpu->ftwx;
-	fxsave->fop = fpu->last_opcode;
-	fxsave->rip = fpu->last_ip;
-	fxsave->rdp = fpu->last_dp;
-	memcpy(fxsave->xmm_space, fpu->xmm, sizeof fxsave->xmm_space);
-
-	vcpu_put(vcpu);
-
-	return 0;
-}
-
-static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
-				    struct kvm_lapic_state *s)
-{
-	vcpu_load(vcpu);
-	memcpy(s->regs, vcpu->apic->regs, sizeof *s);
-	vcpu_put(vcpu);
-
-	return 0;
-}
-
-static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
-				    struct kvm_lapic_state *s)
-{
-	vcpu_load(vcpu);
-	memcpy(vcpu->apic->regs, s->regs, sizeof *s);
-	kvm_apic_post_state_restore(vcpu);
-	vcpu_put(vcpu);
-
-	return 0;
-}
-
-static long kvm_vcpu_ioctl(struct file *filp,
-			   unsigned int ioctl, unsigned long arg)
-{
-	struct kvm_vcpu *vcpu = filp->private_data;
-	void __user *argp = (void __user *)arg;
-	int r = -EINVAL;
-
-	switch (ioctl) {
-	case KVM_RUN:
-		r = -EINVAL;
-		if (arg)
-			goto out;
-		r = kvm_vcpu_ioctl_run(vcpu, vcpu->run);
-		break;
-	case KVM_GET_REGS: {
-		struct kvm_regs kvm_regs;
-
-		memset(&kvm_regs, 0, sizeof kvm_regs);
-		r = kvm_vcpu_ioctl_get_regs(vcpu, &kvm_regs);
-		if (r)
-			goto out;
-		r = -EFAULT;
-		if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs))
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_SET_REGS: {
-		struct kvm_regs kvm_regs;
-
-		r = -EFAULT;
-		if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs))
-			goto out;
-		r = kvm_vcpu_ioctl_set_regs(vcpu, &kvm_regs);
-		if (r)
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_GET_SREGS: {
-		struct kvm_sregs kvm_sregs;
-
-		memset(&kvm_sregs, 0, sizeof kvm_sregs);
-		r = kvm_vcpu_ioctl_get_sregs(vcpu, &kvm_sregs);
-		if (r)
-			goto out;
-		r = -EFAULT;
-		if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs))
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_SET_SREGS: {
-		struct kvm_sregs kvm_sregs;
-
-		r = -EFAULT;
-		if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
-			goto out;
-		r = kvm_vcpu_ioctl_set_sregs(vcpu, &kvm_sregs);
-		if (r)
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_TRANSLATE: {
-		struct kvm_translation tr;
-
-		r = -EFAULT;
-		if (copy_from_user(&tr, argp, sizeof tr))
-			goto out;
-		r = kvm_vcpu_ioctl_translate(vcpu, &tr);
-		if (r)
-			goto out;
-		r = -EFAULT;
-		if (copy_to_user(argp, &tr, sizeof tr))
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_INTERRUPT: {
-		struct kvm_interrupt irq;
-
-		r = -EFAULT;
-		if (copy_from_user(&irq, argp, sizeof irq))
-			goto out;
-		r = kvm_vcpu_ioctl_interrupt(vcpu, &irq);
-		if (r)
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_DEBUG_GUEST: {
-		struct kvm_debug_guest dbg;
-
-		r = -EFAULT;
-		if (copy_from_user(&dbg, argp, sizeof dbg))
-			goto out;
-		r = kvm_vcpu_ioctl_debug_guest(vcpu, &dbg);
-		if (r)
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_GET_MSRS:
-		r = msr_io(vcpu, argp, kvm_get_msr, 1);
-		break;
-	case KVM_SET_MSRS:
-		r = msr_io(vcpu, argp, do_set_msr, 0);
-		break;
-	case KVM_SET_CPUID: {
-		struct kvm_cpuid __user *cpuid_arg = argp;
-		struct kvm_cpuid cpuid;
-
-		r = -EFAULT;
-		if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid))
-			goto out;
-		r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries);
-		if (r)
-			goto out;
-		break;
-	}
-	case KVM_SET_SIGNAL_MASK: {
-		struct kvm_signal_mask __user *sigmask_arg = argp;
-		struct kvm_signal_mask kvm_sigmask;
-		sigset_t sigset, *p;
-
-		p = NULL;
-		if (argp) {
-			r = -EFAULT;
-			if (copy_from_user(&kvm_sigmask, argp,
-					   sizeof kvm_sigmask))
-				goto out;
-			r = -EINVAL;
-			if (kvm_sigmask.len != sizeof sigset)
-				goto out;
-			r = -EFAULT;
-			if (copy_from_user(&sigset, sigmask_arg->sigset,
-					   sizeof sigset))
-				goto out;
-			p = &sigset;
-		}
-		r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset);
-		break;
-	}
-	case KVM_GET_FPU: {
-		struct kvm_fpu fpu;
-
-		memset(&fpu, 0, sizeof fpu);
-		r = kvm_vcpu_ioctl_get_fpu(vcpu, &fpu);
-		if (r)
-			goto out;
-		r = -EFAULT;
-		if (copy_to_user(argp, &fpu, sizeof fpu))
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_SET_FPU: {
-		struct kvm_fpu fpu;
-
-		r = -EFAULT;
-		if (copy_from_user(&fpu, argp, sizeof fpu))
-			goto out;
-		r = kvm_vcpu_ioctl_set_fpu(vcpu, &fpu);
-		if (r)
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_GET_LAPIC: {
-		struct kvm_lapic_state lapic;
-
-		memset(&lapic, 0, sizeof lapic);
-		r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic);
-		if (r)
-			goto out;
-		r = -EFAULT;
-		if (copy_to_user(argp, &lapic, sizeof lapic))
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_SET_LAPIC: {
-		struct kvm_lapic_state lapic;
-
-		r = -EFAULT;
-		if (copy_from_user(&lapic, argp, sizeof lapic))
-			goto out;
-		r = kvm_vcpu_ioctl_set_lapic(vcpu, &lapic);;
-		if (r)
-			goto out;
-		r = 0;
-		break;
-	}
-	default:
-		;
-	}
-out:
-	return r;
-}
-
-static long kvm_vm_ioctl(struct file *filp,
-			   unsigned int ioctl, unsigned long arg)
-{
-	struct kvm *kvm = filp->private_data;
-	void __user *argp = (void __user *)arg;
-	int r = -EINVAL;
-
-	switch (ioctl) {
-	case KVM_CREATE_VCPU:
-		r = kvm_vm_ioctl_create_vcpu(kvm, arg);
-		if (r < 0)
-			goto out;
-		break;
-	case KVM_SET_MEMORY_REGION: {
-		struct kvm_memory_region kvm_mem;
-
-		r = -EFAULT;
-		if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
-			goto out;
-		r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_mem);
-		if (r)
-			goto out;
-		break;
-	}
-	case KVM_GET_DIRTY_LOG: {
-		struct kvm_dirty_log log;
-
-		r = -EFAULT;
-		if (copy_from_user(&log, argp, sizeof log))
-			goto out;
-		r = kvm_vm_ioctl_get_dirty_log(kvm, &log);
-		if (r)
-			goto out;
-		break;
-	}
-	case KVM_SET_MEMORY_ALIAS: {
-		struct kvm_memory_alias alias;
-
-		r = -EFAULT;
-		if (copy_from_user(&alias, argp, sizeof alias))
-			goto out;
-		r = kvm_vm_ioctl_set_memory_alias(kvm, &alias);
-		if (r)
-			goto out;
-		break;
-	}
-	case KVM_CREATE_IRQCHIP:
-		r = -ENOMEM;
-		kvm->vpic = kvm_create_pic(kvm);
-		if (kvm->vpic) {
-			r = kvm_ioapic_init(kvm);
-			if (r) {
-				kfree(kvm->vpic);
-				kvm->vpic = NULL;
-				goto out;
-			}
-		}
-		else
-			goto out;
-		break;
-	case KVM_IRQ_LINE: {
-		struct kvm_irq_level irq_event;
-
-		r = -EFAULT;
-		if (copy_from_user(&irq_event, argp, sizeof irq_event))
-			goto out;
-		if (irqchip_in_kernel(kvm)) {
-			mutex_lock(&kvm->lock);
-			if (irq_event.irq < 16)
-				kvm_pic_set_irq(pic_irqchip(kvm),
-					irq_event.irq,
-					irq_event.level);
-			kvm_ioapic_set_irq(kvm->vioapic,
-					irq_event.irq,
-					irq_event.level);
-			mutex_unlock(&kvm->lock);
-			r = 0;
-		}
-		break;
-	}
-	case KVM_GET_IRQCHIP: {
-		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
-		struct kvm_irqchip chip;
-
-		r = -EFAULT;
-		if (copy_from_user(&chip, argp, sizeof chip))
-			goto out;
-		r = -ENXIO;
-		if (!irqchip_in_kernel(kvm))
-			goto out;
-		r = kvm_vm_ioctl_get_irqchip(kvm, &chip);
-		if (r)
-			goto out;
-		r = -EFAULT;
-		if (copy_to_user(argp, &chip, sizeof chip))
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_SET_IRQCHIP: {
-		/* 0: PIC master, 1: PIC slave, 2: IOAPIC */
-		struct kvm_irqchip chip;
-
-		r = -EFAULT;
-		if (copy_from_user(&chip, argp, sizeof chip))
-			goto out;
-		r = -ENXIO;
-		if (!irqchip_in_kernel(kvm))
-			goto out;
-		r = kvm_vm_ioctl_set_irqchip(kvm, &chip);
-		if (r)
-			goto out;
-		r = 0;
-		break;
-	}
-	default:
-		;
-	}
-out:
-	return r;
-}
-
-static struct page *kvm_vm_nopage(struct vm_area_struct *vma,
-				  unsigned long address,
-				  int *type)
-{
-	struct kvm *kvm = vma->vm_file->private_data;
-	unsigned long pgoff;
-	struct page *page;
-
-	pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
-	page = gfn_to_page(kvm, pgoff);
-	if (!page)
-		return NOPAGE_SIGBUS;
-	get_page(page);
-	if (type != NULL)
-		*type = VM_FAULT_MINOR;
-
-	return page;
-}
-
-static struct vm_operations_struct kvm_vm_vm_ops = {
-	.nopage = kvm_vm_nopage,
-};
-
-static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	vma->vm_ops = &kvm_vm_vm_ops;
-	return 0;
-}
-
-static struct file_operations kvm_vm_fops = {
-	.release        = kvm_vm_release,
-	.unlocked_ioctl = kvm_vm_ioctl,
-	.compat_ioctl   = kvm_vm_ioctl,
-	.mmap           = kvm_vm_mmap,
-};
-
-static int kvm_dev_ioctl_create_vm(void)
-{
-	int fd, r;
-	struct inode *inode;
-	struct file *file;
-	struct kvm *kvm;
-
-	kvm = kvm_create_vm();
-	if (IS_ERR(kvm))
-		return PTR_ERR(kvm);
-	r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm);
-	if (r) {
-		kvm_destroy_vm(kvm);
-		return r;
-	}
-
-	kvm->filp = file;
-
-	return fd;
-}
-
-static long kvm_dev_ioctl(struct file *filp,
-			  unsigned int ioctl, unsigned long arg)
-{
-	void __user *argp = (void __user *)arg;
-	long r = -EINVAL;
-
-	switch (ioctl) {
-	case KVM_GET_API_VERSION:
-		r = -EINVAL;
-		if (arg)
-			goto out;
-		r = KVM_API_VERSION;
-		break;
-	case KVM_CREATE_VM:
-		r = -EINVAL;
-		if (arg)
-			goto out;
-		r = kvm_dev_ioctl_create_vm();
-		break;
-	case KVM_GET_MSR_INDEX_LIST: {
-		struct kvm_msr_list __user *user_msr_list = argp;
-		struct kvm_msr_list msr_list;
-		unsigned n;
-
-		r = -EFAULT;
-		if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list))
-			goto out;
-		n = msr_list.nmsrs;
-		msr_list.nmsrs = num_msrs_to_save + ARRAY_SIZE(emulated_msrs);
-		if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list))
-			goto out;
-		r = -E2BIG;
-		if (n < num_msrs_to_save)
-			goto out;
-		r = -EFAULT;
-		if (copy_to_user(user_msr_list->indices, &msrs_to_save,
-				 num_msrs_to_save * sizeof(u32)))
-			goto out;
-		if (copy_to_user(user_msr_list->indices
-				 + num_msrs_to_save * sizeof(u32),
-				 &emulated_msrs,
-				 ARRAY_SIZE(emulated_msrs) * sizeof(u32)))
-			goto out;
-		r = 0;
-		break;
-	}
-	case KVM_CHECK_EXTENSION: {
-		int ext = (long)argp;
-
-		switch (ext) {
-		case KVM_CAP_IRQCHIP:
-		case KVM_CAP_HLT:
-			r = 1;
-			break;
-		default:
-			r = 0;
-			break;
-		}
-		break;
-	}
-	case KVM_GET_VCPU_MMAP_SIZE:
-		r = -EINVAL;
-		if (arg)
-			goto out;
-		r = 2 * PAGE_SIZE;
-		break;
-	default:
-		;
-	}
-out:
-	return r;
-}
-
-static struct file_operations kvm_chardev_ops = {
-	.unlocked_ioctl = kvm_dev_ioctl,
-	.compat_ioctl   = kvm_dev_ioctl,
-};
-
-static struct miscdevice kvm_dev = {
-	KVM_MINOR,
-	"kvm",
-	&kvm_chardev_ops,
-};
-
-/*
- * Make sure that a cpu that is being hot-unplugged does not have any vcpus
- * cached on it.
- */
-static void decache_vcpus_on_cpu(int cpu)
-{
-	struct kvm *vm;
-	struct kvm_vcpu *vcpu;
-	int i;
-
-	spin_lock(&kvm_lock);
-	list_for_each_entry(vm, &vm_list, vm_list)
-		for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-			vcpu = vm->vcpus[i];
-			if (!vcpu)
-				continue;
-			/*
-			 * If the vcpu is locked, then it is running on some
-			 * other cpu and therefore it is not cached on the
-			 * cpu in question.
-			 *
-			 * If it's not locked, check the last cpu it executed
-			 * on.
-			 */
-			if (mutex_trylock(&vcpu->mutex)) {
-				if (vcpu->cpu == cpu) {
-					kvm_x86_ops->vcpu_decache(vcpu);
-					vcpu->cpu = -1;
-				}
-				mutex_unlock(&vcpu->mutex);
-			}
-		}
-	spin_unlock(&kvm_lock);
-}
-
-static void hardware_enable(void *junk)
-{
-	int cpu = raw_smp_processor_id();
-
-	if (cpu_isset(cpu, cpus_hardware_enabled))
-		return;
-	cpu_set(cpu, cpus_hardware_enabled);
-	kvm_x86_ops->hardware_enable(NULL);
-}
-
-static void hardware_disable(void *junk)
-{
-	int cpu = raw_smp_processor_id();
-
-	if (!cpu_isset(cpu, cpus_hardware_enabled))
-		return;
-	cpu_clear(cpu, cpus_hardware_enabled);
-	decache_vcpus_on_cpu(cpu);
-	kvm_x86_ops->hardware_disable(NULL);
-}
-
-static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
-			   void *v)
-{
-	int cpu = (long)v;
-
-	switch (val) {
-	case CPU_DYING:
-	case CPU_DYING_FROZEN:
-		printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
-		       cpu);
-		hardware_disable(NULL);
-		break;
-	case CPU_UP_CANCELED:
-	case CPU_UP_CANCELED_FROZEN:
-		printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
-		       cpu);
-		smp_call_function_single(cpu, hardware_disable, NULL, 0, 1);
-		break;
-	case CPU_ONLINE:
-	case CPU_ONLINE_FROZEN:
-		printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
-		       cpu);
-		smp_call_function_single(cpu, hardware_enable, NULL, 0, 1);
-		break;
-	}
-	return NOTIFY_OK;
-}
-
-static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
-                       void *v)
-{
-	if (val == SYS_RESTART) {
-		/*
-		 * Some (well, at least mine) BIOSes hang on reboot if
-		 * in vmx root mode.
-		 */
-		printk(KERN_INFO "kvm: exiting hardware virtualization\n");
-		on_each_cpu(hardware_disable, NULL, 0, 1);
-	}
-	return NOTIFY_OK;
-}
-
-static struct notifier_block kvm_reboot_notifier = {
-	.notifier_call = kvm_reboot,
-	.priority = 0,
-};
-
-void kvm_io_bus_init(struct kvm_io_bus *bus)
-{
-	memset(bus, 0, sizeof(*bus));
-}
-
-void kvm_io_bus_destroy(struct kvm_io_bus *bus)
-{
-	int i;
-
-	for (i = 0; i < bus->dev_count; i++) {
-		struct kvm_io_device *pos = bus->devs[i];
-
-		kvm_iodevice_destructor(pos);
-	}
-}
-
-struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr)
-{
-	int i;
-
-	for (i = 0; i < bus->dev_count; i++) {
-		struct kvm_io_device *pos = bus->devs[i];
-
-		if (pos->in_range(pos, addr))
-			return pos;
-	}
-
-	return NULL;
-}
-
-void kvm_io_bus_register_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev)
-{
-	BUG_ON(bus->dev_count > (NR_IOBUS_DEVS-1));
-
-	bus->devs[bus->dev_count++] = dev;
-}
-
-static struct notifier_block kvm_cpu_notifier = {
-	.notifier_call = kvm_cpu_hotplug,
-	.priority = 20, /* must be > scheduler priority */
-};
-
-static u64 stat_get(void *_offset)
-{
-	unsigned offset = (long)_offset;
-	u64 total = 0;
-	struct kvm *kvm;
-	struct kvm_vcpu *vcpu;
-	int i;
-
-	spin_lock(&kvm_lock);
-	list_for_each_entry(kvm, &vm_list, vm_list)
-		for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-			vcpu = kvm->vcpus[i];
-			if (vcpu)
-				total += *(u32 *)((void *)vcpu + offset);
-		}
-	spin_unlock(&kvm_lock);
-	return total;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, NULL, "%llu\n");
-
-static __init void kvm_init_debug(void)
-{
-	struct kvm_stats_debugfs_item *p;
-
-	debugfs_dir = debugfs_create_dir("kvm", NULL);
-	for (p = debugfs_entries; p->name; ++p)
-		p->dentry = debugfs_create_file(p->name, 0444, debugfs_dir,
-						(void *)(long)p->offset,
-						&stat_fops);
-}
-
-static void kvm_exit_debug(void)
-{
-	struct kvm_stats_debugfs_item *p;
-
-	for (p = debugfs_entries; p->name; ++p)
-		debugfs_remove(p->dentry);
-	debugfs_remove(debugfs_dir);
-}
-
-static int kvm_suspend(struct sys_device *dev, pm_message_t state)
-{
-	hardware_disable(NULL);
-	return 0;
-}
-
-static int kvm_resume(struct sys_device *dev)
-{
-	hardware_enable(NULL);
-	return 0;
-}
-
-static struct sysdev_class kvm_sysdev_class = {
-	set_kset_name("kvm"),
-	.suspend = kvm_suspend,
-	.resume = kvm_resume,
-};
-
-static struct sys_device kvm_sysdev = {
-	.id = 0,
-	.cls = &kvm_sysdev_class,
-};
-
-hpa_t bad_page_address;
-
-static inline
-struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn)
-{
-	return container_of(pn, struct kvm_vcpu, preempt_notifier);
-}
-
-static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
-{
-	struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
-
-	kvm_x86_ops->vcpu_load(vcpu, cpu);
-}
-
-static void kvm_sched_out(struct preempt_notifier *pn,
-			  struct task_struct *next)
-{
-	struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
-
-	kvm_x86_ops->vcpu_put(vcpu);
-}
-
-int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size,
-		  struct module *module)
-{
-	int r;
-	int cpu;
-
-	if (kvm_x86_ops) {
-		printk(KERN_ERR "kvm: already loaded the other module\n");
-		return -EEXIST;
-	}
-
-	if (!ops->cpu_has_kvm_support()) {
-		printk(KERN_ERR "kvm: no hardware support\n");
-		return -EOPNOTSUPP;
-	}
-	if (ops->disabled_by_bios()) {
-		printk(KERN_ERR "kvm: disabled by bios\n");
-		return -EOPNOTSUPP;
-	}
-
-	kvm_x86_ops = ops;
-
-	r = kvm_x86_ops->hardware_setup();
-	if (r < 0)
-		goto out;
-
-	for_each_online_cpu(cpu) {
-		smp_call_function_single(cpu,
-				kvm_x86_ops->check_processor_compatibility,
-				&r, 0, 1);
-		if (r < 0)
-			goto out_free_0;
-	}
-
-	on_each_cpu(hardware_enable, NULL, 0, 1);
-	r = register_cpu_notifier(&kvm_cpu_notifier);
-	if (r)
-		goto out_free_1;
-	register_reboot_notifier(&kvm_reboot_notifier);
-
-	r = sysdev_class_register(&kvm_sysdev_class);
-	if (r)
-		goto out_free_2;
-
-	r = sysdev_register(&kvm_sysdev);
-	if (r)
-		goto out_free_3;
-
-	/* A kmem cache lets us meet the alignment requirements of fx_save. */
-	kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size,
-					   __alignof__(struct kvm_vcpu), 0, 0);
-	if (!kvm_vcpu_cache) {
-		r = -ENOMEM;
-		goto out_free_4;
-	}
-
-	kvm_chardev_ops.owner = module;
-
-	r = misc_register(&kvm_dev);
-	if (r) {
-		printk (KERN_ERR "kvm: misc device register failed\n");
-		goto out_free;
-	}
-
-	kvm_preempt_ops.sched_in = kvm_sched_in;
-	kvm_preempt_ops.sched_out = kvm_sched_out;
-
-	return r;
-
-out_free:
-	kmem_cache_destroy(kvm_vcpu_cache);
-out_free_4:
-	sysdev_unregister(&kvm_sysdev);
-out_free_3:
-	sysdev_class_unregister(&kvm_sysdev_class);
-out_free_2:
-	unregister_reboot_notifier(&kvm_reboot_notifier);
-	unregister_cpu_notifier(&kvm_cpu_notifier);
-out_free_1:
-	on_each_cpu(hardware_disable, NULL, 0, 1);
-out_free_0:
-	kvm_x86_ops->hardware_unsetup();
-out:
-	kvm_x86_ops = NULL;
-	return r;
-}
-
-void kvm_exit_x86(void)
-{
-	misc_deregister(&kvm_dev);
-	kmem_cache_destroy(kvm_vcpu_cache);
-	sysdev_unregister(&kvm_sysdev);
-	sysdev_class_unregister(&kvm_sysdev_class);
-	unregister_reboot_notifier(&kvm_reboot_notifier);
-	unregister_cpu_notifier(&kvm_cpu_notifier);
-	on_each_cpu(hardware_disable, NULL, 0, 1);
-	kvm_x86_ops->hardware_unsetup();
-	kvm_x86_ops = NULL;
-}
-
-static __init int kvm_init(void)
-{
-	static struct page *bad_page;
-	int r;
-
-	r = kvm_mmu_module_init();
-	if (r)
-		goto out4;
-
-	kvm_init_debug();
-
-	kvm_init_msr_list();
-
-	if ((bad_page = alloc_page(GFP_KERNEL)) == NULL) {
-		r = -ENOMEM;
-		goto out;
-	}
-
-	bad_page_address = page_to_pfn(bad_page) << PAGE_SHIFT;
-	memset(__va(bad_page_address), 0, PAGE_SIZE);
-
-	return 0;
-
-out:
-	kvm_exit_debug();
-	kvm_mmu_module_exit();
-out4:
-	return r;
-}
-
-static __exit void kvm_exit(void)
-{
-	kvm_exit_debug();
-	__free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT));
-	kvm_mmu_module_exit();
-}
-
-module_init(kvm_init)
-module_exit(kvm_exit)
-
-EXPORT_SYMBOL_GPL(kvm_init_x86);
-EXPORT_SYMBOL_GPL(kvm_exit_x86);
diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h
deleted file mode 100644
index a0e415daef5b..000000000000
--- a/drivers/kvm/kvm_svm.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef __KVM_SVM_H
-#define __KVM_SVM_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <asm/msr.h>
-
-#include "svm.h"
-#include "kvm.h"
-
-static const u32 host_save_user_msrs[] = {
-#ifdef CONFIG_X86_64
-	MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
-	MSR_FS_BASE,
-#endif
-	MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
-};
-
-#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
-#define NUM_DB_REGS 4
-
-struct kvm_vcpu;
-
-struct vcpu_svm {
-	struct kvm_vcpu vcpu;
-	struct vmcb *vmcb;
-	unsigned long vmcb_pa;
-	struct svm_cpu_data *svm_data;
-	uint64_t asid_generation;
-
-	unsigned long db_regs[NUM_DB_REGS];
-
-	u64 next_rip;
-
-	u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
-	u64 host_gs_base;
-	unsigned long host_cr2;
-	unsigned long host_db_regs[NUM_DB_REGS];
-	unsigned long host_dr6;
-	unsigned long host_dr7;
-};
-
-#endif
-
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c
deleted file mode 100644
index 238fcad3cece..000000000000
--- a/drivers/kvm/lapic.c
+++ /dev/null
@@ -1,1080 +0,0 @@
-
-/*
- * Local APIC virtualization
- *
- * Copyright (C) 2006 Qumranet, Inc.
- * Copyright (C) 2007 Novell
- * Copyright (C) 2007 Intel
- *
- * Authors:
- *   Dor Laor <dor.laor@qumranet.com>
- *   Gregory Haskins <ghaskins@novell.com>
- *   Yaozu (Eddie) Dong <eddie.dong@intel.com>
- *
- * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- */
-
-#include "kvm.h"
-#include <linux/kvm.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/smp.h>
-#include <linux/hrtimer.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <asm/processor.h>
-#include <asm/msr.h>
-#include <asm/page.h>
-#include <asm/current.h>
-#include <asm/apicdef.h>
-#include <asm/atomic.h>
-#include <asm/div64.h>
-#include "irq.h"
-
-#define PRId64 "d"
-#define PRIx64 "llx"
-#define PRIu64 "u"
-#define PRIo64 "o"
-
-#define APIC_BUS_CYCLE_NS 1
-
-/* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
-#define apic_debug(fmt, arg...)
-
-#define APIC_LVT_NUM			6
-/* 14 is the version for Xeon and Pentium 8.4.8*/
-#define APIC_VERSION			(0x14UL | ((APIC_LVT_NUM - 1) << 16))
-#define LAPIC_MMIO_LENGTH		(1 << 12)
-/* followed define is not in apicdef.h */
-#define APIC_SHORT_MASK			0xc0000
-#define APIC_DEST_NOSHORT		0x0
-#define APIC_DEST_MASK			0x800
-#define MAX_APIC_VECTOR			256
-
-#define VEC_POS(v) ((v) & (32 - 1))
-#define REG_POS(v) (((v) >> 5) << 4)
-static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off)
-{
-	return *((u32 *) (apic->regs + reg_off));
-}
-
-static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val)
-{
-	*((u32 *) (apic->regs + reg_off)) = val;
-}
-
-static inline int apic_test_and_set_vector(int vec, void *bitmap)
-{
-	return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
-}
-
-static inline int apic_test_and_clear_vector(int vec, void *bitmap)
-{
-	return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
-}
-
-static inline void apic_set_vector(int vec, void *bitmap)
-{
-	set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
-}
-
-static inline void apic_clear_vector(int vec, void *bitmap)
-{
-	clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
-}
-
-static inline int apic_hw_enabled(struct kvm_lapic *apic)
-{
-	return (apic)->vcpu->apic_base & MSR_IA32_APICBASE_ENABLE;
-}
-
-static inline int  apic_sw_enabled(struct kvm_lapic *apic)
-{
-	return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED;
-}
-
-static inline int apic_enabled(struct kvm_lapic *apic)
-{
-	return apic_sw_enabled(apic) &&	apic_hw_enabled(apic);
-}
-
-#define LVT_MASK	\
-	(APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK)
-
-#define LINT_MASK	\
-	(LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
-	 APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
-
-static inline int kvm_apic_id(struct kvm_lapic *apic)
-{
-	return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
-}
-
-static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type)
-{
-	return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
-}
-
-static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type)
-{
-	return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
-}
-
-static inline int apic_lvtt_period(struct kvm_lapic *apic)
-{
-	return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC;
-}
-
-static unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
-	LVT_MASK | APIC_LVT_TIMER_PERIODIC,	/* LVTT */
-	LVT_MASK | APIC_MODE_MASK,	/* LVTTHMR */
-	LVT_MASK | APIC_MODE_MASK,	/* LVTPC */
-	LINT_MASK, LINT_MASK,	/* LVT0-1 */
-	LVT_MASK		/* LVTERR */
-};
-
-static int find_highest_vector(void *bitmap)
-{
-	u32 *word = bitmap;
-	int word_offset = MAX_APIC_VECTOR >> 5;
-
-	while ((word_offset != 0) && (word[(--word_offset) << 2] == 0))
-		continue;
-
-	if (likely(!word_offset && !word[0]))
-		return -1;
-	else
-		return fls(word[word_offset << 2]) - 1 + (word_offset << 5);
-}
-
-static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic)
-{
-	return apic_test_and_set_vector(vec, apic->regs + APIC_IRR);
-}
-
-static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
-{
-	apic_clear_vector(vec, apic->regs + APIC_IRR);
-}
-
-static inline int apic_find_highest_irr(struct kvm_lapic *apic)
-{
-	int result;
-
-	result = find_highest_vector(apic->regs + APIC_IRR);
-	ASSERT(result == -1 || result >= 16);
-
-	return result;
-}
-
-int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
-{
-	struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
-	int highest_irr;
-
-	if (!apic)
-		return 0;
-	highest_irr = apic_find_highest_irr(apic);
-
-	return highest_irr;
-}
-EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr);
-
-int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig)
-{
-	if (!apic_test_and_set_irr(vec, apic)) {
-		/* a new pending irq is set in IRR */
-		if (trig)
-			apic_set_vector(vec, apic->regs + APIC_TMR);
-		else
-			apic_clear_vector(vec, apic->regs + APIC_TMR);
-		kvm_vcpu_kick(apic->vcpu);
-		return 1;
-	}
-	return 0;
-}
-
-static inline int apic_find_highest_isr(struct kvm_lapic *apic)
-{
-	int result;
-
-	result = find_highest_vector(apic->regs + APIC_ISR);
-	ASSERT(result == -1 || result >= 16);
-
-	return result;
-}
-
-static void apic_update_ppr(struct kvm_lapic *apic)
-{
-	u32 tpr, isrv, ppr;
-	int isr;
-
-	tpr = apic_get_reg(apic, APIC_TASKPRI);
-	isr = apic_find_highest_isr(apic);
-	isrv = (isr != -1) ? isr : 0;
-
-	if ((tpr & 0xf0) >= (isrv & 0xf0))
-		ppr = tpr & 0xff;
-	else
-		ppr = isrv & 0xf0;
-
-	apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
-		   apic, ppr, isr, isrv);
-
-	apic_set_reg(apic, APIC_PROCPRI, ppr);
-}
-
-static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
-{
-	apic_set_reg(apic, APIC_TASKPRI, tpr);
-	apic_update_ppr(apic);
-}
-
-int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
-{
-	return kvm_apic_id(apic) == dest;
-}
-
-int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
-{
-	int result = 0;
-	u8 logical_id;
-
-	logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR));
-
-	switch (apic_get_reg(apic, APIC_DFR)) {
-	case APIC_DFR_FLAT:
-		if (logical_id & mda)
-			result = 1;
-		break;
-	case APIC_DFR_CLUSTER:
-		if (((logical_id >> 4) == (mda >> 0x4))
-		    && (logical_id & mda & 0xf))
-			result = 1;
-		break;
-	default:
-		printk(KERN_WARNING "Bad DFR vcpu %d: %08x\n",
-		       apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR));
-		break;
-	}
-
-	return result;
-}
-
-static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
-			   int short_hand, int dest, int dest_mode)
-{
-	int result = 0;
-	struct kvm_lapic *target = vcpu->apic;
-
-	apic_debug("target %p, source %p, dest 0x%x, "
-		   "dest_mode 0x%x, short_hand 0x%x",
-		   target, source, dest, dest_mode, short_hand);
-
-	ASSERT(!target);
-	switch (short_hand) {
-	case APIC_DEST_NOSHORT:
-		if (dest_mode == 0) {
-			/* Physical mode. */
-			if ((dest == 0xFF) || (dest == kvm_apic_id(target)))
-				result = 1;
-		} else
-			/* Logical mode. */
-			result = kvm_apic_match_logical_addr(target, dest);
-		break;
-	case APIC_DEST_SELF:
-		if (target == source)
-			result = 1;
-		break;
-	case APIC_DEST_ALLINC:
-		result = 1;
-		break;
-	case APIC_DEST_ALLBUT:
-		if (target != source)
-			result = 1;
-		break;
-	default:
-		printk(KERN_WARNING "Bad dest shorthand value %x\n",
-		       short_hand);
-		break;
-	}
-
-	return result;
-}
-
-/*
- * Add a pending IRQ into lapic.
- * Return 1 if successfully added and 0 if discarded.
- */
-static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
-			     int vector, int level, int trig_mode)
-{
-	int orig_irr, result = 0;
-	struct kvm_vcpu *vcpu = apic->vcpu;
-
-	switch (delivery_mode) {
-	case APIC_DM_FIXED:
-	case APIC_DM_LOWEST:
-		/* FIXME add logic for vcpu on reset */
-		if (unlikely(!apic_enabled(apic)))
-			break;
-
-		orig_irr = apic_test_and_set_irr(vector, apic);
-		if (orig_irr && trig_mode) {
-			apic_debug("level trig mode repeatedly for vector %d",
-				   vector);
-			break;
-		}
-
-		if (trig_mode) {
-			apic_debug("level trig mode for vector %d", vector);
-			apic_set_vector(vector, apic->regs + APIC_TMR);
-		} else
-			apic_clear_vector(vector, apic->regs + APIC_TMR);
-
-		if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE)
-			kvm_vcpu_kick(vcpu);
-		else if (vcpu->mp_state == VCPU_MP_STATE_HALTED) {
-			vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
-			if (waitqueue_active(&vcpu->wq))
-				wake_up_interruptible(&vcpu->wq);
-		}
-
-		result = (orig_irr == 0);
-		break;
-
-	case APIC_DM_REMRD:
-		printk(KERN_DEBUG "Ignoring delivery mode 3\n");
-		break;
-
-	case APIC_DM_SMI:
-		printk(KERN_DEBUG "Ignoring guest SMI\n");
-		break;
-	case APIC_DM_NMI:
-		printk(KERN_DEBUG "Ignoring guest NMI\n");
-		break;
-
-	case APIC_DM_INIT:
-		if (level) {
-			if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE)
-				printk(KERN_DEBUG
-				       "INIT on a runnable vcpu %d\n",
-				       vcpu->vcpu_id);
-			vcpu->mp_state = VCPU_MP_STATE_INIT_RECEIVED;
-			kvm_vcpu_kick(vcpu);
-		} else {
-			printk(KERN_DEBUG
-			       "Ignoring de-assert INIT to vcpu %d\n",
-			       vcpu->vcpu_id);
-		}
-
-		break;
-
-	case APIC_DM_STARTUP:
-		printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n",
-		       vcpu->vcpu_id, vector);
-		if (vcpu->mp_state == VCPU_MP_STATE_INIT_RECEIVED) {
-			vcpu->sipi_vector = vector;
-			vcpu->mp_state = VCPU_MP_STATE_SIPI_RECEIVED;
-			if (waitqueue_active(&vcpu->wq))
-				wake_up_interruptible(&vcpu->wq);
-		}
-		break;
-
-	default:
-		printk(KERN_ERR "TODO: unsupported delivery mode %x\n",
-		       delivery_mode);
-		break;
-	}
-	return result;
-}
-
-struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
-				       unsigned long bitmap)
-{
-	int vcpu_id;
-	int last;
-	int next;
-	struct kvm_lapic *apic;
-
-	last = kvm->round_robin_prev_vcpu;
-	next = last;
-
-	do {
-		if (++next == KVM_MAX_VCPUS)
-			next = 0;
-		if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap))
-			continue;
-		apic = kvm->vcpus[next]->apic;
-		if (apic && apic_enabled(apic))
-			break;
-		apic = NULL;
-	} while (next != last);
-	kvm->round_robin_prev_vcpu = next;
-
-	if (!apic) {
-		vcpu_id = ffs(bitmap) - 1;
-		if (vcpu_id < 0) {
-			vcpu_id = 0;
-			printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n");
-		}
-		apic = kvm->vcpus[vcpu_id]->apic;
-	}
-
-	return apic;
-}
-
-static void apic_set_eoi(struct kvm_lapic *apic)
-{
-	int vector = apic_find_highest_isr(apic);
-
-	/*
-	 * Not every write EOI will has corresponding ISR,
-	 * one example is when Kernel check timer on setup_IO_APIC
-	 */
-	if (vector == -1)
-		return;
-
-	apic_clear_vector(vector, apic->regs + APIC_ISR);
-	apic_update_ppr(apic);
-
-	if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR))
-		kvm_ioapic_update_eoi(apic->vcpu->kvm, vector);
-}
-
-static void apic_send_ipi(struct kvm_lapic *apic)
-{
-	u32 icr_low = apic_get_reg(apic, APIC_ICR);
-	u32 icr_high = apic_get_reg(apic, APIC_ICR2);
-
-	unsigned int dest = GET_APIC_DEST_FIELD(icr_high);
-	unsigned int short_hand = icr_low & APIC_SHORT_MASK;
-	unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG;
-	unsigned int level = icr_low & APIC_INT_ASSERT;
-	unsigned int dest_mode = icr_low & APIC_DEST_MASK;
-	unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
-	unsigned int vector = icr_low & APIC_VECTOR_MASK;
-
-	struct kvm_lapic *target;
-	struct kvm_vcpu *vcpu;
-	unsigned long lpr_map = 0;
-	int i;
-
-	apic_debug("icr_high 0x%x, icr_low 0x%x, "
-		   "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
-		   "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
-		   icr_high, icr_low, short_hand, dest,
-		   trig_mode, level, dest_mode, delivery_mode, vector);
-
-	for (i = 0; i < KVM_MAX_VCPUS; i++) {
-		vcpu = apic->vcpu->kvm->vcpus[i];
-		if (!vcpu)
-			continue;
-
-		if (vcpu->apic &&
-		    apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) {
-			if (delivery_mode == APIC_DM_LOWEST)
-				set_bit(vcpu->vcpu_id, &lpr_map);
-			else
-				__apic_accept_irq(vcpu->apic, delivery_mode,
-						  vector, level, trig_mode);
-		}
-	}
-
-	if (delivery_mode == APIC_DM_LOWEST) {
-		target = kvm_apic_round_robin(vcpu->kvm, vector, lpr_map);
-		if (target != NULL)
-			__apic_accept_irq(target, delivery_mode,
-					  vector, level, trig_mode);
-	}
-}
-
-static u32 apic_get_tmcct(struct kvm_lapic *apic)
-{
-	u64 counter_passed;
-	ktime_t passed, now;
-	u32 tmcct;
-
-	ASSERT(apic != NULL);
-
-	now = apic->timer.dev.base->get_time();
-	tmcct = apic_get_reg(apic, APIC_TMICT);
-
-	/* if initial count is 0, current count should also be 0 */
-	if (tmcct == 0)
-		return 0;
-
-	if (unlikely(ktime_to_ns(now) <=
-		ktime_to_ns(apic->timer.last_update))) {
-		/* Wrap around */
-		passed = ktime_add(( {
-				    (ktime_t) {
-				    .tv64 = KTIME_MAX -
-				    (apic->timer.last_update).tv64}; }
-				   ), now);
-		apic_debug("time elapsed\n");
-	} else
-		passed = ktime_sub(now, apic->timer.last_update);
-
-	counter_passed = div64_64(ktime_to_ns(passed),
-				  (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
-
-	if (counter_passed > tmcct) {
-		if (unlikely(!apic_lvtt_period(apic))) {
-			/* one-shot timers stick at 0 until reset */
-			tmcct = 0;
-		} else {
-			/*
-			 * periodic timers reset to APIC_TMICT when they
-			 * hit 0. The while loop simulates this happening N
-			 * times. (counter_passed %= tmcct) would also work,
-			 * but might be slower or not work on 32-bit??
-			 */
-			while (counter_passed > tmcct)
-				counter_passed -= tmcct;
-			tmcct -= counter_passed;
-		}
-	} else {
-		tmcct -= counter_passed;
-	}
-
-	return tmcct;
-}
-
-static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
-{
-	u32 val = 0;
-
-	if (offset >= LAPIC_MMIO_LENGTH)
-		return 0;
-
-	switch (offset) {
-	case APIC_ARBPRI:
-		printk(KERN_WARNING "Access APIC ARBPRI register "
-		       "which is for P6\n");
-		break;
-
-	case APIC_TMCCT:	/* Timer CCR */
-		val = apic_get_tmcct(apic);
-		break;
-
-	default:
-		apic_update_ppr(apic);
-		val = apic_get_reg(apic, offset);
-		break;
-	}
-
-	return val;
-}
-
-static void apic_mmio_read(struct kvm_io_device *this,
-			   gpa_t address, int len, void *data)
-{
-	struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
-	unsigned int offset = address - apic->base_address;
-	unsigned char alignment = offset & 0xf;
-	u32 result;
-
-	if ((alignment + len) > 4) {
-		printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d",
-		       (unsigned long)address, len);
-		return;
-	}
-	result = __apic_read(apic, offset & ~0xf);
-
-	switch (len) {
-	case 1:
-	case 2:
-	case 4:
-		memcpy(data, (char *)&result + alignment, len);
-		break;
-	default:
-		printk(KERN_ERR "Local APIC read with len = %x, "
-		       "should be 1,2, or 4 instead\n", len);
-		break;
-	}
-}
-
-static void update_divide_count(struct kvm_lapic *apic)
-{
-	u32 tmp1, tmp2, tdcr;
-
-	tdcr = apic_get_reg(apic, APIC_TDCR);
-	tmp1 = tdcr & 0xf;
-	tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
-	apic->timer.divide_count = 0x1 << (tmp2 & 0x7);
-
-	apic_debug("timer divide count is 0x%x\n",
-				   apic->timer.divide_count);
-}
-
-static void start_apic_timer(struct kvm_lapic *apic)
-{
-	ktime_t now = apic->timer.dev.base->get_time();
-
-	apic->timer.last_update = now;
-
-	apic->timer.period = apic_get_reg(apic, APIC_TMICT) *
-		    APIC_BUS_CYCLE_NS * apic->timer.divide_count;
-	atomic_set(&apic->timer.pending, 0);
-	hrtimer_start(&apic->timer.dev,
-		      ktime_add_ns(now, apic->timer.period),
-		      HRTIMER_MODE_ABS);
-
-	apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
-			   PRIx64 ", "
-			   "timer initial count 0x%x, period %lldns, "
-			   "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__,
-			   APIC_BUS_CYCLE_NS, ktime_to_ns(now),
-			   apic_get_reg(apic, APIC_TMICT),
-			   apic->timer.period,
-			   ktime_to_ns(ktime_add_ns(now,
-					apic->timer.period)));
-}
-
-static void apic_mmio_write(struct kvm_io_device *this,
-			    gpa_t address, int len, const void *data)
-{
-	struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
-	unsigned int offset = address - apic->base_address;
-	unsigned char alignment = offset & 0xf;
-	u32 val;
-
-	/*
-	 * APIC register must be aligned on 128-bits boundary.
-	 * 32/64/128 bits registers must be accessed thru 32 bits.
-	 * Refer SDM 8.4.1
-	 */
-	if (len != 4 || alignment) {
-		if (printk_ratelimit())
-			printk(KERN_ERR "apic write: bad size=%d %lx\n",
-			       len, (long)address);
-		return;
-	}
-
-	val = *(u32 *) data;
-
-	/* too common printing */
-	if (offset != APIC_EOI)
-		apic_debug("%s: offset 0x%x with length 0x%x, and value is "
-			   "0x%x\n", __FUNCTION__, offset, len, val);
-
-	offset &= 0xff0;
-
-	switch (offset) {
-	case APIC_ID:		/* Local APIC ID */
-		apic_set_reg(apic, APIC_ID, val);
-		break;
-
-	case APIC_TASKPRI:
-		apic_set_tpr(apic, val & 0xff);
-		break;
-
-	case APIC_EOI:
-		apic_set_eoi(apic);
-		break;
-
-	case APIC_LDR:
-		apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK);
-		break;
-
-	case APIC_DFR:
-		apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
-		break;
-
-	case APIC_SPIV:
-		apic_set_reg(apic, APIC_SPIV, val & 0x3ff);
-		if (!(val & APIC_SPIV_APIC_ENABLED)) {
-			int i;
-			u32 lvt_val;
-
-			for (i = 0; i < APIC_LVT_NUM; i++) {
-				lvt_val = apic_get_reg(apic,
-						       APIC_LVTT + 0x10 * i);
-				apic_set_reg(apic, APIC_LVTT + 0x10 * i,
-					     lvt_val | APIC_LVT_MASKED);
-			}
-			atomic_set(&apic->timer.pending, 0);
-
-		}
-		break;
-
-	case APIC_ICR:
-		/* No delay here, so we always clear the pending bit */
-		apic_set_reg(apic, APIC_ICR, val & ~(1 << 12));
-		apic_send_ipi(apic);
-		break;
-
-	case APIC_ICR2:
-		apic_set_reg(apic, APIC_ICR2, val & 0xff000000);
-		break;
-
-	case APIC_LVTT:
-	case APIC_LVTTHMR:
-	case APIC_LVTPC:
-	case APIC_LVT0:
-	case APIC_LVT1:
-	case APIC_LVTERR:
-		/* TODO: Check vector */
-		if (!apic_sw_enabled(apic))
-			val |= APIC_LVT_MASKED;
-
-		val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4];
-		apic_set_reg(apic, offset, val);
-
-		break;
-
-	case APIC_TMICT:
-		hrtimer_cancel(&apic->timer.dev);
-		apic_set_reg(apic, APIC_TMICT, val);
-		start_apic_timer(apic);
-		return;
-
-	case APIC_TDCR:
-		if (val & 4)
-			printk(KERN_ERR "KVM_WRITE:TDCR %x\n", val);
-		apic_set_reg(apic, APIC_TDCR, val);
-		update_divide_count(apic);
-		break;
-
-	default:
-		apic_debug("Local APIC Write to read-only register %x\n",
-			   offset);
-		break;
-	}
-
-}
-
-static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr)
-{
-	struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
-	int ret = 0;
-
-
-	if (apic_hw_enabled(apic) &&
-	    (addr >= apic->base_address) &&
-	    (addr < (apic->base_address + LAPIC_MMIO_LENGTH)))
-		ret = 1;
-
-	return ret;
-}
-
-void kvm_free_apic(struct kvm_lapic *apic)
-{
-	if (!apic)
-		return;
-
-	hrtimer_cancel(&apic->timer.dev);
-
-	if (apic->regs_page) {
-		__free_page(apic->regs_page);
-		apic->regs_page = 0;
-	}
-
-	kfree(apic);
-}
-
-/*
- *----------------------------------------------------------------------
- * LAPIC interface
- *----------------------------------------------------------------------
- */
-
-void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
-{
-	struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
-
-	if (!apic)
-		return;
-	apic_set_tpr(apic, ((cr8 & 0x0f) << 4));
-}
-
-u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
-{
-	struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
-	u64 tpr;
-
-	if (!apic)
-		return 0;
-	tpr = (u64) apic_get_reg(apic, APIC_TASKPRI);
-
-	return (tpr & 0xf0) >> 4;
-}
-EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8);
-
-void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
-{
-	struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
-
-	if (!apic) {
-		value |= MSR_IA32_APICBASE_BSP;
-		vcpu->apic_base = value;
-		return;
-	}
-	if (apic->vcpu->vcpu_id)
-		value &= ~MSR_IA32_APICBASE_BSP;
-
-	vcpu->apic_base = value;
-	apic->base_address = apic->vcpu->apic_base &
-			     MSR_IA32_APICBASE_BASE;
-
-	/* with FSB delivery interrupt, we can restart APIC functionality */
-	apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is "
-		   "0x%lx.\n", apic->apic_base, apic->base_address);
-
-}
-
-u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu)
-{
-	return vcpu->apic_base;
-}
-EXPORT_SYMBOL_GPL(kvm_lapic_get_base);
-
-void kvm_lapic_reset(struct kvm_vcpu *vcpu)
-{
-	struct kvm_lapic *apic;
-	int i;
-
-	apic_debug("%s\n", __FUNCTION__);
-
-	ASSERT(vcpu);
-	apic = vcpu->apic;
-	ASSERT(apic != NULL);
-
-	/* Stop the timer in case it's a reset to an active apic */
-	hrtimer_cancel(&apic->timer.dev);
-
-	apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24);
-	apic_set_reg(apic, APIC_LVR, APIC_VERSION);
-
-	for (i = 0; i < APIC_LVT_NUM; i++)
-		apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
-	apic_set_reg(apic, APIC_LVT0,
-		     SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
-
-	apic_set_reg(apic, APIC_DFR, 0xffffffffU);
-	apic_set_reg(apic, APIC_SPIV, 0xff);
-	apic_set_reg(apic, APIC_TASKPRI, 0);
-	apic_set_reg(apic, APIC_LDR, 0);
-	apic_set_reg(apic, APIC_ESR, 0);
-	apic_set_reg(apic, APIC_ICR, 0);
-	apic_set_reg(apic, APIC_ICR2, 0);
-	apic_set_reg(apic, APIC_TDCR, 0);
-	apic_set_reg(apic, APIC_TMICT, 0);
-	for (i = 0; i < 8; i++) {
-		apic_set_reg(apic, APIC_IRR + 0x10 * i, 0);
-		apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
-		apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
-	}
-	update_divide_count(apic);
-	atomic_set(&apic->timer.pending, 0);
-	if (vcpu->vcpu_id == 0)
-		vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
-	apic_update_ppr(apic);
-
-	apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr="
-		   "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__,
-		   vcpu, kvm_apic_id(apic),
-		   vcpu->apic_base, apic->base_address);
-}
-EXPORT_SYMBOL_GPL(kvm_lapic_reset);
-
-int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
-{
-	struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
-	int ret = 0;
-
-	if (!apic)
-		return 0;
-	ret = apic_enabled(apic);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
-
-/*
- *----------------------------------------------------------------------
- * timer interface
- *----------------------------------------------------------------------
- */
-
-/* TODO: make sure __apic_timer_fn runs in current pCPU */
-static int __apic_timer_fn(struct kvm_lapic *apic)
-{
-	int result = 0;
-	wait_queue_head_t *q = &apic->vcpu->wq;
-
-	atomic_inc(&apic->timer.pending);
-	if (waitqueue_active(q))
-	{
-		apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
-		wake_up_interruptible(q);
-	}
-	if (apic_lvtt_period(apic)) {
-		result = 1;
-		apic->timer.dev.expires = ktime_add_ns(
-					apic->timer.dev.expires,
-					apic->timer.period);
-	}
-	return result;
-}
-
-static int __inject_apic_timer_irq(struct kvm_lapic *apic)
-{
-	int vector;
-
-	vector = apic_lvt_vector(apic, APIC_LVTT);
-	return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0);
-}
-
-static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
-{
-	struct kvm_lapic *apic;
-	int restart_timer = 0;
-
-	apic = container_of(data, struct kvm_lapic, timer.dev);
-
-	restart_timer = __apic_timer_fn(apic);
-
-	if (restart_timer)
-		return HRTIMER_RESTART;
-	else
-		return HRTIMER_NORESTART;
-}
-
-int kvm_create_lapic(struct kvm_vcpu *vcpu)
-{
-	struct kvm_lapic *apic;
-
-	ASSERT(vcpu != NULL);
-	apic_debug("apic_init %d\n", vcpu->vcpu_id);
-
-	apic = kzalloc(sizeof(*apic), GFP_KERNEL);
-	if (!apic)
-		goto nomem;
-
-	vcpu->apic = apic;
-
-	apic->regs_page = alloc_page(GFP_KERNEL);
-	if (apic->regs_page == NULL) {
-		printk(KERN_ERR "malloc apic regs error for vcpu %x\n",
-		       vcpu->vcpu_id);
-		goto nomem;
-	}
-	apic->regs = page_address(apic->regs_page);
-	memset(apic->regs, 0, PAGE_SIZE);
-	apic->vcpu = vcpu;
-
-	hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
-	apic->timer.dev.function = apic_timer_fn;
-	apic->base_address = APIC_DEFAULT_PHYS_BASE;
-	vcpu->apic_base = APIC_DEFAULT_PHYS_BASE;
-
-	kvm_lapic_reset(vcpu);
-	apic->dev.read = apic_mmio_read;
-	apic->dev.write = apic_mmio_write;
-	apic->dev.in_range = apic_mmio_range;
-	apic->dev.private = apic;
-
-	return 0;
-nomem:
-	kvm_free_apic(apic);
-	return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(kvm_create_lapic);
-
-int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
-{
-	struct kvm_lapic *apic = vcpu->apic;
-	int highest_irr;
-
-	if (!apic || !apic_enabled(apic))
-		return -1;
-
-	apic_update_ppr(apic);
-	highest_irr = apic_find_highest_irr(apic);
-	if ((highest_irr == -1) ||
-	    ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI)))
-		return -1;
-	return highest_irr;
-}
-
-int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
-{
-	u32 lvt0 = apic_get_reg(vcpu->apic, APIC_LVT0);
-	int r = 0;
-
-	if (vcpu->vcpu_id == 0) {
-		if (!apic_hw_enabled(vcpu->apic))
-			r = 1;
-		if ((lvt0 & APIC_LVT_MASKED) == 0 &&
-		    GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
-			r = 1;
-	}
-	return r;
-}
-
-void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
-{
-	struct kvm_lapic *apic = vcpu->apic;
-
-	if (apic && apic_lvt_enabled(apic, APIC_LVTT) &&
-		atomic_read(&apic->timer.pending) > 0) {
-		if (__inject_apic_timer_irq(apic))
-			atomic_dec(&apic->timer.pending);
-	}
-}
-
-void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
-{
-	struct kvm_lapic *apic = vcpu->apic;
-
-	if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec)
-		apic->timer.last_update = ktime_add_ns(
-				apic->timer.last_update,
-				apic->timer.period);
-}
-
-int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
-{
-	int vector = kvm_apic_has_interrupt(vcpu);
-	struct kvm_lapic *apic = vcpu->apic;
-
-	if (vector == -1)
-		return -1;
-
-	apic_set_vector(vector, apic->regs + APIC_ISR);
-	apic_update_ppr(apic);
-	apic_clear_irr(vector, apic);
-	return vector;
-}
-
-void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
-{
-	struct kvm_lapic *apic = vcpu->apic;
-
-	apic->base_address = vcpu->apic_base &
-			     MSR_IA32_APICBASE_BASE;
-	apic_set_reg(apic, APIC_LVR, APIC_VERSION);
-	apic_update_ppr(apic);
-	hrtimer_cancel(&apic->timer.dev);
-	update_divide_count(apic);
-	start_apic_timer(apic);
-}
-
-void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
-{
-	struct kvm_lapic *apic = vcpu->apic;
-	struct hrtimer *timer;
-
-	if (!apic)
-		return;
-
-	timer = &apic->timer.dev;
-	if (hrtimer_cancel(timer))
-		hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS);
-}
-EXPORT_SYMBOL_GPL(kvm_migrate_apic_timer);
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
deleted file mode 100644
index feb5ac986c5d..000000000000
--- a/drivers/kvm/mmu.c
+++ /dev/null
@@ -1,1498 +0,0 @@
-/*
- * Kernel-based Virtual Machine driver for Linux
- *
- * This module enables machines with Intel VT-x extensions to run virtual
- * machines without emulation or binary translation.
- *
- * MMU support
- *
- * Copyright (C) 2006 Qumranet, Inc.
- *
- * Authors:
- *   Yaniv Kamay  <yaniv@qumranet.com>
- *   Avi Kivity   <avi@qumranet.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "vmx.h"
-#include "kvm.h"
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/module.h>
-
-#include <asm/page.h>
-#include <asm/cmpxchg.h>
-
-#undef MMU_DEBUG
-
-#undef AUDIT
-
-#ifdef AUDIT
-static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg);
-#else
-static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {}
-#endif
-
-#ifdef MMU_DEBUG
-
-#define pgprintk(x...) do { if (dbg) printk(x); } while (0)
-#define rmap_printk(x...) do { if (dbg) printk(x); } while (0)
-
-#else
-
-#define pgprintk(x...) do { } while (0)
-#define rmap_printk(x...) do { } while (0)
-
-#endif
-
-#if defined(MMU_DEBUG) || defined(AUDIT)
-static int dbg = 1;
-#endif
-
-#ifndef MMU_DEBUG
-#define ASSERT(x) do { } while (0)
-#else
-#define ASSERT(x)							\
-	if (!(x)) {							\
-		printk(KERN_WARNING "assertion failed %s:%d: %s\n",	\
-		       __FILE__, __LINE__, #x);				\
-	}
-#endif
-
-#define PT64_PT_BITS 9
-#define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS)
-#define PT32_PT_BITS 10
-#define PT32_ENT_PER_PAGE (1 << PT32_PT_BITS)
-
-#define PT_WRITABLE_SHIFT 1
-
-#define PT_PRESENT_MASK (1ULL << 0)
-#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
-#define PT_USER_MASK (1ULL << 2)
-#define PT_PWT_MASK (1ULL << 3)
-#define PT_PCD_MASK (1ULL << 4)
-#define PT_ACCESSED_MASK (1ULL << 5)
-#define PT_DIRTY_MASK (1ULL << 6)
-#define PT_PAGE_SIZE_MASK (1ULL << 7)
-#define PT_PAT_MASK (1ULL << 7)
-#define PT_GLOBAL_MASK (1ULL << 8)
-#define PT64_NX_MASK (1ULL << 63)
-
-#define PT_PAT_SHIFT 7
-#define PT_DIR_PAT_SHIFT 12
-#define PT_DIR_PAT_MASK (1ULL << PT_DIR_PAT_SHIFT)
-
-#define PT32_DIR_PSE36_SIZE 4
-#define PT32_DIR_PSE36_SHIFT 13
-#define PT32_DIR_PSE36_MASK (((1ULL << PT32_DIR_PSE36_SIZE) - 1) << PT32_DIR_PSE36_SHIFT)
-
-
-#define PT_FIRST_AVAIL_BITS_SHIFT 9
-#define PT64_SECOND_AVAIL_BITS_SHIFT 52
-
-#define PT_SHADOW_IO_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
-
-#define VALID_PAGE(x) ((x) != INVALID_PAGE)
-
-#define PT64_LEVEL_BITS 9
-
-#define PT64_LEVEL_SHIFT(level) \
-		( PAGE_SHIFT + (level - 1) * PT64_LEVEL_BITS )
-
-#define PT64_LEVEL_MASK(level) \
-		(((1ULL << PT64_LEVEL_BITS) - 1) << PT64_LEVEL_SHIFT(level))
-
-#define PT64_INDEX(address, level)\
-	(((address) >> PT64_LEVEL_SHIFT(level)) & ((1 << PT64_LEVEL_BITS) - 1))
-
-
-#define PT32_LEVEL_BITS 10
-
-#define PT32_LEVEL_SHIFT(level) \
-		( PAGE_SHIFT + (level - 1) * PT32_LEVEL_BITS )
-
-#define PT32_LEVEL_MASK(level) \
-		(((1ULL << PT32_LEVEL_BITS) - 1) << PT32_LEVEL_SHIFT(level))
-
-#define PT32_INDEX(address, level)\
-	(((address) >> PT32_LEVEL_SHIFT(level)) & ((1 << PT32_LEVEL_BITS) - 1))
-
-
-#define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1))
-#define PT64_DIR_BASE_ADDR_MASK \
-	(PT64_BASE_ADDR_MASK & ~((1ULL << (PAGE_SHIFT + PT64_LEVEL_BITS)) - 1))
-
-#define PT32_BASE_ADDR_MASK PAGE_MASK
-#define PT32_DIR_BASE_ADDR_MASK \
-	(PAGE_MASK & ~((1ULL << (PAGE_SHIFT + PT32_LEVEL_BITS)) - 1))
-
-
-#define PFERR_PRESENT_MASK (1U << 0)
-#define PFERR_WRITE_MASK (1U << 1)
-#define PFERR_USER_MASK (1U << 2)
-#define PFERR_FETCH_MASK (1U << 4)
-
-#define PT64_ROOT_LEVEL 4
-#define PT32_ROOT_LEVEL 2
-#define PT32E_ROOT_LEVEL 3
-
-#define PT_DIRECTORY_LEVEL 2
-#define PT_PAGE_TABLE_LEVEL 1
-
-#define RMAP_EXT 4
-
-struct kvm_rmap_desc {
-	u64 *shadow_ptes[RMAP_EXT];
-	struct kvm_rmap_desc *more;
-};
-
-static struct kmem_cache *pte_chain_cache;
-static struct kmem_cache *rmap_desc_cache;
-static struct kmem_cache *mmu_page_header_cache;
-
-static int is_write_protection(struct kvm_vcpu *vcpu)
-{
-	return vcpu->cr0 & X86_CR0_WP;
-}
-
-static int is_cpuid_PSE36(void)
-{
-	return 1;
-}
-
-static int is_nx(struct kvm_vcpu *vcpu)
-{
-	return vcpu->shadow_efer & EFER_NX;
-}
-
-static int is_present_pte(unsigned long pte)
-{
-	return pte & PT_PRESENT_MASK;
-}
-
-static int is_writeble_pte(unsigned long pte)
-{
-	return pte & PT_WRITABLE_MASK;
-}
-
-static int is_io_pte(unsigned long pte)
-{
-	return pte & PT_SHADOW_IO_MARK;
-}
-
-static int is_rmap_pte(u64 pte)
-{
-	return (pte & (PT_WRITABLE_MASK | PT_PRESENT_MASK))
-		== (PT_WRITABLE_MASK | PT_PRESENT_MASK);
-}
-
-static void set_shadow_pte(u64 *sptep, u64 spte)
-{
-#ifdef CONFIG_X86_64
-	set_64bit((unsigned long *)sptep, spte);
-#else
-	set_64bit((unsigned long long *)sptep, spte);
-#endif
-}
-
-static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
-				  struct kmem_cache *base_cache, int min)
-{
-	void *obj;
-
-	if (cache->nobjs >= min)
-		return 0;
-	while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
-		obj = kmem_cache_zalloc(base_cache, GFP_KERNEL);
-		if (!obj)
-			return -ENOMEM;
-		cache->objects[cache->nobjs++] = obj;
-	}
-	return 0;
-}
-
-static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
-{
-	while (mc->nobjs)
-		kfree(mc->objects[--mc->nobjs]);
-}
-
-static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
-				       int min)
-{
-	struct page *page;
-
-	if (cache->nobjs >= min)
-		return 0;
-	while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
-		page = alloc_page(GFP_KERNEL);
-		if (!page)
-			return -ENOMEM;
-		set_page_private(page, 0);
-		cache->objects[cache->nobjs++] = page_address(page);
-	}
-	return 0;
-}
-
-static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
-{
-	while (mc->nobjs)
-		free_page((unsigned long)mc->objects[--mc->nobjs]);
-}
-
-static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
-{
-	int r;
-
-	kvm_mmu_free_some_pages(vcpu);
-	r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache,
-				   pte_chain_cache, 4);
-	if (r)
-		goto out;
-	r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache,
-				   rmap_desc_cache, 1);
-	if (r)
-		goto out;
-	r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4);
-	if (r)
-		goto out;
-	r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
-				   mmu_page_header_cache, 4);
-out:
-	return r;
-}
-
-static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
-{
-	mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
-	mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache);
-	mmu_free_memory_cache_page(&vcpu->mmu_page_cache);
-	mmu_free_memory_cache(&vcpu->mmu_page_header_cache);
-}
-
-static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
-				    size_t size)
-{
-	void *p;
-
-	BUG_ON(!mc->nobjs);
-	p = mc->objects[--mc->nobjs];
-	memset(p, 0, size);
-	return p;
-}
-
-static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu)
-{
-	return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache,
-				      sizeof(struct kvm_pte_chain));
-}
-
-static void mmu_free_pte_chain(struct kvm_pte_chain *pc)
-{
-	kfree(pc);
-}
-
-static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
-{
-	return mmu_memory_cache_alloc(&vcpu->mmu_rmap_desc_cache,
-				      sizeof(struct kvm_rmap_desc));
-}
-
-static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
-{
-	kfree(rd);
-}
-
-/*
- * Reverse mapping data structures:
- *
- * If page->private bit zero is zero, then page->private points to the
- * shadow page table entry that points to page_address(page).
- *
- * If page->private bit zero is one, (then page->private & ~1) points
- * to a struct kvm_rmap_desc containing more mappings.
- */
-static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte)
-{
-	struct page *page;
-	struct kvm_rmap_desc *desc;
-	int i;
-
-	if (!is_rmap_pte(*spte))
-		return;
-	page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT);
-	if (!page_private(page)) {
-		rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte);
-		set_page_private(page,(unsigned long)spte);
-	} else if (!(page_private(page) & 1)) {
-		rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte);
-		desc = mmu_alloc_rmap_desc(vcpu);
-		desc->shadow_ptes[0] = (u64 *)page_private(page);
-		desc->shadow_ptes[1] = spte;
-		set_page_private(page,(unsigned long)desc | 1);
-	} else {
-		rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte);
-		desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul);
-		while (desc->shadow_ptes[RMAP_EXT-1] && desc->more)
-			desc = desc->more;
-		if (desc->shadow_ptes[RMAP_EXT-1]) {
-			desc->more = mmu_alloc_rmap_desc(vcpu);
-			desc = desc->more;
-		}
-		for (i = 0; desc->shadow_ptes[i]; ++i)
-			;
-		desc->shadow_ptes[i] = spte;
-	}
-}
-
-static void rmap_desc_remove_entry(struct page *page,
-				   struct kvm_rmap_desc *desc,
-				   int i,
-				   struct kvm_rmap_desc *prev_desc)
-{
-	int j;
-
-	for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j)
-		;
-	desc->shadow_ptes[i] = desc->shadow_ptes[j];
-	desc->shadow_ptes[j] = NULL;
-	if (j != 0)
-		return;
-	if (!prev_desc && !desc->more)
-		set_page_private(page,(unsigned long)desc->shadow_ptes[0]);
-	else
-		if (prev_desc)
-			prev_desc->more = desc->more;
-		else
-			set_page_private(page,(unsigned long)desc->more | 1);
-	mmu_free_rmap_desc(desc);
-}
-
-static void rmap_remove(u64 *spte)
-{
-	struct page *page;
-	struct kvm_rmap_desc *desc;
-	struct kvm_rmap_desc *prev_desc;
-	int i;
-
-	if (!is_rmap_pte(*spte))
-		return;
-	page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT);
-	if (!page_private(page)) {
-		printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
-		BUG();
-	} else if (!(page_private(page) & 1)) {
-		rmap_printk("rmap_remove:  %p %llx 1->0\n", spte, *spte);
-		if ((u64 *)page_private(page) != spte) {
-			printk(KERN_ERR "rmap_remove:  %p %llx 1->BUG\n",
-			       spte, *spte);
-			BUG();
-		}
-		set_page_private(page,0);
-	} else {
-		rmap_printk("rmap_remove:  %p %llx many->many\n", spte, *spte);
-		desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul);
-		prev_desc = NULL;
-		while (desc) {
-			for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
-				if (desc->shadow_ptes[i] == spte) {
-					rmap_desc_remove_entry(page,
-							       desc, i,
-							       prev_desc);
-					return;
-				}
-			prev_desc = desc;
-			desc = desc->more;
-		}
-		BUG();
-	}
-}
-
-static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
-{
-	struct kvm *kvm = vcpu->kvm;
-	struct page *page;
-	struct kvm_rmap_desc *desc;
-	u64 *spte;
-
-	page = gfn_to_page(kvm, gfn);
-	BUG_ON(!page);
-
-	while (page_private(page)) {
-		if (!(page_private(page) & 1))
-			spte = (u64 *)page_private(page);
-		else {
-			desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul);
-			spte = desc->shadow_ptes[0];
-		}
-		BUG_ON(!spte);
-		BUG_ON((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT
-		       != page_to_pfn(page));
-		BUG_ON(!(*spte & PT_PRESENT_MASK));
-		BUG_ON(!(*spte & PT_WRITABLE_MASK));
-		rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
-		rmap_remove(spte);
-		set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
-		kvm_flush_remote_tlbs(vcpu->kvm);
-	}
-}
-
-#ifdef MMU_DEBUG
-static int is_empty_shadow_page(u64 *spt)
-{
-	u64 *pos;
-	u64 *end;
-
-	for (pos = spt, end = pos + PAGE_SIZE / sizeof(u64); pos != end; pos++)
-		if (*pos != 0) {
-			printk(KERN_ERR "%s: %p %llx\n", __FUNCTION__,
-			       pos, *pos);
-			return 0;
-		}
-	return 1;
-}
-#endif
-
-static void kvm_mmu_free_page(struct kvm *kvm,
-			      struct kvm_mmu_page *page_head)
-{
-	ASSERT(is_empty_shadow_page(page_head->spt));
-	list_del(&page_head->link);
-	__free_page(virt_to_page(page_head->spt));
-	kfree(page_head);
-	++kvm->n_free_mmu_pages;
-}
-
-static unsigned kvm_page_table_hashfn(gfn_t gfn)
-{
-	return gfn;
-}
-
-static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
-					       u64 *parent_pte)
-{
-	struct kvm_mmu_page *page;
-
-	if (!vcpu->kvm->n_free_mmu_pages)
-		return NULL;
-
-	page = mmu_memory_cache_alloc(&vcpu->mmu_page_header_cache,
-				      sizeof *page);
-	page->spt = mmu_memory_cache_alloc(&vcpu->mmu_page_cache, PAGE_SIZE);
-	set_page_private(virt_to_page(page->spt), (unsigned long)page);
-	list_add(&page->link, &vcpu->kvm->active_mmu_pages);
-	ASSERT(is_empty_shadow_page(page->spt));
-	page->slot_bitmap = 0;
-	page->multimapped = 0;
-	page->parent_pte = parent_pte;
-	--vcpu->kvm->n_free_mmu_pages;
-	return page;
-}
-
-static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu,
-				    struct kvm_mmu_page *page, u64 *parent_pte)
-{
-	struct kvm_pte_chain *pte_chain;
-	struct hlist_node *node;
-	int i;
-
-	if (!parent_pte)
-		return;
-	if (!page->multimapped) {
-		u64 *old = page->parent_pte;
-
-		if (!old) {
-			page->parent_pte = parent_pte;
-			return;
-		}
-		page->multimapped = 1;
-		pte_chain = mmu_alloc_pte_chain(vcpu);
-		INIT_HLIST_HEAD(&page->parent_ptes);
-		hlist_add_head(&pte_chain->link, &page->parent_ptes);
-		pte_chain->parent_ptes[0] = old;
-	}
-	hlist_for_each_entry(pte_chain, node, &page->parent_ptes, link) {
-		if (pte_chain->parent_ptes[NR_PTE_CHAIN_ENTRIES-1])
-			continue;
-		for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i)
-			if (!pte_chain->parent_ptes[i]) {
-				pte_chain->parent_ptes[i] = parent_pte;
-				return;
-			}
-	}
-	pte_chain = mmu_alloc_pte_chain(vcpu);
-	BUG_ON(!pte_chain);
-	hlist_add_head(&pte_chain->link, &page->parent_ptes);
-	pte_chain->parent_ptes[0] = parent_pte;
-}
-
-static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page,
-				       u64 *parent_pte)
-{
-	struct kvm_pte_chain *pte_chain;
-	struct hlist_node *node;
-	int i;
-
-	if (!page->multimapped) {
-		BUG_ON(page->parent_pte != parent_pte);
-		page->parent_pte = NULL;
-		return;
-	}
-	hlist_for_each_entry(pte_chain, node, &page->parent_ptes, link)
-		for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) {
-			if (!pte_chain->parent_ptes[i])
-				break;
-			if (pte_chain->parent_ptes[i] != parent_pte)
-				continue;
-			while (i + 1 < NR_PTE_CHAIN_ENTRIES
-				&& pte_chain->parent_ptes[i + 1]) {
-				pte_chain->parent_ptes[i]
-					= pte_chain->parent_ptes[i + 1];
-				++i;
-			}
-			pte_chain->parent_ptes[i] = NULL;
-			if (i == 0) {
-				hlist_del(&pte_chain->link);
-				mmu_free_pte_chain(pte_chain);
-				if (hlist_empty(&page->parent_ptes)) {
-					page->multimapped = 0;
-					page->parent_pte = NULL;
-				}
-			}
-			return;
-		}
-	BUG();
-}
-
-static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm_vcpu *vcpu,
-						gfn_t gfn)
-{
-	unsigned index;
-	struct hlist_head *bucket;
-	struct kvm_mmu_page *page;
-	struct hlist_node *node;
-
-	pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn);
-	index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
-	bucket = &vcpu->kvm->mmu_page_hash[index];
-	hlist_for_each_entry(page, node, bucket, hash_link)
-		if (page->gfn == gfn && !page->role.metaphysical) {
-			pgprintk("%s: found role %x\n",
-				 __FUNCTION__, page->role.word);
-			return page;
-		}
-	return NULL;
-}
-
-static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
-					     gfn_t gfn,
-					     gva_t gaddr,
-					     unsigned level,
-					     int metaphysical,
-					     unsigned hugepage_access,
-					     u64 *parent_pte)
-{
-	union kvm_mmu_page_role role;
-	unsigned index;
-	unsigned quadrant;
-	struct hlist_head *bucket;
-	struct kvm_mmu_page *page;
-	struct hlist_node *node;
-
-	role.word = 0;
-	role.glevels = vcpu->mmu.root_level;
-	role.level = level;
-	role.metaphysical = metaphysical;
-	role.hugepage_access = hugepage_access;
-	if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) {
-		quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
-		quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
-		role.quadrant = quadrant;
-	}
-	pgprintk("%s: looking gfn %lx role %x\n", __FUNCTION__,
-		 gfn, role.word);
-	index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
-	bucket = &vcpu->kvm->mmu_page_hash[index];
-	hlist_for_each_entry(page, node, bucket, hash_link)
-		if (page->gfn == gfn && page->role.word == role.word) {
-			mmu_page_add_parent_pte(vcpu, page, parent_pte);
-			pgprintk("%s: found\n", __FUNCTION__);
-			return page;
-		}
-	page = kvm_mmu_alloc_page(vcpu, parent_pte);
-	if (!page)
-		return page;
-	pgprintk("%s: adding gfn %lx role %x\n", __FUNCTION__, gfn, role.word);
-	page->gfn = gfn;
-	page->role = role;
-	hlist_add_head(&page->hash_link, bucket);
-	if (!metaphysical)
-		rmap_write_protect(vcpu, gfn);
-	return page;
-}
-
-static void kvm_mmu_page_unlink_children(struct kvm *kvm,
-					 struct kvm_mmu_page *page)
-{
-	unsigned i;
-	u64 *pt;
-	u64 ent;
-
-	pt = page->spt;
-
-	if (page->role.level == PT_PAGE_TABLE_LEVEL) {
-		for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
-			if (pt[i] & PT_PRESENT_MASK)
-				rmap_remove(&pt[i]);
-			pt[i] = 0;
-		}
-		kvm_flush_remote_tlbs(kvm);
-		return;
-	}
-
-	for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
-		ent = pt[i];
-
-		pt[i] = 0;
-		if (!(ent & PT_PRESENT_MASK))
-			continue;
-		ent &= PT64_BASE_ADDR_MASK;
-		mmu_page_remove_parent_pte(page_header(ent), &pt[i]);
-	}
-	kvm_flush_remote_tlbs(kvm);
-}
-
-static void kvm_mmu_put_page(struct kvm_mmu_page *page,
-			     u64 *parent_pte)
-{
-	mmu_page_remove_parent_pte(page, parent_pte);
-}
-
-static void kvm_mmu_zap_page(struct kvm *kvm,
-			     struct kvm_mmu_page *page)
-{
-	u64 *parent_pte;
-
-	while (page->multimapped || page->parent_pte) {
-		if (!page->multimapped)
-			parent_pte = page->parent_pte;
-		else {
-			struct kvm_pte_chain *chain;
-
-			chain = container_of(page->parent_ptes.first,
-					     struct kvm_pte_chain, link);
-			parent_pte = chain->parent_ptes[0];
-		}
-		BUG_ON(!parent_pte);
-		kvm_mmu_put_page(page, parent_pte);
-		set_shadow_pte(parent_pte, 0);
-	}
-	kvm_mmu_page_unlink_children(kvm, page);
-	if (!page->root_count) {
-		hlist_del(&page->hash_link);
-		kvm_mmu_free_page(kvm, page);
-	} else
-		list_move(&page->link, &kvm->active_mmu_pages);
-}
-
-static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
-{
-	unsigned index;
-	struct hlist_head *bucket;
-	struct kvm_mmu_page *page;
-	struct hlist_node *node, *n;
-	int r;
-
-	pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn);
-	r = 0;
-	index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
-	bucket = &vcpu->kvm->mmu_page_hash[index];
-	hlist_for_each_entry_safe(page, node, n, bucket, hash_link)
-		if (page->gfn == gfn && !page->role.metaphysical) {
-			pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn,
-				 page->role.word);
-			kvm_mmu_zap_page(vcpu->kvm, page);
-			r = 1;
-		}
-	return r;
-}
-
-static void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn)
-{
-	struct kvm_mmu_page *page;
-
-	while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
-		pgprintk("%s: zap %lx %x\n",
-			 __FUNCTION__, gfn, page->role.word);
-		kvm_mmu_zap_page(vcpu->kvm, page);
-	}
-}
-
-static void page_header_update_slot(struct kvm *kvm, void *pte, gpa_t gpa)
-{
-	int slot = memslot_id(kvm, gfn_to_memslot(kvm, gpa >> PAGE_SHIFT));
-	struct kvm_mmu_page *page_head = page_header(__pa(pte));
-
-	__set_bit(slot, &page_head->slot_bitmap);
-}
-
-hpa_t safe_gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa)
-{
-	hpa_t hpa = gpa_to_hpa(vcpu, gpa);
-
-	return is_error_hpa(hpa) ? bad_page_address | (gpa & ~PAGE_MASK): hpa;
-}
-
-hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa)
-{
-	struct page *page;
-
-	ASSERT((gpa & HPA_ERR_MASK) == 0);
-	page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
-	if (!page)
-		return gpa | HPA_ERR_MASK;
-	return ((hpa_t)page_to_pfn(page) << PAGE_SHIFT)
-		| (gpa & (PAGE_SIZE-1));
-}
-
-hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva)
-{
-	gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva);
-
-	if (gpa == UNMAPPED_GVA)
-		return UNMAPPED_GVA;
-	return gpa_to_hpa(vcpu, gpa);
-}
-
-struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva)
-{
-	gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva);
-
-	if (gpa == UNMAPPED_GVA)
-		return NULL;
-	return pfn_to_page(gpa_to_hpa(vcpu, gpa) >> PAGE_SHIFT);
-}
-
-static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
-{
-}
-
-static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p)
-{
-	int level = PT32E_ROOT_LEVEL;
-	hpa_t table_addr = vcpu->mmu.root_hpa;
-
-	for (; ; level--) {
-		u32 index = PT64_INDEX(v, level);
-		u64 *table;
-		u64 pte;
-
-		ASSERT(VALID_PAGE(table_addr));
-		table = __va(table_addr);
-
-		if (level == 1) {
-			pte = table[index];
-			if (is_present_pte(pte) && is_writeble_pte(pte))
-				return 0;
-			mark_page_dirty(vcpu->kvm, v >> PAGE_SHIFT);
-			page_header_update_slot(vcpu->kvm, table, v);
-			table[index] = p | PT_PRESENT_MASK | PT_WRITABLE_MASK |
-								PT_USER_MASK;
-			rmap_add(vcpu, &table[index]);
-			return 0;
-		}
-
-		if (table[index] == 0) {
-			struct kvm_mmu_page *new_table;
-			gfn_t pseudo_gfn;
-
-			pseudo_gfn = (v & PT64_DIR_BASE_ADDR_MASK)
-				>> PAGE_SHIFT;
-			new_table = kvm_mmu_get_page(vcpu, pseudo_gfn,
-						     v, level - 1,
-						     1, 0, &table[index]);
-			if (!new_table) {
-				pgprintk("nonpaging_map: ENOMEM\n");
-				return -ENOMEM;
-			}
-
-			table[index] = __pa(new_table->spt) | PT_PRESENT_MASK
-				| PT_WRITABLE_MASK | PT_USER_MASK;
-		}
-		table_addr = table[index] & PT64_BASE_ADDR_MASK;
-	}
-}
-
-static void mmu_free_roots(struct kvm_vcpu *vcpu)
-{
-	int i;
-	struct kvm_mmu_page *page;
-
-	if (!VALID_PAGE(vcpu->mmu.root_hpa))
-		return;
-#ifdef CONFIG_X86_64
-	if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) {
-		hpa_t root = vcpu->mmu.root_hpa;
-
-		page = page_header(root);
-		--page->root_count;
-		vcpu->mmu.root_hpa = INVALID_PAGE;
-		return;
-	}
-#endif
-	for (i = 0; i < 4; ++i) {
-		hpa_t root = vcpu->mmu.pae_root[i];
-
-		if (root) {
-			root &= PT64_BASE_ADDR_MASK;
-			page = page_header(root);
-			--page->root_count;
-		}
-		vcpu->mmu.pae_root[i] = INVALID_PAGE;
-	}
-	vcpu->mmu.root_hpa = INVALID_PAGE;
-}
-
-static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
-{
-	int i;
-	gfn_t root_gfn;
-	struct kvm_mmu_page *page;
-
-	root_gfn = vcpu->cr3 >> PAGE_SHIFT;
-
-#ifdef CONFIG_X86_64
-	if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) {
-		hpa_t root = vcpu->mmu.root_hpa;
-
-		ASSERT(!VALID_PAGE(root));
-		page = kvm_mmu_get_page(vcpu, root_gfn, 0,
-					PT64_ROOT_LEVEL, 0, 0, NULL);
-		root = __pa(page->spt);
-		++page->root_count;
-		vcpu->mmu.root_hpa = root;
-		return;
-	}
-#endif
-	for (i = 0; i < 4; ++i) {
-		hpa_t root = vcpu->mmu.pae_root[i];
-
-		ASSERT(!VALID_PAGE(root));
-		if (vcpu->mmu.root_level == PT32E_ROOT_LEVEL) {
-			if (!is_present_pte(vcpu->pdptrs[i])) {
-				vcpu->mmu.pae_root[i] = 0;
-				continue;
-			}
-			root_gfn = vcpu->pdptrs[i] >> PAGE_SHIFT;
-		} else if (vcpu->mmu.root_level == 0)
-			root_gfn = 0;
-		page = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
-					PT32_ROOT_LEVEL, !is_paging(vcpu),
-					0, NULL);
-		root = __pa(page->spt);
-		++page->root_count;
-		vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK;
-	}
-	vcpu->mmu.root_hpa = __pa(vcpu->mmu.pae_root);
-}
-
-static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr)
-{
-	return vaddr;
-}
-
-static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
-			       u32 error_code)
-{
-	gpa_t addr = gva;
-	hpa_t paddr;
-	int r;
-
-	r = mmu_topup_memory_caches(vcpu);
-	if (r)
-		return r;
-
-	ASSERT(vcpu);
-	ASSERT(VALID_PAGE(vcpu->mmu.root_hpa));
-
-
-	paddr = gpa_to_hpa(vcpu , addr & PT64_BASE_ADDR_MASK);
-
-	if (is_error_hpa(paddr))
-		return 1;
-
-	return nonpaging_map(vcpu, addr & PAGE_MASK, paddr);
-}
-
-static void nonpaging_free(struct kvm_vcpu *vcpu)
-{
-	mmu_free_roots(vcpu);
-}
-
-static int nonpaging_init_context(struct kvm_vcpu *vcpu)
-{
-	struct kvm_mmu *context = &vcpu->mmu;
-
-	context->new_cr3 = nonpaging_new_cr3;
-	context->page_fault = nonpaging_page_fault;
-	context->gva_to_gpa = nonpaging_gva_to_gpa;
-	context->free = nonpaging_free;
-	context->root_level = 0;
-	context->shadow_root_level = PT32E_ROOT_LEVEL;
-	context->root_hpa = INVALID_PAGE;
-	return 0;
-}
-
-static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
-{
-	++vcpu->stat.tlb_flush;
-	kvm_x86_ops->tlb_flush(vcpu);
-}
-
-static void paging_new_cr3(struct kvm_vcpu *vcpu)
-{
-	pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->cr3);
-	mmu_free_roots(vcpu);
-}
-
-static void inject_page_fault(struct kvm_vcpu *vcpu,
-			      u64 addr,
-			      u32 err_code)
-{
-	kvm_x86_ops->inject_page_fault(vcpu, addr, err_code);
-}
-
-static void paging_free(struct kvm_vcpu *vcpu)
-{
-	nonpaging_free(vcpu);
-}
-
-#define PTTYPE 64
-#include "paging_tmpl.h"
-#undef PTTYPE
-
-#define PTTYPE 32
-#include "paging_tmpl.h"
-#undef PTTYPE
-
-static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)
-{
-	struct kvm_mmu *context = &vcpu->mmu;
-
-	ASSERT(is_pae(vcpu));
-	context->new_cr3 = paging_new_cr3;
-	context->page_fault = paging64_page_fault;
-	context->gva_to_gpa = paging64_gva_to_gpa;
-	context->free = paging_free;
-	context->root_level = level;
-	context->shadow_root_level = level;
-	context->root_hpa = INVALID_PAGE;
-	return 0;
-}
-
-static int paging64_init_context(struct kvm_vcpu *vcpu)
-{
-	return paging64_init_context_common(vcpu, PT64_ROOT_LEVEL);
-}
-
-static int paging32_init_context(struct kvm_vcpu *vcpu)
-{
-	struct kvm_mmu *context = &vcpu->mmu;
-
-	context->new_cr3 = paging_new_cr3;
-	context->page_fault = paging32_page_fault;
-	context->gva_to_gpa = paging32_gva_to_gpa;
-	context->free = paging_free;
-	context->root_level = PT32_ROOT_LEVEL;
-	context->shadow_root_level = PT32E_ROOT_LEVEL;
-	context->root_hpa = INVALID_PAGE;
-	return 0;
-}
-
-static int paging32E_init_context(struct kvm_vcpu *vcpu)
-{
-	return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL);
-}
-
-static int init_kvm_mmu(struct kvm_vcpu *vcpu)
-{
-	ASSERT(vcpu);
-	ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
-
-	if (!is_paging(vcpu))
-		return nonpaging_init_context(vcpu);
-	else if (is_long_mode(vcpu))
-		return paging64_init_context(vcpu);
-	else if (is_pae(vcpu))
-		return paging32E_init_context(vcpu);
-	else
-		return paging32_init_context(vcpu);
-}
-
-static void destroy_kvm_mmu(struct kvm_vcpu *vcpu)
-{
-	ASSERT(vcpu);
-	if (VALID_PAGE(vcpu->mmu.root_hpa)) {
-		vcpu->mmu.free(vcpu);
-		vcpu->mmu.root_hpa = INVALID_PAGE;
-	}
-}
-
-int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
-{
-	destroy_kvm_mmu(vcpu);
-	return init_kvm_mmu(vcpu);
-}
-EXPORT_SYMBOL_GPL(kvm_mmu_reset_context);
-
-int kvm_mmu_load(struct kvm_vcpu *vcpu)
-{
-	int r;
-
-	mutex_lock(&vcpu->kvm->lock);
-	r = mmu_topup_memory_caches(vcpu);
-	if (r)
-		goto out;
-	mmu_alloc_roots(vcpu);
-	kvm_x86_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
-	kvm_mmu_flush_tlb(vcpu);
-out:
-	mutex_unlock(&vcpu->kvm->lock);
-	return r;
-}
-EXPORT_SYMBOL_GPL(kvm_mmu_load);
-
-void kvm_mmu_unload(struct kvm_vcpu *vcpu)
-{
-	mmu_free_roots(vcpu);
-}
-
-static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
-				  struct kvm_mmu_page *page,
-				  u64 *spte)
-{
-	u64 pte;
-	struct kvm_mmu_page *child;
-
-	pte = *spte;
-	if (is_present_pte(pte)) {
-		if (page->role.level == PT_PAGE_TABLE_LEVEL)
-			rmap_remove(spte);
-		else {
-			child = page_header(pte & PT64_BASE_ADDR_MASK);
-			mmu_page_remove_parent_pte(child, spte);
-		}
-	}
-	set_shadow_pte(spte, 0);
-	kvm_flush_remote_tlbs(vcpu->kvm);
-}
-
-static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
-				  struct kvm_mmu_page *page,
-				  u64 *spte,
-				  const void *new, int bytes)
-{
-	if (page->role.level != PT_PAGE_TABLE_LEVEL)
-		return;
-
-	if (page->role.glevels == PT32_ROOT_LEVEL)
-		paging32_update_pte(vcpu, page, spte, new, bytes);
-	else
-		paging64_update_pte(vcpu, page, spte, new, bytes);
-}
-
-void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
-		       const u8 *new, int bytes)
-{
-	gfn_t gfn = gpa >> PAGE_SHIFT;
-	struct kvm_mmu_page *page;
-	struct hlist_node *node, *n;
-	struct hlist_head *bucket;
-	unsigned index;
-	u64 *spte;
-	unsigned offset = offset_in_page(gpa);
-	unsigned pte_size;
-	unsigned page_offset;
-	unsigned misaligned;
-	unsigned quadrant;
-	int level;
-	int flooded = 0;
-	int npte;
-
-	pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes);
-	if (gfn == vcpu->last_pt_write_gfn) {
-		++vcpu->last_pt_write_count;
-		if (vcpu->last_pt_write_count >= 3)
-			flooded = 1;
-	} else {
-		vcpu->last_pt_write_gfn = gfn;
-		vcpu->last_pt_write_count = 1;
-	}
-	index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES;
-	bucket = &vcpu->kvm->mmu_page_hash[index];
-	hlist_for_each_entry_safe(page, node, n, bucket, hash_link) {
-		if (page->gfn != gfn || page->role.metaphysical)
-			continue;
-		pte_size = page->role.glevels == PT32_ROOT_LEVEL ? 4 : 8;
-		misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1);
-		misaligned |= bytes < 4;
-		if (misaligned || flooded) {
-			/*
-			 * Misaligned accesses are too much trouble to fix
-			 * up; also, they usually indicate a page is not used
-			 * as a page table.
-			 *
-			 * If we're seeing too many writes to a page,
-			 * it may no longer be a page table, or we may be
-			 * forking, in which case it is better to unmap the
-			 * page.
-			 */
-			pgprintk("misaligned: gpa %llx bytes %d role %x\n",
-				 gpa, bytes, page->role.word);
-			kvm_mmu_zap_page(vcpu->kvm, page);
-			continue;
-		}
-		page_offset = offset;
-		level = page->role.level;
-		npte = 1;
-		if (page->role.glevels == PT32_ROOT_LEVEL) {
-			page_offset <<= 1;	/* 32->64 */
-			/*
-			 * A 32-bit pde maps 4MB while the shadow pdes map
-			 * only 2MB.  So we need to double the offset again
-			 * and zap two pdes instead of one.
-			 */
-			if (level == PT32_ROOT_LEVEL) {
-				page_offset &= ~7; /* kill rounding error */
-				page_offset <<= 1;
-				npte = 2;
-			}
-			quadrant = page_offset >> PAGE_SHIFT;
-			page_offset &= ~PAGE_MASK;
-			if (quadrant != page->role.quadrant)
-				continue;
-		}
-		spte = &page->spt[page_offset / sizeof(*spte)];
-		while (npte--) {
-			mmu_pte_write_zap_pte(vcpu, page, spte);
-			mmu_pte_write_new_pte(vcpu, page, spte, new, bytes);
-			++spte;
-		}
-	}
-}
-
-int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
-{
-	gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva);
-
-	return kvm_mmu_unprotect_page(vcpu, gpa >> PAGE_SHIFT);
-}
-
-void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
-{
-	while (vcpu->kvm->n_free_mmu_pages < KVM_REFILL_PAGES) {
-		struct kvm_mmu_page *page;
-
-		page = container_of(vcpu->kvm->active_mmu_pages.prev,
-				    struct kvm_mmu_page, link);
-		kvm_mmu_zap_page(vcpu->kvm, page);
-	}
-}
-
-static void free_mmu_pages(struct kvm_vcpu *vcpu)
-{
-	struct kvm_mmu_page *page;
-
-	while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
-		page = container_of(vcpu->kvm->active_mmu_pages.next,
-				    struct kvm_mmu_page, link);
-		kvm_mmu_zap_page(vcpu->kvm, page);
-	}
-	free_page((unsigned long)vcpu->mmu.pae_root);
-}
-
-static int alloc_mmu_pages(struct kvm_vcpu *vcpu)
-{
-	struct page *page;
-	int i;
-
-	ASSERT(vcpu);
-
-	vcpu->kvm->n_free_mmu_pages = KVM_NUM_MMU_PAGES;
-
-	/*
-	 * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64.
-	 * Therefore we need to allocate shadow page tables in the first
-	 * 4GB of memory, which happens to fit the DMA32 zone.
-	 */
-	page = alloc_page(GFP_KERNEL | __GFP_DMA32);
-	if (!page)
-		goto error_1;
-	vcpu->mmu.pae_root = page_address(page);
-	for (i = 0; i < 4; ++i)
-		vcpu->mmu.pae_root[i] = INVALID_PAGE;
-
-	return 0;
-
-error_1:
-	free_mmu_pages(vcpu);
-	return -ENOMEM;
-}
-
-int kvm_mmu_create(struct kvm_vcpu *vcpu)
-{
-	ASSERT(vcpu);
-	ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
-
-	return alloc_mmu_pages(vcpu);
-}
-
-int kvm_mmu_setup(struct kvm_vcpu *vcpu)
-{
-	ASSERT(vcpu);
-	ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
-
-	return init_kvm_mmu(vcpu);
-}
-
-void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
-{
-	ASSERT(vcpu);
-
-	destroy_kvm_mmu(vcpu);
-	free_mmu_pages(vcpu);
-	mmu_free_memory_caches(vcpu);
-}
-
-void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
-{
-	struct kvm_mmu_page *page;
-
-	list_for_each_entry(page, &kvm->active_mmu_pages, link) {
-		int i;
-		u64 *pt;
-
-		if (!test_bit(slot, &page->slot_bitmap))
-			continue;
-
-		pt = page->spt;
-		for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
-			/* avoid RMW */
-			if (pt[i] & PT_WRITABLE_MASK) {
-				rmap_remove(&pt[i]);
-				pt[i] &= ~PT_WRITABLE_MASK;
-			}
-	}
-}
-
-void kvm_mmu_zap_all(struct kvm *kvm)
-{
-	struct kvm_mmu_page *page, *node;
-
-	list_for_each_entry_safe(page, node, &kvm->active_mmu_pages, link)
-		kvm_mmu_zap_page(kvm, page);
-
-	kvm_flush_remote_tlbs(kvm);
-}
-
-void kvm_mmu_module_exit(void)
-{
-	if (pte_chain_cache)
-		kmem_cache_destroy(pte_chain_cache);
-	if (rmap_desc_cache)
-		kmem_cache_destroy(rmap_desc_cache);
-	if (mmu_page_header_cache)
-		kmem_cache_destroy(mmu_page_header_cache);
-}
-
-int kvm_mmu_module_init(void)
-{
-	pte_chain_cache = kmem_cache_create("kvm_pte_chain",
-					    sizeof(struct kvm_pte_chain),
-					    0, 0, NULL);
-	if (!pte_chain_cache)
-		goto nomem;
-	rmap_desc_cache = kmem_cache_create("kvm_rmap_desc",
-					    sizeof(struct kvm_rmap_desc),
-					    0, 0, NULL);
-	if (!rmap_desc_cache)
-		goto nomem;
-
-	mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
-						  sizeof(struct kvm_mmu_page),
-						  0, 0, NULL);
-	if (!mmu_page_header_cache)
-		goto nomem;
-
-	return 0;
-
-nomem:
-	kvm_mmu_module_exit();
-	return -ENOMEM;
-}
-
-#ifdef AUDIT
-
-static const char *audit_msg;
-
-static gva_t canonicalize(gva_t gva)
-{
-#ifdef CONFIG_X86_64
-	gva = (long long)(gva << 16) >> 16;
-#endif
-	return gva;
-}
-
-static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
-				gva_t va, int level)
-{
-	u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK);
-	int i;
-	gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1));
-
-	for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) {
-		u64 ent = pt[i];
-
-		if (!(ent & PT_PRESENT_MASK))
-			continue;
-
-		va = canonicalize(va);
-		if (level > 1)
-			audit_mappings_page(vcpu, ent, va, level - 1);
-		else {
-			gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, va);
-			hpa_t hpa = gpa_to_hpa(vcpu, gpa);
-
-			if ((ent & PT_PRESENT_MASK)
-			    && (ent & PT64_BASE_ADDR_MASK) != hpa)
-				printk(KERN_ERR "audit error: (%s) levels %d"
-				       " gva %lx gpa %llx hpa %llx ent %llx\n",
-				       audit_msg, vcpu->mmu.root_level,
-				       va, gpa, hpa, ent);
-		}
-	}
-}
-
-static void audit_mappings(struct kvm_vcpu *vcpu)
-{
-	unsigned i;
-
-	if (vcpu->mmu.root_level == 4)
-		audit_mappings_page(vcpu, vcpu->mmu.root_hpa, 0, 4);
-	else
-		for (i = 0; i < 4; ++i)
-			if (vcpu->mmu.pae_root[i] & PT_PRESENT_MASK)
-				audit_mappings_page(vcpu,
-						    vcpu->mmu.pae_root[i],
-						    i << 30,
-						    2);
-}
-
-static int count_rmaps(struct kvm_vcpu *vcpu)
-{
-	int nmaps = 0;
-	int i, j, k;
-
-	for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
-		struct kvm_memory_slot *m = &vcpu->kvm->memslots[i];
-		struct kvm_rmap_desc *d;
-
-		for (j = 0; j < m->npages; ++j) {
-			struct page *page = m->phys_mem[j];
-
-			if (!page->private)
-				continue;
-			if (!(page->private & 1)) {
-				++nmaps;
-				continue;
-			}
-			d = (struct kvm_rmap_desc *)(page->private & ~1ul);
-			while (d) {
-				for (k = 0; k < RMAP_EXT; ++k)
-					if (d->shadow_ptes[k])
-						++nmaps;
-					else
-						break;
-				d = d->more;
-			}
-		}
-	}
-	return nmaps;
-}
-
-static int count_writable_mappings(struct kvm_vcpu *vcpu)
-{
-	int nmaps = 0;
-	struct kvm_mmu_page *page;
-	int i;
-
-	list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) {
-		u64 *pt = page->spt;
-
-		if (page->role.level != PT_PAGE_TABLE_LEVEL)
-			continue;
-
-		for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
-			u64 ent = pt[i];
-
-			if (!(ent & PT_PRESENT_MASK))
-				continue;
-			if (!(ent & PT_WRITABLE_MASK))
-				continue;
-			++nmaps;
-		}
-	}
-	return nmaps;
-}
-
-static void audit_rmap(struct kvm_vcpu *vcpu)
-{
-	int n_rmap = count_rmaps(vcpu);
-	int n_actual = count_writable_mappings(vcpu);
-
-	if (n_rmap != n_actual)
-		printk(KERN_ERR "%s: (%s) rmap %d actual %d\n",
-		       __FUNCTION__, audit_msg, n_rmap, n_actual);
-}
-
-static void audit_write_protection(struct kvm_vcpu *vcpu)
-{
-	struct kvm_mmu_page *page;
-
-	list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) {
-		hfn_t hfn;
-		struct page *pg;
-
-		if (page->role.metaphysical)
-			continue;
-
-		hfn = gpa_to_hpa(vcpu, (gpa_t)page->gfn << PAGE_SHIFT)
-			>> PAGE_SHIFT;
-		pg = pfn_to_page(hfn);
-		if (pg->private)
-			printk(KERN_ERR "%s: (%s) shadow page has writable"
-			       " mappings: gfn %lx role %x\n",
-			       __FUNCTION__, audit_msg, page->gfn,
-			       page->role.word);
-	}
-}
-
-static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg)
-{
-	int olddbg = dbg;
-
-	dbg = 0;
-	audit_msg = msg;
-	audit_rmap(vcpu);
-	audit_write_protection(vcpu);
-	audit_mappings(vcpu);
-	dbg = olddbg;
-}
-
-#endif
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
deleted file mode 100644
index 6b094b44f8fb..000000000000
--- a/drivers/kvm/paging_tmpl.h
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * Kernel-based Virtual Machine driver for Linux
- *
- * This module enables machines with Intel VT-x extensions to run virtual
- * machines without emulation or binary translation.
- *
- * MMU support
- *
- * Copyright (C) 2006 Qumranet, Inc.
- *
- * Authors:
- *   Yaniv Kamay  <yaniv@qumranet.com>
- *   Avi Kivity   <avi@qumranet.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-/*
- * We need the mmu code to access both 32-bit and 64-bit guest ptes,
- * so the code in this file is compiled twice, once per pte size.
- */
-
-#if PTTYPE == 64
-	#define pt_element_t u64
-	#define guest_walker guest_walker64
-	#define FNAME(name) paging##64_##name
-	#define PT_BASE_ADDR_MASK PT64_BASE_ADDR_MASK
-	#define PT_DIR_BASE_ADDR_MASK PT64_DIR_BASE_ADDR_MASK
-	#define PT_INDEX(addr, level) PT64_INDEX(addr, level)
-	#define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
-	#define PT_LEVEL_MASK(level) PT64_LEVEL_MASK(level)
-	#ifdef CONFIG_X86_64
-	#define PT_MAX_FULL_LEVELS 4
-	#else
-	#define PT_MAX_FULL_LEVELS 2
-	#endif
-#elif PTTYPE == 32
-	#define pt_element_t u32
-	#define guest_walker guest_walker32
-	#define FNAME(name) paging##32_##name
-	#define PT_BASE_ADDR_MASK PT32_BASE_ADDR_MASK
-	#define PT_DIR_BASE_ADDR_MASK PT32_DIR_BASE_ADDR_MASK
-	#define PT_INDEX(addr, level) PT32_INDEX(addr, level)
-	#define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
-	#define PT_LEVEL_MASK(level) PT32_LEVEL_MASK(level)
-	#define PT_MAX_FULL_LEVELS 2
-#else
-	#error Invalid PTTYPE value
-#endif
-
-/*
- * The guest_walker structure emulates the behavior of the hardware page
- * table walker.
- */
-struct guest_walker {
-	int level;
-	gfn_t table_gfn[PT_MAX_FULL_LEVELS];
-	pt_element_t *table;
-	pt_element_t pte;
-	pt_element_t *ptep;
-	struct page *page;
-	int index;
-	pt_element_t inherited_ar;
-	gfn_t gfn;
-	u32 error_code;
-};
-
-/*
- * Fetch a guest pte for a guest virtual address
- */
-static int FNAME(walk_addr)(struct guest_walker *walker,
-			    struct kvm_vcpu *vcpu, gva_t addr,
-			    int write_fault, int user_fault, int fetch_fault)
-{
-	hpa_t hpa;
-	struct kvm_memory_slot *slot;
-	pt_element_t *ptep;
-	pt_element_t root;
-	gfn_t table_gfn;
-
-	pgprintk("%s: addr %lx\n", __FUNCTION__, addr);
-	walker->level = vcpu->mmu.root_level;
-	walker->table = NULL;
-	walker->page = NULL;
-	walker->ptep = NULL;
-	root = vcpu->cr3;
-#if PTTYPE == 64
-	if (!is_long_mode(vcpu)) {
-		walker->ptep = &vcpu->pdptrs[(addr >> 30) & 3];
-		root = *walker->ptep;
-		walker->pte = root;
-		if (!(root & PT_PRESENT_MASK))
-			goto not_present;
-		--walker->level;
-	}
-#endif
-	table_gfn = (root & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
-	walker->table_gfn[walker->level - 1] = table_gfn;
-	pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__,
-		 walker->level - 1, table_gfn);
-	slot = gfn_to_memslot(vcpu->kvm, table_gfn);
-	hpa = safe_gpa_to_hpa(vcpu, root & PT64_BASE_ADDR_MASK);
-	walker->page = pfn_to_page(hpa >> PAGE_SHIFT);
-	walker->table = kmap_atomic(walker->page, KM_USER0);
-
-	ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
-	       (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0);
-
-	walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK;
-
-	for (;;) {
-		int index = PT_INDEX(addr, walker->level);
-		hpa_t paddr;
-
-		ptep = &walker->table[index];
-		walker->index = index;
-		ASSERT(((unsigned long)walker->table & PAGE_MASK) ==
-		       ((unsigned long)ptep & PAGE_MASK));
-
-		if (!is_present_pte(*ptep))
-			goto not_present;
-
-		if (write_fault && !is_writeble_pte(*ptep))
-			if (user_fault || is_write_protection(vcpu))
-				goto access_error;
-
-		if (user_fault && !(*ptep & PT_USER_MASK))
-			goto access_error;
-
-#if PTTYPE == 64
-		if (fetch_fault && is_nx(vcpu) && (*ptep & PT64_NX_MASK))
-			goto access_error;
-#endif
-
-		if (!(*ptep & PT_ACCESSED_MASK)) {
-			mark_page_dirty(vcpu->kvm, table_gfn);
-			*ptep |= PT_ACCESSED_MASK;
-		}
-
-		if (walker->level == PT_PAGE_TABLE_LEVEL) {
-			walker->gfn = (*ptep & PT_BASE_ADDR_MASK)
-				>> PAGE_SHIFT;
-			break;
-		}
-
-		if (walker->level == PT_DIRECTORY_LEVEL
-		    && (*ptep & PT_PAGE_SIZE_MASK)
-		    && (PTTYPE == 64 || is_pse(vcpu))) {
-			walker->gfn = (*ptep & PT_DIR_BASE_ADDR_MASK)
-				>> PAGE_SHIFT;
-			walker->gfn += PT_INDEX(addr, PT_PAGE_TABLE_LEVEL);
-			break;
-		}
-
-		walker->inherited_ar &= walker->table[index];
-		table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT;
-		kunmap_atomic(walker->table, KM_USER0);
-		paddr = safe_gpa_to_hpa(vcpu, table_gfn << PAGE_SHIFT);
-		walker->page = pfn_to_page(paddr >> PAGE_SHIFT);
-		walker->table = kmap_atomic(walker->page, KM_USER0);
-		--walker->level;
-		walker->table_gfn[walker->level - 1 ] = table_gfn;
-		pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__,
-			 walker->level - 1, table_gfn);
-	}
-	walker->pte = *ptep;
-	if (walker->page)
-		walker->ptep = NULL;
-	if (walker->table)
-		kunmap_atomic(walker->table, KM_USER0);
-	pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)*ptep);
-	return 1;
-
-not_present:
-	walker->error_code = 0;
-	goto err;
-
-access_error:
-	walker->error_code = PFERR_PRESENT_MASK;
-
-err:
-	if (write_fault)
-		walker->error_code |= PFERR_WRITE_MASK;
-	if (user_fault)
-		walker->error_code |= PFERR_USER_MASK;
-	if (fetch_fault)
-		walker->error_code |= PFERR_FETCH_MASK;
-	if (walker->table)
-		kunmap_atomic(walker->table, KM_USER0);
-	return 0;
-}
-
-static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
-					struct guest_walker *walker)
-{
-	mark_page_dirty(kvm, walker->table_gfn[walker->level - 1]);
-}
-
-static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
-				  u64 *shadow_pte,
-				  gpa_t gaddr,
-				  pt_element_t gpte,
-				  u64 access_bits,
-				  int user_fault,
-				  int write_fault,
-				  int *ptwrite,
-				  struct guest_walker *walker,
-				  gfn_t gfn)
-{
-	hpa_t paddr;
-	int dirty = gpte & PT_DIRTY_MASK;
-	u64 spte = *shadow_pte;
-	int was_rmapped = is_rmap_pte(spte);
-
-	pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d"
-		 " user_fault %d gfn %lx\n",
-		 __FUNCTION__, spte, (u64)gpte, access_bits,
-		 write_fault, user_fault, gfn);
-
-	if (write_fault && !dirty) {
-		pt_element_t *guest_ent, *tmp = NULL;
-
-		if (walker->ptep)
-			guest_ent = walker->ptep;
-		else {
-			tmp = kmap_atomic(walker->page, KM_USER0);
-			guest_ent = &tmp[walker->index];
-		}
-
-		*guest_ent |= PT_DIRTY_MASK;
-		if (!walker->ptep)
-			kunmap_atomic(tmp, KM_USER0);
-		dirty = 1;
-		FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
-	}
-
-	spte |= PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK;
-	spte |= gpte & PT64_NX_MASK;
-	if (!dirty)
-		access_bits &= ~PT_WRITABLE_MASK;
-
-	paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK);
-
-	spte |= PT_PRESENT_MASK;
-	if (access_bits & PT_USER_MASK)
-		spte |= PT_USER_MASK;
-
-	if (is_error_hpa(paddr)) {
-		spte |= gaddr;
-		spte |= PT_SHADOW_IO_MARK;
-		spte &= ~PT_PRESENT_MASK;
-		set_shadow_pte(shadow_pte, spte);
-		return;
-	}
-
-	spte |= paddr;
-
-	if ((access_bits & PT_WRITABLE_MASK)
-	    || (write_fault && !is_write_protection(vcpu) && !user_fault)) {
-		struct kvm_mmu_page *shadow;
-
-		spte |= PT_WRITABLE_MASK;
-		if (user_fault) {
-			mmu_unshadow(vcpu, gfn);
-			goto unshadowed;
-		}
-
-		shadow = kvm_mmu_lookup_page(vcpu, gfn);
-		if (shadow) {
-			pgprintk("%s: found shadow page for %lx, marking ro\n",
-				 __FUNCTION__, gfn);
-			access_bits &= ~PT_WRITABLE_MASK;
-			if (is_writeble_pte(spte)) {
-				spte &= ~PT_WRITABLE_MASK;
-				kvm_x86_ops->tlb_flush(vcpu);
-			}
-			if (write_fault)
-				*ptwrite = 1;
-		}
-	}
-
-unshadowed:
-
-	if (access_bits & PT_WRITABLE_MASK)
-		mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT);
-
-	set_shadow_pte(shadow_pte, spte);
-	page_header_update_slot(vcpu->kvm, shadow_pte, gaddr);
-	if (!was_rmapped)
-		rmap_add(vcpu, shadow_pte);
-}
-
-static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte,
-			   u64 *shadow_pte, u64 access_bits,
-			   int user_fault, int write_fault, int *ptwrite,
-			   struct guest_walker *walker, gfn_t gfn)
-{
-	access_bits &= gpte;
-	FNAME(set_pte_common)(vcpu, shadow_pte, gpte & PT_BASE_ADDR_MASK,
-			      gpte, access_bits, user_fault, write_fault,
-			      ptwrite, walker, gfn);
-}
-
-static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
-			      u64 *spte, const void *pte, int bytes)
-{
-	pt_element_t gpte;
-
-	if (bytes < sizeof(pt_element_t))
-		return;
-	gpte = *(const pt_element_t *)pte;
-	if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK))
-		return;
-	pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte);
-	FNAME(set_pte)(vcpu, gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0,
-		       0, NULL, NULL,
-		       (gpte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT);
-}
-
-static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t gpde,
-			   u64 *shadow_pte, u64 access_bits,
-			   int user_fault, int write_fault, int *ptwrite,
-			   struct guest_walker *walker, gfn_t gfn)
-{
-	gpa_t gaddr;
-
-	access_bits &= gpde;
-	gaddr = (gpa_t)gfn << PAGE_SHIFT;
-	if (PTTYPE == 32 && is_cpuid_PSE36())
-		gaddr |= (gpde & PT32_DIR_PSE36_MASK) <<
-			(32 - PT32_DIR_PSE36_SHIFT);
-	FNAME(set_pte_common)(vcpu, shadow_pte, gaddr,
-			      gpde, access_bits, user_fault, write_fault,
-			      ptwrite, walker, gfn);
-}
-
-/*
- * Fetch a shadow pte for a specific level in the paging hierarchy.
- */
-static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
-			 struct guest_walker *walker,
-			 int user_fault, int write_fault, int *ptwrite)
-{
-	hpa_t shadow_addr;
-	int level;
-	u64 *shadow_ent;
-	u64 *prev_shadow_ent = NULL;
-
-	if (!is_present_pte(walker->pte))
-		return NULL;
-
-	shadow_addr = vcpu->mmu.root_hpa;
-	level = vcpu->mmu.shadow_root_level;
-	if (level == PT32E_ROOT_LEVEL) {
-		shadow_addr = vcpu->mmu.pae_root[(addr >> 30) & 3];
-		shadow_addr &= PT64_BASE_ADDR_MASK;
-		--level;
-	}
-
-	for (; ; level--) {
-		u32 index = SHADOW_PT_INDEX(addr, level);
-		struct kvm_mmu_page *shadow_page;
-		u64 shadow_pte;
-		int metaphysical;
-		gfn_t table_gfn;
-		unsigned hugepage_access = 0;
-
-		shadow_ent = ((u64 *)__va(shadow_addr)) + index;
-		if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) {
-			if (level == PT_PAGE_TABLE_LEVEL)
-				break;
-			shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK;
-			prev_shadow_ent = shadow_ent;
-			continue;
-		}
-
-		if (level == PT_PAGE_TABLE_LEVEL)
-			break;
-
-		if (level - 1 == PT_PAGE_TABLE_LEVEL
-		    && walker->level == PT_DIRECTORY_LEVEL) {
-			metaphysical = 1;
-			hugepage_access = walker->pte;
-			hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
-			if (walker->pte & PT64_NX_MASK)
-				hugepage_access |= (1 << 2);
-			hugepage_access >>= PT_WRITABLE_SHIFT;
-			table_gfn = (walker->pte & PT_BASE_ADDR_MASK)
-				>> PAGE_SHIFT;
-		} else {
-			metaphysical = 0;
-			table_gfn = walker->table_gfn[level - 2];
-		}
-		shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1,
-					       metaphysical, hugepage_access,
-					       shadow_ent);
-		shadow_addr = __pa(shadow_page->spt);
-		shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK
-			| PT_WRITABLE_MASK | PT_USER_MASK;
-		*shadow_ent = shadow_pte;
-		prev_shadow_ent = shadow_ent;
-	}
-
-	if (walker->level == PT_DIRECTORY_LEVEL) {
-		FNAME(set_pde)(vcpu, walker->pte, shadow_ent,
-			       walker->inherited_ar, user_fault, write_fault,
-			       ptwrite, walker, walker->gfn);
-	} else {
-		ASSERT(walker->level == PT_PAGE_TABLE_LEVEL);
-		FNAME(set_pte)(vcpu, walker->pte, shadow_ent,
-			       walker->inherited_ar, user_fault, write_fault,
-			       ptwrite, walker, walker->gfn);
-	}
-	return shadow_ent;
-}
-
-/*
- * Page fault handler.  There are several causes for a page fault:
- *   - there is no shadow pte for the guest pte
- *   - write access through a shadow pte marked read only so that we can set
- *     the dirty bit
- *   - write access to a shadow pte marked read only so we can update the page
- *     dirty bitmap, when userspace requests it
- *   - mmio access; in this case we will never install a present shadow pte
- *   - normal guest page fault due to the guest pte marked not present, not
- *     writable, or not executable
- *
- *  Returns: 1 if we need to emulate the instruction, 0 otherwise, or
- *           a negative value on error.
- */
-static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
-			       u32 error_code)
-{
-	int write_fault = error_code & PFERR_WRITE_MASK;
-	int user_fault = error_code & PFERR_USER_MASK;
-	int fetch_fault = error_code & PFERR_FETCH_MASK;
-	struct guest_walker walker;
-	u64 *shadow_pte;
-	int write_pt = 0;
-	int r;
-
-	pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code);
-	kvm_mmu_audit(vcpu, "pre page fault");
-
-	r = mmu_topup_memory_caches(vcpu);
-	if (r)
-		return r;
-
-	/*
-	 * Look up the shadow pte for the faulting address.
-	 */
-	r = FNAME(walk_addr)(&walker, vcpu, addr, write_fault, user_fault,
-			     fetch_fault);
-
-	/*
-	 * The page is not mapped by the guest.  Let the guest handle it.
-	 */
-	if (!r) {
-		pgprintk("%s: guest page fault\n", __FUNCTION__);
-		inject_page_fault(vcpu, addr, walker.error_code);
-		vcpu->last_pt_write_count = 0; /* reset fork detector */
-		return 0;
-	}
-
-	shadow_pte = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
-				  &write_pt);
-	pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__,
-		 shadow_pte, *shadow_pte, write_pt);
-
-	if (!write_pt)
-		vcpu->last_pt_write_count = 0; /* reset fork detector */
-
-	/*
-	 * mmio: emulate if accessible, otherwise its a guest fault.
-	 */
-	if (is_io_pte(*shadow_pte))
-		return 1;
-
-	++vcpu->stat.pf_fixed;
-	kvm_mmu_audit(vcpu, "post page fault (fixed)");
-
-	return write_pt;
-}
-
-static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr)
-{
-	struct guest_walker walker;
-	gpa_t gpa = UNMAPPED_GVA;
-	int r;
-
-	r = FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0);
-
-	if (r) {
-		gpa = (gpa_t)walker.gfn << PAGE_SHIFT;
-		gpa |= vaddr & ~PAGE_MASK;
-	}
-
-	return gpa;
-}
-
-#undef pt_element_t
-#undef guest_walker
-#undef FNAME
-#undef PT_BASE_ADDR_MASK
-#undef PT_INDEX
-#undef SHADOW_PT_INDEX
-#undef PT_LEVEL_MASK
-#undef PT_DIR_BASE_ADDR_MASK
-#undef PT_MAX_FULL_LEVELS
diff --git a/drivers/kvm/segment_descriptor.h b/drivers/kvm/segment_descriptor.h
deleted file mode 100644
index 71fdf458619a..000000000000
--- a/drivers/kvm/segment_descriptor.h
+++ /dev/null
@@ -1,17 +0,0 @@
-struct segment_descriptor {
-	u16 limit_low;
-	u16 base_low;
-	u8  base_mid;
-	u8  type : 4;
-	u8  system : 1;
-	u8  dpl : 2;
-	u8  present : 1;
-	u8  limit_high : 4;
-	u8  avl : 1;
-	u8  long_mode : 1;
-	u8  default_op : 1;
-	u8  granularity : 1;
-	u8  base_high;
-} __attribute__((packed));
-
-
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
deleted file mode 100644
index 4e04e49a2f1c..000000000000
--- a/drivers/kvm/svm.c
+++ /dev/null
@@ -1,1754 +0,0 @@
-/*
- * Kernel-based Virtual Machine driver for Linux
- *
- * AMD SVM support
- *
- * Copyright (C) 2006 Qumranet, Inc.
- *
- * Authors:
- *   Yaniv Kamay  <yaniv@qumranet.com>
- *   Avi Kivity   <avi@qumranet.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "kvm_svm.h"
-#include "x86_emulate.h"
-#include "irq.h"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/highmem.h>
-#include <linux/sched.h>
-
-#include <asm/desc.h>
-
-MODULE_AUTHOR("Qumranet");
-MODULE_LICENSE("GPL");
-
-#define IOPM_ALLOC_ORDER 2
-#define MSRPM_ALLOC_ORDER 1
-
-#define DB_VECTOR 1
-#define UD_VECTOR 6
-#define GP_VECTOR 13
-
-#define DR7_GD_MASK (1 << 13)
-#define DR6_BD_MASK (1 << 13)
-
-#define SEG_TYPE_LDT 2
-#define SEG_TYPE_BUSY_TSS16 3
-
-#define KVM_EFER_LMA (1 << 10)
-#define KVM_EFER_LME (1 << 8)
-
-#define SVM_FEATURE_NPT  (1 << 0)
-#define SVM_FEATURE_LBRV (1 << 1)
-#define SVM_DEATURE_SVML (1 << 2)
-
-static void kvm_reput_irq(struct vcpu_svm *svm);
-
-static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
-{
-	return container_of(vcpu, struct vcpu_svm, vcpu);
-}
-
-unsigned long iopm_base;
-unsigned long msrpm_base;
-
-struct kvm_ldttss_desc {
-	u16 limit0;
-	u16 base0;
-	unsigned base1 : 8, type : 5, dpl : 2, p : 1;
-	unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
-	u32 base3;
-	u32 zero1;
-} __attribute__((packed));
-
-struct svm_cpu_data {
-	int cpu;
-
-	u64 asid_generation;
-	u32 max_asid;
-	u32 next_asid;
-	struct kvm_ldttss_desc *tss_desc;
-
-	struct page *save_area;
-};
-
-static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
-static uint32_t svm_features;
-
-struct svm_init_data {
-	int cpu;
-	int r;
-};
-
-static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000};
-
-#define NUM_MSR_MAPS ARRAY_SIZE(msrpm_ranges)
-#define MSRS_RANGE_SIZE 2048
-#define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2)
-
-#define MAX_INST_SIZE 15
-
-static inline u32 svm_has(u32 feat)
-{
-	return svm_features & feat;
-}
-
-static inline u8 pop_irq(struct kvm_vcpu *vcpu)
-{
-	int word_index = __ffs(vcpu->irq_summary);
-	int bit_index = __ffs(vcpu->irq_pending[word_index]);
-	int irq = word_index * BITS_PER_LONG + bit_index;
-
-	clear_bit(bit_index, &vcpu->irq_pending[word_index]);
-	if (!vcpu->irq_pending[word_index])
-		clear_bit(word_index, &vcpu->irq_summary);
-	return irq;
-}
-
-static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq)
-{
-	set_bit(irq, vcpu->irq_pending);
-	set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
-}
-
-static inline void clgi(void)
-{
-	asm volatile (SVM_CLGI);
-}
-
-static inline void stgi(void)
-{
-	asm volatile (SVM_STGI);
-}
-
-static inline void invlpga(unsigned long addr, u32 asid)
-{
-	asm volatile (SVM_INVLPGA :: "a"(addr), "c"(asid));
-}
-
-static inline unsigned long kvm_read_cr2(void)
-{
-	unsigned long cr2;
-
-	asm volatile ("mov %%cr2, %0" : "=r" (cr2));
-	return cr2;
-}
-
-static inline void kvm_write_cr2(unsigned long val)
-{
-	asm volatile ("mov %0, %%cr2" :: "r" (val));
-}
-
-static inline unsigned long read_dr6(void)
-{
-	unsigned long dr6;
-
-	asm volatile ("mov %%dr6, %0" : "=r" (dr6));
-	return dr6;
-}
-
-static inline void write_dr6(unsigned long val)
-{
-	asm volatile ("mov %0, %%dr6" :: "r" (val));
-}
-
-static inline unsigned long read_dr7(void)
-{
-	unsigned long dr7;
-
-	asm volatile ("mov %%dr7, %0" : "=r" (dr7));
-	return dr7;
-}
-
-static inline void write_dr7(unsigned long val)
-{
-	asm volatile ("mov %0, %%dr7" :: "r" (val));
-}
-
-static inline void force_new_asid(struct kvm_vcpu *vcpu)
-{
-	to_svm(vcpu)->asid_generation--;
-}
-
-static inline void flush_guest_tlb(struct kvm_vcpu *vcpu)
-{
-	force_new_asid(vcpu);
-}
-
-static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
-{
-	if (!(efer & KVM_EFER_LMA))
-		efer &= ~KVM_EFER_LME;
-
-	to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
-	vcpu->shadow_efer = efer;
-}
-
-static void svm_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	svm->vmcb->control.event_inj =		SVM_EVTINJ_VALID |
-						SVM_EVTINJ_VALID_ERR |
-						SVM_EVTINJ_TYPE_EXEPT |
-						GP_VECTOR;
-	svm->vmcb->control.event_inj_err = error_code;
-}
-
-static void inject_ud(struct kvm_vcpu *vcpu)
-{
-	to_svm(vcpu)->vmcb->control.event_inj = SVM_EVTINJ_VALID |
-						SVM_EVTINJ_TYPE_EXEPT |
-						UD_VECTOR;
-}
-
-static int is_page_fault(uint32_t info)
-{
-	info &= SVM_EVTINJ_VEC_MASK | SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
-	return info == (PF_VECTOR | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_EXEPT);
-}
-
-static int is_external_interrupt(u32 info)
-{
-	info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
-	return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR);
-}
-
-static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	if (!svm->next_rip) {
-		printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__);
-		return;
-	}
-	if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE) {
-		printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n",
-		       __FUNCTION__,
-		       svm->vmcb->save.rip,
-		       svm->next_rip);
-	}
-
-	vcpu->rip = svm->vmcb->save.rip = svm->next_rip;
-	svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
-
-	vcpu->interrupt_window_open = 1;
-}
-
-static int has_svm(void)
-{
-	uint32_t eax, ebx, ecx, edx;
-
-	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
-		printk(KERN_INFO "has_svm: not amd\n");
-		return 0;
-	}
-
-	cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
-	if (eax < SVM_CPUID_FUNC) {
-		printk(KERN_INFO "has_svm: can't execute cpuid_8000000a\n");
-		return 0;
-	}
-
-	cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
-	if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) {
-		printk(KERN_DEBUG "has_svm: svm not available\n");
-		return 0;
-	}
-	return 1;
-}
-
-static void svm_hardware_disable(void *garbage)
-{
-	struct svm_cpu_data *svm_data
-		= per_cpu(svm_data, raw_smp_processor_id());
-
-	if (svm_data) {
-		uint64_t efer;
-
-		wrmsrl(MSR_VM_HSAVE_PA, 0);
-		rdmsrl(MSR_EFER, efer);
-		wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
-		per_cpu(svm_data, raw_smp_processor_id()) = NULL;
-		__free_page(svm_data->save_area);
-		kfree(svm_data);
-	}
-}
-
-static void svm_hardware_enable(void *garbage)
-{
-
-	struct svm_cpu_data *svm_data;
-	uint64_t efer;
-#ifdef CONFIG_X86_64
-	struct desc_ptr gdt_descr;
-#else
-	struct Xgt_desc_struct gdt_descr;
-#endif
-	struct desc_struct *gdt;
-	int me = raw_smp_processor_id();
-
-	if (!has_svm()) {
-		printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me);
-		return;
-	}
-	svm_data = per_cpu(svm_data, me);
-
-	if (!svm_data) {
-		printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n",
-		       me);
-		return;
-	}
-
-	svm_data->asid_generation = 1;
-	svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
-	svm_data->next_asid = svm_data->max_asid + 1;
-	svm_features = cpuid_edx(SVM_CPUID_FUNC);
-
-	asm volatile ( "sgdt %0" : "=m"(gdt_descr) );
-	gdt = (struct desc_struct *)gdt_descr.address;
-	svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS);
-
-	rdmsrl(MSR_EFER, efer);
-	wrmsrl(MSR_EFER, efer | MSR_EFER_SVME_MASK);
-
-	wrmsrl(MSR_VM_HSAVE_PA,
-	       page_to_pfn(svm_data->save_area) << PAGE_SHIFT);
-}
-
-static int svm_cpu_init(int cpu)
-{
-	struct svm_cpu_data *svm_data;
-	int r;
-
-	svm_data = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL);
-	if (!svm_data)
-		return -ENOMEM;
-	svm_data->cpu = cpu;
-	svm_data->save_area = alloc_page(GFP_KERNEL);
-	r = -ENOMEM;
-	if (!svm_data->save_area)
-		goto err_1;
-
-	per_cpu(svm_data, cpu) = svm_data;
-
-	return 0;
-
-err_1:
-	kfree(svm_data);
-	return r;
-
-}
-
-static void set_msr_interception(u32 *msrpm, unsigned msr,
-				 int read, int write)
-{
-	int i;
-
-	for (i = 0; i < NUM_MSR_MAPS; i++) {
-		if (msr >= msrpm_ranges[i] &&
-		    msr < msrpm_ranges[i] + MSRS_IN_RANGE) {
-			u32 msr_offset = (i * MSRS_IN_RANGE + msr -
-					  msrpm_ranges[i]) * 2;
-
-			u32 *base = msrpm + (msr_offset / 32);
-			u32 msr_shift = msr_offset % 32;
-			u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1);
-			*base = (*base & ~(0x3 << msr_shift)) |
-				(mask << msr_shift);
-			return;
-		}
-	}
-	BUG();
-}
-
-static __init int svm_hardware_setup(void)
-{
-	int cpu;
-	struct page *iopm_pages;
-	struct page *msrpm_pages;
-	void *iopm_va, *msrpm_va;
-	int r;
-
-	iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
-
-	if (!iopm_pages)
-		return -ENOMEM;
-
-	iopm_va = page_address(iopm_pages);
-	memset(iopm_va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
-	clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */
-	iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT;
-
-
-	msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER);
-
-	r = -ENOMEM;
-	if (!msrpm_pages)
-		goto err_1;
-
-	msrpm_va = page_address(msrpm_pages);
-	memset(msrpm_va, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER));
-	msrpm_base = page_to_pfn(msrpm_pages) << PAGE_SHIFT;
-
-#ifdef CONFIG_X86_64
-	set_msr_interception(msrpm_va, MSR_GS_BASE, 1, 1);
-	set_msr_interception(msrpm_va, MSR_FS_BASE, 1, 1);
-	set_msr_interception(msrpm_va, MSR_KERNEL_GS_BASE, 1, 1);
-	set_msr_interception(msrpm_va, MSR_LSTAR, 1, 1);
-	set_msr_interception(msrpm_va, MSR_CSTAR, 1, 1);
-	set_msr_interception(msrpm_va, MSR_SYSCALL_MASK, 1, 1);
-#endif
-	set_msr_interception(msrpm_va, MSR_K6_STAR, 1, 1);
-	set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_CS, 1, 1);
-	set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_ESP, 1, 1);
-	set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_EIP, 1, 1);
-
-	for_each_online_cpu(cpu) {
-		r = svm_cpu_init(cpu);
-		if (r)
-			goto err_2;
-	}
-	return 0;
-
-err_2:
-	__free_pages(msrpm_pages, MSRPM_ALLOC_ORDER);
-	msrpm_base = 0;
-err_1:
-	__free_pages(iopm_pages, IOPM_ALLOC_ORDER);
-	iopm_base = 0;
-	return r;
-}
-
-static __exit void svm_hardware_unsetup(void)
-{
-	__free_pages(pfn_to_page(msrpm_base >> PAGE_SHIFT), MSRPM_ALLOC_ORDER);
-	__free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
-	iopm_base = msrpm_base = 0;
-}
-
-static void init_seg(struct vmcb_seg *seg)
-{
-	seg->selector = 0;
-	seg->attrib = SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK |
-		SVM_SELECTOR_WRITE_MASK; /* Read/Write Data Segment */
-	seg->limit = 0xffff;
-	seg->base = 0;
-}
-
-static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
-{
-	seg->selector = 0;
-	seg->attrib = SVM_SELECTOR_P_MASK | type;
-	seg->limit = 0xffff;
-	seg->base = 0;
-}
-
-static void init_vmcb(struct vmcb *vmcb)
-{
-	struct vmcb_control_area *control = &vmcb->control;
-	struct vmcb_save_area *save = &vmcb->save;
-
-	control->intercept_cr_read = 	INTERCEPT_CR0_MASK |
-					INTERCEPT_CR3_MASK |
-					INTERCEPT_CR4_MASK;
-
-	control->intercept_cr_write = 	INTERCEPT_CR0_MASK |
-					INTERCEPT_CR3_MASK |
-					INTERCEPT_CR4_MASK;
-
-	control->intercept_dr_read = 	INTERCEPT_DR0_MASK |
-					INTERCEPT_DR1_MASK |
-					INTERCEPT_DR2_MASK |
-					INTERCEPT_DR3_MASK;
-
-	control->intercept_dr_write = 	INTERCEPT_DR0_MASK |
-					INTERCEPT_DR1_MASK |
-					INTERCEPT_DR2_MASK |
-					INTERCEPT_DR3_MASK |
-					INTERCEPT_DR5_MASK |
-					INTERCEPT_DR7_MASK;
-
-	control->intercept_exceptions = 1 << PF_VECTOR;
-
-
-	control->intercept = 	(1ULL << INTERCEPT_INTR) |
-				(1ULL << INTERCEPT_NMI) |
-				(1ULL << INTERCEPT_SMI) |
-		/*
-		 * selective cr0 intercept bug?
-		 *    	0:   0f 22 d8                mov    %eax,%cr3
-		 *	3:   0f 20 c0                mov    %cr0,%eax
-		 *	6:   0d 00 00 00 80          or     $0x80000000,%eax
-		 *	b:   0f 22 c0                mov    %eax,%cr0
-		 * set cr3 ->interception
-		 * get cr0 ->interception
-		 * set cr0 -> no interception
-		 */
-		/*              (1ULL << INTERCEPT_SELECTIVE_CR0) | */
-				(1ULL << INTERCEPT_CPUID) |
-				(1ULL << INTERCEPT_INVD) |
-				(1ULL << INTERCEPT_HLT) |
-				(1ULL << INTERCEPT_INVLPGA) |
-				(1ULL << INTERCEPT_IOIO_PROT) |
-				(1ULL << INTERCEPT_MSR_PROT) |
-				(1ULL << INTERCEPT_TASK_SWITCH) |
-				(1ULL << INTERCEPT_SHUTDOWN) |
-				(1ULL << INTERCEPT_VMRUN) |
-				(1ULL << INTERCEPT_VMMCALL) |
-				(1ULL << INTERCEPT_VMLOAD) |
-				(1ULL << INTERCEPT_VMSAVE) |
-				(1ULL << INTERCEPT_STGI) |
-				(1ULL << INTERCEPT_CLGI) |
-				(1ULL << INTERCEPT_SKINIT) |
-				(1ULL << INTERCEPT_WBINVD) |
-				(1ULL << INTERCEPT_MONITOR) |
-				(1ULL << INTERCEPT_MWAIT);
-
-	control->iopm_base_pa = iopm_base;
-	control->msrpm_base_pa = msrpm_base;
-	control->tsc_offset = 0;
-	control->int_ctl = V_INTR_MASKING_MASK;
-
-	init_seg(&save->es);
-	init_seg(&save->ss);
-	init_seg(&save->ds);
-	init_seg(&save->fs);
-	init_seg(&save->gs);
-
-	save->cs.selector = 0xf000;
-	/* Executable/Readable Code Segment */
-	save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK |
-		SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK;
-	save->cs.limit = 0xffff;
-	/*
-	 * cs.base should really be 0xffff0000, but vmx can't handle that, so
-	 * be consistent with it.
-	 *
-	 * Replace when we have real mode working for vmx.
-	 */
-	save->cs.base = 0xf0000;
-
-	save->gdtr.limit = 0xffff;
-	save->idtr.limit = 0xffff;
-
-	init_sys_seg(&save->ldtr, SEG_TYPE_LDT);
-	init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16);
-
-	save->efer = MSR_EFER_SVME_MASK;
-
-        save->dr6 = 0xffff0ff0;
-	save->dr7 = 0x400;
-	save->rflags = 2;
-	save->rip = 0x0000fff0;
-
-	/*
-	 * cr0 val on cpu init should be 0x60000010, we enable cpu
-	 * cache by default. the orderly way is to enable cache in bios.
-	 */
-	save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP;
-	save->cr4 = X86_CR4_PAE;
-	/* rdx = ?? */
-}
-
-static void svm_vcpu_reset(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	init_vmcb(svm->vmcb);
-
-	if (vcpu->vcpu_id != 0) {
-		svm->vmcb->save.rip = 0;
-		svm->vmcb->save.cs.base = svm->vcpu.sipi_vector << 12;
-		svm->vmcb->save.cs.selector = svm->vcpu.sipi_vector << 8;
-	}
-}
-
-static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
-{
-	struct vcpu_svm *svm;
-	struct page *page;
-	int err;
-
-	svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
-	if (!svm) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	err = kvm_vcpu_init(&svm->vcpu, kvm, id);
-	if (err)
-		goto free_svm;
-
-	if (irqchip_in_kernel(kvm)) {
-		err = kvm_create_lapic(&svm->vcpu);
-		if (err < 0)
-			goto free_svm;
-	}
-
-	page = alloc_page(GFP_KERNEL);
-	if (!page) {
-		err = -ENOMEM;
-		goto uninit;
-	}
-
-	svm->vmcb = page_address(page);
-	clear_page(svm->vmcb);
-	svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
-	svm->asid_generation = 0;
-	memset(svm->db_regs, 0, sizeof(svm->db_regs));
-	init_vmcb(svm->vmcb);
-
-	fx_init(&svm->vcpu);
-	svm->vcpu.fpu_active = 1;
-	svm->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
-	if (svm->vcpu.vcpu_id == 0)
-		svm->vcpu.apic_base |= MSR_IA32_APICBASE_BSP;
-
-	return &svm->vcpu;
-
-uninit:
-	kvm_vcpu_uninit(&svm->vcpu);
-free_svm:
-	kmem_cache_free(kvm_vcpu_cache, svm);
-out:
-	return ERR_PTR(err);
-}
-
-static void svm_free_vcpu(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	__free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT));
-	kvm_vcpu_uninit(vcpu);
-	kmem_cache_free(kvm_vcpu_cache, svm);
-}
-
-static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-	int i;
-
-	if (unlikely(cpu != vcpu->cpu)) {
-		u64 tsc_this, delta;
-
-		/*
-		 * Make sure that the guest sees a monotonically
-		 * increasing TSC.
-		 */
-		rdtscll(tsc_this);
-		delta = vcpu->host_tsc - tsc_this;
-		svm->vmcb->control.tsc_offset += delta;
-		vcpu->cpu = cpu;
-		kvm_migrate_apic_timer(vcpu);
-	}
-
-	for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
-		rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
-}
-
-static void svm_vcpu_put(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-	int i;
-
-	for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
-		wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
-
-	rdtscll(vcpu->host_tsc);
-	kvm_put_guest_fpu(vcpu);
-}
-
-static void svm_vcpu_decache(struct kvm_vcpu *vcpu)
-{
-}
-
-static void svm_cache_regs(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	vcpu->regs[VCPU_REGS_RAX] = svm->vmcb->save.rax;
-	vcpu->regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
-	vcpu->rip = svm->vmcb->save.rip;
-}
-
-static void svm_decache_regs(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-	svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX];
-	svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP];
-	svm->vmcb->save.rip = vcpu->rip;
-}
-
-static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
-{
-	return to_svm(vcpu)->vmcb->save.rflags;
-}
-
-static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
-{
-	to_svm(vcpu)->vmcb->save.rflags = rflags;
-}
-
-static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg)
-{
-	struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save;
-
-	switch (seg) {
-	case VCPU_SREG_CS: return &save->cs;
-	case VCPU_SREG_DS: return &save->ds;
-	case VCPU_SREG_ES: return &save->es;
-	case VCPU_SREG_FS: return &save->fs;
-	case VCPU_SREG_GS: return &save->gs;
-	case VCPU_SREG_SS: return &save->ss;
-	case VCPU_SREG_TR: return &save->tr;
-	case VCPU_SREG_LDTR: return &save->ldtr;
-	}
-	BUG();
-	return NULL;
-}
-
-static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg)
-{
-	struct vmcb_seg *s = svm_seg(vcpu, seg);
-
-	return s->base;
-}
-
-static void svm_get_segment(struct kvm_vcpu *vcpu,
-			    struct kvm_segment *var, int seg)
-{
-	struct vmcb_seg *s = svm_seg(vcpu, seg);
-
-	var->base = s->base;
-	var->limit = s->limit;
-	var->selector = s->selector;
-	var->type = s->attrib & SVM_SELECTOR_TYPE_MASK;
-	var->s = (s->attrib >> SVM_SELECTOR_S_SHIFT) & 1;
-	var->dpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3;
-	var->present = (s->attrib >> SVM_SELECTOR_P_SHIFT) & 1;
-	var->avl = (s->attrib >> SVM_SELECTOR_AVL_SHIFT) & 1;
-	var->l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1;
-	var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1;
-	var->g = (s->attrib >> SVM_SELECTOR_G_SHIFT) & 1;
-	var->unusable = !var->present;
-}
-
-static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	dt->limit = svm->vmcb->save.idtr.limit;
-	dt->base = svm->vmcb->save.idtr.base;
-}
-
-static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	svm->vmcb->save.idtr.limit = dt->limit;
-	svm->vmcb->save.idtr.base = dt->base ;
-}
-
-static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	dt->limit = svm->vmcb->save.gdtr.limit;
-	dt->base = svm->vmcb->save.gdtr.base;
-}
-
-static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	svm->vmcb->save.gdtr.limit = dt->limit;
-	svm->vmcb->save.gdtr.base = dt->base ;
-}
-
-static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
-{
-}
-
-static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-#ifdef CONFIG_X86_64
-	if (vcpu->shadow_efer & KVM_EFER_LME) {
-		if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
-			vcpu->shadow_efer |= KVM_EFER_LMA;
-			svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME;
-		}
-
-		if (is_paging(vcpu) && !(cr0 & X86_CR0_PG) ) {
-			vcpu->shadow_efer &= ~KVM_EFER_LMA;
-			svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME);
-		}
-	}
-#endif
-	if ((vcpu->cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) {
-		svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
-		vcpu->fpu_active = 1;
-	}
-
-	vcpu->cr0 = cr0;
-	cr0 |= X86_CR0_PG | X86_CR0_WP;
-	cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
-	svm->vmcb->save.cr0 = cr0;
-}
-
-static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
-{
-       vcpu->cr4 = cr4;
-       to_svm(vcpu)->vmcb->save.cr4 = cr4 | X86_CR4_PAE;
-}
-
-static void svm_set_segment(struct kvm_vcpu *vcpu,
-			    struct kvm_segment *var, int seg)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-	struct vmcb_seg *s = svm_seg(vcpu, seg);
-
-	s->base = var->base;
-	s->limit = var->limit;
-	s->selector = var->selector;
-	if (var->unusable)
-		s->attrib = 0;
-	else {
-		s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
-		s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
-		s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
-		s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT;
-		s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
-		s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
-		s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
-		s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
-	}
-	if (seg == VCPU_SREG_CS)
-		svm->vmcb->save.cpl
-			= (svm->vmcb->save.cs.attrib
-			   >> SVM_SELECTOR_DPL_SHIFT) & 3;
-
-}
-
-/* FIXME:
-
-	svm(vcpu)->vmcb->control.int_ctl &= ~V_TPR_MASK;
-	svm(vcpu)->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK);
-
-*/
-
-static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
-{
-	return -EOPNOTSUPP;
-}
-
-static int svm_get_irq(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-	u32 exit_int_info = svm->vmcb->control.exit_int_info;
-
-	if (is_external_interrupt(exit_int_info))
-		return exit_int_info & SVM_EVTINJ_VEC_MASK;
-	return -1;
-}
-
-static void load_host_msrs(struct kvm_vcpu *vcpu)
-{
-#ifdef CONFIG_X86_64
-	wrmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base);
-#endif
-}
-
-static void save_host_msrs(struct kvm_vcpu *vcpu)
-{
-#ifdef CONFIG_X86_64
-	rdmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base);
-#endif
-}
-
-static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data)
-{
-	if (svm_data->next_asid > svm_data->max_asid) {
-		++svm_data->asid_generation;
-		svm_data->next_asid = 1;
-		svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
-	}
-
-	svm->vcpu.cpu = svm_data->cpu;
-	svm->asid_generation = svm_data->asid_generation;
-	svm->vmcb->control.asid = svm_data->next_asid++;
-}
-
-static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
-{
-	return to_svm(vcpu)->db_regs[dr];
-}
-
-static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
-		       int *exception)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	*exception = 0;
-
-	if (svm->vmcb->save.dr7 & DR7_GD_MASK) {
-		svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
-		svm->vmcb->save.dr6 |= DR6_BD_MASK;
-		*exception = DB_VECTOR;
-		return;
-	}
-
-	switch (dr) {
-	case 0 ... 3:
-		svm->db_regs[dr] = value;
-		return;
-	case 4 ... 5:
-		if (vcpu->cr4 & X86_CR4_DE) {
-			*exception = UD_VECTOR;
-			return;
-		}
-	case 7: {
-		if (value & ~((1ULL << 32) - 1)) {
-			*exception = GP_VECTOR;
-			return;
-		}
-		svm->vmcb->save.dr7 = value;
-		return;
-	}
-	default:
-		printk(KERN_DEBUG "%s: unexpected dr %u\n",
-		       __FUNCTION__, dr);
-		*exception = UD_VECTOR;
-		return;
-	}
-}
-
-static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	u32 exit_int_info = svm->vmcb->control.exit_int_info;
-	struct kvm *kvm = svm->vcpu.kvm;
-	u64 fault_address;
-	u32 error_code;
-	enum emulation_result er;
-	int r;
-
-	if (!irqchip_in_kernel(kvm) &&
-		is_external_interrupt(exit_int_info))
-		push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
-
-	mutex_lock(&kvm->lock);
-
-	fault_address  = svm->vmcb->control.exit_info_2;
-	error_code = svm->vmcb->control.exit_info_1;
-	r = kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
-	if (r < 0) {
-		mutex_unlock(&kvm->lock);
-		return r;
-	}
-	if (!r) {
-		mutex_unlock(&kvm->lock);
-		return 1;
-	}
-	er = emulate_instruction(&svm->vcpu, kvm_run, fault_address,
-				 error_code);
-	mutex_unlock(&kvm->lock);
-
-	switch (er) {
-	case EMULATE_DONE:
-		return 1;
-	case EMULATE_DO_MMIO:
-		++svm->vcpu.stat.mmio_exits;
-		return 0;
-	case EMULATE_FAIL:
-		kvm_report_emulation_failure(&svm->vcpu, "pagetable");
-		break;
-	default:
-		BUG();
-	}
-
-	kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
-	return 0;
-}
-
-static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
-	if (!(svm->vcpu.cr0 & X86_CR0_TS))
-		svm->vmcb->save.cr0 &= ~X86_CR0_TS;
-	svm->vcpu.fpu_active = 1;
-
-	return 1;
-}
-
-static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	/*
-	 * VMCB is undefined after a SHUTDOWN intercept
-	 * so reinitialize it.
-	 */
-	clear_page(svm->vmcb);
-	init_vmcb(svm->vmcb);
-
-	kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
-	return 0;
-}
-
-static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	u32 io_info = svm->vmcb->control.exit_info_1; //address size bug?
-	int size, down, in, string, rep;
-	unsigned port;
-
-	++svm->vcpu.stat.io_exits;
-
-	svm->next_rip = svm->vmcb->control.exit_info_2;
-
-	string = (io_info & SVM_IOIO_STR_MASK) != 0;
-
-	if (string) {
-		if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO)
-			return 0;
-		return 1;
-	}
-
-	in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
-	port = io_info >> 16;
-	size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
-	rep = (io_info & SVM_IOIO_REP_MASK) != 0;
-	down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
-
-	return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port);
-}
-
-static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	return 1;
-}
-
-static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	svm->next_rip = svm->vmcb->save.rip + 1;
-	skip_emulated_instruction(&svm->vcpu);
-	return kvm_emulate_halt(&svm->vcpu);
-}
-
-static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	svm->next_rip = svm->vmcb->save.rip + 3;
-	skip_emulated_instruction(&svm->vcpu);
-	return kvm_hypercall(&svm->vcpu, kvm_run);
-}
-
-static int invalid_op_interception(struct vcpu_svm *svm,
-				   struct kvm_run *kvm_run)
-{
-	inject_ud(&svm->vcpu);
-	return 1;
-}
-
-static int task_switch_interception(struct vcpu_svm *svm,
-				    struct kvm_run *kvm_run)
-{
-	pr_unimpl(&svm->vcpu, "%s: task switch is unsupported\n", __FUNCTION__);
-	kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
-	return 0;
-}
-
-static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	svm->next_rip = svm->vmcb->save.rip + 2;
-	kvm_emulate_cpuid(&svm->vcpu);
-	return 1;
-}
-
-static int emulate_on_interception(struct vcpu_svm *svm,
-				   struct kvm_run *kvm_run)
-{
-	if (emulate_instruction(&svm->vcpu, NULL, 0, 0) != EMULATE_DONE)
-		pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__);
-	return 1;
-}
-
-static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	switch (ecx) {
-	case MSR_IA32_TIME_STAMP_COUNTER: {
-		u64 tsc;
-
-		rdtscll(tsc);
-		*data = svm->vmcb->control.tsc_offset + tsc;
-		break;
-	}
-	case MSR_K6_STAR:
-		*data = svm->vmcb->save.star;
-		break;
-#ifdef CONFIG_X86_64
-	case MSR_LSTAR:
-		*data = svm->vmcb->save.lstar;
-		break;
-	case MSR_CSTAR:
-		*data = svm->vmcb->save.cstar;
-		break;
-	case MSR_KERNEL_GS_BASE:
-		*data = svm->vmcb->save.kernel_gs_base;
-		break;
-	case MSR_SYSCALL_MASK:
-		*data = svm->vmcb->save.sfmask;
-		break;
-#endif
-	case MSR_IA32_SYSENTER_CS:
-		*data = svm->vmcb->save.sysenter_cs;
-		break;
-	case MSR_IA32_SYSENTER_EIP:
-		*data = svm->vmcb->save.sysenter_eip;
-		break;
-	case MSR_IA32_SYSENTER_ESP:
-		*data = svm->vmcb->save.sysenter_esp;
-		break;
-	default:
-		return kvm_get_msr_common(vcpu, ecx, data);
-	}
-	return 0;
-}
-
-static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX];
-	u64 data;
-
-	if (svm_get_msr(&svm->vcpu, ecx, &data))
-		svm_inject_gp(&svm->vcpu, 0);
-	else {
-		svm->vmcb->save.rax = data & 0xffffffff;
-		svm->vcpu.regs[VCPU_REGS_RDX] = data >> 32;
-		svm->next_rip = svm->vmcb->save.rip + 2;
-		skip_emulated_instruction(&svm->vcpu);
-	}
-	return 1;
-}
-
-static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	switch (ecx) {
-	case MSR_IA32_TIME_STAMP_COUNTER: {
-		u64 tsc;
-
-		rdtscll(tsc);
-		svm->vmcb->control.tsc_offset = data - tsc;
-		break;
-	}
-	case MSR_K6_STAR:
-		svm->vmcb->save.star = data;
-		break;
-#ifdef CONFIG_X86_64
-	case MSR_LSTAR:
-		svm->vmcb->save.lstar = data;
-		break;
-	case MSR_CSTAR:
-		svm->vmcb->save.cstar = data;
-		break;
-	case MSR_KERNEL_GS_BASE:
-		svm->vmcb->save.kernel_gs_base = data;
-		break;
-	case MSR_SYSCALL_MASK:
-		svm->vmcb->save.sfmask = data;
-		break;
-#endif
-	case MSR_IA32_SYSENTER_CS:
-		svm->vmcb->save.sysenter_cs = data;
-		break;
-	case MSR_IA32_SYSENTER_EIP:
-		svm->vmcb->save.sysenter_eip = data;
-		break;
-	case MSR_IA32_SYSENTER_ESP:
-		svm->vmcb->save.sysenter_esp = data;
-		break;
-	default:
-		return kvm_set_msr_common(vcpu, ecx, data);
-	}
-	return 0;
-}
-
-static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX];
-	u64 data = (svm->vmcb->save.rax & -1u)
-		| ((u64)(svm->vcpu.regs[VCPU_REGS_RDX] & -1u) << 32);
-	svm->next_rip = svm->vmcb->save.rip + 2;
-	if (svm_set_msr(&svm->vcpu, ecx, data))
-		svm_inject_gp(&svm->vcpu, 0);
-	else
-		skip_emulated_instruction(&svm->vcpu);
-	return 1;
-}
-
-static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
-{
-	if (svm->vmcb->control.exit_info_1)
-		return wrmsr_interception(svm, kvm_run);
-	else
-		return rdmsr_interception(svm, kvm_run);
-}
-
-static int interrupt_window_interception(struct vcpu_svm *svm,
-				   struct kvm_run *kvm_run)
-{
-	svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR);
-	svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
-	/*
-	 * If the user space waits to inject interrupts, exit as soon as
-	 * possible
-	 */
-	if (kvm_run->request_interrupt_window &&
-	    !svm->vcpu.irq_summary) {
-		++svm->vcpu.stat.irq_window_exits;
-		kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
-		return 0;
-	}
-
-	return 1;
-}
-
-static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
-				      struct kvm_run *kvm_run) = {
-	[SVM_EXIT_READ_CR0]           		= emulate_on_interception,
-	[SVM_EXIT_READ_CR3]           		= emulate_on_interception,
-	[SVM_EXIT_READ_CR4]           		= emulate_on_interception,
-	/* for now: */
-	[SVM_EXIT_WRITE_CR0]          		= emulate_on_interception,
-	[SVM_EXIT_WRITE_CR3]          		= emulate_on_interception,
-	[SVM_EXIT_WRITE_CR4]          		= emulate_on_interception,
-	[SVM_EXIT_READ_DR0] 			= emulate_on_interception,
-	[SVM_EXIT_READ_DR1]			= emulate_on_interception,
-	[SVM_EXIT_READ_DR2]			= emulate_on_interception,
-	[SVM_EXIT_READ_DR3]			= emulate_on_interception,
-	[SVM_EXIT_WRITE_DR0]			= emulate_on_interception,
-	[SVM_EXIT_WRITE_DR1]			= emulate_on_interception,
-	[SVM_EXIT_WRITE_DR2]			= emulate_on_interception,
-	[SVM_EXIT_WRITE_DR3]			= emulate_on_interception,
-	[SVM_EXIT_WRITE_DR5]			= emulate_on_interception,
-	[SVM_EXIT_WRITE_DR7]			= emulate_on_interception,
-	[SVM_EXIT_EXCP_BASE + PF_VECTOR] 	= pf_interception,
-	[SVM_EXIT_EXCP_BASE + NM_VECTOR] 	= nm_interception,
-	[SVM_EXIT_INTR] 			= nop_on_interception,
-	[SVM_EXIT_NMI]				= nop_on_interception,
-	[SVM_EXIT_SMI]				= nop_on_interception,
-	[SVM_EXIT_INIT]				= nop_on_interception,
-	[SVM_EXIT_VINTR]			= interrupt_window_interception,
-	/* [SVM_EXIT_CR0_SEL_WRITE]		= emulate_on_interception, */
-	[SVM_EXIT_CPUID]			= cpuid_interception,
-	[SVM_EXIT_INVD]                         = emulate_on_interception,
-	[SVM_EXIT_HLT]				= halt_interception,
-	[SVM_EXIT_INVLPG]			= emulate_on_interception,
-	[SVM_EXIT_INVLPGA]			= invalid_op_interception,
-	[SVM_EXIT_IOIO] 		  	= io_interception,
-	[SVM_EXIT_MSR]				= msr_interception,
-	[SVM_EXIT_TASK_SWITCH]			= task_switch_interception,
-	[SVM_EXIT_SHUTDOWN]			= shutdown_interception,
-	[SVM_EXIT_VMRUN]			= invalid_op_interception,
-	[SVM_EXIT_VMMCALL]			= vmmcall_interception,
-	[SVM_EXIT_VMLOAD]			= invalid_op_interception,
-	[SVM_EXIT_VMSAVE]			= invalid_op_interception,
-	[SVM_EXIT_STGI]				= invalid_op_interception,
-	[SVM_EXIT_CLGI]				= invalid_op_interception,
-	[SVM_EXIT_SKINIT]			= invalid_op_interception,
-	[SVM_EXIT_WBINVD]                       = emulate_on_interception,
-	[SVM_EXIT_MONITOR]			= invalid_op_interception,
-	[SVM_EXIT_MWAIT]			= invalid_op_interception,
-};
-
-
-static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-	u32 exit_code = svm->vmcb->control.exit_code;
-
-	kvm_reput_irq(svm);
-
-	if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
-		kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
-		kvm_run->fail_entry.hardware_entry_failure_reason
-			= svm->vmcb->control.exit_code;
-		return 0;
-	}
-
-	if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
-	    exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR)
-		printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
-		       "exit_code 0x%x\n",
-		       __FUNCTION__, svm->vmcb->control.exit_int_info,
-		       exit_code);
-
-	if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
-	    || svm_exit_handlers[exit_code] == 0) {
-		kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
-		kvm_run->hw.hardware_exit_reason = exit_code;
-		return 0;
-	}
-
-	return svm_exit_handlers[exit_code](svm, kvm_run);
-}
-
-static void reload_tss(struct kvm_vcpu *vcpu)
-{
-	int cpu = raw_smp_processor_id();
-
-	struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
-	svm_data->tss_desc->type = 9; //available 32/64-bit TSS
-	load_TR_desc();
-}
-
-static void pre_svm_run(struct vcpu_svm *svm)
-{
-	int cpu = raw_smp_processor_id();
-
-	struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
-
-	svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
-	if (svm->vcpu.cpu != cpu ||
-	    svm->asid_generation != svm_data->asid_generation)
-		new_asid(svm, svm_data);
-}
-
-
-static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
-{
-	struct vmcb_control_area *control;
-
-	control = &svm->vmcb->control;
-	control->int_vector = irq;
-	control->int_ctl &= ~V_INTR_PRIO_MASK;
-	control->int_ctl |= V_IRQ_MASK |
-		((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
-}
-
-static void svm_set_irq(struct kvm_vcpu *vcpu, int irq)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	svm_inject_irq(svm, irq);
-}
-
-static void svm_intr_assist(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-	struct vmcb *vmcb = svm->vmcb;
-	int intr_vector = -1;
-
-	kvm_inject_pending_timer_irqs(vcpu);
-	if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) &&
-	    ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) {
-		intr_vector = vmcb->control.exit_int_info &
-			      SVM_EVTINJ_VEC_MASK;
-		vmcb->control.exit_int_info = 0;
-		svm_inject_irq(svm, intr_vector);
-		return;
-	}
-
-	if (vmcb->control.int_ctl & V_IRQ_MASK)
-		return;
-
-	if (!kvm_cpu_has_interrupt(vcpu))
-		return;
-
-	if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
-	    (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
-	    (vmcb->control.event_inj & SVM_EVTINJ_VALID)) {
-		/* unable to deliver irq, set pending irq */
-		vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR);
-		svm_inject_irq(svm, 0x0);
-		return;
-	}
-	/* Okay, we can deliver the interrupt: grab it and update PIC state. */
-	intr_vector = kvm_cpu_get_interrupt(vcpu);
-	svm_inject_irq(svm, intr_vector);
-	kvm_timer_intr_post(vcpu, intr_vector);
-}
-
-static void kvm_reput_irq(struct vcpu_svm *svm)
-{
-	struct vmcb_control_area *control = &svm->vmcb->control;
-
-	if ((control->int_ctl & V_IRQ_MASK)
-	    && !irqchip_in_kernel(svm->vcpu.kvm)) {
-		control->int_ctl &= ~V_IRQ_MASK;
-		push_irq(&svm->vcpu, control->int_vector);
-	}
-
-	svm->vcpu.interrupt_window_open =
-		!(control->int_state & SVM_INTERRUPT_SHADOW_MASK);
-}
-
-static void svm_do_inject_vector(struct vcpu_svm *svm)
-{
-	struct kvm_vcpu *vcpu = &svm->vcpu;
-	int word_index = __ffs(vcpu->irq_summary);
-	int bit_index = __ffs(vcpu->irq_pending[word_index]);
-	int irq = word_index * BITS_PER_LONG + bit_index;
-
-	clear_bit(bit_index, &vcpu->irq_pending[word_index]);
-	if (!vcpu->irq_pending[word_index])
-		clear_bit(word_index, &vcpu->irq_summary);
-	svm_inject_irq(svm, irq);
-}
-
-static void do_interrupt_requests(struct kvm_vcpu *vcpu,
-				       struct kvm_run *kvm_run)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-	struct vmcb_control_area *control = &svm->vmcb->control;
-
-	svm->vcpu.interrupt_window_open =
-		(!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
-		 (svm->vmcb->save.rflags & X86_EFLAGS_IF));
-
-	if (svm->vcpu.interrupt_window_open && svm->vcpu.irq_summary)
-		/*
-		 * If interrupts enabled, and not blocked by sti or mov ss. Good.
-		 */
-		svm_do_inject_vector(svm);
-
-	/*
-	 * Interrupts blocked.  Wait for unblock.
-	 */
-	if (!svm->vcpu.interrupt_window_open &&
-	    (svm->vcpu.irq_summary || kvm_run->request_interrupt_window)) {
-		control->intercept |= 1ULL << INTERCEPT_VINTR;
-	} else
-		control->intercept &= ~(1ULL << INTERCEPT_VINTR);
-}
-
-static void save_db_regs(unsigned long *db_regs)
-{
-	asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0]));
-	asm volatile ("mov %%dr1, %0" : "=r"(db_regs[1]));
-	asm volatile ("mov %%dr2, %0" : "=r"(db_regs[2]));
-	asm volatile ("mov %%dr3, %0" : "=r"(db_regs[3]));
-}
-
-static void load_db_regs(unsigned long *db_regs)
-{
-	asm volatile ("mov %0, %%dr0" : : "r"(db_regs[0]));
-	asm volatile ("mov %0, %%dr1" : : "r"(db_regs[1]));
-	asm volatile ("mov %0, %%dr2" : : "r"(db_regs[2]));
-	asm volatile ("mov %0, %%dr3" : : "r"(db_regs[3]));
-}
-
-static void svm_flush_tlb(struct kvm_vcpu *vcpu)
-{
-	force_new_asid(vcpu);
-}
-
-static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
-{
-}
-
-static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-	u16 fs_selector;
-	u16 gs_selector;
-	u16 ldt_selector;
-
-	pre_svm_run(svm);
-
-	save_host_msrs(vcpu);
-	fs_selector = read_fs();
-	gs_selector = read_gs();
-	ldt_selector = read_ldt();
-	svm->host_cr2 = kvm_read_cr2();
-	svm->host_dr6 = read_dr6();
-	svm->host_dr7 = read_dr7();
-	svm->vmcb->save.cr2 = vcpu->cr2;
-
-	if (svm->vmcb->save.dr7 & 0xff) {
-		write_dr7(0);
-		save_db_regs(svm->host_db_regs);
-		load_db_regs(svm->db_regs);
-	}
-
-	clgi();
-
-	local_irq_enable();
-
-	asm volatile (
-#ifdef CONFIG_X86_64
-		"push %%rbx; push %%rcx; push %%rdx;"
-		"push %%rsi; push %%rdi; push %%rbp;"
-		"push %%r8;  push %%r9;  push %%r10; push %%r11;"
-		"push %%r12; push %%r13; push %%r14; push %%r15;"
-#else
-		"push %%ebx; push %%ecx; push %%edx;"
-		"push %%esi; push %%edi; push %%ebp;"
-#endif
-
-#ifdef CONFIG_X86_64
-		"mov %c[rbx](%[svm]), %%rbx \n\t"
-		"mov %c[rcx](%[svm]), %%rcx \n\t"
-		"mov %c[rdx](%[svm]), %%rdx \n\t"
-		"mov %c[rsi](%[svm]), %%rsi \n\t"
-		"mov %c[rdi](%[svm]), %%rdi \n\t"
-		"mov %c[rbp](%[svm]), %%rbp \n\t"
-		"mov %c[r8](%[svm]),  %%r8  \n\t"
-		"mov %c[r9](%[svm]),  %%r9  \n\t"
-		"mov %c[r10](%[svm]), %%r10 \n\t"
-		"mov %c[r11](%[svm]), %%r11 \n\t"
-		"mov %c[r12](%[svm]), %%r12 \n\t"
-		"mov %c[r13](%[svm]), %%r13 \n\t"
-		"mov %c[r14](%[svm]), %%r14 \n\t"
-		"mov %c[r15](%[svm]), %%r15 \n\t"
-#else
-		"mov %c[rbx](%[svm]), %%ebx \n\t"
-		"mov %c[rcx](%[svm]), %%ecx \n\t"
-		"mov %c[rdx](%[svm]), %%edx \n\t"
-		"mov %c[rsi](%[svm]), %%esi \n\t"
-		"mov %c[rdi](%[svm]), %%edi \n\t"
-		"mov %c[rbp](%[svm]), %%ebp \n\t"
-#endif
-
-#ifdef CONFIG_X86_64
-		/* Enter guest mode */
-		"push %%rax \n\t"
-		"mov %c[vmcb](%[svm]), %%rax \n\t"
-		SVM_VMLOAD "\n\t"
-		SVM_VMRUN "\n\t"
-		SVM_VMSAVE "\n\t"
-		"pop %%rax \n\t"
-#else
-		/* Enter guest mode */
-		"push %%eax \n\t"
-		"mov %c[vmcb](%[svm]), %%eax \n\t"
-		SVM_VMLOAD "\n\t"
-		SVM_VMRUN "\n\t"
-		SVM_VMSAVE "\n\t"
-		"pop %%eax \n\t"
-#endif
-
-		/* Save guest registers, load host registers */
-#ifdef CONFIG_X86_64
-		"mov %%rbx, %c[rbx](%[svm]) \n\t"
-		"mov %%rcx, %c[rcx](%[svm]) \n\t"
-		"mov %%rdx, %c[rdx](%[svm]) \n\t"
-		"mov %%rsi, %c[rsi](%[svm]) \n\t"
-		"mov %%rdi, %c[rdi](%[svm]) \n\t"
-		"mov %%rbp, %c[rbp](%[svm]) \n\t"
-		"mov %%r8,  %c[r8](%[svm]) \n\t"
-		"mov %%r9,  %c[r9](%[svm]) \n\t"
-		"mov %%r10, %c[r10](%[svm]) \n\t"
-		"mov %%r11, %c[r11](%[svm]) \n\t"
-		"mov %%r12, %c[r12](%[svm]) \n\t"
-		"mov %%r13, %c[r13](%[svm]) \n\t"
-		"mov %%r14, %c[r14](%[svm]) \n\t"
-		"mov %%r15, %c[r15](%[svm]) \n\t"
-
-		"pop  %%r15; pop  %%r14; pop  %%r13; pop  %%r12;"
-		"pop  %%r11; pop  %%r10; pop  %%r9;  pop  %%r8;"
-		"pop  %%rbp; pop  %%rdi; pop  %%rsi;"
-		"pop  %%rdx; pop  %%rcx; pop  %%rbx; \n\t"
-#else
-		"mov %%ebx, %c[rbx](%[svm]) \n\t"
-		"mov %%ecx, %c[rcx](%[svm]) \n\t"
-		"mov %%edx, %c[rdx](%[svm]) \n\t"
-		"mov %%esi, %c[rsi](%[svm]) \n\t"
-		"mov %%edi, %c[rdi](%[svm]) \n\t"
-		"mov %%ebp, %c[rbp](%[svm]) \n\t"
-
-		"pop  %%ebp; pop  %%edi; pop  %%esi;"
-		"pop  %%edx; pop  %%ecx; pop  %%ebx; \n\t"
-#endif
-		:
-		: [svm]"a"(svm),
-		  [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)),
-		  [rbx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBX])),
-		  [rcx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RCX])),
-		  [rdx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDX])),
-		  [rsi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RSI])),
-		  [rdi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDI])),
-		  [rbp]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBP]))
-#ifdef CONFIG_X86_64
-		  ,[r8 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R8])),
-		  [r9 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R9 ])),
-		  [r10]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R10])),
-		  [r11]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R11])),
-		  [r12]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R12])),
-		  [r13]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R13])),
-		  [r14]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R14])),
-		  [r15]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R15]))
-#endif
-		: "cc", "memory" );
-
-	if ((svm->vmcb->save.dr7 & 0xff))
-		load_db_regs(svm->host_db_regs);
-
-	vcpu->cr2 = svm->vmcb->save.cr2;
-
-	write_dr6(svm->host_dr6);
-	write_dr7(svm->host_dr7);
-	kvm_write_cr2(svm->host_cr2);
-
-	load_fs(fs_selector);
-	load_gs(gs_selector);
-	load_ldt(ldt_selector);
-	load_host_msrs(vcpu);
-
-	reload_tss(vcpu);
-
-	local_irq_disable();
-
-	stgi();
-
-	svm->next_rip = 0;
-}
-
-static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-
-	svm->vmcb->save.cr3 = root;
-	force_new_asid(vcpu);
-
-	if (vcpu->fpu_active) {
-		svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
-		svm->vmcb->save.cr0 |= X86_CR0_TS;
-		vcpu->fpu_active = 0;
-	}
-}
-
-static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
-				  unsigned long  addr,
-				  uint32_t err_code)
-{
-	struct vcpu_svm *svm = to_svm(vcpu);
-	uint32_t exit_int_info = svm->vmcb->control.exit_int_info;
-
-	++vcpu->stat.pf_guest;
-
-	if (is_page_fault(exit_int_info)) {
-
-		svm->vmcb->control.event_inj_err = 0;
-		svm->vmcb->control.event_inj = 	SVM_EVTINJ_VALID |
-						SVM_EVTINJ_VALID_ERR |
-						SVM_EVTINJ_TYPE_EXEPT |
-						DF_VECTOR;
-		return;
-	}
-	vcpu->cr2 = addr;
-	svm->vmcb->save.cr2 = addr;
-	svm->vmcb->control.event_inj = 	SVM_EVTINJ_VALID |
-					SVM_EVTINJ_VALID_ERR |
-					SVM_EVTINJ_TYPE_EXEPT |
-					PF_VECTOR;
-	svm->vmcb->control.event_inj_err = err_code;
-}
-
-
-static int is_disabled(void)
-{
-	u64 vm_cr;
-
-	rdmsrl(MSR_VM_CR, vm_cr);
-	if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE))
-		return 1;
-
-	return 0;
-}
-
-static void
-svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
-{
-	/*
-	 * Patch in the VMMCALL instruction:
-	 */
-	hypercall[0] = 0x0f;
-	hypercall[1] = 0x01;
-	hypercall[2] = 0xd9;
-	hypercall[3] = 0xc3;
-}
-
-static void svm_check_processor_compat(void *rtn)
-{
-	*(int *)rtn = 0;
-}
-
-static struct kvm_x86_ops svm_x86_ops = {
-	.cpu_has_kvm_support = has_svm,
-	.disabled_by_bios = is_disabled,
-	.hardware_setup = svm_hardware_setup,
-	.hardware_unsetup = svm_hardware_unsetup,
-	.check_processor_compatibility = svm_check_processor_compat,
-	.hardware_enable = svm_hardware_enable,
-	.hardware_disable = svm_hardware_disable,
-
-	.vcpu_create = svm_create_vcpu,
-	.vcpu_free = svm_free_vcpu,
-	.vcpu_reset = svm_vcpu_reset,
-
-	.prepare_guest_switch = svm_prepare_guest_switch,
-	.vcpu_load = svm_vcpu_load,
-	.vcpu_put = svm_vcpu_put,
-	.vcpu_decache = svm_vcpu_decache,
-
-	.set_guest_debug = svm_guest_debug,
-	.get_msr = svm_get_msr,
-	.set_msr = svm_set_msr,
-	.get_segment_base = svm_get_segment_base,
-	.get_segment = svm_get_segment,
-	.set_segment = svm_set_segment,
-	.get_cs_db_l_bits = kvm_get_cs_db_l_bits,
-	.decache_cr4_guest_bits = svm_decache_cr4_guest_bits,
-	.set_cr0 = svm_set_cr0,
-	.set_cr3 = svm_set_cr3,
-	.set_cr4 = svm_set_cr4,
-	.set_efer = svm_set_efer,
-	.get_idt = svm_get_idt,
-	.set_idt = svm_set_idt,
-	.get_gdt = svm_get_gdt,
-	.set_gdt = svm_set_gdt,
-	.get_dr = svm_get_dr,
-	.set_dr = svm_set_dr,
-	.cache_regs = svm_cache_regs,
-	.decache_regs = svm_decache_regs,
-	.get_rflags = svm_get_rflags,
-	.set_rflags = svm_set_rflags,
-
-	.tlb_flush = svm_flush_tlb,
-	.inject_page_fault = svm_inject_page_fault,
-
-	.inject_gp = svm_inject_gp,
-
-	.run = svm_vcpu_run,
-	.handle_exit = handle_exit,
-	.skip_emulated_instruction = skip_emulated_instruction,
-	.patch_hypercall = svm_patch_hypercall,
-	.get_irq = svm_get_irq,
-	.set_irq = svm_set_irq,
-	.inject_pending_irq = svm_intr_assist,
-	.inject_pending_vectors = do_interrupt_requests,
-};
-
-static int __init svm_init(void)
-{
-	return kvm_init_x86(&svm_x86_ops, sizeof(struct vcpu_svm),
-			      THIS_MODULE);
-}
-
-static void __exit svm_exit(void)
-{
-	kvm_exit_x86();
-}
-
-module_init(svm_init)
-module_exit(svm_exit)
diff --git a/drivers/kvm/svm.h b/drivers/kvm/svm.h
deleted file mode 100644
index 3b1b0f35b6cb..000000000000
--- a/drivers/kvm/svm.h
+++ /dev/null
@@ -1,324 +0,0 @@
-#ifndef __SVM_H
-#define __SVM_H
-
-enum {
-	INTERCEPT_INTR,
-	INTERCEPT_NMI,
-	INTERCEPT_SMI,
-	INTERCEPT_INIT,
-	INTERCEPT_VINTR,
-	INTERCEPT_SELECTIVE_CR0,
-	INTERCEPT_STORE_IDTR,
-	INTERCEPT_STORE_GDTR,
-	INTERCEPT_STORE_LDTR,
-	INTERCEPT_STORE_TR,
-	INTERCEPT_LOAD_IDTR,
-	INTERCEPT_LOAD_GDTR,
-	INTERCEPT_LOAD_LDTR,
-	INTERCEPT_LOAD_TR,
-	INTERCEPT_RDTSC,
-	INTERCEPT_RDPMC,
-	INTERCEPT_PUSHF,
-	INTERCEPT_POPF,
-	INTERCEPT_CPUID,
-	INTERCEPT_RSM,
-	INTERCEPT_IRET,
-	INTERCEPT_INTn,
-	INTERCEPT_INVD,
-	INTERCEPT_PAUSE,
-	INTERCEPT_HLT,
-	INTERCEPT_INVLPG,
-	INTERCEPT_INVLPGA,
-	INTERCEPT_IOIO_PROT,
-	INTERCEPT_MSR_PROT,
-	INTERCEPT_TASK_SWITCH,
-	INTERCEPT_FERR_FREEZE,
-	INTERCEPT_SHUTDOWN,
-	INTERCEPT_VMRUN,
-	INTERCEPT_VMMCALL,
-	INTERCEPT_VMLOAD,
-	INTERCEPT_VMSAVE,
-	INTERCEPT_STGI,
-	INTERCEPT_CLGI,
-	INTERCEPT_SKINIT,
-	INTERCEPT_RDTSCP,
-	INTERCEPT_ICEBP,
-	INTERCEPT_WBINVD,
-	INTERCEPT_MONITOR,
-	INTERCEPT_MWAIT,
-	INTERCEPT_MWAIT_COND,
-};
-
-
-struct __attribute__ ((__packed__)) vmcb_control_area {
-	u16 intercept_cr_read;
-	u16 intercept_cr_write;
-	u16 intercept_dr_read;
-	u16 intercept_dr_write;
-	u32 intercept_exceptions;
-	u64 intercept;
-	u8 reserved_1[44];
-	u64 iopm_base_pa;
-	u64 msrpm_base_pa;
-	u64 tsc_offset;
-	u32 asid;
-	u8 tlb_ctl;
-	u8 reserved_2[3];
-	u32 int_ctl;
-	u32 int_vector;
-	u32 int_state;
-	u8 reserved_3[4];
-	u32 exit_code;
-	u32 exit_code_hi;
-	u64 exit_info_1;
-	u64 exit_info_2;
-	u32 exit_int_info;
-	u32 exit_int_info_err;
-	u64 nested_ctl;
-	u8 reserved_4[16];
-	u32 event_inj;
-	u32 event_inj_err;
-	u64 nested_cr3;
-	u64 lbr_ctl;
-	u8 reserved_5[832];
-};
-
-
-#define TLB_CONTROL_DO_NOTHING 0
-#define TLB_CONTROL_FLUSH_ALL_ASID 1
-
-#define V_TPR_MASK 0x0f
-
-#define V_IRQ_SHIFT 8
-#define V_IRQ_MASK (1 << V_IRQ_SHIFT)
-
-#define V_INTR_PRIO_SHIFT 16
-#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT)
-
-#define V_IGN_TPR_SHIFT 20
-#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT)
-
-#define V_INTR_MASKING_SHIFT 24
-#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
-
-#define SVM_INTERRUPT_SHADOW_MASK 1
-
-#define SVM_IOIO_STR_SHIFT 2
-#define SVM_IOIO_REP_SHIFT 3
-#define SVM_IOIO_SIZE_SHIFT 4
-#define SVM_IOIO_ASIZE_SHIFT 7
-
-#define SVM_IOIO_TYPE_MASK 1
-#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT)
-#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT)
-#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT)
-#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT)
-
-struct __attribute__ ((__packed__)) vmcb_seg {
-	u16 selector;
-	u16 attrib;
-	u32 limit;
-	u64 base;
-};
-
-struct __attribute__ ((__packed__)) vmcb_save_area {
-	struct vmcb_seg es;
-	struct vmcb_seg cs;
-	struct vmcb_seg ss;
-	struct vmcb_seg ds;
-	struct vmcb_seg fs;
-	struct vmcb_seg gs;
-	struct vmcb_seg gdtr;
-	struct vmcb_seg ldtr;
-	struct vmcb_seg idtr;
-	struct vmcb_seg tr;
-	u8 reserved_1[43];
-	u8 cpl;
-	u8 reserved_2[4];
-	u64 efer;
-	u8 reserved_3[112];
-	u64 cr4;
-	u64 cr3;
-	u64 cr0;
-	u64 dr7;
-	u64 dr6;
-	u64 rflags;
-	u64 rip;
-	u8 reserved_4[88];
-	u64 rsp;
-	u8 reserved_5[24];
-	u64 rax;
-	u64 star;
-	u64 lstar;
-	u64 cstar;
-	u64 sfmask;
-	u64 kernel_gs_base;
-	u64 sysenter_cs;
-	u64 sysenter_esp;
-	u64 sysenter_eip;
-	u64 cr2;
-	u8 reserved_6[32];
-	u64 g_pat;
-	u64 dbgctl;
-	u64 br_from;
-	u64 br_to;
-	u64 last_excp_from;
-	u64 last_excp_to;
-};
-
-struct __attribute__ ((__packed__)) vmcb {
-	struct vmcb_control_area control;
-	struct vmcb_save_area save;
-};
-
-#define SVM_CPUID_FEATURE_SHIFT 2
-#define SVM_CPUID_FUNC 0x8000000a
-
-#define MSR_EFER_SVME_MASK (1ULL << 12)
-#define MSR_VM_CR       0xc0010114
-#define MSR_VM_HSAVE_PA 0xc0010117ULL
-
-#define SVM_VM_CR_SVM_DISABLE 4
-
-#define SVM_SELECTOR_S_SHIFT 4
-#define SVM_SELECTOR_DPL_SHIFT 5
-#define SVM_SELECTOR_P_SHIFT 7
-#define SVM_SELECTOR_AVL_SHIFT 8
-#define SVM_SELECTOR_L_SHIFT 9
-#define SVM_SELECTOR_DB_SHIFT 10
-#define SVM_SELECTOR_G_SHIFT 11
-
-#define SVM_SELECTOR_TYPE_MASK (0xf)
-#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT)
-#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT)
-#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT)
-#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT)
-#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT)
-#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT)
-#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT)
-
-#define SVM_SELECTOR_WRITE_MASK (1 << 1)
-#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK
-#define SVM_SELECTOR_CODE_MASK (1 << 3)
-
-#define INTERCEPT_CR0_MASK 1
-#define INTERCEPT_CR3_MASK (1 << 3)
-#define INTERCEPT_CR4_MASK (1 << 4)
-
-#define INTERCEPT_DR0_MASK 1
-#define INTERCEPT_DR1_MASK (1 << 1)
-#define INTERCEPT_DR2_MASK (1 << 2)
-#define INTERCEPT_DR3_MASK (1 << 3)
-#define INTERCEPT_DR4_MASK (1 << 4)
-#define INTERCEPT_DR5_MASK (1 << 5)
-#define INTERCEPT_DR6_MASK (1 << 6)
-#define INTERCEPT_DR7_MASK (1 << 7)
-
-#define SVM_EVTINJ_VEC_MASK 0xff
-
-#define SVM_EVTINJ_TYPE_SHIFT 8
-#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT)
-
-#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT)
-#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT)
-#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT)
-#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT)
-
-#define SVM_EVTINJ_VALID (1 << 31)
-#define SVM_EVTINJ_VALID_ERR (1 << 11)
-
-#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
-
-#define	SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR
-#define	SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI
-#define	SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT
-#define	SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT
-
-#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID
-#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR
-
-#define	SVM_EXIT_READ_CR0 	0x000
-#define	SVM_EXIT_READ_CR3 	0x003
-#define	SVM_EXIT_READ_CR4 	0x004
-#define	SVM_EXIT_READ_CR8 	0x008
-#define	SVM_EXIT_WRITE_CR0 	0x010
-#define	SVM_EXIT_WRITE_CR3 	0x013
-#define	SVM_EXIT_WRITE_CR4 	0x014
-#define	SVM_EXIT_WRITE_CR8 	0x018
-#define	SVM_EXIT_READ_DR0 	0x020
-#define	SVM_EXIT_READ_DR1 	0x021
-#define	SVM_EXIT_READ_DR2 	0x022
-#define	SVM_EXIT_READ_DR3 	0x023
-#define	SVM_EXIT_READ_DR4 	0x024
-#define	SVM_EXIT_READ_DR5 	0x025
-#define	SVM_EXIT_READ_DR6 	0x026
-#define	SVM_EXIT_READ_DR7 	0x027
-#define	SVM_EXIT_WRITE_DR0 	0x030
-#define	SVM_EXIT_WRITE_DR1 	0x031
-#define	SVM_EXIT_WRITE_DR2 	0x032
-#define	SVM_EXIT_WRITE_DR3 	0x033
-#define	SVM_EXIT_WRITE_DR4 	0x034
-#define	SVM_EXIT_WRITE_DR5 	0x035
-#define	SVM_EXIT_WRITE_DR6 	0x036
-#define	SVM_EXIT_WRITE_DR7 	0x037
-#define SVM_EXIT_EXCP_BASE      0x040
-#define SVM_EXIT_INTR		0x060
-#define SVM_EXIT_NMI		0x061
-#define SVM_EXIT_SMI		0x062
-#define SVM_EXIT_INIT		0x063
-#define SVM_EXIT_VINTR		0x064
-#define SVM_EXIT_CR0_SEL_WRITE	0x065
-#define SVM_EXIT_IDTR_READ	0x066
-#define SVM_EXIT_GDTR_READ	0x067
-#define SVM_EXIT_LDTR_READ	0x068
-#define SVM_EXIT_TR_READ	0x069
-#define SVM_EXIT_IDTR_WRITE	0x06a
-#define SVM_EXIT_GDTR_WRITE	0x06b
-#define SVM_EXIT_LDTR_WRITE	0x06c
-#define SVM_EXIT_TR_WRITE	0x06d
-#define SVM_EXIT_RDTSC		0x06e
-#define SVM_EXIT_RDPMC		0x06f
-#define SVM_EXIT_PUSHF		0x070
-#define SVM_EXIT_POPF		0x071
-#define SVM_EXIT_CPUID		0x072
-#define SVM_EXIT_RSM		0x073
-#define SVM_EXIT_IRET		0x074
-#define SVM_EXIT_SWINT		0x075
-#define SVM_EXIT_INVD		0x076
-#define SVM_EXIT_PAUSE		0x077
-#define SVM_EXIT_HLT		0x078
-#define SVM_EXIT_INVLPG		0x079
-#define SVM_EXIT_INVLPGA	0x07a
-#define SVM_EXIT_IOIO		0x07b
-#define SVM_EXIT_MSR		0x07c
-#define SVM_EXIT_TASK_SWITCH	0x07d
-#define SVM_EXIT_FERR_FREEZE	0x07e
-#define SVM_EXIT_SHUTDOWN	0x07f
-#define SVM_EXIT_VMRUN		0x080
-#define SVM_EXIT_VMMCALL	0x081
-#define SVM_EXIT_VMLOAD		0x082
-#define SVM_EXIT_VMSAVE		0x083
-#define SVM_EXIT_STGI		0x084
-#define SVM_EXIT_CLGI		0x085
-#define SVM_EXIT_SKINIT		0x086
-#define SVM_EXIT_RDTSCP		0x087
-#define SVM_EXIT_ICEBP		0x088
-#define SVM_EXIT_WBINVD		0x089
-#define SVM_EXIT_MONITOR	0x08a
-#define SVM_EXIT_MWAIT		0x08b
-#define SVM_EXIT_MWAIT_COND	0x08c
-#define SVM_EXIT_NPF  		0x400
-
-#define SVM_EXIT_ERR		-1
-
-#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) // TS and MP
-
-#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda"
-#define SVM_VMRUN  ".byte 0x0f, 0x01, 0xd8"
-#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb"
-#define SVM_CLGI   ".byte 0x0f, 0x01, 0xdd"
-#define SVM_STGI   ".byte 0x0f, 0x01, 0xdc"
-#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf"
-
-#endif
-
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
deleted file mode 100644
index bb56ae3f89b6..000000000000
--- a/drivers/kvm/vmx.c
+++ /dev/null
@@ -1,2566 +0,0 @@
-/*
- * Kernel-based Virtual Machine driver for Linux
- *
- * This module enables machines with Intel VT-x extensions to run virtual
- * machines without emulation or binary translation.
- *
- * Copyright (C) 2006 Qumranet, Inc.
- *
- * Authors:
- *   Avi Kivity   <avi@qumranet.com>
- *   Yaniv Kamay  <yaniv@qumranet.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "kvm.h"
-#include "x86_emulate.h"
-#include "irq.h"
-#include "vmx.h"
-#include "segment_descriptor.h"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/sched.h>
-
-#include <asm/io.h>
-#include <asm/desc.h>
-
-MODULE_AUTHOR("Qumranet");
-MODULE_LICENSE("GPL");
-
-struct vmcs {
-	u32 revision_id;
-	u32 abort;
-	char data[0];
-};
-
-struct vcpu_vmx {
-	struct kvm_vcpu       vcpu;
-	int                   launched;
-	u8                    fail;
-	struct kvm_msr_entry *guest_msrs;
-	struct kvm_msr_entry *host_msrs;
-	int                   nmsrs;
-	int                   save_nmsrs;
-	int                   msr_offset_efer;
-#ifdef CONFIG_X86_64
-	int                   msr_offset_kernel_gs_base;
-#endif
-	struct vmcs          *vmcs;
-	struct {
-		int           loaded;
-		u16           fs_sel, gs_sel, ldt_sel;
-		int           gs_ldt_reload_needed;
-		int           fs_reload_needed;
-	}host_state;
-
-};
-
-static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
-{
-	return container_of(vcpu, struct vcpu_vmx, vcpu);
-}
-
-static int init_rmode_tss(struct kvm *kvm);
-
-static DEFINE_PER_CPU(struct vmcs *, vmxarea);
-static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
-
-static struct page *vmx_io_bitmap_a;
-static struct page *vmx_io_bitmap_b;
-
-#define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE)
-
-static struct vmcs_config {
-	int size;
-	int order;
-	u32 revision_id;
-	u32 pin_based_exec_ctrl;
-	u32 cpu_based_exec_ctrl;
-	u32 vmexit_ctrl;
-	u32 vmentry_ctrl;
-} vmcs_config;
-
-#define VMX_SEGMENT_FIELD(seg)					\
-	[VCPU_SREG_##seg] = {                                   \
-		.selector = GUEST_##seg##_SELECTOR,		\
-		.base = GUEST_##seg##_BASE,		   	\
-		.limit = GUEST_##seg##_LIMIT,		   	\
-		.ar_bytes = GUEST_##seg##_AR_BYTES,	   	\
-	}
-
-static struct kvm_vmx_segment_field {
-	unsigned selector;
-	unsigned base;
-	unsigned limit;
-	unsigned ar_bytes;
-} kvm_vmx_segment_fields[] = {
-	VMX_SEGMENT_FIELD(CS),
-	VMX_SEGMENT_FIELD(DS),
-	VMX_SEGMENT_FIELD(ES),
-	VMX_SEGMENT_FIELD(FS),
-	VMX_SEGMENT_FIELD(GS),
-	VMX_SEGMENT_FIELD(SS),
-	VMX_SEGMENT_FIELD(TR),
-	VMX_SEGMENT_FIELD(LDTR),
-};
-
-/*
- * Keep MSR_K6_STAR at the end, as setup_msrs() will try to optimize it
- * away by decrementing the array size.
- */
-static const u32 vmx_msr_index[] = {
-#ifdef CONFIG_X86_64
-	MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, MSR_KERNEL_GS_BASE,
-#endif
-	MSR_EFER, MSR_K6_STAR,
-};
-#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
-
-static void load_msrs(struct kvm_msr_entry *e, int n)
-{
-	int i;
-
-	for (i = 0; i < n; ++i)
-		wrmsrl(e[i].index, e[i].data);
-}
-
-static void save_msrs(struct kvm_msr_entry *e, int n)
-{
-	int i;
-
-	for (i = 0; i < n; ++i)
-		rdmsrl(e[i].index, e[i].data);
-}
-
-static inline u64 msr_efer_save_restore_bits(struct kvm_msr_entry msr)
-{
-	return (u64)msr.data & EFER_SAVE_RESTORE_BITS;
-}
-
-static inline int msr_efer_need_save_restore(struct vcpu_vmx *vmx)
-{
-	int efer_offset = vmx->msr_offset_efer;
-	return msr_efer_save_restore_bits(vmx->host_msrs[efer_offset]) !=
-		msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]);
-}
-
-static inline int is_page_fault(u32 intr_info)
-{
-	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
-			     INTR_INFO_VALID_MASK)) ==
-		(INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
-}
-
-static inline int is_no_device(u32 intr_info)
-{
-	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
-			     INTR_INFO_VALID_MASK)) ==
-		(INTR_TYPE_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK);
-}
-
-static inline int is_external_interrupt(u32 intr_info)
-{
-	return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
-		== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
-}
-
-static inline int cpu_has_vmx_tpr_shadow(void)
-{
-	return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW);
-}
-
-static inline int vm_need_tpr_shadow(struct kvm *kvm)
-{
-	return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)));
-}
-
-static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
-{
-	int i;
-
-	for (i = 0; i < vmx->nmsrs; ++i)
-		if (vmx->guest_msrs[i].index == msr)
-			return i;
-	return -1;
-}
-
-static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr)
-{
-	int i;
-
-	i = __find_msr_index(vmx, msr);
-	if (i >= 0)
-		return &vmx->guest_msrs[i];
-	return NULL;
-}
-
-static void vmcs_clear(struct vmcs *vmcs)
-{
-	u64 phys_addr = __pa(vmcs);
-	u8 error;
-
-	asm volatile (ASM_VMX_VMCLEAR_RAX "; setna %0"
-		      : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
-		      : "cc", "memory");
-	if (error)
-		printk(KERN_ERR "kvm: vmclear fail: %p/%llx\n",
-		       vmcs, phys_addr);
-}
-
-static void __vcpu_clear(void *arg)
-{
-	struct vcpu_vmx *vmx = arg;
-	int cpu = raw_smp_processor_id();
-
-	if (vmx->vcpu.cpu == cpu)
-		vmcs_clear(vmx->vmcs);
-	if (per_cpu(current_vmcs, cpu) == vmx->vmcs)
-		per_cpu(current_vmcs, cpu) = NULL;
-	rdtscll(vmx->vcpu.host_tsc);
-}
-
-static void vcpu_clear(struct vcpu_vmx *vmx)
-{
-	if (vmx->vcpu.cpu != raw_smp_processor_id() && vmx->vcpu.cpu != -1)
-		smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear,
-					 vmx, 0, 1);
-	else
-		__vcpu_clear(vmx);
-	vmx->launched = 0;
-}
-
-static unsigned long vmcs_readl(unsigned long field)
-{
-	unsigned long value;
-
-	asm volatile (ASM_VMX_VMREAD_RDX_RAX
-		      : "=a"(value) : "d"(field) : "cc");
-	return value;
-}
-
-static u16 vmcs_read16(unsigned long field)
-{
-	return vmcs_readl(field);
-}
-
-static u32 vmcs_read32(unsigned long field)
-{
-	return vmcs_readl(field);
-}
-
-static u64 vmcs_read64(unsigned long field)
-{
-#ifdef CONFIG_X86_64
-	return vmcs_readl(field);
-#else
-	return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32);
-#endif
-}
-
-static noinline void vmwrite_error(unsigned long field, unsigned long value)
-{
-	printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n",
-	       field, value, vmcs_read32(VM_INSTRUCTION_ERROR));
-	dump_stack();
-}
-
-static void vmcs_writel(unsigned long field, unsigned long value)
-{
-	u8 error;
-
-	asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0"
-		       : "=q"(error) : "a"(value), "d"(field) : "cc" );
-	if (unlikely(error))
-		vmwrite_error(field, value);
-}
-
-static void vmcs_write16(unsigned long field, u16 value)
-{
-	vmcs_writel(field, value);
-}
-
-static void vmcs_write32(unsigned long field, u32 value)
-{
-	vmcs_writel(field, value);
-}
-
-static void vmcs_write64(unsigned long field, u64 value)
-{
-#ifdef CONFIG_X86_64
-	vmcs_writel(field, value);
-#else
-	vmcs_writel(field, value);
-	asm volatile ("");
-	vmcs_writel(field+1, value >> 32);
-#endif
-}
-
-static void vmcs_clear_bits(unsigned long field, u32 mask)
-{
-	vmcs_writel(field, vmcs_readl(field) & ~mask);
-}
-
-static void vmcs_set_bits(unsigned long field, u32 mask)
-{
-	vmcs_writel(field, vmcs_readl(field) | mask);
-}
-
-static void update_exception_bitmap(struct kvm_vcpu *vcpu)
-{
-	u32 eb;
-
-	eb = 1u << PF_VECTOR;
-	if (!vcpu->fpu_active)
-		eb |= 1u << NM_VECTOR;
-	if (vcpu->guest_debug.enabled)
-		eb |= 1u << 1;
-	if (vcpu->rmode.active)
-		eb = ~0;
-	vmcs_write32(EXCEPTION_BITMAP, eb);
-}
-
-static void reload_tss(void)
-{
-#ifndef CONFIG_X86_64
-
-	/*
-	 * VT restores TR but not its size.  Useless.
-	 */
-	struct descriptor_table gdt;
-	struct segment_descriptor *descs;
-
-	get_gdt(&gdt);
-	descs = (void *)gdt.base;
-	descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
-	load_TR_desc();
-#endif
-}
-
-static void load_transition_efer(struct vcpu_vmx *vmx)
-{
-	u64 trans_efer;
-	int efer_offset = vmx->msr_offset_efer;
-
-	trans_efer = vmx->host_msrs[efer_offset].data;
-	trans_efer &= ~EFER_SAVE_RESTORE_BITS;
-	trans_efer |= msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]);
-	wrmsrl(MSR_EFER, trans_efer);
-	vmx->vcpu.stat.efer_reload++;
-}
-
-static void vmx_save_host_state(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-
-	if (vmx->host_state.loaded)
-		return;
-
-	vmx->host_state.loaded = 1;
-	/*
-	 * Set host fs and gs selectors.  Unfortunately, 22.2.3 does not
-	 * allow segment selectors with cpl > 0 or ti == 1.
-	 */
-	vmx->host_state.ldt_sel = read_ldt();
-	vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel;
-	vmx->host_state.fs_sel = read_fs();
-	if (!(vmx->host_state.fs_sel & 7)) {
-		vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel);
-		vmx->host_state.fs_reload_needed = 0;
-	} else {
-		vmcs_write16(HOST_FS_SELECTOR, 0);
-		vmx->host_state.fs_reload_needed = 1;
-	}
-	vmx->host_state.gs_sel = read_gs();
-	if (!(vmx->host_state.gs_sel & 7))
-		vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel);
-	else {
-		vmcs_write16(HOST_GS_SELECTOR, 0);
-		vmx->host_state.gs_ldt_reload_needed = 1;
-	}
-
-#ifdef CONFIG_X86_64
-	vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
-	vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
-#else
-	vmcs_writel(HOST_FS_BASE, segment_base(vmx->host_state.fs_sel));
-	vmcs_writel(HOST_GS_BASE, segment_base(vmx->host_state.gs_sel));
-#endif
-
-#ifdef CONFIG_X86_64
-	if (is_long_mode(&vmx->vcpu)) {
-		save_msrs(vmx->host_msrs +
-			  vmx->msr_offset_kernel_gs_base, 1);
-	}
-#endif
-	load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
-	if (msr_efer_need_save_restore(vmx))
-		load_transition_efer(vmx);
-}
-
-static void vmx_load_host_state(struct vcpu_vmx *vmx)
-{
-	unsigned long flags;
-
-	if (!vmx->host_state.loaded)
-		return;
-
-	vmx->host_state.loaded = 0;
-	if (vmx->host_state.fs_reload_needed)
-		load_fs(vmx->host_state.fs_sel);
-	if (vmx->host_state.gs_ldt_reload_needed) {
-		load_ldt(vmx->host_state.ldt_sel);
-		/*
-		 * If we have to reload gs, we must take care to
-		 * preserve our gs base.
-		 */
-		local_irq_save(flags);
-		load_gs(vmx->host_state.gs_sel);
-#ifdef CONFIG_X86_64
-		wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
-#endif
-		local_irq_restore(flags);
-	}
-	reload_tss();
-	save_msrs(vmx->guest_msrs, vmx->save_nmsrs);
-	load_msrs(vmx->host_msrs, vmx->save_nmsrs);
-	if (msr_efer_need_save_restore(vmx))
-		load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1);
-}
-
-/*
- * Switches to specified vcpu, until a matching vcpu_put(), but assumes
- * vcpu mutex is already taken.
- */
-static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	u64 phys_addr = __pa(vmx->vmcs);
-	u64 tsc_this, delta;
-
-	if (vcpu->cpu != cpu) {
-		vcpu_clear(vmx);
-		kvm_migrate_apic_timer(vcpu);
-	}
-
-	if (per_cpu(current_vmcs, cpu) != vmx->vmcs) {
-		u8 error;
-
-		per_cpu(current_vmcs, cpu) = vmx->vmcs;
-		asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0"
-			      : "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
-			      : "cc");
-		if (error)
-			printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n",
-			       vmx->vmcs, phys_addr);
-	}
-
-	if (vcpu->cpu != cpu) {
-		struct descriptor_table dt;
-		unsigned long sysenter_esp;
-
-		vcpu->cpu = cpu;
-		/*
-		 * Linux uses per-cpu TSS and GDT, so set these when switching
-		 * processors.
-		 */
-		vmcs_writel(HOST_TR_BASE, read_tr_base()); /* 22.2.4 */
-		get_gdt(&dt);
-		vmcs_writel(HOST_GDTR_BASE, dt.base);   /* 22.2.4 */
-
-		rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
-		vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
-
-		/*
-		 * Make sure the time stamp counter is monotonous.
-		 */
-		rdtscll(tsc_this);
-		delta = vcpu->host_tsc - tsc_this;
-		vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta);
-	}
-}
-
-static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
-{
-	vmx_load_host_state(to_vmx(vcpu));
-	kvm_put_guest_fpu(vcpu);
-}
-
-static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
-{
-	if (vcpu->fpu_active)
-		return;
-	vcpu->fpu_active = 1;
-	vmcs_clear_bits(GUEST_CR0, X86_CR0_TS);
-	if (vcpu->cr0 & X86_CR0_TS)
-		vmcs_set_bits(GUEST_CR0, X86_CR0_TS);
-	update_exception_bitmap(vcpu);
-}
-
-static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu)
-{
-	if (!vcpu->fpu_active)
-		return;
-	vcpu->fpu_active = 0;
-	vmcs_set_bits(GUEST_CR0, X86_CR0_TS);
-	update_exception_bitmap(vcpu);
-}
-
-static void vmx_vcpu_decache(struct kvm_vcpu *vcpu)
-{
-	vcpu_clear(to_vmx(vcpu));
-}
-
-static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
-{
-	return vmcs_readl(GUEST_RFLAGS);
-}
-
-static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
-{
-	if (vcpu->rmode.active)
-		rflags |= IOPL_MASK | X86_EFLAGS_VM;
-	vmcs_writel(GUEST_RFLAGS, rflags);
-}
-
-static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
-{
-	unsigned long rip;
-	u32 interruptibility;
-
-	rip = vmcs_readl(GUEST_RIP);
-	rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
-	vmcs_writel(GUEST_RIP, rip);
-
-	/*
-	 * We emulated an instruction, so temporary interrupt blocking
-	 * should be removed, if set.
-	 */
-	interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO);
-	if (interruptibility & 3)
-		vmcs_write32(GUEST_INTERRUPTIBILITY_INFO,
-			     interruptibility & ~3);
-	vcpu->interrupt_window_open = 1;
-}
-
-static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
-{
-	printk(KERN_DEBUG "inject_general_protection: rip 0x%lx\n",
-	       vmcs_readl(GUEST_RIP));
-	vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
-	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-		     GP_VECTOR |
-		     INTR_TYPE_EXCEPTION |
-		     INTR_INFO_DELIEVER_CODE_MASK |
-		     INTR_INFO_VALID_MASK);
-}
-
-/*
- * Swap MSR entry in host/guest MSR entry array.
- */
-#ifdef CONFIG_X86_64
-static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
-{
-	struct kvm_msr_entry tmp;
-
-	tmp = vmx->guest_msrs[to];
-	vmx->guest_msrs[to] = vmx->guest_msrs[from];
-	vmx->guest_msrs[from] = tmp;
-	tmp = vmx->host_msrs[to];
-	vmx->host_msrs[to] = vmx->host_msrs[from];
-	vmx->host_msrs[from] = tmp;
-}
-#endif
-
-/*
- * Set up the vmcs to automatically save and restore system
- * msrs.  Don't touch the 64-bit msrs if the guest is in legacy
- * mode, as fiddling with msrs is very expensive.
- */
-static void setup_msrs(struct vcpu_vmx *vmx)
-{
-	int save_nmsrs;
-
-	save_nmsrs = 0;
-#ifdef CONFIG_X86_64
-	if (is_long_mode(&vmx->vcpu)) {
-		int index;
-
-		index = __find_msr_index(vmx, MSR_SYSCALL_MASK);
-		if (index >= 0)
-			move_msr_up(vmx, index, save_nmsrs++);
-		index = __find_msr_index(vmx, MSR_LSTAR);
-		if (index >= 0)
-			move_msr_up(vmx, index, save_nmsrs++);
-		index = __find_msr_index(vmx, MSR_CSTAR);
-		if (index >= 0)
-			move_msr_up(vmx, index, save_nmsrs++);
-		index = __find_msr_index(vmx, MSR_KERNEL_GS_BASE);
-		if (index >= 0)
-			move_msr_up(vmx, index, save_nmsrs++);
-		/*
-		 * MSR_K6_STAR is only needed on long mode guests, and only
-		 * if efer.sce is enabled.
-		 */
-		index = __find_msr_index(vmx, MSR_K6_STAR);
-		if ((index >= 0) && (vmx->vcpu.shadow_efer & EFER_SCE))
-			move_msr_up(vmx, index, save_nmsrs++);
-	}
-#endif
-	vmx->save_nmsrs = save_nmsrs;
-
-#ifdef CONFIG_X86_64
-	vmx->msr_offset_kernel_gs_base =
-		__find_msr_index(vmx, MSR_KERNEL_GS_BASE);
-#endif
-	vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER);
-}
-
-/*
- * reads and returns guest's timestamp counter "register"
- * guest_tsc = host_tsc + tsc_offset    -- 21.3
- */
-static u64 guest_read_tsc(void)
-{
-	u64 host_tsc, tsc_offset;
-
-	rdtscll(host_tsc);
-	tsc_offset = vmcs_read64(TSC_OFFSET);
-	return host_tsc + tsc_offset;
-}
-
-/*
- * writes 'guest_tsc' into guest's timestamp counter "register"
- * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc
- */
-static void guest_write_tsc(u64 guest_tsc)
-{
-	u64 host_tsc;
-
-	rdtscll(host_tsc);
-	vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
-}
-
-/*
- * Reads an msr value (of 'msr_index') into 'pdata'.
- * Returns 0 on success, non-0 otherwise.
- * Assumes vcpu_load() was already called.
- */
-static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
-{
-	u64 data;
-	struct kvm_msr_entry *msr;
-
-	if (!pdata) {
-		printk(KERN_ERR "BUG: get_msr called with NULL pdata\n");
-		return -EINVAL;
-	}
-
-	switch (msr_index) {
-#ifdef CONFIG_X86_64
-	case MSR_FS_BASE:
-		data = vmcs_readl(GUEST_FS_BASE);
-		break;
-	case MSR_GS_BASE:
-		data = vmcs_readl(GUEST_GS_BASE);
-		break;
-	case MSR_EFER:
-		return kvm_get_msr_common(vcpu, msr_index, pdata);
-#endif
-	case MSR_IA32_TIME_STAMP_COUNTER:
-		data = guest_read_tsc();
-		break;
-	case MSR_IA32_SYSENTER_CS:
-		data = vmcs_read32(GUEST_SYSENTER_CS);
-		break;
-	case MSR_IA32_SYSENTER_EIP:
-		data = vmcs_readl(GUEST_SYSENTER_EIP);
-		break;
-	case MSR_IA32_SYSENTER_ESP:
-		data = vmcs_readl(GUEST_SYSENTER_ESP);
-		break;
-	default:
-		msr = find_msr_entry(to_vmx(vcpu), msr_index);
-		if (msr) {
-			data = msr->data;
-			break;
-		}
-		return kvm_get_msr_common(vcpu, msr_index, pdata);
-	}
-
-	*pdata = data;
-	return 0;
-}
-
-/*
- * Writes msr value into into the appropriate "register".
- * Returns 0 on success, non-0 otherwise.
- * Assumes vcpu_load() was already called.
- */
-static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	struct kvm_msr_entry *msr;
-	int ret = 0;
-
-	switch (msr_index) {
-#ifdef CONFIG_X86_64
-	case MSR_EFER:
-		ret = kvm_set_msr_common(vcpu, msr_index, data);
-		if (vmx->host_state.loaded)
-			load_transition_efer(vmx);
-		break;
-	case MSR_FS_BASE:
-		vmcs_writel(GUEST_FS_BASE, data);
-		break;
-	case MSR_GS_BASE:
-		vmcs_writel(GUEST_GS_BASE, data);
-		break;
-#endif
-	case MSR_IA32_SYSENTER_CS:
-		vmcs_write32(GUEST_SYSENTER_CS, data);
-		break;
-	case MSR_IA32_SYSENTER_EIP:
-		vmcs_writel(GUEST_SYSENTER_EIP, data);
-		break;
-	case MSR_IA32_SYSENTER_ESP:
-		vmcs_writel(GUEST_SYSENTER_ESP, data);
-		break;
-	case MSR_IA32_TIME_STAMP_COUNTER:
-		guest_write_tsc(data);
-		break;
-	default:
-		msr = find_msr_entry(vmx, msr_index);
-		if (msr) {
-			msr->data = data;
-			if (vmx->host_state.loaded)
-				load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
-			break;
-		}
-		ret = kvm_set_msr_common(vcpu, msr_index, data);
-	}
-
-	return ret;
-}
-
-/*
- * Sync the rsp and rip registers into the vcpu structure.  This allows
- * registers to be accessed by indexing vcpu->regs.
- */
-static void vcpu_load_rsp_rip(struct kvm_vcpu *vcpu)
-{
-	vcpu->regs[VCPU_REGS_RSP] = vmcs_readl(GUEST_RSP);
-	vcpu->rip = vmcs_readl(GUEST_RIP);
-}
-
-/*
- * Syncs rsp and rip back into the vmcs.  Should be called after possible
- * modification.
- */
-static void vcpu_put_rsp_rip(struct kvm_vcpu *vcpu)
-{
-	vmcs_writel(GUEST_RSP, vcpu->regs[VCPU_REGS_RSP]);
-	vmcs_writel(GUEST_RIP, vcpu->rip);
-}
-
-static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
-{
-	unsigned long dr7 = 0x400;
-	int old_singlestep;
-
-	old_singlestep = vcpu->guest_debug.singlestep;
-
-	vcpu->guest_debug.enabled = dbg->enabled;
-	if (vcpu->guest_debug.enabled) {
-		int i;
-
-		dr7 |= 0x200;  /* exact */
-		for (i = 0; i < 4; ++i) {
-			if (!dbg->breakpoints[i].enabled)
-				continue;
-			vcpu->guest_debug.bp[i] = dbg->breakpoints[i].address;
-			dr7 |= 2 << (i*2);    /* global enable */
-			dr7 |= 0 << (i*4+16); /* execution breakpoint */
-		}
-
-		vcpu->guest_debug.singlestep = dbg->singlestep;
-	} else
-		vcpu->guest_debug.singlestep = 0;
-
-	if (old_singlestep && !vcpu->guest_debug.singlestep) {
-		unsigned long flags;
-
-		flags = vmcs_readl(GUEST_RFLAGS);
-		flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF);
-		vmcs_writel(GUEST_RFLAGS, flags);
-	}
-
-	update_exception_bitmap(vcpu);
-	vmcs_writel(GUEST_DR7, dr7);
-
-	return 0;
-}
-
-static int vmx_get_irq(struct kvm_vcpu *vcpu)
-{
-	u32 idtv_info_field;
-
-	idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
-	if (idtv_info_field & INTR_INFO_VALID_MASK) {
-		if (is_external_interrupt(idtv_info_field))
-			return idtv_info_field & VECTORING_INFO_VECTOR_MASK;
-		else
-			printk("pending exception: not handled yet\n");
-	}
-	return -1;
-}
-
-static __init int cpu_has_kvm_support(void)
-{
-	unsigned long ecx = cpuid_ecx(1);
-	return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */
-}
-
-static __init int vmx_disabled_by_bios(void)
-{
-	u64 msr;
-
-	rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
-	return (msr & (MSR_IA32_FEATURE_CONTROL_LOCKED |
-		       MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
-	    == MSR_IA32_FEATURE_CONTROL_LOCKED;
-	/* locked but not enabled */
-}
-
-static void hardware_enable(void *garbage)
-{
-	int cpu = raw_smp_processor_id();
-	u64 phys_addr = __pa(per_cpu(vmxarea, cpu));
-	u64 old;
-
-	rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
-	if ((old & (MSR_IA32_FEATURE_CONTROL_LOCKED |
-		    MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
-	    != (MSR_IA32_FEATURE_CONTROL_LOCKED |
-		MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
-		/* enable and lock */
-		wrmsrl(MSR_IA32_FEATURE_CONTROL, old |
-		       MSR_IA32_FEATURE_CONTROL_LOCKED |
-		       MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED);
-	write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
-	asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr)
-		      : "memory", "cc");
-}
-
-static void hardware_disable(void *garbage)
-{
-	asm volatile (ASM_VMX_VMXOFF : : : "cc");
-}
-
-static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
-				      u32 msr, u32* result)
-{
-	u32 vmx_msr_low, vmx_msr_high;
-	u32 ctl = ctl_min | ctl_opt;
-
-	rdmsr(msr, vmx_msr_low, vmx_msr_high);
-
-	ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */
-	ctl |= vmx_msr_low;  /* bit == 1 in low word  ==> must be one  */
-
-	/* Ensure minimum (required) set of control bits are supported. */
-	if (ctl_min & ~ctl)
-		return -EIO;
-
-	*result = ctl;
-	return 0;
-}
-
-static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
-{
-	u32 vmx_msr_low, vmx_msr_high;
-	u32 min, opt;
-	u32 _pin_based_exec_control = 0;
-	u32 _cpu_based_exec_control = 0;
-	u32 _vmexit_control = 0;
-	u32 _vmentry_control = 0;
-
-	min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING;
-	opt = 0;
-	if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS,
-				&_pin_based_exec_control) < 0)
-		return -EIO;
-
-	min = CPU_BASED_HLT_EXITING |
-#ifdef CONFIG_X86_64
-	      CPU_BASED_CR8_LOAD_EXITING |
-	      CPU_BASED_CR8_STORE_EXITING |
-#endif
-	      CPU_BASED_USE_IO_BITMAPS |
-	      CPU_BASED_MOV_DR_EXITING |
-	      CPU_BASED_USE_TSC_OFFSETING;
-#ifdef CONFIG_X86_64
-	opt = CPU_BASED_TPR_SHADOW;
-#else
-	opt = 0;
-#endif
-	if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
-				&_cpu_based_exec_control) < 0)
-		return -EIO;
-#ifdef CONFIG_X86_64
-	if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW))
-		_cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING &
-					   ~CPU_BASED_CR8_STORE_EXITING;
-#endif
-
-	min = 0;
-#ifdef CONFIG_X86_64
-	min |= VM_EXIT_HOST_ADDR_SPACE_SIZE;
-#endif
-	opt = 0;
-	if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS,
-				&_vmexit_control) < 0)
-		return -EIO;
-
-	min = opt = 0;
-	if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS,
-				&_vmentry_control) < 0)
-		return -EIO;
-
-	rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high);
-
-	/* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */
-	if ((vmx_msr_high & 0x1fff) > PAGE_SIZE)
-		return -EIO;
-
-#ifdef CONFIG_X86_64
-	/* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */
-	if (vmx_msr_high & (1u<<16))
-		return -EIO;
-#endif
-
-	/* Require Write-Back (WB) memory type for VMCS accesses. */
-	if (((vmx_msr_high >> 18) & 15) != 6)
-		return -EIO;
-
-	vmcs_conf->size = vmx_msr_high & 0x1fff;
-	vmcs_conf->order = get_order(vmcs_config.size);
-	vmcs_conf->revision_id = vmx_msr_low;
-
-	vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control;
-	vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control;
-	vmcs_conf->vmexit_ctrl         = _vmexit_control;
-	vmcs_conf->vmentry_ctrl        = _vmentry_control;
-
-	return 0;
-}
-
-static struct vmcs *alloc_vmcs_cpu(int cpu)
-{
-	int node = cpu_to_node(cpu);
-	struct page *pages;
-	struct vmcs *vmcs;
-
-	pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order);
-	if (!pages)
-		return NULL;
-	vmcs = page_address(pages);
-	memset(vmcs, 0, vmcs_config.size);
-	vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */
-	return vmcs;
-}
-
-static struct vmcs *alloc_vmcs(void)
-{
-	return alloc_vmcs_cpu(raw_smp_processor_id());
-}
-
-static void free_vmcs(struct vmcs *vmcs)
-{
-	free_pages((unsigned long)vmcs, vmcs_config.order);
-}
-
-static void free_kvm_area(void)
-{
-	int cpu;
-
-	for_each_online_cpu(cpu)
-		free_vmcs(per_cpu(vmxarea, cpu));
-}
-
-static __init int alloc_kvm_area(void)
-{
-	int cpu;
-
-	for_each_online_cpu(cpu) {
-		struct vmcs *vmcs;
-
-		vmcs = alloc_vmcs_cpu(cpu);
-		if (!vmcs) {
-			free_kvm_area();
-			return -ENOMEM;
-		}
-
-		per_cpu(vmxarea, cpu) = vmcs;
-	}
-	return 0;
-}
-
-static __init int hardware_setup(void)
-{
-	if (setup_vmcs_config(&vmcs_config) < 0)
-		return -EIO;
-	return alloc_kvm_area();
-}
-
-static __exit void hardware_unsetup(void)
-{
-	free_kvm_area();
-}
-
-static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save)
-{
-	struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
-
-	if (vmcs_readl(sf->base) == save->base && (save->base & AR_S_MASK)) {
-		vmcs_write16(sf->selector, save->selector);
-		vmcs_writel(sf->base, save->base);
-		vmcs_write32(sf->limit, save->limit);
-		vmcs_write32(sf->ar_bytes, save->ar);
-	} else {
-		u32 dpl = (vmcs_read16(sf->selector) & SELECTOR_RPL_MASK)
-			<< AR_DPL_SHIFT;
-		vmcs_write32(sf->ar_bytes, 0x93 | dpl);
-	}
-}
-
-static void enter_pmode(struct kvm_vcpu *vcpu)
-{
-	unsigned long flags;
-
-	vcpu->rmode.active = 0;
-
-	vmcs_writel(GUEST_TR_BASE, vcpu->rmode.tr.base);
-	vmcs_write32(GUEST_TR_LIMIT, vcpu->rmode.tr.limit);
-	vmcs_write32(GUEST_TR_AR_BYTES, vcpu->rmode.tr.ar);
-
-	flags = vmcs_readl(GUEST_RFLAGS);
-	flags &= ~(IOPL_MASK | X86_EFLAGS_VM);
-	flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT);
-	vmcs_writel(GUEST_RFLAGS, flags);
-
-	vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) |
-			(vmcs_readl(CR4_READ_SHADOW) & X86_CR4_VME));
-
-	update_exception_bitmap(vcpu);
-
-	fix_pmode_dataseg(VCPU_SREG_ES, &vcpu->rmode.es);
-	fix_pmode_dataseg(VCPU_SREG_DS, &vcpu->rmode.ds);
-	fix_pmode_dataseg(VCPU_SREG_GS, &vcpu->rmode.gs);
-	fix_pmode_dataseg(VCPU_SREG_FS, &vcpu->rmode.fs);
-
-	vmcs_write16(GUEST_SS_SELECTOR, 0);
-	vmcs_write32(GUEST_SS_AR_BYTES, 0x93);
-
-	vmcs_write16(GUEST_CS_SELECTOR,
-		     vmcs_read16(GUEST_CS_SELECTOR) & ~SELECTOR_RPL_MASK);
-	vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
-}
-
-static gva_t rmode_tss_base(struct kvm* kvm)
-{
-	gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3;
-	return base_gfn << PAGE_SHIFT;
-}
-
-static void fix_rmode_seg(int seg, struct kvm_save_segment *save)
-{
-	struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
-
-	save->selector = vmcs_read16(sf->selector);
-	save->base = vmcs_readl(sf->base);
-	save->limit = vmcs_read32(sf->limit);
-	save->ar = vmcs_read32(sf->ar_bytes);
-	vmcs_write16(sf->selector, vmcs_readl(sf->base) >> 4);
-	vmcs_write32(sf->limit, 0xffff);
-	vmcs_write32(sf->ar_bytes, 0xf3);
-}
-
-static void enter_rmode(struct kvm_vcpu *vcpu)
-{
-	unsigned long flags;
-
-	vcpu->rmode.active = 1;
-
-	vcpu->rmode.tr.base = vmcs_readl(GUEST_TR_BASE);
-	vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm));
-
-	vcpu->rmode.tr.limit = vmcs_read32(GUEST_TR_LIMIT);
-	vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1);
-
-	vcpu->rmode.tr.ar = vmcs_read32(GUEST_TR_AR_BYTES);
-	vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
-
-	flags = vmcs_readl(GUEST_RFLAGS);
-	vcpu->rmode.save_iopl = (flags & IOPL_MASK) >> IOPL_SHIFT;
-
-	flags |= IOPL_MASK | X86_EFLAGS_VM;
-
-	vmcs_writel(GUEST_RFLAGS, flags);
-	vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME);
-	update_exception_bitmap(vcpu);
-
-	vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4);
-	vmcs_write32(GUEST_SS_LIMIT, 0xffff);
-	vmcs_write32(GUEST_SS_AR_BYTES, 0xf3);
-
-	vmcs_write32(GUEST_CS_AR_BYTES, 0xf3);
-	vmcs_write32(GUEST_CS_LIMIT, 0xffff);
-	if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000)
-		vmcs_writel(GUEST_CS_BASE, 0xf0000);
-	vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4);
-
-	fix_rmode_seg(VCPU_SREG_ES, &vcpu->rmode.es);
-	fix_rmode_seg(VCPU_SREG_DS, &vcpu->rmode.ds);
-	fix_rmode_seg(VCPU_SREG_GS, &vcpu->rmode.gs);
-	fix_rmode_seg(VCPU_SREG_FS, &vcpu->rmode.fs);
-
-	kvm_mmu_reset_context(vcpu);
-	init_rmode_tss(vcpu->kvm);
-}
-
-#ifdef CONFIG_X86_64
-
-static void enter_lmode(struct kvm_vcpu *vcpu)
-{
-	u32 guest_tr_ar;
-
-	guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES);
-	if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) {
-		printk(KERN_DEBUG "%s: tss fixup for long mode. \n",
-		       __FUNCTION__);
-		vmcs_write32(GUEST_TR_AR_BYTES,
-			     (guest_tr_ar & ~AR_TYPE_MASK)
-			     | AR_TYPE_BUSY_64_TSS);
-	}
-
-	vcpu->shadow_efer |= EFER_LMA;
-
-	find_msr_entry(to_vmx(vcpu), MSR_EFER)->data |= EFER_LMA | EFER_LME;
-	vmcs_write32(VM_ENTRY_CONTROLS,
-		     vmcs_read32(VM_ENTRY_CONTROLS)
-		     | VM_ENTRY_IA32E_MODE);
-}
-
-static void exit_lmode(struct kvm_vcpu *vcpu)
-{
-	vcpu->shadow_efer &= ~EFER_LMA;
-
-	vmcs_write32(VM_ENTRY_CONTROLS,
-		     vmcs_read32(VM_ENTRY_CONTROLS)
-		     & ~VM_ENTRY_IA32E_MODE);
-}
-
-#endif
-
-static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
-{
-	vcpu->cr4 &= KVM_GUEST_CR4_MASK;
-	vcpu->cr4 |= vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK;
-}
-
-static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
-{
-	vmx_fpu_deactivate(vcpu);
-
-	if (vcpu->rmode.active && (cr0 & X86_CR0_PE))
-		enter_pmode(vcpu);
-
-	if (!vcpu->rmode.active && !(cr0 & X86_CR0_PE))
-		enter_rmode(vcpu);
-
-#ifdef CONFIG_X86_64
-	if (vcpu->shadow_efer & EFER_LME) {
-		if (!is_paging(vcpu) && (cr0 & X86_CR0_PG))
-			enter_lmode(vcpu);
-		if (is_paging(vcpu) && !(cr0 & X86_CR0_PG))
-			exit_lmode(vcpu);
-	}
-#endif
-
-	vmcs_writel(CR0_READ_SHADOW, cr0);
-	vmcs_writel(GUEST_CR0,
-		    (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
-	vcpu->cr0 = cr0;
-
-	if (!(cr0 & X86_CR0_TS) || !(cr0 & X86_CR0_PE))
-		vmx_fpu_activate(vcpu);
-}
-
-static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
-{
-	vmcs_writel(GUEST_CR3, cr3);
-	if (vcpu->cr0 & X86_CR0_PE)
-		vmx_fpu_deactivate(vcpu);
-}
-
-static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
-{
-	vmcs_writel(CR4_READ_SHADOW, cr4);
-	vmcs_writel(GUEST_CR4, cr4 | (vcpu->rmode.active ?
-		    KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON));
-	vcpu->cr4 = cr4;
-}
-
-#ifdef CONFIG_X86_64
-
-static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER);
-
-	vcpu->shadow_efer = efer;
-	if (efer & EFER_LMA) {
-		vmcs_write32(VM_ENTRY_CONTROLS,
-				     vmcs_read32(VM_ENTRY_CONTROLS) |
-				     VM_ENTRY_IA32E_MODE);
-		msr->data = efer;
-
-	} else {
-		vmcs_write32(VM_ENTRY_CONTROLS,
-				     vmcs_read32(VM_ENTRY_CONTROLS) &
-				     ~VM_ENTRY_IA32E_MODE);
-
-		msr->data = efer & ~EFER_LME;
-	}
-	setup_msrs(vmx);
-}
-
-#endif
-
-static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
-{
-	struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
-
-	return vmcs_readl(sf->base);
-}
-
-static void vmx_get_segment(struct kvm_vcpu *vcpu,
-			    struct kvm_segment *var, int seg)
-{
-	struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
-	u32 ar;
-
-	var->base = vmcs_readl(sf->base);
-	var->limit = vmcs_read32(sf->limit);
-	var->selector = vmcs_read16(sf->selector);
-	ar = vmcs_read32(sf->ar_bytes);
-	if (ar & AR_UNUSABLE_MASK)
-		ar = 0;
-	var->type = ar & 15;
-	var->s = (ar >> 4) & 1;
-	var->dpl = (ar >> 5) & 3;
-	var->present = (ar >> 7) & 1;
-	var->avl = (ar >> 12) & 1;
-	var->l = (ar >> 13) & 1;
-	var->db = (ar >> 14) & 1;
-	var->g = (ar >> 15) & 1;
-	var->unusable = (ar >> 16) & 1;
-}
-
-static u32 vmx_segment_access_rights(struct kvm_segment *var)
-{
-	u32 ar;
-
-	if (var->unusable)
-		ar = 1 << 16;
-	else {
-		ar = var->type & 15;
-		ar |= (var->s & 1) << 4;
-		ar |= (var->dpl & 3) << 5;
-		ar |= (var->present & 1) << 7;
-		ar |= (var->avl & 1) << 12;
-		ar |= (var->l & 1) << 13;
-		ar |= (var->db & 1) << 14;
-		ar |= (var->g & 1) << 15;
-	}
-	if (ar == 0) /* a 0 value means unusable */
-		ar = AR_UNUSABLE_MASK;
-
-	return ar;
-}
-
-static void vmx_set_segment(struct kvm_vcpu *vcpu,
-			    struct kvm_segment *var, int seg)
-{
-	struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
-	u32 ar;
-
-	if (vcpu->rmode.active && seg == VCPU_SREG_TR) {
-		vcpu->rmode.tr.selector = var->selector;
-		vcpu->rmode.tr.base = var->base;
-		vcpu->rmode.tr.limit = var->limit;
-		vcpu->rmode.tr.ar = vmx_segment_access_rights(var);
-		return;
-	}
-	vmcs_writel(sf->base, var->base);
-	vmcs_write32(sf->limit, var->limit);
-	vmcs_write16(sf->selector, var->selector);
-	if (vcpu->rmode.active && var->s) {
-		/*
-		 * Hack real-mode segments into vm86 compatibility.
-		 */
-		if (var->base == 0xffff0000 && var->selector == 0xf000)
-			vmcs_writel(sf->base, 0xf0000);
-		ar = 0xf3;
-	} else
-		ar = vmx_segment_access_rights(var);
-	vmcs_write32(sf->ar_bytes, ar);
-}
-
-static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
-{
-	u32 ar = vmcs_read32(GUEST_CS_AR_BYTES);
-
-	*db = (ar >> 14) & 1;
-	*l = (ar >> 13) & 1;
-}
-
-static void vmx_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
-{
-	dt->limit = vmcs_read32(GUEST_IDTR_LIMIT);
-	dt->base = vmcs_readl(GUEST_IDTR_BASE);
-}
-
-static void vmx_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
-{
-	vmcs_write32(GUEST_IDTR_LIMIT, dt->limit);
-	vmcs_writel(GUEST_IDTR_BASE, dt->base);
-}
-
-static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
-{
-	dt->limit = vmcs_read32(GUEST_GDTR_LIMIT);
-	dt->base = vmcs_readl(GUEST_GDTR_BASE);
-}
-
-static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
-{
-	vmcs_write32(GUEST_GDTR_LIMIT, dt->limit);
-	vmcs_writel(GUEST_GDTR_BASE, dt->base);
-}
-
-static int init_rmode_tss(struct kvm* kvm)
-{
-	struct page *p1, *p2, *p3;
-	gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT;
-	char *page;
-
-	p1 = gfn_to_page(kvm, fn++);
-	p2 = gfn_to_page(kvm, fn++);
-	p3 = gfn_to_page(kvm, fn);
-
-	if (!p1 || !p2 || !p3) {
-		kvm_printf(kvm,"%s: gfn_to_page failed\n", __FUNCTION__);
-		return 0;
-	}
-
-	page = kmap_atomic(p1, KM_USER0);
-	clear_page(page);
-	*(u16*)(page + 0x66) = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE;
-	kunmap_atomic(page, KM_USER0);
-
-	page = kmap_atomic(p2, KM_USER0);
-	clear_page(page);
-	kunmap_atomic(page, KM_USER0);
-
-	page = kmap_atomic(p3, KM_USER0);
-	clear_page(page);
-	*(page + RMODE_TSS_SIZE - 2 * PAGE_SIZE - 1) = ~0;
-	kunmap_atomic(page, KM_USER0);
-
-	return 1;
-}
-
-static void seg_setup(int seg)
-{
-	struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
-
-	vmcs_write16(sf->selector, 0);
-	vmcs_writel(sf->base, 0);
-	vmcs_write32(sf->limit, 0xffff);
-	vmcs_write32(sf->ar_bytes, 0x93);
-}
-
-/*
- * Sets up the vmcs for emulated real mode.
- */
-static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
-{
-	u32 host_sysenter_cs;
-	u32 junk;
-	unsigned long a;
-	struct descriptor_table dt;
-	int i;
-	int ret = 0;
-	unsigned long kvm_vmx_return;
-	u64 msr;
-	u32 exec_control;
-
-	if (!init_rmode_tss(vmx->vcpu.kvm)) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	vmx->vcpu.rmode.active = 0;
-
-	vmx->vcpu.regs[VCPU_REGS_RDX] = get_rdx_init_val();
-	set_cr8(&vmx->vcpu, 0);
-	msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
-	if (vmx->vcpu.vcpu_id == 0)
-		msr |= MSR_IA32_APICBASE_BSP;
-	kvm_set_apic_base(&vmx->vcpu, msr);
-
-	fx_init(&vmx->vcpu);
-
-	/*
-	 * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
-	 * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4.  Sigh.
-	 */
-	if (vmx->vcpu.vcpu_id == 0) {
-		vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
-		vmcs_writel(GUEST_CS_BASE, 0x000f0000);
-	} else {
-		vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.sipi_vector << 8);
-		vmcs_writel(GUEST_CS_BASE, vmx->vcpu.sipi_vector << 12);
-	}
-	vmcs_write32(GUEST_CS_LIMIT, 0xffff);
-	vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
-
-	seg_setup(VCPU_SREG_DS);
-	seg_setup(VCPU_SREG_ES);
-	seg_setup(VCPU_SREG_FS);
-	seg_setup(VCPU_SREG_GS);
-	seg_setup(VCPU_SREG_SS);
-
-	vmcs_write16(GUEST_TR_SELECTOR, 0);
-	vmcs_writel(GUEST_TR_BASE, 0);
-	vmcs_write32(GUEST_TR_LIMIT, 0xffff);
-	vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
-
-	vmcs_write16(GUEST_LDTR_SELECTOR, 0);
-	vmcs_writel(GUEST_LDTR_BASE, 0);
-	vmcs_write32(GUEST_LDTR_LIMIT, 0xffff);
-	vmcs_write32(GUEST_LDTR_AR_BYTES, 0x00082);
-
-	vmcs_write32(GUEST_SYSENTER_CS, 0);
-	vmcs_writel(GUEST_SYSENTER_ESP, 0);
-	vmcs_writel(GUEST_SYSENTER_EIP, 0);
-
-	vmcs_writel(GUEST_RFLAGS, 0x02);
-	if (vmx->vcpu.vcpu_id == 0)
-		vmcs_writel(GUEST_RIP, 0xfff0);
-	else
-		vmcs_writel(GUEST_RIP, 0);
-	vmcs_writel(GUEST_RSP, 0);
-
-	//todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0
-	vmcs_writel(GUEST_DR7, 0x400);
-
-	vmcs_writel(GUEST_GDTR_BASE, 0);
-	vmcs_write32(GUEST_GDTR_LIMIT, 0xffff);
-
-	vmcs_writel(GUEST_IDTR_BASE, 0);
-	vmcs_write32(GUEST_IDTR_LIMIT, 0xffff);
-
-	vmcs_write32(GUEST_ACTIVITY_STATE, 0);
-	vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
-	vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
-
-	/* I/O */
-	vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a));
-	vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b));
-
-	guest_write_tsc(0);
-
-	vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */
-
-	/* Special registers */
-	vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
-
-	/* Control */
-	vmcs_write32(PIN_BASED_VM_EXEC_CONTROL,
-		vmcs_config.pin_based_exec_ctrl);
-
-	exec_control = vmcs_config.cpu_based_exec_ctrl;
-	if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) {
-		exec_control &= ~CPU_BASED_TPR_SHADOW;
-#ifdef CONFIG_X86_64
-		exec_control |= CPU_BASED_CR8_STORE_EXITING |
-				CPU_BASED_CR8_LOAD_EXITING;
-#endif
-	}
-	vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);
-
-	vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
-	vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
-	vmcs_write32(CR3_TARGET_COUNT, 0);           /* 22.2.1 */
-
-	vmcs_writel(HOST_CR0, read_cr0());  /* 22.2.3 */
-	vmcs_writel(HOST_CR4, read_cr4());  /* 22.2.3, 22.2.5 */
-	vmcs_writel(HOST_CR3, read_cr3());  /* 22.2.3  FIXME: shadow tables */
-
-	vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS);  /* 22.2.4 */
-	vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
-	vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
-	vmcs_write16(HOST_FS_SELECTOR, read_fs());    /* 22.2.4 */
-	vmcs_write16(HOST_GS_SELECTOR, read_gs());    /* 22.2.4 */
-	vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
-#ifdef CONFIG_X86_64
-	rdmsrl(MSR_FS_BASE, a);
-	vmcs_writel(HOST_FS_BASE, a); /* 22.2.4 */
-	rdmsrl(MSR_GS_BASE, a);
-	vmcs_writel(HOST_GS_BASE, a); /* 22.2.4 */
-#else
-	vmcs_writel(HOST_FS_BASE, 0); /* 22.2.4 */
-	vmcs_writel(HOST_GS_BASE, 0); /* 22.2.4 */
-#endif
-
-	vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8);  /* 22.2.4 */
-
-	get_idt(&dt);
-	vmcs_writel(HOST_IDTR_BASE, dt.base);   /* 22.2.4 */
-
-	asm ("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return));
-	vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */
-	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
-	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
-	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
-
-	rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk);
-	vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs);
-	rdmsrl(MSR_IA32_SYSENTER_ESP, a);
-	vmcs_writel(HOST_IA32_SYSENTER_ESP, a);   /* 22.2.3 */
-	rdmsrl(MSR_IA32_SYSENTER_EIP, a);
-	vmcs_writel(HOST_IA32_SYSENTER_EIP, a);   /* 22.2.3 */
-
-	for (i = 0; i < NR_VMX_MSR; ++i) {
-		u32 index = vmx_msr_index[i];
-		u32 data_low, data_high;
-		u64 data;
-		int j = vmx->nmsrs;
-
-		if (rdmsr_safe(index, &data_low, &data_high) < 0)
-			continue;
-		if (wrmsr_safe(index, data_low, data_high) < 0)
-			continue;
-		data = data_low | ((u64)data_high << 32);
-		vmx->host_msrs[j].index = index;
-		vmx->host_msrs[j].reserved = 0;
-		vmx->host_msrs[j].data = data;
-		vmx->guest_msrs[j] = vmx->host_msrs[j];
-		++vmx->nmsrs;
-	}
-
-	setup_msrs(vmx);
-
-	vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl);
-
-	/* 22.2.1, 20.8.1 */
-	vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl);
-
-	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0);  /* 22.2.1 */
-
-#ifdef CONFIG_X86_64
-	vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
-	if (vm_need_tpr_shadow(vmx->vcpu.kvm))
-		vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
-			     page_to_phys(vmx->vcpu.apic->regs_page));
-	vmcs_write32(TPR_THRESHOLD, 0);
-#endif
-
-	vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
-	vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
-
-	vmx->vcpu.cr0 = 0x60000010;
-	vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); // enter rmode
-	vmx_set_cr4(&vmx->vcpu, 0);
-#ifdef CONFIG_X86_64
-	vmx_set_efer(&vmx->vcpu, 0);
-#endif
-	vmx_fpu_activate(&vmx->vcpu);
-	update_exception_bitmap(&vmx->vcpu);
-
-	return 0;
-
-out:
-	return ret;
-}
-
-static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-
-	vmx_vcpu_setup(vmx);
-}
-
-static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
-{
-	u16 ent[2];
-	u16 cs;
-	u16 ip;
-	unsigned long flags;
-	unsigned long ss_base = vmcs_readl(GUEST_SS_BASE);
-	u16 sp =  vmcs_readl(GUEST_RSP);
-	u32 ss_limit = vmcs_read32(GUEST_SS_LIMIT);
-
-	if (sp > ss_limit || sp < 6 ) {
-		vcpu_printf(vcpu, "%s: #SS, rsp 0x%lx ss 0x%lx limit 0x%x\n",
-			    __FUNCTION__,
-			    vmcs_readl(GUEST_RSP),
-			    vmcs_readl(GUEST_SS_BASE),
-			    vmcs_read32(GUEST_SS_LIMIT));
-		return;
-	}
-
-	if (emulator_read_std(irq * sizeof(ent), &ent, sizeof(ent), vcpu) !=
-							X86EMUL_CONTINUE) {
-		vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__);
-		return;
-	}
-
-	flags =  vmcs_readl(GUEST_RFLAGS);
-	cs =  vmcs_readl(GUEST_CS_BASE) >> 4;
-	ip =  vmcs_readl(GUEST_RIP);
-
-
-	if (emulator_write_emulated(ss_base + sp - 2, &flags, 2, vcpu) != X86EMUL_CONTINUE ||
-	    emulator_write_emulated(ss_base + sp - 4, &cs, 2, vcpu) != X86EMUL_CONTINUE ||
-	    emulator_write_emulated(ss_base + sp - 6, &ip, 2, vcpu) != X86EMUL_CONTINUE) {
-		vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__);
-		return;
-	}
-
-	vmcs_writel(GUEST_RFLAGS, flags &
-		    ~( X86_EFLAGS_IF | X86_EFLAGS_AC | X86_EFLAGS_TF));
-	vmcs_write16(GUEST_CS_SELECTOR, ent[1]) ;
-	vmcs_writel(GUEST_CS_BASE, ent[1] << 4);
-	vmcs_writel(GUEST_RIP, ent[0]);
-	vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));
-}
-
-static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq)
-{
-	if (vcpu->rmode.active) {
-		inject_rmode_irq(vcpu, irq);
-		return;
-	}
-	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-			irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
-}
-
-static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
-{
-	int word_index = __ffs(vcpu->irq_summary);
-	int bit_index = __ffs(vcpu->irq_pending[word_index]);
-	int irq = word_index * BITS_PER_LONG + bit_index;
-
-	clear_bit(bit_index, &vcpu->irq_pending[word_index]);
-	if (!vcpu->irq_pending[word_index])
-		clear_bit(word_index, &vcpu->irq_summary);
-	vmx_inject_irq(vcpu, irq);
-}
-
-
-static void do_interrupt_requests(struct kvm_vcpu *vcpu,
-				       struct kvm_run *kvm_run)
-{
-	u32 cpu_based_vm_exec_control;
-
-	vcpu->interrupt_window_open =
-		((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
-		 (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
-
-	if (vcpu->interrupt_window_open &&
-	    vcpu->irq_summary &&
-	    !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK))
-		/*
-		 * If interrupts enabled, and not blocked by sti or mov ss. Good.
-		 */
-		kvm_do_inject_irq(vcpu);
-
-	cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
-	if (!vcpu->interrupt_window_open &&
-	    (vcpu->irq_summary || kvm_run->request_interrupt_window))
-		/*
-		 * Interrupts blocked.  Wait for unblock.
-		 */
-		cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
-	else
-		cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
-	vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
-}
-
-static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu)
-{
-	struct kvm_guest_debug *dbg = &vcpu->guest_debug;
-
-	set_debugreg(dbg->bp[0], 0);
-	set_debugreg(dbg->bp[1], 1);
-	set_debugreg(dbg->bp[2], 2);
-	set_debugreg(dbg->bp[3], 3);
-
-	if (dbg->singlestep) {
-		unsigned long flags;
-
-		flags = vmcs_readl(GUEST_RFLAGS);
-		flags |= X86_EFLAGS_TF | X86_EFLAGS_RF;
-		vmcs_writel(GUEST_RFLAGS, flags);
-	}
-}
-
-static int handle_rmode_exception(struct kvm_vcpu *vcpu,
-				  int vec, u32 err_code)
-{
-	if (!vcpu->rmode.active)
-		return 0;
-
-	/*
-	 * Instruction with address size override prefix opcode 0x67
-	 * Cause the #SS fault with 0 error code in VM86 mode.
-	 */
-	if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0)
-		if (emulate_instruction(vcpu, NULL, 0, 0) == EMULATE_DONE)
-			return 1;
-	return 0;
-}
-
-static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	u32 intr_info, error_code;
-	unsigned long cr2, rip;
-	u32 vect_info;
-	enum emulation_result er;
-	int r;
-
-	vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
-	intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
-
-	if ((vect_info & VECTORING_INFO_VALID_MASK) &&
-						!is_page_fault(intr_info)) {
-		printk(KERN_ERR "%s: unexpected, vectoring info 0x%x "
-		       "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info);
-	}
-
-	if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) {
-		int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
-		set_bit(irq, vcpu->irq_pending);
-		set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
-	}
-
-	if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */
-		return 1;  /* already handled by vmx_vcpu_run() */
-
-	if (is_no_device(intr_info)) {
-		vmx_fpu_activate(vcpu);
-		return 1;
-	}
-
-	error_code = 0;
-	rip = vmcs_readl(GUEST_RIP);
-	if (intr_info & INTR_INFO_DELIEVER_CODE_MASK)
-		error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
-	if (is_page_fault(intr_info)) {
-		cr2 = vmcs_readl(EXIT_QUALIFICATION);
-
-		mutex_lock(&vcpu->kvm->lock);
-		r = kvm_mmu_page_fault(vcpu, cr2, error_code);
-		if (r < 0) {
-			mutex_unlock(&vcpu->kvm->lock);
-			return r;
-		}
-		if (!r) {
-			mutex_unlock(&vcpu->kvm->lock);
-			return 1;
-		}
-
-		er = emulate_instruction(vcpu, kvm_run, cr2, error_code);
-		mutex_unlock(&vcpu->kvm->lock);
-
-		switch (er) {
-		case EMULATE_DONE:
-			return 1;
-		case EMULATE_DO_MMIO:
-			++vcpu->stat.mmio_exits;
-			return 0;
-		 case EMULATE_FAIL:
-			kvm_report_emulation_failure(vcpu, "pagetable");
-			break;
-		default:
-			BUG();
-		}
-	}
-
-	if (vcpu->rmode.active &&
-	    handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK,
-								error_code)) {
-		if (vcpu->halt_request) {
-			vcpu->halt_request = 0;
-			return kvm_emulate_halt(vcpu);
-		}
-		return 1;
-	}
-
-	if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) == (INTR_TYPE_EXCEPTION | 1)) {
-		kvm_run->exit_reason = KVM_EXIT_DEBUG;
-		return 0;
-	}
-	kvm_run->exit_reason = KVM_EXIT_EXCEPTION;
-	kvm_run->ex.exception = intr_info & INTR_INFO_VECTOR_MASK;
-	kvm_run->ex.error_code = error_code;
-	return 0;
-}
-
-static int handle_external_interrupt(struct kvm_vcpu *vcpu,
-				     struct kvm_run *kvm_run)
-{
-	++vcpu->stat.irq_exits;
-	return 1;
-}
-
-static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
-	return 0;
-}
-
-static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	unsigned long exit_qualification;
-	int size, down, in, string, rep;
-	unsigned port;
-
-	++vcpu->stat.io_exits;
-	exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
-	string = (exit_qualification & 16) != 0;
-
-	if (string) {
-		if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO)
-			return 0;
-		return 1;
-	}
-
-	size = (exit_qualification & 7) + 1;
-	in = (exit_qualification & 8) != 0;
-	down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
-	rep = (exit_qualification & 32) != 0;
-	port = exit_qualification >> 16;
-
-	return kvm_emulate_pio(vcpu, kvm_run, in, size, port);
-}
-
-static void
-vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
-{
-	/*
-	 * Patch in the VMCALL instruction:
-	 */
-	hypercall[0] = 0x0f;
-	hypercall[1] = 0x01;
-	hypercall[2] = 0xc1;
-	hypercall[3] = 0xc3;
-}
-
-static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	unsigned long exit_qualification;
-	int cr;
-	int reg;
-
-	exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
-	cr = exit_qualification & 15;
-	reg = (exit_qualification >> 8) & 15;
-	switch ((exit_qualification >> 4) & 3) {
-	case 0: /* mov to cr */
-		switch (cr) {
-		case 0:
-			vcpu_load_rsp_rip(vcpu);
-			set_cr0(vcpu, vcpu->regs[reg]);
-			skip_emulated_instruction(vcpu);
-			return 1;
-		case 3:
-			vcpu_load_rsp_rip(vcpu);
-			set_cr3(vcpu, vcpu->regs[reg]);
-			skip_emulated_instruction(vcpu);
-			return 1;
-		case 4:
-			vcpu_load_rsp_rip(vcpu);
-			set_cr4(vcpu, vcpu->regs[reg]);
-			skip_emulated_instruction(vcpu);
-			return 1;
-		case 8:
-			vcpu_load_rsp_rip(vcpu);
-			set_cr8(vcpu, vcpu->regs[reg]);
-			skip_emulated_instruction(vcpu);
-			kvm_run->exit_reason = KVM_EXIT_SET_TPR;
-			return 0;
-		};
-		break;
-	case 2: /* clts */
-		vcpu_load_rsp_rip(vcpu);
-		vmx_fpu_deactivate(vcpu);
-		vcpu->cr0 &= ~X86_CR0_TS;
-		vmcs_writel(CR0_READ_SHADOW, vcpu->cr0);
-		vmx_fpu_activate(vcpu);
-		skip_emulated_instruction(vcpu);
-		return 1;
-	case 1: /*mov from cr*/
-		switch (cr) {
-		case 3:
-			vcpu_load_rsp_rip(vcpu);
-			vcpu->regs[reg] = vcpu->cr3;
-			vcpu_put_rsp_rip(vcpu);
-			skip_emulated_instruction(vcpu);
-			return 1;
-		case 8:
-			vcpu_load_rsp_rip(vcpu);
-			vcpu->regs[reg] = get_cr8(vcpu);
-			vcpu_put_rsp_rip(vcpu);
-			skip_emulated_instruction(vcpu);
-			return 1;
-		}
-		break;
-	case 3: /* lmsw */
-		lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f);
-
-		skip_emulated_instruction(vcpu);
-		return 1;
-	default:
-		break;
-	}
-	kvm_run->exit_reason = 0;
-	pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n",
-	       (int)(exit_qualification >> 4) & 3, cr);
-	return 0;
-}
-
-static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	unsigned long exit_qualification;
-	unsigned long val;
-	int dr, reg;
-
-	/*
-	 * FIXME: this code assumes the host is debugging the guest.
-	 *        need to deal with guest debugging itself too.
-	 */
-	exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
-	dr = exit_qualification & 7;
-	reg = (exit_qualification >> 8) & 15;
-	vcpu_load_rsp_rip(vcpu);
-	if (exit_qualification & 16) {
-		/* mov from dr */
-		switch (dr) {
-		case 6:
-			val = 0xffff0ff0;
-			break;
-		case 7:
-			val = 0x400;
-			break;
-		default:
-			val = 0;
-		}
-		vcpu->regs[reg] = val;
-	} else {
-		/* mov to dr */
-	}
-	vcpu_put_rsp_rip(vcpu);
-	skip_emulated_instruction(vcpu);
-	return 1;
-}
-
-static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	kvm_emulate_cpuid(vcpu);
-	return 1;
-}
-
-static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	u32 ecx = vcpu->regs[VCPU_REGS_RCX];
-	u64 data;
-
-	if (vmx_get_msr(vcpu, ecx, &data)) {
-		vmx_inject_gp(vcpu, 0);
-		return 1;
-	}
-
-	/* FIXME: handling of bits 32:63 of rax, rdx */
-	vcpu->regs[VCPU_REGS_RAX] = data & -1u;
-	vcpu->regs[VCPU_REGS_RDX] = (data >> 32) & -1u;
-	skip_emulated_instruction(vcpu);
-	return 1;
-}
-
-static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	u32 ecx = vcpu->regs[VCPU_REGS_RCX];
-	u64 data = (vcpu->regs[VCPU_REGS_RAX] & -1u)
-		| ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32);
-
-	if (vmx_set_msr(vcpu, ecx, data) != 0) {
-		vmx_inject_gp(vcpu, 0);
-		return 1;
-	}
-
-	skip_emulated_instruction(vcpu);
-	return 1;
-}
-
-static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu,
-				      struct kvm_run *kvm_run)
-{
-	return 1;
-}
-
-static int handle_interrupt_window(struct kvm_vcpu *vcpu,
-				   struct kvm_run *kvm_run)
-{
-	u32 cpu_based_vm_exec_control;
-
-	/* clear pending irq */
-	cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
-	cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
-	vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
-	/*
-	 * If the user space waits to inject interrupts, exit as soon as
-	 * possible
-	 */
-	if (kvm_run->request_interrupt_window &&
-	    !vcpu->irq_summary) {
-		kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
-		++vcpu->stat.irq_window_exits;
-		return 0;
-	}
-	return 1;
-}
-
-static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	skip_emulated_instruction(vcpu);
-	return kvm_emulate_halt(vcpu);
-}
-
-static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	skip_emulated_instruction(vcpu);
-	return kvm_hypercall(vcpu, kvm_run);
-}
-
-/*
- * The exit handlers return 1 if the exit was handled fully and guest execution
- * may resume.  Otherwise they set the kvm_run parameter to indicate what needs
- * to be done to userspace and return 0.
- */
-static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
-				      struct kvm_run *kvm_run) = {
-	[EXIT_REASON_EXCEPTION_NMI]           = handle_exception,
-	[EXIT_REASON_EXTERNAL_INTERRUPT]      = handle_external_interrupt,
-	[EXIT_REASON_TRIPLE_FAULT]            = handle_triple_fault,
-	[EXIT_REASON_IO_INSTRUCTION]          = handle_io,
-	[EXIT_REASON_CR_ACCESS]               = handle_cr,
-	[EXIT_REASON_DR_ACCESS]               = handle_dr,
-	[EXIT_REASON_CPUID]                   = handle_cpuid,
-	[EXIT_REASON_MSR_READ]                = handle_rdmsr,
-	[EXIT_REASON_MSR_WRITE]               = handle_wrmsr,
-	[EXIT_REASON_PENDING_INTERRUPT]       = handle_interrupt_window,
-	[EXIT_REASON_HLT]                     = handle_halt,
-	[EXIT_REASON_VMCALL]                  = handle_vmcall,
-	[EXIT_REASON_TPR_BELOW_THRESHOLD]     = handle_tpr_below_threshold
-};
-
-static const int kvm_vmx_max_exit_handlers =
-	ARRAY_SIZE(kvm_vmx_exit_handlers);
-
-/*
- * The guest has exited.  See if we can fix it or if we need userspace
- * assistance.
- */
-static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
-{
-	u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
-	u32 exit_reason = vmcs_read32(VM_EXIT_REASON);
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-
-	if (unlikely(vmx->fail)) {
-		kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
-		kvm_run->fail_entry.hardware_entry_failure_reason
-			= vmcs_read32(VM_INSTRUCTION_ERROR);
-		return 0;
-	}
-
-	if ( (vectoring_info & VECTORING_INFO_VALID_MASK) &&
-				exit_reason != EXIT_REASON_EXCEPTION_NMI )
-		printk(KERN_WARNING "%s: unexpected, valid vectoring info and "
-		       "exit reason is 0x%x\n", __FUNCTION__, exit_reason);
-	if (exit_reason < kvm_vmx_max_exit_handlers
-	    && kvm_vmx_exit_handlers[exit_reason])
-		return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run);
-	else {
-		kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
-		kvm_run->hw.hardware_exit_reason = exit_reason;
-	}
-	return 0;
-}
-
-static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
-{
-}
-
-static void update_tpr_threshold(struct kvm_vcpu *vcpu)
-{
-	int max_irr, tpr;
-
-	if (!vm_need_tpr_shadow(vcpu->kvm))
-		return;
-
-	if (!kvm_lapic_enabled(vcpu) ||
-	    ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) {
-		vmcs_write32(TPR_THRESHOLD, 0);
-		return;
-	}
-
-	tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4;
-	vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4);
-}
-
-static void enable_irq_window(struct kvm_vcpu *vcpu)
-{
-	u32 cpu_based_vm_exec_control;
-
-	cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
-	cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
-	vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
-}
-
-static void vmx_intr_assist(struct kvm_vcpu *vcpu)
-{
-	u32 idtv_info_field, intr_info_field;
-	int has_ext_irq, interrupt_window_open;
-	int vector;
-
-	kvm_inject_pending_timer_irqs(vcpu);
-	update_tpr_threshold(vcpu);
-
-	has_ext_irq = kvm_cpu_has_interrupt(vcpu);
-	intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
-	idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
-	if (intr_info_field & INTR_INFO_VALID_MASK) {
-		if (idtv_info_field & INTR_INFO_VALID_MASK) {
-			/* TODO: fault when IDT_Vectoring */
-			printk(KERN_ERR "Fault when IDT_Vectoring\n");
-		}
-		if (has_ext_irq)
-			enable_irq_window(vcpu);
-		return;
-	}
-	if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
-		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
-		vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
-				vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
-
-		if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK))
-			vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
-				vmcs_read32(IDT_VECTORING_ERROR_CODE));
-		if (unlikely(has_ext_irq))
-			enable_irq_window(vcpu);
-		return;
-	}
-	if (!has_ext_irq)
-		return;
-	interrupt_window_open =
-		((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
-		 (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
-	if (interrupt_window_open) {
-		vector = kvm_cpu_get_interrupt(vcpu);
-		vmx_inject_irq(vcpu, vector);
-		kvm_timer_intr_post(vcpu, vector);
-	} else
-		enable_irq_window(vcpu);
-}
-
-static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	u32 intr_info;
-
-	/*
-	 * Loading guest fpu may have cleared host cr0.ts
-	 */
-	vmcs_writel(HOST_CR0, read_cr0());
-
-	asm (
-		/* Store host registers */
-#ifdef CONFIG_X86_64
-		"push %%rax; push %%rbx; push %%rdx;"
-		"push %%rsi; push %%rdi; push %%rbp;"
-		"push %%r8;  push %%r9;  push %%r10; push %%r11;"
-		"push %%r12; push %%r13; push %%r14; push %%r15;"
-		"push %%rcx \n\t"
-		ASM_VMX_VMWRITE_RSP_RDX "\n\t"
-#else
-		"pusha; push %%ecx \n\t"
-		ASM_VMX_VMWRITE_RSP_RDX "\n\t"
-#endif
-		/* Check if vmlaunch of vmresume is needed */
-		"cmp $0, %1 \n\t"
-		/* Load guest registers.  Don't clobber flags. */
-#ifdef CONFIG_X86_64
-		"mov %c[cr2](%3), %%rax \n\t"
-		"mov %%rax, %%cr2 \n\t"
-		"mov %c[rax](%3), %%rax \n\t"
-		"mov %c[rbx](%3), %%rbx \n\t"
-		"mov %c[rdx](%3), %%rdx \n\t"
-		"mov %c[rsi](%3), %%rsi \n\t"
-		"mov %c[rdi](%3), %%rdi \n\t"
-		"mov %c[rbp](%3), %%rbp \n\t"
-		"mov %c[r8](%3),  %%r8  \n\t"
-		"mov %c[r9](%3),  %%r9  \n\t"
-		"mov %c[r10](%3), %%r10 \n\t"
-		"mov %c[r11](%3), %%r11 \n\t"
-		"mov %c[r12](%3), %%r12 \n\t"
-		"mov %c[r13](%3), %%r13 \n\t"
-		"mov %c[r14](%3), %%r14 \n\t"
-		"mov %c[r15](%3), %%r15 \n\t"
-		"mov %c[rcx](%3), %%rcx \n\t" /* kills %3 (rcx) */
-#else
-		"mov %c[cr2](%3), %%eax \n\t"
-		"mov %%eax,   %%cr2 \n\t"
-		"mov %c[rax](%3), %%eax \n\t"
-		"mov %c[rbx](%3), %%ebx \n\t"
-		"mov %c[rdx](%3), %%edx \n\t"
-		"mov %c[rsi](%3), %%esi \n\t"
-		"mov %c[rdi](%3), %%edi \n\t"
-		"mov %c[rbp](%3), %%ebp \n\t"
-		"mov %c[rcx](%3), %%ecx \n\t" /* kills %3 (ecx) */
-#endif
-		/* Enter guest mode */
-		"jne .Llaunched \n\t"
-		ASM_VMX_VMLAUNCH "\n\t"
-		"jmp .Lkvm_vmx_return \n\t"
-		".Llaunched: " ASM_VMX_VMRESUME "\n\t"
-		".Lkvm_vmx_return: "
-		/* Save guest registers, load host registers, keep flags */
-#ifdef CONFIG_X86_64
-		"xchg %3,     (%%rsp) \n\t"
-		"mov %%rax, %c[rax](%3) \n\t"
-		"mov %%rbx, %c[rbx](%3) \n\t"
-		"pushq (%%rsp); popq %c[rcx](%3) \n\t"
-		"mov %%rdx, %c[rdx](%3) \n\t"
-		"mov %%rsi, %c[rsi](%3) \n\t"
-		"mov %%rdi, %c[rdi](%3) \n\t"
-		"mov %%rbp, %c[rbp](%3) \n\t"
-		"mov %%r8,  %c[r8](%3) \n\t"
-		"mov %%r9,  %c[r9](%3) \n\t"
-		"mov %%r10, %c[r10](%3) \n\t"
-		"mov %%r11, %c[r11](%3) \n\t"
-		"mov %%r12, %c[r12](%3) \n\t"
-		"mov %%r13, %c[r13](%3) \n\t"
-		"mov %%r14, %c[r14](%3) \n\t"
-		"mov %%r15, %c[r15](%3) \n\t"
-		"mov %%cr2, %%rax   \n\t"
-		"mov %%rax, %c[cr2](%3) \n\t"
-		"mov (%%rsp), %3 \n\t"
-
-		"pop  %%rcx; pop  %%r15; pop  %%r14; pop  %%r13; pop  %%r12;"
-		"pop  %%r11; pop  %%r10; pop  %%r9;  pop  %%r8;"
-		"pop  %%rbp; pop  %%rdi; pop  %%rsi;"
-		"pop  %%rdx; pop  %%rbx; pop  %%rax \n\t"
-#else
-		"xchg %3, (%%esp) \n\t"
-		"mov %%eax, %c[rax](%3) \n\t"
-		"mov %%ebx, %c[rbx](%3) \n\t"
-		"pushl (%%esp); popl %c[rcx](%3) \n\t"
-		"mov %%edx, %c[rdx](%3) \n\t"
-		"mov %%esi, %c[rsi](%3) \n\t"
-		"mov %%edi, %c[rdi](%3) \n\t"
-		"mov %%ebp, %c[rbp](%3) \n\t"
-		"mov %%cr2, %%eax  \n\t"
-		"mov %%eax, %c[cr2](%3) \n\t"
-		"mov (%%esp), %3 \n\t"
-
-		"pop %%ecx; popa \n\t"
-#endif
-		"setbe %0 \n\t"
-	      : "=q" (vmx->fail)
-	      : "r"(vmx->launched), "d"((unsigned long)HOST_RSP),
-		"c"(vcpu),
-		[rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])),
-		[rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
-		[rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])),
-		[rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])),
-		[rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])),
-		[rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])),
-		[rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP])),
-#ifdef CONFIG_X86_64
-		[r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])),
-		[r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])),
-		[r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])),
-		[r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])),
-		[r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])),
-		[r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])),
-		[r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])),
-		[r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15])),
-#endif
-		[cr2]"i"(offsetof(struct kvm_vcpu, cr2))
-	      : "cc", "memory" );
-
-	vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
-
-	asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
-	vmx->launched = 1;
-
-	intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
-
-	/* We need to handle NMIs before interrupts are enabled */
-	if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */
-		asm("int $2");
-}
-
-static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
-				  unsigned long addr,
-				  u32 err_code)
-{
-	u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
-
-	++vcpu->stat.pf_guest;
-
-	if (is_page_fault(vect_info)) {
-		printk(KERN_DEBUG "inject_page_fault: "
-		       "double fault 0x%lx @ 0x%lx\n",
-		       addr, vmcs_readl(GUEST_RIP));
-		vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, 0);
-		vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-			     DF_VECTOR |
-			     INTR_TYPE_EXCEPTION |
-			     INTR_INFO_DELIEVER_CODE_MASK |
-			     INTR_INFO_VALID_MASK);
-		return;
-	}
-	vcpu->cr2 = addr;
-	vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, err_code);
-	vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
-		     PF_VECTOR |
-		     INTR_TYPE_EXCEPTION |
-		     INTR_INFO_DELIEVER_CODE_MASK |
-		     INTR_INFO_VALID_MASK);
-
-}
-
-static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-
-	if (vmx->vmcs) {
-		on_each_cpu(__vcpu_clear, vmx, 0, 1);
-		free_vmcs(vmx->vmcs);
-		vmx->vmcs = NULL;
-	}
-}
-
-static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
-{
-	struct vcpu_vmx *vmx = to_vmx(vcpu);
-
-	vmx_free_vmcs(vcpu);
-	kfree(vmx->host_msrs);
-	kfree(vmx->guest_msrs);
-	kvm_vcpu_uninit(vcpu);
-	kmem_cache_free(kvm_vcpu_cache, vmx);
-}
-
-static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
-{
-	int err;
-	struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
-	int cpu;
-
-	if (!vmx)
-		return ERR_PTR(-ENOMEM);
-
-	err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
-	if (err)
-		goto free_vcpu;
-
-	if (irqchip_in_kernel(kvm)) {
-		err = kvm_create_lapic(&vmx->vcpu);
-		if (err < 0)
-			goto free_vcpu;
-	}
-
-	vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
-	if (!vmx->guest_msrs) {
-		err = -ENOMEM;
-		goto uninit_vcpu;
-	}
-
-	vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
-	if (!vmx->host_msrs)
-		goto free_guest_msrs;
-
-	vmx->vmcs = alloc_vmcs();
-	if (!vmx->vmcs)
-		goto free_msrs;
-
-	vmcs_clear(vmx->vmcs);
-
-	cpu = get_cpu();
-	vmx_vcpu_load(&vmx->vcpu, cpu);
-	err = vmx_vcpu_setup(vmx);
-	vmx_vcpu_put(&vmx->vcpu);
-	put_cpu();
-	if (err)
-		goto free_vmcs;
-
-	return &vmx->vcpu;
-
-free_vmcs:
-	free_vmcs(vmx->vmcs);
-free_msrs:
-	kfree(vmx->host_msrs);
-free_guest_msrs:
-	kfree(vmx->guest_msrs);
-uninit_vcpu:
-	kvm_vcpu_uninit(&vmx->vcpu);
-free_vcpu:
-	kmem_cache_free(kvm_vcpu_cache, vmx);
-	return ERR_PTR(err);
-}
-
-static void __init vmx_check_processor_compat(void *rtn)
-{
-	struct vmcs_config vmcs_conf;
-
-	*(int *)rtn = 0;
-	if (setup_vmcs_config(&vmcs_conf) < 0)
-		*(int *)rtn = -EIO;
-	if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) {
-		printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n",
-				smp_processor_id());
-		*(int *)rtn = -EIO;
-	}
-}
-
-static struct kvm_x86_ops vmx_x86_ops = {
-	.cpu_has_kvm_support = cpu_has_kvm_support,
-	.disabled_by_bios = vmx_disabled_by_bios,
-	.hardware_setup = hardware_setup,
-	.hardware_unsetup = hardware_unsetup,
-	.check_processor_compatibility = vmx_check_processor_compat,
-	.hardware_enable = hardware_enable,
-	.hardware_disable = hardware_disable,
-
-	.vcpu_create = vmx_create_vcpu,
-	.vcpu_free = vmx_free_vcpu,
-	.vcpu_reset = vmx_vcpu_reset,
-
-	.prepare_guest_switch = vmx_save_host_state,
-	.vcpu_load = vmx_vcpu_load,
-	.vcpu_put = vmx_vcpu_put,
-	.vcpu_decache = vmx_vcpu_decache,
-
-	.set_guest_debug = set_guest_debug,
-	.guest_debug_pre = kvm_guest_debug_pre,
-	.get_msr = vmx_get_msr,
-	.set_msr = vmx_set_msr,
-	.get_segment_base = vmx_get_segment_base,
-	.get_segment = vmx_get_segment,
-	.set_segment = vmx_set_segment,
-	.get_cs_db_l_bits = vmx_get_cs_db_l_bits,
-	.decache_cr4_guest_bits = vmx_decache_cr4_guest_bits,
-	.set_cr0 = vmx_set_cr0,
-	.set_cr3 = vmx_set_cr3,
-	.set_cr4 = vmx_set_cr4,
-#ifdef CONFIG_X86_64
-	.set_efer = vmx_set_efer,
-#endif
-	.get_idt = vmx_get_idt,
-	.set_idt = vmx_set_idt,
-	.get_gdt = vmx_get_gdt,
-	.set_gdt = vmx_set_gdt,
-	.cache_regs = vcpu_load_rsp_rip,
-	.decache_regs = vcpu_put_rsp_rip,
-	.get_rflags = vmx_get_rflags,
-	.set_rflags = vmx_set_rflags,
-
-	.tlb_flush = vmx_flush_tlb,
-	.inject_page_fault = vmx_inject_page_fault,
-
-	.inject_gp = vmx_inject_gp,
-
-	.run = vmx_vcpu_run,
-	.handle_exit = kvm_handle_exit,
-	.skip_emulated_instruction = skip_emulated_instruction,
-	.patch_hypercall = vmx_patch_hypercall,
-	.get_irq = vmx_get_irq,
-	.set_irq = vmx_inject_irq,
-	.inject_pending_irq = vmx_intr_assist,
-	.inject_pending_vectors = do_interrupt_requests,
-};
-
-static int __init vmx_init(void)
-{
-	void *iova;
-	int r;
-
-	vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
-	if (!vmx_io_bitmap_a)
-		return -ENOMEM;
-
-	vmx_io_bitmap_b = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
-	if (!vmx_io_bitmap_b) {
-		r = -ENOMEM;
-		goto out;
-	}
-
-	/*
-	 * Allow direct access to the PC debug port (it is often used for I/O
-	 * delays, but the vmexits simply slow things down).
-	 */
-	iova = kmap(vmx_io_bitmap_a);
-	memset(iova, 0xff, PAGE_SIZE);
-	clear_bit(0x80, iova);
-	kunmap(vmx_io_bitmap_a);
-
-	iova = kmap(vmx_io_bitmap_b);
-	memset(iova, 0xff, PAGE_SIZE);
-	kunmap(vmx_io_bitmap_b);
-
-	r = kvm_init_x86(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
-	if (r)
-		goto out1;
-
-	return 0;
-
-out1:
-	__free_page(vmx_io_bitmap_b);
-out:
-	__free_page(vmx_io_bitmap_a);
-	return r;
-}
-
-static void __exit vmx_exit(void)
-{
-	__free_page(vmx_io_bitmap_b);
-	__free_page(vmx_io_bitmap_a);
-
-	kvm_exit_x86();
-}
-
-module_init(vmx_init)
-module_exit(vmx_exit)
diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h
deleted file mode 100644
index fd4e14666088..000000000000
--- a/drivers/kvm/vmx.h
+++ /dev/null
@@ -1,310 +0,0 @@
-#ifndef VMX_H
-#define VMX_H
-
-/*
- * vmx.h: VMX Architecture related definitions
- * Copyright (c) 2004, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * A few random additions are:
- * Copyright (C) 2006 Qumranet
- *    Avi Kivity <avi@qumranet.com>
- *    Yaniv Kamay <yaniv@qumranet.com>
- *
- */
-
-#define CPU_BASED_VIRTUAL_INTR_PENDING          0x00000004
-#define CPU_BASED_USE_TSC_OFFSETING             0x00000008
-#define CPU_BASED_HLT_EXITING                   0x00000080
-#define CPU_BASED_INVLPG_EXITING                0x00000200
-#define CPU_BASED_MWAIT_EXITING                 0x00000400
-#define CPU_BASED_RDPMC_EXITING                 0x00000800
-#define CPU_BASED_RDTSC_EXITING                 0x00001000
-#define CPU_BASED_CR8_LOAD_EXITING              0x00080000
-#define CPU_BASED_CR8_STORE_EXITING             0x00100000
-#define CPU_BASED_TPR_SHADOW                    0x00200000
-#define CPU_BASED_MOV_DR_EXITING                0x00800000
-#define CPU_BASED_UNCOND_IO_EXITING             0x01000000
-#define CPU_BASED_USE_IO_BITMAPS                0x02000000
-#define CPU_BASED_USE_MSR_BITMAPS               0x10000000
-#define CPU_BASED_MONITOR_EXITING               0x20000000
-#define CPU_BASED_PAUSE_EXITING                 0x40000000
-#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS   0x80000000
-
-#define PIN_BASED_EXT_INTR_MASK                 0x00000001
-#define PIN_BASED_NMI_EXITING                   0x00000008
-#define PIN_BASED_VIRTUAL_NMIS                  0x00000020
-
-#define VM_EXIT_HOST_ADDR_SPACE_SIZE            0x00000200
-#define VM_EXIT_ACK_INTR_ON_EXIT                0x00008000
-
-#define VM_ENTRY_IA32E_MODE                     0x00000200
-#define VM_ENTRY_SMM                            0x00000400
-#define VM_ENTRY_DEACT_DUAL_MONITOR             0x00000800
-
-#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
-
-/* VMCS Encodings */
-enum vmcs_field {
-	GUEST_ES_SELECTOR               = 0x00000800,
-	GUEST_CS_SELECTOR               = 0x00000802,
-	GUEST_SS_SELECTOR               = 0x00000804,
-	GUEST_DS_SELECTOR               = 0x00000806,
-	GUEST_FS_SELECTOR               = 0x00000808,
-	GUEST_GS_SELECTOR               = 0x0000080a,
-	GUEST_LDTR_SELECTOR             = 0x0000080c,
-	GUEST_TR_SELECTOR               = 0x0000080e,
-	HOST_ES_SELECTOR                = 0x00000c00,
-	HOST_CS_SELECTOR                = 0x00000c02,
-	HOST_SS_SELECTOR                = 0x00000c04,
-	HOST_DS_SELECTOR                = 0x00000c06,
-	HOST_FS_SELECTOR                = 0x00000c08,
-	HOST_GS_SELECTOR                = 0x00000c0a,
-	HOST_TR_SELECTOR                = 0x00000c0c,
-	IO_BITMAP_A                     = 0x00002000,
-	IO_BITMAP_A_HIGH                = 0x00002001,
-	IO_BITMAP_B                     = 0x00002002,
-	IO_BITMAP_B_HIGH                = 0x00002003,
-	MSR_BITMAP                      = 0x00002004,
-	MSR_BITMAP_HIGH                 = 0x00002005,
-	VM_EXIT_MSR_STORE_ADDR          = 0x00002006,
-	VM_EXIT_MSR_STORE_ADDR_HIGH     = 0x00002007,
-	VM_EXIT_MSR_LOAD_ADDR           = 0x00002008,
-	VM_EXIT_MSR_LOAD_ADDR_HIGH      = 0x00002009,
-	VM_ENTRY_MSR_LOAD_ADDR          = 0x0000200a,
-	VM_ENTRY_MSR_LOAD_ADDR_HIGH     = 0x0000200b,
-	TSC_OFFSET                      = 0x00002010,
-	TSC_OFFSET_HIGH                 = 0x00002011,
-	VIRTUAL_APIC_PAGE_ADDR          = 0x00002012,
-	VIRTUAL_APIC_PAGE_ADDR_HIGH     = 0x00002013,
-	VMCS_LINK_POINTER               = 0x00002800,
-	VMCS_LINK_POINTER_HIGH          = 0x00002801,
-	GUEST_IA32_DEBUGCTL             = 0x00002802,
-	GUEST_IA32_DEBUGCTL_HIGH        = 0x00002803,
-	PIN_BASED_VM_EXEC_CONTROL       = 0x00004000,
-	CPU_BASED_VM_EXEC_CONTROL       = 0x00004002,
-	EXCEPTION_BITMAP                = 0x00004004,
-	PAGE_FAULT_ERROR_CODE_MASK      = 0x00004006,
-	PAGE_FAULT_ERROR_CODE_MATCH     = 0x00004008,
-	CR3_TARGET_COUNT                = 0x0000400a,
-	VM_EXIT_CONTROLS                = 0x0000400c,
-	VM_EXIT_MSR_STORE_COUNT         = 0x0000400e,
-	VM_EXIT_MSR_LOAD_COUNT          = 0x00004010,
-	VM_ENTRY_CONTROLS               = 0x00004012,
-	VM_ENTRY_MSR_LOAD_COUNT         = 0x00004014,
-	VM_ENTRY_INTR_INFO_FIELD        = 0x00004016,
-	VM_ENTRY_EXCEPTION_ERROR_CODE   = 0x00004018,
-	VM_ENTRY_INSTRUCTION_LEN        = 0x0000401a,
-	TPR_THRESHOLD                   = 0x0000401c,
-	SECONDARY_VM_EXEC_CONTROL       = 0x0000401e,
-	VM_INSTRUCTION_ERROR            = 0x00004400,
-	VM_EXIT_REASON                  = 0x00004402,
-	VM_EXIT_INTR_INFO               = 0x00004404,
-	VM_EXIT_INTR_ERROR_CODE         = 0x00004406,
-	IDT_VECTORING_INFO_FIELD        = 0x00004408,
-	IDT_VECTORING_ERROR_CODE        = 0x0000440a,
-	VM_EXIT_INSTRUCTION_LEN         = 0x0000440c,
-	VMX_INSTRUCTION_INFO            = 0x0000440e,
-	GUEST_ES_LIMIT                  = 0x00004800,
-	GUEST_CS_LIMIT                  = 0x00004802,
-	GUEST_SS_LIMIT                  = 0x00004804,
-	GUEST_DS_LIMIT                  = 0x00004806,
-	GUEST_FS_LIMIT                  = 0x00004808,
-	GUEST_GS_LIMIT                  = 0x0000480a,
-	GUEST_LDTR_LIMIT                = 0x0000480c,
-	GUEST_TR_LIMIT                  = 0x0000480e,
-	GUEST_GDTR_LIMIT                = 0x00004810,
-	GUEST_IDTR_LIMIT                = 0x00004812,
-	GUEST_ES_AR_BYTES               = 0x00004814,
-	GUEST_CS_AR_BYTES               = 0x00004816,
-	GUEST_SS_AR_BYTES               = 0x00004818,
-	GUEST_DS_AR_BYTES               = 0x0000481a,
-	GUEST_FS_AR_BYTES               = 0x0000481c,
-	GUEST_GS_AR_BYTES               = 0x0000481e,
-	GUEST_LDTR_AR_BYTES             = 0x00004820,
-	GUEST_TR_AR_BYTES               = 0x00004822,
-	GUEST_INTERRUPTIBILITY_INFO     = 0x00004824,
-	GUEST_ACTIVITY_STATE            = 0X00004826,
-	GUEST_SYSENTER_CS               = 0x0000482A,
-	HOST_IA32_SYSENTER_CS           = 0x00004c00,
-	CR0_GUEST_HOST_MASK             = 0x00006000,
-	CR4_GUEST_HOST_MASK             = 0x00006002,
-	CR0_READ_SHADOW                 = 0x00006004,
-	CR4_READ_SHADOW                 = 0x00006006,
-	CR3_TARGET_VALUE0               = 0x00006008,
-	CR3_TARGET_VALUE1               = 0x0000600a,
-	CR3_TARGET_VALUE2               = 0x0000600c,
-	CR3_TARGET_VALUE3               = 0x0000600e,
-	EXIT_QUALIFICATION              = 0x00006400,
-	GUEST_LINEAR_ADDRESS            = 0x0000640a,
-	GUEST_CR0                       = 0x00006800,
-	GUEST_CR3                       = 0x00006802,
-	GUEST_CR4                       = 0x00006804,
-	GUEST_ES_BASE                   = 0x00006806,
-	GUEST_CS_BASE                   = 0x00006808,
-	GUEST_SS_BASE                   = 0x0000680a,
-	GUEST_DS_BASE                   = 0x0000680c,
-	GUEST_FS_BASE                   = 0x0000680e,
-	GUEST_GS_BASE                   = 0x00006810,
-	GUEST_LDTR_BASE                 = 0x00006812,
-	GUEST_TR_BASE                   = 0x00006814,
-	GUEST_GDTR_BASE                 = 0x00006816,
-	GUEST_IDTR_BASE                 = 0x00006818,
-	GUEST_DR7                       = 0x0000681a,
-	GUEST_RSP                       = 0x0000681c,
-	GUEST_RIP                       = 0x0000681e,
-	GUEST_RFLAGS                    = 0x00006820,
-	GUEST_PENDING_DBG_EXCEPTIONS    = 0x00006822,
-	GUEST_SYSENTER_ESP              = 0x00006824,
-	GUEST_SYSENTER_EIP              = 0x00006826,
-	HOST_CR0                        = 0x00006c00,
-	HOST_CR3                        = 0x00006c02,
-	HOST_CR4                        = 0x00006c04,
-	HOST_FS_BASE                    = 0x00006c06,
-	HOST_GS_BASE                    = 0x00006c08,
-	HOST_TR_BASE                    = 0x00006c0a,
-	HOST_GDTR_BASE                  = 0x00006c0c,
-	HOST_IDTR_BASE                  = 0x00006c0e,
-	HOST_IA32_SYSENTER_ESP          = 0x00006c10,
-	HOST_IA32_SYSENTER_EIP          = 0x00006c12,
-	HOST_RSP                        = 0x00006c14,
-	HOST_RIP                        = 0x00006c16,
-};
-
-#define VMX_EXIT_REASONS_FAILED_VMENTRY         0x80000000
-
-#define EXIT_REASON_EXCEPTION_NMI       0
-#define EXIT_REASON_EXTERNAL_INTERRUPT  1
-#define EXIT_REASON_TRIPLE_FAULT        2
-
-#define EXIT_REASON_PENDING_INTERRUPT   7
-
-#define EXIT_REASON_TASK_SWITCH         9
-#define EXIT_REASON_CPUID               10
-#define EXIT_REASON_HLT                 12
-#define EXIT_REASON_INVLPG              14
-#define EXIT_REASON_RDPMC               15
-#define EXIT_REASON_RDTSC               16
-#define EXIT_REASON_VMCALL              18
-#define EXIT_REASON_VMCLEAR             19
-#define EXIT_REASON_VMLAUNCH            20
-#define EXIT_REASON_VMPTRLD             21
-#define EXIT_REASON_VMPTRST             22
-#define EXIT_REASON_VMREAD              23
-#define EXIT_REASON_VMRESUME            24
-#define EXIT_REASON_VMWRITE             25
-#define EXIT_REASON_VMOFF               26
-#define EXIT_REASON_VMON                27
-#define EXIT_REASON_CR_ACCESS           28
-#define EXIT_REASON_DR_ACCESS           29
-#define EXIT_REASON_IO_INSTRUCTION      30
-#define EXIT_REASON_MSR_READ            31
-#define EXIT_REASON_MSR_WRITE           32
-#define EXIT_REASON_MWAIT_INSTRUCTION   36
-#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
-
-/*
- * Interruption-information format
- */
-#define INTR_INFO_VECTOR_MASK           0xff            /* 7:0 */
-#define INTR_INFO_INTR_TYPE_MASK        0x700           /* 10:8 */
-#define INTR_INFO_DELIEVER_CODE_MASK    0x800           /* 11 */
-#define INTR_INFO_VALID_MASK            0x80000000      /* 31 */
-
-#define VECTORING_INFO_VECTOR_MASK           	INTR_INFO_VECTOR_MASK
-#define VECTORING_INFO_TYPE_MASK        	INTR_INFO_INTR_TYPE_MASK
-#define VECTORING_INFO_DELIEVER_CODE_MASK    	INTR_INFO_DELIEVER_CODE_MASK
-#define VECTORING_INFO_VALID_MASK       	INTR_INFO_VALID_MASK
-
-#define INTR_TYPE_EXT_INTR              (0 << 8) /* external interrupt */
-#define INTR_TYPE_EXCEPTION             (3 << 8) /* processor exception */
-
-/*
- * Exit Qualifications for MOV for Control Register Access
- */
-#define CONTROL_REG_ACCESS_NUM          0x7     /* 2:0, number of control register */
-#define CONTROL_REG_ACCESS_TYPE         0x30    /* 5:4, access type */
-#define CONTROL_REG_ACCESS_REG          0xf00   /* 10:8, general purpose register */
-#define LMSW_SOURCE_DATA_SHIFT 16
-#define LMSW_SOURCE_DATA  (0xFFFF << LMSW_SOURCE_DATA_SHIFT) /* 16:31 lmsw source */
-#define REG_EAX                         (0 << 8)
-#define REG_ECX                         (1 << 8)
-#define REG_EDX                         (2 << 8)
-#define REG_EBX                         (3 << 8)
-#define REG_ESP                         (4 << 8)
-#define REG_EBP                         (5 << 8)
-#define REG_ESI                         (6 << 8)
-#define REG_EDI                         (7 << 8)
-#define REG_R8                         (8 << 8)
-#define REG_R9                         (9 << 8)
-#define REG_R10                        (10 << 8)
-#define REG_R11                        (11 << 8)
-#define REG_R12                        (12 << 8)
-#define REG_R13                        (13 << 8)
-#define REG_R14                        (14 << 8)
-#define REG_R15                        (15 << 8)
-
-/*
- * Exit Qualifications for MOV for Debug Register Access
- */
-#define DEBUG_REG_ACCESS_NUM            0x7     /* 2:0, number of debug register */
-#define DEBUG_REG_ACCESS_TYPE           0x10    /* 4, direction of access */
-#define TYPE_MOV_TO_DR                  (0 << 4)
-#define TYPE_MOV_FROM_DR                (1 << 4)
-#define DEBUG_REG_ACCESS_REG            0xf00   /* 11:8, general purpose register */
-
-
-/* segment AR */
-#define SEGMENT_AR_L_MASK (1 << 13)
-
-#define AR_TYPE_ACCESSES_MASK 1
-#define AR_TYPE_READABLE_MASK (1 << 1)
-#define AR_TYPE_WRITEABLE_MASK (1 << 2)
-#define AR_TYPE_CODE_MASK (1 << 3)
-#define AR_TYPE_MASK 0x0f
-#define AR_TYPE_BUSY_64_TSS 11
-#define AR_TYPE_BUSY_32_TSS 11
-#define AR_TYPE_BUSY_16_TSS 3
-#define AR_TYPE_LDT 2
-
-#define AR_UNUSABLE_MASK (1 << 16)
-#define AR_S_MASK (1 << 4)
-#define AR_P_MASK (1 << 7)
-#define AR_L_MASK (1 << 13)
-#define AR_DB_MASK (1 << 14)
-#define AR_G_MASK (1 << 15)
-#define AR_DPL_SHIFT 5
-#define AR_DPL(ar) (((ar) >> AR_DPL_SHIFT) & 3)
-
-#define AR_RESERVD_MASK 0xfffe0f00
-
-#define MSR_IA32_VMX_BASIC                      0x480
-#define MSR_IA32_VMX_PINBASED_CTLS              0x481
-#define MSR_IA32_VMX_PROCBASED_CTLS             0x482
-#define MSR_IA32_VMX_EXIT_CTLS                  0x483
-#define MSR_IA32_VMX_ENTRY_CTLS                 0x484
-#define MSR_IA32_VMX_MISC                       0x485
-#define MSR_IA32_VMX_CR0_FIXED0                 0x486
-#define MSR_IA32_VMX_CR0_FIXED1                 0x487
-#define MSR_IA32_VMX_CR4_FIXED0                 0x488
-#define MSR_IA32_VMX_CR4_FIXED1                 0x489
-#define MSR_IA32_VMX_VMCS_ENUM                  0x48a
-#define MSR_IA32_VMX_PROCBASED_CTLS2            0x48b
-
-#define MSR_IA32_FEATURE_CONTROL                0x3a
-#define MSR_IA32_FEATURE_CONTROL_LOCKED         0x1
-#define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED  0x4
-
-#endif
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
deleted file mode 100644
index bd46de6bf891..000000000000
--- a/drivers/kvm/x86_emulate.c
+++ /dev/null
@@ -1,1662 +0,0 @@
-/******************************************************************************
- * x86_emulate.c
- *
- * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
- *
- * Copyright (c) 2005 Keir Fraser
- *
- * Linux coding style, mod r/m decoder, segment base fixes, real-mode
- * privileged instructions:
- *
- * Copyright (C) 2006 Qumranet
- *
- *   Avi Kivity <avi@qumranet.com>
- *   Yaniv Kamay <yaniv@qumranet.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4
- */
-
-#ifndef __KERNEL__
-#include <stdio.h>
-#include <stdint.h>
-#include <public/xen.h>
-#define DPRINTF(_f, _a ...) printf( _f , ## _a )
-#else
-#include "kvm.h"
-#define DPRINTF(x...) do {} while (0)
-#endif
-#include "x86_emulate.h"
-#include <linux/module.h>
-
-/*
- * Opcode effective-address decode tables.
- * Note that we only emulate instructions that have at least one memory
- * operand (excluding implicit stack references). We assume that stack
- * references and instruction fetches will never occur in special memory
- * areas that require emulation. So, for example, 'mov <imm>,<reg>' need
- * not be handled.
- */
-
-/* Operand sizes: 8-bit operands or specified/overridden size. */
-#define ByteOp      (1<<0)	/* 8-bit operands. */
-/* Destination operand type. */
-#define ImplicitOps (1<<1)	/* Implicit in opcode. No generic decode. */
-#define DstReg      (2<<1)	/* Register operand. */
-#define DstMem      (3<<1)	/* Memory operand. */
-#define DstMask     (3<<1)
-/* Source operand type. */
-#define SrcNone     (0<<3)	/* No source operand. */
-#define SrcImplicit (0<<3)	/* Source operand is implicit in the opcode. */
-#define SrcReg      (1<<3)	/* Register operand. */
-#define SrcMem      (2<<3)	/* Memory operand. */
-#define SrcMem16    (3<<3)	/* Memory operand (16-bit). */
-#define SrcMem32    (4<<3)	/* Memory operand (32-bit). */
-#define SrcImm      (5<<3)	/* Immediate operand. */
-#define SrcImmByte  (6<<3)	/* 8-bit sign-extended immediate operand. */
-#define SrcMask     (7<<3)
-/* Generic ModRM decode. */
-#define ModRM       (1<<6)
-/* Destination is only written; never read. */
-#define Mov         (1<<7)
-#define BitOp       (1<<8)
-
-static u8 opcode_table[256] = {
-	/* 0x00 - 0x07 */
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
-	/* 0x08 - 0x0F */
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
-	/* 0x10 - 0x17 */
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
-	/* 0x18 - 0x1F */
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
-	/* 0x20 - 0x27 */
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	SrcImmByte, SrcImm, 0, 0,
-	/* 0x28 - 0x2F */
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
-	/* 0x30 - 0x37 */
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
-	/* 0x38 - 0x3F */
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-	0, 0, 0, 0,
-	/* 0x40 - 0x4F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x50 - 0x57 */
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	/* 0x58 - 0x5F */
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	/* 0x60 - 0x67 */
-	0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
-	0, 0, 0, 0,
-	/* 0x68 - 0x6F */
-	0, 0, ImplicitOps|Mov, 0,
-	SrcNone  | ByteOp  | ImplicitOps, SrcNone  | ImplicitOps, /* insb, insw/insd */
-	SrcNone  | ByteOp  | ImplicitOps, SrcNone  | ImplicitOps, /* outsb, outsw/outsd */
-	/* 0x70 - 0x77 */
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	/* 0x78 - 0x7F */
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	/* 0x80 - 0x87 */
-	ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
-	ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-	/* 0x88 - 0x8F */
-	ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
-	ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	0, ModRM | DstReg, 0, DstMem | SrcNone | ModRM | Mov,
-	/* 0x90 - 0x9F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps, ImplicitOps, 0, 0,
-	/* 0xA0 - 0xA7 */
-	ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov,
-	ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov,
-	ByteOp | ImplicitOps | Mov, ImplicitOps | Mov,
-	ByteOp | ImplicitOps, ImplicitOps,
-	/* 0xA8 - 0xAF */
-	0, 0, ByteOp | ImplicitOps | Mov, ImplicitOps | Mov,
-	ByteOp | ImplicitOps | Mov, ImplicitOps | Mov,
-	ByteOp | ImplicitOps, ImplicitOps,
-	/* 0xB0 - 0xBF */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xC0 - 0xC7 */
-	ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
-	0, ImplicitOps, 0, 0,
-	ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov,
-	/* 0xC8 - 0xCF */
-	0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xD0 - 0xD7 */
-	ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
-	ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM,
-	0, 0, 0, 0,
-	/* 0xD8 - 0xDF */
-	0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xE0 - 0xE7 */
-	0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xE8 - 0xEF */
-	ImplicitOps, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps, 0, 0, 0, 0,
-	/* 0xF0 - 0xF7 */
-	0, 0, 0, 0,
-	ImplicitOps, 0,
-	ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
-	/* 0xF8 - 0xFF */
-	0, 0, 0, 0,
-	0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM
-};
-
-static u16 twobyte_table[256] = {
-	/* 0x00 - 0x0F */
-	0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0,
-	ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
-	/* 0x10 - 0x1F */
-	0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x20 - 0x2F */
-	ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x30 - 0x3F */
-	ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x40 - 0x47 */
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	/* 0x48 - 0x4F */
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
-	/* 0x50 - 0x5F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x60 - 0x6F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x70 - 0x7F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0x80 - 0x8F */
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
-	/* 0x90 - 0x9F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xA0 - 0xA7 */
-	0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0,
-	/* 0xA8 - 0xAF */
-	0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0,
-	/* 0xB0 - 0xB7 */
-	ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0,
-	    DstMem | SrcReg | ModRM | BitOp,
-	0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
-	    DstReg | SrcMem16 | ModRM | Mov,
-	/* 0xB8 - 0xBF */
-	0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM | BitOp,
-	0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
-	    DstReg | SrcMem16 | ModRM | Mov,
-	/* 0xC0 - 0xCF */
-	0, 0, 0, DstMem | SrcReg | ModRM | Mov, 0, 0, 0, ImplicitOps | ModRM,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xD0 - 0xDF */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xE0 - 0xEF */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	/* 0xF0 - 0xFF */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* Type, address-of, and value of an instruction's operand. */
-struct operand {
-	enum { OP_REG, OP_MEM, OP_IMM } type;
-	unsigned int bytes;
-	unsigned long val, orig_val, *ptr;
-};
-
-/* EFLAGS bit definitions. */
-#define EFLG_OF (1<<11)
-#define EFLG_DF (1<<10)
-#define EFLG_SF (1<<7)
-#define EFLG_ZF (1<<6)
-#define EFLG_AF (1<<4)
-#define EFLG_PF (1<<2)
-#define EFLG_CF (1<<0)
-
-/*
- * Instruction emulation:
- * Most instructions are emulated directly via a fragment of inline assembly
- * code. This allows us to save/restore EFLAGS and thus very easily pick up
- * any modified flags.
- */
-
-#if defined(CONFIG_X86_64)
-#define _LO32 "k"		/* force 32-bit operand */
-#define _STK  "%%rsp"		/* stack pointer */
-#elif defined(__i386__)
-#define _LO32 ""		/* force 32-bit operand */
-#define _STK  "%%esp"		/* stack pointer */
-#endif
-
-/*
- * These EFLAGS bits are restored from saved value during emulation, and
- * any changes are written back to the saved value after emulation.
- */
-#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF)
-
-/* Before executing instruction: restore necessary bits in EFLAGS. */
-#define _PRE_EFLAGS(_sav, _msk, _tmp) \
-	/* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); */	\
-	"push %"_sav"; "					\
-	"movl %"_msk",%"_LO32 _tmp"; "				\
-	"andl %"_LO32 _tmp",("_STK"); "				\
-	"pushf; "						\
-	"notl %"_LO32 _tmp"; "					\
-	"andl %"_LO32 _tmp",("_STK"); "				\
-	"pop  %"_tmp"; "					\
-	"orl  %"_LO32 _tmp",("_STK"); "				\
-	"popf; "						\
-	/* _sav &= ~msk; */					\
-	"movl %"_msk",%"_LO32 _tmp"; "				\
-	"notl %"_LO32 _tmp"; "					\
-	"andl %"_LO32 _tmp",%"_sav"; "
-
-/* After executing instruction: write-back necessary bits in EFLAGS. */
-#define _POST_EFLAGS(_sav, _msk, _tmp) \
-	/* _sav |= EFLAGS & _msk; */		\
-	"pushf; "				\
-	"pop  %"_tmp"; "			\
-	"andl %"_msk",%"_LO32 _tmp"; "		\
-	"orl  %"_LO32 _tmp",%"_sav"; "
-
-/* Raw emulation: instruction has two explicit operands. */
-#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy) \
-	do { 								    \
-		unsigned long _tmp;					    \
-									    \
-		switch ((_dst).bytes) {					    \
-		case 2:							    \
-			__asm__ __volatile__ (				    \
-				_PRE_EFLAGS("0","4","2")		    \
-				_op"w %"_wx"3,%1; "			    \
-				_POST_EFLAGS("0","4","2")		    \
-				: "=m" (_eflags), "=m" ((_dst).val),        \
-				  "=&r" (_tmp)				    \
-				: _wy ((_src).val), "i" (EFLAGS_MASK) );    \
-			break;						    \
-		case 4:							    \
-			__asm__ __volatile__ (				    \
-				_PRE_EFLAGS("0","4","2")		    \
-				_op"l %"_lx"3,%1; "			    \
-				_POST_EFLAGS("0","4","2")		    \
-				: "=m" (_eflags), "=m" ((_dst).val),	    \
-				  "=&r" (_tmp)				    \
-				: _ly ((_src).val), "i" (EFLAGS_MASK) );    \
-			break;						    \
-		case 8:							    \
-			__emulate_2op_8byte(_op, _src, _dst,		    \
-					    _eflags, _qx, _qy);		    \
-			break;						    \
-		}							    \
-	} while (0)
-
-#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \
-	do {								     \
-		unsigned long _tmp;					     \
-		switch ( (_dst).bytes )					     \
-		{							     \
-		case 1:							     \
-			__asm__ __volatile__ (				     \
-				_PRE_EFLAGS("0","4","2")		     \
-				_op"b %"_bx"3,%1; "			     \
-				_POST_EFLAGS("0","4","2")		     \
-				: "=m" (_eflags), "=m" ((_dst).val),	     \
-				  "=&r" (_tmp)				     \
-				: _by ((_src).val), "i" (EFLAGS_MASK) );     \
-			break;						     \
-		default:						     \
-			__emulate_2op_nobyte(_op, _src, _dst, _eflags,	     \
-					     _wx, _wy, _lx, _ly, _qx, _qy);  \
-			break;						     \
-		}							     \
-	} while (0)
-
-/* Source operand is byte-sized and may be restricted to just %cl. */
-#define emulate_2op_SrcB(_op, _src, _dst, _eflags)                      \
-	__emulate_2op(_op, _src, _dst, _eflags,				\
-		      "b", "c", "b", "c", "b", "c", "b", "c")
-
-/* Source operand is byte, word, long or quad sized. */
-#define emulate_2op_SrcV(_op, _src, _dst, _eflags)                      \
-	__emulate_2op(_op, _src, _dst, _eflags,				\
-		      "b", "q", "w", "r", _LO32, "r", "", "r")
-
-/* Source operand is word, long or quad sized. */
-#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags)               \
-	__emulate_2op_nobyte(_op, _src, _dst, _eflags,			\
-			     "w", "r", _LO32, "r", "", "r")
-
-/* Instruction has only one explicit operand (no source operand). */
-#define emulate_1op(_op, _dst, _eflags)                                    \
-	do {								\
-		unsigned long _tmp;					\
-									\
-		switch ( (_dst).bytes )					\
-		{							\
-		case 1:							\
-			__asm__ __volatile__ (				\
-				_PRE_EFLAGS("0","3","2")		\
-				_op"b %1; "				\
-				_POST_EFLAGS("0","3","2")		\
-				: "=m" (_eflags), "=m" ((_dst).val),	\
-				  "=&r" (_tmp)				\
-				: "i" (EFLAGS_MASK) );			\
-			break;						\
-		case 2:							\
-			__asm__ __volatile__ (				\
-				_PRE_EFLAGS("0","3","2")		\
-				_op"w %1; "				\
-				_POST_EFLAGS("0","3","2")		\
-				: "=m" (_eflags), "=m" ((_dst).val),	\
-				  "=&r" (_tmp)				\
-				: "i" (EFLAGS_MASK) );			\
-			break;						\
-		case 4:							\
-			__asm__ __volatile__ (				\
-				_PRE_EFLAGS("0","3","2")		\
-				_op"l %1; "				\
-				_POST_EFLAGS("0","3","2")		\
-				: "=m" (_eflags), "=m" ((_dst).val),	\
-				  "=&r" (_tmp)				\
-				: "i" (EFLAGS_MASK) );			\
-			break;						\
-		case 8:							\
-			__emulate_1op_8byte(_op, _dst, _eflags);	\
-			break;						\
-		}							\
-	} while (0)
-
-/* Emulate an instruction with quadword operands (x86/64 only). */
-#if defined(CONFIG_X86_64)
-#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)           \
-	do {								  \
-		__asm__ __volatile__ (					  \
-			_PRE_EFLAGS("0","4","2")			  \
-			_op"q %"_qx"3,%1; "				  \
-			_POST_EFLAGS("0","4","2")			  \
-			: "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
-			: _qy ((_src).val), "i" (EFLAGS_MASK) );	  \
-	} while (0)
-
-#define __emulate_1op_8byte(_op, _dst, _eflags)                           \
-	do {								  \
-		__asm__ __volatile__ (					  \
-			_PRE_EFLAGS("0","3","2")			  \
-			_op"q %1; "					  \
-			_POST_EFLAGS("0","3","2")			  \
-			: "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \
-			: "i" (EFLAGS_MASK) );				  \
-	} while (0)
-
-#elif defined(__i386__)
-#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy)
-#define __emulate_1op_8byte(_op, _dst, _eflags)
-#endif				/* __i386__ */
-
-/* Fetch next part of the instruction being emulated. */
-#define insn_fetch(_type, _size, _eip)                                  \
-({	unsigned long _x;						\
-	rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x,	\
-                                                  (_size), ctxt->vcpu); \
-	if ( rc != 0 )							\
-		goto done;						\
-	(_eip) += (_size);						\
-	(_type)_x;							\
-})
-
-/* Access/update address held in a register, based on addressing mode. */
-#define address_mask(reg)						\
-	((ad_bytes == sizeof(unsigned long)) ? 				\
-		(reg) :	((reg) & ((1UL << (ad_bytes << 3)) - 1)))
-#define register_address(base, reg)                                     \
-	((base) + address_mask(reg))
-#define register_address_increment(reg, inc)                            \
-	do {								\
-		/* signed type ensures sign extension to long */        \
-		int _inc = (inc);					\
-		if ( ad_bytes == sizeof(unsigned long) )		\
-			(reg) += _inc;					\
-		else							\
-			(reg) = ((reg) & ~((1UL << (ad_bytes << 3)) - 1)) | \
-			   (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \
-	} while (0)
-
-#define JMP_REL(rel) 							\
-	do {								\
-		register_address_increment(_eip, rel);			\
-	} while (0)
-
-/*
- * Given the 'reg' portion of a ModRM byte, and a register block, return a
- * pointer into the block that addresses the relevant register.
- * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
- */
-static void *decode_register(u8 modrm_reg, unsigned long *regs,
-			     int highbyte_regs)
-{
-	void *p;
-
-	p = &regs[modrm_reg];
-	if (highbyte_regs && modrm_reg >= 4 && modrm_reg < 8)
-		p = (unsigned char *)&regs[modrm_reg & 3] + 1;
-	return p;
-}
-
-static int read_descriptor(struct x86_emulate_ctxt *ctxt,
-			   struct x86_emulate_ops *ops,
-			   void *ptr,
-			   u16 *size, unsigned long *address, int op_bytes)
-{
-	int rc;
-
-	if (op_bytes == 2)
-		op_bytes = 3;
-	*address = 0;
-	rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2,
-			   ctxt->vcpu);
-	if (rc)
-		return rc;
-	rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes,
-			   ctxt->vcpu);
-	return rc;
-}
-
-static int test_cc(unsigned int condition, unsigned int flags)
-{
-	int rc = 0;
-
-	switch ((condition & 15) >> 1) {
-	case 0: /* o */
-		rc |= (flags & EFLG_OF);
-		break;
-	case 1: /* b/c/nae */
-		rc |= (flags & EFLG_CF);
-		break;
-	case 2: /* z/e */
-		rc |= (flags & EFLG_ZF);
-		break;
-	case 3: /* be/na */
-		rc |= (flags & (EFLG_CF|EFLG_ZF));
-		break;
-	case 4: /* s */
-		rc |= (flags & EFLG_SF);
-		break;
-	case 5: /* p/pe */
-		rc |= (flags & EFLG_PF);
-		break;
-	case 7: /* le/ng */
-		rc |= (flags & EFLG_ZF);
-		/* fall through */
-	case 6: /* l/nge */
-		rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF));
-		break;
-	}
-
-	/* Odd condition identifiers (lsb == 1) have inverted sense. */
-	return (!!rc ^ (condition & 1));
-}
-
-int
-x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
-{
-	unsigned d;
-	u8 b, sib, twobyte = 0, rex_prefix = 0;
-	u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
-	unsigned long *override_base = NULL;
-	unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
-	int rc = 0;
-	struct operand src, dst;
-	unsigned long cr2 = ctxt->cr2;
-	int mode = ctxt->mode;
-	unsigned long modrm_ea;
-	int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
-	int no_wb = 0;
-	u64 msr_data;
-
-	/* Shadow copy of register state. Committed on successful emulation. */
-	unsigned long _regs[NR_VCPU_REGS];
-	unsigned long _eip = ctxt->vcpu->rip, _eflags = ctxt->eflags;
-	unsigned long modrm_val = 0;
-
-	memcpy(_regs, ctxt->vcpu->regs, sizeof _regs);
-
-	switch (mode) {
-	case X86EMUL_MODE_REAL:
-	case X86EMUL_MODE_PROT16:
-		op_bytes = ad_bytes = 2;
-		break;
-	case X86EMUL_MODE_PROT32:
-		op_bytes = ad_bytes = 4;
-		break;
-#ifdef CONFIG_X86_64
-	case X86EMUL_MODE_PROT64:
-		op_bytes = 4;
-		ad_bytes = 8;
-		break;
-#endif
-	default:
-		return -1;
-	}
-
-	/* Legacy prefixes. */
-	for (i = 0; i < 8; i++) {
-		switch (b = insn_fetch(u8, 1, _eip)) {
-		case 0x66:	/* operand-size override */
-			op_bytes ^= 6;	/* switch between 2/4 bytes */
-			break;
-		case 0x67:	/* address-size override */
-			if (mode == X86EMUL_MODE_PROT64)
-				ad_bytes ^= 12;	/* switch between 4/8 bytes */
-			else
-				ad_bytes ^= 6;	/* switch between 2/4 bytes */
-			break;
-		case 0x2e:	/* CS override */
-			override_base = &ctxt->cs_base;
-			break;
-		case 0x3e:	/* DS override */
-			override_base = &ctxt->ds_base;
-			break;
-		case 0x26:	/* ES override */
-			override_base = &ctxt->es_base;
-			break;
-		case 0x64:	/* FS override */
-			override_base = &ctxt->fs_base;
-			break;
-		case 0x65:	/* GS override */
-			override_base = &ctxt->gs_base;
-			break;
-		case 0x36:	/* SS override */
-			override_base = &ctxt->ss_base;
-			break;
-		case 0xf0:	/* LOCK */
-			lock_prefix = 1;
-			break;
-		case 0xf2:	/* REPNE/REPNZ */
-		case 0xf3:	/* REP/REPE/REPZ */
-			rep_prefix = 1;
-			break;
-		default:
-			goto done_prefixes;
-		}
-	}
-
-done_prefixes:
-
-	/* REX prefix. */
-	if ((mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40)) {
-		rex_prefix = b;
-		if (b & 8)
-			op_bytes = 8;	/* REX.W */
-		modrm_reg = (b & 4) << 1;	/* REX.R */
-		index_reg = (b & 2) << 2; /* REX.X */
-		modrm_rm = base_reg = (b & 1) << 3; /* REG.B */
-		b = insn_fetch(u8, 1, _eip);
-	}
-
-	/* Opcode byte(s). */
-	d = opcode_table[b];
-	if (d == 0) {
-		/* Two-byte opcode? */
-		if (b == 0x0f) {
-			twobyte = 1;
-			b = insn_fetch(u8, 1, _eip);
-			d = twobyte_table[b];
-		}
-
-		/* Unrecognised? */
-		if (d == 0)
-			goto cannot_emulate;
-	}
-
-	/* ModRM and SIB bytes. */
-	if (d & ModRM) {
-		modrm = insn_fetch(u8, 1, _eip);
-		modrm_mod |= (modrm & 0xc0) >> 6;
-		modrm_reg |= (modrm & 0x38) >> 3;
-		modrm_rm |= (modrm & 0x07);
-		modrm_ea = 0;
-		use_modrm_ea = 1;
-
-		if (modrm_mod == 3) {
-			modrm_val = *(unsigned long *)
-				decode_register(modrm_rm, _regs, d & ByteOp);
-			goto modrm_done;
-		}
-
-		if (ad_bytes == 2) {
-			unsigned bx = _regs[VCPU_REGS_RBX];
-			unsigned bp = _regs[VCPU_REGS_RBP];
-			unsigned si = _regs[VCPU_REGS_RSI];
-			unsigned di = _regs[VCPU_REGS_RDI];
-
-			/* 16-bit ModR/M decode. */
-			switch (modrm_mod) {
-			case 0:
-				if (modrm_rm == 6)
-					modrm_ea += insn_fetch(u16, 2, _eip);
-				break;
-			case 1:
-				modrm_ea += insn_fetch(s8, 1, _eip);
-				break;
-			case 2:
-				modrm_ea += insn_fetch(u16, 2, _eip);
-				break;
-			}
-			switch (modrm_rm) {
-			case 0:
-				modrm_ea += bx + si;
-				break;
-			case 1:
-				modrm_ea += bx + di;
-				break;
-			case 2:
-				modrm_ea += bp + si;
-				break;
-			case 3:
-				modrm_ea += bp + di;
-				break;
-			case 4:
-				modrm_ea += si;
-				break;
-			case 5:
-				modrm_ea += di;
-				break;
-			case 6:
-				if (modrm_mod != 0)
-					modrm_ea += bp;
-				break;
-			case 7:
-				modrm_ea += bx;
-				break;
-			}
-			if (modrm_rm == 2 || modrm_rm == 3 ||
-			    (modrm_rm == 6 && modrm_mod != 0))
-				if (!override_base)
-					override_base = &ctxt->ss_base;
-			modrm_ea = (u16)modrm_ea;
-		} else {
-			/* 32/64-bit ModR/M decode. */
-			switch (modrm_rm) {
-			case 4:
-			case 12:
-				sib = insn_fetch(u8, 1, _eip);
-				index_reg |= (sib >> 3) & 7;
-				base_reg |= sib & 7;
-				scale = sib >> 6;
-
-				switch (base_reg) {
-				case 5:
-					if (modrm_mod != 0)
-						modrm_ea += _regs[base_reg];
-					else
-						modrm_ea += insn_fetch(s32, 4, _eip);
-					break;
-				default:
-					modrm_ea += _regs[base_reg];
-				}
-				switch (index_reg) {
-				case 4:
-					break;
-				default:
-					modrm_ea += _regs[index_reg] << scale;
-
-				}
-				break;
-			case 5:
-				if (modrm_mod != 0)
-					modrm_ea += _regs[modrm_rm];
-				else if (mode == X86EMUL_MODE_PROT64)
-					rip_relative = 1;
-				break;
-			default:
-				modrm_ea += _regs[modrm_rm];
-				break;
-			}
-			switch (modrm_mod) {
-			case 0:
-				if (modrm_rm == 5)
-					modrm_ea += insn_fetch(s32, 4, _eip);
-				break;
-			case 1:
-				modrm_ea += insn_fetch(s8, 1, _eip);
-				break;
-			case 2:
-				modrm_ea += insn_fetch(s32, 4, _eip);
-				break;
-			}
-		}
-		if (!override_base)
-			override_base = &ctxt->ds_base;
-		if (mode == X86EMUL_MODE_PROT64 &&
-		    override_base != &ctxt->fs_base &&
-		    override_base != &ctxt->gs_base)
-			override_base = NULL;
-
-		if (override_base)
-			modrm_ea += *override_base;
-
-		if (rip_relative) {
-			modrm_ea += _eip;
-			switch (d & SrcMask) {
-			case SrcImmByte:
-				modrm_ea += 1;
-				break;
-			case SrcImm:
-				if (d & ByteOp)
-					modrm_ea += 1;
-				else
-					if (op_bytes == 8)
-						modrm_ea += 4;
-					else
-						modrm_ea += op_bytes;
-			}
-		}
-		if (ad_bytes != 8)
-			modrm_ea = (u32)modrm_ea;
-		cr2 = modrm_ea;
-	modrm_done:
-		;
-	}
-
-	/*
-	 * Decode and fetch the source operand: register, memory
-	 * or immediate.
-	 */
-	switch (d & SrcMask) {
-	case SrcNone:
-		break;
-	case SrcReg:
-		src.type = OP_REG;
-		if (d & ByteOp) {
-			src.ptr = decode_register(modrm_reg, _regs,
-						  (rex_prefix == 0));
-			src.val = src.orig_val = *(u8 *) src.ptr;
-			src.bytes = 1;
-		} else {
-			src.ptr = decode_register(modrm_reg, _regs, 0);
-			switch ((src.bytes = op_bytes)) {
-			case 2:
-				src.val = src.orig_val = *(u16 *) src.ptr;
-				break;
-			case 4:
-				src.val = src.orig_val = *(u32 *) src.ptr;
-				break;
-			case 8:
-				src.val = src.orig_val = *(u64 *) src.ptr;
-				break;
-			}
-		}
-		break;
-	case SrcMem16:
-		src.bytes = 2;
-		goto srcmem_common;
-	case SrcMem32:
-		src.bytes = 4;
-		goto srcmem_common;
-	case SrcMem:
-		src.bytes = (d & ByteOp) ? 1 : op_bytes;
-		/* Don't fetch the address for invlpg: it could be unmapped. */
-		if (twobyte && b == 0x01 && modrm_reg == 7)
-			break;
-	      srcmem_common:
-		/*
-		 * For instructions with a ModR/M byte, switch to register
-		 * access if Mod = 3.
-		 */
-		if ((d & ModRM) && modrm_mod == 3) {
-			src.type = OP_REG;
-			break;
-		}
-		src.type = OP_MEM;
-		src.ptr = (unsigned long *)cr2;
-		src.val = 0;
-		if ((rc = ops->read_emulated((unsigned long)src.ptr,
-					     &src.val, src.bytes, ctxt->vcpu)) != 0)
-			goto done;
-		src.orig_val = src.val;
-		break;
-	case SrcImm:
-		src.type = OP_IMM;
-		src.ptr = (unsigned long *)_eip;
-		src.bytes = (d & ByteOp) ? 1 : op_bytes;
-		if (src.bytes == 8)
-			src.bytes = 4;
-		/* NB. Immediates are sign-extended as necessary. */
-		switch (src.bytes) {
-		case 1:
-			src.val = insn_fetch(s8, 1, _eip);
-			break;
-		case 2:
-			src.val = insn_fetch(s16, 2, _eip);
-			break;
-		case 4:
-			src.val = insn_fetch(s32, 4, _eip);
-			break;
-		}
-		break;
-	case SrcImmByte:
-		src.type = OP_IMM;
-		src.ptr = (unsigned long *)_eip;
-		src.bytes = 1;
-		src.val = insn_fetch(s8, 1, _eip);
-		break;
-	}
-
-	/* Decode and fetch the destination operand: register or memory. */
-	switch (d & DstMask) {
-	case ImplicitOps:
-		/* Special instructions do their own operand decoding. */
-		goto special_insn;
-	case DstReg:
-		dst.type = OP_REG;
-		if ((d & ByteOp)
-		    && !(twobyte && (b == 0xb6 || b == 0xb7))) {
-			dst.ptr = decode_register(modrm_reg, _regs,
-						  (rex_prefix == 0));
-			dst.val = *(u8 *) dst.ptr;
-			dst.bytes = 1;
-		} else {
-			dst.ptr = decode_register(modrm_reg, _regs, 0);
-			switch ((dst.bytes = op_bytes)) {
-			case 2:
-				dst.val = *(u16 *)dst.ptr;
-				break;
-			case 4:
-				dst.val = *(u32 *)dst.ptr;
-				break;
-			case 8:
-				dst.val = *(u64 *)dst.ptr;
-				break;
-			}
-		}
-		break;
-	case DstMem:
-		dst.type = OP_MEM;
-		dst.ptr = (unsigned long *)cr2;
-		dst.bytes = (d & ByteOp) ? 1 : op_bytes;
-		dst.val = 0;
-		/*
-		 * For instructions with a ModR/M byte, switch to register
-		 * access if Mod = 3.
-		 */
-		if ((d & ModRM) && modrm_mod == 3) {
-			dst.type = OP_REG;
-			break;
-		}
-		if (d & BitOp) {
-			unsigned long mask = ~(dst.bytes * 8 - 1);
-
-			dst.ptr = (void *)dst.ptr + (src.val & mask) / 8;
-		}
-		if (!(d & Mov) && /* optimisation - avoid slow emulated read */
-		    ((rc = ops->read_emulated((unsigned long)dst.ptr,
-					      &dst.val, dst.bytes, ctxt->vcpu)) != 0))
-			goto done;
-		break;
-	}
-	dst.orig_val = dst.val;
-
-	if (twobyte)
-		goto twobyte_insn;
-
-	switch (b) {
-	case 0x00 ... 0x05:
-	      add:		/* add */
-		emulate_2op_SrcV("add", src, dst, _eflags);
-		break;
-	case 0x08 ... 0x0d:
-	      or:		/* or */
-		emulate_2op_SrcV("or", src, dst, _eflags);
-		break;
-	case 0x10 ... 0x15:
-	      adc:		/* adc */
-		emulate_2op_SrcV("adc", src, dst, _eflags);
-		break;
-	case 0x18 ... 0x1d:
-	      sbb:		/* sbb */
-		emulate_2op_SrcV("sbb", src, dst, _eflags);
-		break;
-	case 0x20 ... 0x23:
-	      and:		/* and */
-		emulate_2op_SrcV("and", src, dst, _eflags);
-		break;
-	case 0x24:              /* and al imm8 */
-		dst.type = OP_REG;
-		dst.ptr = &_regs[VCPU_REGS_RAX];
-		dst.val = *(u8 *)dst.ptr;
-		dst.bytes = 1;
-		dst.orig_val = dst.val;
-		goto and;
-	case 0x25:              /* and ax imm16, or eax imm32 */
-		dst.type = OP_REG;
-		dst.bytes = op_bytes;
-		dst.ptr = &_regs[VCPU_REGS_RAX];
-		if (op_bytes == 2)
-			dst.val = *(u16 *)dst.ptr;
-		else
-			dst.val = *(u32 *)dst.ptr;
-		dst.orig_val = dst.val;
-		goto and;
-	case 0x28 ... 0x2d:
-	      sub:		/* sub */
-		emulate_2op_SrcV("sub", src, dst, _eflags);
-		break;
-	case 0x30 ... 0x35:
-	      xor:		/* xor */
-		emulate_2op_SrcV("xor", src, dst, _eflags);
-		break;
-	case 0x38 ... 0x3d:
-	      cmp:		/* cmp */
-		emulate_2op_SrcV("cmp", src, dst, _eflags);
-		break;
-	case 0x63:		/* movsxd */
-		if (mode != X86EMUL_MODE_PROT64)
-			goto cannot_emulate;
-		dst.val = (s32) src.val;
-		break;
-	case 0x80 ... 0x83:	/* Grp1 */
-		switch (modrm_reg) {
-		case 0:
-			goto add;
-		case 1:
-			goto or;
-		case 2:
-			goto adc;
-		case 3:
-			goto sbb;
-		case 4:
-			goto and;
-		case 5:
-			goto sub;
-		case 6:
-			goto xor;
-		case 7:
-			goto cmp;
-		}
-		break;
-	case 0x84 ... 0x85:
-	      test:		/* test */
-		emulate_2op_SrcV("test", src, dst, _eflags);
-		break;
-	case 0x86 ... 0x87:	/* xchg */
-		/* Write back the register source. */
-		switch (dst.bytes) {
-		case 1:
-			*(u8 *) src.ptr = (u8) dst.val;
-			break;
-		case 2:
-			*(u16 *) src.ptr = (u16) dst.val;
-			break;
-		case 4:
-			*src.ptr = (u32) dst.val;
-			break;	/* 64b reg: zero-extend */
-		case 8:
-			*src.ptr = dst.val;
-			break;
-		}
-		/*
-		 * Write back the memory destination with implicit LOCK
-		 * prefix.
-		 */
-		dst.val = src.val;
-		lock_prefix = 1;
-		break;
-	case 0x88 ... 0x8b:	/* mov */
-		goto mov;
-	case 0x8d: /* lea r16/r32, m */
-		dst.val = modrm_val;
-		break;
-	case 0x8f:		/* pop (sole member of Grp1a) */
-		/* 64-bit mode: POP always pops a 64-bit operand. */
-		if (mode == X86EMUL_MODE_PROT64)
-			dst.bytes = 8;
-		if ((rc = ops->read_std(register_address(ctxt->ss_base,
-							 _regs[VCPU_REGS_RSP]),
-					&dst.val, dst.bytes, ctxt->vcpu)) != 0)
-			goto done;
-		register_address_increment(_regs[VCPU_REGS_RSP], dst.bytes);
-		break;
-	case 0xa0 ... 0xa1:	/* mov */
-		dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
-		dst.val = src.val;
-		_eip += ad_bytes;	/* skip src displacement */
-		break;
-	case 0xa2 ... 0xa3:	/* mov */
-		dst.val = (unsigned long)_regs[VCPU_REGS_RAX];
-		_eip += ad_bytes;	/* skip dst displacement */
-		break;
-	case 0xc0 ... 0xc1:
-	      grp2:		/* Grp2 */
-		switch (modrm_reg) {
-		case 0:	/* rol */
-			emulate_2op_SrcB("rol", src, dst, _eflags);
-			break;
-		case 1:	/* ror */
-			emulate_2op_SrcB("ror", src, dst, _eflags);
-			break;
-		case 2:	/* rcl */
-			emulate_2op_SrcB("rcl", src, dst, _eflags);
-			break;
-		case 3:	/* rcr */
-			emulate_2op_SrcB("rcr", src, dst, _eflags);
-			break;
-		case 4:	/* sal/shl */
-		case 6:	/* sal/shl */
-			emulate_2op_SrcB("sal", src, dst, _eflags);
-			break;
-		case 5:	/* shr */
-			emulate_2op_SrcB("shr", src, dst, _eflags);
-			break;
-		case 7:	/* sar */
-			emulate_2op_SrcB("sar", src, dst, _eflags);
-			break;
-		}
-		break;
-	case 0xc6 ... 0xc7:	/* mov (sole member of Grp11) */
-	mov:
-		dst.val = src.val;
-		break;
-	case 0xd0 ... 0xd1:	/* Grp2 */
-		src.val = 1;
-		goto grp2;
-	case 0xd2 ... 0xd3:	/* Grp2 */
-		src.val = _regs[VCPU_REGS_RCX];
-		goto grp2;
-	case 0xf6 ... 0xf7:	/* Grp3 */
-		switch (modrm_reg) {
-		case 0 ... 1:	/* test */
-			/*
-			 * Special case in Grp3: test has an immediate
-			 * source operand.
-			 */
-			src.type = OP_IMM;
-			src.ptr = (unsigned long *)_eip;
-			src.bytes = (d & ByteOp) ? 1 : op_bytes;
-			if (src.bytes == 8)
-				src.bytes = 4;
-			switch (src.bytes) {
-			case 1:
-				src.val = insn_fetch(s8, 1, _eip);
-				break;
-			case 2:
-				src.val = insn_fetch(s16, 2, _eip);
-				break;
-			case 4:
-				src.val = insn_fetch(s32, 4, _eip);
-				break;
-			}
-			goto test;
-		case 2:	/* not */
-			dst.val = ~dst.val;
-			break;
-		case 3:	/* neg */
-			emulate_1op("neg", dst, _eflags);
-			break;
-		default:
-			goto cannot_emulate;
-		}
-		break;
-	case 0xfe ... 0xff:	/* Grp4/Grp5 */
-		switch (modrm_reg) {
-		case 0:	/* inc */
-			emulate_1op("inc", dst, _eflags);
-			break;
-		case 1:	/* dec */
-			emulate_1op("dec", dst, _eflags);
-			break;
-		case 4: /* jmp abs */
-			if (b == 0xff)
-				_eip = dst.val;
-			else
-				goto cannot_emulate;
-			break;
-		case 6:	/* push */
-			/* 64-bit mode: PUSH always pushes a 64-bit operand. */
-			if (mode == X86EMUL_MODE_PROT64) {
-				dst.bytes = 8;
-				if ((rc = ops->read_std((unsigned long)dst.ptr,
-							&dst.val, 8,
-							ctxt->vcpu)) != 0)
-					goto done;
-			}
-			register_address_increment(_regs[VCPU_REGS_RSP],
-						   -dst.bytes);
-			if ((rc = ops->write_emulated(
-				     register_address(ctxt->ss_base,
-						      _regs[VCPU_REGS_RSP]),
-				     &dst.val, dst.bytes, ctxt->vcpu)) != 0)
-				goto done;
-			no_wb = 1;
-			break;
-		default:
-			goto cannot_emulate;
-		}
-		break;
-	}
-
-writeback:
-	if (!no_wb) {
-		switch (dst.type) {
-		case OP_REG:
-			/* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
-			switch (dst.bytes) {
-			case 1:
-				*(u8 *)dst.ptr = (u8)dst.val;
-				break;
-			case 2:
-				*(u16 *)dst.ptr = (u16)dst.val;
-				break;
-			case 4:
-				*dst.ptr = (u32)dst.val;
-				break;	/* 64b: zero-ext */
-			case 8:
-				*dst.ptr = dst.val;
-				break;
-			}
-			break;
-		case OP_MEM:
-			if (lock_prefix)
-				rc = ops->cmpxchg_emulated((unsigned long)dst.
-							   ptr, &dst.orig_val,
-							   &dst.val, dst.bytes,
-							   ctxt->vcpu);
-			else
-				rc = ops->write_emulated((unsigned long)dst.ptr,
-							 &dst.val, dst.bytes,
-							 ctxt->vcpu);
-			if (rc != 0)
-				goto done;
-		default:
-			break;
-		}
-	}
-
-	/* Commit shadow register state. */
-	memcpy(ctxt->vcpu->regs, _regs, sizeof _regs);
-	ctxt->eflags = _eflags;
-	ctxt->vcpu->rip = _eip;
-
-done:
-	return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
-
-special_insn:
-	if (twobyte)
-		goto twobyte_special_insn;
-	switch(b) {
-	case 0x50 ... 0x57:  /* push reg */
-		if (op_bytes == 2)
-			src.val = (u16) _regs[b & 0x7];
-		else
-			src.val = (u32) _regs[b & 0x7];
-		dst.type  = OP_MEM;
-		dst.bytes = op_bytes;
-		dst.val = src.val;
-		register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes);
-		dst.ptr = (void *) register_address(
-			ctxt->ss_base, _regs[VCPU_REGS_RSP]);
-		break;
-	case 0x58 ... 0x5f: /* pop reg */
-		dst.ptr = (unsigned long *)&_regs[b & 0x7];
-	pop_instruction:
-		if ((rc = ops->read_std(register_address(ctxt->ss_base,
-			_regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt->vcpu))
-			!= 0)
-			goto done;
-
-		register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
-		no_wb = 1; /* Disable writeback. */
-		break;
-	case 0x6a: /* push imm8 */
-		src.val = 0L;
-		src.val = insn_fetch(s8, 1, _eip);
-	push:
-		dst.type  = OP_MEM;
-		dst.bytes = op_bytes;
-		dst.val = src.val;
-		register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes);
-		dst.ptr = (void *) register_address(ctxt->ss_base,
-							_regs[VCPU_REGS_RSP]);
-		break;
-	case 0x6c:		/* insb */
-	case 0x6d:		/* insw/insd */
-		 if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
-				1, 					/* in */
-				(d & ByteOp) ? 1 : op_bytes, 		/* size */
-				rep_prefix ?
-				address_mask(_regs[VCPU_REGS_RCX]) : 1,	/* count */
-				(_eflags & EFLG_DF),			/* down */
-				register_address(ctxt->es_base,
-						 _regs[VCPU_REGS_RDI]),	/* address */
-				rep_prefix,
-				_regs[VCPU_REGS_RDX]			/* port */
-				) == 0)
-			return -1;
-		return 0;
-	case 0x6e:		/* outsb */
-	case 0x6f:		/* outsw/outsd */
-		if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
-				0, 					/* in */
-				(d & ByteOp) ? 1 : op_bytes, 		/* size */
-				rep_prefix ?
-				address_mask(_regs[VCPU_REGS_RCX]) : 1,	/* count */
-				(_eflags & EFLG_DF),			/* down */
-				register_address(override_base ?
-						 *override_base : ctxt->ds_base,
-						 _regs[VCPU_REGS_RSI]),	/* address */
-				rep_prefix,
-				_regs[VCPU_REGS_RDX]			/* port */
-				) == 0)
-			return -1;
-		return 0;
-	case 0x70 ... 0x7f: /* jcc (short) */ {
-		int rel = insn_fetch(s8, 1, _eip);
-
-		if (test_cc(b, _eflags))
-		JMP_REL(rel);
-		break;
-	}
-	case 0x9c: /* pushf */
-		src.val =  (unsigned long) _eflags;
-		goto push;
-	case 0x9d: /* popf */
-		dst.ptr = (unsigned long *) &_eflags;
-		goto pop_instruction;
-	case 0xc3: /* ret */
-		dst.ptr = &_eip;
-		goto pop_instruction;
-	case 0xf4:              /* hlt */
-		ctxt->vcpu->halt_request = 1;
-		goto done;
-	}
-	if (rep_prefix) {
-		if (_regs[VCPU_REGS_RCX] == 0) {
-			ctxt->vcpu->rip = _eip;
-			goto done;
-		}
-		_regs[VCPU_REGS_RCX]--;
-		_eip = ctxt->vcpu->rip;
-	}
-	switch (b) {
-	case 0xa4 ... 0xa5:	/* movs */
-		dst.type = OP_MEM;
-		dst.bytes = (d & ByteOp) ? 1 : op_bytes;
-		dst.ptr = (unsigned long *)register_address(ctxt->es_base,
-							_regs[VCPU_REGS_RDI]);
-		if ((rc = ops->read_emulated(register_address(
-		      override_base ? *override_base : ctxt->ds_base,
-		      _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt->vcpu)) != 0)
-			goto done;
-		register_address_increment(_regs[VCPU_REGS_RSI],
-			     (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
-		register_address_increment(_regs[VCPU_REGS_RDI],
-			     (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
-		break;
-	case 0xa6 ... 0xa7:	/* cmps */
-		DPRINTF("Urk! I don't handle CMPS.\n");
-		goto cannot_emulate;
-	case 0xaa ... 0xab:	/* stos */
-		dst.type = OP_MEM;
-		dst.bytes = (d & ByteOp) ? 1 : op_bytes;
-		dst.ptr = (unsigned long *)cr2;
-		dst.val = _regs[VCPU_REGS_RAX];
-		register_address_increment(_regs[VCPU_REGS_RDI],
-			     (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
-		break;
-	case 0xac ... 0xad:	/* lods */
-		dst.type = OP_REG;
-		dst.bytes = (d & ByteOp) ? 1 : op_bytes;
-		dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
-		if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes,
-					     ctxt->vcpu)) != 0)
-			goto done;
-		register_address_increment(_regs[VCPU_REGS_RSI],
-			   (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
-		break;
-	case 0xae ... 0xaf:	/* scas */
-		DPRINTF("Urk! I don't handle SCAS.\n");
-		goto cannot_emulate;
-	case 0xe8: /* call (near) */ {
-		long int rel;
-		switch (op_bytes) {
-		case 2:
-			rel = insn_fetch(s16, 2, _eip);
-			break;
-		case 4:
-			rel = insn_fetch(s32, 4, _eip);
-			break;
-		case 8:
-			rel = insn_fetch(s64, 8, _eip);
-			break;
-		default:
-			DPRINTF("Call: Invalid op_bytes\n");
-			goto cannot_emulate;
-		}
-		src.val = (unsigned long) _eip;
-		JMP_REL(rel);
-		op_bytes = ad_bytes;
-		goto push;
-	}
-	case 0xe9: /* jmp rel */
-	case 0xeb: /* jmp rel short */
-		JMP_REL(src.val);
-		no_wb = 1; /* Disable writeback. */
-		break;
-
-
-	}
-	goto writeback;
-
-twobyte_insn:
-	switch (b) {
-	case 0x01: /* lgdt, lidt, lmsw */
-		/* Disable writeback. */
-		no_wb = 1;
-		switch (modrm_reg) {
-			u16 size;
-			unsigned long address;
-
-		case 2: /* lgdt */
-			rc = read_descriptor(ctxt, ops, src.ptr,
-					     &size, &address, op_bytes);
-			if (rc)
-				goto done;
-			realmode_lgdt(ctxt->vcpu, size, address);
-			break;
-		case 3: /* lidt */
-			rc = read_descriptor(ctxt, ops, src.ptr,
-					     &size, &address, op_bytes);
-			if (rc)
-				goto done;
-			realmode_lidt(ctxt->vcpu, size, address);
-			break;
-		case 4: /* smsw */
-			if (modrm_mod != 3)
-				goto cannot_emulate;
-			*(u16 *)&_regs[modrm_rm]
-				= realmode_get_cr(ctxt->vcpu, 0);
-			break;
-		case 6: /* lmsw */
-			if (modrm_mod != 3)
-				goto cannot_emulate;
-			realmode_lmsw(ctxt->vcpu, (u16)modrm_val, &_eflags);
-			break;
-		case 7: /* invlpg*/
-			emulate_invlpg(ctxt->vcpu, cr2);
-			break;
-		default:
-			goto cannot_emulate;
-		}
-		break;
-	case 0x21: /* mov from dr to reg */
-		no_wb = 1;
-		if (modrm_mod != 3)
-			goto cannot_emulate;
-		rc = emulator_get_dr(ctxt, modrm_reg, &_regs[modrm_rm]);
-		break;
-	case 0x23: /* mov from reg to dr */
-		no_wb = 1;
-		if (modrm_mod != 3)
-			goto cannot_emulate;
-		rc = emulator_set_dr(ctxt, modrm_reg, _regs[modrm_rm]);
-		break;
-	case 0x40 ... 0x4f:	/* cmov */
-		dst.val = dst.orig_val = src.val;
-		no_wb = 1;
-		/*
-		 * First, assume we're decoding an even cmov opcode
-		 * (lsb == 0).
-		 */
-		switch ((b & 15) >> 1) {
-		case 0:	/* cmovo */
-			no_wb = (_eflags & EFLG_OF) ? 0 : 1;
-			break;
-		case 1:	/* cmovb/cmovc/cmovnae */
-			no_wb = (_eflags & EFLG_CF) ? 0 : 1;
-			break;
-		case 2:	/* cmovz/cmove */
-			no_wb = (_eflags & EFLG_ZF) ? 0 : 1;
-			break;
-		case 3:	/* cmovbe/cmovna */
-			no_wb = (_eflags & (EFLG_CF | EFLG_ZF)) ? 0 : 1;
-			break;
-		case 4:	/* cmovs */
-			no_wb = (_eflags & EFLG_SF) ? 0 : 1;
-			break;
-		case 5:	/* cmovp/cmovpe */
-			no_wb = (_eflags & EFLG_PF) ? 0 : 1;
-			break;
-		case 7:	/* cmovle/cmovng */
-			no_wb = (_eflags & EFLG_ZF) ? 0 : 1;
-			/* fall through */
-		case 6:	/* cmovl/cmovnge */
-			no_wb &= (!(_eflags & EFLG_SF) !=
-			      !(_eflags & EFLG_OF)) ? 0 : 1;
-			break;
-		}
-		/* Odd cmov opcodes (lsb == 1) have inverted sense. */
-		no_wb ^= b & 1;
-		break;
-	case 0xa3:
-	      bt:		/* bt */
-		src.val &= (dst.bytes << 3) - 1; /* only subword offset */
-		emulate_2op_SrcV_nobyte("bt", src, dst, _eflags);
-		break;
-	case 0xab:
-	      bts:		/* bts */
-		src.val &= (dst.bytes << 3) - 1; /* only subword offset */
-		emulate_2op_SrcV_nobyte("bts", src, dst, _eflags);
-		break;
-	case 0xb0 ... 0xb1:	/* cmpxchg */
-		/*
-		 * Save real source value, then compare EAX against
-		 * destination.
-		 */
-		src.orig_val = src.val;
-		src.val = _regs[VCPU_REGS_RAX];
-		emulate_2op_SrcV("cmp", src, dst, _eflags);
-		if (_eflags & EFLG_ZF) {
-			/* Success: write back to memory. */
-			dst.val = src.orig_val;
-		} else {
-			/* Failure: write the value we saw to EAX. */
-			dst.type = OP_REG;
-			dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
-		}
-		break;
-	case 0xb3:
-	      btr:		/* btr */
-		src.val &= (dst.bytes << 3) - 1; /* only subword offset */
-		emulate_2op_SrcV_nobyte("btr", src, dst, _eflags);
-		break;
-	case 0xb6 ... 0xb7:	/* movzx */
-		dst.bytes = op_bytes;
-		dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val;
-		break;
-	case 0xba:		/* Grp8 */
-		switch (modrm_reg & 3) {
-		case 0:
-			goto bt;
-		case 1:
-			goto bts;
-		case 2:
-			goto btr;
-		case 3:
-			goto btc;
-		}
-		break;
-	case 0xbb:
-	      btc:		/* btc */
-		src.val &= (dst.bytes << 3) - 1; /* only subword offset */
-		emulate_2op_SrcV_nobyte("btc", src, dst, _eflags);
-		break;
-	case 0xbe ... 0xbf:	/* movsx */
-		dst.bytes = op_bytes;
-		dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val;
-		break;
-	case 0xc3:		/* movnti */
-		dst.bytes = op_bytes;
-		dst.val = (op_bytes == 4) ? (u32) src.val : (u64) src.val;
-		break;
-	}
-	goto writeback;
-
-twobyte_special_insn:
-	/* Disable writeback. */
-	no_wb = 1;
-	switch (b) {
-	case 0x06:
-		emulate_clts(ctxt->vcpu);
-		break;
-	case 0x08:		/* invd */
-		break;
-	case 0x09:		/* wbinvd */
-		break;
-	case 0x0d:		/* GrpP (prefetch) */
-	case 0x18:		/* Grp16 (prefetch/nop) */
-		break;
-	case 0x20: /* mov cr, reg */
-		if (modrm_mod != 3)
-			goto cannot_emulate;
-		_regs[modrm_rm] = realmode_get_cr(ctxt->vcpu, modrm_reg);
-		break;
-	case 0x22: /* mov reg, cr */
-		if (modrm_mod != 3)
-			goto cannot_emulate;
-		realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
-		break;
-	case 0x30:
-		/* wrmsr */
-		msr_data = (u32)_regs[VCPU_REGS_RAX]
-			| ((u64)_regs[VCPU_REGS_RDX] << 32);
-		rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
-		if (rc) {
-			kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
-			_eip = ctxt->vcpu->rip;
-		}
-		rc = X86EMUL_CONTINUE;
-		break;
-	case 0x32:
-		/* rdmsr */
-		rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
-		if (rc) {
-			kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
-			_eip = ctxt->vcpu->rip;
-		} else {
-			_regs[VCPU_REGS_RAX] = (u32)msr_data;
-			_regs[VCPU_REGS_RDX] = msr_data >> 32;
-		}
-		rc = X86EMUL_CONTINUE;
-		break;
-	case 0x80 ... 0x8f: /* jnz rel, etc*/ {
-		long int rel;
-
-		switch (op_bytes) {
-		case 2:
-			rel = insn_fetch(s16, 2, _eip);
-			break;
-		case 4:
-			rel = insn_fetch(s32, 4, _eip);
-			break;
-		case 8:
-			rel = insn_fetch(s64, 8, _eip);
-			break;
-		default:
-			DPRINTF("jnz: Invalid op_bytes\n");
-			goto cannot_emulate;
-		}
-		if (test_cc(b, _eflags))
-			JMP_REL(rel);
-		break;
-	}
-	case 0xc7:		/* Grp9 (cmpxchg8b) */
-		{
-			u64 old, new;
-			if ((rc = ops->read_emulated(cr2, &old, 8, ctxt->vcpu))
-									!= 0)
-				goto done;
-			if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) ||
-			    ((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) {
-				_regs[VCPU_REGS_RAX] = (u32) (old >> 0);
-				_regs[VCPU_REGS_RDX] = (u32) (old >> 32);
-				_eflags &= ~EFLG_ZF;
-			} else {
-				new = ((u64)_regs[VCPU_REGS_RCX] << 32)
-					| (u32) _regs[VCPU_REGS_RBX];
-				if ((rc = ops->cmpxchg_emulated(cr2, &old,
-							  &new, 8, ctxt->vcpu)) != 0)
-					goto done;
-				_eflags |= EFLG_ZF;
-			}
-			break;
-		}
-	}
-	goto writeback;
-
-cannot_emulate:
-	DPRINTF("Cannot emulate %02x\n", b);
-	return -1;
-}
-
-#ifdef __XEN__
-
-#include <asm/mm.h>
-#include <asm/uaccess.h>
-
-int
-x86_emulate_read_std(unsigned long addr,
-		     unsigned long *val,
-		     unsigned int bytes, struct x86_emulate_ctxt *ctxt)
-{
-	unsigned int rc;
-
-	*val = 0;
-
-	if ((rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0) {
-		propagate_page_fault(addr + bytes - rc, 0);	/* read fault */
-		return X86EMUL_PROPAGATE_FAULT;
-	}
-
-	return X86EMUL_CONTINUE;
-}
-
-int
-x86_emulate_write_std(unsigned long addr,
-		      unsigned long val,
-		      unsigned int bytes, struct x86_emulate_ctxt *ctxt)
-{
-	unsigned int rc;
-
-	if ((rc = copy_to_user((void *)addr, (void *)&val, bytes)) != 0) {
-		propagate_page_fault(addr + bytes - rc, PGERR_write_access);
-		return X86EMUL_PROPAGATE_FAULT;
-	}
-
-	return X86EMUL_CONTINUE;
-}
-
-#endif
diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h
deleted file mode 100644
index 92c73aa7f9ac..000000000000
--- a/drivers/kvm/x86_emulate.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/******************************************************************************
- * x86_emulate.h
- *
- * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
- *
- * Copyright (c) 2005 Keir Fraser
- *
- * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4
- */
-
-#ifndef __X86_EMULATE_H__
-#define __X86_EMULATE_H__
-
-struct x86_emulate_ctxt;
-
-/*
- * x86_emulate_ops:
- *
- * These operations represent the instruction emulator's interface to memory.
- * There are two categories of operation: those that act on ordinary memory
- * regions (*_std), and those that act on memory regions known to require
- * special treatment or emulation (*_emulated).
- *
- * The emulator assumes that an instruction accesses only one 'emulated memory'
- * location, that this location is the given linear faulting address (cr2), and
- * that this is one of the instruction's data operands. Instruction fetches and
- * stack operations are assumed never to access emulated memory. The emulator
- * automatically deduces which operand of a string-move operation is accessing
- * emulated memory, and assumes that the other operand accesses normal memory.
- *
- * NOTES:
- *  1. The emulator isn't very smart about emulated vs. standard memory.
- *     'Emulated memory' access addresses should be checked for sanity.
- *     'Normal memory' accesses may fault, and the caller must arrange to
- *     detect and handle reentrancy into the emulator via recursive faults.
- *     Accesses may be unaligned and may cross page boundaries.
- *  2. If the access fails (cannot emulate, or a standard access faults) then
- *     it is up to the memop to propagate the fault to the guest VM via
- *     some out-of-band mechanism, unknown to the emulator. The memop signals
- *     failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will
- *     then immediately bail.
- *  3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
- *     cmpxchg8b_emulated need support 8-byte accesses.
- *  4. The emulator cannot handle 64-bit mode emulation on an x86/32 system.
- */
-/* Access completed successfully: continue emulation as normal. */
-#define X86EMUL_CONTINUE        0
-/* Access is unhandleable: bail from emulation and return error to caller. */
-#define X86EMUL_UNHANDLEABLE    1
-/* Terminate emulation but return success to the caller. */
-#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
-#define X86EMUL_RETRY_INSTR     2 /* retry the instruction for some reason */
-#define X86EMUL_CMPXCHG_FAILED  2 /* cmpxchg did not see expected value */
-struct x86_emulate_ops {
-	/*
-	 * read_std: Read bytes of standard (non-emulated/special) memory.
-	 *           Used for instruction fetch, stack operations, and others.
-	 *  @addr:  [IN ] Linear address from which to read.
-	 *  @val:   [OUT] Value read from memory, zero-extended to 'u_long'.
-	 *  @bytes: [IN ] Number of bytes to read from memory.
-	 */
-	int (*read_std)(unsigned long addr, void *val,
-			unsigned int bytes, struct kvm_vcpu *vcpu);
-
-	/*
-	 * write_std: Write bytes of standard (non-emulated/special) memory.
-	 *            Used for stack operations, and others.
-	 *  @addr:  [IN ] Linear address to which to write.
-	 *  @val:   [IN ] Value to write to memory (low-order bytes used as
-	 *                required).
-	 *  @bytes: [IN ] Number of bytes to write to memory.
-	 */
-	int (*write_std)(unsigned long addr, const void *val,
-			 unsigned int bytes, struct kvm_vcpu *vcpu);
-
-	/*
-	 * read_emulated: Read bytes from emulated/special memory area.
-	 *  @addr:  [IN ] Linear address from which to read.
-	 *  @val:   [OUT] Value read from memory, zero-extended to 'u_long'.
-	 *  @bytes: [IN ] Number of bytes to read from memory.
-	 */
-	int (*read_emulated) (unsigned long addr,
-			      void *val,
-			      unsigned int bytes,
-			      struct kvm_vcpu *vcpu);
-
-	/*
-	 * write_emulated: Read bytes from emulated/special memory area.
-	 *  @addr:  [IN ] Linear address to which to write.
-	 *  @val:   [IN ] Value to write to memory (low-order bytes used as
-	 *                required).
-	 *  @bytes: [IN ] Number of bytes to write to memory.
-	 */
-	int (*write_emulated) (unsigned long addr,
-			       const void *val,
-			       unsigned int bytes,
-			       struct kvm_vcpu *vcpu);
-
-	/*
-	 * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
-	 *                   emulated/special memory area.
-	 *  @addr:  [IN ] Linear address to access.
-	 *  @old:   [IN ] Value expected to be current at @addr.
-	 *  @new:   [IN ] Value to write to @addr.
-	 *  @bytes: [IN ] Number of bytes to access using CMPXCHG.
-	 */
-	int (*cmpxchg_emulated) (unsigned long addr,
-				 const void *old,
-				 const void *new,
-				 unsigned int bytes,
-				 struct kvm_vcpu *vcpu);
-
-};
-
-struct x86_emulate_ctxt {
-	/* Register state before/after emulation. */
-	struct kvm_vcpu *vcpu;
-
-	/* Linear faulting address (if emulating a page-faulting instruction). */
-	unsigned long eflags;
-	unsigned long cr2;
-
-	/* Emulated execution mode, represented by an X86EMUL_MODE value. */
-	int mode;
-
-	unsigned long cs_base;
-	unsigned long ds_base;
-	unsigned long es_base;
-	unsigned long ss_base;
-	unsigned long gs_base;
-	unsigned long fs_base;
-};
-
-/* Execution mode, passed to the emulator. */
-#define X86EMUL_MODE_REAL     0	/* Real mode.             */
-#define X86EMUL_MODE_PROT16   2	/* 16-bit protected mode. */
-#define X86EMUL_MODE_PROT32   4	/* 32-bit protected mode. */
-#define X86EMUL_MODE_PROT64   8	/* 64-bit (long) mode.    */
-
-/* Host execution mode. */
-#if defined(__i386__)
-#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32
-#elif defined(CONFIG_X86_64)
-#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64
-#endif
-
-/*
- * x86_emulate_memop: Emulate an instruction that faulted attempting to
- *                    read/write a 'special' memory area.
- * Returns -1 on failure, 0 on success.
- */
-int x86_emulate_memop(struct x86_emulate_ctxt *ctxt,
-		      struct x86_emulate_ops *ops);
-
-#endif				/* __X86_EMULATE_H__ */
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index cb4c67025d52..7743d73768df 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -151,43 +151,43 @@ int lguest_address_ok(const struct lguest *lg,
 /* This routine copies memory from the Guest.  Here we can see how useful the
  * kill_lguest() routine we met in the Launcher can be: we return a random
  * value (all zeroes) instead of needing to return an error. */
-void __lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
+void __lgread(struct lg_cpu *cpu, void *b, unsigned long addr, unsigned bytes)
 {
-	if (!lguest_address_ok(lg, addr, bytes)
-	    || copy_from_user(b, lg->mem_base + addr, bytes) != 0) {
+	if (!lguest_address_ok(cpu->lg, addr, bytes)
+	    || copy_from_user(b, cpu->lg->mem_base + addr, bytes) != 0) {
 		/* copy_from_user should do this, but as we rely on it... */
 		memset(b, 0, bytes);
-		kill_guest(lg, "bad read address %#lx len %u", addr, bytes);
+		kill_guest(cpu, "bad read address %#lx len %u", addr, bytes);
 	}
 }
 
 /* This is the write (copy into guest) version. */
-void __lgwrite(struct lguest *lg, unsigned long addr, const void *b,
+void __lgwrite(struct lg_cpu *cpu, unsigned long addr, const void *b,
 	       unsigned bytes)
 {
-	if (!lguest_address_ok(lg, addr, bytes)
-	    || copy_to_user(lg->mem_base + addr, b, bytes) != 0)
-		kill_guest(lg, "bad write address %#lx len %u", addr, bytes);
+	if (!lguest_address_ok(cpu->lg, addr, bytes)
+	    || copy_to_user(cpu->lg->mem_base + addr, b, bytes) != 0)
+		kill_guest(cpu, "bad write address %#lx len %u", addr, bytes);
 }
 /*:*/
 
 /*H:030 Let's jump straight to the the main loop which runs the Guest.
  * Remember, this is called by the Launcher reading /dev/lguest, and we keep
  * going around and around until something interesting happens. */
-int run_guest(struct lguest *lg, unsigned long __user *user)
+int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
 {
 	/* We stop running once the Guest is dead. */
-	while (!lg->dead) {
+	while (!cpu->lg->dead) {
 		/* First we run any hypercalls the Guest wants done. */
-		if (lg->hcall)
-			do_hypercalls(lg);
+		if (cpu->hcall)
+			do_hypercalls(cpu);
 
 		/* It's possible the Guest did a NOTIFY hypercall to the
 		 * Launcher, in which case we return from the read() now. */
-		if (lg->pending_notify) {
-			if (put_user(lg->pending_notify, user))
+		if (cpu->pending_notify) {
+			if (put_user(cpu->pending_notify, user))
 				return -EFAULT;
-			return sizeof(lg->pending_notify);
+			return sizeof(cpu->pending_notify);
 		}
 
 		/* Check for signals */
@@ -195,13 +195,13 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
 			return -ERESTARTSYS;
 
 		/* If Waker set break_out, return to Launcher. */
-		if (lg->break_out)
+		if (cpu->break_out)
 			return -EAGAIN;
 
 		/* Check if there are any interrupts which can be delivered
 		 * now: if so, this sets up the hander to be executed when we
 		 * next run the Guest. */
-		maybe_do_interrupt(lg);
+		maybe_do_interrupt(cpu);
 
 		/* All long-lived kernel loops need to check with this horrible
 		 * thing called the freezer.  If the Host is trying to suspend,
@@ -210,12 +210,12 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
 
 		/* Just make absolutely sure the Guest is still alive.  One of
 		 * those hypercalls could have been fatal, for example. */
-		if (lg->dead)
+		if (cpu->lg->dead)
 			break;
 
 		/* If the Guest asked to be stopped, we sleep.  The Guest's
 		 * clock timer or LHCALL_BREAK from the Waker will wake us. */
-		if (lg->halted) {
+		if (cpu->halted) {
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
 			continue;
@@ -226,15 +226,17 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
 		local_irq_disable();
 
 		/* Actually run the Guest until something happens. */
-		lguest_arch_run_guest(lg);
+		lguest_arch_run_guest(cpu);
 
 		/* Now we're ready to be interrupted or moved to other CPUs */
 		local_irq_enable();
 
 		/* Now we deal with whatever happened to the Guest. */
-		lguest_arch_handle_trap(lg);
+		lguest_arch_handle_trap(cpu);
 	}
 
+	if (cpu->lg->dead == ERR_PTR(-ERESTART))
+		return -ERESTART;
 	/* The Guest is dead => "No such file or directory" */
 	return -ENOENT;
 }
@@ -253,7 +255,7 @@ static int __init init(void)
 
 	/* Lguest can't run under Xen, VMI or itself.  It does Tricky Stuff. */
 	if (paravirt_enabled()) {
-		printk("lguest is afraid of %s\n", pv_info.name);
+		printk("lguest is afraid of being a guest\n");
 		return -EPERM;
 	}
 
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
index b478affe8f91..0f2cb4fd7c69 100644
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -23,13 +23,14 @@
 #include <linux/uaccess.h>
 #include <linux/syscalls.h>
 #include <linux/mm.h>
+#include <linux/ktime.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include "lg.h"
 
 /*H:120 This is the core hypercall routine: where the Guest gets what it wants.
  * Or gets killed.  Or, in the case of LHCALL_CRASH, both. */
-static void do_hcall(struct lguest *lg, struct hcall_args *args)
+static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
 {
 	switch (args->arg0) {
 	case LHCALL_FLUSH_ASYNC:
@@ -39,60 +40,62 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
 	case LHCALL_LGUEST_INIT:
 		/* You can't get here unless you're already initialized.  Don't
 		 * do that. */
-		kill_guest(lg, "already have lguest_data");
+		kill_guest(cpu, "already have lguest_data");
 		break;
-	case LHCALL_CRASH: {
-		/* Crash is such a trivial hypercall that we do it in four
+	case LHCALL_SHUTDOWN: {
+		/* Shutdown is such a trivial hypercall that we do it in four
 		 * lines right here. */
 		char msg[128];
 		/* If the lgread fails, it will call kill_guest() itself; the
 		 * kill_guest() with the message will be ignored. */
-		__lgread(lg, msg, args->arg1, sizeof(msg));
+		__lgread(cpu, msg, args->arg1, sizeof(msg));
 		msg[sizeof(msg)-1] = '\0';
-		kill_guest(lg, "CRASH: %s", msg);
+		kill_guest(cpu, "CRASH: %s", msg);
+		if (args->arg2 == LGUEST_SHUTDOWN_RESTART)
+			cpu->lg->dead = ERR_PTR(-ERESTART);
 		break;
 	}
 	case LHCALL_FLUSH_TLB:
 		/* FLUSH_TLB comes in two flavors, depending on the
 		 * argument: */
 		if (args->arg1)
-			guest_pagetable_clear_all(lg);
+			guest_pagetable_clear_all(cpu);
 		else
-			guest_pagetable_flush_user(lg);
+			guest_pagetable_flush_user(cpu);
 		break;
 
 	/* All these calls simply pass the arguments through to the right
 	 * routines. */
 	case LHCALL_NEW_PGTABLE:
-		guest_new_pagetable(lg, args->arg1);
+		guest_new_pagetable(cpu, args->arg1);
 		break;
 	case LHCALL_SET_STACK:
-		guest_set_stack(lg, args->arg1, args->arg2, args->arg3);
+		guest_set_stack(cpu, args->arg1, args->arg2, args->arg3);
 		break;
 	case LHCALL_SET_PTE:
-		guest_set_pte(lg, args->arg1, args->arg2, __pte(args->arg3));
+		guest_set_pte(cpu, args->arg1, args->arg2, __pte(args->arg3));
 		break;
 	case LHCALL_SET_PMD:
-		guest_set_pmd(lg, args->arg1, args->arg2);
+		guest_set_pmd(cpu->lg, args->arg1, args->arg2);
 		break;
 	case LHCALL_SET_CLOCKEVENT:
-		guest_set_clockevent(lg, args->arg1);
+		guest_set_clockevent(cpu, args->arg1);
 		break;
 	case LHCALL_TS:
 		/* This sets the TS flag, as we saw used in run_guest(). */
-		lg->ts = args->arg1;
+		cpu->ts = args->arg1;
 		break;
 	case LHCALL_HALT:
 		/* Similarly, this sets the halted flag for run_guest(). */
-		lg->halted = 1;
+		cpu->halted = 1;
 		break;
 	case LHCALL_NOTIFY:
-		lg->pending_notify = args->arg1;
+		cpu->pending_notify = args->arg1;
 		break;
 	default:
 		/* It should be an architecture-specific hypercall. */
-		if (lguest_arch_do_hcall(lg, args))
-			kill_guest(lg, "Bad hypercall %li\n", args->arg0);
+		if (lguest_arch_do_hcall(cpu, args))
+			kill_guest(cpu, "Bad hypercall %li\n", args->arg0);
 	}
 }
 /*:*/
@@ -104,13 +107,13 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
  * Guest put them in the ring, but we also promise the Guest that they will
  * happen before any normal hypercall (which is why we check this before
  * checking for a normal hcall). */
-static void do_async_hcalls(struct lguest *lg)
+static void do_async_hcalls(struct lg_cpu *cpu)
 {
 	unsigned int i;
 	u8 st[LHCALL_RING_SIZE];
 
 	/* For simplicity, we copy the entire call status array in at once. */
-	if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st)))
+	if (copy_from_user(&st, &cpu->lg->lguest_data->hcall_status, sizeof(st)))
 		return;
 
 	/* We process "struct lguest_data"s hcalls[] ring once. */
@@ -119,7 +122,7 @@ static void do_async_hcalls(struct lguest *lg)
 		/* We remember where we were up to from last time.  This makes
 		 * sure that the hypercalls are done in the order the Guest
 		 * places them in the ring. */
-		unsigned int n = lg->next_hcall;
+		unsigned int n = cpu->next_hcall;
 
 		/* 0xFF means there's no call here (yet). */
 		if (st[n] == 0xFF)
@@ -127,65 +130,65 @@ static void do_async_hcalls(struct lguest *lg)
 
 		/* OK, we have hypercall.  Increment the "next_hcall" cursor,
 		 * and wrap back to 0 if we reach the end. */
-		if (++lg->next_hcall == LHCALL_RING_SIZE)
-			lg->next_hcall = 0;
+		if (++cpu->next_hcall == LHCALL_RING_SIZE)
+			cpu->next_hcall = 0;
 
 		/* Copy the hypercall arguments into a local copy of
 		 * the hcall_args struct. */
-		if (copy_from_user(&args, &lg->lguest_data->hcalls[n],
+		if (copy_from_user(&args, &cpu->lg->lguest_data->hcalls[n],
 				   sizeof(struct hcall_args))) {
-			kill_guest(lg, "Fetching async hypercalls");
+			kill_guest(cpu, "Fetching async hypercalls");
 			break;
 		}
 
 		/* Do the hypercall, same as a normal one. */
-		do_hcall(lg, &args);
+		do_hcall(cpu, &args);
 
 		/* Mark the hypercall done. */
-		if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) {
-			kill_guest(lg, "Writing result for async hypercall");
+		if (put_user(0xFF, &cpu->lg->lguest_data->hcall_status[n])) {
+			kill_guest(cpu, "Writing result for async hypercall");
 			break;
 		}
 
 		/* Stop doing hypercalls if they want to notify the Launcher:
 		 * it needs to service this first. */
-		if (lg->pending_notify)
+		if (cpu->pending_notify)
 			break;
 	}
 }
 
 /* Last of all, we look at what happens first of all.  The very first time the
  * Guest makes a hypercall, we end up here to set things up: */
-static void initialize(struct lguest *lg)
+static void initialize(struct lg_cpu *cpu)
 {
 	/* You can't do anything until you're initialized.  The Guest knows the
 	 * rules, so we're unforgiving here. */
-	if (lg->hcall->arg0 != LHCALL_LGUEST_INIT) {
-		kill_guest(lg, "hypercall %li before INIT", lg->hcall->arg0);
+	if (cpu->hcall->arg0 != LHCALL_LGUEST_INIT) {
+		kill_guest(cpu, "hypercall %li before INIT", cpu->hcall->arg0);
 		return;
 	}
 
-	if (lguest_arch_init_hypercalls(lg))
-		kill_guest(lg, "bad guest page %p", lg->lguest_data);
+	if (lguest_arch_init_hypercalls(cpu))
+		kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data);
 
 	/* The Guest tells us where we're not to deliver interrupts by putting
 	 * the range of addresses into "struct lguest_data". */
-	if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start)
-	    || get_user(lg->noirq_end, &lg->lguest_data->noirq_end))
-		kill_guest(lg, "bad guest page %p", lg->lguest_data);
+	if (get_user(cpu->lg->noirq_start, &cpu->lg->lguest_data->noirq_start)
+	    || get_user(cpu->lg->noirq_end, &cpu->lg->lguest_data->noirq_end))
+		kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data);
 
 	/* We write the current time into the Guest's data page once so it can
 	 * set its clock. */
-	write_timestamp(lg);
+	write_timestamp(cpu);
 
 	/* page_tables.c will also do some setup. */
-	page_table_guest_data_init(lg);
+	page_table_guest_data_init(cpu);
 
 	/* This is the one case where the above accesses might have been the
 	 * first write to a Guest page.  This may have caused a copy-on-write
 	 * fault, but the old page might be (read-only) in the Guest
 	 * pagetable. */
-	guest_pagetable_clear_all(lg);
+	guest_pagetable_clear_all(cpu);
 }
 
 /*H:100
@@ -194,27 +197,27 @@ static void initialize(struct lguest *lg)
  * Remember from the Guest, hypercalls come in two flavors: normal and
  * asynchronous.  This file handles both of types.
  */
-void do_hypercalls(struct lguest *lg)
+void do_hypercalls(struct lg_cpu *cpu)
 {
 	/* Not initialized yet?  This hypercall must do it. */
-	if (unlikely(!lg->lguest_data)) {
+	if (unlikely(!cpu->lg->lguest_data)) {
 		/* Set up the "struct lguest_data" */
-		initialize(lg);
+		initialize(cpu);
 		/* Hcall is done. */
-		lg->hcall = NULL;
+		cpu->hcall = NULL;
 		return;
 	}
 
 	/* The Guest has initialized.
 	 *
 	 * Look in the hypercall ring for the async hypercalls: */
-	do_async_hcalls(lg);
+	do_async_hcalls(cpu);
 
 	/* If we stopped reading the hypercall ring because the Guest did a
 	 * NOTIFY to the Launcher, we want to return now.  Otherwise we do
 	 * the hypercall. */
-	if (!lg->pending_notify) {
-		do_hcall(lg, lg->hcall);
+	if (!cpu->pending_notify) {
+		do_hcall(cpu, cpu->hcall);
 		/* Tricky point: we reset the hcall pointer to mark the
 		 * hypercall as "done".  We use the hcall pointer rather than
 		 * the trap number to indicate a hypercall is pending.
@@ -225,16 +228,17 @@ void do_hypercalls(struct lguest *lg)
 		 * Launcher, the run_guest() loop will exit without running the
 		 * Guest.  When it comes back it would try to re-run the
 		 * hypercall. */
-		lg->hcall = NULL;
+		cpu->hcall = NULL;
 	}
 }
 
 /* This routine supplies the Guest with time: it's used for wallclock time at
  * initial boot and as a rough time source if the TSC isn't available. */
-void write_timestamp(struct lguest *lg)
+void write_timestamp(struct lg_cpu *cpu)
 {
 	struct timespec now;
 	ktime_get_real_ts(&now);
-	if (copy_to_user(&lg->lguest_data->time, &now, sizeof(struct timespec)))
-		kill_guest(lg, "Writing timestamp");
+	if (copy_to_user(&cpu->lg->lguest_data->time,
+			 &now, sizeof(struct timespec)))
+		kill_guest(cpu, "Writing timestamp");
 }
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index 2b66f79c208b..32e97c1858e5 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -41,11 +41,11 @@ static int idt_present(u32 lo, u32 hi)
 
 /* We need a helper to "push" a value onto the Guest's stack, since that's a
  * big part of what delivering an interrupt does. */
-static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
+static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val)
 {
 	/* Stack grows upwards: move stack then write value. */
 	*gstack -= 4;
-	lgwrite(lg, *gstack, u32, val);
+	lgwrite(cpu, *gstack, u32, val);
 }
 
 /*H:210 The set_guest_interrupt() routine actually delivers the interrupt or
@@ -60,7 +60,7 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
  * We set up the stack just like the CPU does for a real interrupt, so it's
  * identical for the Guest (and the standard "iret" instruction will undo
  * it). */
-static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
+static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, int has_err)
 {
 	unsigned long gstack, origstack;
 	u32 eflags, ss, irq_enable;
@@ -69,59 +69,59 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
 	/* There are two cases for interrupts: one where the Guest is already
 	 * in the kernel, and a more complex one where the Guest is in
 	 * userspace.  We check the privilege level to find out. */
-	if ((lg->regs->ss&0x3) != GUEST_PL) {
+	if ((cpu->regs->ss&0x3) != GUEST_PL) {
 		/* The Guest told us their kernel stack with the SET_STACK
 		 * hypercall: both the virtual address and the segment */
-		virtstack = lg->esp1;
-		ss = lg->ss1;
+		virtstack = cpu->esp1;
+		ss = cpu->ss1;
 
-		origstack = gstack = guest_pa(lg, virtstack);
+		origstack = gstack = guest_pa(cpu, virtstack);
 		/* We push the old stack segment and pointer onto the new
 		 * stack: when the Guest does an "iret" back from the interrupt
 		 * handler the CPU will notice they're dropping privilege
 		 * levels and expect these here. */
-		push_guest_stack(lg, &gstack, lg->regs->ss);
-		push_guest_stack(lg, &gstack, lg->regs->esp);
+		push_guest_stack(cpu, &gstack, cpu->regs->ss);
+		push_guest_stack(cpu, &gstack, cpu->regs->esp);
 	} else {
 		/* We're staying on the same Guest (kernel) stack. */
-		virtstack = lg->regs->esp;
-		ss = lg->regs->ss;
+		virtstack = cpu->regs->esp;
+		ss = cpu->regs->ss;
 
-		origstack = gstack = guest_pa(lg, virtstack);
+		origstack = gstack = guest_pa(cpu, virtstack);
 	}
 
 	/* Remember that we never let the Guest actually disable interrupts, so
 	 * the "Interrupt Flag" bit is always set.  We copy that bit from the
 	 * Guest's "irq_enabled" field into the eflags word: we saw the Guest
 	 * copy it back in "lguest_iret". */
-	eflags = lg->regs->eflags;
-	if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0
+	eflags = cpu->regs->eflags;
+	if (get_user(irq_enable, &cpu->lg->lguest_data->irq_enabled) == 0
 	    && !(irq_enable & X86_EFLAGS_IF))
 		eflags &= ~X86_EFLAGS_IF;
 
 	/* An interrupt is expected to push three things on the stack: the old
 	 * "eflags" word, the old code segment, and the old instruction
 	 * pointer. */
-	push_guest_stack(lg, &gstack, eflags);
-	push_guest_stack(lg, &gstack, lg->regs->cs);
-	push_guest_stack(lg, &gstack, lg->regs->eip);
+	push_guest_stack(cpu, &gstack, eflags);
+	push_guest_stack(cpu, &gstack, cpu->regs->cs);
+	push_guest_stack(cpu, &gstack, cpu->regs->eip);
 
 	/* For the six traps which supply an error code, we push that, too. */
 	if (has_err)
-		push_guest_stack(lg, &gstack, lg->regs->errcode);
+		push_guest_stack(cpu, &gstack, cpu->regs->errcode);
 
 	/* Now we've pushed all the old state, we change the stack, the code
 	 * segment and the address to execute. */
-	lg->regs->ss = ss;
-	lg->regs->esp = virtstack + (gstack - origstack);
-	lg->regs->cs = (__KERNEL_CS|GUEST_PL);
-	lg->regs->eip = idt_address(lo, hi);
+	cpu->regs->ss = ss;
+	cpu->regs->esp = virtstack + (gstack - origstack);
+	cpu->regs->cs = (__KERNEL_CS|GUEST_PL);
+	cpu->regs->eip = idt_address(lo, hi);
 
 	/* There are two kinds of interrupt handlers: 0xE is an "interrupt
 	 * gate" which expects interrupts to be disabled on entry. */
 	if (idt_type(lo, hi) == 0xE)
-		if (put_user(0, &lg->lguest_data->irq_enabled))
-			kill_guest(lg, "Disabling interrupts");
+		if (put_user(0, &cpu->lg->lguest_data->irq_enabled))
+			kill_guest(cpu, "Disabling interrupts");
 }
 
 /*H:205
@@ -129,23 +129,23 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
  *
  * maybe_do_interrupt() gets called before every entry to the Guest, to see if
  * we should divert the Guest to running an interrupt handler. */
-void maybe_do_interrupt(struct lguest *lg)
+void maybe_do_interrupt(struct lg_cpu *cpu)
 {
 	unsigned int irq;
 	DECLARE_BITMAP(blk, LGUEST_IRQS);
 	struct desc_struct *idt;
 
 	/* If the Guest hasn't even initialized yet, we can do nothing. */
-	if (!lg->lguest_data)
+	if (!cpu->lg->lguest_data)
 		return;
 
 	/* Take our "irqs_pending" array and remove any interrupts the Guest
 	 * wants blocked: the result ends up in "blk". */
-	if (copy_from_user(&blk, lg->lguest_data->blocked_interrupts,
+	if (copy_from_user(&blk, cpu->lg->lguest_data->blocked_interrupts,
 			   sizeof(blk)))
 		return;
 
-	bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS);
+	bitmap_andnot(blk, cpu->irqs_pending, blk, LGUEST_IRQS);
 
 	/* Find the first interrupt. */
 	irq = find_first_bit(blk, LGUEST_IRQS);
@@ -155,19 +155,20 @@ void maybe_do_interrupt(struct lguest *lg)
 
 	/* They may be in the middle of an iret, where they asked us never to
 	 * deliver interrupts. */
-	if (lg->regs->eip >= lg->noirq_start && lg->regs->eip < lg->noirq_end)
+	if (cpu->regs->eip >= cpu->lg->noirq_start &&
+	   (cpu->regs->eip < cpu->lg->noirq_end))
 		return;
 
 	/* If they're halted, interrupts restart them. */
-	if (lg->halted) {
+	if (cpu->halted) {
 		/* Re-enable interrupts. */
-		if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled))
-			kill_guest(lg, "Re-enabling interrupts");
-		lg->halted = 0;
+		if (put_user(X86_EFLAGS_IF, &cpu->lg->lguest_data->irq_enabled))
+			kill_guest(cpu, "Re-enabling interrupts");
+		cpu->halted = 0;
 	} else {
 		/* Otherwise we check if they have interrupts disabled. */
 		u32 irq_enabled;
-		if (get_user(irq_enabled, &lg->lguest_data->irq_enabled))
+		if (get_user(irq_enabled, &cpu->lg->lguest_data->irq_enabled))
 			irq_enabled = 0;
 		if (!irq_enabled)
 			return;
@@ -176,15 +177,15 @@ void maybe_do_interrupt(struct lguest *lg)
 	/* Look at the IDT entry the Guest gave us for this interrupt.  The
 	 * first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip
 	 * over them. */
-	idt = &lg->arch.idt[FIRST_EXTERNAL_VECTOR+irq];
+	idt = &cpu->arch.idt[FIRST_EXTERNAL_VECTOR+irq];
 	/* If they don't have a handler (yet?), we just ignore it */
 	if (idt_present(idt->a, idt->b)) {
 		/* OK, mark it no longer pending and deliver it. */
-		clear_bit(irq, lg->irqs_pending);
+		clear_bit(irq, cpu->irqs_pending);
 		/* set_guest_interrupt() takes the interrupt descriptor and a
 		 * flag to say whether this interrupt pushes an error code onto
 		 * the stack as well: virtual interrupts never do. */
-		set_guest_interrupt(lg, idt->a, idt->b, 0);
+		set_guest_interrupt(cpu, idt->a, idt->b, 0);
 	}
 
 	/* Every time we deliver an interrupt, we update the timestamp in the
@@ -192,7 +193,7 @@ void maybe_do_interrupt(struct lguest *lg)
 	 * did this more often, but it can actually be quite slow: doing it
 	 * here is a compromise which means at least it gets updated every
 	 * timer interrupt. */
-	write_timestamp(lg);
+	write_timestamp(cpu);
 }
 /*:*/
 
@@ -245,19 +246,19 @@ static int has_err(unsigned int trap)
 }
 
 /* deliver_trap() returns true if it could deliver the trap. */
-int deliver_trap(struct lguest *lg, unsigned int num)
+int deliver_trap(struct lg_cpu *cpu, unsigned int num)
 {
 	/* Trap numbers are always 8 bit, but we set an impossible trap number
 	 * for traps inside the Switcher, so check that here. */
-	if (num >= ARRAY_SIZE(lg->arch.idt))
+	if (num >= ARRAY_SIZE(cpu->arch.idt))
 		return 0;
 
 	/* Early on the Guest hasn't set the IDT entries (or maybe it put a
 	 * bogus one in): if we fail here, the Guest will be killed. */
-	if (!idt_present(lg->arch.idt[num].a, lg->arch.idt[num].b))
+	if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b))
 		return 0;
-	set_guest_interrupt(lg, lg->arch.idt[num].a, lg->arch.idt[num].b,
-			    has_err(num));
+	set_guest_interrupt(cpu, cpu->arch.idt[num].a,
+			    cpu->arch.idt[num].b, has_err(num));
 	return 1;
 }
 
@@ -309,18 +310,18 @@ static int direct_trap(unsigned int num)
  * the Guest.
  *
  * Which is deeply unfair, because (literally!) it wasn't the Guests' fault. */
-void pin_stack_pages(struct lguest *lg)
+void pin_stack_pages(struct lg_cpu *cpu)
 {
 	unsigned int i;
 
 	/* Depending on the CONFIG_4KSTACKS option, the Guest can have one or
 	 * two pages of stack space. */
-	for (i = 0; i < lg->stack_pages; i++)
+	for (i = 0; i < cpu->lg->stack_pages; i++)
 		/* The stack grows *upwards*, so the address we're given is the
 		 * start of the page after the kernel stack.  Subtract one to
 		 * get back onto the first stack page, and keep subtracting to
 		 * get to the rest of the stack pages. */
-		pin_page(lg, lg->esp1 - 1 - i * PAGE_SIZE);
+		pin_page(cpu, cpu->esp1 - 1 - i * PAGE_SIZE);
 }
 
 /* Direct traps also mean that we need to know whenever the Guest wants to use
@@ -331,21 +332,21 @@ void pin_stack_pages(struct lguest *lg)
  *
  * In Linux each process has its own kernel stack, so this happens a lot: we
  * change stacks on each context switch. */
-void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages)
+void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages)
 {
 	/* You are not allowed have a stack segment with privilege level 0: bad
 	 * Guest! */
 	if ((seg & 0x3) != GUEST_PL)
-		kill_guest(lg, "bad stack segment %i", seg);
+		kill_guest(cpu, "bad stack segment %i", seg);
 	/* We only expect one or two stack pages. */
 	if (pages > 2)
-		kill_guest(lg, "bad stack pages %u", pages);
+		kill_guest(cpu, "bad stack pages %u", pages);
 	/* Save where the stack is, and how many pages */
-	lg->ss1 = seg;
-	lg->esp1 = esp;
-	lg->stack_pages = pages;
+	cpu->ss1 = seg;
+	cpu->esp1 = esp;
+	cpu->lg->stack_pages = pages;
 	/* Make sure the new stack pages are mapped */
-	pin_stack_pages(lg);
+	pin_stack_pages(cpu);
 }
 
 /* All this reference to mapping stacks leads us neatly into the other complex
@@ -353,7 +354,7 @@ void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages)
 
 /*H:235 This is the routine which actually checks the Guest's IDT entry and
  * transfers it into the entry in "struct lguest": */
-static void set_trap(struct lguest *lg, struct desc_struct *trap,
+static void set_trap(struct lg_cpu *cpu, struct desc_struct *trap,
 		     unsigned int num, u32 lo, u32 hi)
 {
 	u8 type = idt_type(lo, hi);
@@ -366,7 +367,7 @@ static void set_trap(struct lguest *lg, struct desc_struct *trap,
 
 	/* We only support interrupt and trap gates. */
 	if (type != 0xE && type != 0xF)
-		kill_guest(lg, "bad IDT type %i", type);
+		kill_guest(cpu, "bad IDT type %i", type);
 
 	/* We only copy the handler address, present bit, privilege level and
 	 * type.  The privilege level controls where the trap can be triggered
@@ -383,7 +384,7 @@ static void set_trap(struct lguest *lg, struct desc_struct *trap,
  *
  * We saw the Guest setting Interrupt Descriptor Table (IDT) entries with the
  * LHCALL_LOAD_IDT_ENTRY hypercall before: that comes here. */
-void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi)
+void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int num, u32 lo, u32 hi)
 {
 	/* Guest never handles: NMI, doublefault, spurious interrupt or
 	 * hypercall.  We ignore when it tries to set them. */
@@ -392,13 +393,13 @@ void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi)
 
 	/* Mark the IDT as changed: next time the Guest runs we'll know we have
 	 * to copy this again. */
-	lg->changed |= CHANGED_IDT;
+	cpu->changed |= CHANGED_IDT;
 
 	/* Check that the Guest doesn't try to step outside the bounds. */
-	if (num >= ARRAY_SIZE(lg->arch.idt))
-		kill_guest(lg, "Setting idt entry %u", num);
+	if (num >= ARRAY_SIZE(cpu->arch.idt))
+		kill_guest(cpu, "Setting idt entry %u", num);
 	else
-		set_trap(lg, &lg->arch.idt[num], num, lo, hi);
+		set_trap(cpu, &cpu->arch.idt[num], num, lo, hi);
 }
 
 /* The default entry for each interrupt points into the Switcher routines which
@@ -434,14 +435,14 @@ void setup_default_idt_entries(struct lguest_ro_state *state,
 /*H:240 We don't use the IDT entries in the "struct lguest" directly, instead
  * we copy them into the IDT which we've set up for Guests on this CPU, just
  * before we run the Guest.  This routine does that copy. */
-void copy_traps(const struct lguest *lg, struct desc_struct *idt,
+void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt,
 		const unsigned long *def)
 {
 	unsigned int i;
 
 	/* We can simply copy the direct traps, otherwise we use the default
 	 * ones in the Switcher: they will return to the Host. */
-	for (i = 0; i < ARRAY_SIZE(lg->arch.idt); i++) {
+	for (i = 0; i < ARRAY_SIZE(cpu->arch.idt); i++) {
 		/* If no Guest can ever override this trap, leave it alone. */
 		if (!direct_trap(i))
 			continue;
@@ -450,8 +451,8 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt,
 		 * Interrupt gates (type 14) disable interrupts as they are
 		 * entered, which we never let the Guest do.  Not present
 		 * entries (type 0x0) also can't go direct, of course. */
-		if (idt_type(lg->arch.idt[i].a, lg->arch.idt[i].b) == 0xF)
-			idt[i] = lg->arch.idt[i];
+		if (idt_type(cpu->arch.idt[i].a, cpu->arch.idt[i].b) == 0xF)
+			idt[i] = cpu->arch.idt[i];
 		else
 			/* Reset it to the default. */
 			default_idt_entry(&idt[i], i, def[i]);
@@ -470,13 +471,13 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt,
  * infrastructure to set a callback at that time.
  *
  * 0 means "turn off the clock". */
-void guest_set_clockevent(struct lguest *lg, unsigned long delta)
+void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta)
 {
 	ktime_t expires;
 
 	if (unlikely(delta == 0)) {
 		/* Clock event device is shutting down. */
-		hrtimer_cancel(&lg->hrt);
+		hrtimer_cancel(&cpu->hrt);
 		return;
 	}
 
@@ -484,25 +485,25 @@ void guest_set_clockevent(struct lguest *lg, unsigned long delta)
 	 * all the time between now and the timer interrupt it asked for.  This
 	 * is almost always the right thing to do. */
 	expires = ktime_add_ns(ktime_get_real(), delta);
-	hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS);
+	hrtimer_start(&cpu->hrt, expires, HRTIMER_MODE_ABS);
 }
 
 /* This is the function called when the Guest's timer expires. */
 static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
 {
-	struct lguest *lg = container_of(timer, struct lguest, hrt);
+	struct lg_cpu *cpu = container_of(timer, struct lg_cpu, hrt);
 
 	/* Remember the first interrupt is the timer interrupt. */
-	set_bit(0, lg->irqs_pending);
+	set_bit(0, cpu->irqs_pending);
 	/* If the Guest is actually stopped, we need to wake it up. */
-	if (lg->halted)
-		wake_up_process(lg->tsk);
+	if (cpu->halted)
+		wake_up_process(cpu->tsk);
 	return HRTIMER_NORESTART;
 }
 
 /* This sets up the timer for this Guest. */
-void init_clockdev(struct lguest *lg)
+void init_clockdev(struct lg_cpu *cpu)
 {
-	hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS);
-	lg->hrt.function = clockdev_fn;
+	hrtimer_init(&cpu->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+	cpu->hrt.function = clockdev_fn;
 }
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index 86924891b5eb..2337e1a06f02 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -8,6 +8,7 @@
 #include <linux/lguest.h>
 #include <linux/lguest_launcher.h>
 #include <linux/wait.h>
+#include <linux/hrtimer.h>
 #include <linux/err.h>
 #include <asm/semaphore.h>
 
@@ -38,58 +39,72 @@ struct lguest_pages
 #define CHANGED_GDT_TLS		4 /* Actually a subset of CHANGED_GDT */
 #define CHANGED_ALL	        3
 
-/* The private info the thread maintains about the guest. */
-struct lguest
-{
-	/* At end of a page shared mapped over lguest_pages in guest.  */
-	unsigned long regs_page;
-	struct lguest_regs *regs;
-	struct lguest_data __user *lguest_data;
+struct lguest;
+
+struct lg_cpu {
+	unsigned int id;
+	struct lguest *lg;
 	struct task_struct *tsk;
 	struct mm_struct *mm; 	/* == tsk->mm, but that becomes NULL on exit */
-	u32 pfn_limit;
-	/* This provides the offset to the base of guest-physical
-	 * memory in the Launcher. */
-	void __user *mem_base;
-	unsigned long kernel_address;
+
 	u32 cr2;
-	int halted;
 	int ts;
-	u32 next_hcall;
 	u32 esp1;
 	u8 ss1;
 
+	/* Bitmap of what has changed: see CHANGED_* above. */
+	int changed;
+
+	unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */
+
+	/* At end of a page shared mapped over lguest_pages in guest.  */
+	unsigned long regs_page;
+	struct lguest_regs *regs;
+
+	struct lguest_pages *last_pages;
+
+	int cpu_pgd; /* which pgd this cpu is currently using */
+
 	/* If a hypercall was asked for, this points to the arguments. */
 	struct hcall_args *hcall;
+	u32 next_hcall;
+
+	/* Virtual clock device */
+	struct hrtimer hrt;
 
 	/* Do we need to stop what we're doing and return to userspace? */
 	int break_out;
 	wait_queue_head_t break_wq;
+	int halted;
 
-	/* Bitmap of what has changed: see CHANGED_* above. */
-	int changed;
-	struct lguest_pages *last_pages;
+	/* Pending virtual interrupts */
+	DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
+
+	struct lg_cpu_arch arch;
+};
+
+/* The private info the thread maintains about the guest. */
+struct lguest
+{
+	struct lguest_data __user *lguest_data;
+	struct lg_cpu cpus[NR_CPUS];
+	unsigned int nr_cpus;
+
+	u32 pfn_limit;
+	/* This provides the offset to the base of guest-physical
+	 * memory in the Launcher. */
+	void __user *mem_base;
+	unsigned long kernel_address;
 
-	/* We keep a small number of these. */
-	u32 pgdidx;
 	struct pgdir pgdirs[4];
 
 	unsigned long noirq_start, noirq_end;
-	unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */
 
 	unsigned int stack_pages;
 	u32 tsc_khz;
 
 	/* Dead? */
 	const char *dead;
-
-	struct lguest_arch arch;
-
-	/* Virtual clock device */
-	struct hrtimer hrt;
-
-	/* Pending virtual interrupts */
-	DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
 };
 
 extern struct mutex lguest_lock;
@@ -97,26 +112,26 @@ extern struct mutex lguest_lock;
 /* core.c: */
 int lguest_address_ok(const struct lguest *lg,
 		      unsigned long addr, unsigned long len);
-void __lgread(struct lguest *, void *, unsigned long, unsigned);
-void __lgwrite(struct lguest *, unsigned long, const void *, unsigned);
+void __lgread(struct lg_cpu *, void *, unsigned long, unsigned);
+void __lgwrite(struct lg_cpu *, unsigned long, const void *, unsigned);
 
 /*H:035 Using memory-copy operations like that is usually inconvient, so we
  * have the following helper macros which read and write a specific type (often
  * an unsigned long).
  *
  * This reads into a variable of the given type then returns that. */
-#define lgread(lg, addr, type)						\
-	({ type _v; __lgread((lg), &_v, (addr), sizeof(_v)); _v; })
+#define lgread(cpu, addr, type)						\
+	({ type _v; __lgread((cpu), &_v, (addr), sizeof(_v)); _v; })
 
 /* This checks that the variable is of the given type, then writes it out. */
-#define lgwrite(lg, addr, type, val)				\
+#define lgwrite(cpu, addr, type, val)				\
 	do {							\
 		typecheck(type, val);				\
-		__lgwrite((lg), (addr), &(val), sizeof(val));	\
+		__lgwrite((cpu), (addr), &(val), sizeof(val));	\
 	} while(0)
 /* (end of memory access helper routines) :*/
 
-int run_guest(struct lguest *lg, unsigned long __user *user);
+int run_guest(struct lg_cpu *cpu, unsigned long __user *user);
 
 /* Helper macros to obtain the first 12 or the last 20 bits, this is only the
  * first step in the migration to the kernel types.  pte_pfn is already defined
@@ -126,52 +141,53 @@ int run_guest(struct lguest *lg, unsigned long __user *user);
 #define pgd_pfn(x)	(pgd_val(x) >> PAGE_SHIFT)
 
 /* interrupts_and_traps.c: */
-void maybe_do_interrupt(struct lguest *lg);
-int deliver_trap(struct lguest *lg, unsigned int num);
-void load_guest_idt_entry(struct lguest *lg, unsigned int i, u32 low, u32 hi);
-void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages);
-void pin_stack_pages(struct lguest *lg);
+void maybe_do_interrupt(struct lg_cpu *cpu);
+int deliver_trap(struct lg_cpu *cpu, unsigned int num);
+void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int i,
+			  u32 low, u32 hi);
+void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages);
+void pin_stack_pages(struct lg_cpu *cpu);
 void setup_default_idt_entries(struct lguest_ro_state *state,
 			       const unsigned long *def);
-void copy_traps(const struct lguest *lg, struct desc_struct *idt,
+void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt,
 		const unsigned long *def);
-void guest_set_clockevent(struct lguest *lg, unsigned long delta);
-void init_clockdev(struct lguest *lg);
+void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta);
+void init_clockdev(struct lg_cpu *cpu);
 bool check_syscall_vector(struct lguest *lg);
 int init_interrupts(void);
 void free_interrupts(void);
 
 /* segments.c: */
 void setup_default_gdt_entries(struct lguest_ro_state *state);
-void setup_guest_gdt(struct lguest *lg);
-void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num);
-void guest_load_tls(struct lguest *lg, unsigned long tls_array);
-void copy_gdt(const struct lguest *lg, struct desc_struct *gdt);
-void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt);
+void setup_guest_gdt(struct lg_cpu *cpu);
+void load_guest_gdt(struct lg_cpu *cpu, unsigned long table, u32 num);
+void guest_load_tls(struct lg_cpu *cpu, unsigned long tls_array);
+void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt);
+void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt);
 
 /* page_tables.c: */
 int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
 void free_guest_pagetable(struct lguest *lg);
-void guest_new_pagetable(struct lguest *lg, unsigned long pgtable);
+void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable);
 void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i);
-void guest_pagetable_clear_all(struct lguest *lg);
-void guest_pagetable_flush_user(struct lguest *lg);
-void guest_set_pte(struct lguest *lg, unsigned long gpgdir,
+void guest_pagetable_clear_all(struct lg_cpu *cpu);
+void guest_pagetable_flush_user(struct lg_cpu *cpu);
+void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir,
 		   unsigned long vaddr, pte_t val);
-void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages);
-int demand_page(struct lguest *info, unsigned long cr2, int errcode);
-void pin_page(struct lguest *lg, unsigned long vaddr);
-unsigned long guest_pa(struct lguest *lg, unsigned long vaddr);
-void page_table_guest_data_init(struct lguest *lg);
+void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages);
+int demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode);
+void pin_page(struct lg_cpu *cpu, unsigned long vaddr);
+unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr);
+void page_table_guest_data_init(struct lg_cpu *cpu);
 
 /* <arch>/core.c: */
 void lguest_arch_host_init(void);
 void lguest_arch_host_fini(void);
-void lguest_arch_run_guest(struct lguest *lg);
-void lguest_arch_handle_trap(struct lguest *lg);
-int lguest_arch_init_hypercalls(struct lguest *lg);
-int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args);
-void lguest_arch_setup_regs(struct lguest *lg, unsigned long start);
+void lguest_arch_run_guest(struct lg_cpu *cpu);
+void lguest_arch_handle_trap(struct lg_cpu *cpu);
+int lguest_arch_init_hypercalls(struct lg_cpu *cpu);
+int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args);
+void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start);
 
 /* <arch>/switcher.S: */
 extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
@@ -181,8 +197,8 @@ int lguest_device_init(void);
 void lguest_device_remove(void);
 
 /* hypercalls.c: */
-void do_hypercalls(struct lguest *lg);
-void write_timestamp(struct lguest *lg);
+void do_hypercalls(struct lg_cpu *cpu);
+void write_timestamp(struct lg_cpu *cpu);
 
 /*L:035
  * Let's step aside for the moment, to study one important routine that's used
@@ -208,12 +224,12 @@ void write_timestamp(struct lguest *lg);
  * Like any macro which uses an "if", it is safely wrapped in a run-once "do {
  * } while(0)".
  */
-#define kill_guest(lg, fmt...)					\
+#define kill_guest(cpu, fmt...)					\
 do {								\
-	if (!(lg)->dead) {					\
-		(lg)->dead = kasprintf(GFP_ATOMIC, fmt);	\
-		if (!(lg)->dead)				\
-			(lg)->dead = ERR_PTR(-ENOMEM);		\
+	if (!(cpu)->lg->dead) {					\
+		(cpu)->lg->dead = kasprintf(GFP_ATOMIC, fmt);	\
+		if (!(cpu)->lg->dead)				\
+			(cpu)->lg->dead = ERR_PTR(-ENOMEM);	\
 	}							\
 } while(0)
 /* (End of aside) :*/
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index 3b92a61ba8d2..85d42d3d01a9 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -6,6 +6,7 @@
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
+#include <linux/sched.h>
 #include "lg.h"
 
 /*L:055 When something happens, the Waker process needs a way to stop the
@@ -13,7 +14,7 @@
  * LHREQ_BREAK and the value "1" to /dev/lguest to do this.  Once the Launcher
  * has done whatever needs attention, it writes LHREQ_BREAK and "0" to release
  * the Waker. */
-static int break_guest_out(struct lguest *lg, const unsigned long __user *input)
+static int break_guest_out(struct lg_cpu *cpu, const unsigned long __user*input)
 {
 	unsigned long on;
 
@@ -22,21 +23,21 @@ static int break_guest_out(struct lguest *lg, const unsigned long __user *input)
 		return -EFAULT;
 
 	if (on) {
-		lg->break_out = 1;
+		cpu->break_out = 1;
 		/* Pop it out of the Guest (may be running on different CPU) */
-		wake_up_process(lg->tsk);
+		wake_up_process(cpu->tsk);
 		/* Wait for them to reset it */
-		return wait_event_interruptible(lg->break_wq, !lg->break_out);
+		return wait_event_interruptible(cpu->break_wq, !cpu->break_out);
 	} else {
-		lg->break_out = 0;
-		wake_up(&lg->break_wq);
+		cpu->break_out = 0;
+		wake_up(&cpu->break_wq);
 		return 0;
 	}
 }
 
 /*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
  * number to /dev/lguest. */
-static int user_send_irq(struct lguest *lg, const unsigned long __user *input)
+static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input)
 {
 	unsigned long irq;
 
@@ -46,7 +47,7 @@ static int user_send_irq(struct lguest *lg, const unsigned long __user *input)
 		return -EINVAL;
 	/* Next time the Guest runs, the core code will see if it can deliver
 	 * this interrupt. */
-	set_bit(irq, lg->irqs_pending);
+	set_bit(irq, cpu->irqs_pending);
 	return 0;
 }
 
@@ -55,13 +56,21 @@ static int user_send_irq(struct lguest *lg, const unsigned long __user *input)
 static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
 {
 	struct lguest *lg = file->private_data;
+	struct lg_cpu *cpu;
+	unsigned int cpu_id = *o;
 
 	/* You must write LHREQ_INITIALIZE first! */
 	if (!lg)
 		return -EINVAL;
 
+	/* Watch out for arbitrary vcpu indexes! */
+	if (cpu_id >= lg->nr_cpus)
+		return -EINVAL;
+
+	cpu = &lg->cpus[cpu_id];
+
 	/* If you're not the task which owns the Guest, go away. */
-	if (current != lg->tsk)
+	if (current != cpu->tsk)
 		return -EPERM;
 
 	/* If the guest is already dead, we indicate why */
@@ -81,11 +90,53 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
 
 	/* If we returned from read() last time because the Guest notified,
 	 * clear the flag. */
-	if (lg->pending_notify)
-		lg->pending_notify = 0;
+	if (cpu->pending_notify)
+		cpu->pending_notify = 0;
 
 	/* Run the Guest until something interesting happens. */
-	return run_guest(lg, (unsigned long __user *)user);
+	return run_guest(cpu, (unsigned long __user *)user);
+}
+
+static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
+{
+	if (id >= NR_CPUS)
+		return -EINVAL;
+
+	cpu->id = id;
+	cpu->lg = container_of((cpu - id), struct lguest, cpus[0]);
+	cpu->lg->nr_cpus++;
+	init_clockdev(cpu);
+
+	/* We need a complete page for the Guest registers: they are accessible
+	 * to the Guest and we can only grant it access to whole pages. */
+	cpu->regs_page = get_zeroed_page(GFP_KERNEL);
+	if (!cpu->regs_page)
+		return -ENOMEM;
+
+	/* We actually put the registers at the bottom of the page. */
+	cpu->regs = (void *)cpu->regs_page + PAGE_SIZE - sizeof(*cpu->regs);
+
+	/* Now we initialize the Guest's registers, handing it the start
+	 * address. */
+	lguest_arch_setup_regs(cpu, start_ip);
+
+	/* Initialize the queue for the waker to wait on */
+	init_waitqueue_head(&cpu->break_wq);
+
+	/* We keep a pointer to the Launcher task (ie. current task) for when
+	 * other Guests want to wake this one (inter-Guest I/O). */
+	cpu->tsk = current;
+
+	/* We need to keep a pointer to the Launcher's memory map, because if
+	 * the Launcher dies we need to clean it up.  If we don't keep a
+	 * reference, it is destroyed before close() is called. */
+	cpu->mm = get_task_mm(cpu->tsk);
+
+	/* We remember which CPU's pages this Guest used last, for optimization
+	 * when the same Guest runs on the same CPU twice. */
+	cpu->last_pages = NULL;
+
+	return 0;
 }
 
 /*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit)
@@ -134,15 +185,10 @@ static int initialize(struct file *file, const unsigned long __user *input)
 	lg->mem_base = (void __user *)(long)args[0];
 	lg->pfn_limit = args[1];
 
-	/* We need a complete page for the Guest registers: they are accessible
-	 * to the Guest and we can only grant it access to whole pages. */
-	lg->regs_page = get_zeroed_page(GFP_KERNEL);
-	if (!lg->regs_page) {
-		err = -ENOMEM;
+	/* This is the first cpu */
+	err = lg_cpu_start(&lg->cpus[0], 0, args[3]);
+	if (err)
 		goto release_guest;
-	}
-	/* We actually put the registers at the bottom of the page. */
-	lg->regs = (void *)lg->regs_page + PAGE_SIZE - sizeof(*lg->regs);
 
 	/* Initialize the Guest's shadow page tables, using the toplevel
 	 * address the Launcher gave us.  This allocates memory, so can
@@ -151,28 +197,6 @@ static int initialize(struct file *file, const unsigned long __user *input)
 	if (err)
 		goto free_regs;
 
-	/* Now we initialize the Guest's registers, handing it the start
-	 * address. */
-	lguest_arch_setup_regs(lg, args[3]);
-
-	/* The timer for lguest's clock needs initialization. */
-	init_clockdev(lg);
-
-	/* We keep a pointer to the Launcher task (ie. current task) for when
-	 * other Guests want to wake this one (inter-Guest I/O). */
-	lg->tsk = current;
-	/* We need to keep a pointer to the Launcher's memory map, because if
-	 * the Launcher dies we need to clean it up.  If we don't keep a
-	 * reference, it is destroyed before close() is called. */
-	lg->mm = get_task_mm(lg->tsk);
-
-	/* Initialize the queue for the waker to wait on */
-	init_waitqueue_head(&lg->break_wq);
-
-	/* We remember which CPU's pages this Guest used last, for optimization
-	 * when the same Guest runs on the same CPU twice. */
-	lg->last_pages = NULL;
-
 	/* We keep our "struct lguest" in the file's private_data. */
 	file->private_data = lg;
 
@@ -182,7 +206,8 @@ static int initialize(struct file *file, const unsigned long __user *input)
 	return sizeof(args);
 
 free_regs:
-	free_page(lg->regs_page);
+	/* FIXME: This should be in free_vcpu */
+	free_page(lg->cpus[0].regs_page);
 release_guest:
 	kfree(lg);
 unlock:
@@ -202,30 +227,37 @@ static ssize_t write(struct file *file, const char __user *in,
 	struct lguest *lg = file->private_data;
 	const unsigned long __user *input = (const unsigned long __user *)in;
 	unsigned long req;
+	struct lg_cpu *uninitialized_var(cpu);
+	unsigned int cpu_id = *off;
 
 	if (get_user(req, input) != 0)
 		return -EFAULT;
 	input++;
 
 	/* If you haven't initialized, you must do that first. */
-	if (req != LHREQ_INITIALIZE && !lg)
-		return -EINVAL;
+	if (req != LHREQ_INITIALIZE) {
+		if (!lg || (cpu_id >= lg->nr_cpus))
+			return -EINVAL;
+		cpu = &lg->cpus[cpu_id];
+		if (!cpu)
+			return -EINVAL;
+	}
 
 	/* Once the Guest is dead, all you can do is read() why it died. */
 	if (lg && lg->dead)
 		return -ENOENT;
 
 	/* If you're not the task which owns the Guest, you can only break */
-	if (lg && current != lg->tsk && req != LHREQ_BREAK)
+	if (lg && current != cpu->tsk && req != LHREQ_BREAK)
 		return -EPERM;
 
 	switch (req) {
 	case LHREQ_INITIALIZE:
 		return initialize(file, input);
 	case LHREQ_IRQ:
-		return user_send_irq(lg, input);
+		return user_send_irq(cpu, input);
 	case LHREQ_BREAK:
-		return break_guest_out(lg, input);
+		return break_guest_out(cpu, input);
 	default:
 		return -EINVAL;
 	}
@@ -241,6 +273,7 @@ static ssize_t write(struct file *file, const char __user *in,
 static int close(struct inode *inode, struct file *file)
 {
 	struct lguest *lg = file->private_data;
+	unsigned int i;
 
 	/* If we never successfully initialized, there's nothing to clean up */
 	if (!lg)
@@ -249,19 +282,23 @@ static int close(struct inode *inode, struct file *file)
 	/* We need the big lock, to protect from inter-guest I/O and other
 	 * Launchers initializing guests. */
 	mutex_lock(&lguest_lock);
-	/* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
-	hrtimer_cancel(&lg->hrt);
+
 	/* Free up the shadow page tables for the Guest. */
 	free_guest_pagetable(lg);
-	/* Now all the memory cleanups are done, it's safe to release the
-	 * Launcher's memory management structure. */
-	mmput(lg->mm);
+
+	for (i = 0; i < lg->nr_cpus; i++) {
+		/* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
+		hrtimer_cancel(&lg->cpus[i].hrt);
+		/* We can free up the register page we allocated. */
+		free_page(lg->cpus[i].regs_page);
+		/* Now all the memory cleanups are done, it's safe to release
+		 * the Launcher's memory management structure. */
+		mmput(lg->cpus[i].mm);
+	}
 	/* If lg->dead doesn't contain an error code it will be NULL or a
 	 * kmalloc()ed string, either of which is ok to hand to kfree(). */
 	if (!IS_ERR(lg->dead))
 		kfree(lg->dead);
-	/* We can free up the register page we allocated. */
-	free_page(lg->regs_page);
 	/* We clear the entire structure, which also marks it as free for the
 	 * next user. */
 	memset(lg, 0, sizeof(*lg));
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index fffabb327157..74b4cf2a6c41 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -68,23 +68,23 @@ static DEFINE_PER_CPU(pte_t *, switcher_pte_pages);
  * page directory entry (PGD) for that address.  Since we keep track of several
  * page tables, the "i" argument tells us which one we're interested in (it's
  * usually the current one). */
-static pgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
+static pgd_t *spgd_addr(struct lg_cpu *cpu, u32 i, unsigned long vaddr)
 {
 	unsigned int index = pgd_index(vaddr);
 
 	/* We kill any Guest trying to touch the Switcher addresses. */
 	if (index >= SWITCHER_PGD_INDEX) {
-		kill_guest(lg, "attempt to access switcher pages");
+		kill_guest(cpu, "attempt to access switcher pages");
 		index = 0;
 	}
 	/* Return a pointer index'th pgd entry for the i'th page table. */
-	return &lg->pgdirs[i].pgdir[index];
+	return &cpu->lg->pgdirs[i].pgdir[index];
 }
 
 /* This routine then takes the page directory entry returned above, which
  * contains the address of the page table entry (PTE) page.  It then returns a
  * pointer to the PTE entry for the given address. */
-static pte_t *spte_addr(struct lguest *lg, pgd_t spgd, unsigned long vaddr)
+static pte_t *spte_addr(pgd_t spgd, unsigned long vaddr)
 {
 	pte_t *page = __va(pgd_pfn(spgd) << PAGE_SHIFT);
 	/* You should never call this if the PGD entry wasn't valid */
@@ -94,14 +94,13 @@ static pte_t *spte_addr(struct lguest *lg, pgd_t spgd, unsigned long vaddr)
 
 /* These two functions just like the above two, except they access the Guest
  * page tables.  Hence they return a Guest address. */
-static unsigned long gpgd_addr(struct lguest *lg, unsigned long vaddr)
+static unsigned long gpgd_addr(struct lg_cpu *cpu, unsigned long vaddr)
 {
 	unsigned int index = vaddr >> (PGDIR_SHIFT);
-	return lg->pgdirs[lg->pgdidx].gpgdir + index * sizeof(pgd_t);
+	return cpu->lg->pgdirs[cpu->cpu_pgd].gpgdir + index * sizeof(pgd_t);
 }
 
-static unsigned long gpte_addr(struct lguest *lg,
-			       pgd_t gpgd, unsigned long vaddr)
+static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr)
 {
 	unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT;
 	BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT));
@@ -138,7 +137,7 @@ static unsigned long get_pfn(unsigned long virtpfn, int write)
  * entry can be a little tricky.  The flags are (almost) the same, but the
  * Guest PTE contains a virtual page number: the CPU needs the real page
  * number. */
-static pte_t gpte_to_spte(struct lguest *lg, pte_t gpte, int write)
+static pte_t gpte_to_spte(struct lg_cpu *cpu, pte_t gpte, int write)
 {
 	unsigned long pfn, base, flags;
 
@@ -149,7 +148,7 @@ static pte_t gpte_to_spte(struct lguest *lg, pte_t gpte, int write)
 	flags = (pte_flags(gpte) & ~_PAGE_GLOBAL);
 
 	/* The Guest's pages are offset inside the Launcher. */
-	base = (unsigned long)lg->mem_base / PAGE_SIZE;
+	base = (unsigned long)cpu->lg->mem_base / PAGE_SIZE;
 
 	/* We need a temporary "unsigned long" variable to hold the answer from
 	 * get_pfn(), because it returns 0xFFFFFFFF on failure, which wouldn't
@@ -157,7 +156,7 @@ static pte_t gpte_to_spte(struct lguest *lg, pte_t gpte, int write)
 	 * page, given the virtual number. */
 	pfn = get_pfn(base + pte_pfn(gpte), write);
 	if (pfn == -1UL) {
-		kill_guest(lg, "failed to get page %lu", pte_pfn(gpte));
+		kill_guest(cpu, "failed to get page %lu", pte_pfn(gpte));
 		/* When we destroy the Guest, we'll go through the shadow page
 		 * tables and release_pte() them.  Make sure we don't think
 		 * this one is valid! */
@@ -177,17 +176,18 @@ static void release_pte(pte_t pte)
 }
 /*:*/
 
-static void check_gpte(struct lguest *lg, pte_t gpte)
+static void check_gpte(struct lg_cpu *cpu, pte_t gpte)
 {
 	if ((pte_flags(gpte) & (_PAGE_PWT|_PAGE_PSE))
-	    || pte_pfn(gpte) >= lg->pfn_limit)
-		kill_guest(lg, "bad page table entry");
+	    || pte_pfn(gpte) >= cpu->lg->pfn_limit)
+		kill_guest(cpu, "bad page table entry");
 }
 
-static void check_gpgd(struct lguest *lg, pgd_t gpgd)
+static void check_gpgd(struct lg_cpu *cpu, pgd_t gpgd)
 {
-	if ((pgd_flags(gpgd) & ~_PAGE_TABLE) || pgd_pfn(gpgd) >= lg->pfn_limit)
-		kill_guest(lg, "bad page directory entry");
+	if ((pgd_flags(gpgd) & ~_PAGE_TABLE) ||
+	   (pgd_pfn(gpgd) >= cpu->lg->pfn_limit))
+		kill_guest(cpu, "bad page directory entry");
 }
 
 /*H:330
@@ -200,7 +200,7 @@ static void check_gpgd(struct lguest *lg, pgd_t gpgd)
  *
  * If we fixed up the fault (ie. we mapped the address), this routine returns
  * true.  Otherwise, it was a real fault and we need to tell the Guest. */
-int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
+int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
 {
 	pgd_t gpgd;
 	pgd_t *spgd;
@@ -209,24 +209,24 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
 	pte_t *spte;
 
 	/* First step: get the top-level Guest page table entry. */
-	gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t);
+	gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
 	/* Toplevel not present?  We can't map it in. */
 	if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
 		return 0;
 
 	/* Now look at the matching shadow entry. */
-	spgd = spgd_addr(lg, lg->pgdidx, vaddr);
+	spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr);
 	if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) {
 		/* No shadow entry: allocate a new shadow PTE page. */
 		unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
 		/* This is not really the Guest's fault, but killing it is
 		 * simple for this corner case. */
 		if (!ptepage) {
-			kill_guest(lg, "out of memory allocating pte page");
+			kill_guest(cpu, "out of memory allocating pte page");
 			return 0;
 		}
 		/* We check that the Guest pgd is OK. */
-		check_gpgd(lg, gpgd);
+		check_gpgd(cpu, gpgd);
 		/* And we copy the flags to the shadow PGD entry.  The page
 		 * number in the shadow PGD is the page we just allocated. */
 		*spgd = __pgd(__pa(ptepage) | pgd_flags(gpgd));
@@ -234,8 +234,8 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
 
 	/* OK, now we look at the lower level in the Guest page table: keep its
 	 * address, because we might update it later. */
-	gpte_ptr = gpte_addr(lg, gpgd, vaddr);
-	gpte = lgread(lg, gpte_ptr, pte_t);
+	gpte_ptr = gpte_addr(gpgd, vaddr);
+	gpte = lgread(cpu, gpte_ptr, pte_t);
 
 	/* If this page isn't in the Guest page tables, we can't page it in. */
 	if (!(pte_flags(gpte) & _PAGE_PRESENT))
@@ -252,7 +252,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
 
 	/* Check that the Guest PTE flags are OK, and the page number is below
 	 * the pfn_limit (ie. not mapping the Launcher binary). */
-	check_gpte(lg, gpte);
+	check_gpte(cpu, gpte);
 
 	/* Add the _PAGE_ACCESSED and (for a write) _PAGE_DIRTY flag */
 	gpte = pte_mkyoung(gpte);
@@ -260,7 +260,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
 		gpte = pte_mkdirty(gpte);
 
 	/* Get the pointer to the shadow PTE entry we're going to set. */
-	spte = spte_addr(lg, *spgd, vaddr);
+	spte = spte_addr(*spgd, vaddr);
 	/* If there was a valid shadow PTE entry here before, we release it.
 	 * This can happen with a write to a previously read-only entry. */
 	release_pte(*spte);
@@ -268,17 +268,17 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
 	/* If this is a write, we insist that the Guest page is writable (the
 	 * final arg to gpte_to_spte()). */
 	if (pte_dirty(gpte))
-		*spte = gpte_to_spte(lg, gpte, 1);
+		*spte = gpte_to_spte(cpu, gpte, 1);
 	else
 		/* If this is a read, don't set the "writable" bit in the page
 		 * table entry, even if the Guest says it's writable.  That way
 		 * we will come back here when a write does actually occur, so
 		 * we can update the Guest's _PAGE_DIRTY flag. */
-		*spte = gpte_to_spte(lg, pte_wrprotect(gpte), 0);
+		*spte = gpte_to_spte(cpu, pte_wrprotect(gpte), 0);
 
 	/* Finally, we write the Guest PTE entry back: we've set the
 	 * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */
-	lgwrite(lg, gpte_ptr, pte_t, gpte);
+	lgwrite(cpu, gpte_ptr, pte_t, gpte);
 
 	/* The fault is fixed, the page table is populated, the mapping
 	 * manipulated, the result returned and the code complete.  A small
@@ -297,19 +297,19 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
  *
  * This is a quick version which answers the question: is this virtual address
  * mapped by the shadow page tables, and is it writable? */
-static int page_writable(struct lguest *lg, unsigned long vaddr)
+static int page_writable(struct lg_cpu *cpu, unsigned long vaddr)
 {
 	pgd_t *spgd;
 	unsigned long flags;
 
 	/* Look at the current top level entry: is it present? */
-	spgd = spgd_addr(lg, lg->pgdidx, vaddr);
+	spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr);
 	if (!(pgd_flags(*spgd) & _PAGE_PRESENT))
 		return 0;
 
 	/* Check the flags on the pte entry itself: it must be present and
 	 * writable. */
-	flags = pte_flags(*(spte_addr(lg, *spgd, vaddr)));
+	flags = pte_flags(*(spte_addr(*spgd, vaddr)));
 
 	return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW);
 }
@@ -317,10 +317,10 @@ static int page_writable(struct lguest *lg, unsigned long vaddr)
 /* So, when pin_stack_pages() asks us to pin a page, we check if it's already
  * in the page tables, and if not, we call demand_page() with error code 2
  * (meaning "write"). */
-void pin_page(struct lguest *lg, unsigned long vaddr)
+void pin_page(struct lg_cpu *cpu, unsigned long vaddr)
 {
-	if (!page_writable(lg, vaddr) && !demand_page(lg, vaddr, 2))
-		kill_guest(lg, "bad stack page %#lx", vaddr);
+	if (!page_writable(cpu, vaddr) && !demand_page(cpu, vaddr, 2))
+		kill_guest(cpu, "bad stack page %#lx", vaddr);
 }
 
 /*H:450 If we chase down the release_pgd() code, it looks like this: */
@@ -358,28 +358,28 @@ static void flush_user_mappings(struct lguest *lg, int idx)
  *
  * The Guest has a hypercall to throw away the page tables: it's used when a
  * large number of mappings have been changed. */
-void guest_pagetable_flush_user(struct lguest *lg)
+void guest_pagetable_flush_user(struct lg_cpu *cpu)
 {
 	/* Drop the userspace part of the current page table. */
-	flush_user_mappings(lg, lg->pgdidx);
+	flush_user_mappings(cpu->lg, cpu->cpu_pgd);
 }
 /*:*/
 
 /* We walk down the guest page tables to get a guest-physical address */
-unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
+unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
 {
 	pgd_t gpgd;
 	pte_t gpte;
 
 	/* First step: get the top-level Guest page table entry. */
-	gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t);
+	gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
 	/* Toplevel not present?  We can't map it in. */
 	if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
-		kill_guest(lg, "Bad address %#lx", vaddr);
+		kill_guest(cpu, "Bad address %#lx", vaddr);
 
-	gpte = lgread(lg, gpte_addr(lg, gpgd, vaddr), pte_t);
+	gpte = lgread(cpu, gpte_addr(gpgd, vaddr), pte_t);
 	if (!(pte_flags(gpte) & _PAGE_PRESENT))
-		kill_guest(lg, "Bad address %#lx", vaddr);
+		kill_guest(cpu, "Bad address %#lx", vaddr);
 
 	return pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK);
 }
@@ -399,7 +399,7 @@ static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
 /*H:435 And this is us, creating the new page directory.  If we really do
  * allocate a new one (and so the kernel parts are not there), we set
  * blank_pgdir. */
-static unsigned int new_pgdir(struct lguest *lg,
+static unsigned int new_pgdir(struct lg_cpu *cpu,
 			      unsigned long gpgdir,
 			      int *blank_pgdir)
 {
@@ -407,22 +407,23 @@ static unsigned int new_pgdir(struct lguest *lg,
 
 	/* We pick one entry at random to throw out.  Choosing the Least
 	 * Recently Used might be better, but this is easy. */
-	next = random32() % ARRAY_SIZE(lg->pgdirs);
+	next = random32() % ARRAY_SIZE(cpu->lg->pgdirs);
 	/* If it's never been allocated at all before, try now. */
-	if (!lg->pgdirs[next].pgdir) {
-		lg->pgdirs[next].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);
+	if (!cpu->lg->pgdirs[next].pgdir) {
+		cpu->lg->pgdirs[next].pgdir =
+					(pgd_t *)get_zeroed_page(GFP_KERNEL);
 		/* If the allocation fails, just keep using the one we have */
-		if (!lg->pgdirs[next].pgdir)
-			next = lg->pgdidx;
+		if (!cpu->lg->pgdirs[next].pgdir)
+			next = cpu->cpu_pgd;
 		else
 			/* This is a blank page, so there are no kernel
 			 * mappings: caller must map the stack! */
 			*blank_pgdir = 1;
 	}
 	/* Record which Guest toplevel this shadows. */
-	lg->pgdirs[next].gpgdir = gpgdir;
+	cpu->lg->pgdirs[next].gpgdir = gpgdir;
 	/* Release all the non-kernel mappings. */
-	flush_user_mappings(lg, next);
+	flush_user_mappings(cpu->lg, next);
 
 	return next;
 }
@@ -432,21 +433,21 @@ static unsigned int new_pgdir(struct lguest *lg,
  * Now we've seen all the page table setting and manipulation, let's see what
  * what happens when the Guest changes page tables (ie. changes the top-level
  * pgdir).  This occurs on almost every context switch. */
-void guest_new_pagetable(struct lguest *lg, unsigned long pgtable)
+void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable)
 {
 	int newpgdir, repin = 0;
 
 	/* Look to see if we have this one already. */
-	newpgdir = find_pgdir(lg, pgtable);
+	newpgdir = find_pgdir(cpu->lg, pgtable);
 	/* If not, we allocate or mug an existing one: if it's a fresh one,
 	 * repin gets set to 1. */
-	if (newpgdir == ARRAY_SIZE(lg->pgdirs))
-		newpgdir = new_pgdir(lg, pgtable, &repin);
+	if (newpgdir == ARRAY_SIZE(cpu->lg->pgdirs))
+		newpgdir = new_pgdir(cpu, pgtable, &repin);
 	/* Change the current pgd index to the new one. */
-	lg->pgdidx = newpgdir;
+	cpu->cpu_pgd = newpgdir;
 	/* If it was completely blank, we map in the Guest kernel stack */
 	if (repin)
-		pin_stack_pages(lg);
+		pin_stack_pages(cpu);
 }
 
 /*H:470 Finally, a routine which throws away everything: all PGD entries in all
@@ -468,11 +469,11 @@ static void release_all_pagetables(struct lguest *lg)
  * mapping.  Since kernel mappings are in every page table, it's easiest to
  * throw them all away.  This traps the Guest in amber for a while as
  * everything faults back in, but it's rare. */
-void guest_pagetable_clear_all(struct lguest *lg)
+void guest_pagetable_clear_all(struct lg_cpu *cpu)
 {
-	release_all_pagetables(lg);
+	release_all_pagetables(cpu->lg);
 	/* We need the Guest kernel stack mapped again. */
-	pin_stack_pages(lg);
+	pin_stack_pages(cpu);
 }
 /*:*/
 /*M:009 Since we throw away all mappings when a kernel mapping changes, our
@@ -497,24 +498,24 @@ void guest_pagetable_clear_all(struct lguest *lg)
  * _PAGE_ACCESSED then we can put a read-only PTE entry in immediately, and if
  * they set _PAGE_DIRTY then we can put a writable PTE entry in immediately.
  */
-static void do_set_pte(struct lguest *lg, int idx,
+static void do_set_pte(struct lg_cpu *cpu, int idx,
 		       unsigned long vaddr, pte_t gpte)
 {
 	/* Look up the matching shadow page directory entry. */
-	pgd_t *spgd = spgd_addr(lg, idx, vaddr);
+	pgd_t *spgd = spgd_addr(cpu, idx, vaddr);
 
 	/* If the top level isn't present, there's no entry to update. */
 	if (pgd_flags(*spgd) & _PAGE_PRESENT) {
 		/* Otherwise, we start by releasing the existing entry. */
-		pte_t *spte = spte_addr(lg, *spgd, vaddr);
+		pte_t *spte = spte_addr(*spgd, vaddr);
 		release_pte(*spte);
 
 		/* If they're setting this entry as dirty or accessed, we might
 		 * as well put that entry they've given us in now.  This shaves
 		 * 10% off a copy-on-write micro-benchmark. */
 		if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
-			check_gpte(lg, gpte);
-			*spte = gpte_to_spte(lg, gpte,
+			check_gpte(cpu, gpte);
+			*spte = gpte_to_spte(cpu, gpte,
 					     pte_flags(gpte) & _PAGE_DIRTY);
 		} else
 			/* Otherwise kill it and we can demand_page() it in
@@ -533,22 +534,22 @@ static void do_set_pte(struct lguest *lg, int idx,
  *
  * The benefit is that when we have to track a new page table, we can copy keep
  * all the kernel mappings.  This speeds up context switch immensely. */
-void guest_set_pte(struct lguest *lg,
+void guest_set_pte(struct lg_cpu *cpu,
 		   unsigned long gpgdir, unsigned long vaddr, pte_t gpte)
 {
 	/* Kernel mappings must be changed on all top levels.  Slow, but
 	 * doesn't happen often. */
-	if (vaddr >= lg->kernel_address) {
+	if (vaddr >= cpu->lg->kernel_address) {
 		unsigned int i;
-		for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
-			if (lg->pgdirs[i].pgdir)
-				do_set_pte(lg, i, vaddr, gpte);
+		for (i = 0; i < ARRAY_SIZE(cpu->lg->pgdirs); i++)
+			if (cpu->lg->pgdirs[i].pgdir)
+				do_set_pte(cpu, i, vaddr, gpte);
 	} else {
 		/* Is this page table one we have a shadow for? */
-		int pgdir = find_pgdir(lg, gpgdir);
-		if (pgdir != ARRAY_SIZE(lg->pgdirs))
+		int pgdir = find_pgdir(cpu->lg, gpgdir);
+		if (pgdir != ARRAY_SIZE(cpu->lg->pgdirs))
 			/* If so, do the update. */
-			do_set_pte(lg, pgdir, vaddr, gpte);
+			do_set_pte(cpu, pgdir, vaddr, gpte);
 	}
 }
 
@@ -590,30 +591,32 @@ int init_guest_pagetable(struct lguest *lg, unsigned long pgtable)
 {
 	/* We start on the first shadow page table, and give it a blank PGD
 	 * page. */
-	lg->pgdidx = 0;
-	lg->pgdirs[lg->pgdidx].gpgdir = pgtable;
-	lg->pgdirs[lg->pgdidx].pgdir = (pgd_t*)get_zeroed_page(GFP_KERNEL);
-	if (!lg->pgdirs[lg->pgdidx].pgdir)
+	lg->pgdirs[0].gpgdir = pgtable;
+	lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);
+	if (!lg->pgdirs[0].pgdir)
 		return -ENOMEM;
+	lg->cpus[0].cpu_pgd = 0;
 	return 0;
 }
 
 /* When the Guest calls LHCALL_LGUEST_INIT we do more setup. */
-void page_table_guest_data_init(struct lguest *lg)
+void page_table_guest_data_init(struct lg_cpu *cpu)
 {
 	/* We get the kernel address: above this is all kernel memory. */
-	if (get_user(lg->kernel_address, &lg->lguest_data->kernel_address)
+	if (get_user(cpu->lg->kernel_address,
+		     &cpu->lg->lguest_data->kernel_address)
 	    /* We tell the Guest that it can't use the top 4MB of virtual
 	     * addresses used by the Switcher. */
-	    || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem)
-	    || put_user(lg->pgdirs[lg->pgdidx].gpgdir,&lg->lguest_data->pgdir))
-		kill_guest(lg, "bad guest page %p", lg->lguest_data);
+	    || put_user(4U*1024*1024, &cpu->lg->lguest_data->reserve_mem)
+	    || put_user(cpu->lg->pgdirs[0].gpgdir, &cpu->lg->lguest_data->pgdir))
+		kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data);
 
 	/* In flush_user_mappings() we loop from 0 to
 	 * "pgd_index(lg->kernel_address)".  This assumes it won't hit the
 	 * Switcher mappings, so check that now. */
-	if (pgd_index(lg->kernel_address) >= SWITCHER_PGD_INDEX)
-		kill_guest(lg, "bad kernel address %#lx", lg->kernel_address);
+	if (pgd_index(cpu->lg->kernel_address) >= SWITCHER_PGD_INDEX)
+		kill_guest(cpu, "bad kernel address %#lx",
+				 cpu->lg->kernel_address);
 }
 
 /* When a Guest dies, our cleanup is fairly simple. */
@@ -634,17 +637,18 @@ void free_guest_pagetable(struct lguest *lg)
  * Guest (and not the pages for other CPUs).  We have the appropriate PTE pages
  * for each CPU already set up, we just need to hook them in now we know which
  * Guest is about to run on this CPU. */
-void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages)
+void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages)
 {
 	pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
 	pgd_t switcher_pgd;
 	pte_t regs_pte;
+	unsigned long pfn;
 
 	/* Make the last PGD entry for this Guest point to the Switcher's PTE
 	 * page for this CPU (with appropriate flags). */
-	switcher_pgd = __pgd(__pa(switcher_pte_page) | _PAGE_KERNEL);
+	switcher_pgd = __pgd(__pa(switcher_pte_page) | __PAGE_KERNEL);
 
-	lg->pgdirs[lg->pgdidx].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
+	cpu->lg->pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
 
 	/* We also change the Switcher PTE page.  When we're running the Guest,
 	 * we want the Guest's "regs" page to appear where the first Switcher
@@ -653,7 +657,8 @@ void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages)
 	 * CPU's "struct lguest_pages": if we make sure the Guest's register
 	 * page is already mapped there, we don't have to copy them out
 	 * again. */
-	regs_pte = pfn_pte (__pa(lg->regs_page) >> PAGE_SHIFT, __pgprot(_PAGE_KERNEL));
+	pfn = __pa(cpu->regs_page) >> PAGE_SHIFT;
+	regs_pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL));
 	switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTRS_PER_PTE] = regs_pte;
 }
 /*:*/
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c
index 9e189cbec7dd..ec6aa3f1c36b 100644
--- a/drivers/lguest/segments.c
+++ b/drivers/lguest/segments.c
@@ -58,7 +58,7 @@ static int ignored_gdt(unsigned int num)
  * Protection Fault in the Switcher when it restores a Guest segment register
  * which tries to use that entry.  Then we kill the Guest for causing such a
  * mess: the message will be "unhandled trap 256". */
-static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end)
+static void fixup_gdt_table(struct lg_cpu *cpu, unsigned start, unsigned end)
 {
 	unsigned int i;
 
@@ -71,14 +71,14 @@ static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end)
 		/* Segment descriptors contain a privilege level: the Guest is
 		 * sometimes careless and leaves this as 0, even though it's
 		 * running at privilege level 1.  If so, we fix it here. */
-		if ((lg->arch.gdt[i].b & 0x00006000) == 0)
-			lg->arch.gdt[i].b |= (GUEST_PL << 13);
+		if ((cpu->arch.gdt[i].b & 0x00006000) == 0)
+			cpu->arch.gdt[i].b |= (GUEST_PL << 13);
 
 		/* Each descriptor has an "accessed" bit.  If we don't set it
 		 * now, the CPU will try to set it when the Guest first loads
 		 * that entry into a segment register.  But the GDT isn't
 		 * writable by the Guest, so bad things can happen. */
-		lg->arch.gdt[i].b |= 0x00000100;
+		cpu->arch.gdt[i].b |= 0x00000100;
 	}
 }
 
@@ -109,31 +109,31 @@ void setup_default_gdt_entries(struct lguest_ro_state *state)
 
 /* This routine sets up the initial Guest GDT for booting.  All entries start
  * as 0 (unusable). */
-void setup_guest_gdt(struct lguest *lg)
+void setup_guest_gdt(struct lg_cpu *cpu)
 {
 	/* Start with full 0-4G segments... */
-	lg->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
-	lg->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
+	cpu->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
+	cpu->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
 	/* ...except the Guest is allowed to use them, so set the privilege
 	 * level appropriately in the flags. */
-	lg->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
-	lg->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
+	cpu->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
+	cpu->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
 }
 
 /*H:650 An optimization of copy_gdt(), for just the three "thead-local storage"
  * entries. */
-void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt)
+void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt)
 {
 	unsigned int i;
 
 	for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++)
-		gdt[i] = lg->arch.gdt[i];
+		gdt[i] = cpu->arch.gdt[i];
 }
 
 /*H:640 When the Guest is run on a different CPU, or the GDT entries have
  * changed, copy_gdt() is called to copy the Guest's GDT entries across to this
  * CPU's GDT. */
-void copy_gdt(const struct lguest *lg, struct desc_struct *gdt)
+void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt)
 {
 	unsigned int i;
 
@@ -141,38 +141,38 @@ void copy_gdt(const struct lguest *lg, struct desc_struct *gdt)
 	 * replaced.  See ignored_gdt() above. */
 	for (i = 0; i < GDT_ENTRIES; i++)
 		if (!ignored_gdt(i))
-			gdt[i] = lg->arch.gdt[i];
+			gdt[i] = cpu->arch.gdt[i];
 }
 
 /*H:620 This is where the Guest asks us to load a new GDT (LHCALL_LOAD_GDT).
  * We copy it from the Guest and tweak the entries. */
-void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num)
+void load_guest_gdt(struct lg_cpu *cpu, unsigned long table, u32 num)
 {
 	/* We assume the Guest has the same number of GDT entries as the
 	 * Host, otherwise we'd have to dynamically allocate the Guest GDT. */
-	if (num > ARRAY_SIZE(lg->arch.gdt))
-		kill_guest(lg, "too many gdt entries %i", num);
+	if (num > ARRAY_SIZE(cpu->arch.gdt))
+		kill_guest(cpu, "too many gdt entries %i", num);
 
 	/* We read the whole thing in, then fix it up. */
-	__lgread(lg, lg->arch.gdt, table, num * sizeof(lg->arch.gdt[0]));
-	fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->arch.gdt));
+	__lgread(cpu, cpu->arch.gdt, table, num * sizeof(cpu->arch.gdt[0]));
+	fixup_gdt_table(cpu, 0, ARRAY_SIZE(cpu->arch.gdt));
 	/* Mark that the GDT changed so the core knows it has to copy it again,
 	 * even if the Guest is run on the same CPU. */
-	lg->changed |= CHANGED_GDT;
+	cpu->changed |= CHANGED_GDT;
 }
 
 /* This is the fast-track version for just changing the three TLS entries.
  * Remember that this happens on every context switch, so it's worth
  * optimizing.  But wouldn't it be neater to have a single hypercall to cover
  * both cases? */
-void guest_load_tls(struct lguest *lg, unsigned long gtls)
+void guest_load_tls(struct lg_cpu *cpu, unsigned long gtls)
 {
-	struct desc_struct *tls = &lg->arch.gdt[GDT_ENTRY_TLS_MIN];
+	struct desc_struct *tls = &cpu->arch.gdt[GDT_ENTRY_TLS_MIN];
 
-	__lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
-	fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
+	__lgread(cpu, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
+	fixup_gdt_table(cpu, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
 	/* Note that just the TLS entries have changed. */
-	lg->changed |= CHANGED_GDT_TLS;
+	cpu->changed |= CHANGED_GDT_TLS;
 }
 /*:*/
 
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index 482aec2a9631..61f2f8eb8cad 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -60,7 +60,7 @@ static struct lguest_pages *lguest_pages(unsigned int cpu)
 		  (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
 }
 
-static DEFINE_PER_CPU(struct lguest *, last_guest);
+static DEFINE_PER_CPU(struct lg_cpu *, last_cpu);
 
 /*S:010
  * We approach the Switcher.
@@ -73,16 +73,16 @@ static DEFINE_PER_CPU(struct lguest *, last_guest);
  * since it last ran.  We saw this set in interrupts_and_traps.c and
  * segments.c.
  */
-static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
+static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages)
 {
 	/* Copying all this data can be quite expensive.  We usually run the
 	 * same Guest we ran last time (and that Guest hasn't run anywhere else
 	 * meanwhile).  If that's not the case, we pretend everything in the
 	 * Guest has changed. */
-	if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
-		__get_cpu_var(last_guest) = lg;
-		lg->last_pages = pages;
-		lg->changed = CHANGED_ALL;
+	if (__get_cpu_var(last_cpu) != cpu || cpu->last_pages != pages) {
+		__get_cpu_var(last_cpu) = cpu;
+		cpu->last_pages = pages;
+		cpu->changed = CHANGED_ALL;
 	}
 
 	/* These copies are pretty cheap, so we do them unconditionally: */
@@ -90,42 +90,42 @@ static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
 	pages->state.host_cr3 = __pa(current->mm->pgd);
 	/* Set up the Guest's page tables to see this CPU's pages (and no
 	 * other CPU's pages). */
-	map_switcher_in_guest(lg, pages);
+	map_switcher_in_guest(cpu, pages);
 	/* Set up the two "TSS" members which tell the CPU what stack to use
 	 * for traps which do directly into the Guest (ie. traps at privilege
 	 * level 1). */
-	pages->state.guest_tss.esp1 = lg->esp1;
-	pages->state.guest_tss.ss1 = lg->ss1;
+	pages->state.guest_tss.esp1 = cpu->esp1;
+	pages->state.guest_tss.ss1 = cpu->ss1;
 
 	/* Copy direct-to-Guest trap entries. */
-	if (lg->changed & CHANGED_IDT)
-		copy_traps(lg, pages->state.guest_idt, default_idt_entries);
+	if (cpu->changed & CHANGED_IDT)
+		copy_traps(cpu, pages->state.guest_idt, default_idt_entries);
 
 	/* Copy all GDT entries which the Guest can change. */
-	if (lg->changed & CHANGED_GDT)
-		copy_gdt(lg, pages->state.guest_gdt);
+	if (cpu->changed & CHANGED_GDT)
+		copy_gdt(cpu, pages->state.guest_gdt);
 	/* If only the TLS entries have changed, copy them. */
-	else if (lg->changed & CHANGED_GDT_TLS)
-		copy_gdt_tls(lg, pages->state.guest_gdt);
+	else if (cpu->changed & CHANGED_GDT_TLS)
+		copy_gdt_tls(cpu, pages->state.guest_gdt);
 
 	/* Mark the Guest as unchanged for next time. */
-	lg->changed = 0;
+	cpu->changed = 0;
 }
 
 /* Finally: the code to actually call into the Switcher to run the Guest. */
-static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
+static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages)
 {
 	/* This is a dummy value we need for GCC's sake. */
 	unsigned int clobber;
 
 	/* Copy the guest-specific information into this CPU's "struct
 	 * lguest_pages". */
-	copy_in_guest_info(lg, pages);
+	copy_in_guest_info(cpu, pages);
 
 	/* Set the trap number to 256 (impossible value).  If we fault while
 	 * switching to the Guest (bad segment registers or bug), this will
 	 * cause us to abort the Guest. */
-	lg->regs->trapnum = 256;
+	cpu->regs->trapnum = 256;
 
 	/* Now: we push the "eflags" register on the stack, then do an "lcall".
 	 * This is how we change from using the kernel code segment to using
@@ -143,7 +143,7 @@ static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
 		      * 0-th argument above, ie "a").  %ebx contains the
 		      * physical address of the Guest's top-level page
 		      * directory. */
-		     : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
+		     : "0"(pages), "1"(__pa(cpu->lg->pgdirs[cpu->cpu_pgd].pgdir))
 		     /* We tell gcc that all these registers could change,
 		      * which means we don't have to save and restore them in
 		      * the Switcher. */
@@ -161,12 +161,12 @@ static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
 
 /*H:040 This is the i386-specific code to setup and run the Guest.  Interrupts
  * are disabled: we own the CPU. */
-void lguest_arch_run_guest(struct lguest *lg)
+void lguest_arch_run_guest(struct lg_cpu *cpu)
 {
 	/* Remember the awfully-named TS bit?  If the Guest has asked to set it
 	 * we set it now, so we can trap and pass that trap to the Guest if it
 	 * uses the FPU. */
-	if (lg->ts)
+	if (cpu->ts)
 		lguest_set_ts();
 
 	/* SYSENTER is an optimized way of doing system calls.  We can't allow
@@ -180,7 +180,7 @@ void lguest_arch_run_guest(struct lguest *lg)
 	/* Now we actually run the Guest.  It will return when something
 	 * interesting happens, and we can examine its registers to see what it
 	 * was doing. */
-	run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
+	run_guest_once(cpu, lguest_pages(raw_smp_processor_id()));
 
 	/* Note that the "regs" pointer contains two extra entries which are
 	 * not really registers: a trap number which says what interrupt or
@@ -191,11 +191,11 @@ void lguest_arch_run_guest(struct lguest *lg)
 	 * bad virtual address.  We have to grab this now, because once we
 	 * re-enable interrupts an interrupt could fault and thus overwrite
 	 * cr2, or we could even move off to a different CPU. */
-	if (lg->regs->trapnum == 14)
-		lg->arch.last_pagefault = read_cr2();
+	if (cpu->regs->trapnum == 14)
+		cpu->arch.last_pagefault = read_cr2();
 	/* Similarly, if we took a trap because the Guest used the FPU,
 	 * we have to restore the FPU it expects to see. */
-	else if (lg->regs->trapnum == 7)
+	else if (cpu->regs->trapnum == 7)
 		math_state_restore();
 
 	/* Restore SYSENTER if it's supposed to be on. */
@@ -214,22 +214,22 @@ void lguest_arch_run_guest(struct lguest *lg)
  * When the Guest uses one of these instructions, we get a trap (General
  * Protection Fault) and come here.  We see if it's one of those troublesome
  * instructions and skip over it.  We return true if we did. */
-static int emulate_insn(struct lguest *lg)
+static int emulate_insn(struct lg_cpu *cpu)
 {
 	u8 insn;
 	unsigned int insnlen = 0, in = 0, shift = 0;
 	/* The eip contains the *virtual* address of the Guest's instruction:
 	 * guest_pa just subtracts the Guest's page_offset. */
-	unsigned long physaddr = guest_pa(lg, lg->regs->eip);
+	unsigned long physaddr = guest_pa(cpu, cpu->regs->eip);
 
 	/* This must be the Guest kernel trying to do something, not userspace!
 	 * The bottom two bits of the CS segment register are the privilege
 	 * level. */
-	if ((lg->regs->cs & 3) != GUEST_PL)
+	if ((cpu->regs->cs & 3) != GUEST_PL)
 		return 0;
 
 	/* Decoding x86 instructions is icky. */
-	insn = lgread(lg, physaddr, u8);
+	insn = lgread(cpu, physaddr, u8);
 
 	/* 0x66 is an "operand prefix".  It means it's using the upper 16 bits
 	   of the eax register. */
@@ -237,7 +237,7 @@ static int emulate_insn(struct lguest *lg)
 		shift = 16;
 		/* The instruction is 1 byte so far, read the next byte. */
 		insnlen = 1;
-		insn = lgread(lg, physaddr + insnlen, u8);
+		insn = lgread(cpu, physaddr + insnlen, u8);
 	}
 
 	/* We can ignore the lower bit for the moment and decode the 4 opcodes
@@ -268,26 +268,26 @@ static int emulate_insn(struct lguest *lg)
 	if (in) {
 		/* Lower bit tells is whether it's a 16 or 32 bit access */
 		if (insn & 0x1)
-			lg->regs->eax = 0xFFFFFFFF;
+			cpu->regs->eax = 0xFFFFFFFF;
 		else
-			lg->regs->eax |= (0xFFFF << shift);
+			cpu->regs->eax |= (0xFFFF << shift);
 	}
 	/* Finally, we've "done" the instruction, so move past it. */
-	lg->regs->eip += insnlen;
+	cpu->regs->eip += insnlen;
 	/* Success! */
 	return 1;
 }
 
 /*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
-void lguest_arch_handle_trap(struct lguest *lg)
+void lguest_arch_handle_trap(struct lg_cpu *cpu)
 {
-	switch (lg->regs->trapnum) {
+	switch (cpu->regs->trapnum) {
 	case 13: /* We've intercepted a General Protection Fault. */
 		/* Check if this was one of those annoying IN or OUT
 		 * instructions which we need to emulate.  If so, we just go
 		 * back into the Guest after we've done it. */
-		if (lg->regs->errcode == 0) {
-			if (emulate_insn(lg))
+		if (cpu->regs->errcode == 0) {
+			if (emulate_insn(cpu))
 				return;
 		}
 		break;
@@ -301,7 +301,8 @@ void lguest_arch_handle_trap(struct lguest *lg)
 		 *
 		 * The errcode tells whether this was a read or a write, and
 		 * whether kernel or userspace code. */
-		if (demand_page(lg, lg->arch.last_pagefault, lg->regs->errcode))
+		if (demand_page(cpu, cpu->arch.last_pagefault,
+				cpu->regs->errcode))
 			return;
 
 		/* OK, it's really not there (or not OK): the Guest needs to
@@ -311,15 +312,16 @@ void lguest_arch_handle_trap(struct lguest *lg)
 		 * Note that if the Guest were really messed up, this could
 		 * happen before it's done the LHCALL_LGUEST_INIT hypercall, so
 		 * lg->lguest_data could be NULL */
-		if (lg->lguest_data &&
-		    put_user(lg->arch.last_pagefault, &lg->lguest_data->cr2))
-			kill_guest(lg, "Writing cr2");
+		if (cpu->lg->lguest_data &&
+		    put_user(cpu->arch.last_pagefault,
+			     &cpu->lg->lguest_data->cr2))
+			kill_guest(cpu, "Writing cr2");
 		break;
 	case 7: /* We've intercepted a Device Not Available fault. */
 		/* If the Guest doesn't want to know, we already restored the
 		 * Floating Point Unit, so we just continue without telling
 		 * it. */
-		if (!lg->ts)
+		if (!cpu->ts)
 			return;
 		break;
 	case 32 ... 255:
@@ -332,19 +334,19 @@ void lguest_arch_handle_trap(struct lguest *lg)
 	case LGUEST_TRAP_ENTRY:
 		/* Our 'struct hcall_args' maps directly over our regs: we set
 		 * up the pointer now to indicate a hypercall is pending. */
-		lg->hcall = (struct hcall_args *)lg->regs;
+		cpu->hcall = (struct hcall_args *)cpu->regs;
 		return;
 	}
 
 	/* We didn't handle the trap, so it needs to go to the Guest. */
-	if (!deliver_trap(lg, lg->regs->trapnum))
+	if (!deliver_trap(cpu, cpu->regs->trapnum))
 		/* If the Guest doesn't have a handler (either it hasn't
 		 * registered any yet, or it's one of the faults we don't let
 		 * it handle), it dies with a cryptic error message. */
-		kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
-			   lg->regs->trapnum, lg->regs->eip,
-			   lg->regs->trapnum == 14 ? lg->arch.last_pagefault
-			   : lg->regs->errcode);
+		kill_guest(cpu, "unhandled trap %li at %#lx (%#lx)",
+			   cpu->regs->trapnum, cpu->regs->eip,
+			   cpu->regs->trapnum == 14 ? cpu->arch.last_pagefault
+			   : cpu->regs->errcode);
 }
 
 /* Now we can look at each of the routines this calls, in increasing order of
@@ -416,7 +418,7 @@ void __init lguest_arch_host_init(void)
 		/* We know where we want the stack to be when the Guest enters
 		 * the switcher: in pages->regs.  The stack grows upwards, so
 		 * we start it at the end of that structure. */
-		state->guest_tss.esp0 = (long)(&pages->regs + 1);
+		state->guest_tss.sp0 = (long)(&pages->regs + 1);
 		/* And this is the GDT entry to use for the stack: we keep a
 		 * couple of special LGUEST entries. */
 		state->guest_tss.ss0 = LGUEST_DS;
@@ -459,7 +461,7 @@ void __init lguest_arch_host_init(void)
 
 	/* We don't need the complexity of CPUs coming and going while we're
 	 * doing this. */
-	lock_cpu_hotplug();
+	get_online_cpus();
 	if (cpu_has_pge) { /* We have a broader idea of "global". */
 		/* Remember that this was originally set (for cleanup). */
 		cpu_had_pge = 1;
@@ -469,35 +471,35 @@ void __init lguest_arch_host_init(void)
 		/* Turn off the feature in the global feature set. */
 		clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
 	}
-	unlock_cpu_hotplug();
+	put_online_cpus();
 };
 /*:*/
 
 void __exit lguest_arch_host_fini(void)
 {
 	/* If we had PGE before we started, turn it back on now. */
-	lock_cpu_hotplug();
+	get_online_cpus();
 	if (cpu_had_pge) {
 		set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
 		/* adjust_pge's argument "1" means set PGE. */
 		on_each_cpu(adjust_pge, (void *)1, 0, 1);
 	}
-	unlock_cpu_hotplug();
+	put_online_cpus();
 }
 
 
 /*H:122 The i386-specific hypercalls simply farm out to the right functions. */
-int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args)
+int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
 {
 	switch (args->arg0) {
 	case LHCALL_LOAD_GDT:
-		load_guest_gdt(lg, args->arg1, args->arg2);
+		load_guest_gdt(cpu, args->arg1, args->arg2);
 		break;
 	case LHCALL_LOAD_IDT_ENTRY:
-		load_guest_idt_entry(lg, args->arg1, args->arg2, args->arg3);
+		load_guest_idt_entry(cpu, args->arg1, args->arg2, args->arg3);
 		break;
 	case LHCALL_LOAD_TLS:
-		guest_load_tls(lg, args->arg1);
+		guest_load_tls(cpu, args->arg1);
 		break;
 	default:
 		/* Bad Guest.  Bad! */
@@ -507,13 +509,14 @@ int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args)
 }
 
 /*H:126 i386-specific hypercall initialization: */
-int lguest_arch_init_hypercalls(struct lguest *lg)
+int lguest_arch_init_hypercalls(struct lg_cpu *cpu)
 {
 	u32 tsc_speed;
 
 	/* The pointer to the Guest's "struct lguest_data" is the only
 	 * argument.  We check that address now. */
-	if (!lguest_address_ok(lg, lg->hcall->arg1, sizeof(*lg->lguest_data)))
+	if (!lguest_address_ok(cpu->lg, cpu->hcall->arg1,
+			       sizeof(*cpu->lg->lguest_data)))
 		return -EFAULT;
 
 	/* Having checked it, we simply set lg->lguest_data to point straight
@@ -521,7 +524,7 @@ int lguest_arch_init_hypercalls(struct lguest *lg)
 	 * copy_to_user/from_user from now on, instead of lgread/write.  I put
 	 * this in to show that I'm not immune to writing stupid
 	 * optimizations. */
-	lg->lguest_data = lg->mem_base + lg->hcall->arg1;
+	cpu->lg->lguest_data = cpu->lg->mem_base + cpu->hcall->arg1;
 
 	/* We insist that the Time Stamp Counter exist and doesn't change with
 	 * cpu frequency.  Some devious chip manufacturers decided that TSC
@@ -534,12 +537,12 @@ int lguest_arch_init_hypercalls(struct lguest *lg)
 		tsc_speed = tsc_khz;
 	else
 		tsc_speed = 0;
-	if (put_user(tsc_speed, &lg->lguest_data->tsc_khz))
+	if (put_user(tsc_speed, &cpu->lg->lguest_data->tsc_khz))
 		return -EFAULT;
 
 	/* The interrupt code might not like the system call vector. */
-	if (!check_syscall_vector(lg))
-		kill_guest(lg, "bad syscall vector");
+	if (!check_syscall_vector(cpu->lg))
+		kill_guest(cpu, "bad syscall vector");
 
 	return 0;
 }
@@ -548,9 +551,9 @@ int lguest_arch_init_hypercalls(struct lguest *lg)
  *
  * Most of the Guest's registers are left alone: we used get_zeroed_page() to
  * allocate the structure, so they will be 0. */
-void lguest_arch_setup_regs(struct lguest *lg, unsigned long start)
+void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start)
 {
-	struct lguest_regs *regs = lg->regs;
+	struct lguest_regs *regs = cpu->regs;
 
 	/* There are four "segment" registers which the Guest needs to boot:
 	 * The "code segment" register (cs) refers to the kernel code segment
@@ -577,5 +580,5 @@ void lguest_arch_setup_regs(struct lguest *lg, unsigned long start)
 
 	/* There are a couple of GDT entries the Guest expects when first
 	 * booting. */
-	setup_guest_gdt(lg);
+	setup_guest_gdt(cpu);
 }
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 5ae28f076d25..7ce0ea64465c 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -854,7 +854,7 @@ adbdev_init(void)
 	adb_dev_class = class_create(THIS_MODULE, "adb");
 	if (IS_ERR(adb_dev_class))
 		return;
-	class_device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb");
+	device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), "adb");
 
 	platform_device_register(&adb_pfdev);
 	platform_driver_probe(&adb_pfdrv, adb_dummy_probe);
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 192bef5c20b3..18dde2a27209 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -563,7 +563,8 @@ static void media_bay_step(int i)
 				ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL);
 				hw.irq = bay->cd_irq;
 				hw.chipset = ide_pmac;
-				bay->cd_index = ide_register_hw(&hw, NULL, 0, NULL);
+				bay->cd_index =
+					ide_register_hw(&hw, NULL, NULL);
 				pmu_resume();
 			}
 			if (bay->cd_index == -1) {
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 63ef1f6faaed..d11821af3b8d 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -48,12 +48,10 @@
 
 #define LOG_TEMP		0			/* continously log temperature */
 
-#define I2C_DRIVERID_G4FAN	0x9001			/* fixme */
-
 static int 			do_probe( struct i2c_adapter *adapter, int addr, int kind);
 
 /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
-static unsigned short		normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+static const unsigned short	normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
 						 0x4c, 0x4d, 0x4e, 0x4f,
 						 0x2c, 0x2d, 0x2e, 0x2f,
 						 I2C_CLIENT_END };
@@ -361,7 +359,6 @@ static struct i2c_driver g4fan_driver = {
 	.driver = {
 		.name	= "therm_windtunnel",
 	},
-	.id		= I2C_DRIVERID_G4FAN,
 	.attach_adapter = do_attach,
 	.detach_client	= do_detach,
 };
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 82ec12e0edd2..ebec663d5d37 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -2482,7 +2482,7 @@ static int pmu_sys_resume(struct sys_device *sysdev)
 #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
 
 static struct sysdev_class pmu_sysclass = {
-	set_kset_name("pmu"),
+	.name = "pmu",
 };
 
 static struct sys_device device_pmu = {
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 88c0fd657825..f2d24eb3208c 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1109,7 +1109,7 @@ static void event_callback(void *context)
 	list_splice_init(&md->uevent_list, &uevents);
 	spin_unlock_irqrestore(&md->uevent_lock, flags);
 
-	dm_send_uevents(&uevents, &md->disk->kobj);
+	dm_send_uevents(&uevents, &md->disk->dev.kobj);
 
 	atomic_inc(&md->event_nr);
 	wake_up(&md->eventq);
@@ -1530,7 +1530,7 @@ out:
  *---------------------------------------------------------------*/
 void dm_kobject_uevent(struct mapped_device *md)
 {
-	kobject_uevent(&md->disk->kobj, KOBJ_CHANGE);
+	kobject_uevent(&md->disk->dev.kobj, KOBJ_CHANGE);
 }
 
 uint32_t dm_next_uevent_seq(struct mapped_device *md)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index cef9ebd5a046..c28a120b4161 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -231,7 +231,7 @@ static void mddev_put(mddev_t *mddev)
 		list_del(&mddev->all_mddevs);
 		spin_unlock(&all_mddevs_lock);
 		blk_cleanup_queue(mddev->queue);
-		kobject_unregister(&mddev->kobj);
+		kobject_put(&mddev->kobj);
 	} else
 		spin_unlock(&all_mddevs_lock);
 }
@@ -1383,22 +1383,19 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
 			return -EBUSY;
 	}
 	bdevname(rdev->bdev,b);
-	if (kobject_set_name(&rdev->kobj, "dev-%s", b) < 0)
-		return -ENOMEM;
-	while ( (s=strchr(rdev->kobj.k_name, '/')) != NULL)
+	while ( (s=strchr(b, '/')) != NULL)
 		*s = '!';
-			
+
 	rdev->mddev = mddev;
 	printk(KERN_INFO "md: bind<%s>\n", b);
 
-	rdev->kobj.parent = &mddev->kobj;
-	if ((err = kobject_add(&rdev->kobj)))
+	if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b)))
 		goto fail;
 
 	if (rdev->bdev->bd_part)
-		ko = &rdev->bdev->bd_part->kobj;
+		ko = &rdev->bdev->bd_part->dev.kobj;
 	else
-		ko = &rdev->bdev->bd_disk->kobj;
+		ko = &rdev->bdev->bd_disk->dev.kobj;
 	if ((err = sysfs_create_link(&rdev->kobj, ko, "block"))) {
 		kobject_del(&rdev->kobj);
 		goto fail;
@@ -2036,9 +2033,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
 	if (err)
 		goto abort_free;
 
-	rdev->kobj.parent = NULL;
-	rdev->kobj.ktype = &rdev_ktype;
-	kobject_init(&rdev->kobj);
+	kobject_init(&rdev->kobj, &rdev_ktype);
 
 	rdev->desc_nr = -1;
 	rdev->saved_raid_disk = -1;
@@ -3054,6 +3049,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
 	int partitioned = (MAJOR(dev) != MD_MAJOR);
 	int shift = partitioned ? MdpMinorShift : 0;
 	int unit = MINOR(dev) >> shift;
+	int error;
 
 	if (!mddev)
 		return NULL;
@@ -3082,12 +3078,13 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
 	add_disk(disk);
 	mddev->gendisk = disk;
 	mutex_unlock(&disks_mutex);
-	mddev->kobj.parent = &disk->kobj;
-	kobject_set_name(&mddev->kobj, "%s", "md");
-	mddev->kobj.ktype = &md_ktype;
-	if (kobject_register(&mddev->kobj))
+	error = kobject_init_and_add(&mddev->kobj, &md_ktype, &disk->dev.kobj,
+				     "%s", "md");
+	if (error)
 		printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
 		       disk->disk_name);
+	else
+		kobject_uevent(&mddev->kobj, KOBJ_ADD);
 	return NULL;
 }
 
@@ -3359,7 +3356,7 @@ static int do_md_run(mddev_t * mddev)
 
 	mddev->changed = 1;
 	md_new_event(mddev);
-	kobject_uevent(&mddev->gendisk->kobj, KOBJ_CHANGE);
+	kobject_uevent(&mddev->gendisk->dev.kobj, KOBJ_CHANGE);
 	return 0;
 }
 
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 1604f0490404..8f4a45346de7 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -69,11 +69,13 @@ source "drivers/media/common/Kconfig"
 config VIDEO_TUNER
 	tristate
 	depends on I2C
+	select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE
 	select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE
 	select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE
 	select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE
 	select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE
 	select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE
+	select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE
 
 menuconfig VIDEO_TUNER_CUSTOMIZE
 	bool "Customize analog tuner modules to build"
@@ -89,6 +91,13 @@ menuconfig VIDEO_TUNER_CUSTOMIZE
 
 if VIDEO_TUNER_CUSTOMIZE
 
+config TUNER_XC2028
+	tristate "XCeive xc2028/xc3028 tuners"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for the xc2028/xc3028 tuners.
+
 config TUNER_MT20XX
 	tristate "Microtune 2032 / 2050 tuners"
 	depends on I2C
@@ -97,8 +106,10 @@ config TUNER_MT20XX
 	  Say Y here to include support for the MT2032 / MT2050 tuner.
 
 config TUNER_TDA8290
-	tristate "TDA 8290+8275(a) tuner combo"
+	tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
 	depends on I2C
+	select DVB_TDA827X
+	select DVB_TDA18271
 	default m if VIDEO_TUNER_CUSTOMIZE
 	help
 	  Say Y here to include support for Philips TDA8290+8275(a) tuner.
@@ -120,10 +131,19 @@ config TUNER_TEA5767
 config TUNER_SIMPLE
 	tristate "Simple tuner support"
 	depends on I2C
+	select TUNER_TDA9887
 	default m if VIDEO_TUNER_CUSTOMIZE
 	help
 	  Say Y here to include support for various simple tuners.
 
+config TUNER_TDA9887
+	tristate "TDA 9885/6/7 analog IF demodulator"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for Philips TDA9885/6/7
+	  analog IF demodulator.
+
 endif # VIDEO_TUNER_CUSTOMIZE
 
 config VIDEOBUF_GEN
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index c5092ef1082f..06ca75911b7f 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -1,6 +1,6 @@
 config VIDEO_SAA7146
 	tristate
-	depends on I2C
+	depends on I2C && PCI
 
 config VIDEO_SAA7146_VV
 	tristate
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index e7c3ab951a44..bb2a027b9483 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -258,7 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
  * saa7134 */
 
 /* decode raw bit pattern to RC5 code */
-u32 ir_rc5_decode(unsigned int code)
+static u32 ir_rc5_decode(unsigned int code)
 {
 	unsigned int org_code = code;
 	unsigned int pair;
@@ -371,7 +371,6 @@ EXPORT_SYMBOL_GPL(ir_dump_samples);
 EXPORT_SYMBOL_GPL(ir_decode_biphase);
 EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
 
-EXPORT_SYMBOL_GPL(ir_rc5_decode);
 EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
 EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
 
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index 185e8a860c1a..a4a937c90534 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -1331,7 +1331,12 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
 	[ 0x35 ] = KEY_FASTFORWARD,
 	[ 0x36 ] = KEY_TV,
 	[ 0x37 ] = KEY_RADIO,         /* FM */
-	[ 0x38 ] = KEY_DVD
+	[ 0x38 ] = KEY_DVD,
+
+	[ 0x3e ] = KEY_F21,           /* MCE +VOL, on Y04G0033 */
+	[ 0x3a ] = KEY_F22,           /* MCE -VOL, on Y04G0033 */
+	[ 0x3b ] = KEY_F23,           /* MCE +CH,  on Y04G0033 */
+	[ 0x3f ] = KEY_F24            /* MCE -CH,  on Y04G0033 */
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_winfast);
@@ -1843,3 +1848,142 @@ IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
+
+/* Pinnacle PCTV HD 800i mini remote */
+IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE] = {
+
+	[0x0f] = KEY_1,
+	[0x15] = KEY_2,
+	[0x10] = KEY_3,
+	[0x18] = KEY_4,
+	[0x1b] = KEY_5,
+	[0x1e] = KEY_6,
+	[0x11] = KEY_7,
+	[0x21] = KEY_8,
+	[0x12] = KEY_9,
+	[0x27] = KEY_0,
+
+	[0x24] = KEY_ZOOM,
+	[0x2a] = KEY_SUBTITLE,
+
+	[0x00] = KEY_MUTE,
+	[0x01] = KEY_ENTER,	/* Pinnacle Logo */
+	[0x39] = KEY_POWER,
+
+	[0x03] = KEY_VOLUMEUP,
+	[0x09] = KEY_VOLUMEDOWN,
+	[0x06] = KEY_CHANNELUP,
+	[0x0c] = KEY_CHANNELDOWN,
+
+	[0x2d] = KEY_REWIND,
+	[0x30] = KEY_PLAYPAUSE,
+	[0x33] = KEY_FASTFORWARD,
+	[0x3c] = KEY_STOP,
+	[0x36] = KEY_RECORD,
+	[0x3f] = KEY_EPG,	/* Labeled "?" */
+};
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd);
+
+/*
+ * Igor Kuznetsov <igk72@ya.ru>
+ * Andrey J. Melnikov <temnota@kmv.ru>
+ *
+ * Keytable is used by BeholdTV 60x series, M6 series 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_behold[IR_KEYTAB_SIZE] = {
+
+	/*  0x1c            0x12  *
+	 *  TV/FM          POWER  *
+	 *                        */
+	[ 0x1c ] = KEY_TUNER,	/*XXX KEY_TV KEY_RADIO */
+	[ 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      MODE  *
+	 *                        */
+	[ 0x0a ] = KEY_AGAIN,
+	[ 0x00 ] = KEY_0,
+	[ 0x17 ] = KEY_MODE,
+
+	/*  0x14          0x10    *
+	 * ASPECT      FULLSCREEN *
+	 *                        */
+	[ 0x14 ] = KEY_SCREEN,
+	[ 0x10 ] = KEY_ZOOM,
+
+	/*          0x0b          *
+	 *           Up           *
+	 *                        *
+	 *  0x18    0x16    0x0c  *
+	 *  Left     Ok     Right *
+	 *                        *
+	 *         0x015          *
+	 *         Down           *
+	 *                        */
+	[ 0x0b ] = KEY_CHANNELUP,	/*XXX KEY_UP */
+	[ 0x18 ] = KEY_VOLUMEDOWN,	/*XXX KEY_LEFT */
+	[ 0x16 ] = KEY_OK,		/*XXX KEY_ENTER */
+	[ 0x0c ] = KEY_VOLUMEUP,	/*XXX KEY_RIGHT */
+	[ 0x15 ] = KEY_CHANNELDOWN,	/*XXX KEY_DOWN */
+
+	/*  0x11            0x0d  *
+	 *  MUTE            INFO  *
+	 *                        */
+	[ 0x11 ] = KEY_MUTE,
+	[ 0x0d ] = KEY_INFO,
+
+	/*  0x0f    0x1b    0x1a  *
+	 * RECORD PLAY/PAUSE STOP *
+	 *                        *
+	 *  0x0e    0x1f    0x1e  *
+	 *TELETEXT  AUDIO  SOURCE *
+	 *           RED   YELLOW *
+	 *                        */
+	[ 0x0f ] = KEY_RECORD,
+	[ 0x1b ] = KEY_PLAYPAUSE,
+	[ 0x1a ] = KEY_STOP,
+	[ 0x0e ] = KEY_TEXT,
+	[ 0x1f ] = KEY_RED,	/*XXX KEY_AUDIO */
+	[ 0x1e ] = KEY_YELLOW,	/*XXX KEY_SOURCE */
+
+	/*  0x1d   0x13     0x19  *
+	 * SLEEP  PREVIEW   DVB   *
+	 *         GREEN    BLUE  *
+	 *                        */
+	[ 0x1d ] = KEY_SLEEP,
+	[ 0x13 ] = KEY_GREEN,
+	[ 0x19 ] = KEY_BLUE,	/*XXX KEY_SAT */
+
+	/*  0x58           0x5c   *
+	 * FREEZE        SNAPSHOT *
+	 *                        */
+	[ 0x58 ] = KEY_SLOW,
+	[ 0x5c ] = KEY_SAVE,
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_behold);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 67d1b1b1b254..f0703d8bc3e8 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -61,7 +61,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
 	videobuf_waiton(&buf->vb,0,0);
 	videobuf_dma_unmap(q, dma);
 	videobuf_dma_free(dma);
-	buf->vb.state = STATE_NEEDS_INIT;
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 
@@ -83,7 +83,7 @@ int saa7146_buffer_queue(struct saa7146_dev *dev,
 		buf->activate(dev,buf,NULL);
 	} else {
 		list_add_tail(&buf->vb.queue,&q->queue);
-		buf->vb.state = STATE_QUEUED;
+		buf->vb.state = VIDEOBUF_QUEUED;
 		DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf));
 	}
 	return 0;
@@ -174,7 +174,7 @@ void saa7146_buffer_timeout(unsigned long data)
 	spin_lock_irqsave(&dev->slock,flags);
 	if (q->curr) {
 		DEB_D(("timeout on %p\n", q->curr));
-		saa7146_buffer_finish(dev,q,STATE_ERROR);
+		saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR);
 	}
 
 	/* we don't restart the transfer here like other drivers do. when
@@ -366,7 +366,7 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
 	}
 
 	poll_wait(file, &buf->done, wait);
-	if (buf->state == STATE_DONE || buf->state == STATE_ERROR) {
+	if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
 		DEB_D(("poll succeeded!\n"));
 		return POLLIN|POLLRDNORM;
 	}
@@ -538,6 +538,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
 	// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
 	if (video_register_device(vfd, type, -1) < 0) {
 		ERR(("cannot register v4l2 device. skipping.\n"));
+		video_device_release(vfd);
 		return -1;
 	}
 
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 6103484e4442..c32dda973e92 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -205,7 +205,7 @@ static int buffer_activate(struct saa7146_dev *dev,
 			   struct saa7146_buf *next)
 {
 	struct saa7146_vv *vv = dev->vv_data;
-	buf->vb.state = STATE_ACTIVE;
+	buf->vb.state = VIDEOBUF_ACTIVE;
 
 	DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next));
 	saa7146_set_vbi_capture(dev,buf,next);
@@ -238,7 +238,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
 	if (buf->vb.size != size)
 		saa7146_dma_free(dev,q,buf);
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
 		buf->vb.width  = llength;
@@ -257,7 +257,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
 		if (0 != err)
 			return err;
 	}
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	buf->activate = buffer_activate;
 
 	return 0;
@@ -335,7 +335,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
 	saa7146_write(dev, MC1, MASK_20);
 
 	if (vv->vbi_q.curr) {
-		saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
+		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
 	}
 
 	videobuf_queue_cancel(&fh->vbi_q);
@@ -458,7 +458,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
 		/* this must be += 2, one count for each field */
 		vv->vbi_fieldcount+=2;
 		vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;
-		saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE);
+		saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
 	} else {
 		DEB_VBI(("dev:%p\n",dev));
 	}
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index ae36d101006b..c31ab480d8e1 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1235,7 +1235,7 @@ static int buffer_activate (struct saa7146_dev *dev,
 {
 	struct saa7146_vv *vv = dev->vv_data;
 
-	buf->vb.state = STATE_ACTIVE;
+	buf->vb.state = VIDEOBUF_ACTIVE;
 	saa7146_set_capture(dev,buf,next);
 
 	mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT);
@@ -1281,7 +1281,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 		saa7146_dma_free(dev,q,buf);
 	}
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		struct saa7146_format *sfmt;
 
 		buf->vb.bytesperline  = fh->video_fmt.bytesperline;
@@ -1314,7 +1314,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 		if (err)
 			goto oops;
 	}
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	buf->activate = buffer_activate;
 
 	return 0;
@@ -1453,7 +1453,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
 
 	/* only finish the buffer if we have one... */
 	if( NULL != q->curr ) {
-		saa7146_buffer_finish(dev,q,STATE_DONE);
+		saa7146_buffer_finish(dev,q,VIDEOBUF_DONE);
 	}
 	saa7146_buffer_next(dev,q,0);
 
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 29ec4183118e..2ddafd071c97 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -212,7 +212,6 @@ void flexcop_reset_block_300(struct flexcop_device *fc)
 
 	fc->write_ibi_reg(fc,ctrl_208,v208_save);
 }
-EXPORT_SYMBOL(flexcop_reset_block_300);
 
 struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
 {
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 85e36a1d6d78..c7bbb40223f5 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -378,23 +378,37 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *
 
 EXPORT_SYMBOL(bt878_device_control);
 
+#define BROOKTREE_878_DEVICE(vend, dev, name) \
+	{ \
+		.vendor = PCI_VENDOR_ID_BROOKTREE, \
+		.device = PCI_DEVICE_ID_BROOKTREE_878, \
+		.subvendor = (vend), .subdevice = (dev), \
+		.driver_data = (unsigned long) name \
+	}
 
-static struct cards card_list[] __devinitdata = {
-
-	{ 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" },
-	{ 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" },
-	{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE,		"DViCO FusionHDTV DVB-T Lite" },
-	{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,		"Ultraview DVB-T Lite" },
-	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,	"DViCO FusionHDTV 5 Lite" },
-	{ 0x20007063, BTTV_BOARD_PC_HDTV,			"pcHDTV HD-2000 TV" },
-	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,			"DNTV Live! Mini" }
+static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
+	BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"),
+	BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"),
+	BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"),
+	BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"),
+	BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"),
+	BROOKTREE_878_DEVICE(0x270f, 0xfc00,
+				"ChainTech digitop DST-1000 DVB-S"),
+	BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"),
+	BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"),
+	BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"),
+	BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"),
+	BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"),
+	BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"),
+	{ }
 };
 
+MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
+
+static const char * __devinit card_name(const struct pci_device_id *id)
+{
+	return id->driver_data ? (const char *)id->driver_data : "Unknown";
+}
 
 /***********************/
 /* PCI device handling */
@@ -403,15 +417,13 @@ static struct cards card_list[] __devinitdata = {
 static int __devinit bt878_probe(struct pci_dev *dev,
 				 const struct pci_device_id *pci_id)
 {
-	int result = 0, has_dvb = 0, i;
+	int result = 0;
 	unsigned char lat;
 	struct bt878 *bt;
 #if defined(__powerpc__)
 	unsigned int cmd;
 #endif
 	unsigned int cardid;
-	unsigned short id;
-	struct cards *dvb_cards;
 
 	printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
 	       bt878_num);
@@ -423,25 +435,11 @@ static int __devinit bt878_probe(struct pci_dev *dev,
 	if (pci_enable_device(dev))
 		return -EIO;
 
-	pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &id);
-	cardid = id << 16;
-	pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &id);
-	cardid |= id;
-
-	for (i = 0, dvb_cards = card_list; i < ARRAY_SIZE(card_list); i++, dvb_cards++) {
-		if (cardid == dvb_cards->pci_id) {
-			printk("%s: card id=[0x%x],[ %s ] has DVB functions.\n",
-				__func__, cardid, dvb_cards->name);
-			has_dvb = 1;
-		}
-	}
+	cardid = dev->subsystem_device << 16;
+	cardid |= dev->subsystem_vendor;
 
-	if (!has_dvb) {
-		printk("%s: card id=[0x%x], Unknown card.\nExiting..\n", __func__, cardid);
-		result = -EINVAL;
-
-		goto fail0;
-	}
+	printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n",
+				__func__, cardid, card_name(pci_id));
 
 	bt = &bt878[bt878_num];
 	bt->dev = dev;
@@ -572,14 +570,6 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev)
 	return;
 }
 
-static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
-	{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BROOKTREE_878,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0,}
-};
-
-MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
-
 static struct pci_driver bt878_pci_driver = {
       .name	= "bt878",
       .id_table = bt878_pci_tbl,
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
index d593bc145628..375fd2892a11 100644
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ b/drivers/media/dvb/bt8xx/bt878.h
@@ -101,12 +101,6 @@
 #define BTTV_BOARD_DVICO_DVBT_LITE         0x80
 #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
 
-struct cards {
-	__u32 pci_id;
-	__u16 card_id;
-	char  *name;
-};
-
 extern int bt878_num;
 
 struct bt878 {
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index b7a17e69ca4d..307ff35bdf13 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -71,6 +71,7 @@ MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
 	}								\
 } while(0)
 
+static int dst_command(struct dst_state *state, u8 *data, u8 len);
 
 static void dst_packsize(struct dst_state *state, int psize)
 {
@@ -80,7 +81,8 @@ static void dst_packsize(struct dst_state *state, int psize)
 	bt878_device_control(state->bt, DST_IG_TS, &bits);
 }
 
-int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay)
+static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb,
+			 u32 outhigh, int delay)
 {
 	union dst_gpio_packet enb;
 	union dst_gpio_packet bits;
@@ -109,9 +111,8 @@ int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int
 
 	return 0;
 }
-EXPORT_SYMBOL(dst_gpio_outb);
 
-int dst_gpio_inb(struct dst_state *state, u8 *result)
+static int dst_gpio_inb(struct dst_state *state, u8 *result)
 {
 	union dst_gpio_packet rd_packet;
 	int err;
@@ -125,7 +126,6 @@ int dst_gpio_inb(struct dst_state *state, u8 *result)
 
 	return 0;
 }
-EXPORT_SYMBOL(dst_gpio_inb);
 
 int rdc_reset_state(struct dst_state *state)
 {
@@ -145,7 +145,7 @@ int rdc_reset_state(struct dst_state *state)
 }
 EXPORT_SYMBOL(rdc_reset_state);
 
-int rdc_8820_reset(struct dst_state *state)
+static int rdc_8820_reset(struct dst_state *state)
 {
 	dprintk(verbose, DST_DEBUG, 1, "Resetting DST");
 	if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) {
@@ -160,9 +160,8 @@ int rdc_8820_reset(struct dst_state *state)
 
 	return 0;
 }
-EXPORT_SYMBOL(rdc_8820_reset);
 
-int dst_pio_enable(struct dst_state *state)
+static int dst_pio_enable(struct dst_state *state)
 {
 	if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) {
 		dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !");
@@ -172,7 +171,6 @@ int dst_pio_enable(struct dst_state *state)
 
 	return 0;
 }
-EXPORT_SYMBOL(dst_pio_enable);
 
 int dst_pio_disable(struct dst_state *state)
 {
@@ -611,7 +609,7 @@ static int dst_type_print(struct dst_state *state, u8 type)
 	return 0;
 }
 
-struct tuner_types tuner_list[] = {
+static struct tuner_types tuner_list[] = {
 	{
 		.tuner_type = TUNER_TYPE_L64724,
 		.tuner_name = "L 64724",
@@ -1224,7 +1222,7 @@ static int dst_probe(struct dst_state *state)
 	return 0;
 }
 
-int dst_command(struct dst_state *state, u8 *data, u8 len)
+static int dst_command(struct dst_state *state, u8 *data, u8 len)
 {
 	u8 reply;
 
@@ -1287,7 +1285,6 @@ error:
 	return -EIO;
 
 }
-EXPORT_SYMBOL(dst_command);
 
 static int dst_get_signal(struct dst_state *state)
 {
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 87623d203a89..d88cf2add82b 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -165,10 +165,8 @@ struct dst_config
 };
 
 int rdc_reset_state(struct dst_state *state);
-int rdc_8820_reset(struct dst_state *state);
 
 int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
-int dst_pio_enable(struct dst_state *state);
 int dst_pio_disable(struct dst_state *state);
 int dst_error_recovery(struct dst_state* state);
 int dst_error_bailout(struct dst_state *state);
@@ -179,9 +177,6 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len);
 u8 dst_check_sum(u8 * buf, u32 len);
 struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
 struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
-int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay);
-
-int dst_command(struct dst_state* state, u8 * data, u8 len);
 
 
 #endif // DST_COMMON_H
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 445f02665577..925cfa6221ad 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -1202,6 +1202,10 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
 		fe->ops.tuner_ops.release(fe);
 		symbol_put_addr(fe->ops.tuner_ops.release);
 	}
+	if (fe->ops.analog_ops.release) {
+		fe->ops.analog_ops.release(fe);
+		symbol_put_addr(fe->ops.analog_ops.release);
+	}
 	ptr = (void*)fe->ops.release;
 	if (ptr) {
 		fe->ops.release(fe);
@@ -1215,6 +1219,8 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
 		fe->ops.release_sec(fe);
 	if (fe->ops.tuner_ops.release)
 		fe->ops.tuner_ops.release(fe);
+	if (fe->ops.analog_ops.release)
+		fe->ops.analog_ops.release(fe);
 	if (fe->ops.release)
 		fe->ops.release(fe);
 }
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index a5262e852c82..aa4133f0bd19 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -84,6 +84,9 @@ struct dvb_tuner_ops {
 	/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
 	int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
 
+	/** This is to allow setting tuner-specific configs */
+	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+
 	int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
 	int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
 
@@ -98,6 +101,28 @@ struct dvb_tuner_ops {
 	int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
 };
 
+struct analog_demod_info {
+	char *name;
+};
+
+struct analog_demod_ops {
+
+	struct analog_demod_info info;
+
+	void (*set_params)(struct dvb_frontend *fe,
+			   struct analog_parameters *params);
+	int  (*has_signal)(struct dvb_frontend *fe);
+	int  (*is_stereo)(struct dvb_frontend *fe);
+	int  (*get_afc)(struct dvb_frontend *fe);
+	void (*tuner_status)(struct dvb_frontend *fe);
+	void (*standby)(struct dvb_frontend *fe);
+	void (*release)(struct dvb_frontend *fe);
+	int  (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
+
+	/** This is to allow setting tuner-specific configuration */
+	int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+};
+
 struct dvb_frontend_ops {
 
 	struct dvb_frontend_info info;
@@ -143,6 +168,7 @@ struct dvb_frontend_ops {
 	int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
 
 	struct dvb_tuner_ops tuner_ops;
+	struct analog_demod_ops analog_ops;
 };
 
 #define MAX_EVENT 8
@@ -159,18 +185,19 @@ struct dvb_fe_events {
 struct dvb_frontend {
 	struct dvb_frontend_ops ops;
 	struct dvb_adapter *dvb;
-	void* demodulator_priv;
-	void* tuner_priv;
-	void* frontend_priv;
-	void* sec_priv;
+	void *demodulator_priv;
+	void *tuner_priv;
+	void *frontend_priv;
+	void *sec_priv;
+	void *analog_demod_priv;
 };
 
-extern int dvb_register_frontend(struct dvb_adapter* dvb,
-				 struct dvb_frontend* fe);
+extern int dvb_register_frontend(struct dvb_adapter *dvb,
+				 struct dvb_frontend *fe);
 
-extern int dvb_unregister_frontend(struct dvb_frontend* fe);
+extern int dvb_unregister_frontend(struct dvb_frontend *fe);
 
-extern void dvb_frontend_detach(struct dvb_frontend* fe);
+extern void dvb_frontend_detach(struct dvb_frontend *fe);
 
 extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
 
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index 9878183ba3f0..ac9d93cf83c6 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -261,11 +261,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_init);
 EXPORT_SYMBOL(dvb_ringbuffer_empty);
 EXPORT_SYMBOL(dvb_ringbuffer_free);
 EXPORT_SYMBOL(dvb_ringbuffer_avail);
-EXPORT_SYMBOL(dvb_ringbuffer_flush);
 EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
 EXPORT_SYMBOL(dvb_ringbuffer_read);
 EXPORT_SYMBOL(dvb_ringbuffer_write);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_write);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
-EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
index 7db6eee50e39..e7f76f515b4f 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -1026,6 +1026,7 @@ static int af9005_usb_probe(struct usb_interface *intf,
 static struct usb_device_id af9005_usb_table[] = {
 	{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
 	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+	{USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)},
 	{0},
 };
 
@@ -1075,7 +1076,7 @@ static struct dvb_usb_device_properties af9005_properties = {
 	.rc_key_map_size = 0,
 	.rc_query = af9005_rc_query,
 
-	.num_device_descs = 2,
+	.num_device_descs = 3,
 	.devices = {
 		    {.name = "Afatech DVB-T USB1.1 stick",
 		     .cold_ids = {&af9005_usb_table[0], NULL},
@@ -1085,6 +1086,10 @@ static struct dvb_usb_device_properties af9005_properties = {
 		     .cold_ids = {&af9005_usb_table[1], NULL},
 		     .warm_ids = {NULL},
 		     },
+		    {.name = "Ansonic DVB-T USB1.1 stick",
+		     .cold_ids = {&af9005_usb_table[2], NULL},
+		     .warm_ids = {NULL},
+		     },
 		    {NULL},
 		    }
 };
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
index 18e0b16fb2a9..f3ff81314696 100644
--- a/drivers/media/dvb/dvb-usb/au6610.c
+++ b/drivers/media/dvb/dvb-usb/au6610.c
@@ -79,12 +79,12 @@ static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i;
 
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
 	if (num > 2)
 		return -EINVAL;
 
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
 	for (i = 0; i < num; i++) {
 		/* write/read request */
 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 04e31cf7d530..c58365005ac1 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -15,7 +15,7 @@
  *
  * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
  * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org)
- * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au)
+ * Copyright (C) 2006, 2007 Chris 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
@@ -30,11 +30,16 @@
 #include "mt352.h"
 #include "mt352_priv.h"
 #include "zl10353.h"
+#include "tuner-xc2028.h"
+#include "tuner-xc2028-types.h"
 
 /* debug */
-int dvb_usb_cxusb_debug;
+static int dvb_usb_cxusb_debug;
 module_param_named(debug, dvb_usb_cxusb_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
+#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
+				dprintk(dvb_usb_cxusb_debug,0x01,args)
 
 static int cxusb_ctrl_msg(struct dvb_usb_device *d,
 			  u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
@@ -46,11 +51,9 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d,
 	sndbuf[0] = cmd;
 	memcpy(&sndbuf[1], wbuf, wlen);
 	if (wo)
-		dvb_usb_generic_write(d, sndbuf, 1+wlen);
+		return dvb_usb_generic_write(d, sndbuf, 1+wlen);
 	else
-		dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
-
-	return 0;
+		return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
 }
 
 /* GPIO */
@@ -72,6 +75,34 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff)
 	st->gpio_write_state[GPIO_TUNER] = onoff;
 }
 
+static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask,
+				 u8 newval)
+{
+	u8 o[2], gpio_state;
+	int rc;
+
+	o[0] = 0xff & ~changemask;	/* mask of bits to keep */
+	o[1] = newval & changemask;	/* new values for bits  */
+
+	rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1);
+	if (rc < 0 || (gpio_state & changemask) != (newval & changemask))
+		deb_info("bluebird_gpio_write failed.\n");
+
+	return rc < 0 ? rc : gpio_state;
+}
+
+static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low)
+{
+	cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin);
+	msleep(5);
+	cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0);
+}
+
+static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff)
+{
+	cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40);
+}
+
 /* I2C */
 static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 			  int num)
@@ -82,9 +113,6 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
 
-	if (num > 2)
-		warn("more than two i2c messages at a time is not handled yet. TODO.");
-
 	for (i = 0; i < num; i++) {
 
 		if (d->udev->descriptor.idVendor == USB_VID_MEDION)
@@ -97,8 +125,22 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 				break;
 			}
 
-		/* read request */
-		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+		if (msg[i].flags & I2C_M_RD) {
+			/* read only */
+			u8 obuf[3], ibuf[1+msg[i].len];
+			obuf[0] = 0;
+			obuf[1] = msg[i].len;
+			obuf[2] = msg[i].addr;
+			if (cxusb_ctrl_msg(d, CMD_I2C_READ,
+					   obuf, 3,
+					   ibuf, 1+msg[i].len) < 0) {
+				warn("i2c read failed");
+				break;
+			}
+			memcpy(msg[i].buf, &ibuf[1], msg[i].len);
+		} else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) &&
+			   msg[i].addr == msg[i+1].addr) {
+			/* write to then read from same address */
 			u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
 			obuf[0] = msg[i].len;
 			obuf[1] = msg[i+1].len;
@@ -116,7 +158,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 			memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
 
 			i++;
-		} else { /* write */
+		} else {
+			/* write only */
 			u8 obuf[2+msg[i].len], ibuf;
 			obuf[0] = msg[i].addr;
 			obuf[1] = msg[i].len;
@@ -131,7 +174,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 	}
 
 	mutex_unlock(&d->i2c_mutex);
-	return i;
+	return i == num ? num : -EREMOTEIO;
 }
 
 static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
@@ -162,6 +205,17 @@ static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
 		return 0;
 }
 
+static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+	int rc = 0;
+
+	rc = cxusb_power_ctrl(d, onoff);
+	if (!onoff)
+		cxusb_nano2_led(d, 0);
+
+	return rc;
+}
+
 static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
 	u8 buf[2] = { 0x03, 0x00 };
@@ -197,6 +251,34 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 	return 0;
 }
 
+static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
+				    int *state)
+{
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	u8 ircode[4];
+	int i;
+	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
+			       .buf = ircode, .len = 4 };
+
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+
+	if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
+		return 0;
+
+	for (i = 0; i < d->props.rc_key_map_size; i++) {
+		if (keymap[i].custom == ircode[1] &&
+		    keymap[i].data == ircode[2]) {
+			*event = keymap[i].event;
+			*state = REMOTE_KEY_PRESSED;
+
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
 static struct dvb_usb_rc_key dvico_mce_rc_keys[] = {
 	{ 0xfe, 0x02, KEY_TV },
 	{ 0xfe, 0x0e, KEY_MP3 },
@@ -351,6 +433,20 @@ static struct mt352_config cxusb_mt352_config = {
 	.demod_init    = cxusb_mt352_demod_init,
 };
 
+static struct zl10353_config cxusb_zl10353_xc3028_config = {
+	.demod_address = 0x0f,
+	.if2 = 45600,
+	.no_tuner = 1,
+	.parallel_ts = 1,
+};
+
+static struct mt352_config cxusb_mt352_xc3028_config = {
+	.demod_address = 0x0f,
+	.if2 = 4560,
+	.no_tuner = 1,
+	.demod_init = cxusb_mt352_demod_init,
+};
+
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
@@ -386,6 +482,51 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
 	return 0;
 }
 
+static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
+{
+	struct dvb_usb_device *d = ptr;
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		deb_info("%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+		cxusb_bluebird_gpio_pulse(d, 0x01, 1);
+		break;
+	case XC2028_RESET_CLK:
+		deb_info("%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+		break;
+	default:
+		deb_info("%s: unknown command %d, arg %d\n", __FUNCTION__,
+			 command, arg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dvb_frontend	 *fe;
+	struct xc2028_config	  cfg = {
+		.i2c_adap  = &adap->dev->i2c_adap,
+		.i2c_addr  = 0x61,
+		.video_dev = adap->dev,
+		.callback  = dvico_bluebird_xc2028_callback,
+	};
+	static struct xc2028_ctrl ctl = {
+		.fname       = "xc3028-dvico-au-01.fw",
+		.max_len     = 64,
+		.scode_table = ZARLINK456,
+	};
+
+	fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
+	if (fe == NULL || fe->ops.tuner_ops.set_config == NULL)
+		return -EIO;
+
+	fe->ops.tuner_ops.set_config(fe, &ctl);
+
+	return 0;
+}
+
 static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	u8 b;
@@ -447,27 +588,120 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
 	return -EIO;
 }
 
+static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	u8 ircode[4];
+	int i;
+	struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
+			       .buf = ircode, .len = 4 };
+
+	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	/* reset the tuner and demodulator */
+	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+	if ((adap->fe = dvb_attach(zl10353_attach,
+				   &cxusb_zl10353_xc3028_config,
+				   &adap->dev->i2c_adap)) == NULL)
+		return -EIO;
+
+	/* try to determine if there is no IR decoder on the I2C bus */
+	for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) {
+		msleep(20);
+		if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
+			goto no_IR;
+		if (ircode[0] == 0 && ircode[1] == 0)
+			continue;
+		if (ircode[2] + ircode[3] != 0xff) {
+no_IR:
+			adap->dev->props.rc_key_map = NULL;
+			info("No IR receiver detected on this device.");
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
+		err("set interface failed");
+
+	cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
+
+	/* reset the tuner and demodulator */
+	cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1);
+	cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
+
+	if ((adap->fe = dvb_attach(zl10353_attach,
+				   &cxusb_zl10353_xc3028_config,
+				   &adap->dev->i2c_adap)) != NULL)
+		return 0;
+
+	if ((adap->fe = dvb_attach(mt352_attach,
+				   &cxusb_mt352_xc3028_config,
+				   &adap->dev->i2c_adap)) != NULL)
+		return 0;
+
+	return -EIO;
+}
+
+/*
+ * DViCO has shipped two devices with the same USB ID, but only one of them
+ * needs a firmware download.  Check the device class details to see if they
+ * have non-default values to decide whether the device is actually cold or
+ * not, and forget a match if it turns out we selected the wrong device.
+ */
+static int bluebird_fx2_identify_state(struct usb_device *udev,
+				       struct dvb_usb_device_properties *props,
+				       struct dvb_usb_device_description **desc,
+				       int *cold)
+{
+	int wascold = *cold;
+
+	*cold = udev->descriptor.bDeviceClass == 0xff &&
+		udev->descriptor.bDeviceSubClass == 0xff &&
+		udev->descriptor.bDeviceProtocol == 0xff;
+
+	if (*cold && !wascold)
+		*desc = NULL;
+
+	return 0;
+}
+
 /*
  * DViCO bluebird firmware needs the "warm" product ID to be patched into the
  * firmware file before download.
  */
 
-#define BLUEBIRD_01_ID_OFFSET 6638
+static const int dvico_firmware_id_offsets[] = { 6638, 3204 };
 static int bluebird_patch_dvico_firmware_download(struct usb_device *udev,
 						  const struct firmware *fw)
 {
-	if (fw->size < BLUEBIRD_01_ID_OFFSET + 4)
-		return -EINVAL;
+	int pos;
+
+	for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) {
+		int idoff = dvico_firmware_id_offsets[pos];
 
-	if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) &&
-	    fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) {
+		if (fw->size < idoff + 4)
+			continue;
 
-		fw->data[BLUEBIRD_01_ID_OFFSET + 2] =
-			le16_to_cpu(udev->descriptor.idProduct) + 1;
-		fw->data[BLUEBIRD_01_ID_OFFSET + 3] =
-			le16_to_cpu(udev->descriptor.idProduct) >> 8;
+		if (fw->data[idoff] == (USB_VID_DVICO & 0xff) &&
+		    fw->data[idoff + 1] == USB_VID_DVICO >> 8) {
+			fw->data[idoff + 2] =
+				le16_to_cpu(udev->descriptor.idProduct) + 1;
+			fw->data[idoff + 3] =
+				le16_to_cpu(udev->descriptor.idProduct) >> 8;
 
-		return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
+			return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2);
+		}
 	}
 
 	return -EINVAL;
@@ -479,6 +713,9 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
 static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
 
 static int cxusb_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
@@ -487,7 +724,10 @@ static int cxusb_probe(struct usb_interface *intf,
 		dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) {
+		dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&cxusb_bluebird_nano2_needsfirmware_properties,THIS_MODULE,NULL) == 0) {
 		return 0;
 	}
 
@@ -508,6 +748,9 @@ static struct usb_device_id cxusb_table [] = {
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
 	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
+	{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
 	{}		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -766,6 +1009,151 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
 	}
 };
 
+static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_dualdig4_frontend_attach,
+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = dvico_mce_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(dvico_mce_rc_keys),
+	.rc_query         = cxusb_bluebird2_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T Dual Digital 4",
+			{ NULL },
+			{ &cxusb_table[13], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl         = CYPRESS_FX2,
+	.identify_state   = bluebird_fx2_identify_state,
+
+	.size_of_priv     = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_nano2_frontend_attach,
+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_nano2_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = dvico_portable_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+	.rc_query         = cxusb_bluebird2_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T NANO2",
+			{ NULL },
+			{ &cxusb_table[14], NULL },
+		},
+	}
+};
+
+static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl          = DEVICE_SPECIFIC,
+	.firmware          = "dvb-usb-bluebird-02.fw",
+	.download_firmware = bluebird_patch_dvico_firmware_download,
+	.identify_state    = bluebird_fx2_identify_state,
+
+	.size_of_priv      = sizeof(struct cxusb_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		{
+			.streaming_ctrl   = cxusb_streaming_ctrl,
+			.frontend_attach  = cxusb_nano2_frontend_attach,
+			.tuner_attach     = cxusb_dvico_xc3028_tuner_attach,
+			/* parameter for the MPEG2-data transfer */
+			.stream = {
+				.type = USB_BULK,
+				.count = 5,
+				.endpoint = 0x02,
+				.u = {
+					.bulk = {
+						.buffersize = 8192,
+					}
+				}
+			},
+		},
+	},
+
+	.power_ctrl       = cxusb_nano2_power_ctrl,
+
+	.i2c_algo         = &cxusb_i2c_algo,
+
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.rc_interval      = 100,
+	.rc_key_map       = dvico_portable_rc_keys,
+	.rc_key_map_size  = ARRAY_SIZE(dvico_portable_rc_keys),
+	.rc_query         = cxusb_rc_query,
+
+	.num_device_descs = 1,
+	.devices = {
+		{   "DViCO FusionHDTV DVB-T NANO2 w/o firmware",
+			{ &cxusb_table[14], NULL },
+			{ &cxusb_table[15], NULL },
+		},
+	}
+};
+
 static struct usb_driver cxusb_driver = {
 	.name		= "dvb_usb_cxusb",
 	.probe		= cxusb_probe,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
index c8ef77554b00..4768a2c35517 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.h
+++ b/drivers/media/dvb/dvb-usb/cxusb.h
@@ -4,12 +4,9 @@
 #define DVB_USB_LOG_PREFIX "cxusb"
 #include "dvb-usb.h"
 
-extern int dvb_usb_cxusb_debug;
-#define deb_info(args...)   dprintk(dvb_usb_cxusb_debug,0x01,args)
-#define deb_i2c(args...)    if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
-				dprintk(dvb_usb_cxusb_debug,0x01,args)
-
 /* usb commands - some of it are guesses, don't have a reference yet */
+#define CMD_BLUEBIRD_GPIO_RW 0x05
+
 #define CMD_I2C_WRITE     0x08
 #define CMD_I2C_READ      0x09
 
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 3ea294eb96bd..c9857d5c6982 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -243,7 +243,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 	u8 b[4];
 
 	b[0] = REQUEST_ENABLE_VIDEO;
-	b[1] = 0x00;
+	b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
 	b[2] = (0x01 << 4); /* Master mode */
 	b[3] = 0x00;
 
@@ -256,9 +256,6 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 
 	b[2] |= st->channel_state;
 
-	if (st->channel_state) /* if at least one channel is active */
-		b[1] = (0x01 << 4) | 0x00;
-
 	deb_info("data for streaming: %x %x\n",b[1],b[2]);
 
 	return dib0700_ctrl_wr(adap->dev, b, 4);
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 58452b52002c..e7093826e975 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -94,12 +94,28 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
 		(10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
 }
 
+static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = 0x50, .flags = 0,        .buf = &adrs, .len = 1 },
+		{ .addr = 0x50, .flags = I2C_M_RD, .buf = pval,  .len = 1 },
+	};
+	if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO;
+	return 0;
+}
+
 static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	struct dib0700_state *st = adap->dev->priv;
+	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
 	struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
-	return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id],
-		st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
+	s8 a;
+	int if1=1220;
+	if (adap->dev->udev->descriptor.idVendor  == USB_VID_HAUPPAUGE &&
+		adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_500_2) {
+		if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a;
+	}
+	return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id],
+		if1) == NULL ? -ENODEV : 0;
 }
 
 /* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
@@ -230,6 +246,27 @@ static struct mt2266_config stk7700d_mt2266_config[2] = {
 	}
 };
 
+static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (adap->id == 0) {
+		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+		msleep(10);
+		dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config);
+	}
+
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
+				&stk7700d_dib7000p_mt2266_config[adap->id]);
+
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
 static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	if (adap->id == 0) {
@@ -415,6 +452,35 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = {
 	{ 0x1e, 0x38, KEY_YELLOW },
 	{ 0x1e, 0x3b, KEY_GOTO },
 	{ 0x1e, 0x3d, KEY_POWER },
+
+	/* Key codes for the Leadtek Winfast DTV Dongle */
+	{ 0x00, 0x42, KEY_POWER },
+	{ 0x07, 0x7c, KEY_TUNER },
+	{ 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */
+	{ 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/
+	{ 0x0f, 0x71, KEY_DOT }, /* frequency */
+	{ 0x07, 0x43, KEY_0 },
+	{ 0x0c, 0x41, KEY_1 },
+	{ 0x04, 0x43, KEY_2 },
+	{ 0x0b, 0x7f, KEY_3 },
+	{ 0x0e, 0x41, KEY_4 },
+	{ 0x06, 0x43, KEY_5 },
+	{ 0x09, 0x7f, KEY_6 },
+	{ 0x0d, 0x7e, KEY_7 },
+	{ 0x05, 0x7c, KEY_8 },
+	{ 0x0a, 0x40, KEY_9 },
+	{ 0x0e, 0x4e, KEY_CLEAR },
+	{ 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */
+	{ 0x0f, 0x41, KEY_LAST }, /* recall */
+	{ 0x03, 0x42, KEY_MUTE },
+	{ 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/
+	{ 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */
+	{ 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
+	{ 0x0b, 0x70, KEY_RECORD },
+	{ 0x03, 0x7d, KEY_VOLUMEUP },
+	{ 0x01, 0x7d, KEY_VOLUMEDOWN },
+	{ 0x02, 0x42, KEY_CHANNELUP },
+	{ 0x00, 0x7d, KEY_CHANNELDOWN },
 };
 
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
@@ -578,16 +644,22 @@ static struct mt2060_config stk7700p_mt2060_config = {
 
 static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
 {
+	struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
 	struct dib0700_state *st = adap->dev->priv;
 	struct i2c_adapter *tun_i2c;
-
+	s8 a;
+	int if1=1220;
+	if (adap->dev->udev->descriptor.idVendor  == USB_VID_HAUPPAUGE &&
+		adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_STICK) {
+		if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
+	}
 	if (st->is_dib7000pc)
 		tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
 	else
 		tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
 
 	return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config,
-		st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
+		if1) == NULL ? -ENODEV : 0;
 }
 
 /* DIB7070 generic */
@@ -709,6 +781,8 @@ static struct dib7000p_config dib7070p_dib7000p_config = {
 	.agc_config_count = 1,
 	.agc = &dib7070_agc_config,
 	.bw  = &dib7070_bw_config_12_mhz,
+	.tuner_is_baseband = 1,
+	.spur_protect = 1,
 
 	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
 	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
@@ -748,6 +822,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
 		.agc_config_count = 1,
 		.agc = &dib7070_agc_config,
 		.bw  = &dib7070_bw_config_12_mhz,
+		.tuner_is_baseband = 1,
+		.spur_protect = 1,
 
 		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
 		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
@@ -760,6 +836,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
 		.agc_config_count = 1,
 		.agc = &dib7070_agc_config,
 		.bw  = &dib7070_bw_config_12_mhz,
+		.tuner_is_baseband = 1,
+		.spur_protect = 1,
 
 		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
 		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
@@ -821,6 +899,12 @@ struct usb_device_id dib0700_usb_id_table[] = {
 		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
 		{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500_PC) },
 /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
+		{ USB_DEVICE(USB_VID_GIGABYTE,  USB_PID_GIGABYTE_U7000) },
+		{ USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
+		{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3000) },
+		{ USB_DEVICE(USB_VID_ASUS,      USB_PID_ASUS_U3100) },
+/* 25 */	{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
+		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
 		{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -862,7 +946,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			},
 		},
 
-		.num_device_descs = 7,
+		.num_device_descs = 8,
 		.devices = {
 			{   "DiBcom STK7700P reference design",
 				{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
@@ -891,6 +975,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{   "AVerMedia AVerTV DVB-T Express",
 				{ &dib0700_usb_id_table[20] },
 				{ NULL },
+			},
+			{   "Gigabyte U7000",
+				{ &dib0700_usb_id_table[21], NULL },
+				{ NULL },
 			}
 		},
 
@@ -961,7 +1049,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{   "DiBcom STK7700D reference design",
 				{ &dib0700_usb_id_table[14], NULL },
 				{ NULL },
-			},
+			}
 		},
 
 		.rc_interval      = DEFAULT_RC_INTERVAL,
@@ -974,6 +1062,25 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 		.num_adapters = 1,
 		.adapter = {
 			{
+				.frontend_attach  = stk7700P2_frontend_attach,
+				.tuner_attach     = stk7700d_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			},
+		},
+
+		.num_device_descs = 1,
+		.devices = {
+			{   "ASUS My Cinema U3000 Mini DVBT Tuner",
+				{ &dib0700_usb_id_table[23], NULL },
+				{ NULL },
+			},
+		}
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 1,
+		.adapter = {
+			{
 				.frontend_attach  = stk7070p_frontend_attach,
 				.tuner_attach     = dib7070p_tuner_attach,
 
@@ -983,7 +1090,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			},
 		},
 
-		.num_device_descs = 2,
+		.num_device_descs = 6,
 		.devices = {
 			{   "DiBcom STK7070P reference design",
 				{ &dib0700_usb_id_table[15], NULL },
@@ -993,7 +1100,29 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 				{ &dib0700_usb_id_table[16], NULL },
 				{ NULL },
 			},
-		}
+			{   "Artec T14BR DVB-T",
+				{ &dib0700_usb_id_table[22], NULL },
+				{ NULL },
+			},
+			{   "ASUS My Cinema U3100 Mini DVBT Tuner",
+				{ &dib0700_usb_id_table[24], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-T Stick",
+				{ &dib0700_usb_id_table[25], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-T MyTV.t",
+				{ &dib0700_usb_id_table[26], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = dib0700_rc_keys,
+		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_query         = dib0700_rc_query
+
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 2,
@@ -1024,7 +1153,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
 				{ &dib0700_usb_id_table[18], NULL },
 				{ NULL },
-			},
+			}
 		}
 	},
 };
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index bca1e0905739..3acbda4aa27e 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -17,9 +17,10 @@
 #include "nxt6000.h"
 
 /* debug */
-int dvb_usb_digitv_debug;
+static int dvb_usb_digitv_debug;
 module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
 
 static int digitv_ctrl_msg(struct dvb_usb_device *d,
 		u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h
index 8b43e3db8691..908c09f4966b 100644
--- a/drivers/media/dvb/dvb-usb/digitv.h
+++ b/drivers/media/dvb/dvb-usb/digitv.h
@@ -8,9 +8,6 @@ struct digitv_state {
     int is_nxt6000;
 };
 
-extern int dvb_usb_digitv_debug;
-#define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
-
 /* protocol (from usblogging and the SDK:
  *
  * Always 7 bytes bulk message(s) for controlling
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 4fa3e895028a..aa4844ef875e 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -15,7 +15,9 @@
 #define USB_VID_ALCOR_MICRO			0x058f
 #define USB_VID_ALINK				0x05e3
 #define USB_VID_ANCHOR				0x0547
+#define USB_VID_ANSONIC				0x10b9
 #define USB_VID_ANUBIS_ELECTRONIC		0x10fd
+#define USB_VID_ASUS				0x0b05
 #define USB_VID_AVERMEDIA			0x07ca
 #define USB_VID_COMPRO				0x185b
 #define USB_VID_COMPRO_UNK			0x145f
@@ -44,12 +46,16 @@
 #define USB_VID_ULTIMA_ELECTRONIC		0x05d8
 #define USB_VID_UNIWILL				0x1584
 #define USB_VID_WIDEVIEW			0x14aa
+/* dom : pour gigabyte u7000 */
+#define USB_VID_GIGABYTE			0x1044
+
 
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD			0xa333
 #define USB_PID_ADSTECH_USB2_WARM			0xa334
 #define USB_PID_AFATECH_AF9005				0x9020
 #define USB_VID_ALINK_DTU				0xf170
+#define USB_PID_ANSONIC_DVBT_USB			0x6000
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
@@ -69,6 +75,7 @@
 #define USB_PID_DIBCOM_STK7700P				0x1e14
 #define USB_PID_DIBCOM_STK7700P_PC			0x1e78
 #define USB_PID_DIBCOM_STK7700D				0x1ef0
+#define USB_PID_DIBCOM_STK7700_U7000			0x7001
 #define USB_PID_DIBCOM_STK7070P				0x1ebc
 #define USB_PID_DIBCOM_STK7070PD			0x1ebe
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD			0x2131
@@ -99,6 +106,7 @@
 #define USB_PID_ULTIMA_TVBOX_USB2_WARM			0x810a
 #define USB_PID_ARTEC_T14_COLD				0x810b
 #define USB_PID_ARTEC_T14_WARM				0x810c
+#define USB_PID_ARTEC_T14BR				0x810f
 #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD		0x8613
 #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM		0x1002
 #define USB_PID_UNK_HYPER_PALTEK_COLD			0x005e
@@ -120,6 +128,8 @@
 #define USB_PID_HAUPPAUGE_NOVA_T_500_2			0x9950
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK			0x7050
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2		0x7060
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3		0x7070
+#define USB_PID_HAUPPAUGE_MYTV_T			0x7080
 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK			0x9580
 #define USB_PID_AVERMEDIA_EXPRESS			0xb568
 #define USB_PID_AVERMEDIA_VOLAR				0xa807
@@ -143,6 +153,9 @@
 #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM		0xdb51
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD		0xdb58
 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM		0xdb59
+#define USB_PID_DVICO_BLUEBIRD_DUAL_4			0xdb78
+#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2		0xdb70
+#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM	0xdb71
 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD		0xdb54
 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM		0xdb55
 #define USB_PID_MEDION_MD95700				0x0932
@@ -170,6 +183,9 @@
 #define USB_PID_OPERA1_WARM				0x3829
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD		0x0514
 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM		0x0513
-
+/* dom pour gigabyte u7000 */
+#define USB_PID_GIGABYTE_U7000				0x7001
+#define USB_PID_ASUS_U3000				0x171f
+#define USB_PID_ASUS_U3100				0x173f
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index f01d99c1c43c..6b99d9f4d5b3 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -56,12 +56,12 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i;
 
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-		return -EAGAIN;
-
 	if (num > 2)
 		return -EINVAL;
 
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
 	for (i = 0; i < num; i++) {
 		/* write/read request */
 		if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index 92147ee3e14f..83e8535014c6 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -171,22 +171,6 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
 	return 0;
 }
 
-int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
-{
-	u8 buf;
-	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
-	/* Turn off 8psk power */
-	if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
-		return -EINVAL;
-	/* Turn On 8psk power */
-	if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
-		return -EINVAL;
-	/* load BCM4500 firmware */
-	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
-		if (gp8psk_load_bcm4500fw(d))
-			return EINVAL;
-	return 0;
-}
 
 static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
index e83a57506cfa..e5cd8149c23d 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.h
+++ b/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -92,6 +92,5 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
 extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
 extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
 			     u16 index, u8 *b, int blen);
-extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index d7c04951ceab..21935bf7059e 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -10,7 +10,9 @@
 * see Documentation/dvb/README.dvb-usb for more information
 */
 
-#include "opera1.h"
+#define DVB_USB_LOG_PREFIX "opera"
+
+#include "dvb-usb.h"
 #include "stv0299.h"
 
 #define OPERA_READ_MSG 0
@@ -38,7 +40,7 @@ struct opera_rc_keys {
 	u32 event;
 };
 
-int dvb_usb_opera1_debug;
+static int dvb_usb_opera1_debug;
 module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
 MODULE_PARM_DESC(debug,
 		 "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
diff --git a/drivers/media/dvb/dvb-usb/opera1.h b/drivers/media/dvb/dvb-usb/opera1.h
deleted file mode 100644
index 53174427902d..000000000000
--- a/drivers/media/dvb/dvb-usb/opera1.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _OPERA1_H_
-#define _OPERA1_H_
-
-#define DVB_USB_LOG_PREFIX "opera"
-#include "dvb-usb.h"
-
-extern int dvb_usb_opera1_debug;
-#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args)
-#endif
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index 16533b31a82d..e553c139ac44 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -56,7 +56,7 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
 	return ret;
 }
 
-int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
 			     u16 index, u8 *b, int blen)
 {
 	int ret;
@@ -204,19 +204,6 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 	return 0;
 }
 
-int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-	struct vp702x_device_state *st = d->priv;
-
-	if (st->power_state == 0 && onoff)
-		vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
-	else if (st->power_state == 1 && onoff == 0)
-		vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
-
-	st->power_state = onoff;
-
-	return 0;
-}
 
 static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
 {
diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h
index 25a9dee4c824..c2f97f96c21f 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.h
+++ b/drivers/media/dvb/dvb-usb/vp702x.h
@@ -102,7 +102,5 @@ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
 
 extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
 extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
-extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
-extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff);
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 5bbd2d5192f0..c172babf59bb 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -15,9 +15,12 @@
 #include "vp7045.h"
 
 /* debug */
-int dvb_usb_vp7045_debug;
+static int dvb_usb_vp7045_debug;
 module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
 
 int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
 {
diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h
index 9ce21a20fa86..969688f85267 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.h
+++ b/drivers/media/dvb/dvb-usb/vp7045.h
@@ -17,11 +17,6 @@
 #define DVB_USB_LOG_PREFIX "vp7045"
 #include "dvb-usb.h"
 
-extern int dvb_usb_vp7045_debug;
-#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
-#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
-#define deb_rc(args...)   dprintk(dvb_usb_vp7045_debug,0x04,args)
-
 /* vp7045 commands */
 
 /* Twinhan Vendor requests */
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 59b9ed1f1aec..9ad86ce4a4e5 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -316,6 +316,13 @@ config DVB_TDA827X
 	help
 	  A DVB-T silicon tuner module. Say Y when you want to support this tuner.
 
+config DVB_TDA18271
+	tristate "NXP TDA18271 silicon tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A silicon tuner module. Say Y when you want to support this tuner.
+
 config DVB_TUNER_QT1010
 	tristate "Quantek QT1010 silicon tuner"
 	depends on DVB_CORE && I2C
@@ -353,6 +360,15 @@ config DVB_TUNER_DIB0070
 	  This device is only used inside a SiP called togther with a
 	  demodulator for now.
 
+config DVB_TUNER_XC5000
+	tristate "Xceive XC5000 silicon tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon tuner XC5000 from Xceive.
+	  This device is only used inside a SiP called togther with a
+	  demodulator for now.
+
 comment "Miscellaneous devices"
 	depends on DVB_CORE
 
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 4b8ad1f132aa..16bd107ebd32 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -3,6 +3,9 @@
 #
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/video/
+
+tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o
 
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -39,6 +42,7 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o
 obj-$(CONFIG_DVB_TDA10086) += tda10086.o
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
 obj-$(CONFIG_DVB_TDA827X) += tda827x.o
+obj-$(CONFIG_DVB_TDA18271) += tda18271.o
 obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
 obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
 obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
@@ -46,3 +50,4 @@ obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
 obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
 obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
+obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
index 481eaa684157..fe895bf7b18f 100644
--- a/drivers/media/dvb/frontends/dib0070.c
+++ b/drivers/media/dvb/frontends/dib0070.c
@@ -434,9 +434,14 @@ static u16 dib0070_p1f_defaults[] =
 	0,
 };
 
-static void dib0070_wbd_calibration(struct dib0070_state *state)
+static void dib0070_wbd_calibration(struct dvb_frontend *fe)
 {
 	u16 wbd_offs;
+	struct dib0070_state *state = fe->tuner_priv;
+
+	if (state->cfg->sleep)
+		state->cfg->sleep(fe, 0);
+
 	dib0070_write_reg(state, 0x0f, 0x6d81);
 	dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
 	msleep(9);
@@ -444,6 +449,10 @@ static void dib0070_wbd_calibration(struct dib0070_state *state)
 	dib0070_write_reg(state, 0x20, 0);
 	state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2);
 	dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset);
+
+	if (state->cfg->sleep)
+		state->cfg->sleep(fe, 1);
+
 }
 
 u16 dib0070_wbd_offset(struct dvb_frontend *fe)
@@ -560,7 +569,7 @@ struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter
 	if (dib0070_reset(state) != 0)
 		goto free_mem;
 
-	dib0070_wbd_calibration(state);
+	dib0070_wbd_calibration(fe);
 
 	printk(KERN_INFO "DiB0070: successfully identified\n");
 	memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index edae0be063f5..fa851601e7d4 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -684,6 +684,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 				struct dvb_frontend_parameters *fep)
 {
 	struct dib3000mc_state *state = fe->demodulator_priv;
+    int ret;
+
+	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
 
 	state->current_bandwidth = fep->u.ofdm.bandwidth;
 	dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
@@ -700,7 +703,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 		fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
 		fep->u.ofdm.constellation     == QAM_AUTO ||
 		fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
-		int i = 100, found;
+		int i = 1000, found;
 
 		dib3000mc_autosearch_start(fe, fep);
 		do {
@@ -715,10 +718,11 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
 		dib3000mc_get_frontend(fe, fep);
 	}
 
+    ret = dib3000mc_tune(fe, fep);
+
 	/* make this a config parameter */
 	dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-
-	return dib3000mc_tune(fe, fep);
+    return ret;
 }
 
 static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index fb18441a8c57..5f1375e30dfc 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -1171,7 +1171,9 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
 				struct dvb_frontend_parameters *fep)
 {
 	struct dib7000m_state *state = fe->demodulator_priv;
-	int time;
+	int time, ret;
+
+    dib7000m_set_output_mode(state, OUTMODE_HIGH_Z);
 
 	state->current_bandwidth = fep->u.ofdm.bandwidth;
 	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
@@ -1206,10 +1208,11 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
 		dib7000m_get_frontend(fe, fep);
 	}
 
+	ret = dib7000m_tune(fe, fep);
+
 	/* make this a config parameter */
 	dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-
-	return dib7000m_tune(fe, fep);
+	return ret;
 }
 
 static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index f45bcfc51cf8..47c23e29753e 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -35,8 +35,8 @@ struct dib7000p_state {
 
 	u16 wbd_ref;
 
-	u8 current_band;
-	fe_bandwidth_t current_bandwidth;
+	u8  current_band;
+	u32 current_bandwidth;
 	struct dibx000_agc_config *current_agc;
 	u32 timf;
 
@@ -1074,7 +1074,7 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe,
 
 	fep->inversion = INVERSION_AUTO;
 
-	fep->u.ofdm.bandwidth = state->current_bandwidth;
+	fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth);
 
 	switch ((tps >> 8) & 0x3) {
 		case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
@@ -1128,12 +1128,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
 				struct dvb_frontend_parameters *fep)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
-	int time;
+	int time, ret;
 
-	state->current_bandwidth = fep->u.ofdm.bandwidth;
-	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+	dib7000p_set_output_mode(state, OUTMODE_HIGH_Z);
 
-	/* maybe the parameter has been changed */
+    /* maybe the parameter has been changed */
 	state->sfn_workaround_active = buggy_sfn_workaround;
 
 	if (fe->ops.tuner_ops.set_params)
@@ -1166,10 +1165,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
 		dib7000p_get_frontend(fe, fep);
 	}
 
+	ret = dib7000p_tune(fe, fep);
+
 	/* make this a config parameter */
 	dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
-
-	return dib7000p_tune(fe, fep);
+    return ret;
 }
 
 static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
index 5e17275afd25..84e4d5362922 100644
--- a/drivers/media/dvb/frontends/dibx000_common.h
+++ b/drivers/media/dvb/frontends/dibx000_common.h
@@ -128,6 +128,11 @@ enum dibx000_adc_states {
 			     (v) == BANDWIDTH_7_MHZ  ? 7000 : \
 			     (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000 )
 
+#define BANDWIDTH_TO_INDEX(v) ( \
+	(v) == 8000 ? BANDWIDTH_8_MHZ : \
+		(v) == 7000 ? BANDWIDTH_7_MHZ : \
+		(v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ )
+
 /* Chip output mode. */
 #define OUTMODE_HIGH_Z              0
 #define OUTMODE_MPEG2_PAR_GATED_CLK 1
diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c
index 03fe8265745f..54b18f94b14b 100644
--- a/drivers/media/dvb/frontends/mt2266.c
+++ b/drivers/media/dvb/frontends/mt2266.c
@@ -38,8 +38,12 @@ struct mt2266_priv {
 
 	u32 frequency;
 	u32 bandwidth;
+	u8 band;
 };
 
+#define MT2266_VHF 1
+#define MT2266_UHF 0
+
 /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
 
 static int debug;
@@ -90,26 +94,30 @@ static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
 }
 
 // Initialisation sequences
-static u8 mt2266_init1[] = {
-	REG_TUNE,
-	0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f };
+static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
+				 0x00, 0x52, 0x99, 0x3f };
 
 static u8 mt2266_init2[] = {
-	0x17,                                     0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a,
-	0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01,
-	0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d };
+    0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
+    0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
+    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
+    0xff, 0x00, 0x77, 0x0f, 0x2d
+};
+
+static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
+						0x22, 0x22, 0x22, 0x22 };
 
-static u8 mt2266_init_8mhz[] = {
-	REG_BANDWIDTH,
-	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 };
+static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
+						0x32, 0x32, 0x32, 0x32 };
 
-static u8 mt2266_init_7mhz[] = {
-	REG_BANDWIDTH,
-	0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 };
+static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
+						0xa7, 0xa7, 0xa7, 0xa7 };
 
-static u8 mt2266_init_6mhz[] = {
-	REG_BANDWIDTH,
-	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 };
+static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
+			   0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
+
+static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
+			   0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
 
 #define FREF 30000       // Quartz oscillator 30 MHz
 
@@ -122,35 +130,78 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
 	u8  lnaband;
 	u8  b[10];
 	int i;
+	u8 band;
 
 	priv = fe->tuner_priv;
 
-	mt2266_writereg(priv,0x17,0x6d);
-	mt2266_writereg(priv,0x1c,0xff);
-
 	freq = params->frequency / 1000; // Hz -> kHz
+	if (freq < 470000 && freq > 230000)
+		return -EINVAL; /* Gap between VHF and UHF bands */
 	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 	priv->frequency = freq * 1000;
-	tune=2 * freq * (8192/16) / (FREF/16);
-
-	if (freq <= 495000) lnaband = 0xEE; else
-	if (freq <= 525000) lnaband = 0xDD; else
-	if (freq <= 550000) lnaband = 0xCC; else
-	if (freq <= 580000) lnaband = 0xBB; else
-	if (freq <= 605000) lnaband = 0xAA; else
-	if (freq <= 630000) lnaband = 0x99; else
-	if (freq <= 655000) lnaband = 0x88; else
-	if (freq <= 685000) lnaband = 0x77; else
-	if (freq <= 710000) lnaband = 0x66; else
-	if (freq <= 735000) lnaband = 0x55; else
-	if (freq <= 765000) lnaband = 0x44; else
-	if (freq <= 802000) lnaband = 0x33; else
-	if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11;
-
-	msleep(100);
-	mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz:
-				(params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz:
-				mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
+
+	tune = 2 * freq * (8192/16) / (FREF/16);
+	band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
+	if (band == MT2266_VHF)
+		tune *= 2;
+
+	switch (params->u.ofdm.bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		mt2266_writeregs(priv, mt2266_init_6mhz,
+				 sizeof(mt2266_init_6mhz));
+		break;
+	case BANDWIDTH_7_MHZ:
+		mt2266_writeregs(priv, mt2266_init_7mhz,
+				 sizeof(mt2266_init_7mhz));
+		break;
+	case BANDWIDTH_8_MHZ:
+	default:
+		mt2266_writeregs(priv, mt2266_init_8mhz,
+				 sizeof(mt2266_init_8mhz));
+		break;
+	}
+
+	if (band == MT2266_VHF && priv->band == MT2266_UHF) {
+		dprintk("Switch from UHF to VHF");
+		mt2266_writereg(priv, 0x05, 0x04);
+		mt2266_writereg(priv, 0x19, 0x61);
+		mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
+	} else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
+		dprintk("Switch from VHF to UHF");
+		mt2266_writereg(priv, 0x05, 0x52);
+		mt2266_writereg(priv, 0x19, 0x61);
+		mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
+	}
+	msleep(10);
+
+	if (freq <= 495000)
+		lnaband = 0xEE;
+	else if (freq <= 525000)
+		lnaband = 0xDD;
+	else if (freq <= 550000)
+		lnaband = 0xCC;
+	else if (freq <= 580000)
+		lnaband = 0xBB;
+	else if (freq <= 605000)
+		lnaband = 0xAA;
+	else if (freq <= 630000)
+		lnaband = 0x99;
+	else if (freq <= 655000)
+		lnaband = 0x88;
+	else if (freq <= 685000)
+		lnaband = 0x77;
+	else if (freq <= 710000)
+		lnaband = 0x66;
+	else if (freq <= 735000)
+		lnaband = 0x55;
+	else if (freq <= 765000)
+		lnaband = 0x44;
+	else if (freq <= 802000)
+		lnaband = 0x33;
+	else if (freq <= 840000)
+		lnaband = 0x22;
+	else
+		lnaband = 0x11;
 
 	b[0] = REG_TUNE;
 	b[1] = (tune >> 8) & 0x1F;
@@ -158,47 +209,54 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame
 	b[3] = tune >> 13;
 	mt2266_writeregs(priv,b,4);
 
-	dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband);
-	dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]);
-
-	b[0] = 0x05;
-	b[1] = 0x62;
-	b[2] = lnaband;
-	mt2266_writeregs(priv,b,3);
+	dprintk("set_parms: tune=%d band=%d %s",
+		(int) tune, (int) lnaband,
+		(band == MT2266_UHF) ? "UHF" : "VHF");
+	dprintk("set_parms: [1..3]: %2x %2x %2x",
+		(int) b[1], (int) b[2], (int)b[3]);
+
+	if (band == MT2266_UHF) {
+		b[0] = 0x05;
+		b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
+		b[2] = lnaband;
+		mt2266_writeregs(priv, b, 3);
+	}
 
-	//Waits for pll lock or timeout
+	/* Wait for pll lock or timeout */
 	i = 0;
 	do {
 		mt2266_readreg(priv,REG_LOCK,b);
-		if ((b[0] & 0x40)==0x40)
+		if (b[0] & 0x40)
 			break;
 		msleep(10);
 		i++;
 	} while (i<10);
 	dprintk("Lock when i=%i",(int)i);
+
+	if (band == MT2266_UHF && priv->band == MT2266_VHF)
+		mt2266_writereg(priv, 0x05, 0x62);
+
+	priv->band = band;
+
 	return ret;
 }
 
 static void mt2266_calibrate(struct mt2266_priv *priv)
 {
-	mt2266_writereg(priv,0x11,0x03);
-	mt2266_writereg(priv,0x11,0x01);
-
-	mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1));
-	mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2));
-
-	mt2266_writereg(priv,0x33,0x5e);
-	mt2266_writereg(priv,0x10,0x10);
-	mt2266_writereg(priv,0x10,0x00);
-
-	mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
-
+	mt2266_writereg(priv, 0x11, 0x03);
+	mt2266_writereg(priv, 0x11, 0x01);
+	mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
+	mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
+	mt2266_writereg(priv, 0x33, 0x5e);
+	mt2266_writereg(priv, 0x10, 0x10);
+	mt2266_writereg(priv, 0x10, 0x00);
+	mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
 	msleep(25);
-	mt2266_writereg(priv,0x17,0x6d);
-	mt2266_writereg(priv,0x1c,0x00);
+	mt2266_writereg(priv, 0x17, 0x6d);
+	mt2266_writereg(priv, 0x1c, 0x00);
 	msleep(75);
-	mt2266_writereg(priv,0x17,0x6d);
-	mt2266_writereg(priv,0x1c,0xff);
+	mt2266_writereg(priv, 0x17, 0x6d);
+	mt2266_writereg(priv, 0x1c, 0xff);
 }
 
 static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
@@ -217,17 +275,22 @@ static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 
 static int mt2266_init(struct dvb_frontend *fe)
 {
+	int ret;
 	struct mt2266_priv *priv = fe->tuner_priv;
-	mt2266_writereg(priv,0x17,0x6d);
-	mt2266_writereg(priv,0x1c,0xff);
+	ret = mt2266_writereg(priv, 0x17, 0x6d);
+	if (ret < 0)
+		return ret;
+	ret = mt2266_writereg(priv, 0x1c, 0xff);
+	if (ret < 0)
+		return ret;
 	return 0;
 }
 
 static int mt2266_sleep(struct dvb_frontend *fe)
 {
 	struct mt2266_priv *priv = fe->tuner_priv;
-	mt2266_writereg(priv,0x17,0x6d);
-	mt2266_writereg(priv,0x1c,0x00);
+	mt2266_writereg(priv, 0x17, 0x6d);
+	mt2266_writereg(priv, 0x1c, 0x00);
 	return 0;
 }
 
@@ -241,8 +304,8 @@ static int mt2266_release(struct dvb_frontend *fe)
 static const struct dvb_tuner_ops mt2266_tuner_ops = {
 	.info = {
 		.name           = "Microtune MT2266",
-		.frequency_min  = 470000000,
-		.frequency_max  = 860000000,
+		.frequency_min  = 174000000,
+		.frequency_max  = 862000000,
 		.frequency_step =     50000,
 	},
 	.release       = mt2266_release,
@@ -264,8 +327,9 @@ struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter
 
 	priv->cfg      = cfg;
 	priv->i2c      = i2c;
+	priv->band     = MT2266_UHF;
 
-	if (mt2266_readreg(priv,0,&id) != 0) {
+	if (mt2266_readreg(priv, 0, &id)) {
 		kfree(priv);
 		return NULL;
 	}
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 0606b9a5b616..1638301fbd6e 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -37,9 +37,9 @@
 
 
 struct mt312_state {
-	struct i2c_adapter* i2c;
+	struct i2c_adapter *i2c;
 	/* configuration settings */
-	const struct mt312_config* config;
+	const struct mt312_config *config;
 	struct dvb_frontend frontend;
 
 	u8 id;
@@ -49,14 +49,15 @@ struct mt312_state {
 static int debug;
 #define dprintk(args...) \
 	do { \
-		if (debug) printk(KERN_DEBUG "mt312: " args); \
+		if (debug) \
+			printk(KERN_DEBUG "mt312: " args); \
 	} while (0)
 
 #define MT312_SYS_CLK		90000000UL	/* 90 MHz */
 #define MT312_LPOWER_SYS_CLK	60000000UL	/* 60 MHz */
 #define MT312_PLL_CLK		10000000UL	/* 10 MHz */
 
-static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
+static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
 		      void *buf, const size_t count)
 {
 	int ret;
@@ -79,7 +80,7 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
 		return -EREMOTEIO;
 	}
 
-	if(debug) {
+	if (debug) {
 		int i;
 		dprintk("R(%d):", reg & 0x7f);
 		for (i = 0; i < count; i++)
@@ -90,14 +91,14 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg,
 	return 0;
 }
 
-static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
+static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
 		       const void *src, const size_t count)
 {
 	int ret;
 	u8 buf[count + 1];
 	struct i2c_msg msg;
 
-	if(debug) {
+	if (debug) {
 		int i;
 		dprintk("W(%d):", reg & 0x7f);
 		for (i = 0; i < count; i++)
@@ -123,13 +124,13 @@ static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg,
 	return 0;
 }
 
-static inline int mt312_readreg(struct mt312_state* state,
+static inline int mt312_readreg(struct mt312_state *state,
 				const enum mt312_reg_addr reg, u8 *val)
 {
 	return mt312_read(state, reg, val, 1);
 }
 
-static inline int mt312_writereg(struct mt312_state* state,
+static inline int mt312_writereg(struct mt312_state *state,
 				 const enum mt312_reg_addr reg, const u8 val)
 {
 	return mt312_write(state, reg, &val, 1);
@@ -140,18 +141,19 @@ static inline u32 mt312_div(u32 a, u32 b)
 	return (a + (b / 2)) / b;
 }
 
-static int mt312_reset(struct mt312_state* state, const u8 full)
+static int mt312_reset(struct mt312_state *state, const u8 full)
 {
 	return mt312_writereg(state, RESET, full ? 0x80 : 0x40);
 }
 
-static int mt312_get_inversion(struct mt312_state* state,
+static int mt312_get_inversion(struct mt312_state *state,
 			       fe_spectral_inversion_t *i)
 {
 	int ret;
 	u8 vit_mode;
 
-	if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0)
+	ret = mt312_readreg(state, VIT_MODE, &vit_mode);
+	if (ret < 0)
 		return ret;
 
 	if (vit_mode & 0x80)	/* auto inversion was used */
@@ -160,7 +162,7 @@ static int mt312_get_inversion(struct mt312_state* state,
 	return 0;
 }
 
-static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
+static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr)
 {
 	int ret;
 	u8 sym_rate_h;
@@ -169,37 +171,44 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
 	u16 monitor;
 	u8 buf[2];
 
-	if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0)
+	ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h);
+	if (ret < 0)
 		return ret;
 
-	if (sym_rate_h & 0x80) {	/* symbol rate search was used */
-		if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0)
+	if (sym_rate_h & 0x80) {
+		/* symbol rate search was used */
+		ret = mt312_writereg(state, MON_CTRL, 0x03);
+		if (ret < 0)
 			return ret;
 
-		if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
+		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
+		if (ret < 0)
 			return ret;
 
 		monitor = (buf[0] << 8) | buf[1];
 
-		dprintk(KERN_DEBUG "sr(auto) = %u\n",
+		dprintk("sr(auto) = %u\n",
 		       mt312_div(monitor * 15625, 4));
 	} else {
-		if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0)
+		ret = mt312_writereg(state, MON_CTRL, 0x05);
+		if (ret < 0)
 			return ret;
 
-		if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0)
+		ret = mt312_read(state, MONITOR_H, buf, sizeof(buf));
+		if (ret < 0)
 			return ret;
 
 		dec_ratio = ((buf[0] >> 5) & 0x07) * 32;
 
-		if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0)
+		ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf));
+		if (ret < 0)
 			return ret;
 
 		sym_rat_op = (buf[0] << 8) | buf[1];
 
-		dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n",
+		dprintk("sym_rat_op=%d dec_ratio=%d\n",
 		       sym_rat_op, dec_ratio);
-		dprintk(KERN_DEBUG "*sr(manual) = %lu\n",
+		dprintk("*sr(manual) = %lu\n",
 		       (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
 			2) - dec_ratio);
 	}
@@ -207,7 +216,7 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr)
 	return 0;
 }
 
-static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
+static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr)
 {
 	const fe_code_rate_t fec_tab[8] =
 	    { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8,
@@ -216,7 +225,8 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
 	int ret;
 	u8 fec_status;
 
-	if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0)
+	ret = mt312_readreg(state, FEC_STATUS, &fec_status);
+	if (ret < 0)
 		return ret;
 
 	*cr = fec_tab[(fec_status >> 4) & 0x07];
@@ -224,61 +234,72 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr)
 	return 0;
 }
 
-static int mt312_initfe(struct dvb_frontend* fe)
+static int mt312_initfe(struct dvb_frontend *fe)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[2];
 
 	/* wake up */
-	if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0)
+	ret = mt312_writereg(state, CONFIG,
+			(state->frequency == 60 ? 0x88 : 0x8c));
+	if (ret < 0)
 		return ret;
 
 	/* wait at least 150 usec */
 	udelay(150);
 
 	/* full reset */
-	if ((ret = mt312_reset(state, 1)) < 0)
+	ret = mt312_reset(state, 1);
+	if (ret < 0)
 		return ret;
 
-// Per datasheet, write correct values. 09/28/03 ACCJr.
-// If we don't do this, we won't get FE_HAS_VITERBI in the VP310.
+/* Per datasheet, write correct values. 09/28/03 ACCJr.
+ * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */
 	{
-		u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00};
+		u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02,
+				  0x01, 0x00, 0x00, 0x00 };
 
-		if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0)
+		ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def));
+		if (ret < 0)
 			return ret;
 	}
 
 	/* SYS_CLK */
-	buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000);
+	buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK :
+				MT312_SYS_CLK) * 2, 1000000);
 
 	/* DISEQC_RATIO */
 	buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
 
-	if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0)
+	ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0)
+	ret = mt312_writereg(state, SNR_THS_HIGH, 0x32);
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0)
+	ret = mt312_writereg(state, OP_CTRL, 0x53);
+	if (ret < 0)
 		return ret;
 
 	/* TS_SW_LIM */
 	buf[0] = 0x8c;
 	buf[1] = 0x98;
 
-	if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0)
+	ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
+	ret = mt312_writereg(state, CS_SW_LIM, 0x69);
+	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int mt312_send_master_cmd(struct dvb_frontend* fe,
+static int mt312_send_master_cmd(struct dvb_frontend *fe,
 				 struct dvb_diseqc_master_cmd *c)
 {
 	struct mt312_state *state = fe->demodulator_priv;
@@ -288,29 +309,31 @@ static int mt312_send_master_cmd(struct dvb_frontend* fe,
 	if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg)))
 		return -EINVAL;
 
-	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0)
 		return ret;
 
-	if ((ret =
-	     mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0)
+	ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len);
+	if (ret < 0)
 		return ret;
 
-	if ((ret =
-	     mt312_writereg(state, DISEQC_MODE,
-			    (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
-			    | 0x04)) < 0)
+	ret = mt312_writereg(state, DISEQC_MODE,
+			     (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3)
+			     | 0x04);
+	if (ret < 0)
 		return ret;
 
 	/* set DISEQC_MODE[2:0] to zero if a return message is expected */
-	if (c->msg[0] & 0x02)
-		if ((ret =
-		     mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0)
+	if (c->msg[0] & 0x02) {
+		ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
+		if (ret < 0)
 			return ret;
+	}
 
 	return 0;
 }
 
-static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
+static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	const u8 mini_tab[2] = { 0x02, 0x03 };
@@ -321,18 +344,19 @@ static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c)
 	if (c > SEC_MINI_B)
 		return -EINVAL;
 
-	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0)
 		return ret;
 
-	if ((ret =
-	     mt312_writereg(state, DISEQC_MODE,
-			    (diseqc_mode & 0x40) | mini_tab[c])) < 0)
+	ret = mt312_writereg(state, DISEQC_MODE,
+			     (diseqc_mode & 0x40) | mini_tab[c]);
+	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
+static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	const u8 tone_tab[2] = { 0x01, 0x00 };
@@ -343,18 +367,19 @@ static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t)
 	if (t > SEC_TONE_OFF)
 		return -EINVAL;
 
-	if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0)
+	ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode);
+	if (ret < 0)
 		return ret;
 
-	if ((ret =
-	     mt312_writereg(state, DISEQC_MODE,
-			    (diseqc_mode & 0x40) | tone_tab[t])) < 0)
+	ret = mt312_writereg(state, DISEQC_MODE,
+			     (diseqc_mode & 0x40) | tone_tab[t]);
+	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
+static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
@@ -365,7 +390,7 @@ static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v)
 	return mt312_writereg(state, DISEQC_MODE, volt_tab[v]);
 }
 
-static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
+static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
@@ -373,10 +398,12 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
 
 	*s = 0;
 
-	if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0)
+	ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status));
+	if (ret < 0)
 		return ret;
 
-	dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
+	dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x,"
+		" FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]);
 
 	if (status[0] & 0xc0)
 		*s |= FE_HAS_SIGNAL;	/* signal noise ratio */
@@ -392,13 +419,14 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s)
 	return 0;
 }
 
-static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
+static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[3];
 
-	if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0)
+	ret = mt312_read(state, RS_BERCNT_H, buf, 3);
+	if (ret < 0)
 		return ret;
 
 	*ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64;
@@ -406,7 +434,8 @@ static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber)
 	return 0;
 }
 
-static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength)
+static int mt312_read_signal_strength(struct dvb_frontend *fe,
+				      u16 *signal_strength)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
@@ -414,7 +443,8 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren
 	u16 agc;
 	s16 err_db;
 
-	if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0)
+	ret = mt312_read(state, AGC_H, buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
 	agc = (buf[0] << 6) | (buf[1] >> 2);
@@ -422,18 +452,19 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren
 
 	*signal_strength = agc;
 
-	dprintk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db);
+	dprintk("agc=%08x err_db=%hd\n", agc, err_db);
 
 	return 0;
 }
 
-static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
+static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[2];
 
-	if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0)
+	ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
 	*snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1);
@@ -441,13 +472,14 @@ static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr)
 	return 0;
 }
 
-static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
+static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 buf[2];
 
-	if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0)
+	ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
 	*ubc = (buf[0] << 8) | buf[1];
@@ -455,7 +487,7 @@ static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc)
 	return 0;
 }
 
-static int mt312_set_frontend(struct dvb_frontend* fe,
+static int mt312_set_frontend(struct dvb_frontend *fe,
 			      struct dvb_frontend_parameters *p)
 {
 	struct mt312_state *state = fe->demodulator_priv;
@@ -491,24 +523,28 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 
 	switch (state->id) {
 	case ID_VP310:
-	// For now we will do this only for the VP310.
-	// It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03
+	/* For now we will do this only for the VP310.
+	 * It should be better for the mt312 as well,
+	 * but tuning will be slower. ACCJr 09/29/03
+	 */
 		ret = mt312_readreg(state, CONFIG, &config_val);
 		if (ret < 0)
 			return ret;
-		if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz
-		{
-			if ((config_val & 0x0c) == 0x08) { //We are running 60MHz
+		if (p->u.qpsk.symbol_rate >= 30000000) {
+			/* Note that 30MS/s should use 90MHz */
+			if ((config_val & 0x0c) == 0x08) {
+				/* We are running 60MHz */
 				state->frequency = 90;
-				if ((ret = mt312_initfe(fe)) < 0)
+				ret = mt312_initfe(fe);
+				if (ret < 0)
 					return ret;
 			}
-		}
-		else
-		{
-			if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz
+		} else {
+			if ((config_val & 0x0c) == 0x0C) {
+				/* We are running 90MHz */
 				state->frequency = 60;
-				if ((ret = mt312_initfe(fe)) < 0)
+				ret = mt312_initfe(fe);
+				if (ret < 0)
 					return ret;
 			}
 		}
@@ -523,7 +559,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 
 	if (fe->ops.tuner_ops.set_params) {
 		fe->ops.tuner_ops.set_params(fe, p);
-		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
 	}
 
 	/* sr = (u16)(sr * 256.0 / 1000000.0) */
@@ -545,7 +582,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 	/* GO */
 	buf[4] = 0x01;
 
-	if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0)
+	ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf));
+	if (ret < 0)
 		return ret;
 
 	mt312_reset(state, 0);
@@ -553,27 +591,30 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
 	return 0;
 }
 
-static int mt312_get_frontend(struct dvb_frontend* fe,
+static int mt312_get_frontend(struct dvb_frontend *fe,
 			      struct dvb_frontend_parameters *p)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 
-	if ((ret = mt312_get_inversion(state, &p->inversion)) < 0)
+	ret = mt312_get_inversion(state, &p->inversion);
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0)
+	ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate);
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0)
+	ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner);
+	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
-	struct mt312_state* state = fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 
 	if (enable) {
 		return mt312_writereg(state, GPP_CTRL, 0x40);
@@ -582,27 +623,31 @@ static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
 	}
 }
 
-static int mt312_sleep(struct dvb_frontend* fe)
+static int mt312_sleep(struct dvb_frontend *fe)
 {
 	struct mt312_state *state = fe->demodulator_priv;
 	int ret;
 	u8 config;
 
 	/* reset all registers to defaults */
-	if ((ret = mt312_reset(state, 1)) < 0)
+	ret = mt312_reset(state, 1);
+	if (ret < 0)
 		return ret;
 
-	if ((ret = mt312_readreg(state, CONFIG, &config)) < 0)
+	ret = mt312_readreg(state, CONFIG, &config);
+	if (ret < 0)
 		return ret;
 
 	/* enter standby */
-	if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0)
+	ret = mt312_writereg(state, CONFIG, config & 0x7f);
+	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+static int mt312_get_tune_settings(struct dvb_frontend *fe,
+		struct dvb_frontend_tune_settings *fesettings)
 {
 	fesettings->min_delay_ms = 50;
 	fesettings->step_size = 0;
@@ -610,9 +655,9 @@ static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_
 	return 0;
 }
 
-static void mt312_release(struct dvb_frontend* fe)
+static void mt312_release(struct dvb_frontend *fe)
 {
-	struct mt312_state* state = fe->demodulator_priv;
+	struct mt312_state *state = fe->demodulator_priv;
 	kfree(state);
 }
 
@@ -655,10 +700,10 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
 	.set_voltage = mt312_set_voltage,
 };
 
-struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
-					struct i2c_adapter* i2c)
+struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
+					struct i2c_adapter *i2c)
 {
-	struct mt312_state* state = NULL;
+	struct mt312_state *state = NULL;
 
 	/* allocate memory for the internal state */
 	state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL);
@@ -674,7 +719,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
 		goto error;
 
 	/* create dvb_frontend */
-	memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+	memcpy(&state->frontend.ops, &vp310_mt312_ops,
+		sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
 	switch (state->id) {
@@ -687,7 +733,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
 		state->frequency = 60;
 		break;
 	default:
-		printk (KERN_WARNING "Only Zarlink VP310/MT312 are supported chips.\n");
+		printk(KERN_WARNING "Only Zarlink VP310/MT312"
+			" are supported chips.\n");
 		goto error;
 	}
 
@@ -697,6 +744,7 @@ error:
 	kfree(state);
 	return NULL;
 }
+EXPORT_SYMBOL(vp310_mt312_attach);
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
@@ -705,4 +753,3 @@ MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver");
 MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(vp310_mt312_attach);
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index cf9a1505ad4b..f17cb93ba9ba 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -28,22 +28,21 @@
 
 #include <linux/dvb/frontend.h>
 
-struct mt312_config
-{
+struct mt312_config {
 	/* the demodulator's i2c address */
 	u8 demod_address;
 };
 
 #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
-struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
-					struct i2c_adapter* i2c);
+struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
+					struct i2c_adapter *i2c);
 #else
-static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
-					struct i2c_adapter* i2c)
+static inline struct dvb_frontend *vp310_mt312_attach(
+	const struct mt312_config *config, struct i2c_adapter *i2c)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
 	return NULL;
 }
-#endif // CONFIG_DVB_MT312
+#endif /* CONFIG_DVB_MT312 */
 
-#endif // MT312_H
+#endif /* MT312_H */
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index 5dd9b731f6f2..7cd190b6f015 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -152,7 +152,13 @@ static void mt352_calc_input_freq(struct mt352_state* state,
 	if (state->config.if2)
 		if2 = state->config.if2;
 
-	ife = (2*adc_clock - if2);
+	if (adc_clock >= if2 * 2)
+		ife = if2;
+	else {
+		ife = adc_clock - (if2 % adc_clock);
+		if (ife > adc_clock / 2)
+			ife = adc_clock - ife;
+	}
 	value = -16374 * ife / adc_clock;
 	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
 		__FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff);
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index b314a1f2deed..1d2d28ce823d 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -564,7 +564,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
 	/* Allocate memory for the internal state */
 	state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL);
 	if (state == NULL)
-		goto error;
+		return NULL;
 
 	/* Setup the state */
 	state->config = config;
@@ -576,10 +576,6 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
 	memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
 }
 
 static struct dvb_frontend_ops or51132_ops = {
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index f02bd9445955..6a6b0d727c6f 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -529,7 +529,7 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
 	/* Allocate memory for the internal state */
 	state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL);
 	if (state == NULL)
-		goto error;
+		return NULL;
 
 	/* Setup the state */
 	state->config = config;
@@ -541,10 +541,6 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
 	memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 	return &state->frontend;
-
-error:
-	kfree(state);
-	return NULL;
 }
 
 static struct dvb_frontend_ops or51211_ops = {
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index 562d9208857a..819433485d3b 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -42,6 +42,7 @@ struct s5h1409_state {
 	fe_modulation_t current_modulation;
 
 	u32 current_frequency;
+	int if_freq;
 
 	u32 is_qam_locked;
 	u32 qam_state;
@@ -97,7 +98,7 @@ static struct init_tab {
 	{ 0xac, 0x1003, },
 	{ 0xad, 0x103f, },
 	{ 0xe2, 0x0100, },
-	{ 0xe3, 0x0000, },
+	{ 0xe3, 0x1000, },
 	{ 0x28, 0x1010, },
 	{ 0xb1, 0x000e, },
 };
@@ -348,28 +349,32 @@ static int s5h1409_softreset(struct dvb_frontend* fe)
 	return 0;
 }
 
+#define S5H1409_VSB_IF_FREQ 5380
+#define S5H1409_QAM_IF_FREQ state->config->qam_if
+
 static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
 {
 	struct s5h1409_state* state = fe->demodulator_priv;
-	int ret = 0;
 
 	dprintk("%s(%d KHz)\n", __FUNCTION__, KHz);
 
-	if( (KHz == 44000) || (KHz == 5380) ) {
-		s5h1409_writereg(state, 0x87, 0x01be);
-		s5h1409_writereg(state, 0x88, 0x0436);
-		s5h1409_writereg(state, 0x89, 0x054d);
-	} else
-	if (KHz == 4000) {
+	switch (KHz) {
+	case 4000:
 		s5h1409_writereg(state, 0x87, 0x014b);
 		s5h1409_writereg(state, 0x88, 0x0cb5);
 		s5h1409_writereg(state, 0x89, 0x03e2);
-	} else {
-		printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
-		ret = -1;
+		break;
+	case 5380:
+	case 44000:
+	default:
+		s5h1409_writereg(state, 0x87, 0x01be);
+		s5h1409_writereg(state, 0x88, 0x0436);
+		s5h1409_writereg(state, 0x89, 0x054d);
+		break;
 	}
+	state->if_freq = KHz;
 
-	return ret;
+	return 0;
 }
 
 static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
@@ -394,11 +399,15 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
 	switch(m) {
 	case VSB_8:
 		dprintk("%s() VSB_8\n", __FUNCTION__);
+		if (state->if_freq != S5H1409_VSB_IF_FREQ)
+			s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ);
 		s5h1409_writereg(state, 0xf4, 0);
 		break;
 	case QAM_64:
 	case QAM_256:
 		dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__);
+		if (state->if_freq != S5H1409_QAM_IF_FREQ)
+			s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
 		s5h1409_writereg(state, 0xf4, 1);
 		s5h1409_writereg(state, 0x85, 0x110);
 		break;
@@ -432,9 +441,11 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
 	dprintk("%s(%d)\n", __FUNCTION__, enable);
 
 	if (enable)
-		return s5h1409_writereg(state, 0xe3, 0x1100);
+		return s5h1409_writereg(state, 0xe3,
+			s5h1409_readreg(state, 0xe3) | 0x1100);
 	else
-		return s5h1409_writereg(state, 0xe3, 0x1000);
+		return s5h1409_writereg(state, 0xe3,
+			s5h1409_readreg(state, 0xe3) & 0xeeff);
 }
 
 static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
@@ -504,13 +515,15 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
 			s5h1409_writereg(state, 0x96, 0x20);
 			s5h1409_writereg(state, 0xad,
 				( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) );
-			s5h1409_writereg(state, 0xab, 0x1100);
+			s5h1409_writereg(state, 0xab,
+				s5h1409_readreg(state, 0xab) & 0xeffe);
 		}
 	} else {
 		if (state->qam_state != 1) {
 			state->qam_state = 1;
 			s5h1409_writereg(state, 0x96, 0x08);
-			s5h1409_writereg(state, 0xab, 0x1101);
+			s5h1409_writereg(state, 0xab,
+				s5h1409_readreg(state, 0xab) | 0x1001);
 		}
 	}
 }
@@ -547,6 +560,36 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe,
 	return 0;
 }
 
+static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
+{
+	struct s5h1409_state *state = fe->demodulator_priv;
+	u16 val;
+
+	dprintk("%s(%d)\n", __FUNCTION__, mode);
+
+	val = s5h1409_readreg(state, 0xac) & 0xcfff;
+	switch (mode) {
+	case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK:
+		val |= 0x0000;
+		break;
+	case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK:
+		dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode);
+		val |= 0x1000;
+		break;
+	case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK:
+		val |= 0x2000;
+		break;
+	case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK:
+		val |= 0x3000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Configure MPEG Signal Timing charactistics */
+	return s5h1409_writereg(state, 0xac, val);
+}
+
 /* Reset the demod hardware and reset all of the configuration registers
    to a default state. */
 static int s5h1409_init (struct dvb_frontend* fe)
@@ -566,13 +609,16 @@ static int s5h1409_init (struct dvb_frontend* fe)
 	state->current_modulation = VSB_8;
 
 	if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
-		s5h1409_writereg(state, 0xab, 0x100); /* Serial */
+		s5h1409_writereg(state, 0xab,
+			s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
 	else
-		s5h1409_writereg(state, 0xab, 0x0); /* Parallel */
+		s5h1409_writereg(state, 0xab,
+			s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */
 
 	s5h1409_set_spectralinversion(fe, state->config->inversion);
-	s5h1409_set_if_freq(fe, state->config->if_freq);
+	s5h1409_set_if_freq(fe, state->if_freq);
 	s5h1409_set_gpio(fe, state->config->gpio);
+	s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing);
 	s5h1409_softreset(fe);
 
 	/* Note: Leaving the I2C gate closed. */
@@ -741,6 +787,7 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
 				    struct i2c_adapter* i2c)
 {
 	struct s5h1409_state* state = NULL;
+	u16 reg;
 
 	/* allocate memory for the internal state */
 	state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
@@ -751,9 +798,11 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
 	state->config = config;
 	state->i2c = i2c;
 	state->current_modulation = 0;
+	state->if_freq = S5H1409_VSB_IF_FREQ;
 
 	/* check if the demod exists */
-	if (s5h1409_readreg(state, 0x04) != 0x0066)
+	reg = s5h1409_readreg(state, 0x04);
+	if ((reg != 0x0066) && (reg != 0x007f))
 		goto error;
 
 	/* create dvb_frontend */
@@ -761,8 +810,14 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
 	       sizeof(struct dvb_frontend_ops));
 	state->frontend.demodulator_priv = state;
 
+	if (s5h1409_init(&state->frontend) != 0) {
+		printk(KERN_ERR "%s: Failed to initialize correctly\n",
+			__FUNCTION__);
+		goto error;
+	}
+
 	/* Note: Leaving the I2C gate open here. */
-	s5h1409_writereg(state, 0xf3, 1);
+	s5h1409_i2c_gate_ctrl(&state->frontend, 1);
 
 	return &state->frontend;
 
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
index 20f9af1af445..f0bb13fe808b 100644
--- a/drivers/media/dvb/frontends/s5h1409.h
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -39,8 +39,8 @@ struct s5h1409_config
 #define S5H1409_GPIO_ON  1
 	u8 gpio;
 
-	/* IF Freq in KHz */
-	u16 if_freq;
+	/* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */
+	u16 qam_if;
 
 	/* Spectral Inversion */
 #define S5H1409_INVERSION_OFF 0
@@ -51,6 +51,13 @@ struct s5h1409_config
 #define S5H1409_TUNERLOCKING 0
 #define S5H1409_DEMODLOCKING 1
 	u8 status_mode;
+
+	/* MPEG signal timing */
+#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK       0
+#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK    1
+#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK    2
+#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+	u16 mpeg_timing;
 };
 
 #if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))
diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c
new file mode 100644
index 000000000000..cebb6b90b7e0
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda18271-common.c
@@ -0,0 +1,653 @@
+/*
+    tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.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 "tda18271-priv.h"
+
+static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	enum tda18271_i2c_gate gate;
+	int ret = 0;
+
+	switch (priv->gate) {
+	case TDA18271_GATE_DIGITAL:
+	case TDA18271_GATE_ANALOG:
+		gate = priv->gate;
+		break;
+	case TDA18271_GATE_AUTO:
+	default:
+		switch (priv->mode) {
+		case TDA18271_DIGITAL:
+			gate = TDA18271_GATE_DIGITAL;
+			break;
+		case TDA18271_ANALOG:
+		default:
+			gate = TDA18271_GATE_ANALOG;
+			break;
+		}
+	}
+
+	switch (gate) {
+	case TDA18271_GATE_ANALOG:
+		if (fe->ops.analog_ops.i2c_gate_ctrl)
+			ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable);
+		break;
+	case TDA18271_GATE_DIGITAL:
+		if (fe->ops.i2c_gate_ctrl)
+			ret = fe->ops.i2c_gate_ctrl(fe, enable);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+};
+
+/*---------------------------------------------------------------------*/
+
+static void tda18271_dump_regs(struct dvb_frontend *fe, int extended)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	tda_reg("=== TDA18271 REG DUMP ===\n");
+	tda_reg("ID_BYTE            = 0x%02x\n", 0xff & regs[R_ID]);
+	tda_reg("THERMO_BYTE        = 0x%02x\n", 0xff & regs[R_TM]);
+	tda_reg("POWER_LEVEL_BYTE   = 0x%02x\n", 0xff & regs[R_PL]);
+	tda_reg("EASY_PROG_BYTE_1   = 0x%02x\n", 0xff & regs[R_EP1]);
+	tda_reg("EASY_PROG_BYTE_2   = 0x%02x\n", 0xff & regs[R_EP2]);
+	tda_reg("EASY_PROG_BYTE_3   = 0x%02x\n", 0xff & regs[R_EP3]);
+	tda_reg("EASY_PROG_BYTE_4   = 0x%02x\n", 0xff & regs[R_EP4]);
+	tda_reg("EASY_PROG_BYTE_5   = 0x%02x\n", 0xff & regs[R_EP5]);
+	tda_reg("CAL_POST_DIV_BYTE  = 0x%02x\n", 0xff & regs[R_CPD]);
+	tda_reg("CAL_DIV_BYTE_1     = 0x%02x\n", 0xff & regs[R_CD1]);
+	tda_reg("CAL_DIV_BYTE_2     = 0x%02x\n", 0xff & regs[R_CD2]);
+	tda_reg("CAL_DIV_BYTE_3     = 0x%02x\n", 0xff & regs[R_CD3]);
+	tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]);
+	tda_reg("MAIN_DIV_BYTE_1    = 0x%02x\n", 0xff & regs[R_MD1]);
+	tda_reg("MAIN_DIV_BYTE_2    = 0x%02x\n", 0xff & regs[R_MD2]);
+	tda_reg("MAIN_DIV_BYTE_3    = 0x%02x\n", 0xff & regs[R_MD3]);
+
+	/* only dump extended regs if DBG_ADV is set */
+	if (!(tda18271_debug & DBG_ADV))
+		return;
+
+	/* W indicates write-only registers.
+	 * Register dump for write-only registers shows last value written. */
+
+	tda_reg("EXTENDED_BYTE_1    = 0x%02x\n", 0xff & regs[R_EB1]);
+	tda_reg("EXTENDED_BYTE_2    = 0x%02x\n", 0xff & regs[R_EB2]);
+	tda_reg("EXTENDED_BYTE_3    = 0x%02x\n", 0xff & regs[R_EB3]);
+	tda_reg("EXTENDED_BYTE_4    = 0x%02x\n", 0xff & regs[R_EB4]);
+	tda_reg("EXTENDED_BYTE_5    = 0x%02x\n", 0xff & regs[R_EB5]);
+	tda_reg("EXTENDED_BYTE_6    = 0x%02x\n", 0xff & regs[R_EB6]);
+	tda_reg("EXTENDED_BYTE_7    = 0x%02x\n", 0xff & regs[R_EB7]);
+	tda_reg("EXTENDED_BYTE_8    = 0x%02x\n", 0xff & regs[R_EB8]);
+	tda_reg("EXTENDED_BYTE_9  W = 0x%02x\n", 0xff & regs[R_EB9]);
+	tda_reg("EXTENDED_BYTE_10   = 0x%02x\n", 0xff & regs[R_EB10]);
+	tda_reg("EXTENDED_BYTE_11   = 0x%02x\n", 0xff & regs[R_EB11]);
+	tda_reg("EXTENDED_BYTE_12   = 0x%02x\n", 0xff & regs[R_EB12]);
+	tda_reg("EXTENDED_BYTE_13   = 0x%02x\n", 0xff & regs[R_EB13]);
+	tda_reg("EXTENDED_BYTE_14   = 0x%02x\n", 0xff & regs[R_EB14]);
+	tda_reg("EXTENDED_BYTE_15   = 0x%02x\n", 0xff & regs[R_EB15]);
+	tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]);
+	tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]);
+	tda_reg("EXTENDED_BYTE_18   = 0x%02x\n", 0xff & regs[R_EB18]);
+	tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]);
+	tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]);
+	tda_reg("EXTENDED_BYTE_21   = 0x%02x\n", 0xff & regs[R_EB21]);
+	tda_reg("EXTENDED_BYTE_22   = 0x%02x\n", 0xff & regs[R_EB22]);
+	tda_reg("EXTENDED_BYTE_23   = 0x%02x\n", 0xff & regs[R_EB23]);
+}
+
+int tda18271_read_regs(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	unsigned char buf = 0x00;
+	int ret;
+	struct i2c_msg msg[] = {
+		{ .addr = priv->i2c_addr, .flags = 0,
+		  .buf = &buf, .len = 1 },
+		{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
+		  .buf = regs, .len = 16 }
+	};
+
+	tda18271_i2c_gate_ctrl(fe, 1);
+
+	/* read all registers */
+	ret = i2c_transfer(priv->i2c_adap, msg, 2);
+
+	tda18271_i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+	if (tda18271_debug & DBG_REG)
+		tda18271_dump_regs(fe, 0);
+
+	return (ret == 2 ? 0 : ret);
+}
+
+int tda18271_read_extended(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	unsigned char regdump[TDA18271_NUM_REGS];
+	unsigned char buf = 0x00;
+	int ret, i;
+	struct i2c_msg msg[] = {
+		{ .addr = priv->i2c_addr, .flags = 0,
+		  .buf = &buf, .len = 1 },
+		{ .addr = priv->i2c_addr, .flags = I2C_M_RD,
+		  .buf = regdump, .len = TDA18271_NUM_REGS }
+	};
+
+	tda18271_i2c_gate_ctrl(fe, 1);
+
+	/* read all registers */
+	ret = i2c_transfer(priv->i2c_adap, msg, 2);
+
+	tda18271_i2c_gate_ctrl(fe, 0);
+
+	if (ret != 2)
+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+	for (i = 0; i <= TDA18271_NUM_REGS; i++) {
+		/* don't update write-only registers */
+		if ((i != R_EB9)  &&
+		    (i != R_EB16) &&
+		    (i != R_EB17) &&
+		    (i != R_EB19) &&
+		    (i != R_EB20))
+		regs[i] = regdump[i];
+	}
+
+	if (tda18271_debug & DBG_REG)
+		tda18271_dump_regs(fe, 1);
+
+	return (ret == 2 ? 0 : ret);
+}
+
+int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	unsigned char buf[TDA18271_NUM_REGS + 1];
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = len + 1 };
+	int i, ret;
+
+	BUG_ON((len == 0) || (idx + len > sizeof(buf)));
+
+	buf[0] = idx;
+	for (i = 1; i <= len; i++)
+		buf[i] = regs[idx - 1 + i];
+
+	tda18271_i2c_gate_ctrl(fe, 1);
+
+	/* write registers */
+	ret = i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tda18271_i2c_gate_ctrl(fe, 0);
+
+	if (ret != 1)
+		tda_err("ERROR: i2c_transfer returned: %d\n", ret);
+
+	return (ret == 1 ? 0 : ret);
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_init_regs(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	tda_dbg("initializing registers for device @ %d-%04x\n",
+		i2c_adapter_id(priv->i2c_adap), priv->i2c_addr);
+
+	/* initialize registers */
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_ID]   = 0x83;
+		break;
+	case TDA18271HDC2:
+		regs[R_ID]   = 0x84;
+		break;
+	};
+
+	regs[R_TM]   = 0x08;
+	regs[R_PL]   = 0x80;
+	regs[R_EP1]  = 0xc6;
+	regs[R_EP2]  = 0xdf;
+	regs[R_EP3]  = 0x16;
+	regs[R_EP4]  = 0x60;
+	regs[R_EP5]  = 0x80;
+	regs[R_CPD]  = 0x80;
+	regs[R_CD1]  = 0x00;
+	regs[R_CD2]  = 0x00;
+	regs[R_CD3]  = 0x00;
+	regs[R_MPD]  = 0x00;
+	regs[R_MD1]  = 0x00;
+	regs[R_MD2]  = 0x00;
+	regs[R_MD3]  = 0x00;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB1]  = 0xff;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB1]  = 0xfc;
+		break;
+	};
+
+	regs[R_EB2]  = 0x01;
+	regs[R_EB3]  = 0x84;
+	regs[R_EB4]  = 0x41;
+	regs[R_EB5]  = 0x01;
+	regs[R_EB6]  = 0x84;
+	regs[R_EB7]  = 0x40;
+	regs[R_EB8]  = 0x07;
+	regs[R_EB9]  = 0x00;
+	regs[R_EB10] = 0x00;
+	regs[R_EB11] = 0x96;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB12] = 0x0f;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB12] = 0x33;
+		break;
+	};
+
+	regs[R_EB13] = 0xc1;
+	regs[R_EB14] = 0x00;
+	regs[R_EB15] = 0x8f;
+	regs[R_EB16] = 0x00;
+	regs[R_EB17] = 0x00;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB18] = 0x00;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB18] = 0x8c;
+		break;
+	};
+
+	regs[R_EB19] = 0x00;
+	regs[R_EB20] = 0x20;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		regs[R_EB21] = 0x33;
+		break;
+	case TDA18271HDC2:
+		regs[R_EB21] = 0xb3;
+		break;
+	};
+
+	regs[R_EB22] = 0x48;
+	regs[R_EB23] = 0xb0;
+
+	tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
+
+	/* setup agc1 gain */
+	regs[R_EB17] = 0x00;
+	tda18271_write_regs(fe, R_EB17, 1);
+	regs[R_EB17] = 0x03;
+	tda18271_write_regs(fe, R_EB17, 1);
+	regs[R_EB17] = 0x43;
+	tda18271_write_regs(fe, R_EB17, 1);
+	regs[R_EB17] = 0x4c;
+	tda18271_write_regs(fe, R_EB17, 1);
+
+	/* setup agc2 gain */
+	if ((priv->id) == TDA18271HDC1) {
+		regs[R_EB20] = 0xa0;
+		tda18271_write_regs(fe, R_EB20, 1);
+		regs[R_EB20] = 0xa7;
+		tda18271_write_regs(fe, R_EB20, 1);
+		regs[R_EB20] = 0xe7;
+		tda18271_write_regs(fe, R_EB20, 1);
+		regs[R_EB20] = 0xec;
+		tda18271_write_regs(fe, R_EB20, 1);
+	}
+
+	/* image rejection calibration */
+
+	/* low-band */
+	regs[R_EP3] = 0x1f;
+	regs[R_EP4] = 0x66;
+	regs[R_EP5] = 0x81;
+	regs[R_CPD] = 0xcc;
+	regs[R_CD1] = 0x6c;
+	regs[R_CD2] = 0x00;
+	regs[R_CD3] = 0x00;
+	regs[R_MPD] = 0xcd;
+	regs[R_MD1] = 0x77;
+	regs[R_MD2] = 0x08;
+	regs[R_MD3] = 0x00;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		tda18271_write_regs(fe, R_EP3, 11);
+		break;
+	case TDA18271HDC2:
+		tda18271_write_regs(fe, R_EP3, 12);
+		break;
+	};
+
+	if ((priv->id) == TDA18271HDC2) {
+		/* main pll cp source on */
+		regs[R_EB4] = 0x61;
+		tda18271_write_regs(fe, R_EB4, 1);
+		msleep(1);
+
+		/* main pll cp source off */
+		regs[R_EB4] = 0x41;
+		tda18271_write_regs(fe, R_EB4, 1);
+	}
+
+	msleep(5); /* pll locking */
+
+	/* launch detector */
+	tda18271_write_regs(fe, R_EP1, 1);
+	msleep(5); /* wanted low measurement */
+
+	regs[R_EP5] = 0x85;
+	regs[R_CPD] = 0xcb;
+	regs[R_CD1] = 0x66;
+	regs[R_CD2] = 0x70;
+
+	tda18271_write_regs(fe, R_EP3, 7);
+	msleep(5); /* pll locking */
+
+	/* launch optimization algorithm */
+	tda18271_write_regs(fe, R_EP2, 1);
+	msleep(30); /* image low optimization completion */
+
+	/* mid-band */
+	regs[R_EP5] = 0x82;
+	regs[R_CPD] = 0xa8;
+	regs[R_CD2] = 0x00;
+	regs[R_MPD] = 0xa9;
+	regs[R_MD1] = 0x73;
+	regs[R_MD2] = 0x1a;
+
+	tda18271_write_regs(fe, R_EP3, 11);
+	msleep(5); /* pll locking */
+
+	tda18271_write_regs(fe, R_EP1, 1);
+	msleep(5); /* wanted mid measurement */
+
+	regs[R_EP5] = 0x86;
+	regs[R_CPD] = 0xa8;
+	regs[R_CD1] = 0x66;
+	regs[R_CD2] = 0xa0;
+
+	tda18271_write_regs(fe, R_EP3, 7);
+	msleep(5); /* pll locking */
+
+	/* launch optimization algorithm */
+	tda18271_write_regs(fe, R_EP2, 1);
+	msleep(30); /* image mid optimization completion */
+
+	/* high-band */
+	regs[R_EP5] = 0x83;
+	regs[R_CPD] = 0x98;
+	regs[R_CD1] = 0x65;
+	regs[R_CD2] = 0x00;
+	regs[R_MPD] = 0x99;
+	regs[R_MD1] = 0x71;
+	regs[R_MD2] = 0xcd;
+
+	tda18271_write_regs(fe, R_EP3, 11);
+	msleep(5); /* pll locking */
+
+	/* launch detector */
+	tda18271_write_regs(fe, R_EP1, 1);
+	msleep(5); /* wanted high measurement */
+
+	regs[R_EP5] = 0x87;
+	regs[R_CD1] = 0x65;
+	regs[R_CD2] = 0x50;
+
+	tda18271_write_regs(fe, R_EP3, 7);
+	msleep(5); /* pll locking */
+
+	/* launch optimization algorithm */
+	tda18271_write_regs(fe, R_EP2, 1);
+	msleep(30); /* image high optimization completion */
+
+	/* return to normal mode */
+	regs[R_EP4] = 0x64;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	/* synchronize */
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+/*
+ *  Standby modes, EP3 [7:5]
+ *
+ *  | SM  || SM_LT || SM_XT || mode description
+ *  |=====\\=======\\=======\\===================================
+ *  |  0  ||   0   ||   0   || normal mode
+ *  |-----||-------||-------||-----------------------------------
+ *  |     ||       ||       || standby mode w/ slave tuner output
+ *  |  1  ||   0   ||   0   || & loop thru & xtal oscillator on
+ *  |-----||-------||-------||-----------------------------------
+ *  |  1  ||   1   ||   0   || standby mode w/ xtal oscillator on
+ *  |-----||-------||-------||-----------------------------------
+ *  |  1  ||   1   ||   1   || power off
+ *
+ */
+
+int tda18271_set_standby_mode(struct dvb_frontend *fe,
+			      int sm, int sm_lt, int sm_xt)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt);
+
+	regs[R_EP3]  &= ~0xe0; /* clear sm, sm_lt, sm_xt */
+	regs[R_EP3]  |= sm    ? (1 << 7) : 0 |
+			sm_lt ? (1 << 6) : 0 |
+			sm_xt ? (1 << 5) : 0;
+
+	tda18271_write_regs(fe, R_EP3, 1);
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq)
+{
+	/* sets main post divider & divider bytes, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 d, pd;
+	u32 div;
+
+	int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_MPD]   = (0x77 & pd);
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_MPD]  &= ~0x08;
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_MPD]  |=  0x08;
+		break;
+	}
+
+	div =  ((d * (freq / 1000)) << 7) / 125;
+
+	regs[R_MD1]   = 0x7f & (div >> 16);
+	regs[R_MD2]   = 0xff & (div >> 8);
+	regs[R_MD3]   = 0xff & div;
+fail:
+	return ret;
+}
+
+int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq)
+{
+	/* sets cal post divider & divider bytes, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 d, pd;
+	u32 div;
+
+	int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_CPD]   = pd;
+
+	div =  ((d * (freq / 1000)) << 7) / 125;
+
+	regs[R_CD1]   = 0x7f & (div >> 16);
+	regs[R_CD2]   = 0xff & (div >> 8);
+	regs[R_CD3]   = 0xff & div;
+fail:
+	return ret;
+}
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets bp filter bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EP1]  &= ~0x07; /* clear bp filter bits */
+	regs[R_EP1]  |= (0x07 & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets K & M bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EB13] &= ~0x7c; /* clear k & m bits */
+	regs[R_EB13] |= (0x7c & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets rf band bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EP2]  &= ~0xe0; /* clear rf band bits */
+	regs[R_EP2]  |= (0xe0 & (val << 5));
+fail:
+	return ret;
+}
+
+int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets gain taper bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EP2]  &= ~0x1f; /* clear gain taper bits */
+	regs[R_EP2]  |= (0x1f & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets IR Meas bits, but does not write them */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val);
+	if (ret < 0)
+		goto fail;
+
+	regs[R_EP5] &= ~0x07;
+	regs[R_EP5] |= (0x07 & val);
+fail:
+	return ret;
+}
+
+int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq)
+{
+	/* sets rf cal byte (RFC_Cprog), but does not write it */
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u8 val;
+
+	tda18271_lookup_map(fe, RF_CAL, freq, &val);
+
+	regs[R_EB14] = val;
+
+	return 0;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c
new file mode 100644
index 000000000000..dfe72aaec380
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda18271-fe.c
@@ -0,0 +1,1225 @@
+/*
+    tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.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/delay.h>
+#include <linux/videodev2.h>
+#include "tda18271-priv.h"
+
+int tda18271_debug;
+module_param_named(debug, tda18271_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level "
+		 "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))");
+
+static int tda18271_cal_on_startup;
+module_param_named(cal, tda18271_cal_on_startup, int, 0644);
+MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
+
+static LIST_HEAD(tda18271_list);
+static DEFINE_MUTEX(tda18271_list_mutex);
+
+/*---------------------------------------------------------------------*/
+
+static int tda18271_ir_cal_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	tda18271_read_regs(fe);
+
+	/* test IR_CAL_OK to see if we need init */
+	if ((regs[R_EP1] & 0x08) == 0)
+		tda18271_init_regs(fe);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_channel_configuration(struct dvb_frontend *fe,
+					  u32 ifc, u32 freq, u32 bw, u8 std,
+					  int radio)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u32 N;
+
+	/* update TV broadcast parameters */
+
+	/* set standard */
+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
+	regs[R_EP3]  |= std;
+
+	/* set cal mode to normal */
+	regs[R_EP4]  &= ~0x03;
+
+	/* update IF output level & IF notch frequency */
+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_EP4]  |= 0x04; /* IF level = 1 */
+		regs[R_MPD]  |= 0x80; /* IF notch = 1 */
+		break;
+	}
+
+	if (radio)
+		regs[R_EP4]  |=  0x80;
+	else
+		regs[R_EP4]  &= ~0x80;
+
+	/* update RF_TOP / IF_TOP */
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_EB22]  = 0x2c;
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_EB22]  = 0x37;
+		break;
+	}
+	tda18271_write_regs(fe, R_EB22, 1);
+
+	/* --------------------------------------------------------------- */
+
+	/* disable Power Level Indicator */
+	regs[R_EP1]  |= 0x40;
+
+	/* frequency dependent parameters */
+
+	tda18271_calc_ir_measure(fe, &freq);
+
+	tda18271_calc_bp_filter(fe, &freq);
+
+	tda18271_calc_rf_band(fe, &freq);
+
+	tda18271_calc_gain_taper(fe, &freq);
+
+	/* --------------------------------------------------------------- */
+
+	/* dual tuner and agc1 extra configuration */
+
+	/* main vco when Master, cal vco when slave */
+	regs[R_EB1]  |= 0x04; /* FIXME: assumes master */
+
+	/* agc1 always active */
+	regs[R_EB1]  &= ~0x02;
+
+	/* agc1 has priority on agc2 */
+	regs[R_EB1]  &= ~0x01;
+
+	tda18271_write_regs(fe, R_EB1, 1);
+
+	/* --------------------------------------------------------------- */
+
+	N = freq + ifc;
+
+	/* FIXME: assumes master */
+	tda18271_calc_main_pll(fe, N);
+	tda18271_write_regs(fe, R_MPD, 4);
+
+	tda18271_write_regs(fe, R_TM, 7);
+
+	/* main pll charge pump source */
+	regs[R_EB4] |= 0x20;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	msleep(1);
+
+	/* normal operation for the main pll */
+	regs[R_EB4] &= ~0x20;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	msleep(5);
+
+	return 0;
+}
+
+static int tda18271_read_thermometer(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int tm;
+
+	/* switch thermometer on */
+	regs[R_TM]   |= 0x10;
+	tda18271_write_regs(fe, R_TM, 1);
+
+	/* read thermometer info */
+	tda18271_read_regs(fe);
+
+	if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) ||
+	    (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) {
+
+		if ((regs[R_TM] & 0x20) == 0x20)
+			regs[R_TM] &= ~0x20;
+		else
+			regs[R_TM] |= 0x20;
+
+		tda18271_write_regs(fe, R_TM, 1);
+
+		msleep(10); /* temperature sensing */
+
+		/* read thermometer info */
+		tda18271_read_regs(fe);
+	}
+
+	tm = tda18271_lookup_thermometer(fe);
+
+	/* switch thermometer off */
+	regs[R_TM]   &= ~0x10;
+	tda18271_write_regs(fe, R_TM, 1);
+
+	/* set CAL mode to normal */
+	regs[R_EP4]  &= ~0x03;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	return tm;
+}
+
+static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe,
+						   u32 freq)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+	unsigned char *regs = priv->tda18271_regs;
+	int tm_current, rfcal_comp, approx, i;
+	u8 dc_over_dt, rf_tab;
+
+	/* power up */
+	tda18271_set_standby_mode(fe, 0, 0, 0);
+
+	/* read die current temperature */
+	tm_current = tda18271_read_thermometer(fe);
+
+	/* frequency dependent parameters */
+
+	tda18271_calc_rf_cal(fe, &freq);
+	rf_tab = regs[R_EB14];
+
+	i = tda18271_lookup_rf_band(fe, &freq, NULL);
+	if (i < 0)
+		return -EINVAL;
+
+	if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
+		approx = map[i].rf_a1 *
+			(freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab;
+	} else {
+		approx = map[i].rf_a2 *
+			(freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab;
+	}
+
+	if (approx < 0)
+		approx = 0;
+	if (approx > 255)
+		approx = 255;
+
+	tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
+
+	/* calculate temperature compensation */
+	rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal);
+
+	regs[R_EB14] = approx + rfcal_comp;
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	return 0;
+}
+
+static int tda18271_por(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	/* power up detector 1 */
+	regs[R_EB12] &= ~0x20;
+	tda18271_write_regs(fe, R_EB12, 1);
+
+	regs[R_EB18] &= ~0x80; /* turn agc1 loop on */
+	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
+	tda18271_write_regs(fe, R_EB18, 1);
+
+	regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */
+
+	/* POR mode */
+	tda18271_set_standby_mode(fe, 1, 0, 0);
+
+	/* disable 1.5 MHz low pass filter */
+	regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */
+	regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */
+	tda18271_write_regs(fe, R_EB21, 3);
+
+	return 0;
+}
+
+static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u32 N;
+
+	/* set CAL mode to normal */
+	regs[R_EP4]  &= ~0x03;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	/* switch off agc1 */
+	regs[R_EP3]  |= 0x40; /* sm_lt = 1 */
+
+	regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */
+	tda18271_write_regs(fe, R_EB18, 1);
+
+	/* frequency dependent parameters */
+
+	tda18271_calc_bp_filter(fe, &freq);
+	tda18271_calc_gain_taper(fe, &freq);
+	tda18271_calc_rf_band(fe, &freq);
+	tda18271_calc_km(fe, &freq);
+
+	tda18271_write_regs(fe, R_EP1, 3);
+	tda18271_write_regs(fe, R_EB13, 1);
+
+	/* main pll charge pump source */
+	regs[R_EB4]  |= 0x20;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	/* cal pll charge pump source */
+	regs[R_EB7]  |= 0x20;
+	tda18271_write_regs(fe, R_EB7, 1);
+
+	/* force dcdc converter to 0 V */
+	regs[R_EB14] = 0x00;
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	/* disable plls lock */
+	regs[R_EB20] &= ~0x20;
+	tda18271_write_regs(fe, R_EB20, 1);
+
+	/* set CAL mode to RF tracking filter calibration */
+	regs[R_EP4]  |= 0x03;
+	tda18271_write_regs(fe, R_EP4, 2);
+
+	/* --------------------------------------------------------------- */
+
+	/* set the internal calibration signal */
+	N = freq;
+
+	tda18271_calc_main_pll(fe, N);
+	tda18271_write_regs(fe, R_MPD, 4);
+
+	/* downconvert internal calibration */
+	N += 1000000;
+
+	tda18271_calc_main_pll(fe, N);
+	tda18271_write_regs(fe, R_MPD, 4);
+
+	msleep(5);
+
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	/* --------------------------------------------------------------- */
+
+	/* normal operation for the main pll */
+	regs[R_EB4] &= ~0x20;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	/* normal operation for the cal pll  */
+	regs[R_EB7] &= ~0x20;
+	tda18271_write_regs(fe, R_EB7, 1);
+
+	msleep(5); /* plls locking */
+
+	/* launch the rf tracking filters calibration */
+	regs[R_EB20]  |= 0x20;
+	tda18271_write_regs(fe, R_EB20, 1);
+
+	msleep(60); /* calibration */
+
+	/* --------------------------------------------------------------- */
+
+	/* set CAL mode to normal */
+	regs[R_EP4]  &= ~0x03;
+
+	/* switch on agc1 */
+	regs[R_EP3]  &= ~0x40; /* sm_lt = 0 */
+
+	regs[R_EB18] &= ~0x03; /* set agc1_gain to  6 dB */
+	tda18271_write_regs(fe, R_EB18, 1);
+
+	tda18271_write_regs(fe, R_EP3, 2);
+
+	/* synchronization */
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	/* get calibration result */
+	tda18271_read_extended(fe);
+
+	return regs[R_EB14];
+}
+
+static int tda18271_powerscan(struct dvb_frontend *fe,
+			      u32 *freq_in, u32 *freq_out)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int sgn, bcal, count, wait;
+	u8 cid_target;
+	u16 count_limit;
+	u32 freq;
+
+	freq = *freq_in;
+
+	tda18271_calc_rf_band(fe, &freq);
+	tda18271_calc_rf_cal(fe, &freq);
+	tda18271_calc_gain_taper(fe, &freq);
+	tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit);
+
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	/* downconvert frequency */
+	freq += 1000000;
+
+	tda18271_calc_main_pll(fe, freq);
+	tda18271_write_regs(fe, R_MPD, 4);
+
+	msleep(5); /* pll locking */
+
+	/* detection mode */
+	regs[R_EP4]  &= ~0x03;
+	regs[R_EP4]  |= 0x01;
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	/* launch power detection measurement */
+	tda18271_write_regs(fe, R_EP2, 1);
+
+	/* read power detection info, stored in EB10 */
+	tda18271_read_extended(fe);
+
+	/* algorithm initialization */
+	sgn = 1;
+	*freq_out = *freq_in;
+	bcal = 0;
+	count = 0;
+	wait = false;
+
+	while ((regs[R_EB10] & 0x3f) < cid_target) {
+		/* downconvert updated freq to 1 MHz */
+		freq = *freq_in + (sgn * count) + 1000000;
+
+		tda18271_calc_main_pll(fe, freq);
+		tda18271_write_regs(fe, R_MPD, 4);
+
+		if (wait) {
+			msleep(5); /* pll locking */
+			wait = false;
+		} else
+			udelay(100); /* pll locking */
+
+		/* launch power detection measurement */
+		tda18271_write_regs(fe, R_EP2, 1);
+
+		/* read power detection info, stored in EB10 */
+		tda18271_read_extended(fe);
+
+		count += 200;
+
+		if (count < count_limit)
+			continue;
+
+		if (sgn <= 0)
+			break;
+
+		sgn = -1 * sgn;
+		count = 200;
+		wait = true;
+	}
+
+	if ((regs[R_EB10] & 0x3f) >= cid_target) {
+		bcal = 1;
+		*freq_out = freq - 1000000;
+	} else
+		bcal = 0;
+
+	tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n",
+		bcal, *freq_in, *freq_out, freq);
+
+	return bcal;
+}
+
+static int tda18271_powerscan_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	/* set standard to digital */
+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
+	regs[R_EP3]  |= 0x12;
+
+	/* set cal mode to normal */
+	regs[R_EP4]  &= ~0x03;
+
+	/* update IF output level & IF notch frequency */
+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+
+	tda18271_write_regs(fe, R_EP3, 2);
+
+	regs[R_EB18] &= ~0x03; /* set agc1_gain to   6 dB */
+	tda18271_write_regs(fe, R_EB18, 1);
+
+	regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */
+
+	/* 1.5 MHz low pass filter */
+	regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */
+	regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */
+
+	tda18271_write_regs(fe, R_EB21, 3);
+
+	return 0;
+}
+
+static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+	unsigned char *regs = priv->tda18271_regs;
+	int bcal, rf, i;
+#define RF1 0
+#define RF2 1
+#define RF3 2
+	u32 rf_default[3];
+	u32 rf_freq[3];
+	u8 prog_cal[3];
+	u8 prog_tab[3];
+
+	i = tda18271_lookup_rf_band(fe, &freq, NULL);
+
+	if (i < 0)
+		return i;
+
+	rf_default[RF1] = 1000 * map[i].rf1_def;
+	rf_default[RF2] = 1000 * map[i].rf2_def;
+	rf_default[RF3] = 1000 * map[i].rf3_def;
+
+	for (rf = RF1; rf <= RF3; rf++) {
+		if (0 == rf_default[rf])
+			return 0;
+		tda_cal("freq = %d, rf = %d\n", freq, rf);
+
+		/* look for optimized calibration frequency */
+		bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]);
+
+		tda18271_calc_rf_cal(fe, &rf_freq[rf]);
+		prog_tab[rf] = regs[R_EB14];
+
+		if (1 == bcal)
+			prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]);
+		else
+			prog_cal[rf] = prog_tab[rf];
+
+		switch (rf) {
+		case RF1:
+			map[i].rf_a1 = 0;
+			map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1];
+			map[i].rf1   = rf_freq[RF1] / 1000;
+			break;
+		case RF2:
+			map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] -
+					prog_cal[RF1] + prog_tab[RF1]) /
+				((rf_freq[RF2] - rf_freq[RF1]) / 1000);
+			map[i].rf2   = rf_freq[RF2] / 1000;
+			break;
+		case RF3:
+			map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] -
+					prog_cal[RF2] + prog_tab[RF2]) /
+				((rf_freq[RF3] - rf_freq[RF2]) / 1000);
+			map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2];
+			map[i].rf3   = rf_freq[RF3] / 1000;
+			break;
+		default:
+			BUG();
+		}
+	}
+
+	return 0;
+}
+
+static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned int i;
+
+	tda_info("tda18271: performing RF tracking filter calibration\n");
+
+	/* wait for die temperature stabilization */
+	msleep(200);
+
+	tda18271_powerscan_init(fe);
+
+	/* rf band calibration */
+	for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++)
+		tda18271_rf_tracking_filters_init(fe, 1000 *
+						  priv->rf_cal_state[i].rfmax);
+
+	priv->tm_rfcal = tda18271_read_thermometer(fe);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_rf_cal_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+
+	/* test RF_CAL_OK to see if we need init */
+	if ((regs[R_EP1] & 0x10) == 0)
+		priv->cal_initialized = false;
+
+	if (priv->cal_initialized)
+		return 0;
+
+	tda18271_calc_rf_filter_curve(fe);
+
+	tda18271_por(fe);
+
+	tda_info("tda18271: RF tracking filter calibration complete\n");
+
+	priv->cal_initialized = true;
+
+	return 0;
+}
+
+static int tda18271_init(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	mutex_lock(&priv->lock);
+
+	/* power up */
+	tda18271_set_standby_mode(fe, 0, 0, 0);
+
+	/* initialization */
+	tda18271_ir_cal_init(fe);
+
+	if (priv->id == TDA18271HDC2)
+		tda18271_rf_cal_init(fe);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int tda18271c2_tune(struct dvb_frontend *fe,
+			   u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
+
+	tda18271_init(fe);
+
+	mutex_lock(&priv->lock);
+
+	tda18271_rf_tracking_filters_correction(fe, freq);
+
+	tda18271_channel_configuration(fe, ifc, freq, bw, std, radio);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271c1_tune(struct dvb_frontend *fe,
+			   u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	u32 N = 0;
+
+	tda18271_init(fe);
+
+	mutex_lock(&priv->lock);
+
+	tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
+
+	/* RF tracking filter calibration */
+
+	/* calculate bp filter */
+	tda18271_calc_bp_filter(fe, &freq);
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	regs[R_EB4]  &= 0x07;
+	regs[R_EB4]  |= 0x60;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	regs[R_EB7]   = 0x60;
+	tda18271_write_regs(fe, R_EB7, 1);
+
+	regs[R_EB14]  = 0x00;
+	tda18271_write_regs(fe, R_EB14, 1);
+
+	regs[R_EB20]  = 0xcc;
+	tda18271_write_regs(fe, R_EB20, 1);
+
+	/* set cal mode to RF tracking filter calibration */
+	regs[R_EP4]  |= 0x03;
+
+	/* calculate cal pll */
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		N = freq - 1250000;
+		break;
+	case TDA18271_DIGITAL:
+		N = freq + bw / 2;
+		break;
+	}
+
+	tda18271_calc_cal_pll(fe, N);
+
+	/* calculate main pll */
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		N = freq - 250000;
+		break;
+	case TDA18271_DIGITAL:
+		N = freq + bw / 2 + 1000000;
+		break;
+	}
+
+	tda18271_calc_main_pll(fe, N);
+
+	tda18271_write_regs(fe, R_EP3, 11);
+	msleep(5); /* RF tracking filter calibration initialization */
+
+	/* search for K,M,CO for RF calibration */
+	tda18271_calc_km(fe, &freq);
+	tda18271_write_regs(fe, R_EB13, 1);
+
+	/* search for rf band */
+	tda18271_calc_rf_band(fe, &freq);
+
+	/* search for gain taper */
+	tda18271_calc_gain_taper(fe, &freq);
+
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+	tda18271_write_regs(fe, R_EP2, 1);
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	regs[R_EB4]  &= 0x07;
+	regs[R_EB4]  |= 0x40;
+	tda18271_write_regs(fe, R_EB4, 1);
+
+	regs[R_EB7]   = 0x40;
+	tda18271_write_regs(fe, R_EB7, 1);
+	msleep(10);
+
+	regs[R_EB20]  = 0xec;
+	tda18271_write_regs(fe, R_EB20, 1);
+	msleep(60); /* RF tracking filter calibration completion */
+
+	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
+	tda18271_write_regs(fe, R_EP4, 1);
+
+	tda18271_write_regs(fe, R_EP1, 1);
+
+	/* RF tracking filter correction for VHF_Low band */
+	if (0 == tda18271_calc_rf_cal(fe, &freq))
+		tda18271_write_regs(fe, R_EB14, 1);
+
+	/* Channel Configuration */
+
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_EB22]  = 0x2c;
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_EB22]  = 0x37;
+		break;
+	}
+	tda18271_write_regs(fe, R_EB22, 1);
+
+	regs[R_EP1]  |= 0x40; /* set dis power level on */
+
+	/* set standard */
+	regs[R_EP3]  &= ~0x1f; /* clear std bits */
+
+	/* see table 22 */
+	regs[R_EP3]  |= std;
+
+	regs[R_EP4]  &= ~0x03; /* set cal mode to normal */
+
+	regs[R_EP4]  &= ~0x1c; /* clear if level bits */
+	switch (priv->mode) {
+	case TDA18271_ANALOG:
+		regs[R_MPD]  &= ~0x80; /* IF notch = 0 */
+		break;
+	case TDA18271_DIGITAL:
+		regs[R_EP4]  |= 0x04;
+		regs[R_MPD]  |= 0x80;
+		break;
+	}
+
+	if (radio)
+		regs[R_EP4]  |=  0x80;
+	else
+		regs[R_EP4]  &= ~0x80;
+
+	/* image rejection validity */
+	tda18271_calc_ir_measure(fe, &freq);
+
+	/* calculate MAIN PLL */
+	N = freq + ifc;
+
+	tda18271_calc_main_pll(fe, N);
+
+	tda18271_write_regs(fe, R_TM, 15);
+	msleep(5);
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static inline int tda18271_tune(struct dvb_frontend *fe,
+				u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio);
+		break;
+	case TDA18271HDC2:
+		ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio);
+		break;
+	}
+	return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int tda18271_set_params(struct dvb_frontend *fe,
+			       struct dvb_frontend_parameters *params)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std_map = &priv->std;
+	int ret;
+	u8 std;
+	u16 sgIF;
+	u32 bw, freq = params->frequency;
+
+	priv->mode = TDA18271_DIGITAL;
+
+	if (fe->ops.info.type == FE_ATSC) {
+		switch (params->u.vsb.modulation) {
+		case VSB_8:
+		case VSB_16:
+			std  = std_map->atsc_6.std_bits;
+			sgIF = std_map->atsc_6.if_freq;
+			break;
+		case QAM_64:
+		case QAM_256:
+			std  = std_map->qam_6.std_bits;
+			sgIF = std_map->qam_6.if_freq;
+			break;
+		default:
+			tda_warn("modulation not set!\n");
+			return -EINVAL;
+		}
+#if 0
+		/* userspace request is already center adjusted */
+		freq += 1750000; /* Adjust to center (+1.75MHZ) */
+#endif
+		bw = 6000000;
+	} else if (fe->ops.info.type == FE_OFDM) {
+		switch (params->u.ofdm.bandwidth) {
+		case BANDWIDTH_6_MHZ:
+			bw = 6000000;
+			std  = std_map->dvbt_6.std_bits;
+			sgIF = std_map->dvbt_6.if_freq;
+			break;
+		case BANDWIDTH_7_MHZ:
+			bw = 7000000;
+			std  = std_map->dvbt_7.std_bits;
+			sgIF = std_map->dvbt_7.if_freq;
+			break;
+		case BANDWIDTH_8_MHZ:
+			bw = 8000000;
+			std  = std_map->dvbt_8.std_bits;
+			sgIF = std_map->dvbt_8.if_freq;
+			break;
+		default:
+			tda_warn("bandwidth not set!\n");
+			return -EINVAL;
+		}
+	} else {
+		tda_warn("modulation type not supported!\n");
+		return -EINVAL;
+	}
+
+	/* When tuning digital, the analog demod must be tri-stated */
+	if (fe->ops.analog_ops.standby)
+		fe->ops.analog_ops.standby(fe);
+
+	ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0);
+
+	if (ret < 0)
+		goto fail;
+
+	priv->frequency = freq;
+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
+		params->u.ofdm.bandwidth : 0;
+fail:
+	return ret;
+}
+
+static int tda18271_set_analog_params(struct dvb_frontend *fe,
+				      struct analog_parameters *params)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std_map = &priv->std;
+	char *mode;
+	int ret, radio = 0;
+	u8 std;
+	u16 sgIF;
+	u32 freq = params->frequency * 62500;
+
+	priv->mode = TDA18271_ANALOG;
+
+	if (params->mode == V4L2_TUNER_RADIO) {
+		radio = 1;
+		freq = freq / 1000;
+		std  = std_map->fm_radio.std_bits;
+		sgIF = std_map->fm_radio.if_freq;
+		mode = "fm";
+	} else if (params->std & V4L2_STD_MN) {
+		std  = std_map->atv_mn.std_bits;
+		sgIF = std_map->atv_mn.if_freq;
+		mode = "MN";
+	} else if (params->std & V4L2_STD_B) {
+		std  = std_map->atv_b.std_bits;
+		sgIF = std_map->atv_b.if_freq;
+		mode = "B";
+	} else if (params->std & V4L2_STD_GH) {
+		std  = std_map->atv_gh.std_bits;
+		sgIF = std_map->atv_gh.if_freq;
+		mode = "GH";
+	} else if (params->std & V4L2_STD_PAL_I) {
+		std  = std_map->atv_i.std_bits;
+		sgIF = std_map->atv_i.if_freq;
+		mode = "I";
+	} else if (params->std & V4L2_STD_DK) {
+		std  = std_map->atv_dk.std_bits;
+		sgIF = std_map->atv_dk.if_freq;
+		mode = "DK";
+	} else if (params->std & V4L2_STD_SECAM_L) {
+		std  = std_map->atv_l.std_bits;
+		sgIF = std_map->atv_l.if_freq;
+		mode = "L";
+	} else if (params->std & V4L2_STD_SECAM_LC) {
+		std  = std_map->atv_lc.std_bits;
+		sgIF = std_map->atv_lc.if_freq;
+		mode = "L'";
+	} else {
+		std  = std_map->atv_i.std_bits;
+		sgIF = std_map->atv_i.if_freq;
+		mode = "xx";
+	}
+
+	tda_dbg("setting tda18271 to system %s\n", mode);
+
+	ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio);
+
+	if (ret < 0)
+		goto fail;
+
+	priv->frequency = freq;
+	priv->bandwidth = 0;
+fail:
+	return ret;
+}
+
+static int tda18271_sleep(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	mutex_lock(&priv->lock);
+
+	/* standby mode w/ slave tuner output
+	 * & loop thru & xtal oscillator on */
+	tda18271_set_standby_mode(fe, 1, 0, 0);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int tda18271_release(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+
+	mutex_lock(&tda18271_list_mutex);
+
+	priv->count--;
+
+	if (!priv->count) {
+		tda_dbg("destroying instance @ %d-%04x\n",
+			i2c_adapter_id(priv->i2c_adap),
+			priv->i2c_addr);
+		list_del(&priv->tda18271_list);
+
+		kfree(priv);
+	}
+	mutex_unlock(&tda18271_list_mutex);
+
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+#define tda18271_update_std(std_cfg, name) do {				\
+	if (map->std_cfg.if_freq + map->std_cfg.std_bits > 0) {		\
+		tda_dbg("Using custom std config for %s\n", name);	\
+		memcpy(&std->std_cfg, &map->std_cfg,			\
+			sizeof(struct tda18271_std_map_item));		\
+	} } while (0)
+
+#define tda18271_dump_std_item(std_cfg, name) do {			\
+	tda_dbg("(%s) if freq = %d, std bits = 0x%02x\n",		\
+		name, std->std_cfg.if_freq, std->std_cfg.std_bits);	\
+	} while (0)
+
+static int tda18271_dump_std_map(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std = &priv->std;
+
+	tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
+	tda18271_dump_std_item(fm_radio, "fm");
+	tda18271_dump_std_item(atv_b,  "pal b");
+	tda18271_dump_std_item(atv_dk, "pal dk");
+	tda18271_dump_std_item(atv_gh, "pal gh");
+	tda18271_dump_std_item(atv_i,  "pal i");
+	tda18271_dump_std_item(atv_l,  "pal l");
+	tda18271_dump_std_item(atv_lc, "pal l'");
+	tda18271_dump_std_item(atv_mn, "atv mn");
+	tda18271_dump_std_item(atsc_6, "atsc 6");
+	tda18271_dump_std_item(dvbt_6, "dvbt 6");
+	tda18271_dump_std_item(dvbt_7, "dvbt 7");
+	tda18271_dump_std_item(dvbt_8, "dvbt 8");
+	tda18271_dump_std_item(qam_6,  "qam 6");
+	tda18271_dump_std_item(qam_8,  "qam 8");
+
+	return 0;
+}
+
+static int tda18271_update_std_map(struct dvb_frontend *fe,
+				   struct tda18271_std_map *map)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_std_map *std = &priv->std;
+
+	if (!map)
+		return -EINVAL;
+
+	tda18271_update_std(fm_radio, "fm");
+	tda18271_update_std(atv_b,  "atv b");
+	tda18271_update_std(atv_dk, "atv dk");
+	tda18271_update_std(atv_gh, "atv gh");
+	tda18271_update_std(atv_i,  "atv i");
+	tda18271_update_std(atv_l,  "atv l");
+	tda18271_update_std(atv_lc, "atv l'");
+	tda18271_update_std(atv_mn, "atv mn");
+	tda18271_update_std(atsc_6, "atsc 6");
+	tda18271_update_std(dvbt_6, "dvbt 6");
+	tda18271_update_std(dvbt_7, "dvbt 7");
+	tda18271_update_std(dvbt_8, "dvbt 8");
+	tda18271_update_std(qam_6,  "qam 6");
+	tda18271_update_std(qam_8,  "qam 8");
+
+	return 0;
+}
+
+static int tda18271_get_id(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	char *name;
+	int ret = 0;
+
+	mutex_lock(&priv->lock);
+	tda18271_read_regs(fe);
+	mutex_unlock(&priv->lock);
+
+	switch (regs[R_ID] & 0x7f) {
+	case 3:
+		name = "TDA18271HD/C1";
+		priv->id = TDA18271HDC1;
+		break;
+	case 4:
+		name = "TDA18271HD/C2";
+		priv->id = TDA18271HDC2;
+		break;
+	default:
+		name = "Unknown device";
+		ret = -EINVAL;
+		break;
+	}
+
+	tda_info("%s detected @ %d-%04x%s\n", name,
+		 i2c_adapter_id(priv->i2c_adap), priv->i2c_addr,
+		 (0 == ret) ? "" : ", device not supported.");
+
+	return ret;
+}
+
+static struct dvb_tuner_ops tda18271_tuner_ops = {
+	.info = {
+		.name = "NXP TDA18271HD",
+		.frequency_min  =  45000000,
+		.frequency_max  = 864000000,
+		.frequency_step =     62500
+	},
+	.init              = tda18271_init,
+	.sleep             = tda18271_sleep,
+	.set_params        = tda18271_set_params,
+	.set_analog_params = tda18271_set_analog_params,
+	.release           = tda18271_release,
+	.get_frequency     = tda18271_get_frequency,
+	.get_bandwidth     = tda18271_get_bandwidth,
+};
+
+struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
+				     struct i2c_adapter *i2c,
+				     struct tda18271_config *cfg)
+{
+	struct tda18271_priv *priv = NULL;
+	int state_found = 0;
+
+	mutex_lock(&tda18271_list_mutex);
+
+	list_for_each_entry(priv, &tda18271_list, tda18271_list) {
+		if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) &&
+		    (priv->i2c_addr == addr)) {
+			tda_dbg("attaching existing tuner @ %d-%04x\n",
+				i2c_adapter_id(priv->i2c_adap),
+				priv->i2c_addr);
+			priv->count++;
+			fe->tuner_priv = priv;
+			state_found = 1;
+			/* allow dvb driver to override i2c gate setting */
+			if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
+				priv->gate = cfg->gate;
+			break;
+		}
+	}
+	if (state_found == 0) {
+		tda_dbg("creating new tuner instance @ %d-%04x\n",
+			i2c_adapter_id(i2c), addr);
+
+		priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
+		if (priv == NULL) {
+			mutex_unlock(&tda18271_list_mutex);
+			return NULL;
+		}
+
+		priv->i2c_addr = addr;
+		priv->i2c_adap = i2c;
+		priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
+		priv->cal_initialized = false;
+		mutex_init(&priv->lock);
+		priv->count++;
+
+		fe->tuner_priv = priv;
+
+		list_add_tail(&priv->tda18271_list, &tda18271_list);
+
+		if (tda18271_get_id(fe) < 0)
+			goto fail;
+
+		if (tda18271_assign_map_layout(fe) < 0)
+			goto fail;
+
+		mutex_lock(&priv->lock);
+		tda18271_init_regs(fe);
+
+		if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2))
+			tda18271_rf_cal_init(fe);
+
+		mutex_unlock(&priv->lock);
+	}
+
+	/* override default std map with values in config struct */
+	if ((cfg) && (cfg->std_map))
+		tda18271_update_std_map(fe, cfg->std_map);
+
+	mutex_unlock(&tda18271_list_mutex);
+
+	memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	if (tda18271_debug & DBG_MAP)
+		tda18271_dump_std_map(fe);
+
+	return fe;
+fail:
+	mutex_unlock(&tda18271_list_mutex);
+
+	tda18271_release(fe);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(tda18271_attach);
+MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h
new file mode 100644
index 000000000000..7b939a5325fb
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda18271-priv.h
@@ -0,0 +1,212 @@
+/*
+    tda18271-priv.h - private header for the NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.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.
+*/
+
+#ifndef __TDA18271_PRIV_H__
+#define __TDA18271_PRIV_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include "tda18271.h"
+
+#define R_ID     0x00	/* ID byte                */
+#define R_TM     0x01	/* Thermo byte            */
+#define R_PL     0x02	/* Power level byte       */
+#define R_EP1    0x03	/* Easy Prog byte 1       */
+#define R_EP2    0x04	/* Easy Prog byte 2       */
+#define R_EP3    0x05	/* Easy Prog byte 3       */
+#define R_EP4    0x06	/* Easy Prog byte 4       */
+#define R_EP5    0x07	/* Easy Prog byte 5       */
+#define R_CPD    0x08	/* Cal Post-Divider byte  */
+#define R_CD1    0x09	/* Cal Divider byte 1     */
+#define R_CD2    0x0a	/* Cal Divider byte 2     */
+#define R_CD3    0x0b	/* Cal Divider byte 3     */
+#define R_MPD    0x0c	/* Main Post-Divider byte */
+#define R_MD1    0x0d	/* Main Divider byte 1    */
+#define R_MD2    0x0e	/* Main Divider byte 2    */
+#define R_MD3    0x0f	/* Main Divider byte 3    */
+#define R_EB1    0x10	/* Extended byte 1        */
+#define R_EB2    0x11	/* Extended byte 2        */
+#define R_EB3    0x12	/* Extended byte 3        */
+#define R_EB4    0x13	/* Extended byte 4        */
+#define R_EB5    0x14	/* Extended byte 5        */
+#define R_EB6    0x15	/* Extended byte 6        */
+#define R_EB7    0x16	/* Extended byte 7        */
+#define R_EB8    0x17	/* Extended byte 8        */
+#define R_EB9    0x18	/* Extended byte 9        */
+#define R_EB10   0x19	/* Extended byte 10       */
+#define R_EB11   0x1a	/* Extended byte 11       */
+#define R_EB12   0x1b	/* Extended byte 12       */
+#define R_EB13   0x1c	/* Extended byte 13       */
+#define R_EB14   0x1d	/* Extended byte 14       */
+#define R_EB15   0x1e	/* Extended byte 15       */
+#define R_EB16   0x1f	/* Extended byte 16       */
+#define R_EB17   0x20	/* Extended byte 17       */
+#define R_EB18   0x21	/* Extended byte 18       */
+#define R_EB19   0x22	/* Extended byte 19       */
+#define R_EB20   0x23	/* Extended byte 20       */
+#define R_EB21   0x24	/* Extended byte 21       */
+#define R_EB22   0x25	/* Extended byte 22       */
+#define R_EB23   0x26	/* Extended byte 23       */
+
+#define TDA18271_NUM_REGS 39
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_rf_tracking_filter_cal {
+	u32 rfmax;
+	u8  rfband;
+	u32 rf1_def;
+	u32 rf2_def;
+	u32 rf3_def;
+	u32 rf1;
+	u32 rf2;
+	u32 rf3;
+	int rf_a1;
+	int rf_b1;
+	int rf_a2;
+	int rf_b2;
+};
+
+enum tda18271_mode {
+	TDA18271_ANALOG,
+	TDA18271_DIGITAL,
+};
+
+struct tda18271_map_layout;
+
+enum tda18271_ver {
+	TDA18271HDC1,
+	TDA18271HDC2,
+};
+
+struct tda18271_priv {
+	u8 i2c_addr;
+	struct i2c_adapter *i2c_adap;
+	unsigned char tda18271_regs[TDA18271_NUM_REGS];
+
+	struct list_head tda18271_list;
+
+	enum tda18271_mode mode;
+	enum tda18271_i2c_gate gate;
+	enum tda18271_ver id;
+
+	unsigned int count;
+	unsigned int tm_rfcal;
+	unsigned int cal_initialized:1;
+
+	struct tda18271_map_layout *maps;
+	struct tda18271_std_map std;
+	struct tda18271_rf_tracking_filter_cal rf_cal_state[8];
+
+	struct mutex lock;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+/*---------------------------------------------------------------------*/
+
+extern int tda18271_debug;
+
+#define DBG_INFO 1
+#define DBG_MAP  2
+#define DBG_REG  4
+#define DBG_ADV  8
+#define DBG_CAL  16
+
+#define tda_printk(kern, fmt, arg...) \
+	printk(kern "%s: " fmt, __FUNCTION__, ##arg)
+
+#define dprintk(kern, lvl, fmt, arg...) do {\
+	if (tda18271_debug & lvl) \
+		tda_printk(kern, fmt, ##arg); } while (0)
+
+#define tda_info(fmt, arg...) printk(KERN_INFO              fmt, ##arg)
+#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING,      fmt, ##arg)
+#define tda_err(fmt, arg...)  tda_printk(KERN_ERR,          fmt, ##arg)
+#define tda_dbg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg)
+#define tda_map(fmt, arg...)  dprintk(KERN_DEBUG, DBG_MAP,  fmt, ##arg)
+#define tda_reg(fmt, arg...)  dprintk(KERN_DEBUG, DBG_REG,  fmt, ##arg)
+#define tda_cal(fmt, arg...)  dprintk(KERN_DEBUG, DBG_CAL,  fmt, ##arg)
+
+/*---------------------------------------------------------------------*/
+
+enum tda18271_map_type {
+	/* tda18271_pll_map */
+	MAIN_PLL,
+	CAL_PLL,
+	/* tda18271_map */
+	RF_CAL,
+	RF_CAL_KMCO,
+	RF_CAL_DC_OVER_DT,
+	BP_FILTER,
+	RF_BAND,
+	GAIN_TAPER,
+	IR_MEASURE,
+};
+
+extern int tda18271_lookup_pll_map(struct dvb_frontend *fe,
+				   enum tda18271_map_type map_type,
+				   u32 *freq, u8 *post_div, u8 *div);
+extern int tda18271_lookup_map(struct dvb_frontend *fe,
+			       enum tda18271_map_type map_type,
+			       u32 *freq, u8 *val);
+
+extern int tda18271_lookup_thermometer(struct dvb_frontend *fe);
+
+extern int tda18271_lookup_rf_band(struct dvb_frontend *fe,
+				   u32 *freq, u8 *rf_band);
+
+extern int tda18271_lookup_cid_target(struct dvb_frontend *fe,
+				      u32 *freq, u8 *cid_target,
+				      u16 *count_limit);
+
+extern int tda18271_assign_map_layout(struct dvb_frontend *fe);
+
+/*---------------------------------------------------------------------*/
+
+extern int tda18271_read_regs(struct dvb_frontend *fe);
+extern int tda18271_read_extended(struct dvb_frontend *fe);
+extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len);
+extern int tda18271_init_regs(struct dvb_frontend *fe);
+
+extern int tda18271_set_standby_mode(struct dvb_frontend *fe,
+				     int sm, int sm_lt, int sm_xt);
+
+extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq);
+extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq);
+
+extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq);
+extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq);
+
+#endif /* __TDA18271_PRIV_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c
new file mode 100644
index 000000000000..e94afcfdc5bc
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda18271-tables.c
@@ -0,0 +1,1285 @@
+/*
+    tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.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 "tda18271-priv.h"
+
+struct tda18271_pll_map {
+	u32 lomax;
+	u8 pd; /* post div */
+	u8 d;  /*      div */
+};
+
+struct tda18271_map {
+	u32 rfmax;
+	u8  val;
+};
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_pll_map tda18271c1_main_pll[] = {
+	{ .lomax =  32000, .pd = 0x5f, .d = 0xf0 },
+	{ .lomax =  35000, .pd = 0x5e, .d = 0xe0 },
+	{ .lomax =  37000, .pd = 0x5d, .d = 0xd0 },
+	{ .lomax =  41000, .pd = 0x5c, .d = 0xc0 },
+	{ .lomax =  44000, .pd = 0x5b, .d = 0xb0 },
+	{ .lomax =  49000, .pd = 0x5a, .d = 0xa0 },
+	{ .lomax =  54000, .pd = 0x59, .d = 0x90 },
+	{ .lomax =  61000, .pd = 0x58, .d = 0x80 },
+	{ .lomax =  65000, .pd = 0x4f, .d = 0x78 },
+	{ .lomax =  70000, .pd = 0x4e, .d = 0x70 },
+	{ .lomax =  75000, .pd = 0x4d, .d = 0x68 },
+	{ .lomax =  82000, .pd = 0x4c, .d = 0x60 },
+	{ .lomax =  89000, .pd = 0x4b, .d = 0x58 },
+	{ .lomax =  98000, .pd = 0x4a, .d = 0x50 },
+	{ .lomax = 109000, .pd = 0x49, .d = 0x48 },
+	{ .lomax = 123000, .pd = 0x48, .d = 0x40 },
+	{ .lomax = 131000, .pd = 0x3f, .d = 0x3c },
+	{ .lomax = 141000, .pd = 0x3e, .d = 0x38 },
+	{ .lomax = 151000, .pd = 0x3d, .d = 0x34 },
+	{ .lomax = 164000, .pd = 0x3c, .d = 0x30 },
+	{ .lomax = 179000, .pd = 0x3b, .d = 0x2c },
+	{ .lomax = 197000, .pd = 0x3a, .d = 0x28 },
+	{ .lomax = 219000, .pd = 0x39, .d = 0x24 },
+	{ .lomax = 246000, .pd = 0x38, .d = 0x20 },
+	{ .lomax = 263000, .pd = 0x2f, .d = 0x1e },
+	{ .lomax = 282000, .pd = 0x2e, .d = 0x1c },
+	{ .lomax = 303000, .pd = 0x2d, .d = 0x1a },
+	{ .lomax = 329000, .pd = 0x2c, .d = 0x18 },
+	{ .lomax = 359000, .pd = 0x2b, .d = 0x16 },
+	{ .lomax = 395000, .pd = 0x2a, .d = 0x14 },
+	{ .lomax = 438000, .pd = 0x29, .d = 0x12 },
+	{ .lomax = 493000, .pd = 0x28, .d = 0x10 },
+	{ .lomax = 526000, .pd = 0x1f, .d = 0x0f },
+	{ .lomax = 564000, .pd = 0x1e, .d = 0x0e },
+	{ .lomax = 607000, .pd = 0x1d, .d = 0x0d },
+	{ .lomax = 658000, .pd = 0x1c, .d = 0x0c },
+	{ .lomax = 718000, .pd = 0x1b, .d = 0x0b },
+	{ .lomax = 790000, .pd = 0x1a, .d = 0x0a },
+	{ .lomax = 877000, .pd = 0x19, .d = 0x09 },
+	{ .lomax = 987000, .pd = 0x18, .d = 0x08 },
+	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c2_main_pll[] = {
+	{ .lomax =  33125, .pd = 0x57, .d = 0xf0 },
+	{ .lomax =  35500, .pd = 0x56, .d = 0xe0 },
+	{ .lomax =  38188, .pd = 0x55, .d = 0xd0 },
+	{ .lomax =  41375, .pd = 0x54, .d = 0xc0 },
+	{ .lomax =  45125, .pd = 0x53, .d = 0xb0 },
+	{ .lomax =  49688, .pd = 0x52, .d = 0xa0 },
+	{ .lomax =  55188, .pd = 0x51, .d = 0x90 },
+	{ .lomax =  62125, .pd = 0x50, .d = 0x80 },
+	{ .lomax =  66250, .pd = 0x47, .d = 0x78 },
+	{ .lomax =  71000, .pd = 0x46, .d = 0x70 },
+	{ .lomax =  76375, .pd = 0x45, .d = 0x68 },
+	{ .lomax =  82750, .pd = 0x44, .d = 0x60 },
+	{ .lomax =  90250, .pd = 0x43, .d = 0x58 },
+	{ .lomax =  99375, .pd = 0x42, .d = 0x50 },
+	{ .lomax = 110375, .pd = 0x41, .d = 0x48 },
+	{ .lomax = 124250, .pd = 0x40, .d = 0x40 },
+	{ .lomax = 132500, .pd = 0x37, .d = 0x3c },
+	{ .lomax = 142000, .pd = 0x36, .d = 0x38 },
+	{ .lomax = 152750, .pd = 0x35, .d = 0x34 },
+	{ .lomax = 165500, .pd = 0x34, .d = 0x30 },
+	{ .lomax = 180500, .pd = 0x33, .d = 0x2c },
+	{ .lomax = 198750, .pd = 0x32, .d = 0x28 },
+	{ .lomax = 220750, .pd = 0x31, .d = 0x24 },
+	{ .lomax = 248500, .pd = 0x30, .d = 0x20 },
+	{ .lomax = 265000, .pd = 0x27, .d = 0x1e },
+	{ .lomax = 284000, .pd = 0x26, .d = 0x1c },
+	{ .lomax = 305500, .pd = 0x25, .d = 0x1a },
+	{ .lomax = 331000, .pd = 0x24, .d = 0x18 },
+	{ .lomax = 361000, .pd = 0x23, .d = 0x16 },
+	{ .lomax = 397500, .pd = 0x22, .d = 0x14 },
+	{ .lomax = 441500, .pd = 0x21, .d = 0x12 },
+	{ .lomax = 497000, .pd = 0x20, .d = 0x10 },
+	{ .lomax = 530000, .pd = 0x17, .d = 0x0f },
+	{ .lomax = 568000, .pd = 0x16, .d = 0x0e },
+	{ .lomax = 611000, .pd = 0x15, .d = 0x0d },
+	{ .lomax = 662000, .pd = 0x14, .d = 0x0c },
+	{ .lomax = 722000, .pd = 0x13, .d = 0x0b },
+	{ .lomax = 795000, .pd = 0x12, .d = 0x0a },
+	{ .lomax = 883000, .pd = 0x11, .d = 0x09 },
+	{ .lomax = 994000, .pd = 0x10, .d = 0x08 },
+	{ .lomax =      0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c1_cal_pll[] = {
+	{ .lomax =   33000, .pd = 0xdd, .d = 0xd0 },
+	{ .lomax =   36000, .pd = 0xdc, .d = 0xc0 },
+	{ .lomax =   40000, .pd = 0xdb, .d = 0xb0 },
+	{ .lomax =   44000, .pd = 0xda, .d = 0xa0 },
+	{ .lomax =   49000, .pd = 0xd9, .d = 0x90 },
+	{ .lomax =   55000, .pd = 0xd8, .d = 0x80 },
+	{ .lomax =   63000, .pd = 0xd3, .d = 0x70 },
+	{ .lomax =   67000, .pd = 0xcd, .d = 0x68 },
+	{ .lomax =   73000, .pd = 0xcc, .d = 0x60 },
+	{ .lomax =   80000, .pd = 0xcb, .d = 0x58 },
+	{ .lomax =   88000, .pd = 0xca, .d = 0x50 },
+	{ .lomax =   98000, .pd = 0xc9, .d = 0x48 },
+	{ .lomax =  110000, .pd = 0xc8, .d = 0x40 },
+	{ .lomax =  126000, .pd = 0xc3, .d = 0x38 },
+	{ .lomax =  135000, .pd = 0xbd, .d = 0x34 },
+	{ .lomax =  147000, .pd = 0xbc, .d = 0x30 },
+	{ .lomax =  160000, .pd = 0xbb, .d = 0x2c },
+	{ .lomax =  176000, .pd = 0xba, .d = 0x28 },
+	{ .lomax =  196000, .pd = 0xb9, .d = 0x24 },
+	{ .lomax =  220000, .pd = 0xb8, .d = 0x20 },
+	{ .lomax =  252000, .pd = 0xb3, .d = 0x1c },
+	{ .lomax =  271000, .pd = 0xad, .d = 0x1a },
+	{ .lomax =  294000, .pd = 0xac, .d = 0x18 },
+	{ .lomax =  321000, .pd = 0xab, .d = 0x16 },
+	{ .lomax =  353000, .pd = 0xaa, .d = 0x14 },
+	{ .lomax =  392000, .pd = 0xa9, .d = 0x12 },
+	{ .lomax =  441000, .pd = 0xa8, .d = 0x10 },
+	{ .lomax =  505000, .pd = 0xa3, .d = 0x0e },
+	{ .lomax =  543000, .pd = 0x9d, .d = 0x0d },
+	{ .lomax =  589000, .pd = 0x9c, .d = 0x0c },
+	{ .lomax =  642000, .pd = 0x9b, .d = 0x0b },
+	{ .lomax =  707000, .pd = 0x9a, .d = 0x0a },
+	{ .lomax =  785000, .pd = 0x99, .d = 0x09 },
+	{ .lomax =  883000, .pd = 0x98, .d = 0x08 },
+	{ .lomax = 1010000, .pd = 0x93, .d = 0x07 },
+	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_pll_map tda18271c2_cal_pll[] = {
+	{ .lomax =   33813, .pd = 0xdd, .d = 0xd0 },
+	{ .lomax =   36625, .pd = 0xdc, .d = 0xc0 },
+	{ .lomax =   39938, .pd = 0xdb, .d = 0xb0 },
+	{ .lomax =   43938, .pd = 0xda, .d = 0xa0 },
+	{ .lomax =   48813, .pd = 0xd9, .d = 0x90 },
+	{ .lomax =   54938, .pd = 0xd8, .d = 0x80 },
+	{ .lomax =   62813, .pd = 0xd3, .d = 0x70 },
+	{ .lomax =   67625, .pd = 0xcd, .d = 0x68 },
+	{ .lomax =   73250, .pd = 0xcc, .d = 0x60 },
+	{ .lomax =   79875, .pd = 0xcb, .d = 0x58 },
+	{ .lomax =   87875, .pd = 0xca, .d = 0x50 },
+	{ .lomax =   97625, .pd = 0xc9, .d = 0x48 },
+	{ .lomax =  109875, .pd = 0xc8, .d = 0x40 },
+	{ .lomax =  125625, .pd = 0xc3, .d = 0x38 },
+	{ .lomax =  135250, .pd = 0xbd, .d = 0x34 },
+	{ .lomax =  146500, .pd = 0xbc, .d = 0x30 },
+	{ .lomax =  159750, .pd = 0xbb, .d = 0x2c },
+	{ .lomax =  175750, .pd = 0xba, .d = 0x28 },
+	{ .lomax =  195250, .pd = 0xb9, .d = 0x24 },
+	{ .lomax =  219750, .pd = 0xb8, .d = 0x20 },
+	{ .lomax =  251250, .pd = 0xb3, .d = 0x1c },
+	{ .lomax =  270500, .pd = 0xad, .d = 0x1a },
+	{ .lomax =  293000, .pd = 0xac, .d = 0x18 },
+	{ .lomax =  319500, .pd = 0xab, .d = 0x16 },
+	{ .lomax =  351500, .pd = 0xaa, .d = 0x14 },
+	{ .lomax =  390500, .pd = 0xa9, .d = 0x12 },
+	{ .lomax =  439500, .pd = 0xa8, .d = 0x10 },
+	{ .lomax =  502500, .pd = 0xa3, .d = 0x0e },
+	{ .lomax =  541000, .pd = 0x9d, .d = 0x0d },
+	{ .lomax =  586000, .pd = 0x9c, .d = 0x0c },
+	{ .lomax =  639000, .pd = 0x9b, .d = 0x0b },
+	{ .lomax =  703000, .pd = 0x9a, .d = 0x0a },
+	{ .lomax =  781000, .pd = 0x99, .d = 0x09 },
+	{ .lomax =  879000, .pd = 0x98, .d = 0x08 },
+	{ .lomax =       0, .pd = 0x00, .d = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_bp_filter[] = {
+	{ .rfmax =  62000, .val = 0x00 },
+	{ .rfmax =  84000, .val = 0x01 },
+	{ .rfmax = 100000, .val = 0x02 },
+	{ .rfmax = 140000, .val = 0x03 },
+	{ .rfmax = 170000, .val = 0x04 },
+	{ .rfmax = 180000, .val = 0x05 },
+	{ .rfmax = 865000, .val = 0x06 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c1_km[] = {
+	{ .rfmax =  61100, .val = 0x74 },
+	{ .rfmax = 350000, .val = 0x40 },
+	{ .rfmax = 720000, .val = 0x30 },
+	{ .rfmax = 865000, .val = 0x40 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c2_km[] = {
+	{ .rfmax =  47900, .val = 0x38 },
+	{ .rfmax =  61100, .val = 0x44 },
+	{ .rfmax = 350000, .val = 0x30 },
+	{ .rfmax = 720000, .val = 0x24 },
+	{ .rfmax = 865000, .val = 0x3c },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_rf_band[] = {
+	{ .rfmax =  47900, .val = 0x00 },
+	{ .rfmax =  61100, .val = 0x01 },
+/*	{ .rfmax = 152600, .val = 0x02 }, */
+	{ .rfmax = 121200, .val = 0x02 },
+	{ .rfmax = 164700, .val = 0x03 },
+	{ .rfmax = 203500, .val = 0x04 },
+	{ .rfmax = 457800, .val = 0x05 },
+	{ .rfmax = 865000, .val = 0x06 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_gain_taper[] = {
+	{ .rfmax =  45400, .val = 0x1f },
+	{ .rfmax =  45800, .val = 0x1e },
+	{ .rfmax =  46200, .val = 0x1d },
+	{ .rfmax =  46700, .val = 0x1c },
+	{ .rfmax =  47100, .val = 0x1b },
+	{ .rfmax =  47500, .val = 0x1a },
+	{ .rfmax =  47900, .val = 0x19 },
+	{ .rfmax =  49600, .val = 0x17 },
+	{ .rfmax =  51200, .val = 0x16 },
+	{ .rfmax =  52900, .val = 0x15 },
+	{ .rfmax =  54500, .val = 0x14 },
+	{ .rfmax =  56200, .val = 0x13 },
+	{ .rfmax =  57800, .val = 0x12 },
+	{ .rfmax =  59500, .val = 0x11 },
+	{ .rfmax =  61100, .val = 0x10 },
+	{ .rfmax =  67600, .val = 0x0d },
+	{ .rfmax =  74200, .val = 0x0c },
+	{ .rfmax =  80700, .val = 0x0b },
+	{ .rfmax =  87200, .val = 0x0a },
+	{ .rfmax =  93800, .val = 0x09 },
+	{ .rfmax = 100300, .val = 0x08 },
+	{ .rfmax = 106900, .val = 0x07 },
+	{ .rfmax = 113400, .val = 0x06 },
+	{ .rfmax = 119900, .val = 0x05 },
+	{ .rfmax = 126500, .val = 0x04 },
+	{ .rfmax = 133000, .val = 0x03 },
+	{ .rfmax = 139500, .val = 0x02 },
+	{ .rfmax = 146100, .val = 0x01 },
+	{ .rfmax = 152600, .val = 0x00 },
+	{ .rfmax = 154300, .val = 0x1f },
+	{ .rfmax = 156100, .val = 0x1e },
+	{ .rfmax = 157800, .val = 0x1d },
+	{ .rfmax = 159500, .val = 0x1c },
+	{ .rfmax = 161200, .val = 0x1b },
+	{ .rfmax = 163000, .val = 0x1a },
+	{ .rfmax = 164700, .val = 0x19 },
+	{ .rfmax = 170200, .val = 0x17 },
+	{ .rfmax = 175800, .val = 0x16 },
+	{ .rfmax = 181300, .val = 0x15 },
+	{ .rfmax = 186900, .val = 0x14 },
+	{ .rfmax = 192400, .val = 0x13 },
+	{ .rfmax = 198000, .val = 0x12 },
+	{ .rfmax = 203500, .val = 0x11 },
+	{ .rfmax = 216200, .val = 0x14 },
+	{ .rfmax = 228900, .val = 0x13 },
+	{ .rfmax = 241600, .val = 0x12 },
+	{ .rfmax = 254400, .val = 0x11 },
+	{ .rfmax = 267100, .val = 0x10 },
+	{ .rfmax = 279800, .val = 0x0f },
+	{ .rfmax = 292500, .val = 0x0e },
+	{ .rfmax = 305200, .val = 0x0d },
+	{ .rfmax = 317900, .val = 0x0c },
+	{ .rfmax = 330700, .val = 0x0b },
+	{ .rfmax = 343400, .val = 0x0a },
+	{ .rfmax = 356100, .val = 0x09 },
+	{ .rfmax = 368800, .val = 0x08 },
+	{ .rfmax = 381500, .val = 0x07 },
+	{ .rfmax = 394200, .val = 0x06 },
+	{ .rfmax = 406900, .val = 0x05 },
+	{ .rfmax = 419700, .val = 0x04 },
+	{ .rfmax = 432400, .val = 0x03 },
+	{ .rfmax = 445100, .val = 0x02 },
+	{ .rfmax = 457800, .val = 0x01 },
+	{ .rfmax = 476300, .val = 0x19 },
+	{ .rfmax = 494800, .val = 0x18 },
+	{ .rfmax = 513300, .val = 0x17 },
+	{ .rfmax = 531800, .val = 0x16 },
+	{ .rfmax = 550300, .val = 0x15 },
+	{ .rfmax = 568900, .val = 0x14 },
+	{ .rfmax = 587400, .val = 0x13 },
+	{ .rfmax = 605900, .val = 0x12 },
+	{ .rfmax = 624400, .val = 0x11 },
+	{ .rfmax = 642900, .val = 0x10 },
+	{ .rfmax = 661400, .val = 0x0f },
+	{ .rfmax = 679900, .val = 0x0e },
+	{ .rfmax = 698400, .val = 0x0d },
+	{ .rfmax = 716900, .val = 0x0c },
+	{ .rfmax = 735400, .val = 0x0b },
+	{ .rfmax = 753900, .val = 0x0a },
+	{ .rfmax = 772500, .val = 0x09 },
+	{ .rfmax = 791000, .val = 0x08 },
+	{ .rfmax = 809500, .val = 0x07 },
+	{ .rfmax = 828000, .val = 0x06 },
+	{ .rfmax = 846500, .val = 0x05 },
+	{ .rfmax = 865000, .val = 0x04 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c1_rf_cal[] = {
+	{ .rfmax = 41000, .val = 0x1e },
+	{ .rfmax = 43000, .val = 0x30 },
+	{ .rfmax = 45000, .val = 0x43 },
+	{ .rfmax = 46000, .val = 0x4d },
+	{ .rfmax = 47000, .val = 0x54 },
+	{ .rfmax = 47900, .val = 0x64 },
+	{ .rfmax = 49100, .val = 0x20 },
+	{ .rfmax = 50000, .val = 0x22 },
+	{ .rfmax = 51000, .val = 0x2a },
+	{ .rfmax = 53000, .val = 0x32 },
+	{ .rfmax = 55000, .val = 0x35 },
+	{ .rfmax = 56000, .val = 0x3c },
+	{ .rfmax = 57000, .val = 0x3f },
+	{ .rfmax = 58000, .val = 0x48 },
+	{ .rfmax = 59000, .val = 0x4d },
+	{ .rfmax = 60000, .val = 0x58 },
+	{ .rfmax = 61100, .val = 0x5f },
+	{ .rfmax =     0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271c2_rf_cal[] = {
+	{ .rfmax =  41000, .val = 0x0f },
+	{ .rfmax =  43000, .val = 0x1c },
+	{ .rfmax =  45000, .val = 0x2f },
+	{ .rfmax =  46000, .val = 0x39 },
+	{ .rfmax =  47000, .val = 0x40 },
+	{ .rfmax =  47900, .val = 0x50 },
+	{ .rfmax =  49100, .val = 0x16 },
+	{ .rfmax =  50000, .val = 0x18 },
+	{ .rfmax =  51000, .val = 0x20 },
+	{ .rfmax =  53000, .val = 0x28 },
+	{ .rfmax =  55000, .val = 0x2b },
+	{ .rfmax =  56000, .val = 0x32 },
+	{ .rfmax =  57000, .val = 0x35 },
+	{ .rfmax =  58000, .val = 0x3e },
+	{ .rfmax =  59000, .val = 0x43 },
+	{ .rfmax =  60000, .val = 0x4e },
+	{ .rfmax =  61100, .val = 0x55 },
+	{ .rfmax =  63000, .val = 0x0f },
+	{ .rfmax =  64000, .val = 0x11 },
+	{ .rfmax =  65000, .val = 0x12 },
+	{ .rfmax =  66000, .val = 0x15 },
+	{ .rfmax =  67000, .val = 0x16 },
+	{ .rfmax =  68000, .val = 0x17 },
+	{ .rfmax =  70000, .val = 0x19 },
+	{ .rfmax =  71000, .val = 0x1c },
+	{ .rfmax =  72000, .val = 0x1d },
+	{ .rfmax =  73000, .val = 0x1f },
+	{ .rfmax =  74000, .val = 0x20 },
+	{ .rfmax =  75000, .val = 0x21 },
+	{ .rfmax =  76000, .val = 0x24 },
+	{ .rfmax =  77000, .val = 0x25 },
+	{ .rfmax =  78000, .val = 0x27 },
+	{ .rfmax =  80000, .val = 0x28 },
+	{ .rfmax =  81000, .val = 0x29 },
+	{ .rfmax =  82000, .val = 0x2d },
+	{ .rfmax =  83000, .val = 0x2e },
+	{ .rfmax =  84000, .val = 0x2f },
+	{ .rfmax =  85000, .val = 0x31 },
+	{ .rfmax =  86000, .val = 0x33 },
+	{ .rfmax =  87000, .val = 0x34 },
+	{ .rfmax =  88000, .val = 0x35 },
+	{ .rfmax =  89000, .val = 0x37 },
+	{ .rfmax =  90000, .val = 0x38 },
+	{ .rfmax =  91000, .val = 0x39 },
+	{ .rfmax =  93000, .val = 0x3c },
+	{ .rfmax =  94000, .val = 0x3e },
+	{ .rfmax =  95000, .val = 0x3f },
+	{ .rfmax =  96000, .val = 0x40 },
+	{ .rfmax =  97000, .val = 0x42 },
+	{ .rfmax =  99000, .val = 0x45 },
+	{ .rfmax = 100000, .val = 0x46 },
+	{ .rfmax = 102000, .val = 0x48 },
+	{ .rfmax = 103000, .val = 0x4a },
+	{ .rfmax = 105000, .val = 0x4d },
+	{ .rfmax = 106000, .val = 0x4e },
+	{ .rfmax = 107000, .val = 0x50 },
+	{ .rfmax = 108000, .val = 0x51 },
+	{ .rfmax = 110000, .val = 0x54 },
+	{ .rfmax = 111000, .val = 0x56 },
+	{ .rfmax = 112000, .val = 0x57 },
+	{ .rfmax = 113000, .val = 0x58 },
+	{ .rfmax = 114000, .val = 0x59 },
+	{ .rfmax = 115000, .val = 0x5c },
+	{ .rfmax = 116000, .val = 0x5d },
+	{ .rfmax = 117000, .val = 0x5f },
+	{ .rfmax = 119000, .val = 0x60 },
+	{ .rfmax = 120000, .val = 0x64 },
+	{ .rfmax = 121000, .val = 0x65 },
+	{ .rfmax = 122000, .val = 0x66 },
+	{ .rfmax = 123000, .val = 0x68 },
+	{ .rfmax = 124000, .val = 0x69 },
+	{ .rfmax = 125000, .val = 0x6c },
+	{ .rfmax = 126000, .val = 0x6d },
+	{ .rfmax = 127000, .val = 0x6e },
+	{ .rfmax = 128000, .val = 0x70 },
+	{ .rfmax = 129000, .val = 0x71 },
+	{ .rfmax = 130000, .val = 0x75 },
+	{ .rfmax = 131000, .val = 0x77 },
+	{ .rfmax = 132000, .val = 0x78 },
+	{ .rfmax = 133000, .val = 0x7b },
+	{ .rfmax = 134000, .val = 0x7e },
+	{ .rfmax = 135000, .val = 0x81 },
+	{ .rfmax = 136000, .val = 0x82 },
+	{ .rfmax = 137000, .val = 0x87 },
+	{ .rfmax = 138000, .val = 0x88 },
+	{ .rfmax = 139000, .val = 0x8d },
+	{ .rfmax = 140000, .val = 0x8e },
+	{ .rfmax = 141000, .val = 0x91 },
+	{ .rfmax = 142000, .val = 0x95 },
+	{ .rfmax = 143000, .val = 0x9a },
+	{ .rfmax = 144000, .val = 0x9d },
+	{ .rfmax = 145000, .val = 0xa1 },
+	{ .rfmax = 146000, .val = 0xa2 },
+	{ .rfmax = 147000, .val = 0xa4 },
+	{ .rfmax = 148000, .val = 0xa9 },
+	{ .rfmax = 149000, .val = 0xae },
+	{ .rfmax = 150000, .val = 0xb0 },
+	{ .rfmax = 151000, .val = 0xb1 },
+	{ .rfmax = 152000, .val = 0xb7 },
+	{ .rfmax = 153000, .val = 0xbd },
+	{ .rfmax = 154000, .val = 0x20 },
+	{ .rfmax = 155000, .val = 0x22 },
+	{ .rfmax = 156000, .val = 0x24 },
+	{ .rfmax = 157000, .val = 0x25 },
+	{ .rfmax = 158000, .val = 0x27 },
+	{ .rfmax = 159000, .val = 0x29 },
+	{ .rfmax = 160000, .val = 0x2c },
+	{ .rfmax = 161000, .val = 0x2d },
+	{ .rfmax = 163000, .val = 0x2e },
+	{ .rfmax = 164000, .val = 0x2f },
+	{ .rfmax = 165000, .val = 0x30 },
+	{ .rfmax = 166000, .val = 0x11 },
+	{ .rfmax = 167000, .val = 0x12 },
+	{ .rfmax = 168000, .val = 0x13 },
+	{ .rfmax = 169000, .val = 0x14 },
+	{ .rfmax = 170000, .val = 0x15 },
+	{ .rfmax = 172000, .val = 0x16 },
+	{ .rfmax = 173000, .val = 0x17 },
+	{ .rfmax = 174000, .val = 0x18 },
+	{ .rfmax = 175000, .val = 0x1a },
+	{ .rfmax = 176000, .val = 0x1b },
+	{ .rfmax = 178000, .val = 0x1d },
+	{ .rfmax = 179000, .val = 0x1e },
+	{ .rfmax = 180000, .val = 0x1f },
+	{ .rfmax = 181000, .val = 0x20 },
+	{ .rfmax = 182000, .val = 0x21 },
+	{ .rfmax = 183000, .val = 0x22 },
+	{ .rfmax = 184000, .val = 0x24 },
+	{ .rfmax = 185000, .val = 0x25 },
+	{ .rfmax = 186000, .val = 0x26 },
+	{ .rfmax = 187000, .val = 0x27 },
+	{ .rfmax = 188000, .val = 0x29 },
+	{ .rfmax = 189000, .val = 0x2a },
+	{ .rfmax = 190000, .val = 0x2c },
+	{ .rfmax = 191000, .val = 0x2d },
+	{ .rfmax = 192000, .val = 0x2e },
+	{ .rfmax = 193000, .val = 0x2f },
+	{ .rfmax = 194000, .val = 0x30 },
+	{ .rfmax = 195000, .val = 0x33 },
+	{ .rfmax = 196000, .val = 0x35 },
+	{ .rfmax = 198000, .val = 0x36 },
+	{ .rfmax = 200000, .val = 0x38 },
+	{ .rfmax = 201000, .val = 0x3c },
+	{ .rfmax = 202000, .val = 0x3d },
+	{ .rfmax = 203500, .val = 0x3e },
+	{ .rfmax = 206000, .val = 0x0e },
+	{ .rfmax = 208000, .val = 0x0f },
+	{ .rfmax = 212000, .val = 0x10 },
+	{ .rfmax = 216000, .val = 0x11 },
+	{ .rfmax = 217000, .val = 0x12 },
+	{ .rfmax = 218000, .val = 0x13 },
+	{ .rfmax = 220000, .val = 0x14 },
+	{ .rfmax = 222000, .val = 0x15 },
+	{ .rfmax = 225000, .val = 0x16 },
+	{ .rfmax = 228000, .val = 0x17 },
+	{ .rfmax = 231000, .val = 0x18 },
+	{ .rfmax = 234000, .val = 0x19 },
+	{ .rfmax = 235000, .val = 0x1a },
+	{ .rfmax = 236000, .val = 0x1b },
+	{ .rfmax = 237000, .val = 0x1c },
+	{ .rfmax = 240000, .val = 0x1d },
+	{ .rfmax = 242000, .val = 0x1f },
+	{ .rfmax = 247000, .val = 0x20 },
+	{ .rfmax = 249000, .val = 0x21 },
+	{ .rfmax = 252000, .val = 0x22 },
+	{ .rfmax = 253000, .val = 0x23 },
+	{ .rfmax = 254000, .val = 0x24 },
+	{ .rfmax = 256000, .val = 0x25 },
+	{ .rfmax = 259000, .val = 0x26 },
+	{ .rfmax = 262000, .val = 0x27 },
+	{ .rfmax = 264000, .val = 0x28 },
+	{ .rfmax = 267000, .val = 0x29 },
+	{ .rfmax = 269000, .val = 0x2a },
+	{ .rfmax = 271000, .val = 0x2b },
+	{ .rfmax = 273000, .val = 0x2c },
+	{ .rfmax = 275000, .val = 0x2d },
+	{ .rfmax = 277000, .val = 0x2e },
+	{ .rfmax = 279000, .val = 0x2f },
+	{ .rfmax = 282000, .val = 0x30 },
+	{ .rfmax = 284000, .val = 0x31 },
+	{ .rfmax = 286000, .val = 0x32 },
+	{ .rfmax = 287000, .val = 0x33 },
+	{ .rfmax = 290000, .val = 0x34 },
+	{ .rfmax = 293000, .val = 0x35 },
+	{ .rfmax = 295000, .val = 0x36 },
+	{ .rfmax = 297000, .val = 0x37 },
+	{ .rfmax = 300000, .val = 0x38 },
+	{ .rfmax = 303000, .val = 0x39 },
+	{ .rfmax = 305000, .val = 0x3a },
+	{ .rfmax = 306000, .val = 0x3b },
+	{ .rfmax = 307000, .val = 0x3c },
+	{ .rfmax = 310000, .val = 0x3d },
+	{ .rfmax = 312000, .val = 0x3e },
+	{ .rfmax = 315000, .val = 0x3f },
+	{ .rfmax = 318000, .val = 0x40 },
+	{ .rfmax = 320000, .val = 0x41 },
+	{ .rfmax = 323000, .val = 0x42 },
+	{ .rfmax = 324000, .val = 0x43 },
+	{ .rfmax = 325000, .val = 0x44 },
+	{ .rfmax = 327000, .val = 0x45 },
+	{ .rfmax = 331000, .val = 0x46 },
+	{ .rfmax = 334000, .val = 0x47 },
+	{ .rfmax = 337000, .val = 0x48 },
+	{ .rfmax = 339000, .val = 0x49 },
+	{ .rfmax = 340000, .val = 0x4a },
+	{ .rfmax = 341000, .val = 0x4b },
+	{ .rfmax = 343000, .val = 0x4c },
+	{ .rfmax = 345000, .val = 0x4d },
+	{ .rfmax = 349000, .val = 0x4e },
+	{ .rfmax = 352000, .val = 0x4f },
+	{ .rfmax = 353000, .val = 0x50 },
+	{ .rfmax = 355000, .val = 0x51 },
+	{ .rfmax = 357000, .val = 0x52 },
+	{ .rfmax = 359000, .val = 0x53 },
+	{ .rfmax = 361000, .val = 0x54 },
+	{ .rfmax = 362000, .val = 0x55 },
+	{ .rfmax = 364000, .val = 0x56 },
+	{ .rfmax = 368000, .val = 0x57 },
+	{ .rfmax = 370000, .val = 0x58 },
+	{ .rfmax = 372000, .val = 0x59 },
+	{ .rfmax = 375000, .val = 0x5a },
+	{ .rfmax = 376000, .val = 0x5b },
+	{ .rfmax = 377000, .val = 0x5c },
+	{ .rfmax = 379000, .val = 0x5d },
+	{ .rfmax = 382000, .val = 0x5e },
+	{ .rfmax = 384000, .val = 0x5f },
+	{ .rfmax = 385000, .val = 0x60 },
+	{ .rfmax = 386000, .val = 0x61 },
+	{ .rfmax = 388000, .val = 0x62 },
+	{ .rfmax = 390000, .val = 0x63 },
+	{ .rfmax = 393000, .val = 0x64 },
+	{ .rfmax = 394000, .val = 0x65 },
+	{ .rfmax = 396000, .val = 0x66 },
+	{ .rfmax = 397000, .val = 0x67 },
+	{ .rfmax = 398000, .val = 0x68 },
+	{ .rfmax = 400000, .val = 0x69 },
+	{ .rfmax = 402000, .val = 0x6a },
+	{ .rfmax = 403000, .val = 0x6b },
+	{ .rfmax = 407000, .val = 0x6c },
+	{ .rfmax = 408000, .val = 0x6d },
+	{ .rfmax = 409000, .val = 0x6e },
+	{ .rfmax = 410000, .val = 0x6f },
+	{ .rfmax = 411000, .val = 0x70 },
+	{ .rfmax = 412000, .val = 0x71 },
+	{ .rfmax = 413000, .val = 0x72 },
+	{ .rfmax = 414000, .val = 0x73 },
+	{ .rfmax = 417000, .val = 0x74 },
+	{ .rfmax = 418000, .val = 0x75 },
+	{ .rfmax = 420000, .val = 0x76 },
+	{ .rfmax = 422000, .val = 0x77 },
+	{ .rfmax = 423000, .val = 0x78 },
+	{ .rfmax = 424000, .val = 0x79 },
+	{ .rfmax = 427000, .val = 0x7a },
+	{ .rfmax = 428000, .val = 0x7b },
+	{ .rfmax = 429000, .val = 0x7d },
+	{ .rfmax = 432000, .val = 0x7f },
+	{ .rfmax = 434000, .val = 0x80 },
+	{ .rfmax = 435000, .val = 0x81 },
+	{ .rfmax = 436000, .val = 0x83 },
+	{ .rfmax = 437000, .val = 0x84 },
+	{ .rfmax = 438000, .val = 0x85 },
+	{ .rfmax = 439000, .val = 0x86 },
+	{ .rfmax = 440000, .val = 0x87 },
+	{ .rfmax = 441000, .val = 0x88 },
+	{ .rfmax = 442000, .val = 0x89 },
+	{ .rfmax = 445000, .val = 0x8a },
+	{ .rfmax = 446000, .val = 0x8b },
+	{ .rfmax = 447000, .val = 0x8c },
+	{ .rfmax = 448000, .val = 0x8e },
+	{ .rfmax = 449000, .val = 0x8f },
+	{ .rfmax = 450000, .val = 0x90 },
+	{ .rfmax = 452000, .val = 0x91 },
+	{ .rfmax = 453000, .val = 0x93 },
+	{ .rfmax = 454000, .val = 0x94 },
+	{ .rfmax = 456000, .val = 0x96 },
+	{ .rfmax = 457000, .val = 0x98 },
+	{ .rfmax = 461000, .val = 0x11 },
+	{ .rfmax = 468000, .val = 0x12 },
+	{ .rfmax = 472000, .val = 0x13 },
+	{ .rfmax = 473000, .val = 0x14 },
+	{ .rfmax = 474000, .val = 0x15 },
+	{ .rfmax = 481000, .val = 0x16 },
+	{ .rfmax = 486000, .val = 0x17 },
+	{ .rfmax = 491000, .val = 0x18 },
+	{ .rfmax = 498000, .val = 0x19 },
+	{ .rfmax = 499000, .val = 0x1a },
+	{ .rfmax = 501000, .val = 0x1b },
+	{ .rfmax = 506000, .val = 0x1c },
+	{ .rfmax = 511000, .val = 0x1d },
+	{ .rfmax = 516000, .val = 0x1e },
+	{ .rfmax = 520000, .val = 0x1f },
+	{ .rfmax = 521000, .val = 0x20 },
+	{ .rfmax = 525000, .val = 0x21 },
+	{ .rfmax = 529000, .val = 0x22 },
+	{ .rfmax = 533000, .val = 0x23 },
+	{ .rfmax = 539000, .val = 0x24 },
+	{ .rfmax = 541000, .val = 0x25 },
+	{ .rfmax = 547000, .val = 0x26 },
+	{ .rfmax = 549000, .val = 0x27 },
+	{ .rfmax = 551000, .val = 0x28 },
+	{ .rfmax = 556000, .val = 0x29 },
+	{ .rfmax = 561000, .val = 0x2a },
+	{ .rfmax = 563000, .val = 0x2b },
+	{ .rfmax = 565000, .val = 0x2c },
+	{ .rfmax = 569000, .val = 0x2d },
+	{ .rfmax = 571000, .val = 0x2e },
+	{ .rfmax = 577000, .val = 0x2f },
+	{ .rfmax = 580000, .val = 0x30 },
+	{ .rfmax = 582000, .val = 0x31 },
+	{ .rfmax = 584000, .val = 0x32 },
+	{ .rfmax = 588000, .val = 0x33 },
+	{ .rfmax = 591000, .val = 0x34 },
+	{ .rfmax = 596000, .val = 0x35 },
+	{ .rfmax = 598000, .val = 0x36 },
+	{ .rfmax = 603000, .val = 0x37 },
+	{ .rfmax = 604000, .val = 0x38 },
+	{ .rfmax = 606000, .val = 0x39 },
+	{ .rfmax = 612000, .val = 0x3a },
+	{ .rfmax = 615000, .val = 0x3b },
+	{ .rfmax = 617000, .val = 0x3c },
+	{ .rfmax = 621000, .val = 0x3d },
+	{ .rfmax = 622000, .val = 0x3e },
+	{ .rfmax = 625000, .val = 0x3f },
+	{ .rfmax = 632000, .val = 0x40 },
+	{ .rfmax = 633000, .val = 0x41 },
+	{ .rfmax = 634000, .val = 0x42 },
+	{ .rfmax = 642000, .val = 0x43 },
+	{ .rfmax = 643000, .val = 0x44 },
+	{ .rfmax = 647000, .val = 0x45 },
+	{ .rfmax = 650000, .val = 0x46 },
+	{ .rfmax = 652000, .val = 0x47 },
+	{ .rfmax = 657000, .val = 0x48 },
+	{ .rfmax = 661000, .val = 0x49 },
+	{ .rfmax = 662000, .val = 0x4a },
+	{ .rfmax = 665000, .val = 0x4b },
+	{ .rfmax = 667000, .val = 0x4c },
+	{ .rfmax = 670000, .val = 0x4d },
+	{ .rfmax = 673000, .val = 0x4e },
+	{ .rfmax = 676000, .val = 0x4f },
+	{ .rfmax = 677000, .val = 0x50 },
+	{ .rfmax = 681000, .val = 0x51 },
+	{ .rfmax = 683000, .val = 0x52 },
+	{ .rfmax = 686000, .val = 0x53 },
+	{ .rfmax = 688000, .val = 0x54 },
+	{ .rfmax = 689000, .val = 0x55 },
+	{ .rfmax = 691000, .val = 0x56 },
+	{ .rfmax = 695000, .val = 0x57 },
+	{ .rfmax = 698000, .val = 0x58 },
+	{ .rfmax = 703000, .val = 0x59 },
+	{ .rfmax = 704000, .val = 0x5a },
+	{ .rfmax = 705000, .val = 0x5b },
+	{ .rfmax = 707000, .val = 0x5c },
+	{ .rfmax = 710000, .val = 0x5d },
+	{ .rfmax = 712000, .val = 0x5e },
+	{ .rfmax = 717000, .val = 0x5f },
+	{ .rfmax = 718000, .val = 0x60 },
+	{ .rfmax = 721000, .val = 0x61 },
+	{ .rfmax = 722000, .val = 0x62 },
+	{ .rfmax = 723000, .val = 0x63 },
+	{ .rfmax = 725000, .val = 0x64 },
+	{ .rfmax = 727000, .val = 0x65 },
+	{ .rfmax = 730000, .val = 0x66 },
+	{ .rfmax = 732000, .val = 0x67 },
+	{ .rfmax = 735000, .val = 0x68 },
+	{ .rfmax = 740000, .val = 0x69 },
+	{ .rfmax = 741000, .val = 0x6a },
+	{ .rfmax = 742000, .val = 0x6b },
+	{ .rfmax = 743000, .val = 0x6c },
+	{ .rfmax = 745000, .val = 0x6d },
+	{ .rfmax = 747000, .val = 0x6e },
+	{ .rfmax = 748000, .val = 0x6f },
+	{ .rfmax = 750000, .val = 0x70 },
+	{ .rfmax = 752000, .val = 0x71 },
+	{ .rfmax = 754000, .val = 0x72 },
+	{ .rfmax = 757000, .val = 0x73 },
+	{ .rfmax = 758000, .val = 0x74 },
+	{ .rfmax = 760000, .val = 0x75 },
+	{ .rfmax = 763000, .val = 0x76 },
+	{ .rfmax = 764000, .val = 0x77 },
+	{ .rfmax = 766000, .val = 0x78 },
+	{ .rfmax = 767000, .val = 0x79 },
+	{ .rfmax = 768000, .val = 0x7a },
+	{ .rfmax = 773000, .val = 0x7b },
+	{ .rfmax = 774000, .val = 0x7c },
+	{ .rfmax = 776000, .val = 0x7d },
+	{ .rfmax = 777000, .val = 0x7e },
+	{ .rfmax = 778000, .val = 0x7f },
+	{ .rfmax = 779000, .val = 0x80 },
+	{ .rfmax = 781000, .val = 0x81 },
+	{ .rfmax = 783000, .val = 0x82 },
+	{ .rfmax = 784000, .val = 0x83 },
+	{ .rfmax = 785000, .val = 0x84 },
+	{ .rfmax = 786000, .val = 0x85 },
+	{ .rfmax = 793000, .val = 0x86 },
+	{ .rfmax = 794000, .val = 0x87 },
+	{ .rfmax = 795000, .val = 0x88 },
+	{ .rfmax = 797000, .val = 0x89 },
+	{ .rfmax = 799000, .val = 0x8a },
+	{ .rfmax = 801000, .val = 0x8b },
+	{ .rfmax = 802000, .val = 0x8c },
+	{ .rfmax = 803000, .val = 0x8d },
+	{ .rfmax = 804000, .val = 0x8e },
+	{ .rfmax = 810000, .val = 0x90 },
+	{ .rfmax = 811000, .val = 0x91 },
+	{ .rfmax = 812000, .val = 0x92 },
+	{ .rfmax = 814000, .val = 0x93 },
+	{ .rfmax = 816000, .val = 0x94 },
+	{ .rfmax = 817000, .val = 0x96 },
+	{ .rfmax = 818000, .val = 0x97 },
+	{ .rfmax = 820000, .val = 0x98 },
+	{ .rfmax = 821000, .val = 0x99 },
+	{ .rfmax = 822000, .val = 0x9a },
+	{ .rfmax = 828000, .val = 0x9b },
+	{ .rfmax = 829000, .val = 0x9d },
+	{ .rfmax = 830000, .val = 0x9f },
+	{ .rfmax = 831000, .val = 0xa0 },
+	{ .rfmax = 833000, .val = 0xa1 },
+	{ .rfmax = 835000, .val = 0xa2 },
+	{ .rfmax = 836000, .val = 0xa3 },
+	{ .rfmax = 837000, .val = 0xa4 },
+	{ .rfmax = 838000, .val = 0xa6 },
+	{ .rfmax = 840000, .val = 0xa8 },
+	{ .rfmax = 842000, .val = 0xa9 },
+	{ .rfmax = 845000, .val = 0xaa },
+	{ .rfmax = 846000, .val = 0xab },
+	{ .rfmax = 847000, .val = 0xad },
+	{ .rfmax = 848000, .val = 0xae },
+	{ .rfmax = 852000, .val = 0xaf },
+	{ .rfmax = 853000, .val = 0xb0 },
+	{ .rfmax = 858000, .val = 0xb1 },
+	{ .rfmax = 860000, .val = 0xb2 },
+	{ .rfmax = 861000, .val = 0xb3 },
+	{ .rfmax = 862000, .val = 0xb4 },
+	{ .rfmax = 863000, .val = 0xb6 },
+	{ .rfmax = 864000, .val = 0xb8 },
+	{ .rfmax = 865000, .val = 0xb9 },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+static struct tda18271_map tda18271_ir_measure[] = {
+	{ .rfmax =  30000, .val = 4 },
+	{ .rfmax = 200000, .val = 5 },
+	{ .rfmax = 600000, .val = 6 },
+	{ .rfmax = 865000, .val = 7 },
+	{ .rfmax =      0, .val = 0 }, /* end */
+};
+
+static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = {
+	{ .rfmax =  47900, .val = 0x00 },
+	{ .rfmax =  55000, .val = 0x00 },
+	{ .rfmax =  61100, .val = 0x0a },
+	{ .rfmax =  64000, .val = 0x0a },
+	{ .rfmax =  82000, .val = 0x14 },
+	{ .rfmax =  84000, .val = 0x19 },
+	{ .rfmax = 119000, .val = 0x1c },
+	{ .rfmax = 124000, .val = 0x20 },
+	{ .rfmax = 129000, .val = 0x2a },
+	{ .rfmax = 134000, .val = 0x32 },
+	{ .rfmax = 139000, .val = 0x39 },
+	{ .rfmax = 144000, .val = 0x3e },
+	{ .rfmax = 149000, .val = 0x3f },
+	{ .rfmax = 152600, .val = 0x40 },
+	{ .rfmax = 154000, .val = 0x40 },
+	{ .rfmax = 164700, .val = 0x41 },
+	{ .rfmax = 203500, .val = 0x32 },
+	{ .rfmax = 353000, .val = 0x19 },
+	{ .rfmax = 356000, .val = 0x1a },
+	{ .rfmax = 359000, .val = 0x1b },
+	{ .rfmax = 363000, .val = 0x1c },
+	{ .rfmax = 366000, .val = 0x1d },
+	{ .rfmax = 369000, .val = 0x1e },
+	{ .rfmax = 373000, .val = 0x1f },
+	{ .rfmax = 376000, .val = 0x20 },
+	{ .rfmax = 379000, .val = 0x21 },
+	{ .rfmax = 383000, .val = 0x22 },
+	{ .rfmax = 386000, .val = 0x23 },
+	{ .rfmax = 389000, .val = 0x24 },
+	{ .rfmax = 393000, .val = 0x25 },
+	{ .rfmax = 396000, .val = 0x26 },
+	{ .rfmax = 399000, .val = 0x27 },
+	{ .rfmax = 402000, .val = 0x28 },
+	{ .rfmax = 404000, .val = 0x29 },
+	{ .rfmax = 407000, .val = 0x2a },
+	{ .rfmax = 409000, .val = 0x2b },
+	{ .rfmax = 412000, .val = 0x2c },
+	{ .rfmax = 414000, .val = 0x2d },
+	{ .rfmax = 417000, .val = 0x2e },
+	{ .rfmax = 419000, .val = 0x2f },
+	{ .rfmax = 422000, .val = 0x30 },
+	{ .rfmax = 424000, .val = 0x31 },
+	{ .rfmax = 427000, .val = 0x32 },
+	{ .rfmax = 429000, .val = 0x33 },
+	{ .rfmax = 432000, .val = 0x34 },
+	{ .rfmax = 434000, .val = 0x35 },
+	{ .rfmax = 437000, .val = 0x36 },
+	{ .rfmax = 439000, .val = 0x37 },
+	{ .rfmax = 442000, .val = 0x38 },
+	{ .rfmax = 444000, .val = 0x39 },
+	{ .rfmax = 447000, .val = 0x3a },
+	{ .rfmax = 449000, .val = 0x3b },
+	{ .rfmax = 457800, .val = 0x3c },
+	{ .rfmax = 465000, .val = 0x0f },
+	{ .rfmax = 477000, .val = 0x12 },
+	{ .rfmax = 483000, .val = 0x14 },
+	{ .rfmax = 502000, .val = 0x19 },
+	{ .rfmax = 508000, .val = 0x1b },
+	{ .rfmax = 519000, .val = 0x1c },
+	{ .rfmax = 522000, .val = 0x1d },
+	{ .rfmax = 524000, .val = 0x1e },
+	{ .rfmax = 534000, .val = 0x1f },
+	{ .rfmax = 549000, .val = 0x20 },
+	{ .rfmax = 554000, .val = 0x22 },
+	{ .rfmax = 584000, .val = 0x24 },
+	{ .rfmax = 589000, .val = 0x26 },
+	{ .rfmax = 658000, .val = 0x27 },
+	{ .rfmax = 664000, .val = 0x2c },
+	{ .rfmax = 669000, .val = 0x2d },
+	{ .rfmax = 699000, .val = 0x2e },
+	{ .rfmax = 704000, .val = 0x30 },
+	{ .rfmax = 709000, .val = 0x31 },
+	{ .rfmax = 714000, .val = 0x32 },
+	{ .rfmax = 724000, .val = 0x33 },
+	{ .rfmax = 729000, .val = 0x36 },
+	{ .rfmax = 739000, .val = 0x38 },
+	{ .rfmax = 744000, .val = 0x39 },
+	{ .rfmax = 749000, .val = 0x3b },
+	{ .rfmax = 754000, .val = 0x3c },
+	{ .rfmax = 759000, .val = 0x3d },
+	{ .rfmax = 764000, .val = 0x3e },
+	{ .rfmax = 769000, .val = 0x3f },
+	{ .rfmax = 774000, .val = 0x40 },
+	{ .rfmax = 779000, .val = 0x41 },
+	{ .rfmax = 784000, .val = 0x43 },
+	{ .rfmax = 789000, .val = 0x46 },
+	{ .rfmax = 794000, .val = 0x48 },
+	{ .rfmax = 799000, .val = 0x4b },
+	{ .rfmax = 804000, .val = 0x4f },
+	{ .rfmax = 809000, .val = 0x54 },
+	{ .rfmax = 814000, .val = 0x59 },
+	{ .rfmax = 819000, .val = 0x5d },
+	{ .rfmax = 824000, .val = 0x61 },
+	{ .rfmax = 829000, .val = 0x68 },
+	{ .rfmax = 834000, .val = 0x6e },
+	{ .rfmax = 839000, .val = 0x75 },
+	{ .rfmax = 844000, .val = 0x7e },
+	{ .rfmax = 849000, .val = 0x82 },
+	{ .rfmax = 854000, .val = 0x84 },
+	{ .rfmax = 859000, .val = 0x8f },
+	{ .rfmax = 865000, .val = 0x9a },
+	{ .rfmax =      0, .val = 0x00 }, /* end */
+};
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_thermo_map {
+	u8 d;
+	u8 r0;
+	u8 r1;
+};
+
+static struct tda18271_thermo_map tda18271_thermometer[] = {
+	{ .d = 0x00, .r0 = 60, .r1 =  92 },
+	{ .d = 0x01, .r0 = 62, .r1 =  94 },
+	{ .d = 0x02, .r0 = 66, .r1 =  98 },
+	{ .d = 0x03, .r0 = 64, .r1 =  96 },
+	{ .d = 0x04, .r0 = 74, .r1 = 106 },
+	{ .d = 0x05, .r0 = 72, .r1 = 104 },
+	{ .d = 0x06, .r0 = 68, .r1 = 100 },
+	{ .d = 0x07, .r0 = 70, .r1 = 102 },
+	{ .d = 0x08, .r0 = 90, .r1 = 122 },
+	{ .d = 0x09, .r0 = 88, .r1 = 120 },
+	{ .d = 0x0a, .r0 = 84, .r1 = 116 },
+	{ .d = 0x0b, .r0 = 86, .r1 = 118 },
+	{ .d = 0x0c, .r0 = 76, .r1 = 108 },
+	{ .d = 0x0d, .r0 = 78, .r1 = 110 },
+	{ .d = 0x0e, .r0 = 82, .r1 = 114 },
+	{ .d = 0x0f, .r0 = 80, .r1 = 112 },
+	{ .d = 0x00, .r0 =  0, .r1 =   0 }, /* end */
+};
+
+int tda18271_lookup_thermometer(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	unsigned char *regs = priv->tda18271_regs;
+	int val, i = 0;
+
+	while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) {
+		if (tda18271_thermometer[i + 1].d == 0)
+			break;
+		i++;
+	}
+
+	if ((regs[R_TM] & 0x20) == 0x20)
+		val = tda18271_thermometer[i].r1;
+	else
+		val = tda18271_thermometer[i].r0;
+
+	tda_map("(%d) tm = %d\n", i, val);
+
+	return val;
+}
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_cid_target_map {
+	u32 rfmax;
+	u8  target;
+	u16 limit;
+};
+
+static struct tda18271_cid_target_map tda18271_cid_target[] = {
+	{ .rfmax =  46000, .target = 0x04, .limit =  1800 },
+	{ .rfmax =  52200, .target = 0x0a, .limit =  1500 },
+	{ .rfmax =  79100, .target = 0x01, .limit =  4000 },
+	{ .rfmax = 136800, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 156700, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 156700, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 186250, .target = 0x0a, .limit =  4000 },
+	{ .rfmax = 230000, .target = 0x0a, .limit =  4000 },
+	{ .rfmax = 345000, .target = 0x18, .limit =  4000 },
+	{ .rfmax = 426000, .target = 0x0e, .limit =  4000 },
+	{ .rfmax = 489500, .target = 0x1e, .limit =  4000 },
+	{ .rfmax = 697500, .target = 0x32, .limit =  4000 },
+	{ .rfmax = 842000, .target = 0x3a, .limit =  4000 },
+	{ .rfmax =      0, .target = 0x00, .limit =     0 }, /* end */
+};
+
+int tda18271_lookup_cid_target(struct dvb_frontend *fe,
+			       u32 *freq, u8 *cid_target, u16 *count_limit)
+{
+	int i = 0;
+
+	while ((tda18271_cid_target[i].rfmax * 1000) < *freq) {
+		if (tda18271_cid_target[i + 1].rfmax == 0)
+			break;
+		i++;
+	}
+	*cid_target  = tda18271_cid_target[i].target;
+	*count_limit = tda18271_cid_target[i].limit;
+
+	tda_map("(%d) cid_target = %02x, count_limit = %d\n", i,
+		tda18271_cid_target[i].target, tda18271_cid_target[i].limit);
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = {
+	{ .rfmax =  47900, .rfband = 0x00,
+	  .rf1_def =  46000, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax =  61100, .rfband = 0x01,
+	  .rf1_def =  52200, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax = 152600, .rfband = 0x02,
+	  .rf1_def =  70100, .rf2_def = 136800, .rf3_def =      0 },
+	{ .rfmax = 164700, .rfband = 0x03,
+	  .rf1_def = 156700, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax = 203500, .rfband = 0x04,
+	  .rf1_def = 186250, .rf2_def =      0, .rf3_def =      0 },
+	{ .rfmax = 457800, .rfband = 0x05,
+	  .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 },
+	{ .rfmax = 865000, .rfband = 0x06,
+	  .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 },
+	{ .rfmax =      0, .rfband = 0x00,
+	  .rf1_def =      0, .rf2_def =      0, .rf3_def =      0 }, /* end */
+};
+
+int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
+	int i = 0;
+
+	while ((map[i].rfmax * 1000) < *freq) {
+		if (tda18271_debug & DBG_ADV)
+			tda_map("(%d) rfmax = %d < freq = %d, "
+				"rf1_def = %d, rf2_def = %d, rf3_def = %d, "
+				"rf1 = %d, rf2 = %d, rf3 = %d, "
+				"rf_a1 = %d, rf_a2 = %d, "
+				"rf_b1 = %d, rf_b2 = %d\n",
+				i, map[i].rfmax * 1000, *freq,
+				map[i].rf1_def, map[i].rf2_def, map[i].rf3_def,
+				map[i].rf1, map[i].rf2, map[i].rf3,
+				map[i].rf_a1, map[i].rf_a2,
+				map[i].rf_b1, map[i].rf_b2);
+		if (map[i].rfmax == 0)
+			return -EINVAL;
+		i++;
+	}
+	if (rf_band)
+		*rf_band = map[i].rfband;
+
+	tda_map("(%d) rf_band = %02x\n", i, map[i].rfband);
+
+	return i;
+}
+
+/*---------------------------------------------------------------------*/
+
+struct tda18271_map_layout {
+	struct tda18271_pll_map *main_pll;
+	struct tda18271_pll_map *cal_pll;
+
+	struct tda18271_map *rf_cal;
+	struct tda18271_map *rf_cal_kmco;
+	struct tda18271_map *rf_cal_dc_over_dt;
+
+	struct tda18271_map *bp_filter;
+	struct tda18271_map *rf_band;
+	struct tda18271_map *gain_taper;
+	struct tda18271_map *ir_measure;
+};
+
+/*---------------------------------------------------------------------*/
+
+int tda18271_lookup_pll_map(struct dvb_frontend *fe,
+			    enum tda18271_map_type map_type,
+			    u32 *freq, u8 *post_div, u8 *div)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_pll_map *map = NULL;
+	unsigned int i = 0;
+	char *map_name;
+	int ret = 0;
+
+	BUG_ON(!priv->maps);
+
+	switch (map_type) {
+	case MAIN_PLL:
+		map = priv->maps->main_pll;
+		map_name = "main_pll";
+		break;
+	case CAL_PLL:
+		map = priv->maps->cal_pll;
+		map_name = "cal_pll";
+		break;
+	default:
+		/* we should never get here */
+		map_name = "undefined";
+		break;
+	}
+
+	if (!map) {
+		tda_warn("%s map is not set!\n", map_name);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	while ((map[i].lomax * 1000) < *freq) {
+		if (map[i + 1].lomax == 0) {
+			tda_map("%s: frequency (%d) out of range\n",
+				map_name, *freq);
+			ret = -ERANGE;
+			break;
+		}
+		i++;
+	}
+	*post_div = map[i].pd;
+	*div      = map[i].d;
+
+	tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n",
+		i, map_name, *post_div, *div);
+fail:
+	return ret;
+}
+
+int tda18271_lookup_map(struct dvb_frontend *fe,
+			enum tda18271_map_type map_type,
+			u32 *freq, u8 *val)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	struct tda18271_map *map = NULL;
+	unsigned int i = 0;
+	char *map_name;
+	int ret = 0;
+
+	BUG_ON(!priv->maps);
+
+	switch (map_type) {
+	case BP_FILTER:
+		map = priv->maps->bp_filter;
+		map_name = "bp_filter";
+		break;
+	case RF_CAL_KMCO:
+		map = priv->maps->rf_cal_kmco;
+		map_name = "km";
+		break;
+	case RF_BAND:
+		map = priv->maps->rf_band;
+		map_name = "rf_band";
+		break;
+	case GAIN_TAPER:
+		map = priv->maps->gain_taper;
+		map_name = "gain_taper";
+		break;
+	case RF_CAL:
+		map = priv->maps->rf_cal;
+		map_name = "rf_cal";
+		break;
+	case IR_MEASURE:
+		map = priv->maps->ir_measure;
+		map_name = "ir_measure";
+		break;
+	case RF_CAL_DC_OVER_DT:
+		map = priv->maps->rf_cal_dc_over_dt;
+		map_name = "rf_cal_dc_over_dt";
+		break;
+	default:
+		/* we should never get here */
+		map_name = "undefined";
+		break;
+	}
+
+	if (!map) {
+		tda_warn("%s map is not set!\n", map_name);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	while ((map[i].rfmax * 1000) < *freq) {
+		if (map[i + 1].rfmax == 0) {
+			tda_map("%s: frequency (%d) out of range\n",
+				map_name, *freq);
+			ret = -ERANGE;
+			break;
+		}
+		i++;
+	}
+	*val = map[i].val;
+
+	tda_map("(%d) %s: 0x%02x\n", i, map_name, *val);
+fail:
+	return ret;
+}
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_std_map tda18271c1_std_map = {
+	.fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
+	.atv_b    = { .if_freq = 6750, .std_bits = 0x0e },
+	.atv_dk   = { .if_freq = 7750, .std_bits = 0x0f },
+	.atv_gh   = { .if_freq = 7750, .std_bits = 0x0f },
+	.atv_i    = { .if_freq = 7750, .std_bits = 0x0f },
+	.atv_l    = { .if_freq = 7750, .std_bits = 0x0f },
+	.atv_lc   = { .if_freq = 1250, .std_bits = 0x0f },
+	.atv_mn   = { .if_freq = 5750, .std_bits = 0x0d },
+	.atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
+	.dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
+	.dvbt_7   = { .if_freq = 3800, .std_bits = 0x1d },
+	.dvbt_8   = { .if_freq = 4300, .std_bits = 0x1e },
+	.qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
+	.qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
+};
+
+static struct tda18271_std_map tda18271c2_std_map = {
+	.fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
+	.atv_b    = { .if_freq = 6000, .std_bits = 0x0d },
+	.atv_dk   = { .if_freq = 6900, .std_bits = 0x0e },
+	.atv_gh   = { .if_freq = 7100, .std_bits = 0x0e },
+	.atv_i    = { .if_freq = 7250, .std_bits = 0x0e },
+	.atv_l    = { .if_freq = 6900, .std_bits = 0x0e },
+	.atv_lc   = { .if_freq = 1250, .std_bits = 0x0e },
+	.atv_mn   = { .if_freq = 5400, .std_bits = 0x0c },
+	.atsc_6   = { .if_freq = 3250, .std_bits = 0x1c },
+	.dvbt_6   = { .if_freq = 3300, .std_bits = 0x1c },
+	.dvbt_7   = { .if_freq = 3500, .std_bits = 0x1c },
+	.dvbt_8   = { .if_freq = 4000, .std_bits = 0x1d },
+	.qam_6    = { .if_freq = 4000, .std_bits = 0x1d },
+	.qam_8    = { .if_freq = 5000, .std_bits = 0x1f },
+};
+
+/*---------------------------------------------------------------------*/
+
+static struct tda18271_map_layout tda18271c1_map_layout = {
+	.main_pll          = tda18271c1_main_pll,
+	.cal_pll           = tda18271c1_cal_pll,
+
+	.rf_cal            = tda18271c1_rf_cal,
+	.rf_cal_kmco       = tda18271c1_km,
+
+	.bp_filter         = tda18271_bp_filter,
+	.rf_band           = tda18271_rf_band,
+	.gain_taper        = tda18271_gain_taper,
+	.ir_measure        = tda18271_ir_measure,
+};
+
+static struct tda18271_map_layout tda18271c2_map_layout = {
+	.main_pll          = tda18271c2_main_pll,
+	.cal_pll           = tda18271c2_cal_pll,
+
+	.rf_cal            = tda18271c2_rf_cal,
+	.rf_cal_kmco       = tda18271c2_km,
+
+	.rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt,
+
+	.bp_filter         = tda18271_bp_filter,
+	.rf_band           = tda18271_rf_band,
+	.gain_taper        = tda18271_gain_taper,
+	.ir_measure        = tda18271_ir_measure,
+};
+
+int tda18271_assign_map_layout(struct dvb_frontend *fe)
+{
+	struct tda18271_priv *priv = fe->tuner_priv;
+	int ret = 0;
+
+	switch (priv->id) {
+	case TDA18271HDC1:
+		priv->maps = &tda18271c1_map_layout;
+		memcpy(&priv->std, &tda18271c1_std_map,
+		       sizeof(struct tda18271_std_map));
+		break;
+	case TDA18271HDC2:
+		priv->maps = &tda18271c2_map_layout;
+		memcpy(&priv->std, &tda18271c2_std_map,
+		       sizeof(struct tda18271_std_map));
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	memcpy(priv->rf_cal_state, &tda18271_rf_band_template,
+	       sizeof(tda18271_rf_band_template));
+
+	return ret;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h
new file mode 100644
index 000000000000..24b0e35a2ab3
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda18271.h
@@ -0,0 +1,78 @@
+/*
+    tda18271.h - header for the Philips / NXP TDA18271 silicon tuner
+
+    Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.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.
+*/
+
+#ifndef __TDA18271_H__
+#define __TDA18271_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct tda18271_std_map_item {
+	u16 if_freq;
+	u8 std_bits;
+};
+
+struct tda18271_std_map {
+	struct tda18271_std_map_item fm_radio;
+	struct tda18271_std_map_item atv_b;
+	struct tda18271_std_map_item atv_dk;
+	struct tda18271_std_map_item atv_gh;
+	struct tda18271_std_map_item atv_i;
+	struct tda18271_std_map_item atv_l;
+	struct tda18271_std_map_item atv_lc;
+	struct tda18271_std_map_item atv_mn;
+	struct tda18271_std_map_item atsc_6;
+	struct tda18271_std_map_item dvbt_6;
+	struct tda18271_std_map_item dvbt_7;
+	struct tda18271_std_map_item dvbt_8;
+	struct tda18271_std_map_item qam_6;
+	struct tda18271_std_map_item qam_8;
+};
+
+enum tda18271_i2c_gate {
+	TDA18271_GATE_AUTO = 0,
+	TDA18271_GATE_ANALOG,
+	TDA18271_GATE_DIGITAL,
+};
+
+struct tda18271_config {
+	/* override default if freq / std settings (optional) */
+	struct tda18271_std_map *std_map;
+
+	/* use i2c gate provided by analog or digital demod */
+	enum tda18271_i2c_gate gate;
+};
+
+#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
+					    struct i2c_adapter *i2c,
+					    struct tda18271_config *cfg);
+#else
+static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe,
+						   u8 addr,
+						   struct i2c_adapter *i2c,
+						   struct tda18271_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* __TDA18271_H__ */
diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c
index 256fc4bf500b..229b11987a58 100644
--- a/drivers/media/dvb/frontends/tda827x.c
+++ b/drivers/media/dvb/frontends/tda827x.c
@@ -19,12 +19,16 @@
  */
 
 #include <linux/module.h>
-#include <linux/dvb/frontend.h>
 #include <asm/types.h>
+#include <linux/dvb/frontend.h>
+#include <linux/videodev2.h>
 
 #include "tda827x.h"
 
 static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
 #define dprintk(args...) \
 	do {					    \
 		if (debug) printk(KERN_DEBUG "tda827x: " args); \
@@ -34,10 +38,57 @@ struct tda827x_priv {
 	int i2c_addr;
 	struct i2c_adapter *i2c_adap;
 	struct tda827x_config *cfg;
+
+	unsigned int sgIF;
+	unsigned char lpsel;
+
 	u32 frequency;
 	u32 bandwidth;
 };
 
+static void tda827x_set_std(struct dvb_frontend *fe,
+			    struct analog_parameters *params)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	char *mode;
+
+	priv->lpsel = 0;
+	if (params->std & V4L2_STD_MN) {
+		priv->sgIF = 92;
+		priv->lpsel = 1;
+		mode = "MN";
+	} else if (params->std & V4L2_STD_B) {
+		priv->sgIF = 108;
+		mode = "B";
+	} else if (params->std & V4L2_STD_GH) {
+		priv->sgIF = 124;
+		mode = "GH";
+	} else if (params->std & V4L2_STD_PAL_I) {
+		priv->sgIF = 124;
+		mode = "I";
+	} else if (params->std & V4L2_STD_DK) {
+		priv->sgIF = 124;
+		mode = "DK";
+	} else if (params->std & V4L2_STD_SECAM_L) {
+		priv->sgIF = 124;
+		mode = "L";
+	} else if (params->std & V4L2_STD_SECAM_LC) {
+		priv->sgIF = 20;
+		mode = "LC";
+	} else {
+		priv->sgIF = 124;
+		mode = "xx";
+	}
+
+	if (params->mode == V4L2_TUNER_RADIO)
+		priv->sgIF = 88; /* if frequency is 5.5 MHz */
+
+	dprintk("setting tda827x to system %s\n", mode);
+}
+
+
+/* ------------------------------------------------------------------ */
+
 struct tda827x_data {
 	u32 lomax;
 	u8  spd;
@@ -48,7 +99,7 @@ struct tda827x_data {
 	u8 div1p5;
 };
 
-static const struct tda827x_data tda827x_dvbt[] = {
+static const struct tda827x_data tda827x_table[] = {
 	{ .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
 	{ .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
 	{ .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
@@ -106,21 +157,22 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
 	tuner_freq = params->frequency + if_freq;
 
 	i = 0;
-	while (tda827x_dvbt[i].lomax < tuner_freq) {
-		if(tda827x_dvbt[i + 1].lomax == 0)
+	while (tda827x_table[i].lomax < tuner_freq) {
+		if (tda827x_table[i + 1].lomax == 0)
 			break;
 		i++;
 	}
 
-	N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2);
+	N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
 	buf[0] = 0;
 	buf[1] = (N>>8) | 0x40;
 	buf[2] = N & 0xff;
 	buf[3] = 0;
 	buf[4] = 0x52;
-	buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) +
-				(tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp;
-	buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f;
+	buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) +
+				(tda827x_table[i].bs << 3) +
+				tda827x_table[i].bp;
+	buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f;
 	buf[7] = 0xbf;
 	buf[8] = 0x2a;
 	buf[9] = 0x05;
@@ -140,7 +192,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
 	msleep(500);
 	/* correct CP value */
 	buf[0] = 0x30;
-	buf[1] = 0x50 + tda827x_dvbt[i].cp;
+	buf[1] = 0x50 + tda827x_table[i].cp;
 	msg.len = 2;
 
 	if (fe->ops.i2c_gate_ctrl)
@@ -173,6 +225,102 @@ static int tda827xo_sleep(struct dvb_frontend *fe)
 
 /* ------------------------------------------------------------------ */
 
+static int tda827xo_set_analog_params(struct dvb_frontend *fe,
+				      struct analog_parameters *params)
+{
+	unsigned char tuner_reg[8];
+	unsigned char reg2[2];
+	u32 N;
+	int i;
+	struct tda827x_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 };
+	unsigned int freq = params->frequency;
+
+	tda827x_set_std(fe, params);
+
+	if (params->mode == V4L2_TUNER_RADIO)
+		freq = freq / 1000;
+
+	N = freq + priv->sgIF;
+
+	i = 0;
+	while (tda827x_table[i].lomax < N * 62500) {
+		if (tda827x_table[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	N = N << tda827x_table[i].spd;
+
+	tuner_reg[0] = 0;
+	tuner_reg[1] = (unsigned char)(N>>8);
+	tuner_reg[2] = (unsigned char) N;
+	tuner_reg[3] = 0x40;
+	tuner_reg[4] = 0x52 + (priv->lpsel << 5);
+	tuner_reg[5] = (tda827x_table[i].spd    << 6) +
+		       (tda827x_table[i].div1p5 << 5) +
+		       (tda827x_table[i].bs     << 3) + tda827x_table[i].bp;
+	tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4);
+	tuner_reg[7] = 0x8f;
+
+	msg.buf = tuner_reg;
+	msg.len = 8;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msg.buf = reg2;
+	msg.len = 2;
+	reg2[0] = 0x80;
+	reg2[1] = 0;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	reg2[0] = 0x60;
+	reg2[1] = 0xbf;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4] + 0x80;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(1);
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4] + 4;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(1);
+	reg2[0] = 0x30;
+	reg2[1] = tuner_reg[4];
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(550);
+	reg2[0] = 0x30;
+	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	reg2[0] = 0x60;
+	reg2[1] = 0x3f;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	reg2[0] = 0x80;
+	reg2[1] = 0x08;   /* Vsync en */
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	priv->frequency = freq * 62500;
+
+	return 0;
+}
+
+static void tda827xo_agcf(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	unsigned char data[] = { 0x80, 0x0c };
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = data, .len = 2};
+
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+}
+
+/* ------------------------------------------------------------------ */
+
 struct tda827xa_data {
 	u32 lomax;
 	u8  svco;
@@ -212,6 +360,35 @@ static const struct tda827xa_data tda827xa_dvbt[] = {
 	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
 };
 
+static struct tda827xa_data tda827xa_analog[] = {
+	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
+	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
+	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},
+	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},
+	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
+	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
+	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
+	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
+	{ .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
+	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
+	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
+	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
+	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
+};
+
 static int tda827xa_set_params(struct dvb_frontend *fe,
 			       struct dvb_frontend_parameters *params)
 {
@@ -368,6 +545,163 @@ static int tda827xa_sleep(struct dvb_frontend *fe)
 	return 0;
 }
 
+/* ------------------------------------------------------------------ */
+
+static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+			      struct analog_parameters *params)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	unsigned char buf[] = {0x22, 0x01};
+	int arg;
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = buf, .len = sizeof(buf) };
+
+	if (NULL == priv->cfg) {
+		dprintk("tda827x_config not defined, cannot set LNA gain!\n");
+		return;
+	}
+
+	if (priv->cfg->config) {
+		if (high)
+			dprintk("setting LNA to high gain\n");
+		else
+			dprintk("setting LNA to low gain\n");
+	}
+	switch (*priv->cfg->config) {
+	case 0: /* no LNA */
+		break;
+	case 1: /* switch is GPIO 0 of tda8290 */
+	case 2:
+		/* turn Vsync on */
+		if (params->std & V4L2_STD_MN)
+			arg = 1;
+		else
+			arg = 0;
+		if (priv->cfg->tuner_callback)
+			priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
+						  1, arg);
+		buf[1] = high ? 0 : 1;
+		if (*priv->cfg->config == 2)
+			buf[1] = high ? 1 : 0;
+		i2c_transfer(priv->i2c_adap, &msg, 1);
+		break;
+	case 3: /* switch with GPIO of saa713x */
+		if (priv->cfg->tuner_callback)
+			priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
+						  0, high);
+		break;
+	}
+}
+
+static int tda827xa_set_analog_params(struct dvb_frontend *fe,
+				      struct analog_parameters *params)
+{
+	unsigned char tuner_reg[11];
+	u32 N;
+	int i;
+	struct tda827x_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+			       .buf = tuner_reg, .len = sizeof(tuner_reg) };
+	unsigned int freq = params->frequency;
+
+	tda827x_set_std(fe, params);
+
+	tda827xa_lna_gain(fe, 1, params);
+	msleep(10);
+
+	if (params->mode == V4L2_TUNER_RADIO)
+		freq = freq / 1000;
+
+	N = freq + priv->sgIF;
+
+	i = 0;
+	while (tda827xa_analog[i].lomax < N * 62500) {
+		if (tda827xa_analog[i + 1].lomax == 0)
+			break;
+		i++;
+	}
+
+	N = N << tda827xa_analog[i].spd;
+
+	tuner_reg[0] = 0;
+	tuner_reg[1] = (unsigned char)(N>>8);
+	tuner_reg[2] = (unsigned char) N;
+	tuner_reg[3] = 0;
+	tuner_reg[4] = 0x16;
+	tuner_reg[5] = (tda827xa_analog[i].spd << 5) +
+		       (tda827xa_analog[i].svco << 3) +
+			tda827xa_analog[i].sbs;
+	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
+	tuner_reg[7] = 0x1c;
+	tuner_reg[8] = 4;
+	tuner_reg[9] = 0x20;
+	tuner_reg[10] = 0x00;
+	msg.len = 11;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0x90;
+	tuner_reg[1] = 0xff;
+	tuner_reg[2] = 0xe0;
+	tuner_reg[3] = 0;
+	tuner_reg[4] = 0x99 + (priv->lpsel << 1);
+	msg.len = 5;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0xa0;
+	tuner_reg[1] = 0xc0;
+	msg.len = 2;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0x30;
+	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msg.flags = I2C_M_RD;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+	msg.flags = 0;
+	tuner_reg[1] >>= 4;
+	dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
+	if (tuner_reg[1] < 1)
+		tda827xa_lna_gain(fe, 0, params);
+
+	msleep(100);
+	tuner_reg[0] = 0x60;
+	tuner_reg[1] = 0x3c;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	msleep(163);
+	tuner_reg[0] = 0x50;
+	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0x80;
+	tuner_reg[1] = 0x28;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0xb0;
+	tuner_reg[1] = 0x01;
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	tuner_reg[0] = 0xc0;
+	tuner_reg[1] = 0x19 + (priv->lpsel << 1);
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+
+	priv->frequency = freq * 62500;
+
+	return 0;
+}
+
+static void tda827xa_agcf(struct dvb_frontend *fe)
+{
+	struct tda827x_priv *priv = fe->tuner_priv;
+	unsigned char data[] = {0x80, 0x2c};
+	struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
+			      .buf = data, .len = 2};
+	i2c_transfer(priv->i2c_adap, &msg, 1);
+}
+
+/* ------------------------------------------------------------------ */
+
 static int tda827x_release(struct dvb_frontend *fe)
 {
 	kfree(fe->tuner_priv);
@@ -430,6 +764,7 @@ static struct dvb_tuner_ops tda827xo_tuner_ops = {
 	.init = tda827x_initial_init,
 	.sleep = tda827x_initial_sleep,
 	.set_params = tda827xo_set_params,
+	.set_analog_params = tda827xo_set_analog_params,
 	.get_frequency = tda827x_get_frequency,
 	.get_bandwidth = tda827x_get_bandwidth,
 };
@@ -445,6 +780,7 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = {
 	.init = tda827x_init,
 	.sleep = tda827xa_sleep,
 	.set_params = tda827xa_set_params,
+	.set_analog_params = tda827xa_set_analog_params,
 	.get_frequency = tda827x_get_frequency,
 	.get_bandwidth = tda827x_get_bandwidth,
 };
@@ -465,9 +801,13 @@ static int tda827x_probe_version(struct dvb_frontend *fe)
 		dprintk("tda827x tuner found\n");
 		fe->ops.tuner_ops.init  = tda827x_init;
 		fe->ops.tuner_ops.sleep = tda827xo_sleep;
+		if (priv->cfg)
+			priv->cfg->agcf = tda827xo_agcf;
 	} else {
 		dprintk("tda827xa tuner found\n");
 		memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
+		if (priv->cfg)
+			priv->cfg->agcf = tda827xa_agcf;
 	}
 	return 0;
 }
@@ -487,16 +827,13 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
 	priv->i2c_adap = i2c;
 	priv->cfg = cfg;
 	memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
-
 	fe->tuner_priv = priv;
 
+	dprintk("type set to %s\n", fe->ops.tuner_ops.info.name);
+
 	return fe;
 }
-
-EXPORT_SYMBOL(tda827x_attach);
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+EXPORT_SYMBOL_GPL(tda827x_attach);
 
 MODULE_DESCRIPTION("DVB TDA827x driver");
 MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>");
diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h
index 69e8263d6d59..92eb65b4012b 100644
--- a/drivers/media/dvb/frontends/tda827x.h
+++ b/drivers/media/dvb/frontends/tda827x.h
@@ -29,9 +29,16 @@
 
 struct tda827x_config
 {
+	/* saa7134 - provided callbacks */
 	void (*lna_gain) (struct dvb_frontend *fe, int high);
 	int (*init) (struct dvb_frontend *fe);
 	int (*sleep) (struct dvb_frontend *fe);
+
+	/* interface to tda829x driver */
+	unsigned int *config;
+	int (*tuner_callback) (void *dev, int command, int arg);
+
+	void (*agcf)(struct dvb_frontend *fe);
 };
 
 
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index 60433b5011fd..8791701c8f25 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -65,7 +65,7 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data)
 	ret = i2c_transfer(state->i2c, &msg, 1);
 
 	if (ret != 1)
-		printk("ves1820: %s(): writereg error (reg == 0x%02x,"
+		printk("ves1820: %s(): writereg error (reg == 0x%02x, "
 			"val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret);
 
 	return (ret != 1) ? -EREMOTEIO : 0;
@@ -84,7 +84,7 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg)
 	ret = i2c_transfer(state->i2c, msg, 2);
 
 	if (ret != 2)
-		printk("ves1820: %s(): readreg error (reg == 0x%02x,"
+		printk("ves1820: %s(): readreg error (reg == 0x%02x, "
 		"ret == %i)\n", __FUNCTION__, reg, ret);
 
 	return b1[0];
diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c
new file mode 100644
index 000000000000..f642ca200b59
--- /dev/null
+++ b/drivers/media/dvb/frontends/xc5000.c
@@ -0,0 +1,964 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Xceive Corporation
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *
+ *  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/videodev2.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "xc5000.h"
+#include "xc5000_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
+
+#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
+#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+
+/* Misc Defines */
+#define MAX_TV_STANDARD			23
+#define XC_MAX_I2C_WRITE_LENGTH		64
+
+/* Signal Types */
+#define XC_RF_MODE_AIR			0
+#define XC_RF_MODE_CABLE		1
+
+/* Result codes */
+#define XC_RESULT_SUCCESS		0
+#define XC_RESULT_RESET_FAILURE		1
+#define XC_RESULT_I2C_WRITE_FAILURE	2
+#define XC_RESULT_I2C_READ_FAILURE	3
+#define XC_RESULT_OUT_OF_RANGE		5
+
+/* Product id */
+#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
+#define XC_PRODUCT_ID_FW_LOADED 	0x1388
+
+/* Registers */
+#define XREG_INIT         0x00
+#define XREG_VIDEO_MODE   0x01
+#define XREG_AUDIO_MODE   0x02
+#define XREG_RF_FREQ      0x03
+#define XREG_D_CODE       0x04
+#define XREG_IF_OUT       0x05
+#define XREG_SEEK_MODE    0x07
+#define XREG_POWER_DOWN   0x0A
+#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
+#define XREG_SMOOTHEDCVBS 0x0E
+#define XREG_XTALFREQ     0x0F
+#define XREG_FINERFFREQ   0x10
+#define XREG_DDIMODE      0x11
+
+#define XREG_ADC_ENV      0x00
+#define XREG_QUALITY      0x01
+#define XREG_FRAME_LINES  0x02
+#define XREG_HSYNC_FREQ   0x03
+#define XREG_LOCK         0x04
+#define XREG_FREQ_ERROR   0x05
+#define XREG_SNR          0x06
+#define XREG_VERSION      0x07
+#define XREG_PRODUCT_ID   0x08
+#define XREG_BUSY         0x09
+
+/*
+   Basic firmware description. This will remain with
+   the driver for documentation purposes.
+
+   This represents an I2C firmware file encoded as a
+   string of unsigned char. Format is as follows:
+
+   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
+   char[1  ]=len0_LSB  -> length of first write transaction
+   char[2  ]=data0 -> first byte to be sent
+   char[3  ]=data1
+   char[4  ]=data2
+   char[   ]=...
+   char[M  ]=dataN  -> last byte to be sent
+   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
+   char[M+2]=len1_LSB  -> length of second write transaction
+   char[M+3]=data0
+   char[M+4]=data1
+   ...
+   etc.
+
+   The [len] value should be interpreted as follows:
+
+   len= len_MSB _ len_LSB
+   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
+   len=0000_0000_0000_0000   : Reset command: Do hardware reset
+   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
+   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
+
+   For the RESET and WAIT commands, the two following bytes will contain
+   immediately the length of the following transaction.
+
+*/
+typedef struct {
+	char *Name;
+	u16 AudioMode;
+	u16 VideoMode;
+} XC_TV_STANDARD;
+
+/* Tuner standards */
+#define MN_NTSC_PAL_BTSC	0
+#define MN_NTSC_PAL_A2		1
+#define MN_NTSC_PAL_EIAJ	2
+#define MN_NTSC_PAL_Mono	3
+#define BG_PAL_A2		4
+#define BG_PAL_NICAM		5
+#define BG_PAL_MONO		6
+#define I_PAL_NICAM		7
+#define I_PAL_NICAM_MONO	8
+#define DK_PAL_A2		9
+#define DK_PAL_NICAM		10
+#define DK_PAL_MONO		11
+#define DK_SECAM_A2DK1		12
+#define DK_SECAM_A2LDK3 	13
+#define DK_SECAM_A2MONO 	14
+#define L_SECAM_NICAM		15
+#define LC_SECAM_NICAM		16
+#define DTV6			17
+#define DTV8			18
+#define DTV7_8			19
+#define DTV7			20
+#define FM_Radio_INPUT2 	21
+#define FM_Radio_INPUT1 	22
+
+XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+	{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
+	{"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
+	{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
+	{"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
+	{"B/G-PAL-A2",        0x0A00, 0x8049},
+	{"B/G-PAL-NICAM",     0x0C04, 0x8049},
+	{"B/G-PAL-MONO",      0x0878, 0x8059},
+	{"I-PAL-NICAM",       0x1080, 0x8009},
+	{"I-PAL-NICAM-MONO",  0x0E78, 0x8009},
+	{"D/K-PAL-A2",        0x1600, 0x8009},
+	{"D/K-PAL-NICAM",     0x0E80, 0x8009},
+	{"D/K-PAL-MONO",      0x1478, 0x8009},
+	{"D/K-SECAM-A2 DK1",  0x1200, 0x8009},
+	{"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009},
+	{"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
+	{"L-SECAM-NICAM",     0x8E82, 0x0009},
+	{"L'-SECAM-NICAM",    0x8E82, 0x4009},
+	{"DTV6",              0x00C0, 0x8002},
+	{"DTV8",              0x00C0, 0x800B},
+	{"DTV7/8",            0x00C0, 0x801B},
+	{"DTV7",              0x00C0, 0x8007},
+	{"FM Radio-INPUT2",   0x9802, 0x9002},
+	{"FM Radio-INPUT1",   0x0208, 0x9002}
+};
+
+static int  xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
+static int  xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
+static void xc5000_TunerReset(struct dvb_frontend *fe);
+
+static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+	return xc5000_writeregs(priv, buf, len)
+		? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
+}
+
+static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
+{
+	return xc5000_readregs(priv, buf, len)
+		? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
+}
+
+static int xc_reset(struct dvb_frontend *fe)
+{
+	xc5000_TunerReset(fe);
+	return XC_RESULT_SUCCESS;
+}
+
+static void xc_wait(int wait_ms)
+{
+	msleep(wait_ms);
+}
+
+static void xc5000_TunerReset(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	if (priv->cfg->tuner_callback) {
+		ret = priv->cfg->tuner_callback(priv->cfg->priv,
+						XC5000_TUNER_RESET, 0);
+		if (ret)
+			printk(KERN_ERR "xc5000: reset failed\n");
+	} else
+		printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
+}
+
+static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
+{
+	u8 buf[4];
+	int WatchDogTimer = 5;
+	int result;
+
+	buf[0] = (regAddr >> 8) & 0xFF;
+	buf[1] = regAddr & 0xFF;
+	buf[2] = (i2cData >> 8) & 0xFF;
+	buf[3] = i2cData & 0xFF;
+	result = xc_send_i2c_data(priv, buf, 4);
+	if (result == XC_RESULT_SUCCESS) {
+		/* wait for busy flag to clear */
+		while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
+			buf[0] = 0;
+			buf[1] = XREG_BUSY;
+
+			result = xc_send_i2c_data(priv, buf, 2);
+			if (result == XC_RESULT_SUCCESS) {
+				result = xc_read_i2c_data(priv, buf, 2);
+				if (result == XC_RESULT_SUCCESS) {
+					if ((buf[0] == 0) && (buf[1] == 0)) {
+						/* busy flag cleared */
+					break;
+					} else {
+						xc_wait(100); /* wait 5 ms */
+						WatchDogTimer--;
+					}
+				}
+			}
+		}
+	}
+	if (WatchDogTimer < 0)
+		result = XC_RESULT_I2C_WRITE_FAILURE;
+
+	return result;
+}
+
+static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
+{
+	u8 buf[2];
+	int result;
+
+	buf[0] = (regAddr >> 8) & 0xFF;
+	buf[1] = regAddr & 0xFF;
+	result = xc_send_i2c_data(priv, buf, 2);
+	if (result != XC_RESULT_SUCCESS)
+		return result;
+
+	result = xc_read_i2c_data(priv, buf, 2);
+	if (result != XC_RESULT_SUCCESS)
+		return result;
+
+	*i2cData = buf[0] * 256 + buf[1];
+	return result;
+}
+
+static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[])
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+
+	int i, nbytes_to_send, result;
+	unsigned int len, pos, index;
+	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
+
+	index=0;
+	while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) {
+		len = i2c_sequence[index]* 256 + i2c_sequence[index+1];
+		if (len == 0x0000) {
+			/* RESET command */
+			result = xc_reset(fe);
+			index += 2;
+			if (result != XC_RESULT_SUCCESS)
+				return result;
+		} else if (len & 0x8000) {
+			/* WAIT command */
+			xc_wait(len & 0x7FFF);
+			index += 2;
+		} else {
+			/* Send i2c data whilst ensuring individual transactions
+			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
+			 */
+			index += 2;
+			buf[0] = i2c_sequence[index];
+			buf[1] = i2c_sequence[index + 1];
+			pos = 2;
+			while (pos < len) {
+				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) {
+					nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH;
+				} else {
+					nbytes_to_send = (len - pos + 2);
+				}
+				for (i=2; i<nbytes_to_send; i++) {
+					buf[i] = i2c_sequence[index + pos + i - 2];
+				}
+				result = xc_send_i2c_data(priv, buf, nbytes_to_send);
+
+				if (result != XC_RESULT_SUCCESS)
+					return result;
+
+				pos += nbytes_to_send - 2;
+			}
+			index += len;
+		}
+	}
+	return XC_RESULT_SUCCESS;
+}
+
+static int xc_initialize(struct xc5000_priv *priv)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+	return xc_write_reg(priv, XREG_INIT, 0);
+}
+
+static int xc_SetTVStandard(struct xc5000_priv *priv,
+	u16 VideoMode, u16 AudioMode)
+{
+	int ret;
+	dprintk(1, "%s(0x%04x,0x%04x)\n", __FUNCTION__, VideoMode, AudioMode);
+	dprintk(1, "%s() Standard = %s\n",
+		__FUNCTION__,
+		XC5000_Standard[priv->video_standard].Name);
+
+	ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
+	if (ret == XC_RESULT_SUCCESS)
+		ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
+
+	return ret;
+}
+
+static int xc_shutdown(struct xc5000_priv *priv)
+{
+	return 0;
+	/* Fixme: cannot bring tuner back alive once shutdown
+	 *        without reloading the driver modules.
+	 *    return xc_write_reg(priv, XREG_POWER_DOWN, 0);
+	 */
+}
+
+static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
+{
+	dprintk(1, "%s(%d) Source = %s\n", __FUNCTION__, rf_mode,
+		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
+
+	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE))
+	{
+		rf_mode = XC_RF_MODE_CABLE;
+		printk(KERN_ERR
+			"%s(), Invalid mode, defaulting to CABLE",
+			__FUNCTION__);
+	}
+	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
+}
+
+static const struct dvb_tuner_ops xc5000_tuner_ops;
+
+static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
+{
+	u16 freq_code;
+
+	dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
+
+	if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
+		(freq_hz < xc5000_tuner_ops.info.frequency_min))
+		return XC_RESULT_OUT_OF_RANGE;
+
+	freq_code = (u16)(freq_hz / 15625);
+
+	return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+}
+
+
+static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
+{
+	u32 freq_code = (freq_khz * 1024)/1000;
+	dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
+		__FUNCTION__, freq_khz, freq_code);
+
+	return xc_write_reg(priv, XREG_IF_OUT, freq_code);
+}
+
+
+static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
+{
+	return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
+}
+
+static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
+{
+	int result;
+	u16 regData;
+	u32 tmp;
+
+	result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
+	if (result)
+		return result;
+
+	tmp = (u32)regData;
+	(*freq_error_hz) = (tmp * 15625) / 1000;
+	return result;
+}
+
+static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
+{
+	return xc_read_reg(priv, XREG_LOCK, lock_status);
+}
+
+static int xc_get_version(struct xc5000_priv *priv,
+	u8 *hw_majorversion, u8 *hw_minorversion,
+	u8 *fw_majorversion, u8 *fw_minorversion)
+{
+	u16 data;
+	int result;
+
+	result = xc_read_reg(priv, XREG_VERSION, &data);
+	if (result)
+		return result;
+
+	(*hw_majorversion) = (data >> 12) & 0x0F;
+	(*hw_minorversion) = (data >>  8) & 0x0F;
+	(*fw_majorversion) = (data >>  4) & 0x0F;
+	(*fw_minorversion) = data & 0x0F;
+
+	return 0;
+}
+
+static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
+{
+	u16 regData;
+	int result;
+
+	result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
+	if (result)
+		return result;
+
+	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+	return result;
+}
+
+static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
+{
+	return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
+}
+
+static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
+{
+	return xc_read_reg(priv, XREG_QUALITY, quality);
+}
+
+static u16 WaitForLock(struct xc5000_priv *priv)
+{
+	u16 lockState = 0;
+	int watchDogCount = 40;
+
+	while ((lockState == 0) && (watchDogCount > 0)) {
+		xc_get_lock_status(priv, &lockState);
+		if (lockState != 1) {
+			xc_wait(5);
+			watchDogCount--;
+		}
+	}
+	return lockState;
+}
+
+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
+{
+	int found = 0;
+
+	dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz);
+
+	if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
+		return 0;
+
+	if (WaitForLock(priv) == 1)
+		found = 1;
+
+	return found;
+}
+
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
+{
+	u8 buf[2] = { reg >> 8, reg & 0xff };
+	u8 bval[2] = { 0, 0 };
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address,
+			.flags = 0, .buf = &buf[0], .len = 2 },
+		{ .addr = priv->cfg->i2c_address,
+			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "xc5000: I2C read failed\n");
+		return -EREMOTEIO;
+	}
+
+	*val = (bval[0] << 8) | bval[1];
+	return 0;
+}
+
+static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
+{
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+		.flags = 0, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
+			(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
+{
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+		.flags = I2C_M_RD, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int xc5000_fwupload(struct dvb_frontend* fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	const struct firmware *fw;
+	int ret;
+
+	/* request the firmware, this will block and timeout */
+	printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
+		XC5000_DEFAULT_FIRMWARE);
+
+	ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
+	if (ret) {
+		printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
+		ret = XC_RESULT_RESET_FAILURE;
+		goto out;
+	} else {
+		printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
+		       fw->size);
+		ret = XC_RESULT_SUCCESS;
+	}
+
+	if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) {
+		printk(KERN_ERR "xc5000: firmware incorrect size\n");
+		ret = XC_RESULT_RESET_FAILURE;
+	} else {
+		printk(KERN_INFO "xc5000: firmware upload\n");
+		ret = xc_load_i2c_sequence(fe,  fw->data );
+	}
+
+out:
+	release_firmware(fw);
+	return ret;
+}
+
+static void xc_debug_dump(struct xc5000_priv *priv)
+{
+	u16 adc_envelope;
+	u32 freq_error_hz = 0;
+	u16 lock_status;
+	u32 hsync_freq_hz = 0;
+	u16 frame_lines;
+	u16 quality;
+	u8 hw_majorversion = 0, hw_minorversion = 0;
+	u8 fw_majorversion = 0, fw_minorversion = 0;
+
+	/* Wait for stats to stabilize.
+	 * Frame Lines needs two frame times after initial lock
+	 * before it is valid.
+	 */
+	xc_wait(100);
+
+	xc_get_ADC_Envelope(priv,  &adc_envelope);
+	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
+
+	xc_get_frequency_error(priv, &freq_error_hz);
+	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
+
+	xc_get_lock_status(priv,  &lock_status);
+	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
+		lock_status);
+
+	xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
+		&fw_majorversion, &fw_minorversion);
+	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+		hw_majorversion, hw_minorversion,
+		fw_majorversion, fw_minorversion);
+
+	xc_get_hsync_freq(priv,  &hsync_freq_hz);
+	dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
+
+	xc_get_frame_lines(priv,  &frame_lines);
+	dprintk(1, "*** Frame lines = %d\n", frame_lines);
+
+	xc_get_quality(priv,  &quality);
+	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+}
+
+static int xc5000_set_params(struct dvb_frontend *fe,
+	struct dvb_frontend_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency);
+
+	switch(params->u.vsb.modulation) {
+	case VSB_8:
+	case VSB_16:
+		dprintk(1, "%s() VSB modulation\n", __FUNCTION__);
+		priv->rf_mode = XC_RF_MODE_AIR;
+		priv->freq_hz = params->frequency - 1750000;
+		priv->bandwidth = BANDWIDTH_6_MHZ;
+		priv->video_standard = DTV6;
+		break;
+	case QAM_64:
+	case QAM_256:
+	case QAM_AUTO:
+		dprintk(1, "%s() QAM modulation\n", __FUNCTION__);
+		priv->rf_mode = XC_RF_MODE_CABLE;
+		priv->freq_hz = params->frequency - 1750000;
+		priv->bandwidth = BANDWIDTH_6_MHZ;
+		priv->video_standard = DTV6;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dprintk(1, "%s() frequency=%d (compensated)\n",
+		__FUNCTION__, priv->freq_hz);
+
+	ret = xc_SetSignalSource(priv, priv->rf_mode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: xc_SetSignalSource(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	ret = xc_SetTVStandard(priv,
+		XC5000_Standard[priv->video_standard].VideoMode,
+		XC5000_Standard[priv->video_standard].AudioMode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+		return -EREMOTEIO;
+	}
+
+	ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
+			priv->cfg->if_khz);
+		return -EIO;
+	}
+
+	xc_tune_channel(priv, priv->freq_hz);
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return 0;
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
+
+static int xc5000_set_analog_params(struct dvb_frontend *fe,
+	struct analog_parameters *params)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	if(priv->fwloaded == 0)
+		xc_load_fw_and_init_tuner(fe);
+
+	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
+		__FUNCTION__, params->frequency);
+
+	priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */
+
+	/* params->frequency is in units of 62.5khz */
+	priv->freq_hz = params->frequency * 62500;
+
+	/* FIX ME: Some video standards may have several possible audio
+		   standards. We simply default to one of them here.
+	 */
+	if(params->std & V4L2_STD_MN) {
+		/* default to BTSC audio standard */
+		priv->video_standard = MN_NTSC_PAL_BTSC;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_PAL_BG) {
+		/* default to NICAM audio standard */
+		priv->video_standard = BG_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_PAL_I) {
+		/* default to NICAM audio standard */
+		priv->video_standard = I_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_PAL_DK) {
+		/* default to NICAM audio standard */
+		priv->video_standard = DK_PAL_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_SECAM_DK) {
+		/* default to A2 DK1 audio standard */
+		priv->video_standard = DK_SECAM_A2DK1;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_SECAM_L) {
+		priv->video_standard = L_SECAM_NICAM;
+		goto tune_channel;
+	}
+
+	if(params->std & V4L2_STD_SECAM_LC) {
+		priv->video_standard = LC_SECAM_NICAM;
+		goto tune_channel;
+	}
+
+tune_channel:
+	ret = xc_SetSignalSource(priv, priv->rf_mode);
+	if (ret != XC_RESULT_SUCCESS) {
+	printk(KERN_ERR
+			"xc5000: xc_SetSignalSource(%d) failed\n",
+			priv->rf_mode);
+		return -EREMOTEIO;
+	}
+
+	ret = xc_SetTVStandard(priv,
+		XC5000_Standard[priv->video_standard].VideoMode,
+		XC5000_Standard[priv->video_standard].AudioMode);
+	if (ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+		return -EREMOTEIO;
+	}
+
+	xc_tune_channel(priv, priv->freq_hz);
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return 0;
+}
+
+static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __FUNCTION__);
+	*freq = priv->freq_hz;
+	return 0;
+}
+
+static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	*bw = priv->bandwidth;
+	return 0;
+}
+
+static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	u16 lock_status = 0;
+
+	xc_get_lock_status(priv, &lock_status);
+
+	dprintk(1, "%s() lock_status = 0x%08x\n", __FUNCTION__, lock_status);
+
+	*status = lock_status;
+
+	return 0;
+}
+
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret = 0;
+
+	if (priv->fwloaded == 0) {
+		ret = xc5000_fwupload(fe);
+		if (ret != XC_RESULT_SUCCESS)
+			return ret;
+		priv->fwloaded = 1;
+	}
+
+	/* Start the tuner self-calibration process */
+	ret |= xc_initialize(priv);
+
+	/* Wait for calibration to complete.
+	 * We could continue but XC5000 will clock stretch subsequent
+	 * I2C transactions until calibration is complete.  This way we
+	 * don't have to rely on clock stretching working.
+	 */
+	xc_wait( 100 );
+
+	/* Default to "CABLE" mode */
+	ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
+
+	return ret;
+}
+
+static int xc5000_sleep(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	int ret;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	/* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
+	 * once shutdown without reloading the driver. Maybe I am not
+	 * doing something right.
+	 *
+	 */
+
+	ret = xc_shutdown(priv);
+	if(ret != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR
+			"xc5000: %s() unable to shutdown tuner\n",
+			__FUNCTION__);
+		return -EREMOTEIO;
+	}
+	else {
+		/* priv->fwloaded = 0; */
+		return XC_RESULT_SUCCESS;
+	}
+}
+
+static int xc5000_init(struct dvb_frontend *fe)
+{
+	struct xc5000_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
+		printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
+		return -EREMOTEIO;
+	}
+
+	if (debug)
+		xc_debug_dump(priv);
+
+	return 0;
+}
+
+static int xc5000_release(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops xc5000_tuner_ops = {
+	.info = {
+		.name           = "Xceive XC5000",
+		.frequency_min  =    1000000,
+		.frequency_max  = 1023000000,
+		.frequency_step =      50000,
+	},
+
+	.release	   = xc5000_release,
+	.init		   = xc5000_init,
+	.sleep		   = xc5000_sleep,
+
+	.set_params	   = xc5000_set_params,
+	.set_analog_params = xc5000_set_analog_params,
+	.get_frequency	   = xc5000_get_frequency,
+	.get_bandwidth	   = xc5000_get_bandwidth,
+	.get_status	   = xc5000_get_status
+};
+
+struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe,
+	struct i2c_adapter *i2c,
+	struct xc5000_config *cfg)
+{
+	struct xc5000_priv *priv = NULL;
+	u16 id = 0;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->bandwidth = BANDWIDTH_6_MHZ;
+	priv->i2c = i2c;
+
+	/* Check if firmware has been loaded. It is possible that another
+	   instance of the driver has loaded the firmware.
+	 */
+	if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
+		kfree(priv);
+		return NULL;
+	}
+
+	switch(id) {
+	case XC_PRODUCT_ID_FW_LOADED:
+		printk(KERN_INFO
+			"xc5000: Successfully identified at address 0x%02x\n",
+			cfg->i2c_address);
+		printk(KERN_INFO
+			"xc5000: Firmware has been loaded previously\n");
+		priv->fwloaded = 1;
+		break;
+	case XC_PRODUCT_ID_FW_NOT_LOADED:
+		printk(KERN_INFO
+			"xc5000: Successfully identified at address 0x%02x\n",
+			cfg->i2c_address);
+		printk(KERN_INFO
+			"xc5000: Firmware has not been loaded previously\n");
+		priv->fwloaded = 0;
+		break;
+	default:
+		printk(KERN_ERR
+			"xc5000: Device not found at addr 0x%02x (0x%x)\n",
+			cfg->i2c_address, id);
+		kfree(priv);
+		return NULL;
+	}
+
+	memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
+		sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+
+	return fe;
+}
+EXPORT_SYMBOL(xc5000_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h
new file mode 100644
index 000000000000..e0e84562aed1
--- /dev/null
+++ b/drivers/media/dvb/frontends/xc5000.h
@@ -0,0 +1,62 @@
+/*
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *
+ *  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 __XC5000_H__
+#define __XC5000_H__
+
+#include <linux/firmware.h>
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct xc5000_config {
+	u8   i2c_address;
+	u32  if_khz;
+
+	/* For each bridge framework, when it attaches either analog or digital,
+	 * it has to store a reference back to its _core equivalent structure,
+	 * so that it can service the hardware by steering gpio's etc.
+	 * Each bridge implementation is different so cast priv accordingly.
+	 * The xc5000 driver cares not for this value, other than ensuring
+	 * it's passed back to a bridge during tuner_callback().
+	 */
+	void *priv;
+	int  (*tuner_callback) (void *priv, int command, int arg);
+};
+
+/* xc5000 callback command */
+#define XC5000_TUNER_RESET		0
+
+#if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE)
+extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+					  struct i2c_adapter *i2c,
+					  struct xc5000_config *cfg);
+#else
+static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
+						 struct i2c_adapter *i2c,
+						 struct xc5000_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TUNER_XC5000
+
+#endif // __XC5000_H__
diff --git a/drivers/i2c/busses/i2c-au1550.h b/drivers/media/dvb/frontends/xc5000_priv.h
index fce15d161ae7..13b2d19341da 100644
--- a/drivers/i2c/busses/i2c-au1550.h
+++ b/drivers/media/dvb/frontends/xc5000_priv.h
@@ -1,6 +1,7 @@
 /*
- * Copyright (C) 2004 Embedded Edge, LLC <dan@embeddededge.com>
- * 2.6 port by Matt Porter <mporter@kernel.crashing.org>
+ *  Driver for Xceive XC5000 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
  *
  *  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
@@ -10,6 +11,7 @@
  *  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
@@ -17,16 +19,18 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#ifndef I2C_AU1550_H
-#define I2C_AU1550_H
+#ifndef XC5000_PRIV_H
+#define XC5000_PRIV_H
 
-struct i2c_au1550_data {
-	u32	psc_base;
-	int	xfer_timeout;
-	int	ack_timeout;
-};
+struct xc5000_priv {
+	struct xc5000_config *cfg;
+	struct i2c_adapter   *i2c;
 
-int i2c_au1550_add_bus(struct i2c_adapter *);
-int i2c_au1550_del_bus(struct i2c_adapter *);
+	u32 freq_hz;
+	u32 bandwidth;
+	u8  video_standard;
+	u8  rf_mode;
+	u8  fwloaded;
+};
 
-#endif /* I2C_AU1550_H */
+#endif
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 0106df4c55e8..276e3b631dc2 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -1,7 +1,7 @@
 /*
  * Driver for Zarlink DVB-T ZL10353 demodulator
  *
- * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ * Copyright (C) 2006, 2007 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
@@ -16,7 +16,7 @@
  *
  * 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.=
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/kernel.h>
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/slab.h>
+#include <asm/div64.h>
 
 #include "dvb_frontend.h"
 #include "zl10353_priv.h"
@@ -35,6 +36,8 @@ struct zl10353_state {
 	struct dvb_frontend frontend;
 
 	struct zl10353_config config;
+
+	enum fe_bandwidth bandwidth;
 };
 
 static int debug;
@@ -122,9 +125,10 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
 				      enum fe_bandwidth bandwidth,
 				      u16 *nominal_rate)
 {
-	u32 adc_clock = 45056; /* 45.056 MHz */
-	u8 bw;
 	struct zl10353_state *state = fe->demodulator_priv;
+	u32 adc_clock = 450560; /* 45.056 MHz */
+	u64 value;
+	u8 bw;
 
 	if (state->config.adc_clock)
 		adc_clock = state->config.adc_clock;
@@ -142,12 +146,44 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
 		break;
 	}
 
-	*nominal_rate = (bw * (1 << 23) / 7 * 125 + adc_clock / 2) / adc_clock;
+	value = (u64)10 * (1 << 23) / 7 * 125;
+	value = (bw * value) + adc_clock / 2;
+	do_div(value, adc_clock);
+	*nominal_rate = value;
 
 	dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
 		__FUNCTION__, bw, adc_clock, *nominal_rate);
 }
 
+static void zl10353_calc_input_freq(struct dvb_frontend *fe,
+				    u16 *input_freq)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	u32 adc_clock = 450560;	/* 45.056  MHz */
+	int if2 = 361667;	/* 36.1667 MHz */
+	int ife;
+	u64 value;
+
+	if (state->config.adc_clock)
+		adc_clock = state->config.adc_clock;
+	if (state->config.if2)
+		if2 = state->config.if2;
+
+	if (adc_clock >= if2 * 2)
+		ife = if2;
+	else {
+		ife = adc_clock - (if2 % adc_clock);
+		if (ife > adc_clock / 2)
+			ife = adc_clock - ife;
+	}
+	value = (u64)65536 * ife + adc_clock / 2;
+	do_div(value, adc_clock);
+	*input_freq = -value;
+
+	dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
+		__FUNCTION__, if2, ife, adc_clock, -(int)value, *input_freq);
+}
+
 static int zl10353_sleep(struct dvb_frontend *fe)
 {
 	static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
@@ -160,64 +196,276 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
 				  struct dvb_frontend_parameters *param)
 {
 	struct zl10353_state *state = fe->demodulator_priv;
-	u16 nominal_rate;
-	u8 pllbuf[6] = { 0x67 };
+	u16 nominal_rate, input_freq;
+	u8 pllbuf[6] = { 0x67 }, acq_ctl = 0;
+	u16 tps = 0;
+	struct dvb_ofdm_parameters *op = &param->u.ofdm;
 
-	/* These settings set "auto-everything" and start the FSM. */
-	zl10353_single_write(fe, 0x55, 0x80);
+	zl10353_single_write(fe, RESET, 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, AGC_TARGET, 0x28);
+
+	if (op->transmission_mode != TRANSMISSION_MODE_AUTO)
+		acq_ctl |= (1 << 0);
+	if (op->guard_interval != GUARD_INTERVAL_AUTO)
+		acq_ctl |= (1 << 1);
+	zl10353_single_write(fe, ACQ_CTL, acq_ctl);
 
-	zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate);
+	switch (op->bandwidth) {
+	case BANDWIDTH_6_MHZ:
+		/* These are extrapolated from the 7 and 8MHz values */
+		zl10353_single_write(fe, MCLK_RATIO, 0x97);
+		zl10353_single_write(fe, 0x64, 0x34);
+		break;
+	case BANDWIDTH_7_MHZ:
+		zl10353_single_write(fe, MCLK_RATIO, 0x86);
+		zl10353_single_write(fe, 0x64, 0x35);
+		break;
+	case BANDWIDTH_8_MHZ:
+	default:
+		zl10353_single_write(fe, MCLK_RATIO, 0x75);
+		zl10353_single_write(fe, 0x64, 0x36);
+	}
+
+	zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate);
 	zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
 	zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
+	state->bandwidth = op->bandwidth;
+
+	zl10353_calc_input_freq(fe, &input_freq);
+	zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq));
+	zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq));
+
+	/* Hint at TPS settings */
+	switch (op->code_rate_HP) {
+	case FEC_2_3:
+		tps |= (1 << 7);
+		break;
+	case FEC_3_4:
+		tps |= (2 << 7);
+		break;
+	case FEC_5_6:
+		tps |= (3 << 7);
+		break;
+	case FEC_7_8:
+		tps |= (4 << 7);
+		break;
+	case FEC_1_2:
+	case FEC_AUTO:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (op->code_rate_LP) {
+	case FEC_2_3:
+		tps |= (1 << 4);
+		break;
+	case FEC_3_4:
+		tps |= (2 << 4);
+		break;
+	case FEC_5_6:
+		tps |= (3 << 4);
+		break;
+	case FEC_7_8:
+		tps |= (4 << 4);
+		break;
+	case FEC_1_2:
+	case FEC_AUTO:
+		break;
+	case FEC_NONE:
+		if (op->hierarchy_information == HIERARCHY_AUTO ||
+		    op->hierarchy_information == HIERARCHY_NONE)
+			break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (op->constellation) {
+	case QPSK:
+		break;
+	case QAM_AUTO:
+	case QAM_16:
+		tps |= (1 << 13);
+		break;
+	case QAM_64:
+		tps |= (2 << 13);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (op->transmission_mode) {
+	case TRANSMISSION_MODE_2K:
+	case TRANSMISSION_MODE_AUTO:
+		break;
+	case TRANSMISSION_MODE_8K:
+		tps |= (1 << 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (op->guard_interval) {
+	case GUARD_INTERVAL_1_32:
+	case GUARD_INTERVAL_AUTO:
+		break;
+	case GUARD_INTERVAL_1_16:
+		tps |= (1 << 2);
+		break;
+	case GUARD_INTERVAL_1_8:
+		tps |= (2 << 2);
+		break;
+	case GUARD_INTERVAL_1_4:
+		tps |= (3 << 2);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (op->hierarchy_information) {
+	case HIERARCHY_AUTO:
+	case HIERARCHY_NONE:
+		break;
+	case HIERARCHY_1:
+		tps |= (1 << 10);
+		break;
+	case HIERARCHY_2:
+		tps |= (2 << 10);
+		break;
+	case HIERARCHY_4:
+		tps |= (3 << 10);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	zl10353_single_write(fe, TPS_GIVEN_1, msb(tps));
+	zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps));
 
-	zl10353_single_write(fe, 0x6C, 0xCD);
-	zl10353_single_write(fe, 0x6D, 0x7E);
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 0);
 
-	// if there is no attached secondary tuner, we call set_params to program
-	// a potential tuner attached somewhere else
+	/*
+	 * If there is no tuner attached to the secondary I2C bus, we call
+	 * set_params to program a potential tuner attached somewhere else.
+	 * Otherwise, we update the PLL registers via calc_regs.
+	 */
 	if (state->config.no_tuner) {
 		if (fe->ops.tuner_ops.set_params) {
 			fe->ops.tuner_ops.set_params(fe, param);
 			if (fe->ops.i2c_gate_ctrl)
 				fe->ops.i2c_gate_ctrl(fe, 0);
 		}
+	} else if (fe->ops.tuner_ops.calc_regs) {
+		fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5);
+		pllbuf[1] <<= 1;
+		zl10353_write(fe, pllbuf, sizeof(pllbuf));
 	}
 
-	// if pllbuf is defined, retrieve the settings
-	if (fe->ops.tuner_ops.calc_regs) {
-		fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
-		pllbuf[1] <<= 1;
-	} else {
-		// fake pllbuf settings
-		pllbuf[1] = 0x61 << 1;
-		pllbuf[2] = 0;
-		pllbuf[3] = 0;
-		pllbuf[3] = 0;
-		pllbuf[4] = 0;
+	zl10353_single_write(fe, 0x5F, 0x13);
+
+	/* If no attached tuner or invalid PLL registers, just start the FSM. */
+	if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL)
+		zl10353_single_write(fe, FSM_GO, 0x01);
+	else
+		zl10353_single_write(fe, TUNER_GO, 0x01);
+
+	return 0;
+}
+
+static int zl10353_get_parameters(struct dvb_frontend *fe,
+				  struct dvb_frontend_parameters *param)
+{
+	struct zl10353_state *state = fe->demodulator_priv;
+	struct dvb_ofdm_parameters *op = &param->u.ofdm;
+	int s6, s9;
+	u16 tps;
+	static const u8 tps_fec_to_api[8] = {
+		FEC_1_2,
+		FEC_2_3,
+		FEC_3_4,
+		FEC_5_6,
+		FEC_7_8,
+		FEC_AUTO,
+		FEC_AUTO,
+		FEC_AUTO
+	};
+
+	s6 = zl10353_read_register(state, STATUS_6);
+	s9 = zl10353_read_register(state, STATUS_9);
+	if (s6 < 0 || s9 < 0)
+		return -EREMOTEIO;
+	if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0)
+		return -EINVAL;	/* no FE or TPS lock */
+
+	tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 |
+	      zl10353_read_register(state, TPS_RECEIVED_0);
+
+	op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7];
+	op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7];
+
+	switch ((tps >> 13) & 3) {
+	case 0:
+		op->constellation = QPSK;
+		break;
+	case 1:
+		op->constellation = QAM_16;
+		break;
+	case 2:
+		op->constellation = QAM_64;
+		break;
+	default:
+		op->constellation = QAM_AUTO;
+		break;
 	}
 
-	// there is no call to _just_ start decoding, so we send the pllbuf anyway
-	// even if there isn't a PLL attached to the secondary bus
-	zl10353_write(fe, pllbuf, sizeof(pllbuf));
+	op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K :
+					       TRANSMISSION_MODE_2K;
 
-	zl10353_single_write(fe, 0x5F, 0x13);
-	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);
+	switch ((tps >> 2) & 3) {
+	case 0:
+		op->guard_interval = GUARD_INTERVAL_1_32;
+		break;
+	case 1:
+		op->guard_interval = GUARD_INTERVAL_1_16;
+		break;
+	case 2:
+		op->guard_interval = GUARD_INTERVAL_1_8;
+		break;
+	case 3:
+		op->guard_interval = GUARD_INTERVAL_1_4;
+		break;
+	default:
+		op->guard_interval = GUARD_INTERVAL_AUTO;
+		break;
+	}
+
+	switch ((tps >> 10) & 7) {
+	case 0:
+		op->hierarchy_information = HIERARCHY_NONE;
+		break;
+	case 1:
+		op->hierarchy_information = HIERARCHY_1;
+		break;
+	case 2:
+		op->hierarchy_information = HIERARCHY_2;
+		break;
+	case 3:
+		op->hierarchy_information = HIERARCHY_4;
+		break;
+	default:
+		op->hierarchy_information = HIERARCHY_AUTO;
+		break;
+	}
+
+	param->frequency = 0;
+	op->bandwidth = state->bandwidth;
+	param->inversion = INVERSION_AUTO;
 
 	return 0;
 }
@@ -406,6 +654,7 @@ static struct dvb_frontend_ops zl10353_ops = {
 	.write = zl10353_write,
 
 	.set_frontend = zl10353_set_parameters,
+	.get_frontend = zl10353_get_parameters,
 	.get_tune_settings = zl10353_get_tune_settings,
 
 	.read_status = zl10353_read_status,
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
index 1c3d494a6da9..fc734c22b5fa 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for Zarlink DVB-T ZL10353 demodulator
  *
- *  Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *  Copyright (C) 2006, 2007 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
@@ -29,8 +29,9 @@ struct zl10353_config
 	/* demodulator's I2C address */
 	u8 demod_address;
 
-	/* frequencies in kHz */
-	int adc_clock;	/* default: 45056 */
+	/* frequencies in units of 0.1kHz */
+	int adc_clock;	/* default: 450560 (45.056  MHz) */
+	int if2;	/* default: 361667 (36.1667 MHz) */
 
 	/* set if no pll is connected to the secondary i2c bus */
 	int no_tuner;
@@ -49,6 +50,6 @@ static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *c
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
 	return NULL;
 }
-#endif // CONFIG_DVB_ZL10353
+#endif /* CONFIG_DVB_ZL10353 */
 
 #endif /* ZL10353_H */
diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h
index 4962434b35e7..055ff1f7e349 100644
--- a/drivers/media/dvb/frontends/zl10353_priv.h
+++ b/drivers/media/dvb/frontends/zl10353_priv.h
@@ -1,7 +1,7 @@
 /*
  *  Driver for Zarlink DVB-T ZL10353 demodulator
  *
- *  Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au>
+ *  Copyright (C) 2006, 2007 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
@@ -16,7 +16,7 @@
  *
  *  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.=
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef _ZL10353_PRIV_
@@ -46,9 +46,28 @@ enum zl10353_reg_addr {
 	RS_ERR_CNT_0       = 0x13,
 	RS_UBC_1           = 0x14,
 	RS_UBC_0           = 0x15,
+	TPS_RECEIVED_1     = 0x1D,
+	TPS_RECEIVED_0     = 0x1E,
+	TPS_CURRENT_1      = 0x1F,
+	TPS_CURRENT_0      = 0x20,
+	RESET              = 0x55,
+	AGC_TARGET         = 0x56,
+	MCLK_RATIO         = 0x5C,
+	ACQ_CTL            = 0x5E,
 	TRL_NOMINAL_RATE_1 = 0x65,
 	TRL_NOMINAL_RATE_0 = 0x66,
+	INPUT_FREQ_1       = 0x6C,
+	INPUT_FREQ_0       = 0x6D,
+	TPS_GIVEN_1        = 0x6E,
+	TPS_GIVEN_0        = 0x6F,
+	TUNER_GO           = 0x70,
+	FSM_GO             = 0x71,
 	CHIP_ID            = 0x7F,
+	CHAN_STEP_1        = 0xE4,
+	CHAN_STEP_0        = 0xE5,
+	OFDM_LOCK_TIME     = 0xE7,
+	FEC_LOCK_TIME      = 0xE8,
+	ACQ_DELAY          = 0xE9,
 };
 
 #endif                          /* _ZL10353_PRIV_ */
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 54b91f26ca63..ae882432dd3d 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -1,8 +1,14 @@
+config TTPCI_EEPROM
+	tristate
+	default n
+
 config DVB_AV7110
 	tristate "AV7110 cards"
-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+	depends on DVB_CORE && PCI && I2C
 	select FW_LOADER if !DVB_AV7110_FIRMWARE
+	select TTPCI_EEPROM
 	select VIDEO_SAA7146_VV
+	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
@@ -57,10 +63,19 @@ config DVB_AV7110_OSD
 
 	  All other people say N.
 
+config DVB_BUDGET_CORE
+	tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)"
+	depends on DVB_CORE && PCI && I2C
+	select VIDEO_SAA7146
+	select TTPCI_EEPROM
+	help
+	  Support for simple SAA7146 based DVB cards
+	  (so called Budget- or Nova-PCI cards) without onboard
+	  MPEG2 decoder.
+
 config DVB_BUDGET
 	tristate "Budget cards"
-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
-	select VIDEO_SAA7146
+	depends on DVB_BUDGET_CORE && I2C
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
 	select DVB_VES1820 if !DVB_FE_CUSTOMISE
@@ -73,9 +88,9 @@ config DVB_BUDGET
 	select DVB_TDA826X if !DVB_FE_CUSTOMISE
 	select DVB_LNBP21 if !DVB_FE_CUSTOMISE
 	help
-	  Support for simple SAA7146 based DVB cards
-	  (so called Budget- or Nova-PCI cards) without onboard
-	  MPEG2 decoder.
+	  Support for simple SAA7146 based DVB cards (so called Budget-
+	  or Nova-PCI cards) without onboard MPEG2 decoder, and without
+	  analog inputs or an onboard Common Interface connector.
 
 	  Say Y if you own such a card and want to use it.
 
@@ -84,8 +99,7 @@ config DVB_BUDGET
 
 config DVB_BUDGET_CI
 	tristate "Budget cards with onboard CI connector"
-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 && INPUT
-	select VIDEO_SAA7146
+	depends on DVB_BUDGET_CORE && I2C
 	select DVB_STV0297 if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
@@ -106,8 +120,9 @@ config DVB_BUDGET_CI
 
 config DVB_BUDGET_AV
 	tristate "Budget cards with analog video inputs"
-	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+	depends on DVB_BUDGET_CORE && I2C
 	select VIDEO_SAA7146_VV
+	depends on VIDEO_DEV	# dependencies of VIDEO_SAA7146_VV
 	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
@@ -127,8 +142,8 @@ config DVB_BUDGET_AV
 
 config DVB_BUDGET_PATCH
 	tristate "AV7110 cards with Budget Patch"
-	depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
-	select DVB_AV7110
+	depends on DVB_BUDGET_CORE && I2C
+	depends on DVB_AV7110
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_VES1X93 if !DVB_FE_CUSTOMISE
 	select DVB_TDA8083 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index 2c1145236ee6..d7483f1a9b3f 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -5,11 +5,13 @@
 
 dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o
 
-obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
-obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
+obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
+obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
+obj-$(CONFIG_DVB_BUDGET) += budget.o
+obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o
+obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
+obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
+obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 0d36c155695b..0e5701bdff19 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -2595,7 +2595,8 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
 	mutex_init(&av7110->osd_mutex);
 
 	/* TV standard */
-	av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL;
+	av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC
+					   : AV7110_VIDEO_MODE_PAL;
 
 	/* ARM "watchdog" */
 	init_waitqueue_head(&av7110->arm_wait);
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 0cb439527498..39fbf7d5cffb 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -46,6 +46,11 @@ extern int av7110_debug;
 
 enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM};
 
+enum av7110_video_mode {
+	AV7110_VIDEO_MODE_PAL 	= 0,
+	AV7110_VIDEO_MODE_NTSC	= 1
+};
+
 struct av7110_p2t {
 	u8		  pes[TS_SIZE];
 	u8		  counter;
@@ -170,7 +175,7 @@ struct av7110 {
 
 	ca_slot_info_t		ci_slot[2];
 
-	int			vidmode;
+	enum av7110_video_mode	vidmode;
 	struct dmxdev		dmxdev;
 	struct dvb_demux	demux;
 
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index d75e7e48addc..aef6e36d7c5c 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -329,7 +329,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
 	return 0;
 }
 
-int av7110_set_vidmode(struct av7110 *av7110, int mode)
+int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)
 {
 	int ret;
 	dprintk(2, "av7110:%p, \n", av7110);
@@ -348,11 +348,15 @@ int av7110_set_vidmode(struct av7110 *av7110, int mode)
 }
 
 
-static int sw2mode[16] = {
-	VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL,
-	VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC,
-	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
-	VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
+static enum av7110_video_mode sw2mode[16] = {
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
+	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
+	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
 };
 
 static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h
index 45dc144b8b43..5f02ef85e47d 100644
--- a/drivers/media/dvb/ttpci/av7110_av.h
+++ b/drivers/media/dvb/ttpci/av7110_av.h
@@ -3,7 +3,8 @@
 
 struct av7110;
 
-extern int av7110_set_vidmode(struct av7110 *av7110, int mode);
+extern int av7110_set_vidmode(struct av7110 *av7110,
+			      enum av7110_video_mode mode);
 
 extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
 extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 76cca003252f..e2f066fb7967 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -876,11 +876,11 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
 	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
 
 	if (std->id & V4L2_STD_PAL) {
-		av7110->vidmode = VIDEO_MODE_PAL;
+		av7110->vidmode = AV7110_VIDEO_MODE_PAL;
 		av7110_set_vidmode(av7110, av7110->vidmode);
 	}
 	else if (std->id & V4L2_STD_NTSC) {
-		av7110->vidmode = VIDEO_MODE_NTSC;
+		av7110->vidmode = AV7110_VIDEO_MODE_NTSC;
 		av7110_set_vidmode(av7110, av7110->vidmode);
 	}
 	else
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 11e962f1a97f..8d5214f18cf0 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -351,4 +351,14 @@ config USB_DSBR
 	  To compile this driver as a module, choose M here: the
 	  module will be called dsbr100.
 
+config USB_SI470X
+	tristate "Silicon Labs Si470x FM Radio Receiver support"
+	depends on USB && VIDEO_V4L2
+	---help---
+	  Say Y here if you want to connect this type of radio to your
+	  computer's USB port.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called radio-silabs.
+
 endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index cf55a18e3ddf..a30159f6fa42 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -21,5 +21,6 @@ obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
+obj-$(CONFIG_USB_SI470X) += radio-si470x.o
 
 EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 3bd07f7e3774..36c0e3651502 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -33,6 +33,9 @@
 
  History:
 
+ Version 0.43:
+	Oliver Neukum: avoided DMA coherency issue
+
  Version 0.42:
 	Converted dsbr100 to use video_ioctl2
 	by Douglas Landgraf <dougsland@gmail.com>
@@ -135,7 +138,7 @@ module_param(radio_nr, int, 0);
 struct dsbr100_device {
 	struct usb_device *usbdev;
 	struct video_device *videodev;
-	unsigned char transfer_buffer[TB_LEN];
+	u8 *transfer_buffer;
 	int curfreq;
 	int stereo;
 	int users;
@@ -237,10 +240,7 @@ static void dsbr100_getstat(struct dsbr100_device *radio)
 /* handle unplugging of the device, release data structures
 if nothing keeps us from doing it.  If something is still
 keeping us busy, the release callback of v4l will take care
-of releasing it.  stv680.c does not relase its private
-data, so I don't do this here either.  Checking out the
-code I'd expect I better did that, but if there's a memory
-leak here it's tiny (~50 bytes per disconnect) */
+of releasing it. */
 static void usb_dsbr100_disconnect(struct usb_interface *intf)
 {
 	struct dsbr100_device *radio = usb_get_intfdata(intf);
@@ -250,6 +250,7 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
 		video_unregister_device(radio->videodev);
 		radio->videodev = NULL;
 		if (radio->users) {
+			kfree(radio->transfer_buffer);
 			kfree(radio);
 		} else {
 			radio->removed = 1;
@@ -425,6 +426,7 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file)
 		return -ENODEV;
 	radio->users = 0;
 	if (radio->removed) {
+		kfree(radio->transfer_buffer);
 		kfree(radio);
 	}
 	return 0;
@@ -471,7 +473,12 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
 
 	if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
 		return -ENOMEM;
+	if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) {
+		kfree(radio);
+		return -ENOMEM;
+	}
 	if (!(radio->videodev = video_device_alloc())) {
+		kfree(radio->transfer_buffer);
 		kfree(radio);
 		return -ENOMEM;
 	}
@@ -485,6 +492,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
 	if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
 		warn("Could not register video device");
 		video_device_release(radio->videodev);
+		kfree(radio->transfer_buffer);
 		kfree(radio);
 		return -EIO;
 	}
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 5e4b9ddb23c0..246422b49267 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -58,10 +58,10 @@ static int initmute	= 1;
 static int radio_nr	= -1;
 
 module_param(io, int, 0444);
-MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic"
+MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic "
 	 "probing is disabled or fails. The most common I/O ports are: 0x20c "
 	 "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
-	 " work for the combined sound/radiocard).");
+	 "work for the combined sound/radiocard).");
 
 module_param(probe, bool, 0444);
 MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
@@ -392,7 +392,7 @@ static struct v4l2_queryctrl radio_qctrl[] = {
 	}
 };
 
-static struct file_operations gemtek_fops = {
+static const struct file_operations gemtek_fops = {
 	.owner		= THIS_MODULE,
 	.open		= video_exclusive_open,
 	.release	= video_exclusive_release,
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 8e33a19a22a3..bc51f4d23a5a 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -423,7 +423,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
 errunr:
 	video_unregister_device(maestro_radio_inst);
 errfr1:
-	kfree(maestro_radio_inst);
+	video_device_release(maestro_radio_inst);
 errfr:
 	kfree(radio_unit);
 err:
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 395165367f37..3118bdab3183 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -321,7 +321,7 @@ static struct isapnp_device_id id_table[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(isapnp, id_table);
 
-static int isapnp_fmi_probe(void)
+static int __init isapnp_fmi_probe(void)
 {
 	int i = 0;
 
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index c432c44bd634..f7c8b000404f 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -476,8 +476,7 @@ static int __init fmr2_init(void)
 		return -EBUSY;
 	}
 
-	if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-	{
+	if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
 		release_region(io, 2);
 		return -EINVAL;
 	}
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
new file mode 100644
index 000000000000..8e4bd4769048
--- /dev/null
+++ b/drivers/media/radio/radio-si470x.c
@@ -0,0 +1,1432 @@
+/*
+ *  drivers/media/radio/radio-si470x.c
+ *
+ *  Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers:
+ *   - Silicon Labs USB FM Radio Reference Design
+ *   - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF)
+ *
+ *  Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net>
+ *
+ * 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
+ */
+
+
+/*
+ * History:
+ * 2008-01-12	Tobias Lorenz <tobias.lorenz@gmx.net>
+ *		Version 1.0.0
+ *		- First working version
+ * 2008-01-13   Tobias Lorenz <tobias.lorenz@gmx.net>
+ *		Version 1.0.1
+ *		- Improved error handling, every function now returns errno
+ *		- Improved multi user access (start/mute/stop)
+ *		- Channel doesn't get lost anymore after start/mute/stop
+ *		- RDS support added (polling mode via interrupt EP 1)
+ *		- marked default module parameters with *value*
+ *		- switched from bit structs to bit masks
+ *		- header file cleaned and integrated
+ * 2008-01-14	Tobias Lorenz <tobias.lorenz@gmx.net>
+ * 		Version 1.0.2
+ * 		- hex values are now lower case
+ * 		- commented USB ID for ADS/Tech moved on todo list
+ * 		- blacklisted si470x in hid-quirks.c
+ * 		- rds buffer handling functions integrated into *_work, *_read
+ * 		- rds_command in si470x_poll exchanged against simple retval
+ * 		- check for firmware version 15
+ * 		- code order and prototypes still remain the same
+ * 		- spacing and bottom of band codes remain the same
+ * 2008-01-16	Tobias Lorenz <tobias.lorenz@gmx.net>
+ *		Version 1.0.3
+ * 		- code reordered to avoid function prototypes
+ *		- switch/case defaults are now more user-friendly
+ *		- unified comment style
+ *		- applied all checkpatch.pl v1.12 suggestions
+ *		  except the warning about the too long lines with bit comments
+ *		- renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
+ * 2008-01-22	Tobias Lorenz <tobias.lorenz@gmx.net>
+ *		Version 1.0.4
+ *		- avoid poss. locking when doing copy_to_user which may sleep
+ *		- RDS is automatically activated on read now
+ *		- code cleaned of unnecessary rds_commands
+ *		- USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
+ *		  (thanks to Guillaume RAMOUSSE)
+ *
+ * ToDo:
+ * - add seeking support
+ * - add firmware download/update support
+ * - RDS support: interrupt mode, instead of polling
+ * - add LED status output (check if that's not already done in firmware)
+ */
+
+
+/* driver definitions */
+#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
+#define DRIVER_NAME "radio-si470x"
+#define DRIVER_VERSION KERNEL_VERSION(1, 0, 4)
+#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
+#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
+
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/rds.h>
+
+
+/* USB Device ID List */
+static struct usb_device_id si470x_usb_driver_id_table[] = {
+	/* Silicon Labs USB FM Radio Reference Design */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a,	USB_CLASS_HID, 0, 0) },
+	/* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155,	USB_CLASS_HID, 0, 0) },
+	/* Terminating entry */
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table);
+
+
+
+/**************************************************************************
+ * Module Parameters
+ **************************************************************************/
+
+/* Radio Nr */
+static int radio_nr = -1;
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "Radio Nr");
+
+/* Spacing (kHz) */
+/* 0: 200 kHz (USA, Australia) */
+/* 1: 100 kHz (Europe, Japan) */
+/* 2:  50 kHz */
+static int space = 2;
+module_param(space, int, 0);
+MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
+
+/* Bottom of Band (MHz) */
+/* 0: 87.5 - 108 MHz (USA, Europe)*/
+/* 1: 76   - 108 MHz (Japan wide band) */
+/* 2: 76   -  90 MHz (Japan) */
+static int band = 1;
+module_param(band, int, 0);
+MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
+
+/* De-emphasis */
+/* 0: 75 us (USA) */
+/* 1: 50 us (Europe, Australia, Japan) */
+static int de = 1;
+module_param(de, int, 0);
+MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*");
+
+/* USB timeout */
+static int usb_timeout = 500;
+module_param(usb_timeout, int, 0);
+MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*");
+
+/* Seek retries */
+static int seek_retries = 100;
+module_param(seek_retries, int, 0);
+MODULE_PARM_DESC(seek_retries, "Seek retries: *100*");
+
+/* RDS buffer blocks */
+static int rds_buf = 100;
+module_param(rds_buf, int, 0);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
+
+/* RDS maximum block errors */
+static int max_rds_errors = 1;
+/* 0 means   0  errors requiring correction */
+/* 1 means 1-2  errors requiring correction (used by original USBRadio.exe) */
+/* 2 means 3-5  errors requiring correction */
+/* 3 means   6+ errors or errors in checkword, correction not possible */
+module_param(max_rds_errors, int, 0);
+MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
+
+/* RDS poll frequency */
+static int rds_poll_time = 40;
+/* 40 is used by the original USBRadio.exe */
+/* 50 is used by radio-cadet */
+/* 75 should be okay */
+/* 80 is the usual RDS receive interval */
+module_param(rds_poll_time, int, 0);
+MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*");
+
+
+
+/**************************************************************************
+ * Register Definitions
+ **************************************************************************/
+#define RADIO_REGISTER_SIZE	2	/* 16 register bit width */
+#define RADIO_REGISTER_NUM	16	/* DEVICEID   ... RDSD */
+#define RDS_REGISTER_NUM	6	/* STATUSRSSI ... RDSD */
+
+#define DEVICEID		0	/* Device ID */
+#define DEVICEID_PN		0xf000	/* bits 15..12: Part Number */
+#define DEVICEID_MFGID		0x0fff	/* bits 11..00: Manufacturer ID */
+
+#define CHIPID			1	/* Chip ID */
+#define CHIPID_REV		0xfc00	/* bits 15..10: Chip Version */
+#define CHIPID_DEV		0x0200	/* bits 09..09: Device */
+#define CHIPID_FIRMWARE		0x01ff	/* bits 08..00: Firmware Version */
+
+#define POWERCFG		2	/* Power Configuration */
+#define POWERCFG_DSMUTE		0x8000	/* bits 15..15: Softmute Disable */
+#define POWERCFG_DMUTE		0x4000	/* bits 14..14: Mute Disable */
+#define POWERCFG_MONO		0x2000	/* bits 13..13: Mono Select */
+#define POWERCFG_RDSM		0x0800	/* bits 11..11: RDS Mode (Si4701 only) */
+#define POWERCFG_SKMODE		0x0400	/* bits 10..10: Seek Mode */
+#define POWERCFG_SEEKUP		0x0200	/* bits 09..09: Seek Direction */
+#define POWERCFG_SEEK		0x0100	/* bits 08..08: Seek */
+#define POWERCFG_DISABLE	0x0040	/* bits 06..06: Powerup Disable */
+#define POWERCFG_ENABLE		0x0001	/* bits 00..00: Powerup Enable */
+
+#define CHANNEL			3	/* Channel */
+#define CHANNEL_TUNE		0x8000	/* bits 15..15: Tune */
+#define CHANNEL_CHAN		0x03ff	/* bits 09..00: Channel Select */
+
+#define SYSCONFIG1		4	/* System Configuration 1 */
+#define SYSCONFIG1_RDSIEN	0x8000	/* bits 15..15: RDS Interrupt Enable (Si4701 only) */
+#define SYSCONFIG1_STCIEN	0x4000	/* bits 14..14: Seek/Tune Complete Interrupt Enable */
+#define SYSCONFIG1_RDS		0x1000	/* bits 12..12: RDS Enable (Si4701 only) */
+#define SYSCONFIG1_DE		0x0800	/* bits 11..11: De-emphasis (0=75us 1=50us) */
+#define SYSCONFIG1_AGCD		0x0400	/* bits 10..10: AGC Disable */
+#define SYSCONFIG1_BLNDADJ	0x00c0	/* bits 07..06: Stereo/Mono Blend Level Adjustment */
+#define SYSCONFIG1_GPIO3	0x0030	/* bits 05..04: General Purpose I/O 3 */
+#define SYSCONFIG1_GPIO2	0x000c	/* bits 03..02: General Purpose I/O 2 */
+#define SYSCONFIG1_GPIO1	0x0003	/* bits 01..00: General Purpose I/O 1 */
+
+#define SYSCONFIG2		5	/* System Configuration 2 */
+#define SYSCONFIG2_SEEKTH	0xff00	/* bits 15..08: RSSI Seek Threshold */
+#define SYSCONFIG2_BAND		0x0080	/* bits 07..06: Band Select */
+#define SYSCONFIG2_SPACE	0x0030	/* bits 05..04: Channel Spacing */
+#define SYSCONFIG2_VOLUME	0x000f	/* bits 03..00: Volume */
+
+#define SYSCONFIG3		6	/* System Configuration 3 */
+#define SYSCONFIG3_SMUTER	0xc000	/* bits 15..14: Softmute Attack/Recover Rate */
+#define SYSCONFIG3_SMUTEA	0x3000	/* bits 13..12: Softmute Attenuation */
+#define SYSCONFIG3_SKSNR	0x00f0	/* bits 07..04: Seek SNR Threshold */
+#define SYSCONFIG3_SKCNT	0x000f	/* bits 03..00: Seek FM Impulse Detection Threshold */
+
+#define TEST1			7	/* Test 1 */
+#define TEST1_AHIZEN		0x4000	/* bits 14..14: Audio High-Z Enable */
+
+#define TEST2			8	/* Test 2 */
+/* TEST2 only contains reserved bits */
+
+#define BOOTCONFIG		9	/* Boot Configuration */
+/* BOOTCONFIG only contains reserved bits */
+
+#define STATUSRSSI		10	/* Status RSSI */
+#define STATUSRSSI_RDSR		0x8000	/* bits 15..15: RDS Ready (Si4701 only) */
+#define STATUSRSSI_STC		0x4000	/* bits 14..14: Seek/Tune Complete */
+#define STATUSRSSI_SF		0x2000	/* bits 13..13: Seek Fail/Band Limit */
+#define STATUSRSSI_AFCRL	0x1000	/* bits 12..12: AFC Rail */
+#define STATUSRSSI_RDSS		0x0800	/* bits 11..11: RDS Synchronized (Si4701 only) */
+#define STATUSRSSI_BLERA	0x0600	/* bits 10..09: RDS Block A Errors (Si4701 only) */
+#define STATUSRSSI_ST		0x0100	/* bits 08..08: Stereo Indicator */
+#define STATUSRSSI_RSSI		0x00ff	/* bits 07..00: RSSI (Received Signal Strength Indicator) */
+
+#define READCHAN		11	/* Read Channel */
+#define READCHAN_BLERB		0xc000	/* bits 15..14: RDS Block D Errors (Si4701 only) */
+#define READCHAN_BLERC		0x3000	/* bits 13..12: RDS Block C Errors (Si4701 only) */
+#define READCHAN_BLERD		0x0c00	/* bits 11..10: RDS Block B Errors (Si4701 only) */
+#define READCHAN_READCHAN	0x03ff	/* bits 09..00: Read Channel */
+
+#define RDSA			12	/* RDSA */
+#define RDSA_RDSA		0xffff	/* bits 15..00: RDS Block A Data (Si4701 only) */
+
+#define RDSB			13	/* RDSB */
+#define RDSB_RDSB		0xffff	/* bits 15..00: RDS Block B Data (Si4701 only) */
+
+#define RDSC			14	/* RDSC */
+#define RDSC_RDSC		0xffff	/* bits 15..00: RDS Block C Data (Si4701 only) */
+
+#define RDSD			15	/* RDSD */
+#define RDSD_RDSD		0xffff	/* bits 15..00: RDS Block D Data (Si4701 only) */
+
+
+
+/**************************************************************************
+ * USB HID Reports
+ **************************************************************************/
+
+/* Reports 1-16 give direct read/write access to the 16 Si470x registers */
+/* with the (REPORT_ID - 1) corresponding to the register address across USB */
+/* endpoint 0 using GET_REPORT and SET_REPORT */
+#define REGISTER_REPORT_SIZE	(RADIO_REGISTER_SIZE + 1)
+#define REGISTER_REPORT(reg)	((reg) + 1)
+
+/* Report 17 gives direct read/write access to the entire Si470x register */
+/* map across endpoint 0 using GET_REPORT and SET_REPORT */
+#define ENTIRE_REPORT_SIZE	(RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
+#define ENTIRE_REPORT		17
+
+/* Report 18 is used to send the lowest 6 Si470x registers up the HID */
+/* interrupt endpoint 1 to Windows every 20 milliseconds for status */
+#define RDS_REPORT_SIZE		(RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1)
+#define RDS_REPORT		18
+
+/* Report 19: LED state */
+#define LED_REPORT_SIZE		3
+#define LED_REPORT		19
+
+/* Report 19: stream */
+#define STREAM_REPORT_SIZE	3
+#define	STREAM_REPORT		19
+
+/* Report 20: scratch */
+#define SCRATCH_PAGE_SIZE	63
+#define SCRATCH_REPORT_SIZE	(SCRATCH_PAGE_SIZE + 1)
+#define SCRATCH_REPORT		20
+
+/* Reports 19-22: flash upgrade of the C8051F321 */
+#define WRITE_REPORT		19
+#define FLASH_REPORT		20
+#define CRC_REPORT		21
+#define RESPONSE_REPORT		22
+
+/* Report 23: currently unused, but can accept 60 byte reports on the HID */
+/* interrupt out endpoint 2 every 1 millisecond */
+#define UNUSED_REPORT		23
+
+
+
+/**************************************************************************
+ * Software/Hardware Versions
+ **************************************************************************/
+#define RADIO_SW_VERSION_NOT_BOOTLOADABLE	6
+#define RADIO_SW_VERSION			7
+#define RADIO_SW_VERSION_CURRENT		15
+#define RADIO_HW_VERSION			1
+
+#define SCRATCH_PAGE_SW_VERSION	1
+#define SCRATCH_PAGE_HW_VERSION	2
+
+
+
+/**************************************************************************
+ * LED State Definitions
+ **************************************************************************/
+#define LED_COMMAND		0x35
+
+#define NO_CHANGE_LED		0x00
+#define ALL_COLOR_LED		0x01	/* streaming state */
+#define BLINK_GREEN_LED		0x02	/* connect state */
+#define BLINK_RED_LED		0x04
+#define BLINK_ORANGE_LED	0x10	/* disconnect state */
+#define SOLID_GREEN_LED		0x20	/* tuning/seeking state */
+#define SOLID_RED_LED		0x40	/* bootload state */
+#define SOLID_ORANGE_LED	0x80
+
+
+
+/**************************************************************************
+ * Stream State Definitions
+ **************************************************************************/
+#define STREAM_COMMAND	0x36
+#define STREAM_VIDPID	0x00
+#define STREAM_AUDIO	0xff
+
+
+
+/**************************************************************************
+ * Bootloader / Flash Commands
+ **************************************************************************/
+
+/* unique id sent to bootloader and required to put into a bootload state */
+#define UNIQUE_BL_ID		0x34
+
+/* mask for the flash data */
+#define FLASH_DATA_MASK		0x55
+
+/* bootloader commands */
+#define GET_SW_VERSION_COMMAND	0x00
+#define	SET_PAGE_COMMAND	0x01
+#define ERASE_PAGE_COMMAND	0x02
+#define WRITE_PAGE_COMMAND	0x03
+#define CRC_ON_PAGE_COMMAND	0x04
+#define READ_FLASH_BYTE_COMMAND	0x05
+#define RESET_DEVICE_COMMAND	0x06
+#define GET_HW_VERSION_COMMAND	0x07
+#define BLANK			0xff
+
+/* bootloader command responses */
+#define COMMAND_OK		0x01
+#define COMMAND_FAILED		0x02
+#define COMMAND_PENDING		0x03
+
+/* buffer sizes */
+#define COMMAND_BUFFER_SIZE	4
+#define RESPONSE_BUFFER_SIZE	2
+#define FLASH_BUFFER_SIZE	64
+#define CRC_BUFFER_SIZE		3
+
+
+
+/**************************************************************************
+ * General Driver Definitions
+ **************************************************************************/
+
+/*
+ * si470x_device - private data
+ */
+struct si470x_device {
+	/* reference to USB and video device */
+	struct usb_device *usbdev;
+	struct video_device *videodev;
+
+	/* are these really necessary ? */
+	int users;
+
+	/* report buffer (maximum 64 bytes) */
+	unsigned char buf[64];
+
+	/* Silabs internal registers (0..15) */
+	unsigned short registers[RADIO_REGISTER_NUM];
+
+	/* RDS receive buffer */
+	struct work_struct work;
+	wait_queue_head_t read_queue;
+	struct timer_list timer;
+	spinlock_t lock;		/* buffer locking */
+	unsigned char *buffer;		/* size is always multiple of three */
+	unsigned int buf_size;
+	unsigned int rd_index;
+	unsigned int wr_index;
+};
+
+
+/*
+ * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
+ * 62.5 kHz otherwise.
+ * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
+ * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW
+ * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000
+ */
+#define FREQ_MUL (1000000 / 62.5)
+
+
+
+/**************************************************************************
+ * General Driver Functions
+ **************************************************************************/
+
+/*
+ * si470x_get_report - receive a HID report
+ */
+static int si470x_get_report(struct si470x_device *radio, int size)
+{
+	return usb_control_msg(radio->usbdev,
+		usb_rcvctrlpipe(radio->usbdev, 0),
+		HID_REQ_GET_REPORT,
+		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+		radio->buf[0], 2,
+		radio->buf, size, usb_timeout);
+}
+
+
+/*
+ * si470x_set_report - send a HID report
+ */
+static int si470x_set_report(struct si470x_device *radio, int size)
+{
+	return usb_control_msg(radio->usbdev,
+		usb_sndctrlpipe(radio->usbdev, 0),
+		HID_REQ_SET_REPORT,
+		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+		radio->buf[0], 2,
+		radio->buf, size, usb_timeout);
+}
+
+
+/*
+ * si470x_get_register - read register
+ */
+static int si470x_get_register(struct si470x_device *radio, int regnr)
+{
+	int retval;
+
+	radio->buf[0] = REGISTER_REPORT(regnr);
+
+	retval = si470x_get_report(radio, REGISTER_REPORT_SIZE);
+	if (retval >= 0)
+		radio->registers[regnr] = (radio->buf[1] << 8) | radio->buf[2];
+
+	return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_set_register - write register
+ */
+static int si470x_set_register(struct si470x_device *radio, int regnr)
+{
+	int retval;
+
+	radio->buf[0] = REGISTER_REPORT(regnr);
+	radio->buf[1] = (radio->registers[regnr] & 0xff00) >> 8;
+	radio->buf[2] = (radio->registers[regnr] & 0x00ff);
+
+	retval = si470x_set_report(radio, REGISTER_REPORT_SIZE);
+
+	return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_get_all_registers - read entire registers
+ */
+static int si470x_get_all_registers(struct si470x_device *radio)
+{
+	int retval;
+	int regnr;
+
+	radio->buf[0] = ENTIRE_REPORT;
+
+	retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE);
+
+	if (retval >= 0)
+		for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
+			radio->registers[regnr] =
+			(radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
+			 radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
+
+	return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_get_rds_registers - read rds registers
+ */
+static int si470x_get_rds_registers(struct si470x_device *radio)
+{
+	int retval;
+	int regnr;
+	int size;
+
+	radio->buf[0] = RDS_REPORT;
+
+	retval = usb_interrupt_msg(radio->usbdev,
+		usb_rcvctrlpipe(radio->usbdev, 1),
+		radio->buf, RDS_REPORT_SIZE, &size, usb_timeout);
+
+	if (retval >= 0)
+		for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
+			radio->registers[STATUSRSSI + regnr] =
+			(radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) |
+			 radio->buf[regnr * RADIO_REGISTER_SIZE + 2];
+
+	return (retval < 0) ? -EINVAL : 0;
+}
+
+
+/*
+ * si470x_set_chan - set the channel
+ */
+static int si470x_set_chan(struct si470x_device *radio, int chan)
+{
+	int retval, i;
+
+	/* start tuning */
+	radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
+	radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
+	retval = si470x_set_register(radio, CHANNEL);
+	if (retval < 0)
+		return retval;
+
+	/* wait till seek operation has completed */
+	i = 0;
+	do {
+		retval = si470x_get_register(radio, STATUSRSSI);
+		if (retval < 0)
+			return retval;
+	} while ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) &&
+		(++i < seek_retries));
+	if (i >= seek_retries)
+		printk(KERN_WARNING DRIVER_NAME
+			": seek does not finish after %d tries\n", i);
+
+	/* stop tuning */
+	radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
+	return si470x_set_register(radio, CHANNEL);
+}
+
+
+/*
+ * si470x_get_freq - get the frequency
+ */
+static int si470x_get_freq(struct si470x_device *radio)
+{
+	int spacing, band_bottom, chan, freq;
+	int retval;
+
+	/* Spacing (kHz) */
+	switch (space) {
+	/* 0: 200 kHz (USA, Australia) */
+	case 0 : spacing = 0.200 * FREQ_MUL; break;
+	/* 1: 100 kHz (Europe, Japan) */
+	case 1 : spacing = 0.100 * FREQ_MUL; break;
+	/* 2:  50 kHz */
+	default: spacing = 0.050 * FREQ_MUL; break;
+	};
+
+	/* Bottom of Band (MHz) */
+	switch (band) {
+	/* 0: 87.5 - 108 MHz (USA, Europe) */
+	case 0 : band_bottom = 87.5 * FREQ_MUL; break;
+	/* 1: 76   - 108 MHz (Japan wide band) */
+	default: band_bottom = 76   * FREQ_MUL; break;
+	/* 2: 76   -  90 MHz (Japan) */
+	case 2 : band_bottom = 76   * FREQ_MUL; break;
+	};
+
+	/* read channel */
+	retval = si470x_get_register(radio, READCHAN);
+	if (retval < 0)
+		return retval;
+	chan = radio->registers[READCHAN] & READCHAN_READCHAN;
+
+	/* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
+	freq = chan * spacing + band_bottom;
+
+	return freq;
+}
+
+
+/*
+ * si470x_set_freq - set the frequency
+ */
+static int si470x_set_freq(struct si470x_device *radio, int freq)
+{
+	int spacing, band_bottom, chan;
+
+	/* Spacing (kHz) */
+	switch (space) {
+	/* 0: 200 kHz (USA, Australia) */
+	case 0 : spacing = 0.200 * FREQ_MUL; break;
+	/* 1: 100 kHz (Europe, Japan) */
+	case 1 : spacing = 0.100 * FREQ_MUL; break;
+	/* 2:  50 kHz */
+	default: spacing = 0.050 * FREQ_MUL; break;
+	};
+
+	/* Bottom of Band (MHz) */
+	switch (band) {
+	/* 0: 87.5 - 108 MHz (USA, Europe) */
+	case 0 : band_bottom = 87.5 * FREQ_MUL; break;
+	/* 1: 76   - 108 MHz (Japan wide band) */
+	default: band_bottom = 76   * FREQ_MUL; break;
+	/* 2: 76   -  90 MHz (Japan) */
+	case 2 : band_bottom = 76   * FREQ_MUL; break;
+	};
+
+	/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
+	chan = (freq - band_bottom) / spacing;
+
+	return si470x_set_chan(radio, chan);
+}
+
+
+/*
+ * si470x_start - switch on radio
+ */
+static int si470x_start(struct si470x_device *radio)
+{
+	int retval;
+
+	/* powercfg */
+	radio->registers[POWERCFG] =
+		POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
+	retval = si470x_set_register(radio, POWERCFG);
+	if (retval < 0)
+		return retval;
+
+	/* sysconfig 1 */
+	radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
+	retval = si470x_set_register(radio, SYSCONFIG1);
+	if (retval < 0)
+		return retval;
+
+	/* sysconfig 2 */
+	radio->registers[SYSCONFIG2] =
+		(0x3f  << 8) |	/* SEEKTH */
+		(band  << 6) |	/* BAND */
+		(space << 4) |	/* SPACE */
+		15;		/* VOLUME (max) */
+	retval = si470x_set_register(radio, SYSCONFIG2);
+	if (retval < 0)
+		return retval;
+
+	/* reset last channel */
+	return si470x_set_chan(radio,
+		radio->registers[CHANNEL] & CHANNEL_CHAN);
+}
+
+
+/*
+ * si470x_stop - switch off radio
+ */
+static int si470x_stop(struct si470x_device *radio)
+{
+	int retval;
+
+	/* sysconfig 1 */
+	radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
+	retval = si470x_set_register(radio, SYSCONFIG1);
+	if (retval < 0)
+		return retval;
+
+	/* powercfg */
+	radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
+	/* POWERCFG_ENABLE has to automatically go low */
+	radio->registers[POWERCFG] |= POWERCFG_ENABLE |	POWERCFG_DISABLE;
+	return si470x_set_register(radio, POWERCFG);
+}
+
+
+/*
+ * si470x_rds_on - switch on rds reception
+ */
+static int si470x_rds_on(struct si470x_device *radio)
+{
+	/* sysconfig 1 */
+	radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
+	return si470x_set_register(radio, SYSCONFIG1);
+}
+
+
+
+/**************************************************************************
+ * RDS Driver Functions
+ **************************************************************************/
+
+/*
+ * si470x_rds - rds processing function
+ */
+static void si470x_rds(struct si470x_device *radio)
+{
+	unsigned char tmpbuf[3];
+	unsigned char blocknum;
+	unsigned char bler; /* rds block errors */
+	unsigned short rds;
+	unsigned int i;
+
+	/* get rds blocks */
+	if (si470x_get_rds_registers(radio) < 0)
+		return;
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) {
+		/* No RDS group ready */
+		return;
+	}
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) {
+		/* RDS decoder not synchronized */
+		return;
+	}
+
+	/* copy four RDS blocks to internal buffer */
+	if (spin_trylock(&radio->lock)) {
+		/* process each rds block */
+		for (blocknum = 0; blocknum < 4; blocknum++) {
+			switch (blocknum) {
+			default:
+				bler = (radio->registers[STATUSRSSI] &
+						STATUSRSSI_BLERA) >> 9;
+				rds = radio->registers[RDSA];
+				break;
+			case 1:
+				bler = (radio->registers[READCHAN] &
+						READCHAN_BLERB) >> 14;
+				rds = radio->registers[RDSB];
+				break;
+			case 2:
+				bler = (radio->registers[READCHAN] &
+						READCHAN_BLERC) >> 12;
+				rds = radio->registers[RDSC];
+				break;
+			case 3:
+				bler = (radio->registers[READCHAN] &
+						READCHAN_BLERD) >> 10;
+				rds = radio->registers[RDSD];
+				break;
+			};
+
+			/* Fill the V4L2 RDS buffer */
+			tmpbuf[0] = rds & 0x00ff;	/* LSB */
+			tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */
+			tmpbuf[2] = blocknum;		/* offset name */
+			tmpbuf[2] |= blocknum << 3;	/* received offset */
+			if (bler > max_rds_errors)
+				tmpbuf[2] |= 0x80; /* uncorrectable errors */
+			else if (bler > 0)
+				tmpbuf[2] |= 0x40; /* corrected error(s) */
+
+			/* copy RDS block to internal buffer */
+			for (i = 0; i < 3; i++) {
+				radio->buffer[radio->wr_index] = tmpbuf[i];
+				radio->wr_index++;
+			}
+
+			/* wrap write pointer */
+			if (radio->wr_index >= radio->buf_size)
+				radio->wr_index = 0;
+
+			/* check for overflow */
+			if (radio->wr_index == radio->rd_index) {
+				/* increment and wrap read pointer */
+				radio->rd_index += 3;
+				if (radio->rd_index >= radio->buf_size)
+					radio->rd_index = 0;
+			}
+		}
+		spin_unlock(&radio->lock);
+	}
+
+	/* wake up read queue */
+	if (radio->wr_index != radio->rd_index)
+		wake_up_interruptible(&radio->read_queue);
+}
+
+
+/*
+ * si470x_timer - rds timer function
+ */
+static void si470x_timer(unsigned long data)
+{
+	struct si470x_device *radio = (struct si470x_device *) data;
+
+	schedule_work(&radio->work);
+}
+
+
+/*
+ * si470x_work - rds work function
+ */
+static void si470x_work(struct work_struct *work)
+{
+	struct si470x_device *radio = container_of(work, struct si470x_device,
+		work);
+
+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+		return;
+
+	si470x_rds(radio);
+	mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time));
+}
+
+
+
+/**************************************************************************
+ * File Operations Interface
+ **************************************************************************/
+
+/*
+ * si470x_fops_read - read RDS data
+ */
+static ssize_t si470x_fops_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+	int retval = 0;
+	unsigned int block_count = 0;
+
+	/* switch on rds reception */
+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
+		si470x_rds_on(radio);
+		schedule_work(&radio->work);
+	}
+
+	/* block if no new data available */
+	while (radio->wr_index == radio->rd_index) {
+		if (file->f_flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		interruptible_sleep_on(&radio->read_queue);
+	}
+
+	/* calculate block count from byte count */
+	count /= 3;
+
+	/* copy RDS block out of internal buffer and to user buffer */
+	if (spin_trylock(&radio->lock)) {
+		while (block_count < count) {
+			if (radio->rd_index == radio->wr_index)
+				break;
+
+			/* always transfer rds complete blocks */
+			if (copy_to_user(buf,
+					&radio->buffer[radio->rd_index], 3))
+				/* retval = -EFAULT; */
+				break;
+
+			/* increment and wrap read pointer */
+			radio->rd_index += 3;
+			if (radio->rd_index >= radio->buf_size)
+				radio->rd_index = 0;
+
+			/* increment counters */
+			block_count++;
+			buf += 3;
+			retval += 3;
+		}
+
+		spin_unlock(&radio->lock);
+	}
+
+	return retval;
+}
+
+
+/*
+ * si470x_fops_poll - poll RDS data
+ */
+static unsigned int si470x_fops_poll(struct file *file,
+		struct poll_table_struct *pts)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	/* switch on rds reception */
+	if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) {
+		si470x_rds_on(radio);
+		schedule_work(&radio->work);
+	}
+
+	poll_wait(file, &radio->read_queue, pts);
+
+	if (radio->rd_index != radio->wr_index)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+
+/*
+ * si470x_fops_open - file open
+ */
+static int si470x_fops_open(struct inode *inode, struct file *file)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	radio->users++;
+	if (radio->users == 1)
+		return si470x_start(radio);
+
+	return 0;
+}
+
+
+/*
+ * si470x_fops_release - file release
+ */
+static int si470x_fops_release(struct inode *inode, struct file *file)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (!radio)
+		return -ENODEV;
+
+	radio->users--;
+	if (radio->users == 0) {
+		/* stop rds reception */
+		del_timer_sync(&radio->timer);
+		flush_scheduled_work();
+
+		/* cancel read processes */
+		wake_up_interruptible(&radio->read_queue);
+
+		return si470x_stop(radio);
+	}
+
+	return 0;
+}
+
+
+/*
+ * si470x_fops - file operations interface
+ */
+static const struct file_operations si470x_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= si470x_fops_read,
+	.poll		= si470x_fops_poll,
+	.ioctl		= video_ioctl2,
+	.compat_ioctl	= v4l_compat_ioctl32,
+	.open		= si470x_fops_open,
+	.release	= si470x_fops_release,
+};
+
+
+
+/**************************************************************************
+ * Video4Linux Interface
+ **************************************************************************/
+
+/*
+ * si470x_v4l2_queryctrl - query control
+ */
+static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = {
+/* HINT: the disabled controls are only here to satify kradio and such apps */
+	{
+		.id		= V4L2_CID_AUDIO_VOLUME,
+		.type		= V4L2_CTRL_TYPE_INTEGER,
+		.name		= "Volume",
+		.minimum	= 0,
+		.maximum	= 15,
+		.step		= 1,
+		.default_value	= 15,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_BALANCE,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_BASS,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_TREBLE,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_MUTE,
+		.type		= V4L2_CTRL_TYPE_BOOLEAN,
+		.name		= "Mute",
+		.minimum	= 0,
+		.maximum	= 1,
+		.step		= 1,
+		.default_value	= 1,
+	},
+	{
+		.id		= V4L2_CID_AUDIO_LOUDNESS,
+		.flags		= V4L2_CTRL_FLAG_DISABLED,
+	},
+};
+
+
+/*
+ * si470x_vidioc_querycap - query device capabilities
+ */
+static int si470x_vidioc_querycap(struct file *file, void *priv,
+		struct v4l2_capability *capability)
+{
+	strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
+	strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+	sprintf(capability->bus_info, "USB");
+	capability->version = DRIVER_VERSION;
+	capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_g_input - get input
+ */
+static int si470x_vidioc_g_input(struct file *filp, void *priv,
+		unsigned int *i)
+{
+	*i = 0;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_input - set input
+ */
+static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_queryctrl - enumerate control items
+ */
+static int si470x_vidioc_queryctrl(struct file *file, void *priv,
+		struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) {
+		if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) {
+			memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc));
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+
+/*
+ * si470x_vidioc_g_ctrl - get the value of a control
+ */
+static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		ctrl->value = radio->registers[SYSCONFIG2] &
+				SYSCONFIG2_VOLUME;
+		break;
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = ((radio->registers[POWERCFG] &
+				POWERCFG_DMUTE) == 0) ? 1 : 0;
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_ctrl - set the value of a control
+ */
+static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
+		struct v4l2_control *ctrl)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
+		radio->registers[SYSCONFIG2] |= ctrl->value;
+		return si470x_set_register(radio, SYSCONFIG2);
+	case V4L2_CID_AUDIO_MUTE:
+		if (ctrl->value == 1)
+			radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
+		else
+			radio->registers[POWERCFG] |= POWERCFG_DMUTE;
+		return si470x_set_register(radio, POWERCFG);
+	}
+
+	return -EINVAL;
+}
+
+
+/*
+ * si470x_vidioc_g_audio - get audio attributes
+ */
+static int si470x_vidioc_g_audio(struct file *file, void *priv,
+		struct v4l2_audio *audio)
+{
+	if (audio->index > 1)
+		return -EINVAL;
+
+	strcpy(audio->name, "Radio");
+	audio->capability = V4L2_AUDCAP_STEREO;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_audio - set audio attributes
+ */
+static int si470x_vidioc_s_audio(struct file *file, void *priv,
+		struct v4l2_audio *audio)
+{
+	if (audio->index != 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_g_tuner - get tuner attributes
+ */
+static int si470x_vidioc_g_tuner(struct file *file, void *priv,
+		struct v4l2_tuner *tuner)
+{
+	int retval;
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (tuner->index > 0)
+		return -EINVAL;
+
+	/* read status rssi */
+	retval = si470x_get_register(radio, STATUSRSSI);
+	if (retval < 0)
+		return retval;
+
+	strcpy(tuner->name, "FM");
+	tuner->type = V4L2_TUNER_RADIO;
+	switch (band) {
+	/* 0: 87.5 - 108 MHz (USA, Europe, default) */
+	default:
+		tuner->rangelow  =  87.5 * FREQ_MUL;
+		tuner->rangehigh = 108   * FREQ_MUL;
+		break;
+	/* 1: 76   - 108 MHz (Japan wide band) */
+	case 1 :
+		tuner->rangelow  =  76   * FREQ_MUL;
+		tuner->rangehigh = 108   * FREQ_MUL;
+		break;
+	/* 2: 76   -  90 MHz (Japan) */
+	case 2 :
+		tuner->rangelow  =  76   * FREQ_MUL;
+		tuner->rangehigh =  90   * FREQ_MUL;
+		break;
+	};
+	tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	tuner->capability = V4L2_TUNER_CAP_LOW;
+
+	/* Stereo indicator == Stereo (instead of Mono) */
+	if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1)
+		tuner->audmode = V4L2_TUNER_MODE_STEREO;
+	else
+		tuner->audmode = V4L2_TUNER_MODE_MONO;
+
+	/* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
+	tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI)
+				* 0x0101;
+
+	/* automatic frequency control: -1: freq to low, 1 freq to high */
+	tuner->afc = 0;
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_tuner - set tuner attributes
+ */
+static int si470x_vidioc_s_tuner(struct file *file, void *priv,
+		struct v4l2_tuner *tuner)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (tuner->index > 0)
+		return -EINVAL;
+
+	if (tuner->audmode == V4L2_TUNER_MODE_MONO)
+		radio->registers[POWERCFG] |= POWERCFG_MONO;  /* force mono */
+	else
+		radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
+
+	return si470x_set_register(radio, POWERCFG);
+}
+
+
+/*
+ * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
+ */
+static int si470x_vidioc_g_frequency(struct file *file, void *priv,
+		struct v4l2_frequency *freq)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	freq->type = V4L2_TUNER_RADIO;
+	freq->frequency = si470x_get_freq(radio);
+
+	return 0;
+}
+
+
+/*
+ * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
+ */
+static int si470x_vidioc_s_frequency(struct file *file, void *priv,
+		struct v4l2_frequency *freq)
+{
+	struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+
+	if (freq->type != V4L2_TUNER_RADIO)
+		return -EINVAL;
+
+	return si470x_set_freq(radio, freq->frequency);
+}
+
+
+/*
+ * si470x_viddev_tamples - video device interface
+ */
+static struct video_device si470x_viddev_template = {
+	.fops			= &si470x_fops,
+	.name			= DRIVER_NAME,
+	.type			= VID_TYPE_TUNER,
+	.release		= video_device_release,
+	.vidioc_querycap	= si470x_vidioc_querycap,
+	.vidioc_g_input		= si470x_vidioc_g_input,
+	.vidioc_s_input		= si470x_vidioc_s_input,
+	.vidioc_queryctrl	= si470x_vidioc_queryctrl,
+	.vidioc_g_ctrl		= si470x_vidioc_g_ctrl,
+	.vidioc_s_ctrl		= si470x_vidioc_s_ctrl,
+	.vidioc_g_audio		= si470x_vidioc_g_audio,
+	.vidioc_s_audio		= si470x_vidioc_s_audio,
+	.vidioc_g_tuner		= si470x_vidioc_g_tuner,
+	.vidioc_s_tuner		= si470x_vidioc_s_tuner,
+	.vidioc_g_frequency	= si470x_vidioc_g_frequency,
+	.vidioc_s_frequency	= si470x_vidioc_s_frequency,
+	.owner			= THIS_MODULE,
+};
+
+
+
+/**************************************************************************
+ * USB Interface
+ **************************************************************************/
+
+/*
+ * si470x_usb_driver_probe - probe for the device
+ */
+static int si470x_usb_driver_probe(struct usb_interface *intf,
+		const struct usb_device_id *id)
+{
+	struct si470x_device *radio;
+
+	/* memory and interface allocations */
+	radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL);
+	if (!radio)
+		return -ENOMEM;
+	radio->videodev = video_device_alloc();
+	if (!radio->videodev) {
+		kfree(radio);
+		return -ENOMEM;
+	}
+	memcpy(radio->videodev, &si470x_viddev_template,
+			sizeof(si470x_viddev_template));
+	radio->users = 0;
+	radio->usbdev = interface_to_usbdev(intf);
+	video_set_drvdata(radio->videodev, radio);
+	if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) {
+		printk(KERN_WARNING DRIVER_NAME
+				": Could not register video device\n");
+		video_device_release(radio->videodev);
+		kfree(radio);
+		return -EIO;
+	}
+	usb_set_intfdata(intf, radio);
+
+	/* show some infos about the specific device */
+	if (si470x_get_all_registers(radio) < 0) {
+		video_device_release(radio->videodev);
+		kfree(radio);
+		return -EIO;
+	}
+	printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n",
+			radio->registers[DEVICEID], radio->registers[CHIPID]);
+
+	/* check if firmware is current */
+	if ((radio->registers[CHIPID] & CHIPID_FIRMWARE)
+			< RADIO_SW_VERSION_CURRENT)
+		printk(KERN_WARNING DRIVER_NAME
+			": This driver is known to work with chip version %d, "
+			"but the device has firmware %d.\n"
+			DRIVER_NAME
+			"If you have some trouble using this driver, please "
+			"report to V4L ML at video4linux-list@redhat.com\n",
+			radio->registers[CHIPID] & CHIPID_FIRMWARE,
+			RADIO_SW_VERSION_CURRENT);
+
+	/* set initial frequency */
+	si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
+
+	/* rds initialization */
+	radio->buf_size = rds_buf * 3;
+	radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
+	if (!radio->buffer) {
+		video_device_release(radio->videodev);
+		kfree(radio);
+		return -ENOMEM;
+	}
+	radio->wr_index = 0;
+	radio->rd_index = 0;
+	init_waitqueue_head(&radio->read_queue);
+
+	/* prepare polling via eventd */
+	INIT_WORK(&radio->work, si470x_work);
+	init_timer(&radio->timer);
+	radio->timer.function = si470x_timer;
+	radio->timer.data = (unsigned long) radio;
+
+	return 0;
+}
+
+
+/*
+ * si470x_usb_driver_disconnect - disconnect the device
+ */
+static void si470x_usb_driver_disconnect(struct usb_interface *intf)
+{
+	struct si470x_device *radio = usb_get_intfdata(intf);
+
+	del_timer_sync(&radio->timer);
+	flush_scheduled_work();
+
+	usb_set_intfdata(intf, NULL);
+	if (radio) {
+		video_unregister_device(radio->videodev);
+		kfree(radio->buffer);
+		kfree(radio);
+	}
+}
+
+
+/*
+ * si470x_usb_driver - usb driver interface
+ */
+static struct usb_driver si470x_usb_driver = {
+	.name		= DRIVER_NAME,
+	.probe		= si470x_usb_driver_probe,
+	.disconnect	= si470x_usb_driver_disconnect,
+	.id_table	= si470x_usb_driver_id_table,
+};
+
+
+
+/**************************************************************************
+ * Module Interface
+ **************************************************************************/
+
+/*
+ * si470x_module_init - module init
+ */
+static int __init si470x_module_init(void)
+{
+	printk(KERN_INFO DRIVER_DESC "\n");
+	return usb_register(&si470x_usb_driver);
+}
+
+
+/*
+ * si470x_module_exit - module exit
+ */
+static void __exit si470x_module_exit(void)
+{
+	usb_deregister(&si470x_usb_driver);
+}
+
+
+module_init(si470x_module_init);
+module_exit(si470x_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION("1.0.4");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index c9f14bfc8544..a2e8987a6195 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -45,7 +45,7 @@ comment "Audio decoders"
 
 config VIDEO_TVAUDIO
 	tristate "Simple audio decoder chips"
-	depends on VIDEO_V4L1 && I2C
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for several audio decoder chips found on some bt8xx boards:
 	  Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
@@ -57,7 +57,7 @@ config VIDEO_TVAUDIO
 
 config VIDEO_TDA7432
 	tristate "Philips TDA7432 audio processor"
-	depends on VIDEO_V4L1 && I2C
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for tda7432 audio decoder chip found on some bt8xx boards.
 
@@ -75,7 +75,7 @@ config VIDEO_TDA9840
 
 config VIDEO_TDA9875
 	tristate "Philips TDA9875 audio processor"
-	depends on VIDEO_V4L1 && I2C
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for tda9875 audio decoder chip found on some bt8xx boards.
 
@@ -109,9 +109,19 @@ config VIDEO_MSP3400
 	  To compile this driver as a module, choose M here: the
 	  module will be called msp3400.
 
+config VIDEO_CS5345
+	tristate "Cirrus Logic CS5345 audio ADC"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the Cirrus Logic CS5345 24-bit, 192 kHz
+	  stereo A/D converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cs5345.
+
 config VIDEO_CS53L32A
 	tristate "Cirrus Logic CS53L32A audio ADC"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the Cirrus Logic CS53L32A low voltage
 	  stereo A/D converter.
@@ -119,6 +129,15 @@ config VIDEO_CS53L32A
 	  To compile this driver as a module, choose M here: the
 	  module will be called cs53l32a.
 
+config VIDEO_M52790
+       tristate "Mitsubishi M52790 A/V switch"
+       depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+       ---help---
+	 Support for the Mitsubishi M52790 A/V switch.
+
+	 To compile this driver as a module, choose M here: the
+	 module will be called m52790.
+
 config VIDEO_TLV320AIC23B
 	tristate "Texas Instruments TLV320AIC23B audio codec"
 	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
@@ -130,7 +149,7 @@ config VIDEO_TLV320AIC23B
 
 config VIDEO_WM8775
 	tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the Wolfson Microelectronics WM8775 high
 	  performance stereo A/D Converter with a 4 channel input mixer.
@@ -140,7 +159,7 @@ config VIDEO_WM8775
 
 config VIDEO_WM8739
 	tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the Wolfson Microelectronics WM8739
 	  stereo A/D Converter.
@@ -244,7 +263,7 @@ config VIDEO_SAA7114
 
 config VIDEO_SAA711X
 	tristate "Philips SAA7113/4/5 video decoders"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the Philips SAA7113/4/5 video decoders.
 
@@ -300,7 +319,7 @@ comment "Video encoders"
 
 config VIDEO_SAA7127
 	tristate "Philips SAA7127/9 digital video encoders"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the Philips SAA7127/9 digital video encoders.
 
@@ -338,7 +357,7 @@ comment "Video improvement chips"
 
 config VIDEO_UPD64031A
 	tristate "NEC Electronics uPD64031A Ghost Reduction"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the NEC Electronics uPD64031A Ghost Reduction
 	  video chip. It is most often found in NTSC TV cards made for
@@ -350,7 +369,7 @@ config VIDEO_UPD64031A
 
 config VIDEO_UPD64083
 	tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
-	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	depends on VIDEO_V4L2 && I2C
 	---help---
 	  Support for the NEC Electronics uPD64083 3-Dimensional Y/C
 	  separation video chip. It is used to improve the quality of
@@ -802,6 +821,19 @@ config USB_ZR364XX
 	  To compile this driver as a module, choose M here: the
 	  module will be called zr364xx.
 
+config USB_STKWEBCAM
+	tristate "USB Syntek DC1125 Camera support"
+	depends on VIDEO_V4L2 && EXPERIMENTAL
+	---help---
+	  Say Y here if you want to use this type of camera.
+	  Supported devices are typically found in some Asus laptops,
+	  with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
+	  may be supported by the stk11xx driver, from which this is
+	  derived, see http://stk11xx.sourceforge.net
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called stkwebcam.
+
 endif # V4L_USB_DRIVERS
 
 endif # VIDEO_CAPTURE_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index b5a064163e03..28ddd146c1c5 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -4,10 +4,12 @@
 
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
-tuner-objs	:=	tuner-core.o tuner-types.o tda9887.o
+tuner-objs	:=	tuner-core.o tuner-types.o
 
 msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
 
+stkwebcam-objs	:=	stk-webcam.o stk-sensor.o
+
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
 			   v4l2-int-device.o
 
@@ -66,7 +68,9 @@ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
 obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
 obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_M52790) += m52790.o
 obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
 obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
 obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
@@ -81,11 +85,13 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
 obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 
+obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
 obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
 obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
 obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
 obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
 obj-$(CONFIG_TUNER_TEA5761) += tea5761.o
+obj-$(CONFIG_TUNER_TDA9887) += tda9887.o
 
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
@@ -112,6 +118,7 @@ obj-$(CONFIG_USB_SE401)         += se401.o
 obj-$(CONFIG_USB_STV680)        += stv680.o
 obj-$(CONFIG_USB_W9968CF)       += w9968cf.o
 obj-$(CONFIG_USB_ZR364XX)       += zr364xx.o
+obj-$(CONFIG_USB_STKWEBCAM)     += stkwebcam.o
 
 obj-$(CONFIG_USB_SN9C102)       += sn9c102/
 obj-$(CONFIG_USB_ET61X251)      += et61x251/
@@ -129,3 +136,4 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index 2ca162b390a2..cfc822bb502a 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -1,6 +1,6 @@
 config VIDEO_BT848
 	tristate "BT848 Video For Linux"
-	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1
+	depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT
 	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_BTCX
diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile
index a096a03418aa..924d216d9570 100644
--- a/drivers/media/video/bt8xx/Makefile
+++ b/drivers/media/video/bt8xx/Makefile
@@ -4,7 +4,7 @@
 
 bttv-objs      :=      bttv-driver.o bttv-cards.o bttv-if.o \
 		       bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
-		       bttv-input.o
+		       bttv-input.o bttv-audio-hook.o
 
 obj-$(CONFIG_VIDEO_BT848) += bttv.o
 
diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c
new file mode 100644
index 000000000000..2364d16586b3
--- /dev/null
+++ b/drivers/media/video/bt8xx/bttv-audio-hook.c
@@ -0,0 +1,382 @@
+/*
+ * Handlers for board audio hooks, splitted from bttv-cards
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include "bttv-audio-hook.h"
+
+#include <linux/delay.h>
+
+/* ----------------------------------------------------------------------- */
+/* winview                                                                 */
+
+void winview_volume(struct bttv *btv, __u16 volume)
+{
+	/* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
+	int bits_out, loops, vol, data;
+
+	/* 32 levels logarithmic */
+	vol = 32 - ((volume>>11));
+	/* units */
+	bits_out = (PT2254_DBS_IN_2>>(vol%5));
+	/* tens */
+	bits_out |= (PT2254_DBS_IN_10>>(vol/5));
+	bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
+	data = gpio_read();
+	data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
+		  WINVIEW_PT2254_STROBE);
+	for (loops = 17; loops >= 0 ; loops--) {
+		if (bits_out & (1<<loops))
+			data |=  WINVIEW_PT2254_DATA;
+		else
+			data &= ~WINVIEW_PT2254_DATA;
+		gpio_write(data);
+		udelay(5);
+		data |= WINVIEW_PT2254_CLK;
+		gpio_write(data);
+		udelay(5);
+		data &= ~WINVIEW_PT2254_CLK;
+		gpio_write(data);
+	}
+	data |=  WINVIEW_PT2254_STROBE;
+	data &= ~WINVIEW_PT2254_DATA;
+	gpio_write(data);
+	udelay(10);
+	data &= ~WINVIEW_PT2254_STROBE;
+	gpio_write(data);
+}
+
+/* ----------------------------------------------------------------------- */
+/* mono/stereo control for various cards (which don't use i2c chips but    */
+/* connect something to the GPIO pins                                      */
+
+void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int con = 0;
+
+	if (set) {
+		gpio_inout(0x300, 0x300);
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
+			con = 0x000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			con = 0x300;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			con = 0x200;
+/*		if (t->audmode & V4L2_TUNER_MODE_MONO)
+ *			con = 0x100; */
+		gpio_bits(0x300, con);
+	} else {
+		t->audmode = V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int val, con;
+
+	if (btv->radio_user)
+		return;
+
+	val = gpio_read();
+	if (set) {
+		con = 0x000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2) {
+			if (t->audmode & V4L2_TUNER_MODE_LANG1) {
+				/* LANG1 + LANG2 */
+				con = 0x100;
+			}
+			else {
+				/* LANG2 */
+				con = 0x300;
+			}
+		}
+		if (con != (val & 0x300)) {
+			gpio_bits(0x300, con);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"gvbctv5pci");
+		}
+	} else {
+		switch (val & 0x70) {
+		  case 0x10:
+			t->rxsubchans = V4L2_TUNER_SUB_LANG1 |  V4L2_TUNER_SUB_LANG2;
+			break;
+		  case 0x30:
+			t->rxsubchans = V4L2_TUNER_SUB_LANG2;
+			break;
+		  case 0x50:
+			t->rxsubchans = V4L2_TUNER_SUB_LANG1;
+			break;
+		  case 0x60:
+			t->rxsubchans = V4L2_TUNER_SUB_STEREO;
+			break;
+		  case 0x70:
+			t->rxsubchans = V4L2_TUNER_SUB_MONO;
+			break;
+		  default:
+			t->rxsubchans = V4L2_TUNER_SUB_MONO |
+					 V4L2_TUNER_SUB_STEREO |
+					 V4L2_TUNER_SUB_LANG1 |
+					 V4L2_TUNER_SUB_LANG2;
+		}
+		t->audmode = V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
+ *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
+ *  0xdde enables mono and 0xccd enables sap
+ *
+ * Petr Vandrovec <VANDROVE@vc.cvut.cz>
+ *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
+ *  input/output sound connection, so both must be set for output mode.
+ *
+ * Looks like it's needed only for the "tvphone", the "tvphone 98"
+ * handles this with a tda9840
+ *
+ */
+
+void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	int val = 0;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
+			val = 0x02;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			val = 0x01;
+		if (val) {
+			gpio_bits(0x03,val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"avermedia");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1;
+		return;
+	}
+}
+
+
+void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	int val = 0;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)   /* SAP */
+			val = 0x01;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)  /* STEREO */
+			val = 0x02;
+		btaor(val, ~0x03, BT848_GPIO_DATA);
+		if (bttv_gpio)
+			bttv_gpio_tracking(btv,"avermedia");
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+		return;
+	}
+}
+
+/* Lifetec 9415 handling */
+
+void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	int val = 0;
+
+	if (gpio_read() & 0x4000) {
+		t->audmode = V4L2_TUNER_MODE_MONO;
+		return;
+	}
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)  /* A2 SAP */
+			val = 0x0080;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */
+			val = 0x0880;
+		if ((t->audmode & V4L2_TUNER_MODE_LANG1) ||
+		    (t->audmode & V4L2_TUNER_MODE_MONO))
+			val = 0;
+		gpio_bits(0x0880, val);
+		if (bttv_gpio)
+			bttv_gpio_tracking(btv,"lt9415");
+	} else {
+		/* autodetect doesn't work with this card :-( */
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+		return;
+	}
+}
+
+/* TDA9821 on TerraTV+ Bt848, Bt878 */
+void terratv_audio(struct bttv *btv,  struct v4l2_tuner *t, int set)
+{
+	unsigned int con = 0;
+
+	if (set) {
+		gpio_inout(0x180000,0x180000);
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			con = 0x080000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			con = 0x180000;
+		gpio_bits(0x180000, con);
+		if (bttv_gpio)
+			bttv_gpio_tracking(btv,"terratv");
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+
+void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned long val = 0;
+
+	if (set) {
+		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
+		if (t->audmode & V4L2_TUNER_MODE_MONO)		/* Mono */
+			val = 0x420000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)	/* Mono */
+			val = 0x420000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)	/* SAP */
+			val = 0x410000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)	/* Stereo */
+			val = 0x020000;
+		if (val) {
+			gpio_bits(0x430000, val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"winfast2000");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
+ * revision 9B has on-board TDA9874A sound decoder).
+ *
+ * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
+ *       will mute this cards.
+ */
+void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int val = 0;
+
+	if (btv->radio_user)
+		return;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_MONO)	{
+			val = 0x01;
+		}
+		if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
+		    || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
+			val = 0x02;
+		}
+		if (val) {
+			gpio_bits(0x03,val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"pvbt878p9b");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * Dariusz Kowalewski <darekk@automex.pl>
+ * sound control for FlyVideo 2000S (with tda9874 decoder)
+ * based on pvbt878p9b_audio() - this is not tested, please fix!!!
+ */
+void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int val = 0xffff;
+
+	if (btv->radio_user)
+		return;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_MONO)	{
+			val = 0x0000;
+		}
+		if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2))
+		    || (t->audmode & V4L2_TUNER_MODE_STEREO)) {
+			val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
+		}
+		if (val != 0xffff) {
+			gpio_bits(0x1800, val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"fv2000s");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * sound control for Canopus WinDVR PCI
+ * Masaki Suzuki <masaki@btree.org>
+ */
+void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned long val = 0;
+
+	if (set) {
+		if (t->audmode & V4L2_TUNER_MODE_MONO)
+			val = 0x040000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
+			val = 0;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			val = 0x100000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			val = 0;
+		if (val) {
+			gpio_bits(0x140000, val);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"windvr");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	}
+}
+
+/*
+ * sound control for AD-TVK503
+ * Hiroshi Takekawa <sian@big.or.jp>
+ */
+void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set)
+{
+	unsigned int con = 0xffffff;
+
+	/* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
+
+	if (set) {
+		/* btor(***, BT848_GPIO_OUT_EN); */
+		if (t->audmode & V4L2_TUNER_MODE_LANG1)
+			con = 0x00000000;
+		if (t->audmode & V4L2_TUNER_MODE_LANG2)
+			con = 0x00180000;
+		if (t->audmode & V4L2_TUNER_MODE_STEREO)
+			con = 0x00000000;
+		if (t->audmode & V4L2_TUNER_MODE_MONO)
+			con = 0x00060000;
+		if (con != 0xffffff) {
+			gpio_bits(0x1e0000,con);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv, "adtvk503");
+		}
+	} else {
+		t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO |
+			  V4L2_TUNER_MODE_LANG1  | V4L2_TUNER_MODE_LANG2;
+	}
+}
diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.h b/drivers/media/video/bt8xx/bttv-audio-hook.h
new file mode 100644
index 000000000000..159d07adeff8
--- /dev/null
+++ b/drivers/media/video/bt8xx/bttv-audio-hook.h
@@ -0,0 +1,23 @@
+/*
+ * Handlers for board audio hooks, splitted from bttv-cards
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License
+ */
+
+#include "bttvp.h"
+
+void winview_volume (struct bttv *btv, __u16 volume);
+
+void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void terratv_audio(struct bttv *btv,  struct v4l2_tuner *tuner, int set);
+void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 585d1ef95afd..63a47cd4c161 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -39,6 +39,7 @@
 #include "bttvp.h"
 #include <media/v4l2-common.h>
 #include <media/tvaudio.h>
+#include "bttv-audio-hook.h"
 
 /* fwd decl */
 static void boot_msp34xx(struct bttv *btv, int pin);
@@ -50,20 +51,6 @@ static void modtec_eeprom(struct bttv *btv);
 static void init_PXC200(struct bttv *btv);
 static void init_RTV24(struct bttv *btv);
 
-static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
-static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
-static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
-				    int set);
-static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v,
-				      int set);
-static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
-static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
-static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set);
-static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
-static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set);
-static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set);
-static void windvr_audio(struct bttv *btv, struct video_audio *v, int set);
-static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set);
 static void rv605_muxsel(struct bttv *btv, unsigned int input);
 static void eagle_muxsel(struct bttv *btv, unsigned int input);
 static void xguard_muxsel(struct bttv *btv, unsigned int input);
@@ -427,7 +414,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= avermedia_tvphone_audio,
+		.audio_mode_gpio= avermedia_tvphone_audio,
 		.has_remote     = 1,
 	},
 	[BTTV_BOARD_MATRIX_VISION] = {
@@ -539,7 +526,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook     = avermedia_tv_stereo_audio,
+		.audio_mode_gpio= avermedia_tv_stereo_audio,
 		.no_gpioirq     = 1,
 	},
 	[BTTV_BOARD_VHX] = {
@@ -604,7 +591,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= winview_audio,
+		.volume_gpio	= winview_volume,
 		.has_radio	= 1,
 	},
 	[BTTV_BOARD_AVEC_INTERCAP] = {
@@ -728,7 +715,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook     = terratv_audio,
+		.audio_mode_gpio= terratv_audio,
 	},
 	[BTTV_BOARD_HAUPPAUG_WCAM] = {
 		.name		= "Hauppauge WinCam newer (bt878)",
@@ -776,7 +763,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= terratv_audio,
+		.audio_mode_gpio= terratv_audio,
 		/* GPIO wiring:
 		External 20 pin connector (for Active Radio Upgrade board)
 		gpio00: i2c-sda
@@ -915,7 +902,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= winfast2000_audio,
+		.audio_mode_gpio= winfast2000_audio,
 		.has_remote     = 1,
 	},
 	[BTTV_BOARD_CHRONOS_VS2] = {
@@ -1035,7 +1022,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_radio	= 1,
-		.audio_hook	= avermedia_tvphone_audio,
+		.audio_mode_gpio= avermedia_tvphone_audio,
 	},
 	[BTTV_BOARD_PV951] = {
 		.name		= "ProVideo PV951", /* pic16c54 */
@@ -1167,7 +1154,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_ALPS_TSHC6_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= gvbctv3pci_audio,
+		.audio_mode_gpio= gvbctv3pci_audio,
 	},
 	[BTTV_BOARD_PXELVWPLTVPAK] = {
 		.name		= "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP",
@@ -1472,7 +1459,7 @@ struct tvcard bttv_tvcards[] = {
 				/* -dk-???: set mute=0x1800 for tda9874h daughterboard */
 		.gpiomux 	= { 0x0000,0x0800,0x1000,0x1000 },
 		.gpiomute 	= 0x1800,
-		.audio_hook	= fv2000s_audio,
+		.audio_mode_gpio= fv2000s_audio,
 		.no_msp34xx	= 1,
 		.no_tda9875	= 1,
 		.needs_tvaudio  = 1,
@@ -1513,7 +1500,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type     = TUNER_SHARP_2U5JF5540_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook     = gvbctv3pci_audio,
+		.audio_mode_gpio= gvbctv3pci_audio,
 	},
 
 	/* ---- card 0x44 ---------------------------------- */
@@ -1632,7 +1619,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= pvbt878p9b_audio, /* Note: not all cards have stereo */
+		.audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */
 		.has_radio	= 1,  /* Note: not all cards have radio */
 		.has_remote     = 1,
 		/* GPIO wiring:
@@ -1710,7 +1697,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type     = TUNER_PHILIPS_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook     = windvr_audio,
+		.audio_mode_gpio= windvr_audio,
 	},
 	[BTTV_BOARD_GRANDTEC_MULTI] = {
 		.name           = "GrandTec Multi Capture Card (Bt878)",
@@ -1807,7 +1794,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type     = TUNER_PHILIPS_NTSC_M,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook     = gvbctv5pci_audio,
+		.audio_mode_gpio= gvbctv5pci_audio,
 		.has_radio      = 1,
 	},
 	[BTTV_BOARD_OSPREY1x0] = {
@@ -2106,7 +2093,7 @@ struct tvcard bttv_tvcards[] = {
 		.tuner_type     = TUNER_PHILIPS_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.audio_hook	= adtvk503_audio,
+		.audio_mode_gpio= adtvk503_audio,
 	},
 
 		/* ---- card 0x64 ---------------------------------- */
@@ -3173,8 +3160,8 @@ static void flyvideo_gpio(struct bttv *btv)
 	/* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80
 	 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00
 	 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */
-	if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio;
-	/* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */
+	if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio;
+	/* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */
 }
 
 static int miro_tunermap[] = { 0,6,2,3,   4,5,6,0,  3,0,4,5,  5,2,16,1,
@@ -3574,8 +3561,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
 	}
 
 	if (btv->tda9887_conf) {
-		bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG,
-							&btv->tda9887_conf);
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &btv->tda9887_conf;
+
+		bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg);
 	}
 
 	btv->svhs = bttv_tvcards[btv->c.type].svhs;
@@ -3590,8 +3581,10 @@ void __devinit bttv_init_card2(struct bttv *btv)
 		btv->has_remote=1;
 	if (!bttv_tvcards[btv->c.type].no_gpioirq)
 		btv->gpioirq=1;
-	if (bttv_tvcards[btv->c.type].audio_hook)
-		btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
+	if (bttv_tvcards[btv->c.type].volume_gpio)
+		btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio;
+	if (bttv_tvcards[btv->c.type].audio_mode_gpio)
+		btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio;
 
 	if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) {
 		/* detect Bt832 chip for quartzsight digital camera */
@@ -3950,7 +3943,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv)
 void bttv_tda9880_setnorm(struct bttv *btv, int norm)
 {
 	/* fix up our card entry */
-	if(norm==VIDEO_MODE_NTSC) {
+	if(norm==V4L2_STD_NTSC) {
 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
 		bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
@@ -4319,387 +4312,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq)
 	tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
 }
 
-
-/* ----------------------------------------------------------------------- */
-/* winview                                                                 */
-
-static void winview_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	/* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
-	int bits_out, loops, vol, data;
-
-	if (!set) {
-		/* Fixed by Leandro Lucarella <luca@linuxmendoza.org.ar (07/31/01) */
-		v->flags |= VIDEO_AUDIO_VOLUME;
-		return;
-	}
-
-	/* 32 levels logarithmic */
-	vol = 32 - ((v->volume>>11));
-	/* units */
-	bits_out = (PT2254_DBS_IN_2>>(vol%5));
-	/* tens */
-	bits_out |= (PT2254_DBS_IN_10>>(vol/5));
-	bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL;
-	data = gpio_read();
-	data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
-		  WINVIEW_PT2254_STROBE);
-	for (loops = 17; loops >= 0 ; loops--) {
-		if (bits_out & (1<<loops))
-			data |=  WINVIEW_PT2254_DATA;
-		else
-			data &= ~WINVIEW_PT2254_DATA;
-		gpio_write(data);
-		udelay(5);
-		data |= WINVIEW_PT2254_CLK;
-		gpio_write(data);
-		udelay(5);
-		data &= ~WINVIEW_PT2254_CLK;
-		gpio_write(data);
-	}
-	data |=  WINVIEW_PT2254_STROBE;
-	data &= ~WINVIEW_PT2254_DATA;
-	gpio_write(data);
-	udelay(10);
-	data &= ~WINVIEW_PT2254_STROBE;
-	gpio_write(data);
-}
-
-/* ----------------------------------------------------------------------- */
-/* mono/stereo control for various cards (which don't use i2c chips but    */
-/* connect something to the GPIO pins                                      */
-
-static void
-gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int con = 0;
-
-	if (set) {
-		gpio_inout(0x300, 0x300);
-		if (v->mode & VIDEO_SOUND_LANG1)
-			con = 0x000;
-		if (v->mode & VIDEO_SOUND_LANG2)
-			con = 0x300;
-		if (v->mode & VIDEO_SOUND_STEREO)
-			con = 0x200;
-/*		if (v->mode & VIDEO_SOUND_MONO)
- *			con = 0x100; */
-		gpio_bits(0x300, con);
-	} else {
-		v->mode = VIDEO_SOUND_STEREO |
-			  VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
-	}
-}
-
-static void
-gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int val, con;
-
-	if (btv->radio_user)
-		return;
-
-	val = gpio_read();
-	if (set) {
-		con = 0x000;
-		if (v->mode & VIDEO_SOUND_LANG2) {
-			if (v->mode & VIDEO_SOUND_LANG1) {
-				/* LANG1 + LANG2 */
-				con = 0x100;
-			}
-			else {
-				/* LANG2 */
-				con = 0x300;
-			}
-		}
-		if (con != (val & 0x300)) {
-			gpio_bits(0x300, con);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"gvbctv5pci");
-		}
-	} else {
-		switch (val & 0x70) {
-		  case 0x10:
-			v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-			break;
-		  case 0x30:
-			v->mode = VIDEO_SOUND_LANG2;
-			break;
-		  case 0x50:
-			v->mode = VIDEO_SOUND_LANG1;
-			break;
-		  case 0x60:
-			v->mode = VIDEO_SOUND_STEREO;
-			break;
-		  case 0x70:
-			v->mode = VIDEO_SOUND_MONO;
-			break;
-		  default:
-			v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-				  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-		}
-	}
-}
-
-/*
- * Mario Medina Nussbaum <medisoft@alohabbs.org.mx>
- *  I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo,
- *  0xdde enables mono and 0xccd enables sap
- *
- * Petr Vandrovec <VANDROVE@vc.cvut.cz>
- *  P.S.: At least mask in line above is wrong - GPIO pins 3,2 select
- *  input/output sound connection, so both must be set for output mode.
- *
- * Looks like it's needed only for the "tvphone", the "tvphone 98"
- * handles this with a tda9840
- *
- */
-static void
-avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	int val = 0;
-
-	if (set) {
-		if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
-			val = 0x02;
-		if (v->mode & VIDEO_SOUND_STEREO)
-			val = 0x01;
-		if (val) {
-			gpio_bits(0x03,val);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"avermedia");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1;
-		return;
-	}
-}
-
-static void
-avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	int val = 0;
-
-	if (set) {
-		if (v->mode & VIDEO_SOUND_LANG2)   /* SAP */
-			val = 0x01;
-		if (v->mode & VIDEO_SOUND_STEREO)  /* STEREO */
-			val = 0x02;
-		btaor(val, ~0x03, BT848_GPIO_DATA);
-		if (bttv_gpio)
-			bttv_gpio_tracking(btv,"avermedia");
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-		return;
-	}
-}
-
-/* Lifetec 9415 handling */
-static void
-lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	int val = 0;
-
-	if (gpio_read() & 0x4000) {
-		v->mode = VIDEO_SOUND_MONO;
-		return;
-	}
-
-	if (set) {
-		if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
-			val = 0x0080;
-		if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
-			val = 0x0880;
-		if ((v->mode & VIDEO_SOUND_LANG1) ||
-		    (v->mode & VIDEO_SOUND_MONO))
-			val = 0;
-		gpio_bits(0x0880, val);
-		if (bttv_gpio)
-			bttv_gpio_tracking(btv,"lt9415");
-	} else {
-		/* autodetect doesn't work with this card :-( */
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-		return;
-	}
-}
-
-/* TDA9821 on TerraTV+ Bt848, Bt878 */
-static void
-terratv_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int con = 0;
-
-	if (set) {
-		gpio_inout(0x180000,0x180000);
-		if (v->mode & VIDEO_SOUND_LANG2)
-			con = 0x080000;
-		if (v->mode & VIDEO_SOUND_STEREO)
-			con = 0x180000;
-		gpio_bits(0x180000, con);
-		if (bttv_gpio)
-			bttv_gpio_tracking(btv,"terratv");
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	}
-}
-
-static void
-winfast2000_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned long val = 0;
-
-	if (set) {
-		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
-		if (v->mode & VIDEO_SOUND_MONO)		/* Mono */
-			val = 0x420000;
-		if (v->mode & VIDEO_SOUND_LANG1)	/* Mono */
-			val = 0x420000;
-		if (v->mode & VIDEO_SOUND_LANG2)	/* SAP */
-			val = 0x410000;
-		if (v->mode & VIDEO_SOUND_STEREO)	/* Stereo */
-			val = 0x020000;
-		if (val) {
-			gpio_bits(0x430000, val);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"winfast2000");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	}
-}
-
-/*
- * Dariusz Kowalewski <darekk@automex.pl>
- * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM
- * revision 9B has on-board TDA9874A sound decoder).
- *
- * Note: There are card variants without tda9874a. Forcing the "stereo sound route"
- *       will mute this cards.
- */
-static void
-pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int val = 0;
-
-	if (btv->radio_user)
-		return;
-
-	if (set) {
-		if (v->mode & VIDEO_SOUND_MONO)	{
-			val = 0x01;
-		}
-		if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
-		    || (v->mode & VIDEO_SOUND_STEREO)) {
-			val = 0x02;
-		}
-		if (val) {
-			gpio_bits(0x03,val);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"pvbt878p9b");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	}
-}
-
-/*
- * Dariusz Kowalewski <darekk@automex.pl>
- * sound control for FlyVideo 2000S (with tda9874 decoder)
- * based on pvbt878p9b_audio() - this is not tested, please fix!!!
- */
-static void
-fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int val = 0xffff;
-
-	if (btv->radio_user)
-		return;
-	if (set) {
-		if (v->mode & VIDEO_SOUND_MONO)	{
-			val = 0x0000;
-		}
-		if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2))
-		    || (v->mode & VIDEO_SOUND_STEREO)) {
-			val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */
-		}
-		if (val != 0xffff) {
-			gpio_bits(0x1800, val);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"fv2000s");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	}
-}
-
-/*
- * sound control for Canopus WinDVR PCI
- * Masaki Suzuki <masaki@btree.org>
- */
-static void
-windvr_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned long val = 0;
-
-	if (set) {
-		if (v->mode & VIDEO_SOUND_MONO)
-			val = 0x040000;
-		if (v->mode & VIDEO_SOUND_LANG1)
-			val = 0;
-		if (v->mode & VIDEO_SOUND_LANG2)
-			val = 0x100000;
-		if (v->mode & VIDEO_SOUND_STEREO)
-			val = 0;
-		if (val) {
-			gpio_bits(0x140000, val);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv,"windvr");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	}
-}
-
-/*
- * sound control for AD-TVK503
- * Hiroshi Takekawa <sian@big.or.jp>
- */
-static void
-adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
-{
-	unsigned int con = 0xffffff;
-
-	/* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */
-
-	if (set) {
-		/* btor(***, BT848_GPIO_OUT_EN); */
-		if (v->mode & VIDEO_SOUND_LANG1)
-			con = 0x00000000;
-		if (v->mode & VIDEO_SOUND_LANG2)
-			con = 0x00180000;
-		if (v->mode & VIDEO_SOUND_STEREO)
-			con = 0x00000000;
-		if (v->mode & VIDEO_SOUND_MONO)
-			con = 0x00060000;
-		if (con != 0xffffff) {
-			gpio_bits(0x1e0000,con);
-			if (bttv_gpio)
-				bttv_gpio_tracking(btv, "adtvk503");
-		}
-	} else {
-		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
-			  VIDEO_SOUND_LANG1  | VIDEO_SOUND_LANG2;
-	}
-}
-
 /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
  *
  * This is needed because rv605 don't use a normal multiplex, but a crosspoint
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 581a3c955739..907dc62c1783 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -9,6 +9,12 @@
     some v4l2 code lines are taken from Justin's bttv2 driver which is
     (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
 
+    V4L1 removal from:
+    (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+
+    Fixes to be fully V4L2 compliant by
+    (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+
     Cropping and overscan support
     Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
     Sponsored by OPQ Systems AB
@@ -157,7 +163,7 @@ MODULE_LICENSE("GPL");
 static ssize_t show_card(struct device *cd,
 			 struct device_attribute *attr, char *buf)
 {
-	struct video_device *vfd = to_video_device(cd);
+	struct video_device *vfd = container_of(cd, struct video_device, class_dev);
 	struct bttv *btv = dev_get_drvdata(vfd->dev);
 	return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
 }
@@ -470,31 +476,27 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
 /* ----------------------------------------------------------------------- */
 /* bttv format list
    packed pixel formats must come first */
-static const struct bttv_format bttv_formats[] = {
+static const struct bttv_format formats[] = {
 	{
 		.name     = "8 bpp, gray",
-		.palette  = VIDEO_PALETTE_GREY,
 		.fourcc   = V4L2_PIX_FMT_GREY,
 		.btformat = BT848_COLOR_FMT_Y8,
 		.depth    = 8,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "8 bpp, dithered color",
-		.palette  = VIDEO_PALETTE_HI240,
 		.fourcc   = V4L2_PIX_FMT_HI240,
 		.btformat = BT848_COLOR_FMT_RGB8,
 		.depth    = 8,
 		.flags    = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
 	},{
 		.name     = "15 bpp RGB, le",
-		.palette  = VIDEO_PALETTE_RGB555,
 		.fourcc   = V4L2_PIX_FMT_RGB555,
 		.btformat = BT848_COLOR_FMT_RGB15,
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "15 bpp RGB, be",
-		.palette  = -1,
 		.fourcc   = V4L2_PIX_FMT_RGB555X,
 		.btformat = BT848_COLOR_FMT_RGB15,
 		.btswap   = 0x03, /* byteswap */
@@ -502,14 +504,12 @@ static const struct bttv_format bttv_formats[] = {
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "16 bpp RGB, le",
-		.palette  = VIDEO_PALETTE_RGB565,
 		.fourcc   = V4L2_PIX_FMT_RGB565,
 		.btformat = BT848_COLOR_FMT_RGB16,
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "16 bpp RGB, be",
-		.palette  = -1,
 		.fourcc   = V4L2_PIX_FMT_RGB565X,
 		.btformat = BT848_COLOR_FMT_RGB16,
 		.btswap   = 0x03, /* byteswap */
@@ -517,21 +517,18 @@ static const struct bttv_format bttv_formats[] = {
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "24 bpp RGB, le",
-		.palette  = VIDEO_PALETTE_RGB24,
 		.fourcc   = V4L2_PIX_FMT_BGR24,
 		.btformat = BT848_COLOR_FMT_RGB24,
 		.depth    = 24,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "32 bpp RGB, le",
-		.palette  = VIDEO_PALETTE_RGB32,
 		.fourcc   = V4L2_PIX_FMT_BGR32,
 		.btformat = BT848_COLOR_FMT_RGB32,
 		.depth    = 32,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "32 bpp RGB, be",
-		.palette  = -1,
 		.fourcc   = V4L2_PIX_FMT_RGB32,
 		.btformat = BT848_COLOR_FMT_RGB32,
 		.btswap   = 0x0f, /* byte+word swap */
@@ -539,21 +536,18 @@ static const struct bttv_format bttv_formats[] = {
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "4:2:2, packed, YUYV",
-		.palette  = VIDEO_PALETTE_YUV422,
 		.fourcc   = V4L2_PIX_FMT_YUYV,
 		.btformat = BT848_COLOR_FMT_YUY2,
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "4:2:2, packed, YUYV",
-		.palette  = VIDEO_PALETTE_YUYV,
 		.fourcc   = V4L2_PIX_FMT_YUYV,
 		.btformat = BT848_COLOR_FMT_YUY2,
 		.depth    = 16,
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "4:2:2, packed, UYVY",
-		.palette  = VIDEO_PALETTE_UYVY,
 		.fourcc   = V4L2_PIX_FMT_UYVY,
 		.btformat = BT848_COLOR_FMT_YUY2,
 		.btswap   = 0x03, /* byteswap */
@@ -561,7 +555,6 @@ static const struct bttv_format bttv_formats[] = {
 		.flags    = FORMAT_FLAGS_PACKED,
 	},{
 		.name     = "4:2:2, planar, Y-Cb-Cr",
-		.palette  = VIDEO_PALETTE_YUV422P,
 		.fourcc   = V4L2_PIX_FMT_YUV422P,
 		.btformat = BT848_COLOR_FMT_YCrCb422,
 		.depth    = 16,
@@ -570,7 +563,6 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 0,
 	},{
 		.name     = "4:2:0, planar, Y-Cb-Cr",
-		.palette  = VIDEO_PALETTE_YUV420P,
 		.fourcc   = V4L2_PIX_FMT_YUV420,
 		.btformat = BT848_COLOR_FMT_YCrCb422,
 		.depth    = 12,
@@ -579,7 +571,6 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 1,
 	},{
 		.name     = "4:2:0, planar, Y-Cr-Cb",
-		.palette  = -1,
 		.fourcc   = V4L2_PIX_FMT_YVU420,
 		.btformat = BT848_COLOR_FMT_YCrCb422,
 		.depth    = 12,
@@ -588,7 +579,6 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 1,
 	},{
 		.name     = "4:1:1, planar, Y-Cb-Cr",
-		.palette  = VIDEO_PALETTE_YUV411P,
 		.fourcc   = V4L2_PIX_FMT_YUV411P,
 		.btformat = BT848_COLOR_FMT_YCrCb411,
 		.depth    = 12,
@@ -597,7 +587,6 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 0,
 	},{
 		.name     = "4:1:0, planar, Y-Cb-Cr",
-		.palette  = VIDEO_PALETTE_YUV410P,
 		.fourcc   = V4L2_PIX_FMT_YUV410,
 		.btformat = BT848_COLOR_FMT_YCrCb411,
 		.depth    = 9,
@@ -606,7 +595,6 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 2,
 	},{
 		.name     = "4:1:0, planar, Y-Cr-Cb",
-		.palette  = -1,
 		.fourcc   = V4L2_PIX_FMT_YVU410,
 		.btformat = BT848_COLOR_FMT_YCrCb411,
 		.depth    = 9,
@@ -615,14 +603,13 @@ static const struct bttv_format bttv_formats[] = {
 		.vshift   = 2,
 	},{
 		.name     = "raw scanlines",
-		.palette  = VIDEO_PALETTE_RAW,
 		.fourcc   = -1,
 		.btformat = BT848_COLOR_FMT_RAW,
 		.depth    = 8,
 		.flags    = FORMAT_FLAGS_RAW,
 	}
 };
-static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
+static const unsigned int FORMATS = ARRAY_SIZE(formats);
 
 /* ----------------------------------------------------------------------- */
 
@@ -798,7 +785,17 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
 
 
 };
-static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
+
+static const struct v4l2_queryctrl *ctrl_by_id(int id)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++)
+		if (bttv_ctls[i].id == id)
+			return bttv_ctls+i;
+
+	return NULL;
+}
 
 /* ----------------------------------------------------------------------- */
 /* resource management                                                     */
@@ -1255,16 +1252,6 @@ audio_input(struct bttv *btv, int input)
 }
 
 static void
-i2c_vidiocschan(struct bttv *btv)
-{
-	v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
-
-	bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
-	if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
-		bttv_tda9880_setnorm(btv,btv->tvnorm);
-}
-
-static void
 bttv_crop_calc_limits(struct bttv_crop *c)
 {
 	/* Scale factor min. 1:1, max. 16:1. Min. image size
@@ -1298,6 +1285,7 @@ static int
 set_tvnorm(struct bttv *btv, unsigned int norm)
 {
 	const struct bttv_tvnorm *tvnorm;
+	v4l2_std_id id;
 
 	if (norm < 0 || norm >= BTTV_TVNORMS)
 		return -EINVAL;
@@ -1334,6 +1322,9 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
 		bttv_tda9880_setnorm(btv,norm);
 		break;
 	}
+	id = tvnorm->v4l2_id;
+	bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
+
 	return 0;
 }
 
@@ -1359,7 +1350,6 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm)
 	audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
 		       TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
 	set_tvnorm(btv, norm);
-	i2c_vidiocschan(btv);
 }
 
 static void init_irqreg(struct bttv *btv)
@@ -1452,38 +1442,12 @@ static void bttv_reinit_bt848(struct bttv *btv)
 	set_input(btv, btv->input, btv->tvnorm);
 }
 
-static int get_control(struct bttv *btv, struct v4l2_control *c)
+static int bttv_g_ctrl(struct file *file, void *priv,
+					struct v4l2_control *c)
 {
-	struct video_audio va;
-	int i;
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-	for (i = 0; i < BTTV_CTLS; i++)
-		if (bttv_ctls[i].id == c->id)
-			break;
-	if (i == BTTV_CTLS)
-		return -EINVAL;
-	if (btv->audio_hook && i >= 4 && i <= 8) {
-		memset(&va,0,sizeof(va));
-		btv->audio_hook(btv,&va,0);
-		switch (c->id) {
-		case V4L2_CID_AUDIO_MUTE:
-			c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
-			break;
-		case V4L2_CID_AUDIO_VOLUME:
-			c->value = va.volume;
-			break;
-		case V4L2_CID_AUDIO_BALANCE:
-			c->value = va.balance;
-			break;
-		case V4L2_CID_AUDIO_BASS:
-			c->value = va.bass;
-			break;
-		case V4L2_CID_AUDIO_TREBLE:
-			c->value = va.treble;
-			break;
-		}
-		return 0;
-	}
 	switch (c->id) {
 	case V4L2_CID_BRIGHTNESS:
 		c->value = btv->bright;
@@ -1503,7 +1467,7 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_BASS:
 	case V4L2_CID_AUDIO_TREBLE:
-		bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
+		bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c);
 		break;
 
 	case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1545,67 +1509,44 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
 	return 0;
 }
 
-static int set_control(struct bttv *btv, struct v4l2_control *c)
+static int bttv_s_ctrl(struct file *file, void *f,
+					struct v4l2_control *c)
 {
-	struct video_audio va;
-	int i,val;
+	int err;
+	int val;
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-	for (i = 0; i < BTTV_CTLS; i++)
-		if (bttv_ctls[i].id == c->id)
-			break;
-	if (i == BTTV_CTLS)
-		return -EINVAL;
-	if (btv->audio_hook && i >= 4 && i <= 8) {
-		memset(&va,0,sizeof(va));
-		btv->audio_hook(btv,&va,0);
-		switch (c->id) {
-		case V4L2_CID_AUDIO_MUTE:
-			if (c->value) {
-				va.flags |= VIDEO_AUDIO_MUTE;
-				audio_mute(btv, 1);
-			} else {
-				va.flags &= ~VIDEO_AUDIO_MUTE;
-				audio_mute(btv, 0);
-			}
-			break;
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		case V4L2_CID_AUDIO_VOLUME:
-			va.volume = c->value;
-			break;
-		case V4L2_CID_AUDIO_BALANCE:
-			va.balance = c->value;
-			break;
-		case V4L2_CID_AUDIO_BASS:
-			va.bass = c->value;
-			break;
-		case V4L2_CID_AUDIO_TREBLE:
-			va.treble = c->value;
-			break;
-		}
-		btv->audio_hook(btv,&va,1);
-		return 0;
-	}
 	switch (c->id) {
 	case V4L2_CID_BRIGHTNESS:
-		bt848_bright(btv,c->value);
+		bt848_bright(btv, c->value);
 		break;
 	case V4L2_CID_HUE:
-		bt848_hue(btv,c->value);
+		bt848_hue(btv, c->value);
 		break;
 	case V4L2_CID_CONTRAST:
-		bt848_contrast(btv,c->value);
+		bt848_contrast(btv, c->value);
 		break;
 	case V4L2_CID_SATURATION:
-		bt848_sat(btv,c->value);
+		bt848_sat(btv, c->value);
 		break;
 	case V4L2_CID_AUDIO_MUTE:
 		audio_mute(btv, c->value);
 		/* fall through */
 	case V4L2_CID_AUDIO_VOLUME:
+		if (btv->volume_gpio)
+			btv->volume_gpio(btv, c->value);
+
+		bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
+		break;
 	case V4L2_CID_AUDIO_BALANCE:
 	case V4L2_CID_AUDIO_BASS:
 	case V4L2_CID_AUDIO_TREBLE:
-		bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
+		bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
 		break;
 
 	case V4L2_CID_PRIVATE_CHROMA_AGC:
@@ -1632,8 +1573,9 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
 		break;
 	case V4L2_CID_PRIVATE_AGC_CRUSH:
 		btv->opt_adc_crush = c->value;
-		btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
-			BT848_ADC);
+		btwrite(BT848_ADC_RESERVED |
+				(btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+				BT848_ADC);
 		break;
 	case V4L2_CID_PRIVATE_VCR_HACK:
 		btv->opt_vcr_hack = c->value;
@@ -1693,29 +1635,15 @@ static void bttv_field_count(struct bttv *btv)
 }
 
 static const struct bttv_format*
-format_by_palette(int palette)
-{
-	unsigned int i;
-
-	for (i = 0; i < BTTV_FORMATS; i++) {
-		if (-1 == bttv_formats[i].palette)
-			continue;
-		if (bttv_formats[i].palette == palette)
-			return bttv_formats+i;
-	}
-	return NULL;
-}
-
-static const struct bttv_format*
 format_by_fourcc(int fourcc)
 {
 	unsigned int i;
 
-	for (i = 0; i < BTTV_FORMATS; i++) {
-		if (-1 == bttv_formats[i].fourcc)
+	for (i = 0; i < FORMATS; i++) {
+		if (-1 == formats[i].fourcc)
 			continue;
-		if (bttv_formats[i].fourcc == fourcc)
-			return bttv_formats+i;
+		if (formats[i].fourcc == fourcc)
+			return formats+i;
 	}
 	return NULL;
 }
@@ -1733,7 +1661,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
 
 	dprintk("switch_overlay: enter [new=%p]\n",new);
 	if (new)
-		new->vb.state = STATE_DONE;
+		new->vb.state = VIDEOBUF_DONE;
 	spin_lock_irqsave(&btv->s_lock,flags);
 	old = btv->screen;
 	btv->screen = new;
@@ -1844,7 +1772,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
 	}
 
 	/* alloc risc memory */
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		redo_dma_risc = 1;
 		if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
 			goto fail;
@@ -1854,7 +1782,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
 		if (0 != (rc = bttv_buffer_risc(btv,buf)))
 			goto fail;
 
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	return 0;
 
  fail:
@@ -1893,7 +1821,7 @@ buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 	struct bttv_fh *fh = q->priv_data;
 	struct bttv    *btv = fh->btv;
 
-	buf->vb.state = STATE_QUEUED;
+	buf->vb.state = VIDEOBUF_QUEUED;
 	list_add_tail(&buf->vb.queue,&btv->capture);
 	if (!btv->curr.frame_irq) {
 		btv->loop_irq |= 1;
@@ -1916,374 +1844,234 @@ static struct videobuf_queue_ops bttv_video_qops = {
 	.buf_release  = buffer_release,
 };
 
-static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
+static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-	switch (cmd) {
-	case BTTV_VERSION:
-		return BTTV_VERSION_CODE;
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	unsigned int i;
+	int err;
 
-	/* ***  v4l1  *** ************************************************ */
-	case VIDIOCGFREQ:
-	{
-		unsigned long *freq = arg;
-		*freq = btv->freq;
-		return 0;
-	}
-	case VIDIOCSFREQ:
-	{
-		struct v4l2_frequency freq;
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		memset(&freq, 0, sizeof(freq));
-		freq.frequency = *(unsigned long *)arg;
-		mutex_lock(&btv->lock);
-		freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-		btv->freq = *(unsigned long *)arg;
-		bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);
-		if (btv->has_matchbox && btv->radio_user)
-			tea5757_set_freq(btv,*(unsigned long *)arg);
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
+	for (i = 0; i < BTTV_TVNORMS; i++)
+		if (*id & bttv_tvnorms[i].v4l2_id)
+			break;
+	if (i == BTTV_TVNORMS)
+		return -EINVAL;
 
-	case VIDIOCGTUNER:
-	{
-		struct video_tuner *v = arg;
+	mutex_lock(&btv->lock);
+	set_tvnorm(btv, i);
+	mutex_unlock(&btv->lock);
 
-		if (UNSET == bttv_tvcards[btv->c.type].tuner)
-			return -EINVAL;
-		if (v->tuner) /* Only tuner 0 */
-			return -EINVAL;
-		strcpy(v->name, "Television");
-		v->rangelow  = 0;
-		v->rangehigh = 0x7FFFFFFF;
-		v->flags     = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
-		v->mode      = btv->tvnorm;
-		v->signal    = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
-		bttv_call_i2c_clients(btv,cmd,v);
-		return 0;
-	}
-	case VIDIOCSTUNER:
-	{
-		struct video_tuner *v = arg;
+	return 0;
+}
 
-		if (v->tuner) /* Only tuner 0 */
-			return -EINVAL;
-		if (v->mode >= BTTV_TVNORMS)
-			return -EINVAL;
+static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-		mutex_lock(&btv->lock);
-		set_tvnorm(btv,v->mode);
-		bttv_call_i2c_clients(btv,cmd,v);
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
+	if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
+		*id = V4L2_STD_625_50;
+	else
+		*id = V4L2_STD_525_60;
+	return 0;
+}
 
-	case VIDIOCGCHAN:
-	{
-		struct video_channel *v = arg;
-		unsigned int channel = v->channel;
+static int bttv_enum_input(struct file *file, void *priv,
+					struct v4l2_input *i)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	unsigned int n;
 
-		if (channel >= bttv_tvcards[btv->c.type].video_inputs)
-			return -EINVAL;
-		v->tuners=0;
-		v->flags = VIDEO_VC_AUDIO;
-		v->type = VIDEO_TYPE_CAMERA;
-		v->norm = btv->tvnorm;
-		if (channel == bttv_tvcards[btv->c.type].tuner)  {
-			strcpy(v->name,"Television");
-			v->flags|=VIDEO_VC_TUNER;
-			v->type=VIDEO_TYPE_TV;
-			v->tuners=1;
-		} else if (channel == btv->svhs) {
-			strcpy(v->name,"S-Video");
-		} else {
-			sprintf(v->name,"Composite%d",channel);
-		}
-		return 0;
-	}
-	case VIDIOCSCHAN:
-	{
-		struct video_channel *v = arg;
-		unsigned int channel = v->channel;
+	n = i->index;
 
-		if (channel >= bttv_tvcards[btv->c.type].video_inputs)
-			return -EINVAL;
-		if (v->norm >= BTTV_TVNORMS)
-			return -EINVAL;
+	if (n >= bttv_tvcards[btv->c.type].video_inputs)
+		return -EINVAL;
 
-		mutex_lock(&btv->lock);
-		if (channel == btv->input &&
-		    v->norm == btv->tvnorm) {
-			/* nothing to do */
-			mutex_unlock(&btv->lock);
-			return 0;
-		}
+	memset(i, 0, sizeof(*i));
 
-		set_input(btv, v->channel, v->norm);
-		mutex_unlock(&btv->lock);
-		return 0;
+	i->index    = n;
+	i->type     = V4L2_INPUT_TYPE_CAMERA;
+	i->audioset = 1;
+
+	if (i->index == bttv_tvcards[btv->c.type].tuner) {
+		sprintf(i->name, "Television");
+		i->type  = V4L2_INPUT_TYPE_TUNER;
+		i->tuner = 0;
+	} else if (i->index == btv->svhs) {
+		sprintf(i->name, "S-Video");
+	} else {
+		sprintf(i->name, "Composite%d", i->index);
 	}
 
-	case VIDIOCGAUDIO:
-	{
-		struct video_audio *v = arg;
+	if (i->index == btv->input) {
+		__u32 dstatus = btread(BT848_DSTATUS);
+		if (0 == (dstatus & BT848_DSTATUS_PRES))
+			i->status |= V4L2_IN_ST_NO_SIGNAL;
+		if (0 == (dstatus & BT848_DSTATUS_HLOC))
+			i->status |= V4L2_IN_ST_NO_H_LOCK;
+	}
 
-		memset(v,0,sizeof(*v));
-		strcpy(v->name,"Television");
-		v->flags |= VIDEO_AUDIO_MUTABLE;
-		v->mode  = VIDEO_SOUND_MONO;
+	for (n = 0; n < BTTV_TVNORMS; n++)
+		i->std |= bttv_tvnorms[n].v4l2_id;
 
-		mutex_lock(&btv->lock);
-		bttv_call_i2c_clients(btv,cmd,v);
+	return 0;
+}
 
-		/* card specific hooks */
-		if (btv->audio_hook)
-			btv->audio_hook(btv,v,0);
+static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
-	case VIDIOCSAUDIO:
-	{
-		struct video_audio *v = arg;
-		unsigned int audio = v->audio;
+	*i = btv->input;
+	return 0;
+}
 
-		if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
-			return -EINVAL;
+static int bttv_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
 
-		mutex_lock(&btv->lock);
-		audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
-		bttv_call_i2c_clients(btv,cmd,v);
+	int err;
 
-		/* card specific hooks */
-		if (btv->audio_hook)
-			btv->audio_hook(btv,v,1);
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
+	if (i > bttv_tvcards[btv->c.type].video_inputs)
+		return -EINVAL;
 
-	/* ***  v4l2  *** ************************************************ */
-	case VIDIOC_ENUMSTD:
-	{
-		struct v4l2_standard *e = arg;
-		unsigned int index = e->index;
+	mutex_lock(&btv->lock);
+	set_input(btv, i, btv->tvnorm);
+	mutex_unlock(&btv->lock);
+	return 0;
+}
 
-		if (index >= BTTV_TVNORMS)
-			return -EINVAL;
-		v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
-					 bttv_tvnorms[e->index].name);
-		e->index = index;
-		return 0;
-	}
-	case VIDIOC_G_STD:
-	{
-		v4l2_std_id *id = arg;
-		*id = bttv_tvnorms[btv->tvnorm].v4l2_id;
-		return 0;
-	}
-	case VIDIOC_S_STD:
-	{
-		v4l2_std_id *id = arg;
-		unsigned int i;
+static int bttv_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	int err;
 
-		for (i = 0; i < BTTV_TVNORMS; i++)
-			if (*id & bttv_tvnorms[i].v4l2_id)
-				break;
-		if (i == BTTV_TVNORMS)
-			return -EINVAL;
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		mutex_lock(&btv->lock);
-		set_tvnorm(btv,i);
-		i2c_vidiocschan(btv);
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
-	case VIDIOC_QUERYSTD:
-	{
-		v4l2_std_id *id = arg;
+	if (UNSET == bttv_tvcards[btv->c.type].tuner)
+		return -EINVAL;
 
-		if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
-			*id = V4L2_STD_625_50;
-		else
-			*id = V4L2_STD_525_60;
-		return 0;
-	}
+	if (0 != t->index)
+		return -EINVAL;
 
-	case VIDIOC_ENUMINPUT:
-	{
-		struct v4l2_input *i = arg;
-		unsigned int n;
+	mutex_lock(&btv->lock);
+	bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
 
-		n = i->index;
-		if (n >= bttv_tvcards[btv->c.type].video_inputs)
-			return -EINVAL;
-		memset(i,0,sizeof(*i));
-		i->index    = n;
-		i->type     = V4L2_INPUT_TYPE_CAMERA;
-		i->audioset = 1;
-		if (i->index == bttv_tvcards[btv->c.type].tuner) {
-			sprintf(i->name, "Television");
-			i->type  = V4L2_INPUT_TYPE_TUNER;
-			i->tuner = 0;
-		} else if (i->index == btv->svhs) {
-			sprintf(i->name, "S-Video");
-		} else {
-			sprintf(i->name,"Composite%d",i->index);
-		}
-		if (i->index == btv->input) {
-			__u32 dstatus = btread(BT848_DSTATUS);
-			if (0 == (dstatus & BT848_DSTATUS_PRES))
-				i->status |= V4L2_IN_ST_NO_SIGNAL;
-			if (0 == (dstatus & BT848_DSTATUS_HLOC))
-				i->status |= V4L2_IN_ST_NO_H_LOCK;
-		}
-		for (n = 0; n < BTTV_TVNORMS; n++)
-			i->std |= bttv_tvnorms[n].v4l2_id;
-		return 0;
-	}
-	case VIDIOC_G_INPUT:
-	{
-		int *i = arg;
-		*i = btv->input;
-		return 0;
-	}
-	case VIDIOC_S_INPUT:
-	{
-		unsigned int *i = arg;
+	if (btv->audio_mode_gpio)
+		btv->audio_mode_gpio(btv, t, 1);
 
-		if (*i > bttv_tvcards[btv->c.type].video_inputs)
-			return -EINVAL;
-		mutex_lock(&btv->lock);
-		set_input(btv, *i, btv->tvnorm);
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
+	mutex_unlock(&btv->lock);
 
-	case VIDIOC_G_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
+	return 0;
+}
 
-		if (UNSET == bttv_tvcards[btv->c.type].tuner)
-			return -EINVAL;
-		if (0 != t->index)
-			return -EINVAL;
-		mutex_lock(&btv->lock);
-		memset(t,0,sizeof(*t));
-		t->rxsubchans = V4L2_TUNER_SUB_MONO;
-		bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
-		strcpy(t->name, "Television");
-		t->capability = V4L2_TUNER_CAP_NORM;
-		t->type       = V4L2_TUNER_ANALOG_TV;
-		if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
-			t->signal = 0xffff;
-
-		if (btv->audio_hook) {
-			/* Hmmm ... */
-			struct video_audio va;
-			memset(&va, 0, sizeof(struct video_audio));
-			btv->audio_hook(btv,&va,0);
-			t->audmode    = V4L2_TUNER_MODE_MONO;
-			t->rxsubchans = V4L2_TUNER_SUB_MONO;
-			if(va.mode & VIDEO_SOUND_STEREO) {
-				t->audmode    = V4L2_TUNER_MODE_STEREO;
-				t->rxsubchans = V4L2_TUNER_SUB_STEREO;
-			}
-			if(va.mode & VIDEO_SOUND_LANG2) {
-				t->audmode    = V4L2_TUNER_MODE_LANG1;
-				t->rxsubchans = V4L2_TUNER_SUB_LANG1
-					| V4L2_TUNER_SUB_LANG2;
-			}
-		}
-		/* FIXME: fill capability+audmode */
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
-	case VIDIOC_S_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
+static int bttv_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	int err;
 
-		if (UNSET == bttv_tvcards[btv->c.type].tuner)
-			return -EINVAL;
-		if (0 != t->index)
-			return -EINVAL;
-		mutex_lock(&btv->lock);
-		bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
-		if (btv->audio_hook) {
-			struct video_audio va;
-			memset(&va, 0, sizeof(struct video_audio));
-			if (t->audmode == V4L2_TUNER_MODE_MONO)
-				va.mode = VIDEO_SOUND_MONO;
-			else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
-				 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
-				va.mode = VIDEO_SOUND_STEREO;
-			else if (t->audmode == V4L2_TUNER_MODE_LANG1)
-				va.mode = VIDEO_SOUND_LANG1;
-			else if (t->audmode == V4L2_TUNER_MODE_LANG2)
-				va.mode = VIDEO_SOUND_LANG2;
-			btv->audio_hook(btv,&va,1);
-		}
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-	case VIDIOC_G_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
+	f->type = V4L2_TUNER_ANALOG_TV;
+	f->frequency = btv->freq;
 
-		memset(f,0,sizeof(*f));
-		f->type = V4L2_TUNER_ANALOG_TV;
-		f->frequency = btv->freq;
-		return 0;
-	}
-	case VIDIOC_S_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
+	return 0;
+}
+
+static int bttv_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct bttv_fh *fh  = priv;
+	struct bttv *btv = fh->btv;
+	int err;
+
+	err = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != err)
+		return err;
+
+	if (unlikely(f->tuner != 0))
+		return -EINVAL;
+	if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
+		return -EINVAL;
+	mutex_lock(&btv->lock);
+	btv->freq = f->frequency;
+	bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f);
+	if (btv->has_matchbox && btv->radio_user)
+		tea5757_set_freq(btv, btv->freq);
+	mutex_unlock(&btv->lock);
+	return 0;
+}
+
+static int bttv_log_status(struct file *file, void *f)
+{
+	struct bttv_fh *fh  = f;
+	struct bttv *btv = fh->btv;
+
+	printk(KERN_INFO "bttv%d: ========  START STATUS CARD #%d  ========\n",
+			btv->c.nr, btv->c.nr);
+	bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
+	printk(KERN_INFO "bttv%d: ========  END STATUS CARD   #%d  ========\n",
+			btv->c.nr, btv->c.nr);
+	return 0;
+}
 
-		if (unlikely(f->tuner != 0))
-			return -EINVAL;
-		if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
-			return -EINVAL;
-		mutex_lock(&btv->lock);
-		btv->freq = f->frequency;
-		bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
-		if (btv->has_matchbox && btv->radio_user)
-			tea5757_set_freq(btv,btv->freq);
-		mutex_unlock(&btv->lock);
-		return 0;
-	}
-	case VIDIOC_LOG_STATUS:
-	{
-		printk(KERN_INFO "bttv%d: =================  START STATUS CARD #%d  =================\n", btv->c.nr, btv->c.nr);
-		bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
-		printk(KERN_INFO "bttv%d: ==================  END STATUS CARD #%d  ==================\n", btv->c.nr, btv->c.nr);
-		return 0;
-	}
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	case VIDIOC_DBG_G_REGISTER:
-	case VIDIOC_DBG_S_REGISTER:
-	{
-		struct v4l2_register *reg = arg;
-		if (!capable(CAP_SYS_ADMIN))
-			return -EPERM;
-		if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
-			return -EINVAL;
-		/* bt848 has a 12-bit register space */
-		reg->reg &= 0xfff;
-		if (cmd == VIDIOC_DBG_G_REGISTER)
-			reg->val = btread(reg->reg);
-		else
-			btwrite(reg->val, reg->reg);
-		return 0;
-	}
-#endif
+static int bttv_g_register(struct file *file, void *f,
+					struct v4l2_register *reg)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-	default:
-		return -ENOIOCTLCMD;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return -EINVAL;
+
+	/* bt848 has a 12-bit register space */
+	reg->reg &= 0xfff;
+	reg->val = btread(reg->reg);
+
+	return 0;
+}
+
+static int bttv_s_register(struct file *file, void *f,
+					struct v4l2_register *reg)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return -EINVAL;
+
+	/* bt848 has a 12-bit register space */
+	reg->reg &= 0xfff;
+	btwrite(reg->val, reg->reg);
 
-	}
 	return 0;
 }
+#endif
 
 /* Given cropping boundaries b and the scaled width and height of a
    single field or frame, which must not exceed hardware limits, this
@@ -2659,983 +2447,681 @@ pix_format_set_size     (struct v4l2_pix_format *       f,
 	}
 }
 
-static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+static int bttv_g_fmt_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
 {
-	switch (f->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
-		pix_format_set_size (&f->fmt.pix, fh->fmt,
-				     fh->width, fh->height);
-		f->fmt.pix.field        = fh->cap.field;
-		f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-		return 0;
-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-		memset(&f->fmt.win,0,sizeof(struct v4l2_window));
-		f->fmt.win.w     = fh->ov.w;
-		f->fmt.win.field = fh->ov.field;
-		return 0;
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		bttv_vbi_get_fmt(fh, &f->fmt.vbi);
-		return 0;
-	default:
-		return -EINVAL;
-	}
+	struct bttv_fh *fh  = priv;
+
+	pix_format_set_size(&f->fmt.pix, fh->fmt,
+				fh->width, fh->height);
+	f->fmt.pix.field        = fh->cap.field;
+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+
+	return 0;
 }
 
-static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
-			struct v4l2_format *f, int adjust_crop)
+static int bttv_g_fmt_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
 {
-	switch (f->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-	{
-		const struct bttv_format *fmt;
-		enum v4l2_field field;
-		__s32 width, height;
-		int rc;
+	struct bttv_fh *fh  = priv;
 
-		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-		if (NULL == fmt)
-			return -EINVAL;
+	f->fmt.win.w     = fh->ov.w;
+	f->fmt.win.field = fh->ov.field;
 
-		field = f->fmt.pix.field;
-		if (V4L2_FIELD_ANY == field) {
-			__s32 height2;
+	return 0;
+}
 
-			height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
-			field = (f->fmt.pix.height > height2)
-				? V4L2_FIELD_INTERLACED
-				: V4L2_FIELD_BOTTOM;
-		}
-		if (V4L2_FIELD_SEQ_BT == field)
-			field = V4L2_FIELD_SEQ_TB;
-		switch (field) {
-		case V4L2_FIELD_TOP:
-		case V4L2_FIELD_BOTTOM:
-		case V4L2_FIELD_ALTERNATE:
-		case V4L2_FIELD_INTERLACED:
-			break;
-		case V4L2_FIELD_SEQ_TB:
-			if (fmt->flags & FORMAT_FLAGS_PLANAR)
-				return -EINVAL;
-			break;
-		default:
-			return -EINVAL;
-		}
+static int bttv_try_fmt_cap(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	const struct bttv_format *fmt;
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	enum v4l2_field field;
+	__s32 width, height;
+	int rc;
 
-		width = f->fmt.pix.width;
-		height = f->fmt.pix.height;
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
 
-		rc = limit_scaled_size(fh, &width, &height, field,
-				       /* width_mask: 4 pixels */ ~3,
-				       /* width_bias: nearest */ 2,
-				       /* adjust_size */ 1,
-				       adjust_crop);
-		if (0 != rc)
-			return rc;
+	field = f->fmt.pix.field;
 
-		/* update data for the application */
-		f->fmt.pix.field = field;
-		pix_format_set_size(&f->fmt.pix, fmt, width, height);
+	if (V4L2_FIELD_ANY == field) {
+		__s32 height2;
 
-		return 0;
+		height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+		field = (f->fmt.pix.height > height2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_BOTTOM;
 	}
-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-		return verify_window(fh, &f->fmt.win,
-				     /* adjust_size */ 1,
-				     /* adjust_crop */ 0);
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
+
+	if (V4L2_FIELD_SEQ_BT == field)
+		field = V4L2_FIELD_SEQ_TB;
+
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+	case V4L2_FIELD_ALTERNATE:
+	case V4L2_FIELD_INTERLACED:
+		break;
+	case V4L2_FIELD_SEQ_TB:
+		if (fmt->flags & FORMAT_FLAGS_PLANAR)
+			return -EINVAL;
+		break;
 	default:
 		return -EINVAL;
 	}
+
+	width = f->fmt.pix.width;
+	height = f->fmt.pix.height;
+
+	rc = limit_scaled_size(fh, &width, &height, field,
+			       /* width_mask: 4 pixels */ ~3,
+			       /* width_bias: nearest */ 2,
+			       /* adjust_size */ 1,
+			       /* adjust_crop */ 0);
+	if (0 != rc)
+		return rc;
+
+	/* update data for the application */
+	f->fmt.pix.field = field;
+	pix_format_set_size(&f->fmt.pix, fmt, width, height);
+
+	return 0;
 }
 
-static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
-		      struct v4l2_format *f)
+static int bttv_try_fmt_overlay(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	struct bttv_fh *fh = priv;
+
+	return verify_window(fh, &f->fmt.win,
+			/* adjust_size */ 1,
+			/* adjust_crop */ 0);
+}
+
+static int bttv_s_fmt_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
 {
 	int retval;
+	const struct bttv_format *fmt;
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	__s32 width, height;
+	enum v4l2_field field;
 
-	switch (f->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-	{
-		const struct bttv_format *fmt;
+	retval = bttv_switch_type(fh, f->type);
+	if (0 != retval)
+		return retval;
 
-		retval = bttv_switch_type(fh,f->type);
-		if (0 != retval)
-			return retval;
-		retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
-		if (0 != retval)
-			return retval;
-		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	retval = bttv_try_fmt_cap(file, priv, f);
+	if (0 != retval)
+		return retval;
 
-		/* update our state informations */
-		mutex_lock(&fh->cap.lock);
-		fh->fmt              = fmt;
-		fh->cap.field        = f->fmt.pix.field;
-		fh->cap.last         = V4L2_FIELD_NONE;
-		fh->width            = f->fmt.pix.width;
-		fh->height           = f->fmt.pix.height;
-		btv->init.fmt        = fmt;
-		btv->init.width      = f->fmt.pix.width;
-		btv->init.height     = f->fmt.pix.height;
-		mutex_unlock(&fh->cap.lock);
+	width = f->fmt.pix.width;
+	height = f->fmt.pix.height;
+	field = f->fmt.pix.field;
 
-		return 0;
-	}
-	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-		if (no_overlay > 0) {
-			printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
-			return -EINVAL;
-		}
-		return setup_window(fh, btv, &f->fmt.win, 1);
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		retval = bttv_switch_type(fh,f->type);
-		if (0 != retval)
-			return retval;
-		return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
-	default:
-		return -EINVAL;
-	}
-}
+	retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field,
+			       /* width_mask: 4 pixels */ ~3,
+			       /* width_bias: nearest */ 2,
+			       /* adjust_size */ 1,
+			       /* adjust_crop */ 1);
+	if (0 != retval)
+		return retval;
 
-static int bttv_do_ioctl(struct inode *inode, struct file *file,
-			 unsigned int cmd, void *arg)
-{
-	struct bttv_fh *fh  = file->private_data;
-	struct bttv    *btv = fh->btv;
-	unsigned long flags;
-	int retval = 0;
+	f->fmt.pix.field = field;
 
-	if (bttv_debug > 1)
-		v4l_print_ioctl(btv->c.name, cmd);
-
-	if (btv->errors)
-		bttv_reinit_bt848(btv);
-
-	switch (cmd) {
-	case VIDIOCSFREQ:
-	case VIDIOCSTUNER:
-	case VIDIOCSCHAN:
-	case VIDIOC_S_CTRL:
-	case VIDIOC_S_STD:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_S_FREQUENCY:
-		retval = v4l2_prio_check(&btv->prio,&fh->prio);
-		if (0 != retval)
-			return retval;
-	};
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 
-	switch (cmd) {
+	/* update our state informations */
+	mutex_lock(&fh->cap.lock);
+	fh->fmt              = fmt;
+	fh->cap.field        = f->fmt.pix.field;
+	fh->cap.last         = V4L2_FIELD_NONE;
+	fh->width            = f->fmt.pix.width;
+	fh->height           = f->fmt.pix.height;
+	btv->init.fmt        = fmt;
+	btv->init.width      = f->fmt.pix.width;
+	btv->init.height     = f->fmt.pix.height;
+	mutex_unlock(&fh->cap.lock);
 
-	/* ***  v4l1  *** ************************************************ */
-	case VIDIOCGCAP:
-	{
-		struct video_capability *cap = arg;
+	return 0;
+}
 
-		memset(cap,0,sizeof(*cap));
-		strcpy(cap->name,btv->video_dev->name);
-		if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
-			/* vbi */
-			cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
-		} else {
-			/* others */
-			cap->type = VID_TYPE_CAPTURE|
-				VID_TYPE_TUNER|
-				VID_TYPE_CLIPPING|
-				VID_TYPE_SCALES;
-			if (no_overlay <= 0)
-				cap->type |= VID_TYPE_OVERLAY;
-
-			cap->maxwidth  = bttv_tvnorms[btv->tvnorm].swidth;
-			cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
-			cap->minwidth  = 48;
-			cap->minheight = 32;
-		}
-		cap->channels  = bttv_tvcards[btv->c.type].video_inputs;
-		cap->audios    = bttv_tvcards[btv->c.type].audio_inputs;
-		return 0;
-	}
+static int bttv_s_fmt_overlay(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-	case VIDIOCGPICT:
-	{
-		struct video_picture *pic = arg;
-
-		memset(pic,0,sizeof(*pic));
-		pic->brightness = btv->bright;
-		pic->contrast   = btv->contrast;
-		pic->hue        = btv->hue;
-		pic->colour     = btv->saturation;
-		if (fh->fmt) {
-			pic->depth   = fh->fmt->depth;
-			pic->palette = fh->fmt->palette;
-		}
-		return 0;
+	if (no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
 	}
-	case VIDIOCSPICT:
-	{
-		struct video_picture *pic = arg;
-		const struct bttv_format *fmt;
 
-		fmt = format_by_palette(pic->palette);
-		if (NULL == fmt)
-			return -EINVAL;
-		mutex_lock(&fh->cap.lock);
-		if (fmt->flags & FORMAT_FLAGS_RAW) {
-			/* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
-			   RAW_LINES * 2. F1 is stored at offset 0, F2
-			   at buffer size / 2. */
-			fh->width = RAW_BPL;
-			fh->height = gbufsize / RAW_BPL;
-			btv->init.width  = RAW_BPL;
-			btv->init.height = gbufsize / RAW_BPL;
-		}
-		fh->ovfmt   = fmt;
-		fh->fmt     = fmt;
-		btv->init.ovfmt   = fmt;
-		btv->init.fmt     = fmt;
-		if (bigendian) {
-			/* dirty hack time:  swap bytes for overlay if the
-			   display adaptor is big endian (insmod option) */
-			if (fmt->palette == VIDEO_PALETTE_RGB555 ||
-			    fmt->palette == VIDEO_PALETTE_RGB565 ||
-			    fmt->palette == VIDEO_PALETTE_RGB32) {
-				fh->ovfmt = fmt+1;
-			}
-		}
-		bt848_bright(btv,pic->brightness);
-		bt848_contrast(btv,pic->contrast);
-		bt848_hue(btv,pic->hue);
-		bt848_sat(btv,pic->colour);
+	return setup_window(fh, btv, &f->fmt.win, 1);
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+	int retval;
+	unsigned int i;
+	struct bttv_fh *fh = priv;
+
+	mutex_lock(&fh->cap.lock);
+	retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
+				     V4L2_MEMORY_MMAP);
+	if (retval < 0) {
 		mutex_unlock(&fh->cap.lock);
-		return 0;
+		return retval;
 	}
 
-	case VIDIOCGWIN:
-	{
-		struct video_window *win = arg;
+	gbuffers = retval;
+	memset(mbuf, 0, sizeof(*mbuf));
+	mbuf->frames = gbuffers;
+	mbuf->size   = gbuffers * gbufsize;
 
-		memset(win,0,sizeof(*win));
-		win->x      = fh->ov.w.left;
-		win->y      = fh->ov.w.top;
-		win->width  = fh->ov.w.width;
-		win->height = fh->ov.w.height;
-		return 0;
-	}
-	case VIDIOCSWIN:
-	{
-		struct video_window *win = arg;
-		struct v4l2_window w2;
+	for (i = 0; i < gbuffers; i++)
+		mbuf->offsets[i] = i * gbufsize;
 
-		if (no_overlay > 0) {
-			printk ("VIDIOCSWIN: no_overlay\n");
-			return -EINVAL;
-		}
+	mutex_unlock(&fh->cap.lock);
+	return 0;
+}
+#endif
 
-		w2.field = V4L2_FIELD_ANY;
-		w2.w.left    = win->x;
-		w2.w.top     = win->y;
-		w2.w.width   = win->width;
-		w2.w.height  = win->height;
-		w2.clipcount = win->clipcount;
-		w2.clips     = (struct v4l2_clip __user *)win->clips;
-		retval = setup_window(fh, btv, &w2, 0);
-		if (0 == retval) {
-			/* on v4l1 this ioctl affects the read() size too */
-			fh->width  = fh->ov.w.width;
-			fh->height = fh->ov.w.height;
-			btv->init.width  = fh->ov.w.width;
-			btv->init.height = fh->ov.w.height;
-		}
-		return retval;
-	}
+static int bttv_querycap(struct file *file, void  *priv,
+				struct v4l2_capability *cap)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-	case VIDIOCGFBUF:
-	{
-		struct video_buffer *fbuf = arg;
-
-		fbuf->base          = btv->fbuf.base;
-		fbuf->width         = btv->fbuf.fmt.width;
-		fbuf->height        = btv->fbuf.fmt.height;
-		fbuf->bytesperline  = btv->fbuf.fmt.bytesperline;
-		if (fh->ovfmt)
-			fbuf->depth = fh->ovfmt->depth;
-		else {
-			if (fbuf->width)
-				fbuf->depth   = ((fbuf->bytesperline<<3)
-						  + (fbuf->width-1) )
-						  /fbuf->width;
-			else
-				fbuf->depth = 0;
-		}
-		return 0;
-	}
-	case VIDIOCSFBUF:
-	{
-		struct video_buffer *fbuf = arg;
-		const struct bttv_format *fmt;
-		unsigned long end;
-
-		if(!capable(CAP_SYS_ADMIN) &&
-		   !capable(CAP_SYS_RAWIO))
-			return -EPERM;
-		end = (unsigned long)fbuf->base +
-			fbuf->height * fbuf->bytesperline;
-		mutex_lock(&fh->cap.lock);
-		retval = -EINVAL;
+	if (0 == v4l2)
+		return -EINVAL;
 
-		switch (fbuf->depth) {
-		case 8:
-			fmt = format_by_palette(VIDEO_PALETTE_HI240);
-			break;
-		case 16:
-			fmt = format_by_palette(VIDEO_PALETTE_RGB565);
-			break;
-		case 24:
-			fmt = format_by_palette(VIDEO_PALETTE_RGB24);
-			break;
-		case 32:
-			fmt = format_by_palette(VIDEO_PALETTE_RGB32);
-			break;
-		case 15:
-			fbuf->depth = 16;
-			fmt = format_by_palette(VIDEO_PALETTE_RGB555);
-			break;
-		default:
-			fmt = NULL;
-			break;
-		}
-		if (NULL == fmt)
-			goto fh_unlock_and_return;
-
-		fh->ovfmt = fmt;
-		fh->fmt   = fmt;
-		btv->init.ovfmt = fmt;
-		btv->init.fmt   = fmt;
-		btv->fbuf.base             = fbuf->base;
-		btv->fbuf.fmt.width        = fbuf->width;
-		btv->fbuf.fmt.height       = fbuf->height;
-		if (fbuf->bytesperline)
-			btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
-		else
-			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
-		mutex_unlock(&fh->cap.lock);
-		return 0;
-	}
+	strlcpy(cap->driver, "bttv", sizeof(cap->driver));
+	strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+		 "PCI:%s", pci_name(btv->c.pci));
+	cap->version = BTTV_VERSION_CODE;
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_VBI_CAPTURE |
+		V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING;
+	if (no_overlay <= 0)
+		cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+
+	if (bttv_tvcards[btv->c.type].tuner != UNSET &&
+	    bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
+		cap->capabilities |= V4L2_CAP_TUNER;
+	return 0;
+}
 
-	case VIDIOCCAPTURE:
-	case VIDIOC_OVERLAY:
-	{
-		struct bttv_buffer *new;
-		int *on = arg;
+static int bttv_enum_fmt_vbi(struct file *file, void  *priv,
+				struct v4l2_fmtdesc *f)
+{
+	if (0 != f->index)
+		return -EINVAL;
 
-		if (*on) {
-			/* verify args */
-			if (NULL == btv->fbuf.base)
-				return -EINVAL;
-			if (!fh->ov.setup_ok) {
-				dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
-				return -EINVAL;
-			}
-		}
+	f->pixelformat = V4L2_PIX_FMT_GREY;
+	strcpy(f->description, "vbi data");
 
-		if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
-			return -EBUSY;
+	return 0;
+}
 
-		mutex_lock(&fh->cap.lock);
-		if (*on) {
-			fh->ov.tvnorm = btv->tvnorm;
-			new = videobuf_pci_alloc(sizeof(*new));
-			new->crop = btv->crop[!!fh->do_crop].rect;
-			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
-		} else {
-			new = NULL;
-		}
+static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)
+{
+	int index = -1, i;
 
-		/* switch over */
-		retval = bttv_switch_overlay(btv,fh,new);
-		mutex_unlock(&fh->cap.lock);
-		return retval;
+	for (i = 0; i < FORMATS; i++) {
+		if (formats[i].fourcc != -1)
+			index++;
+		if ((unsigned int)index == f->index)
+			break;
 	}
+	if (FORMATS == i)
+		return -EINVAL;
 
-	case VIDIOCGMBUF:
-	{
-		struct video_mbuf *mbuf = arg;
-		unsigned int i;
+	f->pixelformat = formats[i].fourcc;
+	strlcpy(f->description, formats[i].name, sizeof(f->description));
 
-		retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
-					     V4L2_MEMORY_MMAP);
-		if (retval < 0)
-			return retval;
+	return i;
+}
 
-		gbuffers = retval;
-		memset(mbuf,0,sizeof(*mbuf));
-		mbuf->frames = gbuffers;
-		mbuf->size   = gbuffers * gbufsize;
-		for (i = 0; i < gbuffers; i++)
-			mbuf->offsets[i] = i * gbufsize;
-		return 0;
-	}
-	case VIDIOCMCAPTURE:
-	{
-		struct video_mmap *vm = arg;
-		struct bttv_buffer *buf;
-		enum v4l2_field field;
-		__s32 height2;
-		int res;
+static int bttv_enum_fmt_cap(struct file *file, void  *priv,
+				struct v4l2_fmtdesc *f)
+{
+	int rc = bttv_enum_fmt_cap_ovr(f);
 
-		if (vm->frame >= VIDEO_MAX_FRAME)
-			return -EINVAL;
+	if (rc < 0)
+		return rc;
 
-		res = bttv_resource(fh);
-		if (!check_alloc_btres(btv, fh, res))
-			return -EBUSY;
+	return 0;
+}
 
-		mutex_lock(&fh->cap.lock);
-		retval = -EINVAL;
-		buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
-		if (NULL == buf)
-			goto fh_unlock_and_return;
-		if (0 == buf->vb.baddr)
-			goto fh_unlock_and_return;
-		if (buf->vb.state == STATE_QUEUED ||
-		    buf->vb.state == STATE_ACTIVE)
-			goto fh_unlock_and_return;
+static int bttv_enum_fmt_overlay(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	int rc;
 
-		height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
-		field = (vm->height > height2)
-			? V4L2_FIELD_INTERLACED
-			: V4L2_FIELD_BOTTOM;
-		retval = bttv_prepare_buffer(&fh->cap,btv,buf,
-					     format_by_palette(vm->format),
-					     vm->width,vm->height,field);
-		if (0 != retval)
-			goto fh_unlock_and_return;
-		btv->init.width = vm->width;
-		btv->init.height = vm->height;
-		spin_lock_irqsave(&btv->s_lock,flags);
-		buffer_queue(&fh->cap,&buf->vb);
-		spin_unlock_irqrestore(&btv->s_lock,flags);
-		mutex_unlock(&fh->cap.lock);
-		return 0;
+	if (no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
 	}
-	case VIDIOCSYNC:
-	{
-		int *frame = arg;
-		struct bttv_buffer *buf;
 
-		if (*frame >= VIDEO_MAX_FRAME)
-			return -EINVAL;
+	rc = bttv_enum_fmt_cap_ovr(f);
 
-		mutex_lock(&fh->cap.lock);
-		retval = -EINVAL;
-		buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
-		if (NULL == buf)
-			goto fh_unlock_and_return;
-		retval = videobuf_waiton(&buf->vb,0,1);
-		if (0 != retval)
-			goto fh_unlock_and_return;
-		switch (buf->vb.state) {
-		case STATE_ERROR:
-			retval = -EIO;
-			/* fall through */
-		case STATE_DONE:
-		{
-			struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-			videobuf_dma_sync(&fh->cap,dma);
-			bttv_dma_free(&fh->cap,btv,buf);
-			break;
-		}
-		default:
-			retval = -EINVAL;
-			break;
-		}
-		mutex_unlock(&fh->cap.lock);
-		return retval;
-	}
+	if (rc < 0)
+		return rc;
 
-	case VIDIOCGVBIFMT:
-		if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
-			retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-			if (0 != retval)
-				return retval;
-		}
+	if (!(formats[rc].flags & FORMAT_FLAGS_PACKED))
+		return -EINVAL;
 
-		/* fall through */
+	return 0;
+}
 
-	case VIDIOCSVBIFMT:
-		return v4l_compat_translate_ioctl(inode, file, cmd,
-						  arg, bttv_do_ioctl);
-
-	case BTTV_VERSION:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGTUNER:
-	case VIDIOCSTUNER:
-	case VIDIOCGCHAN:
-	case VIDIOCSCHAN:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-		return bttv_common_ioctls(btv,cmd,arg);
-
-	/* ***  v4l2  *** ************************************************ */
-	case VIDIOC_QUERYCAP:
-	{
-		struct v4l2_capability *cap = arg;
+static int bttv_g_fbuf(struct file *file, void *f,
+				struct v4l2_framebuffer *fb)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-		if (0 == v4l2)
-			return -EINVAL;
-		memset(cap, 0, sizeof (*cap));
-		strlcpy(cap->driver, "bttv", sizeof (cap->driver));
-		strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
-		snprintf(cap->bus_info, sizeof (cap->bus_info),
-			 "PCI:%s", pci_name(btv->c.pci));
-		cap->version = BTTV_VERSION_CODE;
-		cap->capabilities =
-			V4L2_CAP_VIDEO_CAPTURE |
-			V4L2_CAP_VBI_CAPTURE |
-			V4L2_CAP_READWRITE |
-			V4L2_CAP_STREAMING;
-		if (no_overlay <= 0)
-			cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
-
-		if (bttv_tvcards[btv->c.type].tuner != UNSET &&
-		    bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
-			cap->capabilities |= V4L2_CAP_TUNER;
-		return 0;
-	}
+	*fb = btv->fbuf;
+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+	if (fh->ovfmt)
+		fb->fmt.pixelformat  = fh->ovfmt->fourcc;
+	return 0;
+}
 
-	case VIDIOC_ENUM_FMT:
-	{
-		struct v4l2_fmtdesc *f = arg;
-		enum v4l2_buf_type type;
-		unsigned int i;
-		int index;
-
-		type  = f->type;
-		if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
-			/* vbi */
-			index = f->index;
-			if (0 != index)
-				return -EINVAL;
-			memset(f,0,sizeof(*f));
-			f->index       = index;
-			f->type        = type;
-			f->pixelformat = V4L2_PIX_FMT_GREY;
-			strcpy(f->description,"vbi data");
-			return 0;
-		}
+static int bttv_overlay(struct file *file, void *f, unsigned int on)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	struct bttv_buffer *new;
+	int retval;
 
-		/* video capture + overlay */
-		index = -1;
-		for (i = 0; i < BTTV_FORMATS; i++) {
-			if (bttv_formats[i].fourcc != -1)
-				index++;
-			if ((unsigned int)index == f->index)
-				break;
-		}
-		if (BTTV_FORMATS == i)
+	if (on) {
+		/* verify args */
+		if (NULL == btv->fbuf.base)
 			return -EINVAL;
-
-		switch (f->type) {
-		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-			break;
-		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-			if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
-				return -EINVAL;
-			break;
-		default:
+		if (!fh->ov.setup_ok) {
+			dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
 			return -EINVAL;
 		}
-		memset(f,0,sizeof(*f));
-		f->index       = index;
-		f->type        = type;
-		f->pixelformat = bttv_formats[i].fourcc;
-		strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
-		return 0;
 	}
 
-	case VIDIOC_TRY_FMT:
-	{
-		struct v4l2_format *f = arg;
-		return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
-	}
-	case VIDIOC_G_FMT:
-	{
-		struct v4l2_format *f = arg;
-		return bttv_g_fmt(fh,f);
-	}
-	case VIDIOC_S_FMT:
-	{
-		struct v4l2_format *f = arg;
-		return bttv_s_fmt(fh,btv,f);
+	if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
+		return -EBUSY;
+
+	mutex_lock(&fh->cap.lock);
+	if (on) {
+		fh->ov.tvnorm = btv->tvnorm;
+		new = videobuf_pci_alloc(sizeof(*new));
+		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+	} else {
+		new = NULL;
 	}
 
-	case VIDIOC_G_FBUF:
-	{
-		struct v4l2_framebuffer *fb = arg;
+	/* switch over */
+	retval = bttv_switch_overlay(btv, fh, new);
+	mutex_unlock(&fh->cap.lock);
+	return retval;
+}
 
-		*fb = btv->fbuf;
-		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-		if (fh->ovfmt)
-			fb->fmt.pixelformat  = fh->ovfmt->fourcc;
-		return 0;
-	}
-	case VIDIOC_S_FBUF:
-	{
-		struct v4l2_framebuffer *fb = arg;
-		const struct bttv_format *fmt;
+static int bttv_s_fbuf(struct file *file, void *f,
+				struct v4l2_framebuffer *fb)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	const struct bttv_format *fmt;
+	int retval;
 
-		if(!capable(CAP_SYS_ADMIN) &&
-		   !capable(CAP_SYS_RAWIO))
-			return -EPERM;
+	if (!capable(CAP_SYS_ADMIN) &&
+		!capable(CAP_SYS_RAWIO))
+		return -EPERM;
 
-		/* check args */
-		fmt = format_by_fourcc(fb->fmt.pixelformat);
-		if (NULL == fmt)
-			return -EINVAL;
-		if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
-			return -EINVAL;
+	/* check args */
+	fmt = format_by_fourcc(fb->fmt.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+	if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
+		return -EINVAL;
 
-		retval = -EINVAL;
-		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-			__s32 width = fb->fmt.width;
-			__s32 height = fb->fmt.height;
-
-			retval = limit_scaled_size(fh, &width, &height,
-						   V4L2_FIELD_INTERLACED,
-						   /* width_mask */ ~3,
-						   /* width_bias */ 2,
-						   /* adjust_size */ 0,
-						   /* adjust_crop */ 0);
-			if (0 != retval)
-				return retval;
-		}
+	retval = -EINVAL;
+	if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+		__s32 width = fb->fmt.width;
+		__s32 height = fb->fmt.height;
+
+		retval = limit_scaled_size(fh, &width, &height,
+					   V4L2_FIELD_INTERLACED,
+					   /* width_mask */ ~3,
+					   /* width_bias */ 2,
+					   /* adjust_size */ 0,
+					   /* adjust_crop */ 0);
+		if (0 != retval)
+			return retval;
+	}
 
-		/* ok, accept it */
-		mutex_lock(&fh->cap.lock);
-		btv->fbuf.base       = fb->base;
-		btv->fbuf.fmt.width  = fb->fmt.width;
-		btv->fbuf.fmt.height = fb->fmt.height;
-		if (0 != fb->fmt.bytesperline)
-			btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
-		else
-			btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
-
-		retval = 0;
-		fh->ovfmt = fmt;
-		btv->init.ovfmt = fmt;
-		if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
-			fh->ov.w.left   = 0;
-			fh->ov.w.top    = 0;
-			fh->ov.w.width  = fb->fmt.width;
-			fh->ov.w.height = fb->fmt.height;
-			btv->init.ov.w.width  = fb->fmt.width;
-			btv->init.ov.w.height = fb->fmt.height;
-				kfree(fh->ov.clips);
-			fh->ov.clips = NULL;
-			fh->ov.nclips = 0;
-
-			if (check_btres(fh, RESOURCE_OVERLAY)) {
-				struct bttv_buffer *new;
-
-				new = videobuf_pci_alloc(sizeof(*new));
-				new->crop = btv->crop[!!fh->do_crop].rect;
-				bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
-				retval = bttv_switch_overlay(btv,fh,new);
-			}
+	/* ok, accept it */
+	mutex_lock(&fh->cap.lock);
+	btv->fbuf.base       = fb->base;
+	btv->fbuf.fmt.width  = fb->fmt.width;
+	btv->fbuf.fmt.height = fb->fmt.height;
+	if (0 != fb->fmt.bytesperline)
+		btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
+	else
+		btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
+
+	retval = 0;
+	fh->ovfmt = fmt;
+	btv->init.ovfmt = fmt;
+	if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
+		fh->ov.w.left   = 0;
+		fh->ov.w.top    = 0;
+		fh->ov.w.width  = fb->fmt.width;
+		fh->ov.w.height = fb->fmt.height;
+		btv->init.ov.w.width  = fb->fmt.width;
+		btv->init.ov.w.height = fb->fmt.height;
+			kfree(fh->ov.clips);
+		fh->ov.clips = NULL;
+		fh->ov.nclips = 0;
+
+		if (check_btres(fh, RESOURCE_OVERLAY)) {
+			struct bttv_buffer *new;
+
+			new = videobuf_pci_alloc(sizeof(*new));
+			new->crop = btv->crop[!!fh->do_crop].rect;
+			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
+			retval = bttv_switch_overlay(btv, fh, new);
 		}
-		mutex_unlock(&fh->cap.lock);
-		return retval;
 	}
+	mutex_unlock(&fh->cap.lock);
+	return retval;
+}
 
-	case VIDIOC_REQBUFS:
-		return videobuf_reqbufs(bttv_queue(fh),arg);
+static int bttv_reqbufs(struct file *file, void *priv,
+				struct v4l2_requestbuffers *p)
+{
+	struct bttv_fh *fh = priv;
+	return videobuf_reqbufs(bttv_queue(fh), p);
+}
 
-	case VIDIOC_QUERYBUF:
-		return videobuf_querybuf(bttv_queue(fh),arg);
+static int bttv_querybuf(struct file *file, void *priv,
+				struct v4l2_buffer *b)
+{
+	struct bttv_fh *fh = priv;
+	return videobuf_querybuf(bttv_queue(fh), b);
+}
 
-	case VIDIOC_QBUF:
-	{
-		int res = bttv_resource(fh);
+static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	int res = bttv_resource(fh);
 
-		if (!check_alloc_btres(btv, fh, res))
-			return -EBUSY;
-		return videobuf_qbuf(bttv_queue(fh),arg);
-	}
+	if (!check_alloc_btres(btv, fh, res))
+		return -EBUSY;
 
-	case VIDIOC_DQBUF:
-		return videobuf_dqbuf(bttv_queue(fh),arg,
-				      file->f_flags & O_NONBLOCK);
+	return videobuf_qbuf(bttv_queue(fh), b);
+}
 
-	case VIDIOC_STREAMON:
-	{
-		int res = bttv_resource(fh);
+static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct bttv_fh *fh = priv;
+	return videobuf_dqbuf(bttv_queue(fh), b,
+			file->f_flags & O_NONBLOCK);
+}
 
-		if (!check_alloc_btres(btv,fh,res))
-			return -EBUSY;
-		return videobuf_streamon(bttv_queue(fh));
-	}
-	case VIDIOC_STREAMOFF:
-	{
-		int res = bttv_resource(fh);
+static int bttv_streamon(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	int res = bttv_resource(fh);
 
-		retval = videobuf_streamoff(bttv_queue(fh));
-		if (retval < 0)
-			return retval;
-		free_btres(btv,fh,res);
-		return 0;
-	}
+	if (!check_alloc_btres(btv, fh, res))
+		return -EBUSY;
+	return videobuf_streamon(bttv_queue(fh));
+}
 
-	case VIDIOC_QUERYCTRL:
-	{
-		struct v4l2_queryctrl *c = arg;
-		int i;
 
-		if ((c->id <  V4L2_CID_BASE ||
-		     c->id >= V4L2_CID_LASTP1) &&
-		    (c->id <  V4L2_CID_PRIVATE_BASE ||
-		     c->id >= V4L2_CID_PRIVATE_LASTP1))
-			return -EINVAL;
-		for (i = 0; i < BTTV_CTLS; i++)
-			if (bttv_ctls[i].id == c->id)
-				break;
-		if (i == BTTV_CTLS) {
-			*c = no_ctl;
-			return 0;
-		}
-		*c = bttv_ctls[i];
-		if (btv->audio_hook && i >= 4 && i <= 8) {
-			struct video_audio va;
-			memset(&va,0,sizeof(va));
-			btv->audio_hook(btv,&va,0);
-			switch (bttv_ctls[i].id) {
-			case V4L2_CID_AUDIO_VOLUME:
-				if (!(va.flags & VIDEO_AUDIO_VOLUME))
-					*c = no_ctl;
-				break;
-			case V4L2_CID_AUDIO_BALANCE:
-				if (!(va.flags & VIDEO_AUDIO_BALANCE))
-					*c = no_ctl;
-				break;
-			case V4L2_CID_AUDIO_BASS:
-				if (!(va.flags & VIDEO_AUDIO_BASS))
-					*c = no_ctl;
-				break;
-			case V4L2_CID_AUDIO_TREBLE:
-				if (!(va.flags & VIDEO_AUDIO_TREBLE))
-					*c = no_ctl;
-				break;
-			}
-		}
-		return 0;
-	}
-	case VIDIOC_G_CTRL:
-		return get_control(btv,arg);
-	case VIDIOC_S_CTRL:
-		return set_control(btv,arg);
-	case VIDIOC_G_PARM:
-	{
-		struct v4l2_streamparm *parm = arg;
-		struct v4l2_standard s;
-		if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-			return -EINVAL;
-		memset(parm,0,sizeof(*parm));
-		v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
-					 bttv_tvnorms[btv->tvnorm].name);
-		parm->parm.capture.timeperframe = s.frameperiod;
-		return 0;
-	}
+static int bttv_streamoff(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	int retval;
+	int res = bttv_resource(fh);
 
-	case VIDIOC_G_PRIORITY:
-	{
-		enum v4l2_priority *p = arg;
 
-		*p = v4l2_prio_max(&btv->prio);
-		return 0;
-	}
-	case VIDIOC_S_PRIORITY:
-	{
-		enum v4l2_priority *prio = arg;
+	retval = videobuf_streamoff(bttv_queue(fh));
+	if (retval < 0)
+		return retval;
+	free_btres(btv, fh, res);
+	return 0;
+}
 
-		return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
-	}
+static int bttv_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *c)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+	const struct v4l2_queryctrl *ctrl;
 
-	case VIDIOC_CROPCAP:
-	{
-		struct v4l2_cropcap *cap = arg;
-		enum v4l2_buf_type type;
+	if ((c->id <  V4L2_CID_BASE ||
+	     c->id >= V4L2_CID_LASTP1) &&
+	    (c->id <  V4L2_CID_PRIVATE_BASE ||
+	     c->id >= V4L2_CID_PRIVATE_LASTP1))
+		return -EINVAL;
 
-		type = cap->type;
+	if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
+		*c = no_ctl;
+	else {
+		ctrl = ctrl_by_id(c->id);
 
-		if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-		    type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-			return -EINVAL;
+		*c = (NULL != ctrl) ? *ctrl : no_ctl;
+	}
 
-		*cap = bttv_tvnorms[btv->tvnorm].cropcap;
-		cap->type = type;
+	return 0;
+}
 
-		return 0;
-	}
-	case VIDIOC_G_CROP:
-	{
-		struct v4l2_crop * crop = arg;
+static int bttv_g_parm(struct file *file, void *f,
+				struct v4l2_streamparm *parm)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	struct v4l2_standard s;
 
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-			return -EINVAL;
+	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
+				 bttv_tvnorms[btv->tvnorm].name);
+	parm->parm.capture.timeperframe = s.frameperiod;
+	return 0;
+}
 
-		/* No fh->do_crop = 1; because btv->crop[1] may be
-		   inconsistent with fh->width or fh->height and apps
-		   do not expect a change here. */
+static int bttv_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-		crop->c = btv->crop[!!fh->do_crop].rect;
+	if (UNSET == bttv_tvcards[btv->c.type].tuner)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
 
-		return 0;
-	}
-	case VIDIOC_S_CROP:
-	{
-		struct v4l2_crop *crop = arg;
-		const struct v4l2_rect *b;
-		struct bttv_crop c;
-		__s32 b_left;
-		__s32 b_top;
-		__s32 b_right;
-		__s32 b_bottom;
-
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-			return -EINVAL;
+	mutex_lock(&btv->lock);
+	memset(t, 0, sizeof(*t));
+	t->rxsubchans = V4L2_TUNER_SUB_MONO;
+	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+	strcpy(t->name, "Television");
+	t->capability = V4L2_TUNER_CAP_NORM;
+	t->type       = V4L2_TUNER_ANALOG_TV;
+	if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
+		t->signal = 0xffff;
+
+	if (btv->audio_mode_gpio)
+		btv->audio_mode_gpio(btv, t, 0);
 
-		retval = v4l2_prio_check(&btv->prio,&fh->prio);
-		if (0 != retval)
-			return retval;
+	mutex_unlock(&btv->lock);
+	return 0;
+}
 
-		/* Make sure tvnorm, vbi_end and the current cropping
-		   parameters remain consistent until we're done. Note
-		   read() may change vbi_end in check_alloc_btres(). */
-		mutex_lock(&btv->lock);
+static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-		retval = -EBUSY;
+	*p = v4l2_prio_max(&btv->prio);
 
-		if (locked_btres(fh->btv, VIDEO_RESOURCES))
-			goto btv_unlock_and_return;
+	return 0;
+}
 
-		b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+static int bttv_s_priority(struct file *file, void *f,
+					enum v4l2_priority prio)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-		b_left = b->left;
-		b_right = b_left + b->width;
-		b_bottom = b->top + b->height;
+	return v4l2_prio_change(&btv->prio, &fh->prio, prio);
+}
 
-		b_top = max(b->top, btv->vbi_end);
-		if (b_top + 32 >= b_bottom)
-			goto btv_unlock_and_return;
+static int bttv_cropcap(struct file *file, void *priv,
+				struct v4l2_cropcap *cap)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-		/* Min. scaled size 48 x 32. */
-		c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
-		c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
+	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
 
-		c.rect.width = clamp(crop->c.width,
-				     48, b_right - c.rect.left);
+	*cap = bttv_tvnorms[btv->tvnorm].cropcap;
 
-		c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
-		/* Top and height must be a multiple of two. */
-		c.rect.top = (c.rect.top + 1) & ~1;
+	return 0;
+}
 
-		c.rect.height = clamp(crop->c.height,
-				      32, b_bottom - c.rect.top);
-		c.rect.height = (c.rect.height + 1) & ~1;
+static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
 
-		bttv_crop_calc_limits(&c);
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
 
-		btv->crop[1] = c;
+	/* No fh->do_crop = 1; because btv->crop[1] may be
+	   inconsistent with fh->width or fh->height and apps
+	   do not expect a change here. */
 
-		mutex_unlock(&btv->lock);
+	crop->c = btv->crop[!!fh->do_crop].rect;
 
-		fh->do_crop = 1;
+	return 0;
+}
 
-		mutex_lock(&fh->cap.lock);
+static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+	struct bttv_fh *fh = f;
+	struct bttv *btv = fh->btv;
+	const struct v4l2_rect *b;
+	int retval;
+	struct bttv_crop c;
+	__s32 b_left;
+	__s32 b_top;
+	__s32 b_right;
+	__s32 b_bottom;
 
-		if (fh->width < c.min_scaled_width) {
-			fh->width = c.min_scaled_width;
-			btv->init.width = c.min_scaled_width;
-		} else if (fh->width > c.max_scaled_width) {
-			fh->width = c.max_scaled_width;
-			btv->init.width = c.max_scaled_width;
-		}
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
 
-		if (fh->height < c.min_scaled_height) {
-			fh->height = c.min_scaled_height;
-			btv->init.height = c.min_scaled_height;
-		} else if (fh->height > c.max_scaled_height) {
-			fh->height = c.max_scaled_height;
-			btv->init.height = c.max_scaled_height;
-		}
+	retval = v4l2_prio_check(&btv->prio, &fh->prio);
+	if (0 != retval)
+		return retval;
 
-		mutex_unlock(&fh->cap.lock);
+	/* Make sure tvnorm, vbi_end and the current cropping
+	   parameters remain consistent until we're done. Note
+	   read() may change vbi_end in check_alloc_btres(). */
+	mutex_lock(&btv->lock);
 
-		return 0;
+	retval = -EBUSY;
+
+	if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
+		mutex_unlock(&btv->lock);
+		return retval;
 	}
 
-	case VIDIOC_ENUMSTD:
-	case VIDIOC_G_STD:
-	case VIDIOC_S_STD:
-	case VIDIOC_ENUMINPUT:
-	case VIDIOC_G_INPUT:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_G_TUNER:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_G_FREQUENCY:
-	case VIDIOC_S_FREQUENCY:
-	case VIDIOC_LOG_STATUS:
-	case VIDIOC_DBG_G_REGISTER:
-	case VIDIOC_DBG_S_REGISTER:
-		return bttv_common_ioctls(btv,cmd,arg);
+	b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
 
-	default:
-		return -ENOIOCTLCMD;
+	b_left = b->left;
+	b_right = b_left + b->width;
+	b_bottom = b->top + b->height;
+
+	b_top = max(b->top, btv->vbi_end);
+	if (b_top + 32 >= b_bottom) {
+		mutex_unlock(&btv->lock);
+		return retval;
 	}
-	return 0;
 
- fh_unlock_and_return:
-	mutex_unlock(&fh->cap.lock);
-	return retval;
+	/* Min. scaled size 48 x 32. */
+	c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
+	c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
 
- btv_unlock_and_return:
-	mutex_unlock(&btv->lock);
-	return retval;
-}
+	c.rect.width = clamp(crop->c.width,
+			     48, b_right - c.rect.left);
 
-static int bttv_ioctl(struct inode *inode, struct file *file,
-		      unsigned int cmd, unsigned long arg)
-{
-	struct bttv_fh *fh  = file->private_data;
+	c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
+	/* Top and height must be a multiple of two. */
+	c.rect.top = (c.rect.top + 1) & ~1;
 
-	switch (cmd) {
-	case BTTV_VBISIZE:
-	{
-		const struct bttv_tvnorm *tvnorm;
+	c.rect.height = clamp(crop->c.height,
+			      32, b_bottom - c.rect.top);
+	c.rect.height = (c.rect.height + 1) & ~1;
 
-		tvnorm = fh->vbi_fmt.tvnorm;
+	bttv_crop_calc_limits(&c);
 
-		if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
-		    fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
-		    fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
-			/* BTTV_VBISIZE cannot express these parameters,
-			   however open() resets the paramters to defaults
-			   and apps shouldn't call BTTV_VBISIZE after
-			   VIDIOC_S_FMT. */
-			return -EINVAL;
-		}
+	btv->crop[1] = c;
+
+	mutex_unlock(&btv->lock);
+
+	fh->do_crop = 1;
 
-		bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
-		return (fh->vbi_fmt.fmt.count[0] * 2
-			* fh->vbi_fmt.fmt.samples_per_line);
+	mutex_lock(&fh->cap.lock);
+
+	if (fh->width < c.min_scaled_width) {
+		fh->width = c.min_scaled_width;
+		btv->init.width = c.min_scaled_width;
+	} else if (fh->width > c.max_scaled_width) {
+		fh->width = c.max_scaled_width;
+		btv->init.width = c.max_scaled_width;
 	}
 
-	default:
-		return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
+	if (fh->height < c.min_scaled_height) {
+		fh->height = c.min_scaled_height;
+		btv->init.height = c.min_scaled_height;
+	} else if (fh->height > c.max_scaled_height) {
+		fh->height = c.max_scaled_height;
+		btv->init.height = c.max_scaled_height;
 	}
+
+	mutex_unlock(&fh->cap.lock);
+
+	return 0;
+}
+
+static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	strcpy(a->name, "audio");
+	return 0;
+}
+
+static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	return 0;
 }
 
 static ssize_t bttv_read(struct file *file, char __user *data,
@@ -3719,8 +3205,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
 	}
 
 	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == STATE_DONE ||
-	    buf->vb.state == STATE_ERROR)
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
 		return POLLIN|POLLRDNORM;
 	return 0;
 }
@@ -3777,7 +3263,7 @@ static int bttv_open(struct inode *inode, struct file *file)
 			    V4L2_FIELD_SEQ_TB,
 			    sizeof(struct bttv_buffer),
 			    fh);
-	i2c_vidiocschan(btv);
+	set_tvnorm(btv,btv->tvnorm);
 
 	btv->users++;
 
@@ -3857,7 +3343,7 @@ static const struct file_operations bttv_fops =
 	.owner	  = THIS_MODULE,
 	.open	  = bttv_open,
 	.release  = bttv_release,
-	.ioctl	  = bttv_ioctl,
+	.ioctl	  = video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek	  = no_llseek,
 	.read	  = bttv_read,
@@ -3867,19 +3353,61 @@ static const struct file_operations bttv_fops =
 
 static struct video_device bttv_video_template =
 {
-	.name     = "UNSET",
-	.type     = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
-		    VID_TYPE_CLIPPING|VID_TYPE_SCALES,
-	.fops     = &bttv_fops,
-	.minor    = -1,
-};
-
-static struct video_device bttv_vbi_template =
-{
-	.name     = "bt848/878 vbi",
-	.type     = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
 	.fops     = &bttv_fops,
 	.minor    = -1,
+	.vidioc_querycap                = bttv_querycap,
+	.vidioc_enum_fmt_cap            = bttv_enum_fmt_cap,
+	.vidioc_g_fmt_cap               = bttv_g_fmt_cap,
+	.vidioc_try_fmt_cap             = bttv_try_fmt_cap,
+	.vidioc_s_fmt_cap               = bttv_s_fmt_cap,
+	.vidioc_enum_fmt_overlay        = bttv_enum_fmt_overlay,
+	.vidioc_g_fmt_overlay           = bttv_g_fmt_overlay,
+	.vidioc_try_fmt_overlay         = bttv_try_fmt_overlay,
+	.vidioc_s_fmt_overlay           = bttv_s_fmt_overlay,
+	.vidioc_enum_fmt_vbi            = bttv_enum_fmt_vbi,
+	.vidioc_g_fmt_vbi               = bttv_g_fmt_vbi,
+	.vidioc_try_fmt_vbi             = bttv_try_fmt_vbi,
+	.vidioc_s_fmt_vbi               = bttv_s_fmt_vbi,
+	.vidioc_g_audio                 = bttv_g_audio,
+	.vidioc_s_audio                 = bttv_s_audio,
+	.vidioc_cropcap                 = bttv_cropcap,
+	.vidioc_reqbufs                 = bttv_reqbufs,
+	.vidioc_querybuf                = bttv_querybuf,
+	.vidioc_qbuf                    = bttv_qbuf,
+	.vidioc_dqbuf                   = bttv_dqbuf,
+	.vidioc_s_std                   = bttv_s_std,
+	.vidioc_enum_input              = bttv_enum_input,
+	.vidioc_g_input                 = bttv_g_input,
+	.vidioc_s_input                 = bttv_s_input,
+	.vidioc_queryctrl               = bttv_queryctrl,
+	.vidioc_g_ctrl                  = bttv_g_ctrl,
+	.vidioc_s_ctrl                  = bttv_s_ctrl,
+	.vidioc_streamon                = bttv_streamon,
+	.vidioc_streamoff               = bttv_streamoff,
+	.vidioc_g_tuner                 = bttv_g_tuner,
+	.vidioc_s_tuner                 = bttv_s_tuner,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	.vidiocgmbuf                    = vidiocgmbuf,
+#endif
+	.vidioc_g_crop                  = bttv_g_crop,
+	.vidioc_g_crop                  = bttv_g_crop,
+	.vidioc_s_crop                  = bttv_s_crop,
+	.vidioc_g_fbuf                  = bttv_g_fbuf,
+	.vidioc_s_fbuf                  = bttv_s_fbuf,
+	.vidioc_overlay                 = bttv_overlay,
+	.vidioc_g_priority              = bttv_g_priority,
+	.vidioc_s_priority              = bttv_s_priority,
+	.vidioc_g_parm                  = bttv_g_parm,
+	.vidioc_g_frequency             = bttv_g_frequency,
+	.vidioc_s_frequency             = bttv_s_frequency,
+	.vidioc_log_status		= bttv_log_status,
+	.vidioc_querystd		= bttv_querystd,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register		= bttv_g_register,
+	.vidioc_s_register		= bttv_s_register,
+#endif
+	.tvnorms                        = BTTV_NORMS,
+	.current_norm                   = V4L2_STD_PAL,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -3918,7 +3446,7 @@ static int radio_open(struct inode *inode, struct file *file)
 
 static int radio_release(struct inode *inode, struct file *file)
 {
-	struct bttv        *btv = file->private_data;
+	struct bttv *btv = file->private_data;
 	struct rds_command cmd;
 
 	btv->radio_user--;
@@ -3928,59 +3456,116 @@ static int radio_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static int radio_do_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, void *arg)
+static int radio_querycap(struct file *file, void *priv,
+					struct v4l2_capability *cap)
 {
-	struct bttv    *btv = file->private_data;
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-	switch (cmd) {
-	case VIDIOCGCAP:
-	{
-		struct video_capability *cap = arg;
+	strcpy(cap->driver, "bttv");
+	strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));
+	cap->version = BTTV_VERSION_CODE;
+	cap->capabilities = V4L2_CAP_TUNER;
 
-		memset(cap,0,sizeof(*cap));
-		strcpy(cap->name,btv->radio_dev->name);
-		cap->type = VID_TYPE_TUNER;
-		cap->channels = 1;
-		cap->audios = 1;
-		return 0;
-	}
+	return 0;
+}
 
-	case VIDIOCGTUNER:
-	{
-		struct video_tuner *v = arg;
+static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
 
-		if(v->tuner)
-			return -EINVAL;
-		memset(v,0,sizeof(*v));
-		strcpy(v->name, "Radio");
-		bttv_call_i2c_clients(btv,cmd,v);
-		return 0;
-	}
-	case VIDIOCSTUNER:
-		/* nothing to do */
-		return 0;
+	if (UNSET == bttv_tvcards[btv->c.type].tuner)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+	mutex_lock(&btv->lock);
+	memset(t, 0, sizeof(*t));
+	strcpy(t->name, "Radio");
+	t->type = V4L2_TUNER_RADIO;
 
-	case BTTV_VERSION:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-	case VIDIOC_LOG_STATUS:
-	case VIDIOC_DBG_G_REGISTER:
-	case VIDIOC_DBG_S_REGISTER:
-		return bttv_common_ioctls(btv,cmd,arg);
+	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+
+	if (btv->audio_mode_gpio)
+		btv->audio_mode_gpio(btv, t, 0);
+
+	mutex_unlock(&btv->lock);
+
+	return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+
+	strcpy(i->name, "Radio");
+	 i->type = V4L2_INPUT_TYPE_TUNER;
+
+	return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	memset(a, 0, sizeof(*a));
+	strcpy(a->name, "Radio");
+	return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct bttv_fh *fh = priv;
+	struct bttv *btv = fh->btv;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
+	return 0;
+}
+
+static int radio_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	return 0;
+}
+
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	return 0;
+}
+
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+{
+	return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *c)
+{
+	const struct v4l2_queryctrl *ctrl;
+
+	if (c->id <  V4L2_CID_BASE ||
+			c->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+
+	if (c->id == V4L2_CID_AUDIO_MUTE) {
+		ctrl = ctrl_by_id(c->id);
+		*c = *ctrl;
+	} else
+		*c = no_ctl;
 
-	default:
-		return -ENOIOCTLCMD;
-	}
 	return 0;
 }
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg)
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
 {
-	return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
+	*i = 0;
+	return 0;
 }
 
 static ssize_t radio_read(struct file *file, char __user *data,
@@ -4016,17 +3601,29 @@ static const struct file_operations radio_fops =
 	.open	  = radio_open,
 	.read     = radio_read,
 	.release  = radio_release,
-	.ioctl	  = radio_ioctl,
+	.ioctl	  = video_ioctl2,
 	.llseek	  = no_llseek,
 	.poll     = radio_poll,
 };
 
 static struct video_device radio_template =
 {
-	.name     = "bt848/878 radio",
-	.type     = VID_TYPE_TUNER,
 	.fops     = &radio_fops,
 	.minor    = -1,
+	.vidioc_querycap        = radio_querycap,
+	.vidioc_g_tuner         = radio_g_tuner,
+	.vidioc_enum_input      = radio_enum_input,
+	.vidioc_g_audio         = radio_g_audio,
+	.vidioc_s_tuner         = radio_s_tuner,
+	.vidioc_s_audio         = radio_s_audio,
+	.vidioc_s_input         = radio_s_input,
+	.vidioc_s_std           = radio_s_std,
+	.vidioc_queryctrl       = radio_queryctrl,
+	.vidioc_g_input         = radio_g_input,
+	.vidioc_g_ctrl          = bttv_g_ctrl,
+	.vidioc_s_ctrl          = bttv_s_ctrl,
+	.vidioc_g_frequency     = bttv_g_frequency,
+	.vidioc_s_frequency     = bttv_s_frequency,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -4308,20 +3905,20 @@ static void bttv_irq_timeout(unsigned long data)
 	bttv_set_dma(btv, 0);
 
 	/* wake up */
-	bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
-	bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
+	bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR);
+	bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR);
 
 	/* cancel all outstanding capture / vbi requests */
 	while (!list_empty(&btv->capture)) {
 		item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
 		list_del(&item->vb.queue);
-		item->vb.state = STATE_ERROR;
+		item->vb.state = VIDEOBUF_ERROR;
 		wake_up(&item->vb.done);
 	}
 	while (!list_empty(&btv->vcapture)) {
 		item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
 		list_del(&item->vb.queue);
-		item->vb.state = STATE_ERROR;
+		item->vb.state = VIDEOBUF_ERROR;
 		wake_up(&item->vb.done);
 	}
 
@@ -4344,7 +3941,7 @@ bttv_irq_wakeup_top(struct bttv *btv)
 
 	do_gettimeofday(&wakeup->vb.ts);
 	wakeup->vb.field_count = btv->field_count;
-	wakeup->vb.state = STATE_DONE;
+	wakeup->vb.state = VIDEOBUF_DONE;
 	wake_up(&wakeup->vb.done);
 	spin_unlock(&btv->s_lock);
 }
@@ -4393,7 +3990,7 @@ bttv_irq_switch_video(struct bttv *btv)
 	}
 
 	/* wake up finished buffers */
-	bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
+	bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE);
 	spin_unlock(&btv->s_lock);
 }
 
@@ -4426,7 +4023,7 @@ bttv_irq_switch_vbi(struct bttv *btv)
 	bttv_buffer_activate_vbi(btv, new);
 	bttv_set_dma(btv, 0);
 
-	bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
+	bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE);
 	spin_unlock(&btv->s_lock);
 }
 
@@ -4548,8 +4145,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
 /* initialitation                                                          */
 
 static struct video_device *vdev_init(struct bttv *btv,
-				      struct video_device *template,
-				      char *type)
+				      const struct video_device *template,
+				      const char *type_name,
+				      const int type)
 {
 	struct video_device *vfd;
 
@@ -4560,9 +4158,10 @@ static struct video_device *vdev_init(struct bttv *btv,
 	vfd->minor   = -1;
 	vfd->dev     = &btv->c.pci->dev;
 	vfd->release = video_device_release;
+	vfd->type    = type;
 	snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
 		 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
-		 type, bttv_tvcards[btv->c.type].name);
+		 type_name, bttv_tvcards[btv->c.type].name);
 	return vfd;
 }
 
@@ -4594,6 +4193,11 @@ static void bttv_unregister_video(struct bttv *btv)
 /* register video4linux devices */
 static int __devinit bttv_register_video(struct bttv *btv)
 {
+	int video_type = VID_TYPE_CAPTURE |
+			 VID_TYPE_TUNER   |
+			 VID_TYPE_CLIPPING|
+			 VID_TYPE_SCALES;
+
 	if (no_overlay <= 0) {
 		bttv_video_template.type |= VID_TYPE_OVERLAY;
 	} else {
@@ -4601,7 +4205,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
 	}
 
 	/* video */
-	btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
+	btv->video_dev = vdev_init(btv, &bttv_video_template,
+				   "video", video_type);
+
 	if (NULL == btv->video_dev)
 		goto err;
 	if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
@@ -4616,7 +4222,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
 	}
 
 	/* vbi */
-	btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
+	btv->vbi_dev = vdev_init(btv, &bttv_video_template,
+				 "vbi", VID_TYPE_TUNER | VID_TYPE_TELETEXT);
+
 	if (NULL == btv->vbi_dev)
 		goto err;
 	if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
@@ -4627,7 +4235,8 @@ static int __devinit bttv_register_video(struct bttv *btv)
 	if (!btv->has_radio)
 		return 0;
 	/* radio */
-	btv->radio_dev = vdev_init(btv, &radio_template, "radio");
+	btv->radio_dev = vdev_init(btv, &radio_template,
+				   "radio", VID_TYPE_TUNER);
 	if (NULL == btv->radio_dev)
 		goto err;
 	if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
@@ -4768,7 +4377,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
 	btv->init.btv         = btv;
 	btv->init.ov.w.width  = 320;
 	btv->init.ov.w.height = 240;
-	btv->init.fmt         = format_by_palette(VIDEO_PALETTE_RGB24);
+	btv->init.fmt         = format_by_fourcc(V4L2_PIX_FMT_BGR24);
 	btv->init.width       = 320;
 	btv->init.height      = 240;
 	btv->input = 0;
@@ -5013,14 +4622,17 @@ static int __init bttv_init_module(void)
 		printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
 		return ret;
 	}
-	return pci_register_driver(&bttv_pci_driver);
+	ret = pci_register_driver(&bttv_pci_driver);
+	if (ret < 0)
+		bus_unregister(&bttv_sub_bus_type);
+
+	return ret;
 }
 
 static void __exit bttv_cleanup_module(void)
 {
 	pci_unregister_driver(&bttv_pci_driver);
 	bus_unregister(&bttv_sub_bus_type);
-	return;
 }
 
 module_init(bttv_init_module);
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index e7c521b8444a..fc9ecb21eec6 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -69,6 +69,11 @@ static void ir_handle_key(struct bttv *btv)
 	    (ir->mask_keyup    &&  (0 == (gpio & ir->mask_keyup)))) {
 		ir_input_keydown(ir->dev,&ir->ir,data,data);
 	} else {
+		/* HACK: Probably, ir->mask_keydown is missing
+		   for this board */
+		if (btv->c.type == BTTV_BOARD_WINFAST2000)
+			ir_input_keydown(ir->dev, &ir->ir, data, data);
+
 		ir_input_nokey(ir->dev,&ir->ir);
 	}
 
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index 58986f1a5f1a..e5979f77504c 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
 	videobuf_dma_free(dma);
 	btcx_riscmem_free(btv->c.pci,&buf->bottom);
 	btcx_riscmem_free(btv->c.pci,&buf->top);
-	buf->vb.state = STATE_NEEDS_INIT;
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 int
@@ -602,7 +602,7 @@ bttv_buffer_activate_vbi(struct bttv *btv,
 	if (vbi) {
 		unsigned int crop, vdelay;
 
-		vbi->vb.state = STATE_ACTIVE;
+		vbi->vb.state = VIDEOBUF_ACTIVE;
 		list_del(&vbi->vb.queue);
 
 		/* VDELAY is start of video, end of VBI capturing. */
@@ -644,12 +644,12 @@ bttv_buffer_activate_video(struct bttv *btv,
 	/* video capture */
 	if (NULL != set->top  &&  NULL != set->bottom) {
 		if (set->top == set->bottom) {
-			set->top->vb.state    = STATE_ACTIVE;
+			set->top->vb.state    = VIDEOBUF_ACTIVE;
 			if (set->top->vb.queue.next)
 				list_del(&set->top->vb.queue);
 		} else {
-			set->top->vb.state    = STATE_ACTIVE;
-			set->bottom->vb.state = STATE_ACTIVE;
+			set->top->vb.state    = VIDEOBUF_ACTIVE;
+			set->bottom->vb.state = VIDEOBUF_ACTIVE;
 			if (set->top->vb.queue.next)
 				list_del(&set->top->vb.queue);
 			if (set->bottom->vb.queue.next)
@@ -666,7 +666,7 @@ bttv_buffer_activate_video(struct bttv *btv,
 		btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05),
 		      ~0x0f, BT848_COLOR_CTL);
 	} else if (NULL != set->top) {
-		set->top->vb.state  = STATE_ACTIVE;
+		set->top->vb.state  = VIDEOBUF_ACTIVE;
 		if (set->top->vb.queue.next)
 			list_del(&set->top->vb.queue);
 		bttv_apply_geo(btv, &set->top->geo,1);
@@ -677,7 +677,7 @@ bttv_buffer_activate_video(struct bttv *btv,
 		btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT);
 		btaor(set->top->btswap & 0x0f,   ~0x0f, BT848_COLOR_CTL);
 	} else if (NULL != set->bottom) {
-		set->bottom->vb.state = STATE_ACTIVE;
+		set->bottom->vb.state = VIDEOBUF_ACTIVE;
 		if (set->bottom->vb.queue.next)
 			list_del(&set->bottom->vb.queue);
 		bttv_apply_geo(btv, &set->bottom->geo,1);
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 346ce019bdcb..1f0cc79e2a33 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -142,7 +142,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
 		redo_dma_risc = 1;
 	}
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		redo_dma_risc = 1;
 		if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
 			goto fail;
@@ -189,7 +189,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
 	/* For bttv_buffer_activate_vbi(). */
 	buf->geo.vdelay = min_vdelay;
 
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	buf->vb.field = field;
 	dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
 		vb, &buf->top, &buf->bottom,
@@ -209,7 +209,7 @@ vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 	struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
 
 	dprintk("queue %p\n",vb);
-	buf->vb.state = STATE_QUEUED;
+	buf->vb.state = VIDEOBUF_QUEUED;
 	list_add_tail(&buf->vb.queue,&btv->vcapture);
 	if (NULL == btv->cvbi) {
 		fh->btv->loop_irq |= 4;
@@ -236,10 +236,8 @@ struct videobuf_queue_ops bttv_vbi_qops = {
 
 /* ----------------------------------------------------------------------- */
 
-static int
-try_fmt			(struct v4l2_vbi_format *	f,
-			 const struct bttv_tvnorm *	tvnorm,
-			 __s32				crop_start)
+static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
+			__s32 crop_start)
 {
 	__s32 min_start, max_start, max_end, f2_offset;
 	unsigned int i;
@@ -305,10 +303,9 @@ try_fmt			(struct v4l2_vbi_format *	f,
 	return 0;
 }
 
-int
-bttv_vbi_try_fmt	(struct bttv_fh *		fh,
-			 struct v4l2_vbi_format *	f)
+int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 {
+	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
 	const struct bttv_tvnorm *tvnorm;
 	__s32 crop_start;
@@ -320,13 +317,13 @@ bttv_vbi_try_fmt	(struct bttv_fh *		fh,
 
 	mutex_unlock(&btv->lock);
 
-	return try_fmt(f, tvnorm, crop_start);
+	return try_fmt(&frt->fmt.vbi, tvnorm, crop_start);
 }
 
-int
-bttv_vbi_set_fmt	(struct bttv_fh *		fh,
-			 struct v4l2_vbi_format *	f)
+
+int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 {
+	struct bttv_fh *fh = f;
 	struct bttv *btv = fh->btv;
 	const struct bttv_tvnorm *tvnorm;
 	__s32 start1, end;
@@ -340,11 +337,12 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
 
 	tvnorm = &bttv_tvnorms[btv->tvnorm];
 
-	rc = try_fmt(f, tvnorm, btv->crop_start);
+	rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start);
 	if (0 != rc)
 		goto fail;
 
-	start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
+	start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] +
+		tvnorm->vbistart[0];
 
 	/* First possible line of video capturing. Should be
 	   max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
@@ -352,11 +350,11 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
 	   pretend the VBI and video capture window may overlap,
 	   so end = start + 1, the lowest possible value, times two
 	   because vbi_fmt.end counts field lines times two. */
-	end = max(f->start[0], start1) * 2 + 2;
+	end = max(frt->fmt.vbi.start[0], start1) * 2 + 2;
 
 	mutex_lock(&fh->vbi.lock);
 
-	fh->vbi_fmt.fmt    = *f;
+	fh->vbi_fmt.fmt    = frt->fmt.vbi;
 	fh->vbi_fmt.tvnorm = tvnorm;
 	fh->vbi_fmt.end    = end;
 
@@ -370,13 +368,13 @@ bttv_vbi_set_fmt	(struct bttv_fh *		fh,
 	return rc;
 }
 
-void
-bttv_vbi_get_fmt	(struct bttv_fh *		fh,
-			 struct v4l2_vbi_format *	f)
+
+int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt)
 {
+	struct bttv_fh *fh = f;
 	const struct bttv_tvnorm *tvnorm;
 
-	*f = fh->vbi_fmt.fmt;
+	frt->fmt.vbi = fh->vbi_fmt.fmt;
 
 	tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
 
@@ -391,28 +389,28 @@ bttv_vbi_get_fmt	(struct bttv_fh *		fh,
 		max_end = (tvnorm->cropcap.bounds.top
 			   + tvnorm->cropcap.bounds.height) >> 1;
 
-		f->sampling_rate = tvnorm->Fsc;
+		frt->fmt.vbi.sampling_rate = tvnorm->Fsc;
 
 		for (i = 0; i < 2; ++i) {
 			__s32 new_start;
 
-			new_start = f->start[i]
+			new_start = frt->fmt.vbi.start[i]
 				+ tvnorm->vbistart[i]
 				- fh->vbi_fmt.tvnorm->vbistart[i];
 
-			f->start[i] = min(new_start, max_end - 1);
-			f->count[i] = min((__s32) f->count[i],
-					  max_end - f->start[i]);
+			frt->fmt.vbi.start[i] = min(new_start, max_end - 1);
+			frt->fmt.vbi.count[i] =
+				min((__s32) frt->fmt.vbi.count[i],
+					  max_end - frt->fmt.vbi.start[i]);
 
 			max_end += tvnorm->vbistart[1]
 				- tvnorm->vbistart[0];
 		}
 	}
+	return 0;
 }
 
-void
-bttv_vbi_fmt_reset	(struct bttv_vbi_fmt *		f,
-			 int				norm)
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm)
 {
 	const struct bttv_tvnorm *tvnorm;
 	unsigned int real_samples_per_line;
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index 19e75d50a107..bf4c339a520c 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -241,7 +241,10 @@ struct tvcard
 	unsigned int radio_addr;
 
 	unsigned int has_radio;
-	void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
+
+	void (*volume_gpio)(struct bttv *btv, __u16 volume);
+	void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
+
 	void (*muxsel_hook)(struct bttv *btv, unsigned int input);
 };
 
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index d4ac4c4b49b4..1305d315cfc5 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -84,6 +84,11 @@
 
 #define clamp(x, low, high) min (max (low, x), high)
 
+#define BTTV_NORMS    (\
+		V4L2_STD_PAL    | V4L2_STD_PAL_N | \
+		V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
+		V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
+		V4L2_STD_PAL_60)
 /* ---------------------------------------------------------- */
 
 struct bttv_tvnorm {
@@ -112,7 +117,6 @@ extern const struct bttv_tvnorm bttv_tvnorms[];
 
 struct bttv_format {
 	char *name;
-	int  palette;         /* video4linux 1      */
 	int  fourcc;          /* video4linux 2      */
 	int  btformat;        /* BT848_COLOR_FMT_*  */
 	int  btswap;          /* BT848_COLOR_CTL_*  */
@@ -253,9 +257,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
 /* ---------------------------------------------------------- */
 /* bttv-vbi.c                                                 */
 
-int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
-int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
+int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f);
 
 extern struct videobuf_queue_ops bttv_vbi_qops;
 
@@ -337,7 +341,9 @@ struct bttv {
 	/* old gpio interface */
 	wait_queue_head_t gpioq;
 	int shutdown;
-	void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
+
+	void (*volume_gpio)(struct bttv *btv, __u16 volume);
+	void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set);
 
 	/* new gpio interface */
 	spinlock_t gpio_lock;
@@ -458,10 +464,6 @@ struct bttv {
 extern unsigned int bttv_num;
 extern struct bttv bttvs[BTTV_MAX];
 
-/* private ioctls */
-#define BTTV_VERSION            _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
-#define BTTV_VBISIZE            _IOR('v' , BASE_VIDIOCPRIVATE+8, int)
-
 #endif
 
 #define btwrite(dat,adr)    writel((dat), btv->bt848_mmio+(adr))
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 58423525591f..032265383df2 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -82,11 +82,16 @@ OTHER DEALINGS IN THE SOFTWARE.
 static unsigned int maxpoll=250;   /* Maximum busy-loop count for qcam I/O */
 static unsigned int yieldlines=4;  /* Yield after this many during capture */
 static int video_nr = -1;
+static unsigned int force_init;		/* Whether to probe aggressively */
 
 module_param(maxpoll, int, 0);
 module_param(yieldlines, int, 0);
 module_param(video_nr, int, 0);
 
+/* Set force_init=1 to avoid detection by polling status register and
+ * immediately attempt to initialize qcam */
+module_param(force_init, int, 0);
+
 static inline int read_lpstatus(struct qcam_device *q)
 {
 	return parport_read_status(q->pport);
@@ -331,6 +336,9 @@ static int qc_detect(struct qcam_device *q)
 	int count = 0;
 	int i;
 
+	if (force_init)
+		return 1;
+
 	lastreg = reg = read_lpstatus(q) & 0xf0;
 
 	for (i = 0; i < 500; i++)
@@ -354,12 +362,12 @@ static int qc_detect(struct qcam_device *q)
 
 	/* Be (even more) liberal in what you accept...  */
 
-/*	if (count > 30 && count < 200) */
 	if (count > 20 && count < 400) {
 		return 1;	/* found */
 	} else {
 		printk(KERN_ERR "No Quickcam found on port %s\n",
 			q->pport->name);
+		printk(KERN_DEBUG "Quickcam detection counter: %u\n", count);
 		return 0;	/* not found */
 	}
 }
diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
new file mode 100644
index 000000000000..fae469ce16f5
--- /dev/null
+++ b/drivers/media/video/cs5345.c
@@ -0,0 +1,168 @@
+/*
+ * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC
+ * Copyright (C) 2007 Hans Verkuil
+ *
+ * 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/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-i2c-drv.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug;
+
+module_param(debug, bool, 0644);
+
+MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On");
+
+
+/* ----------------------------------------------------------------------- */
+
+static inline int cs5345_write(struct i2c_client *client, u8 reg, u8 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int cs5345_read(struct i2c_client *client, u8 reg)
+{
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+	struct v4l2_routing *route = arg;
+	struct v4l2_control *ctrl = arg;
+
+	switch (cmd) {
+	case VIDIOC_INT_G_AUDIO_ROUTING:
+		route->input = cs5345_read(client, 0x09) & 7;
+		route->input |= cs5345_read(client, 0x05) & 0x70;
+		route->output = 0;
+		break;
+
+	case VIDIOC_INT_S_AUDIO_ROUTING:
+		if ((route->input & 0xf) > 6) {
+			v4l_err(client, "Invalid input %d.\n", route->input);
+			return -EINVAL;
+		}
+		cs5345_write(client, 0x09, route->input & 0xf);
+		cs5345_write(client, 0x05, route->input & 0xf0);
+		break;
+
+	case VIDIOC_G_CTRL:
+		if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+			ctrl->value = (cs5345_read(client, 0x04) & 0x08) != 0;
+			break;
+		}
+		if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+			return -EINVAL;
+		ctrl->value = cs5345_read(client, 0x07) & 0x3f;
+		if (ctrl->value >= 32)
+			ctrl->value = ctrl->value - 64;
+		break;
+
+	case VIDIOC_S_CTRL:
+		break;
+		if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
+			cs5345_write(client, 0x04, ctrl->value ? 0x80 : 0);
+			break;
+		}
+		if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
+			return -EINVAL;
+		if (ctrl->value > 24 || ctrl->value < -24)
+			return -EINVAL;
+		cs5345_write(client, 0x07, ((u8)ctrl->value) & 0x3f);
+		cs5345_write(client, 0x08, ((u8)ctrl->value) & 0x3f);
+		break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	case VIDIOC_DBG_G_REGISTER:
+	case VIDIOC_DBG_S_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+
+		if (!v4l2_chip_match_i2c_client(client,
+					reg->match_type, reg->match_chip))
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (cmd == VIDIOC_DBG_G_REGISTER)
+			reg->val = cs5345_read(client, reg->reg & 0x1f);
+		else
+			cs5345_write(client, reg->reg & 0x1f, reg->val & 0x1f);
+		break;
+	}
+#endif
+
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client,
+				arg, V4L2_IDENT_CS5345, 0);
+
+	case VIDIOC_LOG_STATUS:
+		{
+			u8 v = cs5345_read(client, 0x09) & 7;
+			u8 m = cs5345_read(client, 0x04);
+			int vol = cs5345_read(client, 0x08) & 0x3f;
+
+			v4l_info(client, "Input:  %d%s\n", v,
+				      (m & 0x80) ? " (muted)" : "");
+			if (vol >= 32)
+				vol = vol - 64;
+			v4l_info(client, "Volume: %d dB\n", vol);
+			break;
+		}
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cs5345_probe(struct i2c_client *client)
+{
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	cs5345_write(client, 0x02, 0x00);
+	cs5345_write(client, 0x04, 0x01);
+	cs5345_write(client, 0x09, 0x01);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "cs5345",
+	.driverid = I2C_DRIVERID_CS5345,
+	.command = cs5345_command,
+	.probe = cs5345_probe,
+};
+
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index a73e285af730..f41bfde045fe 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -29,12 +29,13 @@
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
 MODULE_AUTHOR("Martin Vaughan");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 
 module_param(debug, bool, 0644);
 
@@ -57,8 +58,7 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg)
 	return i2c_smbus_read_byte_data(client, reg);
 }
 
-static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
-			    void *arg)
+static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
 	struct v4l2_routing *route = arg;
 	struct v4l2_control *ctrl = arg;
@@ -105,7 +105,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
 		break;
 
 	case VIDIOC_G_CHIP_IDENT:
-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0);
+		return v4l2_chip_ident_i2c_client(client,
+				arg, V4L2_IDENT_CS53l32A, 0);
 
 	case VIDIOC_LOG_STATUS:
 		{
@@ -134,27 +135,18 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd,
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static struct i2c_driver i2c_driver;
-
-static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
+static int cs53l32a_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	int i;
 
 	/* Check if the adapter supports the needed features */
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == 0)
-		return -ENOMEM;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
 
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver;
 	snprintf(client->name, sizeof(client->name) - 1, "cs53l32a");
 
-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
 
 	for (i = 1; i <= 7; i++) {
 		u8 v = cs53l32a_read(client, i);
@@ -179,55 +171,13 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind)
 
 		v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v);
 	}
-
-	i2c_attach_client(client);
-
 	return 0;
 }
 
-static int cs53l32a_probe(struct i2c_adapter *adapter)
-{
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, cs53l32a_attach);
-	return 0;
-}
-
-static int cs53l32a_detach(struct i2c_client *client)
-{
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err) {
-		return err;
-	}
-	kfree(client);
-
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-	.driver = {
-		.name = "cs53l32a",
-	},
-	.id = I2C_DRIVERID_CS53L32A,
-	.attach_adapter = cs53l32a_probe,
-	.detach_client = cs53l32a_detach,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "cs53l32a",
+	.driverid = I2C_DRIVERID_CS53L32A,
 	.command = cs53l32a_command,
+	.probe = cs53l32a_probe,
 };
 
-
-static int __init cs53l32a_init_module(void)
-{
-	return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit cs53l32a_cleanup_module(void)
-{
-	i2c_del_driver(&i2c_driver);
-}
-
-module_init(cs53l32a_init_module);
-module_exit(cs53l32a_cleanup_module);
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 62304255dcae..c592899a2317 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -34,7 +34,7 @@ MODULE_DESCRIPTION("cx23415/6 driver");
 MODULE_AUTHOR("Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
@@ -75,6 +75,7 @@ const u32 cx2341x_mpeg_ctrls[] = {
 	V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
 	0
 };
+EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
 
 
 /* Map the control ID to the correct field in the cx2341x_mpeg_params
@@ -281,13 +282,14 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
 			return -EBUSY;
 		params->stream_type = ctrl->value;
 		params->video_encoding =
-			(params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
-			 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
-			V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
-		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+		    (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+		     params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+			V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
+			V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
 			/* MPEG-1 implies CBR */
-			params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
-		}
+			params->video_bitrate_mode =
+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
 		break;
 	case V4L2_CID_MPEG_STREAM_VBI_FMT:
 		params->stream_vbi_fmt = ctrl->value;
@@ -334,7 +336,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
 	return 0;
 }
 
-static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
+				   s32 min, s32 max, s32 step, s32 def)
 {
 	const char *name;
 
@@ -417,7 +420,8 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma
 	return 0;
 }
 
-int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
+		       struct v4l2_queryctrl *qctrl)
 {
 	int err;
 
@@ -440,7 +444,8 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
 
 	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
 		err = v4l2_ctrl_query_fill_std(qctrl);
-		if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+		if (err == 0 &&
+		    params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return err;
 
@@ -455,13 +460,16 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
 
 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
 		err = v4l2_ctrl_query_fill_std(qctrl);
-		if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+		if (err == 0 &&
+		    params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return err;
 
 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
 		err = v4l2_ctrl_query_fill_std(qctrl);
-		if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+		if (err == 0 &&
+		    params->video_bitrate_mode ==
+				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return err;
 
@@ -476,80 +484,90 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
 	/* CX23415/6 specific */
 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
 		return cx2341x_ctrl_query_fill(qctrl,
-				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
-				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
-				V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
 		cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		if (params->video_spatial_filter_mode ==
+			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
 		cx2341x_ctrl_query_fill(qctrl,
-				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
-				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
-				V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
-		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
+			1,
+			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
+		if (params->video_spatial_filter_mode ==
+			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
 		cx2341x_ctrl_query_fill(qctrl,
-				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
-				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
-				V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
-		if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+		    1,
+		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
+		if (params->video_spatial_filter_mode ==
+			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
 		return cx2341x_ctrl_query_fill(qctrl,
-				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
-				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
-				V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
 		cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-		if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		if (params->video_temporal_filter_mode ==
+			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
 		return cx2341x_ctrl_query_fill(qctrl,
-				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
-				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
-				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
+			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		if (params->video_median_filter_type ==
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		if (params->video_median_filter_type ==
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		if (params->video_median_filter_type ==
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
-		if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
-		       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+		if (params->video_median_filter_type ==
+				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
 		return 0;
 
 	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
@@ -560,6 +578,7 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl
 
 	}
 }
+EXPORT_SYMBOL(cx2341x_ctrl_query);
 
 const char **cx2341x_ctrl_get_menu(u32 id)
 {
@@ -629,6 +648,7 @@ const char **cx2341x_ctrl_get_menu(u32 id)
 		return v4l2_ctrl_get_menu(id);
 	}
 }
+EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
 
 static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
 {
@@ -637,9 +657,8 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
 		((1 + params->audio_l2_bitrate) << 4) |
 		(params->audio_mode << 8) |
 		(params->audio_mode_extension << 10) |
-		(((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
-		  3 :
-		  params->audio_emphasis) << 12) |
+		(((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
+		  ? 3 : params->audio_emphasis) << 12) |
 		(params->audio_crc << 14);
 }
 
@@ -679,19 +698,19 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
 		if (err)
 			break;
 	}
-	if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
-			params->video_bitrate_peak < params->video_bitrate) {
+	if (err == 0 &&
+	    params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+	    params->video_bitrate_peak < params->video_bitrate) {
 		err = -ERANGE;
 		ctrls->error_idx = ctrls->count;
 	}
-	if (err) {
+	if (err)
 		ctrls->error_idx = i;
-	}
-	else {
+	else
 		cx2341x_calc_audio_properties(params);
-	}
 	return err;
 }
+EXPORT_SYMBOL(cx2341x_ext_ctrls);
 
 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
 {
@@ -732,13 +751,18 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
 	.video_mute_yuv = 0x008080,  /* YCbCr value for black */
 
 	/* encoding filters */
-	.video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+	.video_spatial_filter_mode =
+		V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
 	.video_spatial_filter = 0,
-	.video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
-	.video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
-	.video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+	.video_luma_spatial_filter_type =
+		V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+	.video_chroma_spatial_filter_type =
+		V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+	.video_temporal_filter_mode =
+		V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
 	.video_temporal_filter = 8,
-	.video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+	.video_median_filter_type =
+		V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
 	.video_luma_median_filter_top = 255,
 	.video_luma_median_filter_bottom = 0,
 	.video_chroma_median_filter_top = 255,
@@ -748,8 +772,10 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
 	*p = default_params;
 	cx2341x_calc_audio_properties(p);
 }
+EXPORT_SYMBOL(cx2341x_fill_defaults);
 
-static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
+static int cx2341x_api(void *priv, cx2341x_mbox_func func,
+		       u32 cmd, int args, ...)
 {
 	u32 data[CX2341X_MBOX_MAX_DATA];
 	va_list vargs;
@@ -757,15 +783,17 @@ static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ..
 
 	va_start(vargs, args);
 
-	for (i = 0; i < args; i++) {
+	for (i = 0; i < args; i++)
 		data[i] = va_arg(vargs, int);
-	}
 	va_end(vargs);
 	return func(priv, cmd, args, 0, data);
 }
 
+#define NEQ(field) (old->field != new->field)
+
 int cx2341x_update(void *priv, cx2341x_mbox_func func,
-		const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
+		   const struct cx2341x_mpeg_params *old,
+		   const struct cx2341x_mpeg_params *new)
 {
 	static int mpeg_stream_type[] = {
 		0,	/* MPEG-2 PS */
@@ -777,17 +805,18 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
 	};
 
 	int err = 0;
+	int force = (old == NULL);
 	u16 temporal = new->video_temporal_filter;
 
 	cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
 
-	if (old == NULL || old->is_50hz != new->is_50hz) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
+	if (force || NEQ(is_50hz)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1,
+				  new->is_50hz);
 		if (err) return err;
 	}
 
-	if (old == NULL || old->width != new->width || old->height != new->height ||
-			old->video_encoding != new->video_encoding) {
+	if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) {
 		u16 w = new->width;
 		u16 h = new->height;
 
@@ -795,69 +824,74 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
 			w /= 2;
 			h /= 2;
 		}
-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2,
+				  h, w);
 		if (err) return err;
 	}
 
 	if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
-		/* Adjust temporal filter if necessary. The problem with the temporal
-		   filter is that it works well with full resolution capturing, but
-		   not when the capture window is scaled (the filter introduces
-		   a ghosting effect). So if the capture window is scaled, then
-		   force the filter to 0.
+		/* Adjust temporal filter if necessary. The problem with the
+		   temporal filter is that it works well with full resolution
+		   capturing, but not when the capture window is scaled (the
+		   filter introduces a ghosting effect). So if the capture
+		   window is scaled, then force the filter to 0.
 
 		   For full resolution the filter really improves the video
-		   quality, especially if the original video quality is suboptimal. */
+		   quality, especially if the original video quality is
+		   suboptimal. */
 		temporal = 0;
 	}
 
-	if (old == NULL || old->stream_type != new->stream_type) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
+	if (force || NEQ(stream_type)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1,
+				  mpeg_stream_type[new->stream_type]);
 		if (err) return err;
 	}
-	if (old == NULL || old->video_aspect != new->video_aspect) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
+	if (force || NEQ(video_aspect)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1,
+				  1 + new->video_aspect);
 		if (err) return err;
 	}
-	if (old == NULL || old->video_b_frames != new->video_b_frames ||
-		old->video_gop_size != new->video_gop_size) {
+	if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) {
 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
 				new->video_gop_size, new->video_b_frames + 1);
 		if (err) return err;
 	}
-	if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
+	if (force || NEQ(video_gop_closure)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1,
+				  new->video_gop_closure);
 		if (err) return err;
 	}
-	if (old == NULL || old->audio_properties != new->audio_properties) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
+	if (force || NEQ(audio_properties)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES,
+				  1, new->audio_properties);
 		if (err) return err;
 	}
-	if (old == NULL || old->audio_mute != new->audio_mute) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
+	if (force || NEQ(audio_mute)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1,
+				  new->audio_mute);
 		if (err) return err;
 	}
-	if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
-		old->video_bitrate != new->video_bitrate ||
-		old->video_bitrate_peak != new->video_bitrate_peak) {
+	if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) ||
+						NEQ(video_bitrate_peak)) {
 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
 				new->video_bitrate_mode, new->video_bitrate,
 				new->video_bitrate_peak / 400, 0, 0);
 		if (err) return err;
 	}
-	if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
-		old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
-		old->video_median_filter_type != new->video_median_filter_type) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
-				new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
+	if (force || NEQ(video_spatial_filter_mode) ||
+		     NEQ(video_temporal_filter_mode) ||
+		     NEQ(video_median_filter_type)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE,
+				  2, new->video_spatial_filter_mode |
+					(new->video_temporal_filter_mode << 1),
 				new->video_median_filter_type);
 		if (err) return err;
 	}
-	if (old == NULL ||
-		old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
-		old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
-		old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
-		old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
+	if (force || NEQ(video_luma_median_filter_bottom) ||
+		     NEQ(video_luma_median_filter_top) ||
+		     NEQ(video_chroma_median_filter_bottom) ||
+		     NEQ(video_chroma_median_filter_top)) {
 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
 				new->video_luma_median_filter_bottom,
 				new->video_luma_median_filter_top,
@@ -865,36 +899,39 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
 				new->video_chroma_median_filter_top);
 		if (err) return err;
 	}
-	if (old == NULL ||
-		old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
-		old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
-			new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
+	if (force || NEQ(video_luma_spatial_filter_type) ||
+		     NEQ(video_chroma_spatial_filter_type)) {
+		err = cx2341x_api(priv, func,
+				  CX2341X_ENC_SET_SPATIAL_FILTER_TYPE,
+				  2, new->video_luma_spatial_filter_type,
+				  new->video_chroma_spatial_filter_type);
 		if (err) return err;
 	}
-	if (old == NULL ||
-		old->video_spatial_filter != new->video_spatial_filter ||
-		old->video_temporal_filter != temporal) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
-			new->video_spatial_filter, temporal);
+	if (force || NEQ(video_spatial_filter) ||
+		     old->video_temporal_filter != temporal) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS,
+				  2, new->video_spatial_filter, temporal);
 		if (err) return err;
 	}
-	if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
-			new->video_temporal_decimation);
+	if (force || NEQ(video_temporal_decimation)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE,
+				  1, new->video_temporal_decimation);
 		if (err) return err;
 	}
-	if (old == NULL || old->video_mute != new->video_mute ||
-			(new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
+	if (force || NEQ(video_mute) ||
+		(new->video_mute && NEQ(video_mute_yuv))) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1,
+				new->video_mute | (new->video_mute_yuv << 8));
 		if (err) return err;
 	}
-	if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
-		err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
+	if (force || NEQ(stream_insert_nav_packets)) {
+		err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2,
+				7, new->stream_insert_nav_packets);
 		if (err) return err;
 	}
 	return 0;
 }
+EXPORT_SYMBOL(cx2341x_update);
 
 static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
 {
@@ -943,18 +980,17 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
 		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
 		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
 		p->video_bitrate);
-	if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+	if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
 		printk(", Peak %d", p->video_bitrate_peak);
-	}
 	printk("\n");
-	printk(KERN_INFO "%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
+	printk(KERN_INFO
+		"%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
 		prefix,
 		p->video_gop_size, p->video_b_frames,
 		p->video_gop_closure ? "" : "No ");
-	if (p->video_temporal_decimation) {
+	if (p->video_temporal_decimation)
 		printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
 			prefix, p->video_temporal_decimation);
-	}
 
 	/* Audio */
 	printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s%s",
@@ -964,10 +1000,9 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
 		p->audio_mute ? " (muted)" : "");
-	if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
-		printk(", %s",
-			cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
-	}
+	if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+		printk(", %s", cx2341x_menu_item(p,
+				V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
 	printk(", %s, %s\n",
 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
@@ -975,33 +1010,33 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
 	/* Encoding filters */
 	printk(KERN_INFO "%s: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
 		prefix,
-		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
-		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
-		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
+		cx2341x_menu_item(p,
+		    V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
+		cx2341x_menu_item(p,
+		    V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
+		cx2341x_menu_item(p,
+		    V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
 		p->video_spatial_filter);
-	if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) {
+
+	if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480))
 		temporal = 0;
-	}
+
 	printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
 		prefix,
-		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
+		cx2341x_menu_item(p,
+			V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
 		temporal);
-	printk(KERN_INFO "%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
+	printk(KERN_INFO
+		"%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
 		prefix,
-		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
+		cx2341x_menu_item(p,
+			V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
 		p->video_luma_median_filter_bottom,
 		p->video_luma_median_filter_top,
 		p->video_chroma_median_filter_bottom,
 		p->video_chroma_median_filter_top);
 }
-
-EXPORT_SYMBOL(cx2341x_fill_defaults);
-EXPORT_SYMBOL(cx2341x_ctrl_query);
-EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
-EXPORT_SYMBOL(cx2341x_ext_ctrls);
-EXPORT_SYMBOL(cx2341x_update);
 EXPORT_SYMBOL(cx2341x_log_status);
-EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
 
 /*
  * Local variables:
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index 081ee6e1536f..1fd326fe4113 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -12,6 +12,10 @@ config VIDEO_CX23885
 	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
 	select DVB_PLL if !DVB_FE_CUSTOMISE
+	select TUNER_XC2028 if !DVB_FE_CUSTOMIZE
+	select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+	select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
+	select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
 	---help---
 	  This is a video4linux driver for Conexant 23885 based
 	  TV cards.
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
index 665067022d2a..32c90be50602 100644
--- a/drivers/media/video/cx23885/Makefile
+++ b/drivers/media/video/cx23885/Makefile
@@ -1,4 +1,4 @@
-cx23885-objs	:= cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
+cx23885-objs	:= cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
 
 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
 
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index b9012acabb2f..2d414dad5c31 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <media/cx25840.h>
 
 #include "cx23885.h"
 
@@ -32,6 +33,8 @@
 struct cx23885_board cx23885_boards[] = {
 	[CX23885_BOARD_UNKNOWN] = {
 		.name		= "UNKNOWN/GENERIC",
+		/* Ensure safe default for unknown boards */
+		.clk_freq       = 0,
 		.input          = {{
 			.type   = CX23885_VMUX_COMPOSITE1,
 			.vmux   = 0,
@@ -69,23 +72,29 @@ struct cx23885_board cx23885_boards[] = {
 	},
 	[CX23885_BOARD_HAUPPAUGE_HVR1800] = {
 		.name		= "Hauppauge WinTV-HVR1800",
+		.porta		= CX23885_ANALOG_VIDEO,
 		.portc		= CX23885_MPEG_DVB,
+		.tuner_type	= TUNER_PHILIPS_TDA8290,
+		.tuner_addr	= 0x42, /* 0x84 >> 1 */
 		.input          = {{
 			.type   = CX23885_VMUX_TELEVISION,
-			.vmux   = 0,
-			.gpio0  = 0xff00,
-		},{
-			.type   = CX23885_VMUX_DEBUG,
-			.vmux   = 0,
-			.gpio0  = 0xff01,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN5_CH2 |
+					CX25840_VIN2_CH1,
+			.gpio0  = 0,
 		},{
 			.type   = CX23885_VMUX_COMPOSITE1,
-			.vmux   = 1,
-			.gpio0  = 0xff02,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN6_CH1,
+			.gpio0  = 0,
 		},{
 			.type   = CX23885_VMUX_SVIDEO,
-			.vmux   = 2,
-			.gpio0  = 0xff02,
+			.vmux   =	CX25840_VIN7_CH3 |
+					CX25840_VIN4_CH2 |
+					CX25840_VIN8_CH1 |
+					CX25840_SVIDEO_ON,
+			.gpio0  = 0,
 		}},
 	},
 	[CX23885_BOARD_HAUPPAUGE_HVR1250] = {
@@ -113,6 +122,14 @@ struct cx23885_board cx23885_boards[] = {
 		.name		= "DViCO FusionHDTV5 Express",
 		.portb		= CX23885_MPEG_DVB,
 	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1500Q] = {
+		.name		= "Hauppauge WinTV-HVR1500Q",
+		.portc		= CX23885_MPEG_DVB,
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1500] = {
+		.name		= "Hauppauge WinTV-HVR1500",
+		.portc		= CX23885_MPEG_DVB,
+	},
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -138,12 +155,32 @@ struct cx23885_subid cx23885_subids[] = {
 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
 	},{
 		.subvendor = 0x0070,
+		.subdevice = 0x7809,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
+	},{
+		.subvendor = 0x0070,
 		.subdevice = 0x7911,
 		.card      = CX23885_BOARD_HAUPPAUGE_HVR1250,
 	},{
 		.subvendor = 0x18ac,
 		.subdevice = 0xd500,
 		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x7790,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x7797,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500Q,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x7710,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x7717,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1500,
 	},
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -184,9 +221,19 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
 	switch (tv.model)
 	{
 	case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
-	case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
-	case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
-	case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+	case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */
+	case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
+	case 77041: /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM and Basic analog */
+	case 77051: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */
+	case 78011: /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
+	case 78501: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
+	case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */
+	case 78531: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
+	case 78631: /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */
+	case 79001: /* WinTV-HVR1250 (PCIe, Retail, IR, full height, ATSC and Basic analog */
+	case 79101: /* WinTV-HVR1250 (PCIe, Retail, IR, half height, ATSC and Basic analog */
+	case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */
+	case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
 		break;
 	default:
 		printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
@@ -197,6 +244,34 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
 			dev->name, tv.model);
 }
 
+/* Tuner callback function for cx23885 boards. Currently only needed
+ * for HVR1500Q, which has an xc5000 tuner.
+ */
+int cx23885_tuner_callback(void *priv, int command, int arg)
+{
+	struct cx23885_i2c *bus = priv;
+	struct cx23885_dev *dev = bus->dev;
+
+	switch(dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+		if(command == 0) {	/* Tuner Reset Command from xc5000 */
+			/* Drive the tuner into reset and out */
+			cx_clear(GP0_IO, 0x00000004);
+			mdelay(200);
+			cx_set(GP0_IO, 0x00000004);
+			return 0;
+		}
+		else {
+			printk(KERN_ERR
+				"%s(): Unknow command.\n", __FUNCTION__);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	return 0; /* Should never be here */
+}
+
 void cx23885_gpio_setup(struct cx23885_dev *dev)
 {
 	switch(dev->board) {
@@ -204,6 +279,23 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
 		/* GPIO-0 cx24227 demodulator reset */
 		cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+		/* GPIO-0 cx24227 demodulator */
+		/* GPIO-2 xc3028 tuner */
+
+		/* Put the parts into reset */
+		cx_set(GP0_IO, 0x00050000);
+		cx_clear(GP0_IO, 0x00000005);
+		msleep(5);
+
+		/* Bring the parts out of reset */
+		cx_set(GP0_IO, 0x00050005);
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+		/* GPIO-0 cx24227 demodulator reset */
+		/* GPIO-2 xc5000 tuner reset */
+		cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */
+		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
 		/* GPIO-0 656_CLK */
 		/* GPIO-1 656_D0 */
@@ -212,7 +304,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
 		/* GPIO-11-14 cx23417 addr0-3 */
 		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
 		/* GPIO-19 IR_RX */
-		// FIXME: Analog requires the tuner is brought out of reset
+
+		/* Force the TDA8295A into reset and back */
+		cx_set(GP0_IO, 0x00040004);
+		mdelay(20);
+		cx_clear(GP0_IO, 0x00000004);
+		mdelay(20);
+		cx_set(GP0_IO, 0x00040004);
+		mdelay(20);
 		break;
 	}
 }
@@ -221,6 +320,8 @@ int cx23885_ir_init(struct cx23885_dev *dev)
 {
 	switch (dev->board) {
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
 		/* FIXME: Implement me */
 		break;
@@ -244,6 +345,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 
 	switch (dev->board) {
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
 		if (dev->i2c_bus[0].i2c_rc == 0)
@@ -258,6 +361,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
 		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
 	case CX23885_BOARD_HAUPPAUGE_HVR1800:
 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
 	default:
@@ -270,8 +375,6 @@ void cx23885_card_setup(struct cx23885_dev *dev)
 
 /* ------------------------------------------------------------------ */
 
-EXPORT_SYMBOL(cx23885_boards);
-
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 3cdd136477e5..8e40c7bcc06d 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -36,7 +36,7 @@ MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
 MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
 MODULE_LICENSE("GPL");
 
-static unsigned int debug = 0;
+static unsigned int debug;
 module_param(debug,int,0644);
 MODULE_PARM_DESC(debug,"enable debug messages");
 
@@ -44,13 +44,15 @@ static unsigned int card[]  = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card,"card type");
 
-#define dprintk(level,fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg)
+#define dprintk(level, fmt, arg...)\
+	do { if (debug >= level)\
+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+	} while (0)
 
 static unsigned int cx23885_devcount;
 
 static DEFINE_MUTEX(devlist);
-static LIST_HEAD(cx23885_devlist);
+LIST_HEAD(cx23885_devlist);
 
 #define NO_SYNC_LINE (-1U)
 
@@ -73,14 +75,14 @@ static LIST_HEAD(cx23885_devlist);
  * 0x00010ea0 0x00010xxx Free
  */
 
-struct sram_channel cx23885_sram_channels[] = {
+static struct sram_channel cx23885_sram_channels[] = {
 	[SRAM_CH01] = {
-		.name		= "test ch1",
+		.name		= "VID A",
 		.cmds_start	= 0x10000,
-		.ctrl_start	= 0x10500,
-		.cdt		= 0x10900,
-		.fifo_start	= 0x3000,
-		.fifo_size	= 0x1000,
+		.ctrl_start	= 0x105b0,
+		.cdt		= 0x107b0,
+		.fifo_start	= 0x40,
+		.fifo_size	= 0x2800,
 		.ptr1_reg	= DMA1_PTR1,
 		.ptr2_reg	= DMA1_PTR2,
 		.cnt1_reg	= DMA1_CNT1,
@@ -102,8 +104,8 @@ struct sram_channel cx23885_sram_channels[] = {
 	[SRAM_CH03] = {
 		.name		= "TS1 B",
 		.cmds_start	= 0x100A0,
-		.ctrl_start	= 0x10780,
-		.cdt		= 0x10400,
+		.ctrl_start	= 0x10630,
+		.cdt		= 0x10870,
 		.fifo_start	= 0x5000,
 		.fifo_size	= 0x1000,
 		.ptr1_reg	= DMA3_PTR1,
@@ -139,7 +141,7 @@ struct sram_channel cx23885_sram_channels[] = {
 		.name		= "TS2 C",
 		.cmds_start	= 0x10140,
 		.ctrl_start	= 0x10680,
-		.cdt		= 0x10480,
+		.cdt		= 0x108d0,
 		.fifo_start	= 0x6000,
 		.fifo_size	= 0x1000,
 		.ptr1_reg	= DMA5_PTR1,
@@ -205,14 +207,14 @@ struct sram_channel cx23885_sram_channels[] = {
  * 0x00010ea0 0x00010xxx Free
  */
 
-struct sram_channel cx23887_sram_channels[] = {
+static struct sram_channel cx23887_sram_channels[] = {
 	[SRAM_CH01] = {
-		.name		= "test ch1",
-		.cmds_start	= 0x0,
-		.ctrl_start	= 0x0,
-		.cdt		= 0x0,
-		.fifo_start	= 0x0,
-		.fifo_size	= 0x0,
+		.name		= "VID A",
+		.cmds_start	= 0x10000,
+		.ctrl_start	= 0x105b0,
+		.cdt		= 0x107b0,
+		.fifo_start	= 0x40,
+		.fifo_size	= 0x2800,
 		.ptr1_reg	= DMA1_PTR1,
 		.ptr2_reg	= DMA1_PTR2,
 		.cnt1_reg	= DMA1_CNT1,
@@ -231,12 +233,12 @@ struct sram_channel cx23887_sram_channels[] = {
 		.cnt2_reg	= DMA2_CNT2,
 	},
 	[SRAM_CH03] = {
-		.name		= "ch3",
-		.cmds_start	= 0x0,
-		.ctrl_start	= 0x0,
-		.cdt		= 0x0,
-		.fifo_start	= 0x0,
-		.fifo_size	= 0x0,
+		.name		= "TS1 B",
+		.cmds_start	= 0x100A0,
+		.ctrl_start	= 0x10780,
+		.cdt		= 0x10400,
+		.fifo_start	= 0x5000,
+		.fifo_size	= 0x1000,
 		.ptr1_reg	= DMA3_PTR1,
 		.ptr2_reg	= DMA3_PTR2,
 		.cnt1_reg	= DMA3_CNT1,
@@ -357,7 +359,7 @@ static int cx23885_risc_decode(u32 risc)
 }
 
 void cx23885_wakeup(struct cx23885_tsport *port,
-		    struct cx23885_dmaqueue *q, u32 count)
+			   struct cx23885_dmaqueue *q, u32 count)
 {
 	struct cx23885_dev *dev = port->dev;
 	struct cx23885_buffer *buf;
@@ -378,7 +380,7 @@ void cx23885_wakeup(struct cx23885_tsport *port,
 		do_gettimeofday(&buf->vb.ts);
 		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
 			count, buf->count);
-		buf->vb.state = STATE_DONE;
+		buf->vb.state = VIDEOBUF_DONE;
 		list_del(&buf->vb.queue);
 		wake_up(&buf->vb.done);
 	}
@@ -391,12 +393,10 @@ void cx23885_wakeup(struct cx23885_tsport *port,
 		printk("%s: %d buffers handled (should be 1)\n",
 		       __FUNCTION__, bc);
 }
-void cx23885_sram_channel_dump(struct cx23885_dev *dev,
-			       struct sram_channel *ch);
 
 int cx23885_sram_channel_setup(struct cx23885_dev *dev,
-			       struct sram_channel *ch,
-			       unsigned int bpl, u32 risc)
+				      struct sram_channel *ch,
+				      unsigned int bpl, u32 risc)
 {
 	unsigned int i, lines;
 	u32 cdt;
@@ -468,7 +468,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
 }
 
 void cx23885_sram_channel_dump(struct cx23885_dev *dev,
-			       struct sram_channel *ch)
+				      struct sram_channel *ch)
 {
 	static char *name[] = {
 		"init risc lo",
@@ -529,8 +529,8 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
 	       dev->name, cx_read(ch->cnt2_reg));
 }
 
-void cx23885_risc_disasm(struct cx23885_tsport *port,
-			 struct btcx_riscmem *risc)
+static void cx23885_risc_disasm(struct cx23885_tsport *port,
+				struct btcx_riscmem *risc)
 {
 	struct cx23885_dev *dev = port->dev;
 	unsigned int i, j, n;
@@ -548,7 +548,7 @@ void cx23885_risc_disasm(struct cx23885_tsport *port,
 	}
 }
 
-void cx23885_shutdown(struct cx23885_dev *dev)
+static void cx23885_shutdown(struct cx23885_dev *dev)
 {
 	/* disable RISC controller */
 	cx_write(DEV_CNTRL2, 0);
@@ -578,7 +578,7 @@ void cx23885_shutdown(struct cx23885_dev *dev)
 
 }
 
-void cx23885_reset(struct cx23885_dev *dev)
+static void cx23885_reset(struct cx23885_dev *dev)
 {
 	dprintk(1, "%s()\n", __FUNCTION__);
 
@@ -594,15 +594,18 @@ void cx23885_reset(struct cx23885_dev *dev)
 
 	mdelay(100);
 
-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0);
-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0);
-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0);
-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0);
-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0);
-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0);
-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0);
-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0);
-	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
+		720*4, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03],
+		188*4, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06],
+		188*4, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0);
 
 	cx23885_gpio_setup(dev);
 }
@@ -637,7 +640,7 @@ static int get_resources(struct cx23885_dev *dev)
 
 static void cx23885_timeout(unsigned long data);
 int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-			 u32 reg, u32 mask, u32 value);
+				u32 reg, u32 mask, u32 value);
 
 static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
 {
@@ -704,6 +707,44 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p
 	return 0;
 }
 
+static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
+{
+	switch (cx_read(RDR_CFG2) & 0xff) {
+	case 0x00:
+		/* cx23885 */
+		dev->hwrevision = 0xa0;
+		break;
+	case 0x01:
+		/* CX23885-12Z */
+		dev->hwrevision = 0xa1;
+		break;
+	case 0x02:
+		/* CX23885-13Z */
+		dev->hwrevision = 0xb0;
+		break;
+	case 0x03:
+		/* CX23888-22Z */
+		dev->hwrevision = 0xc0;
+		break;
+	case 0x0e:
+		/* CX23887-15Z */
+		dev->hwrevision = 0xc0;
+	case 0x0f:
+		/* CX23887-14Z */
+		dev->hwrevision = 0xb1;
+		break;
+	default:
+		printk(KERN_ERR "%s() New hardware revision found 0x%x\n",
+			__FUNCTION__, dev->hwrevision);
+	}
+	if (dev->hwrevision)
+		printk(KERN_INFO "%s() Hardware revision = 0x%02x\n",
+			__FUNCTION__, dev->hwrevision);
+	else
+		printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n",
+			__FUNCTION__, dev->hwrevision);
+}
+
 static int cx23885_dev_setup(struct cx23885_dev *dev)
 {
 	int i;
@@ -723,10 +764,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
 	if(dev->pci->device == 0x8880) {
 		dev->bridge = CX23885_BRIDGE_887;
 		dev->sram_channels = cx23887_sram_channels;
+		/* Apply a sensible clock frequency for the PCIe bridge */
+		dev->clk_freq = 25000000;
 	} else
 	if(dev->pci->device == 0x8852) {
 		dev->bridge = CX23885_BRIDGE_885;
 		dev->sram_channels = cx23885_sram_channels;
+		/* Apply a sensible clock frequency for the PCIe bridge */
+		dev->clk_freq = 28000000;
 	} else
 		BUG();
 
@@ -746,6 +791,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
 		cx23885_card_list(dev);
 	}
 
+	/* If the user specific a clk freq override, apply it */
+	if (cx23885_boards[dev->board].clk_freq > 0)
+		dev->clk_freq = cx23885_boards[dev->board].clk_freq;
+
 	dev->pci_bus  = dev->pci->bus->number;
 	dev->pci_slot = PCI_SLOT(dev->pci->devfn);
 	dev->pci_irqmask = 0x001f00;
@@ -810,6 +859,17 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
 
 	cx23885_pci_quirks(dev);
 
+	/* Assume some sensible defaults */
+	dev->tuner_type = cx23885_boards[dev->board].tuner_type;
+	dev->tuner_addr = cx23885_boards[dev->board].tuner_addr;
+	dev->radio_type = cx23885_boards[dev->board].radio_type;
+	dev->radio_addr = cx23885_boards[dev->board].radio_addr;
+
+	dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n",
+		__FUNCTION__, dev->tuner_type, dev->tuner_addr);
+	dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
+		__FUNCTION__, dev->radio_type, dev->radio_addr);
+
 	/* init hardware */
 	cx23885_reset(dev);
 
@@ -820,24 +880,33 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
 	cx23885_card_setup(dev);
 	cx23885_ir_init(dev);
 
-	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
+	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
+		if (cx23885_video_register(dev) < 0) {
+			printk(KERN_ERR "%s() Failed to register analog "
+				"video adapters on VID_A\n", __FUNCTION__);
+		}
+	}
+
+	if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
 		if (cx23885_dvb_register(&dev->ts1) < 0) {
 			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
 			       __FUNCTION__);
 		}
 	}
 
-	if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
+	if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
 		if (cx23885_dvb_register(&dev->ts2) < 0) {
 			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n",
 			       __FUNCTION__);
 		}
 	}
 
+	cx23885_dev_checkrevision(dev);
+
 	return 0;
 }
 
-void cx23885_dev_unregister(struct cx23885_dev *dev)
+static void cx23885_dev_unregister(struct cx23885_dev *dev)
 {
 	release_mem_region(pci_resource_start(dev->pci,0),
 			   pci_resource_len(dev->pci,0));
@@ -845,6 +914,9 @@ void cx23885_dev_unregister(struct cx23885_dev *dev)
 	if (!atomic_dec_and_test(&dev->refcount))
 		return;
 
+	if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO)
+		cx23885_video_unregister(dev);
+
 	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
 		cx23885_dvb_unregister(&dev->ts1);
 
@@ -952,9 +1024,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 	return 0;
 }
 
-int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
-			    struct scatterlist *sglist, unsigned int bpl,
-			    unsigned int lines)
+static int cx23885_risc_databuffer(struct pci_dev *pci,
+				   struct btcx_riscmem *risc,
+				   struct scatterlist *sglist,
+				   unsigned int bpl,
+				   unsigned int lines)
 {
 	u32 instructions;
 	u32 *rp;
@@ -982,7 +1056,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 }
 
 int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
-			 u32 reg, u32 mask, u32 value)
+				u32 reg, u32 mask, u32 value)
 {
 	u32 *rp;
 	int rc;
@@ -1011,7 +1085,58 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
 	videobuf_dma_unmap(q, dma);
 	videobuf_dma_free(dma);
 	btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
-	buf->vb.state = STATE_NEEDS_INIT;
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+
+	dprintk(1, "%s() Register Dump\n", __FUNCTION__);
+	dprintk(1, "%s() DEV_CNTRL2               0x%08X\n", __FUNCTION__,
+		cx_read(DEV_CNTRL2));
+	dprintk(1, "%s() PCI_INT_MSK              0x%08X\n", __FUNCTION__,
+		cx_read(PCI_INT_MSK));
+	dprintk(1, "%s() AUD_INT_INT_MSK          0x%08X\n", __FUNCTION__,
+		cx_read(AUDIO_INT_INT_MSK));
+	dprintk(1, "%s() AUD_INT_DMA_CTL          0x%08X\n", __FUNCTION__,
+		cx_read(AUD_INT_DMA_CTL));
+	dprintk(1, "%s() AUD_EXT_INT_MSK          0x%08X\n", __FUNCTION__,
+		cx_read(AUDIO_EXT_INT_MSK));
+	dprintk(1, "%s() AUD_EXT_DMA_CTL          0x%08X\n", __FUNCTION__,
+		cx_read(AUD_EXT_DMA_CTL));
+	dprintk(1, "%s() PAD_CTRL                 0x%08X\n", __FUNCTION__,
+		cx_read(PAD_CTRL));
+	dprintk(1, "%s() ALT_PIN_OUT_SEL          0x%08X\n", __FUNCTION__,
+		cx_read(ALT_PIN_OUT_SEL));
+	dprintk(1, "%s() GPIO2                    0x%08X\n", __FUNCTION__,
+		cx_read(GPIO2));
+	dprintk(1, "%s() gpcnt(0x%08X)          0x%08X\n", __FUNCTION__,
+		port->reg_gpcnt, cx_read(port->reg_gpcnt));
+	dprintk(1, "%s() gpcnt_ctl(0x%08X)      0x%08x\n", __FUNCTION__,
+		port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl));
+	dprintk(1, "%s() dma_ctl(0x%08X)        0x%08x\n", __FUNCTION__,
+		port->reg_dma_ctl, cx_read(port->reg_dma_ctl));
+	dprintk(1, "%s() src_sel(0x%08X)        0x%08x\n", __FUNCTION__,
+		port->reg_src_sel, cx_read(port->reg_src_sel));
+	dprintk(1, "%s() lngth(0x%08X)          0x%08x\n", __FUNCTION__,
+		port->reg_lngth, cx_read(port->reg_lngth));
+	dprintk(1, "%s() hw_sop_ctrl(0x%08X)    0x%08x\n", __FUNCTION__,
+		port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl));
+	dprintk(1, "%s() gen_ctrl(0x%08X)       0x%08x\n", __FUNCTION__,
+		port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl));
+	dprintk(1, "%s() bd_pkt_status(0x%08X)  0x%08x\n", __FUNCTION__,
+		port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status));
+	dprintk(1, "%s() sop_status(0x%08X)     0x%08x\n", __FUNCTION__,
+		port->reg_sop_status, cx_read(port->reg_sop_status));
+	dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __FUNCTION__,
+		port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat));
+	dprintk(1, "%s() vld_misc(0x%08X)       0x%08x\n", __FUNCTION__,
+		port->reg_vld_misc, cx_read(port->reg_vld_misc));
+	dprintk(1, "%s() ts_clk_en(0x%08X)      0x%08x\n", __FUNCTION__,
+		port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
+	dprintk(1, "%s() ts_int_msk(0x%08X)     0x%08x\n", __FUNCTION__,
+		port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
 }
 
 static int cx23885_start_dma(struct cx23885_tsport *port,
@@ -1076,6 +1201,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
 
 	cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
 
+	if (debug > 4)
+		cx23885_tsport_reg_dump(port);
+
 	return 0;
 }
 
@@ -1091,7 +1219,7 @@ static int cx23885_stop_dma(struct cx23885_tsport *port)
 	return 0;
 }
 
-static int cx23885_restart_queue(struct cx23885_tsport *port,
+int cx23885_restart_queue(struct cx23885_tsport *port,
 				struct cx23885_dmaqueue *q)
 {
 	struct cx23885_dev *dev = port->dev;
@@ -1114,7 +1242,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port,
 				list_del(&buf->vb.queue);
 				list_add_tail(&buf->vb.queue, &q->active);
 				cx23885_start_dma(port, q, buf);
-				buf->vb.state = STATE_ACTIVE;
+				buf->vb.state = VIDEOBUF_ACTIVE;
 				buf->count    = q->count++;
 				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
 				dprintk(5, "[%p/%d] restart_queue - first active\n",
@@ -1125,7 +1253,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port,
 				   prev->fmt       == buf->fmt) {
 				list_del(&buf->vb.queue);
 				list_add_tail(&buf->vb.queue, &q->active);
-				buf->vb.state = STATE_ACTIVE;
+				buf->vb.state = VIDEOBUF_ACTIVE;
 				buf->count    = q->count++;
 				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 				prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
@@ -1162,7 +1290,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
 		return -EINVAL;
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		buf->vb.width  = port->ts_packet_size;
 		buf->vb.height = port->ts_packet_count;
 		buf->vb.size   = size;
@@ -1174,7 +1302,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
 					videobuf_to_dma(&buf->vb)->sglist,
 					buf->vb.width, buf->vb.height);
 	}
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	return 0;
 
  fail:
@@ -1197,7 +1325,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
 		dprintk( 1, "queue is empty - first active\n" );
 		list_add_tail(&buf->vb.queue, &cx88q->active);
 		cx23885_start_dma(port, cx88q, buf);
-		buf->vb.state = STATE_ACTIVE;
+		buf->vb.state = VIDEOBUF_ACTIVE;
 		buf->count    = cx88q->count++;
 		mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
 		dprintk(1, "[%p/%d] %s - first active\n",
@@ -1207,7 +1335,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
 		prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
 				  vb.queue);
 		list_add_tail(&buf->vb.queue, &cx88q->active);
-		buf->vb.state = STATE_ACTIVE;
+		buf->vb.state = VIDEOBUF_ACTIVE;
 		buf->count    = cx88q->count++;
 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 		prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
@@ -1231,7 +1359,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
 		buf = list_entry(q->active.next, struct cx23885_buffer,
 				 vb.queue);
 		list_del(&buf->vb.queue);
-		buf->vb.state = STATE_ERROR;
+		buf->vb.state = VIDEOBUF_ERROR;
 		wake_up(&buf->vb.done);
 		dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
 			buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
@@ -1243,16 +1371,6 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
 	spin_unlock_irqrestore(&port->slock, flags);
 }
 
-void cx23885_cancel_buffers(struct cx23885_tsport *port)
-{
-	struct cx23885_dev *dev = port->dev;
-	struct cx23885_dmaqueue *q = &port->mpegq;
-
-	dprintk(1, "%s()\n", __FUNCTION__);
-	del_timer_sync(&q->timeout);
-	cx23885_stop_dma(port);
-	do_cancel_buffers(port, "cancel", 0);
-}
 
 static void cx23885_timeout(unsigned long data)
 {
@@ -1325,12 +1443,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
 	struct cx23885_tsport *ts1 = &dev->ts1;
 	struct cx23885_tsport *ts2 = &dev->ts2;
 	u32 pci_status, pci_mask;
+	u32 vida_status, vida_mask;
 	u32 ts1_status, ts1_mask;
 	u32 ts2_status, ts2_mask;
-	int ts1_count = 0, ts2_count = 0, handled = 0;
+	int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
 
 	pci_status = cx_read(PCI_INT_STAT);
 	pci_mask = cx_read(PCI_INT_MSK);
+	vida_status = cx_read(VID_A_INT_STAT);
+	vida_mask = cx_read(VID_A_INT_MSK);
 	ts1_status = cx_read(VID_B_INT_STAT);
 	ts1_mask = cx_read(VID_B_INT_MSK);
 	ts2_status = cx_read(VID_C_INT_STAT);
@@ -1339,11 +1460,17 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
 	if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) )
 		goto out;
 
+	vida_count = cx_read(VID_A_GPCNT);
 	ts1_count = cx_read(ts1->reg_gpcnt);
 	ts2_count = cx_read(ts2->reg_gpcnt);
-	dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n", pci_status, pci_mask );
-	dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count );
-	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count );
+	dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n",
+		pci_status, pci_mask);
+	dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n",
+		vida_status, vida_mask, vida_count);
+	dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n",
+		ts1_status, ts1_mask, ts1_count);
+	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n",
+		ts2_status, ts2_mask, ts2_count);
 
 	if ( (pci_status & PCI_MSK_RISC_RD) ||
 	     (pci_status & PCI_MSK_RISC_WR) ||
@@ -1380,11 +1507,18 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
 
 	}
 
-	if (ts1_status)
-		handled += cx23885_irq_ts(ts1, ts1_status);
+	if (ts1_status) {
+		if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+			handled += cx23885_irq_ts(ts1, ts1_status);
+	}
+
+	if (ts2_status) {
+		if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+			handled += cx23885_irq_ts(ts2, ts2_status);
+	}
 
-	if (ts2_status)
-		handled += cx23885_irq_ts(ts2, ts2_status);
+	if (vida_status)
+		handled += cx23885_video_irq(dev, vida_status);
 
 	if (handled)
 		cx_write(PCI_INT_STAT, pci_status);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index eda8c05d0931..ed465c007cea 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -32,13 +32,26 @@
 
 #include "s5h1409.h"
 #include "mt2131.h"
+#include "tda8290.h"
+#include "tda18271.h"
 #include "lgdt330x.h"
+#include "xc5000.h"
 #include "dvb-pll.h"
+#include "tuner-xc2028.h"
+#include "tuner-xc2028-types.h"
 
-static unsigned int debug = 0;
+static unsigned int debug;
 
-#define dprintk(level,fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg)
+#define dprintk(level, fmt, arg...)\
+	do { if (debug >= level)\
+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+	} while (0)
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int alt_tuner;
+module_param(alt_tuner, int, 0644);
+MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
 
 /* ------------------------------------------------------------------ */
 
@@ -85,18 +98,39 @@ static struct s5h1409_config hauppauge_generic_config = {
 	.demod_address = 0x32 >> 1,
 	.output_mode   = S5H1409_SERIAL_OUTPUT,
 	.gpio          = S5H1409_GPIO_ON,
-	.if_freq       = 44000,
+	.qam_if        = 44000,
 	.inversion     = S5H1409_INVERSION_OFF,
-	.status_mode   = S5H1409_DEMODLOCKING
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config hauppauge_ezqam_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_OFF,
+	.qam_if        = 4000,
+	.inversion     = S5H1409_INVERSION_ON,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
 static struct s5h1409_config hauppauge_hvr1800lp_config = {
 	.demod_address = 0x32 >> 1,
 	.output_mode   = S5H1409_SERIAL_OUTPUT,
 	.gpio          = S5H1409_GPIO_OFF,
-	.if_freq       = 44000,
+	.qam_if        = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config hauppauge_hvr1500_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_OFF,
 	.inversion     = S5H1409_INVERSION_OFF,
-	.status_mode   = S5H1409_DEMODLOCKING
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
 static struct mt2131_config hauppauge_generic_tunerconfig = {
@@ -109,6 +143,66 @@ static struct lgdt330x_config fusionhdtv_5_express = {
 	.serial_mpeg = 0x40,
 };
 
+static struct s5h1409_config hauppauge_hvr1500q_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_ON,
+	.qam_if        = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
+	.i2c_address      = 0x61,
+	.if_khz           = 5380,
+	.tuner_callback   = cx23885_tuner_callback
+};
+
+static struct tda829x_config tda829x_no_probe = {
+	.probe_tuner = TDA829X_DONT_PROBE,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+	.atsc_6   = { .if_freq = 5380, .std_bits = 0x1b },
+	.qam_6    = { .if_freq = 4000, .std_bits = 0x18 },
+};
+
+static struct tda18271_config hauppauge_tda18271_config = {
+	.std_map = &hauppauge_tda18271_std_map,
+	.gate    = TDA18271_GATE_ANALOG,
+};
+
+static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
+{
+	struct cx23885_tsport *port = ptr;
+	struct cx23885_dev *dev = port->dev;
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+		/* Send the tuner in then out of reset */
+		/* GPIO-2 xc3028 tuner */
+		dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+
+		cx_set(GP0_IO, 0x00040000);
+		cx_clear(GP0_IO, 0x00000004);
+		msleep(5);
+
+		cx_set(GP0_IO, 0x00040004);
+		msleep(5);
+		break;
+	case XC2028_RESET_CLK:
+		dprintk(1, "%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+		break;
+	default:
+		dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__,
+			command, arg);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int dvb_register(struct cx23885_tsport *port)
 {
 	struct cx23885_dev *dev = port->dev;
@@ -120,7 +214,6 @@ static int dvb_register(struct cx23885_tsport *port)
 	/* init frontend */
 	switch (dev->board) {
 	case CX23885_BOARD_HAUPPAUGE_HVR1250:
-	case CX23885_BOARD_HAUPPAUGE_HVR1800:
 		i2c_bus = &dev->i2c_bus[0];
 		port->dvb.frontend = dvb_attach(s5h1409_attach,
 						&hauppauge_generic_config,
@@ -131,6 +224,36 @@ static int dvb_register(struct cx23885_tsport *port)
 				   &hauppauge_generic_tunerconfig, 0);
 		}
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+		i2c_bus = &dev->i2c_bus[0];
+		switch (alt_tuner) {
+		case 1:
+			port->dvb.frontend =
+				dvb_attach(s5h1409_attach,
+					   &hauppauge_ezqam_config,
+					   &i2c_bus->i2c_adap);
+			if (port->dvb.frontend != NULL) {
+				dvb_attach(tda829x_attach, port->dvb.frontend,
+					   &dev->i2c_bus[1].i2c_adap, 0x42,
+					   &tda829x_no_probe);
+				dvb_attach(tda18271_attach, port->dvb.frontend,
+					   0x60, &dev->i2c_bus[1].i2c_adap,
+					   &hauppauge_tda18271_config);
+			}
+			break;
+		case 0:
+		default:
+			port->dvb.frontend =
+				dvb_attach(s5h1409_attach,
+					   &hauppauge_generic_config,
+					   &i2c_bus->i2c_adap);
+			if (port->dvb.frontend != NULL)
+				dvb_attach(mt2131_attach, port->dvb.frontend,
+					   &i2c_bus->i2c_adap,
+					   &hauppauge_generic_tunerconfig, 0);
+			break;
+		}
+		break;
 	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
 		i2c_bus = &dev->i2c_bus[0];
 		port->dvb.frontend = dvb_attach(s5h1409_attach,
@@ -152,6 +275,43 @@ static int dvb_register(struct cx23885_tsport *port)
 				   &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
 		}
 		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+		i2c_bus = &dev->i2c_bus[1];
+		port->dvb.frontend = dvb_attach(s5h1409_attach,
+						&hauppauge_hvr1500q_config,
+						&dev->i2c_bus[0].i2c_adap);
+		if (port->dvb.frontend != NULL) {
+			hauppauge_hvr1500q_tunerconfig.priv = i2c_bus;
+			dvb_attach(xc5000_attach, port->dvb.frontend,
+				&i2c_bus->i2c_adap,
+				&hauppauge_hvr1500q_tunerconfig);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1500:
+		i2c_bus = &dev->i2c_bus[1];
+		port->dvb.frontend = dvb_attach(s5h1409_attach,
+						&hauppauge_hvr1500_config,
+						&dev->i2c_bus[0].i2c_adap);
+		if (port->dvb.frontend != NULL) {
+			struct dvb_frontend *fe;
+			struct xc2028_config cfg = {
+				.i2c_adap  = &i2c_bus->i2c_adap,
+				.i2c_addr  = 0x61,
+				.video_dev = port,
+				.callback  = cx23885_hvr1500_xc3028_callback,
+			};
+			static struct xc2028_ctrl ctl = {
+				.fname       = "xc3028-v27.fw",
+				.max_len     = 64,
+				.scode_table = OREN538,
+			};
+
+			fe = dvb_attach(xc2028_attach,
+					port->dvb.frontend, &cfg);
+			if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+				fe->ops.tuner_ops.set_config(fe, &ctl);
+		}
+		break;
 	default:
 		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->name);
@@ -165,6 +325,9 @@ static int dvb_register(struct cx23885_tsport *port)
 	/* Put the analog decoder in standby to keep it quiet */
 	cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
 
+	if (port->dvb.frontend->ops.analog_ops.standby)
+		port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend);
+
 	/* register everything */
 	return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
 				     &dev->pci->dev);
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index 71da528932df..92fe0bd37c84 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -29,7 +29,7 @@
 
 #include <media/v4l2-common.h>
 
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
 module_param(i2c_debug, int, 0644);
 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
 
@@ -37,8 +37,10 @@ static unsigned int i2c_scan = 0;
 module_param(i2c_scan, int, 0444);
 MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
 
-#define dprintk(level,fmt, arg...)	if (i2c_debug >= level) \
-	printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
+#define dprintk(level, fmt, arg...)\
+	do { if (i2c_debug >= level)\
+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+	} while (0)
 
 #define I2C_WAIT_DELAY 32
 #define I2C_WAIT_RETRY 64
@@ -77,14 +79,19 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap)
 }
 
 static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
-			 const struct i2c_msg *msg, int last)
+			 const struct i2c_msg *msg, int joined_rlen)
 {
 	struct cx23885_i2c *bus = i2c_adap->algo_data;
 	struct cx23885_dev *dev = bus->dev;
 	u32 wdata, addr, ctrl;
 	int retval, cnt;
 
-	dprintk(1, "%s()\n", __FUNCTION__);
+	if (joined_rlen)
+		dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__,
+			msg->len, joined_rlen);
+	else
+		dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
+
 	/* Deal with i2c probe functions with zero payload */
 	if (msg->len == 0) {
 		cx_write(bus->reg_addr, msg->addr << 25);
@@ -106,6 +113,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
 
 	if (msg->len > 1)
 		ctrl |= I2C_NOSTOP | I2C_EXTEND;
+	else if (joined_rlen)
+		ctrl |= I2C_NOSTOP;
 
 	cx_write(bus->reg_addr, addr);
 	cx_write(bus->reg_wdata, wdata);
@@ -127,8 +136,10 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
 		wdata = msg->buf[cnt];
 		ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
 
-		if (cnt < msg->len-1 || !last)
+		if (cnt < msg->len - 1)
 			ctrl |= I2C_NOSTOP | I2C_EXTEND;
+		else if (joined_rlen)
+			ctrl |= I2C_NOSTOP;
 
 		cx_write(bus->reg_addr, addr);
 		cx_write(bus->reg_wdata, wdata);
@@ -150,19 +161,22 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
  eio:
 	retval = -EIO;
  err:
-	printk(" ERR: %d\n", retval);
+	if (i2c_debug)
+		printk(" ERR: %d\n", retval);
 	return retval;
 }
 
 static int i2c_readbytes(struct i2c_adapter *i2c_adap,
-			 const struct i2c_msg *msg, int last)
+			 const struct i2c_msg *msg, int joined)
 {
 	struct cx23885_i2c *bus = i2c_adap->algo_data;
 	struct cx23885_dev *dev = bus->dev;
 	u32 ctrl, cnt;
 	int retval;
 
-	dprintk(1, "%s()\n", __FUNCTION__);
+
+	if (i2c_debug && !joined)
+		dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
 
 	/* Deal with i2c probe functions with zero payload */
 	if (msg->len == 0) {
@@ -178,11 +192,18 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
 		return 0;
 	}
 
+	if (i2c_debug) {
+		if (joined)
+			printk(" R");
+		else
+			printk(" <R %02x", (msg->addr << 1) + 1);
+	}
+
 	for(cnt = 0; cnt < msg->len; cnt++) {
 
 		ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
 
-		if (cnt < msg->len-1 || !last)
+		if (cnt < msg->len - 1)
 			ctrl |= I2C_NOSTOP | I2C_EXTEND;
 
 		cx_write(bus->reg_addr, msg->addr << 25);
@@ -195,9 +216,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
 			goto eio;
 		msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
 		if (i2c_debug) {
-			if (!(ctrl & I2C_NOSTOP))
-				printk(" <R %02x", (msg->addr << 1) +1);
-			printk(" =%02x", msg->buf[cnt]);
+			printk(" %02x", msg->buf[cnt]);
 			if (!(ctrl & I2C_NOSTOP))
 				printk(" >\n");
 		}
@@ -207,7 +226,8 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
  eio:
 	retval = -EIO;
  err:
-	printk(" ERR: %d\n", retval);
+	if (i2c_debug)
+		printk(" ERR: %d\n", retval);
 	return retval;
 }
 
@@ -225,15 +245,22 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
 			__FUNCTION__, num, msgs[i].addr, msgs[i].len);
 		if (msgs[i].flags & I2C_M_RD) {
 			/* read */
-			retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num);
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
+		} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+			   msgs[i].addr == msgs[i + 1].addr) {
+			/* write then read from same address */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i],
+					       msgs[i + 1].len);
 			if (retval < 0)
 				goto err;
+			i++;
+			retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
 		} else {
 			/* write */
-			retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num);
-			if (retval < 0)
-				goto err;
+			retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
 		}
+		if (retval < 0)
+			goto err;
 	}
 	return num;
 
@@ -243,7 +270,9 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
 
 static int attach_inform(struct i2c_client *client)
 {
-	struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
+	struct cx23885_i2c *bus = i2c_get_adapdata(client->adapter);
+	struct cx23885_dev *dev = bus->dev;
+	struct tuner_setup tun_setup;
 
 	dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
 		client->driver->driver.name, client->addr, client->name);
@@ -251,6 +280,31 @@ static int attach_inform(struct i2c_client *client)
 	if (!client->driver->command)
 		return 0;
 
+	if (dev->tuner_type != UNSET) {
+
+		dprintk(1, "%s  (tuner) i2c attach [addr=0x%x,client=%s]\n",
+			client->driver->driver.name, client->addr,
+			client->name);
+
+		if ((dev->tuner_addr == ADDR_UNSET) ||
+			(dev->tuner_addr == client->addr)) {
+
+			dprintk(1, "%s (tuner || addr UNSET)\n",
+				client->driver->driver.name);
+
+			dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+				client->driver->driver.name,
+				client->addr, client->name);
+
+			tun_setup.mode_mask = T_ANALOG_TV;
+			tun_setup.type = dev->tuner_type;
+			tun_setup.addr = dev->tuner_addr;
+
+			client->driver->command(client, TUNER_SET_TYPE_ADDR,
+				&tun_setup);
+		}
+	}
+
 	return 0;
 }
 
@@ -289,6 +343,7 @@ static struct i2c_adapter cx23885_i2c_adap_template = {
 	.owner             = THIS_MODULE,
 	.id                = I2C_HW_B_CX23885,
 	.algo              = &cx23885_i2c_algo_template,
+	.class             = I2C_CLASS_TV_ANALOG,
 	.client_register   = attach_inform,
 	.client_unregister = detach_inform,
 };
@@ -305,7 +360,7 @@ static char *i2c_devs[128] = {
 	[ 0x84 >> 1 ] = "tda8295",
 	[ 0xa0 >> 1 ] = "eeprom",
 	[ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
-	[ 0xc2 >> 1 ] = "tuner/mt2131/tda8275",
+	[ 0xc2 >> 1 ] = "tuner/mt2131/tda8275/xc5000",
 };
 
 static void do_i2c_scan(char *name, struct i2c_client *c)
@@ -344,6 +399,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
 
 	bus->i2c_algo.data = bus;
 	bus->i2c_adap.algo_data = bus;
+	i2c_set_adapdata(&bus->i2c_adap, bus);
 	i2c_add_adapter(&bus->i2c_adap);
 
 	bus->i2c_client.adapter = &bus->i2c_adap;
@@ -366,8 +422,6 @@ int cx23885_i2c_unregister(struct cx23885_i2c *bus)
 
 /* ----------------------------------------------------------------------- */
 
-EXPORT_SYMBOL(cx23885_call_i2c_clients);
-
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
index 162169f9091b..bdd11bc513ad 100644
--- a/drivers/media/video/cx23885/cx23885-reg.h
+++ b/drivers/media/video/cx23885/cx23885-reg.h
@@ -233,6 +233,17 @@ Channel manager Data Structure entry = 20 DWORD
 #define VID_A_INT_SSTAT	0x0004002C
 
 #define VID_B_INT_MSK	0x00040030
+#define VID_B_MSK_BAD_PKT     (1 << 20)
+#define VID_B_MSK_VBI_OPC_ERR (1 << 17)
+#define VID_B_MSK_OPC_ERR     (1 << 16)
+#define VID_B_MSK_VBI_SYNC    (1 << 13)
+#define VID_B_MSK_SYNC        (1 << 12)
+#define VID_B_MSK_VBI_OF      (1 <<  9)
+#define VID_B_MSK_OF          (1 <<  8)
+#define VID_B_MSK_VBI_RISCI2  (1 <<  5)
+#define VID_B_MSK_RISCI2      (1 <<  4)
+#define VID_B_MSK_VBI_RISCI1  (1 <<  1)
+#define VID_B_MSK_RISCI1       1
 #define VID_B_INT_STAT	0x00040034
 #define VID_B_INT_MSTAT	0x00040038
 #define VID_B_INT_SSTAT	0x0004003C
@@ -276,6 +287,7 @@ Channel manager Data Structure entry = 20 DWORD
 
 #define RDR_CFG0	0x00050000
 #define RDR_CFG1	0x00050004
+#define RDR_CFG2	0x00050008
 #define RDR_TLCTL0	0x00050318
 
 /* APB DMAC Current Buffer Pointer */
@@ -335,6 +347,7 @@ Channel manager Data Structure entry = 20 DWORD
 /* GPIO (417 Microsoftcontroller) Output Enable, Low Active */
 #define MC417_OEN	0x00110024
 #define MC417_CTL	0x00110028
+#define ALT_PIN_OUT_SEL 0x0011002C
 #define CLK_DELAY	0x00110048
 #define PAD_CTRL	0x0011004C
 
diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c
new file mode 100644
index 000000000000..e36e3fcae2fb
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-vbi.c
@@ -0,0 +1,258 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *
+ *  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/slab.h>
+
+#include "cx23885.h"
+
+static unsigned int vbibufs = 4;
+module_param(vbibufs, int, 0644);
+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
+
+static unsigned int vbi_debug;
+module_param(vbi_debug, int, 0644);
+MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
+
+#define dprintk(level, fmt, arg...)\
+	do { if (vbi_debug >= level)\
+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+	} while (0)
+
+/* ------------------------------------------------------------------ */
+
+int cx23885_vbi_fmt(struct file *file, void *priv,
+	struct v4l2_format *f)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (dev->tvnorm & V4L2_STD_525_60) {
+		/* ntsc */
+		f->fmt.vbi.sampling_rate = 28636363;
+		f->fmt.vbi.start[0] = 10;
+		f->fmt.vbi.start[1] = 273;
+
+	} else if (dev->tvnorm & V4L2_STD_625_50) {
+		/* pal */
+		f->fmt.vbi.sampling_rate = 35468950;
+		f->fmt.vbi.start[0] = 7 - 1;
+		f->fmt.vbi.start[1] = 319 - 1;
+	}
+	return 0;
+}
+
+static int cx23885_start_vbi_dma(struct cx23885_dev    *dev,
+			 struct cx23885_dmaqueue *q,
+			 struct cx23885_buffer   *buf)
+{
+	/* setup fifo + format */
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
+				buf->vb.width, buf->risc.dma);
+
+	/* reset counter */
+	q->count = 1;
+
+	/* enable irqs */
+	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);
+	cx_set(VID_A_INT_MSK, 0x000022);
+
+	/* start dma */
+	cx_set(DEV_CNTRL2, (1<<5));
+	cx_set(VID_A_DMA_CTL, 0x00000022);
+
+	return 0;
+}
+
+int cx23885_stop_vbi_dma(struct cx23885_dev *dev)
+{
+	/* stop dma */
+	cx_clear(VID_A_DMA_CTL, 0x00000022);
+
+	/* disable irqs */
+	cx_clear(PCI_INT_MSK, 0x000001);
+	cx_clear(VID_A_INT_MSK, 0x00000022);
+	return 0;
+}
+
+int cx23885_restart_vbi_queue(struct cx23885_dev    *dev,
+			     struct cx23885_dmaqueue *q)
+{
+	struct cx23885_buffer *buf;
+	struct list_head *item;
+
+	if (list_empty(&q->active))
+		return 0;
+
+	buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
+	dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+		buf, buf->vb.i);
+	cx23885_start_vbi_dma(dev, q, buf);
+	list_for_each(item, &q->active) {
+		buf = list_entry(item, struct cx23885_buffer, vb.queue);
+		buf->count = q->count++;
+	}
+	mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+	return 0;
+}
+
+void cx23885_vbi_timeout(unsigned long data)
+{
+	struct cx23885_dev *dev = (struct cx23885_dev *)data;
+	struct cx23885_dmaqueue *q = &dev->vbiq;
+	struct cx23885_buffer *buf;
+	unsigned long flags;
+
+	cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]);
+
+	cx_clear(VID_A_DMA_CTL, 0x22);
+
+	spin_lock_irqsave(&dev->slock, flags);
+	while (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx23885_buffer,
+			vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name,
+		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
+	}
+	cx23885_restart_vbi_queue(dev, q);
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+/* ------------------------------------------------------------------ */
+#define VBI_LINE_LENGTH 2048
+#define VBI_LINE_COUNT 17
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+	*size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
+	if (0 == *count)
+		*count = vbibufs;
+	if (*count < 2)
+		*count = 2;
+	if (*count > 32)
+		*count = 32;
+	return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	    enum v4l2_field field)
+{
+	struct cx23885_fh *fh  = q->priv_data;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_buffer *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+	unsigned int size;
+	int rc;
+
+	size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		buf->vb.width  = VBI_LINE_LENGTH;
+		buf->vb.height = VBI_LINE_COUNT;
+		buf->vb.size   = size;
+		buf->vb.field  = V4L2_FIELD_SEQ_TB;
+
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (0 != rc)
+			goto fail;
+		cx23885_risc_buffer(dev->pci, &buf->risc,
+				 dma->sglist,
+				 0, buf->vb.width * buf->vb.height,
+				 buf->vb.width, 0,
+				 buf->vb.height);
+	}
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+ fail:
+	cx23885_free_buffer(q, buf);
+	return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct cx23885_buffer   *buf =
+		container_of(vb, struct cx23885_buffer, vb);
+	struct cx23885_buffer   *prev;
+	struct cx23885_fh       *fh   = vq->priv_data;
+	struct cx23885_dev      *dev  = fh->dev;
+	struct cx23885_dmaqueue *q    = &dev->vbiq;
+
+	/* add jump to stopper */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+	if (list_empty(&q->active)) {
+		list_add_tail(&buf->vb.queue, &q->active);
+		cx23885_start_vbi_dma(dev, q, buf);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = q->count++;
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+		dprintk(2, "[%p/%d] vbi_queue - first active\n",
+			buf, buf->vb.i);
+
+	} else {
+		prev = list_entry(q->active.prev, struct cx23885_buffer,
+			vb.queue);
+		list_add_tail(&buf->vb.queue, &q->active);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = q->count++;
+		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+		prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */
+		dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+			buf, buf->vb.i);
+	}
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct cx23885_buffer *buf =
+		container_of(vb, struct cx23885_buffer, vb);
+
+	cx23885_free_buffer(q, buf);
+}
+
+struct videobuf_queue_ops cx23885_vbi_qops = {
+	.buf_setup    = vbi_setup,
+	.buf_prepare  = vbi_prepare,
+	.buf_queue    = vbi_queue,
+	.buf_release  = vbi_release,
+};
+
+/* ------------------------------------------------------------------ */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
new file mode 100644
index 000000000000..d3c4d2c5cbe0
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -0,0 +1,1557 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2007 Steven Toth <stoth@hauppauge.com>
+ *
+ *  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/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <asm/div64.h>
+
+#include "cx23885.h"
+#include <media/v4l2-common.h>
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+/* Include V4L1 specific functions. Should be removed soon */
+#include <linux/videodev.h>
+#endif
+
+MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
+MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[]   = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr,   int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+
+MODULE_PARM_DESC(video_nr, "video device numbers");
+MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
+
+static unsigned int video_debug;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
+
+static unsigned int irq_debug;
+module_param(irq_debug, int, 0644);
+MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
+
+static unsigned int vid_limit = 16;
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
+
+#define dprintk(level, fmt, arg...)\
+	do { if (video_debug >= level)\
+		printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\
+	} while (0)
+
+/* ------------------------------------------------------------------- */
+/* static data                                                         */
+
+#define FORMAT_FLAGS_PACKED       0x01
+
+static struct cx23885_fmt formats[] = {
+	{
+		.name     = "8 bpp, gray",
+		.fourcc   = V4L2_PIX_FMT_GREY,
+		.depth    = 8,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "15 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB555,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "15 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB555X,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "16 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_RGB565,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "16 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB565X,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "24 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR24,
+		.depth    = 24,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "32 bpp RGB, le",
+		.fourcc   = V4L2_PIX_FMT_BGR32,
+		.depth    = 32,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "32 bpp RGB, be",
+		.fourcc   = V4L2_PIX_FMT_RGB32,
+		.depth    = 32,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "4:2:2, packed, YUYV",
+		.fourcc   = V4L2_PIX_FMT_YUYV,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	}, {
+		.name     = "4:2:2, packed, UYVY",
+		.fourcc   = V4L2_PIX_FMT_UYVY,
+		.depth    = 16,
+		.flags    = FORMAT_FLAGS_PACKED,
+	},
+};
+
+static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (formats[i].fourcc == fourcc)
+			return formats+i;
+
+	printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __FUNCTION__, fourcc);
+	return NULL;
+}
+
+/* ------------------------------------------------------------------- */
+
+static const struct v4l2_queryctrl no_ctl = {
+	.name  = "42",
+	.flags = V4L2_CTRL_FLAG_DISABLED,
+};
+
+static struct cx23885_ctrl cx23885_ctls[] = {
+	/* --- video --- */
+	{
+		.v = {
+			.id            = V4L2_CID_BRIGHTNESS,
+			.name          = "Brightness",
+			.minimum       = 0x00,
+			.maximum       = 0xff,
+			.step          = 1,
+			.default_value = 0x7f,
+			.type          = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off                   = 128,
+		.reg                   = LUMA_CTRL,
+		.mask                  = 0x00ff,
+		.shift                 = 0,
+	}, {
+		.v = {
+			.id            = V4L2_CID_CONTRAST,
+			.name          = "Contrast",
+			.minimum       = 0,
+			.maximum       = 0xff,
+			.step          = 1,
+			.default_value = 0x3f,
+			.type          = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off                   = 0,
+		.reg                   = LUMA_CTRL,
+		.mask                  = 0xff00,
+		.shift                 = 8,
+	}, {
+		.v = {
+			.id            = V4L2_CID_HUE,
+			.name          = "Hue",
+			.minimum       = 0,
+			.maximum       = 0xff,
+			.step          = 1,
+			.default_value = 0x7f,
+			.type          = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off                   = 128,
+		.reg                   = CHROMA_CTRL,
+		.mask                  = 0xff0000,
+		.shift                 = 16,
+	}, {
+		/* strictly, this only describes only U saturation.
+		 * V saturation is handled specially through code.
+		 */
+		.v = {
+			.id            = V4L2_CID_SATURATION,
+			.name          = "Saturation",
+			.minimum       = 0,
+			.maximum       = 0xff,
+			.step          = 1,
+			.default_value = 0x7f,
+			.type          = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.off                   = 0,
+		.reg                   = CHROMA_CTRL,
+		.mask                  = 0x00ff,
+		.shift                 = 0,
+	}, {
+	/* --- audio --- */
+		.v = {
+			.id            = V4L2_CID_AUDIO_MUTE,
+			.name          = "Mute",
+			.minimum       = 0,
+			.maximum       = 1,
+			.default_value = 1,
+			.type          = V4L2_CTRL_TYPE_BOOLEAN,
+		},
+		.reg                   = PATH1_CTL1,
+		.mask                  = (0x1f << 24),
+		.shift                 = 24,
+	}, {
+		.v = {
+			.id            = V4L2_CID_AUDIO_VOLUME,
+			.name          = "Volume",
+			.minimum       = 0,
+			.maximum       = 0x3f,
+			.step          = 1,
+			.default_value = 0x3f,
+			.type          = V4L2_CTRL_TYPE_INTEGER,
+		},
+		.reg                   = PATH1_VOL_CTL,
+		.mask                  = 0xff,
+		.shift                 = 0,
+	}
+};
+static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
+
+const u32 cx23885_user_ctrls[] = {
+	V4L2_CID_USER_CLASS,
+	V4L2_CID_BRIGHTNESS,
+	V4L2_CID_CONTRAST,
+	V4L2_CID_SATURATION,
+	V4L2_CID_HUE,
+	V4L2_CID_AUDIO_VOLUME,
+	V4L2_CID_AUDIO_MUTE,
+	0
+};
+EXPORT_SYMBOL(cx23885_user_ctrls);
+
+static const u32 *ctrl_classes[] = {
+	cx23885_user_ctrls,
+	NULL
+};
+
+void cx23885_video_wakeup(struct cx23885_dev *dev,
+		 struct cx23885_dmaqueue *q, u32 count)
+{
+	struct cx23885_buffer *buf;
+	int bc;
+
+	for (bc = 0;; bc++) {
+		if (list_empty(&q->active))
+			break;
+		buf = list_entry(q->active.next,
+				 struct cx23885_buffer, vb.queue);
+
+		/* count comes from the hw and is is 16bit wide --
+		 * this trick handles wrap-arounds correctly for
+		 * up to 32767 buffers in flight... */
+		if ((s16) (count - buf->count) < 0)
+			break;
+
+		do_gettimeofday(&buf->vb.ts);
+		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
+			count, buf->count);
+		buf->vb.state = VIDEOBUF_DONE;
+		list_del(&buf->vb.queue);
+		wake_up(&buf->vb.done);
+	}
+	if (list_empty(&q->active)) {
+		del_timer(&q->timeout);
+	} else {
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+	}
+	if (bc != 1)
+		printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
+			__FUNCTION__, bc);
+}
+
+int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
+{
+	dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
+		__FUNCTION__,
+		(unsigned int)norm,
+		v4l2_norm_to_name(norm));
+
+	dev->tvnorm = norm;
+
+	/* Tell the analog tuner/demods */
+	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm);
+
+	/* Tell the internal A/V decoder */
+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm);
+
+	return 0;
+}
+
+struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
+				    struct pci_dev *pci,
+				    struct video_device *template,
+				    char *type)
+{
+	struct video_device *vfd;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	vfd->minor   = -1;
+	vfd->dev     = &pci->dev;
+	vfd->release = video_device_release;
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+		 dev->name, type, cx23885_boards[dev->board].name);
+	return vfd;
+}
+
+int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
+{
+	int i;
+
+	if (qctrl->id < V4L2_CID_BASE ||
+	    qctrl->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+	for (i = 0; i < CX23885_CTLS; i++)
+		if (cx23885_ctls[i].v.id == qctrl->id)
+			break;
+	if (i == CX23885_CTLS) {
+		*qctrl = no_ctl;
+		return 0;
+	}
+	*qctrl = cx23885_ctls[i].v;
+	return 0;
+}
+EXPORT_SYMBOL(cx23885_ctrl_query);
+
+/* ------------------------------------------------------------------- */
+/* resource management                                                 */
+
+static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
+	unsigned int bit)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+	if (fh->resources & bit)
+		/* have it already allocated */
+		return 1;
+
+	/* is it free? */
+	mutex_lock(&dev->lock);
+	if (dev->resources & bit) {
+		/* no, someone else uses it */
+		mutex_unlock(&dev->lock);
+		return 0;
+	}
+	/* it's free, grab it */
+	fh->resources  |= bit;
+	dev->resources |= bit;
+	dprintk(1, "res: get %d\n", bit);
+	mutex_unlock(&dev->lock);
+	return 1;
+}
+
+static int res_check(struct cx23885_fh *fh, unsigned int bit)
+{
+	return (fh->resources & bit);
+}
+
+static int res_locked(struct cx23885_dev *dev, unsigned int bit)
+{
+	return (dev->resources & bit);
+}
+
+static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
+	unsigned int bits)
+{
+	BUG_ON((fh->resources & bits) != bits);
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	mutex_lock(&dev->lock);
+	fh->resources  &= ~bits;
+	dev->resources &= ~bits;
+	dprintk(1, "res: put %d\n", bits);
+	mutex_unlock(&dev->lock);
+}
+
+int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
+{
+	struct v4l2_routing route;
+	memset(&route, 0, sizeof(route));
+
+	dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
+		__FUNCTION__,
+		input, INPUT(input)->vmux,
+		INPUT(input)->gpio0, INPUT(input)->gpio1,
+		INPUT(input)->gpio2, INPUT(input)->gpio3);
+	dev->input = input;
+
+	route.input = INPUT(input)->vmux;
+
+	/* Tell the internal A/V decoder */
+	cx23885_call_i2c_clients(&dev->i2c_bus[2],
+		VIDIOC_INT_S_VIDEO_ROUTING, &route);
+
+	return 0;
+}
+EXPORT_SYMBOL(cx23885_video_mux);
+
+/* ------------------------------------------------------------------ */
+int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
+	unsigned int height, enum v4l2_field field)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+	return 0;
+}
+
+static int cx23885_start_video_dma(struct cx23885_dev *dev,
+			   struct cx23885_dmaqueue *q,
+			   struct cx23885_buffer *buf)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	/* setup fifo + format */
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
+				buf->bpl, buf->risc.dma);
+	cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field);
+
+	/* reset counter */
+	cx_write(VID_A_GPCNT_CTL, 3);
+	q->count = 1;
+
+	/* enable irq */
+	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);
+	cx_set(VID_A_INT_MSK, 0x000011);
+
+	/* start dma */
+	cx_set(DEV_CNTRL2, (1<<5));
+	cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */
+
+	return 0;
+}
+
+
+static int cx23885_restart_video_queue(struct cx23885_dev *dev,
+			       struct cx23885_dmaqueue *q)
+{
+	struct cx23885_buffer *buf, *prev;
+	struct list_head *item;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	if (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx23885_buffer,
+			vb.queue);
+		dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+			buf, buf->vb.i);
+		cx23885_start_video_dma(dev, q, buf);
+		list_for_each(item, &q->active) {
+			buf = list_entry(item, struct cx23885_buffer,
+				vb.queue);
+			buf->count    = q->count++;
+		}
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+		return 0;
+	}
+
+	prev = NULL;
+	for (;;) {
+		if (list_empty(&q->queued))
+			return 0;
+		buf = list_entry(q->queued.next, struct cx23885_buffer,
+			vb.queue);
+		if (NULL == prev) {
+			list_move_tail(&buf->vb.queue, &q->active);
+			cx23885_start_video_dma(dev, q, buf);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count    = q->count++;
+			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+			dprintk(2, "[%p/%d] restart_queue - first active\n",
+				buf, buf->vb.i);
+
+		} else if (prev->vb.width  == buf->vb.width  &&
+			   prev->vb.height == buf->vb.height &&
+			   prev->fmt       == buf->fmt) {
+			list_move_tail(&buf->vb.queue, &q->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count    = q->count++;
+			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+			prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
+			dprintk(2, "[%p/%d] restart_queue - move to active\n",
+				buf, buf->vb.i);
+		} else {
+			return 0;
+		}
+		prev = buf;
+	}
+}
+
+static int buffer_setup(struct videobuf_queue *q, unsigned int *count,
+	unsigned int *size)
+{
+	struct cx23885_fh *fh = q->priv_data;
+
+	*size = fh->fmt->depth*fh->width*fh->height >> 3;
+	if (0 == *count)
+		*count = 32;
+	while (*size * *count > vid_limit * 1024 * 1024)
+		(*count)--;
+	return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+	       enum v4l2_field field)
+{
+	struct cx23885_fh *fh  = q->priv_data;
+	struct cx23885_dev *dev = fh->dev;
+	struct cx23885_buffer *buf =
+		container_of(vb, struct cx23885_buffer, vb);
+	int rc, init_buffer = 0;
+	u32 line0_offset, line1_offset;
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+	BUG_ON(NULL == fh->fmt);
+	if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||
+	    fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))
+		return -EINVAL;
+	buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
+		return -EINVAL;
+
+	if (buf->fmt       != fh->fmt    ||
+	    buf->vb.width  != fh->width  ||
+	    buf->vb.height != fh->height ||
+	    buf->vb.field  != field) {
+		buf->fmt       = fh->fmt;
+		buf->vb.width  = fh->width;
+		buf->vb.height = fh->height;
+		buf->vb.field  = field;
+		init_buffer = 1;
+	}
+
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		init_buffer = 1;
+		rc = videobuf_iolock(q, &buf->vb, NULL);
+		if (0 != rc)
+			goto fail;
+	}
+
+	if (init_buffer) {
+		buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
+		switch (buf->vb.field) {
+		case V4L2_FIELD_TOP:
+			cx23885_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist, 0, UNSET,
+					 buf->bpl, 0, buf->vb.height);
+			break;
+		case V4L2_FIELD_BOTTOM:
+			cx23885_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist, UNSET, 0,
+					 buf->bpl, 0, buf->vb.height);
+			break;
+		case V4L2_FIELD_INTERLACED:
+			if (dev->tvnorm & V4L2_STD_NTSC) {
+				/* cx25840 transmits NTSC bottom field first */
+				dprintk(1, "%s() Creating NTSC risc\n",
+					__FUNCTION__);
+				line0_offset = buf->bpl;
+				line1_offset = 0;
+			} else {
+				/* All other formats are top field first */
+				dprintk(1, "%s() Creating PAL/SECAM risc\n",
+					__FUNCTION__);
+				line0_offset = 0;
+				line1_offset = buf->bpl;
+			}
+			cx23885_risc_buffer(dev->pci, &buf->risc,
+					dma->sglist, line0_offset,
+					line1_offset,
+					buf->bpl, buf->bpl,
+					buf->vb.height >> 1);
+			break;
+		case V4L2_FIELD_SEQ_TB:
+			cx23885_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist,
+					 0, buf->bpl * (buf->vb.height >> 1),
+					 buf->bpl, 0,
+					 buf->vb.height >> 1);
+			break;
+		case V4L2_FIELD_SEQ_BT:
+			cx23885_risc_buffer(dev->pci, &buf->risc,
+					 dma->sglist,
+					 buf->bpl * (buf->vb.height >> 1), 0,
+					 buf->bpl, 0,
+					 buf->vb.height >> 1);
+			break;
+		default:
+			BUG();
+		}
+	}
+	dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
+		buf, buf->vb.i,
+		fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
+		(unsigned long)buf->risc.dma);
+
+	buf->vb.state = VIDEOBUF_PREPARED;
+	return 0;
+
+ fail:
+	cx23885_free_buffer(q, buf);
+	return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+	struct cx23885_buffer   *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+	struct cx23885_buffer   *prev;
+	struct cx23885_fh       *fh   = vq->priv_data;
+	struct cx23885_dev      *dev  = fh->dev;
+	struct cx23885_dmaqueue *q    = &dev->vidq;
+
+	/* add jump to stopper */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+	if (!list_empty(&q->queued)) {
+		list_add_tail(&buf->vb.queue, &q->queued);
+		buf->vb.state = VIDEOBUF_QUEUED;
+		dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
+			buf, buf->vb.i);
+
+	} else if (list_empty(&q->active)) {
+		list_add_tail(&buf->vb.queue, &q->active);
+		cx23885_start_video_dma(dev, q, buf);
+		buf->vb.state = VIDEOBUF_ACTIVE;
+		buf->count    = q->count++;
+		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+		dprintk(2, "[%p/%d] buffer_queue - first active\n",
+			buf, buf->vb.i);
+
+	} else {
+		prev = list_entry(q->active.prev, struct cx23885_buffer,
+			vb.queue);
+		if (prev->vb.width  == buf->vb.width  &&
+		    prev->vb.height == buf->vb.height &&
+		    prev->fmt       == buf->fmt) {
+			list_add_tail(&buf->vb.queue, &q->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			buf->count    = q->count++;
+			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+			/* 64 bit bits 63-32 */
+			prev->risc.jmp[2] = cpu_to_le32(0);
+			dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+				buf, buf->vb.i);
+
+		} else {
+			list_add_tail(&buf->vb.queue, &q->queued);
+			buf->vb.state = VIDEOBUF_QUEUED;
+			dprintk(2, "[%p/%d] buffer_queue - first queued\n",
+				buf, buf->vb.i);
+		}
+	}
+}
+
+static void buffer_release(struct videobuf_queue *q,
+	struct videobuf_buffer *vb)
+{
+	struct cx23885_buffer *buf = container_of(vb,
+		struct cx23885_buffer, vb);
+
+	cx23885_free_buffer(q, buf);
+}
+
+static struct videobuf_queue_ops cx23885_video_qops = {
+	.buf_setup    = buffer_setup,
+	.buf_prepare  = buffer_prepare,
+	.buf_queue    = buffer_queue,
+	.buf_release  = buffer_release,
+};
+
+static struct videobuf_queue *get_queue(struct cx23885_fh *fh)
+{
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return &fh->vidq;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return &fh->vbiq;
+	default:
+		BUG();
+		return NULL;
+	}
+}
+
+static int get_resource(struct cx23885_fh *fh)
+{
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		return RESOURCE_VIDEO;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		return RESOURCE_VBI;
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+static int video_open(struct inode *inode, struct file *file)
+{
+	int minor = iminor(inode);
+	struct cx23885_dev *h, *dev = NULL;
+	struct cx23885_fh *fh;
+	struct list_head *list;
+	enum v4l2_buf_type type = 0;
+	int radio = 0;
+
+	list_for_each(list, &cx23885_devlist) {
+		h = list_entry(list, struct cx23885_dev, devlist);
+		if (h->video_dev->minor == minor) {
+			dev  = h;
+			type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		}
+		if (h->vbi_dev &&
+		   h->vbi_dev->minor == minor) {
+			dev  = h;
+			type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		}
+		if (h->radio_dev &&
+		    h->radio_dev->minor == minor) {
+			radio = 1;
+			dev   = h;
+		}
+	}
+	if (NULL == dev)
+		return -ENODEV;
+
+	dprintk(1, "open minor=%d radio=%d type=%s\n",
+		minor, radio, v4l2_type_names[type]);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (NULL == fh)
+		return -ENOMEM;
+	file->private_data = fh;
+	fh->dev      = dev;
+	fh->radio    = radio;
+	fh->type     = type;
+	fh->width    = 320;
+	fh->height   = 240;
+	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+
+	videobuf_queue_pci_init(&fh->vidq, &cx23885_video_qops,
+			    dev->pci, &dev->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			    V4L2_FIELD_INTERLACED,
+			    sizeof(struct cx23885_buffer),
+			    fh);
+
+	dprintk(1, "post videobuf_queue_init()\n");
+
+
+	return 0;
+}
+
+static ssize_t video_read(struct file *file, char __user *data,
+	size_t count, loff_t *ppos)
+{
+	struct cx23885_fh *fh = file->private_data;
+
+	switch (fh->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (res_locked(fh->dev, RESOURCE_VIDEO))
+			return -EBUSY;
+		return videobuf_read_one(&fh->vidq, data, count, ppos,
+					 file->f_flags & O_NONBLOCK);
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		if (!res_get(fh->dev, fh, RESOURCE_VBI))
+			return -EBUSY;
+		return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
+					    file->f_flags & O_NONBLOCK);
+	default:
+		BUG();
+		return 0;
+	}
+}
+
+static unsigned int video_poll(struct file *file,
+	struct poll_table_struct *wait)
+{
+	struct cx23885_fh *fh = file->private_data;
+	struct cx23885_buffer *buf;
+
+	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+		if (!res_get(fh->dev, fh, RESOURCE_VBI))
+			return POLLERR;
+		return videobuf_poll_stream(file, &fh->vbiq, wait);
+	}
+
+	if (res_check(fh, RESOURCE_VIDEO)) {
+		/* streaming capture */
+		if (list_empty(&fh->vidq.stream))
+			return POLLERR;
+		buf = list_entry(fh->vidq.stream.next,
+			struct cx23885_buffer, vb.stream);
+	} else {
+		/* read() capture */
+		buf = (struct cx23885_buffer *)fh->vidq.read_buf;
+		if (NULL == buf)
+			return POLLERR;
+	}
+	poll_wait(file, &buf->vb.done, wait);
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
+		return POLLIN|POLLRDNORM;
+	return 0;
+}
+
+static int video_release(struct inode *inode, struct file *file)
+{
+	struct cx23885_fh *fh = file->private_data;
+	struct cx23885_dev *dev = fh->dev;
+
+	/* turn off overlay */
+	if (res_check(fh, RESOURCE_OVERLAY)) {
+		/* FIXME */
+		res_free(dev, fh, RESOURCE_OVERLAY);
+	}
+
+	/* stop video capture */
+	if (res_check(fh, RESOURCE_VIDEO)) {
+		videobuf_queue_cancel(&fh->vidq);
+		res_free(dev, fh, RESOURCE_VIDEO);
+	}
+	if (fh->vidq.read_buf) {
+		buffer_release(&fh->vidq, fh->vidq.read_buf);
+		kfree(fh->vidq.read_buf);
+	}
+
+	/* stop vbi capture */
+	if (res_check(fh, RESOURCE_VBI)) {
+		if (fh->vbiq.streaming)
+			videobuf_streamoff(&fh->vbiq);
+		if (fh->vbiq.reading)
+			videobuf_read_stop(&fh->vbiq);
+		res_free(dev, fh, RESOURCE_VBI);
+	}
+
+	videobuf_mmap_free(&fh->vidq);
+	file->private_data = NULL;
+	kfree(fh);
+
+	/* We are not putting the tuner to sleep here on exit, because
+	 * we want to use the mpeg encoder in another session to capture
+	 * tuner video. Closing this will result in no video to the encoder.
+	 */
+
+	return 0;
+}
+
+static int video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct cx23885_fh *fh = file->private_data;
+
+	return videobuf_mmap_mapper(get_queue(fh), vma);
+}
+
+/* ------------------------------------------------------------------ */
+/* VIDEO CTRL IOCTLS                                                  */
+
+int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+{
+	dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __FUNCTION__);
+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
+	return 0;
+}
+EXPORT_SYMBOL(cx23885_get_control);
+
+int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
+{
+	dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
+		" (disabled - no action)\n", __FUNCTION__);
+	return 0;
+}
+EXPORT_SYMBOL(cx23885_set_control);
+
+static void init_controls(struct cx23885_dev *dev)
+{
+	struct v4l2_control ctrl;
+	int i;
+
+	for (i = 0; i < CX23885_CTLS; i++) {
+		ctrl.id = cx23885_ctls[i].v.id;
+		ctrl.value = cx23885_ctls[i].v.default_value;
+
+		cx23885_set_control(dev, &ctrl);
+	}
+}
+
+/* ------------------------------------------------------------------ */
+/* VIDEO IOCTLS                                                       */
+
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+	struct v4l2_format *f)
+{
+	struct cx23885_fh *fh   = priv;
+
+	f->fmt.pix.width        = fh->width;
+	f->fmt.pix.height       = fh->height;
+	f->fmt.pix.field        = fh->vidq.field;
+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fh->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+	struct v4l2_format *f)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	struct cx23885_fmt *fmt;
+	enum v4l2_field   field;
+	unsigned int      maxw, maxh;
+
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	field = f->fmt.pix.field;
+	maxw  = norm_maxw(dev->tvnorm);
+	maxh  = norm_maxh(dev->tvnorm);
+
+	if (V4L2_FIELD_ANY == field) {
+		field = (f->fmt.pix.height > maxh/2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_BOTTOM;
+	}
+
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	f->fmt.pix.field = field;
+	if (f->fmt.pix.height < 32)
+		f->fmt.pix.height = 32;
+	if (f->fmt.pix.height > maxh)
+		f->fmt.pix.height = maxh;
+	if (f->fmt.pix.width < 48)
+		f->fmt.pix.width = 48;
+	if (f->fmt.pix.width > maxw)
+		f->fmt.pix.width = maxw;
+	f->fmt.pix.width &= ~0x03;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+	struct v4l2_format *f)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+	int err;
+
+	dprintk(2, "%s()\n", __FUNCTION__);
+	err = vidioc_try_fmt_cap(file, priv, f);
+
+	if (0 != err)
+		return err;
+	fh->fmt        = format_by_fourcc(f->fmt.pix.pixelformat);
+	fh->width      = f->fmt.pix.width;
+	fh->height     = f->fmt.pix.height;
+	fh->vidq.field = f->fmt.pix.field;
+	dprintk(2, "%s() width=%d height=%d field=%d\n", __FUNCTION__,
+		fh->width, fh->height, fh->vidq.field);
+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f);
+	return 0;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+	struct v4l2_capability *cap)
+{
+	struct cx23885_dev *dev  = ((struct cx23885_fh *)priv)->dev;
+
+	strcpy(cap->driver, "cx23885");
+	strlcpy(cap->card, cx23885_boards[dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
+	cap->version = CX23885_VERSION_CODE;
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE     |
+		V4L2_CAP_STREAMING     |
+		V4L2_CAP_VBI_CAPTURE;
+	if (UNSET != dev->tuner_type)
+		cap->capabilities |= V4L2_CAP_TUNER;
+	return 0;
+}
+
+static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
+	struct v4l2_fmtdesc *f)
+{
+	if (unlikely(f->index >= ARRAY_SIZE(formats)))
+		return -EINVAL;
+
+	strlcpy(f->description, formats[f->index].name,
+		sizeof(f->description));
+	f->pixelformat = formats[f->index].fourcc;
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv,
+	struct video_mbuf *mbuf)
+{
+	struct cx23885_fh *fh = priv;
+	struct videobuf_queue *q;
+	struct v4l2_requestbuffers req;
+	unsigned int i;
+	int err;
+
+	q = get_queue(fh);
+	memset(&req, 0, sizeof(req));
+	req.type   = q->type;
+	req.count  = 8;
+	req.memory = V4L2_MEMORY_MMAP;
+	err = videobuf_reqbufs(q, &req);
+	if (err < 0)
+		return err;
+
+	mbuf->frames = req.count;
+	mbuf->size   = 0;
+	for (i = 0; i < mbuf->frames; i++) {
+		mbuf->offsets[i]  = q->bufs[i]->boff;
+		mbuf->size       += q->bufs[i]->bsize;
+	}
+	return 0;
+}
+#endif
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+	struct v4l2_requestbuffers *p)
+{
+	struct cx23885_fh *fh = priv;
+	return (videobuf_reqbufs(get_queue(fh), p));
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+	struct v4l2_buffer *p)
+{
+	struct cx23885_fh *fh = priv;
+	return (videobuf_querybuf(get_queue(fh), p));
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+	struct v4l2_buffer *p)
+{
+	struct cx23885_fh *fh = priv;
+	return (videobuf_qbuf(get_queue(fh), p));
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv,
+	struct v4l2_buffer *p)
+{
+	struct cx23885_fh *fh = priv;
+	return (videobuf_dqbuf(get_queue(fh), p,
+				file->f_flags & O_NONBLOCK));
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+	enum v4l2_buf_type i)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev = fh->dev;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+		return -EINVAL;
+	if (unlikely(i != fh->type))
+		return -EINVAL;
+
+	if (unlikely(!res_get(dev, fh, get_resource(fh))))
+		return -EBUSY;
+	return videobuf_streamon(get_queue(fh));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev = fh->dev;
+	int err, res;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (i != fh->type)
+		return -EINVAL;
+
+	res = get_resource(fh);
+	err = videobuf_streamoff(get_queue(fh));
+	if (err < 0)
+		return err;
+	res_free(dev, fh, res);
+	return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	mutex_lock(&dev->lock);
+	cx23885_set_tvnorm(dev, *tvnorms);
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
+{
+	static const char *iname[] = {
+		[CX23885_VMUX_COMPOSITE1] = "Composite1",
+		[CX23885_VMUX_COMPOSITE2] = "Composite2",
+		[CX23885_VMUX_COMPOSITE3] = "Composite3",
+		[CX23885_VMUX_COMPOSITE4] = "Composite4",
+		[CX23885_VMUX_SVIDEO]     = "S-Video",
+		[CX23885_VMUX_TELEVISION] = "Television",
+		[CX23885_VMUX_CABLE]      = "Cable TV",
+		[CX23885_VMUX_DVB]        = "DVB",
+		[CX23885_VMUX_DEBUG]      = "for debug only",
+	};
+	unsigned int n;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	n = i->index;
+	if (n >= 4)
+		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 ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
+		(CX23885_VMUX_CABLE == INPUT(n)->type))
+		i->type = V4L2_INPUT_TYPE_TUNER;
+		i->std = CX23885_NORMS;
+	return 0;
+}
+EXPORT_SYMBOL(cx23885_enum_input);
+
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+	dprintk(1, "%s()\n", __FUNCTION__);
+	return cx23885_enum_input(dev, i);
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	*i = dev->input;
+	dprintk(1, "%s() returns %d\n", __FUNCTION__, *i);
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	dprintk(1, "%s(%d)\n", __FUNCTION__, i);
+
+	if (i >= 4) {
+		dprintk(1, "%s() -EINVAL\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	mutex_lock(&dev->lock);
+	cx23885_video_mux(dev, i);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qctrl)
+{
+	qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+	if (unlikely(qctrl->id == 0))
+		return -EINVAL;
+	return cx23885_ctrl_query(qctrl);
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctl)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	return cx23885_get_control(dev, ctl);
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctl)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	return cx23885_set_control(dev, ctl);
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	if (unlikely(UNSET == dev->tuner_type))
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "Television");
+	t->type       = V4L2_TUNER_ANALOG_TV;
+	t->capability = V4L2_TUNER_CAP_NORM;
+	t->rangehigh  = 0xffffffffUL;
+	t->signal = 0xffff ; /* LOCKED */
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+
+	if (UNSET == dev->tuner_type)
+		return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (unlikely(UNSET == dev->tuner_type))
+		return -EINVAL;
+
+	/* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
+	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	f->frequency = dev->freq;
+
+	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f);
+
+	return 0;
+}
+
+int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
+{
+	if (unlikely(UNSET == dev->tuner_type))
+		return -EINVAL;
+	if (unlikely(f->tuner != 0))
+		return -EINVAL;
+
+	mutex_lock(&dev->lock);
+	dev->freq = f->frequency;
+
+	cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f);
+
+	/* When changing channels it is required to reset TVAUDIO */
+	msleep(10);
+
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(cx23885_set_freq);
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct cx23885_fh *fh = priv;
+	struct cx23885_dev *dev = fh->dev;
+
+	if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+		return -EINVAL;
+	if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+		return -EINVAL;
+
+	return
+		cx23885_set_freq(dev, f);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *fh,
+				struct v4l2_register *reg)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+
+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return -EINVAL;
+
+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg);
+
+	return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *fh,
+				struct v4l2_register *reg)
+{
+	struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+
+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return -EINVAL;
+
+	cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg);
+
+	return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+
+static void cx23885_vid_timeout(unsigned long data)
+{
+	struct cx23885_dev *dev = (struct cx23885_dev *)data;
+	struct cx23885_dmaqueue *q = &dev->vidq;
+	struct cx23885_buffer *buf;
+	unsigned long flags;
+
+	cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]);
+
+	cx_clear(VID_A_DMA_CTL, 0x11);
+
+	spin_lock_irqsave(&dev->slock, flags);
+	while (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next,
+			struct cx23885_buffer, vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = VIDEOBUF_ERROR;
+		wake_up(&buf->vb.done);
+		printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n",
+			dev->name, buf, buf->vb.i,
+			(unsigned long)buf->risc.dma);
+	}
+	cx23885_restart_video_queue(dev, q);
+	spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
+{
+	u32 mask, count;
+	int handled = 0;
+
+	mask   = cx_read(VID_A_INT_MSK);
+	if (0 == (status & mask))
+		return handled;
+	cx_write(VID_A_INT_STAT, status);
+
+	dprintk(2, "%s() status = 0x%08x\n", __FUNCTION__, status);
+	/* risc op code error */
+	if (status & (1 << 16)) {
+		printk(KERN_WARNING "%s/0: video risc op code error\n",
+			dev->name);
+		cx_clear(VID_A_DMA_CTL, 0x11);
+		cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]);
+	}
+
+	/* risc1 y */
+	if (status & 0x01) {
+		spin_lock(&dev->slock);
+		count = cx_read(VID_A_GPCNT);
+		cx23885_video_wakeup(dev, &dev->vidq, count);
+		spin_unlock(&dev->slock);
+		handled++;
+	}
+	/* risc2 y */
+	if (status & 0x10) {
+		dprintk(2, "stopper video\n");
+		spin_lock(&dev->slock);
+		cx23885_restart_video_queue(dev, &dev->vidq);
+		spin_unlock(&dev->slock);
+		handled++;
+	}
+
+	return handled;
+}
+
+/* ----------------------------------------------------------- */
+/* exported stuff                                              */
+
+static const struct file_operations video_fops = {
+	.owner	       = THIS_MODULE,
+	.open	       = video_open,
+	.release       = video_release,
+	.read	       = video_read,
+	.poll          = video_poll,
+	.mmap	       = video_mmap,
+	.ioctl	       = video_ioctl2,
+	.compat_ioctl  = v4l_compat_ioctl32,
+	.llseek        = no_llseek,
+};
+
+static struct video_device cx23885_vbi_template;
+static struct video_device cx23885_video_template = {
+	.name                 = "cx23885-video",
+	.type                 = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
+	.fops                 = &video_fops,
+	.minor                = -1,
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
+	.vidioc_g_fmt_cap     = vidioc_g_fmt_cap,
+	.vidioc_try_fmt_cap   = vidioc_try_fmt_cap,
+	.vidioc_s_fmt_cap     = vidioc_s_fmt_cap,
+	.vidioc_g_fmt_vbi     = cx23885_vbi_fmt,
+	.vidioc_try_fmt_vbi   = cx23885_vbi_fmt,
+	.vidioc_s_fmt_vbi     = cx23885_vbi_fmt,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_s_std         = vidioc_s_std,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_queryctrl     = vidioc_queryctrl,
+	.vidioc_g_ctrl        = vidioc_g_ctrl,
+	.vidioc_s_ctrl        = vidioc_s_ctrl,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	.vidiocgmbuf          = vidiocgmbuf,
+#endif
+	.vidioc_g_tuner       = vidioc_g_tuner,
+	.vidioc_s_tuner       = vidioc_s_tuner,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_s_frequency   = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register    = vidioc_g_register,
+	.vidioc_s_register    = vidioc_s_register,
+#endif
+	.tvnorms              = CX23885_NORMS,
+	.current_norm         = V4L2_STD_NTSC_M,
+};
+
+static const struct file_operations radio_fops = {
+	.owner         = THIS_MODULE,
+	.open          = video_open,
+	.release       = video_release,
+	.ioctl         = video_ioctl2,
+	.compat_ioctl  = v4l_compat_ioctl32,
+	.llseek        = no_llseek,
+};
+
+
+void cx23885_video_unregister(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+	cx_clear(PCI_INT_MSK, 1);
+
+	if (dev->video_dev) {
+		if (-1 != dev->video_dev->minor)
+			video_unregister_device(dev->video_dev);
+		else
+			video_device_release(dev->video_dev);
+		dev->video_dev = NULL;
+
+		btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
+	}
+}
+
+int cx23885_video_register(struct cx23885_dev *dev)
+{
+	int err;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+	spin_lock_init(&dev->slock);
+
+	/* Initialize VBI template */
+	memcpy(&cx23885_vbi_template, &cx23885_video_template,
+		sizeof(cx23885_vbi_template));
+	strcpy(cx23885_vbi_template.name, "cx23885-vbi");
+	cx23885_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER;
+
+	dev->tvnorm = cx23885_video_template.current_norm;
+
+	/* init video dma queues */
+	INIT_LIST_HEAD(&dev->vidq.active);
+	INIT_LIST_HEAD(&dev->vidq.queued);
+	dev->vidq.timeout.function = cx23885_vid_timeout;
+	dev->vidq.timeout.data = (unsigned long)dev;
+	init_timer(&dev->vidq.timeout);
+	cx23885_risc_stopper(dev->pci, &dev->vidq.stopper,
+		VID_A_DMA_CTL, 0x11, 0x00);
+
+	/* Don't enable VBI yet */
+	cx_set(PCI_INT_MSK, 1);
+
+
+	/* register v4l devices */
+	dev->video_dev = cx23885_vdev_init(dev, dev->pci,
+		&cx23885_video_template, "video");
+	err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
+				    video_nr[dev->nr]);
+	if (err < 0) {
+		printk(KERN_INFO "%s: can't register video device\n",
+			dev->name);
+		goto fail_unreg;
+	}
+	printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n",
+	       dev->name, dev->video_dev->minor & 0x1f);
+	/* initial device configuration */
+	mutex_lock(&dev->lock);
+	cx23885_set_tvnorm(dev, dev->tvnorm);
+	init_controls(dev);
+	cx23885_video_mux(dev, 0);
+	mutex_unlock(&dev->lock);
+
+	return 0;
+
+fail_unreg:
+	cx23885_video_unregister(dev);
+	return err;
+}
+
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index dec4dc2fcbb4..7cb2179f2622 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -44,6 +44,10 @@
 
 /* Max number of inputs by card */
 #define MAX_CX23885_INPUT 8
+#define INPUT(nr) (&cx23885_boards[dev->board].input[nr])
+#define RESOURCE_OVERLAY       1
+#define RESOURCE_VIDEO         2
+#define RESOURCE_VBI           4
 
 #define BUFFER_TIMEOUT     (HZ)  /* 0.5 seconds */
 
@@ -53,6 +57,62 @@
 #define CX23885_BOARD_HAUPPAUGE_HVR1800        2
 #define CX23885_BOARD_HAUPPAUGE_HVR1250        3
 #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP   4
+#define CX23885_BOARD_HAUPPAUGE_HVR1500Q       5
+#define CX23885_BOARD_HAUPPAUGE_HVR1500        6
+
+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
+#define CX23885_NORMS (\
+	V4L2_STD_NTSC_M |  V4L2_STD_NTSC_M_JP |  V4L2_STD_NTSC_443 | \
+	V4L2_STD_PAL_BG |  V4L2_STD_PAL_DK    |  V4L2_STD_PAL_I    | \
+	V4L2_STD_PAL_M  |  V4L2_STD_PAL_N     |  V4L2_STD_PAL_Nc   | \
+	V4L2_STD_PAL_60 |  V4L2_STD_SECAM_L   |  V4L2_STD_SECAM_DK)
+
+struct cx23885_fmt {
+	char  *name;
+	u32   fourcc;          /* v4l2 format id */
+	int   depth;
+	int   flags;
+	u32   cxformat;
+};
+
+struct cx23885_ctrl {
+	struct v4l2_queryctrl v;
+	u32                   off;
+	u32                   reg;
+	u32                   mask;
+	u32                   shift;
+};
+
+struct cx23885_tvnorm {
+	char		*name;
+	v4l2_std_id	id;
+	u32		cxiformat;
+	u32		cxoformat;
+};
+
+struct cx23885_fh {
+	struct cx23885_dev         *dev;
+	enum v4l2_buf_type         type;
+	int                        radio;
+	u32                        resources;
+
+	/* video overlay */
+	struct v4l2_window         win;
+	struct v4l2_clip           *clips;
+	unsigned int               nclips;
+
+	/* video capture */
+	struct cx23885_fmt         *fmt;
+	unsigned int               width, height;
+
+	/* vbi capture */
+	struct videobuf_queue      vidq;
+	struct videobuf_queue      vbiq;
+
+	/* MPEG Encoder specifics ONLY */
+	struct videobuf_queue      mpegq;
+	atomic_t                   v4l_reading;
+};
 
 enum cx23885_itype {
 	CX23885_VMUX_COMPOSITE1 = 1,
@@ -92,12 +152,28 @@ struct cx23885_input {
 
 typedef enum {
 	CX23885_MPEG_UNDEFINED = 0,
-	CX23885_MPEG_DVB
+	CX23885_MPEG_DVB,
+	CX23885_ANALOG_VIDEO,
 } port_t;
 
 struct cx23885_board {
 	char                    *name;
-	port_t			portb, portc;
+	port_t			porta, portb, portc;
+	unsigned int		tuner_type;
+	unsigned int		radio_type;
+	unsigned char		tuner_addr;
+	unsigned char		radio_addr;
+
+	/* Vendors can and do run the PCIe bridge at different
+	 * clock rates, driven physically by crystals on the PCBs.
+	 * The core has to accomodate this. This allows the user
+	 * to add new boards with new frequencys. The value is
+	 * expressed in Hz.
+	 *
+	 * The core framework will default this value based on
+	 * current designs, but it can vary.
+	 */
+	u32			clk_freq;
 	struct cx23885_input    input[MAX_CX23885_INPUT];
 };
 
@@ -189,6 +265,11 @@ struct cx23885_dev {
 	u32                        __iomem *lmmio;
 	u8                         __iomem *bmmio;
 	int                        pci_irqmask;
+	int                        hwrevision;
+
+	/* This valud is board specific and is used to configure the
+	 * AV core so we see nice clean and stable video and audio. */
+	u32                        clk_freq;
 
 	/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
 	struct cx23885_i2c         i2c_bus[3];
@@ -210,8 +291,31 @@ struct cx23885_dev {
 		CX23885_BRIDGE_885 = 885,
 		CX23885_BRIDGE_887 = 887,
 	} bridge;
+
+	/* Analog video */
+	u32                        resources;
+	unsigned int               input;
+	u32                        tvaudio;
+	v4l2_std_id                tvnorm;
+	unsigned int               tuner_type;
+	unsigned char              tuner_addr;
+	unsigned int               radio_type;
+	unsigned char              radio_addr;
+	unsigned int               has_radio;
+
+	/* V4l */
+	u32                        freq;
+	struct video_device        *video_dev;
+	struct video_device        *vbi_dev;
+	struct video_device        *radio_dev;
+
+	struct cx23885_dmaqueue    vidq;
+	struct cx23885_dmaqueue    vbiq;
+	spinlock_t                 slock;
 };
 
+extern struct list_head cx23885_devlist;
+
 #define SRAM_CH01  0 /* Video A */
 #define SRAM_CH02  1 /* VBI A */
 #define SRAM_CH03  2 /* Video B */
@@ -254,19 +358,42 @@ struct sram_channel {
 #define cx_set(reg,bit)          cx_andor((reg),(bit),(bit))
 #define cx_clear(reg,bit)        cx_andor((reg),(bit),0)
 
+/* ----------------------------------------------------------- */
+/* cx23885-core.c                                              */
+
 extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
 	struct sram_channel *ch,
 	unsigned int bpl, u32 risc);
 
-/* ----------------------------------------------------------- */
-/* cx23885-cards.c                                                */
+extern void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+	struct sram_channel *ch);
 
+extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+	u32 reg, u32 mask, u32 value);
+
+extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+	struct scatterlist *sglist,
+	unsigned int top_offset, unsigned int bottom_offset,
+	unsigned int bpl, unsigned int padding, unsigned int lines);
+
+void cx23885_cancel_buffers(struct cx23885_tsport *port);
+
+extern int cx23885_restart_queue(struct cx23885_tsport *port,
+				struct cx23885_dmaqueue *q);
+
+extern void cx23885_wakeup(struct cx23885_tsport *port,
+			   struct cx23885_dmaqueue *q, u32 count);
+
+
+/* ----------------------------------------------------------- */
+/* cx23885-cards.c                                             */
 extern struct cx23885_board cx23885_boards[];
 extern const unsigned int cx23885_bcount;
 
 extern struct cx23885_subid cx23885_subids[];
 extern const unsigned int cx23885_idcount;
 
+extern int cx23885_tuner_callback(void *priv, int command, int arg);
 extern void cx23885_card_list(struct cx23885_dev *dev);
 extern int  cx23885_ir_init(struct cx23885_dev *dev);
 extern void cx23885_gpio_setup(struct cx23885_dev *dev);
@@ -280,19 +407,50 @@ extern int cx23885_buf_prepare(struct videobuf_queue *q,
 			       struct cx23885_tsport *port,
 			       struct cx23885_buffer *buf,
 			       enum v4l2_field field);
-
 extern void cx23885_buf_queue(struct cx23885_tsport *port,
 			      struct cx23885_buffer *buf);
 extern void cx23885_free_buffer(struct videobuf_queue *q,
 				struct cx23885_buffer *buf);
 
 /* ----------------------------------------------------------- */
+/* cx23885-video.c                                             */
+/* Video */
+extern int cx23885_video_register(struct cx23885_dev *dev);
+extern void cx23885_video_unregister(struct cx23885_dev *dev);
+extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status);
+
+/* ----------------------------------------------------------- */
+/* cx23885-vbi.c                                               */
+extern int cx23885_vbi_fmt(struct file *file, void *priv,
+	struct v4l2_format *f);
+extern void cx23885_vbi_timeout(unsigned long data);
+extern struct videobuf_queue_ops cx23885_vbi_qops;
+
 /* cx23885-i2c.c                                                */
 extern int cx23885_i2c_register(struct cx23885_i2c *bus);
 extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
 extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
 				     void *arg);
 
+/* ----------------------------------------------------------- */
+/* tv norms                                                    */
+
+static inline unsigned int norm_maxw(v4l2_std_id norm)
+{
+	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+}
+
+static inline unsigned int norm_maxh(v4l2_std_id norm)
+{
+	return (norm & V4L2_STD_625_50) ? 576 : 480;
+}
+
+static inline unsigned int norm_swidth(v4l2_std_id norm)
+{
+	return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+}
+
+
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index 3d46a776df36..d6421e1e8f6a 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -32,118 +32,156 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
 
 	/* common for all inputs and rates */
 	/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
-	cx25840_write(client, 0x127, 0x50);
+	if (!state->is_cx23885)
+		cx25840_write(client, 0x127, 0x50);
 
 	if (state->aud_input != CX25840_AUDIO_SERIAL) {
 		switch (freq) {
 		case 32000:
+			if (state->is_cx23885) {
+				/* We don't have register values
+				 * so avoid destroying registers. */
+				break;
+			}
 			/* VID_PLL and AUX_PLL */
-			cx25840_write4(client, 0x108, 0x0f040610);
+			cx25840_write4(client, 0x108, 0x1006040f);
 
 			/* AUX_PLL_FRAC */
-			cx25840_write4(client, 0x110, 0xee39bb01);
+			cx25840_write4(client, 0x110, 0x01bb39ee);
 
 			if (state->is_cx25836)
 				break;
 
 			/* src3/4/6_ctl = 0x0801f77f */
-			cx25840_write4(client, 0x900, 0x7ff70108);
-			cx25840_write4(client, 0x904, 0x7ff70108);
-			cx25840_write4(client, 0x90c, 0x7ff70108);
+			cx25840_write4(client, 0x900, 0x0801f77f);
+			cx25840_write4(client, 0x904, 0x0801f77f);
+			cx25840_write4(client, 0x90c, 0x0801f77f);
 			break;
 
 		case 44100:
+			if (state->is_cx23885) {
+				/* We don't have register values
+				 * so avoid destroying registers. */
+				break;
+			}
 			/* VID_PLL and AUX_PLL */
-			cx25840_write4(client, 0x108, 0x0f040910);
+			cx25840_write4(client, 0x108, 0x1009040f);
 
 			/* AUX_PLL_FRAC */
-			cx25840_write4(client, 0x110, 0xd66bec00);
+			cx25840_write4(client, 0x110, 0x00ec6bd6);
 
 			if (state->is_cx25836)
 				break;
 
 			/* src3/4/6_ctl = 0x08016d59 */
-			cx25840_write4(client, 0x900, 0x596d0108);
-			cx25840_write4(client, 0x904, 0x596d0108);
-			cx25840_write4(client, 0x90c, 0x596d0108);
+			cx25840_write4(client, 0x900, 0x08016d59);
+			cx25840_write4(client, 0x904, 0x08016d59);
+			cx25840_write4(client, 0x90c, 0x08016d59);
 			break;
 
 		case 48000:
+			if (state->is_cx23885) {
+				/* We don't have register values
+				 * so avoid destroying registers. */
+				break;
+			}
 			/* VID_PLL and AUX_PLL */
-			cx25840_write4(client, 0x108, 0x0f040a10);
+			cx25840_write4(client, 0x108, 0x100a040f);
 
 			/* AUX_PLL_FRAC */
-			cx25840_write4(client, 0x110, 0xe5d69800);
+			cx25840_write4(client, 0x110, 0x0098d6e5);
 
 			if (state->is_cx25836)
 				break;
 
 			/* src3/4/6_ctl = 0x08014faa */
-			cx25840_write4(client, 0x900, 0xaa4f0108);
-			cx25840_write4(client, 0x904, 0xaa4f0108);
-			cx25840_write4(client, 0x90c, 0xaa4f0108);
+			cx25840_write4(client, 0x900, 0x08014faa);
+			cx25840_write4(client, 0x904, 0x08014faa);
+			cx25840_write4(client, 0x90c, 0x08014faa);
 			break;
 		}
 	} else {
 		switch (freq) {
 		case 32000:
+			if (state->is_cx23885) {
+				/* We don't have register values
+				 * so avoid destroying registers. */
+				break;
+			}
 			/* VID_PLL and AUX_PLL */
-			cx25840_write4(client, 0x108, 0x0f04081e);
+			cx25840_write4(client, 0x108, 0x1e08040f);
 
 			/* AUX_PLL_FRAC */
-			cx25840_write4(client, 0x110, 0x69082a01);
+			cx25840_write4(client, 0x110, 0x012a0869);
 
 			if (state->is_cx25836)
 				break;
 
 			/* src1_ctl = 0x08010000 */
-			cx25840_write4(client, 0x8f8, 0x00000108);
+			cx25840_write4(client, 0x8f8, 0x08010000);
 
 			/* src3/4/6_ctl = 0x08020000 */
-			cx25840_write4(client, 0x900, 0x00000208);
-			cx25840_write4(client, 0x904, 0x00000208);
-			cx25840_write4(client, 0x90c, 0x00000208);
+			cx25840_write4(client, 0x900, 0x08020000);
+			cx25840_write4(client, 0x904, 0x08020000);
+			cx25840_write4(client, 0x90c, 0x08020000);
 
 			/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
 			cx25840_write(client, 0x127, 0x54);
 			break;
 
 		case 44100:
+			if (state->is_cx23885) {
+				/* We don't have register values
+				 * so avoid destroying registers. */
+				break;
+			}
+
 			/* VID_PLL and AUX_PLL */
-			cx25840_write4(client, 0x108, 0x0f040918);
+			cx25840_write4(client, 0x108, 0x1809040f);
 
 			/* AUX_PLL_FRAC */
-			cx25840_write4(client, 0x110, 0xd66bec00);
+			cx25840_write4(client, 0x110, 0x00ec6bd6);
 
 			if (state->is_cx25836)
 				break;
 
 			/* src1_ctl = 0x08010000 */
-			cx25840_write4(client, 0x8f8, 0xcd600108);
+			cx25840_write4(client, 0x8f8, 0x080160cd);
 
 			/* src3/4/6_ctl = 0x08020000 */
-			cx25840_write4(client, 0x900, 0x85730108);
-			cx25840_write4(client, 0x904, 0x85730108);
-			cx25840_write4(client, 0x90c, 0x85730108);
+			cx25840_write4(client, 0x900, 0x08017385);
+			cx25840_write4(client, 0x904, 0x08017385);
+			cx25840_write4(client, 0x90c, 0x08017385);
 			break;
 
 		case 48000:
-			/* VID_PLL and AUX_PLL */
-			cx25840_write4(client, 0x108, 0x0f040a18);
+			if (!state->is_cx23885) {
+				/* VID_PLL and AUX_PLL */
+				cx25840_write4(client, 0x108, 0x180a040f);
 
-			/* AUX_PLL_FRAC */
-			cx25840_write4(client, 0x110, 0xe5d69800);
+				/* AUX_PLL_FRAC */
+				cx25840_write4(client, 0x110, 0x0098d6e5);
+			}
 
 			if (state->is_cx25836)
 				break;
 
-			/* src1_ctl = 0x08010000 */
-			cx25840_write4(client, 0x8f8, 0x00800108);
+			if (!state->is_cx23885) {
+				/* src1_ctl */
+				cx25840_write4(client, 0x8f8, 0x08018000);
 
-			/* src3/4/6_ctl = 0x08020000 */
-			cx25840_write4(client, 0x900, 0x55550108);
-			cx25840_write4(client, 0x904, 0x55550108);
-			cx25840_write4(client, 0x90c, 0x55550108);
+				/* src3/4/6_ctl */
+				cx25840_write4(client, 0x900, 0x08015555);
+				cx25840_write4(client, 0x904, 0x08015555);
+				cx25840_write4(client, 0x90c, 0x08015555);
+			} else {
+
+				cx25840_write4(client, 0x8f8, 0x0801867c);
+
+				cx25840_write4(client, 0x900, 0x08014faa);
+				cx25840_write4(client, 0x904, 0x08014faa);
+				cx25840_write4(client, 0x90c, 0x08014faa);
+			}
 			break;
 		}
 	}
@@ -168,14 +206,14 @@ void cx25840_audio_set_path(struct i2c_client *client)
 
 	if (state->aud_input == CX25840_AUDIO_SERIAL) {
 		/* Set Path1 to Serial Audio Input */
-		cx25840_write4(client, 0x8d0, 0x12100101);
+		cx25840_write4(client, 0x8d0, 0x01011012);
 
 		/* The microcontroller should not be started for the
 		 * non-tuner inputs: autodetection is specific for
 		 * TV audio. */
 	} else {
 		/* Set Path1 to Analog Demod Main Channel */
-		cx25840_write4(client, 0x8d0, 0x7038061f);
+		cx25840_write4(client, 0x8d0, 0x1f063870);
 	}
 
 	set_audclk_freq(client, state->audclk_freq);
@@ -188,6 +226,11 @@ void cx25840_audio_set_path(struct i2c_client *client)
 
 	/* deassert soft reset */
 	cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+	if (state->is_cx23885) {
+		/* Ensure the controller is running when we exit */
+		cx25840_and_or(client, 0x803, ~0x10, 0x10);
+	}
 }
 
 static int get_volume(struct i2c_client *client)
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 15f191e170d2..756a1eeb274e 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -13,6 +13,8 @@
  * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
  * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
  *
+ * CX23885 support by Steven Toth <stoth@hauppauge.com>.
+ *
  * 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
@@ -37,6 +39,7 @@
 #include <linux/delay.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include <media/cx25840.h>
 
 #include "cx25840-core.h"
@@ -72,10 +75,10 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
 	u8 buffer[6];
 	buffer[0] = addr >> 8;
 	buffer[1] = addr & 0xff;
-	buffer[2] = value >> 24;
-	buffer[3] = (value >> 16) & 0xff;
-	buffer[4] = (value >> 8) & 0xff;
-	buffer[5] = value & 0xff;
+	buffer[2] = value & 0xff;
+	buffer[3] = (value >> 8) & 0xff;
+	buffer[4] = (value >> 16) & 0xff;
+	buffer[5] = value >> 24;
 	return i2c_master_send(client, buffer, 6);
 }
 
@@ -122,8 +125,6 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
 
 static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
 						enum cx25840_audio_input aud_input);
-static void log_audio_status(struct i2c_client *client);
-static void log_video_status(struct i2c_client *client);
 
 /* ----------------------------------------------------------------------- */
 
@@ -256,6 +257,96 @@ static void cx25840_initialize(struct i2c_client *client)
 	cx25840_and_or(client, 0x803, ~0x10, 0x10);
 }
 
+static void cx23885_initialize(struct i2c_client *client)
+{
+	DEFINE_WAIT(wait);
+	struct cx25840_state *state = i2c_get_clientdata(client);
+	struct workqueue_struct *q;
+
+	/* Internal Reset */
+	cx25840_and_or(client, 0x102, ~0x01, 0x01);
+	cx25840_and_or(client, 0x102, ~0x01, 0x00);
+
+	/* Stop microcontroller */
+	cx25840_and_or(client, 0x803, ~0x10, 0x00);
+
+	/* DIF in reset? */
+	cx25840_write(client, 0x398, 0);
+
+	/* Trust the default xtal, no division */
+	/* This changes for the cx23888 products */
+	cx25840_write(client, 0x2, 0x76);
+
+	/* Bring down the regulator for AUX clk */
+	cx25840_write(client, 0x1, 0x40);
+
+	/* Sys PLL frac */
+	cx25840_write4(client, 0x11c, 0x01d1744c);
+
+	/* Sys PLL int */
+	cx25840_write4(client, 0x118, 0x00000416);
+
+	/* Disable DIF bypass */
+	cx25840_write4(client, 0x33c, 0x00000001);
+
+	/* DIF Src phase inc */
+	cx25840_write4(client, 0x340, 0x0df7df83);
+
+	/* Vid PLL frac */
+	cx25840_write4(client, 0x10c, 0x01b6db7b);
+
+	/* Vid PLL int */
+	cx25840_write4(client, 0x108, 0x00000512);
+
+	/* Luma */
+	cx25840_write4(client, 0x414, 0x00107d12);
+
+	/* Chroma */
+	cx25840_write4(client, 0x420, 0x3d008282);
+
+	/* Aux PLL frac */
+	cx25840_write4(client, 0x114, 0x017dbf48);
+
+	/* Aux PLL int */
+	cx25840_write4(client, 0x110, 0x000a030e);
+
+	/* ADC2 input select */
+	cx25840_write(client, 0x102, 0x10);
+
+	/* VIN1 & VIN5 */
+	cx25840_write(client, 0x103, 0x11);
+
+	/* Enable format auto detect */
+	cx25840_write(client, 0x400, 0);
+	/* Fast subchroma lock */
+	/* White crush, Chroma AGC & Chroma Killer enabled */
+	cx25840_write(client, 0x401, 0xe8);
+
+	/* Select AFE clock pad output source */
+	cx25840_write(client, 0x144, 0x05);
+
+	/* Do the firmware load in a work handler to prevent.
+	   Otherwise the kernel is blocked waiting for the
+	   bit-banging i2c interface to finish uploading the
+	   firmware. */
+	INIT_WORK(&state->fw_work, cx25840_work_handler);
+	init_waitqueue_head(&state->fw_wait);
+	q = create_singlethread_workqueue("cx25840_fw");
+	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+	queue_work(q, &state->fw_work);
+	schedule();
+	finish_wait(&state->fw_wait, &wait);
+	destroy_workqueue(q);
+
+	cx25840_vbi_setup(client);
+
+	/* (re)set input */
+	set_input(client, state->vid_input, state->aud_input);
+
+	/* start microcontroller */
+	cx25840_and_or(client, 0x803, ~0x10, 0x10);
+}
+
 /* ----------------------------------------------------------------------- */
 
 static void input_change(struct i2c_client *client)
@@ -319,9 +410,22 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 			   vid_input <= CX25840_COMPOSITE8);
 	u8 reg;
 
-	v4l_dbg(1, cx25840_debug, client, "decoder set video input %d, audio input %d\n",
-			vid_input, aud_input);
+	v4l_dbg(1, cx25840_debug, client,
+		"decoder set video input %d, audio input %d\n",
+		vid_input, aud_input);
+
+	if (vid_input >= CX25840_VIN1_CH1) {
+		v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",
+			vid_input);
+		reg = vid_input & 0xff;
+		if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON)
+			is_composite = 0;
+		else
+			is_composite = 1;
 
+		v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",
+			reg, is_composite);
+	} else
 	if (is_composite) {
 		reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
 	} else {
@@ -331,7 +435,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 		if ((vid_input & ~0xff0) ||
 		    luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 ||
 		    chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) {
-			v4l_err(client, "0x%04x is not a valid video input!\n", vid_input);
+			v4l_err(client, "0x%04x is not a valid video input!\n",
+				vid_input);
 			return -EINVAL;
 		}
 		reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);
@@ -344,31 +449,49 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 		}
 	}
 
-	switch (aud_input) {
-	case CX25840_AUDIO_SERIAL:
-		/* do nothing, use serial audio input */
-		break;
-	case CX25840_AUDIO4: reg &= ~0x30; break;
-	case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
-	case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
-	case CX25840_AUDIO7: reg &= ~0xc0; break;
-	case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
+	/* The caller has previously prepared the correct routing
+	 * configuration in reg (for the cx23885) so we have no
+	 * need to attempt to flip bits for earlier av decoders.
+	 */
+	if (!state->is_cx23885) {
+		switch (aud_input) {
+		case CX25840_AUDIO_SERIAL:
+			/* do nothing, use serial audio input */
+			break;
+		case CX25840_AUDIO4: reg &= ~0x30; break;
+		case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+		case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+		case CX25840_AUDIO7: reg &= ~0xc0; break;
+		case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
 
-	default:
-		v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input);
-		return -EINVAL;
+		default:
+			v4l_err(client, "0x%04x is not a valid audio input!\n",
+				aud_input);
+			return -EINVAL;
+		}
 	}
 
 	cx25840_write(client, 0x103, reg);
+
 	/* Set INPUT_MODE to Composite (0) or S-Video (1) */
 	cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
-	/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
-	cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
-	/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
-	if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
-		cx25840_and_or(client, 0x102, ~0x4, 4);
-	else
-		cx25840_and_or(client, 0x102, ~0x4, 0);
+
+	if (!state->is_cx23885) {
+		/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+		/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
+		if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
+			cx25840_and_or(client, 0x102, ~0x4, 4);
+		else
+			cx25840_and_or(client, 0x102, ~0x4, 0);
+	} else {
+		if (is_composite)
+			/* ADC2 input select channel 2 */
+			cx25840_and_or(client, 0x102, ~0x2, 0);
+		else
+			/* ADC2 input select channel 3 */
+			cx25840_and_or(client, 0x102, ~0x2, 2);
+	}
 
 	state->vid_input = vid_input;
 	state->aud_input = aud_input;
@@ -376,6 +499,25 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
 		cx25840_audio_set_path(client);
 		input_change(client);
 	}
+
+	if (state->is_cx23885) {
+		/* Audio channel 1 src : Parallel 1 */
+		cx25840_write(client, 0x124, 0x03);
+
+		/* Select AFE clock pad output source */
+		cx25840_write(client, 0x144, 0x05);
+
+		/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
+		cx25840_write(client, 0x914, 0xa0);
+
+		/* I2S_OUT_CTL:
+		 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
+		 * I2S_OUT_MASTER_MODE = Master
+		 */
+		cx25840_write(client, 0x918, 0xa0);
+		cx25840_write(client, 0x919, 0x01);
+	}
+
 	return 0;
 }
 
@@ -641,6 +783,200 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
 
 /* ----------------------------------------------------------------------- */
 
+static void log_video_status(struct i2c_client *client)
+{
+	static const char *const fmt_strs[] = {
+		"0x0",
+		"NTSC-M", "NTSC-J", "NTSC-4.43",
+		"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
+		"0x9", "0xA", "0xB",
+		"SECAM",
+		"0xD", "0xE", "0xF"
+	};
+
+	struct cx25840_state *state = i2c_get_clientdata(client);
+	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
+	u8 gen_stat1 = cx25840_read(client, 0x40d);
+	u8 gen_stat2 = cx25840_read(client, 0x40e);
+	int vid_input = state->vid_input;
+
+	v4l_info(client, "Video signal:              %spresent\n",
+		    (gen_stat2 & 0x20) ? "" : "not ");
+	v4l_info(client, "Detected format:           %s\n",
+		    fmt_strs[gen_stat1 & 0xf]);
+
+	v4l_info(client, "Specified standard:        %s\n",
+		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+	if (vid_input >= CX25840_COMPOSITE1 &&
+	    vid_input <= CX25840_COMPOSITE8) {
+		v4l_info(client, "Specified video input:     Composite %d\n",
+			vid_input - CX25840_COMPOSITE1 + 1);
+	} else {
+		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
+			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+	}
+
+	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct i2c_client *client)
+{
+	struct cx25840_state *state = i2c_get_clientdata(client);
+	u8 download_ctl = cx25840_read(client, 0x803);
+	u8 mod_det_stat0 = cx25840_read(client, 0x804);
+	u8 mod_det_stat1 = cx25840_read(client, 0x805);
+	u8 audio_config = cx25840_read(client, 0x808);
+	u8 pref_mode = cx25840_read(client, 0x809);
+	u8 afc0 = cx25840_read(client, 0x80b);
+	u8 mute_ctl = cx25840_read(client, 0x8d3);
+	int aud_input = state->aud_input;
+	char *p;
+
+	switch (mod_det_stat0) {
+	case 0x00: p = "mono"; break;
+	case 0x01: p = "stereo"; break;
+	case 0x02: p = "dual"; break;
+	case 0x04: p = "tri"; break;
+	case 0x10: p = "mono with SAP"; break;
+	case 0x11: p = "stereo with SAP"; break;
+	case 0x12: p = "dual with SAP"; break;
+	case 0x14: p = "tri with SAP"; break;
+	case 0xfe: p = "forced mode"; break;
+	default: p = "not defined";
+	}
+	v4l_info(client, "Detected audio mode:       %s\n", p);
+
+	switch (mod_det_stat1) {
+	case 0x00: p = "not defined"; break;
+	case 0x01: p = "EIAJ"; break;
+	case 0x02: p = "A2-M"; break;
+	case 0x03: p = "A2-BG"; break;
+	case 0x04: p = "A2-DK1"; break;
+	case 0x05: p = "A2-DK2"; break;
+	case 0x06: p = "A2-DK3"; break;
+	case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+	case 0x08: p = "AM-L"; break;
+	case 0x09: p = "NICAM-BG"; break;
+	case 0x0a: p = "NICAM-DK"; break;
+	case 0x0b: p = "NICAM-I"; break;
+	case 0x0c: p = "NICAM-L"; break;
+	case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+	case 0x0e: p = "IF FM Radio"; break;
+	case 0x0f: p = "BTSC"; break;
+	case 0x10: p = "high-deviation FM"; break;
+	case 0x11: p = "very high-deviation FM"; break;
+	case 0xfd: p = "unknown audio standard"; break;
+	case 0xfe: p = "forced audio standard"; break;
+	case 0xff: p = "no detected audio standard"; break;
+	default: p = "not defined";
+	}
+	v4l_info(client, "Detected audio standard:   %s\n", p);
+	v4l_info(client, "Audio muted:               %s\n",
+		    (state->unmute_volume >= 0) ? "yes" : "no");
+	v4l_info(client, "Audio microcontroller:     %s\n",
+		    (download_ctl & 0x10) ?
+				((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
+
+	switch (audio_config >> 4) {
+	case 0x00: p = "undefined"; break;
+	case 0x01: p = "BTSC"; break;
+	case 0x02: p = "EIAJ"; break;
+	case 0x03: p = "A2-M"; break;
+	case 0x04: p = "A2-BG"; break;
+	case 0x05: p = "A2-DK1"; break;
+	case 0x06: p = "A2-DK2"; break;
+	case 0x07: p = "A2-DK3"; break;
+	case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
+	case 0x09: p = "AM-L"; break;
+	case 0x0a: p = "NICAM-BG"; break;
+	case 0x0b: p = "NICAM-DK"; break;
+	case 0x0c: p = "NICAM-I"; break;
+	case 0x0d: p = "NICAM-L"; break;
+	case 0x0e: p = "FM radio"; break;
+	case 0x0f: p = "automatic detection"; break;
+	default: p = "undefined";
+	}
+	v4l_info(client, "Configured audio standard: %s\n", p);
+
+	if ((audio_config >> 4) < 0xF) {
+		switch (audio_config & 0xF) {
+		case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
+		case 0x01: p = "MONO2 (LANGUAGE B)"; break;
+		case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
+		case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
+		case 0x04: p = "STEREO"; break;
+		case 0x05: p = "DUAL1 (AB)"; break;
+		case 0x06: p = "DUAL2 (AC) (FM)"; break;
+		case 0x07: p = "DUAL3 (BC) (FM)"; break;
+		case 0x08: p = "DUAL4 (AC) (AM)"; break;
+		case 0x09: p = "DUAL5 (BC) (AM)"; break;
+		case 0x0a: p = "SAP"; break;
+		default: p = "undefined";
+		}
+		v4l_info(client, "Configured audio mode:     %s\n", p);
+	} else {
+		switch (audio_config & 0xF) {
+		case 0x00: p = "BG"; break;
+		case 0x01: p = "DK1"; break;
+		case 0x02: p = "DK2"; break;
+		case 0x03: p = "DK3"; break;
+		case 0x04: p = "I"; break;
+		case 0x05: p = "L"; break;
+		case 0x06: p = "BTSC"; break;
+		case 0x07: p = "EIAJ"; break;
+		case 0x08: p = "A2-M"; break;
+		case 0x09: p = "FM Radio"; break;
+		case 0x0f: p = "automatic standard and mode detection"; break;
+		default: p = "undefined";
+		}
+		v4l_info(client, "Configured audio system:   %s\n", p);
+	}
+
+	if (aud_input) {
+		v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
+	} else {
+		v4l_info(client, "Specified audio input:     External\n");
+	}
+
+	switch (pref_mode & 0xf) {
+	case 0: p = "mono/language A"; break;
+	case 1: p = "language B"; break;
+	case 2: p = "language C"; break;
+	case 3: p = "analog fallback"; break;
+	case 4: p = "stereo"; break;
+	case 5: p = "language AC"; break;
+	case 6: p = "language BC"; break;
+	case 7: p = "language AB"; break;
+	default: p = "undefined";
+	}
+	v4l_info(client, "Preferred audio mode:      %s\n", p);
+
+	if ((audio_config & 0xf) == 0xf) {
+		switch ((afc0 >> 3) & 0x3) {
+		case 0: p = "system DK"; break;
+		case 1: p = "system L"; break;
+		case 2: p = "autodetect"; break;
+		default: p = "undefined";
+		}
+		v4l_info(client, "Selected 65 MHz format:    %s\n", p);
+
+		switch (afc0 & 0x7) {
+		case 0: p = "chroma"; break;
+		case 1: p = "BTSC"; break;
+		case 2: p = "EIAJ"; break;
+		case 3: p = "A2-M"; break;
+		case 4: p = "autodetect"; break;
+		default: p = "undefined";
+		}
+		v4l_info(client, "Selected 45 MHz format:    %s\n", p);
+	}
+}
+
+/* ----------------------------------------------------------------------- */
+
 static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 			   void *arg)
 {
@@ -660,6 +996,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 		state->is_initialized = 1;
 		if (state->is_cx25836)
 			cx25836_initialize(client);
+		else if (state->is_cx23885)
+			cx23885_initialize(client);
 		else
 			cx25840_initialize(client);
 	}
@@ -677,6 +1015,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
+
 		if (cmd == VIDIOC_DBG_G_REGISTER)
 			reg->val = cx25840_read(client, reg->reg & 0x0fff);
 		else
@@ -693,14 +1032,26 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 
 	case VIDIOC_STREAMON:
 		v4l_dbg(1, cx25840_debug, client, "enable output\n");
-		cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c);
-		cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07);
+		if (state->is_cx23885) {
+			u8 v = (cx25840_read(client, 0x421) | 0x0b);
+			cx25840_write(client, 0x421, v);
+		} else {
+			cx25840_write(client, 0x115,
+				state->is_cx25836 ? 0x0c : 0x8c);
+			cx25840_write(client, 0x116,
+				state->is_cx25836 ? 0x04 : 0x07);
+		}
 		break;
 
 	case VIDIOC_STREAMOFF:
 		v4l_dbg(1, cx25840_debug, client, "disable output\n");
-		cx25840_write(client, 0x115, 0x00);
-		cx25840_write(client, 0x116, 0x00);
+		if (state->is_cx23885) {
+			u8 v = cx25840_read(client, 0x421) & ~(0x0b);
+			cx25840_write(client, 0x421, v);
+		} else {
+			cx25840_write(client, 0x115, 0x00);
+			cx25840_write(client, 0x116, 0x00);
+		}
 		break;
 
 	case VIDIOC_LOG_STATUS:
@@ -863,6 +1214,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 	case VIDIOC_INT_RESET:
 		if (state->is_cx25836)
 			cx25836_initialize(client);
+		else if (state->is_cx23885)
+			cx23885_initialize(client);
 		else
 			cx25840_initialize(client);
 		break;
@@ -879,35 +1232,21 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_cx25840;
-
-static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
-				 int kind)
+static int cx25840_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	struct cx25840_state *state;
 	u32 id;
 	u16 device_id;
 
-	/* Check if the adapter supports the needed features
-	 * Not until kernel version 2.6.11 did the bit-algo
-	 * correctly report that it would do an I2C-level xfer */
-	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == 0)
-		return -ENOMEM;
-
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver_cx25840;
-	snprintf(client->name, sizeof(client->name) - 1, "cx25840");
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
 
 	v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1);
 
 	device_id = cx25840_read(client, 0x101) << 8;
 	device_id |= cx25840_read(client, 0x100);
+	v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id);
 
 	/* The high byte of the device ID should be
 	 * 0x83 for the cx2583x and 0x84 for the cx2584x */
@@ -916,16 +1255,18 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
 	}
 	else if ((device_id & 0xff00) == 0x8400) {
 		id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
+	} else if (device_id == 0x0000) {
+		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+	} else if (device_id == 0x1313) {
+		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
 	}
 	else {
 		v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
-		kfree(client);
-		return 0;
+		return -ENODEV;
 	}
 
 	state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
 	if (state == NULL) {
-		kfree(client);
 		return -ENOMEM;
 	}
 
@@ -939,6 +1280,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
 	i2c_set_clientdata(client, state);
 	state->c = client;
 	state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
+	state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313);
 	state->vid_input = CX25840_COMPOSITE7;
 	state->aud_input = CX25840_AUDIO8;
 	state->audclk_freq = 48000;
@@ -949,250 +1291,19 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
 	state->id = id;
 	state->rev = device_id;
 
-	i2c_attach_client(client);
-
-	return 0;
-}
-
-static int cx25840_attach_adapter(struct i2c_adapter *adapter)
-{
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, &cx25840_detect_client);
 	return 0;
 }
 
-static int cx25840_detach_client(struct i2c_client *client)
+static int cx25840_remove(struct i2c_client *client)
 {
-	struct cx25840_state *state = i2c_get_clientdata(client);
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err) {
-		return err;
-	}
-
-	kfree(state);
-	kfree(client);
-
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver i2c_driver_cx25840 = {
-	.driver = {
-		.name = "cx25840",
-	},
-	.id = I2C_DRIVERID_CX25840,
-	.attach_adapter = cx25840_attach_adapter,
-	.detach_client = cx25840_detach_client,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "cx25840",
+	.driverid = I2C_DRIVERID_CX25840,
 	.command = cx25840_command,
+	.probe = cx25840_probe,
+	.remove = cx25840_remove,
 };
-
-
-static int __init m__init(void)
-{
-	return i2c_add_driver(&i2c_driver_cx25840);
-}
-
-static void __exit m__exit(void)
-{
-	i2c_del_driver(&i2c_driver_cx25840);
-}
-
-module_init(m__init);
-module_exit(m__exit);
-
-/* ----------------------------------------------------------------------- */
-
-static void log_video_status(struct i2c_client *client)
-{
-	static const char *const fmt_strs[] = {
-		"0x0",
-		"NTSC-M", "NTSC-J", "NTSC-4.43",
-		"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
-		"0x9", "0xA", "0xB",
-		"SECAM",
-		"0xD", "0xE", "0xF"
-	};
-
-	struct cx25840_state *state = i2c_get_clientdata(client);
-	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
-	u8 gen_stat1 = cx25840_read(client, 0x40d);
-	u8 gen_stat2 = cx25840_read(client, 0x40e);
-	int vid_input = state->vid_input;
-
-	v4l_info(client, "Video signal:              %spresent\n",
-		    (gen_stat2 & 0x20) ? "" : "not ");
-	v4l_info(client, "Detected format:           %s\n",
-		    fmt_strs[gen_stat1 & 0xf]);
-
-	v4l_info(client, "Specified standard:        %s\n",
-		    vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
-
-	if (vid_input >= CX25840_COMPOSITE1 &&
-	    vid_input <= CX25840_COMPOSITE8) {
-		v4l_info(client, "Specified video input:     Composite %d\n",
-			vid_input - CX25840_COMPOSITE1 + 1);
-	} else {
-		v4l_info(client, "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
-			(vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
-	}
-
-	v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void log_audio_status(struct i2c_client *client)
-{
-	struct cx25840_state *state = i2c_get_clientdata(client);
-	u8 download_ctl = cx25840_read(client, 0x803);
-	u8 mod_det_stat0 = cx25840_read(client, 0x804);
-	u8 mod_det_stat1 = cx25840_read(client, 0x805);
-	u8 audio_config = cx25840_read(client, 0x808);
-	u8 pref_mode = cx25840_read(client, 0x809);
-	u8 afc0 = cx25840_read(client, 0x80b);
-	u8 mute_ctl = cx25840_read(client, 0x8d3);
-	int aud_input = state->aud_input;
-	char *p;
-
-	switch (mod_det_stat0) {
-	case 0x00: p = "mono"; break;
-	case 0x01: p = "stereo"; break;
-	case 0x02: p = "dual"; break;
-	case 0x04: p = "tri"; break;
-	case 0x10: p = "mono with SAP"; break;
-	case 0x11: p = "stereo with SAP"; break;
-	case 0x12: p = "dual with SAP"; break;
-	case 0x14: p = "tri with SAP"; break;
-	case 0xfe: p = "forced mode"; break;
-	default: p = "not defined";
-	}
-	v4l_info(client, "Detected audio mode:       %s\n", p);
-
-	switch (mod_det_stat1) {
-	case 0x00: p = "not defined"; break;
-	case 0x01: p = "EIAJ"; break;
-	case 0x02: p = "A2-M"; break;
-	case 0x03: p = "A2-BG"; break;
-	case 0x04: p = "A2-DK1"; break;
-	case 0x05: p = "A2-DK2"; break;
-	case 0x06: p = "A2-DK3"; break;
-	case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
-	case 0x08: p = "AM-L"; break;
-	case 0x09: p = "NICAM-BG"; break;
-	case 0x0a: p = "NICAM-DK"; break;
-	case 0x0b: p = "NICAM-I"; break;
-	case 0x0c: p = "NICAM-L"; break;
-	case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
-	case 0x0e: p = "IF FM Radio"; break;
-	case 0x0f: p = "BTSC"; break;
-	case 0x10: p = "high-deviation FM"; break;
-	case 0x11: p = "very high-deviation FM"; break;
-	case 0xfd: p = "unknown audio standard"; break;
-	case 0xfe: p = "forced audio standard"; break;
-	case 0xff: p = "no detected audio standard"; break;
-	default: p = "not defined";
-	}
-	v4l_info(client, "Detected audio standard:   %s\n", p);
-	v4l_info(client, "Audio muted:               %s\n",
-		    (state->unmute_volume >= 0) ? "yes" : "no");
-	v4l_info(client, "Audio microcontroller:     %s\n",
-		    (download_ctl & 0x10) ?
-				((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
-
-	switch (audio_config >> 4) {
-	case 0x00: p = "undefined"; break;
-	case 0x01: p = "BTSC"; break;
-	case 0x02: p = "EIAJ"; break;
-	case 0x03: p = "A2-M"; break;
-	case 0x04: p = "A2-BG"; break;
-	case 0x05: p = "A2-DK1"; break;
-	case 0x06: p = "A2-DK2"; break;
-	case 0x07: p = "A2-DK3"; break;
-	case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
-	case 0x09: p = "AM-L"; break;
-	case 0x0a: p = "NICAM-BG"; break;
-	case 0x0b: p = "NICAM-DK"; break;
-	case 0x0c: p = "NICAM-I"; break;
-	case 0x0d: p = "NICAM-L"; break;
-	case 0x0e: p = "FM radio"; break;
-	case 0x0f: p = "automatic detection"; break;
-	default: p = "undefined";
-	}
-	v4l_info(client, "Configured audio standard: %s\n", p);
-
-	if ((audio_config >> 4) < 0xF) {
-		switch (audio_config & 0xF) {
-		case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
-		case 0x01: p = "MONO2 (LANGUAGE B)"; break;
-		case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
-		case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
-		case 0x04: p = "STEREO"; break;
-		case 0x05: p = "DUAL1 (AB)"; break;
-		case 0x06: p = "DUAL2 (AC) (FM)"; break;
-		case 0x07: p = "DUAL3 (BC) (FM)"; break;
-		case 0x08: p = "DUAL4 (AC) (AM)"; break;
-		case 0x09: p = "DUAL5 (BC) (AM)"; break;
-		case 0x0a: p = "SAP"; break;
-		default: p = "undefined";
-		}
-		v4l_info(client, "Configured audio mode:     %s\n", p);
-	} else {
-		switch (audio_config & 0xF) {
-		case 0x00: p = "BG"; break;
-		case 0x01: p = "DK1"; break;
-		case 0x02: p = "DK2"; break;
-		case 0x03: p = "DK3"; break;
-		case 0x04: p = "I"; break;
-		case 0x05: p = "L"; break;
-		case 0x06: p = "BTSC"; break;
-		case 0x07: p = "EIAJ"; break;
-		case 0x08: p = "A2-M"; break;
-		case 0x09: p = "FM Radio"; break;
-		case 0x0f: p = "automatic standard and mode detection"; break;
-		default: p = "undefined";
-		}
-		v4l_info(client, "Configured audio system:   %s\n", p);
-	}
-
-	if (aud_input) {
-		v4l_info(client, "Specified audio input:     Tuner (In%d)\n", aud_input);
-	} else {
-		v4l_info(client, "Specified audio input:     External\n");
-	}
-
-	switch (pref_mode & 0xf) {
-	case 0: p = "mono/language A"; break;
-	case 1: p = "language B"; break;
-	case 2: p = "language C"; break;
-	case 3: p = "analog fallback"; break;
-	case 4: p = "stereo"; break;
-	case 5: p = "language AC"; break;
-	case 6: p = "language BC"; break;
-	case 7: p = "language AB"; break;
-	default: p = "undefined";
-	}
-	v4l_info(client, "Preferred audio mode:      %s\n", p);
-
-	if ((audio_config & 0xf) == 0xf) {
-		switch ((afc0 >> 3) & 0x3) {
-		case 0: p = "system DK"; break;
-		case 1: p = "system L"; break;
-		case 2: p = "autodetect"; break;
-		default: p = "undefined";
-		}
-		v4l_info(client, "Selected 65 MHz format:    %s\n", p);
-
-		switch (afc0 & 0x7) {
-		case 0: p = "chroma"; break;
-		case 1: p = "BTSC"; break;
-		case 2: p = "EIAJ"; break;
-		case 3: p = "A2-M"; break;
-		case 4: p = "autodetect"; break;
-		default: p = "undefined";
-		}
-		v4l_info(client, "Selected 45 MHz format:    %s\n", p);
-	}
-}
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index ea669b1f084d..95093edc9186 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -47,6 +47,7 @@ struct cx25840_state {
 	u32 id;
 	u32 rev;
 	int is_cx25836;
+	int is_cx23885;
 	int is_initialized;
 	wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
 	struct work_struct fw_work;   /* work entry for fw load */
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index e852024a5ea3..1ddf724a2c74 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -24,6 +24,7 @@
 #include "cx25840-core.h"
 
 #define FWFILE "v4l-cx25840.fw"
+#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw"
 
 /*
  * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the
@@ -92,10 +93,14 @@ static int fw_write(struct i2c_client *client, u8 * data, int size)
 
 int cx25840_loadfw(struct i2c_client *client)
 {
+	struct cx25840_state *state = i2c_get_clientdata(client);
 	const struct firmware *fw = NULL;
 	u8 buffer[4], *ptr;
 	int size, send, retval;
 
+	if (state->is_cx23885)
+		firmware = FWFILE_CX23885;
+
 	if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
 		v4l_err(client, "unable to open firmware %s\n", firmware);
 		return -EINVAL;
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index ced13febed89..6828f59b9d83 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -180,7 +180,7 @@ void cx25840_vbi_setup(struct i2c_client *client)
 						fsc/1000000,fsc%1000000);
 
 		v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
-			"vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+			"vblank %i, vactive %i, vblank656 %i, src_dec %i, "
 			"burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
 			" sc 0x%06x\n",
 			hblank, hactive, vblank, vactive, vblank656,
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index ceb31d4a2512..49d3813a9b48 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -8,6 +8,7 @@ config VIDEO_CX88
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
+	select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO
 	---help---
 	  This is a video4linux driver for Conexant 2388x based
 	  TV cards.
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 40ffd7a5579a..8735227f7e47 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -417,7 +417,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
 	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
 	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 
 	chip->buf = buf;
 	chip->dma_risc = dma;
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index f802b5653569..a99e9d5950aa 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -307,7 +307,7 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value)
 
 /* ------------------------------------------------------------------ */
 
-static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
 {
 	struct cx8802_dev *dev = priv;
 	unsigned long timeout;
@@ -536,11 +536,12 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
 	dprintk(1,"Initialize codec\n");
 	retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
 	if (retval < 0) {
+
+		dev->mpeg_active = 0;
+
 		/* ping was not successful, reset and upload firmware */
 		cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
-		msleep(1);
 		cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */
-		msleep(1);
 		retval = blackbird_load_firmware(dev);
 		if (retval < 0)
 			return retval;
@@ -562,7 +563,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
 		}
 		dprintk(0, "Firmware version is 0x%08x\n", version);
 	}
-	msleep(1);
 
 	cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */
 	cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */
@@ -570,40 +570,68 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
 	cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */
 
 	blackbird_codec_settings(dev);
-	msleep(1);
 
-	/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
-	   blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
-	   blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
 	blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
 			BLACKBIRD_FIELD1_SAA7115,
 			BLACKBIRD_FIELD2_SAA7115
 		);
 
-	/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
 	blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
 			BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
-	/* initialize the video input */
-	blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+	return 0;
+}
 
-	msleep(1);
+static int blackbird_start_codec(struct file *file, void *priv)
+{
+	struct cx8802_dev *dev  = ((struct cx8802_fh *)priv)->dev;
+	struct cx88_core *core = dev->core;
+	/* start capturing to the host interface */
+	u32 reg;
 
-	blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
-	msleep(1);
-	blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
-	msleep(1);
+	int i;
+	int lastchange = -1;
+	int lastval = 0;
+
+	for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) {
+		reg = cx_read(AUD_STATUS);
+
+		dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg);
+		if ((reg & 0x0F) != lastval) {
+			lastval = reg & 0x0F;
+			lastchange = i;
+		}
+		msleep(100);
+	}
+
+	/* unmute audio source */
+	cx_clear(AUD_VOL_CTL, (1 << 6));
+
+	blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0);
+
+	/* initialize the video input */
+	blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
 
 	/* start capturing to the host interface */
-	/* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */
 	blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
 			BLACKBIRD_MPEG_CAPTURE,
 			BLACKBIRD_RAW_BITS_NONE
 		);
-	msleep(10);
 
-	blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0);
+	dev->mpeg_active = 1;
+	return 0;
+}
+
+static int blackbird_stop_codec(struct cx8802_dev *dev)
+{
+	blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+			BLACKBIRD_END_NOW,
+			BLACKBIRD_MPEG_CAPTURE,
+			BLACKBIRD_RAW_BITS_NONE
+		);
+
+	dev->mpeg_active = 0;
 	return 0;
 }
 
@@ -833,6 +861,10 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv,
 
 	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
 		return -EINVAL;
+
+	if (dev->mpeg_active)
+		blackbird_stop_codec(dev);
+
 	p = dev->params;
 	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
 	if (!err) {
@@ -864,10 +896,9 @@ static int vidioc_s_frequency (struct file *file, void *priv,
 	struct cx8802_dev *dev  = fh->dev;
 	struct cx88_core  *core = dev->core;
 
-	blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
-				BLACKBIRD_END_NOW,
-				BLACKBIRD_MPEG_CAPTURE,
-				BLACKBIRD_RAW_BITS_NONE);
+	if (dev->mpeg_active)
+		blackbird_stop_codec(dev);
+
 	cx88_set_freq (core,f);
 	blackbird_initialize_codec(dev);
 	cx88_set_scale(dev->core, dev->width, dev->height,
@@ -1073,15 +1104,11 @@ static int mpeg_open(struct inode *inode, struct file *file)
 static int mpeg_release(struct inode *inode, struct file *file)
 {
 	struct cx8802_fh  *fh  = file->private_data;
-	struct cx8802_dev *dev = NULL;
+	struct cx8802_dev *dev = fh->dev;
 	struct cx8802_driver *drv = NULL;
 
-	/* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
-	blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
-			BLACKBIRD_END_NOW,
-			BLACKBIRD_MPEG_CAPTURE,
-			BLACKBIRD_RAW_BITS_NONE
-		);
+	if (dev->mpeg_active)
+		blackbird_stop_codec(dev);
 
 	cx8802_cancel_buffers(fh->dev);
 	/* stop mpeg capture */
@@ -1107,6 +1134,10 @@ static ssize_t
 mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
 	struct cx8802_fh *fh = file->private_data;
+	struct cx8802_dev *dev = fh->dev;
+
+	if (!dev->mpeg_active)
+		blackbird_start_codec(file, fh);
 
 	return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
 				    file->f_flags & O_NONBLOCK);
@@ -1282,6 +1313,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
 	       core->name);
 	host_setup(dev->core);
 
+	blackbird_initialize_codec(dev);
 	blackbird_register_video(dev);
 
 	/* initial device configuration: needed ? */
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index a4eb6a87a761..e6b7f518c56e 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 
 #include "cx88.h"
+#include "tea5767.h"
 
 static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
 static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
@@ -245,6 +246,10 @@ static const struct cx88_board cx88_boards[] = {
 		}},
 		.radio = {
 			 .type   = CX88_RADIO,
+			 .vmux   = 3,
+			 .gpio0  = 0x000040bf,
+			 .gpio1  = 0x000080c0,
+			 .gpio2  = 0x0000ff20,
 		},
 	},
 	[CX88_BOARD_WINFAST_DV2000] = {
@@ -297,22 +302,22 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x0000bde2,
-			.extadc = 1,
+			.audioroute = 1,
 		},{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x0000bde6,
-			.extadc = 1,
+			.audioroute = 1,
 		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0000bde6,
-			.extadc = 1,
+			.audioroute = 1,
 		}},
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x0000bd62,
-			.extadc = 1,
+			.audioroute = 1,
 		},
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
@@ -373,7 +378,7 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
-			.extadc = 1,
+			.audioroute = 1,
 		}},
 		.radio = {
 			.type   = CX88_RADIO,
@@ -544,7 +549,7 @@ static const struct cx88_board cx88_boards[] = {
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
-			.extadc = 1,
+			.audioroute = 1,
 		}},
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
@@ -667,22 +672,22 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00009d80,
-			.extadc = 1,
+			.audioroute = 1,
 		},{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00009d76,
-			.extadc = 1,
+			.audioroute = 1,
 		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00009d76,
-			.extadc = 1,
+			.audioroute = 1,
 		}},
 		.radio = {
 			.type   = CX88_RADIO,
 			.gpio0  = 0x00009d00,
-			.extadc = 1,
+			.audioroute = 1,
 		},
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
@@ -821,23 +826,23 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 0,
 			.gpio0  = 0x0000cd73,
-			.extadc = 1,
+			.audioroute = 1,
 		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 1,
 			.gpio0  = 0x0000cd73,
-			.extadc = 1,
+			.audioroute = 1,
 		},{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 3,
 			.gpio0  = 0x0000cdb3,
-			.extadc = 1,
+			.audioroute = 1,
 		}},
 		.radio = {
 			.type   = CX88_RADIO,
 			.vmux   = 2,
 			.gpio0  = 0x0000cdf3,
-			.extadc = 1,
+			.audioroute = 1,
 		},
 		.mpeg           = CX88_MPEG_BLACKBIRD,
 	},
@@ -1105,12 +1110,12 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x3de6,
-			.extadc = 1,
+			.audioroute = 1,
 		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x3de6,
-			.extadc = 1,
+			.audioroute = 1,
 		}},
 		.radio = {
 			.type   = CX88_RADIO,
@@ -1335,17 +1340,17 @@ static const struct cx88_board cx88_boards[] = {
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0	= 0xe780,
-			.extadc = 1,
+			.audioroute = 1,
 		},{
 			.type	= CX88_VMUX_COMPOSITE1,
 			.vmux	= 1,
 			.gpio0	= 0xe780,
-			.extadc = 1,
+			.audioroute = 2,
 		},{
 			.type	= CX88_VMUX_SVIDEO,
 			.vmux	= 2,
 			.gpio0	= 0xe780,
-			.extadc = 1,
+			.audioroute = 2,
 		}},
 		/* fixme: Add radio support */
 		.mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
@@ -1370,6 +1375,32 @@ static const struct cx88_board cx88_boards[] = {
 			.gpio0  = 0x07fa,
 		}},
 	},
+	[CX88_BOARD_PINNACLE_PCTV_HD_800i] = {
+		.name           = "Pinnacle PCTV HD 800i",
+		.tuner_type     = TUNER_XC5000,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0x04fb,
+			.gpio1  = 0x10ff,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x04fb,
+			.gpio1  = 0x10ef,
+			.audioroute = 1,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x04fb,
+			.gpio1  = 0x10ef,
+			.audioroute = 1,
+		}},
+		.mpeg           = CX88_MPEG_DVB,
+	},
 };
 
 /* ------------------------------------------------------------------ */
@@ -1679,6 +1710,10 @@ static const struct cx88_subid cx88_subids[] = {
 		.subvendor = 0x1421,
 		.subdevice = 0x0390,
 		.card      = CX88_BOARD_ADSTECH_PTV_390,
+	},{
+		.subvendor = 0x11bd,
+		.subdevice = 0x0051,
+		.card      = CX88_BOARD_PINNACLE_PCTV_HD_800i,
 	},
 };
 
@@ -1846,6 +1881,36 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
 }
 
 /* ----------------------------------------------------------------------- */
+/* Tuner callback function. Currently only needed for the Pinnacle 	   *
+ * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both	   *
+ * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c)    */
+
+int cx88_tuner_callback(void *priv, int command, int arg)
+{
+	struct i2c_algo_bit_data *i2c_algo = priv;
+	struct cx88_core *core = i2c_algo->data;
+
+	switch(core->boardnr) {
+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+		if(command == 0) { /* This is the reset command from xc5000 */
+			/* Reset XC5000 tuner via SYS_RSTO_pin */
+			cx_write(MO_SRST_IO, 0);
+			msleep(10);
+			cx_write(MO_SRST_IO, 1);
+			return 0;
+		}
+		else {
+			printk(KERN_ERR
+				"xc5000: unknown tuner callback command.\n");
+			return -EINVAL;
+		}
+		break;
+	}
+	return 0; /* Should never be here */
+}
+EXPORT_SYMBOL(cx88_tuner_callback);
+
+/* ----------------------------------------------------------------------- */
 
 static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
 {
@@ -1979,6 +2044,23 @@ static void cx88_card_setup(struct cx88_core *core)
 						core->name, i);
 		}
 		break;
+	case CX88_BOARD_MSI_TVANYWHERE_MASTER:
+	{
+		struct v4l2_priv_tun_config tea5767_cfg;
+		struct tea5767_ctrl ctl;
+
+		memset(&ctl, 0, sizeof(ctl));
+
+		ctl.high_cut  = 1;
+		ctl.st_noise  = 1;
+		ctl.deemph_75 = 1;
+		ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
+
+		tea5767_cfg.tuner = TUNER_TEA5767;
+		tea5767_cfg.priv  = &ctl;
+
+		cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
+	}
 	}
 }
 
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 62e8dd24c5f5..01e2ac98970b 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -220,7 +220,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
 	videobuf_dma_unmap(q, dma);
 	videobuf_dma_free(dma);
 	btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
-	buf->vb.state = STATE_NEEDS_INIT;
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 /* ------------------------------------------------------------------ */
@@ -538,7 +538,7 @@ void cx88_wakeup(struct cx88_core *core,
 		do_gettimeofday(&buf->vb.ts);
 		dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
 			count, buf->count);
-		buf->vb.state = STATE_DONE;
+		buf->vb.state = VIDEOBUF_DONE;
 		list_del(&buf->vb.queue);
 		wake_up(&buf->vb.done);
 	}
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index fce19caf9d04..f7b41eb1bb5a 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -40,6 +40,8 @@
 #include "cx22702.h"
 #include "or51132.h"
 #include "lgdt330x.h"
+#include "s5h1409.h"
+#include "xc5000.h"
 #include "nxt200x.h"
 #include "cx24123.h"
 #include "isl6421.h"
@@ -371,6 +373,22 @@ static struct cx24123_config kworld_dvbs_100_config = {
 	.lnb_polarity  = 1,
 };
 
+static struct s5h1409_config pinnacle_pctv_hd_800i_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_PARALLEL_OUTPUT,
+	.gpio	       = S5H1409_GPIO_ON,
+	.qam_if	       = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING,
+	.mpeg_timing   = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
+	.i2c_address	= 0x64,
+	.if_khz		= 5380,
+	.tuner_callback	= cx88_tuner_callback,
+};
+
 static int dvb_register(struct cx8802_dev *dev)
 {
 	/* init struct videobuf_dvb */
@@ -625,6 +643,21 @@ static int dvb_register(struct cx8802_dev *dev)
 			dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
 		}
 		break;
+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+		dev->dvb.frontend = dvb_attach(s5h1409_attach,
+					       &pinnacle_pctv_hd_800i_config,
+					       &dev->core->i2c_adap);
+		if (dev->dvb.frontend != NULL) {
+			/* tuner_config.video_dev must point to
+			 * i2c_adap.algo_data
+			 */
+			pinnacle_pctv_hd_800i_tuner_config.priv =
+						dev->core->i2c_adap.algo_data;
+			dvb_attach(xc5000_attach, dev->dvb.frontend,
+				   &dev->core->i2c_adap,
+				   &pinnacle_pctv_hd_800i_tuner_config);
+		}
+		break;
 	default:
 		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index c8b1c50625f4..566b26af523e 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -109,26 +109,32 @@ static int attach_inform(struct i2c_client *client)
 
 	if (core->board.radio_type != UNSET) {
 		if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) {
-			tun_setup.mode_mask = T_RADIO;
-			tun_setup.type = core->board.radio_type;
-			tun_setup.addr = core->board.radio_addr;
-
+			tun_setup.mode_mask	 = T_RADIO;
+			tun_setup.type		 = core->board.radio_type;
+			tun_setup.addr		 = core->board.radio_addr;
+			tun_setup.tuner_callback = cx88_tuner_callback;
 			client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
 	}
 	if (core->board.tuner_type != UNSET) {
 		if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) {
 
-			tun_setup.mode_mask = T_ANALOG_TV;
-			tun_setup.type = core->board.tuner_type;
-			tun_setup.addr = core->board.tuner_addr;
-
+			tun_setup.mode_mask	 = T_ANALOG_TV;
+			tun_setup.type		 = core->board.tuner_type;
+			tun_setup.addr		 = core->board.tuner_addr;
+			tun_setup.tuner_callback = cx88_tuner_callback;
 			client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
 	}
 
-	if (core->board.tda9887_conf)
-		client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf);
+	if (core->board.tda9887_conf) {
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv  = &core->board.tda9887_conf;
+
+		client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg);
+	}
 	return 0;
 }
 
@@ -176,6 +182,7 @@ static char *i2c_devs[128] = {
 	[ 0xa0 >> 1 ] = "eeprom",
 	[ 0xc0 >> 1 ] = "tuner (analog)",
 	[ 0xc2 >> 1 ] = "tuner (analog/dvb)",
+	[ 0xc8 >> 1 ] = "xc5000",
 };
 
 static void do_i2c_scan(char *name, struct i2c_client *c)
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index e52de3968c63..bb0911b4d2f6 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -305,6 +305,11 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
 		ir->mask_keycode = 0xfa;
 		ir->polling = 50; /* ms */
 		break;
+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+		ir_codes = ir_codes_pinnacle_pctv_hd;
+		ir_type = IR_TYPE_RC5;
+		ir->sampling = 1;
+		break;
 	}
 
 	if (NULL == ir_codes) {
@@ -443,6 +448,7 @@ void cx88_ir_irq(struct cx88_core *core)
 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
 	case CX88_BOARD_HAUPPAUGE_HVR3000:
+	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
 		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
 		ir_dprintk("biphase decoded: %x\n", ircode);
 		if ((ircode & 0xfffff000) != 0x3000)
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 448c67380945..0aedbeaf94cd 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -102,7 +102,7 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
 		cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
 		udelay(100);
 		cx_write(MO_PINMUX_IO, 0x00);
-		cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01);
+		cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01);
 		switch (core->boardnr) {
 		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
 		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
@@ -117,6 +117,15 @@ static int cx8802_start_dma(struct cx8802_dev    *dev,
 			break;
 		case CX88_BOARD_HAUPPAUGE_HVR1300:
 			break;
+		case CX88_BOARD_PINNACLE_PCTV_HD_800i:
+			/* Enable MPEG parallel IO and video signal pins */
+			cx_write(MO_PINMUX_IO, 0x88);
+			cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4));
+			dev->ts_gen_cntrl = 5;
+			cx_write(TS_SOP_STAT, 0);
+			cx_write(TS_VALERR_CNTRL, 0);
+			udelay(100);
+			break;
 		default:
 			cx_write(TS_SOP_STAT, 0x00);
 			break;
@@ -195,7 +204,7 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
 				list_del(&buf->vb.queue);
 				list_add_tail(&buf->vb.queue,&q->active);
 				cx8802_start_dma(dev, q, buf);
-				buf->vb.state = STATE_ACTIVE;
+				buf->vb.state = VIDEOBUF_ACTIVE;
 				buf->count    = q->count++;
 				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
 				dprintk(1,"[%p/%d] restart_queue - first active\n",
@@ -206,7 +215,7 @@ static int cx8802_restart_queue(struct cx8802_dev    *dev,
 				   prev->fmt       == buf->fmt) {
 				list_del(&buf->vb.queue);
 				list_add_tail(&buf->vb.queue,&q->active);
-				buf->vb.state = STATE_ACTIVE;
+				buf->vb.state = VIDEOBUF_ACTIVE;
 				buf->count    = q->count++;
 				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 				dprintk(1,"[%p/%d] restart_queue - move to active\n",
@@ -242,7 +251,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
 		return -EINVAL;
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		buf->vb.width  = dev->ts_packet_size;
 		buf->vb.height = dev->ts_packet_count;
 		buf->vb.size   = size;
@@ -254,7 +263,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
 				     dma->sglist,
 				     buf->vb.width, buf->vb.height, 0);
 	}
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	return 0;
 
  fail:
@@ -276,7 +285,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
 		dprintk( 1, "queue is empty - first active\n" );
 		list_add_tail(&buf->vb.queue,&cx88q->active);
 		cx8802_start_dma(dev, cx88q, buf);
-		buf->vb.state = STATE_ACTIVE;
+		buf->vb.state = VIDEOBUF_ACTIVE;
 		buf->count    = cx88q->count++;
 		mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
 		dprintk(1,"[%p/%d] %s - first active\n",
@@ -286,7 +295,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
 		dprintk( 1, "queue is not empty - append to active\n" );
 		prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue);
 		list_add_tail(&buf->vb.queue,&cx88q->active);
-		buf->vb.state = STATE_ACTIVE;
+		buf->vb.state = VIDEOBUF_ACTIVE;
 		buf->count    = cx88q->count++;
 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 		dprintk( 1, "[%p/%d] %s - append to active\n",
@@ -306,7 +315,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
 	while (!list_empty(&q->active)) {
 		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
 		list_del(&buf->vb.queue);
-		buf->vb.state = STATE_ERROR;
+		buf->vb.state = VIDEOBUF_ERROR;
 		wake_up(&buf->vb.done);
 		dprintk(1,"[%p/%d] %s - dma=0x%08lx\n",
 			buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
@@ -437,10 +446,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id)
 	return IRQ_RETVAL(handled);
 }
 
-/* ----------------------------------------------------------- */
-/* exported stuff                                              */
-
-int cx8802_init_common(struct cx8802_dev *dev)
+static int cx8802_init_common(struct cx8802_dev *dev)
 {
 	struct cx88_core *core = dev->core;
 	int err;
@@ -488,7 +494,7 @@ int cx8802_init_common(struct cx8802_dev *dev)
 	return 0;
 }
 
-void cx8802_fini_common(struct cx8802_dev *dev)
+static void cx8802_fini_common(struct cx8802_dev *dev)
 {
 	dprintk( 2, "cx8802_fini_common\n" );
 	cx8802_stop_dma(dev);
@@ -504,7 +510,7 @@ void cx8802_fini_common(struct cx8802_dev *dev)
 
 /* ----------------------------------------------------------- */
 
-int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
+static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
 {
 	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 	struct cx88_core *core = dev->core;
@@ -530,7 +536,7 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
 	return 0;
 }
 
-int cx8802_resume_common(struct pci_dev *pci_dev)
+static int cx8802_resume_common(struct pci_dev *pci_dev)
 {
 	struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 	struct cx88_core *core = dev->core;
@@ -874,9 +880,6 @@ EXPORT_SYMBOL(cx8802_buf_prepare);
 EXPORT_SYMBOL(cx8802_buf_queue);
 EXPORT_SYMBOL(cx8802_cancel_buffers);
 
-EXPORT_SYMBOL(cx8802_init_common);
-EXPORT_SYMBOL(cx8802_fini_common);
-
 EXPORT_SYMBOL(cx8802_register_driver);
 EXPORT_SYMBOL(cx8802_unregister_driver);
 EXPORT_SYMBOL(cx8802_get_driver);
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index babb08556406..d96ecfcf393a 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -130,7 +130,7 @@ void cx8800_vbi_timeout(unsigned long data)
 	while (!list_empty(&q->active)) {
 		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
 		list_del(&buf->vb.queue);
-		buf->vb.state = STATE_ERROR;
+		buf->vb.state = VIDEOBUF_ERROR;
 		wake_up(&buf->vb.done);
 		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name,
 		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
@@ -168,7 +168,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
 		return -EINVAL;
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 		buf->vb.width  = VBI_LINE_LENGTH;
 		buf->vb.height = VBI_LINE_COUNT;
@@ -183,7 +183,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
 				 buf->vb.width, 0,
 				 buf->vb.height);
 	}
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	return 0;
 
  fail:
@@ -207,7 +207,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 	if (list_empty(&q->active)) {
 		list_add_tail(&buf->vb.queue,&q->active);
 		cx8800_start_vbi_dma(dev, q, buf);
-		buf->vb.state = STATE_ACTIVE;
+		buf->vb.state = VIDEOBUF_ACTIVE;
 		buf->count    = q->count++;
 		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
 		dprintk(2,"[%p/%d] vbi_queue - first active\n",
@@ -216,7 +216,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 	} else {
 		prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
 		list_add_tail(&buf->vb.queue,&q->active);
-		buf->vb.state = STATE_ACTIVE;
+		buf->vb.state = VIDEOBUF_ACTIVE;
 		buf->count    = q->count++;
 		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 		dprintk(2,"[%p/%d] buffer_queue - append to active\n",
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index c84dafbdb991..7f1931aed207 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -392,13 +392,41 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
 		break;
 	}
 
-	if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
-		/* sets sound input from external adc */
-		if (INPUT(input).extadc)
+	/* if there are audioroutes defined, we have an external
+	   ADC to deal with audio */
+
+	if (INPUT(input).audioroute) {
+
+		/* cx2388's C-ADC is connected to the tuner only.
+		   When used with S-Video, that ADC is busy dealing with
+		   chroma, so an external must be used for baseband audio */
+
+		if (INPUT(input).type != CX88_VMUX_TELEVISION &&
+			INPUT(input).type != CX88_RADIO) {
+			/* "ADC mode" */
+			cx_write(AUD_I2SCNTL, 0x1);
 			cx_set(AUD_CTL, EN_I2SIN_ENABLE);
-		else
+		} else {
+			/* Normal mode */
+			cx_write(AUD_I2SCNTL, 0x0);
 			cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
+		}
+
+		/* The wm8775 module has the "2" route hardwired into
+		   the initialization. Some boards may use different
+		   routes for different inputs. HVR-1300 surely does */
+		if (core->board.audio_chip &&
+		    core->board.audio_chip == AUDIO_CHIP_WM8775) {
+			struct v4l2_routing route;
+
+			route.input = INPUT(input).audioroute;
+			cx88_call_i2c_clients(core,
+				VIDIOC_INT_S_AUDIO_ROUTING, &route);
+
+		}
+
 	}
+
 	return 0;
 }
 EXPORT_SYMBOL(cx88_video_mux);
@@ -486,7 +514,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
 		if (NULL == prev) {
 			list_move_tail(&buf->vb.queue, &q->active);
 			start_video_dma(dev, q, buf);
-			buf->vb.state = STATE_ACTIVE;
+			buf->vb.state = VIDEOBUF_ACTIVE;
 			buf->count    = q->count++;
 			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
 			dprintk(2,"[%p/%d] restart_queue - first active\n",
@@ -496,7 +524,7 @@ static int restart_video_queue(struct cx8800_dev    *dev,
 			   prev->vb.height == buf->vb.height &&
 			   prev->fmt       == buf->fmt) {
 			list_move_tail(&buf->vb.queue, &q->active);
-			buf->vb.state = STATE_ACTIVE;
+			buf->vb.state = VIDEOBUF_ACTIVE;
 			buf->count    = q->count++;
 			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 			dprintk(2,"[%p/%d] restart_queue - move to active\n",
@@ -553,7 +581,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
 		init_buffer = 1;
 	}
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		init_buffer = 1;
 		if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
 			goto fail;
@@ -601,7 +629,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
 		fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
 		(unsigned long)buf->risc.dma);
 
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	return 0;
 
  fail:
@@ -625,14 +653,14 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 
 	if (!list_empty(&q->queued)) {
 		list_add_tail(&buf->vb.queue,&q->queued);
-		buf->vb.state = STATE_QUEUED;
+		buf->vb.state = VIDEOBUF_QUEUED;
 		dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
 			buf, buf->vb.i);
 
 	} else if (list_empty(&q->active)) {
 		list_add_tail(&buf->vb.queue,&q->active);
 		start_video_dma(dev, q, buf);
-		buf->vb.state = STATE_ACTIVE;
+		buf->vb.state = VIDEOBUF_ACTIVE;
 		buf->count    = q->count++;
 		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
 		dprintk(2,"[%p/%d] buffer_queue - first active\n",
@@ -644,7 +672,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 		    prev->vb.height == buf->vb.height &&
 		    prev->fmt       == buf->fmt) {
 			list_add_tail(&buf->vb.queue,&q->active);
-			buf->vb.state = STATE_ACTIVE;
+			buf->vb.state = VIDEOBUF_ACTIVE;
 			buf->count    = q->count++;
 			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 			dprintk(2,"[%p/%d] buffer_queue - append to active\n",
@@ -652,7 +680,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 
 		} else {
 			list_add_tail(&buf->vb.queue,&q->queued);
-			buf->vb.state = STATE_QUEUED;
+			buf->vb.state = VIDEOBUF_QUEUED;
 			dprintk(2,"[%p/%d] buffer_queue - first queued\n",
 				buf, buf->vb.i);
 		}
@@ -822,8 +850,8 @@ video_poll(struct file *file, struct poll_table_struct *wait)
 			return POLLERR;
 	}
 	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == STATE_DONE ||
-	    buf->vb.state == STATE_ERROR)
+	if (buf->vb.state == VIDEOBUF_DONE ||
+	    buf->vb.state == VIDEOBUF_ERROR)
 		return POLLIN|POLLRDNORM;
 	return 0;
 }
@@ -1496,7 +1524,7 @@ static void cx8800_vid_timeout(unsigned long data)
 	while (!list_empty(&q->active)) {
 		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
 		list_del(&buf->vb.queue);
-		buf->vb.state = STATE_ERROR;
+		buf->vb.state = VIDEOBUF_ERROR;
 		wake_up(&buf->vb.done);
 		printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name,
 		       buf, buf->vb.i, (unsigned long)buf->risc.dma);
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index eb296bdecb1e..4e823f2a539a 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -210,6 +210,7 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_TE_DTV_250_OEM_SWANN    55
 #define CX88_BOARD_HAUPPAUGE_HVR1300       56
 #define CX88_BOARD_ADSTECH_PTV_390         57
+#define CX88_BOARD_PINNACLE_PCTV_HD_800i   58
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -228,7 +229,7 @@ struct cx88_input {
 	enum cx88_itype type;
 	u32             gpio0, gpio1, gpio2, gpio3;
 	unsigned int    vmux:2;
-	unsigned int    extadc:1;
+	unsigned int    audioroute:2;
 };
 
 struct cx88_board {
@@ -461,6 +462,7 @@ struct cx8802_dev {
 	u32                        mailbox;
 	int                        width;
 	int                        height;
+	unsigned char              mpeg_active; /* nonzero if mpeg encoder is active */
 
 	/* mpeg params */
 	struct cx2341x_mpeg_params params;
@@ -588,6 +590,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core,
 /* ----------------------------------------------------------- */
 /* cx88-cards.c                                                */
 
+extern int cx88_tuner_callback(void *dev, int command, int arg);
 extern int cx88_get_resources(const struct cx88_core *core,
 			      struct pci_dev *pci);
 extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
@@ -633,12 +636,6 @@ int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
 void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
 void cx8802_cancel_buffers(struct cx8802_dev *dev);
 
-int cx8802_init_common(struct cx8802_dev *dev);
-void cx8802_fini_common(struct cx8802_dev *dev);
-
-int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
-int cx8802_resume_common(struct pci_dev *pci_dev);
-
 /* ----------------------------------------------------------- */
 /* cx88-video.c*/
 extern const u32 cx88_user_ctrls[];
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
index 255dae303708..566e479e2629 100644
--- a/drivers/media/video/dpc7146.c
+++ b/drivers/media/video/dpc7146.c
@@ -87,11 +87,24 @@ struct dpc
 	int cur_input;	/* current input */
 };
 
+static int dpc_check_clients(struct device *dev, void *data)
+{
+	struct dpc* dpc = data;
+	struct i2c_client *client = i2c_verify_client(dev);
+
+	if( !client )
+		return 0;
+
+	if( I2C_SAA7111A == client->addr )
+		dpc->saa7111a = client;
+
+	return 0;
+}
+
 /* fixme: add vbi stuff here */
 static int dpc_probe(struct saa7146_dev* dev)
 {
 	struct dpc* dpc = NULL;
-	struct i2c_client *client;
 
 	dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
 	if( NULL == dpc ) {
@@ -115,9 +128,7 @@ static int dpc_probe(struct saa7146_dev* dev)
 	}
 
 	/* loop through all i2c-devices on the bus and look who is there */
-	list_for_each_entry(client, &dpc->i2c_adapter.clients, list)
-		if( I2C_SAA7111A == client->addr )
-			dpc->saa7111a = client;
+	device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients);
 
 	/* check if all devices are present */
 	if( 0 == dpc->saa7111a ) {
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index c1127802ad9c..abbd38c1ebba 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -1,6 +1,6 @@
 config VIDEO_EM28XX
 	tristate "Empia EM2800/2820/2840 USB video capture support"
-	depends on VIDEO_V4L1 && I2C && INPUT
+	depends on VIDEO_DEV && I2C && INPUT
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
@@ -11,3 +11,18 @@ config VIDEO_EM28XX
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called em28xx
+
+config VIDEO_EM28XX_ALSA
+	depends on VIDEO_EM28XX
+	tristate "Empia EM28xx ALSA audio module"
+	---help---
+	  This is an ALSA driver for some Empia 28xx based TV cards.
+
+	  This is not required for em2800/em2820/em2821 boards. However,
+	  newer em28xx devices uses Vendor Class for audio, instead of
+	  implementing the USB Audio Class. For those chips, this module
+	  will enable digital audio.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called em28xx-alsa
+
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
index 826d0e340753..0924550992d0 100644
--- a/drivers/media/video/em28xx/Makefile
+++ b/drivers/media/video/em28xx/Makefile
@@ -1,6 +1,12 @@
 em28xx-objs     := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
 		   em28xx-input.o
 
+em28xx-alsa-objs := em28xx-audio.o
+
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
 
 EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
new file mode 100644
index 000000000000..941357c4f3f5
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -0,0 +1,489 @@
+/*
+ *  Empiatech em28x1 audio extension
+ *
+ *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
+ *
+ *  Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *	- Port to work with the in-kernel driver
+ *	- Several cleanups
+ *
+ *  This driver is based on my previous au600 usb pstn audio driver
+ *  and inherits all the copyrights
+ *
+ *  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/usb.h>
+#include <linux/init.h>
+#include <linux/sound.h>
+#include <linux/spinlock.h>
+#include <linux/soundcard.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <media/v4l2-common.h>
+#include "em28xx.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
+#define dprintk(fmt, arg...) do {					\
+	    if (debug)							\
+		printk(KERN_INFO "em28xx-audio %s: " fmt,		\
+				  __FUNCTION__, ##arg); 		\
+	} while (0)
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+
+static int em28xx_isoc_audio_deinit(struct em28xx *dev)
+{
+	int i;
+
+	dprintk("Stopping isoc\n");
+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+		usb_kill_urb(dev->adev->urb[i]);
+		usb_free_urb(dev->adev->urb[i]);
+		dev->adev->urb[i] = NULL;
+	}
+
+	return 0;
+}
+
+static void em28xx_audio_isocirq(struct urb *urb)
+{
+	struct em28xx            *dev = urb->context;
+	int                      i;
+	unsigned int             oldptr;
+	unsigned long            flags;
+	int                      period_elapsed = 0;
+	int                      status;
+	unsigned char            *cp;
+	unsigned int             stride;
+	struct snd_pcm_substream *substream;
+	struct snd_pcm_runtime   *runtime;
+	if (dev->adev->capture_pcm_substream) {
+		substream = dev->adev->capture_pcm_substream;
+		runtime = substream->runtime;
+		stride = runtime->frame_bits >> 3;
+
+		for (i = 0; i < urb->number_of_packets; i++) {
+			int length =
+			    urb->iso_frame_desc[i].actual_length / stride;
+			cp = (unsigned char *)urb->transfer_buffer +
+			    urb->iso_frame_desc[i].offset;
+
+			if (!length)
+				continue;
+
+			spin_lock_irqsave(&dev->adev->slock, flags);
+
+			oldptr = dev->adev->hwptr_done_capture;
+			dev->adev->hwptr_done_capture += length;
+			if (dev->adev->hwptr_done_capture >=
+			    runtime->buffer_size)
+				dev->adev->hwptr_done_capture -=
+				    runtime->buffer_size;
+
+			dev->adev->capture_transfer_done += length;
+			if (dev->adev->capture_transfer_done >=
+			    runtime->period_size) {
+				dev->adev->capture_transfer_done -=
+				    runtime->period_size;
+				period_elapsed = 1;
+			}
+
+			spin_unlock_irqrestore(&dev->adev->slock, flags);
+
+			if (oldptr + length >= runtime->buffer_size) {
+				unsigned int cnt =
+				    runtime->buffer_size - oldptr - 1;
+				memcpy(runtime->dma_area + oldptr * stride, cp,
+				       cnt * stride);
+				memcpy(runtime->dma_area, cp + cnt,
+				       length * stride - cnt * stride);
+			} else {
+				memcpy(runtime->dma_area + oldptr * stride, cp,
+				       length * stride);
+			}
+		}
+		if (period_elapsed)
+			snd_pcm_period_elapsed(substream);
+	}
+	urb->status = 0;
+
+	if (dev->adev->shutdown)
+		return;
+
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status < 0) {
+		em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
+			      status);
+	}
+	return;
+}
+
+static int em28xx_init_audio_isoc(struct em28xx *dev)
+{
+	int       i, errCode;
+	const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
+			    EM28XX_AUDIO_MAX_PACKET_SIZE;
+
+	dprintk("Starting isoc transfers\n");
+
+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+		struct urb *urb;
+		int j, k;
+
+		dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
+		if (!dev->adev->transfer_buffer[i])
+			return -ENOMEM;
+
+		memset(dev->adev->transfer_buffer[i], 0x80, sb_size);
+		urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+		if (!urb)
+			return -ENOMEM;
+
+		urb->dev = dev->udev;
+		urb->context = dev;
+		urb->pipe = usb_rcvisocpipe(dev->udev, 0x83);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = dev->adev->transfer_buffer[i];
+		urb->interval = 1;
+		urb->complete = em28xx_audio_isocirq;
+		urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
+		urb->transfer_buffer_length = sb_size;
+
+		for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
+			     j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length =
+			    EM28XX_AUDIO_MAX_PACKET_SIZE;
+		}
+		dev->adev->urb[i] = urb;
+	}
+
+	for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+		errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC);
+		if (errCode) {
+			em28xx_isoc_audio_deinit(dev);
+
+			return errCode;
+		}
+	}
+
+	return 0;
+}
+
+static int em28xx_cmd(struct em28xx *dev, int cmd, int arg)
+{
+	dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)?
+				 "stop" : "start");
+
+	switch (cmd) {
+	case EM28XX_CAPTURE_STREAM_EN:
+		if (dev->adev->capture_stream == STREAM_OFF && arg == 1) {
+			dev->adev->capture_stream = STREAM_ON;
+			em28xx_init_audio_isoc(dev);
+		} else if (dev->adev->capture_stream == STREAM_ON && arg == 0) {
+			dev->adev->capture_stream = STREAM_OFF;
+			em28xx_isoc_audio_deinit(dev);
+		} else {
+			printk(KERN_ERR "An underrun very likely occurred. "
+					"Ignoring it.\n");
+		}
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
+					size_t size)
+{
+	struct snd_pcm_runtime *runtime = subs->runtime;
+
+	dprintk("Alocating vbuffer\n");
+	if (runtime->dma_area) {
+		if (runtime->dma_bytes > size)
+			return 0;
+
+		vfree(runtime->dma_area);
+	}
+	runtime->dma_area = vmalloc(size);
+	if (!runtime->dma_area)
+		return -ENOMEM;
+
+	runtime->dma_bytes = size;
+
+	return 0;
+}
+
+static struct snd_pcm_hardware snd_em28xx_hw_capture = {
+	.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP           |
+		SNDRV_PCM_INFO_INTERLEAVED    |
+		SNDRV_PCM_INFO_MMAP_VALID,
+
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+	.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
+
+	.rate_min = 48000,
+	.rate_max = 48000,
+	.channels_min = 2,
+	.channels_max = 2,
+	.buffer_bytes_max = 62720 * 8,	/* just about the value in usbaudio.c */
+	.period_bytes_min = 64,		/* 12544/2, */
+	.period_bytes_max = 12544,
+	.periods_min = 2,
+	.periods_max = 98,		/* 12544, */
+};
+
+static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
+{
+	struct em28xx *dev = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret = 0;
+
+	dprintk("opening device and trying to acquire exclusive lock\n");
+
+	/* Sets volume, mute, etc */
+	dev->mute = 0;
+	ret = em28xx_audio_analog_set(dev);
+	if (ret < 0)
+		goto err;
+
+	runtime->hw = snd_em28xx_hw_capture;
+	if (dev->alt == 0 && dev->adev->users == 0) {
+		int errCode;
+		dev->alt = 7;
+		errCode = usb_set_interface(dev->udev, 0, 7);
+		dprintk("changing alternate number to 7\n");
+	}
+
+	dev->adev->users++;
+
+	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	dev->adev->capture_pcm_substream = substream;
+	runtime->private_data = dev;
+
+	return 0;
+err:
+	printk(KERN_ERR "Error while configuring em28xx mixer\n");
+	return ret;
+}
+
+static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct em28xx *dev = snd_pcm_substream_chip(substream);
+	dev->adev->users--;
+
+	dprintk("closing device\n");
+
+	dev->mute = 1;
+	em28xx_audio_analog_set(dev);
+
+	if (dev->adev->users == 0 && dev->adev->shutdown == 1) {
+		dprintk("audio users: %d\n", dev->adev->users);
+		dprintk("disabling audio stream!\n");
+		dev->adev->shutdown = 0;
+		dprintk("released lock\n");
+		em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
+	}
+	return 0;
+}
+
+static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *hw_params)
+{
+	unsigned int channels, rate, format;
+	int ret;
+
+	dprintk("Setting capture parameters\n");
+
+	ret = snd_pcm_alloc_vmalloc_buffer(substream,
+				params_buffer_bytes(hw_params));
+	format = params_format(hw_params);
+	rate = params_rate(hw_params);
+	channels = params_channels(hw_params);
+
+	/* TODO: set up em28xx audio chip to deliver the correct audio format,
+	   current default is 48000hz multiplexed => 96000hz mono
+	   which shouldn't matter since analogue TV only supports mono */
+	return 0;
+}
+
+static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
+{
+	struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+	dprintk("Stop capture, if needed\n");
+
+	if (dev->adev->capture_stream == STREAM_ON)
+		em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0);
+
+	return 0;
+}
+
+static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
+				      int cmd)
+{
+	struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+	dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START)?
+				       "start": "stop");
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1);
+		return 0;
+	case SNDRV_PCM_TRIGGER_STOP:
+		dev->adev->shutdown = 1;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
+						    *substream)
+{
+	struct em28xx *dev;
+
+	snd_pcm_uframes_t hwptr_done;
+	dev = snd_pcm_substream_chip(substream);
+	hwptr_done = dev->adev->hwptr_done_capture;
+
+	return hwptr_done;
+}
+
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+					     unsigned long offset)
+{
+	void *pageptr = subs->runtime->dma_area + offset;
+
+	return vmalloc_to_page(pageptr);
+}
+
+static struct snd_pcm_ops snd_em28xx_pcm_capture = {
+	.open      = snd_em28xx_capture_open,
+	.close     = snd_em28xx_pcm_close,
+	.ioctl     = snd_pcm_lib_ioctl,
+	.hw_params = snd_em28xx_hw_capture_params,
+	.hw_free   = snd_em28xx_hw_capture_free,
+	.prepare   = snd_em28xx_prepare,
+	.trigger   = snd_em28xx_capture_trigger,
+	.pointer   = snd_em28xx_capture_pointer,
+	.page      = snd_pcm_get_vmalloc_page,
+};
+
+static int em28xx_audio_init(struct em28xx *dev)
+{
+	struct em28xx_audio *adev;
+	struct snd_pcm      *pcm;
+	struct snd_card     *card;
+	static int          devnr;
+	int                 ret, err;
+
+	printk(KERN_INFO "em28xx-audio.c: probing for em28x1 "
+			 "non standard usbaudio\n");
+	printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
+			 "Rechberger\n");
+
+	adev = kzalloc(sizeof(*adev), GFP_KERNEL);
+	if (!adev) {
+		printk(KERN_ERR "em28xx-audio.c: out of memory\n");
+		return -1;
+	}
+	card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0);
+	if (card == NULL) {
+		kfree(adev);
+		return -ENOMEM;
+	}
+
+	spin_lock_init(&adev->slock);
+	ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
+	pcm->info_flags = 0;
+	pcm->private_data = dev;
+	strcpy(pcm->name, "Empia 28xx Capture");
+	strcpy(card->driver, "Empia Em28xx Audio");
+	strcpy(card->shortname, "Em28xx Audio");
+	strcpy(card->longname, "Empia Em28xx Audio");
+
+	err = snd_card_register(card);
+	if (err < 0) {
+		snd_card_free(card);
+		return -ENOMEM;
+	}
+	adev->sndcard = card;
+	adev->udev = dev->udev;
+	dev->adev = adev;
+
+	return 0;
+}
+
+static int em28xx_audio_fini(struct em28xx *dev)
+{
+	if (dev == NULL)
+		return 0;
+
+	if (dev->adev) {
+		snd_card_free(dev->adev->sndcard);
+		kfree(dev->adev);
+		dev->adev = NULL;
+	}
+
+	return 0;
+}
+
+static struct em28xx_ops audio_ops = {
+	.id   = EM28XX_AUDIO,
+	.name = "Em28xx Audio Extension",
+	.init = em28xx_audio_init,
+	.fini = em28xx_audio_fini,
+};
+
+static int __init em28xx_alsa_register(void)
+{
+	return em28xx_register_extension(&audio_ops);
+}
+
+static void __exit em28xx_alsa_unregister(void)
+{
+	em28xx_unregister_extension(&audio_ops);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_DESCRIPTION("Em28xx Audio driver");
+
+module_init(em28xx_alsa_register);
+module_exit(em28xx_alsa_unregister);
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 418ea8b7f85a..2159d0160df2 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -1,5 +1,6 @@
 /*
-   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+   em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB
+		    video capture devices
 
    Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
 		      Markus Rechberger <mrechberger@gmail.com>
@@ -35,294 +36,735 @@
 #include <media/v4l2-common.h>
 
 #include "em28xx.h"
+#include "tuner-xc2028.h"
+
+static int tuner = -1;
+module_param(tuner, int, 0444);
+MODULE_PARM_DESC(tuner, "tuner type");
+
+static unsigned int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
+
+struct em28xx_hash_table {
+	unsigned long hash;
+	unsigned int  model;
+	unsigned int  tuner;
+};
+
+/* Boards supported by driver */
+
+#define EM2800_BOARD_UNKNOWN			0
+#define EM2820_BOARD_UNKNOWN			1
+#define EM2820_BOARD_TERRATEC_CINERGY_250	2
+#define EM2820_BOARD_PINNACLE_USB_2		3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
+#define EM2820_BOARD_MSI_VOX_USB_2              5
+#define EM2800_BOARD_TERRATEC_CINERGY_200       6
+#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 EM2820_BOARD_PROLINK_PLAYTV_USB2	14
+#define EM2800_BOARD_VGEAR_POCKETTV             15
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950	16
 
 struct em28xx_board em28xx_boards[] = {
 	[EM2800_BOARD_UNKNOWN] = {
 		.name         = "Unknown EM2800 video grabber",
 		.is_em2800    = 1,
 		.vchannels    = 2,
-		.norm         = VIDEO_MODE_PAL,
 		.tda9887_conf = TDA9887_PRESENT,
-		.has_tuner    = 1,
 		.decoder      = EM28XX_SAA7113,
-		.input           = {{
+		.input           = { {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
-		}},
+		} },
 	},
 	[EM2820_BOARD_UNKNOWN] = {
-		.name         = "Unknown EM2820/2840 video grabber",
+		.name         = "Unknown EM2750/28xx video grabber",
 		.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     = SAA7115_COMPOSITE0,
-			.amux     = 1,
-		},{
-			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = SAA7115_SVIDEO3,
-			.amux     = 1,
-		}},
+		.tuner_type   = TUNER_ABSENT,
 	},
 	[EM2820_BOARD_KWORLD_PVRTV2800RF] = {
 		.name         = "Kworld PVR TV 2800 RF",
 		.is_em2800    = 0,
 		.vchannels    = 2,
-		.norm         = VIDEO_MODE_PAL,
+		.tuner_type   = TUNER_TEMIC_PAL,
 		.tda9887_conf = TDA9887_PRESENT,
-		.has_tuner    = 1,
 		.decoder      = EM28XX_SAA7113,
-		.input           = {{
+		.input           = { {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
-		}},
+		} },
 	},
 	[EM2820_BOARD_TERRATEC_CINERGY_250] = {
 		.name         = "Terratec Cinergy 250 USB",
 		.vchannels    = 3,
-		.norm         = VIDEO_MODE_PAL,
 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
 		.tda9887_conf = TDA9887_PRESENT,
-		.has_tuner    = 1,
 		.decoder      = EM28XX_SAA7113,
-		.input          = {{
+		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = SAA7115_COMPOSITE2,
 			.amux     = 1,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
-		}},
+		} },
 	},
 	[EM2820_BOARD_PINNACLE_USB_2] = {
 		.name         = "Pinnacle PCTV USB 2",
 		.vchannels    = 3,
-		.norm         = VIDEO_MODE_PAL,
 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
 		.tda9887_conf = TDA9887_PRESENT,
-		.has_tuner    = 1,
 		.decoder      = EM28XX_SAA7113,
-		.input          = {{
+		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = SAA7115_COMPOSITE2,
 			.amux     = 0,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
-		}},
+		} },
 	},
 	[EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
 		.name         = "Hauppauge WinTV USB 2",
 		.vchannels    = 3,
-		.norm         = VIDEO_MODE_NTSC,
 		.tuner_type   = TUNER_PHILIPS_FM1236_MK3,
-		.tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
-		.has_tuner    = 1,
+		.tda9887_conf = TDA9887_PRESENT |
+				TDA9887_PORT1_ACTIVE|
+				TDA9887_PORT2_ACTIVE,
 		.decoder      = EM28XX_TVP5150,
 		.has_msp34xx  = 1,
 		/*FIXME: S-Video not tested */
-		.input          = {{
+		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = TVP5150_COMPOSITE0,
 			.amux     = MSP_INPUT_DEFAULT,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = TVP5150_SVIDEO,
 			.amux     = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
 					MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
-		}},
+		} },
 	},
-	[EM2820_BOARD_MSI_VOX_USB_2] = {
-		.name		= "MSI VOX USB 2.0",
-		.vchannels	= 3,
-		.norm		= VIDEO_MODE_PAL,
-		.tuner_type	= TUNER_LG_PAL_NEW_TAPC,
-		.tda9887_conf	= TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE,
-		.has_tuner	= 1,
-		.decoder        = EM28XX_SAA7114,
-		.input          = {{
+	[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
+		.name         = "Hauppauge WinTV HVR 900",
+		.vchannels    = 3,
+		.tda9887_conf = TDA9887_PRESENT,
+		.tuner_type   = TUNER_XC2028,
+		.mts_firmware = 1,
+		.decoder      = EM28XX_TVP5150,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = 0,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = 1,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = 1,
+		} },
+	},
+	[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
+		.name           = "Hauppauge WinTV HVR 950",
+		.vchannels      = 3,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.tuner_type     = TUNER_XC2028,
+		.mts_firmware   = 1,
+		.has_12mhz_i2s  = 1,
+		.decoder        = EM28XX_TVP5150,
+		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
-			.vmux     = SAA7115_COMPOSITE4,
+			.vmux     = TVP5150_COMPOSITE0,
 			.amux     = 0,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_COMPOSITE1,
-			.vmux     = SAA7115_COMPOSITE0,
+			.vmux     = TVP5150_COMPOSITE1,
 			.amux     = 1,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
-			.vmux     = SAA7115_SVIDEO3,
+			.vmux     = TVP5150_SVIDEO,
 			.amux     = 1,
-		}},
+		} },
+
+		/* gpio's 4, 1, 0 */
+		.analog_gpio = 0x003d2d,
+	},
+	[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
+		.name         = "Terratec Hybrid XS",
+		.vchannels    = 3,
+		.tda9887_conf = TDA9887_PRESENT,
+		.tuner_type   = TUNER_XC2028,
+		.decoder      = EM28XX_TVP5150,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = 0,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = 1,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = 1,
+		} },
+	},
+	/* maybe there's a reason behind it why Terratec sells the Hybrid XS
+	   as Prodigy XS with a different PID, let's keep it separated for now
+	   maybe we'll need it lateron */
+	[EM2880_BOARD_TERRATEC_PRODIGY_XS] = {
+		.name         = "Terratec Prodigy XS",
+		.vchannels    = 3,
+		.tda9887_conf = TDA9887_PRESENT,
+		.tuner_type   = TUNER_XC2028,
+		.decoder      = EM28XX_TVP5150,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = TVP5150_COMPOSITE0,
+			.amux     = 0,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = TVP5150_COMPOSITE1,
+			.amux     = 1,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = TVP5150_SVIDEO,
+			.amux     = 1,
+		} },
+	},
+	[EM2820_BOARD_MSI_VOX_USB_2] = {
+		.name		   = "MSI VOX USB 2.0",
+		.vchannels	   = 3,
+		.tuner_type	   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf	   = TDA9887_PRESENT      |
+				     TDA9887_PORT1_ACTIVE |
+				     TDA9887_PORT2_ACTIVE,
+		.max_range_640_480 = 1,
+
+		.decoder           = EM28XX_SAA7114,
+		.input             = { {
+			.type      = EM28XX_VMUX_TELEVISION,
+			.vmux      = SAA7115_COMPOSITE4,
+			.amux      = 0,
+		}, {
+			.type      = EM28XX_VMUX_COMPOSITE1,
+			.vmux      = SAA7115_COMPOSITE0,
+			.amux      = 1,
+		}, {
+			.type      = EM28XX_VMUX_SVIDEO,
+			.vmux      = SAA7115_SVIDEO3,
+			.amux      = 1,
+		} },
 	},
 	[EM2800_BOARD_TERRATEC_CINERGY_200] = {
 		.name         = "Terratec Cinergy 200 USB",
 		.is_em2800    = 1,
 		.vchannels    = 3,
-		.norm         = VIDEO_MODE_PAL,
 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
 		.tda9887_conf = TDA9887_PRESENT,
-		.has_tuner    = 1,
 		.decoder      = EM28XX_SAA7113,
-		.input          = {{
+		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = SAA7115_COMPOSITE2,
 			.amux     = 0,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
-		}},
+		} },
 	},
 	[EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
 		.name         = "Leadtek Winfast USB II",
 		.is_em2800    = 1,
 		.vchannels    = 3,
-		.norm         = VIDEO_MODE_PAL,
 		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
 		.tda9887_conf = TDA9887_PRESENT,
-		.has_tuner    = 1,
 		.decoder      = EM28XX_SAA7113,
-		.input          = {{
+		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = SAA7115_COMPOSITE2,
 			.amux     = 0,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
-		}},
+		} },
 	},
 	[EM2800_BOARD_KWORLD_USB2800] = {
 		.name         = "Kworld USB2800",
 		.is_em2800    = 1,
 		.vchannels    = 3,
-		.norm         = VIDEO_MODE_PAL,
 		.tuner_type   = TUNER_PHILIPS_ATSC,
 		.tda9887_conf = TDA9887_PRESENT,
-		.has_tuner    = 1,
 		.decoder      = EM28XX_SAA7113,
-		.input          = {{
+		.input          = { {
 			.type     = EM28XX_VMUX_TELEVISION,
 			.vmux     = SAA7115_COMPOSITE2,
 			.amux     = 0,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
-		}},
+		} },
 	},
 	[EM2820_BOARD_PINNACLE_DVC_90] = {
-		.name         = "Pinnacle Dazzle DVC 90",
+		.name         = "Pinnacle Dazzle DVC 90/DVC 100",
+		.vchannels    = 3,
+		.tuner_type   = TUNER_ABSENT,
+		.decoder      = EM28XX_SAA7113,
+		.input          = { {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = 1,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = 1,
+		} },
+	},
+	[EM2800_BOARD_VGEAR_POCKETTV] = {
+		.name         = "V-Gear PocketTV",
+		.is_em2800    = 1,
+		.vchannels    = 3,
+		.tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+		.tda9887_conf = TDA9887_PRESENT,
+		.decoder      = EM28XX_SAA7113,
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = 0,
+		}, {
+			.type     = EM28XX_VMUX_COMPOSITE1,
+			.vmux     = SAA7115_COMPOSITE0,
+			.amux     = 1,
+		}, {
+			.type     = EM28XX_VMUX_SVIDEO,
+			.vmux     = SAA7115_SVIDEO3,
+			.amux     = 1,
+		} },
+	},
+	[EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
+		.name         = "Pixelview Prolink PlayTV USB 2.0",
 		.vchannels    = 3,
-		.norm         = VIDEO_MODE_PAL,
-		.has_tuner    = 0,
+		.tda9887_conf = TDA9887_PRESENT,
+		.tuner_type   = TUNER_YMEC_TVF_5533MF,
 		.decoder      = EM28XX_SAA7113,
-		.input          = {{
+		.input          = { {
+			.type     = EM28XX_VMUX_TELEVISION,
+			.vmux     = SAA7115_COMPOSITE2,
+			.amux     = 1,
+		}, {
 			.type     = EM28XX_VMUX_COMPOSITE1,
 			.vmux     = SAA7115_COMPOSITE0,
 			.amux     = 1,
-		},{
+		}, {
 			.type     = EM28XX_VMUX_SVIDEO,
 			.vmux     = SAA7115_SVIDEO3,
 			.amux     = 1,
-		}},
+		} },
 	},
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
 /* table of devices that work with this driver */
 struct usb_device_id em28xx_id_table [] = {
-	{ USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
-	{ USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
-	{ USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
-	{ USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
-	{ USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
-	{ USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+	{ USB_DEVICE(0xeb1a, 0x2750),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2800),
+			.driver_info = EM2800_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2820),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2821),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2860),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2861),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2870),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2881),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0xeb1a, 0x2883),
+			.driver_info = EM2820_BOARD_UNKNOWN },
+	{ USB_DEVICE(0x0ccd, 0x0036),
+			.driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
+	{ USB_DEVICE(0x2304, 0x0208),
+			.driver_info = EM2820_BOARD_PINNACLE_USB_2 },
+	{ USB_DEVICE(0x2040, 0x4200),
+			.driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+	{ USB_DEVICE(0x2040, 0x4201),
+			.driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
+	{ USB_DEVICE(0x2304, 0x0207),
+			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+	{ USB_DEVICE(0x2304, 0x021a),
+			.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
+	{ USB_DEVICE(0x2040, 0x6500),
+			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 },
+	{ USB_DEVICE(0x2040, 0x6513),
+			.driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 },
+	{ USB_DEVICE(0x0ccd, 0x0042),
+			.driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
+	{ USB_DEVICE(0x0ccd, 0x0047),
+			.driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
 	{ },
 };
+MODULE_DEVICE_TABLE(usb, em28xx_id_table);
+
+/* EEPROM hash table for devices with generic USB IDs */
+static struct em28xx_hash_table em28xx_eeprom_hash [] = {
+	/* P/N: SA 60002070465 Tuner: TVF7533-MF */
+	{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
+};
+
+/* I2C devicelist hash table for devices with generic USB IDs */
+static struct em28xx_hash_table em28xx_i2c_hash[] = {
+	{0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
+	{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
+};
 
+/* Since em28xx_pre_card_setup() requires a proper dev->model,
+ * this won't work for boards with generic PCI IDs
+ */
 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;
+	switch (dev->model) {
+	case EM2880_BOARD_TERRATEC_PRODIGY_XS:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+	case EM2880_BOARD_TERRATEC_HYBRID_XS:
+		em28xx_write_regs(dev, XCLK_REG, "\x27", 1);
+		em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1);
+		em28xx_write_regs(dev, 0x08, "\xff", 1);
+		em28xx_write_regs(dev, 0x04, "\x00", 1);
+		msleep(100);
+		em28xx_write_regs(dev, 0x04, "\x08", 1);
+		msleep(100);
+		em28xx_write_regs(dev, 0x08, "\xff", 1);
+		msleep(50);
+		em28xx_write_regs(dev, 0x08, "\x2d", 1);
+		msleep(50);
+		em28xx_write_regs(dev, 0x08, "\x3d", 1);
+		break;
+	}
+}
+
+static int em28xx_tuner_callback(void *ptr, int command, int arg)
+{
+	int rc = 0;
+	struct em28xx *dev = ptr;
+
+	if (dev->tuner_type != TUNER_XC2028)
+		return 0;
+
+	switch (command) {
+	case XC2028_TUNER_RESET:
+	{
+		/* GPIO and initialization codes for analog TV and radio
+		   This code should be complemented for DTV, since reset
+		   codes are different.
+		 */
+
+		dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+		dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
+
+		if (dev->analog_gpio) {
+			char gpio0 = dev->analog_gpio & 0xff;
+			char gpio1 = (dev->analog_gpio >> 8) & 0xff;
+			char gpio4 = dev->analog_gpio >> 24;
+
+			if (gpio4) {
+				dev->em28xx_write_regs(dev, 0x04, &gpio4, 1);
+				msleep(140);
 			}
+
+			msleep(6);
+			dev->em28xx_write_regs(dev, 0x08, &gpio0, 1);
+			msleep(10);
+			dev->em28xx_write_regs(dev, 0x08, &gpio1, 1);
+			msleep(5);
+		}
+
+		break;
+	}
+	}
+	return rc;
+}
+
+static void em28xx_config_tuner(struct em28xx *dev)
+{
+	struct v4l2_priv_tun_config  xc2028_cfg;
+	struct xc2028_ctrl           ctl;
+	struct tuner_setup           tun_setup;
+	struct v4l2_frequency        f;
+
+	if (dev->tuner_type == TUNER_ABSENT)
+		return;
+
+	tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+	tun_setup.type = dev->tuner_type;
+	tun_setup.addr = dev->tuner_addr;
+	tun_setup.tuner_callback = em28xx_tuner_callback;
+
+	em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+
+	if (dev->tuner_type == TUNER_XC2028) {
+		memset(&ctl, 0, sizeof(ctl));
+
+		ctl.fname   = XC2028_DEFAULT_FIRMWARE;
+		ctl.max_len = 64;
+		ctl.mts = em28xx_boards[dev->model].mts_firmware;
+
+		xc2028_cfg.tuner = TUNER_XC2028;
+		xc2028_cfg.priv  = &ctl;
+
+		em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
+	}
+
+	/* configure tuner */
+	f.tuner = 0;
+	f.type = V4L2_TUNER_ANALOG_TV;
+	f.frequency = 9076;     /* just a magic number */
+	dev->ctl_freq = f.frequency;
+	em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+}
+
+static int em28xx_hint_board(struct em28xx *dev)
+{
+	int i;
+
+	/* HINT method: EEPROM
+	 *
+	 * This method works only for boards with eeprom.
+	 * Uses a hash of all eeprom bytes. The hash should be
+	 * unique for a vendor/tuner pair.
+	 * There are a high chance that tuners for different
+	 * video standards produce different hashes.
+	 */
+	for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) {
+		if (dev->hash == em28xx_eeprom_hash[i].hash) {
+			dev->model = em28xx_eeprom_hash[i].model;
+			dev->tuner_type = em28xx_eeprom_hash[i].tuner;
+
+			em28xx_errdev("Your board has no unique USB ID.\n");
+			em28xx_errdev("A hint were successfully done, "
+				      "based on eeprom hash.\n");
+			em28xx_errdev("This method is not 100%% failproof.\n");
+			em28xx_errdev("If the board were missdetected, "
+				      "please email this log to:\n");
+			em28xx_errdev("\tV4L Mailing List "
+				      " <video4linux-list@redhat.com>\n");
+			em28xx_errdev("Board detected as %s\n",
+				      em28xx_boards[dev->model].name);
+
+			return 0;
+		}
+	}
+
+	/* HINT method: I2C attached devices
+	 *
+	 * This method works for all boards.
+	 * Uses a hash of i2c scanned devices.
+	 * Devices with the same i2c attached chips will
+	 * be considered equal.
+	 * This method is less precise than the eeprom one.
+	 */
+
+	/* user did not request i2c scanning => do it now */
+	if (!dev->i2c_hash)
+		em28xx_do_i2c_scan(dev);
+
+	for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) {
+		if (dev->i2c_hash == em28xx_i2c_hash[i].hash) {
+			dev->model = em28xx_i2c_hash[i].model;
+			dev->tuner_type = em28xx_i2c_hash[i].tuner;
+			em28xx_errdev("Your board has no unique USB ID.\n");
+			em28xx_errdev("A hint were successfully done, "
+				      "based on i2c devicelist hash.\n");
+			em28xx_errdev("This method is not 100%% failproof.\n");
+			em28xx_errdev("If the board were missdetected, "
+				      "please email this log to:\n");
+			em28xx_errdev("\tV4L Mailing List "
+				      " <video4linux-list@redhat.com>\n");
+			em28xx_errdev("Board detected as %s\n",
+				      em28xx_boards[dev->model].name);
+
+			return 0;
+		}
+	}
+
+	em28xx_errdev("Your board has no unique USB ID and thus need a "
+		      "hint to be detected.\n");
+	em28xx_errdev("You may try to use card=<n> insmod option to "
+		      "workaround that.\n");
+	em28xx_errdev("Please send an email with this log to:\n");
+	em28xx_errdev("\tV4L Mailing List <video4linux-list@redhat.com>\n");
+	em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash);
+	em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash);
+
+	em28xx_errdev("Here is a list of valid choices for the card=<n>"
+		      " insmod option:\n");
+	for (i = 0; i < em28xx_bcount; i++) {
+		em28xx_errdev("    card=%d -> %s\n",
+				i, em28xx_boards[i].name);
+	}
+	return -1;
+}
+
+
+static void em28xx_set_model(struct em28xx *dev)
+{
+	dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
+	dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
+	dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
+	dev->decoder = em28xx_boards[dev->model].decoder;
+	dev->video_inputs = em28xx_boards[dev->model].vchannels;
+	dev->analog_gpio = em28xx_boards[dev->model].analog_gpio;
+	dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
+	dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
+}
+
+/* ----------------------------------------------------------------------- */
+void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
+{
+	if (disable_ir) {
+		ir->get_key = NULL;
+		return ;
+	}
+
+	/* detect & configure */
+	switch (dev->model) {
+	case (EM2800_BOARD_UNKNOWN):
+		break;
+	case (EM2820_BOARD_UNKNOWN):
+		break;
+	case (EM2800_BOARD_TERRATEC_CINERGY_200):
+	case (EM2820_BOARD_TERRATEC_CINERGY_250):
+		ir->ir_codes = ir_codes_em_terratec;
+		ir->get_key = em28xx_get_key_terratec;
+		snprintf(ir->c.name, sizeof(ir->c.name),
+			 "i2c IR (EM28XX Terratec)");
+		break;
+	case (EM2820_BOARD_PINNACLE_USB_2):
+		ir->ir_codes = ir_codes_pinnacle_grey;
+		ir->get_key = em28xx_get_key_pinnacle_usb_grey;
+		snprintf(ir->c.name, sizeof(ir->c.name),
+			 "i2c IR (EM28XX Pinnacle PCTV)");
+		break;
+	case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
+		ir->ir_codes = ir_codes_hauppauge_new;
+		ir->get_key = em28xx_get_key_em_haup;
+		snprintf(ir->c.name, sizeof(ir->c.name),
+			 "i2c IR (EM2840 Hauppauge)");
+		break;
+	case (EM2820_BOARD_MSI_VOX_USB_2):
+		break;
+	case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
+		break;
+	case (EM2800_BOARD_KWORLD_USB2800):
+		break;
 	}
 }
 
 void em28xx_card_setup(struct em28xx *dev)
 {
+	em28xx_set_model(dev);
+
+	dev->tuner_type = em28xx_boards[dev->model].tuner_type;
+
 	/* request some modules */
-	switch(dev->model){
-		case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
-			{
-				struct tveeprom tv;
+	switch (dev->model) {
+	case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+	{
+		struct tveeprom tv;
 #ifdef CONFIG_MODULES
-				request_module("tveeprom");
-				request_module("ir-kbd-i2c");
-				request_module("msp3400");
+		request_module("tveeprom");
 #endif
-				/* Call first TVeeprom */
-
-				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;
-			}
+		/* Call first TVeeprom */
+
+		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;
+		}
+#ifdef CONFIG_MODULES
+		if (tv.has_ir)
+			request_module("ir-kbd-i2c");
+#endif
+		break;
+	}
+	case EM2820_BOARD_KWORLD_PVRTV2800RF:
+		/* GPIO enables sound on KWORLD PVR TV 2800RF */
+		em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1);
+		break;
+	case EM2820_BOARD_UNKNOWN:
+	case EM2800_BOARD_UNKNOWN:
+		if (!em28xx_hint_board(dev))
+			em28xx_set_model(dev);
 	}
-}
 
-MODULE_DEVICE_TABLE (usb, em28xx_id_table);
+	/* Allow override tuner type by a module parameter */
+	if (tuner >= 0)
+		dev->tuner_type = tuner;
+
+#ifdef CONFIG_MODULES
+	/* request some modules */
+	if (dev->has_msp34xx)
+		request_module("msp3400");
+	if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114)
+		request_module("saa7115");
+	if (dev->decoder == EM28XX_TVP5150)
+		request_module("tvp5150");
+	if (dev->tuner_type != TUNER_ABSENT)
+		request_module("tuner");
+#endif
+
+	em28xx_config_tuner(dev);
+}
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index d56484f20467..f6b78357f0e5 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -252,7 +252,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
  * em28xx_write_ac97()
  * write a 16 bit value to the specified AC97 address (LSB first!)
  */
-int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
+static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
 {
 	int ret;
 	u8 addr = reg & 0x7f;
@@ -268,16 +268,98 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val)
 	return 0;
 }
 
+int em28xx_set_audio_source(struct em28xx *dev)
+{
+	static char *enable  = "\x08\x08";
+	static char *disable = "\x08\x88";
+	char *video = enable, *line = disable;
+	int ret, no_ac97;
+	u8 input;
+
+	if (dev->is_em2800) {
+		if (dev->ctl_ainput)
+			input = EM2800_AUDIO_SRC_LINE;
+		else
+			input = EM2800_AUDIO_SRC_TUNER;
+
+		ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (dev->has_msp34xx)
+		input = EM28XX_AUDIO_SRC_TUNER;
+	else {
+		switch (dev->ctl_ainput) {
+		case EM28XX_AMUX_VIDEO:
+			input = EM28XX_AUDIO_SRC_TUNER;
+			no_ac97 = 1;
+			break;
+		case EM28XX_AMUX_LINE_IN:
+			input = EM28XX_AUDIO_SRC_LINE;
+			no_ac97 = 1;
+			break;
+		case EM28XX_AMUX_AC97_VIDEO:
+			input = EM28XX_AUDIO_SRC_LINE;
+			break;
+		case EM28XX_AMUX_AC97_LINE_IN:
+			input = EM28XX_AUDIO_SRC_LINE;
+			video = disable;
+			line  = enable;
+			break;
+		}
+	}
+
+	ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+	if (ret < 0)
+		return ret;
+
+	if (no_ac97)
+		return 0;
+
+	/* Sets AC97 mixer registers */
+
+	ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
+	if (ret < 0)
+		return ret;
+
+	ret = em28xx_write_ac97(dev, LINE_IN_AC97, line);
+
+	return ret;
+}
+
 int em28xx_audio_analog_set(struct em28xx *dev)
 {
+	int ret;
 	char s[2] = { 0x00, 0x00 };
+	u8 xclk = 0x07;
+
 	s[0] |= 0x1f - dev->volume;
 	s[1] |= 0x1f - dev->volume;
+
 	if (dev->mute)
 		s[1] |= 0x80;
-	return em28xx_write_ac97(dev, MASTER_AC97, s);
-}
+	ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+	if (ret < 0)
+		return ret;
+
+	if (dev->has_12mhz_i2s)
+		xclk |= 0x20;
+
+	if (!dev->mute)
+		xclk |= 0x80;
 
+	ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7);
+	if (ret < 0)
+		return ret;
+	msleep(10);
+
+	/* Selects the proper audio input */
+	ret = em28xx_set_audio_source(dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
 
 int em28xx_colorlevels_set_default(struct em28xx *dev)
 {
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index e3a4aa7a9df4..cacd04d46e99 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -25,9 +25,9 @@
 #include <linux/kernel.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/video_decoder.h>
 
 #include "em28xx.h"
+#include "tuner-xc2028.h"
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
 
@@ -291,6 +291,31 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
 	return rc;
 }
 
+/* based on linux/sunrpc/svcauth.h and linux/hash.h
+ * The original hash function returns a different value, if arch is x86_64
+ *  or i386.
+ */
+static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
+{
+	unsigned long hash = 0;
+	unsigned long l = 0;
+	int len = 0;
+	unsigned char c;
+	do {
+		if (len == length) {
+			c = (char)len;
+			len = -1;
+		} else
+			c = *buf++;
+		l = (l << 8) | c;
+		len++;
+		if ((len & (32 / 8 - 1)) == 0)
+			hash = ((hash^l) * 0x9e370001UL);
+	} while (len);
+
+	return (hash >> (32 - bits)) & 0xffffffffUL;
+}
+
 static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
 {
 	unsigned char buf, *p = eedata;
@@ -334,7 +359,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
 			printk("\n");
 	}
 
-	printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id);
+	if (em_eeprom->id == 0x9567eb1a)
+		dev->hash = em28xx_hash_mem(eedata, len, 32);
+
+	printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n",
+	       em_eeprom->id, dev->hash);
 	printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID,
 	       em_eeprom->product_ID);
 
@@ -391,21 +420,6 @@ static u32 functionality(struct i2c_adapter *adap)
 }
 
 
-static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
-{
-	struct em28xx *dev = client->adapter->algo_data;
-	struct tuner_setup tun_setup;
-
-	if (dev->has_tuner) {
-		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);
-	}
-
-	return (0);
-}
-
 /*
  * attach_inform()
  * gets called when a device attaches to the i2c bus
@@ -421,6 +435,8 @@ static int attach_inform(struct i2c_client *client)
 		case 0x96:
 		case 0x94:
 		{
+			struct v4l2_priv_tun_config tda9887_cfg;
+
 			struct tuner_setup tun_setup;
 
 			tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
@@ -428,7 +444,11 @@ static int attach_inform(struct i2c_client *client)
 			tun_setup.addr = client->addr;
 
 			em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
-			em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
+
+			tda9887_cfg.tuner = TUNER_TDA9887;
+			tda9887_cfg.priv = &dev->tda9887_conf;
+			em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
+						&tda9887_cfg);
 			break;
 		}
 		case 0x42:
@@ -458,9 +478,11 @@ static int attach_inform(struct i2c_client *client)
 			break;
 
 		default:
+			if (!dev->tuner_addr)
+				dev->tuner_addr = client->addr;
+
 			dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
-			dev->tuner_addr = client->addr;
-			em28xx_set_tuner(-1, client);
+
 	}
 
 	return 0;
@@ -510,19 +532,26 @@ static char *i2c_devs[128] = {
  * do_i2c_scan()
  * check i2c address range for devices
  */
-static void do_i2c_scan(char *name, struct i2c_client *c)
+void em28xx_do_i2c_scan(struct em28xx *dev)
 {
+	u8 i2c_devicelist[128];
 	unsigned char buf;
 	int i, rc;
 
+	memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
+
 	for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
-		c->addr = i;
-		rc = i2c_master_recv(c, &buf, 0);
+		dev->i2c_client.addr = i;
+		rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
 		if (rc < 0)
 			continue;
-		printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
-		       i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+		i2c_devicelist[i] = i;
+		printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
+		       dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
 	}
+
+	dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
+					ARRAY_SIZE(i2c_devicelist), 32);
 }
 
 /*
@@ -555,7 +584,7 @@ int em28xx_i2c_register(struct em28xx *dev)
 	em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
 
 	if (i2c_scan)
-		do_i2c_scan(dev->name, &dev->i2c_client);
+		em28xx_do_i2c_scan(dev);
 	return 0;
 }
 
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index e3894b68c4ee..10da2fd8d987 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -30,11 +30,7 @@
 
 #include "em28xx.h"
 
-static unsigned int disable_ir = 0;
-module_param(disable_ir, int, 0444);
-MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
-
-static unsigned int ir_debug = 0;
+static unsigned int ir_debug;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
 
@@ -43,7 +39,7 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
 
 /* ----------------------------------------------------------------------- */
 
-static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char b;
 
@@ -72,7 +68,7 @@ static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 }
 
 
-static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char buf[2];
 	unsigned char code;
@@ -103,7 +99,8 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	return 1;
 }
 
-static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
+				     u32 *ir_raw)
 {
 	unsigned char buf[3];
 
@@ -125,45 +122,6 @@ static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw
 	return 1;
 }
 
-/* ----------------------------------------------------------------------- */
-void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
-{
-	if (disable_ir) {
-		ir->get_key=NULL;
-		return ;
-	}
-
-	/* detect & configure */
-	switch (dev->model) {
-	case (EM2800_BOARD_UNKNOWN):
-		break;
-	case (EM2820_BOARD_UNKNOWN):
-		break;
-	case (EM2800_BOARD_TERRATEC_CINERGY_200):
-	case (EM2820_BOARD_TERRATEC_CINERGY_250):
-		ir->ir_codes = ir_codes_em_terratec;
-		ir->get_key = get_key_terratec;
-		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
-		break;
-	case (EM2820_BOARD_PINNACLE_USB_2):
-		ir->ir_codes = ir_codes_pinnacle_grey;
-		ir->get_key = get_key_pinnacle_usb_grey;
-		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
-		break;
-	case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
-		ir->ir_codes = ir_codes_hauppauge_new;
-		ir->get_key = get_key_em_haup;
-		snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)");
-		break;
-	case (EM2820_BOARD_MSI_VOX_USB_2):
-		break;
-	case (EM2800_BOARD_LEADTEK_WINFAST_USBII):
-		break;
-	case (EM2800_BOARD_KWORLD_USB2800):
-		break;
-	}
-}
-
 /* ----------------------------------------------------------------------
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 0906bc5766cc..a0c334672488 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -33,13 +33,12 @@
 #include <linux/i2c.h>
 #include <linux/version.h>
 #include <linux/mm.h>
-#include <linux/video_decoder.h>
 #include <linux/mutex.h>
 
 #include "em28xx.h"
-#include <media/tuner.h>
 #include <media/v4l2-common.h>
 #include <media/msp3400.h>
+#include <media/tuner.h>
 
 #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
 		      "Markus Rechberger <mrechberger@gmail.com>, " \
@@ -48,7 +47,7 @@
 
 #define DRIVER_NAME         "em28xx"
 #define DRIVER_DESC         "Empia em28xx based USB video device driver"
-#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 0, 1)
+#define EM28XX_VERSION_CODE  KERNEL_VERSION(0, 1, 0)
 
 #define em28xx_videodbg(fmt, arg...) do {\
 	if (video_debug) \
@@ -63,17 +62,17 @@ 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 };
+static unsigned int vbi_nr[]   = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_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);
-MODULE_PARM_DESC(tuner, "tuner type");
+module_param_array(radio_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");
+MODULE_PARM_DESC(radio_nr, "radio device numbers");
 
 static unsigned int video_debug = 0;
 module_param(video_debug,int,0644);
@@ -82,29 +81,6 @@ 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[] = {
-	{
-		.name = "PAL",
-		.id = V4L2_STD_PAL,
-		.mode = VIDEO_MODE_PAL,
-	 }, {
-		.name = "NTSC",
-		.id = V4L2_STD_NTSC,
-		.mode = VIDEO_MODE_NTSC,
-	}, {
-		 .name = "SECAM",
-		 .id = V4L2_STD_SECAM,
-		 .mode = VIDEO_MODE_SECAM,
-	}, {
-		.name = "PAL-M",
-		.id = V4L2_STD_PAL_M,
-		.mode = VIDEO_MODE_PAL,
-	}
-};
-
-#define TVNORMS ARRAY_SIZE(tvnorms)
-
 /* supported controls */
 /* Common to all boards */
 static struct v4l2_queryctrl em28xx_qctrl[] = {
@@ -131,8 +107,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
 
 static struct usb_driver em28xx_usb_driver;
 
-static DEFINE_MUTEX(em28xx_sysfs_lock);
-static DECLARE_RWSEM(em28xx_disconnect);
 
 /*********************  v4l2 interface  ******************************************/
 
@@ -153,11 +127,9 @@ static int em28xx_config(struct em28xx *dev)
 /*	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;
-	em28xx_audio_analog_set(dev);
-	em28xx_audio_analog_setup(dev);
+
 	em28xx_outfmt_set_yuv422(dev);
 	em28xx_colorlevels_set_default(dev);
 	em28xx_compression_disable(dev);
@@ -171,7 +143,6 @@ static int em28xx_config(struct em28xx *dev)
  */
 static void em28xx_config_i2c(struct em28xx *dev)
 {
-	struct v4l2_frequency f;
 	struct v4l2_routing route;
 
 	route.input = INPUT(dev->ctl_input)->vmux;
@@ -179,18 +150,6 @@ static void em28xx_config_i2c(struct em28xx *dev)
 	em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
 	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 	em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
-
-	/* configure tuner */
-	f.tuner = 0;
-	f.type = V4L2_TUNER_ANALOG_TV;
-	f.frequency = 9076;	/* FIXME:remove magic number */
-	dev->ctl_freq = f.frequency;
-	em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
-
-	/* configure tda9887 */
-
-
-/*	em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */
 }
 
 /*
@@ -212,7 +171,6 @@ static void em28xx_empty_framequeues(struct em28xx *dev)
 
 static void video_mux(struct em28xx *dev, int index)
 {
-	int ainput;
 	struct v4l2_routing route;
 
 	route.input = INPUT(index)->vmux;
@@ -222,8 +180,6 @@ static void video_mux(struct em28xx *dev, int index)
 
 	em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
 
-	em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput);
-
 	if (dev->has_msp34xx) {
 		if (dev->i2s_speed)
 			em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
@@ -231,18 +187,1068 @@ static void video_mux(struct em28xx *dev, int index)
 		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
 		/* Note: this is msp3400 specific */
 		em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
-		ainput = EM28XX_AUDIO_SRC_TUNER;
-		em28xx_audio_source(dev, ainput);
+	}
+
+	em28xx_set_audio_source(dev);
+}
+
+/* Usage lock check functions */
+static int res_get(struct em28xx_fh *fh)
+{
+	struct em28xx    *dev = fh->dev;
+	int		 rc   = 0;
+
+	/* This instance already has stream_on */
+	if (fh->stream_on)
+		return rc;
+
+	mutex_lock(&dev->lock);
+
+	if (dev->stream_on)
+		rc = -EINVAL;
+	else {
+		dev->stream_on = 1;
+		fh->stream_on  = 1;
+	}
+
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int res_check(struct em28xx_fh *fh)
+{
+	return (fh->stream_on);
+}
+
+static void res_free(struct em28xx_fh *fh)
+{
+	struct em28xx    *dev = fh->dev;
+
+	mutex_lock(&dev->lock);
+	fh->stream_on = 0;
+	dev->stream_on = 0;
+	mutex_unlock(&dev->lock);
+}
+
+/*
+ * em28xx_vm_open()
+ */
+static void em28xx_vm_open(struct vm_area_struct *vma)
+{
+	struct em28xx_frame_t *f = vma->vm_private_data;
+	f->vma_use_count++;
+}
+
+/*
+ * em28xx_vm_close()
+ */
+static void em28xx_vm_close(struct vm_area_struct *vma)
+{
+	/* NOTE: buffers are not freed here */
+	struct em28xx_frame_t *f = vma->vm_private_data;
+
+	if (f->vma_use_count)
+		f->vma_use_count--;
+}
+
+static struct vm_operations_struct em28xx_vm_ops = {
+	.open = em28xx_vm_open,
+	.close = em28xx_vm_close,
+};
+
+
+/*
+ * em28xx_get_ctrl()
+ * return the current saturation, brightness or contrast, mute state
+ */
+static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value = dev->mute;
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		ctrl->value = dev->volume;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ * em28xx_set_ctrl()
+ * mute or set new saturation, brightness or contrast
+ */
+static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		if (ctrl->value != dev->mute) {
+			dev->mute = ctrl->value;
+			return em28xx_audio_analog_set(dev);
+		}
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		dev->volume = ctrl->value;
+		return em28xx_audio_analog_set(dev);
+	default:
+		return -EINVAL;
+	}
+}
+
+/*
+ * em28xx_stream_interrupt()
+ * stops streaming
+ */
+static int em28xx_stream_interrupt(struct em28xx *dev)
+{
+	int rc = 0;
+
+	/* stop reading from the device */
+
+	dev->stream = STREAM_INTERRUPT;
+	rc = wait_event_timeout(dev->wait_stream,
+				(dev->stream == STREAM_OFF) ||
+				(dev->state & DEV_DISCONNECTED),
+				EM28XX_URB_TIMEOUT);
+
+	if (rc) {
+		dev->state |= DEV_MISCONFIGURED;
+		em28xx_videodbg("device is misconfigured; close and "
+			"open /dev/video%d again\n",
+				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
+		return rc;
+	}
+
+	return 0;
+}
+
+
+static int check_dev(struct em28xx *dev)
+{
+	if (dev->state & DEV_DISCONNECTED) {
+		em28xx_errdev("v4l2 ioctl: device not present\n");
+		return -ENODEV;
+	}
+
+	if (dev->state & DEV_MISCONFIGURED) {
+		em28xx_errdev("v4l2 ioctl: device is misconfigured; "
+			      "close and open it again\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static void get_scale(struct em28xx *dev,
+			unsigned int width, unsigned int height,
+			unsigned int *hscale, unsigned int *vscale)
+{
+	unsigned int          maxw   = norm_maxw(dev);
+	unsigned int          maxh   = norm_maxh(dev);
+
+	*hscale = (((unsigned long)maxw) << 12) / width - 4096L;
+	if (*hscale >= 0x4000)
+		*hscale = 0x3fff;
+
+	*vscale = (((unsigned long)maxh) << 12) / height - 4096L;
+	if (*vscale >= 0x4000)
+		*vscale = 0x3fff;
+}
+
+/* ------------------------------------------------------------------
+	IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	mutex_lock(&dev->lock);
+
+	f->fmt.pix.width = dev->width;
+	f->fmt.pix.height = dev->height;
+	f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+	f->fmt.pix.bytesperline = dev->bytesperline;
+	f->fmt.pix.sizeimage = dev->frame_size;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
+	f->fmt.pix.field = dev->interlaced ?
+			   V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct em28xx_fh      *fh    = priv;
+	struct em28xx         *dev   = fh->dev;
+	int                   width  = f->fmt.pix.width;
+	int                   height = f->fmt.pix.height;
+	unsigned int          maxw   = norm_maxw(dev);
+	unsigned int          maxh   = norm_maxh(dev);
+	unsigned int          hscale, vscale;
+
+	/* 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;
+
+	mutex_lock(&dev->lock);
+
+	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;
+	}
+
+	get_scale(dev, width, height, &hscale, &vscale);
+
+	width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+	height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+
+	f->fmt.pix.width = width;
+	f->fmt.pix.height = height;
+	f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+	f->fmt.pix.bytesperline = width * 2;
+	f->fmt.pix.sizeimage = width * 2 * height;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc, i;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	vidioc_try_fmt_cap(file, priv, f);
+
+	mutex_lock(&dev->lock);
+
+	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");
+			rc = -EINVAL;
+			goto err;
+		}
+
+	/* stop io in case it is already in progress */
+	if (dev->stream == STREAM_ON) {
+		em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
+		rc = em28xx_stream_interrupt(dev);
+		if (rc < 0)
+			goto err;
+	}
+
+	em28xx_release_buffers(dev);
+	dev->io = IO_NONE;
+
+	/* set new image size */
+	dev->width = f->fmt.pix.width;
+	dev->height = f->fmt.pix.height;
+	dev->frame_size = dev->width * dev->height * 2;
+	dev->field_size = dev->frame_size >> 1;
+	dev->bytesperline = dev->width * 2;
+	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+	/* FIXME: This is really weird! Why capture is starting with
+	   this ioctl ???
+	 */
+	em28xx_uninit_isoc(dev);
+	em28xx_set_alternate(dev);
+	em28xx_capture_start(dev, 1);
+	em28xx_resolution_set(dev);
+	em28xx_init_isoc(dev);
+	rc = 0;
+
+err:
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+	struct v4l2_format f;
+	int                rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&dev->lock);
+	dev->norm = *norm;
+	mutex_unlock(&dev->lock);
+
+	/* Adjusts width/height, if needed */
+	f.fmt.pix.width = dev->width;
+	f.fmt.pix.height = dev->height;
+	vidioc_try_fmt_cap(file, priv, &f);
+
+	mutex_lock(&dev->lock);
+
+	/* set new image size */
+	dev->width = f.fmt.pix.width;
+	dev->height = f.fmt.pix.height;
+	dev->frame_size = dev->width * dev->height * 2;
+	dev->field_size = dev->frame_size >> 1;
+	dev->bytesperline = dev->width * 2;
+	get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+
+	em28xx_resolution_set(dev);
+	em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm);
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+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",
+};
+
+static int vidioc_enum_input(struct file *file, void *priv,
+				struct v4l2_input *i)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+	unsigned int       n;
+
+	n = i->index;
+	if (n >= MAX_EM28XX_INPUT)
+		return -EINVAL;
+	if (0 == INPUT(n)->type)
+		return -EINVAL;
+
+	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;
+
+	i->std = dev->vdev->tvnorms;
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+
+	*i = dev->ctl_input;
+
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+	int                rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (i >= MAX_EM28XX_INPUT)
+		return -EINVAL;
+	if (0 == INPUT(i)->type)
+		return -EINVAL;
+
+	mutex_lock(&dev->lock);
+
+	video_mux(dev, i);
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	struct em28xx_fh   *fh    = priv;
+	struct em28xx      *dev   = fh->dev;
+	unsigned int        index = a->index;
+
+	if (a->index > 1)
+		return -EINVAL;
+
+	index = dev->ctl_ainput;
+
+	if (index == 0) {
+		strcpy(a->name, "Television");
 	} else {
-		switch (dev->ctl_ainput) {
-			case 0:
-				ainput = EM28XX_AUDIO_SRC_TUNER;
+		strcpy(a->name, "Line In");
+	}
+	a->capability = V4L2_AUDCAP_STEREO;
+	a->index = index;
+
+	return 0;
+}
+
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	struct em28xx_fh   *fh  = priv;
+	struct em28xx      *dev = fh->dev;
+
+	if (a->index != dev->ctl_ainput)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+				struct v4l2_queryctrl *qc)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   id  = qc->id;
+	int                   i;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	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;
+			}
+		}
+	}
+	mutex_lock(&dev->lock);
+	em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc);
+	mutex_unlock(&dev->lock);
+
+	if (qc->type)
+		return 0;
+	else
+		return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+	mutex_lock(&dev->lock);
+
+	if (!dev->has_msp34xx)
+		rc = em28xx_get_ctrl(dev, ctrl);
+	else
+		rc = -EINVAL;
+
+	if (rc == -EINVAL) {
+		em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl);
+		rc = 0;
+	}
+
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	u8                    i;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&dev->lock);
+
+	if (dev->has_msp34xx)
+		em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
+	else {
+		rc = 1;
+		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) {
+					rc = -ERANGE;
+					break;
+				}
+
+				rc = em28xx_set_ctrl(dev, ctrl);
 				break;
-			default:
-				ainput = EM28XX_AUDIO_SRC_LINE;
+			}
+		}
+	}
+
+	/* Control not found - try to send it to the attached devices */
+	if (rc == 1) {
+		em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl);
+		rc = 0;
+	}
+
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	strcpy(t->name, "Tuner");
+
+	mutex_lock(&dev->lock);
+
+	em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+				struct v4l2_tuner *t)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	mutex_lock(&dev->lock);
+
+	em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	f->frequency = dev->ctl_freq;
+
+	return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+				struct v4l2_frequency *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (0 != f->tuner)
+		return -EINVAL;
+
+	if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+		return -EINVAL;
+	if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+		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;
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+					struct v4l2_cropcap *cc)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	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;
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
+		return -EINVAL;
+
+	if (list_empty(&dev->inqueue))
+		return -EINVAL;
+
+	mutex_lock(&dev->lock);
+
+	if (unlikely(res_get(fh) < 0)) {
+		mutex_unlock(&dev->lock);
+		return -EBUSY;
+	}
+
+	dev->stream = STREAM_ON;	/* FIXME: Start video capture here? */
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
+		return -EINVAL;
+
+	mutex_lock(&dev->lock);
+
+	if (dev->stream == STREAM_ON) {
+		em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n");
+		rc = em28xx_stream_interrupt(dev);
+		if (rc < 0) {
+			mutex_unlock(&dev->lock);
+			return rc;
+		}
+	}
+
+	em28xx_empty_framequeues(dev);
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+
+	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->tuner_type != TUNER_ABSENT)
+		cap->capabilities |= V4L2_CAP_TUNER;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *fmtd)
+{
+	if (fmtd->index != 0)
+		return -EINVAL;
+
+	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;
+}
+
+/* Sliced VBI ioctls */
+static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&dev->lock);
+
+	f->fmt.sliced.service_set = 0;
+
+	em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
+
+	if (f->fmt.sliced.service_set == 0)
+		rc = -EINVAL;
+
+	mutex_unlock(&dev->lock);
+	return rc;
+}
+
+static int vidioc_try_set_vbi_capture(struct file *file, void *priv,
+			struct v4l2_format *f)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	mutex_lock(&dev->lock);
+	em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f);
+	mutex_unlock(&dev->lock);
+
+	if (f->fmt.sliced.service_set == 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *rb)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	u32                   i;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	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");
+		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;
+		}
+
+	mutex_lock(&dev->lock);
+
+	if (dev->stream == STREAM_ON) {
+		em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
+		rc = em28xx_stream_interrupt(dev);
+		if (rc < 0) {
+			mutex_unlock(&dev->lock);
+			return rc;
 		}
-		em28xx_audio_source(dev, ainput);
 	}
+
+	em28xx_empty_framequeues(dev);
+
+	em28xx_release_buffers(dev);
+	if (rb->count)
+		rb->count = em28xx_request_buffers(dev, rb->count);
+
+	dev->frame_current = NULL;
+	dev->io = rb->count ? IO_MMAP : IO_NONE;
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *b)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+		b->index >= dev->num_frames || dev->io != IO_MMAP)
+		return -EINVAL;
+
+	mutex_lock(&dev->lock);
+
+	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;
+
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	unsigned long         lock_flags;
+	int                   rc;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE  || dev->io != IO_MMAP ||
+						b->index >= dev->num_frames)
+		return -EINVAL;
+
+	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);
+
+	return 0;
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct em28xx_fh      *fh  = priv;
+	struct em28xx         *dev = fh->dev;
+	int                   rc;
+	struct em28xx_frame_t *f;
+	unsigned long         lock_flags;
+
+	rc = check_dev(dev);
+	if (rc < 0)
+		return rc;
+
+	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 (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		rc = wait_event_interruptible(dev->wait_frame,
+					(!list_empty(&dev->outqueue)) ||
+					(dev->state & DEV_DISCONNECTED));
+		if (rc)
+			return rc;
+
+		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);
+
+	f->state = F_UNUSED;
+	memcpy(b, &f->buf, sizeof(*b));
+
+	if (f->vma_use_count)
+		b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+	return 0;
+}
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS                                      */
+/* ----------------------------------------------------------- */
+
+static int radio_querycap(struct file *file, void  *priv,
+			  struct v4l2_capability *cap)
+{
+	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+
+	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_TUNER;
+	return 0;
+}
+
+static int radio_g_tuner(struct file *file, void *priv,
+			 struct v4l2_tuner *t)
+{
+	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+
+	if (unlikely(t->index > 0))
+		return -EINVAL;
+
+	strcpy(t->name, "Radio");
+	t->type = V4L2_TUNER_RADIO;
+
+	em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+	return 0;
+}
+
+static int radio_enum_input(struct file *file, void *priv,
+			    struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
+	strcpy(i->name, "Radio");
+	i->type = V4L2_INPUT_TYPE_TUNER;
+
+	return 0;
+}
+
+static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	if (unlikely(a->index))
+		return -EINVAL;
+
+	strcpy(a->name, "Radio");
+	return 0;
+}
+
+static int radio_s_tuner(struct file *file, void *priv,
+			 struct v4l2_tuner *t)
+{
+	struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+
+	if (0 != t->index)
+		return -EINVAL;
+
+	em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
+
+	return 0;
+}
+
+static int radio_s_audio(struct file *file, void *fh,
+			 struct v4l2_audio *a)
+{
+	return 0;
+}
+
+static int radio_s_input(struct file *file, void *fh, unsigned int i)
+{
+	return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+			   struct v4l2_queryctrl *qc)
+{
+	int i;
+
+	if (qc->id <  V4L2_CID_BASE ||
+		qc->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+
+	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 -EINVAL;
 }
 
 /*
@@ -252,8 +1258,9 @@ static void video_mux(struct em28xx *dev, int index)
 static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
 {
 	int minor = iminor(inode);
-	int errCode = 0;
+	int errCode = 0, radio = 0;
 	struct em28xx *h,*dev = NULL;
+	struct em28xx_fh *fh;
 
 	list_for_each_entry(h, &em28xx_devlist, devlist) {
 		if (h->vdev->minor == minor) {
@@ -264,6 +1271,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
 			dev  = h;
 			dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
 		}
+		if (h->radio_dev &&
+		    h->radio_dev->minor == minor) {
+			radio = 1;
+			dev   = h;
+		}
 	}
 	if (NULL == dev)
 		return -ENODEV;
@@ -271,23 +1283,18 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
 	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;
+	fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
 
-	if (dev->users) {
-		em28xx_warn("this driver can be opened only once\n");
-		up_read(&em28xx_disconnect);
-		return -EBUSY;
+	if (!fh) {
+		em28xx_errdev("em28xx-video.c: Out of memory?!\n");
+		return -ENOMEM;
 	}
-
-	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);
-
 	mutex_lock(&dev->lock);
+	fh->dev = dev;
+	fh->radio = radio;
+	filp->private_data = fh;
 
-	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
 		em28xx_set_alternate(dev);
 
 		dev->width = norm_maxw(dev);
@@ -301,30 +1308,23 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
 		em28xx_capture_start(dev, 1);
 		em28xx_resolution_set(dev);
 
-		/* device needs to be initialized before isoc transfer */
-		video_mux(dev, 0);
 
 		/* start the transfer */
 		errCode = em28xx_init_isoc(dev);
 		if (errCode)
 			goto err;
 
+		em28xx_empty_framequeues(dev);
+	}
+	if (fh->radio) {
+		em28xx_videodbg("video_open: setting radio device\n");
+		em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL);
 	}
 
 	dev->users++;
-	filp->private_data = dev;
-	dev->io = IO_NONE;
-	dev->stream = STREAM_OFF;
-	dev->num_frames = 0;
-
-	/* prepare queues */
-	em28xx_empty_framequeues(dev);
-
-	dev->state |= DEV_INITIALIZED;
 
 err:
 	mutex_unlock(&dev->lock);
-	up_read(&em28xx_disconnect);
 	return errCode;
 }
 
@@ -335,7 +1335,6 @@ err:
 */
 static void em28xx_release_resources(struct em28xx *dev)
 {
-	mutex_lock(&em28xx_sysfs_lock);
 
 	/*FIXME: I2C IR should be disconnected */
 
@@ -343,12 +1342,29 @@ static void em28xx_release_resources(struct em28xx *dev)
 				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);
+	if (dev->radio_dev) {
+		if (-1 != dev->radio_dev->minor)
+			video_unregister_device(dev->radio_dev);
+		else
+			video_device_release(dev->radio_dev);
+		dev->radio_dev = NULL;
+	}
+	if (dev->vbi_dev) {
+		if (-1 != dev->vbi_dev->minor)
+			video_unregister_device(dev->vbi_dev);
+		else
+			video_device_release(dev->vbi_dev);
+		dev->vbi_dev = NULL;
+	}
+	if (dev->vdev) {
+		if (-1 != dev->vdev->minor)
+			video_unregister_device(dev->vdev);
+		else
+			video_device_release(dev->vdev);
+		dev->vdev = NULL;
+	}
 	em28xx_i2c_unregister(dev);
 	usb_put_dev(dev->udev);
-	mutex_unlock(&em28xx_sysfs_lock);
-
 
 	/* Mark device as unused */
 	em28xx_devused&=~(1<<dev->devno);
@@ -360,34 +1376,42 @@ static void em28xx_release_resources(struct em28xx *dev)
  */
 static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
 {
-	int errCode;
-	struct em28xx *dev=filp->private_data;
+	struct em28xx_fh *fh  = filp->private_data;
+	struct em28xx    *dev = fh->dev;
+	int              errCode;
 
 	em28xx_videodbg("users=%d\n", dev->users);
 
-	mutex_lock(&dev->lock);
 
-	em28xx_uninit_isoc(dev);
+	if (res_check(fh))
+		res_free(fh);
 
-	em28xx_release_buffers(dev);
+	mutex_lock(&dev->lock);
 
-	/* the device is already disconnect, free the remaining resources */
-	if (dev->state & DEV_DISCONNECTED) {
-		em28xx_release_resources(dev);
-		mutex_unlock(&dev->lock);
-		kfree(dev);
-		return 0;
-	}
+	if (dev->users == 1) {
+		em28xx_uninit_isoc(dev);
+		em28xx_release_buffers(dev);
+		dev->io = IO_NONE;
 
-	/* set alternate 0 */
-	dev->alt = 0;
-	em28xx_videodbg("setting alternate 0\n");
-	errCode = usb_set_interface(dev->udev, 0, 0);
-	if (errCode < 0) {
-		em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n",
-		     errCode);
-	}
+		/* the device is already disconnect,
+		   free the remaining resources */
+		if (dev->state & DEV_DISCONNECTED) {
+			em28xx_release_resources(dev);
+			mutex_unlock(&dev->lock);
+			kfree(dev);
+			return 0;
+		}
 
+		/* set alternate 0 */
+		dev->alt = 0;
+		em28xx_videodbg("setting alternate 0\n");
+		errCode = usb_set_interface(dev->udev, 0, 0);
+		if (errCode < 0) {
+			em28xx_errdev("cannot change alternate number to "
+					"0 (error=%i)\n", errCode);
+		}
+	}
+	kfree(fh);
 	dev->users--;
 	wake_up_interruptible_nr(&dev->open, 1);
 	mutex_unlock(&dev->lock);
@@ -405,56 +1429,65 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
 	struct em28xx_frame_t *f, *i;
 	unsigned long lock_flags;
 	int ret = 0;
-	struct em28xx *dev = filp->private_data;
+	struct em28xx_fh *fh = filp->private_data;
+	struct em28xx *dev = fh->dev;
 
-	if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+	/* FIXME: read() is not prepared to allow changing the video
+	   resolution while streaming. Seems a bug at em28xx_set_fmt
+	 */
+
+	if (unlikely(res_get(fh) < 0))
+		return -EBUSY;
+
+	mutex_lock(&dev->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);
+			mutex_unlock(&dev->lock);
 			return -EFAULT;
 		}
+		mutex_unlock(&dev->lock);
 		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);
+			mutex_unlock(&dev->lock);
 			return -EFAULT;
 		}
+		mutex_unlock(&dev->lock);
 		return (1);
 	}
 
-	if (mutex_lock_interruptible(&dev->fileop_lock))
-		return -ERESTARTSYS;
-
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_videodbg("device not present\n");
-		mutex_unlock(&dev->fileop_lock);
+		mutex_unlock(&dev->lock);
 		return -ENODEV;
 	}
 
 	if (dev->state & DEV_MISCONFIGURED) {
 		em28xx_videodbg("device misconfigured; close and open it again\n");
-		mutex_unlock(&dev->fileop_lock);
+		mutex_unlock(&dev->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");
-		mutex_unlock(&dev->fileop_lock);
+		mutex_unlock(&dev->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");
-			mutex_unlock(&dev->fileop_lock);
+			mutex_unlock(&dev->lock);
 			return -ENOMEM;
 		}
 		dev->io = IO_READ;
@@ -463,13 +1496,13 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
 	}
 
 	if (!count) {
-		mutex_unlock(&dev->fileop_lock);
+		mutex_unlock(&dev->lock);
 		return 0;
 	}
 
 	if (list_empty(&dev->outqueue)) {
 		if (filp->f_flags & O_NONBLOCK) {
-			mutex_unlock(&dev->fileop_lock);
+			mutex_unlock(&dev->lock);
 			return -EAGAIN;
 		}
 		ret = wait_event_interruptible
@@ -477,35 +1510,46 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
 		     (!list_empty(&dev->outqueue)) ||
 		     (dev->state & DEV_DISCONNECTED));
 		if (ret) {
-			mutex_unlock(&dev->fileop_lock);
+			mutex_unlock(&dev->lock);
 			return ret;
 		}
 		if (dev->state & DEV_DISCONNECTED) {
-			mutex_unlock(&dev->fileop_lock);
+			mutex_unlock(&dev->lock);
 			return -ENODEV;
 		}
+		dev->video_bytesread = 0;
 	}
 
 	f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
 
-	spin_lock_irqsave(&dev->queue_lock, lock_flags);
-	list_for_each_entry(i, &dev->outqueue, frame)
-	    i->state = F_UNUSED;
-	INIT_LIST_HEAD(&dev->outqueue);
-	spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
 	em28xx_queue_unusedframes(dev);
 
 	if (count > f->buf.length)
 		count = f->buf.length;
 
-	if (copy_to_user(buf, f->bufmem, count)) {
-		mutex_unlock(&dev->fileop_lock);
+	if ((dev->video_bytesread + count) > dev->frame_size)
+		count = dev->frame_size - dev->video_bytesread;
+
+	if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) {
+		em28xx_err("Error while copying to user\n");
 		return -EFAULT;
 	}
+	dev->video_bytesread += count;
+
+	if (dev->video_bytesread == dev->frame_size) {
+		spin_lock_irqsave(&dev->queue_lock, lock_flags);
+		list_for_each_entry(i, &dev->outqueue, frame)
+				    i->state = F_UNUSED;
+		INIT_LIST_HEAD(&dev->outqueue);
+		spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
+
+		em28xx_queue_unusedframes(dev);
+		dev->video_bytesread = 0;
+	}
+
 	*f_pos += count;
 
-	mutex_unlock(&dev->fileop_lock);
+	mutex_unlock(&dev->lock);
 
 	return count;
 }
@@ -517,11 +1561,14 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
 static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
 {
 	unsigned int mask = 0;
-	struct em28xx *dev = filp->private_data;
+	struct em28xx_fh *fh = filp->private_data;
+	struct em28xx *dev = fh->dev;
 
-	if (mutex_lock_interruptible(&dev->fileop_lock))
+	if (unlikely(res_get(fh) < 0))
 		return POLLERR;
 
+	mutex_lock(&dev->lock);
+
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_videodbg("device not present\n");
 	} else if (dev->state & DEV_MISCONFIGURED) {
@@ -545,83 +1592,61 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
 			if (!list_empty(&dev->outqueue))
 				mask |= POLLIN | POLLRDNORM;
 
-			mutex_unlock(&dev->fileop_lock);
+			mutex_unlock(&dev->lock);
 
 			return mask;
 		}
 	}
 
-	mutex_unlock(&dev->fileop_lock);
+	mutex_unlock(&dev->lock);
 	return POLLERR;
 }
 
 /*
- * em28xx_vm_open()
- */
-static void em28xx_vm_open(struct vm_area_struct *vma)
-{
-	struct em28xx_frame_t *f = vma->vm_private_data;
-	f->vma_use_count++;
-}
-
-/*
- * em28xx_vm_close()
- */
-static void em28xx_vm_close(struct vm_area_struct *vma)
-{
-	/* NOTE: buffers are not freed here */
-	struct em28xx_frame_t *f = vma->vm_private_data;
-
-	if (f->vma_use_count)
-		f->vma_use_count--;
-}
-
-static struct vm_operations_struct em28xx_vm_ops = {
-	.open = em28xx_vm_open,
-	.close = em28xx_vm_close,
-};
-
-/*
  * em28xx_v4l2_mmap()
  */
 static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
 {
-	unsigned long size = vma->vm_end - vma->vm_start,
-	    start = vma->vm_start;
-	void *pos;
-	u32 i;
-
-	struct em28xx *dev = filp->private_data;
+	struct em28xx_fh *fh    = filp->private_data;
+	struct em28xx	 *dev   = fh->dev;
+	unsigned long	 size   = vma->vm_end - vma->vm_start;
+	unsigned long	 start  = vma->vm_start;
+	void 		 *pos;
+	u32		 i;
+
+	if (unlikely(res_get(fh) < 0))
+		return -EBUSY;
 
-	if (mutex_lock_interruptible(&dev->fileop_lock))
-		return -ERESTARTSYS;
+	mutex_lock(&dev->lock);
 
 	if (dev->state & DEV_DISCONNECTED) {
 		em28xx_videodbg("mmap: device not present\n");
-		mutex_unlock(&dev->fileop_lock);
+		mutex_unlock(&dev->lock);
 		return -ENODEV;
 	}
 
 	if (dev->state & DEV_MISCONFIGURED) {
 		em28xx_videodbg ("mmap: Device is misconfigured; close and "
 						"open it again\n");
-		mutex_unlock(&dev->fileop_lock);
+		mutex_unlock(&dev->lock);
 		return -EIO;
 	}
 
-	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
-	    size != PAGE_ALIGN(dev->frame[0].buf.length)) {
-		mutex_unlock(&dev->fileop_lock);
+	if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) {
+		mutex_unlock(&dev->lock);
 		return -EINVAL;
 	}
 
+	if (size > PAGE_ALIGN(dev->frame[0].buf.length))
+		size = PAGE_ALIGN(dev->frame[0].buf.length);
+
 	for (i = 0; i < dev->num_frames; i++) {
 		if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
 			break;
 	}
 	if (i == dev->num_frames) {
 		em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
-		mutex_unlock(&dev->fileop_lock);
+		mutex_unlock(&dev->lock);
 		return -EINVAL;
 	}
 
@@ -633,7 +1658,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");
-			mutex_unlock(&dev->fileop_lock);
+			mutex_unlock(&dev->lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -645,900 +1670,210 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
 	vma->vm_private_data = &dev->frame[i];
 
 	em28xx_vm_open(vma);
-	mutex_unlock(&dev->fileop_lock);
-	return 0;
-}
-
-/*
- * em28xx_get_ctrl()
- * return the current saturation, brightness or contrast, mute state
- */
-static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
-{
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value = dev->mute;
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		ctrl->value = dev->volume;
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-/*
- * em28xx_set_ctrl()
- * mute or set new saturation, brightness or contrast
- */
-static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
-{
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (ctrl->value != dev->mute) {
-			dev->mute = ctrl->value;
-			em28xx_audio_usb_mute(dev, ctrl->value);
-			return em28xx_audio_analog_set(dev);
-		}
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		dev->volume = ctrl->value;
-		return em28xx_audio_analog_set(dev);
-	default:
-		return -EINVAL;
-	}
-}
-
-/*
- * em28xx_stream_interrupt()
- * stops streaming
- */
-static int em28xx_stream_interrupt(struct em28xx *dev)
-{
-	int ret = 0;
-
-	/* stop reading from the device */
-
-	dev->stream = STREAM_INTERRUPT;
-	ret = wait_event_timeout(dev->wait_stream,
-				 (dev->stream == STREAM_OFF) ||
-				 (dev->state & DEV_DISCONNECTED),
-				 EM28XX_URB_TIMEOUT);
-	if (dev->state & DEV_DISCONNECTED)
-		return -ENODEV;
-	else if (ret) {
-		dev->state |= DEV_MISCONFIGURED;
-		em28xx_videodbg("device is misconfigured; close and "
-			"open /dev/video%d again\n",
-				dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int em28xx_set_norm(struct em28xx *dev, int width, int height)
-{
-	unsigned int hscale, vscale;
-	unsigned int maxh, maxw;
-
-	maxw = norm_maxw(dev);
-	maxh = norm_maxh(dev);
-
-	/* 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 ((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);
-
-	/* 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;
-
-	em28xx_resolution_set(dev);
-
+	mutex_unlock(&dev->lock);
 	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? */
+static const struct file_operations em28xx_v4l_fops = {
+	.owner         = THIS_MODULE,
+	.open          = em28xx_v4l2_open,
+	.release       = em28xx_v4l2_close,
+	.read          = em28xx_v4l2_read,
+	.poll          = em28xx_v4l2_poll,
+	.mmap          = em28xx_v4l2_mmap,
+	.ioctl	       = video_ioctl2,
+	.llseek        = no_llseek,
+	.compat_ioctl  = v4l_compat_ioctl32,
+};
 
-		em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width,
-			dev->height);
-		break;
-	}
+static const struct file_operations radio_fops = {
+	.owner         = THIS_MODULE,
+	.open          = em28xx_v4l2_open,
+	.release       = em28xx_v4l2_close,
+	.ioctl	       = video_ioctl2,
+	.compat_ioctl  = v4l_compat_ioctl32,
+	.llseek        = no_llseek,
+};
 
-	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
-	{
-		format->fmt.sliced.service_set=0;
+static const struct video_device em28xx_video_template = {
+	.fops                       = &em28xx_v4l_fops,
+	.release                    = video_device_release,
+
+	.minor                      = -1,
+	.vidioc_querycap            = vidioc_querycap,
+	.vidioc_enum_fmt_cap        = vidioc_enum_fmt_cap,
+	.vidioc_g_fmt_cap           = vidioc_g_fmt_cap,
+	.vidioc_try_fmt_cap         = vidioc_try_fmt_cap,
+	.vidioc_s_fmt_cap           = vidioc_s_fmt_cap,
+	.vidioc_g_audio             = vidioc_g_audio,
+	.vidioc_s_audio             = vidioc_s_audio,
+	.vidioc_cropcap             = vidioc_cropcap,
+
+	.vidioc_g_fmt_vbi_capture   = vidioc_g_fmt_vbi_capture,
+	.vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture,
+	.vidioc_s_fmt_vbi_capture   = vidioc_try_set_vbi_capture,
+
+	.vidioc_reqbufs             = vidioc_reqbufs,
+	.vidioc_querybuf            = vidioc_querybuf,
+	.vidioc_qbuf                = vidioc_qbuf,
+	.vidioc_dqbuf               = vidioc_dqbuf,
+	.vidioc_s_std               = vidioc_s_std,
+	.vidioc_enum_input          = vidioc_enum_input,
+	.vidioc_g_input             = vidioc_g_input,
+	.vidioc_s_input             = vidioc_s_input,
+	.vidioc_queryctrl           = vidioc_queryctrl,
+	.vidioc_g_ctrl              = vidioc_g_ctrl,
+	.vidioc_s_ctrl              = vidioc_s_ctrl,
+	.vidioc_streamon            = vidioc_streamon,
+	.vidioc_streamoff           = vidioc_streamoff,
+	.vidioc_g_tuner             = vidioc_g_tuner,
+	.vidioc_s_tuner             = vidioc_s_tuner,
+	.vidioc_g_frequency         = vidioc_g_frequency,
+	.vidioc_s_frequency         = vidioc_s_frequency,
+
+	.tvnorms                    = V4L2_STD_ALL,
+	.current_norm               = V4L2_STD_PAL,
+};
 
-		em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format);
+static struct video_device em28xx_radio_template = {
+	.name                 = "em28xx-radio",
+	.type                 = VID_TYPE_TUNER,
+	.fops                 = &radio_fops,
+	.minor                = -1,
+	.vidioc_querycap      = radio_querycap,
+	.vidioc_g_tuner       = radio_g_tuner,
+	.vidioc_enum_input    = radio_enum_input,
+	.vidioc_g_audio       = radio_g_audio,
+	.vidioc_s_tuner       = radio_s_tuner,
+	.vidioc_s_audio       = radio_s_audio,
+	.vidioc_s_input       = radio_s_input,
+	.vidioc_queryctrl     = radio_queryctrl,
+	.vidioc_g_ctrl        = vidioc_g_ctrl,
+	.vidioc_s_ctrl        = vidioc_s_ctrl,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_s_frequency   = vidioc_s_frequency,
+};
 
-		if (format->fmt.sliced.service_set==0)
-			return -EINVAL;
+/******************************** usb interface *****************************************/
 
-		break;
-	}
 
-	default:
-		return -EINVAL;
-	}
-	return (0);
-}
+static LIST_HEAD(em28xx_extension_devlist);
+static DEFINE_MUTEX(em28xx_extension_devlist_lock);
 
-static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format)
+int em28xx_register_extension(struct em28xx_ops *ops)
 {
-	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;
+	struct em28xx *h, *dev = NULL;
 
-	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;
+	list_for_each_entry(h, &em28xx_devlist, devlist)
+		dev = h;
 
-		return 0;
-	}
+	mutex_lock(&em28xx_extension_devlist_lock);
+	list_add_tail(&ops->next, &em28xx_extension_devlist);
+	if (dev)
+		ops->init(dev);
 
-
-	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: interrupting 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);
+	printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+	mutex_unlock(&em28xx_extension_devlist_lock);
 
 	return 0;
 }
+EXPORT_SYMBOL(em28xx_register_extension);
 
-/*
- * em28xx_v4l2_do_ioctl()
- * This function is _not_ called directly, but from
- * em28xx_v4l2_ioctl. Userspace
- * copying is done already, arg is a kernel pointer.
- */
-static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
-			   struct em28xx *dev, unsigned int cmd, void *arg,
-			   v4l2_kioctl driver_ioctl)
+void em28xx_unregister_extension(struct em28xx_ops *ops)
 {
-	int ret;
+	struct em28xx *h, *dev = NULL;
 
-	switch (cmd) {
-		/* ---------- tv norms ---------- */
-	case VIDIOC_ENUMSTD:
-	{
-		struct v4l2_standard *e = arg;
-		unsigned int i;
+	list_for_each_entry(h, &em28xx_devlist, devlist)
+		dev = h;
 
-		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;
+	if (dev)
+		ops->fini(dev);
 
-		*id = dev->tvnorm->id;
-		return 0;
-	}
-	case VIDIOC_S_STD:
-	{
-		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)
-					break;
-		if (i == TVNORMS)
-			return -EINVAL;
-
-		mutex_lock(&dev->lock);
-		dev->tvnorm = &tvnorms[i];
-
-		em28xx_set_norm(dev, dev->width, dev->height);
-
-		em28xx_i2c_call_clients(dev, VIDIOC_S_STD,
-					&dev->tvnorm->id);
-
-		mutex_unlock(&dev->lock);
-
-		return 0;
-	}
-
-	/* ------ 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;
-	}
-	case VIDIOC_G_INPUT:
-	{
-		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;
-
-		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;
-
-		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;
-	}
-	case VIDIOC_S_AUDIO:
-	{
-		struct v4l2_audio *a = arg;
-
-		if (a->index != dev->ctl_ainput)
-			return -EINVAL;
-
-		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;
-				}
-			}
-		}
-		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);
-				}
-			}
-		}
-
-		em28xx_i2c_call_clients(dev,cmd,arg);
-		return 0;
-	}
-	/* --- tuner ioctls ------------------------------------------ */
-	case VIDIOC_G_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
-
-		if (0 != t->index)
-			return -EINVAL;
-
-		memset(t, 0, sizeof(*t));
-		strcpy(t->name, "Tuner");
-		mutex_lock(&dev->lock);
-		/* let clients fill in the remainder of this struct */
-		em28xx_i2c_call_clients(dev, cmd, t);
-		mutex_unlock(&dev->lock);
-		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;
-
-		if (0 != t->index)
-			return -EINVAL;
-		mutex_lock(&dev->lock);
-		/* let clients handle this */
-		em28xx_i2c_call_clients(dev, cmd, t);
-		mutex_unlock(&dev->lock);
-		return 0;
-	}
-	case VIDIOC_G_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
-
-		memset(f, 0, sizeof(*f));
-		f->type = V4L2_TUNER_ANALOG_TV;
-		f->frequency = dev->ctl_freq;
-
-		return 0;
-	}
-	case VIDIOC_S_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
-
-		if (0 != f->tuner)
-			return -EINVAL;
-
-		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;
-
-		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;
-
-		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-			|| dev->io != IO_MMAP)
-			return -EINVAL;
-
-		if (list_empty(&dev->inqueue))
-			return -EINVAL;
-
-		dev->stream = STREAM_ON;	/* FIXME: Start video capture here? */
-
-		em28xx_videodbg("VIDIOC_STREAMON: starting stream\n");
-
-		return 0;
-	}
-	case VIDIOC_STREAMOFF:
-	{
-		int *type = arg;
-		int ret;
-
-		if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE
-			|| dev->io != IO_MMAP)
-			return -EINVAL;
-
-		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);
-	}
-	return 0;
-}
-
-/*
- * em28xx_v4l2_do_ioctl()
- * This function is _not_ called directly, but from
- * em28xx_v4l2_ioctl. Userspace
- * copying is done already, arg is a kernel pointer.
- */
-static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp,
-				 unsigned int cmd, void *arg)
-{
-	struct em28xx *dev = filp->private_data;
-
-	if (!dev)
-		return -ENODEV;
-
-	if (video_debug > 1)
-		v4l_print_ioctl(dev->name,cmd);
-
-	switch (cmd) {
-
-		/* --- 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_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;
-	}
-	case VIDIOC_G_FMT:
-		return em28xx_get_fmt(dev, (struct v4l2_format *) arg);
-
-	case VIDIOC_TRY_FMT:
-	case VIDIOC_S_FMT:
-		return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg);
-
-	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");
-			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);
-
-		em28xx_release_buffers(dev);
-		if (rb->count)
-			rb->count =
-				em28xx_request_buffers(dev, rb->count);
-
-		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;
-
-		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));
-
-		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;
-
-		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;
-
-		/* 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;
-	}
-	case VIDIOC_DQBUF:
-	{
-		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 (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);
-
-		f->state = F_UNUSED;
-		memcpy(b, &f->buf, sizeof(*b));
-
-		if (f->vma_use_count)
-			b->flags |= V4L2_BUF_FLAG_MAPPED;
-
-		return 0;
-	}
-	default:
-		return em28xx_do_ioctl(inode, filp, dev, cmd, arg,
-				       em28xx_video_do_ioctl);
-	}
-	return 0;
+	mutex_lock(&em28xx_extension_devlist_lock);
+	printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
+	list_del(&ops->next);
+	mutex_unlock(&em28xx_extension_devlist_lock);
 }
+EXPORT_SYMBOL(em28xx_unregister_extension);
 
-/*
- * em28xx_v4l2_ioctl()
- * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl()
- */
-static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp,
-			     unsigned int cmd, unsigned long arg)
+struct video_device *em28xx_vdev_init(struct em28xx *dev,
+				      const struct video_device *template,
+				      const int type,
+				      const char *type_name)
 {
-	int ret = 0;
-	struct em28xx *dev = filp->private_data;
-
-	if (mutex_lock_interruptible(&dev->fileop_lock))
-		return -ERESTARTSYS;
-
-	if (dev->state & DEV_DISCONNECTED) {
-		em28xx_errdev("v4l2 ioctl: device not present\n");
-		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");
-		mutex_unlock(&dev->fileop_lock);
-		return -EIO;
-	}
+	struct video_device *vfd;
 
-	ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl);
+	vfd = video_device_alloc();
+	if (NULL == vfd)
+		return NULL;
+	*vfd = *template;
+	vfd->minor   = -1;
+	vfd->dev = &dev->udev->dev;
+	vfd->release = video_device_release;
+	vfd->type = type;
 
-	mutex_unlock(&dev->fileop_lock);
+	snprintf(vfd->name, sizeof(vfd->name), "%s %s",
+		 dev->name, type_name);
 
-	return ret;
+	return vfd;
 }
 
-static const struct file_operations em28xx_v4l_fops = {
-	.owner = THIS_MODULE,
-	.open = em28xx_v4l2_open,
-	.release = em28xx_v4l2_close,
-	.ioctl = em28xx_v4l2_ioctl,
-	.read = em28xx_v4l2_read,
-	.poll = em28xx_v4l2_poll,
-	.mmap = em28xx_v4l2_mmap,
-	.llseek = no_llseek,
-	.compat_ioctl   = v4l_compat_ioctl32,
-
-};
-
-/******************************** usb interface *****************************************/
 
 /*
  * em28xx_init_dev()
  * allocates and inits the device structs, registers i2c bus and v4l device
  */
 static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
-			   int minor, int model)
+			   int minor)
 {
+	struct em28xx_ops *ops = NULL;
 	struct em28xx *dev = *devhandle;
 	int retval = -ENOMEM;
-	int errCode, i;
+	int errCode;
 	unsigned int maxh, maxw;
 
 	dev->udev = udev;
-	dev->model = model;
 	mutex_init(&dev->lock);
+	spin_lock_init(&dev->queue_lock);
 	init_waitqueue_head(&dev->open);
+	init_waitqueue_head(&dev->wait_frame);
+	init_waitqueue_head(&dev->wait_stream);
 
 	dev->em28xx_write_regs = em28xx_write_regs;
 	dev->em28xx_read_reg = em28xx_read_reg;
 	dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len;
 	dev->em28xx_write_regs_req = em28xx_write_regs_req;
 	dev->em28xx_read_reg_req = em28xx_read_reg_req;
-	dev->is_em2800 = em28xx_boards[model].is_em2800;
-	dev->has_tuner = em28xx_boards[model].has_tuner;
-	dev->has_msp34xx = em28xx_boards[model].has_msp34xx;
-	dev->tda9887_conf = em28xx_boards[model].tda9887_conf;
-	dev->decoder = em28xx_boards[model].decoder;
-
-	if (tuner >= 0)
-		dev->tuner_type = tuner;
-	else
-		dev->tuner_type = em28xx_boards[model].tuner_type;
+	dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
 
-	dev->video_inputs = em28xx_boards[model].vchannels;
+	errCode = em28xx_read_reg(dev, CHIPID_REG);
+	if (errCode >= 0)
+		em28xx_info("em28xx chip ID = %d\n", errCode);
 
-	for (i = 0; i < TVNORMS; i++)
-		if (em28xx_boards[model].norm == tvnorms[i].mode)
-			break;
-	if (i == TVNORMS)
-		i = 0;
+	em28xx_pre_card_setup(dev);
+
+	errCode = em28xx_config(dev);
+	if (errCode) {
+		em28xx_errdev("error configuring device\n");
+		em28xx_devused &= ~(1<<dev->devno);
+		kfree(dev);
+		return -ENOMEM;
+	}
+
+	/* register i2c bus */
+	em28xx_i2c_register(dev);
 
-	dev->tvnorm = &tvnorms[i];	/* set default norm */
+	/* Do board specific init and eeprom reading */
+	em28xx_card_setup(dev);
 
-	em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name);
+	/* Configure audio */
+	em28xx_audio_analog_set(dev);
+
+	/* configure the device */
+	em28xx_config_i2c(dev);
+
+	/* set default norm */
+	dev->norm = em28xx_video_template.current_norm;
 
 	maxw = norm_maxw(dev);
 	maxh = norm_maxh(dev);
@@ -1555,138 +1890,110 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
 	dev->vscale = 0;
 	dev->ctl_input = 2;
 
-	/* setup video picture settings for saa7113h */
-	memset(&dev->vpic, 0, sizeof(dev->vpic));
-	dev->vpic.colour = 128 << 8;
-	dev->vpic.hue = 128 << 8;
-	dev->vpic.brightness = 128 << 8;
-	dev->vpic.contrast = 192 << 8;
-	dev->vpic.whiteness = 128 << 8;	/* This one isn't used */
-	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("saa7115");
-	if (dev->decoder == EM28XX_TVP5150)
-		request_module("tvp5150");
-	if (dev->has_tuner)
-		request_module("tuner");
-#endif
 	errCode = em28xx_config(dev);
-	if (errCode) {
-		em28xx_errdev("error configuring device\n");
-		em28xx_devused&=~(1<<dev->devno);
-		kfree(dev);
-		return -ENOMEM;
-	}
-
-	mutex_lock(&dev->lock);
-	/* register i2c bus */
-	em28xx_i2c_register(dev);
 
-	/* Do board specific init and eeprom reading */
-	em28xx_card_setup(dev);
+	list_add_tail(&dev->devlist, &em28xx_devlist);
 
-	/* configure the device */
-	em28xx_config_i2c(dev);
-
-	mutex_unlock(&dev->lock);
-
-	errCode = em28xx_config(dev);
-
-#ifdef CONFIG_MODULES
-	if (dev->has_msp34xx)
-		request_module("msp3400");
-#endif
-	/* allocate and fill v4l2 device struct */
-	dev->vdev = video_device_alloc();
+	/* allocate and fill video video_device struct */
+	dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template,
+					  VID_TYPE_CAPTURE, "video");
 	if (NULL == dev->vdev) {
 		em28xx_errdev("cannot allocate video_device.\n");
-		em28xx_devused&=~(1<<dev->devno);
-		kfree(dev);
-		return -ENOMEM;
-	}
-
-	dev->vbi_dev = video_device_alloc();
-	if (NULL == dev->vbi_dev) {
-		em28xx_errdev("cannot allocate video_device.\n");
-		kfree(dev->vdev);
-		em28xx_devused&=~(1<<dev->devno);
-		kfree(dev);
-		return -ENOMEM;
+		goto fail_unreg;
 	}
-
-	/* Fills VBI device info */
-	dev->vbi_dev->type = VFL_TYPE_VBI;
-	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)
+	if (dev->tuner_type != TUNER_ABSENT)
 		dev->vdev->type |= VID_TYPE_TUNER;
-	dev->vdev->fops = &em28xx_v4l_fops;
-	dev->vdev->minor = -1;
-	dev->vdev->dev = &dev->udev->dev;
-	dev->vdev->release = video_device_release;
-	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 */
-	mutex_lock(&dev->lock);
-	if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
-					 video_nr[dev->devno]))) {
+	/* register v4l2 video video_device */
+	retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+				       video_nr[dev->devno]);
+	if (retval) {
 		em28xx_errdev("unable to register video device (error=%i).\n",
 			      retval);
-		mutex_unlock(&dev->lock);
-		list_del(&dev->devlist);
-		video_device_release(dev->vdev);
-		em28xx_devused&=~(1<<dev->devno);
-		kfree(dev);
-		return -ENODEV;
+		goto fail_unreg;
 	}
 
+	/* Allocate and fill vbi video_device struct */
+	dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
+					  VFL_TYPE_VBI, "vbi");
+	/* register v4l2 vbi video_device */
 	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);
-		em28xx_devused&=~(1<<dev->devno);
-		kfree(dev);
-		return -ENODEV;
-	} else {
-		printk("registered VBI\n");
+		em28xx_errdev("unable to register vbi device\n");
+		retval = -ENODEV;
+		goto fail_unreg;
 	}
 
+	if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
+		dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
+					VFL_TYPE_RADIO, "radio");
+		if (NULL == dev->radio_dev) {
+			em28xx_errdev("cannot allocate video_device.\n");
+			goto fail_unreg;
+		}
+		retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+					    radio_nr[dev->devno]);
+		if (retval < 0) {
+			em28xx_errdev("can't register radio device\n");
+			goto fail_unreg;
+		}
+		em28xx_info("Registered radio device as /dev/radio%d\n",
+			    dev->radio_dev->minor & 0x1f);
+	}
+
+
 	if (dev->has_msp34xx) {
 		/* Send a reset to other chips via gpio */
 		em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1);
 		msleep(3);
 		em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1);
 		msleep(3);
-
 	}
-	video_mux(dev, 0);
 
-	mutex_unlock(&dev->lock);
+	video_mux(dev, 0);
 
 	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);
 
+	mutex_lock(&em28xx_extension_devlist_lock);
+	if (!list_empty(&em28xx_extension_devlist)) {
+		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+			if (ops->id)
+				ops->init(dev);
+		}
+	}
+	mutex_unlock(&em28xx_extension_devlist_lock);
+
 	return 0;
+
+fail_unreg:
+	em28xx_release_resources(dev);
+	mutex_unlock(&dev->lock);
+	kfree(dev);
+	return retval;
+}
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+static void request_module_async(struct work_struct *work)
+{
+	struct em28xx *dev = container_of(work,
+			     struct em28xx, request_module_wk);
+
+	if (dev->has_audio_class)
+		request_module("snd-usb-audio");
+	else
+		request_module("em28xx-alsa");
+}
+
+static void request_modules(struct em28xx *dev)
+{
+	INIT_WORK(&dev->request_module_wk, request_module_async);
+	schedule_work(&dev->request_module_wk);
 }
+#else
+#define request_modules(dev)
+#endif /* CONFIG_MODULES */
 
 /*
  * em28xx_usb_probe()
@@ -1700,7 +2007,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	struct usb_interface *uif;
 	struct em28xx *dev = NULL;
 	int retval = -ENODEV;
-	int model,i,nr,ifnum;
+	int i, nr, ifnum;
 
 	udev = usb_get_dev(interface_to_usbdev(interface));
 	ifnum = interface->altsetting[0].desc.bInterfaceNumber;
@@ -1740,8 +2047,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 		return -ENODEV;
 	}
 
-	model=id->driver_info;
-
 	if (nr >= EM28XX_MAXBOARDS) {
 		printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
 		em28xx_devused&=~(1<<nr);
@@ -1757,7 +2062,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	}
 
 	snprintf(dev->name, 29, "em28xx #%d", nr);
-	dev->devno=nr;
+	dev->devno = nr;
+	dev->model = id->driver_info;
+
+	/* Checks if audio is provided by some interface */
+	for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
+		uif = udev->config->interface[i];
+		if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
+			dev->has_audio_class = 1;
+			break;
+		}
+	}
+
+	printk(KERN_INFO DRIVER_NAME " %s usb audio class\n",
+		   dev->has_audio_class ? "Has" : "Doesn't have");
 
 	/* compute alternate max packet sizes */
 	uif = udev->actconfig->interface[0];
@@ -1784,33 +2102,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 	}
 
 	if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
-		model=card[nr];
-
-	if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
-		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. Generic type will be used."
-			"%s: Best regards,\n"
-			"%s:         -- tux\n",
-			dev->name,dev->name,dev->name,dev->name,dev->name);
-		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++) {
-			em28xx_errdev("    card=%d -> %s\n", i,
-							em28xx_boards[i].name);
-		}
-	}
+		dev->model = card[nr];
 
 	/* allocate device struct */
-	retval = em28xx_init_dev(&dev, udev, nr, model);
+	retval = em28xx_init_dev(&dev, udev, nr);
 	if (retval)
 		return retval;
 
-	em28xx_info("Found %s\n", em28xx_boards[model].name);
+	em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
 
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(interface, dev);
+
+	request_modules(dev);
+
 	return 0;
 }
 
@@ -1821,18 +2126,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
  */
 static void em28xx_usb_disconnect(struct usb_interface *interface)
 {
-	struct em28xx *dev = usb_get_intfdata(interface);
+	struct em28xx *dev;
+	struct em28xx_ops *ops = NULL;
+
+	dev = usb_get_intfdata(interface);
 	usb_set_intfdata(interface, NULL);
 
 	if (!dev)
 		return;
 
-	down_write(&em28xx_disconnect);
+	em28xx_info("disconnecting %s\n", dev->vdev->name);
 
+	/* wait until all current v4l2 io is finished then deallocate resources */
 	mutex_lock(&dev->lock);
 
-	em28xx_info("disconnecting %s\n", dev->vdev->name);
-
 	wake_up_interruptible_all(&dev->open);
 
 	if (dev->users) {
@@ -1850,15 +2157,20 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 		dev->state |= DEV_DISCONNECTED;
 		em28xx_release_resources(dev);
 	}
-
 	mutex_unlock(&dev->lock);
 
+	mutex_lock(&em28xx_extension_devlist_lock);
+	if (!list_empty(&em28xx_extension_devlist)) {
+		list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+			ops->fini(dev);
+		}
+	}
+	mutex_unlock(&em28xx_extension_devlist_lock);
+
 	if (!dev->users) {
 		kfree(dev->alt_max_pkt_size);
 		kfree(dev);
 	}
-
-	up_write(&em28xx_disconnect);
 }
 
 static struct usb_driver em28xx_usb_driver = {
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index d8fcc9e17ac0..f3bad0c1c517 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -25,28 +25,11 @@
 #ifndef _EM28XX_H
 #define _EM28XX_H
 
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 #include <media/ir-kbd-i2c.h>
 
-/* Boards supported by driver */
-
-#define EM2800_BOARD_UNKNOWN			0
-#define EM2820_BOARD_UNKNOWN			1
-#define EM2820_BOARD_TERRATEC_CINERGY_250	2
-#define EM2820_BOARD_PINNACLE_USB_2		3
-#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2      4
-#define EM2820_BOARD_MSI_VOX_USB_2              5
-#define EM2800_BOARD_TERRATEC_CINERGY_200       6
-#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
 
 /* maximum number of em28xx boards */
@@ -148,10 +131,17 @@ enum enum28xx_itype {
 	EM28XX_RADIO,
 };
 
+enum em28xx_amux {
+	EM28XX_AMUX_VIDEO,
+	EM28XX_AMUX_LINE_IN,
+	EM28XX_AMUX_AC97_VIDEO,
+	EM28XX_AMUX_AC97_LINE_IN,
+};
+
 struct em28xx_input {
 	enum enum28xx_itype type;
 	unsigned int vmux;
-	unsigned int amux;
+	enum em28xx_amux amux;
 };
 
 #define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
@@ -165,19 +155,23 @@ enum em28xx_decoder {
 struct em28xx_board {
 	char *name;
 	int vchannels;
-	int norm;
 	int tuner_type;
 
 	/* i2c flags */
-	unsigned int is_em2800;
 	unsigned int tda9887_conf;
 
-	unsigned int has_tuner:1;
+	unsigned int is_em2800:1;
 	unsigned int has_msp34xx:1;
+	unsigned int mts_firmware:1;
+	unsigned int has_12mhz_i2s:1;
+	unsigned int max_range_640_480:1;
+
+	unsigned int analog_gpio;
 
 	enum em28xx_decoder decoder;
 
 	struct em28xx_input       input[MAX_EM28XX_INPUT];
+	struct em28xx_input	  radio;
 };
 
 struct em28xx_eeprom {
@@ -201,12 +195,26 @@ enum em28xx_dev_state {
 	DEV_MISCONFIGURED = 0x04,
 };
 
-/* tvnorms */
-struct em28xx_tvnorm {
-	char *name;
-	v4l2_std_id id;
-	/* mode for saa7113h */
-	int mode;
+#define EM28XX_AUDIO_BUFS 5
+#define EM28XX_NUM_AUDIO_PACKETS 64
+#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
+#define EM28XX_CAPTURE_STREAM_EN 1
+#define EM28XX_AUDIO   0x10
+
+struct em28xx_audio {
+	char name[50];
+	char *transfer_buffer[EM28XX_AUDIO_BUFS];
+	struct urb *urb[EM28XX_AUDIO_BUFS];
+	struct usb_device *udev;
+	unsigned int capture_transfer_done;
+	struct snd_pcm_substream   *capture_pcm_substream;
+
+	unsigned int hwptr_done_capture;
+	struct snd_card            *sndcard;
+
+	int users, shutdown;
+	enum em28xx_stream_state capture_stream;
+	spinlock_t slock;
 };
 
 /* main device struct */
@@ -215,12 +223,17 @@ struct em28xx {
 	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;
-	unsigned int has_tuner:1;
+	unsigned int analog_gpio;
+	unsigned int is_em2800:1;
 	unsigned int has_msp34xx:1;
 	unsigned int has_tda9887:1;
+	unsigned int stream_on:1;	/* Locks streams */
+	unsigned int has_audio_class:1;
+	unsigned int has_12mhz_i2s:1;
+	unsigned int max_range_640_480:1;
+
+	int video_inputs;	/* number of video inputs */
+	struct list_head	devlist;
 
 	u32 i2s_speed;		/* I2S speed for audio digital stream */
 
@@ -235,8 +248,7 @@ struct em28xx {
 	/* video for linux */
 	int users;		/* user count for exclusive use */
 	struct video_device *vdev;	/* video for linux device struct */
-	struct video_picture vpic;	/* picture settings only used to init saa7113h */
-	struct em28xx_tvnorm *tvnorm;	/* selected tv norm */
+	v4l2_std_id norm;	/* selected tv norm */
 	int ctl_freq;		/* selected frequency */
 	unsigned int ctl_input;	/* selected input */
 	unsigned int ctl_ainput;	/* slected audio input */
@@ -256,17 +268,27 @@ struct em28xx {
 	int vscale;		/* vertical scale factor (see datasheet) */
 	int interlaced;		/* 1=interlace fileds, 0=just top fileds */
 	int type;
+	unsigned int video_bytesread;	/* Number of bytes read */
+
+	unsigned long hash;	/* eeprom hash - for boards with generic ID */
+	unsigned long i2c_hash;	/* i2c devicelist hash - for boards with generic ID */
+
+	struct em28xx_audio *adev;
 
 	/* states */
 	enum em28xx_dev_state state;
 	enum em28xx_stream_state stream;
 	enum em28xx_io_method io;
+
+	struct work_struct         request_module_wk;
+
 	/* locks */
-	struct mutex lock, fileop_lock;
+	struct mutex lock;
 	spinlock_t queue_lock;
 	struct list_head inqueue, outqueue;
 	wait_queue_head_t open, wait_frame, wait_stream;
 	struct video_device *vbi_dev;
+	struct video_device *radio_dev;
 
 	unsigned char eedata[256];
 
@@ -289,16 +311,27 @@ struct em28xx {
 	int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
 };
 
+struct em28xx_fh {
+	struct em28xx *dev;
+	unsigned int  stream_on:1;	/* Locks streams */
+	int           radio;
+};
+
+struct em28xx_ops {
+	struct list_head next;
+	char *name;
+	int id;
+	int (*init)(struct em28xx *);
+	int (*fini)(struct em28xx *);
+};
+
 /* Provided by em28xx-i2c.c */
 
 void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg);
+void em28xx_do_i2c_scan(struct em28xx *dev);
 int em28xx_i2c_register(struct em28xx *dev);
 int em28xx_i2c_unregister(struct em28xx *dev);
 
-/* Provided by em28xx-input.c */
-
-void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir);
-
 /* Provided by em28xx-core.c */
 
 u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
@@ -314,8 +347,9 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
 int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
 int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
 			  u8 bitmask);
-int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val);
+int em28xx_set_audio_source(struct em28xx *dev);
 int em28xx_audio_analog_set(struct em28xx *dev);
+
 int em28xx_colorlevels_set_default(struct em28xx *dev);
 int em28xx_capture_start(struct em28xx *dev, int start);
 int em28xx_outfmt_set_yuv422(struct em28xx *dev);
@@ -324,6 +358,10 @@ int em28xx_init_isoc(struct em28xx *dev);
 void em28xx_uninit_isoc(struct em28xx *dev);
 int em28xx_set_alternate(struct em28xx *dev);
 
+/* Provided by em28xx-video.c */
+int em28xx_register_extension(struct em28xx_ops *dev);
+void em28xx_unregister_extension(struct em28xx_ops *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);
@@ -331,8 +369,20 @@ extern void em28xx_card_setup(struct em28xx *dev);
 extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 extern const unsigned int em28xx_bcount;
+void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
+
+/* Provided by em28xx-input.c */
+/* TODO: Check if the standard get_key handlers on ir-common can be used */
+int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
+				     u32 *ir_raw);
+
+/* em2800 registers */
+#define EM2800_AUDIOSRC_REG 0x08
 
 /* em28xx registers */
+#define I2C_CLK_REG	0x06
 #define CHIPID_REG	0x0a
 #define USBSUSP_REG	0x0c	/* */
 
@@ -384,9 +434,12 @@ extern const unsigned int em28xx_bcount;
 
 /* em202 registers */
 #define MASTER_AC97	0x02
+#define LINE_IN_AC97    0x10
 #define VIDEO_AC97	0x14
 
 /* register settings */
+#define EM2800_AUDIO_SRC_TUNER  0x0d
+#define EM2800_AUDIO_SRC_LINE   0x0c
 #define EM28XX_AUDIO_SRC_TUNER	0xc0
 #define EM28XX_AUDIO_SRC_LINE	0x80
 
@@ -406,22 +459,6 @@ extern const unsigned int em28xx_bcount;
 	printk(KERN_WARNING "%s: "fmt,\
 			dev->name , ##arg); } while (0)
 
-inline static int em28xx_audio_source(struct em28xx *dev, int input)
-{
-	return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
-}
-
-inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute)
-{
-	return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80);
-}
-
-inline static int em28xx_audio_analog_setup(struct em28xx *dev)
-{
-	/* unmute video mixer with default volume level */
-	return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08");
-}
-
 inline static int em28xx_compression_disable(struct em28xx *dev)
 {
 	/* side effect of disabling scaler and mixer */
@@ -497,18 +534,17 @@ inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
 /*FIXME: maxw should be dependent of alt mode */
 inline static unsigned int norm_maxw(struct em28xx *dev)
 {
-	switch(dev->model){
-		case (EM2820_BOARD_MSI_VOX_USB_2): return(640);
-		default: return(720);
-	}
+	if (dev->max_range_640_480)
+		return 640;
+	else
+		return 720;
 }
 
 inline static unsigned int norm_maxh(struct em28xx *dev)
 {
-	switch(dev->model){
-		case (EM2820_BOARD_MSI_VOX_USB_2): return(480);
-		default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480;
-	}
+	if (dev->max_range_640_480)
+		return 480;
+	else
+		return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
 }
-
 #endif
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index d19d73b81ede..06b6a3ae06c4 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -227,7 +227,7 @@ int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
 }
 
 
-int et61x251_read_reg(struct et61x251_device* cam, u16 index)
+static int et61x251_read_reg(struct et61x251_device* cam, u16 index)
 {
 	struct usb_device* udev = cam->usbdev;
 	u8* buff = cam->control_buffer;
@@ -269,73 +269,6 @@ et61x251_i2c_wait(struct et61x251_device* cam,
 
 
 int
-et61x251_i2c_try_read(struct et61x251_device* cam,
-		      const struct et61x251_sensor* sensor, u8 address)
-{
-	struct usb_device* udev = cam->usbdev;
-	u8* data = cam->control_buffer;
-	int err = 0, res;
-
-	data[0] = address;
-	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);
-	if (res < 0)
-		err += res;
-
-	err += et61x251_i2c_wait(cam, sensor);
-
-	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
-			      0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
-	if (res < 0)
-		err += res;
-
-	if (err)
-		DBG(3, "I2C read failed for %s image sensor", sensor->name);
-
-	PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
-
-	return err ? -1 : (int)data[0];
-}
-
-
-int
-et61x251_i2c_try_write(struct et61x251_device* cam,
-		       const struct et61x251_sensor* sensor, u8 address,
-		       u8 value)
-{
-	struct usb_device* udev = cam->usbdev;
-	u8* data = cam->control_buffer;
-	int err = 0, res;
-
-	data[0] = address;
-	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)
-		err += res;
-
-	data[0] = value;
-	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
-			      0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
-	if (res < 0)
-		err += res;
-
-	err += et61x251_i2c_wait(cam, sensor);
-
-	if (err)
-		DBG(3, "I2C write failed for %s image sensor", sensor->name);
-
-	PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
-
-	return err ? -1 : 0;
-}
-
-
-int
 et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
 		       u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
 		       u8 data8, u8 address)
@@ -387,17 +320,6 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
 }
 
 
-int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
-{
-	return et61x251_i2c_try_read(cam, &cam->sensor, address);
-}
-
-
-int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
-{
-	return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
-}
-
 /*****************************************************************************/
 
 static void et61x251_urb_complete(struct urb *urb)
@@ -675,6 +597,83 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam)
 /*****************************************************************************/
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
+
+static int et61x251_i2c_try_read(struct et61x251_device* cam,
+				 const struct et61x251_sensor* sensor,
+				 u8 address)
+{
+	struct usb_device* udev = cam->usbdev;
+	u8* data = cam->control_buffer;
+	int err = 0, res;
+
+	data[0] = address;
+	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);
+	if (res < 0)
+		err += res;
+
+	err += et61x251_i2c_wait(cam, sensor);
+
+	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
+			      0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
+	if (res < 0)
+		err += res;
+
+	if (err)
+		DBG(3, "I2C read failed for %s image sensor", sensor->name);
+
+	PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
+
+	return err ? -1 : (int)data[0];
+}
+
+
+static int et61x251_i2c_try_write(struct et61x251_device* cam,
+				  const struct et61x251_sensor* sensor,
+				  u8 address, u8 value)
+{
+	struct usb_device* udev = cam->usbdev;
+	u8* data = cam->control_buffer;
+	int err = 0, res;
+
+	data[0] = address;
+	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)
+		err += res;
+
+	data[0] = value;
+	res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
+			      0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
+	if (res < 0)
+		err += res;
+
+	err += et61x251_i2c_wait(cam, sensor);
+
+	if (err)
+		DBG(3, "I2C write failed for %s image sensor", sensor->name);
+
+	PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
+
+	return err ? -1 : 0;
+}
+
+static int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
+{
+	return et61x251_i2c_try_read(cam, &cam->sensor, address);
+}
+
+static int et61x251_i2c_write(struct et61x251_device* cam,
+			      u8 address, u8 value)
+{
+	return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
+}
+
 static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
 {
 	char str[5];
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
index e14586330623..71a03148cb09 100644
--- a/drivers/media/video/et61x251/et61x251_sensor.h
+++ b/drivers/media/video/et61x251/et61x251_sensor.h
@@ -52,14 +52,6 @@ et61x251_attach_sensor(struct et61x251_device* cam,
 /*****************************************************************************/
 
 extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
-extern int et61x251_read_reg(struct et61x251_device*, u16 index);
-extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
-extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
-extern int et61x251_i2c_try_write(struct et61x251_device*,
-				  const struct et61x251_sensor*, u8 address,
-				  u8 value);
-extern int et61x251_i2c_try_read(struct et61x251_device*,
-				 const struct et61x251_sensor*, u8 address);
 extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
 				  u8 data2, u8 data3, u8 data4, u8 data5,
 				  u8 data6, u8 data7, u8 data8, u8 address);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 29779d8bf7fb..9851987b95fb 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -398,6 +398,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
 	case 0x7a:
 	case 0x47:
 	case 0x71:
+	case 0x2d:
 		if (adap->id == I2C_HW_B_CX2388x) {
 			/* Handled by cx88-input */
 			name        = "CX2388x remote";
@@ -504,7 +505,7 @@ static int ir_probe(struct i2c_adapter *adap)
 	*/
 
 	static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
-	static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
+	static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 };
 	static const int probe_em28XX[] = { 0x30, 0x47, -1 };
 	static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
 	static const int probe_cx23885[] = { 0x6b, -1 };
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index 854cc9c30ca9..270906fc3146 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -3,6 +3,7 @@ config VIDEO_IVTV
 	depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
 	select I2C_ALGOBIT
 	select FW_LOADER
+	select VIDEO_IR
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_CX2341X
@@ -12,6 +13,7 @@ config VIDEO_IVTV
 	select VIDEO_SAA7127
 	select VIDEO_TVAUDIO
 	select VIDEO_CS53L32A
+	select VIDEO_M52790
 	select VIDEO_WM8775
 	select VIDEO_WM8739
 	select VIDEO_VP27SMPX
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
index e8eefd96d897..a0389014fa88 100644
--- a/drivers/media/video/ivtv/Makefile
+++ b/drivers/media/video/ivtv/Makefile
@@ -6,3 +6,8 @@ ivtv-objs	:= ivtv-routing.o ivtv-cards.o ivtv-controls.o \
 
 obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
 obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index b6a8be622d3c..f23c6b8d6911 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -23,6 +23,7 @@
 #include "ivtv-i2c.h"
 
 #include <media/msp3400.h>
+#include <media/m52790.h>
 #include <media/wm8775.h>
 #include <media/cs53l32a.h>
 #include <media/cx25840.h>
@@ -39,6 +40,27 @@
 #define MSP_MONO   MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
 				MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
 
+/* usual i2c tuner addresses to probe */
+static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
+	.radio = { I2C_CLIENT_END },
+	.demod = { 0x43, I2C_CLIENT_END },
+	.tv    = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
+/* as above, but with possible radio tuner */
+static struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
+	.radio = { 0x60, I2C_CLIENT_END },
+	.demod = { 0x43, I2C_CLIENT_END },
+	.tv    = { 0x61, I2C_CLIENT_END },
+};
+
+/* using the tda8290+75a combo */
+static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = {
+	.radio = { I2C_CLIENT_END },
+	.demod = { I2C_CLIENT_END },
+	.tv    = { 0x4b, I2C_CLIENT_END },
+};
+
 /********************** card configuration *******************************/
 
 /* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
@@ -72,6 +94,7 @@ static const struct ivtv_card ivtv_card_pvr250 = {
 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
 	},
 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -126,6 +149,7 @@ static const struct ivtv_card ivtv_card_pvr350 = {
 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
 	},
 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+	.i2c = &ivtv_i2c_std,
 };
 
 /* PVR-350 V1 boards have a different audio tuner input and use a
@@ -157,6 +181,7 @@ static const struct ivtv_card ivtv_card_pvr350_v1 = {
 		{ IVTV_CARD_INPUT_LINE_IN2,   MSP_SCART3 },
 	},
 	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 },
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -192,6 +217,7 @@ static const struct ivtv_card ivtv_card_pvr150 = {
 			 CX25840_AUDIO_SERIAL, WM8775_AIN4 },
 	/* apparently needed for the IR blaster */
 	.gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 },
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -234,6 +260,7 @@ static const struct ivtv_card ivtv_card_m179 = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC },
 	},
 	.pci_list = ivtv_pci_m179,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -275,6 +302,7 @@ static const struct ivtv_card ivtv_card_mpg600 = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_mpg600,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -315,6 +343,7 @@ static const struct ivtv_card ivtv_card_mpg160 = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_mpg160,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -350,6 +379,7 @@ static const struct ivtv_card ivtv_card_pg600 = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_pg600,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -393,6 +423,7 @@ static const struct ivtv_card ivtv_card_avc2410 = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
 	.pci_list = ivtv_pci_avc2410,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -463,6 +494,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = {
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_tg5000tv,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -493,6 +525,7 @@ static const struct ivtv_card ivtv_card_va2000 = {
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_va2000,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -537,6 +570,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
 	.pci_list = ivtv_pci_cx23416gyc,
+	.i2c = &ivtv_i2c_std,
 };
 
 static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
@@ -567,6 +601,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = {
 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
+	.i2c = &ivtv_i2c_std,
 };
 
 static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
@@ -596,6 +631,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = {
 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
 	},
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -635,6 +671,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = {
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
 	},
 	.pci_list = ivtv_pci_gv_mvprx,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -671,6 +708,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = {
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
 	},
 	.pci_list = ivtv_pci_gv_mvprx2e,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -705,6 +743,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = {
 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 	},
 	.pci_list = ivtv_pci_gotview_pci_dvd,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -743,6 +782,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = {
 		{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
 	},
 	.pci_list = ivtv_pci_gotview_pci_dvd2,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -778,6 +818,7 @@ static const struct ivtv_card ivtv_card_yuan_mpc622 = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 },
 	},
 	.pci_list = ivtv_pci_yuan_mpc622,
+	.i2c = &ivtv_i2c_tda8290,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -819,6 +860,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = {
 		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
 	},
 	.pci_list = ivtv_pci_dctmvtvp1,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -838,7 +880,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = {
 	.hw_video = IVTV_HW_CX25840,
 	.hw_audio = IVTV_HW_CX25840,
 	.hw_audio_ctrl = IVTV_HW_CX25840,
-	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.hw_all = IVTV_HW_CX25840,
 	.video_inputs = {
 		{ IVTV_CARD_INPUT_SVIDEO1,    0,
 		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
@@ -847,10 +889,8 @@ static const struct ivtv_card ivtv_card_pg600v2 = {
 	.audio_inputs = {
 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
 	},
-	.tuners = {
-		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
-	},
 	.pci_list = ivtv_pci_pg600v2,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -871,17 +911,22 @@ static const struct ivtv_card ivtv_card_club3d = {
 	.hw_audio_ctrl = IVTV_HW_CX25840,
 	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
 	.video_inputs = {
-		{ IVTV_CARD_INPUT_SVIDEO1,    0,
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
 		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
-		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 },
 	},
 	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
 	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
+	.gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
 	.tuners = {
-		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
 	},
 	.pci_list = ivtv_pci_club3d,
+	.i2c = &ivtv_i2c_std,
 };
 
 /* ------------------------------------------------------------------------- */
@@ -900,7 +945,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
 	.hw_video = IVTV_HW_CX25840,
 	.hw_audio = IVTV_HW_CX25840,
 	.hw_audio_ctrl = IVTV_HW_CX25840,
-	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
 	.video_inputs = {
 		{ IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3    },
 		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
@@ -909,10 +954,115 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = {
 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
 	},
 	.gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */
+	.pci_list = ivtv_pci_avertv_mce116,
+	.i2c = &ivtv_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia PVR-150 Plus (M113) card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_pvr150 = {
+	.type = IVTV_CARD_AVER_PVR150PLUS,
+	.name = "AVerMedia PVR-150 Plus",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_muxer = IVTV_HW_GPIO,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5,       0 },
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+	.gpio_init = { .direction = 0x0800, .initial_value = 0 },
+	.gpio_audio_input  = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
 	.tuners = {
-		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+		/* This card has a Partsnic PTI-5NF05 tuner */
+		{ .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N },
 	},
-	.pci_list = ivtv_pci_avertv_mce116,
+	.pci_list = ivtv_pci_aver_pvr150,
+	.i2c = &ivtv_i2c_radio,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia EZMaker PCI Deluxe card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc03f },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_ezmaker = {
+	.type = IVTV_CARD_AVER_EZMAKER,
+	.name = "AVerMedia EZMaker PCI Deluxe",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 0 },
+	},
+	.gpio_init = { .direction = 0x4000, .initial_value = 0x4000 },
+	/* Does not have a tuner */
+	.pci_list = ivtv_pci_aver_ezmaker,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* ASUS Falcon2 */
+
+static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e },
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_asus_falcon2 = {
+	.type = IVTV_CARD_ASUS_FALCON2,
+	.name = "ASUS Falcon2",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_muxer = IVTV_HW_M52790,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
+		{ IVTV_CARD_INPUT_SVIDEO1,    1, CX25840_SVIDEO3    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER },
+		{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL,
+			M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX },
+		{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 },
+	},
+	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER },
+	.tuners = {
+		{ .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+	},
+	.pci_list = ivtv_pci_asus_falcon2,
+	.i2c = &ivtv_i2c_std,
 };
 
 static const struct ivtv_card *ivtv_card_list[] = {
@@ -937,6 +1087,9 @@ static const struct ivtv_card *ivtv_card_list[] = {
 	&ivtv_card_pg600v2,
 	&ivtv_card_club3d,
 	&ivtv_card_avertv_mce116,
+	&ivtv_card_asus_falcon2,
+	&ivtv_card_aver_pvr150,
+	&ivtv_card_aver_ezmaker,
 
 	/* Variations of standard cards but with the same PCI IDs.
 	   These cards must come last in this list. */
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index ff46e5ae8653..191aafdd9968 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -45,7 +45,10 @@
 #define IVTV_CARD_PG600V2	     18 /* Yuan PG600V2/GotView PCI DVD Lite */
 #define IVTV_CARD_CLUB3D	     19 /* Club3D ZAP-TV1x01 */
 #define IVTV_CARD_AVERTV_MCE116	     20 /* AVerTV MCE 116 Plus */
-#define IVTV_CARD_LAST 		     20
+#define IVTV_CARD_ASUS_FALCON2	     21 /* ASUS Falcon2 */
+#define IVTV_CARD_AVER_PVR150PLUS    22 /* AVerMedia PVR-150 Plus */
+#define IVTV_CARD_AVER_EZMAKER       23 /* AVerMedia EZMaker PCI Deluxe */
+#define IVTV_CARD_LAST 		     23
 
 /* Variants of existing cards but with the same PCI IDs. The driver
    detects these based on other device information.
@@ -69,6 +72,7 @@
 #define IVTV_PCI_ID_HAUPPAUGE_ALT1 	0x0270
 #define IVTV_PCI_ID_HAUPPAUGE_ALT2 	0x4070
 #define IVTV_PCI_ID_ADAPTEC 		0x9005
+#define IVTV_PCI_ID_ASUSTEK 		0x1043
 #define IVTV_PCI_ID_AVERMEDIA 		0x1461
 #define IVTV_PCI_ID_YUAN1		0x12ab
 #define IVTV_PCI_ID_YUAN2 		0xff01
@@ -80,7 +84,7 @@
 #define IVTV_PCI_ID_GOTVIEW1		0xffac
 #define IVTV_PCI_ID_GOTVIEW2 		0xffad
 
-/* hardware flags */
+/* hardware flags, no gaps allowed, IVTV_HW_GPIO must always be last */
 #define IVTV_HW_CX25840   (1 << 0)
 #define IVTV_HW_SAA7115   (1 << 1)
 #define IVTV_HW_SAA7127   (1 << 2)
@@ -90,12 +94,12 @@
 #define IVTV_HW_CS53L32A  (1 << 6)
 #define IVTV_HW_TVEEPROM  (1 << 7)
 #define IVTV_HW_SAA7114   (1 << 8)
-#define IVTV_HW_TVAUDIO   (1 << 9)
-#define IVTV_HW_UPD64031A (1 << 10)
-#define IVTV_HW_UPD6408X  (1 << 11)
-#define IVTV_HW_SAA717X   (1 << 12)
-#define IVTV_HW_WM8739    (1 << 13)
-#define IVTV_HW_VP27SMPX  (1 << 14)
+#define IVTV_HW_UPD64031A (1 << 9)
+#define IVTV_HW_UPD6408X  (1 << 10)
+#define IVTV_HW_SAA717X   (1 << 11)
+#define IVTV_HW_WM8739    (1 << 12)
+#define IVTV_HW_VP27SMPX  (1 << 13)
+#define IVTV_HW_M52790    (1 << 14)
 #define IVTV_HW_GPIO      (1 << 15)
 
 #define IVTV_HW_SAA711X   (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
@@ -230,6 +234,12 @@ struct ivtv_card_tuner {
 	int 	    tuner; 	/* tuner ID (from tuner.h) */
 };
 
+struct ivtv_card_tuner_i2c {
+	unsigned short radio[2];/* radio tuner i2c address to probe */
+	unsigned short demod[2];/* demodulator i2c address to probe */
+	unsigned short tv[4];	/* tv tuner i2c addresses to probe */
+};
+
 /* for card information/parameters */
 struct ivtv_card {
 	int type;
@@ -257,6 +267,7 @@ struct ivtv_card {
 	struct ivtv_gpio_audio_detect 	gpio_audio_detect;
 
 	struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS];
+	struct ivtv_card_tuner_i2c *i2c;
 
 	/* list of device and subsystem vendor/devices that
 	   correspond to this card type. */
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 6d2dd8764f81..d42f120354e5 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -59,6 +59,7 @@
 #include <media/tveeprom.h>
 #include <media/saa7115.h>
 #include <media/v4l2-chip-ident.h>
+#include "tuner-xc2028.h"
 
 /* var to keep track of the number of array elements in use */
 int ivtv_cards_active = 0;
@@ -185,6 +186,9 @@ MODULE_PARM_DESC(cardtype,
 		 "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n"
 		 "\t\t\t20 = Club3D ZAP-TV1x01\n"
 		 "\t\t\t21 = AverTV MCE 116 Plus\n"
+		 "\t\t\t22 = ASUS Falcon2\n"
+		 "\t\t\t23 = AverMedia PVR-150 Plus\n"
+		 "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
 		 "\t\t\t 0 = Autodetect (default)\n"
 		 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -397,6 +401,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
 
 	itv->v4l2_cap = itv->card->v4l2_capabilities;
 	itv->card_name = itv->card->name;
+	itv->card_i2c = itv->card->i2c;
 
 	/* If this is a PVR500 then it should be possible to detect whether it is the
 	   first or second unit by looking at the subsystem device ID: is bit 4 is
@@ -414,7 +419,14 @@ static void ivtv_process_eeprom(struct ivtv *itv)
 	   This detection is needed since the eeprom reports incorrectly that a radio is
 	   present on the second unit. */
 	if (tv.model / 1000 == 23) {
+		static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = {
+			.radio = { 0x60, I2C_CLIENT_END },
+			.demod = { 0x43, I2C_CLIENT_END },
+			.tv = { 0x61, I2C_CLIENT_END },
+		};
+
 		itv->card_name = "WinTV PVR 500";
+		itv->card_i2c = &ivtv_i2c_radio;
 		if (pci_slot == 8 || pci_slot == 9) {
 			int is_first = (pci_slot & 1) == 0;
 
@@ -628,10 +640,11 @@ done:
 		IVTV_ERR("Defaulting to %s card\n", itv->card->name);
 		IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
 		IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
-		IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n");
+		IVTV_ERR("Prefix your subject line with [UNKNOWN IVTV CARD].\n");
 	}
 	itv->v4l2_cap = itv->card->v4l2_capabilities;
 	itv->card_name = itv->card->name;
+	itv->card_i2c = itv->card->i2c;
 }
 
 /* Precondition: the ivtv structure has been memset to 0. Only
@@ -695,6 +708,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
 	atomic_set(&itv->yuv_info.next_dma_frame, -1);
 	itv->yuv_info.lace_mode = ivtv_yuv_mode;
 	itv->yuv_info.lace_threshold = ivtv_yuv_threshold;
+	itv->yuv_info.max_frames_buffered = 3;
 	return 0;
 }
 
@@ -812,75 +826,61 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
 	return 0;
 }
 
-static void ivtv_request_module(struct ivtv *itv, const char *name)
+static u32 ivtv_request_module(struct ivtv *itv, u32 hw,
+		const char *name, u32 id)
 {
+	if ((hw & id) == 0)
+		return hw;
 	if (request_module(name) != 0) {
 		IVTV_ERR("Failed to load module %s\n", name);
-	} else {
-		IVTV_DEBUG_INFO("Loaded module %s\n", name);
+		return hw & ~id;
 	}
+	IVTV_DEBUG_INFO("Loaded module %s\n", name);
+	return hw;
 }
 
 static void ivtv_load_and_init_modules(struct ivtv *itv)
 {
 	u32 hw = itv->card->hw_all;
-	int i;
+	unsigned i;
 
 	/* load modules */
 #ifndef CONFIG_VIDEO_TUNER
-	if (hw & IVTV_HW_TUNER) {
-		if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
-			IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n");
-			itv->tunerid = 1;
-		}
-		else {
-			ivtv_request_module(itv, "tuner");
-		}
-	}
+	hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
 #endif
 #ifndef CONFIG_VIDEO_CX25840
-	if (hw & IVTV_HW_CX25840)
-		ivtv_request_module(itv, "cx25840");
+	hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840);
 #endif
 #ifndef CONFIG_VIDEO_SAA711X
-	if (hw & IVTV_HW_SAA711X)
-		ivtv_request_module(itv, "saa7115");
+	hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X);
 #endif
 #ifndef CONFIG_VIDEO_SAA7127
-	if (hw & IVTV_HW_SAA7127)
-		ivtv_request_module(itv, "saa7127");
+	hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
 #endif
-	if (hw & IVTV_HW_SAA717X)
-		ivtv_request_module(itv, "saa717x");
+	hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
 #ifndef CONFIG_VIDEO_UPD64031A
-	if (hw & IVTV_HW_UPD64031A)
-		ivtv_request_module(itv, "upd64031a");
+	hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
 #endif
 #ifndef CONFIG_VIDEO_UPD64083
-	if (hw & IVTV_HW_UPD6408X)
-		ivtv_request_module(itv, "upd64083");
+	hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X);
 #endif
 #ifndef CONFIG_VIDEO_MSP3400
-	if (hw & IVTV_HW_MSP34XX)
-		ivtv_request_module(itv, "msp3400");
+	hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX);
 #endif
 #ifndef CONFIG_VIDEO_VP27SMPX
-	if (hw & IVTV_HW_VP27SMPX)
-		ivtv_request_module(itv, "vp27smpx");
+	hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX);
 #endif
-	if (hw & IVTV_HW_TVAUDIO)
-		ivtv_request_module(itv, "tvaudio");
 #ifndef CONFIG_VIDEO_WM8775
-	if (hw & IVTV_HW_WM8775)
-		ivtv_request_module(itv, "wm8775");
+	hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775);
 #endif
 #ifndef CONFIG_VIDEO_WM8739
-	if (hw & IVTV_HW_WM8739)
-		ivtv_request_module(itv, "wm8739");
+	hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739);
 #endif
 #ifndef CONFIG_VIDEO_CS53L32A
-	if (hw & IVTV_HW_CS53L32A)
-		ivtv_request_module(itv, "cs53l32a");
+	hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A);
+#endif
+#ifndef CONFIG_VIDEO_M52790
+	hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790);
 #endif
 
 	/* check which i2c devices are actually found */
@@ -889,11 +889,12 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
 
 		if (!(device & hw))
 			continue;
-		if (device == IVTV_HW_GPIO) {
-			/* GPIO is always available */
-			itv->hw_flags |= IVTV_HW_GPIO;
+		if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) {
+			/* GPIO and TVEEPROM do not use i2c probing */
+			itv->hw_flags |= device;
 			continue;
 		}
+		ivtv_i2c_register(itv, i);
 		if (ivtv_i2c_hw_addr(itv, device) > 0)
 			itv->hw_flags |= device;
 	}
@@ -964,7 +965,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 				const struct pci_device_id *pci_id)
 {
 	int retval = 0;
-	int yuv_buf_size;
 	int vbi_buf_size;
 	struct ivtv *itv;
 
@@ -979,7 +979,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 	}
 
 	itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC);
-	if (itv == 0) {
+	if (itv == NULL) {
 		spin_unlock(&ivtv_cards_lock);
 		return -ENOMEM;
 	}
@@ -1068,9 +1068,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 	IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
 
 	if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
-#ifdef CONFIG_VIDEO_TVEEPROM_MODULE
-		ivtv_request_module(itv, "tveeprom");
-#endif
 		/* Based on the model number the cardtype may be changed.
 		   The PCI IDs are not always reliable. */
 		ivtv_process_eeprom(itv);
@@ -1111,16 +1108,19 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 		itv->is_50hz = 1;
 		itv->is_out_50hz = 1;
 	}
+
+	itv->yuv_info.osd_full_w = 720;
+	itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480;
+	itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w;
+	itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h;
+
 	itv->params.video_gop_size = itv->is_60hz ? 15 : 12;
 
 	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000;
 	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200;
 	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000;
-
-	/* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */
-	yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500;
-	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2;
-	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8;
+	itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = 0x10000;
+	itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = 0x08000;
 
 	/* Setup VBI Raw Size. Should be big enough to hold PAL.
 	   It is possible to switch between PAL and NTSC, so we need to
@@ -1140,13 +1140,26 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 	if (itv->options.radio > 0)
 		itv->v4l2_cap |= V4L2_CAP_RADIO;
 
-	if (itv->options.tuner > -1 && itv->tunerid == 0) {
+	if (itv->options.tuner > -1) {
 		struct tuner_setup setup;
 
 		setup.addr = ADDR_UNSET;
 		setup.type = itv->options.tuner;
 		setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
+		setup.tuner_callback = (setup.type == TUNER_XC2028) ?
+			ivtv_reset_tuner_gpio : NULL;
 		ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
+		if (setup.type == TUNER_XC2028) {
+			static struct xc2028_ctrl ctrl = {
+				.fname = XC2028_DEFAULT_FIRMWARE,
+				.max_len = 64,
+			};
+			struct v4l2_priv_tun_config cfg = {
+				.tuner = itv->options.tuner,
+				.priv = &ctrl,
+			};
+			ivtv_call_i2c_clients(itv, TUNER_SET_CONFIG, &cfg);
+		}
 	}
 
 	/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 49ce14d14a54..536140f0c19e 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -65,7 +65,6 @@
 
 #include <linux/ivtv.h>
 
-
 /* Memory layout */
 #define IVTV_ENCODER_OFFSET	0x00000000
 #define IVTV_ENCODER_SIZE	0x00800000	/* Total size is 0x01000000, but only first half is used */
@@ -392,6 +391,9 @@ struct yuv_frame_info
 	u32 tru_h;
 	u32 offset_y;
 	s32 lace_mode;
+	u32 sync_field;
+	u32 delay;
+	u32 interlaced;
 };
 
 #define IVTV_YUV_MODE_INTERLACED	0x00
@@ -403,6 +405,8 @@ struct yuv_frame_info
 #define IVTV_YUV_SYNC_ODD		0x04
 #define IVTV_YUV_SYNC_MASK		0x04
 
+#define IVTV_YUV_BUFFERS 8
+
 struct yuv_playback_info
 {
 	u32 reg_2834;
@@ -461,9 +465,10 @@ struct yuv_playback_info
 	u32 osd_vis_w;
 	u32 osd_vis_h;
 
-	int decode_height;
+	u32 osd_full_w;
+	u32 osd_full_h;
 
-	int frame_interlaced;
+	int decode_height;
 
 	int lace_mode;
 	int lace_threshold;
@@ -475,16 +480,23 @@ struct yuv_playback_info
 	u32 yuv_forced_update;
 	int update_frame;
 
-	int sync_field[4];  /* Field to sync on */
-	int field_delay[4]; /* Flag to extend duration of previous frame */
 	u8 fields_lapsed;   /* Counter used when delaying a frame */
 
-	struct yuv_frame_info new_frame_info[4];
+	struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS];
 	struct yuv_frame_info old_frame_info;
 	struct yuv_frame_info old_frame_info_args;
 
 	void *blanking_ptr;
 	dma_addr_t blanking_dmaptr;
+
+	int stream_size;
+
+	u8 draw_frame; /* PVR350 buffer to draw into */
+	u8 max_frames_buffered; /* Maximum number of frames to buffer */
+
+	struct v4l2_rect main_rect;
+	u32 v4l2_src_w;
+	u32 v4l2_src_h;
 };
 
 #define IVTV_VBI_FRAMES 32
@@ -577,13 +589,13 @@ struct ivtv {
 	struct pci_dev *dev;		/* PCI device */
 	const struct ivtv_card *card;	/* card information */
 	const char *card_name;          /* full name of the card */
+	const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
 	u8 has_cx23415;			/* 1 if it is a cx23415 based card, 0 for cx23416 */
 	u8 pvr150_workaround;           /* 1 if the cx25840 needs to workaround a PVR150 bug */
 	u8 nof_inputs;			/* number of video inputs */
 	u8 nof_audio_inputs;		/* number of audio inputs */
 	u32 v4l2_cap;			/* V4L2 capabilities of card */
 	u32 hw_flags; 			/* hardware description of the board */
-	int tunerid;			/* userspace tuner ID for experimental Xceive tuner support */
 	v4l2_std_id tuner_std;		/* the norm of the card's tuner (fixed) */
 					/* controlling video decoder function */
 	int (*video_dec_func)(struct ivtv *, unsigned int, void *);
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index a200a8a95a2d..6fb96f19a866 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -542,6 +542,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
 	struct ivtv_open_id *id = filp->private_data;
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
+	struct yuv_playback_info *yi = &itv->yuv_info;
 	struct ivtv_buffer *buf;
 	struct ivtv_queue q;
 	int bytes_written = 0;
@@ -580,6 +581,24 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
 	set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
 
 retry:
+	/* If possible, just DMA the entire frame - Check the data transfer size
+	since we may get here before the stream has been fully set-up */
+	if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) {
+		while (count >= itv->dma_data_req_size) {
+			if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) {
+				bytes_written += itv->dma_data_req_size;
+				user_buf += itv->dma_data_req_size;
+				count -= itv->dma_data_req_size;
+			} else {
+				break;
+			}
+		}
+		if (count == 0) {
+			IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+			return bytes_written;
+		}
+	}
+
 	for (;;) {
 		/* Gather buffers */
 		while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io)))
@@ -604,9 +623,16 @@ retry:
 
 	/* copy user data into buffers */
 	while ((buf = ivtv_dequeue(s, &q))) {
-		/* Make sure we really got all the user data */
-		rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
+		/* yuv is a pain. Don't copy more data than needed for a single
+		   frame, otherwise we lose sync with the incoming stream */
+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
+		    yi->stream_size + count > itv->dma_data_req_size)
+			rc  = ivtv_buf_copy_from_user(s, buf, user_buf,
+				itv->dma_data_req_size - yi->stream_size);
+		else
+			rc = ivtv_buf_copy_from_user(s, buf, user_buf, count);
 
+		/* Make sure we really got all the user data */
 		if (rc < 0) {
 			ivtv_queue_move(s, &q, NULL, &s->q_free, 0);
 			return rc;
@@ -615,6 +641,16 @@ retry:
 		count -= rc;
 		bytes_written += rc;
 
+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+			yi->stream_size += rc;
+			/* If we have a complete yuv frame, break loop now */
+			if (yi->stream_size == itv->dma_data_req_size) {
+				ivtv_enqueue(s, buf, &s->q_full);
+				yi->stream_size = 0;
+				break;
+			}
+		}
+
 		if (buf->bytesused != s->buf_size) {
 			/* incomplete, leave in q_io for next time */
 			ivtv_enqueue(s, buf, &s->q_io);
@@ -642,6 +678,9 @@ retry:
 		if (s->q_full.length >= itv->dma_data_req_size) {
 			int got_sig;
 
+			if (mode == OUT_YUV)
+				ivtv_yuv_setup_stream_frame(itv);
+
 			prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
 			while (!(got_sig = signal_pending(current)) &&
 					test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
@@ -922,10 +961,15 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
 	}
 
 	/* YUV or MPG Decoding Mode? */
-	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+	if (s->type == IVTV_DEC_STREAM_TYPE_MPG) {
 		clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
-	else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
+	} else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
 		set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+		/* For yuv, we need to know the dma size before we start */
+		itv->dma_data_req_size =
+				1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
+		itv->yuv_info.stream_size = 0;
+	}
 	return 0;
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index 132fb5f71366..688cd3856685 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -22,6 +22,7 @@
 #include "ivtv-driver.h"
 #include "ivtv-cards.h"
 #include "ivtv-gpio.h"
+#include "tuner-xc2028.h"
 #include <media/tuner.h>
 
 /*
@@ -122,6 +123,29 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
 	write_reg(curdir, IVTV_REG_GPIO_DIR);
 }
 
+/* Xceive tuner reset function */
+int ivtv_reset_tuner_gpio(void *dev, int cmd, int value)
+{
+	struct i2c_algo_bit_data *algo = dev;
+	struct ivtv *itv = algo->data;
+	int curdir, curout;
+
+	if (cmd != XC2028_TUNER_RESET)
+		return 0;
+	IVTV_DEBUG_INFO("Resetting tuner\n");
+	curout = read_reg(IVTV_REG_GPIO_OUT);
+	curdir = read_reg(IVTV_REG_GPIO_DIR);
+	curdir |= (1 << 12);  /* GPIO bit 12 */
+
+	curout &= ~(1 << 12);
+	write_reg(curout, IVTV_REG_GPIO_OUT);
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
+
+	curout |= (1 << 12);
+	write_reg(curout, IVTV_REG_GPIO_OUT);
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
+	return 0;
+}
 
 void ivtv_gpio_init(struct ivtv *itv)
 {
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 36e54f78aa2a..fa5ab1eb1800 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -80,6 +80,7 @@
 #endif /* I2C_ADAP_CLASS_TV_ANALOG */
 
 #define IVTV_CS53L32A_I2C_ADDR		0x11
+#define IVTV_M52790_I2C_ADDR		0x48
 #define IVTV_CX25840_I2C_ADDR 		0x44
 #define IVTV_SAA7115_I2C_ADDR 		0x21
 #define IVTV_SAA7127_I2C_ADDR 		0x44
@@ -91,7 +92,8 @@
 #define IVTV_TEA5767_I2C_ADDR		0x60
 #define IVTV_UPD64031A_I2C_ADDR 	0x12
 #define IVTV_UPD64083_I2C_ADDR 		0x5c
-#define IVTV_TDA985X_I2C_ADDR      	0x5b
+#define IVTV_VP27SMPX_I2C_ADDR      	0x5b
+#define IVTV_M52790_I2C_ADDR      	0x48
 
 /* This array should match the IVTV_HW_ defines */
 static const u8 hw_driverids[] = {
@@ -104,18 +106,38 @@ static const u8 hw_driverids[] = {
 	I2C_DRIVERID_CS53L32A,
 	I2C_DRIVERID_TVEEPROM,
 	I2C_DRIVERID_SAA711X,
-	I2C_DRIVERID_TVAUDIO,
 	I2C_DRIVERID_UPD64031A,
 	I2C_DRIVERID_UPD64083,
 	I2C_DRIVERID_SAA717X,
 	I2C_DRIVERID_WM8739,
 	I2C_DRIVERID_VP27SMPX,
+	I2C_DRIVERID_M52790,
+	0 		/* IVTV_HW_GPIO dummy driver ID */
+};
+
+/* This array should match the IVTV_HW_ defines */
+static const u8 hw_addrs[] = {
+	IVTV_CX25840_I2C_ADDR,
+	IVTV_SAA7115_I2C_ADDR,
+	IVTV_SAA7127_I2C_ADDR,
+	IVTV_MSP3400_I2C_ADDR,
+	0,
+	IVTV_WM8775_I2C_ADDR,
+	IVTV_CS53L32A_I2C_ADDR,
+	0,
+	IVTV_SAA7115_I2C_ADDR,
+	IVTV_UPD64031A_I2C_ADDR,
+	IVTV_UPD64083_I2C_ADDR,
+	IVTV_SAA717x_I2C_ADDR,
+	IVTV_WM8739_I2C_ADDR,
+	IVTV_VP27SMPX_I2C_ADDR,
+	IVTV_M52790_I2C_ADDR,
 	0 		/* IVTV_HW_GPIO dummy driver ID */
 };
 
 /* This array should match the IVTV_HW_ defines */
 static const char * const hw_drivernames[] = {
-	"cx2584x",
+	"cx25840",
 	"saa7115",
 	"saa7127",
 	"msp3400",
@@ -123,31 +145,67 @@ static const char * const hw_drivernames[] = {
 	"wm8775",
 	"cs53l32a",
 	"tveeprom",
-	"saa7114",
-	"tvaudio",
+	"saa7115",
 	"upd64031a",
 	"upd64083",
 	"saa717x",
 	"wm8739",
 	"vp27smpx",
+	"m52790",
 	"gpio",
 };
 
-static int attach_inform(struct i2c_client *client)
+int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
 {
-	struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter);
+	struct i2c_board_info info;
+	struct i2c_client *c;
+	u8 id;
 	int i;
 
-	IVTV_DEBUG_I2C("i2c client attach\n");
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (itv->i2c_clients[i] == NULL) {
-			itv->i2c_clients[i] = client;
-			break;
-		}
-	}
+	IVTV_DEBUG_I2C("i2c client register\n");
+	if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
+		return -1;
+	id = hw_driverids[idx];
+	memset(&info, 0, sizeof(info));
+	strcpy(info.driver_name, hw_drivernames[idx]);
+	info.addr = hw_addrs[idx];
+	for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
+
 	if (i == I2C_CLIENTS_MAX) {
-		IVTV_ERR("Insufficient room for new I2C client\n");
+		IVTV_ERR("insufficient room for new I2C client!\n");
+		return -ENOMEM;
 	}
+
+	if (id != I2C_DRIVERID_TUNER) {
+		c = i2c_new_device(&itv->i2c_adap, &info);
+		if (c->driver == NULL)
+			i2c_unregister_device(c);
+		else
+			itv->i2c_clients[i] = c;
+		return itv->i2c_clients[i] ? 0 : -ENODEV;
+	}
+
+	/* special tuner handling */
+	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->radio);
+	if (c && c->driver == NULL)
+		i2c_unregister_device(c);
+	else if (c)
+		itv->i2c_clients[i++] = c;
+	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->demod);
+	if (c && c->driver == NULL)
+		i2c_unregister_device(c);
+	else if (c)
+		itv->i2c_clients[i++] = c;
+	c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->tv);
+	if (c && c->driver == NULL)
+		i2c_unregister_device(c);
+	else if (c)
+		itv->i2c_clients[i++] = c;
+	return 0;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
 	return 0;
 }
 
@@ -475,9 +533,6 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = {
 	.client_register = attach_inform,
 	.client_unregister = detach_inform,
 	.owner = THIS_MODULE,
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
-	.class = I2C_ADAP_CLASS_TV_ANALOG,
-#endif
 };
 
 static void ivtv_setscl_old(void *data, int state)
@@ -525,15 +580,12 @@ static int ivtv_getsda_old(void *data)
 /* template for i2c-bit-algo */
 static struct i2c_adapter ivtv_i2c_adap_template = {
 	.name = "ivtv i2c driver",
-	.id = I2C_HW_B_CX2341X,  	/* algo-bit is OR'd with this */
+	.id = I2C_HW_B_CX2341X,
 	.algo = NULL,                   /* set by i2c-algo-bit */
 	.algo_data = NULL,              /* filled from template */
 	.client_register = attach_inform,
 	.client_unregister = detach_inform,
 	.owner = THIS_MODULE,
-#ifdef I2C_ADAP_CLASS_TV_ANALOG
-	.class = I2C_ADAP_CLASS_TV_ANALOG,
-#endif
 };
 
 static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
@@ -558,12 +610,9 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg
 	IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
 		client = itv->i2c_clients[i];
-		if (client == NULL) {
-			continue;
-		}
-		if (client->driver->command == NULL) {
+		if (client == NULL || client->driver == NULL ||
+		    client->driver->command == NULL)
 			continue;
-		}
 		if (addr == client->addr) {
 			retval = client->driver->command(client, cmd, arg);
 			return retval;
@@ -584,7 +633,7 @@ static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id)
 
 	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
 		client = itv->i2c_clients[i];
-		if (client == NULL)
+		if (client == NULL || client->driver == NULL)
 			continue;
 		if (id == client->driver->id) {
 			retval = client->addr;
@@ -710,6 +759,16 @@ int init_ivtv_i2c(struct ivtv *itv)
 {
 	IVTV_DEBUG_I2C("i2c init\n");
 
+	/* Sanity checks for the I2C hardware arrays. They must be the
+	 * same size and GPIO must be the last entry.
+	 */
+	if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) ||
+	    ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) ||
+	    IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) ||
+	    hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) {
+		IVTV_ERR("Mismatched I2C hardware arrays\n");
+		return -ENODEV;
+	}
 	if (itv->options.newi2c > 0) {
 		memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template,
 		       sizeof(struct i2c_adapter));
@@ -718,9 +777,9 @@ int init_ivtv_i2c(struct ivtv *itv)
 		       sizeof(struct i2c_adapter));
 		memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template,
 		       sizeof(struct i2c_algo_bit_data));
-		itv->i2c_algo.data = itv;
-		itv->i2c_adap.algo_data = &itv->i2c_algo;
 	}
+	itv->i2c_algo.data = itv;
+	itv->i2c_adap.algo_data = &itv->i2c_algo;
 
 	sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d",
 		itv->num);
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
index 987042c09b64..022978cf533d 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.h
+++ b/drivers/media/video/ivtv/ivtv-i2c.h
@@ -33,6 +33,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg);
 int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg);
 int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg);
 void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg);
+int ivtv_i2c_register(struct ivtv *itv, unsigned idx);
 
 /* init + register i2c algo-bit adapter */
 int init_ivtv_i2c(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index fd6826f472e3..edef2a579617 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -372,7 +372,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
 		fmt->fmt.pix.height = itv->main_rect.height;
 		fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 		fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
-		if (itv->output_mode == OUT_UDMA_YUV) {
+		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
 			switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
 			case IVTV_YUV_MODE_INTERLACED:
 				fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
@@ -386,14 +386,13 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
 				break;
 			}
 			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
+			fmt->fmt.pix.bytesperline = 720;
+			fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
+			fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
 			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
 			fmt->fmt.pix.sizeimage =
-				fmt->fmt.pix.height * fmt->fmt.pix.width +
-				fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
-		}
-		else if (itv->output_mode == OUT_YUV ||
-				streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
-				streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+				1080 * ((fmt->fmt.pix.height + 31) & ~31);
+		} else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
 			fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
 			/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
 			fmt->fmt.pix.sizeimage =
@@ -490,6 +489,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
 static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
 		struct v4l2_format *fmt, int set_fmt)
 {
+	struct yuv_playback_info *yi = &itv->yuv_info;
 	struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
 	u16 set;
 
@@ -505,39 +505,52 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
 		r.width = fmt->fmt.pix.width;
 		r.height = fmt->fmt.pix.height;
 		ivtv_get_fmt(itv, streamtype, fmt);
-		if (itv->output_mode != OUT_UDMA_YUV) {
-			/* TODO: would setting the rect also be valid for this mode? */
-			fmt->fmt.pix.width = r.width;
-			fmt->fmt.pix.height = r.height;
-		}
-		if (itv->output_mode == OUT_UDMA_YUV) {
-			/* TODO: add checks for validity */
+		fmt->fmt.pix.width = r.width;
+		fmt->fmt.pix.height = r.height;
+		if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
 			fmt->fmt.pix.field = field;
+			if (fmt->fmt.pix.width < 2)
+				fmt->fmt.pix.width = 2;
+			if (fmt->fmt.pix.width > 720)
+				fmt->fmt.pix.width = 720;
+			if (fmt->fmt.pix.height < 2)
+				fmt->fmt.pix.height = 2;
+			if (fmt->fmt.pix.height > 576)
+				fmt->fmt.pix.height = 576;
 		}
-		if (set_fmt) {
-			if (itv->output_mode == OUT_UDMA_YUV) {
-				switch (field) {
-				case V4L2_FIELD_NONE:
-					itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
-					break;
-				case V4L2_FIELD_ANY:
-					itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO;
-					break;
-				case V4L2_FIELD_INTERLACED_BT:
-					itv->yuv_info.lace_mode =
-						IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
-					break;
-				case V4L2_FIELD_INTERLACED_TB:
-				default:
-					itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED;
-					break;
-				}
-				itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+		if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+			/* Return now if we already have some frame data */
+			if (yi->stream_size)
+				return -EBUSY;
 
-				/* Force update of yuv registers */
-				itv->yuv_info.yuv_forced_update = 1;
-				return 0;
+			yi->v4l2_src_w = r.width;
+			yi->v4l2_src_h = r.height;
+
+			switch (field) {
+			case V4L2_FIELD_NONE:
+				yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
+				break;
+			case V4L2_FIELD_ANY:
+				yi->lace_mode = IVTV_YUV_MODE_AUTO;
+				break;
+			case V4L2_FIELD_INTERLACED_BT:
+				yi->lace_mode =
+				     IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
+				break;
+			case V4L2_FIELD_INTERLACED_TB:
+			default:
+				yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
+				break;
 			}
+			yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
+
+			if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+				itv->dma_data_req_size =
+					   1080 * ((yi->v4l2_src_h + 31) & ~31);
+
+			/* Force update of yuv registers */
+			yi->yuv_forced_update = 1;
+			return 0;
 		}
 		return 0;
 	}
@@ -660,11 +673,8 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
 		chip->ident = V4L2_IDENT_NONE;
 		chip->revision = 0;
 		if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
-			if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
-				struct v4l2_chip_ident *chip = arg;
-
+			if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
 				chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
-			}
 			return 0;
 		}
 		if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
@@ -688,7 +698,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
 			ivtv_reset_ir_gpio(itv);
 		}
 		if (val & 0x02) {
-			itv->video_dec_func(itv, cmd, 0);
+			itv->video_dec_func(itv, cmd, NULL);
 		}
 		break;
 	}
@@ -703,8 +713,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 {
 	struct ivtv_open_id *id = NULL;
 	u32 data[CX2341X_MBOX_MAX_DATA];
+	int streamtype = 0;
 
-	if (filp) id = (struct ivtv_open_id *)filp->private_data;
+	if (filp) {
+		id = (struct ivtv_open_id *)filp->private_data;
+		streamtype = id->type;
+	}
 
 	switch (cmd) {
 	case VIDIOC_G_PRIORITY:
@@ -822,6 +836,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 			cropcap->bounds.height = itv->is_50hz ? 576 : 480;
 			cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
 			cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
+		} else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+			cropcap->bounds.width = itv->yuv_info.osd_full_w;
+			cropcap->bounds.height = itv->yuv_info.osd_full_h;
+			cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
+			cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
 		} else {
 			cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
 			cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
@@ -836,10 +855,15 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 
 		if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
 		    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
-			if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
-				 crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
-				itv->main_rect = crop->c;
+			if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
+				itv->yuv_info.main_rect = crop->c;
 				return 0;
+			} else {
+				if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
+					crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
+					itv->main_rect = crop->c;
+					return 0;
+				}
 			}
 			return -EINVAL;
 		}
@@ -853,7 +877,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 
 		if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
 		    (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
-			crop->c = itv->main_rect;
+			if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
+				crop->c = itv->yuv_info.main_rect;
+			else
+				crop->c = itv->main_rect;
 			return 0;
 		}
 		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -864,7 +891,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 	case VIDIOC_ENUM_FMT: {
 		static struct v4l2_fmtdesc formats[] = {
 			{ 0, 0, 0,
-			  "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
+			  "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
 			  { 0, 0, 0, 0 }
 			},
 			{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
@@ -1043,6 +1070,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
 			itv->main_rect.height = itv->params.height;
 			ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
 				720, itv->main_rect.height, 0, 0);
+			itv->yuv_info.main_rect = itv->main_rect;
+			if (!itv->osd_info) {
+				itv->yuv_info.osd_full_w = 720;
+				itv->yuv_info.osd_full_h =
+						itv->is_out_50hz ? 576 : 480;
+			}
 		}
 		break;
 	}
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index fd1688e4757d..65604dde9726 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -204,7 +204,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
 		s->sg_pending[idx].dst = buf->dma_handle;
 		s->sg_pending[idx].src = offset;
 		s->sg_pending[idx].size = s->buf_size;
-		buf->bytesused = (size < s->buf_size) ? size : s->buf_size;
+		buf->bytesused = min(size, s->buf_size);
 		buf->dma_xfer_cnt = s->dma_xfer_cnt;
 
 		s->q_predma.bytesused += buf->bytesused;
@@ -302,8 +302,11 @@ static void dma_post(struct ivtv_stream *s)
 void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
 {
 	struct ivtv *itv = s->itv;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	u8 frame = yi->draw_frame;
+	struct yuv_frame_info *f = &yi->new_frame_info[frame];
 	struct ivtv_buffer *buf;
-	u32 y_size = itv->params.height * itv->params.width;
+	u32 y_size = 720 * ((f->src_h + 31) & ~31);
 	u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
 	int y_done = 0;
 	int bytes_written = 0;
@@ -311,17 +314,42 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
 	int idx = 0;
 
 	IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
+
+	/* Insert buffer block for YUV if needed */
+	if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) {
+		if (yi->blanking_dmaptr) {
+			s->sg_pending[idx].src = yi->blanking_dmaptr;
+			s->sg_pending[idx].dst = offset;
+			s->sg_pending[idx].size = 720 * 16;
+		}
+		offset += 720 * 16;
+		idx++;
+	}
+
 	list_for_each_entry(buf, &s->q_predma.list, list) {
 		/* YUV UV Offset from Y Buffer */
-		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) {
+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done &&
+				(bytes_written + buf->bytesused) >= y_size) {
+			s->sg_pending[idx].src = buf->dma_handle;
+			s->sg_pending[idx].dst = offset;
+			s->sg_pending[idx].size = y_size - bytes_written;
 			offset = uv_offset;
+			if (s->sg_pending[idx].size != buf->bytesused) {
+				idx++;
+				s->sg_pending[idx].src =
+				  buf->dma_handle + s->sg_pending[idx - 1].size;
+				s->sg_pending[idx].dst = offset;
+				s->sg_pending[idx].size =
+				   buf->bytesused - s->sg_pending[idx - 1].size;
+				offset += s->sg_pending[idx].size;
+			}
 			y_done = 1;
+		} else {
+			s->sg_pending[idx].src = buf->dma_handle;
+			s->sg_pending[idx].dst = offset;
+			s->sg_pending[idx].size = buf->bytesused;
+			offset += buf->bytesused;
 		}
-		s->sg_pending[idx].src = buf->dma_handle;
-		s->sg_pending[idx].dst = offset;
-		s->sg_pending[idx].size = buf->bytesused;
-
-		offset += buf->bytesused;
 		bytes_written += buf->bytesused;
 
 		/* Sync SG buffers */
@@ -408,7 +436,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
 		s_vbi->sg_pending_size = 0;
 		s_vbi->dma_xfer_cnt++;
 		set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
-		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
+		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name);
 	}
 
 	s->dma_xfer_cnt++;
@@ -700,12 +728,15 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
 	ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data);
 
 	if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
-		itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2;
-		itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0];
+		itv->dma_data_req_size =
+				 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31);
+		itv->dma_data_req_offset = data[1];
+		if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0)
+			ivtv_yuv_frame_complete(itv);
 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
 	}
 	else {
-		itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2];
+		itv->dma_data_req_size = min_t(u32, data[2], 0x10000);
 		itv->dma_data_req_offset = data[1];
 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
 	}
@@ -715,6 +746,8 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
 		set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
 	}
 	else {
+		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+			ivtv_yuv_setup_stream_frame(itv);
 		clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
 		ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size);
 		ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0);
@@ -731,24 +764,26 @@ static void ivtv_irq_vsync(struct ivtv *itv)
 	 * one vsync per frame.
 	 */
 	unsigned int frame = read_reg(0x28c0) & 1;
+	struct yuv_playback_info *yi = &itv->yuv_info;
 	int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame);
+	struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
 
 	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
 
-	if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 &&
-		((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) ||
-			(frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) {
+	if (((frame ^ f->sync_field) == 0 &&
+		((itv->last_vsync_field & 1) ^ f->sync_field)) ||
+			(frame != (itv->last_vsync_field & 1) && !f->interlaced)) {
 		int next_dma_frame = last_dma_frame;
 
-		if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) {
-			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
+		if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) {
+			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) {
 				write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
 				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
 				write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
 				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
-				next_dma_frame = (next_dma_frame + 1) & 0x3;
-				atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
-				itv->yuv_info.fields_lapsed = -1;
+				next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
+				atomic_set(&yi->next_dma_frame, next_dma_frame);
+				yi->fields_lapsed = -1;
 			}
 		}
 	}
@@ -781,20 +816,22 @@ static void ivtv_irq_vsync(struct ivtv *itv)
 		}
 
 		/* Check if we need to update the yuv registers */
-		if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) {
-			if (!itv->yuv_info.new_frame_info[last_dma_frame].update)
-				last_dma_frame = (last_dma_frame - 1) & 3;
-
-			if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) {
-				itv->yuv_info.update_frame = last_dma_frame;
-				itv->yuv_info.new_frame_info[last_dma_frame].update = 0;
-				itv->yuv_info.yuv_forced_update = 0;
+		if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) {
+			if (!f->update) {
+				last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS;
+				f = &yi->new_frame_info[last_dma_frame];
+			}
+
+			if (f->src_w) {
+				yi->update_frame = last_dma_frame;
+				f->update = 0;
+				yi->yuv_forced_update = 0;
 				set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
 				set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
 			}
 		}
 
-		itv->yuv_info.fields_lapsed ++;
+		yi->fields_lapsed++;
 	}
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index b05436da7136..13a6c374d2db 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -333,7 +333,7 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[])
 	return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res;
 }
 
-int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
 {
 	return ivtv_api(priv, cmd, in, data);
 }
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
index 71a54eef8fc7..6ef12091e3f3 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.h
+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
@@ -28,6 +28,6 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]);
 int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
 int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
 int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
-int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
 
 #endif
diff --git a/drivers/media/video/ivtv/ivtv-routing.c b/drivers/media/video/ivtv/ivtv-routing.c
index 398bd33033ed..05564919b57f 100644
--- a/drivers/media/video/ivtv/ivtv-routing.c
+++ b/drivers/media/video/ivtv/ivtv-routing.c
@@ -25,6 +25,7 @@
 #include "ivtv-routing.h"
 
 #include <media/msp3400.h>
+#include <media/m52790.h>
 #include <media/upd64031a.h>
 #include <media/upd64083.h>
 
@@ -32,28 +33,26 @@
    settings. */
 void ivtv_audio_set_io(struct ivtv *itv)
 {
+	const struct ivtv_card_audio_input *in;
 	struct v4l2_routing route;
-	u32 audio_input;
-	int mux_input;
 
 	/* Determine which input to use */
-	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
-		audio_input = itv->card->radio_input.audio_input;
-		mux_input = itv->card->radio_input.muxer_input;
-	} else {
-		audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
-		mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
-	}
+	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
+		in = &itv->card->radio_input;
+	else
+		in = &itv->card->audio_inputs[itv->audio_input];
 
 	/* handle muxer chips */
-	route.input = mux_input;
+	route.input = in->muxer_input;
 	route.output = 0;
+	if (itv->card->hw_muxer & IVTV_HW_M52790)
+		route.output = M52790_OUT_STEREO;
 	ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
 
-	route.input = audio_input;
-	if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
+	route.input = in->audio_input;
+	route.output = 0;
+	if (itv->card->hw_audio & IVTV_HW_MSP34XX)
 		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
-	}
 	ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 74fb0e021979..24d98ecf35ad 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -43,7 +43,7 @@
 #include "ivtv-cards.h"
 #include "ivtv-streams.h"
 
-static struct file_operations ivtv_v4l2_enc_fops = {
+static const struct file_operations ivtv_v4l2_enc_fops = {
       .owner = THIS_MODULE,
       .read = ivtv_v4l2_read,
       .write = ivtv_v4l2_write,
@@ -53,7 +53,7 @@ static struct file_operations ivtv_v4l2_enc_fops = {
       .poll = ivtv_v4l2_enc_poll,
 };
 
-static struct file_operations ivtv_v4l2_dec_fops = {
+static const struct file_operations ivtv_v4l2_dec_fops = {
       .owner = THIS_MODULE,
       .read = ivtv_v4l2_read,
       .write = ivtv_v4l2_write,
@@ -572,10 +572,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
 		clear_bit(IVTV_F_I_EOS, &itv->i_flags);
 
 		/* Initialize Digitizer for Capture */
-		itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
+		itv->video_dec_func(itv, VIDIOC_STREAMOFF, NULL);
 		ivtv_msleep_timeout(300, 1);
 		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-		itv->video_dec_func(itv, VIDIOC_STREAMON, 0);
+		itv->video_dec_func(itv, VIDIOC_STREAMON, NULL);
 	}
 
 	/* begin_capture */
@@ -661,27 +661,12 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
 
 	IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
 
-	/* Clear Streamoff */
-	if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
-		/* Initialize Decoder */
-		/* Reprogram Decoder YUV Buffers for YUV */
-		write_reg(yuv_offset[0] >> 4, 0x82c);
-		write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
-		write_reg(yuv_offset[0] >> 4, 0x834);
-		write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
-
-		write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24);
-
-		write_reg_sync(0x00108080, 0x2898);
-		/* Enable YUV decoder output */
-		write_reg_sync(0x01, IVTV_REG_VDM);
-	}
-
 	ivtv_setup_v4l2_decode_stream(s);
 
 	/* set dma size to 65536 bytes */
 	ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
 
+	/* Clear Streamoff */
 	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
 
 	/* Zero out decoder counters */
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index d050de2a7229..0f1d4cc4b4d9 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -22,7 +22,7 @@
 
 #define IVTV_DRIVER_NAME "ivtv"
 #define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 1
+#define IVTV_DRIVER_VERSION_MINOR 2
 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0
 
 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index 9091c4837bbc..85183480a225 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -22,32 +22,37 @@
 #include "ivtv-udma.h"
 #include "ivtv-yuv.h"
 
-const u32 yuv_offset[4] = {
-	IVTV_YUV_BUFFER_OFFSET,
-	IVTV_YUV_BUFFER_OFFSET_1,
-	IVTV_YUV_BUFFER_OFFSET_2,
-	IVTV_YUV_BUFFER_OFFSET_3
+/* YUV buffer offsets */
+const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
+	0x001a8600,
+	0x00240400,
+	0x002d8200,
+	0x00370000,
+	0x00029000,
+	0x000C0E00,
+	0x006B0400,
+	0x00748200
 };
 
 static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
-				 struct ivtv_dma_frame *args)
+				  struct ivtv_dma_frame *args)
 {
 	struct ivtv_dma_page_info y_dma;
 	struct ivtv_dma_page_info uv_dma;
-
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	u8 frame = yi->draw_frame;
+	struct yuv_frame_info *f = &yi->new_frame_info[frame];
 	int i;
 	int y_pages, uv_pages;
-
 	unsigned long y_buffer_offset, uv_buffer_offset;
 	int y_decode_height, uv_decode_height, y_size;
-	int frame = atomic_read(&itv->yuv_info.next_fill_frame);
 
 	y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
 	uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
 
-	y_decode_height = uv_decode_height = args->src.height + args->src.top;
+	y_decode_height = uv_decode_height = f->src_h + f->src_y;
 
-	if (y_decode_height < 512-16)
+	if (f->offset_y)
 		y_buffer_offset += 720 * 16;
 
 	if (y_decode_height & 15)
@@ -60,8 +65,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
 
 	/* Still in USE */
 	if (dma->SG_length || dma->page_count) {
-		IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n",
-				dma->SG_length, dma->page_count);
+		IVTV_DEBUG_WARN
+		    ("prep_user_dma: SG_length %d page_count %d still full?\n",
+		     dma->SG_length, dma->page_count);
 		return -EBUSY;
 	}
 
@@ -77,8 +83,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
 	dma->page_count = y_dma.page_count + uv_dma.page_count;
 
 	if (y_pages + uv_pages != dma->page_count) {
-		IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
-				y_pages + uv_pages, dma->page_count);
+		IVTV_DEBUG_WARN
+		    ("failed to map user pages, returned %d instead of %d\n",
+		     y_pages + uv_pages, dma->page_count);
 
 		for (i = 0; i < dma->page_count; i++) {
 			put_page(dma->map[i]);
@@ -99,16 +106,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
 	dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
 
 	/* Fill SG Array with new values */
-	ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size);
+	ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
 
 	/* If we've offset the y plane, ensure top area is blanked */
-	if (args->src.height + args->src.top < 512-16) {
-		if (itv->yuv_info.blanking_dmaptr) {
-			dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
-			dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
-			dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
-			dma->SG_length++;
-		}
+	if (f->offset_y && yi->blanking_dmaptr) {
+		dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
+		dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
+		dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
+		dma->SG_length++;
 	}
 
 	/* Tag SG Array with Interrupt Bit */
@@ -121,11 +126,11 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
 /* We rely on a table held in the firmware - Quick check. */
 int ivtv_yuv_filter_check(struct ivtv *itv)
 {
-	int i, offset_y, offset_uv;
+	int i, y, uv;
 
-	for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) {
-		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) ||
-		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) {
+	for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
+		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
+		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
 			IVTV_WARN ("YUV filter table not found in firmware.\n");
 			return -1;
 		}
@@ -135,69 +140,67 @@ int ivtv_yuv_filter_check(struct ivtv *itv)
 
 static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
 {
-	int filter_index, filter_line;
+	u32 i, line;
 
 	/* If any filter is -1, then don't update it */
 	if (h_filter > -1) {
-		if (h_filter > 4) h_filter = 4;
-		filter_index = h_filter * 384;
-		filter_line = 0;
-		while (filter_line < 16) {
-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804);
-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c);
-			filter_index += 4;
-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808);
-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820);
-			filter_index += 4;
-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c);
-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824);
-			filter_index += 4;
-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810);
-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828);
-			filter_index += 4;
-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814);
-			write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c);
-			filter_index += 8;
+		if (h_filter > 4)
+			h_filter = 4;
+		i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);
+		for (line = 0; line < 16; line++) {
+			write_reg(read_dec(i), 0x02804);
+			write_reg(read_dec(i), 0x0281c);
+			i += 4;
+			write_reg(read_dec(i), 0x02808);
+			write_reg(read_dec(i), 0x02820);
+			i += 4;
+			write_reg(read_dec(i), 0x0280c);
+			write_reg(read_dec(i), 0x02824);
+			i += 4;
+			write_reg(read_dec(i), 0x02810);
+			write_reg(read_dec(i), 0x02828);
+			i += 4;
+			write_reg(read_dec(i), 0x02814);
+			write_reg(read_dec(i), 0x0282c);
+			i += 8;
 			write_reg(0, 0x02818);
 			write_reg(0, 0x02830);
-			filter_line ++;
 		}
-		IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter);
+		IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter);
 	}
 
 	if (v_filter_1 > -1) {
-		if (v_filter_1 > 4) v_filter_1 = 4;
-		filter_index = v_filter_1 * 192;
-		filter_line = 0;
-		while (filter_line < 16) {
-			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900);
-			filter_index += 4;
-			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904);
-			filter_index += 8;
+		if (v_filter_1 > 4)
+			v_filter_1 = 4;
+		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192);
+		for (line = 0; line < 16; line++) {
+			write_reg(read_dec(i), 0x02900);
+			i += 4;
+			write_reg(read_dec(i), 0x02904);
+			i += 8;
 			write_reg(0, 0x02908);
-			filter_line ++;
 		}
-		IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1);
+		IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1);
 	}
 
 	if (v_filter_2 > -1) {
-		if (v_filter_2 > 4) v_filter_2 = 4;
-		filter_index = v_filter_2 * 192;
-		filter_line = 0;
-		while (filter_line < 16) {
-			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c);
-			filter_index += 4;
-			write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910);
-			filter_index += 8;
+		if (v_filter_2 > 4)
+			v_filter_2 = 4;
+		i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192);
+		for (line = 0; line < 16; line++) {
+			write_reg(read_dec(i), 0x0290c);
+			i += 4;
+			write_reg(read_dec(i), 0x02910);
+			i += 8;
 			write_reg(0, 0x02914);
-			filter_line ++;
 		}
-		IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2);
+		IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2);
 	}
 }
 
-static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window)
+static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f)
 {
+	struct yuv_playback_info *yi = &itv->yuv_info;
 	u32 reg_2834, reg_2838, reg_283c;
 	u32 reg_2844, reg_2854, reg_285c;
 	u32 reg_2864, reg_2874, reg_2890;
@@ -206,18 +209,19 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
 	int h_filter;
 	u32 master_width;
 
-	IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
-			 window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x);
+	IVTV_DEBUG_WARN
+	    ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
+	     f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x);
 
 	/* How wide is the src image */
-	x_cutoff  = window->src_w + window->src_x;
+	x_cutoff = f->src_w + f->src_x;
 
 	/* Set the display width */
-	reg_2834 = window->dst_w;
+	reg_2834 = f->dst_w;
 	reg_2838 = reg_2834;
 
 	/* Set the display position */
-	reg_2890 = window->dst_x;
+	reg_2890 = f->dst_x;
 
 	/* Index into the image horizontally */
 	reg_2870 = 0;
@@ -228,32 +232,31 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
 	   Gradually adjust the offset to avoid the video 'snapping'
 	   left/right if it gets dragged through this region.
 	   Only do this if osd is full width. */
-	if (window->vis_w == 720) {
-		if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){
-			reg_2870 = 10 - (window->tru_x - window->pan_x) / 4;
-		}
-		else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) {
-			reg_2870 = (10 + (window->tru_x - window->pan_x) / 2);
-		}
+	if (f->vis_w == 720) {
+		if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680))
+			reg_2870 = 10 - (f->tru_x - f->pan_x) / 4;
+		else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660))
+			reg_2870 = (10 + (f->tru_x - f->pan_x) / 2);
 
-		if (window->dst_w >= window->src_w)
+		if (f->dst_w >= f->src_w)
 			reg_2870 = reg_2870 << 16 | reg_2870;
 		else
 			reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
 	}
 
-	if (window->dst_w < window->src_w)
+	if (f->dst_w < f->src_w)
 		reg_2870 = 0x000d000e - reg_2870;
 	else
 		reg_2870 = 0x0012000e - reg_2870;
 
 	/* We're also using 2870 to shift the image left (src_x & negative dst_x) */
-	reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19;
+	reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19;
 
-	if (window->dst_w >= window->src_w) {
+	if (f->dst_w >= f->src_w) {
 		x_cutoff &= ~1;
-		master_width = (window->src_w * 0x00200000) / (window->dst_w);
-		if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++;
+		master_width = (f->src_w * 0x00200000) / (f->dst_w);
+		if (master_width * f->dst_w != f->src_w * 0x00200000)
+			master_width++;
 		reg_2834 = (reg_2834 << 16) | x_cutoff;
 		reg_2838 = (reg_2838 << 16) | x_cutoff;
 		reg_283c = master_width >> 2;
@@ -264,17 +267,17 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
 
 		/* We also need to factor in the scaling
 		   (src_w - dst_w) / (src_w / 4) */
-		if (window->dst_w > window->src_w)
-			reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14);
+		if (f->dst_w > f->src_w)
+			reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14);
 		else
 			reg_2870_base = 0;
 
 		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
 		reg_2874 = 0;
-	}
-	else if (window->dst_w < window->src_w / 2) {
-		master_width = (window->src_w * 0x00080000) / window->dst_w;
-		if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++;
+	} else if (f->dst_w < f->src_w / 2) {
+		master_width = (f->src_w * 0x00080000) / f->dst_w;
+		if (master_width * f->dst_w != f->src_w * 0x00080000)
+			master_width++;
 		reg_2834 = (reg_2834 << 16) | x_cutoff;
 		reg_2838 = (reg_2838 << 16) | x_cutoff;
 		reg_283c = master_width >> 2;
@@ -282,13 +285,13 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
 		reg_2854 = master_width;
 		reg_285c = master_width >> 1;
 		reg_2864 = master_width >> 1;
-		reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset);
-		reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16;
+		reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset;
+		reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16;
 		reg_2874 = 0x00000012;
-	}
-	else {
-		master_width = (window->src_w * 0x00100000) / window->dst_w;
-		if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++;
+	} else {
+		master_width = (f->src_w * 0x00100000) / f->dst_w;
+		if (master_width * f->dst_w != f->src_w * 0x00100000)
+			master_width++;
 		reg_2834 = (reg_2834 << 16) | x_cutoff;
 		reg_2838 = (reg_2838 << 16) | x_cutoff;
 		reg_283c = master_width >> 2;
@@ -296,62 +299,70 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *
 		reg_2854 = master_width;
 		reg_285c = master_width >> 1;
 		reg_2864 = master_width >> 1;
-		reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1);
-		reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16;
+		reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1;
+		reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16;
 		reg_2874 = 0x00000001;
 	}
 
 	/* Select the horizontal filter */
-	if (window->src_w == window->dst_w) {
+	if (f->src_w == f->dst_w) {
 		/* An exact size match uses filter 0 */
 		h_filter = 0;
-	}
-	else {
+	} else {
 		/* Figure out which filter to use */
-		h_filter = ((window->src_w << 16) / window->dst_w) >> 15;
+		h_filter = ((f->src_w << 16) / f->dst_w) >> 15;
 		h_filter = (h_filter >> 1) + (h_filter & 1);
 		/* Only an exact size match can use filter 0 */
-		if (h_filter == 0) h_filter = 1;
+		h_filter += !h_filter;
 	}
 
 	write_reg(reg_2834, 0x02834);
 	write_reg(reg_2838, 0x02838);
-	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838);
+	IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",
+		       yi->reg_2834, reg_2834, yi->reg_2838, reg_2838);
 
 	write_reg(reg_283c, 0x0283c);
 	write_reg(reg_2844, 0x02844);
 
-	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844);
+	IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",
+		       yi->reg_283c, reg_283c, yi->reg_2844, reg_2844);
 
 	write_reg(0x00080514, 0x02840);
 	write_reg(0x00100514, 0x02848);
-	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514);
+	IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",
+		       yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514);
 
 	write_reg(reg_2854, 0x02854);
-	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854);
+	IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",
+		       yi->reg_2854, reg_2854);
 
 	write_reg(reg_285c, 0x0285c);
 	write_reg(reg_2864, 0x02864);
-	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864);
+	IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",
+		       yi->reg_285c, reg_285c, yi->reg_2864, reg_2864);
 
 	write_reg(reg_2874, 0x02874);
-	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874);
+	IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",
+		       yi->reg_2874, reg_2874);
 
 	write_reg(reg_2870, 0x02870);
-	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870);
+	IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",
+		       yi->reg_2870, reg_2870);
 
-	write_reg( reg_2890,0x02890);
-	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890);
+	write_reg(reg_2890, 0x02890);
+	IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",
+		       yi->reg_2890, reg_2890);
 
 	/* Only update the filter if we really need to */
-	if (h_filter != itv->yuv_info.h_filter) {
-		ivtv_yuv_filter (itv,h_filter,-1,-1);
-		itv->yuv_info.h_filter = h_filter;
+	if (h_filter != yi->h_filter) {
+		ivtv_yuv_filter(itv, h_filter, -1, -1);
+		yi->h_filter = h_filter;
 	}
 }
 
-static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window)
+static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
 {
+	struct yuv_playback_info *yi = &itv->yuv_info;
 	u32 master_height;
 	u32 reg_2918, reg_291c, reg_2920, reg_2928;
 	u32 reg_2930, reg_2934, reg_293c;
@@ -359,69 +370,59 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
 	u32 reg_2950, reg_2954, reg_2958, reg_295c;
 	u32 reg_2960, reg_2964, reg_2968, reg_296c;
 	u32 reg_289c;
-	u32 src_y_major_y, src_y_minor_y;
-	u32 src_y_major_uv, src_y_minor_uv;
+	u32 src_major_y, src_minor_y;
+	u32 src_major_uv, src_minor_uv;
 	u32 reg_2964_base, reg_2968_base;
 	int v_filter_1, v_filter_2;
 
-	IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
-		window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y);
+	IVTV_DEBUG_WARN
+	    ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
+	     f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y);
 
 	/* What scaling mode is being used... */
-	if (window->interlaced_y) {
-		IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n");
-	}
-	else {
-		IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n");
-	}
+	IVTV_DEBUG_YUV("Scaling mode Y: %s\n",
+		       f->interlaced_y ? "Interlaced" : "Progressive");
 
-	if (window->interlaced_uv) {
-		IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n");
-	}
-	else {
-		IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n");
-	}
+	IVTV_DEBUG_YUV("Scaling mode UV: %s\n",
+		       f->interlaced_uv ? "Interlaced" : "Progressive");
 
 	/* What is the source video being treated as... */
-	if (itv->yuv_info.frame_interlaced) {
-		IVTV_DEBUG_WARN("Source video: Interlaced\n");
-	}
-	else {
-		IVTV_DEBUG_WARN("Source video: Non-interlaced\n");
-	}
+	IVTV_DEBUG_WARN("Source video: %s\n",
+			f->interlaced ? "Interlaced" : "Progressive");
 
 	/* We offset into the image using two different index methods, so split
 	   the y source coord into two parts. */
-	if (window->src_y < 8) {
-		src_y_minor_uv = window->src_y;
-		src_y_major_uv = 0;
-	}
-	else {
-		src_y_minor_uv = 8;
-		src_y_major_uv = window->src_y - 8;
+	if (f->src_y < 8) {
+		src_minor_uv = f->src_y;
+		src_major_uv = 0;
+	} else {
+		src_minor_uv = 8;
+		src_major_uv = f->src_y - 8;
 	}
 
-	src_y_minor_y = src_y_minor_uv;
-	src_y_major_y = src_y_major_uv;
+	src_minor_y = src_minor_uv;
+	src_major_y = src_major_uv;
 
-	if (window->offset_y) src_y_minor_y += 16;
+	if (f->offset_y)
+		src_minor_y += 16;
 
-	if (window->interlaced_y)
-		reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y);
+	if (f->interlaced_y)
+		reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y);
 	else
-		reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1);
+		reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1);
 
-	if (window->interlaced_uv)
-		reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1);
+	if (f->interlaced_uv)
+		reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1);
 	else
-		reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv);
+		reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv);
 
-	reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14;
-	reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14;
+	reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14;
+	reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14;
 
-	if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) {
-		master_height = (window->src_h * 0x00400000) / window->dst_h;
-		if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++;
+	if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) {
+		master_height = (f->src_h * 0x00400000) / f->dst_h;
+		if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2)
+			master_height++;
 		reg_2920 = master_height >> 2;
 		reg_2928 = master_height >> 3;
 		reg_2930 = master_height;
@@ -429,45 +430,42 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
 		reg_2964_base >>= 3;
 		reg_2968_base >>= 3;
 		reg_296c = 0x00000000;
-	}
-	else if (window->dst_h >= window->src_h) {
-		master_height = (window->src_h * 0x00400000) / window->dst_h;
+	} else if (f->dst_h >= f->src_h) {
+		master_height = (f->src_h * 0x00400000) / f->dst_h;
 		master_height = (master_height >> 1) + (master_height & 1);
 		reg_2920 = master_height >> 2;
 		reg_2928 = master_height >> 2;
 		reg_2930 = master_height;
 		reg_2940 = master_height >> 1;
 		reg_296c = 0x00000000;
-		if (window->interlaced_y) {
+		if (f->interlaced_y) {
 			reg_2964_base >>= 3;
-		}
-		else {
-			reg_296c ++;
+		} else {
+			reg_296c++;
 			reg_2964_base >>= 2;
 		}
-		if (window->interlaced_uv) reg_2928 >>= 1;
+		if (f->interlaced_uv)
+			reg_2928 >>= 1;
 		reg_2968_base >>= 3;
-	}
-	else if (window->dst_h >= window->src_h / 2) {
-		master_height = (window->src_h * 0x00200000) / window->dst_h;
+	} else if (f->dst_h >= f->src_h / 2) {
+		master_height = (f->src_h * 0x00200000) / f->dst_h;
 		master_height = (master_height >> 1) + (master_height & 1);
 		reg_2920 = master_height >> 2;
 		reg_2928 = master_height >> 2;
 		reg_2930 = master_height;
 		reg_2940 = master_height;
 		reg_296c = 0x00000101;
-		if (window->interlaced_y) {
+		if (f->interlaced_y) {
 			reg_2964_base >>= 2;
-		}
-		else {
-			reg_296c ++;
+		} else {
+			reg_296c++;
 			reg_2964_base >>= 1;
 		}
-		if (window->interlaced_uv) reg_2928 >>= 1;
+		if (f->interlaced_uv)
+			reg_2928 >>= 1;
 		reg_2968_base >>= 2;
-	}
-	else {
-		master_height = (window->src_h * 0x00100000) / window->dst_h;
+	} else {
+		master_height = (f->src_h * 0x00100000) / f->dst_h;
 		master_height = (master_height >> 1) + (master_height & 1);
 		reg_2920 = master_height >> 2;
 		reg_2928 = master_height >> 2;
@@ -480,13 +478,12 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
 
 	/* FIXME These registers change depending on scaled / unscaled output
 	   We really need to work out what they should be */
-	if (window->src_h == window->dst_h){
+	if (f->src_h == f->dst_h) {
 		reg_2934 = 0x00020000;
 		reg_293c = 0x00100000;
 		reg_2944 = 0x00040000;
 		reg_294c = 0x000b0000;
-	}
-	else {
+	} else {
 		reg_2934 = 0x00000FF0;
 		reg_293c = 0x00000FF0;
 		reg_2944 = 0x00000FF0;
@@ -494,34 +491,36 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
 	}
 
 	/* The first line to be displayed */
-	reg_2950 = 0x00010000 + src_y_major_y;
-	if (window->interlaced_y) reg_2950 += 0x00010000;
+	reg_2950 = 0x00010000 + src_major_y;
+	if (f->interlaced_y)
+		reg_2950 += 0x00010000;
 	reg_2954 = reg_2950 + 1;
 
-	reg_2958 = 0x00010000 + (src_y_major_y >> 1);
-	if (window->interlaced_uv) reg_2958 += 0x00010000;
+	reg_2958 = 0x00010000 + (src_major_y >> 1);
+	if (f->interlaced_uv)
+		reg_2958 += 0x00010000;
 	reg_295c = reg_2958 + 1;
 
-	if (itv->yuv_info.decode_height == 480)
+	if (yi->decode_height == 480)
 		reg_289c = 0x011e0017;
 	else
 		reg_289c = 0x01500017;
 
-	if (window->dst_y < 0)
-		reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1);
+	if (f->dst_y < 0)
+		reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1);
 	else
-		reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1);
+		reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1);
 
 	/* How much of the source to decode.
 	   Take into account the source offset */
-	reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) |
-			((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15);
+	reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) |
+		(((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15);
 
 	/* Calculate correct value for register 2964 */
-	if (window->src_h == window->dst_h)
+	if (f->src_h == f->dst_h) {
 		reg_2964 = 1;
-	else {
-		reg_2964 = 2 + ((window->dst_h << 1) / window->src_h);
+	} else {
+		reg_2964 = 2 + ((f->dst_h << 1) / f->src_h);
 		reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
 	}
 	reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
@@ -536,283 +535,246 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
 	/* Deviate further from what it should be. I find the flicker headache
 	   inducing so try to reduce it slightly. Leave 2968 as-is otherwise
 	   colours foul. */
-	if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h))
-		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2);
+	if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h))
+		reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2);
 
-	if (!window->interlaced_y) reg_2964 -= 0x00010001;
-	if (!window->interlaced_uv) reg_2968 -= 0x00010001;
+	if (!f->interlaced_y)
+		reg_2964 -= 0x00010001;
+	if (!f->interlaced_uv)
+		reg_2968 -= 0x00010001;
 
 	reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
 	reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
 
 	/* Select the vertical filter */
-	if (window->src_h == window->dst_h) {
+	if (f->src_h == f->dst_h) {
 		/* An exact size match uses filter 0/1 */
 		v_filter_1 = 0;
 		v_filter_2 = 1;
-	}
-	else {
+	} else {
 		/* Figure out which filter to use */
-		v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15;
+		v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15;
 		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
 		/* Only an exact size match can use filter 0 */
-		if (v_filter_1 == 0) v_filter_1 = 1;
+		v_filter_1 += !v_filter_1;
 		v_filter_2 = v_filter_1;
 	}
 
 	write_reg(reg_2934, 0x02934);
 	write_reg(reg_293c, 0x0293c);
-	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c);
+	IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",
+		       yi->reg_2934, reg_2934, yi->reg_293c, reg_293c);
 	write_reg(reg_2944, 0x02944);
 	write_reg(reg_294c, 0x0294c);
-	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c);
+	IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",
+		       yi->reg_2944, reg_2944, yi->reg_294c, reg_294c);
 
 	/* Ensure 2970 is 0 (does it ever change ?) */
 /*	write_reg(0,0x02970); */
-/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */
+/*	IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */
 
 	write_reg(reg_2930, 0x02938);
 	write_reg(reg_2930, 0x02930);
-	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930);
+	IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",
+		       yi->reg_2930, reg_2930, yi->reg_2938, reg_2930);
 
 	write_reg(reg_2928, 0x02928);
-	write_reg(reg_2928+0x514, 0x0292C);
-	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514);
+	write_reg(reg_2928 + 0x514, 0x0292C);
+	IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",
+		       yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514);
 
 	write_reg(reg_2920, 0x02920);
-	write_reg(reg_2920+0x514, 0x02924);
-	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920);
+	write_reg(reg_2920 + 0x514, 0x02924);
+	IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",
+		       yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514);
 
-	write_reg (reg_2918,0x02918);
-	write_reg (reg_291c,0x0291C);
-	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c);
+	write_reg(reg_2918, 0x02918);
+	write_reg(reg_291c, 0x0291C);
+	IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",
+		       yi->reg_2918, reg_2918, yi->reg_291c, reg_291c);
 
 	write_reg(reg_296c, 0x0296c);
-	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
+	IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",
+		       yi->reg_296c, reg_296c);
 
 	write_reg(reg_2940, 0x02948);
 	write_reg(reg_2940, 0x02940);
-	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940);
+	IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",
+		       yi->reg_2940, reg_2940, yi->reg_2948, reg_2940);
 
 	write_reg(reg_2950, 0x02950);
 	write_reg(reg_2954, 0x02954);
-	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954);
+	IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",
+		       yi->reg_2950, reg_2950, yi->reg_2954, reg_2954);
 
 	write_reg(reg_2958, 0x02958);
 	write_reg(reg_295c, 0x0295C);
-	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c);
+	IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",
+		       yi->reg_2958, reg_2958, yi->reg_295c, reg_295c);
 
 	write_reg(reg_2960, 0x02960);
-	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
+	IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",
+		       yi->reg_2960, reg_2960);
 
 	write_reg(reg_2964, 0x02964);
 	write_reg(reg_2968, 0x02968);
-	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968);
+	IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",
+		       yi->reg_2964, reg_2964, yi->reg_2968, reg_2968);
 
-	write_reg( reg_289c,0x0289c);
-	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
+	write_reg(reg_289c, 0x0289c);
+	IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",
+		       yi->reg_289c, reg_289c);
 
 	/* Only update filter 1 if we really need to */
-	if (v_filter_1 != itv->yuv_info.v_filter_1) {
-		ivtv_yuv_filter (itv,-1,v_filter_1,-1);
-		itv->yuv_info.v_filter_1 = v_filter_1;
+	if (v_filter_1 != yi->v_filter_1) {
+		ivtv_yuv_filter(itv, -1, v_filter_1, -1);
+		yi->v_filter_1 = v_filter_1;
 	}
 
 	/* Only update filter 2 if we really need to */
-	if (v_filter_2 != itv->yuv_info.v_filter_2) {
-		ivtv_yuv_filter (itv,-1,-1,v_filter_2);
-		itv->yuv_info.v_filter_2 = v_filter_2;
+	if (v_filter_2 != yi->v_filter_2) {
+		ivtv_yuv_filter(itv, -1, -1, v_filter_2);
+		yi->v_filter_2 = v_filter_2;
 	}
-
 }
 
 /* Modify the supplied coordinate information to fit the visible osd area */
-static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window)
+static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
 {
-	int osd_crop, lace_threshold;
+	struct yuv_frame_info *of = &itv->yuv_info.old_frame_info;
+	int osd_crop;
 	u32 osd_scale;
 	u32 yuv_update = 0;
 
-	lace_threshold = itv->yuv_info.lace_threshold;
-	if (lace_threshold < 0)
-		lace_threshold = itv->yuv_info.decode_height - 1;
-
-	/* Work out the lace settings */
-	switch (itv->yuv_info.lace_mode) {
-		case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
-			itv->yuv_info.frame_interlaced = 0;
-			if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021))
-				window->interlaced_y = 0;
-			else
-				window->interlaced_y = 1;
-
-			if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
-				window->interlaced_uv = 0;
-			else
-				window->interlaced_uv = 1;
-			break;
-
-		case IVTV_YUV_MODE_AUTO:
-			if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
-				itv->yuv_info.frame_interlaced = 0;
-				if ((window->tru_h < 512) ||
-				  (window->tru_h > 576 && window->tru_h < 1021) ||
-				  (window->tru_w > 720 && window->tru_h < 1021))
-					window->interlaced_y = 0;
-				else
-					window->interlaced_y = 1;
-
-				if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
-					window->interlaced_uv = 0;
-				else
-					window->interlaced_uv = 1;
-			}
-			else {
-				itv->yuv_info.frame_interlaced = 1;
-				window->interlaced_y = 1;
-				window->interlaced_uv = 1;
-			}
-			break;
-
-			case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
-		default:
-			itv->yuv_info.frame_interlaced = 1;
-			window->interlaced_y = 1;
-			window->interlaced_uv = 1;
-			break;
-	}
-
 	/* Sorry, but no negative coords for src */
-	if (window->src_x < 0) window->src_x = 0;
-	if (window->src_y < 0) window->src_y = 0;
+	if (f->src_x < 0)
+		f->src_x = 0;
+	if (f->src_y < 0)
+		f->src_y = 0;
 
 	/* Can only reduce width down to 1/4 original size */
-	if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) {
-		window->src_x += osd_crop / 2;
-		window->src_w = (window->src_w - osd_crop) & ~3;
-		window->dst_w = window->src_w / 4;
-		window->dst_w += window->dst_w & 1;
+	if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) {
+		f->src_x += osd_crop / 2;
+		f->src_w = (f->src_w - osd_crop) & ~3;
+		f->dst_w = f->src_w / 4;
+		f->dst_w += f->dst_w & 1;
 	}
 
 	/* Can only reduce height down to 1/4 original size */
-	if (window->src_h / window->dst_h >= 2) {
-		/* Overflow may be because we're running progressive, so force mode switch */
-		window->interlaced_y = 1;
+	if (f->src_h / f->dst_h >= 2) {
+		/* Overflow may be because we're running progressive,
+		   so force mode switch */
+		f->interlaced_y = 1;
 		/* Make sure we're still within limits for interlace */
-		if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) {
+		if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) {
 			/* If we reach here we'll have to force the height. */
-			window->src_y += osd_crop / 2;
-			window->src_h = (window->src_h - osd_crop) & ~3;
-			window->dst_h = window->src_h / 4;
-			window->dst_h += window->dst_h & 1;
+			f->src_y += osd_crop / 2;
+			f->src_h = (f->src_h - osd_crop) & ~3;
+			f->dst_h = f->src_h / 4;
+			f->dst_h += f->dst_h & 1;
 		}
 	}
 
 	/* If there's nothing to safe to display, we may as well stop now */
-	if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
+	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
+	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
 		return IVTV_YUV_UPDATE_INVALID;
 	}
 
 	/* Ensure video remains inside OSD area */
-	osd_scale = (window->src_h << 16) / window->dst_h;
+	osd_scale = (f->src_h << 16) / f->dst_h;
 
-	if ((osd_crop = window->pan_y - window->dst_y) > 0) {
+	if ((osd_crop = f->pan_y - f->dst_y) > 0) {
 		/* Falls off the upper edge - crop */
-		window->src_y += (osd_scale * osd_crop) >> 16;
-		window->src_h -= (osd_scale * osd_crop) >> 16;
-		window->dst_h -= osd_crop;
-		window->dst_y = 0;
-	}
-	else {
-		window->dst_y -= window->pan_y;
+		f->src_y += (osd_scale * osd_crop) >> 16;
+		f->src_h -= (osd_scale * osd_crop) >> 16;
+		f->dst_h -= osd_crop;
+		f->dst_y = 0;
+	} else {
+		f->dst_y -= f->pan_y;
 	}
 
-	if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) {
+	if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) {
 		/* Falls off the lower edge - crop */
-		window->dst_h -= osd_crop;
-		window->src_h -= (osd_scale * osd_crop) >> 16;
+		f->dst_h -= osd_crop;
+		f->src_h -= (osd_scale * osd_crop) >> 16;
 	}
 
-	osd_scale = (window->src_w << 16) / window->dst_w;
+	osd_scale = (f->src_w << 16) / f->dst_w;
 
-	if ((osd_crop = window->pan_x - window->dst_x) > 0) {
+	if ((osd_crop = f->pan_x - f->dst_x) > 0) {
 		/* Fall off the left edge - crop */
-		window->src_x += (osd_scale * osd_crop) >> 16;
-		window->src_w -= (osd_scale * osd_crop) >> 16;
-		window->dst_w -= osd_crop;
-		window->dst_x = 0;
-	}
-	else {
-		window->dst_x -= window->pan_x;
+		f->src_x += (osd_scale * osd_crop) >> 16;
+		f->src_w -= (osd_scale * osd_crop) >> 16;
+		f->dst_w -= osd_crop;
+		f->dst_x = 0;
+	} else {
+		f->dst_x -= f->pan_x;
 	}
 
-	if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) {
+	if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) {
 		/* Falls off the right edge - crop */
-		window->dst_w -= osd_crop;
-		window->src_w -= (osd_scale * osd_crop) >> 16;
+		f->dst_w -= osd_crop;
+		f->src_w -= (osd_scale * osd_crop) >> 16;
 	}
 
 	/* The OSD can be moved. Track to it */
-	window->dst_x += itv->yuv_info.osd_x_offset;
-	window->dst_y += itv->yuv_info.osd_y_offset;
+	f->dst_x += itv->yuv_info.osd_x_offset;
+	f->dst_y += itv->yuv_info.osd_y_offset;
 
 	/* Width & height for both src & dst must be even.
 	   Same for coordinates. */
-	window->dst_w &= ~1;
-	window->dst_x &= ~1;
+	f->dst_w &= ~1;
+	f->dst_x &= ~1;
 
-	window->src_w += window->src_x & 1;
-	window->src_x &= ~1;
+	f->src_w += f->src_x & 1;
+	f->src_x &= ~1;
 
-	window->src_w &= ~1;
-	window->dst_w &= ~1;
+	f->src_w &= ~1;
+	f->dst_w &= ~1;
 
-	window->dst_h &= ~1;
-	window->dst_y &= ~1;
+	f->dst_h &= ~1;
+	f->dst_y &= ~1;
 
-	window->src_h += window->src_y & 1;
-	window->src_y &= ~1;
+	f->src_h += f->src_y & 1;
+	f->src_y &= ~1;
 
-	window->src_h &= ~1;
-	window->dst_h &= ~1;
+	f->src_h &= ~1;
+	f->dst_h &= ~1;
 
-	/* Due to rounding, we may have reduced the output size to <1/4 of the source
-	   Check again, but this time just resize. Don't change source coordinates */
-	if (window->dst_w < window->src_w / 4) {
-		window->src_w &= ~3;
-		window->dst_w = window->src_w / 4;
-		window->dst_w += window->dst_w & 1;
+	/* Due to rounding, we may have reduced the output size to <1/4 of
+	   the source. Check again, but this time just resize. Don't change
+	   source coordinates */
+	if (f->dst_w < f->src_w / 4) {
+		f->src_w &= ~3;
+		f->dst_w = f->src_w / 4;
+		f->dst_w += f->dst_w & 1;
 	}
-	if (window->dst_h < window->src_h / 4) {
-		window->src_h &= ~3;
-		window->dst_h = window->src_h / 4;
-		window->dst_h += window->dst_h & 1;
+	if (f->dst_h < f->src_h / 4) {
+		f->src_h &= ~3;
+		f->dst_h = f->src_h / 4;
+		f->dst_h += f->dst_h & 1;
 	}
 
 	/* Check again. If there's nothing to safe to display, stop now */
-	if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
+	if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 ||
+	    (int)f->src_w <= 2 || (int)f->src_h <= 2) {
 		return IVTV_YUV_UPDATE_INVALID;
 	}
 
 	/* Both x offset & width are linked, so they have to be done together */
-	if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) ||
-	    (itv->yuv_info.old_frame_info.src_w != window->src_w) ||
-	    (itv->yuv_info.old_frame_info.dst_x != window->dst_x) ||
-	    (itv->yuv_info.old_frame_info.src_x != window->src_x) ||
-	    (itv->yuv_info.old_frame_info.pan_x != window->pan_x) ||
-	    (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) {
+	if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) ||
+	    (of->dst_x != f->dst_x) || (of->src_x != f->src_x) ||
+	    (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) {
 		yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
 	}
 
-	if ((itv->yuv_info.old_frame_info.src_h != window->src_h) ||
-	    (itv->yuv_info.old_frame_info.dst_h != window->dst_h) ||
-	    (itv->yuv_info.old_frame_info.dst_y != window->dst_y) ||
-	    (itv->yuv_info.old_frame_info.src_y != window->src_y) ||
-	    (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
-	    (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
-	    (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
-	    (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
-	    (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
+	if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) ||
+	    (of->dst_y != f->dst_y) || (of->src_y != f->src_y) ||
+	    (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) ||
+	    (of->lace_mode != f->lace_mode) ||
+	    (of->interlaced_y != f->interlaced_y) ||
+	    (of->interlaced_uv != f->interlaced_uv)) {
 		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
 	}
 
@@ -820,24 +782,24 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
 }
 
 /* Update the scaling register to the requested value */
-void ivtv_yuv_work_handler (struct ivtv *itv)
+void ivtv_yuv_work_handler(struct ivtv *itv)
 {
-	struct yuv_frame_info window;
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	struct yuv_frame_info f;
+	int frame = yi->update_frame;
 	u32 yuv_update;
 
-	int frame = itv->yuv_info.update_frame;
-
-/*	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
-	memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));
+	IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
+	f = yi->new_frame_info[frame];
 
 	/* Update the osd pan info */
-	window.pan_x = itv->yuv_info.osd_x_pan;
-	window.pan_y = itv->yuv_info.osd_y_pan;
-	window.vis_w = itv->yuv_info.osd_vis_w;
-	window.vis_h = itv->yuv_info.osd_vis_h;
+	f.pan_x = yi->osd_x_pan;
+	f.pan_y = yi->osd_y_pan;
+	f.vis_w = yi->osd_vis_w;
+	f.vis_h = yi->osd_vis_h;
 
 	/* Calculate the display window coordinates. Exit if nothing left */
-	if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
+	if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
 		return;
 
 	if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
@@ -846,16 +808,15 @@ void ivtv_yuv_work_handler (struct ivtv *itv)
 		write_reg(0x00108080, 0x2898);
 
 		if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
-			ivtv_yuv_handle_horizontal(itv, &window);
+			ivtv_yuv_handle_horizontal(itv, &f);
 
 		if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
-			ivtv_yuv_handle_vertical(itv, &window);
+			ivtv_yuv_handle_vertical(itv, &f);
 	}
-
-	memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
+	yi->old_frame_info = f;
 }
 
-static void ivtv_yuv_init (struct ivtv *itv)
+static void ivtv_yuv_init(struct ivtv *itv)
 {
 	struct yuv_playback_info *yi = &itv->yuv_info;
 
@@ -924,25 +885,23 @@ static void ivtv_yuv_init (struct ivtv *itv)
 		if (!yi->osd_vis_w)
 			yi->osd_vis_w = 720 - yi->osd_x_offset;
 
-		if (!yi->osd_vis_h)
+		if (!yi->osd_vis_h) {
 			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
-		else {
+		} else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
 			/* If output video standard has changed, requested height may
-			not be legal */
-			if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
-				IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
-						yi->osd_vis_h + yi->osd_y_offset,
-						yi->decode_height);
-				yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
-			}
+			   not be legal */
+			IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
+					yi->osd_vis_h + yi->osd_y_offset,
+					yi->decode_height);
+			yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
 		}
 	}
 
 	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
-	yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL);
-	if (yi->blanking_ptr)
+	yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL);
+	if (yi->blanking_ptr) {
 		yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
-	else {
+	} else {
 		yi->blanking_dmaptr = 0;
 		IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
 	}
@@ -954,77 +913,140 @@ static void ivtv_yuv_init (struct ivtv *itv)
 	atomic_set(&yi->next_dma_frame, 0);
 }
 
-int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+/* Get next available yuv buffer on PVR350 */
+void ivtv_yuv_next_free(struct ivtv *itv)
 {
-	DEFINE_WAIT(wait);
-	int rc = 0;
-	int got_sig = 0;
-	int frame, next_fill_frame, last_fill_frame;
-	int register_update = 0;
+	int draw, display;
+	struct yuv_playback_info *yi = &itv->yuv_info;
 
-	IVTV_DEBUG_INFO("yuv_prep_frame\n");
+	if (atomic_read(&yi->next_dma_frame) == -1)
+		ivtv_yuv_init(itv);
 
-	if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv);
+	draw = atomic_read(&yi->next_fill_frame);
+	display = atomic_read(&yi->next_dma_frame);
 
-	frame = atomic_read(&itv->yuv_info.next_fill_frame);
-	next_fill_frame = (frame + 1) & 0x3;
-	last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;
+	if (display > draw)
+		display -= IVTV_YUV_BUFFERS;
 
-	if (next_fill_frame != last_fill_frame && last_fill_frame != frame) {
-		/* Buffers are full - Overwrite the last frame */
-		next_fill_frame = frame;
-		frame = (frame - 1) & 3;
-		register_update = itv->yuv_info.new_frame_info[frame].update;
-	}
+	if (draw - display >= yi->max_frames_buffered)
+		draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
+	else
+		yi->new_frame_info[draw].update = 0;
+
+	yi->draw_frame = draw;
+}
+
+/* Set up frame according to ivtv_dma_frame parameters */
+void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	u8 frame = yi->draw_frame;
+	u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS;
+	struct yuv_frame_info *nf = &yi->new_frame_info[frame];
+	struct yuv_frame_info *of = &yi->new_frame_info[last_frame];
+	int lace_threshold = yi->lace_threshold;
+
+	/* Preserve old update flag in case we're overwriting a queued frame */
+	int update = nf->update;
 
 	/* Take a snapshot of the yuv coordinate information */
-	itv->yuv_info.new_frame_info[frame].src_x = args->src.left;
-	itv->yuv_info.new_frame_info[frame].src_y = args->src.top;
-	itv->yuv_info.new_frame_info[frame].src_w = args->src.width;
-	itv->yuv_info.new_frame_info[frame].src_h = args->src.height;
-	itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left;
-	itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top;
-	itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width;
-	itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height;
-	itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left;
-	itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
-	itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
-
-	/* Snapshot field order */
-	itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
+	nf->src_x = args->src.left;
+	nf->src_y = args->src.top;
+	nf->src_w = args->src.width;
+	nf->src_h = args->src.height;
+	nf->dst_x = args->dst.left;
+	nf->dst_y = args->dst.top;
+	nf->dst_w = args->dst.width;
+	nf->dst_h = args->dst.height;
+	nf->tru_x = args->dst.left;
+	nf->tru_w = args->src_width;
+	nf->tru_h = args->src_height;
 
 	/* Are we going to offset the Y plane */
-	if (args->src.height + args->src.top < 512-16)
-		itv->yuv_info.new_frame_info[frame].offset_y = 1;
-	else
-		itv->yuv_info.new_frame_info[frame].offset_y = 0;
+	nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
 
 	/* Snapshot the osd pan info */
-	itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan;
-	itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan;
-	itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w;
-	itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h;
-
-	itv->yuv_info.new_frame_info[frame].update = 0;
-	itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
-	itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
-	itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
-
-	if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
-	    sizeof (itv->yuv_info.new_frame_info[frame]))) {
-		memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args));
-		itv->yuv_info.new_frame_info[frame].update = 1;
-/*		IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
+	nf->pan_x = yi->osd_x_pan;
+	nf->pan_y = yi->osd_y_pan;
+	nf->vis_w = yi->osd_vis_w;
+	nf->vis_h = yi->osd_vis_h;
+
+	nf->update = 0;
+	nf->interlaced_y = 0;
+	nf->interlaced_uv = 0;
+	nf->delay = 0;
+	nf->sync_field = 0;
+	nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK;
+
+	if (lace_threshold < 0)
+		lace_threshold = yi->decode_height - 1;
+
+	/* Work out the lace settings */
+	switch (nf->lace_mode) {
+	case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
+		nf->interlaced = 0;
+		if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021))
+			nf->interlaced_y = 0;
+		else
+			nf->interlaced_y = 1;
+
+		if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
+			nf->interlaced_uv = 0;
+		else
+			nf->interlaced_uv = 1;
+		break;
+
+	case IVTV_YUV_MODE_AUTO:
+		if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) {
+			nf->interlaced = 0;
+			if ((nf->tru_h < 512) ||
+			    (nf->tru_h > 576 && nf->tru_h < 1021) ||
+			    (nf->tru_w > 720 && nf->tru_h < 1021))
+				nf->interlaced_y = 0;
+			else
+				nf->interlaced_y = 1;
+			if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2))
+				nf->interlaced_uv = 0;
+			else
+				nf->interlaced_uv = 1;
+		} else {
+			nf->interlaced = 1;
+			nf->interlaced_y = 1;
+			nf->interlaced_uv = 1;
+		}
+		break;
+
+	case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
+	default:
+		nf->interlaced = 1;
+		nf->interlaced_y = 1;
+		nf->interlaced_uv = 1;
+		break;
 	}
 
-	itv->yuv_info.new_frame_info[frame].update |= register_update;
+	if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) {
+		yi->old_frame_info_args = *nf;
+		nf->update = 1;
+		IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame);
+	}
 
-	/* Should this frame be delayed ? */
-	if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
-		itv->yuv_info.field_delay[frame] = 1;
-	else
-		itv->yuv_info.field_delay[frame] = 0;
+	nf->update |= update;
+	nf->sync_field = yi->lace_sync_field;
+	nf->delay = nf->sync_field != of->sync_field;
+}
 
+/* Frame is complete & ready for display */
+void ivtv_yuv_frame_complete(struct ivtv *itv)
+{
+	atomic_set(&itv->yuv_info.next_fill_frame,
+			(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
+}
+
+int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+{
+	DEFINE_WAIT(wait);
+	int rc = 0;
+	int got_sig = 0;
 	/* DMA the frame */
 	mutex_lock(&itv->udma.lock);
 
@@ -1036,10 +1058,10 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
 	ivtv_udma_prepare(itv);
 	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
 	/* if no UDMA is pending and no UDMA is in progress, then the DMA
-	is finished */
+	   is finished */
 	while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
 		/* don't interrupt if the DMA is in progress but break off
-		a still pending DMA. */
+		   a still pending DMA. */
 		got_sig = signal_pending(current);
 		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
 			break;
@@ -1057,99 +1079,148 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
 		return -EINTR;
 	}
 
-	atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame);
+	ivtv_yuv_frame_complete(itv);
 
 	mutex_unlock(&itv->udma.lock);
 	return rc;
 }
 
+/* Setup frame according to V4L2 parameters */
+void ivtv_yuv_setup_stream_frame(struct ivtv *itv)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	struct ivtv_dma_frame dma_args;
+
+	ivtv_yuv_next_free(itv);
+
+	/* Copy V4L2 parameters to an ivtv_dma_frame struct... */
+	dma_args.y_source = 0L;
+	dma_args.uv_source = 0L;
+	dma_args.src.left = 0;
+	dma_args.src.top = 0;
+	dma_args.src.width = yi->v4l2_src_w;
+	dma_args.src.height = yi->v4l2_src_h;
+	dma_args.dst = yi->main_rect;
+	dma_args.src_width = yi->v4l2_src_w;
+	dma_args.src_height = yi->v4l2_src_h;
+
+	/* ... and use the same setup routine as ivtv_yuv_prep_frame */
+	ivtv_yuv_setup_frame(itv, &dma_args);
+
+	if (!itv->dma_data_req_offset)
+		itv->dma_data_req_offset = yuv_offset[yi->draw_frame];
+}
+
+/* Attempt to dma a frame from a user buffer */
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src)
+{
+	struct yuv_playback_info *yi = &itv->yuv_info;
+	struct ivtv_dma_frame dma_args;
+
+	ivtv_yuv_setup_stream_frame(itv);
+
+	/* We only need to supply source addresses for this */
+	dma_args.y_source = src;
+	dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31);
+	return ivtv_yuv_udma_frame(itv, &dma_args);
+}
+
+/* IVTV_IOC_DMA_FRAME ioctl handler */
+int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+{
+/*	IVTV_DEBUG_INFO("yuv_prep_frame\n"); */
+
+	ivtv_yuv_next_free(itv);
+	ivtv_yuv_setup_frame(itv, args);
+	return ivtv_yuv_udma_frame(itv, args);
+}
+
 void ivtv_yuv_close(struct ivtv *itv)
 {
+	struct yuv_playback_info *yi = &itv->yuv_info;
 	int h_filter, v_filter_1, v_filter_2;
 
 	IVTV_DEBUG_YUV("ivtv_yuv_close\n");
 	ivtv_waitq(&itv->vsync_waitq);
 
-	atomic_set(&itv->yuv_info.next_dma_frame, -1);
-	atomic_set(&itv->yuv_info.next_fill_frame, 0);
+	atomic_set(&yi->next_dma_frame, -1);
+	atomic_set(&yi->next_fill_frame, 0);
 
 	/* Reset registers we have changed so mpeg playback works */
 
 	/* If we fully restore this register, the display may remain active.
 	   Restore, but set one bit to blank the video. Firmware will always
 	   clear this bit when needed, so not a problem. */
-	write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
-
-	write_reg(itv->yuv_info.reg_2834, 0x02834);
-	write_reg(itv->yuv_info.reg_2838, 0x02838);
-	write_reg(itv->yuv_info.reg_283c, 0x0283c);
-	write_reg(itv->yuv_info.reg_2840, 0x02840);
-	write_reg(itv->yuv_info.reg_2844, 0x02844);
-	write_reg(itv->yuv_info.reg_2848, 0x02848);
-	write_reg(itv->yuv_info.reg_2854, 0x02854);
-	write_reg(itv->yuv_info.reg_285c, 0x0285c);
-	write_reg(itv->yuv_info.reg_2864, 0x02864);
-	write_reg(itv->yuv_info.reg_2870, 0x02870);
-	write_reg(itv->yuv_info.reg_2874, 0x02874);
-	write_reg(itv->yuv_info.reg_2890, 0x02890);
-	write_reg(itv->yuv_info.reg_289c, 0x0289c);
-
-	write_reg(itv->yuv_info.reg_2918, 0x02918);
-	write_reg(itv->yuv_info.reg_291c, 0x0291c);
-	write_reg(itv->yuv_info.reg_2920, 0x02920);
-	write_reg(itv->yuv_info.reg_2924, 0x02924);
-	write_reg(itv->yuv_info.reg_2928, 0x02928);
-	write_reg(itv->yuv_info.reg_292c, 0x0292c);
-	write_reg(itv->yuv_info.reg_2930, 0x02930);
-	write_reg(itv->yuv_info.reg_2934, 0x02934);
-	write_reg(itv->yuv_info.reg_2938, 0x02938);
-	write_reg(itv->yuv_info.reg_293c, 0x0293c);
-	write_reg(itv->yuv_info.reg_2940, 0x02940);
-	write_reg(itv->yuv_info.reg_2944, 0x02944);
-	write_reg(itv->yuv_info.reg_2948, 0x02948);
-	write_reg(itv->yuv_info.reg_294c, 0x0294c);
-	write_reg(itv->yuv_info.reg_2950, 0x02950);
-	write_reg(itv->yuv_info.reg_2954, 0x02954);
-	write_reg(itv->yuv_info.reg_2958, 0x02958);
-	write_reg(itv->yuv_info.reg_295c, 0x0295c);
-	write_reg(itv->yuv_info.reg_2960, 0x02960);
-	write_reg(itv->yuv_info.reg_2964, 0x02964);
-	write_reg(itv->yuv_info.reg_2968, 0x02968);
-	write_reg(itv->yuv_info.reg_296c, 0x0296c);
-	write_reg(itv->yuv_info.reg_2970, 0x02970);
+	write_reg(yi->reg_2898 | 0x01000000, 0x2898);
+
+	write_reg(yi->reg_2834, 0x02834);
+	write_reg(yi->reg_2838, 0x02838);
+	write_reg(yi->reg_283c, 0x0283c);
+	write_reg(yi->reg_2840, 0x02840);
+	write_reg(yi->reg_2844, 0x02844);
+	write_reg(yi->reg_2848, 0x02848);
+	write_reg(yi->reg_2854, 0x02854);
+	write_reg(yi->reg_285c, 0x0285c);
+	write_reg(yi->reg_2864, 0x02864);
+	write_reg(yi->reg_2870, 0x02870);
+	write_reg(yi->reg_2874, 0x02874);
+	write_reg(yi->reg_2890, 0x02890);
+	write_reg(yi->reg_289c, 0x0289c);
+
+	write_reg(yi->reg_2918, 0x02918);
+	write_reg(yi->reg_291c, 0x0291c);
+	write_reg(yi->reg_2920, 0x02920);
+	write_reg(yi->reg_2924, 0x02924);
+	write_reg(yi->reg_2928, 0x02928);
+	write_reg(yi->reg_292c, 0x0292c);
+	write_reg(yi->reg_2930, 0x02930);
+	write_reg(yi->reg_2934, 0x02934);
+	write_reg(yi->reg_2938, 0x02938);
+	write_reg(yi->reg_293c, 0x0293c);
+	write_reg(yi->reg_2940, 0x02940);
+	write_reg(yi->reg_2944, 0x02944);
+	write_reg(yi->reg_2948, 0x02948);
+	write_reg(yi->reg_294c, 0x0294c);
+	write_reg(yi->reg_2950, 0x02950);
+	write_reg(yi->reg_2954, 0x02954);
+	write_reg(yi->reg_2958, 0x02958);
+	write_reg(yi->reg_295c, 0x0295c);
+	write_reg(yi->reg_2960, 0x02960);
+	write_reg(yi->reg_2964, 0x02964);
+	write_reg(yi->reg_2968, 0x02968);
+	write_reg(yi->reg_296c, 0x0296c);
+	write_reg(yi->reg_2970, 0x02970);
 
 	/* Prepare to restore filters */
 
 	/* First the horizontal filter */
-	if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
+	if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) {
 		/* An exact size match uses filter 0 */
 		h_filter = 0;
-	}
-	else {
+	} else {
 		/* Figure out which filter to use */
-		h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
+		h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15;
 		h_filter = (h_filter >> 1) + (h_filter & 1);
 		/* Only an exact size match can use filter 0. */
-		if (h_filter < 1) h_filter = 1;
+		h_filter += !h_filter;
 	}
 
 	/* Now the vertical filter */
-	if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
+	if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) {
 		/* An exact size match uses filter 0/1 */
 		v_filter_1 = 0;
 		v_filter_2 = 1;
-	}
-	else {
+	} else {
 		/* Figure out which filter to use */
-		v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
+		v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15;
 		v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
 		/* Only an exact size match can use filter 0 */
-		if (v_filter_1 == 0) v_filter_1 = 1;
+		v_filter_1 += !v_filter_1;
 		v_filter_2 = v_filter_1;
 	}
 
 	/* Now restore the filters */
-	ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
+	ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2);
 
 	/* and clear a few registers */
 	write_reg(0, 0x02814);
@@ -1158,19 +1229,18 @@ void ivtv_yuv_close(struct ivtv *itv)
 	write_reg(0, 0x02910);
 
 	/* Release the blanking buffer */
-	if (itv->yuv_info.blanking_ptr) {
-		kfree (itv->yuv_info.blanking_ptr);
-		itv->yuv_info.blanking_ptr = NULL;
-		pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
+	if (yi->blanking_ptr) {
+		kfree(yi->blanking_ptr);
+		yi->blanking_ptr = NULL;
+		pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
 	}
 
 	/* Invalidate the old dimension information */
-	itv->yuv_info.old_frame_info.src_w = 0;
-	itv->yuv_info.old_frame_info.src_h = 0;
-	itv->yuv_info.old_frame_info_args.src_w = 0;
-	itv->yuv_info.old_frame_info_args.src_h = 0;
+	yi->old_frame_info.src_w = 0;
+	yi->old_frame_info.src_h = 0;
+	yi->old_frame_info_args.src_w = 0;
+	yi->old_frame_info_args.src_h = 0;
 
 	/* All done. */
 	clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
 }
-
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h
index 3b966f0a204a..2fe5f1250762 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.h
+++ b/drivers/media/video/ivtv/ivtv-yuv.h
@@ -21,11 +21,6 @@
 #ifndef IVTV_YUV_H
 #define IVTV_YUV_H
 
-/* Buffers on hardware offsets */
-#define IVTV_YUV_BUFFER_OFFSET    0x001a8600	/* First YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_1  0x00240400	/* Second YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_2  0x002d8200	/* Third YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_3  0x00370000	/* Fourth YUV Buffer */
 #define IVTV_YUV_BUFFER_UV_OFFSET 0x65400	/* Offset to UV Buffer */
 
 /* Offset to filter table in firmware */
@@ -36,11 +31,14 @@
 #define IVTV_YUV_UPDATE_VERTICAL    0x02
 #define IVTV_YUV_UPDATE_INVALID     0x04
 
-extern const u32 yuv_offset[4];
+extern const u32 yuv_offset[IVTV_YUV_BUFFERS];
 
 int ivtv_yuv_filter_check(struct ivtv *itv);
+void ivtv_yuv_setup_stream_frame(struct ivtv *itv);
+int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src);
+void ivtv_yuv_frame_complete(struct ivtv *itv);
 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
 void ivtv_yuv_close(struct ivtv *itv);
-void ivtv_yuv_work_handler (struct ivtv *itv);
+void ivtv_yuv_work_handler(struct ivtv *itv);
 
 #endif
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 52ffd154a3d8..3b23fc05f7c4 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -504,6 +504,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
 
 	ivtvfb_set_display_window(itv, &ivtv_window);
 
+	/* Pass screen size back to yuv handler */
+	itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
+	itv->yuv_info.osd_full_h = ivtv_osd.lines;
+
 	/* Force update of yuv registers */
 	itv->yuv_info.yuv_forced_update = 1;
 
@@ -1053,7 +1057,7 @@ static int ivtvfb_init_card(struct ivtv *itv)
 	}
 
 	itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
-	if (itv->osd_info == 0) {
+	if (itv->osd_info == NULL) {
 		IVTVFB_ERR("Failed to allocate memory for osd_info\n");
 		return -ENOMEM;
 	}
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index b6cd21e6dab9..4895540be195 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -764,7 +764,6 @@ static struct i2c_client ks0127_client_tmpl =
 	.addr = 0,
 	.adapter = NULL,
 	.driver = &i2c_driver_ks0127,
-	.usage_count = 0
 };
 
 static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
new file mode 100644
index 000000000000..d4bf14c284ef
--- /dev/null
+++ b/drivers/media/video/m52790.c
@@ -0,0 +1,168 @@
+/*
+ * m52790 i2c ivtv driver.
+ * Copyright (C) 2007  Hans Verkuil
+ *
+ * A/V source switching Mitsubishi M52790SP/FP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/m52790.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
+
+MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+
+struct m52790_state {
+	u16 input;
+	u16 output;
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int m52790_write(struct i2c_client *client)
+{
+	struct m52790_state *state = i2c_get_clientdata(client);
+	u8 sw1 = (state->input | state->output) & 0xff;
+	u8 sw2 = (state->input | state->output) >> 8;
+
+	return i2c_smbus_write_byte_data(client, sw1, sw2);
+}
+
+static int m52790_command(struct i2c_client *client, unsigned int cmd,
+			    void *arg)
+{
+	struct m52790_state *state = i2c_get_clientdata(client);
+	struct v4l2_routing *route = arg;
+
+	/* Note: audio and video are linked and cannot be switched separately.
+	   So audio and video routing commands are identical for this chip.
+	   In theory the video amplifier and audio modes could be handled
+	   separately for the output, but that seems to be overkill right now.
+	   The same holds for implementing an audio mute control, this is now
+	   part of the audio output routing. The normal case is that another
+	   chip takes care of the actual muting so making it part of the
+	   output routing seems to be the right thing to do for now. */
+	switch (cmd) {
+	case VIDIOC_INT_G_AUDIO_ROUTING:
+	case VIDIOC_INT_G_VIDEO_ROUTING:
+		route->input = state->input;
+		route->output = state->output;
+		break;
+
+	case VIDIOC_INT_S_AUDIO_ROUTING:
+	case VIDIOC_INT_S_VIDEO_ROUTING:
+		state->input = route->input;
+		state->output = route->output;
+		m52790_write(client);
+		break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	case VIDIOC_DBG_G_REGISTER:
+	case VIDIOC_DBG_S_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+
+		if (!v4l2_chip_match_i2c_client(client,
+					reg->match_type, reg->match_chip))
+			return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (reg->reg != 0)
+			return -EINVAL;
+		if (cmd == VIDIOC_DBG_G_REGISTER)
+			reg->val = state->input | state->output;
+		else {
+			state->input = reg->val & 0x0303;
+			state->output = reg->val & ~0x0303;
+			m52790_write(client);
+		}
+		break;
+	}
+#endif
+
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg,
+				V4L2_IDENT_M52790, 0);
+
+	case VIDIOC_LOG_STATUS:
+		v4l_info(client, "Switch 1: %02x\n",
+				(state->input | state->output) & 0xff);
+		v4l_info(client, "Switch 2: %02x\n",
+				(state->input | state->output) >> 8);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+static int m52790_probe(struct i2c_client *client)
+{
+	struct m52790_state *state;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	snprintf(client->name, sizeof(client->name) - 1, "m52790");
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL);
+	if (state == NULL)
+		return -ENOMEM;
+
+	state->input = M52790_IN_TUNER;
+	state->output = M52790_OUT_STEREO;
+	i2c_set_clientdata(client, state);
+	m52790_write(client);
+	return 0;
+}
+
+static int m52790_remove(struct i2c_client *client)
+{
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "m52790",
+	.driverid = I2C_DRIVERID_M52790,
+	.command = m52790_command,
+	.probe = m52790_probe,
+	.remove = m52790_remove,
+};
+
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index c31163290432..3d51fa0a52b6 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -2023,7 +2023,7 @@ static int __init meye_init(void)
 	if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE)
 		gbufsize = MEYE_MAX_BUFSIZE;
 	gbufsize = PAGE_ALIGN(gbufsize);
-	printk(KERN_INFO "meye: using %d buffers with %dk (%dk total)"
+	printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) "
 			 "for capture\n",
 			 gbuffers,
 			 gbufsize / 1024, gbuffers * gbufsize / 1024);
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index c0c87e06259b..7a11f3159e32 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -42,7 +42,8 @@
  *
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 
@@ -53,6 +54,7 @@
 #include <linux/videodev.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include <media/tvaudio.h>
 #include <media/msp3400.h>
 #include <linux/kthread.h>
@@ -71,7 +73,8 @@ int msp_debug;		 /* msp_debug output */
 int msp_once;		 /* no continous stereo monitoring */
 int msp_amsound;	 /* hard-wire AM sound at 6.5 Hz (france),
 			    the autoscan seems work well only with FM... */
-int msp_standard = 1;    /* Override auto detect of audio msp_standard, if needed. */
+int msp_standard = 1;    /* Override auto detect of audio msp_standard,
+			    if needed. */
 int msp_dolby;
 
 int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
@@ -81,12 +84,12 @@ int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual
 module_param(opmode,           int, 0444);
 
 /* read-write */
-module_param_named(once,msp_once,                      bool, 0644);
-module_param_named(debug,msp_debug,                    int,  0644);
-module_param_named(stereo_threshold,msp_stereo_thresh, int,  0644);
-module_param_named(standard,msp_standard,              int,  0644);
-module_param_named(amsound,msp_amsound,                bool, 0644);
-module_param_named(dolby,msp_dolby,                    bool, 0644);
+module_param_named(once, msp_once,                      bool, 0644);
+module_param_named(debug, msp_debug,                    int,  0644);
+module_param_named(stereo_threshold, msp_stereo_thresh, int,  0644);
+module_param_named(standard, msp_standard,              int,  0644);
+module_param_named(amsound, msp_amsound,                bool, 0644);
+module_param_named(dolby, msp_dolby,                    bool, 0644);
 
 MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect");
 MODULE_PARM_DESC(once, "No continuous stereo monitoring");
@@ -160,12 +163,13 @@ static int msp_read(struct i2c_client *client, int dev, int addr)
 		schedule_timeout_interruptible(msecs_to_jiffies(10));
 	}
 	if (err == 3) {
-		v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
+		v4l_warn(client, "resetting chip, sound will go off.\n");
 		msp_reset(client);
 		return -1;
 	}
 	retval = read[0] << 8 | read[1];
-	v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval);
+	v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n",
+			dev, addr, retval);
 	return retval;
 }
 
@@ -190,7 +194,8 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
 	buffer[3] = val  >> 8;
 	buffer[4] = val  &  0xff;
 
-	v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val);
+	v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n",
+			dev, addr, val);
 	for (err = 0; err < 3; err++) {
 		if (i2c_master_send(client, buffer, 5) == 5)
 			break;
@@ -199,7 +204,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
 		schedule_timeout_interruptible(msecs_to_jiffies(10));
 	}
 	if (err == 3) {
-		v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
+		v4l_warn(client, "resetting chip, sound will go off.\n");
 		msp_reset(client);
 		return -1;
 	}
@@ -273,7 +278,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out)
 		state->acb = 0xf60; /* Mute Input and SCART 1 Output */
 
 	v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n",
-						scart_names[in], out, state->acb);
+					scart_names[in], out, state->acb);
 	msp_write_dsp(client, 0x13, state->acb);
 
 	/* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */
@@ -292,7 +297,8 @@ void msp_set_audio(struct i2c_client *client)
 		val = (state->volume * 0x7f / 65535) << 8;
 
 	v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n",
-		state->muted ? "on" : "off", state->scan_in_progress ? "yes" : "no",
+		state->muted ? "on" : "off",
+		state->scan_in_progress ? "yes" : "no",
 		state->volume);
 
 	msp_write_dsp(client, 0x0000, val);
@@ -681,14 +687,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 		v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a);
 
 		switch (*a) {
-			case 1024000:
-				state->i2s_mode = 0;
-				break;
-			case 2048000:
-				state->i2s_mode = 1;
-				break;
-			default:
-				return -EINVAL;
+		case 1024000:
+			state->i2s_mode = 0;
+			break;
+		case 2048000:
+			state->i2s_mode = 1;
+			break;
+		default:
+			return -EINVAL;
 		}
 		break;
 	}
@@ -698,22 +704,22 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 		struct v4l2_queryctrl *qc = arg;
 
 		switch (qc->id) {
-			case V4L2_CID_AUDIO_VOLUME:
-			case V4L2_CID_AUDIO_MUTE:
-				return v4l2_ctrl_query_fill_std(qc);
-			default:
-				break;
+		case V4L2_CID_AUDIO_VOLUME:
+		case V4L2_CID_AUDIO_MUTE:
+			return v4l2_ctrl_query_fill_std(qc);
+		default:
+			break;
 		}
 		if (!state->has_sound_processing)
 			return -EINVAL;
 		switch (qc->id) {
-			case V4L2_CID_AUDIO_LOUDNESS:
-			case V4L2_CID_AUDIO_BALANCE:
-			case V4L2_CID_AUDIO_BASS:
-			case V4L2_CID_AUDIO_TREBLE:
-				return v4l2_ctrl_query_fill_std(qc);
-			default:
-				return -EINVAL;
+		case V4L2_CID_AUDIO_LOUDNESS:
+		case V4L2_CID_AUDIO_BALANCE:
+		case V4L2_CID_AUDIO_BASS:
+		case V4L2_CID_AUDIO_TREBLE:
+			return v4l2_ctrl_query_fill_std(qc);
+		default:
+			return -EINVAL;
 		}
 	}
 
@@ -735,13 +741,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 				state->volume, state->muted ? " (muted)" : "");
 		if (state->has_sound_processing) {
 			v4l_info(client, "Audio:    balance %d bass %d treble %d loudness %s\n",
-					state->balance, state->bass, state->treble,
+					state->balance, state->bass,
+					state->treble,
 					state->loudness ? "on" : "off");
 		}
 		switch (state->mode) {
 		case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
 		case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
-		case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break;
+		case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break;
 		case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break;
 		case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break;
 		case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break;
@@ -772,7 +779,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 	}
 
 	case VIDIOC_G_CHIP_IDENT:
-		return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2);
+		return v4l2_chip_ident_i2c_client(client, arg, state->ident,
+				(state->rev1 << 16) | state->rev2);
 
 	default:
 		/* unknown */
@@ -783,7 +791,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static int msp_suspend(struct i2c_client *client, pm_message_t state)
 {
-
 	v4l_dbg(1, msp_debug, client, "suspend\n");
 	msp_reset(client);
 	return 0;
@@ -791,7 +798,6 @@ static int msp_suspend(struct i2c_client *client, pm_message_t state)
 
 static int msp_resume(struct i2c_client *client)
 {
-
 	v4l_dbg(1, msp_debug, client, "resume\n");
 	msp_wake_thread(client);
 	return 0;
@@ -799,11 +805,8 @@ static int msp_resume(struct i2c_client *client)
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver;
-
-static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
+static int msp_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	struct msp_state *state;
 	int (*thread_func)(void *data) = NULL;
 	int msp_hard;
@@ -812,26 +815,16 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
 	int msp_product, msp_prod_hi, msp_prod_lo;
 	int msp_rom;
 
-	client = kzalloc(sizeof(*client), GFP_KERNEL);
-	if (!client)
-		return -ENOMEM;
-
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver;
 	snprintf(client->name, sizeof(client->name) - 1, "msp3400");
 
 	if (msp_reset(client) == -1) {
 		v4l_dbg(1, msp_debug, client, "msp3400 not found\n");
-		kfree(client);
-		return 0;
+		return -ENODEV;
 	}
 
 	state = kzalloc(sizeof(*state), GFP_KERNEL);
-	if (!state) {
-		kfree(client);
+	if (!state)
 		return -ENOMEM;
-	}
 
 	i2c_set_clientdata(client, state);
 
@@ -853,12 +846,13 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
 	state->rev1 = msp_read_dsp(client, 0x1e);
 	if (state->rev1 != -1)
 		state->rev2 = msp_read_dsp(client, 0x1f);
-	v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2);
+	v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n",
+			state->rev1, state->rev2);
 	if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) {
-		v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n");
+		v4l_dbg(1, msp_debug, client,
+				"not an msp3400 (cannot read chip version)\n");
 		kfree(state);
-		kfree(client);
-		return 0;
+		return -ENODEV;
 	}
 
 	msp_set_audio(client);
@@ -874,37 +868,55 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
 			msp_family, msp_product,
 			msp_revision, msp_hard, msp_rom);
 	/* Rev B=2, C=3, D=4, G=7 */
-	state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@';
+	state->ident = msp_family * 10000 + 4000 + msp_product * 10 +
+			msp_revision - '@';
 
 	/* Has NICAM support: all mspx41x and mspx45x products have NICAM */
-	state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5;
+	state->has_nicam =
+		msp_prod_hi == 1 || msp_prod_hi == 5;
 	/* Has radio support: was added with revision G */
-	state->has_radio = msp_revision >= 'G';
+	state->has_radio =
+		msp_revision >= 'G';
 	/* Has headphones output: not for stripped down products */
-	state->has_headphones = msp_prod_lo < 5;
+	state->has_headphones =
+		msp_prod_lo < 5;
 	/* Has scart2 input: not in stripped down products of the '3' family */
-	state->has_scart2 = msp_family >= 4 || msp_prod_lo < 7;
+	state->has_scart2 =
+		msp_family >= 4 || msp_prod_lo < 7;
 	/* Has scart3 input: not in stripped down products of the '3' family */
-	state->has_scart3 = msp_family >= 4 || msp_prod_lo < 5;
+	state->has_scart3 =
+		msp_family >= 4 || msp_prod_lo < 5;
 	/* Has scart4 input: not in pre D revisions, not in stripped D revs */
-	state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
-	/* Has scart2 output: not in stripped down products of the '3' family */
-	state->has_scart2_out = msp_family >= 4 || msp_prod_lo < 5;
+	state->has_scart4 =
+		msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5);
+	/* Has scart2 output: not in stripped down products of
+	 * the '3' family */
+	state->has_scart2_out =
+		msp_family >= 4 || msp_prod_lo < 5;
 	/* Has scart2 a volume control? Not in pre-D revisions. */
-	state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart2_out;
+	state->has_scart2_out_volume =
+		msp_revision > 'C' && state->has_scart2_out;
 	/* Has a configurable i2s out? */
-	state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7;
-	/* Has subwoofer output: not in pre-D revs and not in stripped down products */
-	state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5;
-	/* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in
-	   stripped down products */
-	state->has_sound_processing = msp_prod_lo < 7;
+	state->has_i2s_conf =
+		msp_revision >= 'G' && msp_prod_lo < 7;
+	/* Has subwoofer output: not in pre-D revs and not in stripped down
+	 * products */
+	state->has_subwoofer =
+		msp_revision >= 'D' && msp_prod_lo < 5;
+	/* Has soundprocessing (bass/treble/balance/loudness/equalizer):
+	 *  not in stripped down products */
+	state->has_sound_processing =
+		msp_prod_lo < 7;
 	/* Has Virtual Dolby Surround: only in msp34x1 */
-	state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
+	state->has_virtual_dolby_surround =
+		msp_revision == 'G' && msp_prod_lo == 1;
 	/* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
-	state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
-	/* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */
-	state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
+	state->has_dolby_pro_logic =
+		msp_revision == 'G' && msp_prod_lo == 2;
+	/* The msp343xG supports BTSC only and cannot do Automatic Standard
+	 * Detection. */
+	state->force_btsc =
+		msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
 
 	state->opmode = opmode;
 	if (state->opmode == OPMODE_AUTO) {
@@ -919,32 +931,33 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
 	}
 
 	/* hello world :-) */
-	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name);
+	v4l_info(client, "%s found @ 0x%x (%s)\n", client->name,
+			client->addr << 1, client->adapter->name);
 	v4l_info(client, "%s ", client->name);
 	if (state->has_nicam && state->has_radio)
-		printk("supports nicam and radio, ");
+		printk(KERN_CONT "supports nicam and radio, ");
 	else if (state->has_nicam)
-		printk("supports nicam, ");
+		printk(KERN_CONT "supports nicam, ");
 	else if (state->has_radio)
-		printk("supports radio, ");
-	printk("mode is ");
+		printk(KERN_CONT "supports radio, ");
+	printk(KERN_CONT "mode is ");
 
 	/* version-specific initialization */
 	switch (state->opmode) {
 	case OPMODE_MANUAL:
-		printk("manual");
+		printk(KERN_CONT "manual");
 		thread_func = msp3400c_thread;
 		break;
 	case OPMODE_AUTODETECT:
-		printk("autodetect");
+		printk(KERN_CONT "autodetect");
 		thread_func = msp3410d_thread;
 		break;
 	case OPMODE_AUTOSELECT:
-		printk("autodetect and autoselect");
+		printk(KERN_CONT "autodetect and autoselect");
 		thread_func = msp34xxg_thread;
 		break;
 	}
-	printk("\n");
+	printk(KERN_CONT "\n");
 
 	/* startup control thread if needed */
 	if (thread_func) {
@@ -954,24 +967,12 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
 			v4l_warn(client, "kernel_thread() failed\n");
 		msp_wake_thread(client);
 	}
-
-	/* done */
-	i2c_attach_client(client);
-
 	return 0;
 }
 
-static int msp_probe(struct i2c_adapter *adapter)
-{
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, msp_attach);
-	return 0;
-}
-
-static int msp_detach(struct i2c_client *client)
+static int msp_remove(struct i2c_client *client)
 {
 	struct msp_state *state = i2c_get_clientdata(client);
-	int err;
 
 	/* shutdown control thread */
 	if (state->kthread) {
@@ -980,43 +981,22 @@ static int msp_detach(struct i2c_client *client)
 	}
 	msp_reset(client);
 
-	err = i2c_detach_client(client);
-	if (err) {
-		return err;
-	}
-
 	kfree(state);
-	kfree(client);
 	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-	.id             = I2C_DRIVERID_MSP3400,
-	.attach_adapter = msp_probe,
-	.detach_client  = msp_detach,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "msp3400",
+	.driverid = I2C_DRIVERID_MSP3400,
+	.command = msp_command,
+	.probe = msp_probe,
+	.remove = msp_remove,
 	.suspend = msp_suspend,
-	.resume  = msp_resume,
-	.command        = msp_command,
-	.driver = {
-		.name    = "msp3400",
-	},
+	.resume = msp_resume,
 };
 
-static int __init msp3400_init_module(void)
-{
-	return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit msp3400_cleanup_module(void)
-{
-	i2c_del_driver(&i2c_driver);
-}
-
-module_init(msp3400_init_module);
-module_exit(msp3400_cleanup_module);
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index d5ee2629121e..61ec794a737e 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -15,7 +15,8 @@
  *
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 
@@ -78,37 +79,37 @@ static struct msp3400c_init_data_dem {
 		{75, 19, 36, 35, 39, 40},
 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
 		0x00d0, 0x0500, 0x0020, 0x3000
-	},{	/* AM (for carrier detect / msp3410) */
+	}, {	/* AM (for carrier detect / msp3410) */
 		{-1, -1, -8, 2, 59, 126},
 		{-1, -1, -8, 2, 59, 126},
 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
 		0x00d0, 0x0100, 0x0020, 0x3000
-	},{	/* FM Radio */
+	}, {	/* FM Radio */
 		{-8, -8, 4, 6, 78, 107},
 		{-8, -8, 4, 6, 78, 107},
 		MSP_CARRIER(10.7), MSP_CARRIER(10.7),
 		0x00d0, 0x0480, 0x0020, 0x3000
-	},{	/* Terrestial FM-mono + FM-stereo */
+	}, {	/* Terrestial FM-mono + FM-stereo */
 		{3, 18, 27, 48, 66, 72},
 		{3, 18, 27, 48, 66, 72},
 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
 		0x00d0, 0x0480, 0x0030, 0x3000
-	},{	/* Sat FM-mono */
+	}, {	/* Sat FM-mono */
 		{ 1, 9, 14, 24, 33, 37},
 		{ 3, 18, 27, 48, 66, 72},
 		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
 		0x00c6, 0x0480, 0x0000, 0x3000
-	},{	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
+	}, {	/* NICAM/FM --  B/G (5.5/5.85), D/K (6.5/5.85) */
 		{-2, -8, -10, 10, 50, 86},
 		{3, 18, 27, 48, 66, 72},
 		MSP_CARRIER(5.5), MSP_CARRIER(5.5),
 		0x00d0, 0x0040, 0x0120, 0x3000
-	},{	/* NICAM/FM -- I (6.0/6.552) */
+	}, {	/* NICAM/FM -- I (6.0/6.552) */
 		{2, 4, -6, -4, 40, 94},
 		{3, 18, 27, 48, 66, 72},
 		MSP_CARRIER(6.0), MSP_CARRIER(6.0),
 		0x00d0, 0x0040, 0x0120, 0x3000
-	},{	/* NICAM/AM -- L (6.5/5.85) */
+	}, {	/* NICAM/AM -- L (6.5/5.85) */
 		{-2, -8, -10, 10, 50, 86},
 		{-4, -12, -9, 23, 79, 126},
 		MSP_CARRIER(6.5), MSP_CARRIER(6.5),
@@ -224,7 +225,9 @@ void msp3400c_set_mode(struct i2c_client *client, int mode)
    nor do they support stereo BTSC. */
 static void msp3400c_set_audmode(struct i2c_client *client)
 {
-	static char *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2" };
+	static char *strmode[] = {
+		"mono", "stereo", "lang2", "lang1", "lang1+lang2"
+	};
 	struct msp_state *state = i2c_get_clientdata(client);
 	char *modestr = (state->audmode >= 0 && state->audmode < 5) ?
 		strmode[state->audmode] : "unknown";
@@ -298,19 +301,23 @@ static void msp3400c_set_audmode(struct i2c_client *client)
 	case MSP_MODE_FM_NICAM1:
 	case MSP_MODE_FM_NICAM2:
 	case MSP_MODE_AM_NICAM:
-		v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr);
+		v4l_dbg(1, msp_debug, client,
+			"NICAM set_audmode: %s\n", modestr);
 		if (state->nicam_on)
 			src = 0x0100;  /* NICAM */
 		break;
 	case MSP_MODE_BTSC:
-		v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr);
+		v4l_dbg(1, msp_debug, client,
+			"BTSC set_audmode: %s\n", modestr);
 		break;
 	case MSP_MODE_EXTERN:
-		v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr);
+		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 set_audmode: %s\n",modestr);
+		v4l_dbg(1, msp_debug, client,
+			"FM-Radio set_audmode: %s\n", modestr);
 		break;
 	default:
 		v4l_dbg(1, msp_debug, client, "mono set_audmode\n");
@@ -342,7 +349,8 @@ static void msp3400c_set_audmode(struct i2c_client *client)
 		src |= 0x0010;
 		break;
 	}
-	v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src);
+	v4l_dbg(1, msp_debug, client,
+		"set_audmode final source/matrix = 0x%x\n", src);
 
 	msp_set_source(client, src);
 }
@@ -351,22 +359,26 @@ static void msp3400c_print_mode(struct i2c_client *client)
 {
 	struct msp_state *state = i2c_get_clientdata(client);
 
-	if (state->main == state->second) {
-		v4l_dbg(1, msp_debug, client, "mono sound carrier: %d.%03d MHz\n",
-		       state->main / 910000, (state->main / 910) % 1000);
-	} else {
-		v4l_dbg(1, msp_debug, client, "main sound carrier: %d.%03d MHz\n",
-		       state->main / 910000, (state->main / 910) % 1000);
-	}
+	if (state->main == state->second)
+		v4l_dbg(1, msp_debug, client,
+			"mono sound carrier: %d.%03d MHz\n",
+			state->main / 910000, (state->main / 910) % 1000);
+	else
+		v4l_dbg(1, msp_debug, client,
+			"main sound carrier: %d.%03d MHz\n",
+			state->main / 910000, (state->main / 910) % 1000);
 	if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2)
-		v4l_dbg(1, msp_debug, client, "NICAM/FM carrier  : %d.%03d MHz\n",
-		       state->second / 910000, (state->second/910) % 1000);
+		v4l_dbg(1, msp_debug, client,
+			"NICAM/FM carrier  : %d.%03d MHz\n",
+			state->second / 910000, (state->second/910) % 1000);
 	if (state->mode == MSP_MODE_AM_NICAM)
-		v4l_dbg(1, msp_debug, client, "NICAM/AM carrier  : %d.%03d MHz\n",
-		       state->second / 910000, (state->second / 910) % 1000);
+		v4l_dbg(1, msp_debug, client,
+			"NICAM/AM carrier  : %d.%03d MHz\n",
+			state->second / 910000, (state->second / 910) % 1000);
 	if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) {
-		v4l_dbg(1, msp_debug, client, "FM-stereo carrier : %d.%03d MHz\n",
-		       state->second / 910000, (state->second / 910) % 1000);
+		v4l_dbg(1, msp_debug, client,
+			"FM-stereo carrier : %d.%03d MHz\n",
+			state->second / 910000, (state->second / 910) % 1000);
 	}
 }
 
@@ -385,7 +397,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client)
 		val = msp_read_dsp(client, 0x18);
 		if (val > 32767)
 			val -= 65536;
-		v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val);
+		v4l_dbg(2, msp_debug, client,
+			"stereo detect register: %d\n", val);
 		if (val > 8192) {
 			rxsubchans = V4L2_TUNER_SUB_STEREO;
 		} else if (val < -4096) {
@@ -430,7 +443,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client)
 	}
 	if (rxsubchans != state->rxsubchans) {
 		update = 1;
-		v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n",
+		v4l_dbg(1, msp_debug, client,
+			"watch: rxsubchans %02x => %02x\n",
 			state->rxsubchans, rxsubchans);
 		state->rxsubchans = rxsubchans;
 	}
@@ -452,9 +466,8 @@ static void watch_stereo(struct i2c_client *client)
 {
 	struct msp_state *state = i2c_get_clientdata(client);
 
-	if (msp_detect_stereo(client)) {
+	if (msp_detect_stereo(client))
 		msp_set_audmode(client);
-	}
 
 	if (msp_once)
 		state->watch_stereo = 0;
@@ -465,7 +478,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, i;
 
 
 	v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
@@ -475,7 +488,7 @@ int msp3400c_thread(void *data)
 		msp_sleep(state, -1);
 		v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n");
 
-	restart:
+restart:
 		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
 		state->restart = 0;
 		if (kthread_should_stop())
@@ -483,7 +496,8 @@ int msp3400c_thread(void *data)
 
 		if (state->radio || MSP_MODE_EXTERN == state->mode) {
 			/* no carrier scan, just unmute */
-			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+			v4l_dbg(1, msp_debug, client,
+				"thread: no carrier scan\n");
 			state->scan_in_progress = 0;
 			msp_set_audio(client);
 			continue;
@@ -514,16 +528,17 @@ int msp3400c_thread(void *data)
 			v4l_dbg(1, msp_debug, client, "AM sound override\n");
 		}
 
-		for (this = 0; this < count; this++) {
-			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
-			if (msp_sleep(state,100))
+		for (i = 0; i < count; i++) {
+			msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo);
+			if (msp_sleep(state, 100))
 				goto restart;
 			val = msp_read_dsp(client, 0x1b);
 			if (val > 32767)
 				val -= 65536;
 			if (val1 < val)
-				val1 = val, max1 = this;
-			v4l_dbg(1, msp_debug, client, "carrier1 val: %5d / %s\n", val,cd[this].name);
+				val1 = val, max1 = i;
+			v4l_dbg(1, msp_debug, client,
+				"carrier1 val: %5d / %s\n", val, cd[i].name);
 		}
 
 		/* carrier detect pass #2 -- second (stereo) carrier */
@@ -550,16 +565,17 @@ int msp3400c_thread(void *data)
 			count = 0;
 			max2 = 0;
 		}
-		for (this = 0; this < count; this++) {
-			msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo);
-			if (msp_sleep(state,100))
+		for (i = 0; i < count; i++) {
+			msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo);
+			if (msp_sleep(state, 100))
 				goto restart;
 			val = msp_read_dsp(client, 0x1b);
 			if (val > 32767)
 				val -= 65536;
 			if (val2 < val)
-				val2 = val, max2 = this;
-			v4l_dbg(1, msp_debug, client, "carrier2 val: %5d / %s\n", val,cd[this].name);
+				val2 = val, max2 = i;
+			v4l_dbg(1, msp_debug, client,
+				"carrier2 val: %5d / %s\n", val, cd[i].name);
 		}
 
 		/* program the msp3400 according to the results */
@@ -611,7 +627,7 @@ int msp3400c_thread(void *data)
 			break;
 		case 0: /* 4.5 */
 		default:
-		no_second:
+no_second:
 			state->second = msp3400c_carrier_detect_main[max1].cdo;
 			msp3400c_set_mode(client, MSP_MODE_FM_TERRA);
 			break;
@@ -632,7 +648,8 @@ int msp3400c_thread(void *data)
 		while (state->watch_stereo) {
 			if (msp_sleep(state, count ? 1000 : 5000))
 				goto restart;
-			if (count) count--;
+			if (count)
+				count--;
 			watch_stereo(client);
 		}
 	}
@@ -651,10 +668,10 @@ int msp3410d_thread(void *data)
 	set_freezable();
 	for (;;) {
 		v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n");
-		msp_sleep(state,-1);
+		msp_sleep(state, -1);
 		v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n");
 
-	restart:
+restart:
 		v4l_dbg(2, msp_debug, client, "thread: restart scan\n");
 		state->restart = 0;
 		if (kthread_should_stop())
@@ -662,7 +679,8 @@ int msp3410d_thread(void *data)
 
 		if (state->mode == MSP_MODE_EXTERN) {
 			/* no carrier scan needed, just unmute */
-			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+			v4l_dbg(1, msp_debug, client,
+				"thread: no carrier scan\n");
 			state->scan_in_progress = 0;
 			msp_set_audio(client);
 			continue;
@@ -673,7 +691,8 @@ int msp3410d_thread(void *data)
 		msp_set_audio(client);
 
 		/* start autodetect. Note: autodetect is not supported for
-		   NTSC-M and radio, hence we force the standard in those cases. */
+		   NTSC-M and radio, hence we force the standard in those
+		   cases. */
 		if (state->radio)
 			std = 0x40;
 		else
@@ -686,8 +705,9 @@ int msp3410d_thread(void *data)
 			goto restart;
 
 		if (msp_debug)
-			v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n",
-			       msp_standard_std_name(std), std);
+			v4l_dbg(2, msp_debug, client,
+				"setting standard: %s (0x%04x)\n",
+				msp_standard_std_name(std), std);
 
 		if (std != 1) {
 			/* programmed some specific mode */
@@ -703,7 +723,8 @@ int msp3410d_thread(void *data)
 				val = msp_read_dem(client, 0x7e);
 				if (val < 0x07ff)
 					break;
-				v4l_dbg(2, 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++)
@@ -716,12 +737,13 @@ int msp3410d_thread(void *data)
 		state->std = val;
 		state->rxsubchans = V4L2_TUNER_SUB_MONO;
 
-		if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) &&
-				(val != 0x0009)) {
+		if (msp_amsound && !state->radio &&
+		    (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) {
 			/* autodetection has failed, let backup */
 			v4l_dbg(1, msp_debug, client, "autodetection failed,"
 				" switching to backup standard: %s (0x%04x)\n",
-				msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val);
+				msp_stdlist[8].name ?
+					msp_stdlist[8].name : "unknown", val);
 			state->std = val = 0x0009;
 			msp_write_dem(client, 0x20, val);
 		}
@@ -786,7 +808,8 @@ int msp3410d_thread(void *data)
 		while (state->watch_stereo) {
 			if (msp_sleep(state, count ? 1000 : 5000))
 				goto restart;
-			if (count) count--;
+			if (count)
+				count--;
 			watch_stereo(client);
 		}
 	}
@@ -872,8 +895,8 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
 	else
 		source = (in << 8) | matrix;
 
-	v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n",
-			in, source, reg);
+	v4l_dbg(1, msp_debug, client,
+		"set source to %d (0x%x) for output %02x\n", in, source, reg);
 	msp_write_dsp(client, reg, source);
 }
 
@@ -948,7 +971,7 @@ int msp34xxg_thread(void *data)
 		msp_sleep(state, -1);
 		v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n");
 
-	restart:
+restart:
 		v4l_dbg(1, msp_debug, client, "thread: restart scan\n");
 		state->restart = 0;
 		if (kthread_should_stop())
@@ -956,7 +979,8 @@ int msp34xxg_thread(void *data)
 
 		if (state->mode == MSP_MODE_EXTERN) {
 			/* no carrier scan needed, just unmute */
-			v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+			v4l_dbg(1, msp_debug, client,
+				"thread: no carrier scan\n");
 			state->scan_in_progress = 0;
 			msp_set_audio(client);
 			continue;
@@ -972,7 +996,8 @@ int msp34xxg_thread(void *data)
 			goto unmute;
 
 		/* watch autodetect */
-		v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n");
+		v4l_dbg(1, msp_debug, client,
+			"started autodetect, waiting for result\n");
 		for (i = 0; i < 10; i++) {
 			if (msp_sleep(state, 100))
 				goto restart;
@@ -983,15 +1008,18 @@ int msp34xxg_thread(void *data)
 				state->std = val;
 				break;
 			}
-			v4l_dbg(2, msp_debug, client, "detection still in progress\n");
+			v4l_dbg(2, msp_debug, client,
+				"detection still in progress\n");
 		}
 		if (state->std == 1) {
-			v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n");
+			v4l_dbg(1, msp_debug, client,
+				"detection still in progress after 10 tries. giving up.\n");
 			continue;
 		}
 
-	unmute:
-		v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
+unmute:
+		v4l_dbg(1, msp_debug, client,
+			"detected standard: %s (0x%04x)\n",
 			msp_standard_std_name(state->std), state->std);
 
 		if (state->std == 9) {
@@ -1046,9 +1074,11 @@ static int msp34xxg_detect_stereo(struct i2c_client *client)
 		if (state->std == 0x20)
 			state->rxsubchans |= V4L2_TUNER_SUB_SAP;
 		else
-			state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+			state->rxsubchans =
+				V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
 	}
-	v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
+	v4l_dbg(1, msp_debug, client,
+		"status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n",
 		status, is_stereo, is_bilingual, state->rxsubchans);
 	return (oldrx != state->rxsubchans);
 }
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index f49d1f4c40db..b630c26cfe85 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -14,7 +14,7 @@ static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "mt20xx "
+#define PREFIX "mt20xx"
 
 /* ---------------------------------------------------------------------- */
 
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 98ad3092a079..add6d0d680be 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -149,10 +149,33 @@ struct mxb
 
 static struct saa7146_extension extension;
 
+static int mxb_check_clients(struct device *dev, void *data)
+{
+	struct mxb* mxb = data;
+	struct i2c_client *client = i2c_verify_client(dev);
+
+	if( !client )
+		return 0;
+
+	if( I2C_ADDR_TEA6420_1 == client->addr )
+		mxb->tea6420_1 = client;
+	if( I2C_ADDR_TEA6420_2 == client->addr )
+		mxb->tea6420_2 = client;
+	if( I2C_TEA6415C_2 == client->addr )
+		mxb->tea6415c = client;
+	if( I2C_ADDR_TDA9840 == client->addr )
+		mxb->tda9840 = client;
+	if( I2C_SAA7111 == client->addr )
+		mxb->saa7111a = client;
+	if( 0x60 == client->addr )
+		mxb->tuner = client;
+
+	return 0;
+}
+
 static int mxb_probe(struct saa7146_dev* dev)
 {
 	struct mxb* mxb = NULL;
-	struct i2c_client *client;
 	int result;
 
 	if ((result = request_module("saa7111")) < 0) {
@@ -195,20 +218,7 @@ static int mxb_probe(struct saa7146_dev* dev)
 	}
 
 	/* loop through all i2c-devices on the bus and look who is there */
-	list_for_each_entry(client, &mxb->i2c_adapter.clients, list) {
-		if( I2C_ADDR_TEA6420_1 == client->addr )
-			mxb->tea6420_1 = client;
-		if( I2C_ADDR_TEA6420_2 == client->addr )
-			mxb->tea6420_2 = client;
-		if( I2C_TEA6415C_2 == client->addr )
-			mxb->tea6415c = client;
-		if( I2C_ADDR_TDA9840 == client->addr )
-			mxb->tda9840 = client;
-		if( I2C_SAA7111 == client->addr )
-			mxb->saa7111a = client;
-		if( 0x60 == client->addr )
-			mxb->tuner = client;
-	}
+	device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
 
 	/* check if all devices are present */
 	if(    0 == mxb->tea6420_1	|| 0 == mxb->tea6420_2	|| 0 == mxb->tea6415c
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index d0c2cd785430..6fc1b8be1a1f 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -5,6 +5,10 @@ config VIDEO_PVRUSB2
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_CX2341X
+	select VIDEO_SAA711X
+	select VIDEO_CX25840
+	select VIDEO_MSP3400
+	select VIDEO_WM8775
 	---help---
 	  This is a video4linux driver for Conexant 23416 based
 	  usb2 personal video recorder devices.
@@ -12,32 +16,29 @@ config VIDEO_PVRUSB2
 	  To compile this driver as a module, choose M here: the
 	  module will be called pvrusb2
 
-config VIDEO_PVRUSB2_29XXX
-	bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series"
+config VIDEO_PVRUSB2_ONAIR_CREATOR
+	bool "pvrusb2 driver support for OnAir Creator model"
 	depends on VIDEO_PVRUSB2 && EXPERIMENTAL
 	select VIDEO_SAA711X
-	select VIDEO_MSP3400
+	select VIDEO_CS53L32A
 	---help---
-	  This option enables support for WinTV-PVR USB2 devices whose
-	  model number is of the form "29xxx" (leading prefix of "29"
-	  followed by 3 digits).
-	  To see if you may need this option, examine the white
-	  sticker on the underside of your device.
+
+	  This option enables support for the OnAir Creator USB tuner
+	  device.  This is a hybrid device, however currently only
+	  analog mode is supported.
 
 	  If you are in doubt, say Y.
 
-config VIDEO_PVRUSB2_24XXX
-	bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
+config VIDEO_PVRUSB2_ONAIR_USB2
+	bool "pvrusb2 driver support for OnAir USB2 model"
 	depends on VIDEO_PVRUSB2 && EXPERIMENTAL
-	select VIDEO_CX25840
-	select VIDEO_WM8775
+	select VIDEO_SAA711X
+	select VIDEO_CS53L32A
 	---help---
-	  This option enables inclusion of additional logic to operate
-	  newer WinTV-PVR USB2 devices whose model number is of the
-	  form "24xxx" (leading prefix of "24" followed by 3 digits).
-	  To see if you may need this option, examine the white
-	  sticker on the underside of your device.  Enabling this
-	  option will not harm support for older devices.
+
+	  This option enables support for the OnAir USB2 tuner device
+	  (also known as the Sasem tuner).  This is a hybrid device,
+	  however currently only analog mode is supported.
 
 	  If you are in doubt, say Y.
 
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
index 69b3e43cd0eb..47284e558648 100644
--- a/drivers/media/video/pvrusb2/Makefile
+++ b/drivers/media/video/pvrusb2/Makefile
@@ -6,7 +6,7 @@ pvrusb2-objs	:= pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
 		   pvrusb2-encoder.o pvrusb2-video-v4l.o \
 		   pvrusb2-eeprom.o pvrusb2-tuner.o \
 		   pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
-		   pvrusb2-ctrl.o pvrusb2-std.o \
+		   pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
 		   pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
 		   pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
 		   $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 379645e481c6..9a7c8e9c3e8b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -35,34 +35,58 @@ struct pvr2_msp3400_handler {
 };
 
 
+
+struct routing_scheme {
+	const int *def;
+	unsigned int cnt;
+};
+
+static const int routing_scheme0[] = {
+	[PVR2_CVAL_INPUT_TV]        = MSP_INPUT_DEFAULT,
+	[PVR2_CVAL_INPUT_RADIO]     = MSP_INPUT(MSP_IN_SCART2,
+						MSP_IN_TUNER1,
+						MSP_DSP_IN_SCART,
+						MSP_DSP_IN_SCART),
+	[PVR2_CVAL_INPUT_COMPOSITE] = MSP_INPUT(MSP_IN_SCART1,
+						MSP_IN_TUNER1,
+						MSP_DSP_IN_SCART,
+						MSP_DSP_IN_SCART),
+	[PVR2_CVAL_INPUT_SVIDEO]    = MSP_INPUT(MSP_IN_SCART1,
+						MSP_IN_TUNER1,
+						MSP_DSP_IN_SCART,
+						MSP_DSP_IN_SCART),
+};
+
+static const struct routing_scheme routing_schemes[] = {
+	[PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
+		.def = routing_scheme0,
+		.cnt = ARRAY_SIZE(routing_scheme0),
+	},
+};
+
 /* This function selects the correct audio input source */
 static void set_stereo(struct pvr2_msp3400_handler *ctxt)
 {
 	struct pvr2_hdw *hdw = ctxt->hdw;
 	struct v4l2_routing route;
+	const struct routing_scheme *sp;
+	unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
 
 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
 
-	route.input = MSP_INPUT_DEFAULT;
-	route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
-	switch (hdw->input_val) {
-	case PVR2_CVAL_INPUT_TV:
-		break;
-	case PVR2_CVAL_INPUT_RADIO:
-		/* Assume that msp34xx also handle FM decoding, in which case
-		   we're still using the tuner. */
-		/* HV: actually it is more likely to be the SCART2 input if
-		   the ivtv experience is any indication. */
-		route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
-				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
-		break;
-	case PVR2_CVAL_INPUT_SVIDEO:
-	case PVR2_CVAL_INPUT_COMPOSITE:
-		/* SCART 1 input */
-		route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
-				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
-		break;
+	if ((sid < ARRAY_SIZE(routing_schemes)) &&
+	    ((sp = routing_schemes + sid) != 0) &&
+	    (hdw->input_val >= 0) &&
+	    (hdw->input_val < sp->cnt)) {
+		route.input = sp->def[hdw->input_val];
+	} else {
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "*** WARNING *** i2c msp3400 v4l2 set_stereo:"
+			   " Invalid routing scheme (%u) and/or input (%d)",
+			   sid,hdw->input_val);
+		return;
 	}
+	route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
 	pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
 }
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index 22719ba861ac..9d94aed2e12d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -31,52 +31,32 @@
 
 static void pvr2_context_destroy(struct pvr2_context *mp)
 {
-	if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
 	pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
-	if (mp->workqueue) {
-		flush_workqueue(mp->workqueue);
-		destroy_workqueue(mp->workqueue);
-	}
+	if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
 	kfree(mp);
 }
 
 
-static void pvr2_context_trigger_poll(struct pvr2_context *mp)
-{
-	queue_work(mp->workqueue,&mp->workpoll);
-}
-
-
-static void pvr2_context_poll(struct work_struct *work)
-{
-	struct pvr2_context *mp =
-		container_of(work, struct pvr2_context, workpoll);
-	pvr2_context_enter(mp); do {
-		pvr2_hdw_poll(mp->hdw);
-	} while (0); pvr2_context_exit(mp);
-}
-
-
-static void pvr2_context_setup(struct work_struct *work)
+static void pvr2_context_state_check(struct pvr2_context *mp)
 {
-	struct pvr2_context *mp =
-		container_of(work, struct pvr2_context, workinit);
+	if (mp->init_flag) return;
+
+	switch (pvr2_hdw_get_state(mp->hdw)) {
+	case PVR2_STATE_WARM: break;
+	case PVR2_STATE_ERROR: break;
+	case PVR2_STATE_READY: break;
+	case PVR2_STATE_RUN: break;
+	default: return;
+	}
 
 	pvr2_context_enter(mp); do {
-		if (!pvr2_hdw_dev_ok(mp->hdw)) break;
-		pvr2_hdw_setup(mp->hdw);
-		pvr2_hdw_setup_poll_trigger(
-			mp->hdw,
-			(void (*)(void *))pvr2_context_trigger_poll,
-			mp);
-		if (!pvr2_hdw_dev_ok(mp->hdw)) break;
-		if (!pvr2_hdw_init_ok(mp->hdw)) break;
+		mp->init_flag = !0;
 		mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
 		if (mp->setup_func) {
 			mp->setup_func(mp);
 		}
 	} while (0); pvr2_context_exit(mp);
-}
+ }
 
 
 struct pvr2_context *pvr2_context_create(
@@ -96,11 +76,10 @@ struct pvr2_context *pvr2_context_create(
 		mp = NULL;
 		goto done;
 	}
-
-	mp->workqueue = create_singlethread_workqueue("pvrusb2");
-	INIT_WORK(&mp->workinit, pvr2_context_setup);
-	INIT_WORK(&mp->workpoll, pvr2_context_poll);
-	queue_work(mp->workqueue,&mp->workinit);
+	pvr2_hdw_set_state_callback(mp->hdw,
+				    (void (*)(void *))pvr2_context_state_check,
+				    mp);
+	pvr2_context_state_check(mp);
  done:
 	return mp;
 }
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h
index 6327fa1f7e4f..a04187a93225 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.h
@@ -45,14 +45,11 @@ struct pvr2_context {
 	struct pvr2_context_stream video_stream;
 	struct mutex mutex;
 	int disconnect_flag;
+	int init_flag;
 
 	/* Called after pvr2_context initialization is complete */
 	void (*setup_func)(struct pvr2_context *);
 
-	/* Work queue overhead for out-of-line processing */
-	struct workqueue_struct *workqueue;
-	struct work_struct workinit;
-	struct work_struct workpoll;
 };
 
 struct pvr2_channel {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index e8a9252c7df6..ffdc45c324e5 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -49,34 +49,89 @@ struct pvr2_v4l_cx2584x {
 };
 
 
+struct routing_scheme_item {
+	int vid;
+	int aud;
+};
+
+struct routing_scheme {
+	const struct routing_scheme_item *def;
+	unsigned int cnt;
+};
+
+static const struct routing_scheme_item routing_scheme0[] = {
+	[PVR2_CVAL_INPUT_TV] = {
+		.vid = CX25840_COMPOSITE7,
+		.aud = CX25840_AUDIO8,
+	},
+	[PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
+		.vid = CX25840_COMPOSITE3,
+		.aud = CX25840_AUDIO_SERIAL,
+	},
+	[PVR2_CVAL_INPUT_COMPOSITE] = {
+		.vid = CX25840_COMPOSITE3,
+		.aud = CX25840_AUDIO_SERIAL,
+	},
+	[PVR2_CVAL_INPUT_SVIDEO] = {
+		.vid = CX25840_SVIDEO1,
+		.aud = CX25840_AUDIO_SERIAL,
+	},
+};
+
+/* Specific to gotview device */
+static const struct routing_scheme_item routing_schemegv[] = {
+	[PVR2_CVAL_INPUT_TV] = {
+		.vid = CX25840_COMPOSITE2,
+		.aud = CX25840_AUDIO5,
+	},
+	[PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
+		.vid = CX25840_COMPOSITE1,
+		.aud = CX25840_AUDIO_SERIAL,
+	},
+	[PVR2_CVAL_INPUT_COMPOSITE] = {
+		.vid = CX25840_COMPOSITE1,
+		.aud = CX25840_AUDIO_SERIAL,
+	},
+	[PVR2_CVAL_INPUT_SVIDEO] = {
+		.vid = (CX25840_SVIDEO_LUMA3|CX25840_SVIDEO_CHROMA4),
+		.aud = CX25840_AUDIO_SERIAL,
+	},
+};
+
+static const struct routing_scheme routing_schemes[] = {
+	[PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
+		.def = routing_scheme0,
+		.cnt = ARRAY_SIZE(routing_scheme0),
+	},
+	[PVR2_ROUTING_SCHEME_GOTVIEW] = {
+		.def = routing_schemegv,
+		.cnt = ARRAY_SIZE(routing_schemegv),
+	},
+};
+
 static void set_input(struct pvr2_v4l_cx2584x *ctxt)
 {
 	struct pvr2_hdw *hdw = ctxt->hdw;
 	struct v4l2_routing route;
 	enum cx25840_video_input vid_input;
 	enum cx25840_audio_input aud_input;
+	const struct routing_scheme *sp;
+	unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
 
 	memset(&route,0,sizeof(route));
 
-	switch(hdw->input_val) {
-	case PVR2_CVAL_INPUT_TV:
-		vid_input = CX25840_COMPOSITE7;
-		aud_input = CX25840_AUDIO8;
-		break;
-	case PVR2_CVAL_INPUT_RADIO: // Treat same as composite
-	case PVR2_CVAL_INPUT_COMPOSITE:
-		vid_input = CX25840_COMPOSITE3;
-		aud_input = CX25840_AUDIO_SERIAL;
-		break;
-	case PVR2_CVAL_INPUT_SVIDEO:
-		vid_input = CX25840_SVIDEO1;
-		aud_input = CX25840_AUDIO_SERIAL;
-		break;
-	default:
-		// Just set it to be composite input for now...
-		vid_input = CX25840_COMPOSITE3;
-		aud_input = CX25840_AUDIO_SERIAL;
-		break;
+	if ((sid < ARRAY_SIZE(routing_schemes)) &&
+	    ((sp = routing_schemes + sid) != 0) &&
+	    (hdw->input_val >= 0) &&
+	    (hdw->input_val < sp->cnt)) {
+		vid_input = sp->def[hdw->input_val].vid;
+		aud_input = sp->def[hdw->input_val].aud;
+	} else {
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "*** WARNING *** i2c cx2584x set_input:"
+			   " Invalid routing scheme (%u) and/or input (%d)",
+			   sid,hdw->input_val);
+		return;
 	}
 
 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
@@ -140,7 +195,7 @@ static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
 static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
 {
 	ctxt->client->handler = NULL;
-	ctxt->hdw->decoder_ctrl = NULL;
+	pvr2_hdw_set_decoder(ctxt->hdw,NULL);
 	kfree(ctxt);
 }
 
@@ -241,7 +296,7 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
 	ctxt->client = cp;
 	ctxt->hdw = hdw;
 	ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
-	hdw->decoder_ctrl = &ctxt->ctrl;
+	pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
 	cp->handler = &ctxt->handler;
 	{
 		/*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
index da6441b88f31..fca49d8a9311 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -34,25 +34,26 @@ extern int pvrusb2_debug;
 #define PVR2_TRACE_INIT       (1 <<  5) /* misc initialization steps */
 #define PVR2_TRACE_START_STOP (1 <<  6) /* Streaming start / stop */
 #define PVR2_TRACE_CTL        (1 <<  7) /* commit of control changes */
-#define PVR2_TRACE_DEBUG      (1 <<  8) /* Temporary debug code */
-#define PVR2_TRACE_EEPROM     (1 <<  9) /* eeprom parsing / report */
-#define PVR2_TRACE_STRUCT     (1 << 10) /* internal struct creation */
-#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */
-#define PVR2_TRACE_CREG       (1 << 12) /* Main critical region entry / exit */
-#define PVR2_TRACE_SYSFS      (1 << 13) /* Sysfs driven I/O */
-#define PVR2_TRACE_FIRMWARE   (1 << 14) /* firmware upload actions */
-#define PVR2_TRACE_CHIPS      (1 << 15) /* chip broadcast operation */
-#define PVR2_TRACE_I2C        (1 << 16) /* I2C related stuff */
-#define PVR2_TRACE_I2C_CMD    (1 << 17) /* Software commands to I2C modules */
-#define PVR2_TRACE_I2C_CORE   (1 << 18) /* I2C core debugging */
-#define PVR2_TRACE_I2C_TRAF   (1 << 19) /* I2C traffic through the adapter */
-#define PVR2_TRACE_V4LIOCTL   (1 << 20) /* v4l ioctl details */
-#define PVR2_TRACE_ENCODER    (1 << 21) /* mpeg2 encoder operation */
-#define PVR2_TRACE_BUF_POOL   (1 << 22) /* Track buffer pool management */
-#define PVR2_TRACE_BUF_FLOW   (1 << 23) /* Track buffer flow in system */
-#define PVR2_TRACE_DATA_FLOW  (1 << 24) /* Track data flow */
-#define PVR2_TRACE_DEBUGIFC   (1 << 25) /* Debug interface actions */
-#define PVR2_TRACE_GPIO       (1 << 26) /* GPIO state bit changes */
+#define PVR2_TRACE_STATE      (1 <<  8) /* Device state changes */
+#define PVR2_TRACE_STBITS     (1 <<  9) /* Individual bit state changes */
+#define PVR2_TRACE_EEPROM     (1 << 10) /* eeprom parsing / report */
+#define PVR2_TRACE_STRUCT     (1 << 11) /* internal struct creation */
+#define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */
+#define PVR2_TRACE_CREG       (1 << 13) /* Main critical region entry / exit */
+#define PVR2_TRACE_SYSFS      (1 << 14) /* Sysfs driven I/O */
+#define PVR2_TRACE_FIRMWARE   (1 << 15) /* firmware upload actions */
+#define PVR2_TRACE_CHIPS      (1 << 16) /* chip broadcast operation */
+#define PVR2_TRACE_I2C        (1 << 17) /* I2C related stuff */
+#define PVR2_TRACE_I2C_CMD    (1 << 18) /* Software commands to I2C modules */
+#define PVR2_TRACE_I2C_CORE   (1 << 19) /* I2C core debugging */
+#define PVR2_TRACE_I2C_TRAF   (1 << 20) /* I2C traffic through the adapter */
+#define PVR2_TRACE_V4LIOCTL   (1 << 21) /* v4l ioctl details */
+#define PVR2_TRACE_ENCODER    (1 << 22) /* mpeg2 encoder operation */
+#define PVR2_TRACE_BUF_POOL   (1 << 23) /* Track buffer pool management */
+#define PVR2_TRACE_BUF_FLOW   (1 << 24) /* Track buffer flow in system */
+#define PVR2_TRACE_DATA_FLOW  (1 << 25) /* Track data flow */
+#define PVR2_TRACE_DEBUGIFC   (1 << 26) /* Debug interface actions */
+#define PVR2_TRACE_GPIO       (1 << 27) /* GPIO state bit changes */
 
 
 #endif /* __PVRUSB2_HDW_INTERNAL_H */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index 6f135f4a2497..b0687430fdd4 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -31,14 +31,6 @@ struct debugifc_mask_item {
 	unsigned long msk;
 };
 
-static struct debugifc_mask_item mask_items[] = {
-	{"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)},
-	{"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)},
-	{"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)},
-	{"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)},
-	{"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)},
-};
-
 
 static unsigned int debugifc_count_whitespace(const char *buf,
 					      unsigned int count)
@@ -148,134 +140,14 @@ static int debugifc_match_keyword(const char *buf,unsigned int count,
 }
 
 
-static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
-{
-	struct debugifc_mask_item *mip;
-	unsigned int idx;
-	for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
-		mip = mask_items + idx;
-		if (debugifc_match_keyword(buf,count,mip->name)) {
-			return mip->msk;
-		}
-	}
-	return 0;
-}
-
-
-static int debugifc_print_mask(char *buf,unsigned int sz,
-			       unsigned long msk,unsigned long val)
-{
-	struct debugifc_mask_item *mip;
-	unsigned int idx;
-	int bcnt = 0;
-	int ccnt;
-	for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
-		mip = mask_items + idx;
-		if (!(mip->msk & msk)) continue;
-		ccnt = scnprintf(buf,sz,"%s%c%s",
-				 (bcnt ? " " : ""),
-				 ((mip->msk & val) ? '+' : '-'),
-				 mip->name);
-		sz -= ccnt;
-		buf += ccnt;
-		bcnt += ccnt;
-	}
-	return bcnt;
-}
-
-static unsigned int debugifc_parse_subsys_mask(const char *buf,
-					       unsigned int count,
-					       unsigned long *mskPtr,
-					       unsigned long *valPtr)
-{
-	const char *wptr;
-	unsigned int consume_cnt = 0;
-	unsigned int scnt;
-	unsigned int wlen;
-	int mode;
-	unsigned long m1,msk,val;
-
-	msk = 0;
-	val = 0;
-
-	while (count) {
-		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
-		if (!scnt) break;
-		consume_cnt += scnt; count -= scnt; buf += scnt;
-		if (!wptr) break;
-
-		mode = 0;
-		if (wlen) switch (wptr[0]) {
-		case '+':
-			wptr++;
-			wlen--;
-			break;
-		case '-':
-			mode = 1;
-			wptr++;
-			wlen--;
-			break;
-		}
-		if (!wlen) continue;
-		m1 = debugifc_find_mask(wptr,wlen);
-		if (!m1) break;
-		msk |= m1;
-		if (!mode) val |= m1;
-	}
-	*mskPtr = msk;
-	*valPtr = val;
-	return consume_cnt;
-}
-
-
 int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
 {
 	int bcnt = 0;
 	int ccnt;
-	struct pvr2_hdw_debug_info dbg;
-
-	pvr2_hdw_get_debug_info(hdw,&dbg);
-
-	ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s",
-			 (dbg.big_lock_held ? "held" : "free"),
-			 (dbg.ctl_lock_held ? "held" : "free"));
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	if (dbg.ctl_lock_held) {
-		ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d"
-				 " cmd_wlen=%d cmd_rlen=%d"
-				 " wpend=%d rpend=%d tmout=%d rstatus=%d"
-				 " wstatus=%d",
-				 dbg.cmd_debug_state,dbg.cmd_code,
-				 dbg.cmd_debug_write_len,
-				 dbg.cmd_debug_read_len,
-				 dbg.cmd_debug_write_pend,
-				 dbg.cmd_debug_read_pend,
-				 dbg.cmd_debug_timeout,
-				 dbg.cmd_debug_rstatus,
-				 dbg.cmd_debug_wstatus);
-		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	}
-	ccnt = scnprintf(buf,acnt,"\n");
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = scnprintf(
-		buf,acnt,"driver flags: %s %s %s\n",
-		(dbg.flag_init_ok ? "initialized" : "uninitialized"),
-		(dbg.flag_ok ? "ok" : "fail"),
-		(dbg.flag_disconnected ? "disconnected" : "connected"));
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
+	ccnt = scnprintf(buf,acnt,"Driver state info:\n");
 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags);
+	ccnt = pvr2_hdw_state_report(hdw,buf,acnt);
 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = scnprintf(buf,acnt,"\n");
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags);
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = scnprintf(buf,acnt,"\n");
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-
 	ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 	ccnt = pvr2_i2c_report(hdw,buf,acnt);
@@ -290,7 +162,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
 {
 	int bcnt = 0;
 	int ccnt;
-	unsigned long msk;
 	int ret;
 	u32 gpio_dir,gpio_in,gpio_out;
 
@@ -311,28 +182,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
 			 pvr2_hdw_get_streaming(hdw) ? "on" : "off");
 	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
 
-	msk = pvr2_hdw_subsys_get(hdw);
-	ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = debugifc_print_mask(buf,acnt,msk,msk);
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = scnprintf(buf,acnt,"\n");
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = debugifc_print_mask(buf,acnt,~msk,msk);
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = scnprintf(buf,acnt,"\n");
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-
-	msk = pvr2_hdw_subsys_stream_get(hdw);
-	ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: ");
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = debugifc_print_mask(buf,acnt,msk,msk);
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-	ccnt = scnprintf(buf,acnt,"\n");
-	bcnt += ccnt; acnt -= ccnt; buf += ccnt;
-
 	return bcnt;
 }
 
@@ -369,28 +218,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
 			return pvr2_upload_firmware2(hdw);
 		} else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
 			return pvr2_hdw_cmd_decoder_reset(hdw);
+		} else if (debugifc_match_keyword(wptr,wlen,"worker")) {
+			return pvr2_hdw_untrip(hdw);
 		}
 		return -EINVAL;
-	} else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
-		unsigned long msk = 0;
-		unsigned long val = 0;
-		if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
-			pvr2_trace(PVR2_TRACE_DEBUGIFC,
-				   "debugifc parse error on subsys mask");
-			return -EINVAL;
-		}
-		pvr2_hdw_subsys_bit_chg(hdw,msk,val);
-		return 0;
-	} else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) {
-		unsigned long msk = 0;
-		unsigned long val = 0;
-		if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
-			pvr2_trace(PVR2_TRACE_DEBUGIFC,
-				   "debugifc parse error on stream mask");
-			return -EINVAL;
-		}
-		pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val);
-		return 0;
 	} else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
 		scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
 		if (!scnt) return -EINVAL;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
new file mode 100644
index 000000000000..4df6d6d936fc
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -0,0 +1,217 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2007 Mike Isely <isely@pobox.com>
+ *
+ *  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
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+
+This source file should encompass ALL per-device type information for the
+driver.  To define a new device, add elements to the pvr2_device_table and
+pvr2_device_desc structures.
+
+*/
+
+#include "pvrusb2-devattr.h"
+#include <linux/usb.h>
+/* This is needed in order to pull in tuner type ids... */
+#include <linux/i2c.h>
+#include <media/tuner.h>
+
+
+
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 29xxx */
+
+static const char *pvr2_client_29xxx[] = {
+	"msp3400",
+	"saa7115",
+	"tuner",
+};
+
+static const char *pvr2_fw1_names_29xxx[] = {
+		"v4l-pvrusb2-29xxx-01.fw",
+};
+
+static const struct pvr2_device_desc pvr2_device_29xxx = {
+		.description = "WinTV PVR USB2 Model Category 29xxxx",
+		.shortname = "29xxx",
+		.client_modules.lst = pvr2_client_29xxx,
+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx),
+		.fx2_firmware.lst = pvr2_fw1_names_29xxx,
+		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
+		.flag_has_hauppauge_rom = !0,
+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 24xxx */
+
+static const char *pvr2_client_24xxx[] = {
+	"cx25840",
+	"tuner",
+	"wm8775",
+};
+
+static const char *pvr2_fw1_names_24xxx[] = {
+		"v4l-pvrusb2-24xxx-01.fw",
+};
+
+static const struct pvr2_device_desc pvr2_device_24xxx = {
+		.description = "WinTV PVR USB2 Model Category 24xxxx",
+		.shortname = "24xxx",
+		.client_modules.lst = pvr2_client_24xxx,
+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx),
+		.fx2_firmware.lst = pvr2_fw1_names_24xxx,
+		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx),
+		.flag_has_cx25840 = !0,
+		.flag_has_wm8775 = !0,
+		.flag_has_hauppauge_rom = !0,
+		.flag_has_hauppauge_custom_ir = !0,
+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* GOTVIEW USB2.0 DVD2 */
+
+static const char *pvr2_client_gotview_2[] = {
+	"cx25840",
+	"tuner",
+};
+
+static const struct pvr2_device_desc pvr2_device_gotview_2 = {
+		.description = "Gotview USB 2.0 DVD 2",
+		.shortname = "gv2",
+		.client_modules.lst = pvr2_client_gotview_2,
+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
+		.flag_has_cx25840 = !0,
+		.default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
+};
+
+
+
+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
+/*------------------------------------------------------------------------*/
+/* OnAir Creator */
+
+static const char *pvr2_client_onair_creator[] = {
+	"saa7115",
+	"tuner",
+	"cs53l32a",
+};
+
+static const struct pvr2_device_desc pvr2_device_onair_creator = {
+		.description = "OnAir Creator Hybrid USB tuner",
+		.shortname = "oac",
+		.client_modules.lst = pvr2_client_onair_creator,
+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator),
+		.default_tuner_type = TUNER_LG_TDVS_H06XF,
+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+};
+#endif
+
+
+
+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
+/*------------------------------------------------------------------------*/
+/* OnAir USB 2.0 */
+
+static const char *pvr2_client_onair_usb2[] = {
+	"saa7115",
+	"tuner",
+	"cs53l32a",
+};
+
+static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
+		.description = "OnAir USB2 Hybrid USB tuner",
+		.shortname = "oa2",
+		.client_modules.lst = pvr2_client_onair_usb2,
+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2),
+		.default_tuner_type = TUNER_PHILIPS_ATSC,
+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+};
+#endif
+
+
+
+/*------------------------------------------------------------------------*/
+/* Hauppauge PVR-USB2 Model 75xxx */
+
+static const char *pvr2_client_75xxx[] = {
+	"cx25840",
+	"tuner",
+};
+
+static const char *pvr2_fw1_names_75xxx[] = {
+		"v4l-pvrusb2-73xxx-01.fw",
+};
+
+static const struct pvr2_device_desc pvr2_device_75xxx = {
+		.description = "WinTV PVR USB2 Model Category 75xxxx",
+		.shortname = "75xxx",
+		.client_modules.lst = pvr2_client_75xxx,
+		.client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
+		.fx2_firmware.lst = pvr2_fw1_names_75xxx,
+		.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
+		.flag_has_cx25840 = !0,
+		.flag_has_hauppauge_rom = !0,
+		.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+		.default_std_mask = V4L2_STD_NTSC_M,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+
+struct usb_device_id pvr2_device_table[] = {
+	{ USB_DEVICE(0x2040, 0x2900),
+	  .driver_info = (kernel_ulong_t)&pvr2_device_29xxx},
+	{ USB_DEVICE(0x2040, 0x2400),
+	  .driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
+	{ USB_DEVICE(0x1164, 0x0622),
+	  .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
+	{ USB_DEVICE(0x11ba, 0x1003),
+	  .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
+#endif
+#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
+	{ USB_DEVICE(0x11ba, 0x1001),
+	  .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2},
+#endif
+	{ USB_DEVICE(0x2040, 0x7500),
+	  .driver_info = (kernel_ulong_t)&pvr2_device_75xxx},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, pvr2_device_table);
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
new file mode 100644
index 000000000000..64b467f0637f
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -0,0 +1,119 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *
+ *  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
+ *
+ *  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 __PVRUSB2_DEVATTR_H
+#define __PVRUSB2_DEVATTR_H
+
+#include <linux/mod_devicetable.h>
+#include <linux/videodev2.h>
+
+/*
+
+  This header defines structures used to describe attributes of a device.
+
+*/
+
+
+struct pvr2_string_table {
+	const char **lst;
+	unsigned int cnt;
+};
+
+#define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
+#define PVR2_ROUTING_SCHEME_GOTVIEW 1
+
+/* This describes a particular hardware type (except for the USB device ID
+   which must live in a separate structure due to environmental
+   constraints).  See the top of pvrusb2-hdw.c for where this is
+   instantiated. */
+struct pvr2_device_desc {
+	/* Single line text description of hardware */
+	const char *description;
+
+	/* Single token identifier for hardware */
+	const char *shortname;
+
+	/* List of additional client modules we need to load */
+	struct pvr2_string_table client_modules;
+
+	/* List of FX2 firmware file names we should search; if empty then
+	   FX2 firmware check / load is skipped and we assume the device
+	   was initialized from internal ROM. */
+	struct pvr2_string_table fx2_firmware;
+
+	/* Signal routing scheme used by device, contains one of
+	   PVR2_ROUTING_SCHEME_XXX.  Schemes have to be defined as we
+	   encounter them.  This is an arbitrary integer scheme id; its
+	   meaning is contained entirely within the driver and is
+	   interpreted by logic which must send commands to the chip-level
+	   drivers (search for things which touch this field). */
+	unsigned int signal_routing_scheme;
+
+	/* V4L tuner type ID to use with this device (only used if the
+	   driver could not discover the type any other way). */
+	int default_tuner_type;
+
+	/* Initial standard bits to use for this device, if not zero.
+	   Anything set here is also implied as an available standard.
+	   Note: This is ignored if overridden on the module load line via
+	   the video_std module option. */
+	v4l2_std_id default_std_mask;
+
+	/* If set, we don't bother trying to load cx23416 firmware. */
+	char flag_skip_cx23416_firmware;
+
+	/* Device has a hauppauge eeprom which we can interrogate. */
+	char flag_has_hauppauge_rom;
+
+	/* Device does not require a powerup command to be issued. */
+	char flag_no_powerup;
+
+	/* Device has a cx25840 - this enables special additional logic to
+	   handle it. */
+	char flag_has_cx25840;
+
+	/* Device has a wm8775 - this enables special additional logic to
+	   ensure that it is found. */
+	char flag_has_wm8775;
+
+	/* Device has IR hardware that can be faked into looking like a
+	   normal Hauppauge i2c IR receiver.  This is currently very
+	   specific to the 24xxx device, where Hauppauge had replaced their
+	   'standard' I2C IR receiver with a bunch of FPGA logic controlled
+	   directly via the FX2.  Turning this on tells the pvrusb2 driver
+	   to virtualize the presence of the non-existant IR receiver chip and
+	   implement the virtual receiver in terms of appropriate FX2
+	   commands. */
+	char flag_has_hauppauge_custom_ir;
+};
+
+extern struct usb_device_id pvr2_device_table[];
+
+#endif /* __PVRUSB2_HDW_INTERNAL_H */
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
index 45cbca0143ca..5ef005947b04 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
@@ -144,6 +144,7 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
 	trace_eeprom("serial_number=%d",tvdata.serial_number);
 	trace_eeprom("rev_str=%s",tvdata.rev_str);
 	hdw->tuner_type = tvdata.tuner_type;
+	hdw->tuner_updated = !0;
 	hdw->serial_number = tvdata.serial_number;
 	hdw->std_mask_eeprom = tvdata.tuner_formats;
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 205087a3e136..64062879981e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -140,7 +140,7 @@ static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,
    cx2341x.ko to write to our encoder (by handing it a pointer to this
    function).  For earlier kernels this doesn't really matter. */
 static int pvr2_encoder_cmd(void *ctxt,
-			    int cmd,
+			    u32 cmd,
 			    int arg_cnt_send,
 			    int arg_cnt_recv,
 			    u32 *argp)
@@ -209,7 +209,7 @@ static int pvr2_encoder_cmd(void *ctxt,
 
 	LOCK_TAKE(hdw->ctl_lock); do {
 
-		if (!hdw->flag_encoder_ok) {
+		if (!hdw->state_encoder_ok) {
 			ret = -EIO;
 			break;
 		}
@@ -278,12 +278,15 @@ static int pvr2_encoder_cmd(void *ctxt,
 			ret = -EBUSY;
 		}
 		if (ret) {
-			hdw->flag_encoder_ok = 0;
+			hdw->state_encoder_ok = 0;
+			pvr2_trace(PVR2_TRACE_STBITS,
+				   "State bit %s <-- %s",
+				   "state_encoder_ok",
+				   (hdw->state_encoder_ok ? "true" : "false"));
 			pvr2_trace(
 				PVR2_TRACE_ERROR_LEGS,
 				"Giving up on command."
-				"  It is likely that"
-				" this is a bad idea...");
+				"  This is normally recovered by the driver.");
 			break;
 		}
 		wrData[0] = 0x7;
@@ -366,13 +369,13 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
 
 	/* This ENC_MISC(3,encMisc3Arg) command is critical - without
 	   it there will eventually be video corruption.  Also, the
-	   29xxx case is strange - the Windows driver is passing 1
-	   regardless of device type but if we have 1 for 29xxx device
-	   the video turns sluggish.  */
-	switch (hdw->hdw_type) {
-	case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break;
-	case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break;
-	default: break;
+	   saa7115 case is strange - the Windows driver is passing 1
+	   regardless of device type but if we have 1 for saa7115
+	   devices the video turns sluggish.  */
+	if (hdw->hdw_desc->flag_has_cx25840) {
+		encMisc3Arg = 1;
+	} else {
+		encMisc3Arg = 0;
 	}
 	ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,
 				 encMisc3Arg,0,0);
@@ -394,6 +397,24 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
 	return ret;
 }
 
+int pvr2_encoder_adjust(struct pvr2_hdw *hdw)
+{
+	int ret;
+	ret = cx2341x_update(hdw,pvr2_encoder_cmd,
+			     (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
+			     &hdw->enc_ctl_state);
+	if (ret) {
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "Error from cx2341x module code=%d",ret);
+	} else {
+		memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
+		       sizeof(struct cx2341x_mpeg_params));
+		hdw->enc_cur_valid = !0;
+	}
+	return ret;
+}
+
+
 int pvr2_encoder_configure(struct pvr2_hdw *hdw)
 {
 	int ret;
@@ -412,7 +433,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
 
 	/* saa7115: 0xf0 */
 	val = 0xf0;
-	if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+	if (hdw->hdw_desc->flag_has_cx25840) {
 		/* ivtv cx25840: 0x140 */
 		val = 0x140;
 	}
@@ -436,18 +457,10 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
 		return ret;
 	}
 
-	ret = cx2341x_update(hdw,pvr2_encoder_cmd,
-			     (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
-			     &hdw->enc_ctl_state);
-	if (ret) {
-		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-			   "Error from cx2341x module code=%d",ret);
-		return ret;
-	}
-
-	ret = 0;
+	ret = pvr2_encoder_adjust(hdw);
+	if (ret) return ret;
 
-	if (!ret) ret = pvr2_encoder_vcmd(
+	ret = pvr2_encoder_vcmd(
 		hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
 
 	if (ret) {
@@ -456,10 +469,6 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
 		return ret;
 	}
 
-	hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
-	memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
-	       sizeof(struct cx2341x_mpeg_params));
-	hdw->enc_cur_valid = !0;
 	return 0;
 }
 
@@ -478,7 +487,7 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
 	pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
 			  hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
 
-	switch (hdw->config) {
+	switch (hdw->active_stream_type) {
 	case pvr2_config_vbi:
 		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
 					   0x01,0x14);
@@ -492,9 +501,6 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
 					   0,0x13);
 		break;
 	}
-	if (!status) {
-		hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
-	}
 	return status;
 }
 
@@ -505,7 +511,7 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
 	/* mask all interrupts */
 	pvr2_write_register(hdw, 0x0048, 0xffffffff);
 
-	switch (hdw->config) {
+	switch (hdw->active_stream_type) {
 	case pvr2_config_vbi:
 		status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
 					   0x01,0x01,0x14);
@@ -526,9 +532,6 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
 	pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
 	pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
 
-	if (!status) {
-		hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
-	}
 	return status;
 }
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
index 01b5a0b89c03..54caf2e3c428 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
@@ -25,6 +25,7 @@
 
 struct pvr2_hdw;
 
+int pvr2_encoder_adjust(struct pvr2_hdw *);
 int pvr2_encoder_configure(struct pvr2_hdw *);
 int pvr2_encoder_start(struct pvr2_hdw *);
 int pvr2_encoder_stop(struct pvr2_hdw *);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index f873994b088c..d7a216b41b72 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -35,10 +35,12 @@
 
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
+#include <linux/workqueue.h>
 #include <linux/mutex.h>
 #include "pvrusb2-hdw.h"
 #include "pvrusb2-io.h"
 #include <media/cx2341x.h>
+#include "pvrusb2-devattr.h"
 
 /* Legal values for PVR2_CID_HSM */
 #define PVR2_CVAL_HSM_FAIL 0
@@ -161,10 +163,6 @@ struct pvr2_decoder_ctrl {
 #define FW1_STATE_RELOAD 3
 #define FW1_STATE_OK 4
 
-/* Known major hardware variants, keyed from device ID */
-#define PVR2_HDW_TYPE_29XXX 0
-#define PVR2_HDW_TYPE_24XXX 1
-
 typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
 #define PVR2_I2C_FUNC_CNT 128
 
@@ -176,8 +174,15 @@ struct pvr2_hdw {
 	struct usb_device *usb_dev;
 	struct usb_interface *usb_intf;
 
-	/* Device type, one of PVR2_HDW_TYPE_xxxxx */
-	unsigned int hdw_type;
+	/* Device description, anything that must adjust behavior based on
+	   device specific info will use information held here. */
+	const struct pvr2_device_desc *hdw_desc;
+
+	/* Kernel worker thread handling */
+	struct workqueue_struct *workqueue;
+	struct work_struct workpoll;     /* Update driver state */
+	struct work_struct worki2csync;  /* Update i2c clients */
+	struct work_struct workinit;     /* Driver initialization sequence */
 
 	/* Video spigot */
 	struct pvr2_stream *vid_stream;
@@ -186,9 +191,6 @@ struct pvr2_hdw {
 	struct mutex big_lock_mutex;
 	int big_lock_held;  /* For debugging */
 
-	void (*poll_trigger_func)(void *);
-	void *poll_trigger_data;
-
 	char name[32];
 
 	/* I2C stuff */
@@ -215,9 +217,9 @@ struct pvr2_hdw {
 	struct urb *ctl_read_urb;
 	unsigned char *ctl_write_buffer;
 	unsigned char *ctl_read_buffer;
-	volatile int ctl_write_pend_flag;
-	volatile int ctl_read_pend_flag;
-	volatile int ctl_timeout_flag;
+	int ctl_write_pend_flag;
+	int ctl_read_pend_flag;
+	int ctl_timeout_flag;
 	struct completion ctl_done;
 	unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE];
 	int cmd_debug_state;               // Low level command debugging info
@@ -225,14 +227,48 @@ struct pvr2_hdw {
 	unsigned int cmd_debug_write_len;  //
 	unsigned int cmd_debug_read_len;   //
 
+	/* Bits of state that describe what is going on with various parts
+	   of the driver. */
+	int state_encoder_ok;         /* Encoder is operational */
+	int state_encoder_run;        /* Encoder is running */
+	int state_encoder_config;     /* Encoder is configured */
+	int state_encoder_waitok;     /* Encoder pre-wait done */
+	int state_decoder_run;        /* Decoder is running */
+	int state_usbstream_run;      /* FX2 is streaming */
+	int state_decoder_quiescent;  /* Decoder idle for > 50msec */
+	int state_pipeline_config;    /* Pipeline is configured */
+	int state_pipeline_req;                /* Somebody wants to stream */
+	int state_pipeline_pause;              /* Pipeline must be paused */
+	int state_pipeline_idle;               /* Pipeline not running */
+
+	/* This is the master state of the driver.  It is the combined
+	   result of other bits of state.  Examining this will indicate the
+	   overall state of the driver.  Values here are one of
+	   PVR2_STATE_xxxx */
+	unsigned int master_state;
+
+	/* True if states must be re-evaluated */
+	int state_stale;
+
+	void (*state_func)(void *);
+	void *state_data;
+
+	/* Timer for measuring decoder settling time */
+	struct timer_list quiescent_timer;
+
+	/* Timer for measuring encoder pre-wait time */
+	struct timer_list encoder_wait_timer;
+
+	/* Place to block while waiting for state changes */
+	wait_queue_head_t state_wait_data;
+
+
 	int flag_ok;            /* device in known good state */
 	int flag_disconnected;  /* flag_ok == 0 due to disconnect */
 	int flag_init_ok;       /* true if structure is fully initialized */
-	int flag_streaming_enabled; /* true if streaming should be on */
 	int fw1_state;          /* current situation with fw1 */
-	int flag_encoder_ok;    /* True if encoder is healthy */
-
-	int flag_decoder_is_tuned;
+	int flag_decoder_missed;/* We've noticed missing decoder */
+	int flag_tripped;       /* Indicates overall failure to start */
 
 	struct pvr2_decoder_ctrl *decoder_ctrl;
 
@@ -241,12 +277,6 @@ struct pvr2_hdw {
 	unsigned int fw_size;
 	int fw_cpu_flag; /* True if we are dealing with the CPU */
 
-	// Which subsystem pieces have been enabled / configured
-	unsigned long subsys_enabled_mask;
-
-	// Which subsystems are manipulated to enable streaming
-	unsigned long subsys_stream_mask;
-
 	// True if there is a request to trigger logging of state in each
 	// module.
 	int log_requested;
@@ -296,13 +326,16 @@ struct pvr2_hdw {
 	/* Location of eeprom or a negative number if none */
 	int eeprom_addr;
 
-	enum pvr2_config config;
+	enum pvr2_config active_stream_type;
+	enum pvr2_config desired_stream_type;
 
 	/* Control state needed for cx2341x module */
 	struct cx2341x_mpeg_params enc_cur_state;
 	struct cx2341x_mpeg_params enc_ctl_state;
 	/* True if an encoder attribute has changed */
 	int enc_stale;
+	/* True if an unsafe encoder attribute has changed */
+	int enc_unsafe_stale;
 	/* True if enc_cur_state is valid */
 	int enc_cur_valid;
 
@@ -332,6 +365,7 @@ struct pvr2_hdw {
 
 /* This function gets the current frequency */
 unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
+void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *);
 
 #endif /* __PVRUSB2_HDW_INTERNAL_H */
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 402c59488253..41ae980405ed 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -41,47 +41,6 @@
 #define TV_MIN_FREQ     55250000L
 #define TV_MAX_FREQ    850000000L
 
-struct usb_device_id pvr2_device_table[] = {
-	[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
-	[PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
-	{ }
-};
-
-MODULE_DEVICE_TABLE(usb, pvr2_device_table);
-
-static const char *pvr2_device_names[] = {
-	[PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
-	[PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
-};
-
-struct pvr2_string_table {
-	const char **lst;
-	unsigned int cnt;
-};
-
-// Names of other client modules to request for 24xxx model hardware
-static const char *pvr2_client_24xxx[] = {
-	"cx25840",
-	"tuner",
-	"wm8775",
-};
-
-// Names of other client modules to request for 29xxx model hardware
-static const char *pvr2_client_29xxx[] = {
-	"msp3400",
-	"saa7115",
-	"tuner",
-};
-
-static struct pvr2_string_table pvr2_client_lists[] = {
-	[PVR2_HDW_TYPE_29XXX] = {
-		pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
-	},
-	[PVR2_HDW_TYPE_24XXX] = {
-		pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
-	},
-};
-
 static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
 static DEFINE_MUTEX(pvr2_unit_mtx);
 
@@ -246,32 +205,46 @@ static const char *control_values_hsm[] = {
 };
 
 
-static const char *control_values_subsystem[] = {
-	[PVR2_SUBSYS_B_ENC_FIRMWARE]  = "enc_firmware",
-	[PVR2_SUBSYS_B_ENC_CFG] = "enc_config",
-	[PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run",
-	[PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run",
-	[PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
+static const char *pvr2_state_names[] = {
+	[PVR2_STATE_NONE] =    "none",
+	[PVR2_STATE_DEAD] =    "dead",
+	[PVR2_STATE_COLD] =    "cold",
+	[PVR2_STATE_WARM] =    "warm",
+	[PVR2_STATE_ERROR] =   "error",
+	[PVR2_STATE_READY] =   "ready",
+	[PVR2_STATE_RUN] =     "run",
 };
 
+
+static void pvr2_hdw_state_sched(struct pvr2_hdw *);
+static int pvr2_hdw_state_eval(struct pvr2_hdw *);
 static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
+static void pvr2_hdw_worker_i2c(struct work_struct *work);
+static void pvr2_hdw_worker_poll(struct work_struct *work);
+static void pvr2_hdw_worker_init(struct work_struct *work);
+static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
+static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
+static void pvr2_hdw_state_log_state(struct pvr2_hdw *);
 static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
-static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
+static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw);
 static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
 static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
 static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
-static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
-static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
-					    unsigned long msk,
-					    unsigned long val);
-static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
-						   unsigned long msk,
-						   unsigned long val);
+static void pvr2_hdw_quiescent_timeout(unsigned long);
+static void pvr2_hdw_encoder_wait_timeout(unsigned long);
 static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
 				unsigned int timeout,int probe_fl,
 				void *write_data,unsigned int write_len,
 				void *read_data,unsigned int read_len);
 
+
+static void trace_stbit(const char *name,int val)
+{
+	pvr2_trace(PVR2_TRACE_STBITS,
+		   "State bit %s <-- %s",
+		   name,(val ? "true" : "false"));
+}
+
 static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
 {
 	struct pvr2_hdw *hdw = cptr->hdw;
@@ -380,8 +353,8 @@ static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
 
 static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
 {
-	/* Actual minimum depends on device type. */
-	if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+	/* Actual minimum depends on device digitizer type. */
+	if (cptr->hdw->hdw_desc->flag_has_cx25840) {
 		*vp = 75;
 	} else {
 		*vp = 17;
@@ -480,6 +453,7 @@ static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
 static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr)
 {
 	cptr->hdw->enc_stale = 0;
+	cptr->hdw->enc_unsafe_stale = 0;
 }
 
 static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
@@ -502,6 +476,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
 static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
 {
 	int ret;
+	struct pvr2_hdw *hdw = cptr->hdw;
 	struct v4l2_ext_controls cs;
 	struct v4l2_ext_control c1;
 	memset(&cs,0,sizeof(cs));
@@ -510,10 +485,22 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
 	cs.count = 1;
 	c1.id = cptr->info->v4l_id;
 	c1.value = v;
-	ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
+	ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state,
+				hdw->state_encoder_run, &cs,
 				VIDIOC_S_EXT_CTRLS);
+	if (ret == -EBUSY) {
+		/* Oops.  cx2341x is telling us it's not safe to change
+		   this control while we're capturing.  Make a note of this
+		   fact so that the pipeline will be stopped the next time
+		   controls are committed.  Then go on ahead and store this
+		   change anyway. */
+		ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state,
+					0, &cs,
+					VIDIOC_S_EXT_CTRLS);
+		if (!ret) hdw->enc_unsafe_stale = !0;
+	}
 	if (ret) return ret;
-	cptr->hdw->enc_stale = !0;
+	hdw->enc_stale = !0;
 	return 0;
 }
 
@@ -544,7 +531,13 @@ static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr)
 
 static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp)
 {
-	*vp = cptr->hdw->flag_streaming_enabled;
+	*vp = cptr->hdw->state_pipeline_req;
+	return 0;
+}
+
+static int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp)
+{
+	*vp = cptr->hdw->master_state;
 	return 0;
 }
 
@@ -657,29 +650,6 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
 	return 0;
 }
 
-static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp)
-{
-	*vp = cptr->hdw->subsys_enabled_mask;
-	return 0;
-}
-
-static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v)
-{
-	pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v);
-	return 0;
-}
-
-static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp)
-{
-	*vp = cptr->hdw->subsys_stream_mask;
-	return 0;
-}
-
-static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v)
-{
-	pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v);
-	return 0;
-}
 
 static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
 {
@@ -915,6 +885,11 @@ static const struct pvr2_ctl_info control_defs[] = {
 		.get_value = ctrl_hsm_get,
 		DEFENUM(control_values_hsm),
 	},{
+		.desc = "Master State",
+		.name = "master_state",
+		.get_value = ctrl_masterstate_get,
+		DEFENUM(pvr2_state_names),
+	},{
 		.desc = "Signal Present",
 		.name = "signal_present",
 		.get_value = ctrl_signal_get,
@@ -955,20 +930,6 @@ static const struct pvr2_ctl_info control_defs[] = {
 		.sym_to_val = ctrl_std_sym_to_val,
 		.type = pvr2_ctl_bitmask,
 	},{
-		.desc = "Subsystem enabled mask",
-		.name = "debug_subsys_mask",
-		.skip_init = !0,
-		.get_value = ctrl_subsys_get,
-		.set_value = ctrl_subsys_set,
-		DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
-	},{
-		.desc = "Subsystem stream mask",
-		.name = "debug_subsys_stream_mask",
-		.skip_init = !0,
-		.get_value = ctrl_subsys_stream_get,
-		.set_value = ctrl_subsys_stream_set,
-		DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
-	},{
 		.desc = "Video Standard Name",
 		.name = "video_standard",
 		.internal_id = PVR2_CID_STDENUM,
@@ -1129,25 +1090,13 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
 	unsigned int pipe;
 	int ret;
 	u16 address;
-	static const char *fw_files_29xxx[] = {
-		"v4l-pvrusb2-29xxx-01.fw",
-	};
-	static const char *fw_files_24xxx[] = {
-		"v4l-pvrusb2-24xxx-01.fw",
-	};
-	static const struct pvr2_string_table fw_file_defs[] = {
-		[PVR2_HDW_TYPE_29XXX] = {
-			fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
-		},
-		[PVR2_HDW_TYPE_24XXX] = {
-			fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
-		},
-	};
 
-	if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) ||
-	    (!fw_file_defs[hdw->hdw_type].lst)) {
+	if (!hdw->hdw_desc->fx2_firmware.cnt) {
 		hdw->fw1_state = FW1_STATE_OK;
-		return 0;
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "Connected device type defines"
+			   " no firmware to upload; ignoring firmware");
+		return -ENOTTY;
 	}
 
 	hdw->fw1_state = FW1_STATE_FAILED; // default result
@@ -1155,8 +1104,8 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
 	trace_firmware("pvr2_upload_firmware1");
 
 	ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller",
-				   fw_file_defs[hdw->hdw_type].cnt,
-				   fw_file_defs[hdw->hdw_type].lst);
+				   hdw->hdw_desc->fx2_firmware.cnt,
+				   hdw->hdw_desc->fx2_firmware.lst);
 	if (ret < 0) {
 		if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING;
 		return ret;
@@ -1231,8 +1180,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
 		CX2341X_FIRM_ENC_FILENAME,
 	};
 
-	if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) &&
-	    (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) {
+	if (hdw->hdw_desc->flag_skip_cx23416_firmware) {
 		return 0;
 	}
 
@@ -1248,8 +1196,6 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
 	   time we configure the encoder, then we'll fully configure it. */
 	hdw->enc_cur_valid = 0;
 
-	hdw->flag_encoder_ok = 0;
-
 	/* First prepare firmware loading */
 	ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
 	ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
@@ -1347,293 +1293,129 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
 	if (ret) {
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
 			   "firmware2 upload post-proc failure");
-	} else {
-		hdw->flag_encoder_ok = !0;
-		hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE);
 	}
 	return ret;
 }
 
 
-#define FIRMWARE_RECOVERY_BITS \
-	((1<<PVR2_SUBSYS_B_ENC_CFG) | \
-	 (1<<PVR2_SUBSYS_B_ENC_RUN) | \
-	 (1<<PVR2_SUBSYS_B_ENC_FIRMWARE) | \
-	 (1<<PVR2_SUBSYS_B_USBSTREAM_RUN))
-
-/*
-
-  This single function is key to pretty much everything.  The pvrusb2
-  device can logically be viewed as a series of subsystems which can be
-  stopped / started or unconfigured / configured.  To get things streaming,
-  one must configure everything and start everything, but there may be
-  various reasons over time to deconfigure something or stop something.
-  This function handles all of this activity.  Everything EVERYWHERE that
-  must affect a subsystem eventually comes here to do the work.
-
-  The current state of all subsystems is represented by a single bit mask,
-  known as subsys_enabled_mask.  The bit positions are defined by the
-  PVR2_SUBSYS_xxxx macros, with one subsystem per bit position.  At any
-  time the set of configured or active subsystems can be queried just by
-  looking at that mask.  To change bits in that mask, this function here
-  must be called.  The "msk" argument indicates which bit positions to
-  change, and the "val" argument defines the new values for the positions
-  defined by "msk".
-
-  There is a priority ordering of starting / stopping things, and for
-  multiple requested changes, this function implements that ordering.
-  (Thus we will act on a request to load encoder firmware before we
-  configure the encoder.)  In addition to priority ordering, there is a
-  recovery strategy implemented here.  If a particular step fails and we
-  detect that failure, this function will clear the affected subsystem bits
-  and restart.  Thus we have a means for recovering from a dead encoder:
-  Clear all bits that correspond to subsystems that we need to restart /
-  reconfigure and start over.
-
-*/
-static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
-					    unsigned long msk,
-					    unsigned long val)
-{
-	unsigned long nmsk;
-	unsigned long vmsk;
-	int ret;
-	unsigned int tryCount = 0;
-
-	if (!hdw->flag_ok) return;
-
-	msk &= PVR2_SUBSYS_ALL;
-	nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk);
-	nmsk &= PVR2_SUBSYS_ALL;
-
-	for (;;) {
-		tryCount++;
-		if (!((nmsk ^ hdw->subsys_enabled_mask) &
-		      PVR2_SUBSYS_ALL)) break;
-		if (tryCount > 4) {
-			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-				   "Too many retries when configuring device;"
-				   " giving up");
-			pvr2_hdw_render_useless(hdw);
-			break;
-		}
-		if (tryCount > 1) {
-			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-				   "Retrying device reconfiguration");
-		}
-		pvr2_trace(PVR2_TRACE_INIT,
-			   "subsys mask changing 0x%lx:0x%lx"
-			   " from 0x%lx to 0x%lx",
-			   msk,val,hdw->subsys_enabled_mask,nmsk);
-
-		vmsk = (nmsk ^ hdw->subsys_enabled_mask) &
-			hdw->subsys_enabled_mask;
-		if (vmsk) {
-			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
-				pvr2_trace(PVR2_TRACE_CTL,
-					   "/*---TRACE_CTL----*/"
-					   " pvr2_encoder_stop");
-				ret = pvr2_encoder_stop(hdw);
-				if (ret) {
-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-						   "Error recovery initiated");
-					hdw->subsys_enabled_mask &=
-						~FIRMWARE_RECOVERY_BITS;
-					continue;
-				}
-			}
-			if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
-				pvr2_trace(PVR2_TRACE_CTL,
-					   "/*---TRACE_CTL----*/"
-					   " pvr2_hdw_cmd_usbstream(0)");
-				pvr2_hdw_cmd_usbstream(hdw,0);
-			}
-			if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
-				pvr2_trace(PVR2_TRACE_CTL,
-					   "/*---TRACE_CTL----*/"
-					   " decoder disable");
-				if (hdw->decoder_ctrl) {
-					hdw->decoder_ctrl->enable(
-						hdw->decoder_ctrl->ctxt,0);
-				} else {
-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-						   "WARNING:"
-						   " No decoder present");
-				}
-				hdw->subsys_enabled_mask &=
-					~(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
-			}
-			if (vmsk & PVR2_SUBSYS_CFG_ALL) {
-				hdw->subsys_enabled_mask &=
-					~(vmsk & PVR2_SUBSYS_CFG_ALL);
-			}
-		}
-		vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk;
-		if (vmsk) {
-			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_FIRMWARE)) {
-				pvr2_trace(PVR2_TRACE_CTL,
-					   "/*---TRACE_CTL----*/"
-					   " pvr2_upload_firmware2");
-				ret = pvr2_upload_firmware2(hdw);
-				if (ret) {
-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-						   "Failure uploading encoder"
-						   " firmware");
-					pvr2_hdw_render_useless(hdw);
-					break;
-				}
-			}
-			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_CFG)) {
-				pvr2_trace(PVR2_TRACE_CTL,
-					   "/*---TRACE_CTL----*/"
-					   " pvr2_encoder_configure");
-				ret = pvr2_encoder_configure(hdw);
-				if (ret) {
-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-						   "Error recovery initiated");
-					hdw->subsys_enabled_mask &=
-						~FIRMWARE_RECOVERY_BITS;
-					continue;
-				}
-			}
-			if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
-				pvr2_trace(PVR2_TRACE_CTL,
-					   "/*---TRACE_CTL----*/"
-					   " decoder enable");
-				if (hdw->decoder_ctrl) {
-					hdw->decoder_ctrl->enable(
-						hdw->decoder_ctrl->ctxt,!0);
-				} else {
-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-						   "WARNING:"
-						   " No decoder present");
-				}
-				hdw->subsys_enabled_mask |=
-					(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
-			}
-			if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
-				pvr2_trace(PVR2_TRACE_CTL,
-					   "/*---TRACE_CTL----*/"
-					   " pvr2_hdw_cmd_usbstream(1)");
-				pvr2_hdw_cmd_usbstream(hdw,!0);
-			}
-			if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
-				pvr2_trace(PVR2_TRACE_CTL,
-					   "/*---TRACE_CTL----*/"
-					   " pvr2_encoder_start");
-				ret = pvr2_encoder_start(hdw);
-				if (ret) {
-					pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-						   "Error recovery initiated");
-					hdw->subsys_enabled_mask &=
-						~FIRMWARE_RECOVERY_BITS;
-					continue;
-				}
-			}
-		}
+static const char *pvr2_get_state_name(unsigned int st)
+{
+	if (st < ARRAY_SIZE(pvr2_state_names)) {
+		return pvr2_state_names[st];
 	}
+	return "???";
 }
 
-
-void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
-			     unsigned long msk,unsigned long val)
+static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
 {
-	LOCK_TAKE(hdw->big_lock); do {
-		pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val);
-	} while (0); LOCK_GIVE(hdw->big_lock);
+	if (!hdw->decoder_ctrl) {
+		if (!hdw->flag_decoder_missed) {
+			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+				   "WARNING: No decoder present");
+			hdw->flag_decoder_missed = !0;
+			trace_stbit("flag_decoder_missed",
+				    hdw->flag_decoder_missed);
+		}
+		return -EIO;
+	}
+	hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl);
+	return 0;
 }
 
 
-unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw)
+void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr)
 {
-	return hdw->subsys_enabled_mask;
+	if (hdw->decoder_ctrl == ptr) return;
+	hdw->decoder_ctrl = ptr;
+	if (hdw->decoder_ctrl && hdw->flag_decoder_missed) {
+		hdw->flag_decoder_missed = 0;
+		trace_stbit("flag_decoder_missed",
+			    hdw->flag_decoder_missed);
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "Decoder has appeared");
+		pvr2_hdw_state_sched(hdw);
+	}
 }
 
 
-unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw)
+int pvr2_hdw_get_state(struct pvr2_hdw *hdw)
 {
-	return hdw->subsys_stream_mask;
+	return hdw->master_state;
 }
 
 
-static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
-						   unsigned long msk,
-						   unsigned long val)
+static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw)
 {
-	unsigned long val2;
-	msk &= PVR2_SUBSYS_ALL;
-	val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk));
-	pvr2_trace(PVR2_TRACE_INIT,
-		   "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx",
-		   msk,val,hdw->subsys_stream_mask,val2);
-	hdw->subsys_stream_mask = val2;
+	if (!hdw->flag_tripped) return 0;
+	hdw->flag_tripped = 0;
+	pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+		   "Clearing driver error statuss");
+	return !0;
 }
 
 
-void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
-				    unsigned long msk,
-				    unsigned long val)
+int pvr2_hdw_untrip(struct pvr2_hdw *hdw)
 {
+	int fl;
 	LOCK_TAKE(hdw->big_lock); do {
-		pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val);
+		fl = pvr2_hdw_untrip_unlocked(hdw);
 	} while (0); LOCK_GIVE(hdw->big_lock);
+	if (fl) pvr2_hdw_state_sched(hdw);
+	return 0;
 }
 
 
-static int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl)
+const char *pvr2_hdw_get_state_name(unsigned int id)
 {
-	if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0;
-	if (enableFl) {
-		pvr2_trace(PVR2_TRACE_START_STOP,
-			   "/*--TRACE_STREAM--*/ enable");
-		pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0);
-	} else {
-		pvr2_trace(PVR2_TRACE_START_STOP,
-			   "/*--TRACE_STREAM--*/ disable");
-		pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
-	}
-	if (!hdw->flag_ok) return -EIO;
-	hdw->flag_streaming_enabled = enableFl != 0;
-	return 0;
+	if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL;
+	return pvr2_state_names[id];
 }
 
 
 int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
 {
-	return hdw->flag_streaming_enabled != 0;
+	return hdw->state_pipeline_req != 0;
 }
 
 
 int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag)
 {
-	int ret;
+	int ret,st;
 	LOCK_TAKE(hdw->big_lock); do {
-		ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag);
+		pvr2_hdw_untrip_unlocked(hdw);
+		if ((!enable_flag) != !(hdw->state_pipeline_req)) {
+			hdw->state_pipeline_req = enable_flag != 0;
+			pvr2_trace(PVR2_TRACE_START_STOP,
+				   "/*--TRACE_STREAM--*/ %s",
+				   enable_flag ? "enable" : "disable");
+		}
+		pvr2_hdw_state_sched(hdw);
 	} while (0); LOCK_GIVE(hdw->big_lock);
-	return ret;
-}
-
-
-static int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw,
-					    enum pvr2_config config)
-{
-	unsigned long sm = hdw->subsys_enabled_mask;
-	if (!hdw->flag_ok) return -EIO;
-	pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
-	hdw->config = config;
-	pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm);
+	if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret;
+	if (enable_flag) {
+		while ((st = hdw->master_state) != PVR2_STATE_RUN) {
+			if (st != PVR2_STATE_READY) return -EIO;
+			if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret;
+		}
+	}
 	return 0;
 }
 
 
 int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config)
 {
-	int ret;
-	if (!hdw->flag_ok) return -EIO;
+	int fl;
 	LOCK_TAKE(hdw->big_lock);
-	ret = pvr2_hdw_set_stream_type_no_lock(hdw,config);
+	if ((fl = (hdw->desired_stream_type != config)) != 0) {
+		hdw->desired_stream_type = config;
+		hdw->state_pipeline_config = 0;
+		trace_stbit("state_pipeline_config",
+			    hdw->state_pipeline_config);
+		pvr2_hdw_state_sched(hdw);
+	}
 	LOCK_GIVE(hdw->big_lock);
-	return ret;
+	if (fl) return 0;
+	return pvr2_hdw_wait(hdw,0);
 }
 
 
@@ -1646,6 +1428,7 @@ static int get_default_tuner_type(struct pvr2_hdw *hdw)
 	}
 	if (tp < 0) return -EINVAL;
 	hdw->tuner_type = tp;
+	hdw->tuner_updated = !0;
 	return 0;
 }
 
@@ -1656,8 +1439,9 @@ static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw)
 	int tp = 0;
 	if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
 		tp = video_std[unit_number];
+		if (tp) return tp;
 	}
-	return tp;
+	return 0;
 }
 
 
@@ -1731,7 +1515,7 @@ const static struct pvr2_std_hack std_eeprom_maps[] = {
 	},
 	{	/* PAL(D/D1/K) */
 		.pat = V4L2_STD_DK,
-		.std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
+		.std = V4L2_STD_PAL_D|V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
 	},
 };
 
@@ -1739,18 +1523,20 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
 {
 	char buf[40];
 	unsigned int bcnt;
-	v4l2_std_id std1,std2;
+	v4l2_std_id std1,std2,std3;
 
 	std1 = get_default_standard(hdw);
+	std3 = std1 ? 0 : hdw->hdw_desc->default_std_mask;
 
 	bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
 	pvr2_trace(PVR2_TRACE_STD,
-		   "Supported video standard(s) reported by eeprom: %.*s",
+		   "Supported video standard(s) reported available"
+		   " in hardware: %.*s",
 		   bcnt,buf);
 
 	hdw->std_mask_avail = hdw->std_mask_eeprom;
 
-	std2 = std1 & ~hdw->std_mask_avail;
+	std2 = (std1|std3) & ~hdw->std_mask_avail;
 	if (std2) {
 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
 		pvr2_trace(PVR2_TRACE_STD,
@@ -1772,6 +1558,16 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
 		pvr2_hdw_internal_find_stdenum(hdw);
 		return;
 	}
+	if (std3) {
+		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3);
+		pvr2_trace(PVR2_TRACE_STD,
+			   "Initial video standard"
+			   " (determined by device type): %.*s",bcnt,buf);
+		hdw->std_mask_cur = std3;
+		hdw->std_dirty = !0;
+		pvr2_hdw_internal_find_stdenum(hdw);
+		return;
+	}
 
 	{
 		unsigned int idx;
@@ -1816,8 +1612,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
 	unsigned int idx;
 	struct pvr2_ctrl *cptr;
 	int reloadFl = 0;
-	if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
-	    (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
+	if (hdw->hdw_desc->fx2_firmware.cnt) {
 		if (!reloadFl) {
 			reloadFl =
 				(hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
@@ -1853,25 +1648,13 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
 	}
 	if (!pvr2_hdw_dev_ok(hdw)) return;
 
-	if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) {
-		for (idx = 0;
-		     idx < pvr2_client_lists[hdw->hdw_type].cnt;
-		     idx++) {
-			request_module(
-				pvr2_client_lists[hdw->hdw_type].lst[idx]);
-		}
+	for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) {
+		request_module(hdw->hdw_desc->client_modules.lst[idx]);
 	}
 
-	if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
-	    (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
+	if (!hdw->hdw_desc->flag_no_powerup) {
 		pvr2_hdw_cmd_powerup(hdw);
 		if (!pvr2_hdw_dev_ok(hdw)) return;
-
-		if (pvr2_upload_firmware2(hdw)){
-			pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
-			pvr2_hdw_render_useless(hdw);
-			return;
-		}
 	}
 
 	// This step MUST happen after the earlier powerup step.
@@ -1899,15 +1682,22 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
 	// thread-safe against the normal pvr2_send_request() mechanism.
 	// (We should make it thread safe).
 
-	ret = pvr2_hdw_get_eeprom_addr(hdw);
-	if (!pvr2_hdw_dev_ok(hdw)) return;
-	if (ret < 0) {
-		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-			   "Unable to determine location of eeprom, skipping");
-	} else {
-		hdw->eeprom_addr = ret;
-		pvr2_eeprom_analyze(hdw);
+	if (hdw->hdw_desc->flag_has_hauppauge_rom) {
+		ret = pvr2_hdw_get_eeprom_addr(hdw);
 		if (!pvr2_hdw_dev_ok(hdw)) return;
+		if (ret < 0) {
+			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+				   "Unable to determine location of eeprom,"
+				   " skipping");
+		} else {
+			hdw->eeprom_addr = ret;
+			pvr2_eeprom_analyze(hdw);
+			if (!pvr2_hdw_dev_ok(hdw)) return;
+		}
+	} else {
+		hdw->tuner_type = hdw->hdw_desc->default_tuner_type;
+		hdw->tuner_updated = !0;
+		hdw->std_mask_eeprom = V4L2_STD_ALL;
 	}
 
 	pvr2_hdw_setup_std(hdw);
@@ -1918,14 +1708,12 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
 			   hdw->tuner_type);
 	}
 
-	hdw->tuner_updated = !0;
 	pvr2_i2c_core_check_stale(hdw);
 	hdw->tuner_updated = 0;
 
 	if (!pvr2_hdw_dev_ok(hdw)) return;
 
-	pvr2_hdw_commit_ctl_internal(hdw);
-	if (!pvr2_hdw_dev_ok(hdw)) return;
+	pvr2_hdw_commit_setup(hdw);
 
 	hdw->vid_stream = pvr2_stream_create();
 	if (!pvr2_hdw_dev_ok(hdw)) return;
@@ -1945,25 +1733,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
 
 	if (!pvr2_hdw_dev_ok(hdw)) return;
 
-	/* Make sure everything is up to date */
-	pvr2_i2c_core_sync(hdw);
-
-	if (!pvr2_hdw_dev_ok(hdw)) return;
-
 	hdw->flag_init_ok = !0;
+
+	pvr2_hdw_state_sched(hdw);
 }
 
 
-int pvr2_hdw_setup(struct pvr2_hdw *hdw)
+/* Set up the structure and attempt to put the device into a usable state.
+   This can be a time-consuming operation, which is why it is not done
+   internally as part of the create() step. */
+static void pvr2_hdw_setup(struct pvr2_hdw *hdw)
 {
 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw);
-	LOCK_TAKE(hdw->big_lock); do {
+	do {
 		pvr2_hdw_setup_low(hdw);
 		pvr2_trace(PVR2_TRACE_INIT,
 			   "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d",
-			   hdw,hdw->flag_ok,hdw->flag_init_ok);
+			   hdw,pvr2_hdw_dev_ok(hdw),hdw->flag_init_ok);
 		if (pvr2_hdw_dev_ok(hdw)) {
-			if (pvr2_hdw_init_ok(hdw)) {
+			if (hdw->flag_init_ok) {
 				pvr2_trace(
 					PVR2_TRACE_INFO,
 					"Device initialization"
@@ -2013,9 +1801,8 @@ int pvr2_hdw_setup(struct pvr2_hdw *hdw)
 				" the pvrusb2 device"
 				" in order to recover.");
 		}
-	} while (0); LOCK_GIVE(hdw->big_lock);
+	} while (0);
 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw);
-	return hdw->flag_init_ok;
 }
 
 
@@ -2026,24 +1813,32 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 {
 	unsigned int idx,cnt1,cnt2;
 	struct pvr2_hdw *hdw;
-	unsigned int hdw_type;
 	int valid_std_mask;
 	struct pvr2_ctrl *cptr;
+	const struct pvr2_device_desc *hdw_desc;
 	__u8 ifnum;
 	struct v4l2_queryctrl qctrl;
 	struct pvr2_ctl_info *ciptr;
 
-	hdw_type = devid - pvr2_device_table;
-	if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
-		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-			   "Bogus device type of %u reported",hdw_type);
-		return NULL;
-	}
+	hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
 
 	hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
-		   hdw,pvr2_device_names[hdw_type]);
+		   hdw,hdw_desc->description);
 	if (!hdw) goto fail;
+
+	init_timer(&hdw->quiescent_timer);
+	hdw->quiescent_timer.data = (unsigned long)hdw;
+	hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout;
+
+	init_timer(&hdw->encoder_wait_timer);
+	hdw->encoder_wait_timer.data = (unsigned long)hdw;
+	hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout;
+
+	hdw->master_state = PVR2_STATE_DEAD;
+
+	init_waitqueue_head(&hdw->state_wait_data);
+
 	hdw->tuner_signal_stale = !0;
 	cx2341x_fill_defaults(&hdw->enc_ctl_state);
 
@@ -2052,7 +1847,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 	hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
 				GFP_KERNEL);
 	if (!hdw->controls) goto fail;
-	hdw->hdw_type = hdw_type;
+	hdw->hdw_desc = hdw_desc;
 	for (idx = 0; idx < hdw->control_cnt; idx++) {
 		cptr = hdw->controls + idx;
 		cptr->hdw = hdw;
@@ -2184,18 +1979,16 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 	if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1;
 	hdw->name[cnt1] = 0;
 
+	hdw->workqueue = create_singlethread_workqueue(hdw->name);
+	INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
+	INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
+	INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init);
+
 	pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
 		   hdw->unit_number,hdw->name);
 
 	hdw->tuner_type = -1;
 	hdw->flag_ok = !0;
-	/* Initialize the mask of subsystems that we will shut down when we
-	   stop streaming. */
-	hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL;
-	hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
-
-	pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx",
-		   hdw->subsys_stream_mask);
 
 	hdw->usb_intf = intf;
 	hdw->usb_dev = interface_to_usbdev(intf);
@@ -2211,15 +2004,25 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 	mutex_init(&hdw->ctl_lock_mutex);
 	mutex_init(&hdw->big_lock_mutex);
 
+	queue_work(hdw->workqueue,&hdw->workinit);
 	return hdw;
  fail:
 	if (hdw) {
+		del_timer_sync(&hdw->quiescent_timer);
+		del_timer_sync(&hdw->encoder_wait_timer);
+		if (hdw->workqueue) {
+			flush_workqueue(hdw->workqueue);
+			destroy_workqueue(hdw->workqueue);
+			hdw->workqueue = NULL;
+		}
 		usb_free_urb(hdw->ctl_read_urb);
 		usb_free_urb(hdw->ctl_write_urb);
 		kfree(hdw->ctl_read_buffer);
 		kfree(hdw->ctl_write_buffer);
 		kfree(hdw->controls);
 		kfree(hdw->mpeg_ctrl_info);
+		kfree(hdw->std_defs);
+		kfree(hdw->std_enum_names);
 		kfree(hdw);
 	}
 	return NULL;
@@ -2250,10 +2053,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
 		kfree(hdw->ctl_write_buffer);
 		hdw->ctl_write_buffer = NULL;
 	}
-	pvr2_hdw_render_useless_unlocked(hdw);
 	hdw->flag_disconnected = !0;
 	hdw->usb_dev = NULL;
 	hdw->usb_intf = NULL;
+	pvr2_hdw_render_useless(hdw);
 }
 
 
@@ -2262,6 +2065,13 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
 {
 	if (!hdw) return;
 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
+	del_timer_sync(&hdw->quiescent_timer);
+	del_timer_sync(&hdw->encoder_wait_timer);
+	if (hdw->workqueue) {
+		flush_workqueue(hdw->workqueue);
+		destroy_workqueue(hdw->workqueue);
+		hdw->workqueue = NULL;
+	}
 	if (hdw->fw_buffer) {
 		kfree(hdw->fw_buffer);
 		hdw->fw_buffer = NULL;
@@ -2290,12 +2100,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
 }
 
 
-int pvr2_hdw_init_ok(struct pvr2_hdw *hdw)
-{
-	return hdw->flag_init_ok;
-}
-
-
 int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw)
 {
 	return (hdw && hdw->flag_ok);
@@ -2473,17 +2277,11 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
 }
 
 
-/* Commit all control changes made up to this point.  Subsystems can be
-   indirectly affected by these changes.  For a given set of things being
-   committed, we'll clear the affected subsystem bits and then once we're
-   done committing everything we'll make a request to restore the subsystem
-   state(s) back to their previous value before this function was called.
-   Thus we can automatically reconfigure affected pieces of the driver as
-   controls are changed. */
-static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
+/* Figure out if we need to commit control changes.  If so, mark internal
+   state flags to indicate this fact and return true.  Otherwise do nothing
+   else and return false. */
+static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw)
 {
-	unsigned long saved_subsys_mask = hdw->subsys_enabled_mask;
-	unsigned long stale_subsys_mask = 0;
 	unsigned int idx;
 	struct pvr2_ctrl *cptr;
 	int value;
@@ -2518,6 +2316,25 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
 		return 0;
 	}
 
+	hdw->state_pipeline_config = 0;
+	trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
+	pvr2_hdw_state_sched(hdw);
+
+	return !0;
+}
+
+
+/* Perform all operations needed to commit all control changes.  This must
+   be performed in synchronization with the pipeline state and is thus
+   expected to be called as part of the driver's worker thread.  Return
+   true if commit successful, otherwise return false to indicate that
+   commit isn't possible at this time. */
+static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
+{
+	unsigned int idx;
+	struct pvr2_ctrl *cptr;
+	int disruptive_change;
+
 	/* When video standard changes, reset the hres and vres values -
 	   but if the user has pending changes there, then let the changes
 	   take priority. */
@@ -2536,24 +2353,26 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
 		}
 	}
 
-	if (hdw->std_dirty ||
-	    hdw->enc_stale ||
-	    hdw->srate_dirty ||
-	    hdw->res_ver_dirty ||
-	    hdw->res_hor_dirty ||
-	    0) {
-		/* If any of this changes, then the encoder needs to be
-		   reconfigured, and we need to reset the stream. */
-		stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
-	}
-
-	if (hdw->input_dirty) {
-		/* pk: If input changes to or from radio, then the encoder
-		   needs to be restarted (for ENC_MUTE_VIDEO to work) */
-		stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+	/* If any of the below has changed, then we can't do the update
+	   while the pipeline is running.  Pipeline must be paused first
+	   and decoder -> encoder connection be made quiescent before we
+	   can proceed. */
+	disruptive_change =
+		(hdw->std_dirty ||
+		 hdw->enc_unsafe_stale ||
+		 hdw->srate_dirty ||
+		 hdw->res_ver_dirty ||
+		 hdw->res_hor_dirty ||
+		 hdw->input_dirty ||
+		 (hdw->active_stream_type != hdw->desired_stream_type));
+	if (disruptive_change && !hdw->state_pipeline_idle) {
+		/* Pipeline is not idle; we can't proceed.  Arrange to
+		   cause pipeline to stop so that we can try this again
+		   later.... */
+		hdw->state_pipeline_pause = !0;
+		return 0;
 	}
 
-
 	if (hdw->srate_dirty) {
 		/* Write new sample rate into control structure since
 		 * the master copy is stale.  We must track srate
@@ -2582,51 +2401,88 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
 		cptr->info->clear_dirty(cptr);
 	}
 
+	if (hdw->active_stream_type != hdw->desired_stream_type) {
+		/* Handle any side effects of stream config here */
+		hdw->active_stream_type = hdw->desired_stream_type;
+	}
+
 	/* Now execute i2c core update */
 	pvr2_i2c_core_sync(hdw);
 
-	pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0);
-	pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask);
+	if (hdw->state_encoder_run) {
+		/* If encoder isn't running, then this will get worked out
+		   later when we start the encoder. */
+		if (pvr2_encoder_adjust(hdw) < 0) return !0;
+	}
 
-	return 0;
+	hdw->state_pipeline_config = !0;
+	trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
+	return !0;
 }
 
 
 int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
 {
+	int fl;
+	LOCK_TAKE(hdw->big_lock);
+	fl = pvr2_hdw_commit_setup(hdw);
+	LOCK_GIVE(hdw->big_lock);
+	if (!fl) return 0;
+	return pvr2_hdw_wait(hdw,0);
+}
+
+
+static void pvr2_hdw_worker_i2c(struct work_struct *work)
+{
+	struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync);
 	LOCK_TAKE(hdw->big_lock); do {
-		pvr2_hdw_commit_ctl_internal(hdw);
+		pvr2_i2c_core_sync(hdw);
 	} while (0); LOCK_GIVE(hdw->big_lock);
-	return 0;
 }
 
 
-void pvr2_hdw_poll(struct pvr2_hdw *hdw)
+static void pvr2_hdw_worker_poll(struct work_struct *work)
 {
+	int fl = 0;
+	struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workpoll);
 	LOCK_TAKE(hdw->big_lock); do {
-		pvr2_i2c_core_sync(hdw);
+		fl = pvr2_hdw_state_eval(hdw);
 	} while (0); LOCK_GIVE(hdw->big_lock);
+	if (fl && hdw->state_func) {
+		hdw->state_func(hdw->state_data);
+	}
 }
 
 
-void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw,
-				 void (*func)(void *),
-				 void *data)
+static void pvr2_hdw_worker_init(struct work_struct *work)
 {
+	struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit);
 	LOCK_TAKE(hdw->big_lock); do {
-		hdw->poll_trigger_func = func;
-		hdw->poll_trigger_data = data;
+		pvr2_hdw_setup(hdw);
 	} while (0); LOCK_GIVE(hdw->big_lock);
 }
 
 
-void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw)
+static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
 {
-	if (hdw->poll_trigger_func) {
-		hdw->poll_trigger_func(hdw->poll_trigger_data);
-	}
+	return wait_event_interruptible(
+		hdw->state_wait_data,
+		(hdw->state_stale == 0) &&
+		(!state || (hdw->master_state != state)));
 }
 
+
+void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw,
+				 void (*callback_func)(void *),
+				 void *callback_data)
+{
+	LOCK_TAKE(hdw->big_lock); do {
+		hdw->state_data = callback_data;
+		hdw->state_func = callback_func;
+	} while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
 /* Return name for this driver instance */
 const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 {
@@ -2634,6 +2490,18 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 }
 
 
+const char *pvr2_hdw_get_desc(struct pvr2_hdw *hdw)
+{
+	return hdw->hdw_desc->description;
+}
+
+
+const char *pvr2_hdw_get_type(struct pvr2_hdw *hdw)
+{
+	return hdw->hdw_desc->shortname;
+}
+
+
 int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
 {
 	int result;
@@ -2689,6 +2557,7 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
 		pvr2_i2c_core_sync(hdw);
 		pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
 		cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
+		pvr2_hdw_state_log_state(hdw);
 		printk(KERN_INFO "pvrusb2: ==================  END STATUS CARD #%d  ==================\n", nr);
 	} while (0); LOCK_GIVE(hdw->big_lock);
 }
@@ -2959,7 +2828,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
 			   " without lock!!");
 		return -EDEADLK;
 	}
-	if ((!hdw->flag_ok) && !probe_fl) {
+	if (!hdw->flag_ok && !probe_fl) {
 		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
 			   "Attempted to execute control transfer"
 			   " when device not ok");
@@ -3167,7 +3036,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
 
 	hdw->cmd_debug_state = 0;
 	if ((status < 0) && (!probe_fl)) {
-		pvr2_hdw_render_useless_unlocked(hdw);
+		pvr2_hdw_render_useless(hdw);
 	}
 	return status;
 }
@@ -3227,24 +3096,17 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
 }
 
 
-static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
+void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
 {
 	if (!hdw->flag_ok) return;
-	pvr2_trace(PVR2_TRACE_INIT,"render_useless");
-	hdw->flag_ok = 0;
+	pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+		   "Device being rendered inoperable");
 	if (hdw->vid_stream) {
 		pvr2_stream_setup(hdw->vid_stream,NULL,0,0);
 	}
-	hdw->flag_streaming_enabled = 0;
-	hdw->subsys_enabled_mask = 0;
-}
-
-
-void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
-{
-	LOCK_TAKE(hdw->ctl_lock);
-	pvr2_hdw_render_useless_unlocked(hdw);
-	LOCK_GIVE(hdw->ctl_lock);
+	hdw->flag_ok = 0;
+	trace_stbit("flag_ok",hdw->flag_ok);
+	pvr2_hdw_state_sched(hdw);
 }
 
 
@@ -3299,7 +3161,6 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
 	int status;
 	LOCK_TAKE(hdw->ctl_lock); do {
 		pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
-		hdw->flag_ok = !0;
 		hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
 		status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
 	} while (0); LOCK_GIVE(hdw->ctl_lock);
@@ -3349,26 +3210,473 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
 			(runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
 		status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
 	} while (0); LOCK_GIVE(hdw->ctl_lock);
-	if (!status) {
-		hdw->subsys_enabled_mask =
-			((hdw->subsys_enabled_mask &
-			  ~(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) |
-			 (runFl ? (1<<PVR2_SUBSYS_B_USBSTREAM_RUN) : 0));
-	}
 	return status;
 }
 
 
-void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
-			     struct pvr2_hdw_debug_info *ptr)
+/* Evaluate whether or not state_encoder_ok can change */
+static int state_eval_encoder_ok(struct pvr2_hdw *hdw)
+{
+	if (hdw->state_encoder_ok) return 0;
+	if (hdw->flag_tripped) return 0;
+	if (hdw->state_encoder_run) return 0;
+	if (hdw->state_encoder_config) return 0;
+	if (hdw->state_decoder_run) return 0;
+	if (hdw->state_usbstream_run) return 0;
+	if (pvr2_upload_firmware2(hdw) < 0) {
+		hdw->flag_tripped = !0;
+		trace_stbit("flag_tripped",hdw->flag_tripped);
+		return !0;
+	}
+	hdw->state_encoder_ok = !0;
+	trace_stbit("state_encoder_ok",hdw->state_encoder_ok);
+	return !0;
+}
+
+
+/* Evaluate whether or not state_encoder_config can change */
+static int state_eval_encoder_config(struct pvr2_hdw *hdw)
+{
+	if (hdw->state_encoder_config) {
+		if (hdw->state_encoder_ok) {
+			if (hdw->state_pipeline_req &&
+			    !hdw->state_pipeline_pause) return 0;
+		}
+		hdw->state_encoder_config = 0;
+		hdw->state_encoder_waitok = 0;
+		trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok);
+		/* paranoia - solve race if timer just completed */
+		del_timer_sync(&hdw->encoder_wait_timer);
+	} else {
+		if (!hdw->state_encoder_ok ||
+		    !hdw->state_pipeline_idle ||
+		    hdw->state_pipeline_pause ||
+		    !hdw->state_pipeline_req ||
+		    !hdw->state_pipeline_config) {
+			/* We must reset the enforced wait interval if
+			   anything has happened that might have disturbed
+			   the encoder.  This should be a rare case. */
+			if (timer_pending(&hdw->encoder_wait_timer)) {
+				del_timer_sync(&hdw->encoder_wait_timer);
+			}
+			if (hdw->state_encoder_waitok) {
+				/* Must clear the state - therefore we did
+				   something to a state bit and must also
+				   return true. */
+				hdw->state_encoder_waitok = 0;
+				trace_stbit("state_encoder_waitok",
+					    hdw->state_encoder_waitok);
+				return !0;
+			}
+			return 0;
+		}
+		if (!hdw->state_encoder_waitok) {
+			if (!timer_pending(&hdw->encoder_wait_timer)) {
+				/* waitok flag wasn't set and timer isn't
+				   running.  Check flag once more to avoid
+				   a race then start the timer.  This is
+				   the point when we measure out a minimal
+				   quiet interval before doing something to
+				   the encoder. */
+				if (!hdw->state_encoder_waitok) {
+					hdw->encoder_wait_timer.expires =
+						jiffies + (HZ*50/1000);
+					add_timer(&hdw->encoder_wait_timer);
+				}
+			}
+			/* We can't continue until we know we have been
+			   quiet for the interval measured by this
+			   timer. */
+			return 0;
+		}
+		pvr2_encoder_configure(hdw);
+		if (hdw->state_encoder_ok) hdw->state_encoder_config = !0;
+	}
+	trace_stbit("state_encoder_config",hdw->state_encoder_config);
+	return !0;
+}
+
+
+/* Evaluate whether or not state_encoder_run can change */
+static int state_eval_encoder_run(struct pvr2_hdw *hdw)
+{
+	if (hdw->state_encoder_run) {
+		if (hdw->state_encoder_ok) {
+			if (hdw->state_decoder_run) return 0;
+			if (pvr2_encoder_stop(hdw) < 0) return !0;
+		}
+		hdw->state_encoder_run = 0;
+	} else {
+		if (!hdw->state_encoder_ok) return 0;
+		if (!hdw->state_decoder_run) return 0;
+		if (pvr2_encoder_start(hdw) < 0) return !0;
+		hdw->state_encoder_run = !0;
+	}
+	trace_stbit("state_encoder_run",hdw->state_encoder_run);
+	return !0;
+}
+
+
+/* Timeout function for quiescent timer. */
+static void pvr2_hdw_quiescent_timeout(unsigned long data)
+{
+	struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+	hdw->state_decoder_quiescent = !0;
+	trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent);
+	hdw->state_stale = !0;
+	queue_work(hdw->workqueue,&hdw->workpoll);
+}
+
+
+/* Timeout function for encoder wait timer. */
+static void pvr2_hdw_encoder_wait_timeout(unsigned long data)
+{
+	struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+	hdw->state_encoder_waitok = !0;
+	trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok);
+	hdw->state_stale = !0;
+	queue_work(hdw->workqueue,&hdw->workpoll);
+}
+
+
+/* Evaluate whether or not state_decoder_run can change */
+static int state_eval_decoder_run(struct pvr2_hdw *hdw)
+{
+	if (hdw->state_decoder_run) {
+		if (hdw->state_encoder_ok) {
+			if (hdw->state_pipeline_req &&
+			    !hdw->state_pipeline_pause) return 0;
+		}
+		if (!hdw->flag_decoder_missed) {
+			pvr2_decoder_enable(hdw,0);
+		}
+		hdw->state_decoder_quiescent = 0;
+		hdw->state_decoder_run = 0;
+		/* paranoia - solve race if timer just completed */
+		del_timer_sync(&hdw->quiescent_timer);
+	} else {
+		if (!hdw->state_decoder_quiescent) {
+			if (!timer_pending(&hdw->quiescent_timer)) {
+				/* We don't do something about the
+				   quiescent timer until right here because
+				   we also want to catch cases where the
+				   decoder was already not running (like
+				   after initialization) as opposed to
+				   knowing that we had just stopped it.
+				   The second flag check is here to cover a
+				   race - the timer could have run and set
+				   this flag just after the previous check
+				   but before we did the pending check. */
+				if (!hdw->state_decoder_quiescent) {
+					hdw->quiescent_timer.expires =
+						jiffies + (HZ*50/1000);
+					add_timer(&hdw->quiescent_timer);
+				}
+			}
+			/* Don't allow decoder to start again until it has
+			   been quiesced first.  This little detail should
+			   hopefully further stabilize the encoder. */
+			return 0;
+		}
+		if (!hdw->state_pipeline_req ||
+		    hdw->state_pipeline_pause ||
+		    !hdw->state_pipeline_config ||
+		    !hdw->state_encoder_config ||
+		    !hdw->state_encoder_ok) return 0;
+		del_timer_sync(&hdw->quiescent_timer);
+		if (hdw->flag_decoder_missed) return 0;
+		if (pvr2_decoder_enable(hdw,!0) < 0) return 0;
+		hdw->state_decoder_quiescent = 0;
+		hdw->state_decoder_run = !0;
+	}
+	trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent);
+	trace_stbit("state_decoder_run",hdw->state_decoder_run);
+	return !0;
+}
+
+
+/* Evaluate whether or not state_usbstream_run can change */
+static int state_eval_usbstream_run(struct pvr2_hdw *hdw)
+{
+	if (hdw->state_usbstream_run) {
+		if (hdw->state_encoder_ok) {
+			if (hdw->state_encoder_run) return 0;
+		}
+		pvr2_hdw_cmd_usbstream(hdw,0);
+		hdw->state_usbstream_run = 0;
+	} else {
+		if (!hdw->state_encoder_ok ||
+		    !hdw->state_encoder_run ||
+		    !hdw->state_pipeline_req ||
+		    hdw->state_pipeline_pause) return 0;
+		if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0;
+		hdw->state_usbstream_run = !0;
+	}
+	trace_stbit("state_usbstream_run",hdw->state_usbstream_run);
+	return !0;
+}
+
+
+/* Attempt to configure pipeline, if needed */
+static int state_eval_pipeline_config(struct pvr2_hdw *hdw)
+{
+	if (hdw->state_pipeline_config ||
+	    hdw->state_pipeline_pause) return 0;
+	pvr2_hdw_commit_execute(hdw);
+	return !0;
+}
+
+
+/* Update pipeline idle and pipeline pause tracking states based on other
+   inputs.  This must be called whenever the other relevant inputs have
+   changed. */
+static int state_update_pipeline_state(struct pvr2_hdw *hdw)
+{
+	unsigned int st;
+	int updatedFl = 0;
+	/* Update pipeline state */
+	st = !(hdw->state_encoder_run ||
+	       hdw->state_decoder_run ||
+	       hdw->state_usbstream_run ||
+	       (!hdw->state_decoder_quiescent));
+	if (!st != !hdw->state_pipeline_idle) {
+		hdw->state_pipeline_idle = st;
+		updatedFl = !0;
+	}
+	if (hdw->state_pipeline_idle && hdw->state_pipeline_pause) {
+		hdw->state_pipeline_pause = 0;
+		updatedFl = !0;
+	}
+	return updatedFl;
+}
+
+
+typedef int (*state_eval_func)(struct pvr2_hdw *);
+
+/* Set of functions to be run to evaluate various states in the driver. */
+const static state_eval_func eval_funcs[] = {
+	state_eval_pipeline_config,
+	state_eval_encoder_ok,
+	state_eval_encoder_config,
+	state_eval_decoder_run,
+	state_eval_encoder_run,
+	state_eval_usbstream_run,
+};
+
+
+/* Process various states and return true if we did anything interesting. */
+static int pvr2_hdw_state_update(struct pvr2_hdw *hdw)
+{
+	unsigned int i;
+	int state_updated = 0;
+	int check_flag;
+
+	if (!hdw->state_stale) return 0;
+	if ((hdw->fw1_state != FW1_STATE_OK) ||
+	    !hdw->flag_ok) {
+		hdw->state_stale = 0;
+		return !0;
+	}
+	/* This loop is the heart of the entire driver.  It keeps trying to
+	   evaluate various bits of driver state until nothing changes for
+	   one full iteration.  Each "bit of state" tracks some global
+	   aspect of the driver, e.g. whether decoder should run, if
+	   pipeline is configured, usb streaming is on, etc.  We separately
+	   evaluate each of those questions based on other driver state to
+	   arrive at the correct running configuration. */
+	do {
+		check_flag = 0;
+		state_update_pipeline_state(hdw);
+		/* Iterate over each bit of state */
+		for (i = 0; (i<ARRAY_SIZE(eval_funcs)) && hdw->flag_ok; i++) {
+			if ((*eval_funcs[i])(hdw)) {
+				check_flag = !0;
+				state_updated = !0;
+				state_update_pipeline_state(hdw);
+			}
+		}
+	} while (check_flag && hdw->flag_ok);
+	hdw->state_stale = 0;
+	trace_stbit("state_stale",hdw->state_stale);
+	return state_updated;
+}
+
+
+static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
+					     char *buf,unsigned int acnt)
+{
+	switch (which) {
+	case 0:
+		return scnprintf(
+			buf,acnt,
+			"driver:%s%s%s%s%s",
+			(hdw->flag_ok ? " <ok>" : " <fail>"),
+			(hdw->flag_init_ok ? " <init>" : " <uninitialized>"),
+			(hdw->flag_disconnected ? " <disconnected>" :
+			 " <connected>"),
+			(hdw->flag_tripped ? " <tripped>" : ""),
+			(hdw->flag_decoder_missed ? " <no decoder>" : ""));
+	case 1:
+		return scnprintf(
+			buf,acnt,
+			"pipeline:%s%s%s%s",
+			(hdw->state_pipeline_idle ? " <idle>" : ""),
+			(hdw->state_pipeline_config ?
+			 " <configok>" : " <stale>"),
+			(hdw->state_pipeline_req ? " <req>" : ""),
+			(hdw->state_pipeline_pause ? " <pause>" : ""));
+	case 2:
+		return scnprintf(
+			buf,acnt,
+			"worker:%s%s%s%s%s%s",
+			(hdw->state_decoder_run ?
+			 " <decode:run>" :
+			 (hdw->state_decoder_quiescent ?
+			  "" : " <decode:stop>")),
+			(hdw->state_decoder_quiescent ?
+			 " <decode:quiescent>" : ""),
+			(hdw->state_encoder_ok ?
+			 "" : " <encode:init>"),
+			(hdw->state_encoder_run ?
+			 " <encode:run>" : " <encode:stop>"),
+			(hdw->state_encoder_config ?
+			 " <encode:configok>" :
+			 (hdw->state_encoder_waitok ?
+			  "" : " <encode:wait>")),
+			(hdw->state_usbstream_run ?
+			 " <usb:run>" : " <usb:stop>"));
+		break;
+	case 3:
+		return scnprintf(
+			buf,acnt,
+			"state: %s",
+			pvr2_get_state_name(hdw->master_state));
+		break;
+	default: break;
+	}
+	return 0;
+}
+
+
+unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
+				   char *buf,unsigned int acnt)
+{
+	unsigned int bcnt,ccnt,idx;
+	bcnt = 0;
+	LOCK_TAKE(hdw->big_lock);
+	for (idx = 0; ; idx++) {
+		ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,acnt);
+		if (!ccnt) break;
+		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+		if (!acnt) break;
+		buf[0] = '\n'; ccnt = 1;
+		bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+	}
+	LOCK_GIVE(hdw->big_lock);
+	return bcnt;
+}
+
+
+static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
+{
+	char buf[128];
+	unsigned int idx,ccnt;
+
+	for (idx = 0; ; idx++) {
+		ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf));
+		if (!ccnt) break;
+		printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
+	}
+}
+
+
+/* Evaluate and update the driver's current state, taking various actions
+   as appropriate for the update. */
+static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
+{
+	unsigned int st;
+	int state_updated = 0;
+	int callback_flag = 0;
+
+	pvr2_trace(PVR2_TRACE_STBITS,
+		   "Drive state check START");
+	if (pvrusb2_debug & PVR2_TRACE_STBITS) {
+		pvr2_hdw_state_log_state(hdw);
+	}
+
+	/* Process all state and get back over disposition */
+	state_updated = pvr2_hdw_state_update(hdw);
+
+	/* Update master state based upon all other states. */
+	if (!hdw->flag_ok) {
+		st = PVR2_STATE_DEAD;
+	} else if (hdw->fw1_state != FW1_STATE_OK) {
+		st = PVR2_STATE_COLD;
+	} else if (!hdw->state_encoder_ok) {
+		st = PVR2_STATE_WARM;
+	} else if (hdw->flag_tripped || hdw->flag_decoder_missed) {
+		st = PVR2_STATE_ERROR;
+	} else if (hdw->state_encoder_run &&
+		   hdw->state_decoder_run &&
+		   hdw->state_usbstream_run) {
+		st = PVR2_STATE_RUN;
+	} else {
+		st = PVR2_STATE_READY;
+	}
+	if (hdw->master_state != st) {
+		pvr2_trace(PVR2_TRACE_STATE,
+			   "Device state change from %s to %s",
+			   pvr2_get_state_name(hdw->master_state),
+			   pvr2_get_state_name(st));
+		hdw->master_state = st;
+		state_updated = !0;
+		callback_flag = !0;
+	}
+	if (state_updated) {
+		/* Trigger anyone waiting on any state changes here. */
+		wake_up(&hdw->state_wait_data);
+	}
+
+	if (pvrusb2_debug & PVR2_TRACE_STBITS) {
+		pvr2_hdw_state_log_state(hdw);
+	}
+	pvr2_trace(PVR2_TRACE_STBITS,
+		   "Drive state check DONE callback=%d",callback_flag);
+
+	return callback_flag;
+}
+
+
+/* Cause kernel thread to check / update driver state */
+static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw)
+{
+	if (hdw->state_stale) return;
+	hdw->state_stale = !0;
+	trace_stbit("state_stale",hdw->state_stale);
+	queue_work(hdw->workqueue,&hdw->workpoll);
+}
+
+
+void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
+				      struct pvr2_hdw_debug_info *ptr)
 {
 	ptr->big_lock_held = hdw->big_lock_held;
 	ptr->ctl_lock_held = hdw->ctl_lock_held;
-	ptr->flag_ok = hdw->flag_ok;
 	ptr->flag_disconnected = hdw->flag_disconnected;
 	ptr->flag_init_ok = hdw->flag_init_ok;
-	ptr->flag_streaming_enabled = hdw->flag_streaming_enabled;
-	ptr->subsys_flags = hdw->subsys_enabled_mask;
+	ptr->flag_ok = hdw->flag_ok;
+	ptr->fw1_state = hdw->fw1_state;
+	ptr->flag_decoder_missed = hdw->flag_decoder_missed;
+	ptr->flag_tripped = hdw->flag_tripped;
+	ptr->state_encoder_ok = hdw->state_encoder_ok;
+	ptr->state_encoder_run = hdw->state_encoder_run;
+	ptr->state_decoder_run = hdw->state_decoder_run;
+	ptr->state_usbstream_run = hdw->state_usbstream_run;
+	ptr->state_decoder_quiescent = hdw->state_decoder_quiescent;
+	ptr->state_pipeline_config = hdw->state_pipeline_config;
+	ptr->state_pipeline_req = hdw->state_pipeline_req;
+	ptr->state_pipeline_pause = hdw->state_pipeline_pause;
+	ptr->state_pipeline_idle = hdw->state_pipeline_idle;
 	ptr->cmd_debug_state = hdw->cmd_debug_state;
 	ptr->cmd_code = hdw->cmd_debug_code;
 	ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
@@ -3381,6 +3689,15 @@ void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
 }
 
 
+void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
+				    struct pvr2_hdw_debug_info *ptr)
+{
+	LOCK_TAKE(hdw->ctl_lock); do {
+		pvr2_hdw_get_debug_info_unlocked(hdw,ptr);
+	} while(0); LOCK_GIVE(hdw->ctl_lock);
+}
+
+
 int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
 {
 	return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index e2f9d5e4cb65..3ad7a13d6c39 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -44,27 +44,6 @@
 #define PVR2_CVAL_INPUT_COMPOSITE 2
 #define PVR2_CVAL_INPUT_RADIO 3
 
-/* Subsystem definitions - these are various pieces that can be
-   independently stopped / started.  Usually you don't want to mess with
-   this directly (let the driver handle things itself), but it is useful
-   for debugging. */
-#define PVR2_SUBSYS_B_ENC_FIRMWARE        0
-#define PVR2_SUBSYS_B_ENC_CFG             1
-#define PVR2_SUBSYS_B_DIGITIZER_RUN       2
-#define PVR2_SUBSYS_B_USBSTREAM_RUN       3
-#define PVR2_SUBSYS_B_ENC_RUN             4
-
-#define PVR2_SUBSYS_CFG_ALL ( \
-	(1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \
-	(1 << PVR2_SUBSYS_B_ENC_CFG) )
-#define PVR2_SUBSYS_RUN_ALL ( \
-	(1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \
-	(1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \
-	(1 << PVR2_SUBSYS_B_ENC_RUN) )
-#define PVR2_SUBSYS_ALL ( \
-	PVR2_SUBSYS_CFG_ALL | \
-	PVR2_SUBSYS_RUN_ALL )
-
 enum pvr2_config {
 	pvr2_config_empty,    /* No configuration */
 	pvr2_config_mpeg,     /* Encoded / compressed video */
@@ -79,8 +58,41 @@ enum pvr2_v4l_type {
 	pvr2_v4l_type_radio,
 };
 
+/* Major states that we can be in:
+ *
+ *  DEAD - Device is in an unusable state and cannot be recovered.  This
+ *  can happen if we completely lose the ability to communicate with it
+ *  (but it might still on the bus).  In this state there's nothing we can
+ *  do; it must be replugged in order to recover.
+ *
+ *  COLD - Device is in an unusuable state, needs microcontroller firmware.
+ *
+ *  WARM - We can communicate with the device and the proper
+ *  microcontroller firmware is running, but other device initialization is
+ *  still needed (e.g. encoder firmware).
+ *
+ *  ERROR - A problem prevents capture operation (e.g. encoder firmware
+ *  missing).
+ *
+ *  READY - Device is operational, but not streaming.
+ *
+ *  RUN - Device is streaming.
+ *
+ */
+#define PVR2_STATE_NONE 0
+#define PVR2_STATE_DEAD 1
+#define PVR2_STATE_COLD 2
+#define PVR2_STATE_WARM 3
+#define PVR2_STATE_ERROR 4
+#define PVR2_STATE_READY 5
+#define PVR2_STATE_RUN 6
+
+/* Translate configuration enum to a string label */
 const char *pvr2_config_get_name(enum pvr2_config);
 
+/* Translate a master state enum to a string label */
+const char *pvr2_hdw_get_state_name(unsigned int);
+
 struct pvr2_hdw;
 
 /* Create and return a structure for interacting with the underlying
@@ -88,28 +100,13 @@ struct pvr2_hdw;
 struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 				 const struct usb_device_id *devid);
 
-/* Poll for background activity (if any) */
-void pvr2_hdw_poll(struct pvr2_hdw *);
-
-/* Trigger a poll to take place later at a convenient time */
-void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *);
-
-/* Register a callback used to trigger a future poll */
-void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *,
-				 void (*func)(void *),
-				 void *data);
-
 /* Destroy hardware interaction structure */
 void pvr2_hdw_destroy(struct pvr2_hdw *);
 
-/* Set up the structure and attempt to put the device into a usable state.
-   This can be a time-consuming operation, which is why it is not done
-   internally as part of the create() step.  Return value is exactly the
-   same as pvr2_hdw_init_ok(). */
-int pvr2_hdw_setup(struct pvr2_hdw *);
-
-/* Initialization succeeded */
-int pvr2_hdw_init_ok(struct pvr2_hdw *);
+/* Register a function to be called whenever the master state changes. */
+void pvr2_hdw_set_state_callback(struct pvr2_hdw *,
+				 void (*callback_func)(void *),
+				 void *callback_data);
 
 /* Return true if in the ready (normal) state */
 int pvr2_hdw_dev_ok(struct pvr2_hdw *);
@@ -161,12 +158,21 @@ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
 /* Query device and see if it thinks it is on a high-speed USB link */
 int pvr2_hdw_is_hsm(struct pvr2_hdw *);
 
+/* Return a string token representative of the hardware type */
+const char *pvr2_hdw_get_type(struct pvr2_hdw *);
+
+/* Return a single line description of the hardware type */
+const char *pvr2_hdw_get_desc(struct pvr2_hdw *);
+
 /* Turn streaming on/off */
 int pvr2_hdw_set_streaming(struct pvr2_hdw *,int);
 
 /* Find out if streaming is on */
 int pvr2_hdw_get_streaming(struct pvr2_hdw *);
 
+/* Retrieve driver overall state */
+int pvr2_hdw_get_state(struct pvr2_hdw *);
+
 /* Configure the type of stream to generate */
 int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config);
 
@@ -177,26 +183,6 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
 int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
 			       unsigned int idx);
 
-/* Enable / disable various pieces of hardware.  Items to change are
-   identified by bit positions within msk, and new state for each item is
-   identified by corresponding bit positions within val. */
-void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
-			     unsigned long msk,unsigned long val);
-
-/* Retrieve mask indicating which pieces of hardware are currently enabled
-   / configured. */
-unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *);
-
-/* Adjust mask of what get shut down when streaming is stopped.  This is a
-   debugging aid. */
-void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
-				    unsigned long msk,unsigned long val);
-
-/* Retrieve mask indicating which pieces of hardware are disabled when
-   streaming is turned off. */
-unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
-
-
 /* Enable / disable retrieval of CPU firmware or prom contents.  This must
    be enabled before pvr2_hdw_cpufw_get() will function.  Note that doing
    this may prevent the device from running (and leaving this mode may
@@ -253,6 +239,9 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int);
 /* Execute a USB-commanded device reset */
 void pvr2_hdw_device_reset(struct pvr2_hdw *);
 
+/* Reset worker's error trapping circuit breaker */
+int pvr2_hdw_untrip(struct pvr2_hdw *);
+
 /* Execute hard reset command (after this point it's likely that the
    encoder will have to be reconfigured).  This also clears the "useless"
    state. */
@@ -275,11 +264,21 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val);
 struct pvr2_hdw_debug_info {
 	int big_lock_held;
 	int ctl_lock_held;
-	int flag_ok;
 	int flag_disconnected;
 	int flag_init_ok;
-	int flag_streaming_enabled;
-	unsigned long subsys_flags;
+	int flag_ok;
+	int fw1_state;
+	int flag_decoder_missed;
+	int flag_tripped;
+	int state_encoder_ok;
+	int state_encoder_run;
+	int state_decoder_run;
+	int state_usbstream_run;
+	int state_decoder_quiescent;
+	int state_pipeline_config;
+	int state_pipeline_req;
+	int state_pipeline_pause;
+	int state_pipeline_idle;
 	int cmd_debug_state;
 	int cmd_debug_write_len;
 	int cmd_debug_read_len;
@@ -295,8 +294,20 @@ struct pvr2_hdw_debug_info {
    diagnosing lockups.  Note that this operation is completed without any
    kind of locking and so it is not atomic and may yield inconsistent
    results.  This is *purely* a debugging aid. */
-void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
-			     struct pvr2_hdw_debug_info *);
+void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
+				      struct pvr2_hdw_debug_info *);
+
+/* Intrusively retrieve internal state info - this is useful for
+   diagnosing overall driver state.  This operation synchronizes against
+   the overall driver mutex - so if there are locking problems this will
+   likely hang!  This is *purely* a debugging aid. */
+void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
+				    struct pvr2_hdw_debug_info *);
+
+/* Report out several lines of text that describes driver internal state.
+   Results are written into the passed-in buffer. */
+unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
+				   char *buf_ptr,unsigned int buf_size);
 
 /* Cause modules to log their state once */
 void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
@@ -306,9 +317,6 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
    a debugging aid. */
 int pvr2_upload_firmware2(struct pvr2_hdw *hdw);
 
-/* List of device types that we can match */
-extern struct usb_device_id pvr2_device_table[];
-
 #endif /* __PVRUSB2_HDW_H */
 
 /*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index c817c864e6a0..62867fa3517a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -895,7 +895,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
 		list_add_tail(&cp->list,&hdw->i2c_clients);
 		hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
 	} while (0); mutex_unlock(&hdw->i2c_list_lock);
-	if (fl) pvr2_hdw_poll_trigger_unlocked(hdw);
+	if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
 	return 0;
 }
 
@@ -980,14 +980,16 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
 		printk(KERN_INFO "%s: IR disabled\n",hdw->name);
 		hdw->i2c_func[0x18] = i2c_black_hole;
 	} else if (ir_mode[hdw->unit_number] == 1) {
-		if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+		if (hdw->hdw_desc->flag_has_hauppauge_custom_ir) {
 			hdw->i2c_func[0x18] = i2c_24xxx_ir;
 		}
 	}
-	if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
-		hdw->i2c_func[0x1b] = i2c_hack_wm8775;
+	if (hdw->hdw_desc->flag_has_cx25840) {
 		hdw->i2c_func[0x44] = i2c_hack_cx25840;
 	}
+	if (hdw->hdw_desc->flag_has_wm8775) {
+		hdw->i2c_func[0x1b] = i2c_hack_wm8775;
+	}
 
 	// Configure the adapter and set up everything else related to it.
 	memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index 11b3b2e84b90..b63b2265503a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -28,6 +28,7 @@
 #include <linux/videodev2.h>
 
 #include "pvrusb2-hdw.h"
+#include "pvrusb2-devattr.h"
 #include "pvrusb2-context.h"
 #include "pvrusb2-debug.h"
 #include "pvrusb2-v4l2.h"
@@ -148,11 +149,6 @@ static void __exit pvr_exit(void)
 module_init(pvr_init);
 module_exit(pvr_exit);
 
-/* Mike Isely <mcisely@pobox.com> 11-Mar-2006: See pvrusb2-hdw.c for
-   MODULE_DEVICE_TABLE().  We have to declare that attribute there
-   because that's where the device table actually is now and it seems
-   that certain gcc configurations get angry if MODULE_DEVICE_TABLE()
-   is used on what ends up being an external symbol. */
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index 63e55bb59fcb..da309288daa4 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -50,6 +50,10 @@ struct std_name {
 	 V4L2_STD_NTSC_M_KR| \
 	 V4L2_STD_NTSC_443)
 
+#define CSTD_ATSC \
+	(V4L2_STD_ATSC_8_VSB| \
+	 V4L2_STD_ATSC_16_VSB)
+
 #define CSTD_SECAM \
 	(V4L2_STD_SECAM_B| \
 	 V4L2_STD_SECAM_D| \
@@ -82,6 +86,7 @@ static const struct std_name std_groups[] = {
 	{"PAL",CSTD_PAL},
 	{"NTSC",CSTD_NTSC},
 	{"SECAM",CSTD_SECAM},
+	{"ATSC",CSTD_ATSC},
 };
 
 /* Mapping of standard bits to modulation system */
@@ -104,6 +109,8 @@ static const struct std_name std_items[] = {
 	{"N",TSTD_N},
 	{"Nc",TSTD_Nc},
 	{"60",TSTD_60},
+	{"8VSB",V4L2_STD_ATSC_8_VSB},
+	{"16VSB",V4L2_STD_ATSC_16_VSB},
 };
 
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 3c57a7d8200b..7a1cd878e31a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -43,10 +43,14 @@ struct pvr2_sysfs {
 	struct device_attribute attr_v4l_radio_minor_number;
 	struct device_attribute attr_unit_number;
 	struct device_attribute attr_bus_info;
+	struct device_attribute attr_hdw_name;
+	struct device_attribute attr_hdw_desc;
 	int v4l_minor_number_created_ok;
 	int v4l_radio_minor_number_created_ok;
 	int unit_number_created_ok;
 	int bus_info_created_ok;
+	int hdw_name_created_ok;
+	int hdw_desc_created_ok;
 };
 
 #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
@@ -712,6 +716,14 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
 	pvr2_sysfs_tear_down_debugifc(sfp);
 #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
 	pvr2_sysfs_tear_down_controls(sfp);
+	if (sfp->hdw_desc_created_ok) {
+		device_remove_file(sfp->class_dev,
+				   &sfp->attr_hdw_desc);
+	}
+	if (sfp->hdw_name_created_ok) {
+		device_remove_file(sfp->class_dev,
+				   &sfp->attr_hdw_name);
+	}
 	if (sfp->bus_info_created_ok) {
 		device_remove_file(sfp->class_dev,
 					 &sfp->attr_bus_info);
@@ -758,6 +770,28 @@ static ssize_t bus_info_show(struct device *class_dev,
 }
 
 
+static ssize_t hdw_name_show(struct device *class_dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct pvr2_sysfs *sfp;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+	if (!sfp) return -EINVAL;
+	return scnprintf(buf,PAGE_SIZE,"%s\n",
+			 pvr2_hdw_get_type(sfp->channel.hdw));
+}
+
+
+static ssize_t hdw_desc_show(struct device *class_dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct pvr2_sysfs *sfp;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+	if (!sfp) return -EINVAL;
+	return scnprintf(buf,PAGE_SIZE,"%s\n",
+			 pvr2_hdw_get_desc(sfp->channel.hdw));
+}
+
+
 static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
 					   struct device_attribute *attr,
 					   char *buf)
@@ -871,6 +905,32 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
 		sfp->bus_info_created_ok = !0;
 	}
 
+	sfp->attr_hdw_name.attr.name = "device_hardware_type";
+	sfp->attr_hdw_name.attr.mode = S_IRUGO;
+	sfp->attr_hdw_name.show = hdw_name_show;
+	sfp->attr_hdw_name.store = NULL;
+	ret = device_create_file(sfp->class_dev,
+				 &sfp->attr_hdw_name);
+	if (ret < 0) {
+		printk(KERN_WARNING "%s: device_create_file error: %d\n",
+		       __FUNCTION__, ret);
+	} else {
+		sfp->hdw_name_created_ok = !0;
+	}
+
+	sfp->attr_hdw_desc.attr.name = "device_hardware_description";
+	sfp->attr_hdw_desc.attr.mode = S_IRUGO;
+	sfp->attr_hdw_desc.show = hdw_desc_show;
+	sfp->attr_hdw_desc.store = NULL;
+	ret = device_create_file(sfp->class_dev,
+				 &sfp->attr_hdw_desc);
+	if (ret < 0) {
+		printk(KERN_WARNING "%s: device_create_file error: %d\n",
+		       __FUNCTION__, ret);
+	} else {
+		sfp->hdw_desc_created_ok = !0;
+	}
+
 	pvr2_sysfs_add_controls(sfp);
 #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
 	pvr2_sysfs_add_debugifc(sfp);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 7a596ea7cfe6..8f0587ebd4bd 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -205,6 +205,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
 		memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
 		strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
 			sizeof(cap->bus_info));
+		strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
 
 		ret = 0;
 		break;
@@ -1015,10 +1016,8 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
 	sp = fh->dev_info->stream->stream;
 	pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
 	pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
-	pvr2_hdw_set_streaming(hdw,!0);
-	ret = pvr2_ioread_set_enabled(fh->rhp,!0);
-
-	return ret;
+	if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
+	return pvr2_ioread_set_enabled(fh->rhp,!0);
 }
 
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index 61efa6f02200..7c47345501b6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -49,29 +49,50 @@ struct pvr2_v4l_decoder {
 };
 
 
+struct routing_scheme {
+	const int *def;
+	unsigned int cnt;
+};
+
+
+static const int routing_scheme0[] = {
+	[PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4,
+	/* In radio mode, we mute the video, but point at one
+	   spot just to stay consistent */
+	[PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5,
+	[PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE5,
+	[PVR2_CVAL_INPUT_SVIDEO] =  SAA7115_SVIDEO2,
+};
+
+static const struct routing_scheme routing_schemes[] = {
+	[PVR2_ROUTING_SCHEME_HAUPPAUGE] = {
+		.def = routing_scheme0,
+		.cnt = ARRAY_SIZE(routing_scheme0),
+	},
+};
+
 static void set_input(struct pvr2_v4l_decoder *ctxt)
 {
 	struct pvr2_hdw *hdw = ctxt->hdw;
 	struct v4l2_routing route;
+	const struct routing_scheme *sp;
+	unsigned int sid = hdw->hdw_desc->signal_routing_scheme;
 
 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
-	switch(hdw->input_val) {
-	case PVR2_CVAL_INPUT_TV:
-		route.input = SAA7115_COMPOSITE4;
-		break;
-	case PVR2_CVAL_INPUT_COMPOSITE:
-		route.input = SAA7115_COMPOSITE5;
-		break;
-	case PVR2_CVAL_INPUT_SVIDEO:
-		route.input = SAA7115_SVIDEO2;
-		break;
-	case PVR2_CVAL_INPUT_RADIO:
-		// In radio mode, we mute the video, but point at one
-		// spot just to stay consistent
-		route.input = SAA7115_COMPOSITE5;
-	default:
+
+	if ((sid < ARRAY_SIZE(routing_schemes)) &&
+	    ((sp = routing_schemes + sid) != 0) &&
+	    (hdw->input_val >= 0) &&
+	    (hdw->input_val < sp->cnt)) {
+		route.input = sp->def[hdw->input_val];
+	} else {
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "*** WARNING *** i2c v4l2 set_input:"
+			   " Invalid routing scheme (%u) and/or input (%d)",
+			   sid,hdw->input_val);
 		return;
 	}
+
 	route.output = 0;
 	pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
 }
@@ -129,7 +150,7 @@ static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
 static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
 {
 	ctxt->client->handler = NULL;
-	ctxt->hdw->decoder_ctrl = NULL;
+	pvr2_hdw_set_decoder(ctxt->hdw,NULL);
 	kfree(ctxt);
 }
 
@@ -217,7 +238,7 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
 	ctxt->client = cp;
 	ctxt->hdw = hdw;
 	ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
-	hdw->decoder_ctrl = &ctxt->ctrl;
+	pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
 	cp->handler = &ctxt->handler;
 	pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
 		   cp->client->addr);
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 2d18f0069821..41e5e518a47e 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -46,6 +46,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 #include <media/saa7115.h>
 #include <asm/div64.h>
 
@@ -1230,7 +1231,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client,
 
 /* ============ SAA7115 AUDIO settings (end) ============= */
 
-static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct saa711x_state *state = i2c_get_clientdata(client);
 
@@ -1449,26 +1450,17 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa711x;
-
-static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
+static int saa7115_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	struct saa711x_state *state;
 	int	i;
 	char	name[17];
 	u8 chip_id;
 
 	/* Check if the adapter supports the needed features */
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
 
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == 0)
-		return -ENOMEM;
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver_saa711x;
 	snprintf(client->name, sizeof(client->name) - 1, "saa7115");
 
 	for (i = 0; i < 0x0f; i++) {
@@ -1485,18 +1477,16 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
 	/* Check whether this chip is part of the saa711x series */
 	if (memcmp(name, "1f711", 5)) {
 		v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n",
-			address << 1, name);
-		kfree(client);
-		return 0;
+			client->addr << 1, name);
+		return -ENODEV;
 	}
 
 	snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
-	v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name);
+	v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name);
 
 	state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
 	i2c_set_clientdata(client, state);
 	if (state == NULL) {
-		kfree(client);
 		return -ENOMEM;
 	}
 	state->input = -1;
@@ -1549,59 +1539,25 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
 	saa711x_writeregs(client, saa7115_init_misc);
 	saa711x_set_v4lstd(client, V4L2_STD_NTSC);
 
-	i2c_attach_client(client);
-
 	v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
 		saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
-
 	return 0;
 }
 
-static int saa711x_probe(struct i2c_adapter *adapter)
-{
-	if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL)
-		return i2c_probe(adapter, &addr_data, &saa711x_attach);
-	return 0;
-}
+/* ----------------------------------------------------------------------- */
 
-static int saa711x_detach(struct i2c_client *client)
+static int saa7115_remove(struct i2c_client *client)
 {
-	struct saa711x_state *state = i2c_get_clientdata(client);
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err) {
-		return err;
-	}
-
-	kfree(state);
-	kfree(client);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
-/* ----------------------------------------------------------------------- */
-
-/* i2c implementation */
-static struct i2c_driver i2c_driver_saa711x = {
-	.driver = {
-		.name = "saa7115",
-	},
-	.id = I2C_DRIVERID_SAA711X,
-	.attach_adapter = saa711x_probe,
-	.detach_client = saa711x_detach,
-	.command = saa711x_command,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "saa7115",
+	.driverid = I2C_DRIVERID_SAA711X,
+	.command = saa7115_command,
+	.probe = saa7115_probe,
+	.remove = saa7115_remove,
+	.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
 };
 
-
-static int __init saa711x_init_module(void)
-{
-	return i2c_add_driver(&i2c_driver_saa711x);
-}
-
-static void __exit saa711x_cleanup_module(void)
-{
-	i2c_del_driver(&i2c_driver_saa711x);
-}
-
-module_init(saa711x_init_module);
-module_exit(saa711x_cleanup_module);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index e35ef321ec71..06c88db656b4 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -55,10 +55,11 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 #include <media/saa7127.h>
 
-static int debug = 0;
-static int test_image = 0;
+static int debug;
+static int test_image;
 
 MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
 MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
@@ -68,10 +69,6 @@ module_param(test_image, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (0-2)");
 MODULE_PARM_DESC(test_image, "test_image (0-1)");
 
-static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-
-
-I2C_CLIENT_INSMOD;
 
 /*
  * SAA7127 registers
@@ -360,9 +357,10 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data
 	if (enable && (data->field != 0 || data->line != 21))
 		return -EINVAL;
 	if (state->cc_enable != enable) {
-		v4l_dbg(1, debug, client, "Turn CC %s\n", enable ? "on" : "off");
+		v4l_dbg(1, debug, client,
+			"Turn CC %s\n", enable ? "on" : "off");
 		saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
-				(state->xds_enable << 7) | (enable << 6) | 0x11);
+			(state->xds_enable << 7) | (enable << 6) | 0x11);
 		state->cc_enable = enable;
 	}
 	if (!enable)
@@ -420,7 +418,8 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat
 
 	saa7127_write(client, 0x26, data->data[0]);
 	saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
-	v4l_dbg(1, debug, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+	v4l_dbg(1, debug, client,
+		"WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
 	state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
 	return 0;
 }
@@ -507,7 +506,8 @@ static int saa7127_set_output_type(struct i2c_client *client, int output)
 	default:
 		return -EINVAL;
 	}
-	v4l_dbg(1, debug, client, "Selecting %s output type\n", output_strs[output]);
+	v4l_dbg(1, debug, client,
+		"Selecting %s output type\n", output_strs[output]);
 
 	/* Configure Encoder */
 	saa7127_write(client, 0x2d, state->reg_2d);
@@ -569,12 +569,10 @@ static int saa7127_command(struct i2c_client *client,
 	{
 		int rc = 0;
 
-		if (state->input_type != route->input) {
+		if (state->input_type != route->input)
 			rc = saa7127_set_input_type(client, route->input);
-		}
-		if (rc == 0 && state->output_type != route->output) {
+		if (rc == 0 && state->output_type != route->output)
 			rc = saa7127_set_output_type(client, route->output);
-		}
 		return rc;
 	}
 
@@ -620,7 +618,8 @@ static int saa7127_command(struct i2c_client *client,
 	{
 		struct v4l2_register *reg = arg;
 
-		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+		if (!v4l2_chip_match_i2c_client(client,
+					reg->match_type, reg->match_chip))
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
@@ -637,16 +636,16 @@ static int saa7127_command(struct i2c_client *client,
 		struct v4l2_sliced_vbi_data *data = arg;
 
 		switch (data->id) {
-			case V4L2_SLICED_WSS_625:
-				return saa7127_set_wss(client, data);
-			case V4L2_SLICED_VPS:
-				return saa7127_set_vps(client, data);
-			case V4L2_SLICED_CAPTION_525:
-				if (data->field == 0)
-					return saa7127_set_cc(client, data);
-				return saa7127_set_xds(client, data);
-			default:
-				return -EINVAL;
+		case V4L2_SLICED_WSS_625:
+			return saa7127_set_wss(client, data);
+		case V4L2_SLICED_VPS:
+			return saa7127_set_vps(client, data);
+		case V4L2_SLICED_CAPTION_525:
+			if (data->field == 0)
+				return saa7127_set_cc(client, data);
+			return saa7127_set_xds(client, data);
+		default:
+			return -EINVAL;
 		}
 		break;
 	}
@@ -662,31 +661,20 @@ static int saa7127_command(struct i2c_client *client,
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7127;
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
+static int saa7127_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	struct saa7127_state *state;
 	struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 };  /* set to disabled */
 	int read_result = 0;
 
 	/* Check if the adapter supports the needed features */
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == 0)
-		return -ENOMEM;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
 
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver_saa7127;
 	snprintf(client->name, sizeof(client->name) - 1, "saa7127");
 
-	v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", address << 1);
+	v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n",
+			client->addr << 1);
 
 	/* First test register 0: Bits 5-7 are a version ID (should be 0),
 	   and bit 2 should also be 0.
@@ -696,15 +684,12 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
 	if ((saa7127_read(client, 0) & 0xe4) != 0 ||
 			(saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
 		v4l_dbg(1, debug, client, "saa7127 not found\n");
-		kfree(client);
-		return 0;
+		return -ENODEV;
 	}
 	state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL);
 
-	if (state == NULL) {
-		kfree(client);
-		return (-ENOMEM);
-	}
+	if (state == NULL)
+		return -ENOMEM;
 
 	i2c_set_clientdata(client, state);
 
@@ -718,91 +703,48 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
 	saa7127_set_wss(client, &vbi);
 	saa7127_set_cc(client, &vbi);
 	saa7127_set_xds(client, &vbi);
-	if (test_image == 1) {
+	if (test_image == 1)
 		/* The Encoder has an internal Colorbar generator */
 		/* This can be used for debugging */
 		saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE);
-	} else {
+	else
 		saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL);
-	}
 	saa7127_set_video_enable(client, 1);
 
 	/* Detect if it's an saa7129 */
 	read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
 	saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
 	if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
-		v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
+		v4l_info(client, "saa7129 found @ 0x%x (%s)\n",
+				client->addr << 1, client->adapter->name);
 		saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
 		saa7127_write_inittab(client, saa7129_init_config_extra);
 		state->ident = V4L2_IDENT_SAA7129;
 	} else {
-		v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
+		v4l_info(client, "saa7127 found @ 0x%x (%s)\n",
+				client->addr << 1, client->adapter->name);
 		state->ident = V4L2_IDENT_SAA7127;
 	}
-
-	i2c_attach_client(client);
-
 	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static int saa7127_probe(struct i2c_adapter *adapter)
+static int saa7127_remove(struct i2c_client *client)
 {
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, saa7127_attach);
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static int saa7127_detach(struct i2c_client *client)
-{
-	struct saa7127_state *state = i2c_get_clientdata(client);
-	int err;
-
 	/* Turn off TV output */
 	saa7127_set_video_enable(client, 0);
-
-	err = i2c_detach_client(client);
-
-	if (err) {
-		return err;
-	}
-
-	kfree(state);
-	kfree(client);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_driver i2c_driver_saa7127 = {
-	.driver = {
-		.name = "saa7127",
-	},
-	.id = I2C_DRIVERID_SAA7127,
-	.attach_adapter = saa7127_probe,
-	.detach_client = saa7127_detach,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "saa7127",
+	.driverid = I2C_DRIVERID_SAA7127,
 	.command = saa7127_command,
+	.probe = saa7127_probe,
+	.remove = saa7127_remove,
 };
 
-
-/* ----------------------------------------------------------------------- */
-
-static int __init saa7127_init_module(void)
-{
-	return i2c_add_driver(&i2c_driver_saa7127);
-}
-
-/* ----------------------------------------------------------------------- */
-
-static void __exit saa7127_cleanup_module(void)
-{
-	i2c_del_driver(&i2c_driver_saa7127);
-}
-
-/* ----------------------------------------------------------------------- */
-
-module_init(saa7127_init_module);
-module_exit(saa7127_cleanup_module);
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 3aa8cb2b860a..96bc3b1298a2 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -4,6 +4,7 @@ config VIDEO_SAA7134
 	select VIDEOBUF_DMA_SG
 	select VIDEO_IR
 	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
 	select CRC32
 	---help---
 	  This is a video4linux driver for Philips SAA713x based
@@ -23,18 +24,6 @@ config VIDEO_SAA7134_ALSA
 	  To compile this driver as a module, choose M here: the
 	  module will be called saa7134-alsa.
 
-config VIDEO_SAA7134_OSS
-	tristate "Philips SAA7134 DMA audio support (OSS, DEPRECATED)"
-	depends on VIDEO_SAA7134 && SOUND_PRIME && !VIDEO_SAA7134_ALSA
-	---help---
-	  This is a video4linux driver for direct (DMA) audio in
-	  Philips SAA713x based TV cards using OSS
-
-	  This is deprecated in favor of the ALSA module
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called saa7134-oss.
-
 config VIDEO_SAA7134_DVB
 	tristate "DVB/ATSC Support for saa7134 based TV cards"
 	depends on VIDEO_SAA7134 && DVB_CORE
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index c85c8a8ec361..9aff937ba7a5 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -7,7 +7,6 @@ obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o \
 				saa6752hs.o
 
 obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
-obj-$(CONFIG_VIDEO_SAA7134_OSS) += saa7134-oss.o
 
 obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 4878f3067787..ba2531034a91 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -1077,24 +1077,14 @@ static int saa7134_alsa_init(void)
 	struct saa7134_dev *dev = NULL;
 	struct list_head *list;
 
-	if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
-		saa7134_dmasound_init = alsa_device_init;
-		saa7134_dmasound_exit = alsa_device_exit;
-	} else {
-		printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n");
-		return -EBUSY;
-	}
+	saa7134_dmasound_init = alsa_device_init;
+	saa7134_dmasound_exit = alsa_device_exit;
 
 	printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
 
 	list_for_each(list,&saa7134_devlist) {
 		dev = list_entry(list, struct saa7134_dev, devlist);
-		if (dev->dmasound.priv_data == NULL) {
-			alsa_device_init(dev);
-		} else {
-			printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name);
-			return -EBUSY;
-		}
+		alsa_device_init(dev);
 	}
 
 	if (dev == NULL)
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 98c1b084a716..7d7f383b404f 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -26,6 +26,7 @@
 #include "saa7134-reg.h"
 #include "saa7134.h"
 #include <media/v4l2-common.h>
+#include <media/tveeprom.h>
 
 /* commly used strings */
 static char name_mute[]    = "mute";
@@ -349,6 +350,10 @@ struct saa7134_board saa7134_boards[] = {
 			.name = name_radio,
 			.amux = LINE2,
 		},
+	       .mute = {
+		       .name = name_mute,
+		       .amux = TV,
+	       },
 	},
 	[SAA7134_BOARD_TVSTATION_RDS] = {
 		/* Typhoon TV Tuner RDS: Art.Nr. 50694 */
@@ -565,6 +570,10 @@ struct saa7134_board saa7134_boards[] = {
 		.radio = {
 			.name   = name_radio,
 			.amux   = LINE2,
+	       },
+	       .mute = {
+		       .name = name_mute,
+		       .amux = TV,
 		},
 	},
 	[SAA7134_BOARD_TYPHOON_90031] = {
@@ -3553,6 +3562,356 @@ struct saa7134_board saa7134_boards[] = {
 			.tv     = 1,
 		}},
 	},
+	[SAA7134_BOARD_BEHOLD_401] = {
+		.name           = "Beholder BeholdTV 401",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_403] = {
+		.name           = "Beholder BeholdTV 403",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+	},
+	[SAA7134_BOARD_BEHOLD_403FM] = {
+		.name           = "Beholder BeholdTV 403 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FQ1216ME,
+		.radio_type     = UNSET,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr	= ADDR_UNSET,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 1,
+			.amux   = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_405] = {
+		.name           = "Beholder BeholdTV 405",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+	},
+	[SAA7134_BOARD_BEHOLD_405FM] = {
+		/* Sergey <skiv@orel.ru> */
+		.name           = "Beholder BeholdTV 405 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_407] = {
+		.name 		= "Beholder BeholdTV 407",
+		.audio_clock 	= 0x00187de7,
+		.tuner_type 	= TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type 	= UNSET,
+		.tuner_addr 	= ADDR_UNSET,
+		.radio_addr 	= ADDR_UNSET,
+		.tda9887_conf 	= TDA9887_PRESENT,
+		.gpiomask = 0xc0c000,
+		.inputs = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0xc0c000,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+			.gpio = 0xc0c000,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv = 1,
+			.gpio = 0xc0c000,
+		}},
+	},
+	[SAA7134_BOARD_BEHOLD_407FM] = {
+		.name 		= "Beholder BeholdTV 407 FM",
+		.audio_clock 	= 0x00187de7,
+		.tuner_type 	= TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type 	= UNSET,
+		.tuner_addr 	= ADDR_UNSET,
+		.radio_addr 	= ADDR_UNSET,
+		.tda9887_conf 	= TDA9887_PRESENT,
+		.gpiomask = 0xc0c000,
+		.inputs = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0xc0c000,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+			.gpio = 0xc0c000,
+		},{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv = 1,
+			.gpio = 0xc0c000,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+			.gpio = 0xc0c000,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_409] = {
+		.name           = "Beholder BeholdTV 409",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+	},
+	[SAA7134_BOARD_BEHOLD_505FM] = {
+		.name           = "Beholder BeholdTV 505 FM/RDS",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE1,
+		},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_507_9FM] = {
+		.name           = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+			.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
+		.name           = "Beholder BeholdTV Columbus TVFM",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_ALPS_TSBE5_PAL,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_607_9FM] = {
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		.name           = "Beholder BeholdTV 607 / BeholdTV 609",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+	},
+	[SAA7134_BOARD_BEHOLD_M6] = {
+		/* Igor Kuznetsov <igk@igk.ru> */
+		/* Andrey Melnikoff <temnota@kmv.ru> */
+		.name           = "Beholder BeholdTV M6 / BeholdTV M6 Extra",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tda9887_conf   = TDA9887_PRESENT,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 3,
+			.amux = TV,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 1,
+			.amux = LINE1,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		}},
+		.radio = {
+			.name = name_radio,
+			.amux = LINE2,
+		},
+		.mpeg  = SAA7134_MPEG_EMPRESS,
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4033,7 +4392,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x1462,
-		.subdevice    = 0x6231,
+		.subdevice    = 0x6231, /* tda8275a, ks003 IR */
+		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1462,
+		.subdevice    = 0x8624, /* tda8275, ks003 IR */
 		.driver_data  = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -4207,11 +4572,41 @@ struct pci_device_id saa7134_pci_tbl[] = {
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x0070,
+		.subdevice    = 0x6700,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
 		.subdevice    = 0x6701,
 		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6702,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6703,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6704,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0070,
+		.subdevice    = 0x6705,
+		.driver_data  = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x153b,
 		.subdevice    = 0x1172,
 		.driver_data  = SAA7134_BOARD_CINERGY_HT_PCMCIA,
@@ -4289,6 +4684,162 @@ struct pci_device_id saa7134_pci_tbl[] = {
 		.driver_data  = SAA7134_BOARD_AVERMEDIA_SUPER_007,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4016,
+		.driver_data  = SAA7134_BOARD_BEHOLD_401,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4036,
+		.driver_data  = SAA7134_BOARD_BEHOLD_403,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4037,
+		.driver_data  = SAA7134_BOARD_BEHOLD_403FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4050,
+		.driver_data  = SAA7134_BOARD_BEHOLD_405,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4051,
+		.driver_data  = SAA7134_BOARD_BEHOLD_405FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4070,
+		.driver_data  = SAA7134_BOARD_BEHOLD_407,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4071,
+		.driver_data  = SAA7134_BOARD_BEHOLD_407FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x4090,
+		.driver_data  = SAA7134_BOARD_BEHOLD_409,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x5051,
+		.driver_data  = SAA7134_BOARD_BEHOLD_505FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x505B,
+		.driver_data  = SAA7134_BOARD_BEHOLD_505FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x5050,
+		.driver_data  = SAA7134_BOARD_BEHOLD_505FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x5071,
+		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x507B,
+		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x5070,
+		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x5090,
+		.driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x0000,
+		.subdevice    = 0x5201,
+		.driver_data  = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6070,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6071,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6072,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6073,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6090,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6091,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6092,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6093,
+		.driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6190,
+		.driver_data  = SAA7134_BOARD_BEHOLD_M6,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x5ace,
+		.subdevice    = 0x6193,
+		.driver_data  = SAA7134_BOARD_BEHOLD_M6,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
 		.subvendor    = 0x4e42,
 		.subdevice    = 0x3502,
@@ -4351,6 +4902,34 @@ static void board_flyvideo(struct saa7134_dev *dev)
 
 /* ----------------------------------------------------------- */
 
+static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
+{
+	struct tveeprom tv;
+
+	tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+
+	/* Make sure we support the board model */
+	switch (tv.model) {
+	case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+	case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+	case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+	case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */
+	case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */
+	case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+	case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+		break;
+	default:
+		printk(KERN_WARNING "%s: warning: "
+		       "unknown hauppauge model #%d\n", dev->name, tv.model);
+		break;
+	}
+
+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+	       dev->name, tv.model);
+}
+
+/* ----------------------------------------------------------- */
+
 int saa7134_board_init1(struct saa7134_dev *dev)
 {
 	/* Always print gpio, often manufacturers encode tuner type and other info. */
@@ -4406,6 +4985,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
 	case SAA7134_BOARD_ENCORE_ENLTV:
 	case SAA7134_BOARD_ENCORE_ENLTV_FM:
 	case SAA7134_BOARD_10MOONSTVMASTER3:
+	case SAA7134_BOARD_BEHOLD_401:
+	case SAA7134_BOARD_BEHOLD_403:
+	case SAA7134_BOARD_BEHOLD_403FM:
+	case SAA7134_BOARD_BEHOLD_405:
+	case SAA7134_BOARD_BEHOLD_405FM:
+	case SAA7134_BOARD_BEHOLD_407:
+	case SAA7134_BOARD_BEHOLD_407FM:
+	case SAA7134_BOARD_BEHOLD_409:
+	case SAA7134_BOARD_BEHOLD_505FM:
+	case SAA7134_BOARD_BEHOLD_507_9FM:
 		dev->has_remote = SAA7134_REMOTE_GPIO;
 		break;
 	case SAA7134_BOARD_FLYDVBS_LR300:
@@ -4445,6 +5034,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
 		break;
 	case SAA7134_BOARD_AVERMEDIA_CARDBUS:
+	case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
 		/* power-up tuner chip */
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0xffffffff, 0xffffffff);
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
@@ -4466,6 +5056,8 @@ int saa7134_board_init1(struct saa7134_dev *dev)
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
 	case SAA7134_BOARD_UPMOST_PURPLE_TV:
 	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+	case SAA7134_BOARD_BEHOLD_607_9FM:
+	case SAA7134_BOARD_BEHOLD_M6:
 		dev->has_remote = SAA7134_REMOTE_I2C;
 		break;
 	case SAA7134_BOARD_AVERMEDIA_A169_B:
@@ -4477,6 +5069,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
 		break;
 	case SAA7134_BOARD_AVERMEDIA_M102:
 		/* enable tuner */
+	       dev->has_remote = SAA7134_REMOTE_GPIO;
 		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x8c040007, 0x8c040007);
 		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
 		break;
@@ -4570,8 +5163,17 @@ int saa7134_board_init2(struct saa7134_dev *dev)
 
 		printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type);
 		if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) {
-			dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE;
-			saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf);
+			struct v4l2_priv_tun_config tda9887_cfg;
+
+			tda9887_cfg.tuner = TUNER_TDA9887;
+			tda9887_cfg.priv  = &dev->tda9887_conf;
+
+			dev->tda9887_conf = TDA9887_PRESENT      |
+					    TDA9887_PORT1_ACTIVE |
+					    TDA9887_PORT2_ACTIVE;
+
+			saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
+						 &tda9887_cfg);
 		}
 
 		tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
@@ -4601,7 +5203,6 @@ int saa7134_board_init2(struct saa7134_dev *dev)
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
 	case SAA7134_BOARD_PHILIPS_TIGER_S:
-	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
 		{
 		u8 data[] = { 0x3c, 0x33, 0x60};
 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
@@ -4622,13 +5223,16 @@ int saa7134_board_init2(struct saa7134_dev *dev)
 		i2c_transfer(&dev->i2c_adap, &msg, 1);
 		}
 		break;
+	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+		hauppauge_eeprom(dev, dev->eedata+0x80);
+		/* break intentionally omitted */
 	case SAA7134_BOARD_PINNACLE_PCTV_310i:
 	case SAA7134_BOARD_KWORLD_DVBT_210:
 	case SAA7134_BOARD_TEVION_DVBT_220RF:
 	case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
 	case SAA7134_BOARD_MEDION_MD8800_QUADRO:
-	case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+       case SAA7134_BOARD_AVERMEDIA_SUPER_007:
 		/* this is a hybrid board, initialize to analog mode
 		 * and configure firmware eeprom address
 		 */
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 4f0a9157ecb1..52baa4f7f7dd 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -294,7 +294,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
 	videobuf_waiton(&buf->vb,0,0);
 	videobuf_dma_unmap(q, dma);
 	videobuf_dma_free(dma);
-	buf->vb.state = STATE_NEEDS_INIT;
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 /* ------------------------------------------------------------------ */
@@ -313,7 +313,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev,
 			buf->activate(dev,buf,NULL);
 		} else if (list_empty(&q->queue)) {
 			list_add_tail(&buf->vb.queue,&q->queue);
-			buf->vb.state = STATE_QUEUED;
+			buf->vb.state = VIDEOBUF_QUEUED;
 		} else {
 			next = list_entry(q->queue.next,struct saa7134_buf,
 					  vb.queue);
@@ -322,7 +322,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev,
 		}
 	} else {
 		list_add_tail(&buf->vb.queue,&q->queue);
-		buf->vb.state = STATE_QUEUED;
+		buf->vb.state = VIDEOBUF_QUEUED;
 	}
 	return 0;
 }
@@ -387,7 +387,7 @@ void saa7134_buffer_timeout(unsigned long data)
 	   try to start over with the next one. */
 	if (q->curr) {
 		dprintk("timeout on %p\n",q->curr);
-		saa7134_buffer_finish(dev,q,STATE_ERROR);
+		saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR);
 	}
 	saa7134_buffer_next(dev,q);
 	spin_unlock_irqrestore(&dev->slock,flags);
@@ -395,8 +395,8 @@ void saa7134_buffer_timeout(unsigned long data)
 
 /* resends a current buffer in queue after resume */
 
-int saa7134_buffer_requeue(struct saa7134_dev *dev,
-			 struct saa7134_dmaqueue *q)
+static int saa7134_buffer_requeue(struct saa7134_dev *dev,
+				  struct saa7134_dmaqueue *q)
 {
 	struct saa7134_buf *buf, *next;
 
@@ -834,6 +834,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
 	vfd->minor   = -1;
 	vfd->dev     = &dev->pci->dev;
 	vfd->release = video_device_release;
+	vfd->debug   = video_debug;
 	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
 		 dev->name, type, saa7134_boards[dev->board].name);
 	return vfd;
@@ -1052,7 +1053,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
 	printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
 	       dev->name,dev->video_dev->minor & 0x1f);
 
-	dev->vbi_dev = vdev_init(dev,&saa7134_vbi_template,"vbi");
+	dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
+	dev->vbi_dev->type = VID_TYPE_TUNER | VID_TYPE_TELETEXT;
+
 	err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
 				    vbi_nr[dev->nr]);
 	if (err < 0)
@@ -1181,8 +1184,13 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
 	saa_writel(SAA7134_IRQ2, 0);
 	saa_writel(SAA7134_MAIN_CTRL, 0);
 
-	synchronize_irq(pci_dev->irq);
 	dev->insuspend = 1;
+	synchronize_irq(pci_dev->irq);
+
+	/* ACK interrupts once more, just in case,
+		since the IRQ handler won't ack them anymore*/
+
+	saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT));
 
 	/* Disable timeout timers - if we have active buffers, we will
 	   fill them on resume*/
@@ -1194,10 +1202,10 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
 	if (dev->remote)
 		saa7134_ir_stop(dev);
 
-	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
 	pci_save_state(pci_dev);
+	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
 
-    return 0;
+	return 0;
 }
 
 static int saa7134_resume(struct pci_dev *pci_dev)
@@ -1205,8 +1213,8 @@ static int saa7134_resume(struct pci_dev *pci_dev)
 	struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
 	unsigned long flags;
 
-	pci_restore_state(pci_dev);
 	pci_set_power_state(pci_dev, PCI_D0);
+	pci_restore_state(pci_dev);
 
 	/* Do things that are done in saa7134_initdev ,
 		except of initializing memory structures.*/
@@ -1222,6 +1230,7 @@ static int saa7134_resume(struct pci_dev *pci_dev)
 		saa7134_ir_start(dev, dev->remote);
 	saa7134_hw_enable1(dev);
 
+	msleep(100);
 
 	saa7134_board_init2(dev);
 
@@ -1229,10 +1238,13 @@ static int saa7134_resume(struct pci_dev *pci_dev)
 	saa7134_set_tvnorm_hw(dev);
 	saa7134_tvaudio_setmute(dev);
 	saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
+	saa7134_tvaudio_init(dev);
 	saa7134_tvaudio_do_scan(dev);
 	saa7134_enable_i2s(dev);
 	saa7134_hw_enable2(dev);
 
+	saa7134_irq_video_signalchange(dev);
+
 	/*resume unfinished buffer(s)*/
 	spin_lock_irqsave(&dev->slock, flags);
 	saa7134_buffer_requeue(dev, &dev->video_q);
@@ -1246,6 +1258,7 @@ static int saa7134_resume(struct pci_dev *pci_dev)
 
 	/* start DMA now*/
 	dev->insuspend = 0;
+	smp_wmb();
 	saa7134_set_dmabits(dev);
 	spin_unlock_irqrestore(&dev->slock, flags);
 
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index e1ab099ec4c6..a9ca5730826f 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -1073,14 +1073,21 @@ static int dvb_init(struct saa7134_dev *dev)
 
 static int dvb_fini(struct saa7134_dev *dev)
 {
-	static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+	/* FIXME: I suspect that this code is bogus, since the entry for
+	   Pinnacle 300I DVB-T PAL already defines the proper init to allow
+	   the detection of mt2032 (TDA9887_PORT2_INACTIVE)
+	 */
+	if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) {
+		struct v4l2_priv_tun_config tda9887_cfg;
+		static int on  = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv  = &on;
 
-	switch (dev->board) {
-	case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
 		/* otherwise we don't detect the tuner on next insmod */
-		saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on);
-		break;
-	};
+		saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg);
+	}
+
 	videobuf_dvb_unregister(&dev->dvb);
 	return 0;
 }
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 9322f44865b8..b1b01fa86720 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -161,152 +161,176 @@ ts_mmap(struct file *file, struct vm_area_struct * vma)
  * video_generic_ioctl (and maybe others).  userspace
  * copying is done already, arg is a kernel pointer.
  */
-static int ts_do_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, void *arg)
+
+static int empress_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
 {
-	struct saa7134_dev *dev = file->private_data;
-	struct v4l2_ext_controls *ctrls = arg;
-
-	if (debug > 1)
-		v4l_print_ioctl(dev->name,cmd);
-	switch (cmd) {
-	case VIDIOC_QUERYCAP:
-	{
-		struct v4l2_capability *cap = arg;
-
-		memset(cap,0,sizeof(*cap));
-		strcpy(cap->driver, "saa7134");
-		strlcpy(cap->card, saa7134_boards[dev->board].name,
-			sizeof(cap->card));
-		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-		cap->version = SAA7134_VERSION_CODE;
-		cap->capabilities =
-			V4L2_CAP_VIDEO_CAPTURE |
-			V4L2_CAP_READWRITE |
-			V4L2_CAP_STREAMING;
-		return 0;
-	}
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	strcpy(cap->driver, "saa7134");
+	strlcpy(cap->card, saa7134_boards[dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cap->version = SAA7134_VERSION_CODE;
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING;
+	return 0;
+}
 
-	/* --- input switching --------------------------------------- */
-	case VIDIOC_ENUMINPUT:
-	{
-		struct v4l2_input *i = arg;
+static int empress_enum_input(struct file *file, void *priv,
+					struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
 
-		if (i->index != 0)
-			return -EINVAL;
-		i->type = V4L2_INPUT_TYPE_CAMERA;
-		strcpy(i->name,"CCIR656");
-		return 0;
-	}
-	case VIDIOC_G_INPUT:
-	{
-		int *i = arg;
-		*i = 0;
-		return 0;
-	}
-	case VIDIOC_S_INPUT:
-	{
-		int *i = arg;
+	i->type = V4L2_INPUT_TYPE_CAMERA;
+	strcpy(i->name, "CCIR656");
 
-		if (*i != 0)
-			return -EINVAL;
-		return 0;
-	}
-	/* --- capture ioctls ---------------------------------------- */
-
-	case VIDIOC_ENUM_FMT:
-	{
-		struct v4l2_fmtdesc *f = arg;
-		int index;
-
-		index = f->index;
-		if (index != 0)
-			return -EINVAL;
-
-		memset(f,0,sizeof(*f));
-		f->index = index;
-		strlcpy(f->description, "MPEG TS", sizeof(f->description));
-		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		f->pixelformat = V4L2_PIX_FMT_MPEG;
-		return 0;
-	}
+	return 0;
+}
 
-	case VIDIOC_G_FMT:
-	{
-		struct v4l2_format *f = arg;
+static int empress_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
 
-		memset(f,0,sizeof(*f));
-		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+static int empress_s_input(struct file *file, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
 
-		saa7134_i2c_call_clients(dev, cmd, arg);
-		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-		f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
-		return 0;
-	}
+	return 0;
+}
 
-	case VIDIOC_S_FMT:
-	{
-		struct v4l2_format *f = arg;
+static int empress_enum_fmt_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (f->index != 0)
+		return -EINVAL;
 
-		if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-		    return -EINVAL;
+	strlcpy(f->description, "MPEG TS", sizeof(f->description));
+	f->pixelformat = V4L2_PIX_FMT_MPEG;
 
-		saa7134_i2c_call_clients(dev, cmd, arg);
-		f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
-		f->fmt.pix.sizeimage    = TS_PACKET_SIZE* dev->ts.nr_packets;
-		return 0;
-	}
+	return 0;
+}
 
-	case VIDIOC_REQBUFS:
-		return videobuf_reqbufs(&dev->empress_tsq,arg);
+static int empress_g_fmt_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
 
-	case VIDIOC_QUERYBUF:
-		return videobuf_querybuf(&dev->empress_tsq,arg);
+	saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f);
 
-	case VIDIOC_QBUF:
-		return videobuf_qbuf(&dev->empress_tsq,arg);
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
 
-	case VIDIOC_DQBUF:
-		return videobuf_dqbuf(&dev->empress_tsq,arg,
-				      file->f_flags & O_NONBLOCK);
+	return 0;
+}
 
-	case VIDIOC_STREAMON:
-		return videobuf_streamon(&dev->empress_tsq);
+static int empress_s_fmt_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
 
-	case VIDIOC_STREAMOFF:
-		return videobuf_streamoff(&dev->empress_tsq);
+	saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f);
 
-	case VIDIOC_QUERYCTRL:
-	case VIDIOC_G_CTRL:
-	case VIDIOC_S_CTRL:
-		return saa7134_common_ioctl(dev, cmd, arg);
+	f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+	f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
 
-	case VIDIOC_S_EXT_CTRLS:
-		/* count == 0 is abused in saa6752hs.c, so that special
-		   case is handled here explicitly. */
-		if (ctrls->count == 0)
-			return 0;
-		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-			return -EINVAL;
-		saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg);
-		ts_init_encoder(dev);
-		return 0;
-	case VIDIOC_G_EXT_CTRLS:
-		if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-			return -EINVAL;
-		saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg);
+	return 0;
+}
+
+
+static int empress_reqbufs(struct file *file, void *priv,
+					struct v4l2_requestbuffers *p)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	return videobuf_reqbufs(&dev->empress_tsq, p);
+}
+
+static int empress_querybuf(struct file *file, void *priv,
+					struct v4l2_buffer *b)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	return videobuf_querybuf(&dev->empress_tsq, b);
+}
+
+static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	return videobuf_qbuf(&dev->empress_tsq, b);
+}
+
+static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	return videobuf_dqbuf(&dev->empress_tsq, b,
+				file->f_flags & O_NONBLOCK);
+}
+
+static int empress_streamon(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	return videobuf_streamon(&dev->empress_tsq);
+}
+
+static int empress_streamoff(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	return videobuf_streamoff(&dev->empress_tsq);
+}
+
+static int empress_s_ext_ctrls(struct file *file, void *priv,
+			       struct v4l2_ext_controls *ctrls)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	/* count == 0 is abused in saa6752hs.c, so that special
+		case is handled here explicitly. */
+	if (ctrls->count == 0)
 		return 0;
 
-	default:
-		return -ENOIOCTLCMD;
-	}
+	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+
+	saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls);
+	ts_init_encoder(dev);
+
 	return 0;
 }
 
-static int ts_ioctl(struct inode *inode, struct file *file,
-		     unsigned int cmd, unsigned long arg)
+static int empress_g_ext_ctrls(struct file *file, void *priv,
+			       struct v4l2_ext_controls *ctrls)
 {
-	return video_usercopy(inode, file, cmd, arg, ts_do_ioctl);
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+		return -EINVAL;
+	saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls);
+
+	return 0;
 }
 
 static const struct file_operations ts_fops =
@@ -317,7 +341,7 @@ static const struct file_operations ts_fops =
 	.read	  = ts_read,
 	.poll	  = ts_poll,
 	.mmap	  = ts_mmap,
-	.ioctl	  = ts_ioctl,
+	.ioctl	  = video_ioctl2,
 	.llseek   = no_llseek,
 };
 
@@ -330,6 +354,29 @@ static struct video_device saa7134_empress_template =
 	.type2         = 0 /* FIXME */,
 	.fops          = &ts_fops,
 	.minor	       = -1,
+
+	.vidioc_querycap		= empress_querycap,
+	.vidioc_enum_fmt_cap		= empress_enum_fmt_cap,
+	.vidioc_s_fmt_cap		= empress_s_fmt_cap,
+	.vidioc_g_fmt_cap		= empress_g_fmt_cap,
+	.vidioc_reqbufs			= empress_reqbufs,
+	.vidioc_querybuf		= empress_querybuf,
+	.vidioc_qbuf			= empress_qbuf,
+	.vidioc_dqbuf			= empress_dqbuf,
+	.vidioc_streamon		= empress_streamon,
+	.vidioc_streamoff		= empress_streamoff,
+	.vidioc_s_ext_ctrls		= empress_s_ext_ctrls,
+	.vidioc_g_ext_ctrls		= empress_g_ext_ctrls,
+	.vidioc_enum_input		= empress_enum_input,
+	.vidioc_g_input			= empress_g_input,
+	.vidioc_s_input			= empress_s_input,
+
+	.vidioc_queryctrl		= saa7134_queryctrl,
+	.vidioc_g_ctrl			= saa7134_g_ctrl,
+	.vidioc_s_ctrl			= saa7134_s_ctrl,
+
+	.tvnorms			= SAA7134_NORMS,
+	.current_norm			= V4L2_STD_PAL,
 };
 
 static void empress_signal_update(struct work_struct *work)
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 6deaad1a5480..d3322c3018f2 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -323,7 +323,6 @@ static int attach_inform(struct i2c_client *client)
 {
 	struct saa7134_dev *dev = client->adapter->algo_data;
 	int tuner = dev->tuner_type;
-	int conf  = dev->tda9887_conf;
 	struct tuner_setup tun_setup;
 
 	d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
@@ -335,6 +334,7 @@ static int attach_inform(struct i2c_client *client)
 		case 0x7a:
 		case 0x47:
 		case 0x71:
+		case 0x2d:
 		{
 			struct IR_i2c *ir = i2c_get_clientdata(client);
 			d1printk("%s i2c IR detected (%s).\n",
@@ -360,7 +360,6 @@ static int attach_inform(struct i2c_client *client)
 	}
 
 	if (tuner != UNSET) {
-
 		tun_setup.type = tuner;
 		tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
 		tun_setup.config = saa7134_boards[dev->board].tuner_config;
@@ -372,9 +371,18 @@ static int attach_inform(struct i2c_client *client)
 
 			client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
+
+		if (tuner == TUNER_TDA9887) {
+			struct v4l2_priv_tun_config tda9887_cfg;
+
+			tda9887_cfg.tuner = TUNER_TDA9887;
+			tda9887_cfg.priv = &dev->tda9887_conf;
+
+			client->driver->command(client, TUNER_SET_CONFIG,
+						&tda9887_cfg);
+		}
 	}
 
-	client->driver->command(client, TDA9887_SET_CONFIG, &conf);
 
 	return 0;
 }
@@ -432,6 +440,7 @@ static char *i2c_devs[128] = {
 	[ 0xa0 >> 1 ] = "eeprom",
 	[ 0xc0 >> 1 ] = "tuner (analog)",
 	[ 0x86 >> 1 ] = "tda9887",
+	[ 0x5a >> 1 ] = "remote control",
 };
 
 static void do_i2c_scan(char *name, struct i2c_client *c)
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 3abaa1b8ac9d..0db955c2d9b9 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -49,9 +49,14 @@ module_param(repeat_delay, int, 0644);
 MODULE_PARM_DESC(repeat_delay, "delay before key repeat started");
 static int repeat_period = 33;
 module_param(repeat_period, int, 0644);
-MODULE_PARM_DESC(repeat_period, "repeat period between"
+MODULE_PARM_DESC(repeat_period, "repeat period between "
     "keypresses when key is down");
 
+static unsigned int disable_other_ir;
+module_param(disable_other_ir, int, 0644);
+MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
+    "alternative remotes from other manufacturers");
+
 #define dprintk(fmt, arg...)	if (ir_debug) \
 	printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
@@ -154,6 +159,45 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 	return 1;
 }
 
+
+static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char data[12];
+	u32 gpio;
+
+	struct saa7134_dev *dev = ir->c.adapter->algo_data;
+
+	/* rising SAA7134_GPIO_GPRESCAN reads the status */
+	saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+	saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+	gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+	if (0x400000 & ~gpio)
+		return 0; /* No button press */
+
+	ir->c.addr = 0x5a >> 1;
+
+	if (12 != i2c_master_recv(&ir->c, data, 12)) {
+		i2cdprintk("read error\n");
+		return -EIO;
+	}
+	/* IR of this card normally decode signals NEC-standard from
+	 * - Sven IHOO MT 5.1R remote. xxyye718
+	 * - Sven DVD HD-10xx remote. xxyyf708
+	 * - BBK ...
+	 * - mayby others
+	 * So, skip not our, if disable full codes mode.
+	 */
+	if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir)
+		return 0;
+
+	*ir_key = data[9];
+	*ir_raw = data[9];
+
+	return 1;
+}
+
 void saa7134_input_irq(struct saa7134_dev *dev)
 {
 	struct card_ir *ir = dev->remote;
@@ -260,6 +304,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 	case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
 	case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
 	case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+	case SAA7134_BOARD_AVERMEDIA_M102:
 		ir_codes     = ir_codes_avermedia;
 		mask_keycode = 0x0007C8;
 		mask_keydown = 0x000010;
@@ -287,6 +332,16 @@ int saa7134_input_init1(struct saa7134_dev *dev)
 	case SAA7134_BOARD_MANLI_MTV001:
 	case SAA7134_BOARD_MANLI_MTV002:
 	case SAA7134_BOARD_BEHOLD_409FM:
+	case SAA7134_BOARD_BEHOLD_401:
+	case SAA7134_BOARD_BEHOLD_403:
+	case SAA7134_BOARD_BEHOLD_403FM:
+	case SAA7134_BOARD_BEHOLD_405:
+	case SAA7134_BOARD_BEHOLD_405FM:
+	case SAA7134_BOARD_BEHOLD_407:
+	case SAA7134_BOARD_BEHOLD_407FM:
+	case SAA7134_BOARD_BEHOLD_409:
+	case SAA7134_BOARD_BEHOLD_505FM:
+	case SAA7134_BOARD_BEHOLD_507_9FM:
 		ir_codes     = ir_codes_manli;
 		mask_keycode = 0x001f00;
 		mask_keyup   = 0x004000;
@@ -457,6 +512,12 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
 		ir->get_key   = get_key_hvr1110;
 		ir->ir_codes  = ir_codes_hauppauge_new;
 		break;
+	case SAA7134_BOARD_BEHOLD_607_9FM:
+	case SAA7134_BOARD_BEHOLD_M6:
+		snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
+		ir->get_key   = get_key_beholdm6xx;
+		ir->ir_codes  = ir_codes_behold;
+		break;
 	default:
 		dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
 		break;
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
deleted file mode 100644
index aedf04653e0e..000000000000
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ /dev/null
@@ -1,1046 +0,0 @@
-/*
- *
- * device driver for philips saa7134 based TV cards
- * oss dsp interface
- *
- * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *     2005 conversion to standalone module:
- *         Ricardo Cerqueira <v4l@cerqueira.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/init.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-
-#include "saa7134-reg.h"
-#include "saa7134.h"
-
-/* ------------------------------------------------------------------ */
-
-static unsigned int debug  = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"enable debug messages [oss]");
-
-static unsigned int rate  = 0;
-module_param(rate, int, 0444);
-MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)");
-
-static unsigned int dsp_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-MODULE_PARM_DESC(dsp_nr, "device numbers for SAA7134 capture interface(s).");
-module_param_array(dsp_nr,   int, NULL, 0444);
-
-static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-MODULE_PARM_DESC(mixer_nr, "mixer numbers for SAA7134 capture interface(s).");
-module_param_array(mixer_nr, int, NULL, 0444);
-
-#define dprintk(fmt, arg...)	if (debug) \
-	printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
-
-
-/* ------------------------------------------------------------------ */
-
-static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
-{
-	if (blksize < 0x100)
-		blksize = 0x100;
-	if (blksize > 0x10000)
-		blksize = 0x10000;
-
-	if (blocks < 2)
-		blocks = 2;
-	if ((blksize * blocks) > 1024*1024)
-		blocks = 1024*1024 / blksize;
-
-	dev->dmasound.blocks  = blocks;
-	dev->dmasound.blksize = blksize;
-	dev->dmasound.bufsize = blksize * blocks;
-
-	dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
-		blocks,blksize,blksize * blocks / 1024);
-	return 0;
-}
-
-static int dsp_buffer_init(struct saa7134_dev *dev)
-{
-	int err;
-
-	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);
-	if (0 != err)
-		return err;
-	return 0;
-}
-
-static int dsp_buffer_free(struct saa7134_dev *dev)
-{
-	BUG_ON(!dev->dmasound.blksize);
-	videobuf_dma_free(&dev->dmasound.dma);
-	dev->dmasound.blocks  = 0;
-	dev->dmasound.blksize = 0;
-	dev->dmasound.bufsize = 0;
-	return 0;
-}
-
-static void dsp_dma_start(struct saa7134_dev *dev)
-{
-	dev->dmasound.dma_blk     = 0;
-	dev->dmasound.dma_running = 1;
-	saa7134_set_dmabits(dev);
-}
-
-static void dsp_dma_stop(struct saa7134_dev *dev)
-{
-	dev->dmasound.dma_blk     = -1;
-	dev->dmasound.dma_running = 0;
-	saa7134_set_dmabits(dev);
-}
-
-static int dsp_rec_start(struct saa7134_dev *dev)
-{
-	int err, bswap, sign;
-	u32 fmt, control;
-	unsigned long flags;
-
-	/* prepare buffer */
-	if (0 != (err = videobuf_pci_dma_map(dev->pci,&dev->dmasound.dma)))
-		return err;
-	if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
-		goto fail1;
-	if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
-					      dev->dmasound.dma.sglist,
-					      dev->dmasound.dma.sglen,
-					      0)))
-		goto fail2;
-
-	/* sample format */
-	switch (dev->dmasound.afmt) {
-	case AFMT_U8:
-	case AFMT_S8:     fmt = 0x00;  break;
-	case AFMT_U16_LE:
-	case AFMT_U16_BE:
-	case AFMT_S16_LE:
-	case AFMT_S16_BE: fmt = 0x01;  break;
-	default:
-		err = -EINVAL;
-		goto fail2;
-	}
-
-	switch (dev->dmasound.afmt) {
-	case AFMT_S8:
-	case AFMT_S16_LE:
-	case AFMT_S16_BE: sign = 1; break;
-	default:          sign = 0; break;
-	}
-
-	switch (dev->dmasound.afmt) {
-	case AFMT_U16_BE:
-	case AFMT_S16_BE: bswap = 1; break;
-	default:          bswap = 0; break;
-	}
-
-	switch (dev->pci->device) {
-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-		if (1 == dev->dmasound.channels)
-			fmt |= (1 << 3);
-		if (2 == dev->dmasound.channels)
-			fmt |= (3 << 3);
-		if (sign)
-			fmt |= 0x04;
-		fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80;
-
-		saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
-		saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >>  8);
-		saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
-		saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
-
-		break;
-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		if (1 == dev->dmasound.channels)
-			fmt |= (1 << 4);
-		if (2 == dev->dmasound.channels)
-			fmt |= (2 << 4);
-		if (!sign)
-			fmt |= 0x04;
-		saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4);
-		saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
-		break;
-	}
-	dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
-		dev->dmasound.afmt, dev->dmasound.channels, fmt,
-		bswap ? 'b' : '-');
-
-	/* dma: setup channel 6 (= AUDIO) */
-	control = SAA7134_RS_CONTROL_BURST_16 |
-		SAA7134_RS_CONTROL_ME |
-		(dev->dmasound.pt.dma >> 12);
-	if (bswap)
-		control |= SAA7134_RS_CONTROL_BSWAP;
-	saa_writel(SAA7134_RS_BA1(6),0);
-	saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
-	saa_writel(SAA7134_RS_PITCH(6),0);
-	saa_writel(SAA7134_RS_CONTROL(6),control);
-
-	/* start dma */
-	dev->dmasound.recording_on = 1;
-	spin_lock_irqsave(&dev->slock,flags);
-	dsp_dma_start(dev);
-	spin_unlock_irqrestore(&dev->slock,flags);
-	return 0;
-
- fail2:
-	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
- fail1:
-	videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma);
-	return err;
-}
-
-static int dsp_rec_stop(struct saa7134_dev *dev)
-{
-	unsigned long flags;
-
-	dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk);
-
-	/* stop dma */
-	dev->dmasound.recording_on = 0;
-	spin_lock_irqsave(&dev->slock,flags);
-	dsp_dma_stop(dev);
-	spin_unlock_irqrestore(&dev->slock,flags);
-
-	/* unlock buffer */
-	saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
-	videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma);
-	return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int dsp_open(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	struct saa7134_dev *dev;
-	int err;
-
-	list_for_each_entry(dev, &saa7134_devlist, devlist)
-		if (dev->dmasound.minor_dsp == minor)
-			goto found;
-	return -ENODEV;
- found:
-
-	mutex_lock(&dev->dmasound.lock);
-	err = -EBUSY;
-	if (dev->dmasound.users_dsp)
-		goto fail1;
-	dev->dmasound.users_dsp++;
-	file->private_data = dev;
-
-	dev->dmasound.afmt        = AFMT_U8;
-	dev->dmasound.channels    = 1;
-	dev->dmasound.read_count  = 0;
-	dev->dmasound.read_offset = 0;
-	dsp_buffer_conf(dev,PAGE_SIZE,64);
-	err = dsp_buffer_init(dev);
-	if (0 != err)
-		goto fail2;
-
-	mutex_unlock(&dev->dmasound.lock);
-	return 0;
-
- fail2:
-	dev->dmasound.users_dsp--;
- fail1:
-	mutex_unlock(&dev->dmasound.lock);
-	return err;
-}
-
-static int dsp_release(struct inode *inode, struct file *file)
-{
-	struct saa7134_dev *dev = file->private_data;
-
-	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;
-	mutex_unlock(&dev->dmasound.lock);
-	return 0;
-}
-
-static ssize_t dsp_read(struct file *file, char __user *buffer,
-			size_t count, loff_t *ppos)
-{
-	struct saa7134_dev *dev = file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned int bytes;
-	unsigned long flags;
-	int err,ret = 0;
-
-	add_wait_queue(&dev->dmasound.wq, &wait);
-	mutex_lock(&dev->dmasound.lock);
-	while (count > 0) {
-		/* wait for data if needed */
-		if (0 == dev->dmasound.read_count) {
-			if (!dev->dmasound.recording_on) {
-				err = dsp_rec_start(dev);
-				if (err < 0) {
-					if (0 == ret)
-						ret = err;
-					break;
-				}
-			}
-			if (dev->dmasound.recording_on &&
-			    !dev->dmasound.dma_running) {
-				/* recover from overruns */
-				spin_lock_irqsave(&dev->slock,flags);
-				dsp_dma_start(dev);
-				spin_unlock_irqrestore(&dev->slock,flags);
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				if (0 == ret)
-					ret = -EAGAIN;
-				break;
-			}
-			mutex_unlock(&dev->dmasound.lock);
-			set_current_state(TASK_INTERRUPTIBLE);
-			if (0 == dev->dmasound.read_count)
-				schedule();
-			set_current_state(TASK_RUNNING);
-			mutex_lock(&dev->dmasound.lock);
-			if (signal_pending(current)) {
-				if (0 == ret)
-					ret = -EINTR;
-				break;
-			}
-		}
-
-		/* copy data to userspace */
-		bytes = count;
-		if (bytes > dev->dmasound.read_count)
-			bytes = dev->dmasound.read_count;
-		if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset)
-			bytes = dev->dmasound.bufsize - dev->dmasound.read_offset;
-		if (copy_to_user(buffer + ret,
-				 dev->dmasound.dma.vmalloc + dev->dmasound.read_offset,
-				 bytes)) {
-			if (0 == ret)
-				ret = -EFAULT;
-			break;
-		}
-
-		ret   += bytes;
-		count -= bytes;
-		dev->dmasound.read_count  -= bytes;
-		dev->dmasound.read_offset += bytes;
-		if (dev->dmasound.read_offset == dev->dmasound.bufsize)
-			dev->dmasound.read_offset = 0;
-	}
-	mutex_unlock(&dev->dmasound.lock);
-	remove_wait_queue(&dev->dmasound.wq, &wait);
-	return ret;
-}
-
-static ssize_t dsp_write(struct file *file, const char __user *buffer,
-			 size_t count, loff_t *ppos)
-{
-	return -EINVAL;
-}
-
-static const char *osspcm_ioctls[] = {
-	"RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
-	"CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS",
-	"GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER",
-	"GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
-	"SETDUPLEX", "GETODELAY"
-};
-#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls)
-
-static void saa7134_oss_print_ioctl(char *name, unsigned int cmd)
-{
-	char *dir;
-
-	switch (_IOC_DIR(cmd)) {
-	case _IOC_NONE:              dir = "--"; break;
-	case _IOC_READ:              dir = "r-"; break;
-	case _IOC_WRITE:             dir = "-w"; break;
-	case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
-	default:                     dir = "??"; break;
-	}
-	switch (_IOC_TYPE(cmd)) {
-	case 'P':
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n",
-		       name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ?
-		       osspcm_ioctls[_IOC_NR(cmd)] : "???");
-		break;
-	case 'M':
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n",
-		       name, cmd, dir, _IOC_NR(cmd));
-		break;
-	default:
-		printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n",
-		       name, cmd, dir, _IOC_NR(cmd));
-	}
-}
-
-static int dsp_ioctl(struct inode *inode, struct file *file,
-		     unsigned int cmd, unsigned long arg)
-{
-	struct saa7134_dev *dev = file->private_data;
-	void __user *argp = (void __user *) arg;
-	int __user *p = argp;
-	int val = 0;
-
-	if (debug > 1)
-		saa7134_oss_print_ioctl(dev->name,cmd);
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, p);
-	case SNDCTL_DSP_GETCAPS:
-		return 0;
-
-	case SNDCTL_DSP_SPEED:
-		if (get_user(val, p))
-			return -EFAULT;
-		/* fall through */
-	case SOUND_PCM_READ_RATE:
-		return put_user(dev->dmasound.rate, p);
-
-	case SNDCTL_DSP_STEREO:
-		if (get_user(val, p))
-			return -EFAULT;
-		mutex_lock(&dev->dmasound.lock);
-		dev->dmasound.channels = val ? 2 : 1;
-		if (dev->dmasound.recording_on) {
-			dsp_rec_stop(dev);
-			dsp_rec_start(dev);
-		}
-		mutex_unlock(&dev->dmasound.lock);
-		return put_user(dev->dmasound.channels-1, p);
-
-	case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != 1 && val != 2)
-			return -EINVAL;
-		mutex_lock(&dev->dmasound.lock);
-		dev->dmasound.channels = val;
-		if (dev->dmasound.recording_on) {
-			dsp_rec_stop(dev);
-			dsp_rec_start(dev);
-		}
-		mutex_unlock(&dev->dmasound.lock);
-		/* fall through */
-	case SOUND_PCM_READ_CHANNELS:
-		return put_user(dev->dmasound.channels, p);
-
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-		return put_user(AFMT_U8     | AFMT_S8     |
-				AFMT_U16_LE | AFMT_U16_BE |
-				AFMT_S16_LE | AFMT_S16_BE, p);
-
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
-		if (get_user(val, p))
-			return -EFAULT;
-		switch (val) {
-		case AFMT_QUERY:
-			/* nothing to do */
-			break;
-		case AFMT_U8:
-		case AFMT_S8:
-		case AFMT_U16_LE:
-		case AFMT_U16_BE:
-		case AFMT_S16_LE:
-		case AFMT_S16_BE:
-			mutex_lock(&dev->dmasound.lock);
-			dev->dmasound.afmt = val;
-			if (dev->dmasound.recording_on) {
-				dsp_rec_stop(dev);
-				dsp_rec_start(dev);
-			}
-			mutex_unlock(&dev->dmasound.lock);
-			return put_user(dev->dmasound.afmt, p);
-		default:
-			return -EINVAL;
-		}
-
-	case SOUND_PCM_READ_BITS:
-		switch (dev->dmasound.afmt) {
-		case AFMT_U8:
-		case AFMT_S8:
-			return put_user(8, p);
-		case AFMT_U16_LE:
-		case AFMT_U16_BE:
-		case AFMT_S16_LE:
-		case AFMT_S16_BE:
-			return put_user(16, p);
-		default:
-			return -EINVAL;
-		}
-
-	case SNDCTL_DSP_NONBLOCK:
-		file->f_flags |= O_NONBLOCK;
-		return 0;
-
-	case SNDCTL_DSP_RESET:
-		mutex_lock(&dev->dmasound.lock);
-		if (dev->dmasound.recording_on)
-			dsp_rec_stop(dev);
-		mutex_unlock(&dev->dmasound.lock);
-		return 0;
-	case SNDCTL_DSP_GETBLKSIZE:
-		return put_user(dev->dmasound.blksize, p);
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (dev->dmasound.recording_on)
-			return -EBUSY;
-		dsp_buffer_free(dev);
-		/* used to be arg >> 16 instead of val >> 16; fixed */
-		dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff);
-		dsp_buffer_init(dev);
-		return 0;
-
-	case SNDCTL_DSP_SYNC:
-		/* NOP */
-		return 0;
-
-	case SNDCTL_DSP_GETISPACE:
-	{
-		audio_buf_info info;
-		info.fragsize   = dev->dmasound.blksize;
-		info.fragstotal = dev->dmasound.blocks;
-		info.bytes      = dev->dmasound.read_count;
-		info.fragments  = info.bytes / info.fragsize;
-		if (copy_to_user(argp, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	default:
-		return -EINVAL;
-	}
-}
-
-static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct saa7134_dev *dev = file->private_data;
-	unsigned int mask = 0;
-
-	poll_wait(file, &dev->dmasound.wq, wait);
-
-	if (0 == dev->dmasound.read_count) {
-		mutex_lock(&dev->dmasound.lock);
-		if (!dev->dmasound.recording_on)
-			dsp_rec_start(dev);
-		mutex_unlock(&dev->dmasound.lock);
-	} else
-		mask |= (POLLIN | POLLRDNORM);
-	return mask;
-}
-
-const struct file_operations saa7134_dsp_fops = {
-	.owner   = THIS_MODULE,
-	.open    = dsp_open,
-	.release = dsp_release,
-	.read    = dsp_read,
-	.write   = dsp_write,
-	.ioctl   = dsp_ioctl,
-	.poll    = dsp_poll,
-	.llseek  = no_llseek,
-};
-
-/* ------------------------------------------------------------------ */
-
-static int
-mixer_recsrc_7134(struct saa7134_dev *dev)
-{
-	int analog_io,rate;
-
-	switch (dev->dmasound.input) {
-	case TV:
-		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
-		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, 0x00);
-		break;
-	case LINE1:
-	case LINE2:
-	case LINE2_LEFT:
-		analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08;
-		rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03;
-		saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x08, analog_io);
-		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80);
-		saa_andorb(SAA7134_SIF_SAMPLE_FREQ,   0x03, rate);
-		break;
-	}
-	return 0;
-}
-
-static int
-mixer_recsrc_7133(struct saa7134_dev *dev)
-{
-	u32 anabar, xbarin;
-
-	xbarin = 0x03; // adc
-    anabar = 0;
-	switch (dev->dmasound.input) {
-	case TV:
-		xbarin = 0; // Demodulator
-	anabar = 2; // DACs
-		break;
-	case LINE1:
-		anabar = 0;  // aux1, aux1
-		break;
-	case LINE2:
-	case LINE2_LEFT:
-		anabar = 9;  // aux2, aux2
-		break;
-	}
-    /* output xbar always main channel */
-	saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10);
-	saa_dsp_writel(dev, 0x464 >> 2, xbarin);
-	saa_writel(0x594 >> 2, anabar);
-
-	return 0;
-}
-
-static int
-mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
-{
-	static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
-
-	dev->dmasound.count++;
-	dev->dmasound.input = src;
-	dprintk("mixer input = %s\n",iname[dev->dmasound.input]);
-
-	switch (dev->pci->device) {
-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-		mixer_recsrc_7134(dev);
-		break;
-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		mixer_recsrc_7133(dev);
-		break;
-	}
-	return 0;
-}
-
-static int
-mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level)
-{
-	switch (dev->pci->device) {
-	case PCI_DEVICE_ID_PHILIPS_SAA7134:
-		switch (src) {
-		case TV:
-			/* nothing */
-			break;
-		case LINE1:
-			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x10,
-				   (100 == level) ? 0x00 : 0x10);
-			break;
-		case LINE2:
-		case LINE2_LEFT:
-			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x20,
-				   (100 == level) ? 0x00 : 0x20);
-			break;
-		}
-		break;
-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		/* nothing */
-		break;
-	}
-	return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int mixer_open(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	struct saa7134_dev *dev;
-
-	list_for_each_entry(dev, &saa7134_devlist, devlist)
-		if (dev->dmasound.minor_mixer == minor) {
-			file->private_data = dev;
-			return 0;
-		}
-	return -ENODEV;
-}
-
-static int mixer_release(struct inode *inode, struct file *file)
-{
-	file->private_data = NULL;
-	return 0;
-}
-
-static int mixer_ioctl(struct inode *inode, struct file *file,
-		     unsigned int cmd, unsigned long arg)
-{
-	struct saa7134_dev *dev = file->private_data;
-	enum saa7134_audio_in input;
-	int val,ret;
-	void __user *argp = (void __user *) arg;
-	int __user *p = argp;
-
-	if (debug > 1)
-		saa7134_oss_print_ioctl(dev->name,cmd);
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, p);
-	case SOUND_MIXER_INFO:
-	{
-		mixer_info info;
-		memset(&info,0,sizeof(info));
-		strlcpy(info.id,   "TV audio", sizeof(info.id));
-		strlcpy(info.name, dev->name,  sizeof(info.name));
-		info.modify_counter = dev->dmasound.count;
-		if (copy_to_user(argp, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	case SOUND_OLD_MIXER_INFO:
-	{
-		_old_mixer_info info;
-		memset(&info,0,sizeof(info));
-		strlcpy(info.id,   "TV audio", sizeof(info.id));
-		strlcpy(info.name, dev->name,  sizeof(info.name));
-		if (copy_to_user(argp, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	case MIXER_READ(SOUND_MIXER_CAPS):
-		return put_user(SOUND_CAP_EXCL_INPUT, p);
-	case MIXER_READ(SOUND_MIXER_STEREODEVS):
-		return put_user(0, p);
-	case MIXER_READ(SOUND_MIXER_RECMASK):
-	case MIXER_READ(SOUND_MIXER_DEVMASK):
-		val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2;
-		if (32000 == dev->dmasound.rate)
-			val |= SOUND_MASK_VIDEO;
-		return put_user(val, p);
-
-	case MIXER_WRITE(SOUND_MIXER_RECSRC):
-		if (get_user(val, p))
-			return -EFAULT;
-		input = dev->dmasound.input;
-		if (32000 == dev->dmasound.rate  &&
-		    val & SOUND_MASK_VIDEO  &&  dev->dmasound.input != TV)
-			input = TV;
-		if (val & SOUND_MASK_LINE1  &&  dev->dmasound.input != LINE1)
-			input = LINE1;
-		if (val & SOUND_MASK_LINE2  &&  dev->dmasound.input != LINE2)
-			input = LINE2;
-		if (input != dev->dmasound.input)
-			mixer_recsrc(dev,input);
-		/* fall throuth */
-	case MIXER_READ(SOUND_MIXER_RECSRC):
-		switch (dev->dmasound.input) {
-		case TV:    ret = SOUND_MASK_VIDEO; break;
-		case LINE1: ret = SOUND_MASK_LINE1; break;
-		case LINE2: ret = SOUND_MASK_LINE2; break;
-		default:    ret = 0;
-		}
-		return put_user(ret, p);
-
-	case MIXER_WRITE(SOUND_MIXER_VIDEO):
-	case MIXER_READ(SOUND_MIXER_VIDEO):
-		if (32000 != dev->dmasound.rate)
-			return -EINVAL;
-		return put_user(100 | 100 << 8, p);
-
-	case MIXER_WRITE(SOUND_MIXER_LINE1):
-		if (get_user(val, p))
-			return -EFAULT;
-		val &= 0xff;
-		val = (val <= 50) ? 50 : 100;
-		dev->dmasound.line1 = val;
-		mixer_level(dev,LINE1,dev->dmasound.line1);
-		/* fall throuth */
-	case MIXER_READ(SOUND_MIXER_LINE1):
-		return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p);
-
-	case MIXER_WRITE(SOUND_MIXER_LINE2):
-		if (get_user(val, p))
-			return -EFAULT;
-		val &= 0xff;
-		val = (val <= 50) ? 50 : 100;
-		dev->dmasound.line2 = val;
-		mixer_level(dev,LINE2,dev->dmasound.line2);
-		/* fall throuth */
-	case MIXER_READ(SOUND_MIXER_LINE2):
-		return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-const struct file_operations saa7134_mixer_fops = {
-	.owner   = THIS_MODULE,
-	.open    = mixer_open,
-	.release = mixer_release,
-	.ioctl   = mixer_ioctl,
-	.llseek  = no_llseek,
-};
-
-/* ------------------------------------------------------------------ */
-
-static irqreturn_t saa7134_oss_irq(int irq, void *dev_id)
-{
-	struct saa7134_dmasound *dmasound = dev_id;
-	struct saa7134_dev *dev = dmasound->priv_data;
-	unsigned long report, status;
-	int loop, handled = 0;
-
-	for (loop = 0; loop < 10; loop++) {
-		report = saa_readl(SAA7134_IRQ_REPORT);
-		status = saa_readl(SAA7134_IRQ_STATUS);
-
-		if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
-			handled = 1;
-			saa_writel(SAA7134_IRQ_REPORT,report);
-			saa7134_irq_oss_done(dev, status);
-		} else {
-			goto out;
-		}
-	}
-
-	if (loop == 10) {
-		dprintk("error! looping IRQ!");
-	}
-out:
-	return IRQ_RETVAL(handled);
-}
-
-int saa7134_oss_init1(struct saa7134_dev *dev)
-{
-
-	if ((request_irq(dev->pci->irq, saa7134_oss_irq,
-			 IRQF_SHARED | IRQF_DISABLED, dev->name,
-			(void*) &dev->dmasound)) < 0)
-		return -1;
-
-	/* general */
-	mutex_init(&dev->dmasound.lock);
-	init_waitqueue_head(&dev->dmasound.wq);
-
-	switch (dev->pci->device) {
-	case PCI_DEVICE_ID_PHILIPS_SAA7133:
-	case PCI_DEVICE_ID_PHILIPS_SAA7135:
-		saa_writel(0x588 >> 2, 0x00000fff);
-		saa_writel(0x58c >> 2, 0x00543210);
-		saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb);
-		break;
-	}
-
-	/* dsp */
-	dev->dmasound.rate = 32000;
-	if (rate)
-		dev->dmasound.rate = rate;
-	dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000;
-
-	/* mixer */
-	dev->dmasound.line1 = 50;
-	dev->dmasound.line2 = 50;
-	mixer_level(dev,LINE1,dev->dmasound.line1);
-	mixer_level(dev,LINE2,dev->dmasound.line2);
-	mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2);
-
-	return 0;
-}
-
-int saa7134_oss_fini(struct saa7134_dev *dev)
-{
-	/* nothing */
-	return 0;
-}
-
-void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
-{
-	int next_blk, reg = 0;
-
-	spin_lock(&dev->slock);
-	if (UNSET == dev->dmasound.dma_blk) {
-		dprintk("irq: recording stopped\n");
-		goto done;
-	}
-	if (0 != (status & 0x0f000000))
-		dprintk("irq: lost %ld\n", (status >> 24) & 0x0f);
-	if (0 == (status & 0x10000000)) {
-		/* odd */
-		if (0 == (dev->dmasound.dma_blk & 0x01))
-			reg = SAA7134_RS_BA1(6);
-	} else {
-		/* even */
-		if (1 == (dev->dmasound.dma_blk & 0x01))
-			reg = SAA7134_RS_BA2(6);
-	}
-	if (0 == reg) {
-		dprintk("irq: field oops [%s]\n",
-			(status & 0x10000000) ? "even" : "odd");
-		goto done;
-	}
-	if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
-		dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count,
-			dev->dmasound.bufsize);
-		dsp_dma_stop(dev);
-		goto done;
-	}
-
-	/* next block addr */
-	next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
-	saa_writel(reg,next_blk * dev->dmasound.blksize);
-	if (debug > 2)
-		dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
-			(status & 0x10000000) ? "even" : "odd ", next_blk,
-			next_blk * dev->dmasound.blksize);
-
-	/* update status & wake waiting readers */
-	dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
-	dev->dmasound.read_count += dev->dmasound.blksize;
-	wake_up(&dev->dmasound.wq);
-
- done:
-	spin_unlock(&dev->slock);
-}
-
-static int saa7134_dsp_create(struct saa7134_dev *dev)
-{
-	int err;
-
-	err = dev->dmasound.minor_dsp =
-		register_sound_dsp(&saa7134_dsp_fops,
-				   dsp_nr[dev->nr]);
-	if (err < 0) {
-		goto fail;
-	}
-	printk(KERN_INFO "%s: registered device dsp%d\n",
-	       dev->name,dev->dmasound.minor_dsp >> 4);
-
-	err = dev->dmasound.minor_mixer =
-		register_sound_mixer(&saa7134_mixer_fops,
-				     mixer_nr[dev->nr]);
-	if (err < 0)
-		goto fail;
-	printk(KERN_INFO "%s: registered device mixer%d\n",
-	       dev->name,dev->dmasound.minor_mixer >> 4);
-
-	return 0;
-
-fail:
-	unregister_sound_dsp(dev->dmasound.minor_dsp);
-	return 0;
-
-
-}
-
-static int oss_device_init(struct saa7134_dev *dev)
-{
-	dev->dmasound.priv_data = dev;
-	saa7134_oss_init1(dev);
-	saa7134_dsp_create(dev);
-	return 1;
-}
-
-static int oss_device_exit(struct saa7134_dev *dev)
-{
-
-	unregister_sound_mixer(dev->dmasound.minor_mixer);
-	unregister_sound_dsp(dev->dmasound.minor_dsp);
-
-	saa7134_oss_fini(dev);
-
-	if (dev->pci->irq > 0) {
-		synchronize_irq(dev->pci->irq);
-		free_irq(dev->pci->irq,&dev->dmasound);
-	}
-
-	dev->dmasound.priv_data = NULL;
-	return 1;
-}
-
-static int saa7134_oss_init(void)
-{
-	struct saa7134_dev *dev = NULL;
-	struct list_head *list;
-
-	if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
-		saa7134_dmasound_init = oss_device_init;
-		saa7134_dmasound_exit = oss_device_exit;
-	} else {
-		printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n");
-		return -EBUSY;
-	}
-
-	printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n");
-
-
-	list_for_each(list,&saa7134_devlist) {
-		dev = list_entry(list, struct saa7134_dev, devlist);
-		if (dev->dmasound.priv_data == NULL) {
-			oss_device_init(dev);
-		} else {
-			printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name);
-			return -EBUSY;
-		}
-	}
-
-	if (dev == NULL)
-		printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n");
-
-	return 0;
-
-}
-
-static void saa7134_oss_exit(void)
-{
-	struct saa7134_dev *dev;
-
-	list_for_each_entry(dev, &saa7134_devlist, devlist) {
-		/* Device isn't registered by OSS, probably ALSA's */
-		if (!dev->dmasound.minor_dsp)
-			continue;
-
-		oss_device_exit(dev);
-	}
-
-	saa7134_dmasound_init = NULL;
-	saa7134_dmasound_exit = NULL;
-
-	printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n");
-
-	return;
-}
-
-/* We initialize this late, to make sure the sound system is up and running */
-late_initcall(saa7134_oss_init);
-module_exit(saa7134_oss_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index 4b63ad3e8466..f1b8fcaeb43a 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -47,7 +47,7 @@ static int buffer_activate(struct saa7134_dev *dev,
 {
 
 	dprintk("buffer_activate [%p]",buf);
-	buf->vb.state = STATE_ACTIVE;
+	buf->vb.state = VIDEOBUF_ACTIVE;
 	buf->top_seen = 0;
 
 	if (NULL == next)
@@ -91,7 +91,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
 		saa7134_dma_free(q,buf);
 	}
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
 		buf->vb.width  = llength;
@@ -121,7 +121,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
 	saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE);
 	saa_writel(SAA7134_RS_CONTROL(5),control);
 
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	buf->activate = buffer_activate;
 	buf->vb.field = field;
 	return 0;
@@ -242,7 +242,7 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
 			if ((status & 0x100000) != 0x100000)
 				goto done;
 		}
-		saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
+		saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE);
 	}
 	saa7134_buffer_next(dev,&dev->ts_q);
 
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index f8e304c76232..4e9810469ae3 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -163,32 +163,6 @@ static struct saa7134_tvaudio tvaudio[] = {
 
 /* ------------------------------------------------------------------ */
 
-static void tvaudio_init(struct saa7134_dev *dev)
-{
-	int clock = saa7134_boards[dev->board].audio_clock;
-
-	if (UNSET != audio_clock_override)
-		clock = audio_clock_override;
-
-	/* init all audio registers */
-	saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
-	if (need_resched())
-		schedule();
-	else
-		udelay(10);
-
-	saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
-	saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
-	saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
-	/* frame locked audio is mandatory for NICAM */
-	saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
-
-	saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
-	saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
-	saa_writeb(SAA7134_MONITOR_SELECT,   0xa0);
-	saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
-}
-
 static u32 tvaudio_carr2reg(u32 carrier)
 {
 	u64 a = carrier;
@@ -517,9 +491,13 @@ static int tvaudio_thread(void *data)
 		dev->thread.scan1 = dev->thread.scan2;
 		dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
 		dev->tvaudio  = NULL;
-		tvaudio_init(dev);
+
+		saa_writeb(SAA7134_MONITOR_SELECT,   0xa0);
+		saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
+
 		if (dev->ctl_automute)
 			dev->automute = 1;
+
 		mute_input_7134(dev);
 
 		/* give the tuner some time */
@@ -784,27 +762,15 @@ static int mute_input_7133(struct saa7134_dev *dev)
 static int tvaudio_thread_ddep(void *data)
 {
 	struct saa7134_dev *dev = data;
-	u32 value, norms, clock;
+	u32 value, norms;
 
 
 	set_freezable();
-
-	clock = saa7134_boards[dev->board].audio_clock;
-	if (UNSET != audio_clock_override)
-		clock = audio_clock_override;
-	saa_writel(0x598 >> 2, clock);
-
-	/* unmute */
-	saa_dsp_writel(dev, 0x474 >> 2, 0x00);
-	saa_dsp_writel(dev, 0x450 >> 2, 0x00);
-
 	for (;;) {
 		tvaudio_sleep(dev,-1);
 		if (kthread_should_stop())
 			goto done;
-
 	restart:
-
 		try_to_freeze();
 
 		dev->thread.scan1 = dev->thread.scan2;
@@ -978,6 +944,38 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
 	return retval;
 }
 
+void saa7134_tvaudio_init(struct saa7134_dev *dev)
+{
+	int clock = saa7134_boards[dev->board].audio_clock;
+
+	if (UNSET != audio_clock_override)
+		clock = audio_clock_override;
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		/* init all audio registers */
+		saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x00);
+		if (need_resched())
+			schedule();
+		else
+			udelay(10);
+
+		saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
+		saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
+		saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
+		/* frame locked audio is mandatory for NICAM */
+		saa_writeb(SAA7134_AUDIO_PLL_CTRL,   0x01);
+		saa_writeb(SAA7134_NICAM_ERROR_LOW,  0x14);
+		saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		saa_writel(0x598 >> 2, clock);
+		saa_dsp_writel(dev, 0x474 >> 2, 0x00);
+		saa_dsp_writel(dev, 0x450 >> 2, 0x00);
+	}
+}
+
 int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 {
 	int (*my_thread)(void *data) = NULL;
@@ -994,6 +992,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 
 	dev->thread.thread = NULL;
 	if (my_thread) {
+		saa7134_tvaudio_init(dev);
 		/* start tvaudio thread */
 		dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
 		if (IS_ERR(dev->thread.thread)) {
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
index 81a2aedeff5c..f0d5ed9c2b06 100644
--- a/drivers/media/video/saa7134/saa7134-vbi.c
+++ b/drivers/media/video/saa7134/saa7134-vbi.c
@@ -85,7 +85,7 @@ static int buffer_activate(struct saa7134_dev *dev,
 	unsigned long control,base;
 
 	dprintk("buffer_activate [%p]\n",buf);
-	buf->vb.state = STATE_ACTIVE;
+	buf->vb.state = VIDEOBUF_ACTIVE;
 	buf->top_seen = 0;
 
 	task_init(dev,buf,TASK_A);
@@ -136,7 +136,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 	if (buf->vb.size != size)
 		saa7134_dma_free(q,buf);
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
 		buf->vb.width  = llength;
@@ -154,7 +154,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 		if (err)
 			goto oops;
 	}
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	buf->activate = buffer_activate;
 	buf->vb.field = field;
 	return 0;
@@ -240,7 +240,7 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
 			goto done;
 
 		dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount;
-		saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE);
+		saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE);
 	}
 	saa7134_buffer_next(dev,&dev->vbi_q);
 
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 6396d9b5c063..1184d359e848 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -38,7 +38,7 @@
 
 /* ------------------------------------------------------------------ */
 
-static unsigned int video_debug   = 0;
+unsigned int video_debug;
 static unsigned int gbuffers      = 8;
 static unsigned int noninterlaced = 0;
 static unsigned int gbufsize      = 720*576*4;
@@ -54,7 +54,7 @@ module_param_string(secam, secam, sizeof(secam), 0644);
 MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc");
 
 
-#define dprintk(fmt, arg...)	if (video_debug) \
+#define dprintk(fmt, arg...)	if (video_debug&0x04) \
 	printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
 
 /* ------------------------------------------------------------------ */
@@ -540,9 +540,8 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
 
 /* ------------------------------------------------------------------ */
 
-void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
+static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
 {
-
 	dprintk("set tv norm = %s\n",norm->name);
 	dev->tvnorm = norm;
 
@@ -561,7 +560,6 @@ void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
 	dev->crop_current = dev->crop_defrect;
 
 	saa7134_set_tvnorm_hw(dev);
-
 }
 
 static void video_mux(struct saa7134_dev *dev, int input)
@@ -945,7 +943,7 @@ static int buffer_activate(struct saa7134_dev *dev,
 	unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
 
 	dprintk("buffer_activate buf=%p\n",buf);
-	buf->vb.state = STATE_ACTIVE;
+	buf->vb.state = VIDEOBUF_ACTIVE;
 	buf->top_seen = 0;
 
 	set_size(dev,TASK_A,buf->vb.width,buf->vb.height,
@@ -1054,7 +1052,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 		saa7134_dma_free(q,buf);
 	}
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
 		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
 		buf->vb.width  = fh->width;
@@ -1074,7 +1072,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 		if (err)
 			goto oops;
 	}
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 	buf->activate = buffer_activate;
 	return 0;
 
@@ -1119,8 +1117,10 @@ static struct videobuf_queue_ops video_qops = {
 
 /* ------------------------------------------------------------------ */
 
-static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
+int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c)
 {
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
 	const struct v4l2_queryctrl* ctrl;
 
 	ctrl = ctrl_by_id(c->id);
@@ -1165,17 +1165,27 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_g_ctrl);
 
-static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
-		       struct v4l2_control *c)
+int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
 {
 	const struct v4l2_queryctrl* ctrl;
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
 	unsigned long flags;
 	int restart_overlay = 0;
+	int err = -EINVAL;
+
+	err = v4l2_prio_check(&dev->prio, &fh->prio);
+	if (0 != err)
+		return err;
+
+	mutex_lock(&dev->lock);
 
 	ctrl = ctrl_by_id(c->id);
 	if (NULL == ctrl)
-		return -EINVAL;
+		goto error;
+
 	dprintk("set_control name=%s val=%d\n",ctrl->name,c->value);
 	switch (ctrl->type) {
 	case V4L2_CTRL_TYPE_BOOLEAN:
@@ -1236,18 +1246,26 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
 		restart_overlay = 1;
 		break;
 	case V4L2_CID_PRIVATE_AUTOMUTE:
+	{
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &dev->tda9887_conf;
+
 		dev->ctl_automute = c->value;
 		if (dev->tda9887_conf) {
 			if (dev->ctl_automute)
 				dev->tda9887_conf |= TDA9887_AUTOMUTE;
 			else
 				dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
-			saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG,
-						 &dev->tda9887_conf);
+
+			saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
+						 &tda9887_cfg);
 		}
 		break;
+	}
 	default:
-		return -EINVAL;
+		goto error;
 	}
 	if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) {
 		spin_lock_irqsave(&dev->slock,flags);
@@ -1255,8 +1273,13 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
 		start_preview(dev,fh);
 		spin_unlock_irqrestore(&dev->slock,flags);
 	}
-	return 0;
+	err = 0;
+
+error:
+	mutex_unlock(&dev->lock);
+	return err;
 }
+EXPORT_SYMBOL_GPL(saa7134_s_ctrl);
 
 /* ------------------------------------------------------------------ */
 
@@ -1413,8 +1436,8 @@ video_poll(struct file *file, struct poll_table_struct *wait)
 		return POLLERR;
 
 	poll_wait(file, &buf->done, wait);
-	if (buf->state == STATE_DONE ||
-	    buf->state == STATE_ERROR)
+	if (buf->state == VIDEOBUF_DONE ||
+	    buf->state == VIDEOBUF_ERROR)
 		return POLLIN|POLLRDNORM;
 	return 0;
 }
@@ -1478,8 +1501,11 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma)
 
 /* ------------------------------------------------------------------ */
 
-static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
+static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv,
+						struct v4l2_format *f)
 {
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
 	struct saa7134_tvnorm *norm = dev->tvnorm;
 
 	f->fmt.vbi.sampling_rate = 6750000 * 4;
@@ -1492,837 +1518,805 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
 	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
 	f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
 
+	return 0;
 }
 
-static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-			 struct v4l2_format *f)
+static int saa7134_g_fmt_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
 {
-	switch (f->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
-		f->fmt.pix.width        = fh->width;
-		f->fmt.pix.height       = fh->height;
-		f->fmt.pix.field        = fh->cap.field;
-		f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-		f->fmt.pix.bytesperline =
-			(f->fmt.pix.width * fh->fmt->depth) >> 3;
-		f->fmt.pix.sizeimage =
-			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:
-		saa7134_vbi_fmt(dev,f);
-		return 0;
-	default:
-		return -EINVAL;
-	}
+	struct saa7134_fh *fh = priv;
+
+	f->fmt.pix.width        = fh->width;
+	f->fmt.pix.height       = fh->height;
+	f->fmt.pix.field        = fh->cap.field;
+	f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fh->fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+	return 0;
 }
 
-static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-			   struct v4l2_format *f)
+static int saa7134_g_fmt_overlay(struct file *file, void *priv,
+				struct v4l2_format *f)
 {
-	int err;
+	struct saa7134_fh *fh = priv;
 
-	switch (f->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-	{
-		struct saa7134_format *fmt;
-		enum v4l2_field field;
-		unsigned int maxw, maxh;
+	if (saa7134_no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
+	}
+	f->fmt.win = fh->win;
 
-		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
-		if (NULL == fmt)
-			return -EINVAL;
+	return 0;
+}
 
-		field = f->fmt.pix.field;
-		maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
-		maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
+static int saa7134_try_fmt_cap(struct file *file, void *priv,
+						struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_format *fmt;
+	enum v4l2_field field;
+	unsigned int maxw, maxh;
 
-		if (V4L2_FIELD_ANY == field) {
-			field = (f->fmt.pix.height > maxh/2)
-				? V4L2_FIELD_INTERLACED
-				: V4L2_FIELD_BOTTOM;
-		}
-		switch (field) {
-		case V4L2_FIELD_TOP:
-		case V4L2_FIELD_BOTTOM:
-			maxh = maxh / 2;
-			break;
-		case V4L2_FIELD_INTERLACED:
-			break;
-		default:
-			return -EINVAL;
-		}
+	fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
 
-		f->fmt.pix.field = field;
-		if (f->fmt.pix.width  < 48)
-			f->fmt.pix.width  = 48;
-		if (f->fmt.pix.height < 32)
-			f->fmt.pix.height = 32;
-		if (f->fmt.pix.width > maxw)
-			f->fmt.pix.width = maxw;
-		if (f->fmt.pix.height > maxh)
-			f->fmt.pix.height = maxh;
-		f->fmt.pix.width &= ~0x03;
-		f->fmt.pix.bytesperline =
-			(f->fmt.pix.width * fmt->depth) >> 3;
-		f->fmt.pix.sizeimage =
-			f->fmt.pix.height * f->fmt.pix.bytesperline;
+	field = f->fmt.pix.field;
+	maxw  = min(dev->crop_current.width*4,  dev->crop_bounds.width);
+	maxh  = min(dev->crop_current.height*4, dev->crop_bounds.height);
 
-		return 0;
+	if (V4L2_FIELD_ANY == field) {
+		field = (f->fmt.pix.height > maxh/2)
+			? V4L2_FIELD_INTERLACED
+			: V4L2_FIELD_BOTTOM;
 	}
-	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;
-		return 0;
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		saa7134_vbi_fmt(dev,f);
-		return 0;
+	switch (field) {
+	case V4L2_FIELD_TOP:
+	case V4L2_FIELD_BOTTOM:
+		maxh = maxh / 2;
+		break;
+	case V4L2_FIELD_INTERLACED:
+		break;
 	default:
 		return -EINVAL;
 	}
+
+	f->fmt.pix.field = field;
+	if (f->fmt.pix.width  < 48)
+		f->fmt.pix.width  = 48;
+	if (f->fmt.pix.height < 32)
+		f->fmt.pix.height = 32;
+	if (f->fmt.pix.width > maxw)
+		f->fmt.pix.width = maxw;
+	if (f->fmt.pix.height > maxh)
+		f->fmt.pix.height = maxh;
+	f->fmt.pix.width &= ~0x03;
+	f->fmt.pix.bytesperline =
+		(f->fmt.pix.width * fmt->depth) >> 3;
+	f->fmt.pix.sizeimage =
+		f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+	return 0;
 }
 
-static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
-			 struct v4l2_format *f)
+static int saa7134_try_fmt_overlay(struct file *file, void *priv,
+						struct v4l2_format *f)
 {
-	unsigned long flags;
-	int err;
-
-	switch (f->type) {
-	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-		err = saa7134_try_fmt(dev,fh,f);
-		if (0 != err)
-			return err;
-
-		fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
-		fh->width     = f->fmt.pix.width;
-		fh->height    = f->fmt.pix.height;
-		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;
-
-		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)) {
-			mutex_unlock(&dev->lock);
-			return -EFAULT;
-		}
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
 
-		if (res_check(fh, RESOURCE_OVERLAY)) {
-			spin_lock_irqsave(&dev->slock,flags);
-			stop_preview(dev,fh);
-			start_preview(dev,fh);
-			spin_unlock_irqrestore(&dev->slock,flags);
-		}
-		mutex_unlock(&dev->lock);
-		return 0;
-	case V4L2_BUF_TYPE_VBI_CAPTURE:
-		saa7134_vbi_fmt(dev,f);
-		return 0;
-	default:
+	if (saa7134_no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
 		return -EINVAL;
 	}
+
+	return verify_preview(dev, &f->fmt.win);
 }
 
-int saa7134_common_ioctl(struct saa7134_dev *dev,
-			 unsigned int cmd, void *arg)
+static int saa7134_s_fmt_cap(struct file *file, void *priv,
+					struct v4l2_format *f)
 {
+	struct saa7134_fh *fh = priv;
 	int err;
 
-	switch (cmd) {
-	case VIDIOC_QUERYCTRL:
-	{
-		const struct v4l2_queryctrl *ctrl;
-		struct v4l2_queryctrl *c = arg;
+	err = saa7134_try_fmt_cap(file, priv, f);
+	if (0 != err)
+		return err;
 
-		if ((c->id <  V4L2_CID_BASE ||
-		     c->id >= V4L2_CID_LASTP1) &&
-		    (c->id <  V4L2_CID_PRIVATE_BASE ||
-		     c->id >= V4L2_CID_PRIVATE_LASTP1))
-			return -EINVAL;
-		ctrl = ctrl_by_id(c->id);
-		*c = (NULL != ctrl) ? *ctrl : no_ctrl;
-		return 0;
+	fh->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
+	fh->width     = f->fmt.pix.width;
+	fh->height    = f->fmt.pix.height;
+	fh->cap.field = f->fmt.pix.field;
+	return 0;
+}
+
+static int saa7134_s_fmt_overlay(struct file *file, void *priv,
+					struct v4l2_format *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int err;
+	unsigned int flags;
+
+	if (saa7134_no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
 	}
-	case VIDIOC_G_CTRL:
-		return get_control(dev,arg);
-	case VIDIOC_S_CTRL:
-	{
-		mutex_lock(&dev->lock);
-		err = set_control(dev,NULL,arg);
-		mutex_unlock(&dev->lock);
+	err = verify_preview(dev, &f->fmt.win);
+	if (0 != err)
 		return err;
-	}
-	/* --- input switching --------------------------------------- */
-	case VIDIOC_ENUMINPUT:
-	{
-		struct v4l2_input *i = arg;
-		unsigned int n;
 
-		n = i->index;
-		if (n >= SAA7134_INPUT_MAX)
-			return -EINVAL;
-		if (NULL == card_in(dev,i->index).name)
-			return -EINVAL;
-		memset(i,0,sizeof(*i));
-		i->index = n;
-		i->type  = V4L2_INPUT_TYPE_CAMERA;
-		strcpy(i->name,card_in(dev,n).name);
-		if (card_in(dev,n).tv)
-			i->type = V4L2_INPUT_TYPE_TUNER;
-		i->audioset = 1;
-		if (n == dev->ctl_input) {
-			int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
-			int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
-
-			if (0 != (v1 & 0x40))
-				i->status |= V4L2_IN_ST_NO_H_LOCK;
-			if (0 != (v2 & 0x40))
-				i->status |= V4L2_IN_ST_NO_SYNC;
-			if (0 != (v2 & 0x0e))
-				i->status |= V4L2_IN_ST_MACROVISION;
-		}
-		for (n = 0; n < TVNORMS; n++)
-			i->std |= tvnorms[n].id;
-		return 0;
-	}
-	case VIDIOC_G_INPUT:
-	{
-		int *i = arg;
-		*i = dev->ctl_input;
-		return 0;
-	}
-	case VIDIOC_S_INPUT:
-	{
-		int *i = arg;
+	mutex_lock(&dev->lock);
 
-		if (*i < 0  ||  *i >= SAA7134_INPUT_MAX)
-			return -EINVAL;
-		if (NULL == card_in(dev,*i).name)
-			return -EINVAL;
-		mutex_lock(&dev->lock);
-		video_mux(dev,*i);
+	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)) {
 		mutex_unlock(&dev->lock);
-		return 0;
+		return -EFAULT;
 	}
 
+	if (res_check(fh, RESOURCE_OVERLAY)) {
+		spin_lock_irqsave(&dev->slock, flags);
+		stop_preview(dev, fh);
+		start_preview(dev, fh);
+		spin_unlock_irqrestore(&dev->slock, flags);
 	}
+
+	mutex_unlock(&dev->lock);
 	return 0;
 }
-EXPORT_SYMBOL(saa7134_common_ioctl);
 
-/*
- * This function is _not_ called directly, but from
- * video_generic_ioctl (and maybe others).  userspace
- * copying is done already, arg is a kernel pointer.
- */
-static int video_do_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, void *arg)
+int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c)
 {
-	struct saa7134_fh *fh = file->private_data;
+	const struct v4l2_queryctrl *ctrl;
+
+	if ((c->id <  V4L2_CID_BASE ||
+	     c->id >= V4L2_CID_LASTP1) &&
+	    (c->id <  V4L2_CID_PRIVATE_BASE ||
+	     c->id >= V4L2_CID_PRIVATE_LASTP1))
+		return -EINVAL;
+	ctrl = ctrl_by_id(c->id);
+	*c = (NULL != ctrl) ? *ctrl : no_ctrl;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_queryctrl);
+
+static int saa7134_enum_input(struct file *file, void *priv,
+					struct v4l2_input *i)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	unsigned int n;
+
+	n = i->index;
+	if (n >= SAA7134_INPUT_MAX)
+		return -EINVAL;
+	if (NULL == card_in(dev, i->index).name)
+		return -EINVAL;
+	memset(i, 0, sizeof(*i));
+	i->index = n;
+	i->type  = V4L2_INPUT_TYPE_CAMERA;
+	strcpy(i->name, card_in(dev, n).name);
+	if (card_in(dev, n).tv)
+		i->type = V4L2_INPUT_TYPE_TUNER;
+	i->audioset = 1;
+	if (n == dev->ctl_input) {
+		int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
+		int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
+
+		if (0 != (v1 & 0x40))
+			i->status |= V4L2_IN_ST_NO_H_LOCK;
+		if (0 != (v2 & 0x40))
+			i->status |= V4L2_IN_ST_NO_SYNC;
+		if (0 != (v2 & 0x0e))
+			i->status |= V4L2_IN_ST_MACROVISION;
+	}
+	i->std = SAA7134_NORMS;
+	return 0;
+}
+
+static int saa7134_g_input(struct file *file, void *priv, unsigned int *i)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+
+	*i = dev->ctl_input;
+	return 0;
+}
+
+static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
+{
+	struct saa7134_fh *fh = priv;
 	struct saa7134_dev *dev = fh->dev;
-	unsigned long flags;
 	int err;
 
-	if (video_debug > 1)
-		v4l_print_ioctl(dev->name,cmd);
-
-	switch (cmd) {
-	case VIDIOC_S_CTRL:
-	case VIDIOC_S_STD:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_S_TUNER:
-	case VIDIOC_S_FREQUENCY:
-		err = v4l2_prio_check(&dev->prio,&fh->prio);
-		if (0 != err)
-			return err;
-	}
+	err = v4l2_prio_check(&dev->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-	switch (cmd) {
-	case VIDIOC_QUERYCAP:
-	{
-		struct v4l2_capability *cap = arg;
-		unsigned int tuner_type = dev->tuner_type;
-
-		memset(cap,0,sizeof(*cap));
-		strcpy(cap->driver, "saa7134");
-		strlcpy(cap->card, saa7134_boards[dev->board].name,
-			sizeof(cap->card));
-		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-		cap->version = SAA7134_VERSION_CODE;
-		cap->capabilities =
-			V4L2_CAP_VIDEO_CAPTURE |
-			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 (i < 0  ||  i >= SAA7134_INPUT_MAX)
+		return -EINVAL;
+	if (NULL == card_in(dev, i).name)
+		return -EINVAL;
+	mutex_lock(&dev->lock);
+	video_mux(dev, i);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
 
-		if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
-			cap->capabilities &= ~V4L2_CAP_TUNER;
+static int saa7134_querycap(struct file *file, void  *priv,
+					struct v4l2_capability *cap)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
 
+	unsigned int tuner_type = dev->tuner_type;
+
+	strcpy(cap->driver, "saa7134");
+	strlcpy(cap->card, saa7134_boards[dev->board].name,
+		sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cap->version = SAA7134_VERSION_CODE;
+	cap->capabilities =
+		V4L2_CAP_VIDEO_CAPTURE |
+		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;
 		return 0;
-	}
+}
 
-	/* --- tv standards ------------------------------------------ */
-	case VIDIOC_ENUMSTD:
-	{
-		struct v4l2_standard *e = arg;
-		unsigned int i;
+static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	unsigned long flags;
+	unsigned int i;
+	v4l2_std_id fixup;
+	int err;
 
-		i = e->index;
-		if (i >= TVNORMS)
-			return -EINVAL;
-		err = v4l2_video_std_construct(e, tvnorms[e->index].id,
-					       tvnorms[e->index].name);
-		e->index = i;
-		if (err < 0)
-			return err;
-		return 0;
-	}
-	case VIDIOC_G_STD:
-	{
-		v4l2_std_id *id = arg;
+	err = v4l2_prio_check(&dev->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		*id = dev->tvnorm->id;
-		return 0;
-	}
-	case VIDIOC_S_STD:
-	{
-		v4l2_std_id *id = arg;
-		unsigned int i;
-		v4l2_std_id fixup;
+	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;
-		if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
-			if (secam[0] == 'L' || secam[0] == 'l') {
-				if (secam[1] == 'C' || secam[1] == 'c')
-					fixup = V4L2_STD_SECAM_LC;
-				else
-					fixup = V4L2_STD_SECAM_L;
-			} else {
-				if (secam[0] == 'D' || secam[0] == 'd')
-					fixup = V4L2_STD_SECAM_DK;
-				else
-					fixup = V4L2_STD_SECAM;
-			}
-			for (i = 0; i < TVNORMS; i++)
-				if (fixup == tvnorms[i].id)
-					break;
+	if (i == TVNORMS)
+		return -EINVAL;
+
+	if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
+		if (secam[0] == 'L' || secam[0] == 'l') {
+			if (secam[1] == 'C' || secam[1] == 'c')
+				fixup = V4L2_STD_SECAM_LC;
+			else
+				fixup = V4L2_STD_SECAM_L;
+		} else {
+			if (secam[0] == 'D' || secam[0] == 'd')
+				fixup = V4L2_STD_SECAM_DK;
+			else
+				fixup = V4L2_STD_SECAM;
 		}
-		mutex_lock(&dev->lock);
-		if (res_check(fh, RESOURCE_OVERLAY)) {
-			spin_lock_irqsave(&dev->slock,flags);
-			stop_preview(dev,fh);
-			spin_unlock_irqrestore(&dev->slock, flags);
-
-			set_tvnorm(dev,&tvnorms[i]);
-
-			spin_lock_irqsave(&dev->slock, flags);
-			start_preview(dev,fh);
-			spin_unlock_irqrestore(&dev->slock,flags);
-		} else
-			set_tvnorm(dev,&tvnorms[i]);
-		saa7134_tvaudio_do_scan(dev);
-		mutex_unlock(&dev->lock);
-		return 0;
+		for (i = 0; i < TVNORMS; i++)
+			if (fixup == tvnorms[i].id)
+				break;
 	}
 
-	case VIDIOC_CROPCAP:
-	{
-		struct v4l2_cropcap *cap = arg;
+	*id = tvnorms[i].id;
 
-		if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-		    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-			return -EINVAL;
-		cap->bounds  = dev->crop_bounds;
-		cap->defrect = dev->crop_defrect;
-		cap->pixelaspect.numerator   = 1;
-		cap->pixelaspect.denominator = 1;
-		if (dev->tvnorm->id & V4L2_STD_525_60) {
-			cap->pixelaspect.numerator   = 11;
-			cap->pixelaspect.denominator = 10;
-		}
-		if (dev->tvnorm->id & V4L2_STD_625_50) {
-			cap->pixelaspect.numerator   = 54;
-			cap->pixelaspect.denominator = 59;
-		}
-		return 0;
-	}
+	mutex_lock(&dev->lock);
+	if (res_check(fh, RESOURCE_OVERLAY)) {
+		spin_lock_irqsave(&dev->slock, flags);
+		stop_preview(dev, fh);
+		spin_unlock_irqrestore(&dev->slock, flags);
 
-	case VIDIOC_G_CROP:
-	{
-		struct v4l2_crop * crop = arg;
+		set_tvnorm(dev, &tvnorms[i]);
 
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-			return -EINVAL;
-		crop->c = dev->crop_current;
-		return 0;
-	}
-	case VIDIOC_S_CROP:
-	{
-		struct v4l2_crop *crop = arg;
-		struct v4l2_rect *b = &dev->crop_bounds;
+		spin_lock_irqsave(&dev->slock, flags);
+		start_preview(dev, fh);
+		spin_unlock_irqrestore(&dev->slock, flags);
+	} else
+		set_tvnorm(dev, &tvnorms[i]);
 
-		if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-		    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-			return -EINVAL;
-		if (crop->c.height < 0)
-			return -EINVAL;
-		if (crop->c.width < 0)
-			return -EINVAL;
+	saa7134_tvaudio_do_scan(dev);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
 
-		if (res_locked(fh->dev,RESOURCE_OVERLAY))
-			return -EBUSY;
-		if (res_locked(fh->dev,RESOURCE_VIDEO))
-			return -EBUSY;
+static int saa7134_cropcap(struct file *file, void *priv,
+					struct v4l2_cropcap *cap)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
 
-		if (crop->c.top < b->top)
-			crop->c.top = b->top;
-		if (crop->c.top > b->top + b->height)
-			crop->c.top = b->top + b->height;
-		if (crop->c.height > b->top - crop->c.top + b->height)
-			crop->c.height = b->top - crop->c.top + b->height;
-
-		if (crop->c.left < b->left)
-			crop->c.left = b->left;
-		if (crop->c.left > b->left + b->width)
-			crop->c.left = b->left + b->width;
-		if (crop->c.width > b->left - crop->c.left + b->width)
-			crop->c.width = b->left - crop->c.left + b->width;
-
-		dev->crop_current = crop->c;
-		return 0;
+	if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+	cap->bounds  = dev->crop_bounds;
+	cap->defrect = dev->crop_defrect;
+	cap->pixelaspect.numerator   = 1;
+	cap->pixelaspect.denominator = 1;
+	if (dev->tvnorm->id & V4L2_STD_525_60) {
+		cap->pixelaspect.numerator   = 11;
+		cap->pixelaspect.denominator = 10;
+	}
+	if (dev->tvnorm->id & V4L2_STD_625_50) {
+		cap->pixelaspect.numerator   = 54;
+		cap->pixelaspect.denominator = 59;
 	}
+	return 0;
+}
 
-	/* --- tuner ioctls ------------------------------------------ */
-	case VIDIOC_G_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
-		int n;
+static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
 
-		if (0 != t->index)
-			return -EINVAL;
-		memset(t,0,sizeof(*t));
-		for (n = 0; n < SAA7134_INPUT_MAX; n++)
-			if (card_in(dev,n).tv)
-				break;
-		if (NULL != card_in(dev,n).name) {
-			strcpy(t->name, "Television");
-			t->type = V4L2_TUNER_ANALOG_TV;
-			t->capability = V4L2_TUNER_CAP_NORM |
-				V4L2_TUNER_CAP_STEREO |
-				V4L2_TUNER_CAP_LANG1 |
-				V4L2_TUNER_CAP_LANG2;
-			t->rangehigh = 0xffffffffUL;
-			t->rxsubchans = saa7134_tvaudio_getstereo(dev);
-			t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
-		}
-		if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
-			t->signal = 0xffff;
-		return 0;
-	}
-	case VIDIOC_S_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
-		int rx,mode;
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+	crop->c = dev->crop_current;
+	return 0;
+}
 
-		mode = dev->thread.mode;
-		if (UNSET == mode) {
-			rx   = saa7134_tvaudio_getstereo(dev);
-			mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
-		}
-		if (mode != t->audmode) {
-			dev->thread.mode = t->audmode;
-		}
-		return 0;
-	}
-	case VIDIOC_G_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
+static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+	struct v4l2_rect *b = &dev->crop_bounds;
 
-		memset(f,0,sizeof(*f));
-		f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-		f->frequency = dev->ctl_freq;
-		return 0;
-	}
-	case VIDIOC_S_FREQUENCY:
-	{
-		struct v4l2_frequency *f = arg;
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+	if (crop->c.height < 0)
+		return -EINVAL;
+	if (crop->c.width < 0)
+		return -EINVAL;
 
-		if (0 != f->tuner)
-			return -EINVAL;
-		if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
-			return -EINVAL;
-		if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
-			return -EINVAL;
-		mutex_lock(&dev->lock);
-		dev->ctl_freq = f->frequency;
+	if (res_locked(fh->dev, RESOURCE_OVERLAY))
+		return -EBUSY;
+	if (res_locked(fh->dev, RESOURCE_VIDEO))
+		return -EBUSY;
+
+	if (crop->c.top < b->top)
+		crop->c.top = b->top;
+	if (crop->c.top > b->top + b->height)
+		crop->c.top = b->top + b->height;
+	if (crop->c.height > b->top - crop->c.top + b->height)
+		crop->c.height = b->top - crop->c.top + b->height;
+
+	if (crop->c.left < b->left)
+		crop->c.left = b->left;
+	if (crop->c.left > b->left + b->width)
+		crop->c.left = b->left + b->width;
+	if (crop->c.width > b->left - crop->c.left + b->width)
+		crop->c.width = b->left - crop->c.left + b->width;
+
+	dev->crop_current = crop->c;
+	return 0;
+}
 
-		saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
+static int saa7134_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int n;
 
-		saa7134_tvaudio_do_scan(dev);
-		mutex_unlock(&dev->lock);
-		return 0;
-	}
+	if (0 != t->index)
+		return -EINVAL;
+	memset(t, 0, sizeof(*t));
+	for (n = 0; n < SAA7134_INPUT_MAX; n++)
+		if (card_in(dev, n).tv)
+			break;
+	if (NULL != card_in(dev, n).name) {
+		strcpy(t->name, "Television");
+		t->type = V4L2_TUNER_ANALOG_TV;
+		t->capability = V4L2_TUNER_CAP_NORM |
+			V4L2_TUNER_CAP_STEREO |
+			V4L2_TUNER_CAP_LANG1 |
+			V4L2_TUNER_CAP_LANG2;
+		t->rangehigh = 0xffffffffUL;
+		t->rxsubchans = saa7134_tvaudio_getstereo(dev);
+		t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+	}
+	if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
+		t->signal = 0xffff;
+	return 0;
+}
 
-	/* --- control ioctls ---------------------------------------- */
-	case VIDIOC_ENUMINPUT:
-	case VIDIOC_G_INPUT:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_QUERYCTRL:
-	case VIDIOC_G_CTRL:
-	case VIDIOC_S_CTRL:
-		return saa7134_common_ioctl(dev, cmd, arg);
+static int saa7134_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int rx, mode, err;
 
-	case VIDIOC_G_AUDIO:
-	{
-		struct v4l2_audio *a = arg;
+	err = v4l2_prio_check(&dev->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		memset(a,0,sizeof(*a));
-		strcpy(a->name,"audio");
-		return 0;
-	}
-	case VIDIOC_S_AUDIO:
-		return 0;
-	case VIDIOC_G_PARM:
-	{
-		struct v4l2_captureparm *parm = arg;
-		memset(parm,0,sizeof(*parm));
-		return 0;
+	mode = dev->thread.mode;
+	if (UNSET == mode) {
+		rx   = saa7134_tvaudio_getstereo(dev);
+		mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
 	}
+	if (mode != t->audmode)
+		dev->thread.mode = t->audmode;
 
-	case VIDIOC_G_PRIORITY:
-	{
-		enum v4l2_priority *p = arg;
+	return 0;
+}
 
-		*p = v4l2_prio_max(&dev->prio);
-		return 0;
-	}
-	case VIDIOC_S_PRIORITY:
-	{
-		enum v4l2_priority *prio = arg;
+static int saa7134_g_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
 
-		return v4l2_prio_change(&dev->prio, &fh->prio, *prio);
-	}
+	f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+	f->frequency = dev->ctl_freq;
 
-	/* --- preview ioctls ---------------------------------------- */
-	case VIDIOC_ENUM_FMT:
-	{
-		struct v4l2_fmtdesc *f = arg;
-		enum v4l2_buf_type type;
-		unsigned int index;
-
-		index = f->index;
-		type  = f->type;
-		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 &&
-			    formats[index].planar)
-				return -EINVAL;
-			memset(f,0,sizeof(*f));
-			f->index = index;
-			f->type  = type;
-			strlcpy(f->description,formats[index].name,sizeof(f->description));
-			f->pixelformat = formats[index].fourcc;
-			break;
-		case V4L2_BUF_TYPE_VBI_CAPTURE:
-			if (0 != index)
-				return -EINVAL;
-			memset(f,0,sizeof(*f));
-			f->index = index;
-			f->type  = type;
-			f->pixelformat = V4L2_PIX_FMT_GREY;
-			strcpy(f->description,"vbi data");
-			break;
-		default:
-			return -EINVAL;
-		}
-		return 0;
-	}
-	case VIDIOC_G_FBUF:
-	{
-		struct v4l2_framebuffer *fb = arg;
+	return 0;
+}
 
-		*fb = dev->ovbuf;
-		fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
-		return 0;
-	}
-	case VIDIOC_S_FBUF:
-	{
-		struct v4l2_framebuffer *fb = arg;
-		struct saa7134_format *fmt;
+static int saa7134_s_frequency(struct file *file, void *priv,
+					struct v4l2_frequency *f)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int err;
 
-		if(!capable(CAP_SYS_ADMIN) &&
-		   !capable(CAP_SYS_RAWIO))
-			return -EPERM;
+	err = v4l2_prio_check(&dev->prio, &fh->prio);
+	if (0 != err)
+		return err;
 
-		/* check args */
-		fmt = format_by_fourcc(fb->fmt.pixelformat);
-		if (NULL == fmt)
-			return -EINVAL;
+	if (0 != f->tuner)
+		return -EINVAL;
+	if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
+		return -EINVAL;
+	if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
+		return -EINVAL;
+	mutex_lock(&dev->lock);
+	dev->ctl_freq = f->frequency;
 
-		/* ok, accept it */
-		dev->ovbuf = *fb;
-		dev->ovfmt = fmt;
-		if (0 == dev->ovbuf.fmt.bytesperline)
-			dev->ovbuf.fmt.bytesperline =
-				dev->ovbuf.fmt.width*fmt->depth/8;
-		return 0;
+	saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f);
+
+	saa7134_tvaudio_do_scan(dev);
+	mutex_unlock(&dev->lock);
+	return 0;
+}
+
+static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	strcpy(a->name, "audio");
+	return 0;
+}
+
+static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
+{
+	return 0;
+}
+
+static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+
+	*p = v4l2_prio_max(&dev->prio);
+	return 0;
+}
+
+static int saa7134_s_priority(struct file *file, void *f,
+					enum v4l2_priority prio)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+
+	return v4l2_prio_change(&dev->prio, &fh->prio, prio);
+}
+
+static int saa7134_enum_fmt_cap(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (f->index >= FORMATS)
+		return -EINVAL;
+
+	strlcpy(f->description, formats[f->index].name,
+		sizeof(f->description));
+
+	f->pixelformat = formats[f->index].fourcc;
+
+	return 0;
+}
+
+static int saa7134_enum_fmt_overlay(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (saa7134_no_overlay > 0) {
+		printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
+		return -EINVAL;
 	}
-	case VIDIOC_OVERLAY:
-	{
-		int *on = arg;
 
-		if (*on) {
-			if (saa7134_no_overlay > 0) {
-				printk ("no_overlay\n");
-				return -EINVAL;
-			}
+	if ((f->index >= FORMATS) || formats[f->index].planar)
+		return -EINVAL;
 
-			if (!res_get(dev,fh,RESOURCE_OVERLAY))
-				return -EBUSY;
-			spin_lock_irqsave(&dev->slock,flags);
-			start_preview(dev,fh);
-			spin_unlock_irqrestore(&dev->slock,flags);
-		}
-		if (!*on) {
-			if (!res_check(fh, RESOURCE_OVERLAY))
-				return -EINVAL;
-			spin_lock_irqsave(&dev->slock,flags);
-			stop_preview(dev,fh);
-			spin_unlock_irqrestore(&dev->slock,flags);
-			res_free(dev,fh,RESOURCE_OVERLAY);
+	strlcpy(f->description, formats[f->index].name,
+		sizeof(f->description));
+
+	f->pixelformat = formats[f->index].fourcc;
+
+	return 0;
+}
+
+static int saa7134_enum_fmt_vbi(struct file *file, void  *priv,
+					struct v4l2_fmtdesc *f)
+{
+	if (0 != f->index)
+		return -EINVAL;
+
+	f->pixelformat = V4L2_PIX_FMT_GREY;
+	strcpy(f->description, "vbi data");
+
+	return 0;
+}
+
+static int saa7134_g_fbuf(struct file *file, void *f,
+				struct v4l2_framebuffer *fb)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+
+	*fb = dev->ovbuf;
+	fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+
+	return 0;
+}
+
+static int saa7134_s_fbuf(struct file *file, void *f,
+					struct v4l2_framebuffer *fb)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+	struct saa7134_format *fmt;
+
+	if (!capable(CAP_SYS_ADMIN) &&
+	   !capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* check args */
+	fmt = format_by_fourcc(fb->fmt.pixelformat);
+	if (NULL == fmt)
+		return -EINVAL;
+
+	/* ok, accept it */
+	dev->ovbuf = *fb;
+	dev->ovfmt = fmt;
+	if (0 == dev->ovbuf.fmt.bytesperline)
+		dev->ovbuf.fmt.bytesperline =
+			dev->ovbuf.fmt.width*fmt->depth/8;
+	return 0;
+}
+
+static int saa7134_overlay(struct file *file, void *f, unsigned int on)
+{
+	struct saa7134_fh *fh = f;
+	struct saa7134_dev *dev = fh->dev;
+	unsigned long flags;
+
+	if (on) {
+		if (saa7134_no_overlay > 0) {
+			dprintk("no_overlay\n");
+			return -EINVAL;
 		}
-		return 0;
-	}
 
-	/* --- capture ioctls ---------------------------------------- */
-	case VIDIOC_G_FMT:
-	{
-		struct v4l2_format *f = arg;
-		return saa7134_g_fmt(dev,fh,f);
-	}
-	case VIDIOC_S_FMT:
-	{
-		struct v4l2_format *f = arg;
-		return saa7134_s_fmt(dev,fh,f);
+		if (!res_get(dev, fh, RESOURCE_OVERLAY))
+			return -EBUSY;
+		spin_lock_irqsave(&dev->slock, flags);
+		start_preview(dev, fh);
+		spin_unlock_irqrestore(&dev->slock, flags);
 	}
-	case VIDIOC_TRY_FMT:
-	{
-		struct v4l2_format *f = arg;
-		return saa7134_try_fmt(dev,fh,f);
+	if (!on) {
+		if (!res_check(fh, RESOURCE_OVERLAY))
+			return -EINVAL;
+		spin_lock_irqsave(&dev->slock, flags);
+		stop_preview(dev, fh);
+		spin_unlock_irqrestore(&dev->slock, flags);
+		res_free(dev, fh, RESOURCE_OVERLAY);
 	}
+	return 0;
+}
+
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-	case VIDIOCGMBUF:
-		return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers);
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+	struct saa7134_fh *fh = file->private_data;
+	return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8);
+}
 #endif
-	case VIDIOC_REQBUFS:
-		return videobuf_reqbufs(saa7134_queue(fh),arg);
 
-	case VIDIOC_QUERYBUF:
-		return videobuf_querybuf(saa7134_queue(fh),arg);
+static int saa7134_reqbufs(struct file *file, void *priv,
+					struct v4l2_requestbuffers *p)
+{
+	struct saa7134_fh *fh = priv;
+	return videobuf_reqbufs(saa7134_queue(fh), p);
+}
 
-	case VIDIOC_QBUF:
-		return videobuf_qbuf(saa7134_queue(fh),arg);
+static int saa7134_querybuf(struct file *file, void *priv,
+					struct v4l2_buffer *b)
+{
+	struct saa7134_fh *fh = priv;
+	return videobuf_querybuf(saa7134_queue(fh), b);
+}
 
-	case VIDIOC_DQBUF:
-		return videobuf_dqbuf(saa7134_queue(fh),arg,
-				      file->f_flags & O_NONBLOCK);
+static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct saa7134_fh *fh = priv;
+	return videobuf_qbuf(saa7134_queue(fh), b);
+}
 
-	case VIDIOC_STREAMON:
-	{
-		int res = saa7134_resource(fh);
+static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct saa7134_fh *fh = priv;
+	return videobuf_dqbuf(saa7134_queue(fh), b,
+				file->f_flags & O_NONBLOCK);
+}
 
-		if (!res_get(dev,fh,res))
-			return -EBUSY;
-		return videobuf_streamon(saa7134_queue(fh));
-	}
-	case VIDIOC_STREAMOFF:
-	{
-		int res = saa7134_resource(fh);
+static int saa7134_streamon(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int res = saa7134_resource(fh);
 
-		err = videobuf_streamoff(saa7134_queue(fh));
-		if (err < 0)
-			return err;
-		res_free(dev,fh,res);
-		return 0;
-	}
+	if (!res_get(dev, fh, res))
+		return -EBUSY;
 
-	default:
-		return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-						  video_do_ioctl);
-	}
+	return videobuf_streamon(saa7134_queue(fh));
+}
+
+static int saa7134_streamoff(struct file *file, void *priv,
+					enum v4l2_buf_type type)
+{
+	int err;
+	struct saa7134_fh *fh = priv;
+	struct saa7134_dev *dev = fh->dev;
+	int res = saa7134_resource(fh);
+
+	err = videobuf_streamoff(saa7134_queue(fh));
+	if (err < 0)
+		return err;
+	res_free(dev, fh, res);
 	return 0;
 }
 
-static int video_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg)
+static int saa7134_g_parm(struct file *file, void *fh,
+				struct v4l2_streamparm *parm)
 {
-	return video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+	return 0;
 }
 
-static int radio_do_ioctl(struct inode *inode, struct file *file,
-			  unsigned int cmd, void *arg)
+static int radio_querycap(struct file *file, void *priv,
+					struct v4l2_capability *cap)
 {
 	struct saa7134_fh *fh = file->private_data;
 	struct saa7134_dev *dev = fh->dev;
 
-	if (video_debug > 1)
-		v4l_print_ioctl(dev->name,cmd);
-	switch (cmd) {
-	case VIDIOC_QUERYCAP:
-	{
-		struct v4l2_capability *cap = arg;
-
-		memset(cap,0,sizeof(*cap));
-		strcpy(cap->driver, "saa7134");
-		strlcpy(cap->card, saa7134_boards[dev->board].name,
-			sizeof(cap->card));
-		sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
-		cap->version = SAA7134_VERSION_CODE;
-		cap->capabilities = V4L2_CAP_TUNER;
-		return 0;
-	}
-	case VIDIOC_G_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
+	strcpy(cap->driver, "saa7134");
+	strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card));
+	sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+	cap->version = SAA7134_VERSION_CODE;
+	cap->capabilities = V4L2_CAP_TUNER;
+	return 0;
+}
 
-		if (0 != t->index)
-			return -EINVAL;
+static int radio_g_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
 
-		memset(t,0,sizeof(*t));
-		strcpy(t->name, "Radio");
-		t->type = V4L2_TUNER_RADIO;
+	if (0 != t->index)
+		return -EINVAL;
 
-		saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
-		if (dev->input->amux == TV) {
-			t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
-			t->rxsubchans = (saa_readb(0x529) & 0x08) ?
-					V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
-		}
-		return 0;
+	memset(t, 0, sizeof(*t));
+	strcpy(t->name, "Radio");
+	t->type = V4L2_TUNER_RADIO;
+
+	saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+	if (dev->input->amux == TV) {
+		t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
+		t->rxsubchans = (saa_readb(0x529) & 0x08) ?
+				V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
 	}
-	case VIDIOC_S_TUNER:
-	{
-		struct v4l2_tuner *t = arg;
+	return 0;
+}
+static int radio_s_tuner(struct file *file, void *priv,
+					struct v4l2_tuner *t)
+{
+	struct saa7134_fh *fh = file->private_data;
+	struct saa7134_dev *dev = fh->dev;
 
-		if (0 != t->index)
-			return -EINVAL;
+	if (0 != t->index)
+		return -EINVAL;
 
-		saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t);
+	saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t);
+	return 0;
+}
 
-		return 0;
-	}
-	case VIDIOC_ENUMINPUT:
-	{
-		struct v4l2_input *i = arg;
+static int radio_enum_input(struct file *file, void *priv,
+					struct v4l2_input *i)
+{
+	if (i->index != 0)
+		return -EINVAL;
 
-		if (i->index != 0)
-			return -EINVAL;
-		strcpy(i->name,"Radio");
-		i->type = V4L2_INPUT_TYPE_TUNER;
-		return 0;
-	}
-	case VIDIOC_G_INPUT:
-	{
-		int *i = arg;
-		*i = 0;
-		return 0;
-	}
-	case VIDIOC_G_AUDIO:
-	{
-		struct v4l2_audio *a = arg;
+	strcpy(i->name, "Radio");
+	i->type = V4L2_INPUT_TYPE_TUNER;
 
-		memset(a,0,sizeof(*a));
-		strcpy(a->name,"Radio");
-		return 0;
-	}
-	case VIDIOC_G_STD:
-	{
-		v4l2_std_id *id = arg;
-		*id = 0;
-		return 0;
-	}
-	case VIDIOC_S_AUDIO:
-	case VIDIOC_S_INPUT:
-	case VIDIOC_S_STD:
-		return 0;
+	return 0;
+}
 
-	case VIDIOC_QUERYCTRL:
-	{
-		const struct v4l2_queryctrl *ctrl;
-		struct v4l2_queryctrl *c = arg;
+static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
 
-		if (c->id <  V4L2_CID_BASE ||
-		    c->id >= V4L2_CID_LASTP1)
-			return -EINVAL;
-		if (c->id == V4L2_CID_AUDIO_MUTE) {
-			ctrl = ctrl_by_id(c->id);
-			*c = *ctrl;
-		} else
-			*c = no_ctrl;
-		return 0;
-	}
+static int radio_g_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	memset(a, 0, sizeof(*a));
+	strcpy(a->name, "Radio");
+	return 0;
+}
 
-	case VIDIOC_G_CTRL:
-	case VIDIOC_S_CTRL:
-	case VIDIOC_G_FREQUENCY:
-	case VIDIOC_S_FREQUENCY:
-		return video_do_ioctl(inode,file,cmd,arg);
+static int radio_s_audio(struct file *file, void *priv,
+					struct v4l2_audio *a)
+{
+	return 0;
+}
 
-	default:
-		return v4l_compat_translate_ioctl(inode,file,cmd,arg,
-						  radio_do_ioctl);
-	}
+static int radio_s_input(struct file *filp, void *priv, unsigned int i)
+{
 	return 0;
 }
 
-static int radio_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg)
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
 {
-	return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
+	return 0;
+}
+
+static int radio_queryctrl(struct file *file, void *priv,
+					struct v4l2_queryctrl *c)
+{
+	const struct v4l2_queryctrl *ctrl;
+
+	if (c->id <  V4L2_CID_BASE ||
+	    c->id >= V4L2_CID_LASTP1)
+		return -EINVAL;
+	if (c->id == V4L2_CID_AUDIO_MUTE) {
+		ctrl = ctrl_by_id(c->id);
+		*c = *ctrl;
+	} else
+		*c = no_ctrl;
+	return 0;
 }
 
 static const struct file_operations video_fops =
@@ -2333,7 +2327,7 @@ static const struct file_operations video_fops =
 	.read	  = video_read,
 	.poll     = video_poll,
 	.mmap	  = video_mmap,
-	.ioctl	  = video_ioctl,
+	.ioctl	  = video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek   = no_llseek,
 };
@@ -2343,7 +2337,7 @@ static const struct file_operations radio_fops =
 	.owner	  = THIS_MODULE,
 	.open	  = video_open,
 	.release  = video_release,
-	.ioctl	  = radio_ioctl,
+	.ioctl	  = video_ioctl2,
 	.compat_ioctl	= v4l_compat_ioctl32,
 	.llseek   = no_llseek,
 };
@@ -2353,27 +2347,79 @@ static const struct file_operations radio_fops =
 
 struct video_device saa7134_video_template =
 {
-	.name          = "saa7134-video",
-	.type          = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
-			 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
-	.fops          = &video_fops,
-	.minor         = -1,
-};
-
-struct video_device saa7134_vbi_template =
-{
-	.name          = "saa7134-vbi",
-	.type          = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
-	.fops          = &video_fops,
-	.minor         = -1,
+	.name				= "saa7134-video",
+	.type				= VID_TYPE_CAPTURE|VID_TYPE_TUNER |
+					VID_TYPE_CLIPPING|VID_TYPE_SCALES,
+	.fops				= &video_fops,
+	.minor				= -1,
+	.vidioc_querycap		= saa7134_querycap,
+	.vidioc_enum_fmt_cap		= saa7134_enum_fmt_cap,
+	.vidioc_g_fmt_cap		= saa7134_g_fmt_cap,
+	.vidioc_try_fmt_cap		= saa7134_try_fmt_cap,
+	.vidioc_s_fmt_cap		= saa7134_s_fmt_cap,
+	.vidioc_enum_fmt_overlay	= saa7134_enum_fmt_overlay,
+	.vidioc_g_fmt_overlay		= saa7134_g_fmt_overlay,
+	.vidioc_try_fmt_overlay		= saa7134_try_fmt_overlay,
+	.vidioc_s_fmt_overlay		= saa7134_s_fmt_overlay,
+	.vidioc_enum_fmt_vbi		= saa7134_enum_fmt_vbi,
+	.vidioc_g_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
+	.vidioc_try_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
+	.vidioc_s_fmt_vbi		= saa7134_try_get_set_fmt_vbi,
+	.vidioc_g_audio			= saa7134_g_audio,
+	.vidioc_s_audio			= saa7134_s_audio,
+	.vidioc_cropcap			= saa7134_cropcap,
+	.vidioc_reqbufs			= saa7134_reqbufs,
+	.vidioc_querybuf		= saa7134_querybuf,
+	.vidioc_qbuf			= saa7134_qbuf,
+	.vidioc_dqbuf			= saa7134_dqbuf,
+	.vidioc_s_std			= saa7134_s_std,
+	.vidioc_enum_input		= saa7134_enum_input,
+	.vidioc_g_input			= saa7134_g_input,
+	.vidioc_s_input			= saa7134_s_input,
+	.vidioc_queryctrl		= saa7134_queryctrl,
+	.vidioc_g_ctrl			= saa7134_g_ctrl,
+	.vidioc_s_ctrl			= saa7134_s_ctrl,
+	.vidioc_streamon		= saa7134_streamon,
+	.vidioc_streamoff		= saa7134_streamoff,
+	.vidioc_g_tuner			= saa7134_g_tuner,
+	.vidioc_s_tuner			= saa7134_s_tuner,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+	.vidiocgmbuf			= vidiocgmbuf,
+#endif
+	.vidioc_g_crop			= saa7134_g_crop,
+	.vidioc_s_crop			= saa7134_s_crop,
+	.vidioc_g_fbuf			= saa7134_g_fbuf,
+	.vidioc_s_fbuf			= saa7134_s_fbuf,
+	.vidioc_overlay			= saa7134_overlay,
+	.vidioc_g_priority		= saa7134_g_priority,
+	.vidioc_s_priority		= saa7134_s_priority,
+	.vidioc_g_parm			= saa7134_g_parm,
+	.vidioc_g_frequency		= saa7134_g_frequency,
+	.vidioc_s_frequency		= saa7134_s_frequency,
+	.tvnorms			= SAA7134_NORMS,
+	.current_norm			= V4L2_STD_PAL,
 };
 
 struct video_device saa7134_radio_template =
 {
-	.name          = "saa7134-radio",
-	.type          = VID_TYPE_TUNER,
-	.fops          = &radio_fops,
-	.minor         = -1,
+	.name			= "saa7134-radio",
+	.type			= VID_TYPE_TUNER,
+	.fops			= &radio_fops,
+	.minor			= -1,
+	.vidioc_querycap	= radio_querycap,
+	.vidioc_g_tuner		= radio_g_tuner,
+	.vidioc_enum_input	= radio_enum_input,
+	.vidioc_g_audio		= radio_g_audio,
+	.vidioc_s_tuner		= radio_s_tuner,
+	.vidioc_s_audio		= radio_s_audio,
+	.vidioc_s_input		= radio_s_input,
+	.vidioc_s_std		= radio_s_std,
+	.vidioc_queryctrl	= radio_queryctrl,
+	.vidioc_g_input		= radio_g_input,
+	.vidioc_g_ctrl		= saa7134_g_ctrl,
+	.vidioc_s_ctrl		= saa7134_s_ctrl,
+	.vidioc_g_frequency	= saa7134_g_frequency,
+	.vidioc_s_frequency	= saa7134_s_frequency,
 };
 
 int saa7134_video_init1(struct saa7134_dev *dev)
@@ -2511,7 +2557,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
 				goto done;
 		}
 		dev->video_q.curr->vb.field_count = dev->video_fieldcount;
-		saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE);
+		saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE);
 	}
 	saa7134_buffer_next(dev,&dev->video_q);
 
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 66a390c321a7..ce450304fb53 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -240,6 +240,19 @@ struct saa7134_format {
 #define SAA7134_BOARD_SABRENT_TV_PCB05     115
 #define SAA7134_BOARD_10MOONSTVMASTER3     116
 #define SAA7134_BOARD_AVERMEDIA_SUPER_007  117
+#define SAA7134_BOARD_BEHOLD_401  	118
+#define SAA7134_BOARD_BEHOLD_403  	119
+#define SAA7134_BOARD_BEHOLD_403FM	120
+#define SAA7134_BOARD_BEHOLD_405	121
+#define SAA7134_BOARD_BEHOLD_405FM	122
+#define SAA7134_BOARD_BEHOLD_407	123
+#define SAA7134_BOARD_BEHOLD_407FM	124
+#define SAA7134_BOARD_BEHOLD_409	125
+#define SAA7134_BOARD_BEHOLD_505FM	126
+#define SAA7134_BOARD_BEHOLD_507_9FM	127
+#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
+#define SAA7134_BOARD_BEHOLD_607_9FM	129
+#define SAA7134_BOARD_BEHOLD_M6		130
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -481,7 +494,7 @@ struct saa7134_dev {
 	/* i2c i/o */
 	struct i2c_adapter         i2c_adap;
 	struct i2c_client          i2c_client;
-	unsigned char              eedata[128];
+	unsigned char              eedata[256];
 
 	/* video overlay */
 	struct v4l2_framebuffer    ovbuf;
@@ -566,6 +579,12 @@ struct saa7134_dev {
 
 #define saa_wait(us) { udelay(us); }
 
+#define SAA7134_NORMS	(\
+		V4L2_STD_PAL    | V4L2_STD_PAL_N | \
+		V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
+		V4L2_STD_NTSC   | V4L2_STD_PAL_M | \
+		V4L2_STD_PAL_60)
+
 /* ----------------------------------------------------------- */
 /* saa7134-core.c                                              */
 
@@ -596,9 +615,6 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
 void saa7134_buffer_timeout(unsigned long data);
 void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
 
-int saa7134_buffer_requeue(struct saa7134_dev *dev,
-			 struct saa7134_dmaqueue *q);
-
 int saa7134_set_dmabits(struct saa7134_dev *dev);
 
 extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
@@ -628,16 +644,17 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev,
 /* ----------------------------------------------------------- */
 /* saa7134-video.c                                             */
 
+extern unsigned int video_debug;
 extern struct video_device saa7134_video_template;
 extern struct video_device saa7134_radio_template;
 
-void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm);
+int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c);
+int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c);
+int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
+
 int saa7134_videoport_init(struct saa7134_dev *dev);
 void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
 
-int saa7134_common_ioctl(struct saa7134_dev *dev,
-			 unsigned int cmd, void *arg);
-
 int saa7134_video_init1(struct saa7134_dev *dev);
 int saa7134_video_init2(struct saa7134_dev *dev);
 void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
@@ -682,6 +699,7 @@ void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
 void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level);
 int saa7134_tvaudio_getstereo(struct saa7134_dev *dev);
 
+void saa7134_tvaudio_init(struct saa7134_dev *dev);
 int saa7134_tvaudio_init2(struct saa7134_dev *dev);
 int saa7134_tvaudio_fini(struct saa7134_dev *dev);
 int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile
index a56d16f69c71..7ecd5a90c7c9 100644
--- a/drivers/media/video/sn9c102/Makefile
+++ b/drivers/media/video/sn9c102/Makefile
@@ -3,6 +3,7 @@ sn9c102-objs := sn9c102_core.o \
 		sn9c102_hv7131r.o \
 		sn9c102_mi0343.o \
 		sn9c102_mi0360.o \
+		sn9c102_mt9v111.o \
 		sn9c102_ov7630.o \
 		sn9c102_ov7660.o \
 		sn9c102_pas106b.o \
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 511847912c48..c40ba3adab21 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -47,7 +47,7 @@
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.47"
+#define SN9C102_MODULE_VERSION  "1:1.47pre49"
 #define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 47)
 
 /*****************************************************************************/
@@ -3322,7 +3322,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 	cam->v4ldev->fops = &sn9c102_fops;
 	cam->v4ldev->minor = video_nr[dev_nr];
 	cam->v4ldev->release = video_device_release;
-	video_set_drvdata(cam->v4ldev, cam);
 
 	init_completion(&cam->probe);
 
@@ -3340,6 +3339,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
 
 	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
 
+	video_set_drvdata(cam->v4ldev, cam);
 	cam->module_param.force_munmap = force_munmap[dev_nr];
 	cam->module_param.frame_timeout = frame_timeout[dev_nr];
 
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 916054faf9be..35223e0d7e49 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -126,6 +126,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
 extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam);
 extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
 extern int sn9c102_probe_mi0360(struct sn9c102_device* cam);
+extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam);
 extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
 extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
 extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
@@ -144,6 +145,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
 	&sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */
+	&sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
 	&sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
diff --git a/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
new file mode 100644
index 000000000000..3b98ac3bbc38
--- /dev/null
+++ b/drivers/media/video/sn9c102/sn9c102_mt9v111.c
@@ -0,0 +1,259 @@
+/***************************************************************************
+ * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera     *
+ * Controllers                                                             *
+ *                                                                         *
+ * Copyright (C) 2007 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 "sn9c102_sensor.h"
+
+
+static int mt9v111_init(struct sn9c102_device *cam)
+{
+	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
+	int err = 0;
+
+	err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
+				       {0x00, 0x03}, {0x1a, 0x04},
+				       {0x1f, 0x05}, {0x20, 0x06},
+				       {0x1f, 0x07}, {0x81, 0x08},
+				       {0x5c, 0x09}, {0x00, 0x0a},
+				       {0x00, 0x0b}, {0x00, 0x0c},
+				       {0x00, 0x0d}, {0x00, 0x0e},
+				       {0x00, 0x0f}, {0x03, 0x10},
+				       {0x00, 0x11}, {0x00, 0x12},
+				       {0x02, 0x13}, {0x14, 0x14},
+				       {0x28, 0x15}, {0x1e, 0x16},
+				       {0xe2, 0x17}, {0x06, 0x18},
+				       {0x00, 0x19}, {0x00, 0x1a},
+				       {0x00, 0x1b}, {0x08, 0x20},
+				       {0x39, 0x21}, {0x51, 0x22},
+				       {0x63, 0x23}, {0x73, 0x24},
+				       {0x82, 0x25}, {0x8f, 0x26},
+				       {0x9b, 0x27}, {0xa7, 0x28},
+				       {0xb1, 0x29}, {0xbc, 0x2a},
+				       {0xc6, 0x2b}, {0xcf, 0x2c},
+				       {0xd8, 0x2d}, {0xe1, 0x2e},
+				       {0xea, 0x2f}, {0xf2, 0x30},
+				       {0x13, 0x84}, {0x00, 0x85},
+				       {0x25, 0x86}, {0x00, 0x87},
+				       {0x07, 0x88}, {0x00, 0x89},
+				       {0xee, 0x8a}, {0x0f, 0x8b},
+				       {0xe5, 0x8c}, {0x0f, 0x8d},
+				       {0x2e, 0x8e}, {0x00, 0x8f},
+				       {0x30, 0x90}, {0x00, 0x91},
+				       {0xd4, 0x92}, {0x0f, 0x93},
+				       {0xfc, 0x94}, {0x0f, 0x95},
+				       {0x14, 0x96}, {0x00, 0x97},
+				       {0x00, 0x98}, {0x60, 0x99},
+				       {0x07, 0x9a}, {0x40, 0x9b},
+				       {0x20, 0x9c}, {0x00, 0x9d},
+				       {0x00, 0x9e}, {0x00, 0x9f},
+				       {0x2d, 0xc0}, {0x2d, 0xc1},
+				       {0x3a, 0xc2}, {0x05, 0xc3},
+				       {0x04, 0xc4}, {0x3f, 0xc5},
+				       {0x00, 0xc6}, {0x00, 0xc7},
+				       {0x50, 0xc8}, {0x3c, 0xc9},
+				       {0x28, 0xca}, {0xd8, 0xcb},
+				       {0x14, 0xcc}, {0xec, 0xcd},
+				       {0x32, 0xce}, {0xdd, 0xcf},
+				       {0x2d, 0xd0}, {0xdd, 0xd1},
+				       {0x6a, 0xd2}, {0x50, 0xd3},
+				       {0x60, 0xd4}, {0x00, 0xd5},
+				       {0x00, 0xd6});
+
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
+					 0x00, 0x01, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
+					 0x00, 0x01, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
+					 0x00, 0x00, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
+					 0x04, 0x80, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
+					 0x00, 0x04, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08,
+					 0x00, 0x08, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02,
+					 0x00, 0x16, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
+					 0x01, 0xe7, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
+					 0x02, 0x87, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
+					 0x00, 0x40, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
+					 0x00, 0x09, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07,
+					 0x30, 0x02, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c,
+					 0x00, 0x00, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12,
+					 0x00, 0xb0, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13,
+					 0x00, 0x7c, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e,
+					 0x00, 0x00, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
+					 0x00, 0x00, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20,
+					 0x00, 0x00, 0, 0);
+	err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01,
+					 0x00, 0x04, 0, 0);
+
+	return err;
+}
+
+static int mt9v111_get_ctrl(struct sn9c102_device *cam,
+			    struct v4l2_control *ctrl)
+{
+	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
+	u8 data[2];
+	int err = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
+					     data) < 0)
+			return -EIO;
+		ctrl->value = data[1] & 0x80 ? 1 : 0;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	return err ? -EIO : 0;
+}
+
+static int mt9v111_set_ctrl(struct sn9c102_device *cam,
+			    const struct v4l2_control *ctrl)
+{
+	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
+	int err = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_VFLIP:
+		err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
+						 0x20,
+						 ctrl->value ? 0x80 : 0x00,
+						 ctrl->value ? 0x80 : 0x00, 0,
+						 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return err ? -EIO : 0;
+}
+
+static int mt9v111_set_crop(struct sn9c102_device *cam,
+			    const struct v4l2_rect *rect)
+{
+	struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
+	int err = 0;
+	u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2;
+
+	err += sn9c102_write_reg(cam, v_start, 0x13);
+
+	return err;
+}
+
+static int mt9v111_set_pix_format(struct sn9c102_device *cam,
+				  const struct v4l2_pix_format *pix)
+{
+	int err = 0;
+
+	if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
+		err += sn9c102_write_reg(cam, 0xb4, 0x17);
+	} else {
+		err += sn9c102_write_reg(cam, 0xe2, 0x17);
+	}
+
+	return err;
+}
+
+
+static const struct sn9c102_sensor mt9v111 = {
+	.name = "MT9V111",
+	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+	.supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
+	.frequency = SN9C102_I2C_100KHZ,
+	.interface = SN9C102_I2C_2WIRES,
+	.i2c_slave_id = 0x5c,
+	.init = &mt9v111_init,
+	.qctrl = {
+		{
+			.id = V4L2_CID_VFLIP,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "vertical mirror",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 1,
+			.default_value = 0,
+			.flags = 0,
+		},
+	},
+	.get_ctrl = &mt9v111_get_ctrl,
+	.set_ctrl = &mt9v111_set_ctrl,
+	.cropcap = {
+		.bounds = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+		.defrect = {
+			.left = 0,
+			.top = 0,
+			.width = 640,
+			.height = 480,
+		},
+	},
+	.set_crop = &mt9v111_set_crop,
+	.pix_format = {
+		.width = 640,
+		.height = 480,
+		.pixelformat = V4L2_PIX_FMT_SBGGR8,
+		.priv = 8,
+	},
+	.set_pix_format = &mt9v111_set_pix_format
+};
+
+
+int sn9c102_probe_mt9v111(struct sn9c102_device *cam)
+{
+	u8 data[2];
+	int err = 0;
+
+	err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
+					{0x29, 0x01}, {0x42, 0x17},
+					{0x62, 0x17}, {0x08, 0x01});
+	err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4,
+					 mt9v111.i2c_slave_id, 0x01, 0x00,
+					 0x04, 0, 0);
+	if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111,
+					    mt9v111.i2c_slave_id, 0x36, 2,
+					    data) < 0)
+		return -EIO;
+
+	if (data[0] != 0x82 || data[1] != 0x3a)
+		return -ENODEV;
+
+	sn9c102_attach_sensor(cam, &mt9v111);
+
+	return 0;
+}
diff --git a/drivers/media/video/stk-sensor.c b/drivers/media/video/stk-sensor.c
new file mode 100644
index 000000000000..4a9a0b62efa3
--- /dev/null
+++ b/drivers/media/video/stk-sensor.c
@@ -0,0 +1,578 @@
+/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams)
+ *
+ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
+ *
+ * Some parts derived from ov7670.c:
+ * Copyright 2006 One Laptop Per Child Association, Inc.  Written
+ * by Jonathan Corbet with substantial inspiration from Mark
+ * McClelland's ovcamchip code.
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ *
+ * This file may be distributed under the terms of the GNU General
+ * 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.
+ */
+
+/* Controlling the sensor via the STK1125 vendor specific control interface:
+ * The camera uses an OmniVision sensor and the stk1125 provides an
+ * SCCB(i2c)-USB bridge which let us program the sensor.
+ * In my case the sensor id is 0x9652, it can be read from sensor's register
+ * 0x0A and 0x0B as follows:
+ * - read register #R:
+ *   output #R to index 0x0208
+ *   output 0x0070 to index 0x0200
+ *   input 1 byte from index 0x0201 (some kind of status register)
+ *     until its value is 0x01
+ *   input 1 byte from index 0x0209. This is the value of #R
+ * - write value V to register #R
+ *   output #R to index 0x0204
+ *   output V to index 0x0205
+ *   output 0x0005 to index 0x0200
+ *   input 1 byte from index 0x0201 until its value becomes 0x04
+ */
+
+/* It seems the i2c bus is controlled with these registers */
+
+#include "stk-webcam.h"
+
+#define STK_IIC_BASE		(0x0200)
+#  define STK_IIC_OP		(STK_IIC_BASE)
+#    define STK_IIC_OP_TX	(0x05)
+#    define STK_IIC_OP_RX	(0x70)
+#  define STK_IIC_STAT		(STK_IIC_BASE+1)
+#    define STK_IIC_STAT_TX_OK	(0x04)
+#    define STK_IIC_STAT_RX_OK	(0x01)
+/* I don't know what does this register.
+ * when it is 0x00 or 0x01, we cannot talk to the sensor,
+ * other values work */
+#  define STK_IIC_ENABLE	(STK_IIC_BASE+2)
+#    define STK_IIC_ENABLE_NO	(0x00)
+/* This is what the driver writes in windows */
+#    define STK_IIC_ENABLE_YES	(0x1e)
+/*
+ * Address of the slave. Seems like the binary driver look for the
+ * sensor in multiple places, attempting a reset sequence.
+ * We only know about the ov9650
+ */
+#  define STK_IIC_ADDR		(STK_IIC_BASE+3)
+#  define STK_IIC_TX_INDEX	(STK_IIC_BASE+4)
+#  define STK_IIC_TX_VALUE	(STK_IIC_BASE+5)
+#  define STK_IIC_RX_INDEX	(STK_IIC_BASE+8)
+#  define STK_IIC_RX_VALUE	(STK_IIC_BASE+9)
+
+#define MAX_RETRIES		(50)
+
+#define SENSOR_ADDRESS		(0x60)
+
+/* From ov7670.c (These registers aren't fully accurate) */
+
+/* Registers */
+#define REG_GAIN	0x00	/* Gain lower 8 bits (rest in vref) */
+#define REG_BLUE	0x01	/* blue gain */
+#define REG_RED		0x02	/* red gain */
+#define REG_VREF	0x03	/* Pieces of GAIN, VSTART, VSTOP */
+#define REG_COM1	0x04	/* Control 1 */
+#define  COM1_CCIR656	  0x40  /* CCIR656 enable */
+#define  COM1_QFMT	  0x20  /* QVGA/QCIF format */
+#define  COM1_SKIP_0	  0x00  /* Do not skip any row */
+#define  COM1_SKIP_2	  0x04  /* Skip 2 rows of 4 */
+#define  COM1_SKIP_3	  0x08  /* Skip 3 rows of 4 */
+#define REG_BAVE	0x05	/* U/B Average level */
+#define REG_GbAVE	0x06	/* Y/Gb Average level */
+#define REG_AECHH	0x07	/* AEC MS 5 bits */
+#define REG_RAVE	0x08	/* V/R Average level */
+#define REG_COM2	0x09	/* Control 2 */
+#define  COM2_SSLEEP	  0x10	/* Soft sleep mode */
+#define REG_PID		0x0a	/* Product ID MSB */
+#define REG_VER		0x0b	/* Product ID LSB */
+#define REG_COM3	0x0c	/* Control 3 */
+#define  COM3_SWAP	  0x40	  /* Byte swap */
+#define  COM3_SCALEEN	  0x08	  /* Enable scaling */
+#define  COM3_DCWEN	  0x04	  /* Enable downsamp/crop/window */
+#define REG_COM4	0x0d	/* Control 4 */
+#define REG_COM5	0x0e	/* All "reserved" */
+#define REG_COM6	0x0f	/* Control 6 */
+#define REG_AECH	0x10	/* More bits of AEC value */
+#define REG_CLKRC	0x11	/* Clock control */
+#define   CLK_PLL	  0x80	  /* Enable internal PLL */
+#define   CLK_EXT	  0x40	  /* Use external clock directly */
+#define   CLK_SCALE	  0x3f	  /* Mask for internal clock scale */
+#define REG_COM7	0x12	/* Control 7 */
+#define   COM7_RESET	  0x80	  /* Register reset */
+#define   COM7_FMT_MASK	  0x38
+#define   COM7_FMT_SXGA	  0x00
+#define   COM7_FMT_VGA	  0x40
+#define	  COM7_FMT_CIF	  0x20	  /* CIF format */
+#define   COM7_FMT_QVGA	  0x10	  /* QVGA format */
+#define   COM7_FMT_QCIF	  0x08	  /* QCIF format */
+#define	  COM7_RGB	  0x04	  /* bits 0 and 2 - RGB format */
+#define	  COM7_YUV	  0x00	  /* YUV */
+#define	  COM7_BAYER	  0x01	  /* Bayer format */
+#define	  COM7_PBAYER	  0x05	  /* "Processed bayer" */
+#define REG_COM8	0x13	/* Control 8 */
+#define   COM8_FASTAEC	  0x80	  /* Enable fast AGC/AEC */
+#define   COM8_AECSTEP	  0x40	  /* Unlimited AEC step size */
+#define   COM8_BFILT	  0x20	  /* Band filter enable */
+#define   COM8_AGC	  0x04	  /* Auto gain enable */
+#define   COM8_AWB	  0x02	  /* White balance enable */
+#define   COM8_AEC	  0x01	  /* Auto exposure enable */
+#define REG_COM9	0x14	/* Control 9  - gain ceiling */
+#define REG_COM10	0x15	/* Control 10 */
+#define   COM10_HSYNC	  0x40	  /* HSYNC instead of HREF */
+#define   COM10_PCLK_HB	  0x20	  /* Suppress PCLK on horiz blank */
+#define   COM10_HREF_REV  0x08	  /* Reverse HREF */
+#define   COM10_VS_LEAD	  0x04	  /* VSYNC on clock leading edge */
+#define   COM10_VS_NEG	  0x02	  /* VSYNC negative */
+#define   COM10_HS_NEG	  0x01	  /* HSYNC negative */
+#define REG_HSTART	0x17	/* Horiz start high bits */
+#define REG_HSTOP	0x18	/* Horiz stop high bits */
+#define REG_VSTART	0x19	/* Vert start high bits */
+#define REG_VSTOP	0x1a	/* Vert stop high bits */
+#define REG_PSHFT	0x1b	/* Pixel delay after HREF */
+#define REG_MIDH	0x1c	/* Manuf. ID high */
+#define REG_MIDL	0x1d	/* Manuf. ID low */
+#define REG_MVFP	0x1e	/* Mirror / vflip */
+#define   MVFP_MIRROR	  0x20	  /* Mirror image */
+#define   MVFP_FLIP	  0x10	  /* Vertical flip */
+
+#define REG_AEW		0x24	/* AGC upper limit */
+#define REG_AEB		0x25	/* AGC lower limit */
+#define REG_VPT		0x26	/* AGC/AEC fast mode op region */
+#define REG_ADVFL	0x2d	/* Insert dummy lines (LSB) */
+#define REG_ADVFH	0x2e	/* Insert dummy lines (MSB) */
+#define REG_HSYST	0x30	/* HSYNC rising edge delay */
+#define REG_HSYEN	0x31	/* HSYNC falling edge delay */
+#define REG_HREF	0x32	/* HREF pieces */
+#define REG_TSLB	0x3a	/* lots of stuff */
+#define   TSLB_YLAST	  0x04	  /* UYVY or VYUY - see com13 */
+#define   TSLB_BYTEORD	  0x08	  /* swap bytes in 16bit mode? */
+#define REG_COM11	0x3b	/* Control 11 */
+#define   COM11_NIGHT	  0x80	  /* NIght mode enable */
+#define   COM11_NMFR	  0x60	  /* Two bit NM frame rate */
+#define   COM11_HZAUTO	  0x10	  /* Auto detect 50/60 Hz */
+#define	  COM11_50HZ	  0x08	  /* Manual 50Hz select */
+#define   COM11_EXP	  0x02
+#define REG_COM12	0x3c	/* Control 12 */
+#define   COM12_HREF	  0x80	  /* HREF always */
+#define REG_COM13	0x3d	/* Control 13 */
+#define   COM13_GAMMA	  0x80	  /* Gamma enable */
+#define	  COM13_UVSAT	  0x40	  /* UV saturation auto adjustment */
+#define	  COM13_CMATRIX	  0x10	  /* Enable color matrix for RGB or YUV */
+#define   COM13_UVSWAP	  0x01	  /* V before U - w/TSLB */
+#define REG_COM14	0x3e	/* Control 14 */
+#define   COM14_DCWEN	  0x10	  /* DCW/PCLK-scale enable */
+#define REG_EDGE	0x3f	/* Edge enhancement factor */
+#define REG_COM15	0x40	/* Control 15 */
+#define   COM15_R10F0	  0x00	  /* Data range 10 to F0 */
+#define	  COM15_R01FE	  0x80	  /*            01 to FE */
+#define   COM15_R00FF	  0xc0	  /*            00 to FF */
+#define   COM15_RGB565	  0x10	  /* RGB565 output */
+#define   COM15_RGBFIXME	  0x20	  /* FIXME  */
+#define   COM15_RGB555	  0x30	  /* RGB555 output */
+#define REG_COM16	0x41	/* Control 16 */
+#define   COM16_AWBGAIN   0x08	  /* AWB gain enable */
+#define REG_COM17	0x42	/* Control 17 */
+#define   COM17_AECWIN	  0xc0	  /* AEC window - must match COM4 */
+#define   COM17_CBAR	  0x08	  /* DSP Color bar */
+
+/*
+ * This matrix defines how the colors are generated, must be
+ * tweaked to adjust hue and saturation.
+ *
+ * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
+ *
+ * They are nine-bit signed quantities, with the sign bit
+ * stored in 0x58.  Sign for v-red is bit 0, and up from there.
+ */
+#define	REG_CMATRIX_BASE 0x4f
+#define   CMATRIX_LEN 6
+#define REG_CMATRIX_SIGN 0x58
+
+
+#define REG_BRIGHT	0x55	/* Brightness */
+#define REG_CONTRAS	0x56	/* Contrast control */
+
+#define REG_GFIX	0x69	/* Fix gain control */
+
+#define REG_RGB444	0x8c	/* RGB 444 control */
+#define   R444_ENABLE	  0x02	  /* Turn on RGB444, overrides 5x5 */
+#define   R444_RGBX	  0x01	  /* Empty nibble at end */
+
+#define REG_HAECC1	0x9f	/* Hist AEC/AGC control 1 */
+#define REG_HAECC2	0xa0	/* Hist AEC/AGC control 2 */
+
+#define REG_BD50MAX	0xa5	/* 50hz banding step limit */
+#define REG_HAECC3	0xa6	/* Hist AEC/AGC control 3 */
+#define REG_HAECC4	0xa7	/* Hist AEC/AGC control 4 */
+#define REG_HAECC5	0xa8	/* Hist AEC/AGC control 5 */
+#define REG_HAECC6	0xa9	/* Hist AEC/AGC control 6 */
+#define REG_HAECC7	0xaa	/* Hist AEC/AGC control 7 */
+#define REG_BD60MAX	0xab	/* 60hz banding step limit */
+
+
+
+
+/* Returns 0 if OK */
+int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val)
+{
+	int i = 0;
+	int tmpval = 0;
+
+	if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg))
+		return 1;
+	if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val))
+		return 1;
+	if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX))
+		return 1;
+	do {
+		if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
+			return 1;
+		i++;
+	} while (tmpval == 0 && i < MAX_RETRIES);
+	if (tmpval != STK_IIC_STAT_TX_OK) {
+		if (tmpval)
+			STK_ERROR("stk_sensor_outb failed, status=0x%02x\n",
+				tmpval);
+		return 1;
+	} else
+		return 0;
+}
+
+int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val)
+{
+	int i = 0;
+	int tmpval = 0;
+
+	if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg))
+		return 1;
+	if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX))
+		return 1;
+	do {
+		if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
+			return 1;
+		i++;
+	} while (tmpval == 0 && i < MAX_RETRIES);
+	if (tmpval != STK_IIC_STAT_RX_OK) {
+		if (tmpval)
+			STK_ERROR("stk_sensor_inb failed, status=0x%02x\n",
+				tmpval);
+		return 1;
+	}
+
+	if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval))
+		return 1;
+
+	*val = (u8) tmpval;
+	return 0;
+}
+
+static int stk_sensor_write_regvals(struct stk_camera *dev,
+		struct regval *rv)
+{
+	int ret;
+	if (rv == NULL)
+		return 0;
+	while (rv->reg != 0xff || rv->val != 0xff) {
+		ret = stk_sensor_outb(dev, rv->reg, rv->val);
+		if (ret != 0)
+			return ret;
+		rv++;
+	}
+	return 0;
+}
+
+int stk_sensor_sleep(struct stk_camera *dev)
+{
+	u8 tmp;
+	return stk_sensor_inb(dev, REG_COM2, &tmp)
+		|| stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP);
+}
+
+int stk_sensor_wakeup(struct stk_camera *dev)
+{
+	u8 tmp;
+	return stk_sensor_inb(dev, REG_COM2, &tmp)
+		|| stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP);
+}
+
+static struct regval ov_initvals[] = {
+	{REG_CLKRC, CLK_PLL},
+	{REG_COM11, 0x01},
+	{0x6a, 0x7d},
+	{REG_AECH, 0x40},
+	{REG_GAIN, 0x00},
+	{REG_BLUE, 0x80},
+	{REG_RED, 0x80},
+	/* Do not enable fast AEC for now */
+	/*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/
+	{REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},
+	{0x39, 0x50}, {0x38, 0x93},
+	{0x37, 0x00}, {0x35, 0x81},
+	{REG_COM5, 0x20},
+	{REG_COM1, 0x00},
+	{REG_COM3, 0x00},
+	{REG_COM4, 0x00},
+	{REG_PSHFT, 0x00},
+	{0x16, 0x07},
+	{0x33, 0xe2}, {0x34, 0xbf},
+	{REG_COM16, 0x00},
+	{0x96, 0x04},
+	/* Gamma curve values */
+/*	{ 0x7a, 0x20 },		{ 0x7b, 0x10 },
+	{ 0x7c, 0x1e },		{ 0x7d, 0x35 },
+	{ 0x7e, 0x5a },		{ 0x7f, 0x69 },
+	{ 0x80, 0x76 },		{ 0x81, 0x80 },
+	{ 0x82, 0x88 },		{ 0x83, 0x8f },
+	{ 0x84, 0x96 },		{ 0x85, 0xa3 },
+	{ 0x86, 0xaf },		{ 0x87, 0xc4 },
+	{ 0x88, 0xd7 },		{ 0x89, 0xe8 },
+*/
+	{REG_GFIX, 0x40},
+	{0x8e, 0x00},
+	{REG_COM12, 0x73},
+	{0x8f, 0xdf}, {0x8b, 0x06},
+	{0x8c, 0x20},
+	{0x94, 0x88}, {0x95, 0x88},
+/*	{REG_COM15, 0xc1}, TODO */
+	{0x29, 0x3f},
+	{REG_COM6, 0x42},
+	{REG_BD50MAX, 0x80},
+	{REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92},
+	{REG_BD60MAX, 0x0a},
+	{0x90, 0x00}, {0x91, 0x00},
+	{REG_HAECC1, 0x00}, {REG_HAECC2, 0x00},
+	{REG_AEW, 0x68}, {REG_AEB, 0x5c},
+	{REG_VPT, 0xc3},
+	{REG_COM9, 0x2e},
+	{0x2a, 0x00}, {0x2b, 0x00},
+
+	{0xff, 0xff}, /* END MARKER */
+};
+
+/* Probe the I2C bus and initialise the sensor chip */
+int stk_sensor_init(struct stk_camera *dev)
+{
+	u8 idl = 0;
+	u8 idh = 0;
+
+	if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES)
+		|| stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS)
+		|| stk_sensor_outb(dev, REG_COM7, COM7_RESET)) {
+		STK_ERROR("Sensor resetting failed\n");
+		return -ENODEV;
+	}
+	msleep(10);
+	/* Read the manufacturer ID: ov = 0x7FA2 */
+	if (stk_sensor_inb(dev, REG_MIDH, &idh)
+	    || stk_sensor_inb(dev, REG_MIDL, &idl)) {
+		STK_ERROR("Strange error reading sensor ID\n");
+		return -ENODEV;
+	}
+	if (idh != 0x7F || idl != 0xA2) {
+		STK_ERROR("Huh? you don't have a sensor from ovt\n");
+		return -ENODEV;
+	}
+	if (stk_sensor_inb(dev, REG_PID, &idh)
+	    || stk_sensor_inb(dev, REG_VER, &idl)) {
+		STK_ERROR("Could not read sensor model\n");
+		return -ENODEV;
+	}
+	stk_sensor_write_regvals(dev, ov_initvals);
+	msleep(10);
+	STK_INFO("OmniVision sensor detected, id %02X%02X"
+		" at address %x\n", idh, idl, SENSOR_ADDRESS);
+	return 0;
+}
+
+/* V4L2_PIX_FMT_UYVY */
+static struct regval ov_fmt_uyvy[] = {
+	{REG_TSLB, TSLB_YLAST|0x08 },
+	{ 0x4f, 0x80 }, 	/* "matrix coefficient 1" */
+	{ 0x50, 0x80 }, 	/* "matrix coefficient 2" */
+	{ 0x51, 0    },		/* vb */
+	{ 0x52, 0x22 }, 	/* "matrix coefficient 4" */
+	{ 0x53, 0x5e }, 	/* "matrix coefficient 5" */
+	{ 0x54, 0x80 }, 	/* "matrix coefficient 6" */
+	{REG_COM13, COM13_UVSAT|COM13_CMATRIX},
+	{REG_COM15, COM15_R00FF },
+	{0xff, 0xff}, /* END MARKER */
+};
+
+/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */
+static struct regval ov_fmt_rgbr[] = {
+	{ REG_RGB444, 0 },	/* No RGB444 please */
+	{REG_TSLB, 0x00},
+	{ REG_COM1, 0x0 },
+	{ REG_COM9, 0x38 }, 	/* 16x gain ceiling; 0x8 is reserved bit */
+	{ 0x4f, 0xb3 }, 	/* "matrix coefficient 1" */
+	{ 0x50, 0xb3 }, 	/* "matrix coefficient 2" */
+	{ 0x51, 0    },		/* vb */
+	{ 0x52, 0x3d }, 	/* "matrix coefficient 4" */
+	{ 0x53, 0xa7 }, 	/* "matrix coefficient 5" */
+	{ 0x54, 0xe4 }, 	/* "matrix coefficient 6" */
+	{ REG_COM13, COM13_GAMMA },
+	{ REG_COM15, COM15_RGB565|COM15_R00FF },
+	{ 0xff, 0xff },
+};
+
+/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */
+static struct regval ov_fmt_rgbp[] = {
+	{ REG_RGB444, 0 },	/* No RGB444 please */
+	{REG_TSLB, TSLB_BYTEORD },
+	{ REG_COM1, 0x0 },
+	{ REG_COM9, 0x38 }, 	/* 16x gain ceiling; 0x8 is reserved bit */
+	{ 0x4f, 0xb3 }, 	/* "matrix coefficient 1" */
+	{ 0x50, 0xb3 }, 	/* "matrix coefficient 2" */
+	{ 0x51, 0    },		/* vb */
+	{ 0x52, 0x3d }, 	/* "matrix coefficient 4" */
+	{ 0x53, 0xa7 }, 	/* "matrix coefficient 5" */
+	{ 0x54, 0xe4 }, 	/* "matrix coefficient 6" */
+	{ REG_COM13, COM13_GAMMA },
+	{ REG_COM15, COM15_RGB565|COM15_R00FF },
+	{ 0xff, 0xff },
+};
+
+/* V4L2_PIX_FMT_SRGGB8 */
+static struct regval ov_fmt_bayer[] = {
+	/* This changes color order */
+	{REG_TSLB, 0x40}, /* BGGR */
+	/* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */
+	{REG_COM15, COM15_R00FF },
+	{0xff, 0xff}, /* END MARKER */
+};
+/*
+ * Store a set of start/stop values into the camera.
+ */
+static int stk_sensor_set_hw(struct stk_camera *dev,
+		int hstart, int hstop, int vstart, int vstop)
+{
+	int ret;
+	unsigned char v;
+/*
+ * Horizontal: 11 bits, top 8 live in hstart and hstop.  Bottom 3 of
+ * hstart are in href[2:0], bottom 3 of hstop in href[5:3].  There is
+ * a mystery "edge offset" value in the top two bits of href.
+ */
+	ret =  stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff);
+	ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff);
+	ret += stk_sensor_inb(dev, REG_HREF, &v);
+	v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
+	msleep(10);
+	ret += stk_sensor_outb(dev, REG_HREF, v);
+/*
+ * Vertical: similar arrangement (note: this is different from ov7670.c)
+ */
+	ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff);
+	ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff);
+	ret += stk_sensor_inb(dev, REG_VREF, &v);
+	v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7);
+	msleep(10);
+	ret += stk_sensor_outb(dev, REG_VREF, v);
+	return ret;
+}
+
+
+int stk_sensor_configure(struct stk_camera *dev)
+{
+	int com7;
+	/*
+	 * We setup the sensor to output dummy lines in low-res modes,
+	 * so we don't get absurdly hight framerates.
+	 */
+	unsigned dummylines;
+	int flip;
+	struct regval *rv;
+
+	switch (dev->vsettings.mode) {
+	case MODE_QCIF: com7 = COM7_FMT_QCIF;
+		dummylines = 604;
+		break;
+	case MODE_QVGA: com7 = COM7_FMT_QVGA;
+		dummylines = 267;
+		break;
+	case MODE_CIF: com7 = COM7_FMT_CIF;
+		dummylines = 412;
+		break;
+	case MODE_VGA: com7 = COM7_FMT_VGA;
+		dummylines = 11;
+		break;
+	case MODE_SXGA: com7 = COM7_FMT_SXGA;
+		dummylines = 0;
+		break;
+	default: STK_ERROR("Unsupported mode %d\n", dev->vsettings.mode);
+		return -EFAULT;
+	}
+	switch (dev->vsettings.palette) {
+	case V4L2_PIX_FMT_UYVY:
+		com7 |= COM7_YUV;
+		rv = ov_fmt_uyvy;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		com7 |= COM7_RGB;
+		rv = ov_fmt_rgbp;
+		break;
+	case V4L2_PIX_FMT_RGB565X:
+		com7 |= COM7_RGB;
+		rv = ov_fmt_rgbr;
+		break;
+	case V4L2_PIX_FMT_SBGGR8:
+		com7 |= COM7_PBAYER;
+		rv = ov_fmt_bayer;
+		break;
+	default: STK_ERROR("Unsupported colorspace\n");
+		return -EFAULT;
+	}
+	/*FIXME sometimes the sensor go to a bad state
+	stk_sensor_write_regvals(dev, ov_initvals); */
+	stk_sensor_outb(dev, REG_COM7, com7);
+	msleep(50);
+	stk_sensor_write_regvals(dev, rv);
+	flip = (dev->vsettings.vflip?MVFP_FLIP:0)
+		| (dev->vsettings.hflip?MVFP_MIRROR:0);
+	stk_sensor_outb(dev, REG_MVFP, flip);
+	if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8
+			&& !dev->vsettings.vflip)
+		stk_sensor_outb(dev, REG_TSLB, 0x08);
+	stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8);
+	stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff);
+	msleep(50);
+	switch (dev->vsettings.mode) {
+	case MODE_VGA:
+		if (stk_sensor_set_hw(dev, 302, 1582, 6, 486))
+			STK_ERROR("stk_sensor_set_hw failed (VGA)\n");
+		break;
+	case MODE_SXGA:
+	case MODE_CIF:
+	case MODE_QVGA:
+	case MODE_QCIF:
+		/*FIXME These settings seem ignored by the sensor
+		if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034))
+			STK_ERROR("stk_sensor_set_hw failed (SXGA)\n");
+		*/
+		break;
+	}
+	msleep(10);
+	return 0;
+}
+
+int stk_sensor_set_brightness(struct stk_camera *dev, int br)
+{
+	if (br < 0 || br > 0xff)
+		return -EINVAL;
+	stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6));
+	stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6));
+	return 0;
+}
+
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
new file mode 100644
index 000000000000..d37e5e2594b4
--- /dev/null
+++ b/drivers/media/video/stk-webcam.c
@@ -0,0 +1,1465 @@
+/*
+ * stk-webcam.c : Driver for Syntek 1125 USB webcam controller
+ *
+ * Copyright (C) 2006 Nicolas VIVIEN
+ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
+ *
+ * Some parts are inspired from cafe_ccic.c
+ * Copyright 2006-2007 Jonathan Corbet
+ *
+ * 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
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+
+#include <linux/usb.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+#include "stk-webcam.h"
+
+
+static int hflip = 1;
+module_param(hflip, bool, 0444);
+MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1");
+
+static int vflip = 1;
+module_param(vflip, bool, 0444);
+MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1");
+
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN");
+MODULE_DESCRIPTION("Syntek DC1125 webcam driver");
+
+
+
+/* Some cameras have audio interfaces, we aren't interested in those */
+static struct usb_device_id stkwebcam_table[] = {
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, stkwebcam_table);
+
+void stk_camera_cleanup(struct kref *kref)
+{
+	struct stk_camera *dev = to_stk_camera(kref);
+
+	STK_INFO("Syntek USB2.0 Camera release resources"
+		" video device /dev/video%d\n", dev->vdev.minor);
+	video_unregister_device(&dev->vdev);
+	dev->vdev.priv = NULL;
+
+	if (dev->sio_bufs != NULL || dev->isobufs != NULL)
+		STK_ERROR("We are leaking memory\n");
+	usb_put_intf(dev->interface);
+	kfree(dev);
+}
+
+
+/*
+ * Basic stuff
+ */
+int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value)
+{
+	struct usb_device *udev = dev->udev;
+	int ret;
+
+	ret =  usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			0x01,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			value,
+			index,
+			NULL,
+			0,
+			500);
+	if (ret < 0)
+		return ret;
+	else
+		return 0;
+}
+
+int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value)
+{
+	struct usb_device *udev = dev->udev;
+	int ret;
+
+	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			0x00,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			0x00,
+			index,
+			(u8 *) value,
+			sizeof(u8),
+			500);
+	if (ret < 0)
+		return ret;
+	else
+		return 0;
+}
+
+static int stk_start_stream(struct stk_camera *dev)
+{
+	int value;
+	int i, ret;
+	int value_116, value_117;
+
+	if (!is_present(dev))
+		return -ENODEV;
+	if (!is_memallocd(dev) || !is_initialised(dev)) {
+		STK_ERROR("FIXME: Buffers are not allocated\n");
+		return -EFAULT;
+	}
+	ret = usb_set_interface(dev->udev, 0, 5);
+
+	if (ret < 0)
+		STK_ERROR("usb_set_interface failed !\n");
+	if (stk_sensor_wakeup(dev))
+		STK_ERROR("error awaking the sensor\n");
+
+	stk_camera_read_reg(dev, 0x0116, &value_116);
+	stk_camera_read_reg(dev, 0x0117, &value_117);
+
+	stk_camera_write_reg(dev, 0x0116, 0x0000);
+	stk_camera_write_reg(dev, 0x0117, 0x0000);
+
+	stk_camera_read_reg(dev, 0x0100, &value);
+	stk_camera_write_reg(dev, 0x0100, value | 0x80);
+
+	stk_camera_write_reg(dev, 0x0116, value_116);
+	stk_camera_write_reg(dev, 0x0117, value_117);
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		if (dev->isobufs[i].urb) {
+			ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL);
+			atomic_inc(&dev->urbs_used);
+			if (ret)
+				return ret;
+		}
+	}
+	set_streaming(dev);
+	return 0;
+}
+
+static int stk_stop_stream(struct stk_camera *dev)
+{
+	int value;
+	int i;
+	if (is_present(dev)) {
+		stk_camera_read_reg(dev, 0x0100, &value);
+		stk_camera_write_reg(dev, 0x0100, value & ~0x80);
+		if (dev->isobufs != NULL) {
+			for (i = 0; i < MAX_ISO_BUFS; i++) {
+				if (dev->isobufs[i].urb)
+					usb_kill_urb(dev->isobufs[i].urb);
+			}
+		}
+		unset_streaming(dev);
+
+		if (usb_set_interface(dev->udev, 0, 0))
+			STK_ERROR("usb_set_interface failed !\n");
+		if (stk_sensor_sleep(dev))
+			STK_ERROR("error suspending the sensor\n");
+	}
+	return 0;
+}
+
+/*
+ * This seems to be the shortest init sequence we
+ * must do in order to find the sensor
+ * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor
+ * is also reset. Maybe powers down it?
+ * Rest of values don't make a difference
+ */
+
+static struct regval stk1125_initvals[] = {
+	/*TODO: What means this sequence? */
+	{0x0000, 0x24},
+	{0x0100, 0x21},
+	{0x0002, 0x68},
+	{0x0003, 0x80},
+	{0x0005, 0x00},
+	{0x0007, 0x03},
+	{0x000d, 0x00},
+	{0x000f, 0x02},
+	{0x0300, 0x12},
+	{0x0350, 0x41},
+	{0x0351, 0x00},
+	{0x0352, 0x00},
+	{0x0353, 0x00},
+	{0x0018, 0x10},
+	{0x0019, 0x00},
+	{0x001b, 0x0e},
+	{0x001c, 0x46},
+	{0x0300, 0x80},
+	{0x001a, 0x04},
+	{0x0110, 0x00},
+	{0x0111, 0x00},
+	{0x0112, 0x00},
+	{0x0113, 0x00},
+
+	{0xffff, 0xff},
+};
+
+
+static int stk_initialise(struct stk_camera *dev)
+{
+	struct regval *rv;
+	int ret;
+	if (!is_present(dev))
+		return -ENODEV;
+	if (is_initialised(dev))
+		return 0;
+	rv = stk1125_initvals;
+	while (rv->reg != 0xffff) {
+		ret = stk_camera_write_reg(dev, rv->reg, rv->val);
+		if (ret)
+			return ret;
+		rv++;
+	}
+	if (stk_sensor_init(dev) == 0) {
+		set_initialised(dev);
+		return 0;
+	} else
+		return -1;
+}
+
+/* sysfs functions */
+/*FIXME cleanup this */
+
+static ssize_t show_brightness(struct device *class,
+			struct device_attribute *attr, char *buf)
+{
+	struct video_device *vdev = to_video_device(class);
+	struct stk_camera *dev = vdev_to_camera(vdev);
+
+	return sprintf(buf, "%X\n", dev->vsettings.brightness);
+}
+
+static ssize_t store_brightness(struct device *class,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	char *endp;
+	unsigned long value;
+	int ret;
+
+	struct video_device *vdev = to_video_device(class);
+	struct stk_camera *dev = vdev_to_camera(vdev);
+
+	value = simple_strtoul(buf, &endp, 16);
+
+	dev->vsettings.brightness = (int) value;
+
+	ret = stk_sensor_set_brightness(dev, value >> 8);
+	if (ret)
+		return ret;
+	else
+		return count;
+}
+
+static ssize_t show_hflip(struct device *class,
+		struct device_attribute *attr, char *buf)
+{
+	struct video_device *vdev = to_video_device(class);
+	struct stk_camera *dev = vdev_to_camera(vdev);
+
+	return sprintf(buf, "%d\n", dev->vsettings.hflip);
+}
+
+static ssize_t store_hflip(struct device *class,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct video_device *vdev = to_video_device(class);
+	struct stk_camera *dev = vdev_to_camera(vdev);
+
+	if (strncmp(buf, "1", 1) == 0)
+		dev->vsettings.hflip = 1;
+	else if (strncmp(buf, "0", 1) == 0)
+		dev->vsettings.hflip = 0;
+	else
+		return -EINVAL;
+
+	return strlen(buf);
+}
+
+static ssize_t show_vflip(struct device *class,
+		struct device_attribute *attr, char *buf)
+{
+	struct video_device *vdev = to_video_device(class);
+	struct stk_camera *dev = vdev_to_camera(vdev);
+
+	return sprintf(buf, "%d\n", dev->vsettings.vflip);
+}
+
+static ssize_t store_vflip(struct device *class,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct video_device *vdev = to_video_device(class);
+	struct stk_camera *dev = vdev_to_camera(vdev);
+
+	if (strncmp(buf, "1", 1) == 0)
+		dev->vsettings.vflip = 1;
+	else if (strncmp(buf, "0", 1) == 0)
+		dev->vsettings.vflip = 0;
+	else
+		return -EINVAL;
+
+	return strlen(buf);
+}
+
+static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO,
+			show_brightness, store_brightness);
+static DEVICE_ATTR(hflip, S_IRUGO | S_IWUGO, show_hflip, store_hflip);
+static DEVICE_ATTR(vflip, S_IRUGO | S_IWUGO, show_vflip, store_vflip);
+
+static int stk_create_sysfs_files(struct video_device *vdev)
+{
+	int ret;
+
+	ret = video_device_create_file(vdev, &dev_attr_brightness);
+	ret += video_device_create_file(vdev, &dev_attr_hflip);
+	ret += video_device_create_file(vdev, &dev_attr_vflip);
+	return ret;
+}
+
+static void stk_remove_sysfs_files(struct video_device *vdev)
+{
+	video_device_remove_file(vdev, &dev_attr_brightness);
+	video_device_remove_file(vdev, &dev_attr_hflip);
+	video_device_remove_file(vdev, &dev_attr_vflip);
+}
+
+
+/* *********************************************** */
+/*
+ * This function is called as an URB transfert is complete (Isochronous pipe).
+ * So, the traitement is done in interrupt time, so it has be fast, not crash,
+ * and not stall. Neat.
+ */
+static void stk_isoc_handler(struct urb *urb)
+{
+	int i;
+	int ret;
+	int framelen;
+	unsigned long flags;
+
+	unsigned char *fill = NULL;
+	unsigned char *iso_buf = NULL;
+
+	struct stk_camera *dev;
+	struct stk_sio_buffer *fb;
+
+	dev = (struct stk_camera *) urb->context;
+
+	if (dev == NULL) {
+		STK_ERROR("isoc_handler called with NULL device !\n");
+		return;
+	}
+
+	if (urb->status == -ENOENT || urb->status == -ECONNRESET
+		|| urb->status == -ESHUTDOWN) {
+		atomic_dec(&dev->urbs_used);
+		return;
+	}
+
+	spin_lock_irqsave(&dev->spinlock, flags);
+
+	if (urb->status != -EINPROGRESS && urb->status != 0) {
+		STK_ERROR("isoc_handler: urb->status == %d\n", urb->status);
+		goto resubmit;
+	}
+
+	if (list_empty(&dev->sio_avail)) {
+		/*FIXME Stop streaming after a while */
+		(void) (printk_ratelimit() &&
+		STK_ERROR("isoc_handler without available buffer!\n"));
+		goto resubmit;
+	}
+	fb = list_first_entry(&dev->sio_avail,
+			struct stk_sio_buffer, list);
+	fill = fb->buffer + fb->v4lbuf.bytesused;
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		if (urb->iso_frame_desc[i].status != 0) {
+			if (urb->iso_frame_desc[i].status != -EXDEV)
+				STK_ERROR("Frame %d has error %d\n", i,
+					urb->iso_frame_desc[i].status);
+			continue;
+		}
+		framelen = urb->iso_frame_desc[i].actual_length;
+		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		if (framelen <= 4)
+			continue; /* no data */
+
+		/*
+		 * we found something informational from there
+		 * the isoc frames have to type of headers
+		 * type1: 00 xx 00 00 or 20 xx 00 00
+		 * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00
+		 * xx is a sequencer which has never been seen over 0x3f
+		 * imho data written down looks like bayer, i see similarities
+		 * after every 640 bytes
+		 */
+		if (*iso_buf & 0x80) {
+			framelen -= 8;
+			iso_buf += 8;
+			/* This marks a new frame */
+			if (fb->v4lbuf.bytesused != 0
+				&& fb->v4lbuf.bytesused != dev->frame_size) {
+				(void) (printk_ratelimit() &&
+				STK_ERROR("frame %d, "
+					"bytesused=%d, skipping\n",
+					i, fb->v4lbuf.bytesused));
+				fb->v4lbuf.bytesused = 0;
+				fill = fb->buffer;
+			} else if (fb->v4lbuf.bytesused == dev->frame_size) {
+				list_move_tail(dev->sio_avail.next,
+					&dev->sio_full);
+				wake_up(&dev->wait_frame);
+				if (list_empty(&dev->sio_avail)) {
+					(void) (printk_ratelimit() &&
+					STK_ERROR("No buffer available\n"));
+					goto resubmit;
+				}
+				fb = list_first_entry(&dev->sio_avail,
+					struct stk_sio_buffer, list);
+				fb->v4lbuf.bytesused = 0;
+				fill = fb->buffer;
+			}
+		} else {
+			framelen -= 4;
+			iso_buf += 4;
+		}
+
+		/* Our buffer is full !!! */
+		if (framelen + fb->v4lbuf.bytesused > dev->frame_size) {
+			(void) (printk_ratelimit() &&
+			STK_ERROR("Frame buffer overflow, lost sync\n"));
+			/*FIXME Do something here? */
+			continue;
+		}
+		spin_unlock_irqrestore(&dev->spinlock, flags);
+		memcpy(fill, iso_buf, framelen);
+		spin_lock_irqsave(&dev->spinlock, flags);
+		fill += framelen;
+
+		/* New size of our buffer */
+		fb->v4lbuf.bytesused += framelen;
+	}
+
+resubmit:
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+	urb->dev = dev->udev;
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret != 0) {
+		STK_ERROR("Error (%d) re-submitting urb in stk_isoc_handler.\n",
+			ret);
+	}
+}
+
+/* -------------------------------------------- */
+
+static int stk_prepare_iso(struct stk_camera *dev)
+{
+	void *kbuf;
+	int i, j;
+	struct urb *urb;
+	struct usb_device *udev;
+
+	if (dev == NULL)
+		return -ENXIO;
+	udev = dev->udev;
+
+	if (dev->isobufs)
+		STK_ERROR("isobufs already allocated. Bad\n");
+	else
+		dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs),
+					GFP_KERNEL);
+	if (dev->isobufs == NULL) {
+		STK_ERROR("Unable to allocate iso buffers\n");
+		return -ENOMEM;
+	}
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		if (dev->isobufs[i].data == NULL) {
+			kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+			if (kbuf == NULL) {
+				STK_ERROR("Failed to allocate iso buffer %d\n",
+					i);
+				goto isobufs_out;
+			}
+			dev->isobufs[i].data = kbuf;
+		} else
+			STK_ERROR("isobuf data already allocated\n");
+		if (dev->isobufs[i].urb == NULL) {
+			urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
+			if (urb == NULL) {
+				STK_ERROR("Failed to allocate URB %d\n", i);
+				goto isobufs_out;
+			}
+			dev->isobufs[i].urb = urb;
+		} else {
+			STK_ERROR("Killing URB\n");
+			usb_kill_urb(dev->isobufs[i].urb);
+			urb = dev->isobufs[i].urb;
+		}
+		urb->interval = 1;
+		urb->dev = udev;
+		urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep);
+		urb->transfer_flags = URB_ISO_ASAP;
+		urb->transfer_buffer = dev->isobufs[i].data;
+		urb->transfer_buffer_length = ISO_BUFFER_SIZE;
+		urb->complete = stk_isoc_handler;
+		urb->context = dev;
+		urb->start_frame = 0;
+		urb->number_of_packets = ISO_FRAMES_PER_DESC;
+
+		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
+			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
+			urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
+		}
+	}
+	set_memallocd(dev);
+	return 0;
+
+isobufs_out:
+	for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++)
+		kfree(dev->isobufs[i].data);
+	for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++)
+		usb_free_urb(dev->isobufs[i].urb);
+	kfree(dev->isobufs);
+	dev->isobufs = NULL;
+	return -ENOMEM;
+}
+
+static void stk_clean_iso(struct stk_camera *dev)
+{
+	int i;
+
+	if (dev == NULL || dev->isobufs == NULL)
+		return;
+
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		struct urb *urb;
+
+		urb = dev->isobufs[i].urb;
+		if (urb) {
+			if (atomic_read(&dev->urbs_used))
+				usb_kill_urb(urb);
+			usb_free_urb(urb);
+		}
+		kfree(dev->isobufs[i].data);
+	}
+	kfree(dev->isobufs);
+	dev->isobufs = NULL;
+	unset_memallocd(dev);
+}
+
+static int stk_setup_siobuf(struct stk_camera *dev, int index)
+{
+	struct stk_sio_buffer *buf = dev->sio_bufs + index;
+	INIT_LIST_HEAD(&buf->list);
+	buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size);
+	buf->buffer = vmalloc_user(buf->v4lbuf.length);
+	if (buf->buffer == NULL)
+		return -ENOMEM;
+	buf->mapcount = 0;
+	buf->dev = dev;
+	buf->v4lbuf.index = index;
+	buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	buf->v4lbuf.field = V4L2_FIELD_NONE;
+	buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
+	buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
+	return 0;
+}
+
+static int stk_free_sio_buffers(struct stk_camera *dev)
+{
+	int i;
+	int nbufs;
+	unsigned long flags;
+	if (dev->n_sbufs == 0 || dev->sio_bufs == NULL)
+		return 0;
+	/*
+	* If any buffers are mapped, we cannot free them at all.
+	*/
+	for (i = 0; i < dev->n_sbufs; i++) {
+		if (dev->sio_bufs[i].mapcount > 0)
+			return -EBUSY;
+	}
+	/*
+	* OK, let's do it.
+	*/
+	spin_lock_irqsave(&dev->spinlock, flags);
+	INIT_LIST_HEAD(&dev->sio_avail);
+	INIT_LIST_HEAD(&dev->sio_full);
+	nbufs = dev->n_sbufs;
+	dev->n_sbufs = 0;
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+	for (i = 0; i < nbufs; i++) {
+		if (dev->sio_bufs[i].buffer != NULL)
+			vfree(dev->sio_bufs[i].buffer);
+	}
+	kfree(dev->sio_bufs);
+	dev->sio_bufs = NULL;
+	return 0;
+}
+
+static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs)
+{
+	int i;
+	if (dev->sio_bufs != NULL)
+		STK_ERROR("sio_bufs already allocated\n");
+	else {
+		dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer),
+				GFP_KERNEL);
+		if (dev->sio_bufs == NULL)
+			return -ENOMEM;
+		for (i = 0; i < n_sbufs; i++) {
+			if (stk_setup_siobuf(dev, i))
+				return (dev->n_sbufs > 1)? 0 : -ENOMEM;
+			dev->n_sbufs = i+1;
+		}
+	}
+	return 0;
+}
+
+static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs)
+{
+	int err;
+	err = stk_prepare_iso(dev);
+	if (err) {
+		stk_clean_iso(dev);
+		return err;
+	}
+	err = stk_prepare_sio_buffers(dev, n_sbufs);
+	if (err) {
+		stk_free_sio_buffers(dev);
+		return err;
+	}
+	return 0;
+}
+
+static void stk_free_buffers(struct stk_camera *dev)
+{
+	stk_clean_iso(dev);
+	stk_free_sio_buffers(dev);
+}
+/* -------------------------------------------- */
+
+/* v4l file operations */
+
+static int v4l_stk_open(struct inode *inode, struct file *fp)
+{
+	struct stk_camera *dev;
+	struct video_device *vdev;
+
+	vdev = video_devdata(fp);
+	dev = vdev_to_camera(vdev);
+
+	if (dev == NULL || !is_present(dev))
+		return -ENXIO;
+	fp->private_data = vdev;
+	kref_get(&dev->kref);
+
+	return 0;
+}
+
+static int v4l_stk_release(struct inode *inode, struct file *fp)
+{
+	struct stk_camera *dev;
+	struct video_device *vdev;
+
+	vdev = video_devdata(fp);
+	if (vdev == NULL) {
+		STK_ERROR("v4l_release called w/o video devdata\n");
+		return -EFAULT;
+	}
+	dev = vdev_to_camera(vdev);
+	if (dev == NULL) {
+		STK_ERROR("v4l_release called on removed device\n");
+		return -ENODEV;
+	}
+
+	if (dev->owner != fp) {
+		kref_put(&dev->kref, stk_camera_cleanup);
+		return 0;
+	}
+
+	stk_stop_stream(dev);
+
+	stk_free_buffers(dev);
+
+	dev->owner = NULL;
+
+	kref_put(&dev->kref, stk_camera_cleanup);
+
+	return 0;
+}
+
+static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	int i;
+	int ret;
+	unsigned long flags;
+	struct stk_camera *dev;
+	struct video_device *vdev;
+	struct stk_sio_buffer *sbuf;
+
+	vdev = video_devdata(fp);
+	if (vdev == NULL)
+		return -EFAULT;
+	dev = vdev_to_camera(vdev);
+
+	if (dev == NULL)
+		return -EIO;
+
+	if (!is_present(dev))
+		return -EIO;
+	if (dev->owner && dev->owner != fp)
+		return -EBUSY;
+	dev->owner = fp;
+	if (!is_streaming(dev)) {
+		if (stk_initialise(dev)
+			|| stk_allocate_buffers(dev, 3)
+			|| stk_start_stream(dev))
+			return -ENOMEM;
+		spin_lock_irqsave(&dev->spinlock, flags);
+		for (i = 0; i < dev->n_sbufs; i++) {
+			list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail);
+			dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED;
+		}
+		spin_unlock_irqrestore(&dev->spinlock, flags);
+	}
+	if (*f_pos == 0) {
+		if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
+			return -EWOULDBLOCK;
+		ret = wait_event_interruptible(dev->wait_frame,
+			!list_empty(&dev->sio_full) || !is_present(dev));
+		if (ret)
+			return ret;
+		if (!is_present(dev))
+			return -EIO;
+	}
+	if (count + *f_pos > dev->frame_size)
+		count = dev->frame_size - *f_pos;
+	spin_lock_irqsave(&dev->spinlock, flags);
+	if (list_empty(&dev->sio_full)) {
+		spin_unlock_irqrestore(&dev->spinlock, flags);
+		STK_ERROR("BUG: No siobufs ready\n");
+		return 0;
+	}
+	sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+
+	if (copy_to_user(buf, sbuf->buffer + *f_pos, count))
+		return -EFAULT;
+
+	*f_pos += count;
+
+	if (*f_pos >= dev->frame_size) {
+		*f_pos = 0;
+		spin_lock_irqsave(&dev->spinlock, flags);
+		list_move_tail(&sbuf->list, &dev->sio_avail);
+		spin_unlock_irqrestore(&dev->spinlock, flags);
+	}
+	return count;
+}
+
+static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
+{
+	struct stk_camera *dev;
+	struct video_device *vdev;
+
+	vdev = video_devdata(fp);
+
+	if (vdev == NULL)
+		return -EFAULT;
+
+	dev = vdev_to_camera(vdev);
+	if (dev == NULL)
+		return -ENODEV;
+
+	poll_wait(fp, &dev->wait_frame, wait);
+
+	if (!is_present(dev))
+		return POLLERR;
+
+	if (!list_empty(&dev->sio_full))
+		return (POLLIN | POLLRDNORM);
+
+	return 0;
+}
+
+
+static void stk_v4l_vm_open(struct vm_area_struct *vma)
+{
+	struct stk_sio_buffer *sbuf = vma->vm_private_data;
+	sbuf->mapcount++;
+}
+static void stk_v4l_vm_close(struct vm_area_struct *vma)
+{
+	struct stk_sio_buffer *sbuf = vma->vm_private_data;
+	sbuf->mapcount--;
+	if (sbuf->mapcount == 0)
+		sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
+}
+static struct vm_operations_struct stk_v4l_vm_ops = {
+	.open = stk_v4l_vm_open,
+	.close = stk_v4l_vm_close
+};
+
+static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma)
+{
+	unsigned int i;
+	int ret;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct stk_camera *dev;
+	struct video_device *vdev;
+	struct stk_sio_buffer *sbuf = NULL;
+
+	if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+
+	vdev = video_devdata(fp);
+	dev = vdev_to_camera(vdev);
+
+	for (i = 0; i < dev->n_sbufs; i++) {
+		if (dev->sio_bufs[i].v4lbuf.m.offset == offset) {
+			sbuf = dev->sio_bufs + i;
+			break;
+		}
+	}
+	if (sbuf == NULL)
+		return -EINVAL;
+	ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
+	if (ret)
+		return ret;
+	vma->vm_flags |= VM_DONTEXPAND;
+	vma->vm_private_data = sbuf;
+	vma->vm_ops = &stk_v4l_vm_ops;
+	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
+	stk_v4l_vm_open(vma);
+	return 0;
+}
+
+/* v4l ioctl handlers */
+
+static int stk_vidioc_querycap(struct file *filp,
+		void *priv, struct v4l2_capability *cap)
+{
+	strcpy(cap->driver, "stk");
+	strcpy(cap->card, "stk");
+	cap->version = DRIVER_VERSION_NUM;
+
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+		| V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+	return 0;
+}
+
+static int stk_vidioc_enum_input(struct file *filp,
+		void *priv, struct v4l2_input *input)
+{
+	if (input->index != 0)
+		return -EINVAL;
+
+	strcpy(input->name, "Syntek USB Camera");
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+	return 0;
+}
+
+
+static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+	*i = 0;
+	return 0;
+}
+
+static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
+{
+	if (i != 0)
+		return -EINVAL;
+	else
+		return 0;
+}
+
+/* from vivi.c */
+static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
+{
+	return 0;
+}
+
+/* List of all V4Lv2 controls supported by the driver */
+static struct v4l2_queryctrl stk_controls[] = {
+	{
+		.id      = V4L2_CID_BRIGHTNESS,
+		.type    = V4L2_CTRL_TYPE_INTEGER,
+		.name    = "Brightness",
+		.minimum = 0,
+		.maximum = 0xffff,
+		.step    = 0x0100,
+		.default_value = 0x6000,
+	},
+	/*TODO: get more controls to work */
+};
+
+static int stk_vidioc_queryctrl(struct file *filp,
+		void *priv, struct v4l2_queryctrl *c)
+{
+	int i;
+	int nbr;
+	nbr = ARRAY_SIZE(stk_controls);
+
+	for (i = 0; i < nbr; i++) {
+		if (stk_controls[i].id == c->id) {
+			memcpy(c, &stk_controls[i],
+				sizeof(struct v4l2_queryctrl));
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int stk_vidioc_g_ctrl(struct file *filp,
+		void *priv, struct v4l2_control *c)
+{
+	struct stk_camera *dev = priv;
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		c->value = dev->vsettings.brightness;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int stk_vidioc_s_ctrl(struct file *filp,
+		void *priv, struct v4l2_control *c)
+{
+	struct stk_camera *dev = priv;
+	switch (c->id) {
+	case V4L2_CID_BRIGHTNESS:
+		dev->vsettings.brightness = c->value;
+		return stk_sensor_set_brightness(dev, c->value >> 8);
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+static int stk_vidioc_enum_fmt_cap(struct file *filp,
+		void *priv, struct v4l2_fmtdesc *fmtd)
+{
+	fmtd->flags = 0;
+
+	switch (fmtd->index) {
+	case 0:
+		fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
+		strcpy(fmtd->description, "r5g6b5");
+		break;
+	case 1:
+		fmtd->pixelformat = V4L2_PIX_FMT_RGB565X;
+		strcpy(fmtd->description, "r5g6b5BE");
+		break;
+	case 2:
+		fmtd->pixelformat = V4L2_PIX_FMT_UYVY;
+		strcpy(fmtd->description, "yuv4:2:2");
+		break;
+	case 3:
+		fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8;
+		strcpy(fmtd->description, "Raw bayer");
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct stk_size {
+	unsigned w;
+	unsigned h;
+	enum stk_mode m;
+} stk_sizes[] = {
+	{ .w = 1280, .h = 1024, .m = MODE_SXGA, },
+	{ .w = 640,  .h = 480,  .m = MODE_VGA,  },
+	{ .w = 352,  .h = 288,  .m = MODE_CIF,  },
+	{ .w = 320,  .h = 240,  .m = MODE_QVGA, },
+	{ .w = 176,  .h = 144,  .m = MODE_QCIF, },
+};
+
+static int stk_vidioc_g_fmt_cap(struct file *filp,
+		void *priv, struct v4l2_format *f)
+{
+	struct v4l2_pix_format *pix_format = &f->fmt.pix;
+	struct stk_camera *dev = priv;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(stk_sizes)
+			&& stk_sizes[i].m != dev->vsettings.mode;
+		i++);
+	if (i == ARRAY_SIZE(stk_sizes)) {
+		STK_ERROR("ERROR: mode invalid\n");
+		return -EINVAL;
+	}
+	pix_format->width = stk_sizes[i].w;
+	pix_format->height = stk_sizes[i].h;
+	pix_format->field = V4L2_FIELD_NONE;
+	pix_format->colorspace = V4L2_COLORSPACE_SRGB;
+	pix_format->priv = 0;
+	pix_format->pixelformat = dev->vsettings.palette;
+	if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
+		pix_format->bytesperline = pix_format->width;
+	else
+		pix_format->bytesperline = 2 * pix_format->width;
+	pix_format->sizeimage = pix_format->bytesperline
+				* pix_format->height;
+	return 0;
+}
+
+static int stk_vidioc_try_fmt_cap(struct file *filp,
+		void *priv, struct v4l2_format *fmtd)
+{
+	int i;
+	switch (fmtd->fmt.pix.pixelformat) {
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_RGB565X:
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_SBGGR8:
+		break;
+	default:
+		return -EINVAL;
+	}
+	for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) {
+		if (fmtd->fmt.pix.width > stk_sizes[i].w)
+			break;
+	}
+	if (i == ARRAY_SIZE(stk_sizes)
+		|| (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w)
+			< abs(fmtd->fmt.pix.width - stk_sizes[i].w))) {
+		fmtd->fmt.pix.height = stk_sizes[i-1].h;
+		fmtd->fmt.pix.width = stk_sizes[i-1].w;
+		fmtd->fmt.pix.priv = i - 1;
+	} else {
+		fmtd->fmt.pix.height = stk_sizes[i].h;
+		fmtd->fmt.pix.width = stk_sizes[i].w;
+		fmtd->fmt.pix.priv = i;
+	}
+
+	fmtd->fmt.pix.field = V4L2_FIELD_NONE;
+	fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+	if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8)
+		fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width;
+	else
+		fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width;
+	fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline
+		* fmtd->fmt.pix.height;
+	return 0;
+}
+
+static int stk_vidioc_s_fmt_cap(struct file *filp,
+		void *priv, struct v4l2_format *fmtd)
+{
+	int ret;
+	struct stk_camera *dev = priv;
+
+	if (dev == NULL)
+		return -ENODEV;
+	if (!is_present(dev))
+		return -ENODEV;
+	if (is_streaming(dev))
+		return -EBUSY;
+	if (dev->owner && dev->owner != filp)
+		return -EBUSY;
+	dev->owner = filp;
+	ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd);
+	if (ret)
+		return ret;
+
+	dev->vsettings.palette = fmtd->fmt.pix.pixelformat;
+	stk_free_buffers(dev);
+	dev->frame_size = fmtd->fmt.pix.sizeimage;
+	dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m;
+
+	stk_initialise(dev);
+	/* This registers controls some timings, not sure of what. */
+	stk_camera_write_reg(dev, 0x001b, 0x0e);
+	if (dev->vsettings.mode == MODE_SXGA)
+		stk_camera_write_reg(dev, 0x001c, 0x0e);
+	else
+		stk_camera_write_reg(dev, 0x001c, 0x46);
+	/*
+	 * Registers 0x0115 0x0114 are the size of each line (bytes),
+	 * regs 0x0117 0x0116 are the heigth of the image.
+	 */
+	stk_camera_write_reg(dev, 0x0115,
+		(fmtd->fmt.pix.bytesperline >> 8) & 0xff);
+	stk_camera_write_reg(dev, 0x0114,
+		fmtd->fmt.pix.bytesperline & 0xff);
+	stk_camera_write_reg(dev, 0x0117,
+		(fmtd->fmt.pix.height >> 8) & 0xff);
+	stk_camera_write_reg(dev, 0x0116,
+		fmtd->fmt.pix.height & 0xff);
+	return stk_sensor_configure(dev);
+}
+
+static int stk_vidioc_reqbufs(struct file *filp,
+		void *priv, struct v4l2_requestbuffers *rb)
+{
+	struct stk_camera *dev = priv;
+
+	if (dev == NULL)
+		return -ENODEV;
+	if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (rb->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+	if (is_streaming(dev)
+		|| (dev->owner && dev->owner != filp))
+		return -EBUSY;
+	dev->owner = filp;
+
+	/*FIXME If they ask for zero, we must stop streaming and free */
+	if (rb->count < 3)
+		rb->count = 3;
+	/* Arbitrary limit */
+	else if (rb->count > 5)
+		rb->count = 5;
+
+	stk_allocate_buffers(dev, rb->count);
+	rb->count = dev->n_sbufs;
+	return 0;
+}
+
+static int stk_vidioc_querybuf(struct file *filp,
+		void *priv, struct v4l2_buffer *buf)
+{
+	int index;
+	struct stk_camera *dev = priv;
+	struct stk_sio_buffer *sbuf;
+
+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	index = buf->index;
+
+	if (index < 0 || index >= dev->n_sbufs)
+		return -EINVAL;
+	sbuf = dev->sio_bufs + buf->index;
+	*buf = sbuf->v4lbuf;
+	return 0;
+}
+
+static int stk_vidioc_qbuf(struct file *filp,
+		void *priv, struct v4l2_buffer *buf)
+{
+	struct stk_camera *dev = priv;
+	struct stk_sio_buffer *sbuf;
+	unsigned long flags;
+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (buf->memory != V4L2_MEMORY_MMAP)
+		return -EINVAL;
+
+	if (buf->index < 0 || buf->index >= dev->n_sbufs)
+		return -EINVAL;
+	sbuf = dev->sio_bufs + buf->index;
+	if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED)
+		return 0;
+	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
+	sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
+	spin_lock_irqsave(&dev->spinlock, flags);
+	list_add_tail(&sbuf->list, &dev->sio_avail);
+	*buf = sbuf->v4lbuf;
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+	return 0;
+}
+
+static int stk_vidioc_dqbuf(struct file *filp,
+		void *priv, struct v4l2_buffer *buf)
+{
+	struct stk_camera *dev = priv;
+	struct stk_sio_buffer *sbuf;
+	unsigned long flags;
+	int ret;
+
+	if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE
+		|| !is_streaming(dev))
+		return -EINVAL;
+
+	if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
+		return -EWOULDBLOCK;
+	ret = wait_event_interruptible(dev->wait_frame,
+		!list_empty(&dev->sio_full) || !is_present(dev));
+	if (ret)
+		return ret;
+	if (!is_present(dev))
+		return -EIO;
+
+	spin_lock_irqsave(&dev->spinlock, flags);
+	sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
+	list_del_init(&sbuf->list);
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+	sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
+	sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
+	sbuf->v4lbuf.sequence = ++dev->sequence;
+	do_gettimeofday(&sbuf->v4lbuf.timestamp);
+
+	*buf = sbuf->v4lbuf;
+	return 0;
+}
+
+static int stk_vidioc_streamon(struct file *filp,
+		void *priv, enum v4l2_buf_type type)
+{
+	struct stk_camera *dev = priv;
+	if (is_streaming(dev))
+		return 0;
+	if (dev->sio_bufs == NULL)
+		return -EINVAL;
+	dev->sequence = 0;
+	return stk_start_stream(dev);
+}
+
+static int stk_vidioc_streamoff(struct file *filp,
+		void *priv, enum v4l2_buf_type type)
+{
+	struct stk_camera *dev = priv;
+	unsigned long flags;
+	int i;
+	stk_stop_stream(dev);
+	spin_lock_irqsave(&dev->spinlock, flags);
+	INIT_LIST_HEAD(&dev->sio_avail);
+	INIT_LIST_HEAD(&dev->sio_full);
+	for (i = 0; i < dev->n_sbufs; i++) {
+		INIT_LIST_HEAD(&dev->sio_bufs[i].list);
+		dev->sio_bufs[i].v4lbuf.flags = 0;
+	}
+	spin_unlock_irqrestore(&dev->spinlock, flags);
+	return 0;
+}
+
+
+static int stk_vidioc_g_parm(struct file *filp,
+		void *priv, struct v4l2_streamparm *sp)
+{
+	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	sp->parm.capture.capability = 0;
+	sp->parm.capture.capturemode = 0;
+	/*FIXME This is not correct */
+	sp->parm.capture.timeperframe.numerator = 1;
+	sp->parm.capture.timeperframe.denominator = 30;
+	sp->parm.capture.readbuffers = 2;
+	sp->parm.capture.extendedmode = 0;
+	return 0;
+}
+
+static struct file_operations v4l_stk_fops = {
+	.owner = THIS_MODULE,
+	.open = v4l_stk_open,
+	.release = v4l_stk_release,
+	.read = v4l_stk_read,
+	.poll = v4l_stk_poll,
+	.mmap = v4l_stk_mmap,
+	.ioctl = video_ioctl2,
+	.llseek = no_llseek
+};
+
+static void stk_v4l_dev_release(struct video_device *vd)
+{
+}
+
+static struct video_device stk_v4l_data = {
+	.name = "stkwebcam",
+	.type = VFL_TYPE_GRABBER,
+	.type2 = VID_TYPE_CAPTURE,
+	.minor = -1,
+	.tvnorms = V4L2_STD_UNKNOWN,
+	.current_norm = V4L2_STD_UNKNOWN,
+	.fops = &v4l_stk_fops,
+	.release = stk_v4l_dev_release,
+
+	.vidioc_querycap = stk_vidioc_querycap,
+	.vidioc_enum_fmt_cap = stk_vidioc_enum_fmt_cap,
+	.vidioc_try_fmt_cap = stk_vidioc_try_fmt_cap,
+	.vidioc_s_fmt_cap = stk_vidioc_s_fmt_cap,
+	.vidioc_g_fmt_cap = stk_vidioc_g_fmt_cap,
+	.vidioc_enum_input = stk_vidioc_enum_input,
+	.vidioc_s_input = stk_vidioc_s_input,
+	.vidioc_g_input = stk_vidioc_g_input,
+	.vidioc_s_std = stk_vidioc_s_std,
+	.vidioc_reqbufs = stk_vidioc_reqbufs,
+	.vidioc_querybuf = stk_vidioc_querybuf,
+	.vidioc_qbuf = stk_vidioc_qbuf,
+	.vidioc_dqbuf = stk_vidioc_dqbuf,
+	.vidioc_streamon = stk_vidioc_streamon,
+	.vidioc_streamoff = stk_vidioc_streamoff,
+	.vidioc_queryctrl = stk_vidioc_queryctrl,
+	.vidioc_g_ctrl = stk_vidioc_g_ctrl,
+	.vidioc_s_ctrl = stk_vidioc_s_ctrl,
+	.vidioc_g_parm = stk_vidioc_g_parm,
+};
+
+
+static int stk_register_video_device(struct stk_camera *dev)
+{
+	int err;
+
+	dev->vdev = stk_v4l_data;
+	dev->vdev.debug = debug;
+	dev->vdev.dev = &dev->interface->dev;
+	dev->vdev.priv = dev;
+	err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
+	if (err)
+		STK_ERROR("v4l registration failed\n");
+	else
+		STK_INFO("Syntek USB2.0 Camera is now controlling video device"
+			" /dev/video%d\n", dev->vdev.minor);
+	return err;
+}
+
+
+/* USB Stuff */
+
+static int stk_camera_probe(struct usb_interface *interface,
+		const struct usb_device_id *id)
+{
+	int i;
+	int err;
+
+	struct stk_camera *dev = NULL;
+	struct usb_device *udev = interface_to_usbdev(interface);
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+
+	dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL);
+	if (dev == NULL) {
+		STK_ERROR("Out of memory !\n");
+		return -ENOMEM;
+	}
+
+	kref_init(&dev->kref);
+	spin_lock_init(&dev->spinlock);
+	init_waitqueue_head(&dev->wait_frame);
+
+	dev->udev = udev;
+	dev->interface = interface;
+	usb_get_intf(interface);
+
+	dev->vsettings.vflip = vflip;
+	dev->vsettings.hflip = hflip;
+	dev->n_sbufs = 0;
+	set_present(dev);
+
+	/* Set up the endpoint information
+	 * use only the first isoc-in endpoint
+	 * for the current alternate setting */
+	iface_desc = interface->cur_altsetting;
+
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+
+		if (!dev->isoc_ep
+			&& ((endpoint->bEndpointAddress
+				& USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+			&& ((endpoint->bmAttributes
+				& USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) {
+			/* we found an isoc in endpoint */
+			dev->isoc_ep = (endpoint->bEndpointAddress & 0xF);
+			break;
+		}
+	}
+	if (!dev->isoc_ep) {
+		STK_ERROR("Could not find isoc-in endpoint");
+		kref_put(&dev->kref, stk_camera_cleanup);
+		return -ENODEV;
+	}
+	dev->vsettings.brightness = 0x7fff;
+	dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
+	dev->vsettings.mode = MODE_VGA;
+	dev->frame_size = 640*480*2;
+
+	INIT_LIST_HEAD(&dev->sio_avail);
+	INIT_LIST_HEAD(&dev->sio_full);
+
+	usb_set_intfdata(interface, dev);
+
+	err = stk_register_video_device(dev);
+	if (err) {
+		kref_put(&dev->kref, stk_camera_cleanup);
+		return err;
+	}
+
+	stk_create_sysfs_files(&dev->vdev);
+
+	return 0;
+}
+
+static void stk_camera_disconnect(struct usb_interface *interface)
+{
+	struct stk_camera *dev = usb_get_intfdata(interface);
+
+	usb_set_intfdata(interface, NULL);
+	unset_present(dev);
+
+	wake_up_interruptible(&dev->wait_frame);
+	stk_remove_sysfs_files(&dev->vdev);
+
+	kref_put(&dev->kref, stk_camera_cleanup);
+}
+
+static struct usb_driver stk_camera_driver = {
+	.name = "stkwebcam",
+	.probe = stk_camera_probe,
+	.disconnect = stk_camera_disconnect,
+	.id_table = stkwebcam_table,
+};
+
+
+static int __init stk_camera_init(void)
+{
+	int result;
+
+	result = usb_register(&stk_camera_driver);
+	if (result)
+		STK_ERROR("usb_register failed ! Error number %d\n", result);
+
+
+	return result;
+}
+
+static void __exit stk_camera_exit(void)
+{
+	usb_deregister(&stk_camera_driver);
+}
+
+module_init(stk_camera_init);
+module_exit(stk_camera_exit);
+
+
diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/video/stk-webcam.h
new file mode 100644
index 000000000000..7e989d1ac1e0
--- /dev/null
+++ b/drivers/media/video/stk-webcam.h
@@ -0,0 +1,138 @@
+/*
+ * stk-webcam.h : Driver for Syntek 1125 USB webcam controller
+ *
+ * Copyright (C) 2006 Nicolas VIVIEN
+ * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
+ *
+ * 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
+ * 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 STKWEBCAM_H
+#define STKWEBCAM_H
+
+#include <linux/usb.h>
+#include <media/v4l2-common.h>
+
+#define DRIVER_VERSION		"v0.0.1"
+#define DRIVER_VERSION_NUM	0x000001
+
+#define MAX_ISO_BUFS		3
+#define ISO_FRAMES_PER_DESC	16
+#define ISO_MAX_FRAME_SIZE	3 * 1024
+#define ISO_BUFFER_SIZE		(ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
+
+
+#define PREFIX				"stkwebcam: "
+#define STK_INFO(str, args...)		printk(KERN_INFO PREFIX str, ##args)
+#define STK_ERROR(str, args...)		printk(KERN_ERR PREFIX str, ##args)
+#define STK_WARNING(str, args...)	printk(KERN_WARNING PREFIX str, ##args)
+
+struct stk_iso_buf {
+	void *data;
+	int length;
+	int read;
+	struct urb *urb;
+};
+
+/* Streaming IO buffers */
+struct stk_sio_buffer {
+	struct v4l2_buffer v4lbuf;
+	char *buffer;
+	int mapcount;
+	struct stk_camera *dev;
+	struct list_head list;
+};
+
+enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF};
+
+struct stk_video {
+	enum stk_mode mode;
+	int brightness;
+	__u32 palette;
+	int hflip;
+	int vflip;
+};
+
+enum stk_status {
+	S_PRESENT = 1,
+	S_INITIALISED = 2,
+	S_MEMALLOCD = 4,
+	S_STREAMING = 8,
+};
+#define is_present(dev)		((dev)->status & S_PRESENT)
+#define is_initialised(dev)	((dev)->status & S_INITIALISED)
+#define is_streaming(dev)	((dev)->status & S_STREAMING)
+#define is_memallocd(dev)	((dev)->status & S_MEMALLOCD)
+#define set_present(dev)	((dev)->status = S_PRESENT)
+#define unset_present(dev)	((dev)->status &= \
+					~(S_PRESENT|S_INITIALISED|S_STREAMING))
+#define set_initialised(dev)	((dev)->status |= S_INITIALISED)
+#define set_memallocd(dev)	((dev)->status |= S_MEMALLOCD)
+#define unset_memallocd(dev)	((dev)->status &= ~S_MEMALLOCD)
+#define set_streaming(dev)	((dev)->status |= S_STREAMING)
+#define unset_streaming(dev)	((dev)->status &= ~S_STREAMING)
+
+struct regval {
+	unsigned reg;
+	unsigned val;
+};
+
+struct stk_camera {
+	struct video_device vdev;
+	struct usb_device *udev;
+	struct usb_interface *interface;
+	int webcam_model;
+	struct file *owner;
+
+	u8 isoc_ep;
+
+	struct kref kref;
+	/* Not sure if this is right */
+	atomic_t urbs_used;
+
+	struct stk_video vsettings;
+
+	enum stk_status status;
+
+	spinlock_t spinlock;
+	wait_queue_head_t wait_frame;
+
+	struct stk_iso_buf *isobufs;
+
+	int frame_size;
+	/* Streaming buffers */
+	unsigned int n_sbufs;
+	struct stk_sio_buffer *sio_bufs;
+	struct list_head sio_avail;
+	struct list_head sio_full;
+	unsigned sequence;
+};
+
+#define to_stk_camera(d) container_of(d, struct stk_camera, kref)
+#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev)
+
+void stk_camera_delete(struct kref *);
+int stk_camera_write_reg(struct stk_camera *, u16, u8);
+int stk_camera_read_reg(struct stk_camera *, u16, int *);
+
+int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val);
+int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val);
+int stk_sensor_init(struct stk_camera *);
+int stk_sensor_configure(struct stk_camera *);
+int stk_sensor_sleep(struct stk_camera *dev);
+int stk_sensor_wakeup(struct stk_camera *dev);
+int stk_sensor_set_brightness(struct stk_camera *dev, int br);
+
+#endif
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 43225802a551..b4d10f7a4e57 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -8,6 +8,7 @@
  * Muting and tone control by Jonathan Isom <jisom@ematic.com>
  *
  * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com>
+ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
  * This code is placed under the terms of the GNU General Public License
  * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
  * Which was based on tda8425.c by Greg Alexander (c) 1998
@@ -276,7 +277,7 @@ static void do_tda7432_init(struct i2c_client *client)
 	t->volume =  0x3b ;				 /* -27dB Volume            */
 	if (loudness)			 /* Turn loudness on?     */
 		t->volume |= TDA7432_LD_ON;
-	t->muted    = VIDEO_AUDIO_MUTE;
+	t->muted    = 1;
 	t->treble   = TDA7432_TREBLE_0DB; /* 0dB Treble            */
 	t->bass		= TDA7432_BASS_0DB; 	 /* 0dB Bass              */
 	t->lf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
@@ -332,151 +333,160 @@ static int tda7432_detach(struct i2c_client *client)
 	return 0;
 }
 
-static int tda7432_command(struct i2c_client *client,
-			   unsigned int cmd, void *arg)
+static int tda7432_get_ctrl(struct i2c_client *client,
+			    struct v4l2_control *ctrl)
 {
 	struct tda7432 *t = i2c_get_clientdata(client);
-	v4l_dbg(2, debug,client,"In tda7432_command\n");
-	if (debug>1)
-		v4l_i2c_print_ioctl(client,cmd);
 
-	switch (cmd) {
-	/* --- v4l ioctls --- */
-	/* take care: bttv does userspace copying, we'll get a
-	   kernel pointer here... */
-
-	/* Query card - scale from TDA7432 settings to V4L settings */
-	case VIDIOCGAUDIO:
-	{
-		struct video_audio *va = arg;
-
-		va->flags |= VIDEO_AUDIO_VOLUME |
-			VIDEO_AUDIO_BASS |
-			VIDEO_AUDIO_TREBLE |
-			VIDEO_AUDIO_MUTABLE;
-		if (t->muted)
-			va->flags |= VIDEO_AUDIO_MUTE;
-		va->mode |= VIDEO_SOUND_STEREO;
-		/* Master volume control
-		 * V4L volume is min 0, max 65535
-		 * TDA7432 Volume:
-		 * Min (-79dB) is 0x6f
-		 * Max (+20dB) is 0x07 (630)
-		 * Max (0dB) is 0x20 (829)
-		 * (Mask out bit 7 of vol - it's for the loudness setting)
-		 */
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value=t->muted;
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
 		if (!maxvol){  /* max +20db */
-			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630;
+			ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630;
 		} else {       /* max 0db   */
-			va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829;
+			ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829;
 		}
-
-		/* Balance depends on L,R attenuation
-		 * V4L balance is 0 to 65535, middle is 32768
-		 * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f
-		 * to scale up to V4L numbers, mult by 1057
-		 * attenuation exists for lf, lr, rf, rr
-		 * we use only lf and rf (front channels)
-		 */
-
+		return 0;
+	case V4L2_CID_AUDIO_BALANCE:
+	{
 		if ( (t->lf) < (t->rf) )
 			/* right is attenuated, balance shifted left */
-			va->balance = (32768 - 1057*(t->rf));
+			ctrl->value = (32768 - 1057*(t->rf));
 		else
 			/* left is attenuated, balance shifted right */
-			va->balance = (32768 + 1057*(t->lf));
-
+			ctrl->value = (32768 + 1057*(t->lf));
+		return 0;
+	}
+	case V4L2_CID_AUDIO_BASS:
+	{
 		/* Bass/treble 4 bits each */
-		va->bass=t->bass;
-		if(va->bass >= 0x8)
-			va->bass = ~(va->bass - 0x8) & 0xf;
-		va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass);
-		va->treble=t->treble;
-		if(va->treble >= 0x8)
-			va->treble = ~(va->treble - 0x8) & 0xf;
-		va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble);
-
-		break; /* VIDIOCGAUDIO case */
+		int bass=t->bass;
+		if(bass >= 0x8)
+			bass = ~(bass - 0x8) & 0xf;
+		ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass);
+		return 0;
 	}
-
-	/* Set card - scale from V4L settings to TDA7432 settings */
-	case VIDIOCSAUDIO:
+	case V4L2_CID_AUDIO_TREBLE:
 	{
-		struct video_audio *va = arg;
+		int treble=t->treble;
+		if(treble >= 0x8)
+			treble = ~(treble - 0x8) & 0xf;
+		ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble);
+		return 0;
+	}
+	}
+	return -EINVAL;
+}
 
-		if(va->flags & VIDEO_AUDIO_VOLUME){
-			if(!maxvol){ /* max +20db */
-				t->volume = 0x6f - ((va->volume)/630);
-			} else {    /* max 0db   */
-				t->volume = 0x6f - ((va->volume)/829);
-			}
+static int tda7432_set_ctrl(struct i2c_client *client,
+			    struct v4l2_control *ctrl)
+{
+	struct tda7432 *t = i2c_get_clientdata(client);
 
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		t->muted=ctrl->value;
+		break;
+	case V4L2_CID_AUDIO_VOLUME:
+		if(!maxvol){ /* max +20db */
+			t->volume = 0x6f - ((ctrl->value)/630);
+		} else {    /* max 0db   */
+			t->volume = 0x6f - ((ctrl->value)/829);
+		}
 		if (loudness)		/* Turn on the loudness bit */
 			t->volume |= TDA7432_LD_ON;
 
-			tda7432_write(client,TDA7432_VL, t->volume);
-		}
-
-		if(va->flags & VIDEO_AUDIO_BASS)
-		{
-			t->bass = va->bass >> 12;
-			if(t->bass>= 0x8)
-					t->bass = (~t->bass & 0xf) + 0x8 ;
-		}
-		if(va->flags & VIDEO_AUDIO_TREBLE)
-		{
-			t->treble= va->treble >> 12;
-			if(t->treble>= 0x8)
-					t->treble = (~t->treble & 0xf) + 0x8 ;
-		}
-		if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS))
-			tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
-
-		if(va->flags & VIDEO_AUDIO_BALANCE)	{
-		if (va->balance < 32768)
-		{
+		tda7432_write(client,TDA7432_VL, t->volume);
+		return 0;
+	case V4L2_CID_AUDIO_BALANCE:
+		if (ctrl->value < 32768) {
 			/* shifted to left, attenuate right */
-			t->rr = (32768 - va->balance)/1057;
+			t->rr = (32768 - ctrl->value)/1057;
 			t->rf = t->rr;
 			t->lr = TDA7432_ATTEN_0DB;
 			t->lf = TDA7432_ATTEN_0DB;
-		}
-		else if(va->balance > 32769)
-		{
+		} else if(ctrl->value > 32769) {
 			/* shifted to right, attenuate left */
-			t->lf = (va->balance - 32768)/1057;
+			t->lf = (ctrl->value - 32768)/1057;
 			t->lr = t->lf;
 			t->rr = TDA7432_ATTEN_0DB;
 			t->rf = TDA7432_ATTEN_0DB;
-		}
-		else
-		{
+		} else {
 			/* centered */
 			t->rr = TDA7432_ATTEN_0DB;
 			t->rf = TDA7432_ATTEN_0DB;
 			t->lf = TDA7432_ATTEN_0DB;
 			t->lr = TDA7432_ATTEN_0DB;
 		}
-		}
+		break;
+	case V4L2_CID_AUDIO_BASS:
+		t->bass = ctrl->value >> 12;
+		if(t->bass>= 0x8)
+				t->bass = (~t->bass & 0xf) + 0x8 ;
+
+		tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
+		return 0;
+	case V4L2_CID_AUDIO_TREBLE:
+		t->treble= ctrl->value >> 12;
+		if(t->treble>= 0x8)
+				t->treble = (~t->treble & 0xf) + 0x8 ;
+
+		tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble );
+		return 0;
+	default:
+		return -EINVAL;
+	}
 
-		t->muted=(va->flags & VIDEO_AUDIO_MUTE);
-		if (t->muted)
-		{
-			/* Mute & update balance*/
-			tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
-			tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
-			tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
-			tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
-		} else {
-			tda7432_write(client,TDA7432_LF, t->lf);
-			tda7432_write(client,TDA7432_LR, t->lr);
-			tda7432_write(client,TDA7432_RF, t->rf);
-			tda7432_write(client,TDA7432_RR, t->rr);
-		}
+	/* Used for both mute and balance changes */
+	if (t->muted)
+	{
+		/* Mute & update balance*/
+		tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
+		tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
+		tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
+		tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
+	} else {
+		tda7432_write(client,TDA7432_LF, t->lf);
+		tda7432_write(client,TDA7432_LR, t->lr);
+		tda7432_write(client,TDA7432_RF, t->rf);
+		tda7432_write(client,TDA7432_RR, t->rr);
+	}
+	return 0;
+}
 
-		break;
+static int tda7432_command(struct i2c_client *client,
+			   unsigned int cmd, void *arg)
+{
+	v4l_dbg(2, debug,client,"In tda7432_command\n");
+	if (debug>1)
+		v4l_i2c_print_ioctl(client,cmd);
+
+	switch (cmd) {
+	/* --- v4l ioctls --- */
+	/* take care: bttv does userspace copying, we'll get a
+	   kernel pointer here... */
+	case VIDIOC_QUERYCTRL:
+	{
+		struct v4l2_queryctrl *qc = arg;
+
+		switch (qc->id) {
+			case V4L2_CID_AUDIO_MUTE:
+			case V4L2_CID_AUDIO_VOLUME:
+			case V4L2_CID_AUDIO_BALANCE:
+			case V4L2_CID_AUDIO_BASS:
+			case V4L2_CID_AUDIO_TREBLE:
+			default:
+				return -EINVAL;
+		}
+		return v4l2_ctrl_query_fill_std(qc);
+	}
+	case VIDIOC_S_CTRL:
+		return tda7432_set_ctrl(client, arg);
 
-	} /* end of VIDEOCSAUDIO case */
+	case VIDIOC_G_CTRL:
+		return tda7432_get_ctrl(client, arg);
 
 	} /* end of (cmd) switch */
 
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 0e5cf459d3ed..55bc89a6f069 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -25,12 +25,14 @@
 #include <linux/videodev.h>
 #include "tuner-i2c.h"
 #include "tda8290.h"
+#include "tda827x.h"
+#include "tda18271.h"
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tda8290 "
+#define PREFIX "tda8290"
 
 /* ---------------------------------------------------------------------- */
 
@@ -38,345 +40,71 @@ struct tda8290_priv {
 	struct tuner_i2c_props i2c_props;
 
 	unsigned char tda8290_easy_mode;
-	unsigned char tda827x_lpsel;
-	unsigned char tda827x_addr;
-	unsigned char tda827x_ver;
-	unsigned int sgIF;
-
-	u32 frequency;
-
-	unsigned int *lna_cfg;
-	int (*tuner_callback) (void *dev, int command,int arg);
-};
-
-/* ---------------------------------------------------------------------- */
-
-struct tda827x_data {
-	u32 lomax;
-	u8  spd;
-	u8  bs;
-	u8  bp;
-	u8  cp;
-	u8  gc3;
-	u8 div1p5;
-};
-
-     /* Note lomax entry is lo / 62500 */
-
-static struct tda827x_data tda827x_analog[] = {
-	{ .lomax =   992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  62 MHz */
-	{ .lomax =  1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /*  66 MHz */
-	{ .lomax =  1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  76 MHz */
-	{ .lomax =  1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /*  84 MHz */
-	{ .lomax =  1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  93 MHz */
-	{ .lomax =  1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /*  98 MHz */
-	{ .lomax =  1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */
-	{ .lomax =  1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */
-	{ .lomax =  2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */
-	{ .lomax =  2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */
-	{ .lomax =  2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */
-	{ .lomax =  2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */
-	{ .lomax =  2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */
-	{ .lomax =  3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */
-	{ .lomax =  3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */
-	{ .lomax =  4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */
-	{ .lomax =  4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */
-	{ .lomax =  5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */
-	{ .lomax =  5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */
-	{ .lomax =  7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */
-	{ .lomax =  7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */
-	{ .lomax =  8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */
-	{ .lomax =  8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */
-	{ .lomax =  9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */
-	{ .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */
-	{ .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */
-	{ .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */
-	{ .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */
-	{ .lomax =     0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}  /* End      */
-};
-
-static void tda827x_set_analog_params(struct dvb_frontend *fe,
-				      struct analog_parameters *params)
-{
-	unsigned char tuner_reg[8];
-	unsigned char reg2[2];
-	u32 N;
-	int i;
-	struct tda8290_priv *priv = fe->tuner_priv;
-	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
-	unsigned int freq = params->frequency;
-
-	if (params->mode == V4L2_TUNER_RADIO)
-		freq = freq / 1000;
-
-	N = freq + priv->sgIF;
-	i = 0;
-	while (tda827x_analog[i].lomax < N) {
-		if(tda827x_analog[i + 1].lomax == 0)
-			break;
-		i++;
-	}
-
-	N = N << tda827x_analog[i].spd;
-
-	tuner_reg[0] = 0;
-	tuner_reg[1] = (unsigned char)(N>>8);
-	tuner_reg[2] = (unsigned char) N;
-	tuner_reg[3] = 0x40;
-	tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5);
-	tuner_reg[5] = (tda827x_analog[i].spd   << 6) + (tda827x_analog[i].div1p5 <<5) +
-		       (tda827x_analog[i].bs     <<3) +  tda827x_analog[i].bp;
-	tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
-	tuner_reg[7] = 0x8f;
-
-	msg.buf = tuner_reg;
-	msg.len = 8;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	msg.buf= reg2;
-	msg.len = 2;
-	reg2[0] = 0x80;
-	reg2[1] = 0;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	reg2[0] = 0x60;
-	reg2[1] = 0xbf;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	reg2[0] = 0x30;
-	reg2[1] = tuner_reg[4] + 0x80;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	msleep(1);
-	reg2[0] = 0x30;
-	reg2[1] = tuner_reg[4] + 4;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	msleep(1);
-	reg2[0] = 0x30;
-	reg2[1] = tuner_reg[4];
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	msleep(550);
-	reg2[0] = 0x30;
-	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	reg2[0] = 0x60;
-	reg2[1] = 0x3f;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	reg2[0] = 0x80;
-	reg2[1] = 0x08;   // Vsync en
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-}
 
-static void tda827x_agcf(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->tuner_priv;
-	unsigned char data[] = {0x80, 0x0c};
-	struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
-			      .flags = 0, .len = 2};
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-}
-
-/* ---------------------------------------------------------------------- */
+	unsigned char tda827x_addr;
 
-struct tda827xa_data {
-	u32 lomax;
-	u8  svco;
-	u8  spd;
-	u8  scr;
-	u8  sbs;
-	u8  gc3;
-};
+	unsigned char ver;
+#define TDA8290   1
+#define TDA8295   2
+#define TDA8275   4
+#define TDA8275A  8
+#define TDA18271 16
 
-static struct tda827xa_data tda827xa_analog[] = {
-	{ .lomax =   910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},  /*  56.875 MHz */
-	{ .lomax =  1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  67.25 MHz */
-	{ .lomax =  1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  81.25 MHz */
-	{ .lomax =  1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},  /*  97.5  MHz */
-	{ .lomax =  1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},  /* 113.75 MHz */
-	{ .lomax =  2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 134.5 MHz */
-	{ .lomax =  2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 154   MHz */
-	{ .lomax =  2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 162.5 MHz */
-	{ .lomax =  2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},  /* 183   MHz */
-	{ .lomax =  3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},  /* 195   MHz */
-	{ .lomax =  3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},  /* 227.5 MHz */
-	{ .lomax =  4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},  /* 269   MHz */
-	{ .lomax =  5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},  /* 325   MHz */
-	{ .lomax =  6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 390   MHz */
-	{ .lomax =  7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},  /* 455   MHz */
-	{ .lomax =  8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 520   MHz */
-	{ .lomax =  8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},  /* 538   MHz */
-	{ .lomax =  8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},  /* 554   MHz */
-	{ .lomax =  9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 620   MHz */
-	{ .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 650   MHz */
-	{ .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 700   MHz */
-	{ .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 780   MHz */
-	{ .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},  /* 820   MHz */
-	{ .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},  /* 870   MHz */
-	{ .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},  /* 911   MHz */
-	{ .lomax =     0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}   /* End */
+	struct tda827x_config cfg;
 };
 
-static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
-			      struct analog_parameters *params)
-{
-	struct tda8290_priv *priv = fe->tuner_priv;
-	unsigned char buf[] = {0x22, 0x01};
-	int arg;
-	struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
-
-	if ((priv->lna_cfg == NULL)  || (priv->tuner_callback == NULL))
-	    return;
-
-	if (*priv->lna_cfg) {
-		if (high)
-			tuner_dbg("setting LNA to high gain\n");
-		else
-			tuner_dbg("setting LNA to low gain\n");
-	}
-	switch (*priv->lna_cfg) {
-	case 0: /* no LNA */
-		break;
-	case 1: /* switch is GPIO 0 of tda8290 */
-	case 2:
-		/* turn Vsync on */
-		if (params->std & V4L2_STD_MN)
-			arg = 1;
-		else
-			arg = 0;
-		if (priv->tuner_callback)
-			priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg);
-		buf[1] = high ? 0 : 1;
-		if (*priv->lna_cfg == 2)
-			buf[1] = high ? 1 : 0;
-		i2c_transfer(priv->i2c_props.adap, &msg, 1);
-		break;
-	case 3: /* switch with GPIO of saa713x */
-		if (priv->tuner_callback)
-			priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high);
-		break;
-	}
-}
+/*---------------------------------------------------------------------*/
 
-static void tda827xa_set_analog_params(struct dvb_frontend *fe,
-				       struct analog_parameters *params)
+static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
 {
-	unsigned char tuner_reg[11];
-	u32 N;
-	int i;
-	struct tda8290_priv *priv = fe->tuner_priv;
-	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
-	unsigned int freq = params->frequency;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
 
-	tda827xa_lna_gain(fe, 1, params);
-	msleep(10);
-
-	if (params->mode == V4L2_TUNER_RADIO)
-		freq = freq / 1000;
+	unsigned char  enable[2] = { 0x21, 0xC0 };
+	unsigned char disable[2] = { 0x21, 0x00 };
+	unsigned char *msg;
 
-	N = freq + priv->sgIF;
-	i = 0;
-	while (tda827xa_analog[i].lomax < N) {
-		if(tda827xa_analog[i + 1].lomax == 0)
-			break;
-		i++;
+	if (close) {
+		msg = enable;
+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
+		/* let the bridge stabilize */
+		msleep(20);
+	} else {
+		msg = disable;
+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
 	}
 
-	N = N << tda827xa_analog[i].spd;
-
-	tuner_reg[0] = 0;
-	tuner_reg[1] = (unsigned char)(N>>8);
-	tuner_reg[2] = (unsigned char) N;
-	tuner_reg[3] = 0;
-	tuner_reg[4] = 0x16;
-	tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) +
-			tda827xa_analog[i].sbs;
-	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
-	tuner_reg[7] = 0x1c;
-	tuner_reg[8] = 4;
-	tuner_reg[9] = 0x20;
-	tuner_reg[10] = 0x00;
-	msg.len = 11;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	tuner_reg[0] = 0x90;
-	tuner_reg[1] = 0xff;
-	tuner_reg[2] = 0xe0;
-	tuner_reg[3] = 0;
-	tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
-	msg.len = 5;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	tuner_reg[0] = 0xa0;
-	tuner_reg[1] = 0xc0;
-	msg.len = 2;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	tuner_reg[0] = 0x30;
-	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	msg.flags = I2C_M_RD;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-	msg.flags = 0;
-	tuner_reg[1] >>= 4;
-	tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]);
-	if (tuner_reg[1] < 1)
-		tda827xa_lna_gain(fe, 0, params);
-
-	msleep(100);
-	tuner_reg[0] = 0x60;
-	tuner_reg[1] = 0x3c;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	msleep(163);
-	tuner_reg[0] = 0x50;
-	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	tuner_reg[0] = 0x80;
-	tuner_reg[1] = 0x28;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	tuner_reg[0] = 0xb0;
-	tuner_reg[1] = 0x01;
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-
-	tuner_reg[0] = 0xc0;
-	tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
-}
-
-static void tda827xa_agcf(struct dvb_frontend *fe)
-{
-	struct tda8290_priv *priv = fe->tuner_priv;
-	unsigned char data[] = {0x80, 0x2c};
-	struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
-			      .flags = 0, .len = 2};
-	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+	return 0;
 }
 
-/*---------------------------------------------------------------------*/
-
-static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
+static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
 {
-	struct tda8290_priv *priv = fe->tuner_priv;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
 
-	unsigned char  enable[2] = { 0x21, 0xC0 };
-	unsigned char disable[2] = { 0x21, 0x00 };
+	unsigned char  enable[2] = { 0x45, 0xc1 };
+	unsigned char disable[2] = { 0x46, 0x00 };
+	unsigned char buf[3] = { 0x45, 0x01, 0x00 };
 	unsigned char *msg;
-	if(close) {
+
+	if (close) {
 		msg = enable;
 		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
 		/* let the bridge stabilize */
 		msleep(20);
 	} else {
 		msg = disable;
+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 1);
+		tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1);
+
+		buf[2] = msg[1];
+		buf[2] &= ~0x04;
+		tuner_i2c_xfer_send(&priv->i2c_props, buf, 3);
+		msleep(5);
+
+		msg[1] |= 0x04;
 		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
 	}
+
+	return 0;
 }
 
 /*---------------------------------------------------------------------*/
@@ -384,55 +112,43 @@ static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
 static void set_audio(struct dvb_frontend *fe,
 		      struct analog_parameters *params)
 {
-	struct tda8290_priv *priv = fe->tuner_priv;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
 	char* mode;
 
-	priv->tda827x_lpsel = 0;
 	if (params->std & V4L2_STD_MN) {
-		priv->sgIF = 92;
 		priv->tda8290_easy_mode = 0x01;
-		priv->tda827x_lpsel = 1;
 		mode = "MN";
 	} else if (params->std & V4L2_STD_B) {
-		priv->sgIF = 108;
 		priv->tda8290_easy_mode = 0x02;
 		mode = "B";
 	} else if (params->std & V4L2_STD_GH) {
-		priv->sgIF = 124;
 		priv->tda8290_easy_mode = 0x04;
 		mode = "GH";
 	} else if (params->std & V4L2_STD_PAL_I) {
-		priv->sgIF = 124;
 		priv->tda8290_easy_mode = 0x08;
 		mode = "I";
 	} else if (params->std & V4L2_STD_DK) {
-		priv->sgIF = 124;
 		priv->tda8290_easy_mode = 0x10;
 		mode = "DK";
 	} else if (params->std & V4L2_STD_SECAM_L) {
-		priv->sgIF = 124;
 		priv->tda8290_easy_mode = 0x20;
 		mode = "L";
 	} else if (params->std & V4L2_STD_SECAM_LC) {
-		priv->sgIF = 20;
 		priv->tda8290_easy_mode = 0x40;
 		mode = "LC";
 	} else {
-		priv->sgIF = 124;
 		priv->tda8290_easy_mode = 0x10;
 		mode = "xx";
 	}
 
-	if (params->mode == V4L2_TUNER_RADIO)
-		priv->sgIF = 88; /* if frequency is 5.5 MHz */
-
-	tuner_dbg("setting tda8290 to system %s\n", mode);
+	tuner_dbg("setting tda829x to system %s\n", mode);
 }
 
-static int tda8290_set_params(struct dvb_frontend *fe,
-			      struct analog_parameters *params)
+static void tda8290_set_params(struct dvb_frontend *fe,
+			       struct analog_parameters *params)
 {
-	struct tda8290_priv *priv = fe->tuner_priv;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
 	unsigned char soft_reset[]  = { 0x00, 0x00 };
 	unsigned char easy_mode[]   = { 0x01, priv->tda8290_easy_mode };
 	unsigned char expert_mode[] = { 0x01, 0x80 };
@@ -457,8 +173,8 @@ static int tda8290_set_params(struct dvb_frontend *fe,
 
 	set_audio(fe, params);
 
-	if (priv->lna_cfg)
-		tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg);
+	if (priv->cfg.config)
+		tuner_dbg("tda827xa config is 0x%02x\n", *priv->cfg.config);
 	tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
 	tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
 	tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
@@ -475,10 +191,10 @@ static int tda8290_set_params(struct dvb_frontend *fe,
 	tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
 
 	tda8290_i2c_bridge(fe, 1);
-	if (priv->tda827x_ver != 0)
-		tda827xa_set_analog_params(fe, params);
-	else
-		tda827x_set_analog_params(fe, params);
+
+	if (fe->ops.tuner_ops.set_analog_params)
+		fe->ops.tuner_ops.set_analog_params(fe, params);
+
 	for (i = 0; i < 3; i++) {
 		tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
 		tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
@@ -507,10 +223,8 @@ static int tda8290_set_params(struct dvb_frontend *fe,
 		if ((agc_stat > 115) || !(pll_stat & 0x80)) {
 			tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
 				   agc_stat, pll_stat & 0x80);
-			if (priv->tda827x_ver != 0)
-				tda827xa_agcf(fe);
-			else
-				tda827x_agcf(fe);
+			if (priv->cfg.agcf)
+				priv->cfg.agcf(fe);
 			msleep(100);
 			tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
 			tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
@@ -541,99 +255,242 @@ static int tda8290_set_params(struct dvb_frontend *fe,
 
 	tda8290_i2c_bridge(fe, 0);
 	tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
+}
+
+/*---------------------------------------------------------------------*/
+
+static void tda8295_power(struct dvb_frontend *fe, int enable)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */
 
-	priv->frequency = (V4L2_TUNER_RADIO == params->mode) ?
-		params->frequency * 125 / 2 : params->frequency * 62500;
+	tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
+	tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
 
-	return 0;
+	if (enable)
+		buf[1] = 0x01;
+	else
+		buf[1] = 0x03;
+
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+}
+
+static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char buf[] = { 0x01, 0x00 };
+
+	tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
+	tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+
+	if (enable)
+		buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */
+	else
+		buf[1] = 0x00; /* reset active bit */
+
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+}
+
+static void tda8295_set_video_std(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char buf[] = { 0x00, priv->tda8290_easy_mode };
+
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+
+	tda8295_set_easy_mode(fe, 1);
+	msleep(20);
+	tda8295_set_easy_mode(fe, 0);
 }
 
 /*---------------------------------------------------------------------*/
 
-static int tda8290_has_signal(struct dvb_frontend *fe)
+static void tda8295_agc1_out(struct dvb_frontend *fe, int enable)
 {
-	struct tda8290_priv *priv = fe->tuner_priv;
-	int ret;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */
 
-	unsigned char i2c_get_afc[1] = { 0x1B };
-	unsigned char afc = 0;
+	tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
+	tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
 
-	/* for now, report based on afc status */
-	tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
-	tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
+	if (enable)
+		buf[1] &= ~0x40;
+	else
+		buf[1] |= 0x40;
 
-	ret = (afc & 0x80) ? 65535 : 0;
+	tuner_i2c_xfer_send(&priv->i2c_props, buf, 2);
+}
+
+static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	unsigned char set_gpio_cf[]    = { 0x44, 0x00 };
+	unsigned char set_gpio_val[]   = { 0x46, 0x00 };
+
+	tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1);
+	tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1);
+	tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1);
+	tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1);
 
-	tuner_dbg("AFC status: %d\n", ret);
+	set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */
 
-	return ret;
+	if (enable) {
+		set_gpio_cf[1]  |= 0x01; /* config GPIO_0 as Open Drain Out */
+		set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */
+	}
+	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2);
 }
 
-static int tda8290_get_status(struct dvb_frontend *fe, u32 *status)
+static int tda8295_has_signal(struct dvb_frontend *fe)
 {
-	*status = 0;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
 
-	if (tda8290_has_signal(fe))
-		*status = TUNER_STATUS_LOCKED;
+	unsigned char hvpll_stat = 0x26;
+	unsigned char ret;
 
-	return 0;
+	tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1);
+	tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1);
+	return (ret & 0x01) ? 65535 : 0;
 }
 
-static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+/*---------------------------------------------------------------------*/
+
+static void tda8295_set_params(struct dvb_frontend *fe,
+			       struct analog_parameters *params)
 {
-	*strength = tda8290_has_signal(fe);
+	struct tda8290_priv *priv = fe->analog_demod_priv;
 
-	return 0;
+	unsigned char blanking_mode[]     = { 0x1d, 0x00 };
+
+	set_audio(fe, params);
+
+	tuner_dbg("%s: freq = %d\n", __FUNCTION__, params->frequency);
+
+	tda8295_power(fe, 1);
+	tda8295_agc1_out(fe, 1);
+
+	tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1);
+	tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1);
+
+	tda8295_set_video_std(fe);
+
+	blanking_mode[1] = 0x03;
+	tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2);
+	msleep(20);
+
+	tda8295_i2c_bridge(fe, 1);
+
+	if (fe->ops.tuner_ops.set_analog_params)
+		fe->ops.tuner_ops.set_analog_params(fe, params);
+
+	if (priv->cfg.agcf)
+		priv->cfg.agcf(fe);
+
+	if (tda8295_has_signal(fe))
+		tuner_dbg("tda8295 is locked\n");
+	else
+		tuner_dbg("tda8295 not locked, no signal?\n");
+
+	tda8295_i2c_bridge(fe, 0);
+}
+
+/*---------------------------------------------------------------------*/
+
+static int tda8290_has_signal(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	unsigned char i2c_get_afc[1] = { 0x1B };
+	unsigned char afc = 0;
+
+	tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
+	tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
+	return (afc & 0x80)? 65535:0;
 }
 
 /*---------------------------------------------------------------------*/
 
-static int tda8290_standby(struct dvb_frontend *fe)
+static void tda8290_standby(struct dvb_frontend *fe)
 {
-	struct tda8290_priv *priv = fe->tuner_priv;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
 	unsigned char cb1[] = { 0x30, 0xD0 };
 	unsigned char tda8290_standby[] = { 0x00, 0x02 };
 	unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
 	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
 
 	tda8290_i2c_bridge(fe, 1);
-	if (priv->tda827x_ver != 0)
+	if (priv->ver & TDA8275A)
 		cb1[1] = 0x90;
 	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 	tda8290_i2c_bridge(fe, 0);
 	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
 	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
-
-	return 0;
 }
 
+static void tda8295_standby(struct dvb_frontend *fe)
+{
+	tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */
+
+	tda8295_power(fe, 0);
+}
 
 static void tda8290_init_if(struct dvb_frontend *fe)
 {
-	struct tda8290_priv *priv = fe->tuner_priv;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
 
 	unsigned char set_VS[] = { 0x30, 0x6F };
 	unsigned char set_GP00_CF[] = { 0x20, 0x01 };
 	unsigned char set_GP01_CF[] = { 0x20, 0x0B };
 
-	if ((priv->lna_cfg) &&
-	    ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2)))
+	if ((priv->cfg.config) &&
+	    ((*priv->cfg.config == 1) || (*priv->cfg.config == 2)))
 		tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
 	else
 		tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
 	tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2);
 }
 
+static void tda8295_init_if(struct dvb_frontend *fe)
+{
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+
+	static unsigned char set_adc_ctl[]       = { 0x33, 0x14 };
+	static unsigned char set_adc_ctl2[]      = { 0x34, 0x00 };
+	static unsigned char set_pll_reg6[]      = { 0x3e, 0x63 };
+	static unsigned char set_pll_reg0[]      = { 0x38, 0x23 };
+	static unsigned char set_pll_reg7[]      = { 0x3f, 0x01 };
+	static unsigned char set_pll_reg10[]     = { 0x42, 0x61 };
+	static unsigned char set_gpio_reg0[]     = { 0x44, 0x0b };
+
+	tda8295_power(fe, 1);
+
+	tda8295_set_easy_mode(fe, 0);
+	tda8295_set_video_std(fe);
+
+	tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2);
+
+	tda8295_agc1_out(fe, 0);
+	tda8295_agc2_out(fe, 0);
+}
+
 static void tda8290_init_tuner(struct dvb_frontend *fe)
 {
-	struct tda8290_priv *priv = fe->tuner_priv;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
 	unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
 					  0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
 	unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
 					  0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
 	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
 			      .buf=tda8275_init, .len = 14};
-	if (priv->tda827x_ver != 0)
+	if (priv->ver & TDA8275A)
 		msg.buf = tda8275a_init;
 
 	tda8290_i2c_bridge(fe, 1);
@@ -643,58 +500,42 @@ static void tda8290_init_tuner(struct dvb_frontend *fe)
 
 /*---------------------------------------------------------------------*/
 
-static int tda8290_release(struct dvb_frontend *fe)
+static void tda829x_release(struct dvb_frontend *fe)
 {
-	kfree(fe->tuner_priv);
-	fe->tuner_priv = NULL;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
 
-	return 0;
-}
+	/* only try to release the tuner if we've
+	 * attached it from within this module */
+	if (priv->ver & (TDA18271 | TDA8275 | TDA8275A))
+		if (fe->ops.tuner_ops.release)
+			fe->ops.tuner_ops.release(fe);
 
-static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency)
-{
-	struct tda8290_priv *priv = fe->tuner_priv;
-	*frequency = priv->frequency;
-	return 0;
+	kfree(fe->analog_demod_priv);
+	fe->analog_demod_priv = NULL;
 }
 
-static struct dvb_tuner_ops tda8290_tuner_ops = {
-	.sleep             = tda8290_standby,
-	.set_analog_params = tda8290_set_params,
-	.release           = tda8290_release,
-	.get_frequency     = tda8290_get_frequency,
-	.get_status        = tda8290_get_status,
-	.get_rf_strength   = tda8290_get_rf_strength,
+static struct tda18271_config tda829x_tda18271_config = {
+	.gate    = TDA18271_GATE_ANALOG,
 };
 
-struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
-				    struct i2c_adapter* i2c_adap,
-				    u8 i2c_addr,
-				    struct tda8290_config *cfg)
+static int tda829x_find_tuner(struct dvb_frontend *fe)
 {
-	struct tda8290_priv *priv = NULL;
-	u8 data;
+	struct tda8290_priv *priv = fe->analog_demod_priv;
+	struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
 	int i, ret, tuners_found;
 	u32 tuner_addrs;
-	struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
+	u8 data;
+	struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };
 
-	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
-	if (priv == NULL)
-		return NULL;
-	fe->tuner_priv = priv;
+	if (NULL == analog_ops->i2c_gate_ctrl)
+		return -EINVAL;
 
-	priv->i2c_props.addr = i2c_addr;
-	priv->i2c_props.adap = i2c_adap;
-	if (cfg) {
-		priv->lna_cfg        = cfg->lna_cfg;
-		priv->tuner_callback = cfg->tuner_callback;
-	}
+	analog_ops->i2c_gate_ctrl(fe, 1);
 
-	tda8290_i2c_bridge(fe, 1);
 	/* probe for tuner chip */
 	tuners_found = 0;
 	tuner_addrs = 0;
-	for (i=0x60; i<= 0x63; i++) {
+	for (i = 0x60; i <= 0x63; i++) {
 		msg.addr = i;
 		ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
 		if (ret == 1) {
@@ -706,20 +547,23 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
 	   behind the bridge and we choose the highest address that doesn't
 	   give a response now
 	 */
-	tda8290_i2c_bridge(fe, 0);
-	if(tuners_found > 1)
+
+	analog_ops->i2c_gate_ctrl(fe, 0);
+
+	if (tuners_found > 1)
 		for (i = 0; i < tuners_found; i++) {
 			msg.addr = tuner_addrs  & 0xff;
 			ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
-			if(ret == 1)
+			if (ret == 1)
 				tuner_addrs = tuner_addrs >> 8;
 			else
 				break;
 		}
+
 	if (tuner_addrs == 0) {
-		tuner_addrs = 0x61;
-		tuner_info("could not clearly identify tuner address, defaulting to %x\n",
-			     tuner_addrs);
+		tuner_addrs = 0x60;
+		tuner_info("could not clearly identify tuner address, "
+			   "defaulting to %x\n", tuner_addrs);
 	} else {
 		tuner_addrs = tuner_addrs & 0xff;
 		tuner_info("setting tuner address to %x\n", tuner_addrs);
@@ -727,42 +571,181 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
 	priv->tda827x_addr = tuner_addrs;
 	msg.addr = tuner_addrs;
 
-	tda8290_i2c_bridge(fe, 1);
+	analog_ops->i2c_gate_ctrl(fe, 1);
 	ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
-	if( ret != 1)
-		tuner_warn("TDA827x access failed!\n");
-
-	memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops,
-	       sizeof(struct dvb_tuner_ops));
-
-	if ((data & 0x3c) == 0) {
-		strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75",
-			sizeof(fe->ops.tuner_ops.info.name));
-		fe->ops.tuner_ops.info.frequency_min  =  55000000;
-		fe->ops.tuner_ops.info.frequency_max  = 860000000;
-		fe->ops.tuner_ops.info.frequency_step =    250000;
-		priv->tda827x_ver = 0;
+
+	if (ret != 1) {
+		tuner_warn("tuner access failed!\n");
+		return -EREMOTEIO;
+	}
+
+	if ((data == 0x83) || (data == 0x84)) {
+		priv->ver |= TDA18271;
+		tda18271_attach(fe, priv->tda827x_addr,
+				priv->i2c_props.adap,
+				&tda829x_tda18271_config);
 	} else {
-		strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a",
-			sizeof(fe->ops.tuner_ops.info.name));
-		fe->ops.tuner_ops.info.frequency_min  =  44000000;
-		fe->ops.tuner_ops.info.frequency_max  = 906000000;
-		fe->ops.tuner_ops.info.frequency_step =     62500;
-		priv->tda827x_ver = 2;
+		if ((data & 0x3c) == 0)
+			priv->ver |= TDA8275;
+		else
+			priv->ver |= TDA8275A;
+
+		tda827x_attach(fe, priv->tda827x_addr,
+			       priv->i2c_props.adap, &priv->cfg);
+	}
+	if (fe->ops.tuner_ops.init)
+		fe->ops.tuner_ops.init(fe);
+
+	if (fe->ops.tuner_ops.sleep)
+		fe->ops.tuner_ops.sleep(fe);
+
+	analog_ops->i2c_gate_ctrl(fe, 0);
+
+	return 0;
+}
+
+static int tda8290_probe(struct tuner_i2c_props *i2c_props)
+{
+#define TDA8290_ID 0x89
+	unsigned char tda8290_id[] = { 0x1f, 0x00 };
+
+	/* detect tda8290 */
+	tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1);
+	tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1);
+
+	if (tda8290_id[1] == TDA8290_ID) {
+		if (debug)
+			printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
+			       __FUNCTION__, i2c_adapter_id(i2c_props->adap),
+			       i2c_props->addr);
+		return 0;
+	}
+
+	return -ENODEV;
+}
+
+static int tda8295_probe(struct tuner_i2c_props *i2c_props)
+{
+#define TDA8295_ID 0x8a
+	unsigned char tda8295_id[] = { 0x2f, 0x00 };
+
+	/* detect tda8295 */
+	tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1);
+	tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1);
+
+	if (tda8295_id[1] == TDA8295_ID) {
+		if (debug)
+			printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n",
+			       __FUNCTION__, i2c_adapter_id(i2c_props->adap),
+			       i2c_props->addr);
+		return 0;
 	}
 
-	priv->tda827x_lpsel = 0;
+	return -ENODEV;
+}
+
+static struct analog_demod_ops tda8290_ops = {
+	.set_params     = tda8290_set_params,
+	.has_signal     = tda8290_has_signal,
+	.standby        = tda8290_standby,
+	.release        = tda829x_release,
+	.i2c_gate_ctrl  = tda8290_i2c_bridge,
+};
+
+static struct analog_demod_ops tda8295_ops = {
+	.set_params     = tda8295_set_params,
+	.has_signal     = tda8295_has_signal,
+	.standby        = tda8295_standby,
+	.release        = tda829x_release,
+	.i2c_gate_ctrl  = tda8295_i2c_bridge,
+};
+
+struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter *i2c_adap, u8 i2c_addr,
+				    struct tda829x_config *cfg)
+{
+	struct tda8290_priv *priv = NULL;
+	char *name;
+
+	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	fe->analog_demod_priv = priv;
+
+	priv->i2c_props.addr     = i2c_addr;
+	priv->i2c_props.adap     = i2c_adap;
+	if (cfg) {
+		priv->cfg.config         = cfg->lna_cfg;
+		priv->cfg.tuner_callback = cfg->tuner_callback;
+	}
+
+	if (tda8290_probe(&priv->i2c_props) == 0) {
+		priv->ver = TDA8290;
+		memcpy(&fe->ops.analog_ops, &tda8290_ops,
+		       sizeof(struct analog_demod_ops));
+	}
+
+	if (tda8295_probe(&priv->i2c_props) == 0) {
+		priv->ver = TDA8295;
+		memcpy(&fe->ops.analog_ops, &tda8295_ops,
+		       sizeof(struct analog_demod_ops));
+	}
+
+	if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) &&
+	    (tda829x_find_tuner(fe) < 0))
+		goto fail;
+
+	switch (priv->ver) {
+	case TDA8290:
+		name = "tda8290";
+		break;
+	case TDA8295:
+		name = "tda8295";
+		break;
+	case TDA8290 | TDA8275:
+		name = "tda8290+75";
+		break;
+	case TDA8295 | TDA8275:
+		name = "tda8295+75";
+		break;
+	case TDA8290 | TDA8275A:
+		name = "tda8290+75a";
+		break;
+	case TDA8295 | TDA8275A:
+		name = "tda8295+75a";
+		break;
+	case TDA8290 | TDA18271:
+		name = "tda8290+18271";
+		break;
+	case TDA8295 | TDA18271:
+		name = "tda8295+18271";
+		break;
+	default:
+		goto fail;
+	}
+	tuner_info("type set to %s\n", name);
+
+	fe->ops.analog_ops.info.name = name;
+
+	if (priv->ver & TDA8290) {
+		tda8290_init_tuner(fe);
+		tda8290_init_if(fe);
+	} else if (priv->ver & TDA8295)
+		tda8295_init_if(fe);
 
-	tda8290_init_tuner(fe);
-	tda8290_init_if(fe);
 	return fe;
+
+fail:
+	tda829x_release(fe);
+	return NULL;
 }
+EXPORT_SYMBOL_GPL(tda829x_attach);
 
-int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
 {
 	struct tuner_i2c_props i2c_props = {
 		.adap = i2c_adap,
-		.addr = i2c_addr
+		.addr = i2c_addr,
 	};
 
 	unsigned char soft_reset[]   = { 0x00, 0x00 };
@@ -771,7 +754,27 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
 	unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 };
 	unsigned char addr_dto_lsb = 0x07;
 	unsigned char data;
+#define PROBE_BUFFER_SIZE 8
+	unsigned char buf[PROBE_BUFFER_SIZE];
+	int i;
+
+	/* rule out tda9887, which would return the same byte repeatedly */
+	tuner_i2c_xfer_send(&i2c_props, soft_reset, 1);
+	tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE);
+	for (i = 1; i < PROBE_BUFFER_SIZE; i++) {
+		if (buf[i] != buf[0])
+			break;
+	}
 
+	/* all bytes are equal, not a tda829x - probably a tda9887 */
+	if (i == PROBE_BUFFER_SIZE)
+		return -ENODEV;
+
+	if ((tda8290_probe(&i2c_props) == 0) ||
+	    (tda8295_probe(&i2c_props) == 0))
+		return 0;
+
+	/* fall back to old probing method */
 	tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
 	tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
 	tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
@@ -786,14 +789,12 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
 		}
 	}
 	tuner_i2c_xfer_send(&i2c_props, restore_9886, 3);
-	return -1;
+	return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(tda829x_probe);
 
-EXPORT_SYMBOL_GPL(tda8290_probe);
-EXPORT_SYMBOL_GPL(tda8290_attach);
-
-MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver");
-MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann");
+MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver");
+MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky");
 MODULE_LICENSE("GPL");
 
 /*
diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h
index 107b24b05aa1..dc8ef310b7b2 100644
--- a/drivers/media/video/tda8290.h
+++ b/drivers/media/video/tda8290.h
@@ -20,33 +20,36 @@
 #include <linux/i2c.h>
 #include "dvb_frontend.h"
 
-struct tda8290_config
-{
+struct tda829x_config {
 	unsigned int *lna_cfg;
-	int (*tuner_callback) (void *dev, int command,int arg);
+	int (*tuner_callback) (void *dev, int command, int arg);
+
+	unsigned int probe_tuner:1;
+#define TDA829X_PROBE_TUNER 0
+#define TDA829X_DONT_PROBE  1
 };
 
 #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
-extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
 
-extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
-					   struct i2c_adapter* i2c_adap,
+extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter *i2c_adap,
 					   u8 i2c_addr,
-					   struct tda8290_config *cfg);
+					   struct tda829x_config *cfg);
 #else
-static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
 {
-	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
-	       __FUNCTION__);
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
 	return -EINVAL;
 }
 
-static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
-						  struct i2c_adapter* i2c_adap,
+static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
+						  struct i2c_adapter *i2c_adap,
 						  u8 i2c_addr,
-						  struct tda8290_config *cfg)
+						  struct tda829x_config *cfg)
 {
-	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __FUNCTION__);
 	return NULL;
 }
 #endif
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index d11044170872..3c0557130a70 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -7,6 +7,7 @@
  *
  * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and
  * Eric Sandeen
+ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
  * This code is placed under the terms of the GNU General Public License
  * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
  * Which was based on tda8425.c by Greg Alexander (c) 1998
@@ -268,87 +269,143 @@ static int tda9875_detach(struct i2c_client *client)
 	return 0;
 }
 
-static int tda9875_command(struct i2c_client *client,
-				unsigned int cmd, void *arg)
+static int tda9875_get_ctrl(struct i2c_client *client,
+			    struct v4l2_control *ctrl)
 {
 	struct tda9875 *t = i2c_get_clientdata(client);
 
-	dprintk("In tda9875_command...\n");
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+	{
+		int left = (t->lvol+84)*606;
+		int right = (t->rvol+84)*606;
 
-	switch (cmd) {
-	/* --- v4l ioctls --- */
-	/* take care: bttv does userspace copying, we'll get a
-	   kernel pointer here... */
-	case VIDIOCGAUDIO:
+		ctrl->value=max(left,right);
+		return 0;
+	}
+	case V4L2_CID_AUDIO_BALANCE:
 	{
-		struct video_audio *va = arg;
-		int left,right;
+		int left = (t->lvol+84)*606;
+		int right = (t->rvol+84)*606;
+		int volume = max(left,right);
+		int balance = (32768*min(left,right))/
+			      (volume ? volume : 1);
+		ctrl->value=(left<right)?
+			(65535-balance) : balance;
+		return 0;
+	}
+	case V4L2_CID_AUDIO_BASS:
+		ctrl->value = (t->bass+12)*2427;    /* min -12 max +15 */
+		return 0;
+	case V4L2_CID_AUDIO_TREBLE:
+		ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */
+		return 0;
+	}
+	return -EINVAL;
+}
 
-		dprintk("VIDIOCGAUDIO\n");
+static int tda9875_set_ctrl(struct i2c_client *client,
+			    struct v4l2_control *ctrl)
+{
+	struct tda9875 *t = i2c_get_clientdata(client);
+	int chvol=0, volume, balance, left, right;
 
-		va->flags |= VIDEO_AUDIO_VOLUME |
-			VIDEO_AUDIO_BASS |
-			VIDEO_AUDIO_TREBLE;
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_VOLUME:
+		left = (t->lvol+84)*606;
+		right = (t->rvol+84)*606;
+
+		volume = max(left,right);
+		balance = (32768*min(left,right))/
+			      (volume ? volume : 1);
+		balance =(left<right)?
+			(65535-balance) : balance;
+
+		volume = ctrl->value;
 
-		/* min is -84 max is 24 */
+		chvol=1;
+		break;
+	case V4L2_CID_AUDIO_BALANCE:
 		left = (t->lvol+84)*606;
 		right = (t->rvol+84)*606;
-		va->volume=max(left,right);
-		va->balance=(32768*min(left,right))/
-			(va->volume ? va->volume : 1);
-		va->balance=(left<right)?
-			(65535-va->balance) : va->balance;
-		va->bass = (t->bass+12)*2427;    /* min -12 max +15 */
-		va->treble = (t->treble+12)*2730;/* min -12 max +12 */
-		va->mode |= VIDEO_SOUND_MONO;
-
-		break; /* VIDIOCGAUDIO case */
+
+		volume=max(left,right);
+
+		balance = ctrl->value;
+
+		chvol=1;
+		break;
+	case V4L2_CID_AUDIO_BASS:
+		t->bass = ((ctrl->value/2400)-12) & 0xff;
+		if (t->bass > 15)
+			t->bass = 15;
+		if (t->bass < -12)
+			t->bass = -12 & 0xff;
+		break;
+	case V4L2_CID_AUDIO_TREBLE:
+		t->treble = ((ctrl->value/2700)-12) & 0xff;
+		if (t->treble > 12)
+			t->treble = 12;
+		if (t->treble < -12)
+			t->treble = -12 & 0xff;
+		break;
+	default:
+		return -EINVAL;
 	}
 
-	case VIDIOCSAUDIO:
-	{
-		struct video_audio *va = arg;
-		int left,right;
-
-		dprintk("VIDEOCSAUDIO...\n");
-		left = (min(65536 - va->balance,32768) *
-			va->volume) / 32768;
-		right = (min(va->balance,(__u16)32768) *
-			 va->volume) / 32768;
+	if (chvol) {
+		left = (min(65536 - balance,32768) *
+			volume) / 32768;
+		right = (min(balance,32768) *
+				volume) / 32768;
 		t->lvol = ((left/606)-84) & 0xff;
 		if (t->lvol > 24)
-		 t->lvol = 24;
+			t->lvol = 24;
 		if (t->lvol < -84)
-		 t->lvol = -84 & 0xff;
+			t->lvol = -84 & 0xff;
 
 		t->rvol = ((right/606)-84) & 0xff;
 		if (t->rvol > 24)
-		 t->rvol = 24;
+			t->rvol = 24;
 		if (t->rvol < -84)
-		 t->rvol = -84 & 0xff;
-
-		t->bass = ((va->bass/2400)-12) & 0xff;
-		if (t->bass > 15)
-		 t->bass = 15;
-		if (t->bass < -12)
-		 t->bass = -12 & 0xff;
-
-		t->treble = ((va->treble/2700)-12) & 0xff;
-		if (t->treble > 12)
-		 t->treble = 12;
-		if (t->treble < -12)
-		 t->treble = -12 & 0xff;
+			t->rvol = -84 & 0xff;
+	}
 
+//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
 
+	tda9875_set(client);
 
-//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble);
+	return 0;
+}
 
 
-		tda9875_set(client);
+static int tda9875_command(struct i2c_client *client,
+				unsigned int cmd, void *arg)
+{
+	dprintk("In tda9875_command...\n");
 
-		break;
+	switch (cmd) {
+	/* --- v4l ioctls --- */
+	/* take care: bttv does userspace copying, we'll get a
+	   kernel pointer here... */
+	case VIDIOC_QUERYCTRL:
+	{
+		struct v4l2_queryctrl *qc = arg;
+
+		switch (qc->id) {
+			case V4L2_CID_AUDIO_VOLUME:
+			case V4L2_CID_AUDIO_BASS:
+			case V4L2_CID_AUDIO_TREBLE:
+			default:
+				return -EINVAL;
+		}
+		return v4l2_ctrl_query_fill_std(qc);
+	}
+	case VIDIOC_S_CTRL:
+		return tda9875_set_ctrl(client, arg);
 
-	} /* end of VIDEOCSAUDIO case */
+	case VIDIOC_G_CTRL:
+		return tda9875_get_ctrl(client, arg);
 
 	default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */
 
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index be5387f11afb..106c93b8203f 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -9,7 +9,8 @@
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
-#include "tuner-driver.h"
+#include "tuner-i2c.h"
+#include "tda9887.h"
 
 
 /* Chips:
@@ -20,18 +21,20 @@
    Used as part of several tuners
 */
 
-#define tda9887_info(fmt, arg...) do {\
-	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
-			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tda9887_dbg(fmt, arg...) do {\
-	if (tuner_debug) \
-		printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
-			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "tda9887"
 
 struct tda9887_priv {
 	struct tuner_i2c_props i2c_props;
 
 	unsigned char 	   data[4];
+	unsigned int       config;
+	unsigned int       mode;
+	unsigned int       audmode;
+	v4l2_std_id        std;
 };
 
 /* ---------------------------------------------------------------------- */
@@ -262,8 +265,10 @@ static struct tvnorm radio_mono = {
 
 /* ---------------------------------------------------------------------- */
 
-static void dump_read_message(struct tuner *t, unsigned char *buf)
+static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf)
 {
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
 	static char *afc[16] = {
 		"- 12.5 kHz",
 		"- 37.5 kHz",
@@ -282,16 +287,18 @@ static void dump_read_message(struct tuner *t, unsigned char *buf)
 		"+ 37.5 kHz",
 		"+ 12.5 kHz",
 	};
-	tda9887_info("read: 0x%2x\n", buf[0]);
-	tda9887_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
-	tda9887_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
-	tda9887_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
-	tda9887_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
-	tda9887_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
+	tuner_info("read: 0x%2x\n", buf[0]);
+	tuner_info("  after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no");
+	tuner_info("  afc            : %s\n", afc[(buf[0] >> 1) & 0x0f]);
+	tuner_info("  fmif level     : %s\n", (buf[0] & 0x20) ? "high" : "low");
+	tuner_info("  afc window     : %s\n", (buf[0] & 0x40) ? "in" : "out");
+	tuner_info("  vfi level      : %s\n", (buf[0] & 0x80) ? "high" : "low");
 }
 
-static void dump_write_message(struct tuner *t, unsigned char *buf)
+static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf)
 {
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
 	static char *sound[4] = {
 		"AM/TV",
 		"FM/radio",
@@ -330,86 +337,90 @@ static void dump_write_message(struct tuner *t, unsigned char *buf)
 		"44 MHz",
 	};
 
-	tda9887_info("write: byte B 0x%02x\n",buf[1]);
-	tda9887_info("  B0   video mode      : %s\n",
-	       (buf[1] & 0x01) ? "video trap" : "sound trap");
-	tda9887_info("  B1   auto mute fm    : %s\n",
-	       (buf[1] & 0x02) ? "yes" : "no");
-	tda9887_info("  B2   carrier mode    : %s\n",
-	       (buf[1] & 0x04) ? "QSS" : "Intercarrier");
-	tda9887_info("  B3-4 tv sound/radio  : %s\n",
-	       sound[(buf[1] & 0x18) >> 3]);
-	tda9887_info("  B5   force mute audio: %s\n",
-	       (buf[1] & 0x20) ? "yes" : "no");
-	tda9887_info("  B6   output port 1   : %s\n",
-	       (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
-	tda9887_info("  B7   output port 2   : %s\n",
-	       (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
-
-	tda9887_info("write: byte C 0x%02x\n",buf[2]);
-	tda9887_info("  C0-4 top adjustment  : %s dB\n", adjust[buf[2] & 0x1f]);
-	tda9887_info("  C5-6 de-emphasis     : %s\n", deemph[(buf[2] & 0x60) >> 5]);
-	tda9887_info("  C7   audio gain      : %s\n",
-	       (buf[2] & 0x80) ? "-6" : "0");
-
-	tda9887_info("write: byte E 0x%02x\n",buf[3]);
-	tda9887_info("  E0-1 sound carrier   : %s\n",
-	       carrier[(buf[3] & 0x03)]);
-	tda9887_info("  E6   l pll gating   : %s\n",
-	       (buf[3] & 0x40) ? "36" : "13");
+	tuner_info("write: byte B 0x%02x\n", buf[1]);
+	tuner_info("  B0   video mode      : %s\n",
+		   (buf[1] & 0x01) ? "video trap" : "sound trap");
+	tuner_info("  B1   auto mute fm    : %s\n",
+		   (buf[1] & 0x02) ? "yes" : "no");
+	tuner_info("  B2   carrier mode    : %s\n",
+		   (buf[1] & 0x04) ? "QSS" : "Intercarrier");
+	tuner_info("  B3-4 tv sound/radio  : %s\n",
+		   sound[(buf[1] & 0x18) >> 3]);
+	tuner_info("  B5   force mute audio: %s\n",
+		   (buf[1] & 0x20) ? "yes" : "no");
+	tuner_info("  B6   output port 1   : %s\n",
+		   (buf[1] & 0x40) ? "high (inactive)" : "low (active)");
+	tuner_info("  B7   output port 2   : %s\n",
+		   (buf[1] & 0x80) ? "high (inactive)" : "low (active)");
+
+	tuner_info("write: byte C 0x%02x\n", buf[2]);
+	tuner_info("  C0-4 top adjustment  : %s dB\n",
+		   adjust[buf[2] & 0x1f]);
+	tuner_info("  C5-6 de-emphasis     : %s\n",
+		   deemph[(buf[2] & 0x60) >> 5]);
+	tuner_info("  C7   audio gain      : %s\n",
+		   (buf[2] & 0x80) ? "-6" : "0");
+
+	tuner_info("write: byte E 0x%02x\n", buf[3]);
+	tuner_info("  E0-1 sound carrier   : %s\n",
+		   carrier[(buf[3] & 0x03)]);
+	tuner_info("  E6   l pll gating   : %s\n",
+		   (buf[3] & 0x40) ? "36" : "13");
 
 	if (buf[1] & 0x08) {
 		/* radio */
-		tda9887_info("  E2-4 video if        : %s\n",
-		       rif[(buf[3] & 0x0c) >> 2]);
-		tda9887_info("  E7   vif agc output  : %s\n",
-		       (buf[3] & 0x80)
-		       ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio")
-		       : "fm radio carrier afc");
+		tuner_info("  E2-4 video if        : %s\n",
+			   rif[(buf[3] & 0x0c) >> 2]);
+		tuner_info("  E7   vif agc output  : %s\n",
+			   (buf[3] & 0x80)
+			   ? ((buf[3] & 0x10) ? "fm-agc radio" :
+						"sif-agc radio")
+			   : "fm radio carrier afc");
 	} else {
 		/* video */
-		tda9887_info("  E2-4 video if        : %s\n",
-		       vif[(buf[3] & 0x1c) >> 2]);
-		tda9887_info("  E5   tuner gain      : %s\n",
-		       (buf[3] & 0x80)
-		       ? ((buf[3] & 0x20) ? "external" : "normal")
-		       : ((buf[3] & 0x20) ? "minimum"  : "normal"));
-		tda9887_info("  E7   vif agc output  : %s\n",
-		       (buf[3] & 0x80)
-		       ? ((buf[3] & 0x20)
-			  ? "pin3 port, pin22 vif agc out"
-			  : "pin22 port, pin3 vif acg ext in")
-		       : "pin3+pin22 port");
+		tuner_info("  E2-4 video if        : %s\n",
+			   vif[(buf[3] & 0x1c) >> 2]);
+		tuner_info("  E5   tuner gain      : %s\n",
+			   (buf[3] & 0x80)
+			   ? ((buf[3] & 0x20) ? "external" : "normal")
+			   : ((buf[3] & 0x20) ? "minimum"  : "normal"));
+		tuner_info("  E7   vif agc output  : %s\n",
+			   (buf[3] & 0x80) ? ((buf[3] & 0x20)
+				? "pin3 port, pin22 vif agc out"
+				: "pin22 port, pin3 vif acg ext in")
+				: "pin3+pin22 port");
 	}
-	tda9887_info("--\n");
+	tuner_info("--\n");
 }
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_set_tvnorm(struct tuner *t, char *buf)
+static int tda9887_set_tvnorm(struct dvb_frontend *fe)
 {
+	struct tda9887_priv *priv = fe->analog_demod_priv;
 	struct tvnorm *norm = NULL;
+	char *buf = priv->data;
 	int i;
 
-	if (t->mode == V4L2_TUNER_RADIO) {
-		if (t->audmode == V4L2_TUNER_MODE_MONO)
+	if (priv->mode == V4L2_TUNER_RADIO) {
+		if (priv->audmode == V4L2_TUNER_MODE_MONO)
 			norm = &radio_mono;
 		else
 			norm = &radio_stereo;
 	} else {
 		for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
-			if (tvnorms[i].std & t->std) {
+			if (tvnorms[i].std & priv->std) {
 				norm = tvnorms+i;
 				break;
 			}
 		}
 	}
 	if (NULL == norm) {
-		tda9887_dbg("Unsupported tvnorm entry - audio muted\n");
+		tuner_dbg("Unsupported tvnorm entry - audio muted\n");
 		return -1;
 	}
 
-	tda9887_dbg("configure for: %s\n",norm->name);
+	tuner_dbg("configure for: %s\n", norm->name);
 	buf[1] = norm->b;
 	buf[2] = norm->c;
 	buf[3] = norm->e;
@@ -426,8 +437,11 @@ module_param(port2, int, 0644);
 module_param(qss, int, 0644);
 module_param(adjust, int, 0644);
 
-static int tda9887_set_insmod(struct tuner *t, char *buf)
+static int tda9887_set_insmod(struct dvb_frontend *fe)
 {
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+	char *buf = priv->data;
+
 	if (UNSET != port1) {
 		if (port1)
 			buf[1] |= cOutputPort1Inactive;
@@ -455,27 +469,30 @@ static int tda9887_set_insmod(struct tuner *t, char *buf)
 	return 0;
 }
 
-static int tda9887_set_config(struct tuner *t, char *buf)
+static int tda9887_do_config(struct dvb_frontend *fe)
 {
-	if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+	char *buf = priv->data;
+
+	if (priv->config & TDA9887_PORT1_ACTIVE)
 		buf[1] &= ~cOutputPort1Inactive;
-	if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
+	if (priv->config & TDA9887_PORT1_INACTIVE)
 		buf[1] |= cOutputPort1Inactive;
-	if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
+	if (priv->config & TDA9887_PORT2_ACTIVE)
 		buf[1] &= ~cOutputPort2Inactive;
-	if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
+	if (priv->config & TDA9887_PORT2_INACTIVE)
 		buf[1] |= cOutputPort2Inactive;
 
-	if (t->tda9887_config & TDA9887_QSS)
+	if (priv->config & TDA9887_QSS)
 		buf[1] |= cQSS;
-	if (t->tda9887_config & TDA9887_INTERCARRIER)
+	if (priv->config & TDA9887_INTERCARRIER)
 		buf[1] &= ~cQSS;
 
-	if (t->tda9887_config & TDA9887_AUTOMUTE)
+	if (priv->config & TDA9887_AUTOMUTE)
 		buf[1] |= cAutoMuteFmActive;
-	if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
+	if (priv->config & TDA9887_DEEMPHASIS_MASK) {
 		buf[2] &= ~0x60;
-		switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
+		switch (priv->config & TDA9887_DEEMPHASIS_MASK) {
 		case TDA9887_DEEMPHASIS_NONE:
 			buf[2] |= cDeemphasisOFF;
 			break;
@@ -487,21 +504,22 @@ static int tda9887_set_config(struct tuner *t, char *buf)
 			break;
 		}
 	}
-	if (t->tda9887_config & TDA9887_TOP_SET) {
+	if (priv->config & TDA9887_TOP_SET) {
 		buf[2] &= ~cTopMask;
-		buf[2] |= (t->tda9887_config >> 8) & cTopMask;
+		buf[2] |= (priv->config >> 8) & cTopMask;
 	}
-	if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+	if ((priv->config & TDA9887_INTERCARRIER_NTSC) &&
+	    (priv->std & V4L2_STD_NTSC))
 		buf[1] &= ~cQSS;
-	if (t->tda9887_config & TDA9887_GATING_18)
+	if (priv->config & TDA9887_GATING_18)
 		buf[3] &= ~cGating_36;
 
-	if (t->mode == V4L2_TUNER_RADIO) {
-		if (t->tda9887_config & TDA9887_RIF_41_3) {
+	if (priv->mode == V4L2_TUNER_RADIO) {
+		if (priv->config & TDA9887_RIF_41_3) {
 			buf[3] &= ~cVideoIFMask;
 			buf[3] |= cRadioIF_41_30;
 		}
-		if (t->tda9887_config & TDA9887_GAIN_NORMAL)
+		if (priv->config & TDA9887_GAIN_NORMAL)
 			buf[3] &= ~cTunerGainLow;
 	}
 
@@ -510,26 +528,26 @@ static int tda9887_set_config(struct tuner *t, char *buf)
 
 /* ---------------------------------------------------------------------- */
 
-static int tda9887_status(struct tuner *t)
+static int tda9887_status(struct dvb_frontend *fe)
 {
-	struct tda9887_priv *priv = t->priv;
+	struct tda9887_priv *priv = fe->analog_demod_priv;
 	unsigned char buf[1];
 	int rc;
 
 	memset(buf,0,sizeof(buf));
 	if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
-		tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
-	dump_read_message(t, buf);
+		tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc);
+	dump_read_message(fe, buf);
 	return 0;
 }
 
-static void tda9887_configure(struct tuner *t)
+static void tda9887_configure(struct dvb_frontend *fe)
 {
-	struct tda9887_priv *priv = t->priv;
+	struct tda9887_priv *priv = fe->analog_demod_priv;
 	int rc;
 
 	memset(priv->data,0,sizeof(priv->data));
-	tda9887_set_tvnorm(t,priv->data);
+	tda9887_set_tvnorm(fe);
 
 	/* A note on the port settings:
 	   These settings tend to depend on the specifics of the board.
@@ -547,38 +565,38 @@ static void tda9887_configure(struct tuner *t)
 	priv->data[1] |= cOutputPort1Inactive;
 	priv->data[1] |= cOutputPort2Inactive;
 
-	tda9887_set_config(t,priv->data);
-	tda9887_set_insmod(t,priv->data);
+	tda9887_do_config(fe);
+	tda9887_set_insmod(fe);
 
-	if (t->mode == T_STANDBY) {
+	if (priv->mode == T_STANDBY)
 		priv->data[1] |= cForcedMuteAudioON;
-	}
 
-	tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
-		priv->data[1],priv->data[2],priv->data[3]);
-	if (tuner_debug > 1)
-		dump_write_message(t, priv->data);
+	tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
+		  priv->data[1], priv->data[2], priv->data[3]);
+	if (debug > 1)
+		dump_write_message(fe, priv->data);
 
 	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
-		tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
+		tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc);
 
-	if (tuner_debug > 2) {
+	if (debug > 2) {
 		msleep_interruptible(1000);
-		tda9887_status(t);
+		tda9887_status(fe);
 	}
 }
 
 /* ---------------------------------------------------------------------- */
 
-static void tda9887_tuner_status(struct tuner *t)
+static void tda9887_tuner_status(struct dvb_frontend *fe)
 {
-	struct tda9887_priv *priv = t->priv;
-	tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+	tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n",
+		   priv->data[1], priv->data[2], priv->data[3]);
 }
 
-static int tda9887_get_afc(struct tuner *t)
+static int tda9887_get_afc(struct dvb_frontend *fe)
 {
-	struct tda9887_priv *priv = t->priv;
+	struct tda9887_priv *priv = fe->analog_demod_priv;
 	static int AFC_BITS_2_kHz[] = {
 		-12500,  -37500,  -62500,  -97500,
 		-112500, -137500, -162500, -187500,
@@ -594,52 +612,79 @@ static int tda9887_get_afc(struct tuner *t)
 	return afc;
 }
 
-static void tda9887_standby(struct tuner *t)
+static void tda9887_standby(struct dvb_frontend *fe)
+{
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
+	priv->mode = T_STANDBY;
+
+	tda9887_configure(fe);
+}
+
+static void tda9887_set_params(struct dvb_frontend *fe,
+			       struct analog_parameters *params)
 {
-	tda9887_configure(t);
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
+	priv->mode    = params->mode;
+	priv->audmode = params->audmode;
+	priv->std     = params->std;
+	tda9887_configure(fe);
 }
 
-static void tda9887_set_freq(struct tuner *t, unsigned int freq)
+static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
 {
-	tda9887_configure(t);
+	struct tda9887_priv *priv = fe->analog_demod_priv;
+
+	priv->config = *(unsigned int *)priv_cfg;
+	tda9887_configure(fe);
+
+	return 0;
 }
 
-static void tda9887_release(struct tuner *t)
+static void tda9887_release(struct dvb_frontend *fe)
 {
-	kfree(t->priv);
-	t->priv = NULL;
+	kfree(fe->analog_demod_priv);
+	fe->analog_demod_priv = NULL;
 }
 
-static struct tuner_operations tda9887_tuner_ops = {
-	.set_tv_freq    = tda9887_set_freq,
-	.set_radio_freq = tda9887_set_freq,
+static struct analog_demod_ops tda9887_ops = {
+	.info		= {
+		.name	= "tda9887",
+	},
+	.set_params     = tda9887_set_params,
 	.standby        = tda9887_standby,
 	.tuner_status   = tda9887_tuner_status,
 	.get_afc        = tda9887_get_afc,
 	.release        = tda9887_release,
+	.set_config     = tda9887_set_config,
 };
 
-int tda9887_tuner_init(struct tuner *t)
+struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter *i2c_adap,
+				    u8 i2c_addr)
 {
 	struct tda9887_priv *priv = NULL;
 
 	priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
 	if (priv == NULL)
-		return -ENOMEM;
-	t->priv = priv;
-
-	priv->i2c_props.addr = t->i2c.addr;
-	priv->i2c_props.adap = t->i2c.adapter;
+		return NULL;
+	fe->analog_demod_priv = priv;
 
-	strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name));
+	priv->i2c_props.addr = i2c_addr;
+	priv->i2c_props.adap = i2c_adap;
+	priv->mode = T_STANDBY;
 
-	tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
-						t->i2c.driver->driver.name);
+	tuner_info("tda988[5/6/7] found\n");
 
-	memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
+	memcpy(&fe->ops.analog_ops, &tda9887_ops,
+	       sizeof(struct analog_demod_ops));
 
-	return 0;
+	return fe;
 }
+EXPORT_SYMBOL_GPL(tda9887_attach);
+
+MODULE_LICENSE("GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/tda9887.h b/drivers/media/video/tda9887.h
new file mode 100644
index 000000000000..8f873a8e6ed2
--- /dev/null
+++ b/drivers/media/video/tda9887.h
@@ -0,0 +1,38 @@
+/*
+    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 __TDA9887_H__
+#define __TDA9887_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/* ------------------------------------------------------------------------ */
+#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter *i2c_adap,
+					   u8 i2c_addr);
+#else
+static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
+						  struct i2c_adapter *i2c_adap,
+						  u8 i2c_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* __TDA9887_H__ */
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
index 2150222a3860..5326eeceaacd 100644
--- a/drivers/media/video/tea5761.c
+++ b/drivers/media/video/tea5761.c
@@ -18,7 +18,7 @@ static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tea5761 "
+#define PREFIX "tea5761"
 
 struct tea5761_priv {
 	struct tuner_i2c_props i2c_props;
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index 71df419df7bc..e1b48d87e7b7 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -20,12 +20,14 @@ static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tea5767 "
+#define PREFIX "tea5767"
 
-struct tea5767_priv {
-	struct tuner_i2c_props i2c_props;
+/*****************************************************************************/
 
-	u32 frequency;
+struct tea5767_priv {
+	struct tuner_i2c_props	i2c_props;
+	u32			frequency;
+	struct tea5767_ctrl	ctrl;
 };
 
 /*****************************************************************************/
@@ -127,17 +129,10 @@ struct tea5767_priv {
 /* Reserved for future extensions */
 #define TEA5767_RESERVED_MASK	0xff
 
-enum tea5767_xtal_freq {
-	TEA5767_LOW_LO_32768    = 0,
-	TEA5767_HIGH_LO_32768   = 1,
-	TEA5767_LOW_LO_13MHz    = 2,
-	TEA5767_HIGH_LO_13MHz   = 3,
-};
-
-
 /*****************************************************************************/
 
-static void tea5767_status_dump(unsigned char *buffer)
+static void tea5767_status_dump(struct tea5767_priv *priv,
+				unsigned char *buffer)
 {
 	unsigned int div, frq;
 
@@ -153,7 +148,7 @@ static void tea5767_status_dump(unsigned char *buffer)
 
 	div = ((buffer[0] & 0x3f) << 8) | buffer[1];
 
-	switch (TEA5767_HIGH_LO_32768) {
+	switch (priv->ctrl.xtal_freq) {
 	case TEA5767_HIGH_LO_13MHz:
 		frq = (div * 50000 - 700000 - 225000) / 4;	/* Freq in KHz */
 		break;
@@ -202,13 +197,10 @@ static int set_radio_freq(struct dvb_frontend *fe,
 
 	tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
 
-	/* Rounds freq to next decimal value - for 62.5 KHz step */
-	/* frq = 20*(frq/16)+radio_frq[frq%16]; */
+	buffer[2] = 0;
 
-	buffer[2] = TEA5767_PORT1_HIGH;
-	buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL |
-		    TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND;
-	buffer[4] = 0;
+	if (priv->ctrl.port1)
+		buffer[2] |= TEA5767_PORT1_HIGH;
 
 	if (params->audmode == V4L2_TUNER_MODE_MONO) {
 		tuner_dbg("TEA5767 set to mono\n");
@@ -217,18 +209,45 @@ static int set_radio_freq(struct dvb_frontend *fe,
 		tuner_dbg("TEA5767 set to stereo\n");
 	}
 
-	/* Should be replaced */
-	switch (TEA5767_HIGH_LO_32768) {
+
+	buffer[3] = 0;
+
+	if (priv->ctrl.port2)
+		buffer[3] |= TEA5767_PORT2_HIGH;
+
+	if (priv->ctrl.high_cut)
+		buffer[3] |= TEA5767_HIGH_CUT_CTRL;
+
+	if (priv->ctrl.st_noise)
+		buffer[3] |= TEA5767_ST_NOISE_CTL;
+
+	if (priv->ctrl.soft_mute)
+		buffer[3] |= TEA5767_SOFT_MUTE;
+
+	if (priv->ctrl.japan_band)
+		buffer[3] |= TEA5767_JAPAN_BAND;
+
+	buffer[4] = 0;
+
+	if (priv->ctrl.deemph_75)
+		buffer[4] |= TEA5767_DEEMPH_75;
+
+	if (priv->ctrl.pllref)
+		buffer[4] |= TEA5767_PLLREF_ENABLE;
+
+
+	/* Rounds freq to next decimal value - for 62.5 KHz step */
+	/* frq = 20*(frq/16)+radio_frq[frq%16]; */
+
+	switch (priv->ctrl.xtal_freq) {
 	case TEA5767_HIGH_LO_13MHz:
 		tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n");
 		buffer[2] |= TEA5767_HIGH_LO_INJECT;
-		buffer[4] |= TEA5767_PLLREF_ENABLE;
 		div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
 		break;
 	case TEA5767_LOW_LO_13MHz:
 		tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n");
 
-		buffer[4] |= TEA5767_PLLREF_ENABLE;
 		div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
 		break;
 	case TEA5767_LOW_LO_32768:
@@ -256,7 +275,7 @@ static int set_radio_freq(struct dvb_frontend *fe,
 		if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5)))
 			tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
 		else
-			tea5767_status_dump(buffer);
+			tea5767_status_dump(priv, buffer);
 	}
 
 	priv->frequency = frq * 125 / 2;
@@ -382,7 +401,6 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
 		return EINVAL;
 	}
 
-	printk(KERN_WARNING "TEA5767 detected.\n");
 	return 0;
 }
 
@@ -398,6 +416,16 @@ static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 {
 	struct tea5767_priv *priv = fe->tuner_priv;
 	*frequency = priv->frequency;
+
+	return 0;
+}
+
+static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg)
+{
+	struct tea5767_priv *priv = fe->tuner_priv;
+
+	memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl));
+
 	return 0;
 }
 
@@ -407,6 +435,7 @@ static struct dvb_tuner_ops tea5767_tuner_ops = {
 	},
 
 	.set_analog_params = set_radio_freq,
+	.set_config	   = tea5767_set_config,
 	.sleep             = tea5767_standby,
 	.release           = tea5767_release,
 	.get_frequency     = tea5767_get_frequency,
@@ -425,8 +454,14 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
 		return NULL;
 	fe->tuner_priv = priv;
 
-	priv->i2c_props.addr = i2c_addr;
-	priv->i2c_props.adap = i2c_adap;
+	priv->i2c_props.addr  = i2c_addr;
+	priv->i2c_props.adap  = i2c_adap;
+	priv->ctrl.xtal_freq  = TEA5767_HIGH_LO_32768;
+	priv->ctrl.port1      = 1;
+	priv->ctrl.port2      = 1;
+	priv->ctrl.high_cut   = 1;
+	priv->ctrl.st_noise   = 1;
+	priv->ctrl.japan_band = 1;
 
 	memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops,
 	       sizeof(struct dvb_tuner_ops));
@@ -436,7 +471,6 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
 	return fe;
 }
 
-
 EXPORT_SYMBOL_GPL(tea5767_attach);
 EXPORT_SYMBOL_GPL(tea5767_autodetection);
 
diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h
index 5d78281adcc2..a44451f61145 100644
--- a/drivers/media/video/tea5767.h
+++ b/drivers/media/video/tea5767.h
@@ -20,6 +20,25 @@
 #include <linux/i2c.h>
 #include "dvb_frontend.h"
 
+enum tea5767_xtal {
+	TEA5767_LOW_LO_32768    = 0,
+	TEA5767_HIGH_LO_32768   = 1,
+	TEA5767_LOW_LO_13MHz    = 2,
+	TEA5767_HIGH_LO_13MHz   = 3,
+};
+
+struct tea5767_ctrl {
+	unsigned int		port1:1;
+	unsigned int		port2:1;
+	unsigned int		high_cut:1;
+	unsigned int		st_noise:1;
+	unsigned int		soft_mute:1;
+	unsigned int		japan_band:1;
+	unsigned int		deemph_75:1;
+	unsigned int		pllref:1;
+	enum tea5767_xtal	xtal_freq;
+};
+
 #if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE))
 extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
 
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
index 76b2e96429d9..dc7b9c220b90 100644
--- a/drivers/media/video/tlv320aic23b.c
+++ b/drivers/media/video/tlv320aic23b.c
@@ -31,6 +31,7 @@
 #include <linux/i2c-id.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("tlv320aic23b driver");
 MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
@@ -56,37 +57,35 @@ static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
 		return -1;
 	}
 
-	for (i = 0; i < 3; i++) {
-		if (i2c_smbus_write_byte_data(client, (reg << 1) |
-					(val >> 8), val & 0xff) == 0) {
+	for (i = 0; i < 3; i++)
+		if (i2c_smbus_write_byte_data(client,
+				(reg << 1) | (val >> 8), val & 0xff) == 0)
 			return 0;
-		}
-	}
 	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
 	return -1;
 }
 
-static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
-			  void *arg)
+static int tlv320aic23b_command(struct i2c_client *client,
+				unsigned int cmd, void *arg)
 {
 	struct tlv320aic23b_state *state = i2c_get_clientdata(client);
 	struct v4l2_control *ctrl = arg;
-	u32* freq = arg;
+	u32 *freq = arg;
 
 	switch (cmd) {
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
 		switch (*freq) {
-			case 32000: /* set sample rate to 32 kHz */
-				tlv320aic23b_write(client, 8, 0x018);
-				break;
-			case 44100: /* set sample rate to 44.1 kHz */
-				tlv320aic23b_write(client, 8, 0x022);
-				break;
-			case 48000: /* set sample rate to 48 kHz */
-				tlv320aic23b_write(client, 8, 0x000);
-				break;
-			default:
-				return -EINVAL;
+		case 32000: /* set sample rate to 32 kHz */
+			tlv320aic23b_write(client, 8, 0x018);
+			break;
+		case 44100: /* set sample rate to 44.1 kHz */
+			tlv320aic23b_write(client, 8, 0x022);
+			break;
+		case 48000: /* set sample rate to 48 kHz */
+			tlv320aic23b_write(client, 8, 0x000);
+			break;
+		default:
+			return -EINVAL;
 		}
 		break;
 
@@ -126,92 +125,53 @@ static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static struct i2c_driver i2c_driver;
-
-static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind)
+static int tlv320aic23b_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	struct tlv320aic23b_state *state;
 
 	/* Check if the adapter supports the needed features */
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == 0)
-		return -ENOMEM;
-
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver;
-	snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b");
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
 
-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
 
 	state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
-	if (state == NULL) {
-		kfree(client);
+	if (state == NULL)
 		return -ENOMEM;
-	}
 	state->muted = 0;
 	i2c_set_clientdata(client, state);
 
-	/* initialize tlv320aic23b */
-	tlv320aic23b_write(client, 15, 0x000);	/* RESET */
-	tlv320aic23b_write(client, 6, 0x00A);   /* turn off DAC & mic input */
-	tlv320aic23b_write(client, 7, 0x049);   /* left-justified, 24-bit, master mode */
-	tlv320aic23b_write(client, 0, 0x119);   /* set gain on both channels to +3.0 dB */
-	tlv320aic23b_write(client, 8, 0x000);   /* set sample rate to 48 kHz */
-	tlv320aic23b_write(client, 9, 0x001);   /* activate digital interface */
-
-	i2c_attach_client(client);
-
+	/* Initialize tlv320aic23b */
+
+	/* RESET */
+	tlv320aic23b_write(client, 15, 0x000);
+	/* turn off DAC & mic input */
+	tlv320aic23b_write(client, 6, 0x00A);
+	/* left-justified, 24-bit, master mode */
+	tlv320aic23b_write(client, 7, 0x049);
+	/* set gain on both channels to +3.0 dB */
+	tlv320aic23b_write(client, 0, 0x119);
+	/* set sample rate to 48 kHz */
+	tlv320aic23b_write(client, 8, 0x000);
+	/* activate digital interface */
+	tlv320aic23b_write(client, 9, 0x001);
 	return 0;
 }
 
-static int tlv320aic23b_probe(struct i2c_adapter *adapter)
+static int tlv320aic23b_remove(struct i2c_client *client)
 {
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, tlv320aic23b_attach);
-	return 0;
-}
-
-static int tlv320aic23b_detach(struct i2c_client *client)
-{
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err) {
-		return err;
-	}
-	kfree(client);
-
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-	.driver = {
-		.name = "tlv320aic23b",
-	},
-	.id             = I2C_DRIVERID_TLV320AIC23B,
-	.attach_adapter = tlv320aic23b_probe,
-	.detach_client  = tlv320aic23b_detach,
-	.command        = tlv320aic23b_command,
-};
-
 
-static int __init tlv320aic23b_init_module(void)
-{
-	return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit tlv320aic23b_cleanup_module(void)
-{
-	i2c_del_driver(&i2c_driver);
-}
-
-module_init(tlv320aic23b_init_module);
-module_exit(tlv320aic23b_cleanup_module);
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "tlv320aic23b",
+	.driverid = I2C_DRIVERID_TLV320AIC23B,
+	.command = tlv320aic23b_command,
+	.probe = tlv320aic23b_probe,
+	.remove = tlv320aic23b_remove,
+};
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 9e99f3636d3d..ba538f6fbcc3 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -19,15 +19,41 @@
 #include <media/tuner.h>
 #include <media/tuner-types.h>
 #include <media/v4l2-common.h>
-#include "tuner-driver.h"
+#include <media/v4l2-i2c-drv-legacy.h>
 #include "mt20xx.h"
 #include "tda8290.h"
 #include "tea5761.h"
 #include "tea5767.h"
+#include "tuner-xc2028.h"
 #include "tuner-simple.h"
+#include "tda9887.h"
+#include "xc5000.h"
 
 #define UNSET (-1U)
 
+#define PREFIX t->i2c->driver->driver.name
+
+struct tuner {
+	/* device */
+	struct dvb_frontend fe;
+	struct i2c_client   *i2c;
+	struct list_head    list;
+	unsigned int        using_v4l2:1;
+
+	/* keep track of the current settings */
+	v4l2_std_id         std;
+	unsigned int        tv_freq;
+	unsigned int        radio_freq;
+	unsigned int        audmode;
+
+	unsigned int        mode;
+	unsigned int        mode_mask; /* Combination of allowable modes */
+
+	unsigned int        type; /* chip type id */
+	unsigned int        config;
+	int (*tuner_callback) (void *dev, int command, int arg);
+};
+
 /* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
 #if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
@@ -47,7 +73,34 @@ static unsigned int no_autodetect = 0;
 static unsigned int show_i2c = 0;
 
 /* insmod options used at runtime => read/write */
-int tuner_debug = 0;
+static int tuner_debug;
+
+#define tuner_warn(fmt, arg...) do {			\
+	printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
+	       i2c_adapter_id(t->i2c->adapter),		\
+	       t->i2c->addr, ##arg);			\
+	 } while (0)
+
+#define tuner_info(fmt, arg...) do {			\
+	printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,	\
+	       i2c_adapter_id(t->i2c->adapter),		\
+	       t->i2c->addr, ##arg);			\
+	 } while (0)
+
+#define tuner_err(fmt, arg...) do {			\
+	printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX,	\
+	       i2c_adapter_id(t->i2c->adapter),		\
+	       t->i2c->addr, ##arg);			\
+	 } while (0)
+
+#define tuner_dbg(fmt, arg...) do {				\
+	if (tuner_debug)					\
+		printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,	\
+		       i2c_adapter_id(t->i2c->adapter),		\
+		       t->i2c->addr, ##arg);			\
+	 } while (0)
+
+/* ------------------------------------------------------------------------ */
 
 static unsigned int tv_range[2] = { 44, 958 };
 static unsigned int radio_range[2] = { 65, 108 };
@@ -71,66 +124,96 @@ MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
 MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
 MODULE_LICENSE("GPL");
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
 /* ---------------------------------------------------------------------- */
 
-static void fe_set_freq(struct tuner *t, unsigned int freq)
+static void fe_set_params(struct dvb_frontend *fe,
+			  struct analog_parameters *params)
 {
-	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-
-	struct analog_parameters params = {
-		.frequency = freq,
-		.mode      = t->mode,
-		.audmode   = t->audmode,
-		.std       = t->std
-	};
+	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
+	struct tuner *t = fe->analog_demod_priv;
 
 	if (NULL == fe_tuner_ops->set_analog_params) {
 		tuner_warn("Tuner frontend module has no way to set freq\n");
 		return;
 	}
-	fe_tuner_ops->set_analog_params(&t->fe, &params);
+	fe_tuner_ops->set_analog_params(fe, params);
 }
 
-static void fe_release(struct tuner *t)
+static void fe_release(struct dvb_frontend *fe)
 {
-	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
-
-	if (fe_tuner_ops->release)
-		fe_tuner_ops->release(&t->fe);
+	if (fe->ops.tuner_ops.release)
+		fe->ops.tuner_ops.release(fe);
+
+	/* DO NOT kfree(fe->analog_demod_priv)
+	 *
+	 * If we are in this function, analog_demod_priv contains a pointer
+	 * to struct tuner *t.  This will be kfree'd in tuner_detach().
+	 *
+	 * Otherwise, fe->ops.analog_demod_ops->release will
+	 * handle the cleanup for analog demodulator modules.
+	 */
+	fe->analog_demod_priv = NULL;
 }
 
-static void fe_standby(struct tuner *t)
+static void fe_standby(struct dvb_frontend *fe)
 {
-	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
 
 	if (fe_tuner_ops->sleep)
-		fe_tuner_ops->sleep(&t->fe);
+		fe_tuner_ops->sleep(fe);
 }
 
-static int fe_has_signal(struct tuner *t)
+static int fe_has_signal(struct dvb_frontend *fe)
 {
-	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
 	u16 strength = 0;
 
-	if (fe_tuner_ops->get_rf_strength)
-		fe_tuner_ops->get_rf_strength(&t->fe, &strength);
+	if (fe->ops.tuner_ops.get_rf_strength)
+		fe->ops.tuner_ops.get_rf_strength(fe, &strength);
 
 	return strength;
 }
 
+static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+	struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
+	struct tuner *t = fe->analog_demod_priv;
+
+	if (fe_tuner_ops->set_config)
+		return fe_tuner_ops->set_config(fe, priv_cfg);
+
+	tuner_warn("Tuner frontend module has no way to set config\n");
+
+	return 0;
+}
+
+static void tuner_status(struct dvb_frontend *fe);
+
+static struct analog_demod_ops tuner_core_ops = {
+	.set_params     = fe_set_params,
+	.standby        = fe_standby,
+	.release        = fe_release,
+	.has_signal     = fe_has_signal,
+	.set_config     = fe_set_config,
+	.tuner_status   = tuner_status
+};
+
 /* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
 	struct tuner *t = i2c_get_clientdata(c);
+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+	struct analog_parameters params = {
+		.mode      = t->mode,
+		.audmode   = t->audmode,
+		.std       = t->std
+	};
 
 	if (t->type == UNSET) {
 		tuner_warn ("tuner type not set\n");
 		return;
 	}
-	if (NULL == t->ops.set_tv_freq) {
+	if (NULL == analog_ops->set_params) {
 		tuner_warn ("Tuner has no way to set tv freq\n");
 		return;
 	}
@@ -145,18 +228,27 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 		else
 			freq = tv_range[1] * 16;
 	}
-	t->ops.set_tv_freq(t, freq);
+	params.frequency = freq;
+
+	analog_ops->set_params(&t->fe, &params);
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
 	struct tuner *t = i2c_get_clientdata(c);
+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+	struct analog_parameters params = {
+		.mode      = t->mode,
+		.audmode   = t->audmode,
+		.std       = t->std
+	};
 
 	if (t->type == UNSET) {
 		tuner_warn ("tuner type not set\n");
 		return;
 	}
-	if (NULL == t->ops.set_radio_freq) {
+	if (NULL == analog_ops->set_params) {
 		tuner_warn ("tuner has no way to set radio frequency\n");
 		return;
 	}
@@ -171,8 +263,9 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
 		else
 			freq = radio_range[1] * 16000;
 	}
+	params.frequency = freq;
 
-	t->ops.set_radio_freq(t, freq);
+	analog_ops->set_params(&t->fe, &params);
 }
 
 static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -193,54 +286,65 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
 		set_tv_freq(c, freq);
 		t->tv_freq = freq;
 		break;
+	default:
+		tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode);
 	}
 }
 
 static void tuner_i2c_address_check(struct tuner *t)
 {
 	if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
-	    ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f)))
+	    ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
+		return;
+
+	/* We already know that the XC5000 can only be located at
+	 * i2c address 0x61, 0x62, 0x63 or 0x64 */
+	if ((t->type == TUNER_XC5000) &&
+	    ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61))
 		return;
 
 	tuner_warn("====================== WARNING! ======================\n");
 	tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
 	tuner_warn("will soon be dropped. This message indicates that your\n");
 	tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
-		   t->i2c.name, t->i2c.addr);
+		   t->i2c->name, t->i2c->addr);
 	tuner_warn("To ensure continued support for your device, please\n");
 	tuner_warn("send a copy of this message, along with full dmesg\n");
 	tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
 	tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
 	tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
-		   t->i2c.adapter->name, t->i2c.addr, t->type,
+		   t->i2c->adapter->name, t->i2c->addr, t->type,
 		   tuners[t->type].name);
 	tuner_warn("====================== WARNING! ======================\n");
 }
 
-static void attach_tda8290(struct tuner *t)
-{
-	struct tda8290_config cfg = {
-		.lna_cfg        = &t->config,
-		.tuner_callback = t->tuner_callback
-	};
-	tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
-}
-
 static void attach_simple_tuner(struct tuner *t)
 {
 	struct simple_tuner_config cfg = {
 		.type = t->type,
 		.tun  = &tuners[t->type]
 	};
-	simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
+	simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
 }
 
+static void attach_tda829x(struct tuner *t)
+{
+	struct tda829x_config cfg = {
+		.lna_cfg        = &t->config,
+		.tuner_callback = t->tuner_callback,
+	};
+	tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
+}
+
+static struct xc5000_config xc5000_cfg;
+
 static void set_type(struct i2c_client *c, unsigned int type,
 		     unsigned int new_mode_mask, unsigned int new_config,
 		     int (*tuner_callback) (void *dev, int command,int arg))
 {
 	struct tuner *t = i2c_get_clientdata(c);
 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 	unsigned char buffer[4];
 
 	if (type == UNSET || type == TUNER_ABSENT) {
@@ -260,32 +364,27 @@ static void set_type(struct i2c_client *c, unsigned int type,
 		t->tuner_callback = tuner_callback;
 	}
 
-	/* This code detects calls by card attach_inform */
-	if (NULL == t->i2c.dev.driver) {
+	if (t->mode == T_UNINITIALIZED) {
 		tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
 
 		return;
 	}
 
 	/* discard private data, in case set_type() was previously called */
-	if (t->ops.release)
-		t->ops.release(t);
-	else {
-		kfree(t->priv);
-		t->priv = NULL;
-	}
+	if (analog_ops->release)
+		analog_ops->release(&t->fe);
 
 	switch (t->type) {
 	case TUNER_MT2032:
-		microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr);
+		microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
 		break;
 	case TUNER_PHILIPS_TDA8290:
 	{
-		attach_tda8290(t);
+		attach_tda829x(t);
 		break;
 	}
 	case TUNER_TEA5767:
-		if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
+		if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
 			t->type = TUNER_ABSENT;
 			t->mode_mask = T_UNINITIALIZED;
 			return;
@@ -293,7 +392,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
 		t->mode_mask = T_RADIO;
 		break;
 	case TUNER_TEA5761:
-		if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
+		if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) {
 			t->type = TUNER_ABSENT;
 			t->mode_mask = T_UNINITIALIZED;
 			return;
@@ -320,25 +419,60 @@ static void set_type(struct i2c_client *c, unsigned int type,
 		i2c_master_send(c,buffer,4);
 		attach_simple_tuner(t);
 		break;
+	case TUNER_XC2028:
+	{
+		struct xc2028_config cfg = {
+			.i2c_adap  = t->i2c->adapter,
+			.i2c_addr  = t->i2c->addr,
+			.video_dev = c->adapter->algo_data,
+			.callback  = t->tuner_callback,
+		};
+		if (!xc2028_attach(&t->fe, &cfg)) {
+			t->type = TUNER_ABSENT;
+			t->mode_mask = T_UNINITIALIZED;
+			return;
+		}
+		break;
+	}
 	case TUNER_TDA9887:
-		tda9887_tuner_init(t);
+		tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
+		break;
+	case TUNER_XC5000:
+		xc5000_cfg.i2c_address	  = t->i2c->addr;
+		xc5000_cfg.if_khz	  = 5380;
+		xc5000_cfg.priv           = c->adapter->algo_data;
+		xc5000_cfg.tuner_callback = t->tuner_callback;
+		if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) {
+			t->type = TUNER_ABSENT;
+			t->mode_mask = T_UNINITIALIZED;
+			return;
+		}
+		{
+		struct dvb_tuner_ops *xc_tuner_ops;
+		xc_tuner_ops = &t->fe.ops.tuner_ops;
+		if(xc_tuner_ops->init != NULL)
+			xc_tuner_ops->init(&t->fe);
+		}
 		break;
 	default:
 		attach_simple_tuner(t);
 		break;
 	}
 
-	if (fe_tuner_ops->set_analog_params) {
-		strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name));
+	if ((NULL == analog_ops->set_params) &&
+	    (fe_tuner_ops->set_analog_params)) {
+		strlcpy(t->i2c->name, fe_tuner_ops->info.name,
+			sizeof(t->i2c->name));
 
-		t->ops.set_tv_freq    = fe_set_freq;
-		t->ops.set_radio_freq = fe_set_freq;
-		t->ops.standby        = fe_standby;
-		t->ops.release        = fe_release;
-		t->ops.has_signal     = fe_has_signal;
+		t->fe.analog_demod_priv = t;
+		memcpy(analog_ops, &tuner_core_ops,
+		       sizeof(struct analog_demod_ops));
+	} else {
+		strlcpy(t->i2c->name, analog_ops->info.name,
+			sizeof(t->i2c->name));
 	}
 
-	tuner_info("type set to %s\n", t->i2c.name);
+	tuner_dbg("type set to %s\n", t->i2c->name);
 
 	if (t->mode_mask == T_UNINITIALIZED)
 		t->mode_mask = new_mode_mask;
@@ -508,10 +642,12 @@ static int tuner_fixup_std(struct tuner *t)
 	return 0;
 }
 
-static void tuner_status(struct tuner *t)
+static void tuner_status(struct dvb_frontend *fe)
 {
+	struct tuner *t = fe->analog_demod_priv;
 	unsigned long freq, freq_fraction;
 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 	const char *p;
 
 	switch (t->mode) {
@@ -541,172 +677,16 @@ static void tuner_status(struct tuner *t)
 		if (tuner_status & TUNER_STATUS_STEREO)
 			tuner_info("Stereo:          yes\n");
 	}
-	if (t->ops.has_signal) {
-		tuner_info("Signal strength: %d\n", t->ops.has_signal(t));
-	}
-	if (t->ops.is_stereo) {
-		tuner_info("Stereo:          %s\n", t->ops.is_stereo(t) ? "yes" : "no");
-	}
+	if (analog_ops->has_signal)
+		tuner_info("Signal strength: %d\n",
+			   analog_ops->has_signal(fe));
+	if (analog_ops->is_stereo)
+		tuner_info("Stereo:          %s\n",
+			   analog_ops->is_stereo(fe) ? "yes" : "no");
 }
 
 /* ---------------------------------------------------------------------- */
 
-/* static vars: used only in tuner_attach and tuner_probe */
-static unsigned default_mode_mask;
-
-/* During client attach, set_type is called by adapter's attach_inform callback.
-   set_type must then be completed by tuner_attach.
- */
-static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-	struct tuner *t;
-
-	client_template.adapter = adap;
-	client_template.addr = addr;
-
-	t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
-	if (NULL == t)
-		return -ENOMEM;
-	memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
-	i2c_set_clientdata(&t->i2c, t);
-	t->type = UNSET;
-	t->audmode = V4L2_TUNER_MODE_STEREO;
-	t->mode_mask = T_UNINITIALIZED;
-	t->ops.tuner_status = tuner_status;
-
-	if (show_i2c) {
-		unsigned char buffer[16];
-		int i,rc;
-
-		memset(buffer, 0, sizeof(buffer));
-		rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer));
-		tuner_info("I2C RECV = ");
-		for (i=0;i<rc;i++)
-			printk("%02x ",buffer[i]);
-		printk("\n");
-	}
-	/* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */
-	if (adap->id == I2C_HW_SAA7146 && addr < 0x4a)
-		return -ENODEV;
-
-	/* autodetection code based on the i2c addr */
-	if (!no_autodetect) {
-		switch (addr) {
-		case 0x10:
-			if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
-				t->type = TUNER_TEA5761;
-				t->mode_mask = T_RADIO;
-				t->mode = T_STANDBY;
-				t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
-				default_mode_mask &= ~T_RADIO;
-
-				goto register_client;
-			}
-			break;
-		case 0x42:
-		case 0x43:
-		case 0x4a:
-		case 0x4b:
-			/* If chip is not tda8290, don't register.
-			   since it can be tda9887*/
-			if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) {
-				tuner_dbg("chip at addr %x is a tda8290\n", addr);
-			} else {
-				/* Default is being tda9887 */
-				t->type = TUNER_TDA9887;
-				t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
-				t->mode = T_STANDBY;
-				goto register_client;
-			}
-			break;
-		case 0x60:
-			if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
-				t->type = TUNER_TEA5767;
-				t->mode_mask = T_RADIO;
-				t->mode = T_STANDBY;
-				t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
-				default_mode_mask &= ~T_RADIO;
-
-				goto register_client;
-			}
-			break;
-		}
-	}
-
-	/* Initializes only the first adapter found */
-	if (default_mode_mask != T_UNINITIALIZED) {
-		tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
-		t->mode_mask = default_mode_mask;
-		t->tv_freq = 400 * 16; /* Sets freq to VHF High */
-		t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
-		default_mode_mask = T_UNINITIALIZED;
-	}
-
-	/* Should be just before return */
-register_client:
-	tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
-	i2c_attach_client (&t->i2c);
-	set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback);
-	return 0;
-}
-
-static int tuner_probe(struct i2c_adapter *adap)
-{
-	if (0 != addr) {
-		normal_i2c[0] = addr;
-		normal_i2c[1] = I2C_CLIENT_END;
-	}
-
-	/* HACK: Ignore 0x6b and 0x6f on cx88 boards.
-	 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
-	 * and an RTC at 0x6f which can get corrupted if probed.
-	 */
-	if ((adap->id == I2C_HW_B_CX2388x) ||
-	    (adap->id == I2C_HW_B_CX23885)) {
-		unsigned int i = 0;
-
-		while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
-			i += 2;
-		if (i + 4 < I2C_CLIENT_MAX_OPTS) {
-			ignore[i+0] = adap->nr;
-			ignore[i+1] = 0x6b;
-			ignore[i+2] = adap->nr;
-			ignore[i+3] = 0x6f;
-			ignore[i+4] = I2C_CLIENT_END;
-		} else
-			printk(KERN_WARNING "tuner: "
-			       "too many options specified "
-			       "in i2c probe ignore list!\n");
-	}
-
-	default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
-
-	if (adap->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adap, &addr_data, tuner_attach);
-	return 0;
-}
-
-static int tuner_detach(struct i2c_client *client)
-{
-	struct tuner *t = i2c_get_clientdata(client);
-	int err;
-
-	err = i2c_detach_client(&t->i2c);
-	if (err) {
-		tuner_warn
-		    ("Client deregistration failed, client not detached.\n");
-		return err;
-	}
-
-	if (t->ops.release)
-		t->ops.release(t);
-	else {
-		kfree(t->priv);
-	}
-	kfree(t);
-	return 0;
-}
-
 /*
  * Switch tuner to other mode. If tuner support both tv and radio,
  * set another frequency to some value (This is needed for some pal
@@ -716,6 +696,8 @@ static int tuner_detach(struct i2c_client *client)
 
 static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
 {
+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
 	if (mode == t->mode)
 		return 0;
 
@@ -723,8 +705,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
 
 	if (check_mode(t, cmd) == EINVAL) {
 		t->mode = T_STANDBY;
-		if (t->ops.standby)
-			t->ops.standby(t);
+		if (analog_ops->standby)
+			analog_ops->standby(&t->fe);
 		return EINVAL;
 	}
 	return 0;
@@ -747,9 +729,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct tuner *t = i2c_get_clientdata(client);
 	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
 
 	if (tuner_debug>1)
-		v4l_i2c_print_ioctl(&(t->i2c),cmd);
+		v4l_i2c_print_ioctl(client,cmd);
 
 	switch (cmd) {
 	/* --- configuration --- */
@@ -773,8 +756,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 		if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
 			return 0;
 		t->mode = T_STANDBY;
-		if (t->ops.standby)
-			t->ops.standby(t);
+		if (analog_ops->standby)
+			analog_ops->standby(&t->fe);
 		break;
 #ifdef CONFIG_VIDEO_V4L1
 	case VIDIOCSAUDIO:
@@ -842,8 +825,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 					else
 						vt->flags &= ~VIDEO_TUNER_STEREO_ON;
 				} else {
-					if (t->ops.is_stereo) {
-						if (t->ops.is_stereo(t))
+					if (analog_ops->is_stereo) {
+						if (analog_ops->is_stereo(&t->fe))
 							vt->flags |=
 								VIDEO_TUNER_STEREO_ON;
 						else
@@ -851,8 +834,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 								~VIDEO_TUNER_STEREO_ON;
 					}
 				}
-				if (t->ops.has_signal)
-					vt->signal = t->ops.has_signal(t);
+				if (analog_ops->has_signal)
+					vt->signal =
+						analog_ops->has_signal(&t->fe);
 
 				vt->flags |= VIDEO_TUNER_LOW;	/* Allow freqs at 62.5 Hz */
 
@@ -882,21 +866,28 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 					fe_tuner_ops->get_status(&t->fe, &tuner_status);
 					va->mode = (tuner_status & TUNER_STATUS_STEREO)
 					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
-				} else if (t->ops.is_stereo)
-					va->mode = t->ops.is_stereo(t)
+				} else if (analog_ops->is_stereo)
+					va->mode = analog_ops->is_stereo(&t->fe)
 					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
 			}
 			return 0;
 		}
 #endif
-	case TDA9887_SET_CONFIG:
-		if (t->type == TUNER_TDA9887) {
-			int *i = arg;
+	case TUNER_SET_CONFIG:
+	{
+		struct v4l2_priv_tun_config *cfg = arg;
 
-			t->tda9887_config = *i;
-			set_freq(client, t->tv_freq);
+		if (t->type != cfg->tuner)
+			break;
+
+		if (analog_ops->set_config) {
+			analog_ops->set_config(&t->fe, cfg->priv);
+			break;
 		}
+
+		tuner_dbg("Tuner frontend module has no way to set config\n");
 		break;
+	}
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
 	   kernel pointer here... */
@@ -958,8 +949,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 			switch_v4l2();
 
 			tuner->type = t->mode;
-			if (t->ops.get_afc)
-				tuner->afc=t->ops.get_afc(t);
+			if (analog_ops->get_afc)
+				tuner->afc = analog_ops->get_afc(&t->fe);
 			if (t->mode == V4L2_TUNER_ANALOG_TV)
 				tuner->capability |= V4L2_TUNER_CAP_NORM;
 			if (t->mode != V4L2_TUNER_RADIO) {
@@ -975,16 +966,20 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 				u32 tuner_status;
 
 				fe_tuner_ops->get_status(&t->fe, &tuner_status);
-				tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ?
-					V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+				tuner->rxsubchans =
+					(tuner_status & TUNER_STATUS_STEREO) ?
+					V4L2_TUNER_SUB_STEREO :
+					V4L2_TUNER_SUB_MONO;
 			} else {
-				if (t->ops.is_stereo) {
-					tuner->rxsubchans = t->ops.is_stereo(t) ?
-						V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+				if (analog_ops->is_stereo) {
+					tuner->rxsubchans =
+						analog_ops->is_stereo(&t->fe) ?
+						V4L2_TUNER_SUB_STEREO :
+						V4L2_TUNER_SUB_MONO;
 				}
 			}
-			if (t->ops.has_signal)
-				tuner->signal = t->ops.has_signal(t);
+			if (analog_ops->has_signal)
+				tuner->signal = analog_ops->has_signal(&t->fe);
 			tuner->capability |=
 			    V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
 			tuner->audmode = t->audmode;
@@ -1009,8 +1004,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 			break;
 		}
 	case VIDIOC_LOG_STATUS:
-		if (t->ops.tuner_status)
-			t->ops.tuner_status(t);
+		if (analog_ops->tuner_status)
+			analog_ops->tuner_status(&t->fe);
 		break;
 	}
 
@@ -1019,18 +1014,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 
 static int tuner_suspend(struct i2c_client *c, pm_message_t state)
 {
-	struct tuner *t = i2c_get_clientdata (c);
+	struct tuner *t = i2c_get_clientdata(c);
 
-	tuner_dbg ("suspend\n");
+	tuner_dbg("suspend\n");
 	/* FIXME: power down ??? */
 	return 0;
 }
 
 static int tuner_resume(struct i2c_client *c)
 {
-	struct tuner *t = i2c_get_clientdata (c);
+	struct tuner *t = i2c_get_clientdata(c);
 
-	tuner_dbg ("resume\n");
+	tuner_dbg("resume\n");
 	if (V4L2_TUNER_RADIO == t->mode) {
 		if (t->radio_freq)
 			set_freq(c, t->radio_freq);
@@ -1041,36 +1036,227 @@ static int tuner_resume(struct i2c_client *c)
 	return 0;
 }
 
-/* ----------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
 
-static struct i2c_driver driver = {
-	.id = I2C_DRIVERID_TUNER,
-	.attach_adapter = tuner_probe,
-	.detach_client = tuner_detach,
-	.command = tuner_command,
-	.suspend = tuner_suspend,
-	.resume  = tuner_resume,
-	.driver = {
-		.name    = "tuner",
-	},
-};
-static struct i2c_client client_template = {
-	.name = "(tuner unset)",
-	.driver = &driver,
-};
+LIST_HEAD(tuner_list);
 
-static int __init tuner_init_module(void)
+/* Search for existing radio and/or TV tuners on the given I2C adapter.
+   Note that when this function is called from tuner_probe you can be
+   certain no other devices will be added/deleted at the same time, I2C
+   core protects against that. */
+static void tuner_lookup(struct i2c_adapter *adap,
+		struct tuner **radio, struct tuner **tv)
 {
-	return i2c_add_driver(&driver);
+	struct tuner *pos;
+
+	*radio = NULL;
+	*tv = NULL;
+
+	list_for_each_entry(pos, &tuner_list, list) {
+		int mode_mask;
+
+		if (pos->i2c->adapter != adap ||
+		    pos->i2c->driver->id != I2C_DRIVERID_TUNER)
+			continue;
+
+		mode_mask = pos->mode_mask & ~T_STANDBY;
+		if (*radio == NULL && mode_mask == T_RADIO)
+			*radio = pos;
+		/* Note: currently TDA9887 is the only demod-only
+		   device. If other devices appear then we need to
+		   make this test more general. */
+		else if (*tv == NULL && pos->type != TUNER_TDA9887 &&
+			 (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV)))
+			*tv = pos;
+	}
 }
 
-static void __exit tuner_cleanup_module(void)
+/* During client attach, set_type is called by adapter's attach_inform callback.
+   set_type must then be completed by tuner_probe.
+ */
+static int tuner_probe(struct i2c_client *client)
 {
-	i2c_del_driver(&driver);
+	struct tuner *t;
+	struct tuner *radio;
+	struct tuner *tv;
+
+	t = kzalloc(sizeof(struct tuner), GFP_KERNEL);
+	if (NULL == t)
+		return -ENOMEM;
+	t->i2c = client;
+	strlcpy(client->name, "(tuner unset)", sizeof(client->name));
+	i2c_set_clientdata(client, t);
+	t->type = UNSET;
+	t->audmode = V4L2_TUNER_MODE_STEREO;
+	t->mode_mask = T_UNINITIALIZED;
+
+	if (show_i2c) {
+		unsigned char buffer[16];
+		int i, rc;
+
+		memset(buffer, 0, sizeof(buffer));
+		rc = i2c_master_recv(client, buffer, sizeof(buffer));
+		tuner_info("I2C RECV = ");
+		for (i = 0; i < rc; i++)
+			printk(KERN_CONT "%02x ", buffer[i]);
+		printk("\n");
+	}
+	/* HACK: This test was added to avoid tuner to probe tda9840 and
+	   tea6415c on the MXB card */
+	if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
+		kfree(t);
+		return -ENODEV;
+	}
+
+	/* autodetection code based on the i2c addr */
+	if (!no_autodetect) {
+		switch (client->addr) {
+		case 0x10:
+			if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
+					!= EINVAL) {
+				t->type = TUNER_TEA5761;
+				t->mode_mask = T_RADIO;
+				t->mode = T_STANDBY;
+				/* Sets freq to FM range */
+				t->radio_freq = 87.5 * 16000;
+				tuner_lookup(t->i2c->adapter, &radio, &tv);
+				if (tv)
+					tv->mode_mask &= ~T_RADIO;
+
+				goto register_client;
+			}
+			break;
+		case 0x42:
+		case 0x43:
+		case 0x4a:
+		case 0x4b:
+			/* If chip is not tda8290, don't register.
+			   since it can be tda9887*/
+			if (tda829x_probe(t->i2c->adapter,
+					  t->i2c->addr) == 0) {
+				tuner_dbg("tda829x detected\n");
+			} else {
+				/* Default is being tda9887 */
+				t->type = TUNER_TDA9887;
+				t->mode_mask = T_RADIO | T_ANALOG_TV |
+					       T_DIGITAL_TV;
+				t->mode = T_STANDBY;
+				goto register_client;
+			}
+			break;
+		case 0x60:
+			if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
+					!= EINVAL) {
+				t->type = TUNER_TEA5767;
+				t->mode_mask = T_RADIO;
+				t->mode = T_STANDBY;
+				/* Sets freq to FM range */
+				t->radio_freq = 87.5 * 16000;
+				tuner_lookup(t->i2c->adapter, &radio, &tv);
+				if (tv)
+					tv->mode_mask &= ~T_RADIO;
+
+				goto register_client;
+			}
+			break;
+		}
+	}
+
+	/* Initializes only the first TV tuner on this adapter. Why only the
+	   first? Because there are some devices (notably the ones with TI
+	   tuners) that have more than one i2c address for the *same* device.
+	   Experience shows that, except for just one case, the first
+	   address is the right one. The exception is a Russian tuner
+	   (ACORP_Y878F). So, the desired behavior is just to enable the
+	   first found TV tuner. */
+	tuner_lookup(t->i2c->adapter, &radio, &tv);
+	if (tv == NULL) {
+		t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
+		if (radio == NULL)
+			t->mode_mask |= T_RADIO;
+		tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask);
+		t->tv_freq = 400 * 16; /* Sets freq to VHF High */
+		t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+	}
+
+	/* Should be just before return */
+register_client:
+	tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1,
+		       client->adapter->name);
+
+	/* Sets a default mode */
+	if (t->mode_mask & T_ANALOG_TV) {
+		t->mode = V4L2_TUNER_ANALOG_TV;
+	} else  if (t->mode_mask & T_RADIO) {
+		t->mode = V4L2_TUNER_RADIO;
+	} else {
+		t->mode = V4L2_TUNER_DIGITAL_TV;
+	}
+	set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback);
+	list_add_tail(&t->list, &tuner_list);
+	return 0;
+}
+
+static int tuner_legacy_probe(struct i2c_adapter *adap)
+{
+	if (0 != addr) {
+		normal_i2c[0] = addr;
+		normal_i2c[1] = I2C_CLIENT_END;
+	}
+
+	if ((adap->class & I2C_CLASS_TV_ANALOG) == 0)
+		return 0;
+
+	/* HACK: Ignore 0x6b and 0x6f on cx88 boards.
+	 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
+	 * and an RTC at 0x6f which can get corrupted if probed.
+	 */
+	if ((adap->id == I2C_HW_B_CX2388x) ||
+	    (adap->id == I2C_HW_B_CX23885)) {
+		unsigned int i = 0;
+
+		while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
+			i += 2;
+		if (i + 4 < I2C_CLIENT_MAX_OPTS) {
+			ignore[i+0] = adap->nr;
+			ignore[i+1] = 0x6b;
+			ignore[i+2] = adap->nr;
+			ignore[i+3] = 0x6f;
+			ignore[i+4] = I2C_CLIENT_END;
+		} else
+			printk(KERN_WARNING "tuner: "
+			       "too many options specified "
+			       "in i2c probe ignore list!\n");
+	}
+	return 1;
 }
 
-module_init(tuner_init_module);
-module_exit(tuner_cleanup_module);
+static int tuner_remove(struct i2c_client *client)
+{
+	struct tuner *t = i2c_get_clientdata(client);
+	struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+
+	if (analog_ops->release)
+		analog_ops->release(&t->fe);
+
+	list_del(&t->list);
+	kfree(t);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "tuner",
+	.driverid = I2C_DRIVERID_TUNER,
+	.command = tuner_command,
+	.probe = tuner_probe,
+	.remove = tuner_remove,
+	.suspend = tuner_suspend,
+	.resume = tuner_resume,
+	.legacy_probe = tuner_legacy_probe,
+};
+
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
deleted file mode 100644
index 28a10da76d12..000000000000
--- a/drivers/media/video/tuner-driver.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-    tuner-driver.h - interface for different tuners
-
-    Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
-    minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de)
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __TUNER_DRIVER_H__
-#define __TUNER_DRIVER_H__
-
-#include <linux/videodev2.h>
-#include <linux/i2c.h>
-#include "tuner-i2c.h"
-#include "dvb_frontend.h"
-
-extern unsigned const int tuner_count;
-
-struct tuner;
-
-struct tuner_operations {
-	void (*set_tv_freq)(struct tuner *t, unsigned int freq);
-	void (*set_radio_freq)(struct tuner *t, unsigned int freq);
-	int  (*has_signal)(struct tuner *t);
-	int  (*is_stereo)(struct tuner *t);
-	int  (*get_afc)(struct tuner *t);
-	void (*tuner_status)(struct tuner *t);
-	void (*standby)(struct tuner *t);
-	void (*release)(struct tuner *t);
-};
-
-struct tuner {
-	/* device */
-	struct i2c_client i2c;
-
-	unsigned int type;	/* chip type */
-
-	unsigned int mode;
-	unsigned int mode_mask;	/* Combination of allowable modes */
-
-	unsigned int tv_freq;	/* keep track of the current settings */
-	unsigned int radio_freq;
-	unsigned int audmode;
-	v4l2_std_id  std;
-
-	int          using_v4l2;
-	void *priv;
-
-	struct dvb_frontend fe;
-
-	/* used by tda9887 */
-	unsigned int       tda9887_config;
-
-	unsigned int config;
-	int (*tuner_callback) (void *dev, int command,int arg);
-
-	struct tuner_operations ops;
-};
-
-/* ------------------------------------------------------------------------ */
-
-extern int tda9887_tuner_init(struct tuner *t);
-
-/* ------------------------------------------------------------------------ */
-
-#define tuner_warn(fmt, arg...) do {\
-	printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_info(fmt, arg...) do {\
-	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_dbg(fmt, arg...) do {\
-	extern int tuner_debug; \
-	if (tuner_debug) \
-		printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
-			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-
-#endif /* __TUNER_DRIVER_H__ */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h
index 159019ec3373..de52e8ffd347 100644
--- a/drivers/media/video/tuner-i2c.h
+++ b/drivers/media/video/tuner-i2c.h
@@ -46,25 +46,42 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf,
 	return (ret == 1) ? len : ret;
 }
 
-#ifndef __TUNER_DRIVER_H__
-#define tuner_warn(fmt, arg...) do {\
-	printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \
-			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
-#define tuner_info(fmt, arg...) do {\
-	printk(KERN_INFO PREFIX "%d-%04x: " fmt, \
-			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
-#define tuner_dbg(fmt, arg...) do {\
-	if ((debug)) \
-		printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \
-			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
-#endif /* __TUNER_DRIVER_H__ */
+static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
+					   char *obuf, int olen,
+					   char *ibuf, int ilen)
+{
+	struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
+				    .buf = obuf, .len = olen },
+				  { .addr = props->addr, .flags = I2C_M_RD,
+				    .buf = ibuf, .len = ilen } };
+	int ret = i2c_transfer(props->adap, msg, 2);
 
-#endif /* __TUNER_I2C_H__ */
+	return (ret == 2) ? ilen : ret;
+}
 
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+#define tuner_warn(fmt, arg...) do {					\
+	printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX,			\
+			i2c_adapter_id(priv->i2c_props.adap),		\
+			priv->i2c_props.addr, ##arg);			\
+	 } while (0)
+
+#define tuner_info(fmt, arg...) do {					\
+	printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX,			\
+			i2c_adapter_id(priv->i2c_props.adap),		\
+			priv->i2c_props.addr , ##arg);			\
+	} while (0)
+
+#define tuner_err(fmt, arg...) do {					\
+	printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, 			\
+			i2c_adapter_id(priv->i2c_props.adap),		\
+			priv->i2c_props.addr , ##arg);			\
+	} while (0)
+
+#define tuner_dbg(fmt, arg...) do {					\
+	if ((debug))							\
+		printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX,		\
+			i2c_adapter_id(priv->i2c_props.adap),		\
+			priv->i2c_props.addr , ##arg);			\
+	} while (0)
+
+#endif /* __TUNER_I2C_H__ */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 7b93d3b1f4c6..c1db576696c6 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -17,7 +17,7 @@ static int debug = 0;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-#define PREFIX "tuner-simple "
+#define PREFIX "tuner-simple"
 
 static int offset = 0;
 module_param(offset, int, 0664);
@@ -355,10 +355,14 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
 	}
 	priv->last_div = div;
 	if (t_params->has_tda9887) {
+		struct v4l2_priv_tun_config tda9887_cfg;
 		int config = 0;
 		int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
 			!(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
 
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv  = &config;
+
 		if (params->std == V4L2_STD_SECAM_LC) {
 			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
 				config |= TDA9887_PORT1_ACTIVE;
@@ -391,7 +395,8 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
 		}
 		if (t_params->default_pll_gating_18)
 			config |= TDA9887_GATING_18;
-		i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
+		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
+				    &tda9887_cfg);
 	}
 	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
 		  buffer[0],buffer[1],buffer[2],buffer[3]);
@@ -534,6 +539,11 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
 
 	if (t_params->has_tda9887) {
 		int config = 0;
+		struct v4l2_priv_tun_config tda9887_cfg;
+
+		tda9887_cfg.tuner = TUNER_TDA9887;
+		tda9887_cfg.priv = &config;
+
 		if (t_params->port1_active && !t_params->port1_fm_high_sensitivity)
 			config |= TDA9887_PORT1_ACTIVE;
 		if (t_params->port2_active && !t_params->port2_fm_high_sensitivity)
@@ -546,7 +556,8 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
 			config |= TDA9887_GAIN_NORMAL;
 		if (t_params->radio_if == 2)
 			config |= TDA9887_RIF_41_3;
-		i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
+		i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
+					&tda9887_cfg);
 	}
 	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
 		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index c6a7934bd5a6..883047f9c28c 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -1366,7 +1366,7 @@ struct tunertype tuners[] = {
 		.count  = ARRAY_SIZE(tuner_philips_fq1286_params),
 	},
 	[TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */
-		.name   = "tda8290+75",
+		.name   = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271",
 		/* see tda8290.c for details */ },
 	[TUNER_TCL_2002MB] = { /* TCL PAL */
 		.name   = "TCL 2002MB",
@@ -1452,9 +1452,9 @@ struct tunertype tuners[] = {
 		.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_XC2028] = { /* Xceive 2028 */
+		.name   = "Xceive xc2028/xc3028 tuner",
+		/* see tuner-xc2028.c for details */
 	},
 	[TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */
 		.name   = "Thomson FE6600",
@@ -1475,6 +1475,10 @@ struct tunertype tuners[] = {
 		.name   = "Philips TEA5761 FM Radio",
 		/* see tea5767.c for details */
 	},
+	[TUNER_XC5000] = { /* Xceive 5000 */
+		.name   = "Xceive 5000 tuner",
+		/* see xc5000.c for details */
+	},
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h
new file mode 100644
index 000000000000..d0057fbf0ec7
--- /dev/null
+++ b/drivers/media/video/tuner-xc2028-types.h
@@ -0,0 +1,128 @@
+/* tuner-xc2028_types
+ *
+ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+/* xc3028 firmware types */
+
+/* BASE firmware should be loaded before any other firmware */
+#define BASE		(1<<0)
+#define BASE_TYPES	(BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1)
+
+/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */
+#define F8MHZ		(1<<1)
+
+/* Multichannel Television Sound (MTS)
+   Those firmwares are capable of using xc2038 DSP to decode audio and
+   produce a baseband audio output on some pins of the chip.
+   There are MTS firmwares for the most used video standards. It should be
+   required to use MTS firmwares, depending on the way audio is routed into
+   the bridge chip
+ */
+#define MTS		(1<<2)
+
+/* FIXME: I have no idea what's the difference between
+   D2620 and D2633 firmwares
+ */
+#define D2620		(1<<3)
+#define D2633		(1<<4)
+
+/* DTV firmwares for 6, 7 and 8 MHz
+   DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS
+   DTV8 - 8MHz - DVB-C/DVB-T
+ */
+#define DTV6           (1 << 5)
+#define QAM            (1 << 6)
+#define DTV7		(1<<7)
+#define DTV78		(1<<8)
+#define DTV8		(1<<9)
+
+#define DTV_TYPES	(D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC)
+
+/* There's a FM | BASE firmware + FM specific firmware (std=0) */
+#define	FM		(1<<10)
+
+#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD)
+
+/* Applies only for FM firmware
+   Makes it use RF input 1 (pin #2) instead of input 2 (pin #4)
+ */
+#define INPUT1		(1<<11)
+
+
+/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
+	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
+	There are variants both with and without NOGD
+ */
+#define LCD		(1<<12)
+
+/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
+	and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
+ */
+#define NOGD		(1<<13)
+
+/* Old firmwares were broken into init0 and init1 */
+#define INIT1		(1<<14)
+
+/* SCODE firmware selects particular behaviours */
+#define MONO           (1 << 15)
+#define ATSC           (1 << 16)
+#define IF             (1 << 17)
+#define LG60           (1 << 18)
+#define ATI638         (1 << 19)
+#define OREN538        (1 << 20)
+#define OREN36         (1 << 21)
+#define TOYOTA388      (1 << 22)
+#define TOYOTA794      (1 << 23)
+#define DIBCOM52       (1 << 24)
+#define ZARLINK456     (1 << 25)
+#define CHINA          (1 << 26)
+#define F6MHZ          (1 << 27)
+#define INPUT2         (1 << 28)
+#define SCODE          (1 << 29)
+
+/* This flag identifies that the scode table has a new format */
+#define HAS_IF         (1 << 30)
+
+#define SCODE_TYPES	(MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \
+			 LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794|     \
+			 DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE)
+
+/* Newer types to be moved to videodev2.h */
+
+#define V4L2_STD_SECAM_K3	(0x04000000)
+
+/* Audio types */
+
+#define V4L2_STD_A2_A		(1LL<<32)
+#define V4L2_STD_A2_B		(1LL<<33)
+#define V4L2_STD_NICAM_A	(1LL<<34)
+#define V4L2_STD_NICAM_B	(1LL<<35)
+#define V4L2_STD_AM		(1LL<<36)
+#define V4L2_STD_BTSC		(1LL<<37)
+#define V4L2_STD_EIAJ		(1LL<<38)
+
+#define V4L2_STD_A2		(V4L2_STD_A2_A    | V4L2_STD_A2_B)
+#define V4L2_STD_NICAM		(V4L2_STD_NICAM_A | V4L2_STD_NICAM_B)
+
+/* To preserve backward compatibilty,
+   (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported
+ */
+
+#define V4L2_STD_AUDIO		(V4L2_STD_A2    | \
+				 V4L2_STD_NICAM | \
+				 V4L2_STD_AM    | \
+				 V4L2_STD_BTSC  | \
+				 V4L2_STD_EIAJ)
+
+/* Used standards with audio restrictions */
+
+#define V4L2_STD_PAL_BG_A2_A	(V4L2_STD_PAL_BG | V4L2_STD_A2_A)
+#define V4L2_STD_PAL_BG_A2_B	(V4L2_STD_PAL_BG | V4L2_STD_A2_B)
+#define V4L2_STD_PAL_BG_NICAM_A	(V4L2_STD_PAL_BG | V4L2_STD_NICAM_A)
+#define V4L2_STD_PAL_BG_NICAM_B	(V4L2_STD_PAL_BG | V4L2_STD_NICAM_B)
+#define V4L2_STD_PAL_DK_A2	(V4L2_STD_PAL_DK | V4L2_STD_A2)
+#define V4L2_STD_PAL_DK_NICAM	(V4L2_STD_PAL_DK | V4L2_STD_NICAM)
+#define V4L2_STD_SECAM_L_NICAM	(V4L2_STD_SECAM_L | V4L2_STD_NICAM)
+#define V4L2_STD_SECAM_L_AM	(V4L2_STD_SECAM_L | V4L2_STD_AM)
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
new file mode 100644
index 000000000000..f191f6a48070
--- /dev/null
+++ b/drivers/media/video/tuner-xc2028.c
@@ -0,0 +1,1213 @@
+/* tuner-xc2028
+ *
+ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ *
+ * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
+ *       - frontend interface
+ *
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#include <linux/i2c.h>
+#include <asm/div64.h>
+#include <linux/firmware.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#include <linux/mutex.h>
+#include "tuner-i2c.h"
+#include "tuner-xc2028.h"
+#include "tuner-xc2028-types.h"
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+
+#define PREFIX "xc2028"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static char audio_std[8];
+module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
+MODULE_PARM_DESC(audio_std,
+	"Audio standard. XC3028 audio decoder explicitly "
+	"needs to know what audio\n"
+	"standard is needed for some video standards with audio A2 or NICAM.\n"
+	"The valid values are:\n"
+	"A2\n"
+	"A2/A\n"
+	"A2/B\n"
+	"NICAM\n"
+	"NICAM/A\n"
+	"NICAM/B\n");
+
+static LIST_HEAD(xc2028_list);
+static DEFINE_MUTEX(xc2028_list_mutex);
+
+/* struct for storing firmware table */
+struct firmware_description {
+	unsigned int  type;
+	v4l2_std_id   id;
+	__u16         int_freq;
+	unsigned char *ptr;
+	unsigned int  size;
+};
+
+struct firmware_properties {
+	unsigned int	type;
+	v4l2_std_id	id;
+	v4l2_std_id	std_req;
+	__u16		int_freq;
+	unsigned int	scode_table;
+	int 		scode_nr;
+};
+
+struct xc2028_data {
+	struct list_head        xc2028_list;
+	struct tuner_i2c_props  i2c_props;
+	int                     (*tuner_callback) (void *dev,
+						   int command, int arg);
+	void			*video_dev;
+	int			count;
+	__u32			frequency;
+
+	struct firmware_description *firm;
+	int			firm_size;
+	__u16			firm_version;
+
+	__u16			hwmodel;
+	__u16			hwvers;
+
+	struct xc2028_ctrl	ctrl;
+
+	struct firmware_properties cur_fw;
+
+	struct mutex lock;
+};
+
+#define i2c_send(priv, buf, size) ({					\
+	int _rc;							\
+	_rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size);		\
+	if (size != _rc)						\
+		tuner_info("i2c output error: rc = %d (should be %d)\n",\
+			   _rc, (int)size);				\
+	_rc;								\
+})
+
+#define i2c_rcv(priv, buf, size) ({					\
+	int _rc;							\
+	_rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size);		\
+	if (size != _rc)						\
+		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
+			   _rc, (int)size); 				\
+	_rc;								\
+})
+
+#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({		\
+	int _rc;							\
+	_rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,	\
+				       ibuf, isize);			\
+	if (isize != _rc)						\
+		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
+			   _rc, (int)isize); 				\
+	_rc;								\
+})
+
+#define send_seq(priv, data...)	({					\
+	static u8 _val[] = data;					\
+	int _rc;							\
+	if (sizeof(_val) !=						\
+			(_rc = tuner_i2c_xfer_send(&priv->i2c_props,	\
+						_val, sizeof(_val)))) {	\
+		tuner_err("Error on line %d: %d\n", __LINE__, _rc);	\
+	} else 								\
+		msleep(10);						\
+	_rc;								\
+})
+
+static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
+{
+	unsigned char buf[2];
+	unsigned char ibuf[2];
+
+	tuner_dbg("%s %04x called\n", __FUNCTION__, reg);
+
+	buf[0] = reg >> 8;
+	buf[1] = (unsigned char) reg;
+
+	if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
+		return -EIO;
+
+	*val = (ibuf[1]) | (ibuf[0] << 8);
+	return 0;
+}
+
+#define dump_firm_type(t) 	dump_firm_type_and_int_freq(t, 0)
+void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+{
+	 if (type & BASE)
+		printk("BASE ");
+	 if (type & INIT1)
+		printk("INIT1 ");
+	 if (type & F8MHZ)
+		printk("F8MHZ ");
+	 if (type & MTS)
+		printk("MTS ");
+	 if (type & D2620)
+		printk("D2620 ");
+	 if (type & D2633)
+		printk("D2633 ");
+	 if (type & DTV6)
+		printk("DTV6 ");
+	 if (type & QAM)
+		printk("QAM ");
+	 if (type & DTV7)
+		printk("DTV7 ");
+	 if (type & DTV78)
+		printk("DTV78 ");
+	 if (type & DTV8)
+		printk("DTV8 ");
+	 if (type & FM)
+		printk("FM ");
+	 if (type & INPUT1)
+		printk("INPUT1 ");
+	 if (type & LCD)
+		printk("LCD ");
+	 if (type & NOGD)
+		printk("NOGD ");
+	 if (type & MONO)
+		printk("MONO ");
+	 if (type & ATSC)
+		printk("ATSC ");
+	 if (type & IF)
+		printk("IF ");
+	 if (type & LG60)
+		printk("LG60 ");
+	 if (type & ATI638)
+		printk("ATI638 ");
+	 if (type & OREN538)
+		printk("OREN538 ");
+	 if (type & OREN36)
+		printk("OREN36 ");
+	 if (type & TOYOTA388)
+		printk("TOYOTA388 ");
+	 if (type & TOYOTA794)
+		printk("TOYOTA794 ");
+	 if (type & DIBCOM52)
+		printk("DIBCOM52 ");
+	 if (type & ZARLINK456)
+		printk("ZARLINK456 ");
+	 if (type & CHINA)
+		printk("CHINA ");
+	 if (type & F6MHZ)
+		printk("F6MHZ ");
+	 if (type & INPUT2)
+		printk("INPUT2 ");
+	 if (type & SCODE)
+		printk("SCODE ");
+	 if (type & HAS_IF)
+		printk("HAS_IF_%d ", int_freq);
+}
+
+static  v4l2_std_id parse_audio_std_option(void)
+{
+	if (strcasecmp(audio_std, "A2") == 0)
+		return V4L2_STD_A2;
+	if (strcasecmp(audio_std, "A2/A") == 0)
+		return V4L2_STD_A2_A;
+	if (strcasecmp(audio_std, "A2/B") == 0)
+		return V4L2_STD_A2_B;
+	if (strcasecmp(audio_std, "NICAM") == 0)
+		return V4L2_STD_NICAM;
+	if (strcasecmp(audio_std, "NICAM/A") == 0)
+		return V4L2_STD_NICAM_A;
+	if (strcasecmp(audio_std, "NICAM/B") == 0)
+		return V4L2_STD_NICAM_B;
+
+	return 0;
+}
+
+static void free_firmware(struct xc2028_data *priv)
+{
+	int i;
+
+	if (!priv->firm)
+		return;
+
+	for (i = 0; i < priv->firm_size; i++)
+		kfree(priv->firm[i].ptr);
+
+	kfree(priv->firm);
+
+	priv->firm = NULL;
+	priv->firm_size = 0;
+
+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+}
+
+static int load_all_firmwares(struct dvb_frontend *fe)
+{
+	struct xc2028_data    *priv = fe->tuner_priv;
+	const struct firmware *fw   = NULL;
+	unsigned char         *p, *endp;
+	int                   rc = 0;
+	int		      n, n_array;
+	char		      name[33];
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	tuner_dbg("Reading firmware %s\n", priv->ctrl.fname);
+	rc = request_firmware(&fw, priv->ctrl.fname,
+			      &priv->i2c_props.adap->dev);
+	if (rc < 0) {
+		if (rc == -ENOENT)
+			tuner_err("Error: firmware %s not found.\n",
+				   priv->ctrl.fname);
+		else
+			tuner_err("Error %d while requesting firmware %s \n",
+				   rc, priv->ctrl.fname);
+
+		return rc;
+	}
+	p = fw->data;
+	endp = p + fw->size;
+
+	if (fw->size < sizeof(name) - 1 + 2 + 2) {
+		tuner_err("Error: firmware file %s has invalid size!\n",
+			  priv->ctrl.fname);
+		goto corrupt;
+	}
+
+	memcpy(name, p, sizeof(name) - 1);
+	name[sizeof(name) - 1] = 0;
+	p += sizeof(name) - 1;
+
+	priv->firm_version = le16_to_cpu(*(__u16 *) p);
+	p += 2;
+
+	n_array = le16_to_cpu(*(__u16 *) p);
+	p += 2;
+
+	tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
+		   n_array, priv->ctrl.fname, name,
+		   priv->firm_version >> 8, priv->firm_version & 0xff);
+
+	priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
+	if (priv->firm == NULL) {
+		tuner_err("Not enough memory to load firmware file.\n");
+		rc = -ENOMEM;
+		goto err;
+	}
+	priv->firm_size = n_array;
+
+	n = -1;
+	while (p < endp) {
+		__u32 type, size;
+		v4l2_std_id id;
+		__u16 int_freq = 0;
+
+		n++;
+		if (n >= n_array) {
+			tuner_err("More firmware images in file than "
+				  "were expected!\n");
+			goto corrupt;
+		}
+
+		/* Checks if there's enough bytes to read */
+		if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) {
+			tuner_err("Firmware header is incomplete!\n");
+			goto corrupt;
+		}
+
+		type = le32_to_cpu(*(__u32 *) p);
+		p += sizeof(type);
+
+		id = le64_to_cpu(*(v4l2_std_id *) p);
+		p += sizeof(id);
+
+		if (type & HAS_IF) {
+			int_freq = le16_to_cpu(*(__u16 *) p);
+			p += sizeof(int_freq);
+		}
+
+		size = le32_to_cpu(*(__u32 *) p);
+		p += sizeof(size);
+
+		if ((!size) || (size + p > endp)) {
+			tuner_err("Firmware type ");
+			dump_firm_type(type);
+			printk("(%x), id %llx is corrupted "
+			       "(size=%d, expected %d)\n",
+			       type, (unsigned long long)id,
+			       (unsigned)(endp - p), size);
+			goto corrupt;
+		}
+
+		priv->firm[n].ptr = kzalloc(size, GFP_KERNEL);
+		if (priv->firm[n].ptr == NULL) {
+			tuner_err("Not enough memory to load firmware file.\n");
+			rc = -ENOMEM;
+			goto err;
+		}
+		tuner_dbg("Reading firmware type ");
+		if (debug) {
+			dump_firm_type_and_int_freq(type, int_freq);
+			printk("(%x), id %llx, size=%d.\n",
+			       type, (unsigned long long)id, size);
+		}
+
+		memcpy(priv->firm[n].ptr, p, size);
+		priv->firm[n].type = type;
+		priv->firm[n].id   = id;
+		priv->firm[n].size = size;
+		priv->firm[n].int_freq = int_freq;
+
+		p += size;
+	}
+
+	if (n + 1 != priv->firm_size) {
+		tuner_err("Firmware file is incomplete!\n");
+		goto corrupt;
+	}
+
+	goto done;
+
+corrupt:
+	rc = -EINVAL;
+	tuner_err("Error: firmware file is corrupted!\n");
+
+err:
+	tuner_info("Releasing partially loaded firmware file.\n");
+	free_firmware(priv);
+
+done:
+	release_firmware(fw);
+	if (rc == 0)
+		tuner_dbg("Firmware files loaded.\n");
+
+	return rc;
+}
+
+static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
+			 v4l2_std_id *id)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int                 i, best_i = -1, best_nr_matches = 0;
+	unsigned int        ign_firm_type_mask = 0;
+
+	tuner_dbg("%s called, want type=", __FUNCTION__);
+	if (debug) {
+		dump_firm_type(type);
+		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
+	}
+
+	if (!priv->firm) {
+		tuner_err("Error! firmware not loaded\n");
+		return -EINVAL;
+	}
+
+	if (((type & ~SCODE) == 0) && (*id == 0))
+		*id = V4L2_STD_PAL;
+
+	if (type & BASE)
+		type &= BASE_TYPES;
+	else if (type & SCODE) {
+		type &= SCODE_TYPES;
+		ign_firm_type_mask = HAS_IF;
+	} else if (type & DTV_TYPES)
+		type &= DTV_TYPES;
+	else if (type & STD_SPECIFIC_TYPES)
+		type &= STD_SPECIFIC_TYPES;
+
+	/* Seek for exact match */
+	for (i = 0; i < priv->firm_size; i++) {
+		if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) &&
+		    (*id == priv->firm[i].id))
+			goto found;
+	}
+
+	/* Seek for generic video standard match */
+	for (i = 0; i < priv->firm_size; i++) {
+		v4l2_std_id match_mask;
+		int nr_matches;
+
+		if (type != (priv->firm[i].type & ~ign_firm_type_mask))
+			continue;
+
+		match_mask = *id & priv->firm[i].id;
+		if (!match_mask)
+			continue;
+
+		if ((*id & match_mask) == *id)
+			goto found; /* Supports all the requested standards */
+
+		nr_matches = hweight64(match_mask);
+		if (nr_matches > best_nr_matches) {
+			best_nr_matches = nr_matches;
+			best_i = i;
+		}
+	}
+
+	if (best_nr_matches > 0) {
+		tuner_dbg("Selecting best matching firmware (%d bits) for "
+			  "type=", best_nr_matches);
+		dump_firm_type(type);
+		printk("(%x), id %016llx:\n", type, (unsigned long long)*id);
+		i = best_i;
+		goto found;
+	}
+
+	/*FIXME: Would make sense to seek for type "hint" match ? */
+
+	i = -ENOENT;
+	goto ret;
+
+found:
+	*id = priv->firm[i].id;
+
+ret:
+	tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found");
+	if (debug) {
+		dump_firm_type(type);
+		printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
+	}
+	return i;
+}
+
+static int load_firmware(struct dvb_frontend *fe, unsigned int type,
+			 v4l2_std_id *id)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int                pos, rc;
+	unsigned char      *p, *endp, buf[priv->ctrl.max_len];
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	pos = seek_firmware(fe, type, id);
+	if (pos < 0)
+		return pos;
+
+	tuner_info("Loading firmware for type=");
+	dump_firm_type(priv->firm[pos].type);
+	printk("(%x), id %016llx.\n", priv->firm[pos].type,
+	       (unsigned long long)*id);
+
+	p = priv->firm[pos].ptr;
+	endp = p + priv->firm[pos].size;
+
+	while (p < endp) {
+		__u16 size;
+
+		/* Checks if there's enough bytes to read */
+		if (p + sizeof(size) > endp) {
+			tuner_err("Firmware chunk size is wrong\n");
+			return -EINVAL;
+		}
+
+		size = le16_to_cpu(*(__u16 *) p);
+		p += sizeof(size);
+
+		if (size == 0xffff)
+			return 0;
+
+		if (!size) {
+			/* Special callback command received */
+			rc = priv->tuner_callback(priv->video_dev,
+						  XC2028_TUNER_RESET, 0);
+			if (rc < 0) {
+				tuner_err("Error at RESET code %d\n",
+					   (*p) & 0x7f);
+				return -EINVAL;
+			}
+			continue;
+		}
+		if (size >= 0xff00) {
+			switch (size) {
+			case 0xff00:
+				rc = priv->tuner_callback(priv->video_dev,
+							XC2028_RESET_CLK, 0);
+				if (rc < 0) {
+					tuner_err("Error at RESET code %d\n",
+						  (*p) & 0x7f);
+					return -EINVAL;
+				}
+				break;
+			default:
+				tuner_info("Invalid RESET code %d\n",
+					   size & 0x7f);
+				return -EINVAL;
+
+			}
+			continue;
+		}
+
+		/* Checks for a sleep command */
+		if (size & 0x8000) {
+			msleep(size & 0x7fff);
+			continue;
+		}
+
+		if ((size + p > endp)) {
+			tuner_err("missing bytes: need %d, have %d\n",
+				   size, (int)(endp - p));
+			return -EINVAL;
+		}
+
+		buf[0] = *p;
+		p++;
+		size--;
+
+		/* Sends message chunks */
+		while (size > 0) {
+			int len = (size < priv->ctrl.max_len - 1) ?
+				   size : priv->ctrl.max_len - 1;
+
+			memcpy(buf + 1, p, len);
+
+			rc = i2c_send(priv, buf, len + 1);
+			if (rc < 0) {
+				tuner_err("%d returned from send\n", rc);
+				return -EINVAL;
+			}
+
+			p += len;
+			size -= len;
+		}
+	}
+	return 0;
+}
+
+static int load_scode(struct dvb_frontend *fe, unsigned int type,
+			 v4l2_std_id *id, __u16 int_freq, int scode)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int                pos, rc;
+	unsigned char	   *p;
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	if (!int_freq) {
+		pos = seek_firmware(fe, type, id);
+		if (pos < 0)
+			return pos;
+	} else {
+		for (pos = 0; pos < priv->firm_size; pos++) {
+			if ((priv->firm[pos].int_freq == int_freq) &&
+			    (priv->firm[pos].type & HAS_IF))
+				break;
+		}
+		if (pos == priv->firm_size)
+			return -ENOENT;
+	}
+
+	p = priv->firm[pos].ptr;
+
+	if (priv->firm[pos].type & HAS_IF) {
+		if (priv->firm[pos].size != 12 * 16 || scode >= 16)
+			return -EINVAL;
+		p += 12 * scode;
+	} else {
+		/* 16 SCODE entries per file; each SCODE entry is 12 bytes and
+		 * has a 2-byte size header in the firmware format. */
+		if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
+		    le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
+			return -EINVAL;
+		p += 14 * scode + 2;
+	}
+
+	tuner_info("Loading SCODE for type=");
+	dump_firm_type_and_int_freq(priv->firm[pos].type,
+				    priv->firm[pos].int_freq);
+	printk("(%x), id %016llx.\n", priv->firm[pos].type,
+	       (unsigned long long)*id);
+
+	if (priv->firm_version < 0x0202)
+		rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00});
+	else
+		rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
+	if (rc < 0)
+		return -EIO;
+
+	rc = i2c_send(priv, p, 12);
+	if (rc < 0)
+		return -EIO;
+
+	rc = send_seq(priv, {0x00, 0x8c});
+	if (rc < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int check_firmware(struct dvb_frontend *fe, unsigned int type,
+			  v4l2_std_id std, __u16 int_freq)
+{
+	struct xc2028_data         *priv = fe->tuner_priv;
+	struct firmware_properties new_fw;
+	int			   rc = 0, is_retry = 0;
+	u16			   version, hwmodel;
+	v4l2_std_id		   std0;
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	if (!priv->firm) {
+		if (!priv->ctrl.fname) {
+			tuner_info("xc2028/3028 firmware name not set!\n");
+			return -EINVAL;
+		}
+
+		rc = load_all_firmwares(fe);
+		if (rc < 0)
+			return rc;
+	}
+
+	if (priv->ctrl.mts && !(type & FM))
+		type |= MTS;
+
+retry:
+	new_fw.type = type;
+	new_fw.id = std;
+	new_fw.std_req = std;
+	new_fw.scode_table = SCODE | priv->ctrl.scode_table;
+	new_fw.scode_nr = 0;
+	new_fw.int_freq = int_freq;
+
+	tuner_dbg("checking firmware, user requested type=");
+	if (debug) {
+		dump_firm_type(new_fw.type);
+		printk("(%x), id %016llx, ", new_fw.type,
+		       (unsigned long long)new_fw.std_req);
+		if (!int_freq) {
+			printk("scode_tbl ");
+			dump_firm_type(priv->ctrl.scode_table);
+			printk("(%x), ", priv->ctrl.scode_table);
+		} else
+			printk("int_freq %d, ", new_fw.int_freq);
+		printk("scode_nr %d\n", new_fw.scode_nr);
+	}
+
+	/* No need to reload base firmware if it matches */
+	if (((BASE | new_fw.type) & BASE_TYPES) ==
+	    (priv->cur_fw.type & BASE_TYPES)) {
+		tuner_dbg("BASE firmware not changed.\n");
+		goto skip_base;
+	}
+
+	/* Updating BASE - forget about all currently loaded firmware */
+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+
+	/* Reset is needed before loading firmware */
+	rc = priv->tuner_callback(priv->video_dev,
+				  XC2028_TUNER_RESET, 0);
+	if (rc < 0)
+		goto fail;
+
+	/* BASE firmwares are all std0 */
+	std0 = 0;
+	rc = load_firmware(fe, BASE | new_fw.type, &std0);
+	if (rc < 0) {
+		tuner_err("Error %d while loading base firmware\n",
+			  rc);
+		goto fail;
+	}
+
+	/* Load INIT1, if needed */
+	tuner_dbg("Load init1 firmware, if exists\n");
+
+	rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
+	if (rc == -ENOENT)
+		rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
+				   &std0);
+	if (rc < 0 && rc != -ENOENT) {
+		tuner_err("Error %d while loading init1 firmware\n",
+			  rc);
+		goto fail;
+	}
+
+skip_base:
+	/*
+	 * No need to reload standard specific firmware if base firmware
+	 * was not reloaded and requested video standards have not changed.
+	 */
+	if (priv->cur_fw.type == (BASE | new_fw.type) &&
+	    priv->cur_fw.std_req == std) {
+		tuner_dbg("Std-specific firmware already loaded.\n");
+		goto skip_std_specific;
+	}
+
+	/* Reloading std-specific firmware forces a SCODE update */
+	priv->cur_fw.scode_table = 0;
+
+	rc = load_firmware(fe, new_fw.type, &new_fw.id);
+	if (rc == -ENOENT)
+		rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
+
+	if (rc < 0)
+		goto fail;
+
+skip_std_specific:
+	if (priv->cur_fw.scode_table == new_fw.scode_table &&
+	    priv->cur_fw.scode_nr == new_fw.scode_nr) {
+		tuner_dbg("SCODE firmware already loaded.\n");
+		goto check_device;
+	}
+
+	/* Load SCODE firmware, if exists */
+	tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
+
+	rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
+			new_fw.int_freq, new_fw.scode_nr);
+
+check_device:
+	if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
+	    xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
+		tuner_err("Unable to read tuner registers.\n");
+		goto fail;
+	}
+
+	tuner_info("Device is Xceive %d version %d.%d, "
+		   "firmware version %d.%d\n",
+		   hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
+		   (version & 0xf0) >> 4, version & 0xf);
+
+	/* Check firmware version against what we downloaded. */
+	if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
+		tuner_err("Incorrect readback of firmware version.\n");
+		goto fail;
+	}
+
+	/* Check that the tuner hardware model remains consistent over time. */
+	if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
+		priv->hwmodel = hwmodel;
+		priv->hwvers  = version & 0xff00;
+	} else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
+		   priv->hwvers != (version & 0xff00)) {
+		tuner_err("Read invalid device hardware information - tuner "
+			  "hung?\n");
+		goto fail;
+	}
+
+	memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
+
+	/*
+	 * By setting BASE in cur_fw.type only after successfully loading all
+	 * firmwares, we can:
+	 * 1. Identify that BASE firmware with type=0 has been loaded;
+	 * 2. Tell whether BASE firmware was just changed the next time through.
+	 */
+	priv->cur_fw.type |= BASE;
+
+	return 0;
+
+fail:
+	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
+	if (!is_retry) {
+		msleep(50);
+		is_retry = 1;
+		tuner_dbg("Retrying firmware load\n");
+		goto retry;
+	}
+
+	if (rc == -ENOENT)
+		rc = -EINVAL;
+	return rc;
+}
+
+static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	u16                 frq_lock, signal = 0;
+	int                 rc;
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	mutex_lock(&priv->lock);
+
+	/* Sync Lock Indicator */
+	rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
+	if (rc < 0 || frq_lock == 0)
+		goto ret;
+
+	/* Frequency is locked. Return signal quality */
+
+	/* Get SNR of the video signal */
+	rc = xc2028_get_reg(priv, 0x0040, &signal);
+	if (rc < 0)
+		signal = -frq_lock;
+
+ret:
+	mutex_unlock(&priv->lock);
+
+	*strength = signal;
+
+	return rc;
+}
+
+#define DIV 15625
+
+static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
+			    enum tuner_mode new_mode,
+			    unsigned int type,
+			    v4l2_std_id std,
+			    u16 int_freq)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int		   rc = -EINVAL;
+	unsigned char	   buf[4];
+	u32		   div, offset = 0;
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	mutex_lock(&priv->lock);
+
+	tuner_dbg("should set frequency %d kHz\n", freq / 1000);
+
+	if (check_firmware(fe, type, std, int_freq) < 0)
+		goto ret;
+
+	/* On some cases xc2028 can disable video output, if
+	 * very weak signals are received. By sending a soft
+	 * reset, this is re-enabled. So, it is better to always
+	 * send a soft reset before changing channels, to be sure
+	 * that xc2028 will be in a safe state.
+	 * Maybe this might also be needed for DTV.
+	 */
+	if (new_mode == T_ANALOG_TV) {
+		rc = send_seq(priv, {0x00, 0x00});
+	} else if (priv->cur_fw.type & ATSC) {
+		offset = 1750000;
+	} else {
+		offset = 2750000;
+		/*
+		 * We must adjust the offset by 500kHz in two cases in order
+		 * to correctly center the IF output:
+		 * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
+		 *    selected and a 7MHz channel is tuned;
+		 * 2) When tuning a VHF channel with DTV78 firmware.
+		 */
+		if (((priv->cur_fw.type & DTV7) &&
+		     (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
+		    ((priv->cur_fw.type & DTV78) && freq < 470000000))
+			offset -= 500000;
+	}
+
+	div = (freq - offset + DIV / 2) / DIV;
+
+	/* CMD= Set frequency */
+	if (priv->firm_version < 0x0202)
+		rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00});
+	else
+		rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00});
+	if (rc < 0)
+		goto ret;
+
+	rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
+	if (rc < 0)
+		goto ret;
+
+	msleep(10);
+
+	buf[0] = 0xff & (div >> 24);
+	buf[1] = 0xff & (div >> 16);
+	buf[2] = 0xff & (div >> 8);
+	buf[3] = 0xff & (div);
+
+	rc = i2c_send(priv, buf, sizeof(buf));
+	if (rc < 0)
+		goto ret;
+	msleep(100);
+
+	priv->frequency = freq;
+
+	tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n",
+	       buf[0], buf[1], buf[2], buf[3],
+	       freq / 1000000, (freq % 1000000) / 1000);
+
+	rc = 0;
+
+ret:
+	mutex_unlock(&priv->lock);
+
+	return rc;
+}
+
+static int xc2028_set_analog_freq(struct dvb_frontend *fe,
+			      struct analog_parameters *p)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	unsigned int       type=0;
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	if (p->mode == V4L2_TUNER_RADIO) {
+		type |= FM;
+		if (priv->ctrl.input1)
+			type |= INPUT1;
+		return generic_set_freq(fe, (625l * p->frequency) / 10,
+				T_ANALOG_TV, type, 0, 0);
+	}
+
+	/* if std is not defined, choose one */
+	if (!p->std)
+		p->std = V4L2_STD_MN;
+
+	/* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
+	if (!(p->std & V4L2_STD_MN))
+		type |= F8MHZ;
+
+	/* Add audio hack to std mask */
+	p->std |= parse_audio_std_option();
+
+	return generic_set_freq(fe, 62500l * p->frequency,
+				T_ANALOG_TV, type, p->std, 0);
+}
+
+static int xc2028_set_params(struct dvb_frontend *fe,
+			     struct dvb_frontend_parameters *p)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	unsigned int       type=0;
+	fe_bandwidth_t     bw = BANDWIDTH_8_MHZ;
+	u16                demod = 0;
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	if (priv->ctrl.d2633)
+		type |= D2633;
+	else
+		type |= D2620;
+
+	switch(fe->ops.info.type) {
+	case FE_OFDM:
+		bw = p->u.ofdm.bandwidth;
+		break;
+	case FE_QAM:
+		tuner_info("WARN: There are some reports that "
+			   "QAM 6 MHz doesn't work.\n"
+			   "If this works for you, please report by "
+			   "e-mail to: v4l-dvb-maintainer@linuxtv.org\n");
+		bw = BANDWIDTH_6_MHZ;
+		type |= QAM;
+		break;
+	case FE_ATSC:
+		bw = BANDWIDTH_6_MHZ;
+		/* The only ATSC firmware (at least on v2.7) is D2633,
+		   so overrides ctrl->d2633 */
+		type |= ATSC| D2633;
+		type &= ~D2620;
+		break;
+	/* DVB-S is not supported */
+	default:
+		return -EINVAL;
+	}
+
+	switch (bw) {
+	case BANDWIDTH_8_MHZ:
+		if (p->frequency < 470000000)
+			priv->ctrl.vhfbw7 = 0;
+		else
+			priv->ctrl.uhfbw8 = 1;
+		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
+		type |= F8MHZ;
+		break;
+	case BANDWIDTH_7_MHZ:
+		if (p->frequency < 470000000)
+			priv->ctrl.vhfbw7 = 1;
+		else
+			priv->ctrl.uhfbw8 = 0;
+		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
+		type |= F8MHZ;
+		break;
+	case BANDWIDTH_6_MHZ:
+		type |= DTV6;
+		priv->ctrl.vhfbw7 = 0;
+		priv->ctrl.uhfbw8 = 0;
+		break;
+	default:
+		tuner_err("error: bandwidth not supported.\n");
+	};
+
+	/* All S-code tables need a 200kHz shift */
+	if (priv->ctrl.demod)
+		demod = priv->ctrl.demod + 200;
+
+	return generic_set_freq(fe, p->frequency,
+				T_DIGITAL_TV, type, 0, demod);
+}
+
+static int xc2028_sleep(struct dvb_frontend *fe)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	int rc = 0;
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	mutex_lock(&priv->lock);
+
+	if (priv->firm_version < 0x0202)
+		rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
+	else
+		rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
+
+	priv->cur_fw.type = 0;	/* need firmware reload */
+
+	mutex_unlock(&priv->lock);
+
+	return rc;
+}
+
+
+static int xc2028_dvb_release(struct dvb_frontend *fe)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	mutex_lock(&xc2028_list_mutex);
+
+	priv->count--;
+
+	if (!priv->count) {
+		list_del(&priv->xc2028_list);
+
+		kfree(priv->ctrl.fname);
+
+		free_firmware(priv);
+		kfree(priv);
+		fe->tuner_priv = NULL;
+	}
+
+	mutex_unlock(&xc2028_list_mutex);
+
+	return 0;
+}
+
+static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	*frequency = priv->frequency;
+
+	return 0;
+}
+
+static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
+{
+	struct xc2028_data *priv = fe->tuner_priv;
+	struct xc2028_ctrl *p    = priv_cfg;
+	int                 rc   = 0;
+
+	tuner_dbg("%s called\n", __FUNCTION__);
+
+	mutex_lock(&priv->lock);
+
+	kfree(priv->ctrl.fname);
+	free_firmware(priv);
+
+	memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
+	priv->ctrl.fname = NULL;
+
+	if (p->fname) {
+		priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
+		if (priv->ctrl.fname == NULL)
+			rc = -ENOMEM;
+	}
+
+	if (priv->ctrl.max_len < 9)
+		priv->ctrl.max_len = 13;
+
+	mutex_unlock(&priv->lock);
+
+	return rc;
+}
+
+static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
+	.info = {
+		 .name = "Xceive XC3028",
+		 .frequency_min = 42000000,
+		 .frequency_max = 864000000,
+		 .frequency_step = 50000,
+		 },
+
+	.set_config	   = xc2028_set_config,
+	.set_analog_params = xc2028_set_analog_freq,
+	.release           = xc2028_dvb_release,
+	.get_frequency     = xc2028_get_frequency,
+	.get_rf_strength   = xc2028_signal,
+	.set_params        = xc2028_set_params,
+	.sleep             = xc2028_sleep,
+
+};
+
+struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
+				   struct xc2028_config *cfg)
+{
+	struct xc2028_data *priv;
+	void               *video_dev;
+
+	if (debug)
+		printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n");
+
+	if (NULL == cfg || NULL == cfg->video_dev)
+		return NULL;
+
+	if (!fe) {
+		printk(KERN_ERR PREFIX ": No frontend!\n");
+		return NULL;
+	}
+
+	video_dev = cfg->video_dev;
+
+	mutex_lock(&xc2028_list_mutex);
+
+	list_for_each_entry(priv, &xc2028_list, xc2028_list) {
+		if (priv->video_dev == cfg->video_dev) {
+			video_dev = NULL;
+			break;
+		}
+	}
+
+	if (video_dev) {
+		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+		if (priv == NULL) {
+			mutex_unlock(&xc2028_list_mutex);
+			return NULL;
+		}
+
+		priv->i2c_props.addr = cfg->i2c_addr;
+		priv->i2c_props.adap = cfg->i2c_adap;
+		priv->video_dev = video_dev;
+		priv->tuner_callback = cfg->callback;
+		priv->ctrl.max_len = 13;
+
+		mutex_init(&priv->lock);
+
+		list_add_tail(&priv->xc2028_list, &xc2028_list);
+	}
+
+	fe->tuner_priv = priv;
+	priv->count++;
+
+	memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
+	       sizeof(xc2028_dvb_tuner_ops));
+
+	tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
+
+	if (cfg->ctrl)
+		xc2028_set_config(fe, cfg->ctrl);
+
+	mutex_unlock(&xc2028_list_mutex);
+
+	return fe;
+}
+
+EXPORT_SYMBOL(xc2028_attach);
+
+MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
+MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h
new file mode 100644
index 000000000000..3eb8420379a4
--- /dev/null
+++ b/drivers/media/video/tuner-xc2028.h
@@ -0,0 +1,63 @@
+/* tuner-xc2028
+ *
+ * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNU General Public License v2
+ */
+
+#ifndef __TUNER_XC2028_H__
+#define __TUNER_XC2028_H__
+
+#include "dvb_frontend.h"
+
+#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
+
+/*      Dmoduler		IF (kHz) */
+#define	XC3028_FE_DEFAULT	0
+#define XC3028_FE_LG60		6000
+#define	XC3028_FE_ATI638	6380
+#define	XC3028_FE_OREN538	5380
+#define	XC3028_FE_OREN36	3600
+#define	XC3028_FE_TOYOTA388	3880
+#define	XC3028_FE_TOYOTA794	7940
+#define	XC3028_FE_DIBCOM52	5200
+#define	XC3028_FE_ZARLINK456	4560
+#define	XC3028_FE_CHINA		5200
+
+struct xc2028_ctrl {
+	char			*fname;
+	int			max_len;
+	unsigned int		scode_table;
+	unsigned int		mts   :1;
+	unsigned int		d2633 :1;
+	unsigned int		input1:1;
+	unsigned int		vhfbw7:1;
+	unsigned int		uhfbw8:1;
+	unsigned int		demod;
+};
+
+struct xc2028_config {
+	struct i2c_adapter *i2c_adap;
+	u8 		   i2c_addr;
+	void               *video_dev;
+	struct xc2028_ctrl *ctrl;
+	int                (*callback) (void *dev, int command, int arg);
+};
+
+/* xc2028 commands for callback */
+#define XC2028_TUNER_RESET	0
+#define XC2028_RESET_CLK	1
+
+#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE))
+extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
+					  struct xc2028_config *cfg);
+#else
+static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
+						 struct xc2028_config *cfg)
+{
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* __TUNER_XC2028_H__ */
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index a19cdcc17ef7..a75560540e79 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -31,6 +31,7 @@
 #include <media/tvaudio.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 #include <media/i2c-addr.h>
 
@@ -109,7 +110,7 @@ static struct CHIPDESC chiplist[];
 
 /* current state of the chip */
 struct CHIPSTATE {
-	struct i2c_client c;
+	struct i2c_client *c;
 
 	/* index into CHIPDESC array */
 	int type;
@@ -145,10 +146,6 @@ static unsigned short normal_i2c[] = {
 	I2C_CLIENT_END };
 I2C_CLIENT_INSMOD;
 
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
-
 /* ---------------------------------------------------------------------- */
 /* i2c I/O functions                                                      */
 
@@ -157,24 +154,24 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
 	unsigned char buffer[2];
 
 	if (-1 == subaddr) {
-		v4l_dbg(1, debug, &chip->c, "%s: chip_write: 0x%x\n",
-			chip->c.name, val);
+		v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n",
+			chip->c->name, val);
 		chip->shadow.bytes[1] = val;
 		buffer[0] = val;
-		if (1 != i2c_master_send(&chip->c,buffer,1)) {
-			v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n",
-				chip->c.name, val);
+		if (1 != i2c_master_send(chip->c,buffer,1)) {
+			v4l_warn(chip->c, "%s: I/O error (write 0x%x)\n",
+				chip->c->name, val);
 			return -1;
 		}
 	} else {
-		v4l_dbg(1, debug, &chip->c, "%s: chip_write: reg%d=0x%x\n",
-			chip->c.name, subaddr, val);
+		v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n",
+			chip->c->name, subaddr, val);
 		chip->shadow.bytes[subaddr+1] = val;
 		buffer[0] = subaddr;
 		buffer[1] = val;
-		if (2 != i2c_master_send(&chip->c,buffer,2)) {
-			v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n",
-			chip->c.name, subaddr, val);
+		if (2 != i2c_master_send(chip->c,buffer,2)) {
+			v4l_warn(chip->c, "%s: I/O error (write reg%d=0x%x)\n",
+			chip->c->name, subaddr, val);
 			return -1;
 		}
 	}
@@ -197,12 +194,12 @@ static int chip_read(struct CHIPSTATE *chip)
 {
 	unsigned char buffer;
 
-	if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
-		v4l_warn(&chip->c, "%s: I/O error (read)\n",
-		chip->c.name);
+	if (1 != i2c_master_recv(chip->c,&buffer,1)) {
+		v4l_warn(chip->c, "%s: I/O error (read)\n",
+		chip->c->name);
 		return -1;
 	}
-	v4l_dbg(1, debug, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer);
+	v4l_dbg(1, debug, chip->c, "%s: chip_read: 0x%x\n",chip->c->name, buffer);
 	return buffer;
 }
 
@@ -211,17 +208,17 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr)
 	unsigned char write[1];
 	unsigned char read[1];
 	struct i2c_msg msgs[2] = {
-		{ chip->c.addr, 0,        1, write },
-		{ chip->c.addr, I2C_M_RD, 1, read  }
+		{ chip->c->addr, 0,        1, write },
+		{ chip->c->addr, I2C_M_RD, 1, read  }
 	};
 	write[0] = subaddr;
 
-	if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
-		v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name);
+	if (2 != i2c_transfer(chip->c->adapter,msgs,2)) {
+		v4l_warn(chip->c, "%s: I/O error (read2)\n", chip->c->name);
 		return -1;
 	}
-	v4l_dbg(1, debug, &chip->c, "%s: chip_read2: reg%d=0x%x\n",
-		chip->c.name, subaddr,read[0]);
+	v4l_dbg(1, debug, chip->c, "%s: chip_read2: reg%d=0x%x\n",
+		chip->c->name, subaddr,read[0]);
 	return read[0];
 }
 
@@ -233,8 +230,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
 		return 0;
 
 	/* update our shadow register set; print bytes if (debug > 0) */
-	v4l_dbg(1, debug, &chip->c, "%s: chip_cmd(%s): reg=%d, data:",
-		chip->c.name, name,cmd->bytes[0]);
+	v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:",
+		chip->c->name, name,cmd->bytes[0]);
 	for (i = 1; i < cmd->count; i++) {
 		if (debug)
 			printk(" 0x%x",cmd->bytes[i]);
@@ -244,8 +241,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
 		printk("\n");
 
 	/* send data to the chip */
-	if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
-		v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name);
+	if (cmd->count != i2c_master_send(chip->c,cmd->bytes,cmd->count)) {
+		v4l_warn(chip->c, "%s: I/O error (%s)\n", chip->c->name, name);
 		return -1;
 	}
 	return 0;
@@ -269,7 +266,7 @@ static int chip_thread(void *data)
 	struct CHIPSTATE *chip = data;
 	struct CHIPDESC  *desc = chiplist + chip->type;
 
-	v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name);
+	v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name);
 	set_freezable();
 	for (;;) {
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -279,7 +276,7 @@ static int chip_thread(void *data)
 		try_to_freeze();
 		if (kthread_should_stop())
 			break;
-		v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name);
+		v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name);
 
 		/* don't do anything for radio or if mode != auto */
 		if (chip->radio || chip->mode != 0)
@@ -292,7 +289,7 @@ static int chip_thread(void *data)
 		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
 	}
 
-	v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
+	v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name);
 	return 0;
 }
 
@@ -304,17 +301,19 @@ static void generic_checkmode(struct CHIPSTATE *chip)
 	if (mode == chip->prevmode)
 	return;
 
-	v4l_dbg(1, debug, &chip->c, "%s: thread checkmode\n", chip->c.name);
+	v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name);
 	chip->prevmode = mode;
 
-	if (mode & VIDEO_SOUND_STEREO)
-		desc->setmode(chip,VIDEO_SOUND_STEREO);
-	else if (mode & VIDEO_SOUND_LANG1)
-		desc->setmode(chip,VIDEO_SOUND_LANG1);
-	else if (mode & VIDEO_SOUND_LANG2)
-		desc->setmode(chip,VIDEO_SOUND_LANG2);
+	if (mode & V4L2_TUNER_MODE_STEREO)
+		desc->setmode(chip,V4L2_TUNER_MODE_STEREO);
+	if (mode & V4L2_TUNER_MODE_LANG1_LANG2)
+		desc->setmode(chip,V4L2_TUNER_MODE_STEREO);
+	else if (mode & V4L2_TUNER_MODE_LANG1)
+		desc->setmode(chip,V4L2_TUNER_MODE_LANG1);
+	else if (mode & V4L2_TUNER_MODE_LANG2)
+		desc->setmode(chip,V4L2_TUNER_MODE_LANG2);
 	else
-		desc->setmode(chip,VIDEO_SOUND_MONO);
+		desc->setmode(chip,V4L2_TUNER_MODE_MONO);
 }
 
 /* ---------------------------------------------------------------------- */
@@ -345,13 +344,13 @@ static int tda9840_getmode(struct CHIPSTATE *chip)
 	int val, mode;
 
 	val = chip_read(chip);
-	mode = VIDEO_SOUND_MONO;
+	mode = V4L2_TUNER_MODE_MONO;
 	if (val & TDA9840_DS_DUAL)
-		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
 	if (val & TDA9840_ST_STEREO)
-		mode |= VIDEO_SOUND_STEREO;
+		mode |= V4L2_TUNER_MODE_STEREO;
 
-	v4l_dbg(1, debug, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
+	v4l_dbg(1, debug, chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n",
 		val, mode);
 	return mode;
 }
@@ -362,16 +361,16 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode)
 	int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e;
 
 	switch (mode) {
-	case VIDEO_SOUND_MONO:
+	case V4L2_TUNER_MODE_MONO:
 		t |= TDA9840_MONO;
 		break;
-	case VIDEO_SOUND_STEREO:
+	case V4L2_TUNER_MODE_STEREO:
 		t |= TDA9840_STEREO;
 		break;
-	case VIDEO_SOUND_LANG1:
+	case V4L2_TUNER_MODE_LANG1:
 		t |= TDA9840_DUALA;
 		break;
-	case VIDEO_SOUND_LANG2:
+	case V4L2_TUNER_MODE_LANG2:
 		t |= TDA9840_DUALB;
 		break;
 	default:
@@ -502,7 +501,7 @@ static int  tda985x_getmode(struct CHIPSTATE *chip)
 		chip_read(chip)) >> 4;
 	/* Add mono mode regardless of SAP and stereo */
 	/* Allows forced mono */
-	return mode | VIDEO_SOUND_MONO;
+	return mode | V4L2_TUNER_MODE_MONO;
 }
 
 static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
@@ -511,13 +510,13 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode)
 	int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f;
 
 	switch (mode) {
-	case VIDEO_SOUND_MONO:
+	case V4L2_TUNER_MODE_MONO:
 		c6 |= TDA985x_MONO;
 		break;
-	case VIDEO_SOUND_STEREO:
+	case V4L2_TUNER_MODE_STEREO:
 		c6 |= TDA985x_STEREO;
 		break;
-	case VIDEO_SOUND_LANG1:
+	case V4L2_TUNER_MODE_LANG1:
 		c6 |= TDA985x_SAP;
 		break;
 	default:
@@ -650,12 +649,12 @@ static int tda9873_getmode(struct CHIPSTATE *chip)
 	int val,mode;
 
 	val = chip_read(chip);
-	mode = VIDEO_SOUND_MONO;
+	mode = V4L2_TUNER_MODE_MONO;
 	if (val & TDA9873_STEREO)
-		mode |= VIDEO_SOUND_STEREO;
+		mode |= V4L2_TUNER_MODE_STEREO;
 	if (val & TDA9873_DUAL)
-		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
-	v4l_dbg(1, debug, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
+		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
+	v4l_dbg(1, debug, chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n",
 		val, mode);
 	return mode;
 }
@@ -666,24 +665,24 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
 	/*	int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
 
 	if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
-		v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): external input\n");
+		v4l_dbg(1, debug, chip->c, "tda9873_setmode(): external input\n");
 		return;
 	}
 
-	v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
-	v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
+	v4l_dbg(1, debug, chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]);
+	v4l_dbg(1, debug, chip->c, "tda9873_setmode(): sw_data  = %d\n", sw_data);
 
 	switch (mode) {
-	case VIDEO_SOUND_MONO:
+	case V4L2_TUNER_MODE_MONO:
 		sw_data |= TDA9873_TR_MONO;
 		break;
-	case VIDEO_SOUND_STEREO:
+	case V4L2_TUNER_MODE_STEREO:
 		sw_data |= TDA9873_TR_STEREO;
 		break;
-	case VIDEO_SOUND_LANG1:
+	case V4L2_TUNER_MODE_LANG1:
 		sw_data |= TDA9873_TR_DUALA;
 		break;
-	case VIDEO_SOUND_LANG2:
+	case V4L2_TUNER_MODE_LANG2:
 		sw_data |= TDA9873_TR_DUALB;
 		break;
 	default:
@@ -692,7 +691,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode)
 	}
 
 	chip_write(chip, TDA9873_SW, sw_data);
-	v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
+	v4l_dbg(1, debug, chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n",
 		mode, sw_data);
 }
 
@@ -831,7 +830,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip)
 		chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80);
 		chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */
 	}
-	v4l_dbg(1, debug, &chip->c, "tda9874a_setup(): %s [0x%02X].\n",
+	v4l_dbg(1, debug, chip->c, "tda9874a_setup(): %s [0x%02X].\n",
 		tda9874a_modelist[tda9874a_STD].name,tda9874a_STD);
 	return 1;
 }
@@ -841,7 +840,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
 	int dsr,nsr,mode;
 	int necr; /* just for debugging */
 
-	mode = VIDEO_SOUND_MONO;
+	mode = V4L2_TUNER_MODE_MONO;
 
 	if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR)))
 		return mode;
@@ -860,21 +859,21 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
 		 * that sound has (temporarily) switched from NICAM to
 		 * mono FM (or AM) on 1st sound carrier due to high NICAM bit
 		 * error count. So in fact there is no stereo in this case :-(
-		 * But changing the mode to VIDEO_SOUND_MONO would switch
+		 * But changing the mode to V4L2_TUNER_MODE_MONO would switch
 		 * external 4052 multiplexer in audio_hook().
 		 */
 		if(nsr & 0x02) /* NSR.S/MB=1 */
-			mode |= VIDEO_SOUND_STEREO;
+			mode |= V4L2_TUNER_MODE_STEREO;
 		if(nsr & 0x01) /* NSR.D/SB=1 */
-			mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+			mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
 	} else {
 		if(dsr & 0x02) /* DSR.IDSTE=1 */
-			mode |= VIDEO_SOUND_STEREO;
+			mode |= V4L2_TUNER_MODE_STEREO;
 		if(dsr & 0x04) /* DSR.IDDUA=1 */
-			mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+			mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
 	}
 
-	v4l_dbg(1, debug, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
+	v4l_dbg(1, debug, chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n",
 		 dsr, nsr, necr, mode);
 	return mode;
 }
@@ -902,14 +901,14 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
 		int mdacosr = (tda9874a_mode) ? 0x82:0x80;
 
 		switch(mode) {
-		case VIDEO_SOUND_MONO:
-		case VIDEO_SOUND_STEREO:
+		case V4L2_TUNER_MODE_MONO:
+		case V4L2_TUNER_MODE_STEREO:
 			break;
-		case VIDEO_SOUND_LANG1:
+		case V4L2_TUNER_MODE_LANG1:
 			aosr = 0x80; /* auto-select, dual A/A */
 			mdacosr = (tda9874a_mode) ? 0x82:0x80;
 			break;
-		case VIDEO_SOUND_LANG2:
+		case V4L2_TUNER_MODE_LANG2:
 			aosr = 0xa0; /* auto-select, dual B/B */
 			mdacosr = (tda9874a_mode) ? 0x83:0x81;
 			break;
@@ -920,18 +919,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
 		chip_write(chip, TDA9874A_AOSR, aosr);
 		chip_write(chip, TDA9874A_MDACOSR, mdacosr);
 
-		v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
+		v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n",
 			mode, aosr, mdacosr);
 
 	} else { /* dic == 0x07 */
 		int fmmr,aosr;
 
 		switch(mode) {
-		case VIDEO_SOUND_MONO:
+		case V4L2_TUNER_MODE_MONO:
 			fmmr = 0x00; /* mono */
 			aosr = 0x10; /* A/A */
 			break;
-		case VIDEO_SOUND_STEREO:
+		case V4L2_TUNER_MODE_STEREO:
 			if(tda9874a_mode) {
 				fmmr = 0x00;
 				aosr = 0x00; /* handled by NICAM auto-mute */
@@ -940,11 +939,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
 				aosr = 0x00;
 			}
 			break;
-		case VIDEO_SOUND_LANG1:
+		case V4L2_TUNER_MODE_LANG1:
 			fmmr = 0x02; /* dual */
 			aosr = 0x10; /* dual A/A */
 			break;
-		case VIDEO_SOUND_LANG2:
+		case V4L2_TUNER_MODE_LANG2:
 			fmmr = 0x02; /* dual */
 			aosr = 0x20; /* dual B/B */
 			break;
@@ -955,7 +954,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode)
 		chip_write(chip, TDA9874A_FMMR, fmmr);
 		chip_write(chip, TDA9874A_AOSR, aosr);
 
-		v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
+		v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n",
 			mode, fmmr, aosr);
 	}
 }
@@ -969,10 +968,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip)
 	if(-1 == (sic = chip_read2(chip,TDA9874A_SIC)))
 		return 0;
 
-	v4l_dbg(1, debug, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
+	v4l_dbg(1, debug, chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
 
 	if((dic == 0x11)||(dic == 0x07)) {
-		v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
+		v4l_info(chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h");
 		tda9874a_dic = dic;	/* remember device id. */
 		return 1;
 	}
@@ -1095,7 +1094,7 @@ static int tda8425_initialize(struct CHIPSTATE *chip)
 	int inputmap[4] = { /* tuner	*/ TDA8425_S1_CH2, /* radio  */ TDA8425_S1_CH1,
 			    /* extern	*/ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF};
 
-	if (chip->c.adapter->id == I2C_HW_B_RIVA) {
+	if (chip->c->adapter->id == I2C_HW_B_RIVA) {
 		memcpy (desc->inputmap, inputmap, sizeof (inputmap));
 	}
 	return 0;
@@ -1105,20 +1104,20 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
 {
 	int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
 
-	if (mode & VIDEO_SOUND_LANG1) {
+	if (mode & V4L2_TUNER_MODE_LANG1) {
 		s1 |= TDA8425_S1_ML_SOUND_A;
 		s1 |= TDA8425_S1_STEREO_PSEUDO;
 
-	} else if (mode & VIDEO_SOUND_LANG2) {
+	} else if (mode & V4L2_TUNER_MODE_LANG2) {
 		s1 |= TDA8425_S1_ML_SOUND_B;
 		s1 |= TDA8425_S1_STEREO_PSEUDO;
 
 	} else {
 		s1 |= TDA8425_S1_ML_STEREO;
 
-		if (mode & VIDEO_SOUND_MONO)
+		if (mode & V4L2_TUNER_MODE_MONO)
 			s1 |= TDA8425_S1_STEREO_MONO;
-		if (mode & VIDEO_SOUND_STEREO)
+		if (mode & V4L2_TUNER_MODE_STEREO)
 			s1 |= TDA8425_S1_STEREO_SPATIAL;
 	}
 	chip_write(chip,TDA8425_S1,s1);
@@ -1177,13 +1176,13 @@ static int ta8874z_getmode(struct CHIPSTATE *chip)
 	int val, mode;
 
 	val = chip_read(chip);
-	mode = VIDEO_SOUND_MONO;
+	mode = V4L2_TUNER_MODE_MONO;
 	if (val & TA8874Z_B1){
-		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+		mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2;
 	}else if (!(val & TA8874Z_B0)){
-		mode |= VIDEO_SOUND_STEREO;
+		mode |= V4L2_TUNER_MODE_STEREO;
 	}
-	/* v4l_dbg(1, debug, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
+	/* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */
 	return mode;
 }
 
@@ -1196,19 +1195,19 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
 {
 	int update = 1;
 	audiocmd *t = NULL;
-	v4l_dbg(1, debug, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
+	v4l_dbg(1, debug, chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode);
 
 	switch(mode){
-	case VIDEO_SOUND_MONO:
+	case V4L2_TUNER_MODE_MONO:
 		t = &ta8874z_mono;
 		break;
-	case VIDEO_SOUND_STEREO:
+	case V4L2_TUNER_MODE_STEREO:
 		t = &ta8874z_stereo;
 		break;
-	case VIDEO_SOUND_LANG1:
+	case V4L2_TUNER_MODE_LANG1:
 		t = &ta8874z_main;
 		break;
-	case VIDEO_SOUND_LANG2:
+	case V4L2_TUNER_MODE_LANG2:
 		t = &ta8874z_sub;
 		break;
 	default:
@@ -1462,51 +1461,55 @@ static struct CHIPDESC chiplist[] = {
 /* ---------------------------------------------------------------------- */
 /* i2c registration                                                       */
 
-static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
+static int chip_probe(struct i2c_client *client)
 {
 	struct CHIPSTATE *chip;
 	struct CHIPDESC  *desc;
 
+	if (debug) {
+		printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
+		printk(KERN_INFO "tvaudio: known chips: ");
+		for (desc = chiplist; desc->name != NULL; desc++)
+			printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
+		printk("\n");
+	}
+
 	chip = kzalloc(sizeof(*chip),GFP_KERNEL);
 	if (!chip)
 		return -ENOMEM;
-	memcpy(&chip->c,&client_template,sizeof(struct i2c_client));
-	chip->c.adapter = adap;
-	chip->c.addr = addr;
-	i2c_set_clientdata(&chip->c, chip);
+	chip->c = client;
+	i2c_set_clientdata(client, chip);
 
 	/* find description for the chip */
-	v4l_dbg(1, debug, &chip->c, "chip found @ 0x%x\n", addr<<1);
+	v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1);
 	for (desc = chiplist; desc->name != NULL; desc++) {
 		if (0 == *(desc->insmodopt))
 			continue;
-		if (addr < desc->addr_lo ||
-		    addr > desc->addr_hi)
+		if (client->addr < desc->addr_lo ||
+		    client->addr > desc->addr_hi)
 			continue;
 		if (desc->checkit && !desc->checkit(chip))
 			continue;
 		break;
 	}
 	if (desc->name == NULL) {
-		v4l_dbg(1, debug, &chip->c, "no matching chip description found\n");
+		v4l_dbg(1, debug, client, "no matching chip description found\n");
 		return -EIO;
 	}
-	v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name);
+	v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name);
 	if (desc->flags) {
-		v4l_dbg(1, debug, &chip->c, "matches:%s%s%s.\n",
+		v4l_dbg(1, debug, client, "matches:%s%s%s.\n",
 			(desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
 			(desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
 			(desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
 	}
 
 	/* fill required data structures */
-	strcpy(chip->c.name, desc->name);
+	strcpy(client->name, desc->name);
 	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);
 
 	/* initialization  */
 	if (desc->initialize != NULL)
@@ -1533,28 +1536,17 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
 		init_timer(&chip->wt);
 		chip->wt.function = chip_thread_wake;
 		chip->wt.data     = (unsigned long)chip;
-		chip->thread = kthread_run(chip_thread, chip, chip->c.name);
+		chip->thread = kthread_run(chip_thread, chip, chip->c->name);
 		if (IS_ERR(chip->thread)) {
-			v4l_warn(&chip->c, "%s: failed to create kthread\n",
-			       chip->c.name);
+			v4l_warn(chip->c, "%s: failed to create kthread\n",
+			       chip->c->name);
 			chip->thread = NULL;
 		}
 	}
 	return 0;
 }
 
-static int chip_probe(struct i2c_adapter *adap)
-{
-	/* don't attach on saa7146 based cards,
-	   because dedicated drivers are used */
-	if ((adap->id == I2C_HW_SAA7146))
-		return 0;
-	if (adap->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adap, &addr_data, chip_attach);
-	return 0;
-}
-
-static int chip_detach(struct i2c_client *client)
+static int chip_remove(struct i2c_client *client)
 {
 	struct CHIPSTATE *chip = i2c_get_clientdata(client);
 
@@ -1565,12 +1557,52 @@ static int chip_detach(struct i2c_client *client)
 		chip->thread = NULL;
 	}
 
-	i2c_detach_client(&chip->c);
 	kfree(chip);
 	return 0;
 }
 
-static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl)
+static int tvaudio_get_ctrl(struct CHIPSTATE *chip,
+			    struct v4l2_control *ctrl)
+{
+	struct CHIPDESC *desc = chiplist + chip->type;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		ctrl->value=chip->muted;
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		if (!desc->flags & CHIP_HAS_VOLUME)
+			break;
+		ctrl->value = max(chip->left,chip->right);
+		return 0;
+	case V4L2_CID_AUDIO_BALANCE:
+	{
+		int volume;
+		if (!desc->flags & CHIP_HAS_VOLUME)
+			break;
+		volume = max(chip->left,chip->right);
+		if (volume)
+			ctrl->value=(32768*min(chip->left,chip->right))/volume;
+		else
+			ctrl->value=32768;
+		return 0;
+	}
+	case V4L2_CID_AUDIO_BASS:
+		if (desc->flags & CHIP_HAS_BASSTREBLE)
+			break;
+		ctrl->value = chip->bass;
+		return 0;
+	case V4L2_CID_AUDIO_TREBLE:
+		if (desc->flags & CHIP_HAS_BASSTREBLE)
+			return -EINVAL;
+		ctrl->value = chip->treble;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int tvaudio_set_ctrl(struct CHIPSTATE *chip,
+			    struct v4l2_control *ctrl)
 {
 	struct CHIPDESC *desc = chiplist + chip->type;
 
@@ -1584,11 +1616,60 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl)
 		else
 			chip_write_masked(chip,desc->inputreg,
 					desc->inputmap[chip->input],desc->inputmask);
-		break;
-	default:
-		return -EINVAL;
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+	{
+		int volume,balance;
+
+		if (!desc->flags & CHIP_HAS_VOLUME)
+			break;
+
+		volume = max(chip->left,chip->right);
+		if (volume)
+			balance=(32768*min(chip->left,chip->right))/volume;
+		else
+			balance=32768;
+
+		volume=ctrl->value;
+		chip->left = (min(65536 - balance,32768) * volume) / 32768;
+		chip->right = (min(balance,volume *(__u16)32768)) / 32768;
+
+		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
+		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+
+		return 0;
 	}
-	return 0;
+	case V4L2_CID_AUDIO_BALANCE:
+	{
+		int volume, balance;
+		if (!desc->flags & CHIP_HAS_VOLUME)
+			break;
+
+		volume = max(chip->left,chip->right);
+		balance = ctrl->value;
+
+		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
+		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+
+		return 0;
+	}
+	case V4L2_CID_AUDIO_BASS:
+		if (desc->flags & CHIP_HAS_BASSTREBLE)
+			break;
+		chip->bass = ctrl->value;
+		chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
+
+		return 0;
+	case V4L2_CID_AUDIO_TREBLE:
+		if (desc->flags & CHIP_HAS_BASSTREBLE)
+			return -EINVAL;
+
+		chip->treble = ctrl->value;
+		chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
+
+		return 0;
+	}
+	return -EINVAL;
 }
 
 
@@ -1601,7 +1682,7 @@ static int chip_command(struct i2c_client *client,
 	struct CHIPSTATE *chip = i2c_get_clientdata(client);
 	struct CHIPDESC  *desc = chiplist + chip->type;
 
-	v4l_dbg(1, debug, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd);
+	v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd);
 
 	switch (cmd) {
 	case AUDC_SET_RADIO:
@@ -1609,67 +1690,36 @@ static int chip_command(struct i2c_client *client,
 		chip->watch_stereo = 0;
 		/* del_timer(&chip->wt); */
 		break;
-
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
 	kernel pointer here... */
-	case VIDIOCGAUDIO:
-	{
-		struct video_audio *va = arg;
-
-		if (desc->flags & CHIP_HAS_VOLUME) {
-			va->flags  |= VIDEO_AUDIO_VOLUME;
-			va->volume  = max(chip->left,chip->right);
-			if (va->volume)
-				va->balance = (32768*min(chip->left,chip->right))/
-					va->volume;
-			else
-				va->balance = 32768;
-		}
-		if (desc->flags & CHIP_HAS_BASSTREBLE) {
-			va->flags |= VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
-			va->bass   = chip->bass;
-			va->treble = chip->treble;
-		}
-		if (!chip->radio) {
-			if (desc->getmode)
-				va->mode = desc->getmode(chip);
-			else
-				va->mode = VIDEO_SOUND_MONO;
-		}
-		break;
-	}
-
-	case VIDIOCSAUDIO:
+	case VIDIOC_QUERYCTRL:
 	{
-		struct video_audio *va = arg;
-
-		if (desc->flags & CHIP_HAS_VOLUME) {
-			chip->left = (min(65536 - va->balance,32768) *
-				va->volume) / 32768;
-			chip->right = (min(va->balance,(__u16)32768) *
-				va->volume) / 32768;
-			chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
-			chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
-		}
-		if (desc->flags & CHIP_HAS_BASSTREBLE) {
-			chip->bass = va->bass;
-			chip->treble = va->treble;
-			chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
-			chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
-		}
-		if (desc->setmode && va->mode) {
-			chip->watch_stereo = 0;
-			/* del_timer(&chip->wt); */
-			chip->mode = va->mode;
-			desc->setmode(chip,va->mode);
+		struct v4l2_queryctrl *qc = arg;
+
+		switch (qc->id) {
+			case V4L2_CID_AUDIO_MUTE:
+				break;
+			case V4L2_CID_AUDIO_VOLUME:
+			case V4L2_CID_AUDIO_BALANCE:
+				if (!desc->flags & CHIP_HAS_VOLUME)
+					return -EINVAL;
+				break;
+			case V4L2_CID_AUDIO_BASS:
+			case V4L2_CID_AUDIO_TREBLE:
+				if (desc->flags & CHIP_HAS_BASSTREBLE)
+					return -EINVAL;
+				break;
+			default:
+				return -EINVAL;
 		}
-		break;
+		return v4l2_ctrl_query_fill_std(qc);
 	}
-
 	case VIDIOC_S_CTRL:
 		return tvaudio_set_ctrl(chip, arg);
 
+	case VIDIOC_G_CTRL:
+		return tvaudio_get_ctrl(chip, arg);
 	case VIDIOC_INT_G_AUDIO_ROUTING:
 	{
 		struct v4l2_routing *rt = arg;
@@ -1678,7 +1728,6 @@ static int chip_command(struct i2c_client *client,
 		rt->output = 0;
 		break;
 	}
-
 	case VIDIOC_INT_S_AUDIO_ROUTING:
 	{
 		struct v4l2_routing *rt = arg;
@@ -1693,7 +1742,6 @@ static int chip_command(struct i2c_client *client,
 				desc->inputmap[chip->input], desc->inputmask);
 		break;
 	}
-
 	case VIDIOC_S_TUNER:
 	{
 		struct v4l2_tuner *vt = arg;
@@ -1703,17 +1751,13 @@ static int chip_command(struct i2c_client *client,
 			break;
 		switch (vt->audmode) {
 		case V4L2_TUNER_MODE_MONO:
-			mode = VIDEO_SOUND_MONO;
-			break;
 		case V4L2_TUNER_MODE_STEREO:
-		case V4L2_TUNER_MODE_LANG1_LANG2:
-			mode = VIDEO_SOUND_STEREO;
-			break;
 		case V4L2_TUNER_MODE_LANG1:
-			mode = VIDEO_SOUND_LANG1;
-			break;
 		case V4L2_TUNER_MODE_LANG2:
-			mode = VIDEO_SOUND_LANG2;
+			mode = vt->audmode;
+			break;
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			mode = V4L2_TUNER_MODE_STEREO;
 			break;
 		default:
 			return -EINVAL;
@@ -1728,11 +1772,10 @@ static int chip_command(struct i2c_client *client,
 		}
 		break;
 	}
-
 	case VIDIOC_G_TUNER:
 	{
 		struct v4l2_tuner *vt = arg;
-		int mode = VIDEO_SOUND_MONO;
+		int mode = V4L2_TUNER_MODE_MONO;
 
 		if (chip->radio)
 			break;
@@ -1744,30 +1787,26 @@ static int chip_command(struct i2c_client *client,
 		if (desc->getmode)
 			mode = desc->getmode(chip);
 
-		if (mode & VIDEO_SOUND_MONO)
+		if (mode & V4L2_TUNER_MODE_MONO)
 			vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
-		if (mode & VIDEO_SOUND_STEREO)
+		if (mode & V4L2_TUNER_MODE_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)
+		if (mode & V4L2_TUNER_MODE_LANG1)
 			vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
 					 V4L2_TUNER_SUB_LANG2;
 		break;
 	}
-
-	case VIDIOCSCHAN:
 	case VIDIOC_S_STD:
 		chip->radio = 0;
 		break;
-
-	case VIDIOCSFREQ:
 	case VIDIOC_S_FREQUENCY:
 		chip->mode = 0; /* automatic */
 		if (desc->checkmode) {
-			desc->setmode(chip,VIDEO_SOUND_MONO);
-			if (chip->prevmode != VIDEO_SOUND_MONO)
+			desc->setmode(chip,V4L2_TUNER_MODE_MONO);
+			if (chip->prevmode != V4L2_TUNER_MODE_MONO)
 				chip->prevmode = -1; /* reset previous mode */
 			mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
 			/* the thread will call checkmode() later */
@@ -1780,44 +1819,25 @@ static int chip_command(struct i2c_client *client,
 	return 0;
 }
 
-static struct i2c_driver driver = {
-	.driver = {
-		.name    = "tvaudio",
-	},
-	.id              = I2C_DRIVERID_TVAUDIO,
-	.attach_adapter  = chip_probe,
-	.detach_client   = chip_detach,
-	.command         = chip_command,
-};
-
-static struct i2c_client client_template =
+static int chip_legacy_probe(struct i2c_adapter *adap)
 {
-	.name       = "(unset)",
-	.driver     = &driver,
-};
-
-static int __init audiochip_init_module(void)
-{
-	struct CHIPDESC  *desc;
-
-	if (debug) {
-		printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
-		printk(KERN_INFO "tvaudio: known chips: ");
-		for (desc = chiplist; desc->name != NULL; desc++)
-			printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
-		printk("\n");
-	}
-
-	return i2c_add_driver(&driver);
-}
-
-static void __exit audiochip_cleanup_module(void)
-{
-	i2c_del_driver(&driver);
+	/* don't attach on saa7146 based cards,
+	   because dedicated drivers are used */
+	if ((adap->id == I2C_HW_SAA7146))
+		return 0;
+	if (adap->class & I2C_CLASS_TV_ANALOG)
+		return 1;
+	return 0;
 }
 
-module_init(audiochip_init_module);
-module_exit(audiochip_cleanup_module);
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "tvaudio",
+	.driverid = I2C_DRIVERID_TVAUDIO,
+	.command = chip_command,
+	.probe = chip_probe,
+	.remove = chip_remove,
+	.legacy_probe = chip_legacy_probe,
+};
 
 /*
  * Local variables:
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 4b2c4034f5b3..0b8fbad3c721 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -46,11 +46,12 @@ MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
 MODULE_AUTHOR("John Klar");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-#define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown")
+#define STRM(array, i) \
+	(i < sizeof(array) / sizeof(char *) ? array[i] : "unknown")
 
 #define tveeprom_info(fmt, arg...) \
 	v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg)
@@ -58,7 +59,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 	v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg)
 #define tveeprom_dbg(fmt, arg...) do { \
 	if (debug) \
-		v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \
+		v4l_printk(KERN_DEBUG, "tveeprom", \
+				c->adapter, c->addr, fmt , ## arg); \
 	} while (0)
 
 /*
@@ -94,170 +96,172 @@ static struct HAUPPAUGE_TUNER
 hauppauge_tuner[] =
 {
 	/* 0-9 */
-	{ TUNER_ABSENT,        "None" },
-	{ TUNER_ABSENT,        "External" },
-	{ TUNER_ABSENT,        "Unspecified" },
-	{ TUNER_PHILIPS_PAL,   "Philips FI1216" },
-	{ TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
-	{ TUNER_PHILIPS_NTSC,  "Philips FI1236" },
-	{ TUNER_PHILIPS_PAL_I, "Philips FI1246" },
-	{ TUNER_PHILIPS_PAL_DK,"Philips FI1256" },
-	{ TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },
-	{ TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
+	{ TUNER_ABSENT,        		"None" },
+	{ TUNER_ABSENT,        		"External" },
+	{ TUNER_ABSENT,        		"Unspecified" },
+	{ TUNER_PHILIPS_PAL,   		"Philips FI1216" },
+	{ TUNER_PHILIPS_SECAM, 		"Philips FI1216MF" },
+	{ TUNER_PHILIPS_NTSC,  		"Philips FI1236" },
+	{ TUNER_PHILIPS_PAL_I, 		"Philips FI1246" },
+	{ TUNER_PHILIPS_PAL_DK,		"Philips FI1256" },
+	{ TUNER_PHILIPS_PAL,   		"Philips FI1216 MK2" },
+	{ TUNER_PHILIPS_SECAM, 		"Philips FI1216MF MK2" },
 	/* 10-19 */
-	{ TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },
-	{ TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
-	{ TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" },
-	{ TUNER_TEMIC_NTSC,    "Temic 4032FY5" },
-	{ TUNER_TEMIC_PAL,     "Temic 4002FH5" },
-	{ TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },
-	{ TUNER_PHILIPS_PAL,   "Philips FR1216 MK2" },
-	{ TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
-	{ TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },
-	{ TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
+	{ TUNER_PHILIPS_NTSC,  		"Philips FI1236 MK2" },
+	{ TUNER_PHILIPS_PAL_I, 		"Philips FI1246 MK2" },
+	{ TUNER_PHILIPS_PAL_DK,		"Philips FI1256 MK2" },
+	{ TUNER_TEMIC_NTSC,    		"Temic 4032FY5" },
+	{ TUNER_TEMIC_PAL,     		"Temic 4002FH5" },
+	{ TUNER_TEMIC_PAL_I,   		"Temic 4062FY5" },
+	{ TUNER_PHILIPS_PAL,   		"Philips FR1216 MK2" },
+	{ TUNER_PHILIPS_SECAM, 		"Philips FR1216MF MK2" },
+	{ TUNER_PHILIPS_NTSC,  		"Philips FR1236 MK2" },
+	{ TUNER_PHILIPS_PAL_I, 		"Philips FR1246 MK2" },
 	/* 20-29 */
-	{ TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" },
-	{ TUNER_PHILIPS_PAL,   "Philips FM1216" },
-	{ TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
-	{ TUNER_PHILIPS_NTSC,  "Philips FM1236" },
-	{ TUNER_PHILIPS_PAL_I, "Philips FM1246" },
-	{ TUNER_PHILIPS_PAL_DK,"Philips FM1256" },
-	{ TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
-	{ TUNER_ABSENT,        "Samsung TCPN9082D" },
-	{ TUNER_ABSENT,        "Samsung TCPM9092P" },
-	{ TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
+	{ TUNER_PHILIPS_PAL_DK,		"Philips FR1256 MK2" },
+	{ TUNER_PHILIPS_PAL,   		"Philips FM1216" },
+	{ TUNER_PHILIPS_SECAM, 		"Philips FM1216MF" },
+	{ TUNER_PHILIPS_NTSC,  		"Philips FM1236" },
+	{ TUNER_PHILIPS_PAL_I, 		"Philips FM1246" },
+	{ TUNER_PHILIPS_PAL_DK,		"Philips FM1256" },
+	{ TUNER_TEMIC_4036FY5_NTSC, 	"Temic 4036FY5" },
+	{ TUNER_ABSENT,        		"Samsung TCPN9082D" },
+	{ TUNER_ABSENT,        		"Samsung TCPM9092P" },
+	{ TUNER_TEMIC_4006FH5_PAL, 	"Temic 4006FH5" },
 	/* 30-39 */
-	{ TUNER_ABSENT,        "Samsung TCPN9085D" },
-	{ TUNER_ABSENT,        "Samsung TCPB9085P" },
-	{ TUNER_ABSENT,        "Samsung TCPL9091P" },
-	{ TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
-	{ TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
-	{ TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
-	{ TUNER_PHILIPS_NTSC,        "Philips TD1536" },
-	{ TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
-	{ TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
-	{ TUNER_ABSENT,        "Philips FI1256MP" },
+	{ TUNER_ABSENT,        		"Samsung TCPN9085D" },
+	{ TUNER_ABSENT,        		"Samsung TCPB9085P" },
+	{ TUNER_ABSENT,        		"Samsung TCPL9091P" },
+	{ TUNER_TEMIC_4039FR5_NTSC, 	"Temic 4039FR5" },
+	{ TUNER_PHILIPS_FQ1216ME,   	"Philips FQ1216 ME" },
+	{ TUNER_TEMIC_4066FY5_PAL_I, 	"Temic 4066FY5" },
+	{ TUNER_PHILIPS_NTSC,        	"Philips TD1536" },
+	{ TUNER_PHILIPS_NTSC,        	"Philips TD1536D" },
+	{ TUNER_PHILIPS_NTSC,  		"Philips FMR1236" }, /* mono radio */
+	{ TUNER_ABSENT,        		"Philips FI1256MP" },
 	/* 40-49 */
-	{ TUNER_ABSENT,        "Samsung TCPQ9091P" },
+	{ TUNER_ABSENT,        		"Samsung TCPQ9091P" },
 	{ TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
-	{ TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
-	{ TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
+	{ TUNER_TEMIC_4009FR5_PAL, 	"Temic 4009FR5" },
+	{ TUNER_TEMIC_4046FM5,     	"Temic 4046FM5" },
 	{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
-	{ TUNER_ABSENT,        "Philips TD1536D FH 44"},
-	{ TUNER_LG_NTSC_FM,    "LG TP18NSR01F"},
-	{ TUNER_LG_PAL_FM,     "LG TP18PSB01D"},
-	{ TUNER_LG_PAL,        "LG TP18PSB11D"},
-	{ TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
+	{ TUNER_ABSENT,        		"Philips TD1536D FH 44"},
+	{ TUNER_LG_NTSC_FM,    		"LG TP18NSR01F"},
+	{ TUNER_LG_PAL_FM,     		"LG TP18PSB01D"},
+	{ TUNER_LG_PAL,        		"LG TP18PSB11D"},
+	{ TUNER_LG_PAL_I_FM,   		"LG TAPC-I001D"},
 	/* 50-59 */
-	{ TUNER_LG_PAL_I,      "LG TAPC-I701D"},
-	{ TUNER_ABSENT,        "Temic 4042FI5"},
-	{ TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"},
-	{ TUNER_ABSENT,        "LG TPI8NSR11F"},
-	{ TUNER_ABSENT,        "Microtune 4049 FM5 Alt I2C"},
-	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"},
-	{ TUNER_ABSENT,        "Philips FI1236 MK3"},
-	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"},
-	{ TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"},
-	{ TUNER_ABSENT,        "Philips FM1216MP MK3"},
+	{ TUNER_LG_PAL_I,      		"LG TAPC-I701D"},
+	{ TUNER_ABSENT,       		"Temic 4042FI5"},
+	{ TUNER_MICROTUNE_4049FM5, 	"Microtune 4049 FM5"},
+	{ TUNER_ABSENT,        		"LG TPI8NSR11F"},
+	{ TUNER_ABSENT,        		"Microtune 4049 FM5 Alt I2C"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FQ1216ME MK3"},
+	{ TUNER_ABSENT,        		"Philips FI1236 MK3"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FM1216 ME MK3"},
+	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FM1236 MK3"},
+	{ TUNER_ABSENT,        		"Philips FM1216MP MK3"},
 	/* 60-69 */
-	{ TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"},
-	{ TUNER_ABSENT,        "LG M001D MK3"},
-	{ TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"},
-	{ TUNER_ABSENT,        "LG M701D MK3"},
-	{ TUNER_ABSENT,        "Temic 4146FM5"},
-	{ TUNER_ABSENT,        "Temic 4136FY5"},
-	{ TUNER_ABSENT,        "Temic 4106FH5"},
-	{ TUNER_ABSENT,        "Philips FQ1216LMP MK3"},
-	{ TUNER_LG_NTSC_TAPE,  "LG TAPE H001F MK3"},
-	{ TUNER_LG_NTSC_TAPE,  "LG TAPE H701F MK3"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"LG S001D MK3"},
+	{ TUNER_ABSENT,        		"LG M001D MK3"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"LG S701D MK3"},
+	{ TUNER_ABSENT,        		"LG M701D MK3"},
+	{ TUNER_ABSENT,        		"Temic 4146FM5"},
+	{ TUNER_ABSENT,        		"Temic 4136FY5"},
+	{ TUNER_ABSENT,        		"Temic 4106FH5"},
+	{ TUNER_ABSENT,        		"Philips FQ1216LMP MK3"},
+	{ TUNER_LG_NTSC_TAPE,  		"LG TAPE H001F MK3"},
+	{ TUNER_LG_NTSC_TAPE,  		"LG TAPE H701F MK3"},
 	/* 70-79 */
-	{ TUNER_ABSENT,        "LG TALN H200T"},
-	{ TUNER_ABSENT,        "LG TALN H250T"},
-	{ TUNER_ABSENT,        "LG TALN M200T"},
-	{ TUNER_ABSENT,        "LG TALN Z200T"},
-	{ TUNER_ABSENT,        "LG TALN S200T"},
-	{ TUNER_ABSENT,        "Thompson DTT7595"},
-	{ TUNER_ABSENT,        "Thompson DTT7592"},
-	{ TUNER_ABSENT,        "Silicon TDA8275C1 8290"},
-	{ TUNER_ABSENT,        "Silicon TDA8275C1 8290 FM"},
-	{ TUNER_ABSENT,        "Thompson DTT757"},
+	{ TUNER_ABSENT,        		"LG TALN H200T"},
+	{ TUNER_ABSENT,        		"LG TALN H250T"},
+	{ TUNER_ABSENT,        		"LG TALN M200T"},
+	{ TUNER_ABSENT,        		"LG TALN Z200T"},
+	{ TUNER_ABSENT,        		"LG TALN S200T"},
+	{ TUNER_ABSENT,        		"Thompson DTT7595"},
+	{ TUNER_ABSENT,        		"Thompson DTT7592"},
+	{ TUNER_ABSENT,        		"Silicon TDA8275C1 8290"},
+	{ TUNER_ABSENT,        		"Silicon TDA8275C1 8290 FM"},
+	{ TUNER_ABSENT,        		"Thompson DTT757"},
 	/* 80-89 */
-	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
-	{ TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
-	{ TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
-	{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
-	{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"},
-	{ TUNER_TCL_2002N,     "TCL 2002N 6A"},
-	{ TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"},
-	{ TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"},
-	{ TUNER_ABSENT,        "Samsung TCPE 4121P30A"},
-	{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FQ1216LME MK3"},
+	{ TUNER_LG_PAL_NEW_TAPC, 	"LG TAPC G701D"},
+	{ TUNER_LG_NTSC_NEW_TAPC, 	"LG TAPC H791F"},
+	{ TUNER_LG_PAL_NEW_TAPC, 	"TCL 2002MB 3"},
+	{ TUNER_LG_PAL_NEW_TAPC, 	"TCL 2002MI 3"},
+	{ TUNER_TCL_2002N,     		"TCL 2002N 6A"},
+	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FQ1236 MK3"},
+	{ TUNER_SAMSUNG_TCPN_2121P30A, 	"Samsung TCPN 2121P30A"},
+	{ TUNER_ABSENT,        		"Samsung TCPE 4121P30A"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"TCL MFPE05 2"},
 	/* 90-99 */
-	{ TUNER_ABSENT,        "LG TALN H202T"},
-	{ TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"},
-	{ TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"},
-	{ TUNER_ABSENT,        "Philips FQ1286A MK4"},
-	{ TUNER_ABSENT,        "Philips FQ1216ME MK5"},
-	{ TUNER_ABSENT,        "Philips FQ1236 MK5"},
-	{ TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
-	{ TUNER_TCL_2002MB,    "TCL 2002MB_3H"},
-	{ TUNER_ABSENT,        "TCL 2002MI_3H"},
-	{ TUNER_TCL_2002N,     "TCL 2002N 5H"},
+	{ TUNER_ABSENT,        		"LG TALN H202T"},
+	{ TUNER_PHILIPS_FQ1216AME_MK4, 	"Philips FQ1216AME MK4"},
+	{ TUNER_PHILIPS_FQ1236A_MK4, 	"Philips FQ1236A MK4"},
+	{ TUNER_ABSENT,       		"Philips FQ1286A MK4"},
+	{ TUNER_ABSENT,        		"Philips FQ1216ME MK5"},
+	{ TUNER_ABSENT,        		"Philips FQ1236 MK5"},
+	{ TUNER_SAMSUNG_TCPG_6121P30A, 	"Samsung TCPG 6121P30A"},
+	{ TUNER_TCL_2002MB,    		"TCL 2002MB_3H"},
+	{ TUNER_ABSENT,        		"TCL 2002MI_3H"},
+	{ TUNER_TCL_2002N,     		"TCL 2002N 5H"},
 	/* 100-109 */
-	{ TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"},
-	{ TUNER_TEA5767,       "Philips TEA5768HL FM Radio"},
-	{ TUNER_ABSENT,        "Panasonic ENV57H12D5"},
-	{ TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"},
-	{ TUNER_ABSENT,        "TCL MNM05-4"},
-	{ TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"},
-	{ TUNER_ABSENT,        "TCL MQNM05-4"},
-	{ TUNER_ABSENT,        "LG TAPC-W701D"},
-	{ TUNER_ABSENT,        "TCL 9886P-WM"},
-	{ TUNER_ABSENT,        "TCL 1676NM-WM"},
+	{ TUNER_PHILIPS_FMD1216ME_MK3, 	"Philips FMD1216ME"},
+	{ TUNER_TEA5767,       		"Philips TEA5768HL FM Radio"},
+	{ TUNER_ABSENT,        		"Panasonic ENV57H12D5"},
+	{ TUNER_PHILIPS_FM1236_MK3, 	"TCL MFNM05-4"},
+	{ TUNER_ABSENT,        		"TCL MNM05-4"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"TCL MPE05-2"},
+	{ TUNER_ABSENT,        		"TCL MQNM05-4"},
+	{ TUNER_ABSENT,        		"LG TAPC-W701D"},
+	{ TUNER_ABSENT,        		"TCL 9886P-WM"},
+	{ TUNER_ABSENT,        		"TCL 1676NM-WM"},
 	/* 110-119 */
-	{ TUNER_ABSENT,        "Thompson DTT75105"},
-	{ TUNER_ABSENT,        "Conexant_CX24109"},
-	{ TUNER_TCL_2002N,     "TCL M2523_5N_E"},
-	{ TUNER_TCL_2002MB,    "TCL M2523_3DB_E"},
-	{ TUNER_ABSENT,        "Philips 8275A"},
-	{ TUNER_ABSENT,        "Microtune MT2060"},
-	{ TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"},
-	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"},
-	{ TUNER_ABSENT,        "TCL M2523_3DI_E"},
-	{ TUNER_ABSENT,        "Samsung THPD5222FG30A"},
+	{ TUNER_ABSENT,        		"Thompson DTT75105"},
+	{ TUNER_ABSENT,        		"Conexant_CX24109"},
+	{ TUNER_TCL_2002N,     		"TCL M2523_5N_E"},
+	{ TUNER_TCL_2002MB,    		"TCL M2523_3DB_E"},
+	{ TUNER_ABSENT,        		"Philips 8275A"},
+	{ TUNER_ABSENT,        		"Microtune MT2060"},
+	{ TUNER_PHILIPS_FM1236_MK3, 	"Philips FM1236 MK5"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, 	"Philips FM1216ME MK5"},
+	{ TUNER_ABSENT,        		"TCL M2523_3DI_E"},
+	{ TUNER_ABSENT,        		"Samsung THPD5222FG30A"},
 	/* 120-129 */
-	{ TUNER_ABSENT,        "Xceive XC3028"},
-	{ TUNER_ABSENT,        "Philips FQ1216LME MK5"},
-	{ TUNER_ABSENT,        "Philips FQD1216LME"},
-	{ TUNER_ABSENT,        "Conexant CX24118A"},
-	{ TUNER_ABSENT,        "TCL DMF11WIP"},
-	{ TUNER_ABSENT,        "TCL MFNM05_4H_E"},
-	{ TUNER_ABSENT,        "TCL MNM05_4H_E"},
-	{ TUNER_ABSENT,        "TCL MPE05_2H_E"},
-	{ TUNER_ABSENT,        "TCL MQNM05_4_U"},
-	{ TUNER_ABSENT,        "TCL M2523_5NH_E"},
+	{ TUNER_XC2028,        		"Xceive XC3028"},
+	{ TUNER_ABSENT,        		"Philips FQ1216LME MK5"},
+	{ TUNER_ABSENT,        		"Philips FQD1216LME"},
+	{ TUNER_ABSENT,        		"Conexant CX24118A"},
+	{ TUNER_ABSENT,        		"TCL DMF11WIP"},
+	{ TUNER_ABSENT,        		"TCL MFNM05_4H_E"},
+	{ TUNER_ABSENT,        		"TCL MNM05_4H_E"},
+	{ TUNER_ABSENT,        		"TCL MPE05_2H_E"},
+	{ TUNER_ABSENT,        		"TCL MQNM05_4_U"},
+	{ TUNER_ABSENT,        		"TCL M2523_5NH_E"},
 	/* 130-139 */
-	{ TUNER_ABSENT,        "TCL M2523_3DBH_E"},
-	{ TUNER_ABSENT,        "TCL M2523_3DIH_E"},
-	{ TUNER_ABSENT,        "TCL MFPE05_2_U"},
-	{ TUNER_ABSENT,        "Philips FMD1216MEX"},
-	{ TUNER_ABSENT,        "Philips FRH2036B"},
-	{ TUNER_ABSENT,        "Panasonic ENGF75_01GF"},
-	{ TUNER_ABSENT,        "MaxLinear MXL5005"},
-	{ TUNER_ABSENT,        "MaxLinear MXL5003"},
-	{ TUNER_ABSENT,        "Xceive XC2028"},
-	{ TUNER_ABSENT,        "Microtune MT2131"},
+	{ TUNER_ABSENT,        		"TCL M2523_3DBH_E"},
+	{ TUNER_ABSENT,        		"TCL M2523_3DIH_E"},
+	{ TUNER_ABSENT,        		"TCL MFPE05_2_U"},
+	{ TUNER_ABSENT,        		"Philips FMD1216MEX"},
+	{ TUNER_ABSENT,        		"Philips FRH2036B"},
+	{ TUNER_ABSENT,        		"Panasonic ENGF75_01GF"},
+	{ TUNER_ABSENT,        		"MaxLinear MXL5005"},
+	{ TUNER_ABSENT,        		"MaxLinear MXL5003"},
+	{ TUNER_ABSENT,        		"Xceive XC2028"},
+	{ TUNER_ABSENT,        		"Microtune MT2131"},
 	/* 140-149 */
-	{ TUNER_ABSENT,        "Philips 8275A_8295"},
-	{ TUNER_ABSENT,        "TCL MF02GIP_5N_E"},
-	{ TUNER_ABSENT,        "TCL MF02GIP_3DB_E"},
-	{ TUNER_ABSENT,        "TCL MF02GIP_3DI_E"},
-	{ TUNER_ABSENT,        "Microtune MT2266"},
-	{ TUNER_ABSENT,        "TCL MF10WPP_4N_E"},
-	{ TUNER_ABSENT,        "LG TAPQ_H702F"},
-	{ TUNER_ABSENT,        "TCL M09WPP_4N_E"},
-	{ TUNER_ABSENT,        "MaxLinear MXL5005_v2"},
-	{ TUNER_ABSENT,        "Philips 18271_8295"},
+	{ TUNER_ABSENT,        		"Philips 8275A_8295"},
+	{ TUNER_ABSENT,        		"TCL MF02GIP_5N_E"},
+	{ TUNER_ABSENT,        		"TCL MF02GIP_3DB_E"},
+	{ TUNER_ABSENT,        		"TCL MF02GIP_3DI_E"},
+	{ TUNER_ABSENT,        		"Microtune MT2266"},
+	{ TUNER_ABSENT,        		"TCL MF10WPP_4N_E"},
+	{ TUNER_ABSENT,        		"LG TAPQ_H702F"},
+	{ TUNER_ABSENT,        		"TCL M09WPP_4N_E"},
+	{ TUNER_ABSENT,        		"MaxLinear MXL5005_v2"},
+	{ TUNER_PHILIPS_TDA8290, 	"Philips 18271_8295"},
+	/* 150-159 */
+	{ TUNER_ABSENT,        "Xceive XC5000"},
 };
 
 static struct HAUPPAUGE_AUDIOIC
@@ -344,37 +348,37 @@ static const char *decoderIC[] = {
 static int hasRadioTuner(int tunerType)
 {
 	switch (tunerType) {
-		case 18: //PNPEnv_TUNER_FR1236_MK2:
-		case 23: //PNPEnv_TUNER_FM1236:
-		case 38: //PNPEnv_TUNER_FMR1236:
-		case 16: //PNPEnv_TUNER_FR1216_MK2:
-		case 19: //PNPEnv_TUNER_FR1246_MK2:
-		case 21: //PNPEnv_TUNER_FM1216:
-		case 24: //PNPEnv_TUNER_FM1246:
-		case 17: //PNPEnv_TUNER_FR1216MF_MK2:
-		case 22: //PNPEnv_TUNER_FM1216MF:
-		case 20: //PNPEnv_TUNER_FR1256_MK2:
-		case 25: //PNPEnv_TUNER_FM1256:
-		case 33: //PNPEnv_TUNER_4039FR5:
-		case 42: //PNPEnv_TUNER_4009FR5:
-		case 52: //PNPEnv_TUNER_4049FM5:
-		case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
-		case 44: //PNPEnv_TUNER_4009FN5:
-		case 31: //PNPEnv_TUNER_TCPB9085P:
-		case 30: //PNPEnv_TUNER_TCPN9085D:
-		case 46: //PNPEnv_TUNER_TP18NSR01F:
-		case 47: //PNPEnv_TUNER_TP18PSB01D:
-		case 49: //PNPEnv_TUNER_TAPC_I001D:
-		case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
-		case 57: //PNPEnv_TUNER_FM1216ME_MK3:
-		case 59: //PNPEnv_TUNER_FM1216MP_MK3:
-		case 58: //PNPEnv_TUNER_FM1236_MK3:
-		case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
-		case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
-		case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
-		case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
-		case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
-		case 105:
+	case 18: /* PNPEnv_TUNER_FR1236_MK2 */
+	case 23: /* PNPEnv_TUNER_FM1236 */
+	case 38: /* PNPEnv_TUNER_FMR1236 */
+	case 16: /* PNPEnv_TUNER_FR1216_MK2 */
+	case 19: /* PNPEnv_TUNER_FR1246_MK2 */
+	case 21: /* PNPEnv_TUNER_FM1216 */
+	case 24: /* PNPEnv_TUNER_FM1246 */
+	case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */
+	case 22: /* PNPEnv_TUNER_FM1216MF */
+	case 20: /* PNPEnv_TUNER_FR1256_MK2 */
+	case 25: /* PNPEnv_TUNER_FM1256 */
+	case 33: /* PNPEnv_TUNER_4039FR5 */
+	case 42: /* PNPEnv_TUNER_4009FR5 */
+	case 52: /* PNPEnv_TUNER_4049FM5 */
+	case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */
+	case 44: /* PNPEnv_TUNER_4009FN5 */
+	case 31: /* PNPEnv_TUNER_TCPB9085P */
+	case 30: /* PNPEnv_TUNER_TCPN9085D */
+	case 46: /* PNPEnv_TUNER_TP18NSR01F */
+	case 47: /* PNPEnv_TUNER_TP18PSB01D */
+	case 49: /* PNPEnv_TUNER_TAPC_I001D */
+	case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */
+	case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */
+	case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */
+	case 58: /* PNPEnv_TUNER_FM1236_MK3 */
+	case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */
+	case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */
+	case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */
+	case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */
+	case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */
+	case 105:
 		return 1;
 	}
 	return 0;
@@ -392,7 +396,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 	**
 	** In our (ivtv) case we're interested in the following:
 	** tuner type:   tag [00].05 or [0a].01 (index into hauppauge_tuner)
-	** tuner fmts:   tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt)
+	** tuner fmts:   tag [00].04 or [0a].00 (bitmask index into
+	**		 hauppauge_tuner_fmt)
 	** radio:        tag [00].{last} or [0e].00  (bitmask.  bit2=FM)
 	** audio proc:   tag [02].01 or [05].00 (mask with 0x7f)
 	** decoder proc: tag [09].01)
@@ -405,9 +410,9 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 	** # of inputs/outputs ???
 	*/
 
-	int i, j, len, done, beenhere, tag,start;
+	int i, j, len, done, beenhere, tag, start;
 
-	int tuner1 = 0, t_format1 = 0, audioic=-1;
+	int tuner1 = 0, t_format1 = 0, audioic = -1;
 	char *t_name1 = NULL;
 	const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" };
 
@@ -418,17 +423,24 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 	memset(tvee, 0, sizeof(*tvee));
 	done = len = beenhere = 0;
 
-	/* Hack for processing eeprom for em28xx and cx 2388x*/
-	if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) &&
-			(eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95))
-		start=0xa0; /* Generic em28xx offset */
-	else if (((eeprom_data[0] & 0xe1) == 0x01) &&
-					(eeprom_data[1] == 0x00) &&
-					(eeprom_data[2] == 0x00) &&
-					(eeprom_data[8] == 0x84))
-		start=8; /* Generic cx2388x offset */
+	/* Different eeprom start offsets for em28xx, cx2388x and cx23418 */
+	if (eeprom_data[0] == 0x1a &&
+	    eeprom_data[1] == 0xeb &&
+	    eeprom_data[2] == 0x67 &&
+	    eeprom_data[3] == 0x95)
+		start = 0xa0; /* Generic em28xx offset */
+	else if ((eeprom_data[0] & 0xe1) == 0x01 &&
+		 eeprom_data[1] == 0x00 &&
+		 eeprom_data[2] == 0x00 &&
+		 eeprom_data[8] == 0x84)
+		start = 8; /* Generic cx2388x offset */
+	else if (eeprom_data[1] == 0x70 &&
+		 eeprom_data[2] == 0x00 &&
+		 eeprom_data[4] == 0x74 &&
+		 eeprom_data[8] == 0x84)
+		start = 8; /* Generic cx23418 offset (models 74xxx) */
 	else
-		start=0;
+		start = 0;
 
 	for (i = start; !done && i < 256; i += len) {
 		if (eeprom_data[i] == 0x84) {
@@ -444,16 +456,17 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 			++i;
 		} else {
 			tveeprom_warn("Encountered bad packet header [%02x]. "
-				"Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
+				"Corrupt or not a Hauppauge eeprom.\n",
+				eeprom_data[i]);
 			return;
 		}
 
 		if (debug) {
-			tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1);
-			for(j = 1; j < len; j++) {
-				printk(" %02x", eeprom_data[i + j]);
-			}
-			printk("\n");
+			tveeprom_info("Tag [%02x] + %d bytes:",
+					eeprom_data[i], len - 1);
+			for (j = 1; j < len; j++)
+				printk(KERN_CONT " %02x", eeprom_data[i + j]);
+			printk(KERN_CONT "\n");
 		}
 
 		/* process by tag */
@@ -504,16 +517,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 				(eeprom_data[i+6] << 8) +
 				(eeprom_data[i+7] << 16);
 
-				if ( (eeprom_data[i + 8] & 0xf0) &&
-					(tvee->serial_number < 0xffffff) ) {
-					tvee->MAC_address[0] = 0x00;
-					tvee->MAC_address[1] = 0x0D;
-					tvee->MAC_address[2] = 0xFE;
-					tvee->MAC_address[3] = eeprom_data[i + 7];
-					tvee->MAC_address[4] = eeprom_data[i + 6];
-					tvee->MAC_address[5] = eeprom_data[i + 5];
-					tvee->has_MAC_address = 1;
-				}
+			if ((eeprom_data[i + 8] & 0xf0) &&
+					(tvee->serial_number < 0xffffff)) {
+				tvee->MAC_address[0] = 0x00;
+				tvee->MAC_address[1] = 0x0D;
+				tvee->MAC_address[2] = 0xFE;
+				tvee->MAC_address[3] = eeprom_data[i + 7];
+				tvee->MAC_address[4] = eeprom_data[i + 6];
+				tvee->MAC_address[5] = eeprom_data[i + 5];
+				tvee->has_MAC_address = 1;
+			}
 			break;
 
 		case 0x05:
@@ -537,7 +550,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 				(eeprom_data[i + 3] << 16) +
 				(eeprom_data[i + 4] << 24);
 			tvee->revision =
-				eeprom_data[i +5 ] +
+				eeprom_data[i + 5] +
 				(eeprom_data[i + 6] << 8) +
 				(eeprom_data[i + 7] << 16);
 			break;
@@ -557,16 +570,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 		case 0x0a:
 			/* tag 'Tuner' */
 			if (beenhere == 0) {
-				tuner1 = eeprom_data[i+2];
-				t_format1 = eeprom_data[i+1];
+				tuner1 = eeprom_data[i + 2];
+				t_format1 = eeprom_data[i + 1];
 				beenhere = 1;
 			} else {
 				/* a second (radio) tuner may be present */
-				tuner2 = eeprom_data[i+2];
-				t_format2 = eeprom_data[i+1];
-				if (t_format2 == 0) {  /* not a TV tuner? */
+				tuner2 = eeprom_data[i + 2];
+				t_format2 = eeprom_data[i + 1];
+				/* not a TV tuner? */
+				if (t_format2 == 0)
 					tvee->has_radio = 1; /* must be radio */
-				}
 			}
 			break;
 
@@ -594,7 +607,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 		/* case 0x12: tag 'InfoBits' */
 
 		default:
-			tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag);
+			tveeprom_dbg("Not sure what to do with tag [%02x]\n",
+					tag);
 			/* dump the rest of the packet? */
 		}
 	}
@@ -608,7 +622,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 		tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f);
 		tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f);
 		tvee->rev_str[2] = 32 + ((tvee->revision >>  6) & 0x3f);
-		tvee->rev_str[3] = 32 + ( tvee->revision        & 0x3f);
+		tvee->rev_str[3] = 32 + (tvee->revision & 0x3f);
 		tvee->rev_str[4] = 0;
 	}
 
@@ -651,44 +665,40 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
 
 	tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
 		tvee->model, tvee->rev_str, tvee->serial_number);
-	if (tvee->has_MAC_address == 1) {
+	if (tvee->has_MAC_address == 1)
 		tveeprom_info("MAC address is %02X-%02X-%02X-%02X-%02X-%02X\n",
 			tvee->MAC_address[0], tvee->MAC_address[1],
 			tvee->MAC_address[2], tvee->MAC_address[3],
 			tvee->MAC_address[4], tvee->MAC_address[5]);
-	}
 	tveeprom_info("tuner model is %s (idx %d, type %d)\n",
 		t_name1, tuner1, tvee->tuner_type);
 	tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
-		t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3],
-		t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7],
-		t_format1);
-	if (tuner2) {
+		t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2],
+		t_fmt_name1[3],	t_fmt_name1[4], t_fmt_name1[5],
+		t_fmt_name1[6], t_fmt_name1[7],	t_format1);
+	if (tuner2)
 		tveeprom_info("second tuner model is %s (idx %d, type %d)\n",
 					t_name2, tuner2, tvee->tuner2_type);
-	}
-	if (t_format2) {
+	if (t_format2)
 		tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n",
-			t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3],
-			t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7],
-			t_format2);
-	}
-	if (audioic<0) {
+			t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2],
+			t_fmt_name2[3],	t_fmt_name2[4], t_fmt_name2[5],
+			t_fmt_name2[6], t_fmt_name2[7], t_format2);
+	if (audioic < 0) {
 		tveeprom_info("audio processor is unknown (no idx)\n");
-		tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
+		tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
 	} else {
 		if (audioic < ARRAY_SIZE(audioIC))
 			tveeprom_info("audio processor is %s (idx %d)\n",
-					audioIC[audioic].name,audioic);
+					audioIC[audioic].name, audioic);
 		else
 			tveeprom_info("audio processor is unknown (idx %d)\n",
 								audioic);
 	}
-	if (tvee->decoder_processor) {
+	if (tvee->decoder_processor)
 		tveeprom_info("decoder processor is %s (idx %d)\n",
 			STRM(decoderIC, tvee->decoder_processor),
 			tvee->decoder_processor);
-	}
 	if (tvee->has_ir == -1)
 		tveeprom_info("has %sradio\n",
 				tvee->has_radio ? "" : "no ");
@@ -709,11 +719,13 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
 	int err;
 
 	buf = 0;
-	if (1 != (err = i2c_master_send(c, &buf, 1))) {
+	err = i2c_master_send(c, &buf, 1);
+	if (err != 1) {
 		tveeprom_info("Huh, no eeprom present (err=%d)?\n", err);
 		return -1;
 	}
-	if (len != (err = i2c_master_recv(c, eedata, len))) {
+	err = i2c_master_recv(c, eedata, len);
+	if (err != len) {
 		tveeprom_warn("i2c eeprom read error (err=%d)\n", err);
 		return -1;
 	}
@@ -724,9 +736,9 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
 		for (i = 0; i < len; i++) {
 			if (0 == (i % 16))
 				tveeprom_info("%02x:", i);
-			printk(" %02x", eedata[i]);
+			printk(KERN_CONT " %02x", eedata[i]);
 			if (15 == (i % 16))
-				printk("\n");
+				printk(KERN_CONT "\n");
 		}
 	}
 	return 0;
@@ -758,9 +770,9 @@ tveeprom_command(struct i2c_client *client,
 
 	switch (cmd) {
 	case 0:
-		buf = kzalloc(256,GFP_KERNEL);
-		tveeprom_read(client,buf,256);
-		tveeprom_hauppauge_analog(client, &eeprom,buf);
+		buf = kzalloc(256, GFP_KERNEL);
+		tveeprom_read(client, buf, 256);
+		tveeprom_hauppauge_analog(client, &eeprom, buf);
 		kfree(buf);
 		eeprom_props[0] = eeprom.tuner_type;
 		eeprom_props[1] = eeprom.tuner_formats;
@@ -794,7 +806,7 @@ tveeprom_detect_client(struct i2c_adapter *adapter,
 }
 
 static int
-tveeprom_attach_adapter (struct i2c_adapter *adapter)
+tveeprom_attach_adapter(struct i2c_adapter *adapter)
 {
 	if (adapter->class & I2C_CLASS_TV_ANALOG)
 		return i2c_probe(adapter, &addr_data, tveeprom_detect_client);
@@ -802,7 +814,7 @@ tveeprom_attach_adapter (struct i2c_adapter *adapter)
 }
 
 static int
-tveeprom_detach_client (struct i2c_client *client)
+tveeprom_detach_client(struct i2c_client *client)
 {
 	int err;
 
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index 0b2a961efd22..bd201397a2ac 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -28,30 +28,27 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 #include <media/upd64031a.h>
 
-// --------------------- read registers functions define -----------------------
+/* --------------------- read registers functions define -------------------- */
 
 /* bit masks */
 #define GR_MODE_MASK              0xc0
 #define DIRECT_3DYCS_CONNECT_MASK 0xc0
 #define SYNC_CIRCUIT_MASK         0xa0
 
-// -----------------------------------------------------------------------------
+/* -------------------------------------------------------------------------- */
 
 MODULE_DESCRIPTION("uPD64031A driver");
 MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-static unsigned short normal_i2c[] = { 0x24 >> 1, 0x26 >> 1, I2C_CLIENT_END };
-
-
-I2C_CLIENT_INSMOD;
 
 enum {
 	R00 = 0, R01, R02, R03, R04,
@@ -99,7 +96,7 @@ static void upd64031a_write(struct i2c_client *client, u8 reg, u8 val)
 
 	buf[0] = reg;
 	buf[1] = val;
-	v4l_dbg(1, debug, client, "writing reg addr: %02X val: %02X\n", reg, val);
+	v4l_dbg(1, debug, client, "write reg: %02X val: %02X\n", reg, val);
 	if (i2c_master_send(client, buf, 2) != 2)
 		v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
 }
@@ -119,7 +116,7 @@ static void upd64031a_change(struct i2c_client *client)
 
 /* ------------------------------------------------------------------------ */
 
-static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
 	struct upd64031a_state *state = i2c_get_clientdata(client);
 	struct v4l2_routing *route = arg;
@@ -143,8 +140,10 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
 
 		state->gr_mode = (route->input & 3) << 6;
 		state->direct_3dycs_connect = (route->input & 0xc) << 4;
-		state->ext_comp_sync = (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
-		state->ext_vert_sync = (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
+		state->ext_comp_sync =
+			(route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1;
+		state->ext_vert_sync =
+			(route->input & UPD64031A_VERTICAL_EXTERNAL) << 2;
 		r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode;
 		r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) |
 			state->ext_comp_sync | state->ext_vert_sync;
@@ -168,20 +167,23 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
 	{
 		struct v4l2_register *reg = arg;
 
-		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+		if (!v4l2_chip_match_i2c_client(client,
+					reg->match_type, reg->match_chip))
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (cmd == VIDIOC_DBG_G_REGISTER)
+		if (cmd == VIDIOC_DBG_G_REGISTER) {
 			reg->val = upd64031a_read(client, reg->reg & 0xff);
-		else
-			upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
+			break;
+		}
+		upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
 		break;
 	}
 #endif
 
 	case VIDIOC_G_CHIP_IDENT:
-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0);
+		return v4l2_chip_ident_i2c_client(client, arg,
+				V4L2_IDENT_UPD64031A, 0);
 
 	default:
 		break;
@@ -193,90 +195,43 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *
 
 /* i2c implementation */
 
-static struct i2c_driver i2c_driver;
-
-static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind)
+static int upd64031a_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	struct upd64031a_state *state;
 	int i;
 
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == NULL) {
-		return -ENOMEM;
-	}
-
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver;
-	snprintf(client->name, sizeof(client->name) - 1, "uPD64031A");
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
 
-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
 
 	state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL);
-	if (state == NULL) {
-		kfree(client);
+	if (state == NULL)
 		return -ENOMEM;
-	}
 	i2c_set_clientdata(client, state);
 	memcpy(state->regs, upd64031a_init, sizeof(state->regs));
 	state->gr_mode = UPD64031A_GR_ON << 6;
 	state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4;
 	state->ext_comp_sync = state->ext_vert_sync = 0;
-	for (i = 0; i < TOT_REGS; i++) {
+	for (i = 0; i < TOT_REGS; i++)
 		upd64031a_write(client, i, state->regs[i]);
-	}
-
-	i2c_attach_client(client);
-
 	return 0;
 }
 
-static int upd64031a_probe(struct i2c_adapter *adapter)
+static int upd64031a_remove(struct i2c_client *client)
 {
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, upd64031a_attach);
-	return 0;
-}
-
-static int upd64031a_detach(struct i2c_client *client)
-{
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err)
-		return err;
-
-	kfree(client);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-	.driver = {
-		.name = "upd64031a",
-	},
-	.id = I2C_DRIVERID_UPD64031A,
-	.attach_adapter = upd64031a_probe,
-	.detach_client  = upd64031a_detach,
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "upd64031a",
+	.driverid = I2C_DRIVERID_UPD64031A,
 	.command = upd64031a_command,
+	.probe = upd64031a_probe,
+	.remove = upd64031a_remove,
 };
-
-
-static int __init upd64031a_init_module(void)
-{
-	return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit upd64031a_exit_module(void)
-{
-	i2c_del_driver(&i2c_driver);
-}
-
-module_init(upd64031a_init_module);
-module_exit(upd64031a_exit_module);
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index 401bd21f46eb..2d9a88f70c85 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -17,7 +17,8 @@
  *
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
  */
 
 #include <linux/version.h>
@@ -27,21 +28,18 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 #include <media/upd64083.h>
 
 MODULE_DESCRIPTION("uPD64083 driver");
 MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
+static int debug;
 module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-static unsigned short normal_i2c[] = { 0xb8 >> 1, 0xba >> 1, I2C_CLIENT_END };
-
-
-I2C_CLIENT_INSMOD;
 
 enum {
 	R00 = 0, R01, R02, R03, R04,
@@ -88,7 +86,7 @@ static void upd64083_write(struct i2c_client *client, u8 reg, u8 val)
 
 	buf[0] = reg;
 	buf[1] = val;
-	v4l_dbg(1, debug, client, "writing reg addr: %02x val: %02x\n", reg, val);
+	v4l_dbg(1, debug, client, "write reg: %02x val: %02x\n", reg, val);
 	if (i2c_master_send(client, buf, 2) != 2)
 		v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val);
 }
@@ -109,7 +107,7 @@ static u8 upd64083_read(struct i2c_client *client, u8 reg)
 
 /* ------------------------------------------------------------------------ */
 
-static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
 	struct upd64083_state *state = i2c_get_clientdata(client);
 	struct v4l2_routing *route = arg;
@@ -145,20 +143,23 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
 	{
 		struct v4l2_register *reg = arg;
 
-		if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+		if (!v4l2_chip_match_i2c_client(client,
+				reg->match_type, reg->match_chip))
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (cmd == VIDIOC_DBG_G_REGISTER)
+		if (cmd == VIDIOC_DBG_G_REGISTER) {
 			reg->val = upd64083_read(client, reg->reg & 0xff);
-		else
-			upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
+			break;
+		}
+		upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
 		break;
 	}
 #endif
 
 	case VIDIOC_G_CHIP_IDENT:
-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0);
+		return v4l2_chip_ident_i2c_client(client, arg,
+				V4L2_IDENT_UPD64083, 0);
 
 	default:
 		break;
@@ -171,89 +172,43 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a
 
 /* i2c implementation */
 
-static struct i2c_driver i2c_driver;
-
-static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind)
+static int upd64083_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	struct upd64083_state *state;
 	int i;
 
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == NULL) {
-		return -ENOMEM;
-	}
-
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver;
-	snprintf(client->name, sizeof(client->name) - 1, "uPD64083");
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
 
-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
 
 	state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL);
-	if (state == NULL) {
-		kfree(client);
+	if (state == NULL)
 		return -ENOMEM;
-	}
 	i2c_set_clientdata(client, state);
 	/* Initially assume that a ghost reduction chip is present */
 	state->mode = 0;  /* YCS mode */
 	state->ext_y_adc = (1 << 5);
 	memcpy(state->regs, upd64083_init, TOT_REGS);
-	for (i = 0; i < TOT_REGS; i++) {
+	for (i = 0; i < TOT_REGS; i++)
 		upd64083_write(client, i, state->regs[i]);
-	}
-	i2c_attach_client(client);
-
-	return 0;
-}
-
-static int upd64083_probe(struct i2c_adapter *adapter)
-{
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, upd64083_attach);
 	return 0;
 }
 
-static int upd64083_detach(struct i2c_client *client)
+static int upd64083_remove(struct i2c_client *client)
 {
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err)
-		return err;
-
-	kfree(client);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-	.driver = {
-		.name = "upd64083",
-	},
-	.id = I2C_DRIVERID_UPD64083,
-	.attach_adapter = upd64083_probe,
-	.detach_client  = upd64083_detach,
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "upd64083",
+	.driverid = I2C_DRIVERID_UPD64083,
 	.command = upd64083_command,
+	.probe = upd64083_probe,
+	.remove = upd64083_remove,
 };
-
-
-static int __init upd64083_init_module(void)
-{
-	return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit upd64083_exit_module(void)
-{
-	i2c_del_driver(&i2c_driver);
-}
-
-module_init(upd64083_init_module);
-module_exit(upd64083_exit_module);
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index f09eb102731b..503b13beb922 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -901,6 +901,20 @@ struct usbvision_device_data_st  usbvision_device_data[] = {
 		.Y_Offset      = -1,
 		.ModelString   = "Pinnacle Studio PCTV USB (NTSC) FM",
 	},
+	[PINNA_PCTV_USB_NTSC_FM_V3] = {
+		.Interface     = -1,
+		.Codec         = CODEC_SAA7111,
+		.VideoChannels = 3,
+		.VideoNorm     = V4L2_STD_NTSC,
+		.AudioChannels = 1,
+		.Radio         = 1,
+		.vbi           = 1,
+		.Tuner         = 1,
+		.TunerType     = TUNER_PHILIPS_NTSC_M,
+		.X_Offset      = -1,
+		.Y_Offset      = -1,
+		.ModelString   = "Pinnacle Studio PCTV USB (NTSC) FM V3",
+	},
 	[PINNA_PCTV_USB_PAL_FM_V2] = {
 		.Interface     = -1,
 		.Codec         = CODEC_SAA7113,
@@ -1044,7 +1058,7 @@ struct usb_device_id usbvision_table [] = {
 	{ USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN },
 	{ USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 },
 	{ USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL },
-	{ USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 },
+	{ USB_DEVICE(0x0573, 0x4d20), .driver_info = HPG_WINTV_PRO_NTSC_MN_V3 },
 	{ USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG },
 	{ USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I },
 	{ USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L },
@@ -1074,6 +1088,8 @@ struct usb_device_id usbvision_table [] = {
 	{ USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM },
 	{ USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB },
 	{ USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM },
+	{ USB_DEVICE(0x2304, 0x0113),
+	  .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
 	{ USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 },
 	{ USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 },
 	{ USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 },
diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h
index 512c5cee4145..9c6ad22960d8 100644
--- a/drivers/media/video/usbvision/usbvision-cards.h
+++ b/drivers/media/video/usbvision/usbvision-cards.h
@@ -62,5 +62,6 @@
 #define PINNA_LINX_VD_IN_CAB_PAL                 61
 #define PINNA_PCTV_BUNGEE_PAL_FM                 62
 #define HPG_WINTV                                63
+#define PINNA_PCTV_USB_NTSC_FM_V3                64
 
 extern const int usbvision_device_data_size;
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index c7d5f9ed22d7..56775ab8b75d 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -69,6 +69,15 @@ static int SwitchSVideoInput = 0;			// To help people with Black and White outpu
 module_param(SwitchSVideoInput, int, 0444);
 MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input.  Some cables and input device are wired differently. Default: 0 (Off)");
 
+static unsigned int adjust_X_Offset = -1;
+module_param(adjust_X_Offset, int, 0644);
+MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]");
+
+static unsigned int adjust_Y_Offset = -1;
+module_param(adjust_Y_Offset, int, 0644);
+MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");
+
+
 #define	ENABLE_HEXDUMP	0	/* Enable if you need it */
 
 
@@ -624,25 +633,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
 
 			YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv);
 			switch (frame->v4l2_format.format) {
-				case V4L2_PIX_FMT_RGB565:
-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
-					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
-					break;
-				case V4L2_PIX_FMT_RGB24:
-					*f++ = bv;
-					*f++ = gv;
-					*f++ = rv;
-					break;
-				case V4L2_PIX_FMT_RGB32:
-					*f++ = bv;
-					*f++ = gv;
-					*f++ = rv;
-					f++;
-					break;
-				case V4L2_PIX_FMT_RGB555:
-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
-					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
-					break;
+			case V4L2_PIX_FMT_RGB565:
+				*f++ = (0x1F & rv) |
+					(0xE0 & (gv << 5));
+				*f++ = (0x07 & (gv >> 3)) |
+					(0xF8 &  bv);
+				break;
+			case V4L2_PIX_FMT_RGB24:
+				*f++ = rv;
+				*f++ = gv;
+				*f++ = bv;
+				break;
+			case V4L2_PIX_FMT_RGB32:
+				*f++ = rv;
+				*f++ = gv;
+				*f++ = bv;
+				f++;
+				break;
+			case V4L2_PIX_FMT_RGB555:
+				*f++ = (0x1F & rv) |
+					(0xE0 & (gv << 5));
+				*f++ = (0x03 & (gv >> 3)) |
+					(0x7C & (bv << 2));
+				break;
 			}
 		}
 		clipmask_index += clipmask_add;
@@ -656,25 +669,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
 
 			YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv);
 			switch (frame->v4l2_format.format) {
-				case V4L2_PIX_FMT_RGB565:
-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
-					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
-					break;
-				case V4L2_PIX_FMT_RGB24:
-					*f++ = bv;
-					*f++ = gv;
-					*f++ = rv;
-					break;
-				case V4L2_PIX_FMT_RGB32:
-					*f++ = bv;
-					*f++ = gv;
-					*f++ = rv;
-					f++;
-					break;
-				case V4L2_PIX_FMT_RGB555:
-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
-					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
-					break;
+			case V4L2_PIX_FMT_RGB565:
+				*f++ = (0x1F & rv) |
+					(0xE0 & (gv << 5));
+				*f++ = (0x07 & (gv >> 3)) |
+					(0xF8 &  bv);
+				break;
+			case V4L2_PIX_FMT_RGB24:
+				*f++ = rv;
+				*f++ = gv;
+				*f++ = bv;
+				break;
+			case V4L2_PIX_FMT_RGB32:
+				*f++ = rv;
+				*f++ = gv;
+				*f++ = bv;
+				f++;
+				break;
+			case V4L2_PIX_FMT_RGB555:
+				*f++ = (0x1F & rv) |
+					(0xE0 & (gv << 5));
+				*f++ = (0x03 & (gv >> 3)) |
+					(0x7C & (bv << 2));
+				break;
 			}
 		}
 		clipmask_index += clipmask_add;
@@ -942,22 +959,26 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
 					*f++ = Y[Idx];
 					break;
 				case V4L2_PIX_FMT_RGB555:
-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2));
-					*f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1));
+					*f++ = (0x1F & rv) |
+						(0xE0 & (gv << 5));
+					*f++ = (0x03 & (gv >> 3)) |
+						(0x7C & (bv << 2));
 					break;
 				case V4L2_PIX_FMT_RGB565:
-					*f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3));
-					*f++ = (0x07 & (gv >> 5)) | (0xF8 &  rv);
+					*f++ = (0x1F & rv) |
+						(0xE0 & (gv << 5));
+					*f++ = (0x07 & (gv >> 3)) |
+						(0xF8 &  bv);
 					break;
 				case V4L2_PIX_FMT_RGB24:
-					*f++ = bv;
-					*f++ = gv;
 					*f++ = rv;
+					*f++ = gv;
+					*f++ = bv;
 					break;
 				case V4L2_PIX_FMT_RGB32:
-					*f++ = bv;
-					*f++ = gv;
 					*f++ = rv;
+					*f++ = gv;
+					*f++ = bv;
 					f++;
 					break;
 			}
@@ -1071,28 +1092,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
 				r_ = (y_ + ur) >> 16;
 
 				switch (frame->v4l2_format.format) {
-					case V4L2_PIX_FMT_RGB565:
-						g = LIMIT_RGB(g_);
-						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
-						*f_even++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
-						break;
-					case V4L2_PIX_FMT_RGB24:
-						*f_even++ = LIMIT_RGB(b_);
-						*f_even++ = LIMIT_RGB(g_);
-						*f_even++ = LIMIT_RGB(r_);
-						break;
-					case V4L2_PIX_FMT_RGB32:
-						*f_even++ = LIMIT_RGB(b_);
-						*f_even++ = LIMIT_RGB(g_);
-						*f_even++ = LIMIT_RGB(r_);
-						f_even++;
-						break;
-					case V4L2_PIX_FMT_RGB555:
-						g = LIMIT_RGB(g_);
-						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
-						*f_even++ = (0x03 & (          g   >> 6)) |
-							    (0x7C & (LIMIT_RGB(r_) >> 1));
-						break;
+				case V4L2_PIX_FMT_RGB565:
+					g = LIMIT_RGB(g_);
+					*f_even++ =
+						(0x1F & LIMIT_RGB(r_)) |
+						(0xE0 & (g << 5));
+					*f_even++ =
+						(0x07 & (g >> 3)) |
+						(0xF8 &  LIMIT_RGB(b_));
+					break;
+				case V4L2_PIX_FMT_RGB24:
+					*f_even++ = LIMIT_RGB(r_);
+					*f_even++ = LIMIT_RGB(g_);
+					*f_even++ = LIMIT_RGB(b_);
+					break;
+				case V4L2_PIX_FMT_RGB32:
+					*f_even++ = LIMIT_RGB(r_);
+					*f_even++ = LIMIT_RGB(g_);
+					*f_even++ = LIMIT_RGB(b_);
+					f_even++;
+					break;
+				case V4L2_PIX_FMT_RGB555:
+					g = LIMIT_RGB(g_);
+					*f_even++ = (0x1F & LIMIT_RGB(r_)) |
+						(0xE0 & (g << 5));
+					*f_even++ = (0x03 & (g >> 3)) |
+						(0x7C & (LIMIT_RGB(b_) << 2));
+					break;
 				}
 			}
 			clipmask_even_index += clipmask_add;
@@ -1110,28 +1136,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
 				r_ = (y_ + ur) >> 16;
 
 				switch (frame->v4l2_format.format) {
-					case V4L2_PIX_FMT_RGB565:
-						g = LIMIT_RGB(g_);
-						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
-						*f_even++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
-						break;
-					case V4L2_PIX_FMT_RGB24:
-						*f_even++ = LIMIT_RGB(b_);
-						*f_even++ = LIMIT_RGB(g_);
-						*f_even++ = LIMIT_RGB(r_);
-						break;
-					case V4L2_PIX_FMT_RGB32:
-						*f_even++ = LIMIT_RGB(b_);
-						*f_even++ = LIMIT_RGB(g_);
-						*f_even++ = LIMIT_RGB(r_);
-						f_even++;
-						break;
-					case V4L2_PIX_FMT_RGB555:
-						g = LIMIT_RGB(g_);
-						*f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
-						*f_even++ = (0x03 & (          g   >> 6)) |
-							    (0x7C & (LIMIT_RGB(r_) >> 1));
-						break;
+				case V4L2_PIX_FMT_RGB565:
+					g = LIMIT_RGB(g_);
+					*f_even++ =
+						(0x1F & LIMIT_RGB(r_)) |
+						(0xE0 & (g << 5));
+					*f_even++ =
+						(0x07 & (g >> 3)) |
+						(0xF8 &  LIMIT_RGB(b_));
+					break;
+				case V4L2_PIX_FMT_RGB24:
+					*f_even++ = LIMIT_RGB(r_);
+					*f_even++ = LIMIT_RGB(g_);
+					*f_even++ = LIMIT_RGB(b_);
+					break;
+				case V4L2_PIX_FMT_RGB32:
+					*f_even++ = LIMIT_RGB(r_);
+					*f_even++ = LIMIT_RGB(g_);
+					*f_even++ = LIMIT_RGB(b_);
+					f_even++;
+					break;
+				case V4L2_PIX_FMT_RGB555:
+					g = LIMIT_RGB(g_);
+					*f_even++ = (0x1F & LIMIT_RGB(r_)) |
+						(0xE0 & (g << 5));
+					*f_even++ = (0x03 & (g >> 3)) |
+						(0x7C & (LIMIT_RGB(b_) << 2));
+					break;
 				}
 			}
 			clipmask_even_index += clipmask_add;
@@ -1151,28 +1182,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
 				r_ = (y_ + ur) >> 16;
 
 				switch (frame->v4l2_format.format) {
-					case V4L2_PIX_FMT_RGB565:
-						g = LIMIT_RGB(g_);
-						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
-						*f_odd++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
-						break;
-					case V4L2_PIX_FMT_RGB24:
-						*f_odd++ = LIMIT_RGB(b_);
-						*f_odd++ = LIMIT_RGB(g_);
-						*f_odd++ = LIMIT_RGB(r_);
-						break;
-					case V4L2_PIX_FMT_RGB32:
-						*f_odd++ = LIMIT_RGB(b_);
-						*f_odd++ = LIMIT_RGB(g_);
-						*f_odd++ = LIMIT_RGB(r_);
-						f_odd++;
-						break;
-					case V4L2_PIX_FMT_RGB555:
-						g = LIMIT_RGB(g_);
-						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
-						*f_odd++ = (0x03 & (          g   >> 6)) |
-							   (0x7C & (LIMIT_RGB(r_) >> 1));
-						break;
+				case V4L2_PIX_FMT_RGB565:
+					g = LIMIT_RGB(g_);
+					*f_odd++ =
+						(0x1F & LIMIT_RGB(r_)) |
+						(0xE0 & (g << 5));
+					*f_odd++ =
+						(0x07 & (g >> 3)) |
+						(0xF8 &  LIMIT_RGB(b_));
+					break;
+				case V4L2_PIX_FMT_RGB24:
+					*f_odd++ = LIMIT_RGB(r_);
+					*f_odd++ = LIMIT_RGB(g_);
+					*f_odd++ = LIMIT_RGB(b_);
+					break;
+				case V4L2_PIX_FMT_RGB32:
+					*f_odd++ = LIMIT_RGB(r_);
+					*f_odd++ = LIMIT_RGB(g_);
+					*f_odd++ = LIMIT_RGB(b_);
+					f_odd++;
+					break;
+				case V4L2_PIX_FMT_RGB555:
+					g = LIMIT_RGB(g_);
+					*f_odd++ = (0x1F & LIMIT_RGB(r_)) |
+						(0xE0 & (g << 5));
+					*f_odd++ = (0x03 & (g >> 3)) |
+						(0x7C & (LIMIT_RGB(b_) << 2));
+					break;
 				}
 			}
 			clipmask_odd_index += clipmask_add;
@@ -1190,28 +1226,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
 				r_ = (y_ + ur) >> 16;
 
 				switch (frame->v4l2_format.format) {
-					case V4L2_PIX_FMT_RGB565:
-						g = LIMIT_RGB(g_);
-						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3));
-						*f_odd++ = (0x07 & (          g   >> 5)) | (0xF8 & LIMIT_RGB(r_));
-						break;
-					case V4L2_PIX_FMT_RGB24:
-						*f_odd++ = LIMIT_RGB(b_);
-						*f_odd++ = LIMIT_RGB(g_);
-						*f_odd++ = LIMIT_RGB(r_);
-						break;
-					case V4L2_PIX_FMT_RGB32:
-						*f_odd++ = LIMIT_RGB(b_);
-						*f_odd++ = LIMIT_RGB(g_);
-						*f_odd++ = LIMIT_RGB(r_);
-						f_odd++;
-						break;
-					case V4L2_PIX_FMT_RGB555:
-						g = LIMIT_RGB(g_);
-						*f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2));
-						*f_odd++ = (0x03 & (          g   >> 6)) |
-							   (0x7C & (LIMIT_RGB(r_) >> 1));
-						break;
+				case V4L2_PIX_FMT_RGB565:
+					g = LIMIT_RGB(g_);
+					*f_odd++ =
+						(0x1F & LIMIT_RGB(r_)) |
+						(0xE0 & (g << 5));
+					*f_odd++ =
+						(0x07 & (g >> 3)) |
+						(0xF8 &  LIMIT_RGB(b_));
+					break;
+				case V4L2_PIX_FMT_RGB24:
+					*f_odd++ = LIMIT_RGB(r_);
+					*f_odd++ = LIMIT_RGB(g_);
+					*f_odd++ = LIMIT_RGB(b_);
+					break;
+				case V4L2_PIX_FMT_RGB32:
+					*f_odd++ = LIMIT_RGB(r_);
+					*f_odd++ = LIMIT_RGB(g_);
+					*f_odd++ = LIMIT_RGB(b_);
+					f_odd++;
+					break;
+				case V4L2_PIX_FMT_RGB555:
+					g = LIMIT_RGB(g_);
+					*f_odd++ = (0x1F & LIMIT_RGB(r_)) |
+						(0xE0 & (g << 5));
+					*f_odd++ = (0x03 & (g >> 3)) |
+						(0x7C & (LIMIT_RGB(b_) << 2));
+					break;
 				}
 			}
 			clipmask_odd_index += clipmask_add;
@@ -1561,13 +1602,10 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address,
 	if (len > 8) {
 		return -EFAULT;
 	}
-//	down(&usbvision->ctrlUrbLock);
 	if (usbvision->ctrlUrbBusy) {
-//		up(&usbvision->ctrlUrbLock);
 		return -EBUSY;
 	}
 	usbvision->ctrlUrbBusy = 1;
-//	up(&usbvision->ctrlUrbLock);
 
 	usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
 	usbvision->ctrlUrbSetup.bRequest     = USBVISION_OP_CODE;
@@ -2100,11 +2138,21 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
 		value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8;
 	}
 
+	if (adjust_X_Offset != -1) {
+		value[4] = adjust_X_Offset & 0xff;
+		value[5] = (adjust_X_Offset & 0x0300) >> 8;
+	}
+
 	if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) {
 		value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff;
 		value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8;
 	}
 
+	if (adjust_Y_Offset != -1) {
+		value[6] = adjust_Y_Offset & 0xff;
+		value[7] = (adjust_Y_Offset & 0x0300) >> 8;
+	}
+
 	rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
 			     USBVISION_OP_CODE,	/* USBVISION specific code */
 			     USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0,
@@ -2242,14 +2290,18 @@ static void call_usbvision_power_off(struct work_struct *work)
 	struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork);
 
 	PDEBUG(DBG_FUNC, "");
-	down_interruptible(&usbvision->lock);
+	if(mutex_lock_interruptible(&usbvision->lock)) {
+		return;
+	}
+
+
 	if(usbvision->user == 0) {
 		usbvision_i2c_unregister(usbvision);
 
 		usbvision_power_off(usbvision);
 		usbvision->initialized = 0;
 	}
-	up(&usbvision->lock);
+	mutex_unlock(&usbvision->lock);
 }
 
 static void usbvision_powerOffTimer(unsigned long data)
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 36e689fa16c0..b52b826a30be 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -410,7 +410,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
 
 	/* If so far no errors then we shall start the camera */
 	if (!errCode) {
-		down(&usbvision->lock);
+		mutex_lock(&usbvision->lock);
 		if (usbvision->power == 0) {
 			usbvision_power_on(usbvision);
 			usbvision_i2c_register(usbvision);
@@ -439,7 +439,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
 				usbvision->initialized = 0;
 			}
 		}
-		up(&usbvision->lock);
+		mutex_unlock(&usbvision->lock);
 	}
 
 	if (errCode) {
@@ -467,7 +467,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
 		(struct usb_usbvision *) video_get_drvdata(dev);
 
 	PDEBUG(DBG_IO, "close");
-	down(&usbvision->lock);
+	mutex_lock(&usbvision->lock);
 
 	usbvision_audio_off(usbvision);
 	usbvision_restart_isoc(usbvision);
@@ -487,7 +487,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
 		usbvision->initialized = 0;
 	}
 
-	up(&usbvision->lock);
+	mutex_unlock(&usbvision->lock);
 
 	if (usbvision->remove_pending) {
 		printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
@@ -647,13 +647,13 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
 	if ((input >= usbvision->video_inputs) || (input < 0) )
 		return -EINVAL;
 
-	down(&usbvision->lock);
+	mutex_lock(&usbvision->lock);
 	usbvision_muxsel(usbvision, input);
 	usbvision_set_input(usbvision);
 	usbvision_set_output(usbvision,
 			     usbvision->curwidth,
 			     usbvision->curheight);
-	up(&usbvision->lock);
+	mutex_unlock(&usbvision->lock);
 	return 0;
 }
 
@@ -664,10 +664,10 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
 		(struct usb_usbvision *) video_get_drvdata(dev);
 	usbvision->tvnormId=*id;
 
-	down(&usbvision->lock);
+	mutex_lock(&usbvision->lock);
 	call_i2c_clients(usbvision, VIDIOC_S_STD,
 			 &usbvision->tvnormId);
-	up(&usbvision->lock);
+	mutex_unlock(&usbvision->lock);
 	/* propagate the change to the decoder */
 	usbvision_muxsel(usbvision, usbvision->ctl_input);
 
@@ -1083,9 +1083,9 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
 	usbvision->curFrame = NULL;
 
 	/* by now we are committed to the new data... */
-	down(&usbvision->lock);
+	mutex_lock(&usbvision->lock);
 	usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
-	up(&usbvision->lock);
+	mutex_unlock(&usbvision->lock);
 
 	return 0;
 }
@@ -1211,16 +1211,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 
 	PDEBUG(DBG_MMAP, "mmap");
 
-	down(&usbvision->lock);
+	mutex_lock(&usbvision->lock);
 
 	if (!USBVISION_IS_OPERATIONAL(usbvision)) {
-		up(&usbvision->lock);
+		mutex_unlock(&usbvision->lock);
 		return -EFAULT;
 	}
 
 	if (!(vma->vm_flags & VM_WRITE) ||
 	    size != PAGE_ALIGN(usbvision->max_frame_size)) {
-		up(&usbvision->lock);
+		mutex_unlock(&usbvision->lock);
 		return -EINVAL;
 	}
 
@@ -1232,7 +1232,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 	if (i == usbvision->num_frames) {
 		PDEBUG(DBG_MMAP,
 		       "mmap: user supplied mapping address is out of range");
-		up(&usbvision->lock);
+		mutex_unlock(&usbvision->lock);
 		return -EINVAL;
 	}
 
@@ -1245,7 +1245,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 
 		if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
 			PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed");
-			up(&usbvision->lock);
+			mutex_unlock(&usbvision->lock);
 			return -EAGAIN;
 		}
 		start += PAGE_SIZE;
@@ -1253,7 +1253,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 		size -= PAGE_SIZE;
 	}
 
-	up(&usbvision->lock);
+	mutex_unlock(&usbvision->lock);
 	return 0;
 }
 
@@ -1271,7 +1271,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
 
 	PDEBUG(DBG_IO, "%s:", __FUNCTION__);
 
-	down(&usbvision->lock);
+	mutex_lock(&usbvision->lock);
 
 	if (usbvision->user) {
 		err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__);
@@ -1290,7 +1290,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
 		errCode = usbvision_set_alternate(usbvision);
 		if (errCode < 0) {
 			usbvision->last_error = errCode;
-			return -EBUSY;
+			errCode = -EBUSY;
+			goto out;
 		}
 
 		// If so far no errors then we shall start the radio
@@ -1307,7 +1308,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
 			usbvision->initialized = 0;
 		}
 	}
-	up(&usbvision->lock);
+out:
+	mutex_unlock(&usbvision->lock);
 	return errCode;
 }
 
@@ -1321,7 +1323,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
 
 	PDEBUG(DBG_IO, "");
 
-	down(&usbvision->lock);
+	mutex_lock(&usbvision->lock);
 
 	/* Set packet size to 0 */
 	usbvision->ifaceAlt=0;
@@ -1337,7 +1339,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
 		usbvision->initialized = 0;
 	}
 
-	up(&usbvision->lock);
+	mutex_unlock(&usbvision->lock);
 
 	if (usbvision->remove_pending) {
 		printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
@@ -1641,7 +1643,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
 
 	usbvision->dev = dev;
 
-	init_MUTEX(&usbvision->lock);	/* to 1 == available */
+	mutex_init(&usbvision->lock);	/* available */
 
 	// prepare control urb for control messages during interrupts
 	usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
@@ -1649,7 +1651,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
 		goto err_exit;
 	}
 	init_waitqueue_head(&usbvision->ctrlUrb_wq);
-	init_MUTEX(&usbvision->ctrlUrbLock);	/* to 1 == available */
 
 	usbvision_init_powerOffTimer(usbvision);
 
@@ -1676,13 +1677,13 @@ static void usbvision_release(struct usb_usbvision *usbvision)
 {
 	PDEBUG(DBG_PROBE, "");
 
-	down(&usbvision->lock);
+	mutex_lock(&usbvision->lock);
 
 	usbvision_reset_powerOffTimer(usbvision);
 
 	usbvision->initialized = 0;
 
-	up(&usbvision->lock);
+	mutex_unlock(&usbvision->lock);
 
 	usbvision_remove_sysfs(usbvision->vdev);
 	usbvision_unregister_video(usbvision);
@@ -1796,7 +1797,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
 	}
 	PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
 
-	down(&usbvision->lock);
+	mutex_lock(&usbvision->lock);
 
 	/* compute alternate max packet sizes */
 	uif = dev->actconfig->interface[0];
@@ -1807,6 +1808,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
 					      usbvision->num_alt,GFP_KERNEL);
 	if (usbvision->alt_max_pkt_size == NULL) {
 		err("usbvision: out of memory!\n");
+		mutex_unlock(&usbvision->lock);
 		return -ENOMEM;
 	}
 
@@ -1840,7 +1842,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
 	usbvision->streaming = Stream_Off;
 	usbvision_register_video(usbvision);
 	usbvision_configure_video(usbvision);
-	up(&usbvision->lock);
+	mutex_unlock(&usbvision->lock);
 
 
 	usb_set_intfdata (intf, usbvision);
@@ -1871,7 +1873,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
 	}
 	usb_set_intfdata (intf, NULL);
 
-	down(&usbvision->lock);
+	mutex_lock(&usbvision->lock);
 
 	// At this time we ask to cancel outstanding URBs
 	usbvision_stop_isoc(usbvision);
@@ -1885,7 +1887,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
 	usb_put_dev(usbvision->dev);
 	usbvision->dev = NULL;	// USB device is no more
 
-	up(&usbvision->lock);
+	mutex_unlock(&usbvision->lock);
 
 	if (usbvision->user) {
 		printk(KERN_INFO "%s: In use, disconnect pending\n",
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index c5b6c501c869..20d7ec624999 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -34,16 +34,13 @@
 #include <linux/list.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
+#include <linux/mutex.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
 #include <linux/videodev2.h>
 
 #define USBVISION_DEBUG		/* Turn on debug messages */
 
-#ifndef VID_HARDWARE_USBVISION
-	#define VID_HARDWARE_USBVISION 34   /* USBVision Video Grabber */
-#endif
-
 #define USBVISION_PWR_REG		0x00
 	#define USBVISION_SSPND_EN		(1 << 1)
 	#define USBVISION_RES2			(1 << 2)
@@ -373,7 +370,6 @@ struct usb_usbvision {
 	int ctrlUrbBusy;
 	struct usb_ctrlrequest ctrlUrbSetup;
 	wait_queue_head_t ctrlUrb_wq;					// Processes waiting
-	struct semaphore ctrlUrbLock;
 
 	/* configuration part */
 	int have_tuner;
@@ -396,7 +392,7 @@ struct usb_usbvision {
 	unsigned char iface;						/* Video interface number */
 	unsigned char ifaceAlt;			/* Alt settings */
 	unsigned char Vin_Reg2_Preset;
-	struct semaphore lock;
+	struct mutex               lock;
 	struct timer_list powerOffTimer;
 	struct work_struct powerOffWork;
 	int power;							/* is the device powered on? */
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 1141b4bf41ce..c056ff6d810c 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -400,7 +400,7 @@ static const char *v4l2_int_ioctls[] = {
 
 	[_IOC_NR(TUNER_SET_TYPE_ADDR)]         = "TUNER_SET_TYPE_ADDR",
 	[_IOC_NR(TUNER_SET_STANDBY)]           = "TUNER_SET_STANDBY",
-	[_IOC_NR(TDA9887_SET_CONFIG)]          = "TDA9887_SET_CONFIG",
+	[_IOC_NR(TUNER_SET_CONFIG)]            = "TUNER_SET_CONFIG",
 
 	[_IOC_NR(VIDIOC_INT_S_TUNER_MODE)]     = "VIDIOC_INT_S_TUNER_MODE",
 	[_IOC_NR(VIDIOC_INT_RESET)]            = "VIDIOC_INT_RESET",
@@ -1013,6 +1013,34 @@ int v4l2_chip_match_host(u32 match_type, u32 match_chip)
 
 /* ----------------------------------------------------------------- */
 
+/* Helper function for I2C legacy drivers */
+
+int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
+		const char *name, int (*probe)(struct i2c_client *))
+{
+	struct i2c_client *client;
+	int err;
+
+	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = driver;
+	strlcpy(client->name, name, sizeof(client->name));
+
+	err = probe(client);
+	if (err == 0) {
+		i2c_attach_client(client);
+	} else {
+		kfree(client);
+	}
+	return err != -ENOMEM ? 0 : err;
+}
+
+/* ----------------------------------------------------------------- */
+
 EXPORT_SYMBOL(v4l2_norm_to_name);
 EXPORT_SYMBOL(v4l2_video_std_construct);
 
@@ -1038,6 +1066,8 @@ EXPORT_SYMBOL(v4l2_chip_match_i2c_client);
 EXPORT_SYMBOL(v4l2_chip_ident_i2c_client);
 EXPORT_SYMBOL(v4l2_chip_match_host);
 
+EXPORT_SYMBOL(v4l2_i2c_attach);
+
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c
index 8b4ef530a3a8..a545dcaf857f 100644
--- a/drivers/media/video/v4l2-int-device.c
+++ b/drivers/media/video/v4l2-int-device.c
@@ -57,12 +57,12 @@ static void v4l2_int_device_try_attach_all(void)
 			if (!try_module_get(m->module))
 				continue;
 
-			if (m->u.master->attach(m, s)) {
+			s->u.slave->master = m;
+			if (m->u.master->attach(s)) {
+				s->u.slave->master = NULL;
 				module_put(m->module);
 				continue;
 			}
-
-			s->u.slave->master = m;
 		}
 	}
 }
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index c8a5cb57963b..80a14da9acef 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -22,29 +22,32 @@
 #include <media/videobuf-core.h>
 
 #define MAGIC_BUFFER 0x20070728
-#define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
-	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+#define MAGIC_CHECK(is, should) do {					   \
+	if (unlikely((is) != (should))) {				   \
+	printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \
+	BUG(); } } while (0)
 
-static int debug = 0;
+static int debug;
 module_param(debug, int, 0644);
 
 MODULE_DESCRIPTION("helper module to manage video4linux buffers");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 
-#define dprintk(level, fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG "vbuf: " fmt , ## arg)
+#define dprintk(level, fmt, arg...) do {			\
+	if (debug >= level) 					\
+	printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0)
 
 /* --------------------------------------------------------------------- */
 
 #define CALL(q, f, arg...)						\
-	( (q->int_ops->f)? q->int_ops->f(arg) : 0)
+	((q->int_ops->f) ? q->int_ops->f(arg) : 0)
 
-void* videobuf_alloc(struct videobuf_queue* q)
+void *videobuf_alloc(struct videobuf_queue *q)
 {
 	struct videobuf_buffer *vb;
 
-	BUG_ON (q->msize<sizeof(*vb));
+	BUG_ON(q->msize < sizeof(*vb));
 
 	if (!q->int_ops || !q->int_ops->alloc) {
 		printk(KERN_ERR "No specific ops defined!\n");
@@ -66,20 +69,21 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
 	int retval = 0;
 	DECLARE_WAITQUEUE(wait, current);
 
-	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
+	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
 	add_wait_queue(&vb->done, &wait);
-	while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) {
+	while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) {
 		if (non_blocking) {
 			retval = -EAGAIN;
 			break;
 		}
 		set_current_state(intr  ? TASK_INTERRUPTIBLE
 					: TASK_UNINTERRUPTIBLE);
-		if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED)
+		if (vb->state == VIDEOBUF_ACTIVE ||
+		    vb->state == VIDEOBUF_QUEUED)
 			schedule();
 		set_current_state(TASK_RUNNING);
 		if (intr && signal_pending(current)) {
-			dprintk(1,"buffer waiton: -EINTR\n");
+			dprintk(1, "buffer waiton: -EINTR\n");
 			retval = -EINTR;
 			break;
 		}
@@ -88,27 +92,33 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
 	return retval;
 }
 
-int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
+int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
 		    struct v4l2_framebuffer *fbuf)
 {
-	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-	/* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper()
-	   method should be called before _iolock.
+	/* This is required to avoid OOPS on some cases,
+	   since mmap_mapper() method should be called before _iolock.
 	   On some cases, the mmap_mapper() is called only after scheduling.
-
-	   However, this way is just too dirty! Better to wait for some event.
 	 */
-	schedule_timeout(HZ);
+	if (vb->memory == V4L2_MEMORY_MMAP) {
+		wait_event_timeout(vb->done, q->is_mmapped,
+				   msecs_to_jiffies(100));
+		if (!q->is_mmapped) {
+			printk(KERN_ERR
+			       "Error: mmap_mapper() never called!\n");
+			return -EINVAL;
+		}
+	}
 
-	return CALL(q,iolock,q,vb,fbuf);
+	return CALL(q, iolock, q, vb, fbuf);
 }
 
 /* --------------------------------------------------------------------- */
 
 
-void videobuf_queue_core_init(struct videobuf_queue* q,
+void videobuf_queue_core_init(struct videobuf_queue *q,
 			 struct videobuf_queue_ops *ops,
 			 void *dev,
 			 spinlock_t *irqlock,
@@ -118,7 +128,7 @@ void videobuf_queue_core_init(struct videobuf_queue* q,
 			 void *priv,
 			 struct videobuf_qtype_ops *int_ops)
 {
-	memset(q,0,sizeof(*q));
+	memset(q, 0, sizeof(*q));
 	q->irqlock   = irqlock;
 	q->dev       = dev;
 	q->type      = type;
@@ -129,13 +139,13 @@ void videobuf_queue_core_init(struct videobuf_queue* q,
 	q->int_ops   = int_ops;
 
 	/* All buffer operations are mandatory */
-	BUG_ON (!q->ops->buf_setup);
-	BUG_ON (!q->ops->buf_prepare);
-	BUG_ON (!q->ops->buf_queue);
-	BUG_ON (!q->ops->buf_release);
+	BUG_ON(!q->ops->buf_setup);
+	BUG_ON(!q->ops->buf_prepare);
+	BUG_ON(!q->ops->buf_queue);
+	BUG_ON(!q->ops->buf_release);
 
 	/* Having implementations for abstract methods are mandatory */
-	BUG_ON (!q->int_ops);
+	BUG_ON(!q->int_ops);
 
 	mutex_init(&q->lock);
 	INIT_LIST_HEAD(&q->stream);
@@ -146,33 +156,33 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
 {
 	int i;
 
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	if (q->streaming) {
-		dprintk(1,"busy: streaming active\n");
+		dprintk(1, "busy: streaming active\n");
 		return 1;
 	}
 	if (q->reading) {
-		dprintk(1,"busy: pending read #1\n");
+		dprintk(1, "busy: pending read #1\n");
 		return 1;
 	}
 	if (q->read_buf) {
-		dprintk(1,"busy: pending read #2\n");
+		dprintk(1, "busy: pending read #2\n");
 		return 1;
 	}
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 		if (NULL == q->bufs[i])
 			continue;
 		if (q->bufs[i]->map) {
-			dprintk(1,"busy: buffer #%d mapped\n",i);
+			dprintk(1, "busy: buffer #%d mapped\n", i);
 			return 1;
 		}
-		if (q->bufs[i]->state == STATE_QUEUED) {
-			dprintk(1,"busy: buffer #%d queued\n",i);
+		if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
+			dprintk(1, "busy: buffer #%d queued\n", i);
 			return 1;
 		}
-		if (q->bufs[i]->state == STATE_ACTIVE) {
-			dprintk(1,"busy: buffer #%d avtive\n",i);
+		if (q->bufs[i]->state == VIDEOBUF_ACTIVE) {
+			dprintk(1, "busy: buffer #%d avtive\n", i);
 			return 1;
 		}
 	}
@@ -182,28 +192,28 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
 /* Locking: Caller holds q->lock */
 void videobuf_queue_cancel(struct videobuf_queue *q)
 {
-	unsigned long flags=0;
+	unsigned long flags = 0;
 	int i;
 
 	/* remove queued buffers from list */
 	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock,flags);
+		spin_lock_irqsave(q->irqlock, flags);
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 		if (NULL == q->bufs[i])
 			continue;
-		if (q->bufs[i]->state == STATE_QUEUED) {
+		if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
 			list_del(&q->bufs[i]->queue);
-			q->bufs[i]->state = STATE_ERROR;
+			q->bufs[i]->state = VIDEOBUF_ERROR;
 		}
 	}
 	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock,flags);
+		spin_unlock_irqrestore(q->irqlock, flags);
 
 	/* free all buffers + clear queue */
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 		if (NULL == q->bufs[i])
 			continue;
-		q->ops->buf_release(q,q->bufs[i]);
+		q->ops->buf_release(q, q->bufs[i]);
 	}
 	INIT_LIST_HEAD(&q->stream);
 }
@@ -233,8 +243,8 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
 static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
 			    struct videobuf_buffer *vb, enum v4l2_buf_type type)
 {
-	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	b->index    = vb->i;
 	b->type     = type;
@@ -259,17 +269,17 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
 		b->flags |= V4L2_BUF_FLAG_MAPPED;
 
 	switch (vb->state) {
-	case STATE_PREPARED:
-	case STATE_QUEUED:
-	case STATE_ACTIVE:
+	case VIDEOBUF_PREPARED:
+	case VIDEOBUF_QUEUED:
+	case VIDEOBUF_ACTIVE:
 		b->flags |= V4L2_BUF_FLAG_QUEUED;
 		break;
-	case STATE_DONE:
-	case STATE_ERROR:
+	case VIDEOBUF_DONE:
+	case VIDEOBUF_ERROR:
 		b->flags |= V4L2_BUF_FLAG_DONE;
 		break;
-	case STATE_NEEDS_INIT:
-	case STATE_IDLE:
+	case VIDEOBUF_NEEDS_INIT:
+	case VIDEOBUF_IDLE:
 		/* nothing */
 		break;
 	}
@@ -294,16 +304,20 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
 	if (!q)
 		return 0;
 
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+
+	rc  = CALL(q, mmap_free, q);
+
+	q->is_mmapped = 0;
 
-	rc  = CALL(q,mmap_free,q);
-	if (rc<0)
+	if (rc < 0)
 		return rc;
 
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 		if (NULL == q->bufs[i])
 			continue;
-		q->ops->buf_release(q,q->bufs[i]);
+		q->ops->buf_release(q, q->bufs[i]);
 		kfree(q->bufs[i]);
 		q->bufs[i] = NULL;
 	}
@@ -328,7 +342,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
 	unsigned int i;
 	int err;
 
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	err = __videobuf_mmap_free(q);
 	if (0 != err)
@@ -359,7 +373,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
 	if (!i)
 		return -ENOMEM;
 
-	dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
+	dprintk(1, "mmap setup: %d buffers, %d bytes each\n",
 		i, bsize);
 
 	return i;
@@ -379,35 +393,35 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
 int videobuf_reqbufs(struct videobuf_queue *q,
 		 struct v4l2_requestbuffers *req)
 {
-	unsigned int size,count;
+	unsigned int size, count;
 	int retval;
 
 	if (req->count < 1) {
-		dprintk(1,"reqbufs: count invalid (%d)\n",req->count);
+		dprintk(1, "reqbufs: count invalid (%d)\n", req->count);
 		return -EINVAL;
 	}
 
 	if (req->memory != V4L2_MEMORY_MMAP     &&
 	    req->memory != V4L2_MEMORY_USERPTR  &&
 	    req->memory != V4L2_MEMORY_OVERLAY) {
-		dprintk(1,"reqbufs: memory type invalid\n");
+		dprintk(1, "reqbufs: memory type invalid\n");
 		return -EINVAL;
 	}
 
 	mutex_lock(&q->lock);
 	if (req->type != q->type) {
-		dprintk(1,"reqbufs: queue type invalid\n");
+		dprintk(1, "reqbufs: queue type invalid\n");
 		retval = -EINVAL;
 		goto done;
 	}
 
 	if (q->streaming) {
-		dprintk(1,"reqbufs: streaming already exists\n");
+		dprintk(1, "reqbufs: streaming already exists\n");
 		retval = -EBUSY;
 		goto done;
 	}
 	if (!list_empty(&q->stream)) {
-		dprintk(1,"reqbufs: stream running\n");
+		dprintk(1, "reqbufs: stream running\n");
 		retval = -EBUSY;
 		goto done;
 	}
@@ -416,14 +430,14 @@ int videobuf_reqbufs(struct videobuf_queue *q,
 	if (count > VIDEO_MAX_FRAME)
 		count = VIDEO_MAX_FRAME;
 	size = 0;
-	q->ops->buf_setup(q,&count,&size);
+	q->ops->buf_setup(q, &count, &size);
 	size = PAGE_ALIGN(size);
-	dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
+	dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
 		count, size, (count*size)>>PAGE_SHIFT);
 
-	retval = __videobuf_mmap_setup(q,count,size,req->memory);
+	retval = __videobuf_mmap_setup(q, count, size, req->memory);
 	if (retval < 0) {
-		dprintk(1,"reqbufs: mmap setup returned %d\n",retval);
+		dprintk(1, "reqbufs: mmap setup returned %d\n", retval);
 		goto done;
 	}
 
@@ -440,19 +454,19 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
 
 	mutex_lock(&q->lock);
 	if (unlikely(b->type != q->type)) {
-		dprintk(1,"querybuf: Wrong type.\n");
+		dprintk(1, "querybuf: Wrong type.\n");
 		goto done;
 	}
 	if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) {
-		dprintk(1,"querybuf: index out of range.\n");
+		dprintk(1, "querybuf: index out of range.\n");
 		goto done;
 	}
 	if (unlikely(NULL == q->bufs[b->index])) {
-		dprintk(1,"querybuf: buffer is null.\n");
+		dprintk(1, "querybuf: buffer is null.\n");
 		goto done;
 	}
 
-	videobuf_status(q,b,q->bufs[b->index],q->type);
+	videobuf_status(q, b, q->bufs[b->index], q->type);
 
 	ret = 0;
 done:
@@ -465,10 +479,10 @@ int videobuf_qbuf(struct videobuf_queue *q,
 {
 	struct videobuf_buffer *buf;
 	enum v4l2_field field;
-	unsigned long flags=0;
+	unsigned long flags = 0;
 	int retval;
 
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	if (b->memory == V4L2_MEMORY_MMAP)
 		down_read(&current->mm->mmap_sem);
@@ -476,36 +490,36 @@ int videobuf_qbuf(struct videobuf_queue *q,
 	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->reading) {
-		dprintk(1,"qbuf: Reading running...\n");
+		dprintk(1, "qbuf: Reading running...\n");
 		goto done;
 	}
 	retval = -EINVAL;
 	if (b->type != q->type) {
-		dprintk(1,"qbuf: Wrong type.\n");
+		dprintk(1, "qbuf: Wrong type.\n");
 		goto done;
 	}
 	if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
-		dprintk(1,"qbuf: index out of range.\n");
+		dprintk(1, "qbuf: index out of range.\n");
 		goto done;
 	}
 	buf = q->bufs[b->index];
 	if (NULL == buf) {
-		dprintk(1,"qbuf: buffer is null.\n");
+		dprintk(1, "qbuf: buffer is null.\n");
 		goto done;
 	}
-	MAGIC_CHECK(buf->magic,MAGIC_BUFFER);
+	MAGIC_CHECK(buf->magic, MAGIC_BUFFER);
 	if (buf->memory != b->memory) {
-		dprintk(1,"qbuf: memory type is wrong.\n");
+		dprintk(1, "qbuf: memory type is wrong.\n");
 		goto done;
 	}
-	if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) {
-		dprintk(1,"qbuf: buffer is already queued or active.\n");
+	if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) {
+		dprintk(1, "qbuf: buffer is already queued or active.\n");
 		goto done;
 	}
 
 	if (b->flags & V4L2_BUF_FLAG_INPUT) {
 		if (b->input >= q->inputs) {
-			dprintk(1,"qbuf: wrong input.\n");
+			dprintk(1, "qbuf: wrong input.\n");
 			goto done;
 		}
 		buf->input = b->input;
@@ -516,44 +530,46 @@ int videobuf_qbuf(struct videobuf_queue *q,
 	switch (b->memory) {
 	case V4L2_MEMORY_MMAP:
 		if (0 == buf->baddr) {
-			dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n");
+			dprintk(1, "qbuf: mmap requested "
+				   "but buffer addr is zero!\n");
 			goto done;
 		}
 		break;
 	case V4L2_MEMORY_USERPTR:
 		if (b->length < buf->bsize) {
-			dprintk(1,"qbuf: buffer length is not enough\n");
+			dprintk(1, "qbuf: buffer length is not enough\n");
 			goto done;
 		}
-		if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr)
-			q->ops->buf_release(q,buf);
+		if (VIDEOBUF_NEEDS_INIT != buf->state &&
+		    buf->baddr != b->m.userptr)
+			q->ops->buf_release(q, buf);
 		buf->baddr = b->m.userptr;
 		break;
 	case V4L2_MEMORY_OVERLAY:
 		buf->boff = b->m.offset;
 		break;
 	default:
-		dprintk(1,"qbuf: wrong memory type\n");
+		dprintk(1, "qbuf: wrong memory type\n");
 		goto done;
 	}
 
-	dprintk(1,"qbuf: requesting next field\n");
+	dprintk(1, "qbuf: requesting next field\n");
 	field = videobuf_next_field(q);
-	retval = q->ops->buf_prepare(q,buf,field);
+	retval = q->ops->buf_prepare(q, buf, field);
 	if (0 != retval) {
-		dprintk(1,"qbuf: buffer_prepare returned %d\n",retval);
+		dprintk(1, "qbuf: buffer_prepare returned %d\n", retval);
 		goto done;
 	}
 
-	list_add_tail(&buf->stream,&q->stream);
+	list_add_tail(&buf->stream, &q->stream);
 	if (q->streaming) {
 		if (q->irqlock)
-			spin_lock_irqsave(q->irqlock,flags);
-		q->ops->buf_queue(q,buf);
+			spin_lock_irqsave(q->irqlock, flags);
+		q->ops->buf_queue(q, buf);
 		if (q->irqlock)
-			spin_unlock_irqrestore(q->irqlock,flags);
+			spin_unlock_irqrestore(q->irqlock, flags);
 	}
-	dprintk(1,"qbuf: succeded\n");
+	dprintk(1, "qbuf: succeded\n");
 	retval = 0;
 
  done:
@@ -571,49 +587,49 @@ int videobuf_dqbuf(struct videobuf_queue *q,
 	struct videobuf_buffer *buf;
 	int retval;
 
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->reading) {
-		dprintk(1,"dqbuf: Reading running...\n");
+		dprintk(1, "dqbuf: Reading running...\n");
 		goto done;
 	}
 	retval = -EINVAL;
 	if (b->type != q->type) {
-		dprintk(1,"dqbuf: Wrong type.\n");
+		dprintk(1, "dqbuf: Wrong type.\n");
 		goto done;
 	}
 	if (list_empty(&q->stream)) {
-		dprintk(1,"dqbuf: stream running\n");
+		dprintk(1, "dqbuf: stream running\n");
 		goto done;
 	}
 	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
 	retval = videobuf_waiton(buf, nonblocking, 1);
 	if (retval < 0) {
-		dprintk(1,"dqbuf: waiton returned %d\n",retval);
+		dprintk(1, "dqbuf: waiton returned %d\n", retval);
 		goto done;
 	}
 	switch (buf->state) {
-	case STATE_ERROR:
-		dprintk(1,"dqbuf: state is error\n");
+	case VIDEOBUF_ERROR:
+		dprintk(1, "dqbuf: state is error\n");
 		retval = -EIO;
-		CALL(q,sync,q, buf);
-		buf->state = STATE_IDLE;
+		CALL(q, sync, q, buf);
+		buf->state = VIDEOBUF_IDLE;
 		break;
-	case STATE_DONE:
-		dprintk(1,"dqbuf: state is done\n");
-		CALL(q,sync,q, buf);
-		buf->state = STATE_IDLE;
+	case VIDEOBUF_DONE:
+		dprintk(1, "dqbuf: state is done\n");
+		CALL(q, sync, q, buf);
+		buf->state = VIDEOBUF_IDLE;
 		break;
 	default:
-		dprintk(1,"dqbuf: state invalid\n");
+		dprintk(1, "dqbuf: state invalid\n");
 		retval = -EINVAL;
 		goto done;
 	}
 	list_del(&buf->stream);
-	memset(b,0,sizeof(*b));
-	videobuf_status(q,b,buf,q->type);
+	memset(b, 0, sizeof(*b));
+	videobuf_status(q, b, buf, q->type);
 
  done:
 	mutex_unlock(&q->lock);
@@ -623,7 +639,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
 int videobuf_streamon(struct videobuf_queue *q)
 {
 	struct videobuf_buffer *buf;
-	unsigned long flags=0;
+	unsigned long flags = 0;
 	int retval;
 
 	mutex_lock(&q->lock);
@@ -635,12 +651,12 @@ int videobuf_streamon(struct videobuf_queue *q)
 		goto done;
 	q->streaming = 1;
 	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock,flags);
+		spin_lock_irqsave(q->irqlock, flags);
 	list_for_each_entry(buf, &q->stream, stream)
-		if (buf->state == STATE_PREPARED)
-			q->ops->buf_queue(q,buf);
+		if (buf->state == VIDEOBUF_PREPARED)
+			q->ops->buf_queue(q, buf);
 	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock,flags);
+		spin_unlock_irqrestore(q->irqlock, flags);
 
  done:
 	mutex_unlock(&q->lock);
@@ -676,10 +692,10 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
 				      size_t count, loff_t *ppos)
 {
 	enum v4l2_field field;
-	unsigned long flags=0;
+	unsigned long flags = 0;
 	int retval;
 
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	/* setup stuff */
 	q->read_buf = videobuf_alloc(q);
@@ -691,20 +707,20 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
 	q->read_buf->bsize  = count;
 
 	field = videobuf_next_field(q);
-	retval = q->ops->buf_prepare(q,q->read_buf,field);
+	retval = q->ops->buf_prepare(q, q->read_buf, field);
 	if (0 != retval)
 		goto done;
 
 	/* start capture & wait */
 	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock,flags);
-	q->ops->buf_queue(q,q->read_buf);
+		spin_lock_irqsave(q->irqlock, flags);
+	q->ops->buf_queue(q, q->read_buf);
 	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock,flags);
-	retval = videobuf_waiton(q->read_buf,0,0);
+		spin_unlock_irqrestore(q->irqlock, flags);
+	retval = videobuf_waiton(q->read_buf, 0, 0);
 	if (0 == retval) {
-		CALL(q,sync,q,q->read_buf);
-		if (STATE_ERROR == q->read_buf->state)
+		CALL(q, sync, q, q->read_buf);
+		if (VIDEOBUF_ERROR == q->read_buf->state)
 			retval = -EIO;
 		else
 			retval = q->read_buf->size;
@@ -712,7 +728,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
 
  done:
 	/* cleanup */
-	q->ops->buf_release(q,q->read_buf);
+	q->ops->buf_release(q, q->read_buf);
 	kfree(q->read_buf);
 	q->read_buf = NULL;
 	return retval;
@@ -723,21 +739,21 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
 			  int nonblocking)
 {
 	enum v4l2_field field;
-	unsigned long flags=0;
+	unsigned long flags = 0;
 	unsigned size, nbufs;
 	int retval;
 
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	mutex_lock(&q->lock);
 
 	nbufs = 1; size = 0;
-	q->ops->buf_setup(q,&nbufs,&size);
+	q->ops->buf_setup(q, &nbufs, &size);
 
 	if (NULL == q->read_buf  &&
 	    count >= size        &&
 	    !nonblocking) {
-		retval = videobuf_read_zerocopy(q,data,count,ppos);
+		retval = videobuf_read_zerocopy(q, data, count, ppos);
 		if (retval >= 0  ||  retval == -EIO)
 			/* ok, all done */
 			goto done;
@@ -749,25 +765,25 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
 		retval = -ENOMEM;
 		q->read_buf = videobuf_alloc(q);
 
-		dprintk(1,"video alloc=0x%p\n", q->read_buf);
+		dprintk(1, "video alloc=0x%p\n", q->read_buf);
 		if (NULL == q->read_buf)
 			goto done;
 		q->read_buf->memory = V4L2_MEMORY_USERPTR;
 		q->read_buf->bsize = count; /* preferred size */
 		field = videobuf_next_field(q);
-		retval = q->ops->buf_prepare(q,q->read_buf,field);
+		retval = q->ops->buf_prepare(q, q->read_buf, field);
 
 		if (0 != retval) {
-			kfree (q->read_buf);
+			kfree(q->read_buf);
 			q->read_buf = NULL;
 			goto done;
 		}
 		if (q->irqlock)
-			spin_lock_irqsave(q->irqlock,flags);
+			spin_lock_irqsave(q->irqlock, flags);
 
-		q->ops->buf_queue(q,q->read_buf);
+		q->ops->buf_queue(q, q->read_buf);
 		if (q->irqlock)
-			spin_unlock_irqrestore(q->irqlock,flags);
+			spin_unlock_irqrestore(q->irqlock, flags);
 		q->read_off = 0;
 	}
 
@@ -776,11 +792,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
 	if (0 != retval)
 		goto done;
 
-	CALL(q,sync,q,q->read_buf);
+	CALL(q, sync, q, q->read_buf);
 
-	if (STATE_ERROR == q->read_buf->state) {
+	if (VIDEOBUF_ERROR == q->read_buf->state) {
 		/* catch I/O errors */
-		q->ops->buf_release(q,q->read_buf);
+		q->ops->buf_release(q, q->read_buf);
 		kfree(q->read_buf);
 		q->read_buf = NULL;
 		retval = -EIO;
@@ -788,14 +804,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
 	}
 
 	/* Copy to userspace */
-	retval=CALL(q,video_copy_to_user,q,data,count,nonblocking);
-	if (retval<0)
+	retval = CALL(q, video_copy_to_user, q, data, count, nonblocking);
+	if (retval < 0)
 		goto done;
 
 	q->read_off += retval;
 	if (q->read_off == q->read_buf->size) {
 		/* all data copied, cleanup */
-		q->ops->buf_release(q,q->read_buf);
+		q->ops->buf_release(q, q->read_buf);
 		kfree(q->read_buf);
 		q->read_buf = NULL;
 	}
@@ -806,14 +822,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
 }
 
 /* Locking: Caller holds q->lock */
-int __videobuf_read_start(struct videobuf_queue *q)
+static int __videobuf_read_start(struct videobuf_queue *q)
 {
 	enum v4l2_field field;
-	unsigned long flags=0;
+	unsigned long flags = 0;
 	unsigned int count = 0, size = 0;
 	int err, i;
 
-	q->ops->buf_setup(q,&count,&size);
+	q->ops->buf_setup(q, &count, &size);
 	if (count < 2)
 		count = 2;
 	if (count > VIDEO_MAX_FRAME)
@@ -828,17 +844,17 @@ int __videobuf_read_start(struct videobuf_queue *q)
 
 	for (i = 0; i < count; i++) {
 		field = videobuf_next_field(q);
-		err = q->ops->buf_prepare(q,q->bufs[i],field);
+		err = q->ops->buf_prepare(q, q->bufs[i], field);
 		if (err)
 			return err;
 		list_add_tail(&q->bufs[i]->stream, &q->stream);
 	}
 	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock,flags);
+		spin_lock_irqsave(q->irqlock, flags);
 	for (i = 0; i < count; i++)
-		q->ops->buf_queue(q,q->bufs[i]);
+		q->ops->buf_queue(q, q->bufs[i]);
 	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock,flags);
+		spin_unlock_irqrestore(q->irqlock, flags);
 	q->reading = 1;
 	return 0;
 }
@@ -859,7 +875,7 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
 	}
 	q->read_buf = NULL;
 	q->reading  = 0;
-	
+
 }
 
 int videobuf_read_start(struct videobuf_queue *q)
@@ -899,11 +915,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
 			     int vbihack, int nonblocking)
 {
 	int rc, retval;
-	unsigned long flags=0;
+	unsigned long flags = 0;
 
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-	dprintk(2,"%s\n",__FUNCTION__);
+	dprintk(2, "%s\n", __FUNCTION__);
 	mutex_lock(&q->lock);
 	retval = -EBUSY;
 	if (q->streaming)
@@ -931,8 +947,8 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
 			break;
 		}
 
-		if (q->read_buf->state == STATE_DONE) {
-			rc = CALL (q,copy_stream, q, data + retval, count,
+		if (q->read_buf->state == VIDEOBUF_DONE) {
+			rc = CALL(q, copy_stream, q, data + retval, count,
 					retval, vbihack, nonblocking);
 			if (rc < 0) {
 				retval = rc;
@@ -953,10 +969,10 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
 			list_add_tail(&q->read_buf->stream,
 				      &q->stream);
 			if (q->irqlock)
-				spin_lock_irqsave(q->irqlock,flags);
-			q->ops->buf_queue(q,q->read_buf);
+				spin_lock_irqsave(q->irqlock, flags);
+			q->ops->buf_queue(q, q->read_buf);
 			if (q->irqlock)
-				spin_unlock_irqrestore(q->irqlock,flags);
+				spin_unlock_irqrestore(q->irqlock, flags);
 			q->read_buf = NULL;
 		}
 		if (retval < 0)
@@ -999,8 +1015,8 @@ unsigned int videobuf_poll_stream(struct file *file,
 
 	if (0 == rc) {
 		poll_wait(file, &buf->done, wait);
-		if (buf->state == STATE_DONE ||
-		    buf->state == STATE_ERROR)
+		if (buf->state == VIDEOBUF_DONE ||
+		    buf->state == VIDEOBUF_ERROR)
 			rc = POLLIN|POLLRDNORM;
 	}
 	mutex_unlock(&q->lock);
@@ -1012,10 +1028,11 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
 {
 	int retval;
 
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
 	mutex_lock(&q->lock);
-	retval=CALL(q,mmap_mapper,q,vma);
+	retval = CALL(q, mmap_mapper, q, vma);
+	q->is_mmapped = 1;
 	mutex_unlock(&q->lock);
 
 	return retval;
@@ -1026,15 +1043,15 @@ int videobuf_cgmbuf(struct videobuf_queue *q,
 		    struct video_mbuf *mbuf, int count)
 {
 	struct v4l2_requestbuffers req;
-	int rc,i;
+	int rc, i;
 
-	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+	MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
 
-	memset(&req,0,sizeof(req));
+	memset(&req, 0, sizeof(req));
 	req.type   = q->type;
 	req.count  = count;
 	req.memory = V4L2_MEMORY_MMAP;
-	rc = videobuf_reqbufs(q,&req);
+	rc = videobuf_reqbufs(q, &req);
 	if (rc < 0)
 		return rc;
 
@@ -1079,9 +1096,3 @@ EXPORT_SYMBOL_GPL(videobuf_poll_stream);
 EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
 EXPORT_SYMBOL_GPL(videobuf_mmap_free);
 EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 44ee408e145f..98efd7ab1f50 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -385,30 +385,27 @@ videobuf_vm_close(struct vm_area_struct *vma)
  * now ...).  Bounce buffers don't work very well for the data rates
  * video capture has.
  */
-static struct page*
-videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
-		   int *type)
+static int
+videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
 	struct page *page;
 
-	dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
-		vaddr,vma->vm_start,vma->vm_end);
-	if (vaddr > vma->vm_end)
-		return NOPAGE_SIGBUS;
+	dprintk(3,"fault: fault @ %08lx [vma %08lx-%08lx]\n",
+		(unsigned long)vmf->virtual_address,vma->vm_start,vma->vm_end);
 	page = alloc_page(GFP_USER | __GFP_DMA32);
 	if (!page)
-		return NOPAGE_OOM;
-	clear_user_page(page_address(page), vaddr, page);
-	if (type)
-		*type = VM_FAULT_MINOR;
-	return page;
+		return VM_FAULT_OOM;
+	clear_user_page(page_address(page), (unsigned long)vmf->virtual_address,
+			page);
+	vmf->page = page;
+	return 0;
 }
 
 static struct vm_operations_struct videobuf_vm_ops =
 {
 	.open     = videobuf_vm_open,
 	.close    = videobuf_vm_close,
-	.nopage   = videobuf_vm_nopage,
+	.fault    = videobuf_vm_fault,
 };
 
 /* ---------------------------------------------------------------------
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index 880317e04a02..b73aba65d21d 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -67,7 +67,7 @@ static int videobuf_dvb_thread(void *data)
 
 		/* feed buffer data to demux */
 		dma=videobuf_to_dma(buf);
-		if (buf->state == STATE_DONE)
+		if (buf->state == VIDEOBUF_DONE)
 			dvb_dmx_swfilter(&dvb->demux, dma->vmalloc,
 					 buf->size);
 
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index e01259438bb2..9b3898347ca5 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -41,7 +41,7 @@ MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
 
 #define dprintk(level, fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
+	printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg)
 
 
 /***************************************************************************/
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 9611c3990285..28655f8983c6 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -973,7 +973,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 
 		*id = vfd->current_norm;
 
-		dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+		dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
 
 		ret=0;
 		break;
@@ -982,7 +982,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 	{
 		v4l2_std_id *id = arg,norm;
 
-		dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+		dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id);
 
 		norm = (*id) & vfd->tvnorms;
 		if ( vfd->tvnorms && !norm)	/* Check if std is supported */
@@ -1008,7 +1008,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 			break;
 		ret=vfd->vidioc_querystd(file, fh, arg);
 		if (!ret)
-			dbgarg (cmd, "detected std=%Lu\n",
+			dbgarg (cmd, "detected std=%08Lx\n",
 						(unsigned long long)*p);
 		break;
 	}
@@ -1028,7 +1028,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
 		if (!ret)
 			dbgarg (cmd, "index=%d, name=%s, type=%d, "
 					"audioset=%d, "
-					"tuner=%d, std=%Ld, status=%d\n",
+					"tuner=%d, std=%08Lx, status=%d\n",
 					p->index,p->name,p->type,p->audioset,
 					p->tuner,
 					(unsigned long long)p->std,
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 9a03dc82c6ca..5bb75294b5aa 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -2589,11 +2589,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
 	/* First try D1 and then SAA7191 */
 	if (vino_drvdata->camera.driver
 	    && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) {
-		if (i2c_use_client(vino_drvdata->camera.driver)) {
-			ret = -ENODEV;
-			goto out;
-		}
-
+		i2c_use_client(vino_drvdata->camera.driver);
 		vino_drvdata->camera.owner = vcs->channel;
 		vcs->input = VINO_INPUT_D1;
 		vcs->data_norm = VINO_DATA_NORM_D1;
@@ -2602,11 +2598,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
 		int input, data_norm;
 		int saa7191_input;
 
-		if (i2c_use_client(vino_drvdata->decoder.driver)) {
-			ret = -ENODEV;
-			goto out;
-		}
-
+		i2c_use_client(vino_drvdata->decoder.driver);
 		input = VINO_INPUT_COMPOSITE;
 
 		saa7191_input = vino_get_saa7191_input(input);
@@ -2688,10 +2680,7 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
 		}
 
 		if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) {
-			if (i2c_use_client(vino_drvdata->decoder.driver)) {
-				ret = -ENODEV;
-				goto out;
-			}
+			i2c_use_client(vino_drvdata->decoder.driver);
 			vino_drvdata->decoder.owner = vcs->channel;
 		}
 
@@ -2759,10 +2748,7 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
 		}
 
 		if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) {
-			if (i2c_use_client(vino_drvdata->camera.driver)) {
-				ret = -ENODEV;
-				goto out;
-			}
+			i2c_use_client(vino_drvdata->camera.driver);
 			vino_drvdata->camera.owner = vcs->channel;
 		}
 
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 9b54ff9d2e36..1db067c02815 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -44,21 +44,18 @@
 #define WAKE_DENOMINATOR 1001
 #define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
-/* These timers are for 1 fps - used only for testing */
-//#define WAKE_DENOMINATOR 30 /* hack for testing purposes */
-//#define BUFFER_TIMEOUT     msecs_to_jiffies(5000)  /* 5 seconds */
-
 #include "font.h"
 
 #define VIVI_MAJOR_VERSION 0
 #define VIVI_MINOR_VERSION 4
 #define VIVI_RELEASE 0
-#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
+#define VIVI_VERSION \
+	KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
 
 /* Declare static vars that will be used as parameters */
 static unsigned int vid_limit = 16;	/* Video memory limit, in Mb */
-static struct video_device vivi;	/* Video device */
 static int video_nr = -1;		/* /dev/videoN, -1 for autodetect */
+static int n_devs = 1;			/* Number of virtual devices */
 
 /* supported controls */
 static struct v4l2_queryctrl vivi_qctrl[] = {
@@ -71,7 +68,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
 		.default_value = 65535,
 		.flags         = 0,
 		.type          = V4L2_CTRL_TYPE_INTEGER,
-	},{
+	}, {
 		.id            = V4L2_CID_BRIGHTNESS,
 		.type          = V4L2_CTRL_TYPE_INTEGER,
 		.name          = "Brightness",
@@ -112,9 +109,9 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
 
 static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
 
-#define dprintk(level,fmt, arg...)					\
+#define dprintk(dev, level, fmt, arg...)				\
 	do {								\
-		if (vivi.debug >= (level))				\
+		if (dev->vfd->debug >= (level))				\
 			printk(KERN_DEBUG "vivi: " fmt , ## arg);	\
 	} while (0)
 
@@ -166,17 +163,21 @@ struct vivi_dev {
 	struct list_head           vivi_devlist;
 
 	struct mutex               lock;
+	spinlock_t                 slock;
 
 	int                        users;
 
 	/* various device info */
-	struct video_device        vfd;
+	struct video_device        *vfd;
 
 	struct vivi_dmaqueue       vidq;
 
 	/* Several counters */
-	int                        h,m,s,us,jiffies;
+	int                        h, m, s, ms;
+	unsigned long              jiffies;
 	char                       timestr[13];
+
+	int			   mv_count;	/* Controls bars movement */
 };
 
 struct vivi_fh {
@@ -184,7 +185,7 @@ struct vivi_fh {
 
 	/* video capture */
 	struct vivi_fmt            *fmt;
-	unsigned int               width,height;
+	unsigned int               width, height;
 	struct videobuf_queue      vb_vidq;
 
 	enum v4l2_buf_type         type;
@@ -203,109 +204,113 @@ enum colors {
 	GREEN,
 	MAGENTA,
 	RED,
-	BLUE
+	BLUE,
+	BLACK,
 };
 
 static u8 bars[8][3] = {
 	/* R   G   B */
-	{204,204,204},	/* white */
-	{208,208,  0},  /* ambar */
-	{  0,206,206},  /* cyan */
-	{  0,239,  0},  /* green */
-	{239,  0,239},  /* magenta */
-	{205,  0,  0},  /* red */
-	{  0,  0,255},  /* blue */
-	{  0,  0,  0}
+	{204, 204, 204},  /* white */
+	{208, 208,   0},  /* ambar */
+	{  0, 206, 206},  /* cyan */
+	{  0, 239,   0},  /* green */
+	{239,   0, 239},  /* magenta */
+	{205,   0,   0},  /* red */
+	{  0,   0, 255},  /* blue */
+	{  0,   0,   0},  /* black */
 };
 
-#define TO_Y(r,g,b) (((16829*r +33039*g +6416*b  + 32768)>>16)+16)
+#define TO_Y(r, g, b) \
+	(((16829 * r + 33039 * g + 6416 * b  + 32768) >> 16) + 16)
 /* RGB to  V(Cr) Color transform */
-#define TO_V(r,g,b) (((28784*r -24103*g -4681*b  + 32768)>>16)+128)
+#define TO_V(r, g, b) \
+	(((28784 * r - 24103 * g - 4681 * b  + 32768) >> 16) + 128)
 /* RGB to  U(Cb) Color transform */
-#define TO_U(r,g,b) (((-9714*r -19070*g +28784*b + 32768)>>16)+128)
+#define TO_U(r, g, b) \
+	(((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
 
 #define TSTAMP_MIN_Y 24
 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
 #define TSTAMP_MIN_X 64
 
-static void gen_line(char *basep,int inipos,int wmax,
-		     int hmax, int line, int count, char *timestr)
+static void gen_line(char *basep, int inipos, int wmax,
+		int hmax, int line, int count, char *timestr)
 {
-	int  w,i,j,pos=inipos,y;
-	char *p,*s;
-	u8   chr,r,g,b,color;
+	int  w, i, j, y;
+	int pos = inipos;
+	char *p, *s;
+	u8   chr, r, g, b, color;
 
 	/* We will just duplicate the second pixel at the packet */
-	wmax/=2;
+	wmax /= 2;
 
 	/* Generate a standard color bar pattern */
-	for (w=0;w<wmax;w++) {
-		int colorpos=((w+count)*8/(wmax+1)) % 8;
-		r=bars[colorpos][0];
-		g=bars[colorpos][1];
-		b=bars[colorpos][2];
+	for (w = 0; w < wmax; w++) {
+		int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
+		r = bars[colorpos][0];
+		g = bars[colorpos][1];
+		b = bars[colorpos][2];
 
-		for (color=0;color<4;color++) {
-			p=basep+pos;
+		for (color = 0; color < 4; color++) {
+			p = basep + pos;
 
 			switch (color) {
-				case 0:
-				case 2:
-					*p=TO_Y(r,g,b);		/* Luminance */
-					break;
-				case 1:
-					*p=TO_U(r,g,b);		/* Cb */
-					break;
-				case 3:
-					*p=TO_V(r,g,b);		/* Cr */
-					break;
+			case 0:
+			case 2:
+				*p = TO_Y(r, g, b);	/* Luma */
+				break;
+			case 1:
+				*p = TO_U(r, g, b);	/* Cb */
+				break;
+			case 3:
+				*p = TO_V(r, g, b);	/* Cr */
+				break;
 			}
 			pos++;
 		}
 	}
 
 	/* Checks if it is possible to show timestamp */
-	if (TSTAMP_MAX_Y>=hmax)
+	if (TSTAMP_MAX_Y >= hmax)
 		goto end;
-	if (TSTAMP_MIN_X+strlen(timestr)>=wmax)
+	if (TSTAMP_MIN_X + strlen(timestr) >= wmax)
 		goto end;
 
 	/* Print stream time */
-	if (line>=TSTAMP_MIN_Y && line<=TSTAMP_MAX_Y) {
-		j=TSTAMP_MIN_X;
-		for (s=timestr;*s;s++) {
-			chr=rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
-			for (i=0;i<7;i++) {
-				if (chr&1<<(7-i)) { /* Font color*/
-					r=bars[BLUE][0];
-					g=bars[BLUE][1];
-					b=bars[BLUE][2];
-					r=g=b=0;
-					g=198;
-				} else { /* Background color */
-					r=bars[WHITE][0];
-					g=bars[WHITE][1];
-					b=bars[WHITE][2];
-					r=g=b=0;
+	if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
+		j = TSTAMP_MIN_X;
+		for (s = timestr; *s; s++) {
+			chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
+			for (i = 0; i < 7; i++) {
+				if (chr & 1 << (7 - i)) {
+					/* Font color*/
+					r = 0;
+					g = 198;
+					b = 0;
+				} else {
+					/* Background color */
+					r = bars[BLACK][0];
+					g = bars[BLACK][1];
+					b = bars[BLACK][2];
 				}
 
-				pos=inipos+j*2;
-				for (color=0;color<4;color++) {
-					p=basep+pos;
+				pos = inipos + j * 2;
+				for (color = 0; color < 4; color++) {
+					p = basep + pos;
 
-					y=TO_Y(r,g,b);
+					y = TO_Y(r, g, b);
 
 					switch (color) {
-						case 0:
-						case 2:
-							*p=TO_Y(r,g,b);		/* Luminance */
-							break;
-						case 1:
-							*p=TO_U(r,g,b);		/* Cb */
-							break;
-						case 3:
-							*p=TO_V(r,g,b);		/* Cr */
-							break;
+					case 0:
+					case 2:
+						*p = TO_Y(r, g, b); /* Luma */
+						break;
+					case 1:
+						*p = TO_U(r, g, b); /* Cb */
+						break;
+					case 3:
+						*p = TO_V(r, g, b); /* Cr */
+						break;
 					}
 					pos++;
 				}
@@ -314,63 +319,60 @@ static void gen_line(char *basep,int inipos,int wmax,
 		}
 	}
 
-
 end:
 	return;
 }
-static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
+static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 {
-	int h,pos=0;
+	int h , pos = 0;
 	int hmax  = buf->vb.height;
 	int wmax  = buf->vb.width;
 	struct timeval ts;
-	char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL);
-	void *vbuf=videobuf_to_vmalloc (&buf->vb);
-	/* FIXME: move to dev struct */
-	static int mv_count=0;
+	char *tmpbuf = kmalloc(wmax * 2, GFP_KERNEL);
+	void *vbuf = videobuf_to_vmalloc(&buf->vb);
 
 	if (!tmpbuf)
 		return;
 
-	for (h=0;h<hmax;h++) {
-		gen_line(tmpbuf,0,wmax,hmax,h,mv_count,
+	for (h = 0; h < hmax; h++) {
+		gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count,
 			 dev->timestr);
 		/* FIXME: replacing to __copy_to_user */
-		if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0)
-			dprintk(2,"vivifill copy_to_user failed.\n");
+		if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0)
+			dprintk(dev, 2, "vivifill copy_to_user failed.\n");
 		pos += wmax*2;
 	}
 
-	mv_count++;
+	dev->mv_count++;
 
 	kfree(tmpbuf);
 
 	/* Updates stream time */
 
-	dev->us+=jiffies_to_usecs(jiffies-dev->jiffies);
-	dev->jiffies=jiffies;
-	if (dev->us>=1000000) {
-		dev->us-=1000000;
+	dev->ms += jiffies_to_msecs(jiffies-dev->jiffies);
+	dev->jiffies = jiffies;
+	if (dev->ms >= 1000) {
+		dev->ms -= 1000;
 		dev->s++;
-		if (dev->s>=60) {
-			dev->s-=60;
+		if (dev->s >= 60) {
+			dev->s -= 60;
 			dev->m++;
-			if (dev->m>60) {
-				dev->m-=60;
+			if (dev->m > 60) {
+				dev->m -= 60;
 				dev->h++;
-				if (dev->h>24)
-					dev->h-=24;
+				if (dev->h > 24)
+					dev->h -= 24;
 			}
 		}
 	}
-	sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
-			dev->h,dev->m,dev->s,(dev->us+500)/1000);
+	sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
+			dev->h, dev->m, dev->s, dev->ms);
 
-	dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
-			(unsigned long)tmpbuf,pos);
+	dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n",
+			dev->timestr, (unsigned long)tmpbuf, pos);
 
 	/* Advice that buffer was filled */
-	buf->vb.state = STATE_DONE;
+	buf->vb.state = VIDEOBUF_DONE;
 	buf->vb.field_count++;
 	do_gettimeofday(&ts);
 	buf->vb.ts = ts;
@@ -384,14 +386,15 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q);
 static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
 {
 	struct vivi_buffer    *buf;
-	struct vivi_dev *dev= container_of(dma_q,struct vivi_dev,vidq);
+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
 
 	int bc;
 
+	spin_lock(&dev->slock);
 	/* Announces videobuf that all went ok */
 	for (bc = 0;; bc++) {
 		if (list_empty(&dma_q->active)) {
-			dprintk(1,"No active queue to serve\n");
+			dprintk(dev, 1, "No active queue to serve\n");
 			break;
 		}
 
@@ -401,65 +404,89 @@ static void vivi_thread_tick(struct vivi_dmaqueue  *dma_q)
 		/* Nobody is waiting something to be done, just return */
 		if (!waitqueue_active(&buf->vb.done)) {
 			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+			spin_unlock(&dev->slock);
 			return;
 		}
 
 		do_gettimeofday(&buf->vb.ts);
-		dprintk(2,"[%p/%d] wakeup\n",buf,buf->vb.i);
+		dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
 
 		/* Fill buffer */
-		vivi_fillbuff(dev,buf);
+		vivi_fillbuff(dev, buf);
 
 		if (list_empty(&dma_q->active)) {
 			del_timer(&dma_q->timeout);
 		} else {
-			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+			mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT);
 		}
 	}
 	if (bc != 1)
-		dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
+		dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n",
+			__FUNCTION__, bc);
+	spin_unlock(&dev->slock);
 }
 
+#define frames_to_ms(frames)					\
+	((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
+
 static void vivi_sleep(struct vivi_dmaqueue  *dma_q)
 {
-	int timeout;
+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+	int timeout, running_time;
 	DECLARE_WAITQUEUE(wait, current);
 
-	dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
+	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
+		(unsigned long)dma_q);
 
 	add_wait_queue(&dma_q->wq, &wait);
-	if (!kthread_should_stop()) {
-		dma_q->frame++;
+	if (kthread_should_stop())
+		goto stop_task;
 
-		/* Calculate time to wake up */
-		timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies;
+	running_time = jiffies - dma_q->ini_jiffies;
+	dma_q->frame++;
 
-		if (timeout <= 0) {
-			int old=dma_q->frame;
-			dma_q->frame=(jiffies_to_msecs(jiffies-dma_q->ini_jiffies)*WAKE_DENOMINATOR)/(WAKE_NUMERATOR*1000)+1;
+	/* Calculate time to wake up */
+	timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time;
 
-			timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies;
+	if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) {
+		int old = dma_q->frame;
+		int nframes;
 
-			dprintk(1,"underrun, losed %d frames. "
-				  "Now, frame is %d. Waking on %d jiffies\n",
-					dma_q->frame-old,dma_q->frame,timeout);
-		} else
-			dprintk(1,"will sleep for %i jiffies\n",timeout);
+		dma_q->frame = (jiffies_to_msecs(running_time) /
+			       frames_to_ms(1)) + 1;
 
-		vivi_thread_tick(dma_q);
+		timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame))
+			  - running_time;
 
-		schedule_timeout_interruptible (timeout);
-	}
+		if (unlikely (timeout <= 0))
+			timeout = 1;
+
+		nframes = (dma_q->frame > old)?
+				  dma_q->frame - old : old - dma_q->frame;
+
+		dprintk(dev, 1, "%ld: %s %d frames. "
+			"Current frame is %d. Will sleep for %d jiffies\n",
+			jiffies,
+			(dma_q->frame > old)? "Underrun, losed" : "Overrun of",
+			nframes, dma_q->frame, timeout);
+	} else
+		dprintk(dev, 1, "will sleep for %d jiffies\n", timeout);
 
+	vivi_thread_tick(dma_q);
+
+	schedule_timeout_interruptible(timeout);
+
+stop_task:
 	remove_wait_queue(&dma_q->wq, &wait);
 	try_to_freeze();
 }
 
 static int vivi_thread(void *data)
 {
-	struct vivi_dmaqueue  *dma_q=data;
+	struct vivi_dmaqueue  *dma_q = data;
+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
 
-	dprintk(1,"thread started\n");
+	dprintk(dev, 1, "thread started\n");
 
 	mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
 	set_freezable();
@@ -470,16 +497,18 @@ static int vivi_thread(void *data)
 		if (kthread_should_stop())
 			break;
 	}
-	dprintk(1, "thread: exit\n");
+	dprintk(dev, 1, "thread: exit\n");
 	return 0;
 }
 
 static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
 {
-	dma_q->frame=0;
-	dma_q->ini_jiffies=jiffies;
+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
 
-	dprintk(1,"%s\n",__FUNCTION__);
+	dma_q->frame = 0;
+	dma_q->ini_jiffies = jiffies;
+
+	dprintk(dev, 1, "%s\n", __FUNCTION__);
 
 	dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
 
@@ -490,39 +519,43 @@ static int vivi_start_thread(struct vivi_dmaqueue  *dma_q)
 	/* Wakes thread */
 	wake_up_interruptible(&dma_q->wq);
 
-	dprintk(1,"returning from %s\n",__FUNCTION__);
+	dprintk(dev, 1, "returning from %s\n", __FUNCTION__);
 	return 0;
 }
 
 static void vivi_stop_thread(struct vivi_dmaqueue  *dma_q)
 {
-	dprintk(1,"%s\n",__FUNCTION__);
+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+
+	dprintk(dev, 1, "%s\n", __FUNCTION__);
 	/* shutdown control thread */
 	if (dma_q->kthread) {
 		kthread_stop(dma_q->kthread);
-		dma_q->kthread=NULL;
+		dma_q->kthread = NULL;
 	}
 }
 
 static int restart_video_queue(struct vivi_dmaqueue *dma_q)
 {
+	struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
 	struct vivi_buffer *buf, *prev;
 
-	dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
+	dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
+		(unsigned long)dma_q);
 
 	if (!list_empty(&dma_q->active)) {
-		buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue);
-		dprintk(2,"restart_queue [%p/%d]: restart dma\n",
+		buf = list_entry(dma_q->active.next,
+				 struct vivi_buffer, vb.queue);
+		dprintk(dev, 2, "restart_queue [%p/%d]: restart dma\n",
 			buf, buf->vb.i);
 
-		dprintk(1,"Restarting video dma\n");
+		dprintk(dev, 1, "Restarting video dma\n");
 		vivi_stop_thread(dma_q);
-//		vivi_start_thread(dma_q);
 
 		/* cancel all outstanding capture / vbi requests */
 		list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) {
 			list_del(&buf->vb.queue);
-			buf->vb.state = STATE_ERROR;
+			buf->vb.state = VIDEOBUF_ERROR;
 			wake_up(&buf->vb.done);
 		}
 		mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
@@ -534,28 +567,31 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
 	for (;;) {
 		if (list_empty(&dma_q->queued))
 			return 0;
-		buf = list_entry(dma_q->queued.next, struct vivi_buffer, vb.queue);
+		buf = list_entry(dma_q->queued.next,
+				 struct vivi_buffer, vb.queue);
 		if (NULL == prev) {
 			list_del(&buf->vb.queue);
-			list_add_tail(&buf->vb.queue,&dma_q->active);
+			list_add_tail(&buf->vb.queue, &dma_q->active);
 
-			dprintk(1,"Restarting video dma\n");
+			dprintk(dev, 1, "Restarting video dma\n");
 			vivi_stop_thread(dma_q);
 			vivi_start_thread(dma_q);
 
-			buf->vb.state = STATE_ACTIVE;
+			buf->vb.state = VIDEOBUF_ACTIVE;
 			mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
-			dprintk(2,"[%p/%d] restart_queue - first active\n",
-				buf,buf->vb.i);
+			dprintk(dev, 2,
+				"[%p/%d] restart_queue - first active\n",
+				buf, buf->vb.i);
 
 		} else if (prev->vb.width  == buf->vb.width  &&
 			   prev->vb.height == buf->vb.height &&
 			   prev->fmt       == buf->fmt) {
 			list_del(&buf->vb.queue);
-			list_add_tail(&buf->vb.queue,&dma_q->active);
-			buf->vb.state = STATE_ACTIVE;
-			dprintk(2,"[%p/%d] restart_queue - move to active\n",
-				buf,buf->vb.i);
+			list_add_tail(&buf->vb.queue, &dma_q->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			dprintk(dev, 2,
+				"[%p/%d] restart_queue - move to active\n",
+				buf, buf->vb.i);
 		} else {
 			return 0;
 		}
@@ -565,19 +601,23 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
 
 static void vivi_vid_timeout(unsigned long data)
 {
-	struct vivi_dev      *dev  = (struct vivi_dev*)data;
+	struct vivi_dev      *dev  = (struct vivi_dev *)data;
 	struct vivi_dmaqueue *vidq = &dev->vidq;
 	struct vivi_buffer   *buf;
 
+	spin_lock(&dev->slock);
+
 	while (!list_empty(&vidq->active)) {
-		buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue);
+		buf = list_entry(vidq->active.next,
+				 struct vivi_buffer, vb.queue);
 		list_del(&buf->vb.queue);
-		buf->vb.state = STATE_ERROR;
+		buf->vb.state = VIDEOBUF_ERROR;
 		wake_up(&buf->vb.done);
-		printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
+		printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
 	}
-
 	restart_video_queue(vidq);
+
+	spin_unlock(&dev->slock);
 }
 
 /* ------------------------------------------------------------------
@@ -586,7 +626,8 @@ static void vivi_vid_timeout(unsigned long data)
 static int
 buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
 {
-	struct vivi_fh *fh = vq->priv_data;
+	struct vivi_fh  *fh = vq->priv_data;
+	struct vivi_dev *dev  = fh->dev;
 
 	*size = fh->width*fh->height*2;
 
@@ -596,21 +637,25 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
 	while (*size * *count > vid_limit * 1024 * 1024)
 		(*count)--;
 
-	dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size);
+	dprintk(dev, 1, "%s, count=%d, size=%d\n", __FUNCTION__,
+		*count, *size);
 
 	return 0;
 }
 
 static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
 {
-	dprintk(1,"%s\n",__FUNCTION__);
+	struct vivi_fh  *fh = vq->priv_data;
+	struct vivi_dev *dev  = fh->dev;
+
+	dprintk(dev, 1, "%s\n", __FUNCTION__);
 
 	if (in_interrupt())
 		BUG();
 
-	videobuf_waiton(&buf->vb,0,0);
+	videobuf_waiton(&buf->vb, 0, 0);
 	videobuf_vmalloc_free(&buf->vb);
-	buf->vb.state = STATE_NEEDS_INIT;
+	buf->vb.state = VIDEOBUF_NEEDS_INIT;
 }
 
 #define norm_maxw() 1024
@@ -620,10 +665,11 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
 						enum v4l2_field field)
 {
 	struct vivi_fh     *fh  = vq->priv_data;
-	struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb);
+	struct vivi_dev    *dev = fh->dev;
+	struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
 	int rc, init_buffer = 0;
 
-	dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
+	dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field);
 
 	BUG_ON(NULL == fh->fmt);
 	if (fh->width  < 48 || fh->width  > norm_maxw() ||
@@ -644,75 +690,81 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
 		init_buffer = 1;
 	}
 
-	if (STATE_NEEDS_INIT == buf->vb.state) {
-		if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL)))
+	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+		rc = videobuf_iolock(vq, &buf->vb, NULL);
+		if (rc < 0)
 			goto fail;
 	}
 
-	buf->vb.state = STATE_PREPARED;
+	buf->vb.state = VIDEOBUF_PREPARED;
 
 	return 0;
 
 fail:
-	free_buffer(vq,buf);
+	free_buffer(vq, buf);
 	return rc;
 }
 
 static void
 buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
 {
-	struct vivi_buffer    *buf     = container_of(vb,struct vivi_buffer,vb);
-	struct vivi_fh        *fh      = vq->priv_data;
-	struct vivi_dev       *dev     = fh->dev;
-	struct vivi_dmaqueue  *vidq    = &dev->vidq;
+	struct vivi_buffer    *buf  = container_of(vb, struct vivi_buffer, vb);
+	struct vivi_fh        *fh   = vq->priv_data;
+	struct vivi_dev       *dev  = fh->dev;
+	struct vivi_dmaqueue  *vidq = &dev->vidq;
 	struct vivi_buffer    *prev;
 
 	if (!list_empty(&vidq->queued)) {
-		dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue);
-		list_add_tail(&buf->vb.queue,&vidq->queued);
-		buf->vb.state = STATE_QUEUED;
-		dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
+		dprintk(dev, 1, "adding vb queue=0x%08lx\n",
+			(unsigned long)&buf->vb.queue);
+		list_add_tail(&buf->vb.queue, &vidq->queued);
+		buf->vb.state = VIDEOBUF_QUEUED;
+		dprintk(dev, 2, "[%p/%d] buffer_queue - append to queued\n",
 			buf, buf->vb.i);
 	} else if (list_empty(&vidq->active)) {
-		list_add_tail(&buf->vb.queue,&vidq->active);
+		list_add_tail(&buf->vb.queue, &vidq->active);
 
-		buf->vb.state = STATE_ACTIVE;
+		buf->vb.state = VIDEOBUF_ACTIVE;
 		mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
-		dprintk(2,"[%p/%d] buffer_queue - first active\n",
+		dprintk(dev, 2, "[%p/%d] buffer_queue - first active\n",
 			buf, buf->vb.i);
 
 		vivi_start_thread(vidq);
 	} else {
-		prev = list_entry(vidq->active.prev, struct vivi_buffer, vb.queue);
+		prev = list_entry(vidq->active.prev,
+				  struct vivi_buffer, vb.queue);
 		if (prev->vb.width  == buf->vb.width  &&
 		    prev->vb.height == buf->vb.height &&
 		    prev->fmt       == buf->fmt) {
-			list_add_tail(&buf->vb.queue,&vidq->active);
-			buf->vb.state = STATE_ACTIVE;
-			dprintk(2,"[%p/%d] buffer_queue - append to active\n",
+			list_add_tail(&buf->vb.queue, &vidq->active);
+			buf->vb.state = VIDEOBUF_ACTIVE;
+			dprintk(dev, 2,
+				"[%p/%d] buffer_queue - append to active\n",
 				buf, buf->vb.i);
 
 		} else {
-			list_add_tail(&buf->vb.queue,&vidq->queued);
-			buf->vb.state = STATE_QUEUED;
-			dprintk(2,"[%p/%d] buffer_queue - first queued\n",
+			list_add_tail(&buf->vb.queue, &vidq->queued);
+			buf->vb.state = VIDEOBUF_QUEUED;
+			dprintk(dev, 2,
+				"[%p/%d] buffer_queue - first queued\n",
 				buf, buf->vb.i);
 		}
 	}
 }
 
-static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_release(struct videobuf_queue *vq,
+			   struct videobuf_buffer *vb)
 {
-	struct vivi_buffer   *buf  = container_of(vb,struct vivi_buffer,vb);
+	struct vivi_buffer   *buf  = container_of(vb, struct vivi_buffer, vb);
 	struct vivi_fh       *fh   = vq->priv_data;
-	struct vivi_dev      *dev  = (struct vivi_dev*)fh->dev;
+	struct vivi_dev      *dev  = (struct vivi_dev *)fh->dev;
 	struct vivi_dmaqueue *vidq = &dev->vidq;
 
-	dprintk(1,"%s\n",__FUNCTION__);
+	dprintk(dev, 1, "%s\n", __FUNCTION__);
 
 	vivi_stop_thread(vidq);
 
-	free_buffer(vq,buf);
+	free_buffer(vq, buf);
 }
 
 static struct videobuf_queue_ops vivi_video_qops = {
@@ -725,7 +777,7 @@ static struct videobuf_queue_ops vivi_video_qops = {
 /* ------------------------------------------------------------------
 	IOCTL vidioc handling
    ------------------------------------------------------------------*/
-static int vidioc_querycap (struct file *file, void  *priv,
+static int vidioc_querycap(struct file *file, void  *priv,
 					struct v4l2_capability *cap)
 {
 	strcpy(cap->driver, "vivi");
@@ -737,21 +789,21 @@ static int vidioc_querycap (struct file *file, void  *priv,
 	return 0;
 }
 
-static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+static int vidioc_enum_fmt_cap(struct file *file, void  *priv,
 					struct v4l2_fmtdesc *f)
 {
 	if (f->index > 0)
 		return -EINVAL;
 
-	strlcpy(f->description,format.name,sizeof(f->description));
+	strlcpy(f->description, format.name, sizeof(f->description));
 	f->pixelformat = format.fourcc;
 	return 0;
 }
 
-static int vidioc_g_fmt_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
-	struct vivi_fh  *fh=priv;
+	struct vivi_fh *fh = priv;
 
 	f->fmt.pix.width        = fh->width;
 	f->fmt.pix.height       = fh->height;
@@ -765,26 +817,29 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv,
 	return (0);
 }
 
-static int vidioc_try_fmt_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
 			struct v4l2_format *f)
 {
+	struct vivi_fh  *fh  = priv;
+	struct vivi_dev *dev = fh->dev;
 	struct vivi_fmt *fmt;
 	enum v4l2_field field;
 	unsigned int maxw, maxh;
 
 	if (format.fourcc != f->fmt.pix.pixelformat) {
-		dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts "
-			"only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc);
+		dprintk(dev, 1, "Fourcc format (0x%08x) invalid. "
+			"Driver accepts only 0x%08x\n",
+			f->fmt.pix.pixelformat, format.fourcc);
 		return -EINVAL;
 	}
-	fmt=&format;
+	fmt = &format;
 
 	field = f->fmt.pix.field;
 
 	if (field == V4L2_FIELD_ANY) {
-		field=V4L2_FIELD_INTERLACED;
+		field = V4L2_FIELD_INTERLACED;
 	} else if (V4L2_FIELD_INTERLACED != field) {
-		dprintk(1,"Field type invalid.\n");
+		dprintk(dev, 1, "Field type invalid.\n");
 		return -EINVAL;
 	}
 
@@ -810,11 +865,11 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv,
 }
 
 /*FIXME: This seems to be generic enough to be at videodev2 */
-static int vidioc_s_fmt_cap (struct file *file, void *priv,
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
 					struct v4l2_format *f)
 {
-	struct vivi_fh  *fh=priv;
-	int ret = vidioc_try_fmt_cap(file,fh,f);
+	struct vivi_fh  *fh = priv;
+	int ret = vidioc_try_fmt_cap(file, fh, f);
 	if (ret < 0)
 		return (ret);
 
@@ -827,47 +882,48 @@ static int vidioc_s_fmt_cap (struct file *file, void *priv,
 	return (0);
 }
 
-static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *p)
 {
-	struct vivi_fh  *fh=priv;
+	struct vivi_fh  *fh = priv;
 
 	return (videobuf_reqbufs(&fh->vb_vidq, p));
 }
 
-static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	struct vivi_fh  *fh=priv;
+	struct vivi_fh  *fh = priv;
 
 	return (videobuf_querybuf(&fh->vb_vidq, p));
 }
 
-static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	struct vivi_fh  *fh=priv;
+	struct vivi_fh *fh = priv;
 
 	return (videobuf_qbuf(&fh->vb_vidq, p));
 }
 
-static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
-	struct vivi_fh  *fh=priv;
+	struct vivi_fh  *fh = priv;
 
 	return (videobuf_dqbuf(&fh->vb_vidq, p,
 				file->f_flags & O_NONBLOCK));
 }
 
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
 {
-	struct vivi_fh  *fh=priv;
+	struct vivi_fh  *fh = priv;
 
-	return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
+	return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
 }
 #endif
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-	struct vivi_fh  *fh=priv;
+	struct vivi_fh  *fh = priv;
 
 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
@@ -879,7 +935,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
-	struct vivi_fh  *fh=priv;
+	struct vivi_fh  *fh = priv;
 
 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
@@ -889,32 +945,32 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 	return videobuf_streamoff(&fh->vb_vidq);
 }
 
-static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
 {
 	return 0;
 }
 
 /* only one input in this sample driver */
-static int vidioc_enum_input (struct file *file, void *priv,
+static int vidioc_enum_input(struct file *file, void *priv,
 				struct v4l2_input *inp)
 {
 	if (inp->index != 0)
 		return -EINVAL;
 
 	inp->type = V4L2_INPUT_TYPE_CAMERA;
-	inp->std = V4L2_STD_NTSC_M;
-	strcpy(inp->name,"Camera");
+	inp->std = V4L2_STD_525_60;
+	strcpy(inp->name, "Camera");
 
 	return (0);
 }
 
-static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 {
 	*i = 0;
 
 	return (0);
 }
-static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 {
 	if (i > 0)
 		return -EINVAL;
@@ -923,8 +979,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
 }
 
 	/* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl (struct file *file, void *priv,
-				struct v4l2_queryctrl *qc)
+static int vidioc_queryctrl(struct file *file, void *priv,
+			    struct v4l2_queryctrl *qc)
 {
 	int i;
 
@@ -938,33 +994,31 @@ static int vidioc_queryctrl (struct file *file, void *priv,
 	return -EINVAL;
 }
 
-static int vidioc_g_ctrl (struct file *file, void *priv,
-				struct v4l2_control *ctrl)
+static int vidioc_g_ctrl(struct file *file, void *priv,
+			 struct v4l2_control *ctrl)
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
 		if (ctrl->id == vivi_qctrl[i].id) {
-			ctrl->value=qctl_regs[i];
+			ctrl->value = qctl_regs[i];
 			return (0);
 		}
 
 	return -EINVAL;
 }
-static int vidioc_s_ctrl (struct file *file, void *priv,
+static int vidioc_s_ctrl(struct file *file, void *priv,
 				struct v4l2_control *ctrl)
 {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
 		if (ctrl->id == vivi_qctrl[i].id) {
-			if (ctrl->value <
-				vivi_qctrl[i].minimum
-				|| ctrl->value >
-				vivi_qctrl[i].maximum) {
+			if (ctrl->value < vivi_qctrl[i].minimum
+			    || ctrl->value > vivi_qctrl[i].maximum) {
 					return (-ERANGE);
 				}
-			qctl_regs[i]=ctrl->value;
+			qctl_regs[i] = ctrl->value;
 			return (0);
 		}
 	return -EINVAL;
@@ -983,24 +1037,22 @@ static int vivi_open(struct inode *inode, struct file *file)
 	struct vivi_fh *fh;
 	int i;
 
-	printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor);
+	printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
 
 	list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
-		if (dev->vfd.minor == minor)
+		if (dev->vfd->minor == minor)
 			goto found;
 	return -ENODEV;
-found:
-
-
 
+found:
 	/* If more than one user, mutex should be added */
 	dev->users++;
 
-	dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+	dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
 		v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
 
 	/* allocate + initialize per filehandle data */
-	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
 	if (NULL == fh) {
 		dev->users--;
 		return -ENOMEM;
@@ -1016,27 +1068,21 @@ found:
 
 	/* Put all controls at a sane state */
 	for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
-		qctl_regs[i] =vivi_qctrl[i].default_value;
-
-	dprintk(1,"Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
-		(unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq);
-	dprintk(1,"Open: list_empty queued=%d\n",list_empty(&dev->vidq.queued));
-	dprintk(1,"Open: list_empty active=%d\n",list_empty(&dev->vidq.active));
+		qctl_regs[i] = vivi_qctrl[i].default_value;
 
 	/* Resets frame counters */
-	dev->h=0;
-	dev->m=0;
-	dev->s=0;
-	dev->us=0;
-	dev->jiffies=jiffies;
-	sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
-			dev->h,dev->m,dev->s,(dev->us+500)/1000);
+	dev->h = 0;
+	dev->m = 0;
+	dev->s = 0;
+	dev->ms = 0;
+	dev->mv_count = 0;
+	dev->jiffies = jiffies;
+	sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
+			dev->h, dev->m, dev->s, dev->ms);
 
 	videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
-			NULL, NULL,
-			fh->type,
-			V4L2_FIELD_INTERLACED,
-			sizeof(struct vivi_buffer),fh);
+			NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
+			sizeof(struct vivi_buffer), fh);
 
 	return 0;
 }
@@ -1044,9 +1090,9 @@ found:
 static ssize_t
 vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
-	struct vivi_fh        *fh = file->private_data;
+	struct vivi_fh *fh = file->private_data;
 
-	if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
 					file->f_flags & O_NONBLOCK);
 	}
@@ -1057,9 +1103,10 @@ static unsigned int
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct vivi_fh        *fh = file->private_data;
+	struct vivi_dev       *dev = fh->dev;
 	struct videobuf_queue *q = &fh->vb_vidq;
 
-	dprintk(1,"%s\n",__FUNCTION__);
+	dprintk(dev, 1, "%s\n", __FUNCTION__);
 
 	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
 		return POLLERR;
@@ -1067,7 +1114,7 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
 	return videobuf_poll_stream(file, q, wait);
 }
 
-static int vivi_release(struct inode *inode, struct file *file)
+static int vivi_close(struct inode *inode, struct file *file)
 {
 	struct vivi_fh         *fh = file->private_data;
 	struct vivi_dev *dev       = fh->dev;
@@ -1079,26 +1126,48 @@ static int vivi_release(struct inode *inode, struct file *file)
 	videobuf_stop(&fh->vb_vidq);
 	videobuf_mmap_free(&fh->vb_vidq);
 
-	kfree (fh);
+	kfree(fh);
 
 	dev->users--;
 
-	printk(KERN_DEBUG "vivi: close called (minor=%d, users=%d)\n",minor,dev->users);
+	dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
+		minor, dev->users);
 
 	return 0;
 }
 
-static int
-vivi_mmap(struct file *file, struct vm_area_struct * vma)
+static int vivi_release(void)
 {
-	struct vivi_fh        *fh = file->private_data;
+	struct vivi_dev *dev;
+	struct list_head *list;
+
+	while (!list_empty(&vivi_devlist)) {
+		list = vivi_devlist.next;
+		list_del(list);
+		dev = list_entry(list, struct vivi_dev, vivi_devlist);
+
+		if (-1 != dev->vfd->minor)
+			video_unregister_device(dev->vfd);
+		else
+			video_device_release(dev->vfd);
+
+		kfree(dev);
+	}
+
+	return 0;
+}
+
+static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct vivi_fh  *fh = file->private_data;
+	struct vivi_dev *dev = fh->dev;
 	int ret;
 
-	dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
+	dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
-	ret=videobuf_mmap_mapper(&fh->vb_vidq, vma);
+	ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
 
-	dprintk (1,"vma start=0x%08lx, size=%ld, ret=%d\n",
+	dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
 		(unsigned long)vma->vm_start,
 		(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
 		ret);
@@ -1109,7 +1178,7 @@ vivi_mmap(struct file *file, struct vm_area_struct * vma)
 static const struct file_operations vivi_fops = {
 	.owner		= THIS_MODULE,
 	.open           = vivi_open,
-	.release        = vivi_release,
+	.release        = vivi_close,
 	.read           = vivi_read,
 	.poll		= vivi_poll,
 	.ioctl          = video_ioctl2, /* V4L2 ioctl handler */
@@ -1117,12 +1186,12 @@ static const struct file_operations vivi_fops = {
 	.llseek         = no_llseek,
 };
 
-static struct video_device vivi = {
+static struct video_device vivi_template = {
 	.name		= "vivi",
 	.type		= VID_TYPE_CAPTURE,
 	.fops           = &vivi_fops,
 	.minor		= -1,
-//	.release	= video_device_release,
+	.release	= video_device_release,
 
 	.vidioc_querycap      = vidioc_querycap,
 	.vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
@@ -1145,7 +1214,7 @@ static struct video_device vivi = {
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 	.vidiocgmbuf          = vidiocgmbuf,
 #endif
-	.tvnorms              = V4L2_STD_NTSC_M,
+	.tvnorms              = V4L2_STD_525_60,
 	.current_norm         = V4L2_STD_NTSC_M,
 };
 /* -----------------------------------------------------------------
@@ -1154,43 +1223,61 @@ static struct video_device vivi = {
 
 static int __init vivi_init(void)
 {
-	int ret;
+	int ret = -ENOMEM, i;
 	struct vivi_dev *dev;
+	struct video_device *vfd;
 
-	dev = kzalloc(sizeof(*dev),GFP_KERNEL);
-	if (NULL == dev)
-		return -ENOMEM;
-	list_add_tail(&dev->vivi_devlist,&vivi_devlist);
+	for (i = 0; i < n_devs; i++) {
+		dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+		if (NULL == dev)
+			break;
 
-	/* init video dma queues */
-	INIT_LIST_HEAD(&dev->vidq.active);
-	INIT_LIST_HEAD(&dev->vidq.queued);
-	init_waitqueue_head(&dev->vidq.wq);
+		list_add_tail(&dev->vivi_devlist, &vivi_devlist);
 
-	/* initialize locks */
-	mutex_init(&dev->lock);
+		/* init video dma queues */
+		INIT_LIST_HEAD(&dev->vidq.active);
+		INIT_LIST_HEAD(&dev->vidq.queued);
+		init_waitqueue_head(&dev->vidq.wq);
 
-	dev->vidq.timeout.function = vivi_vid_timeout;
-	dev->vidq.timeout.data     = (unsigned long)dev;
-	init_timer(&dev->vidq.timeout);
+		/* initialize locks */
+		mutex_init(&dev->lock);
+		spin_lock_init(&dev->slock);
 
-	ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
-	printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
+		dev->vidq.timeout.function = vivi_vid_timeout;
+		dev->vidq.timeout.data     = (unsigned long)dev;
+		init_timer(&dev->vidq.timeout);
+
+		vfd = video_device_alloc();
+		if (NULL == vfd)
+			break;
+
+		*vfd = vivi_template;
+
+		ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+		if (ret < 0)
+			break;
+
+		snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
+			 vivi_template.name, vfd->minor);
+
+		if (video_nr >= 0)
+			video_nr++;
+
+		dev->vfd = vfd;
+	}
+
+	if (ret < 0) {
+		vivi_release();
+		printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
+	} else
+		printk(KERN_INFO "Video Technology Magazine Virtual Video "
+				 "Capture Board successfully loaded.\n");
 	return ret;
 }
 
 static void __exit vivi_exit(void)
 {
-	struct vivi_dev *h;
-	struct list_head *list;
-
-	while (!list_empty(&vivi_devlist)) {
-		list = vivi_devlist.next;
-		list_del(list);
-		h = list_entry(list, struct vivi_dev, vivi_devlist);
-		kfree (h);
-	}
-	video_unregister_device(&vivi);
+	vivi_release();
 }
 
 module_init(vivi_init);
@@ -1201,10 +1288,13 @@ MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
 MODULE_LICENSE("Dual BSD/GPL");
 
 module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr, "video iminor start number");
 
-module_param_named(debug,vivi.debug, int, 0644);
-MODULE_PARM_DESC(debug,"activates debug info");
+module_param(n_devs, int, 0);
+MODULE_PARM_DESC(n_devs, "number of video devices to create");
 
-module_param(vid_limit,int,0644);
-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+module_param_named(debug, vivi_template.debug, int, 0444);
+MODULE_PARM_DESC(debug, "activates debug info");
 
+module_param(vid_limit, int, 0644);
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
index 63002e0ac764..282c81403c97 100644
--- a/drivers/media/video/vp27smpx.c
+++ b/drivers/media/video/vp27smpx.c
@@ -30,15 +30,12 @@
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("vp27smpx driver");
 MODULE_AUTHOR("Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END };
-
-
-I2C_CLIENT_INSMOD;
 
 /* ----------------------------------------------------------------------- */
 
@@ -53,28 +50,26 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
 	u8 data[3] = { 0x00, 0x00, 0x04 };
 
 	switch (audmode) {
-		case V4L2_TUNER_MODE_MONO:
-		case V4L2_TUNER_MODE_LANG1:
-			break;
-		case V4L2_TUNER_MODE_STEREO:
-		case V4L2_TUNER_MODE_LANG1_LANG2:
-			data[1] = 0x01;
-			break;
-		case V4L2_TUNER_MODE_LANG2:
-			data[1] = 0x02;
-			break;
+	case V4L2_TUNER_MODE_MONO:
+	case V4L2_TUNER_MODE_LANG1:
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		data[1] = 0x01;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		data[1] = 0x02;
+		break;
 	}
 
-	if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) {
-		v4l_err(client, "%s: I/O error setting audmode\n", client->name);
-	}
-	else {
+	if (i2c_master_send(client, data, sizeof(data)) != sizeof(data))
+		v4l_err(client, "%s: I/O error setting audmode\n",
+				client->name);
+	else
 		state->audmode = audmode;
-	}
 }
 
-static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
-			  void *arg)
+static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
 	struct vp27smpx_state *state = i2c_get_clientdata(client);
 	struct v4l2_tuner *vt = arg;
@@ -103,7 +98,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
 		break;
 
 	case VIDIOC_G_CHIP_IDENT:
-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0);
+		return v4l2_chip_ident_i2c_client(client, arg,
+				V4L2_IDENT_VP27SMPX, 0);
 
 	case VIDIOC_LOG_STATUS:
 		v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
@@ -125,88 +121,43 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static struct i2c_driver i2c_driver;
-
-static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind)
+static int vp27smpx_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	struct vp27smpx_state *state;
 
 	/* Check if the adapter supports the needed features */
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == 0)
-		return -ENOMEM;
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
 
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver;
 	snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
 
-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
 
 	state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
-	if (state == NULL) {
-		kfree(client);
+	if (state == NULL)
 		return -ENOMEM;
-	}
 	state->audmode = V4L2_TUNER_MODE_STEREO;
 	i2c_set_clientdata(client, state);
 
 	/* initialize vp27smpx */
 	vp27smpx_set_audmode(client, state->audmode);
-	i2c_attach_client(client);
-
 	return 0;
 }
 
-static int vp27smpx_probe(struct i2c_adapter *adapter)
+static int vp27smpx_remove(struct i2c_client *client)
 {
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, vp27smpx_attach);
-	return 0;
-}
-
-static int vp27smpx_detach(struct i2c_client *client)
-{
-	struct vp27smpx_state *state = i2c_get_clientdata(client);
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err) {
-		return err;
-	}
-	kfree(state);
-	kfree(client);
-
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-	.driver = {
-		.name = "vp27smpx",
-	},
-	.id             = I2C_DRIVERID_VP27SMPX,
-	.attach_adapter = vp27smpx_probe,
-	.detach_client  = vp27smpx_detach,
-	.command        = vp27smpx_command,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "vp27smpx",
+	.driverid = I2C_DRIVERID_VP27SMPX,
+	.command = vp27smpx_command,
+	.probe = vp27smpx_probe,
+	.remove = vp27smpx_remove,
 };
 
-
-static int __init vp27smpx_init_module(void)
-{
-	return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit vp27smpx_cleanup_module(void)
-{
-	i2c_del_driver(&i2c_driver);
-}
-
-module_init(vp27smpx_init_module);
-module_exit(vp27smpx_cleanup_module);
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index 1bf4cbec6a87..31795b4f8b63 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -30,21 +30,19 @@
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
 
 MODULE_DESCRIPTION("wm8739 driver");
 MODULE_AUTHOR("T. Adachi, Hans Verkuil");
 MODULE_LICENSE("GPL");
 
-static int debug = 0;
-static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END };
+static int debug;
 
 module_param(debug, int, 0644);
 
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 
-I2C_CLIENT_INSMOD;
-
 /* ------------------------------------------------------------------------ */
 
 enum {
@@ -75,12 +73,10 @@ static int wm8739_write(struct i2c_client *client, int reg, u16 val)
 
 	v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val);
 
-	for (i = 0; i < 3; i++) {
-		if (i2c_smbus_write_byte_data(client, (reg << 1) |
-					(val >> 8), val & 0xff) == 0) {
+	for (i = 0; i < 3; i++)
+		if (i2c_smbus_write_byte_data(client,
+				(reg << 1) | (val >> 8), val & 0xff) == 0)
 			return 0;
-		}
-	}
 	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
 	return -1;
 }
@@ -167,7 +163,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
 		.default_value = 58880,
 		.flags         = 0,
 		.type          = V4L2_CTRL_TYPE_INTEGER,
-	},{
+	}, {
 		.id            = V4L2_CID_AUDIO_MUTE,
 		.name          = "Mute",
 		.minimum       = 0,
@@ -176,7 +172,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
 		.default_value = 1,
 		.flags         = 0,
 		.type          = V4L2_CTRL_TYPE_BOOLEAN,
-	},{
+	}, {
 		.id            = V4L2_CID_AUDIO_BALANCE,
 		.name          = "Balance",
 		.minimum       = 0,
@@ -190,7 +186,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = {
 
 /* ------------------------------------------------------------------------ */
 
-static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
 	struct wm8739_state *state = i2c_get_clientdata(client);
 
@@ -200,21 +196,26 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
 		u32 audiofreq = *(u32 *)arg;
 
 		state->clock_freq = audiofreq;
-		wm8739_write(client, R9, 0x000);	/* de-activate */
+		/* de-activate */
+		wm8739_write(client, R9, 0x000);
 		switch (audiofreq) {
 		case 44100:
-			wm8739_write(client, R8, 0x020); /* 256fps, fs=44.1k     */
+			/* 256fps, fs=44.1k */
+			wm8739_write(client, R8, 0x020);
 			break;
 		case 48000:
-			wm8739_write(client, R8, 0x000); /* 256fps, fs=48k       */
+			/* 256fps, fs=48k */
+			wm8739_write(client, R8, 0x000);
 			break;
 		case 32000:
-			wm8739_write(client, R8, 0x018); /* 256fps, fs=32k       */
+			/* 256fps, fs=32k */
+			wm8739_write(client, R8, 0x018);
 			break;
 		default:
 			break;
 		}
-		wm8739_write(client, R9, 0x001);	/* activate */
+		/* activate */
+		wm8739_write(client, R9, 0x001);
 		break;
 	}
 
@@ -238,7 +239,8 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
 	}
 
 	case VIDIOC_G_CHIP_IDENT:
-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0);
+		return v4l2_chip_ident_i2c_client(client,
+				arg, V4L2_IDENT_WM8739, 0);
 
 	case VIDIOC_LOG_STATUS:
 		v4l_info(client, "Frequency: %u Hz\n", state->clock_freq);
@@ -259,27 +261,16 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg
 
 /* i2c implementation */
 
-static struct i2c_driver i2c_driver;
-
-static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind)
+static int wm8739_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	struct wm8739_state *state;
 
 	/* Check if the adapter supports the needed features */
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == NULL)
-		return -ENOMEM;
-
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver;
-	snprintf(client->name, sizeof(client->name) - 1, "wm8739");
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
 
-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
 
 	state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
 	if (state == NULL) {
@@ -295,67 +286,37 @@ static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind)
 	state->clock_freq = 48000;
 	i2c_set_clientdata(client, state);
 
-	/* initialize wm8739 */
-	wm8739_write(client, R15, 0x00); /* reset */
-	wm8739_write(client, R5, 0x000); /* filter setting, high path, offet clear */
-	wm8739_write(client, R6, 0x000); /* ADC, OSC, Power Off mode Disable */
-	wm8739_write(client, R7, 0x049); /* Digital Audio interface format */
-					 /* Enable Master mode */
-					 /* 24 bit, MSB first/left justified */
-	wm8739_write(client, R8, 0x000); /* sampling control */
-					 /* normal, 256fs, 48KHz sampling rate */
-	wm8739_write(client, R9, 0x001); /* activate */
-	wm8739_set_audio(client); 	 /* set volume/mute */
-
-	i2c_attach_client(client);
-
-	return 0;
-}
-
-static int wm8739_probe(struct i2c_adapter *adapter)
-{
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, wm8739_attach);
+	/* Initialize wm8739 */
+
+	/* reset */
+	wm8739_write(client, R15, 0x00);
+	/* filter setting, high path, offet clear */
+	wm8739_write(client, R5, 0x000);
+	/* ADC, OSC, Power Off mode Disable */
+	wm8739_write(client, R6, 0x000);
+	/* Digital Audio interface format:
+	   Enable Master mode, 24 bit, MSB first/left justified */
+	wm8739_write(client, R7, 0x049);
+	/* sampling control: normal, 256fs, 48KHz sampling rate */
+	wm8739_write(client, R8, 0x000);
+	/* activate */
+	wm8739_write(client, R9, 0x001);
+	/* set volume/mute */
+	wm8739_set_audio(client);
 	return 0;
 }
 
-static int wm8739_detach(struct i2c_client *client)
+static int wm8739_remove(struct i2c_client *client)
 {
-	struct wm8739_state *state = i2c_get_clientdata(client);
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err)
-		return err;
-
-	kfree(state);
-	kfree(client);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
-/* ----------------------------------------------------------------------- */
-
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-	.driver = {
-		.name = "wm8739",
-	},
-	.id = I2C_DRIVERID_WM8739,
-	.attach_adapter = wm8739_probe,
-	.detach_client  = wm8739_detach,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "wm8739",
+	.driverid = I2C_DRIVERID_WM8739,
 	.command = wm8739_command,
+	.probe = wm8739_probe,
+	.remove = wm8739_remove,
 };
 
-
-static int __init wm8739_init_module(void)
-{
-	return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit wm8739_cleanup_module(void)
-{
-	i2c_del_driver(&i2c_driver);
-}
-
-module_init(wm8739_init_module);
-module_exit(wm8739_cleanup_module);
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 9f7e894ef962..869f9e7946b6 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -34,6 +34,7 @@
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv-legacy.h>
 
 MODULE_DESCRIPTION("wm8775 driver");
 MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
@@ -44,6 +45,7 @@ static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
 
 I2C_CLIENT_INSMOD;
 
+
 /* ----------------------------------------------------------------------- */
 
 enum {
@@ -66,18 +68,15 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val)
 		return -1;
 	}
 
-	for (i = 0; i < 3; i++) {
-		if (i2c_smbus_write_byte_data(client, (reg << 1) |
-					(val >> 8), val & 0xff) == 0) {
+	for (i = 0; i < 3; i++)
+		if (i2c_smbus_write_byte_data(client,
+				(reg << 1) | (val >> 8), val & 0xff) == 0)
 			return 0;
-		}
-	}
 	v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
 	return -1;
 }
 
-static int wm8775_command(struct i2c_client *client, unsigned int cmd,
-			  void *arg)
+static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg)
 {
 	struct wm8775_state *state = i2c_get_clientdata(client);
 	struct v4l2_routing *route = arg;
@@ -126,7 +125,8 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
 		break;
 
 	case VIDIOC_G_CHIP_IDENT:
-		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0);
+		return v4l2_chip_ident_i2c_client(client,
+				arg, V4L2_IDENT_WM8775, 0);
 
 	case VIDIOC_LOG_STATUS:
 		v4l_info(client, "Input: %d%s\n", state->input,
@@ -159,105 +159,67 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd,
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static struct i2c_driver i2c_driver;
-
-static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
+static int wm8775_probe(struct i2c_client *client)
 {
-	struct i2c_client *client;
 	struct wm8775_state *state;
 
 	/* Check if the adapter supports the needed features */
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-		return 0;
-
-	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-	if (client == 0)
-		return -ENOMEM;
-
-	client->addr = address;
-	client->adapter = adapter;
-	client->driver = &i2c_driver;
-	snprintf(client->name, sizeof(client->name) - 1, "wm8775");
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
 
-	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+	v4l_info(client, "chip found @ 0x%x (%s)\n",
+			client->addr << 1, client->adapter->name);
 
 	state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
-	if (state == NULL) {
-		kfree(client);
+	if (state == NULL)
 		return -ENOMEM;
-	}
 	state->input = 2;
 	state->muted = 0;
 	i2c_set_clientdata(client, state);
 
-	/* initialize wm8775 */
-	wm8775_write(client, R23, 0x000);	/* RESET */
-	wm8775_write(client, R7, 0x000);	/* Disable zero cross detect timeout */
-	wm8775_write(client, R11, 0x021);	/* Left justified, 24-bit mode */
-	wm8775_write(client, R12, 0x102);	/* Master mode, clock ratio 256fs */
-	wm8775_write(client, R13, 0x000);	/* Powered up */
-	wm8775_write(client, R14, 0x1d4);	/* ADC gain +2.5dB, enable zero cross */
-	wm8775_write(client, R15, 0x1d4);	/* ADC gain +2.5dB, enable zero cross */
-	wm8775_write(client, R16, 0x1bf);	/* ALC Stereo, ALC target level -1dB FS */
-	/* max gain +8dB */
-	wm8775_write(client, R17, 0x185);	/* Enable gain control, use zero cross */
-	/* detection, ALC hold time 42.6 ms */
-	wm8775_write(client, R18, 0x0a2);	/* ALC gain ramp up delay 34 s, */
-	/* ALC gain ramp down delay 33 ms */
-	wm8775_write(client, R19, 0x005);	/* Enable noise gate, threshold -72dBfs */
-	wm8775_write(client, R20, 0x07a);	/* Transient window 4ms, lower PGA gain */
-	/* limit -1dB */
-	wm8775_write(client, R21, 0x102);	/* LRBOTH = 1, use input 2. */
-	i2c_attach_client(client);
-
+	/* Initialize wm8775 */
+
+	/* RESET */
+	wm8775_write(client, R23, 0x000);
+	/* Disable zero cross detect timeout */
+	wm8775_write(client, R7, 0x000);
+	/* Left justified, 24-bit mode */
+	wm8775_write(client, R11, 0x021);
+	/* Master mode, clock ratio 256fs */
+	wm8775_write(client, R12, 0x102);
+	/* Powered up */
+	wm8775_write(client, R13, 0x000);
+	/* ADC gain +2.5dB, enable zero cross */
+	wm8775_write(client, R14, 0x1d4);
+	/* ADC gain +2.5dB, enable zero cross */
+	wm8775_write(client, R15, 0x1d4);
+	/* ALC Stereo, ALC target level -1dB FS max gain +8dB */
+	wm8775_write(client, R16, 0x1bf);
+	/* Enable gain control, use zero cross detection,
+	   ALC hold time 42.6 ms */
+	wm8775_write(client, R17, 0x185);
+	/* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
+	wm8775_write(client, R18, 0x0a2);
+	/* Enable noise gate, threshold -72dBfs */
+	wm8775_write(client, R19, 0x005);
+	/* Transient window 4ms, lower PGA gain limit -1dB */
+	wm8775_write(client, R20, 0x07a);
+	/* LRBOTH = 1, use input 2. */
+	wm8775_write(client, R21, 0x102);
 	return 0;
 }
 
-static int wm8775_probe(struct i2c_adapter *adapter)
+static int wm8775_remove(struct i2c_client *client)
 {
-	if (adapter->class & I2C_CLASS_TV_ANALOG)
-		return i2c_probe(adapter, &addr_data, wm8775_attach);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
-static int wm8775_detach(struct i2c_client *client)
-{
-	struct wm8775_state *state = i2c_get_clientdata(client);
-	int err;
-
-	err = i2c_detach_client(client);
-	if (err) {
-		return err;
-	}
-	kfree(state);
-	kfree(client);
-
-	return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* i2c implementation */
-static struct i2c_driver i2c_driver = {
-	.driver = {
-		.name = "wm8775",
-	},
-	.id             = I2C_DRIVERID_WM8775,
-	.attach_adapter = wm8775_probe,
-	.detach_client  = wm8775_detach,
-	.command        = wm8775_command,
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+	.name = "wm8775",
+	.driverid = I2C_DRIVERID_WM8775,
+	.command = wm8775_command,
+	.probe = wm8775_probe,
+	.remove = wm8775_remove,
 };
 
-
-static int __init wm8775_init_module(void)
-{
-	return i2c_add_driver(&i2c_driver);
-}
-
-static void __exit wm8775_cleanup_module(void)
-{
-	i2c_del_driver(&i2c_driver);
-}
-
-module_init(wm8775_init_module);
-module_exit(wm8775_cleanup_module);
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index 6f1892585cbb..1fdbb46de7f3 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -749,7 +749,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
 }
 
 
-static struct file_operations zr364xx_fops = {
+static const struct file_operations zr364xx_fops = {
 	.owner = THIS_MODULE,
 	.open = zr364xx_open,
 	.release = zr364xx_release,
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 52fb216dfe74..425f60c21fdd 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -2056,7 +2056,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 						ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 						    "mpt_upload:  alt_%s has cached_fw=%p \n",
 						    ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
-						ioc->alt_ioc->cached_fw = NULL;
+						ioc->cached_fw = NULL;
 					}
 				} else {
 					printk(MYIOC_s_WARN_FMT
@@ -2262,10 +2262,12 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
 	int ret;
 
 	if (ioc->cached_fw != NULL) {
-		ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
-		    "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
-		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
-			printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
+		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto "
+		    "adapter\n", __FUNCTION__, ioc->name));
+		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)
+		    ioc->cached_fw, CAN_SLEEP)) < 0) {
+			printk(MYIOC_s_WARN_FMT
+			    ": firmware downloadboot failure (%d)!\n",
 			    ioc->name, ret);
 		}
 	}
@@ -2303,13 +2305,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
 		ioc->alloc_total -= sz;
 	}
 
-	if (ioc->cached_fw != NULL) {
-		sz = ioc->facts.FWImageSize;
-		pci_free_consistent(ioc->pcidev, sz,
-			ioc->cached_fw, ioc->cached_fw_dma);
-		ioc->cached_fw = NULL;
-		ioc->alloc_total -= sz;
-	}
+	mpt_free_fw_memory(ioc);
 
 	kfree(ioc->spi_data.nvram);
 	mpt_inactive_raid_list_free(ioc);
@@ -3047,44 +3043,62 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
  *
  *	If memory has already been allocated, the same (cached) value
  *	is returned.
- */
-void
+ *
+ *	Return 0 if successfull, or non-zero for failure
+ **/
+int
 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
 {
-	if (ioc->cached_fw)
-		return;  /* use already allocated memory */
-	if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
+	int rc;
+
+	if (ioc->cached_fw) {
+		rc = 0;  /* use already allocated memory */
+		goto out;
+	}
+	else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
 		ioc->cached_fw = ioc->alt_ioc->cached_fw;  /* use alt_ioc's memory */
 		ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
-		ioc->alloc_total += size;
-		ioc->alt_ioc->alloc_total -= size;
+		rc = 0;
+		goto out;
+	}
+	ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma);
+	if (!ioc->cached_fw) {
+		printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n",
+		    ioc->name);
+		rc = -1;
 	} else {
-		if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
-			ioc->alloc_total += size;
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+		    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size));
+		ioc->alloc_total += size;
+		rc = 0;
 	}
+ out:
+	return rc;
 }
+
 /**
  *	mpt_free_fw_memory - free firmware memory
  *	@ioc: Pointer to MPT_ADAPTER structure
  *
  *	If alt_img is NULL, delete from ioc structure.
  *	Else, delete a secondary image in same format.
- */
+ **/
 void
 mpt_free_fw_memory(MPT_ADAPTER *ioc)
 {
 	int sz;
 
+	if (!ioc->cached_fw)
+		return;
+
 	sz = ioc->facts.FWImageSize;
-	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
-	    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+		 ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
 	pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
+	ioc->alloc_total -= sz;
 	ioc->cached_fw = NULL;
-
-	return;
 }
 
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	mpt_do_upload - Construct and Send FWUpload request to MPT adapter port.
@@ -3116,17 +3130,12 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
 	if ((sz = ioc->facts.FWImageSize) == 0)
 		return 0;
 
-	mpt_alloc_fw_memory(ioc, sz);
+	if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0)
+		return -ENOMEM;
 
 	dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image  @ %p[%p], sz=%d[%x] bytes\n",
 	    ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
 
-	if (ioc->cached_fw == NULL) {
-		/* Major Failure.
-		 */
-		return -ENOMEM;
-	}
-
 	prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
 	    kzalloc(ioc->req_sz, GFP_KERNEL);
 	if (!prequest) {
@@ -3498,12 +3507,12 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
 static int
 mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
 {
-	MPT_ADAPTER	*iocp=NULL;
 	u32 diag0val;
 	u32 doorbell;
 	int hard_reset_done = 0;
 	int count = 0;
 	u32 diag1val = 0;
+	MpiFwHeader_t *cached_fw;	/* Pointer to FW */
 
 	/* Clear any existing interrupts */
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
@@ -3635,22 +3644,24 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
 		}
 
 		if (ioc->cached_fw)
-			iocp = ioc;
+			cached_fw = (MpiFwHeader_t *)ioc->cached_fw;
 		else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
-			iocp = ioc->alt_ioc;
-		if (iocp) {
+			cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw;
+		else
+			cached_fw = NULL;
+		if (cached_fw) {
 			/* If the DownloadBoot operation fails, the
 			 * IOC will be left unusable. This is a fatal error
 			 * case.  _diag_reset will return < 0
 			 */
 			for (count = 0; count < 30; count ++) {
-				diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
+				diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
 				if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
 					break;
 				}
 
 				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
-					iocp->name, diag0val, count));
+					ioc->name, diag0val, count));
 				/* wait 1 sec */
 				if (sleepFlag == CAN_SLEEP) {
 					msleep (1000);
@@ -3658,8 +3669,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
 					mdelay (1000);
 				}
 			}
-			if ((count = mpt_downloadboot(ioc,
-				(MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
+			if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) {
 				printk(MYIOC_s_WARN_FMT
 					"firmware downloadboot failure (%d)!\n", ioc->name, count);
 			}
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index d7682e083f59..b49b706c0020 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -907,7 +907,7 @@ extern u32	 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
 extern void	 mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
 extern int	 mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
 extern int	 mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg);
-extern void	 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
+extern int	 mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size);
 extern void	 mpt_free_fw_memory(MPT_ADAPTER *ioc);
 extern int	 mpt_findImVolumes(MPT_ADAPTER *ioc);
 extern int	 mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index e4c94f93de16..f77b329f6923 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -1343,6 +1343,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 		smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
 		memcpy(req->sense, smprep, sizeof(*smprep));
 		req->sense_len = sizeof(*smprep);
+		req->data_len = 0;
+		rsp->data_len -= smprep->ResponseDataLength;
 	} else {
 		printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
 		    ioc->name, __FUNCTION__);
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 626bb3c9af2b..5c614ec38cc4 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -111,7 +111,7 @@ int 		mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
 int 		mptscsih_resume(struct pci_dev *pdev);
 #endif
 
-#define SNS_LEN(scp)	sizeof((scp)->sense_buffer)
+#define SNS_LEN(scp)	SCSI_SENSE_BUFFERSIZE
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index e4ad7a1c4fbd..a95314897402 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -412,13 +412,13 @@ static void i2o_block_delayed_request_fn(struct work_struct *work)
 /**
  *	i2o_block_end_request - Post-processing of completed commands
  *	@req: request which should be completed
- *	@uptodate: 1 for success, 0 for I/O error, < 0 for specific error
+ *	@error: 0 for success, < 0 for error
  *	@nr_bytes: number of bytes to complete
  *
  *	Mark the request as complete. The lock must not be held when entering.
  *
  */
-static void i2o_block_end_request(struct request *req, int uptodate,
+static void i2o_block_end_request(struct request *req, int error,
 				  int nr_bytes)
 {
 	struct i2o_block_request *ireq = req->special;
@@ -426,22 +426,18 @@ static void i2o_block_end_request(struct request *req, int uptodate,
 	struct request_queue *q = req->q;
 	unsigned long flags;
 
-	if (end_that_request_chunk(req, uptodate, nr_bytes)) {
+	if (blk_end_request(req, error, nr_bytes)) {
 		int leftover = (req->hard_nr_sectors << KERNEL_SECTOR_SHIFT);
 
 		if (blk_pc_request(req))
 			leftover = req->data_len;
 
-		if (end_io_error(uptodate))
-			end_that_request_chunk(req, 0, leftover);
+		if (error)
+			blk_end_request(req, -EIO, leftover);
 	}
 
-	add_disk_randomness(req->rq_disk);
-
 	spin_lock_irqsave(q->queue_lock, flags);
 
-	end_that_request_last(req, uptodate);
-
 	if (likely(dev)) {
 		dev->open_queue_depth--;
 		list_del(&ireq->queue);
@@ -468,7 +464,7 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m,
 			   struct i2o_message *msg)
 {
 	struct request *req;
-	int uptodate = 1;
+	int error = 0;
 
 	req = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
 	if (unlikely(!req)) {
@@ -501,10 +497,10 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m,
 
 		req->errors++;
 
-		uptodate = 0;
+		error = -EIO;
 	}
 
-	i2o_block_end_request(req, uptodate, le32_to_cpu(msg->body[1]));
+	i2o_block_end_request(req, error, le32_to_cpu(msg->body[1]));
 
 	return 1;
 };
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index aa6fb9429d58..1bcdbbb9e7d3 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -370,7 +370,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
 	 */
 	if (cmd->result)
 		memcpy(cmd->sense_buffer, &msg->body[3],
-		       min(sizeof(cmd->sense_buffer), (size_t) 40));
+		       min(SCSI_SENSE_BUFFERSIZE, 40));
 
 	/* only output error code if AdapterStatus is not HBA_SUCCESS */
 	if ((error >> 8) & 0xff)
diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
index e325fa71f38b..61aeaf79640d 100644
--- a/drivers/mfd/ucb1x00-assabet.c
+++ b/drivers/mfd/ucb1x00-assabet.c
@@ -20,7 +20,8 @@
 #include "ucb1x00.h"
 
 #define UCB1X00_ATTR(name,input)\
-static ssize_t name##_show(struct class_device *dev, char *buf)	\
+static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
+			   char *buf)	\
 {								\
 	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);		\
 	int val;						\
@@ -29,7 +30,7 @@ static ssize_t name##_show(struct class_device *dev, char *buf)	\
 	ucb1x00_adc_disable(ucb);				\
 	return sprintf(buf, "%d\n", val);			\
 }								\
-static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL)
+static DEVICE_ATTR(name,0444,name##_show,NULL)
 
 UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1);
 UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0);
@@ -37,17 +38,17 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
 
 static int ucb1x00_assabet_add(struct ucb1x00_dev *dev)
 {
-	class_device_create_file(&dev->ucb->cdev, &class_device_attr_vbatt);
-	class_device_create_file(&dev->ucb->cdev, &class_device_attr_vcharger);
-	class_device_create_file(&dev->ucb->cdev, &class_device_attr_batt_temp);
+	device_create_file(&dev->ucb->dev, &dev_attr_vbatt);
+	device_create_file(&dev->ucb->dev, &dev_attr_vcharger);
+	device_create_file(&dev->ucb->dev, &dev_attr_batt_temp);
 	return 0;
 }
 
 static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev)
 {
-	class_device_remove_file(&dev->ucb->cdev, &class_device_attr_batt_temp);
-	class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vcharger);
-	class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vbatt);
+	device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp);
+	device_remove_file(&dev->ucb->dev, &dev_attr_vcharger);
+	device_remove_file(&dev->ucb->dev, &dev_attr_vbatt);
 }
 
 static struct ucb1x00_driver ucb1x00_assabet_driver = {
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index e03f1bcd4f9f..f6b10dda31fd 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -458,7 +458,7 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
 	return probe_irq_off(mask);
 }
 
-static void ucb1x00_release(struct class_device *dev)
+static void ucb1x00_release(struct device *dev)
 {
 	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
 	kfree(ucb);
@@ -466,7 +466,7 @@ static void ucb1x00_release(struct class_device *dev)
 
 static struct class ucb1x00_class = {
 	.name		= "ucb1x00",
-	.release	= ucb1x00_release,
+	.dev_release	= ucb1x00_release,
 };
 
 static int ucb1x00_probe(struct mcp *mcp)
@@ -490,9 +490,9 @@ static int ucb1x00_probe(struct mcp *mcp)
 		goto err_disable;
 
 
-	ucb->cdev.class = &ucb1x00_class;
-	ucb->cdev.dev = &mcp->attached_device;
-	strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id));
+	ucb->dev.class = &ucb1x00_class;
+	ucb->dev.parent = &mcp->attached_device;
+	strlcpy(ucb->dev.bus_id, "ucb1x00", sizeof(ucb->dev.bus_id));
 
 	spin_lock_init(&ucb->lock);
 	spin_lock_init(&ucb->io_lock);
@@ -517,7 +517,7 @@ static int ucb1x00_probe(struct mcp *mcp)
 
 	mcp_set_drvdata(mcp, ucb);
 
-	ret = class_device_register(&ucb->cdev);
+	ret = device_register(&ucb->dev);
 	if (ret)
 		goto err_irq;
 
@@ -554,7 +554,7 @@ static void ucb1x00_remove(struct mcp *mcp)
 	mutex_unlock(&ucb1x00_mutex);
 
 	free_irq(ucb->irq, ucb);
-	class_device_unregister(&ucb->cdev);
+	device_unregister(&ucb->dev);
 }
 
 int ucb1x00_register_driver(struct ucb1x00_driver *drv)
diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h
index ca8df8072d43..a8ad8a0ed5db 100644
--- a/drivers/mfd/ucb1x00.h
+++ b/drivers/mfd/ucb1x00.h
@@ -120,7 +120,7 @@ struct ucb1x00 {
 	u16			irq_fal_enbl;
 	u16			irq_ris_enbl;
 	struct ucb1x00_irq	irq_handler[16];
-	struct class_device	cdev;
+	struct device		dev;
 	struct list_head	node;
 	struct list_head	devs;
 };
@@ -144,7 +144,7 @@ struct ucb1x00_driver {
 	int	(*resume)(struct ucb1x00_dev *dev);
 };
 
-#define classdev_to_ucb1x00(cd)	container_of(cd, struct ucb1x00, cdev)
+#define classdev_to_ucb1x00(cd)	container_of(cd, struct ucb1x00, dev)
 
 int ucb1x00_register_driver(struct ucb1x00_driver *);
 void ucb1x00_unregister_driver(struct ucb1x00_driver *);
diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c
index 6497872df524..1a0e7978226a 100644
--- a/drivers/misc/ibmasm/command.c
+++ b/drivers/misc/ibmasm/command.c
@@ -26,11 +26,6 @@
 #include "lowlevel.h"
 
 static void exec_next_command(struct service_processor *sp);
-static void free_command(struct kobject *kobj);
-
-static struct kobj_type ibmasm_cmd_kobj_type = {
-	.release = free_command,
-};
 
 static atomic_t command_count = ATOMIC_INIT(0);
 
@@ -53,8 +48,7 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
 	}
 	cmd->buffer_size = buffer_size;
 
-	kobject_init(&cmd->kobj);
-	cmd->kobj.ktype = &ibmasm_cmd_kobj_type;
+	kref_init(&cmd->kref);
 	cmd->lock = &sp->lock;
 
 	cmd->status = IBMASM_CMD_PENDING;
@@ -67,9 +61,9 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
 	return cmd;
 }
 
-static void free_command(struct kobject *kobj)
+void ibmasm_free_command(struct kref *kref)
 {
-	struct command *cmd = to_command(kobj);
+	struct command *cmd = to_command(kref);
 
 	list_del(&cmd->queue_node);
 	atomic_dec(&command_count);
diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
index de860bc6d3f5..4d8a4e248b34 100644
--- a/drivers/misc/ibmasm/ibmasm.h
+++ b/drivers/misc/ibmasm/ibmasm.h
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/kref.h>
 #include <linux/device.h>
 #include <linux/input.h>
 
@@ -92,24 +93,25 @@ struct command {
 	unsigned char		*buffer;
 	size_t			buffer_size;
 	int			status;
-	struct kobject		kobj;
+	struct kref		kref;
 	spinlock_t		*lock;
 };
-#define to_command(c) container_of(c, struct command, kobj)
+#define to_command(c) container_of(c, struct command, kref)
 
+void ibmasm_free_command(struct kref *kref);
 static inline void command_put(struct command *cmd)
 {
 	unsigned long flags;
 	spinlock_t *lock = cmd->lock;
 
 	spin_lock_irqsave(lock, flags);
-	kobject_put(&cmd->kobj);
+	kref_put(&cmd->kref, ibmasm_free_command);
 	spin_unlock_irqrestore(lock, flags);
 }
 
 static inline void command_get(struct command *cmd)
 {
-	kobject_get(&cmd->kobj);
+	kref_get(&cmd->kref);
 }
 
 
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 2d1b3df95c5b..54380da343a5 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -149,7 +149,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
 	socket_change_set = fm->socket_change_set;
 	fm->socket_change_set = 0;
 
-	dev_dbg(fm->cdev.dev, "checking media set %x\n",
+	dev_dbg(fm->dev.parent, "checking media set %x\n",
 		socket_change_set);
 
 	if (!socket_change_set) {
@@ -164,7 +164,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work)
 		if (sock) {
 			printk(KERN_INFO
 			       "%s : demand removing card from socket %u:%u\n",
-			       fm->cdev.class_id, fm->id, cnt);
+			       fm->dev.bus_id, fm->id, cnt);
 			fm->sockets[cnt] = NULL;
 			sock_addr = sock->addr;
 			spin_unlock_irqrestore(&fm->lock, flags);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index 8f77949f93dd..97544052e768 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -160,16 +160,16 @@ static struct bus_type tifm_bus_type = {
 	.resume    = tifm_device_resume
 };
 
-static void tifm_free(struct class_device *cdev)
+static void tifm_free(struct device *dev)
 {
-	struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
+	struct tifm_adapter *fm = container_of(dev, struct tifm_adapter, dev);
 
 	kfree(fm);
 }
 
 static struct class tifm_adapter_class = {
 	.name    = "tifm_adapter",
-	.release = tifm_free
+	.dev_release = tifm_free
 };
 
 struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
@@ -180,9 +180,9 @@ struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
 	fm = kzalloc(sizeof(struct tifm_adapter)
 		     + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
 	if (fm) {
-		fm->cdev.class = &tifm_adapter_class;
-		fm->cdev.dev = dev;
-		class_device_initialize(&fm->cdev);
+		fm->dev.class = &tifm_adapter_class;
+		fm->dev.parent = dev;
+		device_initialize(&fm->dev);
 		spin_lock_init(&fm->lock);
 		fm->num_sockets = num_sockets;
 	}
@@ -203,8 +203,8 @@ int tifm_add_adapter(struct tifm_adapter *fm)
 	if (rc)
 		return rc;
 
-	snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
-	rc = class_device_add(&fm->cdev);
+	snprintf(fm->dev.bus_id, BUS_ID_SIZE, "tifm%u", fm->id);
+	rc = device_add(&fm->dev);
 	if (rc) {
 		spin_lock(&tifm_adapter_lock);
 		idr_remove(&tifm_adapter_idr, fm->id);
@@ -228,13 +228,13 @@ void tifm_remove_adapter(struct tifm_adapter *fm)
 	spin_lock(&tifm_adapter_lock);
 	idr_remove(&tifm_adapter_idr, fm->id);
 	spin_unlock(&tifm_adapter_lock);
-	class_device_del(&fm->cdev);
+	device_del(&fm->dev);
 }
 EXPORT_SYMBOL(tifm_remove_adapter);
 
 void tifm_free_adapter(struct tifm_adapter *fm)
 {
-	class_device_put(&fm->cdev);
+	put_device(&fm->dev);
 }
 EXPORT_SYMBOL(tifm_free_adapter);
 
@@ -261,9 +261,9 @@ struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
 		sock->card_event = tifm_dummy_event;
 		sock->data_event = tifm_dummy_event;
 
-		sock->dev.parent = fm->cdev.dev;
+		sock->dev.parent = fm->dev.parent;
 		sock->dev.bus = &tifm_bus_type;
-		sock->dev.dma_mask = fm->cdev.dev->dma_mask;
+		sock->dev.dma_mask = fm->dev.parent->dma_mask;
 		sock->dev.release = tifm_free_device;
 
 		snprintf(sock->dev.bus_id, BUS_ID_SIZE,
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index aeb32a93f6a0..91ded3e82401 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -348,15 +348,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 		 * A block was successfully transferred.
 		 */
 		spin_lock_irq(&md->lock);
-		ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
-		if (!ret) {
-			/*
-			 * The whole request completed successfully.
-			 */
-			add_disk_randomness(req->rq_disk);
-			blkdev_dequeue_request(req);
-			end_that_request_last(req, 1);
-		}
+		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
 		spin_unlock_irq(&md->lock);
 	} while (ret);
 
@@ -386,27 +378,21 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 			else
 				bytes = blocks << 9;
 			spin_lock_irq(&md->lock);
-			ret = end_that_request_chunk(req, 1, bytes);
+			ret = __blk_end_request(req, 0, bytes);
 			spin_unlock_irq(&md->lock);
 		}
 	} else if (rq_data_dir(req) != READ &&
 		   (card->host->caps & MMC_CAP_MULTIWRITE)) {
 		spin_lock_irq(&md->lock);
-		ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
+		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
 		spin_unlock_irq(&md->lock);
 	}
 
 	mmc_release_host(card->host);
 
 	spin_lock_irq(&md->lock);
-	while (ret) {
-		ret = end_that_request_chunk(req, 0,
-				req->current_nr_sectors << 9);
-	}
-
-	add_disk_randomness(req->rq_disk);
-	blkdev_dequeue_request(req);
-	end_that_request_last(req, 0);
+	while (ret)
+		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
 	spin_unlock_irq(&md->lock);
 
 	return 0;
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 30cd13b13ac3..7731ddefdc1b 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -94,8 +94,8 @@ static void mmc_request(struct request_queue *q)
 		printk(KERN_ERR "MMC: killing requests for dead queue\n");
 		while ((req = elv_next_request(q)) != NULL) {
 			do {
-				ret = end_that_request_chunk(req, 0,
-					req->current_nr_sectors << 9);
+				ret = __blk_end_request(req, -EIO,
+							blk_rq_cur_bytes(req));
 			} while (ret);
 		}
 		return;
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 971e18b91f4a..c9dfeb15b487 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -25,6 +25,7 @@
 #include <linux/mmc/card.h>
 #include <linux/clk.h>
 #include <linux/scatterlist.h>
+#include <linux/i2c/tps65010.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -35,7 +36,6 @@
 #include <asm/arch/dma.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
-#include <asm/arch/tps65010.h>
 
 #define	OMAP_MMC_REG_CMD	0x00
 #define	OMAP_MMC_REG_ARGL	0x04
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 1654a3330340..1ea8482037bb 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -65,6 +65,8 @@ struct pxamci_host {
 	unsigned int		dma_len;
 
 	unsigned int		dma_dir;
+	unsigned int		dma_drcmrrx;
+	unsigned int		dma_drcmrtx;
 };
 
 static void pxamci_stop_clock(struct pxamci_host *host)
@@ -131,13 +133,13 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
 	if (data->flags & MMC_DATA_READ) {
 		host->dma_dir = DMA_FROM_DEVICE;
 		dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
-		DRCMRTXMMC = 0;
-		DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
+		DRCMR(host->dma_drcmrtx) = 0;
+		DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
 	} else {
 		host->dma_dir = DMA_TO_DEVICE;
 		dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
-		DRCMRRXMMC = 0;
-		DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
+		DRCMR(host->dma_drcmrrx) = 0;
+		DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
 	}
 
 	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
@@ -375,14 +377,23 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		if (host->clkrt == CLKRT_OFF)
 			clk_enable(host->clk);
 
-		/*
-		 * clk might result in a lower divisor than we
-		 * desire.  check for that condition and adjust
-		 * as appropriate.
-		 */
-		if (rate / clk > ios->clock)
-			clk <<= 1;
-		host->clkrt = fls(clk) - 1;
+		if (ios->clock == 26000000) {
+			/* to support 26MHz on pxa300/pxa310 */
+			host->clkrt = 7;
+		} else {
+			/* to handle (19.5MHz, 26MHz) */
+			if (!clk)
+				clk = 1;
+
+			/*
+			 * clk might result in a lower divisor than we
+			 * desire.  check for that condition and adjust
+			 * as appropriate.
+			 */
+			if (rate / clk > ios->clock)
+				clk <<= 1;
+			host->clkrt = fls(clk) - 1;
+		}
 
 		/*
 		 * we write clkrt on the next command
@@ -459,7 +470,7 @@ static int pxamci_probe(struct platform_device *pdev)
 {
 	struct mmc_host *mmc;
 	struct pxamci_host *host = NULL;
-	struct resource *r;
+	struct resource *r, *dmarx, *dmatx;
 	int ret, irq;
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -519,7 +530,8 @@ static int pxamci_probe(struct platform_device *pdev)
 	 * Calculate minimum clock rate, rounding up.
 	 */
 	mmc->f_min = (host->clkrate + 63) / 64;
-	mmc->f_max = host->clkrate;
+	mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000
+							  : host->clkrate;
 
 	mmc->ocr_avail = host->pdata ?
 			 host->pdata->ocr_mask :
@@ -529,6 +541,9 @@ static int pxamci_probe(struct platform_device *pdev)
 	if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) {
 		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 		host->cmdat |= CMDAT_SDIO_INT_EN;
+		if (cpu_is_pxa300() || cpu_is_pxa310())
+			mmc->caps |= MMC_CAP_MMC_HIGHSPEED |
+				     MMC_CAP_SD_HIGHSPEED;
 	}
 
 	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
@@ -570,6 +585,20 @@ static int pxamci_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, mmc);
 
+	dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!dmarx) {
+		ret = -ENXIO;
+		goto out;
+	}
+	host->dma_drcmrrx = dmarx->start;
+
+	dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!dmatx) {
+		ret = -ENXIO;
+		goto out;
+	}
+	host->dma_drcmrtx = dmatx->start;
+
 	if (host->pdata && host->pdata->init)
 		host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
 
@@ -613,8 +642,8 @@ static int pxamci_remove(struct platform_device *pdev)
 		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
 		       host->base + MMC_I_MASK);
 
-		DRCMRRXMMC = 0;
-		DRCMRTXMMC = 0;
+		DRCMR(host->dma_drcmrrx) = 0;
+		DRCMR(host->dma_drcmrtx) = 0;
 
 		free_irq(host->irq, host);
 		pxa_free_dma(host->dma);
diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h
index 748c7706f237..f6c2e2fcce37 100644
--- a/drivers/mmc/host/pxamci.h
+++ b/drivers/mmc/host/pxamci.h
@@ -68,7 +68,7 @@
 #define PRG_DONE		(1 << 1)
 #define DATA_TRAN_DONE		(1 << 0)
 
-#ifdef CONFIG_PXA27x
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
 #define MMC_I_MASK_ALL          0x00001fff
 #else
 #define MMC_I_MASK_ALL          0x0000007f
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 22ed96c4b7bd..a0cee86464ca 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -27,12 +27,10 @@ static void mtd_notify_add(struct mtd_info* mtd)
 	if (!mtd)
 		return;
 
-	class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
-			    NULL, "mtd%d", mtd->index);
+	device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), "mtd%d", mtd->index);
 
-	class_device_create(mtd_class, NULL,
-			    MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
-			    NULL, "mtd%dro", mtd->index);
+	device_create(mtd_class, NULL,
+		      MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), "mtd%dro", mtd->index);
 }
 
 static void mtd_notify_remove(struct mtd_info* mtd)
@@ -40,8 +38,8 @@ static void mtd_notify_remove(struct mtd_info* mtd)
 	if (!mtd)
 		return;
 
-	class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
-	class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
+	device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
+	device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
 }
 
 static struct mtd_notifier notifier = {
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index be71868d1513..7d253686ed0d 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -17,7 +17,7 @@
 	Annapolis MD 21403
 
     Fixed (again!) the missing interrupt locking on TX/RX shifting.
-    		Alan Cox <Alan.Cox@linux.org>
+	Alan Cox <Alan.Cox@linux.org>
 
     Removed calls to init_etherdev since they are no longer needed, and
     cleaned up modularization just a bit. The driver still allows only
@@ -29,16 +29,16 @@
     the board. Now getting 150K/second FTP with a 3c501 card. Still playing
     with a TX-TX optimisation to see if we can touch 180-200K/second as seems
     theoretically maximum.
-    		19950402 Alan Cox <Alan.Cox@linux.org>
+		19950402 Alan Cox <Alan.Cox@linux.org>
 
     Cleaned up for 2.3.x because we broke SMP now.
-    		20000208 Alan Cox <alan@redhat.com>
+		20000208 Alan Cox <alan@redhat.com>
 
     Check up pass for 2.5. Nothing significant changed
-    		20021009 Alan Cox <alan@redhat.com>
+		20021009 Alan Cox <alan@redhat.com>
 
     Fixed zero fill corner case
-    		20030104 Alan Cox <alan@redhat.com>
+		20030104 Alan Cox <alan@redhat.com>
 
 
    For the avoidance of doubt the "preferred form" of this code is one which
@@ -139,8 +139,8 @@ static const char version[] =
  *	The boilerplate probe code.
  */
 
-static int io=0x280;
-static int irq=5;
+static int io = 0x280;
+static int irq = 5;
 static int mem_start;
 
 /**
@@ -229,8 +229,7 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr)
 	 *	Read the station address PROM data from the special port.
 	 */
 
-	for (i = 0; i < 6; i++)
-	{
+	for (i = 0; i < 6; i++) {
 		outw(i, ioaddr + EL1_DATAPTR);
 		station_addr[i] = inb(ioaddr + EL1_SAPROM);
 	}
@@ -240,28 +239,24 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr)
 	 */
 
 	if (station_addr[0] == 0x02  &&  station_addr[1] == 0x60
-		&& station_addr[2] == 0x8c)
-	{
+						&& station_addr[2] == 0x8c)
 		mname = "3c501";
-	} else if (station_addr[0] == 0x00  &&  station_addr[1] == 0x80
-	&& station_addr[2] == 0xC8)
-	{
+	else if (station_addr[0] == 0x00  &&  station_addr[1] == 0x80
+						&& station_addr[2] == 0xC8)
 		mname = "NP943";
-    	}
-    	else {
+	else {
 		release_region(ioaddr, EL1_IO_EXTENT);
 		return -ENODEV;
 	}
 
 	/*
-	 *	We auto-IRQ by shutting off the interrupt line and letting it float
-	 *	high.
+	 *	We auto-IRQ by shutting off the interrupt line and letting it
+	 *	float high.
 	 */
 
 	dev->irq = irq;
 
-	if (dev->irq < 2)
-	{
+	if (dev->irq < 2) {
 		unsigned long irq_mask;
 
 		irq_mask = probe_irq_on();
@@ -274,8 +269,7 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr)
 		mdelay(20);
 		autoirq = probe_irq_off(irq_mask);
 
-		if (autoirq == 0)
-		{
+		if (autoirq == 0) {
 			printk(KERN_WARNING "%s probe at %#x failed to detect IRQ line.\n",
 				mname, ioaddr);
 			release_region(ioaddr, EL1_IO_EXTENT);
@@ -292,7 +286,8 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr)
 	if (autoirq)
 		dev->irq = autoirq;
 
-	printk(KERN_INFO "%s: %s EtherLink at %#lx, using %sIRQ %d.\n", dev->name, mname, dev->base_addr,
+	printk(KERN_INFO "%s: %s EtherLink at %#lx, using %sIRQ %d.\n",
+			dev->name, mname, dev->base_addr,
 			autoirq ? "auto":"assigned ", dev->irq);
 
 #ifdef CONFIG_IP_MULTICAST
@@ -343,7 +338,8 @@ static int el_open(struct net_device *dev)
 	if (el_debug > 2)
 		printk(KERN_DEBUG "%s: Doing el_open()...", dev->name);
 
-	if ((retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev)))
+	retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev);
+	if (retval)
 		return retval;
 
 	spin_lock_irqsave(&lp->lock, flags);
@@ -371,8 +367,9 @@ static void el_timeout(struct net_device *dev)
 	int ioaddr = dev->base_addr;
 
 	if (el_debug)
-		printk (KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
-			dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS));
+		printk(KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
+			dev->name, inb(TX_STATUS),
+			inb(AX_STATUS), inb(RX_STATUS));
 	dev->stats.tx_errors++;
 	outb(TX_NORM, TX_CMD);
 	outb(RX_NORM, RX_CMD);
@@ -425,8 +422,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	netif_stop_queue(dev);
 
-	do
-	{
+	do {
 		int len = skb->len;
 		int pad = 0;
 		int gp_start;
@@ -435,10 +431,10 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		if (len < ETH_ZLEN)
 			pad = ETH_ZLEN - len;
 
-		gp_start = 0x800 - ( len + pad );
+		gp_start = 0x800 - (len + pad);
 
 		lp->tx_pkt_start = gp_start;
-    		lp->collisions = 0;
+		lp->collisions = 0;
 
 		dev->stats.tx_bytes += skb->len;
 
@@ -455,37 +451,42 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		lp->txing = 1;
 
 		/*
-		 *	Turn interrupts back on while we spend a pleasant afternoon
-		 *	loading bytes into the board
+		 *	Turn interrupts back on while we spend a pleasant
+		 *	afternoon loading bytes into the board
 		 */
 
 		spin_unlock_irqrestore(&lp->lock, flags);
 
-		outw(0x00, RX_BUF_CLR);		/* Set rx packet area to 0. */
-		outw(gp_start, GP_LOW);		/* aim - packet will be loaded into buffer start */
-		outsb(DATAPORT,buf,len);	/* load buffer (usual thing each byte increments the pointer) */
+		/* Set rx packet area to 0. */
+		outw(0x00, RX_BUF_CLR);
+		/* aim - packet will be loaded into buffer start */
+		outw(gp_start, GP_LOW);
+		/* load buffer (usual thing each byte increments the pointer) */
+		outsb(DATAPORT, buf, len);
 		if (pad) {
-			while(pad--)		/* Zero fill buffer tail */
+			while (pad--)		/* Zero fill buffer tail */
 				outb(0, DATAPORT);
 		}
-		outw(gp_start, GP_LOW);		/* the board reuses the same register */
+		/* the board reuses the same register */
+		outw(gp_start, GP_LOW);
 
-		if(lp->loading != 2)
-		{
-			outb(AX_XMIT, AX_CMD);		/* fire ... Trigger xmit.  */
-			lp->loading=0;
+		if (lp->loading != 2) {
+			/* fire ... Trigger xmit.  */
+			outb(AX_XMIT, AX_CMD);
+			lp->loading = 0;
 			dev->trans_start = jiffies;
 			if (el_debug > 2)
 				printk(KERN_DEBUG " queued xmit.\n");
-			dev_kfree_skb (skb);
+			dev_kfree_skb(skb);
 			return 0;
 		}
 		/* A receive upset our load, despite our best efforts */
-		if(el_debug>2)
-			printk(KERN_DEBUG "%s: burped during tx load.\n", dev->name);
+		if (el_debug > 2)
+			printk(KERN_DEBUG "%s: burped during tx load.\n",
+				dev->name);
 		spin_lock_irqsave(&lp->lock, flags);
 	}
-	while(1);
+	while (1);
 
 }
 
@@ -534,64 +535,59 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
 	 */
 
 	if (el_debug > 3)
-		printk(KERN_DEBUG "%s: el_interrupt() aux=%#02x", dev->name, axsr);
-
-        if(lp->loading==1 && !lp->txing)
-        	printk(KERN_WARNING "%s: Inconsistent state loading while not in tx\n",
-        		dev->name);
-
-	if (lp->txing)
-	{
+		printk(KERN_DEBUG "%s: el_interrupt() aux=%#02x",
+							dev->name, axsr);
 
-    		/*
-    		 *	Board in transmit mode. May be loading. If we are
-    		 *	loading we shouldn't have got this.
-    		 */
+	if (lp->loading == 1 && !lp->txing)
+		printk(KERN_WARNING "%s: Inconsistent state loading while not in tx\n",
+			dev->name);
 
+	if (lp->txing) {
+		/*
+		 *	Board in transmit mode. May be loading. If we are
+		 *	loading we shouldn't have got this.
+		 */
 		int txsr = inb(TX_STATUS);
 
-		if(lp->loading==1)
-		{
-			if(el_debug > 2)
-			{
-				printk(KERN_DEBUG "%s: Interrupt while loading [", dev->name);
-				printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x]\n", txsr, inw(GP_LOW),inw(RX_LOW));
+		if (lp->loading == 1) {
+			if (el_debug > 2) {
+				printk(KERN_DEBUG "%s: Interrupt while loading [",
+					dev->name);
+				printk(" txsr=%02x gp=%04x rp=%04x]\n",
+					txsr, inw(GP_LOW), inw(RX_LOW));
 			}
-			lp->loading=2;		/* Force a reload */
+			/* Force a reload */
+			lp->loading = 2;
 			spin_unlock(&lp->lock);
 			goto out;
 		}
-
 		if (el_debug > 6)
-			printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),inw(RX_LOW));
+			printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x",
+					txsr, inw(GP_LOW), inw(RX_LOW));
 
-		if ((axsr & 0x80) && (txsr & TX_READY) == 0)
-		{
+		if ((axsr & 0x80) && (txsr & TX_READY) == 0) {
 			/*
-			 *	FIXME: is there a logic to whether to keep on trying or
-			 *	reset immediately ?
+			 *	FIXME: is there a logic to whether to keep
+			 *	on trying or reset immediately ?
 			 */
-			if(el_debug>1)
-				printk(KERN_DEBUG "%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x"
-			  		" gp=%03x rp=%03x.\n", dev->name, txsr, axsr,
-			inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR));
+			if (el_debug > 1)
+				printk(KERN_DEBUG "%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n",
+					dev->name, txsr, axsr,
+					inw(ioaddr + EL1_DATAPTR),
+					inw(ioaddr + EL1_RXPTR));
 			lp->txing = 0;
 			netif_wake_queue(dev);
-		}
-		else if (txsr & TX_16COLLISIONS)
-		{
+		} else if (txsr & TX_16COLLISIONS) {
 			/*
 			 *	Timed out
 			 */
 			if (el_debug)
-				printk (KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name);
+				printk(KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name);
 			outb(AX_SYS, AX_CMD);
 			lp->txing = 0;
 			dev->stats.tx_aborted_errors++;
 			netif_wake_queue(dev);
-		}
-		else if (txsr & TX_COLLISION)
-		{
+		} else if (txsr & TX_COLLISION) {
 			/*
 			 *	Retrigger xmit.
 			 */
@@ -599,7 +595,8 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
 			if (el_debug > 6)
 				printk(KERN_DEBUG " retransmitting after a collision.\n");
 			/*
-			 *	Poor little chip can't reset its own start pointer
+			 *	Poor little chip can't reset its own start
+			 *	pointer
 			 */
 
 			outb(AX_SYS, AX_CMD);
@@ -608,53 +605,45 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
 			dev->stats.collisions++;
 			spin_unlock(&lp->lock);
 			goto out;
-		}
-		else
-		{
+		} else {
 			/*
 			 *	It worked.. we will now fall through and receive
 			 */
 			dev->stats.tx_packets++;
 			if (el_debug > 6)
 				printk(KERN_DEBUG " Tx succeeded %s\n",
-		       			(txsr & TX_RDY) ? "." : "but tx is busy!");
+					(txsr & TX_RDY) ? "." : "but tx is busy!");
 			/*
 			 *	This is safe the interrupt is atomic WRT itself.
 			 */
-
 			lp->txing = 0;
-			netif_wake_queue(dev);	/* In case more to transmit */
+			/* In case more to transmit */
+			netif_wake_queue(dev);
 		}
-	}
-	else
-	{
-    		/*
-    		 *	In receive mode.
-    		 */
+	} else {
+		/*
+		 *	In receive mode.
+		 */
 
 		int rxsr = inb(RX_STATUS);
 		if (el_debug > 5)
-			printk(KERN_DEBUG " rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS),inw(RX_LOW));
+			printk(KERN_DEBUG " rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS), inw(RX_LOW));
 		/*
 		 *	Just reading rx_status fixes most errors.
 		 */
 		if (rxsr & RX_MISSED)
 			dev->stats.rx_missed_errors++;
-		else if (rxsr & RX_RUNT)
-		{	/* Handled to avoid board lock-up. */
+		else if (rxsr & RX_RUNT) {
+			/* Handled to avoid board lock-up. */
 			dev->stats.rx_length_errors++;
 			if (el_debug > 5)
 				printk(KERN_DEBUG " runt.\n");
-		}
-		else if (rxsr & RX_GOOD)
-		{
+		} else if (rxsr & RX_GOOD) {
 			/*
 			 *	Receive worked.
 			 */
 			el_receive(dev);
-		}
-		else
-		{
+		} else {
 			/*
 			 *	Nothing?  Something is broken!
 			 */
@@ -702,8 +691,7 @@ static void el_receive(struct net_device *dev)
 	if (el_debug > 4)
 		printk(KERN_DEBUG " el_receive %d.\n", pkt_len);
 
-	if ((pkt_len < 60)  ||  (pkt_len > 1536))
-	{
+	if (pkt_len < 60 || pkt_len > 1536) {
 		if (el_debug)
 			printk(KERN_DEBUG "%s: bogus packet, length=%d\n", dev->name, pkt_len);
 		dev->stats.rx_over_errors++;
@@ -722,26 +710,23 @@ static void el_receive(struct net_device *dev)
 	 */
 
 	outw(0x00, GP_LOW);
-	if (skb == NULL)
-	{
+	if (skb == NULL) {
 		printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", dev->name);
 		dev->stats.rx_dropped++;
 		return;
-	}
-	else
-	{
-    		skb_reserve(skb,2);	/* Force 16 byte alignment */
+	} else {
+		skb_reserve(skb, 2);	/* Force 16 byte alignment */
 		/*
 		 *	The read increments through the bytes. The interrupt
 		 *	handler will fix the pointer when it returns to
 		 *	receive mode.
 		 */
-		insb(DATAPORT, skb_put(skb,pkt_len), pkt_len);
-		skb->protocol=eth_type_trans(skb,dev);
+		insb(DATAPORT, skb_put(skb, pkt_len), pkt_len);
+		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
 		dev->last_rx = jiffies;
 		dev->stats.rx_packets++;
-		dev->stats.rx_bytes+=pkt_len;
+		dev->stats.rx_bytes += pkt_len;
 	}
 	return;
 }
@@ -760,7 +745,7 @@ static void  el_reset(struct net_device *dev)
 	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 
-	if (el_debug> 2)
+	if (el_debug > 2)
 		printk(KERN_INFO "3c501 reset...");
 	outb(AX_RESET, AX_CMD);		/* Reset the chip */
 	outb(AX_LOOP, AX_CMD);		/* Aux control, irq and loopback enabled */
@@ -794,7 +779,8 @@ static int el1_close(struct net_device *dev)
 	int ioaddr = dev->base_addr;
 
 	if (el_debug > 2)
-		printk(KERN_INFO "%s: Shutting down Ethernet card at %#x.\n", dev->name, ioaddr);
+		printk(KERN_INFO "%s: Shutting down Ethernet card at %#x.\n",
+						dev->name, ioaddr);
 
 	netif_stop_queue(dev);
 
@@ -822,18 +808,14 @@ static void set_multicast_list(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
 
-	if(dev->flags&IFF_PROMISC)
-	{
+	if (dev->flags & IFF_PROMISC) {
 		outb(RX_PROM, RX_CMD);
 		inb(RX_STATUS);
-	}
-	else if (dev->mc_list || dev->flags&IFF_ALLMULTI)
-	{
-		outb(RX_MULT, RX_CMD);	/* Multicast or all multicast is the same */
+	} else if (dev->mc_list || dev->flags & IFF_ALLMULTI) {
+		/* Multicast or all multicast is the same */
+		outb(RX_MULT, RX_CMD);
 		inb(RX_STATUS);		/* Clear status. */
-	}
-	else
-	{
+	} else {
 		outb(RX_NORM, RX_CMD);
 		inb(RX_STATUS);
 	}
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 964d31ac9449..030c147211ba 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -747,7 +747,7 @@ static void init_82586_mem(struct net_device *dev)
 		int boguscnt = 50;
 		while (readw(shmem+iSCB_STATUS) == 0)
 			if (--boguscnt == 0) {
-				printk("%s: i82586 initialization timed out with status %04x,"
+				printk("%s: i82586 initialization timed out with status %04x, "
 					   "cmd %04x.\n", dev->name,
 					   readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD));
 				break;
@@ -832,10 +832,11 @@ static void el16_rx(struct net_device *dev)
 
 		if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22
 			|| (pkt_len & 0xC000) != 0xC000) {
-			printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x"
-				   "next %04x data-buf @%04x %04x.\n", dev->name, rx_head,
-				   frame_status, rfd_cmd, next_rx_frame, data_buffer_addr,
-				   pkt_len);
+			printk(KERN_ERR "%s: Rx frame at %#x corrupted, "
+			       "status %04x cmd %04x next %04x "
+			       "data-buf @%04x %04x.\n",
+			       dev->name, rx_head, frame_status, rfd_cmd,
+			       next_rx_frame, data_buffer_addr, pkt_len);
 		} else if ((frame_status & 0x2000) == 0) {
 			/* Frame Rxed, but with error. */
 			dev->stats.rx_errors++;
@@ -851,7 +852,9 @@ static void el16_rx(struct net_device *dev)
 			pkt_len &= 0x3fff;
 			skb = dev_alloc_skb(pkt_len+2);
 			if (skb == NULL) {
-				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+				printk(KERN_ERR "%s: Memory squeeze, "
+				       "dropping packet.\n",
+				       dev->name);
 				dev->stats.rx_dropped++;
 				break;
 			}
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 684bab781015..6ab84b661d70 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -1361,7 +1361,7 @@ static int boomerang_rx(struct net_device *dev)
 			/* Check if the packet is long enough to just accept without
 			   copying to a properly sized skbuff. */
 			if (pkt_len < rx_copybreak
-			    && (skb = dev_alloc_skb(pkt_len + 4)) != 0) {
+			    && (skb = dev_alloc_skb(pkt_len + 4)) != NULL) {
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				memcpy(skb_put(skb, pkt_len),
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 224e0bff1ae0..750a46f4bc58 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -277,8 +277,6 @@ static int lance_rx (struct net_device *dev)
         volatile struct lance_init_block *ib = lp->init_block;
         volatile struct lance_rx_desc *rd;
         unsigned char bits;
-        int len = 0;                    /* XXX shut up gcc warnings */
-        struct sk_buff *skb = 0;        /* XXX shut up gcc warnings */
 #ifdef TEST_HITS
         int i;
 #endif
@@ -318,10 +316,10 @@ static int lance_rx (struct net_device *dev)
                         if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
                         if (bits & LE_R1_EOP) dev->stats.rx_errors++;
                 } else {
-                        len = (rd->mblength & 0xfff) - 4;
-                        skb = dev_alloc_skb (len+2);
+			int len = (rd->mblength & 0xfff) - 4;
+			struct sk_buff *skb = dev_alloc_skb (len+2);
 
-                        if (skb == 0) {
+                        if (!skb) {
                                 printk ("%s: Memory squeeze, deferring packet.\n",
                                         dev->name);
                                 dev->stats.rx_dropped++;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 8f3f04d4f34b..389980f0e59e 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -212,7 +212,7 @@ config MII
 
 config MACB
 	tristate "Atmel MACB support"
-	depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263
+	depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91CAP9
 	select PHYLIB
 	help
 	  The Atmel MACB ethernet interface is found on many AT32 and AT91
@@ -912,6 +912,24 @@ config DM9000
 	  To compile this driver as a module, choose M here.  The module
 	  will be called dm9000.
 
+config ENC28J60
+	tristate "ENC28J60 support"
+	depends on EXPERIMENTAL && SPI && NET_ETHERNET
+	select CRC32
+	---help---
+	  Support for the Microchip EN28J60 ethernet chip.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/networking/net-modules.txt>.  The module will be
+	  called enc28j60.
+
+config ENC28J60_WRITEVERIFY
+	bool "Enable write verify"
+	depends on ENC28J60
+	---help---
+	  Enable the verify after the buffer write useful for debugging purpose.
+	  If unsure, say N.
+
 config SMC911X
 	tristate "SMSC LAN911[5678] support"
 	select CRC32
@@ -1584,6 +1602,18 @@ config 8139_OLD_RX_RESET
 	  experience problems, you can enable this option to restore the
 	  old RX-reset behavior.  If unsure, say N.
 
+config R6040
+	tristate "RDC R6040 Fast Ethernet Adapter support (EXPERIMENTAL)"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	help
+	  This is a driver for the R6040 Fast Ethernet MACs found in the
+	  the RDC R-321x System-on-chips.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called r6040. This is recommended.
+
 config SIS900
 	tristate "SiS 900/7016 PCI Fast Ethernet Adapter support"
 	depends on NET_PCI && PCI
@@ -1785,7 +1815,7 @@ config DE620
 
 config SGISEEQ
 	tristate "SGI Seeq ethernet controller support"
-	depends on SGI_IP22
+	depends on SGI_HAS_SEEQ
 	help
 	  Say Y here if you have an Seeq based Ethernet network card. This is
 	  used in many Silicon Graphics machines.
@@ -1979,6 +2009,9 @@ config E1000E
 	  To compile this driver as a module, choose M here. The module
 	  will be called e1000e.
 
+config E1000E_ENABLED
+	def_bool E1000E != n
+
 config IP1000
 	tristate "IP1000 Gigabit Ethernet support"
 	depends on PCI && EXPERIMENTAL
@@ -1989,6 +2022,28 @@ config IP1000
 	  To compile this driver as a module, choose M here: the module
 	  will be called ipg.  This is recommended.
 
+config IGB
+       tristate "Intel(R) 82575 PCI-Express Gigabit Ethernet support"
+       depends on PCI
+       ---help---
+         This driver supports Intel(R) 82575 gigabit ethernet family of
+         adapters.  For more information on how to identify your adapter, go
+         to the Adapter & Driver ID Guide at:
+
+         <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+         For general information and support, go to the Intel support
+         website at:
+
+         <http://support.intel.com>
+
+         More specific information on configuring the driver is in
+         <file:Documentation/networking/e1000.txt>.
+
+         To compile this driver as a module, choose M here and read
+         <file:Documentation/networking/net-modules.txt>.  The module
+         will be called igb.
+
 source "drivers/net/ixp2000/Kconfig"
 
 config MYRI_SBUS
@@ -2560,6 +2615,7 @@ config PASEMI_MAC
 	tristate "PA Semi 1/10Gbit MAC"
 	depends on PPC64 && PCI
 	select PHYLIB
+	select INET_LRO
 	help
 	  This driver supports the on-chip 1/10Gbit Ethernet controller on
 	  PA Semi's PWRficient line of chips.
@@ -2585,6 +2641,16 @@ config TEHUTI
 	help
 	  Tehuti Networks 10G Ethernet NIC
 
+config BNX2X
+	tristate "Broadcom NetXtremeII 10Gb support"
+	depends on PCI
+	select ZLIB_INFLATE
+	help
+	  This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards.
+	  To compile this driver as a module, choose M here: the module
+	  will be called bnx2x.  This is recommended.
+
+
 endif # NETDEV_10000
 
 source "drivers/net/tokenring/Kconfig"
@@ -3015,23 +3081,6 @@ config NET_FC
 	  adaptor below. You also should have said Y to "SCSI support" and
 	  "SCSI generic support".
 
-config SHAPER
-	tristate "Traffic Shaper (OBSOLETE)"
-	depends on EXPERIMENTAL
-	---help---
-	  The traffic shaper is a virtual network device that allows you to
-	  limit the rate of outgoing data flow over some other network device.
-	  The traffic that you want to slow down can then be routed through
-	  these virtual devices. See
-	  <file:Documentation/networking/shaper.txt> for more information.
-
-	  An alternative to this traffic shaper are traffic schedulers which
-	  you'll get if you say Y to "QoS and/or fair queuing" in
-	  "Networking options".
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called shaper.  If unsure, say N.
-
 config NETCONSOLE
 	tristate "Network console logging support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 0e5fde4a1b2c..9fc7794e88ea 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -6,12 +6,14 @@ obj-$(CONFIG_E1000) += e1000/
 obj-$(CONFIG_E1000E) += e1000e/
 obj-$(CONFIG_IBM_EMAC) += ibm_emac/
 obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
+obj-$(CONFIG_IGB) += igb/
 obj-$(CONFIG_IXGBE) += ixgbe/
 obj-$(CONFIG_IXGB) += ixgb/
 obj-$(CONFIG_IP1000) += ipg.o
 obj-$(CONFIG_CHELSIO_T1) += chelsio/
 obj-$(CONFIG_CHELSIO_T3) += cxgb3/
 obj-$(CONFIG_EHEA) += ehea/
+obj-$(CONFIG_CAN) += can/
 obj-$(CONFIG_BONDING) += bonding/
 obj-$(CONFIG_ATL1) += atl1/
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
@@ -54,6 +56,7 @@ obj-$(CONFIG_TLAN) += tlan.o
 obj-$(CONFIG_EPIC100) += epic100.o
 obj-$(CONFIG_SIS190) += sis190.o
 obj-$(CONFIG_SIS900) += sis900.o
+obj-$(CONFIG_R6040) += r6040.o
 obj-$(CONFIG_YELLOWFIN) += yellowfin.o
 obj-$(CONFIG_ACENIC) += acenic.o
 obj-$(CONFIG_ISERIES_VETH) += iseries_veth.o
@@ -63,6 +66,7 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_FEALNX) += fealnx.o
 obj-$(CONFIG_TIGON3) += tg3.o
 obj-$(CONFIG_BNX2) += bnx2.o
+obj-$(CONFIG_BNX2X) += bnx2x.o
 spidernet-y += spider_net.o spider_net_ethtool.o
 obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o
 obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
@@ -92,7 +96,6 @@ obj-$(CONFIG_NET_SB1000) += sb1000.o
 obj-$(CONFIG_MAC8390) += mac8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
-obj-$(CONFIG_SHAPER) += shaper.o
 obj-$(CONFIG_HP100) += hp100.o
 obj-$(CONFIG_SMC9194) += smc9194.o
 obj-$(CONFIG_FEC) += fec.o
@@ -216,6 +219,7 @@ obj-$(CONFIG_DM9000) += dm9000.o
 obj-$(CONFIG_FEC_8XX) += fec_8xx/
 obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
 obj-$(CONFIG_MLX4_CORE) += mlx4/
+obj-$(CONFIG_ENC28J60) += enc28j60.o
 
 obj-$(CONFIG_MACB) += macb.o
 
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 18f7f815f66e..6c5719ae8cca 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -269,8 +269,6 @@ static int lance_rx (struct net_device *dev)
 	volatile struct lance_regs *ll = lp->ll;
 	volatile struct lance_rx_desc *rd;
 	unsigned char bits;
-	int len = 0;			/* XXX shut up gcc warnings */
-	struct sk_buff *skb = 0;	/* XXX shut up gcc warnings */
 
 #ifdef TEST_HITS
 	int i;
@@ -306,10 +304,10 @@ static int lance_rx (struct net_device *dev)
 			if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
 			if (bits & LE_R1_EOP) dev->stats.rx_errors++;
 		} else {
-			len = (rd->mblength & 0xfff) - 4;
-			skb = dev_alloc_skb (len+2);
+			int len = (rd->mblength & 0xfff) - 4;
+			struct sk_buff *skb = dev_alloc_skb (len+2);
 
-			if (skb == 0) {
+			if (!skb) {
 				printk(KERN_WARNING "%s: Memory squeeze, "
 				       "deferring packet.\n", dev->name);
 				dev->stats.rx_dropped++;
@@ -477,7 +475,7 @@ static irqreturn_t lance_interrupt (int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-struct net_device *last_dev = 0;
+struct net_device *last_dev;
 
 static int lance_open (struct net_device *dev)
 {
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index e7fdd81919bd..85f7276aaba5 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1945,13 +1945,13 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
 
 	err = pci_enable_device(pdev);
 	if(err){
-		printk(KERN_ERR "amd8111e: Cannot enable new PCI device,"
+		printk(KERN_ERR "amd8111e: Cannot enable new PCI device, "
 			"exiting.\n");
 		return err;
 	}
 
 	if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)){
-		printk(KERN_ERR "amd8111e: Cannot find PCI base address"
+		printk(KERN_ERR "amd8111e: Cannot find PCI base address, "
 		       "exiting.\n");
 		err = -ENODEV;
 		goto err_disable_pdev;
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index b032c1bf492f..24d81f922533 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -465,8 +465,9 @@ found:
 	/* Snarf the interrupt vector now. */
 	ret = request_irq(irq, &net_interrupt, 0, DRV_NAME, dev);
 	if (ret) {
-		printk ("  AT1700 at %#3x is unusable due to a conflict on"
-				"IRQ %d.\n", ioaddr, irq);
+		printk(KERN_ERR "AT1700 at %#3x is unusable due to a "
+		       "conflict on IRQ %d.\n",
+		       ioaddr, irq);
 		goto err_mca;
 	}
 
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 3d247f3f4a3c..ea2a2b548e3c 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -128,6 +128,8 @@ static void b44_init_rings(struct b44 *);
 #define B44_FULL_RESET		1
 #define B44_FULL_RESET_SKIP_PHY	2
 #define B44_PARTIAL_RESET	3
+#define B44_CHIP_RESET_FULL	4
+#define B44_CHIP_RESET_PARTIAL	5
 
 static void b44_init_hw(struct b44 *, int);
 
@@ -1259,7 +1261,7 @@ static void b44_clear_stats(struct b44 *bp)
 }
 
 /* bp->lock is held. */
-static void b44_chip_reset(struct b44 *bp)
+static void b44_chip_reset(struct b44 *bp, int reset_kind)
 {
 	struct ssb_device *sdev = bp->sdev;
 
@@ -1281,6 +1283,13 @@ static void b44_chip_reset(struct b44 *bp)
 	ssb_device_enable(bp->sdev, 0);
 	b44_clear_stats(bp);
 
+	/*
+	 * Don't enable PHY if we are doing a partial reset
+	 * we are probably going to power down
+	 */
+	if (reset_kind == B44_CHIP_RESET_PARTIAL)
+		return;
+
 	switch (sdev->bus->bustype) {
 	case SSB_BUSTYPE_SSB:
 		bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
@@ -1316,7 +1325,14 @@ static void b44_chip_reset(struct b44 *bp)
 static void b44_halt(struct b44 *bp)
 {
 	b44_disable_ints(bp);
-	b44_chip_reset(bp);
+	/* reset PHY */
+	b44_phy_reset(bp);
+	/* power down PHY */
+	printk(KERN_INFO PFX "%s: powering down PHY\n", bp->dev->name);
+	bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN);
+	/* now reset the chip, but without enabling the MAC&PHY
+	 * part of it. This has to be done _after_ we shut down the PHY */
+	b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
 }
 
 /* bp->lock is held. */
@@ -1365,7 +1381,7 @@ static void b44_init_hw(struct b44 *bp, int reset_kind)
 {
 	u32 val;
 
-	b44_chip_reset(bp);
+	b44_chip_reset(bp, B44_CHIP_RESET_FULL);
 	if (reset_kind == B44_FULL_RESET) {
 		b44_phy_reset(bp);
 		b44_setup_phy(bp);
@@ -1422,7 +1438,7 @@ static int b44_open(struct net_device *dev)
 	err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
 	if (unlikely(err < 0)) {
 		napi_disable(&bp->napi);
-		b44_chip_reset(bp);
+		b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
 		b44_free_rings(bp);
 		b44_free_consistent(bp);
 		goto out;
@@ -2060,11 +2076,11 @@ static int __devinit b44_get_invariants(struct b44 *bp)
 
 	if (sdev->bus->bustype == SSB_BUSTYPE_SSB &&
 	    instance > 1) {
-		addr = sdev->bus->sprom.r1.et1mac;
-		bp->phy_addr = sdev->bus->sprom.r1.et1phyaddr;
+		addr = sdev->bus->sprom.et1mac;
+		bp->phy_addr = sdev->bus->sprom.et1phyaddr;
 	} else {
-		addr = sdev->bus->sprom.r1.et0mac;
-		bp->phy_addr = sdev->bus->sprom.r1.et0phyaddr;
+		addr = sdev->bus->sprom.et0mac;
+		bp->phy_addr = sdev->bus->sprom.et0phyaddr;
 	}
 	memcpy(bp->dev->dev_addr, addr, 6);
 
@@ -2188,7 +2204,7 @@ static int __devinit b44_init_one(struct ssb_device *sdev,
 	/* Chip reset provides power to the b44 MAC & PCI cores, which
 	 * is necessary for MAC register access.
 	 */
-	b44_chip_reset(bp);
+	b44_chip_reset(bp, B44_CHIP_RESET_FULL);
 
 	printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n",
 	       dev->name, print_mac(mac, dev->dev_addr));
@@ -2212,6 +2228,7 @@ static void __devexit b44_remove_one(struct ssb_device *sdev)
 	unregister_netdev(dev);
 	ssb_bus_may_powerdown(sdev->bus);
 	free_netdev(dev);
+	ssb_pcihost_set_power_state(sdev, PCI_D3hot);
 	ssb_set_drvdata(sdev, NULL);
 }
 
@@ -2240,6 +2257,7 @@ static int b44_suspend(struct ssb_device *sdev, pm_message_t state)
 		b44_setup_wol(bp);
 	}
 
+	ssb_pcihost_set_power_state(sdev, PCI_D3hot);
 	return 0;
 }
 
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 4e7b46e44874..34aebc6e7589 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -1,6 +1,6 @@
 /* bnx2.c: Broadcom NX2 network driver.
  *
- * Copyright (c) 2004-2007 Broadcom Corporation
+ * Copyright (c) 2004-2008 Broadcom Corporation
  *
  * 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
@@ -52,12 +52,12 @@
 #include "bnx2_fw.h"
 #include "bnx2_fw2.h"
 
-#define FW_BUF_SIZE		0x8000
+#define FW_BUF_SIZE		0x10000
 
 #define DRV_MODULE_NAME		"bnx2"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.6.9"
-#define DRV_MODULE_RELDATE	"December 8, 2007"
+#define DRV_MODULE_VERSION	"1.7.2"
+#define DRV_MODULE_RELDATE	"January 21, 2008"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -226,7 +226,7 @@ static struct flash_spec flash_5709 = {
 
 MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
 
-static inline u32 bnx2_tx_avail(struct bnx2 *bp)
+static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_napi *bnapi)
 {
 	u32 diff;
 
@@ -235,7 +235,7 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp)
 	/* The ring uses 256 indices for 255 entries, one of them
 	 * needs to be skipped.
 	 */
-	diff = bp->tx_prod - bp->tx_cons;
+	diff = bp->tx_prod - bnapi->tx_cons;
 	if (unlikely(diff >= TX_DESC_CNT)) {
 		diff &= 0xffff;
 		if (diff == TX_DESC_CNT)
@@ -296,7 +296,7 @@ bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
 	u32 val1;
 	int i, ret;
 
-	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
 		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
 		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
 
@@ -334,7 +334,7 @@ bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
 		ret = 0;
 	}
 
-	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
 		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
 		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
 
@@ -353,7 +353,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
 	u32 val1;
 	int i, ret;
 
-	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
 		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
 		val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
 
@@ -383,7 +383,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
 	else
 		ret = 0;
 
-	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) {
 		val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
 		val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
 
@@ -399,30 +399,65 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
 static void
 bnx2_disable_int(struct bnx2 *bp)
 {
-	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
-	       BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+	int i;
+	struct bnx2_napi *bnapi;
+
+	for (i = 0; i < bp->irq_nvecs; i++) {
+		bnapi = &bp->bnx2_napi[i];
+		REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
+		       BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+	}
 	REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
 }
 
 static void
 bnx2_enable_int(struct bnx2 *bp)
 {
-	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
-	       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
-	       BNX2_PCICFG_INT_ACK_CMD_MASK_INT | bp->last_status_idx);
+	int i;
+	struct bnx2_napi *bnapi;
 
-	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
-	       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx);
+	for (i = 0; i < bp->irq_nvecs; i++) {
+		bnapi = &bp->bnx2_napi[i];
+
+		REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
+		       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+		       BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
+		       bnapi->last_status_idx);
 
+		REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
+		       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+		       bnapi->last_status_idx);
+	}
 	REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
 }
 
 static void
 bnx2_disable_int_sync(struct bnx2 *bp)
 {
+	int i;
+
 	atomic_inc(&bp->intr_sem);
 	bnx2_disable_int(bp);
-	synchronize_irq(bp->pdev->irq);
+	for (i = 0; i < bp->irq_nvecs; i++)
+		synchronize_irq(bp->irq_tbl[i].vector);
+}
+
+static void
+bnx2_napi_disable(struct bnx2 *bp)
+{
+	int i;
+
+	for (i = 0; i < bp->irq_nvecs; i++)
+		napi_disable(&bp->bnx2_napi[i].napi);
+}
+
+static void
+bnx2_napi_enable(struct bnx2 *bp)
+{
+	int i;
+
+	for (i = 0; i < bp->irq_nvecs; i++)
+		napi_enable(&bp->bnx2_napi[i].napi);
 }
 
 static void
@@ -430,7 +465,7 @@ bnx2_netif_stop(struct bnx2 *bp)
 {
 	bnx2_disable_int_sync(bp);
 	if (netif_running(bp->dev)) {
-		napi_disable(&bp->napi);
+		bnx2_napi_disable(bp);
 		netif_tx_disable(bp->dev);
 		bp->dev->trans_start = jiffies;	/* prevent tx timeout */
 	}
@@ -442,7 +477,7 @@ bnx2_netif_start(struct bnx2 *bp)
 	if (atomic_dec_and_test(&bp->intr_sem)) {
 		if (netif_running(bp->dev)) {
 			netif_wake_queue(bp->dev);
-			napi_enable(&bp->napi);
+			bnx2_napi_enable(bp);
 			bnx2_enable_int(bp);
 		}
 	}
@@ -468,8 +503,7 @@ bnx2_free_mem(struct bnx2 *bp)
 		bp->stats_blk = NULL;
 	}
 	if (bp->tx_desc_ring) {
-		pci_free_consistent(bp->pdev,
-				    sizeof(struct tx_bd) * TX_DESC_CNT,
+		pci_free_consistent(bp->pdev, TXBD_RING_SIZE,
 				    bp->tx_desc_ring, bp->tx_desc_mapping);
 		bp->tx_desc_ring = NULL;
 	}
@@ -477,14 +511,23 @@ bnx2_free_mem(struct bnx2 *bp)
 	bp->tx_buf_ring = NULL;
 	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,
+			pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
 					    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;
+	for (i = 0; i < bp->rx_max_pg_ring; i++) {
+		if (bp->rx_pg_desc_ring[i])
+			pci_free_consistent(bp->pdev, RXBD_RING_SIZE,
+					    bp->rx_pg_desc_ring[i],
+					    bp->rx_pg_desc_mapping[i]);
+		bp->rx_pg_desc_ring[i] = NULL;
+	}
+	if (bp->rx_pg_ring)
+		vfree(bp->rx_pg_ring);
+	bp->rx_pg_ring = NULL;
 }
 
 static int
@@ -492,38 +535,54 @@ bnx2_alloc_mem(struct bnx2 *bp)
 {
 	int i, status_blk_size;
 
-	bp->tx_buf_ring = kzalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
-				  GFP_KERNEL);
+	bp->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL);
 	if (bp->tx_buf_ring == NULL)
 		return -ENOMEM;
 
-	bp->tx_desc_ring = pci_alloc_consistent(bp->pdev,
-					        sizeof(struct tx_bd) *
-						TX_DESC_CNT,
+	bp->tx_desc_ring = pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE,
 						&bp->tx_desc_mapping);
 	if (bp->tx_desc_ring == NULL)
 		goto alloc_mem_err;
 
-	bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT *
-				  bp->rx_max_ring);
+	bp->rx_buf_ring = vmalloc(SW_RXBD_RING_SIZE * 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_max_ring);
+	memset(bp->rx_buf_ring, 0, SW_RXBD_RING_SIZE * 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,
+			pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
 					     &bp->rx_desc_mapping[i]);
 		if (bp->rx_desc_ring[i] == NULL)
 			goto alloc_mem_err;
 
 	}
 
+	if (bp->rx_pg_ring_size) {
+		bp->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE *
+					 bp->rx_max_pg_ring);
+		if (bp->rx_pg_ring == NULL)
+			goto alloc_mem_err;
+
+		memset(bp->rx_pg_ring, 0, SW_RXPG_RING_SIZE *
+		       bp->rx_max_pg_ring);
+	}
+
+	for (i = 0; i < bp->rx_max_pg_ring; i++) {
+		bp->rx_pg_desc_ring[i] =
+			pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE,
+					     &bp->rx_pg_desc_mapping[i]);
+		if (bp->rx_pg_desc_ring[i] == NULL)
+			goto alloc_mem_err;
+
+	}
+
 	/* Combine status and statistics blocks into one allocation. */
 	status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
+	if (bp->flags & BNX2_FLAG_MSIX_CAP)
+		status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC *
+						 BNX2_SBLK_MSIX_ALIGN_SIZE);
 	bp->status_stats_size = status_blk_size +
 				sizeof(struct statistics_block);
 
@@ -534,6 +593,18 @@ bnx2_alloc_mem(struct bnx2 *bp)
 
 	memset(bp->status_blk, 0, bp->status_stats_size);
 
+	bp->bnx2_napi[0].status_blk = bp->status_blk;
+	if (bp->flags & BNX2_FLAG_MSIX_CAP) {
+		for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) {
+			struct bnx2_napi *bnapi = &bp->bnx2_napi[i];
+
+			bnapi->status_blk_msix = (void *)
+				((unsigned long) bp->status_blk +
+				 BNX2_SBLK_MSIX_ALIGN_SIZE * i);
+			bnapi->int_num = i << 24;
+		}
+	}
+
 	bp->stats_blk = (void *) ((unsigned long) bp->status_blk +
 				  status_blk_size);
 
@@ -563,7 +634,7 @@ bnx2_report_fw_link(struct bnx2 *bp)
 {
 	u32 fw_link_status = 0;
 
-	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
 		return;
 
 	if (bp->link_up) {
@@ -605,7 +676,7 @@ bnx2_report_fw_link(struct bnx2 *bp)
 			bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
 
 			if (!(bmsr & BMSR_ANEGCOMPLETE) ||
-			    bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)
+			    bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)
 				fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
 			else
 				fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
@@ -621,7 +692,7 @@ static char *
 bnx2_xceiver_str(struct bnx2 *bp)
 {
 	return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
-		((bp->phy_flags & PHY_SERDES_FLAG) ? "Remote Copper" :
+		((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" :
 		 "Copper"));
 }
 
@@ -681,7 +752,7 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
 		return;
 	}
 
-	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+	if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
 	    (CHIP_NUM(bp) == CHIP_NUM_5708)) {
 		u32 val;
 
@@ -696,7 +767,7 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
 	bnx2_read_phy(bp, bp->mii_adv, &local_adv);
 	bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
 
-	if (bp->phy_flags & PHY_SERDES_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 		u32 new_local_adv = 0;
 		u32 new_remote_adv = 0;
 
@@ -979,7 +1050,7 @@ bnx2_set_mac_link(struct bnx2 *bp)
 static void
 bnx2_enable_bmsr1(struct bnx2 *bp)
 {
-	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+	if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
 	    (CHIP_NUM(bp) == CHIP_NUM_5709))
 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
 			       MII_BNX2_BLK_ADDR_GP_STATUS);
@@ -988,7 +1059,7 @@ bnx2_enable_bmsr1(struct bnx2 *bp)
 static void
 bnx2_disable_bmsr1(struct bnx2 *bp)
 {
-	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+	if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
 	    (CHIP_NUM(bp) == CHIP_NUM_5709))
 		bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
 			       MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
@@ -1000,7 +1071,7 @@ bnx2_test_and_enable_2g5(struct bnx2 *bp)
 	u32 up1;
 	int ret = 1;
 
-	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
 		return 0;
 
 	if (bp->autoneg & AUTONEG_SPEED)
@@ -1029,7 +1100,7 @@ bnx2_test_and_disable_2g5(struct bnx2 *bp)
 	u32 up1;
 	int ret = 0;
 
-	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
 		return 0;
 
 	if (CHIP_NUM(bp) == CHIP_NUM_5709)
@@ -1054,7 +1125,7 @@ bnx2_enable_forced_2g5(struct bnx2 *bp)
 {
 	u32 bmcr;
 
-	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
 		return;
 
 	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
@@ -1089,7 +1160,7 @@ bnx2_disable_forced_2g5(struct bnx2 *bp)
 {
 	u32 bmcr;
 
-	if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+	if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
 		return;
 
 	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
@@ -1115,6 +1186,19 @@ bnx2_disable_forced_2g5(struct bnx2 *bp)
 	bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
 }
 
+static void
+bnx2_5706s_force_link_dn(struct bnx2 *bp, int start)
+{
+	u32 val;
+
+	bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL);
+	bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
+	if (start)
+		bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f);
+	else
+		bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0);
+}
+
 static int
 bnx2_set_link(struct bnx2 *bp)
 {
@@ -1126,7 +1210,7 @@ bnx2_set_link(struct bnx2 *bp)
 		return 0;
 	}
 
-	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
 		return 0;
 
 	link_up = bp->link_up;
@@ -1136,10 +1220,14 @@ bnx2_set_link(struct bnx2 *bp)
 	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
 	bnx2_disable_bmsr1(bp);
 
-	if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+	if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
 	    (CHIP_NUM(bp) == CHIP_NUM_5706)) {
 		u32 val;
 
+		if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
+			bnx2_5706s_force_link_dn(bp, 0);
+			bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
+		}
 		val = REG_RD(bp, BNX2_EMAC_STATUS);
 		if (val & BNX2_EMAC_STATUS_LINK)
 			bmsr |= BMSR_LSTATUS;
@@ -1150,7 +1238,7 @@ bnx2_set_link(struct bnx2 *bp)
 	if (bmsr & BMSR_LSTATUS) {
 		bp->link_up = 1;
 
-		if (bp->phy_flags & PHY_SERDES_FLAG) {
+		if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 			if (CHIP_NUM(bp) == CHIP_NUM_5706)
 				bnx2_5706s_linkup(bp);
 			else if (CHIP_NUM(bp) == CHIP_NUM_5708)
@@ -1164,11 +1252,19 @@ bnx2_set_link(struct bnx2 *bp)
 		bnx2_resolve_flow_ctrl(bp);
 	}
 	else {
-		if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+		if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) &&
 		    (bp->autoneg & AUTONEG_SPEED))
 			bnx2_disable_forced_2g5(bp);
 
-		bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
+		if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) {
+			u32 bmcr;
+
+			bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+			bmcr |= BMCR_ANENABLE;
+			bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
+
+			bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
+		}
 		bp->link_up = 0;
 	}
 
@@ -1213,7 +1309,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
 	if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
 		(FLOW_CTRL_RX | FLOW_CTRL_TX)) {
 
-		if (bp->phy_flags & PHY_SERDES_FLAG) {
+		if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 			adv = ADVERTISE_1000XPAUSE;
 		}
 		else {
@@ -1221,7 +1317,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
 		}
 	}
 	else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
-		if (bp->phy_flags & PHY_SERDES_FLAG) {
+		if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 			adv = ADVERTISE_1000XPSE_ASYM;
 		}
 		else {
@@ -1229,7 +1325,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
 		}
 	}
 	else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
-		if (bp->phy_flags & PHY_SERDES_FLAG) {
+		if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 			adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
 		}
 		else {
@@ -1304,7 +1400,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
 	u32 adv, bmcr;
 	u32 new_adv = 0;
 
-	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
 		return (bnx2_setup_remote_phy(bp, port));
 
 	if (!(bp->autoneg & AUTONEG_SPEED)) {
@@ -1414,7 +1510,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
 }
 
 #define ETHTOOL_ALL_FIBRE_SPEED						\
-	(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ?			\
+	(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ?			\
 		(ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
 		(ADVERTISED_1000baseT_Full)
 
@@ -1478,12 +1574,12 @@ bnx2_set_default_remote_link(struct bnx2 *bp)
 static void
 bnx2_set_default_link(struct bnx2 *bp)
 {
-	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
 		return bnx2_set_default_remote_link(bp);
 
 	bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
 	bp->req_line_speed = 0;
-	if (bp->phy_flags & PHY_SERDES_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 		u32 reg;
 
 		bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
@@ -1713,7 +1809,7 @@ bnx2_setup_phy(struct bnx2 *bp, u8 port)
 	if (bp->loopback == MAC_LOOPBACK)
 		return 0;
 
-	if (bp->phy_flags & PHY_SERDES_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 		return (bnx2_setup_serdes_phy(bp, port));
 	}
 	else {
@@ -1748,7 +1844,7 @@ bnx2_init_5709s_phy(struct bnx2 *bp)
 
 	bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
 	bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
-	if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
+	if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
 		val |= BCM5708S_UP1_2G5;
 	else
 		val &= ~BCM5708S_UP1_2G5;
@@ -1791,7 +1887,7 @@ bnx2_init_5708s_phy(struct bnx2 *bp)
 	val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
 	bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
 
-	if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) {
 		bnx2_read_phy(bp, BCM5708S_UP1, &val);
 		val |= BCM5708S_UP1_2G5;
 		bnx2_write_phy(bp, BCM5708S_UP1, val);
@@ -1833,7 +1929,7 @@ bnx2_init_5706s_phy(struct bnx2 *bp)
 {
 	bnx2_reset_phy(bp);
 
-	bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
+	bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
 
 	if (CHIP_NUM(bp) == CHIP_NUM_5706)
         	REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
@@ -1872,7 +1968,7 @@ bnx2_init_copper_phy(struct bnx2 *bp)
 
 	bnx2_reset_phy(bp);
 
-	if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) {
 		bnx2_write_phy(bp, 0x18, 0x0c00);
 		bnx2_write_phy(bp, 0x17, 0x000a);
 		bnx2_write_phy(bp, 0x15, 0x310b);
@@ -1883,7 +1979,7 @@ bnx2_init_copper_phy(struct bnx2 *bp)
 		bnx2_write_phy(bp, 0x18, 0x0400);
 	}
 
-	if (bp->phy_flags & PHY_DIS_EARLY_DAC_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) {
 		bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
 			       MII_BNX2_DSP_EXPAND_REG | 0x8);
 		bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
@@ -1923,8 +2019,8 @@ bnx2_init_phy(struct bnx2 *bp)
 	u32 val;
 	int rc = 0;
 
-	bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG;
-	bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG;
+	bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK;
+	bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY;
 
 	bp->mii_bmcr = MII_BMCR;
 	bp->mii_bmsr = MII_BMSR;
@@ -1934,7 +2030,7 @@ bnx2_init_phy(struct bnx2 *bp)
 
         REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
 
-	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
 		goto setup_phy;
 
 	bnx2_read_phy(bp, MII_PHYSID1, &val);
@@ -1942,7 +2038,7 @@ bnx2_init_phy(struct bnx2 *bp)
 	bnx2_read_phy(bp, MII_PHYSID2, &val);
 	bp->phy_id |= val & 0xffff;
 
-	if (bp->phy_flags & PHY_SERDES_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 		if (CHIP_NUM(bp) == CHIP_NUM_5706)
 			rc = bnx2_init_5706s_phy(bp);
 		else if (CHIP_NUM(bp) == CHIP_NUM_5708)
@@ -2125,15 +2221,12 @@ bnx2_init_context(struct bnx2 *bp)
 			vcid_addr += (i << PHY_CTX_SHIFT);
 			pcid_addr += (i << PHY_CTX_SHIFT);
 
-			REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00);
+			REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
 			REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
 
 			/* Zero out the context. */
 			for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
-				CTX_WR(bp, 0x00, offset, 0);
-
-			REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
-			REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
+				CTX_WR(bp, vcid_addr, offset, 0);
 		}
 	}
 }
@@ -2206,7 +2299,43 @@ bnx2_set_mac_addr(struct bnx2 *bp)
 }
 
 static inline int
-bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
+bnx2_alloc_rx_page(struct bnx2 *bp, u16 index)
+{
+	dma_addr_t mapping;
+	struct sw_pg *rx_pg = &bp->rx_pg_ring[index];
+	struct rx_bd *rxbd =
+		&bp->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)];
+	struct page *page = alloc_page(GFP_ATOMIC);
+
+	if (!page)
+		return -ENOMEM;
+	mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
+			       PCI_DMA_FROMDEVICE);
+	rx_pg->page = page;
+	pci_unmap_addr_set(rx_pg, mapping, mapping);
+	rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
+	rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
+	return 0;
+}
+
+static void
+bnx2_free_rx_page(struct bnx2 *bp, u16 index)
+{
+	struct sw_pg *rx_pg = &bp->rx_pg_ring[index];
+	struct page *page = rx_pg->page;
+
+	if (!page)
+		return;
+
+	pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE,
+		       PCI_DMA_FROMDEVICE);
+
+	__free_page(page);
+	rx_pg->page = NULL;
+}
+
+static inline int
+bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, u16 index)
 {
 	struct sk_buff *skb;
 	struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
@@ -2231,15 +2360,15 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
 	rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
 	rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
 
-	bp->rx_prod_bseq += bp->rx_buf_use_size;
+	bnapi->rx_prod_bseq += bp->rx_buf_use_size;
 
 	return 0;
 }
 
 static int
-bnx2_phy_event_is_set(struct bnx2 *bp, u32 event)
+bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event)
 {
-	struct status_block *sblk = bp->status_blk;
+	struct status_block *sblk = bnapi->status_blk;
 	u32 new_link_state, old_link_state;
 	int is_set = 1;
 
@@ -2257,30 +2386,41 @@ bnx2_phy_event_is_set(struct bnx2 *bp, u32 event)
 }
 
 static void
-bnx2_phy_int(struct bnx2 *bp)
+bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi)
 {
-	if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_LINK_STATE)) {
+	if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE)) {
 		spin_lock(&bp->phy_lock);
 		bnx2_set_link(bp);
 		spin_unlock(&bp->phy_lock);
 	}
-	if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_TIMER_ABORT))
+	if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT))
 		bnx2_set_remote_link(bp);
 
 }
 
-static void
-bnx2_tx_int(struct bnx2 *bp)
+static inline u16
+bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi)
+{
+	u16 cons;
+
+	if (bnapi->int_num == 0)
+		cons = bnapi->status_blk->status_tx_quick_consumer_index0;
+	else
+		cons = bnapi->status_blk_msix->status_tx_quick_consumer_index;
+
+	if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT))
+		cons++;
+	return cons;
+}
+
+static int
+bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
 {
-	struct status_block *sblk = bp->status_blk;
 	u16 hw_cons, sw_cons, sw_ring_cons;
-	int tx_free_bd = 0;
+	int tx_pkt = 0;
 
-	hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0;
-	if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
-		hw_cons++;
-	}
-	sw_cons = bp->tx_cons;
+	hw_cons = bnx2_get_hw_tx_cons(bnapi);
+	sw_cons = bnapi->tx_cons;
 
 	while (sw_cons != hw_cons) {
 		struct sw_bd *tx_buf;
@@ -2327,19 +2467,16 @@ bnx2_tx_int(struct bnx2 *bp)
 
 		sw_cons = NEXT_TX_BD(sw_cons);
 
-		tx_free_bd += last + 1;
-
 		dev_kfree_skb(skb);
+		tx_pkt++;
+		if (tx_pkt == budget)
+			break;
 
-		hw_cons = bp->hw_tx_cons =
-			sblk->status_tx_quick_consumer_index0;
-
-		if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
-			hw_cons++;
-		}
+		hw_cons = bnx2_get_hw_tx_cons(bnapi);
 	}
 
-	bp->tx_cons = sw_cons;
+	bnapi->hw_tx_cons = hw_cons;
+	bnapi->tx_cons = sw_cons;
 	/* Need to make the tx_cons update visible to bnx2_start_xmit()
 	 * before checking for netif_queue_stopped().  Without the
 	 * memory barrier, there is a small possibility that bnx2_start_xmit()
@@ -2348,17 +2485,68 @@ bnx2_tx_int(struct bnx2 *bp)
 	smp_mb();
 
 	if (unlikely(netif_queue_stopped(bp->dev)) &&
-		     (bnx2_tx_avail(bp) > bp->tx_wake_thresh)) {
+		     (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)) {
 		netif_tx_lock(bp->dev);
 		if ((netif_queue_stopped(bp->dev)) &&
-		    (bnx2_tx_avail(bp) > bp->tx_wake_thresh))
+		    (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh))
 			netif_wake_queue(bp->dev);
 		netif_tx_unlock(bp->dev);
 	}
+	return tx_pkt;
+}
+
+static void
+bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_napi *bnapi,
+			struct sk_buff *skb, int count)
+{
+	struct sw_pg *cons_rx_pg, *prod_rx_pg;
+	struct rx_bd *cons_bd, *prod_bd;
+	dma_addr_t mapping;
+	int i;
+	u16 hw_prod = bnapi->rx_pg_prod, prod;
+	u16 cons = bnapi->rx_pg_cons;
+
+	for (i = 0; i < count; i++) {
+		prod = RX_PG_RING_IDX(hw_prod);
+
+		prod_rx_pg = &bp->rx_pg_ring[prod];
+		cons_rx_pg = &bp->rx_pg_ring[cons];
+		cons_bd = &bp->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)];
+		prod_bd = &bp->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
+
+		if (i == 0 && skb) {
+			struct page *page;
+			struct skb_shared_info *shinfo;
+
+			shinfo = skb_shinfo(skb);
+			shinfo->nr_frags--;
+			page = shinfo->frags[shinfo->nr_frags].page;
+			shinfo->frags[shinfo->nr_frags].page = NULL;
+			mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
+					       PCI_DMA_FROMDEVICE);
+			cons_rx_pg->page = page;
+			pci_unmap_addr_set(cons_rx_pg, mapping, mapping);
+			dev_kfree_skb(skb);
+		}
+		if (prod != cons) {
+			prod_rx_pg->page = cons_rx_pg->page;
+			cons_rx_pg->page = NULL;
+			pci_unmap_addr_set(prod_rx_pg, mapping,
+				pci_unmap_addr(cons_rx_pg, mapping));
+
+			prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
+			prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
+
+		}
+		cons = RX_PG_RING_IDX(NEXT_RX_BD(cons));
+		hw_prod = NEXT_RX_BD(hw_prod);
+	}
+	bnapi->rx_pg_prod = hw_prod;
+	bnapi->rx_pg_cons = cons;
 }
 
 static inline void
-bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
+bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb,
 	u16 cons, u16 prod)
 {
 	struct sw_bd *cons_rx_buf, *prod_rx_buf;
@@ -2371,7 +2559,7 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
 		pci_unmap_addr(cons_rx_buf, mapping),
 		bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
-	bp->rx_prod_bseq += bp->rx_buf_use_size;
+	bnapi->rx_prod_bseq += bp->rx_buf_use_size;
 
 	prod_rx_buf->skb = skb;
 
@@ -2387,10 +2575,102 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
 	prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
 }
 
+static int
+bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb,
+	    unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
+	    u32 ring_idx)
+{
+	int err;
+	u16 prod = ring_idx & 0xffff;
+
+	err = bnx2_alloc_rx_skb(bp, bnapi, prod);
+	if (unlikely(err)) {
+		bnx2_reuse_rx_skb(bp, bnapi, skb, (u16) (ring_idx >> 16), prod);
+		if (hdr_len) {
+			unsigned int raw_len = len + 4;
+			int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
+
+			bnx2_reuse_rx_skb_pages(bp, bnapi, NULL, pages);
+		}
+		return err;
+	}
+
+	skb_reserve(skb, bp->rx_offset);
+	pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size,
+			 PCI_DMA_FROMDEVICE);
+
+	if (hdr_len == 0) {
+		skb_put(skb, len);
+		return 0;
+	} else {
+		unsigned int i, frag_len, frag_size, pages;
+		struct sw_pg *rx_pg;
+		u16 pg_cons = bnapi->rx_pg_cons;
+		u16 pg_prod = bnapi->rx_pg_prod;
+
+		frag_size = len + 4 - hdr_len;
+		pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT;
+		skb_put(skb, hdr_len);
+
+		for (i = 0; i < pages; i++) {
+			frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
+			if (unlikely(frag_len <= 4)) {
+				unsigned int tail = 4 - frag_len;
+
+				bnapi->rx_pg_cons = pg_cons;
+				bnapi->rx_pg_prod = pg_prod;
+				bnx2_reuse_rx_skb_pages(bp, bnapi, NULL,
+							pages - i);
+				skb->len -= tail;
+				if (i == 0) {
+					skb->tail -= tail;
+				} else {
+					skb_frag_t *frag =
+						&skb_shinfo(skb)->frags[i - 1];
+					frag->size -= tail;
+					skb->data_len -= tail;
+					skb->truesize -= tail;
+				}
+				return 0;
+			}
+			rx_pg = &bp->rx_pg_ring[pg_cons];
+
+			pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping),
+				       PAGE_SIZE, PCI_DMA_FROMDEVICE);
+
+			if (i == pages - 1)
+				frag_len -= 4;
+
+			skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len);
+			rx_pg->page = NULL;
+
+			err = bnx2_alloc_rx_page(bp, RX_PG_RING_IDX(pg_prod));
+			if (unlikely(err)) {
+				bnapi->rx_pg_cons = pg_cons;
+				bnapi->rx_pg_prod = pg_prod;
+				bnx2_reuse_rx_skb_pages(bp, bnapi, skb,
+							pages - i);
+				return err;
+			}
+
+			frag_size -= frag_len;
+			skb->data_len += frag_len;
+			skb->truesize += frag_len;
+			skb->len += frag_len;
+
+			pg_prod = NEXT_RX_BD(pg_prod);
+			pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons));
+		}
+		bnapi->rx_pg_prod = pg_prod;
+		bnapi->rx_pg_cons = pg_cons;
+	}
+	return 0;
+}
+
 static inline u16
-bnx2_get_hw_rx_cons(struct bnx2 *bp)
+bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi)
 {
-	u16 cons = bp->status_blk->status_rx_quick_consumer_index0;
+	u16 cons = bnapi->status_blk->status_rx_quick_consumer_index0;
 
 	if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
 		cons++;
@@ -2398,22 +2678,22 @@ bnx2_get_hw_rx_cons(struct bnx2 *bp)
 }
 
 static int
-bnx2_rx_int(struct bnx2 *bp, int budget)
+bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
 {
 	u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
 	struct l2_fhdr *rx_hdr;
-	int rx_pkt = 0;
+	int rx_pkt = 0, pg_ring_used = 0;
 
-	hw_cons = bnx2_get_hw_rx_cons(bp);
-	sw_cons = bp->rx_cons;
-	sw_prod = bp->rx_prod;
+	hw_cons = bnx2_get_hw_rx_cons(bnapi);
+	sw_cons = bnapi->rx_cons;
+	sw_prod = bnapi->rx_prod;
 
 	/* Memory barrier necessary as speculative reads of the rx
 	 * buffer can be ahead of the index in the status block
 	 */
 	rmb();
 	while (sw_cons != hw_cons) {
-		unsigned int len;
+		unsigned int len, hdr_len;
 		u32 status;
 		struct sw_bd *rx_buf;
 		struct sk_buff *skb;
@@ -2433,7 +2713,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
 			bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
 		rx_hdr = (struct l2_fhdr *) skb->data;
-		len = rx_hdr->l2_fhdr_pkt_len - 4;
+		len = rx_hdr->l2_fhdr_pkt_len;
 
 		if ((status = rx_hdr->l2_fhdr_status) &
 			(L2_FHDR_ERRORS_BAD_CRC |
@@ -2442,18 +2722,30 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
 			L2_FHDR_ERRORS_TOO_SHORT |
 			L2_FHDR_ERRORS_GIANT_FRAME)) {
 
-			goto reuse_rx;
+			bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons,
+					  sw_ring_prod);
+			goto next_rx;
+		}
+		hdr_len = 0;
+		if (status & L2_FHDR_STATUS_SPLIT) {
+			hdr_len = rx_hdr->l2_fhdr_ip_xsum;
+			pg_ring_used = 1;
+		} else if (len > bp->rx_jumbo_thresh) {
+			hdr_len = bp->rx_jumbo_thresh;
+			pg_ring_used = 1;
 		}
 
-		/* Since we don't have a jumbo ring, copy small packets
-		 * if mtu > 1500
-		 */
-		if ((bp->dev->mtu > 1500) && (len <= RX_COPY_THRESH)) {
+		len -= 4;
+
+		if (len <= bp->rx_copy_thresh) {
 			struct sk_buff *new_skb;
 
 			new_skb = netdev_alloc_skb(bp->dev, len + 2);
-			if (new_skb == NULL)
-				goto reuse_rx;
+			if (new_skb == NULL) {
+				bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons,
+						  sw_ring_prod);
+				goto next_rx;
+			}
 
 			/* aligned copy */
 			skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2,
@@ -2461,24 +2753,13 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
 			skb_reserve(new_skb, 2);
 			skb_put(new_skb, len);
 
-			bnx2_reuse_rx_skb(bp, skb,
+			bnx2_reuse_rx_skb(bp, bnapi, skb,
 				sw_ring_cons, sw_ring_prod);
 
 			skb = new_skb;
-		}
-		else if (bnx2_alloc_rx_skb(bp, sw_ring_prod) == 0) {
-			pci_unmap_single(bp->pdev, dma_addr,
-				bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
-
-			skb_reserve(skb, bp->rx_offset);
-			skb_put(skb, len);
-		}
-		else {
-reuse_rx:
-			bnx2_reuse_rx_skb(bp, skb,
-				sw_ring_cons, sw_ring_prod);
+		} else if (unlikely(bnx2_rx_skb(bp, bnapi, skb, len, hdr_len,
+			   dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
 			goto next_rx;
-		}
 
 		skb->protocol = eth_type_trans(skb, bp->dev);
 
@@ -2501,7 +2782,7 @@ reuse_rx:
 		}
 
 #ifdef BCM_VLAN
-		if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && (bp->vlgrp != 0)) {
+		if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && bp->vlgrp) {
 			vlan_hwaccel_receive_skb(skb, bp->vlgrp,
 				rx_hdr->l2_fhdr_vlan_tag);
 		}
@@ -2521,16 +2802,20 @@ next_rx:
 
 		/* Refresh hw_cons to see if there is new work */
 		if (sw_cons == hw_cons) {
-			hw_cons = bnx2_get_hw_rx_cons(bp);
+			hw_cons = bnx2_get_hw_rx_cons(bnapi);
 			rmb();
 		}
 	}
-	bp->rx_cons = sw_cons;
-	bp->rx_prod = sw_prod;
+	bnapi->rx_cons = sw_cons;
+	bnapi->rx_prod = sw_prod;
+
+	if (pg_ring_used)
+		REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX,
+			 bnapi->rx_pg_prod);
 
 	REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, sw_prod);
 
-	REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
+	REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq);
 
 	mmiowb();
 
@@ -2546,8 +2831,9 @@ bnx2_msi(int irq, void *dev_instance)
 {
 	struct net_device *dev = dev_instance;
 	struct bnx2 *bp = netdev_priv(dev);
+	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
 
-	prefetch(bp->status_blk);
+	prefetch(bnapi->status_blk);
 	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
 		BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
 		BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
@@ -2556,7 +2842,7 @@ bnx2_msi(int irq, void *dev_instance)
 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
 		return IRQ_HANDLED;
 
-	netif_rx_schedule(dev, &bp->napi);
+	netif_rx_schedule(dev, &bnapi->napi);
 
 	return IRQ_HANDLED;
 }
@@ -2566,14 +2852,15 @@ bnx2_msi_1shot(int irq, void *dev_instance)
 {
 	struct net_device *dev = dev_instance;
 	struct bnx2 *bp = netdev_priv(dev);
+	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
 
-	prefetch(bp->status_blk);
+	prefetch(bnapi->status_blk);
 
 	/* Return here if interrupt is disabled. */
 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
 		return IRQ_HANDLED;
 
-	netif_rx_schedule(dev, &bp->napi);
+	netif_rx_schedule(dev, &bnapi->napi);
 
 	return IRQ_HANDLED;
 }
@@ -2583,7 +2870,8 @@ bnx2_interrupt(int irq, void *dev_instance)
 {
 	struct net_device *dev = dev_instance;
 	struct bnx2 *bp = netdev_priv(dev);
-	struct status_block *sblk = bp->status_blk;
+	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+	struct status_block *sblk = bnapi->status_blk;
 
 	/* When using INTx, it is possible for the interrupt to arrive
 	 * at the CPU before the status block posted prior to the
@@ -2591,7 +2879,7 @@ bnx2_interrupt(int irq, void *dev_instance)
 	 * When using MSI, the MSI message will always complete after
 	 * the status block write.
 	 */
-	if ((sblk->status_idx == bp->last_status_idx) &&
+	if ((sblk->status_idx == bnapi->last_status_idx) &&
 	    (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
 	     BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
 		return IRQ_NONE;
@@ -2609,24 +2897,41 @@ bnx2_interrupt(int irq, void *dev_instance)
 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
 		return IRQ_HANDLED;
 
-	if (netif_rx_schedule_prep(dev, &bp->napi)) {
-		bp->last_status_idx = sblk->status_idx;
-		__netif_rx_schedule(dev, &bp->napi);
+	if (netif_rx_schedule_prep(dev, &bnapi->napi)) {
+		bnapi->last_status_idx = sblk->status_idx;
+		__netif_rx_schedule(dev, &bnapi->napi);
 	}
 
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t
+bnx2_tx_msix(int irq, void *dev_instance)
+{
+	struct net_device *dev = dev_instance;
+	struct bnx2 *bp = netdev_priv(dev);
+	struct bnx2_napi *bnapi = &bp->bnx2_napi[BNX2_TX_VEC];
+
+	prefetch(bnapi->status_blk_msix);
+
+	/* Return here if interrupt is disabled. */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0))
+		return IRQ_HANDLED;
+
+	netif_rx_schedule(dev, &bnapi->napi);
+	return IRQ_HANDLED;
+}
+
 #define STATUS_ATTN_EVENTS	(STATUS_ATTN_BITS_LINK_STATE | \
 				 STATUS_ATTN_BITS_TIMER_ABORT)
 
 static inline int
-bnx2_has_work(struct bnx2 *bp)
+bnx2_has_work(struct bnx2_napi *bnapi)
 {
-	struct status_block *sblk = bp->status_blk;
+	struct status_block *sblk = bnapi->status_blk;
 
-	if ((bnx2_get_hw_rx_cons(bp) != bp->rx_cons) ||
-	    (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons))
+	if ((bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons) ||
+	    (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons))
 		return 1;
 
 	if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
@@ -2636,16 +2941,40 @@ bnx2_has_work(struct bnx2 *bp)
 	return 0;
 }
 
-static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
+static int bnx2_tx_poll(struct napi_struct *napi, int budget)
+{
+	struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
+	struct bnx2 *bp = bnapi->bp;
+	int work_done = 0;
+	struct status_block_msix *sblk = bnapi->status_blk_msix;
+
+	do {
+		work_done += bnx2_tx_int(bp, bnapi, budget - work_done);
+		if (unlikely(work_done >= budget))
+			return work_done;
+
+		bnapi->last_status_idx = sblk->status_idx;
+		rmb();
+	} while (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons);
+
+	netif_rx_complete(bp->dev, napi);
+	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num |
+	       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+	       bnapi->last_status_idx);
+	return work_done;
+}
+
+static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi,
+			  int work_done, int budget)
 {
-	struct status_block *sblk = bp->status_blk;
+	struct status_block *sblk = bnapi->status_blk;
 	u32 status_attn_bits = sblk->status_attn_bits;
 	u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
 
 	if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
 	    (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
 
-		bnx2_phy_int(bp);
+		bnx2_phy_int(bp, bnapi);
 
 		/* This is needed to take care of transient status
 		 * during link changes.
@@ -2655,49 +2984,50 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
 		REG_RD(bp, BNX2_HC_COMMAND);
 	}
 
-	if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
-		bnx2_tx_int(bp);
+	if (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons)
+		bnx2_tx_int(bp, bnapi, 0);
 
-	if (bnx2_get_hw_rx_cons(bp) != bp->rx_cons)
-		work_done += bnx2_rx_int(bp, budget - work_done);
+	if (bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons)
+		work_done += bnx2_rx_int(bp, bnapi, budget - work_done);
 
 	return work_done;
 }
 
 static int bnx2_poll(struct napi_struct *napi, int budget)
 {
-	struct bnx2 *bp = container_of(napi, struct bnx2, napi);
+	struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi);
+	struct bnx2 *bp = bnapi->bp;
 	int work_done = 0;
-	struct status_block *sblk = bp->status_blk;
+	struct status_block *sblk = bnapi->status_blk;
 
 	while (1) {
-		work_done = bnx2_poll_work(bp, work_done, budget);
+		work_done = bnx2_poll_work(bp, bnapi, work_done, budget);
 
 		if (unlikely(work_done >= budget))
 			break;
 
-		/* bp->last_status_idx is used below to tell the hw how
+		/* bnapi->last_status_idx is used below to tell the hw how
 		 * much work has been processed, so we must read it before
 		 * checking for more work.
 		 */
-		bp->last_status_idx = sblk->status_idx;
+		bnapi->last_status_idx = sblk->status_idx;
 		rmb();
-		if (likely(!bnx2_has_work(bp))) {
+		if (likely(!bnx2_has_work(bnapi))) {
 			netif_rx_complete(bp->dev, napi);
-			if (likely(bp->flags & USING_MSI_FLAG)) {
+			if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) {
 				REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
 				       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
-				       bp->last_status_idx);
+				       bnapi->last_status_idx);
 				break;
 			}
 			REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
 			       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
 			       BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
-			       bp->last_status_idx);
+			       bnapi->last_status_idx);
 
 			REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
 			       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
-			       bp->last_status_idx);
+			       bnapi->last_status_idx);
 			break;
 		}
 	}
@@ -2721,10 +3051,10 @@ bnx2_set_rx_mode(struct net_device *dev)
 				  BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
 	sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
 #ifdef BCM_VLAN
-	if (!bp->vlgrp && !(bp->flags & ASF_ENABLE_FLAG))
+	if (!bp->vlgrp && !(bp->flags & BNX2_FLAG_ASF_ENABLE))
 		rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
 #else
-	if (!(bp->flags & ASF_ENABLE_FLAG))
+	if (!(bp->flags & BNX2_FLAG_ASF_ENABLE))
 		rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
 #endif
 	if (dev->flags & IFF_PROMISC) {
@@ -2781,7 +3111,7 @@ bnx2_set_rx_mode(struct net_device *dev)
 }
 
 static void
-load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
+load_rv2p_fw(struct bnx2 *bp, __le32 *rv2p_code, u32 rv2p_code_len,
 	u32 rv2p_proc)
 {
 	int i;
@@ -2789,9 +3119,9 @@ load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
 
 
 	for (i = 0; i < rv2p_code_len; i += 8) {
-		REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code));
+		REG_WR(bp, BNX2_RV2P_INSTR_HIGH, le32_to_cpu(*rv2p_code));
 		rv2p_code++;
-		REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code));
+		REG_WR(bp, BNX2_RV2P_INSTR_LOW, le32_to_cpu(*rv2p_code));
 		rv2p_code++;
 
 		if (rv2p_proc == RV2P_PROC1) {
@@ -2837,7 +3167,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
 			return rc;
 
 		for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
-			REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
+			REG_WR_IND(bp, offset, le32_to_cpu(fw->text[j]));
 	        }
 	}
 
@@ -2900,20 +3230,34 @@ bnx2_init_cpus(struct bnx2 *bp)
 {
 	struct cpu_reg cpu_reg;
 	struct fw_info *fw;
-	int rc;
-	void *text;
+	int rc, rv2p_len;
+	void *text, *rv2p;
 
 	/* Initialize the RV2P processor. */
 	text = vmalloc(FW_BUF_SIZE);
 	if (!text)
 		return -ENOMEM;
-	rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1));
+	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+		rv2p = bnx2_xi_rv2p_proc1;
+		rv2p_len = sizeof(bnx2_xi_rv2p_proc1);
+	} else {
+		rv2p = bnx2_rv2p_proc1;
+		rv2p_len = sizeof(bnx2_rv2p_proc1);
+	}
+	rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len);
 	if (rc < 0)
 		goto init_cpu_err;
 
 	load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1);
 
-	rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2));
+	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+		rv2p = bnx2_xi_rv2p_proc2;
+		rv2p_len = sizeof(bnx2_xi_rv2p_proc2);
+	} else {
+		rv2p = bnx2_rv2p_proc2;
+		rv2p_len = sizeof(bnx2_rv2p_proc2);
+	}
+	rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len);
 	if (rc < 0)
 		goto init_cpu_err;
 
@@ -3029,14 +3373,14 @@ bnx2_init_cpus(struct bnx2 *bp)
 	cpu_reg.spad_base = BNX2_CP_SCRATCH;
 	cpu_reg.mips_view_base = 0x8000000;
 
-	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+	if (CHIP_NUM(bp) == CHIP_NUM_5709)
 		fw = &bnx2_cp_fw_09;
+	else
+		fw = &bnx2_cp_fw_06;
+
+	fw->text = text;
+	rc = load_cpu_fw(bp, &cpu_reg, fw);
 
-		fw->text = text;
-		rc = load_cpu_fw(bp, &cpu_reg, fw);
-		if (rc)
-			goto init_cpu_err;
-	}
 init_cpu_err:
 	vfree(text);
 	return rc;
@@ -3148,7 +3492,7 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
 			wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
 		}
 
-		if (!(bp->flags & NO_WOL_FLAG))
+		if (!(bp->flags & BNX2_FLAG_NO_WOL))
 			bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0);
 
 		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
@@ -3360,10 +3704,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
 
 		val = REG_RD(bp, BNX2_NVM_COMMAND);
 		if (val & BNX2_NVM_COMMAND_DONE) {
-			val = REG_RD(bp, BNX2_NVM_READ);
-
-			val = be32_to_cpu(val);
-			memcpy(ret_val, &val, 4);
+			__be32 v = cpu_to_be32(REG_RD(bp, BNX2_NVM_READ));
+			memcpy(ret_val, &v, 4);
 			break;
 		}
 	}
@@ -3377,7 +3719,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
 static int
 bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
 {
-	u32 cmd, val32;
+	u32 cmd;
+	__be32 val32;
 	int j;
 
 	/* Build the command word. */
@@ -3394,10 +3737,9 @@ bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
 	REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
 
 	memcpy(&val32, val, 4);
-	val32 = cpu_to_be32(val32);
 
 	/* Write the data. */
-	REG_WR(bp, BNX2_NVM_WRITE, val32);
+	REG_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32));
 
 	/* Address of the NVRAM to write to. */
 	REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
@@ -3796,8 +4138,8 @@ bnx2_init_remote_phy(struct bnx2 *bp)
 {
 	u32 val;
 
-	bp->phy_flags &= ~REMOTE_PHY_CAP_FLAG;
-	if (!(bp->phy_flags & PHY_SERDES_FLAG))
+	bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP;
+	if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES))
 		return;
 
 	val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_CAP_MB);
@@ -3805,7 +4147,7 @@ bnx2_init_remote_phy(struct bnx2 *bp)
 		return;
 
 	if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
-		bp->phy_flags |= REMOTE_PHY_CAP_FLAG;
+		bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP;
 
 		val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
 		if (val & BNX2_LINK_STATUS_SERDES_LINK)
@@ -3831,6 +4173,15 @@ bnx2_init_remote_phy(struct bnx2 *bp)
 	}
 }
 
+static void
+bnx2_setup_msix_tbl(struct bnx2 *bp)
+{
+	REG_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN);
+
+	REG_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR);
+	REG_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR);
+}
+
 static int
 bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
 {
@@ -3917,7 +4268,8 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
 	spin_lock_bh(&bp->phy_lock);
 	old_port = bp->phy_port;
 	bnx2_init_remote_phy(bp);
-	if ((bp->phy_flags & REMOTE_PHY_CAP_FLAG) && old_port != bp->phy_port)
+	if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) &&
+	    old_port != bp->phy_port)
 		bnx2_set_default_remote_link(bp);
 	spin_unlock_bh(&bp->phy_lock);
 
@@ -3930,6 +4282,9 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
 		rc = bnx2_alloc_bad_rbuf(bp);
 	}
 
+	if (bp->flags & BNX2_FLAG_USING_MSIX)
+		bnx2_setup_msix_tbl(bp);
+
 	return rc;
 }
 
@@ -3937,7 +4292,7 @@ static int
 bnx2_init_chip(struct bnx2 *bp)
 {
 	u32 val;
-	int rc;
+	int rc, i;
 
 	/* Make sure the interrupt is not active. */
 	REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
@@ -3953,11 +4308,11 @@ bnx2_init_chip(struct bnx2 *bp)
 
 	val |= (0x2 << 20) | (1 << 11);
 
-	if ((bp->flags & PCIX_FLAG) && (bp->bus_speed_mhz == 133))
+	if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133))
 		val |= (1 << 23);
 
 	if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
-	    (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & PCIX_FLAG))
+	    (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & BNX2_FLAG_PCIX))
 		val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
 
 	REG_WR(bp, BNX2_DMA_CONFIG, val);
@@ -3968,7 +4323,7 @@ bnx2_init_chip(struct bnx2 *bp)
 		REG_WR(bp, BNX2_TDMA_CONFIG, val);
 	}
 
-	if (bp->flags & PCIX_FLAG) {
+	if (bp->flags & BNX2_FLAG_PCIX) {
 		u16 val16;
 
 		pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
@@ -4033,7 +4388,9 @@ bnx2_init_chip(struct bnx2 *bp)
 		val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
 	REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
 
-	bp->last_status_idx = 0;
+	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
+		bp->bnx2_napi[i].last_status_idx = 0;
+
 	bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
 
 	/* Set up how to generate a link change interrupt. */
@@ -4080,7 +4437,25 @@ bnx2_init_chip(struct bnx2 *bp)
 		      BNX2_HC_CONFIG_COLLECT_STATS;
 	}
 
-	if (bp->flags & ONE_SHOT_MSI_FLAG)
+	if (bp->flags & BNX2_FLAG_USING_MSIX) {
+		REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR,
+		       BNX2_HC_MSIX_BIT_VECTOR_VAL);
+
+		REG_WR(bp, BNX2_HC_SB_CONFIG_1,
+			BNX2_HC_SB_CONFIG_1_TX_TMR_MODE |
+			BNX2_HC_SB_CONFIG_1_ONE_SHOT);
+
+		REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP_1,
+			(bp->tx_quick_cons_trip_int << 16) |
+			 bp->tx_quick_cons_trip);
+
+		REG_WR(bp, BNX2_HC_TX_TICKS_1,
+			(bp->tx_ticks_int << 16) | bp->tx_ticks);
+
+		val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B;
+	}
+
+	if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI)
 		val |= BNX2_HC_CONFIG_ONE_SHOT;
 
 	REG_WR(bp, BNX2_HC_CONFIG, val);
@@ -4112,6 +4487,25 @@ bnx2_init_chip(struct bnx2 *bp)
 }
 
 static void
+bnx2_clear_ring_states(struct bnx2 *bp)
+{
+	struct bnx2_napi *bnapi;
+	int i;
+
+	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
+		bnapi = &bp->bnx2_napi[i];
+
+		bnapi->tx_cons = 0;
+		bnapi->hw_tx_cons = 0;
+		bnapi->rx_prod_bseq = 0;
+		bnapi->rx_prod = 0;
+		bnapi->rx_cons = 0;
+		bnapi->rx_pg_prod = 0;
+		bnapi->rx_pg_cons = 0;
+	}
+}
+
+static void
 bnx2_init_tx_context(struct bnx2 *bp, u32 cid)
 {
 	u32 val, offset0, offset1, offset2, offset3;
@@ -4144,7 +4538,17 @@ static void
 bnx2_init_tx_ring(struct bnx2 *bp)
 {
 	struct tx_bd *txbd;
-	u32 cid;
+	u32 cid = TX_CID;
+	struct bnx2_napi *bnapi;
+
+	bp->tx_vec = 0;
+	if (bp->flags & BNX2_FLAG_USING_MSIX) {
+		cid = TX_TSS_CID;
+		bp->tx_vec = BNX2_TX_VEC;
+		REG_WR(bp, BNX2_TSCH_TSS_CFG, BNX2_TX_INT_NUM |
+		       (TX_TSS_CID << 7));
+	}
+	bnapi = &bp->bnx2_napi[bp->tx_vec];
 
 	bp->tx_wake_thresh = bp->tx_ring_size / 2;
 
@@ -4154,11 +4558,8 @@ bnx2_init_tx_ring(struct bnx2 *bp)
 	txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff;
 
 	bp->tx_prod = 0;
-	bp->tx_cons = 0;
-	bp->hw_tx_cons = 0;
 	bp->tx_prod_bseq = 0;
 
-	cid = TX_CID;
 	bp->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
 	bp->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
 
@@ -4166,84 +4567,152 @@ bnx2_init_tx_ring(struct bnx2 *bp)
 }
 
 static void
-bnx2_init_rx_ring(struct bnx2 *bp)
+bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size,
+		     int num_rings)
 {
-	struct rx_bd *rxbd;
 	int i;
-	u16 prod, ring_prod;
-	u32 val;
-
-	/* 8 for CRC and VLAN */
-	bp->rx_buf_use_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
-	/* hw alignment */
-	bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
-
-	ring_prod = prod = bp->rx_prod = 0;
-	bp->rx_cons = 0;
-	bp->rx_prod_bseq = 0;
+	struct rx_bd *rxbd;
 
-	for (i = 0; i < bp->rx_max_ring; i++) {
+	for (i = 0; i < num_rings; i++) {
 		int j;
 
-		rxbd = &bp->rx_desc_ring[i][0];
+		rxbd = &rx_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_len = buf_size;
 			rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
 		}
-		if (i == (bp->rx_max_ring - 1))
+		if (i == (num_rings - 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;
+		rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32;
+		rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff;
+	}
+}
+
+static void
+bnx2_init_rx_ring(struct bnx2 *bp)
+{
+	int i;
+	u16 prod, ring_prod;
+	u32 val, rx_cid_addr = GET_CID_ADDR(RX_CID);
+	struct bnx2_napi *bnapi = &bp->bnx2_napi[0];
+
+	bnx2_init_rxbd_rings(bp->rx_desc_ring, bp->rx_desc_mapping,
+			     bp->rx_buf_use_size, bp->rx_max_ring);
+
+	CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0);
+	if (bp->rx_pg_ring_size) {
+		bnx2_init_rxbd_rings(bp->rx_pg_desc_ring,
+				     bp->rx_pg_desc_mapping,
+				     PAGE_SIZE, bp->rx_max_pg_ring);
+		val = (bp->rx_buf_use_size << 16) | PAGE_SIZE;
+		CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val);
+		CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY,
+		       BNX2_L2CTX_RBDC_JUMBO_KEY);
+
+		val = (u64) bp->rx_pg_desc_mapping[0] >> 32;
+		CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val);
+
+		val = (u64) bp->rx_pg_desc_mapping[0] & 0xffffffff;
+		CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val);
+
+		if (CHIP_NUM(bp) == CHIP_NUM_5709)
+			REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT);
 	}
 
 	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);
+	CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val);
 
 	val = (u64) bp->rx_desc_mapping[0] >> 32;
-	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val);
+	CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
 
 	val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
-	CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
+	CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
 
+	ring_prod = prod = bnapi->rx_pg_prod;
+	for (i = 0; i < bp->rx_pg_ring_size; i++) {
+		if (bnx2_alloc_rx_page(bp, ring_prod) < 0)
+			break;
+		prod = NEXT_RX_BD(prod);
+		ring_prod = RX_PG_RING_IDX(prod);
+	}
+	bnapi->rx_pg_prod = prod;
+
+	ring_prod = prod = bnapi->rx_prod;
 	for (i = 0; i < bp->rx_ring_size; i++) {
-		if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) {
+		if (bnx2_alloc_rx_skb(bp, bnapi, ring_prod) < 0) {
 			break;
 		}
 		prod = NEXT_RX_BD(prod);
 		ring_prod = RX_RING_IDX(prod);
 	}
-	bp->rx_prod = prod;
+	bnapi->rx_prod = prod;
 
+	REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX,
+		 bnapi->rx_pg_prod);
 	REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, prod);
 
-	REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
+	REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq);
 }
 
-static void
-bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
+static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size)
 {
-	u32 num_rings, max;
+	u32 max, num_rings = 1;
 
-	bp->rx_ring_size = size;
-	num_rings = 1;
-	while (size > MAX_RX_DESC_CNT) {
-		size -= MAX_RX_DESC_CNT;
+	while (ring_size > MAX_RX_DESC_CNT) {
+		ring_size -= MAX_RX_DESC_CNT;
 		num_rings++;
 	}
 	/* round to next power of 2 */
-	max = MAX_RX_RINGS;
+	max = max_size;
 	while ((max & num_rings) == 0)
 		max >>= 1;
 
 	if (num_rings != max)
 		max <<= 1;
 
-	bp->rx_max_ring = max;
+	return max;
+}
+
+static void
+bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
+{
+	u32 rx_size, rx_space, jumbo_size;
+
+	/* 8 for CRC and VLAN */
+	rx_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
+
+	rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
+		sizeof(struct skb_shared_info);
+
+	bp->rx_copy_thresh = RX_COPY_THRESH;
+	bp->rx_pg_ring_size = 0;
+	bp->rx_max_pg_ring = 0;
+	bp->rx_max_pg_ring_idx = 0;
+	if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) {
+		int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT;
+
+		jumbo_size = size * pages;
+		if (jumbo_size > MAX_TOTAL_RX_PG_DESC_CNT)
+			jumbo_size = MAX_TOTAL_RX_PG_DESC_CNT;
+
+		bp->rx_pg_ring_size = jumbo_size;
+		bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size,
+							MAX_RX_PG_RINGS);
+		bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1;
+		rx_size = RX_COPY_THRESH + bp->rx_offset;
+		bp->rx_copy_thresh = 0;
+	}
+
+	bp->rx_buf_use_size = rx_size;
+	/* hw alignment */
+	bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
+	bp->rx_jumbo_thresh = rx_size - bp->rx_offset;
+	bp->rx_ring_size = size;
+	bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
 	bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
 }
 
@@ -4306,6 +4775,8 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
 
 		dev_kfree_skb(skb);
 	}
+	for (i = 0; i < bp->rx_max_pg_ring_idx; i++)
+		bnx2_free_rx_page(bp, i);
 }
 
 static void
@@ -4328,6 +4799,7 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
 	if ((rc = bnx2_init_chip(bp)) != 0)
 		return rc;
 
+	bnx2_clear_ring_states(bp);
 	bnx2_init_tx_ring(bp);
 	bnx2_init_rx_ring(bp);
 	return 0;
@@ -4599,13 +5071,18 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
 	struct sw_bd *rx_buf;
 	struct l2_fhdr *rx_hdr;
 	int ret = -ENODEV;
+	struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi;
+
+	tx_napi = bnapi;
+	if (bp->flags & BNX2_FLAG_USING_MSIX)
+		tx_napi = &bp->bnx2_napi[BNX2_TX_VEC];
 
 	if (loopback_mode == BNX2_MAC_LOOPBACK) {
 		bp->loopback = MAC_LOOPBACK;
 		bnx2_set_mac_loopback(bp);
 	}
 	else if (loopback_mode == BNX2_PHY_LOOPBACK) {
-		if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+		if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
 			return 0;
 
 		bp->loopback = PHY_LOOPBACK;
@@ -4614,7 +5091,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
 	else
 		return -EINVAL;
 
-	pkt_size = 1514;
+	pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4);
 	skb = netdev_alloc_skb(bp->dev, pkt_size);
 	if (!skb)
 		return -ENOMEM;
@@ -4633,7 +5110,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
 	REG_RD(bp, BNX2_HC_COMMAND);
 
 	udelay(5);
-	rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0;
+	rx_start_idx = bnx2_get_hw_rx_cons(bnapi);
 
 	num_pkts = 0;
 
@@ -4663,11 +5140,10 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
 	pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
 	dev_kfree_skb(skb);
 
-	if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) {
+	if (bnx2_get_hw_tx_cons(tx_napi) != bp->tx_prod)
 		goto loopback_test_done;
-	}
 
-	rx_idx = bp->status_blk->status_rx_quick_consumer_index0;
+	rx_idx = bnx2_get_hw_rx_cons(bnapi);
 	if (rx_idx != rx_start_idx + num_pkts) {
 		goto loopback_test_done;
 	}
@@ -4739,7 +5215,7 @@ bnx2_test_loopback(struct bnx2 *bp)
 static int
 bnx2_test_nvram(struct bnx2 *bp)
 {
-	u32 buf[NVRAM_SIZE / 4];
+	__be32 buf[NVRAM_SIZE / 4];
 	u8 *data = (u8 *) buf;
 	int rc = 0;
 	u32 magic, csum;
@@ -4776,7 +5252,7 @@ bnx2_test_link(struct bnx2 *bp)
 {
 	u32 bmsr;
 
-	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
 		if (bp->link_up)
 			return 0;
 		return -ENODEV;
@@ -4824,13 +5300,51 @@ bnx2_test_intr(struct bnx2 *bp)
 	return -ENODEV;
 }
 
+static int
+bnx2_5706_serdes_has_link(struct bnx2 *bp)
+{
+	u32 mode_ctl, an_dbg, exp;
+
+	bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL);
+	bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl);
+
+	if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET))
+		return 0;
+
+	bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
+	bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
+	bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg);
+
+	if (an_dbg & MISC_SHDW_AN_DBG_NOSYNC)
+		return 0;
+
+	bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1);
+	bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
+	bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp);
+
+	if (exp & MII_EXPAND_REG1_RUDI_C)	/* receiving CONFIG */
+		return 0;
+
+	return 1;
+}
+
 static void
 bnx2_5706_serdes_timer(struct bnx2 *bp)
 {
+	int check_link = 1;
+
 	spin_lock(&bp->phy_lock);
-	if (bp->serdes_an_pending)
+	if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) {
+		bnx2_5706s_force_link_dn(bp, 0);
+		bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN;
+		spin_unlock(&bp->phy_lock);
+		return;
+	}
+
+	if (bp->serdes_an_pending) {
 		bp->serdes_an_pending--;
-	else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
+		check_link = 0;
+	} else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
 		u32 bmcr;
 
 		bp->current_interval = bp->timer_interval;
@@ -4838,30 +5352,19 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
 		bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
 
 		if (bmcr & BMCR_ANENABLE) {
-			u32 phy1, phy2;
-
-			bnx2_write_phy(bp, 0x1c, 0x7c00);
-			bnx2_read_phy(bp, 0x1c, &phy1);
-
-			bnx2_write_phy(bp, 0x17, 0x0f01);
-			bnx2_read_phy(bp, 0x15, &phy2);
-			bnx2_write_phy(bp, 0x17, 0x0f01);
-			bnx2_read_phy(bp, 0x15, &phy2);
-
-			if ((phy1 & 0x10) &&	/* SIGNAL DETECT */
-				!(phy2 & 0x20)) {	/* no CONFIG */
-
+			if (bnx2_5706_serdes_has_link(bp)) {
 				bmcr &= ~BMCR_ANENABLE;
 				bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
 				bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
-				bp->phy_flags |= PHY_PARALLEL_DETECT_FLAG;
+				bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT;
 			}
 		}
 	}
 	else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
-		 (bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)) {
+		 (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) {
 		u32 phy2;
 
+		check_link = 0;
 		bnx2_write_phy(bp, 0x17, 0x0f01);
 		bnx2_read_phy(bp, 0x15, &phy2);
 		if (phy2 & 0x20) {
@@ -4871,21 +5374,33 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
 			bmcr |= BMCR_ANENABLE;
 			bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
 
-			bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
+			bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
 		}
 	} else
 		bp->current_interval = bp->timer_interval;
 
+	if (bp->link_up && (bp->autoneg & AUTONEG_SPEED) && check_link) {
+		u32 val;
+
+		bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG);
+		bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
+		bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val);
+
+		if (val & MISC_SHDW_AN_DBG_NOSYNC) {
+			bnx2_5706s_force_link_dn(bp, 1);
+			bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN;
+		}
+	}
 	spin_unlock(&bp->phy_lock);
 }
 
 static void
 bnx2_5708_serdes_timer(struct bnx2 *bp)
 {
-	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
 		return;
 
-	if ((bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) == 0) {
+	if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) {
 		bp->serdes_an_pending = 0;
 		return;
 	}
@@ -4932,7 +5447,7 @@ bnx2_timer(unsigned long data)
 		REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
 					    BNX2_HC_COMMAND_STATS_NOW);
 
-	if (bp->phy_flags & PHY_SERDES_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 		if (CHIP_NUM(bp) == CHIP_NUM_5706)
 			bnx2_5706_serdes_timer(bp);
 		else
@@ -4947,18 +5462,23 @@ static int
 bnx2_request_irq(struct bnx2 *bp)
 {
 	struct net_device *dev = bp->dev;
-	int rc = 0;
+	unsigned long flags;
+	struct bnx2_irq *irq;
+	int rc = 0, i;
 
-	if (bp->flags & USING_MSI_FLAG) {
-		irq_handler_t	fn = bnx2_msi;
-
-		if (bp->flags & ONE_SHOT_MSI_FLAG)
-			fn = bnx2_msi_1shot;
+	if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)
+		flags = 0;
+	else
+		flags = IRQF_SHARED;
 
-		rc = request_irq(bp->pdev->irq, fn, 0, dev->name, dev);
-	} else
-		rc = request_irq(bp->pdev->irq, bnx2_interrupt,
-				 IRQF_SHARED, dev->name, dev);
+	for (i = 0; i < bp->irq_nvecs; i++) {
+		irq = &bp->irq_tbl[i];
+		rc = request_irq(irq->vector, irq->handler, flags, irq->name,
+				 dev);
+		if (rc)
+			break;
+		irq->requested = 1;
+	}
 	return rc;
 }
 
@@ -4966,13 +5486,81 @@ static void
 bnx2_free_irq(struct bnx2 *bp)
 {
 	struct net_device *dev = bp->dev;
+	struct bnx2_irq *irq;
+	int i;
 
-	if (bp->flags & USING_MSI_FLAG) {
-		free_irq(bp->pdev->irq, dev);
+	for (i = 0; i < bp->irq_nvecs; i++) {
+		irq = &bp->irq_tbl[i];
+		if (irq->requested)
+			free_irq(irq->vector, dev);
+		irq->requested = 0;
+	}
+	if (bp->flags & BNX2_FLAG_USING_MSI)
 		pci_disable_msi(bp->pdev);
-		bp->flags &= ~(USING_MSI_FLAG | ONE_SHOT_MSI_FLAG);
-	} else
-		free_irq(bp->pdev->irq, dev);
+	else if (bp->flags & BNX2_FLAG_USING_MSIX)
+		pci_disable_msix(bp->pdev);
+
+	bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI);
+}
+
+static void
+bnx2_enable_msix(struct bnx2 *bp)
+{
+	int i, rc;
+	struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
+
+	bnx2_setup_msix_tbl(bp);
+	REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1);
+	REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE);
+	REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE);
+
+	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
+		msix_ent[i].entry = i;
+		msix_ent[i].vector = 0;
+	}
+
+	rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
+	if (rc != 0)
+		return;
+
+	bp->irq_tbl[BNX2_BASE_VEC].handler = bnx2_msi_1shot;
+	bp->irq_tbl[BNX2_TX_VEC].handler = bnx2_tx_msix;
+
+	strcpy(bp->irq_tbl[BNX2_BASE_VEC].name, bp->dev->name);
+	strcat(bp->irq_tbl[BNX2_BASE_VEC].name, "-base");
+	strcpy(bp->irq_tbl[BNX2_TX_VEC].name, bp->dev->name);
+	strcat(bp->irq_tbl[BNX2_TX_VEC].name, "-tx");
+
+	bp->irq_nvecs = BNX2_MAX_MSIX_VEC;
+	bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
+	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
+		bp->irq_tbl[i].vector = msix_ent[i].vector;
+}
+
+static void
+bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi)
+{
+	bp->irq_tbl[0].handler = bnx2_interrupt;
+	strcpy(bp->irq_tbl[0].name, bp->dev->name);
+	bp->irq_nvecs = 1;
+	bp->irq_tbl[0].vector = bp->pdev->irq;
+
+	if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi)
+		bnx2_enable_msix(bp);
+
+	if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi &&
+	    !(bp->flags & BNX2_FLAG_USING_MSIX)) {
+		if (pci_enable_msi(bp->pdev) == 0) {
+			bp->flags |= BNX2_FLAG_USING_MSI;
+			if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+				bp->flags |= BNX2_FLAG_ONE_SHOT_MSI;
+				bp->irq_tbl[0].handler = bnx2_msi_1shot;
+			} else
+				bp->irq_tbl[0].handler = bnx2_msi;
+
+			bp->irq_tbl[0].vector = bp->pdev->irq;
+		}
+	}
 }
 
 /* Called with rtnl_lock */
@@ -4991,19 +5579,12 @@ bnx2_open(struct net_device *dev)
 	if (rc)
 		return rc;
 
-	napi_enable(&bp->napi);
-
-	if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) {
-		if (pci_enable_msi(bp->pdev) == 0) {
-			bp->flags |= USING_MSI_FLAG;
-			if (CHIP_NUM(bp) == CHIP_NUM_5709)
-				bp->flags |= ONE_SHOT_MSI_FLAG;
-		}
-	}
+	bnx2_setup_int_mode(bp, disable_msi);
+	bnx2_napi_enable(bp);
 	rc = bnx2_request_irq(bp);
 
 	if (rc) {
-		napi_disable(&bp->napi);
+		bnx2_napi_disable(bp);
 		bnx2_free_mem(bp);
 		return rc;
 	}
@@ -5011,7 +5592,7 @@ bnx2_open(struct net_device *dev)
 	rc = bnx2_init_nic(bp);
 
 	if (rc) {
-		napi_disable(&bp->napi);
+		bnx2_napi_disable(bp);
 		bnx2_free_irq(bp);
 		bnx2_free_skbs(bp);
 		bnx2_free_mem(bp);
@@ -5024,7 +5605,7 @@ bnx2_open(struct net_device *dev)
 
 	bnx2_enable_int(bp);
 
-	if (bp->flags & USING_MSI_FLAG) {
+	if (bp->flags & BNX2_FLAG_USING_MSI) {
 		/* Test MSI to make sure it is working
 		 * If MSI test fails, go back to INTx mode
 		 */
@@ -5038,13 +5619,15 @@ bnx2_open(struct net_device *dev)
 			bnx2_disable_int(bp);
 			bnx2_free_irq(bp);
 
+			bnx2_setup_int_mode(bp, 1);
+
 			rc = bnx2_init_nic(bp);
 
 			if (!rc)
 				rc = bnx2_request_irq(bp);
 
 			if (rc) {
-				napi_disable(&bp->napi);
+				bnx2_napi_disable(bp);
 				bnx2_free_skbs(bp);
 				bnx2_free_mem(bp);
 				del_timer_sync(&bp->timer);
@@ -5053,9 +5636,10 @@ bnx2_open(struct net_device *dev)
 			bnx2_enable_int(bp);
 		}
 	}
-	if (bp->flags & USING_MSI_FLAG) {
+	if (bp->flags & BNX2_FLAG_USING_MSI)
 		printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
-	}
+	else if (bp->flags & BNX2_FLAG_USING_MSIX)
+		printk(KERN_INFO PFX "%s: using MSIX\n", dev->name);
 
 	netif_start_queue(dev);
 
@@ -5119,8 +5703,10 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	u32 len, vlan_tag_flags, last_frag, mss;
 	u16 prod, ring_prod;
 	int i;
+	struct bnx2_napi *bnapi = &bp->bnx2_napi[bp->tx_vec];
 
-	if (unlikely(bnx2_tx_avail(bp) < (skb_shinfo(skb)->nr_frags + 1))) {
+	if (unlikely(bnx2_tx_avail(bp, bnapi) <
+	    (skb_shinfo(skb)->nr_frags + 1))) {
 		netif_stop_queue(dev);
 		printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
 			dev->name);
@@ -5136,7 +5722,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
 	}
 
-	if (bp->vlgrp != 0 && vlan_tx_tag_present(skb)) {
+	if (bp->vlgrp && vlan_tx_tag_present(skb)) {
 		vlan_tag_flags |=
 			(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
 	}
@@ -5235,9 +5821,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	bp->tx_prod = prod;
 	dev->trans_start = jiffies;
 
-	if (unlikely(bnx2_tx_avail(bp) <= MAX_SKB_FRAGS)) {
+	if (unlikely(bnx2_tx_avail(bp, bnapi) <= MAX_SKB_FRAGS)) {
 		netif_stop_queue(dev);
-		if (bnx2_tx_avail(bp) > bp->tx_wake_thresh)
+		if (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)
 			netif_wake_queue(dev);
 	}
 
@@ -5259,9 +5845,9 @@ bnx2_close(struct net_device *dev)
 		msleep(1);
 
 	bnx2_disable_int_sync(bp);
-	napi_disable(&bp->napi);
+	bnx2_napi_disable(bp);
 	del_timer_sync(&bp->timer);
-	if (bp->flags & NO_WOL_FLAG)
+	if (bp->flags & BNX2_FLAG_NO_WOL)
 		reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
 	else if (bp->wol)
 		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
@@ -5375,7 +5961,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 	int support_serdes = 0, support_copper = 0;
 
 	cmd->supported = SUPPORTED_Autoneg;
-	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
 		support_serdes = 1;
 		support_copper = 1;
 	} else if (bp->phy_port == PORT_FIBRE)
@@ -5386,7 +5972,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 	if (support_serdes) {
 		cmd->supported |= SUPPORTED_1000baseT_Full |
 			SUPPORTED_FIBRE;
-		if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
+		if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)
 			cmd->supported |= SUPPORTED_2500baseX_Full;
 
 	}
@@ -5442,7 +6028,8 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 	if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
 		goto err_out_unlock;
 
-	if (cmd->port != bp->phy_port && !(bp->phy_flags & REMOTE_PHY_CAP_FLAG))
+	if (cmd->port != bp->phy_port &&
+	    !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP))
 		goto err_out_unlock;
 
 	if (cmd->autoneg == AUTONEG_ENABLE) {
@@ -5462,7 +6049,7 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 			advertising = cmd->advertising;
 
 		} else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
-			if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ||
+			if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ||
 			    (cmd->port == PORT_TP))
 				goto err_out_unlock;
 		} else if (cmd->advertising == ADVERTISED_1000baseT_Full)
@@ -5485,7 +6072,7 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 				goto err_out_unlock;
 
 			if (cmd->speed == SPEED_2500 &&
-			    !(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+			    !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
 				goto err_out_unlock;
 		}
 		else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
@@ -5584,7 +6171,7 @@ bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
 	struct bnx2 *bp = netdev_priv(dev);
 
-	if (bp->flags & NO_WOL_FLAG) {
+	if (bp->flags & BNX2_FLAG_NO_WOL) {
 		wol->supported = 0;
 		wol->wolopts = 0;
 	}
@@ -5607,7 +6194,7 @@ bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 		return -EINVAL;
 
 	if (wol->wolopts & WAKE_MAGIC) {
-		if (bp->flags & NO_WOL_FLAG)
+		if (bp->flags & BNX2_FLAG_NO_WOL)
 			return -EINVAL;
 
 		bp->wol = 1;
@@ -5630,7 +6217,7 @@ bnx2_nway_reset(struct net_device *dev)
 
 	spin_lock_bh(&bp->phy_lock);
 
-	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
 		int rc;
 
 		rc = bnx2_setup_remote_phy(bp, bp->phy_port);
@@ -5639,7 +6226,7 @@ bnx2_nway_reset(struct net_device *dev)
 	}
 
 	/* Force a link down visible on the other side */
-	if (bp->phy_flags & PHY_SERDES_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 		bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
 		spin_unlock_bh(&bp->phy_lock);
 
@@ -5778,27 +6365,19 @@ bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 
 	ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
 	ering->rx_mini_max_pending = 0;
-	ering->rx_jumbo_max_pending = 0;
+	ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT;
 
 	ering->rx_pending = bp->rx_ring_size;
 	ering->rx_mini_pending = 0;
-	ering->rx_jumbo_pending = 0;
+	ering->rx_jumbo_pending = bp->rx_pg_ring_size;
 
 	ering->tx_max_pending = MAX_TX_DESC_CNT;
 	ering->tx_pending = bp->tx_ring_size;
 }
 
 static int
-bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx)
 {
-	struct bnx2 *bp = netdev_priv(dev);
-
-	if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
-		(ering->tx_pending > MAX_TX_DESC_CNT) ||
-		(ering->tx_pending <= MAX_SKB_FRAGS)) {
-
-		return -EINVAL;
-	}
 	if (netif_running(bp->dev)) {
 		bnx2_netif_stop(bp);
 		bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
@@ -5806,8 +6385,8 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 		bnx2_free_mem(bp);
 	}
 
-	bnx2_set_rx_ring_size(bp, ering->rx_pending);
-	bp->tx_ring_size = ering->tx_pending;
+	bnx2_set_rx_ring_size(bp, rx);
+	bp->tx_ring_size = tx;
 
 	if (netif_running(bp->dev)) {
 		int rc;
@@ -5818,10 +6397,25 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 		bnx2_init_nic(bp);
 		bnx2_netif_start(bp);
 	}
-
 	return 0;
 }
 
+static int
+bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
+{
+	struct bnx2 *bp = netdev_priv(dev);
+	int rc;
+
+	if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
+		(ering->tx_pending > MAX_TX_DESC_CNT) ||
+		(ering->tx_pending <= MAX_SKB_FRAGS)) {
+
+		return -EINVAL;
+	}
+	rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending);
+	return rc;
+}
+
 static void
 bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 {
@@ -6244,7 +6838,7 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 	case SIOCGMIIREG: {
 		u32 mii_regval;
 
-		if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+		if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
 			return -EOPNOTSUPP;
 
 		if (!netif_running(dev))
@@ -6263,7 +6857,7 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+		if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)
 			return -EOPNOTSUPP;
 
 		if (!netif_running(dev))
@@ -6310,14 +6904,7 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu)
 		return -EINVAL;
 
 	dev->mtu = new_mtu;
-	if (netif_running(dev)) {
-		bnx2_netif_stop(bp);
-
-		bnx2_init_nic(bp);
-
-		bnx2_netif_start(bp);
-	}
-	return 0;
+	return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size));
 }
 
 #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
@@ -6342,7 +6929,7 @@ bnx2_get_5709_media(struct bnx2 *bp)
 	if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
 		return;
 	else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
-		bp->phy_flags |= PHY_SERDES_FLAG;
+		bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
 		return;
 	}
 
@@ -6356,7 +6943,7 @@ bnx2_get_5709_media(struct bnx2 *bp)
 		case 0x4:
 		case 0x5:
 		case 0x6:
-			bp->phy_flags |= PHY_SERDES_FLAG;
+			bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
 			return;
 		}
 	} else {
@@ -6364,7 +6951,7 @@ bnx2_get_5709_media(struct bnx2 *bp)
 		case 0x1:
 		case 0x2:
 		case 0x4:
-			bp->phy_flags |= PHY_SERDES_FLAG;
+			bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
 			return;
 		}
 	}
@@ -6379,7 +6966,7 @@ bnx2_get_pci_speed(struct bnx2 *bp)
 	if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
 		u32 clkreg;
 
-		bp->flags |= PCIX_FLAG;
+		bp->flags |= BNX2_FLAG_PCIX;
 
 		clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
 
@@ -6418,7 +7005,7 @@ bnx2_get_pci_speed(struct bnx2 *bp)
 	}
 
 	if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
-		bp->flags |= PCI_32BIT_FLAG;
+		bp->flags |= BNX2_FLAG_PCI_32BIT;
 
 }
 
@@ -6506,7 +7093,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 			rc = -EIO;
 			goto err_out_unmap;
 		}
-		bp->flags |= PCIE_FLAG;
+		bp->flags |= BNX2_FLAG_PCIE;
+		if (CHIP_REV(bp) == CHIP_REV_Ax)
+			bp->flags |= BNX2_FLAG_JUMBO_BROKEN;
 	} else {
 		bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
 		if (bp->pcix_cap == 0) {
@@ -6517,9 +7106,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 		}
 	}
 
+	if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) {
+		if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
+			bp->flags |= BNX2_FLAG_MSIX_CAP;
+	}
+
 	if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
 		if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
-			bp->flags |= MSI_CAP_FLAG;
+			bp->flags |= BNX2_FLAG_MSI_CAP;
 	}
 
 	/* 5708 cannot support DMA addresses > 40-bit.  */
@@ -6542,7 +7136,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 		goto err_out_unmap;
 	}
 
-	if (!(bp->flags & PCIE_FLAG))
+	if (!(bp->flags & BNX2_FLAG_PCIE))
 		bnx2_get_pci_speed(bp);
 
 	/* 5706A0 may falsely detect SERR and PERR. */
@@ -6552,7 +7146,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 		REG_WR(bp, PCI_COMMAND, reg);
 	}
 	else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
-		!(bp->flags & PCIX_FLAG)) {
+		!(bp->flags & BNX2_FLAG_PCIX)) {
 
 		dev_err(&pdev->dev,
 			"5706 A1 can only be used in a PCIX bus, aborting.\n");
@@ -6602,7 +7196,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 		bp->wol = 1;
 
 	if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
-		bp->flags |= ASF_ENABLE_FLAG;
+		bp->flags |= BNX2_FLAG_ASF_ENABLE;
 
 		for (i = 0; i < 30; i++) {
 			reg = REG_RD_IND(bp, bp->shmem_base +
@@ -6638,13 +7232,13 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 	bp->mac_addr[4] = (u8) (reg >> 8);
 	bp->mac_addr[5] = (u8) reg;
 
+	bp->rx_offset = sizeof(struct l2_fhdr) + 2;
+
 	bp->tx_ring_size = MAX_TX_DESC_CNT;
 	bnx2_set_rx_ring_size(bp, 255);
 
 	bp->rx_csum = 1;
 
-	bp->rx_offset = sizeof(struct l2_fhdr) + 2;
-
 	bp->tx_quick_cons_trip_int = 20;
 	bp->tx_quick_cons_trip = 20;
 	bp->tx_ticks_int = 80;
@@ -6666,36 +7260,36 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 	if (CHIP_NUM(bp) == CHIP_NUM_5709)
 		bnx2_get_5709_media(bp);
 	else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
-		bp->phy_flags |= PHY_SERDES_FLAG;
+		bp->phy_flags |= BNX2_PHY_FLAG_SERDES;
 
 	bp->phy_port = PORT_TP;
-	if (bp->phy_flags & PHY_SERDES_FLAG) {
+	if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) {
 		bp->phy_port = PORT_FIBRE;
 		reg = REG_RD_IND(bp, bp->shmem_base +
 				     BNX2_SHARED_HW_CFG_CONFIG);
 		if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
-			bp->flags |= NO_WOL_FLAG;
+			bp->flags |= BNX2_FLAG_NO_WOL;
 			bp->wol = 0;
 		}
 		if (CHIP_NUM(bp) != CHIP_NUM_5706) {
 			bp->phy_addr = 2;
 			if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
-				bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
+				bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE;
 		}
 		bnx2_init_remote_phy(bp);
 
 	} else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
 		   CHIP_NUM(bp) == CHIP_NUM_5708)
-		bp->phy_flags |= PHY_CRC_FIX_FLAG;
+		bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX;
 	else if (CHIP_NUM(bp) == CHIP_NUM_5709 &&
 		 (CHIP_REV(bp) == CHIP_REV_Ax ||
 		  CHIP_REV(bp) == CHIP_REV_Bx))
-		bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG;
+		bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC;
 
 	if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
 	    (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
 	    (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
-		bp->flags |= NO_WOL_FLAG;
+		bp->flags |= BNX2_FLAG_NO_WOL;
 		bp->wol = 0;
 	}
 
@@ -6769,13 +7363,13 @@ bnx2_bus_string(struct bnx2 *bp, char *str)
 {
 	char *s = str;
 
-	if (bp->flags & PCIE_FLAG) {
+	if (bp->flags & BNX2_FLAG_PCIE) {
 		s += sprintf(s, "PCI Express");
 	} else {
 		s += sprintf(s, "PCI");
-		if (bp->flags & PCIX_FLAG)
+		if (bp->flags & BNX2_FLAG_PCIX)
 			s += sprintf(s, "-X");
-		if (bp->flags & PCI_32BIT_FLAG)
+		if (bp->flags & BNX2_FLAG_PCI_32BIT)
 			s += sprintf(s, " 32-bit");
 		else
 			s += sprintf(s, " 64-bit");
@@ -6784,6 +7378,21 @@ bnx2_bus_string(struct bnx2 *bp, char *str)
 	return str;
 }
 
+static void __devinit
+bnx2_init_napi(struct bnx2 *bp)
+{
+	int i;
+	struct bnx2_napi *bnapi;
+
+	for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
+		bnapi = &bp->bnx2_napi[i];
+		bnapi->bp = bp;
+	}
+	netif_napi_add(bp->dev, &bp->bnx2_napi[0].napi, bnx2_poll, 64);
+	netif_napi_add(bp->dev, &bp->bnx2_napi[BNX2_TX_VEC].napi, bnx2_tx_poll,
+		       64);
+}
+
 static int __devinit
 bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -6825,7 +7434,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	dev->ethtool_ops = &bnx2_ethtool_ops;
 
 	bp = netdev_priv(dev);
-	netif_napi_add(dev, &bp->napi, bnx2_poll, 64);
+	bnx2_init_napi(bp);
 
 #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
 	dev->poll_controller = poll_bnx2;
@@ -6910,7 +7519,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
 	bnx2_netif_stop(bp);
 	netif_device_detach(dev);
 	del_timer_sync(&bp->timer);
-	if (bp->flags & NO_WOL_FLAG)
+	if (bp->flags & BNX2_FLAG_NO_WOL)
 		reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
 	else if (bp->wol)
 		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 30ba366608b0..d8e034700c36 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -154,6 +154,33 @@ struct status_block {
 #endif
 };
 
+/*
+ *  status_block definition
+ */
+struct status_block_msix {
+#if defined(__BIG_ENDIAN)
+	u16 status_tx_quick_consumer_index;
+	u16 status_rx_quick_consumer_index;
+	u16 status_completion_producer_index;
+	u16 status_cmd_consumer_index;
+	u32 status_unused;
+	u16 status_idx;
+	u8 status_unused2;
+	u8 status_blk_num;
+#elif defined(__LITTLE_ENDIAN)
+	u16 status_rx_quick_consumer_index;
+	u16 status_tx_quick_consumer_index;
+	u16 status_cmd_consumer_index;
+	u16 status_completion_producer_index;
+	u32 status_unused;
+	u8 status_blk_num;
+	u8 status_unused2;
+	u16 status_idx;
+#endif
+};
+
+#define BNX2_SBLK_MSIX_ALIGN_SIZE	128
+
 
 /*
  *  statistics_block definition
@@ -259,6 +286,7 @@ struct l2_fhdr {
 		#define L2_FHDR_STATUS_TCP_SEGMENT	(1<<14)
 		#define L2_FHDR_STATUS_UDP_DATAGRAM	(1<<15)
 
+		#define L2_FHDR_STATUS_SPLIT		(1<<16)
 		#define L2_FHDR_ERRORS_BAD_CRC		(1<<17)
 		#define L2_FHDR_ERRORS_PHY_DECODE	(1<<18)
 		#define L2_FHDR_ERRORS_ALIGNMENT	(1<<19)
@@ -332,6 +360,12 @@ struct l2_fhdr {
 #define BNX2_L2CTX_NX_BDHADDR_LO			0x00000014
 #define BNX2_L2CTX_NX_BDIDX				0x00000018
 
+#define BNX2_L2CTX_HOST_PG_BDIDX			0x00000044
+#define BNX2_L2CTX_PG_BUF_SIZE				0x00000048
+#define BNX2_L2CTX_RBDC_KEY				0x0000004c
+#define BNX2_L2CTX_RBDC_JUMBO_KEY			 0x3ffe
+#define BNX2_L2CTX_NX_PG_BDHADDR_HI			0x00000050
+#define BNX2_L2CTX_NX_PG_BDHADDR_LO			0x00000054
 
 /*
  *  pci_config_l definition
@@ -406,6 +440,7 @@ struct l2_fhdr {
 #define BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM	 (1L<<17)
 #define BNX2_PCICFG_INT_ACK_CMD_MASK_INT		 (1L<<18)
 #define BNX2_PCICFG_INT_ACK_CMD_INTERRUPT_NUM		 (0xfL<<24)
+#define BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT		 24
 
 #define BNX2_PCICFG_STATUS_BIT_SET_CMD			0x00000088
 #define BNX2_PCICFG_STATUS_BIT_CLEAR_CMD		0x0000008c
@@ -421,6 +456,9 @@ struct l2_fhdr {
 #define BNX2_PCI_GRC_WINDOW_ADDR_VALUE			 (0x1ffL<<13)
 #define BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN		 (1L<<31)
 
+#define BNX2_PCI_GRC_WINDOW2_BASE		 	 0xc000
+#define BNX2_PCI_GRC_WINDOW3_BASE		 	 0xe000
+
 #define BNX2_PCI_CONFIG_1				0x00000404
 #define BNX2_PCI_CONFIG_1_RESERVED0			 (0xffL<<0)
 #define BNX2_PCI_CONFIG_1_READ_BOUNDARY			 (0x7L<<8)
@@ -693,6 +731,8 @@ struct l2_fhdr {
 #define BNX2_PCI_GRC_WINDOW3_ADDR			0x00000618
 #define BNX2_PCI_GRC_WINDOW3_ADDR_VALUE			 (0x1ffL<<13)
 
+#define BNX2_MSIX_TABLE_ADDR				 0x318000
+#define BNX2_MSIX_PBA_ADDR				 0x31c000
 
 /*
  *  misc_reg definition
@@ -4445,6 +4485,14 @@ struct l2_fhdr {
 #define BNX2_MQ_MEM_RD_DATA2_VALUE			 (0x3fffffffL<<0)
 #define BNX2_MQ_MEM_RD_DATA2_VALUE_XI			 (0x7fffffffL<<0)
 
+#define BNX2_MQ_MAP_L2_3				0x00003d2c
+#define BNX2_MQ_MAP_L2_3_MQ_OFFSET			 (0xffL<<0)
+#define BNX2_MQ_MAP_L2_3_SZ				 (0x3L<<8)
+#define BNX2_MQ_MAP_L2_3_CTX_OFFSET			 (0x2ffL<<10)
+#define BNX2_MQ_MAP_L2_3_BIN_OFFSET			 (0x7L<<23)
+#define BNX2_MQ_MAP_L2_3_ARM				 (0x3L<<26)
+#define BNX2_MQ_MAP_L2_3_ENA				 (0x1L<<31)
+#define BNX2_MQ_MAP_L2_3_DEFAULT			 0x82004646
 
 /*
  *  tsch_reg definition
@@ -6296,6 +6344,15 @@ struct l2_fhdr {
 #define MII_BNX2_DSP_RW_PORT			0x15
 #define MII_BNX2_DSP_ADDRESS			0x17
 #define MII_BNX2_DSP_EXPAND_REG			 0x0f00
+#define MII_EXPAND_REG1				  (MII_BNX2_DSP_EXPAND_REG | 1)
+#define MII_EXPAND_REG1_RUDI_C			   0x20
+#define MII_EXPAND_SERDES_CTL			  (MII_BNX2_DSP_EXPAND_REG | 2)
+
+#define MII_BNX2_MISC_SHADOW			0x1c
+#define MISC_SHDW_AN_DBG			 0x6800
+#define MISC_SHDW_AN_DBG_NOSYNC			  0x0002
+#define MISC_SHDW_MODE_CTL			 0x7c00
+#define MISC_SHDW_MODE_CTL_SIG_DET		  0x0010
 
 #define MII_BNX2_BLK_ADDR			0x1f
 #define MII_BNX2_BLK_ADDR_IEEE0			 0x0000
@@ -6336,7 +6393,7 @@ struct l2_fhdr {
 #define MAX_ETHERNET_PACKET_SIZE	1514
 #define MAX_ETHERNET_JUMBO_PACKET_SIZE	9014
 
-#define RX_COPY_THRESH			92
+#define RX_COPY_THRESH			128
 
 #define BNX2_MISC_ENABLE_DEFAULT	0x7ffffff
 
@@ -6355,9 +6412,11 @@ struct l2_fhdr {
 #define MAX_TX_DESC_CNT (TX_DESC_CNT - 1)
 
 #define MAX_RX_RINGS	4
+#define MAX_RX_PG_RINGS	16
 #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 MAX_TOTAL_RX_PG_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_PG_RINGS)
 
 #define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) ==			\
 		(MAX_TX_DESC_CNT - 1)) ?				\
@@ -6370,6 +6429,7 @@ struct l2_fhdr {
 	(x) + 2 : (x) + 1
 
 #define RX_RING_IDX(x) ((x) & bp->rx_max_ring_idx)
+#define RX_PG_RING_IDX(x) ((x) & bp->rx_max_pg_ring_idx)
 
 #define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> (BCM_PAGE_BITS - 4))
 #define RX_IDX(x) ((x) & MAX_RX_DESC_CNT)
@@ -6408,6 +6468,17 @@ struct sw_bd {
 	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
+struct sw_pg {
+	struct page		*page;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+};
+
+#define SW_RXBD_RING_SIZE (sizeof(struct sw_bd) * RX_DESC_CNT)
+#define SW_RXPG_RING_SIZE (sizeof(struct sw_pg) * RX_DESC_CNT)
+#define RXBD_RING_SIZE (sizeof(struct rx_bd) * RX_DESC_CNT)
+#define SW_TXBD_RING_SIZE (sizeof(struct sw_bd) * TX_DESC_CNT)
+#define TXBD_RING_SIZE (sizeof(struct tx_bd) * TX_DESC_CNT)
+
 /* Buffered flash (Atmel: AT45DB011B) specific information */
 #define SEEPROM_PAGE_BITS			2
 #define SEEPROM_PHY_PAGE_SIZE			(1 << SEEPROM_PAGE_BITS)
@@ -6465,6 +6536,39 @@ struct flash_spec {
 	u8  *name;
 };
 
+#define BNX2_MAX_MSIX_HW_VEC	9
+#define BNX2_MAX_MSIX_VEC	2
+#define BNX2_BASE_VEC		0
+#define BNX2_TX_VEC		1
+#define BNX2_TX_INT_NUM	(BNX2_TX_VEC << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT)
+
+struct bnx2_irq {
+	irq_handler_t	handler;
+	u16		vector;
+	u8		requested;
+	char		name[16];
+};
+
+struct bnx2_napi {
+	struct napi_struct	napi		____cacheline_aligned;
+	struct bnx2		*bp;
+	struct status_block	*status_blk;
+	struct status_block_msix	*status_blk_msix;
+	u32 			last_status_idx;
+	u32			int_num;
+
+	u16			tx_cons;
+	u16			hw_tx_cons;
+
+	u32			rx_prod_bseq;
+	u16			rx_prod;
+	u16			rx_cons;
+
+	u16			rx_pg_prod;
+	u16			rx_pg_cons;
+
+};
+
 struct bnx2 {
 	/* Fields used in the tx and intr/napi performance paths are grouped */
 	/* together in the beginning of the structure. */
@@ -6473,33 +6577,32 @@ struct bnx2 {
 	struct net_device	*dev;
 	struct pci_dev		*pdev;
 
-	struct napi_struct	napi;
-
 	atomic_t		intr_sem;
 
-	struct status_block	*status_blk;
-	u32 			last_status_idx;
-
 	u32			flags;
-#define PCIX_FLAG			0x00000001
-#define PCI_32BIT_FLAG			0x00000002
-#define ONE_TDMA_FLAG			0x00000004	/* no longer used */
-#define NO_WOL_FLAG			0x00000008
-#define USING_MSI_FLAG			0x00000020
-#define ASF_ENABLE_FLAG			0x00000040
-#define MSI_CAP_FLAG			0x00000080
-#define ONE_SHOT_MSI_FLAG		0x00000100
-#define PCIE_FLAG			0x00000200
+#define BNX2_FLAG_PCIX			0x00000001
+#define BNX2_FLAG_PCI_32BIT		0x00000002
+#define BNX2_FLAG_MSIX_CAP		0x00000004
+#define BNX2_FLAG_NO_WOL		0x00000008
+#define BNX2_FLAG_USING_MSI		0x00000020
+#define BNX2_FLAG_ASF_ENABLE		0x00000040
+#define BNX2_FLAG_MSI_CAP		0x00000080
+#define BNX2_FLAG_ONE_SHOT_MSI		0x00000100
+#define BNX2_FLAG_PCIE			0x00000200
+#define BNX2_FLAG_USING_MSIX		0x00000400
+#define BNX2_FLAG_USING_MSI_OR_MSIX	(BNX2_FLAG_USING_MSI | \
+					 BNX2_FLAG_USING_MSIX)
+#define BNX2_FLAG_JUMBO_BROKEN		0x00000800
 
 	/* Put tx producer and consumer fields in separate cache lines. */
 
 	u32		tx_prod_bseq __attribute__((aligned(L1_CACHE_BYTES)));
 	u16		tx_prod;
+	u8		tx_vec;
 	u32		tx_bidx_addr;
 	u32		tx_bseq_addr;
 
-	u16		tx_cons __attribute__((aligned(L1_CACHE_BYTES)));
-	u16		hw_tx_cons;
+	struct bnx2_napi	bnx2_napi[BNX2_MAX_MSIX_VEC];
 
 #ifdef BCM_VLAN
 	struct			vlan_group *vlgrp;
@@ -6508,16 +6611,17 @@ struct bnx2 {
 	u32			rx_offset;
 	u32			rx_buf_use_size;	/* useable size */
 	u32			rx_buf_size;		/* with alignment */
+	u32			rx_copy_thresh;
+	u32			rx_jumbo_thresh;
 	u32			rx_max_ring_idx;
-
-	u32			rx_prod_bseq;
-	u16			rx_prod;
-	u16			rx_cons;
+	u32			rx_max_pg_ring_idx;
 
 	u32			rx_csum;
 
 	struct sw_bd		*rx_buf_ring;
 	struct rx_bd		*rx_desc_ring[MAX_RX_RINGS];
+	struct sw_pg		*rx_pg_ring;
+	struct rx_bd		*rx_pg_desc_ring[MAX_RX_PG_RINGS];
 
 	/* TX constants */
 	struct tx_bd	*tx_desc_ring;
@@ -6540,15 +6644,16 @@ struct bnx2 {
 	spinlock_t		indirect_lock;
 
 	u32			phy_flags;
-#define PHY_SERDES_FLAG			1
-#define PHY_CRC_FIX_FLAG		2
-#define PHY_PARALLEL_DETECT_FLAG	4
-#define PHY_2_5G_CAPABLE_FLAG		8
-#define PHY_INT_MODE_MASK_FLAG		0x300
-#define PHY_INT_MODE_AUTO_POLLING_FLAG	0x100
-#define PHY_INT_MODE_LINK_READY_FLAG	0x200
-#define PHY_DIS_EARLY_DAC_FLAG		0x400
-#define REMOTE_PHY_CAP_FLAG		0x800
+#define BNX2_PHY_FLAG_SERDES			0x00000001
+#define BNX2_PHY_FLAG_CRC_FIX			0x00000002
+#define BNX2_PHY_FLAG_PARALLEL_DETECT		0x00000004
+#define BNX2_PHY_FLAG_2_5G_CAPABLE		0x00000008
+#define BNX2_PHY_FLAG_INT_MODE_MASK		0x00000300
+#define BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING	0x00000100
+#define BNX2_PHY_FLAG_INT_MODE_LINK_READY	0x00000200
+#define BNX2_PHY_FLAG_DIS_EARLY_DAC		0x00000400
+#define BNX2_PHY_FLAG_REMOTE_PHY_CAP		0x00000800
+#define BNX2_PHY_FLAG_FORCED_DOWN		0x00001000
 
 	u32			mii_bmcr;
 	u32			mii_bmsr;
@@ -6605,6 +6710,10 @@ struct bnx2 {
 	int			rx_ring_size;
 	dma_addr_t		rx_desc_mapping[MAX_RX_RINGS];
 
+	int			rx_max_pg_ring;
+	int			rx_pg_ring_size;
+	dma_addr_t		rx_pg_desc_mapping[MAX_RX_PG_RINGS];
+
 	u16			tx_quick_cons_trip;
 	u16			tx_quick_cons_trip_int;
 	u16			rx_quick_cons_trip;
@@ -6622,6 +6731,7 @@ struct bnx2 {
 
 	u32			stats_ticks;
 
+	struct status_block	*status_blk;
 	dma_addr_t		status_blk_mapping;
 
 	struct statistics_block	*stats_blk;
@@ -6680,6 +6790,9 @@ struct bnx2 {
 	u32			flash_size;
 
 	int			status_stats_size;
+
+	struct bnx2_irq		irq_tbl[BNX2_MAX_MSIX_VEC];
+	int			irq_nvecs;
 };
 
 static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
@@ -6737,7 +6850,7 @@ struct fw_info {
 	const u32 text_addr;
 	const u32 text_len;
 	const u32 text_index;
-	u32 *text;
+	__le32 *text;
 	u8 *gz_text;
 	const u32 gz_text_len;
 
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h
index a6d78243163b..c1ad4dd38c32 100644
--- a/drivers/net/bnx2_fw.h
+++ b/drivers/net/bnx2_fw.h
@@ -1,13 +1,13 @@
 /* bnx2_fw.h: Broadcom NX2 network driver.
  *
- * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
+ * Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation
  *
  * 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, except as noted below.
  *
  * This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2004, 2005, 2006 Broadcom Corporation.
+ * source code, Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation.
  *
  * Permission is hereby granted for the distribution of this firmware data
  * in hexadecimal or equivalent format, provided this copyright notice is
@@ -15,2264 +15,3633 @@
  */
 
 static u8 bnx2_COM_b06FwText[] = {
-/*	0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, */
-								    0xdc, 0x5a,
-	0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, 0xc8, 0x15,
-	0x35, 0xa2, 0xc6, 0xf4, 0x5a, 0xa2, 0xed, 0x5d, 0x72, 0x28, 0x12, 0x96,
-	0xec, 0x6e, 0x68, 0xda, 0x62, 0x8c, 0x8d, 0xb4, 0xd9, 0xa5, 0x0c, 0xa1,
-	0x65, 0x6b, 0x4a, 0xa2, 0x6d, 0x05, 0x11, 0x02, 0x62, 0x49, 0xa9, 0x46,
-	0x50, 0xb7, 0x92, 0xab, 0xb6, 0x81, 0x6b, 0x4b, 0x6b, 0x92, 0x6a, 0x09,
-	0x84, 0xe6, 0x08, 0x11, 0x43, 0x19, 0xa9, 0x11, 0x10, 0xa4, 0x1c, 0xbb,
-	0xc0, 0xb6, 0x2b, 0xbf, 0x05, 0x34, 0x2e, 0x15, 0x4a, 0x6e, 0xd4, 0x34,
-	0x30, 0xfc, 0xa7, 0xa8, 0x51, 0x38, 0xad, 0xe1, 0x04, 0xa8, 0x9b, 0x16,
-	0x45, 0xd0, 0xfc, 0x88, 0x0a, 0xdb, 0xd9, 0x7e, 0xdf, 0x9d, 0x3b, 0xcb,
-	0xe1, 0x92, 0xd4, 0xc3, 0x8f, 0xfe, 0x28, 0x81, 0xe5, 0xcc, 0xbd, 0x73,
-	0xe7, 0xde, 0x73, 0xcf, 0xe3, 0x3b, 0x8f, 0xb9, 0x77, 0x8a, 0x34, 0x88,
-	0xfe, 0x5b, 0x8f, 0x5f, 0xf2, 0xd1, 0x3f, 0x18, 0xbe, 0xab, 0xe7, 0xae,
-	0xbb, 0x71, 0x7b, 0xb7, 0x19, 0xb1, 0x22, 0xec, 0xe7, 0x3f, 0x07, 0xbf,
-	0x6e, 0x7d, 0xbf, 0xda, 0x9f, 0x8d, 0xdf, 0x65, 0xfc, 0x86, 0x7e, 0x2e,
-	0x62, 0xac, 0x31, 0x26, 0xfc, 0x57, 0xa9, 0x5c, 0xfd, 0xb9, 0x49, 0x5a,
-	0xae, 0xf2, 0x3c, 0xe2, 0x2f, 0xa9, 0x68, 0xe6, 0x4f, 0x62, 0x66, 0x46,
-	0x8e, 0xe7, 0x5c, 0x89, 0x45, 0x32, 0x1f, 0x1c, 0x1f, 0x76, 0x45, 0xb2,
-	0xa5, 0x6d, 0xc9, 0xbc, 0x7c, 0x5c, 0x29, 0x3a, 0x96, 0xb0, 0xff, 0xd6,
-	0xcc, 0x47, 0x27, 0xde, 0xd8, 0x91, 0xfa, 0xc5, 0x6c, 0x44, 0x62, 0x76,
-	0xe6, 0x15, 0xb1, 0xb7, 0x4a, 0xac, 0x15, 0xef, 0x3c, 0xdb, 0x99, 0x33,
-	0xa4, 0x29, 0x98, 0xeb, 0x83, 0xca, 0x1b, 0x9d, 0x52, 0xdc, 0x9c, 0x89,
-	0x89, 0x99, 0xe9, 0x78, 0x27, 0x17, 0xb1, 0x87, 0x22, 0x19, 0x5b, 0x16,
-	0xca, 0x32, 0x30, 0x32, 0x29, 0xb1, 0x58, 0x66, 0x22, 0x56, 0xdf, 0x21,
-	0xb1, 0x68, 0x66, 0xe8, 0xf8, 0xf7, 0xdc, 0x13, 0x15, 0xd3, 0x75, 0x93,
-	0xa3, 0x12, 0xef, 0x1d, 0xef, 0xc1, 0xf3, 0x52, 0x0a, 0x04, 0xef, 0x10,
-	0xd3, 0x2d, 0xc6, 0x23, 0x6e, 0x4c, 0x72, 0x65, 0x57, 0xf2, 0x65, 0x91,
-	0x1f, 0x96, 0x0c, 0x19, 0x77, 0x5b, 0x64, 0x74, 0xfb, 0x47, 0x95, 0x2c,
-	0x68, 0xf9, 0x3b, 0x77, 0xe8, 0xf8, 0x73, 0x2e, 0xe9, 0x9d, 0x8e, 0xf9,
-	0xf4, 0x8e, 0xd7, 0x0f, 0xbb, 0x96, 0xcc, 0x95, 0xd8, 0x77, 0xd0, 0x64,
-	0x9f, 0x95, 0xf9, 0x7e, 0xc3, 0xb8, 0x1b, 0xd7, 0x7d, 0x13, 0xd9, 0x1c,
-	0xe6, 0x9b, 0x2f, 0x71, 0xec, 0xbb, 0x5f, 0x18, 0x76, 0x1d, 0xdd, 0x9f,
-	0xdd, 0x91, 0x73, 0x13, 0xe8, 0x6f, 0xd5, 0xcf, 0x9e, 0x79, 0x74, 0xd8,
-	0x75, 0xf5, 0x33, 0xcb, 0xca, 0xb9, 0x5d, 0xba, 0xbf, 0xb4, 0x6b, 0xd8,
-	0xdd, 0xae, 0xfb, 0x7f, 0xbc, 0x2b, 0xe7, 0xa6, 0x75, 0x7f, 0xef, 0x57,
-	0x86, 0xdd, 0x1e, 0xdd, 0xff, 0xf6, 0xce, 0x9c, 0xdb, 0xab, 0xfb, 0x4f,
-	0xf5, 0x0e, 0xbb, 0xb6, 0x9c, 0x2d, 0x25, 0xf1, 0x9b, 0x88, 0x59, 0x1d,
-	0x19, 0x3d, 0xe6, 0x59, 0xd0, 0x9b, 0xc5, 0x98, 0x3e, 0xf4, 0xef, 0xc1,
-	0xaf, 0x1f, 0xbf, 0xf2, 0x06, 0x69, 0x1a, 0xc0, 0xf3, 0x0f, 0xb7, 0xf8,
-	0x3c, 0x04, 0xaf, 0xbc, 0x98, 0xbc, 0x17, 0x49, 0xc8, 0x1b, 0x9d, 0xef,
-	0x81, 0x97, 0xb6, 0x9c, 0x2b, 0x8b, 0x31, 0xd0, 0x99, 0x00, 0x0f, 0x1d,
-	0x79, 0xb1, 0xdc, 0x28, 0x91, 0x6f, 0x45, 0xc0, 0xa3, 0xaf, 0x4a, 0xc1,
-	0x89, 0xc9, 0xc6, 0x19, 0x43, 0xda, 0xba, 0xd7, 0x49, 0xd6, 0x2e, 0x4a,
-	0xbe, 0x13, 0x52, 0x9f, 0x72, 0xc4, 0x9a, 0x59, 0xdc, 0x68, 0xa2, 0xc7,
-	0x94, 0x54, 0xa2, 0x80, 0x19, 0x47, 0xce, 0xbe, 0x4b, 0x1d, 0xa5, 0x7c,
-	0xf1, 0x4b, 0x4a, 0x7e, 0xf2, 0x0e, 0x19, 0xb2, 0x49, 0xe7, 0x9f, 0xdd,
-	0xea, 0xaf, 0x19, 0x33, 0x72, 0x67, 0x06, 0xe5, 0xa4, 0x17, 0x37, 0xf2,
-	0x67, 0x76, 0x4a, 0x2e, 0x2d, 0x8e, 0x29, 0x1d, 0xea, 0xdd, 0xf9, 0xd2,
-	0xa0, 0x8c, 0x7b, 0x62, 0xe4, 0x3c, 0x4b, 0x46, 0x4b, 0x2d, 0x78, 0xde,
-	0xa4, 0xc6, 0xa2, 0xaf, 0x35, 0x22, 0x1d, 0x76, 0x5e, 0x62, 0xe8, 0xb7,
-	0xd1, 0xdf, 0x6c, 0xf4, 0xa9, 0x39, 0x54, 0x7f, 0x72, 0x4c, 0xe2, 0xd8,
-	0x9b, 0xa3, 0xc7, 0x56, 0x2a, 0xb9, 0xb4, 0x8d, 0x71, 0x83, 0x32, 0xe6,
-	0x39, 0x32, 0x84, 0xeb, 0xa8, 0xc7, 0xf5, 0x13, 0xd0, 0xb1, 0xb7, 0x8e,
-	0x17, 0xa6, 0xd5, 0x7c, 0xc9, 0x48, 0x86, 0xf3, 0xb5, 0x62, 0xdc, 0x05,
-	0xd0, 0x65, 0x88, 0xa5, 0x64, 0x9b, 0x95, 0xc2, 0xa4, 0x21, 0xe4, 0x5b,
-	0x41, 0xf1, 0xb0, 0x0f, 0xf4, 0x5b, 0xe2, 0x76, 0x1b, 0x32, 0xec, 0xde,
-	0x2c, 0x45, 0x1b, 0xed, 0xd2, 0x79, 0x33, 0xe7, 0xd5, 0x4b, 0xde, 0x4a,
-	0x62, 0xff, 0x94, 0xfd, 0x90, 0x8c, 0xe1, 0x1d, 0xd3, 0xe5, 0x98, 0x8f,
-	0xb0, 0x77, 0xb4, 0xf1, 0x6e, 0x5d, 0xe6, 0xa0, 0x5c, 0x9a, 0x2c, 0x9a,
-	0xb9, 0x72, 0x8b, 0x44, 0x66, 0x52, 0xd0, 0xfe, 0x71, 0x33, 0xff, 0xbc,
-	0x25, 0xd1, 0x29, 0xea, 0x97, 0xd8, 0x91, 0xcc, 0x84, 0xb9, 0xbb, 0x7c,
-	0xde, 0xcc, 0x97, 0xf9, 0x0e, 0xc6, 0x96, 0x4c, 0xf0, 0x96, 0xf7, 0xdb,
-	0xc0, 0x4b, 0xea, 0x36, 0xdf, 0x81, 0x1c, 0xb0, 0x87, 0x17, 0x3d, 0xc8,
-	0x45, 0xc9, 0x29, 0x09, 0x39, 0x89, 0xd1, 0xd7, 0x19, 0x93, 0xb1, 0x69,
-	0x4b, 0x0a, 0xe9, 0x9b, 0x15, 0xe7, 0x0b, 0xe9, 0x25, 0x9a, 0x46, 0x27,
-	0x6b, 0x69, 0xe2, 0x7b, 0xa4, 0xc9, 0xa7, 0x65, 0x6c, 0x9a, 0xb4, 0xf9,
-	0xb4, 0x9c, 0x9c, 0x24, 0x8d, 0x5c, 0x87, 0xf4, 0x90, 0xae, 0x80, 0x26,
-	0xbe, 0x43, 0x9a, 0x36, 0x61, 0x7e, 0x65, 0xc0, 0x46, 0x1f, 0x68, 0x18,
-	0xf3, 0x2c, 0xc8, 0x26, 0x2e, 0x05, 0xbb, 0x68, 0x8c, 0xf5, 0x6e, 0x4b,
-	0xc0, 0xaa, 0x8d, 0xd1, 0x5e, 0xd2, 0xeb, 0x42, 0x7e, 0x75, 0x4a, 0xce,
-	0x66, 0x66, 0x9c, 0x3c, 0xc3, 0x78, 0xae, 0x8d, 0xfb, 0x92, 0x2d, 0xe3,
-	0x6a, 0x3e, 0xd2, 0xf3, 0x59, 0xcc, 0x43, 0x7a, 0x2f, 0x43, 0x57, 0x7b,
-	0xa0, 0xa3, 0x69, 0xf9, 0xdb, 0xf2, 0x76, 0x79, 0xbd, 0xdc, 0x25, 0xaf,
-	0xc1, 0x7e, 0x5f, 0x2d, 0x27, 0xe5, 0x95, 0x72, 0xab, 0xbc, 0x5c, 0x4e,
-	0xc8, 0x4b, 0x4a, 0x7f, 0xfb, 0x44, 0x9a, 0x94, 0x4e, 0xc7, 0x6e, 0x86,
-	0x3e, 0xb6, 0x40, 0x1f, 0x9b, 0x61, 0x4f, 0x1b, 0x61, 0xab, 0xdf, 0x06,
-	0x0f, 0xa7, 0x3b, 0x25, 0xbb, 0x09, 0xfd, 0xb7, 0x65, 0x2c, 0xa5, 0x23,
-	0x16, 0x9e, 0x8f, 0x4d, 0x46, 0x25, 0x6f, 0x9f, 0x95, 0xf7, 0xa7, 0x2c,
-	0x19, 0x2b, 0x3f, 0x79, 0x9b, 0xaf, 0xb3, 0x6c, 0xcf, 0xca, 0x45, 0xf4,
-	0xe5, 0xed, 0x59, 0xb9, 0xb4, 0xd5, 0x94, 0xd1, 0xe9, 0xef, 0x4a, 0xee,
-	0xf9, 0xb3, 0xf2, 0xd3, 0xbf, 0x16, 0x19, 0x00, 0xef, 0xcd, 0xee, 0xff,
-	0xaa, 0x64, 0x6d, 0xec, 0xb1, 0x7b, 0xbb, 0x92, 0x89, 0xd9, 0x4d, 0x3d,
-	0x4e, 0x02, 0x57, 0x2c, 0x23, 0xef, 0xbd, 0x00, 0x6c, 0x69, 0x34, 0x72,
-	0xa7, 0x45, 0x86, 0x4f, 0x57, 0x64, 0x38, 0x1d, 0x95, 0xc7, 0xec, 0x8a,
-	0xf4, 0xa5, 0xeb, 0xe4, 0xa8, 0x4d, 0xac, 0x39, 0x6e, 0x04, 0xb8, 0xfe,
-	0xed, 0xf2, 0x09, 0xdc, 0xb3, 0x4f, 0x64, 0x5a, 0xdd, 0xfb, 0xfd, 0xc5,
-	0x72, 0x54, 0xb2, 0x4e, 0x31, 0x61, 0x49, 0x9b, 0xe9, 0xd3, 0xf4, 0xcd,
-	0xe0, 0x19, 0x78, 0x35, 0x04, 0x2c, 0xf5, 0xed, 0xaf, 0x30, 0xb9, 0xee,
-	0x4a, 0x56, 0x75, 0x47, 0x29, 0x3b, 0xe8, 0x34, 0x79, 0x9d, 0x1c, 0x32,
-	0x32, 0x8e, 0xb4, 0x29, 0xbc, 0xe8, 0xc1, 0x98, 0x5e, 0x63, 0x7f, 0x99,
-	0x7a, 0x8e, 0xfb, 0x12, 0x69, 0xdd, 0x8c, 0xb1, 0x16, 0xae, 0x59, 0x4d,
-	0x73, 0x98, 0x4e, 0xce, 0x45, 0x3a, 0x79, 0x7d, 0x21, 0x44, 0xe7, 0x5f,
-	0x56, 0xef, 0xa7, 0x43, 0xf7, 0xc5, 0xf2, 0x0f, 0x1a, 0x7c, 0xfa, 0xc8,
-	0xcf, 0x5e, 0xe8, 0xe3, 0x37, 0xf4, 0x5a, 0xb8, 0x2f, 0x71, 0x8d, 0xb3,
-	0x15, 0x5f, 0xa7, 0x8a, 0xd7, 0x58, 0xeb, 0x62, 0x68, 0xad, 0x4b, 0xa1,
-	0xb5, 0x2e, 0x85, 0xd6, 0x2a, 0x82, 0xb7, 0xb2, 0xc1, 0x74, 0xa3, 0xc0,
-	0x27, 0xf6, 0x4c, 0x60, 0xce, 0x67, 0x21, 0x97, 0x9f, 0x60, 0x4c, 0x46,
-	0x16, 0x3d, 0xf0, 0xe3, 0x74, 0x54, 0xf6, 0xa9, 0x67, 0xbd, 0x9a, 0xae,
-	0xf0, 0xb3, 0x98, 0xec, 0x75, 0x78, 0x1f, 0x3c, 0xb3, 0xc0, 0x63, 0xb6,
-	0xff, 0xe1, 0x16, 0xbf, 0xcd, 0xfb, 0xf3, 0x9a, 0xfe, 0x87, 0xfc, 0xf7,
-	0xca, 0x1f, 0x28, 0x9c, 0x5c, 0x28, 0x13, 0xc7, 0x24, 0x1d, 0x71, 0xe5,
-	0x48, 0x5f, 0x1a, 0x76, 0x65, 0x1b, 0xe9, 0xd1, 0xae, 0x7a, 0xf2, 0x3c,
-	0x6b, 0xba, 0x8d, 0xc0, 0x0a, 0x49, 0x9a, 0xd0, 0xb3, 0x51, 0xb5, 0x97,
-	0x75, 0xa6, 0x4f, 0xb3, 0xcd, 0xf6, 0x80, 0xe9, 0x36, 0xd7, 0xf4, 0xd3,
-	0xde, 0x1b, 0x71, 0x4f, 0xdd, 0x7e, 0x4c, 0xcb, 0x37, 0x8e, 0x36, 0xf1,
-	0xb9, 0x5f, 0xb7, 0x83, 0xe7, 0x39, 0x6b, 0x79, 0xfb, 0xed, 0x2d, 0xcb,
-	0xdb, 0x01, 0x76, 0x84, 0xb1, 0x9d, 0x7b, 0x4d, 0x4a, 0xc4, 0xa5, 0xce,
-	0x45, 0x41, 0x6b, 0x1a, 0xb6, 0x58, 0xaf, 0x69, 0xb8, 0x5d, 0xd3, 0x00,
-	0x5a, 0x31, 0x6e, 0x54, 0xd9, 0x98, 0x12, 0x5f, 0x4d, 0x9b, 0xfc, 0x0e,
-	0xee, 0xd7, 0xab, 0xe7, 0xbe, 0x2d, 0x06, 0x57, 0x31, 0x76, 0x77, 0x52,
-	0xe6, 0x13, 0x90, 0x79, 0x5c, 0xe6, 0xa7, 0xc9, 0xb3, 0x54, 0xe2, 0x71,
-	0x41, 0xbb, 0x94, 0x90, 0xb3, 0x93, 0x92, 0x3d, 0x7c, 0xaa, 0x57, 0xfa,
-	0x60, 0x9f, 0x73, 0x93, 0x57, 0x2a, 0xe0, 0xdb, 0xbd, 0x75, 0xe2, 0x02,
-	0x83, 0xe1, 0xef, 0x7b, 0xa2, 0x12, 0xc9, 0x64, 0xa0, 0x0b, 0x69, 0xe5,
-	0x83, 0x97, 0xfe, 0x2c, 0xeb, 0xfe, 0x65, 0xed, 0x3a, 0xf8, 0x79, 0xcc,
-	0xdb, 0x93, 0x56, 0x7a, 0x13, 0xfe, 0xcb, 0x01, 0x57, 0x72, 0xe9, 0x8f,
-	0xa1, 0x5b, 0x01, 0x4d, 0x81, 0x6d, 0xd0, 0x07, 0x7d, 0x10, 0xf2, 0x6d,
-	0xad, 0xc0, 0x17, 0x07, 0xf2, 0x0b, 0xfc, 0x11, 0xfd, 0x44, 0x82, 0x58,
-	0x0e, 0x5b, 0xa0, 0x6f, 0x88, 0x8b, 0x39, 0x63, 0x69, 0xff, 0x11, 0xd3,
-	0xfe, 0x23, 0x0e, 0xdf, 0xc1, 0xb6, 0xad, 0xdb, 0x8e, 0x6e, 0x27, 0xd0,
-	0x46, 0xec, 0x31, 0x43, 0xbb, 0x7a, 0xeb, 0xf8, 0xc8, 0xb4, 0xf2, 0x49,
-	0xf4, 0x67, 0xf0, 0x14, 0xf4, 0x29, 0xf4, 0x2d, 0xd8, 0x6f, 0x09, 0xeb,
-	0x55, 0x31, 0x9c, 0xf2, 0x08, 0xd3, 0x43, 0x5a, 0xd6, 0x89, 0x09, 0x3f,
-	0x9b, 0x75, 0x48, 0xef, 0x77, 0x20, 0x0f, 0x62, 0x25, 0xe9, 0xbe, 0x15,
-	0xb4, 0x72, 0x3f, 0xff, 0x97, 0xb4, 0x72, 0xbd, 0x5a, 0x7a, 0x3f, 0x2d,
-	0x66, 0x2b, 0xec, 0xc0, 0x9e, 0x33, 0xc0, 0x66, 0x31, 0xf6, 0x77, 0x0e,
-	0x62, 0xcf, 0x03, 0xc0, 0xee, 0x7e, 0x60, 0xf7, 0x1e, 0x60, 0x77, 0x1f,
-	0xb0, 0x3b, 0x0b, 0xec, 0xee, 0x05, 0x6e, 0xf7, 0x00, 0xb7, 0xd3, 0xe0,
-	0x8d, 0x23, 0xb3, 0xc0, 0xf1, 0x59, 0xe8, 0xcb, 0x2c, 0xe6, 0x28, 0xcc,
-	0x88, 0xf1, 0x35, 0xec, 0xe1, 0xe8, 0x54, 0x6a, 0x16, 0xfa, 0x9d, 0x18,
-	0x32, 0xa1, 0x07, 0xe9, 0xbb, 0x61, 0x6f, 0x88, 0x9b, 0xca, 0x83, 0x32,
-	0x0c, 0xbf, 0xdf, 0xb6, 0xb5, 0x1d, 0xfa, 0x84, 0x68, 0x24, 0x11, 0xe8,
-	0x68, 0xbf, 0x14, 0xbc, 0x76, 0xbb, 0xcd, 0xec, 0x42, 0x5f, 0x2a, 0x89,
-	0x18, 0xd5, 0x38, 0x74, 0x3a, 0x65, 0x8c, 0x9c, 0x26, 0x0f, 0x26, 0x81,
-	0x83, 0x15, 0x19, 0x4f, 0x53, 0x4f, 0x2b, 0xf2, 0x5c, 0x3a, 0xd5, 0x5b,
-	0x94, 0x46, 0x39, 0xe9, 0x4c, 0x2a, 0xdf, 0x6f, 0x65, 0x4e, 0x29, 0x1f,
-	0x3a, 0xec, 0xe2, 0x5a, 0x6a, 0x33, 0x0a, 0xa7, 0xb9, 0xd7, 0x76, 0xfc,
-	0xa2, 0x58, 0xf7, 0x57, 0x90, 0x91, 0x25, 0x7d, 0x3d, 0x62, 0x1c, 0xee,
-	0x2c, 0x02, 0x39, 0x53, 0xf6, 0x22, 0x56, 0xcb, 0x4f, 0xb6, 0x27, 0xda,
-	0x4d, 0x4b, 0x86, 0x2c, 0x43, 0x46, 0x61, 0x5f, 0x7d, 0xe9, 0xff, 0xa9,
-	0x9c, 0x74, 0xf8, 0xbc, 0x5e, 0xfe, 0x5c, 0x61, 0x31, 0xd6, 0x9e, 0x9f,
-	0xc6, 0xba, 0x51, 0xf0, 0x9b, 0xeb, 0x72, 0x1e, 0xb4, 0x81, 0x8b, 0x96,
-	0x9b, 0x9a, 0x2d, 0xca, 0x2e, 0xd8, 0xe9, 0x06, 0xc9, 0x6d, 0xaf, 0x93,
-	0xec, 0x40, 0x52, 0x0a, 0x53, 0xbb, 0x80, 0x8d, 0x31, 0x65, 0xab, 0x85,
-	0xc1, 0xa4, 0x3c, 0x36, 0xc5, 0xbe, 0x2c, 0xf6, 0x9a, 0x3a, 0x95, 0x15,
-	0xee, 0xd5, 0x90, 0xec, 0xc1, 0xac, 0x3c, 0xe6, 0x65, 0x65, 0x04, 0xf2,
-	0x3a, 0x0b, 0x5e, 0x1e, 0xf2, 0x5c, 0x79, 0x0e, 0xbe, 0x26, 0x7f, 0x1a,
-	0x58, 0xeb, 0xae, 0x07, 0x2e, 0xa6, 0xce, 0x31, 0xc6, 0x37, 0x19, 0x87,
-	0x82, 0x97, 0x7f, 0x34, 0x45, 0x5e, 0x9a, 0x32, 0x7d, 0xaf, 0x01, 0x3c,
-	0x48, 0x82, 0x77, 0xae, 0xfc, 0xb1, 0x97, 0x3a, 0x9f, 0x35, 0x81, 0xc5,
-	0xe9, 0xde, 0x88, 0x34, 0x24, 0x30, 0xce, 0x1f, 0x93, 0x4f, 0x47, 0x20,
-	0xd7, 0x22, 0xc6, 0xa6, 0xd0, 0xcf, 0x77, 0x1d, 0xfc, 0xb2, 0x18, 0x07,
-	0x5d, 0xb5, 0x53, 0xe7, 0x67, 0x4d, 0x8e, 0x4f, 0x42, 0x3e, 0x36, 0xc6,
-	0x03, 0xf8, 0x6c, 0xde, 0xa7, 0x8d, 0x02, 0x69, 0xf0, 0xa8, 0x53, 0x88,
-	0x49, 0xcb, 0xc4, 0xd4, 0xf6, 0x73, 0xaf, 0x0b, 0xd7, 0xf9, 0x22, 0xc6,
-	0x7f, 0x88, 0x38, 0xdc, 0x96, 0x79, 0xc8, 0xe5, 0xa7, 0xe0, 0x55, 0x36,
-	0xe1, 0xb7, 0x0b, 0x33, 0xa9, 0x73, 0x8b, 0x26, 0xef, 0xdd, 0xe2, 0xa8,
-	0xd9, 0x23, 0xd2, 0x4c, 0x7e, 0xa5, 0xc1, 0x2b, 0xd7, 0x36, 0xcd, 0xb4,
-	0xf2, 0x65, 0xbe, 0x2d, 0xdf, 0x05, 0x9a, 0xa0, 0xf3, 0xdd, 0x61, 0x9b,
-	0xa0, 0xaf, 0x0d, 0x6c, 0x22, 0x95, 0x98, 0x35, 0xe1, 0x9f, 0xbb, 0x2d,
-	0x39, 0xa5, 0xda, 0xe0, 0xd1, 0x60, 0x2a, 0x91, 0x35, 0x11, 0x33, 0x95,
-	0xba, 0xe4, 0xac, 0xc7, 0xf1, 0x49, 0x85, 0x51, 0xfe, 0x78, 0xc4, 0x7a,
-	0x1e, 0xe3, 0xc5, 0x2e, 0xd0, 0xec, 0xdb, 0xc9, 0xdc, 0xa4, 0xa3, 0x9e,
-	0x9d, 0xf4, 0xfc, 0xb8, 0xd0, 0x44, 0xec, 0x38, 0x8b, 0xd8, 0x31, 0xaf,
-	0x6c, 0xc6, 0xce, 0x22, 0xd7, 0x80, 0xce, 0xfb, 0xf6, 0x32, 0x5f, 0xba,
-	0x4f, 0x86, 0xcf, 0x7c, 0x3f, 0x6e, 0x22, 0xce, 0x2a, 0x38, 0xa4, 0x8b,
-	0xe3, 0xcf, 0x81, 0x4e, 0xf2, 0x4e, 0x86, 0x18, 0x57, 0x21, 0x16, 0x7e,
-	0x84, 0x32, 0x1e, 0xed, 0x7e, 0x88, 0x7c, 0x2b, 0x82, 0xe8, 0x53, 0x3e,
-	0x8e, 0x49, 0x91, 0x71, 0xe8, 0x62, 0xe4, 0x09, 0x19, 0x9a, 0xa7, 0x2f,
-	0xc4, 0xcf, 0x23, 0x26, 0x02, 0xc7, 0x94, 0xcf, 0x6a, 0x87, 0x3e, 0x14,
-	0xc1, 0xef, 0x8d, 0x3a, 0x0e, 0x3b, 0x08, 0xf9, 0xf6, 0x43, 0xfe, 0x19,
-	0x19, 0x39, 0x33, 0x42, 0xdd, 0xee, 0x9a, 0x97, 0x54, 0xd7, 0x49, 0xd9,
-	0x66, 0xcf, 0xc1, 0x06, 0xb3, 0x83, 0x95, 0x5d, 0x66, 0x86, 0xef, 0x9c,
-	0xc0, 0x3b, 0xb8, 0xce, 0x8f, 0xc8, 0xd1, 0x32, 0xfb, 0x9e, 0x05, 0xdf,
-	0x11, 0x17, 0xf7, 0x1c, 0xd4, 0xf6, 0x80, 0xf9, 0xac, 0x60, 0xbe, 0x11,
-	0x3d, 0x1f, 0xc7, 0x71, 0x0c, 0xdf, 0x59, 0x9a, 0x77, 0x37, 0x7d, 0x22,
-	0x30, 0xa8, 0xc3, 0xac, 0xec, 0x8a, 0xe2, 0xf9, 0x73, 0x3d, 0xbc, 0xc7,
-	0x3c, 0xf0, 0x89, 0xb6, 0xdb, 0x8f, 0xb1, 0x83, 0x98, 0x73, 0x9d, 0xb4,
-	0xb5, 0x04, 0xf4, 0x52, 0x3f, 0x18, 0xab, 0xb0, 0x3d, 0xb2, 0xc9, 0x97,
-	0xd1, 0xab, 0x11, 0xdf, 0xc7, 0xcc, 0xa2, 0x4d, 0x3b, 0x3c, 0x26, 0x79,
-	0x2f, 0x85, 0x7d, 0x42, 0x06, 0xe5, 0x51, 0xbd, 0x47, 0xc8, 0x69, 0xe0,
-	0x29, 0xf0, 0x41, 0x8a, 0x3e, 0x6f, 0xc8, 0x17, 0xf2, 0xe4, 0x38, 0x6c,
-	0xe0, 0x71, 0x8c, 0x41, 0xbc, 0xab, 0x78, 0x60, 0x6f, 0xf2, 0xe3, 0xf5,
-	0x54, 0x31, 0xcb, 0xbc, 0xb3, 0x99, 0xba, 0x0d, 0xdc, 0x2a, 0x0f, 0xd8,
-	0x9c, 0x7b, 0xd6, 0x64, 0x7e, 0x92, 0x4a, 0x5e, 0x88, 0xec, 0x67, 0xbb,
-	0x6b, 0xd6, 0x84, 0x8c, 0x20, 0xc7, 0xdc, 0xf6, 0x76, 0x8d, 0x55, 0xef,
-	0x28, 0x5d, 0xa6, 0xde, 0x17, 0xbc, 0x6d, 0xf6, 0x43, 0x42, 0x5d, 0x76,
-	0xa0, 0x17, 0xc4, 0x0b, 0x5e, 0x2d, 0xf8, 0xee, 0x04, 0x74, 0x61, 0xbd,
-	0xa6, 0x9d, 0xf7, 0x96, 0xcc, 0xda, 0x58, 0xc3, 0xfb, 0x8f, 0x0d, 0x7e,
-	0x1f, 0xef, 0x19, 0x33, 0x05, 0x72, 0x0c, 0x68, 0xa5, 0x3c, 0x6b, 0x65,
-	0xf8, 0x24, 0x68, 0x67, 0x3f, 0xae, 0xf3, 0xc7, 0x60, 0xa7, 0xc0, 0x94,
-	0x9e, 0x8e, 0xc4, 0x45, 0x8c, 0xcf, 0x03, 0xf7, 0x8b, 0x16, 0x9f, 0x5d,
-	0x31, 0x96, 0xde, 0x31, 0x19, 0x27, 0x23, 0x1e, 0xbf, 0x60, 0x7c, 0x0d,
-	0xb1, 0x4e, 0x6e, 0xfe, 0x8a, 0x91, 0x87, 0x5e, 0xcc, 0x7b, 0x77, 0x43,
-	0x9f, 0x68, 0x57, 0x36, 0xd6, 0x4e, 0x25, 0xfe, 0xc9, 0x6c, 0x4f, 0xce,
-	0x01, 0x03, 0x0e, 0x81, 0xb1, 0xbe, 0x2c, 0x5d, 0x25, 0xdb, 0x45, 0x33,
-	0xaa, 0xf1, 0x8f, 0xed, 0x94, 0xfd, 0xb0, 0xc0, 0x58, 0x1a, 0xf6, 0x80,
-	0xcf, 0x7b, 0x64, 0xb8, 0x9c, 0x91, 0xc2, 0x99, 0x6d, 0xf6, 0x28, 0x72,
-	0xf5, 0x25, 0xda, 0x89, 0x75, 0x45, 0x60, 0x1d, 0xfc, 0xb7, 0x27, 0xc5,
-	0xba, 0x0c, 0x31, 0xaf, 0x03, 0xfa, 0x84, 0xbe, 0xd2, 0x92, 0x4e, 0xde,
-	0xbf, 0x62, 0x3f, 0xf4, 0xdb, 0xcb, 0xf7, 0x34, 0x2f, 0xd7, 0xde, 0xd3,
-	0xee, 0xea, 0x9e, 0x88, 0x31, 0xf0, 0x03, 0x1e, 0xfc, 0x00, 0x74, 0xfa,
-	0x75, 0x0f, 0x7e, 0xc0, 0x83, 0x1f, 0x80, 0x3d, 0xbe, 0x02, 0x7d, 0x7c,
-	0xd9, 0x83, 0x2f, 0xf0, 0xe0, 0x0b, 0x3c, 0xf8, 0x02, 0x2f, 0x07, 0xd9,
-	0x11, 0xef, 0xe9, 0x4b, 0x0e, 0x54, 0xfd, 0xa7, 0x1f, 0x83, 0xdd, 0xa2,
-	0xe3, 0x1a, 0xd8, 0xae, 0xbd, 0x59, 0x46, 0xbb, 0x98, 0x13, 0x35, 0xe0,
-	0xda, 0x88, 0x2b, 0x62, 0x98, 0xae, 0x2f, 0x69, 0xdb, 0x79, 0x1c, 0x74,
-	0x01, 0x17, 0xba, 0xbe, 0x08, 0xdd, 0x44, 0x1c, 0xe1, 0xfe, 0x86, 0x8e,
-	0x7f, 0x7e, 0x64, 0xf9, 0xba, 0xd9, 0x88, 0xbe, 0xfb, 0xd0, 0xd7, 0x88,
-	0x31, 0x47, 0x31, 0x86, 0xf1, 0x53, 0x93, 0xee, 0x0b, 0x8f, 0x63, 0x1c,
-	0xf5, 0x00, 0xd6, 0x4a, 0x61, 0x5c, 0x13, 0xe6, 0x6e, 0xc5, 0x98, 0x9d,
-	0x18, 0x73, 0x2b, 0xda, 0x8c, 0xb9, 0xb7, 0xa0, 0x7d, 0x4f, 0xcd, 0x3b,
-	0xb7, 0xa3, 0xef, 0x4b, 0x35, 0x7d, 0x8b, 0xe8, 0xeb, 0x41, 0xdf, 0x45,
-	0xfd, 0x5e, 0x11, 0xed, 0x96, 0x9a, 0x31, 0x97, 0xd1, 0x87, 0xb8, 0xd9,
-	0xfe, 0x7b, 0x5c, 0xfb, 0x71, 0x25, 0x4d, 0xc1, 0x33, 0xc6, 0xcd, 0xc8,
-	0x41, 0xab, 0xb1, 0xef, 0x5b, 0x8c, 0x0b, 0xe1, 0x7b, 0x7f, 0x6c, 0xf9,
-	0x71, 0xe3, 0x77, 0x6d, 0x5f, 0x57, 0x83, 0xf6, 0x8f, 0x6a, 0xda, 0x1c,
-	0xfb, 0xdf, 0x35, 0x7d, 0x3b, 0x36, 0x2e, 0x6f, 0xdf, 0x59, 0xb7, 0xf2,
-	0x9d, 0x89, 0x9a, 0x31, 0x2f, 0x37, 0x2f, 0x6f, 0xff, 0xe9, 0x2a, 0xef,
-	0xec, 0xd9, 0xb0, 0xbc, 0xef, 0xd1, 0x4d, 0x35, 0x63, 0xa0, 0x53, 0x0e,
-	0x72, 0xab, 0x60, 0xfc, 0x03, 0x37, 0xf9, 0xcf, 0xc9, 0xdf, 0x5a, 0x5d,
-	0x52, 0x5b, 0x47, 0xdb, 0x84, 0x1c, 0x2e, 0x18, 0xb0, 0x39, 0xdb, 0xcc,
-	0x5c, 0x32, 0xf2, 0xd0, 0xa9, 0x5c, 0x39, 0x98, 0x8f, 0xb6, 0x5c, 0x5b,
-	0xdb, 0x08, 0x6a, 0x1a, 0x8c, 0xbb, 0xe2, 0xd0, 0x9b, 0xfd, 0x90, 0x71,
-	0x6a, 0xa2, 0x28, 0x4b, 0x36, 0xdc, 0x66, 0xae, 0x65, 0xc3, 0x4f, 0x6b,
-	0xdc, 0x7a, 0x0a, 0x74, 0x56, 0x64, 0x20, 0x5d, 0x4f, 0xff, 0xa4, 0xf1,
-	0x8c, 0x58, 0x54, 0xa9, 0x44, 0xb6, 0x56, 0xe4, 0x48, 0xfa, 0xc3, 0x8a,
-	0x28, 0x1c, 0x9c, 0x50, 0x58, 0x94, 0x34, 0xdb, 0x21, 0x23, 0x1b, 0xb9,
-	0x8d, 0x23, 0x43, 0x0e, 0xfd, 0xd9, 0x31, 0xc6, 0x29, 0x27, 0x7c, 0x9c,
-	0x25, 0x16, 0xa1, 0x8d, 0xbc, 0xae, 0x70, 0xda, 0x50, 0x31, 0x70, 0x61,
-	0x9e, 0xd8, 0x4e, 0x3c, 0x85, 0xdf, 0xb6, 0x39, 0xef, 0x6a, 0x78, 0x19,
-	0x8b, 0x32, 0x3e, 0xb4, 0xdc, 0x17, 0xe0, 0x1b, 0xf9, 0x8c, 0x71, 0x04,
-	0xee, 0x4b, 0xaa, 0xae, 0x56, 0x5c, 0xbe, 0x97, 0xcd, 0xcc, 0x43, 0xae,
-	0x63, 0x7f, 0xab, 0x63, 0x54, 0xbb, 0x79, 0x6d, 0x7b, 0xde, 0x5b, 0xb5,
-	0xe7, 0x40, 0xdf, 0x56, 0xab, 0x59, 0xbc, 0xa3, 0xf8, 0xff, 0x52, 0x39,
-	0x75, 0xaa, 0x08, 0xfb, 0x59, 0x50, 0x39, 0x7a, 0x20, 0x0b, 0xc6, 0x3c,
-	0xa9, 0x67, 0x66, 0xe9, 0x2d, 0x54, 0x8e, 0xc2, 0xfc, 0xa4, 0x22, 0xbb,
-	0xd3, 0xff, 0xa6, 0xf6, 0x9e, 0x35, 0x3b, 0xeb, 0x18, 0x63, 0x2c, 0x78,
-	0xe4, 0x53, 0x1a, 0xcf, 0x11, 0xfb, 0xa7, 0x7f, 0x26, 0x79, 0x87, 0x7d,
-	0xbf, 0xac, 0xcc, 0x21, 0x36, 0x52, 0xf1, 0x92, 0x8a, 0x0f, 0x18, 0xef,
-	0x1d, 0x01, 0x8f, 0xc8, 0xc7, 0x01, 0xf0, 0x36, 0x88, 0x19, 0xfe, 0x91,
-	0xbe, 0x58, 0x96, 0xc7, 0xd1, 0xc8, 0xb4, 0x4a, 0x97, 0x30, 0xa7, 0x89,
-	0xf9, 0xe8, 0xe3, 0xe8, 0x47, 0xd8, 0x5f, 0x88, 0x32, 0xb6, 0xf3, 0x63,
-	0x83, 0x08, 0xd6, 0xb3, 0x80, 0x83, 0xef, 0x0a, 0x63, 0x9a, 0x61, 0x25,
-	0x03, 0x62, 0x29, 0x9f, 0xb1, 0x2f, 0xa6, 0x63, 0xef, 0xb8, 0x8e, 0xb5,
-	0x6d, 0x1d, 0x6b, 0x93, 0x0e, 0xd6, 0x2d, 0x83, 0x38, 0x82, 0x72, 0xba,
-	0x70, 0xdc, 0xdc, 0xca, 0x38, 0xa2, 0x49, 0x56, 0x8f, 0x23, 0x02, 0x9a,
-	0x76, 0x82, 0x26, 0xc6, 0x7d, 0xaa, 0x4e, 0xd5, 0xec, 0xd7, 0xc6, 0x48,
-	0x43, 0xe0, 0x27, 0x95, 0x3f, 0x9e, 0x80, 0xeb, 0xc3, 0xde, 0x10, 0x48,
-	0x02, 0xdb, 0x73, 0x93, 0x3b, 0xb5, 0xdf, 0x65, 0x0e, 0xc1, 0xf8, 0xdd,
-	0xd7, 0xd3, 0x5c, 0x7a, 0x34, 0x98, 0xa7, 0x05, 0x9e, 0x32, 0x54, 0x43,
-	0xe3, 0x5a, 0x8c, 0x7b, 0x82, 0x18, 0x68, 0x8f, 0x8e, 0x81, 0xfa, 0xe5,
-	0x88, 0xe7, 0xe7, 0x0c, 0x03, 0xa5, 0x01, 0xf4, 0x29, 0xda, 0x13, 0x8c,
-	0x35, 0x4d, 0x93, 0xb1, 0x66, 0x0a, 0xc9, 0x87, 0xbf, 0x97, 0xb6, 0xad,
-	0xac, 0x65, 0x06, 0x7b, 0x69, 0xbc, 0xb0, 0x7c, 0x2f, 0xbb, 0x94, 0xde,
-	0x9b, 0xe0, 0x9d, 0x8f, 0x4d, 0x9c, 0xf3, 0x7c, 0x94, 0xb8, 0x35, 0x50,
-	0x1a, 0x54, 0xf3, 0x8e, 0xaf, 0x98, 0x57, 0xb0, 0xc7, 0x03, 0x6b, 0x3c,
-	0xe3, 0xfe, 0x19, 0x5b, 0xd8, 0x7a, 0xff, 0x81, 0x0c, 0x2f, 0x63, 0xce,
-	0x2e, 0xa3, 0xa0, 0xe2, 0xb6, 0x83, 0x4a, 0x1e, 0x85, 0xd2, 0x10, 0xae,
-	0xb4, 0x17, 0x35, 0x8f, 0xb2, 0x99, 0x51, 0x25, 0x83, 0x11, 0xb5, 0xc7,
-	0xb9, 0xd2, 0x23, 0x88, 0xd7, 0xbe, 0x0e, 0x3f, 0x18, 0xae, 0x2b, 0x3a,
-	0x18, 0x43, 0x5e, 0x15, 0x43, 0x78, 0x4a, 0x9a, 0x59, 0x33, 0xbc, 0x82,
-	0x35, 0xb8, 0xe7, 0x38, 0xe4, 0x6f, 0xf8, 0xcf, 0xd5, 0xfa, 0x01, 0xcf,
-	0xeb, 0x42, 0xf4, 0x54, 0x10, 0xbf, 0x26, 0x40, 0x43, 0xf8, 0x9d, 0x63,
-	0xd2, 0xe7, 0x51, 0x56, 0xed, 0x89, 0x11, 0xe4, 0xbb, 0x05, 0x09, 0x62,
-	0x11, 0xae, 0x4f, 0x0c, 0xc8, 0x23, 0x97, 0x4a, 0x60, 0x7f, 0x01, 0x5f,
-	0x03, 0x9e, 0xc6, 0x2f, 0xd4, 0xea, 0xc7, 0x38, 0xe8, 0x19, 0xf6, 0xc8,
-	0xa7, 0x40, 0x6f, 0x83, 0xb5, 0x2f, 0xab, 0xfd, 0x8c, 0xa9, 0xda, 0xe7,
-	0xfa, 0xba, 0x40, 0x7f, 0x47, 0x11, 0xb7, 0xf8, 0xfa, 0xf8, 0x7b, 0x9a,
-	0x37, 0x81, 0xde, 0xc6, 0xb5, 0x0e, 0x30, 0x47, 0xa4, 0x5d, 0x05, 0x3a,
-	0xd2, 0x61, 0xef, 0x57, 0xbc, 0xe0, 0x33, 0x95, 0x13, 0x2a, 0x39, 0x0f,
-	0x55, 0xe5, 0xbc, 0xbe, 0x46, 0x67, 0x3b, 0x6d, 0xdf, 0x46, 0x69, 0x8b,
-	0xb0, 0x69, 0xd0, 0xf7, 0xd2, 0x32, 0xdb, 0xef, 0x5a, 0xa3, 0xae, 0x1c,
-	0x97, 0xc8, 0xcc, 0x0f, 0xc0, 0xcb, 0xdb, 0x91, 0xd7, 0x20, 0xcb, 0x9f,
-	0x22, 0x46, 0x31, 0xfe, 0x58, 0x8a, 0x89, 0xe7, 0x64, 0xb5, 0x78, 0xf8,
-	0x5a, 0xb1, 0xc7, 0x9d, 0xd7, 0x19, 0x7b, 0xfc, 0x49, 0x1d, 0xf3, 0x9c,
-	0x05, 0xd8, 0xe9, 0x21, 0xbc, 0x5f, 0xe7, 0xfe, 0x10, 0x3e, 0xed, 0xaf,
-	0xac, 0x7a, 0x37, 0xc0, 0x8b, 0xb8, 0x6c, 0x9c, 0xd9, 0xac, 0x30, 0xc3,
-	0x9e, 0x5a, 0xc2, 0x8c, 0x51, 0xcf, 0xd7, 0x5f, 0xf0, 0xca, 0xd9, 0x28,
-	0xd7, 0x9b, 0x77, 0x2f, 0xe5, 0x10, 0x43, 0xd5, 0x1c, 0xe2, 0x96, 0x1a,
-	0x3e, 0xae, 0x86, 0x99, 0xe7, 0x54, 0xbe, 0xfc, 0x6a, 0x39, 0xf5, 0x82,
-	0x48, 0x1f, 0xf2, 0xe4, 0xd4, 0x79, 0x91, 0x2c, 0x72, 0x65, 0xe6, 0x73,
-	0x7b, 0x90, 0x3b, 0xa7, 0x7e, 0x21, 0xd2, 0x8b, 0x9c, 0x99, 0xf9, 0x70,
-	0x3f, 0xf8, 0xda, 0x03, 0x4c, 0x4d, 0x03, 0x63, 0xb7, 0x83, 0xbf, 0x5d,
-	0x0a, 0x57, 0x0f, 0x9d, 0x46, 0xae, 0xad, 0xea, 0xec, 0xb4, 0x75, 0x07,
-	0x7e, 0xb5, 0x52, 0x79, 0x2c, 0xdd, 0x8e, 0x7c, 0x3f, 0x29, 0x5f, 0xb6,
-	0x98, 0xf3, 0x1a, 0x56, 0xae, 0x7b, 0x26, 0x12, 0x8e, 0x63, 0x0b, 0xd7,
-	0xf4, 0x11, 0x2b, 0x79, 0x3f, 0xac, 0xfc, 0xc4, 0x78, 0xe4, 0x6a, 0xbc,
-	0xdf, 0x5f, 0xe5, 0xfd, 0x9d, 0x0d, 0xd2, 0xd0, 0xaf, 0xea, 0x0b, 0xb9,
-	0xee, 0xaf, 0x13, 0xcb, 0xd2, 0xf0, 0xf3, 0xf0, 0xc7, 0x15, 0xb9, 0x3f,
-	0x7d, 0xa5, 0x72, 0xd1, 0xdd, 0x20, 0x85, 0xed, 0x07, 0x34, 0x9e, 0x1f,
-	0x78, 0x32, 0xe7, 0x16, 0x61, 0x1f, 0xfa, 0xdb, 0xc2, 0x64, 0x0c, 0x51,
-	0x29, 0xff, 0x9a, 0x65, 0xae, 0xf7, 0xf6, 0x7a, 0x69, 0xd8, 0xf6, 0x02,
-	0x8b, 0x63, 0xc4, 0x99, 0x39, 0x27, 0xae, 0xea, 0xdd, 0x37, 0xb9, 0xec,
-	0xb7, 0x21, 0xd3, 0xdf, 0x92, 0x39, 0xc4, 0x13, 0xf3, 0xbd, 0xa0, 0x71,
-	0x7b, 0x0b, 0xc6, 0xd3, 0xee, 0xc8, 0xf3, 0xdf, 0x96, 0xa1, 0x41, 0xf2,
-	0xd4, 0xc1, 0xf8, 0xfb, 0x31, 0xa6, 0x19, 0xd7, 0x07, 0x23, 0x73, 0x76,
-	0xcc, 0x6f, 0x0f, 0x70, 0x0e, 0xfa, 0x52, 0xce, 0xc3, 0xb5, 0x5a, 0x94,
-	0xcd, 0x2f, 0xcd, 0xcf, 0xb9, 0xf9, 0xec, 0xe3, 0xca, 0xbe, 0xee, 0xee,
-	0xd0, 0x1a, 0x4d, 0xa1, 0x35, 0x7a, 0x42, 0x6b, 0x90, 0xb6, 0xe6, 0x10,
-	0x6d, 0xcd, 0x78, 0xff, 0x3e, 0xac, 0xd7, 0xaf, 0xe3, 0x94, 0x60, 0x9d,
-	0x60, 0x1f, 0x2d, 0xa1, 0xb1, 0x1f, 0x62, 0x0d, 0xf6, 0x39, 0xa1, 0x3e,
-	0xae, 0x0b, 0x1c, 0x73, 0xd8, 0x6e, 0x0e, 0xd1, 0x42, 0xfa, 0x1a, 0xd0,
-	0xaf, 0xe6, 0x02, 0x3f, 0x1b, 0xe0, 0xbb, 0x4c, 0xf8, 0x8f, 0x08, 0xe2,
-	0xaa, 0x60, 0x4f, 0xc1, 0x1c, 0x0e, 0xde, 0xe3, 0x18, 0xff, 0xb9, 0xff,
-	0x0e, 0xfb, 0xf9, 0x3c, 0x22, 0xdf, 0x53, 0xf4, 0xb2, 0xcd, 0x3d, 0x34,
-	0x81, 0x56, 0x5e, 0x53, 0x32, 0xdb, 0x0c, 0xd9, 0x77, 0x33, 0x9f, 0x36,
-	0xe4, 0x36, 0xd7, 0x34, 0xf2, 0xdd, 0x94, 0xef, 0x06, 0x8d, 0x97, 0x0d,
-	0x46, 0xee, 0x34, 0x6b, 0x08, 0x8d, 0x3a, 0xf7, 0x43, 0xbe, 0xa1, 0x7c,
-	0x4c, 0xe0, 0x03, 0xe8, 0x63, 0x18, 0xab, 0xd0, 0x7f, 0x66, 0xf5, 0x3d,
-	0xae, 0xd0, 0xd3, 0xc3, 0xf3, 0xcd, 0x72, 0x51, 0xf1, 0xd0, 0x96, 0xc5,
-	0x2a, 0x0f, 0xa3, 0xfa, 0xbb, 0xd1, 0x31, 0xfd, 0x4d, 0x66, 0x3f, 0xe2,
-	0x01, 0xdc, 0x97, 0x80, 0xb9, 0xdd, 0xd0, 0xb7, 0x6e, 0xe6, 0x70, 0x45,
-	0x5c, 0x59, 0xc3, 0x30, 0x70, 0x75, 0x70, 0x8d, 0xe1, 0x0a, 0xbf, 0x04,
-	0xac, 0xc9, 0x77, 0xbf, 0x0d, 0x1d, 0x82, 0x6c, 0xca, 0xb6, 0x71, 0xbf,
-	0xe7, 0xd7, 0x87, 0x16, 0xdd, 0xd5, 0xeb, 0x43, 0x8b, 0xa2, 0xea, 0x43,
-	0x13, 0xd7, 0xa8, 0x0f, 0x65, 0xaf, 0xbf, 0x3e, 0x74, 0xa2, 0x9e, 0x18,
-	0xbc, 0xb7, 0x47, 0x8c, 0xdf, 0xd5, 0xf5, 0xa1, 0xf7, 0xc5, 0xaf, 0x0f,
-	0x5d, 0x94, 0xd5, 0xeb, 0x43, 0x13, 0x35, 0xf5, 0xa1, 0x8d, 0xaa, 0x3e,
-	0xc4, 0x79, 0xfc, 0xfa, 0x10, 0xdb, 0x6d, 0xdd, 0xbd, 0xa1, 0x3a, 0x08,
-	0xf0, 0x54, 0xe5, 0x84, 0xb6, 0x31, 0xe8, 0x05, 0x18, 0x45, 0x2c, 0xbf,
-	0xb9, 0xea, 0x8f, 0x96, 0xf0, 0xca, 0x50, 0xba, 0x75, 0x2d, 0xbc, 0x1a,
-	0xf4, 0x63, 0x90, 0x65, 0x58, 0x35, 0x5e, 0x8d, 0x53, 0x5e, 0xab, 0x67,
-	0xde, 0x3c, 0x56, 0x5a, 0x9a, 0x77, 0x0c, 0xb2, 0x1d, 0xaa, 0xd6, 0x50,
-	0xd6, 0x8a, 0x85, 0x1c, 0x39, 0xb6, 0xea, 0x37, 0xb8, 0x44, 0x76, 0xe5,
-	0x37, 0x38, 0x43, 0x1c, 0xd0, 0xd9, 0xd6, 0x5d, 0x50, 0x79, 0xd5, 0x9c,
-	0xf7, 0x55, 0xb9, 0xf0, 0xb0, 0x0d, 0x3c, 0x09, 0x6a, 0x26, 0x94, 0xe5,
-	0x92, 0x8f, 0x28, 0x98, 0x9f, 0x5f, 0xdd, 0xe4, 0xb0, 0xaa, 0x9b, 0xfc,
-	0xbc, 0x3e, 0x5c, 0x37, 0x59, 0x94, 0xab, 0xd7, 0x4d, 0x0e, 0xaf, 0x52,
-	0x37, 0x79, 0x53, 0x96, 0xea, 0x26, 0x6f, 0x4a, 0x50, 0x37, 0x89, 0xc8,
-	0x85, 0x4d, 0x9c, 0xe7, 0x08, 0xde, 0x19, 0xc0, 0xaf, 0x1f, 0x3f, 0xbf,
-	0x8e, 0xb2, 0x58, 0xa5, 0x7f, 0xb5, 0x3a, 0x4a, 0x7d, 0xec, 0x93, 0xd4,
-	0x51, 0x7c, 0x4c, 0x0f, 0xea, 0x28, 0x0d, 0x88, 0x5f, 0xe0, 0x43, 0xcc,
-	0x70, 0x1d, 0xa5, 0x15, 0xf3, 0xb2, 0x8f, 0x6d, 0xf6, 0xc3, 0x2e, 0xe0,
-	0x67, 0xb2, 0xaa, 0xce, 0xf1, 0x9b, 0x9a, 0x87, 0x07, 0xb0, 0xe7, 0x24,
-	0x64, 0x41, 0x3e, 0xb6, 0xab, 0x38, 0x32, 0x6b, 0x25, 0x8c, 0x5c, 0x27,
-	0xbc, 0xd3, 0x24, 0xbf, 0xd9, 0x27, 0x64, 0xa4, 0x4c, 0x1d, 0x6f, 0x45,
-	0xdc, 0x6d, 0xa1, 0xef, 0x00, 0xda, 0x41, 0x8c, 0xd4, 0x5d, 0x9d, 0x83,
-	0x76, 0x38, 0xc7, 0x7a, 0x9f, 0x73, 0x3d, 0x3e, 0x67, 0x27, 0x68, 0x0e,
-	0xef, 0xa3, 0x08, 0x7f, 0x83, 0x3e, 0x25, 0x73, 0xc6, 0x8a, 0x01, 0x2d,
-	0x49, 0xda, 0xf4, 0x75, 0xcc, 0xc7, 0xbe, 0x9d, 0x2a, 0xdf, 0x1a, 0xee,
-	0xe1, 0x5e, 0xe9, 0xbb, 0x16, 0x40, 0x1f, 0xfa, 0xe6, 0x99, 0xe3, 0xd1,
-	0x8f, 0x05, 0x39, 0x58, 0x5c, 0xe5, 0x60, 0x2d, 0x8a, 0x1f, 0xe4, 0xf5,
-	0x23, 0x31, 0xe2, 0x63, 0x8b, 0xcb, 0x3d, 0xf4, 0x6b, 0x5c, 0x63, 0xdb,
-	0xcf, 0xf5, 0x58, 0x8f, 0x6e, 0x71, 0x9f, 0x80, 0x5c, 0x59, 0xab, 0x09,
-	0xe4, 0xf7, 0x0d, 0xbd, 0xef, 0x5e, 0x29, 0xb6, 0x48, 0x6c, 0x23, 0xe8,
-	0x69, 0x9b, 0x62, 0x8c, 0x7d, 0x8f, 0xca, 0x37, 0x1c, 0x77, 0x6d, 0xbb,
-	0xdd, 0x7f, 0x03, 0x76, 0x3b, 0x70, 0x55, 0xbb, 0x3d, 0x1b, 0x0b, 0xdb,
-	0xed, 0xfe, 0x1b, 0xb0, 0xdb, 0x23, 0x37, 0x64, 0xb7, 0xdc, 0x1b, 0x31,
-	0x29, 0xa8, 0x8b, 0xad, 0x8c, 0x9b, 0x82, 0x75, 0x47, 0xb1, 0x66, 0x76,
-	0x8d, 0x35, 0x87, 0xd6, 0xac, 0xbb, 0xd6, 0xc6, 0x4c, 0xd7, 0x23, 0x6f,
-	0xe6, 0x21, 0xf4, 0xab, 0x71, 0xed, 0x83, 0x9e, 0xd6, 0x3a, 0x1f, 0xe4,
-	0xed, 0x61, 0xfb, 0xa1, 0x5e, 0x50, 0x17, 0x7e, 0x02, 0x7e, 0x51, 0x1f,
-	0x02, 0x9b, 0x6b, 0xaf, 0xd1, 0xc1, 0x05, 0xe4, 0xf3, 0xed, 0x5a, 0x07,
-	0x29, 0xeb, 0x4e, 0xf5, 0x3d, 0x69, 0xde, 0x7b, 0xc2, 0xcf, 0xe3, 0xa1,
-	0x03, 0x85, 0xf9, 0xc0, 0xd6, 0x92, 0x58, 0x37, 0x78, 0x46, 0x3e, 0xba,
-	0x88, 0x61, 0xb6, 0x21, 0xfe, 0x02, 0x8f, 0x54, 0xff, 0xf2, 0x3a, 0xf0,
-	0xd5, 0xf1, 0x4c, 0x8a, 0x51, 0x8c, 0x7d, 0xae, 0x07, 0x36, 0xde, 0x43,
-	0x8c, 0xca, 0x20, 0x8f, 0xa1, 0x1e, 0x52, 0x37, 0x3b, 0xba, 0x0e, 0x99,
-	0x8c, 0x91, 0x0e, 0xc2, 0xf6, 0x6c, 0xa5, 0xc7, 0xbb, 0xcb, 0x1d, 0xe7,
-	0x16, 0x4d, 0xae, 0x51, 0xa9, 0x14, 0x54, 0xbd, 0x5e, 0xcc, 0x5c, 0xf7,
-	0x4d, 0xeb, 0xe8, 0x97, 0x6e, 0x76, 0x23, 0x5a, 0xd7, 0xb2, 0xb8, 0xa7,
-	0xde, 0xfe, 0x2b, 0x7c, 0x3b, 0xf2, 0x89, 0xee, 0x7f, 0x41, 0x7f, 0x02,
-	0x36, 0x4f, 0x5f, 0xce, 0xfc, 0x62, 0x87, 0x1e, 0xd7, 0xae, 0xbe, 0x95,
-	0xaa, 0xef, 0x2d, 0x4e, 0xe0, 0x7f, 0x52, 0xf4, 0xcf, 0xcb, 0xe4, 0xcc,
-	0xb3, 0x1b, 0x79, 0x95, 0x9f, 0xf0, 0x7d, 0xa5, 0x93, 0xc8, 0x29, 0xac,
-	0x50, 0x9d, 0x3d, 0xa6, 0x73, 0x31, 0xda, 0x58, 0x5c, 0xe5, 0x89, 0x7e,
-	0xee, 0xc1, 0x5c, 0x75, 0xf9, 0x99, 0x8d, 0xd5, 0x75, 0x60, 0xf3, 0x27,
-	0xd0, 0x81, 0x5a, 0xf9, 0xc5, 0x60, 0xfb, 0x81, 0xfc, 0x82, 0x98, 0x65,
-	0x56, 0xef, 0xbb, 0xdd, 0x97, 0xe1, 0xff, 0x8b, 0x7d, 0x1a, 0xa1, 0x7d,
-	0x06, 0x78, 0x74, 0x58, 0xef, 0x73, 0x47, 0x0d, 0x1e, 0x0d, 0xd4, 0xd8,
-	0xec, 0xe7, 0x89, 0x47, 0x97, 0xd7, 0x7d, 0xfe, 0x78, 0xc4, 0x7d, 0x6d,
-	0x59, 0x15, 0x87, 0xfc, 0x7d, 0x3c, 0x2d, 0x66, 0xe6, 0xb3, 0xcc, 0xdf,
-	0x3e, 0x89, 0x7c, 0xc2, 0x38, 0x42, 0x99, 0x34, 0xa9, 0x78, 0xd5, 0xb7,
-	0x3d, 0xf8, 0xf2, 0xf9, 0xa8, 0xbc, 0xf7, 0x50, 0x4c, 0x7e, 0x75, 0x2f,
-	0xbf, 0x95, 0x59, 0xba, 0x7e, 0xc5, 0x76, 0xb4, 0xc1, 0xf7, 0x43, 0x48,
-	0x24, 0x94, 0xdf, 0xe1, 0x3b, 0x81, 0x3d, 0xdb, 0x78, 0xce, 0x67, 0x5b,
-	0xe4, 0x42, 0xf3, 0x8d, 0xe4, 0x74, 0x1d, 0xf6, 0xfb, 0xe6, 0x6a, 0x39,
-	0xdd, 0xd5, 0x6b, 0x7f, 0x4b, 0x39, 0x1d, 0x71, 0xb6, 0x59, 0xd7, 0x7b,
-	0x98, 0xd7, 0xec, 0xd7, 0xd8, 0xc9, 0x7b, 0xe4, 0xaa, 0x1e, 0xf2, 0x57,
-	0xc8, 0xf6, 0x35, 0xc4, 0x4b, 0xaf, 0x7a, 0xc8, 0x59, 0x3d, 0xe4, 0xaa,
-	0x1e, 0x72, 0x55, 0x0f, 0xb9, 0xaa, 0xd7, 0xa5, 0x73, 0xde, 0x01, 0x5d,
-	0xd7, 0xe7, 0xf7, 0x70, 0xd6, 0x0b, 0x8a, 0xf0, 0x25, 0xe3, 0x3c, 0x63,
-	0x61, 0xe6, 0xd2, 0xeb, 0x82, 0x73, 0x48, 0xba, 0xe6, 0xdd, 0xaa, 0x6b,
-	0x30, 0x75, 0x37, 0x29, 0xdf, 0x6c, 0xbe, 0xd1, 0xe0, 0x7f, 0x33, 0xe7,
-	0xf9, 0x8f, 0x3f, 0x44, 0x5c, 0xc2, 0x1a, 0xd8, 0x04, 0x6d, 0xb4, 0x62,
-	0x66, 0x58, 0x63, 0x11, 0xd3, 0xcc, 0x7c, 0x01, 0xef, 0x6c, 0xc3, 0x1e,
-	0xea, 0x69, 0xdb, 0x11, 0x33, 0xd3, 0x48, 0x9e, 0x1a, 0x66, 0x66, 0xbd,
-	0x9e, 0xeb, 0x6f, 0x1a, 0xfc, 0xd8, 0xaa, 0x93, 0x6d, 0xcb, 0x64, 0x9c,
-	0xa0, 0x62, 0xed, 0xa0, 0x7f, 0x4f, 0xf3, 0xf2, 0xb5, 0xa2, 0x0a, 0xdf,
-	0x73, 0xe9, 0x87, 0x31, 0x9f, 0x3a, 0xdb, 0x54, 0xe5, 0xb7, 0xb9, 0x26,
-	0xbf, 0xa3, 0x9a, 0xdf, 0x3e, 0x8f, 0x23, 0x1c, 0xa7, 0xea, 0xbe, 0xe4,
-	0x75, 0x30, 0x9f, 0xaa, 0xe1, 0x61, 0x1d, 0x75, 0x8e, 0x03, 0xd7, 0xbb,
-	0xa2, 0xd2, 0x34, 0x78, 0x20, 0xea, 0x86, 0xd7, 0x25, 0x46, 0xf5, 0x2e,
-	0xfb, 0xfe, 0xb4, 0xf6, 0x9a, 0xed, 0xea, 0xdb, 0x99, 0xef, 0x33, 0xa2,
-	0x4a, 0x07, 0x2d, 0x75, 0x36, 0xef, 0xd7, 0xea, 0xcc, 0x0d, 0xf5, 0x2f,
-	0x8f, 0x3c, 0x66, 0xbc, 0xa7, 0x23, 0x69, 0x99, 0x7f, 0xd1, 0xc0, 0x5a,
-	0x6b, 0x5f, 0x39, 0xc0, 0x3d, 0xae, 0x57, 0xeb, 0xc7, 0x59, 0x27, 0x0b,
-	0xf0, 0x4c, 0x36, 0xfb, 0xf5, 0xb3, 0x4f, 0x63, 0x4b, 0x0d, 0x35, 0xb6,
-	0x14, 0xec, 0xd3, 0xcf, 0x57, 0xf9, 0xdd, 0x7a, 0xb5, 0xb3, 0x13, 0x0b,
-	0xe5, 0xd0, 0xf7, 0x8f, 0xaa, 0x6e, 0xf0, 0x5c, 0xcb, 0x83, 0xd0, 0x41,
-	0xd6, 0xfe, 0xf7, 0xc0, 0x8e, 0x2a, 0x95, 0x3e, 0xd6, 0x93, 0xb7, 0x3f,
-	0xa0, 0xcf, 0x27, 0x3c, 0xa3, 0xea, 0x09, 0xd6, 0x8a, 0x7a, 0x42, 0x1f,
-	0x74, 0x05, 0x31, 0x00, 0x6c, 0xb0, 0xa0, 0x64, 0xc9, 0x78, 0xa0, 0xf6,
-	0xfb, 0xca, 0xf9, 0x46, 0x9f, 0x0f, 0xb7, 0x37, 0xfa, 0xdf, 0x18, 0x7e,
-	0xe9, 0x2c, 0x6f, 0xf3, 0xfd, 0x44, 0x63, 0x70, 0xce, 0x67, 0xf8, 0x4c,
-	0x1f, 0x74, 0xb1, 0x4e, 0xf2, 0x6a, 0x3e, 0xc4, 0xbb, 0xcf, 0xff, 0xac,
-	0x79, 0xf9, 0x78, 0xf4, 0x9d, 0x09, 0xc6, 0x37, 0xd7, 0x8c, 0x6f, 0xc6,
-	0xf8, 0x7f, 0xaf, 0x19, 0xdf, 0x1c, 0x1a, 0xef, 0xd4, 0x8c, 0x77, 0x30,
-	0xbe, 0x7e, 0xd3, 0xf2, 0xf1, 0x4e, 0x68, 0x7c, 0x4b, 0xcd, 0xf8, 0x16,
-	0x8c, 0x6f, 0xa8, 0x19, 0x8f, 0xbe, 0x33, 0x75, 0xfa, 0xbb, 0x17, 0x31,
-	0xf6, 0x88, 0xce, 0xbb, 0x71, 0x2d, 0xd5, 0x7e, 0x4b, 0xa1, 0xde, 0xb5,
-	0x42, 0x06, 0xc1, 0x39, 0x3b, 0xda, 0x6b, 0x16, 0xf6, 0xba, 0x14, 0xcb,
-	0xf8, 0xfa, 0x18, 0xd6, 0x45, 0xe2, 0x43, 0x51, 0x22, 0x2e, 0x74, 0x67,
-	0x1e, 0x3a, 0x34, 0x1f, 0xf8, 0x24, 0x9e, 0x99, 0x4a, 0x75, 0xf9, 0x7a,
-	0x6a, 0x48, 0xd4, 0x5d, 0xd0, 0x39, 0xd8, 0x4e, 0xd2, 0x0e, 0xbc, 0x0c,
-	0x30, 0x53, 0x4e, 0xf9, 0x76, 0x43, 0xfd, 0xe5, 0xfc, 0xda, 0x7e, 0xa8,
-	0xab, 0x7a, 0x9d, 0xbe, 0x15, 0xb8, 0x96, 0x5c, 0x51, 0xab, 0x8a, 0x5c,
-	0x07, 0xae, 0x0d, 0x54, 0x71, 0xed, 0x41, 0x99, 0xad, 0xe6, 0xdb, 0xfd,
-	0x72, 0xd4, 0xdb, 0xcb, 0xf3, 0x38, 0xa7, 0xb2, 0xf2, 0xd9, 0xe4, 0xdb,
-	0x7b, 0xab, 0x7e, 0x32, 0x35, 0x91, 0x95, 0x0b, 0xc7, 0x99, 0x43, 0x05,
-	0xb5, 0xd6, 0x71, 0xef, 0x5b, 0x94, 0x0b, 0x6c, 0xe3, 0x46, 0xf3, 0x6d,
-	0xce, 0xe7, 0xc8, 0x51, 0xff, 0x2c, 0x44, 0x75, 0xde, 0x62, 0x75, 0xde,
-	0x84, 0xb6, 0x37, 0xfa, 0xe0, 0x25, 0x7f, 0x99, 0x87, 0xbf, 0x1c, 0x42,
-	0xce, 0xbd, 0xe0, 0xad, 0x56, 0xef, 0xbc, 0x51, 0x7f, 0x59, 0x5b, 0x37,
-	0xae, 0xf5, 0x97, 0x5c, 0xa7, 0xb6, 0x56, 0x9c, 0xac, 0xc1, 0x7f, 0xea,
-	0xd3, 0x53, 0x3a, 0xa6, 0xc6, 0x75, 0xfe, 0x29, 0xd8, 0xa3, 0x29, 0x43,
-	0x4a, 0x7f, 0xd9, 0x0e, 0x72, 0xcb, 0x03, 0xd5, 0xdc, 0x72, 0x29, 0x1f,
-	0x44, 0xec, 0xda, 0x75, 0x9f, 0xc6, 0x47, 0xc6, 0xc8, 0xe3, 0xe8, 0x3f,
-	0x05, 0x1d, 0xe0, 0x33, 0xd6, 0x3f, 0xef, 0x90, 0x2f, 0x5b, 0xbe, 0x7f,
-	0xf2, 0xeb, 0x50, 0x07, 0x54, 0xfc, 0xcf, 0xfa, 0xff, 0x70, 0x7a, 0xa3,
-	0x8e, 0xf7, 0xae, 0x85, 0xab, 0xcb, 0x73, 0x53, 0xd3, 0x3c, 0x81, 0x77,
-	0x99, 0x9b, 0x3e, 0x10, 0x27, 0x86, 0xe6, 0xca, 0x57, 0x7d, 0xbf, 0x48,
-	0xff, 0x32, 0xac, 0xbe, 0xfb, 0xa9, 0x3c, 0x14, 0xe3, 0x16, 0xf4, 0xfb,
-	0x7e, 0x1e, 0x9a, 0x2b, 0x6f, 0x89, 0xfb, 0x38, 0x78, 0xb5, 0x9c, 0xe5,
-	0x58, 0x9c, 0xb5, 0xbc, 0x05, 0xef, 0x5a, 0xb4, 0xae, 0xcc, 0x7b, 0x23,
-	0x2b, 0xf2, 0xde, 0x41, 0x9d, 0xd7, 0x7e, 0x45, 0xe5, 0xbd, 0x3e, 0x8f,
-	0xb9, 0x97, 0x70, 0x1e, 0xe5, 0x02, 0x0b, 0xf9, 0x8d, 0x84, 0xf8, 0x30,
-	0xaa, 0xfc, 0x56, 0x61, 0xf2, 0x77, 0xd4, 0xf9, 0x89, 0x95, 0x7a, 0xf3,
-	0x79, 0xfb, 0x89, 0x60, 0xef, 0x4f, 0x89, 0x5f, 0xaf, 0xdb, 0x03, 0x5a,
-	0x98, 0x5b, 0x45, 0xb5, 0x3e, 0xa4, 0x34, 0x5e, 0x07, 0xe3, 0x82, 0x3c,
-	0xbe, 0xfa, 0x5d, 0xb5, 0x98, 0x5d, 0x56, 0x3f, 0xd9, 0x42, 0x18, 0x86,
-	0xdc, 0xb3, 0x37, 0xf0, 0x1d, 0xe2, 0xd3, 0x9c, 0x7f, 0xa8, 0xf5, 0x6b,
-	0xfc, 0x46, 0xda, 0xaa, 0xcf, 0xc7, 0xb9, 0xb0, 0x01, 0x9e, 0x65, 0x0e,
-	0xe3, 0xab, 0x3a, 0x03, 0x17, 0x73, 0x32, 0x62, 0xec, 0x23, 0x7d, 0xe9,
-	0x7f, 0xd6, 0xfb, 0x4c, 0xc8, 0x91, 0x29, 0xbf, 0xbe, 0x69, 0xae, 0x71,
-	0xfe, 0xcd, 0x34, 0xaf, 0xab, 0xbe, 0x79, 0x03, 0xe7, 0xdf, 0x5e, 0x8f,
-	0x07, 0xf5, 0xcd, 0xda, 0xf3, 0x6f, 0x91, 0xeb, 0x3c, 0xff, 0xe6, 0xd7,
-	0x37, 0x39, 0x4f, 0xb8, 0xbe, 0x79, 0x8f, 0x3a, 0x43, 0x36, 0x3a, 0xd5,
-	0xa3, 0xce, 0x23, 0xb7, 0x75, 0xaf, 0x8d, 0xb3, 0xfb, 0x3e, 0xb3, 0x7c,
-	0xe4, 0x3f, 0xe3, 0xe1, 0x7c, 0x64, 0xdf, 0xe7, 0x92, 0x8f, 0x70, 0x2f,
-	0xbf, 0xef, 0x7f, 0xb7, 0xad, 0x39, 0xfb, 0x95, 0xfb, 0x1c, 0x6b, 0x98,
-	0x47, 0x54, 0x0d, 0x73, 0xcb, 0xfa, 0x70, 0x0d, 0xd3, 0xbc, 0xc6, 0xd9,
-	0xaf, 0x23, 0xab, 0xd4, 0x30, 0xa3, 0xa1, 0xb3, 0x5f, 0x51, 0x7d, 0xf6,
-	0x6b, 0xa3, 0x8b, 0xbc, 0x51, 0xd7, 0x2c, 0xcd, 0xab, 0x9e, 0xfd, 0xea,
-	0x59, 0xff, 0x49, 0x6a, 0x96, 0xb9, 0x65, 0x35, 0xcb, 0x15, 0x67, 0xbf,
-	0xe0, 0xd7, 0x36, 0x4b, 0x32, 0x94, 0xe3, 0xe4, 0x6e, 0xf0, 0x6c, 0x43,
-	0xfe, 0x3a, 0xe2, 0x80, 0x7d, 0x55, 0x5b, 0xe5, 0xd9, 0xfd, 0x3a, 0xec,
-	0x39, 0x2a, 0x7b, 0x1d, 0xea, 0x27, 0xcf, 0x38, 0x76, 0xc2, 0x16, 0x70,
-	0x2d, 0xb3, 0xdd, 0x45, 0x19, 0x19, 0x03, 0x9d, 0xcb, 0xcf, 0x17, 0x2c,
-	0x9d, 0xd3, 0x8d, 0x55, 0xcf, 0xe9, 0x9e, 0x84, 0xde, 0x98, 0x53, 0x31,
-	0x99, 0x0b, 0xe9, 0xd4, 0x38, 0x62, 0x3b, 0x73, 0xc6, 0xd6, 0xcf, 0x93,
-	0x12, 0x99, 0x72, 0x80, 0x6f, 0x3c, 0xdb, 0xdb, 0x24, 0x91, 0x19, 0xff,
-	0x7b, 0xa3, 0xa9, 0xf0, 0x33, 0x81, 0x31, 0x3c, 0xdb, 0x19, 0x95, 0xa3,
-	0xaa, 0x3e, 0x11, 0xe8, 0xf2, 0x37, 0xc1, 0xe3, 0x4d, 0xd9, 0xa5, 0xb6,
-	0xb3, 0x8a, 0x8f, 0x47, 0xcc, 0x38, 0x45, 0x7d, 0xbe, 0x5b, 0xf2, 0xba,
-	0xf6, 0x33, 0x5c, 0xde, 0xa9, 0x73, 0x09, 0xf5, 0xcd, 0x06, 0xbc, 0x6c,
-	0xd3, 0xfe, 0x16, 0xd7, 0xf9, 0x36, 0xfa, 0x37, 0xc6, 0xcc, 0xd2, 0x37,
-	0xb9, 0x2d, 0x31, 0x02, 0x6c, 0x1b, 0x52, 0x6b, 0xde, 0x08, 0xcf, 0x8d,
-	0x15, 0xf1, 0xd7, 0x8d, 0xf1, 0x3d, 0x88, 0x85, 0xdf, 0xc4, 0xfe, 0xda,
-	0xa0, 0x1f, 0x8f, 0x4b, 0xfe, 0xcc, 0x1d, 0xd2, 0x37, 0x9d, 0x02, 0x3d,
-	0xbf, 0xae, 0x0c, 0xa7, 0x11, 0x37, 0x3f, 0xcf, 0x33, 0x60, 0xc0, 0x4b,
-	0xf0, 0xed, 0x95, 0x15, 0xdf, 0xa0, 0xc3, 0xe7, 0xc6, 0xba, 0xaa, 0xe7,
-	0x80, 0x5e, 0x2a, 0x4b, 0xac, 0x99, 0x34, 0x4f, 0x2d, 0x9d, 0x09, 0x5f,
-	0x28, 0xef, 0x56, 0x7e, 0xec, 0xc5, 0xf2, 0xff, 0x52, 0x77, 0x6d, 0xb1,
-	0x6d, 0x9d, 0xf7, 0xfd, 0xcf, 0x43, 0xea, 0x12, 0xdd, 0x7c, 0x24, 0xd3,
-	0x32, 0x2d, 0xd1, 0xf2, 0x39, 0xd2, 0xb1, 0xc5, 0xd8, 0x5a, 0xc7, 0x6a,
-	0xca, 0x26, 0xac, 0x5a, 0xc2, 0x52, 0xf4, 0x65, 0x59, 0x36, 0xd0, 0x97,
-	0x76, 0x1e, 0x16, 0xa0, 0x0e, 0x65, 0x3b, 0x1d, 0xd0, 0x07, 0xb7, 0xd9,
-	0x80, 0xa4, 0x03, 0x6c, 0x96, 0xb2, 0x1c, 0xaf, 0x53, 0x4d, 0x36, 0x66,
-	0xd5, 0xac, 0x1b, 0x50, 0x4e, 0x92, 0x9d, 0xb4, 0x50, 0xc0, 0x64, 0xbd,
-	0x60, 0xd8, 0x43, 0xad, 0xc9, 0xf6, 0xf6, 0xb2, 0x87, 0x6c, 0xd8, 0x83,
-	0x81, 0x0d, 0x98, 0x63, 0x05, 0x68, 0x96, 0x02, 0x49, 0x87, 0x15, 0x43,
-	0x1e, 0x36, 0x70, 0xff, 0xdf, 0x77, 0x21, 0x0f, 0x0f, 0x0f, 0x75, 0x89,
-	0x9d, 0x01, 0x33, 0x60, 0x88, 0xe7, 0x9c, 0xef, 0x9c, 0xf3, 0x7d, 0xff,
-	0xef, 0x7f, 0xbf, 0x9d, 0x3a, 0x3f, 0x8f, 0xd8, 0xc3, 0xdc, 0xca, 0x5b,
-	0x0c, 0x8b, 0xbb, 0x42, 0x96, 0xcd, 0xe5, 0x69, 0x28, 0x48, 0xd8, 0x0f,
-	0x0a, 0x30, 0x0c, 0x44, 0x6e, 0x86, 0x8c, 0xcd, 0x47, 0xc5, 0xbe, 0x4a,
-	0x5e, 0x71, 0xcc, 0x95, 0x5b, 0x51, 0xdb, 0x5b, 0x99, 0x73, 0x21, 0xf7,
-	0x42, 0xe6, 0x85, 0x00, 0x9e, 0xab, 0x17, 0x8f, 0x3b, 0x32, 0x2f, 0x64,
-	0x64, 0x01, 0xe7, 0xfa, 0x3d, 0x72, 0xae, 0x9d, 0x71, 0x00, 0x39, 0x44,
-	0xc8, 0x05, 0xc7, 0x9c, 0x85, 0x5f, 0xc3, 0x37, 0x2e, 0xbd, 0x3d, 0xff,
-	0xaa, 0x7c, 0xe7, 0xb0, 0x78, 0xe7, 0x2e, 0xc5, 0xb3, 0x74, 0x0e, 0x78,
-	0x3c, 0x30, 0x93, 0x1f, 0x8d, 0x04, 0x19, 0xbf, 0x67, 0xca, 0xb0, 0xa5,
-	0x9b, 0xe9, 0x6b, 0x1b, 0xc1, 0x33, 0xd1, 0x00, 0xcf, 0x7a, 0x9a, 0x60,
-	0xdb, 0xbb, 0xca, 0xbb, 0x25, 0xec, 0xe4, 0x79, 0xe4, 0xb7, 0xeb, 0xfc,
-	0x04, 0x09, 0xbb, 0x2a, 0x0d, 0x5d, 0x73, 0xe7, 0x26, 0xd4, 0x60, 0x77,
-	0xa6, 0x0a, 0xbb, 0xdd, 0xff, 0x8f, 0x60, 0x77, 0x4f, 0xe8, 0xba, 0x6f,
-	0x95, 0x91, 0x83, 0xa6, 0xe5, 0xbd, 0xae, 0x5d, 0x02, 0x1c, 0xc1, 0x4f,
-	0xed, 0xd2, 0x2a, 0x81, 0xa7, 0x22, 0x6f, 0xb8, 0x52, 0xf9, 0x41, 0xbc,
-	0xea, 0x93, 0x64, 0x1b, 0x04, 0xb6, 0x08, 0x7c, 0x77, 0xcd, 0x65, 0xe4,
-	0xf1, 0x8f, 0x25, 0x23, 0xa1, 0x17, 0x79, 0x6d, 0x91, 0x1f, 0xf5, 0xb8,
-	0x6d, 0x91, 0xe3, 0xdb, 0xb4, 0x45, 0x2e, 0x48, 0x5b, 0x24, 0xbb, 0x75,
-	0x5b, 0x64, 0xa0, 0x21, 0x5f, 0xab, 0xb6, 0x9e, 0xed, 0xdb, 0x22, 0xc6,
-	0x86, 0xb6, 0xc8, 0x88, 0xcb, 0xef, 0x82, 0xf9, 0xfe, 0x2e, 0x65, 0x4f,
-	0x80, 0xc7, 0x69, 0x38, 0x03, 0xc6, 0x27, 0x3c, 0x3e, 0xe0, 0x4f, 0x12,
-	0xd6, 0xe6, 0x8e, 0xff, 0x5b, 0x58, 0x0f, 0x36, 0xf8, 0xb7, 0x6b, 0xeb,
-	0xa1, 0xf0, 0xce, 0x6d, 0xe9, 0xec, 0x5e, 0x58, 0x0f, 0x36, 0xf5, 0x93,
-	0x36, 0xcf, 0x45, 0xac, 0xf7, 0x93, 0x0e, 0x1b, 0xcd, 0x78, 0xfb, 0x77,
-	0x5d, 0xfe, 0x53, 0x37, 0x7f, 0x07, 0x4d, 0x51, 0xe0, 0xf8, 0xa8, 0x7e,
-	0x17, 0x68, 0xc9, 0xce, 0x66, 0x09, 0xf6, 0x11, 0xde, 0x17, 0x11, 0xb4,
-	0xe6, 0xd1, 0xb7, 0xf8, 0x7d, 0xbc, 0xbe, 0xd7, 0x9e, 0x15, 0x72, 0x4a,
-	0xfa, 0x1a, 0x30, 0x3e, 0x16, 0x38, 0x2b, 0xc6, 0xca, 0xdc, 0x24, 0xe5,
-	0x7b, 0x50, 0x7a, 0x7e, 0x33, 0x9f, 0x43, 0xa3, 0xcc, 0xdb, 0x9e, 0x5d,
-	0xa0, 0x69, 0x7c, 0x1f, 0xef, 0x4b, 0xa4, 0xce, 0xae, 0x02, 0xff, 0xbc,
-	0xc0, 0x7a, 0xc1, 0x70, 0x55, 0x27, 0xa8, 0xdf, 0x9b, 0xcb, 0xc2, 0x7e,
-	0xd3, 0xbc, 0x33, 0x2d, 0xf2, 0xdd, 0x24, 0xef, 0x84, 0x9e, 0xa6, 0x79,
-	0xa7, 0x57, 0x0f, 0xde, 0xe7, 0x83, 0x17, 0xbe, 0x75, 0xa7, 0x7a, 0xef,
-	0x2c, 0xe4, 0x8f, 0xa7, 0x7c, 0xf7, 0xae, 0x5a, 0x77, 0x95, 0xad, 0x8d,
-	0x95, 0xf7, 0xa7, 0xc4, 0xba, 0xa2, 0x4f, 0x27, 0x51, 0x13, 0x57, 0xad,
-	0x09, 0xf2, 0xd6, 0x41, 0x41, 0x0e, 0x68, 0x3a, 0xd4, 0x75, 0xe2, 0x80,
-	0x45, 0xcc, 0xa7, 0x0e, 0xca, 0x2d, 0x4b, 0x70, 0x9f, 0x17, 0x16, 0x35,
-	0x39, 0x32, 0xa7, 0xe4, 0xc8, 0xa2, 0x8b, 0x8f, 0x37, 0xea, 0xed, 0x7d,
-	0x3e, 0x7a, 0xbb, 0xbb, 0xb6, 0x43, 0xd4, 0xb8, 0x35, 0xa9, 0xed, 0xf0,
-	0xab, 0x99, 0xc2, 0xd8, 0x17, 0x59, 0x5f, 0xf9, 0x14, 0xf4, 0x15, 0x13,
-	0x35, 0x4b, 0x52, 0x67, 0xc1, 0x75, 0x96, 0x49, 0xaf, 0x45, 0x18, 0xa7,
-	0x8e, 0xd1, 0x79, 0xd6, 0xc9, 0x6f, 0xd2, 0xe3, 0xca, 0x66, 0x4b, 0xb8,
-	0xf2, 0x4c, 0x91, 0xdf, 0x1f, 0xa0, 0xec, 0xb3, 0x76, 0x2c, 0x41, 0xc7,
-	0xe8, 0x9c, 0xc8, 0x99, 0x41, 0xcc, 0x0f, 0x79, 0x08, 0x07, 0xc5, 0x3c,
-	0xa5, 0x7f, 0xe3, 0x51, 0xe4, 0xcd, 0x6d, 0x3d, 0x67, 0x5f, 0xd7, 0xfa,
-	0x25, 0xc5, 0x3b, 0x97, 0x15, 0xed, 0x89, 0x73, 0x7c, 0xff, 0x8b, 0x46,
-	0xe3, 0xfd, 0x09, 0x23, 0x55, 0x4e, 0x19, 0xc9, 0x25, 0x8c, 0x7b, 0xd1,
-	0x98, 0x2e, 0xc3, 0xd6, 0xd4, 0xb8, 0x64, 0xc7, 0x41, 0x97, 0x6b, 0xb4,
-	0x79, 0x7c, 0x62, 0x91, 0x3c, 0xf5, 0x13, 0x5b, 0x98, 0xf7, 0x91, 0xba,
-	0x79, 0x6b, 0xf8, 0xe2, 0x37, 0x7c, 0x40, 0x09, 0x86, 0xa9, 0xd6, 0x7f,
-	0x3b, 0xe0, 0x73, 0x8f, 0x65, 0x69, 0x23, 0xfd, 0xd7, 0x6e, 0xd0, 0x7f,
-	0x17, 0x37, 0x9d, 0xf7, 0xc3, 0xf2, 0x02, 0x59, 0xc3, 0x1d, 0x74, 0x84,
-	0x9e, 0xcb, 0xf3, 0xae, 0xd3, 0x81, 0x3d, 0x38, 0x85, 0x31, 0xda, 0x37,
-	0xae, 0x7d, 0x63, 0x3d, 0x2a, 0x1f, 0x58, 0xe7, 0x2c, 0x74, 0x28, 0x3c,
-	0xc6, 0x75, 0xd8, 0x62, 0xab, 0x3c, 0x3f, 0xd8, 0x65, 0x4f, 0x8a, 0x39,
-	0xb2, 0x5d, 0x66, 0x4d, 0x93, 0xf4, 0x7f, 0x9f, 0x2d, 0xd7, 0xd5, 0x8f,
-	0xfa, 0xd4, 0x51, 0x0e, 0xfb, 0xd4, 0x51, 0xba, 0x69, 0x32, 0xe4, 0xa2,
-	0xc9, 0x88, 0x4b, 0xbf, 0x8b, 0xb2, 0x7d, 0xd3, 0xc5, 0xbc, 0x06, 0xf6,
-	0x4d, 0x07, 0x05, 0x5f, 0x71, 0xdb, 0x37, 0xde, 0xba, 0x7d, 0xd0, 0x27,
-	0x74, 0x38, 0x69, 0xeb, 0xa4, 0x8a, 0xd5, 0x9a, 0x7f, 0x5e, 0x77, 0xad,
-	0x66, 0x71, 0xa9, 0xa1, 0xbe, 0xd2, 0x6f, 0xbe, 0x43, 0x0d, 0xf3, 0x85,
-	0x9c, 0x4b, 0x34, 0xd5, 0xfd, 0xfc, 0xec, 0xaf, 0x47, 0x35, 0x3f, 0x2f,
-	0xdf, 0xc3, 0xbb, 0x86, 0x85, 0x1f, 0x3c, 0x5b, 0xe5, 0x79, 0x93, 0x72,
-	0xbe, 0xf9, 0x7a, 0x7b, 0x24, 0x78, 0x8d, 0x14, 0xec, 0xfc, 0x65, 0xc0,
-	0xf6, 0x7c, 0x6a, 0x9d, 0x1e, 0xf9, 0x3c, 0xd1, 0x2b, 0x7d, 0x65, 0x2d,
-	0x2a, 0xd7, 0x7a, 0x97, 0xb2, 0x0b, 0x37, 0xc3, 0x77, 0x9c, 0x6b, 0x51,
-	0xfe, 0x45, 0xdb, 0x2a, 0x11, 0xf0, 0xfc, 0xc4, 0xe9, 0x16, 0xc7, 0x54,
-	0xf1, 0x2d, 0xc4, 0xb0, 0x80, 0xf7, 0xfa, 0xf9, 0xb2, 0xd6, 0x6a, 0xf3,
-	0x3d, 0xb3, 0x1a, 0xf6, 0x4c, 0xe2, 0x15, 0x6c, 0x32, 0xe4, 0x10, 0x8f,
-	0x79, 0xf2, 0xb8, 0x1f, 0x06, 0x16, 0x3d, 0x3e, 0xb9, 0xcd, 0xc8, 0x4d,
-	0x6e, 0x36, 0xcf, 0xfb, 0x2e, 0xfd, 0x1d, 0xf3, 0xad, 0x54, 0xde, 0x8c,
-	0x0f, 0x48, 0x99, 0x5d, 0xf6, 0xd7, 0xa5, 0xcc, 0x2d, 0xcf, 0xcf, 0x2b,
-	0xa3, 0xf7, 0x6c, 0x51, 0x46, 0x8b, 0x7e, 0x28, 0x81, 0xc3, 0x82, 0x07,
-	0xa0, 0x06, 0x1b, 0x39, 0xd6, 0x9f, 0x06, 0xcd, 0x33, 0x9f, 0x75, 0xd5,
-	0xaa, 0xf9, 0xef, 0x63, 0x35, 0xce, 0x12, 0x42, 0x2f, 0x88, 0x09, 0xe4,
-	0x9b, 0xf4, 0x31, 0xef, 0xc1, 0xf8, 0xfd, 0xd6, 0x1d, 0xf8, 0x80, 0x95,
-	0x9f, 0x2a, 0xa5, 0xe4, 0xcb, 0xe1, 0x2d, 0xc4, 0x5b, 0xb6, 0xc7, 0xa7,
-	0x6d, 0x6b, 0x95, 0x10, 0x0b, 0x42, 0x4e, 0xf0, 0x0b, 0x3d, 0xd4, 0x73,
-	0xaa, 0xad, 0xcd, 0xb9, 0xdb, 0x2b, 0xe3, 0x53, 0xb8, 0xd6, 0x45, 0x37,
-	0x8a, 0xc8, 0xd7, 0xc6, 0xb5, 0xdf, 0xe3, 0x6b, 0x7e, 0x3c, 0x4a, 0xe7,
-	0x9b, 0x43, 0xe7, 0x93, 0xfb, 0x53, 0x22, 0xd8, 0x54, 0x15, 0xfa, 0xa7,
-	0xf8, 0xaf, 0xc8, 0x18, 0x47, 0xf9, 0x51, 0xc7, 0x6f, 0xfc, 0xfc, 0x8a,
-	0x46, 0xdf, 0xc7, 0xcd, 0x97, 0xfc, 0xf2, 0x96, 0xfc, 0x8a, 0xc8, 0xbb,
-	0xdf, 0x4a, 0x1c, 0x45, 0xc7, 0x8b, 0x27, 0x44, 0xed, 0xa9, 0x1b, 0x0f,
-	0x1e, 0x4d, 0xcc, 0x18, 0xf8, 0x30, 0xd4, 0xc0, 0xab, 0x1e, 0x3e, 0x06,
-	0xe0, 0x85, 0x6b, 0x87, 0xaf, 0x4f, 0xcb, 0x3f, 0x36, 0x8c, 0x3c, 0x00,
-	0xf8, 0xb3, 0x9f, 0xa2, 0xb3, 0xd7, 0x81, 0xc3, 0x06, 0x63, 0xdb, 0x08,
-	0xcd, 0x86, 0x51, 0x57, 0x24, 0x6a, 0x73, 0x54, 0x2c, 0x51, 0xd6, 0x0a,
-	0x9d, 0x15, 0x75, 0x8f, 0xfb, 0x23, 0xeb, 0x94, 0x66, 0xb9, 0x97, 0xa5,
-	0x73, 0x2c, 0x63, 0xcf, 0x2d, 0xd5, 0x74, 0xfc, 0xc6, 0xda, 0xc7, 0x7a,
-	0x1c, 0x5f, 0x17, 0x38, 0x1e, 0xdd, 0x10, 0xc7, 0x8f, 0x56, 0x71, 0x7c,
-	0xae, 0x4f, 0xe2, 0xf3, 0x45, 0x7e, 0x56, 0x0f, 0x1d, 0x16, 0xcf, 0xcd,
-	0xf2, 0xef, 0x4e, 0x3a, 0x2c, 0xfb, 0x62, 0xf0, 0xbb, 0x99, 0xc7, 0xe7,
-	0xb3, 0x74, 0xfe, 0x7a, 0x36, 0x90, 0x12, 0x35, 0x0a, 0xee, 0xbe, 0x1e,
-	0xfa, 0x7e, 0x8c, 0x6b, 0x86, 0xff, 0x9a, 0x2f, 0xc9, 0x9a, 0xab, 0x92,
-	0xe4, 0x4f, 0xf4, 0x76, 0x7c, 0xd0, 0x83, 0xff, 0xf5, 0x36, 0xe6, 0x05,
-	0x25, 0x03, 0x4f, 0x6c, 0xe0, 0xff, 0x68, 0xc4, 0xcb, 0x5e, 0x1f, 0xbd,
-	0xf9, 0x8d, 0x3e, 0x19, 0xbb, 0xda, 0xc8, 0xff, 0xe1, 0xc6, 0xd1, 0xba,
-	0x58, 0x3e, 0xf3, 0xfd, 0x84, 0xaa, 0xff, 0x7b, 0xa7, 0x4f, 0xca, 0x0b,
-	0xd4, 0x04, 0xa6, 0x19, 0x0e, 0x6f, 0xb2, 0xae, 0x32, 0x48, 0xad, 0xaf,
-	0xe8, 0xb5, 0x0e, 0x0a, 0x7e, 0xeb, 0xf6, 0xe7, 0x5c, 0x56, 0xb5, 0xe0,
-	0x39, 0xd7, 0x9a, 0x2e, 0x0b, 0x5b, 0xa8, 0x39, 0xbd, 0x35, 0xcf, 0xc3,
-	0x8a, 0x7a, 0x64, 0x82, 0x17, 0xdf, 0xd0, 0x2f, 0x05, 0xfb, 0x4b, 0x86,
-	0xd4, 0x83, 0x27, 0x59, 0xbf, 0xdd, 0x6e, 0x0c, 0xe9, 0x61, 0x75, 0x44,
-	0x6f, 0x4f, 0x0e, 0xef, 0x6f, 0xec, 0x83, 0xb4, 0x39, 0x32, 0xaf, 0x3d,
-	0x25, 0x78, 0xc1, 0xe5, 0xb1, 0x0a, 0x4d, 0xc7, 0xbb, 0x29, 0x33, 0xc6,
-	0xef, 0x9e, 0x44, 0x4f, 0xac, 0x20, 0x65, 0x99, 0x7e, 0x33, 0x63, 0x8f,
-	0x29, 0x7d, 0x51, 0xfb, 0xdd, 0xdb, 0x54, 0xee, 0xc3, 0x45, 0x11, 0xab,
-	0x94, 0xfd, 0x84, 0xf8, 0xf7, 0x92, 0x7e, 0xf6, 0x45, 0x11, 0x33, 0xcd,
-	0x5c, 0x6f, 0x55, 0xe3, 0x3a, 0x5d, 0xe3, 0x30, 0xa6, 0x53, 0x8d, 0xc5,
-	0x33, 0xb5, 0x4e, 0xd1, 0xae, 0xf8, 0x2d, 0xe8, 0x30, 0xad, 0x6a, 0xf5,
-	0x70, 0xfd, 0x02, 0xcd, 0x54, 0xd7, 0xd2, 0xc9, 0x63, 0xff, 0x5b, 0xf5,
-	0xf2, 0xe8, 0x64, 0x9d, 0x17, 0xf3, 0x6e, 0x9c, 0x13, 0xd6, 0x12, 0x14,
-	0x71, 0x24, 0xfe, 0xad, 0xde, 0x73, 0xa6, 0x3a, 0x27, 0xe4, 0x6d, 0xd8,
-	0x11, 0xf9, 0x2c, 0x3d, 0xae, 0xd3, 0x35, 0x4e, 0xf3, 0x0a, 0x1d, 0xa7,
-	0xf8, 0x57, 0x9e, 0xc7, 0x3f, 0xa8, 0xbc, 0x5e, 0x53, 0xc4, 0x54, 0x65,
-	0xde, 0x86, 0xfe, 0x0d, 0x3f, 0x34, 0xf2, 0x2c, 0x90, 0x3b, 0xe1, 0xe6,
-	0x37, 0x72, 0xbd, 0x21, 0xc8, 0xa2, 0x32, 0x62, 0xa9, 0x88, 0x6b, 0x34,
-	0xd3, 0x9d, 0xf7, 0x20, 0x5f, 0x7f, 0x1b, 0x3a, 0xe8, 0x56, 0xe8, 0xcf,
-	0xf2, 0xa1, 0x3f, 0xf7, 0xfb, 0x51, 0xeb, 0x86, 0x9a, 0xb7, 0x6c, 0xcc,
-	0xa0, 0x0a, 0xdb, 0x0a, 0x06, 0x95, 0xcc, 0x00, 0x9d, 0x77, 0xec, 0xf8,
-	0x12, 0xc9, 0x9a, 0xc9, 0xe9, 0x79, 0x3b, 0xb6, 0x4a, 0x87, 0xcc, 0x73,
-	0x24, 0x7b, 0x25, 0x94, 0x58, 0x06, 0x9f, 0xa1, 0x18, 0xdb, 0x47, 0x6c,
-	0x7f, 0x9e, 0x42, 0x5c, 0x46, 0xef, 0x0b, 0x6a, 0xe3, 0xf1, 0x37, 0xc6,
-	0x70, 0xba, 0xb9, 0x93, 0x3a, 0x12, 0xfc, 0xcc, 0x18, 0xf8, 0x13, 0x3f,
-	0x27, 0x4d, 0x49, 0xb6, 0x93, 0x60, 0xb3, 0x9e, 0x39, 0x65, 0x9b, 0x25,
-	0x32, 0x78, 0x2c, 0x6c, 0x57, 0x3c, 0x07, 0xf7, 0x27, 0xcc, 0x16, 0xf2,
-	0xd6, 0xe1, 0x5e, 0x14, 0x75, 0x8a, 0x6f, 0xc7, 0x0f, 0x92, 0xd1, 0x0f,
-	0x7e, 0x85, 0x7d, 0x1b, 0x55, 0xf1, 0xa4, 0x4b, 0xfc, 0xdb, 0x51, 0xbf,
-	0xbf, 0x2a, 0xea, 0xdd, 0xe4, 0x6f, 0xe0, 0xf6, 0x2f, 0xab, 0x3d, 0xab,
-	0xcb, 0x09, 0x89, 0x8c, 0x18, 0x5f, 0xa5, 0x0b, 0x4b, 0x1b, 0xf9, 0x66,
-	0xfc, 0xea, 0x5b, 0xbb, 0xb6, 0x58, 0xdf, 0xba, 0xbe, 0x53, 0xd6, 0x8c,
-	0xe1, 0xfd, 0x7e, 0xba, 0x97, 0x77, 0x6d, 0xee, 0x7a, 0xd5, 0xef, 0xd0,
-	0xb4, 0xac, 0x35, 0x56, 0xb8, 0x70, 0xbd, 0x89, 0x7f, 0xf3, 0x49, 0x21,
-	0x2f, 0xcf, 0xca, 0x38, 0xc3, 0x80, 0xec, 0x6d, 0x16, 0xa2, 0xe5, 0x6a,
-	0xed, 0x67, 0x50, 0xd5, 0x7f, 0x30, 0x53, 0x7c, 0xa4, 0x75, 0x9f, 0x3a,
-	0x57, 0x15, 0x71, 0xa7, 0xb4, 0x2b, 0x8f, 0x22, 0xa4, 0xf2, 0x24, 0x70,
-	0xdf, 0x48, 0x18, 0x75, 0x5b, 0xb2, 0xd6, 0x12, 0x63, 0x50, 0xe7, 0x08,
-	0x1b, 0x12, 0x75, 0xae, 0xf0, 0xfb, 0x35, 0xab, 0x05, 0xc5, 0x78, 0xf8,
-	0x9f, 0xb4, 0x5d, 0x78, 0x5a, 0xd0, 0x98, 0x7c, 0xa7, 0xac, 0xd9, 0x5c,
-	0x5c, 0x39, 0x23, 0xea, 0x24, 0x93, 0xaa, 0xf6, 0x33, 0x43, 0x5d, 0x42,
-	0x6f, 0xfa, 0xf8, 0x35, 0x9b, 0xe7, 0xc2, 0xdb, 0xaf, 0xd9, 0x74, 0xdf,
-	0xb3, 0xbd, 0x9a, 0x4d, 0x93, 0xd7, 0x6e, 0x2c, 0xc8, 0x9a, 0xcd, 0xfa,
-	0x58, 0x80, 0xf4, 0x43, 0x65, 0x5c, 0xf2, 0x48, 0xea, 0x7f, 0x5f, 0x72,
-	0xe5, 0x08, 0xcb, 0x7a, 0xcc, 0xc5, 0xaa, 0x0e, 0x24, 0xeb, 0x31, 0x65,
-	0x4e, 0xb1, 0xbb, 0x0f, 0x89, 0x8c, 0x39, 0xc8, 0xf7, 0x74, 0x7b, 0x62,
-	0x0e, 0x2d, 0x4c, 0xa3, 0xa3, 0xaa, 0xe6, 0xbc, 0x19, 0x6e, 0xd6, 0xd9,
-	0x2a, 0x4c, 0x73, 0x15, 0xfa, 0x69, 0xfc, 0xd3, 0x74, 0x3f, 0x1c, 0x51,
-	0xb9, 0x74, 0xc8, 0x9d, 0x3b, 0xa8, 0xe0, 0xa8, 0xf5, 0x0f, 0xf2, 0xd1,
-	0x3f, 0x7e, 0x5b, 0xe4, 0x10, 0x4b, 0xfd, 0x65, 0x50, 0xd1, 0x24, 0xe8,
-	0x36, 0xe2, 0xa2, 0xdb, 0x5d, 0x4d, 0xe8, 0x16, 0xf4, 0xf9, 0xdd, 0x1d,
-	0xb2, 0x4f, 0x01, 0xe2, 0xde, 0xdf, 0x57, 0xbf, 0x37, 0xa3, 0xbf, 0xf7,
-	0x78, 0x6f, 0x40, 0x83, 0x78, 0xc6, 0x87, 0xe1, 0x1a, 0x1d, 0xea, 0xdf,
-	0x98, 0xcb, 0x7e, 0xd7, 0x5c, 0x86, 0x5d, 0x73, 0xd9, 0xd7, 0x64, 0x2e,
-	0xac, 0x4f, 0x94, 0x2f, 0xf0, 0xff, 0x8f, 0x3b, 0x27, 0xe1, 0xab, 0x65,
-	0x5a, 0x8d, 0x0b, 0xf9, 0x9a, 0x03, 0x1c, 0x85, 0x9e, 0x32, 0xaa, 0xea,
-	0xe0, 0xdd, 0xf3, 0x6c, 0x66, 0xab, 0x41, 0x16, 0xa0, 0xd7, 0x41, 0x82,
-	0xef, 0xeb, 0x6c, 0xd2, 0xeb, 0x00, 0x3a, 0x86, 0x5f, 0xaf, 0x03, 0x37,
-	0x8f, 0x77, 0xeb, 0x52, 0xd0, 0x7d, 0x21, 0x03, 0xa1, 0xf3, 0xa2, 0x57,
-	0xc1, 0x2f, 0xd1, 0x85, 0xaa, 0x8e, 0x79, 0x90, 0xd2, 0x4a, 0xc7, 0xbc,
-	0xb0, 0xa4, 0xf7, 0x7c, 0xd8, 0xb3, 0xe7, 0x7e, 0x3a, 0xe7, 0x90, 0xca,
-	0xf1, 0xd1, 0xb0, 0xca, 0xba, 0x60, 0x95, 0xf5, 0x81, 0x95, 0x78, 0x47,
-	0x93, 0x79, 0x03, 0x3e, 0xb8, 0x07, 0xff, 0xbf, 0x13, 0x41, 0x8f, 0x16,
-	0xa2, 0xdf, 0xd8, 0x55, 0xf3, 0x0b, 0xe8, 0xdf, 0x98, 0x63, 0xd3, 0xdc,
-	0x4f, 0xa5, 0x0f, 0x0e, 0x06, 0x8e, 0x5c, 0x67, 0x03, 0x9d, 0x65, 0x5e,
-	0xbd, 0x2d, 0xa8, 0x75, 0x85, 0x03, 0x82, 0xef, 0xdd, 0x0f, 0x22, 0x77,
-	0x45, 0x9f, 0xeb, 0xd6, 0xbe, 0x5c, 0xb5, 0xfe, 0xd6, 0x3a, 0x7d, 0xa2,
-	0xa6, 0x4b, 0xe8, 0x1c, 0x54, 0xfd, 0x5b, 0xcb, 0xc0, 0x7b, 0x75, 0xfe,
-	0x89, 0x5b, 0x75, 0xfd, 0x06, 0xe1, 0x0b, 0xea, 0x4e, 0x1b, 0x4e, 0x4a,
-	0xe4, 0x91, 0xf6, 0x3a, 0xf0, 0x7b, 0x25, 0x99, 0x37, 0xf7, 0xa6, 0x91,
-	0xb3, 0xdc, 0x7b, 0xcd, 0xa2, 0x93, 0xf9, 0x2f, 0xed, 0x95, 0x74, 0x7a,
-	0x89, 0x86, 0xc7, 0x79, 0xfc, 0x14, 0x7c, 0xbd, 0x76, 0x2c, 0xc9, 0x4a,
-	0xe4, 0x5c, 0xb9, 0x8d, 0x16, 0x59, 0x5b, 0x0f, 0x3a, 0x25, 0xe1, 0xbb,
-	0x63, 0x99, 0x51, 0x40, 0x6f, 0x55, 0x63, 0xa1, 0x95, 0x9f, 0xdb, 0x4f,
-	0xcb, 0x45, 0xd0, 0x7c, 0x8b, 0xea, 0x11, 0x82, 0xb1, 0x01, 0xea, 0x73,
-	0xfe, 0x84, 0xe1, 0xf5, 0x05, 0x91, 0x47, 0xb9, 0x58, 0xb8, 0x24, 0xff,
-	0x96, 0x5e, 0x52, 0xef, 0xe0, 0xf7, 0x95, 0xff, 0x86, 0x12, 0x7d, 0x96,
-	0xcb, 0x36, 0x73, 0xff, 0xf3, 0xd7, 0x3f, 0x8e, 0x6f, 0x4b, 0xff, 0xc8,
-	0xa6, 0x6b, 0xfa, 0x87, 0xfb, 0xd9, 0x5a, 0x17, 0x39, 0xd6, 0x2f, 0xfb,
-	0x37, 0x00, 0x06, 0x9d, 0xd0, 0xad, 0xd2, 0x80, 0xa5, 0x31, 0x65, 0x47,
-	0x92, 0xc1, 0x49, 0x9a, 0x2d, 0x47, 0x8d, 0x4c, 0x01, 0x3a, 0x30, 0xff,
-	0x2d, 0x5d, 0xd9, 0x2d, 0x7d, 0x2e, 0xfa, 0x1e, 0xf0, 0xf5, 0x9d, 0x3c,
-	0xfe, 0x3f, 0xfa, 0x65, 0xee, 0xb5, 0xfb, 0x7c, 0x0f, 0x9f, 0x7f, 0x2e,
-	0x52, 0x7f, 0xfe, 0x31, 0x3e, 0xdf, 0xc7, 0xe7, 0xe1, 0x87, 0x84, 0x9f,
-	0x31, 0x46, 0x39, 0xde, 0x9f, 0xd9, 0x32, 0xf3, 0xa9, 0x57, 0x58, 0x5e,
-	0x2c, 0xe9, 0x71, 0xbb, 0x50, 0x97, 0x23, 0xf6, 0xc4, 0xe0, 0x31, 0x97,
-	0xf3, 0x63, 0x3c, 0x6e, 0x90, 0x82, 0xaf, 0x58, 0x34, 0xbb, 0xa4, 0x71,
-	0x52, 0xe7, 0xd4, 0xbf, 0xc3, 0xf0, 0x45, 0xde, 0xce, 0x47, 0xbb, 0x25,
-	0xfc, 0x62, 0xc2, 0x87, 0x89, 0x3c, 0x8e, 0x2b, 0x02, 0xf7, 0xec, 0x49,
-	0xab, 0xfa, 0x7e, 0xe0, 0x96, 0x88, 0x73, 0xf0, 0x1a, 0x58, 0x2e, 0x4d,
-	0x39, 0x66, 0xae, 0x9a, 0x8f, 0xf6, 0xe7, 0x03, 0xf2, 0xfe, 0xff, 0xda,
-	0x25, 0xfb, 0xa3, 0xbe, 0x3f, 0xa0, 0xfb, 0x24, 0x4a, 0x9d, 0x00, 0x39,
-	0xca, 0x01, 0x01, 0x9b, 0xe0, 0x02, 0xe4, 0x95, 0xc1, 0xbf, 0x79, 0x3d,
-	0x69, 0xcc, 0xb1, 0xad, 0x5f, 0xf7, 0x7c, 0x91, 0xeb, 0x3a, 0xc6, 0xf3,
-	0x4d, 0xf1, 0xba, 0xf4, 0xf9, 0x04, 0x1f, 0xfb, 0xed, 0x2f, 0x9e, 0xd5,
-	0x91, 0x46, 0x5d, 0x70, 0xe6, 0x54, 0x47, 0x3a, 0x13, 0x93, 0xfb, 0x5c,
-	0xf3, 0xd1, 0x46, 0xaa, 0x3e, 0xda, 0xb9, 0xfc, 0x78, 0x3f, 0xfc, 0x15,
-	0xc6, 0x35, 0xde, 0xef, 0xf0, 0x15, 0x1e, 0x8b, 0x7a, 0x84, 0x1c, 0xff,
-	0xed, 0x52, 0xf9, 0x3c, 0x8d, 0xb8, 0x22, 0xf3, 0x23, 0xb4, 0x5e, 0x81,
-	0x7b, 0x9f, 0xe0, 0x67, 0x48, 0xdd, 0xa2, 0xf9, 0x7b, 0xa8, 0x21, 0xff,
-	0xa5, 0x11, 0xc7, 0x36, 0xf2, 0xab, 0x8a, 0x38, 0xa2, 0x0f, 0x9e, 0x6d,
-	0xd4, 0x83, 0xe0, 0x9e, 0xf0, 0x8b, 0x4d, 0x37, 0xd0, 0x2b, 0xe8, 0x38,
-	0x44, 0x2f, 0xcc, 0x67, 0xe9, 0x31, 0xde, 0xab, 0x3f, 0x30, 0x3e, 0x83,
-	0x38, 0x3b, 0xc9, 0x5c, 0x27, 0x86, 0x71, 0xde, 0x89, 0x9d, 0x33, 0x52,
-	0xe0, 0x8b, 0x95, 0x90, 0xd3, 0x45, 0xad, 0x4c, 0xab, 0xbf, 0x49, 0x23,
-	0x6c, 0xcf, 0x81, 0x66, 0x9d, 0x48, 0x8a, 0x40, 0x6f, 0xb6, 0x79, 0x84,
-	0x71, 0x62, 0xba, 0x0c, 0x7c, 0x36, 0xe8, 0x8b, 0x45, 0xa2, 0xe7, 0x8b,
-	0x23, 0xe6, 0xf7, 0xc8, 0xb1, 0x6a, 0xd7, 0x6d, 0x33, 0xc9, 0xf3, 0x48,
-	0x95, 0x5f, 0xa2, 0xf7, 0x44, 0xdf, 0x12, 0xc0, 0x51, 0xef, 0xfb, 0x1f,
-	0xd1, 0x99, 0x34, 0xe6, 0xbd, 0x75, 0xfa, 0x3c, 0xb9, 0x2d, 0xfa, 0xec,
-	0xf0, 0xa1, 0xcf, 0x7f, 0x54, 0x78, 0x53, 0x61, 0x1c, 0xed, 0xa0, 0x99,
-	0x02, 0x72, 0xbf, 0x3e, 0x8b, 0xfe, 0x52, 0x85, 0x0c, 0xf3, 0xa5, 0x4c,
-	0x8d, 0x2f, 0x5d, 0x4d, 0x06, 0x13, 0xa0, 0x71, 0xf4, 0x65, 0x53, 0xf9,
-	0x3e, 0x58, 0xc7, 0x00, 0x8d, 0x2c, 0x74, 0x22, 0xf6, 0xb5, 0x9a, 0x9c,
-	0x48, 0xa8, 0xfa, 0x7c, 0xdb, 0x9a, 0x66, 0xfe, 0x38, 0xc7, 0xb4, 0x9c,
-	0x2b, 0x1c, 0xa4, 0xc5, 0x70, 0x94, 0x86, 0x17, 0x74, 0xbf, 0x12, 0x11,
-	0x37, 0x89, 0x4a, 0x9e, 0xa4, 0xd7, 0xfd, 0x84, 0xf0, 0x45, 0x58, 0x37,
-	0x3f, 0xa9, 0x75, 0x77, 0x6e, 0xc2, 0x97, 0xde, 0x57, 0x34, 0x5b, 0xb9,
-	0x95, 0x8c, 0x53, 0x36, 0x39, 0xf1, 0xef, 0x02, 0xff, 0x87, 0x6f, 0xc2,
-	0xaf, 0x06, 0x1e, 0x6d, 0x51, 0x3a, 0xef, 0x85, 0x45, 0x94, 0xd7, 0x8d,
-	0xeb, 0x95, 0x0f, 0x67, 0xe2, 0x2f, 0x09, 0xdd, 0x6b, 0xe4, 0x26, 0x8f,
-	0x13, 0xf2, 0x48, 0xf3, 0x0d, 0x3f, 0x3c, 0xd4, 0x3d, 0x29, 0x35, 0x2e,
-	0xca, 0x7c, 0x4e, 0x93, 0x9f, 0x9b, 0x0e, 0x7a, 0x71, 0xf2, 0x5e, 0xe0,
-	0xf8, 0xbc, 0x45, 0x27, 0xf2, 0xf6, 0xab, 0x59, 0x9a, 0x64, 0xba, 0x76,
-	0xcb, 0x0b, 0x1e, 0x4f, 0xc0, 0xb3, 0x29, 0xd0, 0x3e, 0x65, 0x0a, 0x96,
-	0xcc, 0xb7, 0x13, 0x3d, 0xe5, 0x70, 0x8c, 0xda, 0xe2, 0xee, 0xdd, 0x5a,
-	0x1e, 0x64, 0x0a, 0xa8, 0x15, 0xe4, 0xbf, 0x25, 0x1e, 0x8f, 0xfc, 0xfe,
-	0x22, 0x9e, 0x03, 0x19, 0x87, 0xb9, 0xf3, 0xf1, 0xb2, 0xdc, 0xd7, 0x61,
-	0x7e, 0xf6, 0xc8, 0x38, 0xbf, 0xb3, 0x3c, 0xc6, 0xfb, 0xdb, 0x23, 0x78,
-	0xb3, 0xdc, 0xcf, 0x29, 0xba, 0xec, 0xcb, 0x57, 0xe4, 0xbe, 0x64, 0x5c,
-	0xf4, 0x9d, 0x11, 0xf4, 0x3d, 0x25, 0xf6, 0x23, 0x53, 0x34, 0x58, 0x5f,
-	0xd6, 0xbe, 0x04, 0xb6, 0x9b, 0x8b, 0x21, 0xc5, 0x43, 0x70, 0xed, 0x89,
-	0xdd, 0x22, 0x1f, 0x11, 0xf6, 0x74, 0x11, 0x7f, 0xa7, 0xe8, 0x0a, 0xeb,
-	0xfd, 0x2f, 0xe7, 0xdb, 0xe8, 0x4e, 0xa1, 0x8d, 0xee, 0x16, 0xa2, 0x74,
-	0x7b, 0x7e, 0x07, 0x5d, 0x66, 0x9b, 0xe6, 0xb2, 0x13, 0xb2, 0x72, 0xb4,
-	0x03, 0xf1, 0x42, 0xe4, 0x0a, 0x31, 0xdd, 0x61, 0x3c, 0xf4, 0xef, 0xe4,
-	0x1e, 0xc6, 0x39, 0xb6, 0x8d, 0xda, 0xe9, 0x5d, 0x7e, 0x67, 0x2e, 0xaf,
-	0x73, 0x1c, 0xe0, 0x63, 0xdf, 0x5f, 0xb5, 0x1f, 0x36, 0xc7, 0x11, 0x73,
-	0x13, 0x1c, 0x99, 0x12, 0xbc, 0x7e, 0x76, 0x3e, 0x8a, 0xbe, 0xca, 0xd9,
-	0x16, 0xf8, 0x49, 0x99, 0x3f, 0x3f, 0x17, 0xc2, 0x78, 0x9c, 0x73, 0x64,
-	0x8e, 0xa4, 0x58, 0x5b, 0x84, 0x8f, 0x03, 0xa2, 0x0e, 0x5a, 0xc2, 0xa1,
-	0x9d, 0xd7, 0x17, 0x10, 0xe3, 0x33, 0xcb, 0xed, 0x74, 0xb6, 0x68, 0xf2,
-	0x71, 0x90, 0xf5, 0x44, 0x8c, 0xed, 0xdd, 0xa7, 0xfb, 0xcb, 0x5e, 0xe6,
-	0xb9, 0xe7, 0xc4, 0x38, 0xfe, 0xbb, 0xdc, 0x43, 0xb3, 0xc5, 0x2e, 0x75,
-	0x7c, 0x50, 0xe6, 0xf2, 0x8a, 0x5c, 0x6c, 0x5c, 0xdb, 0x88, 0xbf, 0xbd,
-	0xcd, 0x38, 0x05, 0x99, 0x2a, 0x75, 0x7c, 0xf0, 0x9a, 0x5b, 0x0d, 0xfd,
-	0x90, 0x81, 0x73, 0x93, 0xf4, 0x4d, 0x96, 0xb7, 0xc3, 0xaf, 0xc0, 0x1f,
-	0xfc, 0xfb, 0xc0, 0x9b, 0x52, 0x96, 0x06, 0xf9, 0x18, 0x7d, 0x8e, 0x82,
-	0xa2, 0x96, 0x69, 0x3a, 0x1c, 0x13, 0xf5, 0x1f, 0x92, 0x46, 0x4f, 0x89,
-	0x9e, 0x73, 0x3f, 0x12, 0xbc, 0xc9, 0xce, 0x5a, 0x06, 0xf4, 0x11, 0xf8,
-	0x54, 0x64, 0xee, 0xd5, 0x49, 0xa7, 0xf7, 0xed, 0x5d, 0x53, 0xa3, 0x94,
-	0xe8, 0x07, 0xde, 0x4b, 0x9a, 0x55, 0x3d, 0x04, 0x04, 0xbf, 0x37, 0x0f,
-	0xe8, 0x9a, 0x48, 0x7d, 0xac, 0x65, 0x85, 0x3e, 0xee, 0xf2, 0x5c, 0x37,
-	0x3d, 0xd7, 0xab, 0x79, 0x72, 0x2c, 0xf3, 0x58, 0xce, 0x93, 0xec, 0x39,
-	0x84, 0xbe, 0x71, 0xc0, 0x3f, 0xf3, 0xc0, 0x7e, 0xf3, 0x73, 0xca, 0x06,
-	0xca, 0xac, 0x8c, 0x44, 0x7a, 0x8d, 0x98, 0x91, 0x19, 0xfb, 0x97, 0x4a,
-	0x22, 0x0d, 0xbd, 0xe8, 0xc6, 0x6e, 0xc9, 0xe3, 0x30, 0xaf, 0x6c, 0x1c,
-	0xaa, 0xdb, 0xa9, 0x95, 0x2e, 0x5a, 0x15, 0x7d, 0xb5, 0xa0, 0x63, 0xe0,
-	0x7e, 0x3c, 0x27, 0x6b, 0xb6, 0xb0, 0x7d, 0x77, 0xc3, 0x01, 0x8d, 0x1f,
-	0x8a, 0xdc, 0xe4, 0xfd, 0x4c, 0xad, 0x7c, 0x54, 0x39, 0x23, 0xfa, 0xd2,
-	0x60, 0x6c, 0x0f, 0xcd, 0x08, 0x9b, 0x8b, 0xf5, 0x97, 0x3a, 0xbb, 0x76,
-	0x12, 0xf3, 0xcc, 0x22, 0x56, 0x62, 0x38, 0xdf, 0x0e, 0x64, 0x4a, 0x32,
-	0xf6, 0x9d, 0xf2, 0xc4, 0xbe, 0x4f, 0x89, 0xd8, 0x37, 0xe2, 0xde, 0x80,
-	0x2b, 0x60, 0xe9, 0x97, 0xcb, 0x82, 0x7d, 0x8c, 0xf3, 0x3e, 0x5a, 0x34,
-	0x77, 0x5d, 0xf0, 0x9b, 0xc9, 0xe9, 0x60, 0xa2, 0xb7, 0x85, 0xac, 0x40,
-	0xd2, 0xb1, 0xe3, 0x0f, 0x58, 0x87, 0xb8, 0x5d, 0xc0, 0x3c, 0x5f, 0xa2,
-	0xf5, 0x52, 0x0b, 0xd3, 0x89, 0xcd, 0x78, 0xb7, 0xca, 0x3a, 0xed, 0x2c,
-	0xbd, 0x5b, 0x22, 0xba, 0x5d, 0xbc, 0x8a, 0x5e, 0xbb, 0xb1, 0x07, 0x4c,
-	0x2b, 0x88, 0x05, 0x67, 0x62, 0xf0, 0xb1, 0xb1, 0x5e, 0x1b, 0x6b, 0x55,
-	0xb8, 0xd9, 0xc5, 0xb6, 0xa3, 0xc9, 0xff, 0x1d, 0xfe, 0x1f, 0x89, 0x00,
-	0x2e, 0x6b, 0xc5, 0x31, 0xc1, 0x4b, 0x97, 0xf8, 0xfc, 0x12, 0x9f, 0x87,
-	0x4c, 0x5d, 0x2b, 0x56, 0xde, 0x49, 0xc6, 0x13, 0x56, 0x72, 0xe2, 0xa4,
-	0x1c, 0xc3, 0x38, 0x77, 0xf9, 0x7a, 0x62, 0x4f, 0x88, 0xe7, 0x31, 0xc3,
-	0xf3, 0x58, 0x27, 0x99, 0xeb, 0x9d, 0x12, 0xef, 0x26, 0xba, 0x23, 0xde,
-	0xcb, 0x3a, 0x53, 0xfc, 0x71, 0x3a, 0x13, 0x96, 0xef, 0xcf, 0xc5, 0x51,
-	0x73, 0xd5, 0x49, 0xb3, 0x63, 0xa3, 0xaa, 0xe6, 0xea, 0xcd, 0x26, 0x35,
-	0x57, 0xed, 0xb4, 0x36, 0x0f, 0xbb, 0xb7, 0x9d, 0xe9, 0xdd, 0x14, 0xb9,
-	0x7a, 0x6b, 0xf3, 0xa2, 0x1f, 0x3e, 0xaf, 0xa7, 0xb2, 0x3e, 0xc3, 0xaa,
-	0x79, 0x26, 0xde, 0x2d, 0x74, 0xa7, 0xdb, 0xcb, 0xbf, 0xc5, 0xf3, 0x49,
-	0x58, 0x99, 0x09, 0xf7, 0x3a, 0xc4, 0x7c, 0xd7, 0xa7, 0xc5, 0xb8, 0xa0,
-	0x67, 0x5c, 0x82, 0x32, 0x13, 0x98, 0xbf, 0x18, 0xf3, 0x3f, 0xc9, 0xb8,
-	0x5e, 0x8f, 0xfb, 0x7e, 0x8b, 0x72, 0x42, 0xdf, 0xe7, 0xbf, 0x4b, 0x3d,
-	0x81, 0xf5, 0x02, 0xfc, 0x26, 0x06, 0xe3, 0x3f, 0xe6, 0x66, 0x51, 0x76,
-	0x89, 0xd7, 0x75, 0xbd, 0x2b, 0xf0, 0xa0, 0xf0, 0x93, 0x4a, 0xa6, 0x2e,
-	0xb7, 0xa5, 0xde, 0xbf, 0x2e, 0x6d, 0xae, 0x28, 0x39, 0xd7, 0x20, 0x4b,
-	0x21, 0x47, 0xb3, 0x95, 0xa0, 0x03, 0xbd, 0x0f, 0xb6, 0xd0, 0x25, 0xe6,
-	0x63, 0x32, 0x3f, 0x89, 0x79, 0x2a, 0xf3, 0x32, 0x49, 0x47, 0xa9, 0xba,
-	0xcf, 0x32, 0x48, 0x5c, 0x1e, 0xae, 0xe5, 0x45, 0xba, 0xe2, 0xe6, 0x21,
-	0x57, 0xdc, 0xdc, 0x74, 0xe5, 0x45, 0x86, 0x85, 0x9e, 0x56, 0xd3, 0xad,
-	0xc2, 0x4a, 0xb7, 0x8a, 0x8a, 0x9e, 0xf4, 0xe0, 0x71, 0x8b, 0x55, 0x1e,
-	0xb7, 0x73, 0x13, 0x1e, 0xe7, 0x67, 0x9b, 0xae, 0x2a, 0x7e, 0x62, 0xc7,
-	0x21, 0x6b, 0x6e, 0x31, 0xdf, 0xf8, 0x71, 0x79, 0x82, 0xf9, 0x49, 0x9c,
-	0xf9, 0xc9, 0x18, 0xf3, 0x93, 0x18, 0xf3, 0x13, 0x87, 0x61, 0x60, 0xf1,
-	0xda, 0xef, 0x05, 0x6e, 0xcf, 0x43, 0x8e, 0x4c, 0xd2, 0x95, 0x32, 0x78,
-	0xf3, 0x18, 0xeb, 0x42, 0xf7, 0x02, 0x6b, 0xf3, 0x3d, 0x8c, 0xc7, 0x52,
-	0xff, 0xa9, 0xb7, 0x6f, 0xec, 0x57, 0x51, 0x1f, 0x97, 0x8c, 0xaf, 0x81,
-	0xff, 0xbc, 0x99, 0xa5, 0xee, 0xc0, 0xed, 0x42, 0x57, 0x60, 0xad, 0xf0,
-	0x13, 0xf4, 0xa5, 0x78, 0x1d, 0x34, 0x8e, 0xbe, 0xbf, 0x3f, 0x1c, 0x9d,
-	0xe4, 0xb9, 0x77, 0x07, 0x66, 0x79, 0x5f, 0xbe, 0x12, 0x4f, 0xf4, 0xf6,
-	0x49, 0x5a, 0xc8, 0xe6, 0xc0, 0x3d, 0x17, 0x76, 0xd0, 0xfe, 0xf1, 0xe4,
-	0x9e, 0x5e, 0xa6, 0x5b, 0xe0, 0x7b, 0xad, 0xef, 0x4e, 0x90, 0xf1, 0xb0,
-	0x43, 0xf5, 0xeb, 0xb1, 0x58, 0x5e, 0x7e, 0xc8, 0xf7, 0x7f, 0x10, 0xc8,
-	0x15, 0x5e, 0xe3, 0x67, 0xe3, 0xf8, 0x4f, 0xe1, 0xdf, 0x64, 0x7b, 0x01,
-	0xbd, 0x7e, 0x3a, 0x79, 0x0c, 0xc6, 0xe2, 0xd8, 0x8e, 0x31, 0x6f, 0x8b,
-	0xaf, 0x1a, 0xf6, 0x64, 0xc2, 0x78, 0x3e, 0x8a, 0x9e, 0xf1, 0x3f, 0x2c,
-	0x3f, 0x15, 0x95, 0x31, 0xb6, 0xe7, 0xf6, 0x48, 0x3e, 0xc2, 0xb8, 0x19,
-	0x4e, 0x08, 0x9b, 0xad, 0xe5, 0x9a, 0x94, 0x9b, 0x8b, 0xbc, 0xbf, 0x4b,
-	0xf1, 0x18, 0xef, 0x6f, 0x97, 0x92, 0x99, 0x59, 0xbe, 0x2e, 0xe4, 0x31,
-	0xcb, 0x4e, 0x86, 0x77, 0x91, 0x4c, 0xd1, 0x03, 0xe2, 0x14, 0xfa, 0xea,
-	0x3c, 0x83, 0xe7, 0x31, 0xb6, 0x82, 0x6f, 0x7c, 0x18, 0xc8, 0x14, 0xf0,
-	0x5e, 0xe0, 0x1f, 0xff, 0x2e, 0x4d, 0xd2, 0xd5, 0xbc, 0x9e, 0xc3, 0x80,
-	0x61, 0x7c, 0x13, 0xf3, 0x08, 0xd0, 0x4e, 0xe7, 0xdf, 0x18, 0x4e, 0x7c,
-	0xfc, 0x97, 0xde, 0x39, 0x9d, 0x57, 0x73, 0x42, 0x9f, 0xca, 0x36, 0x5e,
-	0xc3, 0x4e, 0x42, 0xff, 0xa2, 0x45, 0xd1, 0x47, 0xb2, 0x55, 0xd8, 0xaa,
-	0x8b, 0xc2, 0xe6, 0x38, 0xba, 0xa7, 0xd6, 0xdb, 0xf2, 0x71, 0xcf, 0xb9,
-	0x9f, 0x07, 0x72, 0xf3, 0x87, 0x85, 0x6e, 0x36, 0x3c, 0xbe, 0x47, 0xd5,
-	0x9c, 0x7e, 0x5e, 0x5c, 0x33, 0x16, 0x70, 0xed, 0x49, 0x75, 0xed, 0xd7,
-	0x84, 0x4e, 0x8c, 0xfc, 0xb8, 0xd0, 0x35, 0x81, 0xdf, 0xbc, 0xaf, 0x4e,
-	0x8c, 0xf1, 0x3b, 0xb2, 0x04, 0xdf, 0xbc, 0x80, 0xa7, 0x86, 0x07, 0x60,
-	0x01, 0x9c, 0xef, 0x52, 0xf8, 0x6e, 0x5b, 0xa9, 0xa0, 0x5e, 0x77, 0x33,
-	0x38, 0xb3, 0x8e, 0x93, 0xc7, 0x5a, 0xb1, 0xa6, 0xdd, 0x81, 0x44, 0xc9,
-	0x32, 0x72, 0xf3, 0xb0, 0x71, 0xe0, 0x7f, 0xdc, 0x8b, 0xbc, 0x28, 0x9e,
-	0xc3, 0x6e, 0x4a, 0xa4, 0x31, 0x2f, 0x8c, 0xd3, 0x30, 0x18, 0xf7, 0xc0,
-	0xc2, 0x7d, 0xdf, 0x0e, 0x75, 0x5f, 0xbb, 0xd8, 0x0b, 0x32, 0xf0, 0x1e,
-	0xfd, 0x6e, 0xbc, 0x17, 0xef, 0xc7, 0x7d, 0x78, 0x9e, 0x7c, 0xee, 0x2e,
-	0xe6, 0xd7, 0xc9, 0x09, 0xf9, 0x2c, 0xe3, 0xa6, 0xbc, 0xb6, 0xcb, 0xf1,
-	0x9f, 0xaf, 0xdc, 0x3f, 0xdc, 0xab, 0xf7, 0x6f, 0x07, 0x95, 0x84, 0x5f,
-	0x09, 0xd7, 0xba, 0xc5, 0xb5, 0xa4, 0xd3, 0x2d, 0xf6, 0x75, 0x8e, 0x8f,
-	0xcf, 0x16, 0x7a, 0x02, 0xb0, 0xd5, 0x73, 0xe9, 0xee, 0x40, 0xa9, 0x84,
-	0xf5, 0x76, 0x07, 0x52, 0x8c, 0xf3, 0xd3, 0x85, 0x23, 0x95, 0x59, 0xc1,
-	0x5b, 0x58, 0xc7, 0xed, 0xb3, 0xcd, 0x33, 0xc6, 0xcf, 0xc4, 0x9a, 0xf8,
-	0x7d, 0xfc, 0x9b, 0xe9, 0x2e, 0xcf, 0x74, 0x97, 0x67, 0xba, 0xcb, 0x33,
-	0xdd, 0xb1, 0x8d, 0xfa, 0x83, 0x3c, 0xd3, 0x1d, 0xcb, 0x90, 0xb7, 0x58,
-	0x86, 0x48, 0x5a, 0x4d, 0x28, 0xdf, 0x9e, 0xa6, 0x55, 0x6f, 0x4d, 0xa6,
-	0xa6, 0x4d, 0xc8, 0x6d, 0x0a, 0x1c, 0x1d, 0xad, 0xa7, 0xd1, 0x3b, 0x4c,
-	0xa3, 0x2d, 0x53, 0xfd, 0xf4, 0xa0, 0x88, 0x3d, 0xb3, 0xad, 0x39, 0xe6,
-	0xd1, 0xa9, 0x20, 0x74, 0xac, 0x10, 0xd3, 0x13, 0x74, 0x4c, 0x9b, 0xe1,
-	0xde, 0x4f, 0xeb, 0xc5, 0x76, 0x1e, 0x03, 0x9a, 0xdd, 0xab, 0x8e, 0xf3,
-	0x4c, 0xb3, 0x90, 0x7b, 0xd7, 0x02, 0x77, 0x0a, 0x06, 0xeb, 0x62, 0x21,
-	0x33, 0x43, 0xe0, 0x9f, 0x42, 0x3f, 0xe3, 0x7d, 0x5f, 0x65, 0x7e, 0x0f,
-	0xdf, 0x29, 0x7a, 0x77, 0x95, 0x20, 0x3b, 0x22, 0xb7, 0x99, 0x7f, 0x5e,
-	0x28, 0x5e, 0x63, 0x3a, 0xef, 0xa3, 0x2f, 0x17, 0x21, 0x9f, 0x01, 0x23,
-	0x3e, 0x2e, 0x91, 0xf0, 0x7d, 0x19, 0x53, 0x58, 0xfb, 0xfe, 0xac, 0x21,
-	0xf0, 0xe4, 0xaf, 0x01, 0x07, 0x86, 0xfd, 0xdd, 0x3d, 0xe8, 0x69, 0x9f,
-	0x30, 0x5a, 0x95, 0x8f, 0x17, 0xbf, 0x31, 0x1e, 0x63, 0x01, 0x37, 0x1c,
-	0x37, 0x8b, 0x2f, 0xe2, 0x1b, 0x11, 0x71, 0x86, 0x87, 0x97, 0x5f, 0x5d,
-	0xe5, 0xfb, 0x05, 0xbc, 0x26, 0x93, 0x41, 0xd4, 0x87, 0xd3, 0xd7, 0x82,
-	0x53, 0x93, 0xf4, 0x72, 0x19, 0xf3, 0xbe, 0x42, 0xb3, 0x61, 0xf0, 0x1f,
-	0x3b, 0x7e, 0x9f, 0x24, 0xec, 0xda, 0x59, 0xdf, 0xfc, 0xa2, 0x3f, 0x4f,
-	0xb3, 0x92, 0x42, 0x3f, 0x6e, 0x63, 0x7b, 0x07, 0xb0, 0x79, 0x83, 0x71,
-	0x2d, 0x0e, 0x1f, 0x80, 0xe2, 0x67, 0xdf, 0x67, 0x9e, 0x83, 0x3d, 0xc3,
-	0x71, 0x3d, 0x0f, 0x5b, 0x53, 0x3c, 0xcc, 0x71, 0xf1, 0xb0, 0x5c, 0x95,
-	0x87, 0x31, 0x2e, 0x08, 0xde, 0x05, 0xde, 0x74, 0x82, 0xf5, 0x45, 0xf9,
-	0x1b, 0x7a, 0xe0, 0x4e, 0xc1, 0xab, 0x98, 0xb7, 0xb3, 0xfd, 0xb0, 0x58,
-	0xce, 0x06, 0x8e, 0x08, 0x9e, 0xa1, 0xf1, 0xf9, 0xa9, 0x01, 0x49, 0x07,
-	0xed, 0xd2, 0x1f, 0x79, 0x0a, 0x7c, 0xca, 0x6f, 0xfc, 0x67, 0x78, 0x1c,
-	0xc6, 0x3b, 0x91, 0xd7, 0x99, 0x7f, 0x2d, 0xc6, 0x63, 0x22, 0x06, 0x22,
-	0x6d, 0x9c, 0x2c, 0xdb, 0x01, 0xbb, 0x90, 0x6b, 0x69, 0x25, 0xab, 0xfc,
-	0x4b, 0xd7, 0x1f, 0xc1, 0xaf, 0x88, 0x3d, 0x4e, 0xf4, 0x1a, 0x72, 0x1d,
-	0x16, 0xd6, 0x31, 0x5b, 0xa4, 0xd0, 0x4c, 0x1c, 0xb9, 0x71, 0xe0, 0xeb,
-	0x1f, 0xf0, 0xba, 0xb1, 0xaf, 0x1f, 0x60, 0x5f, 0xe5, 0xb5, 0x89, 0x63,
-	0x62, 0x5e, 0xb3, 0xcb, 0x35, 0xfe, 0x37, 0x97, 0x1f, 0x30, 0x16, 0x0b,
-	0x72, 0x6e, 0x4b, 0xa3, 0x92, 0xc7, 0x2d, 0x96, 0xd0, 0xab, 0x4b, 0xcc,
-	0x91, 0xe7, 0xa6, 0xd7, 0x85, 0xf7, 0x6a, 0x7a, 0xdf, 0x0a, 0x6d, 0x3d,
-	0xc3, 0x74, 0x84, 0x3d, 0xc8, 0xba, 0x70, 0xe4, 0x5b, 0xfc, 0x7e, 0x9c,
-	0x6b, 0x9c, 0xff, 0x83, 0xea, 0xfc, 0x9f, 0xe4, 0xf9, 0x63, 0xcc, 0x07,
-	0x2c, 0xef, 0xe5, 0xfc, 0x1f, 0x54, 0xe7, 0x5f, 0x54, 0xf3, 0xa7, 0x9c,
-	0x31, 0xd5, 0xab, 0xf4, 0xf7, 0xa6, 0xcf, 0x6a, 0x9f, 0x99, 0x10, 0x63,
-	0xcd, 0x19, 0xe8, 0x44, 0xa6, 0x9e, 0x8b, 0xb6, 0x0d, 0xdd, 0x73, 0xb1,
-	0x63, 0xf7, 0xe9, 0x8f, 0x49, 0xea, 0x1d, 0x43, 0xac, 0x77, 0xe0, 0x3c,
-	0xcd, 0x82, 0xcf, 0xe6, 0xc2, 0xe8, 0x11, 0x3b, 0xc8, 0x30, 0x62, 0x3b,
-	0x6a, 0x82, 0xff, 0x0a, 0xbf, 0x18, 0x9e, 0xa3, 0xef, 0xff, 0x43, 0x5a,
-	0x9f, 0x07, 0x2f, 0x86, 0xfe, 0x29, 0xfb, 0xc8, 0xae, 0xaf, 0x48, 0xff,
-	0x6b, 0xca, 0xd7, 0xff, 0x0a, 0xdf, 0xeb, 0x04, 0xf4, 0x73, 0x13, 0x7e,
-	0xda, 0x69, 0xf5, 0xed, 0x8f, 0x5c, 0x19, 0xcf, 0xf2, 0xe3, 0x2b, 0x93,
-	0xae, 0x1c, 0x35, 0xe4, 0x8c, 0x64, 0x99, 0x4f, 0x38, 0x66, 0x8b, 0x21,
-	0x6b, 0x64, 0x6e, 0x95, 0xb5, 0xae, 0x73, 0x8c, 0xf7, 0xc4, 0x89, 0x1b,
-	0x46, 0x4a, 0xf8, 0x08, 0xda, 0x9d, 0x2e, 0x6a, 0x63, 0x39, 0x78, 0x8e,
-	0xd0, 0xe7, 0xcc, 0xb6, 0x10, 0x3b, 0xb9, 0xca, 0x38, 0x36, 0x1b, 0xb7,
-	0x23, 0xcf, 0x0b, 0x7b, 0x12, 0xf2, 0x01, 0xdf, 0x4e, 0x01, 0xac, 0x30,
-	0x07, 0xfe, 0xbd, 0x8c, 0x9e, 0x95, 0x71, 0x5e, 0x3f, 0x7c, 0xbd, 0x23,
-	0xd6, 0x5d, 0x96, 0x2b, 0x57, 0x85, 0x3f, 0xe5, 0x12, 0xeb, 0x92, 0xb6,
-	0x79, 0x54, 0xd0, 0x99, 0x31, 0xc4, 0x54, 0xc1, 0x74, 0x82, 0x1c, 0x81,
-	0xfd, 0xa2, 0xa7, 0x8e, 0xb4, 0x51, 0x78, 0x95, 0x2b, 0xaa, 0x57, 0x41,
-	0x1a, 0xb4, 0xbf, 0x75, 0x5f, 0x42, 0xfa, 0xa1, 0x7d, 0x28, 0x6e, 0x1d,
-	0xca, 0xeb, 0xa7, 0x86, 0x3d, 0x66, 0x89, 0xde, 0x8c, 0x80, 0x9d, 0xf0,
-	0x03, 0x1a, 0x63, 0x0c, 0x37, 0xfd, 0x9d, 0x1a, 0xb7, 0xbd, 0x7f, 0x5e,
-	0xd4, 0xdc, 0xbf, 0x59, 0x96, 0x32, 0x34, 0xc7, 0xb6, 0xf8, 0xec, 0xb8,
-	0x5b, 0xa7, 0xb0, 0x0b, 0xd3, 0xc2, 0x07, 0x33, 0x40, 0xc9, 0x85, 0x31,
-	0xfa, 0x7c, 0x1e, 0x3c, 0x88, 0xee, 0x27, 0x1d, 0xf1, 0xcd, 0x25, 0x9e,
-	0xd3, 0x18, 0xa5, 0xca, 0x80, 0x51, 0x80, 0x66, 0x99, 0xcb, 0xe7, 0x0a,
-	0x88, 0xbd, 0xf3, 0xef, 0x12, 0xbe, 0xa9, 0xf2, 0x3b, 0xca, 0xb7, 0x1d,
-	0xa5, 0xe9, 0x05, 0xca, 0x66, 0xe2, 0x4f, 0x8b, 0x3e, 0xd3, 0x99, 0xf8,
-	0xa8, 0xf2, 0xc9, 0x44, 0xf8, 0x3c, 0xfc, 0x5c, 0x16, 0x7d, 0x2e, 0x6f,
-	0x67, 0x33, 0x24, 0x7d, 0x0d, 0xc4, 0x73, 0x30, 0x58, 0x76, 0xee, 0x64,
-	0x9e, 0x70, 0x52, 0xf8, 0x1b, 0x58, 0xd3, 0x98, 0xc7, 0x78, 0xf8, 0x0a,
-	0xfa, 0x08, 0xf6, 0x55, 0xa6, 0xf0, 0x92, 0x1a, 0x5b, 0x21, 0x93, 0x71,
-	0xc1, 0xfc, 0x55, 0x27, 0x1b, 0x37, 0x6a, 0xf7, 0xc3, 0x57, 0x71, 0x52,
-	0xe8, 0x7d, 0x43, 0xb4, 0x24, 0x68, 0xbd, 0x52, 0x99, 0x11, 0x7e, 0x07,
-	0x3e, 0x2e, 0x4d, 0x0e, 0x4a, 0x5e, 0x25, 0xcf, 0x4b, 0x7f, 0x04, 0x3f,
-	0xb3, 0xc4, 0xf3, 0xa8, 0xcb, 0x7f, 0x8f, 0x52, 0x62, 0x1b, 0xfe, 0xa1,
-	0x53, 0x8f, 0xd4, 0x3f, 0xc4, 0xb0, 0x66, 0xd9, 0x71, 0x8b, 0x69, 0xe3,
-	0xc7, 0x9b, 0xda, 0x6d, 0xef, 0x69, 0x19, 0xcc, 0xb0, 0x32, 0xc5, 0xb7,
-	0x2b, 0xa0, 0x33, 0xcf, 0x96, 0xe7, 0xf0, 0x1d, 0x99, 0x40, 0x5a, 0xe8,
-	0xb2, 0x11, 0xd6, 0x4d, 0xa0, 0xa3, 0x8c, 0x88, 0x78, 0x62, 0xe2, 0x59,
-	0xcb, 0x98, 0x5d, 0xc1, 0xb7, 0xa1, 0xa0, 0x9b, 0xe9, 0x9c, 0x86, 0x76,
-	0x91, 0xa7, 0x2e, 0xe3, 0xbc, 0x90, 0xaf, 0xe0, 0x79, 0x3f, 0x0f, 0x64,
-	0x56, 0x9e, 0xde, 0xa5, 0xf3, 0xd5, 0x12, 0x61, 0x9d, 0x0f, 0xa3, 0x79,
-	0x8a, 0xc6, 0x3d, 0x1d, 0xa3, 0x70, 0x7f, 0xcb, 0x0b, 0xb4, 0xeb, 0xd6,
-	0x09, 0xe0, 0x57, 0x12, 0x7b, 0x74, 0x15, 0xb1, 0x31, 0xa3, 0x2e, 0xfe,
-	0xd0, 0xc6, 0xfb, 0x64, 0x31, 0x6e, 0xc0, 0x5f, 0xf7, 0x05, 0xfe, 0x8b,
-	0x38, 0x42, 0x69, 0x10, 0x7a, 0x50, 0xaf, 0xc3, 0x38, 0x33, 0x81, 0xe3,
-	0x7e, 0x5a, 0x2c, 0x6a, 0xbd, 0x55, 0xfa, 0x90, 0x16, 0x97, 0xf5, 0x7e,
-	0xc1, 0x7f, 0x34, 0xac, 0x7a, 0x08, 0xd8, 0x64, 0xf5, 0x01, 0x4e, 0x9f,
-	0x14, 0x3d, 0x6e, 0x16, 0x73, 0xd8, 0x4a, 0xce, 0x11, 0xbe, 0x2f, 0x86,
-	0x9e, 0x99, 0xfb, 0x00, 0x7b, 0xde, 0x23, 0x77, 0x4c, 0x62, 0x4e, 0x7d,
-	0xff, 0xe7, 0x51, 0xed, 0xdb, 0x63, 0x3e, 0xfb, 0xf6, 0xd1, 0xa0, 0x8c,
-	0x73, 0x3d, 0xa7, 0xc6, 0xf8, 0xe5, 0x99, 0xfe, 0xf3, 0x0b, 0xf0, 0x1f,
-	0xd5, 0xea, 0x25, 0xee, 0x09, 0xbe, 0xd2, 0xe8, 0xc3, 0x8e, 0x30, 0x3f,
-	0x95, 0x74, 0x7c, 0xd2, 0x87, 0x8e, 0xfb, 0x78, 0x8f, 0x4f, 0x3c, 0x04,
-	0x1d, 0x9f, 0x68, 0x4a, 0xc7, 0x87, 0xa2, 0xd2, 0x87, 0xda, 0x48, 0xc7,
-	0xa8, 0xd9, 0x39, 0x59, 0x6e, 0xe6, 0xaf, 0xc2, 0x3e, 0xa0, 0xf6, 0x1c,
-	0xfe, 0x04, 0xc0, 0x4a, 0xfb, 0x14, 0x10, 0xdb, 0x03, 0x3e, 0x22, 0x56,
-	0xf2, 0x17, 0x94, 0x9a, 0xf7, 0xc6, 0x38, 0x37, 0xba, 0xe7, 0x7d, 0x9f,
-	0x7b, 0xa0, 0x6b, 0x83, 0x16, 0xec, 0x88, 0xb4, 0xd5, 0x35, 0xbc, 0xde,
-	0x0d, 0x1c, 0x29, 0xda, 0xd9, 0x12, 0x18, 0x63, 0x4f, 0x98, 0xce, 0x23,
-	0x8e, 0xaf, 0x7c, 0xbe, 0xc7, 0xf3, 0x72, 0xdd, 0xe6, 0xb8, 0xc0, 0x07,
-	0xe8, 0xa3, 0x91, 0x74, 0x30, 0xcd, 0x7b, 0x2a, 0xfd, 0xbd, 0x99, 0xe5,
-	0x88, 0xda, 0x27, 0x1e, 0x8b, 0xe7, 0xf9, 0xd6, 0xf3, 0x61, 0x7f, 0xec,
-	0x57, 0x57, 0xab, 0x79, 0xc1, 0x90, 0x05, 0x15, 0xfa, 0x05, 0xcb, 0xb9,
-	0xe0, 0xb8, 0x29, 0xfa, 0x28, 0xdc, 0x2a, 0x8f, 0xb3, 0x7e, 0x88, 0x3d,
-	0x84, 0xaf, 0x50, 0xfb, 0x72, 0x7f, 0x31, 0x44, 0x3d, 0x87, 0x58, 0xea,
-	0x1b, 0xe4, 0xb0, 0x7e, 0x68, 0x8c, 0x23, 0xbf, 0xdb, 0xe2, 0x7b, 0xd0,
-	0xff, 0x69, 0xbf, 0x95, 0xa2, 0x2e, 0xf8, 0x09, 0xd0, 0xa7, 0xd9, 0xca,
-	0xd5, 0xd1, 0xd4, 0x69, 0x41, 0x53, 0xa9, 0x95, 0xd3, 0x8a, 0xa6, 0x4e,
-	0x2b, 0x7f, 0xf9, 0x69, 0x45, 0x53, 0xa7, 0x15, 0x4d, 0x9d, 0x56, 0x34,
-	0x75, 0x9a, 0xf1, 0x7a, 0xc4, 0xec, 0x13, 0x3a, 0xbb, 0xf6, 0x57, 0xf6,
-	0x50, 0xa6, 0x88, 0xf3, 0x90, 0xc7, 0x5e, 0xba, 0x7a, 0x75, 0x48, 0xd2,
-	0xd5, 0x24, 0x2d, 0xca, 0x3c, 0x39, 0x7e, 0x17, 0xf6, 0xe0, 0xeb, 0x83,
-	0xd4, 0x73, 0x2f, 0x70, 0x76, 0x1e, 0x73, 0x0d, 0xd0, 0xb4, 0xe8, 0xe1,
-	0xda, 0x42, 0x49, 0xb7, 0x2e, 0x6b, 0xa2, 0x7e, 0x4b, 0xda, 0x6a, 0xd9,
-	0xa6, 0xb5, 0x5c, 0x1a, 0x2f, 0xa6, 0xd4, 0x7e, 0x79, 0xed, 0x98, 0x36,
-	0x4a, 0x17, 0x00, 0x57, 0xe4, 0x32, 0x5a, 0xbc, 0x37, 0x02, 0x4e, 0x59,
-	0xd3, 0x07, 0x06, 0xc7, 0x15, 0x0c, 0xbe, 0x22, 0xd6, 0x88, 0x5c, 0x40,
-	0xf8, 0x1c, 0x9b, 0xc3, 0x21, 0x97, 0x1f, 0xe1, 0xe7, 0x30, 0xee, 0x8f,
-	0x47, 0x98, 0x07, 0x6d, 0x1d, 0x0e, 0xb5, 0xb5, 0x37, 0xe3, 0x35, 0x5b,
-	0xad, 0x87, 0xb9, 0xef, 0x92, 0x1d, 0x11, 0x25, 0x37, 0xa4, 0x9e, 0xfb,
-	0x98, 0x63, 0xa7, 0xb3, 0x3c, 0xb7, 0xbf, 0x8f, 0xb7, 0xef, 0xa5, 0x8e,
-	0x0a, 0x1d, 0x8b, 0x03, 0x9f, 0x7b, 0xd8, 0x6e, 0xe4, 0x39, 0xec, 0xaf,
-	0xd0, 0xd5, 0xf8, 0x01, 0xb6, 0x4d, 0xf0, 0x2d, 0xa6, 0x11, 0xfe, 0xef,
-	0x24, 0x82, 0x01, 0xcc, 0xab, 0x8b, 0xef, 0x0d, 0x93, 0xd1, 0x9b, 0xe8,
-	0x6d, 0x57, 0xba, 0x29, 0xfc, 0x6e, 0xac, 0x9b, 0x1a, 0x33, 0xf1, 0x1d,
-	0xaa, 0xa6, 0x0c, 0xbe, 0x6a, 0xc4, 0xb1, 0x7e, 0x56, 0x91, 0xbd, 0x00,
-	0xa2, 0xea, 0xf8, 0xa7, 0x95, 0x44, 0x14, 0xc7, 0x26, 0xdd, 0x60, 0x7b,
-	0x39, 0x11, 0x18, 0xd9, 0x2b, 0x74, 0xf6, 0x80, 0x7d, 0x4c, 0xe6, 0x30,
-	0xd8, 0xa6, 0x15, 0xf0, 0xc3, 0x77, 0xa9, 0xeb, 0xd4, 0xf2, 0x4c, 0x81,
-	0xff, 0x15, 0xfa, 0x4f, 0xa6, 0x55, 0x93, 0x10, 0xb3, 0x98, 0x14, 0xb5,
-	0xce, 0xc8, 0x33, 0x3e, 0x3b, 0x0f, 0x9a, 0x85, 0xdf, 0xd0, 0x51, 0x7b,
-	0xfc, 0x29, 0xe4, 0x89, 0x15, 0x16, 0x69, 0x63, 0x59, 0x01, 0xbf, 0xd8,
-	0xc8, 0xc2, 0x5a, 0x6f, 0x58, 0xd4, 0x5e, 0xc3, 0xcf, 0xa9, 0xf3, 0x89,
-	0xf7, 0xf3, 0xf3, 0x43, 0xe2, 0xdb, 0x72, 0xd3, 0xd7, 0x30, 0xae, 0x95,
-	0x86, 0x17, 0x2a, 0x4f, 0xf1, 0x75, 0x11, 0x2f, 0xcc, 0x50, 0xbb, 0x8a,
-	0x05, 0x74, 0xa9, 0xf8, 0x51, 0x84, 0x69, 0xa8, 0x56, 0x53, 0x3c, 0x5c,
-	0xf5, 0x9d, 0x01, 0xb7, 0xbd, 0xbe, 0xb3, 0xaf, 0x6d, 0x22, 0x67, 0x36,
-	0xc3, 0x67, 0xe4, 0x82, 0xb6, 0x91, 0xf2, 0x09, 0x5a, 0xb3, 0xb4, 0xd5,
-	0xda, 0xb9, 0x6d, 0xdf, 0xd3, 0xde, 0x3a, 0xb5, 0x7a, 0xf1, 0xae, 0xd3,
-	0xa1, 0xf0, 0xa8, 0x95, 0xce, 0x16, 0x3b, 0x58, 0x56, 0xa3, 0xce, 0x09,
-	0xf0, 0x0a, 0x46, 0x51, 0x27, 0xf2, 0x5c, 0xa8, 0x95, 0x96, 0x97, 0x91,
-	0xd3, 0xf0, 0x67, 0x7b, 0x65, 0x7e, 0x6e, 0x9a, 0xe1, 0x72, 0x88, 0xe5,
-	0x9a, 0xa1, 0x62, 0x35, 0x38, 0x07, 0x9e, 0x20, 0x7a, 0x78, 0x86, 0x9e,
-	0x1e, 0xed, 0x60, 0x7d, 0x5e, 0xfa, 0xfa, 0x0f, 0xf3, 0xb3, 0xbf, 0x57,
-	0x4c, 0xc3, 0x4f, 0x65, 0x1e, 0xe5, 0xe7, 0x4f, 0xb3, 0x1e, 0x90, 0xa0,
-	0x56, 0x5a, 0x5a, 0x6e, 0x65, 0x7d, 0xbe, 0x95, 0xf5, 0x80, 0x11, 0x73,
-	0x38, 0x20, 0xde, 0x25, 0x6a, 0x52, 0x3e, 0x1b, 0x3a, 0x64, 0x1e, 0x13,
-	0x79, 0x36, 0x7f, 0xa5, 0xde, 0xe5, 0x7d, 0xc7, 0x07, 0x15, 0x1c, 0x1f,
-	0x0d, 0xae, 0x5e, 0xbc, 0xe3, 0x98, 0x8c, 0x7f, 0x93, 0xac, 0xf3, 0x86,
-	0xc5, 0xf7, 0x17, 0x8d, 0xa9, 0x29, 0xd6, 0xff, 0xf1, 0x8d, 0xb7, 0x67,
-	0x28, 0x5b, 0x3e, 0x45, 0x5f, 0x2f, 0xbb, 0x7d, 0xaf, 0xcf, 0xf0, 0x9c,
-	0x65, 0xed, 0x7c, 0x1b, 0xcf, 0xeb, 0x3d, 0xc7, 0xcb, 0x2b, 0x3a, 0x28,
-	0xf8, 0xad, 0x30, 0xb5, 0x7e, 0x03, 0x3e, 0x8f, 0x0a, 0x15, 0xe2, 0xf6,
-	0xd5, 0xfb, 0x24, 0xfd, 0xbc, 0x37, 0x44, 0x5e, 0x2a, 0xdf, 0xcf, 0xcf,
-	0x9c, 0xc3, 0xb8, 0x1b, 0x16, 0xdd, 0x76, 0x24, 0xbc, 0xff, 0x36, 0x14,
-	0xa6, 0xe0, 0x1b, 0xc8, 0xf5, 0x82, 0x8e, 0xb5, 0x7a, 0xd1, 0x39, 0xc0,
-	0x7c, 0xfa, 0x1b, 0xb8, 0x8f, 0xff, 0xbe, 0x81, 0xe3, 0x0e, 0x5e, 0x27,
-	0xe4, 0x2c, 0x72, 0x4a, 0xc0, 0xdf, 0x0e, 0x45, 0x4c, 0x81, 0x7f, 0xcf,
-	0x30, 0x4e, 0xb5, 0x08, 0x1f, 0x5f, 0x1f, 0xc6, 0x3a, 0x83, 0xac, 0x13,
-	0xac, 0x5e, 0x1c, 0x3d, 0x80, 0xe3, 0x44, 0x6f, 0x90, 0x61, 0x24, 0x71,
-	0xa8, 0xe1, 0x9b, 0x75, 0xa1, 0xc3, 0xa3, 0xe4, 0xfa, 0x6e, 0x1d, 0x7a,
-	0x26, 0x75, 0x50, 0x8a, 0xdf, 0x31, 0x5d, 0x94, 0xeb, 0x9e, 0x2b, 0x07,
-	0x49, 0xfa, 0x87, 0x52, 0x43, 0xfa, 0xfb, 0x84, 0xd4, 0x8f, 0x67, 0x6b,
-	0x5a, 0xc1, 0xef, 0x1e, 0x7a, 0x50, 0xec, 0xa2, 0x75, 0x15, 0x43, 0x7a,
-	0x20, 0xec, 0x29, 0xe6, 0xc5, 0xe9, 0x1e, 0xba, 0xbf, 0xdc, 0x42, 0xd4,
-	0xd7, 0x21, 0x62, 0xbc, 0x0f, 0x8a, 0x8b, 0x94, 0x7c, 0xed, 0xc9, 0x21,
-	0xe9, 0x4f, 0xa9, 0xe1, 0xc8, 0x03, 0x1f, 0x1c, 0x79, 0x57, 0xe0, 0xc8,
-	0xf0, 0xd0, 0xc6, 0x38, 0xb2, 0x47, 0xe7, 0x22, 0x52, 0xab, 0xc2, 0x8f,
-	0xd7, 0x19, 0x3f, 0x5e, 0x66, 0xfc, 0x38, 0xd2, 0x04, 0x3f, 0x0c, 0x0f,
-	0x7e, 0x1c, 0x15, 0xf8, 0xf1, 0xeb, 0x43, 0x1b, 0xe1, 0xc7, 0x91, 0xe0,
-	0x46, 0x3e, 0x1e, 0x8d, 0x9b, 0x03, 0xb4, 0x54, 0x74, 0x68, 0x79, 0xde,
-	0x8e, 0x27, 0x68, 0x35, 0x22, 0x63, 0x83, 0x53, 0xa2, 0x4e, 0x65, 0x51,
-	0xe0, 0x55, 0x5a, 0xf8, 0x2f, 0xfd, 0xbf, 0x1b, 0x68, 0x29, 0xf8, 0xcb,
-	0x3d, 0x99, 0xce, 0xaf, 0x5e, 0xfc, 0x3b, 0xde, 0xc7, 0xdb, 0x2b, 0xa1,
-	0x10, 0xae, 0x05, 0xa7, 0xc2, 0xb4, 0xb6, 0x82, 0xef, 0x12, 0x46, 0xe8,
-	0x4e, 0x31, 0x4a, 0xb7, 0x8b, 0x03, 0xb4, 0x56, 0x1c, 0xa2, 0xbb, 0x45,
-	0xbc, 0x03, 0x30, 0xe7, 0x63, 0x01, 0x73, 0x83, 0x0e, 0x87, 0x79, 0xcc,
-	0xf2, 0x00, 0xad, 0x2e, 0x6b, 0x7c, 0x05, 0xae, 0x62, 0xff, 0xe1, 0x27,
-	0xf0, 0xc7, 0x81, 0xe9, 0x3a, 0x1c, 0x90, 0xf7, 0x60, 0xef, 0x67, 0x1b,
-	0x6b, 0x64, 0x45, 0x9e, 0xa5, 0xc9, 0x38, 0xd2, 0x32, 0x65, 0x0b, 0x5f,
-	0xea, 0xe1, 0x20, 0x74, 0xd9, 0xc4, 0x3e, 0xea, 0xe1, 0x3d, 0x70, 0x90,
-	0x27, 0x34, 0xc4, 0x7a, 0xe9, 0x0e, 0xa1, 0x87, 0x26, 0x9d, 0x50, 0x64,
-	0x9a, 0x2a, 0x97, 0x0c, 0x07, 0x3d, 0x0f, 0xd3, 0xfc, 0x3c, 0x43, 0xf9,
-	0x71, 0xba, 0x5d, 0xf8, 0xe4, 0xd5, 0x39, 0x11, 0x8b, 0x7d, 0x96, 0xe7,
-	0x0c, 0xf9, 0x58, 0x8b, 0x73, 0x50, 0x35, 0xce, 0xd1, 0xce, 0xeb, 0x96,
-	0xb4, 0x34, 0xe3, 0xf0, 0xb8, 0x32, 0x8f, 0x2b, 0x23, 0x76, 0xc6, 0xe7,
-	0x97, 0x11, 0xb7, 0x8d, 0xd2, 0xda, 0x3c, 0x68, 0x0e, 0x7e, 0x89, 0x5a,
-	0xac, 0x74, 0x6d, 0x05, 0xe7, 0xe1, 0x9b, 0xa8, 0xc5, 0x4a, 0xd7, 0x54,
-	0xac, 0x74, 0x6d, 0x65, 0x4a, 0xf0, 0xe1, 0xd9, 0xff, 0xdd, 0x14, 0x60,
-	0x19, 0x30, 0x85, 0x19, 0xba, 0x4e, 0x53, 0x0d, 0x7a, 0xbf, 0x4e, 0x0c,
-	0x78, 0x6c, 0x58, 0x50, 0x05, 0x7f, 0x18, 0xba, 0x62, 0x84, 0xa1, 0x0d,
-	0xb8, 0xfd, 0xe3, 0x02, 0x34, 0xd3, 0x79, 0x4a, 0x0c, 0x30, 0x3c, 0x23,
-	0x80, 0x79, 0x49, 0x18, 0x9a, 0x97, 0x60, 0x73, 0xaf, 0xfc, 0x0c, 0x90,
-	0xbb, 0x7a, 0x6c, 0xc0, 0x6d, 0x7c, 0x48, 0xf9, 0x23, 0x83, 0x56, 0xfe,
-	0x30, 0xb0, 0x38, 0xa9, 0x43, 0xf4, 0x37, 0xad, 0x7f, 0x2c, 0x07, 0x1b,
-	0x5f, 0x6b, 0x02, 0x9a, 0xdb, 0x3c, 0x85, 0x94, 0xb9, 0x5b, 0x60, 0xbd,
-	0x89, 0x75, 0x5d, 0x26, 0xb1, 0x76, 0xc3, 0xd2, 0x42, 0x0c, 0x19, 0xe9,
-	0x09, 0x62, 0x06, 0x22, 0x3d, 0xd9, 0x00, 0xcb, 0x4e, 0x16, 0x60, 0x5e,
-	0x11, 0x02, 0xd6, 0x0f, 0x0c, 0xd0, 0x3a, 0xe6, 0x00, 0x78, 0x2c, 0xa1,
-	0x89, 0x01, 0x74, 0x07, 0x27, 0xd0, 0xfe, 0x7e, 0x65, 0xf0, 0xba, 0xe3,
-	0x06, 0x09, 0x88, 0xa1, 0x8b, 0x7a, 0x14, 0xe5, 0x41, 0x79, 0xd4, 0x49,
-	0x85, 0x81, 0xc4, 0xfc, 0x04, 0xf2, 0x1f, 0xd0, 0x1f, 0x20, 0x3f, 0x02,
-	0xf3, 0x93, 0x33, 0x50, 0x0e, 0xb4, 0x36, 0xaa, 0x79, 0x0d, 0x48, 0x1f,
-	0x28, 0x0c, 0x41, 0x65, 0x2a, 0x68, 0x8c, 0x03, 0xc8, 0x5e, 0x22, 0x04,
-	0x0d, 0x3b, 0x20, 0x0d, 0x64, 0x37, 0x4f, 0x11, 0x01, 0xf3, 0x93, 0x02,
-	0x84, 0x18, 0x1a, 0xe0, 0xf9, 0x89, 0x1d, 0xe8, 0x52, 0x98, 0x9b, 0xfe,
-	0xff, 0x3f, 0xa6, 0xc2, 0x02, 0x4c, 0x7b, 0xa0, 0xb5, 0xb5, 0xbf, 0xff,
-	0x1f, 0x10, 0x61, 0x61, 0x68, 0x81, 0xaf, 0xd1, 0x0b, 0x94, 0x07, 0x95,
-	0x73, 0x0b, 0x80, 0xac, 0x36, 0x78, 0xbd, 0x0d, 0x92, 0x07, 0x89, 0xfd,
-	0x02, 0x96, 0x2b, 0xff, 0xff, 0x2f, 0x85, 0xab, 0x05, 0x01, 0x00, 0xb3,
-	0x28, 0x79, 0xae, 0x58, 0x7d, 0x00, 0x00, 0x00 };
+	0xcd, 0x7c, 0x0d, 0x70, 0x5c, 0xd5, 0x95, 0xe6, 0xe9, 0xd7, 0xdd, 0x52,
+	0x4b, 0x96, 0xe5, 0x27, 0xb9, 0x51, 0x1a, 0xa2, 0x24, 0xef, 0xa9, 0x9f,
+	0xa4, 0x06, 0x29, 0xe4, 0xd9, 0x08, 0x10, 0x49, 0x0f, 0x34, 0xdd, 0x92,
+	0x11, 0x89, 0x77, 0x24, 0x40, 0x61, 0xbc, 0x3b, 0xae, 0xac, 0xa6, 0x2d,
+	0x13, 0x42, 0x31, 0x35, 0xae, 0x0a, 0x3b, 0x71, 0xb2, 0x04, 0x37, 0x2d,
+	0x99, 0x38, 0x8c, 0xec, 0x56, 0x64, 0x59, 0x66, 0x67, 0xd8, 0xd9, 0x4e,
+	0x4b, 0xb2, 0x19, 0xa6, 0xed, 0xc6, 0x90, 0x1f, 0xa6, 0x92, 0x0c, 0x5a,
+	0xe3, 0x00, 0x93, 0xcd, 0x56, 0x41, 0x2a, 0xb5, 0xcb, 0x6c, 0x51, 0xbb,
+	0x5e, 0x27, 0x4c, 0xb2, 0xa9, 0xda, 0x0a, 0x3b, 0x93, 0xda, 0x65, 0xf2,
+	0x33, 0x6f, 0xbf, 0xef, 0xbe, 0xfb, 0xa4, 0x96, 0xac, 0x38, 0x4c, 0xa6,
+	0x52, 0x35, 0xaa, 0xea, 0xba, 0xef, 0xde, 0x77, 0x7f, 0xce, 0x3d, 0xf7,
+	0xdc, 0x73, 0xbe, 0x73, 0xee, 0x7d, 0xba, 0x55, 0xa4, 0x59, 0xf4, 0xdf,
+	0x56, 0xfc, 0x06, 0x7e, 0xff, 0x0f, 0xf6, 0xdd, 0x78, 0xbd, 0x7b, 0x3d,
+	0xf3, 0x46, 0x54, 0x22, 0x4c, 0xc3, 0xf8, 0xc5, 0xf1, 0xdb, 0xa9, 0x9f,
+	0x37, 0xfb, 0x33, 0xf1, 0xbb, 0x29, 0x24, 0x32, 0xf1, 0x23, 0x91, 0xd0,
+	0x86, 0x77, 0xb1, 0x4d, 0xea, 0x7b, 0xde, 0x2f, 0xe9, 0x48, 0xff, 0x19,
+	0xf8, 0x59, 0x57, 0xae, 0xb2, 0x3a, 0xee, 0xaf, 0xfb, 0x17, 0xd6, 0xcd,
+	0xb7, 0xea, 0x9f, 0xc4, 0x8c, 0xf4, 0xc5, 0xdf, 0xce, 0x3a, 0x12, 0x0b,
+	0xa7, 0xbf, 0x3b, 0xba, 0xcf, 0x11, 0xc9, 0x54, 0xfb, 0xac, 0x9c, 0xfc,
+	0xc2, 0x2b, 0xc4, 0x23, 0xc2, 0xf2, 0xf7, 0xa4, 0x7f, 0x7e, 0xe8, 0x1b,
+	0x37, 0xdb, 0x6f, 0x95, 0xc3, 0x12, 0x33, 0xd3, 0x6f, 0x8b, 0xd9, 0x23,
+	0xb1, 0x4e, 0xb4, 0x79, 0xb2, 0xf7, 0x29, 0x43, 0x5a, 0x83, 0xbe, 0xcc,
+	0x89, 0x70, 0x5a, 0xc6, 0x26, 0x67, 0x0e, 0x79, 0x86, 0x23, 0x85, 0x6b,
+	0xd2, 0x8e, 0x55, 0x94, 0x96, 0xc1, 0xe9, 0x81, 0x9b, 0x05, 0xf9, 0xb1,
+	0xc9, 0x6a, 0x4c, 0xb2, 0xb5, 0x42, 0x8b, 0xe1, 0x38, 0x48, 0x63, 0x85,
+	0x77, 0xa7, 0x25, 0xd6, 0x90, 0x9e, 0x6f, 0x7c, 0xc9, 0xe1, 0xf8, 0x89,
+	0xd1, 0xac, 0xf3, 0x6e, 0x89, 0x38, 0x9e, 0x37, 0x8d, 0xf1, 0x77, 0x55,
+	0x7f, 0xe1, 0x3d, 0x1a, 0xf1, 0xc7, 0x36, 0xd2, 0x07, 0xc3, 0x4c, 0x43,
+	0x69, 0x6b, 0xb4, 0xab, 0xaa, 0xf2, 0x0d, 0x7e, 0xde, 0xd1, 0xf9, 0x58,
+	0xb3, 0x4f, 0xbb, 0x34, 0x81, 0xf6, 0x58, 0x24, 0x9d, 0x6e, 0x42, 0x1f,
+	0xb1, 0x68, 0xfa, 0x99, 0xdf, 0x5a, 0x56, 0xf5, 0xee, 0xd7, 0xf5, 0xee,
+	0x8f, 0xfa, 0xed, 0x26, 0x47, 0x7b, 0xaa, 0x4c, 0x1f, 0x1a, 0xed, 0x56,
+	0xe9, 0xc3, 0xa3, 0x49, 0x95, 0x16, 0x54, 0xbd, 0x50, 0x7a, 0x7a, 0xd4,
+	0x51, 0x69, 0xa7, 0x2e, 0x4f, 0x8d, 0x5a, 0x2a, 0xed, 0xd7, 0xa9, 0xab,
+	0xd3, 0x01, 0x9d, 0x0e, 0xea, 0x34, 0xad, 0xd3, 0x8c, 0x4e, 0x87, 0x74,
+	0x3f, 0x23, 0x3a, 0xbf, 0x5b, 0xa7, 0x63, 0x3a, 0x1d, 0xd7, 0xe9, 0x1e,
+	0x9d, 0xee, 0xd5, 0x74, 0x4d, 0xe8, 0xf4, 0x41, 0x5d, 0x7e, 0x40, 0xd3,
+	0x79, 0x10, 0xf4, 0x7c, 0xa6, 0x51, 0xcb, 0x2d, 0xe6, 0x6b, 0xc9, 0xbe,
+	0x99, 0x98, 0x14, 0x4b, 0x61, 0xc9, 0xa9, 0xf5, 0xfc, 0x7c, 0x54, 0x9a,
+	0x63, 0x32, 0x55, 0x8b, 0xc9, 0x45, 0x25, 0xae, 0x3f, 0xf4, 0xbe, 0xd1,
+	0x6b, 0xca, 0x33, 0xb5, 0xb8, 0xbc, 0x50, 0x93, 0xd0, 0x58, 0x6f, 0x93,
+	0x18, 0x73, 0xd7, 0x48, 0xc6, 0x0c, 0x49, 0x58, 0xf1, 0xd5, 0x92, 0xec,
+	0x4c, 0x07, 0xf2, 0x76, 0x42, 0xe4, 0xe5, 0xa8, 0xbf, 0x8e, 0x31, 0x09,
+	0x2f, 0x70, 0x5d, 0x16, 0x46, 0x5f, 0x9a, 0x4f, 0x48, 0xe4, 0x98, 0x85,
+	0xfe, 0x5b, 0x24, 0xba, 0x20, 0x9d, 0x61, 0xe9, 0x4e, 0xdc, 0x87, 0x1a,
+	0x43, 0xd5, 0x88, 0x0c, 0x57, 0x43, 0x58, 0xab, 0x18, 0xe4, 0xa4, 0x05,
+	0x3f, 0x13, 0xbf, 0x38, 0x7e, 0x09, 0xfc, 0x3c, 0xf4, 0xd3, 0x29, 0xb9,
+	0x2a, 0xfb, 0xc4, 0xb8, 0x25, 0x8c, 0x5f, 0xb2, 0xcd, 0x09, 0x21, 0x4d,
+	0x09, 0xf9, 0x46, 0xaf, 0x4f, 0xd3, 0x0b, 0xb5, 0x58, 0x28, 0x7b, 0x52,
+	0x0e, 0xe4, 0x5c, 0xb1, 0x0c, 0xa7, 0x59, 0xf2, 0x66, 0xc8, 0x9a, 0x4c,
+	0xb5, 0x4b, 0x61, 0x1c, 0xef, 0x4a, 0x92, 0x31, 0xd0, 0x77, 0xde, 0x94,
+	0x09, 0xff, 0x1d, 0xcb, 0xfe, 0x1e, 0xfb, 0xd5, 0x36, 0x29, 0xb8, 0x2f,
+	0x94, 0xfe, 0x02, 0xcf, 0xec, 0xeb, 0xcd, 0x88, 0x4f, 0xf3, 0xdb, 0xc8,
+	0xb3, 0xfc, 0x67, 0xdb, 0xfc, 0x3c, 0x9f, 0x59, 0x37, 0x18, 0x33, 0x98,
+	0x2b, 0xc7, 0xee, 0xc5, 0x7c, 0x39, 0xfe, 0xea, 0x7c, 0x41, 0x47, 0x4b,
+	0x28, 0x77, 0xd2, 0x92, 0xc3, 0xa5, 0x5b, 0x25, 0xeb, 0x7a, 0xde, 0x3e,
+	0x57, 0xe2, 0x86, 0x74, 0x9b, 0x39, 0xbc, 0xad, 0x54, 0x25, 0x94, 0x2d,
+	0x05, 0xfc, 0x60, 0xbf, 0x11, 0x94, 0x75, 0xa0, 0x7e, 0x6b, 0x68, 0xe8,
+	0x24, 0x68, 0x4f, 0x93, 0x2f, 0x90, 0x59, 0xb7, 0x3b, 0x31, 0x89, 0xf1,
+	0x16, 0xab, 0xdd, 0xee, 0x79, 0x31, 0xd1, 0x67, 0x3b, 0xea, 0x90, 0x47,
+	0xec, 0x8b, 0x7d, 0xb2, 0xbf, 0x16, 0xb4, 0x8d, 0xe3, 0x1d, 0x69, 0xf2,
+	0xbc, 0xac, 0x6b, 0x32, 0x2f, 0x65, 0xf0, 0xad, 0x4c, 0xbe, 0x35, 0x77,
+	0xca, 0xa9, 0x2a, 0xc7, 0xd8, 0x8c, 0xee, 0xeb, 0xfe, 0x99, 0xd1, 0x9d,
+	0x40, 0xff, 0x71, 0xa4, 0x5b, 0x42, 0xd9, 0xe3, 0x1e, 0xc6, 0x4f, 0xe0,
+	0x79, 0xb3, 0x39, 0x5c, 0xd4, 0x32, 0x98, 0x00, 0xed, 0x71, 0x39, 0xa7,
+	0xe4, 0x70, 0x8b, 0x84, 0x21, 0x87, 0x5c, 0xe3, 0xb6, 0x85, 0x1b, 0x25,
+	0x1f, 0xb7, 0x2d, 0xea, 0xce, 0xae, 0x9d, 0x4d, 0x98, 0xa3, 0xd6, 0x82,
+	0xc7, 0xe2, 0x90, 0xc3, 0xf3, 0x6d, 0x06, 0x4a, 0x0c, 0xb1, 0xcd, 0x7f,
+	0x25, 0x05, 0xc9, 0x2d, 0x7d, 0x2a, 0x24, 0xcd, 0x06, 0xea, 0x5d, 0x1b,
+	0xf2, 0x79, 0x40, 0xfe, 0x64, 0xc0, 0x9f, 0x90, 0xf8, 0xfb, 0x3a, 0x23,
+	0x5d, 0x55, 0xbe, 0xef, 0xb3, 0x0c, 0xf5, 0x6e, 0x08, 0xef, 0x22, 0x92,
+	0xdc, 0x19, 0xbc, 0x1f, 0xc2, 0xfb, 0x6b, 0x64, 0xc2, 0x04, 0x2d, 0xa5,
+	0xe7, 0x8d, 0x2c, 0x68, 0xbc, 0x3d, 0xa2, 0xe6, 0x8a, 0xba, 0x13, 0x75,
+	0xfd, 0x4c, 0xa0, 0xde, 0x1f, 0x63, 0x2c, 0xd0, 0x5b, 0xb2, 0x40, 0x4b,
+	0x07, 0x68, 0x21, 0x8d, 0x05, 0x23, 0x5b, 0x8b, 0x20, 0x3f, 0x6d, 0xe4,
+	0x4e, 0x1f, 0xc1, 0xb3, 0x98, 0x46, 0xfa, 0x79, 0xa6, 0x68, 0xbf, 0xb7,
+	0xae, 0xfd, 0x5e, 0xb4, 0xe7, 0x18, 0x6c, 0xef, 0xcb, 0x7f, 0x41, 0xc9,
+	0xa2, 0x75, 0x05, 0x7e, 0x84, 0x7f, 0x0d, 0x7e, 0x7c, 0x4d, 0xf3, 0xe3,
+	0x67, 0xf2, 0x9b, 0xe7, 0xc7, 0x7f, 0xff, 0x0d, 0xf1, 0x43, 0x24, 0x7f,
+	0x9c, 0xcf, 0x11, 0x29, 0x28, 0xbd, 0xc5, 0x7d, 0x4b, 0x79, 0xa7, 0xce,
+	0x22, 0x9f, 0x28, 0xc7, 0xd8, 0x03, 0xb5, 0x08, 0xd2, 0xa7, 0x90, 0x6e,
+	0x09, 0x8d, 0x1d, 0xbf, 0x84, 0xf5, 0xf7, 0xc4, 0xdc, 0x19, 0xd8, 0x8d,
+	0x42, 0xc2, 0x94, 0x4e, 0x31, 0xaf, 0x87, 0xd1, 0xee, 0xb0, 0xcd, 0xbc,
+	0xbc, 0x89, 0xf7, 0xbf, 0x08, 0x05, 0xf6, 0x3d, 0x3b, 0xd3, 0xf4, 0x76,
+	0x46, 0x3d, 0x45, 0xc9, 0xcf, 0x8c, 0x91, 0x8e, 0x84, 0x72, 0x25, 0x6b,
+	0xc2, 0x48, 0xc7, 0xa1, 0xa7, 0x98, 0x1f, 0x0c, 0xf9, 0x34, 0x0f, 0xa0,
+	0x6e, 0xa0, 0xb3, 0x02, 0xda, 0x07, 0x40, 0xfb, 0x46, 0xdd, 0x95, 0x01,
+	0x2d, 0xa4, 0x81, 0x74, 0x55, 0xc2, 0x9a, 0xf7, 0xe8, 0xe7, 0xa0, 0xea,
+	0x27, 0x9c, 0x1e, 0x14, 0xda, 0xd0, 0xfc, 0x0c, 0xf7, 0x01, 0xdb, 0xb1,
+	0x2f, 0x5f, 0x27, 0xe7, 0xab, 0x41, 0x1f, 0x85, 0xba, 0x3e, 0x0a, 0xa0,
+	0x47, 0xb6, 0x19, 0x4e, 0x14, 0x6b, 0xcf, 0xae, 0x8e, 0xe0, 0xdd, 0x93,
+	0x92, 0x3d, 0x7d, 0xb3, 0x81, 0x39, 0xa0, 0x5f, 0xf2, 0x68, 0x0c, 0x3a,
+	0x9b, 0xfb, 0x2c, 0x26, 0xb9, 0x38, 0xcb, 0x3e, 0xa6, 0xc7, 0x8d, 0x48,
+	0x46, 0xe5, 0x5f, 0x69, 0x5d, 0xa3, 0xe3, 0x79, 0x3d, 0x9f, 0x34, 0xe6,
+	0x43, 0x1a, 0x82, 0xb9, 0xa4, 0xeb, 0xe6, 0x12, 0xf0, 0x9a, 0xbc, 0x30,
+	0xa1, 0xe3, 0x63, 0xda, 0x86, 0xb0, 0xdd, 0x74, 0xdd, 0xda, 0x4d, 0xa3,
+	0x0d, 0x79, 0x8f, 0x3a, 0x1b, 0xec, 0x0a, 0x6d, 0xca, 0x10, 0xfa, 0x29,
+	0xce, 0x1b, 0x92, 0x73, 0x61, 0xab, 0xdd, 0x77, 0x6b, 0x79, 0x5d, 0x93,
+	0xa5, 0xe8, 0xa6, 0xb2, 0x74, 0xc8, 0xf0, 0xf5, 0x35, 0x6c, 0x0b, 0xec,
+	0xcf, 0xd4, 0xbc, 0x9d, 0x0a, 0x64, 0xa9, 0x38, 0xf3, 0x4e, 0x64, 0x29,
+	0x68, 0x1f, 0x83, 0xec, 0x06, 0x63, 0x6c, 0xa4, 0x39, 0xa8, 0x03, 0x1a,
+	0x4b, 0x59, 0x8d, 0x51, 0x38, 0x8e, 0x6f, 0x1b, 0xca, 0xeb, 0x6c, 0xc3,
+	0x11, 0xb4, 0x95, 0x50, 0xae, 0xb7, 0x45, 0xf6, 0xcf, 0x07, 0x7d, 0x1c,
+	0x51, 0x32, 0x3b, 0x39, 0x63, 0x9b, 0xc3, 0x61, 0xc9, 0x0c, 0xcf, 0x0e,
+	0xca, 0x50, 0xad, 0x13, 0x6b, 0xfa, 0xb6, 0x07, 0xdb, 0x79, 0x7d, 0x54,
+	0x1c, 0xe8, 0x45, 0xcc, 0x79, 0x00, 0x3c, 0xae, 0x45, 0xc5, 0x48, 0xbb,
+	0x48, 0xeb, 0x31, 0x56, 0x24, 0x32, 0xbc, 0x2e, 0xdf, 0x80, 0x3a, 0xe8,
+	0x7b, 0x60, 0x63, 0x3d, 0xc8, 0x27, 0x78, 0x9b, 0x75, 0x7f, 0xe1, 0xc1,
+	0x0e, 0x6b, 0x9b, 0xc5, 0x52, 0xea, 0x89, 0x40, 0x47, 0x7c, 0x14, 0xfb,
+	0x5b, 0xed, 0x85, 0x82, 0x91, 0x3e, 0x80, 0x3e, 0x44, 0xc9, 0x69, 0xb1,
+	0xf6, 0x4c, 0xb0, 0xef, 0x55, 0xf9, 0xae, 0x01, 0xca, 0x5e, 0x19, 0x98,
+	0x80, 0x73, 0x5a, 0x52, 0x7b, 0x3d, 0x67, 0xc6, 0x65, 0xba, 0xc4, 0xf9,
+	0x2c, 0x49, 0xb2, 0xfa, 0xa7, 0x92, 0x3b, 0x2d, 0xf2, 0xad, 0x19, 0xd6,
+	0xfb, 0xba, 0xae, 0xf7, 0x3c, 0xea, 0x25, 0xad, 0xa1, 0x90, 0x0d, 0x3b,
+	0x60, 0x63, 0x9b, 0xf4, 0x59, 0x48, 0xcd, 0x11, 0xfc, 0x86, 0x68, 0x64,
+	0x50, 0xcf, 0xc7, 0x40, 0xcf, 0x83, 0x1f, 0x22, 0x77, 0x95, 0x1a, 0xa1,
+	0x4f, 0xfe, 0x27, 0x68, 0x8d, 0xcb, 0xe3, 0x98, 0xc7, 0x4b, 0x33, 0xc4,
+	0x59, 0x5f, 0x97, 0xe5, 0x19, 0xe2, 0xae, 0xe7, 0x65, 0x7a, 0x26, 0xe9,
+	0x7e, 0x0b, 0x7c, 0x3e, 0x25, 0x9c, 0x4b, 0x9f, 0x8b, 0x14, 0x18, 0xd0,
+	0xb6, 0x1e, 0x83, 0x3e, 0xeb, 0xdd, 0xe9, 0xf7, 0xd7, 0xad, 0xfb, 0x73,
+	0xaa, 0xb6, 0x5c, 0x34, 0xa9, 0x9f, 0x2e, 0xdf, 0xe3, 0x59, 0xbd, 0xc7,
+	0xc7, 0xdc, 0x4e, 0x31, 0xb0, 0xaf, 0x33, 0xe3, 0x05, 0x58, 0x3f, 0xee,
+	0xeb, 0xff, 0x6b, 0xac, 0xe1, 0x9f, 0x04, 0xb0, 0xaa, 0xad, 0xec, 0xdd,
+	0x3f, 0x6e, 0x8f, 0xd7, 0xef, 0x6d, 0x8e, 0xdf, 0x8a, 0x36, 0x11, 0xa4,
+	0x57, 0xde, 0xd7, 0xe8, 0xa3, 0xae, 0xed, 0x20, 0xf7, 0x05, 0xda, 0xfc,
+	0x09, 0x78, 0x41, 0xfe, 0xbf, 0x93, 0xfd, 0xdc, 0x17, 0x7e, 0x47, 0xfb,
+	0x79, 0xfc, 0x4a, 0xfb, 0xb9, 0x7e, 0x2f, 0x9f, 0x25, 0x2f, 0x30, 0xb6,
+	0xcc, 0xfa, 0xb2, 0xd5, 0x0d, 0x5e, 0x5b, 0x90, 0x53, 0xd0, 0x50, 0xfa,
+	0x07, 0x2f, 0x13, 0xf1, 0xf1, 0x9c, 0x2f, 0x4f, 0xac, 0x17, 0xd4, 0xf1,
+	0x75, 0xef, 0x50, 0xed, 0xa2, 0xd2, 0xb3, 0xe7, 0x94, 0x9e, 0xb5, 0x8f,
+	0x14, 0x84, 0xf2, 0x76, 0x43, 0x98, 0x7c, 0x7f, 0xc6, 0xfd, 0x2c, 0x68,
+	0xb4, 0x2d, 0xcb, 0xe8, 0x2e, 0x18, 0xc6, 0x67, 0xe5, 0xc0, 0xe2, 0x43,
+	0x72, 0xa0, 0xc4, 0x3e, 0xd2, 0x78, 0xef, 0xa0, 0xac, 0x09, 0xba, 0x96,
+	0x3a, 0xfd, 0xed, 0x90, 0x3f, 0x96, 0x01, 0xfb, 0xb5, 0x12, 0xba, 0xab,
+	0x76, 0x21, 0x94, 0x5d, 0xe4, 0xde, 0x45, 0x79, 0xad, 0x5e, 0xe7, 0x07,
+	0xfa, 0xbe, 0x5e, 0xb7, 0x17, 0x42, 0x63, 0xa5, 0x69, 0xe2, 0x40, 0x23,
+	0xeb, 0x46, 0xb5, 0xee, 0xf8, 0x9a, 0x29, 0xad, 0xb0, 0x2d, 0xc6, 0x3c,
+	0x78, 0x45, 0x9c, 0x4a, 0xde, 0xa5, 0x24, 0x13, 0x21, 0x9e, 0xe4, 0xb3,
+	0x78, 0xe1, 0x34, 0xf7, 0x9e, 0x44, 0xc2, 0xe9, 0x2e, 0xf0, 0x8e, 0x75,
+	0x6e, 0x05, 0xad, 0xb0, 0x7b, 0xee, 0xfb, 0x84, 0x72, 0xf9, 0x42, 0xe9,
+	0x36, 0xe4, 0x23, 0x9a, 0xbf, 0x51, 0xd4, 0x61, 0x7f, 0x3f, 0x6d, 0x90,
+	0xd6, 0xe3, 0xd0, 0x15, 0x41, 0xbf, 0xac, 0x93, 0xd0, 0x75, 0x5a, 0x74,
+	0x9d, 0x5b, 0xf0, 0x7e, 0x0e, 0xf5, 0x6c, 0x57, 0x84, 0x7c, 0x60, 0x59,
+	0x3b, 0xe6, 0x85, 0xba, 0x8b, 0xe9, 0xf0, 0x7a, 0xba, 0x6e, 0xaa, 0xab,
+	0xcb, 0xfc, 0x66, 0x58, 0x97, 0xf2, 0x24, 0x5a, 0x97, 0xb1, 0x6c, 0x10,
+	0xcf, 0x5d, 0x32, 0xb1, 0x98, 0x81, 0x4e, 0xba, 0x5d, 0xf5, 0x13, 0x75,
+	0xd6, 0xd9, 0x3a, 0xd0, 0x64, 0x69, 0x9a, 0xb6, 0x04, 0xfa, 0x18, 0x65,
+	0xae, 0x2e, 0x6b, 0xa8, 0x2b, 0x0b, 0xe4, 0xe7, 0x5f, 0x83, 0x76, 0x8e,
+	0x3d, 0xa2, 0x71, 0x98, 0xe7, 0xe5, 0x28, 0x77, 0xfd, 0xff, 0x52, 0xf3,
+	0xa2, 0x60, 0x86, 0xd5, 0x5e, 0xa9, 0xfe, 0xf6, 0xda, 0x5e, 0x01, 0x6e,
+	0x57, 0xbd, 0x70, 0x8e, 0xa4, 0xa5, 0x05, 0x6b, 0x3b, 0x04, 0x5a, 0xb1,
+	0x86, 0x1d, 0x21, 0xcc, 0xb7, 0x45, 0xf2, 0xb5, 0xb4, 0x7e, 0xc7, 0xf2,
+	0x88, 0x8c, 0xc5, 0x83, 0xf9, 0x7d, 0xc0, 0xf4, 0xb1, 0x37, 0xea, 0x94,
+	0xb6, 0x44, 0xfc, 0xbd, 0x68, 0x4a, 0xfe, 0xe4, 0x10, 0x64, 0x9e, 0xd8,
+	0xb0, 0x01, 0x32, 0x1f, 0x57, 0x36, 0xc7, 0x70, 0x58, 0x1f, 0xef, 0x4e,
+	0xff, 0xbb, 0xb0, 0xdf, 0x86, 0xf5, 0x82, 0x36, 0xc1, 0xd8, 0xed, 0xab,
+	0x6d, 0xc7, 0x5c, 0x43, 0xc2, 0x6a, 0x7c, 0x94, 0x9d, 0x5e, 0x3f, 0xbe,
+	0xd1, 0x11, 0x8c, 0xff, 0xa7, 0xba, 0xaf, 0xf6, 0xba, 0xbe, 0xe2, 0x57,
+	0x18, 0x1f, 0xef, 0x4e, 0xff, 0xee, 0x76, 0xbf, 0x4d, 0xbc, 0xae, 0x4d,
+	0xc7, 0x86, 0x36, 0xac, 0x1f, 0x8c, 0x81, 0x77, 0xa7, 0xef, 0x6b, 0xf1,
+	0xdb, 0xb0, 0x5e, 0x03, 0x6c, 0x2c, 0xdf, 0x71, 0x0f, 0x1e, 0xa8, 0xdb,
+	0x83, 0x07, 0xb0, 0x07, 0x03, 0xd9, 0xde, 0x88, 0xd7, 0x03, 0xbf, 0x8b,
+	0xfe, 0x16, 0x31, 0xde, 0x9a, 0x7f, 0x15, 0x59, 0x68, 0x01, 0x7e, 0x6a,
+	0xa5, 0x4f, 0xa5, 0xf1, 0x39, 0x7d, 0x2c, 0xe2, 0x71, 0x71, 0x22, 0xd2,
+	0x0d, 0x5d, 0xd9, 0x9d, 0xd8, 0xcf, 0x8d, 0x5f, 0x8d, 0x2b, 0xdc, 0x9e,
+	0xd1, 0x63, 0xd0, 0xbf, 0x22, 0xdf, 0x99, 0xcf, 0xad, 0xfa, 0x5b, 0x9d,
+	0xf0, 0xc7, 0x88, 0xbb, 0x89, 0xdb, 0x02, 0xfa, 0x03, 0x7a, 0x0e, 0x1a,
+	0x6b, 0x7b, 0x33, 0x63, 0x0c, 0xd5, 0x86, 0x0c, 0x7f, 0x6f, 0xf2, 0xfd,
+	0x41, 0x6d, 0x5b, 0x37, 0xd2, 0xfb, 0x9e, 0x0d, 0xf4, 0x12, 0xdf, 0x59,
+	0x32, 0x05, 0x19, 0x89, 0x2c, 0x50, 0xd7, 0x2f, 0x8c, 0x2e, 0xcf, 0x13,
+	0xc7, 0xf4, 0x83, 0x2f, 0xa4, 0x97, 0xfc, 0xa3, 0x4e, 0x69, 0x85, 0x9e,
+	0xea, 0x4e, 0x55, 0x50, 0x9f, 0x7e, 0xfe, 0x84, 0xf2, 0x0f, 0x5b, 0x90,
+	0xc2, 0x89, 0x03, 0xad, 0x13, 0xa0, 0x75, 0x42, 0xfb, 0x86, 0xfb, 0x61,
+	0x47, 0x22, 0xc7, 0x02, 0x5a, 0x6f, 0x89, 0x04, 0x6b, 0xb3, 0x9e, 0xf6,
+	0x7a, 0xfb, 0xe7, 0xe3, 0xc0, 0xbb, 0x7a, 0xd5, 0x9e, 0x2c, 0x10, 0x3b,
+	0x4e, 0x9c, 0x0e, 0xf6, 0xa3, 0xf8, 0x7b, 0xa9, 0x35, 0xc0, 0x01, 0x9c,
+	0x0f, 0x71, 0x08, 0x75, 0x4f, 0x30, 0x87, 0x16, 0xe9, 0x5a, 0xe0, 0x1c,
+	0x56, 0xe9, 0x8f, 0x33, 0xca, 0x72, 0x00, 0xfa, 0x3b, 0xaf, 0x68, 0xdd,
+	0x2d, 0x93, 0xa5, 0xf7, 0x69, 0xfa, 0x5b, 0x40, 0xff, 0x18, 0x64, 0x7b,
+	0x4d, 0x77, 0xe5, 0xab, 0xe3, 0xc8, 0xfb, 0x98, 0x90, 0x3c, 0xce, 0x57,
+	0xa9, 0xc7, 0xf4, 0x7c, 0x9a, 0x39, 0x9f, 0x8d, 0x3a, 0x6e, 0x33, 0xbe,
+	0xbe, 0x77, 0x03, 0x5f, 0x45, 0xf3, 0x35, 0x26, 0x0d, 0x0b, 0xca, 0xbf,
+	0x46, 0xbf, 0xe4, 0x35, 0xed, 0xe8, 0xc2, 0xe8, 0xf4, 0xbc, 0xf4, 0x33,
+	0x08, 0x95, 0x07, 0xdf, 0x50, 0x36, 0xd0, 0x20, 0xdd, 0xee, 0x05, 0xcc,
+	0x3b, 0x8f, 0xf5, 0x36, 0x8e, 0xf9, 0xf2, 0x4d, 0xfe, 0xe6, 0xab, 0xcd,
+	0xf0, 0xe9, 0x39, 0x36, 0x79, 0x46, 0xfa, 0x4d, 0x45, 0xcf, 0x2a, 0xbf,
+	0x41, 0xdf, 0x7d, 0xd5, 0x8d, 0xbc, 0xad, 0xd7, 0x33, 0x41, 0xec, 0xe0,
+	0x35, 0xd3, 0xdf, 0x17, 0x9b, 0xc5, 0x0e, 0x5a, 0xa0, 0xa3, 0x23, 0x8c,
+	0x13, 0x80, 0xf7, 0x8c, 0xf3, 0x5c, 0x8a, 0xd0, 0x17, 0x78, 0xa1, 0x04,
+	0x3d, 0x73, 0x9c, 0xd8, 0xa5, 0x55, 0xef, 0x8f, 0x1b, 0xb4, 0x0d, 0x8b,
+	0x2a, 0xdb, 0x21, 0x86, 0x49, 0x7c, 0x84, 0x32, 0xe4, 0x17, 0x99, 0x0f,
+	0xe8, 0xb8, 0x7b, 0x4f, 0xd4, 0x79, 0x21, 0x12, 0xe8, 0x84, 0x35, 0xba,
+	0xea, 0x63, 0x03, 0x1e, 0x30, 0xe5, 0xfb, 0x20, 0xb7, 0xb7, 0xc3, 0xff,
+	0xb7, 0x24, 0x9f, 0xe2, 0x3e, 0x1a, 0x54, 0x3e, 0x92, 0xe1, 0xec, 0x47,
+	0x59, 0x13, 0xca, 0x60, 0x4c, 0x4d, 0xcc, 0xdf, 0xf9, 0x3d, 0x99, 0x80,
+	0x8c, 0xe7, 0x53, 0x7d, 0xa0, 0x83, 0xf8, 0x0e, 0x58, 0xcb, 0x49, 0x31,
+	0x7e, 0x80, 0xbf, 0x7b, 0xa3, 0xfe, 0xbc, 0xf6, 0x20, 0xdf, 0x8c, 0x3a,
+	0x5d, 0xba, 0xce, 0x16, 0x61, 0x1c, 0x2a, 0x6f, 0xb6, 0x22, 0xed, 0xd9,
+	0x50, 0xf7, 0x43, 0xc8, 0xdf, 0xa2, 0xfb, 0x2f, 0xe0, 0xfd, 0x4d, 0xf8,
+	0x0d, 0xa1, 0xec, 0x66, 0x94, 0xb9, 0x28, 0xbb, 0x11, 0xf9, 0x0f, 0xe9,
+	0xb8, 0x44, 0xd0, 0xa6, 0x15, 0xf9, 0x47, 0xf1, 0x1e, 0xba, 0xc2, 0x7c,
+	0x05, 0xef, 0x6f, 0xc1, 0xef, 0xfa, 0x0d, 0x75, 0xda, 0x37, 0xe4, 0x4f,
+	0xae, 0xf2, 0xe0, 0x85, 0xd2, 0x55, 0xfa, 0x99, 0xf2, 0xcc, 0xfc, 0x2b,
+	0x3a, 0x7f, 0xfb, 0x86, 0xf2, 0xfb, 0x83, 0x7c, 0xdd, 0x1a, 0xc2, 0x0e,
+	0x9a, 0x01, 0xd6, 0xbd, 0xda, 0xf4, 0xd7, 0xe0, 0x3d, 0x7e, 0xbc, 0xa0,
+	0x14, 0xb4, 0x23, 0xf6, 0xbd, 0x3d, 0xbc, 0xbe, 0xaf, 0xff, 0xd6, 0xb0,
+	0x96, 0x6f, 0x09, 0x0d, 0x9f, 0x64, 0xd9, 0x4f, 0x1b, 0xd6, 0xd7, 0x79,
+	0x5f, 0xe3, 0x5a, 0x7e, 0x6b, 0x68, 0xf8, 0x38, 0xcb, 0xee, 0x6b, 0x5c,
+	0x5f, 0x67, 0xb8, 0x71, 0x6d, 0x1e, 0x6b, 0xba, 0x30, 0x92, 0xae, 0x50,
+	0x8e, 0xb1, 0x17, 0xaa, 0xa3, 0xd9, 0x19, 0xcf, 0x9b, 0x72, 0x57, 0x12,
+	0x61, 0xa1, 0x0d, 0x22, 0x66, 0x66, 0xf9, 0x53, 0x28, 0x07, 0xa6, 0xaa,
+	0x8d, 0x09, 0x75, 0xd2, 0xe6, 0xd8, 0xd8, 0xd2, 0xd8, 0x58, 0x65, 0x23,
+	0x59, 0x85, 0x65, 0x9f, 0x18, 0x05, 0xf6, 0xd2, 0xcf, 0x4f, 0xe2, 0xd9,
+	0xaa, 0xc7, 0xdf, 0xe8, 0xb7, 0x3c, 0x9a, 0x9d, 0xa7, 0xcd, 0x5b, 0x1a,
+	0xdd, 0x37, 0xcf, 0x3d, 0x7f, 0x0a, 0x7b, 0x3e, 0x24, 0xd3, 0xca, 0xfe,
+	0x91, 0x0e, 0xb6, 0x2b, 0x8f, 0x76, 0x2d, 0x31, 0xad, 0x8c, 0x3a, 0x4b,
+	0x61, 0xd9, 0x1f, 0xf7, 0xdb, 0x32, 0x6f, 0x2d, 0x05, 0x7b, 0xa0, 0x59,
+	0xa2, 0x69, 0xca, 0xa4, 0x9d, 0x82, 0x0f, 0x80, 0xf9, 0x1c, 0x19, 0x9d,
+	0x76, 0x28, 0x9f, 0x9f, 0x82, 0xdd, 0x6f, 0x96, 0x06, 0xa5, 0x6f, 0x1e,
+	0xd7, 0x63, 0x9d, 0xc2, 0x58, 0xdb, 0xd4, 0x7e, 0xca, 0x3a, 0x91, 0x04,
+	0xc6, 0x39, 0x64, 0x38, 0x7d, 0x18, 0x8f, 0x1e, 0x7b, 0xa7, 0x4c, 0xd5,
+	0xb8, 0x6f, 0xf6, 0x44, 0xd7, 0xfc, 0xf4, 0x39, 0xb4, 0x0b, 0xfc, 0x43,
+	0x8e, 0x57, 0x01, 0x3e, 0x84, 0x2c, 0xa7, 0x6d, 0x33, 0x1b, 0x86, 0x9d,
+	0x9f, 0x0f, 0xea, 0x90, 0xa6, 0x63, 0xa3, 0xc9, 0xa5, 0x24, 0xfa, 0xea,
+	0xa4, 0x0e, 0x83, 0xee, 0x0a, 0xe3, 0xc7, 0xbe, 0xd9, 0x0e, 0xb6, 0x68,
+	0x90, 0x76, 0x64, 0x0e, 0x76, 0xa4, 0x53, 0x0e, 0x97, 0x54, 0x1f, 0x16,
+	0xfb, 0x28, 0xea, 0xb6, 0x5d, 0x4b, 0x0d, 0xf0, 0xb1, 0x92, 0xe6, 0x8b,
+	0xb2, 0xd6, 0x76, 0x58, 0xfc, 0x76, 0x7e, 0xdf, 0x3f, 0xf1, 0x32, 0xf1,
+	0xfa, 0xbd, 0xdf, 0x2c, 0x61, 0xd0, 0x91, 0x43, 0x1f, 0x1c, 0x7f, 0xad,
+	0xef, 0xa0, 0xbf, 0xa4, 0x79, 0xfe, 0xb2, 0xbe, 0xb6, 0x69, 0xfc, 0x66,
+	0x5b, 0xb9, 0x5f, 0x6b, 0x6c, 0xce, 0xf7, 0x09, 0xc8, 0x83, 0x44, 0x72,
+	0xbd, 0xd0, 0x8b, 0xb5, 0x41, 0x2d, 0x23, 0x4f, 0xa2, 0xac, 0xde, 0xc7,
+	0xf2, 0xe5, 0xab, 0x00, 0x6c, 0x59, 0xc4, 0x3e, 0x0f, 0xa7, 0x33, 0x6d,
+	0x7e, 0xcc, 0xeb, 0x4a, 0x7e, 0x15, 0xe4, 0x06, 0x7d, 0x16, 0x57, 0xdb,
+	0x72, 0x4e, 0x4f, 0x8e, 0xbe, 0x34, 0x93, 0xc0, 0x9c, 0x7c, 0xbb, 0xe0,
+	0xf3, 0x9a, 0x36, 0x27, 0x24, 0xcb, 0x8e, 0x05, 0xff, 0x9d, 0x36, 0xde,
+	0x92, 0x97, 0x9d, 0xc0, 0xfe, 0xd0, 0x16, 0xa1, 0x7e, 0x8d, 0xb4, 0x91,
+	0xf6, 0x39, 0xcc, 0xcd, 0x93, 0x59, 0xd7, 0x97, 0xc1, 0x5e, 0xd8, 0x91,
+	0xff, 0x18, 0xb1, 0x8f, 0xd0, 0xcf, 0xbb, 0x18, 0xa9, 0x9f, 0x4f, 0x80,
+	0x15, 0x9e, 0xd0, 0x31, 0xe8, 0x39, 0x2d, 0x2f, 0x65, 0xc8, 0x4b, 0x9f,
+	0x65, 0x4a, 0x0f, 0x68, 0x47, 0x9d, 0xfe, 0x6e, 0xf8, 0x5b, 0xf4, 0xe5,
+	0x13, 0xa0, 0xc7, 0x84, 0xee, 0xd8, 0xa6, 0x7d, 0x87, 0xb7, 0xa2, 0xb4,
+	0x6d, 0x6d, 0x2a, 0xbe, 0x3d, 0xa7, 0xe4, 0xd9, 0x97, 0xef, 0xb0, 0x7e,
+	0x1f, 0xc8, 0x54, 0x98, 0x90, 0x46, 0xd6, 0xe2, 0xb8, 0xac, 0xbf, 0xa0,
+	0xeb, 0xcf, 0xa3, 0x7e, 0x08, 0x73, 0xf2, 0xbc, 0x49, 0x45, 0xef, 0x02,
+	0xf8, 0x1e, 0x96, 0xe2, 0xaa, 0xcc, 0x2f, 0x40, 0xe6, 0x29, 0xdf, 0x73,
+	0xd8, 0xaf, 0x20, 0xfe, 0x6e, 0xca, 0x7d, 0x45, 0x86, 0x4e, 0xef, 0x6f,
+	0x60, 0xcc, 0xd5, 0x32, 0xe8, 0x03, 0x53, 0x26, 0x3b, 0xe5, 0xb1, 0x52,
+	0xd2, 0x9c, 0xaa, 0x5b, 0xcb, 0x5d, 0xeb, 0xd6, 0x92, 0x32, 0xa0, 0xea,
+	0xa7, 0x58, 0xbf, 0x52, 0x27, 0x03, 0x8b, 0xf3, 0x57, 0x6a, 0x47, 0x19,
+	0x60, 0xbb, 0xcd, 0xfc, 0x05, 0xc6, 0x28, 0x3d, 0x6f, 0xd9, 0x25, 0xfe,
+	0x6f, 0x94, 0x82, 0x92, 0xb1, 0x90, 0x14, 0x5d, 0xee, 0xab, 0xac, 0x15,
+	0x11, 0x1b, 0x58, 0xe9, 0xf7, 0x41, 0x67, 0x26, 0x15, 0x15, 0x3f, 0xa6,
+	0x31, 0x81, 0x35, 0x58, 0x31, 0x3d, 0xef, 0x25, 0x47, 0xa4, 0x02, 0x1f,
+	0x78, 0x19, 0x69, 0xb1, 0x8a, 0x3d, 0xdb, 0x1c, 0x81, 0x0e, 0x08, 0x64,
+	0x3c, 0x26, 0x65, 0xd4, 0x59, 0xc4, 0xbb, 0xc7, 0xaa, 0x81, 0xc4, 0x78,
+	0x9e, 0x01, 0x1e, 0xed, 0x73, 0x7e, 0xea, 0xe5, 0xe3, 0xf5, 0x75, 0x03,
+	0x4c, 0x4c, 0x2c, 0x4b, 0x6c, 0x4a, 0x4c, 0xc9, 0x77, 0xc4, 0x89, 0x87,
+	0x40, 0x0b, 0xf7, 0x6c, 0xab, 0xc4, 0xd2, 0x76, 0x62, 0x44, 0x02, 0xdb,
+	0xff, 0x3a, 0x64, 0xa9, 0xe0, 0x35, 0x3a, 0x9d, 0xf2, 0x1c, 0xe4, 0xe6,
+	0xd9, 0x55, 0x1c, 0x63, 0x41, 0x8e, 0x68, 0x47, 0x3d, 0x39, 0xe7, 0x3a,
+	0xd6, 0xe7, 0x90, 0x7e, 0xc7, 0xfd, 0x00, 0xf9, 0xf6, 0x84, 0x48, 0x3f,
+	0x7c, 0x32, 0xe8, 0xf5, 0xd9, 0x00, 0xdb, 0xb7, 0xd2, 0x37, 0xd4, 0xb2,
+	0x74, 0x11, 0x7d, 0xda, 0xa6, 0x01, 0x50, 0x7b, 0x07, 0xea, 0xf9, 0x7b,
+	0x23, 0x28, 0x3b, 0x84, 0xba, 0xa4, 0x81, 0x7e, 0xfb, 0x77, 0xb1, 0x67,
+	0x3d, 0xef, 0x1e, 0xf7, 0xe5, 0x3a, 0x5d, 0xb3, 0x80, 0xf5, 0x57, 0x72,
+	0x3e, 0xd0, 0x26, 0x8c, 0xf3, 0x4a, 0x7f, 0xbb, 0xf2, 0x2b, 0xf9, 0x0c,
+	0x79, 0x1f, 0x20, 0x16, 0xb2, 0x14, 0xd6, 0x24, 0x6e, 0x78, 0x16, 0xbc,
+	0xff, 0xa4, 0xc2, 0x34, 0xc4, 0x6f, 0xa0, 0xbf, 0x44, 0x4c, 0xe1, 0x63,
+	0x69, 0x1f, 0xd7, 0x11, 0x5b, 0xa4, 0xb8, 0x36, 0x1a, 0x5f, 0xb0, 0x2d,
+	0xeb, 0xb1, 0x6d, 0xfd, 0xfa, 0xb1, 0xce, 0xb6, 0x50, 0xee, 0x38, 0xe5,
+	0x99, 0xf6, 0xb1, 0x4d, 0xf6, 0xa7, 0x1a, 0xc1, 0xf7, 0x76, 0x6d, 0xc7,
+	0x3f, 0x08, 0xcc, 0x06, 0xec, 0x6d, 0xd2, 0x87, 0x0a, 0x78, 0x7d, 0x23,
+	0xca, 0x7e, 0x0e, 0xfe, 0xb3, 0x0c, 0xfe, 0x95, 0xb2, 0x93, 0x0f, 0x61,
+	0x2f, 0x97, 0xb7, 0xf9, 0x31, 0x34, 0xae, 0x43, 0x80, 0x13, 0x02, 0xdc,
+	0x67, 0x6a, 0xbc, 0xcf, 0xb5, 0xf1, 0xe3, 0x6d, 0x86, 0xaa, 0x4b, 0x5f,
+	0xab, 0xde, 0xc7, 0xe5, 0x1e, 0xf6, 0xbc, 0x73, 0x6e, 0x80, 0x23, 0xeb,
+	0xfd, 0xc4, 0xc0, 0x07, 0x8c, 0x89, 0xd5, 0x4e, 0x4c, 0xf1, 0x47, 0x0d,
+	0x6b, 0x58, 0xe6, 0x1f, 0xbc, 0xb0, 0x43, 0x9f, 0x93, 0x38, 0x26, 0xf0,
+	0x07, 0x59, 0x97, 0xd8, 0xe6, 0x51, 0x8c, 0x11, 0x16, 0xab, 0x83, 0xf9,
+	0x1f, 0xeb, 0x36, 0x7c, 0xf6, 0xa4, 0x67, 0x67, 0xbd, 0x3c, 0x0f, 0xfa,
+	0xfe, 0x62, 0x73, 0x10, 0x03, 0xee, 0x54, 0xfa, 0x64, 0x4d, 0x2e, 0x02,
+	0x9a, 0x82, 0x71, 0x7d, 0xff, 0xb4, 0x1d, 0xb4, 0xdd, 0x05, 0x9b, 0xb2,
+	0xb3, 0xdd, 0xae, 0xf3, 0x45, 0xeb, 0x69, 0xaa, 0xc7, 0x57, 0x16, 0xc6,
+	0x68, 0x94, 0x9d, 0x1d, 0xe4, 0x5d, 0xa7, 0xb2, 0x2d, 0x6b, 0xeb, 0x41,
+	0xdb, 0xcf, 0xb1, 0x37, 0x96, 0xdf, 0x52, 0x47, 0xd7, 0x46, 0xcc, 0x47,
+	0x1f, 0xd7, 0xc7, 0x7c, 0x99, 0xb8, 0x27, 0xbb, 0xdc, 0x00, 0xdf, 0xd5,
+	0xd3, 0x41, 0x8c, 0x47, 0x9a, 0xa3, 0x75, 0x3e, 0xf2, 0xef, 0xea, 0x33,
+	0xaa, 0x39, 0x3d, 0x97, 0xc0, 0x97, 0x4e, 0xa2, 0xfe, 0x7f, 0x00, 0xdd,
+	0x7c, 0x26, 0xed, 0x01, 0x1e, 0x4c, 0xfa, 0x6d, 0x9b, 0x37, 0xc3, 0xfd,
+	0xdc, 0x27, 0x01, 0x6f, 0xda, 0xf5, 0xba, 0xd4, 0xfb, 0xe3, 0xea, 0xe7,
+	0xae, 0xd7, 0x1d, 0x37, 0xd6, 0xcd, 0xa9, 0x5f, 0x0a, 0x8b, 0x94, 0x85,
+	0xf7, 0x23, 0x0d, 0xfc, 0xa1, 0x01, 0xd8, 0x8e, 0x0c, 0xfc, 0x1f, 0xfa,
+	0x45, 0x97, 0xf9, 0x44, 0x3c, 0xc3, 0x1c, 0xcf, 0xc3, 0x47, 0x56, 0xb6,
+	0xc3, 0xb7, 0x8b, 0xc8, 0x43, 0x87, 0xd4, 0xee, 0xa6, 0x5c, 0x8d, 0x4f,
+	0x54, 0xdd, 0xf1, 0xc9, 0xea, 0xc0, 0x38, 0x7d, 0x07, 0x5f, 0xce, 0x50,
+	0xbf, 0x2a, 0x13, 0x06, 0xda, 0x65, 0x55, 0x3b, 0x15, 0xcb, 0xd8, 0xa4,
+	0x1f, 0xe1, 0x1e, 0x9c, 0xf0, 0xc7, 0x8a, 0x8d, 0xe7, 0xa0, 0x77, 0x16,
+	0x67, 0x61, 0xd7, 0x1c, 0x3b, 0x43, 0x59, 0xdc, 0xe7, 0xda, 0x23, 0x4a,
+	0xde, 0xe2, 0xf6, 0x18, 0xd7, 0xaf, 0x32, 0xfb, 0x5e, 0xe8, 0x4d, 0x4f,
+	0xee, 0x84, 0xfe, 0x7b, 0x00, 0xf2, 0x29, 0x67, 0xa0, 0xfc, 0xce, 0x40,
+	0x61, 0x9d, 0x89, 0x8b, 0x71, 0xa2, 0x53, 0xa2, 0x47, 0x13, 0x12, 0x39,
+	0x4a, 0xff, 0x2b, 0x69, 0xde, 0x29, 0x02, 0x3b, 0xf8, 0xe2, 0xcd, 0x86,
+	0xd8, 0x83, 0x19, 0x49, 0xc2, 0x87, 0xec, 0x33, 0x2b, 0x48, 0x8b, 0x92,
+	0x4c, 0x9d, 0x46, 0x5f, 0xd1, 0x33, 0xa8, 0x8b, 0x76, 0x4d, 0xcb, 0x16,
+	0x7e, 0x1d, 0xd2, 0xbc, 0xec, 0xef, 0x8f, 0xe6, 0xe5, 0xf5, 0xf1, 0x9b,
+	0xa1, 0xd5, 0xf8, 0x0d, 0xdf, 0xbf, 0xad, 0xe3, 0x4e, 0x5f, 0xd2, 0xbe,
+	0x0c, 0xe5, 0x82, 0xf6, 0x4c, 0xf9, 0x63, 0xd0, 0xdd, 0x5f, 0x82, 0xff,
+	0xeb, 0x48, 0xae, 0x04, 0x9c, 0x9e, 0xf6, 0xe4, 0x69, 0xb7, 0xe0, 0x65,
+	0x07, 0x3c, 0x79, 0xdd, 0x75, 0x0a, 0x79, 0xb1, 0xdf, 0xa6, 0x8e, 0xfb,
+	0xb1, 0xfb, 0x21, 0xd9, 0xd3, 0x66, 0xef, 0xc9, 0x84, 0x0a, 0x5e, 0x8b,
+	0xd3, 0x2c, 0x57, 0xa7, 0x0f, 0xc9, 0xbe, 0x1d, 0x2b, 0x66, 0x58, 0x32,
+	0x57, 0x03, 0x0b, 0x26, 0xf2, 0x4a, 0x3f, 0xbd, 0xa1, 0x7c, 0xea, 0xfb,
+	0xbb, 0x0f, 0xc9, 0xd6, 0x1d, 0xb6, 0x79, 0x29, 0x4c, 0x9c, 0x76, 0x08,
+	0xf8, 0xdf, 0x4e, 0xe4, 0xc2, 0x8e, 0xb9, 0x5b, 0xec, 0x91, 0x4f, 0x0b,
+	0xcf, 0x8c, 0x1d, 0xe9, 0x3a, 0xea, 0x24, 0x1e, 0x0c, 0xf5, 0x1c, 0x78,
+	0x90, 0x3e, 0xdd, 0x19, 0xe6, 0x3d, 0x89, 0xed, 0x30, 0xf1, 0x1c, 0x97,
+	0xae, 0x13, 0x96, 0x24, 0xc1, 0x97, 0x5e, 0xc5, 0x13, 0x9e, 0x5d, 0x25,
+	0xa4, 0xe7, 0x28, 0x71, 0x93, 0xe2, 0x4d, 0x2f, 0x78, 0x93, 0x02, 0x6f,
+	0xe0, 0x47, 0xf5, 0x99, 0x97, 0x90, 0x9e, 0x97, 0xe4, 0xe0, 0x9b, 0xe0,
+	0x4d, 0x2f, 0x78, 0xd3, 0x73, 0xc6, 0x42, 0x7b, 0xf4, 0xb1, 0xdc, 0x85,
+	0xb4, 0x59, 0x3e, 0x72, 0x55, 0x07, 0x9e, 0x1d, 0x49, 0x1e, 0x8d, 0x61,
+	0x8c, 0x90, 0xec, 0xea, 0x2e, 0xc8, 0xf0, 0x0e, 0xf8, 0x63, 0xf1, 0x43,
+	0x72, 0x01, 0xb6, 0xa7, 0x04, 0xbf, 0xe0, 0xe9, 0x41, 0x7b, 0x6c, 0x05,
+	0xfa, 0xb3, 0x76, 0x97, 0x27, 0xaf, 0xec, 0xf8, 0x2b, 0x2f, 0x71, 0x95,
+	0xbd, 0x47, 0x42, 0x03, 0x32, 0x5d, 0x52, 0x36, 0x21, 0x91, 0x0d, 0x2b,
+	0x2c, 0x86, 0x39, 0x16, 0x60, 0x57, 0x78, 0x16, 0xee, 0x40, 0xbf, 0x7f,
+	0x5a, 0x1e, 0x28, 0x4f, 0xe1, 0x07, 0x1f, 0x73, 0x86, 0x75, 0x0f, 0xc0,
+	0x87, 0x7b, 0x48, 0xf6, 0xcf, 0x00, 0x2f, 0xa6, 0x41, 0xf7, 0x80, 0x03,
+	0x1f, 0xee, 0x7c, 0xa3, 0xb4, 0xa2, 0x0c, 0xbc, 0x1d, 0xab, 0x6d, 0xf4,
+	0xdd, 0x56, 0xb0, 0x0e, 0x83, 0xf2, 0x97, 0xb5, 0x01, 0xf9, 0x6a, 0xad,
+	0x5f, 0xbe, 0x0c, 0x7b, 0xf2, 0x6c, 0xad, 0x13, 0x7b, 0x25, 0x81, 0x35,
+	0x49, 0x63, 0x7d, 0x5c, 0xf9, 0x4a, 0x2d, 0x25, 0x5f, 0x02, 0xaf, 0x9e,
+	0xc3, 0x6f, 0xb8, 0x94, 0x92, 0x5d, 0xa5, 0x7e, 0xbd, 0x46, 0x5c, 0x1f,
+	0x07, 0xf4, 0x38, 0x98, 0xbb, 0xfd, 0x54, 0x01, 0xfb, 0x6f, 0xb1, 0xe6,
+	0xbc, 0x55, 0x91, 0xc7, 0x1a, 0x19, 0x5f, 0x3e, 0xb5, 0x6a, 0x53, 0x0a,
+	0x9e, 0xe9, 0xd8, 0x47, 0x26, 0xb0, 0x0e, 0x15, 0xec, 0xd3, 0x31, 0xc5,
+	0xfb, 0x35, 0x7b, 0x53, 0xf1, 0xed, 0x4d, 0x30, 0xbf, 0xd9, 0xbc, 0x7c,
+	0x47, 0xb2, 0x73, 0xd3, 0xb2, 0xef, 0xb8, 0x27, 0xbf, 0xe3, 0x7a, 0x90,
+	0x63, 0xea, 0xdf, 0x01, 0xea, 0x75, 0x6b, 0x22, 0x6c, 0x28, 0xff, 0xc9,
+	0xc7, 0x2a, 0xbd, 0xdb, 0xb1, 0x67, 0x53, 0x19, 0x63, 0x4a, 0x92, 0x73,
+	0x53, 0xd2, 0x35, 0x07, 0x59, 0x70, 0xd9, 0xd7, 0x8a, 0x69, 0x5c, 0x26,
+	0x0f, 0x1c, 0xc7, 0x1e, 0xcc, 0x89, 0x63, 0xbe, 0x25, 0x29, 0x8c, 0x7f,
+	0x50, 0xba, 0xd1, 0xc6, 0x41, 0x9b, 0x4b, 0x6a, 0xec, 0x16, 0x8c, 0xdd,
+	0x28, 0x87, 0xe3, 0x36, 0x64, 0x8d, 0x76, 0xfb, 0xff, 0x48, 0xb6, 0xc2,
+	0xf4, 0x6f, 0x25, 0x7b, 0xea, 0x91, 0x98, 0x34, 0xf3, 0x19, 0xaa, 0x61,
+	0x81, 0xe5, 0x5d, 0x48, 0x59, 0xee, 0xc0, 0x77, 0xfe, 0x89, 0x64, 0xcf,
+	0x72, 0xec, 0xb7, 0x50, 0xfe, 0x8a, 0x64, 0x8f, 0xfd, 0x1c, 0xf9, 0x0b,
+	0x48, 0xdf, 0x46, 0x3a, 0x26, 0x5d, 0xc7, 0x24, 0x94, 0x3d, 0xfb, 0x6d,
+	0xe4, 0x23, 0x48, 0x0f, 0xa3, 0xde, 0x6d, 0xa0, 0xef, 0xaf, 0xd1, 0x5f,
+	0x06, 0x7a, 0xee, 0xc3, 0x9a, 0x7e, 0x96, 0xb3, 0x8c, 0xef, 0x0e, 0x43,
+	0xa7, 0xfd, 0x0f, 0x8f, 0xf1, 0x44, 0xf5, 0xbc, 0xc8, 0x3c, 0x75, 0x1b,
+	0x9f, 0xa7, 0xc0, 0x93, 0x83, 0xc8, 0x7b, 0xf2, 0x90, 0x4b, 0x1b, 0x73,
+	0x93, 0x8c, 0x9b, 0x05, 0xaf, 0x19, 0x58, 0xa2, 0x05, 0xfb, 0x60, 0x6a,
+	0xe7, 0xe6, 0xfb, 0xe0, 0x48, 0xcf, 0x21, 0x69, 0xda, 0x11, 0xcc, 0x3f,
+	0x98, 0xaf, 0x63, 0xfe, 0x48, 0xf1, 0xc1, 0x2e, 0x3c, 0x28, 0x9c, 0x87,
+	0x93, 0x78, 0xdc, 0xe8, 0xd9, 0xf3, 0x00, 0xf6, 0x81, 0x71, 0x96, 0x79,
+	0x7f, 0x1f, 0x18, 0x67, 0xa1, 0x1b, 0x16, 0xe0, 0x17, 0x2e, 0x74, 0x4a,
+	0xe3, 0xb1, 0xb5, 0x7d, 0xd0, 0x70, 0xec, 0x57, 0xef, 0x83, 0xc6, 0xb3,
+	0xa8, 0x77, 0x96, 0x3c, 0x43, 0x1f, 0xa7, 0xc8, 0xb3, 0x0e, 0xa4, 0x9f,
+	0xc6, 0x5c, 0x49, 0x7b, 0x23, 0x68, 0xf7, 0xb1, 0xd0, 0xcd, 0x90, 0xf7,
+	0xfb, 0x77, 0x1c, 0xd4, 0xe5, 0xff, 0xd9, 0x1b, 0x89, 0xdb, 0x65, 0x09,
+	0x91, 0xa7, 0xa8, 0x5b, 0x21, 0x0f, 0x6f, 0x69, 0x92, 0xe6, 0x03, 0xd2,
+	0x45, 0xfe, 0x55, 0x76, 0x23, 0x5f, 0xf0, 0xa2, 0x4e, 0x8b, 0xe6, 0x27,
+	0xb0, 0xd1, 0x00, 0xcb, 0x5f, 0x83, 0xcc, 0x10, 0xa3, 0xbe, 0x21, 0xfb,
+	0x66, 0x3c, 0x19, 0x77, 0x39, 0xff, 0xef, 0x63, 0xfe, 0x99, 0x1d, 0x71,
+	0x59, 0xb1, 0xe2, 0xe0, 0xc9, 0x22, 0x74, 0xfb, 0x05, 0xf1, 0xf9, 0xc0,
+	0x33, 0x89, 0x5d, 0xe2, 0x24, 0x86, 0xc5, 0x49, 0xbd, 0x09, 0x3e, 0x0c,
+	0x43, 0xf6, 0x73, 0x35, 0xca, 0xce, 0xab, 0x32, 0x04, 0x99, 0xf8, 0x9e,
+	0x6b, 0xa7, 0x80, 0x7f, 0xa0, 0x2f, 0x28, 0x17, 0x94, 0x89, 0x56, 0xa5,
+	0x93, 0x16, 0x5c, 0xfb, 0x89, 0x8a, 0x5c, 0x27, 0x0b, 0xed, 0xa4, 0x1d,
+	0xef, 0x8e, 0x29, 0x7b, 0x91, 0x9a, 0x30, 0xba, 0xa1, 0xa3, 0x53, 0x62,
+	0xf6, 0x7c, 0xb1, 0x31, 0xb8, 0xbf, 0x92, 0x9f, 0x0b, 0xc9, 0x54, 0x0f,
+	0xd7, 0x8a, 0xfd, 0x22, 0x5f, 0x29, 0x78, 0x11, 0xe7, 0x2d, 0xef, 0x64,
+	0x87, 0x25, 0x9f, 0xec, 0x59, 0x95, 0xcb, 0xb2, 0x88, 0xbf, 0x2f, 0x86,
+	0xd4, 0x7a, 0x04, 0x74, 0x07, 0x73, 0x09, 0xde, 0xf5, 0xd7, 0xbd, 0xe3,
+	0x5c, 0x28, 0xeb, 0xab, 0x7b, 0xc7, 0xba, 0x9c, 0xd6, 0x9f, 0x41, 0x9e,
+	0xec, 0x27, 0x8a, 0xf2, 0x3a, 0x64, 0x0f, 0x3c, 0x3c, 0xcb, 0x94, 0x3c,
+	0x9c, 0x82, 0xdc, 0xbf, 0x26, 0xbb, 0xe6, 0xb8, 0x67, 0x5e, 0xc3, 0x5c,
+	0x95, 0x2e, 0x81, 0x8e, 0x60, 0x7f, 0x9e, 0x4c, 0xbb, 0xdd, 0xa9, 0x53,
+	0x72, 0x5d, 0x62, 0x12, 0x7e, 0xe6, 0x84, 0xe9, 0xc9, 0xb2, 0x5b, 0x90,
+	0xe5, 0x41, 0xb4, 0xa9, 0x7c, 0x1a, 0xbf, 0x79, 0x3d, 0xb7, 0x47, 0xc0,
+	0x77, 0xdb, 0x2a, 0x1b, 0x9f, 0x01, 0xdf, 0x1f, 0x92, 0xe4, 0xb1, 0x55,
+	0x5d, 0x03, 0xb9, 0xf3, 0x75, 0x4d, 0xf2, 0xac, 0x29, 0x95, 0x92, 0x23,
+	0x1f, 0xa3, 0x0e, 0x29, 0x71, 0x5e, 0xd0, 0x31, 0x3c, 0xdf, 0x2f, 0x41,
+	0xcf, 0x94, 0xa0, 0x53, 0xa0, 0x43, 0xbe, 0x8c, 0xf2, 0x2f, 0xa1, 0xce,
+	0x73, 0xf0, 0x99, 0x9e, 0x05, 0xde, 0x3b, 0x07, 0x1c, 0xf1, 0x4c, 0x29,
+	0xa3, 0xfd, 0x57, 0x35, 0x5f, 0xd8, 0x2c, 0xe5, 0xef, 0x48, 0xa5, 0x4c,
+	0x7e, 0xfc, 0x44, 0xad, 0x6d, 0xd6, 0xdd, 0x46, 0x6c, 0x05, 0xca, 0x44,
+	0xca, 0xe5, 0x80, 0x27, 0xd4, 0x7d, 0x3c, 0x1b, 0x0a, 0x74, 0x65, 0xcb,
+	0x06, 0x5d, 0x29, 0xf2, 0x62, 0xd5, 0xc7, 0x90, 0xc4, 0xc4, 0xc5, 0x19,
+	0x6b, 0xf5, 0x0c, 0xb5, 0x08, 0xbb, 0x79, 0x1e, 0xbe, 0x45, 0x2c, 0xfd,
+	0x2d, 0x89, 0x9d, 0xf0, 0xbc, 0x1f, 0xc0, 0x6e, 0x16, 0xb0, 0x26, 0x46,
+	0x08, 0xe5, 0x4b, 0x7c, 0x47, 0xb9, 0xa7, 0x6c, 0x87, 0x78, 0x96, 0x22,
+	0x2f, 0xa3, 0xac, 0xa2, 0x7c, 0xae, 0x6f, 0x83, 0x1e, 0x4d, 0x9f, 0x2a,
+	0x63, 0xbd, 0x46, 0xc9, 0x8d, 0xa7, 0xe0, 0xd7, 0xf4, 0x99, 0x8d, 0x68,
+	0x5f, 0x5e, 0x62, 0x1b, 0x7b, 0x90, 0x57, 0xb9, 0x5e, 0x5e, 0x62, 0x79,
+	0xa7, 0x5c, 0x80, 0xff, 0x49, 0x1a, 0x2a, 0xf3, 0x69, 0xf1, 0xe3, 0xc5,
+	0xd4, 0x57, 0xa4, 0x15, 0x79, 0xf0, 0x2b, 0x5b, 0xa2, 0x9d, 0x8d, 0x48,
+	0x21, 0x41, 0x5e, 0x27, 0xe4, 0xfc, 0xcc, 0x1f, 0x37, 0x31, 0x1e, 0x9b,
+	0x75, 0xf8, 0x1c, 0xc4, 0x37, 0xcc, 0x77, 0x10, 0xdf, 0x60, 0x4c, 0x23,
+	0x02, 0x5b, 0xa6, 0xe2, 0x1c, 0x48, 0xad, 0x3a, 0x9f, 0x97, 0xef, 0x7d,
+	0x6c, 0xb4, 0x86, 0x19, 0x89, 0x21, 0x39, 0x5f, 0xbb, 0xb0, 0x02, 0xfd,
+	0xd1, 0x9e, 0x7e, 0x49, 0xee, 0x5e, 0xf0, 0xe7, 0x67, 0x9c, 0x12, 0xde,
+	0xe3, 0x91, 0x4b, 0xf3, 0xb6, 0x7b, 0x51, 0x78, 0x06, 0xe2, 0x62, 0xbd,
+	0xfe, 0xa0, 0x09, 0xfa, 0x6b, 0x30, 0x63, 0x7c, 0xbb, 0xc9, 0xc7, 0x67,
+	0x11, 0x99, 0x9a, 0xe1, 0x99, 0x2b, 0x74, 0x1b, 0x70, 0xe3, 0xef, 0x45,
+	0xf0, 0x5c, 0x65, 0x1e, 0x7e, 0xa8, 0xef, 0xc3, 0xe2, 0xd9, 0xef, 0x8f,
+	0x3c, 0x37, 0x16, 0x38, 0xf7, 0x90, 0xdc, 0x0d, 0x74, 0x22, 0xe8, 0xbf,
+	0x4b, 0x8f, 0xd5, 0x75, 0x2a, 0xc5, 0xf8, 0xb5, 0x24, 0xa1, 0x2f, 0xb2,
+	0xf0, 0x1f, 0x73, 0xf1, 0x4e, 0x8d, 0xc7, 0xf9, 0x6e, 0x23, 0xde, 0x0c,
+	0xfc, 0xba, 0x94, 0x7c, 0xbe, 0x14, 0x60, 0xbd, 0x14, 0x6c, 0xac, 0x44,
+	0x46, 0x7a, 0x3d, 0xf9, 0x81, 0x4b, 0x7e, 0xf5, 0x23, 0xef, 0xca, 0x91,
+	0xda, 0x2f, 0x3b, 0x5b, 0xad, 0xff, 0x6b, 0x01, 0x8d, 0xfc, 0x81, 0x3e,
+	0xe0, 0x23, 0xd2, 0x6e, 0xc0, 0x9e, 0x17, 0x81, 0xbb, 0x8c, 0x33, 0x9d,
+	0xea, 0x9d, 0x01, 0x6c, 0x50, 0x99, 0x81, 0x6e, 0x3c, 0xc3, 0xf3, 0x66,
+	0xe8, 0xb6, 0x33, 0x51, 0x29, 0xce, 0x52, 0x2e, 0xa5, 0xdd, 0xc0, 0x7a,
+	0xb1, 0x7e, 0x65, 0xa6, 0x13, 0x69, 0x0b, 0x52, 0x4b, 0xf5, 0x53, 0x99,
+	0x71, 0x54, 0xfb, 0xca, 0x4c, 0x4a, 0xb5, 0xab, 0xcc, 0xf4, 0x23, 0x75,
+	0xa5, 0xe1, 0x0c, 0x9c, 0xa5, 0x33, 0x3d, 0x32, 0x75, 0x12, 0xf6, 0x65,
+	0xc0, 0x50, 0x77, 0x35, 0x26, 0x60, 0x7f, 0x22, 0xf0, 0xac, 0x2e, 0x9a,
+	0x83, 0xc0, 0x58, 0x37, 0x01, 0x83, 0xdc, 0x24, 0xce, 0x09, 0xce, 0x9f,
+	0xba, 0xf7, 0x3c, 0x63, 0x5e, 0x89, 0x4f, 0x48, 0x46, 0xf6, 0xcf, 0x36,
+	0x62, 0xbf, 0x46, 0xcc, 0xa2, 0x74, 0x9b, 0xc3, 0xc8, 0xe7, 0xcb, 0xe4,
+	0xdb, 0xbd, 0xca, 0x5f, 0xcb, 0xba, 0x37, 0x34, 0x4b, 0x73, 0x1a, 0x63,
+	0xbc, 0x93, 0xf6, 0xbd, 0x90, 0x3f, 0x47, 0xf7, 0x91, 0x06, 0x3d, 0xf5,
+	0xfc, 0xe0, 0x39, 0x73, 0xe6, 0x57, 0x9c, 0x33, 0x53, 0xae, 0xc9, 0xdf,
+	0x7b, 0xe5, 0xbc, 0x93, 0x96, 0x97, 0x9d, 0x94, 0x5c, 0x70, 0x76, 0xca,
+	0x37, 0x61, 0xa7, 0x5f, 0x72, 0xce, 0x34, 0x11, 0x0b, 0x54, 0xd4, 0xd9,
+	0x5d, 0xb0, 0x56, 0x8e, 0x8e, 0x9d, 0xff, 0x50, 0x96, 0x67, 0x88, 0x9d,
+	0xbd, 0xdb, 0xf6, 0xb9, 0x05, 0xda, 0x2d, 0xd0, 0x40, 0xac, 0x56, 0x80,
+	0xfd, 0x3b, 0x24, 0xc3, 0x2e, 0xed, 0x9e, 0xb2, 0x51, 0x89, 0x61, 0x7f,
+	0x3f, 0xbb, 0x79, 0xe8, 0xd5, 0xf3, 0xb3, 0xd8, 0x4f, 0x42, 0xf9, 0xc7,
+	0x73, 0x99, 0xeb, 0xee, 0xc8, 0xe3, 0x25, 0xce, 0xb3, 0xb8, 0xbd, 0x59,
+	0xc2, 0x32, 0xa2, 0xf0, 0x42, 0xab, 0xbc, 0xb8, 0xb4, 0x45, 0x0c, 0x58,
+	0x28, 0xe3, 0xda, 0xa8, 0xba, 0xe5, 0x42, 0x9f, 0x5b, 0xda, 0x78, 0xb6,
+	0xf6, 0x87, 0xe0, 0x0d, 0xfd, 0x7f, 0xcc, 0xad, 0x8d, 0x33, 0x09, 0xf2,
+	0xfd, 0xd8, 0x5f, 0x7c, 0x0e, 0x49, 0xce, 0x89, 0xe3, 0x99, 0x29, 0xf7,
+	0x1c, 0x63, 0x63, 0x61, 0xf1, 0x31, 0xf7, 0x21, 0xf5, 0xbe, 0xd1, 0xb9,
+	0x15, 0xb8, 0x8e, 0xf2, 0x8a, 0x74, 0xd9, 0x1f, 0x37, 0x07, 0x1c, 0x97,
+	0xef, 0xe7, 0x1d, 0x1b, 0x3b, 0x55, 0xc0, 0x5e, 0x98, 0x50, 0xf5, 0x07,
+	0xe4, 0xa5, 0x99, 0x52, 0xb3, 0xbf, 0x3f, 0x06, 0xf5, 0x33, 0xdf, 0xd3,
+	0xa7, 0x62, 0x8c, 0xe4, 0x99, 0xd1, 0x69, 0xe7, 0xa2, 0xde, 0x3f, 0x12,
+	0xba, 0xb3, 0x17, 0x38, 0xf4, 0x68, 0x03, 0xe6, 0x62, 0x5b, 0x56, 0xc8,
+	0xe8, 0x30, 0x80, 0xe3, 0x87, 0x95, 0xcd, 0xed, 0x55, 0x31, 0xe8, 0x53,
+	0xa9, 0x56, 0xa9, 0x98, 0x8e, 0xba, 0x93, 0xb7, 0x62, 0xee, 0x20, 0xd6,
+	0xc7, 0xaf, 0x09, 0x65, 0xdd, 0x48, 0x1b, 0x91, 0xbe, 0x5f, 0x8a, 0xc7,
+	0xcf, 0xe8, 0xf1, 0xa2, 0x1b, 0xf2, 0x1f, 0xd1, 0xe9, 0x67, 0xb5, 0x3f,
+	0xc5, 0x71, 0xa2, 0xe2, 0x7c, 0xa1, 0x45, 0xba, 0x8f, 0x9a, 0xc0, 0xb6,
+	0x09, 0x60, 0xdd, 0x4e, 0x49, 0x1d, 0xb5, 0xe4, 0xda, 0xa3, 0x41, 0x9c,
+	0xe9, 0x2b, 0xa3, 0x49, 0x15, 0xd7, 0xfc, 0xf2, 0xa8, 0x53, 0x56, 0xe7,
+	0xed, 0xfa, 0xee, 0xe0, 0x8a, 0xbe, 0x53, 0xf8, 0xca, 0x68, 0xaf, 0x4a,
+	0xbf, 0x3d, 0x9a, 0x52, 0xe9, 0xab, 0xa3, 0xd7, 0x56, 0x7d, 0xff, 0xa8,
+	0xb8, 0x98, 0x92, 0xcf, 0x95, 0x88, 0x2f, 0x07, 0x80, 0x1d, 0x5d, 0xe8,
+	0x99, 0x7e, 0xe8, 0x99, 0x14, 0xf4, 0xcc, 0x20, 0xf5, 0x0c, 0xf4, 0xf6,
+	0xab, 0xd0, 0xdb, 0xae, 0x7c, 0x0f, 0xf2, 0xfa, 0x8c, 0xdb, 0x08, 0x5c,
+	0xe8, 0x79, 0xfe, 0x5c, 0xed, 0x27, 0x56, 0xb0, 0xbe, 0x95, 0xd3, 0x12,
+	0x6b, 0x83, 0x0e, 0xda, 0xb1, 0xd0, 0x20, 0x8b, 0x71, 0xcf, 0x9b, 0x73,
+	0x1d, 0xb9, 0x84, 0xfa, 0x59, 0x87, 0xfb, 0xf8, 0x6f, 0x9a, 0xe9, 0x8f,
+	0x5d, 0x9a, 0xd9, 0x09, 0x9d, 0x44, 0x79, 0x8f, 0x49, 0x65, 0x3c, 0x21,
+	0x4b, 0xf0, 0xcf, 0xd6, 0xea, 0xa4, 0xf0, 0xcc, 0xfd, 0xff, 0x13, 0xd4,
+	0x4d, 0xc1, 0x3e, 0x98, 0xb2, 0xdc, 0x6b, 0xc9, 0xa9, 0x5e, 0x7b, 0xd0,
+	0x32, 0xa8, 0xbb, 0x2c, 0x29, 0xc3, 0xbf, 0xaf, 0x94, 0x58, 0x9f, 0xf5,
+	0xb0, 0x3f, 0x4b, 0x7e, 0xbb, 0xe9, 0x52, 0xa0, 0x27, 0x06, 0x18, 0x7b,
+	0x8c, 0xe4, 0x7a, 0x7d, 0x1b, 0x60, 0x18, 0x8d, 0x90, 0x03, 0x17, 0xfc,
+	0x1f, 0x47, 0xf9, 0x00, 0xef, 0x9a, 0xa0, 0x8c, 0x58, 0x28, 0xb6, 0x85,
+	0x18, 0x31, 0xe7, 0x8e, 0xa3, 0x8c, 0x6d, 0xec, 0x44, 0x12, 0xe5, 0x63,
+	0x92, 0x4c, 0xe4, 0xd5, 0xbd, 0xb7, 0x0e, 0x94, 0xb1, 0x8f, 0xb0, 0x8e,
+	0xc1, 0x74, 0x6c, 0xf1, 0xcf, 0x7d, 0x83, 0xf2, 0x3e, 0x15, 0x0f, 0xc8,
+	0x98, 0x2e, 0xf6, 0x03, 0xcb, 0x92, 0x26, 0xdb, 0xe5, 0x5c, 0x57, 0xe9,
+	0xc2, 0x7b, 0xaa, 0x3c, 0xb7, 0x8b, 0xc9, 0xdd, 0xd5, 0x16, 0xc9, 0x55,
+	0x1b, 0xae, 0xa0, 0xff, 0x83, 0x3d, 0x79, 0x3e, 0x61, 0x0a, 0xef, 0x60,
+	0xf8, 0xfb, 0x3c, 0xb2, 0x93, 0x7b, 0x02, 0x7c, 0x87, 0xfd, 0x7d, 0x0e,
+	0xf3, 0x7d, 0x16, 0xf6, 0xf7, 0x1c, 0xec, 0xef, 0x33, 0xa5, 0x35, 0xfd,
+	0xe1, 0xdb, 0x5d, 0xea, 0x80, 0xa7, 0xb0, 0x66, 0x63, 0xc0, 0xfd, 0xbb,
+	0xe1, 0x0f, 0x8c, 0x00, 0xfb, 0x0f, 0x61, 0xfd, 0xd2, 0x58, 0xbb, 0x71,
+	0xde, 0x55, 0xc2, 0x3a, 0x0e, 0xaa, 0xb3, 0xe5, 0x59, 0x75, 0xdf, 0xe3,
+	0x87, 0xca, 0xf6, 0x3e, 0x56, 0x32, 0x60, 0x1f, 0x0a, 0xde, 0x76, 0xc7,
+	0x06, 0xfe, 0x5b, 0xdd, 0xcf, 0x83, 0x2f, 0x42, 0xaf, 0xfc, 0x1d, 0xe8,
+	0x7a, 0x76, 0x96, 0xf6, 0x1c, 0x75, 0x7c, 0xbc, 0xed, 0x32, 0xbe, 0x85,
+	0xfd, 0x7c, 0xe4, 0xbc, 0xac, 0x00, 0x77, 0x64, 0x28, 0xc7, 0xf0, 0x1f,
+	0xec, 0x67, 0xca, 0xd2, 0x43, 0x1d, 0x58, 0xe6, 0x5e, 0x19, 0x38, 0x96,
+	0x00, 0xd6, 0x03, 0x92, 0x57, 0x67, 0xa9, 0x78, 0x3e, 0xbb, 0x55, 0x0c,
+	0xe2, 0x3d, 0xf7, 0x2a, 0x94, 0x51, 0x6f, 0x04, 0x18, 0x69, 0x65, 0xb0,
+	0x5d, 0x32, 0x3b, 0xda, 0x95, 0xee, 0xb0, 0xdd, 0x97, 0x31, 0xee, 0x2e,
+	0x69, 0x04, 0x86, 0x2b, 0x60, 0x8c, 0x83, 0xf2, 0x37, 0x2e, 0xe3, 0x52,
+	0xbe, 0xef, 0x07, 0x5a, 0x62, 0xe0, 0x59, 0xd3, 0x3e, 0xc7, 0x8c, 0xed,
+	0xaa, 0xb1, 0xff, 0x98, 0xc2, 0x58, 0x39, 0x61, 0xff, 0xb0, 0x13, 0x18,
+	0x33, 0x79, 0x8c, 0xb2, 0xdf, 0x87, 0x75, 0xfb, 0x2d, 0x60, 0x20, 0x72,
+	0xf5, 0x5b, 0x5b, 0xfc, 0xfd, 0x42, 0xfa, 0x57, 0x88, 0x27, 0x18, 0xf7,
+	0xf7, 0xfd, 0xf2, 0x55, 0xda, 0x06, 0x40, 0xef, 0x73, 0x5b, 0x82, 0xf3,
+	0xe3, 0xae, 0x63, 0xbe, 0xbd, 0xee, 0x3a, 0x8b, 0x56, 0x73, 0xd2, 0xc1,
+	0x93, 0x68, 0x43, 0xae, 0x95, 0xdb, 0x23, 0x7e, 0x3f, 0xc6, 0x82, 0x09,
+	0x59, 0xa5, 0x1e, 0xe8, 0x80, 0x9c, 0x33, 0x4f, 0x9d, 0x42, 0x9d, 0x40,
+	0x59, 0x70, 0xa4, 0x58, 0x83, 0x4e, 0x68, 0xed, 0x94, 0x32, 0x79, 0xb6,
+	0x40, 0x3d, 0xf1, 0x43, 0x99, 0xde, 0xa0, 0x2b, 0x87, 0x24, 0xf0, 0x6b,
+	0x5b, 0x24, 0x9a, 0x76, 0xcc, 0x7b, 0xd4, 0x1c, 0x7d, 0x7d, 0xb9, 0x9f,
+	0xf8, 0x73, 0x36, 0x63, 0xb7, 0x8b, 0xc6, 0x9e, 0x0a, 0x3f, 0x7d, 0x1f,
+	0x73, 0x65, 0x1f, 0x8a, 0x4f, 0x83, 0x43, 0xbe, 0x2f, 0xa0, 0xe2, 0x7c,
+	0xc0, 0xc1, 0x89, 0xbf, 0x83, 0xae, 0xcd, 0x11, 0x97, 0x80, 0xcf, 0x5d,
+	0x73, 0x94, 0xa3, 0xed, 0xd4, 0x65, 0xc0, 0x79, 0x29, 0xea, 0x6b, 0x59,
+	0x3a, 0x06, 0xcc, 0x65, 0xdc, 0x2a, 0x79, 0xca, 0x2b, 0xef, 0x48, 0x2c,
+	0x19, 0x32, 0x3d, 0xdf, 0x2a, 0xdd, 0x0b, 0x8c, 0xa9, 0x7e, 0xb3, 0x59,
+	0x5a, 0x19, 0x57, 0xa5, 0x0d, 0x1a, 0x90, 0x1c, 0xca, 0xbb, 0x16, 0xc2,
+	0x2a, 0x06, 0x56, 0x36, 0xc8, 0xa3, 0x7e, 0xe8, 0x03, 0x3b, 0xb5, 0x62,
+	0x7c, 0xb4, 0xc9, 0xc7, 0x90, 0x90, 0xa5, 0x12, 0x64, 0xac, 0x04, 0x19,
+	0x2b, 0x41, 0xc6, 0x4a, 0x90, 0x31, 0x60, 0xbf, 0x67, 0xb1, 0xff, 0xce,
+	0x95, 0x06, 0xb5, 0x5d, 0xdf, 0xa3, 0xec, 0xfa, 0xe1, 0xd2, 0xab, 0x1e,
+	0xd3, 0x2f, 0x29, 0xdf, 0xb4, 0x1f, 0x32, 0x48, 0x5f, 0x34, 0xf0, 0x51,
+	0x5f, 0x95, 0xa7, 0x66, 0x5f, 0x93, 0x53, 0xb3, 0x6b, 0x38, 0x70, 0xaa,
+	0xe4, 0xc9, 0xcb, 0x2e, 0xfc, 0xcf, 0x45, 0x62, 0xaa, 0x4c, 0x5b, 0xa3,
+	0xc2, 0x56, 0x87, 0x24, 0xaf, 0x70, 0xb2, 0xb2, 0x23, 0xc0, 0x57, 0x0a,
+	0x17, 0x72, 0x6f, 0x4a, 0xfb, 0x8e, 0xd7, 0xe5, 0x1c, 0xec, 0xf8, 0x52,
+	0xed, 0x0d, 0x79, 0x4e, 0xe1, 0x71, 0xf2, 0xe1, 0x7d, 0xf2, 0xb7, 0xa6,
+	0x7f, 0x86, 0x7f, 0x0a, 0x58, 0x63, 0xa9, 0x97, 0xba, 0x23, 0x02, 0x5b,
+	0x60, 0x17, 0xba, 0xb0, 0xaf, 0x0f, 0x18, 0xef, 0x02, 0xa6, 0xe1, 0xfb,
+	0xad, 0xf2, 0xe2, 0x6c, 0xa1, 0x4e, 0x26, 0xa8, 0x1f, 0xec, 0x23, 0x62,
+	0xd0, 0x4e, 0xd1, 0x6e, 0x72, 0xbe, 0xb4, 0x53, 0x6d, 0x2d, 0xbc, 0x3f,
+	0x56, 0x39, 0x7e, 0xc3, 0x16, 0xc6, 0x18, 0xe3, 0x0e, 0x79, 0xfa, 0xba,
+	0x1c, 0xa8, 0xb2, 0xec, 0x35, 0xac, 0x0f, 0xd3, 0x37, 0xbd, 0xbb, 0xe3,
+	0x1c, 0x8f, 0xfd, 0x02, 0x37, 0x75, 0x60, 0xae, 0xa5, 0xcf, 0x6a, 0xcc,
+	0xdd, 0xaf, 0x70, 0xf4, 0xe5, 0x78, 0x99, 0x7c, 0x72, 0xc1, 0xa7, 0xd7,
+	0x55, 0x0c, 0x70, 0x93, 0xd8, 0xf0, 0x13, 0xd8, 0x57, 0x85, 0x8b, 0xc2,
+	0x38, 0x25, 0x63, 0xb8, 0x8c, 0x0f, 0xd7, 0x6b, 0x0c, 0x75, 0x57, 0x40,
+	0xee, 0x82, 0x7e, 0xb9, 0x1b, 0xfa, 0xe5, 0x9e, 0xcb, 0xee, 0x5f, 0x07,
+	0x71, 0xff, 0xee, 0x42, 0xd8, 0xe8, 0x94, 0xb1, 0x6a, 0x7d, 0x5b, 0xc6,
+	0x6e, 0x37, 0x8b, 0xd5, 0x32, 0x8e, 0x9b, 0xda, 0x10, 0xff, 0xa3, 0x6c,
+	0x78, 0xf2, 0x92, 0xcb, 0xb8, 0x5b, 0x70, 0x67, 0x7f, 0x33, 0xfc, 0x65,
+	0xb5, 0x04, 0x71, 0xe6, 0x48, 0xfa, 0xa2, 0xf0, 0xee, 0x7e, 0x71, 0x86,
+	0x78, 0x20, 0xae, 0xee, 0xd9, 0x19, 0x2a, 0xce, 0xe7, 0xb7, 0x2d, 0xce,
+	0xa8, 0x73, 0xa5, 0x02, 0xe3, 0xd5, 0xe6, 0x4e, 0xdb, 0x1c, 0x0b, 0xfb,
+	0xf7, 0x65, 0xb8, 0x97, 0x7d, 0x5d, 0x06, 0x59, 0xac, 0xad, 0xdd, 0xb1,
+	0x1c, 0x52, 0xfa, 0xe2, 0x22, 0xf6, 0x00, 0xd7, 0x0b, 0xfe, 0x02, 0xf6,
+	0xc9, 0x14, 0xf4, 0x53, 0x5e, 0xf5, 0x17, 0xa3, 0x5c, 0x64, 0xb2, 0x61,
+	0x43, 0xa2, 0x27, 0xe8, 0x0b, 0xf9, 0xb1, 0x96, 0x5c, 0xd8, 0x56, 0xfa,
+	0x1b, 0xb4, 0x03, 0x9f, 0x71, 0x7f, 0x5a, 0x13, 0x8d, 0xe9, 0x06, 0xd8,
+	0x55, 0xac, 0x5f, 0x8d, 0x31, 0x01, 0xec, 0xdd, 0xe5, 0xef, 0xca, 0xfe,
+	0xf9, 0xe1, 0x16, 0x5f, 0xfe, 0x19, 0x3b, 0xe6, 0xfc, 0x02, 0x1a, 0xd6,
+	0xf7, 0x6d, 0x9c, 0x90, 0x58, 0x33, 0x6c, 0xda, 0x87, 0xe1, 0x67, 0xec,
+	0x82, 0xac, 0xac, 0xc4, 0xd9, 0xaf, 0xbf, 0x67, 0xa6, 0x4b, 0xec, 0xfb,
+	0xbb, 0x32, 0x3c, 0x7f, 0xb6, 0x85, 0xb6, 0x64, 0x19, 0x7a, 0xe0, 0xbc,
+	0x49, 0x1b, 0x3a, 0x0e, 0x1b, 0xd7, 0x21, 0xdf, 0x9f, 0xa7, 0x7d, 0x4c,
+	0x9a, 0xa7, 0xa4, 0x2f, 0x71, 0x0a, 0x34, 0x7d, 0xde, 0x8d, 0xd0, 0x47,
+	0xf3, 0x86, 0x50, 0xf6, 0x4d, 0x49, 0x9a, 0x5d, 0x21, 0x3e, 0xf7, 0x99,
+	0x8f, 0x03, 0xc3, 0x66, 0xcc, 0xa4, 0x79, 0x5d, 0x88, 0x72, 0x04, 0x9f,
+	0x7b, 0x79, 0x8d, 0xce, 0x37, 0xe7, 0x95, 0x9f, 0xa4, 0xf4, 0xcc, 0xb2,
+	0xcb, 0xf1, 0x40, 0xb7, 0xd2, 0x59, 0xd7, 0x41, 0x9f, 0xc4, 0xf4, 0x99,
+	0x1b, 0xda, 0x10, 0xdb, 0xb8, 0x11, 0x9d, 0x7f, 0x44, 0xb2, 0x27, 0xe3,
+	0xd0, 0x67, 0xec, 0x2b, 0xf0, 0x1d, 0x68, 0x23, 0x03, 0xbc, 0x4d, 0x7b,
+	0x77, 0x2b, 0xec, 0xde, 0x35, 0x8a, 0x9e, 0x11, 0xb7, 0x5f, 0xa6, 0x8e,
+	0x73, 0xec, 0x5e, 0xe8, 0xf2, 0x84, 0x92, 0xdb, 0x62, 0xe9, 0x7c, 0x22,
+	0x06, 0x9d, 0x1c, 0xdb, 0x41, 0x7e, 0x7e, 0x50, 0xee, 0x70, 0xc6, 0xe5,
+	0x4e, 0xc8, 0xce, 0x90, 0xe3, 0xca, 0x30, 0xd6, 0x62, 0x97, 0x03, 0xbb,
+	0xa3, 0x30, 0x74, 0x23, 0xfc, 0x2e, 0x8e, 0xdd, 0xa1, 0xef, 0x5c, 0xf8,
+	0xf8, 0xf1, 0xcf, 0x6a, 0x3e, 0x8f, 0xb2, 0xf3, 0x2f, 0x2b, 0xde, 0x8c,
+	0xb8, 0x37, 0x69, 0x3b, 0xdb, 0x2a, 0x39, 0x55, 0xef, 0x26, 0x65, 0x8f,
+	0x8b, 0x4b, 0xf7, 0x22, 0x85, 0x6d, 0x5e, 0x82, 0xbe, 0x01, 0xe6, 0x2e,
+	0x56, 0x77, 0x22, 0x0f, 0x1b, 0xba, 0x94, 0x46, 0xfa, 0x41, 0xa4, 0xac,
+	0xfb, 0xb9, 0x16, 0x3f, 0x96, 0x5b, 0x7f, 0x87, 0xcc, 0xbf, 0x7f, 0xfa,
+	0x61, 0x85, 0x4b, 0x2f, 0xaa, 0xfb, 0x87, 0x06, 0xb0, 0x4e, 0x16, 0x7a,
+	0xa5, 0x05, 0x18, 0x68, 0xe6, 0x84, 0x9d, 0x1a, 0x0e, 0xdd, 0x26, 0x1f,
+	0x81, 0x2f, 0x5f, 0x71, 0xb9, 0x96, 0x3b, 0xe5, 0x13, 0xb7, 0x50, 0x46,
+	0x6e, 0x93, 0x7d, 0xb7, 0x84, 0x64, 0x5f, 0xbf, 0x9d, 0x21, 0xdd, 0xd7,
+	0xbe, 0x3f, 0xf0, 0xa7, 0xbb, 0x47, 0x92, 0xa1, 0x01, 0x79, 0x1c, 0x32,
+	0x56, 0x80, 0x7c, 0x0d, 0xd7, 0xc8, 0x73, 0xea, 0x7b, 0xea, 0xf9, 0x14,
+	0xb0, 0x72, 0x80, 0xfd, 0x1c, 0x99, 0xa9, 0x35, 0x88, 0x75, 0x15, 0xe3,
+	0xc9, 0x96, 0x7f, 0xae, 0x71, 0x15, 0x65, 0x02, 0x3e, 0xc8, 0x55, 0xfe,
+	0xfe, 0x54, 0xf7, 0xfe, 0xae, 0xf2, 0xed, 0x0a, 0xfc, 0x5f, 0x8f, 0x38,
+	0xcf, 0xbf, 0x5f, 0x70, 0x51, 0xeb, 0xd2, 0xe4, 0xd6, 0x55, 0x7c, 0xd7,
+	0x4a, 0xff, 0xe1, 0xeb, 0x2d, 0x6b, 0xdf, 0x2d, 0x6c, 0x94, 0xc5, 0x20,
+	0xee, 0x56, 0xc6, 0x9c, 0x69, 0xd3, 0x6d, 0x93, 0xba, 0xb0, 0xcd, 0xd9,
+	0x23, 0x7f, 0x09, 0xfb, 0xfe, 0xd5, 0x55, 0xfb, 0xbe, 0x17, 0xfc, 0xd8,
+	0x88, 0x01, 0x1c, 0xf3, 0x2e, 0xcc, 0x65, 0x04, 0xeb, 0x79, 0x27, 0x7e,
+	0x77, 0x94, 0xd6, 0xc5, 0xf1, 0x66, 0x0b, 0xc0, 0x93, 0x0d, 0x0e, 0xfb,
+	0x5b, 0x17, 0xcf, 0x2b, 0xe4, 0x65, 0x35, 0x56, 0x38, 0x78, 0x49, 0x68,
+	0xf7, 0xde, 0x92, 0x68, 0x8f, 0xf3, 0x56, 0x57, 0xc8, 0x79, 0xde, 0x08,
+	0xf1, 0xec, 0xdb, 0x95, 0xd3, 0x35, 0xe2, 0xb0, 0x0b, 0x62, 0x9c, 0x25,
+	0x06, 0x7b, 0x45, 0xc5, 0xa0, 0x2a, 0xa5, 0x6f, 0x23, 0x45, 0x7d, 0xe8,
+	0xc7, 0xb0, 0x1f, 0xa7, 0x50, 0x58, 0x85, 0x7a, 0xf6, 0x4e, 0xac, 0xc3,
+	0x14, 0x7e, 0x5d, 0x3b, 0xae, 0xc3, 0xfe, 0xa5, 0x9c, 0x32, 0xf6, 0xd5,
+	0x63, 0xee, 0x08, 0xf1, 0xdd, 0x66, 0x71, 0xb0, 0xef, 0x48, 0x64, 0x0e,
+	0xb6, 0xce, 0xa0, 0x7e, 0xe0, 0x3c, 0x68, 0x27, 0x4d, 0x59, 0x3c, 0xce,
+	0xbd, 0xbe, 0x59, 0xfd, 0xa0, 0x6e, 0x30, 0x17, 0x65, 0x37, 0x32, 0x79,
+	0xc6, 0x38, 0x4b, 0x5c, 0x03, 0x17, 0x6b, 0xe0, 0xc9, 0x09, 0xb7, 0x0d,
+	0x7a, 0x3b, 0x2e, 0xe1, 0x13, 0x9e, 0x0c, 0x29, 0xec, 0xda, 0x07, 0xcc,
+	0xb5, 0x55, 0xe3, 0x86, 0xb8, 0x44, 0x4e, 0x74, 0x4a, 0x23, 0x70, 0x75,
+	0xc3, 0x51, 0xda, 0xc8, 0xa4, 0x35, 0x04, 0x21, 0x88, 0xa8, 0xbb, 0xac,
+	0xf6, 0xe0, 0xf7, 0xa5, 0xcf, 0xfa, 0xbe, 0x10, 0x2f, 0xfd, 0x7b, 0xac,
+	0x9f, 0xed, 0x5e, 0xd8, 0xa4, 0x7e, 0x71, 0xad, 0x3e, 0xe4, 0x88, 0xb1,
+	0x35, 0xb6, 0x61, 0xac, 0x2d, 0x39, 0xf8, 0x3d, 0xc6, 0xd8, 0xe0, 0x6b,
+	0x36, 0x9c, 0xf1, 0x69, 0x30, 0x96, 0xdb, 0xa5, 0x72, 0x92, 0x7b, 0x94,
+	0x71, 0x16, 0xd3, 0xf7, 0x53, 0x4b, 0xf4, 0x57, 0xf9, 0xde, 0xd2, 0xef,
+	0xbb, 0xf4, 0x7b, 0xfa, 0xa3, 0x05, 0xaf, 0x01, 0x3c, 0xdd, 0x05, 0xfd,
+	0x79, 0xef, 0x4e, 0x47, 0xe1, 0x86, 0x7b, 0x57, 0xd7, 0x6c, 0xb7, 0xba,
+	0x4f, 0x54, 0x29, 0x1d, 0x12, 0x67, 0xc7, 0x4a, 0x2a, 0x22, 0x63, 0x58,
+	0x0b, 0xe6, 0x33, 0xa4, 0x27, 0x75, 0x58, 0x0e, 0xa8, 0xb5, 0xa9, 0x1c,
+	0xb7, 0x8f, 0x58, 0xa1, 0x29, 0x31, 0x2a, 0x7c, 0xfe, 0x34, 0xd2, 0xc3,
+	0xc0, 0x3b, 0x7e, 0xec, 0xd2, 0xa8, 0xac, 0xe7, 0x25, 0x30, 0x86, 0xb9,
+	0x6b, 0x5d, 0x1c, 0x6b, 0x2d, 0xc6, 0xc5, 0xf7, 0x43, 0xea, 0x7d, 0x6a,
+	0x5d, 0x9c, 0x2b, 0x67, 0x10, 0xcb, 0x04, 0xef, 0xb9, 0x16, 0x5c, 0x2f,
+	0xd8, 0xe2, 0xe3, 0x41, 0xcc, 0xab, 0x55, 0xaf, 0x0b, 0xd7, 0x67, 0x46,
+	0xce, 0x99, 0xf6, 0x08, 0xe5, 0xef, 0x86, 0x9d, 0x57, 0xcb, 0x44, 0x07,
+	0xe3, 0x6d, 0xf5, 0x34, 0x6c, 0x8c, 0xa3, 0xd5, 0x8f, 0xbf, 0x31, 0xfe,
+	0xc6, 0xb1, 0xfd, 0x18, 0x5b, 0x76, 0x5d, 0x8c, 0xad, 0x7e, 0x3c, 0x8e,
+	0xb5, 0x15, 0xfe, 0x53, 0xc1, 0x8b, 0x3b, 0x5c, 0xa3, 0x6e, 0x6b, 0x9e,
+	0xf9, 0x2f, 0x1a, 0x58, 0xc7, 0x38, 0xec, 0x08, 0xd7, 0x32, 0x38, 0x6f,
+	0xe6, 0x9a, 0x26, 0xad, 0xc3, 0xfe, 0x7a, 0x0e, 0xfa, 0xeb, 0xee, 0xaf,
+	0xff, 0x85, 0xd5, 0x75, 0xa4, 0x7d, 0xe0, 0x3a, 0x76, 0x88, 0x40, 0xcf,
+	0x1a, 0x47, 0xb9, 0x86, 0x4c, 0xb9, 0x86, 0x7c, 0xc7, 0x35, 0xec, 0xd2,
+	0xef, 0xb8, 0x7e, 0xc0, 0x69, 0x5f, 0xe0, 0x3d, 0xd5, 0xac, 0xfa, 0x06,
+	0xab, 0xab, 0x27, 0xd8, 0x8b, 0x29, 0x79, 0x6e, 0xb1, 0x59, 0xcc, 0xb4,
+	0x3f, 0xaf, 0xf1, 0x75, 0xf1, 0x76, 0x9e, 0x5f, 0xf5, 0x13, 0x7b, 0x06,
+	0xf3, 0x4a, 0x70, 0x5e, 0x07, 0xe4, 0x75, 0xc9, 0xcf, 0x44, 0xe0, 0x03,
+	0xa6, 0x80, 0x73, 0xfa, 0xa1, 0x6f, 0x19, 0x1f, 0x45, 0x59, 0x95, 0x78,
+	0x85, 0xb6, 0x2e, 0x85, 0xbd, 0x42, 0x1d, 0x4c, 0x3c, 0xf2, 0x9a, 0xe4,
+	0xca, 0x81, 0x8e, 0x41, 0xff, 0x46, 0xd0, 0x3f, 0xf9, 0x9c, 0xb9, 0x76,
+	0xbb, 0xac, 0x58, 0xdb, 0xc5, 0xb6, 0x96, 0x64, 0x6d, 0x5d, 0xc7, 0x37,
+	0xe7, 0xbb, 0x7b, 0x6f, 0x78, 0x4d, 0x36, 0xc6, 0x37, 0x59, 0xfb, 0x49,
+	0x09, 0xde, 0x07, 0x6b, 0xbf, 0xe9, 0x3a, 0x14, 0x5e, 0x15, 0xae, 0x05,
+	0x79, 0x40, 0x3c, 0x1c, 0x95, 0x7f, 0x13, 0xe7, 0x7e, 0x2c, 0xa8, 0x33,
+	0xcd, 0xa4, 0xd1, 0xa3, 0x74, 0xc6, 0x90, 0xeb, 0xcb, 0x6b, 0x01, 0xe3,
+	0xc4, 0xba, 0xff, 0xd0, 0x1b, 0x8a, 0xc3, 0xcf, 0xed, 0xa6, 0x7e, 0x09,
+	0xf6, 0x74, 0xb3, 0xda, 0xd3, 0x9f, 0x77, 0x43, 0x52, 0x74, 0x42, 0x32,
+	0xe5, 0x1c, 0x52, 0x18, 0xff, 0xa3, 0xe8, 0xeb, 0x13, 0xba, 0xaf, 0x29,
+	0xe9, 0xd1, 0xfa, 0xe7, 0x20, 0xe4, 0xdc, 0x93, 0x7b, 0xdc, 0x9d, 0x72,
+	0x43, 0x1b, 0xf7, 0x40, 0x30, 0xff, 0x43, 0xd2, 0xbd, 0x73, 0xc5, 0x82,
+	0x67, 0x70, 0x6d, 0x74, 0x95, 0x07, 0xdc, 0x67, 0x81, 0x7c, 0xfb, 0x7c,
+	0xf0, 0xe7, 0xbf, 0x6e, 0xae, 0x7a, 0x9e, 0x9c, 0x33, 0xeb, 0x71, 0xae,
+	0x3e, 0x96, 0x5f, 0x9b, 0x6b, 0x50, 0xbf, 0x05, 0xb2, 0x64, 0x5b, 0x12,
+	0xaa, 0xe7, 0xcd, 0xaa, 0x8e, 0x1a, 0x61, 0x8c, 0x64, 0xc5, 0xb4, 0x53,
+	0x56, 0x28, 0x88, 0x45, 0xfb, 0x58, 0xb7, 0x0b, 0x38, 0xdc, 0xe9, 0xe9,
+	0x49, 0xe5, 0x55, 0x8c, 0xd4, 0x50, 0xf3, 0x9a, 0x02, 0x26, 0x5b, 0x74,
+	0x5f, 0xf5, 0x3e, 0x09, 0xcc, 0x3a, 0x21, 0x0f, 0x49, 0x78, 0x5d, 0x2c,
+	0x17, 0xf9, 0xb3, 0x8c, 0xe7, 0xda, 0x56, 0x06, 0x6b, 0xfc, 0x3b, 0xf0,
+	0xe1, 0x2b, 0xd0, 0xfb, 0x1f, 0xa3, 0x6d, 0x28, 0xc1, 0x5e, 0x00, 0x97,
+	0x7c, 0xf5, 0x8a, 0x18, 0x7e, 0xa2, 0x2e, 0x96, 0xeb, 0xe3, 0xd3, 0x73,
+	0x0a, 0x93, 0x12, 0xb7, 0x1f, 0x09, 0xdd, 0xd5, 0x1b, 0x86, 0x9f, 0x51,
+	0xf0, 0x62, 0x0e, 0x71, 0xdc, 0x21, 0xb9, 0x03, 0xeb, 0x73, 0x7a, 0xb1,
+	0x10, 0xda, 0x55, 0x0a, 0x64, 0x15, 0x7e, 0x65, 0xcd, 0x4e, 0x9d, 0x07,
+	0x3f, 0x9e, 0xd2, 0x98, 0x8f, 0xe7, 0x35, 0x15, 0xed, 0xb3, 0x30, 0x36,
+	0x54, 0xac, 0x1d, 0x92, 0x69, 0x97, 0xb1, 0x9d, 0x6e, 0x29, 0xc6, 0x33,
+	0x57, 0x37, 0xae, 0xf2, 0xc8, 0x36, 0xe1, 0xf3, 0xa5, 0xa8, 0xbf, 0x2b,
+	0xfa, 0xbc, 0xe3, 0x29, 0x25, 0x5f, 0x41, 0x5c, 0x98, 0xfe, 0x11, 0xcf,
+	0xab, 0xba, 0xcd, 0x11, 0x3e, 0x97, 0x29, 0x03, 0xca, 0x67, 0x02, 0x2f,
+	0xef, 0x90, 0xcc, 0x98, 0xa5, 0x70, 0xcb, 0x63, 0x25, 0xee, 0x17, 0xe2,
+	0xff, 0xd7, 0x81, 0xfd, 0x23, 0x58, 0x33, 0xfa, 0x01, 0x1c, 0x9b, 0xfb,
+	0x02, 0x65, 0x55, 0xf3, 0x97, 0xec, 0x8b, 0x0f, 0x6d, 0x23, 0xc6, 0x78,
+	0xa1, 0xf4, 0x98, 0xe2, 0xdf, 0x8a, 0x04, 0xb1, 0x73, 0x85, 0x05, 0x0b,
+	0xd9, 0x70, 0x48, 0x92, 0x73, 0xff, 0x16, 0x32, 0xd4, 0x0f, 0x1f, 0x89,
+	0xf5, 0x44, 0x9d, 0x5f, 0x0d, 0x01, 0x73, 0x19, 0xce, 0xbb, 0xa4, 0x68,
+	0x46, 0xa5, 0xa8, 0xee, 0xfe, 0xf1, 0x3c, 0x37, 0xac, 0x62, 0x3b, 0x45,
+	0x93, 0x98, 0x3f, 0xbd, 0x2d, 0xb8, 0xfb, 0x57, 0x34, 0xd9, 0x8e, 0x79,
+	0x96, 0x4f, 0x49, 0x74, 0xee, 0xa0, 0x34, 0xcc, 0x3d, 0x24, 0x8d, 0xc7,
+	0x88, 0xf1, 0x18, 0xbb, 0x37, 0x6e, 0x6d, 0x14, 0x62, 0xee, 0x6f, 0x61,
+	0xec, 0x43, 0xf2, 0x03, 0x37, 0xa0, 0xe9, 0xba, 0xad, 0xd2, 0xca, 0x3a,
+	0x41, 0x9e, 0xcf, 0xc4, 0x09, 0x3c, 0x17, 0x77, 0xfc, 0x18, 0xa9, 0x3a,
+	0x57, 0x41, 0x5a, 0xe1, 0xb9, 0x38, 0xdf, 0xbf, 0x66, 0xfa, 0xa9, 0x8f,
+	0xf7, 0x7d, 0xdf, 0x83, 0x6d, 0x52, 0x75, 0xd8, 0x62, 0xfd, 0xf7, 0xa1,
+	0x39, 0x94, 0xe7, 0xe7, 0x83, 0x3b, 0x3a, 0x06, 0x7c, 0x5f, 0xbb, 0x40,
+	0x9f, 0xc1, 0xe4, 0xb7, 0x98, 0xf3, 0x05, 0xf0, 0xf9, 0x1a, 0x75, 0xbf,
+	0x87, 0x77, 0x24, 0x50, 0xcf, 0xf2, 0x31, 0x1f, 0xf3, 0x09, 0xf0, 0xf9,
+	0xfd, 0x9d, 0x46, 0xfa, 0x7f, 0x5f, 0x9d, 0x1d, 0x20, 0xa6, 0xd8, 0xc6,
+	0xb3, 0x3f, 0x60, 0x55, 0xae, 0xed, 0x77, 0xb1, 0xb6, 0x8d, 0xea, 0xac,
+	0xa5, 0x58, 0xa2, 0x0f, 0x95, 0xc7, 0x9a, 0xf1, 0x9e, 0x1c, 0x7d, 0xad,
+	0xbc, 0x8e, 0x81, 0x92, 0x4e, 0xe2, 0xe8, 0x00, 0x93, 0xb3, 0xcf, 0xcd,
+	0xee, 0x03, 0x07, 0x7e, 0x12, 0xd7, 0x38, 0xa1, 0x68, 0x1e, 0xde, 0xe0,
+	0x23, 0x1c, 0xc6, 0xfe, 0x5b, 0x84, 0x0c, 0x4d, 0x42, 0xef, 0x0c, 0x85,
+	0xb9, 0x27, 0x9a, 0xb5, 0xff, 0xe8, 0xd0, 0x57, 0x0e, 0x8d, 0xa1, 0x0f,
+	0xe3, 0xd8, 0x1b, 0x32, 0x05, 0x9d, 0x3b, 0x5d, 0x4b, 0xaa, 0x6f, 0x78,
+	0x32, 0x09, 0xde, 0xdb, 0x62, 0xf9, 0x7f, 0x81, 0x8c, 0xbc, 0x01, 0x0c,
+	0xba, 0x05, 0xfc, 0x34, 0xf4, 0xbd, 0x90, 0x0f, 0xe8, 0xf8, 0x4f, 0x8c,
+	0xf1, 0x6f, 0xe8, 0xaa, 0xa2, 0x8f, 0xef, 0xe2, 0xd3, 0x48, 0xbf, 0xd0,
+	0xec, 0xcb, 0xc8, 0xcb, 0x7a, 0x8d, 0x9b, 0x50, 0xfe, 0xa8, 0x8a, 0xfb,
+	0xf9, 0x73, 0xb2, 0xb5, 0x7f, 0x10, 0xc5, 0x3a, 0x73, 0x5e, 0x5f, 0x41,
+	0x3d, 0xae, 0x6f, 0xaf, 0x3e, 0x0f, 0x6d, 0x56, 0x3a, 0x29, 0xe7, 0x5a,
+	0xf0, 0x75, 0x89, 0x89, 0x80, 0xa9, 0x5d, 0xb6, 0x7b, 0x76, 0x1b, 0xcf,
+	0x1b, 0x1b, 0x1c, 0x85, 0xe7, 0x3b, 0xc2, 0x12, 0x94, 0xdd, 0x8e, 0x32,
+	0xc6, 0x25, 0xde, 0x85, 0xb5, 0x61, 0x59, 0x16, 0x79, 0x8e, 0x75, 0xb5,
+	0x1e, 0x87, 0x63, 0x0c, 0xb7, 0xac, 0xa7, 0x89, 0x73, 0xe9, 0xd8, 0xf0,
+	0xfd, 0x00, 0xcb, 0xde, 0xa5, 0xcb, 0x22, 0x7a, 0x7e, 0xb7, 0xeb, 0x6f,
+	0x67, 0xed, 0x23, 0x99, 0x55, 0x3c, 0x4a, 0xfa, 0x62, 0xaa, 0x5d, 0xc6,
+	0xf4, 0x65, 0xe7, 0x30, 0xd6, 0x23, 0x92, 0xf6, 0xda, 0xb9, 0x47, 0x86,
+	0xc2, 0x81, 0x5f, 0x98, 0x50, 0xbe, 0x9e, 0x65, 0xf8, 0x77, 0x84, 0xce,
+	0x5d, 0x76, 0x0f, 0xda, 0xbf, 0x53, 0x3e, 0xdc, 0xdb, 0x24, 0x8b, 0xb3,
+	0x31, 0x7d, 0x3f, 0x31, 0xa1, 0xf6, 0x49, 0x7e, 0x9c, 0xf9, 0x1f, 0x6d,
+	0xe3, 0x77, 0xcb, 0x86, 0xc3, 0xf2, 0x0e, 0xcd, 0xdf, 0x77, 0xa9, 0xfb,
+	0x3c, 0xbc, 0x67, 0x52, 0x2c, 0xff, 0x44, 0xbd, 0x3f, 0x3d, 0xdf, 0xa0,
+	0xea, 0x9f, 0x9e, 0xdf, 0x78, 0x27, 0x87, 0x65, 0xef, 0x66, 0x4c, 0x41,
+	0x96, 0x66, 0x1a, 0x64, 0x79, 0xde, 0xa2, 0x8f, 0x94, 0x6e, 0x5c, 0xfb,
+	0xf6, 0x45, 0x7f, 0xa7, 0xe6, 0xc9, 0x30, 0xd6, 0x6f, 0x71, 0x70, 0x5a,
+	0x2a, 0x83, 0xf4, 0x01, 0xd4, 0xbd, 0x3b, 0xc8, 0x48, 0x03, 0xf0, 0x5f,
+	0xc1, 0xab, 0x38, 0x8c, 0xbd, 0xb6, 0x6a, 0x1f, 0xea, 0xc7, 0xda, 0xcf,
+	0x22, 0x8f, 0x0c, 0xc9, 0xf5, 0x4f, 0x29, 0xba, 0x2a, 0x8a, 0x57, 0xc1,
+	0xb7, 0x45, 0xec, 0x9f, 0xdf, 0x17, 0x85, 0x35, 0x7e, 0x7c, 0x50, 0xf3,
+	0xfc, 0xaf, 0x75, 0xfa, 0x88, 0xec, 0x3b, 0xfe, 0x19, 0xd0, 0xda, 0xe4,
+	0xdf, 0x2d, 0x92, 0xfa, 0xef, 0x36, 0x22, 0xea, 0xdb, 0x95, 0x88, 0xf3,
+	0x08, 0xca, 0x18, 0x7b, 0x7a, 0x44, 0xcd, 0x83, 0xf7, 0xd7, 0x0a, 0xf2,
+	0xab, 0xee, 0x64, 0x04, 0xfe, 0x0f, 0xef, 0x08, 0x35, 0xeb, 0xfe, 0x76,
+	0xe9, 0x75, 0x1c, 0x97, 0x7d, 0xd0, 0xef, 0x79, 0xe0, 0x40, 0xde, 0xab,
+	0x9a, 0x08, 0xd7, 0x8f, 0x19, 0xc8, 0xb2, 0xef, 0x5b, 0x07, 0x67, 0xfd,
+	0x61, 0xe5, 0x03, 0xac, 0xfa, 0xe9, 0xba, 0x7c, 0x5c, 0xf6, 0x97, 0x94,
+	0xbf, 0xae, 0xce, 0xe8, 0xa6, 0xb1, 0x27, 0x87, 0x94, 0x0e, 0x8f, 0x85,
+	0x86, 0xab, 0x69, 0xc9, 0x9f, 0xdc, 0x8d, 0x71, 0x18, 0xfb, 0xca, 0xe8,
+	0xb3, 0xb0, 0xbd, 0xb2, 0xaf, 0xe6, 0x8f, 0x3d, 0x59, 0xe2, 0xfb, 0x24,
+	0xec, 0x22, 0xdf, 0xe7, 0x12, 0x61, 0x15, 0xcd, 0xbf, 0x0e, 0x6d, 0x1b,
+	0x34, 0x6f, 0x79, 0x9f, 0x9e, 0xed, 0xb9, 0xff, 0x3e, 0x6e, 0x4a, 0x73,
+	0x0e, 0xef, 0xd9, 0x26, 0xe8, 0x6f, 0x12, 0x7a, 0x9a, 0xfe, 0xe8, 0xc3,
+	0xb2, 0x52, 0x9e, 0x96, 0xf3, 0xe5, 0x40, 0xce, 0x78, 0xb7, 0x99, 0xb4,
+	0xdf, 0xa9, 0xef, 0x36, 0x67, 0xb0, 0x0e, 0xeb, 0x79, 0x95, 0x5b, 0xf7,
+	0xfd, 0xd1, 0x5f, 0x98, 0xfe, 0x37, 0x80, 0xb7, 0xa9, 0x7b, 0x4a, 0xeb,
+	0xe5, 0x9d, 0xfd, 0x2c, 0x9b, 0x8c, 0xed, 0xfb, 0x77, 0xad, 0x3a, 0xea,
+	0xde, 0xc7, 0xf5, 0xfd, 0xa6, 0xe7, 0xf4, 0x9d, 0x78, 0xf2, 0x73, 0x4c,
+	0xd3, 0x7b, 0x1d, 0xf6, 0x1e, 0xfb, 0x7c, 0x54, 0xaf, 0x1b, 0xd2, 0x45,
+	0x3e, 0x53, 0x0f, 0xad, 0xe8, 0xf3, 0x4e, 0x53, 0x8f, 0x51, 0x7f, 0xbf,
+	0xac, 0xa1, 0x6e, 0x5c, 0xb6, 0xe7, 0xb7, 0x48, 0xc1, 0x5d, 0x6b, 0x96,
+	0x1d, 0xd7, 0xf7, 0xd8, 0x82, 0xbb, 0xd5, 0x2c, 0x0b, 0xee, 0x5b, 0x91,
+	0x5f, 0x8c, 0xe1, 0x21, 0xad, 0x8d, 0xe9, 0xe7, 0xb1, 0xba, 0x6f, 0x74,
+	0x82, 0x3e, 0x23, 0xe8, 0xe3, 0xf6, 0xf0, 0xe5, 0x77, 0xb1, 0xf9, 0xdd,
+	0x14, 0x65, 0xd1, 0xe0, 0x37, 0xdd, 0xf4, 0x7b, 0x80, 0x55, 0xb6, 0xca,
+	0xa4, 0xa2, 0xa7, 0xa0, 0xee, 0x27, 0x64, 0xdd, 0x26, 0x19, 0x32, 0xfd,
+	0xfc, 0xe4, 0xe2, 0x46, 0x39, 0x65, 0xf9, 0xf5, 0x31, 0x69, 0x2e, 0x60,
+	0x1c, 0xbe, 0xdf, 0xec, 0x1b, 0x81, 0xa8, 0xfe, 0x4e, 0xc9, 0x45, 0x9b,
+	0xcf, 0x53, 0xde, 0x0b, 0x85, 0xd5, 0xbb, 0x90, 0x05, 0x15, 0x97, 0x14,
+	0x23, 0xb8, 0x93, 0xc8, 0x6f, 0xd6, 0x45, 0x9e, 0xa9, 0xf2, 0xbb, 0xad,
+	0xdb, 0xd4, 0xbd, 0x11, 0xff, 0x2c, 0x8e, 0x74, 0x75, 0x2b, 0x9d, 0x5c,
+	0xa9, 0x16, 0xc9, 0x53, 0x1d, 0x87, 0x8d, 0xea, 0x38, 0x2c, 0x79, 0x3c,
+	0x02, 0x1e, 0xff, 0x3f, 0xbd, 0x2e, 0xc1, 0x77, 0x5f, 0x3c, 0xeb, 0xe1,
+	0x79, 0xd0, 0xa3, 0x6a, 0x2e, 0xd4, 0xd1, 0x68, 0xfb, 0xde, 0xb0, 0xda,
+	0xbb, 0xea, 0x9b, 0x78, 0xc8, 0x27, 0xbf, 0x71, 0x87, 0x7e, 0x2d, 0xf1,
+	0x5b, 0xf6, 0x11, 0xf5, 0x3d, 0x47, 0xa5, 0xca, 0x75, 0xe5, 0x37, 0xec,
+	0x63, 0x75, 0xf2, 0x18, 0xd6, 0x63, 0x6d, 0x69, 0x93, 0x66, 0x7f, 0xdd,
+	0xf9, 0x2d, 0x48, 0xa5, 0x1a, 0xdc, 0xa3, 0xdc, 0xb2, 0xc2, 0x3d, 0x21,
+	0xbe, 0x5f, 0xab, 0xbe, 0x67, 0xa9, 0xa8, 0xef, 0x43, 0x2c, 0x7e, 0x67,
+	0x09, 0xdb, 0xb1, 0x07, 0xcf, 0x3c, 0x47, 0xdd, 0x8b, 0x14, 0x3a, 0xa7,
+	0x3a, 0x81, 0xf4, 0x21, 0xc9, 0xa9, 0x38, 0x57, 0x0b, 0xf2, 0x93, 0x6a,
+	0xec, 0x62, 0xf5, 0x7e, 0xd9, 0x77, 0xf2, 0x01, 0x7e, 0x43, 0xa3, 0xbe,
+	0xc3, 0xcf, 0xba, 0xa4, 0x31, 0x2e, 0x53, 0x6a, 0xde, 0x85, 0xb5, 0x6f,
+	0x33, 0x7c, 0x39, 0x6a, 0xe3, 0x9a, 0x16, 0xaa, 0x2d, 0xa0, 0x31, 0xa4,
+	0xef, 0x52, 0x12, 0xff, 0x06, 0xf3, 0x6f, 0xe6, 0xfd, 0x3c, 0x8f, 0xe7,
+	0x65, 0xfb, 0x4a, 0xbc, 0x2b, 0x99, 0xd4, 0x7e, 0x31, 0x63, 0x65, 0x8c,
+	0xc7, 0x53, 0xc6, 0xed, 0xd4, 0x04, 0xb4, 0x7f, 0x54, 0x12, 0x3c, 0xcb,
+	0xd5, 0x73, 0x69, 0xa9, 0x9b, 0x0b, 0xef, 0x87, 0xfa, 0xf3, 0xe1, 0x37,
+	0x27, 0xf9, 0x52, 0xfd, 0xf7, 0x32, 0xea, 0x9b, 0x70, 0xf5, 0x7d, 0xca,
+	0x44, 0xf5, 0x41, 0xb9, 0xaf, 0xb4, 0x55, 0x7f, 0x2b, 0x13, 0x93, 0xfb,
+	0xaa, 0x6f, 0x28, 0x9e, 0xe6, 0xd5, 0x77, 0x3e, 0x51, 0xbd, 0x66, 0x71,
+	0xd5, 0xc7, 0xda, 0xf7, 0x3e, 0x76, 0xdd, 0xb7, 0x1f, 0x51, 0x99, 0x58,
+	0xfc, 0x65, 0xdf, 0xfc, 0x3c, 0x2c, 0xfc, 0xee, 0xe3, 0x25, 0x77, 0x5a,
+	0x1e, 0x2b, 0x7b, 0xde, 0x1d, 0x2e, 0xb1, 0xd4, 0x16, 0x39, 0x1f, 0xcf,
+	0x0c, 0x7e, 0xcf, 0x69, 0x0f, 0x55, 0x66, 0x1b, 0xa1, 0xaf, 0x1b, 0x95,
+	0x2d, 0x61, 0x7e, 0x71, 0x96, 0x7b, 0x3e, 0x82, 0x39, 0xda, 0xe6, 0x25,
+	0xf9, 0x54, 0x1b, 0xe3, 0x4c, 0x77, 0xc0, 0x77, 0xfb, 0xb8, 0xeb, 0xeb,
+	0xe5, 0xcf, 0x2d, 0xed, 0x96, 0xcf, 0x55, 0x63, 0xa1, 0xca, 0x0c, 0xef,
+	0xd7, 0xd9, 0x23, 0x65, 0x49, 0xa2, 0x1e, 0xfb, 0x87, 0xbc, 0x24, 0xb6,
+	0xcb, 0xd3, 0xc7, 0x7f, 0xee, 0x5d, 0x72, 0xf0, 0x1e, 0xba, 0xe6, 0xbc,
+	0x1b, 0xc4, 0xd2, 0xe0, 0x37, 0x1f, 0x65, 0xbd, 0xed, 0x90, 0x03, 0xd8,
+	0x6d, 0xec, 0x39, 0xfa, 0x75, 0x97, 0xb4, 0xde, 0x32, 0x8e, 0x5e, 0x23,
+	0x97, 0x56, 0xef, 0xe4, 0xbe, 0x0e, 0xd9, 0xb6, 0x7c, 0xfe, 0xab, 0xd8,
+	0xf3, 0x41, 0x09, 0x7f, 0x01, 0x76, 0xe2, 0x0b, 0x0d, 0x4a, 0xb7, 0xd3,
+	0x9e, 0x01, 0xf3, 0x03, 0xd7, 0x47, 0xd0, 0xcf, 0xfe, 0x36, 0x5f, 0x66,
+	0xa7, 0x45, 0xbe, 0xd8, 0x24, 0x99, 0x36, 0xfa, 0x8d, 0xf2, 0x2b, 0xf4,
+	0x57, 0xfd, 0x3e, 0x4b, 0xc9, 0x9f, 0x71, 0x8f, 0xd7, 0x38, 0x97, 0x64,
+	0xe2, 0x7f, 0xc9, 0x27, 0x65, 0x22, 0xc1, 0xb9, 0x3c, 0x2c, 0x85, 0xf2,
+	0xa3, 0xf8, 0x71, 0x9e, 0xa4, 0xfb, 0x5f, 0xe8, 0xb3, 0xfb, 0x31, 0x29,
+	0xce, 0xa4, 0x65, 0x6a, 0x7e, 0x92, 0xdf, 0xe4, 0x8e, 0xdc, 0xa1, 0xce,
+	0xb4, 0xec, 0x44, 0x32, 0xd4, 0x67, 0x4d, 0xf1, 0xae, 0x82, 0x9a, 0xcf,
+	0x24, 0xe6, 0xf3, 0x4a, 0x1b, 0xef, 0x78, 0x5f, 0x82, 0xfe, 0x35, 0x4e,
+	0x50, 0x0e, 0x6d, 0xb3, 0x2b, 0xc4, 0xfc, 0x5e, 0xf8, 0xab, 0x2c, 0xdb,
+	0x2b, 0xe1, 0xa3, 0xab, 0x7a, 0x1e, 0xe5, 0xfa, 0x6c, 0x55, 0xb5, 0xff,
+	0xaf, 0x68, 0x8b, 0x7a, 0x47, 0x83, 0xb6, 0x41, 0x1d, 0xb6, 0xe5, 0x3c,
+	0x77, 0xc3, 0x4f, 0x0e, 0xe8, 0x82, 0x1c, 0x26, 0xea, 0xf9, 0xdd, 0xbc,
+	0x81, 0xdf, 0x11, 0xe2, 0x4d, 0xf0, 0x8b, 0x3c, 0x0e, 0x6b, 0x1e, 0xff,
+	0x3d, 0xfa, 0x0f, 0xd6, 0xe0, 0x0e, 0x94, 0x99, 0xfa, 0x1b, 0xbc, 0x77,
+	0xc2, 0x77, 0xf2, 0x9c, 0xf5, 0xf7, 0xb7, 0xf9, 0xb2, 0x46, 0x7a, 0x36,
+	0xe3, 0xf9, 0x7b, 0xdb, 0xfd, 0x75, 0xd9, 0x0b, 0x7e, 0xf1, 0x1e, 0x65,
+	0x9f, 0xba, 0x8f, 0x9f, 0x19, 0xdf, 0x0b, 0xd9, 0x09, 0xe6, 0xd5, 0x07,
+	0x19, 0xe3, 0x39, 0x01, 0xeb, 0xd7, 0xf3, 0xc4, 0xb7, 0x7b, 0x61, 0xfa,
+	0xfa, 0x0e, 0xe7, 0x0a, 0x4c, 0xf8, 0x45, 0xf5, 0xfd, 0x0d, 0xf4, 0xe4,
+	0xbb, 0x57, 0xbf, 0xbf, 0xb9, 0xf2, 0x1a, 0x0f, 0xb4, 0xfb, 0x36, 0xca,
+	0x04, 0x4f, 0x5a, 0x75, 0x9b, 0xbd, 0xc0, 0xa7, 0x8c, 0x7f, 0x26, 0x13,
+	0x9f, 0x90, 0x60, 0x1c, 0xef, 0x36, 0xfa, 0x79, 0x43, 0x03, 0x7d, 0xf0,
+	0x69, 0xd5, 0x1d, 0x95, 0x04, 0xef, 0xbc, 0x24, 0x43, 0x7b, 0xd5, 0x7d,
+	0x85, 0x17, 0xd6, 0x7d, 0x43, 0x95, 0x92, 0xa7, 0xd7, 0x64, 0x65, 0xe4,
+	0x47, 0x62, 0x8b, 0x75, 0x35, 0x65, 0x85, 0xfd, 0x4e, 0x72, 0x9e, 0x89,
+	0x07, 0xd4, 0x3c, 0x4d, 0xf8, 0x4d, 0xbc, 0x5b, 0x60, 0x86, 0x2a, 0xf3,
+	0x5c, 0x77, 0xa4, 0x4b, 0x7c, 0x0e, 0xce, 0x37, 0x95, 0x5e, 0xc1, 0xb8,
+	0x2c, 0xa3, 0x6e, 0xe4, 0xfb, 0xb4, 0x3e, 0xff, 0xbc, 0xa7, 0x9d, 0x67,
+	0xf0, 0x79, 0x94, 0x95, 0x97, 0x36, 0xa7, 0xed, 0xe3, 0x4a, 0x0e, 0x1e,
+	0x06, 0xdf, 0xff, 0x04, 0x75, 0x1f, 0x45, 0xca, 0x39, 0xa6, 0x57, 0xd7,
+	0x9d, 0xfc, 0xfe, 0xb0, 0x0c, 0x42, 0x2e, 0x98, 0x7f, 0x58, 0x8a, 0xea,
+	0xee, 0x10, 0xd2, 0x32, 0x9f, 0xa9, 0xeb, 0x1d, 0x6d, 0x4f, 0x49, 0xcb,
+	0x5e, 0xfd, 0xdd, 0x56, 0x20, 0x4f, 0x7b, 0x74, 0xbb, 0xf1, 0x55, 0x5e,
+	0x3d, 0x70, 0x19, 0xde, 0x88, 0xae, 0xe2, 0x0d, 0x7f, 0xac, 0x62, 0x7b,
+	0x80, 0x35, 0xfc, 0x39, 0xf8, 0x58, 0xc3, 0x97, 0xf3, 0x49, 0x89, 0x40,
+	0x8e, 0xc3, 0x6b, 0x72, 0x0c, 0xdc, 0xe3, 0xef, 0x99, 0x29, 0x9e, 0xdb,
+	0x29, 0x3e, 0x53, 0x0e, 0x29, 0xbf, 0x5c, 0xc7, 0xfa, 0xb5, 0xbe, 0xf1,
+	0x97, 0xac, 0xf5, 0x85, 0xf6, 0x00, 0x3f, 0xfc, 0xd3, 0xf6, 0xc1, 0xd7,
+	0xda, 0xd7, 0xf6, 0xc1, 0x35, 0xbf, 0xa1, 0x7d, 0xb0, 0x51, 0x2e, 0xeb,
+	0x65, 0xca, 0x84, 0x3c, 0x71, 0xbd, 0x28, 0x4f, 0x94, 0x23, 0xf2, 0x92,
+	0xfa, 0xb4, 0x91, 0xbe, 0x53, 0xe2, 0xa2, 0xfa, 0x3e, 0x62, 0x1a, 0x3a,
+	0xa8, 0x3d, 0x54, 0x86, 0x5f, 0x5e, 0x5c, 0xba, 0x49, 0xc9, 0xf4, 0xd3,
+	0x35, 0xea, 0xa5, 0x2b, 0xcd, 0x7d, 0xbd, 0xce, 0xcd, 0x6f, 0xd0, 0xb9,
+	0xf9, 0x55, 0x9d, 0xdb, 0xa6, 0xfd, 0xa5, 0x7f, 0x8a, 0xce, 0x8d, 0xd7,
+	0x9d, 0x85, 0x04, 0xe7, 0x20, 0x12, 0xca, 0xf6, 0x36, 0xcb, 0xae, 0xd9,
+	0xb8, 0x8c, 0xcc, 0xec, 0x96, 0x3f, 0x9a, 0x99, 0x56, 0xf7, 0x82, 0xfe,
+	0xca, 0x4d, 0x26, 0xee, 0x0f, 0x79, 0xf2, 0x61, 0xf8, 0xbb, 0x13, 0x9d,
+	0x0d, 0xb2, 0xeb, 0xfd, 0xea, 0x7c, 0xcf, 0xcc, 0x86, 0x3a, 0x84, 0x91,
+	0xe7, 0x9c, 0x6b, 0xbb, 0x56, 0x88, 0x77, 0xc4, 0x1a, 0x65, 0x22, 0xde,
+	0x22, 0xbb, 0x81, 0x9d, 0x0a, 0x57, 0xb9, 0xea, 0x9b, 0xed, 0x8c, 0x3a,
+	0x3f, 0xe9, 0xde, 0xee, 0x8f, 0x0b, 0x3e, 0xb4, 0x9a, 0xf2, 0xe7, 0xb5,
+	0x6e, 0xf5, 0xfd, 0xf1, 0x0b, 0xa5, 0x3f, 0x6f, 0x5b, 0x9f, 0xe7, 0xf3,
+	0x7f, 0x42, 0x9d, 0x38, 0x78, 0x55, 0x7f, 0xdf, 0x26, 0xac, 0xf8, 0x59,
+	0x2c, 0x8f, 0xab, 0x7b, 0x4c, 0x17, 0xc3, 0xe4, 0x97, 0xf2, 0x9b, 0x12,
+	0xd9, 0x30, 0x30, 0xce, 0x2c, 0x90, 0xb4, 0x43, 0x9f, 0x4f, 0xe3, 0x4f,
+	0xe8, 0xff, 0x7d, 0xea, 0x3c, 0x75, 0x05, 0xbc, 0xf1, 0x54, 0xbc, 0x35,
+	0x1f, 0x27, 0xae, 0x5f, 0xbb, 0xb3, 0x7b, 0x39, 0xbe, 0xf7, 0xbf, 0xf1,
+	0xd2, 0xb1, 0x7f, 0x1d, 0x9f, 0xd1, 0x3e, 0xb8, 0x3a, 0xcb, 0xda, 0xec,
+	0xff, 0x50, 0xf8, 0xdf, 0xec, 0x67, 0x4b, 0xc4, 0x76, 0xf6, 0x91, 0xb2,
+	0xf4, 0x6f, 0x57, 0xb1, 0x26, 0xf2, 0xb7, 0x82, 0x75, 0x3a, 0x96, 0x08,
+	0xec, 0x79, 0xa8, 0xeb, 0x6c, 0xbd, 0x1f, 0xc8, 0x3e, 0x62, 0xea, 0x0e,
+	0xc4, 0xda, 0xff, 0xbd, 0x61, 0x4c, 0x25, 0x13, 0xba, 0xab, 0x34, 0x2d,
+	0xe1, 0xb9, 0x31, 0x89, 0x1c, 0x63, 0xfc, 0x3a, 0x23, 0xc5, 0xb8, 0x27,
+	0xf7, 0xb9, 0xeb, 0x7d, 0x93, 0x2e, 0x63, 0x23, 0xed, 0x0f, 0xcb, 0xd0,
+	0xc9, 0x47, 0x25, 0x3a, 0xc7, 0x77, 0xeb, 0xce, 0x2e, 0xa0, 0x8f, 0xb6,
+	0x48, 0x39, 0xce, 0x18, 0x6e, 0x54, 0x9d, 0x05, 0x9f, 0x1f, 0x5f, 0x90,
+	0x22, 0xb0, 0x42, 0x5e, 0xe9, 0x16, 0xa4, 0xab, 0xbe, 0xc4, 0xf4, 0x76,
+	0xee, 0x29, 0xf8, 0x98, 0xa1, 0x89, 0x72, 0x54, 0xdd, 0xc9, 0x39, 0x1f,
+	0x67, 0x5d, 0xf8, 0xef, 0x73, 0xc4, 0x19, 0xd0, 0x1d, 0x63, 0x12, 0x62,
+	0x3e, 0x3c, 0xb7, 0x86, 0x33, 0xa8, 0x13, 0x86, 0xdc, 0xb8, 0x44, 0x4e,
+	0xf9, 0x73, 0xe7, 0x3f, 0x52, 0x32, 0x16, 0x76, 0x4b, 0xf8, 0x18, 0x9f,
+	0xeb, 0xfd, 0x21, 0x62, 0x77, 0xd8, 0x86, 0xb3, 0x9f, 0x45, 0x7f, 0x7c,
+	0x97, 0xd1, 0xdf, 0xc2, 0x22, 0x5f, 0xf9, 0xc7, 0xfe, 0xcf, 0x04, 0xca,
+	0xfe, 0xff, 0x07, 0x3b, 0x97, 0x22, 0x9a, 0xb0, 0x4e, 0x00, 0x00, 0x00 };
 
 static const u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 };
-static const u32 bnx2_COM_b06FwRodata[(0x88/4) + 1] = {
-	0x08001c1c, 0x08001c4c, 0x08001c4c, 0x08001c4c, 0x08001c4c, 0x08001c4c,
-	0x08001b74, 0x08001c4c, 0x08001bdc, 0x08001c4c, 0x08001b08, 0x08001c4c,
-	0x08001c4c, 0x08001c4c, 0x08001b14, 0x00000000, 0x08002b58, 0x08002ba8,
-	0x08002bd8, 0x08002c08, 0x08002c38, 0x00000000, 0x080060cc, 0x080060cc,
-	0x080060cc, 0x080060cc, 0x080060cc, 0x08006100, 0x08006100, 0x08006140,
-	0x0800614c, 0x0800614c, 0x080060cc, 0x00000000, 0x00000000 };
+static const u32 bnx2_COM_b06FwRodata[(0x14/4) + 1] = {
+	0x08000f04, 0x08000f4c, 0x08000f80, 0x08000fcc, 0x08001000, 0x00000000
+};
 
 static struct fw_info bnx2_com_fw_06 = {
-	.ver_major			= 0x3,
-	.ver_minor			= 0x4,
-	.ver_fix			= 0x3,
+	/* Firmware version: 4.0.5 */
+	.ver_major			= 0x4,
+	.ver_minor			= 0x0,
+	.ver_fix			= 0x5,
 
-	.start_addr			= 0x080000b4,
+	.start_addr			= 0x080000f8,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x7d54,
+	.text_len			= 0x4eac,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_COM_b06FwText,
 	.gz_text_len			= sizeof(bnx2_COM_b06FwText),
 
-	.data_addr			= 0x08007e00,
+	.data_addr			= 0x00000000,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_COM_b06FwData,
 
-	.sbss_addr			= 0x08007e00,
-	.sbss_len			= 0x60,
+	.sbss_addr			= 0x08004ee0,
+	.sbss_len			= 0x38,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x08007e60,
-	.bss_len			= 0x88,
+	.bss_addr			= 0x08004f18,
+	.bss_len			= 0xbc,
 	.bss_index			= 0x0,
 
-	.rodata_addr			= 0x08007d58,
-	.rodata_len			= 0x88,
+	.rodata_addr			= 0x08004eac,
+	.rodata_len			= 0x14,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_COM_b06FwRodata,
 };
 
+static u8 bnx2_CP_b06FwText[] = {
+	0x9d, 0xbc, 0x0d, 0x78, 0x13, 0xe7, 0x99, 0x2e, 0x7c, 0xcf, 0x48, 0xb2,
+	0x65, 0x5b, 0xb6, 0xc7, 0xb6, 0x0c, 0x22, 0x65, 0x41, 0x83, 0x47, 0x20,
+	0x62, 0x27, 0x1d, 0x81, 0x49, 0x94, 0xac, 0x36, 0xa8, 0xc6, 0x01, 0x93,
+	0x90, 0xc6, 0x34, 0xb4, 0x75, 0x7a, 0xd2, 0x8d, 0x62, 0x0c, 0x21, 0x84,
+	0x10, 0x67, 0x9b, 0x9e, 0xe3, 0x7c, 0x5f, 0xce, 0x5a, 0x35, 0x06, 0x0c,
+	0xc8, 0x96, 0x31, 0x0e, 0x90, 0xfd, 0x7a, 0x9d, 0x18, 0x6c, 0x30, 0x49,
+	0x65, 0x8b, 0x34, 0x74, 0x97, 0xf4, 0xa3, 0x45, 0x07, 0xf2, 0xe3, 0xfc,
+	0x35, 0xa4, 0xed, 0x76, 0xdb, 0x3d, 0x39, 0x89, 0x0f, 0x25, 0x84, 0xb4,
+	0xdd, 0xfc, 0xb4, 0xdd, 0x2d, 0x69, 0x9b, 0xcc, 0x77, 0x3f, 0x23, 0x09,
+	0x0c, 0x4d, 0x7f, 0xf6, 0xf3, 0x75, 0xcd, 0x65, 0xcd, 0xcc, 0xfb, 0xf3,
+	0xbc, 0xcf, 0xfb, 0x3c, 0xf7, 0x73, 0x3f, 0xef, 0xbc, 0x33, 0xb3, 0x80,
+	0x62, 0xe4, 0xfe, 0x4a, 0x79, 0x5c, 0x5d, 0xdf, 0xbe, 0x1a, 0x8b, 0xae,
+	0x36, 0xe5, 0xdc, 0xe9, 0x82, 0x13, 0x7f, 0xe1, 0x9f, 0xff, 0x2f, 0x2d,
+	0x38, 0xe5, 0xcf, 0x01, 0x68, 0xf9, 0x7e, 0xe5, 0x80, 0x5b, 0x8d, 0x3c,
+	0xf3, 0x5f, 0x1a, 0x0c, 0xb8, 0x1d, 0x91, 0x9e, 0xd6, 0xd5, 0x06, 0x10,
+	0x4d, 0xd5, 0xfa, 0x97, 0xe0, 0x23, 0x2b, 0xee, 0x75, 0x42, 0xae, 0xff,
+	0x55, 0xe4, 0xf7, 0x9d, 0xdf, 0xb9, 0x56, 0x7f, 0x7f, 0xc8, 0x01, 0xb7,
+	0x16, 0xe9, 0x80, 0x36, 0x17, 0xee, 0x99, 0xac, 0xf3, 0xf5, 0x79, 0xdb,
+	0x15, 0x94, 0xe5, 0xdb, 0x3a, 0x67, 0x7d, 0x67, 0x9e, 0x2f, 0x56, 0x14,
+	0xd1, 0x70, 0x3c, 0x8d, 0xe6, 0xba, 0xde, 0x4e, 0xab, 0xd4, 0x08, 0xc1,
+	0x6d, 0x18, 0x2d, 0xbd, 0x8a, 0x27, 0xbc, 0x7e, 0x11, 0x3c, 0x85, 0x06,
+	0xe2, 0x57, 0x44, 0xd0, 0x7c, 0xe5, 0x58, 0x71, 0xdc, 0x19, 0x71, 0xa3,
+	0x29, 0xed, 0x8e, 0x7f, 0x2a, 0x62, 0x60, 0x59, 0xfa, 0xfa, 0x62, 0x94,
+	0xb9, 0xd1, 0x9d, 0xfe, 0xa8, 0x28, 0xdb, 0x5e, 0x73, 0xee, 0xff, 0xec,
+	0xaa, 0xec, 0xff, 0x69, 0x31, 0x67, 0x04, 0xd8, 0x9c, 0xb0, 0xac, 0x82,
+	0xc8, 0x6d, 0xb7, 0xa9, 0x11, 0xc3, 0x77, 0x10, 0x8b, 0xd1, 0xaa, 0xe1,
+	0xe1, 0x2d, 0xf5, 0xbf, 0x54, 0x4e, 0x0c, 0xb2, 0xe1, 0x51, 0x07, 0xa2,
+	0xda, 0x33, 0xfc, 0x3f, 0x6b, 0x56, 0x4b, 0xd8, 0xc0, 0xde, 0xd1, 0xf3,
+	0xbc, 0xee, 0xb4, 0xaf, 0x6d, 0xda, 0x33, 0x6b, 0xd6, 0xed, 0xe1, 0x67,
+	0xf0, 0xe8, 0xa8, 0xfc, 0xbe, 0x1b, 0x9d, 0x75, 0x0a, 0x26, 0x6f, 0x5b,
+	0x0b, 0x87, 0x61, 0xa0, 0x7b, 0x8f, 0xe2, 0xec, 0xaa, 0x53, 0x11, 0xf5,
+	0xea, 0xc1, 0x18, 0x95, 0xef, 0x34, 0x10, 0x2b, 0x8c, 0x84, 0x9d, 0xef,
+	0x24, 0x22, 0x9a, 0xc3, 0xb0, 0xac, 0x60, 0x68, 0x3a, 0x1c, 0x15, 0x96,
+	0xf5, 0xb4, 0xe9, 0x81, 0xff, 0x8b, 0xcf, 0x21, 0x3e, 0xdc, 0x0c, 0xd5,
+	0x78, 0x0e, 0x5d, 0xc3, 0xcf, 0xe1, 0xb1, 0x5d, 0xc5, 0x98, 0xac, 0xe2,
+	0x78, 0x93, 0x3e, 0x7c, 0x67, 0x9e, 0xf4, 0x2d, 0x72, 0xd4, 0xf1, 0x70,
+	0x63, 0xd2, 0xf1, 0x06, 0xff, 0x4b, 0x99, 0xf3, 0xd6, 0xe4, 0xf4, 0x8b,
+	0x65, 0x36, 0xb3, 0x4c, 0xf7, 0x65, 0x65, 0xe2, 0xc3, 0x11, 0xbc, 0x94,
+	0x50, 0xb0, 0x3e, 0x54, 0x86, 0x68, 0x85, 0x8c, 0xd7, 0xb2, 0x46, 0xcd,
+	0xb3, 0xd6, 0xa4, 0x26, 0x7d, 0x4d, 0xe0, 0x65, 0xde, 0xdb, 0x12, 0x3a,
+	0x63, 0x65, 0xbc, 0xd2, 0x5e, 0x3b, 0x6d, 0x67, 0x25, 0xaf, 0x3b, 0x91,
+	0x4c, 0x20, 0x56, 0x16, 0xb9, 0x8d, 0xe7, 0xba, 0xf9, 0xae, 0xe2, 0x76,
+	0xbf, 0x97, 0x70, 0x7f, 0xb1, 0xd4, 0x50, 0x1f, 0x2c, 0xa7, 0x01, 0xbd,
+	0x42, 0x99, 0x8f, 0x9a, 0x6b, 0xe1, 0x32, 0x1e, 0x10, 0x5b, 0xe3, 0xb8,
+	0x7e, 0x68, 0x61, 0x7a, 0xbe, 0xbe, 0xb4, 0xeb, 0xc6, 0x96, 0xa4, 0x65,
+	0x6d, 0x33, 0xa3, 0xd7, 0x15, 0xd1, 0x20, 0x4e, 0x26, 0x9a, 0xe1, 0x8e,
+	0x04, 0xfc, 0xe7, 0x10, 0xc6, 0x92, 0xb4, 0x17, 0xcf, 0x26, 0xe0, 0x6c,
+	0x98, 0xe7, 0x45, 0x57, 0x3a, 0x82, 0x1b, 0xd3, 0x26, 0x1a, 0xd3, 0x7f,
+	0xde, 0xb2, 0x6e, 0x4e, 0xfa, 0x39, 0x86, 0x8f, 0xac, 0xec, 0x18, 0x64,
+	0x7c, 0xd9, 0xff, 0xdd, 0xc9, 0x2b, 0xb0, 0x9d, 0x73, 0xb4, 0x95, 0xf3,
+	0xb7, 0x3c, 0x94, 0x89, 0x16, 0x41, 0x37, 0xcf, 0x21, 0x82, 0xa5, 0x69,
+	0x83, 0x73, 0x1a, 0xc1, 0x92, 0x64, 0x8d, 0x36, 0x8c, 0xf9, 0x88, 0xfa,
+	0xb2, 0x36, 0xbd, 0x83, 0xe3, 0x6d, 0x0d, 0x34, 0xa3, 0x94, 0x36, 0x92,
+	0x5a, 0x14, 0x46, 0x03, 0xfb, 0x5f, 0xf1, 0x17, 0xf4, 0x7f, 0x2b, 0xfb,
+	0x7f, 0x97, 0xfd, 0x67, 0xec, 0xfe, 0xe1, 0xbc, 0x89, 0xe7, 0x6e, 0xda,
+	0xe3, 0xf6, 0x94, 0xd3, 0xb9, 0x3c, 0xe9, 0xc5, 0xb6, 0x94, 0x49, 0x9b,
+	0x93, 0x5b, 0x3e, 0x6c, 0x19, 0x9c, 0x89, 0xad, 0x83, 0xba, 0xef, 0x79,
+	0xfe, 0xde, 0x34, 0x72, 0x05, 0x36, 0x0f, 0x2a, 0xd8, 0x6f, 0x5c, 0x81,
+	0x2e, 0xfe, 0xde, 0x3b, 0x38, 0x0b, 0x8f, 0x0e, 0x3a, 0x10, 0xae, 0xba,
+	0x74, 0x1c, 0x93, 0x8e, 0x2b, 0x10, 0x1f, 0xf1, 0xa3, 0x2b, 0xf1, 0xa2,
+	0xad, 0xc3, 0xd2, 0xc8, 0xff, 0x9b, 0xf7, 0x63, 0xfa, 0x8e, 0x1f, 0xab,
+	0x13, 0x1a, 0xba, 0x92, 0x0e, 0xb1, 0x4b, 0xfe, 0xfd, 0x92, 0xf7, 0x34,
+	0x6c, 0x4a, 0xe7, 0xeb, 0x8b, 0x9f, 0xf9, 0xd1, 0x90, 0x98, 0xa0, 0x9f,
+	0xd4, 0xd3, 0x47, 0x4c, 0x7c, 0x37, 0x5d, 0x87, 0x7f, 0x4a, 0x07, 0xf1,
+	0x8f, 0xd4, 0xc3, 0xb7, 0xd2, 0x7e, 0x1c, 0x49, 0xcf, 0xc4, 0x53, 0x69,
+	0x1f, 0xbe, 0x49, 0xfd, 0x3f, 0x99, 0x6e, 0xa6, 0xed, 0x6a, 0x38, 0x9c,
+	0x16, 0xfd, 0x15, 0x50, 0xde, 0x62, 0x6c, 0x1a, 0xac, 0x09, 0x9e, 0xa4,
+	0x6d, 0xfc, 0xa3, 0x79, 0x13, 0x32, 0x95, 0xf5, 0xb6, 0x4d, 0x6d, 0xe3,
+	0xf5, 0xed, 0x83, 0x35, 0xd1, 0x2b, 0x15, 0xcb, 0x52, 0x43, 0xb5, 0xe1,
+	0x13, 0xaa, 0x8a, 0x49, 0xaf, 0xee, 0xcf, 0xa8, 0xba, 0x3f, 0x0a, 0x17,
+	0x12, 0xb4, 0xed, 0x78, 0xb5, 0x3e, 0x14, 0xa7, 0x4d, 0x78, 0x8d, 0x7d,
+	0x40, 0x99, 0xee, 0x8f, 0xab, 0x6e, 0x6c, 0x4d, 0xea, 0x7b, 0xe3, 0xaa,
+	0x07, 0xf1, 0x74, 0x31, 0xfe, 0x6d, 0x50, 0xef, 0x89, 0xab, 0x9f, 0x45,
+	0xbc, 0xd2, 0xb2, 0xbe, 0x19, 0x42, 0xfb, 0xf4, 0x08, 0xa2, 0xd5, 0x11,
+	0xc4, 0x66, 0x45, 0xbc, 0x48, 0x26, 0x81, 0x77, 0x7b, 0x0d, 0xdf, 0xbf,
+	0x28, 0xcd, 0xf8, 0x6a, 0xb3, 0xee, 0xf7, 0xab, 0xb5, 0xf1, 0x61, 0x75,
+	0x11, 0x5d, 0x12, 0x7e, 0x5f, 0x64, 0x19, 0x3a, 0xec, 0x6b, 0x0a, 0x34,
+	0xc3, 0x83, 0x4d, 0xc9, 0xeb, 0x10, 0xf3, 0xd6, 0xb4, 0xec, 0x54, 0x6b,
+	0xce, 0x9b, 0xaa, 0x3e, 0xd1, 0xac, 0x5a, 0xd6, 0x07, 0x0b, 0xdf, 0xb5,
+	0xfc, 0xd3, 0x2c, 0x6b, 0xc1, 0x42, 0xe9, 0xd3, 0x8f, 0x8a, 0x88, 0x89,
+	0x95, 0xf6, 0x1c, 0x14, 0xe3, 0xec, 0x60, 0x25, 0xfb, 0xd0, 0xf0, 0xcf,
+	0xd7, 0xea, 0xc1, 0xb5, 0x6a, 0x31, 0xde, 0x1a, 0x29, 0xc6, 0x69, 0x8e,
+	0xe7, 0x97, 0x83, 0x3e, 0xfc, 0x7a, 0xd0, 0xb2, 0xbe, 0x68, 0xfe, 0x35,
+	0x06, 0x2a, 0xfb, 0xf1, 0x4f, 0xe3, 0x5e, 0xfc, 0x1b, 0x75, 0x7b, 0x26,
+	0x11, 0x7d, 0xa0, 0x0a, 0x7a, 0x74, 0x5c, 0x39, 0x79, 0x67, 0x19, 0x6a,
+	0x9b, 0xcb, 0x14, 0xbd, 0x69, 0x07, 0x74, 0xdf, 0x95, 0x8a, 0x17, 0xe7,
+	0x52, 0x1a, 0x7e, 0x9a, 0xaa, 0x09, 0xff, 0x80, 0x7d, 0xfe, 0x87, 0xf9,
+	0xb4, 0x95, 0x99, 0x26, 0x7a, 0x13, 0x1d, 0x51, 0xcf, 0x49, 0xea, 0x39,
+	0x49, 0x3d, 0x27, 0xa9, 0x67, 0xca, 0x70, 0x24, 0x49, 0x3d, 0x53, 0x77,
+	0xdf, 0xa4, 0x4d, 0x3c, 0x99, 0xa4, 0x8e, 0x93, 0x32, 0x47, 0x61, 0xfa,
+	0xe7, 0xa7, 0xf0, 0xf7, 0xf6, 0xdc, 0xbd, 0x6c, 0xfd, 0x37, 0xaf, 0x8c,
+	0xe9, 0xfe, 0x69, 0x59, 0xfc, 0x91, 0xb1, 0xbd, 0x64, 0xc5, 0x34, 0x19,
+	0x97, 0x8c, 0xcf, 0xd6, 0x9f, 0xbf, 0x5d, 0xf9, 0xaa, 0x82, 0x62, 0xcb,
+	0xda, 0x65, 0xe6, 0xee, 0x7b, 0xf3, 0xe3, 0xfb, 0x8c, 0x92, 0xb5, 0x8b,
+	0x7f, 0x72, 0x53, 0xdf, 0xc1, 0xa8, 0xba, 0x88, 0xe7, 0x7a, 0x3c, 0x8a,
+	0x9b, 0x0a, 0x2f, 0x3d, 0xbf, 0xb6, 0x5a, 0xe6, 0xc3, 0x7f, 0xe1, 0x9c,
+	0xf6, 0x64, 0xf7, 0xf7, 0x45, 0x9e, 0xcb, 0x58, 0x04, 0x53, 0xc5, 0x06,
+	0xbc, 0xb4, 0x97, 0x45, 0xb9, 0x7b, 0x88, 0xab, 0x91, 0x76, 0x34, 0xd7,
+	0xef, 0xb5, 0xfb, 0x28, 0xe8, 0x13, 0xbb, 0x57, 0xf0, 0xee, 0x75, 0x0a,
+	0x4e, 0x84, 0x0c, 0xda, 0xcc, 0x10, 0xfd, 0x1a, 0x28, 0xec, 0x83, 0xdb,
+	0x13, 0x89, 0x20, 0xd1, 0x0b, 0x77, 0x51, 0x24, 0x8c, 0xf9, 0xbd, 0x35,
+	0xeb, 0xce, 0x42, 0x0f, 0xf6, 0x2a, 0x7a, 0x33, 0x50, 0x6b, 0x8e, 0x51,
+	0x8f, 0x57, 0x2a, 0xba, 0xbf, 0x40, 0x81, 0x5b, 0x61, 0xb9, 0x40, 0x6a,
+	0x08, 0x5b, 0xd3, 0xf2, 0x3b, 0x0c, 0x23, 0xf5, 0xeb, 0x7c, 0x5f, 0xb4,
+	0xeb, 0x76, 0xda, 0xf5, 0x59, 0x8e, 0x5d, 0xf7, 0x13, 0x1f, 0xdd, 0xae,
+	0xc8, 0x3a, 0x1c, 0x48, 0xc0, 0x5d, 0x10, 0xd9, 0x80, 0xe7, 0x12, 0x1f,
+	0x57, 0xe7, 0xcb, 0x29, 0x2c, 0xe7, 0x4f, 0x4d, 0x95, 0xe5, 0x0d, 0x2b,
+	0xea, 0xcd, 0xca, 0x52, 0xdc, 0x37, 0x84, 0x1d, 0x49, 0xa9, 0x1b, 0xb1,
+	0xeb, 0x3a, 0xd9, 0x47, 0x77, 0xa2, 0xa6, 0xe9, 0x66, 0x45, 0x0f, 0x3f,
+	0x8e, 0xda, 0xe8, 0x3b, 0x9c, 0xc3, 0x2e, 0xe8, 0xe7, 0xd7, 0x21, 0x2b,
+	0xcb, 0xbc, 0x54, 0x56, 0x8e, 0xc5, 0x29, 0x28, 0xb7, 0x27, 0xe1, 0xf1,
+	0x19, 0x55, 0x39, 0x5f, 0x84, 0x72, 0x0b, 0xe7, 0x4f, 0x35, 0xfc, 0xb8,
+	0x85, 0x36, 0xb4, 0x61, 0x97, 0x85, 0x4d, 0xa1, 0x4a, 0xfa, 0x5b, 0x33,
+	0xca, 0x88, 0x87, 0x1b, 0x35, 0x44, 0xcb, 0x23, 0x61, 0xe5, 0xd6, 0xf4,
+	0xce, 0x9c, 0xfe, 0x9f, 0xae, 0xa4, 0x7c, 0x4a, 0x63, 0xf2, 0xf2, 0xeb,
+	0x1f, 0xe5, 0xc7, 0x77, 0xd9, 0xf5, 0xb9, 0x05, 0x9f, 0x5c, 0xbe, 0x56,
+	0x1b, 0x81, 0xc2, 0x78, 0x51, 0x44, 0xfd, 0xea, 0x8c, 0xd2, 0xd1, 0xa0,
+	0xcb, 0xbe, 0xe6, 0xc0, 0x90, 0x33, 0xea, 0x73, 0xe0, 0xf7, 0x56, 0x74,
+	0x95, 0x5c, 0x2b, 0x46, 0xac, 0xb9, 0xd6, 0xe7, 0x44, 0x6d, 0x78, 0x33,
+	0xfd, 0x6d, 0x72, 0x55, 0x03, 0xef, 0x05, 0xcc, 0x93, 0xa8, 0xf1, 0x6f,
+	0x86, 0xfc, 0xfe, 0x90, 0x36, 0xd2, 0x20, 0x75, 0x59, 0x46, 0x6c, 0x4e,
+	0xd7, 0x4e, 0xc2, 0x8b, 0xcd, 0xb4, 0xbf, 0xc2, 0x88, 0x6e, 0x2e, 0x73,
+	0x38, 0x71, 0x88, 0x38, 0xec, 0x30, 0x7a, 0x50, 0xc8, 0x31, 0x32, 0x3e,
+	0xe2, 0xf1, 0x04, 0xf0, 0x62, 0xbf, 0x85, 0x86, 0x90, 0x07, 0x4b, 0x6c,
+	0xdb, 0x3c, 0xaa, 0xdc, 0x98, 0xfc, 0xd8, 0x1a, 0x72, 0x16, 0x45, 0xd5,
+	0x48, 0xc0, 0x77, 0x9a, 0xd1, 0xbc, 0x20, 0x52, 0xab, 0x39, 0x11, 0x57,
+	0x9a, 0xd2, 0xdd, 0xca, 0xf2, 0x74, 0x8f, 0xb2, 0xc4, 0xc6, 0x9c, 0xa3,
+	0xca, 0xd2, 0xb4, 0x07, 0xa9, 0x7e, 0x05, 0x3b, 0x42, 0x94, 0xab, 0x3a,
+	0x6b, 0xc7, 0xe9, 0x7e, 0x95, 0x18, 0xf9, 0x2e, 0x31, 0x52, 0x0f, 0x83,
+	0x7d, 0x3f, 0x9d, 0xa8, 0xc4, 0x51, 0x62, 0xe1, 0x4f, 0x52, 0xe5, 0x2a,
+	0x8a, 0xaf, 0xc0, 0x8f, 0x47, 0xca, 0x30, 0x36, 0x38, 0x8b, 0xbf, 0xeb,
+	0xf0, 0xca, 0x88, 0x65, 0x75, 0x9b, 0x96, 0x75, 0xc0, 0x3c, 0xaa, 0x34,
+	0xb0, 0xcf, 0xa8, 0x33, 0x1e, 0x2d, 0x8c, 0x04, 0xcc, 0xad, 0xec, 0xd3,
+	0x11, 0x89, 0x2b, 0x51, 0xf6, 0x77, 0x23, 0xfb, 0x5b, 0x9a, 0xeb, 0x2f,
+	0xdb, 0xaf, 0xc8, 0x22, 0xf5, 0xf2, 0x75, 0xc2, 0xac, 0x03, 0x1c, 0x4c,
+	0x04, 0x82, 0xf9, 0x7a, 0x4b, 0x59, 0xe7, 0xc6, 0x0b, 0x75, 0x80, 0xe1,
+	0x44, 0x90, 0x73, 0x2a, 0xb6, 0xee, 0x67, 0xec, 0xf9, 0x1a, 0x9c, 0x46,
+	0x3d, 0x5a, 0x87, 0x85, 0x47, 0x84, 0xd5, 0xec, 0x3c, 0x49, 0xfc, 0x74,
+	0xdb, 0x31, 0x6b, 0xd2, 0x21, 0x71, 0x34, 0x88, 0x5e, 0xfa, 0x75, 0x57,
+	0x52, 0x6c, 0xbc, 0xfe, 0xcb, 0x89, 0x80, 0x82, 0x6f, 0x04, 0x32, 0xcd,
+	0xa5, 0x28, 0xc7, 0xba, 0x90, 0xd8, 0xa6, 0xf9, 0xe5, 0xe7, 0x0c, 0x3d,
+	0xbc, 0x42, 0xe1, 0x9c, 0x05, 0xf4, 0xa6, 0xa5, 0x0a, 0x10, 0x18, 0x03,
+	0xce, 0xa4, 0xca, 0xb1, 0xda, 0x74, 0x40, 0xad, 0x08, 0xa2, 0x27, 0x3d,
+	0x15, 0xd7, 0x4d, 0xe2, 0xb4, 0xb4, 0x17, 0xa4, 0x5f, 0x97, 0x60, 0x99,
+	0x96, 0xb5, 0x69, 0x37, 0xdb, 0x76, 0x07, 0x32, 0x41, 0x95, 0xf1, 0xea,
+	0x10, 0x2f, 0x9c, 0x64, 0x5c, 0x6a, 0x30, 0x5c, 0x68, 0xd3, 0xca, 0xd1,
+	0x60, 0xfe, 0xd6, 0x5a, 0xb6, 0x4a, 0xee, 0x5d, 0xc4, 0xf7, 0x42, 0xf6,
+	0xfb, 0xb6, 0xa1, 0xfb, 0x47, 0x79, 0x92, 0x49, 0x65, 0xaf, 0xc7, 0x19,
+	0x73, 0x36, 0xb1, 0xdd, 0x2d, 0x6c, 0x77, 0xad, 0xa6, 0x47, 0xe3, 0x17,
+	0xca, 0x65, 0x82, 0x0e, 0xe8, 0x9a, 0x94, 0x6d, 0x64, 0xbb, 0xab, 0xd9,
+	0x6e, 0x8f, 0x26, 0xf2, 0xfd, 0xd6, 0x5a, 0xbb, 0x4a, 0xee, 0x65, 0xed,
+	0x23, 0xdb, 0x6e, 0xbd, 0xb4, 0x6b, 0x8e, 0xe6, 0xfa, 0x3a, 0x91, 0x40,
+	0xbf, 0x23, 0xc2, 0x18, 0x59, 0x1f, 0xf0, 0x77, 0x31, 0x5e, 0x36, 0x32,
+	0x76, 0x64, 0x6d, 0x62, 0x6a, 0xbc, 0x42, 0xfc, 0x62, 0x19, 0xb9, 0x26,
+	0xe5, 0xc4, 0xd6, 0x26, 0xa9, 0x67, 0x89, 0x2f, 0x3e, 0xea, 0x57, 0xb0,
+	0xc5, 0x89, 0xc3, 0x09, 0xe2, 0x3f, 0xbe, 0x46, 0xbb, 0xf3, 0xa3, 0x39,
+	0x5d, 0x83, 0xb6, 0x5d, 0x8c, 0x63, 0x66, 0x05, 0x6d, 0x3d, 0x6b, 0x6f,
+	0xcb, 0xd8, 0xf6, 0xa4, 0xdd, 0x76, 0x5c, 0x69, 0x4e, 0xd7, 0x6a, 0x15,
+	0x8c, 0x99, 0xc7, 0x2f, 0x60, 0xe7, 0xec, 0x68, 0x71, 0x24, 0xd0, 0xb4,
+	0x9e, 0x93, 0xe4, 0x66, 0x7c, 0xfb, 0xce, 0xbc, 0x6e, 0xda, 0x45, 0x0f,
+	0xed, 0x30, 0x3b, 0xbf, 0x4d, 0x62, 0x70, 0xc4, 0x38, 0xa8, 0x35, 0x58,
+	0xbb, 0x4b, 0xfe, 0x93, 0x6b, 0xd4, 0x3f, 0xca, 0x6b, 0x35, 0x58, 0x3d,
+	0xfc, 0x0d, 0xda, 0x99, 0xee, 0x13, 0x3b, 0xec, 0xba, 0x20, 0x97, 0xc8,
+	0x24, 0xb2, 0x89, 0x4c, 0xff, 0x37, 0xcb, 0xcd, 0xa4, 0x7e, 0x04, 0x1b,
+	0x2b, 0x29, 0xcf, 0x36, 0xf2, 0x99, 0xa3, 0xca, 0x67, 0x29, 0x4f, 0xc6,
+	0xe5, 0xc5, 0x63, 0x49, 0x91, 0x47, 0x89, 0xce, 0x88, 0xcc, 0xc4, 0xf9,
+	0x64, 0x20, 0xfe, 0x34, 0x44, 0xb6, 0x6e, 0xa5, 0x45, 0xea, 0x27, 0x7b,
+	0x78, 0x2f, 0x2f, 0x23, 0xb4, 0x72, 0x5b, 0xb6, 0xac, 0x4c, 0xb7, 0x72,
+	0xae, 0x5d, 0xc6, 0xfd, 0xa5, 0x28, 0x73, 0xd2, 0xd6, 0xa4, 0xed, 0x9f,
+	0x59, 0x51, 0x6d, 0x13, 0xaf, 0x79, 0x39, 0x4f, 0x6e, 0xc6, 0x75, 0x3d,
+	0x78, 0x8b, 0x43, 0x69, 0xf6, 0x48, 0xbc, 0xa6, 0x7d, 0xa6, 0x52, 0x4e,
+	0x3c, 0x93, 0x58, 0xba, 0xb4, 0xc4, 0xb8, 0x1a, 0xdf, 0x18, 0xf1, 0x61,
+	0x84, 0x73, 0xfb, 0x62, 0x42, 0xe2, 0xeb, 0x4c, 0x3c, 0x91, 0xf2, 0xe0,
+	0x85, 0x84, 0x1f, 0x8f, 0x33, 0xfe, 0x4c, 0x24, 0x0c, 0x1c, 0x4a, 0x79,
+	0xf1, 0x3c, 0xed, 0x79, 0x34, 0xe5, 0xa3, 0xbd, 0xd4, 0x61, 0x38, 0xd5,
+	0x6c, 0x8f, 0xe1, 0xd9, 0xc4, 0xab, 0x32, 0xd6, 0xa0, 0x8c, 0x75, 0x8b,
+	0x3d, 0xd6, 0x7c, 0x9c, 0x9f, 0x79, 0x61, 0x1e, 0x4e, 0x25, 0x6c, 0x1c,
+	0xe8, 0x59, 0xe6, 0x90, 0x79, 0xa0, 0xcd, 0x0e, 0x08, 0x16, 0xe8, 0xfd,
+	0x71, 0x58, 0xd8, 0x6f, 0xce, 0xa0, 0xff, 0xf7, 0x50, 0x5e, 0xea, 0x94,
+	0xe3, 0x87, 0xab, 0x2c, 0x5a, 0x1a, 0x09, 0xc4, 0x7a, 0xa9, 0x77, 0x67,
+	0x44, 0xf4, 0x90, 0xd5, 0xfb, 0x8a, 0xf4, 0x51, 0x45, 0xb8, 0xda, 0x95,
+	0x03, 0x71, 0xab, 0xc4, 0x10, 0x7d, 0x07, 0x88, 0xb3, 0xc0, 0xfc, 0xfd,
+	0x4e, 0x8e, 0x6f, 0x25, 0xc7, 0x6c, 0xa2, 0xc0, 0xa8, 0xd5, 0x2a, 0x29,
+	0xfb, 0xf1, 0x3f, 0x88, 0x81, 0xa2, 0xa3, 0x35, 0xb9, 0xf9, 0x2a, 0x77,
+	0x50, 0x5e, 0x3f, 0x90, 0x9f, 0x17, 0xcb, 0xda, 0x69, 0xe6, 0xe7, 0xa6,
+	0x1a, 0xfe, 0x4a, 0x3d, 0x3e, 0x44, 0x8b, 0x18, 0x49, 0x54, 0x21, 0xae,
+	0xa9, 0xb9, 0xb6, 0xa3, 0x4a, 0x01, 0xf3, 0x07, 0x8c, 0x8b, 0xef, 0x97,
+	0x22, 0xea, 0x94, 0xfa, 0x88, 0x16, 0x44, 0x02, 0xc1, 0xb9, 0xea, 0x54,
+	0x9b, 0x11, 0x1c, 0x90, 0xbe, 0xe2, 0x94, 0xf5, 0x52, 0x2c, 0x18, 0x49,
+	0xe4, 0x71, 0xe3, 0x3f, 0x53, 0xcf, 0x4b, 0x1f, 0x9b, 0xaa, 0x53, 0x91,
+	0x53, 0xf4, 0xaa, 0xa2, 0x75, 0x50, 0xf4, 0xe7, 0xc4, 0x4a, 0x73, 0x51,
+	0x4e, 0xe6, 0x99, 0x68, 0x4b, 0xa8, 0xd8, 0x30, 0xc8, 0xbe, 0x52, 0x0a,
+	0x36, 0x87, 0x96, 0x60, 0xc8, 0x6b, 0xd3, 0x45, 0xb4, 0x26, 0x1a, 0x69,
+	0x63, 0xc4, 0x99, 0x71, 0x3b, 0x7e, 0xda, 0xfe, 0x33, 0x9b, 0x3e, 0xb1,
+	0x2c, 0xfd, 0x20, 0xd6, 0x26, 0x03, 0xfe, 0x93, 0x78, 0x10, 0x6d, 0x69,
+	0x17, 0x62, 0xc3, 0x1e, 0x74, 0xb2, 0x6f, 0xb5, 0x4f, 0xfc, 0x49, 0x43,
+	0xe7, 0xe8, 0x89, 0x17, 0x54, 0xda, 0x67, 0xe7, 0xa8, 0x97, 0xc7, 0x34,
+	0x1e, 0x6e, 0x3c, 0xc4, 0xe3, 0x28, 0xe7, 0xbf, 0x83, 0x18, 0x9c, 0x4e,
+	0x98, 0xb8, 0x9f, 0x32, 0x8d, 0x27, 0xea, 0xb1, 0x91, 0xf2, 0x8d, 0x25,
+	0x1c, 0xf0, 0x4f, 0x0b, 0xe3, 0x3e, 0xea, 0xf2, 0xc9, 0x44, 0x58, 0x79,
+	0x80, 0xff, 0x0f, 0x51, 0x26, 0xc9, 0x47, 0xd6, 0xd1, 0x0e, 0xa2, 0xd3,
+	0x68, 0x27, 0x6a, 0xad, 0xc3, 0x9e, 0x07, 0x88, 0x7f, 0x5c, 0x3e, 0x57,
+	0xba, 0x16, 0x43, 0x7e, 0xbe, 0x80, 0xa1, 0x14, 0x62, 0xee, 0x48, 0x5d,
+	0x63, 0x41, 0x6f, 0xeb, 0x86, 0xc2, 0x48, 0xfb, 0x43, 0x3f, 0xad, 0x9f,
+	0x85, 0x93, 0x9c, 0x13, 0xa7, 0x6d, 0xe3, 0x51, 0xc5, 0x65, 0x18, 0xb6,
+	0x2f, 0xab, 0xe3, 0xed, 0xb9, 0xbc, 0x4a, 0x97, 0x38, 0xc6, 0x3e, 0x44,
+	0x6f, 0xa2, 0x0b, 0xd1, 0xc3, 0x71, 0x6b, 0xc8, 0xf6, 0x77, 0xf1, 0x39,
+	0x27, 0x75, 0xf4, 0x5d, 0xc6, 0x6f, 0xd1, 0x85, 0x94, 0xdb, 0xca, 0xb6,
+	0x44, 0x1e, 0x3b, 0x16, 0xfa, 0xfe, 0xd0, 0x76, 0xa6, 0xca, 0x53, 0x87,
+	0xed, 0x7b, 0x0c, 0xec, 0xd8, 0x53, 0x4b, 0xbb, 0xfb, 0xa5, 0xe5, 0xaf,
+	0x18, 0x60, 0xdd, 0xa9, 0xb2, 0x08, 0x2f, 0x40, 0xae, 0x5d, 0x69, 0x73,
+	0x13, 0xef, 0x1d, 0xa6, 0xad, 0x49, 0xbb, 0x96, 0xb5, 0xe5, 0x42, 0xdc,
+	0x28, 0x88, 0x16, 0x31, 0x6e, 0x1c, 0x4a, 0x04, 0xc2, 0x2f, 0xd8, 0xb1,
+	0xcd, 0x49, 0xdb, 0x90, 0xf9, 0xef, 0xb6, 0xe7, 0x7e, 0xd9, 0x85, 0xb9,
+	0x9f, 0xbc, 0xc0, 0x91, 0xfa, 0x93, 0x53, 0x7d, 0x2a, 0x3b, 0xef, 0xce,
+	0x3e, 0xbd, 0xc7, 0xb6, 0xd3, 0x94, 0xe0, 0x9f, 0x03, 0x8e, 0x01, 0xce,
+	0xb3, 0x79, 0x15, 0xc7, 0x5f, 0xc9, 0x78, 0x52, 0xc0, 0x83, 0x79, 0xe4,
+	0xf0, 0xa7, 0x50, 0x3c, 0x90, 0xb1, 0x8a, 0xf8, 0xbb, 0x29, 0x14, 0x08,
+	0x17, 0x29, 0x37, 0xe0, 0xee, 0x61, 0x07, 0x0a, 0x06, 0x14, 0x3c, 0x6b,
+	0xd6, 0xe5, 0xec, 0x43, 0xe6, 0xfb, 0x2a, 0xdb, 0x3e, 0xe6, 0x8c, 0xcb,
+	0x7c, 0xcb, 0x1c, 0x7b, 0xe0, 0xeb, 0x53, 0xe0, 0x21, 0x6e, 0x94, 0x18,
+	0x32, 0xd7, 0x1a, 0xca, 0xfb, 0x64, 0xae, 0x49, 0x1b, 0x77, 0x87, 0xb1,
+	0x91, 0xf6, 0x50, 0xba, 0xfb, 0x7a, 0xdc, 0xc7, 0x72, 0x1b, 0x78, 0x6f,
+	0xc3, 0x68, 0x25, 0x0f, 0x2f, 0x8f, 0x69, 0x3c, 0xea, 0x71, 0xef, 0x70,
+	0x0d, 0xa2, 0x95, 0x7a, 0xd0, 0xaf, 0x3a, 0x50, 0x39, 0x20, 0x3a, 0x55,
+	0xb1, 0x72, 0x81, 0x02, 0xf3, 0xea, 0x42, 0xa8, 0x73, 0x3f, 0xc9, 0x37,
+	0xff, 0x9c, 0xac, 0x3f, 0x9a, 0x32, 0x87, 0x6e, 0x8e, 0xfd, 0x9f, 0xed,
+	0x39, 0x9c, 0x33, 0x2e, 0x7d, 0x48, 0x2c, 0xb5, 0xe7, 0xf1, 0x4f, 0xf8,
+	0xfe, 0x73, 0x9c, 0x8f, 0x2e, 0x96, 0xf9, 0xc3, 0xf9, 0xc5, 0x85, 0xf9,
+	0x9d, 0xca, 0x49, 0x25, 0xae, 0xeb, 0xe1, 0x21, 0x9b, 0xc3, 0xf8, 0x99,
+	0xcf, 0xe9, 0x71, 0xd1, 0x39, 0x39, 0x8b, 0x5b, 0x35, 0xe0, 0x2f, 0x30,
+	0xee, 0xc0, 0x3d, 0x9c, 0xa7, 0x03, 0x09, 0x75, 0xa9, 0x0b, 0xea, 0x4c,
+	0x17, 0x13, 0xdb, 0x11, 0x53, 0xc7, 0xba, 0x61, 0xe6, 0x4a, 0xc3, 0xa5,
+	0xe8, 0xd2, 0x14, 0xf7, 0xf6, 0xba, 0x45, 0x92, 0xf3, 0xfa, 0xcb, 0x0d,
+	0xa8, 0x25, 0x8c, 0xef, 0x3b, 0x34, 0x38, 0x0b, 0x0c, 0x45, 0x4d, 0xd4,
+	0x35, 0x22, 0x5e, 0x01, 0x67, 0x99, 0x01, 0x85, 0x39, 0x2d, 0x7a, 0x35,
+	0x08, 0xb6, 0x44, 0x0b, 0x8c, 0x07, 0x71, 0x4f, 0x12, 0x56, 0x71, 0x84,
+	0xf9, 0x4e, 0xc4, 0x20, 0x87, 0x0d, 0xf8, 0x0a, 0x94, 0x07, 0xb1, 0x9a,
+	0xbc, 0x61, 0xcd, 0xb0, 0xc8, 0xe1, 0x21, 0x9f, 0x30, 0xfc, 0xad, 0x60,
+	0x8e, 0xdd, 0xac, 0x07, 0x27, 0x99, 0x67, 0xae, 0xa6, 0xee, 0x47, 0x12,
+	0x0f, 0xa2, 0x21, 0x79, 0xdc, 0xf2, 0x90, 0x27, 0x16, 0x18, 0x35, 0xe7,
+	0xbb, 0x10, 0xa3, 0x0f, 0x0b, 0xff, 0x69, 0xc3, 0x43, 0xf4, 0xbf, 0x74,
+	0x42, 0x7d, 0x86, 0xec, 0x01, 0x1d, 0xa3, 0xeb, 0x71, 0xff, 0xe8, 0x4c,
+	0xfa, 0xea, 0x06, 0xfa, 0x2a, 0xb9, 0x50, 0xff, 0x0d, 0xb8, 0x6f, 0xf8,
+	0x06, 0xdc, 0xbb, 0xcb, 0x08, 0x6e, 0xa0, 0xae, 0xd7, 0x0c, 0x33, 0x10,
+	0x4e, 0x93, 0x76, 0xf3, 0xba, 0x12, 0x3e, 0x48, 0x5d, 0xe4, 0xf4, 0x94,
+	0x41, 0x9e, 0xa3, 0xfc, 0xb3, 0xc5, 0x4b, 0xf1, 0x82, 0x7a, 0xc5, 0xbf,
+	0xb7, 0xee, 0xfb, 0xcc, 0xbd, 0x45, 0x76, 0x44, 0x67, 0x18, 0xaf, 0x5a,
+	0x8f, 0x6a, 0x0a, 0x0a, 0x22, 0x88, 0xcf, 0xae, 0x7f, 0xd9, 0x7a, 0x6c,
+	0x95, 0x5c, 0xbf, 0xd5, 0x89, 0x62, 0x95, 0xd7, 0xa4, 0xcd, 0x1d, 0x32,
+	0x47, 0x44, 0xda, 0x4f, 0x6a, 0x33, 0x63, 0xf5, 0x5d, 0x28, 0x4f, 0xde,
+	0x47, 0xac, 0x7d, 0x3a, 0xe1, 0x45, 0x4f, 0x32, 0xcb, 0x9d, 0x6e, 0x4f,
+	0x0b, 0x67, 0x72, 0xa3, 0xb8, 0x57, 0xe2, 0x46, 0x14, 0xeb, 0xf9, 0xbb,
+	0xa8, 0x57, 0x6f, 0x8e, 0x83, 0xc9, 0xbc, 0xd1, 0xc8, 0xb9, 0xa0, 0xbd,
+	0xf6, 0x3a, 0x50, 0x64, 0x34, 0x65, 0x6d, 0xb5, 0x77, 0x85, 0x8d, 0x4b,
+	0x65, 0xbd, 0xdd, 0x36, 0x2e, 0x95, 0xb2, 0x9e, 0x60, 0x92, 0xa7, 0x77,
+	0x15, 0xed, 0x75, 0x26, 0x4a, 0x7a, 0x5b, 0x70, 0x2f, 0xe7, 0x78, 0x2d,
+	0x79, 0xf6, 0x09, 0xb3, 0x3c, 0xc7, 0x3f, 0x9b, 0x70, 0x77, 0x32, 0x8a,
+	0xd6, 0x64, 0x4d, 0xf4, 0xb4, 0xac, 0x25, 0xb9, 0xb2, 0xd8, 0x19, 0xad,
+	0x16, 0x5d, 0x3c, 0x97, 0xc3, 0x08, 0xbd, 0x29, 0xcb, 0xd9, 0x74, 0xcd,
+	0xaf, 0xe4, 0x65, 0xef, 0x46, 0x8c, 0xf9, 0xc5, 0xec, 0x48, 0x33, 0xac,
+	0xa4, 0xc8, 0x1d, 0xb7, 0x7c, 0xcc, 0x19, 0x3d, 0x11, 0xbd, 0x7d, 0xb1,
+	0xc3, 0xe8, 0xf8, 0xb1, 0x12, 0xc4, 0xad, 0x94, 0xa1, 0xa4, 0xb7, 0x13,
+	0xaf, 0x84, 0x74, 0xdf, 0xb7, 0x15, 0xfd, 0xfc, 0x06, 0xfc, 0x18, 0x3f,
+	0xe7, 0xb5, 0x82, 0xde, 0x09, 0x3c, 0x96, 0x7e, 0x1d, 0x67, 0x29, 0xab,
+	0xda, 0xfb, 0xb1, 0xb5, 0xcc, 0x20, 0x18, 0x14, 0xbb, 0x95, 0xb7, 0xd3,
+	0x53, 0x6d, 0xf1, 0x06, 0xac, 0xde, 0x25, 0xf6, 0xa7, 0x07, 0xe3, 0xa0,
+	0x7c, 0x66, 0x99, 0x60, 0x9c, 0xc4, 0x1f, 0xca, 0xdf, 0x4c, 0xd9, 0x2c,
+	0xfa, 0x07, 0xed, 0xc0, 0x1e, 0xc3, 0x43, 0x36, 0x0e, 0x3a, 0xfb, 0xe4,
+	0xc8, 0xeb, 0x39, 0xa2, 0xb4, 0x8e, 0x5e, 0x53, 0x8c, 0x62, 0x5f, 0xce,
+	0x0f, 0xb2, 0x6b, 0x0a, 0x17, 0xeb, 0xfe, 0xd2, 0x1a, 0xf1, 0x5e, 0x5a,
+	0xb7, 0x8c, 0x39, 0x56, 0x39, 0xc7, 0xf3, 0x5e, 0x6f, 0xdc, 0x2a, 0xce,
+	0x8e, 0xa5, 0xe9, 0x55, 0x45, 0x6c, 0x32, 0x48, 0xee, 0xde, 0x89, 0xab,
+	0x42, 0x7a, 0xcb, 0xb7, 0x15, 0x29, 0xab, 0x87, 0x37, 0x28, 0xf9, 0x7e,
+	0x7e, 0x84, 0xd3, 0x23, 0xd2, 0x87, 0xf4, 0x35, 0xc1, 0x9c, 0xeb, 0x52,
+	0x7f, 0x4a, 0xd9, 0xf3, 0xa9, 0x9b, 0x43, 0xe4, 0x75, 0x2b, 0x38, 0xcc,
+	0x92, 0x5e, 0x19, 0x93, 0xa9, 0xdc, 0x3b, 0x2a, 0xf3, 0xba, 0x40, 0x59,
+	0x4f, 0x2c, 0x29, 0xea, 0xad, 0x57, 0xee, 0x21, 0x96, 0x14, 0xee, 0xac,
+	0x51, 0xee, 0xb6, 0x6d, 0xbe, 0x0a, 0x23, 0xfd, 0xd7, 0x28, 0x6d, 0xc3,
+	0xa2, 0x03, 0x37, 0xc7, 0x3e, 0x8d, 0x63, 0xf7, 0xa2, 0x8f, 0xfe, 0xfb,
+	0x4a, 0x6f, 0x9d, 0x72, 0x1f, 0x7d, 0xa3, 0x73, 0x97, 0x8a, 0xc9, 0x2a,
+	0x85, 0x78, 0x47, 0xfe, 0x6b, 0xf8, 0x94, 0xd6, 0xe1, 0xef, 0x3b, 0x25,
+	0xbe, 0x64, 0x70, 0x03, 0x5a, 0x79, 0x6f, 0xa9, 0xe9, 0x42, 0x46, 0xab,
+	0xd5, 0x34, 0xac, 0xc0, 0xea, 0xe4, 0x2a, 0xb4, 0x25, 0x8b, 0xc9, 0x73,
+	0x65, 0xbc, 0x79, 0xb9, 0xf3, 0xf3, 0xf8, 0x20, 0x5a, 0x92, 0x88, 0xcf,
+	0x88, 0x04, 0x3a, 0x66, 0x38, 0xe8, 0xd2, 0xc5, 0x75, 0xca, 0xfd, 0xe9,
+	0x1a, 0x65, 0xcd, 0xae, 0x72, 0x64, 0xb1, 0xe7, 0x61, 0x34, 0xed, 0xa9,
+	0x57, 0xee, 0xde, 0x53, 0x85, 0x49, 0xcd, 0xb2, 0x9c, 0xa1, 0x7a, 0xa5,
+	0x75, 0x8f, 0x65, 0xdd, 0x64, 0x46, 0x9b, 0x8a, 0xc9, 0x77, 0xb7, 0xb1,
+	0xbd, 0xd6, 0x51, 0xe9, 0xe7, 0xf2, 0x76, 0x4d, 0x65, 0xe3, 0x9e, 0x87,
+	0xb1, 0x82, 0x65, 0x5f, 0x09, 0x45, 0x5b, 0x4a, 0x59, 0x56, 0x74, 0xd6,
+	0x3a, 0xfa, 0x19, 0xf6, 0x21, 0xe5, 0x17, 0x4c, 0x69, 0x67, 0x31, 0xaf,
+	0x49, 0x5b, 0x59, 0xdd, 0x89, 0xde, 0x1e, 0xcf, 0xea, 0x2d, 0x2c, 0x7a,
+	0x5b, 0x4e, 0x5d, 0xba, 0x7a, 0x7d, 0x3c, 0x5c, 0xf4, 0x75, 0x1f, 0xd6,
+	0xa4, 0x65, 0x4c, 0x33, 0x89, 0x03, 0xcd, 0xb4, 0xdb, 0x76, 0xb4, 0x52,
+	0xaf, 0x71, 0x2d, 0x6b, 0x9f, 0x17, 0x7d, 0x4b, 0xf7, 0x4f, 0x72, 0xec,
+	0xad, 0x49, 0xd1, 0x4b, 0x33, 0xcb, 0xdb, 0xf7, 0xe9, 0xdb, 0x53, 0xcb,
+	0x5c, 0x3a, 0x57, 0xfb, 0x13, 0xc2, 0x27, 0x0a, 0xc8, 0x7d, 0x0a, 0xd8,
+	0x5e, 0x96, 0x2b, 0x8a, 0xbd, 0x38, 0x68, 0x2f, 0xcf, 0x98, 0xc5, 0xd8,
+	0xe4, 0x95, 0x31, 0x66, 0xf5, 0x0c, 0x15, 0x58, 0xc7, 0x7b, 0x2e, 0xde,
+	0x2b, 0x0c, 0x15, 0xe2, 0x2d, 0x5b, 0x57, 0x59, 0x3e, 0x98, 0xf7, 0xf3,
+	0xa1, 0x0b, 0xfd, 0x1c, 0xab, 0xce, 0xda, 0xd8, 0x26, 0x57, 0x96, 0x33,
+	0xe6, 0xb9, 0x8d, 0x65, 0x0d, 0x98, 0x79, 0x6e, 0x23, 0x71, 0xee, 0x53,
+	0xc2, 0x15, 0x6c, 0x1e, 0xd6, 0x96, 0xeb, 0xb7, 0xcb, 0x0c, 0xd0, 0x4f,
+	0x85, 0xfb, 0x45, 0x94, 0xb6, 0x3d, 0xa7, 0x68, 0xab, 0x92, 0x8b, 0x01,
+	0x1b, 0x79, 0xbf, 0x94, 0xf7, 0x5f, 0x0b, 0xb9, 0x70, 0xd5, 0x34, 0xe9,
+	0xfb, 0x06, 0x74, 0xec, 0x8a, 0xa2, 0x7c, 0x61, 0x00, 0x93, 0xf6, 0x7a,
+	0x59, 0x9e, 0xa7, 0xbb, 0x70, 0xdf, 0xae, 0x8f, 0xad, 0x32, 0x9b, 0x3b,
+	0x1a, 0xb1, 0x71, 0x45, 0xc5, 0x8e, 0x45, 0xc2, 0xd7, 0x5d, 0x8c, 0x57,
+	0xe4, 0xce, 0x92, 0x0b, 0xb8, 0x4a, 0xc8, 0xb9, 0x85, 0x73, 0x06, 0x32,
+	0xb7, 0xab, 0xd0, 0xb4, 0x88, 0x70, 0xcf, 0x99, 0x36, 0xe7, 0x16, 0xee,
+	0xfd, 0xcd, 0xe4, 0xd1, 0x29, 0xdc, 0xfb, 0x02, 0x4f, 0x61, 0xae, 0xd6,
+	0x8c, 0x44, 0xaf, 0x07, 0xee, 0x88, 0xde, 0xbc, 0x59, 0xe9, 0xc4, 0xf2,
+	0x90, 0x61, 0xca, 0x1a, 0xc0, 0xf5, 0x8a, 0x1e, 0x3c, 0x87, 0x20, 0xe3,
+	0xc7, 0x8f, 0x30, 0x32, 0xf8, 0x0f, 0x2e, 0xf1, 0x8b, 0xcd, 0xe9, 0x8b,
+	0xf2, 0xdc, 0x4d, 0x79, 0xdc, 0x59, 0x79, 0xcc, 0x73, 0x54, 0xe4, 0xb3,
+	0xf5, 0x2e, 0xe2, 0xf0, 0x7f, 0xb7, 0xed, 0x76, 0x89, 0x9d, 0x4b, 0xfc,
+	0x77, 0xc6, 0x93, 0x70, 0x71, 0x5e, 0xcf, 0x9d, 0xc4, 0xab, 0x0f, 0x17,
+	0x16, 0x21, 0x44, 0x7b, 0xaf, 0x30, 0x3a, 0x98, 0xcf, 0x7f, 0x6c, 0xc5,
+	0x9d, 0xa4, 0xdf, 0x06, 0xb4, 0xa2, 0x48, 0x94, 0xb2, 0x35, 0x2a, 0x37,
+	0x0d, 0x8f, 0xb3, 0x9f, 0x0e, 0xe6, 0x29, 0x1e, 0x3c, 0x40, 0x5c, 0x79,
+	0x80, 0xfe, 0xf4, 0x00, 0x63, 0xf3, 0x03, 0xa3, 0xff, 0x8b, 0xd7, 0xa7,
+	0xd9, 0xbf, 0x37, 0x27, 0xf3, 0xf6, 0xe5, 0x64, 0x9c, 0x13, 0xfd, 0x6e,
+	0x21, 0x16, 0x48, 0x9c, 0x03, 0x65, 0xb2, 0x70, 0xda, 0x2c, 0xa4, 0xae,
+	0xf5, 0x60, 0x06, 0x09, 0xd7, 0xc5, 0x3c, 0x35, 0x1f, 0x2b, 0x65, 0x1e,
+	0x5d, 0xb8, 0x87, 0x32, 0x06, 0x43, 0xbf, 0xb1, 0x50, 0x21, 0x58, 0x74,
+	0xf9, 0xfd, 0xec, 0xbc, 0x1e, 0xbf, 0xc0, 0x59, 0x15, 0xc9, 0x91, 0xe8,
+	0xef, 0xfd, 0x36, 0x07, 0x7b, 0x8d, 0x3e, 0xd9, 0xb6, 0xeb, 0xc4, 0x7c,
+	0x31, 0x95, 0x35, 0xa3, 0x51, 0x6c, 0xe2, 0xb8, 0x57, 0x0f, 0x3f, 0x9a,
+	0xd3, 0x4b, 0x7e, 0xbc, 0xe2, 0xd3, 0x1e, 0xda, 0x74, 0x36, 0xb7, 0x6a,
+	0x1d, 0x15, 0x2e, 0x5e, 0xc9, 0xff, 0xc2, 0xc5, 0xc5, 0x7f, 0x84, 0x97,
+	0x4f, 0xe3, 0x7f, 0x27, 0x39, 0xa7, 0x70, 0xe9, 0x3a, 0xf4, 0xd0, 0x8f,
+	0x0a, 0x03, 0x75, 0xd8, 0x3a, 0x7a, 0xf9, 0x1c, 0x5d, 0x2e, 0x8f, 0x3d,
+	0x07, 0xcc, 0xc3, 0x5c, 0x82, 0xad, 0x7e, 0xbf, 0x2a, 0x7d, 0x5b, 0x68,
+	0x37, 0x6f, 0xc8, 0x72, 0xa7, 0x4a, 0xb9, 0x36, 0x95, 0x9f, 0xe7, 0xdb,
+	0x99, 0x7a, 0x4d, 0x2d, 0x40, 0x71, 0x9e, 0x37, 0x78, 0x73, 0xb9, 0x0e,
+	0xf3, 0x9b, 0xa4, 0xe8, 0x4b, 0xc6, 0x90, 0xcd, 0x5f, 0xc5, 0x5e, 0x2e,
+	0xc5, 0x83, 0xf8, 0xb4, 0x22, 0x43, 0x6c, 0x25, 0x48, 0x7f, 0xd6, 0xc3,
+	0x4d, 0x0c, 0x35, 0x67, 0x13, 0x88, 0x39, 0x22, 0x4d, 0x8d, 0x6b, 0x12,
+	0x73, 0xb5, 0x67, 0x72, 0xf9, 0xf1, 0x7e, 0xc6, 0x1e, 0xd5, 0x90, 0xb5,
+	0x19, 0xda, 0xc3, 0xb0, 0xe8, 0xa7, 0x43, 0xb9, 0x98, 0x0b, 0x47, 0xc9,
+	0x15, 0x19, 0x57, 0x0d, 0xc9, 0x91, 0x1a, 0x95, 0xa5, 0xc3, 0x52, 0x87,
+	0xf6, 0x70, 0x19, 0x67, 0xcc, 0x8e, 0xb7, 0x0c, 0x9e, 0x01, 0xe1, 0x8a,
+	0x3a, 0x36, 0x90, 0x9b, 0x94, 0x0c, 0xf8, 0x69, 0xef, 0x95, 0x28, 0xde,
+	0x1d, 0xc1, 0xfa, 0x51, 0x0d, 0x45, 0xbb, 0x2d, 0x6b, 0x6e, 0xa8, 0x1b,
+	0x6b, 0xd3, 0xcb, 0x0b, 0x24, 0x9f, 0x73, 0xf6, 0x11, 0x2b, 0x88, 0x2b,
+	0xeb, 0x92, 0x0a, 0x6e, 0x24, 0x07, 0x88, 0xa2, 0x99, 0xdc, 0x5d, 0xf0,
+	0xc5, 0xea, 0x9c, 0x1d, 0x71, 0xd1, 0x4e, 0x56, 0xf1, 0x7e, 0x0b, 0xb1,
+	0xa7, 0x85, 0x58, 0x62, 0x59, 0x1f, 0x5e, 0x8b, 0xce, 0x92, 0xc8, 0x1d,
+	0xc4, 0xa0, 0x1a, 0xe6, 0x0f, 0xc2, 0x39, 0xae, 0x45, 0x1b, 0xb1, 0xbb,
+	0xb0, 0xcf, 0xce, 0xf1, 0xa8, 0x47, 0xc6, 0xd5, 0x34, 0xe3, 0x32, 0x65,
+	0x7f, 0x9e, 0x7c, 0xbd, 0x83, 0x7e, 0x54, 0xde, 0xb7, 0x81, 0xf1, 0xd9,
+	0x83, 0xb2, 0x81, 0x6b, 0xb0, 0x91, 0xd8, 0x7e, 0xdf, 0x2e, 0x3f, 0x52,
+	0x8b, 0x6e, 0xa0, 0x7c, 0x0f, 0x62, 0x7d, 0xd2, 0x90, 0xbc, 0x2e, 0x1a,
+	0x5c, 0xf4, 0x20, 0xfb, 0xa5, 0x7d, 0xec, 0x92, 0x1c, 0xb1, 0x04, 0x4b,
+	0x9a, 0x81, 0x60, 0x9f, 0x60, 0x8e, 0x8c, 0xff, 0x36, 0x59, 0xcf, 0x82,
+	0xd1, 0x37, 0x75, 0x3e, 0xa6, 0x72, 0x39, 0x59, 0x1b, 0x6c, 0xc6, 0x7c,
+	0xc6, 0x2f, 0xb1, 0x21, 0x8d, 0x79, 0x6f, 0x91, 0x62, 0xf8, 0xf6, 0xd3,
+	0x17, 0x25, 0x17, 0xbb, 0xae, 0x2f, 0x1f, 0xaf, 0xf5, 0xcc, 0x62, 0x47,
+	0x27, 0xb1, 0x42, 0x6f, 0xff, 0xad, 0xa2, 0xaf, 0x3b, 0xa5, 0xfc, 0x18,
+	0x07, 0xc7, 0x5e, 0xc7, 0xd0, 0x98, 0x5b, 0x19, 0x1d, 0x93, 0xbe, 0x26,
+	0xd0, 0x9b, 0xfe, 0x73, 0x7d, 0x4d, 0x5d, 0x13, 0x5a, 0x74, 0xc9, 0x3a,
+	0xd2, 0x8d, 0xb9, 0xdc, 0x75, 0xe9, 0x25, 0x9c, 0x5e, 0xe6, 0x44, 0x6c,
+	0xcf, 0x8b, 0xee, 0xe4, 0xc5, 0xb5, 0x8a, 0xfe, 0xc4, 0x76, 0xdb, 0x07,
+	0x9b, 0xd3, 0x62, 0x93, 0xcc, 0xef, 0xcc, 0x39, 0xf6, 0xb3, 0x1b, 0x59,
+	0x5f, 0x58, 0xb3, 0xab, 0xd7, 0xbe, 0x77, 0xd0, 0xfc, 0x2b, 0x64, 0xec,
+	0x6b, 0x8b, 0xe9, 0x7f, 0x8c, 0x93, 0xc4, 0xbd, 0x60, 0xc8, 0x87, 0xc2,
+	0x0a, 0x59, 0x5b, 0xba, 0xb8, 0x1e, 0xb1, 0x61, 0x17, 0x69, 0x84, 0x8d,
+	0x2b, 0x0d, 0xc4, 0xb8, 0x1a, 0xce, 0x77, 0x16, 0x4b, 0xd6, 0xd3, 0x86,
+	0x6e, 0x11, 0x1b, 0x72, 0x65, 0x6d, 0xe8, 0x0f, 0xd7, 0x3c, 0x54, 0x90,
+	0xaf, 0x6a, 0x65, 0x76, 0x2e, 0xda, 0xa8, 0xdc, 0x9a, 0xb3, 0xab, 0xcf,
+	0xa6, 0xbf, 0x53, 0x90, 0xcb, 0x91, 0x2e, 0x2b, 0xff, 0x49, 0x3a, 0xb8,
+	0xe6, 0x2f, 0xd0, 0x81, 0x60, 0xbe, 0xe4, 0x31, 0xa2, 0x83, 0x99, 0x53,
+	0xfc, 0xf2, 0x93, 0xf4, 0x50, 0x9b, 0xd3, 0xc3, 0x62, 0x62, 0x48, 0x25,
+	0x71, 0x4f, 0x38, 0x4b, 0x00, 0x4f, 0x6a, 0x79, 0x3d, 0x38, 0x73, 0x7a,
+	0xd0, 0xff, 0x40, 0x0f, 0xf7, 0x13, 0x5f, 0x4b, 0xd9, 0x56, 0x31, 0x8f,
+	0x77, 0xa9, 0x87, 0x8d, 0xc3, 0x8b, 0xf1, 0x00, 0x7d, 0x69, 0x83, 0xbd,
+	0x5e, 0x23, 0xcf, 0xef, 0x5c, 0x97, 0xe8, 0x66, 0x25, 0xe5, 0xf7, 0x17,
+	0xa8, 0x98, 0x41, 0x1d, 0xf8, 0x6c, 0x3c, 0x95, 0x3e, 0x1a, 0x95, 0xdb,
+	0x87, 0x05, 0xe3, 0x3e, 0xa6, 0x0e, 0x3a, 0x18, 0x07, 0xfe, 0x54, 0x9e,
+	0x21, 0xfd, 0x7f, 0x7c, 0x41, 0x57, 0x7f, 0xbc, 0xdc, 0x8f, 0xa9, 0x03,
+	0x79, 0x26, 0x22, 0x6b, 0xec, 0xf2, 0x7c, 0x44, 0xf4, 0x61, 0x4c, 0xd1,
+	0x83, 0x65, 0x1d, 0x31, 0xe7, 0x21, 0x56, 0xa9, 0xf7, 0x4b, 0x1c, 0xed,
+	0x27, 0xa6, 0x38, 0x98, 0xb7, 0x17, 0x44, 0xa2, 0x14, 0x5b, 0xbd, 0x81,
+	0x4c, 0xa7, 0xce, 0x81, 0x4e, 0x9c, 0x31, 0x8d, 0x9e, 0xb5, 0xf8, 0x2b,
+	0x74, 0x79, 0x2d, 0x1c, 0x60, 0x3b, 0x9b, 0x92, 0x45, 0x58, 0x57, 0x47,
+	0xd3, 0x5c, 0xe9, 0xc1, 0xce, 0x64, 0xbc, 0x85, 0xd0, 0xc2, 0xd8, 0x74,
+	0xe6, 0xf6, 0x44, 0x40, 0x6f, 0xde, 0x40, 0xbe, 0xb6, 0xbc, 0xd7, 0x0d,
+	0xbf, 0x92, 0x8d, 0xcf, 0x03, 0xaa, 0xac, 0x7f, 0x5e, 0xc9, 0xb1, 0x77,
+	0xdb, 0x79, 0xac, 0x7f, 0x9a, 0xf4, 0xe3, 0x47, 0x3c, 0x2d, 0x75, 0xa9,
+	0xb3, 0xb9, 0x0a, 0x96, 0xcf, 0xd5, 0xe3, 0x51, 0xc5, 0xb2, 0x16, 0x84,
+	0x9c, 0xf6, 0xfd, 0xed, 0xe9, 0xda, 0x96, 0xdb, 0xd4, 0xd7, 0xad, 0xec,
+	0x9a, 0xab, 0xae, 0x45, 0x99, 0x0c, 0x1d, 0xff, 0xa3, 0xcf, 0x1d, 0x82,
+	0x90, 0xe7, 0x41, 0x6e, 0x63, 0x25, 0x0e, 0xe5, 0xd6, 0x1d, 0x5d, 0x91,
+	0xc3, 0x5f, 0x3e, 0x60, 0x48, 0xbe, 0x26, 0x7a, 0x92, 0xfe, 0xc4, 0x9e,
+	0x1e, 0x28, 0x14, 0x1c, 0xed, 0x4a, 0x2f, 0xe4, 0x3c, 0xfe, 0x87, 0x35,
+	0xea, 0x9d, 0x5a, 0x76, 0x89, 0x9a, 0x7d, 0x8e, 0x20, 0x65, 0xf3, 0xe5,
+	0xe6, 0x10, 0x57, 0x1a, 0x30, 0x7c, 0x49, 0x9b, 0x92, 0x6f, 0xe7, 0xdb,
+	0xec, 0x2d, 0x14, 0x5e, 0x55, 0x81, 0x42, 0xe2, 0xe3, 0x6f, 0xac, 0x83,
+	0x97, 0xb4, 0xb7, 0xd1, 0x95, 0x6d, 0x6f, 0x0f, 0xcb, 0x48, 0xd9, 0x02,
+	0xd6, 0x79, 0x37, 0xc7, 0x7f, 0xf3, 0x65, 0x3e, 0x77, 0x59, 0x19, 0x66,
+	0x78, 0xc6, 0x5b, 0xd6, 0xfe, 0x4b, 0xca, 0x7c, 0xda, 0x79, 0x69, 0x19,
+	0x27, 0x66, 0x1b, 0xaf, 0x5b, 0xc7, 0x2f, 0x29, 0x33, 0x70, 0x59, 0x99,
+	0x6b, 0x31, 0x56, 0xf7, 0xb8, 0x35, 0x94, 0x9d, 0x9b, 0x0c, 0x5d, 0xd0,
+	0x3d, 0x23, 0xe2, 0xfe, 0xd2, 0x75, 0xf3, 0x74, 0xf2, 0x4d, 0x79, 0x16,
+	0xe5, 0x46, 0x26, 0x3b, 0x37, 0x71, 0x99, 0x1b, 0xd7, 0x82, 0xfc, 0xdc,
+	0x3c, 0x90, 0xab, 0x9f, 0x6f, 0x37, 0x56, 0x70, 0x69, 0xbb, 0xf9, 0xeb,
+	0x8e, 0xcb, 0xe4, 0x9e, 0xb8, 0xac, 0x5c, 0x51, 0xe1, 0x27, 0xd7, 0xfb,
+	0x81, 0xe3, 0xd2, 0xeb, 0xff, 0x43, 0xbd, 0xf4, 0xfc, 0x9a, 0xdc, 0x79,
+	0x5e, 0xff, 0xd6, 0x65, 0xf7, 0x1d, 0x97, 0x9d, 0x3f, 0xa3, 0x7e, 0x72,
+	0x3f, 0xab, 0x2e, 0xeb, 0xc7, 0x5e, 0x83, 0xc7, 0x73, 0x17, 0x70, 0x03,
+	0x8d, 0x05, 0x08, 0x98, 0x4e, 0x05, 0x7e, 0xe2, 0x87, 0xff, 0xf9, 0xcb,
+	0xd6, 0xe2, 0x1b, 0x2f, 0xe0, 0xc7, 0x25, 0x5c, 0x35, 0x56, 0x18, 0x91,
+	0x38, 0x28, 0x3c, 0x55, 0xf8, 0xe2, 0x27, 0xf1, 0xef, 0xb2, 0x58, 0x51,
+	0xa4, 0x1e, 0xfe, 0xb1, 0x99, 0xfe, 0xb7, 0x12, 0xb2, 0x1e, 0xfb, 0x7b,
+	0x72, 0x2e, 0xc3, 0x77, 0x08, 0x33, 0xfd, 0x3f, 0x4d, 0x95, 0xb8, 0x51,
+	0xe6, 0xc1, 0x8d, 0x89, 0x4f, 0xae, 0xa7, 0x46, 0xa0, 0x2c, 0xab, 0xf7,
+	0x31, 0xaf, 0x84, 0xf3, 0xa6, 0x79, 0x98, 0xf2, 0xd7, 0x2c, 0x79, 0xae,
+	0x7a, 0xb2, 0x3e, 0xcc, 0x18, 0x9f, 0x7d, 0x8e, 0xbc, 0x24, 0xad, 0xfb,
+	0xa2, 0x4a, 0xf6, 0x59, 0xf1, 0xba, 0xd0, 0x47, 0xe4, 0x45, 0x9d, 0x94,
+	0xcb, 0x62, 0x5f, 0xc0, 0x86, 0x84, 0x65, 0x3d, 0xc7, 0xfc, 0x5c, 0xf6,
+	0x20, 0xfc, 0x22, 0xf5, 0x3b, 0x6b, 0xc2, 0xeb, 0xc4, 0xdb, 0xc6, 0xd4,
+	0xf6, 0xfc, 0x28, 0x8f, 0x98, 0xcc, 0x13, 0xed, 0x13, 0x75, 0xcc, 0xa8,
+	0x6d, 0x3f, 0x40, 0xbf, 0x9b, 0x1f, 0xd0, 0xfd, 0x7d, 0xf8, 0x3f, 0x96,
+	0xbf, 0x5a, 0x0f, 0x0e, 0x29, 0xf9, 0xf5, 0xef, 0xcb, 0xd7, 0xb9, 0xcb,
+	0x62, 0x2e, 0x8e, 0x6f, 0xbf, 0xbd, 0xd6, 0x5d, 0x40, 0xac, 0x44, 0xcc,
+	0x19, 0x99, 0xe9, 0xdf, 0x9a, 0xb0, 0xc7, 0x49, 0x5e, 0xa9, 0xe0, 0x64,
+	0xfd, 0x4c, 0xff, 0xa6, 0x94, 0x17, 0x3b, 0x18, 0xd3, 0x8b, 0x8c, 0x7a,
+	0x3c, 0x9e, 0x52, 0x71, 0xcf, 0x23, 0x5e, 0xac, 0x21, 0x67, 0x6d, 0xef,
+	0xfd, 0x1a, 0x8c, 0xab, 0x9c, 0xb8, 0x9b, 0xf6, 0xb7, 0x96, 0xae, 0x23,
+	0xf9, 0xc3, 0xfa, 0x5e, 0x27, 0xea, 0xae, 0x2a, 0x43, 0xbc, 0xba, 0x10,
+	0xdf, 0x33, 0x1d, 0xcc, 0xf7, 0x4a, 0x30, 0x64, 0x73, 0x69, 0xc9, 0xe1,
+	0x05, 0x13, 0x45, 0x6f, 0x0e, 0x7b, 0xbd, 0xf5, 0x93, 0xe3, 0xc1, 0x7f,
+	0x58, 0x99, 0xea, 0x1d, 0x36, 0x8e, 0x3b, 0x22, 0xa6, 0x1d, 0x73, 0x81,
+	0x2c, 0x9f, 0xeb, 0xba, 0xe4, 0x79, 0x77, 0xb3, 0x32, 0x3b, 0x12, 0x98,
+	0x58, 0xac, 0x38, 0x10, 0x0e, 0x94, 0xc5, 0xca, 0x23, 0x61, 0x2c, 0x4b,
+	0x77, 0xf9, 0x7c, 0xf6, 0x33, 0xf4, 0x08, 0xce, 0x2d, 0x32, 0x99, 0xfb,
+	0xc3, 0xb9, 0x8c, 0xba, 0x6f, 0xa4, 0x5e, 0xb7, 0x98, 0x1f, 0x59, 0x19,
+	0xdb, 0xef, 0xdd, 0x88, 0x31, 0x07, 0x5b, 0x4b, 0xfd, 0x3a, 0xa8, 0xc7,
+	0x9f, 0xe7, 0xf4, 0x2b, 0x3a, 0x2d, 0x19, 0xfb, 0x9d, 0x75, 0x92, 0xfa,
+	0x75, 0xb3, 0x3d, 0x37, 0xdb, 0x2b, 0x1a, 0xbb, 0x54, 0xcf, 0x85, 0x94,
+	0x67, 0x99, 0x2d, 0xc3, 0x42, 0x79, 0x86, 0xe9, 0x8f, 0x2a, 0x32, 0x1e,
+	0xc1, 0xf7, 0x3f, 0x37, 0xa6, 0x1f, 0x4f, 0xc9, 0x55, 0x44, 0xff, 0x7e,
+	0xea, 0x5f, 0x30, 0x5c, 0xe6, 0xa0, 0x4e, 0xd6, 0xbb, 0x7a, 0x80, 0x97,
+	0x98, 0xcc, 0x2a, 0xa8, 0x32, 0x22, 0x78, 0xaa, 0xd9, 0x83, 0xb7, 0x12,
+	0xa5, 0xf6, 0xb8, 0xaf, 0x9a, 0x6b, 0x59, 0x4f, 0x86, 0xfc, 0xf8, 0x85,
+	0x51, 0x1b, 0x5e, 0xa0, 0xea, 0xcc, 0x1f, 0xbd, 0x48, 0x10, 0x67, 0xbb,
+	0x92, 0xb3, 0x38, 0x5f, 0x5e, 0x6c, 0x4d, 0xa2, 0x9d, 0xf6, 0xe4, 0x77,
+	0x44, 0x80, 0x33, 0x09, 0x23, 0xb8, 0x85, 0xfd, 0x0f, 0x7b, 0xeb, 0xc9,
+	0xd3, 0xd5, 0x46, 0xd2, 0xbd, 0x78, 0x51, 0xc4, 0x88, 0x6f, 0xc3, 0xcf,
+	0xac, 0x21, 0xe2, 0x7c, 0x41, 0x48, 0xd6, 0x1c, 0x67, 0xe3, 0x19, 0xcd,
+	0x81, 0x17, 0x83, 0xcc, 0x87, 0x2b, 0x1c, 0x28, 0x31, 0xde, 0xb6, 0x7e,
+	0xe0, 0x95, 0x7e, 0x64, 0x2c, 0x33, 0x38, 0x0e, 0xc5, 0xc6, 0xc2, 0xad,
+	0xc9, 0x7a, 0xea, 0xfb, 0xf2, 0xfe, 0xff, 0x8f, 0x35, 0xe9, 0x95, 0xfe,
+	0x75, 0xcd, 0xaf, 0x72, 0x0c, 0x7f, 0x14, 0xbb, 0xbf, 0x6f, 0xbd, 0x64,
+	0xb7, 0x79, 0xbb, 0x3b, 0x1b, 0x4f, 0xa5, 0xbd, 0xb7, 0x38, 0x3e, 0x69,
+	0x33, 0xdf, 0x8f, 0xe8, 0xed, 0x8c, 0x5b, 0xfc, 0x79, 0x6b, 0x52, 0xf4,
+	0x27, 0x78, 0x75, 0xd2, 0xc2, 0x34, 0x39, 0x7f, 0xd6, 0x2e, 0x1b, 0xa7,
+	0xbe, 0xba, 0x68, 0x43, 0x8c, 0xe1, 0x3e, 0xd8, 0xbb, 0x3b, 0x34, 0x3b,
+	0x9f, 0xdb, 0xcc, 0x1c, 0x60, 0xc8, 0x5b, 0x8e, 0xad, 0x26, 0xed, 0xce,
+	0x50, 0xe7, 0x38, 0x61, 0xe1, 0xa4, 0x29, 0xe7, 0x2e, 0x4c, 0x7a, 0x1d,
+	0xd8, 0x66, 0x3a, 0xb1, 0xce, 0x50, 0x75, 0xb9, 0xee, 0x08, 0xc9, 0xb9,
+	0x0b, 0xfe, 0x6a, 0x05, 0x3b, 0x18, 0x3e, 0xd6, 0x1b, 0x5d, 0x7e, 0xb9,
+	0xbe, 0x24, 0x24, 0xe7, 0x0a, 0xda, 0xa8, 0x93, 0xb8, 0xa6, 0x60, 0x83,
+	0x21, 0xcf, 0x4d, 0xb3, 0xfc, 0x39, 0x06, 0xcb, 0xda, 0x61, 0x36, 0x5c,
+	0x57, 0xc2, 0x72, 0x67, 0x4d, 0xe1, 0x83, 0x87, 0xef, 0x98, 0x1f, 0x88,
+	0x47, 0x0b, 0xa0, 0xc7, 0x8a, 0xe8, 0xa7, 0x5b, 0x7b, 0x67, 0xb3, 0x9e,
+	0x42, 0x6e, 0xe0, 0xf4, 0x6d, 0x87, 0xc4, 0xcf, 0x80, 0xff, 0xa7, 0x4c,
+	0xb2, 0x86, 0xbc, 0xf3, 0xa8, 0x59, 0xc3, 0x7f, 0x9a, 0xf3, 0x56, 0x6e,
+	0x38, 0xdb, 0x5f, 0x85, 0xbe, 0xae, 0x48, 0x99, 0x17, 0x2c, 0x63, 0xae,
+	0x10, 0x27, 0xbe, 0x8f, 0x8c, 0x39, 0xb1, 0x25, 0x69, 0x68, 0x07, 0x6d,
+	0xfe, 0xe7, 0xa4, 0x2e, 0x9c, 0xcc, 0xcf, 0x03, 0xda, 0x84, 0x92, 0x3f,
+	0x9f, 0x2d, 0xd8, 0x40, 0x3e, 0x2f, 0xf8, 0x16, 0xb7, 0x9e, 0xad, 0x17,
+	0xaa, 0xe1, 0xf6, 0xc7, 0x52, 0x1e, 0x1e, 0x1a, 0x0f, 0xaf, 0x7f, 0x4d,
+	0xca, 0xe7, 0x6f, 0x4b, 0xc1, 0xdf, 0x9a, 0xca, 0xdb, 0x65, 0xde, 0xb7,
+	0x05, 0xdb, 0x2c, 0x72, 0xd6, 0x6c, 0x6e, 0xd6, 0x25, 0xb9, 0x0f, 0xe4,
+	0xb9, 0xdf, 0xe1, 0x3b, 0x9e, 0xa3, 0xad, 0xbb, 0x98, 0x0f, 0x6c, 0x33,
+	0xe2, 0x51, 0x79, 0x0e, 0x69, 0x84, 0x74, 0x5f, 0x81, 0xe2, 0xc7, 0xd6,
+	0xba, 0xdf, 0x72, 0x3e, 0xc9, 0x93, 0x53, 0x9f, 0x29, 0xca, 0xce, 0x87,
+	0xf8, 0x99, 0x60, 0x80, 0x9f, 0xf9, 0x92, 0xcf, 0xdf, 0xc5, 0x7e, 0x36,
+	0xa7, 0xa6, 0xfa, 0x80, 0x82, 0x9b, 0xd8, 0x56, 0x43, 0x08, 0xce, 0xa5,
+	0x75, 0xbf, 0xb1, 0x32, 0xde, 0xec, 0x33, 0xc8, 0x2c, 0xe6, 0x81, 0x36,
+	0x67, 0xf7, 0xe9, 0xdc, 0x5f, 0x27, 0xfb, 0x8e, 0x14, 0x0c, 0xd3, 0xa7,
+	0x36, 0xa5, 0xc5, 0x9e, 0xb2, 0x7a, 0x8d, 0xff, 0x01, 0xfe, 0x98, 0xb8,
+	0x37, 0x89, 0x58, 0x41, 0x44, 0xf0, 0xc7, 0xed, 0x7f, 0x29, 0x55, 0x47,
+	0x0e, 0x2f, 0xcf, 0xf2, 0xdd, 0x9c, 0x67, 0x8f, 0xff, 0xc5, 0xd4, 0xf5,
+	0xb8, 0x67, 0x4f, 0x18, 0xeb, 0xf6, 0xa0, 0xae, 0x88, 0x72, 0x17, 0x86,
+	0x02, 0xfe, 0x51, 0x68, 0xfe, 0x67, 0xa8, 0x87, 0x13, 0x94, 0xed, 0xe4,
+	0x25, 0xb2, 0x89, 0xde, 0xe0, 0xbf, 0x2f, 0xe1, 0x46, 0x2a, 0xf4, 0xa1,
+	0x15, 0xb7, 0x79, 0x86, 0xd7, 0xbf, 0x31, 0xe1, 0x47, 0xc6, 0xe6, 0xac,
+	0xae, 0x22, 0xc9, 0x1f, 0xbb, 0x93, 0xf1, 0x28, 0xd3, 0xe1, 0xdc, 0x9c,
+	0xea, 0x61, 0x99, 0xcf, 0x33, 0x09, 0xb9, 0x17, 0xfd, 0x9a, 0x0a, 0xdd,
+	0xaf, 0x32, 0x7e, 0xf6, 0x9b, 0x62, 0xb3, 0x35, 0xa2, 0x93, 0x20, 0x2b,
+	0xc6, 0x3d, 0x91, 0x40, 0x4b, 0x1d, 0xaf, 0x6b, 0x0b, 0x10, 0xab, 0x88,
+	0x08, 0x27, 0xf4, 0xfa, 0x6b, 0xc7, 0x7d, 0x7e, 0x73, 0x1c, 0xfe, 0x2b,
+	0xc7, 0xa7, 0x8a, 0x40, 0x6e, 0xff, 0x89, 0xb9, 0x9f, 0xd7, 0xbf, 0x36,
+	0x31, 0x1b, 0x6a, 0x24, 0x6e, 0x2d, 0xa9, 0x3f, 0x67, 0xcd, 0x8e, 0x18,
+	0x99, 0x93, 0x94, 0xe1, 0xc3, 0x6b, 0xf5, 0xf8, 0x0c, 0xc7, 0x89, 0x87,
+	0xb4, 0x29, 0x7d, 0xbc, 0x1f, 0xfa, 0xff, 0xdb, 0x47, 0x3e, 0xb6, 0x89,
+	0xfc, 0x12, 0xdf, 0x72, 0x73, 0xaa, 0xe6, 0xc7, 0xa2, 0x70, 0x4e, 0x39,
+	0x1f, 0xc9, 0x7c, 0xac, 0xb2, 0xac, 0x56, 0xc3, 0x97, 0x7b, 0xfe, 0x07,
+	0xda, 0xcb, 0x89, 0xeb, 0x9c, 0x58, 0x4c, 0x7b, 0x6f, 0xf8, 0x6b, 0x27,
+	0xa2, 0xbe, 0x42, 0xc6, 0x50, 0xd9, 0x53, 0xf0, 0x4c, 0xdd, 0xa4, 0x35,
+	0x61, 0xd4, 0xa1, 0x21, 0x2d, 0xcf, 0x63, 0x1d, 0xb4, 0x63, 0x0b, 0x8f,
+	0x9b, 0x72, 0x5f, 0xf0, 0x24, 0x1e, 0x73, 0xd0, 0x26, 0xdc, 0x86, 0xde,
+	0xf2, 0x0f, 0x4a, 0x19, 0x8a, 0x23, 0xce, 0xe0, 0x04, 0xf4, 0xf0, 0x7a,
+	0x72, 0x63, 0x7f, 0xc5, 0x3c, 0x53, 0xd4, 0xfe, 0x4e, 0x22, 0x60, 0x06,
+	0x72, 0xf1, 0xe7, 0x2c, 0xe7, 0xeb, 0xdd, 0x84, 0xb1, 0xee, 0xb9, 0xdc,
+	0xf9, 0xbf, 0xa5, 0xa6, 0xe6, 0xbf, 0x62, 0x77, 0x6e, 0xf7, 0xe6, 0x04,
+	0xde, 0x77, 0xd4, 0xe3, 0xfd, 0xfd, 0x66, 0x01, 0xf3, 0x36, 0xb1, 0x47,
+	0xb7, 0x7b, 0x6b, 0x02, 0x93, 0x4e, 0x5e, 0x3b, 0x6b, 0xce, 0x22, 0x76,
+	0xa9, 0xbc, 0x16, 0x96, 0x58, 0x10, 0xd3, 0x18, 0x47, 0x8b, 0x23, 0x5e,
+	0x77, 0xf1, 0x38, 0xb4, 0x22, 0xa3, 0x8c, 0x79, 0x31, 0x1a, 0x1d, 0x7d,
+	0xba, 0xbf, 0xc9, 0x51, 0xc7, 0xfc, 0xd8, 0xaf, 0xb8, 0x8c, 0x6f, 0x31,
+	0xcf, 0x97, 0xf5, 0xaa, 0x30, 0xc7, 0xed, 0x64, 0x85, 0x9d, 0xd3, 0xd4,
+	0x88, 0x42, 0xcc, 0x2b, 0xc3, 0xbd, 0xda, 0x86, 0xc5, 0x6a, 0xa4, 0x1f,
+	0xb7, 0xd6, 0xbb, 0x1b, 0xcb, 0xc7, 0xf3, 0x3a, 0x41, 0xcc, 0x13, 0x61,
+	0x0e, 0x63, 0x40, 0x2d, 0x8d, 0x88, 0x6e, 0xfc, 0x8d, 0x7d, 0x63, 0x22,
+	0xab, 0xe6, 0xee, 0x1d, 0xf3, 0x14, 0xa3, 0x38, 0x4c, 0x4c, 0xfa, 0x57,
+	0xdf, 0x7f, 0xae, 0xde, 0x64, 0x91, 0xe0, 0xba, 0xcb, 0x90, 0xff, 0xb6,
+	0x3d, 0xb9, 0xdd, 0x91, 0x63, 0x31, 0x77, 0xc0, 0xb2, 0x18, 0x0f, 0x7d,
+	0x50, 0x66, 0x71, 0x3c, 0xf4, 0x29, 0xce, 0x4d, 0x5b, 0xea, 0x23, 0xeb,
+	0x33, 0x4e, 0x3b, 0xd6, 0xbb, 0x0b, 0x23, 0xe1, 0xbb, 0xde, 0x36, 0x7e,
+	0x6f, 0xbd, 0x95, 0x60, 0x5e, 0x4d, 0xdf, 0x2d, 0x20, 0x6e, 0x6f, 0x37,
+	0x9d, 0x4d, 0x4b, 0x15, 0x05, 0xdd, 0xc6, 0x3c, 0xad, 0x88, 0xf1, 0x68,
+	0x13, 0xfd, 0x37, 0xe6, 0x35, 0x82, 0xfb, 0xc1, 0x72, 0xa9, 0xb5, 0x6b,
+	0x5d, 0x91, 0x8d, 0x77, 0x8d, 0xd4, 0x8b, 0xcf, 0x9f, 0xbf, 0xeb, 0x39,
+	0xa3, 0x19, 0xdd, 0xe9, 0x41, 0xf4, 0xa4, 0xb3, 0xfd, 0x64, 0x30, 0xfb,
+	0x13, 0xfa, 0x59, 0xbb, 0xb6, 0x30, 0x22, 0x1c, 0xeb, 0xe8, 0x5d, 0x07,
+	0x8c, 0x28, 0xb6, 0xa4, 0x37, 0xde, 0x75, 0xb6, 0xbe, 0x9f, 0xff, 0xb3,
+	0x75, 0x86, 0x50, 0xfe, 0x89, 0x75, 0x4a, 0x22, 0xd2, 0x47, 0x98, 0x7d,
+	0x6c, 0xbc, 0x6b, 0xdd, 0xa2, 0xaf, 0x63, 0x73, 0x7a, 0xdd, 0x9f, 0xed,
+	0xa7, 0x94, 0x75, 0x8a, 0x23, 0x1d, 0xad, 0x37, 0x05, 0x36, 0xde, 0x95,
+	0x5a, 0xd4, 0xc3, 0x3e, 0x56, 0x31, 0x8e, 0x64, 0xeb, 0x44, 0x15, 0xc7,
+	0x27, 0xea, 0xa0, 0x28, 0xd2, 0xd3, 0x3a, 0x3f, 0xf0, 0x7b, 0x6b, 0x5e,
+	0x6f, 0x81, 0xad, 0x03, 0x17, 0x75, 0xf0, 0xa8, 0xe9, 0xcc, 0x04, 0x1c,
+	0xb6, 0x0e, 0x3a, 0x7c, 0xd4, 0x41, 0x1f, 0x75, 0x90, 0xa9, 0x36, 0xc2,
+	0xef, 0x51, 0x07, 0xf3, 0xc6, 0xd6, 0xae, 0x2d, 0x8a, 0xc0, 0xe9, 0x30,
+	0x5e, 0x77, 0x38, 0x39, 0x17, 0x2e, 0x63, 0x2d, 0xf5, 0xb6, 0xf1, 0xae,
+	0x39, 0x8b, 0x6c, 0x9d, 0x7f, 0xd9, 0x1d, 0xd8, 0x60, 0xef, 0xdd, 0xdb,
+	0x94, 0x6e, 0xe3, 0xd1, 0xc4, 0xe3, 0x61, 0x1e, 0xdd, 0xcc, 0x4d, 0xee,
+	0xa0, 0xae, 0x1a, 0x39, 0x8e, 0x15, 0x94, 0xab, 0x9d, 0xbf, 0x5b, 0xf8,
+	0xbb, 0x83, 0xbf, 0x65, 0x7e, 0xd4, 0x0b, 0xb2, 0xc5, 0x2e, 0xc8, 0xe6,
+	0xa0, 0x3c, 0x1e, 0x62, 0x94, 0x8c, 0x69, 0xe2, 0xcb, 0x37, 0x05, 0x62,
+	0x6c, 0xe3, 0xa9, 0x62, 0xd9, 0xf7, 0xe4, 0x32, 0xe2, 0x3e, 0x27, 0x44,
+	0x3e, 0xbd, 0x65, 0x1d, 0x32, 0xc4, 0xd8, 0xdf, 0x65, 0x31, 0x96, 0xb2,
+	0x95, 0x71, 0x7e, 0x5e, 0x59, 0x34, 0x34, 0xdd, 0x63, 0xc0, 0xe7, 0x36,
+	0xe2, 0xe8, 0x4d, 0x27, 0xa8, 0x03, 0xb1, 0x93, 0x07, 0xa9, 0xbf, 0x4e,
+	0x74, 0x19, 0x27, 0xf4, 0xec, 0xde, 0x89, 0xbd, 0x94, 0x21, 0x48, 0x7e,
+	0xe8, 0x81, 0x33, 0xa2, 0xfb, 0x1b, 0x1d, 0x5d, 0x41, 0x17, 0x68, 0xcb,
+	0xc5, 0x62, 0xcb, 0x71, 0xc6, 0x35, 0xc1, 0x3a, 0xb7, 0xd6, 0x66, 0xe3,
+	0x5f, 0x7c, 0xbe, 0x0b, 0x1e, 0x6d, 0x4d, 0x2a, 0x1f, 0x0b, 0x3c, 0x5a,
+	0x6b, 0x42, 0xfc, 0x4a, 0xd6, 0xfc, 0xc3, 0x76, 0x2c, 0x3f, 0x9e, 0x7e,
+	0xb1, 0x18, 0x65, 0xb6, 0x8f, 0x95, 0x39, 0x8d, 0x6c, 0xbb, 0x1a, 0xdb,
+	0x6d, 0x76, 0x68, 0xb8, 0xe8, 0x23, 0xba, 0xd6, 0xec, 0x90, 0x7d, 0xae,
+	0xf4, 0xfe, 0x54, 0xae, 0x5e, 0x16, 0x27, 0x16, 0xbb, 0x6c, 0x9c, 0x60,
+	0x1b, 0xc5, 0xc0, 0x92, 0xc4, 0xe5, 0xfd, 0x4b, 0x7f, 0xd2, 0x6f, 0x57,
+	0x85, 0x8a, 0x09, 0xfb, 0x99, 0xcb, 0x91, 0x74, 0x0c, 0x83, 0xc9, 0xa9,
+	0x7b, 0xf9, 0xf4, 0xa3, 0x6c, 0xff, 0x70, 0x9c, 0xfa, 0x98, 0x65, 0xc8,
+	0x3e, 0x3f, 0xd9, 0xdb, 0x37, 0x75, 0x5f, 0x9f, 0xc8, 0x56, 0x58, 0x42,
+	0x00, 0xc1, 0x01, 0xe2, 0x4c, 0xb4, 0x59, 0xea, 0x5b, 0xd6, 0x1b, 0xf3,
+	0x82, 0xc8, 0x54, 0x39, 0x31, 0x38, 0x17, 0x18, 0xe8, 0x93, 0x7d, 0x57,
+	0x47, 0x63, 0xab, 0x99, 0x97, 0x45, 0x2b, 0x6b, 0xb5, 0x4d, 0xaa, 0xec,
+	0x99, 0x3a, 0xf6, 0xe5, 0x6e, 0xa3, 0x46, 0xeb, 0x56, 0x33, 0x87, 0x88,
+	0xdd, 0x7b, 0x81, 0x69, 0x25, 0xe2, 0x6b, 0x15, 0x46, 0xb4, 0xa7, 0x02,
+	0x73, 0xe1, 0xaf, 0xb4, 0xf1, 0x32, 0xfe, 0x94, 0x6a, 0x04, 0x57, 0xda,
+	0x38, 0xf8, 0xa1, 0x35, 0xc4, 0xb8, 0xf4, 0x95, 0xb9, 0x3f, 0x28, 0xce,
+	0xe6, 0xd9, 0xd1, 0x75, 0xd3, 0x38, 0x57, 0xbf, 0x58, 0xa0, 0xfb, 0x53,
+	0x8a, 0xe8, 0x48, 0xb8, 0x49, 0x02, 0xdb, 0xc8, 0x75, 0x7f, 0x33, 0x37,
+	0x82, 0x83, 0xfc, 0xff, 0xf3, 0xeb, 0x65, 0x0f, 0xaa, 0x65, 0x05, 0x03,
+	0xf3, 0xc2, 0x15, 0x1c, 0xc3, 0x8b, 0xbc, 0xdf, 0x93, 0x7e, 0xdb, 0x3a,
+	0x3b, 0xcd, 0xe8, 0x5f, 0xc6, 0x40, 0x32, 0x30, 0xae, 0x6b, 0x93, 0xea,
+	0x7f, 0x76, 0x4f, 0x1d, 0xdc, 0x65, 0x1c, 0xcb, 0xf7, 0x02, 0xb5, 0x5a,
+	0x9f, 0xaa, 0x96, 0x88, 0x5e, 0x07, 0xc6, 0x7f, 0x3c, 0x65, 0xaf, 0x47,
+	0x9e, 0x1f, 0xda, 0x6b, 0x1d, 0x3d, 0x43, 0xf4, 0xa9, 0x21, 0x2d, 0x1a,
+	0xa7, 0xde, 0xdd, 0x55, 0x1c, 0xf3, 0x57, 0xe6, 0xde, 0x6a, 0x8f, 0xb3,
+	0xd2, 0x98, 0xc1, 0x31, 0x2a, 0xd0, 0xe6, 0xfe, 0x2c, 0xb7, 0xee, 0xd9,
+	0x40, 0x36, 0x33, 0x64, 0x35, 0xd2, 0x06, 0x0b, 0x58, 0xe7, 0x46, 0x73,
+	0xdf, 0xf4, 0xae, 0x3a, 0xdd, 0xf7, 0x15, 0xc6, 0xce, 0xd0, 0xdc, 0x5f,
+	0x5b, 0x51, 0xcd, 0x69, 0x7e, 0x93, 0xa3, 0xbe, 0x27, 0x21, 0x65, 0x65,
+	0x5e, 0x8d, 0xe8, 0x5c, 0xe5, 0x5d, 0x0b, 0xd5, 0x81, 0xf0, 0x5c, 0x7b,
+	0xfc, 0xc0, 0xdd, 0xa9, 0x04, 0xb6, 0x27, 0xa5, 0x4d, 0x05, 0xcb, 0x02,
+	0xef, 0x58, 0xfe, 0x69, 0x09, 0x6c, 0x4d, 0xff, 0x29, 0xae, 0x37, 0x28,
+	0x71, 0xbf, 0x25, 0x0e, 0x3d, 0x9a, 0x7d, 0xc6, 0x35, 0x5b, 0xd6, 0x94,
+	0x65, 0x0f, 0xd2, 0x5d, 0x89, 0x00, 0xdc, 0xa5, 0xc4, 0xba, 0xb1, 0x80,
+	0x3c, 0x13, 0xf5, 0x22, 0xd3, 0x2c, 0x65, 0x6a, 0xb4, 0x31, 0x64, 0xc8,
+	0xc4, 0x64, 0x7d, 0xb2, 0xa7, 0x24, 0xbb, 0x9f, 0x82, 0x86, 0x57, 0xad,
+	0x6b, 0x67, 0xc8, 0x9d, 0x9a, 0x0c, 0x69, 0x43, 0xc1, 0xfc, 0x40, 0x15,
+	0x6a, 0x57, 0xbe, 0xfe, 0x66, 0x41, 0xa0, 0x80, 0xb8, 0x2d, 0xfe, 0x64,
+	0xb4, 0x9f, 0xc4, 0xbf, 0xd3, 0xd7, 0x65, 0x6f, 0xd9, 0x16, 0xa9, 0xc7,
+	0xb6, 0xe6, 0x22, 0xa5, 0x39, 0xc9, 0x33, 0x64, 0x9f, 0xb2, 0x65, 0xdd,
+	0x14, 0x78, 0xcb, 0x8a, 0x56, 0x53, 0x1e, 0xf2, 0x9f, 0x6c, 0x5d, 0x29,
+	0x93, 0xdb, 0x33, 0xa4, 0x34, 0xdc, 0x25, 0x3a, 0x79, 0xd6, 0x8c, 0x93,
+	0x5d, 0x0b, 0xbe, 0x1e, 0x8b, 0xbd, 0x6d, 0x28, 0xf6, 0xb3, 0xca, 0x65,
+	0x4a, 0x39, 0xe3, 0x95, 0xd3, 0x3f, 0x62, 0xe7, 0xdf, 0x61, 0x62, 0xa1,
+	0xf0, 0x35, 0xc9, 0xa1, 0x9c, 0x78, 0xce, 0xa8, 0xc0, 0xb3, 0x5a, 0x96,
+	0xfb, 0x10, 0x53, 0xf0, 0x6a, 0x62, 0x5e, 0x86, 0x1e, 0x42, 0x0e, 0x69,
+	0xac, 0x3b, 0xaf, 0xfc, 0x3b, 0xf3, 0x2b, 0xe0, 0x95, 0x54, 0x3b, 0x1e,
+	0x95, 0x75, 0x3d, 0xa5, 0xa6, 0xa9, 0xd6, 0x21, 0xfd, 0xb5, 0x63, 0x5b,
+	0x5a, 0xda, 0x3a, 0x16, 0x3b, 0x60, 0xf4, 0xe7, 0x64, 0x15, 0xcc, 0x3c,
+	0x16, 0x7b, 0xce, 0x78, 0xdc, 0x9e, 0x3b, 0x79, 0x7e, 0xd6, 0x63, 0x0a,
+	0xb6, 0x14, 0x43, 0x25, 0x0f, 0x77, 0x18, 0x77, 0xc0, 0x51, 0xf1, 0x75,
+	0xda, 0x9e, 0xec, 0xbf, 0xb9, 0x13, 0xce, 0x0a, 0x17, 0x7d, 0xf3, 0x6e,
+	0xb8, 0x2a, 0x84, 0xfb, 0xe6, 0x79, 0x69, 0x94, 0xf7, 0x45, 0xb7, 0xe7,
+	0x6d, 0xdd, 0x3a, 0x89, 0xa7, 0xdd, 0x92, 0x27, 0x19, 0xe5, 0xd4, 0x91,
+	0xde, 0x42, 0x8e, 0x8c, 0x52, 0x62, 0x13, 0xe3, 0x90, 0xbb, 0x9c, 0x65,
+	0xde, 0xa3, 0xde, 0xe7, 0xf5, 0x96, 0x90, 0x13, 0x5b, 0xd6, 0x87, 0xe4,
+	0xc4, 0xf3, 0x03, 0xb5, 0x19, 0x83, 0xf1, 0x03, 0xb7, 0xe9, 0x4d, 0x71,
+	0xe6, 0x88, 0xab, 0x8d, 0xf3, 0x56, 0x6c, 0x95, 0x94, 0xd1, 0x7d, 0x31,
+	0x25, 0xdf, 0xc7, 0x02, 0xf8, 0xab, 0x2c, 0xb8, 0x22, 0xb2, 0x96, 0x2f,
+	0x6b, 0xb8, 0x0d, 0xf2, 0xcc, 0xb0, 0x59, 0xc6, 0xef, 0x92, 0x75, 0x41,
+	0x44, 0x27, 0x5c, 0x30, 0x32, 0x07, 0x65, 0xce, 0xa6, 0x5b, 0x08, 0x2c,
+	0xfc, 0x1d, 0x73, 0x0b, 0x99, 0x9f, 0x9a, 0x4c, 0x9d, 0x92, 0x09, 0xfa,
+	0xc8, 0x91, 0x9f, 0x80, 0xde, 0x9c, 0xa0, 0xae, 0x1b, 0x43, 0xb2, 0x0f,
+	0xc0, 0xe9, 0x4b, 0xc0, 0xe6, 0xc5, 0xe6, 0x69, 0x7c, 0x06, 0xa5, 0xcc,
+	0x05, 0xe7, 0x8e, 0xad, 0x40, 0x59, 0x45, 0xd4, 0x57, 0x8c, 0x6b, 0x78,
+	0xde, 0x46, 0xbe, 0xff, 0x05, 0x94, 0xad, 0x6c, 0x41, 0x82, 0x63, 0x2f,
+	0x35, 0xbe, 0xc4, 0x6b, 0x0f, 0xa3, 0x2f, 0xe9, 0xe2, 0x38, 0xfe, 0xd5,
+	0x2a, 0xab, 0x16, 0xd9, 0x4c, 0x6f, 0x09, 0xf3, 0xf4, 0xa8, 0xad, 0x0b,
+	0x62, 0x63, 0x52, 0xb8, 0x48, 0x6d, 0x74, 0x3d, 0x98, 0x2b, 0x57, 0xeb,
+	0x2d, 0x6d, 0x4a, 0x07, 0x6d, 0xb6, 0x9b, 0x3a, 0x97, 0xb2, 0x96, 0xb5,
+	0x3c, 0x30, 0x49, 0x1d, 0x77, 0xf0, 0xdc, 0xf0, 0xbf, 0x05, 0xf5, 0x9a,
+	0x42, 0x9c, 0xb2, 0xe2, 0x9a, 0x8f, 0x76, 0xa9, 0xae, 0x12, 0xde, 0xb2,
+	0x34, 0x74, 0xae, 0x44, 0xf6, 0x21, 0x67, 0xed, 0xf4, 0x68, 0x4e, 0x97,
+	0xe7, 0xef, 0xea, 0x36, 0x5e, 0xb5, 0xaf, 0x3b, 0xec, 0xeb, 0xe1, 0xdc,
+	0xf5, 0xa3, 0xbc, 0xfe, 0x3d, 0x5e, 0xef, 0xa1, 0xee, 0xd5, 0x2b, 0xa4,
+	0xfe, 0x5a, 0x53, 0xea, 0x33, 0x45, 0x31, 0xba, 0x73, 0xf3, 0xd1, 0xd1,
+	0x9a, 0x2d, 0xdb, 0xd3, 0x9a, 0x6d, 0xc3, 0xc9, 0x36, 0xe2, 0xd1, 0x62,
+	0x98, 0x28, 0x61, 0x9c, 0x3f, 0x6b, 0x88, 0x5c, 0x9c, 0xbb, 0xb4, 0xc8,
+	0xd5, 0xc6, 0xb8, 0xd2, 0xf5, 0x42, 0x31, 0xe2, 0x1d, 0x33, 0x6c, 0x3b,
+	0x3c, 0x7a, 0x97, 0xec, 0x8f, 0x7b, 0x5b, 0x69, 0xf0, 0xc9, 0xb6, 0xca,
+	0x24, 0x79, 0xe2, 0x43, 0xa6, 0x33, 0x5c, 0xe7, 0x98, 0x97, 0x29, 0x84,
+	0x11, 0x3b, 0xaf, 0x7c, 0x64, 0xe3, 0x43, 0x22, 0xd5, 0xc0, 0x4c, 0x26,
+	0x1e, 0x64, 0x0e, 0x12, 0x4c, 0x53, 0xb7, 0xad, 0x44, 0xec, 0xa3, 0xf6,
+	0x1e, 0x39, 0xe7, 0xc4, 0x0a, 0x34, 0xe8, 0x0e, 0xcc, 0x0b, 0xcf, 0x60,
+	0x26, 0x43, 0xbb, 0x34, 0x0b, 0x1d, 0xba, 0xff, 0x56, 0x7c, 0xc6, 0x23,
+	0xf5, 0x0e, 0xa6, 0x32, 0xeb, 0x8a, 0x39, 0xa7, 0xdf, 0xa0, 0x1c, 0xdb,
+	0x03, 0x22, 0xc7, 0xd7, 0x73, 0x72, 0xb4, 0x30, 0x66, 0x99, 0xda, 0xcd,
+	0x81, 0x9e, 0x0b, 0x7a, 0x7b, 0xc1, 0xd6, 0xdb, 0xc3, 0x3c, 0x2f, 0x64,
+	0xbe, 0x5c, 0x80, 0x13, 0x75, 0xde, 0xdc, 0x7e, 0x37, 0xc9, 0x7d, 0x04,
+	0x7f, 0xcf, 0x7c, 0x69, 0xb5, 0xa1, 0x87, 0x1d, 0x36, 0x67, 0x76, 0x23,
+	0x6e, 0xf3, 0x51, 0x79, 0x76, 0x5e, 0x86, 0xc7, 0xed, 0x72, 0x2e, 0xea,
+	0xa4, 0x04, 0x4f, 0xe4, 0xfc, 0x45, 0xf6, 0x2e, 0x7c, 0xc3, 0xfe, 0xbd,
+	0x97, 0x73, 0xeb, 0xa2, 0xaf, 0xe6, 0x63, 0x94, 0xac, 0x81, 0x6f, 0xb4,
+	0x7d, 0x7f, 0x08, 0xc7, 0xec, 0xff, 0x99, 0x6c, 0xfe, 0x82, 0x6e, 0x53,
+	0xf6, 0xfc, 0x94, 0x60, 0x93, 0x3c, 0x8b, 0x4c, 0x4b, 0x4e, 0x7d, 0x3d,
+	0xb6, 0x70, 0x54, 0x6e, 0x83, 0x1c, 0x43, 0x13, 0x9b, 0xe8, 0x44, 0x9f,
+	0x66, 0x7a, 0xd3, 0x75, 0x53, 0x73, 0x0f, 0x13, 0xfb, 0xeb, 0x7e, 0x6f,
+	0x45, 0xed, 0x7c, 0xe4, 0x94, 0x75, 0xc0, 0x38, 0x11, 0xa2, 0x07, 0xaf,
+	0x2b, 0xb0, 0xf5, 0x7b, 0xfe, 0x2e, 0x7b, 0x9f, 0x20, 0x65, 0x7e, 0x21,
+	0x21, 0x71, 0x74, 0x36, 0x52, 0xa6, 0xc8, 0xe6, 0x6c, 0xde, 0xc1, 0x39,
+	0xe9, 0x4e, 0x06, 0xa2, 0x57, 0xf2, 0xde, 0x04, 0x63, 0xd9, 0x26, 0xea,
+	0x33, 0xd6, 0x2c, 0x3c, 0xa8, 0x0d, 0x7b, 0x69, 0x63, 0xe3, 0xa6, 0x65,
+	0x1d, 0x24, 0x46, 0x94, 0xcf, 0x53, 0x91, 0xa9, 0x6e, 0x43, 0x92, 0xb1,
+	0xe9, 0xa0, 0xd1, 0xf0, 0x99, 0x02, 0xc4, 0xfd, 0x6e, 0xe8, 0xbe, 0xad,
+	0x1c, 0xcd, 0x43, 0x9c, 0xaf, 0x13, 0xa6, 0xf0, 0x33, 0xe7, 0xf9, 0xa5,
+	0x30, 0xc2, 0x8b, 0x1d, 0xff, 0x6a, 0x4d, 0xda, 0xcf, 0x51, 0xbb, 0xfe,
+	0x27, 0x65, 0x68, 0x17, 0xe7, 0x2d, 0xe7, 0x1c, 0xbf, 0x17, 0x90, 0xe7,
+	0xe0, 0x40, 0x6d, 0x6f, 0xc3, 0x3a, 0x91, 0xe1, 0x40, 0xc8, 0x19, 0x3b,
+	0x88, 0x40, 0xf3, 0x06, 0xe5, 0x22, 0x07, 0xbf, 0x72, 0xcc, 0xc4, 0x68,
+	0xdd, 0x8b, 0xe4, 0x0b, 0x52, 0xbf, 0x10, 0x4f, 0x9b, 0xcf, 0x5b, 0x35,
+	0xd3, 0xbf, 0x67, 0x1d, 0x32, 0xd4, 0xf5, 0xd4, 0x76, 0xac, 0x94, 0x6d,
+	0x95, 0xb0, 0xad, 0x7b, 0x03, 0xba, 0xb9, 0x83, 0x6d, 0x3d, 0x93, 0x38,
+	0x11, 0x74, 0xb3, 0xad, 0x27, 0x4c, 0xe1, 0xe0, 0xce, 0xa6, 0x26, 0xce,
+	0x6d, 0x57, 0x32, 0xe0, 0xdb, 0x46, 0xb9, 0x24, 0x37, 0xba, 0x33, 0x21,
+	0xef, 0x74, 0x7c, 0x9d, 0xe3, 0x89, 0xb6, 0xbb, 0xd0, 0xf0, 0x50, 0x19,
+	0xed, 0xa7, 0x1c, 0x79, 0x5b, 0xd7, 0x7d, 0xc4, 0x3b, 0xdc, 0xcb, 0x32,
+	0x6f, 0x06, 0x66, 0xe3, 0x95, 0x50, 0xc3, 0xca, 0xd9, 0x70, 0xc6, 0x0e,
+	0x29, 0x81, 0xa6, 0x0d, 0x4a, 0x5c, 0x13, 0x5b, 0xbc, 0x27, 0xa5, 0x07,
+	0x1b, 0x21, 0xd8, 0xdd, 0x42, 0x7d, 0xcc, 0xc6, 0x87, 0x0b, 0x45, 0x2e,
+	0x67, 0x38, 0xe8, 0x08, 0x74, 0x3c, 0xcf, 0xf9, 0x2d, 0x9b, 0x97, 0xcd,
+	0xfb, 0xd2, 0xf6, 0xbe, 0xce, 0x16, 0xf4, 0xa5, 0x4f, 0xbd, 0x77, 0xc0,
+	0x80, 0xf3, 0x68, 0xdd, 0xa3, 0x16, 0xec, 0x77, 0x40, 0x1a, 0x64, 0x1e,
+	0x5a, 0x64, 0x1e, 0x8a, 0xe9, 0x4f, 0x37, 0x51, 0xee, 0xf5, 0xb6, 0xdc,
+	0xb3, 0x31, 0x6c, 0xca, 0x7a, 0x92, 0x53, 0xbb, 0x07, 0x3d, 0xc4, 0xce,
+	0xc0, 0xf9, 0x2e, 0xf6, 0xf3, 0x26, 0x65, 0x9e, 0x47, 0xbd, 0x4f, 0x36,
+	0x0b, 0x3f, 0x7c, 0x18, 0xbd, 0xc9, 0xfc, 0x3b, 0x22, 0x0a, 0x52, 0x01,
+	0xe9, 0xe3, 0x61, 0xf2, 0xa5, 0x2e, 0x6b, 0xb2, 0x5a, 0xae, 0xef, 0x65,
+	0x2e, 0x1d, 0xd5, 0xe8, 0x0f, 0xd4, 0x3b, 0xf4, 0xd9, 0xd0, 0x27, 0xce,
+	0x38, 0xa2, 0xf4, 0x01, 0xd3, 0x7b, 0x9e, 0xd8, 0x70, 0x14, 0x1d, 0x16,
+	0x2a, 0x6c, 0x7b, 0xf8, 0xf9, 0x88, 0xf1, 0x0b, 0x45, 0x62, 0x7b, 0x86,
+	0x3a, 0x60, 0xb6, 0xdf, 0x2e, 0x3a, 0x28, 0xa5, 0xcf, 0x8e, 0x05, 0x74,
+	0xff, 0x2b, 0x94, 0x67, 0x07, 0xe5, 0x59, 0x91, 0x9d, 0x43, 0xdf, 0x16,
+	0x45, 0x7c, 0x3a, 0xd0, 0xbc, 0x9a, 0xd7, 0xb7, 0x53, 0x9e, 0x40, 0xaf,
+	0x82, 0xa1, 0xe6, 0x6e, 0xf2, 0xb1, 0x0e, 0xea, 0xe0, 0xa2, 0x3c, 0x6e,
+	0x7b, 0xce, 0x3a, 0xc8, 0x05, 0x0a, 0x99, 0xff, 0x0b, 0x7e, 0x6b, 0x18,
+	0xa6, 0x9d, 0xee, 0xe7, 0x8c, 0x44, 0xbd, 0x2a, 0x0a, 0x0d, 0xc1, 0x80,
+	0x6a, 0x5e, 0x73, 0x71, 0x6e, 0xca, 0x71, 0x48, 0xdb, 0x6b, 0xef, 0x69,
+	0xce, 0xe6, 0xea, 0x1f, 0x59, 0xa3, 0x5e, 0xe1, 0x67, 0xb2, 0xde, 0x24,
+	0x6b, 0x32, 0x71, 0x4f, 0x76, 0x4f, 0xb5, 0x8b, 0x3a, 0xc9, 0x5e, 0x7f,
+	0x41, 0x73, 0xe4, 0xf2, 0x66, 0xb9, 0xfe, 0x81, 0xf5, 0xac, 0x5d, 0x5e,
+	0xca, 0xb9, 0x6c, 0x2e, 0x5c, 0x6c, 0x97, 0xfb, 0xc0, 0x7a, 0x51, 0x73,
+	0x4e, 0x29, 0x97, 0x7f, 0x86, 0x77, 0xe2, 0x6b, 0x4e, 0x62, 0x5e, 0xe1,
+	0xdc, 0xc5, 0x38, 0x69, 0x9c, 0xaa, 0x39, 0x5d, 0xd7, 0xc9, 0x38, 0x36,
+	0x75, 0x1f, 0x98, 0x85, 0x27, 0xed, 0x1c, 0xb7, 0x6b, 0xbe, 0x03, 0x27,
+	0x76, 0x16, 0xd0, 0x27, 0xa3, 0x9a, 0xac, 0x87, 0x45, 0x4b, 0x72, 0x7b,
+	0x55, 0x24, 0x6f, 0x0c, 0xfa, 0xd5, 0xab, 0x6d, 0x6e, 0x18, 0x55, 0xff,
+	0xdc, 0x7e, 0x3b, 0xe1, 0x2e, 0x9d, 0xd8, 0x6f, 0xe4, 0x39, 0xcb, 0x89,
+	0x47, 0x55, 0xe2, 0xe4, 0x80, 0xb9, 0x58, 0x62, 0xb3, 0x9f, 0xf5, 0x83,
+	0x31, 0x75, 0x2a, 0xb7, 0x59, 0xed, 0x41, 0x59, 0xd7, 0x36, 0x07, 0x64,
+	0x9f, 0xa9, 0xec, 0x19, 0x95, 0xbe, 0x8a, 0x72, 0xeb, 0x3c, 0x9f, 0xc4,
+	0x35, 0xf2, 0x7d, 0x09, 0xdf, 0xf8, 0x20, 0xc7, 0xdd, 0xf4, 0x60, 0xd4,
+	0x96, 0xf3, 0x57, 0xd6, 0x4a, 0x2d, 0x33, 0x43, 0xc3, 0xa5, 0xb2, 0x47,
+	0x73, 0xb2, 0xc7, 0x3e, 0x71, 0x9d, 0x4a, 0xfa, 0x99, 0xda, 0x66, 0x7e,
+	0x4f, 0xb7, 0xac, 0x61, 0xca, 0x3d, 0x05, 0x5d, 0xc4, 0xa1, 0xa8, 0xd6,
+	0xc0, 0x38, 0xaf, 0xfb, 0xd6, 0x70, 0x3e, 0xe2, 0x5e, 0xd9, 0xcb, 0x9e,
+	0x8f, 0x91, 0x85, 0xc8, 0xae, 0x25, 0xca, 0x7e, 0x87, 0xec, 0xfa, 0x21,
+	0xed, 0x1e, 0x5d, 0xa9, 0xdf, 0x59, 0x19, 0xaf, 0x93, 0xb1, 0xf0, 0xe2,
+	0x3e, 0xea, 0x21, 0xea, 0x55, 0xd6, 0x41, 0xb6, 0x5c, 0x58, 0xab, 0x90,
+	0x35, 0x1a, 0x89, 0xbd, 0xbf, 0xb5, 0x5a, 0x2f, 0x29, 0x3b, 0x75, 0x4f,
+	0x79, 0x75, 0x4c, 0x9e, 0x83, 0x8d, 0xe6, 0xd6, 0xb1, 0x1b, 0xff, 0xe0,
+	0x39, 0xd8, 0x04, 0x6d, 0x09, 0xd1, 0x2d, 0xe4, 0x76, 0x71, 0x74, 0x63,
+	0x34, 0x51, 0xab, 0x6d, 0x85, 0x26, 0xeb, 0xb7, 0xfc, 0xeb, 0xc6, 0xa1,
+	0x04, 0xa2, 0x05, 0x57, 0x95, 0x93, 0x6f, 0x21, 0xea, 0x60, 0x8c, 0x7a,
+	0x22, 0x51, 0xdb, 0xb4, 0x9d, 0x63, 0xf2, 0xaf, 0xec, 0xc6, 0x70, 0xa2,
+	0xe1, 0x4b, 0x8c, 0x23, 0xfe, 0x12, 0x9b, 0xeb, 0x44, 0xff, 0xcb, 0x01,
+	0xe2, 0xc0, 0xe6, 0xdc, 0x1a, 0x52, 0x6b, 0xe2, 0xd7, 0x94, 0xdf, 0x16,
+	0x92, 0xf5, 0xfe, 0x54, 0xb9, 0x09, 0xe6, 0xd3, 0xa7, 0xb0, 0xb6, 0x5f,
+	0xc1, 0xb3, 0xc6, 0x29, 0xac, 0x19, 0x12, 0x79, 0x4e, 0xa1, 0xad, 0xff,
+	0xfb, 0xd8, 0xdf, 0x3f, 0x1d, 0x8d, 0xb6, 0x6e, 0x3a, 0xb0, 0x61, 0xd7,
+	0x11, 0xec, 0x48, 0x5a, 0xd8, 0x1e, 0xf2, 0x60, 0xfd, 0x3e, 0x05, 0xcb,
+	0x03, 0xc7, 0xb0, 0x75, 0x97, 0x85, 0x39, 0xa1, 0x4e, 0x34, 0x99, 0x25,
+	0x28, 0xac, 0x98, 0xb7, 0x4e, 0x65, 0xb9, 0xd6, 0xe1, 0x8e, 0xdc, 0xfe,
+	0xe5, 0x43, 0xc4, 0x02, 0x15, 0x3e, 0x43, 0xf6, 0x26, 0x47, 0x95, 0xdb,
+	0xd3, 0x8d, 0x4a, 0x4b, 0xee, 0x39, 0xe2, 0xad, 0xe9, 0x8f, 0x99, 0xff,
+	0xc4, 0xb1, 0x3f, 0x74, 0x0a, 0x43, 0x43, 0xbf, 0x2e, 0xcd, 0xfa, 0xcb,
+	0x04, 0xb9, 0x83, 0xe4, 0x1c, 0x26, 0x6d, 0xea, 0x4f, 0xbd, 0x37, 0x24,
+	0x76, 0x37, 0x89, 0x9f, 0x0e, 0x9e, 0xc6, 0xe9, 0xc1, 0x7f, 0xc1, 0x12,
+	0x4d, 0xf2, 0x34, 0xab, 0xd3, 0x19, 0xb1, 0xac, 0x3d, 0xf5, 0x71, 0xab,
+	0xda, 0x78, 0xab, 0x0c, 0xc5, 0x65, 0x98, 0x16, 0x79, 0x0d, 0xdb, 0x35,
+	0xb6, 0x95, 0x3c, 0x84, 0x9d, 0x8c, 0xeb, 0xbe, 0xc8, 0x1d, 0xf0, 0x25,
+	0x33, 0x66, 0x25, 0xa2, 0x3b, 0x2b, 0xa1, 0xb7, 0x57, 0x38, 0x8c, 0x8e,
+	0x7f, 0x56, 0xea, 0x70, 0x6b, 0xfa, 0x34, 0x7e, 0x31, 0x68, 0xef, 0xc9,
+	0x6a, 0xf9, 0xb6, 0x62, 0x75, 0x6e, 0x0f, 0xe9, 0x4d, 0xff, 0x55, 0x89,
+	0xc6, 0x65, 0x2f, 0x4f, 0x11, 0x73, 0x82, 0xdb, 0x06, 0x25, 0xdf, 0x6c,
+	0x81, 0xbb, 0x57, 0xcf, 0x2c, 0x25, 0xcf, 0xfe, 0xca, 0x82, 0xf8, 0x8c,
+	0x2a, 0xda, 0xa5, 0x43, 0xd1, 0x83, 0x86, 0xda, 0x89, 0xe3, 0xa6, 0x3e,
+	0xf1, 0x5b, 0x87, 0x31, 0xf4, 0x2d, 0xd4, 0x61, 0x55, 0x5a, 0x1f, 0xba,
+	0x86, 0x79, 0xd8, 0xd6, 0x3e, 0x13, 0xc9, 0x3e, 0xbd, 0xa5, 0xc3, 0xd1,
+	0x83, 0xfb, 0x02, 0x35, 0xed, 0xef, 0x91, 0xcb, 0x79, 0x88, 0x29, 0x7d,
+	0xe3, 0x23, 0xcc, 0x13, 0x7b, 0xb0, 0x61, 0x5f, 0x04, 0xeb, 0xf7, 0x98,
+	0xe8, 0xee, 0x1b, 0xa1, 0x6c, 0x2f, 0x95, 0xca, 0x1e, 0x96, 0xe6, 0x50,
+	0xfc, 0x66, 0x15, 0x81, 0x28, 0xfb, 0x6c, 0x50, 0x23, 0x01, 0xbf, 0xaa,
+	0x30, 0xfa, 0x8f, 0x3b, 0xb1, 0x89, 0x65, 0x7a, 0x93, 0xb4, 0xb9, 0x3e,
+	0x37, 0xe3, 0xe5, 0x4c, 0x0c, 0x8f, 0xf9, 0x70, 0x70, 0xcc, 0x83, 0xa1,
+	0x31, 0x8d, 0x47, 0x31, 0x1e, 0x1b, 0x90, 0xbd, 0x20, 0x5e, 0x3c, 0x7d,
+	0xc0, 0x8d, 0xcd, 0xbb, 0x3d, 0x98, 0x1d, 0x99, 0x86, 0x03, 0x07, 0x8a,
+	0xb1, 0x97, 0xd7, 0x2b, 0x16, 0xfa, 0xf1, 0x24, 0xaf, 0xf7, 0xef, 0x76,
+	0x71, 0x1e, 0xe6, 0xe0, 0x30, 0x0d, 0x7b, 0x68, 0xac, 0x04, 0xc9, 0x01,
+	0x9a, 0x3c, 0x39, 0xeb, 0xdb, 0xcc, 0x30, 0x46, 0x0f, 0x30, 0x36, 0xee,
+	0x33, 0x91, 0x60, 0x3f, 0x3b, 0xa8, 0xab, 0x6e, 0xe2, 0xda, 0x86, 0x31,
+	0xc1, 0xf8, 0x55, 0xb8, 0xa9, 0x57, 0x6f, 0x6a, 0x54, 0x8c, 0xe8, 0x22,
+	0x7b, 0xbf, 0x97, 0xbc, 0xdf, 0xb5, 0x0a, 0x0d, 0x09, 0xdd, 0x6c, 0x44,
+	0x27, 0x4e, 0x72, 0xdc, 0xff, 0x17, 0xfd, 0x76, 0xb1, 0x43, 0xef, 0xb9,
+	0x51, 0x3d, 0x82, 0x9d, 0xe9, 0xa3, 0xe4, 0xea, 0x40, 0x78, 0xff, 0x11,
+	0xf2, 0xb7, 0xe3, 0xc4, 0x9f, 0x37, 0x2d, 0x9f, 0xa1, 0xe2, 0xd6, 0x47,
+	0x8c, 0xf0, 0xfb, 0x4a, 0xa0, 0xfd, 0x57, 0xd4, 0xc1, 0x67, 0x0f, 0xa8,
+	0xb8, 0x65, 0xe7, 0x62, 0xa4, 0x42, 0x51, 0xec, 0x58, 0xa4, 0xe2, 0xe6,
+	0x7d, 0x47, 0x88, 0xfb, 0x13, 0x36, 0x4f, 0xce, 0xa4, 0x1e, 0x46, 0xb0,
+	0x57, 0xd6, 0xb8, 0xdd, 0x8c, 0xdf, 0xa5, 0x78, 0xa6, 0x9f, 0x39, 0xb4,
+	0x59, 0x8a, 0x13, 0x43, 0x47, 0x68, 0x8f, 0xa5, 0x38, 0xde, 0x6f, 0x4c,
+	0xfc, 0xd4, 0x51, 0x8a, 0xa7, 0x79, 0xbe, 0x93, 0xe7, 0x0b, 0x07, 0x8c,
+	0xfe, 0x0e, 0xb5, 0x14, 0x0b, 0xf6, 0xd7, 0xa3, 0xbf, 0x4f, 0x6c, 0x53,
+	0x43, 0xfb, 0x58, 0x5d, 0x4e, 0xf7, 0xa2, 0x73, 0x2f, 0x36, 0x52, 0x57,
+	0xf7, 0xed, 0xec, 0x64, 0x7f, 0x3e, 0xea, 0xfc, 0x08, 0x1e, 0x63, 0x5e,
+	0xb7, 0xbd, 0xcf, 0x87, 0x73, 0x49, 0xc3, 0xff, 0x45, 0xc5, 0x30, 0x8b,
+	0x94, 0x80, 0xf6, 0x0c, 0x7c, 0x38, 0x9d, 0x2e, 0xc6, 0xa6, 0x81, 0x99,
+	0xf8, 0x29, 0xed, 0xf3, 0xd1, 0xdd, 0xd2, 0xdf, 0x04, 0xe3, 0xc3, 0x2c,
+	0x3c, 0x3d, 0x62, 0xb2, 0x6d, 0x99, 0x27, 0x89, 0x39, 0xdd, 0x70, 0x25,
+	0xc5, 0x37, 0xa2, 0x3b, 0x69, 0x16, 0xc4, 0xc4, 0x63, 0x48, 0xf7, 0xeb,
+	0x3d, 0xb7, 0xa9, 0xc2, 0xab, 0x55, 0xea, 0xd2, 0x81, 0x49, 0x4d, 0x8f,
+	0x57, 0xa8, 0xf1, 0x7e, 0xe6, 0xaf, 0xf1, 0x4a, 0xf5, 0x18, 0x9e, 0xee,
+	0x77, 0x62, 0xde, 0x42, 0x95, 0xd7, 0xe3, 0xe7, 0x19, 0xdb, 0xe2, 0xb3,
+	0x55, 0x13, 0x7b, 0x6d, 0x59, 0x11, 0x2f, 0x20, 0xb7, 0x2f, 0x5f, 0x58,
+	0xc3, 0xf8, 0xe5, 0x10, 0xdb, 0x8b, 0x95, 0xaa, 0x4e, 0xea, 0xfd, 0x34,
+	0x46, 0x68, 0xd7, 0x4f, 0xf0, 0x38, 0x3c, 0x68, 0x75, 0x2e, 0x27, 0xe7,
+	0x9e, 0x13, 0xb0, 0x3a, 0x6f, 0x33, 0x0d, 0x5f, 0x81, 0x1a, 0x88, 0x7e,
+	0x05, 0xa7, 0x71, 0x68, 0x44, 0xca, 0xc0, 0xed, 0x8d, 0x30, 0xaf, 0xee,
+	0xb3, 0x3a, 0x77, 0x9a, 0x73, 0x50, 0x6f, 0xe7, 0xc6, 0x3f, 0x2f, 0xcd,
+	0x62, 0xa6, 0xf8, 0x91, 0xbd, 0xa7, 0x0a, 0xbf, 0x62, 0x3b, 0xef, 0x0f,
+	0x96, 0xa3, 0xaa, 0x52, 0xfc, 0xe0, 0x14, 0xde, 0xe9, 0x7f, 0x0d, 0xe7,
+	0xfa, 0x2d, 0x2c, 0x08, 0x59, 0x70, 0x86, 0x6a, 0xcd, 0x46, 0xf5, 0x1a,
+	0x62, 0x84, 0x82, 0x9b, 0xe6, 0x7e, 0x1f, 0xef, 0xd2, 0xff, 0x6f, 0x9e,
+	0x6b, 0xd9, 0xb2, 0xf4, 0x62, 0xa1, 0xb5, 0xa3, 0x5a, 0xfc, 0xc6, 0xb4,
+	0xf7, 0xd3, 0xfc, 0xe9, 0x3c, 0x38, 0xbf, 0xaf, 0x4b, 0x72, 0xe1, 0xd3,
+	0x18, 0x1e, 0x34, 0xa2, 0x6b, 0xf3, 0x72, 0xf6, 0x9f, 0xa6, 0x0e, 0x2c,
+	0xec, 0x34, 0x4f, 0xec, 0xab, 0xc0, 0xbc, 0xf3, 0xcc, 0x1a, 0xaf, 0x9b,
+	0x4d, 0xdb, 0x59, 0xb0, 0x30, 0x60, 0x2e, 0x53, 0xff, 0x37, 0xfd, 0xf4,
+	0x34, 0x0e, 0x0e, 0xe5, 0xf1, 0xda, 0x87, 0x46, 0xfa, 0x79, 0x76, 0xcf,
+	0xbb, 0x17, 0x0d, 0xc9, 0xa3, 0xf6, 0xfa, 0xc3, 0x61, 0xe2, 0x63, 0xf6,
+	0x19, 0xa1, 0x86, 0x91, 0x74, 0x23, 0xb1, 0x21, 0x8a, 0xef, 0xa6, 0x23,
+	0xc4, 0x87, 0x30, 0xf1, 0xa1, 0x9e, 0xf8, 0x60, 0x12, 0x1f, 0xea, 0x88,
+	0x0f, 0x41, 0xfb, 0xd9, 0xb9, 0xac, 0x47, 0x0f, 0x8d, 0xbe, 0x86, 0x82,
+	0x81, 0x53, 0x70, 0x0d, 0xc8, 0x3e, 0x35, 0x8b, 0xfc, 0xa4, 0x56, 0x6b,
+	0xc3, 0x1c, 0x45, 0xf6, 0x0c, 0x0e, 0xa5, 0x4f, 0xa1, 0x68, 0x40, 0xe3,
+	0x58, 0x64, 0xaf, 0x40, 0x4d, 0xb8, 0x87, 0x58, 0xfd, 0x6b, 0xa3, 0xb6,
+	0xc7, 0x8b, 0xda, 0xbd, 0xd5, 0x30, 0xfa, 0x17, 0xaa, 0x73, 0x95, 0xe8,
+	0xe7, 0xbc, 0x1c, 0x67, 0x25, 0x66, 0xed, 0xd6, 0x30, 0x9b, 0xc7, 0x3f,
+	0x25, 0x6b, 0x26, 0xde, 0x74, 0xc0, 0x3b, 0x9d, 0x74, 0x67, 0x06, 0x99,
+	0x00, 0x59, 0xad, 0xd7, 0x87, 0x2b, 0x0f, 0x9f, 0x56, 0x15, 0x64, 0x3e,
+	0x27, 0x31, 0xaf, 0x36, 0xd8, 0xad, 0x32, 0x5b, 0xd7, 0x04, 0xc3, 0x79,
+	0xa8, 0x88, 0x90, 0x45, 0xcc, 0x64, 0x7e, 0x61, 0xb5, 0x99, 0x45, 0xd8,
+	0x52, 0xa7, 0xca, 0x7e, 0x8d, 0xa3, 0x12, 0xa3, 0xa6, 0x33, 0x46, 0x14,
+	0xf7, 0xc5, 0xef, 0x99, 0x0e, 0x0f, 0x8a, 0xfa, 0x2c, 0xeb, 0x1b, 0x21,
+	0x0d, 0x9e, 0x48, 0x20, 0xba, 0x81, 0x69, 0xe4, 0xe7, 0xe6, 0x85, 0x71,
+	0x53, 0xfa, 0x30, 0x06, 0x38, 0xbe, 0xe5, 0xe9, 0xfc, 0xbb, 0x9c, 0x7f,
+	0xfa, 0xef, 0xe2, 0x3b, 0xa1, 0x57, 0xee, 0x9d, 0x0e, 0x43, 0x7b, 0x40,
+	0xed, 0x28, 0x27, 0x07, 0x3f, 0xcc, 0xb8, 0xa7, 0x4c, 0x7e, 0x5e, 0x41,
+	0xcb, 0x40, 0x1c, 0x55, 0xa1, 0x53, 0x4a, 0x4c, 0xf6, 0x32, 0x29, 0x95,
+	0xf8, 0xfc, 0x6e, 0xea, 0x7a, 0x41, 0x86, 0xb6, 0xe2, 0xc3, 0xb7, 0x46,
+	0x45, 0xb7, 0x35, 0x43, 0x3b, 0x39, 0x8e, 0x37, 0xe6, 0x1e, 0x16, 0x9c,
+	0x3c, 0x32, 0x0b, 0x8e, 0x23, 0xd3, 0x98, 0x9b, 0xd6, 0xcc, 0xbd, 0xf2,
+	0xfc, 0xbf, 0xa8, 0xa2, 0x17, 0x85, 0xd8, 0xa1, 0xf7, 0xc7, 0xd8, 0xf6,
+	0x07, 0x8e, 0xc3, 0xd8, 0x44, 0x0c, 0x3e, 0x9a, 0xfe, 0x0e, 0x75, 0x79,
+	0x28, 0x97, 0x2f, 0xad, 0x42, 0xa2, 0x57, 0xf6, 0xe3, 0x9d, 0xc2, 0xac,
+	0x01, 0xbd, 0x79, 0x9b, 0x62, 0x04, 0x6f, 0x56, 0x4e, 0x61, 0xc6, 0x40,
+	0x90, 0x73, 0xa9, 0x61, 0x59, 0x5f, 0x1e, 0x3f, 0x05, 0x83, 0x57, 0x11,
+	0x83, 0xad, 0xc5, 0x3f, 0x35, 0xe3, 0xcc, 0x71, 0x74, 0xd3, 0xa9, 0xe8,
+	0x2d, 0x73, 0x15, 0xd9, 0x9b, 0x63, 0x9c, 0x6f, 0x65, 0x1d, 0xcf, 0x40,
+	0x1d, 0xee, 0xe4, 0x98, 0x9b, 0x38, 0x6f, 0xaf, 0x2d, 0xb4, 0xb0, 0x68,
+	0xa1, 0xbe, 0xb7, 0xc8, 0x11, 0x7d, 0xa0, 0x02, 0x99, 0x8e, 0x6a, 0xda,
+	0xcd, 0x7d, 0x0b, 0xf4, 0xf0, 0xab, 0xc4, 0x5d, 0xe2, 0x34, 0x36, 0x31,
+	0xee, 0xb4, 0x31, 0x16, 0x15, 0x47, 0xf4, 0x1e, 0xe6, 0xa8, 0xef, 0xdf,
+	0xed, 0x88, 0x86, 0xe4, 0x7d, 0xa3, 0x7f, 0xc0, 0x62, 0xb8, 0x43, 0x65,
+	0xc4, 0x41, 0x3d, 0xf3, 0x1a, 0xf4, 0xbd, 0x77, 0x92, 0x93, 0xfe, 0x84,
+	0xfc, 0xae, 0xfa, 0xaa, 0xa3, 0xc4, 0xa8, 0x11, 0x3c, 0x9a, 0x3e, 0x82,
+	0xbd, 0xe9, 0x14, 0x76, 0xa5, 0x77, 0x28, 0x43, 0xf6, 0xb3, 0x3a, 0x45,
+	0xde, 0xad, 0x8b, 0x96, 0x29, 0x5f, 0x46, 0x69, 0xe8, 0x9b, 0xd6, 0x50,
+	0x85, 0x8a, 0xf2, 0x50, 0x10, 0x37, 0xf5, 0xc5, 0xe1, 0x88, 0xbc, 0x67,
+	0xc9, 0x7b, 0xd9, 0xeb, 0xc7, 0x0d, 0xdc, 0xd8, 0x57, 0x8c, 0xd8, 0x7e,
+	0xcb, 0xea, 0xa9, 0x77, 0x62, 0xcd, 0x78, 0x1d, 0x96, 0x0d, 0x3c, 0x66,
+	0xcd, 0x66, 0xcc, 0xf9, 0xf8, 0x5a, 0x0f, 0xee, 0xde, 0xef, 0x41, 0x6b,
+	0x5f, 0x14, 0xbe, 0x48, 0x09, 0x7f, 0x07, 0xcc, 0x25, 0x30, 0x26, 0x26,
+	0x60, 0xf4, 0xdc, 0xe0, 0x08, 0x1c, 0x0a, 0xab, 0x1e, 0x7c, 0x95, 0x38,
+	0xbe, 0x9c, 0xb8, 0x13, 0x1b, 0xb7, 0x50, 0x1e, 0xf1, 0xe2, 0x1e, 0xd6,
+	0xbf, 0x85, 0x73, 0xff, 0xee, 0xa2, 0x43, 0xc4, 0x02, 0xd9, 0x83, 0xa8,
+	0x61, 0xc3, 0xb8, 0x9b, 0xba, 0x72, 0x23, 0x76, 0xb0, 0x12, 0x37, 0xee,
+	0xf6, 0xe3, 0xee, 0x71, 0x0f, 0x1a, 0xfa, 0xac, 0xc5, 0x87, 0xcd, 0xf8,
+	0x4a, 0x0d, 0x06, 0x5a, 0xc7, 0xbd, 0xf8, 0xdb, 0x3e, 0xdd, 0x77, 0x33,
+	0x73, 0xfe, 0x11, 0x33, 0x88, 0xbf, 0x1f, 0xf7, 0xe1, 0xf6, 0xbe, 0x13,
+	0x92, 0x47, 0x2e, 0x71, 0x32, 0xf6, 0x3c, 0x34, 0x3e, 0x13, 0x2b, 0xfb,
+	0xf4, 0xf3, 0x13, 0xe4, 0x76, 0x9d, 0x07, 0x4d, 0x3c, 0x30, 0xae, 0xa2,
+	0x85, 0xed, 0x7c, 0xbe, 0x6f, 0x16, 0x3a, 0x0e, 0xd6, 0x53, 0x86, 0x85,
+	0x58, 0x3e, 0xe0, 0x84, 0x49, 0x16, 0x8f, 0x2f, 0x00, 0xcd, 0x03, 0x13,
+	0xcc, 0xe3, 0x1e, 0xc6, 0x8e, 0x5e, 0x13, 0xf7, 0x8e, 0xcb, 0xf9, 0x11,
+	0xfb, 0x5d, 0xd8, 0xf7, 0xf7, 0x2d, 0xc4, 0x67, 0x07, 0x54, 0xe2, 0x40,
+	0x21, 0x86, 0x56, 0x2a, 0xf8, 0x5b, 0x5e, 0xdf, 0x96, 0x94, 0xbd, 0xcc,
+	0x40, 0x68, 0x67, 0xe0, 0x50, 0x05, 0x39, 0xc3, 0xa2, 0x7d, 0xd9, 0xeb,
+	0x8f, 0x12, 0xe7, 0x8b, 0x88, 0xf3, 0x25, 0xe4, 0xb0, 0x37, 0x0c, 0x1f,
+	0xc1, 0x23, 0xc4, 0xe5, 0xa3, 0x03, 0x9d, 0x8c, 0x3b, 0xa5, 0x78, 0x92,
+	0x71, 0xa0, 0x8f, 0xe7, 0xa7, 0x76, 0x1a, 0x1d, 0x45, 0xc4, 0xe9, 0x57,
+	0x89, 0xbf, 0x3d, 0xc4, 0x8c, 0xfb, 0xfa, 0x18, 0xee, 0x77, 0x32, 0x07,
+	0xb8, 0x2a, 0x3a, 0xdf, 0xc3, 0x1c, 0xeb, 0x66, 0x25, 0xe0, 0x7b, 0x0b,
+	0xa5, 0x70, 0xec, 0xab, 0x44, 0xc3, 0x6e, 0x29, 0x23, 0xf8, 0xa5, 0x42,
+	0x3d, 0xe0, 0xa4, 0xce, 0x8f, 0xc1, 0xea, 0x77, 0x70, 0xbc, 0x35, 0x26,
+	0x19, 0x38, 0xde, 0x30, 0x75, 0xed, 0xbb, 0xc4, 0xda, 0x0f, 0x89, 0xa9,
+	0xfe, 0xe9, 0xf5, 0x68, 0x34, 0x4c, 0x1e, 0xc7, 0x70, 0xba, 0xdf, 0x30,
+	0x65, 0x9f, 0xdc, 0x9b, 0xe4, 0x79, 0x93, 0xd3, 0x19, 0x33, 0x0d, 0xf1,
+	0xc3, 0x11, 0x8e, 0x47, 0x95, 0xbc, 0x04, 0x8e, 0x31, 0xe0, 0x9d, 0x7d,
+	0x8b, 0x39, 0x2e, 0x89, 0xa5, 0x12, 0xef, 0x46, 0x28, 0xeb, 0x62, 0xac,
+	0xa0, 0x3e, 0x1a, 0xfb, 0x54, 0xa4, 0x0e, 0x46, 0x70, 0xef, 0x9e, 0x6c,
+	0x1c, 0x6e, 0x0f, 0xc5, 0x6f, 0x63, 0x1c, 0x0e, 0x17, 0x33, 0x0e, 0xbb,
+	0x22, 0x22, 0x9b, 0x13, 0xc3, 0x8c, 0xdb, 0x5b, 0x92, 0x61, 0x34, 0x71,
+	0x0e, 0x27, 0x52, 0xec, 0xb7, 0x6f, 0x26, 0x9e, 0x49, 0x79, 0x18, 0xb3,
+	0x34, 0x1e, 0x44, 0xb5, 0x91, 0x69, 0x3c, 0xfc, 0x3c, 0xe6, 0xf0, 0x30,
+	0xec, 0x6b, 0x6d, 0x7d, 0x0a, 0xe2, 0xcd, 0xd9, 0xe7, 0x65, 0xcf, 0xa4,
+	0x04, 0x9b, 0x65, 0x2d, 0xf3, 0xde, 0x72, 0xd9, 0xfb, 0xd9, 0x9f, 0xfc,
+	0x3e, 0xca, 0x89, 0x4f, 0x65, 0x39, 0x1c, 0xfa, 0x79, 0x48, 0x70, 0xb7,
+	0x86, 0xb8, 0x2b, 0xfb, 0x73, 0x2c, 0x6b, 0x55, 0x60, 0x2a, 0x1e, 0xfd,
+	0xef, 0x8f, 0xa3, 0xf6, 0x7e, 0x56, 0xc1, 0x24, 0xe2, 0x5f, 0x92, 0xf8,
+	0xc7, 0x31, 0x74, 0x5d, 0x4f, 0x0c, 0xa4, 0x4c, 0xff, 0x98, 0x24, 0x06,
+	0x12, 0xa7, 0x8f, 0x10, 0xa7, 0x9f, 0x22, 0x4e, 0x7f, 0x93, 0x38, 0xfd,
+	0x24, 0x31, 0x21, 0xbb, 0xa6, 0xd7, 0x24, 0xcf, 0x2f, 0x38, 0x1f, 0xef,
+	0xd9, 0x6b, 0x8b, 0xd5, 0xd4, 0xd5, 0xac, 0x01, 0x79, 0xe7, 0x47, 0x3f,
+	0x24, 0x76, 0xff, 0x13, 0xce, 0x93, 0xbf, 0x2a, 0xbb, 0xef, 0xaa, 0xb1,
+	0xaf, 0x1b, 0xee, 0xbe, 0x5a, 0xad, 0x07, 0xf6, 0xb7, 0x02, 0x4c, 0xe1,
+	0xa2, 0x05, 0x7d, 0x6d, 0x70, 0xf4, 0xd5, 0x1e, 0x3a, 0x29, 0xcf, 0x43,
+	0xa7, 0x49, 0x5e, 0xdf, 0x26, 0x7b, 0xbd, 0x0f, 0xc9, 0x7e, 0xad, 0x65,
+	0xbc, 0xe7, 0xea, 0xab, 0x35, 0xdf, 0x82, 0x8d, 0x6d, 0xfe, 0x49, 0xfb,
+	0x5e, 0xcd, 0xfb, 0x8f, 0x50, 0x5f, 0x19, 0xb6, 0x99, 0x4a, 0xca, 0x7e,
+	0xd4, 0x99, 0x78, 0x22, 0x2d, 0xbf, 0x6b, 0x5b, 0x12, 0xea, 0xe3, 0x88,
+	0x55, 0x0b, 0x1f, 0x0f, 0xe3, 0xd6, 0x3e, 0x0f, 0xed, 0x20, 0x8e, 0x32,
+	0xfa, 0xd6, 0xfd, 0xe3, 0xf5, 0xf4, 0xb5, 0xc7, 0x2c, 0x2d, 0x12, 0x68,
+	0x19, 0x27, 0xe7, 0x59, 0x3f, 0xbe, 0x18, 0x4b, 0x07, 0x2c, 0xcb, 0x73,
+	0x8d, 0x11, 0xde, 0xa0, 0xf8, 0xe1, 0xa2, 0x0f, 0x3a, 0xe8, 0x57, 0x6b,
+	0xf7, 0x07, 0xb4, 0xb7, 0x88, 0xa7, 0xeb, 0xea, 0x0f, 0xd3, 0x3e, 0x8c,
+	0xf3, 0x4d, 0xc4, 0x52, 0x67, 0x24, 0xc0, 0x3c, 0xd1, 0x43, 0xdb, 0xf7,
+	0xe2, 0x7c, 0x42, 0xfc, 0x4b, 0xef, 0xf8, 0x2e, 0x73, 0x93, 0x0e, 0xfa,
+	0xc6, 0x07, 0x89, 0xeb, 0xe9, 0x4b, 0x61, 0x1e, 0x33, 0xe9, 0x0b, 0x6e,
+	0xbc, 0x93, 0x30, 0xe8, 0x77, 0x1e, 0xbc, 0x9b, 0xa8, 0x63, 0x9f, 0x41,
+	0x96, 0xf5, 0x63, 0xa3, 0xfd, 0xde, 0x75, 0x4d, 0xfc, 0x5b, 0x4a, 0x4d,
+	0xff, 0x2c, 0xb5, 0x02, 0xd1, 0x4a, 0x0d, 0x7f, 0x37, 0xfe, 0x37, 0xf8,
+	0x19, 0xe3, 0xf6, 0x9a, 0x3e, 0x70, 0x0e, 0x11, 0x22, 0x0f, 0x9c, 0x38,
+	0x28, 0xcf, 0xe9, 0x50, 0x1b, 0x9d, 0xeb, 0xd0, 0x99, 0xdb, 0xea, 0x99,
+	0x73, 0x0e, 0x27, 0xfb, 0x24, 0x2b, 0x66, 0xd9, 0x0f, 0xfa, 0x8b, 0xf1,
+	0xc0, 0xfe, 0xc3, 0xf4, 0x91, 0x02, 0x2c, 0x78, 0xc4, 0x8d, 0xbf, 0x3b,
+	0x38, 0x22, 0x6b, 0x4b, 0x82, 0x99, 0xfe, 0x21, 0x12, 0x85, 0x30, 0xb9,
+	0xde, 0xfd, 0x7b, 0x46, 0x30, 0x90, 0xe3, 0x79, 0x1f, 0x84, 0xe2, 0x5f,
+	0x51, 0x71, 0x98, 0x3c, 0x22, 0x10, 0xbf, 0x9a, 0x36, 0x26, 0xef, 0xb8,
+	0x49, 0xec, 0x5f, 0x41, 0x1b, 0xeb, 0xe6, 0x7c, 0x7e, 0x83, 0xe3, 0xd8,
+	0x41, 0x1b, 0x1b, 0x4d, 0xcc, 0xc4, 0x56, 0xda, 0x58, 0x9c, 0x36, 0x16,
+	0xa7, 0x3d, 0xc5, 0x69, 0x63, 0xf2, 0x6e, 0x7e, 0x9c, 0x36, 0x16, 0xa7,
+	0x8d, 0xc5, 0x53, 0x8b, 0xf1, 0x14, 0x99, 0xc6, 0xae, 0x91, 0x45, 0xc4,
+	0x31, 0x79, 0xb6, 0xc6, 0x79, 0xb8, 0xed, 0x6f, 0xc8, 0xd9, 0x6f, 0xe0,
+	0xa1, 0xe0, 0x4e, 0xfa, 0xe4, 0x63, 0x43, 0xc4, 0x3b, 0xda, 0xc1, 0xa2,
+	0xb4, 0x70, 0xfc, 0x7a, 0xe6, 0xb1, 0xc7, 0xc8, 0xf3, 0x55, 0x3c, 0x6b,
+	0x4a, 0x1e, 0x6c, 0xf2, 0x9c, 0xb1, 0x26, 0x29, 0x1c, 0xec, 0x18, 0x36,
+	0xf4, 0x03, 0x37, 0x91, 0x17, 0x56, 0x92, 0x97, 0x8c, 0x2c, 0x00, 0x5e,
+	0x1c, 0x12, 0x19, 0xc5, 0xc7, 0xb3, 0xfb, 0x4f, 0x8f, 0xf7, 0xd7, 0x44,
+	0x1b, 0x65, 0x7d, 0x88, 0x9c, 0x64, 0xf1, 0xb0, 0x70, 0xbc, 0xc3, 0xe4,
+	0x48, 0x7a, 0xf8, 0xdf, 0x21, 0x1c, 0xaf, 0x12, 0x65, 0x7b, 0xf4, 0xf0,
+	0x3b, 0x30, 0xd6, 0xfd, 0x52, 0xb1, 0x16, 0xbf, 0x16, 0x0a, 0xc4, 0x9f,
+	0x54, 0x54, 0x34, 0x93, 0xef, 0xdd, 0xbc, 0xd3, 0x89, 0x9e, 0xd0, 0x62,
+	0x7c, 0x85, 0x9c, 0x6f, 0xf5, 0x35, 0x2a, 0x96, 0xec, 0xa3, 0x2d, 0x55,
+	0x0a, 0xc7, 0xd2, 0xc3, 0xe7, 0x30, 0x61, 0xaf, 0x13, 0x8e, 0xa6, 0x8e,
+	0x5b, 0x55, 0x86, 0x60, 0x11, 0xb1, 0xed, 0xea, 0x37, 0x2d, 0xb7, 0xac,
+	0x35, 0x91, 0x03, 0x0e, 0xf7, 0x47, 0x5f, 0x70, 0x12, 0xf7, 0xd7, 0x93,
+	0x07, 0x3e, 0x91, 0xe3, 0x81, 0x07, 0xfb, 0x0d, 0xed, 0x07, 0xc4, 0x8b,
+	0xfd, 0x3c, 0xdf, 0xca, 0x73, 0xab, 0xdf, 0xe0, 0x7c, 0x04, 0x9a, 0x66,
+	0x90, 0x1b, 0xbe, 0x43, 0x99, 0x7b, 0x29, 0x73, 0x82, 0xf6, 0x9f, 0xee,
+	0xd5, 0x90, 0x1c, 0x33, 0x30, 0xde, 0xeb, 0x45, 0xdf, 0x58, 0x10, 0x4f,
+	0xf6, 0xfa, 0xb0, 0x93, 0xfc, 0xf0, 0x70, 0xaf, 0xf8, 0xe2, 0x4c, 0xf4,
+	0x8f, 0xcd, 0xc4, 0x37, 0x92, 0xb2, 0x3e, 0xf5, 0x2e, 0x56, 0x57, 0x88,
+	0x7e, 0xc4, 0x2f, 0xc9, 0xaf, 0x93, 0x7a, 0x4f, 0x8c, 0x63, 0x8a, 0x79,
+	0xf5, 0x43, 0x31, 0xe8, 0x43, 0x9c, 0xc1, 0x8f, 0x87, 0xbe, 0x20, 0x31,
+	0x52, 0x7c, 0x52, 0xc3, 0x13, 0xe4, 0x3c, 0xa5, 0xc4, 0xd5, 0x92, 0x48,
+	0x4d, 0xf4, 0x0b, 0x8a, 0x1e, 0x7b, 0x45, 0xb5, 0xac, 0x4a, 0x89, 0xe1,
+	0x07, 0x35, 0xf2, 0x0f, 0x13, 0x37, 0xdb, 0x31, 0x5b, 0xc3, 0xf4, 0xdd,
+	0x95, 0xa8, 0xda, 0xdd, 0x87, 0xff, 0x56, 0x19, 0xff, 0x60, 0x1a, 0x63,
+	0xfd, 0x34, 0x62, 0xfb, 0xec, 0xbe, 0x93, 0xd3, 0x67, 0x91, 0x33, 0xbf,
+	0xa1, 0xd6, 0x66, 0xbe, 0x0b, 0xfd, 0xd0, 0x69, 0x87, 0x3e, 0x71, 0x94,
+	0xf1, 0xc1, 0x45, 0xfb, 0x9c, 0x31, 0xae, 0xd1, 0x7f, 0x6b, 0x8f, 0x56,
+	0xc1, 0x88, 0x5f, 0xab, 0x3a, 0x2d, 0x54, 0x8a, 0x3c, 0xa1, 0xf2, 0x6c,
+	0x6e, 0x14, 0x26, 0xf6, 0x4b, 0x6c, 0x70, 0x40, 0x23, 0x0e, 0xff, 0x3d,
+	0x7d, 0xe6, 0x4e, 0x3b, 0x1e, 0x1d, 0xb6, 0x9f, 0x85, 0x76, 0x8e, 0xc7,
+	0xe9, 0x27, 0x8b, 0xd1, 0xd1, 0xef, 0x41, 0xbb, 0x1d, 0x8b, 0x1e, 0xb3,
+	0x2a, 0xe8, 0x33, 0x1d, 0xfb, 0x03, 0x4d, 0x37, 0xd2, 0x67, 0xae, 0xbb,
+	0x46, 0xe2, 0xd8, 0x61, 0xf2, 0x5f, 0xc3, 0xbc, 0x8e, 0xf8, 0xb2, 0xb5,
+	0xde, 0xe8, 0x78, 0x9e, 0x32, 0xdd, 0x4f, 0xfb, 0x7f, 0x97, 0x3c, 0xe7,
+	0xdc, 0x9e, 0x43, 0xd4, 0x99, 0x66, 0xfb, 0xc3, 0xcf, 0x92, 0x3e, 0xdb,
+	0x37, 0x62, 0xfc, 0x2d, 0x71, 0x2f, 0x46, 0x5f, 0xfa, 0x37, 0xc6, 0xec,
+	0xe2, 0x50, 0xfc, 0xf6, 0x62, 0x04, 0x71, 0x1f, 0x65, 0xfd, 0x38, 0xa9,
+	0xf7, 0x6f, 0x90, 0x77, 0x8f, 0x43, 0x26, 0x65, 0xf1, 0xe0, 0x83, 0xa4,
+	0xd8, 0xd9, 0x89, 0xff, 0x59, 0x89, 0xf8, 0x26, 0xc6, 0xe0, 0xa0, 0xe6,
+	0x90, 0xb5, 0xf0, 0x99, 0x58, 0x73, 0xf0, 0x1a, 0xca, 0x5c, 0x47, 0xff,
+	0x03, 0xe6, 0x0c, 0x47, 0x70, 0xcf, 0x1e, 0xc9, 0x31, 0xd0, 0x20, 0xb9,
+	0xda, 0xbc, 0x50, 0xc0, 0x3c, 0x43, 0xac, 0x58, 0x3b, 0x76, 0x98, 0x71,
+	0x42, 0xd6, 0x96, 0x91, 0xf1, 0x19, 0x61, 0xbc, 0xda, 0x5b, 0x6f, 0xbf,
+	0xd3, 0x70, 0xff, 0x58, 0x3d, 0x5e, 0xe9, 0x9d, 0x89, 0xfb, 0x98, 0xeb,
+	0xc4, 0x98, 0xeb, 0xc4, 0xc6, 0xbc, 0x88, 0x1d, 0x98, 0xc6, 0x83, 0xb2,
+	0x1d, 0x98, 0xc3, 0x83, 0xb2, 0x8d, 0xa9, 0xf8, 0x2a, 0xf3, 0x97, 0x0d,
+	0xc4, 0xf3, 0x1e, 0xda, 0xe3, 0xff, 0xe0, 0xdc, 0x0f, 0xd0, 0xde, 0xab,
+	0x89, 0xf7, 0x6f, 0xee, 0x02, 0xee, 0xb4, 0xf5, 0x73, 0x84, 0x7a, 0x54,
+	0xf0, 0x15, 0xfa, 0x44, 0x15, 0x63, 0x52, 0x37, 0xe7, 0x7c, 0xe7, 0xa0,
+	0x11, 0x0c, 0xab, 0x01, 0xed, 0x09, 0xce, 0x73, 0xd7, 0x88, 0x8a, 0x47,
+	0xfb, 0x17, 0x63, 0x3e, 0x63, 0xca, 0xb6, 0xa1, 0x09, 0xbb, 0x7c, 0x37,
+	0xfd, 0xe1, 0x6e, 0xfa, 0xc9, 0x7b, 0xf4, 0x93, 0xc9, 0x95, 0xf2, 0x3e,
+	0xa9, 0x93, 0x39, 0xff, 0xc3, 0x58, 0x93, 0x90, 0x78, 0xa7, 0xf7, 0x0c,
+	0xa9, 0xcc, 0xb5, 0x68, 0x9f, 0x5d, 0xcc, 0x51, 0x6e, 0xa7, 0x6d, 0x3e,
+	0x3a, 0x24, 0x3e, 0x24, 0x39, 0x8b, 0x11, 0xde, 0x46, 0xdb, 0x7c, 0x7e,
+	0x48, 0xfc, 0xa3, 0x14, 0xb7, 0xee, 0x94, 0xfd, 0xa6, 0xa5, 0xf8, 0xec,
+	0xbe, 0xc3, 0x94, 0xef, 0x08, 0x76, 0xd1, 0x2e, 0x4b, 0x69, 0x97, 0xf7,
+	0x51, 0xaf, 0x1e, 0xda, 0xe5, 0x06, 0xe2, 0x50, 0x09, 0xed, 0xf2, 0x5e,
+	0xf2, 0x81, 0xca, 0x9c, 0x5d, 0xfe, 0xdd, 0xf8, 0xc2, 0x8a, 0x6c, 0x8c,
+	0xf0, 0x42, 0xdd, 0x2d, 0xef, 0xf7, 0x59, 0xd6, 0xed, 0x66, 0xa6, 0x69,
+	0x06, 0x74, 0xb6, 0x1d, 0xc1, 0xb2, 0xb4, 0x13, 0xe5, 0x7d, 0x11, 0x2c,
+	0x4d, 0xd6, 0xb4, 0x9f, 0x55, 0x22, 0xc8, 0xcc, 0xc8, 0xf2, 0x40, 0x57,
+	0x9f, 0x7c, 0xdf, 0x43, 0x23, 0x07, 0xe1, 0xf8, 0xaf, 0xcd, 0x7e, 0x53,
+	0xe4, 0xf3, 0x7f, 0x01, 0x7f, 0x5c, 0x42, 0x99, 0x3a, 0xcd, 0x8f, 0xac,
+	0xc9, 0xec, 0xf7, 0x07, 0x9c, 0xb7, 0xf1, 0x7c, 0x16, 0xdb, 0xa8, 0x1a,
+	0x77, 0x3a, 0xbf, 0x98, 0xf4, 0x60, 0xfa, 0xb8, 0x89, 0xbf, 0xcd, 0xb6,
+	0xe3, 0x2e, 0x88, 0x34, 0xe2, 0xb9, 0x84, 0x82, 0x69, 0xc6, 0xd3, 0xf8,
+	0x91, 0xbd, 0x2e, 0x50, 0x89, 0xf2, 0xdd, 0xf6, 0x9a, 0x02, 0x0e, 0x24,
+	0xf4, 0xf6, 0x34, 0xcf, 0xcb, 0x0e, 0x7a, 0x51, 0xbc, 0x5b, 0xc1, 0x2d,
+	0x01, 0x2f, 0x4a, 0xf9, 0xdb, 0x43, 0xbe, 0xd9, 0x1d, 0x5a, 0x6e, 0x6d,
+	0x59, 0x25, 0xf6, 0xed, 0x05, 0x0e, 0x96, 0x94, 0x0b, 0x0e, 0x1e, 0x30,
+	0x65, 0xed, 0xd2, 0x40, 0x77, 0xa2, 0x12, 0x85, 0xbb, 0x6b, 0x9a, 0x1a,
+	0x51, 0x63, 0xbe, 0xc3, 0xfa, 0x05, 0x07, 0x3f, 0x5b, 0x21, 0xeb, 0xf6,
+	0x4f, 0x49, 0x8c, 0x1b, 0x92, 0x79, 0xcd, 0xc6, 0x50, 0xe7, 0xd8, 0x5b,
+	0x9a, 0xe8, 0x65, 0x13, 0x39, 0x8a, 0xda, 0xf7, 0xa6, 0x5d, 0xc6, 0x17,
+	0x39, 0x4a, 0x0c, 0x90, 0xf8, 0x72, 0x0a, 0xed, 0xfd, 0xa7, 0x68, 0xff,
+	0xb2, 0x8e, 0xc1, 0xbc, 0x77, 0x81, 0x85, 0xe2, 0x85, 0x99, 0x60, 0x31,
+	0xa2, 0x15, 0x15, 0xc4, 0x6f, 0xfa, 0x00, 0x5e, 0x30, 0xf5, 0x96, 0x87,
+	0x1c, 0xd1, 0x87, 0x8a, 0xa0, 0xaf, 0x7b, 0x5b, 0xe9, 0xc1, 0xc6, 0xc0,
+	0x08, 0xfa, 0xc8, 0x05, 0xf3, 0xf9, 0xf8, 0xba, 0x3d, 0x8c, 0x6f, 0x8e,
+	0x8b, 0xf9, 0xb8, 0x16, 0x8a, 0xff, 0x8e, 0x3c, 0xc0, 0x3f, 0x9b, 0x18,
+	0xed, 0xb0, 0x7d, 0x27, 0x90, 0xd9, 0x44, 0x7b, 0x0d, 0x8f, 0x87, 0xe9,
+	0x23, 0x23, 0x82, 0x7d, 0xf2, 0x35, 0xa3, 0x17, 0x0a, 0x98, 0x3f, 0x16,
+	0x33, 0x0f, 0x39, 0x9d, 0xb4, 0x3a, 0xdd, 0xb4, 0x6b, 0xe7, 0xa2, 0x99,
+	0x50, 0xd3, 0x37, 0xe0, 0x9d, 0x5d, 0x33, 0x51, 0x48, 0x5f, 0xaa, 0x48,
+	0xca, 0x0b, 0x55, 0xea, 0xa7, 0xd9, 0x6f, 0xec, 0x3d, 0x04, 0xda, 0x03,
+	0x8e, 0xda, 0x75, 0x49, 0x45, 0x27, 0xf6, 0xeb, 0x2d, 0xa5, 0xea, 0x4c,
+	0x78, 0x98, 0xaf, 0x94, 0xa4, 0x3d, 0x00, 0xb9, 0x32, 0x58, 0xef, 0xa7,
+	0xbb, 0x5c, 0x28, 0x37, 0x8c, 0xe8, 0x33, 0xcc, 0x81, 0x1c, 0xa3, 0x4e,
+	0xfc, 0xcc, 0x96, 0x6b, 0x1a, 0x8a, 0x47, 0x6f, 0xc0, 0xe9, 0x5d, 0x7e,
+	0xa8, 0xbc, 0x76, 0x76, 0xcf, 0x1c, 0x14, 0x8c, 0x12, 0x08, 0xd2, 0x8b,
+	0xf1, 0xd6, 0x2e, 0x15, 0xae, 0xd1, 0xbf, 0xc1, 0x87, 0xbb, 0x14, 0xcc,
+	0x9f, 0xa7, 0xa0, 0x68, 0x78, 0x84, 0x3a, 0x11, 0xee, 0x45, 0x3f, 0x4d,
+	0xc1, 0xe6, 0x5d, 0x5b, 0x92, 0xc2, 0xed, 0xc9, 0xe9, 0x06, 0x2b, 0x61,
+	0xee, 0x7e, 0xd3, 0xaa, 0x30, 0x8c, 0xd8, 0x2d, 0xaa, 0xb5, 0xb8, 0x72,
+	0x41, 0xa0, 0x65, 0x80, 0x38, 0xfd, 0x12, 0x7d, 0xe0, 0x64, 0x7f, 0xdc,
+	0xf2, 0x18, 0x8b, 0x89, 0xb5, 0x51, 0x34, 0x30, 0x37, 0x97, 0xbc, 0x7b,
+	0x9b, 0x9d, 0xef, 0xca, 0x7e, 0x63, 0x27, 0xfc, 0x63, 0x0f, 0xe3, 0x78,
+	0xc2, 0x8d, 0xc5, 0x63, 0xa5, 0xb8, 0x8e, 0x39, 0x75, 0x98, 0xdc, 0x21,
+	0xbc, 0x2f, 0xcb, 0xf1, 0x9e, 0x27, 0xc7, 0xfb, 0x15, 0xb2, 0x1c, 0x6f,
+	0x80, 0xb9, 0x5a, 0x95, 0x51, 0x8a, 0x5b, 0x06, 0x0c, 0xc6, 0x80, 0x52,
+	0x34, 0xdb, 0xeb, 0x01, 0x1a, 0x6e, 0xa3, 0xff, 0x7e, 0x9e, 0xf9, 0xf8,
+	0xcd, 0x3b, 0x03, 0xbe, 0x1d, 0x8a, 0x8f, 0x71, 0x40, 0xda, 0x3f, 0x4c,
+	0xdc, 0xf0, 0x61, 0x4e, 0xaf, 0x11, 0x5c, 0x8a, 0xc0, 0xf9, 0x43, 0xd4,
+	0xe5, 0xe2, 0xb1, 0x1b, 0x10, 0xa6, 0xee, 0xc2, 0xfb, 0x0e, 0xe7, 0xc6,
+	0x31, 0x41, 0xd9, 0x9d, 0x78, 0x6f, 0x70, 0x16, 0x5e, 0x3d, 0x90, 0xcd,
+	0xc3, 0x03, 0x7d, 0x13, 0xb2, 0x5e, 0xfc, 0x35, 0x86, 0xd7, 0x7b, 0x24,
+	0x0f, 0xff, 0x41, 0xbf, 0xde, 0x5f, 0x2a, 0xeb, 0x84, 0xf4, 0xe7, 0xaf,
+	0x2e, 0x70, 0x30, 0xbe, 0xe8, 0xfe, 0xef, 0x3b, 0xe2, 0xf2, 0x1c, 0xd9,
+	0xff, 0x08, 0xef, 0x7f, 0x9f, 0xf1, 0xfc, 0x36, 0x5e, 0x8f, 0x55, 0x32,
+	0xd7, 0x5e, 0x18, 0x3f, 0xef, 0xe2, 0xf5, 0xc7, 0x38, 0x97, 0x65, 0x46,
+	0x4d, 0xec, 0x15, 0xe5, 0x08, 0x71, 0xc3, 0x81, 0x1d, 0x21, 0x3d, 0xba,
+	0xc3, 0xce, 0xa1, 0x9d, 0x98, 0x48, 0x5f, 0x9d, 0xf3, 0xc1, 0x4a, 0x94,
+	0xec, 0x96, 0xfc, 0xc5, 0x90, 0xf5, 0x9f, 0xfe, 0x12, 0xe6, 0x4f, 0x95,
+	0x17, 0xec, 0x33, 0xbf, 0xff, 0x09, 0xee, 0x8a, 0x48, 0x33, 0x42, 0x7d,
+	0xf9, 0x7d, 0x50, 0x87, 0xd0, 0x9d, 0x7e, 0x10, 0xed, 0xbb, 0xf4, 0x76,
+	0x59, 0x1f, 0x7a, 0x25, 0x14, 0xb7, 0xca, 0x8d, 0x4e, 0xb8, 0x16, 0x18,
+	0xcd, 0xcc, 0x5d, 0x62, 0xdf, 0x56, 0x8a, 0x19, 0x3b, 0x8e, 0x61, 0xf3,
+	0xb0, 0x1e, 0xdc, 0xa1, 0x18, 0xcc, 0xf7, 0x34, 0x1c, 0x1a, 0x2c, 0xc0,
+	0xdd, 0x7b, 0x5a, 0x19, 0xdb, 0x4c, 0xe2, 0x66, 0x8d, 0xff, 0x1c, 0xde,
+	0xc7, 0x49, 0x53, 0xde, 0x11, 0x2a, 0x42, 0xab, 0x26, 0x7b, 0x80, 0x98,
+	0x79, 0x4e, 0xbb, 0xe4, 0x3d, 0x71, 0x4f, 0x91, 0x91, 0x7f, 0xdf, 0xdf,
+	0x60, 0xae, 0x38, 0x89, 0xfd, 0x83, 0xb2, 0x2e, 0x50, 0xa5, 0x1c, 0xef,
+	0x9f, 0xeb, 0xeb, 0x22, 0xe6, 0x3f, 0x64, 0x66, 0x70, 0x7e, 0x61, 0x25,
+	0x30, 0x5d, 0x41, 0xe8, 0xd3, 0x01, 0xf9, 0x9e, 0x0d, 0xff, 0xde, 0xb3,
+	0xfc, 0x5f, 0x90, 0x76, 0x4a, 0xcb, 0xb2, 0x6b, 0x05, 0x3f, 0xaa, 0x94,
+	0xf7, 0x01, 0x8f, 0x27, 0x2b, 0xca, 0xb3, 0xcf, 0x9c, 0xff, 0x54, 0x1f,
+	0x6f, 0x58, 0x7e, 0xbb, 0x8d, 0x7c, 0xdd, 0xd7, 0xad, 0xa8, 0x57, 0xca,
+	0x17, 0xb0, 0x6d, 0xf1, 0xcb, 0x2a, 0x65, 0x1d, 0x71, 0x54, 0x0d, 0x55,
+	0x29, 0xad, 0x43, 0x97, 0xb7, 0xfb, 0x9a, 0x15, 0x6d, 0x96, 0xf3, 0x7c,
+	0x39, 0x8b, 0xf7, 0xa5, 0x6c, 0xfe, 0xfe, 0x0b, 0xb9, 0xb6, 0x0a, 0xc9,
+	0x53, 0xb3, 0x65, 0xee, 0xee, 0x97, 0xfd, 0x4b, 0x51, 0x9c, 0xa8, 0x9f,
+	0xda, 0x5e, 0xbe, 0xef, 0xef, 0x5c, 0xd2, 0x5e, 0xb6, 0x6c, 0x55, 0x15,
+	0x8a, 0xa5, 0x7c, 0x06, 0xff, 0x8f, 0xbd, 0x86, 0x70, 0xc6, 0xde, 0x73,
+	0xb8, 0xcd, 0x6c, 0x88, 0x16, 0xe1, 0x33, 0x50, 0xaf, 0x8a, 0xcf, 0x2f,
+	0xb2, 0xb9, 0x6d, 0xb4, 0xb9, 0x88, 0xf9, 0xad, 0xdb, 0x88, 0x3e, 0xe4,
+	0x46, 0x26, 0xe3, 0x86, 0xde, 0x72, 0x5e, 0x39, 0xa4, 0xdc, 0x1d, 0xd0,
+	0xdb, 0xdf, 0x23, 0xd7, 0x78, 0x39, 0x10, 0xb7, 0x4a, 0x0d, 0xc3, 0xd7,
+	0xab, 0xe8, 0xe6, 0x1a, 0xc6, 0xb2, 0x17, 0x99, 0x3f, 0xb6, 0x05, 0x7a,
+	0xec, 0xe7, 0x8b, 0x4a, 0x64, 0x05, 0xae, 0xb4, 0xbf, 0xdd, 0xd2, 0x0c,
+	0x23, 0xf5, 0xb2, 0xac, 0x77, 0xf1, 0x77, 0x0c, 0xf3, 0xed, 0x6b, 0x6d,
+	0x08, 0xda, 0xff, 0x57, 0xe5, 0xbe, 0xef, 0xd2, 0x82, 0x1a, 0xfb, 0xff,
+	0x1d, 0x98, 0x9b, 0xba, 0xb0, 0x2e, 0x8c, 0x4d, 0xa6, 0x65, 0x3d, 0x67,
+	0x5a, 0x38, 0x73, 0x71, 0xbf, 0xf3, 0x0a, 0x07, 0xf3, 0x0d, 0x52, 0xac,
+	0x58, 0xf6, 0xfb, 0x54, 0x17, 0xdf, 0x97, 0x58, 0x7a, 0xc9, 0x7e, 0x67,
+	0xf9, 0xae, 0x42, 0xa5, 0xfd, 0xfd, 0xb1, 0x79, 0x8b, 0x9c, 0x78, 0x29,
+	0x51, 0x16, 0xf3, 0xf0, 0xf7, 0xe6, 0x45, 0x05, 0x58, 0x4f, 0x4e, 0xd6,
+	0x74, 0xd5, 0x33, 0x38, 0x67, 0x7f, 0xc7, 0x21, 0x1e, 0x92, 0xef, 0x37,
+	0x9c, 0x48, 0xd0, 0xa7, 0x07, 0xbb, 0x43, 0xfb, 0xed, 0xbe, 0x5f, 0xc7,
+	0xa6, 0x51, 0x79, 0xe6, 0xd7, 0x8c, 0xd5, 0x89, 0x49, 0xc6, 0x37, 0x69,
+	0x4b, 0xf2, 0x6e, 0x3d, 0xd3, 0xc6, 0x5c, 0x55, 0x75, 0x04, 0x71, 0x3b,
+	0xe3, 0xca, 0x2b, 0x09, 0xda, 0xe9, 0x42, 0xbd, 0xe3, 0xdb, 0xe4, 0x06,
+	0x65, 0x11, 0x3d, 0xf8, 0xae, 0xd2, 0x82, 0x31, 0xd6, 0x9f, 0x48, 0x88,
+	0x2d, 0x56, 0xc6, 0x0a, 0x39, 0x96, 0x43, 0xe4, 0xa3, 0x2f, 0x27, 0x34,
+	0x9c, 0xab, 0xf7, 0x20, 0x45, 0x7e, 0xfa, 0x52, 0x42, 0xb8, 0x9a, 0x17,
+	0x4f, 0x0c, 0xca, 0xfa, 0x60, 0x23, 0x1a, 0x12, 0xb2, 0x36, 0xec, 0xc5,
+	0xe3, 0x23, 0x5e, 0xda, 0xa3, 0x65, 0x6d, 0xa2, 0xed, 0xb6, 0x6a, 0x13,
+	0xec, 0x53, 0xd6, 0x14, 0xa3, 0xb8, 0xa9, 0xb7, 0x12, 0x4f, 0x8c, 0xf8,
+	0xf0, 0x3d, 0xf2, 0xf1, 0x3e, 0xd6, 0x7b, 0x25, 0xe1, 0x47, 0x6f, 0xca,
+	0x87, 0xe7, 0xc9, 0xcb, 0xb7, 0xf2, 0x5c, 0xbe, 0x05, 0x56, 0x60, 0x04,
+	0x91, 0x48, 0x1d, 0x63, 0x6c, 0xbc, 0x02, 0x6b, 0x57, 0x1e, 0x81, 0xda,
+	0x7b, 0x94, 0xc7, 0xf5, 0x8c, 0xd5, 0xd7, 0x23, 0x39, 0x18, 0x41, 0x72,
+	0xe4, 0x87, 0xe8, 0x19, 0x94, 0x71, 0xc9, 0x37, 0xa1, 0x64, 0x6f, 0x91,
+	0x81, 0xf9, 0x8c, 0xa7, 0x43, 0x23, 0xd2, 0x4f, 0x25, 0xfb, 0xfe, 0x4b,
+	0xdb, 0xff, 0x99, 0xb5, 0xf6, 0xf3, 0xd2, 0xf6, 0x91, 0x3f, 0xd1, 0xbe,
+	0xe8, 0x2a, 0xff, 0x6e, 0x9f, 0xac, 0x73, 0xb8, 0xd9, 0xa6, 0x07, 0x8e,
+	0x48, 0x66, 0x65, 0x29, 0xf4, 0xe8, 0x76, 0xc5, 0x68, 0x2a, 0x51, 0x26,
+	0xb1, 0x3d, 0x2d, 0xef, 0x71, 0x15, 0xe2, 0x79, 0x72, 0x02, 0x57, 0x48,
+	0xd7, 0xbe, 0x4d, 0xdb, 0x59, 0x42, 0x8c, 0x39, 0x63, 0x7e, 0x1a, 0x71,
+	0x4d, 0xf4, 0x57, 0x88, 0x57, 0xfb, 0xdd, 0x78, 0x37, 0xc4, 0x98, 0x6d,
+	0xef, 0xa1, 0xf6, 0xe0, 0x27, 0x09, 0x2f, 0xe7, 0xab, 0x36, 0x63, 0x38,
+	0xe6, 0x02, 0x55, 0xd9, 0x6b, 0x27, 0x12, 0x6d, 0xd8, 0x4f, 0x79, 0x5f,
+	0x49, 0x9c, 0xe7, 0xfc, 0xac, 0xa3, 0xfe, 0x45, 0xdf, 0xf1, 0x9c, 0xae,
+	0xbb, 0xa9, 0xeb, 0x99, 0x78, 0x31, 0xf1, 0x30, 0x9e, 0xa0, 0xfc, 0x8f,
+	0xf7, 0x1b, 0xd1, 0x39, 0xca, 0x31, 0x1c, 0x1a, 0x2a, 0x24, 0x7e, 0xbb,
+	0x71, 0x37, 0xb3, 0xe4, 0x49, 0xe9, 0x2b, 0x29, 0x6b, 0x93, 0x0a, 0xb9,
+	0xc7, 0x31, 0x8c, 0xf3, 0xde, 0x4f, 0xf8, 0x3b, 0xbc, 0xb0, 0x9c, 0x7d,
+	0x88, 0x7e, 0xfc, 0x76, 0x1e, 0xd0, 0x45, 0x7e, 0xb3, 0xbc, 0xfe, 0x98,
+	0xcd, 0x79, 0xba, 0x93, 0xad, 0xe8, 0xe9, 0x7f, 0x9f, 0x7c, 0x8e, 0x38,
+	0xe4, 0xad, 0xa7, 0xad, 0x67, 0xb0, 0x3d, 0xf5, 0xef, 0x55, 0x59, 0xee,
+	0xf9, 0x6a, 0x95, 0xec, 0xeb, 0x3d, 0x91, 0x28, 0xc4, 0x4b, 0xac, 0xb3,
+	0x36, 0xe4, 0xca, 0x3d, 0x2f, 0x39, 0x86, 0x5e, 0xe2, 0x6a, 0x8a, 0x7d,
+	0x24, 0xec, 0x36, 0xaa, 0x94, 0xbd, 0xf4, 0xc3, 0xf2, 0x85, 0x55, 0x4a,
+	0x92, 0xe7, 0x7d, 0xc9, 0x1f, 0xe2, 0xd9, 0x47, 0xb2, 0x3a, 0xdc, 0x6f,
+	0xb6, 0x61, 0x28, 0x75, 0x2a, 0xd7, 0xde, 0x8f, 0xa7, 0xbc, 0x9b, 0x26,
+	0xef, 0xba, 0xe4, 0xdf, 0x7b, 0xc9, 0x3e, 0xcf, 0x7a, 0x2a, 0x5d, 0x46,
+	0xde, 0x5c, 0x4c, 0x5b, 0x2b, 0x88, 0x79, 0x19, 0x4f, 0xdb, 0x16, 0x68,
+	0xd8, 0x75, 0xcd, 0x9c, 0x2a, 0x94, 0x69, 0xee, 0x5f, 0xd7, 0xbf, 0xcc,
+	0x7e, 0xca, 0x62, 0x15, 0x91, 0x8c, 0xbd, 0x07, 0x2a, 0x74, 0x4d, 0x35,
+	0x73, 0x68, 0x79, 0x2e, 0x1c, 0xc3, 0xdb, 0x89, 0xca, 0x58, 0x65, 0xa4,
+	0x9c, 0x78, 0x7b, 0x0e, 0xbd, 0xc3, 0xc4, 0x76, 0xf2, 0xe5, 0xd2, 0xbe,
+	0x4a, 0xb8, 0xed, 0x35, 0xbc, 0x2b, 0x30, 0x63, 0xf7, 0x2c, 0xf8, 0x76,
+	0xcf, 0x24, 0x5f, 0x61, 0x6e, 0x19, 0xb2, 0xac, 0x9f, 0x2f, 0xb4, 0xac,
+	0x2b, 0x79, 0x14, 0xf1, 0x38, 0x1b, 0x12, 0x3f, 0x8d, 0xa2, 0xd6, 0xf6,
+	0x57, 0x03, 0x75, 0xf6, 0xff, 0x46, 0xfa, 0x7a, 0x47, 0x68, 0xfe, 0xf8,
+	0xc3, 0xa1, 0xb9, 0xe3, 0xd5, 0x50, 0x07, 0xa6, 0xc1, 0xc1, 0xb6, 0x3e,
+	0x77, 0x8d, 0x85, 0x46, 0xfa, 0xf0, 0x1a, 0x53, 0xf8, 0x50, 0x1b, 0xf9,
+	0x50, 0x4f, 0xc8, 0x18, 0x3f, 0x82, 0x1b, 0xc9, 0x97, 0xdd, 0x03, 0x3e,
+	0xf6, 0x23, 0xf9, 0xb5, 0x33, 0x33, 0x9b, 0x3c, 0xfb, 0xd3, 0x0b, 0x85,
+	0x1b, 0xb5, 0x90, 0x1b, 0x1d, 0x45, 0xcb, 0xf8, 0x31, 0xdc, 0xca, 0x32,
+	0x1e, 0xe6, 0xfd, 0x7d, 0xe9, 0x1f, 0x92, 0x77, 0x58, 0x8c, 0x39, 0x19,
+	0xdc, 0xcc, 0xb6, 0x8b, 0x07, 0x9a, 0x70, 0xf7, 0xf8, 0x0a, 0xac, 0x1d,
+	0xb7, 0xb0, 0x3c, 0x34, 0x81, 0xe5, 0xe3, 0xe4, 0x9a, 0xe3, 0x79, 0x7f,
+	0x15, 0x9e, 0xb4, 0x82, 0x3c, 0x49, 0xe2, 0xd0, 0x2a, 0x7b, 0x1d, 0x4d,
+	0xa5, 0x1f, 0x36, 0x24, 0xe4, 0x9d, 0x9b, 0x38, 0x56, 0x8f, 0x0b, 0x56,
+	0x3f, 0x88, 0x4d, 0xe3, 0xb2, 0x2e, 0xfb, 0xf5, 0xd0, 0x9c, 0xf1, 0xd7,
+	0xd1, 0x30, 0x3e, 0x14, 0x9a, 0x37, 0x3e, 0x42, 0xb9, 0x13, 0x94, 0xad,
+	0x3f, 0x54, 0x33, 0x3e, 0x18, 0x0a, 0x8e, 0xef, 0x0d, 0x05, 0xc6, 0x9b,
+	0xb1, 0x75, 0x7c, 0x15, 0xb6, 0x8c, 0xb7, 0x63, 0xf3, 0xb8, 0xe0, 0xfc,
+	0x24, 0x96, 0x8d, 0x9f, 0xc1, 0xd2, 0xf1, 0x97, 0xd1, 0x38, 0x7e, 0x0a,
+	0x4b, 0xc6, 0x7f, 0x88, 0xa6, 0xf1, 0x1f, 0x73, 0x2c, 0xb2, 0xce, 0x2b,
+	0x6b, 0xbc, 0xf9, 0x67, 0x6a, 0xf9, 0xf7, 0x44, 0xf3, 0xdf, 0xd7, 0x70,
+	0x21, 0xaa, 0xbd, 0x81, 0xee, 0x3d, 0xf2, 0xbd, 0xc1, 0x5a, 0x6d, 0x93,
+	0xfd, 0xbe, 0xc1, 0xcb, 0xb2, 0x4f, 0x1d, 0x45, 0xc6, 0xe5, 0xef, 0xc5,
+	0xcb, 0x77, 0x31, 0xe4, 0x39, 0xe7, 0x24, 0xba, 0xd2, 0xe7, 0xad, 0xa8,
+	0x26, 0x65, 0xde, 0xc0, 0xe6, 0x3d, 0xf2, 0x3e, 0x71, 0x06, 0x5d, 0x49,
+	0x79, 0x0e, 0x2f, 0xef, 0xa0, 0xbf, 0x81, 0x2d, 0xa3, 0xb6, 0xaf, 0xa1,
+	0x71, 0x48, 0xde, 0x89, 0x69, 0xc3, 0x75, 0xc9, 0x8c, 0xbd, 0x56, 0x5e,
+	0x66, 0xe0, 0xef, 0x67, 0xe0, 0x41, 0xe6, 0x04, 0x05, 0xe4, 0xfd, 0xc5,
+	0xe8, 0x7c, 0x24, 0x6e, 0x15, 0x1a, 0x1e, 0xcc, 0x88, 0x18, 0x99, 0x77,
+	0x1d, 0xc5, 0xe8, 0xe0, 0xb5, 0xfb, 0x76, 0xc2, 0xef, 0x33, 0x44, 0xf7,
+	0x81, 0xd8, 0x28, 0x63, 0xec, 0x86, 0x7d, 0x19, 0xf2, 0x8b, 0x0e, 0xf8,
+	0xf9, 0x7f, 0x7b, 0x52, 0xf6, 0x21, 0x6d, 0x42, 0x74, 0x9f, 0xe8, 0xb0,
+	0x99, 0x3a, 0x9c, 0x64, 0xdc, 0x90, 0x67, 0x38, 0x46, 0x70, 0x2b, 0x64,
+	0x9d, 0x52, 0xc5, 0xf7, 0x06, 0xe5, 0x79, 0x83, 0xde, 0xf1, 0x25, 0xfa,
+	0xf4, 0x87, 0xca, 0x0f, 0x51, 0x76, 0x40, 0xf8, 0xd2, 0x04, 0x7a, 0x84,
+	0x6f, 0x47, 0x14, 0x23, 0x15, 0x38, 0x0b, 0xcf, 0x01, 0xc1, 0x5d, 0x27,
+	0x4a, 0xc6, 0xe4, 0xfb, 0x38, 0x40, 0x31, 0xf3, 0x12, 0x1c, 0x20, 0xa7,
+	0x3d, 0x70, 0x0a, 0xd8, 0x27, 0xeb, 0x56, 0xaf, 0x61, 0x72, 0x48, 0xe6,
+	0xad, 0x8d, 0xf3, 0x26, 0x7e, 0xf8, 0x7d, 0x0c, 0x0f, 0x79, 0xe8, 0xe3,
+	0x13, 0x1c, 0xc7, 0xeb, 0x78, 0x74, 0x8f, 0x3c, 0x17, 0x99, 0x89, 0x36,
+	0xd6, 0x3b, 0xc1, 0x3c, 0xbf, 0x75, 0xcc, 0xe4, 0x78, 0x56, 0xa1, 0xf3,
+	0xc0, 0x17, 0x78, 0x4c, 0xc3, 0x43, 0x07, 0xd6, 0x71, 0x8c, 0x71, 0x74,
+	0x8c, 0x75, 0xf3, 0x68, 0xc5, 0xc6, 0x9d, 0x26, 0xb9, 0xa0, 0xd8, 0xb4,
+	0x46, 0x3f, 0x6b, 0xe5, 0x98, 0xa4, 0x8f, 0xd5, 0xf8, 0x19, 0x31, 0xa6,
+	0x29, 0xb4, 0x1a, 0xe7, 0x6c, 0xbf, 0x5b, 0x8d, 0x2d, 0xfd, 0x46, 0xf0,
+	0x24, 0x56, 0x63, 0x33, 0xcf, 0x1f, 0xa5, 0xef, 0xcf, 0x21, 0x17, 0xbc,
+	0x93, 0xbe, 0xbd, 0x78, 0x78, 0x42, 0xbe, 0x9d, 0x80, 0xbe, 0x5d, 0x32,
+	0x1f, 0x6d, 0xf0, 0x8d, 0x65, 0x50, 0x3e, 0xc6, 0xec, 0x79, 0x27, 0xee,
+	0x2a, 0x43, 0x39, 0xbe, 0x11, 0x92, 0x3d, 0x0b, 0x3f, 0x40, 0xf1, 0x3e,
+	0x91, 0xf5, 0x87, 0x6c, 0xfb, 0x1c, 0x73, 0xf1, 0x53, 0x9c, 0x83, 0xfc,
+	0xb3, 0xf1, 0x5f, 0xe0, 0x60, 0x6a, 0x92, 0xb8, 0x7a, 0x9a, 0xc7, 0xe5,
+	0xcf, 0xa5, 0xbd, 0x76, 0x8e, 0x92, 0xdd, 0xff, 0xed, 0xc4, 0x8c, 0x3e,
+	0x59, 0xdf, 0x6d, 0x86, 0x2f, 0x29, 0x7c, 0x27, 0xb3, 0x8d, 0xf9, 0x4a,
+	0x7b, 0xd8, 0xe6, 0x3f, 0x46, 0x8c, 0xbc, 0xa7, 0xf9, 0xdb, 0x8a, 0x87,
+	0xbc, 0x27, 0x88, 0x15, 0x69, 0x3d, 0x7a, 0x33, 0xf5, 0x5b, 0xf4, 0xc8,
+	0x8f, 0xe0, 0x7c, 0xc4, 0x89, 0x42, 0xe6, 0x37, 0xa1, 0x90, 0xe8, 0x59,
+	0xde, 0x95, 0xcd, 0xe8, 0x85, 0xc4, 0xcc, 0x82, 0xbe, 0x0c, 0xe7, 0x27,
+	0x33, 0xbf, 0x00, 0x7e, 0xce, 0xcd, 0x0d, 0x68, 0xeb, 0x8f, 0x72, 0x6e,
+	0x3e, 0x45, 0x1b, 0x9b, 0xa0, 0xbd, 0x48, 0x4e, 0xf4, 0x32, 0x65, 0x74,
+	0xe5, 0xbe, 0xc9, 0x93, 0xd1, 0x9d, 0xd0, 0x4d, 0xbf, 0x5a, 0x95, 0x7d,
+	0x27, 0x05, 0xf6, 0xb3, 0xe7, 0x30, 0xf0, 0x06, 0x6d, 0x33, 0xcf, 0x67,
+	0x2c, 0xab, 0x9d, 0xf6, 0xd5, 0x3f, 0x2a, 0xbe, 0xb2, 0xb4, 0x2a, 0xfb,
+	0xbe, 0xee, 0x54, 0xae, 0x93, 0xaf, 0xeb, 0x20, 0x36, 0xe6, 0xef, 0xff,
+	0x08, 0x77, 0x32, 0x7e, 0x9d, 0x59, 0x78, 0x2a, 0x67, 0xf3, 0xd3, 0xab,
+	0xb3, 0xf8, 0xf5, 0x49, 0xdf, 0x0b, 0xfa, 0x2b, 0xfb, 0xdb, 0x3b, 0xd9,
+	0x6f, 0x1f, 0x01, 0xcf, 0x26, 0x0a, 0xe4, 0x29, 0xc1, 0x62, 0x17, 0x54,
+	0xaf, 0x0b, 0x85, 0x8c, 0x01, 0xd5, 0xd8, 0xe4, 0xb5, 0x70, 0xa3, 0x59,
+	0x80, 0x43, 0x75, 0xb7, 0x00, 0x15, 0xf1, 0x16, 0x97, 0xfd, 0x4e, 0xde,
+	0xef, 0xbf, 0xf4, 0x87, 0xef, 0xe4, 0x9d, 0xb1, 0xf3, 0xe1, 0x52, 0xe3,
+	0x76, 0xbc, 0x62, 0xc7, 0x09, 0x05, 0x25, 0x73, 0x65, 0x5d, 0xd2, 0x8f,
+	0x17, 0x8d, 0x5a, 0x7f, 0x85, 0x3c, 0x6f, 0x52, 0xce, 0x5a, 0x71, 0xaf,
+	0xbc, 0x87, 0xf7, 0xc7, 0xf6, 0x8f, 0x3f, 0x87, 0xad, 0xbb, 0xc2, 0x90,
+	0xf7, 0x3b, 0x9c, 0x46, 0xa1, 0x37, 0x2b, 0xbf, 0xc8, 0x26, 0xeb, 0x44,
+	0xb7, 0x71, 0x1c, 0x67, 0xe8, 0x8b, 0x67, 0xec, 0x75, 0x2a, 0xb7, 0xf1,
+	0xd7, 0x08, 0x56, 0xe4, 0xc7, 0x2f, 0x39, 0x8d, 0x92, 0xd5, 0x41, 0xf6,
+	0xfd, 0xda, 0x6a, 0xc1, 0xfe, 0x2d, 0xc9, 0x33, 0xf6, 0x9a, 0xac, 0xcb,
+	0xf8, 0x0f, 0xeb, 0x2d, 0x6f, 0x25, 0xcb, 0x3e, 0x95, 0xbb, 0x3f, 0x29,
+	0xeb, 0x38, 0xa6, 0x7c, 0xbb, 0xca, 0x69, 0xd7, 0x11, 0xbd, 0x5f, 0xac,
+	0xb3, 0x89, 0xbc, 0x7a, 0xb6, 0x71, 0xca, 0xea, 0xf4, 0xca, 0x18, 0xd6,
+	0x5c, 0x56, 0x47, 0xd6, 0x08, 0x34, 0xe9, 0x37, 0x2c, 0x63, 0xee, 0x4a,
+	0xff, 0x61, 0x9f, 0xb2, 0x7e, 0x5b, 0x60, 0x94, 0xe0, 0x6c, 0x45, 0x76,
+	0x4d, 0xe5, 0xa2, 0x8c, 0xed, 0xd5, 0xb2, 0xef, 0xae, 0xd0, 0x3e, 0xb7,
+	0xfb, 0x35, 0x2f, 0xd6, 0x7b, 0x30, 0x37, 0xde, 0x4a, 0xfb, 0x9d, 0x9a,
+	0x47, 0x6d, 0xae, 0xe3, 0x98, 0x32, 0xee, 0xdf, 0x78, 0x2f, 0xed, 0xe7,
+	0xf3, 0xb9, 0x7e, 0x45, 0x1e, 0xef, 0x94, 0x3e, 0x44, 0xae, 0xde, 0x5c,
+	0x1d, 0x3d, 0x1c, 0xb5, 0xfb, 0x57, 0x11, 0xde, 0x93, 0xef, 0xd3, 0xb2,
+	0x0a, 0x16, 0xe6, 0xdb, 0xc8, 0xd0, 0x0f, 0xad, 0xce, 0x42, 0xc6, 0xab,
+	0xb3, 0xf5, 0x0f, 0x62, 0x73, 0x42, 0xf4, 0x2c, 0xdf, 0x70, 0x25, 0x2e,
+	0xdb, 0xfc, 0xcb, 0xc5, 0x5c, 0xf6, 0x1a, 0x0c, 0x69, 0x71, 0xec, 0xaf,
+	0x93, 0x77, 0xc8, 0x5c, 0xf4, 0x85, 0x38, 0x71, 0xb0, 0x90, 0x38, 0x1a,
+	0xb7, 0xf7, 0x94, 0x1c, 0x34, 0xf5, 0xe8, 0xb3, 0xf2, 0x8d, 0xb2, 0xab,
+	0xec, 0xb5, 0xa7, 0xa6, 0x21, 0xc8, 0xf5, 0xfc, 0x7a, 0x52, 0xfe, 0xaf,
+	0x88, 0xb6, 0x23, 0x72, 0x89, 0x0d, 0x50, 0xba, 0x84, 0xbc, 0xeb, 0x54,
+	0x1b, 0x23, 0x67, 0xc4, 0x2b, 0x29, 0xd9, 0x7f, 0xf0, 0x5b, 0x2b, 0x5e,
+	0x2d, 0xfb, 0x1c, 0xa7, 0xd6, 0x29, 0x20, 0x97, 0x0b, 0x84, 0xcb, 0x94,
+	0xfc, 0xfb, 0x4e, 0x17, 0xff, 0x6e, 0xa5, 0xcd, 0x9c, 0xb3, 0xdf, 0x51,
+	0x93, 0xb3, 0x08, 0x1a, 0x92, 0xf2, 0xad, 0x52, 0x7d, 0x62, 0x39, 0x6a,
+	0x33, 0x35, 0x0e, 0x67, 0x8e, 0x93, 0x84, 0xb1, 0x82, 0x76, 0xb3, 0x25,
+	0x10, 0xb6, 0xdf, 0xc5, 0x5a, 0x96, 0xac, 0x09, 0x3e, 0xce, 0x1c, 0xfa,
+	0x1d, 0x96, 0xbf, 0x25, 0xfd, 0x3d, 0x6b, 0xc8, 0x2b, 0x63, 0xca, 0x63,
+	0xc3, 0x29, 0xfa, 0x06, 0xf5, 0x18, 0x11, 0xff, 0xf0, 0xa0, 0x22, 0x12,
+	0xa6, 0xff, 0x4a, 0x4c, 0x97, 0xf7, 0xb8, 0xf4, 0xbd, 0x71, 0x98, 0xc4,
+	0xfc, 0x1e, 0xda, 0x91, 0xec, 0x5b, 0xd6, 0xfd, 0x2b, 0x19, 0x5b, 0x8e,
+	0x5f, 0x78, 0xc6, 0x2f, 0x1c, 0xe0, 0xd9, 0xea, 0xdc, 0xde, 0x66, 0xf7,
+	0x6c, 0xc6, 0x3c, 0xcb, 0x7e, 0x6e, 0xdf, 0x66, 0x63, 0x8a, 0x66, 0xe8,
+	0x87, 0x7e, 0xe5, 0xe8, 0xc4, 0xd3, 0x0b, 0x8c, 0x8e, 0xc3, 0x6a, 0x66,
+	0xc8, 0x47, 0x7c, 0xb9, 0xde, 0x11, 0xdd, 0xc9, 0xff, 0xfe, 0xd7, 0xec,
+	0x6f, 0xab, 0x48, 0x5d, 0x3d, 0xb8, 0x4a, 0x95, 0xfd, 0x40, 0xcd, 0x18,
+	0xeb, 0x95, 0x77, 0x06, 0xf4, 0x96, 0xa7, 0x94, 0x4e, 0x6c, 0x08, 0x19,
+	0xcd, 0xed, 0x8a, 0xde, 0xf4, 0x0f, 0x8a, 0xee, 0x0f, 0x29, 0x52, 0x2e,
+	0xc8, 0xbc, 0xeb, 0x62, 0x3c, 0x75, 0xb1, 0x8f, 0x03, 0x09, 0x3d, 0x5c,
+	0xc5, 0xb2, 0x67, 0x4d, 0xc3, 0xf7, 0x3e, 0xdb, 0xfc, 0x57, 0x1e, 0x3b,
+	0xed, 0xf7, 0xc4, 0xa5, 0x7c, 0x74, 0xbe, 0xcb, 0xfe, 0xbe, 0x69, 0x0b,
+	0xe3, 0xae, 0x7c, 0x23, 0x38, 0x06, 0xad, 0x6f, 0x26, 0x4d, 0x4c, 0xef,
+	0xb9, 0x0d, 0xb2, 0xe7, 0xa0, 0x89, 0x09, 0xba, 0x07, 0xde, 0x48, 0x27,
+	0xe6, 0x2e, 0x30, 0x7c, 0x8b, 0x54, 0xbb, 0x7e, 0x30, 0xaa, 0x4a, 0x7d,
+	0xdd, 0x3f, 0x08, 0x69, 0x23, 0x63, 0x69, 0x73, 0xcb, 0xed, 0x3a, 0x0b,
+	0xd4, 0xcf, 0xc0, 0x75, 0xf5, 0xaf, 0xe5, 0x5b, 0x46, 0x5a, 0xa5, 0x21,
+	0x75, 0xe2, 0x3b, 0x35, 0xfc, 0xb1, 0x7a, 0x82, 0x2b, 0xbf, 0xb2, 0x30,
+	0x4d, 0xea, 0xc9, 0x9e, 0xb1, 0x3b, 0x70, 0xaf, 0xfd, 0x3d, 0x16, 0xf1,
+	0x47, 0x3d, 0xfa, 0x15, 0xf2, 0xcf, 0x62, 0x45, 0xb8, 0xa7, 0xf0, 0x84,
+	0x56, 0x74, 0x33, 0x8e, 0x69, 0x21, 0xbd, 0xe7, 0x0a, 0xd5, 0x83, 0xc2,
+	0xc8, 0x63, 0xb2, 0x6f, 0x66, 0xef, 0x3c, 0x35, 0xbb, 0xbf, 0x26, 0xc6,
+	0x76, 0x8f, 0xff, 0xd1, 0xe7, 0xb8, 0xec, 0xab, 0xd8, 0x94, 0xf7, 0x5b,
+	0xec, 0x35, 0xc5, 0xd6, 0x84, 0x23, 0xb7, 0x5f, 0x30, 0x3f, 0xb7, 0x1a,
+	0xda, 0xc8, 0xf5, 0xd7, 0xc8, 0x37, 0x31, 0x39, 0xd6, 0xb5, 0x09, 0x59,
+	0x4d, 0xfa, 0xff, 0x00, 0x85, 0x57, 0x0f, 0xe7, 0xe8, 0x59, 0x00, 0x00,
+	0x00 };
+
+static const u32 bnx2_CP_b06FwData[(0x84/4) + 1] = {
+	0x00000000, 0x0000001b, 0x0000000f, 0x0000000a, 0x00000008, 0x00000006,
+	0x00000005, 0x00000005, 0x00000004, 0x00000004, 0x00000003, 0x00000003,
+	0x00000003, 0x00000003, 0x00000003, 0x00000002, 0x00000002, 0x00000002,
+	0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002,
+	0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002,
+	0x00000001, 0x00000001, 0x00000001, 0x00000000 };
+static const u32 bnx2_CP_b06FwRodata[(0x130/4) + 1] = {
+	0x08001f1c, 0x08001da8, 0x08001ef8, 0x08001ed4, 0x08001eb0, 0x08001e8c,
+	0x08001e64, 0x08001e3c, 0x08001e10, 0x08002014, 0x08002004, 0x08001dc4,
+	0x08001dc4, 0x08001dc4, 0x08001f44, 0x08001f44, 0x08001dc4, 0x08001dc4,
+	0x08001ff4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001fe4,
+	0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4,
+	0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4,
+	0x08001dc4, 0x08001dc4, 0x08001fd4, 0x08001dc4, 0x08001dc4, 0x08001fc4,
+	0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4,
+	0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4,
+	0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001fac,
+	0x08001dc4, 0x08001dc4, 0x08001f9c, 0x08001f8c, 0x080031e8, 0x080031f0,
+	0x080031b8, 0x080031c4, 0x080031d0, 0x080031dc, 0x08005644, 0x08005604,
+	0x080055d0, 0x080055a4, 0x08005580, 0x0800553c, 0x00000000 };
+
+static struct fw_info bnx2_cp_fw_06 = {
+	/* Firmware version: 4.0.5 */
+	.ver_major			= 0x4,
+	.ver_minor			= 0x0,
+	.ver_fix			= 0x5,
+
+	.start_addr			= 0x08000078,
+
+	.text_addr			= 0x08000000,
+	.text_len			= 0x59e4,
+	.text_index			= 0x0,
+	.gz_text			= bnx2_CP_b06FwText,
+	.gz_text_len			= sizeof(bnx2_CP_b06FwText),
+
+	.data_addr			= 0x08005b40,
+	.data_len			= 0x84,
+	.data_index			= 0x0,
+	.data				= bnx2_CP_b06FwData,
+
+	.sbss_addr			= 0x08005bc4,
+	.sbss_len			= 0xe9,
+	.sbss_index			= 0x0,
+
+	.bss_addr			= 0x08005cb0,
+	.bss_len			= 0x5d8,
+	.bss_index			= 0x0,
+
+	.rodata_addr			= 0x080059e4,
+	.rodata_len			= 0x130,
+	.rodata_index			= 0x0,
+	.rodata				= bnx2_CP_b06FwRodata,
+};
+
 static u8 bnx2_RXP_b06FwText[] = {
-/*	0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
-							0xec, 0x5c, 0x6f, 0x6c,
-	0x1c, 0xc7, 0x75, 0x7f, 0x3b, 0xbb, 0xa4, 0x4e, 0xd4, 0x91, 0x5c, 0x1e,
-	0x4f, 0xf4, 0x49, 0x66, 0x94, 0x5d, 0x71, 0x25, 0x5e, 0x2d, 0xc6, 0x5d,
-	0x31, 0x57, 0x9b, 0x08, 0xce, 0xf1, 0x79, 0xef, 0x64, 0xb1, 0x86, 0x0a,
-	0x51, 0x0d, 0x1d, 0x1b, 0x85, 0x6b, 0xb0, 0x47, 0x39, 0xae, 0xdb, 0x7e,
-	0x90, 0x65, 0x1b, 0x30, 0xda, 0x10, 0xbe, 0x1c, 0xe9, 0x46, 0x75, 0x2f,
-	0xdc, 0x8b, 0xc4, 0x98, 0x06, 0xfa, 0x07, 0x57, 0x92, 0xfa, 0x83, 0xe0,
-	0xa0, 0x93, 0xe2, 0x26, 0xf5, 0x17, 0x57, 0x84, 0x2a, 0xc7, 0xf9, 0xe0,
-	0x02, 0x4e, 0x63, 0x20, 0x06, 0xea, 0x16, 0xaa, 0xec, 0xd8, 0x46, 0x81,
-	0xa2, 0x42, 0x1c, 0xd8, 0x46, 0xfc, 0x67, 0xfb, 0x7b, 0x33, 0xbb, 0xd4,
-	0x91, 0x96, 0x6d, 0xa0, 0x1f, 0xfa, 0xa5, 0x3b, 0xc0, 0x61, 0x67, 0x66,
-	0xe7, 0xbd, 0x79, 0xf3, 0xfe, 0xbf, 0x59, 0x4a, 0x7f, 0x90, 0xa4, 0x2e,
-	0x0a, 0x5b, 0x37, 0x7e, 0xd6, 0x91, 0xc7, 0x8f, 0xde, 0x3c, 0x76, 0xf3,
-	0x28, 0xd1, 0x97, 0x47, 0xf5, 0x1b, 0x12, 0x22, 0x9a, 0x8f, 0x5b, 0xdc,
-	0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2,
-	0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16,
-	0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7,
-	0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8,
-	0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5,
-	0x2d, 0x6e, 0x71, 0xfb, 0xff, 0xde, 0x74, 0x22, 0x93, 0x9f, 0xdd, 0xe1,
-	0x8f, 0x12, 0x22, 0xbf, 0xfa, 0x90, 0xe7, 0x50, 0x42, 0xcf, 0xbf, 0x34,
-	0x33, 0xed, 0x10, 0x15, 0x9a, 0x7b, 0xac, 0x22, 0x7d, 0x14, 0x54, 0xd2,
-	0x06, 0xf1, 0xfc, 0x17, 0xf2, 0x1f, 0x3e, 0xf1, 0xfc, 0xad, 0xf6, 0xd5,
-	0x86, 0x4e, 0x09, 0x33, 0x3f, 0xb7, 0xd7, 0xdc, 0x4d, 0x89, 0x41, 0xc0,
-	0xfc, 0xf5, 0xf0, 0x7f, 0xf4, 0x50, 0x0f, 0x5d, 0xc3, 0xe3, 0x24, 0xe8,
-	0xb2, 0xfe, 0x9c, 0xe6, 0xb5, 0x82, 0xe0, 0xa4, 0x1b, 0x04, 0x3f, 0xc6,
-	0xef, 0x2d, 0x17, 0x63, 0xff, 0xe3, 0xa0, 0x60, 0xe8, 0x24, 0x9c, 0xbf,
-	0xd4, 0xbc, 0xe5, 0x2e, 0xaa, 0x2e, 0x1a, 0x34, 0xeb, 0xa7, 0xe9, 0x98,
-	0x5f, 0xd1, 0x4a, 0xad, 0x9a, 0xb6, 0xef, 0xf4, 0xbc, 0x76, 0xe7, 0xe9,
-	0x63, 0xda, 0xfe, 0xd3, 0x75, 0xcd, 0x3b, 0x4d, 0x15, 0xb1, 0x37, 0x49,
-	0x05, 0xf3, 0x8c, 0x56, 0x6c, 0x0d, 0x68, 0xde, 0x89, 0x0f, 0xc9, 0x73,
-	0x6d, 0xf3, 0xf7, 0xc8, 0x28, 0x80, 0x16, 0xf2, 0x6a, 0x41, 0xe0, 0xb9,
-	0x06, 0x15, 0xd2, 0x41, 0x20, 0xf2, 0xc1, 0x13, 0x5e, 0xce, 0x31, 0x85,
-	0x96, 0xa6, 0x6a, 0x6b, 0x00, 0x78, 0x93, 0x5a, 0x71, 0xd1, 0xd0, 0x4a,
-	0x7e, 0x70, 0xc1, 0x73, 0x69, 0x50, 0xa7, 0x20, 0x98, 0x73, 0x77, 0x65,
-	0x0e, 0xd3, 0x29, 0xe0, 0x6d, 0x02, 0x1f, 0x99, 0x22, 0xcf, 0xf4, 0x31,
-	0x9d, 0x4c, 0x72, 0x45, 0x2b, 0x0e, 0x47, 0xf4, 0x91, 0xc5, 0xf4, 0x97,
-	0x57, 0x04, 0xe8, 0xdc, 0x42, 0xe5, 0x86, 0x49, 0x53, 0x2b, 0x1b, 0xd7,
-	0x5f, 0x0e, 0x9e, 0x1f, 0x36, 0xe9, 0x5c, 0xcb, 0xae, 0x54, 0x28, 0x41,
-	0x73, 0xbe, 0x45, 0x22, 0x4f, 0x05, 0x2f, 0x37, 0x48, 0x17, 0x5a, 0x19,
-	0xfa, 0x41, 0xcb, 0xc9, 0x54, 0x69, 0x13, 0x95, 0xd3, 0x69, 0x3a, 0xdf,
-	0x4a, 0xe3, 0x8c, 0xc1, 0x05, 0xe1, 0x38, 0x66, 0x15, 0x6b, 0xab, 0xad,
-	0x97, 0xf8, 0xdf, 0xbf, 0x98, 0xd3, 0x39, 0x09, 0x53, 0x01, 0xdd, 0xe1,
-	0x5a, 0x3e, 0x87, 0x5c, 0x2b, 0xcf, 0xa2, 0xd6, 0x52, 0x65, 0x3a, 0x87,
-	0xb9, 0xd6, 0x1d, 0x6b, 0xfc, 0x2d, 0xa4, 0xf9, 0x69, 0x52, 0xd5, 0xef,
-	0x00, 0x6f, 0xb8, 0x3f, 0x88, 0xb3, 0xee, 0xd0, 0xbc, 0xc5, 0x7f, 0x65,
-	0xbc, 0x69, 0x41, 0x3b, 0x30, 0x1e, 0xc4, 0x98, 0xfb, 0xbb, 0x32, 0x65,
-	0x02, 0x8f, 0x5b, 0x49, 0x8c, 0x99, 0xce, 0x20, 0xd8, 0xef, 0x92, 0x59,
-	0x75, 0x7b, 0x01, 0x6b, 0x51, 0xd5, 0xed, 0x01, 0xbe, 0x0e, 0xea, 0x73,
-	0xf8, 0x7c, 0xbc, 0xe7, 0x66, 0xcc, 0x07, 0xdd, 0x7a, 0x3e, 0x08, 0xa6,
-	0x73, 0xd4, 0xa3, 0xe6, 0xf6, 0x48, 0x1c, 0x53, 0x13, 0x1a, 0xd6, 0xbd,
-	0xc3, 0x7b, 0x24, 0x52, 0x79, 0xee, 0xf3, 0x33, 0x47, 0xde, 0xfc, 0x8e,
-	0x90, 0xa6, 0x0c, 0x68, 0xba, 0x31, 0xec, 0x43, 0x0e, 0x3e, 0xf8, 0xe1,
-	0xde, 0x80, 0xb1, 0xf6, 0x45, 0xe0, 0xc9, 0x56, 0x89, 0xf7, 0xe8, 0xa7,
-	0xa5, 0x34, 0x89, 0x2b, 0x6e, 0x5f, 0xb8, 0xae, 0x07, 0xb4, 0x46, 0xfa,
-	0x30, 0x40, 0x73, 0x8b, 0xcc, 0xf3, 0x1a, 0x64, 0x24, 0x68, 0xe7, 0x2d,
-	0x15, 0xad, 0xd0, 0x3a, 0x86, 0xbe, 0x41, 0xd3, 0x4e, 0x70, 0x61, 0xce,
-	0x9d, 0xd7, 0x8a, 0xa7, 0x4f, 0x69, 0xa5, 0xd3, 0xcf, 0x69, 0xfb, 0x5a,
-	0x2f, 0x76, 0x53, 0x97, 0x8d, 0xd3, 0x27, 0xe8, 0x49, 0x5f, 0x23, 0xa6,
-	0x73, 0x09, 0x3c, 0x2c, 0x98, 0x15, 0x32, 0x9c, 0x1e, 0xed, 0x4e, 0xe0,
-	0xe9, 0x70, 0xfe, 0x2c, 0x49, 0x3d, 0x3a, 0x6d, 0x72, 0xa2, 0xb5, 0x69,
-	0xfa, 0x73, 0xd0, 0x74, 0xd1, 0xdd, 0xca, 0x7c, 0xeb, 0x55, 0x30, 0xa9,
-	0x90, 0x0e, 0xd6, 0x2f, 0x96, 0x9f, 0x6d, 0x7a, 0xba, 0xa0, 0xd2, 0xc2,
-	0x5f, 0xf4, 0x57, 0x47, 0xb6, 0xf0, 0x3a, 0xd8, 0xc2, 0xd5, 0x87, 0xa6,
-	0x1d, 0xaf, 0xcf, 0xa0, 0x8a, 0x29, 0xc8, 0x36, 0x8b, 0xf4, 0x45, 0x9a,
-	0x73, 0x89, 0x8a, 0x35, 0xec, 0xeb, 0x18, 0xe0, 0x8f, 0x03, 0xfe, 0xec,
-	0xaa, 0xe8, 0xe2, 0x1e, 0xa0, 0xa9, 0x68, 0x46, 0xc8, 0xcb, 0x25, 0xba,
-	0x4b, 0xc2, 0x8b, 0xbc, 0x0b, 0x5d, 0xed, 0xe2, 0x3e, 0xf6, 0x4e, 0xc8,
-	0xbd, 0xf5, 0xbc, 0x93, 0x59, 0x26, 0xd2, 0x44, 0x7e, 0x0f, 0xf0, 0xb1,
-	0x0e, 0xf3, 0xba, 0x79, 0xd0, 0xc9, 0xf4, 0x73, 0xdf, 0x01, 0x4c, 0x02,
-	0xfa, 0xde, 0xdd, 0x46, 0x2b, 0xe8, 0x49, 0x33, 0xbf, 0x99, 0x7f, 0xf2,
-	0xac, 0xda, 0xb5, 0xb3, 0x7e, 0x10, 0x0c, 0x8f, 0x1a, 0xf4, 0x63, 0x79,
-	0x66, 0xb6, 0x37, 0x5e, 0x97, 0x0e, 0xf5, 0x23, 0x01, 0x9d, 0x22, 0xad,
-	0xec, 0x9a, 0x6b, 0xb8, 0xca, 0x44, 0x42, 0xcf, 0x27, 0xa9, 0x28, 0xe9,
-	0x1b, 0xc3, 0x5e, 0x6c, 0x87, 0xb0, 0x27, 0x87, 0xcf, 0xc2, 0x73, 0x79,
-	0xd8, 0xbb, 0xcd, 0x7d, 0x2a, 0xd7, 0xd9, 0xf6, 0x99, 0xb6, 0x55, 0x5b,
-	0xfe, 0xd3, 0x2c, 0x89, 0x4f, 0x0c, 0xe8, 0xd4, 0x4b, 0x13, 0xee, 0x87,
-	0x81, 0xd8, 0x8d, 0xf7, 0x23, 0x19, 0xd0, 0x66, 0x5b, 0xb0, 0xca, 0x94,
-	0x4e, 0x1a, 0xe8, 0xde, 0x93, 0x31, 0xc9, 0xc1, 0xd9, 0xc0, 0xdf, 0x89,
-	0x55, 0x30, 0xff, 0xd3, 0xe8, 0x54, 0x78, 0x41, 0x66, 0xc1, 0x03, 0x8d,
-	0x9e, 0xfb, 0x65, 0xc9, 0x33, 0x13, 0xe7, 0xd7, 0xe7, 0x99, 0xbf, 0x5d,
-	0xb0, 0x0b, 0x8d, 0xca, 0x2e, 0xe3, 0x8e, 0x70, 0x08, 0x1a, 0xbe, 0xa5,
-	0x1d, 0x47, 0x24, 0x5f, 0xd6, 0x5d, 0x83, 0x46, 0x47, 0x79, 0x2d, 0xaf,
-	0xe3, 0xf5, 0xf6, 0x98, 0x25, 0x3e, 0x08, 0xf6, 0xae, 0xdb, 0xd3, 0x21,
-	0x31, 0x0f, 0x9a, 0x95, 0x2c, 0xc0, 0xc3, 0xcf, 0x5b, 0xcb, 0x72, 0xd8,
-	0xc8, 0x6f, 0x5e, 0xdb, 0xbe, 0x0e, 0xfa, 0x3c, 0xc0, 0x34, 0x9c, 0x4c,
-	0x2a, 0x3b, 0x8d, 0x68, 0x8a, 0x64, 0xa9, 0x85, 0x38, 0x3e, 0xeb, 0x1c,
-	0xbc, 0x1e, 0xfe, 0xc3, 0x87, 0xff, 0x80, 0x4f, 0x3c, 0xef, 0xc3, 0xbf,
-	0xf8, 0xec, 0x6f, 0x2c, 0x7a, 0x7e, 0x18, 0xfe, 0xf1, 0x9a, 0x7f, 0x42,
-	0x1b, 0x47, 0x5f, 0x90, 0x0e, 0xff, 0x34, 0xdb, 0x10, 0xb0, 0x73, 0xf8,
-	0x8a, 0x15, 0x9e, 0x83, 0x5f, 0x58, 0x29, 0xe1, 0xe9, 0x50, 0xb5, 0xc9,
-	0x7a, 0x18, 0xf9, 0x61, 0xf6, 0x57, 0x19, 0xf8, 0x26, 0xf6, 0x47, 0xec,
-	0xb7, 0x78, 0x6d, 0x10, 0x94, 0x5c, 0x86, 0x0d, 0x20, 0x47, 0xb6, 0xbb,
-	0x24, 0x89, 0x54, 0x45, 0x3b, 0x34, 0x0c, 0x7b, 0xbc, 0x89, 0x7d, 0x0b,
-	0xdb, 0xe5, 0x8d, 0x44, 0x9d, 0xbc, 0xdf, 0xaf, 0xbb, 0xd5, 0xbf, 0xd9,
-	0xdb, 0x84, 0x35, 0xf2, 0xd9, 0xa3, 0xc6, 0x66, 0xe8, 0x97, 0xf8, 0xbd,
-	0x6d, 0x15, 0x68, 0x57, 0x38, 0xe6, 0xfe, 0x1a, 0xbd, 0xae, 0xb8, 0x25,
-	0x41, 0x3b, 0x4f, 0x29, 0x7f, 0xba, 0x73, 0x09, 0x9a, 0x71, 0x4a, 0xd1,
-	0xb8, 0xf3, 0x6c, 0xe4, 0x57, 0x93, 0xc0, 0x07, 0xfa, 0xfc, 0xb5, 0x18,
-	0x82, 0xf6, 0x9e, 0x06, 0xd3, 0xc2, 0xdc, 0x46, 0x5e, 0xb0, 0x2f, 0x67,
-	0xfb, 0x34, 0xdb, 0xed, 0x73, 0x2f, 0xec, 0xd3, 0xed, 0x24, 0xdb, 0xfd,
-	0x27, 0xd8, 0xe7, 0xb7, 0x5d, 0x0d, 0xbc, 0x21, 0xba, 0x54, 0xcb, 0xc0,
-	0x3f, 0x18, 0x99, 0xd7, 0x69, 0x97, 0x35, 0x0b, 0xbd, 0x3c, 0xc9, 0x73,
-	0x4d, 0xcc, 0x49, 0x3f, 0xae, 0xfc, 0xc7, 0x65, 0xfd, 0xbb, 0xa0, 0x2b,
-	0x08, 0x66, 0x81, 0xb3, 0x3c, 0xa2, 0x87, 0xb6, 0x18, 0xcd, 0x5f, 0x45,
-	0x3c, 0xf4, 0x7e, 0x43, 0xa7, 0x4a, 0xb6, 0x83, 0xec, 0xec, 0x12, 0x70,
-	0x4f, 0xbb, 0xca, 0xee, 0xd9, 0x36, 0x96, 0x81, 0x7f, 0xce, 0x1f, 0x86,
-	0x5f, 0x60, 0xbb, 0x01, 0x5d, 0xc0, 0xbf, 0x0c, 0xfc, 0x73, 0xad, 0x0e,
-	0xfa, 0x96, 0x11, 0xc5, 0xd9, 0xe8, 0x3c, 0xdb, 0xb0, 0x2c, 0xda, 0xf7,
-	0x08, 0xdd, 0xe5, 0xa7, 0xe0, 0x73, 0xd8, 0x27, 0x57, 0xb3, 0xb0, 0x2b,
-	0xad, 0xea, 0xf2, 0xde, 0x3a, 0x2d, 0xaf, 0xad, 0xa1, 0x42, 0x55, 0xd9,
-	0x6c, 0xc1, 0x1b, 0xae, 0x64, 0x74, 0xe9, 0x7b, 0x88, 0xee, 0x84, 0xad,
-	0x2e, 0x3b, 0x3c, 0xe6, 0x79, 0x35, 0x37, 0x5e, 0x1b, 0xd0, 0x8a, 0xec,
-	0xbf, 0x86, 0x3f, 0x04, 0x7d, 0x6a, 0xee, 0xb7, 0x6b, 0x0f, 0xb1, 0x8c,
-	0x70, 0x16, 0xb2, 0xaa, 0xee, 0x7f, 0x06, 0xd0, 0xdf, 0x75, 0x30, 0xd7,
-	0xc7, 0x63, 0x8f, 0x2b, 0x9d, 0x25, 0x6d, 0xbf, 0x23, 0x06, 0x3a, 0x43,
-	0x9f, 0xb7, 0x1f, 0x93, 0xfb, 0x6a, 0xd5, 0xfe, 0x4e, 0xfa, 0x50, 0xe7,
-	0x18, 0x7c, 0x85, 0xc8, 0xf0, 0x6a, 0xbb, 0xc1, 0x8f, 0x6a, 0x5f, 0xdb,
-	0x5c, 0xa2, 0x54, 0x0b, 0xe8, 0xa2, 0xab, 0x60, 0x30, 0x4e, 0x16, 0x6b,
-	0x62, 0x20, 0x41, 0x6b, 0x63, 0x93, 0x61, 0x56, 0x68, 0x77, 0x76, 0x99,
-	0x24, 0x6c, 0x7f, 0xe2, 0x1a, 0x6c, 0xba, 0x54, 0xab, 0xf6, 0xb5, 0x8d,
-	0x33, 0x45, 0xe0, 0x12, 0x7b, 0xd7, 0x60, 0x07, 0xaf, 0xc1, 0x6e, 0x25,
-	0xab, 0x8f, 0xe1, 0xc5, 0xc0, 0xe6, 0x6b, 0xb8, 0xad, 0x90, 0x9e, 0xfe,
-	0xcd, 0xd7, 0x70, 0x38, 0x8c, 0xb3, 0x6d, 0x9c, 0x65, 0x9c, 0x3b, 0xaf,
-	0xe1, 0x1c, 0x59, 0x4f, 0xcf, 0x11, 0x82, 0x0f, 0x4a, 0x74, 0xe6, 0x69,
-	0xef, 0xa5, 0xda, 0xd0, 0xc4, 0x5d, 0x84, 0xf8, 0x38, 0xb2, 0x29, 0xf4,
-	0xe1, 0xc6, 0x5e, 0x0f, 0xbc, 0x32, 0x88, 0x7d, 0xa2, 0x46, 0x55, 0xc8,
-	0xf9, 0x8f, 0x9a, 0xb4, 0xf7, 0x62, 0xd3, 0x08, 0x75, 0x89, 0x75, 0xe2,
-	0x6d, 0xd8, 0x58, 0x72, 0xca, 0x40, 0x0c, 0xbf, 0x20, 0x6d, 0x8c, 0x26,
-	0xaa, 0x35, 0xaa, 0x6c, 0xcf, 0x3f, 0x11, 0x40, 0x17, 0xa7, 0xe0, 0xd3,
-	0xc0, 0xe3, 0xe4, 0x98, 0x97, 0xc3, 0x7c, 0x93, 0x6d, 0x0b, 0x7e, 0x05,
-	0xb0, 0xd0, 0xb5, 0x84, 0x3e, 0xbf, 0xeb, 0x55, 0x4f, 0xe7, 0x7d, 0x2c,
-	0xe4, 0x5c, 0x89, 0x84, 0x98, 0xbf, 0x1a, 0xb0, 0x9e, 0x4d, 0x8f, 0x5c,
-	0x45, 0x8e, 0x63, 0x92, 0x37, 0x06, 0xff, 0x01, 0x7d, 0x9f, 0x6d, 0x11,
-	0x72, 0x82, 0x3f, 0xed, 0x55, 0x36, 0xf6, 0x9d, 0xad, 0xea, 0x49, 0x06,
-	0xfb, 0xf2, 0xe9, 0x1c, 0xe7, 0x0f, 0x9d, 0x09, 0x2f, 0x37, 0xbe, 0x4d,
-	0x3f, 0x7b, 0x60, 0x9b, 0x38, 0x5b, 0xd9, 0x26, 0x10, 0x03, 0x60, 0x53,
-	0xc2, 0xcb, 0xa1, 0x7f, 0x36, 0xb2, 0xa1, 0x0c, 0x6c, 0x88, 0x69, 0x65,
-	0x3a, 0x7f, 0x04, 0x7b, 0x95, 0xb4, 0xd2, 0x84, 0x0f, 0x9a, 0x46, 0x3f,
-	0x82, 0x9e, 0xe0, 0x2c, 0xf0, 0x81, 0x05, 0x70, 0x49, 0x8c, 0xfe, 0x2a,
-	0xb4, 0x67, 0xee, 0xbf, 0x1b, 0xa8, 0x78, 0x72, 0x30, 0xdc, 0xff, 0x17,
-	0xa1, 0x0f, 0x88, 0x70, 0x31, 0x9e, 0xac, 0x36, 0x81, 0x5c, 0x68, 0xa2,
-	0x65, 0x68, 0xec, 0xcf, 0x8b, 0x3e, 0xe7, 0x30, 0x9c, 0xbf, 0x3c, 0x1e,
-	0xfa, 0x45, 0xce, 0x5b, 0x92, 0x21, 0x4f, 0x73, 0x51, 0x5c, 0x94, 0xf6,
-	0x86, 0x18, 0x65, 0x95, 0x5d, 0x99, 0xd3, 0x68, 0xd3, 0xb9, 0x24, 0xd6,
-	0x61, 0xae, 0x85, 0x73, 0xc3, 0x2f, 0x21, 0x0f, 0xe2, 0xdc, 0x14, 0xeb,
-	0x3b, 0x43, 0x9b, 0xbf, 0x44, 0x65, 0xf8, 0x54, 0xc3, 0xe1, 0xf7, 0x5e,
-	0x2f, 0x75, 0x61, 0xdc, 0xc4, 0x5e, 0xf0, 0x13, 0xba, 0xe4, 0x33, 0x62,
-	0x41, 0xfa, 0x06, 0xce, 0xaf, 0xb0, 0xd6, 0xc2, 0x5a, 0xf6, 0xbb, 0xbc,
-	0xf6, 0x3c, 0xe8, 0xc0, 0xb8, 0xc9, 0x30, 0xec, 0xa3, 0x82, 0xf7, 0xbc,
-	0xdc, 0x1e, 0x73, 0x82, 0x12, 0x21, 0x5e, 0xab, 0x0d, 0xef, 0xc6, 0xb5,
-	0x9c, 0xd3, 0x04, 0x17, 0x74, 0x87, 0xf1, 0x47, 0x79, 0x18, 0xd1, 0xf4,
-	0x09, 0xe4, 0x71, 0x4e, 0x07, 0xe2, 0x14, 0x8f, 0x86, 0x4c, 0x75, 0xce,
-	0x08, 0xe6, 0x81, 0xfe, 0xf5, 0xe3, 0xbb, 0x53, 0xd7, 0xfc, 0x23, 0x5b,
-	0x17, 0x15, 0x10, 0x1f, 0xc0, 0x27, 0x6b, 0x8a, 0x73, 0xbf, 0x62, 0x53,
-	0xa2, 0xc4, 0xdc, 0x18, 0x7c, 0xa2, 0xca, 0xa3, 0x2e, 0xf8, 0x1b, 0xe5,
-	0x66, 0x82, 0xd7, 0x05, 0xf0, 0xd7, 0x82, 0xfe, 0x8c, 0x03, 0x96, 0x8e,
-	0x00, 0x07, 0xc7, 0x6a, 0x57, 0xe4, 0x53, 0x54, 0x36, 0x39, 0xa7, 0xe8,
-	0x64, 0xfa, 0x0a, 0x6c, 0xfb, 0x22, 0xbf, 0x19, 0x73, 0xdc, 0x7f, 0xac,
-	0x57, 0xc9, 0xab, 0x9b, 0xc7, 0x13, 0x22, 0xdf, 0xbb, 0x61, 0xfe, 0x9f,
-	0xbb, 0x15, 0x6d, 0x72, 0x8c, 0xf9, 0x7f, 0xdb, 0x30, 0xfe, 0xe3, 0xd4,
-	0xfa, 0xf1, 0xdd, 0xdb, 0x42, 0xfd, 0x43, 0xff, 0xf1, 0x90, 0x5e, 0xd0,
-	0xb6, 0x46, 0x6b, 0x94, 0x2b, 0x53, 0x5d, 0x20, 0x5f, 0xf4, 0x72, 0xbb,
-	0xac, 0x2a, 0x6c, 0xaa, 0xd4, 0x02, 0xdd, 0x6b, 0x71, 0x6c, 0x6d, 0x4d,
-	0xe5, 0xda, 0x1a, 0xe5, 0xe7, 0x4b, 0xad, 0x00, 0x79, 0x56, 0x7b, 0xcc,
-	0xcb, 0xa2, 0x5f, 0xc1, 0x3e, 0x05, 0x9a, 0xf6, 0x2f, 0x16, 0x84, 0x73,
-	0x4c, 0xe6, 0x89, 0xc2, 0x79, 0x4a, 0x2b, 0x2d, 0x73, 0xfe, 0x08, 0x5b,
-	0x72, 0x64, 0xdd, 0x80, 0x98, 0x72, 0x5c, 0x2b, 0x9c, 0x5e, 0x40, 0xfe,
-	0xb8, 0x82, 0xdf, 0x19, 0xfc, 0x9a, 0xf8, 0x45, 0xf9, 0xfb, 0x33, 0xc8,
-	0xff, 0xa5, 0x7f, 0x45, 0x2c, 0x50, 0xfb, 0xff, 0x62, 0x05, 0x3a, 0xb6,
-	0x90, 0xa6, 0x6f, 0x3b, 0xa2, 0x5f, 0x28, 0x9f, 0x52, 0x40, 0xde, 0x6b,
-	0xbe, 0x4d, 0xbf, 0x13, 0xe6, 0x50, 0x44, 0xaf, 0xd7, 0xc1, 0xc7, 0x91,
-	0xfd, 0xa1, 0xbe, 0x66, 0x1f, 0xf4, 0xa4, 0xef, 0x0c, 0x73, 0x24, 0xe4,
-	0x6a, 0x05, 0xb9, 0xea, 0xfb, 0xe0, 0x8d, 0x46, 0x6f, 0x41, 0x7f, 0x5e,
-	0xaf, 0x77, 0x81, 0x1e, 0x87, 0xca, 0x93, 0xf6, 0x18, 0x69, 0x43, 0xe6,
-	0x26, 0xad, 0x0b, 0x36, 0x0c, 0xfb, 0x96, 0x63, 0x4a, 0x74, 0xe4, 0xcf,
-	0xcd, 0x2c, 0xd5, 0x04, 0xd6, 0x22, 0xef, 0xc9, 0xa1, 0x0f, 0xd9, 0x5f,
-	0xa9, 0x33, 0x9c, 0xa0, 0x37, 0xea, 0x3a, 0xbd, 0x89, 0xbc, 0xeb, 0x2d,
-	0xe7, 0xdc, 0x0c, 0x62, 0xd6, 0x00, 0xe2, 0x03, 0x6a, 0x98, 0x5d, 0xec,
-	0xa3, 0x77, 0x1a, 0x78, 0x96, 0xf0, 0xbb, 0x13, 0x79, 0xe3, 0xf5, 0x61,
-	0x3e, 0x6d, 0x3d, 0xd3, 0x96, 0x00, 0x0c, 0xaf, 0x37, 0x40, 0x5b, 0x0f,
-	0xe4, 0x6f, 0x9b, 0x53, 0xf4, 0xcb, 0x5e, 0x99, 0xab, 0x68, 0x3c, 0xaf,
-	0xfc, 0xd2, 0x27, 0xe7, 0x99, 0xcf, 0x3a, 0x74, 0x9c, 0xc7, 0xfc, 0x8e,
-	0xfd, 0x27, 0xe3, 0xb3, 0xc7, 0x0a, 0x38, 0xcc, 0x95, 0xba, 0xea, 0x47,
-	0x73, 0xa4, 0x45, 0x31, 0x8c, 0xfd, 0x62, 0x89, 0x0a, 0x92, 0xef, 0x13,
-	0x24, 0x65, 0xb0, 0x4e, 0x9e, 0x94, 0x30, 0xf2, 0xf5, 0x99, 0x39, 0x87,
-	0xe5, 0x0a, 0xff, 0x56, 0x8b, 0xe4, 0xca, 0x32, 0xea, 0xa4, 0x6a, 0xfd,
-	0x29, 0xc8, 0x55, 0x84, 0xf5, 0x01, 0xec, 0x7b, 0x81, 0xe5, 0x8b, 0xba,
-	0xb1, 0x8e, 0xbc, 0xa7, 0x4e, 0x29, 0x55, 0xdf, 0x1c, 0x47, 0x5d, 0x00,
-	0xf9, 0xd5, 0x16, 0x80, 0x03, 0x36, 0x5a, 0x5b, 0xc1, 0x13, 0xb5, 0x48,
-	0xed, 0x0c, 0x9e, 0x83, 0x78, 0x36, 0x59, 0x37, 0xc3, 0x3c, 0xe3, 0x13,
-	0xf4, 0xc0, 0x9e, 0x4a, 0x6c, 0x4f, 0xf4, 0x8f, 0xad, 0x3c, 0xfd, 0x43,
-	0x6b, 0x8c, 0x7e, 0xd4, 0xca, 0xd1, 0x0f, 0x5b, 0x2e, 0xfd, 0x7d, 0x6b,
-	0x84, 0x9e, 0x6d, 0x65, 0xb9, 0x96, 0x43, 0xce, 0x64, 0x71, 0xce, 0x44,
-	0x0f, 0xfa, 0xb7, 0xc3, 0xde, 0x59, 0xfe, 0xe7, 0x66, 0x0a, 0xcd, 0x21,
-	0x2a, 0x9f, 0x80, 0x6f, 0x76, 0x6f, 0xe3, 0x1a, 0x94, 0x1e, 0x73, 0xb9,
-	0x86, 0xe8, 0xe0, 0xf7, 0xa8, 0x23, 0xe0, 0xbb, 0xe1, 0xcb, 0xa6, 0xd2,
-	0xf6, 0x39, 0x4f, 0x1f, 0x08, 0x7d, 0xc0, 0x5d, 0x29, 0xea, 0xc2, 0x5e,
-	0xf0, 0x7f, 0x17, 0x9f, 0x86, 0x0d, 0xc8, 0x1a, 0x28, 0x01, 0x5f, 0xc3,
-	0x79, 0x80, 0xc1, 0x76, 0xcc, 0xf5, 0x87, 0xe5, 0xe9, 0x5c, 0x17, 0xb2,
-	0x3d, 0xeb, 0x08, 0x1a, 0x0c, 0x37, 0x69, 0xb2, 0xdc, 0x0c, 0x87, 0x7d,
-	0x6a, 0x21, 0xf4, 0x6f, 0x89, 0x50, 0x2f, 0x4d, 0xcc, 0x3f, 0x15, 0xfa,
-	0xe3, 0x8d, 0xfb, 0x20, 0x56, 0x20, 0x97, 0x54, 0xeb, 0x18, 0x56, 0x0b,
-	0x61, 0xfb, 0xc3, 0xb9, 0x24, 0xf8, 0xed, 0x52, 0xd9, 0x7f, 0x43, 0xe3,
-	0x1c, 0x5b, 0x38, 0xcc, 0xff, 0x11, 0x8c, 0x2f, 0x87, 0xe3, 0xaf, 0xd0,
-	0xf4, 0x22, 0x81, 0xd6, 0xd7, 0xb4, 0xa2, 0x1c, 0x8f, 0x61, 0x2c, 0x30,
-	0xd6, 0xb9, 0x6e, 0xe0, 0x0c, 0x23, 0xc5, 0xba, 0x2e, 0x9c, 0x71, 0xf0,
-	0x71, 0x12, 0xbf, 0x82, 0xfc, 0x3d, 0xe2, 0x0f, 0x15, 0xde, 0x41, 0xbc,
-	0xd0, 0x3a, 0xa2, 0xdc, 0x67, 0x3b, 0x6a, 0xcf, 0x20, 0x38, 0x84, 0x5a,
-	0xdd, 0x4a, 0x19, 0xf4, 0x2f, 0xf3, 0xb6, 0x79, 0x48, 0xcc, 0xe1, 0x4c,
-	0x41, 0x30, 0xe1, 0xd8, 0x95, 0x82, 0xe8, 0xa6, 0x9f, 0x1f, 0xe7, 0xb8,
-	0x5b, 0x9f, 0x79, 0x01, 0xba, 0xd7, 0x58, 0xe9, 0xa4, 0x46, 0xc3, 0xa0,
-	0x2b, 0xa3, 0x43, 0xa0, 0xd3, 0xa4, 0x46, 0x33, 0x85, 0x5c, 0x6e, 0x33,
-	0xa1, 0x3c, 0x94, 0x0e, 0x43, 0xcf, 0x67, 0xa5, 0x8f, 0xf6, 0x1c, 0x3c,
-	0x9b, 0x1f, 0xf4, 0xae, 0x3f, 0x73, 0x09, 0xf4, 0xf7, 0xa0, 0x0a, 0xd9,
-	0x2e, 0xe5, 0x5c, 0xf6, 0x87, 0x4c, 0x4f, 0x20, 0x6e, 0x19, 0x43, 0xe6,
-	0x7e, 0xf1, 0xab, 0xe0, 0x0e, 0x83, 0x65, 0xf7, 0xaa, 0xac, 0x77, 0x64,
-	0x9c, 0xc3, 0x7e, 0x4b, 0x2b, 0xaf, 0x81, 0x16, 0x93, 0x9e, 0x6d, 0x6e,
-	0x0f, 0xc7, 0x96, 0xe4, 0xc5, 0xb3, 0xcd, 0x2e, 0xfa, 0x61, 0x63, 0x0b,
-	0x2d, 0x37, 0xf8, 0x7d, 0x27, 0x2d, 0x35, 0x86, 0xae, 0x1e, 0x15, 0x03,
-	0xb4, 0x7a, 0xe3, 0x4d, 0xe6, 0x57, 0x05, 0xf2, 0x82, 0xc9, 0x8f, 0xe9,
-	0xbd, 0xd1, 0x5e, 0xfa, 0xe9, 0x3d, 0x76, 0xfd, 0x7e, 0x01, 0x1b, 0x18,
-	0x4d, 0xb2, 0x6d, 0xa3, 0xcf, 0xf3, 0xf6, 0x55, 0x4b, 0xb0, 0x6e, 0xff,
-	0x04, 0x3c, 0xb5, 0x8f, 0x29, 0x3b, 0x60, 0xdc, 0x8c, 0x17, 0xba, 0xe1,
-	0xbc, 0x08, 0x9c, 0x78, 0xd7, 0x1c, 0x02, 0xae, 0x17, 0x25, 0x2f, 0x0e,
-	0xb9, 0xf6, 0x55, 0x42, 0x0e, 0x79, 0xc5, 0x19, 0xca, 0x0a, 0xb1, 0x9d,
-	0x1a, 0x99, 0x9b, 0xcc, 0xf3, 0xf0, 0xff, 0xa8, 0xab, 0x2a, 0x97, 0xa9,
-	0x3e, 0x73, 0xc9, 0x61, 0xfd, 0x67, 0xbf, 0xf1, 0x12, 0xf2, 0x4e, 0x93,
-	0x4e, 0x34, 0xd9, 0x5f, 0x32, 0x2e, 0xce, 0xfd, 0x77, 0x9b, 0x5f, 0x13,
-	0x9c, 0x23, 0xe0, 0x1d, 0xe6, 0xf5, 0x2f, 0xb1, 0x9c, 0x3b, 0x18, 0x36,
-	0x6b, 0x89, 0x60, 0x03, 0x8f, 0x86, 0xcc, 0x5d, 0x82, 0xf7, 0xfb, 0x6f,
-	0xec, 0xfb, 0x2e, 0x68, 0x1d, 0x02, 0x2c, 0xe2, 0x65, 0xa6, 0x7d, 0x8f,
-	0x57, 0xe4, 0x1e, 0xc7, 0x9b, 0xc8, 0xf3, 0xd6, 0xf6, 0xc0, 0x5c, 0x53,
-	0xe0, 0x9c, 0x86, 0x94, 0xcb, 0x95, 0x51, 0xe6, 0xef, 0x6d, 0x7d, 0x9c,
-	0x63, 0xea, 0xf9, 0xbf, 0x09, 0xa2, 0x5a, 0xf3, 0x95, 0xf9, 0x49, 0xf8,
-	0xe7, 0x20, 0xa8, 0xee, 0x1e, 0x52, 0x71, 0x68, 0x90, 0xdf, 0x1f, 0x90,
-	0xb2, 0xa8, 0x8a, 0x4e, 0xba, 0xc3, 0xb0, 0x00, 0xcb, 0x73, 0x2f, 0x87,
-	0x72, 0x84, 0x11, 0x75, 0xa1, 0xdf, 0x8c, 0xf4, 0x32, 0x05, 0x1d, 0xdb,
-	0x63, 0x1e, 0x0a, 0x63, 0x32, 0xc7, 0xb4, 0x9f, 0x42, 0xe7, 0xac, 0x14,
-	0xeb, 0x4d, 0xaa, 0xef, 0x9a, 0xde, 0xf0, 0xbb, 0xfa, 0x8c, 0x07, 0xda,
-	0x8a, 0x0b, 0x9d, 0x54, 0xaa, 0x27, 0x90, 0x03, 0x19, 0x34, 0x97, 0xc3,
-	0x18, 0x3a, 0x54, 0x6a, 0xb0, 0xce, 0x57, 0x42, 0x9d, 0x4f, 0x86, 0xb8,
-	0x4f, 0x82, 0x17, 0xb6, 0xb5, 0x2a, 0xb8, 0x76, 0xda, 0x26, 0xeb, 0x5f,
-	0x1d, 0xb6, 0x5c, 0xae, 0x71, 0xed, 0x89, 0xfc, 0xdb, 0x3c, 0x37, 0x33,
-	0xed, 0x18, 0xa0, 0x6b, 0x44, 0x2b, 0xb7, 0x1c, 0xad, 0xec, 0x33, 0x7d,
-	0xbb, 0x41, 0xb7, 0x26, 0x6b, 0xdc, 0xa5, 0xd6, 0x7b, 0xc1, 0xd2, 0xee,
-	0x4d, 0xe8, 0x43, 0xe7, 0x27, 0x58, 0xae, 0x5f, 0x60, 0xba, 0xac, 0x82,
-	0x60, 0x3e, 0xa7, 0xe9, 0xd4, 0xf0, 0xdf, 0xf5, 0x72, 0x3e, 0x75, 0x7a,
-	0x98, 0xf1, 0x83, 0x8e, 0x74, 0x9a, 0x96, 0x7d, 0xde, 0xa3, 0x3e, 0xc3,
-	0x3c, 0x2c, 0x2f, 0x98, 0xf4, 0x88, 0x94, 0xdb, 0x6b, 0xd2, 0xa6, 0xcb,
-	0x2b, 0xb0, 0xa5, 0xd4, 0x90, 0x79, 0x94, 0xec, 0xab, 0x17, 0x75, 0xbb,
-	0x3e, 0x05, 0x7b, 0x5e, 0x5a, 0xd4, 0x69, 0xa7, 0xac, 0xb1, 0x58, 0x36,
-	0xf6, 0x31, 0x58, 0x7c, 0x78, 0xf6, 0x43, 0x6d, 0x67, 0xef, 0xa1, 0x4b,
-	0x4f, 0xff, 0x16, 0x7c, 0x0d, 0xf3, 0xd5, 0xb0, 0x0e, 0x23, 0x9f, 0x58,
-	0x40, 0xee, 0x51, 0x45, 0x6e, 0x5c, 0xc8, 0x30, 0x6c, 0xc4, 0xef, 0xad,
-	0x92, 0xff, 0x42, 0xf2, 0x7f, 0x07, 0x55, 0xa5, 0x0d, 0x65, 0xe4, 0x3b,
-	0x01, 0x1c, 0xea, 0x1d, 0x8f, 0x91, 0x2b, 0xc9, 0x77, 0xf7, 0x2a, 0x38,
-	0xf6, 0x11, 0x19, 0x7e, 0x77, 0x14, 0x7b, 0x32, 0x8f, 0xa3, 0xf9, 0x6e,
-	0x52, 0x36, 0x14, 0xf1, 0x1d, 0x89, 0x44, 0x33, 0x4d, 0xbf, 0x8b, 0x9a,
-	0x67, 0xb2, 0x39, 0x48, 0xa5, 0xa6, 0x05, 0x19, 0xcc, 0xf4, 0xf1, 0xd9,
-	0x8a, 0x2b, 0x38, 0x8f, 0x60, 0x5a, 0xef, 0xa5, 0xc3, 0x7e, 0x44, 0x4f,
-	0x32, 0xa4, 0x6f, 0x32, 0x1c, 0x27, 0x42, 0x1a, 0xda, 0xf1, 0x25, 0x81,
-	0x0b, 0x31, 0x3e, 0xf7, 0x57, 0x21, 0x1e, 0xf6, 0x1f, 0xa0, 0x75, 0x32,
-	0x43, 0x2b, 0x3e, 0xd3, 0xb1, 0x85, 0xaa, 0x69, 0xee, 0x1f, 0x80, 0x9e,
-	0x31, 0x9e, 0x4d, 0x9c, 0xc7, 0xac, 0xe3, 0xf1, 0x91, 0x66, 0x05, 0x3c,
-	0x66, 0xfe, 0xf2, 0xba, 0x24, 0x2d, 0x7d, 0x85, 0xe5, 0xb7, 0x07, 0xf9,
-	0x3b, 0xeb, 0xc2, 0x96, 0x50, 0xaf, 0xd4, 0x9e, 0xa5, 0x85, 0x1e, 0xc8,
-	0x8a, 0xf7, 0xed, 0xa2, 0xbb, 0x61, 0xef, 0xc5, 0x06, 0xef, 0x3f, 0x09,
-	0x3d, 0x7a, 0x59, 0xee, 0x5f, 0x5a, 0x19, 0x08, 0xe1, 0x19, 0xb6, 0x67,
-	0x03, 0x6c, 0x27, 0xed, 0xab, 0x9b, 0xd7, 0x81, 0xff, 0x7d, 0xc0, 0x0b,
-	0x3a, 0x99, 0x63, 0x78, 0xc6, 0x83, 0x75, 0x8d, 0xf4, 0x67, 0xe0, 0x49,
-	0xc9, 0x5a, 0xbe, 0xd8, 0xe8, 0xa4, 0x62, 0x3d, 0xc2, 0xc5, 0x78, 0x3e,
-	0x46, 0xad, 0x7b, 0x9f, 0xc4, 0x35, 0x2d, 0x71, 0xe1, 0x7d, 0x83, 0x7d,
-	0xcd, 0xad, 0x80, 0x47, 0xbd, 0xee, 0x80, 0xb6, 0x54, 0x37, 0x2d, 0xc9,
-	0x7a, 0xbd, 0x4b, 0xf9, 0x98, 0xd4, 0x66, 0xbc, 0xdf, 0x02, 0x5b, 0xdf,
-	0x83, 0x3c, 0xa6, 0x07, 0x73, 0xd6, 0x86, 0xb9, 0x8d, 0xf4, 0x27, 0x36,
-	0xd0, 0xdf, 0x89, 0x75, 0xfd, 0xd8, 0x53, 0xad, 0x2b, 0x61, 0xdd, 0xec,
-	0x02, 0x6c, 0x82, 0x73, 0xf3, 0x34, 0xc7, 0xe4, 0x1b, 0x25, 0x2d, 0xb3,
-	0x2b, 0xef, 0xe1, 0x5c, 0x03, 0x80, 0x8d, 0xc6, 0x8a, 0x0f, 0x75, 0xe0,
-	0xf9, 0x5e, 0x43, 0xde, 0x4b, 0x40, 0x06, 0x9b, 0x53, 0x7c, 0xf6, 0x6a,
-	0xe3, 0xf3, 0x78, 0x76, 0x63, 0x1b, 0xbf, 0x98, 0x57, 0x4c, 0x2f, 0xd3,
-	0x0a, 0x3d, 0x25, 0xd8, 0x9b, 0x8b, 0x9a, 0x2f, 0xa5, 0x53, 0x29, 0x87,
-	0x78, 0xee, 0xf3, 0x5d, 0x2d, 0xdb, 0xe5, 0xa0, 0xaa, 0x0b, 0x1c, 0x8e,
-	0xeb, 0x86, 0x3c, 0xfb, 0xe1, 0x15, 0xbe, 0xaf, 0xb5, 0x10, 0x4f, 0xed,
-	0x2c, 0xe1, 0xec, 0x0f, 0xaf, 0x38, 0xf4, 0x68, 0x33, 0x4b, 0x47, 0x9b,
-	0xb6, 0x79, 0x3f, 0x7c, 0x40, 0x79, 0xed, 0x1e, 0x77, 0x57, 0x8a, 0xfd,
-	0x96, 0x81, 0x9c, 0xb3, 0xc3, 0x51, 0x39, 0x48, 0x95, 0xeb, 0xb1, 0x05,
-	0x9b, 0xef, 0x68, 0xcc, 0x06, 0x6d, 0xcc, 0x53, 0xfe, 0x2f, 0x73, 0x14,
-	0xde, 0x9f, 0xfd, 0x34, 0x72, 0x12, 0x1f, 0x39, 0x89, 0x8f, 0x9c, 0xc4,
-	0x47, 0x4e, 0xe2, 0x23, 0x27, 0xf1, 0x91, 0x93, 0xf8, 0xc8, 0x49, 0x7c,
-	0xe4, 0x24, 0xc8, 0xff, 0x55, 0x5d, 0x30, 0x8e, 0x5c, 0x1b, 0xfe, 0xcb,
-	0xff, 0x6a, 0x98, 0x53, 0x44, 0x31, 0x99, 0xe7, 0x56, 0x37, 0x79, 0x6e,
-	0x74, 0x4f, 0x7c, 0x00, 0x73, 0x13, 0x61, 0xee, 0xc3, 0x6b, 0xa2, 0x98,
-	0xcd, 0xeb, 0x68, 0xcc, 0x43, 0xbd, 0x59, 0x98, 0xe4, 0xdc, 0x48, 0xc5,
-	0x2a, 0x95, 0x97, 0xbf, 0x8a, 0xfc, 0xc8, 0x42, 0x7e, 0x34, 0x88, 0x5c,
-	0x88, 0xef, 0xb5, 0xa3, 0xfb, 0xa3, 0x82, 0x76, 0xc8, 0x1f, 0xd7, 0xbe,
-	0xe6, 0x73, 0xde, 0xee, 0x58, 0x65, 0x21, 0x16, 0xfa, 0x29, 0xa0, 0xe2,
-	0xe8, 0xb7, 0x90, 0x23, 0x7f, 0x4f, 0xde, 0x95, 0x4d, 0x0c, 0xb3, 0xcc,
-	0x27, 0x3e, 0x25, 0x4f, 0x8e, 0xf8, 0xab, 0xee, 0xf8, 0xc4, 0x12, 0xf3,
-	0x8f, 0xa8, 0xef, 0x2c, 0x18, 0x7e, 0x36, 0x41, 0xa9, 0x53, 0x5b, 0x30,
-	0x67, 0x52, 0xbf, 0xbc, 0x27, 0x82, 0x28, 0xcf, 0xfe, 0x1a, 0xf2, 0x72,
-	0x48, 0x9c, 0xe5, 0xdb, 0x04, 0xc6, 0xcb, 0xfe, 0xb5, 0x32, 0x53, 0x6c,
-	0x54, 0xa4, 0x4e, 0x1d, 0x6a, 0x96, 0x90, 0x3f, 0xf5, 0xf6, 0x53, 0x97,
-	0x81, 0x1a, 0x2a, 0xc2, 0xcd, 0x38, 0x7f, 0x99, 0x92, 0xb5, 0xcd, 0xd9,
-	0x35, 0x79, 0x42, 0xd6, 0xbc, 0x4f, 0x65, 0xa6, 0x5a, 0xb7, 0x33, 0x5c,
-	0xd7, 0x82, 0xd6, 0x99, 0x27, 0x81, 0x63, 0x19, 0x39, 0x81, 0x2e, 0xf7,
-	0xae, 0xcc, 0xcc, 0xd6, 0xd5, 0x5d, 0x95, 0xa2, 0x01, 0xf1, 0x2f, 0xd7,
-	0x45, 0xfa, 0x92, 0xba, 0xb3, 0x12, 0x12, 0x96, 0xe1, 0x18, 0xde, 0x00,
-	0x1c, 0xcb, 0x2d, 0x0b, 0x58, 0x96, 0x1d, 0xd3, 0x50, 0x99, 0xa9, 0x34,
-	0xda, 0x69, 0x60, 0x3c, 0x8c, 0x37, 0x3a, 0x0f, 0x9f, 0x25, 0x45, 0xe2,
-	0x54, 0x10, 0x94, 0x47, 0x07, 0xc3, 0x3a, 0x12, 0xf5, 0xe3, 0x09, 0x43,
-	0xea, 0xb9, 0x1a, 0x7f, 0x53, 0xc6, 0x29, 0x4b, 0xf0, 0x3c, 0x3f, 0xf1,
-	0x2e, 0xf7, 0x24, 0xe6, 0x30, 0x5e, 0x8e, 0xd6, 0x8a, 0x70, 0x6d, 0x77,
-	0x1b, 0x3f, 0x3b, 0xc2, 0xfd, 0x98, 0x26, 0x3e, 0xe7, 0x65, 0xec, 0xc5,
-	0x74, 0xf1, 0x1a, 0x13, 0xb4, 0x41, 0x96, 0xfe, 0xff, 0x96, 0xf7, 0xed,
-	0x67, 0x62, 0x9e, 0x1a, 0x80, 0xe1, 0xf5, 0x8c, 0x23, 0x82, 0xc1, 0x8b,
-	0xb3, 0x0a, 0x4e, 0xac, 0xdd, 0xed, 0x7d, 0xd6, 0xbe, 0xed, 0xb4, 0x46,
-	0xfb, 0x47, 0x78, 0xb2, 0x4a, 0x6e, 0x6b, 0xf0, 0xf2, 0xff, 0x0a, 0xc3,
-	0x13, 0xba, 0xf8, 0x89, 0x3b, 0xd2, 0x6c, 0x5b, 0x6d, 0x1c, 0xdd, 0x35,
-	0x70, 0xcd, 0xcf, 0x35, 0x3c, 0x7f, 0x47, 0x68, 0xaf, 0x4b, 0x4b, 0x61,
-	0x2c, 0x83, 0x2e, 0xaa, 0xbb, 0xd4, 0x70, 0x6c, 0x70, 0x6c, 0x43, 0xe3,
-	0x1c, 0x3f, 0xb2, 0x91, 0xf6, 0x7b, 0x42, 0x95, 0x9b, 0x9c, 0x59, 0x8c,
-	0x7c, 0x0e, 0xfc, 0xc1, 0xb0, 0x11, 0xfa, 0xed, 0x24, 0xfc, 0x56, 0x0f,
-	0xed, 0x83, 0xbf, 0xb9, 0x13, 0xfe, 0x66, 0x3f, 0xea, 0xca, 0xf1, 0x95,
-	0xf6, 0xfb, 0x57, 0xae, 0x65, 0xab, 0x74, 0x58, 0xca, 0xae, 0x12, 0xe8,
-	0xce, 0xc7, 0x90, 0xdf, 0x2e, 0x99, 0xa3, 0x29, 0x79, 0xc2, 0x57, 0xba,
-	0xfc, 0x2d, 0x62, 0xe3, 0x3d, 0x6f, 0x16, 0x7a, 0xdd, 0x55, 0x10, 0x32,
-	0xff, 0x52, 0x7c, 0xab, 0x36, 0x14, 0xdf, 0xe0, 0x53, 0x81, 0xdf, 0xa0,
-	0x4a, 0xd3, 0xa4, 0x0a, 0xf6, 0xad, 0x60, 0xdf, 0x0a, 0xea, 0xc1, 0xd9,
-	0x66, 0xfb, 0x77, 0xaa, 0xee, 0xb0, 0xc6, 0x66, 0xd8, 0xa8, 0x6f, 0x86,
-	0xe7, 0xd2, 0xda, 0x9e, 0xc7, 0xc0, 0xbb, 0x47, 0xc1, 0xbb, 0x23, 0xa8,
-	0x83, 0xfe, 0x04, 0x75, 0xd0, 0x1f, 0xa2, 0x0e, 0x3a, 0x8c, 0x3a, 0x68,
-	0x0a, 0x75, 0xd0, 0x7d, 0xb0, 0xfd, 0x7b, 0x61, 0xfb, 0x93, 0xb0, 0xfd,
-	0x09, 0x79, 0xc7, 0x73, 0xc8, 0xdf, 0x78, 0xef, 0x11, 0xed, 0xc5, 0xed,
-	0x4d, 0x22, 0x88, 0xaf, 0x7c, 0x62, 0x9c, 0x1a, 0x2d, 0xae, 0x87, 0x5c,
-	0x79, 0x7f, 0x35, 0xed, 0x4e, 0x6a, 0x53, 0xc8, 0xb9, 0xef, 0x1f, 0xe1,
-	0x3a, 0x29, 0xa5, 0xee, 0x2b, 0x73, 0xf6, 0x73, 0x1e, 0xd2, 0x2e, 0xe4,
-	0x6d, 0x38, 0xb3, 0x7d, 0xa6, 0xa8, 0x47, 0x35, 0x4a, 0xdf, 0x5a, 0x8d,
-	0xb2, 0x3c, 0xcf, 0x35, 0xca, 0xab, 0x6b, 0x35, 0xca, 0xf2, 0x3c, 0xd7,
-	0x28, 0xaf, 0xac, 0xab, 0x51, 0xae, 0x3c, 0xfd, 0xf2, 0xba, 0x1a, 0xe5,
-	0xca, 0xd3, 0x2f, 0x85, 0x63, 0xa6, 0x03, 0x7e, 0xc9, 0x0d, 0x69, 0x35,
-	0x5d, 0x3c, 0x7b, 0xc3, 0x7c, 0xe1, 0xfb, 0xfd, 0xeb, 0xff, 0x1f, 0x3a,
-	0x6e, 0x9d, 0x1a, 0x39, 0xdf, 0xd8, 0xaa, 0xea, 0x9a, 0xf6, 0xf9, 0xde,
-	0xb6, 0xf9, 0x55, 0xf9, 0x6d, 0xb4, 0x5c, 0xdb, 0xfc, 0x3e, 0xbc, 0x27,
-	0xad, 0x0c, 0xdb, 0xf5, 0x02, 0x7d, 0x1c, 0xf0, 0xf7, 0x3d, 0x4f, 0x74,
-	0xc9, 0xef, 0x6a, 0x9e, 0xcc, 0x91, 0x61, 0xa3, 0xa3, 0x47, 0xb7, 0x2a,
-	0x3b, 0xe6, 0x7e, 0x5a, 0x53, 0xbe, 0xf9, 0x41, 0xe0, 0x01, 0xaf, 0x7d,
-	0x43, 0xde, 0xe1, 0xa8, 0xf3, 0xaa, 0xbb, 0x6c, 0x23, 0xbf, 0x8a, 0x38,
-	0x03, 0x59, 0x4b, 0xdc, 0x5c, 0xf3, 0x71, 0x9d, 0x18, 0xf9, 0xef, 0x08,
-	0xd7, 0xcf, 0xd2, 0x8a, 0xee, 0xdb, 0x50, 0xef, 0xf1, 0x9a, 0x68, 0xdc,
-	0x5e, 0x1f, 0x26, 0xc3, 0xfb, 0xac, 0x55, 0x95, 0x13, 0x49, 0x7c, 0x46,
-	0x88, 0xef, 0xbf, 0x02, 0xe5, 0x37, 0x18, 0xde, 0x6c, 0x83, 0x1f, 0x47,
-	0x9e, 0xc6, 0x77, 0x2b, 0x9c, 0x6f, 0x19, 0xf4, 0xee, 0x7c, 0x37, 0xbd,
-	0x73, 0x1c, 0xf9, 0xa6, 0x6b, 0x67, 0x5f, 0x46, 0xbd, 0x70, 0x8a, 0xf3,
-	0xe2, 0x51, 0xa6, 0x73, 0xc8, 0x9a, 0x25, 0xab, 0x5f, 0xe5, 0xd1, 0x47,
-	0xb4, 0x4f, 0xd2, 0x2d, 0xc2, 0x7d, 0x7e, 0xd6, 0xb6, 0x8f, 0xd5, 0xb6,
-	0x4f, 0x81, 0xed, 0xad, 0xf1, 0x75, 0x9c, 0xb9, 0xb2, 0xfd, 0x26, 0x33,
-	0x1d, 0xd6, 0x52, 0x8f, 0x8c, 0x6e, 0xa6, 0xfa, 0x80, 0x7d, 0xee, 0x15,
-	0xe4, 0xda, 0xe5, 0x51, 0xcc, 0xa5, 0x87, 0xf0, 0x8e, 0xe7, 0xed, 0x06,
-	0x09, 0xfb, 0x5c, 0x83, 0x90, 0x4c, 0x77, 0xd9, 0x15, 0xbe, 0x63, 0x4b,
-	0x0b, 0xee, 0x4b, 0xda, 0x1a, 0xa1, 0xfd, 0x66, 0x2e, 0xe2, 0xcc, 0x53,
-	0xa8, 0x99, 0x8e, 0xa8, 0xbb, 0xaf, 0x70, 0x9f, 0x5b, 0xb4, 0x8b, 0x32,
-	0xaf, 0xcd, 0x69, 0x95, 0xb4, 0x3a, 0xe3, 0x37, 0x60, 0xeb, 0xba, 0x60,
-	0xd8, 0x77, 0x81, 0x5b, 0xa3, 0xa5, 0xe3, 0xba, 0xbc, 0xeb, 0x2c, 0x8f,
-	0xb2, 0xac, 0xf9, 0x79, 0x3d, 0xde, 0x45, 0x67, 0xfa, 0xdb, 0xf0, 0x4c,
-	0x5f, 0x0a, 0x6b, 0xed, 0xe8, 0x4c, 0x09, 0x7a, 0x63, 0xde, 0x04, 0xec,
-	0x08, 0xf8, 0x51, 0xa2, 0x95, 0x96, 0xf5, 0x39, 0x78, 0x6a, 0x6d, 0xbc,
-	0x31, 0x36, 0xc8, 0x30, 0xaa, 0x59, 0xc0, 0x83, 0x89, 0x0c, 0xec, 0x70,
-	0xba, 0x3f, 0xba, 0x83, 0xd5, 0x1d, 0xa1, 0xa9, 0xda, 0x9b, 0xe7, 0x07,
-	0x61, 0x8b, 0x16, 0xec, 0x93, 0xf3, 0x9d, 0x12, 0xd7, 0x19, 0xe1, 0xf7,
-	0x4b, 0xdb, 0x9c, 0xa4, 0x2c, 0x6a, 0x15, 0x3e, 0x7f, 0x9e, 0x96, 0x5b,
-	0x11, 0x0d, 0x39, 0xd8, 0xe3, 0x18, 0x7e, 0x23, 0x78, 0xe7, 0xe2, 0xc7,
-	0x75, 0x4e, 0x81, 0x1e, 0x93, 0x79, 0x34, 0xf2, 0xe4, 0x61, 0xa6, 0xef,
-	0x00, 0xd6, 0xb3, 0x3e, 0xb3, 0x9e, 0x1e, 0x20, 0x6f, 0x80, 0x7d, 0x45,
-	0x06, 0xb8, 0x01, 0xe3, 0xbf, 0x0e, 0x5b, 0x1f, 0xc4, 0xd3, 0x36, 0xcb,
-	0xcc, 0x5b, 0x89, 0x3f, 0x08, 0xf4, 0x1c, 0x7f, 0x3b, 0x18, 0x0f, 0xc7,
-	0x43, 0xe6, 0xdd, 0xac, 0x7b, 0x99, 0x1d, 0x74, 0x6e, 0x31, 0x8a, 0x61,
-	0x33, 0xb0, 0x41, 0xbe, 0x53, 0x1d, 0x07, 0x5f, 0x78, 0xac, 0x85, 0xb1,
-	0x0c, 0xf3, 0xcb, 0x0b, 0x38, 0x77, 0x9e, 0x4e, 0xa1, 0x66, 0xa7, 0x01,
-	0x7e, 0x22, 0x57, 0xf5, 0xb7, 0x84, 0xfa, 0xbe, 0x1e, 0x5e, 0x77, 0xb8,
-	0x3f, 0x0e, 0xfa, 0x8c, 0x36, 0x78, 0x86, 0x51, 0xb5, 0xc5, 0x45, 0x42,
-	0x2c, 0xcd, 0x04, 0xb7, 0x8b, 0xfc, 0x7d, 0xf4, 0x80, 0x3c, 0x53, 0x9e,
-	0x0e, 0x2f, 0x06, 0x81, 0x97, 0x1b, 0xca, 0x2e, 0x93, 0x9d, 0x7d, 0x92,
-	0xf6, 0x98, 0xfb, 0x48, 0x97, 0xdf, 0xe0, 0x50, 0x13, 0xdf, 0xde, 0x91,
-	0x0f, 0x82, 0x93, 0xa0, 0xfd, 0x05, 0xb9, 0xcf, 0x7d, 0xa0, 0x1f, 0xbc,
-	0x92, 0xf5, 0x04, 0xd3, 0x0a, 0xde, 0xa4, 0x99, 0xde, 0x24, 0x1d, 0x6e,
-	0x9d, 0x0f, 0x65, 0xf3, 0x28, 0x79, 0xfe, 0xdb, 0x3a, 0xdf, 0x47, 0x97,
-	0x5b, 0x4f, 0x86, 0xb4, 0xe5, 0x41, 0x2f, 0xf6, 0x6f, 0xbd, 0x90, 0x66,
-	0xdf, 0xc0, 0x32, 0xf7, 0x90, 0xf1, 0x79, 0xa3, 0xcf, 0x40, 0x07, 0x3f,
-	0xcd, 0x0f, 0xa4, 0x68, 0xbd, 0x1f, 0x60, 0xb8, 0xd4, 0x75, 0x74, 0x85,
-	0xe9, 0x20, 0xe9, 0x3f, 0x85, 0xb3, 0x19, 0xf4, 0x30, 0x3e, 0x7d, 0x83,
-	0x2f, 0xa8, 0xc8, 0xe7, 0xaa, 0xce, 0xbe, 0x89, 0xe3, 0x14, 0xeb, 0x70,
-	0x0f, 0xfc, 0x1f, 0x74, 0x10, 0x76, 0x5c, 0x5c, 0xe4, 0x3b, 0x85, 0x61,
-	0xbe, 0x87, 0x3a, 0x53, 0x82, 0x6c, 0x97, 0xf8, 0xbb, 0x60, 0x5a, 0xe5,
-	0x82, 0xaa, 0x76, 0xb2, 0xd8, 0x17, 0x32, 0xaf, 0xa5, 0x9f, 0x2c, 0xc9,
-	0xef, 0x80, 0x29, 0xac, 0x09, 0xf0, 0x6c, 0xff, 0x9b, 0x88, 0x9f, 0x14,
-	0xd4, 0xdf, 0x44, 0x84, 0xdf, 0x64, 0x1b, 0x2a, 0x07, 0x78, 0xb8, 0x69,
-	0xd0, 0x54, 0x33, 0xfa, 0x1b, 0x09, 0x96, 0x83, 0x83, 0x3a, 0x3e, 0x8a,
-	0xfb, 0x81, 0x8c, 0x2f, 0xd5, 0x75, 0xb2, 0xfc, 0x66, 0x98, 0xcf, 0x70,
-	0xfe, 0xce, 0x3c, 0xc4, 0x78, 0x59, 0xc9, 0x6f, 0x49, 0xec, 0x84, 0xfc,
-	0xc0, 0x73, 0xdf, 0x80, 0x2d, 0x65, 0xc2, 0x98, 0x6c, 0x72, 0x7d, 0x18,
-	0xd6, 0xac, 0xdb, 0xa9, 0x3a, 0xc9, 0xef, 0x13, 0xf4, 0xfa, 0xfc, 0xa0,
-	0x7c, 0x5f, 0xa6, 0x44, 0xf8, 0x9e, 0xc7, 0x29, 0x2a, 0xcb, 0xf7, 0xf7,
-	0x86, 0xf8, 0x50, 0x63, 0xdd, 0x1b, 0x8d, 0x33, 0x90, 0xa3, 0x82, 0x9b,
-	0x46, 0x2c, 0x7b, 0x0c, 0x71, 0x6c, 0x1a, 0x7c, 0x2f, 0x4e, 0x54, 0x68,
-	0x87, 0xc3, 0x3a, 0x0e, 0x99, 0xa5, 0x58, 0xc7, 0x58, 0xbf, 0x18, 0xa6,
-	0x17, 0x79, 0x26, 0xce, 0x3b, 0x4a, 0x53, 0x7a, 0xfe, 0xfd, 0x83, 0xe5,
-	0x9a, 0x6d, 0x16, 0xe8, 0xa3, 0xc0, 0x33, 0x78, 0xbc, 0x7a, 0xf0, 0x61,
-	0x75, 0x4f, 0x2f, 0x44, 0xfe, 0xd2, 0xc1, 0xb2, 0xea, 0xe3, 0xcc, 0xef,
-	0x87, 0x7d, 0x86, 0xd3, 0xe5, 0xf7, 0xd3, 0x7f, 0xbf, 0xd5, 0xa0, 0x8b,
-	0xb7, 0x06, 0xc1, 0xfd, 0xfc, 0x0d, 0x27, 0xac, 0x41, 0xd5, 0x77, 0x71,
-	0x8e, 0x13, 0xa8, 0x37, 0x46, 0x2d, 0xad, 0x04, 0xdb, 0x3d, 0xe5, 0xa3,
-	0x5e, 0x11, 0xf6, 0xd8, 0xaa, 0x30, 0x11, 0x7f, 0xb9, 0x96, 0xff, 0xcd,
-	0x7e, 0xfe, 0x26, 0x3c, 0xe7, 0xf2, 0x9a, 0x6d, 0xea, 0xae, 0xea, 0xe6,
-	0xdb, 0xa4, 0xcf, 0x25, 0x0a, 0xe3, 0xd0, 0xcd, 0xed, 0xf6, 0xd1, 0x9e,
-	0x23, 0xb2, 0x5d, 0xd0, 0x94, 0x01, 0x7a, 0xaa, 0xb5, 0x28, 0xdf, 0xe2,
-	0xef, 0xfd, 0xab, 0x07, 0xbf, 0xdb, 0xbc, 0x74, 0x70, 0x16, 0xf2, 0xe1,
-	0x33, 0xcd, 0x36, 0x23, 0xfd, 0x8b, 0x72, 0x7e, 0xee, 0x23, 0xfe, 0xfb,
-	0x88, 0xff, 0x3e, 0xe2, 0xbf, 0x8f, 0xf8, 0xef, 0x23, 0xfe, 0xfb, 0x88,
-	0xff, 0xe0, 0xe1, 0x0f, 0xa0, 0x2f, 0xe7, 0xfd, 0x89, 0x30, 0xdf, 0x7a,
-	0x7c, 0x2d, 0xdf, 0x3a, 0xd7, 0xe2, 0x6f, 0x3f, 0x92, 0x96, 0x4a, 0x85,
-	0x54, 0xbe, 0x4a, 0x82, 0xf3, 0x9b, 0x28, 0x5f, 0xbd, 0xfe, 0x37, 0x0c,
-	0x05, 0xc7, 0xb9, 0x1a, 0xc3, 0x55, 0x34, 0xe1, 0x30, 0x9c, 0xca, 0xd7,
-	0xb8, 0x46, 0x5a, 0x0f, 0xc3, 0xdf, 0xc9, 0xd8, 0xb7, 0xa9, 0x6f, 0x34,
-	0xea, 0x7b, 0xd0, 0xe3, 0x5f, 0xf7, 0x10, 0x8b, 0xcb, 0x4d, 0x19, 0x8f,
-	0x31, 0x7e, 0x06, 0x63, 0x83, 0xf5, 0x8f, 0xdf, 0xdd, 0xc3, 0x75, 0x41,
-	0xb9, 0x89, 0xbc, 0x68, 0x39, 0xca, 0x85, 0x00, 0xe7, 0xbf, 0xa9, 0x95,
-	0xea, 0x2c, 0x67, 0x41, 0xb3, 0x69, 0x30, 0xc5, 0x69, 0xaf, 0x75, 0x5e,
-	0x96, 0xb5, 0x8e, 0xfa, 0x9b, 0x9e, 0x11, 0xd0, 0x16, 0xdd, 0xfd, 0x12,
-	0xe9, 0xf3, 0x69, 0xf9, 0x77, 0x00, 0x29, 0x67, 0x58, 0xfe, 0x3d, 0x42,
-	0x1f, 0xf6, 0x11, 0xf3, 0x3b, 0xdb, 0xee, 0x56, 0xa9, 0xa0, 0x7c, 0x76,
-	0xa7, 0xfa, 0x3b, 0x08, 0x91, 0x86, 0xed, 0xde, 0xb6, 0x0d, 0x67, 0x83,
-	0x5c, 0x5f, 0xdd, 0x2a, 0xf3, 0x67, 0xf8, 0xd1, 0x93, 0xc3, 0x7d, 0x03,
-	0xd4, 0xb3, 0x9d, 0x4e, 0x0d, 0x73, 0xad, 0xb5, 0x19, 0xf8, 0x78, 0xad,
-	0x9d, 0x2d, 0x88, 0xed, 0x74, 0x7a, 0x11, 0x7e, 0x76, 0xd1, 0x76, 0x59,
-	0x97, 0x97, 0x86, 0xd3, 0xf0, 0xcf, 0x63, 0x03, 0x1c, 0x9f, 0x97, 0x5b,
-	0xac, 0x2b, 0x7d, 0x80, 0x1f, 0x84, 0x5e, 0x6e, 0x82, 0x3d, 0x09, 0xec,
-	0x1f, 0xe1, 0xfe, 0xb9, 0xc4, 0xdd, 0xe7, 0xec, 0xd9, 0x26, 0x75, 0x43,
-	0xd8, 0xa6, 0x25, 0x40, 0xfb, 0x27, 0x6a, 0x44, 0x97, 0xf8, 0x6c, 0xb3,
-	0x7e, 0xfb, 0xb7, 0xba, 0x37, 0xb5, 0x72, 0x9d, 0xff, 0x0e, 0x61, 0x98,
-	0xf6, 0x41, 0xbf, 0x4c, 0xe7, 0x4d, 0xed, 0x81, 0xc6, 0xff, 0x14, 0x6e,
-	0x75, 0xb1, 0x71, 0x5c, 0x55, 0xf8, 0xdc, 0x59, 0xaf, 0xed, 0x38, 0x6b,
-	0x67, 0xe2, 0x6c, 0xec, 0xb5, 0x15, 0xc4, 0xce, 0x7a, 0x12, 0x4f, 0xb5,
-	0x8e, 0x3a, 0xb6, 0x12, 0xb4, 0x42, 0x96, 0x58, 0xed, 0x7a, 0x5d, 0x87,
-	0x92, 0xb2, 0x85, 0x50, 0x05, 0x09, 0x55, 0x96, 0x9d, 0xd2, 0x54, 0x80,
-	0x90, 0xfa, 0x80, 0x78, 0xcb, 0x6a, 0x6d, 0x87, 0xa4, 0xec, 0x76, 0x6d,
-	0x62, 0xd7, 0x2f, 0x3c, 0x2c, 0xeb, 0x75, 0x6a, 0xbb, 0x9b, 0xac, 0x42,
-	0xfb, 0x50, 0x9e, 0x62, 0x99, 0x92, 0xc2, 0x4b, 0x85, 0xc4, 0x03, 0x02,
-	0x54, 0xa9, 0x4a, 0xda, 0x34, 0x0f, 0x25, 0x11, 0xbc, 0x50, 0x0a, 0xd2,
-	0xf0, 0x7d, 0x77, 0x66, 0x1d, 0x27, 0x50, 0x61, 0x69, 0x35, 0x77, 0xee,
-	0xdc, 0x3b, 0x73, 0x7f, 0xce, 0xf9, 0xce, 0x77, 0xce, 0x3d, 0x66, 0x1b,
-	0x1b, 0x65, 0xfa, 0xd3, 0xab, 0x6a, 0xa6, 0xda, 0x2b, 0x0b, 0x90, 0xe3,
-	0xe2, 0x48, 0x38, 0x88, 0x97, 0x76, 0x05, 0xfa, 0x0c, 0xc7, 0xdf, 0xb7,
-	0x57, 0x9a, 0x57, 0x16, 0xcd, 0x4e, 0xcd, 0xab, 0x1e, 0x7d, 0x76, 0x0a,
-	0x63, 0x8a, 0x61, 0x1d, 0xba, 0xfb, 0x34, 0x36, 0x19, 0xbc, 0xef, 0x7f,
-	0xec, 0xbe, 0xef, 0xb1, 0xfb, 0xc3, 0xff, 0xa3, 0x3d, 0xcb, 0x8f, 0xcb,
-	0x03, 0xc7, 0x69, 0xa5, 0xf8, 0x95, 0x62, 0xc9, 0x36, 0x66, 0x4b, 0x56,
-	0x9a, 0xbc, 0x20, 0x2b, 0x9e, 0xca, 0xba, 0xed, 0xc0, 0xbb, 0x76, 0x99,
-	0x5f, 0x86, 0xcc, 0x63, 0x1e, 0x1d, 0x36, 0xcf, 0xb4, 0x13, 0x7d, 0xd4,
-	0x99, 0x4e, 0x6c, 0x83, 0x61, 0x0f, 0xc5, 0xd0, 0xce, 0x7b, 0xc9, 0x4d,
-	0x9a, 0xe7, 0x74, 0x1c, 0x86, 0x7c, 0xc6, 0x53, 0x45, 0x9d, 0x9f, 0xc1,
-	0x36, 0x6d, 0x72, 0xc7, 0xce, 0xf4, 0x06, 0xf9, 0x3e, 0xf0, 0x5b, 0xc7,
-	0xfa, 0xc8, 0x35, 0x5e, 0x74, 0x77, 0xeb, 0xcc, 0xdb, 0xc2, 0x3c, 0x2a,
-	0x08, 0xcd, 0xb3, 0x22, 0xd5, 0xba, 0xc8, 0xeb, 0xf8, 0xfd, 0xae, 0x1e,
-	0xf8, 0x0a, 0x8a, 0x3e, 0xf3, 0xb8, 0x6c, 0x55, 0xbe, 0x2c, 0x0d, 0xd8,
-	0x9f, 0x4d, 0xd7, 0xf3, 0xee, 0xb9, 0x71, 0xbd, 0xe6, 0x3f, 0x29, 0x29,
-	0x49, 0x8c, 0xd2, 0xbe, 0xb5, 0xcb, 0x4f, 0x97, 0xdb, 0x64, 0xdb, 0xb4,
-	0xcc, 0x7b, 0xc2, 0x5c, 0xb6, 0x98, 0x4c, 0x45, 0x43, 0x9a, 0xa3, 0xca,
-	0xb7, 0xc0, 0xa0, 0xf1, 0xec, 0xee, 0xf2, 0x33, 0x7d, 0x8c, 0x9d, 0x7c,
-	0xb4, 0xcc, 0x7b, 0x03, 0x57, 0x43, 0x76, 0xec, 0x10, 0xb8, 0x2c, 0x40,
-	0xc8, 0xe4, 0xba, 0x73, 0xbe, 0xcf, 0x71, 0x6c, 0xa8, 0xa3, 0x2f, 0xda,
-	0x2e, 0xc5, 0xa3, 0xc0, 0x44, 0x35, 0xa4, 0x73, 0x8a, 0x76, 0xa2, 0x1a,
-	0xa3, 0x43, 0x35, 0xe6, 0xc8, 0x99, 0xfb, 0x35, 0x5e, 0x67, 0xae, 0x7d,
-	0x5f, 0xcf, 0x05, 0xe5, 0x42, 0xcd, 0xa5, 0xac, 0x9a, 0xb2, 0x09, 0x5d,
-	0xdb, 0x68, 0x2e, 0xf5, 0x73, 0xaf, 0xb6, 0x9a, 0x3f, 0xe8, 0xf3, 0x7d,
-	0x2d, 0xd6, 0xfd, 0xb0, 0xcf, 0xaf, 0x8b, 0x07, 0xbe, 0x13, 0x7d, 0xac,
-	0x2a, 0xe6, 0xf6, 0xb2, 0x34, 0x57, 0x7f, 0x2c, 0x6f, 0x57, 0x7e, 0x24,
-	0xbf, 0x5a, 0x3d, 0x0b, 0xfe, 0x61, 0x55, 0x0b, 0xb0, 0x27, 0x37, 0x9a,
-	0x9e, 0x77, 0xc3, 0x3d, 0x03, 0x5f, 0xc1, 0xf3, 0xfe, 0xe0, 0x6e, 0x4b,
-	0x62, 0xec, 0x3b, 0x98, 0x73, 0x1e, 0x3a, 0x44, 0x2c, 0x9c, 0x82, 0xbc,
-	0x25, 0xfb, 0xa5, 0x2b, 0xa2, 0xe5, 0x64, 0x68, 0x2c, 0x8c, 0x39, 0x18,
-	0x01, 0x27, 0xe7, 0x5c, 0x46, 0xfa, 0x29, 0x33, 0x46, 0xf3, 0x15, 0x7c,
-	0x3f, 0x0c, 0xbd, 0xd8, 0x8f, 0x9f, 0x92, 0x7b, 0xa3, 0x18, 0xeb, 0x28,
-	0x65, 0x2f, 0x2c, 0x89, 0x27, 0x31, 0x8f, 0x7c, 0x9b, 0xdc, 0x2f, 0x5d,
-	0xe9, 0x63, 0x5c, 0xee, 0x7e, 0x89, 0x65, 0xe3, 0x4b, 0x3d, 0xe2, 0x49,
-	0x1b, 0x6c, 0xf9, 0xfc, 0x09, 0x9f, 0x37, 0xfd, 0x5a, 0x0d, 0xa3, 0xbd,
-	0x5d, 0x78, 0x47, 0x91, 0xe7, 0x15, 0xbc, 0x30, 0x78, 0x79, 0x0e, 0x7c,
-	0x28, 0xd3, 0xbc, 0x20, 0x3b, 0xa3, 0x11, 0xb4, 0x21, 0x5f, 0xd1, 0x58,
-	0x22, 0xd9, 0x12, 0x73, 0xb0, 0x98, 0x0f, 0x85, 0x31, 0x9e, 0x21, 0x6e,
-	0x70, 0x8c, 0xed, 0x3c, 0xb7, 0x0b, 0xea, 0x6c, 0xc8, 0x08, 0xeb, 0x28,
-	0xdf, 0x69, 0xcd, 0xa9, 0x60, 0x43, 0xf1, 0xbe, 0x11, 0xc9, 0xe8, 0x72,
-	0x0f, 0xde, 0x77, 0x41, 0xe7, 0x25, 0xfa, 0xef, 0x4c, 0xa1, 0x0d, 0x71,
-	0x26, 0x05, 0x2e, 0xf1, 0xa1, 0x9a, 0x00, 0xbd, 0x99, 0x29, 0xf5, 0xc9,
-	0x84, 0xb9, 0x6f, 0xcf, 0x1c, 0x0b, 0xda, 0x57, 0x30, 0x8c, 0x91, 0x60,
-	0x4c, 0x3d, 0x7b, 0xc6, 0xc4, 0xfe, 0xf8, 0xc1, 0xc7, 0xcd, 0x2c, 0x2f,
-	0x02, 0xa7, 0x16, 0x7f, 0x9b, 0x71, 0x9f, 0x97, 0x6c, 0xb4, 0x5d, 0xfb,
-	0x36, 0x35, 0xec, 0x4b, 0xb6, 0xc4, 0x78, 0xd4, 0xb7, 0x81, 0x43, 0xfb,
-	0x82, 0x3a, 0xb6, 0x15, 0x23, 0x83, 0xb5, 0x4f, 0x6b, 0x3d, 0x64, 0xdd,
-	0x17, 0x25, 0xb3, 0x98, 0x97, 0x49, 0xdd, 0x8f, 0x6b, 0x38, 0xa8, 0x79,
-	0x08, 0x75, 0x35, 0x71, 0x08, 0x6b, 0x99, 0x0c, 0x07, 0x6d, 0xf7, 0x91,
-	0xc9, 0xe3, 0xef, 0xd3, 0x40, 0x67, 0xf1, 0xec, 0x10, 0xf7, 0xa8, 0x5d,
-	0x12, 0xdf, 0x84, 0xbd, 0x2c, 0xb5, 0xea, 0x23, 0xf2, 0x49, 0xe9, 0xb3,
-	0x3e, 0x9e, 0x93, 0xfc, 0xb5, 0x64, 0xca, 0x47, 0x25, 0x7d, 0x7e, 0x3a,
-	0x1d, 0x12, 0xeb, 0xbc, 0xef, 0x67, 0x1f, 0x9d, 0x9e, 0x57, 0x7c, 0x7e,
-	0xf4, 0xfc, 0xba, 0xea, 0x44, 0xdb, 0x08, 0xda, 0x71, 0x1c, 0xa6, 0xe4,
-	0x4a, 0x7f, 0xf7, 0x66, 0x8e, 0x79, 0xde, 0xa4, 0xce, 0xe1, 0x4a, 0x9a,
-	0xf3, 0xaa, 0xc5, 0xcf, 0x1d, 0x29, 0x45, 0x3b, 0xf0, 0xad, 0xa4, 0xb9,
-	0xae, 0x8e, 0x62, 0x3c, 0x2c, 0x1f, 0xa2, 0x4e, 0xc4, 0xb6, 0x85, 0xef,
-	0xb7, 0xa6, 0xd6, 0x54, 0x32, 0x3e, 0xa4, 0xac, 0x74, 0x11, 0xbf, 0x36,
-	0xa5, 0xcf, 0x1e, 0x63, 0x71, 0x05, 0xdd, 0xc5, 0x9c, 0xec, 0xe3, 0x9e,
-	0x37, 0x65, 0xb3, 0x3e, 0x69, 0x46, 0x14, 0xe3, 0x26, 0x5d, 0xfa, 0x8c,
-	0xf2, 0xd2, 0xe1, 0xa4, 0x79, 0x5c, 0x1d, 0x0c, 0xee, 0x53, 0xc0, 0xcc,
-	0xdd, 0xf7, 0x9d, 0x5d, 0x53, 0xa6, 0x5c, 0x2e, 0x25, 0xe3, 0xb3, 0xca,
-	0xca, 0xe3, 0x9d, 0xf9, 0x09, 0x45, 0xdc, 0x48, 0x9a, 0x5d, 0x8a, 0xb1,
-	0xcd, 0x0e, 0x3d, 0xef, 0x29, 0xf4, 0x4f, 0xaa, 0xb6, 0x60, 0x3c, 0xdc,
-	0xaf, 0xcb, 0xfd, 0xbe, 0xce, 0x10, 0x73, 0x06, 0x8c, 0x99, 0x45, 0xe6,
-	0x83, 0xe9, 0x3c, 0x84, 0x74, 0x62, 0x8c, 0xf7, 0x86, 0x3c, 0x38, 0xf9,
-	0x0f, 0xd4, 0xa1, 0x5c, 0x65, 0x9d, 0x13, 0xe8, 0xdb, 0x31, 0xcd, 0x9f,
-	0x1f, 0x9c, 0x2c, 0xe8, 0xfc, 0xc4, 0x1d, 0x95, 0x08, 0xe6, 0xbd, 0xbb,
-	0x67, 0xf1, 0x8c, 0xfb, 0x05, 0xbe, 0x67, 0x31, 0x34, 0xde, 0x21, 0xcc,
-	0x07, 0xcd, 0x55, 0x5a, 0xb2, 0xc1, 0xd8, 0x00, 0xcf, 0xf7, 0x5b, 0x67,
-	0xe5, 0x17, 0xc4, 0x18, 0xeb, 0xdc, 0x23, 0x27, 0xe0, 0x9d, 0xe0, 0xab,
-	0x75, 0xbc, 0xa7, 0xb8, 0x2c, 0x05, 0xbf, 0xbf, 0x74, 0x32, 0xff, 0xb4,
-	0x58, 0xff, 0xbc, 0x77, 0xf8, 0x36, 0x30, 0x87, 0xfb, 0x07, 0x27, 0x29,
-	0x9f, 0x5c, 0x9b, 0xb8, 0x9a, 0xbc, 0xc2, 0xf1, 0x0c, 0x4a, 0x6e, 0x19,
-	0xdc, 0x08, 0xbf, 0xf9, 0x65, 0x7f, 0xdf, 0xd6, 0xc1, 0xb3, 0x73, 0x25,
-	0x53, 0xeb, 0xeb, 0xac, 0xcb, 0xb3, 0x0f, 0xe8, 0x8a, 0xce, 0x7b, 0x62,
-	0x5f, 0xe6, 0x0a, 0x1e, 0xa1, 0x7d, 0x74, 0x6a, 0x12, 0x45, 0x5b, 0x72,
-	0x56, 0xd6, 0x83, 0xbf, 0xc3, 0x66, 0x16, 0x5f, 0x8d, 0x08, 0x30, 0x39,
-	0x15, 0x0f, 0x1d, 0x90, 0x79, 0xd7, 0x95, 0x46, 0xf3, 0x84, 0x5c, 0x6b,
-	0x3a, 0xfa, 0x19, 0xed, 0xd9, 0xc2, 0x6b, 0xfa, 0x5c, 0x3a, 0xfe, 0xa1,
-	0xb2, 0x9c, 0xab, 0xf0, 0x6b, 0xbe, 0x7b, 0x8c, 0x79, 0xc2, 0xe1, 0x81,
-	0x87, 0x79, 0x70, 0xc0, 0x0e, 0x70, 0x8e, 0xb7, 0xc0, 0x39, 0xde, 0x04,
-	0xe7, 0xf8, 0x25, 0x38, 0xf6, 0x8d, 0xca, 0x54, 0x80, 0xff, 0xd3, 0xc0,
-	0x21, 0xda, 0x6a, 0xeb, 0x2c, 0xf6, 0x74, 0xba, 0x00, 0x19, 0xfc, 0x00,
-	0xfe, 0xc7, 0x56, 0x25, 0x23, 0x1b, 0xab, 0x93, 0xb2, 0xb9, 0xea, 0xe7,
-	0x1c, 0xbf, 0xcb, 0x3c, 0xad, 0x51, 0xee, 0x93, 0x03, 0x1c, 0xda, 0x27,
-	0x89, 0xe3, 0xc4, 0x8f, 0x4e, 0x59, 0x2b, 0xaf, 0x69, 0x1c, 0x5a, 0x2b,
-	0xb3, 0x1c, 0x12, 0x9d, 0xf3, 0x75, 0x66, 0x5b, 0x6a, 0xee, 0x16, 0xea,
-	0xbb, 0x99, 0xdb, 0x15, 0xc4, 0xd6, 0x89, 0x97, 0x7f, 0x0e, 0xf6, 0x5e,
-	0xe9, 0x5c, 0xb8, 0x19, 0xf3, 0x00, 0xda, 0xb5, 0xb0, 0x6b, 0xc8, 0x3f,
-	0x27, 0x57, 0x7f, 0x41, 0x1b, 0x7c, 0x03, 0x9c, 0xf1, 0x2a, 0x6c, 0xc8,
-	0x8e, 0x73, 0x40, 0x73, 0xbf, 0x1d, 0xe7, 0x88, 0xce, 0xad, 0xe5, 0x7b,
-	0x8a, 0x65, 0x5b, 0xe6, 0xca, 0x56, 0xbc, 0x00, 0xf9, 0xbb, 0x06, 0xbf,
-	0x6d, 0x03, 0x7b, 0xb0, 0x89, 0xb5, 0xd8, 0x6a, 0xd2, 0xce, 0xbf, 0xaf,
-	0xb1, 0x77, 0xad, 0xf9, 0x27, 0xbc, 0xc7, 0x3a, 0x9b, 0x96, 0x3f, 0xf6,
-	0x13, 0x03, 0x99, 0x8f, 0x97, 0xd5, 0xfd, 0xfd, 0x7e, 0x1b, 0x68, 0xbb,
-	0xd9, 0x24, 0x1e, 0x8b, 0x5c, 0x2c, 0xd9, 0xb0, 0x25, 0x17, 0x63, 0xe4,
-	0x00, 0x55, 0xd5, 0xea, 0xe7, 0x05, 0x63, 0xf6, 0xbc, 0xfd, 0x36, 0xc7,
-	0xe5, 0x04, 0xb8, 0x4d, 0xdb, 0xbf, 0xad, 0xb9, 0x4d, 0xa9, 0xf2, 0xbc,
-	0x5c, 0x5f, 0x4d, 0x05, 0x1c, 0x27, 0x2f, 0x6f, 0x80, 0xe3, 0x35, 0x2b,
-	0xad, 0x1c, 0xed, 0x71, 0xac, 0x53, 0x45, 0xcd, 0x2d, 0x75, 0xc9, 0xa5,
-	0x95, 0xa2, 0xba, 0xbc, 0x52, 0x52, 0xaf, 0x2c, 0x95, 0x55, 0x71, 0xc9,
-	0xf3, 0xfe, 0xe9, 0xce, 0xc8, 0xdb, 0xab, 0x9e, 0x9c, 0x76, 0x8d, 0x81,
-	0x90, 0xb4, 0xf2, 0xdf, 0x3c, 0xaf, 0x13, 0xd8, 0xbc, 0x75, 0xd8, 0xf3,
-	0x9e, 0x18, 0x1d, 0x15, 0xe7, 0x30, 0x39, 0xca, 0x70, 0x8c, 0x39, 0xac,
-	0xc4, 0x9c, 0x8c, 0x6d, 0x9f, 0xaf, 0x29, 0x05, 0x7c, 0x3b, 0xe0, 0xf3,
-	0x97, 0x27, 0xbb, 0x83, 0x33, 0x8f, 0xb3, 0x2f, 0x31, 0x26, 0x1c, 0xfb,
-	0xaf, 0x98, 0xb0, 0x29, 0xe7, 0xca, 0x58, 0x88, 0xae, 0xa8, 0x7c, 0xaf,
-	0x1c, 0x79, 0xac, 0x6c, 0xe2, 0xea, 0x18, 0xc5, 0xf2, 0x7d, 0x6f, 0x48,
-	0xc7, 0xfe, 0xc1, 0x49, 0x4c, 0xcf, 0x9b, 0x75, 0xf9, 0xbd, 0x03, 0x8c,
-	0xc9, 0x98, 0xdd, 0xb0, 0xff, 0xa7, 0xb5, 0x7d, 0xae, 0xaa, 0x8c, 0x4d,
-	0xfd, 0x8e, 0xca, 0x44, 0x19, 0x36, 0x5e, 0x31, 0x2f, 0x94, 0x5c, 0xc1,
-	0x8a, 0xcd, 0x02, 0x3b, 0x66, 0x80, 0x37, 0x4f, 0xeb, 0xb3, 0xd1, 0x43,
-	0x1a, 0x7b, 0xe6, 0x58, 0xce, 0x4b, 0xba, 0xe6, 0xf6, 0xea, 0xf5, 0xbb,
-	0x7d, 0xad, 0x18, 0xf3, 0xf7, 0x1c, 0x7a, 0x9c, 0xe7, 0xf9, 0x40, 0xaf,
-	0x64, 0xd7, 0xcf, 0x40, 0x27, 0x62, 0x58, 0xdb, 0xb0, 0xd6, 0x87, 0x1d,
-	0xd8, 0xef, 0x1d, 0x27, 0x1c, 0x60, 0x6a, 0x27, 0xee, 0xd9, 0x6e, 0x12,
-	0xfd, 0x3a, 0x24, 0xb3, 0xd4, 0xae, 0x71, 0xf5, 0xd1, 0xba, 0x34, 0x78,
-	0x48, 0x0e, 0xe5, 0x10, 0xea, 0xe2, 0x41, 0x99, 0xdc, 0x6b, 0x1a, 0xe5,
-	0x36, 0x5c, 0xd9, 0xe6, 0x28, 0x78, 0x05, 0xae, 0xbf, 0xc0, 0xfb, 0x46,
-	0x31, 0xe6, 0xbc, 0x29, 0xef, 0x9d, 0xa4, 0x2d, 0x71, 0x0c, 0xe6, 0x1a,
-	0xcf, 0xda, 0xb8, 0x36, 0xca, 0x2a, 0xbb, 0xc8, 0x32, 0xae, 0x55, 0xff,
-	0xf9, 0x23, 0x98, 0x84, 0x3e, 0x99, 0x15, 0x1f, 0x93, 0xde, 0xdb, 0xc5,
-	0x24, 0xd6, 0x75, 0xc8, 0xc4, 0x52, 0x5c, 0x9d, 0xba, 0x62, 0x42, 0xde,
-	0xba, 0x24, 0xbb, 0x12, 0xd5, 0x7c, 0xb4, 0x06, 0x59, 0x5c, 0x87, 0x5c,
-	0xad, 0x41, 0xa6, 0x32, 0x65, 0x2b, 0x35, 0xad, 0xe2, 0x3a, 0x2e, 0x30,
-	0x05, 0x79, 0x0d, 0xbf, 0x4a, 0x2e, 0x4a, 0xfd, 0x75, 0xd0, 0x46, 0x68,
-	0x47, 0xd3, 0x61, 0x65, 0x43, 0x0e, 0x21, 0x97, 0x65, 0x5f, 0x7f, 0xdf,
-	0x51, 0x1a, 0x57, 0x53, 0x77, 0x24, 0xe9, 0xdc, 0x11, 0xcb, 0xdd, 0xc1,
-	0xef, 0x37, 0xe2, 0xca, 0x55, 0xe8, 0xfb, 0xeb, 0xf8, 0x4e, 0xf8, 0x35,
-	0x43, 0x8e, 0x0d, 0x6b, 0x9d, 0x4e, 0x49, 0xc8, 0x72, 0x36, 0xc5, 0xd7,
-	0xf1, 0x75, 0xad, 0xe3, 0x90, 0x37, 0x60, 0x90, 0xaf, 0xd3, 0xe9, 0x40,
-	0x46, 0xbf, 0x01, 0xfd, 0xb5, 0xe0, 0x95, 0xc5, 0x65, 0x1e, 0xfa, 0x7f,
-	0x15, 0xcf, 0x6f, 0x36, 0x3f, 0x56, 0x73, 0x8b, 0x2a, 0xc8, 0x3f, 0x79,
-	0x0e, 0x3c, 0xf9, 0xf7, 0x58, 0xbb, 0x1e, 0xcd, 0xdd, 0x13, 0xa3, 0x3c,
-	0x07, 0xfb, 0xb7, 0xba, 0x64, 0x1f, 0x97, 0xdb, 0x23, 0x27, 0x50, 0xee,
-	0xc6, 0xd5, 0xc0, 0x3a, 0x44, 0xf4, 0xf9, 0xf5, 0x5a, 0x69, 0xc4, 0x28,
-	0xea, 0x33, 0xe6, 0x31, 0xf4, 0x25, 0x96, 0x1d, 0xc6, 0x73, 0xc6, 0x65,
-	0x38, 0x37, 0x70, 0x26, 0x15, 0xd3, 0x39, 0xa1, 0x35, 0x70, 0x89, 0x75,
-	0xbc, 0xef, 0x16, 0xe3, 0x7a, 0x0d, 0xe8, 0xf0, 0xc8, 0x67, 0x5e, 0x3a,
-	0xca, 0xbc, 0xf3, 0xf7, 0x63, 0xbe, 0xfd, 0xfb, 0xc4, 0xbb, 0x6d, 0xcf,
-	0xa5, 0x0c, 0xdc, 0x7c, 0x60, 0x02, 0xef, 0xc8, 0xdb, 0x61, 0x8b, 0xaa,
-	0x5a, 0x7e, 0xd9, 0xce, 0xef, 0x5b, 0x6c, 0x24, 0xcd, 0x77, 0xc5, 0xef,
-	0x3b, 0x6f, 0xd3, 0xee, 0x74, 0x00, 0x5f, 0xe2, 0x9a, 0x57, 0xde, 0xb2,
-	0x0b, 0x40, 0x05, 0x2b, 0x3e, 0x05, 0x19, 0x6d, 0x17, 0xcb, 0xc9, 0xc9,
-	0xc3, 0xef, 0xce, 0xea, 0xbe, 0x6c, 0xdb, 0xea, 0xdb, 0xfa, 0x2e, 0xc7,
-	0xcf, 0xb9, 0x70, 0x0e, 0xf0, 0x6d, 0x4c, 0x53, 0xcb, 0xe8, 0x4e, 0xc3,
-	0x18, 0xf0, 0x65, 0xb4, 0x35, 0x8f, 0xe8, 0xff, 0x99, 0x07, 0xe5, 0x64,
-	0xc4, 0xf0, 0xcf, 0xdb, 0x71, 0x6d, 0x70, 0x3d, 0x3f, 0x06, 0xbf, 0xdf,
-	0x2b, 0x3f, 0xad, 0x38, 0xa3, 0x2f, 0x3f, 0x4f, 0xec, 0xca, 0x0f, 0x7d,
-	0xd4, 0x2e, 0xc9, 0xad, 0xd8, 0x32, 0x59, 0xd6, 0xfb, 0x0d, 0xae, 0xc9,
-	0xf8, 0xd1, 0x09, 0xc8, 0x0d, 0x65, 0x9d, 0xba, 0x65, 0x4a, 0x15, 0x72,
-	0x54, 0x05, 0x3e, 0x55, 0x21, 0x53, 0xe4, 0x40, 0x55, 0xe0, 0x5b, 0xb5,
-	0x69, 0x39, 0x75, 0xcc, 0x99, 0x36, 0x7b, 0x1d, 0x72, 0x74, 0xb5, 0xc9,
-	0xfd, 0xd7, 0x63, 0x36, 0x69, 0x07, 0x6f, 0xee, 0xee, 0xfd, 0xa7, 0xd8,
-	0xfb, 0x23, 0x72, 0x0d, 0x7e, 0xcb, 0xf5, 0xca, 0x08, 0x30, 0x49, 0x80,
-	0x51, 0x2e, 0x64, 0x23, 0x25, 0x1b, 0x95, 0x71, 0xd9, 0x84, 0x7d, 0xda,
-	0x5a, 0x4d, 0x80, 0x4f, 0x03, 0x47, 0xaf, 0x1c, 0x93, 0x37, 0x56, 0x95,
-	0xcc, 0xd8, 0xb0, 0x33, 0x6b, 0x8c, 0xc1, 0x43, 0x9e, 0xab, 0x5d, 0xfa,
-	0xbc, 0x7d, 0xa2, 0xee, 0xc7, 0xe2, 0x73, 0xf5, 0x1e, 0x99, 0xac, 0x9b,
-	0xf2, 0x54, 0xbd, 0x57, 0xbe, 0x5a, 0x8f, 0xca, 0xe9, 0x46, 0x4c, 0xbe,
-	0x56, 0x1f, 0x94, 0xa7, 0xeb, 0x47, 0xe4, 0x99, 0x46, 0x5c, 0xbe, 0x0e,
-	0xbf, 0x30, 0xdf, 0x70, 0x64, 0xaa, 0x31, 0x22, 0xa7, 0x1a, 0x8c, 0xb1,
-	0xe3, 0x7b, 0xf8, 0x65, 0x77, 0x63, 0x17, 0x1c, 0x57, 0x27, 0xc6, 0xe5,
-	0xa8, 0x9c, 0x3e, 0x6f, 0x94, 0xbc, 0x1f, 0xff, 0x10, 0x79, 0x01, 0x7d,
-	0x17, 0xae, 0x28, 0xa9, 0xe9, 0xef, 0xb7, 0xfe, 0x47, 0x24, 0xa2, 0x7d,
-	0xa3, 0x17, 0xaa, 0x83, 0x68, 0x63, 0xd3, 0x27, 0x09, 0xe2, 0x20, 0xad,
-	0xf8, 0x7f, 0xcb, 0xf7, 0x32, 0x74, 0x0c, 0xfb, 0x26, 0x7d, 0x2f, 0xbd,
-	0xf6, 0xc4, 0x0f, 0xfa, 0x39, 0xf4, 0xb5, 0xf6, 0x9e, 0x51, 0xb4, 0xbe,
-	0xbb, 0x90, 0x7f, 0xf4, 0x7f, 0x51, 0xfc, 0xb3, 0xa6, 0x73, 0x8d, 0x41,
-	0xfe, 0x4f, 0x0a, 0xc6, 0xf2, 0xf9, 0xf9, 0xdd, 0x93, 0x95, 0x09, 0xf5,
-	0x54, 0x85, 0x8c, 0xc6, 0x93, 0x85, 0xdd, 0x3c, 0xba, 0xaf, 0xc8, 0x9a,
-	0x1b, 0xd1, 0x63, 0xf0, 0xe3, 0xf6, 0x69, 0x9d, 0x53, 0x37, 0x31, 0x4c,
-	0xf9, 0xe3, 0x19, 0x5a, 0x4f, 0x70, 0xb6, 0x00, 0x6e, 0xeb, 0x9a, 0x72,
-	0xb1, 0xee, 0xc7, 0xaf, 0xe6, 0xb4, 0xbc, 0x5c, 0x87, 0xcc, 0xf1, 0xfc,
-	0xc1, 0xbf, 0x16, 0xaa, 0x7e, 0xdf, 0xec, 0xb0, 0x43, 0x7f, 0x1c, 0xf3,
-	0x35, 0x7a, 0xf9, 0x2d, 0xfe, 0x4f, 0x0e, 0xca, 0xc1, 0x78, 0x99, 0x0f,
-	0x6c, 0x6b, 0x59, 0xf4, 0xcf, 0x67, 0x1d, 0x79, 0x11, 0x7b, 0x51, 0x33,
-	0x39, 0xfe, 0x4e, 0xa9, 0x39, 0xf4, 0x6d, 0x89, 0xdf, 0xc3, 0x52, 0xc5,
-	0x77, 0x6a, 0x4e, 0x2b, 0x36, 0xe6, 0xe3, 0x6c, 0xcd, 0x7c, 0xf8, 0xdd,
-	0xe9, 0xea, 0x41, 0xdc, 0xa3, 0xce, 0x01, 0x67, 0x3a, 0xc3, 0xfb, 0x05,
-	0x94, 0x19, 0x1b, 0x99, 0xc3, 0x35, 0x16, 0xd4, 0xfd, 0x7c, 0x40, 0x73,
-	0xf5, 0xf1, 0x87, 0xfd, 0x66, 0xaa, 0x56, 0x21, 0x13, 0xba, 0xab, 0x8c,
-	0x9f, 0xad, 0x0f, 0x10, 0x73, 0x0f, 0xda, 0xfc, 0x45, 0xe4, 0x6f, 0xa6,
-	0x8e, 0x29, 0x04, 0xcf, 0xf6, 0xc9, 0xb3, 0x26, 0x73, 0xcd, 0xd3, 0x6a,
-	0xa2, 0xf2, 0x72, 0x90, 0x57, 0x7b, 0x57, 0x1d, 0xac, 0x35, 0x07, 0xfc,
-	0xbc, 0x74, 0xbe, 0x7b, 0x6f, 0x2e, 0xfa, 0x5e, 0x39, 0x61, 0x4e, 0x7a,
-	0x07, 0x78, 0xab, 0x36, 0x62, 0xd0, 0x41, 0xe0, 0x9d, 0xdd, 0xa6, 0xf5,
-	0xb1, 0xd8, 0xf8, 0x97, 0xb7, 0xad, 0xf5, 0xb9, 0x15, 0x63, 0xb8, 0x35,
-	0x40, 0xdf, 0x96, 0xb8, 0x71, 0xd1, 0x8f, 0x1b, 0x69, 0x1f, 0x1a, 0x58,
-	0x81, 0x3a, 0xea, 0x2a, 0xf4, 0x64, 0xb7, 0x2d, 0xff, 0xfe, 0x03, 0x7d,
-	0xe7, 0x95, 0xf0, 0x2c, 0x67, 0x00, 0x00, 0x00 };
+	0xec, 0x5b, 0x6d, 0x6c, 0x5c, 0x57, 0x5a, 0x7e, 0xef, 0x99, 0xb1, 0x3d,
+	0x76, 0x6c, 0xe7, 0xda, 0x99, 0xa6, 0x93, 0xe2, 0x6e, 0x67, 0xec, 0x6b,
+	0x7b, 0xba, 0x36, 0xe5, 0x3a, 0x4c, 0x5b, 0xaf, 0x18, 0xb6, 0xc3, 0x1d,
+	0x27, 0x75, 0x77, 0x83, 0xe4, 0xb6, 0x61, 0x37, 0x82, 0xae, 0xb0, 0x66,
+	0x12, 0x51, 0x84, 0x10, 0x21, 0x82, 0xaa, 0x2c, 0x5d, 0x65, 0x34, 0x76,
+	0x53, 0xb7, 0x3b, 0xf1, 0x0c, 0x89, 0x4b, 0xf8, 0xd8, 0x1f, 0xee, 0xd8,
+	0x4e, 0x0a, 0x9a, 0x78, 0xba, 0xcb, 0x8f, 0x5d, 0x56, 0x4d, 0x63, 0xd2,
+	0x12, 0xfa, 0x03, 0x89, 0x16, 0x56, 0x50, 0x89, 0x85, 0x86, 0x24, 0xdb,
+	0x14, 0x09, 0x41, 0x77, 0x01, 0x6d, 0xa1, 0x69, 0x2f, 0xcf, 0x73, 0xee,
+	0xbd, 0xc9, 0xc4, 0x35, 0x6c, 0x7f, 0xf0, 0xf3, 0x1e, 0xc9, 0xba, 0xf7,
+	0x9e, 0xf3, 0x9e, 0xf7, 0xbc, 0xdf, 0x1f, 0x67, 0x92, 0xdf, 0xe8, 0x96,
+	0x2e, 0xf1, 0x47, 0x0f, 0xfe, 0x32, 0x87, 0x9f, 0x3c, 0x72, 0xef, 0x3d,
+	0xf6, 0x3d, 0xfc, 0x8e, 0xb4, 0x49, 0x94, 0x4f, 0x43, 0xc2, 0x11, 0x8e,
+	0x70, 0x84, 0x23, 0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70,
+	0x84, 0x23, 0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84,
+	0x23, 0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84, 0x23,
+	0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84, 0x23, 0x1c,
+	0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84, 0x23, 0x1c, 0xe1,
+	0x08, 0x47, 0x38, 0xc2, 0xf1, 0xff, 0x39, 0x22, 0x22, 0x26, 0x9f, 0x3d,
+	0xfe, 0x9f, 0xc4, 0x54, 0x56, 0x8e, 0x38, 0x96, 0xc4, 0x22, 0xd9, 0xd5,
+	0x27, 0x8a, 0x96, 0x48, 0xae, 0x31, 0x96, 0xcc, 0xcb, 0x87, 0x6e, 0x29,
+	0x1e, 0x15, 0xce, 0xdf, 0x99, 0xbd, 0x7e, 0xf4, 0xdc, 0xfd, 0xa9, 0xf7,
+	0x96, 0x23, 0x12, 0x33, 0xb3, 0x6f, 0x4c, 0x98, 0x23, 0x12, 0x1b, 0xc0,
+	0x9e, 0xaf, 0x8d, 0xbe, 0xbc, 0x5d, 0x7a, 0x03, 0x5c, 0x22, 0xf5, 0x4a,
+	0xca, 0xde, 0x2b, 0x63, 0xe6, 0x05, 0x89, 0x4a, 0x0e, 0x67, 0x9c, 0x6e,
+	0x88, 0x94, 0x2b, 0x06, 0x71, 0x48, 0xb9, 0x11, 0x93, 0x4b, 0x11, 0x42,
+	0x7d, 0xcb, 0x70, 0xaa, 0x1f, 0xb9, 0xb9, 0x28, 0xce, 0xb5, 0xf0, 0xde,
+	0x0c, 0xe6, 0x63, 0xa2, 0xb2, 0xa9, 0x84, 0x13, 0x99, 0x96, 0xc2, 0x92,
+	0xeb, 0xce, 0xdb, 0xb7, 0x03, 0x47, 0xbf, 0xcc, 0x5b, 0xde, 0xb7, 0x63,
+	0x7f, 0xda, 0x9c, 0x92, 0x1d, 0x98, 0x8b, 0x88, 0xb2, 0xee, 0xc0, 0xdf,
+	0x57, 0x0d, 0x67, 0xa5, 0x5b, 0xca, 0x55, 0xc9, 0x39, 0x76, 0x0c, 0xf3,
+	0x09, 0x99, 0xab, 0x26, 0x0d, 0xe7, 0xa4, 0x21, 0xc5, 0x0c, 0xde, 0x9b,
+	0xae, 0x38, 0xf6, 0x47, 0xae, 0x63, 0x11, 0xff, 0x92, 0xe1, 0x9c, 0xf9,
+	0xc8, 0x55, 0x96, 0x65, 0x16, 0x84, 0xdf, 0x09, 0x29, 0x37, 0x89, 0x87,
+	0xef, 0xc4, 0x73, 0xc9, 0x3d, 0x37, 0x9a, 0x90, 0x6f, 0x34, 0xe3, 0xf2,
+	0xf5, 0xa6, 0x29, 0x2f, 0x35, 0x07, 0xe4, 0x7c, 0xd3, 0x75, 0xbf, 0x6e,
+	0xbb, 0xee, 0x1b, 0xf8, 0xfb, 0x81, 0x7d, 0x83, 0x66, 0x8c, 0x92, 0x31,
+	0xd5, 0xfc, 0xc3, 0x6e, 0xe9, 0x4d, 0x25, 0x45, 0x75, 0xe3, 0xcc, 0x84,
+	0xcc, 0x57, 0x2b, 0xc6, 0xc3, 0x67, 0x16, 0x8d, 0x99, 0x33, 0x35, 0x23,
+	0x7f, 0x26, 0x8a, 0x39, 0x29, 0x95, 0xed, 0x17, 0x8d, 0x7c, 0x73, 0xc1,
+	0x78, 0xe4, 0x4c, 0xaf, 0xa6, 0xad, 0x5c, 0xdd, 0x09, 0xda, 0xae, 0x83,
+	0x26, 0xca, 0x34, 0x65, 0xfe, 0x3c, 0xc4, 0xec, 0x54, 0xc8, 0x57, 0xbb,
+	0xe4, 0xe2, 0x5c, 0x77, 0x5d, 0x95, 0x75, 0x8f, 0x3a, 0x19, 0xcb, 0x2c,
+	0x0b, 0xe9, 0xd3, 0x73, 0xe7, 0x23, 0xa0, 0x39, 0x2f, 0xa7, 0x41, 0x7f,
+	0xb7, 0x91, 0x3f, 0x15, 0x05, 0x1d, 0x32, 0x10, 0x11, 0xee, 0x1b, 0x4e,
+	0x14, 0xa4, 0x81, 0x33, 0xc4, 0x54, 0x59, 0xca, 0x11, 0x34, 0x83, 0x96,
+	0x6f, 0x54, 0xc1, 0x43, 0x15, 0x3c, 0x54, 0xc9, 0x5b, 0x52, 0xce, 0x8d,
+	0x06, 0xbc, 0xb9, 0xee, 0x5f, 0xdb, 0xa4, 0x3d, 0x95, 0xcc, 0xa9, 0x80,
+	0x4f, 0xd7, 0xfd, 0xbe, 0x4d, 0x5e, 0xc9, 0x8f, 0xeb, 0xbe, 0x64, 0x53,
+	0x86, 0xee, 0x79, 0x65, 0x55, 0xc0, 0x8b, 0x05, 0xfc, 0x94, 0xef, 0x22,
+	0x78, 0x58, 0x00, 0x7f, 0xa7, 0xc1, 0x5b, 0x0d, 0x74, 0xfc, 0xa8, 0xf3,
+	0x4a, 0x46, 0x7e, 0xf4, 0x86, 0xbc, 0x92, 0x94, 0x71, 0x61, 0x55, 0x41,
+	0xd6, 0xdb, 0xa4, 0xb0, 0x6c, 0xca, 0xec, 0x6a, 0xb0, 0x3f, 0xd0, 0xfb,
+	0x61, 0xd9, 0x57, 0xed, 0x87, 0x6c, 0x28, 0xcb, 0x94, 0x2d, 0x42, 0xbd,
+	0x95, 0xd3, 0x4a, 0xc4, 0x28, 0xd8, 0x47, 0xb5, 0xbe, 0x57, 0x2d, 0xc9,
+	0x15, 0x6c, 0xca, 0x51, 0x92, 0x05, 0xbb, 0x94, 0x88, 0xc2, 0xbe, 0x56,
+	0xad, 0x92, 0x19, 0x15, 0xca, 0x31, 0x95, 0xf8, 0x32, 0x64, 0x79, 0xa8,
+	0x22, 0xb9, 0xcf, 0x55, 0x02, 0x19, 0x7b, 0xf2, 0xfd, 0x7c, 0xe5, 0xa7,
+	0x7b, 0xa4, 0x4b, 0x7d, 0xaa, 0x4d, 0x7e, 0x15, 0x7b, 0x89, 0xfb, 0x96,
+	0xbd, 0xd8, 0xe7, 0xc1, 0x79, 0x7b, 0x53, 0x07, 0x44, 0x08, 0x5b, 0x1e,
+	0x6a, 0xf3, 0x7c, 0xc2, 0x70, 0xac, 0x52, 0x22, 0x02, 0xb8, 0x82, 0x94,
+	0x27, 0xfc, 0xb9, 0x36, 0xc7, 0xba, 0x1e, 0x99, 0xb7, 0x53, 0xc9, 0xb2,
+	0x5c, 0x8f, 0x5c, 0xb4, 0xf5, 0x5c, 0xa7, 0x63, 0xb9, 0xb2, 0x06, 0xec,
+	0xcf, 0xc0, 0xfe, 0x2f, 0x80, 0xa3, 0x5f, 0xae, 0xe8, 0xf9, 0x1e, 0xec,
+	0x4f, 0xb7, 0x01, 0x67, 0x97, 0xa4, 0xd2, 0x75, 0xcc, 0x5f, 0xf4, 0xe6,
+	0xfb, 0x3c, 0xbc, 0xe5, 0xa1, 0x2e, 0x8d, 0x5b, 0xe4, 0x45, 0x6f, 0xfe,
+	0x36, 0x0f, 0x77, 0xf9, 0x6e, 0xcc, 0x03, 0xff, 0xc8, 0xf4, 0xa8, 0xa1,
+	0xe7, 0x77, 0xd1, 0x7f, 0x7e, 0xa9, 0x72, 0x3d, 0xb2, 0x66, 0xbb, 0x92,
+	0x9f, 0x18, 0x99, 0x1e, 0x31, 0x3c, 0x7c, 0xc7, 0xbc, 0x7d, 0x77, 0x7a,
+	0xf8, 0x46, 0xa6, 0xd3, 0x86, 0x87, 0x6f, 0xb5, 0xa2, 0xf7, 0x4a, 0xa1,
+	0x42, 0xd8, 0x91, 0x69, 0xcb, 0xb8, 0x53, 0x66, 0xfb, 0x46, 0xa6, 0x07,
+	0x0d, 0xf5, 0xa9, 0x6d, 0x1e, 0x1f, 0xa9, 0x80, 0x86, 0x6d, 0x9a, 0x06,
+	0x9e, 0xab, 0xe7, 0x87, 0x1d, 0xab, 0x7c, 0xf7, 0x36, 0x7d, 0x3e, 0xcf,
+	0xd4, 0x73, 0x77, 0x93, 0x2e, 0x9e, 0x5d, 0x9c, 0xb8, 0xe5, 0xdc, 0x1f,
+	0xbf, 0x29, 0x9f, 0xad, 0xce, 0xe4, 0x79, 0x12, 0x8b, 0x66, 0xa3, 0x13,
+	0xf3, 0x95, 0xc3, 0xe2, 0x54, 0x93, 0x32, 0x37, 0xde, 0x29, 0xb3, 0xe6,
+	0xd0, 0xec, 0x3e, 0x61, 0xac, 0x89, 0x4d, 0x14, 0x7d, 0x1d, 0xe6, 0xc5,
+	0x90, 0x39, 0xf0, 0xb8, 0xaf, 0x21, 0x31, 0x03, 0xf0, 0x43, 0x8d, 0xa8,
+	0x3c, 0xdb, 0x34, 0xa4, 0x5d, 0xfb, 0x67, 0xca, 0xdc, 0x80, 0x1d, 0x3e,
+	0x5d, 0xa5, 0x1d, 0xd3, 0x66, 0x25, 0x57, 0x87, 0x9d, 0x9e, 0xd7, 0xbe,
+	0xda, 0x45, 0xbd, 0x96, 0x4a, 0x02, 0x57, 0xcc, 0x5a, 0x66, 0x5d, 0x3a,
+	0x24, 0x37, 0x23, 0x25, 0xae, 0xfb, 0xbe, 0x93, 0x58, 0x91, 0x73, 0xb0,
+	0x01, 0x31, 0x9d, 0x0c, 0xe7, 0x09, 0xdf, 0x02, 0x6b, 0x7a, 0x7e, 0x17,
+	0x81, 0xdf, 0x15, 0x33, 0x84, 0x95, 0x92, 0x93, 0xa1, 0xef, 0xc1, 0x16,
+	0x9b, 0xbb, 0x7a, 0xbc, 0xd8, 0x86, 0xd8, 0x12, 0xef, 0x86, 0x8f, 0x7f,
+	0x0a, 0xfe, 0x37, 0x60, 0x38, 0xa7, 0x5c, 0xb7, 0x68, 0x4b, 0x5c, 0x09,
+	0xfd, 0x0f, 0xbe, 0xde, 0xe4, 0x5a, 0x37, 0xe6, 0xc5, 0x9c, 0xb3, 0xfb,
+	0xc0, 0x9f, 0xeb, 0x4e, 0xdb, 0x49, 0x29, 0xdb, 0xdb, 0xb1, 0xaf, 0x4d,
+	0xfa, 0x2c, 0xda, 0x3b, 0x7d, 0x7a, 0x1b, 0xce, 0x33, 0xf8, 0xdd, 0x8b,
+	0xf3, 0x7a, 0x30, 0x97, 0x98, 0xa3, 0x1f, 0x67, 0xc6, 0xc0, 0xbf, 0x17,
+	0x2f, 0x45, 0xde, 0x06, 0xad, 0xdc, 0xa3, 0xe1, 0x62, 0x1d, 0xd9, 0x8c,
+	0x5c, 0xab, 0xec, 0x92, 0x4b, 0x71, 0xf2, 0x0f, 0x9c, 0x55, 0xc4, 0xc4,
+	0xb8, 0x01, 0xfa, 0x13, 0x7e, 0xdc, 0xdb, 0xe1, 0x7f, 0x1b, 0x77, 0x79,
+	0x67, 0x88, 0x19, 0xc9, 0xf6, 0x4a, 0x5e, 0xcf, 0x89, 0x52, 0x13, 0xdb,
+	0xfc, 0xf5, 0x5e, 0x63, 0xef, 0x29, 0x25, 0xa3, 0xf7, 0x21, 0x66, 0xe1,
+	0xac, 0x8b, 0x96, 0xeb, 0x5e, 0xb4, 0xbf, 0x0f, 0x9f, 0x57, 0xd2, 0x66,
+	0xfd, 0x63, 0xaf, 0x74, 0x41, 0x9e, 0x55, 0xa3, 0x45, 0x86, 0x09, 0x39,
+	0x56, 0xe5, 0x9e, 0x92, 0x44, 0x2d, 0xc2, 0x10, 0xfe, 0xef, 0x01, 0x17,
+	0x91, 0x0e, 0xf8, 0xe2, 0x05, 0x3b, 0x4e, 0x7a, 0xb7, 0x7b, 0xf0, 0x7d,
+	0x38, 0x83, 0xb4, 0xd3, 0xf7, 0x5c, 0xed, 0x7b, 0x4e, 0x44, 0xe5, 0xa6,
+	0x96, 0xe0, 0x49, 0xe3, 0x94, 0xb7, 0xd3, 0x87, 0x50, 0x2f, 0x73, 0xa3,
+	0x25, 0x53, 0x69, 0x5d, 0x8b, 0xe4, 0x2b, 0x77, 0xc9, 0xbc, 0x8d, 0xf3,
+	0xac, 0x28, 0x68, 0x66, 0x9c, 0x19, 0x2e, 0x45, 0x14, 0x3c, 0xac, 0x9f,
+	0xb2, 0x0a, 0x68, 0x7d, 0x0b, 0xe7, 0x95, 0x8c, 0xa8, 0xc5, 0x33, 0xbe,
+	0xe4, 0xcb, 0x87, 0x76, 0x67, 0x8b, 0x53, 0xe9, 0xe6, 0x37, 0xe8, 0xe8,
+	0xd2, 0x74, 0x44, 0xb2, 0x5a, 0x77, 0x86, 0xca, 0x52, 0x96, 0x6d, 0x3e,
+	0x3d, 0xb7, 0xe0, 0x01, 0x1f, 0xdc, 0x6b, 0x61, 0x6f, 0x0c, 0x34, 0xf6,
+	0xb4, 0xd0, 0xdf, 0x45, 0x78, 0xc8, 0x2a, 0xe6, 0x9f, 0xa1, 0xf9, 0x36,
+	0x3c, 0xbe, 0x03, 0x59, 0x7d, 0x1b, 0xb2, 0xfa, 0xc0, 0x1d, 0xdd, 0x4d,
+	0x1c, 0x19, 0xe0, 0x60, 0x1e, 0x62, 0xbc, 0x62, 0x8c, 0x32, 0x6f, 0xe0,
+	0x82, 0x1f, 0xa8, 0x48, 0xb6, 0x5b, 0xf2, 0xa6, 0xce, 0x01, 0x80, 0x9d,
+	0x14, 0x1d, 0xe3, 0x2d, 0xf2, 0xe8, 0x7f, 0x5b, 0x29, 0x6d, 0x37, 0x85,
+	0x1a, 0xf3, 0xc0, 0x57, 0x40, 0xdb, 0x46, 0x4a, 0x69, 0xd6, 0xba, 0x21,
+	0x73, 0x89, 0xb5, 0x65, 0xdf, 0x90, 0xb5, 0x8a, 0xda, 0xd9, 0x2e, 0xdb,
+	0x65, 0x06, 0x32, 0xaa, 0x4f, 0x22, 0x7f, 0x8e, 0x77, 0x4b, 0xe4, 0x1e,
+	0xe6, 0x81, 0x04, 0x68, 0xdd, 0x48, 0x99, 0x72, 0xdd, 0x55, 0x23, 0xd8,
+	0x3f, 0x0e, 0x3d, 0xec, 0xa7, 0x4e, 0x95, 0x0f, 0x47, 0x98, 0x08, 0x65,
+	0xde, 0xdf, 0x2e, 0xc4, 0xcd, 0xb5, 0xb1, 0x84, 0x29, 0x9c, 0xef, 0x84,
+	0x5e, 0xb9, 0x97, 0xfc, 0x79, 0x7b, 0x3e, 0xce, 0x5f, 0xb0, 0x4e, 0x99,
+	0x51, 0x76, 0xb0, 0x31, 0xf0, 0xe8, 0xd8, 0x3f, 0xeb, 0xcb, 0xe6, 0x76,
+	0xb9, 0x64, 0x8a, 0x51, 0xb7, 0x6f, 0x6b, 0x91, 0x1f, 0x79, 0xee, 0xdb,
+	0xc4, 0x33, 0x71, 0x6c, 0xcd, 0xf7, 0xc1, 0x1a, 0xcf, 0xf4, 0xce, 0x9e,
+	0xb7, 0x36, 0x52, 0x51, 0xb9, 0x55, 0xbe, 0xd0, 0xa5, 0x14, 0x2b, 0xb4,
+	0x8d, 0x76, 0x29, 0xa0, 0xfe, 0xb0, 0x77, 0x23, 0xa8, 0x3c, 0xa2, 0x64,
+	0xe2, 0x3e, 0xe2, 0xfc, 0x3b, 0xf2, 0x34, 0x99, 0x54, 0x86, 0x14, 0xec,
+	0xce, 0x16, 0x7d, 0x71, 0xae, 0xd5, 0xb6, 0xbf, 0xed, 0xdb, 0xf6, 0x07,
+	0xee, 0xc4, 0xee, 0x40, 0xef, 0x90, 0xd7, 0xc7, 0xf6, 0x08, 0xf4, 0xfc,
+	0x7f, 0xed, 0xa1, 0xad, 0xc4, 0x36, 0xed, 0x29, 0x6d, 0xb1, 0x67, 0x87,
+	0xc8, 0x17, 0xe8, 0x43, 0x3d, 0x7e, 0xcc, 0x08, 0x7c, 0x2a, 0xc0, 0x03,
+	0xdd, 0x68, 0x5b, 0xe5, 0xdc, 0x56, 0xbe, 0x48, 0x1c, 0xc4, 0xc5, 0xbd,
+	0x84, 0x09, 0x72, 0x2a, 0xd4, 0x21, 0x5b, 0xe6, 0x55, 0x8c, 0x69, 0xbc,
+	0x2b, 0xc4, 0xa1, 0xd6, 0xfc, 0xca, 0x39, 0x13, 0xdf, 0x53, 0x78, 0x5a,
+	0x52, 0x68, 0xd0, 0x9f, 0xb8, 0x9f, 0xf9, 0xf6, 0x5d, 0x3f, 0x7e, 0x76,
+	0xcf, 0x46, 0xb3, 0x71, 0xc4, 0x4f, 0x99, 0x29, 0x57, 0x8e, 0xba, 0x11,
+	0x4b, 0x4a, 0x77, 0x64, 0x69, 0x1f, 0xdd, 0x93, 0x88, 0x91, 0x33, 0xe5,
+	0x06, 0xeb, 0x22, 0x84, 0x31, 0xec, 0x43, 0x8e, 0x8e, 0xa9, 0xc5, 0x58,
+	0xe9, 0xc7, 0xb2, 0x8c, 0xcb, 0x49, 0x49, 0x36, 0xde, 0x43, 0xdd, 0x61,
+	0x8a, 0xa3, 0x6d, 0xed, 0xf9, 0x5d, 0xa4, 0xb7, 0x8c, 0x1a, 0x22, 0x9a,
+	0x95, 0xa8, 0xca, 0xb6, 0xc7, 0xe6, 0x32, 0xdd, 0xe2, 0x64, 0xa6, 0x77,
+	0xa9, 0xf5, 0x7d, 0xbb, 0x22, 0xeb, 0x3b, 0x67, 0xdb, 0xb2, 0xa5, 0x5d,
+	0x6a, 0x51, 0x64, 0xa5, 0x22, 0x0a, 0x75, 0x4d, 0xe2, 0xa0, 0xe0, 0x7b,
+	0xfd, 0xd1, 0x47, 0x55, 0x36, 0x02, 0xdd, 0xca, 0x53, 0xab, 0x99, 0x28,
+	0x6b, 0xc6, 0xe4, 0x8c, 0x3c, 0x85, 0x3a, 0xf1, 0x49, 0x99, 0xab, 0x80,
+	0x2e, 0xcd, 0x77, 0x02, 0xfc, 0x0e, 0x00, 0x37, 0x69, 0x8f, 0x23, 0xc6,
+	0x7a, 0xb4, 0x83, 0xe6, 0x5c, 0x9e, 0x75, 0x52, 0x86, 0x79, 0xe5, 0x3d,
+	0xd8, 0x0f, 0xfd, 0xe5, 0x5f, 0x64, 0xcd, 0xea, 0x94, 0x82, 0x17, 0x1f,
+	0x68, 0xaf, 0x58, 0x7b, 0xd7, 0x5f, 0xbb, 0x8a, 0x35, 0xda, 0xef, 0xb6,
+	0x16, 0x1d, 0x7e, 0x55, 0xd7, 0x3a, 0x17, 0x6d, 0xbe, 0x13, 0xf6, 0x2f,
+	0x27, 0x3c, 0xd8, 0xd7, 0x27, 0xd6, 0xac, 0x47, 0xb7, 0x4b, 0x97, 0x49,
+	0xbd, 0xe1, 0x9c, 0x38, 0x63, 0x2c, 0xd6, 0x2f, 0xf9, 0xb8, 0xbe, 0x0b,
+	0x5c, 0xdd, 0xa4, 0x1b, 0x23, 0x8a, 0x75, 0xd0, 0x87, 0x9a, 0xa7, 0x70,
+	0x23, 0xd6, 0x10, 0xf6, 0x65, 0x1f, 0xd7, 0xb7, 0x5a, 0x70, 0x71, 0x8d,
+	0x4f, 0x9e, 0x89, 0xb3, 0xbb, 0xc8, 0x1b, 0xf9, 0xa1, 0x0e, 0xa8, 0x8f,
+	0xb4, 0x31, 0x83, 0xd8, 0x3e, 0xd3, 0xd4, 0xb5, 0x9d, 0x91, 0xaf, 0xa2,
+	0xe6, 0x6a, 0x3e, 0x0f, 0x1a, 0x59, 0xc3, 0x0e, 0xfa, 0xf5, 0x35, 0xed,
+	0x68, 0x43, 0xdb, 0x23, 0xe3, 0x4e, 0x59, 0xdb, 0xd5, 0x6b, 0x9e, 0x5d,
+	0x59, 0xd4, 0xcd, 0x6b, 0x32, 0xd8, 0xa8, 0x6c, 0xf7, 0xfe, 0xaf, 0xb6,
+	0x29, 0x11, 0xad, 0x4f, 0xe6, 0x37, 0xda, 0xd8, 0xed, 0x88, 0xeb, 0xee,
+	0x0f, 0x99, 0x67, 0x66, 0x98, 0x83, 0x66, 0x98, 0x3b, 0x0c, 0x3f, 0x1e,
+	0x26, 0x5b, 0x70, 0x24, 0x81, 0xa3, 0xee, 0xdb, 0xef, 0x73, 0x3e, 0xae,
+	0xa0, 0xfe, 0x0c, 0x62, 0xea, 0xef, 0xdf, 0x71, 0xeb, 0xfa, 0x47, 0x3e,
+	0x7d, 0xed, 0x3a, 0x1e, 0xc3, 0xd6, 0x41, 0x7f, 0x72, 0x56, 0xc1, 0xbe,
+	0xf2, 0x0d, 0x4f, 0x1f, 0xf0, 0x7d, 0xd8, 0x1e, 0x5f, 0x03, 0xdd, 0x7a,
+	0xf5, 0xb7, 0x27, 0x03, 0xea, 0x34, 0x47, 0xbe, 0x73, 0x51, 0xd2, 0xd2,
+	0x9c, 0xc6, 0x7e, 0x39, 0xcc, 0xdc, 0x58, 0x00, 0x1f, 0x07, 0xcd, 0x31,
+	0x73, 0x8e, 0xb8, 0xe3, 0x02, 0x9c, 0xa8, 0x25, 0xb3, 0x1d, 0xbe, 0x9e,
+	0xbf, 0xc9, 0xf3, 0x81, 0x7b, 0x1b, 0xbf, 0xf1, 0xfc, 0xa6, 0x4f, 0xcf,
+	0x95, 0x5e, 0x8f, 0x9e, 0x60, 0x7d, 0xd0, 0xbc, 0xf5, 0xbb, 0xbe, 0xcb,
+	0x97, 0x27, 0xde, 0x9f, 0xf4, 0xe9, 0xa2, 0x6e, 0x5a, 0x69, 0xa2, 0x5e,
+	0xfe, 0x1d, 0x78, 0x74, 0xad, 0x51, 0x52, 0x59, 0xd4, 0x2e, 0x19, 0xe6,
+	0xac, 0xd4, 0x64, 0x4e, 0x2c, 0xe8, 0x24, 0x65, 0xcf, 0x62, 0xd7, 0xbb,
+	0x15, 0xea, 0xf9, 0x3a, 0x62, 0x35, 0xf5, 0xfe, 0xbe, 0xcc, 0x57, 0x86,
+	0xec, 0x76, 0x83, 0xfe, 0x9a, 0x4a, 0x9f, 0x96, 0x31, 0xfb, 0xb4, 0xae,
+	0xa1, 0x52, 0xc9, 0x63, 0x42, 0xd9, 0x5e, 0x97, 0x61, 0x5d, 0xdb, 0xbc,
+	0x2f, 0x16, 0xe4, 0x32, 0x53, 0x85, 0x8f, 0xed, 0xfe, 0x57, 0x57, 0xd7,
+	0xa4, 0x08, 0x6f, 0xef, 0x6c, 0x81, 0xeb, 0x75, 0x8d, 0x87, 0xf8, 0x5a,
+	0x71, 0x19, 0xd2, 0xb1, 0x3b, 0xc0, 0x67, 0xc9, 0x42, 0x33, 0xc0, 0x19,
+	0x45, 0x5c, 0x46, 0x0c, 0xd8, 0xfd, 0x05, 0x5f, 0x1f, 0x7c, 0x7f, 0xd3,
+	0x65, 0x2d, 0xa4, 0xb2, 0xa7, 0xfc, 0xb9, 0x3f, 0xa3, 0x0c, 0xf0, 0x1d,
+	0xc8, 0xfd, 0x79, 0x3f, 0xde, 0x94, 0x8c, 0x5c, 0x93, 0x32, 0xa0, 0xad,
+	0x40, 0xff, 0xda, 0x3e, 0xe1, 0x33, 0xd5, 0xcf, 0x22, 0x66, 0xf5, 0x79,
+	0xf5, 0x03, 0x7a, 0xb0, 0x5c, 0x93, 0x73, 0x1b, 0x1d, 0x8e, 0xdd, 0xe6,
+	0xfb, 0xd2, 0x3e, 0xcc, 0xcd, 0xe0, 0x8f, 0xb2, 0x23, 0xcc, 0x7e, 0xbc,
+	0xe7, 0x7c, 0x38, 0x99, 0x74, 0x90, 0xbb, 0x72, 0xfb, 0xa7, 0xf0, 0x6d,
+	0xf8, 0x7d, 0x96, 0x96, 0x7b, 0x0d, 0xb5, 0x0a, 0xe4, 0x39, 0x0c, 0x7e,
+	0x92, 0x32, 0xd5, 0x84, 0xce, 0x6f, 0xc4, 0xb3, 0x1b, 0x30, 0xa5, 0x9b,
+	0x30, 0x5e, 0xec, 0x9b, 0x6a, 0xbe, 0xe5, 0x32, 0x1e, 0xfc, 0x89, 0xf6,
+	0x97, 0x24, 0x68, 0x0f, 0x7a, 0xb5, 0x9c, 0xf1, 0x70, 0x75, 0xda, 0x78,
+	0xa4, 0xca, 0x3d, 0xea, 0x6b, 0xfd, 0x62, 0x25, 0x1d, 0x85, 0x3a, 0x75,
+	0x77, 0x2f, 0xce, 0x3c, 0x06, 0xdb, 0x28, 0x19, 0x33, 0xa3, 0xdb, 0xa5,
+	0x90, 0xee, 0x07, 0xcd, 0xf7, 0xe3, 0xd9, 0x8e, 0xf9, 0x9f, 0xc2, 0x3c,
+	0xec, 0x28, 0x4d, 0xff, 0xe8, 0xd4, 0xbd, 0xe4, 0xac, 0x49, 0x1a, 0x87,
+	0x7d, 0xdb, 0xfa, 0x8e, 0xe9, 0xd9, 0xd2, 0x13, 0xf8, 0xde, 0x86, 0xf9,
+	0x5f, 0xc0, 0x13, 0xb9, 0x6c, 0x77, 0x30, 0x4f, 0x1f, 0x9c, 0xc4, 0xfc,
+	0xbd, 0xc0, 0xf1, 0xdb, 0x78, 0xbf, 0x0b, 0xef, 0xbf, 0xb5, 0x69, 0xef,
+	0x6f, 0xf2, 0x6c, 0xcc, 0x3b, 0x9b, 0xe6, 0x83, 0xf8, 0xcd, 0xf3, 0x44,
+	0xfa, 0xd6, 0xc1, 0xf8, 0x7a, 0x4c, 0x76, 0x9c, 0xee, 0x12, 0x55, 0xf7,
+	0x62, 0xb8, 0xaa, 0x9b, 0xd2, 0x7f, 0x9a, 0xf1, 0xfb, 0xaf, 0xb0, 0xc7,
+	0x12, 0xb5, 0x0e, 0xa5, 0x51, 0xb7, 0xda, 0x47, 0x0f, 0x1c, 0x19, 0x5c,
+	0xe6, 0x73, 0xf6, 0xc8, 0x44, 0x83, 0x30, 0x7c, 0x7f, 0xec, 0xc8, 0x60,
+	0xe3, 0x6f, 0x01, 0x0b, 0xb9, 0x54, 0x03, 0xfc, 0x84, 0xff, 0xd3, 0x4d,
+	0x67, 0x6a, 0xd9, 0xe2, 0x4c, 0xfa, 0xfd, 0x81, 0x23, 0x4e, 0x8d, 0x75,
+	0x42, 0x2a, 0x21, 0xba, 0x16, 0x9f, 0x3d, 0x52, 0x44, 0x7e, 0x8c, 0x68,
+	0x5a, 0x82, 0x75, 0xae, 0x51, 0x0f, 0x5b, 0xd1, 0x46, 0xba, 0x5a, 0xf1,
+	0x30, 0xcf, 0x10, 0xcf, 0x63, 0xc0, 0x93, 0x06, 0x1e, 0xe6, 0x1b, 0x8f,
+	0xde, 0xe4, 0xf2, 0x56, 0xb4, 0x11, 0x17, 0xcf, 0x0a, 0xf0, 0xf5, 0x8b,
+	0x3a, 0xfd, 0x26, 0xe9, 0x35, 0x59, 0xdb, 0x7a, 0xb1, 0xa6, 0x4d, 0x0a,
+	0x27, 0x99, 0xb3, 0x77, 0xfb, 0xdf, 0x71, 0x93, 0x3d, 0x77, 0x52, 0x71,
+	0x9e, 0x4f, 0xac, 0x65, 0xee, 0xc4, 0x1c, 0xbe, 0x57, 0x02, 0x58, 0xe5,
+	0xc3, 0xf6, 0xb4, 0xf0, 0xdd, 0xe6, 0xcb, 0x9a, 0x67, 0x06, 0xbd, 0x67,
+	0x2b, 0x2d, 0x00, 0x85, 0x1e, 0xfa, 0x6e, 0xe8, 0x21, 0xe0, 0x13, 0x0b,
+	0xeb, 0xa4, 0x2d, 0x0d, 0x5e, 0x03, 0xda, 0x3e, 0xa9, 0xfe, 0xb8, 0x37,
+	0x8d, 0xbf, 0xe0, 0xbc, 0x40, 0x06, 0xa4, 0x8b, 0x4f, 0xd8, 0xf2, 0xc7,
+	0x7a, 0xe7, 0x34, 0xfc, 0x8e, 0xf7, 0x1e, 0xae, 0xbb, 0x66, 0x53, 0xf6,
+	0x1d, 0xd0, 0x3b, 0x79, 0x31, 0xd0, 0x4b, 0x28, 0xd6, 0x74, 0x49, 0xf6,
+	0xac, 0x87, 0xe4, 0x6d, 0xe0, 0xca, 0xa1, 0xaf, 0xf4, 0x7a, 0xa3, 0x59,
+	0xc4, 0xc7, 0x0d, 0xd8, 0xe7, 0x45, 0x8b, 0xf7, 0x2f, 0x51, 0xe6, 0x3b,
+	0x29, 0x37, 0xfe, 0x19, 0x30, 0xac, 0xaf, 0x6e, 0xde, 0xad, 0x2c, 0x03,
+	0x66, 0x05, 0x6b, 0xc7, 0xbc, 0xb8, 0xcc, 0xd8, 0xee, 0x2a, 0xd4, 0x1e,
+	0x45, 0xeb, 0xbf, 0x5d, 0xd6, 0x59, 0x37, 0x61, 0xb7, 0xba, 0x0b, 0x41,
+	0xce, 0x59, 0x4a, 0x2d, 0x2c, 0x23, 0x86, 0xd7, 0x2c, 0xb5, 0x43, 0x69,
+	0x8b, 0x4c, 0xd5, 0x10, 0x93, 0xd0, 0xf5, 0xa6, 0x92, 0xcb, 0xf2, 0x03,
+	0xad, 0x87, 0x36, 0x6b, 0xcc, 0xec, 0x57, 0x5f, 0xa4, 0x5d, 0x69, 0xca,
+	0x23, 0x27, 0x90, 0x97, 0xc7, 0x1f, 0x46, 0xce, 0x81, 0xbc, 0x4e, 0x94,
+	0xd0, 0xc9, 0xd3, 0x46, 0x36, 0x7e, 0xbd, 0x68, 0x79, 0x7d, 0x80, 0xce,
+	0x67, 0xe2, 0xf1, 0x18, 0x39, 0xd1, 0xad, 0xe3, 0x4c, 0x41, 0xc7, 0x9b,
+	0x21, 0x73, 0x46, 0x75, 0xa1, 0xc6, 0x40, 0x01, 0x8a, 0x0a, 0xc7, 0x1c,
+	0x11, 0x19, 0x5c, 0x44, 0x5c, 0x41, 0x1c, 0x1e, 0x5c, 0x47, 0x74, 0x3b,
+	0x41, 0x78, 0x25, 0xd1, 0x13, 0x11, 0x69, 0x3b, 0xc1, 0xfb, 0x10, 0xd9,
+	0x89, 0x7e, 0x8c, 0x38, 0x07, 0xa3, 0x78, 0x4e, 0xe1, 0x6f, 0x0f, 0x6a,
+	0x2b, 0x13, 0x35, 0xf2, 0x16, 0xf0, 0x80, 0xe5, 0x9e, 0xad, 0xe0, 0xbb,
+	0xfb, 0xa4, 0x2b, 0x86, 0x3d, 0x84, 0x8f, 0x82, 0x8e, 0x9d, 0xa0, 0xc7,
+	0x3b, 0x9f, 0x38, 0xa2, 0x27, 0x44, 0x86, 0x16, 0xa5, 0x5f, 0xe9, 0x3d,
+	0x51, 0x29, 0x66, 0xb8, 0xd6, 0x0d, 0x78, 0xee, 0xc3, 0x9a, 0xde, 0xe7,
+	0xdd, 0x2b, 0x15, 0x6e, 0xd2, 0x8d, 0x39, 0x03, 0xef, 0xa8, 0xa7, 0x32,
+	0xa6, 0x0c, 0xd5, 0x3d, 0xd8, 0xc1, 0xf5, 0x43, 0x78, 0x92, 0x57, 0x8f,
+	0x36, 0x85, 0x9a, 0xb8, 0x00, 0xa9, 0x46, 0x47, 0x78, 0x3f, 0x43, 0x18,
+	0xf6, 0xb5, 0xdd, 0x1a, 0xc6, 0x1c, 0xa1, 0xfc, 0xbc, 0x39, 0xa5, 0xfe,
+	0xb7, 0x7b, 0x97, 0xd6, 0x9a, 0x42, 0xfb, 0x0a, 0xf6, 0x7f, 0x45, 0xfb,
+	0x8a, 0xa8, 0xa4, 0xef, 0x2b, 0xf8, 0x5e, 0xe1, 0x77, 0x90, 0x8b, 0x7f,
+	0xed, 0x0e, 0x2f, 0xde, 0xbb, 0x32, 0x67, 0xf3, 0x0e, 0xc3, 0x95, 0x8b,
+	0x76, 0xc9, 0x78, 0xf0, 0x96, 0x3a, 0x33, 0xad, 0xf3, 0x73, 0x11, 0xb2,
+	0xbf, 0xdc, 0xd0, 0x3d, 0x9b, 0x5c, 0x6a, 0xc4, 0xe4, 0xca, 0x6a, 0x97,
+	0x5c, 0x5e, 0xf6, 0x6c, 0xfe, 0xf2, 0x32, 0xed, 0xdc, 0x94, 0xef, 0xad,
+	0x5a, 0x58, 0x4b, 0xe3, 0xaf, 0x5f, 0xde, 0x59, 0xbd, 0xb5, 0xee, 0x3c,
+	0xdf, 0x7c, 0x00, 0xb4, 0xf4, 0x4b, 0xc4, 0x72, 0x75, 0xff, 0x95, 0x47,
+	0xee, 0x2b, 0xc9, 0x94, 0x14, 0xaa, 0x43, 0xe8, 0x01, 0x91, 0x9c, 0xa3,
+	0xcc, 0x41, 0xd0, 0x7f, 0xf5, 0x33, 0xa8, 0x4d, 0x52, 0x70, 0x9e, 0x21,
+	0x7d, 0x8f, 0xf8, 0x33, 0xd1, 0x7e, 0x69, 0xb7, 0xbe, 0xdc, 0xe7, 0xe5,
+	0x2a, 0xd3, 0xeb, 0x53, 0xad, 0x20, 0x5f, 0xbf, 0x0e, 0xdc, 0xe3, 0xb0,
+	0x53, 0xda, 0xa6, 0x0d, 0x9b, 0x35, 0x65, 0x6d, 0x34, 0x55, 0x2b, 0x09,
+	0xe3, 0x43, 0x06, 0x67, 0x7e, 0x08, 0x9e, 0xd3, 0x90, 0x47, 0xa7, 0xae,
+	0x85, 0x72, 0x0a, 0xba, 0x5d, 0x9c, 0x97, 0x42, 0xf3, 0x57, 0x80, 0x2f,
+	0x27, 0xb3, 0xcd, 0x49, 0x9c, 0x75, 0x1c, 0x76, 0x3b, 0xda, 0x2f, 0x5d,
+	0x3c, 0x27, 0x03, 0x1a, 0xef, 0x97, 0xe2, 0xc9, 0x79, 0x39, 0x58, 0x25,
+	0x9d, 0xc8, 0x25, 0x76, 0x2a, 0x9d, 0x97, 0xb1, 0xe4, 0x2a, 0x6a, 0x27,
+	0xcf, 0x1f, 0xb3, 0x52, 0x3c, 0x05, 0x1c, 0x55, 0xde, 0x03, 0x0c, 0xc1,
+	0x6e, 0xc6, 0x74, 0x5f, 0x33, 0xab, 0xe3, 0x0e, 0xe7, 0xdf, 0x84, 0x9e,
+	0x86, 0x4a, 0x7b, 0x00, 0x57, 0x40, 0x0f, 0x34, 0x83, 0x7a, 0x79, 0xa5,
+	0x8a, 0x7e, 0xcf, 0x8e, 0xb0, 0xf6, 0x52, 0xea, 0x9e, 0x01, 0xa9, 0x57,
+	0xc7, 0x4c, 0xa5, 0x58, 0x53, 0x51, 0x17, 0x5c, 0xa3, 0x7f, 0x27, 0x54,
+	0xd4, 0x1a, 0x90, 0xd5, 0x6a, 0x09, 0x7d, 0xb3, 0xf2, 0xef, 0x35, 0x4a,
+	0x62, 0x5a, 0x5e, 0xdc, 0xcb, 0x29, 0xf2, 0x8d, 0xfa, 0xb3, 0xf9, 0x59,
+	0xd0, 0x98, 0x4b, 0x9a, 0x72, 0x14, 0xf4, 0xe1, 0x7d, 0x05, 0x36, 0xbe,
+	0xc8, 0x1a, 0x2e, 0x87, 0xb5, 0xac, 0x1c, 0x3e, 0x33, 0x03, 0x1a, 0x7a,
+	0x65, 0xe8, 0x77, 0xe9, 0x63, 0x07, 0x30, 0xc7, 0xef, 0x14, 0xec, 0xf5,
+	0x31, 0xbc, 0x13, 0x36, 0x81, 0x27, 0xe5, 0x30, 0x80, 0xa7, 0x09, 0x5a,
+	0x62, 0x5e, 0x6f, 0xb2, 0x3f, 0x29, 0xf5, 0x93, 0xf7, 0xc9, 0xec, 0xca,
+	0x7d, 0xc0, 0xff, 0x36, 0xfa, 0x02, 0xe4, 0xb7, 0x15, 0x9e, 0xc5, 0xfa,
+	0x8f, 0xe7, 0x74, 0xf4, 0x6b, 0xdf, 0x58, 0xe4, 0x3c, 0x9f, 0xfb, 0xb0,
+	0x1f, 0x3d, 0x46, 0x35, 0x27, 0xc5, 0x2a, 0xcf, 0x82, 0xee, 0x50, 0x4f,
+	0x15, 0x4e, 0xce, 0xf8, 0x3a, 0xee, 0x97, 0x7c, 0xbc, 0xc4, 0xfe, 0x02,
+	0x79, 0x62, 0x79, 0xc2, 0xa9, 0xa4, 0x4c, 0x47, 0x11, 0x57, 0x5a, 0x98,
+	0x1b, 0xbc, 0xb9, 0x98, 0x58, 0x8b, 0xe8, 0x6d, 0xb3, 0x5c, 0x3b, 0xea,
+	0xdf, 0x1d, 0x10, 0xd7, 0x5b, 0x32, 0x05, 0x1b, 0x1b, 0x5a, 0x1c, 0x47,
+	0x2d, 0xfc, 0x5d, 0xd4, 0x92, 0x77, 0xfa, 0x32, 0x98, 0xf4, 0x6d, 0xa3,
+	0xab, 0xc5, 0x26, 0xa0, 0xe7, 0x2a, 0x74, 0x5f, 0x85, 0x1d, 0x20, 0x56,
+	0xbf, 0x74, 0xc3, 0x3e, 0x26, 0x5b, 0x6a, 0xcc, 0x1e, 0xf9, 0x8b, 0x5a,
+	0x2a, 0xbd, 0x01, 0xfb, 0x79, 0x07, 0xbd, 0xc0, 0x06, 0x7a, 0xd5, 0xcb,
+	0xe8, 0xeb, 0x56, 0x2a, 0xfb, 0x41, 0x3f, 0x6b, 0x4a, 0x7e, 0x27, 0x74,
+	0xad, 0xd3, 0x61, 0x1d, 0xbb, 0x43, 0xdf, 0xed, 0xca, 0xfe, 0x7e, 0xf6,
+	0x9a, 0xec, 0xcb, 0x79, 0x0f, 0x7d, 0x05, 0x7a, 0xdc, 0x30, 0xb9, 0x1e,
+	0xec, 0x63, 0x2f, 0x10, 0xd8, 0x0f, 0x69, 0xa1, 0xfd, 0x70, 0x0f, 0x61,
+	0xfa, 0xb5, 0x9f, 0x14, 0x34, 0x3e, 0xda, 0xec, 0x8b, 0x7d, 0x9e, 0x9f,
+	0xe9, 0x3a, 0xcb, 0xbc, 0x24, 0x81, 0xfd, 0xbe, 0xef, 0xb2, 0xaf, 0x73,
+	0x46, 0x11, 0xbb, 0x9b, 0xae, 0x3c, 0x67, 0xdf, 0xea, 0x77, 0x7b, 0xab,
+	0x81, 0x9c, 0x28, 0xc7, 0xfd, 0x72, 0xac, 0x99, 0x82, 0x4f, 0x50, 0x86,
+	0x56, 0x8b, 0x0c, 0x45, 0xfe, 0xa8, 0x2a, 0xf2, 0x62, 0x95, 0x6b, 0x5a,
+	0x86, 0x09, 0x27, 0xd2, 0xa5, 0xef, 0xd2, 0x0b, 0xf2, 0x1d, 0x39, 0xb8,
+	0x24, 0x72, 0x06, 0xeb, 0x6b, 0x55, 0xfa, 0xea, 0x38, 0xea, 0xd7, 0x6d,
+	0x52, 0x5f, 0x46, 0x4f, 0x56, 0x95, 0x59, 0xe7, 0x5e, 0xe6, 0x9b, 0x98,
+	0x5c, 0xd6, 0x77, 0xb2, 0x22, 0x23, 0x67, 0xa3, 0x12, 0x3d, 0x8b, 0xe6,
+	0x0f, 0xb2, 0x3f, 0x37, 0x1a, 0xdc, 0xd1, 0x7a, 0x3e, 0x5f, 0xae, 0x60,
+	0x6f, 0x75, 0x48, 0xc7, 0xc9, 0x72, 0xa3, 0x28, 0x85, 0x1a, 0xcf, 0xc2,
+	0x73, 0x39, 0x89, 0xb5, 0x8c, 0xcc, 0x9d, 0x1c, 0x97, 0xa7, 0x71, 0x06,
+	0xfa, 0x3f, 0x9c, 0x31, 0x25, 0xa5, 0x33, 0x98, 0x6f, 0x5c, 0x95, 0xe5,
+	0xd5, 0xa2, 0xd4, 0x6b, 0xe7, 0x5d, 0xaf, 0x8f, 0x20, 0x3e, 0x7c, 0x2f,
+	0xb7, 0xf6, 0xb2, 0xfb, 0xd9, 0xcf, 0xa0, 0x57, 0xb5, 0xf0, 0x0d, 0x99,
+	0x35, 0xe6, 0x66, 0x6f, 0xbd, 0x33, 0x6e, 0xed, 0x61, 0xa7, 0x65, 0xa1,
+	0x9a, 0x91, 0xf2, 0xc9, 0x71, 0x7d, 0xd7, 0xd0, 0x91, 0x3d, 0xfc, 0xc4,
+	0x35, 0xe4, 0x8a, 0x69, 0x7d, 0x67, 0x7c, 0x5d, 0x1e, 0xb2, 0x17, 0xe4,
+	0x90, 0xb5, 0x4f, 0x8e, 0xa1, 0xbe, 0xfe, 0x1c, 0x7a, 0xfd, 0x64, 0x1f,
+	0xf5, 0x08, 0x7a, 0x2d, 0xf6, 0xa0, 0xae, 0x4c, 0xd9, 0x9f, 0x36, 0x9f,
+	0x65, 0x97, 0xd0, 0x60, 0x9e, 0xfc, 0x2f, 0x37, 0x87, 0xbc, 0x77, 0x0d,
+	0xbd, 0x63, 0x4e, 0xc3, 0x19, 0x1e, 0x5c, 0x8d, 0x70, 0x63, 0xe6, 0x73,
+	0x84, 0x5b, 0x36, 0x7c, 0x38, 0x03, 0x70, 0x11, 0xb9, 0x60, 0x47, 0x61,
+	0x23, 0xd3, 0xe0, 0x13, 0x31, 0x7e, 0xa2, 0xc7, 0xaf, 0x83, 0x3b, 0x91,
+	0x5b, 0x6f, 0xee, 0x7f, 0xd5, 0xdf, 0xff, 0xb4, 0xbf, 0xff, 0xe2, 0x8d,
+	0xfd, 0x41, 0x7e, 0xfd, 0xd0, 0x95, 0x16, 0xba, 0x5e, 0xad, 0x78, 0xf0,
+	0x0b, 0x3e, 0x5d, 0x17, 0x6f, 0xd0, 0x15, 0xc0, 0x43, 0x9e, 0x9a, 0x67,
+	0xc6, 0x66, 0xc6, 0xe8, 0x21, 0xc8, 0xd1, 0x95, 0xbc, 0x0d, 0xdf, 0xa8,
+	0xa6, 0x26, 0x4b, 0xfa, 0x4e, 0x4d, 0xc9, 0x46, 0x7c, 0x41, 0xa6, 0xad,
+	0xd4, 0xe4, 0x9c, 0x44, 0x60, 0xcb, 0x8c, 0x2d, 0x11, 0xa9, 0x33, 0xe6,
+	0xe0, 0x59, 0xb0, 0xb7, 0xa6, 0xf5, 0x4a, 0x0b, 0xad, 0x91, 0x17, 0x48,
+	0xa3, 0x47, 0x6b, 0x6c, 0xf8, 0x26, 0xad, 0x1e, 0xbc, 0x47, 0xeb, 0x95,
+	0x4a, 0x0b, 0xfc, 0xd9, 0xa8, 0x0f, 0x1f, 0x6d, 0x81, 0xa7, 0x3d, 0xb3,
+	0xae, 0xa0, 0x3d, 0x93, 0xb6, 0x9f, 0x80, 0x6f, 0x48, 0xac, 0x33, 0x7b,
+	0xf8, 0xc8, 0xdd, 0xc3, 0xae, 0xc4, 0x50, 0x6f, 0xb4, 0x63, 0xed, 0x72,
+	0x8d, 0xb5, 0x88, 0x1a, 0x6c, 0x97, 0x11, 0xd8, 0x2c, 0x75, 0xe7, 0xdd,
+	0x0d, 0x3e, 0xa4, 0x6b, 0x02, 0x57, 0x0e, 0xd9, 0xa4, 0xe5, 0x3f, 0xdd,
+	0x17, 0xe3, 0x23, 0x76, 0x59, 0x46, 0xcd, 0x76, 0x9c, 0x5f, 0x6f, 0x6a,
+	0x9c, 0x69, 0xd2, 0x72, 0x7a, 0x74, 0xc8, 0xfc, 0x73, 0xf0, 0x39, 0x55,
+	0x33, 0xa4, 0x6e, 0xa5, 0x12, 0xe7, 0x80, 0x63, 0x0f, 0x74, 0x53, 0x1f,
+	0x27, 0x3d, 0x22, 0x07, 0x61, 0xdf, 0x75, 0x9d, 0x17, 0x69, 0xc7, 0xa9,
+	0xe9, 0x12, 0x6a, 0x9d, 0x3f, 0xd6, 0xb9, 0xcd, 0x75, 0xaf, 0x21, 0xbf,
+	0x4d, 0x6f, 0xb2, 0x3d, 0x75, 0xd6, 0xb3, 0x3d, 0x75, 0x16, 0x3d, 0xf0,
+	0xf1, 0x98, 0x74, 0xac, 0xc1, 0x7f, 0x5e, 0xd8, 0xe9, 0xd5, 0x73, 0x2f,
+	0x24, 0x8d, 0xfc, 0x49, 0xc4, 0xbb, 0xe3, 0x51, 0xb1, 0x8e, 0xeb, 0x7c,
+	0x00, 0x79, 0x4f, 0xc9, 0xdc, 0x29, 0xc6, 0x54, 0x4b, 0x86, 0x8f, 0x53,
+	0x1f, 0xac, 0x6b, 0x96, 0x27, 0x8a, 0xf0, 0x91, 0x79, 0xc4, 0x05, 0xb5,
+	0xf6, 0xae, 0x14, 0x2d, 0xca, 0xa1, 0x57, 0xba, 0xd6, 0xd0, 0x8f, 0xaf,
+	0x21, 0x36, 0xac, 0x25, 0xa4, 0x0d, 0xbe, 0xa5, 0xce, 0xc6, 0x8d, 0xf2,
+	0xd2, 0x0f, 0xe1, 0x0f, 0xfc, 0x0d, 0x07, 0xb5, 0xe5, 0xd9, 0x84, 0x41,
+	0xdf, 0x52, 0x67, 0x69, 0xe7, 0x28, 0xa7, 0xce, 0xd2, 0xce, 0x49, 0x47,
+	0xe0, 0x2f, 0x78, 0x3f, 0x3b, 0xae, 0xef, 0xa9, 0xaf, 0xd9, 0xe4, 0xe5,
+	0x6f, 0xc4, 0xa9, 0xb1, 0x46, 0x24, 0x3f, 0xd2, 0x87, 0x5a, 0x66, 0xbb,
+	0x63, 0x0f, 0x4f, 0x5e, 0x96, 0x4f, 0xca, 0xd7, 0xed, 0x9f, 0x80, 0x2f,
+	0xf2, 0xd1, 0xca, 0x17, 0x79, 0xea, 0x95, 0x36, 0xcd, 0x57, 0xc0, 0x0f,
+	0x04, 0x0d, 0x7e, 0x06, 0x8f, 0x27, 0x80, 0xff, 0x31, 0xc4, 0x80, 0x01,
+	0x3c, 0x0f, 0xe0, 0x89, 0x94, 0x76, 0x96, 0xbc, 0x93, 0xd7, 0x77, 0x50,
+	0x37, 0x06, 0x7c, 0xce, 0xe2, 0xfd, 0x15, 0x99, 0x5b, 0x72, 0x8f, 0x22,
+	0xaf, 0xf2, 0x0e, 0xbd, 0xdf, 0xbb, 0x0f, 0xde, 0xcc, 0xfb, 0x2b, 0xe2,
+	0xc9, 0x27, 0x65, 0xd6, 0x05, 0xef, 0xab, 0x9b, 0x65, 0xd1, 0x1a, 0x3b,
+	0x12, 0xba, 0x0e, 0x3f, 0xd8, 0x60, 0x9c, 0xa0, 0x8c, 0xde, 0x11, 0x67,
+	0x89, 0xf7, 0x5f, 0x1e, 0xbe, 0xd9, 0x46, 0x10, 0x37, 0x5a, 0xf7, 0xd8,
+	0x80, 0x1b, 0x00, 0x1c, 0xe9, 0xda, 0xa0, 0xfc, 0x10, 0x73, 0x76, 0xb5,
+	0xc4, 0x9a, 0xd6, 0x7d, 0x93, 0xf2, 0x0c, 0xea, 0x80, 0x57, 0xed, 0x5b,
+	0xe4, 0x3a, 0xcb, 0x5a, 0xa8, 0xde, 0x98, 0x81, 0x4f, 0xb6, 0x21, 0x96,
+	0x99, 0x72, 0xb9, 0xd2, 0x2e, 0x75, 0xd4, 0x3b, 0x2b, 0xab, 0x8c, 0x85,
+	0xa4, 0xbd, 0x0b, 0xf3, 0x5e, 0xfc, 0x62, 0xac, 0xbd, 0x5c, 0x41, 0x9e,
+	0x85, 0x6f, 0x5f, 0xae, 0xc4, 0xf1, 0x1c, 0xc0, 0xd3, 0xc2, 0x33, 0x89,
+	0x67, 0x1a, 0xcf, 0x71, 0x3c, 0xc7, 0xf1, 0xb4, 0xb0, 0x37, 0x81, 0x67,
+	0xd0, 0x33, 0x10, 0xd7, 0x4d, 0xbe, 0xcb, 0xfa, 0x3c, 0xd4, 0x8a, 0x16,
+	0x73, 0x5a, 0xd4, 0xce, 0xa3, 0x8f, 0x70, 0xc6, 0x75, 0xad, 0x87, 0xfc,
+	0xf6, 0x91, 0x6b, 0x5a, 0xec, 0xcb, 0x4b, 0xc6, 0x9e, 0x51, 0xe6, 0x85,
+	0x1a, 0xf2, 0xc2, 0x7f, 0xec, 0x40, 0xff, 0x68, 0xee, 0xd5, 0x77, 0x47,
+	0x4b, 0xf8, 0xe6, 0x3b, 0x7a, 0xde, 0xf8, 0x3c, 0xf2, 0x14, 0xe3, 0xa7,
+	0x8b, 0x3d, 0x05, 0xc4, 0xf1, 0xed, 0xf0, 0xbf, 0x1c, 0xe2, 0x36, 0xde,
+	0x97, 0x37, 0x76, 0x78, 0x39, 0x15, 0xf5, 0xbb, 0xda, 0x7c, 0x5f, 0x63,
+	0x63, 0xcf, 0x56, 0xbd, 0x41, 0x0f, 0x70, 0xa4, 0x6a, 0xcb, 0xf0, 0xc1,
+	0x37, 0xed, 0xa3, 0xba, 0xb6, 0xa3, 0x2e, 0x9e, 0x46, 0x8d, 0x9a, 0x5f,
+	0x64, 0x0d, 0xf3, 0x14, 0xfa, 0x12, 0xf4, 0x67, 0x71, 0xf6, 0xe4, 0xcc,
+	0x05, 0xba, 0x16, 0x8d, 0x4b, 0x17, 0xf3, 0xc0, 0x15, 0x9c, 0x07, 0xbe,
+	0x56, 0x5c, 0xc8, 0xec, 0x41, 0xd4, 0x84, 0xae, 0x1b, 0xb5, 0xf6, 0x48,
+	0xf2, 0x11, 0xc6, 0x1c, 0xc1, 0x7e, 0x53, 0xbc, 0x7b, 0x75, 0xc4, 0xdd,
+	0x19, 0xfd, 0xfb, 0x30, 0x8c, 0x6b, 0x1c, 0x7b, 0x6f, 0x13, 0xef, 0xb7,
+	0x5c, 0xde, 0x69, 0x8b, 0xec, 0x59, 0xf4, 0x6a, 0x5a, 0x65, 0xb5, 0xe2,
+	0xfb, 0x49, 0x1f, 0x1f, 0xd7, 0x95, 0xff, 0xdb, 0xc6, 0x4e, 0xc8, 0x08,
+	0xfe, 0x00, 0x1d, 0x1f, 0x43, 0xfd, 0x7c, 0x01, 0x7a, 0x79, 0x15, 0x3a,
+	0x79, 0xad, 0x42, 0x5b, 0x1f, 0x83, 0xdd, 0x43, 0x86, 0x33, 0xfa, 0x0c,
+	0x7d, 0xf6, 0x85, 0x0a, 0x62, 0x27, 0xe3, 0x9f, 0xfa, 0x52, 0x9c, 0xf5,
+	0x21, 0xf3, 0xa0, 0x87, 0x67, 0xc0, 0x83, 0x93, 0x60, 0x6d, 0x87, 0xa6,
+	0xa7, 0xae, 0xef, 0xc1, 0x28, 0x27, 0xd8, 0x20, 0x7f, 0x23, 0xd0, 0x30,
+	0x5f, 0x8c, 0xeb, 0x7b, 0x78, 0xc5, 0x39, 0xf2, 0x31, 0x2e, 0xce, 0x62,
+	0xb0, 0xaf, 0x0f, 0xfb, 0x3a, 0x5b, 0x70, 0xdd, 0xbe, 0x89, 0x07, 0xe5,
+	0xf3, 0xc0, 0xf5, 0xcd, 0x75, 0x7f, 0xca, 0x2c, 0xdd, 0xb8, 0x1b, 0x66,
+	0xfe, 0xa5, 0x6e, 0x32, 0xd8, 0x1f, 0xe8, 0x67, 0xc0, 0xef, 0x05, 0x52,
+	0x0b, 0xe8, 0x23, 0x20, 0x7f, 0xea, 0x68, 0x92, 0xf1, 0x09, 0xf8, 0x6d,
+	0xa9, 0x55, 0x3a, 0x44, 0xf5, 0xb3, 0x37, 0x66, 0xad, 0xdc, 0x7a, 0xe6,
+	0x2f, 0xfa, 0x67, 0xa2, 0x9f, 0x3e, 0xc1, 0xba, 0x59, 0xe7, 0x19, 0xc0,
+	0x74, 0x6f, 0xa2, 0xed, 0xe7, 0x7c, 0x38, 0xae, 0xa7, 0xa5, 0x84, 0x3a,
+	0x34, 0xbf, 0x88, 0x8a, 0x1e, 0xf1, 0x5b, 0x65, 0xf9, 0xbb, 0x16, 0xef,
+	0xf0, 0xc6, 0x92, 0x73, 0xa0, 0xb1, 0x64, 0xe6, 0x78, 0x6f, 0x06, 0x1c,
+	0xbb, 0x36, 0xe1, 0x98, 0xf2, 0x71, 0x4c, 0x49, 0xf9, 0xd4, 0x34, 0x7c,
+	0x2d, 0x87, 0xfc, 0x3e, 0x64, 0x3e, 0x28, 0x9f, 0x41, 0x73, 0x8d, 0xb9,
+	0x33, 0xe3, 0xd0, 0x93, 0xeb, 0xee, 0xb1, 0xf7, 0x83, 0xee, 0x97, 0x91,
+	0x5b, 0x83, 0x9a, 0xa7, 0x9c, 0x88, 0x20, 0x87, 0x1d, 0xd6, 0xbf, 0xc3,
+	0x96, 0x4c, 0x13, 0xf6, 0xaa, 0x8c, 0xb1, 0x34, 0xda, 0x7b, 0xe4, 0xb7,
+	0x05, 0xe4, 0x2a, 0xf2, 0xd9, 0x23, 0x65, 0xd3, 0x78, 0x20, 0x82, 0xba,
+	0xc6, 0x59, 0xa4, 0x1f, 0xc9, 0x70, 0x24, 0xdb, 0x8e, 0x9a, 0xd4, 0x95,
+	0xef, 0xd9, 0xfc, 0x77, 0x09, 0x0b, 0x72, 0xa1, 0x61, 0xe2, 0x79, 0x0e,
+	0x7a, 0xf8, 0x3d, 0xbc, 0xff, 0x53, 0x3f, 0xea, 0x3e, 0xac, 0xe4, 0x60,
+	0xbb, 0x69, 0x5d, 0xcf, 0xb0, 0x8e, 0xa8, 0x23, 0xdf, 0x2a, 0xe4, 0x1a,
+	0xd4, 0x55, 0x93, 0xac, 0x5d, 0x9f, 0x59, 0xb9, 0x2a, 0xaf, 0x2d, 0xf1,
+	0x77, 0x50, 0xe6, 0xe5, 0x7d, 0x8c, 0x07, 0xe6, 0x7c, 0x06, 0x73, 0xab,
+	0x8c, 0x65, 0xf8, 0x6e, 0xc2, 0x81, 0xfa, 0x51, 0x23, 0xa0, 0xd6, 0xbe,
+	0x6c, 0xa5, 0xc1, 0xe7, 0x55, 0xb9, 0xb0, 0x14, 0x95, 0x15, 0x8b, 0x75,
+	0x91, 0x24, 0x1d, 0xc0, 0x5e, 0x58, 0xfd, 0x07, 0xcf, 0x26, 0x08, 0x8f,
+	0x9e, 0xa7, 0x84, 0xba, 0xee, 0x41, 0xbd, 0xf7, 0x47, 0xe9, 0x99, 0x34,
+	0xb5, 0xf6, 0x79, 0x45, 0xb9, 0x40, 0x7f, 0xd2, 0xbf, 0x51, 0xb0, 0x36,
+	0x78, 0x0a, 0x36, 0xcb, 0xda, 0x9d, 0xfd, 0x00, 0xde, 0x1b, 0x5c, 0x27,
+	0xef, 0x78, 0x2e, 0x0f, 0x41, 0x36, 0xf4, 0x7b, 0xde, 0x89, 0x21, 0x8f,
+	0x2a, 0xfa, 0x7a, 0x59, 0xc7, 0x82, 0x72, 0xb5, 0x88, 0x9c, 0x82, 0x18,
+	0x60, 0xef, 0x82, 0x2d, 0xce, 0x40, 0x97, 0x93, 0x80, 0xdb, 0x94, 0x4b,
+	0xd6, 0xcb, 0xba, 0x2e, 0x53, 0xa7, 0x6f, 0xde, 0xdf, 0x14, 0xe0, 0x3f,
+	0x6a, 0x1d, 0xb6, 0x05, 0x1f, 0x52, 0xeb, 0x71, 0x3c, 0x11, 0x8f, 0xd7,
+	0xd1, 0x5f, 0x54, 0x78, 0x3f, 0x84, 0xde, 0xa0, 0xc2, 0xbb, 0x93, 0x34,
+	0x9e, 0xe3, 0xbc, 0x2f, 0xf2, 0xe3, 0x1a, 0xf1, 0x93, 0x8e, 0x20, 0xbe,
+	0xb0, 0x96, 0x64, 0x7c, 0x09, 0xea, 0x49, 0xcf, 0x16, 0x8e, 0x55, 0x19,
+	0x43, 0x68, 0xd7, 0x43, 0x88, 0x5b, 0xb4, 0x05, 0xaf, 0x96, 0x5c, 0xad,
+	0x79, 0x32, 0x9b, 0x6b, 0x9e, 0xd7, 0x39, 0x62, 0xaf, 0x58, 0xb0, 0x31,
+	0xca, 0x0e, 0x6b, 0x3a, 0x07, 0x9c, 0x93, 0x9c, 0x7e, 0x52, 0x66, 0xaf,
+	0x48, 0x6e, 0x75, 0x5c, 0x9e, 0xd3, 0x71, 0x2b, 0x88, 0x59, 0xac, 0x21,
+	0xf9, 0xfb, 0x71, 0x5a, 0x9e, 0x3d, 0x79, 0x55, 0x9c, 0xe7, 0x19, 0xb7,
+	0xc6, 0x12, 0x9d, 0x06, 0x63, 0x95, 0x2b, 0x0d, 0xe4, 0xa6, 0x07, 0x6d,
+	0xfe, 0x5b, 0x80, 0x08, 0x7a, 0x3a, 0x57, 0xda, 0x27, 0x52, 0x76, 0xd2,
+	0x18, 0x3a, 0xd0, 0x69, 0x30, 0x37, 0x8e, 0x99, 0x8f, 0x4b, 0x70, 0x1f,
+	0xd5, 0x21, 0x8f, 0xeb, 0xbb, 0x0a, 0xb8, 0xed, 0xe2, 0x07, 0xfa, 0x77,
+	0x94, 0x6b, 0x19, 0xca, 0x1a, 0xdf, 0xeb, 0x9c, 0x2f, 0xc5, 0xae, 0x65,
+	0xda, 0xa4, 0x7c, 0x9b, 0xeb, 0x1e, 0x9a, 0x98, 0xd8, 0xe1, 0xfd, 0x7b,
+	0x91, 0x23, 0xb7, 0x79, 0xb1, 0xa0, 0xe0, 0x7f, 0xaf, 0xe1, 0x49, 0xdb,
+	0x66, 0xbe, 0x65, 0x7e, 0xa4, 0xde, 0xf0, 0x5c, 0xe5, 0x3b, 0x73, 0xef,
+	0x02, 0x72, 0x2f, 0xf3, 0xe5, 0x76, 0xc9, 0xf3, 0x77, 0x3e, 0xa5, 0xe7,
+	0x4b, 0x5e, 0x2d, 0xed, 0xc3, 0xd5, 0x66, 0x65, 0xae, 0xc6, 0x1a, 0xea,
+	0x02, 0x72, 0xd9, 0x28, 0x6c, 0x95, 0x39, 0xed, 0x28, 0xf2, 0x39, 0x7f,
+	0x9f, 0xc6, 0xda, 0x32, 0xf7, 0xa5, 0xd2, 0x49, 0xd5, 0xfa, 0xbb, 0xd2,
+	0xd5, 0x38, 0xef, 0xa3, 0xce, 0x8d, 0x42, 0xef, 0xbf, 0xc3, 0xde, 0x62,
+	0x58, 0xdb, 0x88, 0xf3, 0x02, 0x65, 0xef, 0xfd, 0x7e, 0x2d, 0x7d, 0x9e,
+	0x0f, 0xb0, 0x0e, 0xf8, 0x3c, 0xe4, 0xb2, 0xd7, 0xbe, 0xca, 0xdc, 0xfd,
+	0x6f, 0xca, 0x1a, 0x4b, 0x3f, 0x6e, 0xd0, 0xb7, 0xf1, 0xbd, 0x1a, 0x91,
+	0xe5, 0x38, 0xf9, 0x87, 0xbc, 0x0c, 0xfa, 0xce, 0x56, 0x72, 0xd8, 0x2c,
+	0x83, 0x3f, 0x80, 0x0c, 0x28, 0xcb, 0x40, 0x06, 0x7c, 0x9f, 0x86, 0xbe,
+	0xd8, 0x33, 0x0c, 0xe9, 0x3e, 0xb2, 0xdc, 0xf4, 0xce, 0x2e, 0x57, 0x5b,
+	0x69, 0x26, 0xbd, 0xd4, 0xe9, 0x39, 0xc9, 0x6b, 0xfd, 0x2e, 0x48, 0xbe,
+	0x76, 0x4e, 0xf6, 0xd4, 0x16, 0xe4, 0x21, 0xeb, 0x01, 0xf0, 0x7b, 0xc9,
+	0x2d, 0x5a, 0xba, 0x57, 0x99, 0x2c, 0xe0, 0xec, 0xe2, 0xff, 0x74, 0x6e,
+	0xb5, 0xbf, 0x6d, 0x55, 0x67, 0xfc, 0xf1, 0xb5, 0x9d, 0xa4, 0xa1, 0x09,
+	0xb7, 0xae, 0x93, 0xb8, 0x69, 0x0a, 0x76, 0x7c, 0xdb, 0x46, 0x24, 0xad,
+	0x6e, 0x43, 0x46, 0xa3, 0x2e, 0x53, 0x4c, 0x12, 0xba, 0x74, 0xeb, 0x44,
+	0xda, 0x75, 0x5d, 0x37, 0xd0, 0x64, 0x9c, 0xb4, 0x14, 0x98, 0x54, 0x28,
+	0xac, 0x43, 0x08, 0xa9, 0xc6, 0x6d, 0x35, 0xa6, 0xa5, 0x71, 0xfa, 0x46,
+	0x10, 0x5f, 0xb0, 0x92, 0xb4, 0x65, 0x52, 0x84, 0x5b, 0x04, 0xdb, 0x3e,
+	0xb0, 0xd1, 0xa5, 0x8c, 0x3f, 0x60, 0xfb, 0x30, 0x26, 0xb1, 0x29, 0x2b,
+	0xb0, 0xb1, 0x7d, 0xea, 0x07, 0x26, 0x75, 0xda, 0x8a, 0xf7, 0xfb, 0x3d,
+	0xe7, 0x5e, 0xc7, 0x36, 0x41, 0x48, 0x8b, 0x14, 0xf9, 0x9e, 0x97, 0x7b,
+	0xee, 0xb9, 0xe7, 0x79, 0x7f, 0x9e, 0xdf, 0xed, 0x59, 0x27, 0x9f, 0xc0,
+	0xef, 0x38, 0x35, 0x67, 0x4b, 0xda, 0xee, 0x97, 0x9f, 0x6a, 0x2e, 0x9f,
+	0xf1, 0x49, 0x00, 0x3e, 0xa9, 0xc1, 0x16, 0x48, 0x8b, 0x13, 0xbb, 0x21,
+	0xf4, 0x29, 0xc3, 0xa0, 0x75, 0xdc, 0xf8, 0xcd, 0xb6, 0x19, 0xdf, 0x74,
+	0x06, 0xbe, 0xbb, 0xbb, 0xad, 0xc5, 0xcf, 0xf9, 0x1a, 0xff, 0xf6, 0x7d,
+	0xaf, 0x86, 0xd6, 0x2f, 0xd3, 0xd8, 0xcf, 0x9b, 0xaa, 0x67, 0x1d, 0xf0,
+	0x12, 0x73, 0xd3, 0x31, 0xcd, 0x3f, 0x84, 0xa7, 0xa8, 0xa3, 0xae, 0x40,
+	0x47, 0x0d, 0x50, 0x77, 0x0d, 0xce, 0xb9, 0xcc, 0x0f, 0x44, 0xe5, 0x0f,
+	0x93, 0xd4, 0xc3, 0x71, 0xf9, 0xfd, 0xe4, 0xb3, 0xd8, 0x4f, 0xa2, 0xc0,
+	0x1c, 0xe5, 0xf5, 0xe9, 0xac, 0x62, 0x92, 0x86, 0xd5, 0x07, 0x7e, 0x5a,
+	0xed, 0x40, 0xdc, 0xca, 0xad, 0x0d, 0xab, 0xbe, 0x39, 0xa2, 0xb5, 0xdd,
+	0xb8, 0xd5, 0x21, 0xd7, 0xcf, 0x1b, 0x1d, 0x1b, 0x9e, 0x8a, 0x06, 0x86,
+	0xe7, 0x69, 0x97, 0x92, 0xb1, 0x8c, 0x55, 0x2f, 0x07, 0xa3, 0xcc, 0x3d,
+	0xa7, 0xa8, 0x9f, 0x61, 0x0b, 0xbb, 0xed, 0x8c, 0xd5, 0xe0, 0xd9, 0x9f,
+	0x58, 0x8d, 0x9e, 0x3d, 0xe2, 0xe9, 0x59, 0x8e, 0xa5, 0x40, 0x53, 0xda,
+	0xa2, 0xc4, 0xf4, 0x88, 0x95, 0x84, 0xcd, 0xc3, 0xf5, 0x02, 0xd7, 0x8f,
+	0xcb, 0xd1, 0x85, 0xc3, 0xf0, 0xbf, 0xbb, 0xed, 0xbd, 0xb4, 0xab, 0xf6,
+	0x00, 0xf1, 0x38, 0x78, 0xfe, 0x86, 0x9a, 0xb5, 0x1e, 0xf6, 0xd6, 0xe2,
+	0x38, 0xe4, 0x7c, 0x8a, 0xf5, 0xda, 0x7a, 0xe6, 0x73, 0x74, 0xaf, 0xd5,
+	0x73, 0xf7, 0x94, 0x9f, 0x7b, 0x32, 0xef, 0x78, 0x58, 0x30, 0xfc, 0xc2,
+	0x17, 0xfa, 0x76, 0x84, 0xcf, 0xe4, 0xf3, 0x9a, 0x65, 0x68, 0x3f, 0xf4,
+	0xcb, 0x14, 0xff, 0xb3, 0x5e, 0xed, 0x0a, 0xf1, 0x4a, 0xb4, 0x7d, 0x05,
+	0xdb, 0xf4, 0x35, 0x6f, 0xbd, 0xad, 0xad, 0xd2, 0x18, 0xad, 0x98, 0xcf,
+	0xdc, 0x0a, 0xdb, 0x71, 0xc9, 0x2e, 0xf0, 0xb7, 0x54, 0x8a, 0x38, 0x75,
+	0xb2, 0xd7, 0x5e, 0x5f, 0xb3, 0xc6, 0x16, 0xf4, 0x19, 0x9f, 0x20, 0x38,
+	0x15, 0xf0, 0x7c, 0x8b, 0xbb, 0xe9, 0x37, 0x79, 0xd7, 0x0d, 0x9a, 0x93,
+	0x89, 0x5b, 0xed, 0x35, 0xef, 0x71, 0x77, 0xd9, 0x0e, 0xc7, 0x2d, 0xea,
+	0xce, 0x60, 0x54, 0x9a, 0xc9, 0x43, 0x25, 0xf5, 0xe3, 0x43, 0x8e, 0xc1,
+	0x5c, 0x44, 0x9d, 0xf1, 0x56, 0xe6, 0xec, 0xdf, 0xd1, 0x73, 0x6b, 0xa2,
+	0x4f, 0x80, 0x6b, 0xf0, 0xc9, 0xe7, 0xf2, 0xbd, 0xcc, 0xf5, 0x62, 0xfd,
+	0x46, 0xae, 0xef, 0x7a, 0xe7, 0x9c, 0x70, 0xb3, 0xd6, 0x7d, 0x92, 0x39,
+	0x6f, 0xf8, 0x6f, 0xc8, 0x01, 0xef, 0x35, 0xa3, 0x3d, 0x4f, 0x9b, 0xf0,
+	0x45, 0xeb, 0xf8, 0xb6, 0xa1, 0x4b, 0x6d, 0xc3, 0x89, 0x3c, 0xf9, 0x93,
+	0x7c, 0xe9, 0xf3, 0xa3, 0xaf, 0xf3, 0xc8, 0xa3, 0xd4, 0xb3, 0xfd, 0x72,
+	0x26, 0xcf, 0xb3, 0x49, 0x69, 0x4d, 0x6b, 0xe3, 0xd9, 0x71, 0xc5, 0x64,
+	0x75, 0x4e, 0x25, 0x5e, 0xce, 0xca, 0xa0, 0x5c, 0x71, 0x79, 0x66, 0x89,
+	0x42, 0x3a, 0xd8, 0x54, 0xf1, 0xfe, 0xfb, 0xf5, 0xcc, 0xc2, 0xea, 0x33,
+	0xc6, 0x30, 0xf7, 0x79, 0x8f, 0xde, 0xcd, 0x7a, 0xb6, 0xe9, 0x2a, 0xfa,
+	0x7c, 0x53, 0xcf, 0x29, 0x0c, 0x9d, 0xc8, 0xfa, 0x7e, 0x38, 0xc2, 0x7b,
+	0xf8, 0x5c, 0xfa, 0x7c, 0x7c, 0x16, 0x79, 0xaf, 0x13, 0x16, 0xbb, 0x57,
+	0x82, 0x3b, 0x20, 0xfa, 0x3b, 0x58, 0x47, 0x0e, 0x40, 0x56, 0x37, 0x1a,
+	0x0c, 0xcc, 0x98, 0xf1, 0x35, 0xd2, 0xd6, 0x55, 0x9c, 0x23, 0x62, 0x15,
+	0xf8, 0xd1, 0x27, 0x5e, 0xba, 0x8d, 0xf5, 0xd2, 0x9e, 0xbf, 0xde, 0x87,
+	0xf5, 0x1d, 0xaf, 0xae, 0x3e, 0xb9, 0x8d, 0xbc, 0x3a, 0xa2, 0xf5, 0x41,
+	0xde, 0x43, 0x39, 0xe6, 0x99, 0x91, 0x2e, 0xef, 0xe3, 0x7e, 0xb6, 0xb7,
+	0xd4, 0xd0, 0x31, 0xe9, 0xed, 0xcf, 0x1f, 0x0f, 0x4b, 0xb8, 0x95, 0x3a,
+	0x2e, 0x2a, 0xc9, 0x29, 0xc6, 0x2c, 0xb0, 0x5d, 0x63, 0x5c, 0xeb, 0xcb,
+	0x75, 0x71, 0xfa, 0xff, 0xd4, 0xc5, 0x69, 0xeb, 0x23, 0xe5, 0x9d, 0xb0,
+	0xe6, 0xb1, 0xbe, 0x98, 0xae, 0x85, 0x2a, 0xba, 0xfa, 0xb5, 0xfb, 0x68,
+	0x99, 0x8e, 0x3f, 0xc9, 0xd3, 0x5e, 0xa5, 0x34, 0xa7, 0xfc, 0xb7, 0x49,
+	0x9e, 0x2d, 0xf7, 0x78, 0x85, 0x7b, 0x1c, 0x5c, 0x74, 0x89, 0x83, 0xf9,
+	0x96, 0xca, 0xf0, 0xa9, 0x3c, 0x75, 0x4c, 0x93, 0xcc, 0x4d, 0xfb, 0x7a,
+	0x66, 0xd4, 0xf3, 0x71, 0x73, 0x6b, 0xeb, 0x54, 0xcf, 0xc0, 0xbb, 0x71,
+	0x86, 0x3d, 0xfb, 0xd2, 0x21, 0xb3, 0xe7, 0x69, 0x77, 0x93, 0xe8, 0x8b,
+	0x06, 0x66, 0xe7, 0x59, 0x9b, 0x24, 0x16, 0x65, 0x50, 0x58, 0xf7, 0x1f,
+	0xb6, 0x4f, 0x40, 0xde, 0x62, 0xf2, 0xe1, 0x24, 0x7d, 0xfa, 0x3a, 0xf8,
+	0xc6, 0xcd, 0x35, 0xe7, 0xbb, 0xbd, 0xec, 0x13, 0x56, 0xd3, 0xbd, 0xa3,
+	0x4d, 0x1a, 0xc9, 0xe7, 0x8e, 0x7d, 0x5d, 0xe8, 0x83, 0xf1, 0x3a, 0x83,
+	0x58, 0x80, 0xb1, 0x47, 0x5c, 0x63, 0x8f, 0xd9, 0x02, 0xfb, 0x9a, 0xbc,
+	0xbc, 0x52, 0x93, 0xf2, 0x0a, 0xf9, 0x2d, 0xad, 0xfe, 0xf7, 0x80, 0xea,
+	0xac, 0xdc, 0x64, 0xb7, 0xc1, 0xb1, 0xd8, 0x31, 0xe5, 0x3d, 0xa9, 0xe2,
+	0xbd, 0x98, 0xef, 0x4b, 0xb6, 0x19, 0xdf, 0xca, 0x56, 0x7d, 0x13, 0xd6,
+	0x79, 0xb4, 0x2b, 0x5c, 0x9f, 0xbc, 0x41, 0x1e, 0xa1, 0xce, 0xf3, 0xe7,
+	0xf9, 0xf4, 0xf0, 0xdb, 0x9c, 0x4f, 0xfe, 0xaf, 0xc4, 0x22, 0xf8, 0xb2,
+	0xea, 0xf7, 0xf9, 0x72, 0xc7, 0xb1, 0x4a, 0x9b, 0x40, 0xb9, 0xab, 0xac,
+	0x4f, 0xda, 0x12, 0x99, 0x5a, 0xa6, 0xcb, 0x50, 0x2f, 0xf7, 0xff, 0x3c,
+	0x73, 0xbb, 0x90, 0xb7, 0x95, 0x68, 0x73, 0x4c, 0x69, 0x93, 0x06, 0x6d,
+	0x22, 0x4a, 0x1b, 0xc6, 0x7b, 0x4f, 0x79, 0xfc, 0xd6, 0x84, 0xf3, 0x62,
+	0xae, 0x16, 0xba, 0x6e, 0x1f, 0x75, 0xfe, 0x33, 0x6d, 0x5a, 0x1f, 0x74,
+	0xa8, 0xfb, 0x56, 0x43, 0x9f, 0xb1, 0xbd, 0x59, 0xfd, 0x11, 0x13, 0x6f,
+	0xc5, 0x35, 0x0f, 0x1a, 0x84, 0x7e, 0x9e, 0x9d, 0x84, 0xaf, 0x46, 0xdc,
+	0x5b, 0x15, 0xad, 0x1e, 0xf7, 0xce, 0xeb, 0x55, 0xa5, 0x0d, 0x65, 0x80,
+	0x7a, 0x73, 0x0d, 0xd6, 0xdb, 0x13, 0xed, 0x01, 0x7f, 0xbd, 0x82, 0xfe,
+	0x8d, 0x1a, 0x4f, 0x04, 0x21, 0xf3, 0x37, 0x26, 0x5b, 0xbd, 0x18, 0xce,
+	0x41, 0x1b, 0x71, 0xeb, 0x64, 0x84, 0x31, 0x05, 0xda, 0x5d, 0x52, 0x37,
+	0x85, 0xf8, 0x15, 0x7a, 0x7c, 0x51, 0xed, 0x51, 0x0f, 0xc6, 0xef, 0x20,
+	0xce, 0x0f, 0xd7, 0x87, 0x71, 0x5f, 0xb7, 0xc1, 0x22, 0x44, 0x37, 0xe9,
+	0x99, 0xce, 0x4e, 0x26, 0x62, 0x87, 0xc4, 0xeb, 0x1b, 0x73, 0x55, 0x1f,
+	0x2c, 0xef, 0xeb, 0x01, 0xd9, 0x53, 0xb6, 0x17, 0x8c, 0xa3, 0xe1, 0xc3,
+	0x4f, 0x1b, 0x7b, 0x90, 0x2b, 0xf4, 0x28, 0x3e, 0x2a, 0x38, 0xb0, 0x80,
+	0xb3, 0xa4, 0x4f, 0xba, 0x04, 0x3f, 0xdc, 0xc5, 0x19, 0xd2, 0xef, 0x2e,
+	0x1d, 0x3f, 0xe9, 0xa6, 0x58, 0x1f, 0x83, 0x3e, 0x38, 0x2e, 0xc3, 0x88,
+	0x0b, 0x86, 0x83, 0xcd, 0xcc, 0x2b, 0xc3, 0x37, 0xcc, 0x7a, 0xb9, 0xc7,
+	0x1e, 0xe6, 0x4c, 0xe5, 0xec, 0x3c, 0xf7, 0x4e, 0xd9, 0x36, 0xb1, 0xf7,
+	0xec, 0x24, 0xf7, 0x6b, 0xf2, 0x10, 0x6c, 0x5b, 0x53, 0x2e, 0x7e, 0x79,
+	0x16, 0x7d, 0xf8, 0xed, 0x87, 0x3c, 0x70, 0x2e, 0x7e, 0xe7, 0x97, 0xe4,
+	0xbd, 0xf3, 0xbe, 0x6d, 0x0f, 0xc8, 0xbb, 0x4e, 0xe9, 0xf8, 0x09, 0x77,
+	0x2d, 0xcf, 0xc0, 0xcd, 0xb2, 0x66, 0xed, 0x38, 0x6e, 0x4e, 0x4a, 0xa5,
+	0x45, 0x77, 0x71, 0xad, 0xa5, 0xb4, 0xa4, 0xfc, 0x7f, 0x80, 0x33, 0xbc,
+	0x76, 0xaf, 0x25, 0x86, 0x7e, 0xa4, 0xcd, 0xe7, 0x6b, 0x7f, 0x95, 0xb6,
+	0xc0, 0xd7, 0x7f, 0xe4, 0x47, 0xf2, 0xe5, 0x92, 0xec, 0x54, 0xfd, 0xbf,
+	0xd2, 0x7d, 0x95, 0xba, 0xdf, 0xf7, 0x6f, 0xa9, 0xdf, 0xc9, 0x8b, 0x31,
+	0x8d, 0x0f, 0x36, 0x4d, 0xd5, 0xea, 0x84, 0x1f, 0x78, 0x75, 0x85, 0x95,
+	0x78, 0xef, 0x80, 0xa7, 0x17, 0x52, 0xea, 0x3b, 0xa7, 0x6c, 0xea, 0x07,
+	0xee, 0xa7, 0x51, 0xc6, 0x67, 0x6e, 0x83, 0x26, 0xbe, 0x0e, 0x66, 0xdc,
+	0xe7, 0xeb, 0x8e, 0x66, 0xcf, 0x17, 0xb6, 0xa4, 0xf3, 0x2c, 0x7d, 0x27,
+	0x07, 0x7a, 0xb4, 0x45, 0xd2, 0x63, 0x41, 0x49, 0x9e, 0x6d, 0x89, 0x19,
+	0x5f, 0x97, 0xfc, 0x07, 0x79, 0xd3, 0x3e, 0xb6, 0x37, 0xa0, 0xff, 0x4e,
+	0xe1, 0xb3, 0x0d, 0x3f, 0x43, 0x9e, 0xf7, 0xf9, 0x63, 0x76, 0x0d, 0x8f,
+	0xee, 0xf0, 0x78, 0x94, 0xe3, 0x96, 0xa9, 0x7f, 0x60, 0x6e, 0xe7, 0x59,
+	0xee, 0xd1, 0xdc, 0xd7, 0x79, 0xd6, 0xc4, 0xeb, 0xd5, 0xf7, 0xf5, 0x94,
+	0xef, 0xc3, 0x78, 0x97, 0x62, 0xc3, 0xb0, 0xf6, 0xce, 0x7e, 0xf8, 0x74,
+	0x3d, 0xb4, 0x39, 0xb4, 0xdf, 0x1b, 0xdd, 0x9d, 0x42, 0x7e, 0x4f, 0x78,
+	0x3c, 0x47, 0x7d, 0x13, 0xf1, 0xf4, 0xcd, 0xb2, 0x7d, 0x19, 0x36, 0xf8,
+	0x13, 0xe6, 0x44, 0x2a, 0xec, 0xcb, 0x43, 0xe6, 0xdd, 0xaa, 0xec, 0xcb,
+	0x9d, 0xde, 0x3a, 0xfe, 0x98, 0xaf, 0x57, 0xfc, 0xb6, 0xaf, 0x57, 0x6a,
+	0x7d, 0x5a, 0x9f, 0xf6, 0xd5, 0xb8, 0xaf, 0xca, 0x98, 0x2f, 0xb7, 0x62,
+	0xde, 0x25, 0x83, 0x98, 0x8d, 0x3e, 0x65, 0x22, 0x6b, 0x30, 0xd3, 0xd6,
+	0x19, 0x8b, 0xb8, 0x0f, 0xe7, 0x67, 0x32, 0x14, 0xb9, 0xad, 0xb1, 0xf5,
+	0xa9, 0x99, 0x51, 0xcd, 0xf3, 0xcc, 0xba, 0x9e, 0xde, 0x89, 0xee, 0x86,
+	0x5c, 0xcd, 0x47, 0x96, 0x31, 0x45, 0x4f, 0x1e, 0x1b, 0x82, 0x1d, 0x4a,
+	0x69, 0xbd, 0xec, 0x71, 0xec, 0xb7, 0x5f, 0xf1, 0x5c, 0xab, 0x9c, 0xe7,
+	0x64, 0x97, 0x5d, 0xd2, 0xda, 0x4d, 0xc3, 0x40, 0xf6, 0x58, 0xc3, 0x69,
+	0x9f, 0xef, 0xc9, 0x4f, 0x4f, 0x1e, 0x1b, 0x9f, 0x2e, 0x0d, 0x86, 0xb6,
+	0x75, 0xdb, 0x39, 0x59, 0x0f, 0x9a, 0x0f, 0xca, 0xa3, 0x8a, 0x1d, 0x7e,
+	0x0d, 0xe3, 0xfb, 0x18, 0x5f, 0x26, 0x42, 0x8a, 0x09, 0x4e, 0xc4, 0x26,
+	0x20, 0x8b, 0x19, 0x37, 0xd1, 0x35, 0x14, 0x5c, 0xcd, 0xdc, 0x0d, 0x62,
+	0x66, 0xfa, 0x59, 0xc4, 0x14, 0x3c, 0x2b, 0x87, 0xdc, 0x8d, 0xee, 0xa2,
+	0x64, 0x3d, 0x4c, 0x3e, 0x6b, 0x42, 0xf5, 0x32, 0xe1, 0x86, 0x1a, 0x86,
+	0x8a, 0x46, 0x06, 0x46, 0x82, 0xa9, 0x55, 0x27, 0x9d, 0x68, 0xc3, 0xce,
+	0x22, 0x64, 0xbc, 0x08, 0xfd, 0x5f, 0x8c, 0x05, 0x86, 0x15, 0x9b, 0xf6,
+	0x55, 0x19, 0x6a, 0xa5, 0x9f, 0x4f, 0x7d, 0xf2, 0x35, 0xb9, 0x61, 0x6f,
+	0x96, 0x1b, 0x5d, 0xc4, 0x63, 0xf6, 0xa2, 0x4d, 0x5d, 0xd2, 0x8f, 0xbe,
+	0x24, 0xfa, 0x1a, 0x94, 0x1f, 0x35, 0x3e, 0x83, 0xce, 0xba, 0x61, 0x53,
+	0x57, 0xdd, 0xc5, 0x5f, 0xbc, 0xeb, 0x9f, 0x41, 0x13, 0x62, 0x3b, 0xb6,
+	0xa0, 0x4d, 0x1d, 0x67, 0xd7, 0xf4, 0xb7, 0xa3, 0x7d, 0x2f, 0xd6, 0xa8,
+	0xd3, 0xf7, 0xb3, 0x9c, 0x6d, 0xa6, 0xce, 0x59, 0x35, 0x67, 0x4d, 0x4d,
+	0xfb, 0xdd, 0x16, 0x83, 0x4f, 0xb8, 0x45, 0x7a, 0x67, 0x53, 0xb2, 0xab,
+	0xad, 0xba, 0xfd, 0xcf, 0x9a, 0x76, 0xb3, 0xac, 0x6a, 0x21, 0x19, 0x9e,
+	0x68, 0xad, 0xee, 0xf7, 0xf9, 0xc9, 0x6f, 0xb7, 0xe1, 0x7d, 0x13, 0x30,
+	0x78, 0x49, 0x8d, 0xa5, 0x6e, 0x44, 0xf9, 0xac, 0xbf, 0xd6, 0xdc, 0xc3,
+	0x6b, 0xde, 0xc3, 0x7b, 0x99, 0xd7, 0xfb, 0x37, 0xfb, 0x71, 0x0f, 0x73,
+	0x02, 0xcc, 0x6b, 0x90, 0x67, 0x57, 0x8a, 0xb3, 0x38, 0xe7, 0xf3, 0xf9,
+	0x86, 0x74, 0x99, 0xf7, 0x7c, 0xbd, 0x12, 0x2b, 0x63, 0xd5, 0x76, 0xe6,
+	0xfd, 0x9c, 0x30, 0x69, 0xa7, 0x35, 0xa9, 0xd8, 0x75, 0xd0, 0xf9, 0x20,
+	0xe8, 0xfc, 0x40, 0x90, 0x71, 0x61, 0xa3, 0x47, 0x6b, 0x47, 0x86, 0x8b,
+	0x6f, 0x43, 0xc6, 0xc9, 0xa3, 0xf0, 0x29, 0x8a, 0x96, 0x87, 0xcf, 0xe8,
+	0x83, 0x4d, 0x73, 0x25, 0xa8, 0x79, 0x07, 0xc4, 0xf7, 0x73, 0xd7, 0x64,
+	0x78, 0x92, 0x39, 0x01, 0xf2, 0x33, 0xe3, 0xfa, 0x14, 0xc6, 0x6e, 0x62,
+	0xae, 0x0b, 0x19, 0x1e, 0x05, 0xbf, 0x86, 0xc4, 0x99, 0xda, 0x22, 0xd9,
+	0xb1, 0x51, 0xf5, 0x01, 0x3a, 0x61, 0xa3, 0x4e, 0xb8, 0x23, 0x72, 0xf2,
+	0xf2, 0xdd, 0x90, 0x55, 0xc6, 0xfd, 0x9a, 0xd3, 0x28, 0x85, 0xd5, 0x37,
+	0xa7, 0xcf, 0xc1, 0x3c, 0x9c, 0xa9, 0x31, 0x1b, 0xb9, 0x7d, 0x24, 0x26,
+	0xcd, 0x23, 0x32, 0x3d, 0x63, 0x2b, 0xde, 0x25, 0x25, 0xb7, 0x4b, 0xa4,
+	0x5d, 0x66, 0x5f, 0x1c, 0xba, 0x8a, 0xbe, 0x7c, 0x2e, 0x62, 0xce, 0x72,
+	0x74, 0x1d, 0x63, 0xe2, 0xe4, 0x54, 0xe5, 0x1a, 0x8a, 0x91, 0xc1, 0xd8,
+	0xa5, 0x16, 0x23, 0x33, 0x8c, 0x8f, 0x3f, 0x2a, 0xa5, 0xa2, 0x7c, 0x26,
+	0xe7, 0xb2, 0x76, 0x4b, 0x1e, 0xe1, 0xde, 0xfe, 0xe3, 0xf1, 0xf2, 0x4b,
+	0x58, 0x2f, 0x2e, 0x9d, 0xaf, 0x8f, 0x6a, 0x5c, 0x7f, 0xa2, 0x2a, 0x86,
+	0x35, 0xf9, 0x02, 0x13, 0xc7, 0x5e, 0x93, 0x89, 0x05, 0xd2, 0x87, 0x36,
+	0x3e, 0x20, 0x3f, 0x77, 0xba, 0xed, 0xc7, 0xb4, 0xd6, 0x98, 0x48, 0xb1,
+	0x3e, 0xd3, 0xe8, 0x24, 0xed, 0x39, 0x09, 0xf5, 0x7f, 0x03, 0xd7, 0x8c,
+	0x6b, 0x73, 0x6e, 0xb7, 0xfb, 0x98, 0xf8, 0x38, 0x90, 0x8d, 0xa9, 0xfa,
+	0xc0, 0xad, 0xd2, 0xb5, 0x7d, 0x9c, 0x63, 0x70, 0x20, 0x12, 0x20, 0xad,
+	0x3e, 0xb8, 0x8b, 0xf8, 0x99, 0xea, 0xfc, 0xdf, 0xfd, 0x47, 0xf6, 0xf6,
+	0x25, 0x5e, 0x64, 0x0c, 0x1b, 0x76, 0x0e, 0xac, 0x33, 0xef, 0x9a, 0xcd,
+	0xae, 0x11, 0xad, 0x9f, 0x1d, 0xfd, 0xbb, 0x43, 0x3c, 0x44, 0x22, 0x56,
+	0x6f, 0x31, 0x0f, 0x4e, 0x1d, 0xc7, 0x9a, 0x0a, 0x73, 0x6e, 0xc4, 0xf2,
+	0x37, 0xc8, 0xa5, 0x1e, 0x4b, 0xee, 0x0f, 0xa5, 0xe2, 0x96, 0x6c, 0x8a,
+	0x9f, 0x15, 0x3c, 0x93, 0xf5, 0x95, 0x85, 0x44, 0x96, 0xf3, 0x43, 0x53,
+	0x5c, 0x2f, 0xae, 0xf1, 0x4a, 0x72, 0x53, 0xa9, 0xf4, 0x94, 0x2b, 0x81,
+	0xe4, 0xd6, 0x8f, 0x4b, 0xac, 0x85, 0x5b, 0xaf, 0x7f, 0x11, 0x4e, 0x41,
+	0xbf, 0x1d, 0x98, 0x30, 0x98, 0xc3, 0x89, 0xa3, 0x9d, 0x0b, 0x6c, 0xa7,
+	0x77, 0x99, 0xf6, 0x61, 0xb4, 0xeb, 0x3c, 0xac, 0xd3, 0x0f, 0x8f, 0x76,
+	0x16, 0x9e, 0x58, 0x67, 0xe2, 0xef, 0x25, 0xc5, 0x7f, 0xbd, 0x53, 0x15,
+	0xd3, 0xa4, 0x02, 0x63, 0xf9, 0xd1, 0xc0, 0x68, 0xde, 0xea, 0x69, 0x00,
+	0xad, 0xe6, 0x5d, 0xe6, 0x6a, 0xfc, 0x9c, 0x15, 0xf3, 0xfd, 0x22, 0x4f,
+	0x2a, 0x46, 0x8a, 0x35, 0x45, 0x4b, 0x7d, 0xa1, 0x83, 0xf3, 0xcc, 0xf1,
+	0x47, 0x54, 0x1f, 0x1c, 0x5a, 0x68, 0x96, 0x9c, 0xbd, 0x56, 0x72, 0x2a,
+	0xe3, 0x51, 0xd5, 0x01, 0x96, 0xb3, 0x15, 0x7d, 0xdc, 0xf7, 0x43, 0x8a,
+	0x8b, 0x78, 0x23, 0xdf, 0x8e, 0x36, 0x73, 0xcd, 0xdb, 0x6b, 0xfa, 0x2b,
+	0xeb, 0xb2, 0x09, 0xdb, 0xb2, 0x6a, 0x6b, 0xb2, 0xec, 0xab, 0xad, 0xc5,
+	0x9e, 0x92, 0x6b, 0xe4, 0x9b, 0xa2, 0x9f, 0x73, 0x77, 0xbd, 0x9c, 0xfb,
+	0xf7, 0xb1, 0x26, 0xd7, 0x96, 0x74, 0x68, 0xa0, 0xa1, 0xe7, 0xc4, 0x64,
+	0xf0, 0xe6, 0x72, 0xfe, 0x14, 0xed, 0x85, 0x72, 0xad, 0x1c, 0x63, 0xcf,
+	0xc0, 0x17, 0xc9, 0xc1, 0xaf, 0xc8, 0x7a, 0xdf, 0x1f, 0x70, 0xbc, 0x7c,
+	0xff, 0x97, 0xec, 0xa9, 0x51, 0xeb, 0xec, 0x56, 0x55, 0x9d, 0xfd, 0x7b,
+	0xb8, 0x97, 0x35, 0xf6, 0x6c, 0xa9, 0x0e, 0xbc, 0x5b, 0x47, 0x9c, 0x48,
+	0x79, 0x3e, 0x75, 0xbc, 0xea, 0x72, 0x5d, 0x6b, 0xa7, 0xb7, 0x56, 0x10,
+	0x7a, 0x7e, 0x7c, 0xd2, 0x9f, 0x73, 0x5c, 0xea, 0x7b, 0x13, 0xb1, 0xa0,
+	0xc5, 0x39, 0x46, 0xdf, 0x0f, 0xb9, 0xc7, 0xa1, 0xc7, 0xa9, 0xf3, 0xf9,
+	0xde, 0x0e, 0x7c, 0x3d, 0xea, 0x02, 0xea, 0x73, 0xb5, 0x01, 0xf1, 0x1c,
+	0x74, 0xfd, 0x70, 0xd1, 0x7c, 0xeb, 0xf5, 0xf5, 0x60, 0x62, 0x3a, 0xa3,
+	0xba, 0x01, 0xfe, 0x5e, 0xf1, 0x0d, 0xe6, 0x83, 0x5e, 0x94, 0x40, 0x65,
+	0x9d, 0x86, 0xb1, 0x19, 0x6b, 0x1a, 0x4d, 0xd0, 0x0d, 0x22, 0x57, 0xc0,
+	0x1b, 0x57, 0xe7, 0xc9, 0xaf, 0xc1, 0x56, 0x13, 0x5f, 0x2d, 0x6e, 0xb7,
+	0xa4, 0x55, 0x6b, 0x9f, 0x39, 0x27, 0x42, 0xff, 0x64, 0x30, 0xd9, 0x0b,
+	0x3f, 0x5b, 0xb1, 0x07, 0xcc, 0x57, 0x8e, 0x23, 0x1e, 0xab, 0xcc, 0xb1,
+	0x40, 0xbe, 0xc6, 0xd8, 0x9f, 0x81, 0x5f, 0xb9, 0x5c, 0xf7, 0xc8, 0x15,
+	0x4e, 0x6a, 0x6e, 0x73, 0x76, 0xbe, 0x49, 0x75, 0xec, 0x6c, 0x61, 0x04,
+	0xe7, 0x22, 0x9b, 0xad, 0x81, 0x9c, 0xd7, 0x1f, 0x96, 0x42, 0x81, 0x6d,
+	0xe9, 0xa8, 0xd3, 0x73, 0xf7, 0x6b, 0x3b, 0xb6, 0xcc, 0xc1, 0x57, 0x2c,
+	0x2c, 0x38, 0xf8, 0xef, 0xc2, 0x7f, 0x0f, 0xfe, 0x77, 0xcb, 0xd0, 0x14,
+	0xfd, 0x57, 0xd6, 0x72, 0x9a, 0x6a, 0x9e, 0x4f, 0x1f, 0xa9, 0x43, 0x71,
+	0x60, 0x39, 0x2f, 0xce, 0xc9, 0x15, 0x6a, 0xe5, 0x84, 0x79, 0x52, 0x5f,
+	0x47, 0x30, 0x5f, 0xea, 0xd7, 0xfa, 0x2a, 0x6b, 0x58, 0x96, 0x57, 0xf7,
+	0x22, 0x4f, 0x37, 0xca, 0xa1, 0x82, 0x5f, 0xbb, 0x8a, 0xc9, 0xa3, 0xe5,
+	0xda, 0x95, 0xa4, 0x83, 0x03, 0xb7, 0x1e, 0xcc, 0x4c, 0x2a, 0x9e, 0xc0,
+	0xb2, 0x06, 0xae, 0x3d, 0x38, 0xb1, 0xf0, 0xee, 0x83, 0xcb, 0x98, 0x70,
+	0x8c, 0x2d, 0xac, 0x84, 0x19, 0x22, 0x96, 0xee, 0x33, 0xf2, 0x10, 0x0d,
+	0x27, 0xf6, 0xed, 0xc7, 0x3c, 0xc4, 0xd9, 0x6d, 0xb0, 0x97, 0xf1, 0xcb,
+	0x7e, 0x3c, 0x4a, 0x1c, 0x29, 0xef, 0xab, 0xc4, 0x7e, 0x84, 0x70, 0xfe,
+	0x12, 0xb0, 0x9c, 0x2c, 0xf6, 0x71, 0xa1, 0xdd, 0xf8, 0x81, 0xc4, 0x99,
+	0x26, 0x2a, 0xb0, 0x47, 0x3e, 0xd6, 0xf4, 0x65, 0xac, 0x95, 0x96, 0xdf,
+	0x14, 0x1f, 0x96, 0x5f, 0x16, 0x47, 0x21, 0xdf, 0x13, 0x58, 0xf3, 0x80,
+	0xfc, 0xa2, 0xb8, 0x4f, 0xde, 0x2a, 0x8e, 0xc9, 0x9b, 0xc5, 0xdd, 0x88,
+	0xa9, 0x46, 0x88, 0xf5, 0xf4, 0xb0, 0xd2, 0x83, 0x32, 0x7e, 0x4e, 0x31,
+	0x80, 0x37, 0xe9, 0xf7, 0x1c, 0x55, 0x3f, 0x9b, 0xf8, 0xfa, 0xc4, 0xaf,
+	0x18, 0xcf, 0x13, 0x9b, 0x59, 0x28, 0xfa, 0x18, 0x8e, 0x89, 0x0e, 0x3c,
+	0xdb, 0xe6, 0xb7, 0x29, 0xc3, 0xe7, 0x22, 0x81, 0x91, 0x73, 0xa1, 0xc0,
+	0x03, 0xfa, 0x9d, 0x0b, 0xeb, 0x9d, 0x25, 0x39, 0xe9, 0x3a, 0xe4, 0xcd,
+	0xfe, 0x61, 0xc8, 0xc2, 0x08, 0x54, 0xfd, 0x2e, 0x67, 0xad, 0x80, 0xa4,
+	0xa9, 0x4f, 0xe0, 0x67, 0x26, 0x4f, 0xbb, 0x92, 0xc9, 0xcf, 0x05, 0x0c,
+	0x1e, 0xcd, 0x46, 0xbb, 0x07, 0xed, 0x57, 0xbd, 0xf6, 0x0e, 0xc9, 0xcc,
+	0x48, 0xea, 0x43, 0xf5, 0x87, 0x5f, 0xf1, 0xfa, 0xfa, 0xd1, 0x07, 0xce,
+	0xbc, 0xc0, 0xbe, 0x0b, 0x5e, 0x1f, 0xcf, 0x84, 0xb5, 0xfa, 0xb8, 0xf2,
+	0x55, 0xc6, 0x1e, 0x13, 0xfd, 0xae, 0x41, 0x6b, 0xf1, 0x4b, 0xed, 0x46,
+	0xb7, 0x11, 0x13, 0xf8, 0x8f, 0x76, 0xc6, 0x60, 0x05, 0xc8, 0xd7, 0x5d,
+	0xd0, 0x89, 0x7f, 0xd9, 0xbc, 0xdc, 0xb6, 0x06, 0x3e, 0xad, 0xc0, 0x68,
+	0x7f, 0x2a, 0x9d, 0x0b, 0xff, 0xf2, 0xf0, 0xbc, 0x07, 0xf1, 0x6e, 0x38,
+	0xab, 0x3c, 0x71, 0xe3, 0x71, 0xc8, 0x76, 0x93, 0xac, 0x3d, 0x43, 0x7a,
+	0x75, 0x43, 0x57, 0xa7, 0x20, 0xb7, 0xae, 0xcc, 0x17, 0x43, 0x81, 0xe1,
+	0x7c, 0x4a, 0x0c, 0x9e, 0xda, 0x92, 0x74, 0x34, 0x25, 0xa7, 0xfa, 0x12,
+	0x5d, 0xcc, 0x43, 0x66, 0x7a, 0x5d, 0xb9, 0x58, 0xa4, 0x3d, 0xce, 0xca,
+	0xa5, 0xbe, 0x84, 0x5b, 0x10, 0xe2, 0x62, 0x5c, 0xb9, 0x04, 0xd9, 0xfc,
+	0xdd, 0xb9, 0xdd, 0xf2, 0x68, 0x5e, 0xfd, 0xe0, 0xee, 0xb0, 0xbc, 0x20,
+	0x17, 0xfb, 0x5e, 0xb8, 0x79, 0xd1, 0x7d, 0x04, 0x67, 0x4a, 0x3e, 0xcc,
+	0x74, 0x98, 0x7d, 0x2b, 0x0e, 0x49, 0x98, 0x0f, 0xd1, 0x9a, 0x9a, 0x53,
+	0x2f, 0x43, 0xfb, 0x23, 0x5e, 0x5c, 0x0e, 0x9f, 0x3b, 0xe0, 0x9a, 0x7a,
+	0x4a, 0xc0, 0xdf, 0x67, 0x18, 0x7e, 0x0c, 0xef, 0xf3, 0x69, 0xe3, 0xaf,
+	0xd3, 0x1e, 0x18, 0x9a, 0x69, 0x96, 0xd0, 0x85, 0xaf, 0x80, 0xae, 0x21,
+	0x39, 0xd8, 0x5b, 0x2a, 0x7d, 0xc7, 0x0d, 0xc5, 0x27, 0x10, 0xa3, 0x60,
+	0xff, 0xb2, 0xe6, 0x74, 0x0b, 0x68, 0xd2, 0x20, 0xd1, 0xd3, 0xfe, 0xf3,
+	0xea, 0x3d, 0x2c, 0xc3, 0x99, 0x35, 0xc6, 0x96, 0xf9, 0xd8, 0x06, 0x7f,
+	0x3d, 0x83, 0x29, 0xeb, 0xb4, 0x7a, 0x03, 0xde, 0x77, 0x12, 0x5e, 0x7b,
+	0x6b, 0xe0, 0xfe, 0x50, 0xab, 0x84, 0x9c, 0x67, 0xd7, 0x13, 0x1b, 0xb9,
+	0x98, 0xf7, 0xfb, 0xe1, 0x27, 0x86, 0x7c, 0x7f, 0x58, 0xb6, 0x2d, 0x9f,
+	0xb5, 0x6c, 0xeb, 0x5c, 0xf8, 0xae, 0xb7, 0x66, 0xca, 0x9b, 0x8b, 0x98,
+	0x23, 0xb6, 0x5a, 0xed, 0x93, 0x99, 0xfb, 0x5f, 0x79, 0xba, 0x37, 0xf1,
+	0x9a, 0xe2, 0x64, 0xcb, 0xf7, 0x70, 0x1c, 0x31, 0x64, 0x51, 0xef, 0x89,
+	0xed, 0x01, 0x7d, 0xd3, 0xb1, 0x7b, 0xec, 0x39, 0x2b, 0x18, 0x30, 0xfe,
+	0x48, 0x9d, 0xfc, 0x28, 0x0a, 0xbb, 0xcd, 0x6f, 0x58, 0x98, 0xff, 0x72,
+	0x6f, 0x7b, 0x7e, 0x0a, 0xfb, 0x12, 0x2f, 0x26, 0xad, 0x34, 0xf6, 0xc7,
+	0x33, 0x20, 0x06, 0xd4, 0x02, 0x9d, 0xda, 0xf1, 0x7e, 0x88, 0x9f, 0x7a,
+	0xfd, 0xf7, 0x5f, 0x03, 0x1d, 0xc6, 0xfd, 0x1b, 0x5c, 0x98, 0x58, 0xcc,
+	0x85, 0x0c, 0x7a, 0x18, 0xd8, 0x4a, 0xb9, 0xf5, 0xb1, 0xb1, 0x3e, 0x9e,
+	0x8e, 0x18, 0xa5, 0x18, 0xfc, 0x40, 0xca, 0x04, 0x79, 0xb3, 0x0d, 0xfd,
+	0xab, 0x6e, 0xa5, 0xf4, 0xd5, 0xfd, 0xbe, 0x8f, 0xcb, 0xd8, 0xee, 0x89,
+	0xfc, 0x3e, 0x83, 0xcd, 0xb3, 0x96, 0x24, 0xd5, 0x91, 0xb4, 0x4f, 0x62,
+	0xbf, 0x43, 0xa1, 0x44, 0x21, 0x2b, 0x31, 0x99, 0x83, 0xbe, 0xb8, 0x0a,
+	0xd9, 0x7f, 0xab, 0xc8, 0xef, 0x6d, 0x53, 0x72, 0x28, 0x0f, 0x83, 0x3e,
+	0xa3, 0xdf, 0x7e, 0x41, 0xef, 0x0f, 0xc8, 0x6c, 0x3e, 0xd1, 0x35, 0x07,
+	0xfe, 0x9b, 0xcb, 0x13, 0x5f, 0xd4, 0x1d, 0x1f, 0xc1, 0x8a, 0x8b, 0xf9,
+	0x8d, 0xb0, 0x0f, 0x92, 0xba, 0x08, 0xff, 0xe7, 0x62, 0xb1, 0x0b, 0x7c,
+	0x86, 0xf1, 0xa2, 0x83, 0x5f, 0xe8, 0xcc, 0x62, 0x1f, 0xe4, 0x9c, 0x7b,
+	0xb1, 0x65, 0x7e, 0x33, 0xce, 0x8e, 0x38, 0x22, 0xc5, 0x8f, 0x7f, 0x86,
+	0xf3, 0xf5, 0xdf, 0x7b, 0xbb, 0xda, 0xe9, 0x39, 0xdd, 0x17, 0xec, 0x32,
+	0x62, 0x80, 0x4c, 0xaf, 0xb1, 0xdb, 0x43, 0x91, 0x16, 0x19, 0xba, 0x87,
+	0x76, 0xbc, 0x55, 0x63, 0x44, 0xe5, 0xc5, 0x08, 0xc7, 0x7f, 0xbb, 0xde,
+	0xd0, 0x2f, 0x5c, 0xd3, 0x7e, 0x1b, 0xbf, 0xcd, 0xd2, 0xe6, 0xf0, 0xd7,
+	0xc6, 0xef, 0xb5, 0xf5, 0xac, 0xef, 0xb6, 0x39, 0x49, 0x3c, 0xeb, 0xd7,
+	0x5e, 0xbe, 0x00, 0xd7, 0x73, 0xbc, 0x67, 0x9d, 0xf7, 0x5c, 0xae, 0xdb,
+	0x8c, 0x75, 0x9a, 0xbc, 0x67, 0x35, 0x6b, 0x7e, 0xd2, 0x3c, 0x0b, 0x31,
+	0x6e, 0xfe, 0x4f, 0xeb, 0x79, 0x86, 0xfc, 0xde, 0xb8, 0xba, 0xfd, 0xc7,
+	0xf5, 0xc4, 0xcd, 0xb5, 0x39, 0xcd, 0x8a, 0xf1, 0xbc, 0xd1, 0xda, 0x8a,
+	0x6b, 0x3e, 0x93, 0x73, 0x4c, 0x3e, 0x7c, 0xb6, 0xc8, 0xf5, 0xd9, 0x4e,
+	0xc9, 0x31, 0xcd, 0x67, 0x18, 0x2c, 0xdf, 0x6c, 0xfe, 0x3e, 0x99, 0x38,
+	0xa7, 0xf8, 0xba, 0xe9, 0x9c, 0xc5, 0xef, 0x5e, 0xf8, 0xbd, 0x1c, 0x7d,
+	0x89, 0x51, 0x19, 0xc7, 0xf9, 0x5d, 0x82, 0x4f, 0xb5, 0x68, 0xbe, 0x8b,
+	0xc5, 0xdf, 0x01, 0x9c, 0x4b, 0x08, 0x32, 0x46, 0x19, 0xa5, 0x4c, 0xe1,
+	0xfc, 0xc6, 0x6c, 0x79, 0xaf, 0x8f, 0xf2, 0xdc, 0x27, 0x97, 0xcb, 0xf2,
+	0x9c, 0x85, 0x3c, 0x53, 0x96, 0xb3, 0x90, 0x69, 0xc3, 0xd7, 0xfb, 0x11,
+	0x63, 0xa4, 0x62, 0xb0, 0x57, 0xea, 0x43, 0xbc, 0x0c, 0xbe, 0xb6, 0xbd,
+	0x6f, 0xa5, 0x02, 0x9a, 0xc3, 0xc9, 0xcc, 0xd4, 0x79, 0xdf, 0x01, 0xe0,
+	0xfa, 0xf2, 0x73, 0x32, 0x34, 0xd3, 0x88, 0x7d, 0x6f, 0xe8, 0xe0, 0x99,
+	0x65, 0x2e, 0xf3, 0xdf, 0xe7, 0x45, 0xe2, 0x4d, 0xe9, 0xcf, 0xf2, 0x9a,
+	0x71, 0xde, 0x7a, 0xcc, 0xe9, 0x07, 0x9d, 0x1b, 0xb1, 0x3e, 0xf7, 0xb8,
+	0xd2, 0x3c, 0x8e, 0x87, 0x2a, 0xf0, 0xa9, 0x3e, 0xbd, 0x57, 0xeb, 0x33,
+	0x33, 0xbd, 0x8d, 0xde, 0xfb, 0xf1, 0x1c, 0xc8, 0xf7, 0x31, 0xf0, 0x2d,
+	0x7d, 0x62, 0xf2, 0x4b, 0x4a, 0xcf, 0x61, 0x36, 0x4f, 0xfe, 0x0d, 0x69,
+	0x0e, 0x23, 0x03, 0xdb, 0xb2, 0x57, 0xe7, 0xc7, 0x96, 0xe5, 0xbb, 0x23,
+	0xa0, 0x71, 0x77, 0x26, 0xbf, 0x4a, 0x3a, 0x55, 0x07, 0x75, 0x78, 0xbc,
+	0x0d, 0x7b, 0xa1, 0x58, 0xee, 0x03, 0x72, 0xb4, 0xd8, 0x0f, 0x3a, 0xc4,
+	0xe4, 0x29, 0xf8, 0xcd, 0xcf, 0x14, 0xef, 0x90, 0xa5, 0x08, 0xf6, 0x55,
+	0x96, 0xb1, 0x41, 0xf9, 0xf1, 0xdc, 0x06, 0xef, 0x3a, 0xe1, 0x2e, 0x59,
+	0xdb, 0xb1, 0x07, 0xca, 0x13, 0xe5, 0x8a, 0xf3, 0x82, 0x88, 0x45, 0xb8,
+	0xee, 0x11, 0xa3, 0xdb, 0xb0, 0x6e, 0x21, 0x42, 0xf9, 0xe5, 0xde, 0x42,
+	0x9e, 0xcc, 0x32, 0xae, 0xe2, 0x3b, 0x1b, 0x9b, 0x94, 0xae, 0x3a, 0x8b,
+	0x84, 0xe2, 0x40, 0x97, 0xcf, 0xc0, 0x5f, 0xc7, 0x97, 0x4b, 0xff, 0x3b,
+	0x0a, 0xea, 0x51, 0xd8, 0xca, 0x3c, 0x6c, 0x65, 0x1e, 0x36, 0x12, 0xb2,
+	0xf0, 0x56, 0x1e, 0x36, 0x32, 0x0f, 0x1b, 0x09, 0x7d, 0xf6, 0x06, 0x62,
+	0xbb, 0xab, 0xe0, 0x21, 0xe3, 0x6b, 0x1f, 0xa6, 0xaf, 0x8d, 0xbf, 0xff,
+	0x01, 0x88, 0x97, 0xee, 0xe9, 0xc4, 0x71, 0x00, 0x00, 0x00 };
 
-static u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_RXP_b06FwRodata[(0x278/4) + 1] = {
-	0x08003fdc, 0x08003edc, 0x08003f80, 0x08003f98, 0x08003fb0, 0x08003fd0,
-	0x08003fdc, 0x08003fdc, 0x08003ee4, 0x00000000, 0x08004a04, 0x08004a3c,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004a74, 0x08004c38,
-	0x08004b80, 0x08004bb8, 0x08004c38, 0x08004b08, 0x08004c38, 0x08004c38,
-	0x08004bb8, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004bf8,
-	0x08004c38, 0x08004bf8, 0x08004b80, 0x08004c38, 0x08004c38, 0x08004bf8,
-	0x08004bf8, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38,
-	0x08004ae4, 0x00000000, 0x08006018, 0x08006030, 0x08006030, 0x08006030,
-	0x08006018, 0x08006030, 0x08006030, 0x08006030, 0x08006018, 0x08006030,
-	0x08006030, 0x08006030, 0x08006018, 0x08006030, 0x08006030, 0x08006030,
-	0x08006024, 0x00000000, 0x00000000 };
+static const u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_RXP_b06FwRodata[(0x24/4) + 1] = {
+	0x08004580, 0x08004580, 0x080044f8, 0x08004530, 0x08004564, 0x08004588,
+	0x08004588, 0x08004588, 0x08004468, 0x00000000 };
 
 static struct fw_info bnx2_rxp_fw_06 = {
-	.ver_major			= 0x2,
-	.ver_minor			= 0x8,
-	.ver_fix			= 0x17,
+	/* Firmware version: 4.0.5 */
+	.ver_major			= 0x4,
+	.ver_minor			= 0x0,
+	.ver_fix			= 0x5,
 
-	.start_addr			= 0x08003184,
+	.start_addr			= 0x080031d0,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x6728,
+	.text_len			= 0x71c0,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_RXP_b06FwText,
 	.gz_text_len			= sizeof(bnx2_RXP_b06FwText),
 
-	.data_addr			= 0x080069c0,
+	.data_addr			= 0x00000000,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_RXP_b06FwData,
 
-	.sbss_addr			= 0x080069c0,
-	.sbss_len			= 0x2c,
+	.sbss_addr			= 0x08007200,
+	.sbss_len			= 0x58,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x080069f0,
-	.bss_len			= 0x13dc,
+	.bss_addr			= 0x08007258,
+	.bss_len			= 0x44c,
 	.bss_index			= 0x0,
 
-	.rodata_addr			= 0x08006728,
-	.rodata_len			= 0x278,
+	.rodata_addr			= 0x080071c0,
+	.rodata_len			= 0x24,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_RXP_b06FwRodata,
 };
 
 static u8 bnx2_rv2p_proc1[] = {
-/*	0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
-							0xc5, 0x56, 0xcf, 0x6b,
-	0x13, 0x51, 0x10, 0x9e, 0xec, 0x6e, 0xb2, 0xdb, 0x74, 0xbb, 0x1b, 0x2b,
-	0xda, 0xa0, 0xb1, 0x8d, 0x51, 0x6a, 0x7f, 0xa4, 0xb4, 0x11, 0x0f, 0x82,
-	0x42, 0x25, 0x3d, 0x04, 0x54, 0x44, 0x7a, 0x28, 0x22, 0x82, 0x36, 0x8a,
-	0xfe, 0x1b, 0xa1, 0x3f, 0xd2, 0x4b, 0x10, 0x7a, 0xb0, 0x58, 0xf1, 0x50,
-	0x10, 0x2a, 0x68, 0x0f, 0xc9, 0xa1, 0x20, 0x52, 0x11, 0xda, 0x8b, 0x07,
-	0x2f, 0x42, 0x0f, 0x7a, 0x69, 0xbd, 0xa8, 0xff, 0x82, 0x08, 0x4d, 0x7c,
-	0x6f, 0x66, 0x9e, 0xee, 0x6e, 0xb2, 0x4d, 0x15, 0xc1, 0x85, 0xf6, 0xe3,
-	0xbd, 0x9d, 0x79, 0x33, 0xf3, 0xcd, 0x37, 0xfb, 0x62, 0x01, 0x40, 0x04,
-	0x60, 0xcd, 0x46, 0x2c, 0x8d, 0x26, 0x04, 0x1a, 0x30, 0x7e, 0x52, 0x62,
-	0x16, 0xde, 0xa6, 0x25, 0x4e, 0x44, 0xc6, 0xd3, 0x49, 0x81, 0x7b, 0x0d,
-	0x28, 0xc9, 0x75, 0x4f, 0xf5, 0x55, 0xad, 0x53, 0xa0, 0x06, 0xbb, 0xa3,
-	0x80, 0xcf, 0x47, 0x9d, 0xf0, 0x7c, 0xd6, 0x42, 0x2c, 0x31, 0xc2, 0x48,
-	0x02, 0x61, 0x7b, 0x51, 0xae, 0xad, 0x48, 0x69, 0xc4, 0x42, 0x3f, 0xd0,
-	0x68, 0x7f, 0x67, 0xd1, 0x15, 0xff, 0x53, 0xf0, 0x39, 0x2f, 0xd7, 0x56,
-	0x7c, 0x0e, 0xed, 0xaa, 0xec, 0x2f, 0xfe, 0xd0, 0xfe, 0xba, 0xf0, 0x03,
-	0x7e, 0x94, 0x5f, 0x02, 0xcf, 0x29, 0x66, 0x65, 0x5e, 0xdd, 0x22, 0xa0,
-	0xca, 0xc7, 0x46, 0x2c, 0xf5, 0x91, 0xb5, 0x89, 0xef, 0xbf, 0x8a, 0xbc,
-	0x55, 0xdc, 0x76, 0xf1, 0x82, 0xf9, 0x06, 0xe3, 0x26, 0x91, 0x1f, 0x28,
-	0xf9, 0xe3, 0x00, 0xc8, 0xfd, 0x4f, 0x8d, 0x5f, 0xfb, 0x83, 0xfe, 0xf7,
-	0xbb, 0x43, 0xf2, 0xbc, 0x28, 0xc0, 0x90, 0xb4, 0xdb, 0xe6, 0x7c, 0xc6,
-	0xe0, 0xb4, 0x96, 0xc4, 0xf7, 0x06, 0xfa, 0x1f, 0x11, 0xe7, 0x4a, 0xec,
-	0x61, 0x3c, 0xce, 0x78, 0x95, 0xb1, 0xc2, 0xe8, 0x32, 0x3a, 0x8c, 0x5d,
-	0x8c, 0x36, 0xe3, 0x26, 0x63, 0x9c, 0xb1, 0x83, 0xd1, 0x62, 0xdc, 0x63,
-	0x8c, 0x31, 0x46, 0x19, 0x1b, 0x8c, 0x46, 0x84, 0x50, 0xe3, 0xf5, 0x63,
-	0x46, 0xe0, 0xba, 0x23, 0x81, 0xba, 0x5f, 0xb3, 0x2e, 0x24, 0x6f, 0xfc,
-	0x7e, 0x50, 0xd9, 0x31, 0xef, 0x58, 0xf7, 0x3a, 0xdb, 0x75, 0x57, 0x57,
-	0x02, 0xfa, 0x49, 0xef, 0xab, 0x9b, 0x54, 0x8b, 0x3e, 0xb8, 0x58, 0xcf,
-	0x9d, 0x82, 0x8b, 0x71, 0x9c, 0x18, 0xed, 0xab, 0xb4, 0x6e, 0xb8, 0x84,
-	0xf7, 0xe2, 0x84, 0x5f, 0x18, 0xef, 0x77, 0x12, 0x4e, 0x77, 0xc9, 0x7c,
-	0x0e, 0x8b, 0x80, 0xea, 0x1c, 0x95, 0x4f, 0xbb, 0x3c, 0xc2, 0xe2, 0xa9,
-	0xbc, 0xda, 0xc5, 0x25, 0x2c, 0x6a, 0xfe, 0xfa, 0x9f, 0x8c, 0x11, 0x1a,
-	0x39, 0x22, 0x75, 0xc9, 0x16, 0x3d, 0x83, 0x46, 0x63, 0xd9, 0x36, 0xe4,
-	0xfa, 0xdc, 0xf2, 0x7b, 0xd4, 0xfb, 0xd9, 0xa5, 0x1a, 0xe7, 0xe7, 0x2a,
-	0x9e, 0x69, 0x0e, 0x32, 0x40, 0xeb, 0x49, 0xe4, 0x1d, 0x04, 0x5a, 0xb8,
-	0x86, 0x8c, 0xbf, 0x5f, 0xa4, 0x43, 0x9d, 0xfb, 0x31, 0xcb, 0xfd, 0x38,
-	0x11, 0xd2, 0x8f, 0xb0, 0xb9, 0x68, 0x9e, 0xc7, 0xdb, 0xe9, 0x20, 0x6f,
-	0x61, 0xf3, 0xa3, 0xf8, 0xa6, 0xdd, 0x3f, 0xe5, 0xf1, 0x01, 0xf3, 0x58,
-	0x24, 0x1e, 0x93, 0xdf, 0x5a, 0xf2, 0x94, 0xf6, 0xf0, 0x24, 0xeb, 0xec,
-	0x0d, 0xe9, 0x73, 0x58, 0x7d, 0xd9, 0xbf, 0xee, 0x73, 0x20, 0x3f, 0xb8,
-	0x8b, 0xdf, 0x9b, 0x04, 0x14, 0x0b, 0x2a, 0x5f, 0x3f, 0xcf, 0xc7, 0xa8,
-	0xdf, 0x30, 0x97, 0x93, 0xfb, 0x62, 0xfe, 0x36, 0x35, 0x5c, 0x1b, 0xf9,
-	0x88, 0x04, 0xab, 0x98, 0x23, 0x7f, 0x47, 0xd3, 0x78, 0x7d, 0x50, 0x5d,
-	0xa8, 0xbe, 0x4b, 0x8c, 0x41, 0x7e, 0x9a, 0xeb, 0xcc, 0x50, 0x3c, 0xd2,
-	0x81, 0xc1, 0x3a, 0xc8, 0xf3, 0xf7, 0x28, 0xc8, 0x87, 0x55, 0x5d, 0x59,
-	0xf4, 0xce, 0x75, 0x12, 0x8a, 0x39, 0xd2, 0x55, 0x73, 0x5f, 0x59, 0x6f,
-	0x6b, 0xea, 0xbb, 0x84, 0xdb, 0xd5, 0x92, 0xee, 0xab, 0xf7, 0x12, 0x64,
-	0xbd, 0x3c, 0x47, 0x5a, 0xe8, 0xa3, 0x5d, 0x1c, 0xdf, 0x79, 0x0e, 0x64,
-	0x5b, 0x7d, 0x6f, 0x4c, 0xae, 0xeb, 0x0c, 0xeb, 0xfb, 0x68, 0x93, 0xbe,
-	0xd5, 0x7d, 0xf5, 0xef, 0x74, 0xce, 0xf5, 0x9b, 0x68, 0x97, 0xda, 0x59,
-	0xf7, 0xde, 0x4f, 0x71, 0xcf, 0xfd, 0x44, 0x6e, 0xa6, 0xca, 0xbb, 0xcf,
-	0x7b, 0xaf, 0x1c, 0x0a, 0xe9, 0x83, 0xf7, 0x3e, 0x0a, 0xd6, 0xeb, 0xd7,
-	0x23, 0xf5, 0x35, 0xce, 0xf5, 0x9b, 0x0d, 0xee, 0xc3, 0x54, 0xff, 0x0c,
-	0xe9, 0x3f, 0x53, 0x90, 0xfa, 0x71, 0xc1, 0x31, 0xe9, 0x7c, 0x42, 0x71,
-	0x8e, 0x66, 0x62, 0xde, 0xf3, 0x1a, 0xad, 0xe7, 0x67, 0xd0, 0x2f, 0x3e,
-	0xa7, 0xf6, 0xf3, 0x48, 0xd8, 0xe4, 0x8b, 0x2d, 0xe2, 0xbd, 0xa6, 0xab,
-	0xb9, 0x70, 0x91, 0xef, 0x01, 0x97, 0xec, 0xcc, 0x2b, 0x8a, 0x2f, 0xb9,
-	0xaf, 0xc3, 0x12, 0xcd, 0xc5, 0xad, 0x47, 0x84, 0x37, 0xe1, 0x32, 0x9d,
-	0xfb, 0xfb, 0xfb, 0x66, 0x21, 0x42, 0x97, 0x57, 0xc7, 0x51, 0xa1, 0x63,
-	0x9c, 0x63, 0x25, 0x57, 0x78, 0xae, 0x11, 0x9f, 0xf3, 0xa4, 0x73, 0x8d,
-	0xf3, 0xc3, 0xab, 0x45, 0x3e, 0xab, 0xba, 0xac, 0xf7, 0x9a, 0xd2, 0x1d,
-	0x0c, 0x9b, 0x38, 0x3f, 0xa9, 0xca, 0x02, 0x2e, 0x7b, 0x1d, 0x46, 0xbb,
-	0x4c, 0x18, 0xc3, 0xfc, 0x75, 0x78, 0x58, 0x93, 0x7e, 0x05, 0xbe, 0xdf,
-	0x7e, 0xb0, 0x5e, 0x74, 0xa8, 0xf0, 0xef, 0x8b, 0x05, 0x7c, 0x3f, 0x01,
-	0xcd, 0xf7, 0x1b, 0xc5, 0x29, 0x0f, 0x11, 0xda, 0xa7, 0xb8, 0xaf, 0xc3,
-	0xd2, 0xce, 0x11, 0x7e, 0xdc, 0x3f, 0xec, 0xc3, 0x05, 0x8f, 0x3f, 0x42,
-	0xe5, 0xc3, 0x40, 0x98, 0xbf, 0xb4, 0xff, 0xde, 0xe2, 0x3e, 0xa5, 0xf7,
-	0x2f, 0xc9, 0x7e, 0xaa, 0xff, 0x19, 0xd7, 0x3f, 0xec, 0xd5, 0xbd, 0x8a,
-	0xf7, 0xae, 0xbe, 0xff, 0x7d, 0xdc, 0xc1, 0x76, 0x5b, 0xfb, 0xd8, 0xd1,
-	0xf1, 0xf9, 0x41, 0xef, 0xfd, 0xfd, 0xa6, 0x4e, 0x3c, 0x6d, 0xd4, 0xd5,
-	0x5c, 0x6d, 0x84, 0xcc, 0xd5, 0xc5, 0xff, 0x3a, 0x57, 0x10, 0x98, 0xab,
-	0xd5, 0xfa, 0xc1, 0xe6, 0x0a, 0xb8, 0x7e, 0x08, 0x99, 0xab, 0x18, 0xf3,
-	0xf0, 0x94, 0xcf, 0x33, 0x20, 0xaa, 0xc7, 0xb0, 0x7d, 0xc6, 0x2c, 0xeb,
-	0x92, 0xf4, 0x68, 0x47, 0xcb, 0xa8, 0x3f, 0xc7, 0x2e, 0x93, 0x9d, 0x41,
-	0xfb, 0x49, 0x85, 0x0b, 0xb3, 0xf4, 0x7b, 0x4a, 0x83, 0x9f, 0x94, 0x15,
-	0x12, 0x3d, 0x80, 0x0b, 0x00, 0x00, 0x00 };
+	/* Date:        12/07/2007 14:57 */
+	0xd5, 0x56, 0x41, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xdd, 0x6c, 0xbb, 0xdb,
+	0x64, 0xb3, 0x59, 0xaa, 0xd6, 0x50, 0x53, 0x93, 0x06, 0x2f, 0xad, 0x29,
+	0x6d, 0xaa, 0x82, 0x42, 0xa1, 0x92, 0x4b, 0xc1, 0xf6, 0x20, 0xf5, 0x22,
+	0x22, 0xd8, 0x46, 0xd1, 0x5f, 0x21, 0x06, 0xdb, 0xd4, 0x73, 0x05, 0x0b,
+	0xf5, 0xa0, 0x3d, 0x59, 0x11, 0xc1, 0x04, 0x14, 0x44, 0x04, 0x41, 0x45,
+	0x04, 0x3d, 0x78, 0xa8, 0x60, 0x2f, 0xad, 0x22, 0x56, 0x3c, 0x78, 0xd4,
+	0x93, 0x26, 0xbe, 0x37, 0x33, 0xaf, 0xdd, 0xdd, 0x66, 0x9b, 0x2a, 0x82,
+	0x18, 0x68, 0x3f, 0xde, 0xec, 0xbc, 0x37, 0x33, 0xdf, 0xcc, 0x9b, 0x79,
+	0x2e, 0x00, 0xe8, 0x50, 0xaa, 0xa6, 0x05, 0x82, 0xa5, 0x69, 0x96, 0x00,
+	0x0d, 0xe0, 0xae, 0x8d, 0x58, 0xea, 0x77, 0x05, 0xda, 0xda, 0x70, 0x46,
+	0x62, 0x04, 0x86, 0xbb, 0x25, 0xee, 0x87, 0x27, 0x99, 0xa4, 0xc0, 0x9f,
+	0x75, 0x28, 0xc9, 0xf5, 0xee, 0xca, 0xc3, 0x6a, 0x0c, 0xcf, 0x59, 0xed,
+	0x07, 0xfc, 0xbd, 0x8b, 0x10, 0x1e, 0xce, 0x59, 0x88, 0x25, 0x46, 0xe8,
+	0x73, 0x11, 0x96, 0x66, 0x2d, 0x34, 0x57, 0xea, 0xb3, 0x70, 0x1f, 0xe8,
+	0x24, 0x5f, 0x99, 0x4d, 0x88, 0xff, 0x29, 0x78, 0x5f, 0x90, 0x6b, 0x2b,
+	0x3a, 0x8d, 0x7a, 0x15, 0xde, 0x2f, 0xfe, 0x50, 0xff, 0xb8, 0xd8, 0x07,
+	0xfc, 0x53, 0xfb, 0x5c, 0x3c, 0xa7, 0x98, 0x93, 0x7e, 0xb5, 0x0b, 0x83,
+	0xca, 0x1f, 0x9b, 0xe2, 0x4b, 0x93, 0xb6, 0x89, 0xdf, 0xd7, 0x84, 0xdf,
+	0xca, 0x6e, 0x33, 0x7b, 0x41, 0x7f, 0x83, 0x76, 0xe5, 0x79, 0x86, 0xb0,
+	0xe7, 0xb7, 0x03, 0x20, 0xe5, 0xcb, 0xf5, 0x75, 0x79, 0x8f, 0xff, 0xfb,
+	0x6a, 0xaf, 0x3c, 0xaf, 0x05, 0xa0, 0x57, 0xea, 0x2d, 0xb1, 0x3f, 0x83,
+	0xb0, 0x4f, 0x4f, 0xe2, 0x77, 0x03, 0xf7, 0xef, 0x11, 0xe7, 0x4a, 0xec,
+	0x62, 0xec, 0x66, 0x1c, 0x67, 0xbc, 0xca, 0xb8, 0x8b, 0x71, 0x27, 0xe3,
+	0x0e, 0xc6, 0x76, 0xc6, 0x97, 0x8c, 0x2e, 0x63, 0x82, 0xd1, 0x61, 0x7c,
+	0xce, 0x68, 0x33, 0xc6, 0x18, 0x5f, 0x30, 0xbe, 0x62, 0xb4, 0x18, 0x6f,
+	0x30, 0x7e, 0x61, 0xfc, 0xaa, 0xfc, 0xd0, 0x08, 0x1f, 0xf1, 0xfa, 0x10,
+	0xaf, 0x8f, 0x30, 0x02, 0xf3, 0xa4, 0x05, 0x78, 0xba, 0xcf, 0x75, 0x24,
+	0x79, 0xe6, 0xef, 0x3d, 0x4a, 0x8f, 0xf3, 0x84, 0x3c, 0xdd, 0x63, 0xbd,
+	0xf6, 0xca, 0x42, 0xa0, 0xde, 0x32, 0x5b, 0xd6, 0x59, 0xaa, 0x41, 0xde,
+	0x12, 0x18, 0xcf, 0xc4, 0x48, 0x02, 0xed, 0x38, 0xad, 0x24, 0x57, 0x6e,
+	0x9d, 0x4c, 0x10, 0x9e, 0x8b, 0x12, 0x7e, 0x62, 0x3c, 0x1f, 0x23, 0x9c,
+	0x8c, 0x2b, 0x9e, 0xd5, 0x39, 0xca, 0x9f, 0x66, 0x7e, 0x84, 0xd9, 0x53,
+	0x7e, 0x35, 0xb3, 0x4b, 0x58, 0xd4, 0xfd, 0xf1, 0x5f, 0x1f, 0x20, 0x34,
+	0xf2, 0x44, 0xea, 0x9c, 0xdd, 0x26, 0xa0, 0x5e, 0x9f, 0xb7, 0x0d, 0xb9,
+	0x3e, 0x38, 0xff, 0x1a, 0xef, 0xc7, 0xe0, 0x5c, 0x95, 0xfd, 0x4b, 0x28,
+	0x9e, 0xe9, 0xde, 0x64, 0x81, 0xd6, 0xe3, 0xc8, 0xbb, 0xa8, 0xb0, 0x1e,
+	0xee, 0x03, 0x59, 0x7f, 0xbe, 0xa8, 0x6e, 0x23, 0x9c, 0x8f, 0x8b, 0x9c,
+	0x8f, 0xae, 0x90, 0x7c, 0x84, 0xdd, 0xa3, 0xcd, 0xf7, 0xf7, 0x4c, 0x26,
+	0xc8, 0x5b, 0xd8, 0x7d, 0x53, 0x7c, 0x93, 0xf4, 0x77, 0x79, 0xbc, 0xc0,
+	0x3c, 0x16, 0x89, 0xc7, 0xe4, 0xe7, 0x86, 0x3c, 0x65, 0x3c, 0x3c, 0xc9,
+	0x38, 0xf7, 0x86, 0xe4, 0x39, 0x2c, 0xbe, 0xdc, 0x1f, 0xe7, 0x39, 0xe0,
+	0x1f, 0x9c, 0xc5, 0xfe, 0xe4, 0x42, 0x71, 0x44, 0xf9, 0xeb, 0xe7, 0xb9,
+	0x93, 0xf2, 0x0d, 0xd3, 0x79, 0x29, 0xaf, 0x03, 0x3c, 0xd5, 0x71, 0x6d,
+	0x14, 0x34, 0x09, 0x56, 0x31, 0x4f, 0xfb, 0x1d, 0x5d, 0xe7, 0xf5, 0x76,
+	0xeb, 0x42, 0xe5, 0x5d, 0x62, 0x2b, 0x14, 0x26, 0x39, 0xce, 0x2c, 0xd9,
+	0xa3, 0x3a, 0x30, 0xb8, 0x0e, 0x86, 0xb8, 0x7f, 0x05, 0xf9, 0xb0, 0x2a,
+	0x0b, 0xb3, 0xde, 0x7b, 0x9d, 0x84, 0x62, 0x9e, 0xea, 0x6a, 0x73, 0x5e,
+	0xd5, 0xdc, 0x51, 0x7d, 0x09, 0xc5, 0x95, 0x52, 0xc4, 0x17, 0xef, 0x51,
+	0xc8, 0x79, 0x79, 0xd6, 0x1a, 0xd4, 0x47, 0x33, 0x3b, 0xbe, 0xf3, 0x1c,
+	0xc8, 0x35, 0xea, 0x37, 0x26, 0xc7, 0xd5, 0xcd, 0xf5, 0xdd, 0xb1, 0xa9,
+	0xbe, 0xd5, 0x7c, 0xfb, 0x7b, 0x75, 0xce, 0xf1, 0x9b, 0xa8, 0x97, 0x5a,
+	0x79, 0xe0, 0x9d, 0x67, 0x51, 0xcf, 0x3c, 0xa3, 0x6d, 0xa6, 0xf2, 0x3b,
+	0xed, 0x9d, 0x43, 0xb1, 0x90, 0x3c, 0x78, 0xe7, 0x57, 0x30, 0x5e, 0x7f,
+	0x3d, 0x52, 0x5e, 0xa3, 0x1c, 0xbf, 0xd6, 0xa4, 0x2f, 0xb7, 0xb1, 0xde,
+	0x8f, 0x5a, 0xb8, 0x1e, 0x9d, 0x5b, 0xe8, 0xf1, 0xf6, 0xf1, 0xef, 0x35,
+	0x9a, 0x07, 0xdf, 0x6a, 0x8a, 0xdf, 0xc7, 0x21, 0xfc, 0x0e, 0xfd, 0x53,
+	0x7e, 0x21, 0xc0, 0xef, 0x6a, 0x6d, 0x7b, 0xfc, 0x02, 0xc7, 0x0f, 0x21,
+	0xfc, 0xb6, 0x32, 0x0f, 0x6f, 0xb7, 0xe0, 0x4d, 0xea, 0xc5, 0x58, 0xef,
+	0x8d, 0x47, 0x0f, 0xfd, 0x1e, 0xa2, 0x7b, 0x65, 0x16, 0xd7, 0x02, 0xbc,
+	0xe5, 0x73, 0xf2, 0x7e, 0x5f, 0x82, 0x2a, 0xc7, 0xbf, 0xec, 0xe3, 0x21,
+	0x2e, 0xfc, 0x73, 0xd1, 0xfe, 0xed, 0xaa, 0xe2, 0x8b, 0x3e, 0x67, 0x72,
+	0x84, 0x8b, 0xa8, 0xef, 0x7a, 0x78, 0xf3, 0xbe, 0xaf, 0x5c, 0xb8, 0x55,
+	0x55, 0xfd, 0x4c, 0xf6, 0x15, 0x13, 0x06, 0x78, 0x4e, 0x4e, 0x70, 0xff,
+	0xfa, 0x10, 0xa5, 0x3e, 0x59, 0x1c, 0xc5, 0x3e, 0x03, 0x1d, 0xeb, 0xfd,
+	0x8c, 0xd6, 0x9d, 0x71, 0x7a, 0x47, 0x0e, 0x98, 0x36, 0xea, 0x75, 0xc6,
+	0x09, 0x3b, 0x62, 0x72, 0x5f, 0x12, 0x3e, 0x8e, 0xa1, 0x7a, 0x6e, 0xa3,
+	0x3f, 0x05, 0xfb, 0x12, 0xc7, 0x79, 0x40, 0xca, 0x3b, 0x02, 0xfd, 0x48,
+	0xe8, 0xf4, 0x92, 0x7f, 0x37, 0x81, 0xe3, 0x52, 0xfb, 0xd2, 0x92, 0xc7,
+	0xc5, 0x9a, 0xea, 0xe3, 0xd9, 0x11, 0xe9, 0x4f, 0x02, 0x1c, 0x93, 0xf2,
+	0x48, 0x28, 0xf4, 0x74, 0x53, 0x6e, 0x4b, 0x95, 0x75, 0x5a, 0x97, 0x2f,
+	0xe3, 0x31, 0x63, 0x65, 0x25, 0x2f, 0x60, 0x61, 0x8e, 0xdf, 0x79, 0x86,
+	0x72, 0xa7, 0x1a, 0x21, 0xb9, 0x39, 0xaa, 0xf8, 0x48, 0x60, 0x7c, 0x73,
+	0xc4, 0xc7, 0xe9, 0x6b, 0x84, 0xa7, 0xe0, 0x18, 0x62, 0x74, 0x63, 0x2e,
+	0x5b, 0x88, 0x10, 0xf7, 0xf6, 0xdf, 0x16, 0xe1, 0x1e, 0xf6, 0x4d, 0x4f,
+	0x7e, 0x82, 0x73, 0xb5, 0x59, 0x9e, 0xbc, 0x73, 0x5d, 0xe6, 0xa9, 0xd1,
+	0xfc, 0x8e, 0x73, 0x5d, 0x95, 0x9b, 0xd4, 0x9f, 0xea, 0x83, 0x25, 0xae,
+	0xfb, 0x46, 0xef, 0x1a, 0x89, 0x4e, 0xc8, 0xfc, 0x4f, 0xad, 0xfb, 0x95,
+	0x0e, 0x7d, 0x77, 0x91, 0xfe, 0xf6, 0xde, 0x5b, 0x6e, 0xc8, 0x1c, 0xfe,
+	0x1f, 0xde, 0x55, 0x5b, 0xbd, 0xa7, 0x1c, 0xe6, 0xf9, 0x04, 0xf3, 0x6c,
+	0x40, 0x4b, 0x04, 0x89, 0xb1, 0x8d, 0x29, 0x3c, 0x57, 0x2f, 0xd3, 0x58,
+	0xb7, 0x5b, 0x66, 0x70, 0xae, 0x3b, 0xf6, 0x0c, 0xe9, 0x19, 0x24, 0x4f,
+	0x2a, 0xbc, 0x32, 0x45, 0xef, 0x6c, 0x1d, 0x7e, 0x01, 0x50, 0xb6, 0x82,
+	0xa7, 0xd8, 0x0d, 0x00, 0x00, 0x00 };
 
 static u8 bnx2_rv2p_proc2[] = {
-/*	0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
-							0xcd, 0x58, 0x5b, 0x6c,
-	0x54, 0x55, 0x14, 0x3d, 0xf3, 0xe8, 0xcc, 0x9d, 0xe9, 0xed, 0x9d, 0xf2,
-	0xb2, 0x03, 0xad, 0x08, 0xe5, 0xd1, 0x56, 0x29, 0xe8, 0x54, 0xab, 0x18,
-	0x15, 0x2c, 0x5a, 0x8c, 0x26, 0x68, 0xf0, 0xf9, 0x63, 0x14, 0x04, 0xda,
-	0x9a, 0x56, 0x9b, 0x16, 0xfb, 0x81, 0xaf, 0x09, 0x14, 0x6a, 0x4c, 0x25,
-	0xd6, 0x08, 0xc5, 0x47, 0xa0, 0x11, 0x1f, 0x84, 0xf0, 0xd3, 0x1f, 0x3b,
-	0x8d, 0x7f, 0x0a, 0x24, 0x6a, 0x88, 0xc4, 0xa8, 0x9f, 0x24, 0x68, 0xa0,
-	0x21, 0x0a, 0x58, 0x8b, 0x63, 0x4c, 0xb4, 0xf5, 0xec, 0xbd, 0xf6, 0xb9,
-	0x73, 0xef, 0x6d, 0x8b, 0x1a, 0xf9, 0x70, 0x3e, 0xba, 0x7b, 0xce, 0xd9,
-	0x67, 0x3f, 0xd6, 0xde, 0x67, 0x9f, 0x7d, 0xae, 0x52, 0xfc, 0xbb, 0xb6,
-	0x94, 0xc9, 0x37, 0x83, 0x96, 0xfe, 0x1b, 0x51, 0x0f, 0x85, 0xd3, 0x3c,
-	0x8e, 0x2a, 0xa2, 0x49, 0xa5, 0xb2, 0x5e, 0xea, 0x08, 0x7d, 0x44, 0xe8,
-	0x70, 0x08, 0xf4, 0xb4, 0xd0, 0x77, 0x84, 0xfe, 0x2e, 0xf4, 0x80, 0xd0,
-	0x0f, 0x85, 0xea, 0x5f, 0xd6, 0xd6, 0x7f, 0xf4, 0xb0, 0x46, 0x89, 0x7e,
-	0x1b, 0xd3, 0x35, 0xb0, 0xe3, 0xc1, 0x05, 0xc4, 0x77, 0x61, 0xa2, 0xc0,
-	0x87, 0xf9, 0x53, 0x7d, 0xa0, 0xd7, 0x60, 0xd7, 0xe1, 0xec, 0x0a, 0xb3,
-	0x1f, 0x64, 0x43, 0x09, 0xe8, 0xc6, 0x08, 0xe8, 0xea, 0x65, 0x4c, 0x7a,
-	0x9f, 0x0a, 0x63, 0xdc, 0xb8, 0x94, 0xf6, 0x87, 0x55, 0x83, 0x22, 0x3f,
-	0x67, 0xaa, 0x68, 0x98, 0xc6, 0xf5, 0x56, 0x6c, 0x18, 0xeb, 0x8f, 0xa5,
-	0x40, 0x37, 0x25, 0x41, 0xcf, 0x08, 0xdd, 0x52, 0x2c, 0x7a, 0x6c, 0x31,
-	0xbf, 0x98, 0xf6, 0x25, 0x5c, 0x39, 0xc7, 0x6d, 0xe0, 0x96, 0x95, 0xfd,
-	0x4a, 0xc1, 0xce, 0x03, 0xb2, 0x3e, 0xa3, 0x0a, 0xb3, 0xaf, 0x6f, 0xc1,
-	0xb8, 0xfc, 0x20, 0xf9, 0xa7, 0xff, 0xcf, 0x62, 0x7e, 0xfa, 0xfd, 0xf8,
-	0x15, 0xf6, 0x83, 0x96, 0x2f, 0xa2, 0x75, 0x27, 0xd3, 0x3f, 0x88, 0xf1,
-	0xde, 0x25, 0x32, 0x1f, 0x36, 0xf8, 0x18, 0x79, 0x41, 0x5c, 0x99, 0x58,
-	0xc7, 0x2a, 0x7d, 0xf2, 0x2b, 0x15, 0xe4, 0x2f, 0xc8, 0x2e, 0x35, 0xf2,
-	0x81, 0xfb, 0xfa, 0x16, 0xb2, 0x73, 0x4c, 0xc7, 0x01, 0xb8, 0xcd, 0x0a,
-	0x95, 0xb2, 0xdc, 0x7d, 0x83, 0x5e, 0x3d, 0x51, 0xad, 0x07, 0xfa, 0x54,
-	0xa5, 0xc5, 0x20, 0x65, 0x97, 0x81, 0xaa, 0x5a, 0xbf, 0x1f, 0x7b, 0x97,
-	0x18, 0x7b, 0x30, 0x9e, 0x9d, 0x01, 0xdd, 0x23, 0xf4, 0xaa, 0x3a, 0x26,
-	0xcb, 0x7f, 0xb8, 0xc1, 0x62, 0x0c, 0xb2, 0xb5, 0xde, 0x7c, 0x38, 0x32,
-	0x61, 0xf0, 0x52, 0x8b, 0x40, 0xce, 0x2e, 0x21, 0x3e, 0x1d, 0x9c, 0x4a,
-	0xc8, 0x5d, 0xdf, 0x32, 0x55, 0x1e, 0x7d, 0x30, 0x45, 0x1e, 0x61, 0xff,
-	0xb7, 0x2b, 0x7c, 0xf9, 0xa4, 0xda, 0x25, 0x4f, 0x36, 0x22, 0x8f, 0xac,
-	0xa7, 0x3e, 0x91, 0x85, 0x6b, 0x13, 0xfa, 0xcf, 0x84, 0x7a, 0x32, 0x4e,
-	0x01, 0x8a, 0x2b, 0x87, 0xfd, 0x53, 0xe2, 0xe7, 0x26, 0xed, 0x27, 0xd1,
-	0x8a, 0x50, 0xb6, 0x36, 0xc1, 0x38, 0x35, 0xc4, 0xa0, 0xaf, 0x61, 0x03,
-	0xb6, 0xaf, 0x46, 0x5c, 0x7b, 0x4f, 0x86, 0x8d, 0xfd, 0x51, 0xfa, 0x3b,
-	0xd0, 0xb6, 0x9d, 0x47, 0x03, 0xd1, 0x1d, 0x4c, 0xed, 0x63, 0x95, 0x58,
-	0xee, 0x8a, 0xf0, 0x7a, 0x72, 0x97, 0xcc, 0xf7, 0xec, 0xf0, 0xdb, 0xfd,
-	0x02, 0xf2, 0xdb, 0x7e, 0x7e, 0x47, 0x88, 0xa8, 0x13, 0x73, 0xf9, 0x98,
-	0x3a, 0x3b, 0xb7, 0x13, 0xff, 0x55, 0x6a, 0xd7, 0x20, 0x29, 0x4e, 0xab,
-	0x0d, 0x6b, 0xb1, 0x6f, 0x77, 0x2c, 0xc5, 0xb8, 0x36, 0xad, 0x05, 0xfd,
-	0x1e, 0xf3, 0xf3, 0x9d, 0x1e, 0xe2, 0x2f, 0x9d, 0xe7, 0x0c, 0x71, 0x5e,
-	0xa9, 0x11, 0xce, 0xc7, 0x04, 0x65, 0x06, 0xff, 0xda, 0xaa, 0xc1, 0xdf,
-	0xbc, 0x99, 0x15, 0xbf, 0xd9, 0x9a, 0xe7, 0x3c, 0x18, 0xe8, 0x18, 0x26,
-	0x3f, 0xe7, 0xaa, 0x91, 0x4e, 0xa2, 0x51, 0xd5, 0xb0, 0x90, 0xf0, 0x5e,
-	0x15, 0x36, 0x71, 0x3a, 0x7f, 0x33, 0xcd, 0xcf, 0xd3, 0xeb, 0x26, 0x1e,
-	0x24, 0xd7, 0x92, 0x78, 0x45, 0x5d, 0x7c, 0xf2, 0x61, 0xf8, 0xdb, 0xcd,
-	0x76, 0x5f, 0x97, 0xec, 0xe6, 0xfc, 0x4a, 0xaa, 0x26, 0x8e, 0x7f, 0xd4,
-	0x6a, 0x1b, 0xc6, 0xfa, 0xf9, 0x8f, 0x8d, 0x5c, 0xd2, 0x53, 0x23, 0x75,
-	0x44, 0xb9, 0x72, 0xa2, 0x37, 0x83, 0xee, 0x34, 0x7a, 0xeb, 0x88, 0x6f,
-	0xb1, 0x42, 0xfe, 0x26, 0x26, 0xc9, 0x69, 0x03, 0xce, 0xf6, 0x33, 0xec,
-	0xf7, 0x35, 0xf6, 0x85, 0x3e, 0x63, 0x2f, 0xe6, 0x2f, 0xfa, 0xf4, 0x95,
-	0x7b, 0xf4, 0x11, 0x7f, 0x51, 0xf2, 0x02, 0xef, 0x9b, 0x63, 0x3d, 0x3b,
-	0xcc, 0xb8, 0x58, 0xcf, 0x0c, 0x41, 0xfe, 0xc5, 0x21, 0xe2, 0x9f, 0x23,
-	0x7a, 0xed, 0xff, 0x88, 0xe7, 0x9c, 0x30, 0xe4, 0x4c, 0x8f, 0x5f, 0xc1,
-	0x6f, 0xe3, 0x17, 0xcb, 0xb5, 0x47, 0x73, 0x69, 0xe6, 0x33, 0xf1, 0xe8,
-	0x0e, 0x73, 0x02, 0xa6, 0x1b, 0x16, 0xfa, 0x71, 0x33, 0xf6, 0x9c, 0xdf,
-	0xcc, 0x79, 0x3e, 0xd1, 0x26, 0x75, 0x40, 0x71, 0x9d, 0xb9, 0x5d, 0xe2,
-	0xa1, 0xf3, 0x3a, 0x04, 0xff, 0x46, 0x73, 0x2c, 0x3f, 0xd9, 0xc5, 0x79,
-	0xb9, 0xd2, 0x8e, 0xe6, 0x38, 0x5e, 0xd6, 0xd9, 0x21, 0x6c, 0x2b, 0xd4,
-	0x4f, 0xc8, 0x6b, 0xb6, 0x41, 0x9b, 0xa4, 0x8e, 0x9e, 0x15, 0xda, 0x6d,
-	0x33, 0x3e, 0xba, 0x8e, 0x59, 0x2c, 0x3f, 0x9b, 0x32, 0xf7, 0x0c, 0xd6,
-	0x9f, 0x16, 0x39, 0x3f, 0x0a, 0x55, 0x22, 0xa7, 0x55, 0xf6, 0x9f, 0xf3,
-	0xc9, 0x89, 0x04, 0xe4, 0x84, 0x94, 0xc1, 0xcd, 0x9c, 0xef, 0x5d, 0x52,
-	0xbf, 0xf7, 0xc5, 0xa6, 0xab, 0xb7, 0x7c, 0x0e, 0xdc, 0xba, 0x5a, 0x8e,
-	0x3a, 0x53, 0x1f, 0x0d, 0xb3, 0xbf, 0x03, 0xdd, 0x3b, 0x80, 0x53, 0x8f,
-	0xe0, 0x14, 0x07, 0x4e, 0xf3, 0x0a, 0xf5, 0x59, 0x14, 0xd4, 0x90, 0xfe,
-	0x53, 0x21, 0xe3, 0xc7, 0xbe, 0x98, 0xaf, 0xfe, 0xf6, 0x9a, 0xfa, 0x5b,
-	0xa8, 0xd3, 0xc4, 0xff, 0xb3, 0xa9, 0x6f, 0x5a, 0x9f, 0xd1, 0xff, 0x6f,
-	0xf5, 0x72, 0x9c, 0x92, 0xdd, 0x7d, 0x26, 0xce, 0x98, 0x2e, 0xd4, 0xd9,
-	0x22, 0x22, 0xcb, 0x46, 0x3a, 0x99, 0x5e, 0xdf, 0xbc, 0x15, 0xf3, 0x65,
-	0x7c, 0x4e, 0x6e, 0x09, 0x01, 0xaf, 0xa8, 0x3a, 0xde, 0x87, 0xba, 0xae,
-	0xe2, 0x2c, 0xaf, 0xe2, 0x28, 0xc7, 0x3f, 0xaa, 0xe5, 0x12, 0xdf, 0x67,
-	0xa1, 0x42, 0x3e, 0x7a, 0xfd, 0xd9, 0xad, 0xf3, 0x84, 0xec, 0x88, 0xe9,
-	0xbc, 0xa5, 0xb1, 0x3e, 0x47, 0xb6, 0xe4, 0xf9, 0x1a, 0xe6, 0xb3, 0xc7,
-	0x22, 0x34, 0xff, 0x80, 0xd5, 0xd3, 0x87, 0xf9, 0x9f, 0x1a, 0x69, 0xbc,
-	0xce, 0x7e, 0x0d, 0xe7, 0xcc, 0x7e, 0x0d, 0xf5, 0xcb, 0x2a, 0x3a, 0x88,
-	0xba, 0xd6, 0x78, 0x10, 0xf2, 0x71, 0x4f, 0x7b, 0xfd, 0xf2, 0xe2, 0x47,
-	0xe7, 0xe1, 0xb2, 0x38, 0xd9, 0xcf, 0x09, 0x4e, 0x97, 0x7c, 0xf1, 0x39,
-	0x6c, 0xe2, 0xd3, 0x1b, 0x93, 0xf3, 0xd2, 0x7c, 0x29, 0xe8, 0x17, 0xf1,
-	0x9d, 0x71, 0xef, 0x9d, 0xae, 0x95, 0xa0, 0xdd, 0x2b, 0xe5, 0x9c, 0xd6,
-	0xf9, 0xf3, 0x6b, 0x3e, 0xea, 0xf2, 0xb8, 0x7b, 0x4f, 0x20, 0xbf, 0xac,
-	0x9d, 0xf0, 0x4b, 0xbd, 0x28, 0x79, 0x3c, 0x2e, 0xf4, 0x65, 0xc9, 0xdf,
-	0x6d, 0xd2, 0xb7, 0x98, 0xfe, 0xe2, 0x0f, 0xcc, 0x3b, 0xfd, 0x6e, 0x5f,
-	0x60, 0xea, 0x36, 0x8d, 0x43, 0xca, 0x89, 0x13, 0x83, 0x36, 0xeb, 0x33,
-	0x24, 0x4a, 0xcf, 0x1a, 0xe0, 0x35, 0x52, 0x07, 0xbe, 0xdd, 0x91, 0xb0,
-	0x8c, 0x21, 0x6f, 0xac, 0xda, 0x77, 0x0f, 0xd7, 0x4f, 0xc6, 0x93, 0xe4,
-	0xc6, 0xdc, 0xfa, 0x24, 0x79, 0xaf, 0x26, 0x84, 0x96, 0x2f, 0xbe, 0x2c,
-	0xbe, 0x85, 0xfe, 0x64, 0xa9, 0x17, 0xdf, 0x97, 0x34, 0xbe, 0xbc, 0xaf,
-	0xbe, 0xf9, 0x12, 0xa6, 0x4b, 0x6f, 0x05, 0xed, 0xbb, 0x95, 0xe7, 0x17,
-	0xa3, 0xee, 0x11, 0x7e, 0x9c, 0x5f, 0xf5, 0x6f, 0x0c, 0x9a, 0x7e, 0x42,
-	0xf0, 0x08, 0xf4, 0x41, 0x65, 0x77, 0x80, 0xbe, 0x29, 0x74, 0xce, 0x2a,
-	0xd0, 0xbd, 0xab, 0xfc, 0x71, 0x88, 0xa5, 0x7c, 0x71, 0xac, 0x47, 0x1c,
-	0x8f, 0x4c, 0x04, 0xeb, 0x81, 0xc4, 0x4b, 0xc7, 0x27, 0x70, 0xbf, 0x1b,
-	0xfd, 0xe2, 0xce, 0xdf, 0xc5, 0xed, 0x4a, 0xc7, 0xab, 0x7b, 0x25, 0xee,
-	0x93, 0x0e, 0xe9, 0x4b, 0xc7, 0xdc, 0xfb, 0xe2, 0x9f, 0xc4, 0x31, 0x7e,
-	0x85, 0xe3, 0x78, 0xf7, 0xff, 0x2c, 0x8e, 0x9d, 0x12, 0xc7, 0x22, 0xb9,
-	0x57, 0x4d, 0xbf, 0xd9, 0x2e, 0x7d, 0x18, 0xf5, 0x8d, 0x7e, 0xbd, 0x4f,
-	0x70, 0x1f, 0x78, 0xb5, 0x5b, 0x8f, 0xe7, 0x33, 0x7f, 0x4e, 0xf6, 0x95,
-	0xca, 0xbe, 0x7b, 0x26, 0xed, 0x3b, 0xc5, 0xf5, 0xee, 0xf1, 0xf1, 0xc9,
-	0xef, 0x15, 0x9f, 0x9d, 0x59, 0x95, 0x02, 0xee, 0xa8, 0xe3, 0xb1, 0x29,
-	0xde, 0x37, 0x86, 0x1f, 0xf9, 0xb5, 0x36, 0x85, 0xba, 0x05, 0xfe, 0xb9,
-	0x9e, 0x7a, 0x4a, 0xe3, 0xfb, 0xc7, 0xa7, 0xef, 0x57, 0x8d, 0x3c, 0xc4,
-	0x6d, 0x43, 0xb8, 0x84, 0xf9, 0x4e, 0xb7, 0xf3, 0x7d, 0xe7, 0xfa, 0xb7,
-	0x9a, 0xfd, 0x3a, 0x2a, 0xfe, 0x55, 0x88, 0x7f, 0x7a, 0xb9, 0x96, 0xeb,
-	0xbe, 0x75, 0xba, 0xdd, 0xeb, 0xdf, 0x9d, 0x97, 0xd1, 0xf7, 0x4f, 0xfb,
-	0x63, 0xd1, 0x9b, 0x32, 0xfa, 0x49, 0x5e, 0xb9, 0xf4, 0x7d, 0xd4, 0x4f,
-	0x62, 0x7e, 0x72, 0x9f, 0x41, 0xfa, 0x5b, 0x34, 0x5e, 0x72, 0xdf, 0x70,
-	0x3e, 0x47, 0xac, 0xa3, 0x6c, 0x57, 0x5e, 0xf9, 0x71, 0x39, 0x23, 0x7c,
-	0x53, 0xc5, 0x8d, 0xd6, 0x8b, 0x64, 0x7d, 0x2a, 0xbf, 0xc5, 0x4e, 0x37,
-	0x1f, 0x64, 0x1f, 0xf3, 0x35, 0x0b, 0x5f, 0x34, 0x34, 0x39, 0xfe, 0x18,
-	0xe5, 0xab, 0x38, 0xaf, 0xf7, 0x6f, 0xcb, 0x11, 0x9f, 0x76, 0x9e, 0xf3,
-	0xf0, 0xfb, 0x80, 0x7d, 0xe9, 0x2b, 0x80, 0x23, 0xf1, 0xcd, 0x50, 0x4d,
-	0xce, 0x74, 0x78, 0xe1, 0xdd, 0x30, 0x9a, 0x33, 0x78, 0xdb, 0xec, 0xe7,
-	0x48, 0x27, 0xe9, 0x5f, 0x1d, 0xc0, 0x31, 0x2c, 0x38, 0x9e, 0x50, 0x7f,
-	0x9f, 0xf7, 0xc6, 0x0f, 0x6f, 0x5e, 0x8c, 0xff, 0x19, 0xcc, 0xe3, 0x87,
-	0xe5, 0x5d, 0xdd, 0x18, 0x03, 0xfd, 0x2e, 0x62, 0xec, 0x46, 0x5e, 0xdf,
-	0xc3, 0xe7, 0xb5, 0x4a, 0xf5, 0xf2, 0xbb, 0xc3, 0x52, 0x0d, 0x6b, 0xc9,
-	0xee, 0x94, 0xae, 0x7f, 0xc8, 0x77, 0x27, 0xee, 0xbd, 0xb7, 0x75, 0x0d,
-	0x4c, 0xc4, 0x69, 0x58, 0x31, 0x33, 0xc1, 0x82, 0xde, 0xf8, 0xe2, 0x4b,
-	0x5e, 0x7e, 0xaf, 0xbf, 0x18, 0xf3, 0x65, 0xf7, 0x91, 0x9c, 0x88, 0xda,
-	0x8b, 0xba, 0xfb, 0xee, 0x1e, 0xd0, 0xb7, 0xd5, 0xbd, 0xd8, 0x3f, 0x73,
-	0x3b, 0xd7, 0x51, 0xab, 0x4c, 0xf2, 0x2b, 0x0d, 0x5c, 0xd3, 0xa8, 0xc3,
-	0x13, 0x13, 0xaa, 0x04, 0xf7, 0x9a, 0x79, 0x07, 0xab, 0x1a, 0xd1, 0x8b,
-	0xfa, 0x68, 0x17, 0xde, 0xc1, 0x44, 0x8b, 0x83, 0x7d, 0x9f, 0x55, 0xe8,
-	0xaf, 0x08, 0x8f, 0xf7, 0x5d, 0x1c, 0xd3, 0xe1, 0x60, 0x5d, 0xf2, 0xfa,
-	0x15, 0x93, 0x73, 0xfd, 0xab, 0xfb, 0x6e, 0xee, 0xe1, 0x7e, 0x2a, 0x19,
-	0xac, 0xcb, 0x01, 0xf9, 0xfb, 0x24, 0x7e, 0x49, 0x89, 0x5f, 0x54, 0xc7,
-	0x0f, 0xef, 0xed, 0x4f, 0x7d, 0xef, 0x7a, 0xaa, 0x1b, 0xde, 0xbc, 0xfb,
-	0xfc, 0x4f, 0x63, 0xd7, 0xf6, 0x98, 0xb7, 0x0e, 0x57, 0xbb, 0xe7, 0xae,
-	0x43, 0xde, 0x8b, 0x5d, 0x87, 0x30, 0xce, 0x73, 0xbf, 0xbc, 0x38, 0xd3,
-	0x21, 0x79, 0x74, 0x57, 0x44, 0xf2, 0x41, 0xec, 0xfb, 0x22, 0x62, 0xee,
-	0x1b, 0x8c, 0xbf, 0x92, 0xfb, 0xee, 0x97, 0x2a, 0xf4, 0xd9, 0x17, 0x87,
-	0xcc, 0xfb, 0xc4, 0xbc, 0x57, 0xb0, 0xbe, 0x3e, 0xae, 0x04, 0x67, 0xbe,
-	0xff, 0xb5, 0x3f, 0x9c, 0xaf, 0x99, 0x8e, 0x61, 0x1f, 0x5e, 0x2a, 0x16,
-	0x78, 0xbf, 0xc4, 0xe5, 0xfb, 0x45, 0xbf, 0xe0, 0xe1, 0xf0, 0xf9, 0x29,
-	0xd5, 0xf6, 0x13, 0x4d, 0x65, 0x3a, 0x73, 0xb0, 0xa7, 0xd5, 0xed, 0x23,
-	0xc1, 0x27, 0xd4, 0x79, 0x4b, 0xde, 0xc1, 0xf2, 0x5e, 0xd6, 0xef, 0x61,
-	0xf4, 0x73, 0xad, 0x79, 0x8c, 0xc7, 0xd0, 0xb7, 0x39, 0xbf, 0xca, 0xbd,
-	0xb5, 0x75, 0x9b, 0xe9, 0x4b, 0xa7, 0xde, 0x67, 0xee, 0xb9, 0xb6, 0x6a,
-	0xd0, 0x16, 0xee, 0x5b, 0x1f, 0xb2, 0xf3, 0x92, 0x1f, 0x85, 0x77, 0x89,
-	0xff, 0x3d, 0x62, 0xfa, 0x85, 0x73, 0xc5, 0xb8, 0x67, 0xf3, 0xbd, 0x34,
-	0xa1, 0xdf, 0x23, 0x09, 0x6f, 0x9e, 0x25, 0x32, 0x65, 0x82, 0xfb, 0xec,
-	0x9b, 0x40, 0xf7, 0xdc, 0x84, 0xbe, 0xbc, 0xb5, 0x4b, 0x70, 0xb8, 0x91,
-	0x71, 0x5b, 0x3e, 0x9a, 0x0b, 0x7e, 0x67, 0x21, 0x5c, 0x7f, 0x73, 0xfb,
-	0xd1, 0x73, 0x6c, 0xd7, 0xbc, 0x81, 0x3c, 0xf3, 0xcd, 0x55, 0xb3, 0xf8,
-	0xfc, 0xa6, 0x9d, 0x51, 0xd8, 0x99, 0xe9, 0x17, 0xbf, 0xda, 0x6f, 0x01,
-	0xed, 0x92, 0x3a, 0x73, 0xd2, 0x7d, 0x97, 0xc3, 0x4e, 0x53, 0x4f, 0x26,
-	0xbf, 0x13, 0x30, 0x9e, 0x5b, 0xc7, 0x63, 0xd5, 0xbc, 0x95, 0xe4, 0x97,
-	0x4c, 0x7a, 0xcf, 0x16, 0xe2, 0x6e, 0xf2, 0xc1, 0xe4, 0x8f, 0xf7, 0x1d,
-	0x7b, 0x9b, 0xa7, 0x5e, 0xfa, 0xe3, 0xef, 0x70, 0xbe, 0x84, 0x65, 0x3d,
-	0x96, 0xe9, 0xef, 0xbb, 0x3c, 0x3e, 0x6f, 0x01, 0x9f, 0x8c, 0xd8, 0x6d,
-	0xb7, 0xf0, 0x3b, 0x74, 0x96, 0xda, 0x25, 0xf1, 0x39, 0x57, 0x2d, 0x75,
-	0x50, 0xec, 0xfb, 0x49, 0xfa, 0x1f, 0xc4, 0x31, 0x6e, 0x6f, 0xc9, 0x49,
-	0xdc, 0x24, 0x8f, 0x9e, 0x16, 0xbf, 0x7f, 0x84, 0xdf, 0xb6, 0xf1, 0xbb,
-	0xc5, 0xf5, 0xdb, 0xd4, 0x59, 0xaf, 0x9c, 0x99, 0x3a, 0x1f, 0xb8, 0x5e,
-	0xdb, 0x27, 0xf9, 0xdd, 0x53, 0x24, 0xe7, 0xa1, 0x42, 0xbe, 0x3b, 0x38,
-	0xe2, 0x4f, 0x89, 0x6a, 0x5a, 0xee, 0xdd, 0x57, 0x2c, 0xfb, 0x92, 0x7a,
-	0x1f, 0xe6, 0x71, 0xfe, 0xec, 0x29, 0xf0, 0x34, 0xdf, 0x11, 0x8c, 0xdc,
-	0xe0, 0x39, 0xf2, 0xe2, 0xc7, 0x37, 0x13, 0xff, 0x50, 0x07, 0x74, 0x9c,
-	0x6a, 0xcd, 0xf7, 0x07, 0xcc, 0xe3, 0xfc, 0x26, 0xf7, 0xb7, 0xa1, 0xaf,
-	0xdc, 0xdf, 0x76, 0x48, 0xfa, 0x08, 0xc1, 0xe5, 0x81, 0x21, 0xb2, 0x43,
-	0xc7, 0xae, 0xd2, 0x7f, 0xfe, 0x61, 0x47, 0x54, 0xec, 0x28, 0xf7, 0xd8,
-	0x11, 0xd0, 0x7b, 0x1d, 0xcd, 0xaf, 0x50, 0x5f, 0x73, 0x1e, 0x2e, 0x57,
-	0xeb, 0x29, 0x47, 0xf4, 0xbd, 0xb0, 0xae, 0x88, 0xc6, 0xcb, 0xd4, 0xab,
-	0xf0, 0xb7, 0x37, 0x59, 0x84, 0x3a, 0x96, 0xdc, 0x49, 0xf3, 0x35, 0xea,
-	0xd5, 0x3e, 0x0e, 0xc4, 0x2b, 0xea, 0x18, 0xea, 0x73, 0xe3, 0x41, 0xb6,
-	0x47, 0x1d, 0x1f, 0x34, 0xf5, 0x7a, 0xca, 0xef, 0x98, 0xbd, 0xeb, 0xa4,
-	0x5e, 0x9c, 0xc0, 0x77, 0x51, 0xfd, 0x5e, 0x23, 0xfe, 0xd9, 0xe6, 0x3d,
-	0xb8, 0xfb, 0x98, 0xa1, 0x8b, 0x7c, 0xe3, 0xfd, 0x27, 0x96, 0x0a, 0xad,
-	0xf2, 0x8d, 0x07, 0xd6, 0x55, 0x09, 0xad, 0x36, 0xe3, 0xe9, 0xbe, 0x2b,
-	0x5e, 0x29, 0xf9, 0x62, 0xf7, 0x7b, 0xe2, 0xcf, 0x47, 0xe2, 0xcf, 0x59,
-	0xe0, 0x9f, 0xdc, 0x28, 0x78, 0x2c, 0x0a, 0xea, 0x17, 0xbb, 0xdc, 0x73,
-	0x63, 0xd6, 0x11, 0x8f, 0x47, 0xd5, 0x5f, 0x3f, 0x97, 0x8f, 0x31, 0xd8,
-	0x17, 0x00, 0x00, 0x00 };
+	/* Date:        12/07/2007 14:57 */
+	0xed, 0x59, 0x5d, 0x6c, 0x54, 0xc7, 0x15, 0x9e, 0xbd, 0xbb, 0x7b, 0xf7,
+	0x7a, 0x7d, 0xf7, 0xae, 0x71, 0xa8, 0xff, 0xf9, 0xb3, 0x09, 0xd8, 0xa9,
+	0x21, 0xce, 0x9a, 0x98, 0x02, 0x55, 0x63, 0x39, 0x95, 0x81, 0xa6, 0x55,
+	0x0c, 0x49, 0x9b, 0xbe, 0x35, 0x76, 0x02, 0xb6, 0xa9, 0x4d, 0x2d, 0x43,
+	0x83, 0x4a, 0x1b, 0x65, 0x85, 0xd7, 0xf6, 0xcb, 0x26, 0xea, 0x22, 0xc0,
+	0x24, 0xaa, 0xa8, 0x1b, 0xa4, 0x28, 0xea, 0xdb, 0x56, 0x6a, 0x6d, 0xda,
+	0x97, 0xfe, 0x10, 0xb7, 0x4a, 0xa4, 0x42, 0xa5, 0xf6, 0xa1, 0x52, 0x85,
+	0x44, 0xda, 0x62, 0x99, 0xc4, 0x20, 0x63, 0xba, 0x79, 0x21, 0x75, 0x67,
+	0xce, 0x77, 0xe6, 0xee, 0xbd, 0xeb, 0xb5, 0x21, 0x2d, 0x8f, 0xdd, 0x07,
+	0x1f, 0x66, 0xee, 0x99, 0x33, 0xe7, 0xe7, 0x9b, 0x33, 0x67, 0x0e, 0x65,
+	0x42, 0x08, 0x43, 0x24, 0xb3, 0x1b, 0x24, 0x15, 0x56, 0x20, 0x20, 0xf0,
+	0x7b, 0xac, 0x8c, 0xc8, 0x9f, 0xb3, 0x96, 0xfc, 0x1b, 0x16, 0xcf, 0x1b,
+	0x55, 0x34, 0x0e, 0x09, 0x45, 0x1d, 0x21, 0x92, 0x5e, 0x5a, 0xce, 0xf4,
+	0x67, 0x4c, 0x77, 0x1b, 0xa0, 0x3d, 0x4c, 0xeb, 0x98, 0x9e, 0x64, 0xba,
+	0x91, 0xe9, 0x56, 0xa6, 0x27, 0x98, 0x7e, 0x8f, 0xe9, 0x07, 0x4c, 0x77,
+	0xb2, 0x3c, 0xf9, 0x4b, 0xda, 0xf2, 0x4f, 0x40, 0x24, 0x9b, 0xb4, 0x7e,
+	0x36, 0xa6, 0x9b, 0xa0, 0xe7, 0x73, 0x1b, 0x15, 0xdf, 0xcd, 0xa5, 0x3c,
+	0x1f, 0xe6, 0xaf, 0x65, 0x40, 0x37, 0x60, 0xd5, 0x4f, 0x93, 0x8f, 0xeb,
+	0xf5, 0x20, 0xdd, 0x31, 0xd0, 0x9e, 0x20, 0x68, 0x7b, 0x33, 0x91, 0xf4,
+	0x4b, 0x06, 0xc6, 0x9d, 0x5b, 0x2c, 0xb2, 0x2f, 0x64, 0x28, 0x39, 0xeb,
+	0x2d, 0xf3, 0x12, 0xe6, 0xbf, 0x19, 0x07, 0x7d, 0x39, 0x0a, 0xfa, 0x4f,
+	0xa6, 0x87, 0x4b, 0x59, 0xbe, 0xcd, 0x6a, 0x97, 0x62, 0xfd, 0x8c, 0xad,
+	0x68, 0x50, 0x24, 0x79, 0x9d, 0x10, 0xd0, 0xeb, 0xc7, 0x02, 0xdf, 0xd7,
+	0x6c, 0xc5, 0xec, 0x0f, 0x0f, 0x63, 0x5c, 0x7b, 0xb1, 0x8c, 0xf8, 0xcf,
+	0x67, 0xb5, 0xfe, 0x16, 0x79, 0x3f, 0x19, 0x87, 0x1c, 0x51, 0x6f, 0xd1,
+	0x26, 0xc9, 0x66, 0x50, 0xb1, 0x4d, 0xcb, 0xc3, 0xef, 0xdc, 0xa3, 0xda,
+	0x3f, 0x18, 0xaf, 0x4d, 0x80, 0x9e, 0x65, 0x5a, 0xd1, 0x4a, 0x64, 0xfb,
+	0xdf, 0x9f, 0xb0, 0x48, 0x97, 0xe4, 0x36, 0xaf, 0x1f, 0x7f, 0x23, 0xfd,
+	0xc8, 0x82, 0x1a, 0x40, 0x6e, 0x3c, 0xaa, 0xf8, 0xa4, 0x71, 0xf5, 0x90,
+	0x7b, 0xb0, 0xbf, 0x98, 0xff, 0x7f, 0xf9, 0x19, 0xfc, 0xaf, 0xe4, 0xb5,
+	0xb3, 0xfe, 0x1b, 0xa5, 0xfe, 0x8a, 0xd6, 0x05, 0x92, 0xdb, 0xfc, 0xfe,
+	0xb9, 0x96, 0x89, 0xd3, 0xbf, 0x6f, 0x76, 0x94, 0x91, 0xfd, 0xcf, 0x62,
+	0xfe, 0x74, 0xe7, 0x14, 0xfc, 0xb4, 0x9f, 0xe2, 0x22, 0xa2, 0xa9, 0x9f,
+	0x63, 0x55, 0x77, 0x4c, 0x8d, 0x5f, 0xd8, 0x71, 0x23, 0x8b, 0xef, 0xe1,
+	0x11, 0x35, 0x36, 0xe4, 0x3a, 0xfc, 0xf6, 0x07, 0x09, 0xe0, 0x69, 0x73,
+	0x84, 0x86, 0xf6, 0x0c, 0x7d, 0xb7, 0xc5, 0x78, 0x16, 0xdf, 0x8f, 0x96,
+	0xaa, 0xf1, 0xb3, 0xcd, 0x73, 0x18, 0x37, 0xf7, 0x8f, 0xf1, 0x42, 0xa3,
+	0x44, 0xfe, 0x59, 0x5a, 0xba, 0x69, 0x40, 0x1e, 0x87, 0x37, 0x1a, 0x32,
+	0xe2, 0x64, 0xaf, 0xdd, 0x09, 0x3a, 0x4a, 0xdf, 0xef, 0x05, 0xd2, 0x64,
+	0x77, 0xa7, 0x13, 0x9a, 0x02, 0x23, 0xe3, 0xca, 0xc5, 0x8d, 0xc6, 0xdd,
+	0x83, 0xe2, 0x67, 0xcc, 0xc5, 0x0f, 0xfb, 0xbf, 0x69, 0x25, 0xfc, 0x80,
+	0x76, 0x6e, 0x01, 0x35, 0x1b, 0x14, 0x5f, 0xb8, 0x08, 0x8e, 0xfc, 0x7e,
+	0xe6, 0xf8, 0x14, 0xe2, 0x44, 0xe2, 0x03, 0x63, 0xc6, 0x8b, 0xc4, 0x95,
+	0xe2, 0xaf, 0x96, 0xfe, 0xd2, 0xf1, 0x57, 0x82, 0x22, 0xe2, 0xdb, 0x2c,
+	0xaf, 0x9f, 0xed, 0x1a, 0x60, 0x7b, 0xe6, 0xa3, 0xda, 0xaf, 0xda, 0x1e,
+	0xd0, 0x71, 0x9f, 0x3d, 0x01, 0x89, 0x27, 0x8d, 0x23, 0x9f, 0x3e, 0xe9,
+	0xf7, 0xea, 0xf1, 0x8f, 0x5a, 0xc6, 0xa1, 0x6b, 0xe7, 0x16, 0xc5, 0x67,
+	0x26, 0x26, 0xb2, 0x7e, 0x1c, 0x6e, 0x10, 0x5a, 0x8e, 0x96, 0xaf, 0x70,
+	0x99, 0x93, 0xb8, 0x44, 0xdc, 0xce, 0x67, 0xbd, 0xe7, 0xa8, 0xa6, 0xc8,
+	0x39, 0xf2, 0x9f, 0x07, 0xed, 0x97, 0xa3, 0x31, 0x4a, 0x10, 0x3b, 0xae,
+	0xcc, 0xfa, 0xf7, 0x03, 0xbe, 0x23, 0x2e, 0x7e, 0xd6, 0xb6, 0xb1, 0xff,
+	0x98, 0x56, 0xec, 0x54, 0xf2, 0xba, 0x58, 0x7e, 0x0b, 0xcb, 0xb7, 0x0b,
+	0xce, 0xdb, 0x73, 0xee, 0x79, 0xd3, 0x71, 0xcb, 0x9f, 0x3b, 0xed, 0x3f,
+	0xda, 0xbf, 0xf9, 0xca, 0xac, 0x5a, 0x5f, 0x7b, 0x9f, 0x73, 0xb8, 0xbf,
+	0xc8, 0x39, 0x84, 0x9c, 0xbf, 0x3c, 0xee, 0xb7, 0x6b, 0x88, 0xf3, 0x5c,
+	0x0f, 0xe2, 0x66, 0xbd, 0xf4, 0x2b, 0xfe, 0xf0, 0x18, 0xe1, 0x5d, 0xbc,
+	0x18, 0x41, 0x7c, 0x1d, 0xd2, 0x5f, 0xb0, 0x1d, 0x2f, 0x7b, 0xce, 0x6b,
+	0x09, 0xf9, 0xb5, 0xc3, 0xc4, 0x7e, 0x1d, 0xdd, 0x58, 0xde, 0xce, 0x78,
+	0xc8, 0xf1, 0x79, 0x99, 0xb5, 0x49, 0xff, 0xe8, 0x9d, 0x53, 0x98, 0x1f,
+	0xdd, 0x43, 0x24, 0x7d, 0xd5, 0xd0, 0xf6, 0x86, 0xd4, 0xdf, 0xc9, 0x41,
+	0x7c, 0x9f, 0x0c, 0xf1, 0xf9, 0x7c, 0xaf, 0x9e, 0xd6, 0x5b, 0xf3, 0x19,
+	0xac, 0xcf, 0xb1, 0x7e, 0x27, 0x82, 0xc4, 0x1f, 0x1d, 0x63, 0xbe, 0xf1,
+	0x11, 0xbf, 0x9d, 0x3f, 0x40, 0x3e, 0xb7, 0xbf, 0x3f, 0x42, 0xe7, 0xdd,
+	0x31, 0x5d, 0x3e, 0xa2, 0xce, 0xe8, 0x29, 0xc5, 0x5f, 0x29, 0xc6, 0xb2,
+	0x4a, 0xd1, 0x2a, 0xd1, 0xbd, 0x17, 0xeb, 0xde, 0x30, 0x91, 0x6f, 0x7a,
+	0xf7, 0x82, 0x7e, 0x88, 0xf9, 0xf5, 0xce, 0xb8, 0xe2, 0x5f, 0x53, 0xe3,
+	0x4c, 0x29, 0x1a, 0x97, 0xf6, 0x28, 0xfb, 0xa5, 0xed, 0x8c, 0xcf, 0xc1,
+	0x46, 0xf0, 0xf7, 0x1d, 0xa2, 0x8d, 0xcf, 0x0c, 0xe4, 0x28, 0x5f, 0x4d,
+	0x0e, 0x5f, 0x52, 0x7e, 0xa9, 0x16, 0xb3, 0xc7, 0x14, 0x0d, 0x89, 0x8e,
+	0x4d, 0xec, 0x97, 0x3d, 0xfe, 0xfc, 0x3c, 0xbf, 0x53, 0x8d, 0x6b, 0x24,
+	0x9f, 0x17, 0xbf, 0x16, 0xc7, 0x39, 0xe4, 0xfa, 0xf5, 0x13, 0x03, 0x76,
+	0xa7, 0x48, 0xff, 0x3d, 0xd1, 0x14, 0x9d, 0xeb, 0x98, 0xe8, 0x25, 0x3c,
+	0x85, 0xac, 0xc1, 0x4b, 0xf8, 0x3e, 0xff, 0x0b, 0x2d, 0x57, 0xe1, 0x61,
+	0x17, 0xdf, 0x9f, 0xc2, 0x95, 0x13, 0xda, 0xc9, 0x71, 0xd0, 0xfb, 0xb6,
+	0xe2, 0xbe, 0xe9, 0x08, 0xa8, 0xf1, 0x3a, 0x39, 0xb6, 0x29, 0x6e, 0x1d,
+	0xdd, 0x6a, 0xbd, 0x4c, 0x02, 0x74, 0x7e, 0x1c, 0x29, 0x5f, 0xcd, 0x47,
+	0xa4, 0x1d, 0xfe, 0x7d, 0x06, 0x11, 0x0f, 0xfb, 0x28, 0xf9, 0xe7, 0xf3,
+	0xf6, 0xad, 0x8c, 0xb6, 0x07, 0xf3, 0xb7, 0x5d, 0x7d, 0x6c, 0xb2, 0xab,
+	0x63, 0x13, 0xf6, 0x9b, 0x75, 0x78, 0x9f, 0x4d, 0xbc, 0xef, 0x31, 0xb5,
+	0x5f, 0x83, 0x47, 0x5f, 0xc5, 0x67, 0x45, 0x6f, 0x91, 0xdc, 0x75, 0xd6,
+	0x77, 0x2e, 0x91, 0x7f, 0xad, 0xa3, 0x53, 0xd8, 0xff, 0xf6, 0xd4, 0x6a,
+	0x7a, 0xd7, 0xb0, 0x9c, 0x75, 0xec, 0xd7, 0xd8, 0x43, 0x8c, 0xdb, 0xea,
+	0x71, 0xca, 0xfb, 0x57, 0xfb, 0x87, 0xe4, 0xdb, 0x0b, 0xd3, 0xab, 0xe9,
+	0x2b, 0x6d, 0x4a, 0x82, 0x3f, 0x65, 0xd0, 0xc1, 0xa8, 0x82, 0x5f, 0xf2,
+	0x71, 0xd3, 0xfa, 0xce, 0x1f, 0xc2, 0x7d, 0x34, 0xe8, 0xe6, 0x0b, 0x25,
+	0xb7, 0x9d, 0xf1, 0x20, 0xe5, 0x05, 0xe0, 0x9f, 0x85, 0x69, 0x9c, 0x9b,
+	0x13, 0x74, 0x3e, 0xbe, 0x68, 0x87, 0x68, 0xff, 0xa8, 0x75, 0x83, 0xef,
+	0xa5, 0xfc, 0xfd, 0x03, 0x79, 0x7d, 0x36, 0x68, 0x2f, 0xe7, 0xe9, 0x1b,
+	0x4c, 0x53, 0xb6, 0x5a, 0x57, 0x2a, 0xf3, 0xad, 0x45, 0xf2, 0x91, 0x57,
+	0x4b, 0x5c, 0x7d, 0x8f, 0xb0, 0x9c, 0x8f, 0x98, 0x0a, 0x96, 0x33, 0xc0,
+	0xeb, 0xe7, 0x7c, 0x72, 0x0c, 0x8f, 0x1c, 0x7f, 0x3e, 0x1a, 0xe3, 0x7b,
+	0xef, 0xbc, 0xb9, 0x52, 0xbd, 0xa4, 0x68, 0xb9, 0x5c, 0x8f, 0x59, 0x7d,
+	0x2f, 0xa4, 0x1a, 0x89, 0xb4, 0x85, 0x0c, 0xb2, 0x77, 0x32, 0x35, 0x02,
+	0x3f, 0x8d, 0xb3, 0x9f, 0x22, 0xf0, 0x53, 0x4d, 0xfe, 0x9e, 0xe4, 0x8d,
+	0xf8, 0xfc, 0xcd, 0x6c, 0xf6, 0x9f, 0xc7, 0xf3, 0xa6, 0x8e, 0x2f, 0x91,
+	0x34, 0xf2, 0x90, 0xbe, 0x3f, 0xf5, 0xbd, 0x72, 0x4b, 0xe7, 0x6d, 0xb9,
+	0x6f, 0x81, 0x3e, 0x41, 0x8a, 0x73, 0x74, 0x9c, 0xf3, 0xd1, 0xd5, 0xa0,
+	0x8e, 0x27, 0xf4, 0x1b, 0xff, 0x8c, 0xfa, 0xe5, 0xef, 0xe5, 0xb0, 0x22,
+	0xcd, 0xb3, 0xc7, 0x88, 0xb6, 0xf4, 0x1d, 0xc7, 0x7c, 0x65, 0xab, 0xd2,
+	0xe7, 0x27, 0x01, 0x9c, 0xd3, 0xb0, 0x98, 0xc9, 0xe0, 0x9e, 0x13, 0x11,
+	0xd2, 0xa3, 0xee, 0x32, 0xe1, 0xc2, 0x8c, 0xa6, 0x32, 0x3e, 0x7f, 0x79,
+	0xec, 0x2e, 0x66, 0xef, 0x84, 0xc4, 0x93, 0xfa, 0x6e, 0xf2, 0x79, 0x95,
+	0x78, 0xb5, 0xf9, 0xbc, 0x3c, 0x4d, 0x7c, 0xf6, 0x22, 0xd9, 0xf9, 0x0d,
+	0x6b, 0x9c, 0xeb, 0xb4, 0x8f, 0x3b, 0xd5, 0xf8, 0x79, 0xfb, 0x75, 0x9c,
+	0x77, 0xfb, 0x75, 0xe4, 0x5b, 0x2b, 0x7c, 0x11, 0x79, 0xb8, 0xf3, 0xa2,
+	0x6f, 0xff, 0x74, 0xc8, 0xd0, 0xe7, 0xe7, 0x7f, 0xf2, 0x9b, 0xfd, 0x5d,
+	0xf6, 0xdb, 0xdd, 0xd5, 0xe3, 0x9a, 0x36, 0xf9, 0x1c, 0xf6, 0xdd, 0x2d,
+	0xb4, 0x57, 0xf9, 0xef, 0x43, 0xf7, 0x1e, 0x0e, 0xed, 0x62, 0x7d, 0x76,
+	0x71, 0x1e, 0xe0, 0xfa, 0x67, 0x7d, 0x50, 0xdf, 0x8b, 0x1a, 0x0f, 0x7c,
+	0x3f, 0x02, 0xa7, 0xd6, 0x28, 0xec, 0x15, 0xaf, 0xf2, 0x39, 0xf8, 0x37,
+	0xd3, 0xd7, 0x18, 0xff, 0x27, 0xb9, 0x3e, 0xd2, 0xf5, 0xdd, 0x3d, 0xcc,
+	0x3b, 0x13, 0x6e, 0x3d, 0xa4, 0xef, 0x1f, 0x35, 0x0e, 0x08, 0x27, 0x52,
+	0x4a, 0xfb, 0x25, 0x7f, 0x07, 0x80, 0x8d, 0x3f, 0x0d, 0x3f, 0xce, 0xb6,
+	0x82, 0xef, 0x0d, 0xf8, 0xc7, 0xd1, 0xfa, 0x2d, 0x36, 0xfa, 0xde, 0x01,
+	0x6d, 0xf0, 0xaf, 0xe9, 0xfa, 0x57, 0xe3, 0x73, 0x89, 0x69, 0xed, 0x66,
+	0xb6, 0xf3, 0xbf, 0xf3, 0xbb, 0xa7, 0x1e, 0x5b, 0xc9, 0xef, 0xb4, 0xbe,
+	0xad, 0xef, 0x2e, 0xe6, 0xcb, 0x76, 0x83, 0x66, 0x76, 0xd3, 0xfc, 0x66,
+	0xe4, 0xdb, 0x70, 0xdb, 0xe9, 0xfb, 0xd4, 0xa7, 0xfa, 0x5d, 0x53, 0xf9,
+	0x25, 0xd0, 0x33, 0x4c, 0x3f, 0xf7, 0x14, 0xe8, 0xb9, 0xa7, 0xfc, 0x79,
+	0xc4, 0x8c, 0xfb, 0xe2, 0xdb, 0x86, 0xf8, 0xbe, 0xe3, 0xc6, 0x77, 0x3d,
+	0xea, 0x03, 0x19, 0xaf, 0x55, 0xe3, 0xe9, 0xc6, 0xe9, 0x7e, 0xf1, 0x7c,
+	0xd8, 0x71, 0x4c, 0xed, 0xc2, 0x3d, 0x37, 0xcc, 0xef, 0xcd, 0x45, 0xf7,
+	0x9e, 0x2a, 0x16, 0xdf, 0xc8, 0xff, 0xe3, 0x4b, 0xf1, 0x3d, 0xb2, 0xa4,
+	0xf3, 0x1f, 0xee, 0x79, 0x5d, 0xd7, 0x0f, 0x79, 0xea, 0x7a, 0xff, 0xbe,
+	0xdf, 0xa2, 0x7a, 0x79, 0x34, 0xe0, 0xe2, 0x82, 0xf8, 0xa7, 0x79, 0x5d,
+	0x19, 0xaf, 0xdb, 0xb7, 0x6c, 0xdd, 0xb5, 0x8c, 0x5a, 0xf7, 0xb7, 0x4f,
+	0x97, 0xf7, 0x25, 0x7c, 0x7a, 0x26, 0x45, 0x1c, 0xf1, 0xc1, 0x7d, 0x61,
+	0x16, 0xe9, 0x63, 0xf8, 0x71, 0xb7, 0x37, 0x8e, 0x7c, 0xa8, 0xdf, 0x79,
+	0xfe, 0xba, 0xfe, 0x8f, 0x9f, 0xae, 0x5c, 0xd7, 0x6b, 0x79, 0x88, 0x5f,
+	0xb7, 0x11, 0x23, 0xbe, 0xeb, 0x43, 0x6a, 0x5d, 0xbf, 0x6b, 0x5f, 0x3b,
+	0xd9, 0x75, 0x99, 0xed, 0xab, 0x63, 0xfb, 0xe4, 0xe7, 0x6d, 0x74, 0x9f,
+	0x58, 0xd7, 0x87, 0xbc, 0xf6, 0xfd, 0x7a, 0x95, 0xfd, 0x1e, 0xf4, 0x1d,
+	0xc1, 0xfb, 0xc6, 0xf5, 0xfe, 0x4a, 0x5e, 0x2d, 0xd7, 0x63, 0x8e, 0xe0,
+	0xe7, 0x54, 0x91, 0xba, 0x46, 0xed, 0xff, 0x7b, 0xe9, 0x00, 0xbe, 0xc7,
+	0xe8, 0x1d, 0x11, 0xb4, 0x2e, 0x67, 0x8a, 0xf9, 0xe5, 0x6b, 0x01, 0xf0,
+	0x15, 0x8b, 0x9b, 0xfa, 0x1e, 0x66, 0x39, 0xc5, 0xec, 0x66, 0x3d, 0x5d,
+	0x3c, 0xf0, 0x3a, 0xe2, 0xeb, 0x63, 0xbe, 0x50, 0x91, 0xbe, 0x04, 0x46,
+	0xb9, 0xad, 0x54, 0x2f, 0x5e, 0x38, 0x39, 0xad, 0xf8, 0x62, 0xee, 0xbb,
+	0xcc, 0xaf, 0xdf, 0xc4, 0x43, 0xf0, 0x23, 0xbd, 0x3f, 0x44, 0xaf, 0xb3,
+	0x92, 0xbf, 0xf0, 0x7e, 0x5a, 0x98, 0xd6, 0xfe, 0xb6, 0xc9, 0x4e, 0xd4,
+	0xd3, 0x17, 0x0a, 0xfc, 0x68, 0x78, 0xfc, 0x08, 0xfe, 0x95, 0x71, 0xef,
+	0x7f, 0x97, 0x03, 0x17, 0xaf, 0x16, 0xc1, 0x3d, 0xf5, 0xf7, 0x1e, 0xd8,
+	0xce, 0x03, 0xad, 0x5e, 0xbb, 0x1a, 0xc4, 0x4c, 0x16, 0xf8, 0xef, 0x62,
+	0x9c, 0xbc, 0xc8, 0x79, 0xf6, 0x7a, 0x54, 0x4d, 0x58, 0xa2, 0xe7, 0x19,
+	0xe4, 0xe9, 0x8a, 0x52, 0xd8, 0xdd, 0xf3, 0x55, 0xed, 0x27, 0xcc, 0xd7,
+	0xc4, 0x50, 0x57, 0x77, 0x45, 0xf0, 0xbe, 0xa8, 0x89, 0x81, 0x56, 0x70,
+	0x9e, 0x9e, 0x71, 0xfb, 0x29, 0xa0, 0xf9, 0xfa, 0x12, 0x7d, 0xa5, 0xdf,
+	0x9a, 0xa8, 0xc3, 0x45, 0x13, 0xd7, 0xcf, 0x94, 0xef, 0x82, 0xe2, 0x60,
+	0x13, 0x70, 0x22, 0xea, 0xfd, 0x79, 0x8a, 0xf3, 0xec, 0xb2, 0x7a, 0x0d,
+	0x7d, 0x99, 0x12, 0x4f, 0x5f, 0x42, 0xef, 0xa7, 0xfd, 0xa8, 0xe5, 0xd2,
+	0x70, 0x85, 0xba, 0x72, 0x91, 0xf3, 0xd8, 0x23, 0xe2, 0x0f, 0x59, 0xd8,
+	0x35, 0x93, 0x2d, 0xc4, 0x95, 0xde, 0x4f, 0xcb, 0x83, 0xde, 0xda, 0x8e,
+	0xbc, 0x7c, 0xec, 0x7f, 0x88, 0xf5, 0xfc, 0x07, 0xf5, 0x33, 0x2b, 0xd8,
+	0x1e, 0x25, 0x17, 0xf3, 0xfb, 0xb8, 0x4f, 0x94, 0x74, 0xc7, 0xfe, 0xfe,
+	0x4e, 0x17, 0xe9, 0xb5, 0x86, 0x71, 0x54, 0xe1, 0xc1, 0x39, 0xf8, 0xd7,
+	0xb6, 0x80, 0x9e, 0x6d, 0xd1, 0x71, 0xd0, 0xf1, 0xd2, 0xf1, 0x41, 0x1c,
+	0x2b, 0xd0, 0x4f, 0xda, 0xd1, 0xf3, 0x04, 0xdd, 0x0f, 0x2d, 0x3d, 0x0b,
+	0xfa, 0xdc, 0x61, 0xfd, 0x81, 0x66, 0xc5, 0xff, 0x9a, 0xf8, 0x13, 0xf7,
+	0x1b, 0xfe, 0xca, 0xb4, 0xb0, 0x6f, 0x82, 0xbe, 0x8b, 0x8c, 0x5b, 0x98,
+	0x03, 0xd2, 0xaa, 0xf3, 0xac, 0xf7, 0x9d, 0xa0, 0xcf, 0xdf, 0xd6, 0x65,
+	0x78, 0xcd, 0xe7, 0x4b, 0x6d, 0x9f, 0xe2, 0x6f, 0x66, 0x1c, 0xca, 0xf7,
+	0xe9, 0x5e, 0xa5, 0x47, 0x5c, 0xde, 0xdb, 0xc8, 0xc7, 0x4e, 0xc4, 0x1b,
+	0x27, 0x89, 0x87, 0x92, 0x88, 0x1a, 0xd6, 0x95, 0x97, 0x90, 0x1d, 0xa7,
+	0xdf, 0xff, 0x80, 0x3e, 0xbf, 0x3d, 0x51, 0x8a, 0xf9, 0xca, 0x67, 0xe2,
+	0xe4, 0x87, 0x73, 0xc0, 0xf1, 0x8f, 0xce, 0x82, 0xbe, 0x25, 0xbe, 0x82,
+	0xf5, 0xe5, 0xa7, 0xe8, 0xfe, 0xb7, 0x2a, 0x19, 0x97, 0x55, 0x38, 0xf7,
+	0x69, 0xd4, 0x0f, 0x4b, 0x4b, 0x22, 0x86, 0xba, 0x4d, 0xdf, 0x03, 0xc0,
+	0x65, 0xc8, 0x13, 0xdf, 0xfb, 0xe1, 0x54, 0x51, 0xbb, 0xf0, 0x9d, 0x64,
+	0x15, 0xe2, 0x55, 0xfb, 0xa3, 0xca, 0x28, 0x8a, 0xcf, 0x36, 0x3f, 0x3e,
+	0x4d, 0xc6, 0xe7, 0x5d, 0xb7, 0x8e, 0x5a, 0x2e, 0x97, 0xde, 0x89, 0x12,
+	0xb7, 0x0f, 0x0b, 0xaf, 0xa0, 0xfb, 0x1a, 0xd4, 0xfe, 0x95, 0xcb, 0xf2,
+	0xeb, 0x06, 0x5f, 0x9c, 0x6f, 0xde, 0xd3, 0x7a, 0x9d, 0x32, 0xbd, 0xdf,
+	0x5b, 0xdc, 0x7b, 0x66, 0x98, 0xfb, 0xfc, 0x39, 0xf4, 0xa3, 0x12, 0xf3,
+	0x69, 0x1a, 0xda, 0xd5, 0xef, 0x52, 0xdf, 0x22, 0x31, 0xcc, 0xf9, 0xf3,
+	0xfd, 0xa0, 0xae, 0xb7, 0x30, 0xbe, 0xc2, 0x79, 0xe3, 0x0e, 0xeb, 0x75,
+	0x80, 0x61, 0x39, 0xdf, 0x48, 0x79, 0x37, 0xa1, 0xeb, 0xb4, 0x61, 0x7e,
+	0x5f, 0xe8, 0x3e, 0xd5, 0x97, 0x83, 0x9c, 0x4f, 0xc9, 0x8f, 0xa1, 0xc4,
+	0xed, 0x29, 0xdd, 0x4f, 0xd0, 0xfd, 0x05, 0xd6, 0x07, 0xfd, 0x30, 0x71,
+	0x30, 0x02, 0x2a, 0x9a, 0xfc, 0xf1, 0x11, 0xae, 0x9d, 0x18, 0x99, 0x05,
+	0xfd, 0x86, 0x08, 0xf7, 0x09, 0x27, 0x58, 0xbf, 0x33, 0xfc, 0xbe, 0x73,
+	0xc8, 0x4f, 0x65, 0xd2, 0x7e, 0xea, 0x5b, 0x25, 0x8e, 0x4d, 0xc3, 0xae,
+	0x01, 0xf7, 0xfd, 0x06, 0x3e, 0xa6, 0xce, 0x9b, 0xdc, 0x2f, 0xe3, 0xbe,
+	0x9a, 0x63, 0x8e, 0xc0, 0x9e, 0x81, 0x1c, 0xc6, 0x8b, 0x78, 0x17, 0x39,
+	0xff, 0xe2, 0x3a, 0xef, 0xf8, 0x49, 0xfd, 0x1e, 0x2c, 0xbe, 0x4e, 0xd7,
+	0x85, 0x83, 0xf4, 0x2e, 0x79, 0x61, 0x92, 0xfb, 0xea, 0xa2, 0x9f, 0xea,
+	0xd1, 0xaf, 0xdb, 0x39, 0x1e, 0xe7, 0xfb, 0x07, 0xfe, 0xbe, 0x81, 0xae,
+	0xbf, 0xe7, 0xd0, 0xff, 0x9c, 0xcc, 0xa5, 0x81, 0x97, 0x64, 0x89, 0x17,
+	0xe7, 0x25, 0x89, 0x4a, 0x8e, 0xdb, 0xda, 0x27, 0x41, 0xcf, 0x3e, 0x89,
+	0x77, 0xf2, 0xc0, 0x2b, 0xec, 0x97, 0x1d, 0x14, 0xa7, 0xed, 0xe8, 0xbf,
+	0x78, 0xeb, 0x50, 0x85, 0x9b, 0x4f, 0x5c, 0x3c, 0xcf, 0x91, 0x5e, 0xb5,
+	0x93, 0x39, 0xe2, 0xab, 0x11, 0x8f, 0xd0, 0xbd, 0x57, 0xed, 0x2c, 0x40,
+	0xcf, 0xc4, 0x04, 0xdb, 0x37, 0xf4, 0x05, 0xd0, 0x57, 0x38, 0xce, 0x3a,
+	0x7e, 0x57, 0xdd, 0x3e, 0x1e, 0xf4, 0xd5, 0xf7, 0xf1, 0xf2, 0xf7, 0x3b,
+	0xc6, 0xd5, 0xad, 0x48, 0x60, 0x7d, 0xc7, 0x8b, 0xf7, 0xa7, 0xfc, 0x78,
+	0x50, 0x78, 0xd1, 0xb8, 0xf4, 0xe2, 0xa8, 0xf0, 0x9c, 0xe5, 0x71, 0xe1,
+	0x34, 0x55, 0x91, 0xbf, 0x70, 0x9f, 0x98, 0x89, 0x89, 0xcc, 0xea, 0x7e,
+	0x7a, 0x13, 0x7e, 0x4a, 0xb0, 0xde, 0x76, 0xff, 0x08, 0xee, 0xa1, 0x31,
+	0x8e, 0xd3, 0x5c, 0x23, 0xd7, 0x11, 0xac, 0xdf, 0xc7, 0xfc, 0xce, 0x40,
+	0x3c, 0x23, 0xf6, 0xe1, 0x69, 0x8e, 0x1f, 0xe3, 0xea, 0x08, 0xdb, 0xfd,
+	0x11, 0xec, 0xb6, 0xb5, 0xdd, 0xfd, 0xae, 0xdd, 0xba, 0x4e, 0xf1, 0xca,
+	0x29, 0x97, 0xb8, 0xa0, 0x7a, 0xc7, 0xbe, 0x4a, 0x79, 0x24, 0xcc, 0x76,
+	0x4a, 0xbe, 0x56, 0xfd, 0xff, 0x8e, 0xf0, 0x57, 0xef, 0x76, 0xef, 0xba,
+	0x52, 0x5e, 0x17, 0x95, 0xeb, 0x30, 0x8f, 0xf3, 0x67, 0xaf, 0xe0, 0x4f,
+	0xe5, 0x37, 0x2d, 0xb7, 0xf0, 0x7c, 0x79, 0xfd, 0x47, 0x95, 0x1d, 0xfd,
+	0x90, 0x57, 0x64, 0x9c, 0xe8, 0x1e, 0xb2, 0xdd, 0xbc, 0x72, 0x87, 0xea,
+	0xc0, 0xe8, 0x85, 0x41, 0xe4, 0x81, 0x0b, 0x83, 0xef, 0x72, 0x1d, 0xce,
+	0x7e, 0xe9, 0xa2, 0xff, 0xaf, 0x92, 0xb1, 0xab, 0xf7, 0xe7, 0x15, 0xbf,
+	0x1e, 0xb5, 0x1e, 0x3d, 0xf4, 0xbe, 0xff, 0x01, 0xfe, 0xf0, 0x11, 0xdc,
+	0xa0, 0x1d, 0x00, 0x00, 0x00 };
 
 static u8 bnx2_TPAT_b06FwText[] = {
-/*	0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
-							0xc5, 0x57, 0x4d, 0x68,
-	0x1c, 0xe7, 0x19, 0x7e, 0xe7, 0x77, 0x47, 0x62, 0x25, 0x8d, 0x93, 0x3d,
-	0xac, 0x5d, 0xa5, 0x99, 0x91, 0x46, 0x3f, 0x54, 0x26, 0x9e, 0x84, 0xa5,
-	0x56, 0x61, 0x20, 0xe3, 0x99, 0x95, 0x2c, 0x0c, 0x05, 0x07, 0x42, 0x08,
-	0xe4, 0xb2, 0x1d, 0x49, 0x36, 0x85, 0x1e, 0x5a, 0x9a, 0x43, 0xa0, 0x05,
-	0x0f, 0x33, 0xeb, 0x34, 0x87, 0xc5, 0xdb, 0xaa, 0xc5, 0xbe, 0x94, 0xd6,
-	0x95, 0xea, 0xe8, 0xb2, 0x68, 0xe2, 0x53, 0x0f, 0xc5, 0xd8, 0xb4, 0x54,
-	0xd0, 0x53, 0x7b, 0x0a, 0x85, 0x5c, 0x4c, 0x69, 0x20, 0x85, 0x12, 0x44,
-	0x0f, 0x21, 0xd4, 0xad, 0xa7, 0xcf, 0xfb, 0xcd, 0x8c, 0xbc, 0xbb, 0x95,
-	0x5b, 0x1f, 0x02, 0x15, 0xac, 0x66, 0xe6, 0xfb, 0xde, 0xf7, 0xfb, 0x79,
-	0x9f, 0xe7, 0x79, 0xbf, 0xf7, 0x6b, 0xca, 0x34, 0x49, 0xe5, 0xdf, 0x14,
-	0x7e, 0x6f, 0x7f, 0xe3, 0xdb, 0x6f, 0x7f, 0xf5, 0xa5, 0x57, 0x2c, 0xa2,
-	0x57, 0x5e, 0x92, 0x64, 0x5d, 0xa6, 0x2f, 0xe0, 0x4f, 0x21, 0x32, 0xab,
-	0xf1, 0xf9, 0x47, 0x86, 0xec, 0x75, 0xce, 0x04, 0x0e, 0x19, 0x8a, 0x77,
-	0x34, 0xbb, 0xe9, 0x10, 0xf9, 0x83, 0x15, 0x2b, 0xa4, 0x7f, 0xe5, 0x71,
-	0x43, 0x25, 0x6e, 0x7f, 0xc1, 0xfb, 0xe7, 0xb9, 0x7b, 0xe7, 0xed, 0xa3,
-	0xdb, 0x0a, 0x19, 0xa6, 0xd7, 0x31, 0xcc, 0x45, 0x32, 0x66, 0xe1, 0xf3,
-	0xd3, 0xa5, 0x75, 0x8d, 0xa6, 0xab, 0xb1, 0x4c, 0x4a, 0xfa, 0x06, 0xad,
-	0xf5, 0x30, 0x8e, 0xf3, 0x8e, 0x14, 0x66, 0xaa, 0x14, 0xde, 0x32, 0x48,
-	0xf6, 0x7c, 0x29, 0xc8, 0x1c, 0xf4, 0x49, 0x14, 0xb8, 0x35, 0xf2, 0xcd,
-	0x3c, 0xff, 0xa6, 0x2b, 0x93, 0xec, 0x3c, 0xce, 0xe7, 0x17, 0xd6, 0xa5,
-	0x60, 0x7f, 0x43, 0x0a, 0xf7, 0x03, 0xde, 0x37, 0xd6, 0xb1, 0x2e, 0xf9,
-	0xfb, 0xfc, 0xf4, 0x8c, 0xb0, 0x37, 0x4d, 0x9d, 0x06, 0xcd, 0xc8, 0x0e,
-	0xfb, 0x5a, 0x14, 0xba, 0x2b, 0x4d, 0x85, 0xe6, 0xf1, 0x9b, 0xa0, 0x6d,
-	0x97, 0xea, 0x81, 0x4b, 0xaa, 0xe2, 0xc8, 0x14, 0x36, 0x24, 0xfa, 0x65,
-	0x4b, 0xc3, 0xef, 0x92, 0xd4, 0xde, 0xdf, 0x2a, 0xc7, 0x69, 0x50, 0x8a,
-	0xb5, 0x44, 0x0d, 0x5e, 0x5b, 0xe1, 0x1f, 0xb8, 0x2b, 0xa6, 0x4c, 0xf3,
-	0xf8, 0x4d, 0xe1, 0x3d, 0x82, 0x9d, 0x46, 0x41, 0x6b, 0xbc, 0x6f, 0x02,
-	0xef, 0x58, 0x27, 0xc6, 0x0a, 0xc4, 0x3a, 0x2c, 0xac, 0xc3, 0xa1, 0x6e,
-	0x7f, 0x03, 0xfb, 0x58, 0x68, 0x46, 0xa4, 0x53, 0x57, 0xac, 0x7d, 0x8a,
-	0x12, 0x53, 0xa1, 0xe4, 0xac, 0x46, 0xfe, 0x65, 0x15, 0xdf, 0xcf, 0x51,
-	0x6c, 0x4a, 0xb0, 0xe9, 0x96, 0xf8, 0xd5, 0xd0, 0xaf, 0xa3, 0x7d, 0x86,
-	0x92, 0xc6, 0x29, 0x49, 0xf6, 0xbe, 0x8f, 0xf6, 0x05, 0x33, 0xa2, 0xef,
-	0xe1, 0x29, 0xe1, 0xfb, 0x14, 0x8f, 0x87, 0x6f, 0x89, 0x14, 0x87, 0xcc,
-	0x20, 0xb3, 0x28, 0xcd, 0x2a, 0x5f, 0x6e, 0x2f, 0xda, 0xe2, 0x6c, 0x1c,
-	0x3b, 0xd8, 0xf5, 0x5f, 0xa5, 0x8e, 0x49, 0xb1, 0xea, 0xc1, 0xa6, 0xef,
-	0x98, 0x6d, 0xe0, 0xe4, 0x0b, 0x3c, 0xbf, 0xc6, 0xed, 0xfc, 0x87, 0x76,
-	0x8b, 0x14, 0xcf, 0x31, 0x43, 0x6a, 0x51, 0xd1, 0xd7, 0x30, 0x83, 0x5b,
-	0x2f, 0x93, 0x2f, 0xe2, 0x61, 0xe0, 0xdd, 0xc4, 0x9e, 0x74, 0x60, 0x9b,
-	0xf8, 0x32, 0xc5, 0x4d, 0x83, 0xec, 0xd5, 0x2d, 0xf4, 0x7c, 0xdc, 0x53,
-	0x10, 0x67, 0xc6, 0x49, 0x2d, 0xfd, 0x18, 0xd7, 0xdf, 0x62, 0x5d, 0xb1,
-	0x69, 0xd0, 0x0c, 0x75, 0x5e, 0xcf, 0xf3, 0x3b, 0x6e, 0x9e, 0xeb, 0x9e,
-	0xb3, 0xfc, 0x3e, 0xad, 0x34, 0x35, 0x5a, 0x34, 0xf1, 0x44, 0xdc, 0x1c,
-	0xc4, 0x46, 0x2d, 0xe7, 0x9f, 0x2a, 0xd7, 0xfa, 0x48, 0x42, 0xe8, 0xe9,
-	0xcf, 0xbd, 0xdf, 0xf0, 0xde, 0x97, 0xd7, 0x85, 0x7d, 0x9e, 0xef, 0xae,
-	0x3e, 0xcd, 0x5e, 0x93, 0x0b, 0xfb, 0x3c, 0x5f, 0x6b, 0xf1, 0x7c, 0x36,
-	0xf6, 0xc6, 0x9c, 0x24, 0x5a, 0x1b, 0xb8, 0x46, 0xd4, 0xc3, 0xba, 0x1c,
-	0x3c, 0x07, 0x4d, 0xac, 0xdd, 0x5e, 0xb6, 0x24, 0x83, 0x12, 0x27, 0x7f,
-	0x11, 0x3c, 0xf0, 0x43, 0xc7, 0xfe, 0x53, 0xa8, 0xd4, 0x68, 0xcf, 0xad,
-	0x53, 0x37, 0x6b, 0x52, 0x92, 0x75, 0x29, 0xc8, 0x64, 0x8c, 0x5f, 0xa3,
-	0x5d, 0xe7, 0xf3, 0x7c, 0xcd, 0x75, 0x81, 0x33, 0xb1, 0x5f, 0x73, 0x8d,
-	0x66, 0xd1, 0xbf, 0x62, 0x6e, 0x91, 0x8b, 0x98, 0xcb, 0x88, 0xc9, 0xbc,
-	0x78, 0x4f, 0x32, 0x17, 0xfd, 0x14, 0xcb, 0x2d, 0xdb, 0x4c, 0xc8, 0x6e,
-	0x06, 0x0a, 0x99, 0xb2, 0x67, 0xc2, 0x26, 0xa6, 0x76, 0x66, 0xd0, 0x43,
-	0xe5, 0x1d, 0xc1, 0xe3, 0xb4, 0xff, 0x30, 0xbf, 0xb7, 0xd4, 0xa4, 0xfb,
-	0x59, 0x83, 0xee, 0x66, 0x24, 0x47, 0x1c, 0xab, 0x86, 0x49, 0x1f, 0x64,
-	0xd5, 0x3e, 0xc0, 0x65, 0x27, 0x39, 0xa3, 0x40, 0x67, 0x9b, 0xee, 0x03,
-	0xb0, 0xc4, 0x06, 0x0e, 0x31, 0xf6, 0x5c, 0x3d, 0x79, 0x4f, 0xb7, 0xcf,
-	0x6c, 0x3a, 0xf6, 0x7b, 0x21, 0xb3, 0xf3, 0x86, 0x8a, 0xd6, 0xe1, 0x38,
-	0x7c, 0x1d, 0xfe, 0x26, 0x5d, 0x87, 0x5e, 0x64, 0xc4, 0x63, 0xee, 0xc0,
-	0xa0, 0xfd, 0x5e, 0x8d, 0xac, 0x5d, 0x95, 0xa2, 0x7e, 0x83, 0xdc, 0x45,
-	0xdb, 0x22, 0x59, 0x6e, 0xc8, 0x88, 0xdf, 0xdc, 0x6e, 0x4e, 0xeb, 0xae,
-	0x46, 0x87, 0xce, 0x77, 0x75, 0x9a, 0x4e, 0x5c, 0x9d, 0xd8, 0xc6, 0xa0,
-	0xb9, 0xf7, 0x0d, 0x29, 0xec, 0xf3, 0xfa, 0x39, 0xce, 0x46, 0x19, 0x67,
-	0x55, 0x0a, 0x6e, 0xd5, 0x68, 0x7e, 0xe7, 0x6f, 0x79, 0xe0, 0x20, 0xc6,
-	0xe0, 0xf1, 0x66, 0xcb, 0x56, 0x68, 0x12, 0x6d, 0xbb, 0xdc, 0x77, 0x54,
-	0xb6, 0xf3, 0x18, 0x79, 0x1e, 0xb8, 0xcf, 0x53, 0xc0, 0xfc, 0x7e, 0x9d,
-	0x7d, 0x6a, 0x34, 0xb7, 0xc3, 0xba, 0xc0, 0x73, 0x97, 0xbf, 0x79, 0x6d,
-	0x13, 0x14, 0x61, 0x37, 0xd1, 0x72, 0x03, 0xfb, 0x97, 0x85, 0x06, 0x22,
-	0xec, 0x56, 0x76, 0x26, 0xf1, 0x14, 0x71, 0x50, 0x0a, 0x3e, 0x73, 0x5e,
-	0xa8, 0x53, 0x08, 0x5c, 0x55, 0xac, 0x67, 0x8b, 0x16, 0x9a, 0xdb, 0xa2,
-	0x0f, 0x6d, 0x03, 0xee, 0x33, 0xc7, 0xfa, 0xf0, 0x3d, 0xa8, 0xd6, 0x20,
-	0x03, 0xf3, 0x14, 0xb3, 0x68, 0x62, 0xaf, 0x6b, 0x2e, 0xdb, 0xb3, 0x6d,
-	0xbc, 0xac, 0x91, 0xbd, 0xbc, 0x8b, 0xd1, 0xf7, 0x7b, 0xd8, 0xef, 0x4d,
-	0xce, 0x35, 0x8e, 0xf5, 0x17, 0x62, 0xfb, 0x79, 0xec, 0x79, 0x61, 0x35,
-	0xe5, 0xbe, 0x81, 0x46, 0xce, 0x4e, 0x6c, 0xaa, 0x88, 0xbd, 0x8c, 0xc0,
-	0x87, 0x3f, 0xfc, 0x2c, 0xd7, 0x3c, 0x70, 0xb8, 0x35, 0x03, 0x6c, 0x6c,
-	0x2b, 0x85, 0x9e, 0x1d, 0x8c, 0x9b, 0xb8, 0x0a, 0xfc, 0x0a, 0x8c, 0xd8,
-	0x6e, 0xbd, 0x97, 0x53, 0x2a, 0xe6, 0xba, 0xc6, 0x73, 0x21, 0xe7, 0x38,
-	0xab, 0xbf, 0x03, 0x27, 0x22, 0xaa, 0xd3, 0xe2, 0x41, 0x9d, 0xae, 0x0e,
-	0xea, 0x34, 0x77, 0x43, 0x47, 0x1c, 0xf2, 0xbc, 0xdb, 0x62, 0x0d, 0x02,
-	0x6b, 0x87, 0xed, 0xec, 0xa6, 0x22, 0xf3, 0x3a, 0xd0, 0x7f, 0x40, 0xb4,
-	0x35, 0xd0, 0x11, 0x37, 0x75, 0x68, 0x6c, 0x99, 0x2e, 0xfe, 0x84, 0xe8,
-	0xe2, 0x80, 0x7d, 0x79, 0xfc, 0xc2, 0x27, 0xc2, 0x9e, 0x65, 0x60, 0x7e,
-	0x75, 0x20, 0x23, 0x1f, 0x20, 0x5f, 0xee, 0x07, 0xc8, 0x83, 0x6d, 0xfc,
-	0xd6, 0x91, 0x1b, 0x19, 0x1b, 0xce, 0x13, 0x8f, 0x81, 0xcf, 0x06, 0xfa,
-	0x2e, 0xa1, 0x8d, 0xf3, 0x16, 0xdb, 0xea, 0xd4, 0x76, 0xa7, 0x28, 0xad,
-	0x72, 0x91, 0xc9, 0xb9, 0xe8, 0x14, 0xf8, 0x34, 0x81, 0xfc, 0x72, 0x47,
-	0x19, 0xcd, 0x45, 0xc8, 0x59, 0x8d, 0xd3, 0xc8, 0x3d, 0x3f, 0x47, 0x3b,
-	0x8f, 0xf7, 0x33, 0x3c, 0x27, 0xf0, 0x7d, 0x1a, 0xb6, 0xc3, 0x79, 0xa8,
-	0xf2, 0x7b, 0x5a, 0x0e, 0x02, 0xef, 0x76, 0x0c, 0xd8, 0x5b, 0xd0, 0x0b,
-	0xc7, 0xbb, 0x86, 0x7c, 0xc1, 0x31, 0xaf, 0x21, 0xa6, 0x3a, 0xe6, 0x36,
-	0x69, 0xfe, 0x80, 0x62, 0xa5, 0xcc, 0x4f, 0xe1, 0x71, 0x7e, 0x6a, 0x0a,
-	0x1e, 0x24, 0x99, 0x09, 0x1f, 0xd6, 0x6d, 0xa5, 0x53, 0xc6, 0x8e, 0xfc,
-	0x00, 0x1a, 0x0e, 0x94, 0x3c, 0xdf, 0xc4, 0x19, 0x11, 0x01, 0x77, 0x1f,
-	0xda, 0x8d, 0xa0, 0xdd, 0x70, 0x48, 0xbb, 0xe1, 0xff, 0xd4, 0x2e, 0x74,
-	0x09, 0x8d, 0xdc, 0x05, 0xa7, 0x3e, 0xe8, 0x9f, 0xa4, 0x63, 0xd6, 0x30,
-	0x6b, 0xd9, 0xa2, 0x7b, 0x4b, 0xcf, 0xa2, 0xe5, 0xbf, 0x3e, 0xab, 0x96,
-	0x63, 0xd6, 0xb2, 0xca, 0x5a, 0x6e, 0x0c, 0x6b, 0xf9, 0x53, 0xf8, 0x17,
-	0x9a, 0xbc, 0xa0, 0x36, 0x48, 0x5b, 0x04, 0x0e, 0x3b, 0x75, 0x52, 0x6e,
-	0x3c, 0xe1, 0x1b, 0x73, 0x38, 0x1c, 0xe0, 0xdf, 0x81, 0x86, 0x3e, 0x69,
-	0xb4, 0x1d, 0x39, 0x4f, 0xf5, 0xec, 0xe6, 0x96, 0xb0, 0x51, 0x49, 0x47,
-	0xdc, 0xbf, 0xb3, 0x64, 0x5b, 0x96, 0x3c, 0xac, 0x79, 0xa8, 0x7e, 0x27,
-	0xbf, 0xa6, 0x79, 0x3c, 0x4f, 0x6c, 0x81, 0xeb, 0xd6, 0x8f, 0x80, 0x51,
-	0xda, 0x63, 0x9e, 0x3b, 0xe6, 0x9a, 0xe0, 0x17, 0xbe, 0xa1, 0x05, 0x0d,
-	0x7c, 0xad, 0xc1, 0x4e, 0xdd, 0x29, 0xf4, 0x73, 0x17, 0xe3, 0xee, 0xf5,
-	0x98, 0x5f, 0x06, 0xe9, 0x37, 0x9d, 0xe6, 0x55, 0x91, 0x73, 0xe7, 0xcd,
-	0x75, 0x62, 0xed, 0xf1, 0x79, 0x87, 0xfe, 0x41, 0x8d, 0x14, 0xa1, 0xf7,
-	0xc9, 0x52, 0xef, 0x2f, 0x20, 0x46, 0x93, 0xf8, 0x66, 0xcd, 0x9f, 0x2e,
-	0x35, 0x3f, 0x8d, 0x27, 0xb7, 0x5d, 0x54, 0x0b, 0xee, 0x80, 0x87, 0x3b,
-	0x8c, 0x6b, 0x1d, 0xf9, 0x8d, 0xe7, 0xff, 0x7b, 0xbe, 0xe9, 0x30, 0xb6,
-	0x8e, 0xf5, 0x03, 0x5a, 0x80, 0xee, 0xd0, 0x7e, 0xc0, 0xb6, 0xec, 0x53,
-	0xd9, 0x9a, 0xa5, 0xed, 0xa7, 0x63, 0xb6, 0x68, 0x3f, 0x60, 0x3b, 0xd6,
-	0xc5, 0x73, 0xa4, 0xdc, 0xe4, 0xf3, 0x38, 0x60, 0x5d, 0xc0, 0xaf, 0x8d,
-	0x36, 0xae, 0x19, 0xd8, 0x9f, 0xcf, 0x66, 0x5e, 0x27, 0xd7, 0x13, 0x7c,
-	0x7e, 0x8f, 0x9d, 0xd3, 0xc7, 0xda, 0xb8, 0x00, 0xbe, 0x7f, 0x4b, 0xfd,
-	0x4f, 0x6d, 0xbc, 0x06, 0x2d, 0x5c, 0x51, 0x0b, 0x6d, 0x6c, 0xe3, 0x79,
-	0x01, 0xdf, 0xaf, 0x8d, 0x69, 0xa3, 0xf2, 0x7b, 0xfa, 0xf9, 0x9c, 0xf4,
-	0x9b, 0xe2, 0x6c, 0xe5, 0xf9, 0x94, 0x1d, 0x8a, 0xb5, 0x52, 0x07, 0x6b,
-	0xc7, 0x3a, 0x98, 0x44, 0xae, 0x18, 0xe1, 0xb8, 0x12, 0xba, 0xb6, 0x99,
-	0x12, 0x6b, 0x62, 0xf8, 0xfc, 0xfa, 0x7f, 0xe9, 0x82, 0xc0, 0x23, 0x31,
-	0x37, 0x6a, 0x0c, 0x3e, 0x0f, 0xf2, 0xfc, 0x8a, 0x8b, 0xfe, 0xaa, 0xd6,
-	0x10, 0xd8, 0xf3, 0x59, 0xcb, 0x78, 0xa0, 0xbe, 0x73, 0xe6, 0xa1, 0x05,
-	0xce, 0x01, 0x8f, 0xf3, 0x3d, 0x27, 0x40, 0x5b, 0x1b, 0xf1, 0x67, 0x4c,
-	0x36, 0xa4, 0xf5, 0x7d, 0x83, 0xfd, 0xa0, 0xb3, 0x93, 0x6a, 0x2c, 0x1d,
-	0x9a, 0x7a, 0x82, 0x13, 0xf3, 0x28, 0x1a, 0xc2, 0xa9, 0x23, 0x70, 0xfa,
-	0xf0, 0x18, 0xa7, 0xa8, 0xc4, 0x29, 0x12, 0x38, 0xfd, 0xb1, 0xc4, 0xe9,
-	0x0f, 0x4f, 0xc1, 0xe9, 0xc3, 0x67, 0xc0, 0xc9, 0xa0, 0x3d, 0xa7, 0x89,
-	0x73, 0x56, 0x17, 0x35, 0xe9, 0xa1, 0x7b, 0x52, 0x4d, 0x75, 0x52, 0xdc,
-	0x6d, 0x73, 0x8f, 0x86, 0xeb, 0x0e, 0xdb, 0x7a, 0x80, 0xf5, 0xa5, 0xc0,
-	0xee, 0xfa, 0x58, 0xed, 0x91, 0xc0, 0xbe, 0x5d, 0xe2, 0x74, 0x1d, 0x38,
-	0xb5, 0x4b, 0x9c, 0xb6, 0x87, 0x70, 0xda, 0x1e, 0xc1, 0x89, 0xf3, 0x49,
-	0xcb, 0xd8, 0xee, 0x55, 0x18, 0x55, 0xf8, 0xe8, 0x74, 0xdb, 0x9c, 0xc6,
-	0xfe, 0xcf, 0x51, 0xfa, 0x63, 0x95, 0xeb, 0x5a, 0x60, 0xf7, 0xaa, 0x2a,
-	0x8b, 0xf3, 0x80, 0xdf, 0x9f, 0xd4, 0x27, 0x98, 0xcb, 0x0f, 0x5c, 0x8e,
-	0x23, 0xea, 0x57, 0xa7, 0xca, 0x43, 0xcf, 0xab, 0xa8, 0xad, 0xf0, 0xcd,
-	0x36, 0xaa, 0xd4, 0x86, 0xde, 0x15, 0xd4, 0xe5, 0xe1, 0x71, 0x5d, 0x5e,
-	0xc4, 0xe0, 0x7a, 0x59, 0x97, 0xef, 0x39, 0x5c, 0x97, 0x2f, 0x6a, 0x34,
-	0xb9, 0x51, 0x62, 0xc9, 0x9c, 0x9e, 0x42, 0xdf, 0x25, 0x81, 0x79, 0x8a,
-	0xfc, 0xbd, 0x89, 0xfd, 0x47, 0x82, 0x9b, 0xa8, 0xb1, 0x4a, 0xde, 0xa2,
-	0x86, 0xa5, 0x30, 0x2b, 0x62, 0xf5, 0xc5, 0xd6, 0x5d, 0x9f, 0x20, 0x4f,
-	0x1b, 0x1d, 0x15, 0x75, 0xfd, 0xfd, 0x8c, 0xf3, 0x33, 0x5d, 0x4e, 0x7a,
-	0x14, 0x9f, 0xf1, 0xae, 0xe5, 0xc0, 0xdc, 0x7f, 0xeb, 0x3c, 0x9f, 0x33,
-	0xf5, 0xd5, 0xa0, 0x85, 0xf6, 0x81, 0x41, 0xa8, 0x7d, 0x70, 0x4f, 0xa1,
-	0x38, 0x38, 0x2f, 0xa1, 0xc6, 0xc1, 0x37, 0x7c, 0x92, 0x6c, 0xb6, 0x23,
-	0x7b, 0x4d, 0x70, 0x21, 0x26, 0x1f, 0xeb, 0xf4, 0x33, 0x71, 0x57, 0xe9,
-	0x28, 0x9e, 0x81, 0xda, 0x92, 0x0c, 0x9c, 0xf3, 0x88, 0x89, 0x65, 0xa4,
-	0x03, 0xd4, 0x41, 0x38, 0xfb, 0x83, 0x55, 0xc4, 0xe5, 0x2c, 0x70, 0xcb,
-	0x54, 0xf8, 0xbe, 0xa9, 0x17, 0xf7, 0x1c, 0x54, 0x35, 0x22, 0x5e, 0x8f,
-	0x4a, 0x7e, 0x88, 0x3a, 0x4b, 0x6a, 0xf7, 0xc9, 0x8a, 0x5c, 0xf0, 0x1c,
-	0xe7, 0x48, 0x37, 0xe3, 0xda, 0xf9, 0xac, 0x21, 0xdf, 0xe0, 0x5c, 0x7e,
-	0x88, 0x18, 0xe2, 0xfd, 0x80, 0xcf, 0x16, 0x85, 0xeb, 0x6f, 0xdc, 0x67,
-	0x96, 0x90, 0x6b, 0x68, 0x0a, 0x79, 0x0f, 0x79, 0x77, 0x96, 0x71, 0xf2,
-	0x23, 0xc6, 0x4b, 0x9c, 0x1b, 0xe7, 0xe4, 0x62, 0x9e, 0x5f, 0x6b, 0x05,
-	0x7f, 0x71, 0x87, 0x41, 0xfc, 0x36, 0xfb, 0x2e, 0xe7, 0xdb, 0x2f, 0x2b,
-	0x74, 0x44, 0x82, 0x8f, 0xe6, 0xcb, 0xc8, 0xc3, 0xe7, 0xe0, 0xe3, 0x0b,
-	0x2d, 0x16, 0xf5, 0x56, 0xe5, 0xf3, 0xc9, 0xd8, 0x18, 0x1f, 0x29, 0xa3,
-	0xdf, 0x3e, 0xf8, 0xbc, 0x52, 0xce, 0x57, 0xf1, 0xe3, 0x57, 0xe0, 0xc7,
-	0x61, 0xd9, 0xcf, 0x77, 0x16, 0x1d, 0x36, 0xbc, 0x3e, 0xe6, 0x11, 0xdb,
-	0x9b, 0xda, 0xe8, 0x18, 0x5f, 0x1a, 0xf3, 0xff, 0xfd, 0x90, 0xff, 0x34,
-	0xef, 0xc9, 0x8c, 0x0a, 0x0e, 0xe2, 0xef, 0x3d, 0x7d, 0xd4, 0xf7, 0x17,
-	0x6a, 0xf1, 0x7d, 0xb6, 0xe0, 0x9e, 0x83, 0x67, 0x76, 0x38, 0xb4, 0x36,
-	0x75, 0x6c, 0xec, 0x87, 0x18, 0x7b, 0x15, 0x79, 0x84, 0x7c, 0x05, 0x77,
-	0xa6, 0x90, 0xf0, 0x9e, 0x5d, 0xa9, 0xe2, 0x03, 0x4e, 0xd0, 0xe5, 0xb4,
-	0xe4, 0x82, 0x5c, 0x70, 0x81, 0xeb, 0xb4, 0xd5, 0x4d, 0x70, 0x21, 0x05,
-	0x17, 0xe0, 0xd7, 0xd1, 0xbc, 0x59, 0xe0, 0xcc, 0x39, 0x07, 0xdf, 0x19,
-	0xf3, 0x82, 0x79, 0xc0, 0x9c, 0x78, 0xc2, 0x85, 0x2b, 0x3d, 0xc3, 0xd8,
-	0xfd, 0x2f, 0x3c, 0x78, 0x57, 0xf0, 0x80, 0xf9, 0x58, 0xe4, 0x85, 0x2e,
-	0x70, 0x48, 0xca, 0xbc, 0x50, 0xe8, 0x9c, 0xeb, 0x1b, 0xd6, 0x78, 0xa1,
-	0x8d, 0x2d, 0x68, 0xa3, 0xad, 0x70, 0xbd, 0xc3, 0xba, 0x60, 0x3f, 0xd6,
-	0xc6, 0x49, 0x7e, 0x85, 0x46, 0xd2, 0xbe, 0x6d, 0x55, 0xf9, 0x21, 0x85,
-	0x2e, 0xba, 0xa5, 0x46, 0xd2, 0x52, 0x23, 0xb0, 0x89, 0x95, 0x16, 0xe7,
-	0x7a, 0xdb, 0x0a, 0x91, 0x17, 0xba, 0x62, 0xcc, 0x98, 0x8a, 0x3b, 0x09,
-	0xeb, 0x96, 0xf3, 0xe9, 0x50, 0x1e, 0x2d, 0xef, 0xa5, 0x1d, 0x71, 0x2f,
-	0xfd, 0x8a, 0x3e, 0x9a, 0x47, 0x67, 0x90, 0x43, 0xf8, 0x5e, 0x3a, 0xa7,
-	0xf3, 0xbd, 0x14, 0xba, 0xd3, 0x87, 0xef, 0xa5, 0xc9, 0xc8, 0xbd, 0xb4,
-	0xf2, 0xe5, 0xf6, 0x93, 0xf2, 0x69, 0x15, 0x13, 0xce, 0xa9, 0x02, 0xf3,
-	0x13, 0x6a, 0xbf, 0xca, 0x86, 0xf3, 0x0d, 0x6b, 0xb9, 0xcc, 0x51, 0xa8,
-	0xb5, 0xee, 0x67, 0x15, 0xe7, 0xdf, 0xc0, 0x3c, 0xf8, 0xee, 0x9f, 0xc4,
-	0x79, 0xa3, 0xe4, 0xfc, 0x54, 0xe1, 0xd3, 0x1f, 0xe6, 0xfd, 0x1b, 0xfa,
-	0x28, 0xef, 0xab, 0x71, 0x2a, 0xde, 0x17, 0x63, 0x3e, 0x54, 0x9a, 0x38,
-	0xdb, 0x96, 0x91, 0x6b, 0x66, 0xf8, 0xbe, 0x85, 0x5c, 0xe0, 0xd5, 0x71,
-	0xef, 0x98, 0xe1, 0xb1, 0xd3, 0x0c, 0xe7, 0x4d, 0x03, 0xbc, 0x17, 0x9c,
-	0x3d, 0x12, 0xf7, 0x01, 0xac, 0x7b, 0x86, 0xab, 0xab, 0x51, 0x2e, 0xbe,
-	0x88, 0x0b, 0x45, 0xb5, 0x97, 0xaa, 0xcd, 0x19, 0x6a, 0x5b, 0x2e, 0xb1,
-	0x2e, 0x62, 0xfd, 0xa0, 0xb8, 0x8f, 0xd3, 0x2e, 0x6a, 0xb1, 0x43, 0xd4,
-	0x39, 0x77, 0x70, 0x9f, 0x4b, 0x06, 0x8f, 0xf2, 0x07, 0x0d, 0x95, 0xba,
-	0xc7, 0x3e, 0x5d, 0xac, 0xd7, 0x36, 0x6f, 0xe3, 0xed, 0xdd, 0x41, 0x15,
-	0x53, 0xee, 0xe7, 0xb6, 0x7f, 0xe0, 0xbc, 0x45, 0x1d, 0x37, 0x32, 0x67,
-	0xf5, 0xce, 0x7f, 0xff, 0x06, 0x63, 0xe1, 0x4b, 0x7b, 0x30, 0x12, 0x00,
-	0x00, 0x00 };
+	0xbd, 0x59, 0x6f, 0x70, 0x5c, 0xd5, 0x7d, 0x3d, 0x6f, 0xf7, 0xed, 0xee,
+	0x93, 0xb4, 0x92, 0x9e, 0x90, 0x0c, 0xab, 0x56, 0x8d, 0xf6, 0x59, 0x6f,
+	0xa5, 0xc5, 0xab, 0xd8, 0x6f, 0x2d, 0xb9, 0xac, 0x87, 0x37, 0xcd, 0xb3,
+	0x2c, 0x29, 0x8b, 0xec, 0xd8, 0xeb, 0x42, 0x66, 0xe4, 0x09, 0x1d, 0x0b,
+	0x59, 0xd8, 0xc2, 0x18, 0xa2, 0x12, 0x3e, 0xa8, 0x13, 0x4f, 0xbd, 0xe8,
+	0x9f, 0x85, 0xbd, 0xd2, 0x23, 0x02, 0x2c, 0x3b, 0x93, 0x0e, 0x1e, 0xf9,
+	0x8f, 0x18, 0x58, 0x6b, 0xa1, 0xfd, 0x92, 0x69, 0xc3, 0x44, 0x13, 0x1b,
+	0xec, 0x90, 0x38, 0x4e, 0xa7, 0x5f, 0xcc, 0xb4, 0x9d, 0xaa, 0x80, 0x29,
+	0x50, 0x70, 0xdc, 0xce, 0xa4, 0x63, 0x0a, 0xf5, 0xed, 0xb9, 0x6f, 0x57,
+	0x46, 0x38, 0x4e, 0x3f, 0xd6, 0x33, 0x8b, 0x76, 0xef, 0x7b, 0xf7, 0xde,
+	0xdf, 0xbd, 0xbf, 0x73, 0xce, 0xef, 0xdc, 0xcb, 0x6a, 0x1f, 0xca, 0x51,
+	0xfa, 0x57, 0xc9, 0x4f, 0xfb, 0x23, 0x43, 0x4f, 0x6f, 0x58, 0x6b, 0xad,
+	0x95, 0xbf, 0x95, 0x00, 0x54, 0xfc, 0x3f, 0xfe, 0xf3, 0x03, 0xfa, 0x72,
+	0x1c, 0xf2, 0x03, 0xcd, 0x67, 0x2f, 0xae, 0xee, 0x30, 0xa1, 0xf9, 0xed,
+	0x87, 0x5a, 0x76, 0x9b, 0x80, 0x93, 0x4f, 0x44, 0x37, 0xe3, 0x7f, 0x44,
+	0xb6, 0x4e, 0x85, 0x6c, 0xff, 0x23, 0xfb, 0x8b, 0x75, 0x6f, 0xdc, 0x67,
+	0x5c, 0x3f, 0xe1, 0x87, 0xa6, 0xdb, 0x93, 0x9a, 0xde, 0x0c, 0xad, 0x81,
+	0x7d, 0x7e, 0xd4, 0xb2, 0x2b, 0x88, 0xaa, 0xe5, 0xb1, 0x80, 0x93, 0x39,
+	0xc3, 0xda, 0x83, 0x84, 0x7e, 0x8e, 0x0b, 0x72, 0x38, 0xc7, 0x99, 0x3c,
+	0x70, 0x28, 0xa7, 0xe0, 0x2a, 0xc7, 0x1c, 0xcf, 0x6b, 0x58, 0xf2, 0x7b,
+	0xd3, 0xf5, 0x95, 0xd9, 0xc8, 0x98, 0x53, 0x07, 0x45, 0xc8, 0x44, 0xf6,
+	0x0f, 0x6c, 0x33, 0x7e, 0x08, 0xe1, 0xd4, 0x5c, 0x3b, 0x32, 0xab, 0xcf,
+	0x6a, 0xd8, 0xe9, 0x36, 0xf4, 0x69, 0x36, 0xf8, 0x8e, 0x82, 0xd4, 0x7d,
+	0x1a, 0x7a, 0x0b, 0x71, 0x64, 0x0b, 0x59, 0x38, 0x85, 0x31, 0x7e, 0x34,
+	0x84, 0xa6, 0x34, 0x6d, 0xdd, 0xd4, 0xdd, 0xf2, 0x1d, 0x84, 0xa7, 0xae,
+	0x8b, 0x6b, 0x49, 0x1d, 0x6f, 0x6f, 0x14, 0xa2, 0xd2, 0x46, 0xb6, 0xa2,
+	0x3d, 0x0b, 0xbf, 0x6d, 0x58, 0x5b, 0xfc, 0x0a, 0x3a, 0xbf, 0x6e, 0xc6,
+	0xa7, 0x94, 0x07, 0x1f, 0xf4, 0xd9, 0xd0, 0x14, 0x3b, 0xaa, 0x35, 0xe5,
+	0x1b, 0x30, 0x51, 0xd0, 0x71, 0xa8, 0x50, 0x87, 0xb1, 0x02, 0x0e, 0xf8,
+	0x37, 0x04, 0x31, 0xa7, 0xc3, 0xf9, 0x4e, 0xcb, 0x01, 0xec, 0xcb, 0x0d,
+	0x63, 0x77, 0x2e, 0x85, 0xc3, 0x05, 0x19, 0x63, 0x14, 0xa3, 0x05, 0x15,
+	0xc1, 0x29, 0x23, 0xf2, 0x73, 0xdc, 0xe9, 0x99, 0x10, 0x63, 0x56, 0x08,
+	0x23, 0x56, 0x1c, 0xe3, 0xae, 0x8f, 0xeb, 0x0c, 0x61, 0xd4, 0xbc, 0x21,
+	0x06, 0x2c, 0xc3, 0x1a, 0x87, 0x68, 0x3c, 0x6f, 0x19, 0x91, 0x4e, 0x3f,
+	0x9c, 0xef, 0x9b, 0x11, 0x8c, 0x33, 0xf6, 0x31, 0xaf, 0xdf, 0x18, 0x3a,
+	0x6f, 0xf5, 0x73, 0xd8, 0x4f, 0xc7, 0xc4, 0x57, 0xfb, 0x46, 0xc7, 0x91,
+	0x88, 0x4c, 0xc0, 0x87, 0xbe, 0xba, 0x56, 0xf6, 0x6b, 0x8a, 0x4e, 0xc0,
+	0x88, 0x73, 0x9c, 0x6c, 0xb0, 0xdd, 0xe1, 0x18, 0x59, 0xf6, 0x37, 0xa2,
+	0x67, 0x20, 0xc7, 0x6a, 0xe0, 0xef, 0x76, 0xf6, 0x57, 0xe0, 0xb3, 0x63,
+	0xd1, 0x11, 0xf6, 0x39, 0x67, 0xa9, 0x78, 0x93, 0x9f, 0x3e, 0xdd, 0x90,
+	0x99, 0x55, 0x42, 0x6c, 0x3f, 0x04, 0x3e, 0x37, 0x2b, 0x70, 0x22, 0x63,
+	0x61, 0x84, 0xeb, 0xd6, 0xd8, 0x36, 0xc9, 0xb6, 0x80, 0x69, 0x71, 0x7c,
+	0xe8, 0x9d, 0x85, 0x95, 0x98, 0x58, 0xce, 0xcd, 0xef, 0x6b, 0xe7, 0x18,
+	0x6e, 0x31, 0xa7, 0xf2, 0x9d, 0xcd, 0xee, 0x4d, 0xf1, 0x88, 0xba, 0xf2,
+	0xf9, 0xb0, 0xd2, 0xc1, 0x36, 0x47, 0x6d, 0xc0, 0x21, 0x17, 0x5a, 0xd0,
+	0xd4, 0x38, 0x8f, 0x86, 0xf7, 0x72, 0xc3, 0x4a, 0x77, 0xc1, 0x51, 0xba,
+	0xe6, 0x3b, 0x14, 0x67, 0x5e, 0x55, 0x3a, 0x67, 0x65, 0xdc, 0x42, 0x3c,
+	0x6b, 0x29, 0x8c, 0xf9, 0x07, 0x32, 0x5e, 0x27, 0xaa, 0xdc, 0x14, 0x6b,
+	0x62, 0x3e, 0x54, 0x98, 0xdd, 0xca, 0x96, 0x79, 0x21, 0xd2, 0xc9, 0xb4,
+	0xd2, 0x33, 0x0f, 0x2d, 0x6c, 0xdb, 0x5a, 0x6e, 0xea, 0x30, 0xb2, 0xab,
+	0x4c, 0x1c, 0x77, 0xa3, 0xb8, 0x64, 0xf9, 0x70, 0x62, 0x55, 0x19, 0x54,
+	0x53, 0xe1, 0x07, 0xe1, 0xcb, 0x16, 0xd4, 0x2a, 0x7e, 0xbf, 0xb6, 0x43,
+	0xc5, 0x58, 0x7b, 0x8f, 0xd2, 0xc9, 0x3e, 0x01, 0xe6, 0xf9, 0x74, 0x2e,
+	0x8d, 0x30, 0xb1, 0x53, 0x61, 0xc7, 0x22, 0x79, 0xee, 0xcd, 0xdb, 0x56,
+	0x2c, 0xfe, 0xb8, 0xc4, 0x63, 0x8d, 0x11, 0x91, 0x7b, 0x53, 0x69, 0xc7,
+	0xe2, 0x67, 0xb9, 0x0f, 0x7e, 0x53, 0xc5, 0xaf, 0xac, 0x00, 0x16, 0x77,
+	0x58, 0xcc, 0xa9, 0x8e, 0x20, 0xdb, 0xcf, 0x78, 0xed, 0xf2, 0x37, 0xf4,
+	0xae, 0xaf, 0xec, 0x43, 0x71, 0x0f, 0x46, 0xdd, 0x26, 0xc6, 0x5c, 0xdc,
+	0x83, 0xed, 0x5c, 0xef, 0xbf, 0x06, 0xe4, 0xd7, 0xaf, 0xdd, 0x6a, 0xdb,
+	0xc9, 0x38, 0x7d, 0xb6, 0xb9, 0xb8, 0xda, 0x5f, 0x0f, 0xd4, 0xb6, 0xe3,
+	0x30, 0x73, 0xdc, 0x99, 0xbc, 0x1b, 0x59, 0xef, 0x79, 0x9d, 0xbe, 0x65,
+	0xb6, 0x16, 0x7d, 0xab, 0xbc, 0x7d, 0xd3, 0xb7, 0xcd, 0x0a, 0xf1, 0x66,
+	0x32, 0x88, 0xb3, 0xe6, 0x48, 0xa4, 0x12, 0x59, 0xcb, 0xcf, 0x7c, 0x5f,
+	0xe0, 0xfc, 0xf9, 0xa4, 0x1f, 0x27, 0x93, 0x27, 0x90, 0xad, 0x01, 0xe6,
+	0x72, 0x92, 0x57, 0xc6, 0xe2, 0x05, 0xfe, 0xd7, 0x57, 0x90, 0xeb, 0xb3,
+	0xb8, 0x3e, 0x05, 0x67, 0x4c, 0x89, 0x69, 0x4b, 0x6b, 0x26, 0xbf, 0xf6,
+	0x71, 0x3f, 0xeb, 0xdb, 0xc3, 0xc4, 0x27, 0xf0, 0x6e, 0x6e, 0x00, 0x3b,
+	0x8b, 0xb1, 0xe0, 0x46, 0x8e, 0xc2, 0xd2, 0x96, 0xc6, 0x89, 0xe2, 0x6f,
+	0x72, 0x3c, 0xad, 0x75, 0xe4, 0x8c, 0x4c, 0x1a, 0x89, 0x8b, 0x1d, 0x8a,
+	0xec, 0x9f, 0xd6, 0xd6, 0xe4, 0x83, 0x88, 0xd6, 0x16, 0x9f, 0x57, 0xd8,
+	0x5b, 0xb5, 0xc7, 0xa7, 0x14, 0xec, 0x8d, 0xc9, 0x67, 0x5b, 0xb5, 0x96,
+	0x3c, 0xb4, 0x4a, 0x7b, 0x48, 0x3b, 0x3b, 0x65, 0xf4, 0xbd, 0xac, 0x24,
+	0xa2, 0x53, 0x5e, 0x9f, 0x21, 0xad, 0x35, 0x1f, 0xe2, 0x7a, 0xe2, 0xcc,
+	0x09, 0xb4, 0x2a, 0xfb, 0x69, 0xed, 0x57, 0x7c, 0x70, 0xd1, 0xeb, 0xf3,
+	0xb4, 0x16, 0xcf, 0xcb, 0x76, 0xc3, 0x8a, 0x2a, 0x21, 0xdc, 0x9b, 0xd4,
+	0xb0, 0xa6, 0x45, 0x34, 0x76, 0x25, 0x8d, 0xc5, 0x2e, 0x7f, 0x04, 0xc7,
+	0xc9, 0x05, 0xe2, 0xce, 0xf9, 0xc3, 0x96, 0x31, 0x74, 0x15, 0xfc, 0x88,
+	0xd6, 0x38, 0x38, 0xe2, 0x86, 0xf0, 0x33, 0xe2, 0xbf, 0xdb, 0xd2, 0x31,
+	0xe6, 0x1a, 0xf1, 0x5f, 0x20, 0x91, 0x3a, 0xc5, 0x9c, 0x2d, 0x91, 0x03,
+	0x47, 0x0a, 0x4d, 0xf1, 0x53, 0x30, 0x06, 0xbb, 0xc8, 0x01, 0xad, 0x5d,
+	0xc6, 0x00, 0x5d, 0xb5, 0xc9, 0x9d, 0x42, 0x03, 0x72, 0xe4, 0x43, 0x97,
+	0xc7, 0xab, 0x61, 0xa5, 0xb3, 0xf0, 0x4b, 0x6a, 0x6b, 0x37, 0xf1, 0x85,
+	0xea, 0x88, 0x19, 0x44, 0xaa, 0x36, 0x8a, 0xf3, 0xc4, 0x4a, 0xb6, 0xae,
+	0x8c, 0xb9, 0x94, 0xf9, 0x7c, 0x87, 0xcf, 0x7b, 0x94, 0xcd, 0xf3, 0x51,
+	0xfc, 0xcc, 0xfa, 0x42, 0x38, 0x75, 0x95, 0x6c, 0x0b, 0xac, 0x68, 0xd7,
+	0x70, 0xf5, 0x85, 0x72, 0x7c, 0xfc, 0x42, 0x18, 0x9f, 0xbd, 0x40, 0x7e,
+	0xbb, 0x68, 0x2f, 0x87, 0x10, 0xa9, 0x36, 0x21, 0x0a, 0x56, 0x2b, 0xde,
+	0xab, 0x89, 0x45, 0xaf, 0x40, 0x6a, 0xa3, 0xa3, 0xed, 0xce, 0x19, 0x43,
+	0x83, 0x48, 0x38, 0xe7, 0xbc, 0xbd, 0x70, 0xb4, 0xb5, 0xf9, 0xf3, 0x02,
+	0x3b, 0x8a, 0x7b, 0x11, 0xb4, 0x3b, 0xb5, 0xb7, 0x98, 0x9b, 0xcb, 0x5e,
+	0x6e, 0x3a, 0xb5, 0x75, 0xf9, 0xfb, 0xfd, 0x28, 0x2f, 0x3e, 0x53, 0xed,
+	0x8c, 0x36, 0x96, 0x33, 0x7a, 0x27, 0xb9, 0xbe, 0x01, 0xaf, 0x6f, 0x46,
+	0x4b, 0x70, 0xef, 0x97, 0x4a, 0xb9, 0xa9, 0xb4, 0x1f, 0xe2, 0x3e, 0x33,
+	0xf7, 0xde, 0x3e, 0x3e, 0xc4, 0x3d, 0x96, 0xf3, 0x0d, 0xdf, 0x36, 0xdf,
+	0x30, 0xe7, 0x7b, 0x79, 0xc5, 0x7c, 0x07, 0x56, 0xcc, 0x77, 0x60, 0xc5,
+	0x7c, 0x29, 0x72, 0xf5, 0x1f, 0xc4, 0x48, 0x5d, 0x71, 0x6c, 0xd5, 0x1e,
+	0xbc, 0x6d, 0xee, 0x41, 0xce, 0x7d, 0x54, 0x2c, 0x65, 0x8a, 0xe3, 0x54,
+	0xda, 0xfb, 0x57, 0xcc, 0xbd, 0x9f, 0x73, 0x2f, 0x8f, 0xa3, 0x53, 0x8b,
+	0x84, 0xd8, 0x66, 0x09, 0xa1, 0xda, 0xa6, 0xde, 0x89, 0xe6, 0x4c, 0x27,
+	0xb1, 0x53, 0x8e, 0xc4, 0xa2, 0x0f, 0xe6, 0x70, 0xbd, 0x3f, 0x80, 0xa5,
+	0x9a, 0x65, 0x6e, 0x54, 0x96, 0xfe, 0xbe, 0xa4, 0x80, 0x5a, 0xff, 0x6a,
+	0xae, 0x9a, 0x63, 0xc4, 0xf4, 0x01, 0x45, 0x88, 0x73, 0x1b, 0x13, 0x83,
+	0x7e, 0x24, 0xfa, 0xaa, 0x60, 0x12, 0x43, 0x81, 0x12, 0x17, 0x56, 0xf6,
+	0x79, 0xd9, 0xeb, 0x53, 0xf0, 0xfa, 0x08, 0xf1, 0xee, 0x86, 0x0f, 0xc5,
+	0x1b, 0x2d, 0x75, 0xf8, 0x29, 0x39, 0xf9, 0x5a, 0x61, 0x59, 0x57, 0xa4,
+	0x6e, 0xc0, 0x77, 0xce, 0x0a, 0x32, 0xa6, 0x91, 0x7d, 0xc1, 0xaf, 0xf4,
+	0x27, 0x60, 0x4c, 0xd9, 0xe6, 0xc7, 0x2b, 0x49, 0x3c, 0x52, 0x0e, 0xa3,
+	0xf7, 0xb0, 0x92, 0x4d, 0x57, 0xc0, 0x70, 0xd6, 0x28, 0xd9, 0x94, 0x06,
+	0xc9, 0x1b, 0xb5, 0xe9, 0xb4, 0x69, 0x64, 0xaf, 0xf2, 0x65, 0x75, 0xfa,
+	0x4e, 0x31, 0xa8, 0x1c, 0x23, 0x8c, 0x27, 0xdd, 0x0b, 0x58, 0x0c, 0x34,
+	0x50, 0x9f, 0xa5, 0x76, 0x72, 0xe0, 0x05, 0x8d, 0x35, 0x2d, 0x44, 0x22,
+	0xaa, 0x38, 0xe8, 0xfa, 0xce, 0x37, 0x42, 0x20, 0xd8, 0x16, 0xc0, 0x3b,
+	0xe6, 0xa8, 0x55, 0x8f, 0x4d, 0xb8, 0xdc, 0xca, 0x3d, 0x58, 0xa5, 0x22,
+	0x32, 0xb7, 0x72, 0xac, 0x08, 0xc7, 0xfa, 0xb3, 0x10, 0xaa, 0xea, 0xa0,
+	0x36, 0xab, 0xd8, 0xeb, 0x6a, 0x4a, 0x97, 0x2b, 0xb1, 0x6b, 0x46, 0x4e,
+	0xe1, 0x14, 0xb5, 0x82, 0x35, 0xec, 0x8c, 0xaa, 0x6c, 0x99, 0x0d, 0xa1,
+	0x7c, 0xe6, 0x13, 0xf1, 0x18, 0xb5, 0x2f, 0xbd, 0x41, 0x08, 0x33, 0x19,
+	0x82, 0xc6, 0x79, 0x86, 0xc9, 0xe7, 0xea, 0xb6, 0x5a, 0x5c, 0xfb, 0x3a,
+	0xb5, 0xe9, 0xdb, 0x21, 0xf8, 0x67, 0x42, 0x08, 0xce, 0x28, 0x78, 0xa7,
+	0x3d, 0x84, 0xfa, 0x39, 0xf9, 0x5b, 0x41, 0xa3, 0x79, 0x14, 0x07, 0x75,
+	0x3f, 0x63, 0xfc, 0x2b, 0xf4, 0xeb, 0x0d, 0x98, 0xa4, 0x36, 0x3f, 0xea,
+	0x6a, 0xa8, 0x3a, 0x4a, 0x2d, 0xb0, 0x85, 0x38, 0x49, 0xfc, 0x1f, 0x64,
+	0x8c, 0x32, 0xde, 0x0b, 0x56, 0x36, 0x1a, 0x42, 0x00, 0xc1, 0x39, 0x23,
+	0x3d, 0xc9, 0xe8, 0x52, 0x53, 0xaa, 0xb2, 0x7d, 0x96, 0xb5, 0xd7, 0x36,
+	0x7b, 0xeb, 0xfd, 0x42, 0x7c, 0x9a, 0x6c, 0xea, 0x5b, 0xa0, 0x06, 0x8f,
+	0xc4, 0x62, 0x99, 0x7e, 0x05, 0x58, 0x73, 0x96, 0x76, 0x64, 0xe6, 0xbf,
+	0x44, 0x98, 0xe3, 0x1c, 0xd9, 0x20, 0x30, 0x6e, 0x65, 0x23, 0x01, 0x18,
+	0x37, 0x86, 0x50, 0x87, 0x0f, 0x9e, 0x17, 0x42, 0xb4, 0x57, 0xe3, 0x1d,
+	0xcb, 0x18, 0x34, 0xfd, 0x02, 0x3f, 0x4e, 0x66, 0x87, 0x22, 0x30, 0x86,
+	0x7f, 0xad, 0x44, 0xf1, 0xf1, 0x94, 0x91, 0xbe, 0xa8, 0x04, 0x51, 0x39,
+	0x67, 0xea, 0x5b, 0x94, 0x30, 0xca, 0x17, 0xc2, 0x58, 0x7d, 0x36, 0x88,
+	0xc0, 0x4c, 0x18, 0xc1, 0x69, 0xf3, 0xe2, 0x2e, 0x78, 0xe3, 0x2c, 0x0e,
+	0xa1, 0x19, 0xd5, 0xb3, 0x66, 0xf4, 0x5f, 0x20, 0xb1, 0x1d, 0x86, 0xba,
+	0x10, 0x45, 0x7d, 0xc1, 0x44, 0x35, 0xf3, 0x7d, 0xf9, 0xac, 0xcc, 0xb3,
+	0x8e, 0xb0, 0xe9, 0xe3, 0xda, 0x1c, 0x65, 0xab, 0x57, 0x37, 0x3a, 0xf9,
+	0xe9, 0x56, 0x3a, 0xe6, 0xe5, 0x9e, 0x29, 0x28, 0xe3, 0xb3, 0x8b, 0xd6,
+	0x4d, 0xb1, 0x2f, 0x26, 0xeb, 0x44, 0x19, 0x02, 0x76, 0x8f, 0xf2, 0xc0,
+	0x3c, 0x8b, 0x90, 0xa7, 0xef, 0x65, 0x4a, 0xc0, 0x2e, 0x6a, 0xfb, 0x25,
+	0x6a, 0xfb, 0x89, 0x92, 0xb6, 0x57, 0x51, 0xdb, 0x17, 0xfe, 0x4f, 0x6d,
+	0x67, 0xbd, 0x9f, 0xf1, 0xe1, 0xbc, 0x19, 0xc2, 0x71, 0xab, 0x69, 0xb1,
+	0x1e, 0x21, 0x54, 0xb7, 0xe9, 0xa8, 0x5e, 0xb0, 0xf0, 0x1c, 0xf7, 0x16,
+	0x77, 0x15, 0xf5, 0xfd, 0x9b, 0x52, 0xf3, 0x4b, 0x5e, 0xed, 0x71, 0x77,
+	0x59, 0x13, 0xc2, 0xd4, 0x2a, 0x55, 0xe9, 0xa1, 0x9e, 0x3f, 0x90, 0xbc,
+	0x29, 0xe2, 0x31, 0x23, 0x4e, 0xce, 0xde, 0x38, 0x89, 0xa2, 0x46, 0xc4,
+	0xa8, 0x97, 0x4b, 0xb5, 0x71, 0x1c, 0x73, 0x65, 0x4d, 0xeb, 0x64, 0x4d,
+	0x53, 0x30, 0x12, 0x2b, 0x6a, 0xc4, 0xea, 0xbc, 0x6c, 0xd7, 0x51, 0x4f,
+	0x9d, 0x5c, 0xd7, 0x16, 0xc1, 0x31, 0x6a, 0xa4, 0x4b, 0x9f, 0xb3, 0x9d,
+	0xe3, 0x6d, 0x9b, 0x35, 0xb2, 0xdb, 0x99, 0x9f, 0xf3, 0xc4, 0xc5, 0x14,
+	0xab, 0xc3, 0x89, 0x1a, 0x6a, 0x67, 0x73, 0x08, 0x13, 0xd4, 0xcb, 0xf3,
+	0xf4, 0x10, 0x2f, 0xb1, 0xdf, 0xb8, 0x6b, 0x44, 0x5f, 0x22, 0xaf, 0xc7,
+	0x4b, 0x9a, 0xf9, 0x12, 0x7d, 0xc3, 0x38, 0xf3, 0xf4, 0x53, 0x3e, 0x7b,
+	0xcd, 0x35, 0x1c, 0xe9, 0x1f, 0xfc, 0x9e, 0x7f, 0x30, 0xe2, 0x7e, 0x45,
+	0x7a, 0x88, 0x08, 0xde, 0x68, 0x91, 0x58, 0x24, 0xc6, 0x6f, 0xe9, 0xa7,
+	0xaa, 0x7c, 0x6b, 0xf6, 0xba, 0xc8, 0xc7, 0xca, 0x55, 0xc9, 0xbf, 0xb1,
+	0xa4, 0xc4, 0x93, 0x10, 0x65, 0x76, 0x98, 0x5e, 0xcb, 0x8c, 0x7f, 0x84,
+	0x18, 0x71, 0x1b, 0xe1, 0xb3, 0x30, 0xfc, 0x67, 0xb7, 0xa8, 0x9e, 0x8f,
+	0x5d, 0x90, 0x7e, 0x8b, 0x79, 0x9a, 0x32, 0x7b, 0xa7, 0x94, 0x58, 0x66,
+	0x40, 0x91, 0xcf, 0x75, 0x94, 0x9f, 0x5d, 0x22, 0x77, 0x23, 0xe4, 0x6e,
+	0x1d, 0x5e, 0xbf, 0x8d, 0xbf, 0xd4, 0x55, 0xdf, 0x00, 0xf9, 0x9b, 0xad,
+	0x1b, 0xe9, 0xf7, 0x7f, 0x85, 0x7b, 0x87, 0x24, 0x7f, 0xd9, 0xe6, 0xc7,
+	0xb3, 0x49, 0xec, 0x2c, 0x83, 0x91, 0x79, 0x4c, 0xc9, 0x3a, 0xe4, 0x71,
+	0xaa, 0x4c, 0xc9, 0xd2, 0x31, 0x7d, 0xc9, 0xdf, 0x37, 0xf9, 0xb6, 0x9f,
+	0xfc, 0xed, 0xab, 0xbb, 0x9d, 0xbf, 0x47, 0x38, 0x86, 0x8a, 0x27, 0xdc,
+	0xe3, 0x98, 0x0b, 0x04, 0x11, 0x99, 0x09, 0x20, 0x34, 0xa3, 0xa2, 0x92,
+	0x5c, 0x09, 0xdb, 0xd9, 0x78, 0x08, 0x46, 0xfa, 0x35, 0x44, 0x90, 0x98,
+	0xd2, 0xf0, 0xe7, 0x2d, 0x01, 0x9c, 0x89, 0x19, 0x99, 0xfd, 0x4a, 0x84,
+	0x58, 0x1f, 0x61, 0x44, 0x46, 0x34, 0xea, 0x2b, 0xf2, 0x35, 0xd0, 0x1c,
+	0x84, 0x36, 0x23, 0xb9, 0x2e, 0x0e, 0xfa, 0xec, 0x6c, 0x54, 0x23, 0x46,
+	0x7f, 0x40, 0x6c, 0x5c, 0x99, 0x12, 0x62, 0x73, 0xbb, 0x79, 0xf1, 0x3d,
+	0xbf, 0x41, 0xdd, 0x53, 0x89, 0xd3, 0xe2, 0xf8, 0x15, 0x33, 0x1a, 0x82,
+	0x47, 0xbd, 0xf1, 0x6f, 0xbc, 0xce, 0x28, 0x3e, 0x75, 0x55, 0x65, 0x2b,
+	0x71, 0x40, 0x6e, 0x45, 0xe6, 0xa9, 0x7d, 0x87, 0x93, 0x46, 0x7a, 0x8b,
+	0xd2, 0xe4, 0x34, 0xf3, 0xbb, 0x2f, 0x19, 0x8b, 0xf6, 0xf3, 0x9d, 0xf7,
+	0x0b, 0x45, 0x0e, 0xd7, 0x9b, 0xbb, 0xf1, 0x17, 0xe4, 0x70, 0x95, 0xf9,
+	0x14, 0x9e, 0xf4, 0xf4, 0x88, 0x38, 0x98, 0x2e, 0x27, 0xb7, 0x1d, 0x65,
+	0x17, 0x71, 0xbf, 0x73, 0x9e, 0xba, 0x32, 0xd3, 0xee, 0x69, 0x51, 0xc8,
+	0xec, 0x54, 0x7a, 0xe7, 0xbb, 0x3d, 0x0f, 0xb5, 0x7d, 0xd6, 0x87, 0xd7,
+	0xad, 0x4d, 0xf4, 0x2b, 0x69, 0x65, 0xfb, 0xbc, 0xc4, 0x7c, 0x8f, 0xf2,
+	0x4d, 0xe2, 0x3f, 0x7a, 0x97, 0x8a, 0x39, 0x6b, 0x93, 0x12, 0xf4, 0xf0,
+	0x1f, 0x80, 0x93, 0x29, 0x62, 0xdf, 0x6f, 0xc7, 0xac, 0x73, 0x2b, 0xb0,
+	0xdf, 0x7d, 0x07, 0x5f, 0x23, 0xf5, 0x03, 0x45, 0x2d, 0xd7, 0x3b, 0x99,
+	0xaf, 0x67, 0x4a, 0x18, 0x7f, 0x92, 0xed, 0x81, 0x19, 0x68, 0xe5, 0xc4,
+	0x71, 0xcf, 0x54, 0x18, 0xd3, 0x1e, 0x56, 0x04, 0x5e, 0x65, 0x4d, 0xc8,
+	0x27, 0x0d, 0x6b, 0xbf, 0x62, 0xa4, 0xbb, 0x95, 0x44, 0x76, 0x4d, 0xa9,
+	0x1e, 0xde, 0xcb, 0x9a, 0x86, 0xbb, 0xa8, 0x0b, 0x16, 0xb4, 0x10, 0xf1,
+	0xfd, 0x6f, 0xac, 0x4f, 0xff, 0x51, 0xaa, 0x87, 0xc9, 0x7c, 0x39, 0xaa,
+	0x5b, 0xa8, 0xef, 0xc4, 0x73, 0x97, 0xc4, 0x33, 0x3d, 0xc4, 0x18, 0xeb,
+	0xff, 0x4e, 0xe2, 0x79, 0x75, 0x9b, 0x91, 0xed, 0xa4, 0x77, 0xf6, 0xad,
+	0x8f, 0x10, 0xab, 0x71, 0xfa, 0xd5, 0x31, 0x74, 0x70, 0xae, 0xf4, 0xac,
+	0x11, 0xe9, 0x20, 0x07, 0x54, 0xf6, 0x79, 0x89, 0x7d, 0x96, 0x6a, 0xa5,
+	0xaf, 0x0e, 0xe1, 0x59, 0xf6, 0x31, 0x93, 0x8e, 0xa7, 0x15, 0x92, 0x03,
+	0x13, 0x48, 0x64, 0x24, 0x07, 0x9c, 0x55, 0xad, 0xf4, 0xf8, 0x92, 0x03,
+	0xc4, 0xa0, 0x4b, 0x0c, 0x16, 0x79, 0x30, 0x28, 0x79, 0x50, 0x45, 0x0f,
+	0xb1, 0x40, 0x0f, 0x51, 0x61, 0x47, 0xc9, 0x01, 0xc9, 0x89, 0xa2, 0x8f,
+	0xe8, 0x2c, 0xf1, 0x60, 0x8b, 0x37, 0x9f, 0x4a, 0xed, 0x0b, 0xa3, 0x69,
+	0xda, 0xd0, 0x55, 0xe5, 0x3f, 0xc5, 0x2e, 0xd3, 0x5c, 0xdc, 0x4b, 0x2f,
+	0xf0, 0x59, 0x5b, 0x8c, 0x79, 0x0f, 0x63, 0xdd, 0x42, 0x79, 0x40, 0xe2,
+	0xbc, 0x7e, 0x3a, 0x8c, 0xea, 0x69, 0xc9, 0x83, 0xec, 0x24, 0xf5, 0x6f,
+	0xc8, 0xf2, 0xfd, 0x13, 0xf1, 0x1f, 0x25, 0x2e, 0x54, 0xa5, 0x8b, 0x63,
+	0x54, 0xcd, 0xe8, 0x68, 0x9d, 0x36, 0x06, 0x17, 0x70, 0x4d, 0xbc, 0x1a,
+	0x33, 0x33, 0x87, 0x98, 0xff, 0x3d, 0xc9, 0x18, 0xf7, 0x4a, 0xc7, 0xbd,
+	0xb7, 0xc6, 0xf0, 0x38, 0xe1, 0xf4, 0x5b, 0xe1, 0x92, 0xaf, 0xd6, 0xd0,
+	0xef, 0x02, 0x7b, 0x5c, 0x1a, 0x5b, 0xd3, 0xb7, 0x36, 0x88, 0xeb, 0x38,
+	0x49, 0xf4, 0x0f, 0xe8, 0x0e, 0xf3, 0x1f, 0xc2, 0xde, 0xd2, 0x3b, 0x45,
+	0xbf, 0xfd, 0xe3, 0xd2, 0x79, 0xf2, 0x17, 0xfe, 0xe2, 0xdf, 0xbf, 0x55,
+	0x97, 0xcf, 0x97, 0xfd, 0xc4, 0xe0, 0x66, 0x62, 0xb0, 0x9b, 0x39, 0xda,
+	0x6b, 0x91, 0xdf, 0xcc, 0x67, 0x56, 0x0d, 0x51, 0x0f, 0x9b, 0xfa, 0x2a,
+	0xa9, 0x6b, 0x87, 0xa9, 0x51, 0x3f, 0x37, 0xcb, 0xe9, 0xb7, 0x1d, 0xfa,
+	0xed, 0x0e, 0x6a, 0x68, 0x27, 0xf5, 0x53, 0x62, 0x2b, 0x4d, 0x1c, 0x69,
+	0x4a, 0x9a, 0x1e, 0x36, 0x90, 0xa4, 0xd7, 0xae, 0x5b, 0xf6, 0xda, 0x32,
+	0x4e, 0xe9, 0xaf, 0x8d, 0xb8, 0x2c, 0xb5, 0x4f, 0x32, 0x0f, 0x8b, 0x35,
+	0x9b, 0xa0, 0xda, 0x9b, 0x14, 0xd5, 0x96, 0xe7, 0x09, 0x15, 0xdf, 0xa5,
+	0xd6, 0x2e, 0xed, 0x90, 0xe7, 0x0a, 0xae, 0x8b, 0x6d, 0x11, 0x33, 0x16,
+	0x3d, 0x4e, 0x5c, 0x1d, 0xfb, 0x9d, 0x73, 0x46, 0x11, 0x6f, 0xa3, 0xae,
+	0x7a, 0xcb, 0x33, 0x4b, 0x7d, 0xd8, 0x74, 0x0b, 0x6f, 0x1a, 0x9e, 0x68,
+	0x89, 0x12, 0x8f, 0x12, 0x6b, 0x1a, 0xf2, 0x2f, 0x96, 0xe3, 0xd5, 0x17,
+	0xc3, 0x78, 0xe5, 0x45, 0x21, 0xc6, 0x93, 0xe0, 0x69, 0x46, 0x6a, 0xec,
+	0x46, 0xbc, 0xac, 0xc7, 0xa2, 0xcf, 0x7a, 0x9e, 0xd5, 0xa1, 0x67, 0x35,
+	0x06, 0x2f, 0xe0, 0x26, 0xf5, 0x4b, 0x72, 0x3a, 0x41, 0xbe, 0x15, 0xb1,
+	0xe8, 0x79, 0xdb, 0x1a, 0x0d, 0x57, 0x88, 0xbf, 0x6a, 0xe2, 0xef, 0x37,
+	0xd4, 0xdd, 0x6b, 0x25, 0xdd, 0x5d, 0x9b, 0x27, 0x1f, 0xdb, 0x42, 0xe8,
+	0x96, 0x6b, 0x21, 0x0e, 0x47, 0x6f, 0xe1, 0x50, 0x88, 0x0f, 0xb8, 0xe7,
+	0x17, 0x2c, 0x23, 0xbe, 0x99, 0x78, 0x9c, 0xb3, 0x0c, 0xa7, 0x83, 0xde,
+	0x75, 0xd4, 0xc3, 0x24, 0xf5, 0x37, 0x26, 0x71, 0x49, 0x1c, 0x32, 0x27,
+	0x87, 0xd9, 0xe7, 0x3c, 0xfb, 0x4c, 0x94, 0xbc, 0xeb, 0xdb, 0x48, 0xa4,
+	0xa5, 0x77, 0x8d, 0x12, 0x83, 0x87, 0x3d, 0xef, 0x2a, 0xbd, 0xaa, 0xf4,
+	0xa9, 0x32, 0xce, 0x76, 0x2f, 0xce, 0xae, 0x5b, 0x38, 0xa4, 0x86, 0xd5,
+	0x48, 0xfc, 0x7d, 0x03, 0x13, 0xcf, 0x57, 0xa1, 0xda, 0xbc, 0x07, 0x97,
+	0x33, 0xdf, 0x50, 0x23, 0x26, 0xf4, 0x7a, 0xbb, 0x88, 0xc7, 0x9d, 0x85,
+	0x14, 0x5c, 0xf7, 0x2d, 0xe1, 0xd6, 0x19, 0xce, 0x05, 0xcf, 0x7f, 0x0e,
+	0xb2, 0xd6, 0xdc, 0x14, 0xbe, 0x98, 0x71, 0xb1, 0x9f, 0x1e, 0xac, 0xc9,
+	0x5f, 0xf4, 0x72, 0x1b, 0xf3, 0xbf, 0x14, 0xa8, 0x2d, 0xae, 0x53, 0xa5,
+	0x7f, 0x1b, 0x23, 0xe7, 0xc6, 0xcd, 0xa2, 0x97, 0x8b, 0xe5, 0xaf, 0x06,
+	0xa4, 0xa6, 0xfb, 0xda, 0xe4, 0xb8, 0x69, 0x6a, 0xc8, 0xf2, 0xd8, 0x5f,
+	0xea, 0xf2, 0x18, 0x31, 0x38, 0x2a, 0x7d, 0x15, 0x7d, 0x09, 0xcf, 0xe5,
+	0x2b, 0x34, 0x75, 0xd8, 0x0f, 0x53, 0xb6, 0x39, 0xca, 0x03, 0x5c, 0x83,
+	0x66, 0x0e, 0x2b, 0x69, 0x9e, 0x3b, 0x0f, 0x11, 0x5f, 0xdd, 0xac, 0xc3,
+	0x57, 0xad, 0x66, 0x72, 0x98, 0xf5, 0x89, 0xb5, 0xf8, 0xb0, 0xb9, 0x7c,
+	0x7e, 0x93, 0x35, 0x99, 0x35, 0xcc, 0xad, 0x64, 0xfd, 0xee, 0x61, 0xcd,
+	0xe6, 0x28, 0xcc, 0xe9, 0x67, 0x31, 0xd1, 0xb8, 0xb6, 0xcd, 0x18, 0xdc,
+	0xe6, 0x0f, 0x21, 0x47, 0xbc, 0x1f, 0x63, 0x1d, 0x72, 0xb9, 0xa7, 0xd3,
+	0x05, 0x23, 0x95, 0xc5, 0x18, 0xb6, 0x71, 0x4f, 0x79, 0xde, 0x71, 0xfe,
+	0x2e, 0x56, 0x3c, 0x0f, 0xef, 0x65, 0x7d, 0x9b, 0x2c, 0x71, 0xfb, 0x43,
+	0x24, 0x2c, 0xc9, 0xed, 0x45, 0xd6, 0xb7, 0x49, 0x8f, 0xdb, 0x46, 0x4a,
+	0xf2, 0xb9, 0xac, 0x54, 0xd7, 0x3e, 0x82, 0xe4, 0xf0, 0xed, 0x35, 0x4d,
+	0xe2, 0xd9, 0x0e, 0x4a, 0x1f, 0xeb, 0xba, 0xb2, 0x26, 0xc9, 0x5a, 0xb4,
+	0x5c, 0x97, 0x34, 0x79, 0x77, 0x90, 0x69, 0x9c, 0x3a, 0x28, 0x7c, 0xc5,
+	0xfb, 0x87, 0x8b, 0xef, 0xfa, 0xc3, 0xa9, 0xd4, 0x7d, 0xc8, 0x44, 0xce,
+	0x6a, 0xd8, 0xe1, 0x36, 0xf4, 0x85, 0x6c, 0xf0, 0x1d, 0x05, 0xd6, 0x1f,
+	0x6b, 0xc8, 0xdc, 0x76, 0xff, 0xf0, 0x41, 0x4e, 0xd3, 0xaa, 0xa7, 0xee,
+	0x96, 0xef, 0xe0, 0x93, 0xdc, 0x1d, 0xef, 0x1f, 0xd2, 0xbf, 0xef, 0xfe,
+	0xe1, 0x59, 0xf2, 0x63, 0xa2, 0x78, 0xff, 0xe0, 0x7c, 0xa7, 0xc5, 0x8f,
+	0xb9, 0x3a, 0x1c, 0x78, 0xaf, 0x5d, 0xc5, 0xd5, 0x9c, 0x11, 0x79, 0x19,
+	0x07, 0x30, 0xe0, 0xdd, 0x35, 0xf0, 0xcc, 0x6f, 0x0f, 0xe1, 0xd7, 0xed,
+	0xf2, 0xae, 0x21, 0x25, 0xd7, 0x38, 0xc9, 0xe5, 0x43, 0xa3, 0xde, 0x6c,
+	0x61, 0x2d, 0xd8, 0xb7, 0x51, 0xc1, 0x03, 0xc9, 0x7b, 0x3c, 0x6c, 0x4f,
+	0x16, 0x8c, 0x74, 0x94, 0xcf, 0xd6, 0x4d, 0xc9, 0x1a, 0xf9, 0x30, 0xcf,
+	0x86, 0xd0, 0x1a, 0xed, 0x5e, 0x4d, 0xb8, 0x4d, 0x91, 0x0f, 0x15, 0xc3,
+	0x39, 0x09, 0x79, 0x1f, 0x90, 0xb8, 0xe8, 0x57, 0x8c, 0xc5, 0x77, 0xfd,
+	0x46, 0xaa, 0xde, 0xc3, 0xcc, 0xc3, 0x3c, 0xa7, 0xc9, 0xbf, 0xbd, 0xf2,
+	0x8c, 0x87, 0x6d, 0x1c, 0xf3, 0xd2, 0x46, 0x79, 0xee, 0xfc, 0x54, 0x64,
+	0x57, 0x19, 0xce, 0x92, 0xa2, 0x31, 0x37, 0xa0, 0x3e, 0x49, 0x0d, 0x7f,
+	0x98, 0x1a, 0x2e, 0xcf, 0x08, 0xbd, 0x3c, 0x23, 0x34, 0x2d, 0xc6, 0xfd,
+	0x46, 0xe6, 0x06, 0xf5, 0x8e, 0x63, 0xf6, 0xf5, 0x2a, 0x46, 0xef, 0x02,
+	0xf5, 0x7f, 0xbf, 0x52, 0x1c, 0x73, 0x4d, 0x69, 0xcc, 0x7b, 0xf3, 0x9a,
+	0xb2, 0xd9, 0x05, 0x75, 0x07, 0xd1, 0x3d, 0x16, 0xb5, 0xa3, 0x50, 0x4e,
+	0x8e, 0x99, 0x72, 0xcd, 0x8c, 0xad, 0x95, 0xb1, 0x29, 0xf8, 0xb0, 0x45,
+	0xbe, 0xdb, 0x2a, 0xe3, 0x70, 0x2a, 0xec, 0x14, 0xb5, 0xf7, 0xb9, 0x60,
+	0x49, 0xbf, 0x7c, 0xfd, 0xd6, 0x2a, 0x38, 0x75, 0xa8, 0x0e, 0x98, 0xb5,
+	0x18, 0xd7, 0x51, 0x19, 0x36, 0x9b, 0x91, 0xd3, 0x83, 0xe8, 0xb7, 0x7e,
+	0x2b, 0xa8, 0x93, 0x7c, 0x1f, 0x78, 0xec, 0x79, 0x9e, 0xd7, 0xcd, 0xeb,
+	0x88, 0x25, 0x9f, 0xc6, 0x19, 0x7d, 0x08, 0xe5, 0xac, 0xa5, 0xaf, 0x78,
+	0x7a, 0x62, 0x13, 0xcf, 0x0a, 0x31, 0x64, 0xcb, 0x5a, 0x77, 0xdb, 0xd8,
+	0xf2, 0xfe, 0xe1, 0x7d, 0x91, 0x2d, 0x8e, 0xe1, 0xec, 0xb1, 0x32, 0x8c,
+	0xeb, 0x4b, 0xdd, 0xdd, 0x47, 0xdd, 0xa5, 0xb7, 0xfc, 0x5a, 0x39, 0x75,
+	0x77, 0xb7, 0xf5, 0x6d, 0x3c, 0x46, 0x8e, 0x57, 0x98, 0x9f, 0x88, 0xc7,
+	0xeb, 0xe4, 0x98, 0xd4, 0xd7, 0xaa, 0x95, 0xe3, 0xff, 0x33, 0xc7, 0x94,
+	0x73, 0xc8, 0x7a, 0x78, 0x59, 0x48, 0x6f, 0x56, 0x61, 0x0f, 0x2b, 0xdb,
+	0xc8, 0xa9, 0x45, 0x96, 0xde, 0xef, 0x92, 0x4f, 0x4b, 0xcc, 0x4f, 0xe3,
+	0x1d, 0xf8, 0xd4, 0x48, 0x3e, 0xed, 0x5a, 0xc1, 0xa7, 0xe3, 0xe4, 0x53,
+	0x2f, 0xf9, 0xd4, 0xd2, 0xf6, 0x27, 0xd4, 0x15, 0x21, 0x82, 0x6d, 0x37,
+	0xc5, 0x9b, 0x9e, 0xff, 0x95, 0x9e, 0x37, 0xad, 0x74, 0xcd, 0x4b, 0x7d,
+	0xaa, 0xa4, 0x27, 0xee, 0xa1, 0x1f, 0x06, 0x06, 0xc8, 0xa7, 0xc7, 0x4d,
+	0xd1, 0xb8, 0x2f, 0x69, 0xa4, 0x16, 0xe9, 0x6b, 0x7a, 0xc8, 0xa9, 0xb7,
+	0xc8, 0xa9, 0xb1, 0x42, 0x51, 0xa7, 0x0e, 0x73, 0xdd, 0xf7, 0x53, 0xa7,
+	0x7a, 0x0a, 0x52, 0xdb, 0x1c, 0xe2, 0x3f, 0x84, 0x4f, 0xc9, 0xa9, 0xf9,
+	0xa4, 0xa7, 0x53, 0xd6, 0x6f, 0x90, 0x18, 0x3a, 0x2f, 0xf9, 0x44, 0x9d,
+	0x72, 0x0b, 0x4d, 0xd6, 0x79, 0xae, 0x69, 0xd2, 0x35, 0x6e, 0x74, 0x93,
+	0x53, 0x81, 0x76, 0xe3, 0xe2, 0x55, 0x62, 0x37, 0x14, 0x83, 0x1e, 0xb1,
+	0xe5, 0x9a, 0x58, 0x63, 0x59, 0x27, 0x8f, 0x13, 0xff, 0xdd, 0xd4, 0x8c,
+	0xde, 0x82, 0x8d, 0x43, 0x85, 0x95, 0x7b, 0xca, 0x3a, 0x74, 0xc7, 0x7d,
+	0x19, 0x0d, 0xdd, 0xb9, 0x9d, 0xf5, 0xea, 0x8e, 0xed, 0x92, 0xaf, 0x7a,
+	0x48, 0xf2, 0x75, 0xd4, 0xfd, 0x61, 0xe0, 0xce, 0xef, 0xc8, 0xfb, 0x33,
+	0x21, 0x4e, 0x5b, 0xf2, 0xfe, 0x41, 0xfa, 0x1e, 0xfa, 0x68, 0x4b, 0xde,
+	0xa1, 0x75, 0x44, 0x55, 0x18, 0x91, 0x47, 0xf1, 0xb9, 0xc8, 0xd6, 0x39,
+	0xf1, 0x80, 0x57, 0x23, 0x0d, 0xbd, 0x8f, 0xb5, 0x6e, 0xb1, 0x74, 0xce,
+	0x9b, 0xcb, 0x09, 0xf1, 0x16, 0xeb, 0xd4, 0x69, 0x9e, 0xe9, 0x46, 0xf2,
+	0x9f, 0x8b, 0xc5, 0x3a, 0x15, 0x63, 0xe6, 0xad, 0xfb, 0x48, 0x4f, 0xc7,
+	0x4e, 0xf2, 0xd9, 0x44, 0x7e, 0xb9, 0x46, 0x51, 0x33, 0x4d, 0x21, 0x76,
+	0x9b, 0xff, 0x2d, 0xfa, 0xbf, 0xf2, 0xae, 0x10, 0xd3, 0x8c, 0xe1, 0x8a,
+	0x85, 0x03, 0x01, 0xc4, 0xfa, 0x6e, 0xb0, 0xae, 0x5f, 0xda, 0x68, 0x64,
+	0xf2, 0x4a, 0xa2, 0x77, 0xab, 0x22, 0xbd, 0x9e, 0xaf, 0xb3, 0x8c, 0xef,
+	0xb4, 0xd0, 0x1b, 0x7d, 0xc8, 0x0c, 0x06, 0xf9, 0xfd, 0x4d, 0xcb, 0xa0,
+	0x7f, 0x16, 0xa2, 0x3f, 0x25, 0xc7, 0x10, 0xa2, 0xc3, 0x92, 0xe7, 0x80,
+	0x31, 0x9e, 0x03, 0xb2, 0xa2, 0xc2, 0xbc, 0x42, 0x6d, 0x32, 0x32, 0x63,
+	0x8a, 0xc9, 0xbe, 0x51, 0x78, 0x3a, 0xcb, 0x67, 0xda, 0x54, 0x04, 0x7f,
+	0xed, 0xf9, 0xe7, 0x28, 0x35, 0xab, 0x01, 0x7f, 0xe3, 0xe9, 0x96, 0x8a,
+	0x3d, 0xcf, 0x1b, 0x29, 0x55, 0x39, 0x88, 0xf7, 0x2d, 0x43, 0xff, 0x21,
+	0xe3, 0xa6, 0xd6, 0x3c, 0xb7, 0x19, 0x51, 0x70, 0x8e, 0x6c, 0x9f, 0xbf,
+	0x46, 0xd1, 0x58, 0x3b, 0xbe, 0xdf, 0x22, 0x6b, 0xf7, 0x10, 0xba, 0x9b,
+	0xf7, 0xf3, 0xa3, 0xa2, 0x76, 0x46, 0x55, 0x76, 0xd0, 0x93, 0x54, 0xcf,
+	0x54, 0x63, 0xef, 0x7a, 0x21, 0xd6, 0xae, 0x77, 0xc0, 0x33, 0x5f, 0xfc,
+	0x02, 0x6b, 0xd0, 0x89, 0x1a, 0x23, 0x0d, 0xfc, 0x04, 0x3b, 0xe9, 0x65,
+	0x53, 0x6d, 0x39, 0xe0, 0x1e, 0xb9, 0xc6, 0x9f, 0x60, 0xb3, 0xf4, 0xc0,
+	0x56, 0xb5, 0xf4, 0x5b, 0x1e, 0x7e, 0x8b, 0x77, 0x48, 0x4c, 0xf5, 0xd1,
+	0xac, 0x28, 0x37, 0x8d, 0xbe, 0x79, 0xd6, 0xdb, 0x4b, 0xb1, 0xbb, 0xf5,
+	0x6f, 0xcd, 0x4b, 0x0f, 0x6c, 0x46, 0xb7, 0x28, 0x82, 0xb9, 0x78, 0x86,
+	0xb9, 0x88, 0x39, 0x61, 0x5a, 0x86, 0x6a, 0x3b, 0xe6, 0x54, 0x2b, 0xc3,
+	0xca, 0x83, 0xe4, 0x43, 0x5f, 0xb0, 0x9c, 0x1e, 0xc2, 0xa1, 0x7f, 0xf0,
+	0xa1, 0xf2, 0xa8, 0xf4, 0x14, 0x21, 0x6a, 0x4d, 0x53, 0x2f, 0x4f, 0x17,
+	0xd8, 0x97, 0x94, 0xfe, 0x83, 0x58, 0x3f, 0x7a, 0x53, 0x6c, 0xa6, 0xc7,
+	0xdd, 0x5c, 0xf2, 0xb8, 0xbb, 0x66, 0xd3, 0xf4, 0xc0, 0x9a, 0x22, 0xef,
+	0xd3, 0x52, 0x6d, 0x3c, 0x94, 0x3e, 0x28, 0x7d, 0x88, 0x5c, 0x83, 0x8e,
+	0x6b, 0x49, 0x89, 0x5d, 0x1d, 0xa3, 0xed, 0x46, 0x24, 0x0b, 0x79, 0x7f,
+	0x73, 0xbb, 0xbf, 0x80, 0x9e, 0xfe, 0x1d, 0xcf, 0x01, 0x7d, 0x07, 0x63,
+	0x31, 0x82, 0x42, 0xd4, 0x26, 0xfd, 0xe8, 0xf3, 0xce, 0x73, 0x11, 0x3d,
+	0x4d, 0xde, 0x5f, 0xa4, 0x4f, 0xf0, 0xf3, 0xdc, 0x7c, 0x90, 0x58, 0xfa,
+	0xac, 0x65, 0xe4, 0x58, 0x3d, 0xb2, 0x93, 0xb5, 0x30, 0xac, 0xfb, 0xa9,
+	0xab, 0x57, 0x72, 0x0f, 0xb2, 0x9e, 0xfb, 0xda, 0x23, 0x3c, 0x03, 0x34,
+	0xce, 0x64, 0x45, 0x3d, 0xfd, 0xe0, 0x37, 0x78, 0xee, 0xad, 0x69, 0x8b,
+	0xd3, 0x6f, 0x2f, 0xef, 0x95, 0x0f, 0x4f, 0x59, 0x26, 0x1c, 0xef, 0x77,
+	0x58, 0xef, 0x9a, 0xbd, 0x29, 0xe6, 0xcc, 0xbb, 0xf5, 0x8e, 0x62, 0x5c,
+	0x6a, 0x99, 0x6d, 0xa1, 0x65, 0x03, 0xcf, 0x8e, 0x77, 0x88, 0xa9, 0x47,
+	0x7a, 0x9f, 0x40, 0xb1, 0xdf, 0x9f, 0xce, 0x36, 0xe8, 0xdb, 0x59, 0xef,
+	0x16, 0x89, 0x95, 0x5d, 0xeb, 0x2d, 0x19, 0xcb, 0xa2, 0x8c, 0x85, 0xfe,
+	0xd2, 0xb9, 0xdf, 0x47, 0x5f, 0x92, 0x04, 0xaa, 0xcf, 0x3e, 0x45, 0x5e,
+	0xf9, 0x5a, 0xab, 0x91, 0x1d, 0x62, 0x8c, 0xc7, 0xfe, 0x91, 0x5b, 0x33,
+	0x30, 0x8d, 0x01, 0x1f, 0xfb, 0x4c, 0x59, 0xc0, 0x13, 0x0b, 0x3c, 0x97,
+	0x4e, 0xc7, 0xe8, 0xcb, 0xe9, 0x23, 0x17, 0x34, 0x3c, 0x3a, 0x5b, 0x8e,
+	0xef, 0xcd, 0x86, 0xb1, 0x6f, 0xd6, 0xbb, 0xd7, 0xda, 0x5a, 0xcb, 0xf7,
+	0x3a, 0x92, 0x42, 0xcc, 0x5b, 0xeb, 0xf1, 0x1e, 0x3d, 0xd4, 0x6a, 0xc5,
+	0x87, 0xc8, 0x51, 0xe8, 0x3a, 0x71, 0x53, 0xd3, 0xf2, 0x3d, 0x26, 0x58,
+	0x08, 0x73, 0xbd, 0xd4, 0xc9, 0x67, 0xbc, 0xef, 0x63, 0xf4, 0x8f, 0x19,
+	0x89, 0x41, 0x97, 0x18, 0x74, 0x89, 0xc9, 0x5b, 0x9e, 0x5a, 0x62, 0x39,
+	0x4e, 0x1f, 0xfd, 0xb4, 0x28, 0x62, 0xe3, 0x0b, 0x71, 0xda, 0x7c, 0x95,
+	0xfc, 0x55, 0xa9, 0xa1, 0xc0, 0xdf, 0xe7, 0x22, 0xfa, 0x8e, 0x82, 0xcc,
+	0xff, 0x5f, 0x96, 0xf2, 0xbf, 0x18, 0x2a, 0xea, 0x85, 0xe1, 0xcc, 0xa3,
+	0x01, 0xd3, 0x6e, 0x83, 0xbe, 0xd5, 0x1d, 0x19, 0xd6, 0x90, 0x8d, 0x56,
+	0xc3, 0x18, 0x9c, 0x86, 0xaf, 0x35, 0x0c, 0xb9, 0x76, 0x20, 0xef, 0xad,
+	0x51, 0x88, 0x09, 0xea, 0x9b, 0xcc, 0xc1, 0xbf, 0xe7, 0xd0, 0xea, 0x63,
+	0x3e, 0x1c, 0xc6, 0xbe, 0x8f, 0x7b, 0xf0, 0x71, 0x5e, 0xde, 0x73, 0xc6,
+	0xd2, 0x5d, 0xb8, 0xee, 0x8d, 0xf9, 0x51, 0x3e, 0x85, 0x23, 0xee, 0x25,
+	0x71, 0xa4, 0xae, 0xa8, 0xf1, 0x69, 0x9e, 0x8f, 0xaa, 0x8f, 0x96, 0xbc,
+	0x10, 0x39, 0x5c, 0xc9, 0xf5, 0x5e, 0x4b, 0x7a, 0xde, 0x9f, 0x35, 0x72,
+	0x50, 0x3b, 0x6d, 0x6e, 0xe4, 0xda, 0x6e, 0x8a, 0x89, 0x58, 0xb3, 0x56,
+	0x8c, 0x29, 0xa1, 0x9f, 0x42, 0x19, 0xb1, 0x2b, 0xcf, 0x48, 0x52, 0x3f,
+	0xe4, 0x6f, 0x9e, 0x4f, 0x54, 0x27, 0xe2, 0xe7, 0xba, 0x9c, 0x87, 0x64,
+	0x5b, 0xa8, 0xe4, 0x57, 0x97, 0xbd, 0x48, 0x07, 0x9f, 0x49, 0x2f, 0xf2,
+	0xb9, 0xe8, 0xab, 0xeb, 0xb8, 0xa5, 0x39, 0x59, 0xbe, 0x31, 0xee, 0xca,
+	0xfb, 0xab, 0x16, 0x3a, 0x62, 0x05, 0xe7, 0x18, 0xf9, 0xa9, 0xd6, 0x98,
+	0x3e, 0xca, 0xf1, 0x1c, 0x5d, 0x27, 0x97, 0x0f, 0xd2, 0x2f, 0xf3, 0x9d,
+	0x42, 0x0b, 0xfb, 0x48, 0x2d, 0xdb, 0xc1, 0xb5, 0xfe, 0xb6, 0x59, 0x62,
+	0x7b, 0xd4, 0x7d, 0xc3, 0xa7, 0x9a, 0x72, 0x9d, 0x89, 0xd4, 0x28, 0xe3,
+	0x59, 0xd2, 0xa5, 0xb7, 0x76, 0xa8, 0x6d, 0x09, 0xaf, 0x7f, 0x56, 0x95,
+	0x71, 0x78, 0xf1, 0xb0, 0x4d, 0x6a, 0x96, 0x91, 0x39, 0x87, 0x84, 0x33,
+	0x20, 0xcd, 0xc1, 0x2a, 0x19, 0x43, 0x53, 0x64, 0x80, 0xf1, 0x9c, 0xa8,
+	0xf3, 0xf4, 0x90, 0xcf, 0x38, 0x9f, 0xeb, 0xdb, 0x5a, 0x0e, 0x81, 0xd5,
+	0x49, 0xef, 0xdc, 0x5f, 0xfa, 0x7f, 0x18, 0x2a, 0x7d, 0x88, 0xc4, 0xe2,
+	0xff, 0x02, 0xc7, 0x2a, 0x26, 0xcf, 0x94, 0x1a, 0x00, 0x00, 0x00 };
 
-static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_tpat_fw_06 = {
-	.ver_major			= 0x1,
+	/* Firmware version: 4.0.5 */
+	.ver_major			= 0x4,
 	.ver_minor			= 0x0,
-	.ver_fix			= 0x0,
+	.ver_fix			= 0x5,
 
-	.start_addr			= 0x08000860,
+	.start_addr			= 0x08000888,
 
 	.text_addr			= 0x08000800,
-	.text_len			= 0x122c,
+	.text_len			= 0x1a90,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_TPAT_b06FwText,
 	.gz_text_len			= sizeof(bnx2_TPAT_b06FwText),
 
-	.data_addr			= 0x08001a60,
+	.data_addr			= 0x00000000,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_TPAT_b06FwData,
 
-	.sbss_addr			= 0x08001a60,
-	.sbss_len			= 0x34,
+	.sbss_addr			= 0x080022c0,
+	.sbss_len			= 0x44,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x08001aa0,
-	.bss_len			= 0x250,
+	.bss_addr			= 0x08002304,
+	.bss_len			= 0x450,
 	.bss_index			= 0x0,
 
 	.rodata_addr			= 0x00000000,
@@ -2282,450 +3651,877 @@ static struct fw_info bnx2_tpat_fw_06 = {
 };
 
 static u8 bnx2_TXP_b06FwText[] = {
-/*	0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
-							0xed, 0x5c, 0x6d, 0x6c,
-	0x1b, 0xf7, 0x79, 0x7f, 0xee, 0x85, 0xd2, 0x51, 0x96, 0xe9, 0x93, 0xc2,
-	0x78, 0x6c, 0xc0, 0xa6, 0x77, 0xd6, 0x51, 0x66, 0x20, 0xb5, 0xa0, 0x05,
-	0x36, 0x55, 0x87, 0x43, 0x73, 0x3e, 0x52, 0x2f, 0x4e, 0x5c, 0x57, 0x71,
-	0x94, 0x86, 0x6e, 0x0d, 0x8c, 0xa0, 0xec, 0xd8, 0xeb, 0x5a, 0x2c, 0x1f,
-	0x8c, 0xd5, 0x68, 0xd1, 0x99, 0xa1, 0x68, 0xc7, 0xc9, 0x68, 0x51, 0xa9,
-	0xe5, 0xa8, 0x43, 0x57, 0x80, 0x95, 0x64, 0xcb, 0x29, 0x4e, 0x3a, 0x65,
-	0xcb, 0x16, 0x0c, 0x58, 0x16, 0xcd, 0x2f, 0x5d, 0x3f, 0x74, 0x80, 0x3f,
-	0xec, 0x43, 0x3a, 0xec, 0x83, 0x91, 0x14, 0xad, 0x11, 0x6c, 0x59, 0xb0,
-	0x2f, 0x33, 0xd6, 0x26, 0xb7, 0xdf, 0x73, 0x77, 0x94, 0x95, 0xc4, 0x4e,
-	0xab, 0x7d, 0xbe, 0x07, 0x20, 0xee, 0x7f, 0xff, 0xd7, 0xe7, 0xfd, 0xe5,
-	0x7f, 0x90, 0x06, 0xb7, 0x53, 0x17, 0x85, 0xb0, 0x1d, 0x3f, 0xed, 0x99,
-	0x93, 0x27, 0x3e, 0xf7, 0xf9, 0xcf, 0x0d, 0xa1, 0x39, 0x4c, 0x4a, 0x4c,
-	0xe4, 0xc1, 0x5b, 0x12, 0x51, 0xf9, 0x1d, 0x8a, 0x20, 0x82, 0x08, 0x22,
-	0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20,
-	0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08,
-	0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88,
-	0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82,
-	0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22,
-	0xf8, 0x9d, 0x20, 0x11, 0xa9, 0xfc, 0xdc, 0x1e, 0xfe, 0x48, 0x11, 0xcd,
-	0xf2, 0x53, 0xb6, 0x41, 0x8a, 0x64, 0x1e, 0x39, 0x34, 0x65, 0x10, 0x59,
-	0xce, 0x80, 0x56, 0xa0, 0xf7, 0xbd, 0x6a, 0x52, 0x26, 0xee, 0xff, 0xb4,
-	0xf9, 0xdb, 0x53, 0xaf, 0x7f, 0x41, 0x7f, 0xaf, 0x25, 0x91, 0xa2, 0x9a,
-	0x6b, 0x79, 0xb5, 0x9f, 0x94, 0x34, 0xd6, 0xfc, 0xd5, 0xee, 0xaf, 0xef,
-	0xa0, 0x44, 0x7b, 0xaf, 0x24, 0xd5, 0x9b, 0xb7, 0xbc, 0xd7, 0x77, 0x27,
-	0xe9, 0x15, 0x57, 0xa5, 0x35, 0x57, 0x16, 0x46, 0x9b, 0x0a, 0x4d, 0x37,
-	0x1d, 0x3a, 0xdd, 0xa8, 0x52, 0xc1, 0xbd, 0x4c, 0xb5, 0x39, 0x35, 0x61,
-	0x2f, 0xff, 0x84, 0xa6, 0xe7, 0x7a, 0x13, 0x85, 0x65, 0x87, 0x6a, 0x8d,
-	0x54, 0xc2, 0x76, 0xd5, 0x44, 0x61, 0x3e, 0x89, 0xf7, 0xde, 0x84, 0x3d,
-	0xaf, 0x57, 0x89, 0x76, 0x62, 0x4e, 0x2a, 0x51, 0x68, 0xea, 0x65, 0xa2,
-	0xbe, 0xdc, 0x75, 0x4a, 0x27, 0x0a, 0xee, 0x82, 0xb0, 0xae, 0x0a, 0x54,
-	0xfb, 0x2c, 0xa9, 0x09, 0xf3, 0xb6, 0xf7, 0x29, 0x43, 0xa5, 0x1e, 0x83,
-	0x76, 0xec, 0x30, 0xe8, 0xd9, 0x94, 0xa9, 0x50, 0xe5, 0x7c, 0x9c, 0x2c,
-	0x9f, 0x26, 0x95, 0x2a, 0xf3, 0x03, 0xea, 0x15, 0x8a, 0x91, 0x95, 0x6c,
-	0xbf, 0x7b, 0x9e, 0x9d, 0xfb, 0x16, 0xff, 0x9d, 0x16, 0xce, 0xa2, 0xc4,
-	0xa8, 0x4b, 0x64, 0x03, 0x2f, 0x3b, 0xf7, 0xbe, 0x17, 0xac, 0x51, 0x70,
-	0xae, 0x9c, 0x18, 0x69, 0x7a, 0x5e, 0x31, 0x87, 0x33, 0x72, 0xed, 0xb5,
-	0x31, 0x6a, 0x25, 0xad, 0xd6, 0x74, 0x2e, 0xbf, 0x23, 0xf8, 0x1b, 0x2f,
-	0xa6, 0x91, 0xdf, 0x2d, 0x12, 0x8d, 0xaf, 0x50, 0x25, 0x49, 0xad, 0x5a,
-	0xee, 0x61, 0x7a, 0x21, 0xd7, 0x4d, 0x67, 0xb1, 0xdf, 0xf3, 0x39, 0xf0,
-	0xd1, 0x38, 0x29, 0xd8, 0xae, 0x9e, 0x22, 0xe1, 0x05, 0xb2, 0xe7, 0xfb,
-	0xd4, 0x02, 0xe1, 0x6c, 0xc3, 0xfb, 0x8c, 0x9d, 0xc3, 0x79, 0x83, 0xff,
-	0xeb, 0x59, 0x49, 0xbd, 0xdc, 0xa2, 0x14, 0xd5, 0x9a, 0x7d, 0xb9, 0x9f,
-	0x93, 0x40, 0x9d, 0x06, 0xf3, 0xc7, 0xa3, 0xc7, 0x70, 0xae, 0x6d, 0xa0,
-	0xdf, 0x25, 0x4b, 0xcc, 0xc4, 0xe8, 0x4f, 0x55, 0x5d, 0xb3, 0xa5, 0x5e,
-	0xaa, 0x9d, 0xef, 0x04, 0x9e, 0x56, 0xaf, 0x88, 0xb9, 0x63, 0x79, 0x4a,
-	0x6e, 0x23, 0x12, 0x24, 0x33, 0x83, 0x7d, 0x89, 0x6a, 0x4e, 0x0a, 0x6b,
-	0x33, 0xc3, 0xef, 0xd0, 0x0e, 0xd2, 0x7a, 0x64, 0x9a, 0x76, 0xba, 0xc0,
-	0xc7, 0x6e, 0xc8, 0x20, 0x33, 0xfc, 0x2e, 0x84, 0x22, 0x1a, 0x99, 0xd4,
-	0x49, 0x2a, 0x0b, 0x05, 0xb7, 0x83, 0xa6, 0x33, 0x0a, 0xd5, 0x81, 0x47,
-	0x3d, 0xf7, 0x35, 0xc1, 0x5e, 0x2e, 0x09, 0x85, 0x65, 0xcc, 0x73, 0x5f,
-	0x0b, 0xff, 0x76, 0xad, 0x1b, 0xfb, 0x88, 0x54, 0xcb, 0x94, 0x30, 0xa6,
-	0xd0, 0x14, 0xe6, 0x4d, 0x81, 0xa6, 0x69, 0x77, 0x07, 0xad, 0x4f, 0x26,
-	0x13, 0xcc, 0xab, 0x1a, 0xc6, 0xbf, 0x32, 0x21, 0x90, 0x6a, 0x58, 0xf4,
-	0xeb, 0x3c, 0x64, 0x38, 0xdf, 0xcb, 0x32, 0xa3, 0xd3, 0x4d, 0x4a, 0x8a,
-	0x94, 0x49, 0x55, 0xe8, 0x32, 0x2d, 0x3a, 0x2c, 0x7f, 0xc8, 0x13, 0xf2,
-	0xae, 0x39, 0xbc, 0x0e, 0x72, 0x6b, 0x16, 0xc1, 0x8f, 0x71, 0xe0, 0x70,
-	0x50, 0x78, 0x6c, 0x71, 0x52, 0x18, 0x73, 0x7f, 0x93, 0xa0, 0xae, 0x93,
-	0xc2, 0x01, 0xf7, 0xa8, 0x10, 0xf2, 0x1e, 0xb2, 0x53, 0xc8, 0x9a, 0x50,
-	0xe8, 0x92, 0x1b, 0xc8, 0x6e, 0x01, 0xfa, 0x69, 0xa9, 0x16, 0xe4, 0x70,
-	0x78, 0x63, 0x0e, 0x8f, 0xd5, 0x97, 0x65, 0x3a, 0xed, 0xf2, 0xfc, 0x3f,
-	0x82, 0x7c, 0x14, 0x72, 0x76, 0x77, 0x53, 0x19, 0xfd, 0xb5, 0x79, 0xb2,
-	0xec, 0x9c, 0x88, 0x35, 0x09, 0x92, 0x8c, 0x9d, 0xf8, 0x75, 0xd1, 0xd4,
-	0x62, 0xa7, 0x25, 0x19, 0x49, 0x9a, 0x72, 0x99, 0x87, 0x78, 0x36, 0xdb,
-	0x7c, 0x64, 0x5c, 0xb9, 0x9f, 0xd7, 0x71, 0xbf, 0x8a, 0xfe, 0xcd, 0x7d,
-	0xac, 0x17, 0x09, 0xe0, 0xa3, 0x67, 0x59, 0x9f, 0x2b, 0xcd, 0x8c, 0x7a,
-	0x80, 0x9f, 0x2e, 0xf3, 0xb6, 0xcd, 0x53, 0x19, 0x73, 0x45, 0xaa, 0x2c,
-	0xe2, 0x9c, 0xf3, 0xbf, 0xf5, 0x62, 0x79, 0xbc, 0x1b, 0x1d, 0xa0, 0x8b,
-	0xcf, 0x95, 0x81, 0x93, 0x48, 0xe5, 0x45, 0xde, 0x8b, 0xc7, 0x09, 0xb2,
-	0xaf, 0xf5, 0x88, 0x94, 0x85, 0x7c, 0x75, 0x9c, 0x13, 0xc7, 0x9c, 0x6e,
-	0xf0, 0x0f, 0xb4, 0x2e, 0xa3, 0x0d, 0xda, 0x45, 0x43, 0xc4, 0xfa, 0x4e,
-	0x9a, 0xca, 0xb1, 0xbe, 0x30, 0x9e, 0xdb, 0xb0, 0x77, 0x9c, 0x8e, 0x9c,
-	0x67, 0x7e, 0xc8, 0xf4, 0x3c, 0x70, 0x9c, 0x9e, 0xd7, 0xd5, 0x22, 0xe9,
-	0xe0, 0x8d, 0x85, 0x79, 0x9d, 0x54, 0x56, 0x3d, 0x6f, 0x24, 0x37, 0xa0,
-	0xbe, 0xec, 0xeb, 0xf9, 0x80, 0x9a, 0x11, 0xa8, 0xda, 0x61, 0xfe, 0x21,
-	0x70, 0xd0, 0x4b, 0x44, 0xfc, 0xfe, 0xcf, 0x64, 0x4d, 0xb2, 0xfd, 0x24,
-	0xf9, 0x2c, 0xd8, 0xd3, 0x4e, 0xe0, 0xcf, 0x36, 0x97, 0x86, 0x5c, 0x52,
-	0xbe, 0x1d, 0x8c, 0xdc, 0xd5, 0x0e, 0xf4, 0xf1, 0x16, 0x6c, 0xa6, 0xb6,
-	0x2c, 0xb3, 0xfd, 0xe5, 0xa0, 0x6e, 0xb4, 0xcd, 0x80, 0x6e, 0xf9, 0xb2,
-	0xd9, 0x8f, 0xfd, 0x3d, 0xef, 0xcb, 0xb9, 0x00, 0xa7, 0xda, 0xbc, 0x85,
-	0xb5, 0x32, 0xf8, 0xae, 0x1f, 0xd7, 0xfc, 0xf3, 0xf7, 0x87, 0xe7, 0xab,
-	0x34, 0x05, 0xbc, 0x6b, 0x4d, 0x89, 0x0a, 0x2a, 0xef, 0xf1, 0x2e, 0xf7,
-	0x97, 0x83, 0xbd, 0xa0, 0xb7, 0xe7, 0xfa, 0xd4, 0x7d, 0xb0, 0x25, 0xb6,
-	0xb1, 0xda, 0x0a, 0xf3, 0x18, 0xfb, 0xe4, 0x99, 0xc7, 0xaa, 0x8f, 0xa3,
-	0x3d, 0xcf, 0x7a, 0x44, 0x69, 0x89, 0x58, 0xcf, 0x2f, 0xb3, 0x2e, 0x41,
-	0x3f, 0x03, 0xbd, 0xaa, 0x38, 0x2c, 0xff, 0x2f, 0x85, 0xf6, 0x29, 0x52,
-	0x7f, 0x86, 0xf5, 0xfd, 0x05, 0x2a, 0xc0, 0xc6, 0xa7, 0x70, 0xd2, 0x22,
-	0x68, 0x5a, 0x68, 0xf6, 0x81, 0x57, 0x6d, 0xbb, 0x83, 0x7c, 0x07, 0xff,
-	0xc7, 0x0b, 0xe6, 0x77, 0x03, 0x27, 0xb6, 0x99, 0x9a, 0x2a, 0x52, 0x15,
-	0x3f, 0xe8, 0x8d, 0xa1, 0x67, 0x6d, 0x49, 0x9f, 0x28, 0x03, 0x37, 0xe8,
-	0x3d, 0xd9, 0x7b, 0x58, 0x9f, 0x31, 0xc7, 0xa5, 0xa1, 0xb6, 0x9d, 0x2d,
-	0x38, 0x2c, 0xa7, 0x2e, 0x9c, 0xdb, 0xc6, 0x49, 0x46, 0x1f, 0xef, 0xa3,
-	0x40, 0xe7, 0xdb, 0x3a, 0xc3, 0xfa, 0xa7, 0x5b, 0xeb, 0xd4, 0x41, 0xd9,
-	0x0c, 0x7c, 0xd9, 0xbc, 0x08, 0xf9, 0xa5, 0xe1, 0x53, 0x64, 0x7a, 0xba,
-	0x99, 0xa4, 0x63, 0x4d, 0xc6, 0xaf, 0x08, 0xbb, 0x83, 0x6f, 0x9b, 0x1f,
-	0x85, 0x9d, 0x8d, 0x0b, 0x23, 0xb0, 0x89, 0x47, 0x17, 0x19, 0x27, 0x8f,
-	0xd8, 0x2e, 0x8b, 0xcb, 0x65, 0x61, 0xd4, 0x2d, 0x09, 0xe3, 0xcb, 0x6c,
-	0x27, 0x6c, 0x23, 0xba, 0xfa, 0x38, 0x31, 0x0d, 0x98, 0xe3, 0xfe, 0x22,
-	0xc1, 0xb6, 0x5a, 0x3b, 0x17, 0x07, 0x1e, 0xdb, 0x80, 0x4f, 0x37, 0x6c,
-	0x0f, 0xfa, 0x65, 0xe8, 0x13, 0xac, 0x33, 0xc5, 0x8c, 0xa1, 0xfd, 0x25,
-	0x7d, 0x9c, 0x0f, 0x23, 0x1b, 0x7c, 0x18, 0x00, 0x4f, 0x3e, 0xcc, 0x87,
-	0xfa, 0xc7, 0xf9, 0x60, 0x55, 0xc1, 0x87, 0x3a, 0xfc, 0x50, 0xdd, 0x65,
-	0x9a, 0x3d, 0x12, 0xf7, 0x10, 0xb4, 0x93, 0xf6, 0x8a, 0x26, 0xeb, 0x28,
-	0xdb, 0x49, 0x46, 0x9b, 0xc6, 0x0e, 0x4b, 0x4e, 0xb7, 0x6f, 0x1b, 0xa3,
-	0x3e, 0x2f, 0x7e, 0x17, 0xbd, 0x4c, 0xdf, 0x1d, 0x9a, 0xc7, 0x17, 0xd9,
-	0xdf, 0x40, 0xcf, 0x33, 0x86, 0x7a, 0x88, 0xee, 0xd0, 0xbd, 0xef, 0x0e,
-	0xdd, 0x38, 0xa7, 0xed, 0x83, 0x98, 0xe6, 0xb6, 0x3f, 0x66, 0x5d, 0x79,
-	0xc3, 0x93, 0x0c, 0x03, 0x32, 0x60, 0x7d, 0x61, 0x1c, 0x74, 0xf5, 0xcb,
-	0xa0, 0xa7, 0x02, 0xbf, 0xc0, 0xb6, 0x54, 0xf6, 0xe7, 0x75, 0x50, 0xb9,
-	0x27, 0x98, 0x3f, 0xd5, 0xf4, 0xfe, 0x4b, 0x34, 0x3f, 0xf0, 0xec, 0xbc,
-	0x11, 0xda, 0xb8, 0x42, 0x7f, 0xb2, 0xa8, 0x97, 0x35, 0xa1, 0x9b, 0xaa,
-	0xf7, 0xc3, 0xaf, 0x34, 0xd9, 0x3e, 0x76, 0xde, 0xc3, 0x97, 0xa5, 0x43,
-	0x5f, 0xf6, 0x3e, 0x78, 0xcf, 0xb1, 0xe7, 0xe8, 0x07, 0xeb, 0x49, 0x7e,
-	0x66, 0xd4, 0x09, 0x2a, 0x71, 0xbc, 0xd9, 0x21, 0xfa, 0xfe, 0xbb, 0x8f,
-	0x63, 0x41, 0x55, 0x36, 0xe3, 0x54, 0xed, 0xa1, 0xaa, 0x64, 0xb2, 0x1d,
-	0xb1, 0x6d, 0xb4, 0xf1, 0xde, 0x1e, 0xc6, 0xdd, 0x41, 0x89, 0x0c, 0x1e,
-	0x47, 0x8c, 0x68, 0x32, 0x0d, 0xef, 0x87, 0xf2, 0x60, 0x7f, 0x4a, 0xb1,
-	0x40, 0xdf, 0xf6, 0xc3, 0x5f, 0x32, 0x3f, 0x37, 0xeb, 0x0a, 0xfb, 0x51,
-	0xd2, 0x44, 0x83, 0xfd, 0x28, 0xa9, 0x92, 0x79, 0x50, 0xb0, 0x16, 0xbf,
-	0x26, 0x58, 0xe0, 0x9b, 0x05, 0xbe, 0x59, 0xe0, 0x9b, 0x0d, 0xbe, 0x15,
-	0x5c, 0xc6, 0x85, 0xf1, 0x08, 0xf6, 0x2f, 0x06, 0xfb, 0x03, 0xc7, 0x9d,
-	0x54, 0xf1, 0xed, 0x9b, 0x69, 0x85, 0x3f, 0xf6, 0x7d, 0xc1, 0xa8, 0x10,
-	0xf8, 0x02, 0xde, 0x6f, 0x1c, 0xeb, 0x1f, 0x47, 0x8c, 0xb3, 0x44, 0xd1,
-	0xb8, 0xc3, 0x8f, 0xfa, 0x26, 0x7e, 0x4c, 0x3b, 0xcc, 0x1f, 0x9e, 0xcf,
-	0x76, 0xec, 0x40, 0xe6, 0x6d, 0x9e, 0xec, 0x07, 0x0e, 0x9d, 0x4c, 0x77,
-	0x48, 0x07, 0xef, 0xdf, 0x1b, 0xee, 0x7f, 0x00, 0x7b, 0xb2, 0xdd, 0xde,
-	0xed, 0x5c, 0x3e, 0x93, 0xe3, 0xe8, 0x27, 0xd1, 0x83, 0x3c, 0x02, 0x7e,
-	0x66, 0x0d, 0x76, 0x76, 0x53, 0x4a, 0xd1, 0xeb, 0xbb, 0x6f, 0x20, 0xb7,
-	0xa0, 0xea, 0x03, 0xa6, 0xa7, 0xc9, 0xe6, 0xfb, 0x5e, 0x3d, 0x0f, 0xdf,
-	0x69, 0xea, 0x29, 0x5b, 0x1a, 0xa4, 0x37, 0xdc, 0x2c, 0xfd, 0x9d, 0x6b,
-	0xd0, 0xdf, 0xba, 0x1a, 0xbd, 0xea, 0xa6, 0xe9, 0x6f, 0xdc, 0x14, 0xfd,
-	0xb5, 0xdb, 0xce, 0x43, 0x92, 0xac, 0x47, 0x89, 0xa2, 0x7b, 0xb7, 0x5c,
-	0x08, 0x3a, 0x8e, 0xbd, 0xec, 0xbc, 0x5c, 0x96, 0x4d, 0x3f, 0x3f, 0x98,
-	0x98, 0x6e, 0x90, 0xb2, 0xd3, 0xa0, 0xed, 0xf7, 0x23, 0xef, 0x49, 0x9a,
-	0xb4, 0xe3, 0x3e, 0x3c, 0x7b, 0x4d, 0xb2, 0x7a, 0xcc, 0x53, 0x9e, 0x68,
-	0xb0, 0x1e, 0x75, 0x0f, 0x4f, 0xe5, 0xe3, 0x8c, 0xfb, 0xc4, 0x34, 0xfc,
-	0x91, 0x8d, 0xb3, 0xaa, 0xd0, 0xc5, 0xaa, 0x7b, 0xe8, 0xfe, 0x20, 0x17,
-	0x7a, 0x2f, 0xcc, 0x89, 0x38, 0xaf, 0x5a, 0x7f, 0x6a, 0xc2, 0x60, 0x3f,
-	0x2b, 0x6c, 0xf2, 0xb3, 0x24, 0x14, 0x41, 0x53, 0x1d, 0xb8, 0x16, 0x41,
-	0xe7, 0x57, 0x5d, 0x45, 0x28, 0x9c, 0xef, 0xa5, 0xe9, 0x45, 0x8e, 0x55,
-	0x3c, 0x4f, 0x09, 0x73, 0x19, 0x7e, 0xef, 0xc0, 0x3b, 0x21, 0x7e, 0x14,
-	0xb6, 0x53, 0x42, 0x7f, 0x73, 0x82, 0x9c, 0x30, 0x17, 0x89, 0xd1, 0x05,
-	0x5f, 0x77, 0xb8, 0xdf, 0x2a, 0xfd, 0xb0, 0xff, 0x4e, 0xff, 0xf9, 0x8d,
-	0xfe, 0x72, 0xe9, 0xeb, 0x1b, 0xfd, 0xef, 0xa8, 0x01, 0x4e, 0xc3, 0xc2,
-	0xe3, 0xee, 0xf3, 0x61, 0xdf, 0x6d, 0xf0, 0xd3, 0xf3, 0xea, 0x88, 0x27,
-	0x35, 0xe3, 0x36, 0x72, 0x1f, 0xf6, 0x29, 0x5b, 0xf1, 0x21, 0x1f, 0xf2,
-	0x1f, 0xaa, 0x2d, 0xb1, 0x9c, 0x14, 0x0a, 0xf6, 0xe4, 0xf1, 0x4e, 0xf8,
-	0x92, 0xdb, 0x68, 0x73, 0xec, 0x6a, 0xfb, 0x31, 0x9e, 0xc3, 0xeb, 0x6f,
-	0xdd, 0x43, 0x96, 0x2a, 0x64, 0xb9, 0x35, 0x79, 0xd5, 0x1a, 0xa7, 0x42,
-	0x9f, 0xd0, 0x3d, 0x6c, 0x43, 0x2e, 0x12, 0xe4, 0x52, 0x83, 0x5c, 0x0a,
-	0xf7, 0x94, 0x0b, 0xce, 0xd8, 0xd0, 0x29, 0xc6, 0xa3, 0x2b, 0x3c, 0x9b,
-	0x14, 0xd9, 0xac, 0x96, 0xea, 0xc6, 0xa7, 0x28, 0x66, 0x30, 0x1e, 0x06,
-	0xf0, 0x38, 0x8a, 0xb5, 0x1c, 0xc3, 0x48, 0x89, 0x99, 0x2c, 0xcf, 0xdc,
-	0x13, 0xb6, 0x71, 0xab, 0xb4, 0xe0, 0xdc, 0x2a, 0x5d, 0x34, 0xf8, 0xfd,
-	0xf6, 0x64, 0x90, 0x37, 0x77, 0x3f, 0x89, 0xbc, 0x19, 0xeb, 0xd9, 0x1f,
-	0x72, 0xff, 0x30, 0xe6, 0x71, 0x7c, 0xa0, 0x43, 0x35, 0xfc, 0xea, 0xfe,
-	0xdc, 0x6b, 0x4f, 0xf0, 0xdc, 0x4e, 0x53, 0x9e, 0xfc, 0x35, 0x9e, 0x1d,
-	0xa6, 0xf6, 0xe4, 0x4f, 0x0d, 0xde, 0x77, 0x78, 0xf2, 0xa2, 0xbf, 0x07,
-	0x62, 0xa6, 0xbf, 0x36, 0xfb, 0x24, 0xaf, 0x7d, 0x0e, 0x3e, 0xf6, 0x0c,
-	0xe2, 0xcb, 0x69, 0x47, 0x3b, 0x54, 0xc1, 0x6f, 0x8a, 0x71, 0x6a, 0xf2,
-	0xb8, 0x85, 0x71, 0x19, 0xb1, 0x90, 0xdb, 0x0a, 0x1d, 0xc3, 0xbc, 0xa7,
-	0x31, 0xef, 0xa8, 0x33, 0x8e, 0xbc, 0xbd, 0x4d, 0xd7, 0xbf, 0xc5, 0x0b,
-	0xf3, 0xec, 0xcf, 0x91, 0xed, 0xaf, 0xfc, 0x7b, 0xdc, 0x86, 0x5f, 0x16,
-	0x57, 0x6e, 0xc6, 0x0b, 0xa0, 0x5b, 0x5a, 0xf9, 0x45, 0xbc, 0x08, 0x3d,
-	0x13, 0x0d, 0x09, 0x7e, 0xf9, 0x33, 0x54, 0x53, 0x3d, 0x7a, 0x19, 0xf1,
-	0xab, 0x96, 0x85, 0xbf, 0x82, 0x34, 0x45, 0x03, 0x7e, 0x4c, 0x25, 0xa5,
-	0xcb, 0x3c, 0xa9, 0x52, 0x57, 0x3e, 0x6e, 0x23, 0xde, 0xd4, 0x54, 0x09,
-	0xfd, 0xfd, 0x78, 0x6e, 0xee, 0xff, 0x65, 0x1c, 0x7e, 0x0b, 0x3e, 0x82,
-	0x14, 0x3b, 0xdf, 0x8d, 0xfd, 0xbf, 0x8d, 0x7e, 0x4c, 0xc8, 0x6c, 0xf4,
-	0x3f, 0x1b, 0xf4, 0xdf, 0x02, 0x2e, 0xbc, 0x8e, 0xe3, 0x27, 0x29, 0x53,
-	0x79, 0x15, 0x38, 0xf0, 0xdc, 0xa4, 0x3f, 0xb7, 0x38, 0xcf, 0x3c, 0xa8,
-	0x96, 0x16, 0x8c, 0x34, 0x15, 0xe6, 0x92, 0x34, 0x3a, 0xa7, 0xd2, 0xd8,
-	0x9c, 0x3e, 0xd1, 0x62, 0xfb, 0x01, 0xcd, 0x84, 0x1c, 0x41, 0x5c, 0x21,
-	0x50, 0xac, 0xa7, 0x9e, 0xa6, 0xbe, 0xd4, 0x31, 0xfa, 0x6f, 0x0f, 0xb1,
-	0x08, 0x71, 0xa8, 0x9b, 0x64, 0x7f, 0x9f, 0x54, 0xfb, 0x4c, 0x96, 0xd1,
-	0x87, 0xce, 0x2d, 0xce, 0xdf, 0x6b, 0x5f, 0x28, 0xf1, 0x4a, 0xea, 0x23,
-	0xfb, 0xbe, 0x1b, 0xee, 0xab, 0x62, 0xdf, 0x34, 0xf6, 0x64, 0x1a, 0xf5,
-	0xf8, 0xc8, 0x79, 0xb2, 0x3a, 0x81, 0x5f, 0x31, 0x83, 0x98, 0x8f, 0x7d,
-	0xce, 0xcc, 0xb1, 0xde, 0xd3, 0x4e, 0xfc, 0x06, 0x63, 0x94, 0xc9, 0x2e,
-	0x23, 0x27, 0x18, 0xf1, 0xf7, 0x08, 0xf2, 0x05, 0x71, 0x65, 0x10, 0xf9,
-	0xda, 0x3b, 0xc0, 0x87, 0xe3, 0x18, 0xd3, 0x2c, 0x83, 0xde, 0x41, 0xe4,
-	0x09, 0x9c, 0xe3, 0x7b, 0xa7, 0xec, 0x1c, 0xda, 0xcb, 0x5a, 0xbc, 0x00,
-	0xdb, 0x16, 0x4d, 0x7a, 0x50, 0xf2, 0x7d, 0x2c, 0xcb, 0x65, 0x10, 0x72,
-	0x62, 0xbc, 0x73, 0x90, 0x13, 0xf3, 0x68, 0x38, 0x5e, 0x6c, 0x32, 0x8f,
-	0x08, 0xf8, 0x68, 0xb0, 0x27, 0xd9, 0xcf, 0xf3, 0xc5, 0x15, 0x0b, 0xf3,
-	0x7e, 0xac, 0x72, 0x2e, 0x66, 0x1b, 0xdc, 0x86, 0xed, 0xac, 0x8c, 0x63,
-	0x2e, 0xb7, 0x1f, 0xc6, 0xbe, 0x7d, 0xb9, 0x1a, 0x75, 0xe4, 0x9e, 0x86,
-	0xdd, 0x8a, 0xf9, 0x01, 0xc4, 0x68, 0x01, 0xb9, 0xa0, 0xe7, 0x75, 0xe4,
-	0xbf, 0x00, 0x7a, 0x98, 0x0e, 0xe8, 0xf5, 0x2c, 0xf3, 0x95, 0xfe, 0x40,
-	0xe4, 0x5c, 0x2d, 0xdf, 0xce, 0x6b, 0x38, 0x9e, 0xf3, 0xf9, 0x88, 0x23,
-	0x8d, 0x3d, 0x88, 0xa5, 0xfe, 0xd9, 0xd0, 0xb1, 0x71, 0x2a, 0x34, 0x3e,
-	0x8b, 0x9c, 0x93, 0x6d, 0x67, 0x9b, 0x60, 0x9f, 0x67, 0x1a, 0x09, 0xb1,
-	0x66, 0x8d, 0x2a, 0x0d, 0x39, 0x6c, 0xbf, 0x8a, 0xb6, 0x12, 0xb6, 0xd7,
-	0xd1, 0xee, 0x0e, 0xdb, 0xd7, 0xd0, 0x56, 0xc3, 0xf6, 0xcf, 0xd0, 0x4e,
-	0x86, 0xed, 0x9f, 0xa3, 0x9d, 0x0a, 0xdb, 0x37, 0xd1, 0x4e, 0x87, 0xed,
-	0x5b, 0x68, 0x6b, 0x61, 0xfb, 0x3d, 0xb4, 0x13, 0xb0, 0x73, 0x03, 0xef,
-	0x37, 0x50, 0x2b, 0x66, 0xf1, 0xfc, 0x57, 0xe0, 0x36, 0x08, 0xde, 0x64,
-	0xc1, 0x8f, 0x5e, 0x8c, 0xe5, 0xd0, 0x87, 0x1c, 0xb1, 0x91, 0xc7, 0xd3,
-	0xc1, 0x18, 0x95, 0x61, 0x7b, 0x18, 0x1f, 0x2f, 0x16, 0x1a, 0x26, 0x9e,
-	0x6c, 0x0f, 0xba, 0x4a, 0xc2, 0x65, 0xd8, 0xb9, 0xef, 0x63, 0x72, 0xb6,
-	0x34, 0x09, 0xdb, 0x9e, 0xa0, 0x7f, 0x74, 0xf7, 0xd3, 0x6b, 0xee, 0x38,
-	0xe2, 0x46, 0x11, 0x71, 0xc3, 0x42, 0xdc, 0x30, 0x11, 0x37, 0x86, 0x11,
-	0x37, 0xf2, 0x88, 0x1b, 0x39, 0xc4, 0x0d, 0xa2, 0x33, 0x7e, 0x8c, 0x4a,
-	0x2a, 0xa8, 0x51, 0x15, 0xcb, 0x2d, 0x82, 0xbf, 0x13, 0x90, 0xcd, 0x24,
-	0x78, 0x7d, 0x38, 0x3e, 0xd2, 0xcc, 0xc3, 0x9f, 0x69, 0xf0, 0x11, 0x69,
-	0xf8, 0xf2, 0x1c, 0x6a, 0x13, 0xa2, 0x2b, 0xb3, 0x1a, 0xfc, 0x8f, 0x47,
-	0x45, 0xc4, 0xfe, 0x69, 0x15, 0xb8, 0x19, 0xbb, 0x7c, 0x9b, 0x91, 0xcc,
-	0x2f, 0xf6, 0x50, 0xd7, 0x20, 0xe8, 0x39, 0x8b, 0xbe, 0x14, 0xf6, 0x63,
-	0xbe, 0xde, 0x2a, 0xd9, 0x86, 0x46, 0x0b, 0x6e, 0x1c, 0xfe, 0x9f, 0xdf,
-	0xe3, 0xcc, 0xe3, 0x43, 0x4f, 0x19, 0x4c, 0x03, 0xea, 0x3c, 0x23, 0xad,
-	0x14, 0x1c, 0x81, 0x24, 0x93, 0x9f, 0xed, 0x1c, 0xe2, 0xcf, 0x90, 0x43,
-	0x74, 0x41, 0x06, 0x55, 0xc4, 0x05, 0x9d, 0xf3, 0x0b, 0xe8, 0xf2, 0x27,
-	0xcd, 0xff, 0x1e, 0xe6, 0xef, 0xc5, 0xd9, 0x3c, 0x8f, 0xcf, 0x39, 0x85,
-	0xfa, 0xc1, 0xea, 0x91, 0x68, 0x3d, 0x25, 0xa1, 0x9e, 0x28, 0xd0, 0x59,
-	0x2a, 0x00, 0x9f, 0x82, 0xdb, 0xbe, 0x07, 0xb0, 0x0e, 0x05, 0xfe, 0x6c,
-	0xe2, 0xd0, 0xb7, 0x0d, 0x0b, 0xeb, 0x18, 0x3f, 0xd6, 0x5b, 0xe0, 0xbe,
-	0xb1, 0xe7, 0x05, 0xec, 0xf9, 0x4f, 0x49, 0xea, 0x9a, 0x0c, 0xfc, 0x91,
-	0x5f, 0xf3, 0xca, 0xc2, 0x48, 0xf3, 0x2c, 0xf8, 0xd3, 0x87, 0x1a, 0x05,
-	0x7e, 0xa4, 0xd4, 0x02, 0x9f, 0xda, 0xf3, 0x5f, 0xc1, 0x7c, 0x7e, 0xf7,
-	0xef, 0x0e, 0x4a, 0xd2, 0xea, 0x12, 0xe6, 0x69, 0xac, 0x3f, 0x25, 0xb9,
-	0xff, 0x86, 0xf7, 0xa2, 0x91, 0xa7, 0x5d, 0xab, 0xbc, 0x2e, 0x4b, 0x7d,
-	0xab, 0x37, 0xbc, 0x9a, 0xa3, 0xd1, 0x62, 0x93, 0xc0, 0xab, 0xf8, 0x6d,
-	0x8b, 0xf4, 0x35, 0x12, 0xf5, 0x59, 0x0b, 0x7a, 0x5a, 0x1c, 0x12, 0xc9,
-	0x1e, 0xea, 0x84, 0x8f, 0x32, 0x68, 0x09, 0x7c, 0xdf, 0x35, 0x63, 0xd1,
-	0x13, 0x43, 0xed, 0x7c, 0x10, 0x51, 0x0f, 0xb8, 0xee, 0x5a, 0xd5, 0x30,
-	0x87, 0x73, 0x71, 0xa6, 0x45, 0x03, 0x2f, 0x85, 0x60, 0x8d, 0x1f, 0xb3,
-	0xb8, 0x8e, 0x05, 0xdf, 0xdc, 0xb5, 0xd2, 0xd5, 0x19, 0xd4, 0x1a, 0x90,
-	0xf3, 0xae, 0x19, 0xae, 0x85, 0xb6, 0x81, 0x2f, 0x31, 0xd8, 0x06, 0xe7,
-	0xf1, 0x08, 0xf4, 0xf0, 0x87, 0x27, 0xe0, 0xf1, 0x6b, 0xcd, 0x13, 0xd0,
-	0xfb, 0x2e, 0x2a, 0xcb, 0x3e, 0x11, 0x9f, 0xc0, 0xe3, 0xff, 0xe4, 0xbc,
-	0x0e, 0xf3, 0xbf, 0x4b, 0xc5, 0xd9, 0x2e, 0xec, 0xb5, 0x9b, 0xa6, 0x93,
-	0x8c, 0x9b, 0x3e, 0x8c, 0x41, 0x2d, 0x06, 0x7e, 0xc6, 0xcd, 0x8f, 0xe6,
-	0x7d, 0x6b, 0xa5, 0x2b, 0x33, 0x6b, 0xa5, 0x6b, 0xa0, 0xbf, 0x6e, 0x70,
-	0x8d, 0x0c, 0x5d, 0x6a, 0x70, 0x6d, 0xcf, 0x79, 0xd1, 0x18, 0x74, 0x64,
-	0xbf, 0x5f, 0x33, 0xdb, 0x8b, 0x39, 0xea, 0x3b, 0x47, 0xaa, 0x68, 0x96,
-	0x84, 0x31, 0xe4, 0x45, 0x23, 0xee, 0x49, 0x7f, 0xee, 0x99, 0x06, 0xd7,
-	0x2b, 0x18, 0x5b, 0x61, 0x5d, 0x18, 0x03, 0x3e, 0x49, 0xba, 0xe8, 0xb2,
-	0x4f, 0x0a, 0xec, 0x78, 0x0c, 0xfc, 0x5a, 0xf0, 0xe9, 0x4a, 0x71, 0x1c,
-	0x47, 0xbe, 0xc1, 0xf2, 0xf9, 0x21, 0xc7, 0x41, 0xa1, 0xd3, 0x6c, 0xfb,
-	0xdb, 0x89, 0x5e, 0xe6, 0x59, 0xa1, 0x01, 0xdf, 0x3f, 0x34, 0x11, 0xe6,
-	0x1c, 0x7f, 0x8f, 0x39, 0x8c, 0x3b, 0xcd, 0x4a, 0x26, 0xce, 0xc8, 0x33,
-	0xcf, 0x38, 0xa7, 0xe4, 0x7d, 0xc1, 0x5b, 0xf0, 0x7d, 0x53, 0x6e, 0xe9,
-	0xc3, 0x74, 0x33, 0x46, 0x95, 0x59, 0xf0, 0x2e, 0x8f, 0x27, 0x9c, 0x6b,
-	0x1d, 0x7c, 0x03, 0x2d, 0xd5, 0x20, 0x9f, 0x3d, 0xc1, 0x31, 0x0d, 0xfe,
-	0x06, 0x36, 0xcd, 0x31, 0x6b, 0xe3, 0xde, 0xc9, 0xf7, 0x25, 0x32, 0x19,
-	0x41, 0xce, 0x2a, 0xe2, 0x2c, 0x3b, 0xcf, 0x7e, 0x10, 0xf8, 0xb8, 0xdf,
-	0xa5, 0xfa, 0x2c, 0xd3, 0x05, 0x1b, 0x4f, 0xb2, 0x2e, 0xfe, 0x7f, 0xf9,
-	0x38, 0xba, 0x45, 0x3e, 0x8e, 0x6e, 0x99, 0x8f, 0x12, 0xf8, 0x58, 0xd9,
-	0xe0, 0xa3, 0x82, 0x3d, 0xf8, 0x3e, 0xe1, 0xab, 0x64, 0x4d, 0x3c, 0x02,
-	0x3f, 0x0c, 0xff, 0xd1, 0x3c, 0x05, 0x9f, 0x70, 0x52, 0xb8, 0xda, 0xf0,
-	0x68, 0x1c, 0xb5, 0xb2, 0x74, 0xff, 0x66, 0xfa, 0x33, 0xa0, 0xff, 0xcf,
-	0x31, 0x5e, 0xa5, 0x6b, 0xb3, 0x94, 0x56, 0xa8, 0x7d, 0x2e, 0xed, 0x92,
-	0xe9, 0x3b, 0x74, 0x75, 0xb6, 0x8b, 0xae, 0xcf, 0x66, 0xc0, 0xeb, 0x2c,
-	0xc5, 0x7a, 0x32, 0xc3, 0x15, 0x18, 0xf1, 0xcf, 0x5a, 0xba, 0xc5, 0xba,
-	0xf8, 0xfb, 0xf3, 0x82, 0xf9, 0x70, 0xd0, 0xe7, 0xc3, 0xd8, 0x47, 0xf8,
-	0x30, 0x7e, 0x4f, 0x3e, 0x1c, 0xfc, 0x18, 0x1f, 0xc6, 0x3f, 0xc6, 0x07,
-	0xe6, 0x01, 0xf3, 0xe2, 0xd1, 0xde, 0xf0, 0xff, 0x1f, 0x7d, 0x82, 0x7d,
-	0x7c, 0x09, 0x74, 0x22, 0xa7, 0xd8, 0x19, 0xe4, 0x50, 0x9c, 0x63, 0xd5,
-	0x0c, 0xe6, 0x57, 0x60, 0xbf, 0x32, 0x72, 0xea, 0x23, 0xa1, 0xfd, 0x16,
-	0x1c, 0xe8, 0x65, 0x23, 0xe6, 0xdb, 0xaf, 0x64, 0xe6, 0xe1, 0x03, 0xaa,
-	0xa5, 0x96, 0xc3, 0xfe, 0x07, 0x6d, 0x87, 0x79, 0xda, 0x0b, 0x5a, 0x12,
-	0x54, 0x99, 0x54, 0x10, 0x5f, 0x87, 0xa1, 0xb7, 0x71, 0xdf, 0x07, 0x4a,
-	0x26, 0xeb, 0xe1, 0x7e, 0xcc, 0x3f, 0x1c, 0xe6, 0x45, 0x88, 0x73, 0x38,
-	0xa3, 0xd6, 0x38, 0x0d, 0xfc, 0xf8, 0x9c, 0x6a, 0xa9, 0xec, 0xf0, 0x9a,
-	0x34, 0x62, 0x21, 0x3f, 0x37, 0xeb, 0xb7, 0xaf, 0xef, 0xf7, 0xd2, 0x71,
-	0xe8, 0x26, 0xeb, 0xb4, 0x82, 0xdc, 0x78, 0x02, 0xf1, 0xc5, 0xd7, 0xd3,
-	0xec, 0x02, 0xb1, 0xdf, 0x7f, 0x06, 0x75, 0xd1, 0x61, 0xfc, 0x34, 0x1a,
-	0x71, 0x03, 0x9b, 0x5a, 0xf2, 0xcf, 0xfc, 0xb0, 0x4f, 0xaa, 0x39, 0xeb,
-	0xc8, 0xdf, 0x0d, 0xec, 0xcb, 0xe7, 0x56, 0xc1, 0x1b, 0x09, 0xe7, 0x72,
-	0x5f, 0x37, 0xe2, 0x00, 0xf8, 0xe4, 0xfe, 0x07, 0xfa, 0x97, 0xe0, 0x1f,
-	0x39, 0x2f, 0x68, 0xe3, 0x8e, 0x1c, 0xc2, 0xe1, 0x78, 0x9d, 0x07, 0xcd,
-	0x9c, 0x63, 0x73, 0x2e, 0x81, 0xfc, 0x63, 0xe9, 0x4d, 0xf4, 0x0d, 0xd3,
-	0xe9, 0xa1, 0x2c, 0xe4, 0xc3, 0x7d, 0x0f, 0x84, 0x7d, 0x3c, 0x8f, 0x94,
-	0x07, 0x4d, 0xfd, 0x07, 0x55, 0xdf, 0xaf, 0x43, 0x0f, 0x51, 0xf7, 0xd5,
-	0x96, 0x90, 0x63, 0x00, 0xa7, 0xca, 0x6a, 0x16, 0xb9, 0x3c, 0xdf, 0xab,
-	0xe9, 0x97, 0x91, 0x07, 0x83, 0x27, 0x0a, 0xf5, 0x1a, 0xa5, 0xd0, 0x0f,
-	0xe7, 0x40, 0x1f, 0xdf, 0x3d, 0xf5, 0x21, 0xf7, 0x91, 0xc0, 0x08, 0xd8,
-	0xe9, 0xaa, 0x44, 0x7b, 0xe5, 0x01, 0xb5, 0x46, 0xff, 0x80, 0xb9, 0x32,
-	0x95, 0x57, 0x39, 0x87, 0x90, 0xe9, 0xc8, 0x2a, 0xd1, 0x5b, 0x33, 0xec,
-	0x97, 0x19, 0xd8, 0x2f, 0xb3, 0x7f, 0x7d, 0xd0, 0x1f, 0x7b, 0x6b, 0x06,
-	0x35, 0xf8, 0xcc, 0x00, 0xc7, 0xb0, 0x75, 0x11, 0xbc, 0x44, 0xee, 0xc3,
-	0xf9, 0xf9, 0x5d, 0xee, 0x98, 0xda, 0xf7, 0x4b, 0x0a, 0x55, 0x66, 0xf8,
-	0x6e, 0x49, 0xc6, 0xf9, 0x5c, 0x5b, 0x6c, 0x03, 0x7e, 0x02, 0xa1, 0xee,
-	0x12, 0x38, 0xa6, 0x09, 0xd0, 0xa1, 0x5d, 0x90, 0x3d, 0xf8, 0x1f, 0xb6,
-	0xdb, 0xfa, 0xf4, 0x2f, 0xd0, 0x27, 0x9e, 0x27, 0x6f, 0xc2, 0x25, 0x33,
-	0x6b, 0x8b, 0x1c, 0x1f, 0x3e, 0x0d, 0xdb, 0xb3, 0xe2, 0x63, 0xcd, 0x0e,
-	0x6a, 0xf5, 0xb2, 0x3d, 0xb0, 0x5e, 0x5c, 0x66, 0x9d, 0xc0, 0x19, 0xd0,
-	0xa1, 0x19, 0xae, 0xe7, 0x65, 0xcc, 0xbb, 0x2f, 0x9c, 0xc7, 0xfc, 0xfe,
-	0x1e, 0x4d, 0x0f, 0xa9, 0x42, 0x59, 0x0d, 0xe2, 0x45, 0x6d, 0xa8, 0x03,
-	0x63, 0x22, 0x1d, 0x7c, 0x38, 0x8f, 0xb5, 0x9c, 0x53, 0xc5, 0x85, 0xc0,
-	0x6f, 0x71, 0x1f, 0xdf, 0xd7, 0xa9, 0x54, 0xbe, 0xd4, 0x4b, 0x95, 0x4b,
-	0x0a, 0xf8, 0x02, 0x44, 0x17, 0x82, 0x7d, 0xd8, 0x17, 0x1c, 0x87, 0xdc,
-	0xc4, 0x73, 0x0a, 0xc5, 0xce, 0x21, 0x87, 0xbc, 0xd0, 0x45, 0x1d, 0x17,
-	0xfa, 0x49, 0xba, 0xa0, 0x73, 0x7e, 0xa8, 0x9d, 0x81, 0x0c, 0x8f, 0x50,
-	0x9e, 0x9e, 0x73, 0x07, 0x39, 0xc7, 0xc3, 0x39, 0x5c, 0xe7, 0x25, 0x49,
-	0x42, 0xf2, 0x2f, 0xbe, 0x68, 0xd1, 0x8b, 0x43, 0xc0, 0x2b, 0x8f, 0xf6,
-	0x8f, 0x91, 0xc7, 0xbb, 0x23, 0xf7, 0x71, 0xcc, 0x96, 0xcd, 0x3e, 0xc8,
-	0x16, 0x74, 0xe5, 0x1e, 0xf2, 0xef, 0x44, 0x5f, 0x1c, 0x62, 0x7a, 0x34,
-	0xd0, 0x52, 0x87, 0xae, 0xf3, 0x3d, 0x57, 0x17, 0xd9, 0x32, 0xeb, 0x32,
-	0xf2, 0xaa, 0x0b, 0x75, 0x9a, 0x6a, 0xe8, 0x90, 0x59, 0x1f, 0xf4, 0x02,
-	0x32, 0x4b, 0x73, 0x3f, 0xef, 0x2d, 0x84, 0xfb, 0xde, 0xd1, 0xf7, 0x17,
-	0xef, 0xad, 0xef, 0x3e, 0xd4, 0x9b, 0x8f, 0xc0, 0x67, 0xa3, 0x2e, 0x32,
-	0xe0, 0xd3, 0x55, 0xe4, 0x72, 0x06, 0xbf, 0x07, 0x77, 0x95, 0x15, 0xe4,
-	0x85, 0xfc, 0x5e, 0x6b, 0xdd, 0xcd, 0x77, 0x07, 0xf6, 0x7d, 0x06, 0x3c,
-	0xba, 0x32, 0xf7, 0x00, 0x5d, 0x9d, 0x53, 0xe8, 0x5a, 0x43, 0xcf, 0x16,
-	0xa8, 0x83, 0xaa, 0xc9, 0x34, 0x5d, 0x5f, 0x6a, 0xe7, 0x93, 0x22, 0xf4,
-	0xc4, 0x22, 0xce, 0xcd, 0xaf, 0x2c, 0x55, 0x4b, 0x37, 0x76, 0xa7, 0x49,
-	0x7e, 0x09, 0xb6, 0xfd, 0x92, 0xae, 0xd5, 0xc0, 0xe7, 0xba, 0xe1, 0xa2,
-	0x56, 0xe3, 0x3a, 0x32, 0x05, 0xbb, 0xd3, 0x53, 0x2d, 0xca, 0x90, 0xb4,
-	0xa0, 0xd0, 0xaf, 0x66, 0x74, 0x8d, 0x75, 0xee, 0xa2, 0x81, 0x7e, 0x37,
-	0x7e, 0x7b, 0x3d, 0xd0, 0x43, 0xf4, 0xf5, 0xa3, 0xbe, 0xd5, 0xb3, 0x9a,
-	0xd8, 0x4d, 0x6f, 0x43, 0x27, 0xca, 0x7e, 0xdf, 0x47, 0xf7, 0xbc, 0x1e,
-	0xee, 0x59, 0x2d, 0x5d, 0xe1, 0x3a, 0x68, 0x86, 0x75, 0xbe, 0x17, 0xfe,
-	0x03, 0xef, 0x6e, 0x07, 0x95, 0x27, 0x11, 0xa3, 0x66, 0x1e, 0xa5, 0xc2,
-	0x90, 0x18, 0xd0, 0xed, 0xf3, 0x82, 0xfb, 0xf8, 0x7e, 0xb2, 0x76, 0x1f,
-	0xdb, 0xb2, 0xb8, 0x0a, 0xbd, 0x3a, 0xc8, 0x7a, 0x80, 0xdc, 0x0e, 0x39,
-	0x04, 0xfb, 0x4e, 0x09, 0x39, 0x44, 0xc1, 0x0d, 0x74, 0xa3, 0x75, 0x30,
-	0x49, 0xc7, 0x5e, 0x62, 0x19, 0x61, 0x6c, 0x43, 0xef, 0x36, 0xee, 0xc4,
-	0x31, 0x66, 0xd0, 0xf1, 0xef, 0xb7, 0x73, 0x4a, 0xb6, 0xbd, 0x34, 0xe4,
-	0xa1, 0xa3, 0xf6, 0xe8, 0x53, 0x2b, 0xbe, 0x4f, 0x81, 0x4e, 0xa4, 0x02,
-	0x19, 0xd4, 0x30, 0x36, 0xed, 0x4e, 0xc2, 0x27, 0xc6, 0xe8, 0xe6, 0xa4,
-	0x05, 0x9d, 0x68, 0x01, 0x87, 0xc3, 0x71, 0xbe, 0x4b, 0xb8, 0x39, 0x59,
-	0xc4, 0xfb, 0x61, 0x3f, 0xf7, 0x97, 0xf6, 0x40, 0x97, 0xdc, 0x07, 0xc2,
-	0xfc, 0x9c, 0xcf, 0xd3, 0x84, 0xda, 0xac, 0x2e, 0x4c, 0xcf, 0x7a, 0x34,
-	0x9a, 0xeb, 0x4b, 0x5d, 0xa5, 0x4e, 0xff, 0xce, 0xd8, 0xf7, 0x9b, 0xfe,
-	0x9c, 0x5d, 0x18, 0xff, 0x00, 0x3a, 0x85, 0x27, 0xe2, 0xf5, 0xe9, 0x66,
-	0x35, 0xd5, 0x41, 0xac, 0x53, 0x24, 0x2c, 0x18, 0xec, 0x3b, 0x04, 0xba,
-	0xea, 0xdf, 0x47, 0x13, 0x15, 0x9d, 0xd7, 0x99, 0x6e, 0x61, 0xb1, 0xc5,
-	0x6b, 0x58, 0xce, 0xbc, 0x46, 0xa2, 0x9b, 0x49, 0xd8, 0xe5, 0x9e, 0x3d,
-	0x7e, 0xbd, 0xf8, 0xf8, 0x10, 0xe3, 0xda, 0x0d, 0x99, 0x42, 0xbf, 0x50,
-	0xdb, 0x94, 0x83, 0xbe, 0x59, 0xae, 0x4d, 0xa7, 0xf9, 0xde, 0x23, 0xef,
-	0xeb, 0x5a, 0xa8, 0x1f, 0x1f, 0xd7, 0xb5, 0xe7, 0xb0, 0xf6, 0x2d, 0xf6,
-	0xab, 0x90, 0x75, 0xe0, 0x23, 0xbe, 0x41, 0x6f, 0xcd, 0x55, 0xb3, 0xfc,
-	0xcd, 0xa3, 0x35, 0x21, 0xa0, 0x16, 0x3f, 0x4e, 0x6f, 0xcf, 0x3d, 0x4b,
-	0xbf, 0x9c, 0x65, 0xdd, 0x31, 0x68, 0x14, 0xfa, 0x74, 0x94, 0xe4, 0xec,
-	0x69, 0x1a, 0x50, 0xaf, 0xfb, 0xb5, 0x8d, 0x9e, 0xf3, 0x6b, 0x3a, 0x33,
-	0x4b, 0xc5, 0xc6, 0x40, 0xea, 0x1a, 0xfa, 0xca, 0x93, 0xba, 0xb6, 0x8e,
-	0xdc, 0xa3, 0xd0, 0xfc, 0x80, 0xef, 0x6c, 0xb2, 0x35, 0xd8, 0xde, 0x22,
-	0x6a, 0x9b, 0xb7, 0x9d, 0xbb, 0xe9, 0x2c, 0xd7, 0x56, 0x81, 0xff, 0x5e,
-	0x33, 0x50, 0x63, 0xac, 0xaa, 0xa1, 0x0e, 0x31, 0x70, 0x9d, 0xc1, 0xf1,
-	0x07, 0x4f, 0x37, 0x06, 0x9f, 0xb2, 0x1f, 0x7c, 0x67, 0xd9, 0x42, 0xfe,
-	0xab, 0xfc, 0x8d, 0x0a, 0xf2, 0x5f, 0x5d, 0xfe, 0x40, 0xeb, 0x65, 0x3f,
-	0x6b, 0x80, 0x96, 0x41, 0x3a, 0x33, 0xcf, 0xf2, 0x47, 0xec, 0xf5, 0xed,
-	0x34, 0x0d, 0xfe, 0x72, 0x7c, 0x19, 0xa4, 0x5f, 0x2d, 0x15, 0xfd, 0xfb,
-	0x6b, 0x1b, 0xb9, 0xd6, 0x11, 0x67, 0x12, 0xf5, 0xfa, 0x77, 0x40, 0x2f,
-	0xce, 0x1e, 0xda, 0x8d, 0xa7, 0x0a, 0x9b, 0xdc, 0x72, 0x9e, 0x23, 0x07,
-	0x79, 0xce, 0xde, 0x2d, 0xe6, 0x39, 0x7b, 0xb7, 0x92, 0xe7, 0xc8, 0x9d,
-	0xe0, 0xab, 0xd6, 0xbb, 0x65, 0xdc, 0xa4, 0x00, 0xb7, 0x03, 0x5b, 0xc4,
-	0xed, 0xc0, 0x56, 0x70, 0x93, 0x3a, 0xcd, 0xbf, 0x40, 0x8c, 0x35, 0x10,
-	0xdb, 0xe0, 0xd7, 0x86, 0xfa, 0x59, 0x7f, 0x80, 0xa3, 0x8f, 0xeb, 0xef,
-	0x8b, 0xa7, 0x18, 0xe0, 0xf9, 0xd8, 0x16, 0xf1, 0x7c, 0x6c, 0x2b, 0x78,
-	0x8a, 0x9d, 0x26, 0xe3, 0x28, 0xc3, 0xd7, 0x70, 0x6d, 0x83, 0xd8, 0x3c,
-	0x24, 0x87, 0xba, 0x2e, 0x87, 0x75, 0x0e, 0x03, 0x7c, 0x50, 0xaf, 0x46,
-	0x4b, 0x4c, 0xcb, 0x46, 0xdf, 0x9d, 0x3a, 0x4b, 0x32, 0x5b, 0xa5, 0x4a,
-	0x83, 0xef, 0x95, 0xfb, 0xb0, 0x0f, 0xf7, 0xf1, 0x37, 0x2a, 0x8b, 0x64,
-	0xc4, 0xf7, 0xe7, 0x9a, 0x77, 0xa7, 0xf5, 0x2a, 0x68, 0x9d, 0x0a, 0x69,
-	0xad, 0xf8, 0xb9, 0xe0, 0xbe, 0x4d, 0xb9, 0x60, 0x40, 0xe3, 0x08, 0x68,
-	0x2c, 0x86, 0x34, 0x3e, 0xdd, 0x60, 0xda, 0xf6, 0xf9, 0xb4, 0x2d, 0x6d,
-	0xa2, 0x6d, 0xe4, 0x9e, 0xf9, 0x1f, 0xe3, 0x81, 0x5a, 0x1a, 0xb9, 0xd7,
-	0x6b, 0x4d, 0xd4, 0xd2, 0x4d, 0xd4, 0xd2, 0xd0, 0xf7, 0x57, 0x9b, 0xa8,
-	0xa5, 0x9b, 0xa8, 0xa5, 0x61, 0x07, 0xaf, 0xc0, 0x56, 0x82, 0x3b, 0xdc,
-	0x12, 0x71, 0x0d, 0xee, 0xd7, 0xe3, 0x14, 0xe4, 0x39, 0x05, 0xc4, 0xf0,
-	0xa3, 0xc8, 0xf1, 0xd8, 0x6e, 0x4f, 0x13, 0xc7, 0x04, 0x3d, 0x87, 0x9a,
-	0x2f, 0x5b, 0x25, 0x33, 0x5e, 0x9c, 0x1f, 0x50, 0x97, 0x02, 0xfb, 0xd6,
-	0x5a, 0xc4, 0x71, 0x70, 0x20, 0x85, 0x08, 0xa9, 0xb2, 0x5f, 0xb0, 0x73,
-	0x4c, 0xe7, 0x76, 0xf0, 0x10, 0xbe, 0xdb, 0x60, 0x1f, 0xc6, 0xbe, 0xb4,
-	0x4e, 0x0b, 0x8d, 0xf0, 0x1b, 0x9a, 0xcc, 0xfd, 0xfc, 0xce, 0x31, 0xb7,
-	0xcf, 0xf7, 0x69, 0x76, 0xb6, 0x0f, 0x71, 0x80, 0xfb, 0x15, 0xf8, 0x35,
-	0xe8, 0xca, 0x52, 0x1b, 0x17, 0x19, 0xeb, 0x55, 0xaa, 0xcf, 0x07, 0x31,
-	0x7c, 0xca, 0xe0, 0x38, 0x87, 0xf8, 0xbe, 0xc4, 0xdf, 0xb0, 0x10, 0xeb,
-	0x97, 0xae, 0x68, 0x32, 0x6a, 0xc7, 0x3a, 0x7f, 0xa3, 0x1d, 0xec, 0xc3,
-	0xf9, 0x1d, 0xfe, 0x1d, 0xed, 0x51, 0xff, 0xae, 0xcd, 0xa0, 0x23, 0xad,
-	0x80, 0x16, 0xdb, 0xc8, 0xd0, 0xc8, 0x2c, 0xdf, 0x35, 0x51, 0x8f, 0x68,
-	0xca, 0x54, 0x75, 0xf8, 0x7e, 0x68, 0xe3, 0xbb, 0x49, 0x76, 0x91, 0xeb,
-	0x4f, 0x23, 0xb8, 0xff, 0x3c, 0xed, 0xbc, 0xc9, 0xf7, 0x9f, 0xe1, 0x3a,
-	0x8d, 0xde, 0x70, 0x33, 0x34, 0x8e, 0xf8, 0x5a, 0x6c, 0x68, 0xf0, 0x6f,
-	0xbe, 0x3c, 0x39, 0xa7, 0xad, 0xc6, 0x42, 0x99, 0x8e, 0x84, 0x32, 0xad,
-	0x34, 0xd6, 0x80, 0xdf, 0x0d, 0xef, 0x8f, 0x43, 0x99, 0xee, 0x3a, 0x47,
-	0xda, 0xd5, 0x1c, 0xcb, 0x95, 0x65, 0x19, 0xc8, 0x75, 0x7c, 0xb1, 0x24,
-	0x14, 0x21, 0xd3, 0x51, 0x5f, 0xa6, 0x32, 0xc7, 0x05, 0xec, 0x95, 0x83,
-	0xfc, 0xd9, 0x8f, 0xe1, 0xe9, 0xb0, 0x8c, 0xb9, 0xde, 0xe0, 0x58, 0x98,
-	0xa4, 0x4b, 0x9b, 0xe4, 0x5c, 0xbc, 0xa7, 0x0e, 0xe7, 0xa9, 0xff, 0x9c,
-	0x16, 0xde, 0x9b, 0x66, 0x21, 0xc7, 0x76, 0x2e, 0xf6, 0x23, 0x81, 0x8c,
-	0xf6, 0x9d, 0x6e, 0xbb, 0xef, 0xe5, 0x4d, 0x7d, 0xed, 0x67, 0x9b, 0x56,
-	0xc4, 0xb7, 0x0d, 0xde, 0xf3, 0x1d, 0xe4, 0x9d, 0x7e, 0xc9, 0x1f, 0x53,
-	0x31, 0xd6, 0x4b, 0x85, 0x25, 0x83, 0xac, 0x16, 0xcf, 0x91, 0x49, 0x34,
-	0xda, 0x72, 0xea, 0xa4, 0xf5, 0x30, 0xc6, 0x2d, 0x34, 0x3c, 0xef, 0xa7,
-	0xd0, 0x9d, 0x8b, 0x5c, 0x77, 0x3b, 0xbf, 0xf1, 0xd6, 0x93, 0xc8, 0x21,
-	0x37, 0xce, 0xfc, 0xe6, 0xfd, 0xd4, 0xa5, 0xab, 0x88, 0x09, 0x74, 0xc6,
-	0x09, 0x51, 0x22, 0x1e, 0xe7, 0x3e, 0xfe, 0x06, 0xef, 0x79, 0x17, 0x8d,
-	0x3b, 0x78, 0x75, 0x99, 0xc7, 0x69, 0xdf, 0x39, 0xf6, 0xff, 0x3f, 0xd0,
-	0x2e, 0x1a, 0xd6, 0x9e, 0x38, 0xf2, 0xe7, 0xeb, 0xc4, 0xb1, 0x4f, 0x4e,
-	0x14, 0x9b, 0xba, 0x7a, 0x09, 0x6b, 0x8b, 0x8e, 0xc2, 0xdf, 0xd6, 0xf9,
-	0xfb, 0xa8, 0x76, 0x89, 0xda, 0xf7, 0x65, 0x90, 0xa7, 0xa3, 0xf2, 0x77,
-	0x52, 0xb5, 0x8a, 0xd8, 0x52, 0x70, 0x92, 0x98, 0xaf, 0x62, 0x2e, 0xc7,
-	0x05, 0x8f, 0x14, 0xd8, 0x50, 0xc1, 0x49, 0x27, 0xc6, 0x9a, 0x9e, 0xa7,
-	0x7c, 0x5e, 0xa0, 0x87, 0x32, 0x29, 0x1a, 0x73, 0xf8, 0xfe, 0xf7, 0x9b,
-	0xf4, 0x36, 0xec, 0xac, 0x78, 0x9e, 0x6b, 0x26, 0xf6, 0x29, 0x78, 0x77,
-	0xf8, 0xbe, 0xea, 0x14, 0x3d, 0xb4, 0x47, 0xcf, 0x5e, 0x22, 0xe0, 0xb3,
-	0x42, 0xfd, 0x48, 0x72, 0x53, 0xc7, 0xfd, 0xef, 0x6d, 0x8c, 0x6b, 0x9a,
-	0x96, 0xc0, 0x1b, 0xa7, 0x99, 0xa4, 0x95, 0x66, 0x8a, 0x56, 0xa1, 0x1f,
-	0xdb, 0xcc, 0x32, 0x7d, 0x03, 0x78, 0x2b, 0x66, 0x95, 0x94, 0x8c, 0xb5,
-	0xaf, 0x0b, 0x78, 0x67, 0x05, 0x3d, 0x15, 0x17, 0x18, 0x77, 0x5d, 0x2d,
-	0x03, 0x6f, 0xd6, 0xd1, 0x51, 0xa7, 0x9b, 0x8e, 0x61, 0xed, 0x7e, 0xe4,
-	0x1f, 0xdf, 0x72, 0xa8, 0x2c, 0x99, 0x29, 0x3a, 0x80, 0xf3, 0x8e, 0x36,
-	0x38, 0x57, 0x3b, 0x02, 0x5f, 0x23, 0xd0, 0xa3, 0x19, 0x8f, 0x1e, 0xdd,
-	0xa3, 0x5b, 0x71, 0x01, 0x7b, 0xae, 0xb0, 0x9e, 0xa0, 0xdf, 0x09, 0xce,
-	0x8d, 0xad, 0xf8, 0xba, 0x08, 0x7f, 0xfa, 0x0c, 0x65, 0xce, 0xad, 0xe5,
-	0xa6, 0x90, 0x9f, 0x8f, 0x36, 0xe9, 0x8b, 0x31, 0x9c, 0xf7, 0x36, 0xf8,
-	0x34, 0xea, 0xc8, 0x02, 0xf3, 0xe9, 0x58, 0xc0, 0x27, 0x8c, 0xf1, 0xb7,
-	0x23, 0xce, 0xd1, 0xf8, 0xec, 0x13, 0x74, 0xb6, 0xc1, 0x77, 0xdd, 0x27,
-	0xe8, 0x4a, 0xe3, 0x11, 0xba, 0x98, 0xe3, 0x5c, 0x07, 0xfb, 0xf8, 0x67,
-	0xa0, 0xcf, 0x3f, 0xa3, 0x9b, 0x8e, 0xfb, 0x72, 0xfa, 0x3f, 0xc3, 0x06,
-	0xd0, 0x70, 0x4c, 0x57, 0x00, 0x00, 0x00 };
+	0xad, 0x7b, 0x7f, 0x70, 0x9b, 0x75, 0x7a, 0xe7, 0xe7, 0xd5, 0x0f, 0x5b,
+	0xb2, 0x65, 0x59, 0x0e, 0x4a, 0x90, 0x77, 0xbd, 0x8d, 0x5e, 0xf4, 0xca,
+	0x16, 0xd8, 0x49, 0x5e, 0x25, 0xce, 0xc6, 0x59, 0xab, 0x44, 0x75, 0x1c,
+	0xdb, 0x71, 0x1c, 0x30, 0xc1, 0xdd, 0x3a, 0x3d, 0xae, 0xf1, 0x25, 0x26,
+	0x31, 0x10, 0xc0, 0xe9, 0xa6, 0x7b, 0x62, 0x8f, 0xd6, 0xc2, 0x76, 0x82,
+	0x43, 0x64, 0xbf, 0xce, 0x2a, 0x59, 0x87, 0x4e, 0x67, 0xd6, 0x60, 0x07,
+	0x07, 0x56, 0x8e, 0x60, 0xdb, 0x6b, 0xbb, 0x73, 0xbb, 0x83, 0x8e, 0x40,
+	0xf0, 0x72, 0x01, 0xb6, 0xfd, 0xa3, 0x47, 0x6f, 0xee, 0xda, 0xcc, 0x02,
+	0x59, 0xa0, 0x4b, 0xa0, 0x3b, 0x7b, 0x53, 0x67, 0x0b, 0xbc, 0xf7, 0x79,
+	0xde, 0x57, 0x4a, 0xb2, 0x94, 0x4e, 0x67, 0x3a, 0xe7, 0x19, 0x8f, 0xac,
+	0xf7, 0xc7, 0xf3, 0x7d, 0x7e, 0x3f, 0x9f, 0xe7, 0xf9, 0x7e, 0x5d, 0x0f,
+	0x54, 0xa0, 0xf8, 0x53, 0xc5, 0xdf, 0xe6, 0xe1, 0xd4, 0xe1, 0x8d, 0x6b,
+	0xf5, 0xb5, 0xd6, 0x05, 0x37, 0x5c, 0x72, 0xf3, 0xab, 0x0a, 0x30, 0xf0,
+	0x01, 0xfe, 0x5d, 0x3f, 0x5f, 0xf9, 0xf7, 0xbd, 0x66, 0xfd, 0x38, 0x81,
+	0x40, 0x89, 0x2f, 0xf9, 0x85, 0xc7, 0x91, 0x40, 0x6b, 0x9b, 0x06, 0x8f,
+	0x33, 0xf1, 0x67, 0x89, 0x7d, 0x1a, 0x90, 0xcc, 0x35, 0x86, 0xb7, 0xe2,
+	0x53, 0x33, 0x1d, 0x74, 0x41, 0xae, 0x7f, 0x25, 0xf1, 0xc9, 0xc8, 0x8f,
+	0x36, 0xa9, 0x1f, 0xcf, 0x3a, 0xe1, 0x09, 0x24, 0x4e, 0x23, 0x50, 0x0f,
+	0x4f, 0x1d, 0xdf, 0xf9, 0x93, 0x86, 0x6a, 0x27, 0xfc, 0x25, 0x5a, 0x2d,
+	0x18, 0x33, 0x90, 0xf6, 0x24, 0x86, 0x51, 0xbe, 0x11, 0x78, 0x37, 0x13,
+	0xd5, 0xc7, 0x80, 0x69, 0x47, 0x22, 0x1a, 0x7e, 0x09, 0x3a, 0x8e, 0xe4,
+	0xc3, 0x68, 0xe7, 0xef, 0x76, 0xe3, 0x33, 0x33, 0xec, 0x46, 0xda, 0xc9,
+	0xe7, 0xf6, 0x36, 0x03, 0xdb, 0x32, 0x3a, 0x8e, 0x1a, 0xf0, 0xd4, 0x26,
+	0x1e, 0xc5, 0x66, 0x7e, 0xfa, 0x13, 0x29, 0xbc, 0x31, 0x19, 0x09, 0x3f,
+	0x03, 0xb5, 0x5f, 0x73, 0xaa, 0x29, 0xa0, 0x71, 0x68, 0x50, 0x51, 0x07,
+	0xde, 0x54, 0xd4, 0xde, 0x49, 0x05, 0x1e, 0x85, 0xcf, 0x35, 0xe6, 0xe4,
+	0x33, 0x85, 0xdb, 0x72, 0x1e, 0x5c, 0x72, 0xca, 0xfa, 0xbf, 0x49, 0x7d,
+	0x2b, 0x70, 0x69, 0x2d, 0x18, 0x27, 0x0f, 0xee, 0x84, 0x82, 0xa7, 0x9b,
+	0xa3, 0xa1, 0x51, 0xc8, 0xfd, 0x30, 0xb6, 0xe6, 0xe5, 0x53, 0xa5, 0xd4,
+	0xa6, 0x39, 0xae, 0x9b, 0xe6, 0x19, 0xbd, 0x1c, 0xe9, 0x80, 0x1a, 0x02,
+	0x14, 0x8c, 0xea, 0x0e, 0x24, 0x03, 0x6d, 0x61, 0x17, 0xd4, 0xd0, 0xbd,
+	0xf8, 0x67, 0xca, 0x9c, 0x8c, 0xb9, 0x61, 0x3f, 0x3f, 0x80, 0x72, 0x14,
+	0x02, 0xb6, 0xd6, 0x9e, 0xce, 0x98, 0xe6, 0x05, 0xcd, 0x85, 0x33, 0xd4,
+	0xcf, 0x68, 0xee, 0x9f, 0xcd, 0x02, 0x75, 0x33, 0xae, 0x95, 0xd6, 0xf7,
+	0x60, 0x36, 0x60, 0x9a, 0x73, 0xbc, 0x77, 0x34, 0x57, 0xd2, 0xb3, 0x69,
+	0x3a, 0x34, 0xd3, 0xdc, 0xa7, 0xfd, 0xca, 0xdc, 0xfb, 0x6b, 0xcf, 0x9a,
+	0xe6, 0x13, 0xfa, 0x4d, 0x38, 0x9b, 0x6d, 0x57, 0xba, 0x17, 0x56, 0xf9,
+	0xb7, 0xcf, 0x98, 0xb8, 0xa0, 0x23, 0xe0, 0x48, 0x74, 0x28, 0xdb, 0x17,
+	0xba, 0x94, 0x6d, 0xf9, 0x5d, 0x4a, 0xc7, 0xdc, 0xef, 0x2a, 0x5d, 0x0b,
+	0x03, 0x4a, 0x67, 0x3e, 0x84, 0x79, 0x23, 0x88, 0x39, 0xa3, 0x5f, 0x69,
+	0x5f, 0xe8, 0x53, 0x6c, 0x39, 0x52, 0x4a, 0x5b, 0xbe, 0x44, 0xeb, 0xba,
+	0x1e, 0xb7, 0x67, 0x12, 0x98, 0x30, 0xca, 0xb9, 0xce, 0xb2, 0xf9, 0xa3,
+	0x86, 0x65, 0xca, 0xa9, 0xe3, 0x58, 0xfe, 0x09, 0xec, 0x9c, 0x31, 0xcd,
+	0x5c, 0x1c, 0xc8, 0xe5, 0x81, 0xef, 0x19, 0x91, 0xde, 0x21, 0xc5, 0x34,
+	0x3b, 0xa3, 0xe6, 0xea, 0xcb, 0x7a, 0x63, 0xec, 0x65, 0xfc, 0x93, 0x39,
+	0x1b, 0x44, 0xda, 0x47, 0x1a, 0xc7, 0x69, 0xb3, 0xfb, 0x27, 0xe1, 0x29,
+	0x4f, 0x8c, 0xe3, 0x67, 0x19, 0x78, 0xca, 0x12, 0x69, 0x5c, 0xc8, 0x8c,
+	0x06, 0x3c, 0x88, 0x84, 0xb6, 0x2b, 0xe9, 0x94, 0x03, 0xea, 0xf0, 0xdb,
+	0x50, 0xc3, 0xb4, 0xc7, 0xd2, 0x79, 0x45, 0x2d, 0xbc, 0x0c, 0x35, 0xf9,
+	0x2b, 0x45, 0xed, 0xaa, 0x75, 0x22, 0xe9, 0x88, 0x7a, 0xf0, 0xa3, 0x06,
+	0xb1, 0xc9, 0x38, 0xd6, 0x5a, 0xb6, 0x49, 0xe3, 0xd6, 0x6b, 0xb6, 0x49,
+	0x60, 0x94, 0x7c, 0x1d, 0x25, 0x5f, 0xaf, 0xe8, 0x6a, 0xe8, 0x69, 0x98,
+	0xab, 0x07, 0x75, 0xb9, 0x97, 0xc0, 0x78, 0xde, 0x0c, 0xfb, 0x13, 0x97,
+	0xc8, 0x2f, 0xd2, 0x5f, 0x4a, 0x78, 0xd2, 0xd5, 0x89, 0x4f, 0xcd, 0xd7,
+	0x37, 0x86, 0xf0, 0x62, 0x3e, 0x88, 0x17, 0xf2, 0x01, 0x3c, 0x9f, 0x6f,
+	0x87, 0x91, 0x87, 0x7f, 0x67, 0xfe, 0x8b, 0xfc, 0xd8, 0x84, 0x8f, 0xcf,
+	0x93, 0x6f, 0xff, 0x8e, 0xbc, 0x6b, 0xa0, 0x2c, 0x81, 0xde, 0x1f, 0x67,
+	0x46, 0xcc, 0x0a, 0x0d, 0x03, 0x35, 0x09, 0x2d, 0x79, 0x9b, 0xe2, 0x6b,
+	0xa1, 0x1f, 0xf6, 0xbe, 0x9a, 0x6b, 0x71, 0x69, 0x53, 0x5e, 0xb8, 0xa9,
+	0xff, 0x6d, 0x79, 0xd3, 0x1c, 0xd3, 0x0f, 0xad, 0xdb, 0xdb, 0xf2, 0xa7,
+	0x85, 0x5e, 0xad, 0x07, 0xe9, 0xfc, 0x20, 0xe0, 0x4f, 0xf0, 0x93, 0xa1,
+	0xb8, 0xab, 0xa9, 0x3d, 0x7c, 0xee, 0x41, 0x97, 0xed, 0xcf, 0xe4, 0x81,
+	0x7a, 0x7f, 0xc1, 0x20, 0x0f, 0xc6, 0xb4, 0x1f, 0x15, 0x61, 0xca, 0xf7,
+	0x13, 0xf2, 0x19, 0xc3, 0xf7, 0xf3, 0x1a, 0x79, 0x6b, 0x22, 0x8f, 0x61,
+	0xf2, 0xe7, 0xc1, 0xde, 0xac, 0x3a, 0x9d, 0x86, 0x3a, 0x31, 0x8b, 0x35,
+	0x48, 0x06, 0x03, 0xf4, 0xc1, 0x3f, 0x86, 0x4d, 0xa3, 0x07, 0x53, 0x06,
+	0xd6, 0x07, 0x12, 0xb4, 0x6f, 0x1c, 0x8f, 0x96, 0x21, 0x3a, 0xf0, 0xb1,
+	0xa2, 0xe0, 0xf5, 0x68, 0x0f, 0x26, 0x29, 0x4f, 0x4f, 0xce, 0x8b, 0x07,
+	0xb2, 0x15, 0xb8, 0x2f, 0x6b, 0xe2, 0xfe, 0x38, 0x12, 0x15, 0x94, 0x27,
+	0x16, 0x8f, 0x86, 0xdf, 0x83, 0x0b, 0xed, 0xb9, 0x1e, 0xc6, 0xd2, 0x56,
+	0x24, 0xcb, 0x3c, 0xd8, 0x9a, 0xf3, 0x31, 0x1e, 0x93, 0x38, 0x3d, 0xe3,
+	0x81, 0x7b, 0x83, 0x03, 0xb3, 0xc1, 0x32, 0xc4, 0xea, 0x1d, 0xfc, 0x0d,
+	0xfa, 0xdb, 0x66, 0xea, 0xfc, 0xdb, 0x0c, 0x17, 0x0e, 0x18, 0x0e, 0x8c,
+	0x64, 0x4d, 0xb3, 0x5d, 0x37, 0x71, 0x75, 0x43, 0x00, 0x3f, 0xa0, 0xfe,
+	0x0e, 0x19, 0x21, 0x9c, 0xcd, 0x3f, 0x4e, 0x5e, 0x82, 0x36, 0xbf, 0x06,
+	0x79, 0x37, 0xc8, 0xbb, 0x41, 0xbe, 0x0d, 0xe1, 0xf3, 0x3c, 0x63, 0x46,
+	0xa7, 0x5c, 0x5e, 0xf2, 0x50, 0x89, 0x21, 0xf2, 0x11, 0x89, 0x9b, 0x70,
+	0xc4, 0xd5, 0xf4, 0x5e, 0x26, 0xaf, 0xd5, 0xf5, 0xa6, 0xf9, 0xf1, 0x06,
+	0x91, 0x85, 0x36, 0x77, 0xf4, 0x48, 0x8c, 0xfe, 0x56, 0x15, 0xe3, 0xea,
+	0x6f, 0xa9, 0xb7, 0x27, 0xf3, 0x5e, 0xa4, 0xb2, 0x96, 0xdf, 0x1e, 0x2e,
+	0x23, 0xdf, 0xc2, 0x57, 0x5e, 0x8b, 0x32, 0x46, 0xa3, 0xfd, 0x8c, 0x51,
+	0xec, 0x20, 0xcf, 0xf7, 0x1b, 0xd1, 0x96, 0x5d, 0x8a, 0x0b, 0x9d, 0xb9,
+	0xa0, 0xbf, 0xfd, 0x06, 0x3e, 0x29, 0xaf, 0xc4, 0x20, 0x65, 0x0d, 0x90,
+	0xbf, 0x20, 0xf6, 0x91, 0xcf, 0x17, 0x8a, 0x7c, 0xce, 0xe5, 0x65, 0xad,
+	0xcf, 0xf3, 0x5a, 0xe2, 0x13, 0xe9, 0x15, 0x89, 0xa0, 0x82, 0x0a, 0x1f,
+	0x76, 0xe5, 0xde, 0xa2, 0x2d, 0xea, 0xf0, 0xa7, 0xb4, 0xc1, 0x8b, 0x8c,
+	0x91, 0xef, 0x5f, 0xf3, 0x17, 0xb1, 0xc7, 0x63, 0xb4, 0x83, 0x7a, 0x3a,
+	0x0d, 0x1f, 0x06, 0xf2, 0x49, 0x1c, 0x99, 0x41, 0x72, 0x5e, 0x3f, 0xce,
+	0x78, 0x5f, 0x05, 0xa7, 0x56, 0x9e, 0x0c, 0x68, 0x15, 0xd8, 0x37, 0x17,
+	0xc4, 0x70, 0xbe, 0x0d, 0x46, 0x36, 0x88, 0x83, 0xf4, 0xcd, 0x2b, 0xf1,
+	0xe4, 0xfd, 0x7e, 0x08, 0xef, 0x41, 0x3c, 0xc0, 0x77, 0x9e, 0x98, 0x09,
+	0x62, 0x88, 0x3a, 0xda, 0x1e, 0x8f, 0xb6, 0x78, 0x79, 0xed, 0x00, 0xaf,
+	0x1d, 0xa5, 0xfe, 0xcf, 0xeb, 0x93, 0x18, 0xe8, 0x55, 0x63, 0x40, 0x10,
+	0xfb, 0x0d, 0x04, 0xe8, 0xc2, 0x8f, 0x31, 0xbf, 0xc5, 0xce, 0xf3, 0xfb,
+	0xbd, 0xf9, 0x0a, 0xca, 0xe9, 0x47, 0x48, 0xfb, 0xc4, 0x74, 0x37, 0x9b,
+	0xe6, 0x77, 0xf5, 0xe8, 0xd2, 0x4f, 0x9d, 0x2e, 0x3c, 0x92, 0x77, 0x20,
+	0x35, 0x57, 0x81, 0xdf, 0xcf, 0xba, 0x70, 0x57, 0x7d, 0x05, 0x0e, 0xcd,
+	0x25, 0x31, 0x36, 0x53, 0x81, 0xc1, 0x2c, 0x56, 0xef, 0xd7, 0xc7, 0x6a,
+	0xca, 0xa0, 0x2e, 0xb7, 0x23, 0x86, 0xab, 0xb4, 0xc3, 0x23, 0x73, 0x3e,
+	0x7f, 0xff, 0x4c, 0x00, 0xa9, 0x05, 0x2f, 0x9f, 0x77, 0xf0, 0xf9, 0x72,
+	0xe8, 0xeb, 0x23, 0xa9, 0x00, 0x84, 0xc7, 0x4a, 0x3c, 0x34, 0xe7, 0xc5,
+	0x83, 0xd9, 0x00, 0x0e, 0xce, 0x34, 0x63, 0xda, 0x48, 0xe2, 0x18, 0x73,
+	0xc7, 0xf7, 0xe2, 0x6a, 0xef, 0x41, 0x45, 0x4d, 0x6e, 0x53, 0x92, 0x68,
+	0x88, 0xbb, 0x71, 0x89, 0x79, 0xc8, 0x1d, 0x6f, 0x6c, 0x79, 0x9e, 0xb9,
+	0xa1, 0x2c, 0x11, 0xe4, 0x77, 0x75, 0x82, 0x31, 0x9b, 0x74, 0x3b, 0x36,
+	0x00, 0x2b, 0x25, 0x7e, 0x83, 0xfe, 0x6e, 0x23, 0xe0, 0xef, 0xce, 0xd7,
+	0xf9, 0xb7, 0x1b, 0x21, 0xff, 0x76, 0xc6, 0xd7, 0x36, 0xf1, 0x47, 0xc3,
+	0x83, 0xe3, 0xf1, 0x4f, 0xcd, 0x81, 0x1a, 0x2b, 0x9f, 0xf9, 0x77, 0xce,
+	0xa8, 0xe9, 0x59, 0xa8, 0x3a, 0xab, 0x01, 0x26, 0x17, 0x5c, 0xb4, 0x9f,
+	0x82, 0x1a, 0xad, 0x99, 0x79, 0x3c, 0x80, 0x87, 0x98, 0x53, 0xfe, 0x9a,
+	0x39, 0x65, 0x70, 0x2a, 0x12, 0x98, 0x86, 0x97, 0xfa, 0x06, 0xf6, 0x9e,
+	0x0b, 0xd2, 0xe6, 0x5d, 0x78, 0x9c, 0x7c, 0x6d, 0xdf, 0x18, 0xc4, 0x7d,
+	0xf9, 0x80, 0xbf, 0x8b, 0xf6, 0x7b, 0x2f, 0x17, 0xf2, 0x6f, 0xa5, 0x2d,
+	0xdf, 0xce, 0xa9, 0xe1, 0x02, 0xfe, 0xaf, 0xf8, 0x53, 0x0c, 0x0e, 0x60,
+	0xff, 0x94, 0x1b, 0x85, 0xa0, 0xac, 0x45, 0x9d, 0x1b, 0x2f, 0x9a, 0x3e,
+	0x4d, 0x3b, 0x7d, 0x90, 0xba, 0xfe, 0x46, 0xde, 0x87, 0x07, 0x0d, 0x35,
+	0xf6, 0x7d, 0xc5, 0x47, 0x9d, 0x7a, 0xa8, 0x07, 0x26, 0x98, 0x55, 0xf2,
+	0x5c, 0x1c, 0xe1, 0x55, 0x76, 0xae, 0x3d, 0x34, 0x27, 0x7e, 0x42, 0xdb,
+	0x1b, 0xf4, 0x01, 0xfa, 0xcf, 0xf7, 0xaf, 0xc5, 0xaa, 0x1a, 0x48, 0x5b,
+	0xb9, 0x3b, 0x46, 0x7f, 0xb1, 0x75, 0x74, 0x62, 0x46, 0xf4, 0xa0, 0x4e,
+	0xc3, 0x91, 0xc4, 0xba, 0xf5, 0x7f, 0x6d, 0x5e, 0x5a, 0x29, 0xfa, 0x08,
+	0x60, 0x84, 0x3a, 0x3c, 0x6d, 0x98, 0xe6, 0xd5, 0x0d, 0x1f, 0x9a, 0x2d,
+	0x37, 0x8b, 0x5e, 0x44, 0xd6, 0x1f, 0x28, 0x52, 0x47, 0x6a, 0x34, 0xff,
+	0xff, 0x07, 0x5f, 0xf9, 0xa6, 0x39, 0x60, 0xc9, 0x27, 0xfe, 0xe2, 0xa2,
+	0x2f, 0x3e, 0x4e, 0xda, 0x0e, 0x0c, 0x90, 0xde, 0xc3, 0x86, 0xf9, 0x51,
+	0x6d, 0xe2, 0x33, 0xb3, 0x65, 0x93, 0x36, 0xbc, 0xac, 0xfc, 0x4f, 0x5e,
+	0x0f, 0xe2, 0xa1, 0x7c, 0x0b, 0x75, 0xd7, 0x8e, 0x27, 0xa8, 0xc3, 0xa3,
+	0x86, 0xe4, 0xc4, 0x10, 0xfd, 0xb9, 0x8e, 0xfe, 0xed, 0x52, 0xb6, 0x19,
+	0x39, 0x6c, 0x9f, 0x4c, 0xa3, 0x93, 0xfe, 0xbe, 0x94, 0x89, 0xb4, 0x3c,
+	0x0b, 0x35, 0x4d, 0x19, 0xfc, 0x5d, 0xd4, 0x71, 0xbb, 0xa1, 0x76, 0x89,
+	0x4d, 0xdb, 0x99, 0x97, 0x5e, 0xca, 0x84, 0xfc, 0x6d, 0x79, 0xd1, 0x77,
+	0x9d, 0x7f, 0x6b, 0xfe, 0xab, 0xb4, 0xbd, 0x82, 0xcd, 0x6b, 0x3c, 0xcc,
+	0x33, 0x77, 0xc1, 0xb6, 0xab, 0x6d, 0xbb, 0xd7, 0xe3, 0x8d, 0x03, 0x1f,
+	0x32, 0x3f, 0xa5, 0x57, 0xda, 0xd7, 0x52, 0xbc, 0x56, 0xbd, 0x01, 0xfe,
+	0x3b, 0xe9, 0x07, 0x7b, 0xe8, 0x07, 0x57, 0x37, 0x7c, 0x6a, 0x86, 0x6f,
+	0xb2, 0xfd, 0xa0, 0x6d, 0xc6, 0xe5, 0xef, 0xa0, 0x9e, 0xb6, 0xe9, 0x0a,
+	0xe6, 0xf4, 0x0c, 0x06, 0xae, 0x61, 0x87, 0xe4, 0xec, 0x59, 0x3d, 0xc9,
+	0x3c, 0xf2, 0x9b, 0x70, 0xd5, 0x60, 0xf6, 0x59, 0xfd, 0x71, 0x84, 0x6d,
+	0xdf, 0xc1, 0xc1, 0xac, 0x17, 0xe9, 0xbb, 0x02, 0x98, 0x6f, 0x08, 0xe0,
+	0x61, 0xd2, 0xbe, 0x12, 0x6f, 0x1c, 0x7a, 0x83, 0x3a, 0x98, 0xad, 0x91,
+	0x6b, 0x49, 0xfc, 0xa5, 0xfe, 0x28, 0x70, 0x93, 0xbd, 0xf6, 0x82, 0xc4,
+	0xe8, 0x42, 0x33, 0x8e, 0xe6, 0xfb, 0x15, 0x3b, 0x6f, 0xaa, 0x5d, 0x49,
+	0xfc, 0xc4, 0x94, 0x5c, 0xba, 0x60, 0x30, 0xc7, 0x51, 0x1f, 0xe3, 0xf4,
+	0xa3, 0xd1, 0x5c, 0x9d, 0xbf, 0x93, 0x7e, 0xf4, 0x78, 0x4e, 0x64, 0x8a,
+	0xea, 0xba, 0xb3, 0x96, 0xb5, 0x99, 0xfa, 0x31, 0xac, 0x9a, 0x5f, 0x1d,
+	0xd0, 0x8e, 0x61, 0xda, 0xe2, 0x2d, 0xa5, 0xf4, 0x13, 0x63, 0x30, 0x64,
+	0xaa, 0xcb, 0xb5, 0x43, 0x78, 0xdc, 0xba, 0x16, 0xf4, 0xef, 0x9e, 0x49,
+	0x3a, 0x1c, 0x1a, 0x02, 0x95, 0x89, 0x76, 0x65, 0x37, 0xeb, 0x6e, 0xc7,
+	0x4c, 0x87, 0xd2, 0xb1, 0x20, 0x31, 0xd0, 0xa5, 0x6c, 0x67, 0xcd, 0x4d,
+	0xb2, 0xe6, 0x26, 0x59, 0x73, 0x93, 0xe4, 0x23, 0xc9, 0x5a, 0xdb, 0x96,
+	0x4f, 0x29, 0x3b, 0x44, 0xff, 0xf4, 0xaf, 0xe7, 0x0d, 0x1b, 0x47, 0x30,
+	0x07, 0xf9, 0x3b, 0xf3, 0x6b, 0x1d, 0x36, 0xb6, 0x4b, 0x29, 0x45, 0x2c,
+	0xe3, 0xa9, 0xd0, 0x58, 0xcb, 0x8c, 0x94, 0xd2, 0xcd, 0x7a, 0xdb, 0x6f,
+	0xe9, 0x32, 0x32, 0xfc, 0x0e, 0xeb, 0xec, 0xeb, 0xac, 0xb3, 0xb9, 0x38,
+	0xe3, 0x6a, 0xcd, 0x55, 0x73, 0x60, 0xa5, 0x5d, 0x13, 0xc6, 0xc8, 0xef,
+	0x77, 0x69, 0xb3, 0x02, 0x6b, 0x69, 0xbb, 0x53, 0xc1, 0x7e, 0x0d, 0xd5,
+	0xb5, 0xcc, 0xa9, 0x47, 0xf3, 0xac, 0x03, 0x7a, 0xa4, 0xe5, 0x7d, 0x2a,
+	0xf6, 0xa8, 0xe6, 0xc6, 0xd5, 0x9b, 0x08, 0x76, 0xb4, 0x36, 0x1c, 0xcf,
+	0x96, 0x63, 0x28, 0x9e, 0x5c, 0xe1, 0x21, 0x56, 0xe9, 0x6a, 0xc6, 0xa3,
+	0x5c, 0x5a, 0x09, 0x25, 0xa2, 0xf4, 0x1b, 0x24, 0xa7, 0x58, 0x27, 0x26,
+	0x8d, 0xaf, 0x22, 0xc7, 0x7a, 0x3a, 0xaf, 0xbb, 0xf0, 0x7a, 0x6e, 0x2d,
+	0xf3, 0x5c, 0x54, 0xf7, 0x29, 0x15, 0x8c, 0xdf, 0x04, 0x32, 0x86, 0xe4,
+	0x27, 0xd3, 0x9c, 0x17, 0x1e, 0xa2, 0xd1, 0xe4, 0x28, 0x24, 0x67, 0x99,
+	0xab, 0xef, 0x8d, 0x97, 0x61, 0x73, 0xd4, 0x8f, 0xd5, 0xda, 0x80, 0xd2,
+	0x95, 0x8f, 0xea, 0xe7, 0xf1, 0xbb, 0xca, 0x9e, 0x85, 0x04, 0x63, 0xbb,
+	0x9f, 0xba, 0xa9, 0xc0, 0xa5, 0xa0, 0xf0, 0x88, 0x6a, 0xb7, 0xe6, 0xc0,
+	0xbb, 0x77, 0x2b, 0x08, 0x68, 0x49, 0x5c, 0x68, 0x0e, 0xd0, 0xaf, 0xba,
+	0x88, 0x31, 0xc2, 0x70, 0x2e, 0x86, 0xfc, 0x3b, 0x68, 0x8b, 0xca, 0xc5,
+	0x3a, 0xda, 0x87, 0xbe, 0x47, 0x1d, 0xb6, 0x51, 0x87, 0xdd, 0x73, 0x08,
+	0x54, 0x24, 0xfa, 0x94, 0x8e, 0x7c, 0xbb, 0xd2, 0x9e, 0x57, 0xa9, 0x27,
+	0xd1, 0xc9, 0x37, 0x89, 0x95, 0xc4, 0x57, 0x4a, 0xb6, 0x14, 0x7f, 0xbd,
+	0xd1, 0x9e, 0xfd, 0x0e, 0x89, 0xb9, 0xcd, 0x6b, 0x12, 0x8c, 0x47, 0x07,
+	0xf9, 0x12, 0x1e, 0x3c, 0xa8, 0x6e, 0x30, 0x57, 0x5f, 0x89, 0x33, 0x79,
+	0x56, 0x24, 0x30, 0x95, 0xef, 0xa1, 0x5d, 0x36, 0x14, 0xfd, 0x2b, 0xe0,
+	0xdf, 0x36, 0xd3, 0xae, 0x6c, 0x5b, 0x58, 0xe1, 0xef, 0xa5, 0x0d, 0x7b,
+	0x17, 0x42, 0x42, 0x97, 0xeb, 0x8b, 0x6d, 0x93, 0x70, 0x68, 0xff, 0x9a,
+	0x2d, 0xbf, 0x41, 0x5a, 0x62, 0x4f, 0x6f, 0xc9, 0x4f, 0xfd, 0x7b, 0x66,
+	0x92, 0x78, 0x77, 0x83, 0x9b, 0x35, 0xb5, 0x84, 0x29, 0xaa, 0x8a, 0x9f,
+	0xa7, 0x1d, 0xd0, 0x52, 0x4a, 0x97, 0xf8, 0x91, 0xdb, 0x5e, 0xf3, 0xce,
+	0x19, 0xb8, 0x09, 0x15, 0xc2, 0x4e, 0x62, 0xba, 0x0f, 0xe3, 0xd1, 0x81,
+	0x73, 0x4a, 0x8f, 0xd2, 0x93, 0x97, 0x1a, 0x6c, 0xfb, 0x54, 0x1b, 0x7d,
+	0xaa, 0x9d, 0xfc, 0xb4, 0xd3, 0xa7, 0xba, 0xc9, 0x4f, 0xb7, 0xe5, 0x53,
+	0xe2, 0x9b, 0xbf, 0xce, 0xcb, 0xd6, 0xfc, 0x1e, 0x4b, 0x2f, 0x3b, 0xf8,
+	0x6e, 0x17, 0xe5, 0xe8, 0xe2, 0x7b, 0x7b, 0xf8, 0xde, 0x9e, 0x85, 0xff,
+	0x2d, 0xfc, 0x51, 0x16, 0x3b, 0xf6, 0xaf, 0xd7, 0x34, 0xc9, 0x01, 0xaf,
+	0x15, 0x31, 0x05, 0xd2, 0x8e, 0x84, 0xe4, 0x88, 0x61, 0xf4, 0x36, 0xc3,
+	0xb3, 0x22, 0xf1, 0x93, 0xd6, 0x5d, 0xf5, 0xcc, 0x67, 0xcc, 0xa7, 0x9e,
+	0x29, 0x62, 0x69, 0xe6, 0xe8, 0xf9, 0x16, 0x05, 0x63, 0xfa, 0xcd, 0x8c,
+	0x53, 0x1d, 0x13, 0x79, 0xb5, 0x2b, 0xcc, 0x7b, 0x4d, 0x93, 0x82, 0xf1,
+	0x0f, 0xa2, 0x8d, 0xb8, 0x2e, 0x94, 0x18, 0x42, 0xc8, 0x88, 0x84, 0x26,
+	0x14, 0x75, 0x68, 0x2b, 0xd4, 0x25, 0xd6, 0x86, 0xd4, 0x9c, 0xa2, 0x0e,
+	0xd7, 0x3a, 0xd5, 0xe4, 0x9b, 0x16, 0xbe, 0x3e, 0x88, 0x35, 0x16, 0x86,
+	0x1b, 0x42, 0x8c, 0x58, 0x76, 0x07, 0x69, 0x1e, 0xd8, 0xac, 0xe0, 0xb2,
+	0xfe, 0x21, 0xed, 0xa8, 0x26, 0xd3, 0x8a, 0x8e, 0x0c, 0xf3, 0x44, 0x68,
+	0x4a, 0xb0, 0xfa, 0x41, 0x62, 0x75, 0x78, 0x7c, 0x7c, 0x36, 0x33, 0x19,
+	0x49, 0x79, 0x9c, 0x6a, 0x8c, 0x38, 0x3d, 0x49, 0x9a, 0x7a, 0x9e, 0xf8,
+	0x9d, 0x6b, 0x84, 0xf7, 0x17, 0x69, 0x46, 0x8b, 0x34, 0xb5, 0x1c, 0x18,
+	0x37, 0x13, 0xe8, 0x8c, 0xb2, 0x56, 0x30, 0xe7, 0x1d, 0x93, 0x9e, 0x80,
+	0xf4, 0xca, 0xa7, 0x74, 0x7e, 0x4f, 0x29, 0xbb, 0x25, 0xa6, 0xca, 0x6d,
+	0x2b, 0x54, 0x73, 0x8d, 0xaa, 0xc4, 0x61, 0x2c, 0x5a, 0x6b, 0x0c, 0xcb,
+	0x1a, 0xc3, 0x3f, 0x53, 0xd4, 0xd8, 0x39, 0x45, 0x72, 0x75, 0x63, 0xff,
+	0x39, 0xc6, 0xd0, 0x51, 0x45, 0x6d, 0x39, 0x4e, 0xf1, 0xbd, 0x9a, 0xd0,
+	0x3f, 0x5c, 0x5c, 0x67, 0x18, 0x0d, 0x39, 0xc6, 0x67, 0xde, 0xa3, 0x6c,
+	0xcd, 0xb6, 0x61, 0x6c, 0xae, 0x0d, 0xa3, 0x59, 0x05, 0x7b, 0xf4, 0x95,
+	0xb8, 0x74, 0xb3, 0xd5, 0xa7, 0x54, 0xad, 0xd6, 0x6a, 0x31, 0x12, 0x40,
+	0xb5, 0x43, 0xfb, 0x0a, 0xf6, 0x16, 0x31, 0x7e, 0xe7, 0x89, 0x5e, 0xe6,
+	0x7d, 0x13, 0xef, 0x33, 0x96, 0x22, 0x35, 0x48, 0xba, 0x13, 0x2d, 0xc4,
+	0xe3, 0x75, 0x4e, 0x3b, 0xde, 0xff, 0xc9, 0x63, 0xdb, 0x40, 0xf4, 0xff,
+	0xf9, 0x7b, 0x6d, 0x78, 0x32, 0x5b, 0x86, 0x96, 0x0d, 0xb8, 0x2b, 0x84,
+	0x2a, 0x07, 0x6b, 0xdc, 0x5b, 0xbb, 0x94, 0x14, 0xef, 0x59, 0xcf, 0x7a,
+	0xbe, 0x9c, 0xe8, 0x4d, 0xfc, 0x97, 0x06, 0xb9, 0x6e, 0xe5, 0x8d, 0x1b,
+	0xae, 0x0f, 0x7f, 0xc1, 0x75, 0x05, 0xcf, 0x31, 0x91, 0x7d, 0x8f, 0x35,
+	0x25, 0x97, 0x31, 0xe1, 0x4c, 0xb8, 0x30, 0x34, 0x19, 0xc6, 0xc1, 0xc5,
+	0x20, 0x16, 0x33, 0xea, 0xc0, 0x25, 0xf6, 0x0f, 0x7b, 0x9b, 0x35, 0x3c,
+	0xb8, 0x18, 0xc2, 0x42, 0x06, 0xa6, 0x37, 0xa1, 0x15, 0xbc, 0x4a, 0x0c,
+	0x07, 0x16, 0xeb, 0x70, 0x2e, 0xa3, 0x2d, 0x8d, 0x2a, 0xd1, 0x54, 0x2d,
+	0x71, 0xc7, 0xc3, 0x8b, 0x4d, 0x78, 0x68, 0xd1, 0xc3, 0x77, 0x4c, 0x74,
+	0xc7, 0xeb, 0xf8, 0xbc, 0x03, 0xcf, 0x9e, 0x34, 0x4d, 0xc1, 0x5d, 0x43,
+	0x8b, 0xc0, 0xc2, 0x34, 0x6b, 0xd1, 0x19, 0xd6, 0xa5, 0xa7, 0x80, 0x03,
+	0x4f, 0x39, 0x30, 0x37, 0x6d, 0x62, 0xaf, 0x3e, 0x5a, 0xeb, 0xa0, 0xc3,
+	0x0f, 0xb0, 0x6e, 0xb8, 0x59, 0x03, 0xef, 0x0d, 0xd8, 0xf9, 0xfc, 0x12,
+	0xf3, 0xd4, 0xfd, 0x4f, 0xc5, 0xf0, 0x56, 0x26, 0x8d, 0x6e, 0xe2, 0xf3,
+	0x14, 0x79, 0x79, 0x33, 0xc3, 0x3a, 0xb6, 0xa8, 0xe3, 0x8d, 0x8c, 0x87,
+	0xeb, 0x34, 0xe1, 0xe5, 0x8c, 0x3c, 0x23, 0xcf, 0xfa, 0x30, 0x48, 0x5e,
+	0x5e, 0xcf, 0x84, 0xb8, 0x66, 0x10, 0x3f, 0xe6, 0x73, 0xf7, 0x2d, 0x6a,
+	0xac, 0x5b, 0x1e, 0xae, 0x1b, 0xc6, 0xab, 0x19, 0x1f, 0x79, 0x0d, 0xb2,
+	0x56, 0x0d, 0x62, 0x2c, 0xd3, 0xb8, 0xb4, 0x95, 0x89, 0xda, 0xae, 0x35,
+	0x72, 0xed, 0x1d, 0xb3, 0xc7, 0x8a, 0x45, 0x59, 0xa7, 0xb4, 0xee, 0x20,
+	0x46, 0x33, 0x6f, 0x38, 0x4b, 0xfd, 0xf4, 0x73, 0xd3, 0xcb, 0x16, 0xf6,
+	0x7b, 0xd6, 0xe0, 0xdf, 0x73, 0xc0, 0x39, 0x23, 0x6d, 0x56, 0x27, 0x88,
+	0x75, 0x59, 0xa3, 0x7e, 0xba, 0xb1, 0x89, 0xeb, 0x6a, 0x03, 0x2f, 0x29,
+	0xd2, 0xef, 0xb8, 0x10, 0x7e, 0x4a, 0xf4, 0x45, 0xcc, 0xbc, 0x00, 0xfc,
+	0x25, 0xf1, 0x67, 0xc3, 0xa4, 0x2a, 0x7e, 0xdf, 0x4f, 0x5c, 0xd3, 0x5b,
+	0x40, 0x7d, 0xec, 0x41, 0x8c, 0x98, 0x65, 0xc4, 0xe7, 0xd5, 0xc4, 0xb5,
+	0x8b, 0x4d, 0xac, 0x53, 0x1b, 0x4d, 0xf3, 0x6f, 0x9b, 0x61, 0x3a, 0x12,
+	0x9a, 0x5e, 0xeb, 0x2c, 0x7c, 0xa5, 0x0a, 0xda, 0x92, 0x5f, 0xd1, 0x0a,
+	0x3f, 0x45, 0x74, 0xf8, 0x3c, 0x44, 0xaf, 0xc0, 0xda, 0x45, 0x17, 0xd6,
+	0x51, 0x9e, 0x6d, 0x93, 0x5c, 0x9b, 0xf8, 0x24, 0x4a, 0x99, 0x76, 0x4e,
+	0x12, 0x73, 0x69, 0x3e, 0xac, 0xa1, 0x8e, 0x87, 0x4e, 0x99, 0x66, 0x39,
+	0x75, 0xdc, 0x40, 0xfb, 0xec, 0x3f, 0x61, 0xe2, 0x25, 0xfd, 0x25, 0xea,
+	0x54, 0x21, 0x6e, 0x6c, 0xe6, 0x3b, 0x41, 0x3e, 0xef, 0xc1, 0x81, 0x49,
+	0xe9, 0x97, 0xea, 0xf8, 0xcc, 0x45, 0x1c, 0xcf, 0xc4, 0xd0, 0x44, 0xfd,
+	0x85, 0x49, 0xb3, 0x91, 0xef, 0x84, 0x49, 0x2f, 0xbc, 0xf8, 0x35, 0x6c,
+	0x3f, 0xa5, 0x40, 0x8b, 0x8a, 0x0e, 0xbe, 0x86, 0xf6, 0x33, 0x5f, 0x94,
+	0x13, 0x98, 0xa5, 0xa6, 0xd5, 0x89, 0x02, 0xf1, 0x77, 0x55, 0x62, 0x04,
+	0xac, 0xdf, 0x78, 0x73, 0x56, 0xc1, 0xd4, 0x34, 0xfb, 0xbd, 0x8d, 0x30,
+	0x2b, 0x28, 0xd3, 0x1b, 0xb3, 0xbf, 0x81, 0x67, 0x4e, 0x52, 0x0f, 0x4f,
+	0x07, 0xf1, 0xbd, 0x8c, 0x0b, 0xb7, 0x4e, 0x09, 0xa6, 0xd3, 0x62, 0x07,
+	0x15, 0xe9, 0x8f, 0xa4, 0x6f, 0x89, 0x86, 0xdd, 0x8a, 0x03, 0xf5, 0xcf,
+	0xb8, 0xa0, 0x9d, 0x0b, 0xc3, 0x5d, 0xef, 0x81, 0x56, 0xff, 0xfb, 0xcc,
+	0x35, 0x0e, 0x94, 0xb1, 0x97, 0xed, 0xfc, 0x76, 0x8c, 0xd7, 0x82, 0xbc,
+	0x86, 0xdf, 0x28, 0x87, 0x73, 0x95, 0x93, 0x35, 0xbc, 0x4c, 0x23, 0x1e,
+	0x73, 0x99, 0xa6, 0x93, 0xb5, 0x61, 0xf7, 0x77, 0x4c, 0x33, 0xb2, 0x41,
+	0x9e, 0x0f, 0x20, 0x72, 0x4e, 0xe3, 0x73, 0x76, 0xbd, 0xbc, 0x8e, 0xc7,
+	0x9c, 0xf4, 0x23, 0x89, 0x55, 0xd6, 0x7b, 0xab, 0x87, 0xb2, 0x71, 0xfb,
+	0x0b, 0x79, 0xc1, 0x36, 0x61, 0x4b, 0x86, 0xb3, 0xd3, 0x0a, 0x73, 0x76,
+	0x82, 0xcf, 0x6e, 0x81, 0x33, 0xae, 0x4e, 0xa4, 0xe9, 0x07, 0x7b, 0x03,
+	0x2d, 0x78, 0xce, 0x70, 0xa3, 0x52, 0x5b, 0x85, 0x07, 0x7a, 0x03, 0x78,
+	0x8e, 0x7d, 0x01, 0x6d, 0x16, 0x2b, 0x80, 0x8d, 0xb4, 0x9f, 0xf4, 0x1c,
+	0x3f, 0x84, 0xf6, 0x6d, 0x07, 0xf3, 0x9c, 0xd3, 0xca, 0x73, 0x65, 0xf5,
+	0x40, 0x21, 0xe7, 0xc2, 0x05, 0xcd, 0xc6, 0x84, 0x2f, 0x58, 0x35, 0x5b,
+	0x0d, 0x14, 0xae, 0x61, 0x41, 0xb5, 0x25, 0xa9, 0x90, 0x19, 0xbf, 0xe8,
+	0xae, 0xdf, 0x65, 0xfb, 0xd2, 0xdf, 0x38, 0xa5, 0xe7, 0xb8, 0xfe, 0xbd,
+	0x02, 0x8e, 0x84, 0x1a, 0x6a, 0x73, 0xc2, 0xe3, 0x4a, 0x0c, 0xb5, 0x8e,
+	0x6b, 0x5f, 0xba, 0x81, 0xf7, 0x26, 0x8c, 0xe5, 0xaf, 0xf7, 0xda, 0x5d,
+	0x19, 0xcb, 0x87, 0xba, 0x44, 0xf7, 0x4f, 0xe8, 0x92, 0x67, 0x53, 0x4a,
+	0x3b, 0xf3, 0x56, 0xda, 0x85, 0x74, 0x15, 0x9f, 0xa1, 0xfe, 0x71, 0x74,
+	0x52, 0xe8, 0x1c, 0xc6, 0x78, 0x46, 0x66, 0x1b, 0xc3, 0xd8, 0x6c, 0x44,
+	0x62, 0x4b, 0xec, 0xa1, 0x8f, 0x40, 0xe6, 0x10, 0x8d, 0x85, 0x57, 0x14,
+	0x35, 0x75, 0x8b, 0x53, 0x1d, 0x5a, 0x56, 0xec, 0xbc, 0xb5, 0xb6, 0x98,
+	0xb7, 0xd6, 0xe4, 0x56, 0xf9, 0x7b, 0x58, 0x0f, 0x7a, 0x16, 0x4a, 0xf5,
+	0xa1, 0x47, 0xe9, 0xb4, 0x6a, 0x6b, 0xbf, 0xb2, 0x63, 0xc1, 0xa3, 0x74,
+	0x64, 0x3d, 0x78, 0x85, 0x58, 0x6c, 0xb6, 0x0f, 0x81, 0x5b, 0x37, 0xc2,
+	0xbb, 0x23, 0xdb, 0x8b, 0x72, 0x4d, 0x7a, 0xc8, 0x72, 0x74, 0x5a, 0x75,
+	0xad, 0xce, 0xdf, 0xc3, 0xfa, 0xd3, 0x93, 0xef, 0x63, 0xfe, 0x43, 0xc0,
+	0x9b, 0xb0, 0x67, 0x06, 0x92, 0x0b, 0xef, 0xe0, 0xbb, 0x4b, 0xf1, 0x15,
+	0x80, 0x5d, 0xff, 0x94, 0x7e, 0xf6, 0x12, 0xd5, 0x1b, 0x14, 0x5c, 0xba,
+	0xcb, 0x03, 0xd2, 0x62, 0xcf, 0x7f, 0xb1, 0xf5, 0xc2, 0x74, 0xaf, 0xd2,
+	0x31, 0x37, 0xef, 0xdd, 0x66, 0xc8, 0x2c, 0x62, 0xd6, 0xdb, 0x4e, 0x1e,
+	0xda, 0x17, 0x9e, 0xf6, 0x6e, 0x25, 0x4f, 0x5b, 0x17, 0x3e, 0x4f, 0x53,
+	0xea, 0xca, 0x44, 0x6b, 0x1b, 0x63, 0x7b, 0xb7, 0xfe, 0x91, 0x19, 0xfe,
+	0x1d, 0xa1, 0xb3, 0x58, 0xd4, 0x67, 0x92, 0x7c, 0x05, 0x3d, 0x9d, 0xf9,
+	0x80, 0x27, 0x99, 0x6f, 0xf7, 0xb6, 0x19, 0xbd, 0xde, 0xad, 0x46, 0x9f,
+	0xb7, 0xdd, 0xb8, 0x87, 0xb4, 0x7b, 0xbc, 0x1d, 0x06, 0xe3, 0x3a, 0xdf,
+	0x47, 0xbd, 0xf6, 0x62, 0x3c, 0x7f, 0x0f, 0xb1, 0x87, 0xd0, 0x1c, 0x20,
+	0x0e, 0xf2, 0x52, 0xc6, 0x11, 0xca, 0x58, 0x08, 0xb9, 0x91, 0x54, 0xdd,
+	0xd4, 0xd7, 0x98, 0x65, 0xc7, 0x09, 0x6b, 0x16, 0x55, 0x91, 0x98, 0x6c,
+	0xed, 0x3e, 0xc1, 0x7c, 0x9f, 0x38, 0xda, 0x7a, 0xeb, 0x29, 0xd4, 0xb8,
+	0x13, 0xd2, 0x3b, 0xb3, 0x1f, 0x8e, 0x46, 0xf5, 0xf7, 0x10, 0x0d, 0xbd,
+	0xc2, 0x67, 0x47, 0xe9, 0xbb, 0x63, 0xd6, 0xfc, 0x81, 0x06, 0xc9, 0x35,
+	0xa1, 0xdb, 0xf0, 0x78, 0x77, 0xb2, 0x37, 0xf3, 0x27, 0xd4, 0x96, 0x3b,
+	0x9c, 0x32, 0x0f, 0x29, 0xfc, 0x96, 0x0f, 0x4d, 0xe8, 0xca, 0x7b, 0x28,
+	0xd7, 0x97, 0xf0, 0x0f, 0x27, 0x59, 0xd7, 0x20, 0x7e, 0x68, 0x9a, 0xf7,
+	0xb1, 0xaf, 0x39, 0x96, 0xab, 0xc3, 0x65, 0xcb, 0xc6, 0x2e, 0x1c, 0xcd,
+	0x85, 0xf1, 0x0e, 0xe5, 0x73, 0x2d, 0xd6, 0xe2, 0xed, 0x69, 0x27, 0xf6,
+	0xe9, 0xb7, 0x17, 0xeb, 0x85, 0x03, 0xf7, 0xc6, 0x0e, 0x11, 0x3b, 0x38,
+	0x50, 0x4d, 0xfc, 0xf6, 0xb0, 0x75, 0xcd, 0xc9, 0xfe, 0xef, 0xb7, 0x91,
+	0xb2, 0xeb, 0x09, 0x79, 0x7c, 0x94, 0x3c, 0x36, 0x7b, 0xb7, 0x66, 0x55,
+	0xef, 0x9d, 0x59, 0x78, 0xdc, 0x89, 0xd1, 0xd6, 0x33, 0x27, 0x4d, 0x0c,
+	0xea, 0xb7, 0xe1, 0xca, 0xc9, 0xd1, 0x21, 0x17, 0xfd, 0xe7, 0xe7, 0xf1,
+	0x7e, 0x18, 0x33, 0xb8, 0x40, 0xe4, 0x71, 0xd1, 0xc7, 0xdc, 0xde, 0x10,
+	0x8f, 0x06, 0x58, 0x8b, 0xf5, 0x05, 0xc6, 0x66, 0x07, 0xd4, 0x21, 0xd6,
+	0xe4, 0xa4, 0x33, 0x11, 0x1d, 0x18, 0x23, 0x78, 0xac, 0x22, 0x3f, 0x5e,
+	0xe6, 0x6e, 0xdf, 0x62, 0xd8, 0xbb, 0x9b, 0xf5, 0x26, 0xc4, 0xfe, 0xce,
+	0x1b, 0xc5, 0xed, 0xb5, 0x88, 0xc6, 0x96, 0x29, 0xb7, 0x7b, 0xb1, 0xc9,
+	0x7b, 0x07, 0xeb, 0xc7, 0xe5, 0xa8, 0x39, 0xf2, 0x92, 0xee, 0x83, 0x7f,
+	0x51, 0xa7, 0xbe, 0xfb, 0x31, 0xba, 0xc0, 0x96, 0x2b, 0xca, 0x9e, 0x7f,
+	0xb1, 0xc5, 0xbb, 0x93, 0xb1, 0x59, 0x45, 0x13, 0x35, 0x2e, 0x26, 0xbd,
+	0xd2, 0xf3, 0x35, 0x2d, 0x6e, 0x22, 0x7f, 0xe2, 0xa3, 0x99, 0xd6, 0xcd,
+	0xf4, 0x87, 0xf0, 0x22, 0x3a, 0x99, 0xe6, 0x5e, 0x26, 0xcd, 0xfe, 0x10,
+	0x31, 0xec, 0x81, 0x8d, 0x3e, 0xe6, 0x29, 0xd1, 0x25, 0xf5, 0x98, 0x2f,
+	0xc9, 0x24, 0x75, 0xf9, 0x68, 0xeb, 0xe2, 0x29, 0xa9, 0xcb, 0xa9, 0xd6,
+	0xcc, 0x29, 0x0d, 0xef, 0xb0, 0xb6, 0xac, 0x8d, 0xab, 0xfa, 0x39, 0x25,
+	0x12, 0xba, 0x48, 0x59, 0x5c, 0xf8, 0x85, 0xb9, 0x57, 0x8b, 0x16, 0x6e,
+	0x61, 0x3c, 0x55, 0x33, 0x37, 0x86, 0x98, 0xf3, 0xab, 0x17, 0xa9, 0x98,
+	0x45, 0xa7, 0x1b, 0x15, 0x21, 0x78, 0xa2, 0x1a, 0xde, 0x3d, 0x19, 0xa3,
+	0x1e, 0xae, 0xd1, 0x3c, 0x48, 0xa8, 0x35, 0xc8, 0x52, 0xf8, 0xd8, 0x33,
+	0xf4, 0xc5, 0x71, 0xae, 0x5b, 0xb6, 0x28, 0x3c, 0xcb, 0xf3, 0x41, 0x3e,
+	0x7f, 0x7d, 0xed, 0x6a, 0xae, 0xfd, 0xd1, 0x29, 0xf1, 0xd7, 0x54, 0xeb,
+	0x85, 0x93, 0xf6, 0xda, 0xd1, 0x78, 0x0c, 0x1f, 0x9e, 0x54, 0x87, 0xdf,
+	0x55, 0x22, 0x03, 0x17, 0x14, 0x59, 0x1f, 0x75, 0x55, 0xb8, 0x62, 0x8e,
+	0x46, 0xa3, 0xa9, 0xbd, 0xa4, 0xd9, 0xb2, 0x89, 0xfa, 0xb7, 0xf8, 0xa0,
+	0xcf, 0x33, 0xcf, 0xba, 0xc9, 0x8f, 0xcd, 0x4b, 0x1d, 0x69, 0x9f, 0x2c,
+	0xf6, 0x6a, 0xec, 0x53, 0xaf, 0xf3, 0x13, 0xa4, 0x1e, 0x3c, 0xbb, 0x9b,
+	0x7d, 0xa8, 0xb5, 0x9e, 0x0b, 0xf0, 0x39, 0xd1, 0xc3, 0x2f, 0x15, 0x87,
+	0xf6, 0x1e, 0xf3, 0x98, 0xe4, 0x92, 0x20, 0x73, 0xd8, 0x3d, 0xd2, 0xd3,
+	0xa6, 0xd3, 0xf4, 0x77, 0x37, 0xfd, 0x7d, 0x9b, 0xf8, 0xb4, 0x41, 0x9f,
+	0x36, 0xe8, 0xd3, 0x86, 0x1a, 0x1a, 0x46, 0x24, 0x30, 0x48, 0xbb, 0x25,
+	0x43, 0xe2, 0xeb, 0x7d, 0xd8, 0xc7, 0xdf, 0xfd, 0xbc, 0x7f, 0x94, 0x7d,
+	0x2e, 0x56, 0xc8, 0x9a, 0x87, 0xd1, 0x6e, 0x3c, 0x86, 0xa1, 0x2c, 0x7e,
+	0xe5, 0x6d, 0x2e, 0x47, 0xf9, 0x1a, 0xe9, 0xe1, 0xd5, 0xc0, 0x31, 0x3c,
+	0xc6, 0x3e, 0xea, 0x97, 0x4a, 0xa5, 0xe6, 0xea, 0x3d, 0xae, 0xa8, 0x81,
+	0x76, 0xf6, 0xc3, 0x7b, 0xf3, 0xf7, 0xd0, 0xbe, 0x91, 0xa1, 0x57, 0x14,
+	0xf6, 0x52, 0xb5, 0x5c, 0x9b, 0xb1, 0x74, 0x27, 0xd7, 0x31, 0x84, 0x0f,
+	0x2b, 0xdf, 0xfe, 0x1e, 0x44, 0xb7, 0x3f, 0x6a, 0x18, 0xe4, 0xfa, 0x36,
+	0x1f, 0xa3, 0xec, 0x29, 0x07, 0x19, 0x63, 0xfb, 0xac, 0xf8, 0xea, 0x23,
+	0x8d, 0xeb, 0x79, 0x6c, 0x6b, 0x46, 0x6a, 0xa9, 0x89, 0xc7, 0x75, 0x13,
+	0xcf, 0xf2, 0x77, 0x89, 0xb9, 0x6c, 0xec, 0x86, 0x5c, 0xe6, 0xe0, 0x73,
+	0xbb, 0xf9, 0x5c, 0x0b, 0x53, 0xe7, 0xc2, 0x9c, 0xcc, 0x06, 0x0f, 0xcb,
+	0x6c, 0x10, 0x39, 0x43, 0x74, 0x3f, 0x8c, 0x0b, 0x99, 0x48, 0xca, 0xe9,
+	0x34, 0x47, 0x18, 0x57, 0x4b, 0x1f, 0xd1, 0x77, 0x5f, 0xdf, 0xa8, 0xf6,
+	0x52, 0x87, 0xb1, 0x49, 0x45, 0x0d, 0xbd, 0x86, 0x42, 0xa7, 0x07, 0x8d,
+	0xe1, 0x75, 0xce, 0x68, 0xe0, 0x2c, 0xd4, 0xc2, 0x20, 0x25, 0x7d, 0x3a,
+	0x6f, 0xe7, 0xba, 0xcd, 0xc5, 0x5c, 0xd7, 0x92, 0xab, 0x50, 0xee, 0xcc,
+	0xb2, 0x3e, 0xcf, 0x99, 0x69, 0x3f, 0xeb, 0x55, 0x7e, 0x4e, 0x68, 0x8f,
+	0xa0, 0x31, 0x2e, 0xb4, 0xb4, 0xae, 0x49, 0x05, 0x5f, 0xaf, 0x44, 0x94,
+	0xb5, 0x0a, 0x7a, 0xb9, 0x96, 0x36, 0x59, 0x93, 0x02, 0xee, 0x84, 0xd4,
+	0xce, 0x1e, 0xf6, 0x2d, 0x7d, 0xcc, 0x8b, 0x82, 0xa9, 0x65, 0x5e, 0x6a,
+	0xe7, 0xa3, 0x6d, 0x79, 0xb1, 0x8b, 0xd8, 0x44, 0x6c, 0x73, 0x18, 0x07,
+	0xac, 0x79, 0xb4, 0x89, 0x69, 0x5d, 0x72, 0x83, 0xd8, 0xe9, 0x30, 0xf6,
+	0xe7, 0xdd, 0xb8, 0x97, 0x79, 0x70, 0xbe, 0x99, 0xba, 0xf2, 0xbb, 0x31,
+	0x38, 0x77, 0x3b, 0xf6, 0x65, 0x65, 0x9e, 0xe0, 0xa6, 0xfd, 0x92, 0xc4,
+	0x40, 0xcc, 0x3a, 0xc4, 0x3f, 0x65, 0x5a, 0x49, 0xa7, 0x42, 0x5b, 0x74,
+	0x5a, 0xfa, 0xbe, 0xe0, 0xb6, 0x75, 0x6c, 0xcf, 0x2d, 0x9d, 0x09, 0x59,
+	0xab, 0x34, 0xb3, 0xb4, 0xf5, 0xda, 0x99, 0x91, 0x35, 0x4d, 0x9c, 0xd5,
+	0x6d, 0x4c, 0x5b, 0xd2, 0x67, 0x88, 0x32, 0xd7, 0x6c, 0x02, 0xd6, 0xdd,
+	0x80, 0x6b, 0x2b, 0x78, 0xad, 0xfb, 0x3a, 0xae, 0xed, 0x17, 0xec, 0x4c,
+	0x5c, 0xdb, 0xb5, 0x83, 0xb8, 0xb6, 0x5e, 0x29, 0x61, 0x5a, 0x99, 0x59,
+	0x94, 0x70, 0x6d, 0x75, 0x31, 0x7f, 0x1f, 0xc6, 0x5e, 0x62, 0x9e, 0xda,
+	0xfa, 0x11, 0x78, 0xd6, 0x3b, 0x3e, 0x73, 0x60, 0x84, 0xbd, 0x4c, 0x19,
+	0xb0, 0xd2, 0xc4, 0x2d, 0x1b, 0xd2, 0x66, 0xb9, 0x56, 0x1f, 0x2e, 0x77,
+	0xc8, 0x4c, 0x3a, 0x9a, 0x1e, 0x63, 0x9e, 0x71, 0xac, 0x57, 0xd3, 0x49,
+	0x78, 0x02, 0x35, 0xda, 0x3d, 0xc5, 0x5e, 0x22, 0xe4, 0xd9, 0x4e, 0x4c,
+	0x14, 0x8d, 0x7f, 0x6a, 0xce, 0x06, 0x85, 0x46, 0xa1, 0xe0, 0x41, 0xf2,
+	0x11, 0x0f, 0x6b, 0xd4, 0xb2, 0x32, 0x81, 0xd7, 0xa3, 0x21, 0xcf, 0xce,
+	0x7c, 0xda, 0xdb, 0xdd, 0x70, 0x0b, 0x7a, 0x4e, 0x49, 0x3d, 0x0a, 0x63,
+	0xc7, 0xa9, 0x76, 0xd6, 0x20, 0x0d, 0x1d, 0x93, 0x5d, 0xec, 0xf1, 0x7a,
+	0x95, 0xde, 0x39, 0xd1, 0xa1, 0xd8, 0x40, 0x0d, 0x84, 0x1d, 0x37, 0xce,
+	0x4c, 0x4b, 0xfd, 0xf2, 0x7b, 0x96, 0x7f, 0x8d, 0xeb, 0x01, 0xea, 0xe7,
+	0xaa, 0x1b, 0x7e, 0x13, 0x67, 0x74, 0xf1, 0x4b, 0x7e, 0x37, 0x92, 0xd8,
+	0xd6, 0x3c, 0x6d, 0xba, 0x34, 0x99, 0x7d, 0x87, 0x2c, 0x9b, 0x6e, 0x65,
+	0x9d, 0x6b, 0x9f, 0xeb, 0xa3, 0x1d, 0x4b, 0x73, 0xee, 0x1b, 0xed, 0xb9,
+	0xc5, 0xbb, 0x8d, 0x39, 0x8f, 0x3d, 0xbc, 0xc7, 0xc3, 0x3c, 0xea, 0x39,
+	0x65, 0x62, 0x4e, 0x7f, 0xcb, 0x7c, 0x5c, 0x73, 0xd1, 0x6e, 0x5f, 0x65,
+	0x4e, 0x16, 0xcc, 0x92, 0xf0, 0xde, 0x31, 0xe3, 0x72, 0x54, 0x25, 0xd0,
+	0x5c, 0x46, 0x7f, 0xbc, 0x18, 0xb7, 0xe7, 0x91, 0xc7, 0x73, 0xb7, 0x7b,
+	0xbb, 0xb3, 0xec, 0x33, 0xd8, 0x07, 0xdb, 0xbd, 0xdf, 0x57, 0xbd, 0x7b,
+	0xb2, 0x4e, 0xa5, 0x36, 0x01, 0x67, 0xcb, 0x26, 0x13, 0x1f, 0x6f, 0x88,
+	0xa6, 0x42, 0x0e, 0xe6, 0x4f, 0xd2, 0x32, 0x72, 0xcd, 0xde, 0x7e, 0xe6,
+	0xeb, 0x9d, 0x59, 0xba, 0x01, 0x7d, 0xc7, 0xbf, 0x61, 0x74, 0xc0, 0x0f,
+	0x99, 0xb3, 0xe1, 0xeb, 0x8c, 0xd8, 0x20, 0xfd, 0x31, 0xd4, 0xa6, 0x44,
+	0x97, 0x87, 0x10, 0x5d, 0xfa, 0xd8, 0xf9, 0x96, 0xf9, 0x64, 0x6e, 0x13,
+	0x9f, 0xef, 0x62, 0x2e, 0x4d, 0x32, 0xb7, 0x8e, 0xa6, 0xdc, 0x90, 0x77,
+	0xd4, 0xfe, 0x37, 0x95, 0x08, 0xe3, 0x00, 0xbf, 0xc3, 0xe7, 0x03, 0x1d,
+	0xcc, 0xa3, 0x73, 0x7a, 0x34, 0xb9, 0x15, 0xe9, 0xae, 0x6a, 0xa8, 0x7a,
+	0x83, 0x22, 0x73, 0x31, 0xb1, 0x43, 0x0c, 0x3f, 0xe1, 0x9a, 0x2e, 0x4d,
+	0xf4, 0xb8, 0x85, 0xbe, 0x48, 0x6c, 0xe0, 0xf8, 0xbc, 0xdf, 0xfd, 0x5e,
+	0x19, 0x2a, 0x56, 0x50, 0xb6, 0x9f, 0x58, 0x39, 0xc7, 0xab, 0x69, 0xf8,
+	0xaf, 0xc4, 0x4e, 0x7f, 0x96, 0x97, 0xf9, 0x67, 0x09, 0x0f, 0x8a, 0x6f,
+	0x64, 0x5a, 0x6f, 0x9d, 0x8d, 0x15, 0xe7, 0xa1, 0x1e, 0x6f, 0xd7, 0x8c,
+	0x89, 0xac, 0xee, 0x87, 0xf4, 0xff, 0xe5, 0xf1, 0x02, 0xd1, 0x41, 0x13,
+	0x3a, 0x78, 0xbd, 0x7d, 0xa6, 0x52, 0x69, 0xcf, 0x9a, 0xf8, 0x33, 0x5d,
+	0x4d, 0xb7, 0x39, 0x19, 0xef, 0xba, 0x7a, 0x16, 0xf8, 0x19, 0x71, 0x94,
+	0xf8, 0x98, 0x0b, 0x3e, 0xcd, 0xa6, 0xd5, 0x34, 0x7b, 0x3b, 0xb1, 0x85,
+	0xc4, 0x9f, 0x73, 0x6d, 0x05, 0x9a, 0x95, 0x59, 0x97, 0xe8, 0xad, 0x0b,
+	0xc9, 0x7c, 0xa5, 0xb2, 0x8b, 0xba, 0xbc, 0x73, 0xbd, 0x17, 0x97, 0x2c,
+	0x5d, 0xde, 0x4e, 0x5d, 0xe2, 0x8d, 0xd5, 0x70, 0x5e, 0xa8, 0x05, 0xc1,
+	0x44, 0xb9, 0x1a, 0x1e, 0x70, 0x88, 0x4d, 0x18, 0x27, 0x82, 0xd5, 0x50,
+	0xc9, 0x7a, 0x9e, 0x24, 0x0e, 0x26, 0x6e, 0x0c, 0xf4, 0xe1, 0xdb, 0xcc,
+	0x4b, 0x8f, 0xd3, 0x6f, 0x7f, 0xa1, 0x35, 0xa1, 0xe2, 0x3b, 0xcd, 0xb4,
+	0xe9, 0x26, 0xef, 0xf6, 0x6c, 0x3f, 0x9e, 0x58, 0x30, 0xf1, 0x0c, 0x63,
+	0xa6, 0x21, 0x9e, 0x0e, 0x94, 0xb3, 0xaf, 0x63, 0xed, 0x5b, 0x3e, 0x61,
+	0xf9, 0xfc, 0x68, 0xeb, 0x96, 0xf9, 0x10, 0x9c, 0xdf, 0xb6, 0xf6, 0x7e,
+	0x5a, 0xc3, 0xf3, 0xd6, 0xde, 0x0f, 0x3f, 0x4d, 0x0c, 0xeb, 0x6a, 0xf2,
+	0x63, 0x67, 0x05, 0x2a, 0xa3, 0xa6, 0x39, 0x1c, 0xb7, 0xf6, 0x1f, 0x5a,
+	0x63, 0xd6, 0xfd, 0xa3, 0xfc, 0x2c, 0xcd, 0xae, 0xff, 0x46, 0x30, 0x63,
+	0x38, 0x49, 0xf9, 0x77, 0x10, 0x07, 0xf4, 0x13, 0x07, 0xd4, 0x26, 0xd4,
+	0xe4, 0x6e, 0xa7, 0xcc, 0x69, 0x0a, 0x87, 0xaa, 0x79, 0xfd, 0x8e, 0x22,
+	0x0e, 0xa8, 0x3a, 0x25, 0xb3, 0x3f, 0x62, 0x45, 0xd8, 0x7b, 0x26, 0x3d,
+	0xc4, 0x01, 0x15, 0x93, 0x2e, 0x74, 0x13, 0x03, 0xb8, 0x89, 0xd9, 0xb7,
+	0xe5, 0x6a, 0xe1, 0x3d, 0xe1, 0x44, 0x24, 0xfe, 0x23, 0x1c, 0xa2, 0xbf,
+	0x1d, 0x8a, 0x79, 0x94, 0xf0, 0x2a, 0x07, 0x75, 0xf6, 0x2b, 0x1c, 0x0c,
+	0x38, 0x51, 0xa5, 0xbd, 0x86, 0x07, 0xbf, 0xa0, 0xf6, 0xf7, 0x67, 0x25,
+	0xce, 0x47, 0x5b, 0xbb, 0x4f, 0xd9, 0xb5, 0xdf, 0x77, 0x6a, 0x74, 0x59,
+	0x6a, 0x7f, 0xed, 0x86, 0x7e, 0x9c, 0x9e, 0xc1, 0x37, 0x57, 0x13, 0x64,
+	0xd6, 0x72, 0xcd, 0xfa, 0x78, 0x94, 0x3d, 0xb8, 0x3a, 0xd4, 0xa1, 0x44,
+	0x27, 0xaa, 0x98, 0x0f, 0x4e, 0xb3, 0xf6, 0x7b, 0x12, 0xd1, 0x40, 0xcc,
+	0x81, 0x1e, 0x37, 0x6d, 0xf3, 0x3e, 0xfb, 0xf1, 0x9f, 0xe6, 0xc2, 0xa4,
+	0x59, 0x06, 0x17, 0x6b, 0xff, 0xfb, 0x1a, 0x3e, 0x73, 0xd2, 0x0f, 0xdf,
+	0x71, 0x7a, 0x70, 0x35, 0x67, 0xd7, 0xfe, 0xea, 0x06, 0x73, 0xe4, 0x72,
+	0xdc, 0x87, 0x2b, 0x39, 0x9d, 0xfe, 0xd8, 0x8f, 0xa3, 0xac, 0xfd, 0x97,
+	0xb5, 0x00, 0x3e, 0xcc, 0xb5, 0xd0, 0x47, 0x83, 0xf8, 0x39, 0x71, 0xf2,
+	0x7a, 0xd6, 0xfe, 0xbb, 0xe8, 0x5f, 0x71, 0xd6, 0xfe, 0x36, 0x0b, 0x97,
+	0x64, 0x5a, 0xcf, 0x4c, 0x5b, 0xb5, 0xbf, 0xc1, 0xc1, 0xba, 0xe9, 0x46,
+	0x74, 0x99, 0x39, 0xc3, 0xfc, 0xc5, 0x26, 0x1f, 0x9f, 0xa5, 0xde, 0xf2,
+	0x1b, 0x30, 0x6b, 0xd5, 0xaa, 0x2d, 0xde, 0x5d, 0x5c, 0x7b, 0xa5, 0x15,
+	0x73, 0x26, 0x76, 0xac, 0xff, 0x6b, 0xfc, 0x41, 0x8d, 0x83, 0x3e, 0x99,
+	0xf0, 0xde, 0xc9, 0xb8, 0xf3, 0x27, 0x4a, 0xb3, 0x91, 0x18, 0xd7, 0xb9,
+	0xdd, 0x7b, 0x17, 0xfd, 0xe4, 0x96, 0xf5, 0xcc, 0x2a, 0x01, 0x3b, 0xe6,
+	0xda, 0x19, 0x73, 0x21, 0xc6, 0xdc, 0x6a, 0xc6, 0xdc, 0x93, 0x7a, 0x34,
+	0xb6, 0x85, 0xf8, 0xec, 0x95, 0x9c, 0xc4, 0x5d, 0x33, 0xe9, 0xaa, 0x94,
+	0x6b, 0x74, 0x40, 0xe2, 0x67, 0xc7, 0xfa, 0xd1, 0xb3, 0x95, 0x10, 0x5d,
+	0xe1, 0xb3, 0x95, 0xc4, 0x22, 0xcc, 0x52, 0x4b, 0xcb, 0xce, 0x68, 0xea,
+	0x36, 0x67, 0x74, 0xf8, 0x3d, 0xe5, 0x2d, 0xf3, 0x0d, 0xc6, 0xdc, 0x4e,
+	0xc6, 0xdc, 0x2e, 0xc6, 0x5c, 0x9b, 0x61, 0xe2, 0x85, 0xb8, 0xda, 0xdf,
+	0xe4, 0x88, 0xe8, 0x6d, 0x0e, 0xac, 0xae, 0x64, 0x09, 0xf1, 0x22, 0xda,
+	0xf5, 0x07, 0xe4, 0x7f, 0x49, 0x8f, 0xf6, 0xc6, 0x14, 0x89, 0xb3, 0x30,
+	0x3e, 0xa0, 0xdc, 0xe5, 0xc5, 0x38, 0x3b, 0x30, 0x77, 0xbe, 0xe8, 0x1b,
+	0x25, 0xd9, 0x9d, 0x78, 0x5e, 0x67, 0x5e, 0x5d, 0x21, 0xbe, 0xdb, 0x87,
+	0x09, 0xea, 0xd1, 0x1b, 0xed, 0xc3, 0x31, 0xd6, 0xcd, 0xfb, 0x58, 0xaf,
+	0xef, 0x37, 0x22, 0x2d, 0xdb, 0xd9, 0x27, 0x5d, 0x0a, 0xa9, 0xe1, 0xb0,
+	0xd2, 0x87, 0x41, 0xfa, 0xf0, 0x20, 0xeb, 0x4b, 0x9b, 0xf1, 0x4b, 0xa5,
+	0x83, 0x98, 0x62, 0x7f, 0x5e, 0xde, 0x53, 0x63, 0x69, 0xc7, 0x10, 0x06,
+	0x16, 0x24, 0xcf, 0x21, 0x70, 0x53, 0xa2, 0x0f, 0x53, 0x46, 0x19, 0xfa,
+	0x9a, 0x7b, 0x94, 0x3b, 0xf2, 0x32, 0xa7, 0x63, 0x6c, 0x1a, 0x8c, 0x5d,
+	0x8b, 0x5f, 0x05, 0xb9, 0x68, 0x0f, 0x32, 0x12, 0xab, 0xc6, 0x2e, 0xe5,
+	0xae, 0x39, 0x89, 0xf7, 0x3e, 0xa5, 0x4f, 0xe2, 0xd9, 0x48, 0x29, 0x77,
+	0x4b, 0x7c, 0x5b, 0xb3, 0x6d, 0xc9, 0x01, 0xb2, 0xf7, 0x71, 0x3b, 0xf1,
+	0x1e, 0x18, 0x5f, 0xce, 0xef, 0x84, 0x18, 0x83, 0x6d, 0x65, 0x0e, 0xfa,
+	0x69, 0x84, 0xb6, 0x73, 0xa0, 0x5d, 0xff, 0xb2, 0x99, 0x0e, 0x0c, 0x30,
+	0xa6, 0xfa, 0x70, 0xd4, 0x08, 0x99, 0x97, 0x2d, 0x1c, 0x53, 0xca, 0xf1,
+	0x5b, 0x58, 0xeb, 0x56, 0xc1, 0xa3, 0x49, 0x7d, 0xf7, 0x21, 0x56, 0xe3,
+	0x41, 0x85, 0x26, 0xb5, 0x27, 0xd3, 0xba, 0x78, 0x42, 0x91, 0x3e, 0xa5,
+	0x18, 0xeb, 0x5b, 0xf0, 0x00, 0x73, 0xc2, 0xbe, 0xf8, 0xbd, 0xb8, 0x3f,
+	0x50, 0x01, 0x3f, 0xf5, 0xf4, 0x50, 0xc0, 0xc7, 0x5c, 0xfb, 0x7b, 0x45,
+	0x3a, 0x7f, 0x51, 0x56, 0xec, 0xbf, 0xaf, 0x61, 0xb0, 0x5a, 0xc6, 0xd8,
+	0xe6, 0x19, 0x99, 0x27, 0xa5, 0x5a, 0x43, 0x33, 0x1a, 0xfc, 0xec, 0x7b,
+	0xb7, 0xc4, 0xd5, 0xd4, 0x16, 0x67, 0x44, 0x7a, 0x9a, 0x8c, 0x9f, 0xf8,
+	0x2f, 0x17, 0x8d, 0xf6, 0x36, 0x89, 0x8e, 0xb5, 0x10, 0x3a, 0xa9, 0xa7,
+	0xee, 0x5c, 0x90, 0x31, 0xe4, 0x28, 0x17, 0x2c, 0x95, 0xcc, 0x5d, 0xa7,
+	0x15, 0x22, 0xad, 0xd0, 0x8c, 0xe0, 0xba, 0x14, 0x71, 0x9d, 0xc6, 0x38,
+	0x34, 0xcd, 0xcd, 0xc4, 0x73, 0xbe, 0x53, 0x32, 0x97, 0x8a, 0x4c, 0x10,
+	0x03, 0x37, 0x11, 0x1f, 0xf7, 0xd1, 0xab, 0xcd, 0x5b, 0xea, 0xa3, 0x7a,
+	0x9b, 0x82, 0xc7, 0xe6, 0x9b, 0xe1, 0x71, 0x92, 0xe6, 0x3b, 0xb9, 0x00,
+	0x2e, 0xe7, 0x42, 0x78, 0x9b, 0xb4, 0x2f, 0x59, 0xb4, 0xeb, 0xf0, 0xb3,
+	0x62, 0x0e, 0x8b, 0x33, 0x87, 0x6d, 0xcd, 0x2a, 0xf4, 0xd7, 0x30, 0x46,
+	0xf4, 0xbf, 0xfa, 0xec, 0xd2, 0xcd, 0x1e, 0xea, 0x4d, 0x64, 0x71, 0xf1,
+	0x73, 0x1c, 0x0f, 0x59, 0x39, 0xfb, 0xb5, 0xcf, 0x66, 0x6b, 0x68, 0x2b,
+	0xea, 0xbe, 0xba, 0xf8, 0xde, 0xba, 0xd9, 0x3f, 0x2f, 0xca, 0xdb, 0x53,
+	0xb4, 0x35, 0x71, 0x9b, 0x71, 0x9e, 0xd7, 0x04, 0x47, 0x69, 0x70, 0x9c,
+	0x8a, 0xa1, 0xec, 0xd4, 0x35, 0xfe, 0x35, 0x89, 0x19, 0x56, 0xde, 0xc7,
+	0xbe, 0x4b, 0x9e, 0x1e, 0x21, 0x5e, 0x34, 0xc9, 0xd3, 0x55, 0x8b, 0x97,
+	0x20, 0x79, 0xf9, 0xe4, 0xb3, 0x12, 0xb6, 0x0c, 0x5d, 0x7b, 0x27, 0x40,
+	0x7d, 0xe0, 0xd1, 0x10, 0xf5, 0x79, 0x65, 0xa3, 0x3c, 0xe7, 0xc3, 0x1d,
+	0xb9, 0x44, 0xb9, 0xe4, 0x79, 0xaf, 0xb6, 0x05, 0x7b, 0xe7, 0x3e, 0xaf,
+	0xf7, 0x20, 0x6d, 0x11, 0xa0, 0xf1, 0xe4, 0xde, 0x17, 0xd5, 0xd4, 0x3f,
+	0x42, 0x8a, 0x3d, 0xd3, 0x23, 0xd9, 0x34, 0x1e, 0xca, 0x7e, 0xcb, 0xda,
+	0xcb, 0x5b, 0xb7, 0x01, 0xfb, 0x49, 0xff, 0x60, 0x35, 0xe3, 0xe8, 0x7f,
+	0xc4, 0xa3, 0x82, 0xa5, 0x76, 0x55, 0x42, 0xea, 0x6e, 0xb4, 0xe5, 0x36,
+	0xc5, 0x44, 0x59, 0x1c, 0xc3, 0xed, 0xcd, 0xd1, 0xd8, 0x65, 0x3c, 0x66,
+	0xca, 0x5c, 0xdc, 0x59, 0xac, 0xc1, 0xc4, 0xaf, 0x4a, 0x3b, 0xeb, 0x70,
+	0x5b, 0x11, 0x53, 0x6d, 0xcd, 0xbf, 0xf5, 0xb9, 0xd9, 0x83, 0xf4, 0xed,
+	0x52, 0x7b, 0xbc, 0x4a, 0x1b, 0xd7, 0x39, 0xca, 0x9c, 0xfd, 0xbc, 0xfe,
+	0x52, 0x88, 0x95, 0x19, 0xae, 0xf5, 0x0a, 0x0e, 0x11, 0x3f, 0xa5, 0x83,
+	0x26, 0x76, 0xf1, 0xf3, 0x00, 0x71, 0xd6, 0xbb, 0x7a, 0x15, 0x66, 0x03,
+	0x01, 0x62, 0x4b, 0xe6, 0x60, 0xc7, 0xdf, 0x49, 0x4d, 0x88, 0x85, 0x1d,
+	0xb2, 0x57, 0xff, 0x6f, 0xed, 0xdf, 0xac, 0x27, 0x96, 0x11, 0xd9, 0xbd,
+	0x0a, 0x73, 0x68, 0x0c, 0xc4, 0x37, 0x7b, 0xf5, 0x42, 0xd8, 0x81, 0xe4,
+	0x55, 0x07, 0xd4, 0xd3, 0xef, 0xb0, 0x1f, 0x7c, 0xa4, 0x5e, 0x3d, 0xdd,
+	0xea, 0xd4, 0x90, 0x9a, 0xf2, 0xe0, 0xe1, 0xa9, 0x0e, 0x54, 0x5b, 0x73,
+	0xa4, 0x71, 0xda, 0xcc, 0xc1, 0x3e, 0x6c, 0xf4, 0x53, 0x17, 0xfb, 0xb1,
+	0xab, 0x1b, 0x1e, 0x45, 0x8b, 0x75, 0x7d, 0x0c, 0xfb, 0xb3, 0x5e, 0xa5,
+	0x3b, 0xeb, 0x42, 0xc7, 0x5d, 0x8f, 0xc2, 0xbd, 0x7e, 0x80, 0x7c, 0xc9,
+	0x75, 0xf9, 0xfb, 0x6e, 0xf6, 0x71, 0xc2, 0x5f, 0x19, 0xc2, 0xab, 0xc8,
+	0xdb, 0x7a, 0x0d, 0x23, 0x53, 0x2e, 0x65, 0xb7, 0xf1, 0x37, 0xe6, 0x55,
+	0x6b, 0x6f, 0x48, 0xae, 0x55, 0xc8, 0x99, 0x01, 0x3e, 0x23, 0x39, 0x67,
+	0x10, 0x59, 0xc6, 0xf6, 0xdd, 0xd6, 0xfb, 0xa7, 0xca, 0x6c, 0x99, 0x92,
+	0xec, 0x6f, 0xdb, 0xe9, 0x1f, 0xf2, 0x4c, 0x5b, 0xf1, 0xda, 0x76, 0x8f,
+	0x7d, 0x2e, 0x41, 0xec, 0x3e, 0x88, 0x5b, 0x69, 0x84, 0xfa, 0xa8, 0xf8,
+	0xd8, 0x20, 0xea, 0x73, 0x4c, 0xa8, 0xab, 0x6c, 0x7e, 0x1f, 0x34, 0x0a,
+	0xec, 0x4d, 0x35, 0xe6, 0x4d, 0xea, 0x6e, 0xa5, 0xbc, 0x4f, 0x47, 0xfd,
+	0xb5, 0xf7, 0x4b, 0xf5, 0x54, 0x70, 0xe9, 0x17, 0xdd, 0xff, 0x4d, 0xc8,
+	0x3d, 0x97, 0xf6, 0x87, 0x8c, 0xe3, 0x68, 0x6f, 0xa5, 0x43, 0xfc, 0xe7,
+	0x0f, 0x71, 0xff, 0x1c, 0x1b, 0xd7, 0x0a, 0xa1, 0x4f, 0xdc, 0x6b, 0xb8,
+	0x94, 0x2e, 0xe6, 0x9f, 0x03, 0x53, 0x8e, 0x3b, 0xca, 0xf0, 0xe7, 0x66,
+	0xf9, 0xca, 0x11, 0xd4, 0xc7, 0xc7, 0xf8, 0xbc, 0x82, 0x76, 0x62, 0xc8,
+	0x27, 0xf4, 0xad, 0xe8, 0xa8, 0x91, 0x1c, 0xf0, 0xbc, 0x39, 0xd8, 0x27,
+	0x3a, 0x54, 0xb0, 0x8d, 0xd7, 0x5f, 0xa0, 0x7d, 0x9f, 0xd6, 0x5d, 0xa8,
+	0x5f, 0x21, 0x33, 0x41, 0x75, 0x3a, 0x89, 0x3d, 0x1e, 0x7b, 0x8f, 0x2c,
+	0x6d, 0x56, 0x6b, 0xda, 0xf0, 0x9d, 0x8e, 0xfa, 0xe9, 0x37, 0xe9, 0x4f,
+	0x6d, 0xeb, 0x6f, 0xbc, 0x57, 0xd2, 0x89, 0x8e, 0xd0, 0xfa, 0xe7, 0x4c,
+	0xdc, 0x34, 0x8a, 0xc0, 0xfa, 0x1b, 0xed, 0x5f, 0xe2, 0xfb, 0x30, 0x63,
+	0x10, 0xe9, 0xea, 0x84, 0xcc, 0x89, 0xa2, 0xa4, 0x73, 0x18, 0xbf, 0x9f,
+	0x1f, 0xc3, 0xa1, 0xac, 0xc8, 0xb9, 0x60, 0xf9, 0xb6, 0xb6, 0xfe, 0xba,
+	0x6c, 0x0f, 0x66, 0xa3, 0x03, 0x55, 0x45, 0xd9, 0x0e, 0xb2, 0x1f, 0xa9,
+	0x64, 0x8e, 0x7d, 0x80, 0x3a, 0x1d, 0xb6, 0x74, 0xda, 0x07, 0x3d, 0x77,
+	0x9d, 0xee, 0x10, 0xe9, 0x7a, 0x13, 0xa2, 0x37, 0xd9, 0x97, 0x63, 0x2f,
+	0x40, 0xba, 0xfb, 0x6e, 0xa0, 0x3b, 0xa8, 0x5f, 0xa7, 0xbb, 0x37, 0x1b,
+	0x3d, 0xed, 0x28, 0xd2, 0xfd, 0xc6, 0x5c, 0x89, 0x46, 0x1a, 0x3b, 0xd7,
+	0xa7, 0x91, 0xdb, 0x7c, 0xd0, 0x3c, 0x68, 0xe9, 0xe3, 0xfb, 0xd6, 0xf5,
+	0x6d, 0xf5, 0x12, 0x0f, 0xfc, 0x33, 0xa1, 0x59, 0x67, 0x00, 0x6c, 0x1c,
+	0x76, 0x63, 0x7c, 0xa8, 0x6f, 0x75, 0x3b, 0x93, 0x8c, 0xe3, 0xa0, 0x67,
+	0xfb, 0xe7, 0x66, 0x1f, 0x1d, 0xec, 0xd7, 0x3a, 0x8d, 0x1e, 0x6f, 0x97,
+	0xe1, 0x21, 0x06, 0xab, 0x54, 0xb6, 0x65, 0x65, 0x06, 0x22, 0xb1, 0x5c,
+	0xc4, 0xc5, 0x79, 0xe9, 0x0b, 0xef, 0x61, 0xcf, 0xb0, 0x81, 0xf6, 0x1d,
+	0xc0, 0x44, 0x7e, 0x40, 0x49, 0x06, 0xb9, 0x8e, 0x21, 0x75, 0x05, 0xac,
+	0x79, 0xbd, 0xa8, 0xa4, 0x2f, 0x05, 0x13, 0xd3, 0x89, 0x93, 0xf5, 0x26,
+	0x88, 0x51, 0x3c, 0x2b, 0x12, 0xb3, 0x89, 0x5d, 0xf5, 0x4e, 0x1c, 0xb7,
+	0xb0, 0x98, 0x3a, 0xcb, 0xdf, 0x69, 0x89, 0x99, 0x3b, 0xb3, 0x52, 0xc7,
+	0x08, 0x27, 0xb5, 0x11, 0xfc, 0x63, 0xbc, 0x30, 0x5c, 0x83, 0xe4, 0x7d,
+	0x35, 0x90, 0x1e, 0x63, 0x02, 0x7f, 0xa9, 0x85, 0x3c, 0xfd, 0x79, 0x97,
+	0xd2, 0x6d, 0xcc, 0x7b, 0x77, 0x18, 0x7e, 0xf8, 0xd8, 0xbf, 0xf5, 0x38,
+	0x23, 0xec, 0x39, 0xac, 0x19, 0x7d, 0xeb, 0xad, 0xb9, 0x7e, 0x6f, 0xbb,
+	0x61, 0xe7, 0xc2, 0x5b, 0x66, 0x3d, 0xde, 0x8e, 0x99, 0x48, 0x68, 0xc2,
+	0xc2, 0x62, 0x07, 0x5b, 0x23, 0x39, 0xd3, 0x7c, 0x55, 0x2f, 0x5c, 0x2d,
+	0xb7, 0xbe, 0x4f, 0xb7, 0xc6, 0x72, 0x4d, 0xd8, 0x43, 0xfc, 0xd4, 0x36,
+	0xd3, 0x04, 0x7d, 0x06, 0x38, 0x31, 0x15, 0xc2, 0xba, 0xac, 0x7a, 0x3a,
+	0xe5, 0xec, 0xc7, 0xf4, 0x42, 0x17, 0xb2, 0x79, 0xef, 0x72, 0xd8, 0x41,
+	0x8c, 0x1d, 0x77, 0xe0, 0x0e, 0x7d, 0x83, 0x52, 0xb0, 0x62, 0x5a, 0xc1,
+	0xdd, 0xfa, 0x2e, 0x65, 0xc0, 0xc2, 0x14, 0xf3, 0xc4, 0x22, 0x0a, 0x6e,
+	0xb2, 0x72, 0xef, 0xc9, 0xd6, 0x38, 0xf1, 0xf7, 0x1d, 0x59, 0xa9, 0xef,
+	0x26, 0x2e, 0xc6, 0xa9, 0x97, 0x78, 0xba, 0xdf, 0xcd, 0x7e, 0xe8, 0xa0,
+	0xa2, 0xf6, 0xea, 0x8a, 0x8d, 0xf1, 0x6e, 0x9b, 0xb7, 0x71, 0xe1, 0xad,
+	0xf3, 0xcd, 0x5e, 0xc9, 0x41, 0xed, 0xba, 0x1a, 0x72, 0x39, 0x02, 0x18,
+	0xb6, 0x68, 0xa4, 0x5b, 0xf5, 0xf9, 0x32, 0xac, 0xd6, 0xfa, 0x70, 0xda,
+	0x92, 0x61, 0xa2, 0x75, 0x0b, 0xb1, 0xf6, 0x93, 0x46, 0x3f, 0x7b, 0x65,
+	0xd9, 0x37, 0x8d, 0xc4, 0x5a, 0x9c, 0x6d, 0xc4, 0xb3, 0x91, 0xf0, 0xb2,
+	0x92, 0x54, 0xd2, 0xae, 0xc6, 0xe4, 0x3c, 0x58, 0x51, 0x6a, 0xec, 0xfa,
+	0x26, 0x32, 0x46, 0x89, 0xb3, 0xda, 0xa6, 0xbc, 0xcb, 0x49, 0xd8, 0x73,
+	0x9e, 0x4e, 0xfd, 0xff, 0xe0, 0x52, 0x50, 0x9d, 0x48, 0x92, 0xef, 0x0e,
+	0xe6, 0xdd, 0x42, 0x9f, 0x8b, 0xf7, 0x65, 0xbe, 0x37, 0xdc, 0x3a, 0x9e,
+	0x41, 0xc1, 0x99, 0x90, 0x1e, 0x0b, 0xfe, 0xde, 0x3c, 0x64, 0xd6, 0xc4,
+	0x3e, 0xe3, 0x53, 0xb3, 0xb4, 0xc7, 0xd4, 0x33, 0x63, 0xef, 0x9f, 0x65,
+	0x16, 0x5c, 0xfe, 0x1d, 0x46, 0x33, 0x8e, 0xe7, 0x5d, 0x37, 0xd0, 0x8e,
+	0x4e, 0xdc, 0xe2, 0x70, 0x20, 0xba, 0xfe, 0x6e, 0xa5, 0xb8, 0x07, 0xc5,
+	0x3c, 0x91, 0xb2, 0x6a, 0x62, 0x19, 0xe5, 0xbc, 0x70, 0x52, 0xd6, 0xf8,
+	0x56, 0xeb, 0xf8, 0x49, 0xa9, 0x91, 0xc3, 0xad, 0x21, 0x43, 0xed, 0x95,
+	0x9e, 0xb0, 0x9a, 0x7a, 0xfa, 0x68, 0x52, 0x6a, 0xf0, 0x14, 0x6b, 0xb0,
+	0xba, 0xdc, 0xae, 0x48, 0x1d, 0x53, 0x63, 0x5e, 0xa7, 0x03, 0x57, 0x1a,
+	0xd4, 0xfe, 0x1f, 0x40, 0x1d, 0xb0, 0xe7, 0x8a, 0x8f, 0xb6, 0x36, 0x16,
+	0xf1, 0xf0, 0x6d, 0xf3, 0x83, 0x72, 0xee, 0xc4, 0xd2, 0x71, 0x53, 0x4e,
+	0xb0, 0xb1, 0x69, 0xbe, 0x1c, 0xef, 0x21, 0x6e, 0x10, 0x6c, 0x2c, 0xd7,
+	0x27, 0x5b, 0x1b, 0x66, 0x3d, 0xe4, 0x4d, 0xc1, 0x7b, 0x5a, 0x0f, 0x7d,
+	0xaf, 0xc4, 0xa3, 0x8d, 0x9b, 0xb7, 0x13, 0x37, 0x3b, 0x13, 0x6a, 0xcb,
+	0x56, 0xe2, 0x66, 0x8d, 0xfd, 0x84, 0x0b, 0x7d, 0x78, 0xc2, 0xb0, 0x7b,
+	0x0a, 0xc1, 0xce, 0xe6, 0x49, 0x35, 0x29, 0xb8, 0xf9, 0xea, 0x06, 0x60,
+	0x37, 0x71, 0xf3, 0x72, 0xc6, 0x85, 0x7e, 0xe2, 0xe6, 0x8f, 0x98, 0x82,
+	0xee, 0x24, 0x6e, 0xbe, 0x42, 0x8c, 0x75, 0x3e, 0xfe, 0x73, 0x7c, 0xa3,
+	0x38, 0x3b, 0xdb, 0x4b, 0xec, 0x9c, 0x0c, 0xde, 0x88, 0x9d, 0xff, 0xe2,
+	0x5f, 0x60, 0xe7, 0x3d, 0xc4, 0x84, 0x3d, 0x59, 0xd9, 0x67, 0x1a, 0x6d,
+	0x7d, 0xe3, 0x94, 0x9c, 0x6d, 0xb9, 0x0d, 0xef, 0x9e, 0x1c, 0x1d, 0x22,
+	0x56, 0xc6, 0x58, 0xbc, 0x1f, 0x99, 0x19, 0xac, 0x22, 0x2e, 0x78, 0xd9,
+	0xc9, 0x75, 0xd7, 0xc5, 0x55, 0xfd, 0x4d, 0x25, 0xda, 0xd5, 0x8f, 0x28,
+	0xfb, 0x66, 0x75, 0x99, 0x26, 0x4c, 0xba, 0x12, 0xc4, 0xc6, 0xac, 0x81,
+	0xab, 0x89, 0x9d, 0xab, 0x16, 0x81, 0xda, 0x45, 0x1b, 0x3b, 0xcb, 0xdc,
+	0xac, 0x2a, 0x8a, 0x3f, 0x22, 0x76, 0x66, 0xaf, 0xcb, 0x50, 0x5b, 0x6c,
+	0x62, 0x8c, 0x2a, 0x38, 0x1a, 0xf5, 0xa1, 0x67, 0x8a, 0xb8, 0xc7, 0x9a,
+	0x9b, 0x99, 0x23, 0x3f, 0xd6, 0xfb, 0x71, 0x6c, 0xc1, 0x9e, 0x9b, 0x75,
+	0x12, 0xbf, 0xb9, 0xa2, 0x41, 0x94, 0x2f, 0xba, 0xf0, 0x1c, 0xf1, 0xf3,
+	0x36, 0xda, 0xf9, 0x0c, 0xf1, 0xf3, 0x9e, 0x1b, 0x66, 0x67, 0xb3, 0x8b,
+	0x78, 0x95, 0x58, 0xbe, 0xae, 0x16, 0x51, 0x99, 0x8b, 0x98, 0x57, 0x36,
+	0xfa, 0x70, 0xce, 0xc2, 0xcf, 0xde, 0xe5, 0xb4, 0x62, 0xcb, 0x56, 0x46,
+	0x5b, 0x88, 0x5d, 0x1d, 0xb4, 0x6b, 0xdb, 0x49, 0xb5, 0xeb, 0x25, 0xea,
+	0xa2, 0x31, 0x7a, 0xde, 0xb2, 0xc7, 0x60, 0x5c, 0x66, 0x2c, 0x43, 0xad,
+	0x72, 0xfe, 0xaa, 0x82, 0xf6, 0xee, 0x9e, 0x8c, 0x24, 0x3f, 0x80, 0x1d,
+	0x93, 0xb1, 0x5c, 0x59, 0xb1, 0x1e, 0xca, 0xbd, 0x09, 0xde, 0x4b, 0xa2,
+	0x6b, 0xa3, 0xed, 0xdf, 0xb1, 0xdc, 0x71, 0x62, 0x57, 0xd9, 0x5b, 0x0d,
+	0xf8, 0x3b, 0x8d, 0x2e, 0x4c, 0x1b, 0x61, 0x94, 0x9f, 0x2b, 0xee, 0xd1,
+	0x9e, 0x93, 0x33, 0x7b, 0x8f, 0xb6, 0x06, 0xbe, 0x53, 0xc2, 0x84, 0x49,
+	0xe2, 0xbb, 0xa0, 0xe7, 0x8e, 0xbc, 0xe0, 0xc5, 0x5e, 0x1c, 0x33, 0xd4,
+	0xd0, 0x4f, 0x18, 0x13, 0xf7, 0xc9, 0xfe, 0xfc, 0x0d, 0x33, 0xaa, 0x87,
+	0x79, 0xcf, 0xf8, 0xdc, 0x8c, 0x2a, 0x95, 0xc5, 0xaf, 0x9c, 0xcd, 0xe5,
+	0x70, 0xac, 0x93, 0x19, 0x89, 0x1a, 0x1a, 0xc3, 0x63, 0xc4, 0x1c, 0xbf,
+	0x54, 0x7c, 0x9a, 0x6b, 0xa8, 0xc9, 0xa9, 0x86, 0xe6, 0x15, 0x1f, 0xdf,
+	0xbd, 0x87, 0xf9, 0xed, 0x1e, 0xfa, 0x46, 0x64, 0xb9, 0x42, 0x71, 0xe2,
+	0xd2, 0x97, 0x2d, 0x3c, 0xea, 0xed, 0xe5, 0xb5, 0xe9, 0x7c, 0x09, 0xd7,
+	0xf4, 0x09, 0xaf, 0xe8, 0x9c, 0xb2, 0x73, 0x88, 0x96, 0xf3, 0x2e, 0x5f,
+	0x82, 0x2d, 0x5b, 0x25, 0x65, 0x7d, 0x60, 0x32, 0x60, 0x0e, 0xac, 0x94,
+	0x18, 0xd6, 0xb0, 0xd3, 0x10, 0xff, 0x1a, 0x24, 0x9f, 0x7d, 0x38, 0x62,
+	0xac, 0x66, 0xef, 0x26, 0xf3, 0xd2, 0x26, 0x62, 0xeb, 0x5e, 0xd6, 0x60,
+	0xd3, 0x4c, 0xe9, 0x69, 0xb3, 0x69, 0x93, 0xa6, 0xe7, 0x94, 0x42, 0x4d,
+	0x88, 0xf8, 0x66, 0x3d, 0x6b, 0x77, 0x5b, 0xbe, 0x09, 0x6f, 0x9e, 0xd1,
+	0xe8, 0x9b, 0xed, 0xc4, 0xef, 0xbd, 0xb8, 0x97, 0xf2, 0x7c, 0x23, 0xff,
+	0x4d, 0x24, 0xbf, 0xee, 0xc2, 0xc4, 0x54, 0x12, 0x5b, 0xd6, 0x8f, 0xe0,
+	0xd2, 0xef, 0x78, 0x98, 0xab, 0x7c, 0x78, 0x72, 0x4a, 0xf2, 0x6b, 0x09,
+	0x6f, 0xdf, 0x88, 0x45, 0x3c, 0x08, 0x5b, 0x38, 0xe4, 0x8b, 0xef, 0xd9,
+	0x18, 0xc5, 0xcb, 0x5e, 0xb8, 0xf4, 0x3e, 0xf3, 0xd0, 0xfa, 0x7f, 0x81,
+	0x67, 0x88, 0x5b, 0x88, 0x05, 0x2a, 0x62, 0xd6, 0xf9, 0xb8, 0x12, 0xde,
+	0x75, 0xd1, 0x07, 0x24, 0xa6, 0x57, 0x33, 0xd6, 0x4d, 0x62, 0xe7, 0xe5,
+	0xe2, 0xfc, 0xf2, 0xed, 0x93, 0xea, 0xd2, 0x11, 0x44, 0x88, 0xa1, 0x31,
+	0x28, 0xd8, 0xcd, 0x49, 0xbc, 0x7b, 0x25, 0x1a, 0xd5, 0xcf, 0x11, 0xef,
+	0x8e, 0xd2, 0xd6, 0x2e, 0x4d, 0x7c, 0x33, 0x80, 0xb2, 0xc5, 0x10, 0x7d,
+	0x52, 0xe6, 0x97, 0x7f, 0xe5, 0xb5, 0xe7, 0x97, 0x32, 0x33, 0x97, 0xf3,
+	0x23, 0xe8, 0x28, 0x63, 0xef, 0x56, 0xae, 0xa4, 0x99, 0x93, 0x67, 0xbd,
+	0xbb, 0x99, 0xdf, 0xfb, 0x8d, 0xa0, 0x7f, 0x77, 0x3e, 0xc0, 0xdf, 0x3a,
+	0x7f, 0x7f, 0x7e, 0x07, 0x9f, 0x0f, 0xf1, 0x33, 0x8c, 0x6c, 0x2e, 0x52,
+	0x21, 0xcd, 0x40, 0x36, 0x67, 0xe7, 0xbc, 0x70, 0xee, 0x90, 0x57, 0xb0,
+	0x66, 0xdb, 0x94, 0xfd, 0x5d, 0xbb, 0xe1, 0xfb, 0xe7, 0x31, 0xbf, 0x9b,
+	0x7c, 0x9f, 0x39, 0xa9, 0xe1, 0xa3, 0x93, 0x16, 0xe6, 0x2f, 0x10, 0xf3,
+	0x0f, 0xbb, 0x9d, 0x82, 0x35, 0x7f, 0x61, 0x9e, 0x8f, 0x46, 0x07, 0xe6,
+	0xe8, 0x07, 0x3d, 0xa4, 0xeb, 0xd0, 0x82, 0x16, 0xbf, 0x36, 0x9f, 0xf6,
+	0xcc, 0xf7, 0xf2, 0xc9, 0x18, 0xde, 0xb9, 0x3e, 0x63, 0xfd, 0xa4, 0xcc,
+	0x9a, 0x15, 0xe3, 0xb1, 0x77, 0x37, 0xc1, 0xd3, 0xc2, 0x7e, 0xd3, 0xcd,
+	0xe7, 0x43, 0xd6, 0xf3, 0x32, 0xf3, 0xbd, 0x8e, 0x9d, 0x3f, 0xba, 0xfe,
+	0xce, 0x61, 0x76, 0x6a, 0x9e, 0xf3, 0x8c, 0x2d, 0xa7, 0xf5, 0x9c, 0xcc,
+	0x65, 0xbd, 0xcb, 0xb0, 0xe2, 0x6b, 0x88, 0x32, 0x89, 0x7d, 0x0f, 0x99,
+	0xb6, 0xdf, 0x06, 0xfd, 0x3b, 0x19, 0x0f, 0xdf, 0xa6, 0x7d, 0x76, 0x9e,
+	0xab, 0xf3, 0xdf, 0x6d, 0xec, 0xb2, 0x64, 0xbe, 0xfb, 0x9c, 0xd4, 0x24,
+	0xb9, 0xff, 0x40, 0x85, 0x60, 0xef, 0x27, 0x59, 0xb3, 0x46, 0x0d, 0xd9,
+	0x03, 0x80, 0xe2, 0x4a, 0x1c, 0x41, 0xe7, 0x74, 0x18, 0x6f, 0xeb, 0xde,
+	0xe2, 0x59, 0x17, 0x89, 0xc9, 0x69, 0xc6, 0x64, 0x10, 0x63, 0x46, 0x24,
+	0xfc, 0x36, 0xf1, 0x69, 0x9a, 0x0c, 0x1f, 0xcb, 0x3a, 0xf1, 0x36, 0x31,
+	0x23, 0x14, 0xfb, 0xac, 0xa8, 0xfd, 0x6e, 0xe9, 0xef, 0x4a, 0x84, 0x6b,
+	0x22, 0x2d, 0x07, 0x50, 0x87, 0x0c, 0x73, 0xbe, 0x57, 0xfb, 0x21, 0x8e,
+	0x9f, 0x70, 0xe0, 0x7e, 0xf6, 0x7d, 0xc9, 0xbb, 0x74, 0x7e, 0x6f, 0x1c,
+	0x7a, 0x1f, 0xff, 0x68, 0xce, 0xca, 0x79, 0x2c, 0x45, 0xce, 0x7c, 0x7c,
+	0x62, 0xd6, 0x6a, 0x5a, 0xe1, 0x07, 0xd0, 0x52, 0x57, 0xd1, 0x38, 0xbc,
+	0x8c, 0x0f, 0xcc, 0x02, 0xef, 0xbd, 0xc7, 0xf8, 0x79, 0x49, 0x8f, 0x84,
+	0x1c, 0x14, 0xa6, 0x10, 0x74, 0xe2, 0x3e, 0x5d, 0xe6, 0x29, 0xea, 0xf0,
+	0xb3, 0x50, 0x87, 0x2e, 0x28, 0x72, 0x86, 0xe7, 0x92, 0x99, 0xae, 0x91,
+	0x75, 0x15, 0xac, 0x5b, 0xd3, 0xd8, 0x55, 0x06, 0xb5, 0xc5, 0xad, 0x68,
+	0xfa, 0xfb, 0xca, 0xff, 0x32, 0x0b, 0xc1, 0x4f, 0xcc, 0x77, 0xb4, 0x12,
+	0x5d, 0x35, 0xec, 0x71, 0x96, 0x78, 0xab, 0xc3, 0x71, 0x43, 0xf6, 0xf1,
+	0x7e, 0x88, 0xfb, 0x4f, 0xb8, 0xd0, 0x1e, 0xff, 0xb9, 0x99, 0x0e, 0x0a,
+	0xcd, 0x50, 0x25, 0x2a, 0x84, 0xbe, 0x3d, 0xdb, 0x7e, 0x31, 0x0f, 0xa5,
+	0xc3, 0x10, 0xbc, 0x2c, 0x7e, 0x3a, 0x0d, 0xd3, 0x90, 0x99, 0xa2, 0x89,
+	0x3b, 0xe3, 0x23, 0x78, 0x2f, 0x9e, 0xfc, 0x4f, 0x1e, 0xa8, 0x4b, 0x97,
+	0x9d, 0x6a, 0xa1, 0xc9, 0x19, 0x56, 0xbc, 0x0d, 0xda, 0x70, 0x83, 0x55,
+	0x6f, 0x2e, 0xb2, 0x77, 0xf2, 0x31, 0xb7, 0x48, 0x8f, 0x39, 0x8d, 0xc5,
+	0xc9, 0x34, 0x5c, 0xc4, 0x76, 0xa3, 0xcd, 0x6a, 0xff, 0x33, 0x8a, 0x1a,
+	0x3a, 0xa8, 0x84, 0x95, 0x7b, 0xb5, 0x14, 0x9e, 0xd3, 0xa3, 0xc9, 0x36,
+	0xa5, 0xce, 0xd3, 0x95, 0x2f, 0xd1, 0x6e, 0x27, 0x56, 0x51, 0x0b, 0x97,
+	0x9d, 0xe5, 0xa8, 0xdd, 0xa0, 0x75, 0x95, 0x3b, 0xd5, 0xd4, 0xd7, 0x18,
+	0x5f, 0xdb, 0xf3, 0x05, 0xef, 0xfb, 0x51, 0x07, 0xd6, 0x5a, 0xfb, 0x0d,
+	0x99, 0xe2, 0xbc, 0x74, 0x1a, 0xdd, 0x93, 0xe6, 0x96, 0x8b, 0x71, 0x35,
+	0xf4, 0x8c, 0x92, 0xde, 0xed, 0x23, 0xa6, 0x79, 0x00, 0x5a, 0x78, 0x81,
+	0x75, 0xaa, 0x3d, 0xef, 0xc0, 0x2d, 0xa7, 0x84, 0x66, 0x86, 0x34, 0x8f,
+	0xa0, 0xfc, 0x84, 0xb9, 0x65, 0xb7, 0xae, 0xa6, 0x2e, 0x3b, 0xd3, 0xff,
+	0xbd, 0x96, 0x7a, 0xeb, 0x50, 0x64, 0xbf, 0x6d, 0x84, 0xb8, 0x62, 0x44,
+	0xce, 0xcd, 0xc5, 0xfe, 0x98, 0x98, 0xe2, 0x5b, 0xf4, 0x55, 0x67, 0xc2,
+	0x4f, 0x3e, 0xd5, 0xd8, 0x1c, 0x64, 0xce, 0x1e, 0xc6, 0x65, 0x3d, 0xed,
+	0xed, 0x6c, 0x88, 0x11, 0x9b, 0x85, 0x58, 0x07, 0xc3, 0x38, 0x46, 0x8c,
+	0x77, 0x24, 0x5f, 0x86, 0x42, 0x40, 0x23, 0x36, 0xeb, 0x85, 0x63, 0xd2,
+	0xa7, 0xcc, 0x67, 0x22, 0x7a, 0x3b, 0xfe, 0x33, 0x0a, 0x21, 0x71, 0x91,
+	0x23, 0xf0, 0x9d, 0xf8, 0x7b, 0xb3, 0x4a, 0xd3, 0x5a, 0x26, 0x15, 0xae,
+	0xfb, 0x54, 0x88, 0x3a, 0xe6, 0x7b, 0x72, 0xbe, 0xc5, 0xe8, 0xc1, 0xbd,
+	0x93, 0x41, 0xbe, 0x5f, 0x85, 0x75, 0x27, 0xc2, 0xb8, 0x12, 0xbf, 0x19,
+	0x85, 0x1a, 0x1b, 0x03, 0x79, 0x35, 0xfa, 0x11, 0xfb, 0xac, 0x34, 0x7b,
+	0x4a, 0xd9, 0x63, 0x3a, 0x62, 0x48, 0x7f, 0xee, 0xe2, 0x77, 0x1f, 0x7f,
+	0x45, 0x9f, 0xdf, 0x2a, 0x62, 0x9d, 0xa9, 0xd6, 0xf0, 0xfc, 0xcf, 0x2b,
+	0xec, 0x79, 0x5a, 0x98, 0xcf, 0x05, 0xac, 0x19, 0xe1, 0x28, 0x69, 0x9e,
+	0x9d, 0x96, 0xbe, 0xad, 0x6d, 0xb3, 0xa7, 0xb8, 0x4f, 0xff, 0x53, 0xdd,
+	0x81, 0x2d, 0xec, 0xed, 0x43, 0x9a, 0xd4, 0xcb, 0x51, 0xb5, 0x16, 0x9b,
+	0x71, 0x3a, 0xc0, 0x26, 0x5c, 0xfb, 0x0f, 0x98, 0x08, 0xc4, 0x98, 0xf3,
+	0x35, 0xbc, 0x9b, 0xf9, 0x32, 0xfb, 0x9d, 0x3a, 0x39, 0xe3, 0x83, 0x5b,
+	0x4e, 0xb8, 0xb9, 0xe6, 0x16, 0xe2, 0x9a, 0x4e, 0xbc, 0x16, 0xb0, 0x7b,
+	0x8d, 0xa3, 0xbc, 0x3e, 0x3e, 0xe7, 0x23, 0x16, 0xf5, 0xf0, 0xf7, 0x46,
+	0xde, 0xbe, 0x88, 0x27, 0x91, 0xe5, 0xdf, 0xe2, 0xc9, 0x43, 0x3c, 0xa0,
+	0xe1, 0x6a, 0xe6, 0x65, 0x5c, 0x21, 0xed, 0xf4, 0x9c, 0x4d, 0x73, 0x2a,
+	0x2f, 0x74, 0x65, 0xbd, 0x48, 0xaa, 0xd6, 0x29, 0xf4, 0x7d, 0x72, 0xde,
+	0xf7, 0xdf, 0xb9, 0x06, 0x91, 0xdd, 0x09, 0xf6, 0xc7, 0x7a, 0x03, 0xda,
+	0x03, 0xb4, 0x97, 0x21, 0x6b, 0xa8, 0xec, 0x45, 0xe5, 0xdd, 0x10, 0xd6,
+	0x4e, 0x9a, 0x23, 0xa1, 0x84, 0x5c, 0x37, 0xcd, 0xea, 0x4d, 0x5a, 0xe8,
+	0x4d, 0xc5, 0xc5, 0x5a, 0xe7, 0xa2, 0x0e, 0xc6, 0x71, 0x36, 0xd3, 0xb8,
+	0xf4, 0x1e, 0xb1, 0x53, 0x98, 0xbd, 0xde, 0x25, 0xe7, 0x38, 0xe6, 0x33,
+	0x0b, 0x95, 0x32, 0x23, 0x18, 0xcf, 0xfb, 0x94, 0xb9, 0xcc, 0x91, 0x4a,
+	0xc9, 0x45, 0x63, 0xf4, 0x85, 0xa6, 0x49, 0xe1, 0xd5, 0x1c, 0xa9, 0x22,
+	0x9d, 0x63, 0xa4, 0x33, 0xb7, 0x51, 0xeb, 0x1f, 0x53, 0x44, 0x67, 0x3e,
+	0xe2, 0xba, 0x8b, 0x32, 0x3f, 0xa3, 0xde, 0xfe, 0x94, 0xcf, 0x8b, 0xde,
+	0x82, 0x78, 0xad, 0x48, 0xe7, 0x89, 0xfc, 0x12, 0xe6, 0x32, 0x1f, 0x58,
+	0x7f, 0x8f, 0xe5, 0x63, 0xac, 0x7d, 0x83, 0xc8, 0x31, 0x9f, 0x4c, 0x66,
+	0x1a, 0xfb, 0x27, 0xc9, 0x87, 0x7d, 0x36, 0x6f, 0x10, 0x4f, 0x17, 0x9f,
+	0x19, 0xe5, 0xbb, 0xa3, 0xd7, 0xfe, 0x16, 0x1d, 0xd9, 0xfb, 0xff, 0xf6,
+	0x1e, 0x43, 0x39, 0x6d, 0x67, 0xf7, 0xe1, 0x47, 0x0d, 0xb7, 0xcc, 0xc3,
+	0xf1, 0xf2, 0xf4, 0x16, 0x8c, 0xe9, 0x7f, 0x8e, 0xbd, 0x94, 0x7b, 0x9c,
+	0xfa, 0x3c, 0x61, 0x58, 0xfb, 0xfc, 0x72, 0xfe, 0x8b, 0xb9, 0xfa, 0x60,
+	0xeb, 0x19, 0x62, 0xb1, 0xe3, 0x8c, 0x99, 0xfd, 0xf1, 0xc6, 0xde, 0x57,
+	0xe8, 0x77, 0xc9, 0xdf, 0x96, 0xbd, 0x74, 0x60, 0x32, 0xfb, 0x0d, 0xcc,
+	0xd6, 0x34, 0x2e, 0x3f, 0xcf, 0x9c, 0x70, 0x9a, 0x79, 0xca, 0xc5, 0x9c,
+	0x50, 0x9d, 0x25, 0x86, 0x64, 0x9e, 0x2a, 0x30, 0x4f, 0xb9, 0xb4, 0xc6,
+	0xa5, 0x79, 0xfc, 0x15, 0xf5, 0x22, 0xfc, 0x45, 0x62, 0xf3, 0x90, 0x67,
+	0xed, 0xf9, 0xab, 0x36, 0x3f, 0x84, 0x4b, 0x37, 0xdb, 0x33, 0x34, 0x27,
+	0x6b, 0xf6, 0xbe, 0x4c, 0x63, 0x60, 0x4c, 0x68, 0xf7, 0xa9, 0xa1, 0x34,
+	0x6d, 0x35, 0x61, 0x61, 0xef, 0x61, 0xf6, 0x0b, 0x72, 0xde, 0xab, 0x0a,
+	0x2e, 0xfa, 0xfe, 0x98, 0x2e, 0xe7, 0x20, 0x42, 0xfe, 0xed, 0xb4, 0xe1,
+	0x98, 0xd1, 0xd8, 0x12, 0x51, 0x76, 0xe3, 0x52, 0x31, 0xc7, 0xda, 0x58,
+	0x5a, 0xed, 0x3f, 0x86, 0xc6, 0xde, 0x07, 0xf0, 0x75, 0x24, 0x6b, 0x1a,
+	0x07, 0xa6, 0x11, 0xd1, 0xef, 0x83, 0x9c, 0x1b, 0xb5, 0x69, 0xd5, 0xe7,
+	0x9c, 0xc4, 0x23, 0x9f, 0x98, 0xab, 0xb5, 0x27, 0x30, 0x4d, 0xcc, 0xd8,
+	0xb0, 0x5e, 0x5b, 0xfa, 0x6e, 0xf1, 0x9e, 0xbd, 0xa7, 0x24, 0xfe, 0xe2,
+	0xa1, 0x0e, 0xca, 0xe1, 0x5a, 0x51, 0xc7, 0x35, 0xa8, 0x0b, 0xeb, 0x4c,
+	0xf1, 0x45, 0x1c, 0xa2, 0xbf, 0x4d, 0xe7, 0x15, 0xe8, 0xf5, 0x17, 0x31,
+	0x2c, 0xb5, 0x89, 0xef, 0xb4, 0x65, 0x7c, 0xc4, 0x29, 0x21, 0x94, 0x6b,
+	0x91, 0xf0, 0x28, 0xe5, 0x6b, 0x63, 0x2e, 0x1f, 0x67, 0x0e, 0x49, 0x07,
+	0x7c, 0xd6, 0x39, 0xd7, 0x72, 0x2d, 0x64, 0xfd, 0x6f, 0x82, 0xf4, 0x41,
+	0x0d, 0xb3, 0xb2, 0x9f, 0x7d, 0x04, 0x17, 0xa7, 0x0b, 0x38, 0x1e, 0x4f,
+	0xe2, 0x40, 0x4d, 0x00, 0x93, 0xc6, 0x4a, 0x6b, 0x6e, 0x20, 0xfd, 0x56,
+	0x77, 0xf6, 0xb0, 0x35, 0x8b, 0xdc, 0x16, 0x77, 0xd4, 0xcb, 0x79, 0x8f,
+	0x39, 0xf6, 0x5d, 0xd3, 0xfa, 0x08, 0x0e, 0xe9, 0xdf, 0x82, 0xbe, 0x42,
+	0x72, 0xe7, 0x18, 0xce, 0xcf, 0x4a, 0x0d, 0x9b, 0x68, 0xbd, 0x75, 0x52,
+	0xf4, 0xe3, 0x20, 0xe6, 0xf5, 0xa0, 0xc9, 0xc2, 0x70, 0xaf, 0xb7, 0xae,
+	0x99, 0xb5, 0xb1, 0x5c, 0x53, 0x4e, 0xce, 0x66, 0x57, 0xc1, 0x4f, 0x7d,
+	0x5d, 0x88, 0xbb, 0x99, 0x73, 0x44, 0x9f, 0x72, 0x16, 0xd0, 0x96, 0x33,
+	0x96, 0x53, 0x30, 0xd6, 0x7c, 0xe3, 0x5e, 0x8b, 0xfc, 0x9f, 0xc2, 0xb5,
+	0xf3, 0x89, 0xc5, 0xd9, 0xf8, 0x1f, 0x9b, 0x97, 0x6e, 0x12, 0xb9, 0x5b,
+	0x7d, 0xcc, 0xe9, 0xe1, 0xd9, 0x6b, 0xfa, 0x15, 0x9d, 0x9e, 0x93, 0x9a,
+	0x61, 0xe9, 0xdc, 0x9e, 0xb7, 0xa9, 0xc3, 0xef, 0x28, 0x8d, 0xac, 0x27,
+	0xf4, 0xab, 0x1a, 0xfa, 0x5b, 0x13, 0x06, 0x56, 0x27, 0x5c, 0x7d, 0x57,
+	0x8d, 0x2d, 0x68, 0xd9, 0xf0, 0xae, 0x89, 0x9b, 0xdb, 0xe0, 0xd4, 0xe4,
+	0xfa, 0xac, 0x99, 0x0c, 0xc8, 0xdf, 0x4f, 0xfa, 0xa4, 0x96, 0xbf, 0x68,
+	0x14, 0xcc, 0x35, 0x2b, 0x6d, 0x6c, 0xf8, 0xf7, 0x19, 0xd9, 0x07, 0x4b,
+	0x9b, 0xec, 0xb5, 0x97, 0xde, 0x76, 0x1e, 0xc6, 0xdf, 0xe6, 0x8e, 0xe0,
+	0xad, 0x69, 0x17, 0x71, 0xa6, 0xc8, 0xb2, 0x05, 0xd5, 0x1b, 0xa2, 0xc9,
+	0x77, 0x99, 0x17, 0x97, 0x66, 0x4b, 0x7e, 0xf1, 0x7a, 0xeb, 0xda, 0x59,
+	0x85, 0xb4, 0xaa, 0x50, 0x46, 0x39, 0x7f, 0xac, 0x3b, 0x11, 0x2e, 0x62,
+	0x5b, 0x27, 0xf9, 0xdc, 0x97, 0xb1, 0x31, 0x6f, 0x24, 0x37, 0xed, 0xb3,
+	0xe7, 0x5f, 0x3e, 0xe6, 0xd1, 0x71, 0x4c, 0x64, 0x1a, 0x63, 0xef, 0xc9,
+	0x79, 0x1e, 0xf6, 0x62, 0x97, 0x30, 0x8e, 0x13, 0x99, 0x52, 0x0e, 0x0d,
+	0xc9, 0x39, 0xd8, 0x58, 0xd8, 0x61, 0xe7, 0xc8, 0xb0, 0x43, 0x4d, 0xf3,
+	0xd7, 0x27, 0xd8, 0x60, 0x34, 0x1f, 0x09, 0x95, 0xc3, 0x89, 0xfd, 0xba,
+	0xed, 0x1f, 0xf5, 0xf3, 0x6e, 0x84, 0x57, 0x48, 0x5d, 0x96, 0x9a, 0xec,
+	0x62, 0x4d, 0x5e, 0x89, 0xe4, 0x4a, 0x17, 0x5e, 0xd7, 0x44, 0x1f, 0x53,
+	0x25, 0x7d, 0xe8, 0xe7, 0xf0, 0x90, 0x59, 0xe8, 0x15, 0x5f, 0x72, 0xe3,
+	0x48, 0xd3, 0x9c, 0x39, 0x1b, 0x14, 0xd9, 0x9d, 0x38, 0xcd, 0xfc, 0x8a,
+	0x9b, 0x23, 0xa1, 0xd3, 0xac, 0xd9, 0x63, 0x5a, 0xc9, 0xc7, 0xff, 0x63,
+	0x91, 0x4f, 0xad, 0x7f, 0x01, 0x47, 0xf8, 0x77, 0x7d, 0xe8, 0x80, 0x62,
+	0xaf, 0xb7, 0x66, 0xfe, 0x43, 0x5f, 0x69, 0x76, 0x2a, 0xcf, 0x86, 0x73,
+	0xa7, 0xf9, 0x5d, 0x68, 0xf9, 0xe8, 0x9f, 0xe5, 0x18, 0x08, 0xca, 0x79,
+	0x10, 0xd1, 0x8b, 0xec, 0x3f, 0x82, 0xfa, 0x30, 0xf1, 0x32, 0xf5, 0x71,
+	0xe4, 0xda, 0xd9, 0x2b, 0x3b, 0x7f, 0x55, 0xf0, 0xfa, 0xf6, 0xf8, 0x4b,
+	0x9b, 0xbd, 0xf8, 0x95, 0x79, 0x29, 0x18, 0x62, 0x4e, 0x10, 0x9b, 0xa6,
+	0x2c, 0x1c, 0xe9, 0x24, 0x3e, 0xd9, 0x67, 0x9f, 0x33, 0x69, 0x95, 0xff,
+	0xa1, 0x29, 0xca, 0x51, 0x18, 0x24, 0xce, 0x5e, 0xcc, 0x58, 0x67, 0xfb,
+	0x06, 0xde, 0x54, 0x22, 0xcc, 0x35, 0x5f, 0xc2, 0x40, 0xad, 0xd0, 0x0b,
+	0xf8, 0x77, 0xce, 0xc4, 0xa8, 0x83, 0x3a, 0xa1, 0x6b, 0x3e, 0xc3, 0x6e,
+	0xee, 0xc8, 0xa4, 0xd0, 0x07, 0xc6, 0x26, 0x23, 0x43, 0x3f, 0x06, 0x36,
+	0x57, 0x41, 0x4d, 0x2d, 0x14, 0xff, 0xdf, 0xe3, 0x67, 0x8a, 0xd0, 0x12,
+	0x3a, 0x2e, 0x18, 0xcc, 0x71, 0x53, 0x8b, 0x15, 0xd4, 0x9d, 0xda, 0xfb,
+	0x3d, 0xa5, 0x02, 0x4f, 0x3c, 0x15, 0x23, 0xef, 0x2b, 0xfc, 0xdb, 0x67,
+	0x3c, 0xf0, 0x9e, 0xa9, 0x62, 0xcd, 0xf5, 0xe0, 0x72, 0x33, 0xed, 0xfa,
+	0x54, 0x89, 0x77, 0x6b, 0x9f, 0x14, 0x8f, 0x67, 0xc3, 0x30, 0xe8, 0xb3,
+	0x8b, 0x86, 0xec, 0x17, 0x7b, 0xac, 0xfc, 0xb9, 0xb4, 0xb1, 0xce, 0xda,
+	0xaf, 0x7a, 0x3e, 0xaf, 0x85, 0xce, 0x2a, 0x55, 0xf8, 0xe0, 0x44, 0xe1,
+	0xe6, 0x72, 0x98, 0x2f, 0xae, 0x4e, 0x44, 0xfb, 0xf7, 0xd2, 0xe7, 0xd7,
+	0xae, 0x09, 0xb2, 0x97, 0x61, 0x4f, 0xb9, 0x49, 0xfa, 0xdf, 0x69, 0xf6,
+	0xbf, 0xa5, 0xbd, 0x7f, 0x6d, 0xe8, 0x11, 0x25, 0xdd, 0xe9, 0x87, 0xf9,
+	0x51, 0x79, 0xc2, 0xfc, 0xd8, 0x9d, 0x88, 0xf2, 0x7d, 0xd9, 0xdf, 0x33,
+	0xcd, 0x9f, 0x36, 0x9b, 0x66, 0xae, 0x39, 0xd2, 0x1f, 0x70, 0x06, 0x70,
+	0xa6, 0x41, 0xf6, 0x04, 0x1d, 0xf8, 0x20, 0xaa, 0x85, 0xf6, 0x42, 0xf6,
+	0xe8, 0x99, 0xe3, 0x57, 0xca, 0xf9, 0xc4, 0x3a, 0x7f, 0x97, 0xb1, 0x02,
+	0xcf, 0x2d, 0x6c, 0xc2, 0x80, 0x1b, 0xd6, 0xf9, 0x19, 0x53, 0xc7, 0x9b,
+	0xab, 0x21, 0x75, 0x3b, 0xda, 0xf2, 0x08, 0x82, 0x58, 0xc8, 0x1f, 0xc1,
+	0xc3, 0x27, 0x64, 0xaf, 0x71, 0xb2, 0xd5, 0x73, 0xc2, 0xfc, 0xfb, 0x50,
+	0xa2, 0xc0, 0xbc, 0x68, 0x9a, 0x15, 0x9b, 0x1a, 0x43, 0x2c, 0x47, 0xc4,
+	0x18, 0x69, 0xc1, 0xee, 0x43, 0x1f, 0xa0, 0x06, 0x67, 0xe7, 0x92, 0x37,
+	0xb3, 0x97, 0xec, 0x7a, 0x5a, 0x09, 0xe0, 0x07, 0x94, 0xf1, 0xd9, 0xbc,
+	0xe0, 0x14, 0xa3, 0xb5, 0xfb, 0xc4, 0x2a, 0xbc, 0xb8, 0x10, 0xc4, 0x59,
+	0x43, 0x23, 0x4e, 0x82, 0x52, 0x99, 0x30, 0xab, 0xab, 0xc9, 0x6b, 0xa5,
+	0xd3, 0x89, 0xce, 0xb8, 0xf4, 0x87, 0xda, 0x90, 0x4f, 0xc1, 0xaa, 0x72,
+	0x68, 0xcb, 0x0f, 0x01, 0xc3, 0x5e, 0xf6, 0xab, 0x4f, 0x2b, 0xd1, 0xfe,
+	0xf7, 0x9d, 0x41, 0xfc, 0x80, 0xf9, 0xe7, 0x7b, 0x79, 0x39, 0x5b, 0xc5,
+	0x1c, 0x33, 0x17, 0xa6, 0xad, 0x3c, 0x70, 0xd4, 0x57, 0xe1, 0x28, 0xe3,
+	0xe5, 0x65, 0xbd, 0x8c, 0x39, 0x4a, 0xce, 0x5a, 0x49, 0x7e, 0x7f, 0x54,
+	0xce, 0x94, 0x98, 0xcf, 0x6b, 0x76, 0xbf, 0xaf, 0xcf, 0xdf, 0x78, 0x5e,
+	0x39, 0xc0, 0xbc, 0xde, 0xd8, 0x1b, 0x52, 0x5e, 0x35, 0x93, 0xbf, 0xad,
+	0x50, 0xce, 0x07, 0xab, 0x50, 0x61, 0xc9, 0x8a, 0xd1, 0x6c, 0xa9, 0xa6,
+	0x54, 0x4b, 0x2f, 0xd7, 0x9b, 0x2e, 0xfa, 0x60, 0x25, 0x63, 0xfd, 0x18,
+	0x6b, 0x74, 0xf9, 0x09, 0xa9, 0x25, 0xec, 0x5f, 0x94, 0x2d, 0xc4, 0xc2,
+	0x82, 0x1b, 0x3c, 0x78, 0x20, 0xa0, 0xb6, 0xc8, 0x99, 0xed, 0x67, 0xf3,
+	0x1d, 0x2e, 0x39, 0x3b, 0xf5, 0x5c, 0x5e, 0x6a, 0xb9, 0xe4, 0x82, 0xd2,
+	0x7a, 0x21, 0xd4, 0x4e, 0x8a, 0x8d, 0x86, 0x5b, 0x3f, 0x9a, 0xf4, 0xc9,
+	0xf9, 0xfa, 0x11, 0x07, 0x7b, 0x6d, 0xcf, 0xa4, 0x69, 0xee, 0x69, 0xd6,
+	0x86, 0xb6, 0x38, 0x65, 0x6f, 0x39, 0x32, 0x70, 0x4e, 0x51, 0x5b, 0x26,
+	0x94, 0x1b, 0xe9, 0xfc, 0xb7, 0x2a, 0x89, 0x91, 0x34, 0xe5, 0x7c, 0xdc,
+	0x92, 0x69, 0x8a, 0x32, 0x95, 0xce, 0x16, 0x55, 0xe1, 0xf2, 0x34, 0x34,
+	0x46, 0x2d, 0xce, 0xeb, 0x4c, 0x4e, 0x81, 0x68, 0xb2, 0x1d, 0xe2, 0xff,
+	0xea, 0x80, 0x60, 0xa8, 0x4a, 0xe6, 0xe4, 0xb9, 0x69, 0xa9, 0x31, 0x8a,
+	0xe0, 0x93, 0x34, 0xd7, 0xc6, 0x95, 0x8d, 0xc0, 0xab, 0x93, 0xf6, 0xde,
+	0x7b, 0xf1, 0x2c, 0xb8, 0x75, 0xe6, 0xe1, 0x11, 0xeb, 0x2c, 0x83, 0xd0,
+	0x3f, 0x8c, 0x33, 0x19, 0xc1, 0x94, 0xc3, 0xc4, 0x94, 0x91, 0x14, 0xf1,
+	0x66, 0x4b, 0xde, 0x3e, 0x97, 0xa5, 0x7f, 0x44, 0x9f, 0x7f, 0x9a, 0x58,
+	0xf5, 0x28, 0xec, 0xbd, 0xf7, 0x86, 0xe2, 0x59, 0x85, 0x48, 0xae, 0x4b,
+	0xd9, 0x91, 0x97, 0x18, 0x9b, 0x66, 0x8c, 0xb5, 0x2b, 0xdb, 0x17, 0x3a,
+	0x94, 0xee, 0x85, 0x1e, 0x65, 0x77, 0x5e, 0x7a, 0xd6, 0xc9, 0xd6, 0x07,
+	0x4e, 0xec, 0x52, 0x76, 0xcc, 0xf5, 0x29, 0xc4, 0xb4, 0x01, 0x4f, 0xa2,
+	0x5f, 0xe9, 0x59, 0xb0, 0xe7, 0xe7, 0x5d, 0xec, 0xbb, 0x76, 0x18, 0xa5,
+	0x7e, 0x5e, 0xfe, 0xdf, 0x2b, 0x28, 0xff, 0x5b, 0x31, 0xb0, 0x4d, 0x31,
+	0xcd, 0xdb, 0xe2, 0x7f, 0x27, 0xf6, 0x30, 0x9f, 0x8d, 0xb3, 0x36, 0x1a,
+	0x55, 0x18, 0x64, 0xdf, 0x31, 0xaa, 0xdf, 0x5a, 0xdc, 0x2f, 0x13, 0x99,
+	0xe4, 0x3c, 0x85, 0xf8, 0x2b, 0xd2, 0xe5, 0xe4, 0xe1, 0x1f, 0xc8, 0xff,
+	0x81, 0xa2, 0x5c, 0x3d, 0x72, 0xa6, 0xc0, 0x7d, 0xfd, 0xbc, 0xd9, 0xf1,
+	0xc9, 0xeb, 0x72, 0x31, 0xd7, 0x63, 0x9c, 0xf8, 0xf4, 0x80, 0xa2, 0xa6,
+	0x9e, 0xb1, 0xe5, 0x5a, 0xba, 0xcc, 0x18, 0x1e, 0xb5, 0x62, 0xd8, 0x96,
+	0x6b, 0x5d, 0x51, 0xae, 0xb5, 0xb9, 0x2e, 0xeb, 0x1c, 0x17, 0xf1, 0x7a,
+	0xeb, 0xe2, 0xa4, 0x9c, 0x37, 0x93, 0xd9, 0xa5, 0xc8, 0x26, 0x72, 0x9c,
+	0x30, 0x2b, 0xb4, 0x1e, 0x65, 0xa7, 0x75, 0xfe, 0x4c, 0xce, 0x7e, 0xc9,
+	0x5e, 0x7f, 0x49, 0x2e, 0xa9, 0xe3, 0x2b, 0xfc, 0x1d, 0x33, 0x72, 0x1e,
+	0xdb, 0x34, 0x5f, 0xd3, 0x83, 0x7e, 0x91, 0xe5, 0xac, 0x2e, 0xb2, 0xc8,
+	0xb9, 0x92, 0x92, 0x3c, 0x5f, 0x2b, 0xca, 0x23, 0xb6, 0xba, 0x6e, 0xa7,
+	0xd2, 0xff, 0x09, 0xbe, 0x9d, 0xb1, 0xcf, 0x9c, 0x94, 0xe4, 0xf1, 0x27,
+	0x84, 0xff, 0x8b, 0xad, 0xe3, 0xd3, 0xc3, 0x78, 0x95, 0xf7, 0x7f, 0x9e,
+	0x29, 0xc9, 0xe5, 0xc4, 0xfc, 0x5c, 0xe9, 0x2c, 0x1d, 0x5b, 0x4a, 0x23,
+	0xa2, 0x8f, 0xd1, 0x8f, 0x6c, 0xf9, 0xe4, 0x2c, 0x5d, 0x63, 0xe1, 0xb2,
+	0x35, 0xf7, 0x8a, 0x26, 0xd9, 0x2f, 0xe3, 0x6c, 0xfe, 0xd7, 0xed, 0xd7,
+	0x94, 0xab, 0x60, 0x8f, 0x2c, 0xb4, 0x5f, 0x27, 0x6d, 0x39, 0x73, 0xa2,
+	0xe0, 0x99, 0x39, 0x60, 0xce, 0xe0, 0xb2, 0x89, 0x11, 0x3c, 0xa9, 0x9b,
+	0xe6, 0xd3, 0xcd, 0x9a, 0x9c, 0x15, 0xba, 0x50, 0x6b, 0xcd, 0x85, 0xa0,
+	0x57, 0x69, 0xb2, 0x77, 0x27, 0xe7, 0x4d, 0xfa, 0xa8, 0x03, 0x91, 0x5d,
+	0x7c, 0xa0, 0x64, 0x7b, 0x39, 0x07, 0x97, 0xa6, 0x7e, 0x44, 0x37, 0xa5,
+	0xf3, 0x70, 0x32, 0x73, 0xb9, 0x51, 0x27, 0x5d, 0x96, 0x4e, 0x9e, 0xd5,
+	0xc5, 0x5f, 0x99, 0x7d, 0xe8, 0xab, 0xf3, 0xc4, 0x0f, 0x63, 0xba, 0xdb,
+	0xc2, 0x6a, 0x47, 0x89, 0x4f, 0x26, 0x18, 0x3b, 0x8f, 0x1b, 0x4b, 0x58,
+	0xca, 0xbd, 0x8c, 0x57, 0xaf, 0xfd, 0xcf, 0x9c, 0xf8, 0x8b, 0xde, 0xd2,
+	0x6d, 0x9d, 0x79, 0xfa, 0xa4, 0xe5, 0xd6, 0xa8, 0xe4, 0xa1, 0x1f, 0x36,
+	0xc9, 0x19, 0xa8, 0xf2, 0x44, 0xe0, 0x6b, 0xb2, 0xbf, 0x55, 0x96, 0x98,
+	0xfd, 0xea, 0x05, 0x4d, 0x74, 0xa3, 0x35, 0x9f, 0xd1, 0x44, 0xae, 0x1e,
+	0x7d, 0xdc, 0xfa, 0x1f, 0xce, 0x96, 0x4d, 0xfb, 0x34, 0x89, 0x1d, 0xdf,
+	0xc6, 0x36, 0x2b, 0x27, 0x9c, 0x4e, 0xdc, 0x66, 0xe9, 0xe0, 0x64, 0xe2,
+	0x56, 0xeb, 0x73, 0x3a, 0x11, 0xb3, 0x3e, 0xff, 0x24, 0x61, 0xeb, 0x26,
+	0x97, 0xa8, 0xb7, 0x3e, 0xe7, 0x13, 0xf6, 0xd9, 0xe9, 0xd9, 0x84, 0x66,
+	0x7d, 0x3e, 0x9f, 0x88, 0x58, 0x9f, 0x67, 0x13, 0xb7, 0x5c, 0xe7, 0x8b,
+	0x3f, 0xff, 0x0f, 0x4c, 0xd3, 0x85, 0x76, 0xdc, 0x3a, 0x00, 0x00, 0x00 };
 
-static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_txp_fw_06 = {
-	.ver_major			= 0x1,
+	/* Firmware version: 4.0.5 */
+	.ver_major			= 0x4,
 	.ver_minor			= 0x0,
-	.ver_fix			= 0x0,
+	.ver_fix			= 0x5,
 
-	.start_addr			= 0x080034b0,
+	.start_addr			= 0x08000098,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x5748,
+	.text_len			= 0x3ad8,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_TXP_b06FwText,
 	.gz_text_len			= sizeof(bnx2_TXP_b06FwText),
 
-	.data_addr			= 0x08005760,
+	.data_addr			= 0x00000000,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_TXP_b06FwData,
 
-	.sbss_addr			= 0x08005760,
-	.sbss_len			= 0x38,
+	.sbss_addr			= 0x08003b00,
+	.sbss_len			= 0x68,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x080057a0,
-	.bss_len			= 0x1c4,
+	.bss_addr			= 0x08003b68,
+	.bss_len			= 0x14c,
 	.bss_index			= 0x0,
 
 	.rodata_addr			= 0x00000000,
diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h
index 4b129b7cbfad..13b222eb2f63 100644
--- a/drivers/net/bnx2_fw2.h
+++ b/drivers/net/bnx2_fw2.h
@@ -15,4088 +15,4566 @@
  */
 
 static u8 bnx2_COM_b09FwText[] = {
-	0xdc, 0x5b, 0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae,
-	0xc8, 0x15, 0x35, 0x22, 0x57, 0xd4, 0x9a, 0xa2, 0xed, 0x5d, 0x72, 0x28,
-	0xb2, 0x96, 0xea, 0xae, 0x29, 0xa6, 0x62, 0xd3, 0x4d, 0xb4, 0xd9, 0xa5,
-	0x5c, 0xb5, 0x75, 0x5a, 0x4a, 0x26, 0xfc, 0x48, 0x55, 0x83, 0xde, 0xa5,
-	0x9c, 0xa0, 0xa8, 0x53, 0xc9, 0x76, 0x85, 0x20, 0x05, 0xaa, 0x05, 0x1f,
-	0x89, 0x52, 0xb0, 0x1c, 0xc5, 0x92, 0x29, 0xb5, 0x71, 0x6b, 0x96, 0xb4,
-	0x6c, 0x15, 0xd8, 0x6a, 0x65, 0xc7, 0x6d, 0x68, 0x54, 0x2e, 0x65, 0xca,
-	0x69, 0x95, 0x26, 0x48, 0x8d, 0xa0, 0x42, 0x95, 0x3f, 0x8e, 0xe1, 0xf4,
-	0x87, 0x5b, 0xf4, 0x87, 0xd1, 0x07, 0x22, 0xd7, 0x8f, 0xed, 0xf7, 0xdd,
-	0xb9, 0x43, 0x0e, 0x97, 0x14, 0x45, 0xf9, 0xf5, 0xa3, 0x04, 0x56, 0x33,
-	0xf7, 0x7d, 0xee, 0xb9, 0xe7, 0x7c, 0xe7, 0x31, 0x57, 0x3f, 0x2f, 0x52,
-	0x27, 0xfa, 0x6f, 0x3d, 0x7e, 0x89, 0x87, 0x7f, 0xaf, 0x70, 0xfb, 0xce,
-	0xdb, 0x77, 0xe0, 0xf5, 0x0e, 0xd3, 0xa8, 0x0d, 0xb1, 0x9e, 0xff, 0xc4,
-	0xf0, 0xeb, 0xd6, 0xef, 0x2b, 0xfd, 0xd9, 0xf8, 0xbd, 0x89, 0xc6, 0xc1,
-	0x7f, 0x17, 0x31, 0xae, 0xd1, 0x27, 0xf8, 0x57, 0xa9, 0xac, 0xde, 0x6e,
-	0x92, 0x96, 0x55, 0xda, 0x43, 0xde, 0x92, 0x8a, 0x66, 0xfe, 0x24, 0x62,
-	0xa6, 0x33, 0x47, 0xb2, 0x8e, 0x11, 0x09, 0xa5, 0xbb, 0x8a, 0x05, 0x47,
-	0x24, 0x53, 0xda, 0x96, 0xc8, 0xc9, 0x7b, 0x95, 0x62, 0xcc, 0x92, 0xac,
-	0x23, 0x91, 0x9b, 0xd3, 0xef, 0x3e, 0xf5, 0xd2, 0xce, 0xe4, 0x5b, 0x53,
-	0x21, 0x89, 0xd8, 0xe9, 0x17, 0xc4, 0xde, 0x2a, 0x91, 0x56, 0x8c, 0x79,
-	0xb2, 0x33, 0x63, 0x48, 0x83, 0x3f, 0xd7, 0x9b, 0x95, 0x97, 0x3a, 0xa5,
-	0xd8, 0x92, 0x8e, 0x88, 0x99, 0xee, 0xb8, 0x92, 0x0d, 0xd9, 0x83, 0xa1,
-	0xb4, 0x2d, 0x73, 0x65, 0xe9, 0x3f, 0x30, 0x2e, 0x91, 0x48, 0xfa, 0x4b,
-	0x91, 0xda, 0x0e, 0x89, 0x58, 0xe9, 0xa9, 0x23, 0x5f, 0x73, 0x8e, 0x54,
-	0x4c, 0xc7, 0xe9, 0x9a, 0x96, 0x68, 0xef, 0xe9, 0x1e, 0xb4, 0x97, 0x92,
-	0x5d, 0x22, 0x3b, 0xc5, 0x74, 0x8a, 0xd1, 0x90, 0x13, 0x91, 0x6c, 0xd9,
-	0x91, 0x5c, 0x59, 0xe4, 0x1f, 0x4a, 0x86, 0x9c, 0x76, 0x9a, 0x65, 0x7a,
-	0xfb, 0xbb, 0x95, 0x0c, 0x68, 0xf9, 0x7b, 0x67, 0xea, 0xc8, 0xa8, 0x43,
-	0x7a, 0x1f, 0x8b, 0x90, 0xae, 0x50, 0x7a, 0xa8, 0xb6, 0xe0, 0x58, 0x32,
-	0x5c, 0x62, 0xdd, 0x80, 0xc9, 0xba, 0x70, 0x3a, 0x52, 0x77, 0xda, 0x89,
-	0xea, 0xba, 0x52, 0x26, 0x8b, 0xf9, 0x46, 0x4a, 0xec, 0x1b, 0xe9, 0x2e,
-	0x38, 0x31, 0x5d, 0x3f, 0xba, 0x33, 0xeb, 0xc4, 0x51, 0xdf, 0xaa, 0xdb,
-	0x7a, 0xbe, 0x5c, 0x70, 0x1c, 0xdd, 0x76, 0x35, 0x94, 0x75, 0xba, 0x74,
-	0xfd, 0xab, 0xbb, 0x0a, 0xce, 0x76, 0x5d, 0xff, 0xd6, 0xae, 0xac, 0x93,
-	0xd2, 0xf5, 0xe3, 0xf7, 0x17, 0x9c, 0x1e, 0x5d, 0xdf, 0x8a, 0xfa, 0x5e,
-	0x5d, 0xff, 0x83, 0xde, 0x82, 0x93, 0x46, 0xfd, 0x97, 0x22, 0x66, 0x87,
-	0x2d, 0x63, 0xa5, 0x04, 0x7e, 0x19, 0xb4, 0xf5, 0xa1, 0x6e, 0x0f, 0x7e,
-	0x77, 0xe1, 0x37, 0xbf, 0x41, 0x1a, 0xfa, 0xf1, 0x6c, 0x6b, 0xf5, 0x78,
-	0x07, 0x1e, 0xb9, 0x11, 0x79, 0x3d, 0x14, 0x97, 0x97, 0x3a, 0x5f, 0x07,
-	0x0f, 0x6d, 0x39, 0x57, 0x16, 0xa3, 0xbf, 0x33, 0x0e, 0xde, 0xc5, 0xe4,
-	0xb9, 0x72, 0xbd, 0x84, 0x1e, 0x0f, 0x81, 0x37, 0x5f, 0x90, 0x7c, 0x2c,
-	0x22, 0x1b, 0x27, 0x0d, 0x69, 0xeb, 0x8e, 0x48, 0xc6, 0xe6, 0xda, 0x38,
-	0xed, 0x89, 0x98, 0x84, 0x26, 0x33, 0x4d, 0xa6, 0x74, 0xd8, 0x39, 0x29,
-	0x82, 0x77, 0x57, 0x28, 0x97, 0x68, 0x4b, 0x48, 0x6e, 0xfc, 0x36, 0x19,
-	0xb4, 0x49, 0xd7, 0xdc, 0xcd, 0xde, 0x5a, 0x11, 0x23, 0x7b, 0x72, 0x40,
-	0xc6, 0xdc, 0xa8, 0x91, 0x3b, 0xf9, 0x59, 0xc9, 0xa6, 0x24, 0x86, 0x71,
-	0xf1, 0x3c, 0x5a, 0x66, 0x4a, 0x03, 0x32, 0xea, 0x8a, 0x91, 0x75, 0xc9,
-	0xcf, 0x66, 0xb4, 0x37, 0xa8, 0xbe, 0xa8, 0x6b, 0x0d, 0xa9, 0xb9, 0x23,
-	0xa8, 0xb7, 0x51, 0xdf, 0x68, 0xf4, 0xa9, 0x39, 0x54, 0x7d, 0x62, 0x44,
-	0xa2, 0xf2, 0x74, 0x29, 0xa6, 0xfb, 0x56, 0x2a, 0xd9, 0x94, 0x8d, 0x7e,
-	0x03, 0x32, 0xe2, 0xc6, 0x64, 0x10, 0xcf, 0x61, 0x97, 0x72, 0x15, 0x87,
-	0x4c, 0x35, 0x14, 0xf3, 0x27, 0xd4, 0x7c, 0x89, 0x50, 0x9a, 0xf3, 0xb5,
-	0xa2, 0xdf, 0xdb, 0xa0, 0xcb, 0x10, 0x4b, 0x9d, 0x65, 0x46, 0xf2, 0xe3,
-	0x06, 0xe4, 0x0d, 0x4f, 0xc5, 0xd7, 0x3e, 0xd0, 0x6f, 0x89, 0xd3, 0x6d,
-	0x48, 0x01, 0x67, 0x55, 0xb4, 0x51, 0x2e, 0xcd, 0x9a, 0x59, 0xb7, 0x56,
-	0x72, 0x56, 0x42, 0x42, 0x13, 0x94, 0xa5, 0x41, 0x19, 0xc1, 0x18, 0xd3,
-	0x61, 0x9f, 0xb7, 0xb1, 0xef, 0x41, 0x75, 0x0e, 0x35, 0xe9, 0xa2, 0x99,
-	0x2b, 0x37, 0x8b, 0x39, 0xb9, 0x5f, 0x5e, 0x19, 0x17, 0x3b, 0x94, 0x7e,
-	0xb7, 0x92, 0x75, 0x46, 0xcd, 0xec, 0xb3, 0x96, 0x84, 0x27, 0x0c, 0x19,
-	0x75, 0x92, 0xd0, 0x80, 0xa3, 0xe6, 0xee, 0xf2, 0x2c, 0xfa, 0x71, 0x1c,
-	0xfa, 0x95, 0x4c, 0xf0, 0x95, 0xef, 0xdb, 0x6c, 0x53, 0xc9, 0x33, 0xfb,
-	0xe0, 0x0c, 0xb0, 0x8f, 0xe7, 0x5c, 0x9c, 0x89, 0x3a, 0xa3, 0x04, 0xce,
-	0x48, 0x8c, 0xbe, 0x4e, 0xc8, 0xd4, 0x09, 0x4b, 0xf2, 0x29, 0xec, 0x0b,
-	0xbd, 0xf3, 0xa9, 0x45, 0xba, 0x46, 0xc6, 0xab, 0xe9, 0xe2, 0x38, 0xd2,
-	0xe5, 0xd1, 0x34, 0x7c, 0x82, 0xf4, 0x2d, 0xd2, 0x33, 0x36, 0xee, 0xd3,
-	0xc8, 0xf5, 0x48, 0x9b, 0x4f, 0x17, 0xc7, 0x91, 0xae, 0x26, 0x9e, 0x35,
-	0xff, 0x8c, 0x3e, 0xd0, 0x31, 0xe2, 0x5a, 0x38, 0xa3, 0xa8, 0xe4, 0xed,
-	0xa2, 0x31, 0xd2, 0xbb, 0x2d, 0x0e, 0x6d, 0x36, 0x86, 0x7b, 0x49, 0xb3,
-	0x83, 0x73, 0xac, 0x51, 0xe7, 0x0d, 0xf9, 0x26, 0xef, 0xd0, 0x9f, 0xeb,
-	0xe3, 0xbd, 0x64, 0xcb, 0xa8, 0x9a, 0x8f, 0x34, 0x7d, 0x14, 0xf3, 0x90,
-	0xd6, 0x4b, 0x90, 0xd5, 0x1e, 0xc8, 0x68, 0x4a, 0xfe, 0xae, 0xbc, 0x5d,
-	0xbe, 0x53, 0xee, 0x92, 0xbf, 0x81, 0xde, 0xfe, 0x75, 0x39, 0x21, 0x2f,
-	0x94, 0x5b, 0xe5, 0xdb, 0xe5, 0xb8, 0x3c, 0xaf, 0xe4, 0xb7, 0x4f, 0xa4,
-	0x81, 0x32, 0x9d, 0x90, 0x46, 0xe8, 0xcf, 0x46, 0xe8, 0xe6, 0x13, 0xe0,
-	0xdf, 0x89, 0x4e, 0xc9, 0x34, 0xa5, 0x25, 0x72, 0x0b, 0x7e, 0x9b, 0xf1,
-	0x6b, 0x4e, 0x43, 0xee, 0x5c, 0xf2, 0x8e, 0x3c, 0xb4, 0x24, 0xa7, 0xf6,
-	0x6c, 0xc9, 0x48, 0x79, 0xfe, 0x16, 0x4f, 0x76, 0x45, 0xfa, 0xc1, 0x63,
-	0xb3, 0xfb, 0x7f, 0x2a, 0x19, 0x1b, 0xfb, 0xe8, 0xde, 0xa6, 0x78, 0x6f,
-	0x76, 0x53, 0x66, 0x13, 0x90, 0x7b, 0xcb, 0xc8, 0xb9, 0x67, 0x80, 0x1b,
-	0xf5, 0x46, 0xf6, 0x78, 0x51, 0x0a, 0xc7, 0x2b, 0x52, 0x48, 0x85, 0xe5,
-	0x11, 0xbb, 0x22, 0x7d, 0xa9, 0x1a, 0x39, 0x64, 0x83, 0xf7, 0xdb, 0x7f,
-	0xdf, 0xf0, 0x31, 0xfb, 0x89, 0xf2, 0x61, 0xbc, 0xb3, 0x4e, 0xe4, 0x84,
-	0x7a, 0xf7, 0xea, 0x8b, 0xe5, 0xb0, 0x64, 0x62, 0xc5, 0xb8, 0x25, 0x2d,
-	0xa6, 0xb7, 0xee, 0xb0, 0xdf, 0x06, 0x7e, 0x4c, 0x01, 0x27, 0x93, 0x4a,
-	0x5f, 0xf2, 0xe3, 0xeb, 0xae, 0x66, 0x54, 0x35, 0xfa, 0xdb, 0x3d, 0x32,
-	0xaf, 0xf8, 0x99, 0x18, 0x34, 0xd2, 0x31, 0x69, 0x2b, 0xb1, 0xdc, 0x6b,
-	0xdc, 0x5d, 0xa6, 0x3c, 0xe3, 0xbd, 0x4c, 0x3a, 0x6f, 0x42, 0x3f, 0x0b,
-	0xcf, 0x8c, 0xa6, 0x37, 0x48, 0x23, 0xe7, 0x21, 0x8d, 0x7c, 0xfe, 0x79,
-	0x80, 0xc6, 0xa7, 0x16, 0xde, 0x4f, 0x04, 0xde, 0x8b, 0xe5, 0x4b, 0x75,
-	0x1e, 0x6d, 0xbd, 0xf2, 0xc6, 0xc4, 0x57, 0xf4, 0x3a, 0x78, 0x3f, 0xcb,
-	0xf9, 0xff, 0xaa, 0xe2, 0xc9, 0x4b, 0xf1, 0x3a, 0xeb, 0xcc, 0x06, 0xd6,
-	0x79, 0x31, 0xb0, 0xce, 0x8b, 0x81, 0x75, 0x8a, 0xe0, 0xa9, 0x6c, 0x30,
-	0x21, 0xc3, 0x79, 0x9a, 0x31, 0x39, 0x8a, 0x39, 0x5f, 0x97, 0x50, 0x9a,
-	0x7a, 0xee, 0xe3, 0xcd, 0x65, 0xf4, 0x4f, 0xcb, 0xfc, 0x44, 0x51, 0xf2,
-	0xc7, 0xc3, 0xb2, 0x4f, 0xf5, 0xdb, 0xa5, 0xe9, 0x0b, 0xb6, 0x45, 0x64,
-	0x6f, 0x8c, 0xef, 0x7e, 0x9b, 0x05, 0x3e, 0xb3, 0xfc, 0xc6, 0x4d, 0x5e,
-	0x99, 0xef, 0xb3, 0x7a, 0x2f, 0x03, 0xde, 0xb8, 0xb3, 0x6f, 0x2a, 0x3c,
-	0x9c, 0x2b, 0x13, 0xb7, 0x24, 0x15, 0x72, 0xe4, 0x60, 0x5f, 0xaa, 0x59,
-	0x46, 0x6c, 0x23, 0x35, 0xdc, 0x55, 0x4b, 0xbd, 0xc8, 0x98, 0x4e, 0x3d,
-	0xb0, 0x41, 0x12, 0x26, 0x31, 0x5f, 0xed, 0xcb, 0x30, 0x3d, 0xfa, 0x6d,
-	0x96, 0xfb, 0x4d, 0xa7, 0xb1, 0xaa, 0x9e, 0xba, 0x1d, 0xc2, 0x3b, 0x65,
-	0x78, 0xb7, 0x3e, 0x63, 0x0b, 0x65, 0xe2, 0xf0, 0xad, 0xba, 0xec, 0xb7,
-	0xe3, 0xc0, 0x96, 0x94, 0x7f, 0xb6, 0x65, 0x69, 0xd9, 0xc7, 0x89, 0x20,
-	0x86, 0x73, 0xaf, 0xc0, 0x27, 0x87, 0x72, 0x17, 0x06, 0xad, 0x29, 0xe8,
-	0x5c, 0xad, 0xa6, 0x61, 0xb3, 0xa6, 0x01, 0xb4, 0x76, 0x42, 0xb2, 0x94,
-	0x2e, 0x29, 0xd1, 0xaa, 0x2a, 0x93, 0xf7, 0xfe, 0xfb, 0x7a, 0xd5, 0xee,
-	0xe9, 0x9c, 0xff, 0xf4, 0xf1, 0xfd, 0xcd, 0x80, 0xbd, 0x68, 0x85, 0xce,
-	0xc6, 0xc0, 0x2b, 0x1f, 0xeb, 0x89, 0xc1, 0x71, 0xd8, 0x07, 0xc8, 0xaa,
-	0xc2, 0xf6, 0x28, 0xf0, 0xd0, 0xd2, 0xd8, 0x1c, 0xd1, 0xd8, 0x1c, 0x05,
-	0x2e, 0xb3, 0x6c, 0xeb, 0x72, 0x4c, 0x97, 0xe3, 0x28, 0xc3, 0x8e, 0x4f,
-	0x12, 0xbb, 0x1b, 0x8a, 0x43, 0x27, 0x14, 0xde, 0xd3, 0x56, 0x00, 0x85,
-	0x89, 0xd7, 0xc4, 0xed, 0x56, 0x99, 0x2e, 0x61, 0xbd, 0x05, 0x6c, 0xe4,
-	0xde, 0x83, 0xf4, 0x90, 0x96, 0x75, 0x62, 0xc2, 0x76, 0x65, 0x62, 0xa4,
-	0xf7, 0x61, 0xec, 0x9d, 0xf8, 0x43, 0xba, 0x6f, 0x06, 0xad, 0xdc, 0xc7,
-	0x27, 0x49, 0x2b, 0xd7, 0xab, 0xa6, 0xf7, 0xc3, 0xe2, 0x20, 0x69, 0x3f,
-	0x83, 0x3d, 0x67, 0x80, 0x79, 0x62, 0x0c, 0x74, 0x0e, 0x60, 0xcf, 0xfd,
-	0xc0, 0xc3, 0xbb, 0x80, 0x87, 0x7b, 0x80, 0x87, 0x7d, 0xc0, 0xc3, 0x34,
-	0xb0, 0xb0, 0x17, 0x58, 0xd8, 0x03, 0x2c, 0x4c, 0x81, 0x37, 0x31, 0x99,
-	0x02, 0x36, 0x4e, 0x01, 0x23, 0xa7, 0x30, 0xc7, 0xf0, 0xa4, 0x18, 0x0f,
-	0x60, 0x0f, 0xdf, 0x9c, 0x48, 0x9e, 0x82, 0x2c, 0xc5, 0x8b, 0x26, 0xe4,
-	0x3f, 0xd5, 0x0b, 0xd9, 0xee, 0x92, 0x99, 0xb2, 0x25, 0x05, 0xd8, 0xd4,
-	0xb6, 0xad, 0xed, 0xd0, 0x35, 0xc8, 0x7b, 0x5c, 0xf4, 0xdf, 0x7a, 0xfd,
-	0xfc, 0xb1, 0x88, 0xf3, 0x4f, 0x94, 0xc5, 0x84, 0xc8, 0x79, 0xc9, 0xbb,
-	0xed, 0x76, 0x9b, 0xd9, 0x85, 0x7e, 0x2c, 0xa7, 0xcc, 0x03, 0xc7, 0xef,
-	0x30, 0x87, 0x8e, 0x2b, 0x7f, 0x05, 0x78, 0x55, 0x91, 0xd1, 0x14, 0x75,
-	0xab, 0x22, 0xa7, 0x53, 0xc9, 0xde, 0xa2, 0xd4, 0xcb, 0x58, 0x6c, 0x5c,
-	0xd9, 0x5a, 0x2b, 0x7d, 0x4c, 0xd9, 0xab, 0x82, 0x83, 0x67, 0xa9, 0xdb,
-	0xcc, 0x1f, 0xe7, 0xfe, 0xdb, 0xf1, 0x0b, 0x83, 0x16, 0xce, 0x6f, 0x49,
-	0x5f, 0x8f, 0x6d, 0x3e, 0xd4, 0x59, 0x84, 0x42, 0x24, 0xed, 0x79, 0xac,
-	0x9c, 0x1b, 0x6f, 0x8f, 0xb7, 0x9b, 0x96, 0x0c, 0x5a, 0x86, 0x0c, 0x43,
-	0xbe, 0xfb, 0x52, 0x6f, 0x57, 0xc6, 0x62, 0x6c, 0xaf, 0x95, 0xaf, 0x2b,
-	0x9f, 0x03, 0x6b, 0xcf, 0x9c, 0xc0, 0xba, 0x61, 0x9c, 0x01, 0xd7, 0xe5,
-	0x3c, 0x28, 0x97, 0x2c, 0x94, 0x93, 0xa7, 0x8a, 0x52, 0x86, 0x9e, 0x6c,
-	0x90, 0xec, 0xf6, 0x1a, 0xc9, 0xf4, 0x27, 0x64, 0x78, 0xa2, 0x0c, 0x9c,
-	0x8a, 0x28, 0x5d, 0xc9, 0x0f, 0x24, 0xe4, 0xf1, 0x09, 0xd6, 0x9d, 0xc3,
-	0xfe, 0x93, 0xc7, 0x32, 0xc2, 0xfd, 0x1b, 0x92, 0xd9, 0x7f, 0x4e, 0x1e,
-	0x71, 0xcf, 0xc9, 0x10, 0xce, 0xf0, 0xe9, 0xf2, 0xac, 0x1c, 0x70, 0x1d,
-	0x39, 0x0d, 0xbc, 0xcf, 0x1d, 0x07, 0xee, 0x39, 0xeb, 0x81, 0x51, 0xc9,
-	0x73, 0xb4, 0xa1, 0x26, 0xfc, 0xbc, 0x69, 0xf0, 0xf7, 0x89, 0x09, 0xf2,
-	0xd7, 0x94, 0x47, 0x7f, 0xd1, 0x80, 0x3e, 0x26, 0xc0, 0xcf, 0x56, 0x39,
-	0xec, 0x26, 0x67, 0x33, 0x26, 0x70, 0x31, 0x65, 0x87, 0xa4, 0x2e, 0x8e,
-	0x7e, 0x5e, 0x9f, 0x5c, 0x2a, 0x84, 0xb3, 0x2e, 0xa2, 0xef, 0xdb, 0xa0,
-	0x93, 0x63, 0x63, 0xf8, 0x65, 0xd0, 0x0f, 0xf2, 0x6b, 0x27, 0x67, 0xa7,
-	0x4c, 0xf6, 0x4f, 0xe0, 0xcc, 0x80, 0x2b, 0x93, 0x00, 0x1e, 0x9b, 0xef,
-	0x69, 0x33, 0x4f, 0x1a, 0x5c, 0xca, 0x59, 0x02, 0x34, 0x11, 0xd3, 0xda,
-	0xcf, 0x7d, 0x47, 0xb8, 0xce, 0x46, 0xf4, 0x7f, 0x07, 0x7e, 0xae, 0x2d,
-	0x33, 0x38, 0x97, 0x9f, 0x82, 0x57, 0x99, 0xb8, 0x57, 0x1e, 0x9e, 0x4c,
-	0x9e, 0x9b, 0x37, 0xf9, 0xee, 0x14, 0xf3, 0xe6, 0x6d, 0x22, 0x8d, 0xe4,
-	0x57, 0x0a, 0xbc, 0x72, 0x6c, 0xd3, 0xdc, 0xaa, 0x7d, 0x3b, 0xea, 0x89,
-	0x03, 0x9a, 0xe0, 0x67, 0x74, 0x07, 0xf5, 0x84, 0xf6, 0xce, 0xd7, 0x93,
-	0x64, 0x7c, 0xca, 0x84, 0xff, 0xd1, 0x6d, 0xc9, 0x31, 0x55, 0x06, 0x8f,
-	0x06, 0x92, 0xf1, 0x8c, 0x49, 0x9f, 0xb7, 0x4b, 0x9e, 0x76, 0xd9, 0x1f,
-	0x7c, 0x1c, 0x8f, 0xea, 0xfe, 0xe7, 0x20, 0x23, 0xf4, 0xcf, 0xba, 0x40,
-	0xb3, 0xa7, 0x3b, 0xd3, 0xe3, 0x31, 0xd5, 0x36, 0xa6, 0xf6, 0x60, 0x60,
-	0x5d, 0xc8, 0x26, 0x7c, 0xb5, 0x9c, 0xd2, 0x23, 0x3b, 0x03, 0x5f, 0x1e,
-	0x7a, 0xe0, 0xe9, 0xd0, 0x4c, 0x89, 0xb4, 0xdc, 0x43, 0x7e, 0x14, 0x41,
-	0xcc, 0x31, 0x33, 0x8d, 0x73, 0xed, 0x91, 0x22, 0xfd, 0xb9, 0xf9, 0xd0,
-	0xd3, 0x32, 0x38, 0x43, 0x7b, 0x83, 0x9f, 0xeb, 0xd8, 0x8c, 0x1f, 0x32,
-	0xca, 0x16, 0x6c, 0xc1, 0x39, 0xc3, 0x4e, 0xa4, 0x36, 0x6a, 0x3f, 0xe6,
-	0x49, 0x9c, 0xdb, 0x79, 0x9c, 0x6b, 0x49, 0x86, 0x4e, 0x5e, 0xa2, 0xcc,
-	0x76, 0xcd, 0x48, 0xb2, 0x6b, 0x4c, 0xb6, 0xd9, 0xd3, 0xd0, 0xb7, 0xcc,
-	0x40, 0x65, 0x97, 0x99, 0xe6, 0x98, 0x23, 0x18, 0x83, 0xe7, 0xcc, 0x25,
-	0x39, 0x54, 0x66, 0xdd, 0xef, 0x80, 0x9f, 0xb0, 0x3b, 0x3d, 0x4f, 0x6a,
-	0x39, 0xc7, 0x7c, 0x96, 0x3f, 0xdf, 0x25, 0x3d, 0x1f, 0xfb, 0xb1, 0x0f,
-	0xc7, 0x2c, 0xce, 0xbb, 0x9b, 0xb6, 0x06, 0x78, 0xd3, 0x61, 0x56, 0x76,
-	0x85, 0xd1, 0x7e, 0xba, 0x87, 0xef, 0x98, 0x07, 0xb6, 0xc6, 0x76, 0xce,
-	0xa3, 0x2f, 0xf6, 0xe5, 0xae, 0x93, 0xb6, 0x66, 0x9f, 0x5e, 0x9e, 0x3b,
-	0xfd, 0x00, 0x96, 0x1f, 0x6e, 0xf2, 0x78, 0x3f, 0x12, 0xf2, 0xb0, 0xfb,
-	0x2f, 0x51, 0xa6, 0x7e, 0x3d, 0x26, 0x39, 0x37, 0x89, 0x7d, 0x42, 0x87,
-	0xca, 0x0d, 0x86, 0xb7, 0x47, 0xf0, 0xbf, 0xff, 0x32, 0xf8, 0x20, 0x45,
-	0x8f, 0x37, 0xe4, 0x0b, 0x79, 0xd2, 0x00, 0xd9, 0xae, 0xc3, 0xbc, 0x58,
-	0x47, 0xf1, 0xe0, 0x96, 0x26, 0xcf, 0xef, 0x4d, 0x16, 0x33, 0x8c, 0xd7,
-	0x1a, 0x29, 0xb3, 0xc0, 0xa8, 0xf2, 0xfd, 0x36, 0xe7, 0x9e, 0x32, 0xd7,
-	0x91, 0xde, 0xc4, 0x85, 0xd0, 0x7e, 0x96, 0xbb, 0xa6, 0x4c, 0xf0, 0x1e,
-	0xe7, 0x93, 0xdd, 0xde, 0xae, 0x71, 0xe9, 0x99, 0x10, 0x65, 0x94, 0xf2,
-	0x9c, 0x77, 0xb7, 0xd9, 0xf7, 0x08, 0x65, 0x34, 0x86, 0xf3, 0x26, 0x2e,
-	0xf0, 0x69, 0xc1, 0x26, 0xc6, 0x71, 0xc6, 0x5b, 0x34, 0xed, 0x7c, 0xb7,
-	0x64, 0xca, 0xc6, 0x1a, 0xee, 0x7f, 0x6f, 0xf0, 0xea, 0xf8, 0xde, 0xc2,
-	0x33, 0x39, 0xb6, 0x94, 0x56, 0x9e, 0x67, 0xf5, 0x19, 0x9e, 0x06, 0xed,
-	0xac, 0xc7, 0x73, 0xe6, 0x14, 0xf4, 0x0f, 0x58, 0xd1, 0xd3, 0x11, 0xbf,
-	0x88, 0xfe, 0x39, 0x60, 0x7c, 0xd1, 0x62, 0xdb, 0x55, 0x63, 0x71, 0x8c,
-	0x49, 0x3f, 0x13, 0x3e, 0xed, 0x05, 0xe3, 0x81, 0xf2, 0x2b, 0x46, 0x76,
-	0xe6, 0xaa, 0x91, 0x83, 0x5c, 0xcc, 0xb8, 0x3b, 0x20, 0xcf, 0xd4, 0x17,
-	0x1b, 0x6b, 0x27, 0xe3, 0xff, 0x62, 0xb6, 0x27, 0xa6, 0xa1, 0xdb, 0x07,
-	0xc0, 0x58, 0xef, 0x2c, 0x5b, 0xd5, 0xd9, 0xce, 0x9b, 0x61, 0x8d, 0x75,
-	0x2c, 0x27, 0xed, 0x7b, 0xe5, 0x35, 0xec, 0x77, 0x16, 0x7c, 0x9e, 0x95,
-	0x42, 0xb9, 0x24, 0xf9, 0x93, 0xdb, 0xec, 0x61, 0xc4, 0xb8, 0x8b, 0xb4,
-	0x13, 0xc3, 0x8a, 0xf4, 0xbd, 0x8d, 0xdd, 0xae, 0x14, 0x6b, 0xd2, 0xc4,
-	0xb2, 0x0e, 0xc8, 0x13, 0xea, 0x4a, 0x8b, 0x32, 0x79, 0xe7, 0xb2, 0xfd,
-	0x20, 0xbe, 0xed, 0x59, 0xba, 0xa7, 0x19, 0xb9, 0xfe, 0x9e, 0x76, 0x2f,
-	0xec, 0x89, 0xd8, 0x01, 0xcc, 0x77, 0x81, 0xf9, 0x2e, 0x30, 0xdf, 0x05,
-	0xe6, 0xbb, 0xc0, 0x7c, 0x17, 0xf6, 0xc0, 0x05, 0xee, 0xbb, 0xc0, 0x7d,
-	0x17, 0xb8, 0xef, 0x02, 0xf7, 0xdd, 0x2c, 0xce, 0x8e, 0xd8, 0x4e, 0xbb,
-	0x71, 0xdf, 0x82, 0xad, 0xf4, 0x7c, 0x9b, 0x9b, 0xb4, 0xbf, 0x00, 0x9d,
-	0xb4, 0x5b, 0x64, 0xb8, 0x6b, 0x33, 0xf6, 0x56, 0x87, 0x67, 0x3d, 0x9e,
-	0x58, 0xa3, 0xeb, 0x33, 0x5a, 0x77, 0xbe, 0x0a, 0xba, 0x4c, 0x94, 0x7f,
-	0x09, 0xb2, 0x59, 0x03, 0x7a, 0x7e, 0x41, 0xfb, 0x15, 0xa7, 0x2c, 0x4f,
-	0x36, 0xeb, 0x51, 0xf7, 0x69, 0xd4, 0xd5, 0xa3, 0xcf, 0x21, 0xf4, 0xa1,
-	0x5f, 0xd2, 0xa0, 0xeb, 0x82, 0xfd, 0xe8, 0x9f, 0xfc, 0x26, 0xd6, 0x4a,
-	0xa2, 0x5f, 0x03, 0xe6, 0x6e, 0x45, 0x9f, 0xcf, 0xa2, 0xcf, 0xcd, 0x28,
-	0xd3, 0x9f, 0xdd, 0x82, 0xf2, 0xa7, 0xaa, 0xc6, 0xdc, 0x8a, 0xba, 0xcf,
-	0x54, 0xd5, 0xcd, 0xa3, 0x0e, 0x71, 0xb0, 0x7d, 0x51, 0x8f, 0x2b, 0xa2,
-	0xdc, 0x5c, 0xd5, 0xe7, 0x12, 0xea, 0x7a, 0x51, 0xf7, 0x3d, 0x3c, 0x11,
-	0xff, 0xda, 0xa4, 0xc9, 0x6f, 0xa3, 0x6f, 0x9a, 0x40, 0x7d, 0x58, 0xfb,
-	0x97, 0x4f, 0xd2, 0xdf, 0x82, 0x9d, 0xfd, 0x53, 0xcb, 0xf3, 0xc7, 0x9e,
-	0xb1, 0x3d, 0x59, 0xf5, 0xcb, 0x3f, 0xaa, 0x2a, 0xb3, 0xef, 0xff, 0x56,
-	0xd5, 0xed, 0xda, 0xb8, 0xb4, 0xfc, 0x7e, 0x78, 0xf9, 0x98, 0xe3, 0x55,
-	0x7d, 0x5e, 0x6e, 0x5c, 0x5a, 0xfe, 0x7c, 0xcd, 0xf2, 0x31, 0xbf, 0xb5,
-	0x61, 0x69, 0xdd, 0xe1, 0xa6, 0xa5, 0x65, 0xfa, 0x7d, 0x31, 0xc4, 0x2d,
-	0x7e, 0xff, 0x07, 0x37, 0x79, 0xed, 0xe4, 0x6f, 0xb5, 0x2c, 0x29, 0xe3,
-	0x8d, 0xb2, 0x89, 0x73, 0xb8, 0x60, 0x40, 0xe7, 0x6c, 0x33, 0xfd, 0x8a,
-	0x91, 0x83, 0x4c, 0x65, 0xcb, 0xfe, 0x7c, 0xd4, 0xe5, 0xea, 0xdc, 0x80,
-	0x9f, 0x13, 0xa0, 0x8f, 0x15, 0x85, 0xdc, 0x00, 0x8b, 0x63, 0xc9, 0xa3,
-	0x45, 0x59, 0xd4, 0xe1, 0x36, 0xf3, 0x5a, 0x3a, 0x3c, 0xa9, 0x71, 0xeb,
-	0x32, 0xe8, 0xac, 0x48, 0x7f, 0xaa, 0x96, 0x76, 0x47, 0xe3, 0x19, 0xb1,
-	0xa8, 0x52, 0x09, 0x6d, 0xad, 0xc8, 0xc1, 0xd4, 0x3b, 0x15, 0x51, 0x38,
-	0xf8, 0x4d, 0xcd, 0x57, 0xe2, 0xa1, 0x0d, 0xb9, 0x8d, 0x29, 0x3f, 0x2e,
-	0x94, 0x3e, 0x45, 0x9f, 0xe4, 0x88, 0x87, 0xb3, 0xc4, 0x22, 0x94, 0xcb,
-	0x63, 0xe8, 0xc3, 0xf5, 0xf1, 0x9c, 0x21, 0xb6, 0x5b, 0xca, 0xce, 0xe4,
-	0x6d, 0xce, 0xbb, 0x12, 0x5e, 0xfe, 0xd8, 0xa2, 0x2f, 0x68, 0x39, 0x67,
-	0x60, 0xf3, 0xd8, 0x46, 0xff, 0xe0, 0x0c, 0x7d, 0x91, 0x80, 0x6f, 0xd3,
-	0x11, 0x12, 0x67, 0x11, 0x47, 0xbd, 0x7d, 0xb5, 0xd0, 0xd7, 0x5f, 0xc3,
-	0x5e, 0x57, 0xc6, 0xab, 0x76, 0xf3, 0xfa, 0xba, 0xbd, 0x77, 0x41, 0xb7,
-	0x7d, 0xd9, 0x5b, 0x29, 0x07, 0x70, 0x45, 0x9d, 0xc5, 0xf3, 0xe5, 0xe4,
-	0xb1, 0x22, 0x74, 0x69, 0x4e, 0xc5, 0xbb, 0xfe, 0xb9, 0xd0, 0xaf, 0x49,
-	0x9e, 0x9a, 0x82, 0x6c, 0x0f, 0xa9, 0x38, 0x80, 0x31, 0x40, 0x45, 0x76,
-	0xa7, 0x86, 0x62, 0xe4, 0x43, 0xc6, 0xbc, 0x1a, 0xa6, 0x1f, 0x31, 0xe7,
-	0x92, 0x67, 0x29, 0xb4, 0xa7, 0xc0, 0xdb, 0x7f, 0x95, 0x5c, 0x8c, 0x75,
-	0xff, 0x55, 0x99, 0x86, 0xff, 0xa3, 0x7c, 0x22, 0xe5, 0x03, 0xd0, 0xa7,
-	0x83, 0xad, 0x2f, 0x93, 0xa7, 0x17, 0xc0, 0x67, 0xdf, 0x2f, 0xb8, 0x4c,
-	0xbf, 0x54, 0x96, 0xfa, 0xcf, 0x22, 0x8f, 0x94, 0xfe, 0x19, 0x76, 0xc8,
-	0xc4, 0x7c, 0xb4, 0x77, 0xb4, 0x29, 0xac, 0xdf, 0x11, 0xa6, 0xff, 0xe6,
-	0xd9, 0xff, 0x10, 0xd6, 0x43, 0x4c, 0x5d, 0xfa, 0x0f, 0x23, 0xef, 0xb6,
-	0xd2, 0xb7, 0xc2, 0xfe, 0x89, 0xab, 0x6c, 0x63, 0x5d, 0x44, 0xfb, 0xdc,
-	0x51, 0xed, 0x63, 0xdb, 0xda, 0xc7, 0x26, 0x1d, 0x46, 0xc4, 0x4e, 0xfb,
-	0xbe, 0x02, 0xcf, 0x0c, 0x67, 0xb3, 0x55, 0xf9, 0x0a, 0xb2, 0xb2, 0xaf,
-	0xe0, 0xd3, 0x74, 0x16, 0xfb, 0xa4, 0x6f, 0xa7, 0x72, 0x3f, 0x8d, 0x5e,
-	0xbe, 0x89, 0x34, 0xf8, 0x36, 0x53, 0xd9, 0xe6, 0xa3, 0x30, 0x83, 0xd8,
-	0xdb, 0x6f, 0x83, 0xd6, 0x3d, 0x92, 0x1d, 0x3f, 0xab, 0x6d, 0x30, 0x63,
-	0x07, 0xfa, 0xed, 0x9e, 0xcc, 0x66, 0x53, 0x0d, 0x86, 0x9e, 0xa7, 0x19,
-	0x56, 0x33, 0x90, 0x97, 0xe2, 0x5a, 0xf4, 0x6d, 0x7c, 0x3f, 0x67, 0x56,
-	0xfb, 0x39, 0xe7, 0xe5, 0xa0, 0xeb, 0xc5, 0x0a, 0xfd, 0xa5, 0x0b, 0xa8,
-	0x53, 0xb4, 0xc7, 0xe9, 0x4f, 0x9a, 0x26, 0xfd, 0xc9, 0x24, 0x82, 0x0e,
-	0x6f, 0x2f, 0x6d, 0xd8, 0xcb, 0xcc, 0xc2, 0x5e, 0xea, 0x2f, 0x2c, 0xdd,
-	0x0b, 0xe9, 0xb7, 0xc1, 0x4f, 0x4b, 0xe3, 0x14, 0xe7, 0xfc, 0x46, 0x98,
-	0x18, 0xd6, 0x4f, 0x9f, 0xc8, 0xf5, 0x7c, 0xb1, 0xa5, 0xf3, 0xc2, 0x63,
-	0x28, 0x4d, 0x5d, 0xa3, 0x8d, 0xfb, 0xf7, 0xf5, 0xca, 0xd2, 0xd8, 0xce,
-	0x3d, 0xfc, 0x09, 0xe6, 0x8c, 0x19, 0x79, 0xe5, 0x9b, 0xd1, 0xcf, 0x41,
-	0xdc, 0x5d, 0x7a, 0x05, 0x4f, 0xea, 0x8e, 0x9a, 0x07, 0xfb, 0x8d, 0xaa,
-	0xfd, 0x8e, 0xb9, 0x97, 0xd4, 0x1e, 0xa7, 0x4b, 0x3f, 0x90, 0xc2, 0xc9,
-	0x1f, 0xc2, 0x26, 0x06, 0x73, 0x75, 0xcc, 0x73, 0x92, 0x57, 0xc5, 0x00,
-	0xb6, 0x92, 0x66, 0xe6, 0xe1, 0xbe, 0x17, 0xf6, 0xe2, 0x85, 0x71, 0x9c,
-	0xbf, 0xe1, 0xb5, 0xab, 0xf5, 0x7d, 0x9e, 0xd7, 0x04, 0xe8, 0xa9, 0xc0,
-	0x47, 0x8d, 0x83, 0x86, 0xe0, 0x98, 0xc7, 0xa4, 0xcf, 0xe5, 0x59, 0xb5,
-	0xc7, 0x87, 0xc4, 0xb1, 0xf3, 0xe2, 0xfb, 0x25, 0x5c, 0x9f, 0x78, 0x90,
-	0x43, 0x0c, 0xc5, 0xdc, 0xaa, 0xcf, 0x57, 0x9f, 0xa7, 0xd1, 0x0b, 0xd5,
-	0xf2, 0x31, 0x8a, 0xd8, 0xab, 0xe0, 0x92, 0x4f, 0xbe, 0xdc, 0xfa, 0x6b,
-	0x5f, 0x31, 0xb8, 0x9f, 0x11, 0x95, 0x4f, 0x7c, 0x6d, 0x41, 0x7e, 0x87,
-	0x81, 0x2b, 0x9e, 0x3c, 0xbe, 0xaa, 0x79, 0xe3, 0xcb, 0x6d, 0x54, 0xcb,
-	0x00, 0x63, 0x43, 0xea, 0x95, 0x2f, 0x23, 0x1d, 0xf6, 0xdd, 0x8a, 0x17,
-	0x6c, 0x53, 0x79, 0x46, 0x75, 0xce, 0x83, 0x0b, 0xe7, 0xbc, 0xbe, 0x4a,
-	0x66, 0x53, 0xb6, 0xa7, 0xa3, 0xd4, 0x45, 0xe8, 0x34, 0xf8, 0xf5, 0xfc,
-	0x12, 0xdd, 0xef, 0xba, 0x46, 0x8e, 0x36, 0x2a, 0xa1, 0xc9, 0x97, 0xc1,
-	0xcb, 0x5b, 0x11, 0xbb, 0x88, 0x58, 0x13, 0xc4, 0x28, 0xfa, 0x22, 0x8b,
-	0xfe, 0xf1, 0xb4, 0xac, 0xe4, 0x1b, 0x5f, 0xcf, 0x0f, 0xb9, 0x7d, 0x8d,
-	0x7e, 0xc8, 0xaf, 0xd6, 0x30, 0x96, 0x99, 0x83, 0x9e, 0x1e, 0xc0, 0xf8,
-	0x1a, 0xe7, 0x47, 0xb0, 0x6f, 0xa7, 0xad, 0x5a, 0xc7, 0xc7, 0x8b, 0xa8,
-	0x6c, 0x9c, 0xdc, 0xa2, 0x30, 0xc3, 0x9e, 0x58, 0xc4, 0x8c, 0x61, 0x97,
-	0xf2, 0xab, 0xf4, 0x34, 0xb6, 0x51, 0x7c, 0x8c, 0x78, 0xd6, 0x62, 0xbe,
-	0x67, 0x65, 0x1c, 0xf0, 0x72, 0xba, 0x2b, 0xc7, 0x0a, 0x37, 0x55, 0xf1,
-	0x72, 0x25, 0xdc, 0x3c, 0x07, 0xde, 0xa5, 0x11, 0x13, 0x27, 0xcf, 0x88,
-	0xec, 0x41, 0x9c, 0x9c, 0x7c, 0x4b, 0xa4, 0x0f, 0xb1, 0x72, 0x72, 0x56,
-	0x24, 0x83, 0x78, 0x99, 0xf1, 0xdb, 0x5d, 0xe0, 0x69, 0x2f, 0xe2, 0xe9,
-	0x1e, 0x60, 0x6a, 0x0a, 0x18, 0xbb, 0x1d, 0xfc, 0xed, 0x02, 0xbf, 0x6d,
-	0xc4, 0x5b, 0x65, 0x39, 0x70, 0x5c, 0x8c, 0x7d, 0x2a, 0x7f, 0x4d, 0x7d,
-	0x8f, 0xc1, 0xce, 0x56, 0x2a, 0x87, 0x52, 0xed, 0x88, 0xf5, 0x13, 0xf2,
-	0x39, 0x8b, 0xb1, 0xad, 0x61, 0xb5, 0x75, 0x7f, 0x3f, 0x14, 0xf4, 0x6b,
-	0xb3, 0xd7, 0xb5, 0x13, 0xcb, 0xf9, 0x9f, 0x53, 0xb6, 0xe2, 0xc5, 0xd0,
-	0x6a, 0xfc, 0xdf, 0xb7, 0xc0, 0xff, 0x9e, 0x3a, 0xa9, 0xbb, 0x4b, 0xe5,
-	0x16, 0xda, 0xba, 0x0f, 0x11, 0xcf, 0x52, 0xb0, 0xfb, 0xb0, 0xcf, 0x15,
-	0xb9, 0x33, 0x75, 0xb5, 0x72, 0xd1, 0xd9, 0x20, 0xf9, 0xed, 0x0f, 0x6a,
-	0x4c, 0x3f, 0xf5, 0x87, 0x59, 0xa7, 0x08, 0x1d, 0xf1, 0xf2, 0x88, 0x43,
-	0xe3, 0x11, 0x58, 0x0a, 0xfe, 0x35, 0xca, 0x74, 0xef, 0x55, 0x9c, 0xe3,
-	0xb6, 0x33, 0x4c, 0x42, 0x11, 0x6b, 0xa6, 0x63, 0x51, 0x95, 0x43, 0xde,
-	0xe4, 0xb0, 0xde, 0xc6, 0xb9, 0x0e, 0xc8, 0x34, 0xfc, 0x8b, 0x99, 0x5e,
-	0xd0, 0xb8, 0xbd, 0x19, 0xfd, 0xa9, 0x7b, 0xe4, 0xf9, 0x80, 0x0c, 0xc6,
-	0xc8, 0xd3, 0x18, 0xfa, 0xef, 0x45, 0x9f, 0x46, 0x3c, 0xff, 0x28, 0x34,
-	0x6d, 0x33, 0x9e, 0xfe, 0x3c, 0xca, 0x9c, 0x23, 0x68, 0x5b, 0x77, 0x85,
-	0x45, 0xcd, 0xc9, 0x31, 0xcd, 0x0a, 0x03, 0x16, 0xd7, 0xe2, 0x3a, 0x6c,
-	0x7b, 0xaf, 0x72, 0x47, 0x77, 0x6f, 0x60, 0xbd, 0x86, 0xc0, 0x7a, 0xbd,
-	0x81, 0xf5, 0x48, 0x67, 0x63, 0x80, 0xce, 0x46, 0x8c, 0xff, 0x5d, 0xac,
-	0x4d, 0x7e, 0x04, 0xd7, 0xcc, 0x07, 0xd6, 0xf4, 0xf7, 0xd7, 0x1c, 0x18,
-	0xf7, 0x0e, 0xd6, 0x63, 0x5d, 0x2c, 0x50, 0x47, 0x1a, 0x9a, 0x50, 0xc7,
-	0x72, 0x63, 0x80, 0xae, 0xa8, 0x8a, 0xf7, 0xa7, 0xd5, 0x19, 0x92, 0xcf,
-	0x75, 0xb0, 0x6b, 0x26, 0x6c, 0x4b, 0x0d, 0xfc, 0xaf, 0xea, 0xbd, 0x7e,
-	0x0d, 0xeb, 0xfa, 0xf3, 0xc5, 0x30, 0x07, 0xfb, 0xb3, 0x6f, 0x48, 0x8f,
-	0x67, 0x3d, 0xdb, 0xff, 0xb6, 0xf2, 0x8c, 0xe2, 0x5b, 0x1a, 0xb4, 0x93,
-	0xc6, 0x36, 0x99, 0x6a, 0xb4, 0x70, 0x9e, 0xa6, 0xb6, 0xa5, 0xc0, 0xda,
-	0xb2, 0x69, 0xb4, 0x77, 0xf3, 0xfc, 0x37, 0x68, 0x4c, 0xad, 0x33, 0xb2,
-	0xc7, 0x99, 0x4b, 0xa8, 0xd7, 0xb1, 0x22, 0xe2, 0x13, 0x65, 0x87, 0x7c,
-	0x3b, 0x41, 0x3b, 0x44, 0xdf, 0x86, 0x36, 0xf6, 0x9c, 0x7e, 0xc7, 0x13,
-	0x72, 0xfc, 0xd0, 0x4c, 0xa3, 0x5c, 0x54, 0x7c, 0xb5, 0x65, 0x7e, 0x81,
-	0xaf, 0x61, 0xfd, 0xbd, 0xe6, 0x31, 0xfd, 0x2d, 0x64, 0x3f, 0x7c, 0x27,
-	0xbc, 0x97, 0x32, 0xa0, 0x23, 0x21, 0xed, 0xdd, 0xcc, 0x61, 0x14, 0xf1,
-	0x74, 0xf0, 0x34, 0xf0, 0x84, 0xcd, 0x42, 0x0c, 0xd2, 0xde, 0xcd, 0x58,
-	0x50, 0x40, 0xdb, 0x15, 0x15, 0x07, 0xce, 0x94, 0x6d, 0xe3, 0x4e, 0xd7,
-	0xcb, 0x1d, 0xcd, 0x3b, 0xab, 0xe5, 0x8e, 0x1e, 0xa8, 0xc5, 0x79, 0x9c,
-	0xf2, 0x73, 0x47, 0xf3, 0xa2, 0x72, 0x47, 0xa7, 0xae, 0x93, 0x3b, 0xca,
-	0xac, 0x3d, 0x77, 0xc4, 0xf9, 0x2d, 0xb9, 0xbb, 0xc7, 0x36, 0xbf, 0xa8,
-	0x73, 0x47, 0x6f, 0x88, 0x97, 0x3b, 0xba, 0x28, 0x2b, 0xe7, 0x8e, 0x8e,
-	0x56, 0xe5, 0x8e, 0x9a, 0x54, 0xee, 0x88, 0xf3, 0x78, 0xb9, 0x23, 0x96,
-	0xf3, 0xdd, 0xbf, 0xac, 0x72, 0xe9, 0xf9, 0x6e, 0x60, 0xb0, 0xeb, 0x63,
-	0x9c, 0x6d, 0x0c, 0xa8, 0xf8, 0xf2, 0x4a, 0xb8, 0xd9, 0xf1, 0x31, 0x8e,
-	0xb6, 0x60, 0xf3, 0x82, 0x3d, 0xf3, 0xf1, 0x6e, 0x54, 0xd9, 0xbd, 0xe5,
-	0xf9, 0xc5, 0x7b, 0xaa, 0xf2, 0x8b, 0x03, 0x9e, 0xdd, 0x50, 0x38, 0x37,
-	0xa8, 0x71, 0x6e, 0x74, 0xc1, 0xcf, 0x39, 0x59, 0xcb, 0x18, 0x7c, 0xa4,
-	0x14, 0xc4, 0x51, 0x4b, 0x8d, 0xf5, 0xf2, 0x2c, 0x8b, 0x18, 0x7a, 0xb8,
-	0x0a, 0x43, 0x1f, 0x5b, 0xf1, 0xbb, 0x58, 0x3c, 0xb3, 0xfc, 0xbb, 0x98,
-	0x21, 0xcd, 0xf4, 0x39, 0xba, 0xf3, 0xd8, 0x03, 0x63, 0xe6, 0xfd, 0x92,
-	0x19, 0xb0, 0x81, 0x45, 0x7e, 0xfe, 0x85, 0xe7, 0xbc, 0x68, 0x63, 0xb2,
-	0xe6, 0xc7, 0x97, 0x83, 0x79, 0x48, 0xe5, 0x60, 0xbe, 0x5f, 0x1b, 0xcc,
-	0xc1, 0xcc, 0x03, 0xb3, 0x32, 0x16, 0xf3, 0x5b, 0x2b, 0xe7, 0x60, 0x1e,
-	0x5a, 0x21, 0x07, 0xf3, 0x5d, 0x59, 0xcc, 0xc1, 0x7c, 0x57, 0xfc, 0x1c,
-	0x0c, 0xe7, 0x08, 0x69, 0x9f, 0x56, 0x30, 0xee, 0x02, 0x7e, 0xe7, 0xf1,
-	0xf3, 0xf2, 0x32, 0xf3, 0x0b, 0x7b, 0x58, 0x29, 0x2f, 0xf3, 0x6f, 0xb5,
-	0x1f, 0x24, 0x2f, 0xe3, 0xd9, 0x04, 0x3f, 0x2f, 0x83, 0x9f, 0x0d, 0x1b,
-	0x64, 0x06, 0xf3, 0x32, 0xef, 0x53, 0x37, 0x50, 0xc7, 0x32, 0xeb, 0xa1,
-	0x23, 0xb0, 0x53, 0x19, 0xd8, 0x99, 0x69, 0xf7, 0xd7, 0xd5, 0x79, 0xcc,
-	0xb8, 0x53, 0xd8, 0x77, 0x02, 0xe7, 0x41, 0x5e, 0xb6, 0x2b, 0x5f, 0x34,
-	0x63, 0xc5, 0x8d, 0x6c, 0x27, 0xac, 0xda, 0x38, 0xbf, 0x9d, 0x5b, 0xc6,
-	0x50, 0x99, 0xf2, 0x1e, 0x31, 0x0a, 0xd8, 0x4b, 0xdf, 0xf8, 0x94, 0x0c,
-	0x95, 0x7d, 0x3f, 0xab, 0x5b, 0x9f, 0xc5, 0x94, 0xd2, 0xd3, 0x69, 0xf0,
-	0x00, 0x98, 0xb1, 0x06, 0x9b, 0x75, 0x16, 0x34, 0x07, 0xf7, 0x81, 0x18,
-	0xba, 0x07, 0x75, 0xea, 0xdc, 0xe9, 0x6f, 0xfa, 0xb4, 0x24, 0xa8, 0xf3,
-	0x6b, 0x98, 0x8f, 0x75, 0x67, 0x55, 0xfc, 0x56, 0xe8, 0xe1, 0x5e, 0x69,
-	0xfb, 0xe6, 0x40, 0x1f, 0xea, 0x66, 0x18, 0x33, 0xd2, 0x0e, 0xfa, 0x31,
-	0x5d, 0x54, 0xc5, 0x74, 0x9b, 0x15, 0x3f, 0xc8, 0xeb, 0x5f, 0x8b, 0x10,
-	0x3b, 0x37, 0x3b, 0xdc, 0xc3, 0x79, 0x8d, 0x7b, 0x2c, 0xfb, 0xb1, 0x23,
-	0xdf, 0xc9, 0xa7, 0xa7, 0x54, 0xde, 0x67, 0xda, 0xf5, 0xcf, 0xf0, 0x5b,
-	0xd8, 0x3b, 0xcb, 0xbd, 0x72, 0xa1, 0x59, 0x22, 0xb1, 0x34, 0x73, 0xbd,
-	0xf4, 0xd5, 0x77, 0x30, 0xf7, 0x50, 0xd3, 0xb4, 0x8a, 0xfe, 0xee, 0x5b,
-	0x45, 0x7f, 0xef, 0xae, 0xd2, 0xdf, 0xfe, 0x55, 0xf5, 0xf7, 0xeb, 0x91,
-	0xa0, 0xfe, 0xee, 0x5b, 0x45, 0x7f, 0x1f, 0xad, 0xd2, 0xdf, 0x83, 0x37,
-	0xa4, 0xbf, 0x3a, 0x36, 0x4e, 0xdd, 0xaa, 0x72, 0xc6, 0xc3, 0x13, 0xc4,
-	0xac, 0x4f, 0xeb, 0xdc, 0xd5, 0x4a, 0xbe, 0x98, 0x4f, 0x43, 0x5b, 0xcd,
-	0x47, 0xe3, 0x87, 0xfd, 0x23, 0xf6, 0xe9, 0xf9, 0xa3, 0xfd, 0xf0, 0x69,
-	0xaf, 0xbd, 0xee, 0x1f, 0x8b, 0x99, 0xf6, 0x7d, 0xc0, 0xad, 0x1f, 0xd1,
-	0xda, 0x6b, 0x91, 0x3f, 0xc6, 0x56, 0xf4, 0x07, 0xa2, 0xda, 0x66, 0x4e,
-	0x6a, 0x1d, 0xf4, 0xf3, 0x12, 0x41, 0x7d, 0xa6, 0x9c, 0x52, 0x36, 0x7f,
-	0x8a, 0x3d, 0x51, 0x3e, 0x7d, 0x0c, 0xd8, 0x52, 0xa5, 0x13, 0x73, 0x52,
-	0x00, 0x6e, 0x79, 0x3a, 0x41, 0x39, 0xeb, 0xc4, 0xbe, 0x61, 0x2b, 0xdd,
-	0xa7, 0xbd, 0xb3, 0x70, 0xf0, 0x9c, 0xf1, 0x75, 0x3f, 0x81, 0x75, 0xfd,
-	0x36, 0xda, 0x1e, 0x07, 0x3e, 0xd9, 0x36, 0xf8, 0x93, 0x2d, 0xc0, 0x19,
-	0xd6, 0x2f, 0xcd, 0x73, 0xaf, 0x8e, 0xb1, 0x52, 0x0c, 0xa3, 0xef, 0xe9,
-	0x1e, 0x60, 0x4e, 0x0f, 0x71, 0xb3, 0x84, 0xd8, 0x8c, 0x7a, 0x41, 0x5d,
-	0xe9, 0xe8, 0xda, 0x6d, 0xd2, 0xe7, 0x7b, 0x12, 0x71, 0xfc, 0x2d, 0x4a,
-	0xaf, 0x76, 0x97, 0x3b, 0x66, 0xdf, 0x30, 0xb9, 0x46, 0xa5, 0x92, 0x57,
-	0xdf, 0x19, 0xc4, 0x6c, 0xeb, 0xde, 0xb2, 0x8e, 0x36, 0xf3, 0x16, 0x27,
-	0xa4, 0xe5, 0x3e, 0x83, 0x77, 0xea, 0xd1, 0xeb, 0xf0, 0x47, 0x78, 0x47,
-	0xe1, 0x27, 0x2a, 0x5f, 0x37, 0xed, 0xd2, 0xf7, 0x60, 0xcc, 0xb4, 0x53,
-	0xf7, 0xdb, 0xa2, 0xbe, 0xb1, 0x66, 0x53, 0x3b, 0xf4, 0xf7, 0x36, 0xda,
-	0xc4, 0x24, 0x31, 0x75, 0xc9, 0x79, 0xf3, 0x8e, 0x47, 0x4e, 0xc5, 0x5c,
-	0x1c, 0xaf, 0x7c, 0x7f, 0xc4, 0x49, 0x56, 0xe0, 0xfb, 0x40, 0x44, 0xc7,
-	0x97, 0xd4, 0xf9, 0xa8, 0x8a, 0x7d, 0xbd, 0x78, 0x8a, 0xf1, 0xf7, 0xd2,
-	0xbb, 0x1d, 0x2b, 0xcb, 0x40, 0xcb, 0x07, 0x90, 0x81, 0xea, 0xf3, 0x8b,
-	0x00, 0x8b, 0xfc, 0xf3, 0xf3, 0x7d, 0xac, 0xbf, 0xd0, 0xfb, 0xde, 0xa2,
-	0xf5, 0xe9, 0xff, 0xc3, 0x3e, 0x8d, 0xc0, 0x3e, 0x7d, 0x6c, 0xfc, 0xa2,
-	0xde, 0xe7, 0xce, 0x2a, 0x6c, 0xec, 0x41, 0xfd, 0xe1, 0x9a, 0x8d, 0x1f,
-	0x10, 0x1b, 0xf7, 0xde, 0x10, 0x36, 0xfe, 0x70, 0xdd, 0x5a, 0xb1, 0xf1,
-	0xd0, 0x07, 0xc6, 0x46, 0xee, 0x6b, 0x65, 0x3c, 0xda, 0xb7, 0x0c, 0x8f,
-	0xfe, 0xe0, 0x13, 0xc4, 0xa3, 0xd5, 0xb0, 0x84, 0xe7, 0xd2, 0xa0, 0x7c,
-	0x6c, 0x4f, 0xff, 0xe0, 0x5f, 0xcc, 0x84, 0xe5, 0xc2, 0xbd, 0x11, 0x79,
-	0x6d, 0x27, 0xfc, 0x6e, 0xf2, 0x48, 0x9d, 0x07, 0xcb, 0xd1, 0x3a, 0xcf,
-	0x36, 0xc6, 0x1b, 0xbd, 0x9c, 0x02, 0xc7, 0xf8, 0x3a, 0x6d, 0xa3, 0x9d,
-	0x6d, 0x5b, 0xe4, 0xf5, 0xc6, 0x1b, 0x89, 0x53, 0xf9, 0x8d, 0x66, 0xa5,
-	0x38, 0x75, 0xf5, 0x9c, 0xe6, 0x62, 0x9c, 0x4a, 0xac, 0x6d, 0xd4, 0x79,
-	0x2c, 0xc6, 0x67, 0xfb, 0x35, 0x7e, 0xf2, 0x1d, 0xf1, 0xb8, 0x8b, 0x58,
-	0xdc, 0x45, 0x1c, 0xee, 0x22, 0x46, 0x87, 0x6d, 0x7e, 0x01, 0x32, 0xf7,
-	0x6d, 0x17, 0x31, 0xb8, 0x8b, 0x18, 0xdc, 0xed, 0xd2, 0x71, 0x7c, 0xbf,
-	0xfe, 0x76, 0xc1, 0xef, 0xfb, 0xcc, 0x83, 0x14, 0x61, 0x57, 0x46, 0x79,
-	0x3f, 0xc3, 0xcc, 0xa6, 0xd6, 0xe9, 0xfd, 0xf9, 0x79, 0xfd, 0x56, 0x9d,
-	0x5b, 0xda, 0xb4, 0x49, 0xf9, 0x0b, 0xe6, 0x2b, 0x75, 0xde, 0x1d, 0x00,
-	0xde, 0x23, 0x79, 0x14, 0xbe, 0x92, 0xba, 0x87, 0x45, 0x3d, 0xad, 0x98,
-	0x69, 0xe6, 0x8e, 0xc4, 0x34, 0xd3, 0x77, 0x60, 0xcc, 0x36, 0x2f, 0x66,
-	0x89, 0x49, 0xc8, 0x4c, 0xd7, 0x93, 0xa7, 0x86, 0x99, 0x5e, 0xaf, 0xe7,
-	0x9a, 0xaf, 0xf3, 0xfc, 0xbd, 0x4e, 0x96, 0x2d, 0x33, 0xfd, 0x59, 0x3e,
-	0x71, 0xee, 0x7e, 0xfd, 0x3d, 0x8d, 0x4b, 0xd7, 0x1a, 0x53, 0x18, 0x9f,
-	0x4d, 0xdd, 0x8b, 0xf9, 0xd4, 0xfd, 0xa7, 0x05, 0x7e, 0x9b, 0xd7, 0xe4,
-	0xf7, 0x98, 0xe6, 0xb7, 0xc7, 0xe3, 0x10, 0xfb, 0xa9, 0xdc, 0x36, 0x79,
-	0xed, 0xcf, 0xa7, 0x72, 0x93, 0x58, 0x47, 0xdd, 0x01, 0xc1, 0xb3, 0x62,
-	0x49, 0xc3, 0xc0, 0x7d, 0x61, 0x27, 0xb8, 0xae, 0xff, 0x2d, 0x7f, 0x2d,
-	0x6b, 0x6e, 0x51, 0xdf, 0x07, 0x3d, 0xbb, 0x31, 0xa6, 0x64, 0xd0, 0x4a,
-	0x73, 0x5f, 0xef, 0x43, 0xfe, 0xc6, 0x94, 0xfc, 0xe5, 0x10, 0x67, 0x8d,
-	0xf6, 0x74, 0x24, 0x2c, 0x73, 0xba, 0x8e, 0x39, 0xe4, 0xbe, 0xb2, 0x8f,
-	0x7d, 0x5c, 0xaf, 0xda, 0xa6, 0x33, 0xff, 0xe7, 0x63, 0x9a, 0xb4, 0x78,
-	0x79, 0xc1, 0xb5, 0xde, 0xa9, 0x58, 0xd4, 0xa5, 0xc1, 0x05, 0x5d, 0xaa,
-	0xab, 0xd2, 0x25, 0x7f, 0x9f, 0xeb, 0xc5, 0xff, 0xe6, 0xbe, 0xd2, 0x5d,
-	0x90, 0xb9, 0x72, 0xe0, 0x1b, 0xcf, 0x82, 0x6c, 0xf0, 0x4e, 0xcc, 0x3d,
-	0x90, 0x41, 0x7e, 0xdf, 0xd8, 0x03, 0x3d, 0xaa, 0x54, 0xfa, 0x98, 0x27,
-	0xdf, 0xde, 0xaf, 0xef, 0x5b, 0x5c, 0x51, 0x39, 0x12, 0x6b, 0x59, 0x8e,
-	0xa4, 0x0f, 0xb2, 0x02, 0x3f, 0x00, 0x3a, 0x98, 0x57, 0x67, 0x49, 0x9f,
-	0xa0, 0xfa, 0x1b, 0xd2, 0xc5, 0x7a, 0x8f, 0x0f, 0x9d, 0xf5, 0xde, 0x77,
-	0x14, 0x73, 0xd3, 0xd2, 0x32, 0xc7, 0x27, 0xea, 0x3d, 0x59, 0x39, 0x06,
-	0xfb, 0xdc, 0x07, 0x59, 0xac, 0x91, 0x9c, 0x9a, 0xef, 0x98, 0xe4, 0x9f,
-	0xfd, 0xcf, 0xc6, 0xa5, 0xfd, 0x51, 0x77, 0xd2, 0xef, 0xff, 0x78, 0x55,
-	0xff, 0xc7, 0xd1, 0xff, 0x67, 0x55, 0xfd, 0x1f, 0x0f, 0xf4, 0x3f, 0xa1,
-	0xfb, 0xd7, 0xa2, 0xbf, 0xd2, 0x83, 0x26, 0xdf, 0x2f, 0x36, 0x1d, 0xc4,
-	0xb3, 0xcf, 0xfa, 0x63, 0x4e, 0x04, 0xc6, 0x4c, 0x56, 0xad, 0x31, 0x89,
-	0x7e, 0xf1, 0xa6, 0xa5, 0x6b, 0xa0, 0xee, 0x64, 0x8d, 0xfe, 0xbe, 0x47,
-	0x9f, 0xe5, 0xa0, 0xce, 0x17, 0xe0, 0x59, 0x0a, 0x7e, 0x33, 0xe2, 0x77,
-	0x0a, 0xca, 0x9e, 0xff, 0x8d, 0xc2, 0xbf, 0x93, 0x47, 0xbd, 0xcd, 0x40,
-	0x6f, 0x17, 0xfd, 0x1a, 0x4f, 0x2e, 0x83, 0x32, 0x49, 0x9c, 0x28, 0x4a,
-	0xc8, 0x29, 0xd3, 0x57, 0x32, 0x0a, 0x33, 0xbe, 0x7d, 0xe2, 0xbd, 0x2b,
-	0xde, 0xd7, 0xf5, 0xec, 0x70, 0xd8, 0x99, 0xd3, 0x31, 0xe2, 0xaf, 0x90,
-	0x7e, 0xe0, 0xa6, 0x8f, 0x9d, 0x72, 0xcc, 0xd3, 0x1f, 0xca, 0x31, 0xe7,
-	0xd7, 0x7a, 0x44, 0x99, 0xd5, 0xeb, 0xf4, 0x2d, 0xc3, 0xb7, 0xc4, 0xb2,
-	0x3c, 0x5c, 0x68, 0x0d, 0xf8, 0xd6, 0xbf, 0x80, 0x6f, 0xf7, 0xca, 0x94,
-	0x9d, 0x50, 0x79, 0xd0, 0x43, 0x0b, 0x79, 0x81, 0xc3, 0x91, 0x46, 0x87,
-	0x79, 0x81, 0xe4, 0xa9, 0x8c, 0x7c, 0xb0, 0xbc, 0xc0, 0xbe, 0x2a, 0x1d,
-	0xd9, 0xbb, 0xaa, 0xed, 0xfc, 0xb3, 0xfa, 0xb5, 0xe6, 0x05, 0x1e, 0xa9,
-	0xb2, 0x63, 0x87, 0x6e, 0xc0, 0x76, 0xe6, 0x95, 0xed, 0xe4, 0x5e, 0xaf,
-	0xe7, 0xcb, 0x7f, 0x25, 0xf2, 0xd1, 0xd8, 0xce, 0xd5, 0x72, 0xe2, 0x41,
-	0x7b, 0x40, 0xb9, 0xba, 0xac, 0xfd, 0x6c, 0x3c, 0x67, 0x2e, 0x43, 0x3f,
-	0x4d, 0x19, 0x54, 0xb2, 0xcc, 0xb2, 0x1f, 0xff, 0xde, 0xb7, 0x10, 0xff,
-	0x2e, 0xc6, 0xac, 0xf0, 0x67, 0xbb, 0xfc, 0xd8, 0x88, 0x7e, 0xb3, 0x6d,
-	0x14, 0xdc, 0x3d, 0xe6, 0x90, 0x6a, 0x63, 0x8e, 0xf7, 0x36, 0xf9, 0x9c,
-	0xba, 0x27, 0x70, 0x5e, 0xe7, 0xd2, 0xa6, 0x54, 0x4c, 0xc0, 0xef, 0x1c,
-	0x85, 0xd4, 0x46, 0xed, 0x03, 0x5e, 0x0f, 0x67, 0x97, 0xc6, 0xcf, 0xa6,
-	0x79, 0x04, 0x63, 0x19, 0x3f, 0x7f, 0x21, 0x4a, 0x4c, 0xcd, 0x96, 0x57,
-	0x1d, 0x8f, 0x71, 0x1c, 0xcf, 0x3e, 0x2a, 0x56, 0x46, 0xbf, 0x39, 0x3d,
-	0xde, 0x8b, 0x95, 0xb3, 0xe5, 0xad, 0x51, 0x0f, 0x17, 0x57, 0x8b, 0x63,
-	0x8e, 0x44, 0x99, 0x8b, 0x9c, 0x73, 0xaf, 0x47, 0xeb, 0xf2, 0xd8, 0x3c,
-	0xb4, 0x2c, 0x36, 0xb7, 0x74, 0xec, 0x7d, 0xbf, 0x8a, 0xcd, 0x3d, 0x1e,
-	0x73, 0x2f, 0xc1, 0xd8, 0xca, 0x01, 0x36, 0xf2, 0x5b, 0x10, 0xb1, 0x82,
-	0x3e, 0x0b, 0xe4, 0x67, 0xfc, 0x37, 0x94, 0x1f, 0xb3, 0x5c, 0x7e, 0x3e,
-	0x6e, 0xbb, 0xe1, 0xef, 0xfd, 0xb2, 0x78, 0xf9, 0xc5, 0x3d, 0xa0, 0x85,
-	0xf1, 0x56, 0x58, 0xcb, 0xc3, 0xcf, 0x69, 0xfc, 0xf6, 0xfb, 0xf9, 0xb9,
-	0x86, 0x85, 0x6f, 0xc9, 0xc5, 0xcc, 0x92, 0x1c, 0xcf, 0x16, 0xa6, 0xce,
-	0x71, 0xee, 0x99, 0x1b, 0xf8, 0xde, 0xf2, 0x61, 0xee, 0x7c, 0x54, 0xdb,
-	0xb9, 0x57, 0x21, 0xfb, 0x09, 0x7d, 0xff, 0xaf, 0x0b, 0x3a, 0xc0, 0x3b,
-	0xd0, 0xd5, 0x58, 0xab, 0xee, 0xf9, 0x45, 0x36, 0xa5, 0xf9, 0xed, 0x82,
-	0x3e, 0xc1, 0x4f, 0xf4, 0x5e, 0xe3, 0x72, 0x6c, 0xc2, 0xcb, 0xd3, 0x9a,
-	0xab, 0xde, 0xf1, 0xbb, 0x04, 0x5e, 0x24, 0x8f, 0xfa, 0x79, 0x5a, 0xd3,
-	0xbb, 0xe3, 0x77, 0xf4, 0xa3, 0xbb, 0xe3, 0xc7, 0xf9, 0x2d, 0xd9, 0xbb,
-	0xc2, 0x1d, 0xbf, 0xd0, 0x1a, 0xef, 0xf8, 0x6d, 0x54, 0x79, 0x5a, 0xce,
-	0xe3, 0xe5, 0x69, 0x59, 0x6e, 0xeb, 0xfe, 0x94, 0xc2, 0xa8, 0xe9, 0x09,
-	0xe6, 0x75, 0x1e, 0x5c, 0xf7, 0xc9, 0xe4, 0x75, 0xde, 0x8b, 0x7e, 0xfc,
-	0x79, 0x1d, 0x7e, 0x17, 0xf8, 0xb2, 0xf7, 0xdd, 0x5a, 0x6e, 0x24, 0x3f,
-	0xf0, 0xe1, 0x72, 0xb0, 0x07, 0x55, 0x0e, 0x76, 0xfb, 0xfa, 0x60, 0x0e,
-	0xd6, 0xbc, 0xce, 0x3d, 0xb8, 0x83, 0x2b, 0xe4, 0x60, 0xc3, 0x81, 0x7b,
-	0x70, 0x61, 0x7d, 0x0f, 0x6e, 0xa3, 0x83, 0x18, 0x53, 0xe7, 0x5b, 0xcd,
-	0x55, 0xef, 0xc1, 0xed, 0x5e, 0xff, 0xe1, 0xf3, 0xad, 0xcb, 0xee, 0xc1,
-	0x1d, 0xcd, 0x48, 0x8b, 0x24, 0x6e, 0x28, 0x16, 0xfa, 0x30, 0x71, 0x10,
-	0xff, 0x8f, 0x40, 0x0d, 0xf6, 0x0c, 0x99, 0x8f, 0x51, 0x3e, 0x29, 0x77,
-	0x69, 0x33, 0x5f, 0xe6, 0x7b, 0x17, 0xcf, 0xc7, 0xe8, 0xef, 0x5c, 0x7a,
-	0xb7, 0x62, 0xf1, 0x6e, 0x72, 0x64, 0xe1, 0x6e, 0xf2, 0x18, 0x64, 0xc6,
-	0x9c, 0x88, 0xc8, 0x74, 0xc0, 0xb6, 0x8e, 0xba, 0xf0, 0x9b, 0x26, 0x6d,
-	0xdd, 0xce, 0xff, 0xa7, 0x82, 0xb8, 0xb0, 0xc4, 0xfb, 0xcc, 0x0d, 0x12,
-	0x9a, 0x54, 0x98, 0x1a, 0xf3, 0xfe, 0xaf, 0x4e, 0x1c, 0x7d, 0x78, 0x77,
-	0x35, 0x2c, 0x87, 0x62, 0x94, 0x65, 0x5f, 0x8e, 0xbf, 0x05, 0xfe, 0x36,
-	0x65, 0x16, 0xcb, 0x31, 0x2d, 0xd7, 0x94, 0x69, 0x5f, 0xfe, 0x62, 0x32,
-	0x32, 0x41, 0x59, 0xde, 0xa1, 0xff, 0x9f, 0xc4, 0x39, 0x29, 0x94, 0xcf,
-	0xea, 0x78, 0x43, 0x7d, 0x8b, 0x02, 0x1f, 0x5b, 0xb4, 0x0d, 0xc6, 0x73,
-	0xa6, 0x85, 0x36, 0x8f, 0xdf, 0x1e, 0xa5, 0x6f, 0x7c, 0x5b, 0x7c, 0x08,
-	0x78, 0x37, 0xa8, 0x72, 0x27, 0x37, 0xc2, 0x6f, 0xe3, 0x1a, 0xdf, 0x48,
-	0xd7, 0xca, 0x73, 0xdf, 0x5f, 0xbe, 0x8c, 0xfd, 0xb5, 0x40, 0x36, 0xbe,
-	0x2a, 0xb9, 0x93, 0xb7, 0x49, 0xdf, 0x89, 0x24, 0xe8, 0x79, 0xbf, 0x52,
-	0x48, 0xc1, 0xb7, 0x7e, 0x96, 0x77, 0xe1, 0x80, 0xa1, 0x2e, 0x30, 0x14,
-	0xbc, 0x7b, 0x61, 0x99, 0xbf, 0x11, 0xbc, 0x43, 0x97, 0x5a, 0xb8, 0x13,
-	0xf5, 0x7c, 0x59, 0x22, 0x8d, 0xa4, 0x7b, 0x62, 0xf1, 0x2e, 0xfc, 0x5c,
-	0x39, 0xa7, 0xec, 0xdb, 0x73, 0xe5, 0x25, 0x39, 0x21, 0x75, 0x8e, 0xc3,
-	0xa5, 0x97, 0x61, 0xe3, 0x2e, 0x1b, 0xb4, 0x71, 0x63, 0xae, 0xdc, 0x12,
-	0x12, 0x9e, 0x89, 0x18, 0xe0, 0x83, 0xba, 0x9b, 0xe2, 0xdd, 0x4d, 0x68,
-	0x55, 0x67, 0xfb, 0x7f, 0xd4, 0x5d, 0x7d, 0x6c, 0x5b, 0xd7, 0x75, 0x3f,
-	0x7c, 0xa4, 0x3e, 0x4c, 0xcb, 0xd2, 0x93, 0x4c, 0xc9, 0xb4, 0x2d, 0xcb,
-	0x8f, 0xd2, 0x93, 0xa5, 0xc4, 0x4a, 0xc1, 0x79, 0xda, 0xaa, 0x01, 0x5a,
-	0xc7, 0x52, 0xf4, 0xc7, 0x82, 0x60, 0xa5, 0x65, 0x25, 0xf3, 0xd2, 0x2c,
-	0x51, 0x29, 0xdb, 0xc9, 0xfe, 0x18, 0xe0, 0x25, 0xd9, 0x9a, 0xfd, 0x51,
-	0xe4, 0x95, 0x94, 0x12, 0x63, 0x56, 0x4d, 0xc6, 0xe6, 0x84, 0x02, 0x0b,
-	0x36, 0x56, 0x92, 0x9d, 0x14, 0x50, 0xc0, 0x24, 0x6d, 0x87, 0x2c, 0x6d,
-	0x11, 0x55, 0x76, 0xda, 0x7f, 0x8d, 0x2d, 0xc0, 0xb2, 0x2e, 0x69, 0x14,
-	0x3b, 0xc8, 0x02, 0x2c, 0x58, 0xbb, 0x6e, 0x28, 0xf6, 0x4f, 0xc7, 0x9d,
-	0xdf, 0xfd, 0x20, 0x1f, 0xc9, 0x47, 0x7d, 0x24, 0x6e, 0x81, 0x09, 0x10,
-	0xc8, 0xf7, 0xde, 0x7d, 0xef, 0xdd, 0x7b, 0xee, 0xf9, 0xf8, 0x9d, 0x73,
-	0xcf, 0xb9, 0x94, 0xba, 0xe2, 0x35, 0x57, 0x6e, 0x49, 0x65, 0x7e, 0x65,
-	0xce, 0x89, 0x9c, 0x0f, 0x95, 0x43, 0x0b, 0x9a, 0x3a, 0x27, 0x6d, 0x99,
-	0x17, 0x33, 0xb0, 0x80, 0x73, 0x3d, 0x35, 0xf6, 0xaf, 0x95, 0xf9, 0xc0,
-	0x14, 0x31, 0x85, 0x69, 0x13, 0x7d, 0xde, 0x2b, 0xf4, 0x81, 0xf7, 0xba,
-	0x7c, 0x40, 0xe9, 0xbc, 0x56, 0xa5, 0xa3, 0x36, 0xc2, 0x6f, 0xf2, 0x9d,
-	0xfd, 0xe2, 0x9d, 0xdd, 0x4a, 0x67, 0xe9, 0xdc, 0xf7, 0x71, 0x63, 0xba,
-	0x08, 0x5f, 0x9b, 0xe9, 0x52, 0x87, 0xdf, 0xac, 0x4d, 0xe8, 0xf8, 0xb9,
-	0x3a, 0x3a, 0x56, 0xcb, 0x03, 0xfb, 0xe6, 0x65, 0x9d, 0x2d, 0x69, 0x26,
-	0xcf, 0x23, 0x9f, 0x5f, 0xe7, 0x65, 0x48, 0x9a, 0x95, 0xe5, 0xe7, 0x92,
-	0x3b, 0x27, 0xa3, 0x42, 0xb3, 0xe9, 0x32, 0xcd, 0xf6, 0xfc, 0x3f, 0xa0,
-	0xd9, 0x4d, 0x81, 0x79, 0x5f, 0x29, 0x22, 0xff, 0x6e, 0x58, 0xe4, 0x2e,
-	0xac, 0xd2, 0x88, 0xb2, 0xff, 0xee, 0x1a, 0x28, 0xd0, 0x12, 0xba, 0x34,
-	0x52, 0x58, 0xa7, 0x98, 0x8c, 0x43, 0x98, 0xa5, 0xd2, 0x77, 0xa2, 0x90,
-	0x3f, 0xf8, 0x24, 0xf0, 0x51, 0x10, 0xdf, 0x3b, 0xc9, 0x63, 0xfb, 0x97,
-	0x60, 0xd7, 0x06, 0x36, 0xf2, 0xe4, 0x36, 0x7c, 0x94, 0x8a, 0x8d, 0x04,
-	0x5e, 0x22, 0x27, 0x6e, 0x57, 0xf2, 0x5e, 0x66, 0xb3, 0x3f, 0x6c, 0x67,
-	0x3f, 0x92, 0x69, 0x5c, 0x79, 0xee, 0xd6, 0x7c, 0x14, 0x3c, 0x4f, 0xda,
-	0xc9, 0xd9, 0x6c, 0xe5, 0xb9, 0x4e, 0xf9, 0xb9, 0x61, 0x0f, 0x5d, 0x65,
-	0xd1, 0xcc, 0xa5, 0x7d, 0x75, 0xf9, 0x6a, 0x95, 0xf1, 0x48, 0x5f, 0x45,
-	0x8f, 0xe7, 0xc9, 0x4d, 0xf1, 0xa5, 0xcc, 0x3b, 0xab, 0xe4, 0xf0, 0xd4,
-	0xfa, 0x29, 0xfb, 0x5d, 0xf1, 0x19, 0xd0, 0xf8, 0x0f, 0x69, 0x75, 0x12,
-	0x7a, 0xae, 0x96, 0xd6, 0xef, 0xff, 0x9a, 0x68, 0x1d, 0xe9, 0xf8, 0xf5,
-	0xd2, 0x7a, 0x7f, 0x5d, 0x2c, 0xbc, 0x32, 0x1e, 0x0a, 0x75, 0x6f, 0x0b,
-	0xcb, 0xd7, 0xd2, 0x7a, 0x7f, 0xc3, 0x78, 0x6a, 0xe3, 0x5c, 0xcc, 0xea,
-	0x78, 0x6a, 0xbf, 0xc1, 0x32, 0x92, 0x65, 0x79, 0x69, 0xa8, 0xe3, 0xff,
-	0xce, 0x15, 0x6f, 0x75, 0xeb, 0x79, 0xc8, 0x1a, 0xf9, 0x4e, 0x0e, 0xe9,
-	0x77, 0x42, 0xae, 0x22, 0x8e, 0x43, 0xf0, 0x9f, 0xf0, 0x5e, 0xe4, 0x62,
-	0xd5, 0xe1, 0x2e, 0x7e, 0x2f, 0xcb, 0xff, 0x0b, 0xcf, 0x0b, 0x9b, 0x25,
-	0x63, 0x12, 0x68, 0x1f, 0xf2, 0x9d, 0x11, 0x6d, 0x65, 0x8e, 0x96, 0x8a,
-	0x51, 0x28, 0x3f, 0xa0, 0x51, 0x6c, 0xa2, 0xde, 0xfe, 0x6d, 0xcf, 0x6f,
-	0xd0, 0xf1, 0x88, 0x83, 0x3c, 0x3f, 0xe1, 0x2a, 0xbf, 0x0b, 0xfa, 0xf4,
-	0x3c, 0x63, 0x84, 0xfe, 0x32, 0x3e, 0xa8, 0x9e, 0xa3, 0x59, 0xe1, 0xdf,
-	0x69, 0x5d, 0xba, 0x2a, 0x73, 0x6b, 0xc5, 0x79, 0xe0, 0xb5, 0xb2, 0x2e,
-	0xad, 0xc1, 0xc3, 0x07, 0x3d, 0xf8, 0xc3, 0xb3, 0x9e, 0x55, 0xcf, 0xa1,
-	0x85, 0x9c, 0xfa, 0x84, 0xe7, 0x1c, 0x96, 0xeb, 0xd2, 0x9c, 0x4a, 0x5b,
-	0x79, 0x7f, 0x42, 0x8c, 0x6b, 0xea, 0xde, 0x38, 0xea, 0xef, 0xca, 0x35,
-	0x51, 0xb5, 0x75, 0x60, 0xb0, 0x0b, 0x5a, 0x1e, 0x75, 0xcd, 0x39, 0x68,
-	0xd1, 0xe7, 0x51, 0x07, 0xe6, 0xb6, 0x2d, 0xb8, 0xaf, 0x96, 0x16, 0x15,
-	0xbb, 0x32, 0xa7, 0xec, 0xca, 0xa2, 0x4b, 0xaf, 0xd7, 0xe3, 0xf7, 0x2e,
-	0x0f, 0xfc, 0xee, 0x55, 0x0b, 0x86, 0x3e, 0x3d, 0xc5, 0x98, 0xe4, 0x33,
-	0xc0, 0x24, 0x26, 0x6a, 0xb1, 0x24, 0x2e, 0xc1, 0xf5, 0x1c, 0x63, 0x93,
-	0x30, 0xf3, 0xca, 0x6b, 0x74, 0x8e, 0x31, 0xf7, 0x35, 0xba, 0x4b, 0xf9,
-	0x69, 0x90, 0x5f, 0x9d, 0x47, 0x8b, 0x5a, 0x06, 0x1f, 0x39, 0x0f, 0x45,
-	0x86, 0x63, 0xf4, 0x1a, 0x9d, 0x15, 0xf9, 0x3e, 0x58, 0xff, 0x43, 0x9e,
-	0xc4, 0xdd, 0xe2, 0xfd, 0x32, 0xae, 0x71, 0x27, 0xf2, 0x02, 0xb7, 0x5e,
-	0x9f, 0xa0, 0xea, 0x05, 0xb9, 0x1d, 0xde, 0xb9, 0xac, 0x64, 0x4a, 0x9c,
-	0xe3, 0xfb, 0x9f, 0x32, 0xea, 0xef, 0x8f, 0x19, 0x89, 0x62, 0xc2, 0x88,
-	0x2f, 0xa1, 0xdd, 0x53, 0xc6, 0x44, 0x11, 0xbe, 0xa4, 0xe6, 0x91, 0x48,
-	0x14, 0xf2, 0xb6, 0x46, 0x9b, 0xaf, 0x53, 0x2c, 0x52, 0x4d, 0xad, 0xc8,
-	0x16, 0xfa, 0x7d, 0xac, 0xaa, 0xdf, 0x9a, 0xbe, 0xf8, 0x8e, 0xd8, 0xcf,
-	0xcb, 0x4c, 0x53, 0x8d, 0x71, 0x83, 0x88, 0xbd, 0x0f, 0x3b, 0xb4, 0x11,
-	0xc6, 0x8d, 0xd4, 0x61, 0xdc, 0xc5, 0x4d, 0xfb, 0xfd, 0x69, 0x65, 0x5c,
-	0xd6, 0x7c, 0xfb, 0x6d, 0x81, 0x65, 0xb9, 0xdf, 0x55, 0x38, 0xb7, 0x86,
-	0xa7, 0xd0, 0x46, 0xc7, 0xc8, 0x75, 0x4c, 0xac, 0x5d, 0xc5, 0x74, 0x75,
-	0x3e, 0x45, 0x50, 0xc5, 0xb4, 0x71, 0x1d, 0xbe, 0xd6, 0x2a, 0xf7, 0x0f,
-	0x7e, 0x17, 0xe2, 0x3f, 0x6e, 0xbf, 0xcb, 0x1d, 0xf3, 0xf5, 0xaa, 0x0d,
-	0xed, 0xf7, 0xa8, 0x0d, 0x75, 0xcb, 0x59, 0xc0, 0x25, 0x67, 0x61, 0x17,
-	0x86, 0xeb, 0x65, 0xff, 0xa5, 0x8d, 0xf5, 0x07, 0xfc, 0x97, 0x20, 0xf9,
-	0x2f, 0xbb, 0xfd, 0x97, 0xda, 0x3a, 0x7f, 0xc8, 0x1c, 0x70, 0x9a, 0xf4,
-	0x65, 0x12, 0xf9, 0xf2, 0x1e, 0x01, 0x3c, 0xe6, 0x4a, 0x1d, 0xe6, 0x52,
-	0x5d, 0xcd, 0xa8, 0x57, 0x7f, 0xfb, 0xea, 0xfa, 0x0b, 0x1b, 0x16, 0x6b,
-	0x88, 0xef, 0xbc, 0xfc, 0xab, 0x3b, 0xd5, 0xbf, 0x5a, 0x5d, 0x86, 0x77,
-	0xf5, 0x8b, 0x18, 0xb8, 0x53, 0xd6, 0x63, 0x63, 0xb2, 0xbf, 0xd9, 0x6a,
-	0x5f, 0xc3, 0x7f, 0x89, 0x14, 0xed, 0xbc, 0xf5, 0xfa, 0xf6, 0xe2, 0x68,
-	0x3b, 0x6b, 0x6c, 0xef, 0x78, 0xa7, 0x8c, 0x8f, 0xcd, 0xa9, 0x3c, 0xf2,
-	0x6e, 0xe5, 0xf7, 0x6d, 0xc6, 0xeb, 0x38, 0x37, 0xa7, 0x62, 0x8a, 0x11,
-	0xab, 0x40, 0xe0, 0xf1, 0xc9, 0xd3, 0x4d, 0xb6, 0xa9, 0xd6, 0xb8, 0xb0,
-	0x8e, 0x05, 0x9e, 0xd7, 0xcf, 0x97, 0x35, 0x65, 0x9b, 0xcf, 0x99, 0x55,
-	0x37, 0x67, 0x92, 0xaf, 0xe0, 0x6f, 0x21, 0x3f, 0x7a, 0xa4, 0x26, 0x47,
-	0xfd, 0xd3, 0xd0, 0xa2, 0xdd, 0x23, 0x6f, 0x1b, 0x79, 0xd7, 0x8d, 0xfa,
-	0xb9, 0xee, 0xc2, 0xea, 0xb2, 0x6e, 0x63, 0x95, 0xd0, 0xef, 0x52, 0xe9,
-	0xe5, 0x28, 0xb0, 0x69, 0x6f, 0x1d, 0xaf, 0x69, 0xbc, 0x64, 0xba, 0xfa,
-	0xf9, 0xf8, 0xc6, 0xfd, 0xac, 0xb1, 0xbf, 0x7b, 0x3d, 0xec, 0x6f, 0x23,
-	0x5f, 0x42, 0xec, 0x9d, 0xe2, 0x3b, 0x2a, 0x74, 0x41, 0x1b, 0x2d, 0xe5,
-	0x91, 0x4b, 0xfe, 0x1b, 0xa8, 0x67, 0x65, 0x7d, 0xeb, 0xaa, 0xcf, 0xf3,
-	0x9e, 0xd3, 0xf2, 0x7a, 0x4b, 0x60, 0x1c, 0xeb, 0x83, 0xc8, 0x41, 0xe9,
-	0x62, 0x1d, 0x84, 0xf6, 0x83, 0xd6, 0x0d, 0xc4, 0x80, 0x55, 0x3c, 0x2a,
-	0xa1, 0xec, 0xcc, 0xd1, 0x2d, 0xac, 0xbb, 0x6c, 0x4f, 0x5f, 0x47, 0xac,
-	0x55, 0xc2, 0x9a, 0x10, 0xf2, 0x9e, 0x9d, 0x76, 0x6a, 0xbf, 0xbf, 0xa5,
-	0xc5, 0xbe, 0xd9, 0x29, 0xd7, 0xaa, 0x70, 0xad, 0x8d, 0xae, 0xe6, 0x91,
-	0x97, 0x8e, 0x6b, 0x0f, 0xf2, 0x35, 0x2f, 0x7d, 0xf5, 0xb6, 0xe2, 0x25,
-	0x60, 0x3a, 0x39, 0x47, 0x05, 0x92, 0x73, 0xb6, 0x4e, 0xf0, 0xa5, 0x4a,
-	0xf4, 0x4f, 0xd1, 0xdf, 0x14, 0xfe, 0x5f, 0x65, 0xae, 0xb6, 0xb7, 0x8e,
-	0x53, 0x9b, 0x03, 0x31, 0xb9, 0x61, 0x1c, 0xb1, 0xa3, 0x6b, 0xab, 0xeb,
-	0x38, 0xb5, 0x39, 0x10, 0x8f, 0x6f, 0x29, 0x8e, 0x18, 0xb1, 0xa6, 0x37,
-	0xac, 0x33, 0x70, 0xaf, 0xa9, 0xe8, 0xb5, 0xe4, 0x51, 0x51, 0x7b, 0xeb,
-	0xe6, 0x89, 0x3b, 0xb3, 0x9e, 0x0c, 0xde, 0xe8, 0xab, 0xd3, 0x61, 0x77,
-	0x60, 0x3d, 0xa0, 0x86, 0xb6, 0x41, 0xcf, 0x58, 0x96, 0xf7, 0xba, 0x31,
-	0x72, 0x04, 0x10, 0xc3, 0x2e, 0xd2, 0x99, 0x2b, 0xe0, 0x67, 0x83, 0x39,
-	0x6f, 0x80, 0x32, 0x21, 0xd4, 0x52, 0x89, 0xba, 0x28, 0xbd, 0xbe, 0x28,
-	0xea, 0xa3, 0xce, 0x88, 0xba, 0xcf, 0xc1, 0xf0, 0x6d, 0xb6, 0x91, 0x67,
-	0x8a, 0x6f, 0xd1, 0xd9, 0xa5, 0x20, 0xff, 0x57, 0xf0, 0x7c, 0x7d, 0xed,
-	0x67, 0x35, 0xbf, 0xdf, 0x16, 0xfc, 0xde, 0xbb, 0x21, 0xbf, 0x1f, 0x2f,
-	0xf3, 0x3b, 0x77, 0x28, 0x28, 0x6b, 0x2b, 0x53, 0x57, 0xda, 0xe9, 0xa8,
-	0x78, 0xee, 0x5b, 0xfc, 0x7d, 0x27, 0x1d, 0x35, 0xe5, 0xf7, 0xb3, 0x4b,
-	0xac, 0xfb, 0xb3, 0x6f, 0xd1, 0xb9, 0x2b, 0x8e, 0x2f, 0x21, 0xea, 0x32,
-	0xdc, 0x7b, 0x86, 0xe8, 0xfb, 0xd1, 0xce, 0x4b, 0x16, 0xea, 0xf5, 0x55,
-	0x41, 0xea, 0x2b, 0xba, 0x29, 0x62, 0x20, 0xde, 0xfa, 0x0a, 0xfc, 0x79,
-	0x5e, 0xd9, 0xc6, 0xc9, 0x0d, 0x62, 0x1f, 0xf5, 0xbc, 0xd9, 0xe9, 0x81,
-	0x91, 0xbf, 0xdb, 0x25, 0xd7, 0xb1, 0x36, 0x8a, 0x81, 0x54, 0xe5, 0x81,
-	0xb8, 0xd7, 0xf9, 0xd9, 0x1e, 0x4c, 0xaa, 0x75, 0xf7, 0x9f, 0x76, 0x49,
-	0x3b, 0x82, 0x9a, 0xc8, 0x55, 0xa6, 0xc3, 0x3f, 0x30, 0x7e, 0xd9, 0x4f,
-	0xcd, 0x97, 0xf5, 0x58, 0xf7, 0x0b, 0x7f, 0xc8, 0x1d, 0xcb, 0x99, 0x55,
-	0x35, 0xee, 0x69, 0xd7, 0x98, 0x66, 0x85, 0xdf, 0xf3, 0x49, 0xd6, 0x31,
-	0x7b, 0x6b, 0x6c, 0x45, 0x2d, 0xbf, 0x61, 0x3f, 0x16, 0xcc, 0x2f, 0x19,
-	0x12, 0x1b, 0x8f, 0x31, 0xe6, 0xdd, 0xee, 0x7a, 0xd2, 0xa7, 0xc5, 0x8d,
-	0xb5, 0x7b, 0x7d, 0xd4, 0x7e, 0xc7, 0x3c, 0x48, 0x3f, 0x24, 0xf5, 0x42,
-	0x51, 0xe8, 0x82, 0xd9, 0x91, 0x12, 0x4d, 0x44, 0x77, 0x51, 0x6a, 0x84,
-	0xdf, 0x3d, 0x66, 0xb3, 0x3f, 0xe6, 0x27, 0x87, 0xe5, 0x37, 0x35, 0xb2,
-	0x43, 0xd5, 0xcc, 0xe9, 0x58, 0x7b, 0x8b, 0xc2, 0x90, 0xed, 0x62, 0xdd,
-	0x52, 0xee, 0x49, 0xc4, 0xdf, 0x97, 0xf4, 0xb3, 0x71, 0x1e, 0xbc, 0xdb,
-	0xac, 0xda, 0x5d, 0x74, 0xb5, 0x43, 0x9b, 0x8b, 0xaa, 0x2d, 0x9e, 0xa9,
-	0xb1, 0x86, 0xae, 0xd3, 0x82, 0x1c, 0xae, 0xaa, 0xfa, 0x44, 0xf9, 0xbc,
-	0x99, 0xe2, 0x45, 0x6e, 0xd3, 0xa5, 0xae, 0x5f, 0x64, 0xfc, 0x5b, 0x14,
-	0x32, 0x22, 0xfb, 0xd2, 0x54, 0xee, 0x8b, 0xc4, 0xed, 0xb8, 0xa7, 0x5d,
-	0xe5, 0x62, 0xbe, 0x25, 0xd7, 0x05, 0x54, 0x1f, 0xe4, 0x75, 0xfe, 0x5c,
-	0xaa, 0xf6, 0x29, 0xdf, 0x28, 0xea, 0x75, 0x88, 0x8f, 0x7d, 0x33, 0xd9,
-	0x77, 0x7c, 0x32, 0xe7, 0xd8, 0x14, 0x6b, 0xa9, 0x32, 0x7f, 0x43, 0x7f,
-	0x47, 0xac, 0x19, 0x39, 0x16, 0xc8, 0x9f, 0x70, 0xeb, 0x16, 0x39, 0xb6,
-	0x00, 0x6c, 0x50, 0x11, 0x6b, 0xa8, 0x1b, 0xe1, 0xe7, 0xbd, 0xcc, 0x9b,
-	0xe6, 0x36, 0x70, 0xe8, 0x56, 0x64, 0xcd, 0xf2, 0x90, 0x35, 0xf7, 0xfb,
-	0x51, 0xcb, 0x87, 0x9a, 0x3e, 0x67, 0xd8, 0xa0, 0x12, 0xfb, 0x0a, 0x06,
-	0x15, 0x4c, 0x1f, 0x9d, 0xb3, 0x23, 0xd1, 0x25, 0x81, 0x37, 0xef, 0x43,
-	0xce, 0xcf, 0xf0, 0x2a, 0x1d, 0x36, 0xcf, 0x92, 0xdc, 0xef, 0xa1, 0xc0,
-	0xb6, 0x77, 0x9a, 0xf9, 0xed, 0x2c, 0xfb, 0x1f, 0xce, 0x14, 0xd6, 0x5d,
-	0x34, 0xcd, 0xb0, 0x0f, 0x00, 0x3e, 0x2d, 0x9e, 0xa7, 0xe2, 0x6e, 0x0a,
-	0xc6, 0xf8, 0x99, 0x16, 0x74, 0x11, 0x3f, 0x27, 0x49, 0x71, 0xf6, 0x93,
-	0xe0, 0xb3, 0x4e, 0x4f, 0x45, 0xcc, 0x02, 0x19, 0xdc, 0x16, 0xbe, 0x2b,
-	0x9e, 0x83, 0xfb, 0x63, 0x66, 0x13, 0xd5, 0xd6, 0x1c, 0xb7, 0x8b, 0x3a,
-	0xcc, 0x9b, 0xd1, 0x7b, 0xc8, 0xe8, 0x81, 0x6e, 0xc2, 0x9c, 0xdd, 0xad,
-	0xd6, 0x8b, 0x3a, 0xf8, 0xfb, 0x90, 0xfa, 0x2e, 0xe7, 0x5a, 0x7e, 0xd7,
-	0xbc, 0x8c, 0xbf, 0x0f, 0x5b, 0xc8, 0xfe, 0x5d, 0x35, 0x7f, 0xd5, 0xeb,
-	0x66, 0xfd, 0x46, 0x90, 0xce, 0x7b, 0xae, 0x9b, 0x6d, 0x54, 0xcb, 0xdb,
-	0xb1, 0xc5, 0x5a, 0xde, 0x9f, 0xef, 0x96, 0xf5, 0x71, 0xee, 0xbe, 0xfc,
-	0x9c, 0xfb, 0xe2, 0x15, 0x0f, 0x71, 0xeb, 0x5e, 0xad, 0x73, 0x4b, 0xf4,
-	0x6f, 0xd1, 0xcf, 0xd2, 0x7a, 0x28, 0xac, 0xf2, 0x99, 0x90, 0xbf, 0x74,
-	0x8f, 0xe2, 0x55, 0xad, 0xe7, 0xc9, 0x43, 0xcf, 0x3f, 0x20, 0xf2, 0x8e,
-	0xa5, 0x9d, 0xd8, 0xaf, 0xe8, 0x01, 0x9a, 0x85, 0x5d, 0x34, 0xeb, 0x76,
-	0xd1, 0xcc, 0x50, 0xdf, 0x77, 0x89, 0xe3, 0xf3, 0x4b, 0xaf, 0x76, 0xc8,
-	0x7a, 0x78, 0xac, 0x29, 0x7e, 0x5f, 0x7d, 0xdf, 0x6c, 0xbc, 0x0f, 0x84,
-	0x28, 0x28, 0xe2, 0x4d, 0xae, 0xb1, 0xbe, 0x44, 0x64, 0xb3, 0x37, 0x5c,
-	0x47, 0x83, 0x6f, 0xb9, 0xce, 0xa3, 0x8f, 0x83, 0xae, 0x3e, 0xf6, 0xbb,
-	0xfa, 0x78, 0xb0, 0x41, 0x1f, 0x59, 0x9f, 0xf3, 0x7b, 0xce, 0x16, 0x3f,
-	0x69, 0x5f, 0xd1, 0x4f, 0xd4, 0x49, 0x83, 0x9e, 0x3b, 0x29, 0x1d, 0x0a,
-	0x2b, 0x3b, 0x11, 0x55, 0xf5, 0x03, 0x5e, 0x7d, 0xfe, 0x31, 0x35, 0x9e,
-	0x37, 0x37, 0xaf, 0xba, 0xeb, 0xab, 0x9f, 0xa3, 0x09, 0x59, 0x27, 0xaf,
-	0x64, 0xfb, 0x62, 0x83, 0x78, 0x34, 0x72, 0x3b, 0x80, 0x37, 0x84, 0x6f,
-	0xb8, 0x4f, 0xee, 0x6f, 0x17, 0xa0, 0xe5, 0x72, 0xad, 0xb2, 0x5f, 0xd5,
-	0xf0, 0x3d, 0x1b, 0xba, 0xb3, 0x75, 0xca, 0x38, 0xff, 0x3d, 0x11, 0xcb,
-	0x93, 0xeb, 0x48, 0xab, 0xaa, 0xde, 0x3a, 0x62, 0x21, 0x47, 0x60, 0x71,
-	0x05, 0x71, 0xd8, 0x46, 0xb5, 0xc9, 0x52, 0x17, 0xa5, 0xca, 0x7b, 0xc2,
-	0x14, 0x44, 0x1d, 0x86, 0x8c, 0x8f, 0xc9, 0x1a, 0xe2, 0xc5, 0x95, 0x1b,
-	0xa2, 0x6e, 0x37, 0xae, 0x6a, 0x91, 0x53, 0xd4, 0x26, 0x70, 0xed, 0x27,
-	0xaf, 0x21, 0xfe, 0x71, 0x68, 0xfb, 0x35, 0xc4, 0xee, 0x7b, 0xb6, 0x57,
-	0x43, 0x6c, 0xf2, 0xd8, 0x8d, 0x05, 0x59, 0x43, 0x5c, 0xbd, 0x46, 0x23,
-	0x6b, 0x88, 0x53, 0x2e, 0xac, 0x20, 0xf1, 0xf9, 0x4d, 0x57, 0x7e, 0xb7,
-	0xac, 0x0f, 0x5e, 0x2c, 0xe3, 0x53, 0x59, 0x1f, 0x2c, 0xf3, 0xc1, 0xdd,
-	0x7b, 0xdf, 0xc8, 0xb5, 0x20, 0xf9, 0x9e, 0x5d, 0x35, 0x6b, 0x41, 0xb2,
-	0x2e, 0xd8, 0x32, 0xbc, 0xf8, 0x4e, 0xdb, 0x25, 0xec, 0xf7, 0x10, 0x63,
-	0xde, 0xdd, 0xd9, 0x60, 0xbf, 0x87, 0x58, 0x83, 0xfd, 0x1e, 0xdc, 0xba,
-	0xdf, 0x8d, 0xa7, 0x80, 0x7f, 0x61, 0x17, 0x81, 0x7b, 0xb1, 0x5f, 0x43,
-	0x94, 0xce, 0x97, 0x71, 0xe6, 0x3d, 0x94, 0x54, 0x38, 0xf3, 0xfc, 0x92,
-	0xd6, 0x47, 0xfd, 0x35, 0xfa, 0xc8, 0x0b, 0x77, 0x46, 0x54, 0xce, 0x8f,
-	0x96, 0x57, 0xc7, 0x25, 0xaf, 0x8e, 0x87, 0xbc, 0xe2, 0x1e, 0xa7, 0x41,
-	0xbf, 0x41, 0x13, 0xdc, 0x83, 0xff, 0x97, 0xc2, 0xd8, 0xa7, 0x86, 0xe8,
-	0x0b, 0xdd, 0x0a, 0xeb, 0xb9, 0xe4, 0xf5, 0x2c, 0xcb, 0xab, 0x3e, 0x8f,
-	0xfe, 0x36, 0xc2, 0xfb, 0x1a, 0x1f, 0xee, 0xf7, 0x1d, 0xbb, 0xf2, 0x0b,
-	0x91, 0x17, 0x50, 0xed, 0x27, 0x6a, 0x0c, 0x71, 0x48, 0xc8, 0xd2, 0xba,
-	0x1f, 0xf9, 0x2b, 0xfa, 0x1c, 0x6a, 0xa7, 0x20, 0x7f, 0x9a, 0x16, 0xcd,
-	0x35, 0x38, 0xa3, 0x5d, 0xe1, 0x08, 0x91, 0xff, 0xeb, 0xea, 0xdb, 0x7f,
-	0x72, 0xdf, 0xf4, 0x79, 0x6d, 0x33, 0xdf, 0xae, 0x8a, 0x69, 0x54, 0xe7,
-	0x4d, 0x22, 0x7e, 0xb4, 0x2b, 0x69, 0xd8, 0x09, 0x91, 0x7f, 0xda, 0x69,
-	0x23, 0x56, 0x16, 0x67, 0xd9, 0xef, 0x4c, 0x22, 0xd7, 0xb9, 0xf3, 0x92,
-	0x45, 0xa7, 0xb2, 0x57, 0x0f, 0x48, 0x5e, 0x79, 0x5a, 0xec, 0xd3, 0x89,
-	0x7d, 0x1d, 0x27, 0xd8, 0x3e, 0xc7, 0x19, 0x60, 0xce, 0x15, 0x5b, 0x68,
-	0x91, 0x91, 0xbc, 0xdf, 0x2e, 0x88, 0x58, 0x1f, 0xeb, 0xa4, 0x1c, 0xf6,
-	0x6b, 0x35, 0x16, 0x9a, 0xf9, 0xb9, 0x3d, 0xb4, 0x9c, 0x07, 0xcf, 0x35,
-	0xa9, 0xfd, 0x53, 0xd0, 0xd6, 0x47, 0x5d, 0xf6, 0xdf, 0x32, 0xed, 0x1e,
-	0x11, 0x79, 0x97, 0x8b, 0xb9, 0xa7, 0xe5, 0x67, 0xe1, 0x55, 0xf5, 0x0e,
-	0x7e, 0x5f, 0xf1, 0x75, 0x8a, 0x75, 0xb9, 0xf3, 0x00, 0xdd, 0x7f, 0xde,
-	0x78, 0xe5, 0xe4, 0xb6, 0xf0, 0x8a, 0x93, 0xac, 0xe0, 0x15, 0xf7, 0xb3,
-	0x35, 0x76, 0xf9, 0xe3, 0x1e, 0xb9, 0x9f, 0x05, 0x68, 0xb0, 0x13, 0x58,
-	0x2c, 0x09, 0x5a, 0x1a, 0xe3, 0x91, 0x70, 0xdc, 0x3f, 0x46, 0x99, 0xe2,
-	0x35, 0x4a, 0xe5, 0x60, 0xe7, 0xf9, 0xb3, 0xf0, 0x37, 0x7b, 0x64, 0x9c,
-	0x46, 0xdf, 0x03, 0xbd, 0xb2, 0x9b, 0xdb, 0x37, 0xef, 0x91, 0x39, 0xdb,
-	0xee, 0xf3, 0xed, 0x7c, 0xfe, 0xc9, 0x70, 0xf5, 0xf9, 0x1d, 0x7c, 0xbe,
-	0x2b, 0x89, 0x39, 0x34, 0x2e, 0x21, 0x36, 0x39, 0x4c, 0x69, 0x9e, 0x9f,
-	0x4c, 0x91, 0x6d, 0xeb, 0x65, 0xd6, 0x57, 0x4b, 0xba, 0x5d, 0x37, 0xb7,
-	0x0b, 0x89, 0x39, 0x31, 0xb8, 0xcd, 0x6c, 0x76, 0x84, 0xdb, 0xed, 0x27,
-	0xff, 0x65, 0x8b, 0x32, 0x4b, 0x9a, 0x57, 0x75, 0x2e, 0xfe, 0x2f, 0xba,
-	0x65, 0x6e, 0xd5, 0xae, 0xb0, 0xa4, 0xdf, 0xb0, 0x88, 0x7b, 0x22, 0xb7,
-	0xe3, 0x19, 0xc1, 0x87, 0x91, 0x31, 0xab, 0xfc, 0x7e, 0xec, 0x31, 0x26,
-	0xf6, 0x7c, 0xe5, 0x31, 0xb0, 0x5e, 0x1c, 0xb7, 0xcd, 0x74, 0x39, 0x6f,
-	0x6d, 0x6d, 0x9f, 0xbc, 0x7f, 0x67, 0x8f, 0xdc, 0x7f, 0xb5, 0x53, 0xed,
-	0x15, 0xa8, 0x6d, 0xce, 0x17, 0x90, 0xa7, 0x2d, 0x68, 0xe3, 0x5f, 0x80,
-	0xbe, 0x34, 0xf8, 0x3b, 0x8f, 0x27, 0x89, 0x3e, 0xf6, 0xf6, 0xe8, 0x3d,
-	0x17, 0xe5, 0xb8, 0x4e, 0x70, 0x7f, 0x13, 0x3c, 0x2e, 0x7d, 0x3e, 0xc6,
-	0xc7, 0x5e, 0xf3, 0x8b, 0x67, 0x05, 0xf9, 0x39, 0x2c, 0x03, 0x53, 0xc1,
-	0x64, 0x6a, 0x58, 0xce, 0x73, 0x25, 0xae, 0x1b, 0x2e, 0xc7, 0x75, 0xe7,
-	0xb2, 0xc7, 0x7b, 0x10, 0xcf, 0x30, 0x2e, 0xf1, 0x7c, 0x87, 0x9e, 0xe1,
-	0xb6, 0xa8, 0x63, 0x48, 0xf3, 0x67, 0x9b, 0xca, 0xef, 0xa9, 0xe7, 0x15,
-	0x99, 0x2f, 0xa1, 0xed, 0x16, 0xee, 0xbd, 0x97, 0x9f, 0x21, 0x6d, 0x57,
-	0xe3, 0xf7, 0x50, 0x5d, 0x4e, 0x4c, 0x3d, 0x8f, 0x6d, 0x14, 0x8b, 0x15,
-	0xeb, 0x8a, 0x1e, 0x7c, 0xb6, 0x51, 0xac, 0x44, 0xe4, 0x39, 0xfb, 0x26,
-	0xea, 0xe4, 0x15, 0x72, 0x1c, 0xa0, 0x27, 0xe6, 0x1d, 0xda, 0xc1, 0x73,
-	0xf5, 0x27, 0x06, 0xea, 0x86, 0x4b, 0x24, 0x73, 0x9f, 0x98, 0xc6, 0x59,
-	0x7b, 0xf8, 0xac, 0xc1, 0x74, 0xce, 0x3a, 0xa5, 0x80, 0xdd, 0x46, 0xcd,
-	0x2c, 0xab, 0xbf, 0x4f, 0x03, 0xec, 0xeb, 0x41, 0x66, 0xed, 0x70, 0x82,
-	0x20, 0x6f, 0x11, 0xf3, 0x18, 0xf3, 0xc4, 0x44, 0x11, 0xfc, 0x6c, 0xd0,
-	0x63, 0x79, 0xa2, 0x47, 0xf3, 0x03, 0xe6, 0x37, 0xc9, 0xb6, 0x2a, 0xd7,
-	0x23, 0x66, 0x9c, 0xfb, 0x91, 0x28, 0xfe, 0x25, 0x7d, 0x24, 0xf6, 0x71,
-	0x01, 0x1d, 0xf5, 0xbc, 0xff, 0x39, 0x4d, 0x27, 0xd1, 0xef, 0xad, 0xcb,
-	0xe7, 0xa9, 0x6d, 0xc9, 0x67, 0xd0, 0x43, 0x3e, 0x3f, 0x54, 0x7c, 0x53,
-	0x62, 0x1e, 0x0d, 0xd2, 0x4c, 0x0e, 0xb9, 0x60, 0x9f, 0x47, 0x0d, 0x66,
-	0x2e, 0xc5, 0x7a, 0x29, 0x55, 0xd1, 0x4b, 0x17, 0xe2, 0xfe, 0x18, 0x64,
-	0x1c, 0x7b, 0xd1, 0xa9, 0x1c, 0x20, 0x8c, 0x63, 0x1f, 0x0d, 0x2c, 0xec,
-	0xe4, 0x7b, 0x69, 0x35, 0x3e, 0x1a, 0x53, 0x7b, 0x15, 0x44, 0xac, 0x09,
-	0xd6, 0x8f, 0x73, 0x2c, 0xcb, 0xe9, 0xdc, 0xdd, 0xb4, 0x18, 0xea, 0xa5,
-	0xfe, 0x05, 0xbd, 0x7f, 0x0b, 0xc6, 0x3a, 0xd4, 0x2b, 0x75, 0x92, 0x1e,
-	0xf7, 0x6f, 0x89, 0x38, 0x85, 0x75, 0xed, 0x57, 0x35, 0xee, 0x9d, 0x9b,
-	0xe8, 0xa5, 0x92, 0x92, 0xd9, 0xd2, 0x1b, 0xf1, 0x28, 0x39, 0xf1, 0xd1,
-	0xff, 0x15, 0xfc, 0xdf, 0x7f, 0x0d, 0xb5, 0x38, 0xd0, 0xd1, 0x16, 0x25,
-	0xb3, 0xb5, 0xb4, 0xe8, 0xe5, 0x71, 0xe3, 0x7a, 0xe9, 0xa7, 0x33, 0xd1,
-	0x57, 0x85, 0xed, 0x1f, 0xb8, 0xc6, 0xed, 0x84, 0x6d, 0xd2, 0x7a, 0xc3,
-	0x8b, 0x0f, 0xf5, 0xde, 0x9c, 0x9a, 0x17, 0x65, 0xce, 0x27, 0xe3, 0x37,
-	0x33, 0xe9, 0xaf, 0xe5, 0xc9, 0x8f, 0xe9, 0xe4, 0xbc, 0x45, 0x93, 0x59,
-	0xec, 0x81, 0x38, 0xc6, 0x72, 0xed, 0xb6, 0x17, 0xdc, 0x9e, 0xc0, 0x67,
-	0xe3, 0x2c, 0xfb, 0xec, 0xb7, 0xe7, 0x2c, 0x99, 0x7f, 0x27, 0xf6, 0xdb,
-	0x6b, 0x11, 0x7a, 0xd4, 0xb4, 0xfb, 0xf7, 0x68, 0x7b, 0x90, 0xca, 0xa1,
-	0xce, 0x90, 0x3f, 0x0b, 0xdc, 0x3e, 0xdb, 0x43, 0xa9, 0x3c, 0x9e, 0x03,
-	0x7b, 0x87, 0xbe, 0xf3, 0xf1, 0xb2, 0x9c, 0xd7, 0x7e, 0x7e, 0x36, 0xf6,
-	0x0e, 0x98, 0x2c, 0x8e, 0x88, 0x1c, 0x3c, 0xe8, 0x66, 0x39, 0x9f, 0xe3,
-	0x34, 0xeb, 0xa9, 0x57, 0x14, 0xa6, 0x74, 0xc9, 0x77, 0x4a, 0xc8, 0xf7,
-	0xb8, 0x98, 0x8f, 0x54, 0xde, 0x60, 0xbc, 0xa6, 0xe3, 0x0c, 0x5d, 0x7c,
-	0x1c, 0x50, 0x3a, 0x04, 0xd7, 0xee, 0xdd, 0x23, 0xf2, 0x13, 0x6d, 0x9c,
-	0xc7, 0xe7, 0x38, 0x3d, 0xc3, 0xb8, 0xf3, 0xd9, 0x6c, 0x0b, 0xdd, 0xc8,
-	0xb5, 0xd0, 0x9b, 0xb9, 0x5e, 0xba, 0x3e, 0xdf, 0x41, 0xb3, 0x8c, 0x99,
-	0x67, 0xed, 0x80, 0x95, 0x66, 0xff, 0xe2, 0x6a, 0x54, 0xe4, 0x10, 0xb1,
-	0xdc, 0xa1, 0x3d, 0xf0, 0x5f, 0x7c, 0x2f, 0xf3, 0x1c, 0x63, 0xef, 0x56,
-	0xfa, 0x80, 0xdf, 0x99, 0xce, 0xea, 0x9c, 0x07, 0xc4, 0xe3, 0x07, 0xcb,
-	0xf8, 0x75, 0x73, 0x1e, 0x31, 0x37, 0xe1, 0x91, 0x71, 0xa1, 0xeb, 0x33,
-	0xf3, 0x7c, 0x7d, 0x1e, 0x71, 0x73, 0x4b, 0xc4, 0x24, 0xbe, 0x14, 0x40,
-	0x7b, 0x9c, 0xb3, 0x65, 0xce, 0xa4, 0x18, 0x5b, 0x98, 0x8f, 0x41, 0xdb,
-	0xb0, 0xa2, 0x43, 0x2b, 0x8f, 0x4f, 0xc6, 0x30, 0x52, 0xcb, 0xad, 0x74,
-	0x26, 0xcf, 0x18, 0x24, 0xef, 0x67, 0x1f, 0x06, 0x6d, 0x7f, 0xe7, 0xa0,
-	0xde, 0xd3, 0x76, 0x96, 0xfb, 0x9e, 0xce, 0x4b, 0x0c, 0x92, 0x5e, 0x6e,
-	0xa7, 0x4c, 0xbe, 0x4d, 0x1d, 0xdf, 0x2d, 0xf2, 0xdd, 0xe5, 0xde, 0x12,
-	0xb8, 0xb6, 0x91, 0x7e, 0x43, 0xae, 0x11, 0x6c, 0xaa, 0xf4, 0x4b, 0xa1,
-	0x6b, 0xbc, 0xf3, 0x8c, 0xc6, 0xe8, 0x39, 0xb6, 0xb7, 0xfd, 0x97, 0x11,
-	0x2b, 0xfe, 0x22, 0xf8, 0xa6, 0x00, 0x1e, 0xeb, 0xbf, 0x8c, 0x7d, 0x9f,
-	0xfc, 0x22, 0xf7, 0x68, 0x22, 0x34, 0x2c, 0x6a, 0x46, 0xa4, 0x8c, 0x4e,
-	0x89, 0xba, 0xec, 0xef, 0x08, 0xdd, 0x14, 0x71, 0x2c, 0x03, 0x78, 0x24,
-	0x12, 0x26, 0x92, 0x39, 0x59, 0xa7, 0xec, 0xce, 0x9b, 0xdd, 0xe3, 0x43,
-	0x14, 0xeb, 0x01, 0xdf, 0x4b, 0x99, 0x95, 0x7b, 0x22, 0x90, 0xd0, 0xf7,
-	0xe6, 0x21, 0x5d, 0x63, 0xa0, 0x8f, 0xb5, 0xad, 0xd0, 0xc7, 0x6d, 0x35,
-	0xd7, 0xcd, 0x9a, 0xeb, 0x1a, 0x7f, 0x63, 0xad, 0x8c, 0xed, 0x3c, 0xc9,
-	0x3d, 0x98, 0x52, 0x0b, 0x92, 0xff, 0xcc, 0x43, 0x83, 0xe6, 0xfd, 0x0a,
-	0x83, 0xa7, 0x56, 0x06, 0xc2, 0x9d, 0x46, 0x9b, 0x3f, 0x35, 0xf2, 0xaf,
-	0xa5, 0x58, 0x12, 0xb8, 0xe8, 0xf5, 0x3d, 0x52, 0xc7, 0xa1, 0x5f, 0x4e,
-	0x14, 0xd0, 0x6d, 0x6a, 0xa5, 0x8d, 0x56, 0xc5, 0x9e, 0x63, 0xc0, 0x18,
-	0xb8, 0x1f, 0xcf, 0x71, 0xcc, 0x26, 0xc2, 0x3e, 0xf2, 0x90, 0xf1, 0xc3,
-	0xe1, 0x6b, 0x3c, 0x9f, 0x89, 0x95, 0xff, 0x29, 0x4d, 0x8b, 0x7d, 0x7a,
-	0xd0, 0x96, 0x31, 0xa4, 0xc0, 0xfc, 0x8c, 0x5f, 0xaa, 0xfc, 0xaa, 0x31,
-	0xf4, 0xd3, 0xc1, 0x9a, 0x8a, 0x61, 0xbf, 0xc0, 0x32, 0x26, 0xd7, 0xca,
-	0x13, 0x35, 0x6b, 0xe5, 0x53, 0x62, 0xad, 0x1c, 0xeb, 0xe4, 0x1b, 0xe5,
-	0x2d, 0xea, 0x3c, 0x16, 0x8b, 0x66, 0xaf, 0x08, 0x7d, 0x13, 0x9d, 0xf0,
-	0xcb, 0x3c, 0xeb, 0x04, 0xbb, 0x37, 0x86, 0xa8, 0x6d, 0xc0, 0x67, 0xcc,
-	0x88, 0xdb, 0x91, 0xe1, 0x35, 0xc6, 0x14, 0x4b, 0xb9, 0x1d, 0x74, 0xbd,
-	0xd0, 0xc4, 0x98, 0xef, 0x9f, 0x69, 0xad, 0x40, 0x8c, 0x0d, 0x3b, 0x28,
-	0x13, 0x65, 0x5e, 0x1b, 0x0e, 0xf2, 0xbc, 0x32, 0xbe, 0x1d, 0x66, 0xf9,
-	0xe3, 0x31, 0x2c, 0xe5, 0x4b, 0xef, 0xa7, 0xa3, 0x31, 0x2b, 0x3e, 0xda,
-	0xc6, 0xfe, 0x8b, 0xc9, 0xff, 0x36, 0xff, 0x9f, 0x0b, 0x83, 0x36, 0x8b,
-	0xcb, 0xb8, 0xce, 0xd8, 0x27, 0x5b, 0x7a, 0x7f, 0x86, 0xdb, 0xcc, 0x8c,
-	0xc2, 0x0f, 0x82, 0xbf, 0x67, 0xf3, 0xbf, 0x6c, 0xb3, 0xc4, 0x7c, 0x97,
-	0xbe, 0xe2, 0x84, 0x0d, 0xa1, 0xe3, 0xb1, 0x2f, 0xcd, 0x80, 0xfa, 0x8c,
-	0x19, 0x33, 0xdc, 0x97, 0xeb, 0x84, 0x67, 0x58, 0x94, 0x8a, 0x1e, 0x62,
-	0x39, 0xe8, 0xe0, 0x4f, 0xd4, 0x6a, 0xed, 0xa4, 0xcc, 0xc8, 0xa0, 0xaa,
-	0xd5, 0xfa, 0x59, 0x83, 0x5a, 0x2d, 0xdc, 0xc7, 0x38, 0x60, 0xbe, 0x74,
-	0x7b, 0x26, 0xea, 0x7e, 0x2f, 0x19, 0xa9, 0xe8, 0x2e, 0x81, 0x99, 0x96,
-	0x96, 0x1f, 0xe6, 0x3e, 0xc4, 0xac, 0xd4, 0x28, 0xf7, 0x35, 0xef, 0xee,
-	0x7f, 0xe9, 0xf6, 0x44, 0x14, 0xed, 0xfc, 0x35, 0xed, 0x62, 0x24, 0xda,
-	0x2e, 0xa3, 0x7d, 0xe9, 0x97, 0xf1, 0xa8, 0x1e, 0xa7, 0xfb, 0x5e, 0x8c,
-	0x07, 0xf2, 0xc5, 0x9f, 0x4b, 0xef, 0xd0, 0xf5, 0x1c, 0xfc, 0x71, 0x43,
-	0xd5, 0x5f, 0x59, 0xe4, 0x2c, 0x31, 0x06, 0xbc, 0x72, 0xd0, 0xb7, 0x96,
-	0xfb, 0x41, 0x29, 0x55, 0x95, 0xdb, 0x52, 0x1d, 0x73, 0x97, 0x3e, 0x58,
-	0x2f, 0xd9, 0x97, 0x60, 0x43, 0x61, 0x3f, 0x9d, 0x92, 0xdf, 0x06, 0xde,
-	0x83, 0x6f, 0xf4, 0x34, 0xeb, 0x2f, 0x99, 0x9f, 0xc4, 0xba, 0x94, 0x75,
-	0x98, 0x94, 0x9f, 0x44, 0xd5, 0x4f, 0x3c, 0x48, 0x1e, 0xee, 0xaf, 0xe4,
-	0x49, 0xba, 0xd6, 0xd8, 0x03, 0xae, 0x35, 0x76, 0xd3, 0x95, 0x27, 0x19,
-	0x12, 0xf8, 0xac, 0x82, 0xa9, 0x42, 0x0a, 0x53, 0x01, 0x7b, 0x49, 0xdd,
-	0xb6, 0x58, 0xd6, 0x6d, 0xbb, 0x37, 0xd1, 0x6d, 0x5e, 0xbe, 0xea, 0xaa,
-	0xd2, 0x23, 0x91, 0x28, 0x6c, 0x0c, 0xf6, 0x59, 0xfa, 0xfb, 0xe2, 0x28,
-	0xeb, 0x91, 0x28, 0xeb, 0x91, 0x11, 0xd6, 0x23, 0xc3, 0xac, 0x47, 0x6c,
-	0xa6, 0x81, 0xc5, 0x63, 0xff, 0x98, 0xf5, 0x34, 0xec, 0xc7, 0x18, 0x3d,
-	0x53, 0x84, 0x4e, 0x1e, 0x61, 0x0c, 0xf4, 0x31, 0xad, 0xcd, 0xb7, 0x33,
-	0xff, 0x4a, 0xdc, 0x53, 0xed, 0xd7, 0x60, 0xdf, 0x18, 0xc4, 0x86, 0x7f,
-	0x08, 0xbd, 0xf3, 0xb2, 0x43, 0x7d, 0xbe, 0xeb, 0x39, 0xd0, 0x79, 0x0d,
-	0x7b, 0x6b, 0xbc, 0x08, 0xd9, 0xc6, 0xbe, 0xc7, 0xdf, 0x1e, 0x1a, 0xe3,
-	0xbe, 0xf7, 0xf9, 0x32, 0x3c, 0x2f, 0x8f, 0x47, 0x1d, 0xb3, 0x8b, 0x65,
-	0x60, 0x52, 0xc9, 0xc0, 0x64, 0x45, 0x06, 0x9c, 0x34, 0x8f, 0xa4, 0x73,
-	0xa1, 0x83, 0x06, 0x8f, 0xc4, 0xf7, 0x76, 0xb2, 0xfc, 0x22, 0x67, 0xa2,
-	0xb2, 0xff, 0x90, 0x9f, 0xa6, 0x43, 0x41, 0xb5, 0x6f, 0x91, 0xc5, 0x76,
-	0xf3, 0x27, 0x94, 0xc9, 0xbd, 0xcb, 0xb8, 0x84, 0xe5, 0xd4, 0xc4, 0xf1,
-	0x45, 0xc4, 0x45, 0xd9, 0x6f, 0x68, 0x15, 0x71, 0xa5, 0x45, 0xd1, 0x16,
-	0xc7, 0x91, 0x61, 0xd6, 0x71, 0xd1, 0x55, 0x23, 0x32, 0x16, 0x33, 0x2e,
-	0xf7, 0x62, 0x5f, 0xfa, 0x6f, 0x17, 0x1f, 0xeb, 0x95, 0xf5, 0xb9, 0x4f,
-	0xed, 0x95, 0xfa, 0x84, 0x79, 0x34, 0x14, 0x13, 0xbe, 0x5b, 0xd3, 0x25,
-	0x69, 0x3f, 0x17, 0x79, 0xbe, 0x97, 0xa2, 0xc3, 0x3c, 0xdf, 0x6d, 0xca,
-	0x76, 0x3a, 0x7c, 0x5d, 0xd8, 0x65, 0xb6, 0xa1, 0xbd, 0xd8, 0xd3, 0xdf,
-	0x8c, 0x47, 0x9f, 0xe2, 0x77, 0x62, 0x1f, 0xa1, 0x2f, 0xe3, 0x79, 0xcc,
-	0xbd, 0xd0, 0x1f, 0x3f, 0x61, 0x1b, 0x8d, 0xf7, 0x82, 0x1f, 0xf9, 0x7b,
-	0x61, 0x8c, 0x2e, 0x64, 0x75, 0x1f, 0xde, 0x23, 0xe3, 0x39, 0xf4, 0xc3,
-	0x47, 0xbb, 0xed, 0xf7, 0x44, 0x4d, 0x88, 0xf1, 0x8d, 0xda, 0x3e, 0x7d,
-	0x45, 0xf5, 0x09, 0x7b, 0x79, 0xb6, 0xf0, 0x18, 0x76, 0x13, 0xf6, 0x74,
-	0x5a, 0x14, 0x7b, 0x6d, 0x36, 0x0b, 0x9f, 0x75, 0x51, 0xf8, 0x1e, 0x0f,
-	0xef, 0xad, 0xec, 0xff, 0x79, 0x57, 0xcd, 0xb9, 0x75, 0xb6, 0x5b, 0x47,
-	0x05, 0x46, 0xeb, 0xc7, 0x1e, 0xf4, 0xa2, 0x66, 0xf5, 0x4f, 0xc5, 0x35,
-	0x63, 0x01, 0xd7, 0x3e, 0xa7, 0xae, 0x7d, 0x56, 0x60, 0x63, 0x63, 0xbc,
-	0x95, 0xf5, 0xa2, 0xe0, 0x77, 0x9e, 0x67, 0x7b, 0x98, 0xf9, 0x3d, 0xbc,
-	0xc4, 0xcf, 0x9d, 0x16, 0xf4, 0xd4, 0xf4, 0x00, 0x2d, 0x20, 0x03, 0x6d,
-	0x8a, 0xff, 0x23, 0x56, 0xc2, 0xaf, 0xc7, 0xdd, 0x88, 0xce, 0x63, 0xb0,
-	0xcf, 0x3c, 0x56, 0x8c, 0xc9, 0xf2, 0xc5, 0x0a, 0x61, 0x5f, 0x7a, 0x1e,
-	0xbe, 0x0e, 0xea, 0x5e, 0x0e, 0x20, 0x9f, 0x8a, 0xfb, 0xb0, 0x87, 0x62,
-	0x49, 0xf4, 0x0b, 0xed, 0x34, 0x0d, 0xfe, 0xa8, 0x86, 0x16, 0xee, 0xfb,
-	0x3a, 0xd4, 0x7d, 0xad, 0x62, 0x2e, 0xc8, 0xc0, 0x7b, 0xf4, 0xbb, 0xf1,
-	0x5e, 0xbc, 0x1f, 0xf7, 0xe1, 0x79, 0xf2, 0xb9, 0xdd, 0xac, 0xb7, 0xe3,
-	0xa3, 0xf2, 0x59, 0xc6, 0x35, 0x79, 0xad, 0xdb, 0xf6, 0xee, 0xaf, 0x9c,
-	0x3f, 0x9f, 0xda, 0x83, 0x08, 0xf3, 0xd7, 0x41, 0x05, 0x11, 0xfb, 0xc4,
-	0xb5, 0x3e, 0x9f, 0xf0, 0x6b, 0x6d, 0xfe, 0xe4, 0x79, 0x9d, 0xe3, 0xe3,
-	0x33, 0xb9, 0x77, 0x84, 0xcf, 0x9e, 0x4e, 0xf6, 0xf9, 0x0a, 0x05, 0x8c,
-	0xb7, 0xcf, 0x97, 0x60, 0x19, 0x98, 0xc8, 0xc5, 0x4b, 0x19, 0xa1, 0x6b,
-	0x18, 0xeb, 0x76, 0x45, 0xcc, 0x69, 0xa3, 0x47, 0x60, 0x3e, 0x7e, 0x1f,
-	0x7f, 0x67, 0x39, 0xcc, 0xb2, 0x1c, 0x66, 0x59, 0x0e, 0xb3, 0x2c, 0x87,
-	0xec, 0xab, 0x7e, 0x2b, 0xcb, 0x72, 0xc8, 0xb6, 0xe4, 0x15, 0xb6, 0x25,
-	0x52, 0x76, 0x63, 0x2a, 0xbe, 0xa9, 0x65, 0x17, 0xeb, 0x7f, 0x6e, 0x1f,
-	0x47, 0xcb, 0x2a, 0xec, 0x37, 0xf9, 0x8e, 0x0f, 0x55, 0xcb, 0xec, 0x0d,
-	0x96, 0xd9, 0xa6, 0xf1, 0x1e, 0xba, 0x95, 0xc7, 0x9c, 0x45, 0xac, 0x39,
-	0xd6, 0xd5, 0x09, 0x3f, 0xb0, 0x56, 0x80, 0xe5, 0x09, 0x58, 0x33, 0xc2,
-	0x74, 0xef, 0xa1, 0xdb, 0xac, 0xaf, 0x6f, 0xe5, 0x21, 0xc3, 0x07, 0xd4,
-	0x71, 0x84, 0x65, 0x18, 0xf6, 0xcf, 0xf6, 0xdd, 0xc8, 0x19, 0x8c, 0xc9,
-	0x02, 0x66, 0x8a, 0xa0, 0x4f, 0x05, 0x4e, 0xe3, 0x79, 0x5f, 0x65, 0xbd,
-	0x8f, 0x18, 0x1e, 0xec, 0xc5, 0x19, 0x1f, 0xdb, 0x8b, 0xf0, 0x75, 0xd6,
-	0xa7, 0xe7, 0xf3, 0x36, 0xcb, 0x7d, 0x17, 0xfd, 0x59, 0x1e, 0x76, 0x1a,
-	0x34, 0xe2, 0xe3, 0x02, 0x89, 0xd8, 0x98, 0x31, 0x8e, 0xb1, 0x0f, 0x3a,
-	0x86, 0xe0, 0x93, 0xdb, 0x98, 0x23, 0xa6, 0xfd, 0x3b, 0x7b, 0xb1, 0x9f,
-	0x7e, 0xcc, 0x68, 0x56, 0xb1, 0x46, 0x7c, 0x47, 0xfb, 0x1e, 0x85, 0x4d,
-	0x71, 0xdc, 0x68, 0x0d, 0x12, 0xbf, 0x43, 0x11, 0x65, 0x7a, 0xd4, 0xea,
-	0xaf, 0x0b, 0x7c, 0xbf, 0xa0, 0xd7, 0x58, 0xdc, 0x8f, 0xfa, 0x72, 0xfa,
-	0xaa, 0x7f, 0x7c, 0x8c, 0x9e, 0x2d, 0xa2, 0xdf, 0x97, 0x29, 0x13, 0x82,
-	0x3e, 0x8a, 0x44, 0xd7, 0x49, 0xd2, 0xae, 0x95, 0x71, 0xe7, 0x63, 0xde,
-	0x3a, 0xce, 0x8a, 0x0b, 0x9c, 0xdc, 0xc2, 0xfa, 0x05, 0xb4, 0xf9, 0x3e,
-	0xf3, 0x5a, 0x14, 0x75, 0x69, 0x4a, 0xbf, 0xbd, 0xce, 0x3a, 0x07, 0x73,
-	0x86, 0xe3, 0x8d, 0x75, 0xda, 0x9a, 0xd2, 0x69, 0xb6, 0x4b, 0xa7, 0xa5,
-	0xcb, 0x3a, 0x8d, 0x79, 0x43, 0xe8, 0xb2, 0xa0, 0xa8, 0x8d, 0x4e, 0xab,
-	0xef, 0xc0, 0x87, 0xbb, 0x85, 0xee, 0x62, 0xdd, 0x3f, 0x84, 0x3d, 0xc8,
-	0x1c, 0xdf, 0x31, 0xa1, 0x43, 0x34, 0x7f, 0x3f, 0xbc, 0x4f, 0xca, 0x45,
-	0xab, 0xd0, 0x07, 0xe9, 0x29, 0xe8, 0x2d, 0xaf, 0xf6, 0x0f, 0x72, 0x3b,
-	0xb4, 0xb7, 0xc3, 0x2f, 0xb2, 0x3e, 0x5b, 0x8c, 0xc2, 0xa7, 0x6d, 0x53,
-	0xbe, 0x0f, 0xf6, 0x14, 0xc3, 0x5a, 0x17, 0xc6, 0xaa, 0xf5, 0x59, 0xb7,
-	0x8a, 0x6b, 0x20, 0x0e, 0x89, 0x39, 0x6f, 0x88, 0x11, 0x2c, 0x60, 0x04,
-	0xbe, 0x27, 0xc0, 0xf4, 0x82, 0x7e, 0x61, 0x3b, 0xf0, 0x2e, 0xad, 0x09,
-	0xd9, 0x78, 0x57, 0x60, 0x97, 0x0c, 0x5f, 0x9b, 0x19, 0x7d, 0x54, 0xf4,
-	0x33, 0xb3, 0x5c, 0xd1, 0x8f, 0x73, 0xd9, 0xf7, 0x60, 0x37, 0x44, 0x5f,
-	0x97, 0x86, 0xa4, 0x0e, 0x5c, 0x2c, 0x98, 0xd8, 0xe3, 0x0c, 0x7d, 0xe6,
-	0xbe, 0xea, 0x71, 0xa2, 0x1f, 0x5a, 0x1f, 0x6c, 0x45, 0xf6, 0x18, 0xd7,
-	0x76, 0x61, 0x8e, 0x1c, 0x17, 0x0f, 0x7d, 0x8f, 0xdf, 0x8f, 0x73, 0x9b,
-	0x8f, 0xe7, 0x76, 0x79, 0x3c, 0x88, 0xed, 0xe1, 0x9e, 0x77, 0xe9, 0x96,
-	0x1a, 0xcf, 0xad, 0xf2, 0x78, 0xbe, 0xab, 0xc6, 0x43, 0x69, 0x63, 0xbc,
-	0x5b, 0xe1, 0xfe, 0x2d, 0x3f, 0xbb, 0x35, 0xce, 0x38, 0x26, 0xbd, 0x0c,
-	0x3a, 0xdf, 0xa5, 0xf8, 0xc9, 0x1d, 0x47, 0x75, 0xf7, 0x35, 0x32, 0xbc,
-	0xce, 0xfa, 0xf7, 0xb6, 0xc0, 0x31, 0x7d, 0x8c, 0x63, 0x70, 0x9e, 0x32,
-	0xd0, 0xd3, 0xe9, 0x10, 0xf6, 0xe1, 0x1d, 0xe3, 0x71, 0xb3, 0x3f, 0x36,
-	0xca, 0x9f, 0x22, 0xbe, 0x26, 0xe2, 0xbe, 0xea, 0xfe, 0xaf, 0xd3, 0xed,
-	0x79, 0xe8, 0x72, 0xe0, 0x58, 0xb9, 0x57, 0xef, 0xed, 0x15, 0x19, 0xdf,
-	0x4d, 0x78, 0xc6, 0x77, 0x11, 0xdb, 0x1d, 0x05, 0xce, 0x37, 0x11, 0x07,
-	0x9e, 0x50, 0xbf, 0x5f, 0x92, 0x2e, 0xe2, 0x59, 0x5e, 0x7a, 0x69, 0xcc,
-	0x95, 0x1f, 0x87, 0xbc, 0x14, 0x87, 0xf5, 0x8c, 0x6d, 0x36, 0x19, 0x47,
-	0x65, 0x9c, 0xb9, 0xa8, 0xb1, 0xd3, 0x09, 0x9e, 0x33, 0x3b, 0x6a, 0x18,
-	0x09, 0x11, 0x6b, 0x68, 0xb5, 0xdb, 0xa8, 0x85, 0xed, 0xe8, 0x59, 0xc2,
-	0x3e, 0x70, 0x11, 0x0b, 0x6b, 0x00, 0x17, 0x98, 0x27, 0x33, 0xd1, 0x48,
-	0xf8, 0x51, 0xe1, 0x97, 0xc2, 0xbe, 0x18, 0xa0, 0x13, 0xd3, 0x1a, 0x7d,
-	0xe0, 0xef, 0xcb, 0xd8, 0x0b, 0x34, 0xca, 0xe3, 0x47, 0xfc, 0x78, 0xc0,
-	0x7a, 0x93, 0xed, 0xd2, 0x05, 0x11, 0x97, 0x79, 0x9a, 0xd2, 0x2c, 0xa7,
-	0xc7, 0x85, 0x9c, 0x1a, 0x7d, 0x2c, 0x45, 0x2c, 0x57, 0xc8, 0x43, 0x18,
-	0x44, 0x0c, 0x50, 0xf9, 0x3a, 0x3c, 0xca, 0x15, 0xb5, 0x57, 0x42, 0x12,
-	0xba, 0x63, 0xeb, 0x31, 0x89, 0xe4, 0xa7, 0x8e, 0xc5, 0xb8, 0x31, 0x59,
-	0xa3, 0xda, 0x51, 0xf8, 0x69, 0x2a, 0x9e, 0x88, 0xfc, 0xf8, 0xf2, 0x6f,
-	0xe9, 0xb8, 0xe3, 0x06, 0xe7, 0x44, 0x6e, 0xe8, 0xcb, 0x45, 0x69, 0x83,
-	0xd3, 0xec, 0xd3, 0x67, 0x8e, 0xb8, 0x31, 0x49, 0x24, 0x37, 0x21, 0x62,
-	0x39, 0xfb, 0x28, 0xbe, 0x30, 0x42, 0x0f, 0x64, 0xa1, 0xc3, 0x68, 0x3d,
-	0x6e, 0xe3, 0x57, 0x72, 0x20, 0xe3, 0x23, 0x94, 0x28, 0x82, 0x46, 0x3e,
-	0xc6, 0x4a, 0xcc, 0x7b, 0x39, 0xac, 0xef, 0xf3, 0xf7, 0x02, 0x7e, 0x1b,
-	0xe6, 0x0f, 0x54, 0xbc, 0xbc, 0x97, 0x26, 0x16, 0xc8, 0x49, 0x45, 0xef,
-	0x15, 0x7b, 0x79, 0xa7, 0xa2, 0x43, 0x2a, 0xb6, 0x13, 0xe6, 0xf3, 0x88,
-	0x97, 0x59, 0x74, 0x7f, 0x36, 0xe2, 0xa4, 0x48, 0xc6, 0x2c, 0x88, 0xfb,
-	0x60, 0xb0, 0xed, 0xdd, 0xcd, 0x3a, 0xe4, 0x94, 0x88, 0x5b, 0x30, 0x52,
-	0x99, 0x47, 0x7b, 0xc4, 0x1c, 0xba, 0x08, 0x7e, 0x5a, 0x2a, 0xf7, 0xaa,
-	0x6a, 0x5b, 0x22, 0x93, 0x79, 0xc1, 0xfc, 0x6d, 0xdb, 0x89, 0x1a, 0x95,
-	0xfb, 0x11, 0xf3, 0x38, 0x25, 0x70, 0x64, 0x1f, 0xfb, 0x3c, 0xa2, 0x5d,
-	0x69, 0x46, 0xc4, 0x2f, 0xf8, 0xb8, 0xf0, 0xc8, 0x7e, 0xa9, 0xdb, 0xe4,
-	0x79, 0x19, 0xd7, 0xe0, 0x67, 0x16, 0xb8, 0x1f, 0x55, 0xf9, 0xf4, 0xbd,
-	0x14, 0xdb, 0x46, 0x9c, 0x69, 0xea, 0x8e, 0xc6, 0x99, 0x98, 0xd6, 0xc5,
-	0xcd, 0x6a, 0x1a, 0xb4, 0xff, 0xf7, 0x91, 0xb6, 0xe1, 0x4c, 0x2b, 0x53,
-	0xfc, 0x16, 0x08, 0x30, 0x78, 0xa6, 0xf8, 0x3c, 0x7e, 0x03, 0xc7, 0x97,
-	0x14, 0xd8, 0x38, 0xcc, 0xd8, 0x06, 0x18, 0x67, 0x40, 0xac, 0x8b, 0xc5,
-	0x1e, 0x0a, 0xfb, 0x32, 0x2b, 0x3d, 0xe4, 0x47, 0x3c, 0xce, 0xd6, 0xb9,
-	0x1c, 0xad, 0x22, 0xef, 0x5d, 0xae, 0x47, 0xc2, 0x3e, 0x43, 0x27, 0xae,
-	0xb3, 0xdf, 0xf0, 0x90, 0xca, 0xb9, 0x41, 0xcd, 0xa6, 0xce, 0xb9, 0xd1,
-	0x3a, 0x45, 0xf3, 0x9e, 0x5e, 0xeb, 0x70, 0xff, 0xde, 0x18, 0x64, 0xd7,
-	0x8d, 0x29, 0x10, 0x9f, 0x12, 0x73, 0x74, 0x81, 0x48, 0xce, 0x71, 0x65,
-	0x1d, 0xa3, 0x85, 0xe7, 0x09, 0xfe, 0x20, 0xe2, 0x7e, 0x8f, 0xf0, 0x27,
-	0xd6, 0x23, 0x7e, 0xb4, 0x1f, 0x38, 0xaa, 0xd3, 0x66, 0x9e, 0x19, 0xc5,
-	0x71, 0x0f, 0xfb, 0x67, 0x1a, 0xf7, 0xca, 0x58, 0x14, 0xfb, 0x6c, 0x6a,
-	0xbe, 0x10, 0x87, 0xea, 0x97, 0x39, 0x4c, 0xd9, 0x08, 0x59, 0x5d, 0xa0,
-	0xd3, 0xaf, 0x4a, 0x1e, 0x37, 0x5b, 0xbb, 0xd8, 0x4a, 0x5e, 0x13, 0x7e,
-	0x0b, 0x0d, 0xfb, 0x8d, 0x1e, 0x04, 0xed, 0x79, 0x8e, 0xdc, 0x6b, 0x1b,
-	0xcf, 0xef, 0xd5, 0xbf, 0xc3, 0x74, 0x67, 0xe6, 0x6d, 0x87, 0xc7, 0xbc,
-	0x1d, 0xec, 0x95, 0x6b, 0x67, 0x7f, 0xa1, 0xda, 0x78, 0xe5, 0xb8, 0x3a,
-	0x4f, 0x22, 0x0e, 0x55, 0xa9, 0xbf, 0x78, 0x5b, 0xe8, 0x95, 0xfa, 0x58,
-	0x78, 0x98, 0xf5, 0xa9, 0x94, 0xe3, 0x53, 0x1e, 0x72, 0xdc, 0x35, 0x0e,
-	0xdc, 0xf2, 0xc9, 0xe5, 0x78, 0xb2, 0xa1, 0x1c, 0x4f, 0xf6, 0xca, 0x58,
-	0x6c, 0xbd, 0x1c, 0xbf, 0x81, 0xbe, 0x14, 0x37, 0xca, 0x81, 0x44, 0x4d,
-	0xbb, 0x3b, 0x56, 0x02, 0x9a, 0xe9, 0x78, 0x09, 0xd6, 0x0d, 0xc1, 0x97,
-	0x58, 0x7b, 0x99, 0x32, 0x12, 0xf3, 0xb5, 0x6b, 0xa9, 0x5b, 0xb9, 0x17,
-	0xeb, 0x34, 0xb5, 0xf7, 0x02, 0xbb, 0x43, 0x36, 0x22, 0x61, 0x19, 0x0b,
-	0xd0, 0xf4, 0xeb, 0xf5, 0x1d, 0xcb, 0x47, 0x9c, 0x02, 0x21, 0xd6, 0x1d,
-	0xa2, 0x73, 0x58, 0x9f, 0x56, 0xb1, 0xe4, 0x93, 0x59, 0x49, 0x07, 0xf3,
-	0x88, 0xe0, 0x0f, 0xe0, 0xdb, 0x70, 0xd2, 0x9f, 0xe4, 0x39, 0x96, 0x71,
-	0xe4, 0xd4, 0x72, 0x58, 0xcd, 0x1b, 0xb7, 0xc5, 0xf3, 0xaa, 0xf6, 0x92,
-	0xd7, 0x71, 0x07, 0xcc, 0x57, 0xe4, 0xeb, 0x95, 0xdc, 0x64, 0xd8, 0x86,
-	0x12, 0xfd, 0x37, 0xdb, 0x3d, 0xff, 0x11, 0x53, 0xec, 0xe3, 0xf0, 0x46,
-	0xf1, 0x08, 0xe3, 0x4d, 0xcc, 0x29, 0x62, 0x90, 0x3a, 0x46, 0xfc, 0xc4,
-	0x41, 0x6a, 0x3f, 0xcc, 0x28, 0xc0, 0x20, 0x9b, 0xf1, 0xa5, 0x71, 0x04,
-	0xb9, 0xe6, 0x16, 0xdf, 0x83, 0xfd, 0xa8, 0x06, 0xad, 0x04, 0xb5, 0x21,
-	0x0e, 0x81, 0xfd, 0xb0, 0xad, 0x74, 0x95, 0x8c, 0x9d, 0x16, 0x32, 0x96,
-	0x58, 0x39, 0xad, 0x64, 0xec, 0xb4, 0x8a, 0xc3, 0x9f, 0x56, 0x32, 0x76,
-	0x5a, 0xc9, 0xd8, 0x69, 0x25, 0x63, 0xa7, 0x99, 0xcf, 0x07, 0x18, 0xdf,
-	0x02, 0x8b, 0xe8, 0x38, 0x68, 0x3b, 0xa5, 0xf2, 0x38, 0x0f, 0xfb, 0x5c,
-	0x2b, 0x67, 0xef, 0xf6, 0x49, 0x39, 0x63, 0x6c, 0x22, 0xeb, 0xc9, 0xf8,
-	0x5d, 0x98, 0x83, 0x57, 0x98, 0xe6, 0x1f, 0xd3, 0x99, 0x79, 0xf4, 0xd5,
-	0x47, 0x13, 0x62, 0x1f, 0xdc, 0x26, 0x8a, 0xbb, 0xb1, 0xb0, 0xc9, 0x63,
-	0xcd, 0x4a, 0xdf, 0xcf, 0x31, 0x6c, 0xc1, 0x27, 0xde, 0x7a, 0x15, 0x7c,
-	0x32, 0xae, 0xe6, 0xab, 0xd6, 0x2f, 0x6a, 0xa1, 0x64, 0x0e, 0x74, 0x45,
-	0xfe, 0xa4, 0xc5, 0x73, 0x23, 0xe8, 0xe4, 0x98, 0x1e, 0x34, 0x38, 0xa9,
-	0x68, 0xf0, 0xb8, 0x18, 0x23, 0xf2, 0x0f, 0x11, 0xcb, 0x6c, 0x4c, 0x87,
-	0x74, 0x76, 0x80, 0x9f, 0xc3, 0xb2, 0x70, 0x24, 0xcc, 0x3a, 0x69, 0xeb,
-	0x74, 0xa8, 0x8c, 0xbd, 0x91, 0xee, 0xd9, 0x6a, 0x5d, 0xce, 0xba, 0xcb,
-	0x96, 0x84, 0x95, 0x1d, 0x91, 0xb8, 0x78, 0x87, 0x5d, 0xa2, 0x13, 0xd1,
-	0x83, 0xfc, 0x3d, 0x92, 0x74, 0xe8, 0x30, 0x19, 0x9d, 0x25, 0xfa, 0x11,
-	0xcb, 0x41, 0x2b, 0xcb, 0xc1, 0x09, 0xe5, 0x97, 0x9c, 0x28, 0xfb, 0x25,
-	0x93, 0x07, 0x90, 0x97, 0x91, 0x12, 0xeb, 0x5e, 0x3b, 0xcb, 0xbf, 0xc3,
-	0x02, 0x3d, 0xb6, 0x88, 0xfd, 0x28, 0x7a, 0x71, 0x6c, 0xd2, 0x55, 0xf6,
-	0xab, 0x63, 0xbe, 0x07, 0x0f, 0x08, 0xec, 0xee, 0x7b, 0x00, 0xf7, 0x9c,
-	0x90, 0x7a, 0xcf, 0x47, 0xfe, 0xc1, 0x77, 0x18, 0x4f, 0x94, 0xe8, 0x31,
-	0x7e, 0x67, 0x26, 0x77, 0x88, 0x9f, 0xad, 0xf7, 0x96, 0xb0, 0x63, 0x86,
-	0x6f, 0x27, 0xf9, 0x3b, 0x1b, 0xbd, 0x3b, 0x22, 0xf8, 0x91, 0xf1, 0xb4,
-	0x31, 0x13, 0x7d, 0xaf, 0x34, 0x3d, 0x85, 0x18, 0x3b, 0xe4, 0x24, 0x62,
-	0x5a, 0x3e, 0x2f, 0xf9, 0x90, 0x58, 0xa9, 0x92, 0x0b, 0x2b, 0xf3, 0xc2,
-	0xff, 0x8b, 0xc7, 0x66, 0x12, 0xd6, 0x4e, 0xe4, 0xf3, 0x93, 0x04, 0x9f,
-	0x00, 0xfb, 0x53, 0x58, 0x4c, 0x67, 0xfd, 0x2e, 0x5b, 0xf1, 0xc6, 0x67,
-	0x90, 0xe7, 0x96, 0x5b, 0xa4, 0x8d, 0x6d, 0x0e, 0xe2, 0x75, 0x03, 0x0b,
-	0x6b, 0x9d, 0x21, 0x51, 0x1b, 0xde, 0xc1, 0x18, 0x49, 0xe7, 0x3e, 0x0f,
-	0xf2, 0xf3, 0x11, 0xc7, 0x0b, 0xd0, 0xc4, 0x25, 0xb4, 0x6b, 0xa6, 0xfe,
-	0x85, 0xd2, 0xef, 0xf1, 0x75, 0xb1, 0x7e, 0x99, 0xa2, 0x56, 0xb5, 0x36,
-	0xa1, 0xf7, 0xad, 0x08, 0xb3, 0xec, 0x55, 0x6a, 0x9f, 0xfb, 0xcb, 0x31,
-	0x3d, 0x21, 0x13, 0x35, 0x31, 0xbd, 0xaf, 0x6e, 0x62, 0xaf, 0x36, 0x93,
-	0x03, 0xe4, 0xd4, 0xb5, 0x90, 0x8a, 0x55, 0x5a, 0x19, 0xda, 0x6a, 0x4d,
-	0xdf, 0x76, 0xef, 0xf1, 0xb5, 0x36, 0x8f, 0x93, 0xf3, 0xa6, 0x1d, 0x54,
-	0xfc, 0xd7, 0x4c, 0x67, 0xf2, 0x41, 0xb6, 0xf9, 0xd0, 0xad, 0xa0, 0x97,
-	0xbf, 0x17, 0xb5, 0x2e, 0x5f, 0x0a, 0x34, 0xd3, 0xf2, 0x32, 0x72, 0x2d,
-	0xfe, 0xf1, 0x80, 0xcc, 0x25, 0x4e, 0x32, 0x5d, 0x0e, 0xb3, 0x7d, 0x34,
-	0xd4, 0xda, 0x11, 0xce, 0x41, 0x97, 0x88, 0xdf, 0x21, 0x0a, 0xdc, 0x3b,
-	0x14, 0x64, 0xbf, 0x40, 0xae, 0x3d, 0x1c, 0xe5, 0x67, 0x7f, 0x33, 0x9f,
-	0x44, 0xbc, 0xcc, 0x3c, 0xce, 0xcf, 0x9f, 0x60, 0x3c, 0x11, 0xa3, 0x66,
-	0x5a, 0x5a, 0x6e, 0x66, 0xbf, 0xa0, 0x99, 0xf1, 0xc4, 0x80, 0xd9, 0xef,
-	0x13, 0xef, 0x12, 0x75, 0x35, 0x9f, 0x0f, 0x1c, 0x66, 0xbe, 0xc2, 0xbb,
-	0xfe, 0x5d, 0xbd, 0xab, 0xf6, 0x1d, 0xff, 0x51, 0xc2, 0xf1, 0x71, 0x3f,
-	0x39, 0x37, 0xf0, 0x1b, 0x5c, 0xf3, 0x63, 0x8c, 0x9d, 0x43, 0x94, 0x99,
-	0x6f, 0xe2, 0x31, 0x8c, 0xb3, 0x1f, 0x11, 0xe5, 0xe3, 0xfb, 0xc8, 0x29,
-	0x4e, 0xd1, 0x5f, 0x15, 0xdd, 0x31, 0xe1, 0xfb, 0xb8, 0xcf, 0xb2, 0xb6,
-	0xbf, 0x85, 0xfb, 0xf5, 0x91, 0x5d, 0xab, 0x63, 0x82, 0xe4, 0xff, 0xeb,
-	0x10, 0x35, 0x7f, 0x0d, 0xb1, 0x97, 0x12, 0xe5, 0xa2, 0xa8, 0x57, 0x90,
-	0xf1, 0xe7, 0xab, 0x22, 0x87, 0x96, 0xef, 0xe7, 0x67, 0xce, 0xa1, 0xdd,
-	0x55, 0x8b, 0xae, 0xdb, 0x92, 0xde, 0x3f, 0x08, 0x84, 0xc8, 0xff, 0x12,
-	0x72, 0x9f, 0xc4, 0xfe, 0x1a, 0x8e, 0x7d, 0x88, 0xf5, 0xfb, 0xd7, 0x70,
-	0x1f, 0x7f, 0xbe, 0x84, 0xe3, 0x20, 0x8f, 0x13, 0xf6, 0x1a, 0xf9, 0x2e,
-	0xd0, 0x8b, 0x87, 0xc3, 0xa6, 0xe0, 0xbf, 0xfb, 0x98, 0xa7, 0x9a, 0x44,
-	0xac, 0xb1, 0x0b, 0x6d, 0xed, 0xfd, 0xc0, 0x16, 0xce, 0xd0, 0x21, 0x1c,
-	0xc7, 0x3a, 0xfd, 0x4c, 0x23, 0xc9, 0x43, 0x18, 0x4f, 0x15, 0x73, 0x07,
-	0x8e, 0x0e, 0x11, 0xcf, 0x27, 0xf0, 0xc7, 0x2f, 0xf1, 0x1b, 0x91, 0x4e,
-	0x3f, 0xbf, 0x23, 0xc1, 0xef, 0x98, 0xc8, 0xcb, 0x71, 0xcf, 0x15, 0xfd,
-	0x24, 0xe3, 0x54, 0x5f, 0xe9, 0xd3, 0xbf, 0xd1, 0x48, 0x3d, 0x78, 0x76,
-	0x59, 0x56, 0xf8, 0x7b, 0x3b, 0xdd, 0xca, 0xb7, 0xd1, 0x6d, 0xb5, 0xa6,
-	0x75, 0x4b, 0xf8, 0x65, 0xac, 0xc3, 0x93, 0xed, 0xb4, 0xbe, 0xdc, 0x44,
-	0xd4, 0x15, 0x14, 0x6b, 0xce, 0xb7, 0xf2, 0x05, 0x7e, 0xff, 0x97, 0xfb,
-	0x64, 0x5c, 0xa7, 0xc2, 0x23, 0xb7, 0x3c, 0x78, 0xe4, 0x03, 0xc1, 0x23,
-	0x5f, 0xec, 0xdb, 0x98, 0x47, 0x50, 0xf3, 0x0f, 0xde, 0x08, 0x52, 0xb3,
-	0xe2, 0x8f, 0x17, 0x99, 0x3f, 0x9e, 0x65, 0xfe, 0x38, 0xd6, 0x80, 0x3f,
-	0x8c, 0x1a, 0xfe, 0x38, 0x2e, 0xf8, 0xe3, 0x89, 0xbe, 0x8d, 0xf8, 0xe3,
-	0x98, 0x7f, 0xa3, 0x58, 0x93, 0xaf, 0x35, 0xc0, 0xef, 0x9e, 0xb3, 0xf7,
-	0x31, 0xaf, 0xdb, 0xb4, 0x34, 0x8f, 0xfa, 0x84, 0xd5, 0xa8, 0x41, 0x3f,
-	0x13, 0x3e, 0xd9, 0x9a, 0xf0, 0xf9, 0xc7, 0x45, 0xcd, 0xc1, 0xa2, 0xe0,
-	0x2f, 0xb6, 0xff, 0xe3, 0xa8, 0xab, 0xaa, 0x9d, 0x8b, 0x56, 0xba, 0x1e,
-	0xc5, 0x5c, 0x58, 0x7a, 0x2e, 0x08, 0xeb, 0xbb, 0x6a, 0xef, 0xc8, 0x40,
-	0x3c, 0x4b, 0xce, 0x07, 0xe0, 0xd1, 0x95, 0xb6, 0xc0, 0x44, 0xf6, 0x1b,
-	0x7d, 0xc0, 0x7f, 0x99, 0x15, 0x72, 0x9d, 0x0f, 0xf0, 0xf9, 0x90, 0xf8,
-	0x6d, 0x2b, 0xc8, 0xca, 0x87, 0xc8, 0x71, 0x64, 0x9e, 0xbc, 0x9e, 0xef,
-	0xa5, 0x1b, 0xf9, 0x7d, 0xb4, 0x96, 0xef, 0xa3, 0x37, 0xc5, 0xbe, 0x1a,
-	0xb2, 0x36, 0x72, 0x4d, 0xcc, 0x91, 0x41, 0x47, 0x43, 0xdc, 0x66, 0x79,
-	0x1f, 0xad, 0x2e, 0x6b, 0xfe, 0x06, 0x6f, 0x83, 0x5f, 0x62, 0x9d, 0xb2,
-	0x66, 0xae, 0x9e, 0x67, 0x26, 0xaa, 0x79, 0x46, 0xdc, 0x03, 0x5e, 0xc9,
-	0xd4, 0xd5, 0xfa, 0x22, 0x5f, 0x11, 0xb9, 0x7a, 0x41, 0x6a, 0x42, 0xde,
-	0xa2, 0x11, 0x19, 0x3e, 0xea, 0x07, 0x86, 0xce, 0xb1, 0xcd, 0xe5, 0x39,
-	0xb3, 0x91, 0xe7, 0xd4, 0xc7, 0x78, 0xb8, 0x43, 0xe0, 0xdf, 0xb8, 0x1d,
-	0x08, 0x4f, 0x50, 0xe9, 0x69, 0xc3, 0xc6, 0x5e, 0x8f, 0x49, 0x7e, 0x9e,
-	0xa1, 0xe2, 0x4d, 0xbb, 0x5c, 0xfc, 0x57, 0x8b, 0x75, 0xb1, 0x96, 0xfc,
-	0x10, 0xf7, 0x19, 0x76, 0xb8, 0xb2, 0x5e, 0x43, 0xe5, 0xf5, 0x9a, 0x56,
-	0x1e, 0xb7, 0x94, 0xbd, 0x19, 0x9b, 0xdb, 0x15, 0xff, 0x6f, 0x40, 0x75,
-	0xeb, 0x41, 0x73, 0x7f, 0x40, 0xf1, 0x25, 0xa0, 0x79, 0x67, 0x19, 0x86,
-	0x43, 0x3d, 0xa0, 0x3c, 0x0a, 0x1a, 0x0f, 0x41, 0xcc, 0xf5, 0x1e, 0x5a,
-	0x03, 0x12, 0x07, 0x8d, 0x89, 0x20, 0xe6, 0x7a, 0x0f, 0x41, 0xe7, 0x7a,
-	0x0f, 0xad, 0xb1, 0x01, 0x97, 0xdb, 0xcd, 0x53, 0x80, 0xe1, 0x3e, 0x85,
-	0x19, 0xba, 0xce, 0x51, 0x0d, 0x7a, 0x77, 0x52, 0x0c, 0x78, 0x4c, 0x5b,
-	0x50, 0x05, 0x7f, 0x18, 0xba, 0x62, 0x84, 0xa1, 0x0d, 0xb8, 0x9d, 0xe5,
-	0x02, 0x34, 0xd3, 0x79, 0x4a, 0x0c, 0x30, 0x3c, 0x23, 0x80, 0x79, 0x4f,
-	0x18, 0x9a, 0xf7, 0x60, 0x73, 0xc7, 0xfc, 0x0c, 0x90, 0x7b, 0x98, 0x6c,
-	0xc0, 0x7d, 0x0b, 0x48, 0x79, 0x25, 0x83, 0x56, 0x5e, 0x01, 0xd3, 0x84,
-	0x3a, 0x44, 0x7f, 0xd3, 0x7a, 0x0d, 0x79, 0xd8, 0x38, 0x60, 0x13, 0xd0,
-	0xdc, 0xe6, 0x29, 0xa4, 0xcc, 0x3d, 0x03, 0xeb, 0x5b, 0xac, 0x6b, 0x1b,
-	0x6d, 0xc0, 0x7b, 0xac, 0x17, 0x4d, 0x61, 0x61, 0x58, 0xd2, 0xc3, 0x00,
-	0xac, 0x1f, 0x40, 0x69, 0x1d, 0x54, 0x47, 0xc0, 0xd3, 0xbb, 0x40, 0x13,
-	0xd0, 0x7d, 0x4e, 0xc0, 0xb6, 0xa8, 0x73, 0xbf, 0x32, 0x78, 0xad, 0x6c,
-	0x03, 0xf4, 0xfc, 0xaa, 0x45, 0x3d, 0xde, 0xf2, 0xa0, 0x7c, 0xe6, 0xa4,
-	0xc2, 0x40, 0x46, 0x5e, 0x60, 0x83, 0xe6, 0x05, 0x70, 0x38, 0x01, 0xd3,
-	0x3a, 0xb0, 0x8c, 0x5a, 0x93, 0x04, 0x34, 0x8f, 0x87, 0xc5, 0xa5, 0x1f,
-	0x24, 0xc6, 0x00, 0x15, 0x63, 0x01, 0xf2, 0x65, 0x80, 0x6d, 0x4a, 0x90,
-	0x5f, 0x41, 0x79, 0x01, 0x64, 0x36, 0xc8, 0xef, 0xa0, 0xb2, 0x13, 0x94,
-	0x17, 0x81, 0xec, 0x25, 0x42, 0x50, 0x3f, 0x03, 0x69, 0x20, 0xbb, 0x79,
-	0x8a, 0x08, 0x98, 0x9f, 0x14, 0x20, 0xc4, 0xd0, 0x00, 0xcf, 0x07, 0xc4,
-	0x86, 0x31, 0x4c, 0x7d, 0x0c, 0x19, 0xf9, 0x06, 0x62, 0x06, 0x22, 0xdf,
-	0xb0, 0x33, 0x1c, 0x10, 0x80, 0x85, 0xd5, 0xff, 0xff, 0xc7, 0x54, 0x58,
-	0x80, 0xe9, 0x14, 0xb4, 0x8e, 0xf5, 0xf7, 0xff, 0x03, 0x22, 0x2c, 0x0c,
-	0x2d, 0xf0, 0xf5, 0x88, 0x0b, 0xe5, 0x41, 0x65, 0xe8, 0x02, 0x20, 0xab,
-	0x0d, 0xde, 0x26, 0x60, 0x01, 0xdf, 0x61, 0xbd, 0x80, 0xe1, 0x17, 0xb0,
-	0xcc, 0xfa, 0xff, 0x7f, 0x29, 0x5c, 0x2d, 0x08, 0x00, 0x00, 0xff, 0x88,
-	0x78, 0xb5, 0x98, 0x7e, 0x00, 0x00, 0x00 };
+	0xcd, 0x7c, 0x7f, 0x6c, 0x5c, 0xd7, 0x95, 0xde, 0x79, 0x6f, 0x1e, 0xc9,
+	0xe1, 0x88, 0xa2, 0x1e, 0xe9, 0x31, 0x3d, 0x8e, 0xb9, 0xc9, 0x0c, 0xe7,
+	0x91, 0xa2, 0x4d, 0x26, 0xfb, 0xcc, 0x8e, 0x6d, 0x3a, 0x99, 0xb5, 0xc6,
+	0x33, 0x94, 0xad, 0xc4, 0x8c, 0x41, 0x3b, 0xca, 0xd6, 0x28, 0xdc, 0x80,
+	0x1d, 0x52, 0x8e, 0xb3, 0x75, 0xbb, 0x8e, 0x1b, 0xa4, 0x89, 0x11, 0x44,
+	0x93, 0x21, 0xa5, 0x55, 0x82, 0x21, 0x67, 0x22, 0xd3, 0xdc, 0xfc, 0xb1,
+	0x68, 0xc6, 0x43, 0x52, 0x71, 0xb6, 0x23, 0xd1, 0x4e, 0xb2, 0x41, 0x16,
+	0xd8, 0xc0, 0x2c, 0x25, 0xcb, 0xc2, 0x22, 0x2d, 0xdc, 0x34, 0x28, 0x82,
+	0xec, 0xfe, 0x21, 0xc8, 0xce, 0xc6, 0x29, 0xd2, 0xc2, 0xed, 0x06, 0x8d,
+	0x37, 0x48, 0xf2, 0xfa, 0x7d, 0xf7, 0xde, 0x37, 0x1a, 0x8d, 0x68, 0x27,
+	0xdd, 0xfe, 0x53, 0x02, 0x83, 0xfb, 0xde, 0xfd, 0x79, 0xee, 0xb9, 0xe7,
+	0x9e, 0xf3, 0x9d, 0x73, 0xef, 0xe3, 0x3d, 0x22, 0x31, 0x31, 0x7f, 0xfb,
+	0xf1, 0xcb, 0xfc, 0xab, 0x3f, 0x5e, 0xb8, 0xe3, 0x7d, 0xfe, 0xfb, 0xf8,
+	0x6e, 0x77, 0x89, 0xc3, 0x34, 0x82, 0x5f, 0x1c, 0xbf, 0x29, 0xf3, 0xbc,
+	0xd7, 0x9f, 0x8b, 0xdf, 0x9d, 0x96, 0xc8, 0xfc, 0x7f, 0x13, 0xb1, 0x3a,
+	0xca, 0xa2, 0x7b, 0xd4, 0x0f, 0x82, 0xb7, 0xe9, 0xc8, 0xfc, 0xd9, 0xf8,
+	0x25, 0xdf, 0xb9, 0xca, 0xff, 0xf3, 0x5f, 0x44, 0x93, 0xad, 0xe6, 0xcd,
+	0x9f, 0x44, 0xed, 0x6c, 0xfd, 0x81, 0xbc, 0x27, 0xd1, 0x48, 0x76, 0x6d,
+	0x76, 0xc1, 0x13, 0xc9, 0x35, 0x27, 0x92, 0x05, 0xf9, 0x75, 0x50, 0x8a,
+	0x3b, 0xc2, 0xfc, 0xdf, 0xcb, 0xfe, 0xea, 0xab, 0xdf, 0xbd, 0x2b, 0xf5,
+	0x66, 0x3d, 0x22, 0x51, 0x37, 0xfb, 0x96, 0xb8, 0x63, 0x12, 0x1d, 0x46,
+	0x9b, 0x3f, 0x3b, 0x78, 0xc9, 0x96, 0xfe, 0xb0, 0x2f, 0x77, 0x3e, 0x92,
+	0x95, 0xb9, 0x63, 0x95, 0xe3, 0x81, 0xed, 0x49, 0xc9, 0xc9, 0x7a, 0xe3,
+	0x0d, 0xe9, 0x9b, 0xde, 0xca, 0xdc, 0x25, 0x78, 0x9f, 0x3b, 0xd6, 0x8c,
+	0x4a, 0xb9, 0x59, 0xea, 0xb3, 0x3d, 0x0f, 0xa9, 0x44, 0xbb, 0xb3, 0x8b,
+	0xd1, 0x8b, 0x1e, 0xc7, 0xfe, 0x21, 0xc6, 0xbe, 0x45, 0xba, 0xbc, 0x20,
+	0xd8, 0xc2, 0xd8, 0xf7, 0x35, 0x7f, 0x1d, 0x3c, 0xe7, 0xe8, 0x71, 0xed,
+	0xec, 0x93, 0x11, 0xa6, 0x56, 0xf6, 0xf2, 0x03, 0x23, 0x4d, 0xbe, 0x7b,
+	0x3d, 0x9a, 0x4e, 0x37, 0x06, 0x3a, 0xa3, 0x4e, 0x76, 0x2e, 0xb6, 0x8c,
+	0xb4, 0x2b, 0xfb, 0xe8, 0xed, 0x5b, 0xaa, 0xde, 0xeb, 0xa6, 0xde, 0x13,
+	0x5d, 0xba, 0xdd, 0xf8, 0xec, 0x58, 0x93, 0x69, 0x66, 0x76, 0x54, 0xa5,
+	0xd9, 0xd9, 0xb4, 0x4a, 0x73, 0xb3, 0x23, 0x2a, 0x9d, 0x99, 0xf5, 0x54,
+	0xfa, 0xb7, 0x0f, 0xe8, 0xfc, 0x37, 0x1e, 0x48, 0xaa, 0xf4, 0x67, 0x26,
+	0x7d, 0xd3, 0xa4, 0x3f, 0x37, 0xe9, 0x5b, 0x26, 0xfd, 0x95, 0x49, 0x65,
+	0x56, 0xa7, 0x8e, 0xe9, 0x27, 0x6a, 0xde, 0xfb, 0x4c, 0xea, 0x9a, 0x34,
+	0x6e, 0xd2, 0x84, 0x49, 0x87, 0x0d, 0x5d, 0x49, 0x93, 0x7a, 0x26, 0x9d,
+	0x34, 0xe5, 0xbe, 0xa1, 0x77, 0x1a, 0xf4, 0x7e, 0xa1, 0xcb, 0xc8, 0x2a,
+	0xe6, 0x9d, 0x94, 0x85, 0x8a, 0x23, 0xe5, 0x6a, 0x44, 0x0a, 0x6a, 0x0d,
+	0x1f, 0xd9, 0x2f, 0x31, 0x47, 0x96, 0xb6, 0xa3, 0x72, 0x59, 0x89, 0xe8,
+	0x1b, 0xc1, 0x77, 0x0f, 0x4a, 0xc9, 0xce, 0xba, 0xf2, 0xc2, 0x76, 0x5c,
+	0x5e, 0xda, 0x16, 0x6b, 0x2e, 0xd3, 0x2b, 0xf6, 0xe9, 0x77, 0x49, 0xce,
+	0xb5, 0x24, 0xa2, 0x78, 0x9a, 0x94, 0x7c, 0x65, 0x08, 0xef, 0xa9, 0x84,
+	0xc8, 0xe9, 0xfd, 0x7a, 0xfd, 0xa2, 0x12, 0x59, 0xe7, 0x9a, 0x3c, 0x3d,
+	0x7b, 0x71, 0x2d, 0x21, 0xce, 0xea, 0x24, 0xc6, 0xe8, 0x93, 0xae, 0x75,
+	0x19, 0x8e, 0xc8, 0x68, 0xe2, 0x31, 0xd4, 0x98, 0x69, 0x3a, 0x72, 0xb8,
+	0x69, 0x89, 0xe3, 0x45, 0x21, 0x1f, 0x7d, 0xf8, 0xb9, 0xf8, 0xc5, 0xf1,
+	0x4b, 0xe0, 0xf7, 0x97, 0xe8, 0x67, 0x58, 0x0a, 0x4d, 0xf6, 0x89, 0x71,
+	0xab, 0x18, 0xbf, 0x9a, 0x72, 0xe7, 0x85, 0x74, 0x25, 0xe4, 0xbb, 0x07,
+	0x49, 0x97, 0x4b, 0x7a, 0x40, 0x5b, 0xd4, 0xca, 0xaf, 0xc9, 0x93, 0x05,
+	0x5f, 0x92, 0xb6, 0x17, 0x93, 0xa2, 0x6b, 0x25, 0x17, 0xc7, 0x07, 0xa5,
+	0x74, 0x14, 0xe5, 0x55, 0xc9, 0xd9, 0xe8, 0xbf, 0xe8, 0xca, 0xbc, 0x2e,
+	0x63, 0xde, 0x5b, 0xd8, 0xab, 0x29, 0x97, 0x42, 0xfb, 0x52, 0xf5, 0xdb,
+	0x78, 0x66, 0x7f, 0xff, 0xe0, 0x68, 0xba, 0x7f, 0x81, 0x77, 0xe6, 0xff,
+	0x7d, 0x9f, 0x7e, 0xe7, 0x33, 0xeb, 0x86, 0xe3, 0x86, 0xf3, 0xe5, 0xf8,
+	0xe3, 0x98, 0x33, 0x69, 0x08, 0xe7, 0x2c, 0xa5, 0x2e, 0xd0, 0xd2, 0x58,
+	0xeb, 0xb3, 0x36, 0xd6, 0x26, 0xe5, 0x64, 0xf5, 0x1e, 0xc9, 0xfb, 0x41,
+	0xb0, 0xe0, 0x4b, 0xdc, 0x96, 0x51, 0xb7, 0x80, 0x0a, 0xbb, 0x4d, 0xb1,
+	0x1a, 0x15, 0x89, 0xf6, 0x80, 0x2f, 0x3f, 0x59, 0x63, 0xdf, 0x0e, 0xf2,
+	0x86, 0x50, 0xbf, 0xdf, 0xda, 0x5c, 0x03, 0xfd, 0x59, 0xf2, 0x27, 0x08,
+	0x96, 0xfd, 0xd1, 0xc4, 0x22, 0xc6, 0x3c, 0xdf, 0x1c, 0x9d, 0xbe, 0x22,
+	0x2e, 0xfa, 0x1c, 0x44, 0x1d, 0xf2, 0x8a, 0x7d, 0xb1, 0x4f, 0xf6, 0xd7,
+	0x87, 0xb6, 0x71, 0x94, 0x91, 0xae, 0x20, 0xc8, 0xfb, 0x2e, 0xdf, 0x65,
+	0x07, 0xfc, 0xdb, 0x21, 0xff, 0x62, 0xc3, 0xf2, 0x4a, 0x93, 0x63, 0xec,
+	0x45, 0xfb, 0xc4, 0xff, 0x87, 0xb4, 0x27, 0xd0, 0x7f, 0x1c, 0xe9, 0x3e,
+	0xab, 0x51, 0x0b, 0x30, 0x7e, 0x02, 0xcf, 0x7b, 0xcd, 0xe3, 0xb2, 0x5a,
+	0xfb, 0x17, 0xb0, 0xf6, 0x6e, 0x36, 0x2e, 0x2f, 0x6e, 0x0f, 0x63, 0x1e,
+	0x09, 0xf9, 0x06, 0x64, 0x73, 0xe0, 0xce, 0x7d, 0x92, 0x86, 0x6c, 0x72,
+	0xcd, 0xa7, 0xd6, 0x1f, 0x95, 0x62, 0x3c, 0x35, 0x4e, 0x3d, 0x9a, 0x9f,
+	0xea, 0xc1, 0x7c, 0xb5, 0xb6, 0x1a, 0x59, 0x8d, 0x4b, 0x7a, 0x3d, 0x77,
+	0x83, 0x9e, 0x57, 0xdd, 0x92, 0x58, 0x49, 0xec, 0x73, 0x21, 0x6f, 0xc6,
+	0x4d, 0xbd, 0x96, 0x1c, 0x5b, 0xf6, 0x7a, 0x9f, 0x15, 0x59, 0x9f, 0x94,
+	0x13, 0x7b, 0xf0, 0xa4, 0x01, 0x9e, 0xd8, 0xab, 0xa1, 0x9c, 0x3b, 0x78,
+	0x1f, 0x42, 0xdd, 0x7e, 0xcb, 0x59, 0xbf, 0x9e, 0x1f, 0x1b, 0xcd, 0x51,
+	0x7f, 0x17, 0xfc, 0xb0, 0xd7, 0x07, 0x51, 0xe7, 0x7a, 0x7e, 0x34, 0xc0,
+	0x0f, 0x7b, 0x5d, 0xf3, 0xa2, 0x01, 0x5e, 0xd8, 0xa0, 0xb3, 0x01, 0x5e,
+	0xd8, 0xa7, 0x35, 0x2f, 0x1a, 0x66, 0x4f, 0x9c, 0x51, 0xfa, 0x28, 0x07,
+	0x5a, 0x2d, 0xd1, 0x3a, 0x29, 0x27, 0xd4, 0x3d, 0x91, 0xec, 0x0c, 0xf6,
+	0xb2, 0x8d, 0xb9, 0x3a, 0x32, 0x33, 0x65, 0xc9, 0x82, 0x2a, 0x9b, 0x91,
+	0x74, 0xf3, 0x5d, 0x60, 0xd4, 0xc4, 0x38, 0x2c, 0x41, 0xa9, 0x3b, 0xfb,
+	0x1d, 0x7b, 0xb7, 0x12, 0x95, 0x82, 0x93, 0x14, 0x6f, 0x95, 0xfd, 0xcc,
+	0xb7, 0xf5, 0x33, 0x8f, 0x7e, 0x76, 0xc1, 0x0f, 0x0b, 0xba, 0x93, 0x65,
+	0x8f, 0xaa, 0x7d, 0x9d, 0x5e, 0x77, 0x64, 0x74, 0x95, 0x75, 0x4a, 0xf6,
+	0x85, 0xe6, 0xaf, 0x02, 0xdd, 0xef, 0xa3, 0x1c, 0xd3, 0xb5, 0xb3, 0xcb,
+	0xf6, 0xf9, 0xcd, 0x53, 0xf6, 0xcb, 0x4d, 0xf4, 0xdb, 0x24, 0xaf, 0xb1,
+	0x16, 0x55, 0xac, 0x45, 0x15, 0xeb, 0x62, 0xf6, 0x6c, 0x5d, 0xed, 0x9d,
+	0xa4, 0x59, 0x37, 0xd2, 0xc0, 0xb5, 0x4b, 0x60, 0xcd, 0xb8, 0x76, 0x62,
+	0xbd, 0x9a, 0xd9, 0x27, 0x91, 0xd3, 0x11, 0xb5, 0x66, 0x03, 0xeb, 0x1f,
+	0x68, 0xad, 0xd9, 0xc8, 0xd4, 0x81, 0xd6, 0x9a, 0xd9, 0xab, 0xb9, 0x5b,
+	0x6c, 0x39, 0x24, 0x76, 0x16, 0xfc, 0xc9, 0x4c, 0x80, 0x5f, 0x11, 0x94,
+	0xc5, 0xc5, 0x59, 0xcf, 0x21, 0x2f, 0x95, 0x28, 0x82, 0x8f, 0x65, 0xf0,
+	0xb1, 0x28, 0x25, 0xc8, 0xcc, 0xcf, 0x2c, 0xad, 0xdf, 0x7e, 0x29, 0x46,
+	0xb6, 0xdf, 0x91, 0x5f, 0x23, 0xe0, 0x97, 0xf7, 0x3b, 0xf0, 0xcb, 0xd9,
+	0x93, 0x5f, 0xfd, 0x76, 0x27, 0xbf, 0x22, 0xe0, 0x57, 0xd7, 0xef, 0xcc,
+	0x2f, 0xf0, 0x61, 0x4f, 0x5e, 0x45, 0xa1, 0xd7, 0x4a, 0x92, 0xcf, 0x88,
+	0xe4, 0x6b, 0x5a, 0x17, 0x97, 0x94, 0x4e, 0xa6, 0x2e, 0x0a, 0x75, 0x32,
+	0xf5, 0xb1, 0xda, 0x07, 0x56, 0xa1, 0x92, 0x84, 0xae, 0x74, 0x90, 0x3e,
+	0x8f, 0x74, 0x9f, 0x35, 0x57, 0x83, 0x68, 0xf5, 0x07, 0xe2, 0x4e, 0x85,
+	0xf6, 0xb0, 0x94, 0x70, 0xb1, 0x36, 0xee, 0xfb, 0xba, 0x44, 0x86, 0x52,
+	0xe0, 0xd3, 0xcd, 0x28, 0x4f, 0x25, 0x72, 0x92, 0xb1, 0x43, 0xdc, 0x92,
+	0xaf, 0xf4, 0xbe, 0x95, 0x53, 0x4f, 0xcc, 0x67, 0xbb, 0x0c, 0xf2, 0xba,
+	0x64, 0x1e, 0x7a, 0x7e, 0xc6, 0xe3, 0x78, 0xec, 0x3f, 0x39, 0xcf, 0x71,
+	0x0b, 0xcd, 0x50, 0x27, 0x4b, 0x0e, 0x36, 0x1a, 0x65, 0xdc, 0x97, 0xd3,
+	0x56, 0x41, 0xdb, 0x46, 0xf1, 0x9a, 0xed, 0xf6, 0xa3, 0x45, 0x27, 0xf6,
+	0x6b, 0x8e, 0x72, 0x8d, 0xb1, 0x93, 0xd8, 0x73, 0xe5, 0x48, 0xb8, 0x3e,
+	0x4e, 0x76, 0x5a, 0x60, 0x77, 0xa5, 0x5c, 0x61, 0x7f, 0x9f, 0xb1, 0x22,
+	0xe7, 0xc2, 0xfe, 0xc9, 0x47, 0xf6, 0xad, 0xfb, 0x2b, 0x37, 0xdf, 0x30,
+	0x7b, 0x5f, 0xd9, 0x22, 0xf4, 0x57, 0x6a, 0xeb, 0xaf, 0x64, 0x45, 0x56,
+	0xe5, 0x80, 0xd2, 0xf7, 0x47, 0xc9, 0xbf, 0x53, 0x28, 0xbb, 0x2c, 0x11,
+	0xca, 0x8c, 0xda, 0x63, 0xdc, 0xe7, 0x9f, 0xe5, 0x7c, 0xdb, 0x78, 0x3b,
+	0x07, 0x1b, 0xc6, 0xfd, 0x85, 0x35, 0x8e, 0x33, 0xff, 0x2e, 0x43, 0x93,
+	0x23, 0x39, 0xf5, 0xfe, 0xb5, 0x7d, 0xa1, 0x7e, 0xc4, 0x7e, 0x06, 0x6d,
+	0xdf, 0x51, 0x73, 0xb4, 0xb3, 0x59, 0xf0, 0xa6, 0x9d, 0x46, 0x85, 0x05,
+	0xb0, 0xc6, 0xa1, 0x8e, 0x0a, 0xd7, 0x8a, 0xb8, 0xc5, 0xb1, 0x96, 0x2a,
+	0x7d, 0xb0, 0x7f, 0x51, 0x63, 0x63, 0xd9, 0x7e, 0x19, 0xed, 0x99, 0xcf,
+	0xb6, 0x7d, 0xb0, 0xb7, 0x6c, 0xbf, 0x6c, 0xda, 0x5f, 0xb5, 0xbb, 0xdc,
+	0x2b, 0xb4, 0xb9, 0x17, 0x32, 0xc0, 0x3a, 0x6b, 0xb6, 0x14, 0x7c, 0xe0,
+	0x18, 0x7f, 0xd8, 0xec, 0x0b, 0x2d, 0x9b, 0xf7, 0x3a, 0x96, 0xf4, 0x78,
+	0x7b, 0xc9, 0xe6, 0xcb, 0xb6, 0xb6, 0x65, 0x57, 0x65, 0x73, 0x09, 0x3a,
+	0xea, 0x04, 0x64, 0x65, 0xb9, 0x55, 0x8f, 0x72, 0xa9, 0x64, 0x14, 0xb2,
+	0x99, 0x9a, 0xe6, 0x34, 0x2f, 0x34, 0xdb, 0x65, 0x34, 0xec, 0x23, 0xaa,
+	0xe4, 0x40, 0x8f, 0xb3, 0xdc, 0x36, 0xce, 0x72, 0xdb, 0x38, 0x27, 0x0d,
+	0x76, 0x63, 0x3f, 0xda, 0x6e, 0x5e, 0xbe, 0xc6, 0x5e, 0x73, 0xcd, 0x3e,
+	0x8a, 0x3d, 0xa9, 0x65, 0x01, 0x58, 0x4c, 0xaf, 0x41, 0xc5, 0x95, 0xf2,
+	0xf6, 0xd9, 0x70, 0xaf, 0x96, 0x7a, 0x90, 0xff, 0x53, 0xe4, 0x8f, 0xaf,
+	0xb8, 0xb0, 0x43, 0xc4, 0x62, 0x7f, 0x25, 0x5b, 0x15, 0xca, 0xc8, 0x77,
+	0x40, 0x77, 0xda, 0xef, 0xb6, 0xc8, 0xd7, 0xd4, 0xf8, 0x19, 0x49, 0x25,
+	0xcb, 0x32, 0xe1, 0x33, 0x3d, 0x49, 0x45, 0x8d, 0x7a, 0x1a, 0xe3, 0x7c,
+	0x07, 0xf2, 0x27, 0xf2, 0x66, 0xa5, 0x47, 0xec, 0xa9, 0x9f, 0x06, 0xb4,
+	0x73, 0xa7, 0xb6, 0x3b, 0xfb, 0x11, 0x19, 0x5b, 0x51, 0xfd, 0xa0, 0x8f,
+	0xb4, 0x7f, 0x49, 0xf5, 0x17, 0xf6, 0x85, 0x79, 0x4e, 0x75, 0xf6, 0xe7,
+	0xc8, 0x65, 0xd7, 0x46, 0x7f, 0xb7, 0x98, 0x39, 0xf2, 0x19, 0x32, 0xe2,
+	0x3a, 0x48, 0xef, 0xb3, 0x43, 0x99, 0xb1, 0xa7, 0xfe, 0x3a, 0xc8, 0xcd,
+	0x71, 0x6e, 0xff, 0xcc, 0xe4, 0xfd, 0x47, 0x23, 0x6f, 0x52, 0xb3, 0xb3,
+	0xe0, 0x59, 0x66, 0x14, 0xe3, 0xf1, 0x3d, 0x09, 0xfc, 0x23, 0x25, 0xe2,
+	0xaf, 0x62, 0xe5, 0x37, 0x41, 0xce, 0xd1, 0x98, 0x49, 0xaf, 0x3d, 0xcb,
+	0x2d, 0x29, 0xa0, 0xee, 0x92, 0xd1, 0x07, 0x33, 0xcd, 0xcb, 0x8a, 0x7f,
+	0x2f, 0xaa, 0x7d, 0x94, 0x3a, 0x55, 0xa2, 0xde, 0xd8, 0x8e, 0x46, 0xb8,
+	0xc7, 0x5f, 0xf0, 0x37, 0x83, 0xa5, 0x6a, 0x2a, 0x99, 0xb4, 0x47, 0xa5,
+	0x58, 0x1b, 0x2d, 0xd9, 0x48, 0x9f, 0xac, 0x27, 0xe4, 0xc9, 0x0a, 0xfb,
+	0xb9, 0x01, 0x75, 0xa0, 0x88, 0x6c, 0x6c, 0xf2, 0x21, 0xea, 0x1a, 0x8e,
+	0xf9, 0x96, 0xa5, 0xc7, 0xc4, 0x1c, 0xbc, 0x1d, 0xeb, 0x93, 0xcd, 0x0b,
+	0x56, 0xb1, 0xce, 0xf5, 0x47, 0x7e, 0xb3, 0x5d, 0x1f, 0xb5, 0xeb, 0xed,
+	0x50, 0x5f, 0xeb, 0xb5, 0x73, 0xb0, 0xef, 0x6a, 0x95, 0x65, 0xab, 0xbc,
+	0x26, 0x76, 0xde, 0xef, 0x32, 0xf2, 0x68, 0xb9, 0x7a, 0xce, 0x4f, 0x46,
+	0xa8, 0x13, 0x23, 0xde, 0x29, 0xab, 0x5c, 0xb9, 0x55, 0x72, 0x0e, 0x31,
+	0x1c, 0x9f, 0x25, 0x88, 0x64, 0x3d, 0xda, 0x4d, 0x27, 0x92, 0x4d, 0x63,
+	0xbf, 0xb1, 0xce, 0x66, 0xf0, 0x65, 0x8c, 0x33, 0x72, 0x1a, 0xfa, 0xd9,
+	0x7f, 0x0f, 0xfa, 0xe1, 0xf8, 0xbd, 0x78, 0x77, 0xcc, 0xbe, 0xec, 0x42,
+	0xbd, 0x14, 0x36, 0xf7, 0xc5, 0x7e, 0xe9, 0x7f, 0x06, 0x7a, 0x36, 0xec,
+	0x9b, 0x75, 0x12, 0xa6, 0x4e, 0x9f, 0xa9, 0x73, 0x37, 0xca, 0x3f, 0x86,
+	0x7a, 0x29, 0x9f, 0xd0, 0x16, 0x29, 0xf2, 0x06, 0x31, 0x47, 0xd4, 0x6d,
+	0xdc, 0x60, 0xde, 0xc3, 0xf6, 0x77, 0xb6, 0xd5, 0xe5, 0xfb, 0xb5, 0x7a,
+	0x78, 0xbe, 0xa5, 0x87, 0xc9, 0xc3, 0x1c, 0xf4, 0x9e, 0xd8, 0xd8, 0xf7,
+	0x6e, 0x24, 0xcb, 0xfc, 0x69, 0x3c, 0x3f, 0x1f, 0x94, 0xab, 0xd4, 0xfb,
+	0xc0, 0xc1, 0x75, 0xa5, 0xff, 0xd0, 0x6f, 0xce, 0x9a, 0xa9, 0x84, 0xeb,
+	0xc4, 0x79, 0x85, 0xb8, 0x44, 0xf1, 0x0c, 0xf4, 0x26, 0xaf, 0xd2, 0xeb,
+	0x2a, 0x99, 0x40, 0x9e, 0x6f, 0xf2, 0x7a, 0xda, 0xf2, 0x42, 0x9d, 0xf4,
+	0x05, 0xcc, 0x6b, 0x58, 0xad, 0x99, 0x9d, 0x3d, 0x62, 0xe5, 0x15, 0x26,
+	0x0a, 0x82, 0x82, 0xd7, 0x25, 0xc5, 0xc9, 0xa7, 0xc1, 0x2b, 0x96, 0x95,
+	0xdc, 0x88, 0xc2, 0xf1, 0x73, 0x0f, 0x2c, 0x78, 0x29, 0x85, 0x49, 0xf2,
+	0xd0, 0x09, 0x5a, 0x8f, 0x4b, 0x69, 0x00, 0xb4, 0x7b, 0xab, 0xe4, 0xc5,
+	0x66, 0x70, 0x1a, 0xf8, 0x7b, 0x6e, 0x75, 0xc6, 0x1a, 0x59, 0xc5, 0xba,
+	0x0f, 0x59, 0xe0, 0x4b, 0x9f, 0xe4, 0xcf, 0x91, 0x2f, 0xac, 0xc3, 0xfc,
+	0x6e, 0x99, 0x8b, 0x77, 0xda, 0xef, 0x3f, 0x3e, 0x20, 0x31, 0xf2, 0x01,
+	0x75, 0x57, 0x21, 0xec, 0x31, 0x8d, 0x89, 0x47, 0xd6, 0x29, 0x47, 0x33,
+	0xd6, 0x42, 0x85, 0xba, 0xb5, 0x17, 0x36, 0x5b, 0xad, 0x3f, 0xfa, 0x44,
+	0xd9, 0x99, 0xce, 0x3e, 0x3e, 0x1d, 0xd1, 0x7d, 0xb0, 0x5d, 0xd8, 0x47,
+	0x3b, 0x3f, 0xf6, 0x29, 0xdd, 0x3b, 0x98, 0x1d, 0xec, 0xe8, 0x37, 0xd1,
+	0xd6, 0x2f, 0xca, 0xce, 0xfc, 0x34, 0x42, 0x2c, 0xf8, 0x52, 0x15, 0x7c,
+	0x56, 0x73, 0x62, 0x19, 0xdb, 0xcc, 0x58, 0x85, 0xd5, 0x20, 0x98, 0xf3,
+	0x6d, 0x89, 0x0c, 0x85, 0x75, 0xf5, 0xbc, 0x66, 0x30, 0xaf, 0x3c, 0xe6,
+	0x65, 0x0f, 0x75, 0xd2, 0xf4, 0x39, 0x43, 0xd3, 0x60, 0x1b, 0x4d, 0xf1,
+	0x77, 0x98, 0x57, 0x7c, 0x8f, 0x79, 0x9d, 0x1c, 0xd4, 0x7d, 0xc4, 0xdb,
+	0xfa, 0x18, 0xea, 0xe8, 0x03, 0xb6, 0x28, 0xce, 0xf6, 0x43, 0x7b, 0xb4,
+	0xff, 0x49, 0xaf, 0x6e, 0xcf, 0x36, 0xdd, 0xb0, 0x37, 0xc3, 0x46, 0x57,
+	0x3f, 0xd9, 0xa6, 0x5f, 0x9f, 0x84, 0x7e, 0x6d, 0x6f, 0x13, 0xca, 0x65,
+	0xbb, 0x5f, 0x46, 0x9f, 0x2c, 0xc4, 0xaf, 0xef, 0x52, 0xb8, 0xe8, 0x2a,
+	0xae, 0x8f, 0x02, 0x23, 0xf5, 0x01, 0x93, 0xf4, 0xd3, 0xf7, 0x32, 0x38,
+	0x95, 0xbe, 0x18, 0xb1, 0xa9, 0x78, 0x40, 0x76, 0xd0, 0x77, 0xa3, 0x89,
+	0x63, 0x22, 0xca, 0xf7, 0x22, 0xa6, 0xa7, 0x1f, 0xc6, 0x71, 0xe8, 0x87,
+	0x71, 0xdd, 0xf9, 0x5e, 0x68, 0xf9, 0x65, 0xc3, 0xd0, 0x45, 0xc4, 0xe4,
+	0xc4, 0xaf, 0xa1, 0xfd, 0x6b, 0xd7, 0xf1, 0x7b, 0xd1, 0x34, 0xdc, 0x41,
+	0x13, 0xf4, 0x24, 0xfc, 0xc1, 0x25, 0xc8, 0x23, 0x70, 0x32, 0xf4, 0xf2,
+	0xd3, 0xb3, 0x5b, 0x6b, 0x22, 0xc5, 0x26, 0x6d, 0xf6, 0xa4, 0xc0, 0x97,
+	0x03, 0x5d, 0xec, 0x5b, 0xd9, 0x6d, 0xe8, 0xcb, 0xfe, 0x9c, 0x9d, 0x1d,
+	0x85, 0xef, 0xef, 0xc8, 0xa2, 0xa1, 0x6d, 0x5e, 0xf9, 0x8d, 0x7d, 0x48,
+	0x13, 0x4a, 0xae, 0xe6, 0x41, 0x1f, 0x9f, 0xe7, 0x8d, 0xbf, 0x70, 0xac,
+	0xd9, 0x49, 0xdb, 0x0f, 0x41, 0x9b, 0x07, 0x1a, 0x92, 0xf2, 0x2d, 0xf8,
+	0x0b, 0xdf, 0x54, 0xfb, 0x32, 0xd4, 0x67, 0x4a, 0x57, 0xd4, 0x4a, 0xf2,
+	0x7c, 0xb0, 0x56, 0xe5, 0xbe, 0x25, 0xae, 0xe8, 0x93, 0x12, 0xd6, 0x6b,
+	0x64, 0x35, 0x95, 0xcc, 0xd9, 0x62, 0xdd, 0x70, 0x27, 0xe5, 0xe9, 0x09,
+	0x19, 0x39, 0x27, 0x96, 0xb3, 0x8a, 0xbd, 0xde, 0x1f, 0x62, 0x3e, 0xce,
+	0xef, 0xdd, 0x98, 0x1f, 0xfa, 0xae, 0x86, 0xf3, 0xeb, 0x93, 0xe2, 0x3a,
+	0xe7, 0xd7, 0x9a, 0x5b, 0x9c, 0x51, 0x98, 0xa7, 0x60, 0x43, 0x30, 0x47,
+	0xd0, 0x38, 0x0d, 0xec, 0xfd, 0x1e, 0x33, 0xa7, 0x3e, 0xcc, 0x09, 0xb8,
+	0x61, 0x95, 0xed, 0x41, 0x17, 0x68, 0x2e, 0xa2, 0x5e, 0x79, 0x95, 0x6b,
+	0x0e, 0x5a, 0xb1, 0xee, 0xc5, 0x26, 0xd7, 0x9e, 0x73, 0xd3, 0x58, 0xc3,
+	0xf1, 0x38, 0x3f, 0xce, 0x73, 0x1c, 0xf3, 0x62, 0x1d, 0xb6, 0xeb, 0x94,
+	0x91, 0xf1, 0x77, 0x58, 0x8f, 0x77, 0x77, 0xac, 0x87, 0x98, 0xf5, 0x88,
+	0x4a, 0xf7, 0xba, 0xf2, 0xd1, 0x15, 0x0d, 0xf4, 0x6b, 0x1c, 0xd0, 0xbf,
+	0xbc, 0x26, 0x93, 0x0c, 0x60, 0xd1, 0x36, 0x20, 0x2f, 0xd3, 0x2d, 0xa3,
+	0xfe, 0x05, 0xc8, 0x55, 0x11, 0xb2, 0x40, 0x1f, 0xe5, 0xa5, 0xaa, 0x5e,
+	0x8b, 0x62, 0x33, 0x26, 0xf6, 0x69, 0x8e, 0x4f, 0x7e, 0x73, 0x6e, 0xae,
+	0x5a, 0x87, 0xf6, 0x75, 0x79, 0xec, 0xba, 0x75, 0xd9, 0x84, 0x1e, 0xa5,
+	0x1e, 0x20, 0x16, 0xa3, 0x2e, 0x08, 0xe3, 0x10, 0x7f, 0xe4, 0xea, 0xfd,
+	0x14, 0xda, 0xc4, 0xcb, 0x2d, 0xcc, 0xfb, 0xa2, 0xf2, 0x1d, 0xf4, 0x9c,
+	0xf2, 0x19, 0xe8, 0xa5, 0xb5, 0x1b, 0xb0, 0x77, 0x68, 0x13, 0x37, 0x83,
+	0x5a, 0xb5, 0x4b, 0xd1, 0x90, 0xf7, 0xfb, 0x89, 0xdf, 0x44, 0xdb, 0x01,
+	0xa6, 0xcc, 0xa7, 0x8d, 0x44, 0x59, 0x86, 0x6b, 0x89, 0xf7, 0x06, 0xdf,
+	0xdb, 0xf5, 0xfe, 0x7f, 0x72, 0xf4, 0x7e, 0x64, 0xec, 0x69, 0x2f, 0x3b,
+	0x78, 0x35, 0xe6, 0xe0, 0xc0, 0x57, 0x2e, 0xaf, 0x05, 0xc0, 0x63, 0xef,
+	0xc1, 0xde, 0xce, 0x49, 0xd1, 0x85, 0x1d, 0x1f, 0xbf, 0x19, 0x7c, 0x9d,
+	0x16, 0x15, 0x67, 0x18, 0xdf, 0x8f, 0xe7, 0x7d, 0xca, 0xa7, 0x29, 0x8e,
+	0xbf, 0x57, 0x72, 0x73, 0xc4, 0x43, 0x8f, 0xcb, 0x3c, 0x6c, 0x6e, 0x71,
+	0x1c, 0x36, 0x31, 0xce, 0x77, 0xe8, 0x25, 0x6f, 0x8c, 0xb1, 0x09, 0xfc,
+	0xfd, 0x1b, 0x13, 0x93, 0x39, 0x88, 0xf7, 0x7d, 0xa8, 0xf3, 0x31, 0x53,
+	0xa7, 0x7f, 0x8f, 0x3a, 0x79, 0xbc, 0xdf, 0x8d, 0x3a, 0x31, 0x8c, 0x01,
+	0x4c, 0x0b, 0x5b, 0x66, 0x7b, 0x1f, 0x46, 0xde, 0x5d, 0xc8, 0xbb, 0x0b,
+	0x79, 0x77, 0xe0, 0xbd, 0x60, 0x62, 0x1d, 0x61, 0x9b, 0x7e, 0xbc, 0x7f,
+	0x01, 0xe5, 0xd0, 0x33, 0xee, 0x25, 0x94, 0xdf, 0xad, 0xda, 0x5d, 0x5b,
+	0x67, 0xb0, 0xe3, 0x7d, 0xcb, 0xd1, 0xb1, 0x11, 0xe6, 0x0d, 0x9b, 0x67,
+	0xb1, 0x96, 0x2b, 0x7c, 0xff, 0xa1, 0x79, 0xbf, 0xb7, 0x23, 0xff, 0x71,
+	0xf3, 0xde, 0xb9, 0xae, 0xb7, 0x61, 0x5d, 0x59, 0xfe, 0xd1, 0x03, 0x7a,
+	0x3d, 0xc6, 0x74, 0xfc, 0xe1, 0x1a, 0x3c, 0xa2, 0x44, 0x11, 0xcf, 0x3b,
+	0xc0, 0x21, 0xc4, 0x26, 0xed, 0xb8, 0x84, 0x34, 0xa9, 0xfa, 0x66, 0x9c,
+	0xe7, 0xfa, 0xc3, 0x71, 0xcb, 0x90, 0x81, 0xc3, 0x6b, 0x61, 0xfe, 0xc5,
+	0xfe, 0x6b, 0xe9, 0xf9, 0x9f, 0x6d, 0xf5, 0xf6, 0xcb, 0xe1, 0x5a, 0x98,
+	0x7f, 0xe8, 0xc0, 0xb5, 0xf5, 0x6e, 0x3e, 0x70, 0x75, 0xae, 0xad, 0x78,
+	0x09, 0x68, 0xfb, 0x8c, 0x7d, 0x15, 0x2b, 0xe5, 0xec, 0xc5, 0xe6, 0x8c,
+	0xad, 0x69, 0x62, 0x1d, 0x94, 0x35, 0x77, 0x06, 0x1c, 0x25, 0xa3, 0x39,
+	0x9b, 0x7e, 0x4a, 0x69, 0x83, 0xcf, 0x37, 0x23, 0x6d, 0x6f, 0x3b, 0x0c,
+	0x7d, 0x9b, 0xb3, 0xf5, 0x9c, 0x3a, 0xdb, 0x87, 0xf2, 0xed, 0xcb, 0x52,
+	0x0d, 0x32, 0xe9, 0xa5, 0xc6, 0x4b, 0xf0, 0x73, 0x17, 0xfc, 0xd4, 0x1c,
+	0x65, 0x16, 0xbe, 0xf0, 0x23, 0x22, 0xb3, 0x52, 0xae, 0x3d, 0x08, 0xec,
+	0x1e, 0xc8, 0x87, 0x60, 0xff, 0xff, 0x25, 0xf0, 0x43, 0x1d, 0xba, 0xa0,
+	0xde, 0xf4, 0xf0, 0x1b, 0x96, 0xaf, 0x57, 0x12, 0xf2, 0x3c, 0x7c, 0x91,
+	0xc6, 0x1a, 0xf5, 0x65, 0xda, 0xfd, 0x90, 0xc8, 0x80, 0x2d, 0xe7, 0xef,
+	0xb2, 0x65, 0x22, 0x39, 0x62, 0xa5, 0x13, 0xf8, 0xb9, 0xdd, 0xf8, 0xcd,
+	0xc0, 0xff, 0xdb, 0x68, 0x32, 0x8e, 0x10, 0x97, 0x3f, 0xdf, 0x4c, 0xe2,
+	0x37, 0x24, 0xff, 0x7e, 0x93, 0xe3, 0x8f, 0x98, 0x34, 0xf4, 0x4d, 0xbe,
+	0x05, 0x1d, 0x71, 0x29, 0x58, 0xae, 0x32, 0x26, 0x14, 0xda, 0xa1, 0x6f,
+	0x29, 0x3b, 0xb4, 0x54, 0x09, 0x8e, 0x6b, 0x1f, 0xdc, 0x83, 0xcf, 0x8d,
+	0xf7, 0xe6, 0x5b, 0x56, 0xa3, 0x35, 0xc7, 0x1d, 0xab, 0x61, 0xd6, 0xad,
+	0xd1, 0x9a, 0x23, 0xca, 0x9b, 0x17, 0x20, 0x0b, 0xd4, 0xbf, 0xa1, 0xee,
+	0xf5, 0x0c, 0x2e, 0x0a, 0xf5, 0x2f, 0xf6, 0x70, 0x4d, 0xa2, 0xf1, 0xec,
+	0x2f, 0x64, 0xed, 0x34, 0xf7, 0x14, 0xed, 0xe5, 0x34, 0x64, 0x31, 0xf5,
+	0x95, 0x12, 0x71, 0xb6, 0xc7, 0x98, 0xc0, 0x25, 0xf4, 0x31, 0x3f, 0xa8,
+	0x65, 0xe7, 0x12, 0xf6, 0xf9, 0xac, 0x38, 0xa7, 0x3f, 0xdf, 0x25, 0xfd,
+	0xc7, 0x65, 0xd9, 0x87, 0x3f, 0x6b, 0x97, 0x82, 0x88, 0xe7, 0x25, 0x0a,
+	0xca, 0xdf, 0x5a, 0x03, 0x5d, 0xdf, 0x03, 0x26, 0x3e, 0xae, 0xfc, 0xba,
+	0x63, 0x35, 0xd6, 0xed, 0xc6, 0x7a, 0xa4, 0x4a, 0x05, 0xac, 0xd5, 0x89,
+	0xf8, 0x05, 0x94, 0x05, 0x81, 0xed, 0x0d, 0x48, 0xb1, 0x1e, 0x3e, 0x43,
+	0xf6, 0x37, 0xff, 0x01, 0x32, 0xc6, 0x67, 0xc0, 0xc4, 0x75, 0x96, 0x8d,
+	0x20, 0x65, 0x39, 0xcb, 0x3c, 0xa5, 0xeb, 0x8a, 0x4d, 0xd2, 0x31, 0x2b,
+	0x85, 0x1a, 0xe7, 0x04, 0xbb, 0x58, 0xbf, 0x14, 0x9c, 0xa8, 0x5e, 0x00,
+	0xaf, 0x38, 0x5e, 0x56, 0x1a, 0x58, 0x8b, 0x72, 0xf3, 0x71, 0x60, 0xfa,
+	0xd7, 0x91, 0x2e, 0x22, 0xbd, 0x8c, 0xf4, 0x09, 0xa4, 0x6f, 0x20, 0xe5,
+	0xbc, 0x1e, 0x97, 0x46, 0x3d, 0xd1, 0x2d, 0x31, 0xf6, 0xf3, 0xd9, 0xd6,
+	0x7c, 0xca, 0xd0, 0x0d, 0xb9, 0x56, 0x3e, 0x9f, 0x99, 0x7e, 0x02, 0xe9,
+	0x47, 0x91, 0xf7, 0x3d, 0x3c, 0x4f, 0x4b, 0xa1, 0xf2, 0x04, 0xec, 0x30,
+	0xb1, 0xea, 0x27, 0x30, 0x2e, 0xc7, 0x7f, 0x19, 0x74, 0xb0, 0x2c, 0x90,
+	0x4f, 0x62, 0x9e, 0xf9, 0xda, 0x71, 0x79, 0xd8, 0xbf, 0x45, 0xa6, 0x1e,
+	0x26, 0x3d, 0xe4, 0x0d, 0xf5, 0xdb, 0x5e, 0xbc, 0x21, 0x5f, 0x42, 0x7e,
+	0xf4, 0x61, 0x5e, 0xd4, 0x55, 0xc4, 0xc6, 0x10, 0xc0, 0x7e, 0x8d, 0x77,
+	0x46, 0xc6, 0x02, 0x79, 0xc8, 0xcf, 0x4a, 0xe4, 0xf4, 0x98, 0x9b, 0xb1,
+	0x27, 0xe0, 0xf9, 0xa4, 0xf1, 0x3b, 0x0e, 0xb9, 0xf4, 0x4e, 0x8d, 0xd8,
+	0x23, 0xa0, 0x09, 0x65, 0x0d, 0x8e, 0x73, 0x29, 0xf8, 0x93, 0xea, 0xab,
+	0xf0, 0xdb, 0xb3, 0x72, 0xa5, 0xf9, 0x2a, 0xe4, 0x83, 0xf4, 0x08, 0xe8,
+	0x9c, 0x95, 0x1f, 0xd7, 0x5e, 0x96, 0x93, 0xe0, 0xfd, 0x6b, 0x48, 0x97,
+	0x6b, 0x25, 0xf0, 0x95, 0xf1, 0x7b, 0xf6, 0x11, 0x60, 0xcd, 0x46, 0xe1,
+	0x6f, 0xdd, 0x96, 0x58, 0xc4, 0xfa, 0xce, 0xbb, 0x81, 0x6c, 0xf9, 0x25,
+	0xd9, 0x9a, 0x46, 0x9b, 0x3a, 0xdb, 0xf7, 0xca, 0x61, 0x95, 0x52, 0xfe,
+	0xfa, 0x31, 0xc7, 0x98, 0xe2, 0xf3, 0x72, 0x35, 0x94, 0x3d, 0xca, 0x61,
+	0xa7, 0xfc, 0x91, 0xee, 0x1d, 0xeb, 0x9b, 0x4d, 0xda, 0xd1, 0xbd, 0x6c,
+	0x62, 0x28, 0x97, 0xb4, 0x8b, 0xed, 0xb2, 0x29, 0xd2, 0xa8, 0x69, 0xff,
+	0xe6, 0x1b, 0xdb, 0x4a, 0xd6, 0xb1, 0x3e, 0xc4, 0xd3, 0x3f, 0x17, 0xe0,
+	0x37, 0xf0, 0x29, 0x8c, 0x2f, 0x6a, 0xbf, 0xab, 0x0e, 0x7a, 0xe1, 0x6b,
+	0x00, 0x2b, 0x88, 0xd4, 0xeb, 0x9f, 0x57, 0xfc, 0xf2, 0x4e, 0x0f, 0x4b,
+	0xad, 0x4a, 0x1e, 0xa7, 0x5c, 0xdb, 0x56, 0xfe, 0x0d, 0x78, 0xeb, 0x41,
+	0x56, 0xc2, 0xf2, 0x14, 0xfc, 0xaf, 0xe3, 0xe2, 0x4e, 0xc5, 0x60, 0xbf,
+	0xf8, 0x2c, 0x32, 0x77, 0xae, 0x13, 0x0b, 0x86, 0x36, 0xa6, 0x1b, 0x7e,
+	0x7e, 0x17, 0x74, 0x41, 0x1f, 0xfc, 0x74, 0xf8, 0xbf, 0x90, 0xa7, 0x3f,
+	0x01, 0x7e, 0x3a, 0xa5, 0x7c, 0x76, 0xee, 0xc3, 0x07, 0x67, 0x47, 0x36,
+	0x99, 0x7e, 0x78, 0x36, 0x5d, 0x67, 0x7a, 0xd4, 0xc4, 0xf5, 0x1f, 0x31,
+	0xf1, 0xfe, 0xf9, 0xd9, 0x83, 0x2a, 0x5d, 0x9c, 0x1d, 0x57, 0xe9, 0xe3,
+	0xb3, 0x57, 0x63, 0x31, 0x17, 0x20, 0xab, 0xa4, 0x4d, 0x9c, 0x62, 0x26,
+	0x23, 0x9b, 0x15, 0x1f, 0x7e, 0xf7, 0x34, 0xf0, 0xc7, 0x34, 0xe4, 0x36,
+	0x0b, 0x7a, 0xa1, 0x7f, 0xb2, 0x3e, 0x52, 0x31, 0x7f, 0x61, 0xbb, 0x6e,
+	0xc6, 0xdd, 0xb8, 0x66, 0xc6, 0x77, 0xf5, 0xe9, 0xbb, 0xb6, 0xff, 0xb1,
+	0x4f, 0xc8, 0x38, 0xed, 0xee, 0xaf, 0xe1, 0x6f, 0xb3, 0x7f, 0xb6, 0x65,
+	0xff, 0x22, 0xbb, 0x6b, 0x12, 0x8d, 0x66, 0xff, 0x5a, 0xa2, 0xcf, 0x06,
+	0xc1, 0x4f, 0xfc, 0xd4, 0x91, 0x92, 0x80, 0x4f, 0x16, 0xf2, 0x37, 0x59,
+	0x46, 0x9d, 0x35, 0xe1, 0x5e, 0x81, 0xcc, 0xe5, 0x8e, 0x8a, 0xbc, 0x82,
+	0xbc, 0xc6, 0x1a, 0xf9, 0xff, 0x3d, 0xf0, 0xdf, 0xac, 0x87, 0xca, 0x63,
+	0x3d, 0xf8, 0x48, 0x71, 0xca, 0xdc, 0x84, 0xdb, 0x83, 0xf6, 0xf5, 0x4d,
+	0xb6, 0x49, 0x4d, 0xf3, 0x98, 0xec, 0x95, 0xcd, 0x0b, 0x4a, 0x5f, 0x75,
+	0x67, 0xc7, 0x19, 0x43, 0x92, 0x8d, 0xb5, 0xdf, 0x04, 0x0b, 0xfe, 0x0e,
+	0x80, 0x5a, 0x0a, 0x72, 0x9f, 0x95, 0xf3, 0xc0, 0x58, 0xe7, 0x2b, 0x69,
+	0xac, 0x0d, 0xf0, 0x6d, 0x82, 0x24, 0x7b, 0xa8, 0xf7, 0x66, 0x37, 0x71,
+	0x6c, 0x9e, 0xe7, 0x47, 0x95, 0x69, 0xd9, 0x6d, 0xce, 0x09, 0xb1, 0x52,
+	0x3e, 0xc3, 0xf9, 0xb4, 0xf3, 0x41, 0xff, 0x15, 0xb1, 0x06, 0x66, 0x7e,
+	0xea, 0x0f, 0x74, 0x62, 0x3f, 0xa1, 0xbd, 0xbf, 0x83, 0xbd, 0x91, 0x82,
+	0x7e, 0x15, 0x07, 0x7e, 0xa2, 0xa4, 0xcf, 0x3a, 0x4e, 0xbe, 0xe2, 0xc8,
+	0xc8, 0x59, 0x6c, 0xa9, 0xac, 0xe1, 0x43, 0x33, 0x94, 0xb1, 0x50, 0xe7,
+	0x51, 0xa6, 0x38, 0xff, 0x54, 0x69, 0x07, 0x8c, 0x1e, 0xcc, 0x5e, 0x94,
+	0x87, 0xd7, 0xf5, 0x7c, 0xed, 0x33, 0xc2, 0xb3, 0x13, 0xb9, 0xb2, 0x96,
+	0xf2, 0x2f, 0x0b, 0xfd, 0x5f, 0x1f, 0x32, 0x72, 0xb1, 0x1b, 0xfb, 0x79,
+	0x3a, 0x67, 0x1f, 0xec, 0xd1, 0xb6, 0xd9, 0xc1, 0x1e, 0x00, 0x4e, 0xac,
+	0xc0, 0x6f, 0xf6, 0x7a, 0xe4, 0x5f, 0x38, 0x78, 0x26, 0x6e, 0x44, 0x9e,
+	0xb1, 0xa3, 0x78, 0xd6, 0xfd, 0x95, 0x31, 0x0f, 0x1d, 0x57, 0xb6, 0xe4,
+	0x61, 0x58, 0x15, 0x41, 0xff, 0x23, 0x66, 0xac, 0x91, 0x33, 0x17, 0xd4,
+	0x7e, 0x4d, 0xaf, 0x67, 0x81, 0xa3, 0x1c, 0xe3, 0x6f, 0x52, 0x4f, 0xc9,
+	0x1e, 0xfe, 0x4a, 0x28, 0xa3, 0x17, 0x82, 0x2f, 0x56, 0xc3, 0x98, 0x40,
+	0x46, 0x46, 0x56, 0xb4, 0x4c, 0x3d, 0x9e, 0x81, 0xce, 0x86, 0x2c, 0x8d,
+	0xac, 0x04, 0xf2, 0x13, 0xdf, 0x97, 0x53, 0xdb, 0x7b, 0xc9, 0x54, 0xe7,
+	0x5f, 0x1f, 0xe8, 0xe4, 0x6f, 0x48, 0x96, 0xfe, 0x14, 0x74, 0x9e, 0x75,
+	0xf1, 0x9c, 0x9a, 0x9b, 0xa7, 0x8f, 0x70, 0x16, 0xba, 0x14, 0xbe, 0xac,
+	0x7d, 0x76, 0x58, 0xd5, 0xb1, 0xcf, 0xc2, 0xc6, 0x41, 0xc6, 0x6c, 0xf0,
+	0xb5, 0x0c, 0x7b, 0x67, 0x9f, 0xed, 0x82, 0x5d, 0xe4, 0x1e, 0x95, 0x41,
+	0x1b, 0xba, 0x80, 0xf5, 0x1b, 0xd8, 0x2b, 0xf6, 0xd9, 0x3e, 0xa4, 0x49,
+	0xd5, 0x57, 0xa3, 0xe2, 0xa9, 0xf6, 0x8d, 0xca, 0xb8, 0x6a, 0xd7, 0xa8,
+	0x4c, 0x22, 0x85, 0x8e, 0xcf, 0xf8, 0xd2, 0x7d, 0x36, 0x23, 0x72, 0xd6,
+	0x92, 0xe2, 0x5c, 0x10, 0xc4, 0x40, 0x7b, 0xec, 0xec, 0x01, 0xb9, 0xac,
+	0xd6, 0x76, 0x4e, 0x46, 0x9e, 0x25, 0xbf, 0xb2, 0xa8, 0x3b, 0x23, 0xe9,
+	0x67, 0x67, 0xc4, 0x7b, 0x96, 0x3c, 0x61, 0xac, 0x7e, 0x57, 0xc9, 0xd4,
+	0x27, 0xe4, 0x28, 0xec, 0x4a, 0x0f, 0xf6, 0x84, 0xe3, 0x96, 0x65, 0x05,
+	0x6b, 0x32, 0xea, 0x1e, 0x86, 0x9c, 0xc9, 0xdb, 0xd6, 0x67, 0x5d, 0xb6,
+	0x61, 0xfd, 0x83, 0x90, 0x17, 0x0f, 0xf5, 0x8f, 0xc2, 0xc6, 0xb4, 0xf3,
+	0x82, 0xfb, 0x2c, 0xf7, 0x0e, 0xf2, 0x17, 0xee, 0xaf, 0x0b, 0xc1, 0xc9,
+	0x2a, 0xf7, 0x18, 0xf7, 0xd7, 0x87, 0xe4, 0x15, 0x6f, 0x4e, 0x76, 0xbd,
+	0x8c, 0x5c, 0x00, 0x0e, 0x7d, 0xd9, 0x9b, 0x91, 0x8b, 0x5e, 0xb4, 0x87,
+	0x31, 0xb6, 0x06, 0x71, 0x72, 0x6b, 0xcd, 0xe2, 0xc6, 0x1f, 0x79, 0x43,
+	0xb6, 0x2a, 0xb4, 0xd5, 0xc1, 0xa1, 0x05, 0xbf, 0x74, 0x33, 0x68, 0x03,
+	0x1d, 0x8c, 0x1b, 0x5c, 0xb5, 0x11, 0x5d, 0xd8, 0x43, 0x1b, 0xca, 0x46,
+	0xf4, 0xd1, 0x46, 0xf8, 0x05, 0xd9, 0x2f, 0xbb, 0x35, 0x1d, 0xd3, 0xcb,
+	0x03, 0x43, 0xed, 0xd6, 0xb9, 0xfe, 0x71, 0xf9, 0x52, 0x95, 0x73, 0x2d,
+	0xdf, 0x10, 0x93, 0x88, 0x1c, 0x51, 0x36, 0xbb, 0x5f, 0xce, 0x6f, 0x02,
+	0xf3, 0x02, 0x7d, 0xd8, 0xb7, 0x32, 0x26, 0x64, 0xab, 0x18, 0x83, 0x0c,
+	0xd0, 0x66, 0xfd, 0x17, 0xf0, 0x88, 0x71, 0x20, 0xcc, 0x71, 0x80, 0xb3,
+	0x09, 0xdf, 0x27, 0x65, 0xb7, 0xc2, 0x67, 0x4b, 0x0a, 0xf0, 0x27, 0x77,
+	0x2b, 0x4c, 0x13, 0x48, 0x4d, 0x8c, 0x5f, 0x61, 0xf8, 0xbf, 0x55, 0xe5,
+	0x3d, 0xde, 0x2c, 0xd6, 0x85, 0x72, 0x8b, 0x74, 0x4b, 0x8f, 0x5b, 0x80,
+	0xcf, 0x5f, 0x9c, 0xec, 0xa5, 0xfd, 0x02, 0x6e, 0x72, 0x64, 0x5e, 0xd5,
+	0xcf, 0xc8, 0xc5, 0xca, 0xcf, 0xcc, 0x3e, 0x99, 0x36, 0xcf, 0x2c, 0x67,
+	0xac, 0x87, 0x3e, 0xcd, 0x91, 0xd9, 0x65, 0xef, 0x03, 0xa6, 0x5c, 0xc5,
+	0x5c, 0xac, 0x0f, 0x02, 0x43, 0x8e, 0xac, 0x74, 0x63, 0x3e, 0xf6, 0x90,
+	0x3e, 0x93, 0x39, 0x24, 0x33, 0xfe, 0x41, 0xd0, 0x7f, 0x40, 0xca, 0xf0,
+	0x95, 0x96, 0xb6, 0xa1, 0x57, 0xc6, 0xe1, 0x13, 0xbb, 0xb7, 0x13, 0xa3,
+	0xa9, 0x98, 0x52, 0xd9, 0x1d, 0x45, 0xda, 0x83, 0xf4, 0x66, 0x29, 0x3f,
+	0x73, 0x43, 0x54, 0xf7, 0xd7, 0xd5, 0xf1, 0xfe, 0x3c, 0xc7, 0x4e, 0x26,
+	0xad, 0xdf, 0x86, 0x07, 0xdb, 0xb1, 0x20, 0xe9, 0xe8, 0x12, 0xef, 0xcb,
+	0x7d, 0x32, 0xba, 0xe2, 0xca, 0xd8, 0x4a, 0x42, 0x0e, 0xae, 0x0c, 0xcb,
+	0xf8, 0x4a, 0x52, 0x6e, 0x5d, 0x09, 0xf1, 0xd8, 0x83, 0xb3, 0x69, 0x63,
+	0x07, 0xbc, 0xdf, 0xd1, 0x0e, 0xdc, 0xda, 0xd4, 0xd8, 0xb4, 0xbc, 0x71,
+	0x01, 0x36, 0x7b, 0x07, 0xfb, 0x37, 0x03, 0x2c, 0xe6, 0x43, 0x27, 0x4d,
+	0x42, 0x27, 0x8d, 0x43, 0x27, 0x4d, 0x53, 0x27, 0x01, 0xff, 0xbd, 0x0a,
+	0xfc, 0x77, 0x8f, 0xbc, 0x06, 0x9d, 0xfb, 0x82, 0xdf, 0xe3, 0xce, 0x81,
+	0x1f, 0x87, 0xd5, 0xb9, 0x57, 0xea, 0x2b, 0x3b, 0x90, 0x81, 0xc6, 0xd7,
+	0x24, 0x3a, 0x00, 0x7d, 0x75, 0xfb, 0x7a, 0x8f, 0x6c, 0xc4, 0x83, 0xe0,
+	0x34, 0xf6, 0xfa, 0x95, 0x8a, 0x96, 0xd9, 0xbc, 0xc7, 0x3d, 0xff, 0x20,
+	0xe6, 0x3e, 0x89, 0xbc, 0x1c, 0x74, 0x98, 0x8e, 0xa3, 0x34, 0x8e, 0x26,
+	0x64, 0xf3, 0xe0, 0x74, 0x47, 0xbd, 0x0c, 0xde, 0xa9, 0x33, 0xfe, 0x39,
+	0xea, 0x53, 0x7f, 0xbb, 0xb2, 0x05, 0x8c, 0x78, 0xe6, 0x60, 0x6a, 0x3a,
+	0x69, 0x53, 0xdf, 0x25, 0xa5, 0xfe, 0xb5, 0x84, 0x6c, 0x54, 0xb5, 0xcd,
+	0x59, 0x00, 0x26, 0x2c, 0x00, 0xef, 0x6e, 0x00, 0x67, 0x15, 0x9a, 0x5a,
+	0xdf, 0xdb, 0xd9, 0x2e, 0x61, 0x7f, 0x85, 0x66, 0x1e, 0xf8, 0x58, 0x9c,
+	0x7c, 0x86, 0x74, 0x4e, 0x24, 0x22, 0x76, 0x0f, 0x64, 0x81, 0xfb, 0xe3,
+	0x41, 0xd8, 0x53, 0x96, 0xd1, 0x36, 0x53, 0xff, 0x3f, 0x15, 0x25, 0xc6,
+	0x2b, 0xf8, 0xc4, 0xd3, 0x79, 0x94, 0xa5, 0x12, 0x69, 0xe4, 0xcf, 0x49,
+	0x5a, 0x9d, 0x21, 0x2d, 0x60, 0xcf, 0x97, 0x15, 0xcd, 0x11, 0xc6, 0xa4,
+	0x28, 0x1e, 0x51, 0x1d, 0x2f, 0x0c, 0xf3, 0x27, 0xdc, 0x22, 0xd6, 0x38,
+	0xc7, 0xbe, 0xab, 0xcc, 0x4b, 0xbb, 0x6c, 0x57, 0xf0, 0xf9, 0x2e, 0xf2,
+	0x91, 0x26, 0xe3, 0x27, 0x51, 0x79, 0xb8, 0xd9, 0x07, 0x9a, 0xba, 0x7f,
+	0x8b, 0x3d, 0x71, 0xdb, 0xec, 0xc9, 0x6e, 0xc2, 0x85, 0x9e, 0x58, 0x34,
+	0x7a, 0xc5, 0x99, 0xd2, 0x18, 0xf8, 0xa5, 0x2a, 0xd6, 0xa8, 0x8a, 0x35,
+	0xaa, 0x62, 0x8d, 0xaa, 0x58, 0xa3, 0x2a, 0xf5, 0x07, 0x75, 0x4d, 0xce,
+	0x9c, 0x31, 0x50, 0x87, 0x3c, 0x8f, 0xb5, 0x9c, 0x93, 0x6f, 0x6f, 0xcf,
+	0xca, 0x5f, 0x6c, 0x1f, 0x01, 0xc6, 0x9e, 0xc1, 0xba, 0xe6, 0xb0, 0xae,
+	0xd3, 0x58, 0xd3, 0xa3, 0x58, 0xd3, 0x2c, 0xcf, 0xd9, 0xe4, 0xcb, 0x95,
+	0xd4, 0x0b, 0x25, 0x85, 0xef, 0xdf, 0xc0, 0xfa, 0x4e, 0x89, 0xb7, 0x3e,
+	0x0c, 0x9d, 0x50, 0x0a, 0xe2, 0x5e, 0x70, 0x08, 0x18, 0x1a, 0xf3, 0x2f,
+	0xa5, 0x1c, 0x45, 0x83, 0xe7, 0x7e, 0x0a, 0x13, 0xbf, 0x21, 0x9b, 0xaa,
+	0x51, 0x3d, 0x6d, 0xd5, 0xc6, 0xa5, 0x78, 0x0e, 0xf5, 0x4f, 0xf7, 0x81,
+	0xdf, 0xc4, 0x6f, 0xa9, 0x52, 0x51, 0x76, 0xa0, 0xcf, 0x72, 0xa0, 0xf1,
+	0xbd, 0x52, 0x8e, 0xa7, 0x9e, 0xe7, 0x3e, 0xbb, 0x71, 0x95, 0xf1, 0x01,
+	0x1b, 0xbc, 0x21, 0xed, 0x78, 0x3e, 0x97, 0x55, 0x31, 0xbe, 0xbc, 0x7f,
+	0xc0, 0xec, 0x63, 0x8d, 0x49, 0xeb, 0xc2, 0x71, 0x39, 0xde, 0x67, 0x64,
+	0x11, 0xb8, 0xcf, 0xce, 0x12, 0x57, 0x78, 0x09, 0x8c, 0x19, 0x5d, 0x38,
+	0xe7, 0x46, 0x17, 0xcf, 0xb1, 0x9f, 0xa8, 0xa4, 0x57, 0xa9, 0x97, 0xd8,
+	0x0f, 0x74, 0x36, 0xfa, 0x8e, 0xa8, 0x33, 0xb5, 0x09, 0xb4, 0xfb, 0x03,
+	0x60, 0x46, 0xcd, 0xc3, 0xfc, 0x69, 0x6d, 0xc7, 0xf2, 0x8d, 0x76, 0xcc,
+	0x06, 0x1d, 0x02, 0x3b, 0x97, 0x6b, 0x68, 0xfc, 0x35, 0xa3, 0xf0, 0x99,
+	0xc6, 0x66, 0x47, 0xe5, 0x50, 0xaf, 0xc4, 0x3c, 0x35, 0x9f, 0xf4, 0xe9,
+	0x1d, 0x62, 0x52, 0x8c, 0xa1, 0xe3, 0xcc, 0x57, 0xe9, 0xce, 0x60, 0x2e,
+	0x37, 0xf7, 0x86, 0x31, 0x41, 0x7b, 0x55, 0x9f, 0x41, 0xd9, 0xe7, 0x7c,
+	0xcc, 0x47, 0x86, 0x18, 0x65, 0xb4, 0x31, 0x87, 0x7b, 0x95, 0x9d, 0x9d,
+	0x62, 0xec, 0x0f, 0xb2, 0x4d, 0xfd, 0x32, 0x84, 0xbd, 0xc1, 0x77, 0x1d,
+	0x53, 0xee, 0xf1, 0x28, 0x2f, 0x71, 0xc8, 0x20, 0x74, 0x4d, 0xff, 0xb0,
+	0xd4, 0xb7, 0x59, 0x36, 0xac, 0xf4, 0xb0, 0x83, 0x35, 0x58, 0xae, 0x04,
+	0x87, 0xf2, 0x7e, 0x09, 0xda, 0x92, 0x3c, 0x27, 0x3f, 0xc8, 0xf7, 0x49,
+	0xd0, 0x46, 0x1e, 0xf7, 0x97, 0xf4, 0xb9, 0xe6, 0x7e, 0x29, 0xd6, 0xa8,
+	0x8b, 0x91, 0xd6, 0xf7, 0x9b, 0xd8, 0x46, 0x5c, 0x72, 0x73, 0x9c, 0x3b,
+	0x7d, 0x13, 0xa0, 0xba, 0xd5, 0x94, 0x5f, 0xb7, 0x67, 0xa5, 0x48, 0xf9,
+	0x84, 0x6e, 0x2c, 0x6e, 0x4e, 0xc9, 0xf2, 0x1a, 0xe3, 0x7d, 0x3c, 0x7b,
+	0x9e, 0x88, 0x4a, 0x7f, 0x10, 0x6c, 0xf9, 0xb4, 0xf3, 0x79, 0x29, 0x20,
+	0xdf, 0x5e, 0x87, 0x9d, 0x3f, 0xaa, 0x79, 0xc7, 0xf9, 0x96, 0x37, 0xfe,
+	0x6f, 0xf8, 0xf8, 0xf6, 0x38, 0x77, 0x66, 0x0f, 0x9c, 0xfb, 0xea, 0x39,
+	0xc8, 0x5f, 0x15, 0xb2, 0x09, 0x9f, 0xe9, 0x2f, 0xaa, 0x90, 0x4d, 0xd8,
+	0x8c, 0x6f, 0x56, 0x21, 0x9b, 0xd8, 0x3b, 0x2f, 0xc2, 0xa7, 0xd1, 0x98,
+	0xe2, 0x11, 0x85, 0x29, 0x4e, 0x54, 0x89, 0xf9, 0x2f, 0x41, 0x96, 0x27,
+	0x21, 0xc7, 0x49, 0xc8, 0xaf, 0x0f, 0xd9, 0x1d, 0x87, 0x3c, 0x7b, 0x90,
+	0xe7, 0x61, 0x15, 0xf7, 0x79, 0x61, 0x3b, 0x2a, 0xf7, 0xc3, 0x9f, 0x38,
+	0x53, 0x23, 0x1f, 0x8f, 0xcb, 0xff, 0x82, 0x2f, 0xb1, 0xeb, 0xef, 0x80,
+	0x87, 0x39, 0x59, 0xf4, 0xc8, 0xaf, 0x9c, 0xbd, 0xe0, 0xd1, 0xd7, 0x70,
+	0xe5, 0xcc, 0x06, 0x7d, 0x04, 0xea, 0x88, 0x57, 0xe5, 0x9b, 0x95, 0x1f,
+	0xc8, 0xb7, 0x80, 0x05, 0x0a, 0xf0, 0x9b, 0x37, 0x9e, 0xa1, 0xcf, 0xa8,
+	0x68, 0x84, 0xdc, 0xc5, 0x65, 0x73, 0xfb, 0x76, 0x79, 0xca, 0xa5, 0x0c,
+	0xc7, 0xa1, 0x5b, 0xf0, 0x7e, 0x90, 0x7a, 0x28, 0x83, 0xfd, 0x09, 0x39,
+	0x87, 0x6e, 0xa8, 0xd9, 0x3c, 0xc3, 0x28, 0x05, 0x03, 0xd4, 0x59, 0x35,
+	0xcf, 0x1d, 0xb1, 0xc9, 0x9b, 0x5b, 0x18, 0x73, 0xfa, 0x0a, 0x84, 0x17,
+	0x79, 0xb4, 0xd9, 0x48, 0xeb, 0xd0, 0x8d, 0xcf, 0x90, 0x8f, 0xf4, 0x61,
+	0xf1, 0xbc, 0xc1, 0xbd, 0xf6, 0x73, 0x15, 0xcb, 0x2d, 0xce, 0xc1, 0x5f,
+	0xdf, 0x20, 0x9f, 0x20, 0x2b, 0xcf, 0x90, 0x8f, 0xe4, 0x9d, 0xe6, 0xe3,
+	0x43, 0x12, 0xf2, 0x90, 0x65, 0x9d, 0x3c, 0xfc, 0x77, 0x90, 0xc3, 0x38,
+	0xe6, 0xfd, 0xd5, 0x28, 0x63, 0x8e, 0x37, 0x7a, 0x5c, 0xf3, 0x57, 0xe5,
+	0xc9, 0x26, 0xc7, 0x7a, 0xd9, 0x8c, 0xf9, 0xfd, 0xe0, 0xe1, 0x38, 0x69,
+	0xe7, 0x7a, 0xee, 0x93, 0xc6, 0x90, 0x6f, 0xe2, 0x2a, 0xbf, 0xcd, 0xde,
+	0xb0, 0x1e, 0x78, 0x0d, 0xbd, 0xf2, 0xad, 0x2a, 0x78, 0x0c, 0xbf, 0xe9,
+	0x1b, 0xf0, 0x9b, 0x18, 0x6b, 0xd4, 0xeb, 0x32, 0x6d, 0xe2, 0xa6, 0x9d,
+	0xf1, 0xd2, 0x24, 0xd6, 0x85, 0xbe, 0x79, 0xaa, 0x74, 0x19, 0xba, 0xef,
+	0x45, 0x9f, 0x71, 0xc4, 0x40, 0xbe, 0xef, 0xb7, 0x6b, 0x37, 0x15, 0x63,
+	0x96, 0x87, 0xa0, 0x0f, 0x1f, 0x86, 0x3e, 0xfc, 0xc8, 0x75, 0xf7, 0x7b,
+	0x28, 0x67, 0x4f, 0xcf, 0x2e, 0xac, 0x8d, 0x96, 0x22, 0xf6, 0xb0, 0xcc,
+	0x5d, 0xa3, 0x1b, 0x19, 0x4f, 0x4c, 0x9a, 0x78, 0x68, 0x3b, 0xfe, 0x0c,
+	0x63, 0x9e, 0x94, 0xe7, 0x40, 0x2e, 0xfa, 0xa5, 0xbe, 0x88, 0x3a, 0x97,
+	0xe6, 0xba, 0xee, 0x85, 0x2d, 0xbf, 0x6d, 0xf6, 0x30, 0x65, 0xab, 0xf3,
+	0xdc, 0x98, 0xe7, 0xd0, 0xfd, 0xf0, 0x13, 0xb8, 0x57, 0x53, 0xc9, 0x1c,
+	0xf6, 0x73, 0x79, 0x9b, 0xfa, 0x9f, 0xd8, 0xb0, 0x9b, 0xf1, 0xbc, 0xf9,
+	0x9e, 0x2c, 0x63, 0x01, 0xfd, 0xf0, 0x3f, 0x7e, 0x24, 0x5b, 0x6b, 0x7f,
+	0xd3, 0xab, 0xf7, 0x91, 0xbe, 0x6f, 0x66, 0x9f, 0xeb, 0x8c, 0x63, 0xd2,
+	0xa6, 0x4a, 0xb4, 0x17, 0x76, 0xf1, 0xd6, 0x67, 0xfb, 0x95, 0xdd, 0xbb,
+	0xcf, 0x77, 0x64, 0x27, 0xce, 0xfe, 0x7e, 0x24, 0x3f, 0x5e, 0x1b, 0x89,
+	0x31, 0xfe, 0xb9, 0x0c, 0x3e, 0xef, 0x2a, 0xdd, 0xf5, 0x20, 0xea, 0x64,
+	0xe5, 0xf5, 0x35, 0xda, 0xd6, 0xb4, 0x7b, 0x46, 0x26, 0x12, 0x67, 0xc0,
+	0xcb, 0x53, 0x68, 0x03, 0x7f, 0x38, 0x98, 0x41, 0xde, 0xcb, 0xf4, 0xb9,
+	0x2d, 0x3e, 0x4f, 0xb8, 0x5f, 0x04, 0x4e, 0xce, 0xb9, 0x69, 0xb7, 0xd7,
+	0xba, 0xa4, 0xce, 0x9d, 0x22, 0x1e, 0xfb, 0x1a, 0x92, 0xc2, 0xa6, 0xa6,
+	0xf1, 0xca, 0x26, 0xc7, 0xe0, 0x5c, 0x48, 0xe3, 0xdf, 0xf0, 0x5c, 0x01,
+	0xf4, 0xdf, 0x06, 0x9f, 0x84, 0x98, 0xe5, 0x12, 0x64, 0x66, 0x08, 0xfa,
+	0x81, 0xbe, 0x0a, 0xcf, 0x2c, 0xc9, 0xb3, 0xcf, 0x03, 0xef, 0xc7, 0x21,
+	0xab, 0xc8, 0xdf, 0xbc, 0xea, 0x1f, 0x2e, 0xb7, 0x70, 0x3d, 0x6d, 0xe3,
+	0x2c, 0x6c, 0xe4, 0xbb, 0x14, 0x3d, 0x47, 0x7c, 0xf8, 0xda, 0xcf, 0x50,
+	0xbe, 0x0e, 0x4a, 0x31, 0x4e, 0x5c, 0x49, 0x7d, 0xb2, 0x9b, 0x88, 0x02,
+	0xd7, 0x46, 0x6f, 0xe7, 0xbe, 0x3b, 0x22, 0xf7, 0x7b, 0x0f, 0xca, 0x07,
+	0xbd, 0x49, 0x99, 0xf1, 0xee, 0x91, 0xc3, 0x5e, 0x5e, 0xee, 0xf3, 0x60,
+	0x9b, 0x14, 0x3e, 0xef, 0xc1, 0x3c, 0x38, 0xf6, 0x90, 0x39, 0xdf, 0xd3,
+	0xf8, 0xf4, 0xeb, 0xdb, 0x5a, 0x27, 0xe5, 0xd7, 0xb2, 0x31, 0xda, 0xe4,
+	0x23, 0xfe, 0x8c, 0xb1, 0xc9, 0xf0, 0xf9, 0x55, 0xbd, 0x19, 0x65, 0xbb,
+	0xcb, 0x9b, 0x73, 0x48, 0x61, 0xc7, 0x37, 0xa7, 0x81, 0xfb, 0xe9, 0x4b,
+	0xe5, 0xf0, 0x7e, 0x0f, 0xde, 0x3f, 0x84, 0xf4, 0x08, 0x52, 0x75, 0xae,
+	0x19, 0xd3, 0xb1, 0xdb, 0xd6, 0xb9, 0x1d, 0xe4, 0xeb, 0xe8, 0xec, 0x42,
+	0x2d, 0x8c, 0x81, 0x1f, 0x92, 0xc7, 0x7d, 0x7d, 0x96, 0x7e, 0x18, 0x7e,
+	0x74, 0x0c, 0xf8, 0xe9, 0x43, 0xcf, 0x4e, 0x49, 0xe4, 0xee, 0x43, 0x62,
+	0xdf, 0x6d, 0xc9, 0xc2, 0x24, 0xe8, 0x9b, 0x1c, 0xc5, 0x3c, 0x86, 0xe5,
+	0xc4, 0xb6, 0xf2, 0x51, 0x0d, 0x5e, 0xa4, 0x1e, 0x07, 0xd6, 0xdd, 0x0e,
+	0x71, 0x63, 0x37, 0x70, 0x05, 0xe3, 0x7b, 0x49, 0x85, 0x77, 0xed, 0x1b,
+	0xb9, 0xbe, 0x7d, 0x92, 0xbf, 0x91, 0xfc, 0x63, 0x1e, 0xfc, 0x9d, 0x1b,
+	0xb5, 0xdd, 0x48, 0xaf, 0x70, 0x6d, 0x7a, 0x4c, 0xec, 0x96, 0x36, 0x80,
+	0xe9, 0x6a, 0xac, 0x85, 0x0b, 0x19, 0x9f, 0xb1, 0x6e, 0x8f, 0x5d, 0xbd,
+	0x67, 0x16, 0xca, 0x73, 0x78, 0x7f, 0xc0, 0x53, 0x38, 0xe7, 0x44, 0xf5,
+	0x05, 0xcc, 0x81, 0x36, 0x3d, 0x22, 0xdd, 0xd0, 0x6b, 0x5b, 0x1e, 0xf7,
+	0x1e, 0x6d, 0xce, 0x11, 0xcc, 0x87, 0x36, 0x9e, 0xb6, 0xfe, 0xde, 0x7e,
+	0xe9, 0xa7, 0x9d, 0x67, 0xfd, 0x24, 0xca, 0x58, 0x97, 0x79, 0x97, 0x51,
+	0x9f, 0xb1, 0x29, 0xf8, 0x3e, 0xd5, 0x45, 0xe8, 0x19, 0x0f, 0xe9, 0xe3,
+	0x48, 0xc7, 0x91, 0x3e, 0x81, 0x54, 0xc7, 0xb1, 0x36, 0x9f, 0x61, 0x2c,
+	0x49, 0xc5, 0x68, 0x14, 0xbe, 0xa0, 0x4d, 0x9c, 0xf3, 0xa9, 0x27, 0x8f,
+	0x8b, 0x3d, 0x75, 0x1b, 0xf2, 0xe8, 0x6b, 0x63, 0xd4, 0xf7, 0x7f, 0xde,
+	0xc4, 0x88, 0x5a, 0x71, 0x25, 0x63, 0x07, 0xd6, 0xd0, 0x17, 0xfb, 0xa1,
+	0x2f, 0xfb, 0x0b, 0x79, 0xf8, 0x9a, 0xd8, 0x5c, 0x2b, 0xde, 0x34, 0x5d,
+	0x50, 0x3a, 0x96, 0x7c, 0x81, 0x7e, 0x75, 0x33, 0xf2, 0xb5, 0xed, 0x01,
+	0xe8, 0xaf, 0x38, 0xb1, 0x26, 0xf0, 0xb6, 0xc6, 0x6e, 0x8b, 0x98, 0x9b,
+	0xb6, 0xef, 0x71, 0xf9, 0xbb, 0xb5, 0x61, 0xf9, 0x71, 0x25, 0x21, 0xaf,
+	0x57, 0x82, 0xe0, 0xa2, 0x9f, 0xf6, 0xef, 0x13, 0xb9, 0xbd, 0x5b, 0x9f,
+	0xfd, 0xa3, 0x86, 0x3e, 0xaf, 0x2f, 0xab, 0x33, 0x7b, 0xd4, 0x83, 0x5e,
+	0x79, 0xbd, 0xf9, 0xf7, 0xe0, 0xaf, 0xee, 0xb3, 0xb3, 0xed, 0xae, 0x6e,
+	0xcb, 0x33, 0xff, 0xc4, 0x8e, 0xa4, 0xcd, 0xdd, 0x81, 0x34, 0xda, 0xa6,
+	0xc7, 0x37, 0x5a, 0xed, 0xd9, 0x36, 0xa3, 0xec, 0x40, 0x71, 0x73, 0x50,
+	0x1a, 0x7f, 0xca, 0xfd, 0x01, 0xbf, 0x53, 0x9d, 0xcb, 0x30, 0xe5, 0x39,
+	0x07, 0xeb, 0x24, 0x4d, 0xf9, 0x88, 0x29, 0xf7, 0x54, 0x6c, 0x70, 0xb9,
+	0x4a, 0x19, 0x85, 0x1f, 0x4a, 0x6c, 0xd8, 0x24, 0x76, 0x0d, 0xe3, 0x61,
+	0xd4, 0xd3, 0xb3, 0x52, 0x56, 0x71, 0x2d, 0xda, 0xa0, 0x5e, 0x15, 0xd3,
+	0xd2, 0xb1, 0x3e, 0x96, 0x3d, 0x2c, 0x73, 0xee, 0x71, 0x19, 0x98, 0xba,
+	0x36, 0x6e, 0xd7, 0xeb, 0x1d, 0x87, 0x6f, 0xa5, 0xec, 0xac, 0xfb, 0x41,
+	0x21, 0x8f, 0xbb, 0x69, 0x17, 0x72, 0xb6, 0x05, 0xdf, 0xf4, 0xcb, 0x19,
+	0x79, 0x7e, 0x3b, 0x95, 0x14, 0xac, 0xd7, 0x07, 0xe1, 0x7b, 0xda, 0xcf,
+	0xe1, 0x9d, 0x71, 0xae, 0x67, 0xe3, 0x12, 0x79, 0x76, 0x58, 0x7a, 0x56,
+	0x88, 0x3f, 0xc8, 0xd3, 0x84, 0x74, 0xaf, 0x10, 0xfb, 0x32, 0x2e, 0x9c,
+	0x9a, 0xbe, 0x22, 0x8c, 0xb7, 0xa4, 0xfc, 0x0b, 0xf8, 0xed, 0x62, 0xde,
+	0x3d, 0xf0, 0x9b, 0xbb, 0xcf, 0xea, 0x76, 0xf6, 0xd6, 0x10, 0x00, 0x1f,
+	0x7c, 0xee, 0x15, 0xfa, 0xd9, 0x4c, 0xe9, 0x77, 0xb3, 0x0c, 0xb2, 0xbd,
+	0x35, 0x62, 0xca, 0xe8, 0x53, 0x73, 0x7c, 0x9e, 0xd9, 0xeb, 0x7b, 0xa0,
+	0xf6, 0x18, 0x7d, 0x52, 0x5f, 0x5e, 0xdc, 0x60, 0x0c, 0xfc, 0x55, 0xf8,
+	0x6f, 0x19, 0x89, 0xac, 0x64, 0x20, 0x87, 0x3e, 0x6c, 0x29, 0x71, 0x1c,
+	0xed, 0x17, 0xf2, 0x61, 0x73, 0x36, 0x9e, 0x51, 0x31, 0x87, 0x92, 0x93,
+	0x85, 0xcc, 0xd5, 0x3f, 0x63, 0x97, 0xdb, 0x6c, 0x54, 0xd9, 0xd8, 0xa8,
+	0xb2, 0xb1, 0x51, 0xe5, 0x66, 0xb8, 0x3f, 0x38, 0xc6, 0x71, 0xd8, 0xd5,
+	0x2e, 0x79, 0x2a, 0x4e, 0x59, 0xd1, 0xb2, 0x17, 0xb1, 0xc7, 0x94, 0xac,
+	0xce, 0xd0, 0xde, 0x3e, 0xe3, 0xee, 0x83, 0xaf, 0x55, 0x52, 0x7b, 0xe3,
+	0x99, 0x50, 0xce, 0x78, 0xe7, 0x33, 0x90, 0x1a, 0xb0, 0x4c, 0xd9, 0xb3,
+	0x64, 0xc9, 0x3b, 0xae, 0xb0, 0xde, 0xc3, 0xe8, 0xe3, 0x49, 0xd3, 0xc7,
+	0x92, 0x8c, 0x19, 0x79, 0xe7, 0xda, 0x44, 0xd5, 0x79, 0xc5, 0x43, 0xfe,
+	0xef, 0xc9, 0xc0, 0x20, 0xd7, 0x93, 0xf2, 0x4f, 0x7c, 0xc1, 0xf5, 0x60,
+	0x8c, 0xff, 0x6d, 0x63, 0xa9, 0xea, 0x0e, 0x5f, 0xa1, 0x42, 0x5b, 0xb2,
+	0x1f, 0xf2, 0x9b, 0x81, 0xff, 0x1d, 0xc6, 0x53, 0xd5, 0xbe, 0x4a, 0xd8,
+	0x36, 0xec, 0xda, 0xd8, 0xd8, 0x78, 0x51, 0x8e, 0x4b, 0x19, 0x7e, 0x2b,
+	0x69, 0x58, 0x82, 0x1d, 0xdb, 0xf0, 0xff, 0x2e, 0xf8, 0x64, 0x3c, 0x55,
+	0x9a, 0x97, 0xce, 0x18, 0x27, 0x7d, 0xf1, 0xb7, 0x8b, 0x73, 0x1e, 0x51,
+	0xfa, 0xf1, 0x5a, 0x2c, 0x15, 0xc6, 0x38, 0xe7, 0x3a, 0x62, 0x9c, 0xfa,
+	0xec, 0xac, 0x27, 0x4b, 0xbd, 0x7e, 0xca, 0xfa, 0x71, 0x26, 0x22, 0x0d,
+	0x60, 0xca, 0xfb, 0x7c, 0x62, 0xa4, 0x92, 0xf5, 0x7a, 0x45, 0xd4, 0x7b,
+	0xc1, 0x8f, 0xe8, 0x58, 0xbb, 0x0b, 0xdb, 0xb2, 0xed, 0x98, 0xb3, 0x22,
+	0x07, 0x79, 0xb6, 0xf2, 0x77, 0x8b, 0x4a, 0x27, 0x27, 0xfa, 0x24, 0x46,
+	0x3d, 0x75, 0x2f, 0xde, 0x79, 0x5e, 0x71, 0xa4, 0x23, 0x7f, 0x67, 0x80,
+	0x7b, 0xac, 0x0c, 0x3c, 0xb6, 0xe4, 0x69, 0x7e, 0x39, 0xe0, 0xf1, 0x0c,
+	0x30, 0xce, 0x95, 0x26, 0x71, 0x6d, 0xcc, 0xe0, 0x5a, 0xe2, 0x26, 0xac,
+	0xd1, 0xf6, 0x28, 0xca, 0x88, 0x9d, 0xe2, 0xca, 0xaf, 0x53, 0x58, 0xca,
+	0x2f, 0x18, 0x3b, 0x41, 0x99, 0xa2, 0x3c, 0x11, 0x93, 0x69, 0x99, 0x5a,
+	0xa8, 0xb8, 0x1d, 0xf2, 0xe4, 0xfe, 0x23, 0xe5, 0xe9, 0xa6, 0x3e, 0x9e,
+	0xf7, 0xbc, 0x84, 0xfd, 0x79, 0x12, 0xf6, 0x74, 0xa3, 0xb6, 0x4f, 0x76,
+	0x6b, 0xa3, 0xc0, 0xc5, 0xcc, 0xe3, 0xbe, 0x4c, 0xc8, 0xfd, 0x95, 0x59,
+	0x39, 0x5c, 0x8b, 0xca, 0xc5, 0x9a, 0x7d, 0x4f, 0x8f, 0x30, 0x46, 0x4d,
+	0xcc, 0xf1, 0x0d, 0xa5, 0xd7, 0x7e, 0xe2, 0x5f, 0x6d, 0xbf, 0x84, 0xf6,
+	0x0d, 0xb4, 0x5f, 0xa8, 0xdd, 0x28, 0x45, 0xd5, 0x7e, 0xfd, 0xba, 0x31,
+	0xae, 0xd6, 0xe9, 0x33, 0xf6, 0x33, 0x3c, 0x97, 0xa4, 0x6d, 0xee, 0xc2,
+	0xbc, 0xe1, 0x27, 0x65, 0x90, 0xd6, 0x79, 0x36, 0x49, 0xdb, 0xfe, 0x47,
+	0xae, 0x4e, 0x13, 0x6d, 0x76, 0x21, 0xd9, 0x66, 0x17, 0xde, 0x68, 0xbb,
+	0x4b, 0xa9, 0xef, 0x65, 0xbf, 0x9c, 0x01, 0xf6, 0xab, 0x0d, 0xb5, 0xdd,
+	0xa9, 0x48, 0x95, 0x68, 0x93, 0x18, 0x0b, 0xdb, 0xac, 0x84, 0xba, 0x3a,
+	0x37, 0xc0, 0x38, 0xfe, 0xb2, 0x4f, 0xbe, 0x4b, 0x32, 0x92, 0xa5, 0xae,
+	0xf7, 0xa3, 0xbb, 0xc0, 0x68, 0x0d, 0x75, 0x4e, 0x1d, 0xc1, 0x0f, 0xb6,
+	0xd0, 0xb1, 0xc4, 0xf5, 0x98, 0x57, 0xd2, 0x58, 0xd7, 0x85, 0xde, 0xb4,
+	0x55, 0x9d, 0x64, 0xde, 0xbf, 0xc9, 0xbc, 0x43, 0xbf, 0x55, 0xde, 0x3b,
+	0x6c, 0x67, 0xff, 0xfb, 0xcd, 0xf9, 0x0c, 0xcf, 0x0e, 0x99, 0x47, 0xcc,
+	0xfb, 0x03, 0x60, 0x5e, 0xde, 0xb7, 0xe5, 0xba, 0xbc, 0x89, 0xf5, 0xbf,
+	0x08, 0xdb, 0xe2, 0x41, 0xaf, 0x3b, 0xb2, 0x90, 0xb9, 0x68, 0xce, 0x2e,
+	0x38, 0xb7, 0x6e, 0xd8, 0xa8, 0x1f, 0xc9, 0xe1, 0xb5, 0x14, 0xb0, 0x4a,
+	0x88, 0xaf, 0xd8, 0xc7, 0xf5, 0xd8, 0xea, 0x44, 0xb5, 0xfd, 0xfc, 0x37,
+	0xbc, 0x3f, 0x4a, 0xd9, 0x50, 0xe7, 0xda, 0x56, 0x81, 0xf1, 0xc0, 0xd5,
+	0x1f, 0x60, 0x9e, 0xa9, 0x53, 0x22, 0x3c, 0xeb, 0x62, 0x9c, 0x17, 0x3e,
+	0xc2, 0x36, 0xf3, 0xe7, 0xd0, 0xf7, 0x0f, 0x78, 0x97, 0x16, 0xfe, 0x93,
+	0x6d, 0xf8, 0xf3, 0xfb, 0xc6, 0xbf, 0x8f, 0x32, 0x36, 0x0a, 0xd9, 0x2f,
+	0x2b, 0xdb, 0x5d, 0x8c, 0x2f, 0x23, 0xfd, 0x1f, 0xc6, 0x56, 0x7f, 0xbd,
+	0x4f, 0xdb, 0x6a, 0xde, 0x03, 0xf9, 0x02, 0xf7, 0x96, 0xa1, 0x9b, 0xf4,
+	0x92, 0xee, 0x2e, 0xe9, 0x3e, 0x4d, 0x9a, 0xbf, 0x82, 0x7a, 0x94, 0x8d,
+	0x83, 0xe6, 0xbe, 0x08, 0xcf, 0xc1, 0xd9, 0x27, 0x6c, 0x84, 0xc2, 0x5b,
+	0x39, 0xa4, 0x6c, 0xb7, 0x86, 0x7a, 0x39, 0xcc, 0x59, 0x61, 0xb0, 0xa1,
+	0x88, 0x84, 0x79, 0xf7, 0x22, 0x8f, 0x3e, 0xe5, 0x4d, 0xf0, 0x29, 0x99,
+	0x97, 0xc7, 0x3b, 0xc7, 0xba, 0xd9, 0x8c, 0x63, 0x30, 0xdd, 0x35, 0x34,
+	0x71, 0x2e, 0xe1, 0x5a, 0x77, 0x9b, 0x33, 0x73, 0xe6, 0xdd, 0x64, 0xf2,
+	0x1c, 0x33, 0xbf, 0x61, 0x73, 0x8f, 0x3d, 0x75, 0x2a, 0x27, 0xa1, 0xec,
+	0x93, 0xbe, 0x68, 0x1b, 0x16, 0xfc, 0x83, 0xc1, 0xab, 0x77, 0x1c, 0x29,
+	0x6b, 0x94, 0xaf, 0x84, 0xba, 0xbf, 0xc7, 0xf3, 0xf2, 0x17, 0x14, 0xfe,
+	0x0e, 0x71, 0x95, 0xd2, 0x65, 0x3c, 0x07, 0xa8, 0xd9, 0xd9, 0x9e, 0xdf,
+	0xf9, 0x3e, 0x5b, 0x24, 0x1b, 0xb6, 0x03, 0x1e, 0x52, 0x6d, 0x92, 0xb2,
+	0xd8, 0x7c, 0xbb, 0xbb, 0x6f, 0xc0, 0x68, 0xd7, 0xdc, 0x67, 0x49, 0x28,
+	0xfd, 0xb3, 0x51, 0x8b, 0x80, 0xbf, 0x43, 0x78, 0xbe, 0x0c, 0x1e, 0x44,
+	0x31, 0x4f, 0xe0, 0xf4, 0xf8, 0x4d, 0xea, 0xbe, 0x4f, 0xc4, 0xbb, 0xa4,
+	0xce, 0x8d, 0x0a, 0xf5, 0x9f, 0xa9, 0xb2, 0xaf, 0xad, 0xf5, 0xf0, 0x0e,
+	0x28, 0x52, 0x9e, 0x43, 0xff, 0x06, 0x32, 0xd8, 0x65, 0x64, 0x10, 0x69,
+	0x9d, 0xf9, 0xb7, 0xc0, 0x87, 0x14, 0xc8, 0x4b, 0x37, 0xb0, 0xbd, 0xf2,
+	0x13, 0x30, 0x9b, 0xab, 0x34, 0x74, 0x67, 0xc3, 0x3b, 0x97, 0x81, 0x1c,
+	0x86, 0x6c, 0x6c, 0x4c, 0x2f, 0x4b, 0x63, 0xba, 0x1d, 0x27, 0x02, 0x07,
+	0xba, 0xa5, 0xa0, 0xe1, 0x31, 0xd6, 0xd7, 0x6f, 0xee, 0xbf, 0x2d, 0x1a,
+	0x6c, 0x47, 0xfe, 0xdb, 0x52, 0x98, 0x5c, 0x52, 0x32, 0xd5, 0x50, 0xeb,
+	0xe0, 0x58, 0xe7, 0xd5, 0xdd, 0x59, 0x8e, 0xc1, 0xfb, 0xb3, 0x11, 0x83,
+	0x71, 0xfe, 0xa9, 0x59, 0xcf, 0xef, 0xf7, 0x85, 0xdf, 0x64, 0x74, 0x65,
+	0x4f, 0xf2, 0xce, 0x08, 0xf0, 0x6b, 0x6d, 0x76, 0xa1, 0x42, 0xbd, 0x16,
+	0x04, 0x0d, 0x7f, 0x07, 0x3d, 0xbe, 0xa9, 0xf0, 0xd9, 0xae, 0x68, 0xfd,
+	0xb9, 0xa4, 0xee, 0xa1, 0x56, 0x66, 0xf3, 0x2a, 0xa6, 0x06, 0xdc, 0xd1,
+	0x3a, 0xbf, 0x78, 0xa7, 0xb3, 0x8b, 0x28, 0xfc, 0xe5, 0x5e, 0xb3, 0xee,
+	0x51, 0xa7, 0x58, 0xe9, 0x73, 0x16, 0xd4, 0xb9, 0xd2, 0xe7, 0xcc, 0xf7,
+	0x2b, 0xa5, 0xd9, 0x74, 0x33, 0xbb, 0x9f, 0x58, 0x9a, 0x31, 0xfd, 0x42,
+	0x85, 0x67, 0x19, 0xba, 0x3c, 0x6d, 0xca, 0x47, 0x9a, 0xaa, 0x4c, 0xc5,
+	0xe4, 0xe0, 0x77, 0xc1, 0xae, 0x30, 0xfe, 0x47, 0xdd, 0x82, 0xfe, 0xe3,
+	0x7a, 0x0e, 0x91, 0xec, 0x32, 0x7c, 0x3b, 0xd2, 0x77, 0x6a, 0x36, 0xbf,
+	0xc6, 0x7b, 0x47, 0x5f, 0x9a, 0xbd, 0x08, 0xff, 0x63, 0xcb, 0xd3, 0x77,
+	0xb5, 0x37, 0x19, 0x3b, 0x62, 0x3b, 0xd5, 0xe7, 0xb2, 0x89, 0x65, 0x9e,
+	0x9c, 0x1d, 0xdd, 0x8c, 0xc8, 0x49, 0xd3, 0x07, 0xdf, 0x93, 0x2d, 0xdf,
+	0x44, 0xe9, 0x3b, 0x60, 0xf0, 0x27, 0x80, 0xc1, 0x63, 0xb0, 0x8b, 0xc4,
+	0xf2, 0xc4, 0xb7, 0x31, 0xec, 0x15, 0x8e, 0xf3, 0xaf, 0xd5, 0x38, 0x11,
+	0x8c, 0xb3, 0xb0, 0x76, 0x40, 0xdd, 0x23, 0xc9, 0x7b, 0x0e, 0xec, 0x34,
+	0xec, 0xa9, 0xc7, 0x58, 0xb2, 0x8d, 0x39, 0x8f, 0x43, 0x1f, 0xf0, 0x6e,
+	0xc7, 0x60, 0x78, 0xef, 0x85, 0x77, 0xad, 0x4c, 0xbb, 0x4f, 0xa3, 0x1d,
+	0x31, 0x38, 0xdb, 0xca, 0x8d, 0xb6, 0x8c, 0x2a, 0xbb, 0xab, 0x75, 0x0e,
+	0x69, 0xa8, 0x63, 0xae, 0xb4, 0x5d, 0xd8, 0x6b, 0x6a, 0x5e, 0x9f, 0x56,
+	0xed, 0xac, 0xec, 0x53, 0xa0, 0x9d, 0xd8, 0x0a, 0x7d, 0x57, 0x75, 0x7c,
+	0xb0, 0xa0, 0xe4, 0x08, 0x72, 0x32, 0x1d, 0xde, 0x17, 0xd1, 0xed, 0xc2,
+	0xfa, 0x23, 0x9b, 0x9f, 0x35, 0xe3, 0xff, 0x32, 0xc8, 0x1d, 0x8d, 0xa9,
+	0xfb, 0x39, 0x2f, 0x5d, 0x73, 0x87, 0x8a, 0x6d, 0xc2, 0x3a, 0x11, 0x23,
+	0x5b, 0x27, 0xda, 0x68, 0xfe, 0x9c, 0x59, 0x73, 0xb6, 0x63, 0xfc, 0x94,
+	0x79, 0x25, 0xe6, 0x39, 0x8b, 0x19, 0xf6, 0xd1, 0x7e, 0xee, 0x32, 0x09,
+	0x5b, 0xae, 0x6d, 0x46, 0x69, 0xdb, 0x83, 0x4d, 0xec, 0xc6, 0xda, 0xd1,
+	0x06, 0x8c, 0x1a, 0xdc, 0xfe, 0x8e, 0x71, 0x49, 0xa7, 0x98, 0x81, 0x1f,
+	0xdf, 0x6a, 0xcf, 0x75, 0x2c, 0xcd, 0x5e, 0xac, 0x78, 0x72, 0xa2, 0xaa,
+	0xef, 0x37, 0x69, 0x3e, 0x50, 0x37, 0x73, 0x6d, 0x93, 0xb2, 0xe0, 0x31,
+	0xfe, 0x91, 0x94, 0x57, 0xbc, 0x76, 0x3d, 0x8d, 0xfa, 0xdb, 0x93, 0xe6,
+	0x8e, 0xf3, 0xa7, 0x31, 0x7f, 0xe2, 0x31, 0x2d, 0x4b, 0x07, 0x61, 0x77,
+	0xfe, 0x83, 0x43, 0x9d, 0xdd, 0x2d, 0x97, 0x9d, 0xf6, 0xf9, 0x85, 0x71,
+	0x6e, 0x2d, 0x97, 0x0e, 0x64, 0x64, 0xb9, 0xc5, 0x77, 0xf8, 0xbf, 0xef,
+	0x1b, 0x83, 0x8e, 0xb7, 0x64, 0x66, 0xd2, 0x4b, 0x2c, 0x31, 0xee, 0xef,
+	0x4e, 0xb8, 0xae, 0xba, 0xa7, 0x97, 0x04, 0xbd, 0x7c, 0x1e, 0x05, 0x06,
+	0xe1, 0x9d, 0x3a, 0xbc, 0xf3, 0x4e, 0x5b, 0xdc, 0x03, 0xbd, 0xae, 0x8a,
+	0xe7, 0x6b, 0x1d, 0xfd, 0xf5, 0xfd, 0x8c, 0xa7, 0x0c, 0x78, 0xe1, 0xda,
+	0xab, 0x7b, 0xcd, 0xe8, 0x3b, 0x62, 0xca, 0x07, 0x5b, 0xfc, 0x97, 0x21,
+	0xa6, 0xad, 0xbb, 0x52, 0x26, 0x6e, 0xc1, 0xfa, 0x9f, 0x51, 0xb4, 0x2c,
+	0x78, 0x41, 0xb0, 0xa8, 0xe6, 0xf3, 0x34, 0x64, 0x21, 0x22, 0xe5, 0x96,
+	0xfc, 0x3e, 0x0d, 0xf9, 0xdd, 0xc7, 0x6b, 0x35, 0x7b, 0xc8, 0x5a, 0x28,
+	0x63, 0x94, 0x2f, 0xca, 0x56, 0xa2, 0x9f, 0x7b, 0xae, 0xd4, 0x5a, 0x77,
+	0x47, 0xd9, 0xd8, 0xa4, 0x1d, 0xae, 0x3b, 0x9f, 0xf7, 0xba, 0x93, 0x14,
+	0xee, 0x8f, 0xcc, 0x3f, 0x62, 0x6d, 0x7d, 0xb3, 0xb6, 0x99, 0xb6, 0x6f,
+	0x0b, 0xc2, 0xfe, 0x18, 0x3b, 0x54, 0xf6, 0x38, 0x21, 0xd0, 0xd9, 0x25,
+	0x7d, 0xbf, 0x57, 0xe1, 0xd6, 0x9c, 0x9b, 0x4f, 0x32, 0x4e, 0x7c, 0x4c,
+	0xee, 0x02, 0xcd, 0xb9, 0xf1, 0x2e, 0xd1, 0x6d, 0xe7, 0xc1, 0xef, 0x1d,
+	0x17, 0xbe, 0x16, 0xcf, 0x6c, 0x2b, 0x8e, 0x6c, 0xa9, 0xb3, 0x47, 0xec,
+	0xd1, 0x98, 0x23, 0xcb, 0x5e, 0xd8, 0x6f, 0x54, 0xea, 0xa8, 0xb3, 0x81,
+	0xb2, 0x93, 0x2d, 0xda, 0x88, 0xd3, 0xe1, 0xa7, 0x78, 0xbf, 0x0c, 0x8a,
+	0xf1, 0x6b, 0xea, 0x9a, 0x7b, 0xfa, 0x8c, 0x77, 0xf4, 0x29, 0x1f, 0xaa,
+	0x00, 0x9f, 0xab, 0x00, 0x7f, 0xab, 0xa0, 0xf4, 0x02, 0xe3, 0x1f, 0x8c,
+	0x4f, 0x95, 0x80, 0xed, 0x4b, 0x41, 0x8f, 0x77, 0x5c, 0xc5, 0xdd, 0x5e,
+	0xd8, 0xa6, 0x0f, 0xe0, 0x25, 0xef, 0x97, 0xd0, 0x86, 0xf4, 0x97, 0xa2,
+	0xd9, 0xf6, 0x18, 0x56, 0x52, 0xc5, 0x80, 0x7a, 0x81, 0x43, 0x1f, 0x87,
+	0xae, 0x7e, 0xd1, 0x67, 0xec, 0xea, 0x56, 0xf2, 0xfb, 0x2b, 0x9c, 0xa4,
+	0x3d, 0x36, 0x29, 0xde, 0x59, 0x6f, 0xfc, 0x7e, 0x21, 0xb6, 0x4f, 0x25,
+	0x8f, 0x90, 0x6f, 0xad, 0xef, 0x04, 0x42, 0xbb, 0x3a, 0x29, 0xa3, 0x67,
+	0x7f, 0xa4, 0xce, 0x04, 0x3e, 0xe2, 0x77, 0xca, 0x86, 0x8a, 0x7d, 0x4d,
+	0x0e, 0xc8, 0x28, 0xfc, 0x4a, 0x81, 0x75, 0xe2, 0x77, 0x03, 0x96, 0x2c,
+	0x67, 0xd4, 0xbb, 0xcc, 0x35, 0x93, 0xe6, 0x9e, 0x25, 0x63, 0x5b, 0x8c,
+	0x8d, 0x71, 0x4d, 0xfb, 0xd4, 0xdd, 0x4a, 0xde, 0xff, 0x9b, 0x69, 0x6a,
+	0x9b, 0x9b, 0x53, 0x77, 0x1c, 0x19, 0x2b, 0x63, 0xcc, 0x4b, 0xdf, 0x9f,
+	0x3b, 0xdc, 0xdc, 0x2b, 0x2e, 0x16, 0xde, 0xf7, 0xd3, 0x76, 0x6b, 0x37,
+	0x73, 0x00, 0xb6, 0xce, 0x55, 0xf1, 0x89, 0xa2, 0x3b, 0x20, 0xc7, 0xc6,
+	0x7b, 0xc0, 0xf3, 0x41, 0x75, 0x17, 0xcd, 0xf6, 0xde, 0x2f, 0x5d, 0xb4,
+	0x9b, 0xae, 0xba, 0x23, 0x6d, 0xf8, 0x7c, 0x07, 0xf2, 0x7e, 0x05, 0xde,
+	0x33, 0xef, 0x63, 0xfd, 0xda, 0x0e, 0x7d, 0x0a, 0x78, 0x9b, 0xf7, 0xca,
+	0xeb, 0x07, 0xf2, 0x6a, 0x3d, 0xe8, 0xf7, 0x86, 0xba, 0x29, 0xbc, 0xff,
+	0x18, 0x85, 0x6d, 0x72, 0xcd, 0x79, 0x71, 0x49, 0x96, 0x88, 0x01, 0x37,
+	0xa9, 0x7f, 0x2c, 0x35, 0xd6, 0xe5, 0xc8, 0xbb, 0xa4, 0x54, 0xdf, 0xeb,
+	0xdc, 0x3b, 0x08, 0xbe, 0xe1, 0xab, 0x3b, 0x97, 0xa7, 0x4a, 0x66, 0x8d,
+	0xf5, 0x37, 0x85, 0x4e, 0xdb, 0x7d, 0xee, 0xa8, 0xd2, 0xbb, 0xb9, 0x41,
+	0x60, 0x15, 0xef, 0xa3, 0xfd, 0x57, 0xef, 0xf0, 0xfd, 0xc6, 0xe0, 0x58,
+	0xde, 0xdf, 0xd3, 0x77, 0xbb, 0xed, 0x46, 0x28, 0x27, 0xf4, 0x9b, 0x89,
+	0x9f, 0x0f, 0xc2, 0xa7, 0x86, 0xde, 0x1c, 0xe2, 0xfb, 0x5f, 0x9a, 0xb6,
+	0x7c, 0x0e, 0xe4, 0xbe, 0xa9, 0xce, 0x33, 0xed, 0x69, 0x7d, 0x0f, 0x3c,
+	0x16, 0xde, 0x73, 0x1f, 0xee, 0xb8, 0x9b, 0xa4, 0xe8, 0x84, 0x3c, 0x85,
+	0x34, 0xe8, 0xb1, 0x0e, 0x83, 0xde, 0x46, 0x2d, 0x21, 0x83, 0x1e, 0x7d,
+	0xc5, 0x88, 0x4c, 0x0d, 0xa6, 0x5a, 0x77, 0xcd, 0x1b, 0x75, 0xd8, 0xfc,
+	0x5a, 0x48, 0xa7, 0xbe, 0x6b, 0xd8, 0xa8, 0xb3, 0x3c, 0x89, 0xb1, 0x7a,
+	0x64, 0x6a, 0x88, 0x7c, 0xee, 0xa4, 0x23, 0x61, 0xee, 0x23, 0x77, 0xe6,
+	0xdf, 0xdd, 0x46, 0xdf, 0xf5, 0xdf, 0x62, 0xea, 0xfb, 0x8f, 0xbc, 0xcb,
+	0x4e, 0x1a, 0x79, 0xce, 0x82, 0x39, 0xfa, 0xa1, 0x6f, 0x11, 0xf2, 0x65,
+	0x50, 0xdd, 0x97, 0x2f, 0xd4, 0xbb, 0x94, 0x5c, 0x2c, 0x64, 0x38, 0x17,
+	0xe2, 0xa0, 0xf0, 0x4e, 0xfc, 0x3f, 0x39, 0xa0, 0xd7, 0xfc, 0x63, 0xe1,
+	0x1c, 0x4d, 0x3e, 0xdb, 0xdf, 0x82, 0x36, 0x5f, 0x0d, 0xd0, 0x3f, 0x83,
+	0x5b, 0xd8, 0xf3, 0x21, 0x36, 0xbf, 0x45, 0xb7, 0x8f, 0x85, 0xdf, 0xe3,
+	0xb5, 0x7f, 0x1f, 0xc0, 0x3d, 0x15, 0xf2, 0x8d, 0x7d, 0x70, 0x7c, 0xd2,
+	0xc1, 0x71, 0x7b, 0xdb, 0xc6, 0x55, 0x3f, 0xff, 0x5a, 0xbd, 0x76, 0x47,
+	0xdb, 0x7c, 0x29, 0x5f, 0xfd, 0xb2, 0x54, 0x8b, 0x49, 0xb9, 0xa6, 0xfc,
+	0x99, 0x71, 0x20, 0x36, 0xe0, 0x39, 0xee, 0x45, 0x75, 0xff, 0xd6, 0xdc,
+	0x2d, 0x0c, 0xf7, 0x64, 0x3f, 0xea, 0xd1, 0x6e, 0x20, 0xad, 0x6b, 0x9d,
+	0x54, 0x97, 0xeb, 0xbf, 0x77, 0x58, 0x6c, 0x7d, 0xef, 0xa0, 0xfd, 0xe3,
+	0x62, 0xeb, 0x6e, 0x46, 0xb4, 0x34, 0x98, 0x6d, 0xbf, 0xef, 0x53, 0x92,
+	0x87, 0xee, 0xe4, 0x77, 0x06, 0x31, 0x23, 0x97, 0xef, 0x37, 0xe3, 0x60,
+	0xbc, 0xd5, 0x69, 0x19, 0x59, 0xfd, 0xbc, 0x14, 0xe7, 0xd4, 0x9d, 0xed,
+	0xb6, 0x3b, 0xfb, 0xa3, 0xe6, 0x3b, 0xa2, 0x9c, 0xc5, 0x3b, 0x20, 0x85,
+	0x55, 0xac, 0xd1, 0x9d, 0xa9, 0xf1, 0xa4, 0xcd, 0x6f, 0x59, 0x1f, 0x95,
+	0x91, 0xf5, 0x69, 0x49, 0xaf, 0x12, 0x27, 0xf0, 0x74, 0x3c, 0xa5, 0xe2,
+	0x8d, 0xe9, 0x73, 0xba, 0x3f, 0x6f, 0x95, 0xe5, 0x69, 0x60, 0x54, 0x96,
+	0x17, 0x12, 0x11, 0x75, 0x82, 0x7e, 0x1b, 0x64, 0xa8, 0xdb, 0x60, 0x00,
+	0x47, 0xf2, 0xab, 0x6c, 0x4f, 0xbc, 0xf1, 0x1c, 0xd6, 0xac, 0x90, 0xb4,
+	0x85, 0x6d, 0x54, 0x7f, 0x78, 0x8e, 0x2a, 0xec, 0x5c, 0xc8, 0x90, 0xd7,
+	0x93, 0xb2, 0xd9, 0xf4, 0xb0, 0x0f, 0xf4, 0x3d, 0xff, 0x62, 0x3d, 0xbc,
+	0x77, 0xf9, 0x90, 0xf9, 0x6e, 0x40, 0xd3, 0x38, 0x53, 0xe9, 0x94, 0xb7,
+	0xc7, 0xcc, 0x7d, 0x7f, 0xce, 0xdb, 0x6d, 0xd7, 0x79, 0xa6, 0xfe, 0x6b,
+	0x07, 0x78, 0x96, 0x4e, 0x9f, 0x68, 0xa4, 0xdd, 0xff, 0x88, 0xc7, 0xcd,
+	0x77, 0x16, 0x61, 0xbd, 0xff, 0x7d, 0x40, 0xdf, 0xd5, 0x27, 0x9f, 0xb2,
+	0x86, 0xe6, 0x29, 0xe5, 0xdf, 0xbc, 0x54, 0x3d, 0x88, 0xb6, 0x5c, 0x27,
+	0xa4, 0x0d, 0x3e, 0x53, 0x6f, 0x1e, 0x31, 0x67, 0x4e, 0x43, 0x6a, 0x2c,
+	0x37, 0xdb, 0xfe, 0x0d, 0x48, 0x6f, 0xdb, 0xf8, 0x9d, 0xf4, 0xf2, 0x9b,
+	0x90, 0x8b, 0x46, 0x5e, 0x58, 0xce, 0xf7, 0xce, 0x3a, 0x87, 0x0e, 0x84,
+	0xe5, 0x4e, 0xeb, 0xbb, 0x01, 0xf2, 0x92, 0xe7, 0x65, 0x48, 0x79, 0x4e,
+	0xa9, 0x9e, 0x91, 0x9a, 0xef, 0x21, 0x9c, 0x55, 0xfe, 0x3a, 0xfb, 0x71,
+	0xd0, 0x77, 0xb8, 0x4f, 0xf7, 0xba, 0x17, 0x43, 0xfd, 0x7b, 0xca, 0xda,
+	0xad, 0x44, 0xe9, 0xef, 0xc8, 0xb1, 0x4c, 0x3f, 0xfc, 0x7d, 0x9b, 0xdf,
+	0x78, 0x32, 0xb6, 0xc9, 0x33, 0x3d, 0x59, 0x54, 0x7a, 0x6d, 0x4c, 0xf4,
+	0xf7, 0xad, 0xbd, 0x32, 0xe3, 0x52, 0x9e, 0xc7, 0x64, 0xb3, 0x3e, 0xd7,
+	0x76, 0x57, 0xb6, 0xdb, 0xc8, 0xd9, 0x2b, 0x5d, 0x12, 0x2b, 0x59, 0x17,
+	0x2a, 0xe1, 0x3e, 0x1e, 0x93, 0x99, 0x7a, 0xfb, 0x7d, 0x68, 0xde, 0xb3,
+	0xa1, 0xdc, 0x0e, 0xb7, 0xed, 0x3d, 0xde, 0x4d, 0x03, 0x96, 0x8a, 0xd3,
+	0x1f, 0x65, 0xbd, 0xfd, 0xc6, 0xc6, 0x7e, 0xd4, 0x95, 0x98, 0x6b, 0x89,
+	0x47, 0xda, 0xfa, 0x4d, 0x5c, 0x3e, 0x2d, 0xf7, 0xc5, 0x4b, 0xf0, 0xc7,
+	0xc6, 0xcc, 0xb8, 0xef, 0xc1, 0x3b, 0xeb, 0x1e, 0x30, 0xe5, 0xb7, 0x98,
+	0xf7, 0x98, 0x79, 0x8f, 0xe0, 0x9d, 0x77, 0xac, 0xd9, 0x27, 0xd3, 0xe7,
+	0x55, 0xdc, 0x65, 0x20, 0x9b, 0x95, 0xae, 0x73, 0x02, 0xdb, 0x14, 0x93,
+	0xc7, 0xea, 0x8a, 0xbf, 0x96, 0xb7, 0x4a, 0x10, 0x70, 0x83, 0x79, 0xbe,
+	0x7e, 0x0f, 0x3e, 0x75, 0xcd, 0x37, 0x47, 0x7f, 0xe8, 0x6a, 0x59, 0x69,
+	0xa7, 0xf7, 0x6e, 0xd0, 0xfa, 0x76, 0xf7, 0x8f, 0x68, 0x97, 0xb4, 0x9f,
+	0x38, 0x53, 0xa1, 0x0e, 0xcc, 0xca, 0xb1, 0x0a, 0x68, 0xad, 0x0d, 0xbb,
+	0xfa, 0x9e, 0x08, 0xf9, 0xa5, 0xef, 0x0d, 0xe6, 0x6b, 0x63, 0xe6, 0x7c,
+	0x97, 0x6d, 0x79, 0x8f, 0x91, 0x7c, 0x8b, 0x76, 0xc4, 0x11, 0x68, 0x7f,
+	0x68, 0x5b, 0xf8, 0x2d, 0x8e, 0x8f, 0xba, 0xcb, 0xd4, 0x35, 0xb0, 0x4d,
+	0x21, 0x7e, 0xf8, 0x82, 0x89, 0x47, 0x85, 0x76, 0x9e, 0xdf, 0x47, 0x8b,
+	0xfc, 0x67, 0x60, 0x57, 0xfb, 0x74, 0xaf, 0x44, 0x4e, 0x87, 0x77, 0x90,
+	0xb8, 0xc6, 0xa3, 0xea, 0x8e, 0xd9, 0x6e, 0xf3, 0xc3, 0x28, 0x0b, 0xcf,
+	0x8a, 0xbb, 0xcc, 0x59, 0x71, 0x28, 0xe7, 0x70, 0x34, 0x62, 0x51, 0xc8,
+	0x38, 0xdb, 0xe7, 0x14, 0x5f, 0x73, 0x71, 0xe2, 0xac, 0x83, 0x26, 0x6e,
+	0xc0, 0xb2, 0x92, 0x0c, 0xdc, 0xf9, 0x61, 0xee, 0x8d, 0x77, 0x47, 0x24,
+	0xfc, 0x8e, 0x40, 0x8d, 0x13, 0xd7, 0xb8, 0x91, 0xdf, 0x57, 0xfb, 0xd8,
+	0x57, 0xfb, 0x76, 0xc2, 0xef, 0x08, 0xce, 0x37, 0x33, 0xea, 0x7b, 0x05,
+	0x9e, 0x25, 0xec, 0xf2, 0x1e, 0xd6, 0x2a, 0xbf, 0xa5, 0xa6, 0x6c, 0x9b,
+	0xef, 0xa8, 0xfb, 0x87, 0xe5, 0xe5, 0xa6, 0xfe, 0xf6, 0x42, 0xdf, 0xed,
+	0x25, 0x3e, 0x4b, 0xa2, 0x9c, 0x77, 0xc7, 0xf8, 0xad, 0x03, 0xff, 0x9f,
+	0xc2, 0x23, 0x48, 0x3f, 0x25, 0x1b, 0x15, 0x1d, 0xcf, 0x2c, 0xc3, 0x7f,
+	0x18, 0x59, 0x75, 0xd5, 0x99, 0xcb, 0xc8, 0xea, 0x0c, 0xc6, 0x0b, 0xbf,
+	0x7d, 0x8e, 0x23, 0x8f, 0xf4, 0x95, 0xcc, 0x1e, 0x0d, 0xef, 0x4b, 0xfc,
+	0x57, 0x97, 0x36, 0xa1, 0xd4, 0xec, 0x43, 0x5d, 0xcb, 0x60, 0x10, 0xe2,
+	0xbb, 0xf0, 0x1b, 0xaf, 0x18, 0x6d, 0x54, 0x40, 0x9d, 0x94, 0xc6, 0x38,
+	0x8d, 0x0a, 0xef, 0x5d, 0xa8, 0xff, 0xc3, 0xe0, 0x16, 0xe9, 0xa3, 0x29,
+	0x1d, 0x9f, 0x1a, 0x9f, 0x97, 0x82, 0xdb, 0x25, 0x09, 0xf5, 0x7f, 0x1d,
+	0x6c, 0xcc, 0x3d, 0xbf, 0xd6, 0xb7, 0x13, 0xc9, 0x72, 0x6e, 0x1c, 0x9b,
+	0xbe, 0x87, 0x9e, 0x0f, 0xbf, 0x19, 0x71, 0xb2, 0xbc, 0xdb, 0xcd, 0xef,
+	0x9e, 0x98, 0x5f, 0x02, 0xce, 0x0a, 0xbf, 0x73, 0xd1, 0xdf, 0x31, 0xcc,
+	0x37, 0x8f, 0xc8, 0x89, 0xca, 0x7e, 0x7e, 0x6f, 0xe1, 0xef, 0x82, 0x6f,
+	0xc7, 0x9a, 0x7d, 0xea, 0x5b, 0x8a, 0xf9, 0x26, 0xef, 0x8f, 0x85, 0xb6,
+	0x87, 0x6b, 0x15, 0x57, 0x67, 0x18, 0x2f, 0xa8, 0x6f, 0x2d, 0xf4, 0x77,
+	0x16, 0x8f, 0xa9, 0xef, 0x16, 0xf4, 0x7e, 0xbf, 0x1e, 0x7b, 0x53, 0x06,
+	0x3f, 0x07, 0x7f, 0x50, 0xeb, 0xdd, 0xfb, 0x32, 0xbc, 0x23, 0x19, 0x04,
+	0xc7, 0x7c, 0xc6, 0x45, 0x73, 0xd3, 0x1b, 0x98, 0xe3, 0x85, 0x3a, 0x78,
+	0x78, 0x94, 0x79, 0xbc, 0x43, 0xd5, 0x23, 0xf9, 0x49, 0xf5, 0x1d, 0xba,
+	0xb5, 0xe1, 0xed, 0x97, 0xf3, 0x35, 0xee, 0x05, 0x07, 0xf3, 0x4e, 0xb9,
+	0x0d, 0xb9, 0x61, 0x80, 0x67, 0x60, 0x87, 0x55, 0xfb, 0x70, 0xbf, 0xeb,
+	0x58, 0xc1, 0xe1, 0x4d, 0xad, 0x4f, 0x78, 0xbf, 0xae, 0xeb, 0xac, 0x58,
+	0x1f, 0xcf, 0x0c, 0xc3, 0xdf, 0xe6, 0x58, 0x69, 0xb4, 0x83, 0xec, 0x24,
+	0xb8, 0xd7, 0x7f, 0x15, 0x34, 0x40, 0xef, 0x95, 0x26, 0x31, 0x3a, 0x70,
+	0xd3, 0x1c, 0xdb, 0x64, 0xc5, 0x5e, 0x61, 0x9d, 0x41, 0xc8, 0x5f, 0x17,
+	0xe6, 0xe3, 0x00, 0xff, 0x1f, 0x90, 0x86, 0xcb, 0x32, 0x3e, 0x27, 0x4c,
+	0x6c, 0x42, 0x7d, 0x23, 0x0c, 0xfe, 0x25, 0x95, 0x4e, 0xca, 0xb9, 0x7a,
+	0x7c, 0xde, 0xe1, 0x5c, 0xa8, 0xcd, 0x62, 0x0f, 0x39, 0x06, 0x8f, 0x39,
+	0xe8, 0xe3, 0xd7, 0xe6, 0xbb, 0x8c, 0x92, 0x14, 0x32, 0x1a, 0x7f, 0x68,
+	0x1b, 0xc3, 0xf3, 0x12, 0x07, 0xf8, 0x3f, 0xdc, 0x97, 0x8f, 0x1d, 0xb8,
+	0xf6, 0xfb, 0x0d, 0x62, 0x97, 0x74, 0xe2, 0x0c, 0xcf, 0xb9, 0xb6, 0x1f,
+	0x94, 0x79, 0xd0, 0x7c, 0xca, 0xcc, 0xf3, 0xfe, 0x8c, 0x27, 0x97, 0xeb,
+	0x68, 0x93, 0x39, 0x88, 0x94, 0x77, 0xfd, 0x48, 0xf3, 0x84, 0xb9, 0xc7,
+	0x98, 0xc5, 0x5c, 0x1f, 0x95, 0xd7, 0x80, 0xa9, 0x5f, 0xaf, 0xa4, 0xfd,
+	0xc3, 0xea, 0x8e, 0x4e, 0x2a, 0x71, 0x5e, 0x26, 0x92, 0xf4, 0xfb, 0x4a,
+	0x6e, 0x2a, 0x71, 0x59, 0x78, 0xd7, 0xe8, 0xb1, 0x01, 0xfe, 0x4f, 0x87,
+	0x06, 0xec, 0xa1, 0xbe, 0x73, 0x94, 0x62, 0x9c, 0x04, 0xef, 0xc3, 0xe6,
+	0xbb, 0x22, 0x8e, 0xc3, 0xb2, 0x61, 0x79, 0xad, 0xd2, 0xb2, 0xbf, 0x1c,
+	0xc7, 0x7c, 0x4b, 0xce, 0xb1, 0xfe, 0xed, 0x00, 0xf5, 0x10, 0xc7, 0xd3,
+	0x7d, 0x84, 0x75, 0xc8, 0x57, 0xbd, 0xc6, 0xf9, 0x8c, 0xfa, 0xae, 0x35,
+	0x29, 0x96, 0x25, 0xdd, 0x1e, 0xe7, 0x7e, 0xd3, 0x80, 0xc6, 0x40, 0x6c,
+	0x97, 0x76, 0xef, 0x53, 0xfd, 0xf1, 0xac, 0x8c, 0xe7, 0x49, 0x61, 0x3f,
+	0xbc, 0x33, 0x84, 0x75, 0x8f, 0x73, 0xbd, 0xdb, 0x69, 0xd0, 0xf6, 0xff,
+	0x35, 0x15, 0xa3, 0x9e, 0x46, 0x7d, 0xda, 0x68, 0xc8, 0x4b, 0x3d, 0xd1,
+	0xfa, 0x36, 0x42, 0xf3, 0x92, 0xcf, 0x8f, 0xb5, 0xbe, 0x4f, 0xb0, 0x6f,
+	0x77, 0x4d, 0x79, 0x88, 0x45, 0x87, 0xb1, 0x5f, 0x1f, 0x95, 0xc6, 0x5a,
+	0x3a, 0xf1, 0x98, 0x84, 0xfd, 0x06, 0x87, 0x78, 0x8e, 0x30, 0x93, 0x99,
+	0x70, 0x97, 0x14, 0x3d, 0xa9, 0x04, 0xef, 0xdd, 0x9e, 0xc7, 0x78, 0x8d,
+	0x66, 0x67, 0xbc, 0x21, 0x95, 0xdb, 0x91, 0xb4, 0xaf, 0xd7, 0x66, 0x4c,
+	0x76, 0xb0, 0x36, 0x5f, 0x32, 0x6b, 0xf3, 0x41, 0xf4, 0xed, 0xad, 0x4c,
+	0x4a, 0x7a, 0x25, 0x9d, 0x3c, 0x25, 0x3c, 0x9b, 0x3b, 0xc0, 0xb8, 0x95,
+	0x75, 0x7f, 0x26, 0x89, 0xf9, 0xa6, 0x30, 0x5f, 0xa4, 0x4d, 0x3e, 0x4f,
+	0xc0, 0x1f, 0xdf, 0xc7, 0xbd, 0x7d, 0x88, 0x3a, 0x93, 0xbc, 0x98, 0x51,
+	0x65, 0x8f, 0x9a, 0xbb, 0x94, 0xdf, 0xe3, 0xfa, 0xa8, 0xb8, 0xdf, 0xe5,
+	0x26, 0xcf, 0xeb, 0x34, 0x7d, 0x05, 0xd0, 0xb7, 0xa8, 0xe9, 0x4b, 0xce,
+	0xb7, 0xf0, 0x6a, 0x2a, 0x71, 0x42, 0x88, 0x97, 0x88, 0x5f, 0x88, 0xe5,
+	0x6f, 0x19, 0xd4, 0xdf, 0x7e, 0xc0, 0x77, 0xbd, 0x3d, 0xd7, 0x9a, 0x7b,
+	0x37, 0xea, 0x5e, 0x80, 0xee, 0xa7, 0xbc, 0x1c, 0x91, 0x0f, 0x48, 0xee,
+	0x91, 0x54, 0x32, 0x67, 0x79, 0x06, 0x03, 0x22, 0xad, 0xf3, 0x99, 0x3a,
+	0xd7, 0x33, 0xd8, 0x82, 0x6b, 0x93, 0xc1, 0x58, 0xfa, 0x3b, 0x92, 0x5d,
+	0xcc, 0x2d, 0xaf, 0x64, 0xed, 0xf7, 0xb1, 0x87, 0xf4, 0xff, 0xb3, 0x38,
+	0x0f, 0x3e, 0x96, 0xc1, 0xc7, 0xc7, 0xaf, 0xc3, 0x60, 0x5d, 0x2d, 0x0c,
+	0xb6, 0xab, 0xc6, 0xb3, 0x40, 0x53, 0xc1, 0x25, 0xfe, 0x2a, 0xb7, 0x64,
+	0x85, 0x34, 0x4d, 0xf2, 0x7f, 0xd2, 0xc8, 0xcb, 0x19, 0xae, 0x07, 0x30,
+	0x18, 0xfa, 0xdb, 0xb8, 0x2a, 0x4b, 0x98, 0xbf, 0x92, 0x5f, 0xc8, 0x6e,
+	0xca, 0x75, 0x2c, 0xae, 0x05, 0xfb, 0x13, 0xeb, 0x22, 0x68, 0xd9, 0x55,
+	0x72, 0xa0, 0x65, 0x60, 0xb7, 0x1e, 0x7b, 0x07, 0x19, 0xe0, 0x3c, 0x29,
+	0x7f, 0xa1, 0xec, 0xb5, 0xbe, 0x39, 0x87, 0x4f, 0x5b, 0x92, 0xdb, 0xee,
+	0xc8, 0x4a, 0x7e, 0x85, 0x67, 0x4b, 0x62, 0x4d, 0xdc, 0x41, 0x99, 0x24,
+	0x4e, 0x00, 0x86, 0x4c, 0x90, 0xc7, 0x1a, 0x0f, 0xce, 0x3f, 0xb7, 0x1f,
+	0xbf, 0x73, 0x03, 0xbc, 0x5b, 0x92, 0xdf, 0xa2, 0xbe, 0x12, 0xeb, 0xd6,
+	0x3b, 0xb4, 0x4f, 0x78, 0x25, 0x0e, 0x9e, 0xa3, 0x7c, 0xe4, 0xcb, 0xdd,
+	0xd0, 0x57, 0x8e, 0x99, 0x37, 0xdf, 0xc9, 0x57, 0xa4, 0xcf, 0x71, 0x5c,
+	0xed, 0x5f, 0xe8, 0x38, 0x20, 0xf7, 0x45, 0x49, 0x16, 0xa1, 0x0f, 0x16,
+	0x32, 0x31, 0x39, 0x5c, 0x8b, 0xcb, 0x91, 0xca, 0xb4, 0x7c, 0xb1, 0xd2,
+	0xa7, 0x70, 0xc3, 0x9f, 0xfb, 0xe9, 0xc4, 0xb8, 0x15, 0xc8, 0xfd, 0xc0,
+	0x3f, 0xf3, 0xc3, 0xdd, 0xf2, 0xfa, 0xa4, 0xa5, 0xf4, 0xde, 0x15, 0x7e,
+	0x18, 0xed, 0xf2, 0x0e, 0x27, 0xe7, 0x03, 0xbd, 0x6f, 0xc1, 0x17, 0xb0,
+	0x78, 0x6f, 0xaf, 0x4f, 0x1e, 0xf0, 0x91, 0xde, 0xe8, 0xab, 0xef, 0x62,
+	0xcd, 0x77, 0x5c, 0x46, 0x8f, 0x9c, 0x33, 0x63, 0x1f, 0x31, 0x69, 0x6a,
+	0xb0, 0x8d, 0x16, 0x6b, 0x31, 0x13, 0x51, 0xf3, 0x2b, 0xd7, 0xa9, 0xdf,
+	0xd8, 0x06, 0xfa, 0x04, 0x7b, 0xb7, 0x0b, 0x7c, 0xd9, 0x80, 0x7e, 0x29,
+	0xd6, 0xc4, 0xda, 0xca, 0x00, 0x51, 0x7b, 0x1a, 0x7f, 0x16, 0x21, 0x5f,
+	0x0b, 0x35, 0xea, 0xbf, 0x23, 0x90, 0x05, 0xda, 0x6f, 0x87, 0xdf, 0xdc,
+	0x00, 0x43, 0x98, 0x3b, 0x1f, 0x31, 0xc6, 0x40, 0xda, 0x75, 0x58, 0xf8,
+	0x3f, 0x67, 0x3e, 0x3e, 0x28, 0xfd, 0x25, 0xac, 0x4b, 0x88, 0xb9, 0xc1,
+	0x53, 0x8c, 0x99, 0x57, 0xeb, 0x14, 0xae, 0x09, 0x75, 0x4f, 0x88, 0x37,
+	0xda, 0xfd, 0x23, 0xee, 0x59, 0xda, 0x0b, 0x29, 0x45, 0x81, 0x69, 0x7b,
+	0x57, 0x60, 0xbb, 0x6b, 0x59, 0xc8, 0x0a, 0xef, 0xe1, 0x4f, 0x4b, 0x19,
+	0xd8, 0xed, 0xe3, 0xfe, 0xe7, 0xc4, 0x7e, 0xf6, 0xa0, 0x6c, 0xd4, 0x7a,
+	0xc1, 0x0f, 0xda, 0x85, 0x2e, 0xe5, 0x53, 0x5f, 0x39, 0x4a, 0x7b, 0x47,
+	0x5b, 0xa2, 0xd7, 0x62, 0xb7, 0x0e, 0x27, 0x38, 0xa6, 0xf3, 0x76, 0xea,
+	0xa1, 0x2d, 0xe4, 0xf7, 0x34, 0x5d, 0xc6, 0x2e, 0xc7, 0xa0, 0xbb, 0xd7,
+	0xa5, 0xa1, 0xfc, 0x73, 0xce, 0x9f, 0x36, 0xa8, 0x8b, 0xf7, 0xc7, 0xac,
+	0x86, 0xc7, 0xb9, 0xb7, 0xdb, 0x20, 0x8d, 0x3b, 0xdc, 0x3b, 0x39, 0x1e,
+	0xef, 0x26, 0x70, 0x8e, 0x71, 0xe9, 0x3a, 0xf3, 0xa8, 0xd8, 0xf0, 0x5b,
+	0x22, 0xab, 0xc4, 0x7a, 0xd7, 0xfa, 0x2e, 0x91, 0x73, 0x51, 0xf3, 0xfd,
+	0xf0, 0xa8, 0xc6, 0x32, 0x19, 0xa4, 0x8d, 0xf0, 0x9b, 0x62, 0xfe, 0xda,
+	0xed, 0x66, 0xe8, 0x5b, 0xec, 0x69, 0x4b, 0xf1, 0xf7, 0x7f, 0x00, 0xb6,
+	0x9d, 0x3c, 0x32, 0x44, 0x4b, 0x00, 0x00, 0x00 };
 
 static const u32 bnx2_COM_b09FwData[(0x0/4) + 1] = { 0x0 };
-static const u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = {
-	0x08001b7c, 0x08001bb8, 0x08001bb8, 0x08001bb8, 0x08001bb8, 0x08001bb8,
-	0x08001ac8, 0x08001bb8, 0x08001b3c, 0x08001bb8, 0x08001a50, 0x08001bb8,
-	0x08001bb8, 0x08001bb8, 0x08001a5c, 0x00000000, 0x08002b74, 0x08002bc4,
-	0x08002bf4, 0x08002c24, 0x08002c58, 0x00000000, 0x08006120, 0x08006120,
-	0x08006120, 0x08006120, 0x08006120, 0x0800614c, 0x0800614c, 0x0800618c,
-	0x08006198, 0x08006198, 0x08006120, 0x00000000, 0x00000000 };
+static const u32 bnx2_COM_b09FwRodata[(0x30/4) + 1] = {
+	0x80080100, 0x80080080, 0x80080000, 0x80080240, 0x08000e94, 0x08000eec,
+	0x08000f30, 0x08000fc4, 0x08001008, 0x80080100, 0x80080080, 0x80080000,
+	0x00000000 };
 
 static struct fw_info bnx2_com_fw_09 = {
-	/* Firmware version:  3.7.1 */
-	.ver_major			= 0x3,
-	.ver_minor			= 0x7,
-	.ver_fix			= 0x1,
+	/* Firmware version: 4.0.5 */
+	.ver_major			= 0x4,
+	.ver_minor			= 0x0,
+	.ver_fix			= 0x5,
 
-	.start_addr			= 0x080000b4,
+	.start_addr			= 0x080000f8,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x7e94,
+	.text_len			= 0x4b40,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_COM_b09FwText,
 	.gz_text_len			= sizeof(bnx2_COM_b09FwText),
 
-	.data_addr			= 0x08007f40,
+	.data_addr			= 0x00000000,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_COM_b09FwData,
 
-	.sbss_addr			= 0x08007f40,
-	.sbss_len			= 0x60,
+	.sbss_addr			= 0x08004ba0,
+	.sbss_len			= 0x38,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x08007fa0,
-	.bss_len			= 0x88,
+	.bss_addr			= 0x08004bd8,
+	.bss_len			= 0xbc,
 	.bss_index			= 0x0,
 
-	.rodata_addr			= 0x08007e98,
-	.rodata_len			= 0x88,
+	.rodata_addr			= 0x08004b40,
+	.rodata_len			= 0x30,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_COM_b09FwRodata,
 };
 
 static u8 bnx2_CP_b09FwText[] = {
-	0xbd, 0x7d, 0x0d, 0x74, 0x5c, 0xd7, 0x5d, 0xe7, 0xff, 0xdd, 0x79, 0x92,
-	0xc6, 0xb2, 0x6c, 0x3f, 0xcb, 0x13, 0x79, 0x62, 0xab, 0xf6, 0x8c, 0xf4,
-	0x64, 0xab, 0x91, 0x08, 0x2f, 0xae, 0x28, 0x82, 0x9d, 0x84, 0xe9, 0x48,
-	0xb2, 0x9d, 0x34, 0xed, 0xca, 0x8d, 0x5b, 0xb2, 0x9c, 0x02, 0x62, 0x24,
-	0x27, 0xe9, 0x77, 0xd2, 0x04, 0xb6, 0xec, 0xc9, 0x6e, 0x26, 0x23, 0xf9,
-	0x83, 0x74, 0xec, 0x51, 0x12, 0x25, 0xce, 0xa1, 0x3d, 0xbb, 0xaa, 0xa4,
-	0xd8, 0x06, 0x06, 0x8f, 0x93, 0xb8, 0xa5, 0xec, 0xa6, 0x54, 0x28, 0xae,
-	0x09, 0xa1, 0x07, 0x52, 0x48, 0xd9, 0x40, 0x53, 0x2a, 0xdc, 0xb4, 0xcd,
-	0x9e, 0x53, 0xb6, 0x01, 0xca, 0x12, 0x68, 0xe8, 0xdb, 0xdf, 0xef, 0xde,
-	0xfb, 0x34, 0xa3, 0x0f, 0xe7, 0xa3, 0xec, 0xe2, 0x73, 0x9e, 0xdf, 0xbc,
-	0xfb, 0xee, 0xc7, 0xff, 0xfe, 0xef, 0xff, 0xfb, 0xfe, 0xef, 0xd3, 0x76,
-	0x91, 0x66, 0xb1, 0xff, 0x36, 0xe0, 0x7a, 0x5b, 0xea, 0xf6, 0xd1, 0x6b,
-	0xae, 0xfe, 0xc9, 0xab, 0xf9, 0xec, 0x3a, 0x4d, 0x31, 0x79, 0x13, 0xff,
-	0x52, 0x6f, 0xa0, 0x0e, 0x3a, 0xf4, 0xa2, 0xb1, 0x78, 0x49, 0x5c, 0x65,
-	0xdc, 0x3b, 0x72, 0xbe, 0xc4, 0x63, 0x99, 0x91, 0x5f, 0x1e, 0xf5, 0x45,
-	0xb2, 0x95, 0x9e, 0xd4, 0x80, 0xfc, 0x4b, 0x58, 0x48, 0xb8, 0xc2, 0xf2,
-	0xb7, 0x64, 0x5e, 0xfd, 0x6f, 0x5f, 0xf8, 0xc9, 0xf4, 0xcb, 0xd3, 0x31,
-	0x89, 0x7b, 0x99, 0x0f, 0x8b, 0xb7, 0x4b, 0xe2, 0xed, 0x19, 0xb9, 0xe3,
-	0xd3, 0xbb, 0xff, 0x46, 0x64, 0x63, 0xd4, 0xd7, 0x4b, 0xe1, 0x17, 0x76,
-	0x4b, 0x61, 0x5b, 0x26, 0x39, 0xd2, 0x90, 0x49, 0xc8, 0x17, 0xab, 0x9e,
-	0x9c, 0xab, 0xca, 0xf0, 0xa9, 0xd2, 0xcb, 0xa1, 0x9b, 0x09, 0x63, 0x13,
-	0x7d, 0x8e, 0xc4, 0x32, 0x72, 0x61, 0xb4, 0xef, 0x9e, 0x50, 0xf9, 0x32,
-	0xe2, 0x65, 0xfc, 0x60, 0x41, 0x5a, 0xfa, 0x2f, 0xf6, 0xa1, 0x4e, 0xe5,
-	0xe0, 0xb5, 0x8d, 0x27, 0xe2, 0xa2, 0x32, 0x5d, 0xcf, 0xe7, 0x62, 0xd7,
-	0x88, 0xf2, 0xfd, 0xe0, 0x82, 0x74, 0x05, 0x4f, 0x09, 0xca, 0xcf, 0xc6,
-	0x25, 0x57, 0x95, 0x16, 0x94, 0xe1, 0xde, 0x8c, 0x3a, 0x69, 0x2f, 0x17,
-	0x4b, 0x48, 0xb1, 0xfa, 0x63, 0xcd, 0x66, 0xec, 0xaf, 0xaf, 0x33, 0xf7,
-	0xdd, 0xf6, 0xbe, 0xee, 0x67, 0xdd, 0x4c, 0x3c, 0xae, 0x4e, 0xc8, 0xcb,
-	0x13, 0x7d, 0x2f, 0x87, 0x31, 0xdf, 0xf7, 0x06, 0xa4, 0x41, 0x06, 0x13,
-	0x80, 0xa9, 0xec, 0xa0, 0xef, 0x14, 0xda, 0xfe, 0x12, 0x70, 0x0e, 0xf8,
-	0xca, 0x29, 0x29, 0x10, 0xce, 0x72, 0x5c, 0x16, 0x63, 0x49, 0x01, 0xfc,
-	0xc0, 0x45, 0xbb, 0x8c, 0xa3, 0x3c, 0x57, 0xe2, 0x7c, 0x5c, 0xc9, 0x7b,
-	0x1e, 0xe6, 0xd2, 0x8e, 0x36, 0x3b, 0x1d, 0xd3, 0x3f, 0x9e, 0x97, 0xd5,
-	0x67, 0xdd, 0xe7, 0x51, 0x37, 0xa5, 0xeb, 0x3d, 0x51, 0x4d, 0xca, 0xe3,
-	0xd5, 0x84, 0x3c, 0x56, 0xfd, 0x98, 0x64, 0x3d, 0xe2, 0x00, 0xb0, 0x96,
-	0x1b, 0x65, 0x60, 0xaa, 0x59, 0x72, 0x53, 0x9d, 0xc9, 0xbc, 0x84, 0xe1,
-	0x9d, 0xc1, 0x07, 0x64, 0xa4, 0x15, 0xf5, 0xcb, 0x7c, 0x97, 0x5c, 0xf6,
-	0x2e, 0x1f, 0xf4, 0x78, 0x79, 0xe5, 0x48, 0xf6, 0x60, 0x3a, 0x39, 0xa2,
-	0xf8, 0xdc, 0x20, 0xb9, 0x5e, 0x3c, 0x0f, 0xbb, 0x12, 0xf3, 0xc3, 0xf0,
-	0x8e, 0x60, 0x17, 0xe0, 0x48, 0xa7, 0x52, 0x8a, 0x6d, 0xd9, 0x2e, 0x5d,
-	0x48, 0xa9, 0x24, 0xe6, 0x71, 0xb5, 0xa4, 0x5a, 0xc3, 0xf0, 0x3d, 0x81,
-	0x8f, 0x72, 0x91, 0x81, 0x92, 0xdc, 0xae, 0x32, 0x3e, 0xfa, 0x94, 0x40,
-	0x65, 0xb6, 0x60, 0x1e, 0x3d, 0xc0, 0x43, 0xa3, 0x64, 0x13, 0x92, 0x55,
-	0x19, 0x49, 0xa9, 0xcc, 0x3a, 0x94, 0x39, 0xd2, 0xe0, 0xff, 0x77, 0x4b,
-	0x7f, 0x9b, 0xf0, 0x2c, 0xc3, 0x2a, 0xd3, 0xba, 0xa2, 0x3c, 0x9d, 0x12,
-	0xf5, 0xe3, 0x71, 0x8c, 0xd9, 0x9d, 0x55, 0x2c, 0xc3, 0x5d, 0x97, 0x15,
-	0x9a, 0x56, 0x97, 0x4d, 0x3a, 0xcb, 0xcb, 0x4e, 0xb5, 0x10, 0x56, 0x51,
-	0xfc, 0x9d, 0xd4, 0x73, 0xcd, 0x26, 0x3a, 0xbd, 0x06, 0xcc, 0x6b, 0x38,
-	0x48, 0x7b, 0x43, 0xea, 0xb9, 0x50, 0xda, 0x08, 0x33, 0xdf, 0x29, 0xbc,
-	0x43, 0xd5, 0x4c, 0x80, 0x75, 0x4e, 0xc8, 0x51, 0xcc, 0xed, 0xd2, 0x54,
-	0xda, 0xeb, 0x50, 0xb8, 0xcf, 0xf1, 0x77, 0x18, 0xe6, 0x82, 0x82, 0xa6,
-	0x81, 0x6f, 0x4e, 0x25, 0xf1, 0x0c, 0xf8, 0x13, 0xd9, 0xf4, 0x66, 0xb9,
-	0xc9, 0xae, 0xcb, 0x37, 0x31, 0x66, 0xa7, 0x77, 0x87, 0xea, 0xf4, 0x02,
-	0x95, 0xf6, 0x66, 0xe4, 0xf7, 0xf1, 0x1c, 0x86, 0x07, 0x82, 0x74, 0xb2,
-	0x80, 0x35, 0x7b, 0xb1, 0x94, 0x90, 0x6f, 0x95, 0xd2, 0xa0, 0xfc, 0x74,
-	0xf7, 0xac, 0xf4, 0x04, 0xb3, 0x80, 0xb7, 0x88, 0xeb, 0x08, 0xdf, 0x55,
-	0xf0, 0xae, 0xc2, 0xb6, 0x61, 0x78, 0x53, 0xf0, 0xeb, 0xe1, 0x48, 0x9b,
-	0xe1, 0xa5, 0x2f, 0x96, 0xb1, 0x9e, 0x80, 0xf9, 0x71, 0xac, 0xd3, 0x63,
-	0xe5, 0x88, 0x4e, 0xba, 0xb1, 0xee, 0xa4, 0x0d, 0xd2, 0xc5, 0x1e, 0x4b,
-	0xff, 0xa3, 0xf6, 0x2e, 0x92, 0x03, 0x8d, 0xe5, 0x82, 0x1f, 0x84, 0x59,
-	0xcd, 0x63, 0xe2, 0x0c, 0x94, 0x49, 0xbb, 0x0d, 0x80, 0x95, 0x8f, 0x1f,
-	0xb3, 0xf5, 0xda, 0x1d, 0xe0, 0x96, 0xeb, 0xc0, 0xf7, 0x71, 0xe5, 0x37,
-	0xd9, 0xf7, 0x11, 0x2f, 0xf1, 0x1f, 0xe8, 0xcd, 0xaf, 0xd5, 0xcb, 0x91,
-	0x26, 0xab, 0x05, 0xc9, 0x3f, 0x18, 0xca, 0x40, 0x00, 0x3c, 0xb1, 0x4f,
-	0x2f, 0x10, 0xdd, 0xd6, 0x63, 0x1d, 0x5d, 0x17, 0xff, 0xae, 0x69, 0xc4,
-	0x18, 0xce, 0x60, 0xb9, 0xd6, 0x76, 0xb0, 0xfc, 0xe4, 0x16, 0x0b, 0x1f,
-	0x9e, 0xfb, 0x9d, 0x5c, 0xf5, 0x6f, 0xed, 0xda, 0x46, 0xf3, 0xb8, 0x69,
-	0x0d, 0xda, 0x0e, 0xc3, 0x89, 0x40, 0x46, 0x54, 0x66, 0x31, 0x9e, 0x2b,
-	0x89, 0xd3, 0x90, 0xf1, 0xbd, 0x21, 0x59, 0x27, 0x76, 0x5e, 0xb6, 0xdc,
-	0x03, 0xaf, 0x74, 0xa1, 0xdc, 0x11, 0xc8, 0x8d, 0x11, 0x07, 0x65, 0x1d,
-	0x15, 0x94, 0x61, 0xfd, 0xc6, 0x81, 0xaf, 0x7c, 0xa9, 0x5f, 0xaf, 0x65,
-	0xbe, 0x34, 0x0c, 0xde, 0xcf, 0xe0, 0x77, 0x76, 0xb3, 0x2b, 0x5d, 0xa0,
-	0x43, 0xae, 0xb1, 0xb8, 0xb9, 0xdd, 0xa0, 0xd5, 0xea, 0xeb, 0x4b, 0x2c,
-	0x3d, 0xf7, 0xe0, 0x5f, 0x88, 0xd3, 0x25, 0x78, 0x62, 0x19, 0xf2, 0xf5,
-	0xf3, 0x21, 0xe8, 0x19, 0x65, 0x84, 0x99, 0x35, 0x13, 0x32, 0x51, 0xde,
-	0x26, 0xc5, 0x29, 0x5f, 0xc6, 0x4b, 0xf3, 0xdd, 0x4a, 0x5e, 0x86, 0xac,
-	0xf1, 0x41, 0x0b, 0x69, 0xf0, 0x41, 0x46, 0x06, 0xaa, 0x18, 0xaf, 0x84,
-	0x7b, 0xb9, 0x13, 0x6d, 0x5d, 0xc9, 0x26, 0xcd, 0x3a, 0x17, 0x4b, 0x63,
-	0xc0, 0x15, 0xd6, 0x8d, 0xb2, 0x41, 0xc3, 0x3c, 0x0c, 0x3a, 0xf4, 0x24,
-	0xd7, 0xa7, 0xe1, 0x7c, 0x13, 0xf0, 0xc5, 0x65, 0x26, 0x68, 0xb4, 0x38,
-	0x22, 0x7f, 0xc6, 0xdd, 0x01, 0xe0, 0x61, 0xa0, 0x72, 0x0f, 0xfa, 0x6f,
-	0xc1, 0x6f, 0x96, 0x89, 0x2d, 0x73, 0xf5, 0xf3, 0x40, 0x85, 0x30, 0x47,
-	0x74, 0x0f, 0x3e, 0x98, 0x82, 0xfc, 0x01, 0xdd, 0x0f, 0x90, 0x5f, 0xe6,
-	0x38, 0x17, 0xc2, 0xb5, 0x4d, 0xff, 0x1e, 0x9f, 0xda, 0xa1, 0x9f, 0xf3,
-	0xc3, 0xdb, 0xa4, 0x30, 0x17, 0xcd, 0x99, 0xb2, 0x87, 0xf2, 0x26, 0x7d,
-	0x0c, 0x74, 0x05, 0xf9, 0x13, 0x86, 0x0f, 0x06, 0x94, 0x41, 0x61, 0xf8,
-	0x78, 0x40, 0x99, 0x74, 0x1e, 0xb2, 0x86, 0x72, 0x88, 0x72, 0x61, 0x50,
-	0x71, 0xdd, 0x73, 0xa5, 0x00, 0xeb, 0xd3, 0x28, 0xf9, 0xde, 0x47, 0x08,
-	0x2b, 0x64, 0xd8, 0xb3, 0x1f, 0xcb, 0xf9, 0x85, 0x64, 0x4c, 0xe3, 0x49,
-	0xb0, 0x5e, 0x71, 0xc9, 0xea, 0x99, 0x75, 0x48, 0xb1, 0x77, 0xd2, 0xd6,
-	0x79, 0x49, 0xd7, 0x71, 0x57, 0xd5, 0xf9, 0x75, 0x65, 0x78, 0x3c, 0xc0,
-	0x5a, 0xfe, 0xb4, 0x22, 0x1e, 0x3b, 0x76, 0xf1, 0x59, 0xe2, 0x0d, 0x99,
-	0xaf, 0xe1, 0xdd, 0xb9, 0x3b, 0x1f, 0xf5, 0xd7, 0x7a, 0xb7, 0xb5, 0x61,
-	0xf5, 0xbb, 0x09, 0x71, 0xfd, 0x74, 0xf7, 0x01, 0xf5, 0x4f, 0x78, 0x17,
-	0x86, 0x8f, 0x06, 0x51, 0x79, 0x6f, 0xc3, 0xea, 0x31, 0x7e, 0x76, 0x8d,
-	0xb2, 0xf3, 0x6b, 0x94, 0xfd, 0xc9, 0x1a, 0x65, 0xef, 0x6d, 0x5c, 0x5d,
-	0xf6, 0xc0, 0x1a, 0x65, 0x4f, 0xaf, 0x51, 0xe6, 0x37, 0xad, 0x2e, 0xdb,
-	0xb5, 0x46, 0xd9, 0x5b, 0xd7, 0x28, 0x3b, 0xb0, 0x46, 0x99, 0x0b, 0x1e,
-	0xde, 0x25, 0xc5, 0xc4, 0xbd, 0x9c, 0xbb, 0xc5, 0xcd, 0xe7, 0x62, 0xab,
-	0x71, 0xd3, 0x80, 0x7a, 0xed, 0x2b, 0xea, 0x7d, 0x6d, 0x8d, 0x7a, 0x8d,
-	0xa8, 0xd7, 0xba, 0xa2, 0xde, 0xcd, 0xee, 0xea, 0x7a, 0x4d, 0xa8, 0x17,
-	0x5f, 0x51, 0xef, 0x77, 0xd7, 0xa8, 0xc7, 0xf2, 0x4f, 0xd9, 0x71, 0x7a,
-	0xa0, 0xd1, 0x5e, 0x6b, 0xbd, 0x1a, 0x45, 0xda, 0x58, 0x1e, 0x40, 0x1f,
-	0xfd, 0xb4, 0x32, 0x32, 0x86, 0xf2, 0x4c, 0xe3, 0x0d, 0x74, 0x9e, 0x04,
-	0xdd, 0x51, 0x26, 0x83, 0xcf, 0x7c, 0xf2, 0xfe, 0x06, 0x19, 0x49, 0xf4,
-	0x78, 0x6f, 0x53, 0x2d, 0xa0, 0xb1, 0xb4, 0x97, 0x52, 0xe4, 0x3f, 0x29,
-	0x80, 0xb7, 0x0b, 0x03, 0xa2, 0x12, 0x4a, 0x42, 0x19, 0x0c, 0x54, 0xab,
-	0x92, 0x7b, 0xc0, 0x5f, 0x59, 0xe8, 0xbf, 0x03, 0xe1, 0x80, 0xe6, 0x2d,
-	0x53, 0xf7, 0xf2, 0xf2, 0xb9, 0x5f, 0x8e, 0x50, 0xae, 0x66, 0x82, 0x3b,
-	0x73, 0xfe, 0x7c, 0x7f, 0x23, 0x68, 0xf6, 0x12, 0xda, 0xec, 0x43, 0xcb,
-	0x43, 0x15, 0x57, 0x06, 0x2b, 0x19, 0xf0, 0x82, 0x23, 0x17, 0xfd, 0x4d,
-	0x72, 0x31, 0x40, 0xdd, 0x6a, 0x4c, 0x16, 0x12, 0x8e, 0x2c, 0xe0, 0x39,
-	0x17, 0xe0, 0x5d, 0x35, 0xe2, 0xad, 0x8c, 0x1c, 0x2e, 0xf7, 0xcb, 0xb1,
-	0xf2, 0x87, 0x55, 0xa4, 0x23, 0x87, 0x82, 0xf5, 0x72, 0xc6, 0x33, 0x7d,
-	0xef, 0xf3, 0xe7, 0xa1, 0x9d, 0x5d, 0xb9, 0xe4, 0xa7, 0x93, 0x0b, 0x9a,
-	0x27, 0xfe, 0x31, 0x1c, 0x44, 0x3f, 0x33, 0x7e, 0xda, 0xfb, 0x03, 0x0a,
-	0xc9, 0x0a, 0x6d, 0xa9, 0x5a, 0x5f, 0xe3, 0xe8, 0xeb, 0x68, 0x79, 0x83,
-	0xdc, 0x6a, 0xdb, 0xef, 0xf5, 0xe7, 0xbb, 0xc1, 0x73, 0xde, 0x29, 0xca,
-	0x90, 0x12, 0xe0, 0x3a, 0x08, 0xde, 0x46, 0xdb, 0x2f, 0x09, 0xdb, 0xc0,
-	0xf6, 0x2a, 0x6d, 0x82, 0xac, 0xff, 0x87, 0xf0, 0xd6, 0x04, 0xeb, 0xb3,
-	0x8c, 0xfa, 0x4b, 0x26, 0x55, 0x06, 0x32, 0xa1, 0xaf, 0x0b, 0xfa, 0x2b,
-	0x25, 0x83, 0x55, 0xc8, 0x9e, 0xf2, 0x0f, 0xc3, 0xac, 0xcb, 0x31, 0xa2,
-	0xb1, 0xa4, 0x50, 0xab, 0xc3, 0x32, 0xd6, 0x23, 0xff, 0x2f, 0x2e, 0xc9,
-	0x8a, 0x02, 0xe4, 0x8b, 0xb1, 0xd1, 0xfe, 0x13, 0x78, 0xb4, 0x5d, 0x06,
-	0x4b, 0xe9, 0x42, 0x56, 0x76, 0x61, 0xfd, 0x7e, 0x0d, 0x6b, 0xea, 0xe2,
-	0xfa, 0x93, 0xf5, 0xb2, 0x31, 0x80, 0x1d, 0xc0, 0x72, 0x74, 0xda, 0x46,
-	0xfb, 0xec, 0x19, 0xe0, 0x61, 0x9c, 0x6b, 0x9e, 0xcc, 0xc5, 0x9c, 0x61,
-	0xda, 0x3e, 0xc3, 0x90, 0x8f, 0xf9, 0x0a, 0xfb, 0x26, 0xbc, 0x49, 0xfb,
-	0x1b, 0x36, 0x5b, 0xa9, 0xdd, 0xfe, 0x6e, 0xc1, 0xef, 0x94, 0xfd, 0x0d,
-	0x99, 0x5a, 0xf2, 0xed, 0xef, 0x04, 0x7e, 0x77, 0xdb, 0xdf, 0x49, 0xfc,
-	0xee, 0xd5, 0xbf, 0x27, 0xca, 0x7b, 0xf7, 0x2a, 0xff, 0x6a, 0xc9, 0xcf,
-	0xb5, 0xcb, 0xe1, 0xd2, 0x7b, 0xad, 0x6c, 0xc1, 0x25, 0x9f, 0x77, 0xcc,
-	0x3c, 0x01, 0x77, 0x99, 0x6d, 0x0a, 0xce, 0xb0, 0xb6, 0xdd, 0xda, 0x61,
-	0xeb, 0xf4, 0x78, 0x9b, 0x85, 0x34, 0x30, 0xe1, 0x0c, 0x54, 0x9d, 0x6c,
-	0x2c, 0xd3, 0x95, 0x1c, 0x97, 0x63, 0xf8, 0x2d, 0x5e, 0x2c, 0xf3, 0x79,
-	0xdc, 0x0d, 0x0e, 0xbe, 0x00, 0x7d, 0x33, 0x5e, 0xa6, 0xbc, 0xf4, 0x31,
-	0xf7, 0x94, 0x9c, 0x5f, 0x66, 0xaf, 0x11, 0x17, 0x4a, 0xf2, 0x53, 0xe9,
-	0x47, 0x0a, 0x92, 0x2e, 0x4c, 0x83, 0x21, 0x0e, 0x04, 0xae, 0xbc, 0x27,
-	0x00, 0xed, 0x5e, 0xed, 0xc8, 0xde, 0xab, 0x5d, 0xd8, 0x57, 0xfe, 0xf4,
-	0x5e, 0xc8, 0xd8, 0x7c, 0xe9, 0xea, 0x18, 0xe9, 0x41, 0x9d, 0x95, 0x11,
-	0x37, 0x03, 0x6c, 0x9f, 0xed, 0x1d, 0x1c, 0x2f, 0xe5, 0x3f, 0xac, 0x32,
-	0xb7, 0xff, 0x6a, 0xae, 0x6f, 0x17, 0x74, 0x79, 0x18, 0xc6, 0x32, 0x6d,
-	0xd0, 0x4b, 0x5c, 0x57, 0xea, 0xa9, 0x9b, 0x6e, 0x8a, 0x65, 0x1a, 0x64,
-	0xe0, 0x60, 0x1b, 0xea, 0xb3, 0x9c, 0xb8, 0x72, 0xd0, 0x47, 0x3a, 0x35,
-	0x28, 0x72, 0xf7, 0x44, 0xdf, 0xa2, 0x33, 0x3e, 0xf9, 0x73, 0xe0, 0xc7,
-	0x7e, 0xc9, 0x1f, 0x7c, 0x00, 0xf8, 0x7d, 0xd9, 0x29, 0x4e, 0xbd, 0xe2,
-	0x8c, 0x4f, 0xfd, 0x9d, 0x33, 0x31, 0xb5, 0x63, 0xc7, 0x50, 0xff, 0x8e,
-	0x1d, 0xa3, 0xfd, 0xae, 0xd5, 0x2d, 0x3b, 0x76, 0x4c, 0xf4, 0x67, 0x31,
-	0xff, 0x1e, 0x6f, 0x50, 0x7c, 0x6f, 0x2f, 0x95, 0x7c, 0xc2, 0xac, 0xfd,
-	0x4c, 0xd0, 0x8d, 0xf7, 0x6c, 0xdf, 0xab, 0xdf, 0x0f, 0x48, 0x4f, 0xb2,
-	0x55, 0x38, 0x7e, 0x87, 0xd5, 0x49, 0x6c, 0x07, 0x7a, 0xe9, 0xa5, 0x1d,
-	0xa8, 0x50, 0x2f, 0x05, 0x7c, 0xd0, 0x26, 0xde, 0x06, 0x1b, 0x82, 0xed,
-	0x94, 0x5d, 0xf7, 0x92, 0x6a, 0xf0, 0x63, 0xba, 0x5f, 0x75, 0x36, 0x13,
-	0x33, 0x6b, 0xde, 0x63, 0xed, 0xeb, 0x4d, 0x28, 0xe7, 0x33, 0x71, 0x49,
-	0x7c, 0xd1, 0xde, 0x69, 0xd0, 0xf6, 0x69, 0xbe, 0x44, 0x5a, 0x72, 0x65,
-	0xac, 0xd4, 0x8f, 0x36, 0xa0, 0x97, 0xb3, 0xf6, 0x3a, 0x81, 0xf1, 0x0e,
-	0xa2, 0xaf, 0x13, 0x47, 0xd1, 0x8e, 0xb2, 0x24, 0xdd, 0x2d, 0xea, 0x41,
-	0xd4, 0xe9, 0xf1, 0xb6, 0x08, 0xed, 0x9a, 0x47, 0x24, 0x5f, 0x26, 0xdf,
-	0xd3, 0x36, 0x88, 0x4b, 0xaa, 0x0d, 0xcf, 0xd5, 0xc3, 0xb0, 0x75, 0x1a,
-	0x22, 0x7b, 0x43, 0x6a, 0x76, 0xd1, 0xaf, 0x2a, 0xf1, 0x0f, 0xcb, 0xc8,
-	0xec, 0x76, 0xd4, 0x33, 0xf6, 0xbc, 0xf2, 0x61, 0x17, 0xcd, 0x66, 0x25,
-	0xb7, 0xeb, 0x5e, 0xdc, 0x3d, 0x3c, 0x17, 0x71, 0x7f, 0x0b, 0xee, 0xe3,
-	0xb8, 0x47, 0x70, 0x02, 0xe7, 0x41, 0xcc, 0xea, 0xb2, 0x51, 0x8c, 0xfd,
-	0xef, 0x25, 0x37, 0x09, 0x7a, 0x2d, 0x85, 0x9b, 0x72, 0x7e, 0xd6, 0x53,
-	0xa2, 0xb6, 0x28, 0x99, 0x40, 0x7d, 0xf8, 0x29, 0xfe, 0x11, 0x19, 0x3d,
-	0x8d, 0xdf, 0x0f, 0xd2, 0xee, 0x9e, 0x90, 0xd1, 0x59, 0x8e, 0x53, 0x02,
-	0x4c, 0x93, 0x92, 0x3f, 0xfd, 0x00, 0xae, 0x29, 0x5c, 0x0f, 0xe3, 0xe2,
-	0xdc, 0xd8, 0xff, 0xc2, 0x66, 0x25, 0x2d, 0xfa, 0x39, 0x4f, 0xfa, 0xae,
-	0xe2, 0x37, 0x69, 0xbb, 0x4a, 0x1b, 0x08, 0x74, 0x5d, 0x8d, 0xe8, 0x3d,
-	0xb0, 0xbf, 0x93, 0x9a, 0xdf, 0x0b, 0xad, 0xa0, 0xa5, 0x6a, 0x56, 0xcb,
-	0x22, 0xc0, 0x00, 0xb9, 0x03, 0x9b, 0xa4, 0x95, 0x73, 0xec, 0xb5, 0x65,
-	0xbd, 0xba, 0x2c, 0xa5, 0xcb, 0xfa, 0x6c, 0x19, 0xee, 0xd5, 0x06, 0x19,
-	0x69, 0x03, 0xc4, 0x94, 0xdb, 0x12, 0xe1, 0x93, 0xb2, 0x01, 0x74, 0x8d,
-	0xf5, 0x3d, 0x7f, 0x59, 0xb9, 0xb8, 0xa8, 0xed, 0xbd, 0x73, 0x55, 0xd2,
-	0x37, 0x69, 0x3e, 0x0c, 0xef, 0x0f, 0x9a, 0xd0, 0x3f, 0x65, 0x81, 0x48,
-	0xc3, 0x09, 0x57, 0xa6, 0x3d, 0xd2, 0xc0, 0xc7, 0x5a, 0x48, 0x03, 0x8d,
-	0x3e, 0x69, 0xbb, 0x9e, 0xef, 0xb8, 0x86, 0xec, 0xaf, 0x00, 0x1b, 0x92,
-	0xb6, 0x64, 0x17, 0xec, 0x73, 0x8e, 0x71, 0x8c, 0xcf, 0x9e, 0x02, 0xaf,
-	0xe5, 0x96, 0x78, 0x4d, 0x64, 0xa6, 0x44, 0xdc, 0x44, 0x36, 0x26, 0xd7,
-	0x99, 0xf8, 0x39, 0x87, 0x39, 0xf3, 0x7e, 0xde, 0xe2, 0xe9, 0xf3, 0x16,
-	0x4f, 0x4f, 0xda, 0xbb, 0xe7, 0xe4, 0xb5, 0xcd, 0x38, 0x8f, 0x67, 0xae,
-	0x0f, 0xe8, 0xaa, 0x4a, 0x9e, 0x9b, 0xc6, 0x1d, 0x75, 0xcb, 0xe7, 0x64,
-	0x54, 0xdb, 0x6f, 0x31, 0x79, 0x87, 0x96, 0x79, 0x5f, 0xc5, 0x5a, 0x96,
-	0x00, 0x73, 0x83, 0x14, 0x12, 0x31, 0xbd, 0xf6, 0xae, 0xff, 0x5b, 0xae,
-	0xa1, 0x55, 0xe2, 0x64, 0x99, 0xbf, 0x56, 0x07, 0x53, 0xe4, 0xa3, 0x12,
-	0x2e, 0xd2, 0xee, 0xa7, 0x35, 0x5c, 0xb7, 0x40, 0x0e, 0x16, 0x44, 0xb5,
-	0x35, 0xca, 0x95, 0xa0, 0x05, 0x95, 0x80, 0x46, 0x0b, 0x9f, 0x82, 0x3d,
-	0x95, 0x9f, 0xa5, 0x9d, 0xde, 0x41, 0xdf, 0x28, 0x9e, 0xef, 0xdd, 0x48,
-	0x3a, 0x52, 0x86, 0x6f, 0x1c, 0x95, 0xef, 0xd5, 0x74, 0xea, 0x28, 0x3f,
-	0xa1, 0x6d, 0x71, 0xd7, 0xdf, 0xea, 0x5a, 0x9f, 0xde, 0x55, 0xfe, 0x96,
-	0x95, 0x65, 0x29, 0xea, 0x67, 0xb4, 0x4b, 0xe5, 0x7b, 0xdb, 0xc8, 0x63,
-	0x1e, 0xfc, 0xe1, 0xac, 0xf2, 0xb5, 0xff, 0x55, 0x50, 0x7d, 0x9b, 0x56,
-	0xd4, 0xd7, 0x77, 0xc7, 0x3e, 0xbb, 0xf6, 0xee, 0xd9, 0x7b, 0xca, 0xde,
-	0x0b, 0x6e, 0x1f, 0xef, 0x8e, 0xb8, 0x19, 0xde, 0xb1, 0x86, 0x19, 0xf6,
-	0xa1, 0xf9, 0x2a, 0x34, 0xb6, 0x72, 0x97, 0x57, 0x14, 0xf2, 0xd5, 0x57,
-	0xe5, 0x96, 0x59, 0x23, 0x97, 0xf7, 0x96, 0xc2, 0x10, 0x3e, 0xa2, 0xb7,
-	0x00, 0xff, 0x38, 0x7b, 0xb0, 0x22, 0xb7, 0x54, 0x89, 0xb7, 0x4f, 0x02,
-	0x7f, 0x43, 0x2e, 0x79, 0xd3, 0x13, 0xca, 0xe3, 0xbb, 0x84, 0xf6, 0x6a,
-	0xb1, 0x44, 0x9c, 0x5f, 0x10, 0xae, 0x4d, 0xb1, 0xf4, 0xb4, 0x5e, 0x9b,
-	0x23, 0xa5, 0x05, 0xe0, 0xe7, 0xcb, 0xa0, 0xfb, 0x30, 0x5c, 0x08, 0x8a,
-	0xa0, 0x9c, 0x3f, 0xc6, 0x6f, 0xd8, 0x28, 0xa5, 0x67, 0xf1, 0x7e, 0xa3,
-	0x14, 0x27, 0xc9, 0x73, 0xae, 0xe5, 0xe1, 0xb3, 0xe0, 0xa7, 0x9f, 0x41,
-	0xbf, 0x28, 0xeb, 0xe3, 0xef, 0x1f, 0xe0, 0x1d, 0xee, 0xb3, 0x58, 0xc4,
-	0x36, 0xda, 0x40, 0x1c, 0x9b, 0x6b, 0xc7, 0x35, 0xa3, 0xaf, 0x5e, 0xef,
-	0x97, 0x73, 0xbd, 0xd2, 0xdd, 0x05, 0x59, 0x8a, 0x2b, 0xc8, 0xb9, 0x12,
-	0xeb, 0x93, 0xfe, 0xfb, 0xd6, 0x19, 0x1d, 0xb1, 0xa1, 0xd9, 0xdc, 0x57,
-	0xb6, 0xe5, 0x9a, 0xd7, 0xd3, 0x20, 0x7d, 0xa8, 0x74, 0x7f, 0x01, 0x72,
-	0xc7, 0xf5, 0x37, 0xca, 0xa0, 0x96, 0x9d, 0xa4, 0x09, 0xd2, 0xc0, 0xcd,
-	0xca, 0xd0, 0xe6, 0xfb, 0x95, 0xa1, 0xcd, 0xa7, 0x41, 0x8b, 0xb8, 0xca,
-	0x8b, 0x8e, 0xa1, 0xcd, 0x2f, 0xe3, 0x8e, 0xab, 0xfc, 0xa2, 0x13, 0xf1,
-	0xf1, 0x00, 0xfc, 0xca, 0xbd, 0x25, 0xd7, 0x19, 0xad, 0x82, 0x7e, 0xcb,
-	0x71, 0x94, 0xcf, 0x13, 0xe7, 0x98, 0x3f, 0xc7, 0xd9, 0x69, 0xfb, 0x3f,
-	0x27, 0x63, 0xe5, 0x50, 0xdb, 0x5b, 0xf9, 0xd9, 0x7b, 0x71, 0x5f, 0xaf,
-	0xe5, 0x8c, 0xf2, 0xb3, 0xca, 0xc8, 0xab, 0x77, 0xe0, 0xde, 0x99, 0x3c,
-	0x22, 0x9d, 0x5e, 0x4c, 0x9e, 0x45, 0x5f, 0xdf, 0x75, 0xc6, 0xaa, 0x2f,
-	0xe3, 0xfa, 0x3e, 0xae, 0x57, 0x71, 0xbd, 0x82, 0x7e, 0x5f, 0x40, 0xf9,
-	0x7a, 0x99, 0xf7, 0x9a, 0x51, 0x5f, 0xd4, 0x68, 0xf5, 0x79, 0x67, 0xe4,
-	0xf4, 0x4b, 0xb8, 0x5c, 0x35, 0x56, 0x7d, 0xce, 0xc9, 0xcf, 0x86, 0x9b,
-	0x16, 0x7c, 0xca, 0xb0, 0xaf, 0x3a, 0xa6, 0xef, 0x0c, 0xe6, 0x00, 0x9a,
-	0x2e, 0xcf, 0x63, 0xec, 0xa7, 0x35, 0xcf, 0x0c, 0x42, 0x1f, 0xe4, 0x61,
-	0xaf, 0x8c, 0x68, 0x98, 0xb6, 0x03, 0x3e, 0xf8, 0xd3, 0x7d, 0xb8, 0xcf,
-	0x36, 0xca, 0x62, 0x82, 0xf6, 0xe5, 0x93, 0xba, 0x7e, 0xbe, 0x7c, 0xbd,
-	0xc6, 0xed, 0xf4, 0x2a, 0xfe, 0xa1, 0x4f, 0x18, 0xc9, 0x03, 0x23, 0x8d,
-	0x67, 0x4a, 0x94, 0x05, 0xd0, 0x4d, 0xa5, 0x09, 0xdc, 0x1b, 0xb5, 0x4c,
-	0x28, 0x4a, 0x24, 0x0f, 0xd8, 0x8e, 0x32, 0xa1, 0x5e, 0xee, 0x50, 0xd6,
-	0x50, 0xf6, 0x50, 0x96, 0x98, 0xf5, 0x18, 0x7d, 0x90, 0x32, 0xfc, 0x3a,
-	0xe8, 0x4d, 0xda, 0x25, 0xbe, 0xf1, 0x4d, 0xa6, 0x72, 0xca, 0xc8, 0xd3,
-	0xfd, 0x7a, 0x2d, 0xc6, 0x4a, 0x2a, 0x01, 0xc8, 0x51, 0x86, 0xeb, 0xe4,
-	0x41, 0xdc, 0xf3, 0x6a, 0x0c, 0x57, 0xfe, 0xe4, 0xfb, 0xf0, 0x9b, 0x6b,
-	0x33, 0x86, 0x7a, 0xb8, 0xca, 0xc3, 0xb8, 0xe3, 0x2a, 0xdf, 0xa8, 0x8c,
-	0x1c, 0xe1, 0x9a, 0x26, 0xed, 0x9a, 0x3e, 0x09, 0x3c, 0x70, 0x7e, 0x4a,
-	0xc7, 0x38, 0x94, 0xbf, 0x07, 0x78, 0xaf, 0x5a, 0x9f, 0x7a, 0xa3, 0x18,
-	0x1e, 0xc4, 0xd5, 0x4d, 0x7e, 0x6e, 0x31, 0xeb, 0xa5, 0x69, 0x77, 0x5d,
-	0x83, 0xe1, 0xc5, 0x04, 0xca, 0x62, 0x28, 0x6b, 0x33, 0x3a, 0x73, 0x09,
-	0x8f, 0x59, 0x8b, 0x47, 0xfe, 0x56, 0xf6, 0x37, 0xe8, 0x09, 0xb6, 0x2e,
-	0xe4, 0x35, 0xc6, 0xc5, 0x5c, 0x4e, 0xee, 0x57, 0xa3, 0x65, 0xfa, 0xc9,
-	0x94, 0xe1, 0x8c, 0x65, 0x70, 0x7e, 0xec, 0x17, 0xe5, 0x1a, 0x07, 0x81,
-	0xd4, 0xe2, 0x04, 0x4f, 0x62, 0xcd, 0xce, 0xc9, 0xa1, 0xf2, 0x47, 0xb4,
-	0xdf, 0xde, 0x78, 0xc2, 0xac, 0x87, 0xa8, 0xa8, 0x1e, 0xfa, 0x4e, 0xd0,
-	0xe6, 0xf9, 0x75, 0xfd, 0xde, 0x3d, 0xc1, 0xdf, 0x49, 0x1d, 0x4f, 0xaa,
-	0xc9, 0x7b, 0x63, 0xef, 0x14, 0x97, 0xc9, 0x3a, 0xda, 0x1d, 0x58, 0xb3,
-	0x4a, 0x3d, 0xde, 0x19, 0x47, 0xa0, 0xcc, 0x23, 0x3f, 0x1d, 0x01, 0x4f,
-	0x60, 0xf2, 0x9a, 0xf7, 0xe9, 0x83, 0xac, 0xc5, 0x4f, 0x3e, 0x6c, 0x62,
-	0x57, 0x4e, 0xc1, 0xa6, 0xdb, 0xbb, 0xd4, 0x07, 0x64, 0x65, 0x22, 0x2e,
-	0xa7, 0x4b, 0x2d, 0x32, 0x5b, 0x52, 0x6d, 0x31, 0x2b, 0x3b, 0x63, 0x92,
-	0xd4, 0xfa, 0x97, 0x76, 0xdf, 0xc0, 0x54, 0xcc, 0xd2, 0xdd, 0x8d, 0xe8,
-	0xff, 0x93, 0xd0, 0xb1, 0x15, 0xe8, 0xd8, 0x8d, 0xd0, 0xc1, 0x2b, 0x65,
-	0xc4, 0xfe, 0x86, 0xd5, 0x32, 0x82, 0x6d, 0xd2, 0xf0, 0xd6, 0x8f, 0xa0,
-	0x5d, 0x44, 0x7f, 0x71, 0x4d, 0x6b, 0x79, 0x29, 0x38, 0x7b, 0xab, 0x13,
-	0xce, 0xbe, 0xea, 0x4a, 0x1d, 0xd4, 0xe3, 0xb9, 0x62, 0x60, 0x3d, 0x5d,
-	0xa2, 0xed, 0x9a, 0x0e, 0x72, 0xc0, 0xc9, 0x3e, 0xd0, 0xdd, 0x53, 0x93,
-	0xf0, 0xef, 0x29, 0x97, 0x01, 0xf3, 0x19, 0xc0, 0x3c, 0x33, 0xe9, 0x44,
-	0xb6, 0x81, 0x30, 0x40, 0x33, 0x33, 0xd5, 0x2b, 0x0b, 0x73, 0xa4, 0x43,
-	0xc8, 0x80, 0x49, 0xac, 0x67, 0xb0, 0x0e, 0x76, 0x00, 0xc7, 0x87, 0xdc,
-	0x9e, 0xda, 0xa6, 0xdf, 0x19, 0x7d, 0xde, 0x2e, 0x0b, 0x95, 0x3b, 0x2d,
-	0x6c, 0xc7, 0xea, 0x60, 0x5b, 0xb7, 0x04, 0xdb, 0x3e, 0xc0, 0xb6, 0x7f,
-	0x4d, 0xd8, 0xd6, 0xd2, 0xc5, 0x1d, 0xb0, 0x69, 0xc8, 0x1f, 0x11, 0x5e,
-	0xdb, 0x2c, 0x3d, 0x94, 0xac, 0x1d, 0x4c, 0x9b, 0xe8, 0x87, 0x80, 0x87,
-	0x34, 0x86, 0xdf, 0xb3, 0x8f, 0x52, 0x96, 0xa1, 0x9c, 0xcf, 0x0f, 0xa1,
-	0x0e, 0x9e, 0x67, 0x13, 0x56, 0x0e, 0x7e, 0xc2, 0xc2, 0x42, 0x3b, 0x21,
-	0x0b, 0x5b, 0x79, 0xd0, 0xc9, 0xcd, 0x12, 0x86, 0x53, 0x80, 0x17, 0xef,
-	0xaa, 0xf5, 0x7d, 0xf2, 0xce, 0x7e, 0xaf, 0xb2, 0xfd, 0xb0, 0xef, 0x68,
-	0x2e, 0xeb, 0xad, 0x9e, 0x8f, 0xe8, 0x2b, 0xb2, 0xbb, 0x27, 0x9c, 0xec,
-	0xaa, 0x79, 0xd5, 0xd3, 0x1c, 0xe5, 0xad, 0x2b, 0x43, 0xa0, 0x93, 0xa1,
-	0x65, 0xb4, 0xa6, 0xdd, 0x13, 0x4b, 0xc7, 0xeb, 0xec, 0xfc, 0x0e, 0x1b,
-	0xbe, 0x09, 0xe2, 0xd0, 0x87, 0x94, 0x37, 0xff, 0xc5, 0xf8, 0xec, 0xf2,
-	0xe5, 0x06, 0xc6, 0x69, 0xcd, 0x33, 0x69, 0x93, 0xbf, 0x29, 0x93, 0x6a,
-	0xb4, 0x68, 0x7c, 0x9a, 0x76, 0x8c, 0x55, 0x6f, 0xc7, 0xbb, 0x32, 0x6c,
-	0xd6, 0xfc, 0x18, 0xd7, 0x9c, 0x3e, 0x4a, 0xe7, 0x03, 0xc3, 0x96, 0xbf,
-	0xd2, 0x93, 0x05, 0xb9, 0xd5, 0xce, 0xfd, 0xd2, 0x1a, 0x6b, 0xb7, 0x71,
-	0x69, 0xed, 0x86, 0xab, 0x2b, 0xe7, 0x28, 0xd2, 0xf1, 0x80, 0xab, 0x7d,
-	0x5e, 0xfa, 0xf0, 0x8d, 0x3e, 0xe5, 0x27, 0x6d, 0x25, 0x94, 0xcf, 0xf4,
-	0x78, 0xad, 0xf0, 0x0d, 0xbe, 0xb8, 0xca, 0xee, 0x4a, 0x59, 0xb9, 0x49,
-	0xff, 0x38, 0x1a, 0xa3, 0x60, 0xe5, 0x64, 0x01, 0xfd, 0x4f, 0x38, 0x43,
-	0xd5, 0xb5, 0xe4, 0x65, 0x24, 0x27, 0x39, 0x9f, 0x7b, 0xe5, 0x8e, 0x07,
-	0xc9, 0xa3, 0x25, 0x6d, 0x5f, 0x5f, 0xb3, 0xe7, 0x30, 0xf0, 0x47, 0xf8,
-	0x17, 0x36, 0xc3, 0x64, 0x80, 0xce, 0xcd, 0xca, 0xa8, 0x5d, 0xb7, 0xd1,
-	0xa5, 0xf5, 0xe7, 0x35, 0x0c, 0xdd, 0xc8, 0x58, 0xae, 0xb2, 0x30, 0x6b,
-	0x3b, 0x16, 0x76, 0xdd, 0x4a, 0x5b, 0x96, 0x73, 0xa0, 0x3d, 0xdb, 0x68,
-	0x6c, 0xc1, 0x32, 0xed, 0x4f, 0xca, 0x2e, 0xda, 0x9f, 0x57, 0x37, 0x4a,
-	0x33, 0xe7, 0x93, 0xb5, 0x65, 0xb4, 0x53, 0x57, 0xce, 0x6f, 0xa5, 0x5f,
-	0x49, 0x38, 0x09, 0xb7, 0xa1, 0xad, 0x94, 0x22, 0x6c, 0xa1, 0x0c, 0x07,
-	0xd7, 0xe9, 0x35, 0x50, 0xb4, 0x5d, 0xf7, 0x34, 0x34, 0x9a, 0x38, 0xf6,
-	0x5e, 0xf4, 0xcf, 0x31, 0xc9, 0x7f, 0xbc, 0xd3, 0xce, 0x5f, 0x4b, 0x96,
-	0xd5, 0xeb, 0x9e, 0x2b, 0x97, 0xf0, 0x37, 0xb4, 0x6c, 0x8d, 0x22, 0xfc,
-	0x45, 0x74, 0x51, 0x8f, 0x43, 0xd2, 0x04, 0x69, 0x21, 0xa2, 0xc5, 0x9d,
-	0x56, 0xdf, 0x44, 0xb4, 0xb7, 0x15, 0xb4, 0x77, 0x1f, 0xf0, 0x44, 0x19,
-	0xce, 0x78, 0xde, 0x16, 0x3c, 0x1f, 0xc7, 0x73, 0xc4, 0x27, 0x91, 0x0c,
-	0xa7, 0x4d, 0xb4, 0x52, 0x8e, 0x53, 0x86, 0xc7, 0x61, 0xf7, 0x50, 0xd6,
-	0x6f, 0xb7, 0xfc, 0x94, 0xb3, 0xbc, 0x44, 0x5d, 0xf0, 0xfb, 0xe8, 0xe7,
-	0x86, 0x46, 0x63, 0xa7, 0x17, 0x1b, 0x29, 0x5f, 0x37, 0xcb, 0x91, 0xba,
-	0xb2, 0xcb, 0xc9, 0xef, 0xfa, 0x39, 0x6f, 0xff, 0x7f, 0x30, 0xe7, 0xe4,
-	0x8a, 0x39, 0x7b, 0x76, 0xce, 0x55, 0xbc, 0x6f, 0xc5, 0xfb, 0x16, 0xea,
-	0x82, 0x54, 0x4d, 0xde, 0x58, 0x5c, 0x68, 0x7d, 0x56, 0x2f, 0x27, 0x22,
-	0x19, 0xc1, 0x79, 0x1d, 0xb5, 0x73, 0xf8, 0x7c, 0xdd, 0xbc, 0x8e, 0xbe,
-	0x89, 0x79, 0xb5, 0x2f, 0x9b, 0xd7, 0xde, 0xcb, 0xce, 0x6b, 0x2d, 0x1e,
-	0x27, 0x2f, 0x47, 0xf3, 0x8b, 0xcb, 0x81, 0x12, 0xe7, 0x38, 0x84, 0x39,
-	0x12, 0x86, 0x68, 0x8e, 0x19, 0x3b, 0x47, 0x51, 0x1d, 0x7b, 0x7e, 0x0a,
-	0xbf, 0xeb, 0xe7, 0x47, 0xdd, 0xff, 0xf7, 0xa0, 0xe9, 0x26, 0xf8, 0xc4,
-	0x4d, 0x56, 0xfe, 0x3f, 0x29, 0xb7, 0x96, 0xb9, 0xd6, 0xe9, 0xac, 0xc8,
-	0x7e, 0x75, 0xa8, 0xfc, 0x72, 0x23, 0xf7, 0x11, 0xf6, 0x06, 0x56, 0x8f,
-	0x41, 0x5f, 0xec, 0x83, 0xcd, 0x37, 0x54, 0x52, 0x7d, 0x31, 0x09, 0xc3,
-	0xdb, 0x82, 0x66, 0x8c, 0xbd, 0x49, 0xfb, 0xaa, 0xab, 0x63, 0xf8, 0xcf,
-	0x36, 0x8a, 0x4f, 0x7b, 0x83, 0xfa, 0x1c, 0xfa, 0xee, 0x24, 0x6d, 0xb0,
-	0x1c, 0xec, 0xe4, 0x6c, 0x32, 0xa6, 0x6d, 0x31, 0xea, 0xc4, 0x74, 0x32,
-	0x2b, 0x15, 0xc9, 0x9f, 0xcc, 0x26, 0xe1, 0xd8, 0x62, 0x0c, 0xd8, 0x6a,
-	0xb0, 0x21, 0x6f, 0x85, 0xac, 0xb9, 0xb5, 0x7a, 0x50, 0xdd, 0x02, 0x7b,
-	0xe7, 0x96, 0xd3, 0xef, 0x53, 0xb7, 0xc1, 0xd6, 0xb9, 0xed, 0xf4, 0x8d,
-	0xea, 0x10, 0x6c, 0x9b, 0x43, 0xb0, 0x73, 0x0e, 0x55, 0x69, 0x7b, 0xde,
-	0x0c, 0xba, 0x6b, 0x87, 0x1e, 0xe2, 0x5c, 0xb8, 0x26, 0xb4, 0x71, 0x38,
-	0x3f, 0xe2, 0xfe, 0x0b, 0x5c, 0x83, 0x20, 0xa5, 0x76, 0x34, 0x71, 0x5d,
-	0x5a, 0x97, 0x95, 0xbd, 0x96, 0xac, 0x8a, 0xf4, 0xd3, 0x06, 0x1b, 0x4f,
-	0x32, 0x7e, 0xe5, 0xe5, 0x69, 0x8b, 0x34, 0xe2, 0x01, 0xcf, 0xc4, 0x1f,
-	0x69, 0xab, 0x7e, 0xfe, 0x57, 0x36, 0x89, 0x9f, 0xc3, 0xf8, 0xf7, 0x42,
-	0xbe, 0xd6, 0xd3, 0x14, 0xef, 0x5e, 0x1d, 0x7f, 0x50, 0x06, 0x47, 0xf4,
-	0xb0, 0xf3, 0x35, 0xe4, 0xef, 0x65, 0xe9, 0xe9, 0x9e, 0x58, 0x26, 0x0c,
-	0x47, 0xfb, 0x64, 0x13, 0xe3, 0x01, 0xb9, 0x6a, 0x2d, 0x26, 0xa0, 0xfc,
-	0xfa, 0x98, 0x00, 0xfd, 0xac, 0x4f, 0x03, 0xbf, 0xd3, 0xb8, 0x44, 0x46,
-	0x18, 0x77, 0xa8, 0x46, 0x76, 0xf9, 0x57, 0xac, 0x5d, 0x1e, 0xc1, 0x91,
-	0x02, 0x1c, 0x46, 0x3e, 0xaf, 0xd6, 0x73, 0xcb, 0xf5, 0x77, 0x61, 0xc9,
-	0xa6, 0x4d, 0xc9, 0x81, 0xb2, 0xb6, 0x13, 0x21, 0x83, 0x89, 0x9b, 0x7a,
-	0x19, 0x9c, 0xb4, 0x76, 0x14, 0xea, 0x68, 0xf9, 0xb9, 0x5a, 0x76, 0x52,
-	0xee, 0x31, 0x6e, 0xff, 0x40, 0x40, 0x5a, 0x7f, 0x97, 0x64, 0x97, 0xe2,
-	0xf6, 0x02, 0x7a, 0x93, 0x20, 0x96, 0xd1, 0x7b, 0x7a, 0xde, 0x8c, 0xec,
-	0x93, 0x81, 0x04, 0x63, 0xa0, 0x8c, 0xf3, 0xf9, 0x85, 0x19, 0xe9, 0x66,
-	0x8c, 0x03, 0x16, 0x7c, 0xa3, 0x8c, 0x78, 0xa1, 0xec, 0x0d, 0x1c, 0x1d,
-	0x53, 0x36, 0xba, 0xf6, 0x62, 0x93, 0xb1, 0x5d, 0x1d, 0x1d, 0x17, 0x5e,
-	0x00, 0xf5, 0x2d, 0x68, 0xfb, 0x56, 0x69, 0xfd, 0x3b, 0xaf, 0xeb, 0xfc,
-	0x41, 0x53, 0x14, 0xdf, 0x5c, 0xf0, 0x62, 0xb6, 0x5e, 0x7d, 0xf9, 0xd7,
-	0x6c, 0xdc, 0xba, 0x1b, 0xb2, 0x3f, 0x2a, 0xfb, 0xde, 0x1a, 0x65, 0xb1,
-	0xf8, 0xea, 0xb2, 0xcd, 0x6b, 0x94, 0x99, 0x78, 0xe1, 0x50, 0x69, 0x27,
-	0xde, 0x4d, 0x68, 0xdf, 0x5d, 0xf4, 0x9e, 0x5b, 0xb7, 0x14, 0x96, 0xea,
-	0x6c, 0xb0, 0x7e, 0x19, 0x63, 0xc7, 0x26, 0x66, 0x9c, 0xd7, 0x31, 0xe3,
-	0x1e, 0x6f, 0x8f, 0xd2, 0x7b, 0x2c, 0xb7, 0x33, 0xfe, 0x78, 0x48, 0xe3,
-	0x85, 0x38, 0xf9, 0x02, 0x63, 0xc3, 0x05, 0xee, 0x0f, 0xa7, 0xd4, 0xe5,
-	0x68, 0xbb, 0x66, 0x9b, 0x98, 0x75, 0xa3, 0x5d, 0xdc, 0x22, 0x83, 0xb0,
-	0x15, 0x86, 0x4a, 0xad, 0xb2, 0x77, 0xea, 0xa3, 0xeb, 0xa8, 0xb7, 0xf6,
-	0x4d, 0x19, 0x7f, 0xf0, 0x10, 0xf8, 0x2a, 0x2b, 0x84, 0x31, 0x1d, 0x88,
-	0xd0, 0x26, 0x5e, 0x6d, 0x0b, 0xbf, 0x76, 0x7f, 0xf7, 0x5f, 0xa6, 0x3f,
-	0x07, 0xb6, 0xc3, 0x1b, 0xed, 0xaf, 0x59, 0x06, 0xa7, 0x22, 0x5c, 0xa9,
-	0x1f, 0xb1, 0x5d, 0xec, 0x32, 0xed, 0xb4, 0x5d, 0x22, 0x4f, 0x2d, 0xc9,
-	0xe2, 0x9d, 0xb0, 0x99, 0x24, 0xcc, 0xf5, 0x49, 0x7b, 0x4c, 0x74, 0x8c,
-	0x27, 0x30, 0xb2, 0xb9, 0x8b, 0x7b, 0x3e, 0xa0, 0x7f, 0x63, 0xab, 0x98,
-	0x78, 0x6a, 0x64, 0xa7, 0xac, 0x45, 0xbb, 0xd7, 0x5b, 0xda, 0xe5, 0xbe,
-	0xee, 0x3e, 0xca, 0x5c, 0xac, 0x89, 0xa1, 0xe3, 0xbd, 0x25, 0x49, 0x45,
-	0x74, 0xbc, 0x20, 0xd9, 0x65, 0x74, 0xbc, 0x20, 0x83, 0x9a, 0x8e, 0x1b,
-	0x97, 0xd1, 0x71, 0xbb, 0xa5, 0xe3, 0x8f, 0xc6, 0x0d, 0x5d, 0x28, 0xad,
-	0xa7, 0x48, 0xa7, 0x86, 0x8e, 0x1d, 0x4d, 0xc7, 0x0b, 0xb8, 0xbb, 0xfe,
-	0xc7, 0x6c, 0x9d, 0x98, 0x2d, 0xe3, 0xef, 0xa8, 0x8c, 0x72, 0x71, 0x2a,
-	0x6e, 0xf4, 0xd2, 0x20, 0xe8, 0x28, 0x2a, 0xff, 0x4d, 0x4b, 0x9f, 0xf5,
-	0x65, 0x26, 0x3e, 0x32, 0x54, 0x3a, 0xb2, 0x82, 0x3e, 0x07, 0x41, 0x9f,
-	0x51, 0x9d, 0xd7, 0xa2, 0xcf, 0x66, 0xbb, 0x9f, 0x91, 0xd4, 0x7b, 0xff,
-	0xd9, 0x84, 0xa1, 0xd5, 0x5b, 0xf4, 0xdc, 0x39, 0xef, 0x0b, 0x6f, 0x80,
-	0x56, 0xcd, 0xda, 0x5c, 0xac, 0xf9, 0xdb, 0x8c, 0x45, 0xa5, 0x4c, 0x6c,
-	0x9b, 0x71, 0xd2, 0xcb, 0xd9, 0x8e, 0x2f, 0xd5, 0xf9, 0x15, 0x1b, 0xa4,
-	0xc0, 0xbc, 0x87, 0xea, 0x46, 0xc6, 0xa2, 0x47, 0xdc, 0x4c, 0x9f, 0x64,
-	0x2b, 0xed, 0xa9, 0x62, 0x89, 0x7e, 0xd1, 0xab, 0x36, 0x37, 0x02, 0xcf,
-	0x95, 0x16, 0x79, 0xb4, 0x44, 0xda, 0x3a, 0x62, 0x70, 0xb1, 0x26, 0xad,
-	0x73, 0xad, 0xd9, 0x4f, 0xbd, 0x0e, 0xe8, 0x83, 0xee, 0xa1, 0xcd, 0xae,
-	0xe5, 0x3e, 0xde, 0xb5, 0xa7, 0x72, 0xa5, 0xa8, 0x5f, 0xee, 0x3f, 0x70,
-	0x4f, 0xb8, 0x3d, 0xd5, 0x51, 0xf1, 0x6d, 0x9c, 0x79, 0x23, 0x9e, 0xfb,
-	0xa4, 0xa3, 0xa2, 0xe4, 0x03, 0x53, 0x2d, 0x72, 0x7b, 0xc9, 0x95, 0x0f,
-	0xa1, 0xfd, 0x07, 0x4b, 0x1e, 0xfc, 0xfb, 0xff, 0x1d, 0xa7, 0x9d, 0x79,
-	0xa8, 0xc4, 0x7d, 0x50, 0x47, 0xdb, 0x2a, 0xcb, 0xf7, 0x86, 0x63, 0xd2,
-	0xd1, 0x55, 0x84, 0xe7, 0x23, 0xee, 0x7e, 0xc0, 0xd1, 0x94, 0xc9, 0xc8,
-	0x77, 0xfa, 0x36, 0xa1, 0x2c, 0xca, 0xf1, 0x18, 0x76, 0x4c, 0xfc, 0xb8,
-	0x5f, 0xde, 0x59, 0xcd, 0xc8, 0x0d, 0x55, 0xb3, 0x77, 0x5b, 0xdb, 0x9b,
-	0x4d, 0x7b, 0xf3, 0xd0, 0x67, 0x59, 0x2f, 0x0c, 0x2f, 0xfa, 0xa0, 0xa2,
-	0xe3, 0xae, 0xc4, 0xbb, 0xd2, 0xc9, 0x79, 0x31, 0xcf, 0x97, 0x2a, 0xff,
-	0x1c, 0x8e, 0x24, 0x5c, 0xf9, 0x8e, 0xcf, 0x39, 0xf6, 0xcb, 0xf5, 0x95,
-	0xfa, 0xb1, 0xb9, 0x3f, 0x1b, 0x5b, 0xc7, 0xfd, 0x90, 0x5c, 0xf5, 0x9f,
-	0xe3, 0x8c, 0xdb, 0xd3, 0x87, 0xe9, 0xf8, 0x31, 0xee, 0x87, 0xbb, 0xb8,
-	0x83, 0x0e, 0x13, 0xb0, 0x21, 0xae, 0x01, 0x8c, 0xd7, 0x30, 0x96, 0xc6,
-	0x18, 0x1a, 0x9f, 0xbf, 0x8c, 0x71, 0xd9, 0xf6, 0x93, 0xd6, 0xfe, 0x3e,
-	0xb2, 0xc4, 0x8b, 0x6b, 0xeb, 0xb1, 0x8d, 0x23, 0xf1, 0x8c, 0x38, 0xf1,
-	0x9f, 0x48, 0xca, 0x3a, 0xbf, 0x7e, 0x7c, 0xee, 0x47, 0xc3, 0xa2, 0xec,
-	0x13, 0x77, 0xdf, 0xee, 0x7e, 0x19, 0xc4, 0xfc, 0x86, 0x56, 0xcd, 0xef,
-	0x1e, 0x61, 0xbc, 0xf6, 0x52, 0x89, 0x73, 0xa8, 0xcd, 0x4b, 0xfd, 0xb6,
-	0x99, 0x57, 0xbc, 0x6b, 0xe5, 0x7c, 0x74, 0x7b, 0x75, 0x0a, 0xb0, 0x7c,
-	0x49, 0xe7, 0x42, 0x84, 0xe1, 0x5b, 0xbb, 0x2e, 0x85, 0xa9, 0x2b, 0xd2,
-	0xdd, 0xf3, 0xb5, 0x7d, 0xa4, 0x91, 0x58, 0x26, 0xab, 0xf5, 0x23, 0x9e,
-	0x53, 0xf9, 0xca, 0x7e, 0xac, 0xa3, 0xb8, 0xf9, 0x5e, 0x57, 0xf3, 0x5d,
-	0xde, 0xdf, 0x6f, 0xf7, 0xca, 0x22, 0x9f, 0x2c, 0x0c, 0x95, 0xbf, 0x52,
-	0x0e, 0x51, 0xff, 0x61, 0xee, 0xf2, 0x98, 0xdd, 0x3f, 0xe8, 0x66, 0x7c,
-	0x0c, 0xb4, 0x18, 0x07, 0xdd, 0xf9, 0xf8, 0xdd, 0x82, 0xfb, 0x1e, 0xd8,
-	0x3f, 0x01, 0xec, 0x23, 0x49, 0x28, 0x23, 0x6b, 0xc0, 0x1b, 0x5d, 0x05,
-	0xa5, 0xc8, 0xeb, 0x5e, 0x6a, 0xbc, 0x92, 0x48, 0x4d, 0x56, 0x9e, 0x60,
-	0x7b, 0xd4, 0x5d, 0x2b, 0x36, 0x68, 0xf2, 0x6c, 0xbe, 0x58, 0xe5, 0x18,
-	0xa4, 0xfb, 0x37, 0x32, 0x86, 0x6b, 0xfb, 0x66, 0x9f, 0x11, 0x5e, 0x5c,
-	0xba, 0xf8, 0xf8, 0xb7, 0xdf, 0xfa, 0x3a, 0x9c, 0xdf, 0x13, 0x16, 0xee,
-	0x95, 0xe3, 0x3e, 0xaf, 0xed, 0xa1, 0xc7, 0xab, 0xb4, 0x41, 0xb9, 0x8f,
-	0x94, 0x7e, 0x64, 0x5a, 0x08, 0x47, 0x18, 0x3e, 0x1b, 0x18, 0x5b, 0xe0,
-	0x8b, 0x55, 0xee, 0x99, 0x84, 0xe1, 0xdf, 0xd2, 0xce, 0x3e, 0x58, 0xc6,
-	0x78, 0x11, 0x0e, 0x76, 0x16, 0x5c, 0xc8, 0xd9, 0x89, 0x3e, 0xe2, 0x57,
-	0xe0, 0xf1, 0x76, 0x79, 0x07, 0x24, 0x9e, 0xfa, 0x78, 0xa5, 0x25, 0x75,
-	0x67, 0xc5, 0x03, 0x9e, 0x39, 0xef, 0x44, 0x6a, 0xcc, 0xce, 0x39, 0x5f,
-	0x21, 0x7e, 0x5f, 0x6b, 0xbf, 0xf3, 0xf9, 0x65, 0xfe, 0x17, 0x61, 0xaa,
-	0xc1, 0x42, 0xd8, 0x52, 0x16, 0x37, 0x61, 0xf8, 0xf7, 0x01, 0xc7, 0xdc,
-	0x0f, 0x1f, 0x46, 0x26, 0x30, 0x6e, 0x61, 0x8b, 0x22, 0x1e, 0xe2, 0xa9,
-	0x3b, 0x30, 0xf6, 0xc7, 0x31, 0xf6, 0xed, 0x15, 0x8e, 0x07, 0xd9, 0x83,
-	0xb9, 0x4f, 0x54, 0x23, 0x78, 0xd7, 0x1a, 0x3b, 0x5a, 0xf3, 0x6e, 0x6b,
-	0x33, 0x46, 0xcf, 0x1a, 0x91, 0x6d, 0x0a, 0xbe, 0x63, 0xae, 0xba, 0xb0,
-	0xd9, 0x95, 0x9f, 0x81, 0x1c, 0x0f, 0xe5, 0x51, 0xc8, 0xc7, 0x05, 0x4d,
-	0x37, 0xb9, 0xed, 0xfc, 0x3f, 0x26, 0x4f, 0xad, 0x63, 0xbc, 0x7a, 0xc0,
-	0xa7, 0x2d, 0xbc, 0x18, 0x2e, 0xf8, 0x94, 0xf7, 0x1b, 0x64, 0xda, 0x2b,
-	0x74, 0x43, 0xf7, 0xa0, 0x6c, 0x23, 0xfd, 0xf7, 0x54, 0x2e, 0x96, 0x4e,
-	0x8d, 0x0b, 0x73, 0xbe, 0x98, 0x13, 0xc1, 0xbc, 0x26, 0xca, 0x06, 0x17,
-	0x32, 0x94, 0x6b, 0x68, 0xc6, 0x1b, 0xaf, 0xd4, 0xea, 0x1e, 0x16, 0xee,
-	0x4d, 0xa6, 0x93, 0x87, 0xb4, 0xbd, 0x23, 0x32, 0x5a, 0x62, 0xdd, 0xdd,
-	0xb0, 0x76, 0xfc, 0xba, 0xfa, 0x3a, 0x57, 0x0d, 0x7c, 0x1e, 0xc5, 0xc5,
-	0xe2, 0xcc, 0x29, 0x79, 0x39, 0xd6, 0x27, 0x2f, 0xd3, 0x8e, 0x1d, 0x00,
-	0x6d, 0x7b, 0xbe, 0xce, 0x2b, 0xd1, 0xe5, 0xb9, 0x40, 0x16, 0x73, 0xfd,
-	0x3d, 0xb4, 0xdb, 0x0b, 0x4a, 0xf3, 0x84, 0x28, 0xb4, 0x8d, 0xe7, 0x2b,
-	0x32, 0x98, 0x2f, 0xd9, 0xd8, 0xd1, 0x30, 0xe7, 0xbc, 0xa1, 0x6e, 0xee,
-	0x1b, 0xc5, 0x05, 0x4c, 0x83, 0xb1, 0x94, 0xd3, 0xe0, 0x7f, 0xaa, 0xc5,
-	0xd8, 0x10, 0xd0, 0x23, 0xad, 0xf7, 0xb7, 0x71, 0x6f, 0x56, 0xc1, 0x27,
-	0x57, 0x6d, 0x1f, 0xbe, 0x56, 0x65, 0xfe, 0x32, 0x09, 0xbd, 0x6a, 0x65,
-	0x65, 0x7c, 0xb0, 0x63, 0x89, 0xbe, 0x39, 0xbe, 0xb4, 0xc5, 0xfc, 0xd4,
-	0xe0, 0x40, 0x45, 0x54, 0x2c, 0xe3, 0xc5, 0x07, 0x2a, 0xcb, 0x69, 0xfe,
-	0x8b, 0xd5, 0xcf, 0x5a, 0xdb, 0xb2, 0x3e, 0x46, 0x5b, 0xff, 0x8e, 0x7c,
-	0xb7, 0x6c, 0xff, 0x23, 0x05, 0xbe, 0xb2, 0xfb, 0xc6, 0x5c, 0x93, 0xec,
-	0x5b, 0x19, 0xd8, 0x9c, 0xd6, 0x3e, 0x1f, 0x73, 0x3b, 0xe2, 0x36, 0xbf,
-	0xce, 0xe0, 0x3a, 0x5b, 0x71, 0x64, 0x02, 0xf2, 0xe1, 0xb0, 0xfc, 0x53,
-	0x98, 0x4d, 0x98, 0xf7, 0x66, 0x7d, 0x59, 0x9f, 0x7b, 0x1b, 0xcd, 0x52,
-	0x3c, 0xed, 0x4a, 0xe1, 0x34, 0xf7, 0xd4, 0xce, 0xdd, 0x51, 0xcb, 0x0f,
-	0xa1, 0x1c, 0xe0, 0xbe, 0xb0, 0x23, 0x45, 0xf8, 0xc8, 0x83, 0xdc, 0xef,
-	0xef, 0xfd, 0x47, 0xe6, 0xea, 0xc4, 0xb9, 0x4e, 0xa6, 0x6d, 0x0b, 0xda,
-	0x36, 0xda, 0xb6, 0xc1, 0xc7, 0xdf, 0x5c, 0xdb, 0x8d, 0x68, 0x1b, 0x8f,
-	0xc6, 0x7d, 0x83, 0x6d, 0x35, 0x3e, 0xaf, 0x1d, 0x28, 0x95, 0x17, 0x5d,
-	0xdf, 0x4f, 0x8e, 0x49, 0xd6, 0x19, 0xed, 0xd3, 0xf3, 0xb9, 0x76, 0xa0,
-	0x02, 0x38, 0x12, 0x61, 0x58, 0x0c, 0x22, 0xbd, 0xce, 0x7f, 0x27, 0xa1,
-	0xde, 0x59, 0xc6, 0x7d, 0x50, 0xfa, 0x27, 0x8c, 0xba, 0x7a, 0xcc, 0xc1,
-	0x93, 0x22, 0xf7, 0x3b, 0x13, 0x9b, 0x70, 0x57, 0x1d, 0xc4, 0x49, 0xde,
-	0x67, 0xfc, 0x78, 0x93, 0x2d, 0x8f, 0xb1, 0x3c, 0xed, 0x42, 0x96, 0x98,
-	0xf2, 0x98, 0x2d, 0x07, 0x4c, 0x41, 0x31, 0x05, 0x6e, 0xb3, 0xe5, 0x7c,
-	0x56, 0xba, 0xdc, 0x3c, 0x1b, 0x1e, 0x1a, 0x11, 0xc6, 0x89, 0x72, 0xd7,
-	0x37, 0xc8, 0x4e, 0xac, 0x0f, 0x7d, 0x50, 0x47, 0x9a, 0x01, 0xc7, 0xc5,
-	0xe0, 0xc7, 0x61, 0xab, 0x87, 0xf2, 0x9d, 0xc0, 0xd0, 0xff, 0x8c, 0x74,
-	0x65, 0x95, 0xc3, 0x5c, 0x83, 0x50, 0x86, 0x82, 0x5d, 0xc9, 0xbd, 0xf8,
-	0x3d, 0xda, 0x9b, 0x92, 0x99, 0x7e, 0xd0, 0x63, 0x2f, 0x79, 0x63, 0x27,
-	0x6c, 0x28, 0xfc, 0xee, 0x6a, 0x91, 0x45, 0xaf, 0xe0, 0xad, 0x83, 0xff,
-	0x37, 0x88, 0x59, 0xcd, 0x96, 0x7c, 0xef, 0x36, 0x08, 0xb9, 0xac, 0xd7,
-	0x85, 0x7b, 0xfd, 0x7c, 0xbf, 0x8e, 0xf9, 0x9e, 0x6b, 0x96, 0x66, 0x96,
-	0xd7, 0xd7, 0x6d, 0x94, 0xfd, 0xde, 0x6e, 0x2f, 0xbe, 0xac, 0xee, 0x25,
-	0xd4, 0x65, 0x99, 0xef, 0x31, 0x17, 0x68, 0xa6, 0x42, 0x3a, 0x33, 0xb0,
-	0x76, 0x74, 0x85, 0xe1, 0xf5, 0x01, 0xc7, 0x0d, 0xc3, 0x1b, 0x82, 0x1e,
-	0xef, 0x19, 0x79, 0x2e, 0x34, 0x36, 0x5a, 0x44, 0x3b, 0xcf, 0x5a, 0x79,
-	0x1d, 0x86, 0x2f, 0x07, 0xdd, 0xf2, 0xb9, 0x6a, 0xfa, 0x1c, 0x7d, 0xf8,
-	0xf3, 0x78, 0x3e, 0x1f, 0x98, 0xfc, 0xa5, 0x3f, 0x43, 0xbb, 0x84, 0xea,
-	0x05, 0x0d, 0xfb, 0xf2, 0x59, 0xed, 0xf3, 0x13, 0x7f, 0x66, 0xcf, 0xa0,
-	0x06, 0x03, 0x26, 0xec, 0xe7, 0x36, 0x7b, 0xcc, 0x69, 0xd4, 0xf4, 0x5b,
-	0xff, 0x4e, 0xe1, 0x1d, 0xcb, 0xc2, 0xf0, 0x8a, 0xbe, 0x96, 0xf5, 0xd0,
-	0xd7, 0x93, 0xdc, 0x0b, 0x7c, 0x9f, 0xe6, 0x3f, 0x91, 0x03, 0xdc, 0xf7,
-	0x02, 0x0e, 0x95, 0xf2, 0x8f, 0x75, 0xa8, 0x74, 0x41, 0xe4, 0x2d, 0x58,
-	0x7f, 0xae, 0x31, 0x18, 0xa4, 0x15, 0xb0, 0xef, 0xfa, 0xa5, 0x66, 0x13,
-	0x9b, 0xa2, 0x6f, 0x9e, 0xdd, 0x0c, 0xdf, 0x59, 0xdb, 0x33, 0xdc, 0x57,
-	0x1f, 0x6b, 0x0d, 0xc3, 0xf7, 0x06, 0xd1, 0x9a, 0xd9, 0xd8, 0x37, 0x74,
-	0x7c, 0xbe, 0x57, 0xd6, 0x1b, 0xbb, 0x90, 0xb9, 0x8d, 0x29, 0xbd, 0x4f,
-	0xa0, 0xda, 0xa0, 0x43, 0x76, 0xfd, 0x00, 0x38, 0xe5, 0x18, 0xcc, 0x73,
-	0x8c, 0x60, 0xaa, 0xb5, 0xcf, 0xf7, 0xae, 0xb3, 0x36, 0xac, 0x0b, 0x5c,
-	0xfa, 0x5e, 0x87, 0xfa, 0x5e, 0x68, 0x74, 0x6b, 0x44, 0xc3, 0xff, 0x10,
-	0x3e, 0x98, 0x30, 0xcf, 0xb9, 0x5d, 0xec, 0x63, 0xa7, 0x8c, 0xef, 0xc2,
-	0xb3, 0x7b, 0x1d, 0xee, 0x03, 0x57, 0xc6, 0xe4, 0xaa, 0xe4, 0x80, 0xda,
-	0xe5, 0x3d, 0x28, 0x3d, 0x56, 0xc6, 0x7d, 0x09, 0xfa, 0xbe, 0x00, 0xff,
-	0xbe, 0x49, 0x1e, 0x04, 0x4d, 0xab, 0xbe, 0x74, 0x6a, 0x5e, 0xa5, 0xbb,
-	0xa7, 0x55, 0x3a, 0x18, 0x51, 0x13, 0x9c, 0x57, 0x3f, 0x71, 0x31, 0x4d,
-	0xfc, 0x96, 0x81, 0xff, 0x32, 0x70, 0x7c, 0xd9, 0x3d, 0xe3, 0xc0, 0xea,
-	0x16, 0xa3, 0xdf, 0x0a, 0x9a, 0x36, 0x8d, 0x9d, 0xff, 0xa7, 0x41, 0xb4,
-	0x86, 0x3d, 0x5e, 0x03, 0x73, 0x71, 0xd6, 0x5c, 0xa3, 0x3c, 0xd7, 0x08,
-	0x8a, 0xa1, 0x00, 0xba, 0x4f, 0xa7, 0xc6, 0xd4, 0x62, 0xb8, 0x79, 0x4f,
-	0x67, 0xf7, 0x63, 0xba, 0x9f, 0x74, 0x90, 0x55, 0x4f, 0x02, 0x9e, 0x9d,
-	0xd2, 0xb4, 0x87, 0x78, 0x26, 0xac, 0x71, 0xc6, 0xa7, 0xbc, 0x3b, 0x50,
-	0x77, 0x44, 0xe9, 0x3d, 0x6d, 0x5b, 0x87, 0x30, 0xbf, 0x1b, 0xf8, 0xa5,
-	0x1e, 0x62, 0xcc, 0xed, 0xb5, 0x74, 0x21, 0x64, 0xd2, 0x49, 0xca, 0xc0,
-	0x98, 0x89, 0x25, 0x57, 0xef, 0xe4, 0xfa, 0xd3, 0x13, 0x88, 0xbb, 0x90,
-	0x51, 0x13, 0xe0, 0xe2, 0xa3, 0x27, 0xc5, 0x6d, 0xf0, 0xbb, 0xd7, 0x1b,
-	0x3f, 0x8c, 0x3e, 0x19, 0xc7, 0x6e, 0x90, 0xe2, 0xaa, 0xf8, 0xcd, 0x24,
-	0xe0, 0x6f, 0x96, 0xf1, 0x93, 0x5c, 0x0b, 0x17, 0x32, 0x87, 0x63, 0x8b,
-	0x9b, 0xeb, 0x0d, 0xc3, 0x51, 0x96, 0x9f, 0x26, 0xff, 0x4a, 0x9a, 0xef,
-	0x0a, 0xa7, 0xe7, 0x37, 0xab, 0x65, 0xb2, 0xb6, 0xc5, 0xc2, 0xa1, 0xf1,
-	0x24, 0x93, 0x5a, 0x8e, 0x50, 0xdf, 0xcc, 0xd4, 0xc1, 0x13, 0x7c, 0x7c,
-	0xc2, 0x6f, 0x7c, 0x13, 0xf0, 0xfc, 0x0f, 0xc0, 0xd3, 0x62, 0xe1, 0x69,
-	0x5c, 0x01, 0x4f, 0x4b, 0x04, 0x0f, 0xe4, 0x1c, 0xe5, 0x6a, 0xfc, 0xda,
-	0x6c, 0x45, 0x9c, 0xa2, 0x2f, 0xed, 0x4a, 0xfb, 0x43, 0xd4, 0x37, 0x8d,
-	0xde, 0x68, 0x9f, 0x27, 0xa3, 0x5a, 0xd7, 0xb8, 0xd7, 0x76, 0x56, 0xe6,
-	0x61, 0xbd, 0x8a, 0x93, 0xf3, 0x09, 0xfb, 0x5a, 0x76, 0xd5, 0x3d, 0x90,
-	0xff, 0x0b, 0x69, 0xd7, 0xda, 0x12, 0x93, 0x01, 0xfd, 0xa0, 0x84, 0xce,
-	0x15, 0xa8, 0xc1, 0xf4, 0x12, 0x60, 0x82, 0x3c, 0x3e, 0xd9, 0xe3, 0x0d,
-	0xcb, 0x56, 0xed, 0xeb, 0x59, 0x5c, 0x63, 0x6e, 0xf1, 0xba, 0xb9, 0x41,
-	0xff, 0xa9, 0x68, 0x6e, 0x90, 0x89, 0xa8, 0x37, 0x29, 0x7f, 0x64, 0x71,
-	0xb1, 0x11, 0x73, 0x8a, 0xd7, 0xcd, 0xa7, 0x33, 0x79, 0x3b, 0xcb, 0xcc,
-	0x7c, 0xba, 0x8a, 0x7e, 0xdc, 0xe2, 0x77, 0x2d, 0x9f, 0xc4, 0xd8, 0x3d,
-	0xd3, 0x12, 0xca, 0x44, 0x80, 0x35, 0xea, 0xa6, 0x7f, 0x12, 0xb7, 0xb9,
-	0xd7, 0x0a, 0xcf, 0x1b, 0x2c, 0x7f, 0x79, 0x52, 0xd4, 0xfe, 0xe0, 0xdf,
-	0x59, 0x3e, 0x75, 0x6d, 0x9e, 0x1c, 0x7f, 0x1f, 0x5c, 0x6f, 0xf3, 0x05,
-	0x0a, 0x59, 0x79, 0x65, 0x3d, 0xed, 0x92, 0x06, 0xff, 0x57, 0x56, 0x94,
-	0xc5, 0x51, 0x76, 0x6a, 0xbd, 0x95, 0x0b, 0x28, 0xbb, 0x07, 0x7e, 0x1f,
-	0xf3, 0x3e, 0xf8, 0x8e, 0x32, 0xb8, 0x1e, 0x27, 0x3d, 0x60, 0x45, 0xf2,
-	0x3c, 0xe5, 0x22, 0x6d, 0x4a, 0xcc, 0x51, 0x6d, 0x8f, 0xe2, 0xf2, 0xf8,
-	0xbd, 0x96, 0xed, 0x4f, 0x7c, 0x13, 0xd7, 0xf2, 0x8d, 0x09, 0xf0, 0xfd,
-	0xe1, 0xc0, 0x71, 0x67, 0x98, 0x57, 0xa0, 0x69, 0xb8, 0xbe, 0xef, 0x1b,
-	0x18, 0x26, 0xb4, 0xb4, 0x4c, 0x7a, 0x21, 0x4f, 0x3b, 0xd2, 0x44, 0x5d,
-	0x7c, 0xd2, 0xd3, 0x39, 0xee, 0x39, 0xad, 0x97, 0xeb, 0xd7, 0xb1, 0x09,
-	0xba, 0x26, 0x61, 0x78, 0xd4, 0x33, 0xfb, 0xe7, 0xb5, 0xfe, 0x46, 0xd0,
-	0x1f, 0xed, 0x34, 0xf8, 0xfd, 0x3e, 0xa3, 0x43, 0x94, 0x5f, 0x8e, 0xab,
-	0xae, 0xd6, 0x7e, 0x6b, 0x5c, 0xe7, 0x37, 0x2d, 0xd5, 0x1d, 0xb3, 0x63,
-	0x93, 0x6e, 0xcd, 0x7e, 0x42, 0x6d, 0x7c, 0x71, 0xd4, 0x2e, 0x01, 0x95,
-	0x35, 0xca, 0x44, 0x1f, 0x69, 0x94, 0x73, 0xd7, 0x36, 0xd4, 0xb5, 0xb4,
-	0x23, 0x0c, 0x7d, 0xd2, 0x76, 0x72, 0xaf, 0xcd, 0x97, 0x1a, 0x8d, 0xcf,
-	0x92, 0x90, 0x2d, 0x0d, 0x3a, 0x2f, 0x01, 0x65, 0x95, 0x48, 0x97, 0xb9,
-	0x32, 0xd3, 0xfb, 0x7f, 0xc2, 0xec, 0x41, 0xd6, 0x5d, 0x33, 0x0f, 0x20,
-	0x39, 0x2d, 0x1a, 0x4f, 0x5f, 0xab, 0xe1, 0xc9, 0xce, 0x2d, 0xb1, 0x72,
-	0x6e, 0x70, 0x6a, 0xfd, 0x7b, 0x20, 0x3b, 0xb9, 0x4e, 0x26, 0xe7, 0xfc,
-	0x9c, 0x38, 0x6e, 0xae, 0x7b, 0xad, 0xb9, 0x4d, 0x46, 0x78, 0xe5, 0xdc,
-	0x40, 0xab, 0xd1, 0xbc, 0x48, 0xdb, 0x09, 0xbd, 0xef, 0xa4, 0x14, 0x61,
-	0xd9, 0xb8, 0x02, 0xb7, 0x11, 0xdd, 0x19, 0x9a, 0xfb, 0xa2, 0xa6, 0xb9,
-	0x16, 0x4b, 0x73, 0xa8, 0xeb, 0x71, 0x1f, 0xfd, 0xbe, 0x96, 0x1a, 0xcd,
-	0x6d, 0xb0, 0x34, 0xa7, 0x5a, 0xcc, 0x1e, 0x7b, 0xb9, 0xc5, 0xec, 0x71,
-	0x25, 0x57, 0x3c, 0xbf, 0x93, 0xcf, 0xf0, 0xc5, 0xa2, 0xe7, 0x7a, 0x58,
-	0xcf, 0x03, 0xd6, 0x7a, 0x59, 0xd3, 0x64, 0xe3, 0x78, 0xdc, 0x8f, 0xa7,
-	0xdf, 0xe7, 0xca, 0xa3, 0xb0, 0x83, 0x8a, 0x95, 0x1f, 0x84, 0xf3, 0xf0,
-	0xfd, 0x26, 0x96, 0x74, 0xef, 0x4c, 0x0b, 0xf9, 0x6d, 0x1a, 0xbf, 0x8e,
-	0xd4, 0xf9, 0x3c, 0x98, 0x2f, 0xca, 0xfe, 0x19, 0xeb, 0x01, 0xb9, 0xbc,
-	0x54, 0x97, 0x31, 0x10, 0xe3, 0xe3, 0x9c, 0xab, 0xb6, 0xdb, 0xfd, 0x49,
-	0xca, 0xf9, 0xbb, 0xe1, 0x13, 0xdd, 0x03, 0x3d, 0x49, 0xfa, 0xee, 0xd8,
-	0x60, 0xf2, 0x89, 0x13, 0xd0, 0x63, 0x3f, 0x6f, 0x73, 0xab, 0x6e, 0xbf,
-	0x7d, 0xed, 0x5c, 0x62, 0xd0, 0xbe, 0x43, 0x9a, 0x79, 0xdb, 0x06, 0x13,
-	0x83, 0xde, 0xba, 0x81, 0x7c, 0xa6, 0x76, 0xed, 0xda, 0xa8, 0xf9, 0xc2,
-	0x89, 0x9e, 0xab, 0x2b, 0x9e, 0xa3, 0x76, 0x7f, 0xb3, 0x71, 0x79, 0xbb,
-	0xa8, 0xfc, 0xce, 0x4d, 0xcb, 0xcb, 0xff, 0xa3, 0xb7, 0xbc, 0x7d, 0xe3,
-	0xe6, 0xe5, 0xcf, 0x7b, 0x57, 0x3c, 0x7f, 0x64, 0xc5, 0xf3, 0xef, 0xad,
-	0x78, 0xde, 0xd1, 0xba, 0xfc, 0xf9, 0x43, 0x2b, 0x9e, 0x4f, 0xb5, 0xae,
-	0x0d, 0xef, 0x42, 0xeb, 0x72, 0xb8, 0xee, 0xd6, 0xfb, 0x07, 0xd3, 0x55,
-	0x57, 0xf6, 0x96, 0xf0, 0xde, 0x79, 0xdf, 0x16, 0xa3, 0xd7, 0xea, 0xdf,
-	0x33, 0x5e, 0xb7, 0x7b, 0xcb, 0xf2, 0xfe, 0x6a, 0xed, 0xf6, 0xd5, 0xda,
-	0x05, 0xb5, 0x76, 0x46, 0xb6, 0xcd, 0x54, 0xf9, 0x8e, 0xe5, 0x51, 0xbf,
-	0xa6, 0xed, 0x44, 0xd9, 0xd7, 0x39, 0xb7, 0xc3, 0x3a, 0xe7, 0x36, 0x05,
-	0x3e, 0xbc, 0x5b, 0xc7, 0xa8, 0x36, 0xc3, 0x50, 0x1e, 0xaf, 0x6e, 0xd4,
-	0x71, 0x2a, 0xd1, 0x79, 0xb7, 0xc3, 0xb0, 0x6d, 0x99, 0x6b, 0x1b, 0xca,
-	0xfe, 0xc0, 0xdc, 0x4d, 0xee, 0xed, 0xb1, 0x70, 0xc0, 0x0b, 0xc3, 0x71,
-	0xff, 0x76, 0x9b, 0x7f, 0x86, 0x7b, 0xd5, 0xb4, 0xa1, 0x0e, 0x7e, 0x0c,
-	0x3a, 0xb8, 0xa6, 0x7b, 0xef, 0xc6, 0x58, 0xf3, 0xa0, 0x99, 0x3e, 0xf9,
-	0x9d, 0x6a, 0xfa, 0xf3, 0xa2, 0xcf, 0x16, 0xf5, 0xc2, 0x86, 0x9b, 0xbf,
-	0xf3, 0xbd, 0x7e, 0x00, 0x5b, 0x2f, 0x94, 0x87, 0x83, 0x7e, 0xd0, 0x50,
-	0x37, 0xec, 0x3d, 0x5f, 0xfb, 0xa5, 0x8f, 0x6b, 0xda, 0x22, 0x8d, 0x31,
-	0xdf, 0x86, 0x76, 0x81, 0x13, 0xcf, 0xf5, 0xfe, 0xb1, 0x89, 0xd3, 0x04,
-	0x9d, 0xde, 0x97, 0xc0, 0xb7, 0x43, 0xfe, 0x0e, 0xf8, 0x28, 0xa4, 0x21,
-	0xc6, 0xd3, 0xb6, 0xdb, 0x7c, 0xc7, 0x36, 0x99, 0x76, 0x19, 0x77, 0x4c,
-	0xf7, 0x8f, 0x08, 0xe7, 0x9d, 0x4e, 0xa6, 0x94, 0xb6, 0xab, 0xc2, 0x03,
-	0x01, 0x73, 0x79, 0xb9, 0x67, 0x43, 0x7e, 0x1e, 0xbe, 0x6b, 0xc2, 0x2f,
-	0x78, 0x31, 0x9b, 0xff, 0x9b, 0x2b, 0x19, 0xda, 0x1c, 0x23, 0x6d, 0xc2,
-	0x9f, 0x5a, 0xe8, 0xfd, 0xbb, 0x90, 0xf6, 0x7d, 0x4a, 0x91, 0xf6, 0xbf,
-	0x17, 0xce, 0xba, 0xec, 0x8b, 0x70, 0x0f, 0xdf, 0x95, 0xd3, 0xb8, 0xba,
-	0x5b, 0x0e, 0x97, 0x69, 0x0b, 0xc7, 0x75, 0x7e, 0xc8, 0x68, 0x40, 0x3b,
-	0x2d, 0x0e, 0x3c, 0x8e, 0x01, 0x7f, 0x2d, 0xb0, 0xb9, 0x6f, 0x44, 0x9d,
-	0x98, 0x8c, 0x0c, 0xb7, 0x80, 0xf7, 0xc8, 0x9f, 0xbc, 0xbb, 0xa8, 0xef,
-	0xc9, 0x5c, 0x69, 0x44, 0xe7, 0xef, 0x3d, 0x8e, 0xb6, 0x4f, 0xe0, 0x9a,
-	0x29, 0x7d, 0x18, 0x6d, 0xde, 0xaf, 0xeb, 0xcf, 0x4c, 0x32, 0x17, 0x5a,
-	0x20, 0x97, 0x3e, 0x21, 0xc5, 0xd9, 0x0e, 0x19, 0x49, 0xcc, 0x4f, 0xbb,
-	0x4b, 0x71, 0x99, 0x47, 0x37, 0x70, 0xcf, 0xa4, 0x78, 0x35, 0xf7, 0x97,
-	0xc5, 0x1d, 0xde, 0xad, 0xba, 0x5b, 0xb5, 0xcf, 0xd5, 0x2f, 0x43, 0xd5,
-	0x8c, 0xdc, 0x54, 0x7d, 0x62, 0x8b, 0x89, 0x45, 0x2d, 0x8b, 0x6f, 0x1d,
-	0xd3, 0x52, 0xe5, 0x84, 0xcb, 0xf3, 0x59, 0x32, 0x73, 0x56, 0x24, 0x76,
-	0x22, 0x8a, 0x4d, 0xb2, 0xcc, 0x93, 0x8e, 0xab, 0x01, 0xd7, 0x59, 0xc8,
-	0xd6, 0x44, 0x5c, 0x3e, 0xbb, 0x2b, 0x1a, 0xab, 0x10, 0x4e, 0xed, 0x2a,
-	0xc8, 0x9d, 0xb8, 0xf2, 0x57, 0xa7, 0x27, 0x73, 0x8a, 0xe3, 0xfe, 0x75,
-	0x48, 0x59, 0xa6, 0x32, 0xbe, 0x14, 0x5a, 0xa3, 0xb1, 0xe1, 0xdf, 0xec,
-	0x89, 0xc6, 0xa7, 0xcd, 0x6d, 0xce, 0x56, 0x14, 0xb9, 0x8f, 0x03, 0xfa,
-	0x8b, 0x65, 0x3e, 0xb7, 0x81, 0xbe, 0xc3, 0x80, 0xb0, 0x1d, 0x64, 0xba,
-	0x62, 0xdf, 0x84, 0x93, 0xf0, 0xd7, 0xc3, 0xb9, 0x90, 0x4a, 0x00, 0x47,
-	0x85, 0xd7, 0x85, 0xb7, 0xc7, 0xf3, 0xd5, 0x5a, 0xf0, 0xde, 0x6c, 0x63,
-	0x89, 0x8c, 0x0f, 0xae, 0x03, 0xde, 0x5a, 0x50, 0x9e, 0x97, 0x89, 0x93,
-	0xb7, 0x6e, 0xe1, 0xde, 0x78, 0x83, 0xef, 0xd8, 0x1c, 0x56, 0x9e, 0x39,
-	0x9a, 0x40, 0x1d, 0xbe, 0x1f, 0x41, 0x9b, 0x74, 0x21, 0x17, 0xdb, 0x02,
-	0x9f, 0x88, 0xe3, 0x86, 0xb1, 0x8e, 0x3d, 0xcd, 0x3a, 0x27, 0x55, 0xce,
-	0x52, 0x9f, 0x47, 0x6d, 0x27, 0x74, 0xce, 0x07, 0xfc, 0xf6, 0xc2, 0x60,
-	0x8c, 0xf2, 0xab, 0x5b, 0x06, 0xa8, 0x4f, 0xce, 0x8e, 0x68, 0xda, 0xef,
-	0xdc, 0xc5, 0xf3, 0x57, 0x3d, 0xc6, 0x46, 0x4f, 0x10, 0xc6, 0x9b, 0x51,
-	0x0e, 0xfb, 0xfd, 0x35, 0x61, 0x28, 0xbc, 0x49, 0x18, 0x0a, 0x6f, 0x12,
-	0x06, 0xe2, 0x02, 0x70, 0x54, 0xaf, 0xd8, 0x18, 0xc5, 0xbe, 0xb7, 0x62,
-	0x1e, 0x47, 0xca, 0x05, 0x39, 0x5a, 0x76, 0x74, 0xdc, 0x71, 0x5e, 0x51,
-	0x26, 0x78, 0xe0, 0x49, 0xf0, 0x5e, 0x19, 0xbc, 0x59, 0x06, 0x2f, 0x96,
-	0xc1, 0x97, 0xb0, 0xff, 0xcf, 0x43, 0x3e, 0x3c, 0x81, 0xb5, 0x79, 0x7c,
-	0x19, 0x2f, 0x67, 0x35, 0x2f, 0x17, 0xcb, 0xf4, 0xd5, 0x7a, 0x2f, 0xc3,
-	0xaf, 0xae, 0x0c, 0x94, 0xd2, 0x50, 0x25, 0x8e, 0x9b, 0xef, 0xfd, 0x28,
-	0xf9, 0x55, 0x1e, 0x0c, 0x0e, 0xa2, 0xcd, 0x24, 0x68, 0x3c, 0x4d, 0x3b,
-	0x90, 0xf6, 0x4f, 0x01, 0xbc, 0x79, 0x8c, 0xbe, 0x9a, 0xba, 0x7a, 0xb3,
-	0x50, 0xbf, 0xb8, 0x7b, 0x98, 0xcb, 0xc8, 0xb9, 0xa6, 0x56, 0xe0, 0xc9,
-	0xf0, 0xef, 0x98, 0x4f, 0x3d, 0x43, 0xbe, 0x7d, 0x96, 0x7c, 0x5b, 0xc7,
-	0xab, 0x3f, 0xc5, 0xf9, 0x85, 0xde, 0xae, 0xb5, 0xda, 0xd6, 0xea, 0x6f,
-	0x5e, 0xaa, 0xaf, 0xc7, 0x9f, 0x24, 0x3f, 0xaa, 0xcc, 0x24, 0x71, 0x9f,
-	0xca, 0xc5, 0x76, 0x58, 0xdc, 0xc3, 0x76, 0xdb, 0x73, 0x05, 0x70, 0xdf,
-	0x2e, 0x85, 0xb9, 0x50, 0xfc, 0x3d, 0x51, 0x9f, 0xb5, 0x7e, 0x3c, 0xdb,
-	0xcf, 0x68, 0xc9, 0x91, 0xc1, 0x5d, 0xdc, 0xd7, 0x70, 0xa0, 0xe7, 0xa3,
-	0xf5, 0x80, 0xbd, 0xaf, 0xd7, 0x9c, 0x32, 0x96, 0xb2, 0xb5, 0xc5, 0xc6,
-	0x9f, 0xd8, 0xdf, 0xe4, 0x8a, 0x75, 0x7a, 0x31, 0xe4, 0xb9, 0xb6, 0x09,
-	0xff, 0x60, 0x1d, 0xad, 0x3c, 0x60, 0x69, 0x45, 0xad, 0x98, 0xc7, 0x5d,
-	0x96, 0x56, 0x22, 0x78, 0x13, 0x11, 0xad, 0x34, 0x45, 0xb4, 0x52, 0x98,
-	0x8e, 0x68, 0x85, 0x6d, 0xef, 0x8a, 0x68, 0x25, 0x55, 0x4f, 0x2b, 0x85,
-	0x69, 0x07, 0xd7, 0x4a, 0x38, 0x48, 0x2f, 0xec, 0x87, 0xf4, 0x02, 0x58,
-	0xaa, 0x9f, 0x59, 0xa2, 0x97, 0x04, 0xfa, 0x39, 0x5a, 0x36, 0x39, 0x22,
-	0xf0, 0xbb, 0xac, 0x0e, 0xf1, 0xb0, 0xe6, 0xc6, 0x47, 0x5c, 0x9b, 0x46,
-	0x02, 0x4b, 0x23, 0xb5, 0x7c, 0xfa, 0x15, 0xb4, 0x01, 0xdc, 0x33, 0x37,
-	0x76, 0xb7, 0xa6, 0x8d, 0xfb, 0x83, 0x12, 0xea, 0x0e, 0x83, 0x36, 0x22,
-	0x1c, 0xbc, 0xc7, 0xe2, 0x60, 0xe5, 0x5a, 0xde, 0x66, 0x71, 0x30, 0x6c,
-	0x71, 0xa0, 0xf9, 0xa5, 0xc0, 0x35, 0x53, 0x1a, 0x07, 0x4d, 0x1a, 0x07,
-	0xa2, 0xa2, 0xb6, 0xb7, 0xad, 0x81, 0x03, 0xd6, 0x19, 0xd6, 0xf3, 0x8f,
-	0x61, 0xfe, 0xb7, 0x63, 0xfe, 0x4a, 0xcf, 0x9f, 0xeb, 0x60, 0x72, 0xb9,
-	0x8b, 0xd5, 0xbf, 0x5e, 0x9a, 0x7f, 0x2b, 0xfa, 0x38, 0x52, 0x8e, 0xe9,
-	0xf9, 0xc3, 0xb6, 0xef, 0x8f, 0xe6, 0xff, 0x78, 0xd5, 0xe4, 0x53, 0x3f,
-	0xbe, 0x4a, 0xcf, 0x95, 0x2c, 0x6f, 0xf8, 0xda, 0x2f, 0x66, 0x4c, 0xfb,
-	0x3c, 0x74, 0xdb, 0x54, 0x90, 0xb2, 0xe7, 0xae, 0x8c, 0xbd, 0xf4, 0x95,
-	0x80, 0xbc, 0xf3, 0x21, 0x9d, 0xd7, 0x72, 0x8e, 0x76, 0x53, 0xb9, 0x55,
-	0x06, 0xa7, 0xea, 0xe1, 0x26, 0xbc, 0x05, 0x2d, 0x47, 0xf3, 0x98, 0xdf,
-	0x68, 0xd0, 0x0d, 0xf9, 0xa6, 0x69, 0x09, 0xe5, 0xe9, 0xc2, 0x40, 0xac,
-	0x49, 0xd4, 0x03, 0xef, 0xc7, 0x9c, 0x5d, 0xd9, 0xe2, 0x77, 0x7a, 0x7b,
-	0x14, 0x75, 0xe1, 0x95, 0x75, 0xba, 0xb0, 0xcd, 0xea, 0xc2, 0xcd, 0xd4,
-	0x85, 0x80, 0xfb, 0x6e, 0x39, 0x56, 0xe6, 0xfa, 0x15, 0x52, 0x4d, 0xd0,
-	0xff, 0xdf, 0xf1, 0x79, 0xc6, 0x45, 0xc7, 0xcd, 0x92, 0xc7, 0x34, 0x2d,
-	0x53, 0xa7, 0xa5, 0xf5, 0x99, 0x90, 0x05, 0xda, 0xd8, 0x09, 0xc6, 0x42,
-	0xa9, 0xf7, 0xfe, 0x3e, 0xfc, 0xcc, 0x1a, 0x7a, 0x6f, 0xbc, 0x6c, 0xec,
-	0xb7, 0x06, 0xd8, 0x84, 0x72, 0xaa, 0x0d, 0xd7, 0x26, 0x9e, 0x89, 0xe8,
-	0xee, 0x52, 0xcd, 0xd2, 0x70, 0x6a, 0xa3, 0x8c, 0x4d, 0x19, 0x1b, 0x57,
-	0x9d, 0x02, 0xfe, 0x4f, 0x31, 0x7f, 0x56, 0x74, 0xbe, 0x7f, 0x7e, 0x12,
-	0x76, 0xee, 0xcc, 0xdd, 0xe6, 0x1c, 0xc8, 0x54, 0x83, 0xfe, 0x4d, 0x1b,
-	0xa4, 0x18, 0x64, 0xa1, 0xef, 0xe2, 0x32, 0x86, 0x3e, 0x3b, 0x77, 0x35,
-	0x62, 0xce, 0x09, 0xb4, 0xa5, 0xcf, 0xc7, 0x38, 0x5a, 0xa3, 0xb8, 0x33,
-	0x49, 0x9d, 0xab, 0xcf, 0xf3, 0xae, 0xb9, 0xfe, 0x56, 0xbc, 0x63, 0x7e,
-	0x84, 0x87, 0xb1, 0x22, 0xd9, 0x8f, 0x7e, 0x4f, 0x88, 0xdd, 0xef, 0xc9,
-	0x68, 0xfd, 0x17, 0x3b, 0xe1, 0xd9, 0xb3, 0x7a, 0xfd, 0x58, 0xf7, 0xb5,
-	0xf4, 0xa2, 0x31, 0x72, 0x73, 0x58, 0x3f, 0x75, 0xd6, 0xc5, 0xbd, 0x1d,
-	0xf7, 0xa8, 0xbf, 0x48, 0x8f, 0x40, 0x37, 0xbe, 0xfd, 0xd0, 0x26, 0x69,
-	0x06, 0xbe, 0x67, 0x14, 0x70, 0x6d, 0x72, 0xbc, 0x0a, 0x9a, 0x17, 0x6a,
-	0xf4, 0xf0, 0xc4, 0xeb, 0xf2, 0x03, 0x69, 0x82, 0xb4, 0x40, 0xb9, 0x48,
-	0xda, 0xa0, 0x4c, 0x24, 0x6d, 0x1b, 0x7a, 0x78, 0x2c, 0xf0, 0x63, 0xcc,
-	0x03, 0x30, 0x71, 0x79, 0xd2, 0x06, 0x69, 0x3e, 0xa5, 0xe3, 0xf5, 0x59,
-	0xf9, 0x96, 0x64, 0x5b, 0x3b, 0x61, 0x97, 0xfd, 0xdb, 0xae, 0xb1, 0x39,
-	0x2b, 0xac, 0x69, 0x0e, 0xba, 0x89, 0x39, 0x79, 0xdd, 0xf2, 0x9e, 0x6a,
-	0x01, 0x78, 0xb8, 0x17, 0x4a, 0xf9, 0x6e, 0x9d, 0xe7, 0xb8, 0xaf, 0xb4,
-	0x49, 0x6e, 0x09, 0xe2, 0x36, 0xee, 0x7e, 0x04, 0x74, 0xb0, 0xe0, 0xc8,
-	0xa9, 0x0b, 0xb8, 0x2e, 0x3a, 0x5c, 0xbf, 0x4b, 0x41, 0x36, 0xad, 0xc8,
-	0xec, 0xbe, 0x9b, 0x5c, 0x90, 0x1e, 0x6f, 0x4c, 0x18, 0xeb, 0x98, 0x77,
-	0x9a, 0x4e, 0xfd, 0xfe, 0x26, 0xe3, 0x4b, 0x03, 0x16, 0xbf, 0xd1, 0x1b,
-	0xa4, 0x2d, 0x17, 0x84, 0x61, 0x9e, 0x76, 0x83, 0x28, 0xed, 0x23, 0xc1,
-	0xe7, 0x43, 0x19, 0xe3, 0x13, 0x3b, 0x9d, 0xc6, 0xb3, 0x2f, 0x58, 0x5a,
-	0x91, 0x98, 0xca, 0x3c, 0xed, 0x34, 0x9c, 0x7a, 0x84, 0x6b, 0xa6, 0xf3,
-	0xae, 0x0d, 0x5d, 0x3d, 0xeb, 0xd4, 0xe8, 0xea, 0x2b, 0xf6, 0xb7, 0xca,
-	0x34, 0x49, 0x36, 0xdd, 0x84, 0xf9, 0x0e, 0x94, 0x22, 0x18, 0xbf, 0x0d,
-	0xb8, 0x08, 0x0f, 0xe8, 0x76, 0xe6, 0x7f, 0xe2, 0x5a, 0x04, 0x2c, 0xf7,
-	0x01, 0xee, 0x4b, 0x80, 0xf9, 0x45, 0x5c, 0x6a, 0x5b, 0x4c, 0xfe, 0xd4,
-	0x89, 0xcd, 0xd4, 0xc3, 0x4b, 0x18, 0xbf, 0x6b, 0xe1, 0x7d, 0x2d, 0x58,
-	0x3d, 0x59, 0xe8, 0xeb, 0x00, 0x3c, 0x84, 0xf3, 0x25, 0xc0, 0x48, 0xbb,
-	0xf5, 0x39, 0x3c, 0x7b, 0x80, 0xef, 0x79, 0x0b, 0x13, 0xe8, 0x71, 0xea,
-	0x2f, 0x6a, 0xbf, 0x4b, 0xb4, 0xa3, 0xff, 0xd2, 0x3e, 0xb7, 0xaf, 0x90,
-	0x01, 0x5d, 0x0e, 0xf1, 0x3c, 0x51, 0x5e, 0xa4, 0x1d, 0x00, 0xbe, 0xff,
-	0xae, 0xc4, 0xce, 0x26, 0xe5, 0x68, 0x89, 0x7b, 0x40, 0xa7, 0x81, 0x0f,
-	0x7d, 0xc6, 0x05, 0x75, 0xae, 0xc2, 0x05, 0x65, 0x3f, 0xb3, 0x1b, 0x57,
-	0x37, 0xae, 0xb7, 0xe2, 0x02, 0x39, 0xcc, 0x9c, 0xc2, 0xd5, 0x83, 0xbe,
-	0x55, 0xa2, 0x49, 0x98, 0x9b, 0xf5, 0x0d, 0xb4, 0xd1, 0xb6, 0x65, 0x41,
-	0x65, 0xfa, 0x80, 0xbf, 0x3e, 0xc0, 0x96, 0xc4, 0xc5, 0x7c, 0xe6, 0xef,
-	0x3a, 0x72, 0xf6, 0x65, 0x5c, 0x60, 0xb0, 0xb3, 0x20, 0xcc, 0xb3, 0xfd,
-	0xb8, 0xa0, 0xc4, 0xce, 0x66, 0x71, 0x0d, 0xe2, 0xfa, 0x2b, 0xc7, 0xf0,
-	0x5c, 0x3b, 0xf0, 0x15, 0xf1, 0x08, 0x70, 0xbe, 0x8c, 0xe7, 0xbe, 0xec,
-	0xbc, 0x71, 0x9e, 0xfb, 0xbe, 0x63, 0x78, 0xee, 0x15, 0xa7, 0xc6, 0x73,
-	0x17, 0x1c, 0xf5, 0xf0, 0xd3, 0x4e, 0xec, 0x61, 0xfa, 0x12, 0x17, 0x1c,
-	0xc3, 0xff, 0x31, 0x19, 0x38, 0x08, 0x5a, 0x7a, 0x78, 0x1e, 0x17, 0xe9,
-	0xea, 0x19, 0x94, 0x3f, 0xbf, 0x62, 0xdc, 0xe7, 0xde, 0xc4, 0xb8, 0xaf,
-	0xda, 0x71, 0x45, 0xd5, 0xc6, 0x7d, 0x11, 0x7d, 0xbf, 0x64, 0xc7, 0x7d,
-	0xb1, 0x6e, 0x5c, 0xd0, 0xca, 0xc3, 0x8b, 0xb8, 0x48, 0x17, 0x2f, 0xa0,
-	0x3c, 0x92, 0x09, 0x1f, 0xf4, 0xa4, 0xb9, 0x01, 0xbc, 0x1b, 0x87, 0x7e,
-	0x6c, 0x58, 0xd2, 0x8d, 0xd9, 0x3a, 0xfd, 0xf0, 0x46, 0xf4, 0xe3, 0x78,
-	0x99, 0x36, 0xe2, 0x7c, 0x9d, 0x5c, 0xa0, 0x6f, 0x14, 0xca, 0x49, 0xed,
-	0x07, 0xd1, 0x27, 0xa2, 0x7f, 0xb4, 0xd2, 0xb6, 0xfa, 0xa8, 0xce, 0x45,
-	0xfb, 0x95, 0x52, 0xbb, 0xdc, 0x59, 0xa2, 0x4d, 0x48, 0x7a, 0x09, 0xc3,
-	0xb1, 0x3d, 0xb4, 0x4f, 0x0b, 0xe1, 0x15, 0x3e, 0xe9, 0xc4, 0xf7, 0x7e,
-	0x79, 0xb5, 0xce, 0x98, 0x1c, 0x80, 0xef, 0x9e, 0x3b, 0xf1, 0x8b, 0xd0,
-	0x19, 0x0d, 0x80, 0x9b, 0xf4, 0xb6, 0x4d, 0x0e, 0x4c, 0xaa, 0x89, 0x2d,
-	0x90, 0x25, 0x37, 0x95, 0x1a, 0x61, 0xf7, 0x30, 0x4f, 0xab, 0x59, 0x3a,
-	0xf7, 0xc4, 0x4d, 0x1e, 0xb9, 0x97, 0xc0, 0x6f, 0xcf, 0xe4, 0xb5, 0x27,
-	0x92, 0x78, 0xff, 0x0f, 0x1e, 0xe5, 0x60, 0xc2, 0xbf, 0x4e, 0xe7, 0x08,
-	0x75, 0xec, 0xa1, 0xdd, 0x72, 0x83, 0xd6, 0xe1, 0xee, 0x2a, 0x3b, 0x49,
-	0x6d, 0xf3, 0xa4, 0x66, 0xa3, 0x8d, 0x96, 0xd2, 0x29, 0xc2, 0xf5, 0x90,
-	0x70, 0xff, 0xeb, 0x1e, 0x29, 0x06, 0x1b, 0xe1, 0x17, 0x30, 0x76, 0x9e,
-	0xee, 0xa6, 0x6d, 0x34, 0x33, 0xe5, 0xd9, 0x3c, 0xeb, 0x4d, 0xf2, 0xac,
-	0x1e, 0xa7, 0x51, 0xc3, 0x68, 0xce, 0x5e, 0x70, 0x1f, 0x21, 0xae, 0xcf,
-	0xfb, 0xcc, 0x54, 0x5a, 0xb4, 0xde, 0x99, 0xa9, 0x30, 0xaf, 0x1f, 0xfe,
-	0x54, 0x85, 0x79, 0xfc, 0x81, 0x78, 0x6f, 0x87, 0x9f, 0x5b, 0xd9, 0x21,
-	0xa3, 0x53, 0xeb, 0xa4, 0xd1, 0x57, 0x89, 0x2d, 0xd0, 0x1f, 0x6c, 0xd3,
-	0xb1, 0x07, 0xfe, 0xe1, 0xf4, 0x4e, 0x79, 0x62, 0x9a, 0x7d, 0x6f, 0x93,
-	0xd9, 0x39, 0x71, 0xbc, 0xb7, 0xaf, 0x47, 0x1d, 0xc8, 0xf5, 0x3d, 0x2c,
-	0x4b, 0xe1, 0x2e, 0xca, 0x7b, 0xbb, 0x2b, 0x17, 0xfb, 0xf8, 0xcc, 0xb3,
-	0x04, 0xe2, 0xb2, 0xbf, 0x8b, 0x7d, 0xed, 0x72, 0x6e, 0x0e, 0x34, 0x01,
-	0xb9, 0x3f, 0x78, 0x8a, 0x30, 0x89, 0xec, 0x9d, 0x61, 0x2c, 0xbd, 0xd3,
-	0x63, 0xdc, 0x94, 0xfb, 0x34, 0xb7, 0xf4, 0x71, 0x2c, 0xe8, 0x25, 0xe8,
-	0xb8, 0x8e, 0x3d, 0x46, 0x16, 0x64, 0x67, 0x1a, 0x50, 0xce, 0x7e, 0xe1,
-	0x3f, 0x1e, 0x64, 0x3f, 0x51, 0x5b, 0x85, 0x39, 0x35, 0x6a, 0x7a, 0x59,
-	0x5c, 0xa1, 0x3f, 0xce, 0xff, 0x48, 0xf6, 0x37, 0xfb, 0xe8, 0xd6, 0x7b,
-	0x21, 0xdc, 0x53, 0x36, 0xb6, 0x15, 0xd7, 0x44, 0xef, 0x29, 0xc0, 0xae,
-	0xba, 0x4a, 0xdb, 0x17, 0xb3, 0x55, 0xae, 0x20, 0x63, 0x51, 0xd1, 0x1a,
-	0x25, 0xe5, 0xd1, 0xf2, 0xd2, 0x3a, 0xed, 0x68, 0x58, 0xbe, 0x4e, 0xa4,
-	0x95, 0x60, 0xc4, 0xda, 0x1e, 0x0b, 0x72, 0x0c, 0x76, 0x59, 0xb7, 0x5e,
-	0xb3, 0x05, 0xd8, 0xb2, 0x76, 0xcd, 0xb4, 0x3d, 0x5b, 0x8c, 0xd6, 0x6c,
-	0x18, 0x1a, 0xa7, 0x92, 0xd9, 0xcc, 0x35, 0xf3, 0x18, 0xef, 0x06, 0xde,
-	0x0b, 0x58, 0xa7, 0x02, 0xd6, 0xa8, 0x50, 0xd9, 0x26, 0x33, 0x27, 0x55,
-	0x7b, 0x83, 0x48, 0x6a, 0xd4, 0xdf, 0x26, 0xe3, 0x73, 0x8c, 0x25, 0xec,
-	0x80, 0x0d, 0xb6, 0x13, 0x57, 0x3b, 0x9e, 0xd9, 0x2e, 0x21, 0xc5, 0x8a,
-	0x42, 0xdb, 0xa6, 0x55, 0x76, 0xd6, 0x39, 0x8c, 0xcd, 0x33, 0x9d, 0x8f,
-	0x01, 0x0f, 0x35, 0xde, 0x29, 0xd5, 0xc5, 0x9f, 0x38, 0x57, 0xad, 0x43,
-	0x31, 0xdf, 0x84, 0x5e, 0x4f, 0x1d, 0x87, 0x2a, 0x37, 0xbe, 0x19, 0x7b,
-	0x2a, 0x49, 0x7b, 0x2a, 0x3f, 0xe9, 0x99, 0xf3, 0x06, 0xc3, 0xf0, 0x9d,
-	0xfc, 0xfc, 0x66, 0xd2, 0xfa, 0xc8, 0x34, 0xe1, 0x8a, 0x47, 0x70, 0x2d,
-	0x5b, 0x33, 0x9e, 0x0f, 0x5b, 0x1d, 0xe7, 0x28, 0x2d, 0xe5, 0x43, 0x9a,
-	0xd8, 0x3e, 0xe3, 0x28, 0xed, 0x6b, 0xc0, 0x74, 0xb7, 0xb6, 0x61, 0x45,
-	0xdd, 0x26, 0x87, 0xcb, 0x3c, 0x5b, 0xc6, 0x78, 0xe2, 0x27, 0x19, 0x5f,
-	0xea, 0x9e, 0x91, 0x63, 0x18, 0x9b, 0xb9, 0x3f, 0xca, 0xc6, 0x6f, 0x36,
-	0xd8, 0x1c, 0x91, 0xfa, 0x18, 0x8e, 0xc9, 0x0d, 0x5a, 0x9e, 0x67, 0x9d,
-	0x1e, 0x5e, 0xc4, 0x3a, 0xff, 0x9a, 0xde, 0x1b, 0x94, 0xc9, 0x18, 0xb4,
-	0xdf, 0x68, 0x5f, 0xba, 0xdf, 0x9c, 0xab, 0x49, 0xc9, 0x50, 0xd9, 0xcc,
-	0xff, 0x92, 0xce, 0x11, 0x32, 0xb9, 0x90, 0x26, 0x7f, 0xe8, 0x1e, 0xb9,
-	0x04, 0x1d, 0x5e, 0x5b, 0xdb, 0x26, 0x19, 0x07, 0x2e, 0xf2, 0x7a, 0x5f,
-	0x22, 0x25, 0xf9, 0xbe, 0x47, 0x37, 0xf3, 0xdc, 0x45, 0x1c, 0xeb, 0x53,
-	0x9c, 0xe6, 0x59, 0x4c, 0xf6, 0x7b, 0xb9, 0xbe, 0x28, 0x66, 0x99, 0xd7,
-	0x0f, 0x59, 0xf9, 0x63, 0x3d, 0xc9, 0x66, 0xfd, 0x7e, 0x9d, 0xcd, 0xdf,
-	0x76, 0x44, 0x0e, 0x84, 0xf2, 0x87, 0xd0, 0x93, 0x67, 0xec, 0x9c, 0x52,
-	0x3a, 0x66, 0x25, 0xe1, 0xc5, 0x20, 0x69, 0x63, 0x96, 0x9c, 0xcb, 0x41,
-	0x4b, 0xdf, 0xc6, 0xfe, 0xa9, 0xd9, 0xd0, 0x66, 0xdf, 0xef, 0x09, 0x2d,
-	0x0b, 0x7b, 0xad, 0xed, 0xac, 0xe3, 0x3c, 0x8f, 0x88, 0xce, 0x09, 0x88,
-	0x7c, 0xa3, 0xae, 0x3a, 0xbf, 0xc0, 0xf8, 0x72, 0xc5, 0xa9, 0xb5, 0x64,
-	0x54, 0xcd, 0x27, 0xa4, 0x2f, 0x37, 0xb6, 0x8b, 0xdf, 0x47, 0x88, 0x7c,
-	0xb9, 0x5e, 0xeb, 0xcb, 0x6d, 0xd4, 0xbe, 0x9c, 0x89, 0x3d, 0x6c, 0x5c,
-	0xf2, 0xe5, 0x8a, 0x53, 0x05, 0xd0, 0x4a, 0xf4, 0x3d, 0x07, 0x63, 0x0b,
-	0x8d, 0x97, 0x78, 0x86, 0xa6, 0x51, 0xf2, 0xc3, 0x0a, 0x7e, 0x83, 0xf1,
-	0xb1, 0x18, 0xab, 0x50, 0xea, 0xeb, 0xd6, 0xbf, 0x68, 0x97, 0x6c, 0xdb,
-	0x3a, 0xcc, 0xfb, 0x6e, 0xbd, 0xe6, 0xb3, 0x25, 0xb3, 0xf7, 0x99, 0x3f,
-	0xc8, 0x98, 0x10, 0xcf, 0x49, 0x69, 0xfe, 0x4a, 0x0d, 0xc4, 0xba, 0x8d,
-	0x3d, 0xeb, 0x7b, 0xad, 0xd2, 0x7c, 0x1a, 0x38, 0x8f, 0xdb, 0x71, 0x53,
-	0x80, 0xe9, 0x30, 0xd6, 0xe6, 0x3a, 0x2b, 0x93, 0x39, 0xf6, 0x47, 0x9b,
-	0x18, 0x1b, 0x98, 0x2b, 0x45, 0x31, 0xc2, 0x98, 0x3d, 0xa3, 0xe9, 0xc7,
-	0x1a, 0xfd, 0x75, 0x6b, 0xda, 0xaa, 0x8f, 0xbf, 0xae, 0x6e, 0x22, 0x2d,
-	0xdd, 0xad, 0xf3, 0x5c, 0xd6, 0xf7, 0xa5, 0xf7, 0xeb, 0x9c, 0x7b, 0x1d,
-	0x63, 0x2c, 0x08, 0x73, 0xd4, 0xbe, 0x29, 0x3f, 0xa1, 0x65, 0xfe, 0xe1,
-	0x80, 0xfa, 0x6b, 0x8f, 0xfe, 0xdd, 0x98, 0x09, 0xc3, 0x8b, 0x7d, 0x13,
-	0x8c, 0x29, 0x7a, 0xdf, 0x96, 0xce, 0xe4, 0x80, 0xb6, 0x9d, 0xb0, 0x46,
-	0x07, 0x9b, 0x65, 0x9d, 0x3f, 0x62, 0x73, 0x66, 0x0a, 0x90, 0x9b, 0x69,
-	0xd8, 0x4c, 0x3c, 0x7f, 0xdc, 0x65, 0xdf, 0x15, 0xc2, 0x66, 0xd0, 0xd1,
-	0x07, 0xc5, 0xc8, 0x98, 0x7c, 0x4d, 0xc6, 0x30, 0xd7, 0x20, 0x4b, 0x42,
-	0x76, 0x8f, 0x4b, 0x9a, 0xdf, 0x2a, 0xe1, 0xd8, 0x45, 0xd9, 0x0a, 0xbd,
-	0xcc, 0x76, 0xb4, 0x55, 0xf9, 0xcc, 0x3d, 0x1c, 0xdf, 0x3b, 0x02, 0xdd,
-	0x72, 0xc3, 0x6a, 0xdd, 0x92, 0xa4, 0x5f, 0x9f, 0x9f, 0xa4, 0x6f, 0xb8,
-	0x1e, 0x6d, 0xb6, 0xc9, 0x87, 0xa6, 0x7e, 0xbe, 0x95, 0xbc, 0x35, 0x02,
-	0xb9, 0xae, 0xee, 0x8f, 0xce, 0x16, 0xb1, 0x8c, 0xef, 0xd9, 0x6f, 0x93,
-	0xa4, 0xde, 0xeb, 0xc9, 0x6f, 0x54, 0xd3, 0xa9, 0x45, 0xe8, 0xa6, 0x11,
-	0xe7, 0x57, 0xb7, 0x9b, 0x98, 0xea, 0x07, 0x5a, 0xcd, 0x59, 0x84, 0x66,
-	0xe0, 0x34, 0x8a, 0xb3, 0xd6, 0xd3, 0xec, 0xa2, 0x95, 0xc7, 0x61, 0xd8,
-	0xdc, 0xa7, 0x65, 0xf0, 0x7e, 0xca, 0xe0, 0xc3, 0x41, 0x97, 0xa1, 0x7d,
-	0xed, 0x33, 0x85, 0x58, 0x47, 0xe0, 0xa1, 0xcf, 0x65, 0xbe, 0x9f, 0xe5,
-	0x4f, 0x3f, 0xbb, 0x60, 0xe5, 0x92, 0x72, 0x56, 0xf3, 0xa5, 0xba, 0x26,
-	0xbe, 0x4c, 0xe6, 0x1e, 0x9d, 0xa2, 0x3e, 0x0e, 0xe6, 0xbf, 0x09, 0x39,
-	0x95, 0xd7, 0x78, 0xd8, 0x26, 0xf7, 0x4d, 0x49, 0xf6, 0x12, 0x74, 0x55,
-	0x71, 0x6e, 0x39, 0x6f, 0xae, 0xee, 0x8f, 0x73, 0x7d, 0xa4, 0xd5, 0xf8,
-	0xb6, 0xcb, 0xe7, 0x3a, 0x8f, 0xb9, 0x66, 0xf5, 0x5c, 0xb9, 0x6f, 0x33,
-	0x67, 0xe7, 0xba, 0x3e, 0x9a, 0x6b, 0xff, 0xf2, 0xb9, 0x46, 0xbe, 0x7d,
-	0x24, 0x77, 0x53, 0x3a, 0xff, 0x5e, 0xe7, 0x7d, 0x4f, 0xad, 0x97, 0x81,
-	0xc9, 0x8d, 0x56, 0x5e, 0x7a, 0xd0, 0x3d, 0xcc, 0x89, 0x9f, 0xbf, 0xd7,
-	0x13, 0x8b, 0x33, 0x45, 0x3c, 0x50, 0xd6, 0xb6, 0xea, 0x33, 0x3b, 0x33,
-	0xf0, 0xaf, 0x6e, 0x2d, 0xb1, 0x6e, 0xf4, 0xfe, 0x72, 0xb1, 0xe3, 0xc8,
-	0xa7, 0xa6, 0xdf, 0xd4, 0xbd, 0x2a, 0xa6, 0x60, 0xe2, 0xc3, 0x8c, 0x0b,
-	0x9b, 0xb3, 0xc4, 0xcc, 0x45, 0xbc, 0x03, 0x3c, 0xf5, 0xf1, 0x52, 0xba,
-	0x3f, 0x17, 0xa3, 0x1c, 0x9d, 0x96, 0xa3, 0xd5, 0x41, 0xe9, 0xd0, 0xe7,
-	0x49, 0x5f, 0x37, 0x76, 0x9c, 0xad, 0x8f, 0x1d, 0x33, 0x9d, 0x80, 0xb1,
-	0xe3, 0xfd, 0x3f, 0x42, 0xec, 0x58, 0x1c, 0x13, 0x3b, 0x5e, 0xcb, 0xbf,
-	0x9a, 0x28, 0x4f, 0x63, 0x5e, 0xcd, 0x90, 0x25, 0x0b, 0x4e, 0x7e, 0xae,
-	0x05, 0xf7, 0x0b, 0xb8, 0xc7, 0x71, 0xbf, 0x84, 0xbb, 0x87, 0xfb, 0x8b,
-	0xb8, 0x27, 0x64, 0x62, 0x49, 0x67, 0x4c, 0x43, 0x6e, 0x50, 0x97, 0xb1,
-	0xad, 0xf1, 0x07, 0x66, 0x2b, 0x6d, 0xfc, 0x2e, 0x8c, 0x33, 0x33, 0xc7,
-	0x39, 0x6c, 0x94, 0xf1, 0x29, 0xca, 0xec, 0x56, 0x99, 0x9c, 0x8a, 0x6c,
-	0xdb, 0xbb, 0xb6, 0x71, 0xcf, 0x60, 0x44, 0x22, 0xdb, 0xf5, 0x77, 0xb7,
-	0xd9, 0x5c, 0xfb, 0x2d, 0xd2, 0xbc, 0x09, 0x6b, 0x70, 0x5a, 0x2e, 0x4d,
-	0x6f, 0x5a, 0x66, 0xc3, 0xa6, 0x6c, 0x4c, 0x70, 0xda, 0xea, 0xde, 0xb5,
-	0x65, 0x44, 0xfd, 0xfa, 0x27, 0x6d, 0x4e, 0x69, 0x94, 0x23, 0x94, 0xd2,
-	0xeb, 0x33, 0x5c, 0x9d, 0xc6, 0x78, 0xfd, 0x92, 0x9d, 0xe6, 0x3c, 0x97,
-	0xbe, 0x4d, 0x01, 0x79, 0x78, 0x0a, 0x7a, 0x75, 0x19, 0x5d, 0x82, 0x6e,
-	0x39, 0x37, 0x07, 0xb4, 0xfb, 0xa8, 0xcc, 0x4c, 0x12, 0xbe, 0xae, 0x64,
-	0x4c, 0x9f, 0x5d, 0xc3, 0xf3, 0xb4, 0xc9, 0x99, 0x1f, 0xa8, 0x46, 0xe7,
-	0xd6, 0x36, 0xeb, 0xef, 0x11, 0x2c, 0x3f, 0xbb, 0x66, 0xf5, 0xb3, 0xb6,
-	0x1d, 0x78, 0x86, 0x2d, 0x9a, 0xc3, 0x5a, 0xf4, 0x14, 0xca, 0xb8, 0xce,
-	0x3b, 0xdb, 0x22, 0x67, 0x1e, 0x5c, 0xca, 0xa1, 0x6d, 0x85, 0x8d, 0xd2,
-	0x0e, 0x13, 0x79, 0xd8, 0xcd, 0x74, 0xc1, 0xc7, 0x63, 0x9e, 0x4c, 0x57,
-	0xf2, 0x36, 0x9d, 0xdb, 0x5c, 0x3b, 0x47, 0x58, 0xcb, 0x6f, 0x8e, 0xce,
-	0x6d, 0x25, 0x65, 0x10, 0x74, 0x38, 0xa4, 0xcb, 0x13, 0x98, 0x0f, 0xf7,
-	0xfd, 0x34, 0x1e, 0x20, 0x7b, 0xb8, 0xe7, 0x87, 0xb9, 0x57, 0xbf, 0x01,
-	0x7a, 0x77, 0xec, 0x19, 0x36, 0xd2, 0x58, 0x9f, 0x8c, 0x55, 0x92, 0xce,
-	0x58, 0xa5, 0xcf, 0x39, 0x54, 0xb1, 0xef, 0xfa, 0x8a, 0x58, 0x0f, 0xfc,
-	0x9e, 0xee, 0x70, 0x46, 0x80, 0xaf, 0x62, 0xb9, 0xd3, 0xc9, 0xea, 0xbb,
-	0x6f, 0xef, 0x90, 0x03, 0x58, 0xab, 0x81, 0xe9, 0xa4, 0x96, 0xf3, 0xb5,
-	0xef, 0x61, 0x45, 0xeb, 0xfa, 0xa4, 0xde, 0x1b, 0x9a, 0x97, 0x69, 0xfd,
-	0x7d, 0x25, 0x63, 0x3b, 0x9c, 0x46, 0x7f, 0xd3, 0x36, 0x26, 0xde, 0xe3,
-	0xe4, 0x75, 0x3f, 0x66, 0x3d, 0x8a, 0xe5, 0x53, 0xb8, 0xaf, 0x3c, 0x43,
-	0x1d, 0xe9, 0x19, 0xc2, 0xfd, 0x08, 0xf4, 0x59, 0x78, 0x8f, 0x91, 0x57,
-	0xd3, 0x32, 0x51, 0x65, 0xfe, 0x08, 0xfb, 0x41, 0x79, 0xe5, 0x30, 0x74,
-	0xd2, 0xf2, 0x33, 0x84, 0x43, 0xb5, 0x75, 0x48, 0x4d, 0x0b, 0x61, 0xe1,
-	0x1a, 0x2c, 0x3f, 0x5f, 0x7f, 0xf9, 0x7f, 0xd1, 0xbe, 0xa2, 0x91, 0xa1,
-	0x16, 0x8e, 0x2c, 0xe5, 0x9d, 0x91, 0x2b, 0x9f, 0x96, 0x23, 0xc0, 0xe3,
-	0x31, 0xc0, 0xa4, 0xee, 0xe7, 0xf7, 0x5e, 0x2a, 0x52, 0x9c, 0xbd, 0x4f,
-	0xd4, 0x43, 0x97, 0x1c, 0xf7, 0xa1, 0x23, 0x12, 0x7b, 0x68, 0xc1, 0x69,
-	0x78, 0xa8, 0x53, 0xfb, 0xe5, 0xfb, 0x82, 0xce, 0xe4, 0x21, 0x39, 0x2d,
-	0xee, 0xfd, 0x4a, 0x9f, 0x27, 0x2b, 0x7a, 0x8c, 0xf1, 0x9d, 0x96, 0xd8,
-	0xfd, 0x71, 0x7b, 0x16, 0xd5, 0xc4, 0xf5, 0x16, 0x35, 0xdf, 0x3f, 0x97,
-	0x20, 0xce, 0x16, 0x65, 0x5a, 0xf3, 0xce, 0x00, 0xf4, 0x44, 0x6e, 0x32,
-	0xb5, 0x54, 0xc7, 0xe4, 0x7b, 0x6e, 0x4c, 0x18, 0x7e, 0x61, 0x9d, 0x2e,
-	0x87, 0xdf, 0x85, 0xb0, 0x3a, 0xff, 0xca, 0x28, 0xf7, 0xd3, 0xac, 0x29,
-	0xdf, 0xff, 0x10, 0x6b, 0xd8, 0x85, 0xf5, 0xe2, 0x78, 0x8e, 0xde, 0xcf,
-	0xe5, 0x59, 0x5c, 0x4f, 0x7a, 0x92, 0x4d, 0x4b, 0x76, 0x10, 0xeb, 0xde,
-	0x27, 0x4d, 0x80, 0x5b, 0x3d, 0x54, 0x34, 0x76, 0x9d, 0x90, 0x4e, 0x05,
-	0x92, 0x9b, 0x34, 0xdb, 0xd5, 0xbf, 0x4f, 0xaf, 0xe1, 0xbd, 0x96, 0x66,
-	0xd6, 0x19, 0xfb, 0x11, 0xcf, 0x86, 0x2e, 0x8a, 0xb2, 0x77, 0xea, 0xbb,
-	0xd0, 0xf3, 0xdc, 0x77, 0xd1, 0xf6, 0xe2, 0x1a, 0xb6, 0x20, 0x79, 0xe9,
-	0x69, 0xeb, 0x57, 0x86, 0xe1, 0x54, 0x10, 0x00, 0x8f, 0x6b, 0xf9, 0x92,
-	0x3b, 0x9c, 0xd9, 0xc9, 0x9d, 0xce, 0xcc, 0x64, 0x28, 0x63, 0x01, 0xbf,
-	0x19, 0xc2, 0x1c, 0x00, 0xda, 0x5b, 0x2c, 0xeb, 0x84, 0x6e, 0xdd, 0x9d,
-	0xe0, 0xf9, 0xa6, 0x9b, 0xfc, 0x17, 0xc4, 0xd4, 0x23, 0x8e, 0xe9, 0x23,
-	0x77, 0x3e, 0x92, 0x17, 0x7e, 0x9f, 0xa3, 0x27, 0x99, 0xd0, 0xdf, 0x10,
-	0xf9, 0x0c, 0xda, 0x61, 0x8c, 0x32, 0xc7, 0x7d, 0xc6, 0x99, 0x81, 0x3c,
-	0x9b, 0x9d, 0xe2, 0x37, 0x01, 0x98, 0x4f, 0x1b, 0x6b, 0x57, 0x72, 0x95,
-	0x37, 0x6e, 0xbf, 0x5b, 0x57, 0x80, 0x0b, 0x14, 0xd3, 0x65, 0x3d, 0xde,
-	0xe8, 0xd2, 0xb7, 0xec, 0xa2, 0xb2, 0xe8, 0x9b, 0x76, 0x4a, 0xe7, 0x4e,
-	0xc3, 0x97, 0x3d, 0x33, 0x22, 0xdf, 0x77, 0xe6, 0x4a, 0xaf, 0x38, 0x8f,
-	0x96, 0xb2, 0xd7, 0x5c, 0x01, 0xfa, 0xb8, 0x18, 0xe4, 0x29, 0xbf, 0x60,
-	0xf3, 0x4d, 0x49, 0xa1, 0x3a, 0x26, 0xd3, 0xdb, 0x3a, 0xbd, 0xfb, 0xf5,
-	0xda, 0x9c, 0x01, 0xce, 0xbe, 0x81, 0xf5, 0x3b, 0x93, 0xa0, 0x7e, 0x1b,
-	0x2d, 0x29, 0xf0, 0xb2, 0xfa, 0x69, 0x5c, 0xb0, 0x6d, 0x1b, 0xb5, 0x8d,
-	0x72, 0x28, 0x60, 0xbd, 0x9d, 0xce, 0xc0, 0xe4, 0x0e, 0xac, 0xe3, 0x41,
-	0xe8, 0x4f, 0x07, 0x76, 0x1a, 0x68, 0x1b, 0x65, 0xe3, 0xc0, 0xc1, 0x68,
-	0x60, 0xe4, 0xf9, 0x80, 0x14, 0xb4, 0x8f, 0x67, 0xee, 0x59, 0x65, 0x62,
-	0x66, 0x61, 0x38, 0x0b, 0xfb, 0x80, 0xdf, 0xc5, 0x9a, 0xa8, 0xce, 0xe1,
-	0xfa, 0x71, 0xbb, 0xa7, 0x3d, 0x7f, 0x99, 0x3d, 0x6d, 0x4f, 0x4e, 0x57,
-	0xf5, 0x39, 0x79, 0x9d, 0x5f, 0x95, 0x52, 0xeb, 0xda, 0xf4, 0x5a, 0xa9,
-	0x2e, 0x9d, 0x93, 0x96, 0x95, 0x47, 0x12, 0x46, 0x0f, 0x13, 0xa6, 0x14,
-	0xe0, 0xd9, 0x09, 0x5c, 0x10, 0x1e, 0xd3, 0x46, 0xd4, 0x3b, 0xb7, 0x52,
-	0x1f, 0x2e, 0xca, 0xa7, 0x12, 0xd1, 0x19, 0x05, 0xf4, 0x03, 0x19, 0x37,
-	0xb7, 0xd5, 0xe8, 0xc9, 0x2d, 0x6b, 0xf4, 0x13, 0xcd, 0xcd, 0xb1, 0x73,
-	0x23, 0xdd, 0x6e, 0xbe, 0x92, 0x3e, 0xc5, 0xa2, 0x34, 0xad, 0xa8, 0xcf,
-	0x98, 0xfe, 0xbe, 0xed, 0xe6, 0xcc, 0x03, 0xeb, 0x7a, 0xb0, 0x4d, 0x69,
-	0xe7, 0x12, 0x8f, 0x7a, 0xdd, 0x4a, 0x4a, 0x78, 0x6e, 0xe1, 0x0c, 0x64,
-	0xcb, 0x55, 0xde, 0x4f, 0x28, 0xd2, 0x61, 0x84, 0xeb, 0x6f, 0x68, 0x3e,
-	0x19, 0x2d, 0x31, 0xb6, 0xf2, 0x68, 0x98, 0x1d, 0x26, 0x8f, 0xb1, 0x0f,
-	0xbe, 0x9f, 0xd2, 0xf1, 0xdc, 0x83, 0x01, 0x63, 0x45, 0x9d, 0x8f, 0xdc,
-	0xa1, 0x22, 0x39, 0x05, 0xfd, 0x5b, 0x5e, 0x70, 0xf8, 0xdd, 0xbe, 0x03,
-	0x82, 0xfb, 0xdc, 0x82, 0xf3, 0xcd, 0xa9, 0x67, 0xf0, 0xdc, 0x60, 0xbf,
-	0xd5, 0x67, 0xf4, 0x94, 0xc8, 0x1f, 0x46, 0xf3, 0x4d, 0x16, 0xb0, 0xf6,
-	0x2f, 0x62, 0xed, 0xd7, 0xfe, 0x36, 0x1f, 0xde, 0x55, 0xf0, 0xae, 0xf2,
-	0x0b, 0x61, 0xb6, 0x95, 0xb4, 0x18, 0xe8, 0xb3, 0xa9, 0x97, 0xf7, 0x9b,
-	0xfb, 0x35, 0x5f, 0x8c, 0x97, 0xcf, 0x81, 0x2f, 0xb2, 0xdc, 0x6f, 0x0e,
-	0x1f, 0x0e, 0x6e, 0x04, 0x5f, 0xec, 0x97, 0xdf, 0x83, 0x5d, 0xf0, 0x3b,
-	0xd5, 0x0c, 0xf8, 0xa3, 0x1f, 0xfc, 0xd2, 0x07, 0x1e, 0x09, 0xb4, 0x8d,
-	0xfc, 0x18, 0xf4, 0x1f, 0xf4, 0x9a, 0x73, 0x68, 0xb2, 0xc3, 0xc9, 0x4f,
-	0xfa, 0xce, 0xd8, 0x24, 0xbf, 0xff, 0xa2, 0xde, 0xda, 0x20, 0x6e, 0x72,
-	0x56, 0xc8, 0x0b, 0x9d, 0xcc, 0x71, 0x6c, 0x03, 0xae, 0xce, 0x12, 0x57,
-	0xb3, 0xd5, 0x1e, 0xef, 0x0a, 0xf0, 0x44, 0x9b, 0xe6, 0x89, 0x8d, 0x4e,
-	0xd6, 0xbb, 0xd1, 0xf2, 0xc4, 0x0b, 0xe0, 0x89, 0x4b, 0xab, 0x78, 0xe2,
-	0x29, 0x4b, 0xff, 0xf3, 0x75, 0x3c, 0x31, 0x6b, 0xcb, 0xa6, 0x2f, 0xc3,
-	0x13, 0x5b, 0xfd, 0xf4, 0xe7, 0x47, 0xe4, 0x55, 0xf0, 0x84, 0x28, 0xf2,
-	0xc4, 0x56, 0xcd, 0x13, 0x8c, 0x1d, 0x91, 0x2f, 0xda, 0x21, 0x47, 0xc8,
-	0x17, 0x17, 0x64, 0x11, 0x7c, 0xf1, 0x9c, 0xe2, 0xd8, 0x67, 0x68, 0x2b,
-	0x4c, 0xd2, 0x27, 0x3b, 0x55, 0xee, 0x00, 0xbf, 0x2b, 0xf9, 0xaf, 0x53,
-	0x61, 0xb8, 0x00, 0x3f, 0xfd, 0x41, 0xd8, 0xf3, 0xae, 0xfe, 0x0e, 0xe4,
-	0x3c, 0xe8, 0x3e, 0xa2, 0xf7, 0x31, 0x07, 0xf4, 0x7e, 0x6c, 0x06, 0x73,
-	0x18, 0x53, 0x9f, 0x82, 0x2f, 0xec, 0x61, 0x5d, 0x69, 0xe7, 0x9f, 0xd4,
-	0x3c, 0xd4, 0x00, 0x7d, 0xf0, 0x68, 0x1f, 0x63, 0x4d, 0xbe, 0x77, 0x48,
-	0x75, 0x16, 0x06, 0x01, 0x73, 0x4c, 0xdd, 0x2f, 0x8c, 0x73, 0xb4, 0xae,
-	0xb0, 0xf3, 0x29, 0x23, 0x86, 0x21, 0xeb, 0xcc, 0xbb, 0x42, 0xd8, 0x04,
-	0x9b, 0xb4, 0x49, 0x19, 0x1b, 0x5d, 0xed, 0x49, 0x7b, 0x3f, 0x07, 0x01,
-	0xda, 0x08, 0x7b, 0x61, 0x2f, 0x56, 0x7b, 0xb0, 0x54, 0x6f, 0xe3, 0xff,
-	0x67, 0xd8, 0xf8, 0x6c, 0x23, 0xae, 0xb1, 0xf1, 0x7f, 0xc5, 0xf2, 0x1a,
-	0x7f, 0x7b, 0xda, 0xde, 0x3f, 0x0c, 0xf8, 0xf6, 0x2d, 0xd9, 0xfb, 0xec,
-	0x83, 0x76, 0x87, 0xc8, 0x0d, 0xb0, 0xf9, 0xde, 0x09, 0x1e, 0xbc, 0x11,
-	0xbe, 0xd4, 0xbb, 0x4a, 0x9e, 0xec, 0x2f, 0xb5, 0xc1, 0xe7, 0x6e, 0x97,
-	0x77, 0x4f, 0xed, 0x94, 0xa1, 0xc9, 0x0f, 0x5e, 0x21, 0xcd, 0xdb, 0x60,
-	0xa3, 0x4e, 0x01, 0xce, 0x98, 0x95, 0xdb, 0x3f, 0x04, 0xde, 0x3a, 0x53,
-	0xdf, 0x57, 0x6d, 0xdb, 0x8d, 0x9c, 0xe7, 0xd9, 0xc9, 0xb5, 0xfa, 0x49,
-	0xa0, 0x3d, 0x63, 0x29, 0xdb, 0xe4, 0xec, 0x49, 0x7a, 0x5f, 0x29, 0xd8,
-	0xe5, 0x01, 0x6c, 0x92, 0x1d, 0xe8, 0x8f, 0xf1, 0xe4, 0x4d, 0xf2, 0xd4,
-	0x35, 0xee, 0x27, 0xf2, 0x9a, 0x0f, 0xdb, 0x9d, 0xdc, 0xd4, 0x8d, 0x52,
-	0x3c, 0x18, 0xc7, 0x1c, 0x54, 0xdb, 0x16, 0xb9, 0x5e, 0x86, 0xf4, 0x7c,
-	0xce, 0xc8, 0x11, 0xe8, 0xe6, 0x3f, 0x28, 0x0d, 0xc9, 0xe2, 0x70, 0x2b,
-	0x9e, 0xe3, 0xf2, 0x54, 0xa9, 0x07, 0xbe, 0xcf, 0x3b, 0x80, 0xa3, 0x46,
-	0x3c, 0x37, 0xca, 0xc0, 0x15, 0xe4, 0xd5, 0x16, 0x59, 0x40, 0xf9, 0x3b,
-	0xe5, 0xdf, 0xd9, 0x72, 0x96, 0x91, 0x37, 0x5a, 0xd0, 0x36, 0x2e, 0x17,
-	0x4b, 0xb4, 0x2b, 0x35, 0x4f, 0xf4, 0x7f, 0x4b, 0x7a, 0xb2, 0xdf, 0x82,
-	0x9d, 0x7a, 0x01, 0xd7, 0xd3, 0x92, 0xde, 0x3f, 0xea, 0xf4, 0xa4, 0x3a,
-	0x1d, 0xe8, 0x4e, 0x5c, 0xae, 0xd3, 0xe3, 0x35, 0x3a, 0x57, 0xd9, 0x3e,
-	0x1a, 0xe4, 0xe9, 0x83, 0x2a, 0xd9, 0x82, 0x35, 0xd9, 0xed, 0x74, 0xd9,
-	0x32, 0x3e, 0xeb, 0x9c, 0x3c, 0xe9, 0x3c, 0xab, 0x76, 0x6c, 0x10, 0xe9,
-	0x68, 0x81, 0xcd, 0x33, 0x26, 0xaa, 0xad, 0x45, 0x5c, 0xe9, 0x9c, 0x51,
-	0xed, 0x28, 0xf3, 0x6d, 0x59, 0xa2, 0x05, 0xfa, 0x01, 0x65, 0xdb, 0x50,
-	0xb6, 0xcb, 0x96, 0xb5, 0xb6, 0x48, 0x23, 0xca, 0xce, 0x68, 0x9e, 0xbf,
-	0xd4, 0xe5, 0x7b, 0x79, 0xa7, 0x59, 0x3a, 0x4e, 0xb5, 0x40, 0x36, 0x6c,
-	0x92, 0x85, 0x6b, 0x9a, 0xa4, 0x03, 0xef, 0x18, 0xe7, 0x0e, 0x4e, 0xc5,
-	0xe5, 0xba, 0x53, 0x9d, 0xc9, 0x0f, 0x61, 0x0e, 0x9d, 0x67, 0x19, 0xf7,
-	0x7e, 0xf2, 0x0a, 0xc6, 0x7d, 0x3a, 0xce, 0xf2, 0xde, 0xa4, 0xe5, 0x0f,
-	0xf1, 0x61, 0xbe, 0x71, 0x44, 0x99, 0x7c, 0x1a, 0x7e, 0x2e, 0x75, 0x78,
-	0xa7, 0xfd, 0x1e, 0xc7, 0x9f, 0x5e, 0x41, 0xbf, 0x6d, 0x86, 0xf6, 0x54,
-	0x99, 0xfc, 0x48, 0x3d, 0x84, 0xfb, 0xb4, 0x23, 0xc5, 0x9a, 0xcc, 0x9a,
-	0x23, 0x5f, 0x9d, 0x54, 0xcc, 0x65, 0x41, 0x59, 0xf5, 0x67, 0x42, 0xb3,
-	0xc6, 0xe4, 0x05, 0x23, 0x97, 0xde, 0x67, 0xe4, 0xd2, 0x99, 0xf3, 0xcb,
-	0xe4, 0xd2, 0x25, 0x2d, 0x97, 0x0e, 0x0a, 0xee, 0x73, 0x97, 0x20, 0x97,
-	0x5e, 0xc0, 0xb3, 0xa7, 0xe5, 0x52, 0x42, 0xac, 0xbd, 0x2c, 0x3f, 0xd0,
-	0xe3, 0xcf, 0x96, 0x5d, 0x6d, 0x57, 0x15, 0xa7, 0x61, 0x93, 0x94, 0x27,
-	0xac, 0xfe, 0x96, 0x4c, 0xab, 0x74, 0xf5, 0xff, 0x50, 0x22, 0x9b, 0xf3,
-	0xcf, 0xae, 0xe0, 0xf7, 0x46, 0x9f, 0x53, 0x94, 0x61, 0xaf, 0x42, 0x86,
-	0x89, 0x5a, 0x5b, 0x86, 0xe1, 0x5d, 0x05, 0xef, 0x2a, 0xec, 0xf7, 0x6f,
-	0x7f, 0x38, 0xe2, 0x51, 0x7e, 0x50, 0x66, 0x40, 0x26, 0x95, 0x21, 0x93,
-	0xca, 0x90, 0x53, 0x65, 0xc8, 0x25, 0xd8, 0x6c, 0xe7, 0xcb, 0x90, 0x4b,
-	0x65, 0xc8, 0x25, 0xc8, 0xb8, 0xc7, 0x20, 0xe3, 0x8c, 0x4c, 0x1b, 0x86,
-	0x4c, 0x3b, 0x23, 0xf7, 0x59, 0x5d, 0x6f, 0x62, 0x25, 0xbd, 0xd6, 0x47,
-	0xea, 0xd3, 0x31, 0xe4, 0xf3, 0x75, 0xb1, 0xc1, 0x03, 0xc7, 0x35, 0xbf,
-	0x7b, 0xbe, 0xba, 0xca, 0x61, 0x0e, 0xcd, 0xf7, 0xb5, 0xff, 0xbe, 0x9b,
-	0xbf, 0xa5, 0x09, 0x7c, 0xfd, 0x1d, 0xcb, 0xd7, 0xbb, 0x97, 0xf8, 0x3a,
-	0xed, 0x30, 0x56, 0xbc, 0x36, 0x5f, 0x6f, 0xb3, 0xef, 0x0a, 0xe1, 0x3a,
-	0xf0, 0xf5, 0xba, 0x15, 0x7c, 0x1d, 0x07, 0x5f, 0xef, 0x5f, 0xc5, 0xd7,
-	0x1b, 0x9c, 0x01, 0xdd, 0x86, 0x67, 0x24, 0xf8, 0xdc, 0xe8, 0xd4, 0xf8,
-	0xfa, 0x1e, 0xcd, 0xd7, 0x47, 0xc1, 0xd7, 0xd7, 0xd7, 0xf1, 0xf5, 0x7e,
-	0x49, 0xdf, 0x9c, 0x8b, 0xed, 0x94, 0xd1, 0xfb, 0x55, 0xdb, 0x66, 0xf9,
-	0x17, 0x31, 0xed, 0x0d, 0x8f, 0x0d, 0x4c, 0xb5, 0x49, 0xfe, 0xa1, 0x57,
-	0x50, 0x46, 0x3e, 0x4b, 0x8f, 0x64, 0x1d, 0x4f, 0x8e, 0x1c, 0xff, 0xbe,
-	0xcc, 0x6b, 0xde, 0x12, 0x19, 0x3b, 0x1e, 0x97, 0xf1, 0xe3, 0x8c, 0x43,
-	0x7c, 0xcf, 0xd2, 0x7b, 0x93, 0x8c, 0x1f, 0x64, 0xde, 0x9c, 0x2b, 0xa3,
-	0xc7, 0xe1, 0x6f, 0x1d, 0x67, 0x1c, 0xe2, 0xa5, 0x25, 0x1e, 0x9b, 0x87,
-	0x6c, 0x19, 0x3d, 0xce, 0xb5, 0x8e, 0xa3, 0x9f, 0x16, 0x39, 0x7a, 0x5c,
-	0xe4, 0xb6, 0xe3, 0xae, 0x7c, 0xe0, 0xf8, 0x12, 0xaf, 0x0d, 0x47, 0xbc,
-	0xf6, 0x0c, 0x78, 0xad, 0xd3, 0xf2, 0x9a, 0x5a, 0xe2, 0xb5, 0xaf, 0xd6,
-	0xf1, 0x1a, 0xdb, 0x93, 0xd7, 0x9e, 0xb5, 0x65, 0x7c, 0x76, 0xe5, 0xd0,
-	0xf1, 0x76, 0x19, 0x7d, 0xe8, 0x2d, 0x32, 0x76, 0x3f, 0x61, 0x35, 0xdf,
-	0x85, 0xa2, 0x2d, 0x36, 0x5d, 0xed, 0x44, 0xff, 0x51, 0x0e, 0x11, 0x71,
-	0xed, 0x77, 0xcf, 0x48, 0xba, 0xc0, 0xf1, 0x1a, 0xe1, 0x47, 0x9f, 0x82,
-	0x7f, 0x71, 0x08, 0x30, 0xdd, 0x72, 0x5c, 0xd2, 0xae, 0xbc, 0x2c, 0x13,
-	0xc1, 0xe9, 0xed, 0xc6, 0x9e, 0x80, 0x2d, 0xa2, 0x6d, 0x9f, 0xac, 0xe4,
-	0xdf, 0x1e, 0x6a, 0x1f, 0x63, 0xb2, 0x22, 0x8c, 0x05, 0x30, 0x6e, 0x6e,
-	0xbf, 0x85, 0xca, 0xfc, 0xc7, 0x06, 0x7d, 0xe6, 0x45, 0xc7, 0x6c, 0xfb,
-	0xf8, 0x9e, 0xcf, 0xb0, 0x67, 0xf4, 0xd9, 0x45, 0xb6, 0x67, 0x3f, 0x09,
-	0x1d, 0x53, 0x2f, 0x56, 0xf8, 0x4d, 0x1c, 0xf8, 0x9f, 0x15, 0x7e, 0x5b,
-	0xeb, 0x37, 0xdb, 0x4c, 0x7c, 0x96, 0x7c, 0xf7, 0x5d, 0x27, 0x5f, 0x9a,
-	0xd3, 0xdf, 0x38, 0xc8, 0xf9, 0xf8, 0x5d, 0xe1, 0x33, 0xeb, 0xcf, 0x31,
-	0xde, 0x91, 0x4a, 0xa9, 0x63, 0xdb, 0x99, 0x7b, 0x70, 0x70, 0x8e, 0x75,
-	0x77, 0x5a, 0x1e, 0xdd, 0xa9, 0xfd, 0x0e, 0xda, 0x58, 0xa3, 0x93, 0x2f,
-	0x48, 0x91, 0xb6, 0xc9, 0xf0, 0x4e, 0xa7, 0x30, 0xfd, 0x73, 0xdb, 0x8d,
-	0xfd, 0x3c, 0xb0, 0x95, 0x79, 0x87, 0x59, 0xb5, 0x5a, 0x26, 0x9f, 0x92,
-	0x48, 0x26, 0xa7, 0x6f, 0xce, 0xc2, 0xce, 0xce, 0x1f, 0xd7, 0xdf, 0xab,
-	0x4a, 0x75, 0x2a, 0xce, 0xe9, 0x4e, 0xc8, 0xd7, 0x88, 0x16, 0x92, 0xf2,
-	0xd1, 0xe3, 0xa4, 0x07, 0x95, 0xd8, 0x28, 0x1f, 0xb1, 0xf4, 0x70, 0x46,
-	0x4a, 0x90, 0x3b, 0xc7, 0x8f, 0x7f, 0x40, 0xa6, 0x0f, 0xac, 0xa4, 0x87,
-	0xb1, 0x1a, 0x3d, 0x24, 0x60, 0x9f, 0x39, 0xf5, 0xf4, 0xf0, 0xf3, 0x4b,
-	0xf4, 0x30, 0xed, 0xfc, 0x6b, 0xe9, 0xe1, 0x86, 0x65, 0xf4, 0x30, 0xa1,
-	0xe9, 0x61, 0x68, 0x89, 0x1e, 0x26, 0x8e, 0x73, 0x5c, 0xbd, 0x37, 0xea,
-	0x2d, 0x38, 0x5c, 0xf3, 0x25, 0x5a, 0x48, 0x8d, 0xeb, 0x7c, 0xfd, 0x74,
-	0x81, 0xe7, 0x9b, 0x36, 0x28, 0xc6, 0x49, 0x6a, 0xeb, 0xbf, 0xf1, 0xdf,
-	0x74, 0xfd, 0xaf, 0xda, 0xfa, 0xff, 0x77, 0xfd, 0x33, 0x5b, 0x99, 0xbb,
-	0xcf, 0x33, 0xb0, 0x46, 0x1e, 0x47, 0xf4, 0x90, 0xdb, 0x6a, 0xf4, 0x02,
-	0xd7, 0x98, 0xcf, 0x90, 0x67, 0x90, 0x7f, 0xe7, 0x21, 0xff, 0x9e, 0x80,
-	0xfc, 0x7b, 0x7c, 0xd9, 0x9e, 0x40, 0xbf, 0x8d, 0x47, 0x84, 0x72, 0x24,
-	0xa8, 0xe1, 0x63, 0xa1, 0x8f, 0xf8, 0x30, 0xf9, 0x27, 0xcc, 0xfd, 0x5d,
-	0x8e, 0x13, 0x57, 0xe7, 0x1c, 0x3d, 0x1a, 0xd4, 0xe3, 0x84, 0x70, 0xbf,
-	0x5c, 0x37, 0x47, 0xfc, 0xae, 0xf0, 0xf9, 0x8c, 0xce, 0x23, 0x29, 0xea,
-	0x3d, 0x28, 0xe2, 0x85, 0x7b, 0x50, 0xc4, 0x89, 0xab, 0xed, 0xfd, 0x62,
-	0xa5, 0x49, 0xe7, 0xd0, 0x1f, 0x9e, 0x4b, 0xc8, 0x42, 0x82, 0x31, 0x3e,
-	0x7e, 0xe7, 0x90, 0x7e, 0xb3, 0x9f, 0x2c, 0x4a, 0x81, 0xb9, 0x72, 0xe0,
-	0xe9, 0x0d, 0x96, 0xb6, 0x19, 0x1b, 0xe4, 0x19, 0xe0, 0x68, 0x2f, 0xa2,
-	0xdb, 0xca, 0xba, 0x96, 0xba, 0x98, 0x25, 0xf0, 0x3e, 0x25, 0xa9, 0x5c,
-	0x1f, 0xee, 0x73, 0x1c, 0xfb, 0x13, 0x32, 0xf1, 0xe0, 0x87, 0x61, 0xcb,
-	0xbd, 0x1f, 0x3a, 0x87, 0xe7, 0xcf, 0xb8, 0xf7, 0xe0, 0x69, 0x18, 0x66,
-	0xf4, 0x77, 0xac, 0xe8, 0x03, 0x92, 0x1e, 0x92, 0x78, 0x3e, 0x63, 0xe3,
-	0x4a, 0x49, 0x29, 0x96, 0x5e, 0x94, 0x7c, 0x85, 0xdf, 0x5c, 0x7b, 0x09,
-	0xf7, 0xd7, 0x5b, 0x0f, 0xe3, 0x87, 0x0c, 0xeb, 0x3b, 0xd7, 0x66, 0x51,
-	0xb2, 0x15, 0x93, 0xe3, 0x52, 0x8b, 0x9b, 0x9c, 0x91, 0x63, 0xda, 0x7e,
-	0xce, 0xd8, 0xdc, 0x96, 0xf4, 0x70, 0x41, 0x8c, 0x0d, 0xfd, 0x39, 0xd8,
-	0xd0, 0x9f, 0xad, 0x66, 0xf5, 0x3e, 0xd6, 0xe3, 0xb0, 0xa1, 0x1f, 0x83,
-	0xee, 0xa1, 0xce, 0x49, 0x58, 0x9d, 0x33, 0xa1, 0x0e, 0x68, 0x9d, 0xf3,
-	0xe7, 0x5a, 0xe7, 0xbc, 0x7b, 0x95, 0xce, 0x39, 0xaa, 0x3a, 0x27, 0xa9,
-	0x73, 0x06, 0xd4, 0x7e, 0x87, 0xf6, 0xe2, 0x96, 0x35, 0x74, 0xce, 0x7b,
-	0xe4, 0x1d, 0xf6, 0xdd, 0x3d, 0xf2, 0xde, 0x3d, 0x7a, 0xef, 0xc6, 0x9b,
-	0x51, 0xfc, 0x76, 0x93, 0xd1, 0x41, 0xd7, 0xab, 0x6e, 0xbd, 0xe7, 0xfb,
-	0x95, 0x3a, 0x9d, 0xd3, 0xa1, 0xfa, 0x9c, 0x01, 0xdd, 0x86, 0xb1, 0x09,
-	0x3e, 0x07, 0x4e, 0x76, 0xb8, 0x09, 0xcf, 0x49, 0x89, 0x1d, 0xc7, 0xdc,
-	0xcd, 0xf7, 0xa5, 0x94, 0x79, 0xf7, 0x56, 0xfb, 0x4e, 0x45, 0xe5, 0xae,
-	0x29, 0xef, 0xb4, 0xe5, 0x46, 0x57, 0x75, 0xa8, 0x76, 0xad, 0xab, 0x76,
-	0x83, 0xa1, 0x66, 0xa0, 0x5f, 0x67, 0xca, 0x91, 0xce, 0xe2, 0x6f, 0xc6,
-	0x9e, 0x19, 0xa3, 0x88, 0x62, 0xd8, 0x29, 0xd4, 0xc1, 0x55, 0x8e, 0x6c,
-	0x4a, 0xfe, 0x86, 0xaf, 0x80, 0x6b, 0x0e, 0x78, 0xbd, 0x19, 0xfc, 0xf3,
-	0x1f, 0x4a, 0x8c, 0x81, 0xb6, 0xc9, 0x89, 0xa9, 0xfa, 0x77, 0xed, 0xf2,
-	0xae, 0xa9, 0x1d, 0x72, 0xfb, 0xe4, 0xd6, 0xa4, 0x34, 0xef, 0x94, 0x89,
-	0xc9, 0x29, 0x7d, 0xfe, 0x7d, 0xb3, 0xfe, 0x2e, 0x08, 0xbf, 0x97, 0x63,
-	0x64, 0xe4, 0x90, 0x63, 0x64, 0x64, 0x56, 0xd5, 0x6c, 0xd6, 0xa8, 0x4f,
-	0x7e, 0x8b, 0x64, 0x70, 0x32, 0xa9, 0xbf, 0xa5, 0x3a, 0x53, 0xbd, 0x4a,
-	0x7e, 0xfb, 0xa4, 0xba, 0x4b, 0xd5, 0xce, 0xf7, 0x6a, 0x9b, 0x75, 0x76,
-	0x99, 0xcd, 0xfa, 0xbf, 0x64, 0xe1, 0xbd, 0x71, 0xcc, 0x13, 0x34, 0x7c,
-	0xf5, 0xb7, 0xb8, 0x17, 0xda, 0x96, 0x90, 0x17, 0x65, 0x50, 0xe3, 0x8f,
-	0xf2, 0xb4, 0x05, 0x72, 0x70, 0x51, 0xeb, 0xd7, 0x2d, 0xa0, 0x41, 0xca,
-	0xd2, 0x0f, 0xca, 0x0b, 0x5a, 0x9e, 0x6d, 0xb1, 0xb6, 0xeb, 0x3c, 0xbf,
-	0x6d, 0x7d, 0x9c, 0xb6, 0xeb, 0x9f, 0xdb, 0x72, 0x96, 0xa5, 0x93, 0x8b,
-	0x42, 0x7d, 0x97, 0x80, 0x0c, 0xa5, 0x3c, 0x7d, 0xa3, 0xb6, 0xeb, 0x97,
-	0x6c, 0x1f, 0x94, 0x9f, 0x46, 0x76, 0xef, 0x76, 0xe6, 0x6d, 0x19, 0x9f,
-	0xa3, 0x78, 0xba, 0x9f, 0xcd, 0x5b, 0x3e, 0x53, 0xce, 0xe7, 0xf1, 0x7e,
-	0x33, 0xde, 0x93, 0xcf, 0x1e, 0xd7, 0x7c, 0xa6, 0xed, 0x13, 0xa7, 0xd7,
-	0xee, 0x2f, 0x2c, 0xed, 0x0d, 0x14, 0xc8, 0x67, 0xea, 0x84, 0x37, 0x6f,
-	0xe4, 0x01, 0xf3, 0x54, 0x7f, 0x03, 0xba, 0x83, 0x6d, 0x51, 0xfe, 0x70,
-	0x96, 0xbe, 0x2d, 0xfc, 0x9f, 0x8d, 0x78, 0x6e, 0xc3, 0xf3, 0x8c, 0xbc,
-	0xfb, 0x60, 0x5c, 0xcf, 0x7b, 0x02, 0xf3, 0x38, 0x7c, 0x1c, 0x73, 0x72,
-	0x8c, 0xed, 0xec, 0x9e, 0x75, 0xa5, 0xe1, 0x2c, 0xf9, 0x8e, 0x67, 0x6d,
-	0xc2, 0xf0, 0x50, 0x2f, 0xe9, 0x36, 0xed, 0x0d, 0xe9, 0xb3, 0xa5, 0xbb,
-	0x93, 0x31, 0xe0, 0xe4, 0x30, 0xd6, 0x63, 0xa2, 0xe4, 0x7b, 0x39, 0xc7,
-	0x4f, 0x62, 0x9e, 0xb0, 0x01, 0x3b, 0x61, 0x0b, 0x76, 0xc2, 0x0e, 0xec,
-	0x84, 0x1d, 0xb8, 0x49, 0x4e, 0x5d, 0xc3, 0x1c, 0x93, 0xc2, 0x75, 0xf0,
-	0xca, 0xe5, 0xaf, 0x75, 0x9c, 0xbe, 0xf1, 0xe6, 0x41, 0xf8, 0xec, 0xe2,
-	0xa5, 0x87, 0x99, 0x87, 0xbf, 0xe8, 0x35, 0xde, 0x3c, 0x24, 0x9d, 0xfd,
-	0x78, 0xdf, 0xff, 0xa2, 0x74, 0xdd, 0x7c, 0xab, 0xd3, 0x38, 0x3c, 0x08,
-	0x3c, 0x66, 0x9d, 0x74, 0x72, 0xc4, 0x99, 0xc7, 0x38, 0xb9, 0xdd, 0x31,
-	0x61, 0xdc, 0x72, 0x9e, 0xb1, 0x88, 0x9b, 0x3b, 0x63, 0x3d, 0xa9, 0x51,
-	0x27, 0x3d, 0xac, 0x62, 0xe9, 0xe1, 0x41, 0x27, 0xaa, 0xc7, 0x6f, 0xae,
-	0x42, 0xce, 0x00, 0xd6, 0xc3, 0xe5, 0x4f, 0x83, 0x9e, 0x8e, 0x48, 0xf1,
-	0x64, 0x8b, 0xcc, 0x95, 0x3a, 0xbd, 0x9c, 0x4a, 0xe8, 0xdc, 0x12, 0x75,
-	0x0a, 0x44, 0x7f, 0x36, 0x2e, 0x33, 0x93, 0x3b, 0x45, 0x69, 0xdb, 0x7d,
-	0x9b, 0xe4, 0xa6, 0x26, 0xe5, 0x62, 0x9f, 0xb4, 0x2a, 0xf4, 0xcf, 0x6f,
-	0xdc, 0xaa, 0x53, 0xdc, 0x4b, 0x8c, 0x78, 0x61, 0x3b, 0xf9, 0x64, 0x12,
-	0x38, 0x04, 0xdd, 0x32, 0xc6, 0xdb, 0x24, 0x94, 0x7b, 0x1f, 0xd0, 0xf1,
-	0x53, 0xc6, 0x6c, 0xeb, 0xf7, 0x1e, 0xc8, 0x1f, 0xf1, 0x35, 0xf9, 0x63,
-	0xb6, 0xcc, 0x7d, 0x1a, 0x29, 0xb8, 0x8c, 0x11, 0xfb, 0xf8, 0x3d, 0xcd,
-	0xba, 0x4d, 0x32, 0xd1, 0x57, 0xb0, 0x79, 0x1e, 0x7f, 0x9e, 0x64, 0x0e,
-	0x31, 0x71, 0x32, 0xda, 0x47, 0x5e, 0x5f, 0xb9, 0xb7, 0x11, 0xaf, 0x93,
-	0x07, 0x8e, 0x2c, 0x4c, 0x46, 0x7b, 0x21, 0xec, 0x0f, 0xcf, 0xd3, 0x46,
-	0xde, 0xe6, 0x56, 0xb5, 0x23, 0x5c, 0xdc, 0xaf, 0x5c, 0x2e, 0x63, 0x95,
-	0x4f, 0x99, 0xea, 0x69, 0xf9, 0x7a, 0xa6, 0x6a, 0x64, 0xeb, 0x74, 0x35,
-	0xd2, 0x2d, 0x71, 0xa3, 0x4b, 0x57, 0xe9, 0x13, 0x13, 0xcd, 0xac, 0xe9,
-	0x13, 0xea, 0x45, 0x25, 0xef, 0x9b, 0xdb, 0x26, 0xee, 0xc3, 0xb2, 0x38,
-	0xe1, 0x7f, 0x7a, 0x3b, 0x73, 0x35, 0x26, 0x82, 0x37, 0xa3, 0x1f, 0x9b,
-	0xae, 0xa4, 0x3e, 0x1c, 0x51, 0x8d, 0xb8, 0x6f, 0xd6, 0xf4, 0x07, 0x9e,
-	0xc2, 0xb3, 0xf1, 0x13, 0x3e, 0x07, 0x3f, 0xe1, 0xb3, 0xd0, 0x75, 0xe7,
-	0xe1, 0x27, 0x3c, 0x01, 0x3f, 0xe1, 0x71, 0xf8, 0x09, 0x8f, 0x41, 0x4f,
-	0xd6, 0xfb, 0x07, 0xe3, 0xcb, 0xfc, 0x83, 0x50, 0xf3, 0x3f, 0xe3, 0x81,
-	0x4f, 0xd4, 0xf9, 0x06, 0x87, 0x8c, 0xbe, 0x82, 0xdf, 0x6f, 0xf8, 0xa8,
-	0x43, 0xdd, 0xa4, 0xf5, 0xa3, 0xc9, 0xdb, 0x1d, 0x5e, 0xd2, 0x57, 0x1d,
-	0xca, 0xe8, 0xab, 0x99, 0x9a, 0xbe, 0x32, 0x7c, 0xf4, 0xf0, 0xa4, 0xc4,
-	0xfc, 0xc9, 0xf9, 0x5c, 0xb0, 0x57, 0xf3, 0x50, 0xab, 0xbf, 0x53, 0x62,
-	0x0f, 0xa8, 0xb6, 0x06, 0xc9, 0xd9, 0x67, 0xd0, 0xd7, 0x89, 0x4f, 0xa3,
-	0xaf, 0xeb, 0x24, 0xaf, 0xed, 0xb3, 0xcb, 0xe3, 0xfb, 0xb1, 0x15, 0xf8,
-	0x2e, 0x96, 0x27, 0x34, 0xce, 0xef, 0xaf, 0x70, 0x9f, 0xa5, 0x45, 0xc6,
-	0x2b, 0x11, 0xce, 0x79, 0x9e, 0x95, 0xb9, 0x18, 0xed, 0x12, 0x7b, 0x78,
-	0x1b, 0xcf, 0x59, 0xa9, 0x7c, 0xb0, 0x5e, 0xe7, 0xb0, 0x9c, 0xea, 0x93,
-	0x64, 0xbe, 0x8f, 0xb4, 0x7a, 0x9f, 0xcc, 0xe8, 0xb5, 0xd8, 0x26, 0x0d,
-	0x0f, 0xd3, 0x46, 0x89, 0xf6, 0xf3, 0xde, 0x7f, 0xa5, 0xfd, 0xe6, 0x6a,
-	0xdc, 0xd4, 0x13, 0x39, 0xa2, 0xd7, 0x6b, 0x5a, 0xe7, 0x19, 0xde, 0x34,
-	0xc7, 0xb8, 0x3c, 0xbf, 0x6f, 0xc5, 0x98, 0xfc, 0xbf, 0x66, 0xfd, 0x7e,
-	0xf9, 0x4a, 0x63, 0xcf, 0x6c, 0xb6, 0x76, 0x8c, 0x89, 0x53, 0xad, 0x6d,
-	0xc3, 0xb0, 0x9f, 0xfa, 0x6f, 0x32, 0xee, 0x70, 0xc6, 0x27, 0x77, 0x3a,
-	0xc5, 0x49, 0xee, 0x65, 0xdb, 0xbf, 0xd1, 0xe1, 0xed, 0x77, 0x0e, 0xfb,
-	0x3b, 0x50, 0xc6, 0x98, 0x25, 0x63, 0x36, 0xf7, 0x5f, 0xc9, 0x18, 0x6d,
-	0xce, 0xe7, 0xd8, 0x2c, 0xdb, 0xe1, 0x4c, 0x4c, 0x76, 0xc2, 0x37, 0xe7,
-	0xb9, 0x2a, 0xbe, 0x1f, 0xe2, 0xda, 0x41, 0x07, 0x7b, 0xfa, 0xcc, 0xee,
-	0x98, 0x5c, 0x65, 0x63, 0xd0, 0xd4, 0xc3, 0x3f, 0xbd, 0x6c, 0xef, 0xf6,
-	0x28, 0xf4, 0xd8, 0x2d, 0x90, 0x47, 0xd4, 0xc3, 0x47, 0xe5, 0x6d, 0x96,
-	0x9e, 0x97, 0xeb, 0xe1, 0x4b, 0xc2, 0x38, 0x71, 0x2f, 0xde, 0x15, 0xc2,
-	0x38, 0xe8, 0xe1, 0x58, 0x9d, 0xaf, 0x46, 0xbf, 0xaf, 0x29, 0x63, 0xf6,
-	0xc3, 0x96, 0xfb, 0x7d, 0x90, 0x03, 0x89, 0xc8, 0xcf, 0x6b, 0x5c, 0xda,
-	0xaf, 0xdd, 0x6f, 0xdb, 0x4e, 0x04, 0x7f, 0x44, 0x1c, 0xa5, 0x8e, 0xca,
-	0x2f, 0x42, 0xa7, 0x31, 0x07, 0xe4, 0x2f, 0x34, 0xce, 0x44, 0x91, 0xf6,
-	0x36, 0x6b, 0x18, 0xad, 0x9c, 0x4f, 0x45, 0x39, 0x1c, 0x45, 0xdb, 0x76,
-	0xcc, 0xee, 0xc9, 0x17, 0xe5, 0xeb, 0x8c, 0x73, 0xa6, 0x06, 0x63, 0xeb,
-	0xf9, 0x3d, 0x46, 0xb4, 0xfd, 0x45, 0xed, 0xb7, 0x67, 0x25, 0xea, 0x8b,
-	0xcf, 0x0d, 0x75, 0x7d, 0xd3, 0x8e, 0xe2, 0x7d, 0xe5, 0x39, 0xb2, 0xa7,
-	0xf5, 0x3e, 0xa3, 0xf9, 0x5e, 0x42, 0xc4, 0x27, 0xe4, 0x9d, 0x94, 0x3e,
-	0xeb, 0xe4, 0x3f, 0x4c, 0xbb, 0x87, 0x7b, 0xb0, 0xde, 0xfc, 0x78, 0xf0,
-	0x11, 0xfd, 0xcd, 0xc0, 0x69, 0x11, 0xa7, 0x18, 0xdc, 0xa6, 0x73, 0x4f,
-	0x8a, 0x3a, 0xd6, 0x5c, 0xc0, 0xbd, 0xe6, 0xa3, 0x76, 0x3c, 0xcc, 0xbf,
-	0xc3, 0xc1, 0xb2, 0x3c, 0x60, 0xa3, 0x0e, 0xa1, 0xec, 0x4d, 0x48, 0xc7,
-	0x89, 0x5f, 0xd0, 0xbc, 0xb0, 0x05, 0xbe, 0xc0, 0xc0, 0x09, 0xe8, 0xea,
-	0x13, 0x49, 0x19, 0x3a, 0xa1, 0x75, 0x63, 0x76, 0x75, 0xac, 0xa0, 0xc7,
-	0x73, 0x9d, 0x77, 0xe9, 0x73, 0x6c, 0x6f, 0x3d, 0x11, 0x93, 0x63, 0x89,
-	0x1e, 0xaf, 0xcb, 0x79, 0xb7, 0xd5, 0x85, 0x51, 0x0c, 0xbb, 0x05, 0xed,
-	0x5f, 0x2f, 0x8e, 0x1d, 0xc5, 0xaf, 0x63, 0x32, 0x7d, 0xb0, 0x1d, 0xb0,
-	0x75, 0x6e, 0x33, 0x67, 0x90, 0xb1, 0x56, 0xfa, 0x1b, 0xf7, 0x6e, 0x92,
-	0xb2, 0xac, 0x03, 0xb0, 0x0c, 0x9e, 0xa0, 0x3e, 0xf3, 0x35, 0x8f, 0x03,
-	0x06, 0xaf, 0x41, 0xfb, 0x21, 0xe4, 0xcb, 0xb7, 0x88, 0xff, 0x00, 0x64,
-	0xdc, 0x89, 0xb8, 0x74, 0x9d, 0x68, 0x91, 0x5d, 0x27, 0xe8, 0x87, 0xd4,
-	0xfb, 0xa5, 0xb4, 0x4b, 0xe7, 0x30, 0xc7, 0x77, 0x6a, 0x39, 0xc9, 0x3d,
-	0xcd, 0xdb, 0xc9, 0xbb, 0xa8, 0x9b, 0x87, 0xcd, 0x9c, 0x3b, 0xe1, 0xe9,
-	0x3d, 0xd2, 0x1c, 0xe6, 0x9c, 0xaf, 0x78, 0x18, 0xc7, 0xc8, 0x9c, 0x22,
-	0xfd, 0x94, 0xe1, 0x6d, 0xc0, 0xf1, 0x31, 0xcb, 0x3b, 0x43, 0xdb, 0x2c,
-	0x8f, 0xfe, 0x88, 0xbc, 0x77, 0xf3, 0x36, 0x23, 0x3b, 0x7f, 0x76, 0x1b,
-	0x73, 0x93, 0xb6, 0xf8, 0xbc, 0x37, 0x69, 0x7b, 0xc2, 0xc8, 0xd0, 0xd7,
-	0xe2, 0x45, 0x01, 0x8e, 0xa2, 0x7d, 0x29, 0x7d, 0x96, 0x2f, 0xbc, 0x18,
-	0xe8, 0xf3, 0x2b, 0xc1, 0x02, 0xf3, 0x08, 0xf5, 0x77, 0x14, 0x6a, 0xdf,
-	0x5b, 0xd9, 0x5b, 0x65, 0x9c, 0xfc, 0x89, 0xe8, 0x6f, 0xa9, 0xd4, 0xe5,
-	0x1d, 0xd6, 0xef, 0x81, 0x31, 0xd6, 0xb4, 0x94, 0x1b, 0x14, 0x4e, 0xea,
-	0xef, 0x21, 0x3d, 0xeb, 0x5c, 0x2a, 0x5d, 0x70, 0xbe, 0x39, 0x25, 0xa1,
-	0xeb, 0x7f, 0xdf, 0xf9, 0xb6, 0xcf, 0x3d, 0xf3, 0x2f, 0x3b, 0xdf, 0x2a,
-	0xf9, 0xe0, 0xc3, 0x0b, 0x98, 0xc7, 0x2b, 0xce, 0x77, 0xb0, 0xbe, 0x47,
-	0xca, 0xd9, 0xb4, 0x67, 0x63, 0xe2, 0x17, 0x4a, 0xaf, 0x38, 0x5f, 0xaa,
-	0xc5, 0x93, 0xfa, 0x23, 0x1a, 0x39, 0xca, 0x77, 0x15, 0xbc, 0xab, 0xe8,
-	0xfd, 0x1f, 0x67, 0x76, 0xca, 0xe6, 0x97, 0x68, 0x3e, 0x9e, 0x5f, 0xda,
-	0x97, 0x19, 0xd6, 0x7b, 0x15, 0xcf, 0x38, 0xb3, 0x73, 0x9f, 0xdb, 0x66,
-	0xf2, 0x8c, 0x2e, 0xe0, 0x9d, 0xc9, 0xb9, 0x9c, 0x99, 0xbb, 0x80, 0x3a,
-	0x4f, 0x3b, 0x33, 0x3a, 0xfe, 0xc5, 0x76, 0x17, 0x9c, 0xe9, 0xb9, 0xa7,
-	0x9d, 0x39, 0xbd, 0x07, 0x7d, 0xd1, 0x79, 0x74, 0x8a, 0x7d, 0x5f, 0x44,
-	0x9d, 0x79, 0xe7, 0x14, 0xfa, 0x9b, 0x9b, 0xe2, 0x79, 0xdc, 0x4e, 0xd8,
-	0x05, 0xfc, 0x1b, 0x45, 0xfc, 0x1e, 0xc7, 0x33, 0xce, 0xdc, 0x52, 0xbf,
-	0x0b, 0xe8, 0x87, 0x75, 0x49, 0x8b, 0x1c, 0xf7, 0x19, 0xf4, 0xbf, 0x7a,
-	0xaf, 0x6a, 0x35, 0x4e, 0x9e, 0x07, 0x4e, 0x5e, 0xb4, 0x38, 0x79, 0xd5,
-	0xe2, 0xe4, 0xb9, 0x3a, 0x9c, 0x88, 0x5a, 0x8e, 0x93, 0x57, 0x81, 0x13,
-	0x51, 0x6b, 0xe3, 0x04, 0xef, 0x2a, 0x78, 0xa7, 0x71, 0xf2, 0xd2, 0x0a,
-	0x9c, 0x2c, 0x2e, 0xc5, 0xe5, 0x0d, 0x4e, 0x5e, 0x00, 0x4e, 0x7e, 0x60,
-	0x61, 0x7f, 0xd1, 0xe2, 0x04, 0xf7, 0xb9, 0x17, 0x51, 0xe7, 0xa5, 0x3a,
-	0x9c, 0xbc, 0x08, 0x9c, 0xbc, 0x64, 0x71, 0xf2, 0x6d, 0x8b, 0x93, 0x6f,
-	0xa3, 0xce, 0x22, 0x70, 0x72, 0x69, 0x0d, 0x9c, 0xbc, 0x00, 0x9c, 0x44,
-	0xfd, 0x5e, 0x42, 0x3f, 0xdf, 0xae, 0xc3, 0xc9, 0x0b, 0x6b, 0xe0, 0x84,
-	0x7b, 0xb1, 0x51, 0x4e, 0xf7, 0x99, 0xd7, 0xc9, 0xe9, 0x5e, 0x7c, 0x03,
-	0x39, 0xdd, 0xac, 0x73, 0x46, 0x6a, 0x7f, 0xbb, 0x62, 0xc2, 0xe6, 0xa8,
-	0x99, 0x5c, 0xc0, 0xda, 0x37, 0x9b, 0x3a, 0xc1, 0xe7, 0xc5, 0x02, 0xbc,
-	0x11, 0x9d, 0x53, 0xea, 0xee, 0x19, 0x03, 0xaf, 0xbd, 0x5b, 0x0e, 0x9f,
-	0x6c, 0x3c, 0x96, 0xb7, 0x65, 0xfe, 0x9e, 0xce, 0x82, 0x52, 0x7c, 0x17,
-	0xe5, 0x24, 0xd0, 0x2f, 0x69, 0xe0, 0xb7, 0x0a, 0xbb, 0xb3, 0x52, 0xbf,
-	0x27, 0x3d, 0xc5, 0x6f, 0x34, 0x71, 0x7f, 0x8c, 0x7f, 0x67, 0x23, 0xc5,
-	0x3c, 0xab, 0xa2, 0x86, 0x37, 0x0d, 0xfd, 0xd1, 0xaf, 0x73, 0xab, 0xf8,
-	0x37, 0x82, 0x62, 0xf0, 0xfb, 0x47, 0xfb, 0x68, 0x2b, 0x67, 0xec, 0x99,
-	0xb0, 0x40, 0x9f, 0x53, 0xa9, 0xf1, 0x4f, 0xfd, 0x79, 0x68, 0xf2, 0x5d,
-	0x8d, 0x6e, 0x8e, 0x2c, 0x7d, 0x77, 0xf0, 0xb4, 0x3c, 0xa5, 0x63, 0xc5,
-	0xcd, 0xfa, 0xef, 0x2b, 0x9c, 0x09, 0x4c, 0x8c, 0x76, 0x41, 0xc7, 0x68,
-	0x05, 0xde, 0xf8, 0xb8, 0x8d, 0xd3, 0x76, 0xf5, 0xbf, 0xb4, 0x14, 0xa3,
-	0xad, 0xcf, 0x67, 0x31, 0xfb, 0xeb, 0xb9, 0xc9, 0x39, 0x9d, 0xa3, 0x33,
-	0xc8, 0xef, 0x6f, 0x40, 0x46, 0x8c, 0x4d, 0x57, 0x64, 0xfc, 0x41, 0x3e,
-	0x53, 0xbf, 0xc5, 0xa0, 0xc3, 0x28, 0xc3, 0x0b, 0x92, 0xeb, 0x67, 0x99,
-	0x69, 0x33, 0xa8, 0xfd, 0xe5, 0xd3, 0x32, 0xb0, 0x34, 0x3e, 0xf1, 0xfb,
-	0x89, 0xba, 0xef, 0x60, 0xd3, 0xe6, 0xc9, 0x3a, 0xb9, 0x2a, 0xdf, 0x47,
-	0x7b, 0xe4, 0x9f, 0xb0, 0xdf, 0x0a, 0xe4, 0xfb, 0xfa, 0x6f, 0xbf, 0x6a,
-	0xd1, 0x81, 0xdf, 0xfc, 0xbe, 0xda, 0x84, 0x33, 0x88, 0x36, 0xf3, 0x5e,
-	0xcb, 0xb0, 0xca, 0xdc, 0x38, 0xcc, 0x73, 0x73, 0x33, 0xab, 0xbe, 0x9d,
-	0x5d, 0xd3, 0x8b, 0x45, 0xbd, 0xa6, 0xcc, 0xcf, 0x2a, 0x80, 0x16, 0x35,
-	0x6d, 0x69, 0xfa, 0x3f, 0xbc, 0xa4, 0x2f, 0xa9, 0x67, 0xcd, 0xb7, 0x67,
-	0x8c, 0xbe, 0x4c, 0x27, 0x07, 0x31, 0xbe, 0xfe, 0x1b, 0x0d, 0xf6, 0x5c,
-	0x6f, 0x7e, 0xee, 0x2e, 0xad, 0xeb, 0x27, 0x82, 0x6c, 0xca, 0x95, 0x35,
-	0xea, 0x4e, 0xd6, 0xd5, 0xd5, 0xf3, 0xf6, 0xe4, 0xb7, 0xb0, 0x36, 0xbf,
-	0x51, 0xae, 0xc8, 0xc0, 0xd4, 0x5f, 0xc1, 0x7f, 0x4c, 0xca, 0x6f, 0x96,
-	0x1f, 0x01, 0xbd, 0x16, 0xb6, 0xd8, 0x6f, 0x35, 0xe5, 0x00, 0x37, 0xbf,
-	0xbd, 0xa2, 0xf3, 0x89, 0x63, 0xbf, 0x0d, 0xba, 0xf8, 0xcc, 0x23, 0x1c,
-	0x03, 0xb0, 0xc4, 0x60, 0xdb, 0xc3, 0x4e, 0x98, 0x7e, 0x44, 0xe7, 0xce,
-	0x5d, 0x5f, 0x79, 0x44, 0xc7, 0x2c, 0x86, 0x2a, 0xed, 0xb2, 0xb7, 0xd2,
-	0x22, 0xfb, 0xa0, 0x17, 0xf6, 0x55, 0x7c, 0x5c, 0x71, 0x79, 0x67, 0xc5,
-	0xac, 0xd3, 0x07, 0x2b, 0x5c, 0xef, 0x3d, 0x32, 0x73, 0x72, 0xe5, 0xf7,
-	0x3e, 0xe7, 0x0b, 0xd1, 0xdf, 0x73, 0x52, 0x8a, 0xf9, 0x65, 0xa4, 0x25,
-	0x5c, 0xe5, 0xf4, 0xb1, 0x79, 0x8d, 0x07, 0x66, 0xb8, 0xa6, 0x27, 0x17,
-	0x85, 0x79, 0xfa, 0xfc, 0x1b, 0x4e, 0x7f, 0xb9, 0x9d, 0xe7, 0xa6, 0xf9,
-	0x2d, 0xaf, 0xa1, 0x6a, 0x94, 0x37, 0xbe, 0x56, 0xce, 0x38, 0xec, 0xfc,
-	0x3d, 0x51, 0x8e, 0x5f, 0x9c, 0x39, 0xe3, 0xd2, 0x71, 0xb6, 0x05, 0xf7,
-	0xef, 0x6e, 0xd7, 0x67, 0x9b, 0xcf, 0x8a, 0x2d, 0xd3, 0xf9, 0xe4, 0x78,
-	0x5e, 0xf9, 0xbd, 0xb6, 0x88, 0x1f, 0x6a, 0x7f, 0xf7, 0x40, 0xe4, 0xff,
-	0x02, 0x06, 0x86, 0xe5, 0x0a, 0xd4, 0x6f, 0x00, 0x00, 0x00 };
+	0xad, 0xbc, 0x0f, 0x74, 0x53, 0xd7, 0x95, 0x2e, 0xfe, 0xdd, 0x2b, 0xc9,
+	0x96, 0x6d, 0xd9, 0x96, 0x8d, 0x70, 0xe4, 0xc4, 0x0d, 0x52, 0x7c, 0x05,
+	0x0a, 0x36, 0xe9, 0x95, 0x11, 0x89, 0xd3, 0x77, 0x13, 0x54, 0x70, 0x82,
+	0x49, 0x68, 0xe2, 0x10, 0xa6, 0x75, 0x67, 0x98, 0xa9, 0x1e, 0x21, 0x09,
+	0x49, 0x99, 0x3c, 0xb7, 0xaf, 0xed, 0x23, 0xf9, 0xd1, 0xf1, 0xad, 0xcd,
+	0x1f, 0x03, 0x92, 0x25, 0x1b, 0xf3, 0x27, 0x6f, 0xba, 0x5e, 0x84, 0x31,
+	0x18, 0x12, 0xd9, 0x4e, 0xda, 0x4c, 0x87, 0xbc, 0xd5, 0x79, 0x78, 0x0c,
+	0x24, 0x90, 0x34, 0x7f, 0x9a, 0xb4, 0xab, 0x69, 0xa7, 0x6f, 0xe2, 0x12,
+	0x92, 0x92, 0x7f, 0x94, 0x34, 0x9d, 0x0e, 0x74, 0x86, 0xde, 0xdf, 0xb7,
+	0xaf, 0x24, 0x30, 0x94, 0xa4, 0xed, 0x5a, 0xcf, 0x6b, 0x69, 0x49, 0xf7,
+	0xde, 0x73, 0xf6, 0x39, 0x67, 0x9f, 0xbd, 0xbf, 0xfd, 0xed, 0x73, 0xce,
+	0xf5, 0xa7, 0x80, 0x52, 0xe4, 0xff, 0xca, 0xf9, 0xb9, 0x2e, 0xda, 0x71,
+	0x0f, 0xe6, 0x5d, 0xa7, 0xcb, 0xb5, 0xd3, 0x05, 0x27, 0xfe, 0xc4, 0xbf,
+	0xc0, 0x9f, 0x5a, 0x30, 0xff, 0xe7, 0x00, 0xbc, 0x85, 0x36, 0xe5, 0x03,
+	0xb7, 0x6a, 0xac, 0xfb, 0xe2, 0x02, 0x0d, 0x6e, 0x87, 0x11, 0x5d, 0x7e,
+	0x8f, 0x06, 0xc4, 0xb2, 0x0d, 0x81, 0x85, 0x38, 0x67, 0x99, 0x3e, 0x27,
+	0xe4, 0xfe, 0xa7, 0x8c, 0xff, 0x7c, 0xec, 0x9f, 0x6e, 0x08, 0x9e, 0xce,
+	0x38, 0xe0, 0xf6, 0x1a, 0x5f, 0x83, 0x77, 0x26, 0xdc, 0x75, 0xac, 0xf3,
+	0xed, 0x59, 0xb3, 0x55, 0x54, 0x14, 0x64, 0x05, 0xfd, 0x19, 0x04, 0xbd,
+	0x26, 0x82, 0x61, 0x13, 0x88, 0x3b, 0x0d, 0xc4, 0x8b, 0x0d, 0x37, 0x8a,
+	0xb4, 0x22, 0xc4, 0xbd, 0x6b, 0x02, 0xeb, 0xa2, 0xc0, 0x82, 0x84, 0x3b,
+	0x70, 0x3c, 0x0b, 0xdc, 0x93, 0x70, 0x63, 0xd2, 0xe1, 0x09, 0xbc, 0x99,
+	0xbd, 0xb9, 0x32, 0xa7, 0x83, 0x18, 0x1c, 0x1a, 0xe2, 0xaa, 0x21, 0xf7,
+	0x11, 0x58, 0x98, 0x8d, 0x62, 0x7d, 0xca, 0xb2, 0x9c, 0x1a, 0x9c, 0x83,
+	0x8d, 0x0e, 0xc4, 0xbc, 0x0a, 0x76, 0x6b, 0x51, 0x74, 0x8f, 0x05, 0x39,
+	0x58, 0x29, 0x23, 0xed, 0xfc, 0xe6, 0xdc, 0xc6, 0xd4, 0x49, 0xeb, 0x9f,
+	0x66, 0x79, 0xf1, 0xe4, 0x98, 0x0f, 0x07, 0xc7, 0x82, 0xa6, 0x89, 0x2a,
+	0x9c, 0x48, 0x37, 0xe2, 0xa4, 0x56, 0x87, 0x37, 0x35, 0x0b, 0xeb, 0xf5,
+	0x30, 0x54, 0x2d, 0xa8, 0x43, 0xf1, 0x63, 0xd0, 0x1b, 0x0c, 0xc4, 0xc1,
+	0x4e, 0x54, 0x04, 0xc3, 0xe3, 0xac, 0x9b, 0x4a, 0x21, 0x5e, 0x64, 0x38,
+	0x51, 0xa2, 0xdd, 0x8c, 0x53, 0xdb, 0x0c, 0x7c, 0xb0, 0x0d, 0xcb, 0x2b,
+	0x60, 0x59, 0xd9, 0x48, 0xa8, 0x6d, 0xb5, 0xe2, 0x0d, 0x3c, 0x9f, 0x45,
+	0xe0, 0x58, 0x76, 0xaa, 0xde, 0x38, 0x21, 0xd5, 0x6c, 0x27, 0x15, 0xc5,
+	0x4e, 0xf6, 0xcd, 0x3b, 0x2b, 0x8a, 0xf4, 0x18, 0xdb, 0x4e, 0x49, 0x7f,
+	0xfc, 0xf8, 0xa7, 0x59, 0x7f, 0xcd, 0xf9, 0x64, 0x5b, 0x94, 0xbd, 0x21,
+	0xf5, 0x3a, 0xfb, 0x55, 0x87, 0xef, 0x8e, 0xf9, 0xf1, 0x1d, 0xf6, 0xed,
+	0x29, 0x29, 0x37, 0x16, 0x60, 0x1f, 0xab, 0x70, 0x84, 0xfd, 0xfb, 0x21,
+	0xfb, 0xf7, 0x0a, 0xfb, 0xb7, 0x9b, 0xfd, 0x5b, 0xd1, 0x1c, 0xdc, 0x69,
+	0x42, 0xc1, 0xd2, 0xc6, 0x36, 0xe9, 0x1b, 0xc7, 0xc7, 0x8f, 0xaa, 0x22,
+	0x56, 0x1d, 0x0c, 0x07, 0xd4, 0x60, 0x18, 0x76, 0x9f, 0xa5, 0xfd, 0xdf,
+	0x9c, 0x4b, 0xa6, 0x60, 0xba, 0xa9, 0x57, 0x97, 0x71, 0x33, 0xb2, 0xec,
+	0xf3, 0x13, 0xdb, 0x42, 0xcd, 0xab, 0x54, 0x2c, 0xf1, 0xb0, 0xdf, 0x0f,
+	0x46, 0x42, 0x81, 0xd9, 0xec, 0xf7, 0x50, 0x56, 0x55, 0x55, 0xcd, 0x17,
+	0x18, 0xce, 0x2a, 0x88, 0x2d, 0x55, 0x39, 0x7e, 0xb6, 0x9b, 0x62, 0x5f,
+	0x52, 0xec, 0x4b, 0x8a, 0x7d, 0x49, 0x49, 0x9f, 0xc3, 0xec, 0x6f, 0x4e,
+	0xd7, 0x83, 0xd9, 0xcb, 0xf5, 0x35, 0xd8, 0xc3, 0xb9, 0xa4, 0x3e, 0xa5,
+	0xcf, 0x96, 0xf5, 0xaa, 0xbe, 0x88, 0x7d, 0xb0, 0xac, 0x8f, 0x74, 0xe9,
+	0x9b, 0xf4, 0xab, 0x1c, 0x31, 0x5f, 0x8a, 0x73, 0x56, 0xe8, 0x1b, 0x8c,
+	0x6a, 0xcc, 0x30, 0x5d, 0x86, 0xcc, 0xbb, 0xca, 0xfb, 0x21, 0xfd, 0x23,
+	0xc0, 0x1a, 0x8c, 0x7a, 0x03, 0x1b, 0xb2, 0xbe, 0x40, 0x17, 0x75, 0xd9,
+	0x9d, 0x0d, 0xfa, 0xc5, 0x56, 0xff, 0xb0, 0x2f, 0x41, 0x6f, 0xdc, 0x9e,
+	0x53, 0xe9, 0xd3, 0x64, 0x7e, 0x3e, 0x2d, 0xeb, 0x15, 0xdd, 0xcf, 0xb6,
+	0xa5, 0x3f, 0x51, 0xbb, 0xed, 0x0f, 0x75, 0x44, 0xbd, 0x10, 0xbb, 0x08,
+	0x99, 0x3f, 0xb4, 0xed, 0xcb, 0x1b, 0x48, 0x67, 0x59, 0xe6, 0xbc, 0x1c,
+	0x27, 0xc7, 0x0a, 0xb6, 0x65, 0x59, 0xbb, 0xb5, 0xa0, 0x57, 0xda, 0xca,
+	0x8d, 0x51, 0xec, 0x46, 0xec, 0xc4, 0x1f, 0xf7, 0x18, 0x5e, 0xca, 0x44,
+	0xdb, 0xce, 0x64, 0xa7, 0x55, 0xab, 0x89, 0x2e, 0xb5, 0x35, 0xb5, 0x0e,
+	0x4f, 0xf3, 0xa9, 0x79, 0x5f, 0x31, 0xcb, 0xa3, 0x11, 0x94, 0x6a, 0xf0,
+	0x94, 0x68, 0x68, 0xeb, 0x1d, 0x29, 0x35, 0xcb, 0x8c, 0xef, 0xdf, 0x9d,
+	0x1c, 0x71, 0xa3, 0x74, 0x44, 0x43, 0xc9, 0x48, 0xc8, 0x89, 0x0a, 0x03,
+	0x5b, 0xc6, 0xde, 0x71, 0xe4, 0xc6, 0xbb, 0xb0, 0x30, 0x6e, 0xb1, 0x71,
+	0xf7, 0x5b, 0x89, 0xd3, 0x56, 0x91, 0x56, 0xf2, 0x05, 0x87, 0xa1, 0x05,
+	0xf6, 0x02, 0xa7, 0x57, 0x44, 0xfd, 0xe8, 0xa2, 0xcd, 0xce, 0xd0, 0x7e,
+	0xe2, 0x41, 0x45, 0x2b, 0xcc, 0xb1, 0x1a, 0xf1, 0x07, 0xac, 0x4f, 0x58,
+	0x56, 0x91, 0x71, 0xf7, 0xdd, 0x2c, 0xe7, 0xdd, 0x8b, 0x5a, 0x2c, 0xf4,
+	0x62, 0xed, 0xfa, 0xe8, 0xaf, 0x95, 0x7d, 0x03, 0xcb, 0x61, 0x0e, 0xaf,
+	0xe6, 0x47, 0x05, 0xaa, 0xae, 0xbe, 0xda, 0x71, 0xe3, 0x72, 0x74, 0x0f,
+	0xb3, 0xaf, 0xa9, 0x18, 0xed, 0x53, 0x6c, 0x6b, 0x35, 0x36, 0x0d, 0x3f,
+	0x04, 0x73, 0xf7, 0x4a, 0x96, 0x91, 0x31, 0x75, 0xf1, 0xbb, 0x15, 0x8f,
+	0x8d, 0x89, 0x7c, 0xe9, 0xc6, 0xe5, 0xe4, 0xbf, 0x63, 0x2d, 0xf4, 0x89,
+	0x7c, 0x27, 0x36, 0x26, 0xec, 0x79, 0x51, 0x68, 0x9f, 0xe1, 0x13, 0xb4,
+	0x95, 0x6e, 0xdd, 0x40, 0x4f, 0xaa, 0x19, 0x1b, 0x53, 0xb1, 0x20, 0xd1,
+	0x80, 0xf3, 0xd6, 0x06, 0xd5, 0x08, 0xb5, 0x76, 0x41, 0x7c, 0x02, 0x4a,
+	0xa9, 0x01, 0x67, 0x36, 0x3a, 0xe9, 0x7e, 0x31, 0xa1, 0xb5, 0x3f, 0xae,
+	0xb8, 0x10, 0xaf, 0x92, 0x36, 0x26, 0xdd, 0x2f, 0x27, 0x14, 0xfc, 0x52,
+	0x0b, 0x75, 0xbc, 0xab, 0x4c, 0xba, 0x5f, 0xca, 0x7a, 0x51, 0x9b, 0x0c,
+	0xb6, 0x9b, 0x4a, 0x33, 0x9e, 0xc9, 0xfa, 0xe0, 0x4f, 0x1a, 0x38, 0x90,
+	0xd5, 0xb1, 0xff, 0x22, 0x9f, 0xb9, 0xec, 0x9f, 0xe9, 0x60, 0x5f, 0x57,
+	0x26, 0x02, 0xe8, 0xd2, 0xcf, 0x59, 0x31, 0x2f, 0xe2, 0x95, 0xc6, 0xa4,
+	0xfb, 0x83, 0x24, 0x94, 0x0a, 0x43, 0xf3, 0x8f, 0x2a, 0xbf, 0xb0, 0xe2,
+	0x3e, 0x29, 0xc6, 0xfe, 0x8d, 0xc9, 0x58, 0x97, 0x50, 0xef, 0x06, 0xe7,
+	0xfd, 0xb4, 0x55, 0xc6, 0x39, 0x2b, 0x32, 0xae, 0xc4, 0xf0, 0x80, 0x86,
+	0xfd, 0x1c, 0xeb, 0xfb, 0xfa, 0x78, 0xb3, 0x07, 0x5a, 0xdb, 0x7b, 0x08,
+	0xc6, 0x66, 0x2b, 0x06, 0x8e, 0x66, 0x35, 0x0c, 0x25, 0x0c, 0x1c, 0x4a,
+	0xd4, 0x7b, 0xbb, 0x31, 0x17, 0x31, 0x7f, 0x0e, 0x1f, 0x47, 0xd8, 0xef,
+	0xc1, 0x50, 0x1b, 0x2a, 0x8d, 0x66, 0x4c, 0xb0, 0xdf, 0xa7, 0xe6, 0x89,
+	0x1c, 0x1d, 0x2f, 0xfd, 0x09, 0x7d, 0x15, 0xbd, 0x3e, 0xca, 0xbe, 0x36,
+	0xcf, 0x3d, 0x67, 0x61, 0x9a, 0x1b, 0xc7, 0xf5, 0x2b, 0x88, 0x47, 0x30,
+	0x4b, 0x0c, 0xb7, 0xb3, 0x27, 0xe1, 0xc5, 0xbe, 0xac, 0xc7, 0xd9, 0x9d,
+	0xf0, 0x61, 0x77, 0x36, 0x80, 0x5a, 0x03, 0xa6, 0x9f, 0x72, 0x6b, 0xe9,
+	0x4b, 0xa3, 0x03, 0x75, 0x18, 0x1b, 0x08, 0xea, 0x2f, 0x13, 0x7b, 0xf6,
+	0x0e, 0x5d, 0x89, 0x91, 0x01, 0x05, 0xc3, 0x21, 0xf6, 0x9d, 0xbf, 0x9f,
+	0x18, 0xb8, 0x1a, 0xd9, 0x01, 0x07, 0xb6, 0xd8, 0x7a, 0xb5, 0xfd, 0x30,
+	0xff, 0x7d, 0x25, 0x32, 0x43, 0x70, 0xce, 0x4e, 0x7a, 0xf1, 0x78, 0xd6,
+	0xe9, 0xd4, 0x92, 0x3e, 0x0c, 0x65, 0xbf, 0xce, 0x79, 0x13, 0xd9, 0x01,
+	0x0c, 0x26, 0xfe, 0x9a, 0xbf, 0x65, 0x1c, 0xb7, 0x2b, 0xf9, 0xd8, 0x41,
+	0xcc, 0x0e, 0x10, 0x4f, 0x5b, 0xd0, 0x95, 0x72, 0x60, 0x85, 0x8d, 0xeb,
+	0x29, 0x3e, 0x6b, 0xa1, 0xcd, 0x17, 0xe4, 0x0a, 0xbe, 0x07, 0x88, 0xbd,
+	0x47, 0xe9, 0x03, 0x51, 0xda, 0xbf, 0x8e, 0xff, 0x33, 0xd6, 0x88, 0x7f,
+	0x1c, 0x0b, 0xe3, 0x7b, 0x63, 0x1a, 0xfe, 0x81, 0xb8, 0xf4, 0xf4, 0xd8,
+	0x54, 0xff, 0xbf, 0x9b, 0xe3, 0x13, 0x1f, 0x34, 0xb0, 0x2e, 0x55, 0x84,
+	0x0d, 0x03, 0xa5, 0xe8, 0x1e, 0xa8, 0x0f, 0x1f, 0xa2, 0xdd, 0x7c, 0x4f,
+	0xff, 0x1c, 0xc6, 0xab, 0x29, 0x83, 0xfe, 0xbb, 0x89, 0xf7, 0x37, 0x0f,
+	0xd4, 0x53, 0xef, 0x96, 0xa5, 0x46, 0x1a, 0x9a, 0x27, 0x88, 0x59, 0x93,
+	0xbe, 0x60, 0x60, 0x5c, 0x0d, 0x06, 0x62, 0x70, 0x21, 0xd1, 0xa8, 0xc2,
+	0x9c, 0x1e, 0xcc, 0x98, 0xc4, 0x4d, 0x9f, 0x76, 0xb5, 0x22, 0xd8, 0x66,
+	0xaa, 0x06, 0x6d, 0x8e, 0x78, 0xa7, 0xc6, 0xe8, 0x13, 0xa5, 0xf8, 0x60,
+	0x20, 0xd8, 0x63, 0xaa, 0x77, 0xc1, 0xac, 0xb6, 0xac, 0xef, 0x44, 0xd0,
+	0x71, 0x85, 0x81, 0xd8, 0x74, 0x62, 0xc8, 0xd5, 0xc6, 0x12, 0x10, 0x9f,
+	0x71, 0x2a, 0xa9, 0xf9, 0x7f, 0xa2, 0xdc, 0x8d, 0xaf, 0xb7, 0x05, 0x03,
+	0x01, 0xb5, 0xc1, 0xdc, 0xad, 0x36, 0xd3, 0xd4, 0x11, 0xf0, 0x1b, 0xb7,
+	0x61, 0x8d, 0x3d, 0x56, 0x05, 0x5e, 0x2d, 0x86, 0xee, 0x14, 0x2b, 0xf9,
+	0xea, 0xdb, 0xfb, 0xd4, 0xfa, 0x33, 0xba, 0x1a, 0x3c, 0xda, 0xa6, 0x12,
+	0x2f, 0xe6, 0x9e, 0xb2, 0x02, 0x35, 0x96, 0xd5, 0x34, 0x57, 0xda, 0x0c,
+	0xa0, 0x9a, 0x73, 0x53, 0xc5, 0xb9, 0x69, 0x1a, 0x2d, 0xc5, 0xbb, 0x03,
+	0x30, 0xaf, 0x30, 0x82, 0xad, 0x0f, 0xaa, 0xa5, 0x78, 0x67, 0xa8, 0x14,
+	0x6f, 0x0e, 0x38, 0x71, 0x72, 0xc0, 0xb2, 0xee, 0xd5, 0x2b, 0x51, 0x14,
+	0xc1, 0xf4, 0x22, 0x84, 0x4e, 0x0f, 0xc2, 0xc4, 0xef, 0x59, 0xf6, 0x37,
+	0x03, 0x7e, 0xfc, 0xdb, 0xc0, 0x67, 0xf0, 0x74, 0x75, 0xec, 0xd8, 0x34,
+	0xf8, 0x70, 0x86, 0x73, 0x7e, 0x2a, 0x11, 0x6c, 0xaf, 0x75, 0x04, 0xd7,
+	0x00, 0x0d, 0xab, 0x1e, 0x56, 0x82, 0xf1, 0x97, 0x95, 0x60, 0x20, 0xa9,
+	0xf8, 0xf0, 0x1e, 0x6d, 0xeb, 0x44, 0xb6, 0xbe, 0xf9, 0x35, 0xb6, 0xff,
+	0x5b, 0xfd, 0x7b, 0xd6, 0x78, 0x8d, 0xe8, 0x50, 0xf4, 0x45, 0x9d, 0xa7,
+	0xa8, 0x73, 0xe2, 0xee, 0xf7, 0x52, 0xd4, 0x39, 0xfb, 0xf3, 0xf4, 0x1f,
+	0xe0, 0xa0, 0xcc, 0x57, 0x33, 0x7d, 0xfd, 0x2a, 0xfc, 0x9d, 0x3d, 0xb6,
+	0x63, 0xd6, 0xff, 0xf0, 0xc9, 0xf8, 0x7e, 0x34, 0x3d, 0xe7, 0xe3, 0x32,
+	0xce, 0xa3, 0x56, 0xdc, 0x2b, 0x63, 0x94, 0xb1, 0xda, 0xba, 0x0c, 0x74,
+	0x28, 0xd3, 0x55, 0x94, 0x5a, 0xd6, 0x56, 0x3d, 0xff, 0xdc, 0x57, 0x18,
+	0xeb, 0xbf, 0xd2, 0x0e, 0x64, 0xbc, 0x6b, 0x1d, 0xa2, 0xfb, 0x80, 0xfa,
+	0xaa, 0xf8, 0xbf, 0x19, 0x43, 0xb9, 0x47, 0x62, 0x60, 0xec, 0xfc, 0xf5,
+	0x53, 0x15, 0x17, 0x3f, 0xa7, 0x6d, 0xd9, 0xed, 0xfd, 0x3b, 0xaf, 0x65,
+	0x2c, 0xaf, 0xd0, 0x6e, 0xc4, 0x4e, 0x38, 0x9d, 0x86, 0xd8, 0xcc, 0xa5,
+	0xf6, 0x22, 0xb6, 0xd2, 0x48, 0xbb, 0xfa, 0x17, 0x62, 0x62, 0x07, 0x9e,
+	0xbc, 0xde, 0x2d, 0xd3, 0x1c, 0x70, 0x18, 0x26, 0x3e, 0x1f, 0x75, 0xe0,
+	0xab, 0x51, 0x05, 0xd3, 0xb4, 0x60, 0x06, 0xaa, 0x69, 0x55, 0x91, 0x5b,
+	0x6c, 0xe8, 0x4d, 0x63, 0xc3, 0x18, 0x50, 0xd9, 0x0b, 0x77, 0x85, 0x61,
+	0xe0, 0xa5, 0x24, 0xdc, 0x65, 0xf4, 0xcb, 0x2f, 0x27, 0xeb, 0xc7, 0xdf,
+	0x56, 0x82, 0xb1, 0xd7, 0xa9, 0x4f, 0xea, 0xb5, 0xcd, 0xaf, 0x04, 0x5b,
+	0x57, 0x2b, 0xc1, 0xe6, 0xd9, 0x0a, 0xdc, 0x0a, 0xcb, 0x85, 0xb3, 0x69,
+	0xa4, 0xc6, 0xe4, 0x77, 0x33, 0x66, 0x65, 0xfb, 0xf2, 0x7d, 0x14, 0x3f,
+	0x06, 0x8e, 0xd0, 0xbf, 0x87, 0x9a, 0x15, 0xe2, 0xc9, 0x3b, 0x56, 0xcc,
+	0x47, 0xf9, 0x29, 0xb8, 0x4b, 0x59, 0xe7, 0xb6, 0x64, 0x1a, 0x8c, 0x99,
+	0xee, 0x12, 0xd6, 0xb9, 0x36, 0x09, 0x78, 0x7a, 0x05, 0xf3, 0x83, 0x81,
+	0x6b, 0x94, 0xfa, 0xf6, 0xa4, 0x12, 0x0c, 0xdf, 0xae, 0x34, 0xe8, 0x4f,
+	0x90, 0xb7, 0x6c, 0x40, 0xae, 0x8d, 0x50, 0x36, 0x27, 0xbf, 0x3e, 0x0b,
+	0x65, 0x46, 0x12, 0x9e, 0x5a, 0x6d, 0x26, 0xce, 0x4e, 0xb3, 0xdb, 0x51,
+	0x2a, 0x93, 0x01, 0x3b, 0x96, 0x56, 0x8e, 0x00, 0x2f, 0xf5, 0x5b, 0x38,
+	0x14, 0xa9, 0xa7, 0xbf, 0xb5, 0xc1, 0xcf, 0x32, 0x39, 0x5b, 0xb4, 0xb1,
+	0x42, 0xe9, 0x49, 0xd0, 0xe9, 0xa6, 0xcb, 0xa5, 0x0f, 0xf1, 0xcf, 0x23,
+	0x26, 0xf7, 0x76, 0x26, 0xa0, 0xf4, 0x26, 0x82, 0x3b, 0x01, 0x6d, 0x4d,
+	0x95, 0x23, 0xf6, 0x40, 0x25, 0x3a, 0x31, 0x11, 0x09, 0xc5, 0x07, 0x95,
+	0x50, 0x7b, 0xbf, 0xa2, 0xbb, 0xb7, 0xb0, 0xbd, 0xcd, 0x2c, 0xb3, 0x81,
+	0x9f, 0x45, 0x21, 0xad, 0xf5, 0x43, 0xc4, 0xae, 0x2d, 0x61, 0x99, 0x43,
+	0x7a, 0xe8, 0xcc, 0x6e, 0x84, 0x8e, 0xfe, 0xda, 0xa1, 0xbb, 0x1f, 0xcd,
+	0x8a, 0xac, 0x66, 0x65, 0x68, 0xf4, 0x26, 0x35, 0xe7, 0xfb, 0xff, 0x33,
+	0xaf, 0x83, 0xaf, 0xcb, 0xb5, 0xdd, 0xb6, 0x33, 0x79, 0xb4, 0xf4, 0x0f,
+	0xef, 0x71, 0x92, 0x2e, 0xba, 0xd7, 0xe0, 0x1d, 0xa2, 0xdf, 0x38, 0xb4,
+	0x12, 0xfa, 0xb9, 0xf0, 0x95, 0x58, 0xd8, 0x05, 0xb9, 0xe7, 0x40, 0xc6,
+	0x19, 0xf3, 0x3b, 0xf0, 0x9f, 0x56, 0x6c, 0x99, 0xdc, 0x2b, 0x45, 0xbc,
+	0xad, 0xc1, 0xef, 0x44, 0x43, 0xf3, 0x7a, 0xfa, 0xf0, 0xe4, 0xb2, 0x05,
+	0x7c, 0x16, 0xd2, 0x0f, 0xa1, 0x3e, 0xb0, 0x1e, 0xf2, 0xfb, 0x2c, 0x6d,
+	0x6d, 0x81, 0xd4, 0x65, 0x99, 0x1c, 0x27, 0x13, 0x8c, 0x58, 0xa7, 0x5b,
+	0x78, 0x56, 0x87, 0x59, 0x6c, 0x1c, 0x50, 0x8e, 0x27, 0x7e, 0x6f, 0xc5,
+	0x9c, 0x58, 0x42, 0x7f, 0xd2, 0x35, 0x05, 0x01, 0xb7, 0x11, 0x0a, 0x1c,
+	0x25, 0xfb, 0xa4, 0x6d, 0x28, 0x93, 0xd9, 0x75, 0xca, 0x5b, 0xd9, 0x1e,
+	0xe5, 0x44, 0x56, 0xea, 0x1e, 0x50, 0xde, 0xcc, 0x4a, 0xec, 0xa9, 0x0b,
+	0x1c, 0x61, 0x2c, 0x65, 0x1c, 0x57, 0xbb, 0xc9, 0xda, 0x36, 0xe8, 0x15,
+	0xe4, 0x8e, 0x5a, 0x78, 0x90, 0xfd, 0xdd, 0x13, 0x85, 0xbe, 0x51, 0x77,
+	0x61, 0xd2, 0x0b, 0x4f, 0xb7, 0xee, 0x94, 0x6b, 0xc6, 0x34, 0xa9, 0x5b,
+	0x17, 0x58, 0x9f, 0x3d, 0x47, 0xbf, 0xc8, 0x5d, 0xef, 0x89, 0x16, 0xee,
+	0x7d, 0x64, 0x8d, 0x2f, 0x53, 0x79, 0xfd, 0xa2, 0x8c, 0x9b, 0x75, 0xa7,
+	0x72, 0x45, 0x89, 0xdb, 0x2a, 0xb9, 0x69, 0x15, 0x4c, 0x6f, 0xd0, 0xcc,
+	0x60, 0x09, 0x7d, 0xe7, 0x30, 0xb9, 0xac, 0x9f, 0x71, 0x69, 0x09, 0xb1,
+	0x54, 0x78, 0x98, 0xc2, 0xe7, 0x1e, 0xdc, 0x92, 0xf8, 0x87, 0x3c, 0xc7,
+	0x65, 0x6c, 0xae, 0x71, 0x08, 0x9f, 0xf4, 0xca, 0xdc, 0x1e, 0x4c, 0x4d,
+	0xe5, 0x7e, 0x75, 0x81, 0x93, 0xec, 0x77, 0x89, 0xa6, 0x85, 0x4b, 0x94,
+	0xba, 0xc0, 0x5b, 0xd9, 0x25, 0xf4, 0xcd, 0x77, 0xd9, 0xae, 0x07, 0x6f,
+	0x25, 0x2a, 0xc8, 0x6b, 0x83, 0x31, 0x93, 0x02, 0x6f, 0x25, 0x2f, 0x20,
+	0xbf, 0x98, 0xf2, 0xd7, 0x06, 0xc6, 0x5a, 0x89, 0x87, 0xea, 0xa2, 0x79,
+	0xcd, 0x58, 0x95, 0x85, 0x73, 0x65, 0xd4, 0xc0, 0xbd, 0x8c, 0xa3, 0xf7,
+	0x33, 0x36, 0xad, 0x66, 0xdc, 0xd9, 0x12, 0xe1, 0xd8, 0xaa, 0x2c, 0xab,
+	0x58, 0xeb, 0x14, 0x8e, 0x8c, 0x24, 0xe3, 0xde, 0x3d, 0x9a, 0x13, 0xeb,
+	0xf8, 0xfb, 0xc5, 0xec, 0x7f, 0x58, 0xf7, 0x93, 0xa3, 0x3f, 0x7b, 0x91,
+	0x4c, 0xa8, 0x43, 0x5a, 0x43, 0x78, 0x3d, 0xe3, 0x1e, 0xe5, 0x9a, 0x15,
+	0x86, 0x65, 0x5d, 0x1b, 0x0a, 0xc6, 0x5c, 0x8a, 0x8e, 0x43, 0x23, 0x93,
+	0x56, 0x60, 0xba, 0xf0, 0xf3, 0x42, 0x6c, 0x90, 0xb1, 0x16, 0xf8, 0x9f,
+	0x70, 0xbd, 0xa9, 0x3e, 0xad, 0xe2, 0xd6, 0x01, 0xe1, 0xa6, 0x7e, 0x2c,
+	0x4d, 0x7c, 0x0b, 0x87, 0x1a, 0x9d, 0x68, 0x25, 0x6f, 0x5f, 0x94, 0xf0,
+	0xe0, 0x2e, 0x62, 0xe0, 0xe2, 0x44, 0x31, 0xe7, 0xc6, 0x87, 0xdb, 0x12,
+	0x4e, 0x1c, 0x6e, 0x9c, 0x06, 0xd3, 0x57, 0x8c, 0xf7, 0x74, 0x07, 0x8e,
+	0xe8, 0x5e, 0x64, 0x6c, 0x7f, 0xd8, 0x42, 0xec, 0x0a, 0xe6, 0xf9, 0xa2,
+	0xe8, 0xd0, 0x41, 0x7d, 0xaa, 0x88, 0x9f, 0xd7, 0xe1, 0xe5, 0xb8, 0x60,
+	0x81, 0x07, 0x7e, 0x68, 0xc5, 0xa7, 0x4b, 0x7d, 0x98, 0x1e, 0x43, 0xc6,
+	0x21, 0x5c, 0x4a, 0x47, 0xf7, 0x48, 0x8c, 0x9c, 0x67, 0xea, 0x50, 0x4f,
+	0x93, 0xc7, 0x55, 0xe2, 0x75, 0x4d, 0x78, 0xdc, 0x2b, 0xf0, 0xd2, 0x77,
+	0x7b, 0x46, 0x42, 0x1d, 0xa7, 0x15, 0x07, 0x5e, 0xd4, 0x2a, 0xe2, 0x6e,
+	0xfa, 0xf4, 0xc6, 0x11, 0x38, 0xd7, 0xcf, 0xd3, 0xd1, 0x3b, 0xd2, 0xd5,
+	0x5c, 0x0e, 0x12, 0x9b, 0x79, 0x39, 0xfe, 0xf1, 0x65, 0xea, 0x76, 0x45,
+	0xc4, 0xe6, 0x1f, 0xb9, 0xd8, 0xeb, 0xb5, 0x2c, 0xe6, 0x0c, 0xd4, 0x33,
+	0xb0, 0x2f, 0xaf, 0xe3, 0x3d, 0xfc, 0xdd, 0x93, 0xd7, 0xf1, 0x3a, 0xca,
+	0xa3, 0xff, 0x61, 0xc3, 0x45, 0x9c, 0x21, 0x80, 0x62, 0x43, 0x30, 0x88,
+	0xf8, 0x49, 0x3c, 0x89, 0x51, 0xc7, 0xcf, 0x65, 0x7f, 0xc7, 0xb1, 0x06,
+	0x39, 0xdd, 0x62, 0x4f, 0x8c, 0x85, 0xea, 0x67, 0x1c, 0xc4, 0x55, 0xea,
+	0x41, 0xf4, 0x2c, 0xfa, 0xb5, 0xac, 0x7e, 0x5d, 0x74, 0x2c, 0xfa, 0x16,
+	0xbd, 0xe7, 0xf0, 0x93, 0x7c, 0xbf, 0x07, 0x48, 0xb3, 0xac, 0x83, 0x78,
+	0x69, 0xe0, 0xbb, 0x6d, 0x62, 0x3b, 0xe5, 0x76, 0x8c, 0x9b, 0x33, 0xd3,
+	0xb2, 0x9e, 0x8a, 0x04, 0xf0, 0xbe, 0xd6, 0xd0, 0xdc, 0xa4, 0x06, 0xd9,
+	0xd7, 0x25, 0x48, 0x8c, 0xc5, 0x38, 0x77, 0x57, 0x93, 0x87, 0x8b, 0xad,
+	0xa1, 0xa3, 0xc8, 0xc6, 0x5c, 0xe0, 0x44, 0x42, 0x0b, 0x6f, 0xe0, 0x9c,
+	0xed, 0xf6, 0x2d, 0x23, 0x67, 0x52, 0x5b, 0x98, 0xb5, 0x90, 0xab, 0x68,
+	0xe6, 0x26, 0xbc, 0x6b, 0x65, 0x7c, 0x16, 0xe3, 0x9b, 0x0a, 0xa7, 0x36,
+	0x03, 0x87, 0xbd, 0x0e, 0x3c, 0x1f, 0xae, 0x41, 0xac, 0x4a, 0x41, 0x99,
+	0xf6, 0x4b, 0xeb, 0x05, 0x9f, 0xb4, 0xc3, 0x7c, 0x43, 0xfd, 0x39, 0xfb,
+	0xad, 0xb0, 0x8c, 0xc8, 0x5d, 0x86, 0xae, 0xb1, 0x4b, 0xdb, 0xff, 0x85,
+	0x35, 0xe9, 0x93, 0xf6, 0x83, 0xde, 0x80, 0xfa, 0x49, 0x73, 0xf8, 0xaa,
+	0xf5, 0x5a, 0x4e, 0xa6, 0x1d, 0x7f, 0xa0, 0x8a, 0xbc, 0xc7, 0x39, 0x3e,
+	0x91, 0x59, 0x68, 0x47, 0xfc, 0x6c, 0x3f, 0xef, 0xc9, 0x33, 0xb1, 0x91,
+	0x75, 0x6c, 0xf7, 0x90, 0x85, 0x1a, 0xb9, 0xde, 0x6c, 0x97, 0x35, 0xc7,
+	0x26, 0x16, 0x3b, 0x31, 0x1f, 0xb3, 0x22, 0x0b, 0x16, 0xca, 0x58, 0x54,
+	0x23, 0x16, 0x70, 0xc3, 0xac, 0x71, 0x10, 0x8b, 0xdf, 0x6e, 0x6c, 0xc4,
+	0xc2, 0xec, 0xa4, 0xf5, 0x2e, 0xc1, 0xa5, 0x4b, 0x73, 0x60, 0x9c, 0xe3,
+	0xdb, 0xaf, 0x4b, 0x6e, 0x68, 0x61, 0x51, 0xc4, 0x8c, 0xd3, 0x63, 0xcd,
+	0x72, 0xda, 0x4e, 0xa9, 0x26, 0xf1, 0xb9, 0x02, 0x65, 0x86, 0x33, 0xfc,
+	0x2e, 0x82, 0xfa, 0x16, 0xf2, 0x93, 0x40, 0xd5, 0xac, 0x66, 0x17, 0xb5,
+	0xfb, 0x52, 0x22, 0xd4, 0x7c, 0x44, 0xc9, 0xf9, 0xc3, 0x73, 0x9c, 0xdb,
+	0xd7, 0x13, 0xda, 0x9a, 0x62, 0x47, 0xee, 0xfa, 0xe5, 0xac, 0xe4, 0x23,
+	0x05, 0x7f, 0xf0, 0xe7, 0x71, 0xc3, 0xed, 0x3e, 0x91, 0xc0, 0x69, 0x95,
+	0xf8, 0x53, 0x65, 0xe0, 0x74, 0xb7, 0x9e, 0x51, 0x5c, 0x5a, 0x05, 0x71,
+	0x55, 0xb0, 0xb4, 0x88, 0x31, 0x41, 0x62, 0xb6, 0xdb, 0xfd, 0x2e, 0xcb,
+	0x2c, 0x8e, 0x60, 0x32, 0x7c, 0x63, 0x43, 0xb3, 0x1b, 0x31, 0xb3, 0x98,
+	0x7e, 0x59, 0x6e, 0xf8, 0xdc, 0x73, 0x46, 0xcd, 0x1a, 0x0f, 0xed, 0xba,
+	0xcc, 0x40, 0xcb, 0xac, 0xde, 0xd6, 0x4a, 0x54, 0x34, 0x62, 0xf5, 0x88,
+	0xe4, 0x96, 0x7d, 0x35, 0x2a, 0xfb, 0xea, 0xd2, 0xca, 0xe1, 0xaa, 0x5e,
+	0x3d, 0x5f, 0x35, 0x7e, 0x80, 0xb6, 0xa8, 0xbb, 0x45, 0x1f, 0x9d, 0x9a,
+	0xe3, 0x08, 0x46, 0x9a, 0x35, 0x95, 0xc4, 0xc7, 0x0a, 0x43, 0xf2, 0x9b,
+	0x40, 0xcb, 0xcb, 0x36, 0x7e, 0x7a, 0xc9, 0xc7, 0x7f, 0xe6, 0xff, 0xf3,
+	0xeb, 0x3c, 0x4f, 0x1d, 0x4b, 0x9b, 0xf2, 0x2d, 0xb9, 0x26, 0x9c, 0xcc,
+	0x1d, 0xd1, 0x35, 0xec, 0x61, 0x7e, 0x21, 0x73, 0x03, 0x77, 0x91, 0x11,
+	0xfe, 0xcb, 0x67, 0xe9, 0x17, 0x2e, 0xea, 0x78, 0x93, 0x66, 0x12, 0xce,
+	0x2d, 0x4b, 0x8b, 0x04, 0xfd, 0x45, 0x4a, 0x00, 0x1b, 0x1b, 0x7f, 0x47,
+	0x5b, 0x00, 0xf1, 0x0a, 0x24, 0xab, 0x35, 0x58, 0x37, 0x5c, 0x31, 0xa5,
+	0xde, 0xbe, 0xf3, 0xf5, 0x92, 0x9a, 0x19, 0x97, 0x7a, 0x43, 0x91, 0x60,
+	0xfb, 0x06, 0xd6, 0xdb, 0xcc, 0x7a, 0x31, 0xc6, 0xc8, 0x7b, 0xe9, 0x9b,
+	0x2e, 0xe6, 0x37, 0xeb, 0x99, 0xeb, 0x4c, 0x69, 0xef, 0xaf, 0x0a, 0xf5,
+	0x1e, 0xd5, 0xcc, 0x71, 0xbb, 0xbd, 0xb9, 0xc1, 0x35, 0x45, 0x8e, 0x00,
+	0x7a, 0x59, 0x6f, 0x9c, 0xf5, 0xde, 0x1a, 0xa9, 0xce, 0x97, 0x77, 0x62,
+	0xc3, 0xac, 0x5c, 0xd9, 0x1e, 0xcd, 0xf4, 0x4b, 0x59, 0x67, 0x24, 0xd8,
+	0x7c, 0x1f, 0xb1, 0xba, 0x4b, 0xda, 0x60, 0xdf, 0xde, 0xb2, 0xe3, 0x0a,
+	0x6e, 0x7a, 0x21, 0x91, 0x9a, 0x74, 0x6a, 0x5a, 0xdb, 0x4a, 0x25, 0xa6,
+	0x2c, 0x9e, 0x67, 0xcf, 0xef, 0x4d, 0xc7, 0xb2, 0x9d, 0xd8, 0xa8, 0x4d,
+	0x44, 0x8a, 0x59, 0xef, 0x88, 0x36, 0xe1, 0x77, 0xd1, 0xd7, 0x56, 0xb2,
+	0xed, 0x2e, 0xe6, 0x15, 0x2a, 0x7d, 0x7b, 0xdd, 0xb0, 0xf0, 0x01, 0x9d,
+	0x7c, 0xa3, 0x8e, 0x76, 0x28, 0xfa, 0x91, 0x36, 0x65, 0x9e, 0x45, 0x17,
+	0xc1, 0xf0, 0xb0, 0xad, 0x0b, 0xa5, 0x7a, 0x5f, 0x23, 0x8d, 0xa5, 0x8a,
+	0xfc, 0xab, 0x51, 0x62, 0xa2, 0x42, 0x3c, 0xbe, 0x12, 0x1b, 0xec, 0x3c,
+	0xad, 0x8e, 0x5c, 0xc7, 0xb2, 0xf6, 0xe8, 0x96, 0xf5, 0xac, 0x3e, 0x03,
+	0xfb, 0xf4, 0x60, 0x5c, 0x6c, 0xf3, 0x97, 0xfa, 0x82, 0x6b, 0x5d, 0x08,
+	0x32, 0xe1, 0xff, 0x14, 0xc6, 0x69, 0x2f, 0x25, 0x9a, 0xf8, 0xa0, 0x02,
+	0x7f, 0xc8, 0x19, 0x28, 0x53, 0x2c, 0xb8, 0xe7, 0xce, 0x5c, 0x33, 0x93,
+	0x7a, 0xaa, 0xb8, 0x51, 0xc1, 0x07, 0x73, 0x14, 0x4c, 0xcc, 0x09, 0xf9,
+	0x07, 0x95, 0x72, 0xe2, 0x6d, 0xa8, 0xad, 0x45, 0x31, 0x8f, 0xb2, 0x6e,
+	0xac, 0xd1, 0xc1, 0x7c, 0x5a, 0xa9, 0x24, 0x16, 0xcc, 0x0a, 0x08, 0x1d,
+	0x70, 0x26, 0x43, 0xfe, 0xcd, 0xfc, 0x76, 0x8c, 0x28, 0x18, 0xd1, 0x82,
+	0x31, 0xd8, 0xf2, 0xd9, 0x76, 0x44, 0xc1, 0x75, 0x21, 0xcb, 0x3a, 0x16,
+	0x69, 0xf0, 0x1e, 0xc3, 0x2f, 0x2d, 0x59, 0x4b, 0xf1, 0x87, 0xce, 0xe7,
+	0x06, 0x28, 0x4d, 0x6a, 0xb1, 0x16, 0x65, 0xbb, 0x53, 0x38, 0xc5, 0xaa,
+	0xac, 0xc4, 0xc8, 0x42, 0x7f, 0x0b, 0xb1, 0xd2, 0xb2, 0x7e, 0xa9, 0xe7,
+	0x64, 0x79, 0xa3, 0xc2, 0xcd, 0x66, 0x60, 0x4c, 0x0b, 0xb6, 0x8e, 0x53,
+	0x07, 0x7e, 0xfa, 0x60, 0x2d, 0xe7, 0x7d, 0xd2, 0x15, 0xf4, 0x4e, 0x2a,
+	0x0b, 0xcf, 0xaa, 0x98, 0xbd, 0xea, 0x31, 0xa5, 0xa1, 0xa3, 0x04, 0x5a,
+	0x6c, 0x54, 0xb9, 0x82, 0x3a, 0x31, 0xfd, 0x1e, 0x04, 0xbd, 0x2b, 0x61,
+	0xc7, 0x6d, 0xdc, 0x9e, 0x70, 0xc6, 0xce, 0xa0, 0x9e, 0xfe, 0xa0, 0xb5,
+	0xdf, 0x4f, 0x6e, 0x07, 0x7c, 0x96, 0x84, 0x5f, 0xfa, 0x5a, 0x83, 0xf8,
+	0x5f, 0x58, 0xd6, 0x03, 0xec, 0xeb, 0x16, 0xf6, 0x75, 0x75, 0xe4, 0x7d,
+	0xeb, 0x17, 0xb6, 0xcc, 0x9b, 0x31, 0xa8, 0x5d, 0x2a, 0xf7, 0x3d, 0x0b,
+	0xd3, 0x45, 0xae, 0x0b, 0xb7, 0x4e, 0x67, 0xee, 0x11, 0x15, 0x2c, 0x79,
+	0x84, 0xf9, 0xb9, 0xc8, 0x63, 0x5c, 0x51, 0x2f, 0x8d, 0xcd, 0x0e, 0x30,
+	0xe6, 0xf9, 0xe3, 0x8a, 0x5a, 0x57, 0x06, 0x2f, 0xdc, 0x9a, 0x85, 0x07,
+	0xc9, 0x23, 0x62, 0xd3, 0x2b, 0xf1, 0x90, 0xee, 0x46, 0x79, 0x48, 0xbd,
+	0xd2, 0xc1, 0x39, 0xd9, 0x17, 0x91, 0x6b, 0x17, 0xc6, 0xa7, 0x3b, 0xd0,
+	0x49, 0x7e, 0xe1, 0x0d, 0xa9, 0xb5, 0x72, 0xdf, 0xdd, 0x24, 0xd7, 0xec,
+	0xff, 0x15, 0x0a, 0x1e, 0xa0, 0x55, 0xa8, 0xa1, 0x2e, 0xbf, 0xdc, 0x6f,
+	0xd5, 0xe5, 0x5a, 0x41, 0x7d, 0xc4, 0xc9, 0x79, 0xb1, 0xe0, 0x60, 0xdf,
+	0x4b, 0x43, 0xbc, 0x1f, 0x91, 0xdf, 0xb1, 0x07, 0x38, 0xee, 0xd8, 0x6e,
+	0x45, 0xb0, 0xe7, 0xc7, 0xd6, 0xf3, 0x8c, 0x2d, 0x5e, 0x3e, 0x7f, 0x88,
+	0x6d, 0x1f, 0x8d, 0x3c, 0x6b, 0xd5, 0x12, 0x73, 0x8f, 0x35, 0x07, 0x30,
+	0x63, 0x4e, 0x1d, 0x26, 0xef, 0x96, 0x31, 0x2b, 0x28, 0xd7, 0xca, 0x5d,
+	0x92, 0xe7, 0x55, 0x68, 0x57, 0xe0, 0xd6, 0xbb, 0x72, 0xf7, 0x4a, 0x28,
+	0x2f, 0x4c, 0xdc, 0x2d, 0x99, 0x53, 0x8d, 0x40, 0xfe, 0xde, 0xc2, 0x90,
+	0xb3, 0xad, 0x5c, 0xd1, 0xbc, 0xb7, 0x2b, 0xf2, 0xfc, 0x37, 0xb4, 0x71,
+	0xcb, 0x7a, 0x90, 0xf3, 0x35, 0x2b, 0xe2, 0xc1, 0x29, 0xb6, 0xd3, 0x45,
+	0xfd, 0x2d, 0x39, 0x3f, 0x5f, 0x85, 0xfa, 0xbf, 0xb6, 0x02, 0x7f, 0x21,
+	0x75, 0x45, 0xc6, 0xcc, 0xd6, 0x5b, 0x95, 0xe7, 0x9c, 0x92, 0x33, 0xac,
+	0x8e, 0xd8, 0x3a, 0x63, 0xd9, 0x5a, 0x97, 0x5c, 0x7b, 0xa3, 0xaf, 0x9f,
+	0x5f, 0x7f, 0x39, 0x6d, 0xc7, 0xa8, 0x05, 0x37, 0x7a, 0x31, 0x69, 0x55,
+	0x35, 0x99, 0xde, 0x62, 0x48, 0xac, 0xaa, 0x0f, 0x3f, 0x45, 0xb9, 0xaf,
+	0xe9, 0xb9, 0x38, 0xb6, 0x47, 0x0f, 0xa6, 0x4d, 0xfa, 0x43, 0x9c, 0x39,
+	0x5f, 0x8b, 0xbd, 0x56, 0xb4, 0x87, 0xf3, 0x30, 0x03, 0xc5, 0x4d, 0xc1,
+	0x9e, 0x6b, 0x98, 0x03, 0x39, 0xa2, 0x12, 0xff, 0x64, 0x7e, 0xec, 0x32,
+	0x6c, 0xab, 0x04, 0x0b, 0xd9, 0xc7, 0x48, 0xd3, 0x1f, 0x8b, 0x1d, 0x22,
+	0x47, 0xac, 0x33, 0xd8, 0x13, 0xc3, 0x1f, 0x2b, 0x0b, 0x46, 0x6a, 0xc4,
+	0x1d, 0x86, 0xfb, 0xa6, 0x78, 0x56, 0x25, 0xf7, 0x28, 0xf2, 0x76, 0x45,
+	0x6b, 0xf8, 0x91, 0xe7, 0xce, 0x9b, 0x56, 0x64, 0xcf, 0xaf, 0x29, 0x21,
+	0xad, 0x17, 0x41, 0xbd, 0x4e, 0x70, 0x9c, 0x88, 0xec, 0x95, 0xf1, 0x99,
+	0xcd, 0x5e, 0x3b, 0x87, 0x5e, 0xfb, 0x85, 0x7b, 0xb4, 0xa0, 0xfe, 0x26,
+	0x5b, 0x3c, 0x4c, 0x8e, 0x63, 0xda, 0x9e, 0x21, 0xbe, 0x3e, 0x15, 0x47,
+	0x25, 0xae, 0x88, 0x4c, 0xc1, 0xd0, 0x2b, 0xd1, 0xb7, 0xa3, 0x03, 0x81,
+	0x9a, 0x1c, 0x66, 0xb9, 0x8c, 0xb9, 0xd8, 0x93, 0xde, 0xec, 0xca, 0xf1,
+	0xf2, 0x4e, 0x3c, 0x45, 0x4c, 0xdb, 0xb8, 0x63, 0xa2, 0xb6, 0x8a, 0xba,
+	0xea, 0xd0, 0x1b, 0xf4, 0xd3, 0xb8, 0x83, 0x7e, 0x2e, 0x65, 0x27, 0xbe,
+	0x52, 0x05, 0x29, 0x67, 0xe1, 0x48, 0xa4, 0x06, 0xc9, 0x1d, 0x9f, 0x46,
+	0x66, 0xba, 0xdc, 0x97, 0x7b, 0x6e, 0xe2, 0xb0, 0x0f, 0xeb, 0x77, 0xf8,
+	0x91, 0xf1, 0xc9, 0x5a, 0x99, 0xac, 0x57, 0x0a, 0x36, 0xbf, 0x61, 0x99,
+	0x5e, 0xe9, 0x87, 0xc4, 0xf7, 0x50, 0x73, 0x37, 0x63, 0x9a, 0xd7, 0x88,
+	0x11, 0x3f, 0xc8, 0x3d, 0x46, 0x7f, 0x62, 0x65, 0x6c, 0x0e, 0xef, 0x36,
+	0x85, 0x23, 0x3d, 0xab, 0x35, 0xc4, 0x8e, 0xb0, 0x07, 0xf1, 0xec, 0x7f,
+	0xd2, 0x47, 0x9c, 0xb8, 0x47, 0xfb, 0xb8, 0xfe, 0x7b, 0xd8, 0x3f, 0xb8,
+	0x9d, 0xc4, 0x76, 0xf2, 0x48, 0x62, 0x70, 0xc8, 0x25, 0x31, 0xbf, 0x88,
+	0xed, 0x6f, 0xd9, 0xa1, 0xa0, 0x85, 0x18, 0xb8, 0x99, 0x36, 0xf5, 0x40,
+	0x08, 0xce, 0xd6, 0x39, 0xe4, 0x35, 0xf8, 0x02, 0x73, 0x1a, 0x1f, 0x36,
+	0x0d, 0x63, 0x6e, 0x56, 0x1b, 0xaf, 0xf5, 0xa0, 0xc7, 0x25, 0xdc, 0xd6,
+	0x24, 0xde, 0xe7, 0xe4, 0xec, 0xbb, 0x44, 0x4e, 0x0d, 0x1e, 0xcd, 0xcb,
+	0xd9, 0x49, 0x39, 0x9f, 0x9e, 0x05, 0x67, 0xc5, 0xa7, 0x65, 0x2e, 0x17,
+	0xd2, 0xbf, 0x6a, 0x90, 0xb2, 0xe3, 0x04, 0x79, 0xe0, 0x67, 0xa0, 0x68,
+	0x33, 0x25, 0x67, 0x58, 0x6a, 0xd7, 0xbb, 0xa5, 0x71, 0xfc, 0x4c, 0x15,
+	0xc1, 0xf5, 0xf4, 0xac, 0x71, 0x3a, 0x72, 0x41, 0x27, 0xde, 0x42, 0x5f,
+	0xff, 0xea, 0x42, 0x1b, 0x1c, 0x33, 0xed, 0xcb, 0x1d, 0x95, 0xbe, 0x3d,
+	0x6e, 0xb5, 0x7a, 0x73, 0x73, 0x95, 0xd8, 0x11, 0x0c, 0xb4, 0x51, 0xe7,
+	0x5b, 0xf4, 0xfa, 0xb6, 0x34, 0x29, 0xcc, 0x03, 0x73, 0x3e, 0x4d, 0xdf,
+	0xf7, 0x63, 0xf3, 0x30, 0x6e, 0x18, 0xd1, 0x24, 0xc6, 0x8c, 0x07, 0xcb,
+	0x2f, 0x9a, 0x83, 0xab, 0xa9, 0xef, 0x6a, 0xca, 0x27, 0xbf, 0x9b, 0x55,
+	0xe8, 0x3b, 0xfb, 0x41, 0xfc, 0x7e, 0x74, 0x87, 0xe4, 0xc2, 0x75, 0xe4,
+	0x58, 0x96, 0x75, 0x90, 0x63, 0x68, 0x9e, 0xd5, 0xb0, 0xe6, 0xb8, 0xa3,
+	0x16, 0x93, 0xd3, 0xaf, 0xc4, 0xce, 0x61, 0x89, 0x3f, 0x01, 0xd6, 0x6d,
+	0xaa, 0xcc, 0x71, 0x1b, 0xb8, 0x6e, 0xe5, 0x58, 0x0f, 0xe7, 0xc7, 0xe1,
+	0xd2, 0xc4, 0x26, 0x9a, 0xb0, 0x67, 0xe0, 0xfc, 0xf3, 0xe0, 0x2d, 0xda,
+	0x78, 0xd0, 0xf5, 0x07, 0xb6, 0x32, 0xce, 0xef, 0x0a, 0x89, 0x33, 0x17,
+	0xe9, 0x75, 0xdd, 0xf0, 0x69, 0x7e, 0x57, 0x33, 0x2e, 0xe6, 0xfa, 0xbd,
+	0x6e, 0xf8, 0x5f, 0x79, 0x2d, 0x7d, 0xb7, 0xb0, 0xce, 0xce, 0x63, 0x8a,
+	0x18, 0xdf, 0x04, 0x9b, 0xc5, 0xae, 0x6b, 0x24, 0x8f, 0x6b, 0xce, 0x40,
+	0x62, 0xb3, 0xd8, 0xf2, 0x80, 0xd8, 0x72, 0xd8, 0xa1, 0x00, 0x43, 0xe7,
+	0x6d, 0xb9, 0x13, 0x3f, 0xd0, 0x26, 0xee, 0x2a, 0xc6, 0xc4, 0x17, 0x65,
+	0xad, 0xb8, 0x23, 0x82, 0x63, 0x8b, 0x88, 0x13, 0x6f, 0xe9, 0x05, 0xbd,
+	0x8a, 0x3e, 0x05, 0x43, 0x15, 0x14, 0xd3, 0x66, 0x36, 0x50, 0x8f, 0x45,
+	0xaa, 0x9f, 0xed, 0x5e, 0x8a, 0xa5, 0xd2, 0x7f, 0x1d, 0x7b, 0x12, 0x13,
+	0x0f, 0x17, 0xe3, 0x7f, 0x49, 0x5e, 0xf4, 0xc6, 0x09, 0xca, 0xb9, 0x45,
+	0x17, 0xfd, 0x89, 0xee, 0x0a, 0x32, 0xae, 0x44, 0xef, 0x8e, 0x42, 0x5d,
+	0x05, 0x2f, 0x86, 0xfc, 0xf9, 0xb5, 0xd8, 0x2b, 0x91, 0x1c, 0x9e, 0x38,
+	0x46, 0x2e, 0x44, 0x7d, 0x4e, 0xac, 0xf1, 0xb3, 0x2f, 0xa7, 0x23, 0x05,
+	0xfb, 0x11, 0x9c, 0x98, 0x2a, 0x43, 0xfc, 0x03, 0x4a, 0xc5, 0x4c, 0xac,
+	0xab, 0xa0, 0x1f, 0x64, 0x43, 0x88, 0x97, 0x19, 0x35, 0x48, 0x0c, 0xd3,
+	0xcf, 0x47, 0x8a, 0xe0, 0xbc, 0x5e, 0xec, 0x5e, 0xf8, 0x98, 0xf3, 0xa6,
+	0xe3, 0x89, 0x22, 0x7c, 0x49, 0x3f, 0x67, 0x09, 0x46, 0x1f, 0xd3, 0x70,
+	0x55, 0x11, 0xf5, 0x34, 0x33, 0x12, 0x8a, 0xad, 0x24, 0x3f, 0x38, 0xd2,
+	0xe8, 0xbc, 0xe9, 0x64, 0xf6, 0xb7, 0xe4, 0xbe, 0x97, 0x8e, 0x45, 0xf4,
+	0x81, 0x17, 0x17, 0x87, 0x72, 0x73, 0x4e, 0xde, 0x9f, 0xf7, 0x07, 0x69,
+	0xdf, 0xb2, 0x42, 0x11, 0x1f, 0xed, 0xe2, 0xc2, 0x18, 0xde, 0xd6, 0x0a,
+	0x63, 0xf0, 0x31, 0xb6, 0x2f, 0x21, 0xb7, 0x16, 0xde, 0xef, 0x66, 0x9e,
+	0xeb, 0x64, 0xbe, 0xd0, 0x06, 0xe1, 0xa3, 0x47, 0xc9, 0xab, 0xf6, 0x27,
+	0x80, 0x77, 0xd3, 0x16, 0x16, 0x44, 0xca, 0x89, 0x75, 0x3d, 0x94, 0x2d,
+	0xeb, 0xab, 0x07, 0x94, 0x61, 0xe6, 0xc2, 0x93, 0xce, 0x92, 0x98, 0xca,
+	0xdc, 0x77, 0x5f, 0x36, 0xe4, 0x9f, 0x60, 0x1e, 0xec, 0x66, 0x2e, 0x4e,
+	0xcd, 0x29, 0xfb, 0x99, 0x07, 0xef, 0xce, 0xe7, 0xc1, 0xfb, 0xb2, 0x1e,
+	0x64, 0x69, 0xbc, 0x5b, 0x22, 0xcc, 0xbf, 0xed, 0x75, 0x04, 0x0f, 0xc6,
+	0xd2, 0x2a, 0x4e, 0x45, 0x3e, 0xb0, 0xc6, 0xab, 0x64, 0xcc, 0x3e, 0x3c,
+	0x93, 0xa8, 0xc6, 0x81, 0x81, 0x3a, 0x9c, 0xcd, 0x3e, 0x52, 0x84, 0xd2,
+	0x2b, 0x71, 0x66, 0xa8, 0x02, 0x23, 0x03, 0x9b, 0xf9, 0xbb, 0x11, 0x1f,
+	0x0c, 0xd9, 0x39, 0x38, 0xb1, 0x59, 0xfa, 0x77, 0x40, 0x99, 0xb0, 0x73,
+	0x70, 0x33, 0xc6, 0xdc, 0xbb, 0xb9, 0x27, 0x9f, 0x7b, 0x8f, 0x33, 0xf7,
+	0x3e, 0xc2, 0x36, 0x9f, 0xcb, 0xb7, 0x79, 0xc8, 0xfe, 0x96, 0xbe, 0x48,
+	0xdd, 0xa9, 0xf5, 0x9a, 0x59, 0x0f, 0x18, 0x4e, 0x84, 0xc2, 0x85, 0xba,
+	0xcf, 0xb1, 0xde, 0x91, 0xf3, 0xf5, 0x72, 0x39, 0x35, 0x79, 0x31, 0x36,
+	0x24, 0xec, 0x75, 0x1f, 0xea, 0x23, 0x4c, 0x5d, 0x48, 0x8e, 0x49, 0x7e,
+	0x9e, 0xfd, 0x16, 0xf9, 0xfc, 0x9e, 0x22, 0x54, 0x54, 0x61, 0x61, 0x46,
+	0xd6, 0xb3, 0x4b, 0x98, 0xfb, 0x15, 0xf4, 0x1f, 0x47, 0x32, 0xb5, 0x8a,
+	0xfe, 0x05, 0xb7, 0xc7, 0xc8, 0xfe, 0x55, 0x82, 0xf3, 0xf0, 0x44, 0x68,
+	0xbc, 0xad, 0x1c, 0x95, 0x58, 0x15, 0xb1, 0xf9, 0x23, 0x79, 0x60, 0xb0,
+	0x79, 0x09, 0xe3, 0x9c, 0x23, 0x14, 0x64, 0xcc, 0x02, 0x42, 0x23, 0xcc,
+	0x6f, 0xb2, 0x95, 0xb8, 0x87, 0x79, 0xa6, 0x5a, 0x15, 0x47, 0xcf, 0xf9,
+	0x35, 0x4e, 0xf9, 0x5e, 0x85, 0xee, 0x31, 0x91, 0x17, 0x67, 0xee, 0x50,
+	0x86, 0x45, 0xb9, 0x35, 0x19, 0xb7, 0x9b, 0xb2, 0xdd, 0xa1, 0xf1, 0x30,
+	0x5d, 0x50, 0xdf, 0xc7, 0x1b, 0x87, 0x12, 0x0a, 0x16, 0x68, 0x2e, 0xac,
+	0xf4, 0x56, 0x62, 0x81, 0xfe, 0x3b, 0x6b, 0xd1, 0x32, 0x79, 0x76, 0x61,
+	0xad, 0xb4, 0x98, 0xed, 0xfe, 0x92, 0xf9, 0xc2, 0xb0, 0x78, 0x67, 0x36,
+	0x77, 0xdf, 0xcc, 0x52, 0x36, 0xe5, 0x6e, 0xa0, 0xdc, 0xfb, 0xbc, 0x76,
+	0x2e, 0x9f, 0x2f, 0x37, 0x1e, 0x76, 0x30, 0x3e, 0x49, 0xd9, 0x16, 0xca,
+	0xbd, 0x87, 0x72, 0x7b, 0xbc, 0xd2, 0xbf, 0xdf, 0x59, 0xf7, 0x2d, 0x93,
+	0x67, 0xb9, 0x75, 0x91, 0x9c, 0xdc, 0xac, 0xc8, 0xd5, 0x87, 0xf3, 0x6d,
+	0x4d, 0x24, 0x98, 0xec, 0x11, 0xb3, 0x57, 0x44, 0x43, 0x81, 0x2e, 0x7b,
+	0x4d, 0x3c, 0x80, 0x95, 0xd9, 0x00, 0xee, 0xa5, 0xde, 0x33, 0xce, 0xc2,
+	0x98, 0xec, 0x3e, 0x99, 0x92, 0x17, 0x2c, 0x64, 0xb9, 0xee, 0x3c, 0x7e,
+	0xb7, 0x64, 0xc5, 0xfe, 0x26, 0xf3, 0xf9, 0xa4, 0xc4, 0xb1, 0xba, 0x3c,
+	0x16, 0x38, 0xf1, 0x64, 0xe2, 0x37, 0xe7, 0xfa, 0x52, 0x12, 0x97, 0x65,
+	0xad, 0x27, 0x80, 0x74, 0xf6, 0x2a, 0xd4, 0xf7, 0x7b, 0xb1, 0x42, 0x9f,
+	0x46, 0x9c, 0xf8, 0xd6, 0x79, 0x7b, 0xdc, 0xc7, 0x76, 0xe0, 0xb2, 0xc5,
+	0x2b, 0x4f, 0x66, 0x1b, 0xbc, 0xd5, 0xc4, 0xba, 0x83, 0x17, 0xc5, 0xd7,
+	0x19, 0xb1, 0x32, 0x23, 0xd4, 0xf6, 0x02, 0xe7, 0xbd, 0xc4, 0xce, 0x1b,
+	0xd6, 0x29, 0x19, 0xce, 0xfd, 0xe3, 0xf9, 0xb9, 0xdf, 0x9f, 0x45, 0x71,
+	0x0e, 0xdb, 0xae, 0xc2, 0xac, 0x7e, 0xf9, 0xf6, 0xe2, 0xed, 0x68, 0x29,
+	0xef, 0x5d, 0x85, 0x99, 0x83, 0x57, 0x17, 0xe7, 0xf6, 0xc2, 0x64, 0x7d,
+	0xe1, 0xd2, 0x1c, 0x2a, 0xd8, 0x63, 0xe2, 0x3d, 0xda, 0x44, 0x1d, 0x75,
+	0x26, 0x18, 0x2b, 0xfd, 0xda, 0x74, 0xbe, 0x5f, 0x4f, 0xb0, 0x5f, 0x71,
+	0x97, 0xac, 0xff, 0x4a, 0xbf, 0x94, 0x58, 0x85, 0x51, 0x87, 0x0f, 0x92,
+	0xf0, 0x7a, 0x8d, 0x50, 0xfc, 0x25, 0xfa, 0xca, 0x08, 0xfb, 0x5a, 0x85,
+	0x1e, 0x25, 0x6b, 0xef, 0xfd, 0x1c, 0x60, 0x99, 0xa9, 0x7c, 0x40, 0xfa,
+	0xe9, 0xa4, 0xcd, 0xfd, 0x25, 0x71, 0x58, 0x27, 0x0e, 0x8b, 0xfc, 0x77,
+	0xc8, 0x79, 0xbb, 0x29, 0x7f, 0x09, 0xe7, 0xcf, 0x2d, 0x7b, 0x54, 0x66,
+	0xa9, 0xd1, 0x66, 0x73, 0x6e, 0x27, 0x7d, 0x76, 0x01, 0x6d, 0x6a, 0x7f,
+	0x46, 0xc1, 0x10, 0x95, 0x7e, 0x34, 0x2d, 0x6b, 0xd7, 0x7e, 0xec, 0xcb,
+	0xb8, 0xf0, 0x5c, 0xba, 0x16, 0xc3, 0x99, 0x22, 0x1c, 0x4a, 0x5f, 0x89,
+	0xdd, 0x19, 0x22, 0x67, 0xfa, 0x2a, 0x0c, 0x66, 0xdc, 0x78, 0x23, 0x4d,
+	0x3d, 0x65, 0x4a, 0xf0, 0xd3, 0xf4, 0xa7, 0xf0, 0x4c, 0xa6, 0x14, 0xaf,
+	0xa7, 0xaf, 0xc6, 0x81, 0x4c, 0x19, 0x5e, 0x4e, 0x93, 0x17, 0x67, 0x3c,
+	0x78, 0x29, 0x1d, 0xc0, 0x68, 0xa6, 0x1c, 0x2f, 0xa6, 0x83, 0x18, 0xc9,
+	0x54, 0xe0, 0x07, 0xe9, 0x6b, 0x90, 0xcd, 0x54, 0xe2, 0x85, 0x74, 0x3d,
+	0x9e, 0xa0, 0x0f, 0x3c, 0x9f, 0xd6, 0xf0, 0x78, 0xa6, 0x0a, 0xc7, 0xd2,
+	0x21, 0xb6, 0xeb, 0xc3, 0xd1, 0x81, 0x30, 0xf6, 0x0d, 0xd5, 0xe0, 0xb9,
+	0x81, 0xd9, 0x18, 0x1e, 0xf2, 0xe3, 0xd0, 0x40, 0x23, 0x76, 0x0f, 0x8d,
+	0xdb, 0xfa, 0x39, 0x92, 0x68, 0x39, 0xaf, 0xc7, 0x0d, 0x1f, 0x33, 0xdf,
+	0xaf, 0x24, 0x44, 0x6f, 0x6e, 0xb3, 0x8a, 0x73, 0xf4, 0x64, 0xd6, 0x9e,
+	0x77, 0x68, 0xfd, 0x6d, 0xf4, 0x33, 0x0b, 0xdd, 0xfa, 0x95, 0xcc, 0x47,
+	0x7b, 0x24, 0x1e, 0xd1, 0x16, 0x0e, 0x28, 0x1b, 0x6d, 0x0c, 0xaa, 0x88,
+	0x95, 0x53, 0x97, 0x1c, 0xb6, 0xb7, 0x8c, 0xfe, 0x9c, 0x26, 0x16, 0x98,
+	0x9c, 0xd7, 0x44, 0xf6, 0x80, 0xb2, 0x85, 0xf9, 0xef, 0xb5, 0xfd, 0xa6,
+	0x55, 0x6a, 0x63, 0x71, 0x28, 0x36, 0x9b, 0x3e, 0x17, 0x1e, 0x14, 0x7d,
+	0x96, 0x17, 0x89, 0x3e, 0x8b, 0xb4, 0xcb, 0xd9, 0x49, 0x41, 0xef, 0x3f,
+	0x2e, 0xca, 0xd9, 0xc3, 0xdf, 0x17, 0xe7, 0x72, 0xc9, 0xc2, 0xbc, 0x5b,
+	0x56, 0x9f, 0x5e, 0x98, 0x7b, 0xf2, 0xd8, 0x6a, 0x59, 0x6f, 0x03, 0x63,
+	0x48, 0x15, 0x79, 0x8e, 0xac, 0x45, 0x4c, 0xc5, 0x1b, 0xc4, 0x8a, 0x8d,
+	0x50, 0x60, 0x96, 0x7a, 0x51, 0xfe, 0xea, 0x75, 0xd8, 0xf6, 0x67, 0xda,
+	0x98, 0x75, 0xf8, 0x3c, 0xf6, 0x4c, 0x14, 0x4b, 0x0c, 0xdd, 0x93, 0x90,
+	0xbe, 0x41, 0x2d, 0x92, 0x3e, 0x23, 0x77, 0x0f, 0xa3, 0xb2, 0x9e, 0x77,
+	0x39, 0xbb, 0x53, 0xb1, 0x72, 0xc0, 0x89, 0x2e, 0xfd, 0xbf, 0x48, 0xcc,
+	0x64, 0x3f, 0xea, 0xe8, 0x6f, 0x2a, 0xfe, 0x76, 0x80, 0xf1, 0x25, 0x72,
+	0x37, 0x4c, 0xe2, 0xad, 0x6b, 0xd4, 0x89, 0x15, 0x89, 0x65, 0x7c, 0xee,
+	0x86, 0x3a, 0x4a, 0x56, 0xd1, 0xeb, 0x36, 0x2b, 0x68, 0x33, 0xb2, 0xff,
+	0xd2, 0x3c, 0x66, 0xe2, 0xf0, 0x3c, 0x3f, 0x52, 0x09, 0x59, 0x3f, 0x5d,
+	0x82, 0x9d, 0xa9, 0xd0, 0xaa, 0xb3, 0x8a, 0x1f, 0xc9, 0xac, 0x0b, 0x26,
+	0xe7, 0xbe, 0x9b, 0x7d, 0xf3, 0xf4, 0x7a, 0xd1, 0x3d, 0x54, 0xcd, 0xcf,
+	0xc4, 0x67, 0x3d, 0xc4, 0xea, 0x6e, 0xce, 0x6d, 0xf7, 0x90, 0x07, 0x47,
+	0xf7, 0xb8, 0x51, 0x96, 0x82, 0xf2, 0xec, 0x3c, 0xa2, 0x8d, 0xd6, 0x88,
+	0x17, 0x46, 0x3c, 0x28, 0x25, 0xa7, 0x7d, 0x7e, 0xc4, 0x8b, 0x92, 0xad,
+	0xb4, 0x87, 0x5d, 0x55, 0x28, 0xde, 0xea, 0xc6, 0x73, 0x99, 0x6a, 0xb8,
+	0xb6, 0xde, 0x81, 0xf5, 0x99, 0x69, 0x50, 0xb7, 0x56, 0x63, 0x62, 0x97,
+	0x0f, 0x33, 0x76, 0x18, 0x78, 0x63, 0x4f, 0x0d, 0x6a, 0x77, 0xdc, 0x8c,
+	0x9f, 0xee, 0xf1, 0xa3, 0x92, 0xba, 0x79, 0x79, 0xc4, 0x29, 0xfc, 0x93,
+	0xf3, 0x74, 0xa0, 0x38, 0xbf, 0x6f, 0x1c, 0xbb, 0x94, 0xaf, 0x42, 0x29,
+	0xcc, 0x0d, 0x90, 0xc9, 0xca, 0xfa, 0x68, 0x63, 0x4b, 0x77, 0x62, 0xe4,
+	0x5f, 0x8b, 0x8d, 0x5f, 0xfd, 0x9f, 0xb7, 0xa3, 0x0d, 0xc4, 0x32, 0xf1,
+	0xff, 0x15, 0xab, 0x4b, 0x8c, 0x8e, 0x87, 0xc3, 0xf3, 0x8a, 0xb1, 0xca,
+	0x9e, 0x8f, 0x95, 0xe4, 0x80, 0xcb, 0xd1, 0xbd, 0xa3, 0xa1, 0xed, 0x1e,
+	0xc5, 0x87, 0x58, 0x55, 0x3f, 0xef, 0xa9, 0x79, 0x9f, 0x82, 0x2a, 0xf9,
+	0xba, 0xac, 0x99, 0xa9, 0xa3, 0x8b, 0xf2, 0x7b, 0xa0, 0x3e, 0x7b, 0x0d,
+	0xaa, 0x3b, 0x55, 0xd0, 0xe3, 0x98, 0x65, 0xda, 0xfb, 0x5a, 0xe2, 0xe3,
+	0x4e, 0xac, 0x4c, 0x8c, 0x32, 0x47, 0x11, 0x5d, 0x4a, 0x5f, 0x37, 0x52,
+	0x8e, 0xf4, 0x57, 0x9e, 0x37, 0xc4, 0xaa, 0x3e, 0xb6, 0xbf, 0x85, 0x71,
+	0x75, 0xb3, 0xfc, 0x67, 0xdd, 0x28, 0x95, 0xb2, 0xd2, 0xf7, 0x7a, 0xfe,
+	0x96, 0xfe, 0x5a, 0xd6, 0xc6, 0x8b, 0xe2, 0x54, 0x51, 0xac, 0x94, 0x71,
+	0x6a, 0x7f, 0x22, 0x14, 0x7b, 0x97, 0x78, 0x76, 0x2c, 0xeb, 0x24, 0xf7,
+	0x11, 0xbb, 0x59, 0x47, 0x7b, 0xe9, 0x51, 0x8e, 0x9e, 0xb7, 0x99, 0x42,
+	0x2e, 0xb0, 0x04, 0xe9, 0xd4, 0x54, 0x5f, 0x92, 0xfd, 0x6e, 0x27, 0x5c,
+	0xbd, 0x05, 0xdc, 0x64, 0xac, 0x19, 0x25, 0xbf, 0xcb, 0x3a, 0xe0, 0xe8,
+	0xa7, 0x3d, 0xe8, 0x2a, 0xc7, 0x58, 0xc4, 0x39, 0xaf, 0xe6, 0xc7, 0x6d,
+	0x56, 0x1a, 0x26, 0x4e, 0xcd, 0x2b, 0xc1, 0xa1, 0x5d, 0x57, 0xa1, 0xbc,
+	0x7f, 0xdc, 0xf2, 0xf0, 0x5e, 0xa9, 0x31, 0x1f, 0x4f, 0x44, 0x42, 0xad,
+	0xab, 0x15, 0x13, 0xad, 0xf3, 0xdc, 0x28, 0xd9, 0xe5, 0x40, 0x71, 0x3f,
+	0x79, 0x83, 0x7e, 0x03, 0xc6, 0x7d, 0x39, 0x3c, 0x57, 0x7b, 0x67, 0xdb,
+	0x76, 0x75, 0xcd, 0xa8, 0xdb, 0xf4, 0x1b, 0x13, 0x37, 0xaa, 0x8c, 0xed,
+	0xc5, 0xc3, 0x1e, 0x14, 0xf5, 0x9a, 0x98, 0x71, 0x83, 0xe0, 0x51, 0x23,
+	0x8a, 0x68, 0xaf, 0xae, 0x5e, 0x1f, 0xf3, 0xea, 0x3a, 0xb8, 0xc8, 0xed,
+	0x1c, 0xdb, 0x0d, 0x38, 0xc8, 0xc3, 0xd4, 0xed, 0x37, 0x43, 0x65, 0xd9,
+	0x13, 0x7c, 0x7e, 0x82, 0xfc, 0xf3, 0x04, 0xef, 0x9d, 0x18, 0xae, 0xe1,
+	0xa7, 0x0a, 0xb5, 0xbb, 0xcb, 0x10, 0x5b, 0x2a, 0xeb, 0xac, 0x0e, 0x54,
+	0xf7, 0x8b, 0x7f, 0xaa, 0xb8, 0xab, 0x49, 0x81, 0x7e, 0x1d, 0xdb, 0x9c,
+	0x79, 0x39, 0x5f, 0xbd, 0xd3, 0x8d, 0x8a, 0x2e, 0xb6, 0x77, 0xa9, 0x2f,
+	0x4b, 0xac, 0xba, 0x30, 0x07, 0x01, 0x55, 0x62, 0xb7, 0xcc, 0xd9, 0x27,
+	0xf9, 0xbd, 0x1b, 0xce, 0x5e, 0x99, 0x6b, 0x19, 0xe3, 0x37, 0xdd, 0x39,
+	0x5e, 0x7b, 0xd1, 0x5a, 0x3b, 0xb2, 0x89, 0x25, 0xd8, 0x62, 0x9f, 0x5d,
+	0x08, 0xc0, 0x33, 0x12, 0x6c, 0xcd, 0xe0, 0xf4, 0xb9, 0x9e, 0x94, 0x13,
+	0xf7, 0x26, 0xe5, 0x0c, 0x87, 0x9c, 0x33, 0xe0, 0x58, 0x47, 0xdc, 0x78,
+	0xb0, 0xcf, 0x2d, 0x6b, 0xdc, 0x01, 0x97, 0x56, 0x8b, 0x77, 0x33, 0x82,
+	0x79, 0x25, 0x38, 0x9c, 0xf6, 0xe3, 0x84, 0xfd, 0xbb, 0x94, 0x18, 0x6c,
+	0xa1, 0x45, 0x2f, 0x47, 0xb7, 0xb7, 0x04, 0xc9, 0xf0, 0xcd, 0xc8, 0xdc,
+	0xc5, 0x1c, 0x9a, 0xb6, 0x59, 0x41, 0x4e, 0x41, 0xb7, 0x63, 0x6e, 0xe0,
+	0x40, 0x2a, 0xfc, 0x39, 0x4c, 0x56, 0x39, 0xa9, 0x3f, 0x59, 0x9f, 0x50,
+	0xb1, 0x93, 0x56, 0x45, 0xfc, 0x8b, 0x89, 0xdd, 0x96, 0x27, 0x61, 0x55,
+	0x18, 0x5a, 0x7c, 0x54, 0x09, 0xb5, 0xaf, 0xa7, 0xdf, 0x96, 0x8d, 0x94,
+	0x11, 0x8f, 0x67, 0xa1, 0x74, 0x97, 0xd8, 0xaf, 0x87, 0xd8, 0x70, 0xbd,
+	0xec, 0x07, 0x84, 0x03, 0x8a, 0x07, 0xf7, 0x0d, 0x08, 0xae, 0x2e, 0x47,
+	0xd1, 0x9e, 0x0a, 0x3c, 0x9c, 0x76, 0x12, 0xfb, 0xdc, 0xa8, 0xdd, 0x25,
+	0x3e, 0x5f, 0x89, 0xca, 0xad, 0x07, 0x2d, 0xbf, 0x56, 0x82, 0x4a, 0x5e,
+	0x3f, 0x46, 0x5d, 0x7c, 0x90, 0xfa, 0x1a, 0x46, 0x13, 0xf5, 0x94, 0xdb,
+	0xce, 0xf1, 0xf9, 0xf0, 0x5e, 0xaa, 0x91, 0xb2, 0xfd, 0x78, 0x77, 0x87,
+	0x65, 0xb5, 0x44, 0x62, 0x70, 0x8e, 0x5c, 0x89, 0x5f, 0xf2, 0xf7, 0x71,
+	0xbd, 0x05, 0xea, 0x48, 0x1d, 0xde, 0x4c, 0xb5, 0xc2, 0x31, 0x52, 0x81,
+	0xb3, 0x5b, 0x45, 0xa6, 0x1b, 0x95, 0x7d, 0x5a, 0xf8, 0x0c, 0x6d, 0xdf,
+	0xb5, 0x8b, 0x81, 0xbf, 0x46, 0xda, 0x2f, 0xcc, 0x4f, 0x8e, 0xef, 0x1d,
+	0xcc, 0xcf, 0xcd, 0x38, 0x0a, 0xdc, 0xe9, 0x07, 0xd6, 0x63, 0x4c, 0x67,
+	0x5c, 0xd1, 0x20, 0xba, 0xc3, 0xc7, 0x64, 0xbf, 0x9c, 0xe3, 0x8b, 0x11,
+	0xf3, 0x9f, 0xb5, 0xe4, 0xdc, 0x81, 0x8b, 0xf6, 0x59, 0xac, 0x1d, 0xb2,
+	0x36, 0x2e, 0x93, 0xfb, 0x3f, 0xe7, 0x9c, 0x30, 0x41, 0x31, 0x44, 0xe6,
+	0x16, 0x99, 0x4b, 0xa2, 0xf1, 0xe5, 0x64, 0xfe, 0xa3, 0xf5, 0xe8, 0xf9,
+	0xf2, 0xf0, 0xba, 0xec, 0x75, 0x70, 0x59, 0x87, 0x95, 0xb9, 0x94, 0xf5,
+	0xca, 0x00, 0x56, 0x8d, 0x78, 0xed, 0xdc, 0xf9, 0xdd, 0x84, 0xcc, 0x9f,
+	0x9c, 0xa1, 0xf1, 0x90, 0x9b, 0xe8, 0x28, 0xe5, 0xdc, 0x7d, 0x90, 0x80,
+	0x72, 0x5b, 0xb4, 0x0d, 0xe5, 0xc4, 0xb5, 0x77, 0x12, 0xc1, 0x55, 0x26,
+	0x12, 0x6c, 0x2b, 0x8a, 0x12, 0xd6, 0x79, 0x33, 0xe1, 0x60, 0xbc, 0x6d,
+	0xe6, 0x98, 0xbd, 0xb0, 0x6c, 0xae, 0xbc, 0x0c, 0x33, 0xa8, 0xa7, 0xb3,
+	0x09, 0x03, 0xb5, 0xd4, 0xd3, 0x99, 0x84, 0x13, 0x67, 0xa8, 0x97, 0x53,
+	0x89, 0x00, 0x2a, 0x18, 0x98, 0x8a, 0xfa, 0x2c, 0x4c, 0xe8, 0x95, 0x72,
+	0x3e, 0x02, 0x72, 0xfe, 0xc5, 0x9f, 0xd4, 0x51, 0x9b, 0xac, 0x5f, 0x53,
+	0xeb, 0x70, 0x60, 0xd2, 0xe6, 0x2c, 0x4e, 0xe6, 0xcd, 0xa2, 0x1f, 0x19,
+	0x93, 0x9d, 0xab, 0xb7, 0xca, 0xa1, 0xa6, 0x83, 0x1c, 0x4f, 0x40, 0x29,
+	0x8c, 0x67, 0x19, 0x40, 0x59, 0xa3, 0x89, 0x30, 0x1e, 0x62, 0x5b, 0x6f,
+	0x27, 0x5e, 0xc1, 0xad, 0xfc, 0x7e, 0x3f, 0xf1, 0x23, 0x2c, 0x61, 0x3f,
+	0xde, 0x23, 0x6e, 0xdc, 0x1f, 0xba, 0xad, 0x04, 0xa5, 0x75, 0x58, 0x34,
+	0x72, 0xfa, 0x5c, 0xb7, 0x3d, 0xce, 0x42, 0x4e, 0xe5, 0xc6, 0xfd, 0xe9,
+	0xc2, 0x59, 0xa6, 0x18, 0x7d, 0x58, 0xf0, 0xd5, 0xcd, 0x1c, 0x1e, 0x68,
+	0x4b, 0x7c, 0x23, 0x77, 0x4e, 0x47, 0x95, 0xcf, 0x79, 0x3d, 0x3a, 0x51,
+	0xea, 0xcf, 0xfb, 0x95, 0xf4, 0xe7, 0x93, 0xca, 0x5c, 0xe0, 0xcc, 0xa3,
+	0xb6, 0x7e, 0x65, 0x7d, 0x3e, 0x80, 0xeb, 0x88, 0xe7, 0x27, 0xc9, 0xa1,
+	0x19, 0x93, 0xb1, 0x7a, 0xde, 0x0a, 0xf4, 0xec, 0x11, 0x9d, 0x06, 0xdb,
+	0xd9, 0x87, 0xb6, 0x0c, 0x56, 0x22, 0xb9, 0xc7, 0xc3, 0x31, 0x88, 0xde,
+	0xc9, 0x43, 0xf7, 0xd0, 0xff, 0xd3, 0x7f, 0x83, 0x75, 0xbb, 0xa6, 0xe1,
+	0xad, 0xf4, 0x97, 0xb0, 0x9e, 0x36, 0xe4, 0xa0, 0xef, 0xac, 0xd0, 0xaf,
+	0x42, 0x6e, 0x3f, 0xc3, 0xc7, 0x39, 0x78, 0x9f, 0xbe, 0xb5, 0x0e, 0xef,
+	0x64, 0x67, 0x61, 0x46, 0x9f, 0x8a, 0xc9, 0x69, 0x0a, 0xed, 0x43, 0xf6,
+	0x5e, 0xdc, 0xc4, 0xb7, 0xaf, 0x40, 0xdd, 0x65, 0x62, 0x7d, 0xd4, 0x8d,
+	0xdd, 0xcc, 0x2d, 0x56, 0xc8, 0x7a, 0x98, 0x5d, 0xaf, 0x19, 0x7b, 0x39,
+	0x17, 0x89, 0x04, 0x79, 0x8b, 0x37, 0xa7, 0xe7, 0xf8, 0xf4, 0x62, 0xd6,
+	0xb9, 0xa7, 0xc4, 0xde, 0xcb, 0x50, 0x04, 0x1f, 0x44, 0xcf, 0x05, 0x1d,
+	0x7f, 0x0d, 0x37, 0x26, 0xdf, 0xa7, 0x1d, 0x84, 0xc6, 0xaf, 0x75, 0xfc,
+	0x4f, 0xea, 0x72, 0x1d, 0xe7, 0xf1, 0x6f, 0x30, 0x94, 0xf6, 0xd0, 0x8f,
+	0x64, 0xef, 0x69, 0x2d, 0x8e, 0x6e, 0x8b, 0x33, 0x37, 0x09, 0xea, 0x19,
+	0xf2, 0xfa, 0x4c, 0x95, 0x65, 0x39, 0x22, 0x71, 0x0c, 0x0e, 0x58, 0xd6,
+	0x62, 0x3d, 0xd6, 0x5c, 0x42, 0xfd, 0xde, 0x8f, 0xfd, 0xac, 0xe7, 0xc3,
+	0x91, 0xa1, 0x15, 0xbc, 0x2f, 0x3c, 0x78, 0x2d, 0x1e, 0xe6, 0xf3, 0x2f,
+	0xe9, 0xb1, 0xf1, 0x19, 0x08, 0x72, 0xce, 0x73, 0xcf, 0xc7, 0x86, 0x56,
+	0x7e, 0x4c, 0xbd, 0x0b, 0xfa, 0x7c, 0x22, 0xaf, 0xcf, 0x52, 0xea, 0xf3,
+	0xf6, 0x91, 0xf7, 0xcf, 0x6d, 0x48, 0x05, 0x63, 0x19, 0xc6, 0x98, 0xb7,
+	0xa8, 0xb7, 0x8d, 0xb4, 0x57, 0xe6, 0x1a, 0x38, 0x92, 0x6d, 0xa6, 0x6e,
+	0x5c, 0xe4, 0x44, 0x4e, 0x1c, 0xcb, 0x1a, 0xb4, 0x4d, 0x60, 0x21, 0xe3,
+	0x85, 0xe9, 0xcd, 0xd9, 0x4f, 0xe6, 0xbc, 0x3f, 0x70, 0xee, 0x94, 0x66,
+	0x1c, 0x4f, 0xc8, 0xd8, 0xa5, 0x9c, 0xfd, 0x5c, 0xd6, 0x80, 0xa7, 0x94,
+	0xb9, 0xd0, 0xf6, 0xee, 0x84, 0xf0, 0xf4, 0x00, 0x65, 0x15, 0x53, 0xd6,
+	0xe9, 0x73, 0x9b, 0x52, 0x6d, 0xf6, 0xd9, 0x37, 0xf2, 0x1b, 0x84, 0x69,
+	0xcf, 0xc5, 0x91, 0x32, 0xbc, 0xed, 0x13, 0x19, 0x39, 0x5d, 0x0a, 0x06,
+	0x6e, 0x61, 0x19, 0x79, 0xfe, 0x20, 0x9f, 0xdf, 0x12, 0x29, 0xc2, 0x90,
+	0xb7, 0xb0, 0xee, 0x94, 0xeb, 0x8b, 0x79, 0xbe, 0x9d, 0x6b, 0x2b, 0x73,
+	0x76, 0x55, 0x5c, 0x6a, 0xef, 0x25, 0xd9, 0xdc, 0xaa, 0xee, 0x92, 0xfd,
+	0x3a, 0x89, 0x7f, 0x82, 0x93, 0x39, 0x9c, 0x2d, 0xa1, 0x3d, 0x3d, 0x97,
+	0x90, 0x75, 0x21, 0x93, 0x39, 0x46, 0x18, 0x8b, 0xb2, 0xf6, 0x99, 0x2e,
+	0xc6, 0x37, 0xea, 0x8c, 0xbc, 0x77, 0x65, 0x54, 0xf6, 0xe3, 0x6e, 0xae,
+	0x14, 0x5e, 0xd7, 0x11, 0x95, 0x7c, 0x42, 0x6c, 0xb5, 0x70, 0xcf, 0x8d,
+	0x3d, 0xf9, 0x39, 0x0f, 0xa8, 0x9f, 0x84, 0xfd, 0xaf, 0x5f, 0xc2, 0xf1,
+	0x0a, 0x7b, 0x5a, 0xd2, 0xaf, 0xf3, 0x5c, 0xcf, 0xe6, 0xf5, 0x43, 0xf4,
+	0x37, 0xd3, 0x59, 0x46, 0x7e, 0x27, 0xbc, 0x3e, 0xa4, 0xcf, 0x52, 0x85,
+	0xd3, 0x4b, 0x4e, 0x21, 0x6b, 0x7b, 0x3d, 0xca, 0xde, 0xac, 0xac, 0xef,
+	0x09, 0x9f, 0xbf, 0xdc, 0x1a, 0x9f, 0x9c, 0x8d, 0x93, 0xf8, 0x78, 0xfa,
+	0x5c, 0x7f, 0xaa, 0xcd, 0xde, 0x07, 0x5d, 0xd0, 0x6f, 0xe1, 0x6e, 0xc6,
+	0x82, 0x7b, 0xaa, 0xed, 0x1c, 0x29, 0x9f, 0x8b, 0x9c, 0x3e, 0xb7, 0x33,
+	0xf5, 0x7b, 0x4b, 0xb5, 0xf7, 0x1d, 0x5d, 0x70, 0x6c, 0xd5, 0xce, 0xac,
+	0x20, 0xe7, 0x3b, 0x7b, 0x83, 0xe4, 0x25, 0x2e, 0xc6, 0xc9, 0xff, 0x52,
+	0x2a, 0x7b, 0xe0, 0xe4, 0xcb, 0xb8, 0xa5, 0x3f, 0x86, 0x21, 0xfd, 0x43,
+	0xcb, 0xf4, 0x4d, 0xad, 0xef, 0xc2, 0x92, 0xfe, 0xdf, 0x5b, 0xe5, 0x76,
+	0x7d, 0xad, 0x3d, 0xa9, 0xa8, 0x78, 0x70, 0x9e, 0x0b, 0xb7, 0x0d, 0x86,
+	0xb0, 0xb8, 0x5f, 0x45, 0x78, 0x9e, 0xc8, 0x09, 0xa1, 0x75, 0xb0, 0xde,
+	0x99, 0x5f, 0xd7, 0xc1, 0x22, 0xf6, 0xe3, 0x6d, 0xbd, 0x0c, 0xaf, 0x11,
+	0x77, 0x2b, 0x6c, 0x9e, 0xbd, 0x46, 0x49, 0x09, 0xcf, 0x76, 0xa9, 0x98,
+	0xa6, 0xc1, 0x5b, 0x6d, 0xc4, 0xc8, 0xb1, 0x5b, 0x94, 0xad, 0x99, 0x35,
+	0x4a, 0x7f, 0xb6, 0xd0, 0xbe, 0x07, 0x77, 0x8c, 0x7a, 0x71, 0xc7, 0xde,
+	0x6a, 0x7e, 0x7c, 0xfc, 0xd4, 0xf0, 0xf3, 0x8d, 0xd2, 0xdc, 0xfe, 0xfc,
+	0x12, 0xac, 0x4b, 0x15, 0xec, 0xca, 0xc9, 0xbc, 0x5a, 0x6c, 0x57, 0xea,
+	0x04, 0xb0, 0x97, 0xfc, 0xfc, 0x64, 0x5a, 0xb8, 0xfd, 0x06, 0xea, 0x42,
+	0xd6, 0x99, 0x8b, 0xc9, 0xef, 0xe5, 0x3c, 0x63, 0x24, 0xbf, 0xef, 0x9f,
+	0xb3, 0x1b, 0x9c, 0xb7, 0x1b, 0x17, 0xde, 0xa1, 0x7f, 0xcf, 0x8a, 0xfc,
+	0xbb, 0x35, 0xe9, 0xbd, 0x60, 0x57, 0x17, 0x9e, 0x17, 0xf8, 0xd0, 0xe9,
+	0x73, 0xe9, 0xd4, 0x54, 0x7b, 0x52, 0x50, 0xd4, 0x2f, 0x7c, 0x59, 0xf4,
+	0xe2, 0xc4, 0xab, 0xc4, 0x07, 0x67, 0xff, 0xc4, 0xb5, 0x42, 0xeb, 0x5c,
+	0x7b, 0x63, 0xe8, 0x8e, 0x52, 0xb7, 0x83, 0xa5, 0xc5, 0x39, 0xfb, 0xc8,
+	0xe9, 0x22, 0xa0, 0x0a, 0xbe, 0x78, 0x6c, 0x9e, 0x17, 0x60, 0x2e, 0xa8,
+	0xee, 0x15, 0xce, 0x58, 0xcd, 0x6f, 0xe1, 0xe6, 0xe4, 0x2f, 0x7b, 0x85,
+	0xa7, 0xd7, 0xf0, 0x9b, 0x24, 0xbf, 0x46, 0xec, 0x69, 0x25, 0x7a, 0x18,
+	0x13, 0x8b, 0x43, 0x2b, 0xb1, 0x71, 0xf8, 0x72, 0xb6, 0x95, 0xcb, 0x77,
+	0x0e, 0x5e, 0xb0, 0x6f, 0x69, 0x8f, 0x7d, 0x3a, 0x7d, 0x4e, 0x6c, 0x35,
+	0xc0, 0xb9, 0xda, 0x9d, 0x96, 0x3e, 0x58, 0xe8, 0xd0, 0xc9, 0x8d, 0xe8,
+	0x6b, 0x6a, 0xb5, 0xdc, 0x9f, 0xca, 0x29, 0x0b, 0xb2, 0xa6, 0xde, 0xdb,
+	0x55, 0x2a, 0xeb, 0xec, 0x17, 0xc6, 0x5e, 0x68, 0x43, 0xd6, 0x55, 0x03,
+	0xa8, 0xea, 0x15, 0x3d, 0xca, 0x98, 0x02, 0x70, 0x92, 0x03, 0x56, 0x8d,
+	0x5e, 0x4e, 0x1e, 0x6a, 0x4a, 0xec, 0xf3, 0x83, 0x61, 0xfa, 0x99, 0xc7,
+	0x2c, 0x26, 0x5f, 0x7c, 0x3b, 0x21, 0xe7, 0x32, 0x5b, 0x5b, 0x76, 0x27,
+	0x66, 0x7a, 0x0f, 0xe7, 0xf3, 0xfe, 0x15, 0x70, 0x93, 0xa3, 0x9a, 0x98,
+	0x88, 0x2a, 0x36, 0xde, 0x38, 0xb4, 0x10, 0x16, 0x32, 0xb7, 0xbc, 0x25,
+	0x23, 0xf3, 0xb9, 0x26, 0xbf, 0x26, 0x24, 0xed, 0xc5, 0x94, 0xa1, 0xac,
+	0xe4, 0x05, 0xf0, 0x3a, 0x8d, 0x16, 0x65, 0x5f, 0x46, 0xea, 0xaf, 0xe1,
+	0xbd, 0xc2, 0x9e, 0xf1, 0x12, 0xf4, 0xa7, 0x0a, 0xbe, 0x55, 0xd0, 0x47,
+	0x05, 0x6d, 0x55, 0xf2, 0x3e, 0x13, 0xfa, 0xf5, 0xb5, 0x68, 0x1c, 0x2c,
+	0xc7, 0xed, 0xfd, 0xb9, 0xfd, 0xfa, 0x86, 0xc1, 0x6a, 0xdc, 0xb6, 0x7d,
+	0x39, 0x4a, 0xf7, 0x7a, 0xb1, 0x78, 0xbb, 0xec, 0x0d, 0x2c, 0x43, 0xf1,
+	0xe8, 0xaf, 0x4a, 0xed, 0x9c, 0xbb, 0xb7, 0x99, 0x73, 0xd4, 0x4c, 0xce,
+	0x19, 0x6c, 0x8e, 0x41, 0xd6, 0x3a, 0x0d, 0x14, 0x8d, 0x1a, 0xe4, 0xa6,
+	0x56, 0xe7, 0x0c, 0x83, 0xf3, 0xcc, 0x7e, 0x5e, 0xc3, 0xbc, 0x67, 0x16,
+	0xc7, 0xee, 0xe2, 0xc7, 0xd1, 0x6b, 0x59, 0x67, 0x6f, 0x40, 0x67, 0x19,
+	0xf3, 0x70, 0xc7, 0xe8, 0x55, 0x08, 0x0c, 0x36, 0xa2, 0x76, 0xb4, 0x1a,
+	0xda, 0xa0, 0x0f, 0xad, 0xbd, 0xe2, 0x8b, 0xc1, 0x40, 0x5c, 0x8d, 0xc2,
+	0x3d, 0xca, 0x38, 0xdd, 0xfb, 0x7b, 0xeb, 0x24, 0xe7, 0xba, 0x99, 0x3a,
+	0xbb, 0xb3, 0xb7, 0x15, 0x95, 0xa3, 0xb4, 0xf3, 0xfe, 0x3b, 0x50, 0x31,
+	0xe8, 0x26, 0x4f, 0x0e, 0x20, 0x4b, 0x5e, 0xec, 0x19, 0xf4, 0xa3, 0xb4,
+	0x57, 0x6b, 0xbd, 0x5d, 0x41, 0x6c, 0x26, 0x73, 0xa9, 0x22, 0xb6, 0xe5,
+	0xa2, 0x0f, 0x0d, 0xd2, 0x97, 0x17, 0xd2, 0xcd, 0x3b, 0x7b, 0x05, 0x77,
+	0x44, 0x27, 0x67, 0x6d, 0x9b, 0x5e, 0xd9, 0x7b, 0xf9, 0x33, 0xa3, 0x38,
+	0x7f, 0x66, 0xd4, 0xb4, 0xcf, 0x72, 0x56, 0x1a, 0x50, 0xce, 0xcc, 0xd2,
+	0x7a, 0x6a, 0x79, 0xef, 0x43, 0xc6, 0xfd, 0xaf, 0xf6, 0x7a, 0x18, 0x7f,
+	0x3a, 0xf1, 0xb9, 0xa6, 0xa0, 0x39, 0xaa, 0xbc, 0xc2, 0xf1, 0xff, 0x88,
+	0x01, 0xb7, 0x8e, 0xfd, 0xfc, 0x73, 0xe5, 0x5f, 0xba, 0x26, 0x36, 0xef,
+	0xa2, 0xb5, 0xb4, 0x23, 0xcc, 0x9f, 0xc7, 0x2f, 0x5a, 0x4b, 0x13, 0x2c,
+	0xbd, 0xf4, 0x4c, 0x6d, 0x60, 0xca, 0xfa, 0x8c, 0xcc, 0x99, 0xcc, 0x53,
+	0x61, 0x7d, 0xc6, 0x44, 0xd3, 0xf5, 0x2e, 0x2c, 0xec, 0x97, 0x9c, 0x47,
+	0x62, 0x71, 0x88, 0xb9, 0xc6, 0x66, 0xce, 0x83, 0xbd, 0xae, 0xc2, 0x7b,
+	0x01, 0xe2, 0x4b, 0x80, 0x39, 0x44, 0x92, 0xf7, 0x4a, 0x70, 0x5b, 0x7f,
+	0xb5, 0xbd, 0x87, 0xb5, 0x38, 0x72, 0x15, 0xc2, 0x55, 0xb2, 0xbe, 0x76,
+	0x61, 0x1d, 0x66, 0x0e, 0x73, 0x95, 0x32, 0x1b, 0xbb, 0x16, 0x50, 0xd7,
+	0x57, 0xd1, 0x26, 0x72, 0x78, 0x75, 0xfb, 0x60, 0x0e, 0x97, 0x7a, 0xd9,
+	0xff, 0x71, 0x57, 0xce, 0xde, 0xd2, 0xb4, 0x37, 0xaf, 0xd6, 0xa2, 0xa4,
+	0x33, 0x0d, 0xde, 0x69, 0x97, 0x3d, 0x8b, 0x01, 0x6f, 0xa5, 0x51, 0x38,
+	0x27, 0x4c, 0x4c, 0xcb, 0x3e, 0x58, 0x96, 0xcf, 0xdb, 0x3e, 0xa6, 0xfc,
+	0xc7, 0xe9, 0xeb, 0xfa, 0x3f, 0x51, 0x5f, 0x72, 0xae, 0xac, 0xa0, 0x2f,
+	0x6d, 0xca, 0xd9, 0x88, 0x9c, 0xce, 0xaa, 0x0d, 0x39, 0x4b, 0x78, 0x41,
+	0x67, 0x77, 0x51, 0x67, 0xf5, 0xe7, 0x75, 0x76, 0x5d, 0x5e, 0x67, 0x25,
+	0xd4, 0x59, 0x35, 0x71, 0x57, 0x30, 0xf9, 0x5a, 0x62, 0xf2, 0xb7, 0xec,
+	0x7b, 0xb3, 0xa9, 0x97, 0x9c, 0xce, 0x34, 0xea, 0x6c, 0x2a, 0xde, 0x5f,
+	0x85, 0x76, 0xe2, 0x7d, 0x05, 0xe3, 0x61, 0x99, 0x9c, 0xed, 0xba, 0xe1,
+	0x2a, 0xdc, 0x39, 0x58, 0x82, 0xb9, 0x83, 0x2e, 0xea, 0xd2, 0x8e, 0x01,
+	0xe4, 0xf4, 0xae, 0xf3, 0x7a, 0x6c, 0x18, 0x94, 0x71, 0xad, 0x51, 0x7e,
+	0xc8, 0x71, 0x05, 0x8a, 0x72, 0x7a, 0x7c, 0x25, 0x9b, 0xeb, 0x43, 0xb5,
+	0x26, 0xf1, 0xac, 0x45, 0x79, 0x35, 0x23, 0x38, 0xfb, 0x3d, 0xea, 0x6a,
+	0x0d, 0x9f, 0x35, 0x78, 0x7d, 0xe0, 0x58, 0x3e, 0xf6, 0xbc, 0x9f, 0xe8,
+	0xeb, 0x7b, 0xe7, 0xf5, 0xfa, 0xc7, 0xcb, 0x16, 0xec, 0x4a, 0xce, 0xfb,
+	0x15, 0xf4, 0xa5, 0x4d, 0xc1, 0x48, 0xcb, 0x7a, 0x5a, 0x9f, 0x85, 0x78,
+	0x75, 0x30, 0x2d, 0x6b, 0x46, 0x69, 0xf2, 0x1d, 0x47, 0xaf, 0xf4, 0x59,
+	0x72, 0x03, 0xf5, 0x66, 0xb2, 0xbf, 0x46, 0x07, 0x3a, 0x71, 0x42, 0xd7,
+	0x7a, 0xee, 0xc3, 0xa7, 0xd0, 0xe5, 0xb3, 0xb0, 0x47, 0x6f, 0x67, 0xee,
+	0x53, 0x8a, 0x55, 0x8d, 0x34, 0xf9, 0xbb, 0x62, 0xe8, 0x4b, 0x99, 0xed,
+	0x0e, 0xc8, 0x9a, 0xec, 0xf7, 0xbf, 0x90, 0x08, 0x05, 0xdb, 0x56, 0x2b,
+	0xc0, 0xe2, 0xa4, 0x1b, 0x01, 0xc5, 0xe6, 0x26, 0xe1, 0x7e, 0x55, 0xd6,
+	0x96, 0xb7, 0x17, 0xe5, 0xce, 0x6a, 0xa8, 0x08, 0xd4, 0x48, 0x3b, 0xed,
+	0x30, 0xc7, 0xa4, 0x2e, 0xf5, 0x38, 0x53, 0xc1, 0x6d, 0x33, 0x83, 0x66,
+	0x5c, 0xb1, 0xac, 0xa5, 0x11, 0xa7, 0xfd, 0x7c, 0xcb, 0x58, 0x43, 0xfc,
+	0x6e, 0xf5, 0xe7, 0x96, 0x69, 0xaf, 0x67, 0x07, 0xbd, 0x31, 0xf5, 0x8f,
+	0x8d, 0x93, 0x79, 0x03, 0x73, 0x84, 0xfd, 0xf9, 0x35, 0x5c, 0x97, 0x11,
+	0x5e, 0xbe, 0xc7, 0x5e, 0x47, 0xfe, 0x96, 0x7d, 0x2e, 0x25, 0x9d, 0x92,
+	0x35, 0xc0, 0xa8, 0x07, 0xa5, 0xed, 0xe8, 0x1a, 0xbb, 0x01, 0x23, 0x8d,
+	0xbf, 0xb0, 0x32, 0xb9, 0xbe, 0x8b, 0x79, 0xbb, 0x6b, 0x8d, 0x13, 0x5f,
+	0xb8, 0x71, 0x96, 0x70, 0x47, 0x39, 0x43, 0x4a, 0xde, 0xae, 0xe4, 0xb8,
+	0xec, 0x0c, 0xed, 0x16, 0x1c, 0xbc, 0x48, 0xa6, 0xac, 0x31, 0x14, 0x64,
+	0xb6, 0x51, 0x9e, 0xc8, 0x75, 0x51, 0x57, 0xff, 0x6e, 0x0d, 0xfa, 0xa6,
+	0x96, 0xfb, 0x47, 0x77, 0x2e, 0xc6, 0x49, 0xb9, 0x42, 0xbb, 0xc2, 0xed,
+	0x3e, 0xb0, 0x86, 0x2e, 0x2a, 0xf7, 0x6a, 0x9e, 0x33, 0x3d, 0xe4, 0x91,
+	0x33, 0x2d, 0xe9, 0x54, 0x31, 0xf9, 0xd4, 0x09, 0x6b, 0xef, 0x45, 0x65,
+	0x3e, 0xbc, 0xa4, 0x4c, 0x3d, 0x73, 0xb5, 0x7f, 0xb1, 0x86, 0x2f, 0x2a,
+	0x53, 0x59, 0x7a, 0x71, 0x99, 0x6b, 0x88, 0xb3, 0xaf, 0x5a, 0xbb, 0x2f,
+	0x2a, 0xf3, 0x77, 0x97, 0xc8, 0x99, 0x4b, 0x1b, 0x7f, 0xda, 0xda, 0x97,
+	0x2f, 0xe3, 0x64, 0x99, 0x75, 0xda, 0x53, 0xf9, 0xbc, 0xbc, 0x50, 0xa6,
+	0x70, 0xbf, 0xa4, 0xec, 0xd2, 0xfb, 0x39, 0x99, 0xe1, 0x4b, 0x64, 0x06,
+	0x4d, 0x99, 0x6f, 0x57, 0x53, 0x61, 0xbe, 0xa3, 0xf9, 0xfb, 0xdf, 0x28,
+	0xbb, 0xb8, 0xdc, 0xc4, 0x25, 0xd7, 0x05, 0x79, 0x7f, 0xed, 0xbe, 0xf8,
+	0x7e, 0x65, 0xf1, 0xc5, 0xd7, 0xbb, 0x8b, 0x72, 0xd7, 0x05, 0x9d, 0x6e,
+	0xb9, 0xe4, 0xf9, 0x7f, 0x2b, 0xba, 0xf8, 0xfa, 0xc6, 0xe2, 0xcb, 0xb7,
+	0xf3, 0x93, 0x4b, 0xee, 0x2b, 0x5d, 0xf2, 0xfe, 0x89, 0xc3, 0x50, 0x2b,
+	0xba, 0xa2, 0xab, 0x6e, 0x8a, 0x67, 0x7b, 0x68, 0x9f, 0x62, 0x5b, 0xab,
+	0x6f, 0x5a, 0x91, 0x3d, 0x79, 0x7e, 0x8f, 0x3b, 0xad, 0x2f, 0xf0, 0x7b,
+	0xf1, 0x59, 0xac, 0xb0, 0xf7, 0xd2, 0x64, 0x8d, 0xc7, 0xe4, 0x18, 0xed,
+	0x77, 0x51, 0xdc, 0x8a, 0x11, 0x87, 0x6e, 0x9f, 0x07, 0x5d, 0x89, 0xfa,
+	0xac, 0xbd, 0x8f, 0x17, 0x8e, 0xe3, 0xa0, 0xda, 0xaa, 0x99, 0xf9, 0x73,
+	0x7e, 0xe6, 0x8d, 0x5e, 0xc4, 0xa6, 0xe6, 0xd2, 0x81, 0x61, 0xfb, 0x2c,
+	0x69, 0x07, 0xba, 0xed, 0x73, 0xaa, 0xed, 0xf9, 0xf3, 0xa4, 0xcb, 0xa1,
+	0x65, 0x0b, 0x7c, 0x4b, 0xd6, 0x64, 0xe5, 0x6c, 0x85, 0x45, 0x1f, 0x14,
+	0xfe, 0x70, 0x40, 0x51, 0x93, 0xf6, 0xba, 0xe7, 0x32, 0x07, 0x42, 0xcd,
+	0x2d, 0x0a, 0xe2, 0x25, 0x46, 0x28, 0xf0, 0x4e, 0x1e, 0x2b, 0x5d, 0x23,
+	0xeb, 0x94, 0xa2, 0x91, 0x1e, 0xc5, 0x39, 0x92, 0xc3, 0x4a, 0xc7, 0x88,
+	0xf0, 0xfb, 0x6a, 0x96, 0xf1, 0x62, 0xd6, 0x3c, 0x27, 0x5e, 0x48, 0x54,
+	0xd8, 0xef, 0x34, 0xac, 0x9f, 0x57, 0x84, 0x07, 0x23, 0x0a, 0x5a, 0xe7,
+	0x1c, 0xc6, 0x49, 0xe6, 0x32, 0x87, 0x13, 0x66, 0x64, 0x88, 0x6d, 0x4e,
+	0x24, 0x54, 0x1c, 0x1a, 0x58, 0x17, 0x19, 0xb4, 0xdb, 0x37, 0xd1, 0x6d,
+	0xef, 0x5b, 0x2d, 0xb3, 0x36, 0xa6, 0x96, 0x5b, 0x1b, 0x52, 0x4e, 0xe6,
+	0x9f, 0xd5, 0xf1, 0x4a, 0xd6, 0x3f, 0x39, 0x6f, 0x15, 0x4e, 0xb1, 0xcc,
+	0x48, 0x62, 0x35, 0x3e, 0xc8, 0x7a, 0xed, 0xf5, 0x9a, 0x1f, 0x64, 0x3d,
+	0xcc, 0xa7, 0x5a, 0xf1, 0x42, 0x76, 0x19, 0x9e, 0x1f, 0x90, 0x33, 0xe4,
+	0x2d, 0x58, 0x90, 0x50, 0xb0, 0x38, 0xb4, 0x0c, 0xc7, 0x86, 0x96, 0xe1,
+	0xf0, 0x80, 0xbc, 0x47, 0x70, 0x45, 0xfe, 0xcc, 0xb9, 0x3c, 0x8f, 0xf1,
+	0xf9, 0x52, 0x4c, 0x0c, 0xf9, 0x99, 0x0b, 0xe9, 0x78, 0x33, 0xeb, 0xc3,
+	0x60, 0xa2, 0x11, 0xc7, 0xc9, 0xe7, 0x9f, 0x49, 0x34, 0xe3, 0x2c, 0xaf,
+	0x0f, 0x24, 0x84, 0x07, 0x45, 0x71, 0x26, 0xfb, 0x7d, 0x14, 0x25, 0x6b,
+	0x71, 0xa4, 0xed, 0x69, 0xa8, 0xc9, 0x03, 0xfc, 0xb4, 0xe2, 0xf8, 0x50,
+	0x2b, 0x4e, 0x0c, 0xdc, 0x86, 0x13, 0x43, 0x3f, 0xc3, 0xc9, 0x01, 0xe9,
+	0xaf, 0x9c, 0x2b, 0x17, 0xb9, 0x1a, 0xe5, 0x2e, 0xc3, 0xf8, 0xd0, 0x9f,
+	0x23, 0xfb, 0x3d, 0xeb, 0xc8, 0x32, 0x91, 0xfb, 0xf4, 0x27, 0xc8, 0xce,
+	0xe5, 0x4a, 0x72, 0x66, 0xf4, 0x58, 0xc2, 0x8d, 0xa3, 0x89, 0xf1, 0x6b,
+	0x4b, 0x30, 0x7e, 0x23, 0x91, 0x0e, 0x1b, 0x99, 0xc3, 0x1d, 0x4a, 0xcb,
+	0xba, 0xdf, 0x67, 0x98, 0x17, 0xaf, 0xc3, 0xfa, 0xb1, 0x62, 0xbc, 0x90,
+	0x76, 0x53, 0xc7, 0x37, 0x22, 0x56, 0xd5, 0x4e, 0xfd, 0x79, 0xf0, 0x62,
+	0xc2, 0x87, 0x97, 0x12, 0x0d, 0x8c, 0x0f, 0x4d, 0xc8, 0xad, 0x77, 0x7a,
+	0xa8, 0xef, 0x0e, 0xbb, 0x4f, 0x2f, 0x24, 0x96, 0x59, 0xeb, 0xa9, 0xe3,
+	0x9e, 0xd4, 0xd7, 0xec, 0x33, 0xe1, 0xcf, 0x27, 0xce, 0x30, 0x27, 0x39,
+	0x8a, 0xc7, 0xa9, 0xd3, 0x63, 0x89, 0x38, 0x39, 0x63, 0x1d, 0xe7, 0x68,
+	0x1c, 0x43, 0xd9, 0xb5, 0x78, 0x33, 0xad, 0x1d, 0x5d, 0x81, 0xb5, 0x38,
+	0x9b, 0x29, 0xc6, 0xeb, 0x6c, 0xa3, 0x72, 0xae, 0x13, 0x93, 0xb6, 0xbc,
+	0xb5, 0xf8, 0x20, 0xad, 0x30, 0x8e, 0xaf, 0xc5, 0xfb, 0x7c, 0xf6, 0x32,
+	0x7f, 0x9f, 0x8a, 0xb0, 0x87, 0xf9, 0x67, 0x27, 0xc8, 0xeb, 0x65, 0x7d,
+	0xab, 0x2b, 0xba, 0x16, 0xc7, 0x33, 0xcf, 0x92, 0x0b, 0x57, 0xe2, 0x61,
+	0x7d, 0x1a, 0x9a, 0xa7, 0x91, 0x8b, 0x69, 0xc5, 0x38, 0xc6, 0xe7, 0x33,
+	0x89, 0xbf, 0xe3, 0xde, 0x5c, 0xf9, 0xf7, 0x38, 0x9e, 0x07, 0x29, 0xeb,
+	0xdd, 0xcc, 0x37, 0x29, 0x77, 0x3e, 0xb2, 0x91, 0x6f, 0x52, 0xee, 0xcf,
+	0x30, 0x9c, 0xd7, 0xc7, 0x71, 0x5d, 0xc6, 0xf5, 0xf5, 0x72, 0xc9, 0xa9,
+	0x27, 0x12, 0xdf, 0xe0, 0x77, 0x07, 0x26, 0xb3, 0x3b, 0xf8, 0xfd, 0x03,
+	0xec, 0x63, 0x8c, 0x4e, 0xa4, 0x2e, 0xe5, 0xe3, 0xd3, 0xb1, 0xa9, 0xaf,
+	0x22, 0x5e, 0x45, 0xfb, 0x89, 0x5c, 0x5f, 0x89, 0xd9, 0x91, 0x04, 0x36,
+	0xef, 0x76, 0x62, 0x13, 0xf1, 0x76, 0x73, 0xb2, 0x1a, 0x3b, 0xb7, 0x79,
+	0x91, 0xda, 0x76, 0x25, 0x7a, 0xb7, 0x5d, 0x8d, 0xe4, 0xb6, 0x3a, 0x6c,
+	0xdc, 0x46, 0x9d, 0xcf, 0xb5, 0xac, 0x93, 0x11, 0xcb, 0x3a, 0xcc, 0xcf,
+	0x5e, 0x7e, 0xde, 0xd3, 0xc5, 0x3f, 0x62, 0x08, 0xdb, 0x7e, 0xd2, 0x42,
+	0x3f, 0x91, 0x6f, 0x0d, 0xd7, 0x64, 0xd7, 0x44, 0x66, 0x8e, 0xae, 0x8d,
+	0x34, 0x8c, 0x4e, 0x47, 0x77, 0x5f, 0x0d, 0xd6, 0x6f, 0xab, 0x8e, 0x7b,
+	0xd9, 0x8e, 0xf7, 0x7a, 0x0b, 0x9d, 0xf4, 0x9f, 0x67, 0xf4, 0x9e, 0xc8,
+	0xfc, 0xd1, 0xa7, 0xc9, 0x43, 0x7d, 0xd8, 0xd9, 0xe7, 0x67, 0x1b, 0x0a,
+	0x2a, 0x35, 0xe7, 0xaa, 0x4a, 0x8e, 0xe3, 0x68, 0xe4, 0x00, 0xca, 0x47,
+	0xbf, 0x4f, 0x9e, 0xe7, 0xc3, 0xc6, 0xbe, 0x22, 0x79, 0x4f, 0x08, 0xbd,
+	0x51, 0x0b, 0xef, 0xe9, 0xe3, 0x28, 0xa3, 0xbc, 0xae, 0xbe, 0x0a, 0x74,
+	0x6f, 0xf3, 0x50, 0x66, 0x05, 0x1e, 0xdb, 0x56, 0x1a, 0x2f, 0x32, 0x44,
+	0xde, 0x12, 0xfc, 0x74, 0xe4, 0x6b, 0xd8, 0x34, 0xe6, 0x41, 0x0f, 0xef,
+	0xaf, 0xdb, 0xe6, 0x75, 0xbf, 0xc0, 0x3a, 0xed, 0x6c, 0xeb, 0xbf, 0xf1,
+	0xf3, 0x01, 0xfb, 0x5d, 0x1c, 0x59, 0x83, 0xcd, 0x63, 0xc2, 0x6d, 0x8e,
+	0xc2, 0x3f, 0xda, 0x8a, 0x97, 0x47, 0xda, 0xf0, 0xb7, 0x23, 0xff, 0xea,
+	0x41, 0xc5, 0x32, 0xdc, 0x3f, 0x22, 0xfb, 0xee, 0x71, 0xdc, 0x93, 0x10,
+	0x3c, 0x5a, 0x89, 0x3d, 0x09, 0xd9, 0xbf, 0x6c, 0xc7, 0xb3, 0x09, 0xb1,
+	0xdf, 0xe5, 0xb4, 0xdf, 0x0e, 0xe6, 0x74, 0x92, 0x47, 0x64, 0x22, 0xf5,
+	0xa3, 0xdf, 0x8e, 0x5c, 0x33, 0xfa, 0x73, 0x72, 0xf0, 0xa1, 0x48, 0x68,
+	0x74, 0x27, 0xc7, 0x39, 0x49, 0x5e, 0x7d, 0x82, 0x5c, 0xfb, 0x75, 0x72,
+	0xe1, 0x42, 0x1c, 0xfc, 0xaf, 0xce, 0x5c, 0x8e, 0x52, 0xc8, 0x03, 0x0b,
+	0x6b, 0xed, 0x96, 0xe5, 0x60, 0x9e, 0xb3, 0xd0, 0x2b, 0xb9, 0x42, 0x17,
+	0xd6, 0xef, 0x58, 0x8d, 0x0d, 0x3b, 0x1a, 0xbc, 0x7b, 0x19, 0xb3, 0x62,
+	0x3e, 0xe1, 0xee, 0xf9, 0xfc, 0xee, 0xfc, 0x1a, 0x98, 0xac, 0xd9, 0x77,
+	0xd0, 0xe7, 0xd7, 0xd9, 0xe7, 0x38, 0x4b, 0x35, 0x04, 0x4a, 0xb4, 0xdf,
+	0x5a, 0xb1, 0xf3, 0xf5, 0xdb, 0x2d, 0x59, 0x97, 0x2d, 0x36, 0x14, 0x8c,
+	0x69, 0x6d, 0xf6, 0x7e, 0xd8, 0x71, 0x9b, 0x8f, 0x75, 0x21, 0x35, 0x4c,
+	0x6e, 0xbc, 0x4b, 0xc6, 0xb1, 0x52, 0xc6, 0x61, 0xaa, 0xda, 0x32, 0x6b,
+	0x5d, 0x0a, 0xb7, 0x16, 0x31, 0xbf, 0x58, 0x35, 0x52, 0x84, 0xf8, 0x9e,
+	0x52, 0xdc, 0xb3, 0x6d, 0xb9, 0x95, 0x4a, 0x09, 0xff, 0x96, 0x3c, 0xbb,
+	0x14, 0x9d, 0xbc, 0xb7, 0xa6, 0x4f, 0xf6, 0x21, 0x42, 0x1d, 0xb5, 0x8e,
+	0x52, 0x3c, 0xb4, 0x8b, 0xfd, 0xd8, 0xb5, 0x04, 0xf1, 0x5d, 0x47, 0x60,
+	0x66, 0x54, 0x8c, 0x0c, 0x38, 0xe1, 0x37, 0x4e, 0x93, 0x6f, 0xfd, 0x0c,
+	0xc9, 0x21, 0x15, 0xd9, 0x01, 0x45, 0xdb, 0x18, 0x1a, 0xc5, 0xc6, 0x21,
+	0x27, 0xf6, 0x26, 0x5a, 0xf0, 0x36, 0x71, 0x6e, 0x30, 0x11, 0xc3, 0x71,
+	0xea, 0x76, 0x72, 0xcf, 0x32, 0x7e, 0x3c, 0xf4, 0xf7, 0x83, 0xf4, 0x9d,
+	0x30, 0xba, 0xe9, 0x47, 0x07, 0x13, 0x1a, 0x1e, 0xcb, 0xde, 0x0c, 0x73,
+	0xe8, 0x0e, 0x6c, 0x1e, 0x32, 0xf1, 0xe8, 0x8e, 0x36, 0x7e, 0x1b, 0x78,
+	0x74, 0xe8, 0x6b, 0x58, 0x33, 0x72, 0x14, 0x9b, 0xb2, 0x71, 0xbc, 0x33,
+	0xf2, 0x2c, 0x92, 0x69, 0x9d, 0xbe, 0x21, 0xdc, 0x4d, 0xc1, 0xe6, 0x79,
+	0xcf, 0x62, 0x73, 0xe6, 0x30, 0x36, 0xa6, 0x3b, 0xc9, 0x09, 0x0f, 0x63,
+	0x03, 0x7f, 0xaf, 0x4f, 0x6b, 0xfe, 0x41, 0x1c, 0x46, 0x77, 0x66, 0x2d,
+	0x3a, 0xfb, 0x44, 0x5f, 0x0a, 0xce, 0xde, 0xb0, 0x16, 0x0f, 0xef, 0xea,
+	0xc0, 0x03, 0x23, 0x3f, 0xc0, 0xce, 0xec, 0xb3, 0xe8, 0x4d, 0x27, 0x90,
+	0xda, 0x2a, 0xfa, 0xac, 0xc4, 0x0f, 0x22, 0x78, 0xa0, 0x12, 0xa1, 0xb6,
+	0xa4, 0x22, 0xb2, 0xd6, 0x60, 0x13, 0xfd, 0x7a, 0x63, 0x4a, 0xf4, 0xfb,
+	0x34, 0xdb, 0x3c, 0x40, 0xbc, 0x58, 0x43, 0x7d, 0x3c, 0xc2, 0x4f, 0x61,
+	0xcf, 0x76, 0xea, 0x3e, 0x83, 0xf8, 0x8b, 0xdf, 0xce, 0xe5, 0x4b, 0x7b,
+	0x25, 0xaf, 0x1c, 0x0f, 0x96, 0x92, 0x8b, 0x94, 0xf4, 0x8a, 0x3e, 0xdb,
+	0xad, 0xae, 0xd4, 0xf8, 0x67, 0x4b, 0x20, 0x73, 0x10, 0x20, 0x76, 0xff,
+	0x0c, 0xeb, 0xe9, 0x8f, 0xb7, 0xca, 0xe1, 0x15, 0xc6, 0xa1, 0x43, 0xf4,
+	0xe7, 0xb8, 0xcf, 0xb2, 0x9e, 0xd2, 0x59, 0xad, 0xb7, 0x83, 0x78, 0xe5,
+	0xca, 0xef, 0xc5, 0x8d, 0x5f, 0x5b, 0x41, 0x19, 0xe5, 0xbd, 0x5d, 0x72,
+	0xe6, 0x45, 0xcf, 0xe5, 0xbc, 0x96, 0xb5, 0x25, 0x54, 0xb0, 0x9f, 0xf1,
+	0x6b, 0xcb, 0x31, 0x4d, 0xd6, 0x8f, 0x9b, 0x73, 0xef, 0xc1, 0x9d, 0x63,
+	0x5c, 0xec, 0xc2, 0x96, 0xe1, 0xb6, 0xbc, 0x1d, 0xfd, 0xbf, 0x92, 0x77,
+	0xb9, 0x3d, 0xbe, 0x6b, 0xec, 0x75, 0x1f, 0xd8, 0x67, 0xea, 0x81, 0x7b,
+	0x13, 0xb2, 0x6f, 0xa2, 0xde, 0x40, 0x56, 0x45, 0x0b, 0x2d, 0xc6, 0x61,
+	0xfd, 0x4a, 0x74, 0x93, 0x77, 0xde, 0xa2, 0x17, 0x61, 0xb8, 0xd1, 0xc0,
+	0xa4, 0xd7, 0x6c, 0x13, 0xce, 0x56, 0x66, 0x8c, 0xb7, 0x7f, 0x39, 0x14,
+	0x94, 0xbc, 0x10, 0x61, 0x62, 0x08, 0x6c, 0xce, 0xd6, 0x83, 0x64, 0x4a,
+	0x81, 0x47, 0xbb, 0x03, 0xd9, 0x2a, 0x9f, 0xb4, 0x1f, 0x2e, 0x9c, 0xbf,
+	0x2c, 0xd6, 0xce, 0xe5, 0xdf, 0x7d, 0x5b, 0xc2, 0xf9, 0xa0, 0x6d, 0xcf,
+	0xb4, 0xac, 0xb6, 0x48, 0x00, 0xf5, 0xa1, 0x86, 0x40, 0x95, 0xfa, 0x0b,
+	0xcb, 0x94, 0x3d, 0xa9, 0x31, 0x39, 0x0f, 0x78, 0xb9, 0xfc, 0xfd, 0x21,
+	0x6c, 0xdc, 0x3a, 0x07, 0x93, 0x3e, 0x91, 0xf9, 0x44, 0x79, 0x4e, 0x8e,
+	0xac, 0x5f, 0xbc, 0x5a, 0x81, 0xd2, 0x1e, 0xfa, 0x4a, 0x0f, 0x7a, 0x52,
+	0x2a, 0xdb, 0x78, 0xd3, 0x2a, 0x9e, 0x2e, 0xe3, 0xfe, 0x1f, 0x15, 0xb9,
+	0x32, 0xaf, 0x55, 0x08, 0xbf, 0xd8, 0x94, 0xea, 0xa1, 0xee, 0x54, 0xc6,
+	0x9b, 0x7f, 0xb1, 0x8e, 0xf8, 0xaa, 0xf9, 0x3c, 0x9e, 0x97, 0xb1, 0x4e,
+	0xd6, 0xd1, 0xf4, 0x18, 0xe4, 0xde, 0x2b, 0x2c, 0x2b, 0xfa, 0xea, 0xa1,
+	0x1e, 0x1c, 0xe4, 0x9e, 0x3e, 0x74, 0x7a, 0x73, 0x6b, 0x34, 0x17, 0xc6,
+	0x21, 0x65, 0x64, 0x2c, 0x3d, 0x48, 0xa5, 0x64, 0x1f, 0xe3, 0xac, 0x75,
+	0x6a, 0xba, 0x3c, 0x2f, 0xc9, 0xb7, 0x57, 0x6b, 0xef, 0xad, 0x3d, 0x9a,
+	0x72, 0x4c, 0xe9, 0x9b, 0xd4, 0xb5, 0x65, 0xb3, 0xfe, 0xa7, 0x2e, 0x69,
+	0xd7, 0x6b, 0x73, 0x72, 0xd5, 0x9e, 0xa7, 0x57, 0xf2, 0xe5, 0xcb, 0xcb,
+	0x0b, 0xef, 0x2f, 0xc8, 0xd9, 0xde, 0x0b, 0x6d, 0x4f, 0x2d, 0x23, 0x6b,
+	0x01, 0xb9, 0xba, 0xcd, 0x3b, 0x0a, 0xf2, 0x2d, 0xab, 0x68, 0x6e, 0x3b,
+	0x6d, 0xd4, 0xea, 0x2c, 0x26, 0x46, 0xbe, 0x1d, 0xf5, 0x63, 0x7d, 0x42,
+	0x74, 0xa4, 0xf9, 0xf7, 0x12, 0x03, 0xba, 0x6d, 0x4e, 0xe1, 0x42, 0x57,
+	0xa6, 0x70, 0xde, 0x44, 0xd6, 0x3d, 0xe5, 0xdc, 0x9a, 0xbc, 0x87, 0x43,
+	0x2e, 0xe5, 0x5d, 0x10, 0x70, 0x92, 0x0f, 0xdd, 0x8b, 0xff, 0xe0, 0x5c,
+	0xc8, 0xfb, 0x24, 0xb9, 0x35, 0x91, 0x38, 0x6d, 0x20, 0x17, 0x93, 0x40,
+	0x5f, 0x27, 0x17, 0xca, 0x9f, 0xb3, 0xef, 0xca, 0xfe, 0x87, 0x35, 0x6e,
+	0x9f, 0xb3, 0xbf, 0x70, 0xa6, 0x23, 0xe3, 0x95, 0x77, 0x39, 0x31, 0xe5,
+	0xcc, 0x3d, 0x63, 0x88, 0x26, 0x67, 0xf3, 0x7f, 0x67, 0xad, 0xb8, 0xa8,
+	0xec, 0x78, 0x55, 0xee, 0x1d, 0x94, 0x98, 0xba, 0x40, 0x2b, 0xf0, 0x3b,
+	0xd9, 0x57, 0x12, 0x5e, 0x77, 0x77, 0x65, 0x6e, 0xbd, 0x35, 0xd8, 0xda,
+	0x06, 0xd9, 0xdb, 0x2e, 0xf0, 0x35, 0x4d, 0x9f, 0xad, 0x74, 0x62, 0x56,
+	0xa4, 0x54, 0xde, 0xa9, 0x0d, 0x3a, 0x8d, 0xa0, 0xf7, 0x24, 0x42, 0xe1,
+	0xc3, 0xf6, 0x59, 0x0c, 0xf1, 0x6d, 0x0d, 0xf7, 0x66, 0x1b, 0xa9, 0x1b,
+	0x79, 0x1f, 0x5a, 0x7e, 0xdb, 0xf2, 0xf9, 0x1b, 0xee, 0x72, 0x62, 0xfb,
+	0x48, 0xd2, 0xfc, 0xaf, 0x2e, 0x5b, 0x5e, 0xb0, 0x7d, 0xc8, 0x7e, 0x57,
+	0xa9, 0x20, 0xcf, 0x73, 0x19, 0x79, 0x61, 0xd6, 0x0f, 0x53, 0x96, 0xc8,
+	0xd0, 0x28, 0xe3, 0xd2, 0xf3, 0x39, 0xd3, 0xe3, 0x92, 0x23, 0xef, 0xcb,
+	0xf3, 0xbe, 0xc3, 0x7f, 0x90, 0x23, 0x5f, 0xb6, 0xcd, 0x18, 0xdb, 0x6c,
+	0x2d, 0x55, 0x62, 0x11, 0x79, 0x57, 0xa8, 0x38, 0x12, 0x0a, 0x3f, 0x47,
+	0xe7, 0x74, 0x1a, 0x21, 0xff, 0x90, 0x7d, 0x66, 0x44, 0x77, 0x2f, 0xcc,
+	0xe6, 0xf2, 0x29, 0x73, 0xec, 0x93, 0x75, 0x52, 0xa6, 0x69, 0x6d, 0x0d,
+	0x4a, 0xec, 0x46, 0x22, 0x38, 0xc2, 0x11, 0x04, 0x8a, 0x8c, 0x82, 0x8e,
+	0x42, 0xe1, 0x93, 0x9c, 0xcf, 0x89, 0x68, 0x88, 0x78, 0x29, 0x5c, 0x49,
+	0xf4, 0xa2, 0xbb, 0x73, 0x73, 0xdf, 0x28, 0x9c, 0xda, 0x74, 0x31, 0xee,
+	0x0d, 0x27, 0x64, 0x9d, 0xab, 0xc1, 0xbb, 0x11, 0x55, 0xb4, 0x57, 0xc4,
+	0xba, 0x1b, 0xe3, 0xd8, 0x97, 0x40, 0xcc, 0x31, 0xa7, 0x12, 0x71, 0x92,
+	0x64, 0x87, 0x16, 0x27, 0xef, 0x69, 0x08, 0x6f, 0xa2, 0x0d, 0xca, 0xd9,
+	0x46, 0x13, 0x71, 0x1c, 0x4a, 0x2c, 0xf8, 0x4b, 0x07, 0x4c, 0xbd, 0x0c,
+	0xf2, 0xae, 0x16, 0xbe, 0x78, 0x5b, 0x28, 0x18, 0x78, 0x3e, 0x7f, 0xe6,
+	0xa5, 0x2b, 0xf1, 0x91, 0xbd, 0xa7, 0xe5, 0xd0, 0x3e, 0xa9, 0x8c, 0xdb,
+	0x5e, 0xc7, 0xdd, 0x9b, 0xfe, 0x36, 0xd6, 0x6d, 0x65, 0x1f, 0x99, 0xdf,
+	0x2f, 0xd0, 0x3b, 0xb1, 0x50, 0xf7, 0x60, 0xa5, 0x77, 0x56, 0xb3, 0x9c,
+	0xe9, 0x19, 0xcc, 0xe4, 0xd6, 0x3d, 0xd6, 0xdb, 0x67, 0x6a, 0x06, 0xb0,
+	0x99, 0x3e, 0x56, 0xa2, 0xc9, 0xb9, 0xab, 0x98, 0xb2, 0x39, 0xdb, 0xa2,
+	0x6c, 0xca, 0xaf, 0xb3, 0xf5, 0x64, 0x5f, 0xaf, 0x44, 0xa9, 0x89, 0xe3,
+	0xba, 0xbc, 0x23, 0x29, 0x72, 0x4d, 0x0c, 0x45, 0xff, 0x94, 0x77, 0x25,
+	0x45, 0xa7, 0x6b, 0xd0, 0x3d, 0xf0, 0x08, 0xba, 0x06, 0x5e, 0xb4, 0xcf,
+	0xb6, 0xba, 0x34, 0xb7, 0x79, 0xb5, 0x11, 0x3c, 0x60, 0xe2, 0x69, 0xaf,
+	0xac, 0xe7, 0xd6, 0x18, 0x47, 0xb1, 0xd9, 0x2b, 0xef, 0x00, 0x0e, 0x90,
+	0x03, 0x08, 0xce, 0x2d, 0xc7, 0x97, 0x93, 0x32, 0x87, 0x15, 0xc4, 0xfc,
+	0x60, 0x6c, 0xa5, 0x3d, 0x87, 0x8d, 0x38, 0x36, 0xfa, 0x08, 0xde, 0xde,
+	0xde, 0x09, 0x35, 0x12, 0xf4, 0x2f, 0x82, 0xd5, 0x79, 0x44, 0x8f, 0x99,
+	0x2e, 0x04, 0xf7, 0x39, 0x54, 0xe0, 0xe0, 0x76, 0xc9, 0x69, 0xdb, 0x71,
+	0x23, 0x63, 0x6d, 0xa5, 0x66, 0xcd, 0xff, 0xb7, 0xb9, 0xc1, 0x1e, 0xcd,
+	0x61, 0xfe, 0xf3, 0x74, 0x04, 0xd3, 0xcd, 0xaa, 0xd6, 0x7e, 0xa7, 0x0a,
+	0xc5, 0x63, 0xc8, 0x7b, 0xeb, 0x9d, 0xb8, 0xa3, 0xc9, 0x63, 0x96, 0x1b,
+	0xc1, 0xf4, 0x8b, 0x4a, 0x30, 0x6c, 0xaa, 0x9f, 0xe7, 0x3c, 0x87, 0xf1,
+	0xfc, 0xa8, 0x17, 0xad, 0xbd, 0x3a, 0x16, 0xf7, 0x36, 0xda, 0xb8, 0xa5,
+	0x6a, 0xf5, 0xcd, 0x25, 0x8a, 0x17, 0x8b, 0x46, 0x81, 0x89, 0xcc, 0x72,
+	0xbc, 0xb9, 0x5d, 0x47, 0x0b, 0x9f, 0xf5, 0xa5, 0x9e, 0xaa, 0x94, 0xb3,
+	0x6f, 0x1d, 0xba, 0xd9, 0xa0, 0x22, 0x74, 0xd4, 0xa5, 0x62, 0xc1, 0x0c,
+	0x23, 0x34, 0x3e, 0xdf, 0xe1, 0x44, 0xf3, 0xa8, 0x13, 0x77, 0xb1, 0xcc,
+	0x46, 0x62, 0xfa, 0x9d, 0xbd, 0x6e, 0xf2, 0x87, 0x3a, 0x7c, 0x48, 0xae,
+	0xfb, 0x2b, 0x72, 0xda, 0x49, 0xc6, 0xe6, 0xc9, 0x6c, 0x29, 0xda, 0xfa,
+	0x5d, 0x72, 0x8e, 0x67, 0xdc, 0xc5, 0xb9, 0xa8, 0x68, 0xf2, 0xe1, 0xd4,
+	0x90, 0x1b, 0x9f, 0xdb, 0x1e, 0xdc, 0x39, 0xa9, 0xd6, 0xe0, 0x83, 0xa1,
+	0x52, 0x7b, 0xbd, 0xb2, 0xdc, 0xb0, 0xb0, 0x85, 0x38, 0xfd, 0x1e, 0x9f,
+	0xb5, 0x6c, 0x87, 0x92, 0x9d, 0x77, 0x0d, 0x79, 0xb9, 0xc6, 0xfa, 0x65,
+	0xb8, 0xad, 0x5f, 0xd6, 0x68, 0x54, 0xbc, 0x33, 0xa4, 0xe0, 0x64, 0x46,
+	0xc7, 0x02, 0xb6, 0xd7, 0x9d, 0x3a, 0x68, 0xb9, 0xe9, 0xe7, 0x2b, 0xb2,
+	0x3a, 0xee, 0xcb, 0x34, 0xa2, 0x37, 0xf5, 0x06, 0x39, 0x50, 0x13, 0xde,
+	0xd8, 0xa6, 0x1d, 0x7d, 0xcb, 0x11, 0x1a, 0x9f, 0xe7, 0x68, 0xc2, 0xeb,
+	0x7b, 0x9a, 0xf0, 0xc3, 0xbe, 0xf9, 0xf8, 0x74, 0x53, 0x0c, 0xa7, 0xe7,
+	0x35, 0xe1, 0x95, 0x5d, 0x8d, 0xc4, 0xe8, 0x28, 0x02, 0x23, 0xe3, 0xd8,
+	0x92, 0x6c, 0x46, 0xc3, 0x88, 0x01, 0xad, 0xcf, 0xea, 0x2c, 0x33, 0x3a,
+	0xb1, 0x59, 0x37, 0x30, 0x7b, 0x97, 0xe8, 0xc1, 0xb2, 0x56, 0xce, 0x33,
+	0xf0, 0x5c, 0x5a, 0xa3, 0x9f, 0x1a, 0xd4, 0x43, 0x23, 0x71, 0xd6, 0x40,
+	0x68, 0xab, 0x76, 0x66, 0x37, 0xaf, 0xe7, 0xef, 0x8e, 0xa2, 0x9d, 0xed,
+	0x27, 0x52, 0x31, 0xec, 0x1c, 0x69, 0xe4, 0x98, 0x75, 0x8e, 0xbf, 0xde,
+	0xfc, 0x50, 0x69, 0x41, 0x7a, 0xa4, 0x15, 0xbd, 0x7d, 0x9d, 0x78, 0x31,
+	0xd2, 0x8a, 0x24, 0x65, 0xad, 0x4f, 0xe9, 0xb8, 0xad, 0xb7, 0x15, 0xfb,
+	0x13, 0x72, 0x96, 0x5e, 0x6b, 0xbe, 0x5e, 0x09, 0xe9, 0x27, 0xd1, 0x8a,
+	0xbd, 0xd4, 0xc9, 0x82, 0xfe, 0x25, 0xf6, 0xb9, 0xa1, 0x85, 0xdb, 0x1b,
+	0xf1, 0x58, 0xea, 0x0e, 0xbc, 0x39, 0xac, 0xa3, 0xad, 0x57, 0xf4, 0x2d,
+	0xe7, 0x27, 0xe3, 0x38, 0x92, 0x5a, 0x8b, 0x0f, 0xfb, 0x63, 0xff, 0xcc,
+	0x69, 0x3e, 0xa6, 0xda, 0xfb, 0x5d, 0x2a, 0xae, 0x6b, 0x92, 0x73, 0xad,
+	0x0e, 0xa2, 0x5a, 0xd0, 0xac, 0x54, 0xcd, 0x00, 0xef, 0x9b, 0x4e, 0x75,
+	0x2d, 0xfe, 0xb6, 0xdf, 0x49, 0xde, 0xae, 0x32, 0xdf, 0x30, 0x3b, 0x68,
+	0x1b, 0x66, 0x85, 0x9a, 0x9b, 0x37, 0x7b, 0x7f, 0x40, 0x73, 0x40, 0xce,
+	0xbd, 0x96, 0xb1, 0xde, 0xe2, 0x48, 0x30, 0x56, 0xa2, 0x46, 0xc9, 0x27,
+	0x1e, 0xc1, 0xca, 0xed, 0x8f, 0x60, 0x05, 0x3f, 0x1d, 0xdb, 0xad, 0xce,
+	0x5b, 0x75, 0x05, 0x87, 0x34, 0xab, 0xb3, 0x53, 0xd7, 0x38, 0xb7, 0x32,
+	0xaf, 0x8f, 0x60, 0xcd, 0xde, 0x47, 0xf0, 0x15, 0xda, 0x57, 0x35, 0xfd,
+	0x78, 0x69, 0xaf, 0xd5, 0xf9, 0xe9, 0xa6, 0x30, 0x7e, 0x6d, 0xe7, 0x18,
+	0x62, 0xaf, 0x5b, 0xec, 0xbc, 0x37, 0xa3, 0xca, 0xef, 0xbf, 0xb7, 0x7f,
+	0x9b, 0xea, 0x2b, 0xf9, 0xbd, 0xa8, 0x35, 0xf8, 0x88, 0x72, 0x7f, 0xb3,
+	0xbd, 0x12, 0x5b, 0xab, 0x25, 0x66, 0xb8, 0xcd, 0x12, 0x03, 0x8a, 0x36,
+	0x8f, 0xb9, 0xd4, 0xd6, 0x23, 0x36, 0xdf, 0xf2, 0x45, 0x24, 0xcf, 0x6d,
+	0xd0, 0xd7, 0xa9, 0x37, 0x13, 0xdb, 0xc9, 0xc5, 0x66, 0x7e, 0x1b, 0x49,
+	0xfa, 0xea, 0x96, 0x99, 0xc1, 0x78, 0x12, 0x86, 0xb5, 0x65, 0xfa, 0xc0,
+	0x9f, 0xf1, 0x7e, 0x6c, 0x61, 0xdf, 0x4d, 0xde, 0x91, 0x7d, 0x04, 0x9d,
+	0xdb, 0x65, 0xfe, 0x1f, 0xc1, 0xc3, 0xec, 0xff, 0x9a, 0xfe, 0x47, 0xf0,
+	0x10, 0x6d, 0xa7, 0x6a, 0xee, 0xc4, 0xc3, 0x55, 0x98, 0xc5, 0x4c, 0x68,
+	0xfc, 0x81, 0x6a, 0x39, 0xf3, 0x4a, 0x4c, 0x4c, 0x2a, 0x8f, 0xe0, 0xde,
+	0xc1, 0xfd, 0xf4, 0x45, 0xdb, 0xff, 0x88, 0xc5, 0x85, 0x78, 0xe5, 0xc7,
+	0xca, 0x6c, 0x5d, 0x1e, 0xd7, 0x7d, 0x58, 0x91, 0x78, 0xd2, 0xf6, 0xfd,
+	0x22, 0x63, 0x09, 0xfd, 0xbe, 0x95, 0x7e, 0xdf, 0x42, 0xbf, 0x8f, 0xd1,
+	0xef, 0x0d, 0xfa, 0x7d, 0x33, 0xfd, 0x3e, 0x4a, 0xbf, 0xd7, 0xe9, 0xf7,
+	0x8d, 0xf4, 0xfb, 0xb0, 0xec, 0x47, 0x28, 0x47, 0xa3, 0x47, 0xe0, 0xea,
+	0x73, 0xd3, 0x86, 0x72, 0xef, 0x3d, 0xee, 0x21, 0xfe, 0x1c, 0xd7, 0x67,
+	0xfb, 0x6f, 0x61, 0x2c, 0x1d, 0x22, 0x46, 0x64, 0x86, 0xbf, 0x6d, 0xbf,
+	0x23, 0x97, 0x21, 0xee, 0x3f, 0x4f, 0x7d, 0x2c, 0x8e, 0xd4, 0xeb, 0xfb,
+	0x19, 0xc3, 0x7e, 0xa4, 0x35, 0xf4, 0xf8, 0x58, 0xe6, 0xbb, 0xa9, 0x86,
+	0xf4, 0x34, 0x68, 0x66, 0x93, 0xba, 0x1e, 0x58, 0xea, 0xe3, 0x98, 0x65,
+	0xbf, 0x6e, 0x29, 0x1e, 0x1e, 0x68, 0xc3, 0xdf, 0x0d, 0x78, 0xa9, 0x8b,
+	0xfa, 0xf1, 0x9b, 0x1d, 0xf8, 0xbe, 0x1f, 0x0e, 0xdf, 0x15, 0xc0, 0x7f,
+	0xd6, 0x60, 0xf6, 0x3e, 0x79, 0xcf, 0x3a, 0x53, 0xe3, 0x68, 0x9c, 0x01,
+	0xb1, 0x11, 0x10, 0xa9, 0x1d, 0xcc, 0xf6, 0x66, 0xdb, 0xef, 0x74, 0xc6,
+	0x96, 0x09, 0xa6, 0x97, 0x60, 0x7d, 0xd8, 0xc6, 0xd9, 0x27, 0x65, 0xff,
+	0xb0, 0x86, 0x78, 0xe4, 0x31, 0x5a, 0xb1, 0x21, 0x69, 0x7e, 0xb1, 0x86,
+	0x5c, 0xa9, 0x27, 0x99, 0xd3, 0xc1, 0x03, 0x11, 0xaa, 0xc4, 0x90, 0xff,
+	0x19, 0x01, 0x67, 0x47, 0xb4, 0x19, 0xf7, 0x65, 0x77, 0x22, 0xcd, 0xb1,
+	0xae, 0xa2, 0x9f, 0xad, 0xfc, 0xe3, 0xef, 0xc5, 0xe3, 0xa1, 0x44, 0x80,
+	0xf6, 0x7f, 0xce, 0xca, 0x54, 0xcd, 0x4e, 0xd7, 0x40, 0x5b, 0x73, 0x97,
+	0x7a, 0x3d, 0xf3, 0xd6, 0xe0, 0x01, 0x3e, 0x32, 0xa7, 0xdb, 0xe7, 0xd1,
+	0xdc, 0xb8, 0xa6, 0x1f, 0xca, 0x50, 0xaf, 0xbc, 0xd7, 0xd6, 0x89, 0xbf,
+	0xd1, 0x3f, 0x6f, 0xdb, 0xcf, 0xb8, 0xc3, 0x8b, 0x19, 0xbd, 0x72, 0xdf,
+	0x9a, 0x7f, 0x76, 0x6e, 0x30, 0x1c, 0x70, 0x3c, 0x54, 0x29, 0xfb, 0x12,
+	0xcf, 0x30, 0xce, 0xfa, 0xfb, 0xe7, 0x43, 0x9d, 0xeb, 0xc6, 0xdd, 0x8d,
+	0xe5, 0x88, 0x2f, 0x15, 0x0e, 0x69, 0xef, 0x9b, 0x50, 0x9f, 0x7f, 0x8d,
+	0xfb, 0xf5, 0xa7, 0xc8, 0xd7, 0x76, 0xa2, 0x9f, 0xf8, 0xb5, 0x52, 0xff,
+	0x9c, 0x62, 0xf2, 0xf7, 0x86, 0x94, 0x89, 0x55, 0xfa, 0x6d, 0xc0, 0x5f,
+	0x54, 0xa3, 0x74, 0xbb, 0x94, 0x17, 0xb9, 0x5b, 0x6c, 0x79, 0x7b, 0x52,
+	0xf2, 0xfb, 0xef, 0xf3, 0x6d, 0xde, 0x09, 0x54, 0xbb, 0xed, 0x3c, 0xe7,
+	0x57, 0x33, 0x77, 0x62, 0x6b, 0x0a, 0xdf, 0xaf, 0x44, 0x7d, 0xa6, 0x4f,
+	0x75, 0x7c, 0xff, 0x0a, 0xcc, 0x4e, 0xff, 0x56, 0x95, 0xf9, 0x88, 0xe1,
+	0xbe, 0x99, 0x0a, 0x71, 0x4d, 0x3b, 0x7d, 0x97, 0x1a, 0x34, 0xc7, 0x41,
+	0xf9, 0x63, 0x2f, 0x5a, 0xe3, 0x57, 0xf8, 0xb0, 0x6f, 0x4c, 0xea, 0xb6,
+	0xc1, 0xe2, 0x9c, 0xec, 0xb7, 0xf7, 0xe2, 0x82, 0x47, 0x2d, 0x35, 0x00,
+	0x27, 0xef, 0x9d, 0x1d, 0xd2, 0x99, 0xc7, 0xb7, 0xe1, 0xdf, 0x06, 0x96,
+	0xe2, 0xb7, 0x03, 0xf5, 0x1d, 0x37, 0x28, 0x96, 0x75, 0x28, 0xf2, 0x59,
+	0xfc, 0xb8, 0xda, 0x8b, 0xdd, 0xe4, 0xff, 0xbf, 0x4d, 0x98, 0xb5, 0x57,
+	0x10, 0x0b, 0xfe, 0x3d, 0x11, 0x4c, 0x1f, 0x52, 0xed, 0x77, 0xc6, 0xf5,
+	0x85, 0x6a, 0x70, 0xe7, 0xaf, 0xd8, 0xc6, 0x7d, 0xea, 0x12, 0xfc, 0x3a,
+	0xdb, 0x8a, 0xd3, 0xd9, 0xa9, 0xb6, 0xd0, 0x69, 0xa1, 0x46, 0xec, 0x40,
+	0xec, 0x81, 0xb6, 0x98, 0xa2, 0x2d, 0x92, 0xdf, 0x76, 0x7d, 0x86, 0xf6,
+	0x48, 0x2c, 0xfa, 0x1e, 0x31, 0xea, 0x1f, 0x52, 0xb4, 0x47, 0xfa, 0xcd,
+	0x77, 0xe9, 0x37, 0xdf, 0xa1, 0xdf, 0x3c, 0x45, 0xbf, 0xc9, 0x71, 0xdb,
+	0x36, 0x7b, 0xbd, 0xfe, 0x65, 0xc6, 0xc4, 0xc4, 0xd6, 0x4e, 0x9c, 0x8a,
+	0xd4, 0xaf, 0x1a, 0x45, 0xb0, 0x3d, 0xa9, 0x58, 0x5e, 0xe1, 0x73, 0x5f,
+	0x0b, 0x89, 0x0f, 0xc8, 0xfb, 0x69, 0x7e, 0x3c, 0x3e, 0xdc, 0x59, 0x29,
+	0xef, 0xbb, 0xee, 0xd9, 0xf1, 0x71, 0x3a, 0xfb, 0x07, 0xf6, 0x43, 0xf4,
+	0xf5, 0xe7, 0x8e, 0x5d, 0x74, 0xf9, 0xcf, 0xd6, 0x8f, 0x6b, 0x64, 0xfc,
+	0xcb, 0xf0, 0xfb, 0x81, 0x16, 0x9c, 0x66, 0xfc, 0x7d, 0x7e, 0xee, 0xb8,
+	0xb7, 0x14, 0xc1, 0xb8, 0xaa, 0x1a, 0xc8, 0x66, 0x5b, 0x70, 0x26, 0x61,
+	0xe0, 0x89, 0x44, 0xfd, 0xaa, 0x32, 0xc7, 0xcf, 0xd5, 0x4c, 0xad, 0x58,
+	0x54, 0x0c, 0x27, 0x85, 0x5f, 0x86, 0xda, 0x50, 0x6c, 0x34, 0x63, 0x30,
+	0x2b, 0x76, 0xea, 0xc5, 0x5b, 0x51, 0x5d, 0xde, 0x2f, 0xfb, 0xa3, 0x7f,
+	0xf7, 0xd1, 0x1e, 0x5f, 0x95, 0xff, 0x27, 0xc1, 0x79, 0xf6, 0x1a, 0xcb,
+	0xe0, 0xdc, 0x2e, 0xef, 0xf8, 0x8b, 0x3f, 0x2b, 0xd8, 0xa4, 0x8f, 0x77,
+	0x94, 0x20, 0xf8, 0xe4, 0x4f, 0x68, 0xeb, 0x87, 0x7a, 0xe5, 0x2c, 0x6e,
+	0x0b, 0x7e, 0xc9, 0xf2, 0x95, 0xf4, 0x8b, 0x43, 0x59, 0xa7, 0xf3, 0xc7,
+	0xbd, 0xf2, 0x8e, 0xfa, 0x12, 0xfc, 0x38, 0x3b, 0xa1, 0x7e, 0xe4, 0xd5,
+	0xf1, 0xab, 0xd1, 0xa5, 0xb4, 0x27, 0xc9, 0xe5, 0x63, 0xcc, 0xe5, 0x83,
+	0xde, 0xc7, 0xb1, 0x14, 0xea, 0xde, 0x65, 0xf0, 0x6c, 0x97, 0xf7, 0x67,
+	0x96, 0xa1, 0x8c, 0xbf, 0xfd, 0xdb, 0x2d, 0xcb, 0x39, 0xb7, 0xd2, 0xda,
+	0xb8, 0x4c, 0xe6, 0x4e, 0xf0, 0xe4, 0xff, 0x7a, 0x65, 0x2d, 0x00, 0x7b,
+	0x45, 0xbe, 0x46, 0xf9, 0x4b, 0xe1, 0xde, 0x5e, 0x1f, 0x5e, 0x84, 0xfa,
+	0xd3, 0x2e, 0x65, 0x29, 0xae, 0xde, 0xab, 0x54, 0xa1, 0x54, 0xca, 0x86,
+	0x69, 0x7f, 0x26, 0xe4, 0x9c, 0x74, 0x4b, 0xef, 0xaf, 0xac, 0x19, 0x86,
+	0xbd, 0xbf, 0x86, 0x95, 0xa3, 0x1a, 0xe3, 0x5d, 0x29, 0xe2, 0x83, 0x8f,
+	0x59, 0x95, 0x86, 0x13, 0x2b, 0x46, 0x1b, 0x71, 0x4b, 0xbf, 0x65, 0x9d,
+	0x9a, 0x17, 0x83, 0xc7, 0xf0, 0x10, 0xc3, 0x3c, 0xf8, 0x4a, 0x6f, 0x19,
+	0xbf, 0x2d, 0x14, 0x31, 0x26, 0xcf, 0x52, 0xb5, 0x55, 0xb5, 0x0e, 0xad,
+	0x7d, 0x54, 0x91, 0xb8, 0xef, 0xc1, 0x83, 0x8c, 0xcf, 0x8b, 0x7b, 0xfd,
+	0x88, 0x8f, 0x5a, 0xd6, 0x2b, 0x51, 0x1f, 0x1e, 0x60, 0xfd, 0xd6, 0xde,
+	0x01, 0x74, 0xd1, 0x2e, 0xe2, 0x7b, 0xb5, 0x80, 0x97, 0xf1, 0x7e, 0xe5,
+	0xa8, 0x9b, 0x31, 0xac, 0x1a, 0x8b, 0xb6, 0x07, 0xf0, 0x95, 0x51, 0x0f,
+	0xe3, 0x9b, 0x35, 0xff, 0x4d, 0xdd, 0xbc, 0xd6, 0x01, 0x0d, 0x6b, 0x46,
+	0x7d, 0x58, 0xd2, 0x1b, 0x3c, 0x23, 0xef, 0x5a, 0x9f, 0xd5, 0xc3, 0x58,
+	0x3d, 0xea, 0xc7, 0xed, 0xbd, 0x13, 0x5f, 0x99, 0x01, 0xf3, 0xff, 0xab,
+	0x45, 0x23, 0xbe, 0x3c, 0x5a, 0x47, 0xf9, 0xc1, 0x55, 0x2f, 0x2b, 0x75,
+	0xf8, 0xdb, 0xbd, 0x3a, 0xe5, 0xab, 0xb8, 0x8d, 0x72, 0x6e, 0xed, 0xbd,
+	0x1a, 0x0f, 0xee, 0x8d, 0xe2, 0xbe, 0xd1, 0xb9, 0x58, 0xc8, 0xf8, 0xd4,
+	0xc1, 0xbc, 0x0e, 0x9f, 0x07, 0x6e, 0xef, 0x17, 0xdd, 0x43, 0x79, 0x25,
+	0x3a, 0x0e, 0x37, 0xe3, 0x1d, 0x0d, 0x91, 0xf7, 0x1a, 0xc9, 0xc1, 0x74,
+	0xdc, 0xbe, 0x6b, 0xae, 0xbd, 0x9f, 0x5e, 0x1f, 0x29, 0x46, 0xbc, 0x4d,
+	0x41, 0x4b, 0xbf, 0xc4, 0x59, 0xe1, 0x36, 0x3a, 0xe3, 0x6a, 0x88, 0x6d,
+	0xe8, 0x8c, 0xab, 0xb9, 0xfb, 0x5d, 0x29, 0x39, 0x6b, 0xf5, 0x06, 0xf9,
+	0x52, 0x04, 0x2d, 0x76, 0x8c, 0x76, 0x93, 0x5f, 0x9b, 0x70, 0x32, 0x76,
+	0x47, 0x68, 0xe3, 0xf3, 0x9b, 0x24, 0x56, 0x37, 0x32, 0x4f, 0x34, 0x30,
+	0xd6, 0xa7, 0x75, 0x9c, 0x51, 0x0c, 0x8c, 0xee, 0x92, 0x98, 0xe8, 0xc3,
+	0xea, 0x5e, 0x03, 0x6f, 0xca, 0x59, 0xfa, 0x39, 0xb1, 0xc5, 0x65, 0xd0,
+	0xf4, 0x07, 0x11, 0x32, 0x8f, 0x31, 0xb6, 0x9f, 0xce, 0x54, 0xe3, 0x96,
+	0xed, 0x52, 0xa6, 0x09, 0x6f, 0x0d, 0x39, 0x71, 0x4b, 0xef, 0x5a, 0x3c,
+	0x96, 0x76, 0x60, 0x50, 0xaf, 0xef, 0x51, 0x19, 0x3f, 0x6f, 0x6c, 0x0a,
+	0x7a, 0x9f, 0x21, 0x57, 0x3d, 0x33, 0x97, 0x51, 0xf9, 0x8a, 0x28, 0x5a,
+	0xd8, 0xaf, 0x16, 0x2d, 0x77, 0x96, 0xe2, 0xbe, 0xe8, 0x5a, 0x1c, 0x4b,
+	0x6b, 0xe6, 0x7e, 0xe6, 0xcb, 0xee, 0x26, 0x3e, 0x9f, 0xee, 0x44, 0xb7,
+	0x26, 0x9c, 0xb6, 0x91, 0xbe, 0x25, 0xeb, 0x2a, 0x51, 0xbc, 0x49, 0x7b,
+	0xed, 0xc9, 0xcc, 0x67, 0xec, 0x97, 0x98, 0x2f, 0x67, 0xfd, 0x4c, 0x54,
+	0xde, 0xa0, 0xe0, 0xf8, 0x6e, 0xe1, 0x58, 0xf3, 0xf1, 0x45, 0xea, 0xa9,
+	0xa5, 0x57, 0xc5, 0x8d, 0x7b, 0x97, 0xe3, 0xd4, 0xb6, 0x1c, 0xe7, 0x7a,
+	0x25, 0x62, 0x7e, 0x99, 0x9c, 0xab, 0xbd, 0x9c, 0x9c, 0x8b, 0x5c, 0x2e,
+	0xbc, 0x5a, 0x71, 0x22, 0x34, 0xda, 0x4c, 0x5e, 0x21, 0xfc, 0x82, 0xfe,
+	0x9a, 0x8d, 0x62, 0x51, 0x6f, 0x1d, 0x86, 0xc9, 0xb7, 0x32, 0xc4, 0x8b,
+	0x4c, 0x96, 0x71, 0x65, 0xa8, 0x86, 0x9f, 0x00, 0x3f, 0xd7, 0xf0, 0xa3,
+	0xd9, 0xf7, 0x56, 0xd0, 0x96, 0x63, 0x6d, 0x8a, 0x7d, 0xce, 0x7e, 0x30,
+	0x2b, 0xb1, 0x5a, 0x41, 0x95, 0xf6, 0x17, 0x55, 0x92, 0x67, 0x7a, 0x35,
+	0x05, 0xaf, 0xa5, 0x03, 0xf8, 0x6a, 0xd3, 0x5a, 0x25, 0x56, 0x6d, 0xbf,
+	0xa7, 0x6a, 0x96, 0xb2, 0x6f, 0x8b, 0xe6, 0xc9, 0x3a, 0x64, 0x98, 0x39,
+	0xaf, 0xfc, 0x8f, 0x02, 0x05, 0x0f, 0x30, 0x97, 0x0f, 0x54, 0x05, 0xe4,
+	0x1c, 0x14, 0xfd, 0xdd, 0x87, 0x17, 0x12, 0x71, 0x64, 0x13, 0x0d, 0x3d,
+	0xab, 0x15, 0xd9, 0xef, 0x09, 0x36, 0xc7, 0x95, 0x1c, 0xe7, 0x2f, 0x67,
+	0xdd, 0xdd, 0xf3, 0x3a, 0xd0, 0x41, 0x6e, 0x7f, 0x3a, 0xc7, 0xed, 0x03,
+	0x93, 0xe8, 0xc0, 0xca, 0x84, 0xec, 0x6f, 0xc6, 0xad, 0x2e, 0xce, 0xc1,
+	0xe1, 0x44, 0x07, 0xee, 0x4c, 0x34, 0x74, 0x10, 0x5a, 0x30, 0x7e, 0x57,
+	0x07, 0x5a, 0x12, 0xf5, 0xe3, 0x5b, 0xe5, 0x7f, 0x50, 0x4d, 0xd3, 0x70,
+	0x60, 0x4c, 0x45, 0xad, 0x16, 0x20, 0xf6, 0x07, 0x30, 0x98, 0x6a, 0x38,
+	0xd3, 0xa5, 0xde, 0xa9, 0x4c, 0x5e, 0x21, 0x39, 0x64, 0x33, 0x9e, 0x4f,
+	0x78, 0x50, 0x96, 0x34, 0x69, 0xfb, 0x40, 0xe9, 0x48, 0x94, 0xf9, 0xc3,
+	0x63, 0x56, 0x95, 0x11, 0x4a, 0x8b, 0x5e, 0x4a, 0x46, 0xe6, 0xe3, 0x0d,
+	0xc6, 0xdc, 0xfa, 0xeb, 0x35, 0xef, 0x42, 0x1b, 0x8b, 0x7e, 0x65, 0xd5,
+	0x1a, 0x65, 0x98, 0xb1, 0x2b, 0xd4, 0xdc, 0xc2, 0xf8, 0xda, 0x7c, 0x03,
+	0xed, 0x80, 0xb1, 0xaf, 0xd2, 0xd8, 0xc9, 0x39, 0x16, 0x7b, 0xf2, 0xa0,
+	0x7c, 0xc4, 0x47, 0x1c, 0xa2, 0xe8, 0x11, 0x0d, 0x7b, 0xd9, 0x2f, 0xef,
+	0x88, 0x9c, 0x0b, 0x0a, 0xb6, 0xdf, 0x27, 0xff, 0x53, 0x64, 0x4f, 0xee,
+	0xfc, 0xe1, 0xfb, 0x89, 0xcf, 0x40, 0x92, 0x51, 0xcf, 0x88, 0x07, 0x1f,
+	0x26, 0xe4, 0x0c, 0x1f, 0x69, 0xcd, 0x48, 0x00, 0x55, 0xac, 0xfb, 0x66,
+	0xa2, 0x3e, 0xfd, 0xdf, 0x51, 0x1f, 0xb8, 0x55, 0xad, 0xb4, 0xcf, 0x0a,
+	0x39, 0x47, 0x6e, 0xc2, 0x89, 0x74, 0x70, 0x9c, 0x79, 0xf4, 0xaa, 0x76,
+	0xaa, 0x98, 0xb9, 0xae, 0x79, 0x8d, 0xd2, 0xd0, 0xa1, 0xaa, 0xc1, 0xf0,
+	0xa8, 0x02, 0xca, 0x73, 0xb2, 0x8d, 0x9b, 0xf0, 0x76, 0xba, 0x14, 0x45,
+	0xbb, 0x76, 0xd2, 0xee, 0x8b, 0xb0, 0x78, 0x9b, 0x1b, 0x25, 0x7b, 0xc4,
+	0x56, 0x45, 0xaf, 0x92, 0xef, 0x83, 0xb6, 0x6a, 0x62, 0x6f, 0x74, 0x39,
+	0x9e, 0x1f, 0x90, 0x7d, 0xf4, 0x0b, 0x1c, 0xbc, 0x2d, 0x62, 0xde, 0xae,
+	0x32, 0x06, 0xad, 0x4f, 0x85, 0xe2, 0x25, 0xb4, 0x09, 0x87, 0x11, 0x6a,
+	0xef, 0xe6, 0xd8, 0x1b, 0x46, 0xc5, 0xce, 0x9a, 0xf1, 0x1d, 0x8e, 0xa5,
+	0x9f, 0x36, 0x31, 0x9c, 0xa8, 0xc3, 0x46, 0xda, 0x84, 0x49, 0x9b, 0x30,
+	0x39, 0xff, 0x26, 0x6d, 0xc2, 0xa4, 0x4d, 0x98, 0xb4, 0x09, 0x93, 0x36,
+	0x61, 0x66, 0xe7, 0x63, 0x5f, 0x5a, 0x45, 0xcf, 0x50, 0x19, 0xe2, 0xd5,
+	0xf2, 0x1e, 0xbd, 0x86, 0xb1, 0x54, 0x97, 0x32, 0x79, 0xd7, 0x4d, 0x18,
+	0x4c, 0xdf, 0xcc, 0x8f, 0x82, 0x76, 0xda, 0xc5, 0xce, 0x8c, 0xd8, 0x99,
+	0x1b, 0xdf, 0xcd, 0xce, 0x99, 0x86, 0xd2, 0x5c, 0xac, 0x7c, 0xcc, 0xbe,
+	0xa7, 0x70, 0x8e, 0xdc, 0x78, 0x26, 0x2b, 0xf7, 0x4c, 0x9c, 0xa0, 0xfd,
+	0xf7, 0x50, 0x9e, 0x1a, 0x91, 0xfd, 0x92, 0x28, 0xf9, 0xbe, 0x9c, 0x0b,
+	0xdf, 0xc9, 0x7e, 0x0b, 0xcf, 0x30, 0xb1, 0x65, 0x1e, 0xd0, 0xd4, 0xbf,
+	0x16, 0x0f, 0xf5, 0x61, 0xbc, 0x9c, 0xcf, 0xbe, 0x93, 0xd9, 0x49, 0x1f,
+	0x6e, 0xb4, 0xd7, 0x30, 0xee, 0x6f, 0x52, 0xf0, 0xa5, 0xb4, 0x9c, 0x27,
+	0xaf, 0x8f, 0x6d, 0x44, 0xc4, 0xf6, 0xdb, 0xfe, 0xd4, 0x4e, 0xa4, 0xf8,
+	0xcc, 0x1f, 0x69, 0xa2, 0x4f, 0x56, 0xe3, 0xdd, 0x6d, 0x41, 0xfd, 0x35,
+	0x68, 0xad, 0x23, 0xb0, 0xe6, 0x2f, 0x8c, 0x84, 0xcc, 0x7a, 0xa5, 0x09,
+	0x6d, 0x7b, 0x9b, 0x98, 0x3b, 0x04, 0xf5, 0xd7, 0xe9, 0x73, 0xcf, 0x45,
+	0xe6, 0x33, 0x7f, 0x88, 0xe1, 0x2b, 0xe4, 0xf9, 0x77, 0x0d, 0xaa, 0x1c,
+	0x53, 0xa3, 0xbd, 0xf6, 0xf1, 0x9c, 0xfd, 0x0e, 0x5c, 0x54, 0xce, 0xc8,
+	0x28, 0x0f, 0x12, 0x73, 0x16, 0x27, 0x0f, 0x5a, 0xf2, 0x4e, 0xed, 0xca,
+	0xeb, 0x9a, 0xb1, 0x3f, 0x6b, 0xe0, 0xc9, 0xf4, 0x1b, 0x96, 0xaa, 0xc5,
+	0xce, 0x3a, 0xc9, 0x45, 0x3c, 0xc4, 0x8c, 0x6c, 0x46, 0xfc, 0x5f, 0xf6,
+	0xc0, 0x0d, 0x7c, 0x98, 0xd6, 0xd2, 0x0d, 0x8c, 0x4b, 0xbf, 0xe6, 0xbd,
+	0x9d, 0xc4, 0x11, 0xf7, 0x56, 0xed, 0xa8, 0x4a, 0x0e, 0x3f, 0xdf, 0x61,
+	0xa0, 0x68, 0xb7, 0xcc, 0x81, 0xe0, 0x56, 0x00, 0x63, 0x89, 0x18, 0xee,
+	0xa4, 0xfd, 0x8c, 0x26, 0x5a, 0x70, 0x07, 0x6d, 0x63, 0x24, 0xd1, 0x8a,
+	0xcf, 0x31, 0x37, 0xd8, 0x9d, 0x10, 0x3f, 0x5b, 0x82, 0x85, 0xb4, 0x95,
+	0xfd, 0xa9, 0xff, 0x05, 0x7d, 0x7a, 0x00, 0xbb, 0x6d, 0xae, 0x29, 0xfb,
+	0xd6, 0x50, 0x56, 0x26, 0xdc, 0xcc, 0x6d, 0xe2, 0x56, 0x7f, 0x4a, 0x38,
+	0x50, 0x27, 0x6e, 0x89, 0x34, 0x62, 0x0b, 0xe5, 0x65, 0xc9, 0x75, 0x87,
+	0x98, 0x4f, 0xad, 0xde, 0xb5, 0x9c, 0x98, 0x7c, 0x61, 0xee, 0x4f, 0xeb,
+	0xe6, 0x21, 0x62, 0x41, 0xd8, 0xcf, 0x79, 0x57, 0x69, 0xc3, 0x72, 0xce,
+	0x7c, 0x90, 0x63, 0x9f, 0x43, 0x3c, 0x70, 0xa7, 0xc4, 0x7e, 0x82, 0x47,
+	0x19, 0xf2, 0x1e, 0xae, 0x95, 0x77, 0x15, 0xe8, 0x1b, 0x33, 0x52, 0x56,
+	0xa7, 0x93, 0x71, 0x64, 0x53, 0xb4, 0x0e, 0x07, 0x47, 0x6e, 0x86, 0x77,
+	0x6b, 0x1d, 0x46, 0x93, 0x7e, 0x64, 0x93, 0xa8, 0xf5, 0x42, 0xbd, 0xc1,
+	0x8b, 0x60, 0xf3, 0x21, 0xc6, 0x89, 0xb7, 0x95, 0x86, 0xf6, 0x37, 0x11,
+	0xec, 0xd9, 0xac, 0x04, 0xbd, 0x0d, 0xaa, 0xb4, 0x4d, 0x3c, 0xa1, 0x1f,
+	0x0c, 0xd2, 0xde, 0x33, 0x23, 0xc4, 0x14, 0xd6, 0x75, 0x6d, 0x75, 0xc9,
+	0x3a, 0xf1, 0x78, 0x95, 0xe6, 0xc3, 0x9e, 0x3d, 0xc4, 0xb8, 0x1d, 0xf2,
+	0xbf, 0x03, 0x6a, 0xb0, 0x6f, 0xcf, 0xcd, 0x98, 0xb1, 0x35, 0x80, 0x83,
+	0xbc, 0x57, 0xbb, 0xe3, 0x1a, 0x3c, 0x43, 0x3f, 0xc9, 0xd0, 0x0f, 0x8b,
+	0xb6, 0xaa, 0xd8, 0xbb, 0xe7, 0x26, 0x54, 0x92, 0xd7, 0x9f, 0x0a, 0x29,
+	0x36, 0xf6, 0x26, 0x38, 0xae, 0xdd, 0x29, 0xfb, 0xdc, 0xbc, 0xf2, 0x22,
+	0xf3, 0x81, 0xee, 0x11, 0x1d, 0x9b, 0x79, 0x3f, 0xc5, 0xb9, 0xde, 0x42,
+	0xcc, 0x3d, 0xbe, 0xad, 0x1a, 0xf7, 0x6f, 0xd3, 0x62, 0xd7, 0xa8, 0xd6,
+	0xfc, 0xb7, 0xf4, 0xd0, 0x19, 0x17, 0xe7, 0xd8, 0x62, 0x0e, 0x77, 0xb6,
+	0xef, 0xa0, 0x55, 0x45, 0xac, 0x77, 0x69, 0xf3, 0x31, 0x73, 0x6e, 0x0c,
+	0xaf, 0x47, 0x9b, 0x70, 0x66, 0x97, 0xe8, 0xca, 0x62, 0x0c, 0x90, 0xf8,
+	0x10, 0x45, 0x9c, 0x39, 0xdd, 0x6e, 0xe6, 0x74, 0xf7, 0x30, 0xa7, 0x7b,
+	0xb0, 0x4f, 0x74, 0xdc, 0x89, 0x25, 0x11, 0x83, 0x3a, 0x6c, 0x24, 0x7e,
+	0x19, 0x50, 0xfb, 0xb4, 0xe6, 0xbb, 0x88, 0xf1, 0xc5, 0x76, 0x8e, 0x67,
+	0x10, 0x27, 0x24, 0x4f, 0x30, 0xf0, 0xd3, 0x4c, 0xce, 0xef, 0x6a, 0x19,
+	0xd3, 0x0f, 0x8c, 0xb4, 0xe0, 0xbb, 0xcc, 0xe1, 0x46, 0xfb, 0x42, 0x3b,
+	0x5f, 0x56, 0x5a, 0xf1, 0x5d, 0x3b, 0x5e, 0x88, 0x0d, 0xb7, 0xe2, 0xdd,
+	0x84, 0x16, 0x5f, 0xa8, 0x84, 0xda, 0xd3, 0xbc, 0xff, 0x5e, 0xf6, 0x66,
+	0x72, 0xd8, 0x25, 0x38, 0x4e, 0x1b, 0xee, 0x49, 0x09, 0x96, 0x3b, 0xe1,
+	0xda, 0x76, 0x07, 0xde, 0x1a, 0xce, 0xe5, 0x6e, 0x21, 0xe6, 0x6e, 0x77,
+	0xf6, 0xd3, 0x1e, 0x52, 0x10, 0x6f, 0x60, 0x0e, 0x17, 0x5c, 0x55, 0xc4,
+	0xfc, 0xed, 0xa3, 0x48, 0x2e, 0x7f, 0x8b, 0x57, 0x07, 0xf5, 0x17, 0x15,
+	0x73, 0xa7, 0xbc, 0x7b, 0xf4, 0x1a, 0x72, 0xe7, 0xc6, 0x4f, 0x10, 0x6b,
+	0x37, 0xd1, 0x07, 0xae, 0x8b, 0x48, 0x7e, 0xa7, 0x61, 0x38, 0x65, 0xbf,
+	0xcf, 0xad, 0xff, 0x94, 0xf3, 0xeb, 0xd7, 0xc4, 0x06, 0x1c, 0x38, 0xad,
+	0xd7, 0x7b, 0xbd, 0x0e, 0x07, 0x6e, 0xd1, 0x83, 0xab, 0x8e, 0x20, 0xca,
+	0x79, 0x97, 0xbd, 0xc2, 0x5c, 0x3c, 0x75, 0x26, 0xe5, 0x1d, 0x94, 0x4e,
+	0xbc, 0x35, 0xf7, 0xef, 0xf3, 0x79, 0x58, 0x21, 0x1f, 0x13, 0x9b, 0x6b,
+	0x68, 0x76, 0xa0, 0xde, 0x2c, 0x86, 0x96, 0x49, 0x93, 0x5f, 0xc6, 0x39,
+	0xd7, 0x71, 0x08, 0xf6, 0x37, 0x98, 0x5e, 0x84, 0xed, 0xff, 0xf9, 0xf5,
+	0x7c, 0xc2, 0x3e, 0x03, 0x4a, 0x9c, 0xcb, 0xe1, 0xea, 0x73, 0x89, 0x52,
+	0x80, 0xf8, 0x94, 0xe0, 0xd8, 0x8a, 0x47, 0x4c, 0xb8, 0x0c, 0xfa, 0x57,
+	0x9f, 0x07, 0xea, 0x2e, 0x0f, 0xfc, 0xc9, 0xc7, 0xac, 0x72, 0xe2, 0x6a,
+	0xd9, 0x2e, 0xce, 0x91, 0xc3, 0xb2, 0x9e, 0x9a, 0x27, 0x38, 0x2b, 0x65,
+	0xb5, 0xd6, 0x0f, 0x79, 0xad, 0x11, 0x67, 0x35, 0x62, 0x6b, 0x05, 0xf1,
+	0xb1, 0x3b, 0x59, 0x8d, 0xcd, 0xdb, 0x06, 0xa8, 0x73, 0x2f, 0x1c, 0xbc,
+	0x4e, 0x25, 0xfd, 0x36, 0x76, 0x82, 0xbf, 0x2b, 0xe9, 0x33, 0xa0, 0x9d,
+	0x6d, 0x4d, 0x5a, 0xf3, 0xef, 0x8c, 0x98, 0x7d, 0x95, 0xec, 0xcb, 0x34,
+	0xe2, 0xed, 0xc6, 0x64, 0xd0, 0x7b, 0xab, 0xaa, 0xe0, 0xf6, 0x88, 0xce,
+	0xb6, 0x3d, 0xe8, 0x4b, 0x0a, 0x4e, 0x4c, 0x50, 0x8f, 0x66, 0x43, 0x19,
+	0x75, 0xe9, 0xa2, 0x2e, 0x67, 0xd8, 0xe7, 0x55, 0xeb, 0x50, 0xbe, 0x27,
+	0xca, 0x3e, 0x37, 0x12, 0x8b, 0x4d, 0x6c, 0xe2, 0xcf, 0xf9, 0xbb, 0x97,
+	0xe3, 0xba, 0x6d, 0x76, 0xee, 0xbb, 0x40, 0xf2, 0x99, 0xd7, 0x22, 0x21,
+	0xfd, 0x1e, 0xd5, 0x89, 0xb7, 0xb3, 0x82, 0xb5, 0xf2, 0x3e, 0x3d, 0xc6,
+	0x67, 0x68, 0xcd, 0x58, 0x9a, 0x14, 0x8c, 0xf2, 0x93, 0x67, 0x47, 0xb1,
+	0x24, 0x29, 0xfe, 0x68, 0xe2, 0xb6, 0xeb, 0xeb, 0xf0, 0xfe, 0xf9, 0x75,
+	0x0b, 0x1f, 0x26, 0x89, 0x99, 0x93, 0xc4, 0xcc, 0x49, 0x62, 0xe6, 0xa4,
+	0xbd, 0x16, 0xa1, 0xe2, 0xf4, 0x90, 0x82, 0xf7, 0x6c, 0xfc, 0xdb, 0x69,
+	0x73, 0xa8, 0x27, 0x19, 0xd3, 0xdb, 0xd3, 0x3a, 0x0e, 0xd0, 0x16, 0x92,
+	0x29, 0xb1, 0x35, 0x05, 0x4f, 0xf5, 0x45, 0x50, 0x45, 0xdb, 0xd9, 0x4a,
+	0x9b, 0x7e, 0x78, 0xbb, 0x16, 0x98, 0xef, 0x08, 0xb5, 0xa6, 0xd0, 0x84,
+	0x07, 0x88, 0x57, 0x0f, 0x31, 0x97, 0x39, 0x44, 0x4c, 0xbb, 0x67, 0x70,
+	0x2d, 0x96, 0xf4, 0xa9, 0xc4, 0x2c, 0x62, 0xd5, 0x74, 0xc1, 0x6e, 0xc1,
+	0x4b, 0x79, 0x57, 0x2e, 0x2a, 0xeb, 0x9a, 0xca, 0x5d, 0xc4, 0xaa, 0xc6,
+	0x5e, 0xe1, 0x38, 0xcc, 0x93, 0x18, 0x8b, 0x12, 0xc4, 0xaa, 0x2d, 0x69,
+	0x99, 0xaf, 0x4e, 0xdc, 0x4b, 0xbb, 0x5e, 0x9f, 0x5f, 0x97, 0x98, 0xb3,
+	0x55, 0x3b, 0x73, 0x40, 0xc9, 0x71, 0x9d, 0x5e, 0x5e, 0x1f, 0xee, 0x0b,
+	0x50, 0x0f, 0x06, 0x8e, 0xed, 0x92, 0x3c, 0x48, 0xfa, 0x13, 0xc0, 0x21,
+	0xe2, 0x93, 0x83, 0xba, 0x7e, 0x99, 0xf8, 0x54, 0x49, 0x7c, 0x7a, 0x8d,
+	0xf8, 0x34, 0x8d, 0xf8, 0xf4, 0x6a, 0x1e, 0x9f, 0xaa, 0x47, 0xc4, 0x16,
+	0x72, 0x5c, 0xfb, 0x78, 0xe2, 0xb9, 0x2a, 0xf9, 0x5f, 0x62, 0x82, 0xf3,
+	0x97, 0xc7, 0xff, 0xa5, 0x78, 0x71, 0x00, 0xee, 0x19, 0xe4, 0xb2, 0x16,
+	0xf1, 0xe6, 0x03, 0xc7, 0x52, 0xfc, 0x74, 0xa8, 0xc0, 0x61, 0x27, 0xed,
+	0x5c, 0xb9, 0xdc, 0x90, 0x75, 0x30, 0x59, 0x03, 0xab, 0xcb, 0xef, 0x0b,
+	0x9a, 0xf8, 0xce, 0x3c, 0xe1, 0x8d, 0xb2, 0xae, 0x53, 0x44, 0x7e, 0xd8,
+	0x86, 0xe1, 0x6d, 0xcf, 0x62, 0x53, 0x9f, 0x7a, 0x6b, 0x19, 0xc8, 0x85,
+	0x95, 0x4e, 0x38, 0x22, 0x95, 0x98, 0x19, 0x11, 0x1b, 0x64, 0x2e, 0x32,
+	0xf6, 0x6d, 0x74, 0xef, 0x2e, 0xc3, 0x84, 0xd7, 0xb2, 0x9e, 0xd4, 0x6b,
+	0xe5, 0xdf, 0x00, 0x08, 0x5e, 0x7a, 0x8a, 0x18, 0xa3, 0x6e, 0x1d, 0xfd,
+	0xb8, 0x33, 0xa7, 0x6b, 0xf0, 0xc5, 0xed, 0x8f, 0xa0, 0x7d, 0xfb, 0x37,
+	0xe9, 0x7b, 0x33, 0x7b, 0x6a, 0x69, 0x87, 0xd7, 0x35, 0x8d, 0xe3, 0x44,
+	0x84, 0xb1, 0xcf, 0xa7, 0xe0, 0x87, 0x73, 0x66, 0x8a, 0x1c, 0xfe, 0x7d,
+	0x60, 0x05, 0x6c, 0x79, 0x6f, 0xe5, 0xfd, 0xe3, 0x39, 0x1f, 0xc7, 0x4e,
+	0xd9, 0x27, 0xbc, 0xf9, 0xb3, 0x9b, 0x7f, 0x42, 0x5b, 0x3f, 0x13, 0x19,
+	0xfc, 0x2b, 0xc8, 0x78, 0xdd, 0x8a, 0x2d, 0x93, 0x7a, 0x45, 0xf9, 0x36,
+	0xbe, 0x49, 0x8e, 0x47, 0x9e, 0xa7, 0xf3, 0x7b, 0xf0, 0x59, 0x91, 0xcf,
+	0x67, 0x05, 0xf9, 0x2f, 0x5a, 0xb1, 0x36, 0xb9, 0x96, 0x32, 0x1f, 0xf1,
+	0x99, 0x94, 0x2b, 0x3c, 0x7b, 0x36, 0x2f, 0xa7, 0x18, 0x81, 0xea, 0x9c,
+	0x9c, 0x2f, 0x51, 0xce, 0x69, 0x62, 0x9e, 0x7a, 0xfd, 0x54, 0x59, 0x85,
+	0x76, 0xff, 0xf7, 0x79, 0x59, 0xb9, 0x72, 0x45, 0xd3, 0x51, 0x2a, 0x65,
+	0xa7, 0xae, 0x7b, 0x17, 0xd1, 0x77, 0x43, 0xde, 0xf5, 0xf6, 0x7a, 0xb3,
+	0x8e, 0x15, 0x17, 0xe7, 0x4c, 0xf2, 0xde, 0x1b, 0xb9, 0x82, 0x17, 0x6f,
+	0x33, 0x47, 0xca, 0xad, 0xbf, 0x4b, 0xfe, 0x65, 0xe0, 0xf1, 0x44, 0xb0,
+	0x75, 0xa5, 0xd2, 0x10, 0x9b, 0x4d, 0x6e, 0x81, 0x2a, 0x59, 0x93, 0x6e,
+	0xb6, 0xff, 0x5f, 0x5e, 0x36, 0xd4, 0xcc, 0x3c, 0xcd, 0xa0, 0x2d, 0x05,
+	0x3b, 0x4e, 0xd8, 0xfb, 0x89, 0x06, 0x5e, 0xca, 0xbe, 0x92, 0x3f, 0x8f,
+	0x28, 0x73, 0x1e, 0xe6, 0x9c, 0x4f, 0x5d, 0x13, 0x95, 0xf9, 0x0f, 0xa6,
+	0x33, 0xa8, 0x16, 0x1e, 0x68, 0x9a, 0xd0, 0xe9, 0x37, 0x26, 0x43, 0xd8,
+	0x0d, 0x88, 0xfb, 0x64, 0x6f, 0xc1, 0x97, 0xff, 0x3f, 0x66, 0xac, 0xf7,
+	0x09, 0x6b, 0x3c, 0x60, 0xbd, 0xdc, 0x99, 0x33, 0x1d, 0xe6, 0xd8, 0xd5,
+	0xc8, 0x78, 0x65, 0xfd, 0x00, 0xe6, 0x34, 0x23, 0x00, 0x9f, 0x76, 0x37,
+	0xc7, 0xed, 0xc2, 0x74, 0xe6, 0x47, 0x91, 0x99, 0x0d, 0x6d, 0x4d, 0xea,
+	0x15, 0x88, 0x55, 0xc9, 0x79, 0x22, 0x9d, 0xf6, 0x0f, 0x14, 0xf7, 0xca,
+	0xf9, 0x0d, 0xb3, 0xd5, 0x8d, 0xa0, 0x7f, 0xae, 0xa2, 0xa0, 0x28, 0x04,
+	0xe7, 0xfd, 0x59, 0xf2, 0xb0, 0x99, 0x1f, 0x59, 0x3f, 0xf2, 0xe9, 0xcc,
+	0xe7, 0x0b, 0x7d, 0xd0, 0xf1, 0xf5, 0xd1, 0x4b, 0x33, 0xc8, 0x82, 0xcc,
+	0xf7, 0xad, 0xd8, 0x74, 0x69, 0x5b, 0xe4, 0x7e, 0x52, 0x5f, 0x73, 0x7d,
+	0xfc, 0xa7, 0x59, 0xf5, 0x01, 0x07, 0x2a, 0xb1, 0x5e, 0x37, 0xa6, 0xcb,
+	0xd9, 0xec, 0x7b, 0x65, 0x8d, 0xc5, 0x3e, 0xcf, 0x36, 0xf5, 0x5c, 0xd6,
+	0xd4, 0x75, 0x63, 0x2f, 0xaa, 0x89, 0xe1, 0x25, 0x49, 0xd1, 0xf5, 0x35,
+	0x50, 0xa9, 0xef, 0x63, 0xc4, 0xa2, 0xe2, 0xa4, 0x87, 0x79, 0xab, 0x87,
+	0x58, 0x67, 0xe0, 0xb9, 0x6c, 0x07, 0x5c, 0xe4, 0x4e, 0x13, 0xd9, 0x30,
+	0x5e, 0xcd, 0xce, 0x99, 0x2e, 0xe7, 0x5e, 0xa9, 0x02, 0x38, 0x67, 0xca,
+	0x6f, 0x53, 0xde, 0xe7, 0x53, 0x72, 0xbf, 0xdf, 0xb7, 0xdf, 0x35, 0x77,
+	0x18, 0x2b, 0x71, 0x4f, 0xa2, 0x4a, 0xd6, 0xda, 0x4d, 0x9f, 0x61, 0x5a,
+	0xd3, 0xb4, 0xaa, 0xe9, 0xb9, 0xf3, 0x30, 0xc1, 0xf6, 0xa5, 0xc4, 0x91,
+	0xd5, 0x11, 0xad, 0xed, 0xbf, 0x2b, 0xc1, 0x40, 0x5a, 0x69, 0x63, 0xf9,
+	0x30, 0x36, 0x8f, 0x4a, 0x5d, 0x85, 0xe3, 0x2d, 0xec, 0x57, 0x37, 0x04,
+	0x42, 0xea, 0xaf, 0x0b, 0x67, 0xa1, 0xdd, 0x45, 0x46, 0x1c, 0xcf, 0x26,
+	0xa6, 0xcb, 0xff, 0x2c, 0x90, 0x35, 0x95, 0xbc, 0x4c, 0x8f, 0x59, 0x65,
+	0x48, 0x5b, 0xed, 0x6c, 0xcb, 0x3c, 0xeb, 0x25, 0x86, 0xb8, 0xb4, 0xe0,
+	0xd1, 0xaf, 0x22, 0xb8, 0x66, 0xbe, 0xa3, 0x13, 0x67, 0x22, 0x5a, 0xc7,
+	0x47, 0x6c, 0xa3, 0xca, 0x11, 0x46, 0x6f, 0x5e, 0xbe, 0xfc, 0x9f, 0xd8,
+	0x9c, 0xac, 0x86, 0x55, 0x45, 0xea, 0x69, 0x2b, 0x33, 0x3d, 0x27, 0xbf,
+	0xd8, 0x58, 0xce, 0xfc, 0xd8, 0x43, 0xb9, 0x72, 0xe6, 0x36, 0xb8, 0xf3,
+	0xd7, 0x30, 0xad, 0x6a, 0x4d, 0xeb, 0xf9, 0xaa, 0xda, 0x89, 0x15, 0x4d,
+	0xc1, 0xc0, 0x32, 0xda, 0x48, 0x95, 0x2d, 0x23, 0x16, 0x2e, 0xfa, 0xd8,
+	0x33, 0x71, 0xf4, 0x23, 0xc8, 0xba, 0x23, 0xcb, 0x95, 0xca, 0x99, 0x31,
+	0x79, 0xd7, 0xd4, 0x89, 0x85, 0x8c, 0x6f, 0xf1, 0xc2, 0xff, 0x74, 0xb2,
+	0xf7, 0x86, 0xbe, 0x31, 0xfd, 0xc2, 0xff, 0xd9, 0xfd, 0xff, 0x01, 0x02,
+	0x8b, 0x0c, 0x6e, 0x74, 0x57, 0x00, 0x00, 0x00 };
 
-static const u32 bnx2_CP_b09FwData[(0x0/4) + 1] = { 0x0 };
-static const u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = {
-	0x0800069c, 0x080008bc, 0x08000800, 0x08000828, 0x08000850, 0x08000878,
-	0x080006d4, 0x080006c0, 0x080008e4, 0x080008e4, 0x080006f0, 0x0800070c,
-	0x0800070c, 0x080008e4, 0x08000724, 0x08000738, 0x080008e4, 0x0800074c,
-	0x080008e4, 0x080008e4, 0x08000760, 0x080008e4, 0x080008e4, 0x080008e4,
-	0x080008e4, 0x080008e4, 0x080008e4, 0x080008e4, 0x080008e4, 0x080008e4,
-	0x080008e4, 0x08000774, 0x080008e4, 0x08000788, 0x0800079c, 0x080007b0,
-	0x080008e4, 0x080007c4, 0x080007d8, 0x080007ec, 0x080032e8, 0x08003300,
-	0x08003310, 0x08003320, 0x08003338, 0x08003350, 0x08003360, 0x08003370,
-	0x08003390, 0x080033a0, 0x080033b0, 0x08003440, 0x08003380, 0x080033c0,
-	0x080033d0, 0x080033e8, 0x08003408, 0x08003440, 0x08003420, 0x08003420,
-	0x080051bc, 0x080051bc, 0x080051bc, 0x080051bc, 0x080051bc, 0x080051e4,
-	0x080051e4, 0x0800520c, 0x0800525c, 0x0800522c, 0x00000000 };
+static const u32 bnx2_CP_b09FwData[(0x84/4) + 1] = {
+	0x00000000, 0x0000001b, 0x0000000f, 0x0000000a, 0x00000008, 0x00000006,
+	0x00000005, 0x00000005, 0x00000004, 0x00000004, 0x00000003, 0x00000003,
+	0x00000003, 0x00000003, 0x00000003, 0x00000002, 0x00000002, 0x00000002,
+	0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002,
+	0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002,
+	0x00000001, 0x00000001, 0x00000001, 0x00000000 };
+static const u32 bnx2_CP_b09FwRodata[(0x178/4) + 1] = {
+	0x80080100, 0x80080080, 0x80080000, 0x080015a0, 0x080015d8, 0x08001600,
+	0x08001600, 0x08001614, 0x080015bc, 0x080018a4, 0x0800186c, 0x080018f8,
+	0x080018f8, 0x08001980, 0x080018b4, 0x80080240, 0x80080100, 0x80080080,
+	0x80080000, 0x08003148, 0x080030b4, 0x08003170, 0x08003198, 0x080031c0,
+	0x080031e4, 0x0800322c, 0x08003208, 0x08003250, 0x0800311c, 0x08003344,
+	0x08003334, 0x080030d0, 0x080030d0, 0x080030d0, 0x080032a4, 0x080032a4,
+	0x080030d0, 0x080030d0, 0x08003324, 0x080030d0, 0x080030d0, 0x080030d0,
+	0x080030d0, 0x08003314, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0,
+	0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0,
+	0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x08003304, 0x080030d0,
+	0x080030d0, 0x080032f4, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0,
+	0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0,
+	0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0,
+	0x080030d0, 0x080032dc, 0x080030d0, 0x080030d0, 0x080032cc, 0x080032bc,
+	0x08003c0c, 0x08003be8, 0x08003bbc, 0x08003b9c, 0x08003b7c, 0x08003b24,
+	0x80080100, 0x80080080, 0x80080000, 0x80080080, 0x00000000 };
 
 static struct fw_info bnx2_cp_fw_09 = {
-	/* Firmware version:  3.7.1 */
-	.ver_major			= 0x3,
-	.ver_minor			= 0x7,
-	.ver_fix			= 0x1,
+	/* Firmware version: 4.0.5 */
+	.ver_major			= 0x4,
+	.ver_minor			= 0x0,
+	.ver_fix			= 0x5,
 
-	.start_addr			= 0x0800006c,
+	.start_addr			= 0x08000074,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x6fd0,
+	.text_len			= 0x5770,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_CP_b09FwText,
 	.gz_text_len			= sizeof(bnx2_CP_b09FwText),
 
-	.data_addr			= 0x08007100,
-	.data_len			= 0x0,
+	.data_addr			= 0x08005900,
+	.data_len			= 0x84,
 	.data_index			= 0x0,
 	.data				= bnx2_CP_b09FwData,
 
-	.sbss_addr			= 0x08007104,
-	.sbss_len			= 0xa9,
+	.sbss_addr			= 0x08005988,
+	.sbss_len			= 0x99,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x080071b0,
-	.bss_len			= 0x3b0,
+	.bss_addr			= 0x08005a28,
+	.bss_len			= 0x20c,
 	.bss_index			= 0x0,
 
-	.rodata_addr			= 0x08006fd0,
-	.rodata_len			= 0x118,
+	.rodata_addr			= 0x08005770,
+	.rodata_len			= 0x178,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_CP_b09FwRodata,
 };
 
 static u8 bnx2_RXP_b09FwText[] = {
-	0xec, 0x5c, 0x7d, 0x6c, 0x1c, 0xc7, 0x75, 0x7f, 0x3b, 0xbb, 0xa4, 0x8e,
-	0xd4, 0x91, 0x5c, 0x1e, 0x4f, 0xcc, 0x51, 0xa6, 0xed, 0x5b, 0x71, 0x25,
-	0x9e, 0x4d, 0xc6, 0x59, 0xd1, 0x07, 0x9b, 0x28, 0x0e, 0xc9, 0x66, 0xef,
-	0x24, 0xb1, 0x86, 0x5b, 0x53, 0x35, 0x1d, 0x1b, 0x6d, 0xea, 0xb2, 0x47,
-	0xb5, 0x29, 0x8c, 0x06, 0x90, 0xbf, 0x00, 0x17, 0xa8, 0xe4, 0xcb, 0x91,
-	0x8a, 0x55, 0xf7, 0xc0, 0xbd, 0xc8, 0x8c, 0x18, 0x20, 0x6e, 0x7d, 0x25,
-	0x29, 0x4a, 0x08, 0x0e, 0x3a, 0xa6, 0x71, 0x1a, 0xfd, 0x61, 0xd7, 0x04,
-	0x2b, 0x1b, 0x6e, 0x91, 0xd6, 0x72, 0xe3, 0xb6, 0x46, 0x50, 0x04, 0x84,
-	0xec, 0x34, 0x6e, 0xd0, 0x0f, 0xa1, 0x2e, 0x6c, 0x03, 0x96, 0xbd, 0xfd,
-	0xbd, 0xd9, 0x5d, 0xf2, 0x48, 0x5b, 0x76, 0xd0, 0x3f, 0xfa, 0x4f, 0x77,
-	0x80, 0xc3, 0xce, 0xcc, 0xbe, 0xf7, 0xe6, 0xcd, 0x9b, 0xf7, 0x39, 0x4b,
-	0xe9, 0xb7, 0xe3, 0xd4, 0x4e, 0x41, 0xeb, 0xc0, 0x2f, 0x7d, 0xf4, 0xb1,
-	0x87, 0x6e, 0xb9, 0xfd, 0x96, 0x5b, 0xd1, 0xdd, 0xaf, 0x2a, 0x3b, 0xd4,
-	0x70, 0x3e, 0x6a, 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45,
-	0x2d, 0x6a, 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d,
-	0x6a, 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d, 0x6a,
-	0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d, 0x6a, 0x51,
-	0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d, 0x6a, 0x51, 0x8b,
-	0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0xed, 0xff, 0x7b, 0x53, 0x89,
-	0x74, 0x7e, 0x76, 0x04, 0x3f, 0x8a, 0x89, 0x5c, 0xfa, 0x01, 0xc7, 0xa4,
-	0x98, 0x9a, 0xeb, 0x3f, 0x3e, 0x65, 0x12, 0xd9, 0xf5, 0xa1, 0x74, 0x9e,
-	0x3e, 0xf0, 0x4a, 0x49, 0x8d, 0x78, 0xfe, 0xfa, 0xdc, 0xd5, 0x67, 0x9e,
-	0xbf, 0xdd, 0xb8, 0x52, 0x53, 0x29, 0xa6, 0xe7, 0x66, 0xf6, 0xeb, 0xfb,
-	0x28, 0xd6, 0x0f, 0x9c, 0xa7, 0x07, 0xff, 0xb1, 0x93, 0x3a, 0x43, 0x5a,
-	0x44, 0x0b, 0x15, 0xc3, 0x3a, 0x88, 0xe7, 0x72, 0x7d, 0xc8, 0x5a, 0x23,
-	0x8d, 0x56, 0x75, 0x7f, 0xc5, 0x72, 0x45, 0x61, 0x3a, 0x54, 0xae, 0xc7,
-	0x68, 0x5d, 0xfe, 0x3b, 0x0f, 0xac, 0x69, 0x72, 0xff, 0x82, 0xe2, 0x34,
-	0x3c, 0xef, 0x8c, 0xe5, 0x79, 0x2f, 0xe1, 0xf7, 0x33, 0x0b, 0x63, 0xf7,
-	0x43, 0xcf, 0xd6, 0x54, 0x12, 0xe6, 0x1f, 0x2b, 0xce, 0x62, 0x2b, 0x95,
-	0xe7, 0x89, 0xa6, 0xdd, 0x18, 0x9d, 0x74, 0x4b, 0x4a, 0xa1, 0x51, 0x51,
-	0x0e, 0x9c, 0x9d, 0x55, 0x0e, 0x9e, 0x3d, 0xa9, 0x1c, 0x3a, 0x5b, 0x55,
-	0x9c, 0xb3, 0x54, 0x12, 0xfb, 0xe3, 0x64, 0xeb, 0xe7, 0x94, 0x7c, 0xa3,
-	0x57, 0x71, 0xe6, 0xaf, 0x7a, 0x8e, 0x65, 0xe8, 0xbf, 0x4e, 0x9a, 0xcd,
-	0xeb, 0x39, 0x15, 0x0f, 0x63, 0x8d, 0xec, 0xa4, 0xe7, 0x89, 0x9c, 0xf7,
-	0xb8, 0x93, 0x35, 0x75, 0xa1, 0xc4, 0xa8, 0xdc, 0x68, 0x07, 0x5d, 0x4d,
-	0xc9, 0xbb, 0xde, 0x0b, 0x8e, 0xb5, 0x0c, 0x3a, 0x75, 0xe0, 0x93, 0x2e,
-	0x72, 0xcc, 0x4f, 0xc8, 0x63, 0x49, 0xc9, 0x0f, 0x86, 0xfc, 0x50, 0x9a,
-	0xf9, 0x2d, 0x2e, 0x09, 0xf0, 0xb5, 0x93, 0x8a, 0x35, 0x9d, 0x26, 0x97,
-	0xb6, 0xc3, 0xaf, 0x7b, 0xcf, 0x0f, 0xea, 0xb4, 0xd2, 0x30, 0x4a, 0x25,
-	0xec, 0x7d, 0xc6, 0x4d, 0x93, 0xc8, 0x91, 0xed, 0x64, 0xfb, 0xe9, 0x85,
-	0x46, 0x8a, 0xfe, 0xbc, 0x61, 0xa6, 0xca, 0xb4, 0x83, 0x8a, 0xc9, 0x24,
-	0x7d, 0x17, 0x38, 0xd3, 0x58, 0x5b, 0x98, 0xa6, 0x5e, 0x06, 0x6c, 0xb9,
-	0xf1, 0x23, 0xfe, 0xb7, 0x31, 0xfa, 0x54, 0x56, 0xe2, 0x94, 0xc0, 0x67,
-	0x00, 0xcb, 0x7c, 0x4b, 0x58, 0xc9, 0xbb, 0x0f, 0x4b, 0xa5, 0xa9, 0x2c,
-	0xe6, 0x1a, 0x4e, 0x20, 0xfb, 0x56, 0xec, 0x8f, 0x9f, 0x37, 0x28, 0xf9,
-	0xf9, 0x1b, 0x20, 0x03, 0x4a, 0x0a, 0xda, 0x9b, 0x2a, 0x62, 0x66, 0xba,
-	0x11, 0xc7, 0x98, 0x79, 0xf1, 0xbc, 0x43, 0x16, 0xe9, 0x65, 0xab, 0x0b,
-	0xb2, 0x4a, 0x53, 0xd9, 0xea, 0x04, 0x4e, 0x0b, 0x75, 0x9b, 0xbc, 0x07,
-	0xa6, 0xdb, 0x86, 0x79, 0xaf, 0x43, 0xcd, 0x79, 0xde, 0x54, 0x96, 0x3a,
-	0xfd, 0xb9, 0x21, 0xd0, 0xd0, 0x68, 0x72, 0x5c, 0x01, 0xdc, 0xdb, 0xcc,
-	0x5f, 0x2c, 0x91, 0xe3, 0x3e, 0x3f, 0xb3, 0xe4, 0xcc, 0xa6, 0x83, 0x75,
-	0xe3, 0x54, 0x76, 0xaf, 0x0f, 0xfa, 0x90, 0xad, 0x8b, 0x3d, 0x5b, 0x7d,
-	0x18, 0x2b, 0x37, 0x82, 0x8e, 0x55, 0x26, 0x5e, 0x63, 0x17, 0xad, 0x25,
-	0x49, 0x5c, 0xb6, 0x7a, 0x02, 0xb8, 0x4e, 0xf0, 0x1a, 0x9e, 0x71, 0x3b,
-	0xcd, 0xcc, 0xb7, 0xd2, 0x89, 0x79, 0x96, 0x6d, 0x05, 0x67, 0x21, 0x68,
-	0xcf, 0x6d, 0x25, 0xc5, 0x6e, 0x9c, 0x44, 0x5f, 0xa3, 0x29, 0xd3, 0x7b,
-	0x61, 0xc6, 0x9a, 0x55, 0xf2, 0x67, 0x97, 0x95, 0x02, 0xce, 0xfc, 0xc0,
-	0xd9, 0x0b, 0xca, 0xc1, 0xc6, 0xcb, 0x1d, 0xd4, 0x6e, 0x40, 0xbb, 0x34,
-	0x3a, 0xe1, 0x2a, 0xc4, 0xfc, 0x2e, 0x40, 0x5e, 0xb6, 0x0e, 0xc9, 0x9b,
-	0x9d, 0xca, 0x41, 0xd0, 0x6a, 0x31, 0xbf, 0x1e, 0xa7, 0x4e, 0x95, 0x76,
-	0x98, 0x21, 0x6c, 0x8c, 0xbe, 0x0e, 0xde, 0xd6, 0xac, 0x24, 0xe0, 0xa8,
-	0xcb, 0xc7, 0xe9, 0x0e, 0xf8, 0x61, 0xdd, 0x61, 0xbd, 0x11, 0x76, 0x61,
-	0xee, 0x8f, 0x7a, 0xca, 0xc3, 0x3b, 0x19, 0x06, 0xf6, 0x60, 0x3f, 0x30,
-	0x65, 0x3a, 0xdd, 0x1a, 0x95, 0x74, 0x41, 0x86, 0x9e, 0xa7, 0x1b, 0x69,
-	0xc6, 0x22, 0xca, 0x43, 0x9f, 0x85, 0xa9, 0x41, 0x46, 0x26, 0x64, 0xb4,
-	0xb7, 0xa4, 0x8a, 0x7b, 0x41, 0xa2, 0xa4, 0x68, 0x81, 0x3c, 0x17, 0xe8,
-	0x0e, 0x89, 0x2f, 0x72, 0x16, 0x74, 0xb0, 0x9d, 0xfb, 0x58, 0x37, 0x26,
-	0xd7, 0x55, 0x73, 0x66, 0x6a, 0x91, 0x48, 0x11, 0xb9, 0x21, 0xd0, 0x63,
-	0xdd, 0x64, 0x38, 0x17, 0x3c, 0x32, 0xef, 0xdc, 0x37, 0x81, 0x13, 0x23,
-	0xc7, 0xea, 0x68, 0xe2, 0x13, 0xfc, 0x24, 0x59, 0xe6, 0x2c, 0x43, 0xb9,
-	0x4f, 0x65, 0x73, 0x9f, 0xef, 0x7b, 0x83, 0x23, 0x1a, 0xbd, 0x24, 0xf7,
-	0xcb, 0x76, 0xc4, 0x70, 0x72, 0x8f, 0xc4, 0xf2, 0x99, 0x76, 0x49, 0x29,
-	0x5a, 0xfa, 0x06, 0x2d, 0xe8, 0x85, 0x50, 0x73, 0x71, 0xca, 0x4b, 0xfe,
-	0x46, 0xb1, 0x16, 0xdb, 0x17, 0xec, 0xc4, 0xe4, 0xbd, 0xf0, 0x5c, 0x0e,
-	0xb6, 0x6a, 0x48, 0xfd, 0x29, 0x56, 0xd9, 0xfe, 0x99, 0xb7, 0x55, 0x43,
-	0x50, 0x48, 0x4f, 0xf4, 0xaa, 0xd4, 0x45, 0xe3, 0xd6, 0x55, 0x4f, 0xec,
-	0xc3, 0xfb, 0xe1, 0x14, 0x78, 0x33, 0xd2, 0xb0, 0xb6, 0x84, 0x4a, 0xb0,
-	0x73, 0x6b, 0x28, 0xa5, 0x93, 0x89, 0xbd, 0x25, 0xc8, 0x1e, 0x5f, 0x85,
-	0xe0, 0xaf, 0xc5, 0xa7, 0x4f, 0x17, 0x6c, 0xda, 0x0e, 0x78, 0x74, 0xac,
-	0x5b, 0xa5, 0xcc, 0x74, 0xec, 0x5f, 0x9d, 0x65, 0xf9, 0xb6, 0x43, 0xff,
-	0x15, 0x2a, 0x5a, 0x4c, 0x3b, 0xa4, 0x21, 0x68, 0xf0, 0xb6, 0x66, 0x1a,
-	0xe1, 0xd9, 0xb2, 0xfe, 0x6a, 0x34, 0x32, 0xc2, 0xb0, 0x0c, 0xc7, 0xf0,
-	0xc6, 0x68, 0x5a, 0xbc, 0xef, 0xed, 0xdf, 0xb2, 0xa6, 0x49, 0x62, 0x16,
-	0x3c, 0xfb, 0x67, 0x01, 0x19, 0x7e, 0x1a, 0x2c, 0x9f, 0xc3, 0x76, 0x79,
-	0x33, 0x6c, 0x33, 0x1c, 0x74, 0xa8, 0x97, 0x79, 0xa8, 0xc7, 0x7d, 0x7b,
-	0x0c, 0x79, 0x0a, 0xcf, 0x52, 0x09, 0x68, 0x7c, 0xd2, 0x3e, 0x18, 0x1e,
-	0x7e, 0xc2, 0x85, 0x9f, 0x70, 0xe1, 0x1f, 0x5c, 0xf8, 0x11, 0x97, 0xfd,
-	0x4a, 0x9a, 0x9e, 0x1f, 0x84, 0xdf, 0xdb, 0xf4, 0x43, 0x68, 0x63, 0xe8,
-	0x0b, 0x52, 0xe1, 0x87, 0xa6, 0x6b, 0x02, 0xb6, 0x0e, 0x9b, 0x5b, 0xe2,
-	0x39, 0x1d, 0xcf, 0x02, 0x9e, 0x26, 0xfc, 0x2c, 0xeb, 0x61, 0xe8, 0x5f,
-	0xd9, 0x2f, 0xa5, 0xe0, 0x83, 0xd8, 0xef, 0xb0, 0x7f, 0x62, 0x58, 0xcf,
-	0x2b, 0x58, 0x8c, 0xeb, 0xe1, 0x1c, 0xd9, 0xee, 0xe2, 0x24, 0x12, 0x25,
-	0xe5, 0xf0, 0x20, 0x6c, 0xf2, 0xe6, 0x16, 0xf0, 0xca, 0xb6, 0x79, 0x1d,
-	0xbb, 0x16, 0xb4, 0xf7, 0x3b, 0xfc, 0x7f, 0xb7, 0xb7, 0x03, 0x30, 0xd2,
-	0xc6, 0x3b, 0xfd, 0x71, 0x77, 0xe0, 0x7f, 0xf8, 0xbd, 0x91, 0xb6, 0x69,
-	0x5f, 0x30, 0xe6, 0xfe, 0x06, 0xbf, 0x96, 0xb8, 0x2d, 0x46, 0x7b, 0x96,
-	0x7d, 0xbf, 0xb9, 0x67, 0x01, 0x9a, 0xb1, 0xec, 0xf3, 0xb8, 0xe7, 0x7c,
-	0xe8, 0x3f, 0x3b, 0x40, 0x0f, 0xfc, 0xb9, 0x9b, 0x71, 0x84, 0xe8, 0xbf,
-	0x14, 0x98, 0x16, 0xe6, 0xb6, 0xcb, 0xc2, 0xf3, 0x66, 0x2c, 0xb6, 0x4f,
-	0xbd, 0xd9, 0x3e, 0xf7, 0xc3, 0x3e, 0xad, 0x56, 0x32, 0xac, 0xbf, 0x82,
-	0x7d, 0x3e, 0x61, 0x29, 0x90, 0x0d, 0xd1, 0xc5, 0x4a, 0x1c, 0xbe, 0x41,
-	0x4b, 0xbd, 0x41, 0x7b, 0xd3, 0xd3, 0xd0, 0xcb, 0x33, 0x3c, 0x87, 0x23,
-	0x3a, 0x21, 0xfd, 0xb5, 0xef, 0x0f, 0xd6, 0xd5, 0x6f, 0x80, 0x2f, 0xcf,
-	0x9b, 0x06, 0xcd, 0xe2, 0xb0, 0x1a, 0xd8, 0x62, 0x38, 0x6f, 0x23, 0x26,
-	0x3a, 0x37, 0xa9, 0x54, 0xca, 0xb4, 0x90, 0x91, 0x59, 0x00, 0xed, 0x29,
-	0xcb, 0xb7, 0x7b, 0xb6, 0x8d, 0x45, 0xd0, 0x9f, 0x71, 0x07, 0xe1, 0x17,
-	0xd8, 0x6e, 0xc0, 0x17, 0xe8, 0x2f, 0x82, 0xfe, 0x4c, 0xa3, 0x85, 0xbe,
-	0xa6, 0x85, 0xb1, 0x36, 0xdc, 0x0f, 0x44, 0x6d, 0x86, 0xeb, 0x1e, 0xa5,
-	0x3b, 0xdc, 0x84, 0xe2, 0x3c, 0xc5, 0x7e, 0xb9, 0x9c, 0x81, 0x5d, 0x29,
-	0x65, 0x8b, 0xd7, 0x56, 0x69, 0x71, 0x03, 0x86, 0xec, 0xb2, 0x6f, 0xb3,
-	0xb6, 0x33, 0x58, 0x4a, 0xa9, 0xd2, 0xf7, 0x10, 0x1d, 0xac, 0x68, 0x80,
-	0xe1, 0x31, 0xcf, 0xfb, 0x73, 0x63, 0x95, 0x5e, 0xf8, 0x52, 0x1e, 0x5f,
-	0xf5, 0xa6, 0x2c, 0x7f, 0xee, 0x97, 0x2b, 0x0f, 0xf0, 0x19, 0x61, 0x2f,
-	0x94, 0x2e, 0x5b, 0x3f, 0xf7, 0xa0, 0xbf, 0x5b, 0x70, 0x3e, 0x9e, 0x8e,
-	0x31, 0xe6, 0xeb, 0x2c, 0x29, 0x87, 0x4c, 0xd1, 0xdb, 0x1a, 0xf8, 0xbc,
-	0x43, 0x98, 0x3c, 0x50, 0x29, 0xf7, 0xb4, 0xd2, 0x55, 0x95, 0x63, 0xeb,
-	0x65, 0x38, 0x01, 0xa7, 0xb2, 0x0f, 0xf2, 0x28, 0x77, 0x37, 0xcd, 0xc5,
-	0x0a, 0x15, 0x8f, 0xd6, 0x2c, 0x1f, 0x07, 0xe3, 0x78, 0xbe, 0x22, 0x7a,
-	0x63, 0xb4, 0x31, 0xd6, 0x19, 0x67, 0x89, 0xf6, 0x65, 0x16, 0x49, 0xe2,
-	0xf6, 0xc4, 0x36, 0x71, 0x93, 0x85, 0x4a, 0xb9, 0xbb, 0x69, 0x9c, 0xca,
-	0x83, 0x96, 0xd8, 0xbf, 0x81, 0xdb, 0xbf, 0x89, 0xbb, 0x8b, 0xd2, 0xdd,
-	0x8c, 0x2f, 0x7a, 0xdb, 0x36, 0x69, 0xa7, 0x03, 0x7e, 0x7a, 0xda, 0x36,
-	0x69, 0x98, 0x4c, 0xb3, 0x69, 0x9c, 0x61, 0x9a, 0x7b, 0x36, 0x69, 0x0e,
-	0x6f, 0xe5, 0xe7, 0x28, 0xc1, 0x07, 0xc5, 0x5a, 0x73, 0xb4, 0xff, 0x62,
-	0x65, 0x60, 0xfc, 0x0e, 0x42, 0x8c, 0x1c, 0xde, 0x11, 0xf8, 0x70, 0x6d,
-	0xbf, 0x03, 0x59, 0x69, 0xc4, 0x3e, 0x51, 0xa1, 0x32, 0xce, 0xf9, 0x81,
-	0x3a, 0xed, 0x5f, 0xab, 0x53, 0xa0, 0x4b, 0xac, 0x13, 0x6f, 0xc1, 0xc6,
-	0xa8, 0xb4, 0x3b, 0x17, 0x9f, 0xd4, 0x72, 0x3a, 0x6c, 0x8d, 0xc6, 0xcb,
-	0xf0, 0xe1, 0x6a, 0x6e, 0xef, 0xeb, 0x79, 0xf5, 0x71, 0x4f, 0x35, 0xd9,
-	0x1f, 0xc6, 0x47, 0x9d, 0x2c, 0xe6, 0xeb, 0x6c, 0x5b, 0xf0, 0x2b, 0x0d,
-	0xa6, 0xfd, 0x4c, 0x17, 0x75, 0x22, 0x8e, 0xd6, 0xcf, 0xec, 0xf2, 0x6d,
-	0x87, 0x34, 0x0d, 0xbe, 0x79, 0x26, 0xcb, 0x71, 0xbf, 0x35, 0x06, 0xf8,
-	0x49, 0x35, 0x37, 0xd6, 0x77, 0xa4, 0x7e, 0x67, 0x5f, 0xb1, 0x5e, 0xea,
-	0x2b, 0x56, 0x74, 0xb6, 0x13, 0xe1, 0x64, 0xd1, 0x97, 0xb9, 0x54, 0x0a,
-	0x36, 0xc1, 0x6b, 0x27, 0xb1, 0xe6, 0x0f, 0x60, 0x7f, 0x6c, 0xdf, 0x44,
-	0xe3, 0x2e, 0xd6, 0x18, 0xf9, 0x00, 0xe7, 0x0e, 0xde, 0xe0, 0xd3, 0x6c,
-	0xec, 0x5a, 0x8c, 0xfc, 0x6b, 0x60, 0x9f, 0xdc, 0x7f, 0xc7, 0xf3, 0xe3,
-	0xc3, 0xdd, 0x5d, 0xfe, 0xdc, 0x8f, 0x03, 0x9b, 0x0e, 0x69, 0x31, 0x9d,
-	0x8c, 0x32, 0x8e, 0x1c, 0x66, 0xbc, 0xa1, 0x29, 0xec, 0x9f, 0xf3, 0x2e,
-	0xe7, 0x1e, 0x9c, 0x77, 0x4c, 0x07, 0x7e, 0x8e, 0x6c, 0xe4, 0x4f, 0x9e,
-	0x40, 0x2e, 0x52, 0x84, 0xdd, 0x68, 0xb9, 0x2b, 0x34, 0x23, 0x7d, 0x24,
-	0xc5, 0x5a, 0x72, 0x8f, 0x01, 0xe6, 0xdf, 0x60, 0x73, 0xdd, 0x5d, 0x81,
-	0x1e, 0x06, 0x3e, 0x5e, 0xfa, 0x5d, 0xc0, 0xbe, 0xb5, 0x0d, 0xf6, 0xcd,
-	0x66, 0x58, 0xbc, 0x5f, 0xdf, 0xf6, 0xfe, 0x9f, 0xd9, 0x7e, 0xf1, 0x6e,
-	0x15, 0xfe, 0xb4, 0x35, 0xb0, 0xfd, 0x8b, 0x54, 0x84, 0x6f, 0xd5, 0x4c,
-	0xce, 0x2d, 0x0f, 0x02, 0x17, 0xe3, 0x3a, 0x78, 0x84, 0xbf, 0x40, 0x8c,
-	0x85, 0xbc, 0x11, 0x13, 0x92, 0x37, 0x72, 0x3e, 0x05, 0xd8, 0x34, 0x60,
-	0xd9, 0xff, 0x32, 0xec, 0x85, 0x38, 0xcb, 0xbc, 0x58, 0x67, 0x1c, 0xf6,
-	0x55, 0xe4, 0x39, 0xd9, 0x36, 0x68, 0x94, 0xf7, 0x82, 0x6a, 0x86, 0xb0,
-	0x21, 0xdd, 0xed, 0xb0, 0x9c, 0xdf, 0x30, 0xed, 0xae, 0x20, 0x6f, 0x18,
-	0x23, 0xbb, 0x61, 0xe3, 0x57, 0xa2, 0xa9, 0xa7, 0x90, 0xbb, 0x99, 0x2d,
-	0x2c, 0x0b, 0x9e, 0xd7, 0x7d, 0x19, 0x85, 0x78, 0xa5, 0x9e, 0xad, 0xe3,
-	0xdf, 0x4a, 0x6c, 0xfa, 0x4a, 0xb6, 0x34, 0xb2, 0x11, 0x2b, 0x20, 0xe3,
-	0xf4, 0xa4, 0xc8, 0x25, 0x29, 0x5f, 0xf7, 0xe5, 0x8b, 0xf8, 0x0c, 0xff,
-	0x28, 0xfd, 0x07, 0xce, 0x3d, 0xf4, 0x83, 0xe1, 0x99, 0xb3, 0x9e, 0xd9,
-	0x38, 0x9b, 0x34, 0x74, 0x69, 0x0c, 0xb8, 0x74, 0x14, 0x34, 0x38, 0x6e,
-	0x5b, 0x22, 0x97, 0xa0, 0xa2, 0xce, 0xf9, 0x85, 0xcc, 0x0d, 0x6d, 0xf6,
-	0x03, 0x22, 0xd7, 0x86, 0x39, 0xee, 0xff, 0x41, 0x97, 0x7f, 0xd6, 0x1d,
-	0x3c, 0x1e, 0x17, 0xb9, 0xae, 0x6d, 0xf3, 0x7f, 0xd7, 0xe1, 0xf3, 0x26,
-	0xc7, 0x98, 0xff, 0xc9, 0xb6, 0xf1, 0xa3, 0x89, 0xad, 0xe3, 0xaf, 0xf6,
-	0x85, 0xfa, 0x20, 0x72, 0x8f, 0x05, 0xfc, 0xb2, 0x9e, 0x6e, 0xe7, 0xf5,
-	0x17, 0xd1, 0x97, 0x3f, 0x01, 0x4d, 0xa9, 0xe3, 0xbf, 0x80, 0xbe, 0x6c,
-	0xc0, 0x5e, 0x43, 0x5f, 0x9a, 0x79, 0xd8, 0xa8, 0x3b, 0xaa, 0x02, 0x39,
-	0xac, 0x93, 0xdd, 0x9b, 0x2e, 0xc3, 0xc6, 0x0b, 0x0d, 0xc8, 0x6e, 0x23,
-	0xae, 0x6e, 0xc0, 0x94, 0x36, 0x61, 0xfc, 0xb8, 0x53, 0x68, 0x78, 0xc8,
-	0xfb, 0x9a, 0x63, 0x70, 0x06, 0xfd, 0x12, 0xf6, 0xba, 0x42, 0x53, 0xee,
-	0x9a, 0x2d, 0xcc, 0x93, 0x32, 0x6f, 0x15, 0xe6, 0x93, 0x4a, 0x61, 0x91,
-	0x73, 0xda, 0x18, 0xfa, 0xb2, 0x3e, 0x41, 0x8c, 0x3b, 0xa5, 0xd8, 0x67,
-	0xe7, 0x90, 0xcf, 0x2e, 0xe1, 0x77, 0x0e, 0xbf, 0x3a, 0x7e, 0x61, 0xdd,
-	0xf0, 0x2d, 0xd4, 0x1d, 0xd2, 0xdf, 0x23, 0x36, 0xf9, 0xeb, 0xff, 0x74,
-	0x09, 0xf9, 0xf4, 0x5c, 0x92, 0x9e, 0x30, 0x45, 0x8f, 0xf0, 0x7d, 0x9c,
-	0x8d, 0x5c, 0x5c, 0x7f, 0x8b, 0x7e, 0x25, 0xc8, 0xe9, 0x88, 0xde, 0xa8,
-	0xe2, 0x2c, 0x87, 0x0f, 0x05, 0xfe, 0xe9, 0xe4, 0x57, 0x1c, 0xe9, 0xcb,
-	0x83, 0x9c, 0x0d, 0x7e, 0xc7, 0x96, 0x50, 0xaf, 0x40, 0x3e, 0x0a, 0xfd,
-	0x0c, 0x7a, 0xfc, 0x46, 0xb5, 0x1d, 0xfc, 0x98, 0x54, 0x9c, 0x30, 0x46,
-	0x49, 0x19, 0xd0, 0x77, 0x28, 0xed, 0xc8, 0xdb, 0xe0, 0x77, 0xe4, 0x98,
-	0x65, 0x46, 0xc7, 0x17, 0x2a, 0x02, 0xb0, 0x90, 0x79, 0x16, 0x7d, 0xe8,
-	0xdf, 0xe5, 0x2a, 0xe3, 0x09, 0x7a, 0xb3, 0xaa, 0xd2, 0xbf, 0x20, 0x0f,
-	0xc4, 0xbb, 0xe3, 0xb0, 0xc1, 0x5e, 0xc4, 0xab, 0x7e, 0x95, 0xf6, 0x72,
-	0xcc, 0xd8, 0xa3, 0xe1, 0x59, 0xc0, 0xef, 0x20, 0xf2, 0xc2, 0x6b, 0xe0,
-	0x5c, 0x03, 0x9e, 0x79, 0x8b, 0x01, 0x87, 0xe1, 0x35, 0xf0, 0xd6, 0x09,
-	0x1d, 0x34, 0xf4, 0x49, 0xfa, 0x8c, 0x2e, 0x73, 0x27, 0x85, 0xe7, 0x7d,
-	0x3f, 0xf9, 0xd1, 0x79, 0x96, 0xb3, 0x0a, 0x1d, 0xe2, 0x31, 0xbf, 0x63,
-	0x7f, 0xce, 0xf4, 0x8c, 0x51, 0x1b, 0x9b, 0xb9, 0x5c, 0xf5, 0xfb, 0xe1,
-	0x1c, 0x29, 0x61, 0x4c, 0x65, 0x3f, 0x5d, 0x80, 0xad, 0xf2, 0x78, 0x9c,
-	0xe4, 0x19, 0x6c, 0x39, 0x4f, 0xa9, 0x47, 0xc7, 0x66, 0x4c, 0x3e, 0x57,
-	0x9d, 0xa6, 0x2b, 0xe1, 0xb9, 0xf2, 0x19, 0xa1, 0x0e, 0xad, 0x3e, 0x89,
-	0x73, 0x15, 0x41, 0xcd, 0x02, 0x3f, 0x30, 0xc7, 0xe7, 0x8b, 0x3a, 0xb2,
-	0x8a, 0x3c, 0xac, 0x4a, 0x09, 0xbf, 0xe6, 0x3a, 0x85, 0x3a, 0x05, 0xe7,
-	0x57, 0x99, 0x03, 0x8d, 0x24, 0x9e, 0x4b, 0x78, 0xa6, 0xf0, 0x3c, 0x87,
-	0x67, 0x3f, 0x9e, 0x75, 0xb6, 0x8f, 0x20, 0xef, 0xf9, 0x08, 0x3f, 0xb0,
-	0x93, 0x02, 0xdb, 0x34, 0xfd, 0x65, 0x23, 0x47, 0x3f, 0x68, 0x8c, 0xd2,
-	0x5f, 0x34, 0xb2, 0xf4, 0xfd, 0x86, 0x45, 0xcf, 0x36, 0x86, 0xe9, 0x7b,
-	0x8d, 0x0c, 0xd7, 0x90, 0xc8, 0xe1, 0xd2, 0xf0, 0xcd, 0x17, 0xe8, 0x2b,
-	0x6e, 0x03, 0x3e, 0x47, 0xfa, 0xcb, 0xe3, 0x76, 0xfd, 0x3a, 0x2a, 0x3e,
-	0xa5, 0x23, 0xcf, 0x54, 0xb9, 0x8e, 0xa3, 0x47, 0xad, 0xbb, 0x13, 0x7c,
-	0xf6, 0xc2, 0xe4, 0xba, 0xe6, 0x04, 0xc3, 0xa1, 0x1e, 0x56, 0x90, 0xbf,
-	0xb4, 0xd0, 0x64, 0xd2, 0x58, 0x71, 0xd4, 0x74, 0xe0, 0x8f, 0x26, 0x00,
-	0x87, 0x35, 0xdd, 0x38, 0xad, 0x9d, 0x86, 0x2d, 0x58, 0xa8, 0xa5, 0x93,
-	0x31, 0xf8, 0x3e, 0x99, 0x9f, 0x48, 0xdf, 0xe2, 0xfb, 0xd2, 0xb0, 0xc6,
-	0xe4, 0x39, 0x3b, 0x98, 0xe3, 0xf8, 0xa8, 0x03, 0xb6, 0x11, 0xc4, 0x90,
-	0xed, 0x34, 0xd9, 0x37, 0x4e, 0x04, 0xfe, 0x71, 0x85, 0x1e, 0x76, 0x07,
-	0xec, 0xb7, 0x11, 0x7b, 0x94, 0x96, 0x30, 0x2f, 0xda, 0x0d, 0xde, 0x3c,
-	0xef, 0x30, 0xea, 0xf3, 0x74, 0x42, 0xa3, 0xbf, 0x9f, 0x35, 0xf4, 0xc3,
-	0x02, 0x01, 0xae, 0xdd, 0xf3, 0xc6, 0x4d, 0xa3, 0x64, 0x8b, 0x0e, 0xfa,
-	0xa7, 0x53, 0x1c, 0x93, 0xd7, 0x8f, 0xbd, 0x08, 0x3d, 0xa8, 0x2d, 0xb5,
-	0x52, 0xad, 0xa6, 0xd1, 0xe5, 0x91, 0x01, 0xb9, 0x6e, 0xad, 0x9e, 0x40,
-	0x9e, 0xd7, 0x46, 0x8b, 0xbd, 0x52, 0xd9, 0xe1, 0xb7, 0x33, 0xd2, 0x6f,
-	0x3b, 0x26, 0x9e, 0xf5, 0xb4, 0xbe, 0x95, 0x97, 0x67, 0xa9, 0xe8, 0x76,
-	0xa2, 0x42, 0xd9, 0x0d, 0x99, 0x70, 0x7f, 0x40, 0x77, 0x04, 0x62, 0xa0,
-	0x36, 0xa0, 0x1f, 0x12, 0xff, 0xed, 0x7d, 0x51, 0x63, 0x39, 0xbe, 0x8e,
-	0xd8, 0xc2, 0xb1, 0x52, 0x91, 0x7a, 0xb7, 0xb0, 0xf4, 0xa6, 0xce, 0xfe,
-	0xe5, 0x7b, 0xf5, 0xdd, 0xc1, 0x98, 0xfd, 0x3b, 0x8f, 0xdb, 0xe9, 0xfb,
-	0xb5, 0x9d, 0xb4, 0x58, 0xe3, 0xf7, 0xad, 0xb4, 0x50, 0x1b, 0xb8, 0xf2,
-	0x90, 0xe8, 0xa5, 0xd5, 0xeb, 0x6e, 0xd6, 0x3f, 0x2f, 0x20, 0x93, 0x89,
-	0x0f, 0xe9, 0xdd, 0x91, 0x2e, 0x7a, 0xf5, 0x5e, 0xa3, 0x7a, 0xbf, 0x80,
-	0x3e, 0x8e, 0xc4, 0xd9, 0xce, 0xd0, 0xe7, 0x79, 0xe3, 0x4a, 0x5a, 0xb0,
-	0x9e, 0xbd, 0x0c, 0xfd, 0x32, 0x4e, 0xfa, 0x3a, 0xc9, 0xb4, 0x99, 0x2e,
-	0xce, 0xc7, 0x7c, 0x05, 0x34, 0xf1, 0xae, 0x3e, 0x00, 0x5a, 0xaf, 0x48,
-	0x59, 0x1c, 0xb6, 0x8c, 0x2b, 0x08, 0x51, 0xde, 0x65, 0x73, 0x20, 0x23,
-	0xc4, 0x6e, 0xaa, 0xa5, 0x6e, 0xd6, 0xbf, 0x8b, 0x78, 0x80, 0x9a, 0xab,
-	0xb4, 0x4e, 0xeb, 0xc7, 0x2e, 0x9a, 0xac, 0x8b, 0x6c, 0xc3, 0x3f, 0x44,
-	0x4e, 0xaa, 0xd3, 0x53, 0x75, 0xf6, 0x5d, 0x4c, 0x8b, 0xeb, 0x82, 0x7d,
-	0xfa, 0xdd, 0xe0, 0xc1, 0x19, 0xc6, 0x3b, 0xcc, 0xab, 0x9f, 0xe5, 0x73,
-	0x6b, 0x61, 0xdc, 0x4c, 0x9a, 0x37, 0xb3, 0x45, 0x46, 0x03, 0xfa, 0x5e,
-	0xc1, 0xeb, 0xbd, 0x8b, 0x75, 0xdf, 0x01, 0xaf, 0x03, 0xc0, 0x45, 0x0c,
-	0x4d, 0x35, 0xaf, 0xf1, 0x9a, 0x5c, 0xe3, 0x54, 0x1d, 0x39, 0xe0, 0xc6,
-	0x1a, 0x98, 0xab, 0x0b, 0xec, 0xf3, 0x57, 0x65, 0xfe, 0xac, 0x22, 0xff,
-	0xb9, 0x3c, 0xf2, 0x4c, 0x90, 0x5f, 0x3c, 0x07, 0x59, 0xc7, 0xe8, 0xb5,
-	0x59, 0xae, 0x2f, 0x0f, 0x51, 0x39, 0xb1, 0x7e, 0x6c, 0xca, 0x44, 0x4d,
-	0x8f, 0x38, 0x50, 0xde, 0x37, 0xe0, 0xeb, 0x55, 0x3f, 0xe3, 0x3c, 0x27,
-	0xcf, 0xa4, 0x2c, 0x5a, 0xe9, 0x8b, 0x5a, 0x1a, 0xf8, 0x3c, 0x77, 0x29,
-	0x38, 0xcf, 0x6f, 0x83, 0x1f, 0xf4, 0xeb, 0x3d, 0x81, 0xff, 0x4b, 0x40,
-	0x57, 0x87, 0xf4, 0xc3, 0x14, 0x0b, 0xfc, 0x5f, 0x82, 0x5e, 0x3d, 0xad,
-	0x42, 0x87, 0x58, 0x7f, 0xfa, 0xbb, 0x37, 0xf5, 0x87, 0xdf, 0xad, 0x1f,
-	0x73, 0xc0, 0x63, 0x7e, 0xae, 0x95, 0x0a, 0xd5, 0x18, 0x4d, 0x65, 0x91,
-	0x73, 0x23, 0xfe, 0xe4, 0xa1, 0x4b, 0x85, 0x1a, 0xeb, 0x72, 0x29, 0xd0,
-	0xe5, 0x78, 0x40, 0xfb, 0x6f, 0xa0, 0xcb, 0x46, 0x7a, 0x55, 0x70, 0x7d,
-	0xd5, 0x27, 0x6b, 0x64, 0x15, 0xf6, 0x55, 0xac, 0x70, 0x2c, 0x62, 0xdb,
-	0xa2, 0xe3, 0xcc, 0x7f, 0xb1, 0x32, 0x2a, 0x8a, 0x8d, 0xac, 0x28, 0xba,
-	0xcc, 0xdf, 0x3e, 0xf0, 0xad, 0xc8, 0x3a, 0x78, 0xa1, 0xf1, 0xae, 0xb7,
-	0xb0, 0x6f, 0x07, 0xfa, 0xd0, 0xfd, 0x71, 0x3e, 0xdf, 0xeb, 0x99, 0xaf,
-	0xb4, 0x2d, 0x58, 0xde, 0x49, 0x5a, 0x1e, 0x7c, 0xa9, 0x8b, 0x73, 0xb4,
-	0xb3, 0x83, 0x4c, 0x1f, 0x7c, 0x24, 0x93, 0xb4, 0xe8, 0xf2, 0x1a, 0x2c,
-	0x17, 0xf8, 0xba, 0x39, 0x9d, 0x1e, 0x96, 0xe7, 0xc7, 0xba, 0xc5, 0xf7,
-	0x4d, 0x2a, 0xe5, 0x13, 0x03, 0xfa, 0x43, 0x64, 0x5c, 0x59, 0x53, 0x8d,
-	0xea, 0x24, 0xe2, 0xea, 0xc2, 0xbc, 0x4a, 0x7b, 0x64, 0x1d, 0xc6, 0x67,
-	0x64, 0x9c, 0x84, 0x35, 0x06, 0x7b, 0xff, 0x8d, 0xa6, 0xbd, 0x77, 0xd2,
-	0xc5, 0xd3, 0x9f, 0x85, 0xdd, 0xb3, 0x5c, 0xb5, 0xf4, 0x11, 0xe4, 0x19,
-	0x73, 0x04, 0xf9, 0x22, 0x7f, 0xb6, 0x53, 0xe1, 0xb9, 0xb0, 0xbc, 0x77,
-	0x49, 0xf9, 0x0b, 0x29, 0xff, 0x1b, 0xa8, 0xdc, 0xeb, 0xdb, 0x38, 0xbf,
-	0x13, 0xa0, 0xe1, 0xbf, 0xe3, 0xf1, 0x67, 0x90, 0x1f, 0xf1, 0xbb, 0x9a,
-	0x8f, 0x47, 0x3d, 0x4c, 0x07, 0xef, 0xfe, 0x10, 0x6b, 0xb2, 0x8c, 0xc3,
-	0xf9, 0x0e, 0xf2, 0x6d, 0x29, 0x94, 0x3b, 0x12, 0x8c, 0x7a, 0x92, 0x7e,
-	0xad, 0x9e, 0xa2, 0x89, 0x7a, 0x3f, 0x15, 0xea, 0x69, 0x9c, 0xc1, 0x13,
-	0xdd, 0xbc, 0xb7, 0xfc, 0x12, 0xf6, 0x23, 0x98, 0xd7, 0x1a, 0x1d, 0x71,
-	0x43, 0x7e, 0xe2, 0x01, 0x7f, 0x5a, 0x30, 0x8e, 0x05, 0x3c, 0x34, 0xd3,
-	0x8b, 0x83, 0x96, 0x0d, 0x3a, 0x67, 0x02, 0x3a, 0xec, 0x47, 0xc0, 0xeb,
-	0x44, 0x8a, 0x96, 0x5c, 0xe6, 0x63, 0x27, 0x95, 0x93, 0xdc, 0x7f, 0x0e,
-	0x7a, 0xc6, 0x74, 0x76, 0x70, 0x7e, 0xb3, 0x45, 0xc6, 0x47, 0xeb, 0x25,
-	0xc8, 0x98, 0xe5, 0xcb, 0x70, 0x71, 0x5a, 0xf8, 0x25, 0x3e, 0xbf, 0x21,
-	0xe4, 0xf8, 0xac, 0x0b, 0x3b, 0x03, 0xbd, 0xf2, 0xd7, 0x2c, 0xcc, 0x75,
-	0xe2, 0xac, 0x78, 0xdd, 0x76, 0xba, 0x07, 0x76, 0x9f, 0xaf, 0xf1, 0xfa,
-	0x13, 0xd0, 0xa3, 0x1f, 0xcb, 0xf5, 0x0b, 0x4b, 0xbd, 0x01, 0x3e, 0xe3,
-	0x76, 0x6e, 0xc3, 0x6d, 0xa5, 0x03, 0x55, 0xfd, 0x63, 0xf0, 0x7f, 0x13,
-	0xf8, 0x82, 0xce, 0x64, 0x19, 0x9f, 0xe9, 0x00, 0xae, 0x96, 0xfc, 0x04,
-	0x3a, 0x09, 0x59, 0xef, 0xe7, 0x6b, 0xad, 0x94, 0xaf, 0x86, 0xb4, 0x98,
-	0xce, 0x87, 0xa8, 0x87, 0xbf, 0x2c, 0x69, 0x4d, 0x49, 0x5a, 0x78, 0x5f,
-	0x63, 0x9f, 0x73, 0x3b, 0xf0, 0xe3, 0xec, 0xff, 0x69, 0x21, 0xd1, 0x41,
-	0x0b, 0xb2, 0xa6, 0x6f, 0xf7, 0x7d, 0x4d, 0xa2, 0x0d, 0xef, 0x77, 0xc1,
-	0xe6, 0x87, 0x90, 0x5b, 0x74, 0x62, 0x2e, 0xbd, 0x6d, 0x6e, 0x3b, 0xff,
-	0xb1, 0x6d, 0xfc, 0xeb, 0x80, 0xeb, 0xc1, 0x9a, 0x3e, 0x5c, 0x01, 0x70,
-	0xd3, 0x73, 0x90, 0xb3, 0xc5, 0x7e, 0x85, 0xe3, 0xe4, 0x75, 0x92, 0x97,
-	0xe9, 0x25, 0x05, 0x70, 0xbd, 0xc0, 0x0d, 0xc7, 0xbe, 0x1c, 0xaa, 0xa0,
-	0xf3, 0xcd, 0x9a, 0xbc, 0xbb, 0xc0, 0x19, 0xf4, 0x24, 0x78, 0xef, 0xe5,
-	0xda, 0xa7, 0xc9, 0xec, 0xba, 0x26, 0x79, 0xb1, 0xac, 0x98, 0x5f, 0xe6,
-	0x15, 0x7a, 0x8a, 0x38, 0xe4, 0x58, 0xa8, 0x0b, 0x13, 0x2a, 0x15, 0xb2,
-	0x3a, 0xf2, 0x73, 0xbe, 0xb7, 0x65, 0xbb, 0xd4, 0xf9, 0xae, 0x34, 0x26,
-	0x4c, 0x8e, 0xb5, 0x9a, 0xdc, 0xfb, 0x91, 0x25, 0xbe, 0xbb, 0x4d, 0xf3,
-	0x5d, 0x5f, 0x86, 0xb0, 0xf7, 0x07, 0x97, 0x4c, 0x7a, 0xa4, 0x9e, 0xa1,
-	0x87, 0xea, 0x86, 0x7e, 0x3f, 0x7c, 0x40, 0x71, 0xe3, 0x4e, 0xf7, 0x73,
-	0x09, 0xae, 0x45, 0x34, 0xe4, 0x81, 0x2d, 0xa6, 0x9f, 0x17, 0x94, 0xb9,
-	0x66, 0x9b, 0x33, 0xf8, 0x1e, 0x47, 0xaf, 0xd1, 0xf6, 0xdc, 0xe1, 0xff,
-	0x32, 0x6f, 0xe0, 0xf5, 0xd9, 0x5f, 0x23, 0x4f, 0x70, 0x91, 0x27, 0xb8,
-	0xc8, 0x13, 0x5c, 0xe4, 0x09, 0x2e, 0xf2, 0x04, 0x17, 0x79, 0x82, 0x8b,
-	0x3c, 0xc1, 0x45, 0x9e, 0x80, 0xd8, 0xed, 0xd7, 0x0b, 0x63, 0xc8, 0x7f,
-	0xe1, 0xbf, 0xdc, 0xcf, 0x43, 0x4e, 0x7c, 0xdf, 0xc9, 0x31, 0x87, 0x63,
-	0x33, 0xcf, 0xad, 0xee, 0x70, 0xf8, 0xdc, 0xa4, 0xef, 0xbb, 0x13, 0x73,
-	0xe3, 0x41, 0x3e, 0xc2, 0x30, 0x61, 0xec, 0x66, 0x38, 0x1a, 0x75, 0x2c,
-	0x05, 0x36, 0xc6, 0xf9, 0x8a, 0x1f, 0xb3, 0xfc, 0x5c, 0xf9, 0x75, 0xe4,
-	0x2c, 0x69, 0xe4, 0x2c, 0xfd, 0xc8, 0x4f, 0xf8, 0x8e, 0x3b, 0xbc, 0x63,
-	0xb2, 0x95, 0xc3, 0xee, 0x98, 0x72, 0xb7, 0xcb, 0xb9, 0xb4, 0x99, 0x2e,
-	0x0a, 0x31, 0xd7, 0x43, 0x1e, 0xe5, 0x47, 0xbe, 0x86, 0xbc, 0xf5, 0x9b,
-	0xf2, 0x3e, 0x6d, 0x7c, 0x90, 0xcf, 0x7c, 0xe5, 0x1a, 0xb9, 0x6b, 0x28,
-	0x5f, 0xff, 0x1e, 0x50, 0x2c, 0xb0, 0xfc, 0x88, 0xba, 0xcf, 0x43, 0xe0,
-	0xe7, 0x63, 0x94, 0x58, 0xde, 0x89, 0x39, 0x9d, 0x7a, 0xe4, 0x5d, 0x12,
-	0x8e, 0xf2, 0xbc, 0xd6, 0x43, 0xed, 0x26, 0x89, 0xf3, 0x7c, 0xe3, 0xc0,
-	0x74, 0xd9, 0xbf, 0x5e, 0x3a, 0x96, 0xaf, 0x5d, 0x92, 0x3a, 0x75, 0xb8,
-	0x5e, 0x40, 0x7d, 0xd4, 0x07, 0x18, 0x0d, 0xb5, 0x55, 0x48, 0x9b, 0x69,
-	0x5e, 0x4d, 0xc8, 0x9a, 0xe7, 0xfc, 0xc6, 0x79, 0xe2, 0xac, 0x79, 0x9d,
-	0x4b, 0xc7, 0xca, 0x55, 0x23, 0xc5, 0xb5, 0xb2, 0xad, 0x5f, 0x3a, 0x76,
-	0x02, 0x34, 0x16, 0x91, 0x1b, 0xa8, 0x72, 0xed, 0x4b, 0xc7, 0xa6, 0xab,
-	0xfe, 0x7d, 0x96, 0xcf, 0x03, 0xe2, 0x60, 0xb6, 0x9d, 0xd4, 0x05, 0xff,
-	0x5e, 0x4b, 0x48, 0x5c, 0xc6, 0x63, 0x7c, 0x0d, 0x78, 0x7c, 0x6e, 0x19,
-	0xe0, 0xf2, 0xd9, 0x31, 0x0f, 0x97, 0x8e, 0x95, 0x6a, 0xcd, 0x3c, 0x30,
-	0x1d, 0xa6, 0x1b, 0xee, 0x87, 0xf7, 0x92, 0x20, 0xb1, 0xec, 0x79, 0xc5,
-	0x91, 0xfe, 0x20, 0xef, 0x3a, 0x81, 0xfc, 0x4e, 0x93, 0x7a, 0xee, 0x8f,
-	0xff, 0x4c, 0xc6, 0xa9, 0xb4, 0xe0, 0x79, 0x7e, 0xe2, 0x5d, 0xf6, 0x3b,
-	0x98, 0xc3, 0x78, 0x31, 0x84, 0x15, 0x01, 0x6c, 0x47, 0x93, 0x3c, 0x5b,
-	0x82, 0xf5, 0x98, 0x27, 0xde, 0xe7, 0xcf, 0xb1, 0x7f, 0x79, 0x07, 0xc7,
-	0xf9, 0x18, 0xd6, 0xc5, 0x59, 0xba, 0xff, 0x5b, 0xd9, 0x37, 0xef, 0x89,
-	0x65, 0xaa, 0x01, 0x87, 0xe1, 0x99, 0x46, 0x88, 0x83, 0x17, 0xe7, 0x7d,
-	0x3c, 0xb1, 0x71, 0xff, 0xf7, 0x49, 0xeb, 0x36, 0xf3, 0x1a, 0xae, 0x1f,
-	0xd2, 0xc9, 0xf8, 0xe7, 0xb6, 0x81, 0x2f, 0xff, 0x4f, 0x31, 0x3c, 0xa1,
-	0x8b, 0x1f, 0xb9, 0x47, 0xcd, 0x34, 0xd5, 0xa1, 0xe1, 0xfd, 0x05, 0xdf,
-	0x07, 0x70, 0x7d, 0xcf, 0xdf, 0x1a, 0x9a, 0x6b, 0xc5, 0x67, 0x83, 0x58,
-	0xd6, 0x47, 0xb6, 0xc6, 0x75, 0xc3, 0x85, 0x60, 0xbc, 0x0b, 0xb1, 0x8d,
-	0xc7, 0x0d, 0xc8, 0x17, 0xba, 0x6c, 0xb5, 0x07, 0x75, 0x4b, 0xc2, 0xff,
-	0x26, 0x94, 0x61, 0x3b, 0xe2, 0xba, 0xaf, 0x2d, 0x98, 0x0b, 0xed, 0x88,
-	0xfd, 0xb0, 0x16, 0xcc, 0xb1, 0xbf, 0x15, 0xa8, 0x5d, 0xb8, 0x0f, 0x3a,
-	0x8b, 0xcd, 0xb6, 0x14, 0x3e, 0x13, 0x74, 0x6e, 0x3e, 0xf4, 0x5b, 0xf0,
-	0x29, 0x83, 0x5a, 0xe0, 0xfb, 0xe3, 0xf0, 0x7d, 0x9d, 0x74, 0x00, 0x3e,
-	0xeb, 0x20, 0x7c, 0xd6, 0x21, 0xd4, 0x8b, 0x63, 0x4b, 0xcd, 0xf7, 0xbc,
-	0x5c, 0xa3, 0x76, 0x2a, 0x47, 0xe4, 0xf9, 0x97, 0x3c, 0xd5, 0xfc, 0x10,
-	0x3a, 0xc0, 0x75, 0x57, 0xa8, 0x13, 0xf0, 0xb7, 0x56, 0x02, 0x3a, 0xb1,
-	0xfd, 0x3e, 0x39, 0x03, 0xdb, 0x68, 0xb7, 0x85, 0xcc, 0xe5, 0x7c, 0xd9,
-	0x97, 0x6b, 0xbe, 0xec, 0xe1, 0x97, 0x41, 0x5f, 0xa3, 0x52, 0x5d, 0xa7,
-	0x12, 0xd6, 0x2d, 0x61, 0xdd, 0x12, 0xea, 0xbc, 0xe9, 0x7a, 0xf3, 0x77,
-	0xaf, 0x8e, 0x80, 0x77, 0xc6, 0x0d, 0xfb, 0x7a, 0xd3, 0xfe, 0xc3, 0xe7,
-	0x49, 0xc8, 0xff, 0x11, 0xc8, 0xff, 0x28, 0xea, 0x9b, 0xdf, 0x47, 0x7d,
-	0xf3, 0x7b, 0xa8, 0x6f, 0x8e, 0xa0, 0xbe, 0x99, 0x44, 0x7d, 0xf3, 0x65,
-	0xf8, 0x8f, 0xfb, 0xe0, 0x3f, 0x26, 0xe0, 0x3f, 0xc6, 0xe5, 0xdd, 0xd3,
-	0x61, 0x77, 0xfb, 0x9d, 0x4a, 0xb8, 0x16, 0xb7, 0x9f, 0x12, 0x99, 0x25,
-	0xec, 0x69, 0x8c, 0x6a, 0x0d, 0xae, 0x6f, 0x2c, 0x72, 0x46, 0xb9, 0xbe,
-	0x99, 0x50, 0x26, 0x91, 0xbf, 0xdf, 0x3f, 0xcc, 0x75, 0x4f, 0x42, 0xc9,
-	0xcb, 0xba, 0xc7, 0xb8, 0xe0, 0x20, 0x75, 0x43, 0xee, 0x87, 0x3d, 0x1b,
-	0xe7, 0xf2, 0xe0, 0xc5, 0xcf, 0xf9, 0xba, 0x03, 0xbf, 0x17, 0xa7, 0xc5,
-	0x59, 0xd4, 0x0c, 0xee, 0x3f, 0x28, 0x45, 0xe9, 0x1b, 0x75, 0x8c, 0x51,
-	0x2b, 0xbb, 0xaf, 0x06, 0xe3, 0x11, 0x9a, 0x9a, 0x47, 0x6d, 0x7b, 0xfa,
-	0x6f, 0x95, 0xbc, 0x1c, 0x5b, 0x18, 0x23, 0xdf, 0x3d, 0xfd, 0xd7, 0xc1,
-	0xb8, 0x14, 0xe8, 0x43, 0xc0, 0xab, 0x6e, 0xe1, 0xd9, 0x15, 0xe4, 0x1c,
-	0x2f, 0xf6, 0x6c, 0xfd, 0x3f, 0xef, 0xb8, 0xb5, 0x28, 0x64, 0x1e, 0xdf,
-	0xe5, 0xd7, 0x67, 0xcd, 0xf3, 0x9d, 0x4d, 0xf3, 0xba, 0xfc, 0x0e, 0x5b,
-	0xac, 0xb4, 0xbd, 0x07, 0x0f, 0x4c, 0x4b, 0x83, 0x46, 0xd5, 0xa6, 0x0f,
-	0x3d, 0xfe, 0x5e, 0xe8, 0x88, 0x76, 0xf9, 0x0d, 0xcf, 0x91, 0xf7, 0x7a,
-	0xb0, 0xf3, 0x91, 0x27, 0x77, 0xf9, 0xbe, 0x80, 0xfb, 0x49, 0xc5, 0xf7,
-	0xef, 0x8f, 0x83, 0x0e, 0x64, 0xed, 0x36, 0xd7, 0x70, 0x7a, 0x70, 0x97,
-	0xa2, 0x1f, 0x9f, 0xe1, 0xb3, 0x96, 0xb4, 0xb9, 0xd6, 0xe3, 0xba, 0x2f,
-	0x8c, 0x01, 0x21, 0xad, 0xff, 0x48, 0xfa, 0x7c, 0xdf, 0x87, 0x9a, 0x8e,
-	0x61, 0xc2, 0x71, 0x73, 0xfd, 0x17, 0x0f, 0xee, 0xe1, 0x98, 0xd7, 0x58,
-	0xc0, 0xab, 0x16, 0xd0, 0xfb, 0x77, 0xcf, 0xf7, 0x3d, 0x8c, 0xaf, 0x37,
-	0xe1, 0x5f, 0x40, 0xae, 0xc7, 0x77, 0x26, 0xbb, 0xe5, 0x77, 0xc9, 0x77,
-	0x66, 0x3b, 0xe8, 0xed, 0x53, 0xc8, 0x59, 0x2d, 0x23, 0x73, 0x09, 0xb5,
-	0xc7, 0x32, 0xdb, 0xc9, 0x08, 0xf3, 0x39, 0x90, 0x9e, 0xa6, 0x9b, 0x7b,
-	0xfc, 0x5c, 0xfc, 0xab, 0xca, 0x47, 0xf9, 0x16, 0xc1, 0x3a, 0x3f, 0x6a,
-	0x5a, 0x27, 0xdd, 0xb4, 0xce, 0x0a, 0xdb, 0x6c, 0xed, 0x4b, 0xd8, 0x73,
-	0x69, 0xf7, 0xcd, 0x7a, 0x32, 0xa8, 0xcb, 0x1e, 0x1e, 0x69, 0xa3, 0x6a,
-	0xaf, 0xb1, 0xf2, 0x1a, 0xf2, 0xf5, 0xe2, 0x08, 0xe6, 0x92, 0x03, 0x78,
-	0xc7, 0xf3, 0x46, 0x8d, 0x84, 0xb1, 0x52, 0xa3, 0xcf, 0x01, 0xdf, 0x28,
-	0x11, 0xf1, 0x3c, 0xf7, 0x25, 0x6f, 0xb5, 0xc0, 0x07, 0xa4, 0xd6, 0xb0,
-	0xe7, 0x49, 0xd4, 0x5f, 0x47, 0x37, 0xea, 0x61, 0x5e, 0xe7, 0x56, 0x65,
-	0x4d, 0xe6, 0xc6, 0xfb, 0x95, 0x52, 0xd2, 0xdf, 0xe3, 0xef, 0xc2, 0x5f,
-	0xa8, 0x82, 0x71, 0xdf, 0x01, 0x6d, 0x85, 0x16, 0x4e, 0xa9, 0xf2, 0x0e,
-	0xb6, 0x38, 0xc2, 0x67, 0xcd, 0xcf, 0x8f, 0x93, 0x5d, 0xb8, 0xa7, 0x3f,
-	0x0d, 0xf6, 0x34, 0x16, 0xd4, 0xd3, 0xe1, 0x9e, 0x62, 0xf4, 0xe6, 0xac,
-	0x0e, 0xdc, 0x9b, 0x20, 0x8f, 0x02, 0x2d, 0x35, 0xd2, 0x9f, 0x42, 0xa7,
-	0xd2, 0x24, 0x1b, 0x6d, 0xdb, 0x19, 0x96, 0x36, 0x6b, 0xf8, 0xf1, 0x14,
-	0xec, 0xf0, 0x78, 0x4f, 0x78, 0x37, 0xac, 0x9a, 0x1e, 0xd7, 0x3d, 0x68,
-	0x3c, 0xdf, 0x0f, 0x5b, 0x4c, 0xc3, 0x3e, 0x39, 0x67, 0x2a, 0x70, 0xad,
-	0xc2, 0xf6, 0xa4, 0x3b, 0xaa, 0xa1, 0x4f, 0x50, 0x06, 0xf5, 0x0e, 0xef,
-	0x3f, 0x47, 0x8b, 0x8d, 0x90, 0x87, 0x2c, 0xec, 0x71, 0x14, 0xbf, 0x61,
-	0xbc, 0xb3, 0xf0, 0xe3, 0x5a, 0x69, 0x85, 0x1e, 0x95, 0xb9, 0x38, 0x72,
-	0xed, 0x41, 0xe6, 0xef, 0x4e, 0xc0, 0xb3, 0x3e, 0xb3, 0x9e, 0xde, 0x49,
-	0x4e, 0x2f, 0xfb, 0x8a, 0x14, 0x68, 0x03, 0xc7, 0x5d, 0x87, 0xad, 0xf7,
-	0xe3, 0x69, 0xe8, 0x45, 0x96, 0xad, 0xa4, 0xef, 0x79, 0x6a, 0x96, 0xbf,
-	0x51, 0x5c, 0x08, 0xc6, 0x03, 0xfa, 0x3d, 0xac, 0x7b, 0xa9, 0x1b, 0x68,
-	0x65, 0x3e, 0x8c, 0x83, 0x67, 0x60, 0x83, 0x7c, 0x67, 0x3b, 0x06, 0xb9,
-	0xf0, 0x58, 0x09, 0xe2, 0x21, 0xe6, 0x17, 0x91, 0x94, 0xb4, 0xe7, 0x68,
-	0x19, 0xf5, 0x3f, 0xf5, 0xf2, 0x13, 0xf9, 0xae, 0xbb, 0x33, 0xd0, 0xf7,
-	0xad, 0xf8, 0xaa, 0xc9, 0xfd, 0x31, 0xf0, 0xa7, 0x35, 0xe1, 0x33, 0x8e,
-	0x5f, 0x9f, 0xac, 0x11, 0xe2, 0x71, 0xca, 0xfb, 0x82, 0xc8, 0x3d, 0x4d,
-	0xbf, 0x23, 0xf7, 0x54, 0xa7, 0x23, 0xf3, 0xa8, 0x6d, 0xb3, 0x03, 0x99,
-	0x45, 0x32, 0x32, 0x27, 0x68, 0x48, 0x3f, 0x40, 0xaa, 0xfc, 0xd6, 0x97,
-	0x16, 0xde, 0x17, 0x5a, 0x72, 0x9e, 0x77, 0x06, 0xbc, 0xbf, 0x28, 0xd7,
-	0x79, 0x1a, 0xfc, 0x43, 0x56, 0xb2, 0x26, 0x61, 0x5e, 0xf1, 0x4c, 0x32,
-	0xbf, 0x15, 0x3a, 0xd2, 0xf8, 0x61, 0x70, 0x36, 0x8f, 0x90, 0xe3, 0xbe,
-	0xa5, 0x3a, 0x66, 0x05, 0xb0, 0xdf, 0x09, 0x78, 0xcb, 0x81, 0x5f, 0xac,
-	0xdf, 0x58, 0x4f, 0xb2, 0x6f, 0xe0, 0x33, 0x77, 0x90, 0x35, 0x3a, 0x23,
-	0xc8, 0xa3, 0x92, 0xd7, 0xf2, 0x03, 0x09, 0xda, 0xea, 0x07, 0x18, 0x2f,
-	0xf1, 0x31, 0xba, 0xc2, 0x7c, 0x94, 0xa4, 0xff, 0x94, 0x71, 0x4b, 0xd2,
-	0x53, 0xb7, 0xf9, 0x82, 0x6f, 0xc9, 0xe7, 0xaa, 0xca, 0xbe, 0x89, 0xe3,
-	0x1f, 0xeb, 0x70, 0x27, 0xfc, 0x1f, 0x74, 0x10, 0x76, 0x9c, 0x9f, 0xe7,
-	0xfb, 0x89, 0x41, 0xbe, 0x57, 0x3a, 0x57, 0xc0, 0xd9, 0x2e, 0xf0, 0xf7,
-	0xc7, 0xa4, 0x5f, 0x63, 0xfa, 0xf5, 0x57, 0x9a, 0x7d, 0x21, 0xda, 0x92,
-	0xf4, 0x93, 0x05, 0xf9, 0xbd, 0x31, 0x01, 0x18, 0x8f, 0x7d, 0x67, 0xd3,
-	0xdf, 0x58, 0xbc, 0x6c, 0xfb, 0x7f, 0x63, 0x11, 0x7c, 0xfb, 0xad, 0xf9,
-	0x79, 0xc4, 0x83, 0x75, 0x8d, 0x26, 0xeb, 0xe1, 0xdf, 0x5c, 0xf0, 0x39,
-	0xc0, 0x37, 0xd7, 0xc3, 0xdc, 0xc1, 0x93, 0xf1, 0xa5, 0xbc, 0xe5, 0x2c,
-	0x97, 0x82, 0x9c, 0x88, 0x6b, 0x00, 0x96, 0x21, 0xc6, 0x8b, 0xfe, 0xf9,
-	0x2d, 0x88, 0x3d, 0x38, 0x3f, 0xc8, 0x1c, 0x7c, 0xbd, 0x39, 0xeb, 0xd7,
-	0xb9, 0x65, 0xf6, 0x8b, 0xfd, 0x61, 0xdd, 0xbb, 0x9b, 0xca, 0x13, 0xfc,
-	0x3e, 0x46, 0x6f, 0xcc, 0xc6, 0xe4, 0xfb, 0x22, 0xc5, 0x82, 0xf7, 0x3c,
-	0x4e, 0x50, 0x51, 0xbe, 0xaf, 0x05, 0xf4, 0x50, 0xa7, 0xdd, 0x17, 0x8e,
-	0x35, 0xe5, 0x48, 0xc3, 0xc7, 0x9b, 0x6a, 0xd4, 0xe8, 0xd1, 0xc6, 0x2a,
-	0xf6, 0xaf, 0x50, 0x7e, 0xbc, 0x44, 0x37, 0x98, 0xba, 0x8c, 0xfb, 0x4e,
-	0x82, 0x75, 0x8c, 0xf5, 0x6b, 0x4c, 0xd6, 0x9d, 0x25, 0xe4, 0x0b, 0xc5,
-	0x11, 0xfe, 0xc6, 0xf3, 0xde, 0x5d, 0xc5, 0x8a, 0xa1, 0xdb, 0xf4, 0x81,
-	0xe7, 0x68, 0x3c, 0x26, 0x21, 0x72, 0xab, 0x77, 0x3d, 0x58, 0xbf, 0x78,
-	0x97, 0xbf, 0x57, 0xbc, 0xaf, 0x33, 0xac, 0x2a, 0xbf, 0xcd, 0xfe, 0xe4,
-	0x76, 0x8d, 0xd6, 0x6e, 0xf7, 0xbc, 0xfb, 0x2d, 0x9d, 0x9c, 0xa0, 0x76,
-	0xf5, 0xbf, 0xb9, 0xb7, 0xcb, 0x1c, 0xc4, 0x19, 0x49, 0x2b, 0x05, 0xd8,
-	0xeb, 0xb2, 0x8b, 0x3a, 0x47, 0x18, 0xa3, 0xab, 0x42, 0x47, 0xcc, 0xe5,
-	0x3b, 0x80, 0x3b, 0x7a, 0xf8, 0x7b, 0xf3, 0x8c, 0xc5, 0x30, 0x7d, 0xfe,
-	0x5d, 0xd7, 0x2d, 0xf7, 0x49, 0x3f, 0x4b, 0x14, 0xc4, 0x9e, 0x5b, 0x9a,
-	0x6d, 0xa2, 0x39, 0xb7, 0x64, 0x5b, 0xa0, 0x49, 0x0d, 0xbc, 0x94, 0x2b,
-	0x61, 0x9e, 0xc6, 0x7f, 0x4b, 0xb0, 0x7a, 0xd7, 0x37, 0xc0, 0xe7, 0x34,
-	0xf8, 0xe4, 0x7d, 0x4c, 0xd7, 0x43, 0x9d, 0x0b, 0x6b, 0x05, 0xee, 0x23,
-	0xe6, 0xbb, 0x88, 0xf9, 0x2e, 0x62, 0xbe, 0x8b, 0x98, 0xef, 0x22, 0xe6,
-	0xbb, 0x88, 0xf9, 0x2e, 0x62, 0xbe, 0x8b, 0x98, 0xef, 0x8e, 0x07, 0x79,
-	0xda, 0x63, 0x1b, 0x79, 0xda, 0x4a, 0x83, 0xbf, 0x43, 0x49, 0x5e, 0x4a,
-	0x25, 0xf2, 0xf3, 0x5c, 0x12, 0x9c, 0xd3, 0x84, 0x79, 0xee, 0xc7, 0x7f,
-	0x13, 0xf1, 0xf1, 0x38, 0xc7, 0x63, 0xbc, 0x92, 0x22, 0x4c, 0xc6, 0xf3,
-	0xf3, 0x3c, 0xae, 0xad, 0xb6, 0xe2, 0x20, 0x5f, 0xcb, 0xb1, 0x3f, 0x63,
-	0xbb, 0x48, 0xfa, 0xf5, 0x62, 0xee, 0xf5, 0x2f, 0xa1, 0x76, 0x3c, 0x5e,
-	0xac, 0xcb, 0x18, 0x8c, 0xf1, 0x7b, 0x18, 0x6b, 0xac, 0x73, 0xfc, 0xee,
-	0x5e, 0xae, 0x27, 0x8a, 0xf5, 0x14, 0x95, 0x16, 0xc3, 0xfc, 0x07, 0x78,
-	0xee, 0x90, 0x52, 0xa8, 0xf2, 0xd9, 0x0a, 0x9a, 0x4e, 0x42, 0x28, 0x66,
-	0x73, 0x5e, 0x77, 0x49, 0xd6, 0x48, 0xfe, 0xdf, 0x05, 0x0d, 0x83, 0xb7,
-	0xf0, 0x1e, 0x97, 0x48, 0x9d, 0x4d, 0xca, 0xbf, 0x31, 0x48, 0x98, 0x83,
-	0xf2, 0x6f, 0x1d, 0xba, 0xb1, 0x8e, 0x98, 0xdd, 0x13, 0xfe, 0xed, 0x06,
-	0xd7, 0x5d, 0xf6, 0xe6, 0xfd, 0x2b, 0xef, 0x23, 0x09, 0x7b, 0xbd, 0xa7,
-	0x0f, 0x7b, 0xc3, 0xb9, 0x5e, 0xd9, 0x25, 0xf3, 0x6e, 0xf8, 0xce, 0x33,
-	0x83, 0x37, 0xf5, 0x52, 0xe7, 0x6e, 0x5a, 0x1e, 0xe4, 0x1a, 0xad, 0x0d,
-	0xf4, 0x18, 0xd6, 0xc8, 0xd8, 0x62, 0x37, 0x9d, 0x9d, 0x87, 0x6f, 0x9d,
-	0x37, 0x2c, 0xfe, 0xfb, 0x82, 0x85, 0xc1, 0x24, 0x7c, 0xf2, 0x78, 0x2f,
-	0xc7, 0xe4, 0xc5, 0x06, 0xeb, 0x4a, 0x37, 0xf0, 0xfb, 0xa1, 0x8b, 0x3b,
-	0x60, 0x43, 0x02, 0xeb, 0x87, 0xb4, 0xff, 0x53, 0xd2, 0xee, 0x36, 0xf3,
-	0x7d, 0x52, 0x37, 0x84, 0xa1, 0xa7, 0x05, 0x78, 0xff, 0x48, 0x6d, 0x69,
-	0x11, 0x7f, 0x2f, 0x9c, 0x76, 0x9b, 0xbf, 0x1b, 0x0e, 0x29, 0xc5, 0x2a,
-	0xff, 0x8d, 0xc3, 0x20, 0xfd, 0x4f, 0xe1, 0x56, 0x17, 0xd3, 0xd6, 0x79,
-	0x86, 0xdf, 0xcf, 0xe6, 0x2f, 0xc4, 0x81, 0x13, 0xe2, 0x80, 0x41, 0x54,
-	0xf3, 0x31, 0x07, 0xe2, 0xca, 0x44, 0x3d, 0x20, 0x32, 0x59, 0x15, 0x52,
-	0x2d, 0xdb, 0x50, 0xb7, 0x5d, 0x36, 0x77, 0xcb, 0xa6, 0x4c, 0xda, 0x22,
-	0x06, 0x49, 0x9b, 0x6a, 0xd2, 0x2e, 0x76, 0x31, 0xed, 0x2e, 0x96, 0x81,
-	0x34, 0xcd, 0xec, 0x1a, 0x56, 0x32, 0xa4, 0x5d, 0x4c, 0xae, 0x31, 0x04,
-	0x88, 0x53, 0xab, 0x5b, 0x2f, 0x32, 0x4d, 0x53, 0x90, 0x57, 0x25, 0xdd,
-	0x4d, 0x6f, 0x76, 0x3f, 0x55, 0x64, 0xad, 0x72, 0xd1, 0x25, 0x6a, 0xa7,
-	0x6a, 0x7f, 0x17, 0x67, 0xcf, 0xf3, 0x9d, 0x63, 0x20, 0x6c, 0xd5, 0x90,
-	0xac, 0xf3, 0x9d, 0xef, 0x7c, 0xff, 0xdf, 0xfb, 0x3e, 0xef, 0x2f, 0x53,
-	0xa0, 0x2f, 0xc3, 0x8a, 0xa9, 0x4b, 0x65, 0xb6, 0xb1, 0x50, 0xa6, 0x1d,
-	0x7e, 0x13, 0xbc, 0xdc, 0x23, 0x8b, 0xa0, 0xe3, 0xfc, 0x68, 0xab, 0xe7,
-	0x6f, 0xed, 0xf4, 0x78, 0x38, 0xd2, 0xeb, 0xc9, 0x28, 0xad, 0x4b, 0xe6,
-	0xb5, 0x3e, 0xdd, 0x7d, 0xe8, 0xdb, 0x0f, 0xb0, 0xa6, 0x10, 0xce, 0x61,
-	0xb8, 0x57, 0xe3, 0x91, 0x8f, 0xef, 0x7d, 0x87, 0xde, 0x7b, 0x0f, 0xbd,
-	0x9f, 0xfc, 0x1f, 0xed, 0x59, 0x3e, 0x4c, 0x0f, 0x5c, 0xa7, 0x19, 0xe7,
-	0x2c, 0xf9, 0xc2, 0x84, 0x9a, 0x2b, 0x98, 0x09, 0xea, 0x02, 0x29, 0x71,
-	0x54, 0xca, 0x6e, 0x03, 0xc6, 0xb5, 0xc9, 0xc2, 0x0a, 0x68, 0x1e, 0xfb,
-	0x68, 0xb7, 0x18, 0x2f, 0x7f, 0xb6, 0x97, 0x3c, 0xd3, 0x81, 0x6b, 0xf0,
-	0x59, 0x43, 0x21, 0xb4, 0x73, 0x5e, 0xb3, 0x63, 0xc6, 0x45, 0xed, 0xbf,
-	0xa1, 0x0e, 0xe3, 0xa8, 0xbc, 0xce, 0xfd, 0x60, 0x9b, 0x16, 0x79, 0x60,
-	0x25, 0x7b, 0xbc, 0x5c, 0x22, 0xd8, 0xbb, 0x2f, 0xf6, 0x52, 0xbf, 0x78,
-	0xd5, 0xde, 0xab, 0x33, 0x76, 0x85, 0x79, 0x5a, 0x20, 0x9a, 0x97, 0x45,
-	0xca, 0x55, 0x91, 0x9b, 0xf8, 0xfd, 0xb1, 0xea, 0xc5, 0x2f, 0x14, 0x6d,
-	0xed, 0x49, 0xd9, 0x2e, 0x3d, 0x2b, 0x35, 0xc8, 0x9c, 0x2d, 0xdb, 0x71,
-	0x1e, 0xda, 0x61, 0x7d, 0xe6, 0xaf, 0x17, 0x94, 0x44, 0xc6, 0x28, 0xd3,
-	0xda, 0xe4, 0x67, 0x2b, 0xcc, 0xbb, 0x33, 0x8d, 0x87, 0xc2, 0xfc, 0xb7,
-	0x90, 0x64, 0x82, 0x7e, 0xad, 0x97, 0xca, 0xb7, 0x45, 0x3e, 0xc1, 0xb7,
-	0x4f, 0x56, 0x5e, 0xe9, 0xa5, 0xcf, 0xe5, 0xe3, 0x15, 0xbe, 0xfb, 0xf0,
-	0xf4, 0x49, 0xc3, 0xf2, 0x43, 0x7f, 0x05, 0xf0, 0x18, 0x3c, 0x77, 0xee,
-	0xf7, 0x47, 0x5c, 0x1b, 0xea, 0x68, 0xc3, 0xb6, 0x49, 0x7e, 0x18, 0x38,
-	0xa8, 0x86, 0x74, 0xbe, 0x52, 0x23, 0xa8, 0x71, 0xd9, 0x5f, 0x61, 0x5e,
-	0x9d, 0x71, 0x54, 0x63, 0x74, 0xf2, 0xf6, 0x82, 0xde, 0x0b, 0xca, 0xb9,
-	0x8a, 0x4d, 0x5a, 0x35, 0x64, 0x0b, 0xbc, 0xb6, 0x59, 0xdf, 0xea, 0xe3,
-	0x5d, 0x6d, 0xd7, 0x17, 0x7b, 0x5d, 0x1b, 0x8d, 0x75, 0xaf, 0xf7, 0xba,
-	0x75, 0x61, 0xcf, 0xe6, 0xa2, 0x6d, 0x56, 0xc6, 0xde, 0x7e, 0x2c, 0xf5,
-	0xd5, 0x9f, 0xca, 0x9d, 0xd2, 0x4f, 0xe4, 0xb7, 0xab, 0xe7, 0xa1, 0x73,
-	0x98, 0xe5, 0x1c, 0xe4, 0xc9, 0xbb, 0x75, 0xc7, 0x79, 0xd7, 0x3e, 0x07,
-	0xfb, 0xc0, 0x71, 0xfe, 0x64, 0xef, 0x48, 0x64, 0xfc, 0x7b, 0xd8, 0x73,
-	0x16, 0x3c, 0x44, 0x2c, 0xcc, 0x80, 0xde, 0x52, 0x7d, 0xd2, 0x19, 0xd0,
-	0x74, 0x32, 0x34, 0xde, 0x8a, 0x3d, 0xf8, 0x3c, 0x3d, 0x9c, 0x7b, 0x49,
-	0xf7, 0x91, 0x66, 0x7c, 0xf5, 0x0a, 0xe6, 0x6f, 0x05, 0x5f, 0x1c, 0xc5,
-	0x4f, 0xc9, 0xc3, 0x31, 0xac, 0x75, 0x8c, 0xb4, 0xd7, 0x2a, 0x91, 0x67,
-	0xb0, 0x8f, 0x6c, 0x8b, 0x3c, 0x2a, 0xdc, 0xea, 0xa5, 0x3f, 0xef, 0x51,
-	0x81, 0x65, 0xdf, 0x57, 0xbb, 0xc4, 0x91, 0x16, 0xc8, 0xef, 0x85, 0x09,
-	0x57, 0x57, 0xfa, 0x83, 0x3a, 0x85, 0xf6, 0x56, 0xee, 0x7d, 0x45, 0xdd,
-	0x2e, 0xe7, 0xb4, 0x42, 0x17, 0x9f, 0x82, 0x0e, 0x94, 0xac, 0x5f, 0x91,
-	0xc6, 0x58, 0x00, 0x6d, 0xa8, 0xa3, 0x68, 0x2c, 0x91, 0x54, 0x81, 0xf9,
-	0x5d, 0xcc, 0xb5, 0xc2, 0x1a, 0xcf, 0x11, 0x37, 0xb8, 0xc6, 0x36, 0xc6,
-	0xe0, 0xbc, 0x3a, 0x0b, 0x34, 0xc2, 0x3a, 0xd2, 0x77, 0x02, 0x3c, 0x99,
-	0xa0, 0xdc, 0xc4, 0x78, 0xa3, 0x18, 0x8f, 0xe5, 0x2e, 0x8c, 0x77, 0x45,
-	0x92, 0x76, 0x73, 0xcc, 0x38, 0xda, 0x10, 0x67, 0xe2, 0xd0, 0x1f, 0x06,
-	0x55, 0x7a, 0x25, 0x08, 0xf9, 0xdd, 0x2b, 0x69, 0xe3, 0xc8, 0x81, 0x3d,
-	0xe6, 0xb4, 0x7d, 0xe0, 0xf3, 0x8d, 0x7a, 0x6b, 0xea, 0x3a, 0xb0, 0x26,
-	0xf6, 0xc7, 0x0f, 0xb6, 0x71, 0x72, 0x65, 0x09, 0x38, 0xb5, 0xf4, 0x41,
-	0xd2, 0xbe, 0x20, 0xa9, 0x20, 0xd7, 0xc4, 0xfa, 0x20, 0xd6, 0x4c, 0x3f,
-	0xd6, 0x77, 0x81, 0x43, 0x47, 0xbc, 0x3a, 0xb6, 0x15, 0x5f, 0x12, 0x67,
-	0xef, 0xda, 0xb5, 0xac, 0xfb, 0x8a, 0x24, 0x97, 0xb2, 0x32, 0xad, 0xfb,
-	0xf1, 0x0c, 0x07, 0xb4, 0xee, 0x41, 0x5e, 0x8d, 0x9c, 0xc0, 0x59, 0xc6,
-	0xf6, 0x6d, 0xe0, 0xf0, 0x09, 0x72, 0x91, 0xd1, 0xe7, 0xf2, 0x2c, 0xbe,
-	0x9d, 0xe0, 0x1d, 0xb5, 0x49, 0xe4, 0x5b, 0x90, 0x91, 0x85, 0x66, 0x7d,
-	0x40, 0x3e, 0x2d, 0xf4, 0xf4, 0x31, 0xce, 0xf2, 0xd7, 0x82, 0x21, 0x1f,
-	0x17, 0x74, 0x2c, 0x74, 0xc6, 0x2f, 0xe6, 0x65, 0xd7, 0x3e, 0x1f, 0x9e,
-	0x59, 0x50, 0xfc, 0x3e, 0x7c, 0x79, 0x5d, 0x75, 0xa0, 0x6d, 0x00, 0xed,
-	0xb8, 0x0e, 0x43, 0xa6, 0x0a, 0x9f, 0x3b, 0xb3, 0x23, 0x8e, 0x33, 0xad,
-	0xf3, 0xc3, 0x62, 0xc6, 0x82, 0x6a, 0xea, 0xe4, 0x51, 0x29, 0x04, 0xdb,
-	0x31, 0x57, 0xcc, 0x58, 0x57, 0xc3, 0x58, 0x0f, 0xcb, 0x27, 0xc8, 0x13,
-	0xa1, 0x1d, 0xe1, 0xf8, 0x66, 0x66, 0x4d, 0xc5, 0xc2, 0x43, 0xca, 0x4c,
-	0xe4, 0xf1, 0x6b, 0x51, 0x3a, 0x8e, 0x18, 0x0a, 0x2b, 0xf0, 0x2e, 0xf6,
-	0x64, 0x9d, 0x76, 0x9c, 0x8c, 0xc5, 0xfa, 0x98, 0x11, 0x50, 0xf4, 0xb7,
-	0x74, 0xea, 0x78, 0xe3, 0xb5, 0x93, 0x31, 0xe3, 0xb4, 0x3a, 0xee, 0xbd,
-	0xc7, 0x81, 0x99, 0x7b, 0xe3, 0x9d, 0x5f, 0x53, 0x86, 0xbc, 0x51, 0x88,
-	0x85, 0xe7, 0x94, 0x99, 0xc5, 0x98, 0xd9, 0xb4, 0x22, 0x6e, 0xc4, 0x8c,
-	0x4e, 0x45, 0x9f, 0x68, 0xbb, 0xde, 0x77, 0x06, 0xfd, 0x63, 0xaa, 0xc5,
-	0x5b, 0x0f, 0xef, 0xeb, 0xed, 0x3e, 0x97, 0x67, 0x88, 0x39, 0x23, 0xc0,
-	0x4c, 0xe6, 0x9a, 0xe9, 0xdc, 0x86, 0x44, 0x64, 0x7c, 0x44, 0x63, 0xe8,
-	0xe3, 0x33, 0x7f, 0x47, 0x1d, 0xca, 0x65, 0xd6, 0x45, 0x3d, 0x7e, 0x1b,
-	0xd1, 0x3a, 0xf3, 0xe3, 0x33, 0x39, 0x9d, 0xf7, 0xd8, 0x50, 0x11, 0x6f,
-	0xdf, 0x7b, 0x77, 0x16, 0x4e, 0xda, 0x4f, 0x71, 0x9c, 0x25, 0xff, 0x64,
-	0xbb, 0x30, 0xa7, 0x74, 0xaa, 0xd4, 0xa4, 0x0d, 0xfa, 0x03, 0x98, 0x2f,
-	0xd0, 0x8c, 0x7b, 0x5f, 0x11, 0xdf, 0x78, 0xc7, 0x01, 0x3a, 0x81, 0xae,
-	0x09, 0x1d, 0xb5, 0x8a, 0x71, 0xf2, 0x2b, 0x92, 0x73, 0xfb, 0x4b, 0x07,
-	0x73, 0x58, 0xf3, 0xd5, 0x2f, 0x1b, 0x83, 0x73, 0x63, 0x0e, 0xbc, 0x3f,
-	0x3e, 0x43, 0xfa, 0xe4, 0xd9, 0x84, 0xd5, 0xd4, 0x2a, 0xd7, 0x33, 0x20,
-	0xd3, 0x2b, 0x83, 0x32, 0x87, 0xdf, 0xc2, 0x8a, 0x7b, 0x6f, 0x1b, 0xd0,
-	0xad, 0xa7, 0x0b, 0x86, 0xe6, 0xd7, 0x39, 0x9b, 0x31, 0x13, 0xf0, 0x8a,
-	0xce, 0xa9, 0x62, 0x5f, 0xc6, 0x89, 0x06, 0x29, 0x1f, 0xed, 0x06, 0xe4,
-	0xea, 0x46, 0x9d, 0x7a, 0x2a, 0xeb, 0xcd, 0x78, 0xd8, 0xdf, 0x2d, 0x0b,
-	0xc0, 0xbb, 0x0a, 0x64, 0x67, 0xfe, 0xcd, 0x80, 0xcc, 0x15, 0x74, 0x3c,
-	0x39, 0xfc, 0x17, 0x65, 0x4b, 0xad, 0x3e, 0x21, 0xb7, 0xeb, 0x51, 0xfd,
-	0x8d, 0x72, 0x2d, 0xff, 0x0b, 0x9f, 0xbc, 0x32, 0xa2, 0xf3, 0xea, 0xa2,
-	0x15, 0x79, 0xaa, 0x9f, 0x3a, 0xcf, 0xba, 0xce, 0xb1, 0x03, 0x76, 0x40,
-	0xe7, 0x78, 0x0f, 0x3a, 0xc7, 0x6f, 0xa0, 0x73, 0xfc, 0xba, 0x04, 0x7c,
-	0x29, 0x65, 0x3c, 0xfc, 0x9f, 0x01, 0x0e, 0x51, 0x56, 0x9b, 0xe7, 0x71,
-	0xa7, 0x33, 0x39, 0xd0, 0xe0, 0x47, 0x92, 0x01, 0xde, 0x26, 0x65, 0x73,
-	0x75, 0x5a, 0xb6, 0x56, 0xdd, 0x3c, 0xe5, 0xfb, 0xcc, 0x01, 0x1b, 0xe3,
-	0x3d, 0x45, 0x81, 0x43, 0x47, 0x24, 0x72, 0x9a, 0xf8, 0xd1, 0x21, 0x6b,
-	0xc5, 0xdf, 0x69, 0x1c, 0x5a, 0x2b, 0xb2, 0xec, 0x17, 0x9d, 0x4f, 0x76,
-	0x6e, 0x47, 0x2a, 0x76, 0x03, 0xf5, 0xc7, 0xb4, 0x0f, 0xc8, 0xf5, 0xc9,
-	0x13, 0x2f, 0x3f, 0xf7, 0xee, 0x5e, 0xe9, 0x3c, 0xbb, 0x59, 0xa3, 0x1b,
-	0xed, 0x9a, 0xd8, 0x35, 0xe4, 0xc6, 0xbc, 0xd5, 0xdf, 0xd0, 0x06, 0x73,
-	0x94, 0xba, 0x65, 0x03, 0x32, 0xa4, 0x11, 0xed, 0xd6, 0xba, 0x5f, 0x23,
-	0x3a, 0xa8, 0x73, 0x77, 0x39, 0x4e, 0xbe, 0x68, 0xc9, 0x7c, 0xd1, 0x0c,
-	0xe7, 0x40, 0x7f, 0xb7, 0x61, 0xab, 0x6d, 0xe2, 0x0e, 0xb6, 0x70, 0x06,
-	0xdb, 0x75, 0xca, 0xf9, 0x2f, 0x34, 0xf6, 0xae, 0xd5, 0x3f, 0xc3, 0x38,
-	0xe6, 0xf9, 0x84, 0x3c, 0xee, 0x23, 0x06, 0xd2, 0x1f, 0x95, 0xd2, 0xfd,
-	0xdd, 0x7e, 0x9b, 0x68, 0xbb, 0x55, 0x27, 0x1e, 0x8b, 0x5c, 0x2d, 0x58,
-	0x90, 0x25, 0xbf, 0x0a, 0x51, 0x07, 0x28, 0xab, 0x66, 0x3f, 0xc7, 0x5b,
-	0xb3, 0xe3, 0x1c, 0xb5, 0xb8, 0xae, 0xa8, 0x87, 0xdb, 0x94, 0xfd, 0x3b,
-	0x5a, 0xee, 0x17, 0x4a, 0x17, 0xe4, 0x1d, 0xdc, 0xb7, 0xab, 0xe3, 0x64,
-	0xe5, 0x16, 0x74, 0xbc, 0x7a, 0xa9, 0x99, 0xd7, 0x3d, 0x89, 0x73, 0x32,
-	0xd5, 0xfc, 0xf2, 0x75, 0xb9, 0x76, 0x63, 0x57, 0xbd, 0x71, 0x23, 0xa2,
-	0xae, 0x2f, 0x0f, 0xa9, 0xfc, 0xb2, 0xe3, 0xfc, 0xd3, 0x9e, 0x95, 0x3b,
-	0xab, 0x8e, 0x9c, 0xb5, 0x7d, 0xfd, 0x7e, 0x69, 0xe6, 0xd6, 0x39, 0x4e,
-	0x07, 0xb0, 0x79, 0xfb, 0xa4, 0xe3, 0x3c, 0x3d, 0x36, 0x26, 0xd1, 0x93,
-	0xd4, 0x51, 0x9e, 0x0b, 0x31, 0x3f, 0x96, 0x98, 0x93, 0xb4, 0xac, 0xcb,
-	0x15, 0xa5, 0x80, 0x6f, 0xdd, 0xae, 0xfe, 0xf2, 0xcc, 0x31, 0x2f, 0x56,
-	0x72, 0xe7, 0x35, 0xfa, 0x92, 0x43, 0xff, 0xe5, 0x4b, 0x36, 0xe4, 0x62,
-	0x71, 0x04, 0xfd, 0x83, 0xf2, 0xc3, 0x62, 0xe0, 0x50, 0xd9, 0xc0, 0x73,
-	0x54, 0xe5, 0x8b, 0x8f, 0x9c, 0x21, 0x1d, 0x33, 0x80, 0x4e, 0x62, 0x38,
-	0xce, 0x9c, 0xcd, 0xf9, 0xba, 0x31, 0xdf, 0x8e, 0x71, 0x0c, 0xf2, 0xff,
-	0xac, 0x96, 0xcf, 0x17, 0x15, 0x6c, 0x5f, 0xf0, 0x77, 0x50, 0xd2, 0x45,
-	0xc8, 0x78, 0xc5, 0x9c, 0x53, 0xea, 0x0a, 0x66, 0x68, 0x0e, 0xd8, 0x31,
-	0x0b, 0xbc, 0x79, 0x49, 0xc7, 0x56, 0x4f, 0x68, 0xec, 0x99, 0x67, 0x39,
-	0x2b, 0x89, 0x8a, 0xdd, 0xa3, 0xcf, 0x6f, 0xf7, 0xf6, 0x2f, 0x43, 0xee,
-	0x9d, 0x83, 0x8f, 0xb3, 0x4a, 0xda, 0x60, 0x03, 0xa5, 0xd6, 0xcf, 0x81,
-	0x27, 0x42, 0x38, 0xdb, 0x56, 0xcd, 0x0f, 0x0d, 0xc8, 0xef, 0x86, 0xf6,
-	0x23, 0xba, 0xf1, 0x8a, 0x86, 0xc1, 0x76, 0x17, 0xd0, 0xaf, 0x5d, 0x92,
-	0xcb, 0x6d, 0x1a, 0x57, 0x9f, 0xac, 0x4b, 0x40, 0x0f, 0xf9, 0x3e, 0xca,
-	0x7e, 0xd4, 0x85, 0xbd, 0xb2, 0x0f, 0xe5, 0x19, 0x94, 0x5b, 0xf0, 0x64,
-	0x9b, 0x61, 0xe8, 0x15, 0x78, 0xbe, 0x8d, 0xf1, 0xc6, 0xb0, 0xe6, 0xac,
-	0x21, 0x1f, 0x9e, 0xa1, 0x2c, 0x19, 0x55, 0xcc, 0x63, 0x9e, 0xb3, 0xf0,
-	0xac, 0x0d, 0xa9, 0xd4, 0x12, 0xcb, 0x78, 0x96, 0xdd, 0xef, 0x4f, 0x60,
-	0x12, 0xfa, 0x24, 0x6f, 0xb8, 0x98, 0xf4, 0xe1, 0x1e, 0x26, 0xb1, 0xae,
-	0x5d, 0xd2, 0xcb, 0xe4, 0x75, 0x03, 0xf4, 0xd6, 0x29, 0xa9, 0x1b, 0x41,
-	0xad, 0x8f, 0x56, 0x40, 0x8b, 0x1b, 0xa0, 0xab, 0x35, 0xd0, 0x54, 0xb2,
-	0x68, 0xc6, 0x67, 0x54, 0x58, 0xfb, 0x02, 0x5e, 0x00, 0xbd, 0x76, 0xbc,
-	0x49, 0x5d, 0x94, 0xbc, 0x1c, 0x05, 0xed, 0x89, 0xd3, 0x61, 0x59, 0x99,
-	0xa8, 0xb2, 0x40, 0x83, 0xa0, 0xcb, 0xa2, 0xcb, 0xd3, 0xef, 0x2b, 0x8d,
-	0xab, 0xf1, 0x07, 0x12, 0x4b, 0x3c, 0x10, 0x13, 0x58, 0x60, 0xda, 0x1f,
-	0x88, 0x8d, 0x31, 0x27, 0xe4, 0x26, 0xe6, 0xf1, 0x81, 0xbf, 0x47, 0x4e,
-	0x69, 0xfe, 0x8e, 0x8b, 0xff, 0x30, 0x8f, 0x83, 0xde, 0x80, 0x41, 0x2e,
-	0x4f, 0x27, 0x3c, 0x1a, 0xfd, 0x26, 0xf8, 0xd7, 0x84, 0x25, 0x16, 0x94,
-	0x05, 0xf0, 0xff, 0x06, 0xbe, 0xdf, 0xad, 0x0f, 0xab, 0xf9, 0x25, 0xe5,
-	0xe5, 0x92, 0x7c, 0x07, 0x7a, 0xf2, 0x43, 0x9c, 0x5d, 0x97, 0xd6, 0xdd,
-	0x23, 0x63, 0x8c, 0x9f, 0x65, 0xd4, 0x35, 0xeb, 0xb4, 0xec, 0x8e, 0x4e,
-	0xa0, 0x7c, 0x0c, 0x4f, 0x1f, 0xce, 0x21, 0xa0, 0xe3, 0xdf, 0x6b, 0x05,
-	0x5b, 0xb9, 0xff, 0xd3, 0x30, 0x8e, 0xbe, 0xc4, 0xb2, 0x93, 0xf8, 0x4e,
-	0x5f, 0x0c, 0xf7, 0x06, 0x9d, 0x49, 0x85, 0x74, 0xbe, 0x69, 0x05, 0xba,
-	0xc4, 0x3a, 0xc6, 0xbb, 0x47, 0x5f, 0x5e, 0x0d, 0x3c, 0x3c, 0xfa, 0x2f,
-	0x27, 0x11, 0x64, 0x4e, 0xfb, 0x17, 0x21, 0x57, 0xfe, 0x7d, 0xea, 0xec,
-	0x5a, 0xf3, 0x71, 0x1f, 0x5e, 0x3e, 0x32, 0x82, 0x68, 0x0b, 0x59, 0x06,
-	0x59, 0x54, 0xd6, 0xf4, 0xcb, 0x76, 0x6e, 0xdf, 0x7c, 0x2d, 0x66, 0xdc,
-	0x17, 0xb7, 0xef, 0x82, 0x45, 0xb9, 0xd3, 0x0e, 0x7c, 0x09, 0x6b, 0xbd,
-	0xf2, 0x9e, 0x95, 0x03, 0x2a, 0x98, 0xe1, 0x0c, 0x68, 0xb4, 0x4d, 0xcc,
-	0xe8, 0x94, 0xec, 0xcf, 0x3b, 0xa7, 0xfb, 0xb2, 0x6d, 0xb3, 0x6f, 0x73,
-	0x5e, 0xae, 0x9f, 0x7b, 0xe1, 0x1e, 0xe8, 0x9b, 0x36, 0x34, 0x8d, 0x36,
-	0x6a, 0x03, 0xfd, 0x2e, 0x8d, 0x36, 0xf7, 0x11, 0xfc, 0x3f, 0xfb, 0x20,
-	0x9d, 0xd8, 0xca, 0x8d, 0xd3, 0xe3, 0x59, 0xe3, 0x79, 0x0e, 0x83, 0x36,
-	0x0e, 0xd2, 0x4f, 0xd3, 0xb7, 0xe8, 0xd2, 0xcf, 0xd3, 0x7b, 0xf4, 0x43,
-	0xba, 0xe9, 0x94, 0xf4, 0x0d, 0x4b, 0xa6, 0x8b, 0xfa, 0xbe, 0xa1, 0x6b,
-	0xd2, 0x67, 0x34, 0x01, 0xba, 0x21, 0xad, 0x93, 0xb7, 0x0c, 0x29, 0x83,
-	0x8e, 0xca, 0xc0, 0xa7, 0x32, 0x68, 0xaa, 0x02, 0x7c, 0x2b, 0x03, 0xdf,
-	0xca, 0x75, 0x33, 0x5a, 0xc5, 0x9e, 0x29, 0xb3, 0xd7, 0x41, 0x47, 0x1b,
-	0x75, 0xde, 0xbf, 0x5e, 0xb3, 0x41, 0x39, 0x78, 0x77, 0xef, 0xee, 0xff,
-	0x81, 0xbb, 0x1f, 0x94, 0xdb, 0xb0, 0x5b, 0xde, 0x29, 0x8d, 0x02, 0x93,
-	0x04, 0x18, 0x65, 0x83, 0x36, 0xe2, 0xb2, 0x59, 0x9a, 0x94, 0x2d, 0xc8,
-	0xa7, 0xed, 0xd5, 0x08, 0xf4, 0xe9, 0x90, 0xcc, 0xbf, 0x35, 0x22, 0xb7,
-	0x56, 0x95, 0xcc, 0x82, 0x7e, 0xf3, 0x6b, 0xf4, 0xbb, 0x83, 0x9e, 0xcb,
-	0x9d, 0x3a, 0x4e, 0x9f, 0xae, 0xba, 0xfe, 0xf7, 0xa9, 0x6a, 0x97, 0x4c,
-	0x57, 0x0d, 0x79, 0xbe, 0xda, 0x23, 0x2f, 0x56, 0x83, 0x72, 0x16, 0x76,
-	0xe0, 0xd7, 0xaa, 0x03, 0xf2, 0x52, 0x75, 0x50, 0xbe, 0x5e, 0x0b, 0xcb,
-	0x37, 0x6a, 0x96, 0x64, 0x6b, 0x51, 0xc9, 0xd4, 0x46, 0xe5, 0x85, 0x1a,
-	0xfd, 0xea, 0x98, 0x0f, 0xbf, 0xd4, 0x9e, 0xbf, 0x82, 0xeb, 0xea, 0xc0,
-	0xba, 0xa2, 0x6a, 0x4a, 0xc7, 0x29, 0x25, 0xeb, 0xfa, 0x3c, 0x44, 0x2e,
-	0x61, 0xac, 0xc5, 0xb7, 0x94, 0x54, 0xf4, 0xfc, 0xcd, 0xff, 0x33, 0x09,
-	0x68, 0xdb, 0xe8, 0x52, 0x79, 0x00, 0x6d, 0x20, 0xf7, 0x0a, 0x4d, 0xdf,
-	0x47, 0xd3, 0xe7, 0xdf, 0xb4, 0xbd, 0x7c, 0xda, 0x6f, 0x7d, 0x97, 0xb6,
-	0x97, 0x3e, 0x7b, 0xe2, 0x07, 0xed, 0x9c, 0x9b, 0xda, 0x6f, 0xb2, 0x1f,
-	0xdb, 0x68, 0xce, 0xbb, 0x98, 0x7d, 0xf2, 0xff, 0x59, 0xdc, 0x18, 0xd5,
-	0xc5, 0xda, 0x00, 0xff, 0xaf, 0x05, 0x6b, 0xf9, 0xf2, 0xdc, 0xf1, 0xe9,
-	0x52, 0x5a, 0x3d, 0x5f, 0xa2, 0x46, 0xe3, 0xc8, 0xe2, 0x5e, 0x4e, 0xdc,
-	0x73, 0xb2, 0x66, 0x07, 0xf4, 0x1a, 0x5c, 0x5f, 0x7d, 0x42, 0xe7, 0xc7,
-	0xa5, 0x4f, 0x91, 0xfe, 0x18, 0x7b, 0xeb, 0xf2, 0xe2, 0x09, 0xd0, 0x6d,
-	0x6d, 0x43, 0xae, 0x56, 0x5d, 0x9f, 0xd5, 0xbc, 0xa6, 0x97, 0x7b, 0xa0,
-	0x39, 0xc6, 0x1c, 0xdc, 0x67, 0xae, 0xec, 0xf6, 0x4d, 0xe1, 0xde, 0x60,
-	0x8f, 0x63, 0xbf, 0xbe, 0x1e, 0xce, 0xc5, 0xff, 0xe3, 0x41, 0xd9, 0x5b,
-	0x2f, 0x73, 0x8d, 0x2d, 0x4d, 0x8b, 0x6e, 0x5c, 0x37, 0x2a, 0xaf, 0xe2,
-	0xfc, 0x2a, 0x06, 0xd7, 0xdf, 0x21, 0x95, 0x28, 0x6d, 0x5b, 0xe2, 0xf7,
-	0x29, 0x29, 0x63, 0x9e, 0x4a, 0xb4, 0xe9, 0x0f, 0x73, 0x71, 0xb6, 0x62,
-	0xec, 0xcf, 0x3b, 0x53, 0x3e, 0x8e, 0x77, 0xd4, 0x45, 0xa1, 0x33, 0x9d,
-	0xe3, 0xfb, 0x22, 0xca, 0xf4, 0x8d, 0xcc, 0xe3, 0x19, 0xf2, 0xea, 0xde,
-	0xeb, 0xd7, 0xba, 0xfa, 0xe4, 0x7e, 0xbf, 0xd9, 0xb2, 0x99, 0x4b, 0xfa,
-	0x63, 0xca, 0xf7, 0xf3, 0xdf, 0xf7, 0x13, 0x73, 0x8f, 0x5b, 0xfc, 0x05,
-	0xe4, 0x33, 0x43, 0xfb, 0x14, 0xbc, 0x6f, 0x47, 0xe4, 0x65, 0x83, 0x79,
-	0xec, 0x09, 0x95, 0x2e, 0x5d, 0xf7, 0x72, 0x7c, 0x63, 0xea, 0x78, 0xe5,
-	0x7e, 0xbf, 0x9b, 0xf3, 0xce, 0xb1, 0x0f, 0xe6, 0xb9, 0x1f, 0xa4, 0x13,
-	0xe6, 0xbb, 0xb7, 0xef, 0xfd, 0x0f, 0x55, 0xa5, 0x00, 0xbc, 0xb3, 0x5a,
-	0x34, 0x3f, 0xe6, 0x6b, 0xff, 0x76, 0x76, 0x34, 0x3f, 0x37, 0x7d, 0x0c,
-	0x7f, 0xee, 0xa7, 0x6d, 0x4b, 0xdc, 0xb8, 0xea, 0xe6, 0x8e, 0x6a, 0x1b,
-	0x1a, 0x58, 0x81, 0x3a, 0xf2, 0x2a, 0xf8, 0x64, 0xaf, 0x2d, 0xff, 0xfe,
-	0x03, 0x9a, 0xb8, 0x8a, 0x6c, 0x8c, 0x67, 0x00, 0x00, 0x00 };
+	0xec, 0x5b, 0x7f, 0x70, 0x1c, 0xf5, 0x75, 0xff, 0x7c, 0xf7, 0xf6, 0xa4,
+	0x95, 0x74, 0xba, 0x5b, 0x49, 0x27, 0xf9, 0x14, 0x8c, 0xb5, 0x8b, 0x56,
+	0x27, 0x61, 0x19, 0x77, 0x4f, 0x3a, 0xd9, 0x4a, 0x66, 0x1b, 0x2e, 0xb6,
+	0x63, 0xe4, 0x81, 0x82, 0xb0, 0x09, 0x31, 0x53, 0x26, 0xa8, 0xb6, 0x63,
+	0xc4, 0x8f, 0x34, 0x26, 0x61, 0x06, 0x11, 0x68, 0xd8, 0x48, 0x36, 0xa6,
+	0xf6, 0x9e, 0xd6, 0x36, 0x12, 0xe0, 0x99, 0x74, 0x22, 0x64, 0x59, 0x36,
+	0xe4, 0xa4, 0x33, 0x90, 0x1f, 0x66, 0x5a, 0x6a, 0x81, 0xf9, 0x61, 0x88,
+	0x0d, 0x84, 0x42, 0x02, 0x33, 0x99, 0x89, 0xf9, 0x11, 0xc7, 0x66, 0x68,
+	0x50, 0x5a, 0x92, 0x8a, 0x89, 0xea, 0x6f, 0xdf, 0xbb, 0x93, 0xf8, 0x61,
+	0x3a, 0x4d, 0x3b, 0xd3, 0x3f, 0xf7, 0xcd, 0xdc, 0x68, 0xf7, 0xfb, 0x7d,
+	0xef, 0x7d, 0xdf, 0xef, 0xf7, 0xbe, 0x3b, 0xa3, 0x5b, 0x23, 0x28, 0xc7,
+	0x1c, 0x54, 0xd2, 0x2f, 0xbd, 0xa5, 0xef, 0x5b, 0x1d, 0x4b, 0xed, 0xa5,
+	0xfc, 0x1e, 0x0a, 0x43, 0xe5, 0xbf, 0x02, 0x01, 0x04, 0x10, 0x40, 0x00,
+	0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04,
+	0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40,
+	0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01,
+	0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10,
+	0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0xfc, 0x7f, 0x42, 0x08,
+	0xd0, 0xf9, 0x6f, 0xe5, 0xdc, 0x0f, 0x9a, 0xe2, 0x8c, 0x7c, 0x67, 0x85,
+	0x05, 0x2d, 0xe4, 0xc4, 0xef, 0xd8, 0x68, 0x01, 0x99, 0x5c, 0xab, 0xb1,
+	0x12, 0xff, 0x29, 0xdd, 0xb8, 0x0a, 0x5e, 0x3f, 0xdf, 0x99, 0xfd, 0xc1,
+	0x13, 0xcb, 0xcd, 0xe9, 0x91, 0x10, 0x34, 0xdd, 0x79, 0x39, 0xa5, 0x27,
+	0xa1, 0x2d, 0x24, 0x9a, 0xef, 0x37, 0x6f, 0xab, 0x46, 0x74, 0x9e, 0x17,
+	0x5c, 0xc5, 0x91, 0x72, 0xbf, 0x2d, 0xf1, 0xac, 0xed, 0x8a, 0xae, 0x34,
+	0xdc, 0x90, 0x73, 0x58, 0xdc, 0xe0, 0x9d, 0x95, 0x46, 0xb8, 0x78, 0xb2,
+	0x3a, 0xa1, 0x21, 0xbc, 0x1f, 0xba, 0xea, 0x28, 0x08, 0x5b, 0xe5, 0x28,
+	0x79, 0xb0, 0x02, 0xe1, 0x07, 0x13, 0x28, 0x9d, 0x38, 0x24, 0x7a, 0x46,
+	0x34, 0x9c, 0x0c, 0x1d, 0x16, 0x9b, 0x72, 0xe8, 0x09, 0x3b, 0x33, 0x57,
+	0x8c, 0x12, 0x5d, 0xa6, 0xf0, 0xff, 0x25, 0x53, 0x57, 0x8c, 0xe5, 0xa0,
+	0x87, 0x1c, 0x28, 0xaa, 0xf3, 0x34, 0x3d, 0x33, 0xde, 0xcc, 0x15, 0xfb,
+	0x72, 0xa7, 0xe5, 0x13, 0xcd, 0x71, 0x1c, 0xc9, 0xeb, 0x38, 0x94, 0xff,
+	0x25, 0xc9, 0x61, 0xba, 0x2e, 0x34, 0x57, 0x75, 0x5c, 0x6c, 0x4b, 0x87,
+	0x31, 0xbe, 0xeb, 0xac, 0x0c, 0x59, 0xa6, 0x01, 0xc5, 0xd2, 0x8f, 0x82,
+	0xf0, 0x7c, 0xc2, 0xf3, 0xc3, 0x18, 0x1d, 0x79, 0xb3, 0x1a, 0xe5, 0x09,
+	0x3c, 0xd1, 0xcc, 0xf4, 0x4c, 0xcb, 0x3c, 0x42, 0xb1, 0x79, 0xfa, 0x12,
+	0xa2, 0x7f, 0x26, 0x0d, 0x8c, 0xed, 0xea, 0x26, 0x52, 0x89, 0x01, 0xbb,
+	0x14, 0x1b, 0x74, 0xb8, 0x65, 0x0e, 0xf3, 0x9a, 0xe7, 0xe3, 0x0a, 0x63,
+	0x22, 0xaa, 0x17, 0xf9, 0x40, 0x68, 0x16, 0xdc, 0xd2, 0x73, 0xf6, 0x4f,
+	0xe7, 0xe6, 0xf7, 0xef, 0xa1, 0x73, 0x34, 0xda, 0xef, 0xc5, 0x4f, 0xf2,
+	0x9b, 0xf0, 0xe3, 0xfc, 0xb5, 0x78, 0x2c, 0xdf, 0x4d, 0xe7, 0xde, 0x4a,
+	0xe7, 0x6e, 0xc1, 0x3f, 0xe7, 0x6f, 0xc6, 0x4f, 0xf3, 0x3d, 0xf8, 0x51,
+	0x7e, 0x3d, 0x1e, 0xcd, 0x5f, 0x85, 0x47, 0xf2, 0x28, 0xc8, 0x70, 0x3a,
+	0xdd, 0x22, 0x7e, 0xee, 0x95, 0x41, 0xdd, 0xbd, 0x15, 0x53, 0xb9, 0x30,
+	0xc2, 0xbb, 0x25, 0x76, 0xd9, 0xe6, 0x03, 0x40, 0xb3, 0x1e, 0x86, 0xc0,
+	0x4a, 0xdb, 0x3c, 0x08, 0x7c, 0x01, 0x3d, 0x71, 0xf3, 0x10, 0x50, 0x27,
+	0x5e, 0x19, 0xaa, 0x13, 0x27, 0x86, 0x54, 0xf1, 0xa2, 0x27, 0x10, 0x73,
+	0x10, 0x79, 0x21, 0x2d, 0xe5, 0xa5, 0x6d, 0x52, 0xe6, 0x52, 0x56, 0xd7,
+	0x4b, 0xc2, 0xb4, 0x77, 0x88, 0x45, 0x30, 0x6a, 0xcd, 0xcc, 0x8d, 0x42,
+	0x73, 0xcb, 0x89, 0xff, 0x9a, 0x0e, 0xc0, 0xda, 0x6d, 0x90, 0x1f, 0x58,
+	0xc7, 0x6d, 0xf8, 0x7a, 0x21, 0x26, 0xba, 0x51, 0x63, 0xad, 0xc4, 0xb7,
+	0xbb, 0x6d, 0x8c, 0xe4, 0xa1, 0x55, 0x39, 0x1f, 0x20, 0x35, 0x28, 0x60,
+	0x93, 0xbf, 0x05, 0x3d, 0xdb, 0xb9, 0x27, 0x6b, 0x8a, 0xfe, 0x26, 0xd9,
+	0x7d, 0x92, 0xdd, 0x27, 0xd9, 0x7d, 0xd2, 0xcb, 0x27, 0xbd, 0x7c, 0xd2,
+	0xc1, 0x27, 0xdd, 0x7c, 0xd2, 0xc3, 0x27, 0x3d, 0x7c, 0xd2, 0xd1, 0x67,
+	0x5f, 0xf5, 0x91, 0x0d, 0x22, 0xf8, 0xa5, 0xb7, 0x10, 0x1f, 0x78, 0xe7,
+	0xe3, 0x83, 0xb5, 0x3a, 0x5e, 0x27, 0x19, 0x15, 0xeb, 0xff, 0xca, 0xe3,
+	0xa7, 0x11, 0xf2, 0x91, 0xf1, 0xbf, 0x3f, 0xdb, 0x24, 0x8d, 0xe6, 0x69,
+	0x97, 0xe0, 0x94, 0xf7, 0xb6, 0x2c, 0x59, 0xc0, 0xe7, 0x7e, 0x11, 0x72,
+	0x08, 0x58, 0x34, 0x2c, 0xe5, 0x87, 0xed, 0xbf, 0x96, 0x6f, 0x7c, 0x95,
+	0xf9, 0x39, 0x78, 0x6b, 0x48, 0x41, 0x88, 0xd6, 0x2e, 0xb1, 0xdf, 0x90,
+	0xd7, 0xc7, 0x19, 0xef, 0x8f, 0x11, 0x94, 0xb3, 0xad, 0xa0, 0xd5, 0x38,
+	0xea, 0x1d, 0xdf, 0x4e, 0xc2, 0x8d, 0x3a, 0xaa, 0x78, 0x35, 0x6b, 0x60,
+	0x81, 0x93, 0x41, 0xa5, 0x63, 0xed, 0xba, 0x5f, 0x69, 0xed, 0xab, 0x46,
+	0xe6, 0xc2, 0x18, 0x6c, 0xec, 0xcf, 0xab, 0xe2, 0x78, 0xb6, 0x12, 0xd5,
+	0xbb, 0xad, 0xf5, 0x59, 0xa1, 0xa0, 0xa7, 0x36, 0x83, 0xb1, 0xb4, 0x69,
+	0x8c, 0xc0, 0xc0, 0xfa, 0x36, 0x05, 0x58, 0xe0, 0xe2, 0xee, 0xb4, 0x69,
+	0xbb, 0xe8, 0xc7, 0x54, 0xdc, 0xc6, 0x78, 0x5e, 0xa3, 0xfc, 0x70, 0x71,
+	0x7d, 0x5a, 0x83, 0xdc, 0x95, 0xc1, 0xa9, 0xf6, 0x52, 0x4c, 0x75, 0x73,
+	0x9c, 0xa8, 0x74, 0xf6, 0x76, 0x28, 0xd5, 0xd5, 0xe4, 0x9b, 0xb4, 0x08,
+	0x57, 0x17, 0x52, 0x94, 0xd6, 0x21, 0xfe, 0x35, 0xcd, 0x32, 0x7c, 0x4e,
+	0x1c, 0x1f, 0x8e, 0xa2, 0x7c, 0x58, 0xc3, 0x0f, 0x77, 0xab, 0x58, 0x43,
+	0x3e, 0xbe, 0x3f, 0xa5, 0x1a, 0x37, 0x0a, 0x07, 0x63, 0x79, 0x15, 0xf1,
+	0x6c, 0x3d, 0x8c, 0x2a, 0x0d, 0x8b, 0xb2, 0x2e, 0xde, 0x26, 0xde, 0x7d,
+	0xc4, 0x3b, 0xd6, 0xae, 0xe3, 0x64, 0x6d, 0xd1, 0xbf, 0xb7, 0x78, 0x8d,
+	0xee, 0x6e, 0xa5, 0x04, 0x28, 0x81, 0xab, 0x39, 0x69, 0xdc, 0xe6, 0x35,
+	0x92, 0x1e, 0xd7, 0x60, 0x45, 0x89, 0x86, 0x0d, 0x83, 0xbc, 0xb6, 0x0a,
+	0x98, 0x58, 0x50, 0x89, 0x72, 0xb6, 0x01, 0xe7, 0xf5, 0x4a, 0x7a, 0xe6,
+	0x78, 0xb8, 0x37, 0xce, 0xf6, 0x77, 0x95, 0xff, 0x90, 0x99, 0x38, 0xe3,
+	0x15, 0x73, 0xe5, 0x68, 0x3a, 0x8d, 0xdb, 0xbd, 0xc6, 0xcc, 0x5e, 0xa5,
+	0x06, 0x08, 0x9b, 0x86, 0xa1, 0x40, 0x8b, 0x3b, 0x48, 0x0d, 0x51, 0xdc,
+	0xdc, 0x5b, 0x88, 0x1b, 0xa4, 0xda, 0x73, 0x9c, 0x9f, 0x9a, 0xab, 0x13,
+	0x7e, 0xc3, 0xb2, 0x26, 0xfc, 0xf1, 0x5e, 0xc6, 0x53, 0xf1, 0x3c, 0x3d,
+	0x9f, 0xd9, 0xf7, 0xe6, 0x5c, 0x0d, 0xf9, 0x87, 0x82, 0x7f, 0x0d, 0x65,
+	0xfe, 0x6c, 0x1b, 0xd7, 0x7b, 0x8d, 0x33, 0xdb, 0x15, 0xf2, 0xe1, 0x79,
+	0x11, 0x94, 0x51, 0x1d, 0x0a, 0x13, 0xaf, 0xfd, 0xde, 0x2c, 0xd6, 0xb6,
+	0x99, 0x87, 0xf9, 0xff, 0xce, 0x46, 0xad, 0x22, 0xff, 0x0b, 0x72, 0x36,
+	0x1e, 0xca, 0xdb, 0xd8, 0x48, 0x72, 0xdc, 0x8a, 0x37, 0x81, 0xfa, 0xc5,
+	0xc6, 0x69, 0xe5, 0x2d, 0xe9, 0x5e, 0xc5, 0xfc, 0x16, 0xe2, 0x74, 0x75,
+	0x63, 0xcf, 0x69, 0xc5, 0x1c, 0xb9, 0x47, 0x61, 0x5b, 0x29, 0xf8, 0xab,
+	0xb6, 0x34, 0x46, 0xaa, 0x74, 0x5c, 0xd3, 0xa6, 0xb9, 0x8b, 0x48, 0xa6,
+	0x97, 0x97, 0x6b, 0xa8, 0xdb, 0x93, 0xc1, 0x6b, 0x6d, 0xaf, 0x62, 0x64,
+	0x2d, 0xdb, 0x81, 0xe9, 0x58, 0xe6, 0x04, 0xaa, 0xad, 0x32, 0x54, 0x8f,
+	0x86, 0x11, 0xdb, 0x73, 0x56, 0x26, 0x2c, 0x5e, 0xb7, 0xb6, 0xcc, 0x08,
+	0x96, 0x39, 0x8c, 0xe8, 0xe8, 0xe7, 0xa1, 0x5a, 0x66, 0x0b, 0xf0, 0x8d,
+	0x38, 0xe3, 0x96, 0x58, 0xf3, 0xb2, 0x0b, 0x5c, 0xfa, 0x05, 0x81, 0x1b,
+	0x53, 0x4f, 0xca, 0x4c, 0x2d, 0xd3, 0x3c, 0x46, 0xeb, 0x2c, 0x43, 0xd9,
+	0x4c, 0x06, 0x75, 0x44, 0x33, 0x8f, 0x17, 0x41, 0xef, 0x9e, 0xa2, 0x0c,
+	0x6f, 0x2c, 0xc7, 0x63, 0x1a, 0x3a, 0xd1, 0xec, 0x7f, 0x0f, 0xaf, 0x2d,
+	0x63, 0x9a, 0xef, 0x4d, 0xef, 0x6f, 0xdb, 0x49, 0x36, 0xe1, 0x7a, 0x7a,
+	0xae, 0x5f, 0x78, 0xbf, 0xbb, 0x96, 0xec, 0xd5, 0x02, 0x91, 0xa0, 0x35,
+	0x8e, 0xe1, 0xdd, 0xd2, 0x58, 0x57, 0xf4, 0x4b, 0x29, 0xf1, 0x3b, 0x93,
+	0xee, 0x44, 0x63, 0x56, 0x85, 0xf4, 0x1a, 0xed, 0x5f, 0x87, 0x76, 0xc8,
+	0xa9, 0x6b, 0x79, 0xaf, 0x51, 0x3f, 0x1a, 0x12, 0x58, 0xa1, 0x9a, 0xd3,
+	0x3d, 0x48, 0xe0, 0x20, 0xd5, 0x9a, 0x7a, 0x47, 0xa7, 0xda, 0x13, 0xa7,
+	0x1a, 0x64, 0x88, 0xe6, 0xfb, 0x6d, 0x2c, 0xce, 0x5e, 0x8b, 0x8b, 0x87,
+	0x1d, 0x1c, 0xf6, 0x6d, 0xfc, 0xd0, 0x97, 0xf2, 0x94, 0x2d, 0xe5, 0xfb,
+	0xed, 0x66, 0xef, 0x31, 0x6a, 0x0b, 0x4b, 0x97, 0xb7, 0xf6, 0xc4, 0x42,
+	0x2a, 0xd9, 0xa7, 0xc9, 0xb8, 0x59, 0x98, 0x89, 0x49, 0x61, 0x53, 0xcc,
+	0x75, 0x91, 0xed, 0x0d, 0xec, 0xcb, 0xb7, 0xe0, 0xe1, 0xbc, 0x45, 0xbf,
+	0x25, 0x14, 0x2b, 0x69, 0xaa, 0x6b, 0xac, 0xab, 0x8e, 0xb1, 0x66, 0xca,
+	0x0d, 0x5f, 0xc1, 0x41, 0x9b, 0x72, 0xa0, 0x8a, 0x70, 0xfd, 0xb3, 0xe4,
+	0x3f, 0x0d, 0x2d, 0xbb, 0x33, 0x28, 0x4b, 0xd5, 0xc0, 0xb8, 0xd2, 0xc2,
+	0x98, 0xaf, 0xb9, 0x61, 0x8a, 0xfb, 0x51, 0xef, 0x61, 0x7c, 0x4d, 0x8f,
+	0xa3, 0x9c, 0xec, 0xb7, 0xbe, 0x2d, 0x02, 0xac, 0xe3, 0xbd, 0x08, 0xea,
+	0xad, 0xe7, 0x50, 0x5f, 0x5d, 0x89, 0x92, 0xc5, 0x4f, 0x62, 0x4a, 0x8f,
+	0xa2, 0x94, 0x7a, 0x47, 0x03, 0xe1, 0x34, 0x90, 0xaf, 0x6a, 0x2d, 0x8b,
+	0x78, 0x0a, 0x58, 0x4d, 0x84, 0x4b, 0x39, 0x95, 0x20, 0xdd, 0xc3, 0xcb,
+	0xe3, 0xc8, 0x93, 0xfc, 0x93, 0x9e, 0x94, 0x91, 0xb4, 0xd9, 0xeb, 0x53,
+	0x7e, 0x4e, 0xe4, 0x3a, 0x31, 0x99, 0xbf, 0x9c, 0xea, 0xba, 0x8d, 0x7d,
+	0x9e, 0x83, 0x51, 0x5f, 0x5d, 0xef, 0xc1, 0xec, 0xbe, 0x09, 0x69, 0x3c,
+	0x4c, 0xf1, 0x33, 0xee, 0x9b, 0xc6, 0x53, 0x21, 0x0d, 0xc7, 0xec, 0x0a,
+	0x92, 0x93, 0x72, 0x97, 0x74, 0x7a, 0xdc, 0xbb, 0x0f, 0x56, 0x0d, 0xdb,
+	0x9f, 0xfd, 0x94, 0xc6, 0x01, 0xbf, 0x10, 0xdf, 0x97, 0x6a, 0x70, 0x61,
+	0x77, 0xb0, 0x6f, 0xdc, 0xe9, 0x70, 0x5b, 0xb1, 0x9e, 0x76, 0x77, 0xd8,
+	0x28, 0x1d, 0xec, 0x24, 0xbe, 0x8d, 0xf6, 0x5b, 0xb8, 0x09, 0x53, 0x09,
+	0x17, 0x4b, 0x29, 0xfe, 0x55, 0xe7, 0x81, 0xd4, 0x56, 0xcf, 0x95, 0x31,
+	0xcb, 0xea, 0x7d, 0x49, 0xdc, 0x85, 0xe3, 0x29, 0xae, 0xef, 0x2a, 0xe5,
+	0xbe, 0x8e, 0x9d, 0xf6, 0x2e, 0x9c, 0xc8, 0x7d, 0x09, 0x3d, 0x55, 0x66,
+	0xcb, 0x80, 0xb8, 0x09, 0x87, 0x77, 0x5d, 0x0c, 0x7c, 0x95, 0xf3, 0x84,
+	0x74, 0xb3, 0x6e, 0xc2, 0x91, 0x91, 0xef, 0xe0, 0x99, 0xa1, 0x72, 0x3c,
+	0x6e, 0x55, 0xa3, 0x7e, 0xbc, 0x78, 0xce, 0x97, 0x3b, 0x34, 0x8c, 0x52,
+	0x4e, 0x5f, 0x62, 0xab, 0x38, 0x19, 0xe7, 0x1a, 0x42, 0xb1, 0xd6, 0xf6,
+	0x2d, 0xaa, 0x37, 0x85, 0x16, 0x8c, 0x4d, 0x69, 0x03, 0x9e, 0x97, 0xa1,
+	0x3a, 0x58, 0x86, 0x3d, 0x55, 0x10, 0x1b, 0xa9, 0x97, 0xfd, 0xad, 0xd7,
+	0xd8, 0x3b, 0xa8, 0x54, 0x63, 0xa4, 0x3e, 0x43, 0xbe, 0x10, 0xa8, 0xb3,
+	0x0c, 0x6c, 0xcb, 0x51, 0x25, 0xcd, 0xa9, 0xf8, 0x6e, 0xae, 0x1d, 0x23,
+	0x75, 0x4c, 0x7b, 0x11, 0xa6, 0x0a, 0x7f, 0xc3, 0x38, 0x59, 0x6d, 0x26,
+	0x40, 0x36, 0x1b, 0xf3, 0x55, 0x0c, 0xdb, 0xc3, 0x67, 0x47, 0xd6, 0x9a,
+	0x7a, 0x0f, 0xe5, 0x5b, 0xa8, 0x10, 0xb7, 0xfc, 0x0c, 0x7c, 0xd3, 0xfb,
+	0xbd, 0xfc, 0xa0, 0x70, 0xa6, 0xca, 0xf9, 0x3f, 0xf5, 0x46, 0xe8, 0x8c,
+	0x14, 0xa5, 0xcc, 0xff, 0xf6, 0x68, 0xf1, 0x7f, 0x46, 0x7f, 0xcc, 0xb8,
+	0x19, 0x80, 0xe3, 0x60, 0xc1, 0x27, 0x62, 0x7e, 0xbe, 0x8e, 0x9f, 0x1b,
+	0xd3, 0xc5, 0xfa, 0xa0, 0x2f, 0x63, 0xf9, 0xe6, 0xf3, 0xaf, 0x1a, 0x75,
+	0xe3, 0x4d, 0x28, 0xdb, 0xc3, 0xef, 0xbc, 0x2e, 0x70, 0x41, 0x07, 0xe7,
+	0x5e, 0x13, 0x94, 0xd1, 0x4d, 0xd1, 0x62, 0x7d, 0x9e, 0xaf, 0x1b, 0x7f,
+	0x37, 0x77, 0x6e, 0x61, 0x16, 0xa0, 0xf7, 0x62, 0x7d, 0xfd, 0x6e, 0x9a,
+	0x9f, 0x99, 0xa6, 0x0c, 0xaf, 0xed, 0x33, 0xed, 0x11, 0x65, 0x39, 0xc9,
+	0xc2, 0xf9, 0xca, 0x79, 0x7b, 0xc7, 0x1c, 0x0d, 0xe5, 0x82, 0x7f, 0x50,
+	0xe2, 0x1a, 0xe6, 0x37, 0x4f, 0xdf, 0x84, 0x92, 0x8f, 0xce, 0x55, 0xf1,
+	0x54, 0xfa, 0xdc, 0x73, 0xaf, 0x96, 0xe5, 0x6b, 0xab, 0x29, 0xfe, 0x6a,
+	0xa1, 0x2e, 0xa6, 0x01, 0x40, 0xaf, 0x43, 0x05, 0xe5, 0x73, 0xc8, 0xba,
+	0x52, 0x86, 0xae, 0xe6, 0xf8, 0xd5, 0xdc, 0x88, 0x73, 0x1e, 0x06, 0x77,
+	0x3f, 0x41, 0xbe, 0x8f, 0x72, 0x9c, 0x92, 0xff, 0xcf, 0x43, 0xf6, 0xc1,
+	0x86, 0x28, 0xeb, 0xbb, 0xbe, 0x0d, 0x6e, 0x03, 0xd5, 0xf2, 0xdf, 0xdc,
+	0xdf, 0x2b, 0x47, 0xba, 0x75, 0x3c, 0x9b, 0x5e, 0x49, 0xeb, 0x1c, 0x67,
+	0x36, 0x7e, 0xe4, 0x69, 0xb8, 0x6d, 0x30, 0x41, 0x72, 0x72, 0x0d, 0x2d,
+	0x9b, 0x39, 0xa9, 0xd8, 0x78, 0x8c, 0x62, 0xf4, 0x11, 0x9f, 0x6d, 0xa5,
+	0xe2, 0x82, 0xb6, 0x95, 0xb2, 0xb4, 0x8e, 0xe3, 0x7e, 0x31, 0xd1, 0xe8,
+	0xc4, 0x3b, 0x0a, 0xdd, 0xfa, 0x4b, 0x79, 0x68, 0x2d, 0x3f, 0x5f, 0x48,
+	0x6b, 0x75, 0xf4, 0xf7, 0x2f, 0x64, 0xc5, 0x67, 0xe4, 0xd0, 0xff, 0x3b,
+	0x39, 0x28, 0x1f, 0x4c, 0x7b, 0x33, 0x5a, 0x69, 0x4e, 0x52, 0x91, 0xa1,
+	0xae, 0x39, 0x4e, 0xb1, 0xb1, 0x9d, 0x7a, 0xf4, 0x6f, 0x68, 0x16, 0xdc,
+	0x56, 0x98, 0xb7, 0x0a, 0xe3, 0x5b, 0x61, 0x9e, 0xdb, 0x50, 0x9c, 0xcb,
+	0x34, 0xd5, 0xe2, 0x59, 0x6d, 0x7e, 0x8f, 0x6d, 0xdd, 0x85, 0x0d, 0x43,
+	0x52, 0x6e, 0xb5, 0xe3, 0xc4, 0xa3, 0x1a, 0x5b, 0xad, 0x2e, 0xf4, 0x0e,
+	0x81, 0xf2, 0x5a, 0xca, 0xd2, 0xd4, 0xe2, 0xc4, 0x3b, 0x54, 0xe4, 0x7b,
+	0x74, 0x57, 0x8c, 0xa7, 0x3f, 0x47, 0x76, 0xaa, 0xc0, 0xcf, 0x68, 0xde,
+	0xdb, 0xe1, 0x23, 0xb3, 0x26, 0x55, 0x49, 0xfd, 0x4a, 0x87, 0xef, 0x1b,
+	0x62, 0x72, 0x48, 0x47, 0xd6, 0x3f, 0x2b, 0x8f, 0x37, 0x09, 0xec, 0xef,
+	0x88, 0xe3, 0xf8, 0x18, 0xf3, 0xd7, 0xb1, 0x2d, 0xcf, 0xb3, 0x65, 0x88,
+	0xec, 0xe1, 0x8a, 0x6b, 0xd2, 0xbc, 0x56, 0x01, 0x6b, 0x1f, 0xd7, 0x63,
+	0xcb, 0x9e, 0x11, 0x45, 0x9c, 0xbb, 0xf3, 0xaf, 0xd3, 0x9c, 0x65, 0x50,
+	0x2d, 0x5b, 0x48, 0xf3, 0x55, 0x82, 0x66, 0xa9, 0x38, 0xcd, 0x52, 0xd6,
+	0xdc, 0x7c, 0x68, 0x52, 0x36, 0x4a, 0xf9, 0x18, 0xd5, 0xb2, 0x57, 0xe8,
+	0xf7, 0x01, 0xd5, 0xd3, 0x2a, 0xd2, 0xe5, 0x82, 0x41, 0xd6, 0xc5, 0x15,
+	0x36, 0xd5, 0xdb, 0x8c, 0x52, 0x1e, 0xe3, 0x3e, 0x14, 0x9a, 0x24, 0x5e,
+	0x34, 0x73, 0x6c, 0xf3, 0x81, 0x01, 0x1f, 0xee, 0xd3, 0x94, 0xfb, 0x35,
+	0xe3, 0x51, 0x54, 0x8f, 0xeb, 0x08, 0x8f, 0xb7, 0xd0, 0xbe, 0x86, 0x38,
+	0xbd, 0xbb, 0x34, 0x13, 0xc6, 0x9c, 0x3a, 0xb1, 0xe4, 0xbe, 0x59, 0xb9,
+	0x33, 0xa5, 0xe2, 0xc6, 0x26, 0xb3, 0xeb, 0x4a, 0x81, 0x4c, 0x4b, 0x96,
+	0xf5, 0x2d, 0xa5, 0xdc, 0x94, 0x47, 0xe2, 0x96, 0x94, 0x51, 0x47, 0xde,
+	0x75, 0xa2, 0xc3, 0xb2, 0x4f, 0x80, 0x65, 0x64, 0x1a, 0x5e, 0x77, 0xc5,
+	0xef, 0x3b, 0xac, 0x07, 0x5e, 0x45, 0x12, 0xed, 0xe3, 0xaa, 0xf8, 0xb7,
+	0xec, 0x12, 0xb4, 0x4d, 0x42, 0x2f, 0x71, 0x0e, 0x89, 0x93, 0x0f, 0x1e,
+	0x16, 0xa7, 0x26, 0x48, 0x6e, 0x9f, 0x74, 0xf1, 0x49, 0x17, 0x9f, 0x74,
+	0xf1, 0x49, 0x97, 0xc2, 0x5c, 0xc9, 0xba, 0xb6, 0xd0, 0x3c, 0xf3, 0x7a,
+	0x61, 0xf6, 0xe5, 0x59, 0xb1, 0xca, 0x31, 0x33, 0x2e, 0x58, 0x6f, 0xd6,
+	0x53, 0xca, 0x57, 0xed, 0xa2, 0x3e, 0x2e, 0x95, 0x5b, 0x6d, 0x72, 0xde,
+	0x16, 0x52, 0xfe, 0xbb, 0xcd, 0xb6, 0x60, 0x1d, 0xa5, 0x7c, 0xd4, 0x26,
+	0x9b, 0x12, 0xaf, 0x01, 0x5f, 0x1e, 0x29, 0xb1, 0x2c, 0x63, 0x1c, 0x11,
+	0xd2, 0x2f, 0x4a, 0x7a, 0x69, 0xa4, 0x6b, 0x12, 0x2a, 0xe9, 0x1a, 0x1a,
+	0x87, 0xae, 0x90, 0x3c, 0xc6, 0x28, 0xd9, 0x69, 0xf2, 0xcf, 0xc9, 0xc3,
+	0xfe, 0x71, 0xc5, 0x97, 0x69, 0x3e, 0x51, 0xc9, 0xae, 0x03, 0x14, 0x23,
+	0x3d, 0x2a, 0x8c, 0x52, 0x4b, 0xa1, 0x9e, 0xa8, 0xe1, 0xc0, 0x58, 0x05,
+	0xc6, 0x47, 0x74, 0x8c, 0x8c, 0x41, 0x0f, 0x13, 0x4f, 0x77, 0xe4, 0xb0,
+	0xf8, 0x64, 0x5c, 0x95, 0x3a, 0x5b, 0xf0, 0x0e, 0xd5, 0xa9, 0x41, 0xaf,
+	0x5a, 0x9c, 0xda, 0xa5, 0x61, 0xab, 0xcf, 0xb9, 0x29, 0x71, 0xd4, 0xee,
+	0x4f, 0x10, 0x8a, 0xe8, 0xb7, 0xd7, 0x50, 0x4c, 0x85, 0xb0, 0xd9, 0x42,
+	0x66, 0x9b, 0xdd, 0x05, 0x62, 0x65, 0xec, 0xa5, 0xfa, 0xd7, 0x67, 0xb9,
+	0x7d, 0x34, 0xc6, 0xf4, 0x26, 0x60, 0xae, 0xff, 0xad, 0x30, 0x7b, 0x0e,
+	0x90, 0xfd, 0x37, 0x67, 0x91, 0xd9, 0x99, 0xad, 0x13, 0xef, 0x0e, 0xcd,
+	0xca, 0x35, 0x29, 0x33, 0xd3, 0x4c, 0x6b, 0x95, 0x59, 0x25, 0x59, 0x82,
+	0xfe, 0x8d, 0x84, 0xdb, 0xa2, 0x62, 0x36, 0xb4, 0x3d, 0xd5, 0x5f, 0x45,
+	0x13, 0x90, 0x16, 0xa1, 0x1a, 0xec, 0x35, 0x99, 0x89, 0x1c, 0xad, 0xad,
+	0xa7, 0x7b, 0xcb, 0xf3, 0xb6, 0x79, 0xec, 0x3d, 0x4c, 0x63, 0x83, 0x37,
+	0xad, 0x36, 0xfb, 0x66, 0x5f, 0x24, 0xe4, 0x76, 0x97, 0x41, 0x59, 0x5d,
+	0x81, 0x69, 0xed, 0x4c, 0xd6, 0xb4, 0x2f, 0x13, 0x6e, 0x8b, 0x86, 0xfe,
+	0x46, 0x7a, 0x8f, 0x1c, 0xf3, 0x8a, 0x74, 0x7b, 0xed, 0xfe, 0x27, 0x2b,
+	0x90, 0xec, 0xbb, 0x84, 0x7a, 0xc9, 0x92, 0x90, 0xc4, 0xf5, 0xa9, 0x69,
+	0x7d, 0xb3, 0x37, 0x1b, 0x0a, 0xb7, 0x27, 0xf5, 0x33, 0xc2, 0x4d, 0x94,
+	0x62, 0x3a, 0x7e, 0x45, 0xd6, 0x34, 0x72, 0x48, 0x1e, 0xeb, 0xc2, 0x74,
+	0x62, 0x87, 0x67, 0x4e, 0xdd, 0x8c, 0xe4, 0xfa, 0x64, 0x68, 0x7a, 0x61,
+	0x99, 0x9f, 0xcc, 0x7c, 0x53, 0x24, 0x3b, 0xcb, 0x69, 0x36, 0x1f, 0xa9,
+	0x4d, 0x66, 0xce, 0x14, 0x72, 0x8c, 0xe7, 0x1c, 0x95, 0xe6, 0x9c, 0x2d,
+	0xb8, 0x9d, 0x6c, 0xd2, 0x49, 0x76, 0x9f, 0x58, 0x52, 0x4a, 0xf3, 0x4a,
+	0xa3, 0x1d, 0x0d, 0xb9, 0x9d, 0x61, 0x98, 0xfa, 0x7b, 0x54, 0x8b, 0x27,
+	0xad, 0x19, 0x7b, 0x75, 0x8e, 0xe7, 0x1f, 0x35, 0xb5, 0x94, 0xf2, 0xf5,
+	0x9e, 0xbc, 0xa0, 0x79, 0x91, 0x6d, 0x6a, 0xea, 0x23, 0x74, 0x77, 0x33,
+	0x6a, 0xd8, 0x86, 0x2a, 0xbe, 0x6e, 0xb9, 0x06, 0xe9, 0x6d, 0x33, 0xdd,
+	0x73, 0x30, 0x13, 0xdb, 0xa9, 0x8f, 0x6f, 0xf6, 0x90, 0xb9, 0xd4, 0x7b,
+	0x34, 0x46, 0xf5, 0xb9, 0x17, 0x50, 0x2e, 0xaf, 0x84, 0xdb, 0x57, 0x86,
+	0xfe, 0x75, 0x95, 0x30, 0xed, 0xf7, 0xc4, 0x6c, 0xe8, 0xd2, 0x54, 0xff,
+	0x85, 0x95, 0x98, 0x36, 0x5e, 0xf7, 0x4c, 0xea, 0xf3, 0x12, 0xa3, 0xa9,
+	0xd9, 0xd0, 0x01, 0x7b, 0xda, 0xf2, 0x49, 0xe7, 0xf7, 0xe0, 0x1e, 0x53,
+	0x30, 0xdd, 0xb2, 0xd9, 0x33, 0xbb, 0x96, 0x84, 0x92, 0xdd, 0x09, 0x31,
+	0xbd, 0xe4, 0xa2, 0x6c, 0x32, 0x73, 0x85, 0x48, 0xae, 0x2f, 0x11, 0xbf,
+	0x22, 0x9e, 0xc9, 0xcc, 0x37, 0x04, 0xe7, 0xcf, 0xc9, 0xb9, 0xfb, 0x15,
+	0x32, 0xa3, 0x76, 0x82, 0x62, 0x8f, 0xe3, 0x55, 0x27, 0x3f, 0xf2, 0x3d,
+	0xcb, 0x80, 0xea, 0x58, 0x89, 0x31, 0xba, 0x37, 0xf6, 0x50, 0x1e, 0x1d,
+	0xb4, 0x39, 0xe7, 0xe4, 0x91, 0x52, 0xcb, 0x6a, 0x39, 0x40, 0xb7, 0xd3,
+	0xa3, 0x94, 0xe3, 0x94, 0xf3, 0xc6, 0x24, 0xf5, 0xe2, 0xa9, 0x5a, 0x15,
+	0x55, 0xce, 0x11, 0xca, 0x75, 0x42, 0x2a, 0xb7, 0xf4, 0x3e, 0x30, 0xfe,
+	0x16, 0xa0, 0xd6, 0x00, 0xcd, 0xe6, 0x84, 0x33, 0x23, 0xa7, 0xa8, 0x7e,
+	0x0c, 0xf8, 0x8c, 0x67, 0xf5, 0x3d, 0x82, 0x3f, 0xc8, 0x93, 0x55, 0x8c,
+	0x9f, 0xc1, 0x86, 0x34, 0xc4, 0xe3, 0x76, 0x0c, 0x46, 0x8d, 0x8e, 0x7e,
+	0xea, 0xe7, 0x8a, 0x63, 0xcd, 0x8c, 0x72, 0x7f, 0xab, 0x81, 0x5b, 0x41,
+	0xf3, 0x46, 0x51, 0x86, 0xd3, 0x2c, 0x03, 0xc1, 0x22, 0x71, 0xe3, 0xf0,
+	0x42, 0x71, 0x03, 0xdf, 0x01, 0x52, 0x58, 0x55, 0x86, 0x26, 0xfb, 0x34,
+	0xad, 0x72, 0xce, 0x46, 0x9d, 0x88, 0x38, 0x31, 0x0c, 0x3d, 0x67, 0x53,
+	0xe7, 0xaf, 0x92, 0xf2, 0x60, 0xca, 0x40, 0xde, 0x2e, 0xa1, 0x99, 0x3a,
+	0x8c, 0x2a, 0x0b, 0x7a, 0xc2, 0xb1, 0xee, 0x39, 0x8c, 0xaf, 0xc0, 0xa8,
+	0x43, 0x54, 0xa5, 0x7e, 0x4c, 0x6b, 0x62, 0xdc, 0x2e, 0xa3, 0x39, 0x5f,
+	0x20, 0xe1, 0x24, 0xb0, 0xdd, 0xe7, 0x7a, 0x60, 0xf5, 0x1d, 0xa6, 0x1a,
+	0x50, 0xac, 0x79, 0x3f, 0xa0, 0xb9, 0x47, 0x34, 0x54, 0x3a, 0xbc, 0xcf,
+	0xeb, 0x97, 0xf3, 0x7c, 0x5e, 0x98, 0xc5, 0xb6, 0xd3, 0xbe, 0xe4, 0xde,
+	0x5e, 0x83, 0x18, 0xc9, 0x9b, 0x18, 0xa5, 0xfb, 0x02, 0xdb, 0x28, 0xe2,
+	0x90, 0xe6, 0x75, 0xd0, 0xcb, 0x1c, 0xcb, 0x7d, 0x08, 0x5d, 0x40, 0x35,
+	0xcf, 0x11, 0xd0, 0x4a, 0x1c, 0x1b, 0xcf, 0x7a, 0xdf, 0xa7, 0xb3, 0x90,
+	0x79, 0xd7, 0x86, 0x46, 0xfc, 0x90, 0xa0, 0xbc, 0x8c, 0xb5, 0x53, 0x2c,
+	0x50, 0xff, 0x3f, 0x60, 0x23, 0xd6, 0xe0, 0x58, 0xc7, 0x8e, 0x50, 0x2c,
+	0x18, 0x0b, 0xa0, 0x28, 0xa9, 0x57, 0xc0, 0xf3, 0xbb, 0xea, 0xf0, 0xde,
+	0x04, 0x4e, 0xea, 0x88, 0x95, 0x38, 0x56, 0xd7, 0x38, 0x05, 0x82, 0xee,
+	0x3c, 0x04, 0xbb, 0xaa, 0x90, 0x93, 0xc4, 0xa7, 0x93, 0xf8, 0x80, 0xeb,
+	0xa0, 0x16, 0xa5, 0xe7, 0x17, 0x9b, 0xa4, 0x8c, 0x35, 0x5b, 0xbd, 0x79,
+	0x98, 0x3d, 0x93, 0x42, 0xc5, 0xce, 0xdd, 0x5c, 0xf3, 0xa6, 0x4c, 0x6a,
+	0x9f, 0xd4, 0xb7, 0xa3, 0xa2, 0xe4, 0x3e, 0x05, 0xcd, 0xcb, 0x54, 0xbc,
+	0x48, 0x35, 0xef, 0xd9, 0x14, 0xdf, 0xef, 0x5b, 0x63, 0xc5, 0xb9, 0x9e,
+	0x7c, 0xff, 0x51, 0xbd, 0x98, 0xbf, 0x93, 0x19, 0x54, 0x33, 0xac, 0xae,
+	0x87, 0xb1, 0x4b, 0x1a, 0x55, 0xec, 0x43, 0x9a, 0x85, 0x68, 0xd6, 0xac,
+	0xa4, 0x5a, 0x99, 0xeb, 0xb0, 0x5a, 0x28, 0x9c, 0xdd, 0x8d, 0x1d, 0x0d,
+	0xe4, 0x6f, 0x8e, 0x03, 0x59, 0xa9, 0x14, 0xfc, 0x24, 0xe5, 0x75, 0xe9,
+	0xd6, 0x63, 0x6f, 0x87, 0x0e, 0xd2, 0x9c, 0xcb, 0x36, 0xbe, 0x9c, 0xf6,
+	0xd9, 0xfe, 0x51, 0x91, 0xba, 0xdf, 0xa5, 0xde, 0xc0, 0x67, 0x4a, 0x99,
+	0x6c, 0xa3, 0x83, 0xca, 0x43, 0x34, 0x23, 0x22, 0xf3, 0xba, 0x07, 0x11,
+	0x6b, 0xdf, 0x54, 0xb0, 0xc3, 0xe3, 0x76, 0x2d, 0xc5, 0x01, 0x62, 0x9a,
+	0x63, 0xe9, 0x74, 0x71, 0x56, 0x1a, 0x9c, 0x2a, 0x5c, 0x47, 0xd2, 0x64,
+	0x7d, 0xce, 0xb7, 0x4e, 0xec, 0xf7, 0xf8, 0xfb, 0x47, 0x27, 0x36, 0x12,
+	0x8f, 0x49, 0xcb, 0x22, 0x1d, 0xcd, 0xf5, 0x03, 0x22, 0x2a, 0x9e, 0x1f,
+	0x22, 0x3d, 0x77, 0x33, 0x6f, 0x15, 0xcd, 0x4d, 0x2a, 0x56, 0x35, 0xf1,
+	0x4c, 0x3c, 0x65, 0xaa, 0x60, 0xfd, 0xfe, 0x24, 0x9b, 0xdb, 0x98, 0xce,
+	0xa2, 0xbb, 0x87, 0xa0, 0x5a, 0x97, 0xc5, 0x66, 0x5d, 0xa0, 0xcf, 0xa6,
+	0x28, 0x5e, 0xa0, 0xc2, 0x6e, 0x53, 0xd1, 0x6b, 0xef, 0x05, 0x85, 0x06,
+	0xd5, 0x38, 0x0d, 0x9b, 0xec, 0x2c, 0xdc, 0x38, 0xfb, 0xf2, 0x1f, 0x25,
+	0xae, 0x66, 0xbb, 0xec, 0x98, 0xb3, 0xd1, 0x9e, 0xc2, 0xb7, 0x82, 0x23,
+	0x3e, 0xe3, 0x45, 0xc5, 0xa9, 0x21, 0x57, 0xb0, 0x3e, 0x1f, 0xdb, 0x93,
+	0x75, 0x62, 0x19, 0xea, 0xc4, 0xce, 0x61, 0x64, 0x76, 0x74, 0x48, 0xb9,
+	0x39, 0x65, 0x76, 0xbd, 0x00, 0x05, 0xc9, 0xe1, 0x30, 0x9e, 0x5e, 0xd2,
+	0x27, 0x5d, 0x7d, 0x85, 0x49, 0x79, 0xae, 0x53, 0x54, 0x63, 0xa0, 0xd9,
+	0x9c, 0x59, 0x49, 0x5c, 0x7f, 0xe7, 0x37, 0xe0, 0x0d, 0x9b, 0x62, 0xcc,
+	0x52, 0xfb, 0x3a, 0x43, 0xdc, 0xf7, 0x37, 0x12, 0x9f, 0x26, 0xb7, 0x52,
+	0xb1, 0x7a, 0x26, 0x28, 0xcf, 0x2a, 0x9c, 0x1e, 0xb9, 0xb3, 0x96, 0x63,
+	0x10, 0x4a, 0x34, 0xf5, 0x35, 0x39, 0x55, 0xcb, 0xb1, 0xc8, 0x73, 0x59,
+	0x54, 0xe8, 0xc3, 0x7c, 0x3e, 0xcf, 0x69, 0x2a, 0xc2, 0x49, 0x29, 0xc7,
+	0xed, 0xcd, 0x24, 0x2b, 0xcb, 0x30, 0x2f, 0xeb, 0x26, 0x99, 0xa9, 0x42,
+	0x2c, 0xea, 0x58, 0xbd, 0x93, 0x54, 0xa3, 0x23, 0x4e, 0x2b, 0xdd, 0x7b,
+	0xaf, 0x93, 0xc5, 0x39, 0x94, 0xfb, 0x7e, 0x54, 0x8c, 0x0f, 0x31, 0x0f,
+	0xf6, 0xcd, 0xb9, 0x7a, 0x40, 0xa3, 0xfb, 0x33, 0x26, 0xb2, 0x02, 0xfb,
+	0x52, 0x7d, 0xb2, 0x47, 0x67, 0x7e, 0x51, 0xf1, 0xec, 0xd0, 0xc7, 0x67,
+	0x7e, 0x1a, 0x7f, 0xef, 0x9c, 0x9d, 0xbe, 0x54, 0x8c, 0x09, 0xbf, 0x18,
+	0xa3, 0x25, 0xce, 0xcb, 0x14, 0xfb, 0xca, 0x6a, 0xba, 0x9d, 0x41, 0x4f,
+	0x09, 0x3c, 0xd5, 0x29, 0x70, 0xdd, 0x12, 0x9a, 0xc1, 0x96, 0x5a, 0x14,
+	0x27, 0xd7, 0x48, 0x63, 0xc1, 0x14, 0x05, 0xdc, 0xac, 0x2c, 0x4d, 0xaa,
+	0x78, 0x67, 0x09, 0x25, 0xd1, 0x55, 0x1c, 0xab, 0x0a, 0x5e, 0x20, 0xbc,
+	0xd5, 0x17, 0x59, 0x5d, 0x47, 0x51, 0x01, 0xe3, 0x2b, 0xbc, 0xb6, 0x62,
+	0x43, 0x18, 0xad, 0x09, 0x1d, 0x16, 0xf9, 0xbc, 0x86, 0x67, 0x69, 0x92,
+	0x9f, 0x69, 0xe7, 0x63, 0xdb, 0x2b, 0xc8, 0xd1, 0xbc, 0x8c, 0x9f, 0x59,
+	0xbe, 0x8f, 0xdf, 0x07, 0x86, 0x58, 0x3e, 0xf6, 0x17, 0xf9, 0x9a, 0x64,
+	0x2e, 0x49, 0xcd, 0xc7, 0xc5, 0x6d, 0x73, 0xb2, 0x46, 0x69, 0xae, 0x61,
+	0x9a, 0x62, 0x0c, 0x9d, 0xa0, 0xf8, 0x19, 0xff, 0x08, 0x87, 0x2c, 0x58,
+	0xce, 0xe7, 0x70, 0xac, 0x08, 0x60, 0xad, 0x82, 0xd4, 0x32, 0x9e, 0x11,
+	0x28, 0x06, 0x86, 0xcd, 0x4e, 0x43, 0x59, 0x44, 0xfb, 0x4c, 0x1b, 0x25,
+	0xbf, 0xf3, 0x7b, 0xf1, 0x9c, 0x5b, 0x9a, 0x38, 0xce, 0x5b, 0xe7, 0xfc,
+	0xf1, 0x0b, 0xbd, 0x38, 0xc3, 0x46, 0xa9, 0xe7, 0x81, 0xf6, 0x19, 0x4f,
+	0xc5, 0x1a, 0xc6, 0x49, 0xcd, 0xe3, 0xcc, 0xc7, 0xe8, 0xbf, 0x10, 0xee,
+	0x9f, 0x64, 0xaa, 0x8d, 0xfb, 0x75, 0x54, 0x5c, 0x37, 0xc4, 0xb8, 0x45,
+	0x7b, 0x7f, 0xd8, 0x4c, 0xf8, 0xed, 0xe7, 0xe2, 0xbf, 0xfc, 0x09, 0xfc,
+	0xcf, 0xf4, 0x77, 0x82, 0x2e, 0xb1, 0xc3, 0xa3, 0x0b, 0xbf, 0xa5, 0x5c,
+	0x56, 0x4e, 0x79, 0xfd, 0x10, 0xf5, 0xf9, 0x83, 0x23, 0x5d, 0x62, 0x3b,
+	0x99, 0xe7, 0xc0, 0xd8, 0x2a, 0x71, 0xb7, 0x67, 0xf1, 0x2c, 0x39, 0xd7,
+	0xf3, 0x8b, 0xdf, 0xf7, 0xb6, 0x7d, 0xea, 0xbb, 0x5d, 0xa4, 0x47, 0x77,
+	0xd0, 0x5d, 0x3f, 0x78, 0x97, 0x6c, 0xb0, 0xb8, 0x9e, 0x59, 0x53, 0x17,
+	0x87, 0x22, 0x9d, 0xb1, 0xe5, 0x21, 0x44, 0x2d, 0x74, 0xc7, 0x68, 0xd6,
+	0x7a, 0xb1, 0xd0, 0xe3, 0x0c, 0x18, 0xb9, 0x81, 0xda, 0x62, 0x0c, 0x48,
+	0x49, 0x75, 0x5f, 0xad, 0x74, 0xd0, 0x53, 0xe2, 0x94, 0x68, 0x97, 0x74,
+	0x44, 0x90, 0xeb, 0xe8, 0xaa, 0x3f, 0x9e, 0xbb, 0xac, 0xfe, 0xb9, 0x5c,
+	0x5d, 0x0f, 0xdd, 0x7d, 0xeb, 0x7f, 0xe6, 0x01, 0x67, 0x48, 0x86, 0xb0,
+	0x73, 0xa5, 0xbb, 0x2f, 0x0d, 0xa5, 0xb7, 0xc3, 0x32, 0x16, 0x8b, 0x75,
+	0xeb, 0x48, 0x87, 0xfa, 0x63, 0xb9, 0x3b, 0xd7, 0x85, 0x26, 0xa9, 0xdb,
+	0xe9, 0xb8, 0xf3, 0xed, 0xf4, 0x9d, 0xd8, 0xe2, 0xf5, 0x61, 0x93, 0x17,
+	0x2f, 0xd4, 0xa8, 0x5d, 0x2c, 0x93, 0xcf, 0xdf, 0xec, 0x58, 0xd6, 0x08,
+	0xb6, 0xe6, 0x55, 0xbc, 0x55, 0xd8, 0x33, 0x13, 0xab, 0xf1, 0x31, 0xee,
+	0x67, 0xf1, 0x3e, 0xf9, 0x2d, 0x91, 0x63, 0x06, 0x99, 0xd0, 0xa0, 0x94,
+	0x4a, 0x9a, 0xef, 0x7f, 0xd3, 0x34, 0x0b, 0x73, 0x8d, 0x79, 0x0f, 0xfb,
+	0xad, 0x05, 0xfc, 0x2d, 0x91, 0x21, 0x53, 0x3a, 0xc8, 0x7b, 0xa7, 0xe7,
+	0xf6, 0xde, 0xa1, 0x3d, 0x88, 0x53, 0xd4, 0xab, 0xa8, 0x8e, 0x17, 0xf6,
+	0xcb, 0x07, 0x23, 0xf8, 0x7b, 0x9f, 0x71, 0x4e, 0xce, 0xe1, 0xfc, 0x8a,
+	0x70, 0xe2, 0x58, 0x53, 0x05, 0xb7, 0x92, 0x73, 0x6b, 0x78, 0xfe, 0x5b,
+	0x23, 0xe5, 0x89, 0xfd, 0x61, 0xb4, 0xf8, 0xad, 0x31, 0x2a, 0xb4, 0xfb,
+	0xe8, 0x39, 0xca, 0x71, 0xc8, 0xb1, 0xca, 0xf4, 0xc7, 0x53, 0x45, 0xfa,
+	0x63, 0x29, 0xa6, 0xff, 0x2c, 0x8d, 0x9a, 0x89, 0x0c, 0xc6, 0xa9, 0xfe,
+	0xbe, 0x4b, 0xb5, 0xa0, 0xc8, 0xbb, 0x48, 0xf7, 0x4f, 0x73, 0x74, 0x87,
+	0x89, 0xee, 0x0f, 0x14, 0x87, 0x4c, 0xcb, 0x7a, 0x72, 0x6e, 0xcc, 0xfb,
+	0xaf, 0x45, 0x1c, 0xf2, 0x0c, 0x1c, 0xca, 0xa9, 0x62, 0x1f, 0xd5, 0xda,
+	0x31, 0xba, 0xb7, 0x0c, 0x14, 0xbe, 0xa5, 0xea, 0x64, 0x93, 0x17, 0xaa,
+	0x8a, 0xfe, 0xe2, 0xef, 0xcb, 0x53, 0x58, 0xe1, 0x25, 0xa9, 0xf7, 0x6b,
+	0x05, 0x9d, 0x4a, 0x9d, 0xa7, 0xf1, 0x5b, 0xaa, 0x97, 0xa7, 0x0a, 0xdf,
+	0x6f, 0x9e, 0x46, 0x32, 0xc7, 0x73, 0x8f, 0x25, 0x36, 0x79, 0x46, 0x8f,
+	0x42, 0xbc, 0x57, 0xe5, 0x8a, 0x35, 0x84, 0xfa, 0x5b, 0x86, 0x6a, 0xb3,
+	0x78, 0xa6, 0xf0, 0x5e, 0x43, 0x3d, 0x8f, 0x65, 0xc8, 0x88, 0x44, 0xd2,
+	0x45, 0x43, 0xd2, 0x95, 0xaa, 0x65, 0x1d, 0x53, 0x43, 0x96, 0xfe, 0x4e,
+	0x28, 0x73, 0x8b, 0x82, 0xbb, 0xf0, 0x7e, 0x7b, 0xe6, 0x6f, 0xea, 0xe9,
+	0x6f, 0x65, 0x3b, 0x8c, 0x0a, 0xca, 0xf3, 0x1b, 0x3a, 0x9a, 0x32, 0x2f,
+	0x89, 0xa6, 0xee, 0xac, 0x68, 0x72, 0xd7, 0x88, 0xa6, 0xce, 0x32, 0x61,
+	0x6b, 0xcf, 0x51, 0x13, 0x7f, 0x39, 0x37, 0x6f, 0x07, 0xf6, 0x1f, 0xdb,
+	0x80, 0xc2, 0xdc, 0xb1, 0x32, 0x8b, 0x45, 0x8c, 0xee, 0xfe, 0x9c, 0x0f,
+	0x0d, 0xa0, 0x5e, 0x74, 0x36, 0xd7, 0xd1, 0xba, 0x7e, 0x97, 0x28, 0xa3,
+	0x7a, 0xa0, 0x63, 0x2f, 0xcd, 0x27, 0x0d, 0x16, 0xc7, 0x27, 0x35, 0xc8,
+	0x05, 0x2c, 0xcf, 0xcf, 0x23, 0x45, 0xfd, 0xd6, 0x55, 0x17, 0xf3, 0x4f,
+	0x50, 0x9d, 0x83, 0x16, 0xa3, 0x58, 0x7d, 0x9f, 0xea, 0xda, 0xef, 0x9a,
+	0x8a, 0x71, 0xbb, 0x94, 0xbf, 0x03, 0x17, 0xf0, 0x8e, 0x4b, 0xba, 0x5b,
+	0x91, 0x4e, 0xe7, 0x31, 0x3e, 0xe9, 0x3b, 0x55, 0xfd, 0x69, 0xfa, 0xa2,
+	0x6d, 0x15, 0x9a, 0x01, 0x8e, 0xe4, 0x33, 0x62, 0xb5, 0x87, 0x2d, 0xa1,
+	0x82, 0xfe, 0x06, 0x56, 0xe7, 0xba, 0xc4, 0x2a, 0xcf, 0x32, 0x06, 0xc8,
+	0x06, 0xdb, 0xf4, 0x56, 0x7d, 0x8c, 0xea, 0x16, 0xf1, 0x32, 0x4a, 0x29,
+	0x07, 0x34, 0x67, 0x01, 0xee, 0x99, 0x8b, 0x29, 0xca, 0x0b, 0xb7, 0xcc,
+	0xe9, 0x13, 0x8b, 0x27, 0xf8, 0x95, 0xf8, 0x7c, 0xa4, 0xdf, 0x87, 0x72,
+	0xfb, 0x55, 0xbc, 0xdf, 0x3f, 0xe7, 0x93, 0x9b, 0xf9, 0x4c, 0x7a, 0x3f,
+	0x35, 0x27, 0xc3, 0xff, 0x44, 0x3b, 0x71, 0xfe, 0xa7, 0x69, 0x78, 0xae,
+	0xe3, 0x3b, 0x05, 0xdc, 0x6a, 0x87, 0x67, 0xba, 0x85, 0x73, 0xb1, 0x30,
+	0x4c, 0xbc, 0xb7, 0xe0, 0xca, 0x65, 0x40, 0xf3, 0xe0, 0x42, 0x6c, 0xcf,
+	0x03, 0x2d, 0x83, 0x3c, 0x63, 0xcf, 0xc2, 0xcb, 0x42, 0x2b, 0x73, 0x66,
+	0x70, 0x61, 0xb6, 0xb1, 0xb7, 0x54, 0x98, 0x2d, 0x59, 0x61, 0x76, 0x03,
+	0xad, 0x34, 0x7d, 0x98, 0x89, 0xc5, 0xc2, 0x34, 0x36, 0x83, 0x6d, 0x35,
+	0x8b, 0xa6, 0x42, 0xae, 0xcf, 0xc0, 0x22, 0x7f, 0x77, 0x0f, 0x86, 0xa0,
+	0xb4, 0xfd, 0x8e, 0x6c, 0x66, 0x76, 0x42, 0x2c, 0xa4, 0xf9, 0x96, 0x63,
+	0x72, 0x16, 0x5b, 0xa9, 0x4f, 0xd7, 0x13, 0xce, 0xe7, 0xa9, 0x07, 0x34,
+	0x0e, 0x9a, 0x33, 0x80, 0xd9, 0x77, 0x71, 0xa8, 0xb1, 0xa5, 0x17, 0xe6,
+	0x96, 0x6d, 0x68, 0x9d, 0x7a, 0x46, 0x98, 0x99, 0x19, 0x21, 0x50, 0xda,
+	0x56, 0xe4, 0xb9, 0x74, 0x8e, 0x67, 0x0b, 0xdf, 0x37, 0x0a, 0xb9, 0x45,
+	0x77, 0x92, 0xb6, 0x5f, 0xc8, 0xa9, 0x82, 0xcd, 0xfe, 0x7a, 0x4e, 0xff,
+	0xec, 0x9c, 0x0f, 0xd4, 0xb9, 0xf7, 0x9f, 0x54, 0x73, 0x7d, 0x2f, 0x69,
+	0x2b, 0xcc, 0xe3, 0x14, 0x97, 0x5f, 0x44, 0x3f, 0xcd, 0x7e, 0x99, 0x02,
+	0x7d, 0x17, 0x7a, 0x72, 0x10, 0x9b, 0xbd, 0xa9, 0xd2, 0x67, 0x68, 0xaa,
+	0x1e, 0x29, 0xf0, 0xb9, 0x8c, 0xd6, 0xba, 0xe9, 0xc7, 0x36, 0xfb, 0xaf,
+	0x4a, 0xbe, 0x3d, 0x38, 0xaa, 0xfb, 0x4a, 0xf3, 0xbb, 0xfd, 0x90, 0x5a,
+	0xef, 0xab, 0x27, 0x2d, 0x03, 0x56, 0x37, 0x7d, 0x5b, 0x6a, 0x5b, 0xb2,
+	0xb9, 0x0d, 0xcd, 0x22, 0x7b, 0xb5, 0x4b, 0x1b, 0x84, 0x2c, 0x82, 0xb1,
+	0x65, 0x1b, 0xc7, 0xb8, 0xd6, 0xb5, 0x56, 0xb0, 0x31, 0x18, 0x3b, 0x89,
+	0xec, 0xe1, 0x0f, 0x25, 0x9e, 0x1d, 0xf5, 0x48, 0x20, 0x04, 0xf4, 0x4b,
+	0x12, 0x2c, 0xb0, 0x55, 0x53, 0x6e, 0xf4, 0x00, 0xe2, 0xb4, 0x24, 0xbc,
+	0x99, 0xd4, 0x2a, 0xa9, 0x9a, 0xb1, 0x62, 0xc4, 0x2b, 0x36, 0xc6, 0x9e,
+	0xc9, 0x6c, 0x91, 0x2d, 0xbb, 0xcc, 0x40, 0x00, 0x27, 0x7e, 0xe1, 0xcc,
+	0x4c, 0x2c, 0xc6, 0x89, 0xef, 0x7e, 0xe7, 0xde, 0x6e, 0x10, 0x84, 0xc4,
+	0x35, 0x54, 0xa9, 0xda, 0xdd, 0xf7, 0xf7, 0x3c, 0xbf, 0x73, 0xbe, 0xf3,
+	0x9d, 0x73, 0x7e, 0xd7, 0x92, 0xcb, 0x58, 0xcb, 0xff, 0x0e, 0x9b, 0xed,
+	0x36, 0x45, 0xd1, 0x98, 0x1b, 0xbc, 0x6a, 0x9c, 0x53, 0x2d, 0x1d, 0xb1,
+	0x99, 0x1c, 0xbd, 0x59, 0x9e, 0x25, 0x25, 0x77, 0xb3, 0x3e, 0xe4, 0xf7,
+	0x74, 0x9b, 0xbc, 0xdf, 0x83, 0x67, 0xd2, 0x1e, 0x6c, 0x20, 0xb6, 0xa6,
+	0x4c, 0x6c, 0xbd, 0x1e, 0x1f, 0xd9, 0xd8, 0x6e, 0x05, 0xdb, 0xf5, 0x64,
+	0xb8, 0x53, 0x73, 0xfa, 0xac, 0xa9, 0x2b, 0x8e, 0x26, 0x39, 0x07, 0x91,
+	0xbd, 0xc4, 0x76, 0xd9, 0xd8, 0x57, 0xce, 0x24, 0xac, 0x0c, 0x46, 0x5b,
+	0x95, 0xfe, 0x68, 0x31, 0xe7, 0x8b, 0x28, 0xc9, 0x90, 0x6d, 0x77, 0x29,
+	0xe3, 0xa9, 0x15, 0x8b, 0x56, 0x12, 0x7f, 0xb4, 0x80, 0x66, 0x2b, 0xc1,
+	0xb3, 0x81, 0x39, 0x98, 0x52, 0x97, 0x62, 0x73, 0x20, 0x87, 0x5c, 0x69,
+	0x3f, 0x36, 0xaa, 0xb9, 0xd8, 0x14, 0xf8, 0x0b, 0xe0, 0xe1, 0x3c, 0xea,
+	0xb1, 0xc5, 0x39, 0x73, 0x38, 0x6f, 0x1e, 0x31, 0xe3, 0x39, 0x73, 0xdf,
+	0xe3, 0xb2, 0x57, 0xae, 0xb3, 0x59, 0x49, 0x12, 0xf3, 0x2b, 0x4c, 0xdb,
+	0x9d, 0xf9, 0x7e, 0x28, 0x65, 0xe6, 0x60, 0x5f, 0x5e, 0x6c, 0xca, 0xf9,
+	0xf7, 0xdf, 0xd7, 0xd3, 0xab, 0xcb, 0xc9, 0xd3, 0xa9, 0x3f, 0xcb, 0x11,
+	0xae, 0x5c, 0x82, 0xe7, 0x03, 0x8d, 0x28, 0xd2, 0x9a, 0xf1, 0x6d, 0x35,
+	0x42, 0x4c, 0x1f, 0xc2, 0x77, 0xcc, 0x31, 0x64, 0x3c, 0xb3, 0x66, 0xc4,
+	0x7f, 0xbf, 0xb3, 0x43, 0xfb, 0xba, 0xf8, 0xd2, 0xca, 0xc9, 0xb4, 0xdb,
+	0x9c, 0xe8, 0x19, 0x90, 0x4f, 0x07, 0xbe, 0x13, 0xb2, 0x72, 0xb0, 0xf1,
+	0x21, 0x27, 0x62, 0x03, 0x0e, 0xa4, 0x83, 0x64, 0x3f, 0x95, 0x37, 0x8f,
+	0x3d, 0xc4, 0xb1, 0xad, 0xbc, 0xc5, 0x77, 0x29, 0xd7, 0x73, 0x4e, 0x27,
+	0xb9, 0x10, 0xd4, 0x0a, 0xb6, 0x29, 0x1f, 0x2f, 0x80, 0x7b, 0x48, 0xea,
+	0x4e, 0x93, 0xca, 0x96, 0xb4, 0xd5, 0xe6, 0x7b, 0x52, 0xab, 0xca, 0xb5,
+	0x81, 0xbe, 0x88, 0xdb, 0x75, 0xb0, 0x8d, 0x8b, 0x71, 0x71, 0x3e, 0x6a,
+	0x86, 0x0a, 0xf8, 0xa7, 0xa2, 0xf4, 0x20, 0x1f, 0x8c, 0x37, 0x2b, 0x2f,
+	0x46, 0x03, 0x28, 0x65, 0xbc, 0x5e, 0xd6, 0x64, 0xf5, 0x7f, 0x29, 0xfd,
+	0x75, 0xeb, 0x77, 0xa2, 0xbd, 0x54, 0xce, 0xab, 0x06, 0x85, 0xda, 0x94,
+	0xf1, 0x82, 0x85, 0xf1, 0xa6, 0x2f, 0xed, 0xbe, 0x56, 0xe7, 0x92, 0x35,
+	0x29, 0xc2, 0x5b, 0xd5, 0xf2, 0x26, 0x89, 0x9b, 0xf9, 0xa3, 0x19, 0x77,
+	0xcb, 0x1a, 0x64, 0xec, 0x7c, 0xe4, 0x0e, 0xc9, 0xd8, 0x05, 0xc8, 0xb9,
+	0xb6, 0x16, 0x99, 0x87, 0x61, 0xde, 0xb8, 0xf8, 0x57, 0x99, 0x6f, 0x52,
+	0x19, 0x4c, 0xcb, 0x1a, 0xb2, 0xf3, 0x9e, 0x32, 0x9e, 0x51, 0x0b, 0xe8,
+	0xcf, 0x87, 0x8d, 0x0d, 0x15, 0x86, 0xe1, 0x5f, 0x74, 0xdc, 0x48, 0xad,
+	0x35, 0xb1, 0xd6, 0xd8, 0x9d, 0x70, 0x62, 0x17, 0xe5, 0xb6, 0x39, 0x78,
+	0x58, 0x78, 0x5c, 0xe6, 0x5f, 0x56, 0x6e, 0x47, 0x28, 0xb7, 0xb9, 0x99,
+	0x73, 0x9c, 0x54, 0x8e, 0x5e, 0xf3, 0xf7, 0xb2, 0x46, 0x59, 0x97, 0x82,
+	0x72, 0x4d, 0xd6, 0x65, 0x43, 0x99, 0x96, 0x8f, 0x72, 0xca, 0xa7, 0xcc,
+	0x5c, 0x53, 0xb3, 0xf2, 0x6e, 0x14, 0x6a, 0x09, 0xb9, 0x43, 0xe9, 0xb8,
+	0xb5, 0xae, 0x29, 0xca, 0xe7, 0xcc, 0x35, 0x9d, 0x98, 0x2d, 0x67, 0xa1,
+	0x57, 0x62, 0xd3, 0x33, 0xdf, 0xdf, 0x9a, 0x94, 0x71, 0xed, 0x74, 0x9c,
+	0x0a, 0xb6, 0x87, 0xc4, 0x5f, 0xe0, 0xe5, 0xe5, 0x51, 0x4b, 0x06, 0x36,
+	0xf3, 0x0c, 0xc4, 0x06, 0x64, 0xff, 0xd9, 0xbd, 0x37, 0x2b, 0x4f, 0x45,
+	0xa5, 0xbf, 0x86, 0x1a, 0xb3, 0x9f, 0x15, 0x37, 0xdb, 0xa8, 0x7f, 0xcb,
+	0x79, 0x36, 0xb6, 0x71, 0x4b, 0x37, 0x3d, 0xa9, 0x56, 0xce, 0x2b, 0xe7,
+	0x34, 0xa9, 0x74, 0x72, 0x4e, 0x98, 0x67, 0xfb, 0x5f, 0xcb, 0x2d, 0x5b,
+	0x9f, 0xa4, 0x6d, 0xf2, 0x37, 0xa7, 0x8d, 0xfa, 0x5e, 0x00, 0xc7, 0x90,
+	0xcb, 0xcc, 0xf1, 0xc8, 0xd8, 0xcf, 0x45, 0xcb, 0x90, 0x77, 0x30, 0xdb,
+	0xd7, 0xf2, 0xed, 0x56, 0x8d, 0x30, 0x6b, 0x8f, 0x82, 0x8f, 0xe2, 0x27,
+	0x22, 0x4a, 0xf8, 0x5a, 0x9d, 0x4f, 0x72, 0x5f, 0x52, 0xff, 0xcc, 0xe5,
+	0x7a, 0x24, 0x7f, 0xaa, 0x10, 0x33, 0x6c, 0xc4, 0xe9, 0xe5, 0x1e, 0x07,
+	0x71, 0x6e, 0x03, 0xbe, 0x34, 0x22, 0x15, 0xe1, 0x80, 0x13, 0x56, 0x8c,
+	0xde, 0x8e, 0x5c, 0x58, 0x18, 0x44, 0x2d, 0x8d, 0xd2, 0x1f, 0x73, 0xaf,
+	0xe4, 0x00, 0xe8, 0x4e, 0x7f, 0x69, 0x4c, 0x55, 0x38, 0xe8, 0xf3, 0xaf,
+	0xe5, 0xd6, 0x68, 0x77, 0x86, 0x31, 0xcc, 0x67, 0xbd, 0xe9, 0xec, 0x39,
+	0x91, 0x5b, 0x90, 0x6b, 0x3e, 0xad, 0xfd, 0xbb, 0xb1, 0xfe, 0x86, 0xb6,
+	0x59, 0x6c, 0xb6, 0x62, 0xed, 0x23, 0x26, 0x36, 0x17, 0xa2, 0x77, 0xb7,
+	0x37, 0x99, 0x02, 0x79, 0x8b, 0x66, 0x9b, 0x2b, 0x31, 0x82, 0x1d, 0xde,
+	0xbe, 0x66, 0xc6, 0xfa, 0xc4, 0x4e, 0x4f, 0x0a, 0xff, 0x5c, 0x2e, 0x76,
+	0xc4, 0x78, 0xcd, 0x53, 0x6a, 0x2b, 0x93, 0xb5, 0x9b, 0xab, 0xb2, 0x0f,
+	0xe4, 0x61, 0x43, 0x43, 0x1e, 0x52, 0x6d, 0xc4, 0xac, 0x81, 0x48, 0x2b,
+	0x87, 0x77, 0xe5, 0x37, 0xbd, 0xf5, 0xbd, 0x6f, 0xf8, 0xbd, 0xf4, 0x93,
+	0x40, 0x6e, 0x8c, 0x73, 0x22, 0x83, 0x69, 0x03, 0xde, 0x88, 0xcd, 0x26,
+	0xfd, 0x7f, 0x6b, 0x90, 0x63, 0xb3, 0xaf, 0x8c, 0xc1, 0xb9, 0xff, 0xc8,
+	0x16, 0x24, 0xee, 0xfb, 0xb2, 0x5c, 0xf2, 0x8e, 0x6a, 0xad, 0x82, 0xc2,
+	0x81, 0x42, 0x14, 0x30, 0x4e, 0xdf, 0x55, 0xe9, 0xeb, 0xd0, 0x6d, 0xf9,
+	0x38, 0x7d, 0xd7, 0x7f, 0x41, 0xaa, 0x32, 0x07, 0xae, 0x5a, 0x60, 0x45,
+	0xdc, 0x06, 0x5b, 0x2d, 0xb1, 0x37, 0x04, 0x34, 0x8f, 0xf3, 0xdc, 0x06,
+	0x14, 0x3c, 0x91, 0xb4, 0xe1, 0xc1, 0xa4, 0x1d, 0xab, 0x93, 0xf8, 0xab,
+	0x1a, 0x60, 0xba, 0x1a, 0xfe, 0xf6, 0x19, 0x05, 0x9b, 0x8b, 0x61, 0xfa,
+	0xf8, 0xd6, 0xd5, 0x8c, 0x4b, 0x57, 0x8d, 0x13, 0xcf, 0xd8, 0xd6, 0xc9,
+	0x98, 0xcd, 0xd1, 0x6f, 0x47, 0x75, 0x3f, 0x6e, 0xcf, 0x05, 0x42, 0x4e,
+	0xf8, 0x67, 0xe8, 0x67, 0xca, 0x1c, 0xf0, 0x4f, 0x9d, 0xb7, 0xfb, 0x3b,
+	0xab, 0xed, 0x3c, 0xdc, 0x5a, 0x59, 0x8b, 0x0b, 0x0f, 0x51, 0x9f, 0x6b,
+	0x06, 0xd8, 0xbe, 0xd6, 0x06, 0x55, 0x53, 0x70, 0xe5, 0x71, 0xc9, 0xfb,
+	0xca, 0x33, 0xc9, 0x55, 0x28, 0x28, 0x1e, 0xb0, 0x13, 0xc3, 0xde, 0x34,
+	0x4e, 0x57, 0x0a, 0x7e, 0x03, 0x4f, 0x70, 0x6d, 0x6e, 0xfe, 0xa6, 0xd6,
+	0xba, 0xb0, 0x70, 0xa9, 0x8a, 0x75, 0x43, 0x5f, 0x9a, 0x3a, 0x25, 0xe3,
+	0x38, 0x69, 0x53, 0x39, 0xb4, 0xf1, 0x83, 0x66, 0x0d, 0xd1, 0xc6, 0x3d,
+	0xda, 0x51, 0x30, 0x00, 0xac, 0x8a, 0xe3, 0x91, 0x42, 0xf8, 0xc3, 0xb2,
+	0xc6, 0xba, 0x25, 0x0e, 0xf6, 0x2d, 0x44, 0xeb, 0xb8, 0xd5, 0xef, 0xfe,
+	0xf1, 0x92, 0x0a, 0x2b, 0x07, 0xfe, 0xa7, 0x6b, 0xda, 0x3d, 0x21, 0x3f,
+	0x36, 0x24, 0xa9, 0x73, 0x36, 0x0f, 0x86, 0x32, 0xb9, 0xe8, 0xf5, 0x29,
+	0xef, 0xac, 0x9a, 0xf3, 0xdf, 0x14, 0x66, 0xea, 0xd1, 0xb4, 0x85, 0x19,
+	0x8e, 0x13, 0x51, 0xd6, 0x53, 0x76, 0x43, 0x13, 0x06, 0xa2, 0xba, 0x81,
+	0x31, 0xfe, 0xbd, 0xad, 0x4b, 0xde, 0x63, 0x52, 0x79, 0x26, 0xf6, 0x95,
+	0x11, 0xc9, 0xd8, 0xf3, 0x0f, 0x12, 0x01, 0x65, 0x53, 0x0c, 0x78, 0x95,
+	0xfe, 0xf4, 0x10, 0xff, 0x46, 0x12, 0x92, 0x47, 0xa2, 0xec, 0x69, 0xd7,
+	0xdb, 0x52, 0xc0, 0x70, 0x02, 0xe1, 0xfd, 0x4b, 0x84, 0xc3, 0x17, 0x70,
+	0x3e, 0x5a, 0x0d, 0xdb, 0xa4, 0xf9, 0x77, 0x90, 0x7f, 0x13, 0x3c, 0x53,
+	0xce, 0x87, 0xc0, 0x98, 0x03, 0xe1, 0x31, 0x02, 0xed, 0x58, 0x00, 0x53,
+	0xf4, 0x81, 0x57, 0x47, 0x54, 0x14, 0x1d, 0x2a, 0xc3, 0xa7, 0xa3, 0xc4,
+	0xc7, 0x03, 0x16, 0xef, 0xdf, 0x30, 0x26, 0xf5, 0x42, 0xd9, 0x9f, 0xd4,
+	0xd7, 0xc5, 0x9e, 0xf2, 0x70, 0x28, 0x59, 0x66, 0xd6, 0xd8, 0x2f, 0xe8,
+	0x1c, 0x5b, 0x95, 0xda, 0x68, 0x1b, 0x0e, 0x47, 0x7d, 0x9e, 0x3e, 0xea,
+	0x7c, 0xc4, 0x21, 0x36, 0x16, 0xc2, 0xab, 0xd1, 0x6c, 0x8d, 0xcd, 0xc7,
+	0x78, 0xd7, 0x09, 0x8f, 0xb3, 0x8c, 0xf2, 0x95, 0x67, 0x59, 0x5f, 0x2a,
+	0x7b, 0x96, 0x7c, 0x7e, 0x96, 0xb7, 0xcc, 0xfe, 0xfd, 0xa4, 0x21, 0xb5,
+	0xdf, 0xd7, 0x26, 0xbc, 0x7d, 0x29, 0xe8, 0xa6, 0xaf, 0x1c, 0xad, 0xf3,
+	0x26, 0x23, 0x90, 0xf3, 0x0d, 0x71, 0x0d, 0x1f, 0x53, 0xf7, 0x03, 0x94,
+	0xf5, 0x5f, 0xd3, 0xb7, 0x4b, 0x9e, 0xbc, 0x14, 0xbb, 0xfa, 0xcb, 0xb0,
+	0xb3, 0x3f, 0x82, 0xde, 0x25, 0x6b, 0x71, 0x32, 0x6a, 0x60, 0x43, 0xd0,
+	0xc0, 0xaa, 0xa0, 0x37, 0xf0, 0x03, 0xd4, 0x37, 0x1e, 0xc6, 0x43, 0xe4,
+	0x10, 0x2a, 0x65, 0xf2, 0x24, 0x3e, 0xd8, 0xed, 0xc0, 0xb3, 0xfa, 0x37,
+	0x69, 0xc3, 0x86, 0xf1, 0xab, 0xc5, 0xf3, 0x30, 0x94, 0xa8, 0x57, 0xbb,
+	0xb9, 0xbe, 0xf0, 0x5a, 0x9e, 0x55, 0x83, 0x03, 0x1b, 0xf5, 0xbf, 0x62,
+	0x5b, 0xb7, 0xcd, 0xa1, 0xc9, 0x77, 0x1b, 0xfd, 0xa9, 0x9c, 0x65, 0x84,
+	0xfa, 0x65, 0xf9, 0xb2, 0x70, 0xa6, 0x3e, 0xf1, 0x6c, 0x48, 0x30, 0xbf,
+	0x10, 0x27, 0x28, 0xb7, 0x37, 0x92, 0x61, 0x49, 0x45, 0x29, 0x1b, 0x43,
+	0x5d, 0x78, 0x8a, 0x7c, 0xe3, 0x03, 0x12, 0x81, 0x7b, 0xe2, 0x0a, 0x1a,
+	0xeb, 0x74, 0x9c, 0x4d, 0x3f, 0x89, 0x77, 0x46, 0x9a, 0xf0, 0x36, 0x7d,
+	0xfa, 0xc2, 0xff, 0xe9, 0x65, 0x2c, 0xef, 0xc1, 0xe9, 0x74, 0x13, 0xde,
+	0x8c, 0x7a, 0xdb, 0x5e, 0x20, 0x3f, 0xfa, 0x79, 0xda, 0x81, 0x3b, 0xe2,
+	0x8c, 0x7b, 0x38, 0x8e, 0x3f, 0xee, 0xc0, 0xc5, 0xb4, 0x8a, 0xc3, 0x3c,
+	0x1f, 0x47, 0x70, 0x21, 0xe3, 0x5e, 0x0f, 0x0e, 0x0e, 0x3e, 0x88, 0xa9,
+	0xd4, 0x83, 0x38, 0x96, 0xfc, 0xc0, 0x70, 0x69, 0x52, 0x27, 0x73, 0xe1,
+	0x22, 0x63, 0xb2, 0x69, 0x4a, 0xa3, 0x70, 0x69, 0x1b, 0xfd, 0xbc, 0x16,
+	0x11, 0xb9, 0xbf, 0xc3, 0xdf, 0xee, 0x89, 0x37, 0x62, 0xff, 0x18, 0x45,
+	0x9a, 0xd0, 0x91, 0x88, 0xc9, 0x5c, 0x21, 0xc4, 0xc8, 0x0b, 0x77, 0xf5,
+	0x1b, 0xf4, 0x17, 0x77, 0x48, 0x0c, 0xa2, 0xb4, 0xd6, 0xfe, 0x73, 0x66,
+	0x1f, 0x8d, 0xb3, 0x6a, 0xa0, 0xf9, 0x3c, 0x1b, 0xca, 0x95, 0xfd, 0xfe,
+	0x77, 0xa2, 0xc1, 0xf4, 0x4d, 0x47, 0xae, 0x9d, 0x47, 0x23, 0xcf, 0xe3,
+	0x49, 0x9c, 0xdd, 0xbd, 0x16, 0xef, 0x10, 0xef, 0x8a, 0x17, 0xfb, 0x3a,
+	0x9d, 0xb6, 0x7a, 0x8e, 0x9d, 0x36, 0x52, 0x95, 0x22, 0xd3, 0xb5, 0xf8,
+	0x65, 0x54, 0x64, 0x9a, 0x26, 0xfe, 0xf9, 0x3c, 0x7e, 0xfb, 0x5b, 0xb4,
+	0x09, 0xb7, 0xad, 0xbb, 0xc1, 0xaa, 0xe9, 0x15, 0x2e, 0x75, 0xe1, 0x92,
+	0xb9, 0x36, 0x59, 0xeb, 0x9f, 0x5b, 0xdf, 0x2f, 0x8d, 0x55, 0x95, 0xb2,
+	0xbe, 0x88, 0x91, 0xa3, 0x69, 0x81, 0x1c, 0x45, 0xfc, 0x6c, 0xc0, 0xac,
+	0x63, 0xd4, 0xc5, 0xbb, 0x60, 0x0f, 0x16, 0x32, 0x3e, 0xf3, 0xce, 0x74,
+	0xe0, 0x1d, 0x5c, 0x9e, 0x70, 0x61, 0x41, 0x3c, 0x80, 0x57, 0x26, 0x72,
+	0x2b, 0x91, 0xff, 0x0b, 0x9c, 0xe7, 0x77, 0x5f, 0xdc, 0xb2, 0xb7, 0xee,
+	0xd0, 0x5a, 0xac, 0x48, 0xcb, 0xfe, 0x9e, 0xe4, 0x44, 0x3a, 0xc2, 0x69,
+	0xd9, 0x67, 0x8c, 0xb6, 0x21, 0xfb, 0x2c, 0xfb, 0x9a, 0x7d, 0xbe, 0xcb,
+	0xb5, 0xcf, 0xa3, 0x2d, 0x65, 0x7d, 0x47, 0x11, 0x0e, 0x26, 0x55, 0x9c,
+	0xd0, 0x8b, 0x70, 0x4e, 0x95, 0x7c, 0xbd, 0x8b, 0x3e, 0xc4, 0x81, 0x66,
+	0xc6, 0x4b, 0xc3, 0xd1, 0x3c, 0x3c, 0xa3, 0x3a, 0x70, 0x4a, 0x77, 0xe0,
+	0x98, 0x7e, 0x1b, 0xb1, 0x5e, 0xe2, 0x08, 0xd3, 0xbf, 0x90, 0x31, 0x65,
+	0xf5, 0x58, 0x9e, 0x17, 0xc2, 0x53, 0x5a, 0x86, 0x37, 0x25, 0xef, 0x68,
+	0xb6, 0x71, 0x49, 0xad, 0x17, 0x87, 0x28, 0xb3, 0x9c, 0x58, 0x39, 0x2e,
+	0xb5, 0x35, 0xde, 0xa2, 0x1f, 0x69, 0xac, 0xf6, 0xb1, 0xb1, 0xb9, 0xf2,
+	0xda, 0x98, 0x1e, 0x28, 0x47, 0x2a, 0x2c, 0x9c, 0xc8, 0xd6, 0xe1, 0xb2,
+	0xbe, 0x6c, 0x76, 0xbf, 0xd9, 0xfb, 0x7c, 0xa1, 0x52, 0xb0, 0xc9, 0x61,
+	0xc6, 0x82, 0x6d, 0xdf, 0xa4, 0x8f, 0xa2, 0xcf, 0x5e, 0xbb, 0x45, 0x62,
+	0x43, 0x5b, 0xd3, 0xba, 0x6f, 0x2e, 0xd7, 0x72, 0x60, 0x37, 0xb9, 0xa0,
+	0xe3, 0x65, 0x8b, 0xbf, 0xbb, 0x5e, 0xd6, 0xcc, 0xcf, 0xc2, 0x97, 0x17,
+	0x98, 0x9f, 0xea, 0xcb, 0xbe, 0xd4, 0x75, 0x5f, 0x66, 0xf1, 0x63, 0xf3,
+	0xae, 0x10, 0xfa, 0xf4, 0x88, 0x72, 0x7f, 0x48, 0x78, 0xe6, 0x6c, 0x8e,
+	0x11, 0x50, 0x4e, 0x45, 0x23, 0x46, 0xb5, 0x96, 0x1f, 0x29, 0x26, 0xf7,
+	0x6e, 0xf4, 0x6b, 0xc4, 0x6a, 0x89, 0xe9, 0x34, 0x9c, 0xe1, 0x79, 0x10,
+	0x62, 0xa9, 0xe3, 0xff, 0x0f, 0xd1, 0xdd, 0x68, 0xcf, 0x37, 0x71, 0xc9,
+	0x30, 0x76, 0x05, 0x25, 0x07, 0x21, 0xe3, 0x3a, 0xf0, 0x11, 0xcf, 0xf9,
+	0x37, 0x23, 0x05, 0xf8, 0x30, 0xa5, 0xe1, 0x5c, 0x7a, 0x2d, 0x76, 0x4c,
+	0x58, 0x1c, 0xe4, 0x58, 0xda, 0xe2, 0x44, 0x12, 0xd3, 0xef, 0x27, 0x47,
+	0x88, 0x25, 0x5e, 0x37, 0xf2, 0x34, 0xdf, 0x94, 0xdf, 0xee, 0xc0, 0xbe,
+	0xf4, 0x34, 0x26, 0xfa, 0x3f, 0x33, 0xec, 0x5a, 0x17, 0x3e, 0x0d, 0x4e,
+	0x63, 0xfc, 0x80, 0xd4, 0x50, 0x43, 0xd8, 0x35, 0x18, 0x40, 0x6f, 0xc2,
+	0x86, 0x9d, 0x4b, 0x5a, 0xb1, 0x6b, 0xa2, 0x05, 0x91, 0x43, 0x1e, 0xec,
+	0x4c, 0xa7, 0x31, 0x35, 0x32, 0x8d, 0x93, 0x49, 0x8d, 0xf1, 0xe4, 0x34,
+	0x4e, 0xa4, 0x38, 0x66, 0xe2, 0x3d, 0x44, 0x38, 0xc6, 0xb6, 0xa4, 0xa6,
+	0x0e, 0x9b, 0x7b, 0x9c, 0x46, 0x77, 0xea, 0x56, 0x39, 0x13, 0xae, 0x27,
+	0xd1, 0xd3, 0x6e, 0xd5, 0x45, 0x88, 0xbd, 0x69, 0x4d, 0xe9, 0xe3, 0xf9,
+	0x1d, 0x4e, 0x67, 0x6b, 0x24, 0x37, 0xe7, 0x4a, 0x42, 0xe8, 0x1b, 0x6c,
+	0x65, 0x9f, 0x00, 0xba, 0x13, 0x52, 0x87, 0xf6, 0x71, 0x4e, 0x03, 0xbf,
+	0xd6, 0xbd, 0xee, 0x05, 0xfc, 0x1c, 0xd5, 0x3b, 0xb1, 0x89, 0x63, 0x4d,
+	0x31, 0x46, 0xd2, 0x14, 0x6f, 0x63, 0x04, 0x76, 0xfc, 0x4a, 0x27, 0x1f,
+	0xaa, 0xb0, 0xe3, 0x55, 0xea, 0x5a, 0xb8, 0xd4, 0x8e, 0xfa, 0x20, 0x7d,
+	0x78, 0xc6, 0xa7, 0x7f, 0x92, 0x54, 0xf0, 0x20, 0xf1, 0xf6, 0x8d, 0x60,
+	0x7d, 0xfb, 0x4a, 0x61, 0x7b, 0x07, 0x14, 0x5c, 0xd6, 0xae, 0x1a, 0x11,
+	0xea, 0x87, 0xcb, 0x9f, 0x3d, 0xa3, 0x7f, 0xc9, 0xe4, 0xf0, 0xbe, 0x34,
+	0xb2, 0xfd, 0x66, 0xb8, 0xc6, 0x27, 0xd8, 0x6f, 0xc1, 0xe2, 0xfa, 0x4e,
+	0xe9, 0xe7, 0x26, 0xde, 0x4b, 0xbf, 0x73, 0x95, 0x8e, 0x59, 0xfd, 0x42,
+	0xd8, 0x36, 0xd8, 0x6c, 0xae, 0x77, 0x7b, 0x02, 0x8b, 0x1c, 0x10, 0x5b,
+	0xab, 0x57, 0x2f, 0x02, 0x5d, 0xd3, 0x7a, 0x09, 0x79, 0x90, 0x3f, 0xf0,
+	0x0c, 0x44, 0x56, 0x12, 0x67, 0xbe, 0x87, 0x9d, 0xd1, 0x11, 0x30, 0xd6,
+	0x24, 0x06, 0xfa, 0xd7, 0x0d, 0x23, 0x85, 0xe7, 0xd3, 0x29, 0xbc, 0x40,
+	0x19, 0x45, 0xcc, 0xbb, 0x62, 0x69, 0x7c, 0x3b, 0xfa, 0x1e, 0x62, 0xe6,
+	0x99, 0x1d, 0xc6, 0xfa, 0xa8, 0xbb, 0x0a, 0xf9, 0xd2, 0x77, 0x25, 0xc7,
+	0x17, 0xb9, 0x7a, 0xdb, 0x22, 0xf8, 0x8a, 0xe3, 0xaf, 0x44, 0xcf, 0xb0,
+	0x61, 0xfc, 0x90, 0xbe, 0xed, 0x2d, 0x72, 0xaf, 0xcb, 0x99, 0x7b, 0x67,
+	0x79, 0x94, 0xb7, 0x66, 0xfa, 0xb8, 0xb5, 0x3c, 0xe7, 0x2a, 0xe1, 0xfc,
+	0x28, 0x1a, 0xd3, 0x94, 0x05, 0x31, 0x39, 0x77, 0x72, 0xca, 0x31, 0x0f,
+	0x9e, 0x20, 0x7f, 0xc9, 0x1d, 0xfd, 0x5b, 0x45, 0xfc, 0x5c, 0xf5, 0x01,
+	0xc6, 0x02, 0x07, 0x3c, 0xca, 0xc2, 0x3d, 0x2e, 0x3c, 0x18, 0x73, 0xe0,
+	0xfe, 0x58, 0x0b, 0x7a, 0xf6, 0x6a, 0x6c, 0xe3, 0xd5, 0xcf, 0x30, 0x5e,
+	0x3d, 0x01, 0x9f, 0x67, 0x98, 0x9c, 0xcb, 0x4d, 0x9c, 0x76, 0x8c, 0x16,
+	0xa3, 0x60, 0x54, 0x85, 0x6d, 0xb4, 0x0c, 0x85, 0xa3, 0x6e, 0x54, 0xd3,
+	0xef, 0xb9, 0xc7, 0xce, 0x62, 0x62, 0x8f, 0xe4, 0x53, 0xbf, 0x30, 0x72,
+	0xc9, 0xcb, 0x3e, 0x0d, 0x06, 0x50, 0x3c, 0xb6, 0x05, 0xe9, 0x58, 0x03,
+	0x0a, 0xc7, 0x48, 0xb3, 0xc6, 0x26, 0x95, 0x7a, 0xce, 0xd9, 0x12, 0xd3,
+	0x38, 0x96, 0xc5, 0x83, 0x56, 0xd2, 0x57, 0xf6, 0x25, 0xbc, 0xeb, 0xa4,
+	0x2e, 0x79, 0x59, 0x3f, 0x8e, 0xbc, 0xfe, 0xec, 0xfd, 0x39, 0x78, 0xf3,
+	0x80, 0x92, 0x1e, 0xdd, 0xdf, 0xb6, 0x11, 0xd6, 0x5d, 0xba, 0xfb, 0x33,
+	0x7b, 0x6a, 0x90, 0x3d, 0x39, 0xd7, 0x52, 0x17, 0xe6, 0xa0, 0x84, 0x7b,
+	0x3a, 0x4f, 0xfd, 0xb9, 0x87, 0xeb, 0xbd, 0xca, 0xb8, 0xb1, 0x33, 0x26,
+	0x7a, 0xff, 0xb7, 0x0a, 0xed, 0x06, 0x33, 0xa9, 0x02, 0x7c, 0x96, 0xf2,
+	0x28, 0x3e, 0xee, 0xe7, 0x3b, 0x7c, 0xfe, 0x6d, 0xee, 0x67, 0xeb, 0x5e,
+	0x6f, 0xdb, 0x51, 0xc5, 0xdb, 0xbe, 0x46, 0xf1, 0xa9, 0x5b, 0x95, 0x42,
+	0x9c, 0x1f, 0x29, 0xc6, 0x45, 0xfa, 0xe9, 0xab, 0x23, 0x65, 0xb8, 0x34,
+	0x52, 0x41, 0x5b, 0xd1, 0x38, 0x86, 0x61, 0x14, 0x69, 0x6e, 0xcc, 0xa4,
+	0x5f, 0x40, 0x49, 0x6c, 0x1e, 0x3e, 0x4b, 0x6f, 0x42, 0x71, 0x4c, 0xf8,
+	0xbc, 0x07, 0x9f, 0xf2, 0xf9, 0x27, 0xe9, 0x71, 0xe4, 0xef, 0xf9, 0x82,
+	0x6d, 0x0c, 0xa3, 0x85, 0x7b, 0xbc, 0x94, 0xee, 0x40, 0xe1, 0x9e, 0x97,
+	0xe0, 0xd8, 0x63, 0x74, 0xf5, 0x04, 0xf1, 0x73, 0x3b, 0xf7, 0xd2, 0xad,
+	0x7b, 0xa7, 0x16, 0xd8, 0x1b, 0x38, 0x86, 0xce, 0x31, 0x27, 0x95, 0x85,
+	0x63, 0x2f, 0xa1, 0x78, 0x8f, 0x07, 0x9b, 0x29, 0xcb, 0x71, 0x68, 0x81,
+	0x35, 0xca, 0x4b, 0xc8, 0x19, 0xb5, 0x64, 0xb0, 0x61, 0xcc, 0xb2, 0x91,
+	0x96, 0x90, 0xe4, 0x94, 0x26, 0x95, 0x61, 0xd3, 0x46, 0xdc, 0x72, 0xd7,
+	0x07, 0xd3, 0xe9, 0x02, 0x9c, 0x4a, 0x89, 0x8c, 0xe4, 0xbe, 0xe0, 0x38,
+	0x72, 0xf7, 0x10, 0x3f, 0x47, 0x74, 0x93, 0x5f, 0x88, 0x6d, 0x8c, 0xa4,
+	0x6f, 0x65, 0x5f, 0x3a, 0x76, 0x26, 0xaa, 0x69, 0x5b, 0xf3, 0xb0, 0x6a,
+	0x8f, 0x61, 0x04, 0x82, 0x53, 0xf7, 0xb8, 0xa8, 0x4d, 0x87, 0xd2, 0xb7,
+	0xb2, 0xad, 0x46, 0xea, 0xa9, 0xb7, 0x35, 0x62, 0xe6, 0xbb, 0x0d, 0x4c,
+	0xeb, 0x93, 0x8a, 0x2d, 0x26, 0xb1, 0xd8, 0x5a, 0xda, 0x7c, 0x1b, 0x7a,
+	0x06, 0xd1, 0xbe, 0x3f, 0x24, 0xb5, 0x70, 0x27, 0x86, 0x19, 0x5b, 0x9d,
+	0x67, 0x3c, 0x42, 0x99, 0xab, 0x39, 0x4d, 0x39, 0x18, 0x1a, 0x71, 0xe1,
+	0x27, 0x23, 0x1e, 0x34, 0xc6, 0xbe, 0x20, 0x66, 0xe4, 0x63, 0x92, 0xf2,
+	0x9e, 0x20, 0x37, 0xfa, 0x34, 0xaa, 0x62, 0x9c, 0x7e, 0xf8, 0x93, 0x68,
+	0x05, 0xc6, 0x18, 0x87, 0x7d, 0x1c, 0xd5, 0x90, 0xe6, 0xd9, 0x7c, 0x44,
+	0xbc, 0xf9, 0x61, 0xba, 0x01, 0xbf, 0x89, 0x36, 0xe0, 0x55, 0xca, 0xb1,
+	0x2e, 0xe6, 0xe6, 0x9a, 0x8e, 0x28, 0x38, 0x30, 0xa9, 0xe4, 0x50, 0x2f,
+	0xfc, 0x31, 0xcd, 0x33, 0x9c, 0xd1, 0x0b, 0x6d, 0xac, 0x8d, 0x76, 0x24,
+	0x77, 0x2d, 0xc4, 0x77, 0x38, 0xf4, 0x61, 0x90, 0xef, 0x35, 0x64, 0x73,
+	0x8b, 0x5e, 0xf7, 0x14, 0xaa, 0x68, 0x4b, 0x5f, 0x19, 0xaa, 0x26, 0x79,
+	0xb4, 0x64, 0xf0, 0x72, 0x54, 0x53, 0x2f, 0x99, 0x7b, 0x88, 0x28, 0xce,
+	0x25, 0x92, 0xa3, 0xd8, 0xca, 0xfd, 0x07, 0x88, 0x19, 0x57, 0xcc, 0x73,
+	0x52, 0xb5, 0xe3, 0x68, 0x30, 0xef, 0xa4, 0x31, 0xd6, 0x5b, 0x72, 0x1c,
+	0x77, 0x1e, 0xf8, 0x3f, 0x55, 0x16, 0x57, 0xa2, 0x6d, 0xdb, 0x6e, 0xce,
+	0x83, 0x49, 0x4e, 0x7d, 0x77, 0xf0, 0x78, 0xf4, 0x37, 0x55, 0x52, 0x6b,
+	0x3b, 0x4a, 0xce, 0xb4, 0x3d, 0x71, 0xab, 0x98, 0xc2, 0xc0, 0x3b, 0xc4,
+	0x97, 0x4b, 0x49, 0xe1, 0x55, 0xc2, 0xa7, 0xba, 0xe8, 0xbb, 0x8a, 0xc8,
+	0x27, 0xe8, 0x67, 0xc9, 0xf9, 0x7d, 0xf1, 0x29, 0xc6, 0x34, 0x77, 0x93,
+	0xd3, 0x15, 0x73, 0x98, 0xf7, 0x39, 0x5f, 0x1b, 0x76, 0xd2, 0x4e, 0xf3,
+	0xb4, 0x05, 0x58, 0x45, 0xbe, 0xe4, 0xd0, 0xe8, 0x6e, 0x1e, 0x11, 0x9f,
+	0x03, 0xd4, 0xc6, 0x55, 0x14, 0x36, 0x69, 0xeb, 0xde, 0xc2, 0x3d, 0x68,
+	0xaf, 0x74, 0x41, 0xea, 0x09, 0x6f, 0x63, 0x19, 0x52, 0x8f, 0x89, 0xef,
+	0xb5, 0x49, 0x7d, 0x2c, 0x72, 0x16, 0x35, 0x26, 0x73, 0xcf, 0x6f, 0x92,
+	0xf5, 0x54, 0xf0, 0x2c, 0x54, 0x5c, 0xa0, 0x8c, 0x2f, 0x46, 0x7d, 0x33,
+	0x2b, 0x50, 0x7f, 0xf2, 0xa2, 0x9d, 0xbc, 0xb0, 0x5c, 0xda, 0x37, 0x40,
+	0xe3, 0x78, 0x9f, 0x47, 0x83, 0xe8, 0x57, 0xe5, 0xbb, 0xf0, 0xcb, 0x36,
+	0x74, 0x0f, 0xcb, 0x1a, 0x0c, 0xa3, 0x8c, 0x58, 0xf9, 0x88, 0x39, 0xbf,
+	0xcc, 0x7d, 0x73, 0x7c, 0x92, 0xf5, 0x7f, 0x12, 0xa3, 0x4c, 0xe3, 0x70,
+	0xd2, 0x03, 0xc7, 0x92, 0xaa, 0x39, 0xc8, 0x9f, 0xc6, 0x48, 0x4a, 0x23,
+	0xf7, 0x2c, 0x80, 0xa7, 0x52, 0xc7, 0x2e, 0xfa, 0xfc, 0x18, 0xdb, 0xa7,
+	0x63, 0x05, 0x88, 0x54, 0x5a, 0x73, 0xde, 0x1d, 0xff, 0xd8, 0x98, 0x7a,
+	0xd8, 0xf4, 0xa1, 0xfc, 0x1e, 0x64, 0x9f, 0x39, 0x72, 0xed, 0x14, 0xcf,
+	0xc6, 0x2e, 0x19, 0x53, 0x6d, 0xb3, 0x7f, 0x2f, 0x35, 0xef, 0x6e, 0x85,
+	0x6d, 0x95, 0xfc, 0xb4, 0xe4, 0xd2, 0x4d, 0xb9, 0x94, 0x68, 0xef, 0x19,
+	0x0f, 0x59, 0x72, 0x99, 0x23, 0xf1, 0x40, 0x6d, 0xfc, 0xf1, 0x39, 0x92,
+	0x6f, 0x15, 0x7f, 0xe6, 0x6a, 0xd2, 0x1a, 0x4f, 0xe2, 0x17, 0xc6, 0xb9,
+	0x1b, 0xc6, 0x29, 0xe7, 0x33, 0xf1, 0x4d, 0xe7, 0x32, 0xf7, 0x00, 0xdc,
+	0x99, 0x98, 0x61, 0x1a, 0x47, 0x93, 0xe2, 0x17, 0x3c, 0x58, 0x2f, 0xf9,
+	0x2a, 0xd5, 0xdb, 0x17, 0xc1, 0x14, 0x39, 0xe2, 0x07, 0x94, 0xbd, 0x22,
+	0xf5, 0x3a, 0xf2, 0xc4, 0xd9, 0xbe, 0x2b, 0x8c, 0x94, 0x59, 0x8f, 0x12,
+	0x6c, 0x9d, 0xc6, 0xf6, 0xa4, 0xd4, 0x4d, 0x3f, 0x23, 0x6f, 0xea, 0x22,
+	0x27, 0x9f, 0x46, 0x4f, 0xaa, 0x05, 0xaf, 0xec, 0x6d, 0x25, 0xde, 0x08,
+	0x6e, 0xfa, 0x4e, 0x9e, 0xb7, 0xb7, 0x60, 0xff, 0xa1, 0x34, 0x52, 0xa3,
+	0xe2, 0x2f, 0xe5, 0x1e, 0x9c, 0xf8, 0xca, 0x00, 0xa2, 0x89, 0x13, 0x88,
+	0xf0, 0x73, 0x67, 0xe2, 0x25, 0x84, 0x47, 0xdf, 0x63, 0x2c, 0x30, 0x8d,
+	0x95, 0xd4, 0xb9, 0x83, 0x98, 0xc6, 0xea, 0x03, 0x1a, 0x92, 0x89, 0x56,
+	0x8e, 0xdf, 0x82, 0xde, 0xbd, 0xde, 0x80, 0xc3, 0x56, 0x42, 0x7f, 0xa5,
+	0x61, 0xdb, 0x44, 0x33, 0x22, 0xc3, 0x56, 0x5d, 0xac, 0x21, 0xee, 0x51,
+	0x3e, 0x21, 0x9f, 0xae, 0x8f, 0x7b, 0x19, 0xc7, 0x79, 0x23, 0xab, 0x15,
+	0x9f, 0x27, 0xc7, 0x66, 0x18, 0xbd, 0xf4, 0x1b, 0x27, 0x75, 0x05, 0x79,
+	0xf7, 0x28, 0x08, 0xd2, 0x8f, 0x79, 0xaa, 0xe8, 0x5f, 0x86, 0x43, 0xe8,
+	0x1d, 0x9c, 0x5d, 0x53, 0x94, 0xf3, 0x7a, 0x80, 0xe3, 0xc9, 0xd9, 0xb5,
+	0xa2, 0x77, 0xc2, 0xd7, 0x71, 0xd2, 0xac, 0x39, 0x4a, 0xbb, 0x6c, 0x1b,
+	0x14, 0x7e, 0x16, 0xf2, 0x06, 0x4a, 0x14, 0x69, 0xbb, 0x95, 0x58, 0x36,
+	0xbb, 0x7d, 0x44, 0x49, 0x2e, 0x21, 0x7f, 0xb5, 0x89, 0x5d, 0x74, 0x9b,
+	0xb6, 0x23, 0xb2, 0xe8, 0x4d, 0x86, 0xa9, 0xd3, 0x3f, 0x35, 0x52, 0x6d,
+	0x6d, 0x5c, 0x67, 0xa3, 0xd4, 0x9c, 0x4c, 0x9e, 0x72, 0x5a, 0xf2, 0x73,
+	0x4e, 0xf1, 0xe3, 0xdd, 0xed, 0x2e, 0xea, 0x53, 0x2e, 0xb1, 0x2a, 0x6f,
+	0xdc, 0x05, 0xd7, 0xc1, 0x02, 0xe4, 0x0e, 0x09, 0x9f, 0x83, 0x5a, 0xdc,
+	0xa4, 0xc2, 0x3e, 0x5e, 0x48, 0x1b, 0xe0, 0x19, 0x8e, 0xd3, 0xc6, 0xa2,
+	0x6e, 0xd4, 0x8c, 0xbb, 0xf1, 0x13, 0xe2, 0x41, 0xf5, 0xb8, 0x86, 0x49,
+	0xe2, 0x81, 0x7b, 0x3c, 0x80, 0x09, 0xe2, 0x41, 0x49, 0x26, 0x47, 0xf2,
+	0x76, 0xfa, 0x65, 0x9e, 0xab, 0xcc, 0x25, 0x72, 0xcc, 0x9e, 0xab, 0x9c,
+	0x69, 0x2b, 0x31, 0x50, 0xce, 0xb7, 0x01, 0x3b, 0x06, 0xd3, 0x58, 0xbe,
+	0xc7, 0xc0, 0xbb, 0x7a, 0xbd, 0x3b, 0x4f, 0x91, 0x78, 0xc2, 0x40, 0x5a,
+	0x97, 0x3b, 0xab, 0xde, 0x75, 0x72, 0xaf, 0xbb, 0xbd, 0xc2, 0x40, 0x4e,
+	0xd0, 0xab, 0x13, 0xf9, 0xd7, 0xe5, 0x29, 0xe2, 0xc3, 0xea, 0x3d, 0x9b,
+	0x30, 0x57, 0x6a, 0x8e, 0xfc, 0xb7, 0x02, 0x9b, 0xc8, 0x1b, 0xf3, 0xb5,
+	0x56, 0xec, 0x2c, 0x8d, 0xb8, 0x2e, 0x87, 0x0c, 0x63, 0x43, 0xf0, 0xf1,
+	0x2a, 0x93, 0x03, 0xda, 0xf6, 0xf1, 0x73, 0x2d, 0xf7, 0x2d, 0x7b, 0xef,
+	0x40, 0x6c, 0xb7, 0x82, 0xb4, 0xbf, 0x03, 0xd1, 0x91, 0x0e, 0xec, 0xda,
+	0x2d, 0x98, 0xd0, 0x47, 0x4c, 0x30, 0xba, 0x36, 0x06, 0x1f, 0xc2, 0x25,
+	0x93, 0x11, 0x48, 0x1f, 0x6f, 0xc0, 0x63, 0x9b, 0x7d, 0x0e, 0x1b, 0xb9,
+	0x7e, 0xcb, 0x76, 0x9a, 0xfb, 0x85, 0x7b, 0xfb, 0xfb, 0x7a, 0x79, 0xfe,
+	0x0f, 0x1f, 0x10, 0xdf, 0x63, 0x18, 0x7d, 0xfa, 0x3c, 0xa0, 0x54, 0xf6,
+	0x10, 0x40, 0x3c, 0x61, 0x7c, 0x56, 0xad, 0xf9, 0x66, 0x76, 0xd1, 0xcf,
+	0x9f, 0xdd, 0x53, 0xbf, 0x69, 0x93, 0x70, 0x9a, 0xc5, 0xc2, 0xf3, 0xd2,
+	0x38, 0x33, 0x7a, 0x27, 0x52, 0x0f, 0x73, 0x3f, 0x3c, 0x2b, 0x67, 0xfc,
+	0x4b, 0x43, 0x78, 0x9d, 0x5d, 0x93, 0x9a, 0x2d, 0xa7, 0x1c, 0xf7, 0xa3,
+	0xa7, 0x14, 0x91, 0xcb, 0x21, 0x99, 0xff, 0xda, 0xfa, 0xb9, 0xdf, 0x16,
+	0xec, 0xda, 0x2b, 0xbc, 0x43, 0x38, 0x9a, 0x2f, 0xf2, 0x11, 0x5a, 0x91,
+	0x9c, 0xb0, 0xe6, 0x8a, 0x26, 0x6e, 0xd6, 0x15, 0x39, 0xf7, 0x13, 0xd8,
+	0x41, 0x8e, 0xe7, 0xe2, 0xf8, 0xf4, 0x35, 0x1c, 0x4f, 0x0b, 0xe4, 0xc9,
+	0x7c, 0xe3, 0x3f, 0x35, 0x76, 0x56, 0x8a, 0x6c, 0x64, 0x7c, 0xcd, 0xc4,
+	0x8c, 0x0d, 0xc1, 0x3f, 0xb7, 0xd7, 0x1a, 0x37, 0xf2, 0xbd, 0xad, 0x96,
+	0x3c, 0xa4, 0xad, 0xf6, 0x27, 0xd6, 0xb3, 0x90, 0xed, 0x64, 0x4d, 0x1d,
+	0xd8, 0xb1, 0x1b, 0x91, 0x7c, 0x4d, 0x6a, 0x0d, 0x1d, 0xe8, 0xa3, 0x7c,
+	0xb7, 0x25, 0x3b, 0xb0, 0x9f, 0x36, 0x3b, 0xa4, 0xbf, 0x51, 0x6d, 0x43,
+	0xdd, 0x8c, 0x1d, 0x53, 0x3f, 0xab, 0x21, 0x9e, 0x2e, 0x5c, 0xec, 0xa7,
+	0x7d, 0x75, 0x20, 0x9e, 0xca, 0x75, 0x9b, 0x35, 0x40, 0x9b, 0xf8, 0x42,
+	0x91, 0x45, 0x27, 0xf2, 0xfb, 0x4f, 0xc0, 0xd9, 0xdf, 0x89, 0x3c, 0xff,
+	0x32, 0xdc, 0x1f, 0x3c, 0x67, 0x5c, 0xd2, 0x1c, 0xee, 0xa3, 0x94, 0xcf,
+	0x1b, 0x0d, 0xd5, 0x8c, 0x3b, 0x1b, 0xb0, 0x6d, 0xf8, 0x36, 0xda, 0x7e,
+	0x23, 0xb9, 0x2f, 0xe7, 0x6a, 0xb2, 0x61, 0xf5, 0x12, 0x89, 0xe9, 0xa5,
+	0x3e, 0x5d, 0x25, 0xf7, 0x10, 0xd4, 0xe7, 0x21, 0xf1, 0x1a, 0x39, 0x59,
+	0x85, 0x07, 0x4f, 0xd3, 0xc6, 0xda, 0x55, 0x79, 0xbe, 0x85, 0x71, 0xc4,
+	0x16, 0x54, 0xc7, 0x22, 0x86, 0xc8, 0xfb, 0x28, 0xc2, 0xdf, 0x93, 0x9a,
+	0x4a, 0xe3, 0x62, 0xff, 0xa6, 0x19, 0x45, 0x74, 0xda, 0xdf, 0x3e, 0xae,
+	0xe8, 0xae, 0x07, 0xc6, 0x14, 0x04, 0xfa, 0x39, 0x56, 0xf0, 0xfd, 0x39,
+	0x56, 0x1e, 0x2d, 0xcb, 0xff, 0xb6, 0x90, 0x33, 0x6c, 0x41, 0x11, 0xfb,
+	0xbb, 0x35, 0xc1, 0x86, 0xf0, 0x7d, 0xc5, 0xec, 0x9f, 0x0e, 0xfa, 0xdb,
+	0x0a, 0x15, 0xe1, 0x46, 0xfe, 0xc6, 0xd5, 0x8a, 0xf0, 0x18, 0xe9, 0xa7,
+	0xbb, 0xea, 0xc6, 0xce, 0x66, 0x6a, 0x66, 0x8d, 0xc4, 0x07, 0x8f, 0x79,
+	0x07, 0xd5, 0xba, 0xaf, 0x95, 0xbd, 0xb3, 0xa4, 0xf2, 0xfc, 0x25, 0xc6,
+	0x38, 0x12, 0x5c, 0x1e, 0x6d, 0x92, 0xfb, 0x21, 0xcb, 0x0e, 0x51, 0xef,
+	0xcf, 0xa3, 0x02, 0xff, 0x10, 0x15, 0x5c, 0xf3, 0xe0, 0x1f, 0xa3, 0xb9,
+	0x12, 0x57, 0xa7, 0x24, 0x6f, 0xf9, 0x66, 0x32, 0x62, 0x50, 0xae, 0xad,
+	0xab, 0xa9, 0x4b, 0x81, 0x60, 0x21, 0x50, 0xd9, 0xfd, 0xb4, 0xd3, 0x8c,
+	0xf3, 0x8b, 0x50, 0x4a, 0x1f, 0xd0, 0x3f, 0xfc, 0xa7, 0x72, 0xb4, 0xef,
+	0x9b, 0xdc, 0xf2, 0xef, 0xea, 0xec, 0xd8, 0x16, 0xfc, 0x57, 0x23, 0x95,
+	0xb9, 0x33, 0x7c, 0x66, 0xb7, 0xe8, 0x69, 0x00, 0xb9, 0xf1, 0xb3, 0xd4,
+	0x49, 0x15, 0xa7, 0xa3, 0x3e, 0x7d, 0x8d, 0xed, 0x49, 0xea, 0x7f, 0xcd,
+	0x0d, 0xd8, 0x5d, 0xa3, 0x3d, 0x88, 0xa7, 0x4c, 0xec, 0x0e, 0xa3, 0x87,
+	0xbe, 0x81, 0x9c, 0x6e, 0xdf, 0xd3, 0x36, 0x15, 0x79, 0x31, 0x9f, 0xea,
+	0xa3, 0x4e, 0xf5, 0x70, 0x0e, 0xe1, 0x9b, 0xe5, 0xe4, 0x83, 0x1b, 0xa3,
+	0xf5, 0x9e, 0x7f, 0xc1, 0x7a, 0xda, 0xa3, 0xcc, 0x21, 0x7b, 0xd2, 0x50,
+	0x18, 0xd7, 0x70, 0x8c, 0xfb, 0xd8, 0x56, 0x6a, 0xcd, 0x5b, 0x9c, 0x19,
+	0x3b, 0x3e, 0x2c, 0x5c, 0x6c, 0x29, 0xd6, 0x98, 0x63, 0xeb, 0xb4, 0x4b,
+	0x0d, 0xfb, 0xe4, 0x6e, 0x7f, 0x9d, 0x86, 0x44, 0xba, 0x19, 0x2f, 0x95,
+	0x79, 0xb0, 0x3f, 0xb1, 0x05, 0x8b, 0x12, 0xf7, 0xe1, 0xd1, 0xb2, 0x88,
+	0xdc, 0x85, 0x41, 0x5e, 0x5c, 0x53, 0xef, 0x54, 0xee, 0xcd, 0xd4, 0x29,
+	0x2a, 0xe0, 0x88, 0x8b, 0xcf, 0xcb, 0xc1, 0x80, 0x3a, 0x17, 0x05, 0xe6,
+	0x9d, 0x4a, 0x6b, 0xec, 0x5d, 0xc3, 0xde, 0x8c, 0x1f, 0x24, 0x6a, 0xc4,
+	0x15, 0xf1, 0xbf, 0x81, 0x17, 0x50, 0xce, 0x38, 0x21, 0x82, 0x9c, 0x26,
+	0x2d, 0xf5, 0x2c, 0xf2, 0x10, 0xa9, 0x12, 0x4c, 0x94, 0x3e, 0xb7, 0xdd,
+	0xb4, 0xa6, 0xb2, 0xcc, 0x9a, 0xb2, 0xcf, 0x31, 0x07, 0xc5, 0xa2, 0x5b,
+	0xc2, 0x35, 0xe4, 0xf7, 0x7c, 0xb4, 0x51, 0x9f, 0x2a, 0xb8, 0xe6, 0x84,
+	0x79, 0x5f, 0xd6, 0xab, 0x47, 0x6c, 0x21, 0xfc, 0x76, 0x8f, 0xa5, 0x83,
+	0xeb, 0x6a, 0x79, 0xfe, 0xc5, 0x21, 0xcc, 0x8c, 0x8a, 0x3f, 0xfb, 0x53,
+	0x67, 0x92, 0xf5, 0xc5, 0x72, 0x2e, 0x22, 0x57, 0xef, 0xc9, 0x0b, 0xa8,
+	0x9f, 0x7a, 0xc2, 0x76, 0xd8, 0x40, 0xb9, 0xc8, 0xf8, 0xb8, 0x5b, 0x62,
+	0x58, 0x1b, 0x79, 0x44, 0x24, 0x7d, 0xc5, 0x2d, 0xbe, 0xd2, 0x11, 0x07,
+	0x6a, 0xe2, 0x11, 0xe4, 0x36, 0x69, 0xfb, 0x2e, 0xdb, 0xaf, 0x1a, 0xed,
+	0x55, 0xb7, 0x31, 0x26, 0xbc, 0xbe, 0xe7, 0x3e, 0xae, 0xdd, 0xae, 0xfd,
+	0xd4, 0x58, 0x51, 0x21, 0x6b, 0xac, 0xae, 0xb6, 0xf2, 0xd1, 0xf3, 0x29,
+	0x97, 0xac, 0x4c, 0x0c, 0xea, 0xcf, 0xff, 0x32, 0xbe, 0x71, 0xc3, 0x73,
+	0xe1, 0x33, 0xa2, 0xa7, 0xb3, 0xef, 0x14, 0x8a, 0xce, 0x7a, 0xa8, 0xa7,
+	0xd3, 0x38, 0x94, 0x6c, 0x44, 0x7f, 0x42, 0x64, 0x1c, 0xc6, 0x79, 0x72,
+	0xc5, 0xda, 0x81, 0x69, 0x0c, 0x91, 0x2b, 0xfa, 0xe2, 0xde, 0x7d, 0x94,
+	0x24, 0x5e, 0x52, 0x97, 0x99, 0x3c, 0xc9, 0xa5, 0x65, 0xd7, 0x70, 0xb7,
+	0x29, 0x77, 0xf1, 0x31, 0x3b, 0xb9, 0xdf, 0x3b, 0xc8, 0x93, 0x9a, 0x63,
+	0xb9, 0xd0, 0x4a, 0x8b, 0x51, 0xa8, 0x49, 0x5d, 0xc3, 0x6a, 0x17, 0xe5,
+	0x5a, 0x0a, 0x34, 0x1f, 0x56, 0x9b, 0x6d, 0x3d, 0xe6, 0xfd, 0x09, 0x47,
+	0x99, 0xf8, 0x60, 0xf1, 0xbb, 0xe4, 0xe2, 0x4b, 0xc4, 0xef, 0x86, 0xb9,
+	0xb6, 0x05, 0x3c, 0xb3, 0x45, 0x70, 0xdf, 0xeb, 0x41, 0xf5, 0xbd, 0xf4,
+	0x91, 0x0b, 0x15, 0x94, 0x2d, 0xf4, 0x47, 0x16, 0xd9, 0x9a, 0x81, 0xaa,
+	0x00, 0xf1, 0x47, 0x33, 0x7a, 0x12, 0x7f, 0xe0, 0x18, 0x1d, 0x30, 0x76,
+	0xe7, 0x63, 0xfd, 0xee, 0x12, 0xea, 0xaa, 0x47, 0xf2, 0xf0, 0x2e, 0x57,
+	0x53, 0x34, 0xe8, 0x8a, 0xd5, 0xeb, 0x4e, 0x65, 0x01, 0xfd, 0xb1, 0x9c,
+	0x9f, 0xcc, 0x7f, 0xd7, 0x0d, 0x7c, 0xa9, 0x9c, 0xfe, 0xed, 0x51, 0x73,
+	0x0d, 0x92, 0x2b, 0x96, 0x7e, 0x7f, 0x7c, 0x4e, 0x53, 0xd7, 0xce, 0xe9,
+	0x4e, 0x38, 0x1e, 0xa9, 0x20, 0xff, 0xba, 0xb5, 0x0f, 0xc9, 0xa3, 0x0f,
+	0xb9, 0x23, 0x66, 0x74, 0x6d, 0x0e, 0x16, 0x48, 0xfe, 0xc8, 0xf4, 0x21,
+	0xed, 0xb6, 0x8d, 0xa6, 0xee, 0x38, 0xb5, 0x1e, 0xca, 0xdb, 0xca, 0x47,
+	0x53, 0x06, 0x73, 0xac, 0xbb, 0xb9, 0xd9, 0xdf, 0x3a, 0xb0, 0x9d, 0x98,
+	0x29, 0x77, 0xea, 0x9d, 0x9a, 0x46, 0xfb, 0xef, 0x40, 0x0f, 0xc7, 0x7c,
+	0x85, 0xb8, 0xd9, 0x4f, 0xdc, 0xbc, 0xba, 0xf8, 0x8d, 0x9f, 0x55, 0xa3,
+	0x2e, 0xe9, 0xc6, 0xd4, 0x5f, 0x97, 0x09, 0x6e, 0x2e, 0xf2, 0x77, 0x5c,
+	0x31, 0x71, 0x53, 0xc6, 0x96, 0xf1, 0x66, 0x8f, 0xfd, 0x3f, 0xf8, 0xdf,
+	0xf9, 0x92, 0x73, 0x34, 0x9c, 0xda, 0xff, 0x35, 0xb6, 0x55, 0xc8, 0x5a,
+	0x6f, 0xb5, 0x0e, 0xc1, 0xda, 0xd9, 0x35, 0xfd, 0x69, 0x62, 0xae, 0x19,
+	0x2f, 0xd0, 0xe7, 0x86, 0xb1, 0x6a, 0x89, 0x8a, 0x4b, 0xd1, 0x69, 0xe4,
+	0x1d, 0xc8, 0xe2, 0x93, 0xb1, 0xec, 0x18, 0xb1, 0x69, 0x08, 0x82, 0x47,
+	0x4d, 0x3c, 0x97, 0x08, 0xed, 0xa4, 0x08, 0xe3, 0x49, 0xb9, 0x47, 0x64,
+	0x60, 0x57, 0xd0, 0x45, 0x6e, 0xdb, 0x7d, 0x34, 0xc7, 0xf4, 0x13, 0x45,
+	0x54, 0xad, 0x2c, 0xef, 0x16, 0xce, 0x2d, 0xf8, 0x23, 0xfc, 0xd8, 0x8e,
+	0x92, 0xc5, 0x92, 0x17, 0xf8, 0xc2, 0xb8, 0xf4, 0x98, 0xb4, 0x9b, 0x87,
+	0xa1, 0xdd, 0xa2, 0x7f, 0x3e, 0x54, 0x6b, 0x67, 0x19, 0x73, 0x80, 0x73,
+	0xda, 0x6e, 0xcf, 0x21, 0x37, 0xee, 0xd2, 0x97, 0xe0, 0x6a, 0x79, 0x0f,
+	0x0a, 0x9a, 0xdc, 0xf8, 0x30, 0x3a, 0x85, 0x43, 0xc4, 0x8f, 0x5c, 0xea,
+	0x50, 0x5e, 0x46, 0xcf, 0x76, 0x0c, 0xcb, 0xfe, 0xaa, 0xb1, 0xd2, 0xb4,
+	0x53, 0x19, 0x63, 0x1a, 0xaf, 0x92, 0xcf, 0x36, 0x2f, 0x11, 0x2e, 0xab,
+	0x63, 0x5f, 0xa2, 0x08, 0x35, 0x83, 0x5d, 0x94, 0x5d, 0x11, 0xaa, 0x87,
+	0xc5, 0xbe, 0xe6, 0x0b, 0x8e, 0xca, 0x05, 0x39, 0xca, 0x43, 0xc5, 0xf6,
+	0x68, 0xbd, 0x7a, 0x81, 0x41, 0x42, 0xf8, 0x9a, 0xaf, 0x77, 0xd3, 0xef,
+	0x30, 0x26, 0xca, 0xe8, 0x85, 0x4a, 0xbd, 0x68, 0xbb, 0xc6, 0xa3, 0xb3,
+	0x7b, 0x99, 0x9d, 0x3f, 0x52, 0xb1, 0x23, 0x6a, 0x62, 0x21, 0xfb, 0xfa,
+	0x02, 0x3e, 0x85, 0x58, 0x3e, 0x26, 0x3a, 0xf6, 0x7e, 0x46, 0xce, 0x79,
+	0xb7, 0x59, 0xf7, 0x5a, 0x36, 0xde, 0xf4, 0x5d, 0x6b, 0x7f, 0x13, 0x67,
+	0x8d, 0x5d, 0x8f, 0xc9, 0x1a, 0x8f, 0xe3, 0x60, 0xf2, 0x8a, 0xdc, 0x9b,
+	0xef, 0x38, 0x03, 0x1b, 0x4e, 0x33, 0x76, 0x19, 0x4b, 0xfd, 0xae, 0x5a,
+	0xde, 0x45, 0xd9, 0x97, 0x98, 0xed, 0x3b, 0xc4, 0x2e, 0x3d, 0x19, 0xbf,
+	0x61, 0xd9, 0x67, 0x69, 0x5c, 0xee, 0xaf, 0x1c, 0x09, 0x3e, 0xcd, 0x73,
+	0xf1, 0x2f, 0xaa, 0x37, 0x73, 0x32, 0xe4, 0xc2, 0x8c, 0x53, 0x04, 0x73,
+	0x23, 0xf4, 0xf9, 0x45, 0xf8, 0x79, 0x52, 0x7c, 0xb0, 0x81, 0x5c, 0xea,
+	0xe3, 0xb9, 0x8a, 0xee, 0xe7, 0x4b, 0x4d, 0x6e, 0x5d, 0x84, 0x32, 0xee,
+	0x73, 0x60, 0xf8, 0x56, 0xba, 0x7e, 0xdd, 0x4f, 0xa4, 0x83, 0x0a, 0x71,
+	0xe3, 0x5f, 0xb9, 0x4e, 0xab, 0xcf, 0x99, 0xa4, 0x0b, 0x9f, 0x06, 0xdb,
+	0x31, 0x55, 0x1a, 0xc6, 0x60, 0x22, 0x0f, 0xed, 0x55, 0x75, 0xe6, 0xbb,
+	0x1d, 0xd5, 0x71, 0x0f, 0xce, 0x46, 0x9d, 0x68, 0x9c, 0xe3, 0x31, 0x73,
+	0x83, 0x36, 0x62, 0xfd, 0x07, 0xd1, 0xb0, 0x69, 0x83, 0xb3, 0x7d, 0x48,
+	0x8e, 0xb6, 0x18, 0x2d, 0x19, 0x9c, 0xdf, 0x9f, 0xf8, 0x82, 0x38, 0x54,
+	0x1c, 0x29, 0x6f, 0x2a, 0xc2, 0x1d, 0x83, 0x72, 0xc7, 0x41, 0xee, 0x64,
+	0x68, 0x33, 0x77, 0x2a, 0x45, 0x58, 0x36, 0x2c, 0x98, 0x2f, 0xb6, 0x9b,
+	0xa6, 0xed, 0xae, 0xe5, 0xb9, 0x75, 0x42, 0xde, 0xd9, 0x78, 0x85, 0xb2,
+	0xb7, 0x2b, 0x46, 0xd7, 0x45, 0x3d, 0x2c, 0xf7, 0x3c, 0x3b, 0x5b, 0x68,
+	0x07, 0x33, 0x41, 0x6f, 0x7b, 0xb9, 0x5d, 0xeb, 0xf8, 0x95, 0xd2, 0x80,
+	0xf1, 0x31, 0xa0, 0x7f, 0x34, 0x80, 0x8f, 0x12, 0x12, 0x03, 0x04, 0xf0,
+	0x1b, 0x72, 0xa3, 0x0b, 0x89, 0x06, 0xfa, 0x0b, 0x6f, 0xf8, 0x39, 0x34,
+	0xe0, 0x43, 0x7e, 0xcf, 0x8d, 0xeb, 0xb8, 0x4c, 0xf9, 0x39, 0xe3, 0x21,
+	0x5c, 0x9c, 0xb8, 0x17, 0x97, 0xf6, 0x2a, 0x78, 0x43, 0xbb, 0x17, 0xe7,
+	0x0f, 0x75, 0x62, 0xf1, 0x5e, 0x79, 0xef, 0xef, 0x48, 0x50, 0xa5, 0xaf,
+	0x78, 0xba, 0xd6, 0xe8, 0x7a, 0x51, 0xaf, 0x83, 0x5e, 0xe6, 0xd5, 0xdb,
+	0x89, 0x09, 0x82, 0xf1, 0x61, 0x9b, 0x9c, 0xa1, 0x9c, 0x65, 0x27, 0x2e,
+	0x99, 0xb8, 0x7e, 0x6b, 0xac, 0xb8, 0x8e, 0xe9, 0x32, 0x8f, 0xe0, 0xcb,
+	0x7c, 0xfc, 0x48, 0x0d, 0x70, 0x1f, 0x6e, 0x72, 0xb1, 0x29, 0xfa, 0xc7,
+	0x3c, 0xe4, 0x56, 0x4a, 0xcd, 0x5a, 0x43, 0x3e, 0x71, 0xe4, 0x14, 0x65,
+	0xb7, 0xaa, 0xd2, 0x6b, 0xc6, 0x3a, 0xb9, 0xf1, 0x06, 0xc6, 0x31, 0xe5,
+	0xf8, 0xe8, 0x06, 0xff, 0xfb, 0x23, 0xe3, 0x51, 0x13, 0xaf, 0x13, 0xb7,
+	0x09, 0x1f, 0x7b, 0x3d, 0xf1, 0xf8, 0x6d, 0x82, 0xdb, 0x92, 0x5f, 0x2c,
+	0xd6, 0xb4, 0x4d, 0xdf, 0x81, 0xbc, 0xff, 0xf6, 0xc6, 0x7f, 0x2b, 0x24,
+	0x4f, 0x7e, 0x31, 0x58, 0x17, 0x29, 0x45, 0x1f, 0x9f, 0x4f, 0x2d, 0x56,
+	0x71, 0x90, 0x9f, 0x7e, 0xb6, 0x6b, 0xe0, 0x3a, 0x3e, 0x36, 0x52, 0xaa,
+	0xcf, 0xf4, 0x25, 0x71, 0xfa, 0xd3, 0xd3, 0xb1, 0xfa, 0xf6, 0x51, 0xe5,
+	0xb2, 0x11, 0xa9, 0xac, 0xe5, 0x6f, 0x15, 0x38, 0x13, 0xf5, 0x4e, 0x1d,
+	0x42, 0xbd, 0x67, 0x46, 0xd9, 0x6f, 0x44, 0x54, 0x39, 0x1f, 0xd9, 0xaf,
+	0xf4, 0x5f, 0xc0, 0xe7, 0xe7, 0x66, 0xe9, 0xe1, 0xf5, 0x38, 0xcc, 0x79,
+	0x4d, 0xff, 0x84, 0xa7, 0x18, 0xcb, 0x46, 0xf4, 0x7a, 0xb5, 0x87, 0xd8,
+	0x10, 0x56, 0x6f, 0xa5, 0x7f, 0x79, 0xd4, 0xbf, 0x30, 0xe3, 0xca, 0x22,
+	0xa8, 0xd6, 0x7b, 0x3d, 0x48, 0x0e, 0xcf, 0xe6, 0x9a, 0xa2, 0x77, 0x16,
+	0x6f, 0x6d, 0x2f, 0xed, 0x3e, 0xea, 0x24, 0x36, 0x25, 0x88, 0xeb, 0x71,
+	0xe2, 0x7a, 0x2e, 0x71, 0xfd, 0xe3, 0x3d, 0xf9, 0x38, 0xbd, 0xa7, 0x11,
+	0xe9, 0x52, 0xe9, 0x63, 0x87, 0x93, 0xbb, 0x4b, 0x65, 0xee, 0x39, 0x54,
+	0x0f, 0xdc, 0x27, 0x77, 0x1e, 0x21, 0x7e, 0x36, 0x27, 0xce, 0xb8, 0xab,
+	0xcd, 0x0e, 0x87, 0xf9, 0x4e, 0x43, 0xc9, 0x0d, 0xfa, 0xe7, 0xd2, 0x72,
+	0xd1, 0x4a, 0x39, 0xe6, 0x6a, 0xbe, 0xb9, 0xd6, 0xdd, 0xbe, 0x22, 0xc6,
+	0x91, 0x72, 0x5f, 0x71, 0xa9, 0xd4, 0x03, 0xd9, 0x5e, 0xfa, 0x49, 0xac,
+	0x63, 0x60, 0x07, 0x35, 0xac, 0xae, 0xd2, 0x40, 0x42, 0x0f, 0xd3, 0x87,
+	0x05, 0x11, 0x26, 0xa7, 0x2f, 0xd4, 0xe4, 0xbb, 0x8a, 0x8b, 0x8c, 0xd3,
+	0xc6, 0x1a, 0x14, 0x7c, 0x7a, 0x97, 0x70, 0x03, 0xbf, 0x7e, 0x5a, 0xc1,
+	0x1c, 0xeb, 0x5d, 0x0a, 0xc1, 0x8c, 0x62, 0x13, 0x33, 0x72, 0x4d, 0x9e,
+	0x34, 0xc7, 0xc4, 0x1b, 0x79, 0x57, 0xac, 0x9a, 0x7e, 0xe8, 0x9e, 0x44,
+	0xfd, 0x94, 0xcf, 0x4e, 0xce, 0xf6, 0xf8, 0x5d, 0xe4, 0x6a, 0x26, 0x67,
+	0x20, 0xfe, 0xbf, 0x9f, 0xe1, 0x15, 0xde, 0xc6, 0x9b, 0xef, 0x90, 0x9e,
+	0xbb, 0x16, 0xa7, 0x5b, 0x7b, 0xe8, 0x1f, 0xfe, 0x9d, 0xd1, 0x76, 0xc3,
+	0xfa, 0xb3, 0xb8, 0xb2, 0x80, 0xdf, 0xa5, 0xbf, 0xd8, 0x1d, 0xf5, 0x22,
+	0xfe, 0x33, 0xe3, 0x29, 0x93, 0xdf, 0xd9, 0xe7, 0xca, 0x1d, 0x51, 0xc7,
+	0xc0, 0x17, 0xb7, 0xc9, 0xfb, 0x13, 0xb6, 0x59, 0x3c, 0xc1, 0xf2, 0xbd,
+	0x17, 0x8c, 0xd5, 0xe6, 0x5a, 0xf3, 0x33, 0xed, 0x24, 0xa6, 0x96, 0xb5,
+	0x28, 0xf8, 0x81, 0x56, 0xaf, 0x9e, 0x42, 0xa1, 0xe0, 0x49, 0x58, 0x6a,
+	0x9f, 0xf9, 0x9a, 0xcf, 0x7d, 0x90, 0x9f, 0xbb, 0xf8, 0xfc, 0xb8, 0xe6,
+	0x68, 0xdc, 0x0c, 0xa9, 0xf7, 0xda, 0x78, 0x56, 0xf5, 0xee, 0x53, 0xf0,
+	0x87, 0x73, 0x95, 0x19, 0xa3, 0xbd, 0x42, 0xda, 0x58, 0x75, 0x5f, 0x28,
+	0x67, 0xcd, 0x7c, 0x8a, 0xa5, 0x33, 0xf3, 0xa8, 0x33, 0x82, 0x5d, 0xc2,
+	0x4d, 0x16, 0x72, 0xef, 0x2a, 0x86, 0x27, 0x80, 0x9c, 0x01, 0x97, 0xc9,
+	0x95, 0xd4, 0xda, 0x5a, 0xcf, 0xb3, 0x58, 0x3e, 0x57, 0xde, 0x01, 0xdb,
+	0xaa, 0xe3, 0x76, 0x1b, 0xde, 0xbb, 0xdd, 0xd6, 0x74, 0xdf, 0x77, 0x5b,
+	0x42, 0x9b, 0x65, 0x5f, 0x44, 0x67, 0x33, 0xb7, 0xeb, 0x96, 0x1a, 0xe5,
+	0x4a, 0xfa, 0xb4, 0x21, 0xc6, 0xfc, 0x2b, 0x1b, 0xfe, 0xdd, 0xf8, 0x96,
+	0x23, 0xec, 0xb1, 0xa3, 0xd6, 0xd3, 0x8b, 0xab, 0x46, 0xaa, 0x42, 0x9e,
+	0xcb, 0x18, 0xf2, 0xae, 0xa7, 0xd4, 0x59, 0x0c, 0xe3, 0x8e, 0x5a, 0x83,
+	0xf1, 0xb4, 0x6d, 0xb9, 0x9d, 0x76, 0x91, 0xab, 0x9d, 0x37, 0xea, 0xaa,
+	0x6a, 0xdd, 0x36, 0xa5, 0x8e, 0xda, 0x51, 0x81, 0x57, 0xa9, 0xbf, 0xaf,
+	0x4e, 0x88, 0x0f, 0x54, 0x71, 0x98, 0x76, 0x7a, 0xa8, 0xce, 0xd7, 0x79,
+	0x89, 0xb1, 0xe5, 0x27, 0xe4, 0xfc, 0x6f, 0x6b, 0xde, 0xf6, 0x93, 0x92,
+	0x93, 0x0c, 0x3a, 0xf0, 0x66, 0xc3, 0x55, 0x33, 0x4f, 0x1c, 0x3b, 0xa0,
+	0x62, 0x28, 0x61, 0xd9, 0xfb, 0x6b, 0xb4, 0xe3, 0xeb, 0x77, 0x1e, 0x42,
+	0xe8, 0x19, 0x14, 0xfb, 0x08, 0x99, 0x76, 0x74, 0x3d, 0x77, 0x24, 0x78,
+	0x2d, 0x76, 0xb1, 0x5e, 0x6a, 0x7e, 0x91, 0x14, 0xc8, 0x6d, 0x06, 0x56,
+	0x92, 0x13, 0x8b, 0xcf, 0x6d, 0x60, 0xfc, 0xeb, 0xa0, 0xfd, 0x9c, 0x64,
+	0x2c, 0xc2, 0xb5, 0x35, 0x19, 0xc6, 0x05, 0xc6, 0x66, 0xc3, 0xa8, 0x57,
+	0x8f, 0x61, 0x0d, 0x79, 0x2d, 0x39, 0xcf, 0x44, 0x0b, 0x76, 0x9a, 0xb1,
+	0x95, 0x4f, 0xbd, 0x5f, 0x59, 0xc4, 0xfd, 0xb7, 0xa0, 0xfb, 0x90, 0x87,
+	0x3e, 0xc1, 0x30, 0x1e, 0xd0, 0xff, 0x12, 0x65, 0x83, 0xdd, 0x9d, 0x65,
+	0x94, 0xc7, 0xe7, 0xc1, 0x48, 0x07, 0x31, 0x7d, 0xd3, 0x31, 0x45, 0xee,
+	0xa5, 0x7e, 0x8b, 0xe7, 0x11, 0x30, 0xf9, 0xf6, 0x8e, 0xc4, 0x03, 0xf4,
+	0x71, 0xff, 0x1d, 0x3b, 0x54, 0x65, 0x19, 0xdd, 0x1d, 0x39, 0x23, 0xfc,
+	0x6a, 0x93, 0x76, 0xf2, 0xbc, 0xfd, 0xfb, 0xd0, 0xe7, 0x34, 0xf2, 0x99,
+	0xf8, 0x79, 0x69, 0x0b, 0x5c, 0x88, 0x76, 0xe2, 0x68, 0x9a, 0x7a, 0x1d,
+	0xed, 0xc3, 0xb1, 0xb4, 0xcc, 0x29, 0x9c, 0xab, 0x01, 0xb1, 0x41, 0x3b,
+	0xc6, 0x75, 0x5f, 0xb8, 0x98, 0x72, 0xc9, 0x0f, 0x7a, 0xc3, 0x6b, 0x88,
+	0xb1, 0x7d, 0xc3, 0x69, 0xbc, 0xb9, 0xdb, 0xdb, 0x5e, 0xa7, 0x68, 0x88,
+	0x4e, 0x40, 0x7d, 0x6e, 0x49, 0x1a, 0xa7, 0x46, 0x1e, 0x86, 0xa7, 0xca,
+	0xeb, 0x59, 0xa9, 0xb4, 0x62, 0xeb, 0xc4, 0xd7, 0xe5, 0x9c, 0x34, 0xce,
+	0xdd, 0x8a, 0x08, 0x65, 0xbf, 0x1d, 0xff, 0x38, 0x57, 0x70, 0xac, 0x77,
+	0xa2, 0x10, 0x35, 0xf4, 0x47, 0xaf, 0x98, 0x7e, 0xd7, 0xb2, 0xa3, 0x6a,
+	0xed, 0x53, 0xe3, 0x89, 0x8c, 0x5f, 0xff, 0xf3, 0xf2, 0xfa, 0xb1, 0x11,
+	0x56, 0x45, 0x5e, 0xd2, 0xaf, 0x9a, 0xdc, 0x40, 0x78, 0x81, 0xe5, 0xbf,
+	0x4b, 0xb5, 0xf7, 0x8d, 0x87, 0xcd, 0x31, 0x46, 0x39, 0x8f, 0xec, 0x29,
+	0x90, 0xd9, 0xb7, 0x8e, 0xdf, 0x46, 0x25, 0xf7, 0xa1, 0xe2, 0x98, 0x2e,
+	0x38, 0xd2, 0x4a, 0x5b, 0x75, 0x62, 0x53, 0x03, 0xcd, 0xd1, 0xac, 0x09,
+	0x4c, 0x63, 0x67, 0xf2, 0xf7, 0xc6, 0xf3, 0xd4, 0xa3, 0x55, 0xe4, 0x34,
+	0x1e, 0xe2, 0xc0, 0x33, 0xc1, 0x07, 0xc8, 0x4b, 0xb9, 0xe7, 0x84, 0x83,
+	0x18, 0xa4, 0x20, 0xd1, 0x48, 0xfb, 0x0f, 0x2e, 0xc4, 0x94, 0xd9, 0xfe,
+	0xb1, 0xb9, 0x56, 0xae, 0xb1, 0x61, 0x9e, 0x15, 0x2b, 0x8a, 0xfc, 0xff,
+	0x23, 0xf2, 0x7b, 0xcd, 0xf0, 0x94, 0x89, 0xfc, 0x1c, 0x70, 0xfb, 0x1b,
+	0xb0, 0x8f, 0x6d, 0xce, 0xec, 0x76, 0x60, 0x40, 0x6b, 0xc5, 0xc0, 0x04,
+	0x3c, 0x9f, 0xb3, 0xcd, 0xbb, 0x23, 0xbf, 0x98, 0x6b, 0x71, 0x87, 0xf7,
+	0xd0, 0x1d, 0x7d, 0xc1, 0x58, 0x5e, 0x26, 0xfb, 0x95, 0x7b, 0x3e, 0x6d,
+	0x6c, 0x9f, 0xcd, 0xfb, 0x3d, 0x6b, 0x3c, 0x62, 0xfa, 0x89, 0x7f, 0x9a,
+	0x2b, 0x75, 0xb9, 0xd7, 0x13, 0x06, 0x2e, 0xea, 0xe7, 0xe4, 0xfd, 0x49,
+	0x93, 0xeb, 0xf5, 0x26, 0xe4, 0x6c, 0x65, 0x6d, 0xc7, 0x32, 0xf2, 0x28,
+	0xa8, 0xba, 0x71, 0xdd, 0x67, 0x33, 0x39, 0x50, 0xe1, 0x10, 0x22, 0xab,
+	0x2c, 0xd7, 0xf0, 0x64, 0xf2, 0x6e, 0xc7, 0xd1, 0x93, 0x94, 0x9a, 0xb9,
+	0xbc, 0x9f, 0x5d, 0x82, 0x17, 0xf5, 0x87, 0xb0, 0xa0, 0xec, 0x0f, 0x9c,
+	0x4f, 0x72, 0x30, 0xad, 0x1c, 0xcf, 0x30, 0x36, 0xea, 0xf5, 0xfa, 0x45,
+	0x7c, 0x13, 0x53, 0x15, 0x21, 0xb3, 0x86, 0x91, 0xd7, 0xe4, 0x51, 0xb4,
+	0x3d, 0x6b, 0xe0, 0x2c, 0xd5, 0x88, 0xfd, 0xa2, 0x93, 0x82, 0x31, 0xb2,
+	0x26, 0xc1, 0x19, 0xc9, 0xf1, 0x4b, 0x4e, 0x3c, 0x12, 0xae, 0x69, 0xea,
+	0x54, 0x1e, 0x64, 0xcc, 0xff, 0x4e, 0x50, 0xde, 0x21, 0xf4, 0xb7, 0xd7,
+	0xd8, 0x90, 0x37, 0x19, 0xca, 0xc5, 0x2f, 0x83, 0x72, 0x9f, 0x1b, 0xae,
+	0xb1, 0xb4, 0x37, 0xd2, 0x68, 0x57, 0x5d, 0x69, 0xb3, 0x56, 0x29, 0xb8,
+	0x9b, 0xa0, 0xcc, 0x89, 0x2d, 0x26, 0xa6, 0xdc, 0x85, 0x15, 0xe6, 0x39,
+	0xab, 0xf4, 0xa7, 0xc2, 0x1b, 0x8e, 0x90, 0x37, 0x00, 0xb9, 0x03, 0xc6,
+	0xb2, 0xe6, 0x60, 0xbd, 0xde, 0x87, 0xdb, 0xc9, 0xfd, 0x97, 0xe1, 0x23,
+	0x5d, 0xea, 0x24, 0x91, 0x6f, 0x39, 0xcc, 0xfb, 0x38, 0x87, 0x83, 0x5b,
+	0xa3, 0x2b, 0xb1, 0x7f, 0x30, 0xa2, 0x38, 0x9b, 0xbc, 0xad, 0x31, 0xf2,
+	0x22, 0x42, 0xba, 0x99, 0x23, 0xdc, 0x41, 0xfe, 0x70, 0x38, 0xd4, 0x89,
+	0xed, 0x7a, 0x2e, 0x7a, 0xf5, 0x70, 0x5e, 0xcf, 0x92, 0x2e, 0xbc, 0xa2,
+	0x17, 0x4a, 0x1e, 0x9e, 0xf8, 0xae, 0x6d, 0x4a, 0xc2, 0xdf, 0xf1, 0x21,
+	0xbc, 0x53, 0x47, 0xc9, 0x41, 0xce, 0xdb, 0x15, 0xf8, 0x97, 0x3a, 0x5c,
+	0xb1, 0xb1, 0x26, 0xec, 0x9b, 0xa8, 0x70, 0xc5, 0xc7, 0x18, 0x0f, 0x4e,
+	0x30, 0x86, 0x61, 0x1c, 0xac, 0x8d, 0xad, 0xc4, 0xb6, 0x61, 0xb9, 0xe3,
+	0x1b, 0xc0, 0xdd, 0x65, 0xe7, 0x8c, 0xa7, 0xfd, 0x82, 0xa3, 0xf3, 0x71,
+	0x67, 0x99, 0xcf, 0xf4, 0x81, 0xed, 0xb6, 0xaf, 0xe3, 0x0f, 0x76, 0x6c,
+	0x0e, 0xfe, 0xc8, 0x08, 0x3f, 0x26, 0x72, 0x7b, 0x9e, 0x67, 0xf4, 0x00,
+	0xb1, 0xd4, 0x92, 0xe1, 0x86, 0x6b, 0x32, 0x0c, 0xa1, 0x7b, 0x30, 0x44,
+	0xfb, 0x71, 0x93, 0x6f, 0x5d, 0x3f, 0x87, 0xf5, 0xba, 0x6f, 0x66, 0x08,
+	0xad, 0x78, 0x65, 0xe2, 0x6f, 0xd8, 0x4f, 0xf2, 0x33, 0x4b, 0xd1, 0x91,
+	0x89, 0x47, 0xc2, 0xb6, 0x02, 0xf2, 0x3f, 0xcb, 0x0f, 0x0c, 0x0c, 0xcb,
+	0x73, 0xef, 0xbe, 0x30, 0xb9, 0xcc, 0x8b, 0x0d, 0x33, 0xd4, 0xc3, 0x48,
+	0xa7, 0xdd, 0x7c, 0x2f, 0xe2, 0xca, 0xf7, 0xdc, 0x75, 0xde, 0x75, 0x33,
+	0x0a, 0xf0, 0x17, 0x31, 0xfa, 0x64, 0x9b, 0xf4, 0x95, 0xb1, 0x9d, 0x38,
+	0xd8, 0x30, 0x1f, 0x53, 0x6b, 0x65, 0x4c, 0x99, 0xcf, 0x30, 0x9e, 0xa3,
+	0x8e, 0xff, 0x00, 0x4e, 0xe4, 0xde, 0x65, 0xc7, 0x39, 0x95, 0xb6, 0xa2,
+	0xff, 0xde, 0x48, 0xd3, 0x57, 0x6e, 0xcd, 0xd8, 0xcc, 0x36, 0xda, 0xcc,
+	0x28, 0x6d, 0xa6, 0x9f, 0x36, 0x73, 0xf7, 0xa2, 0x3b, 0x32, 0x36, 0x23,
+	0xb1, 0xe1, 0x34, 0x1e, 0xe9, 0x57, 0xd1, 0xf6, 0x9f, 0xa6, 0xd1, 0x76,
+	0x20, 0xbb, 0x76, 0xd1, 0xbb, 0xec, 0xfa, 0xa5, 0xde, 0x28, 0xf3, 0xc8,
+	0x1a, 0x65, 0x2f, 0xd9, 0xdf, 0xaf, 0x7f, 0xaf, 0xd6, 0x9c, 0x78, 0xc2,
+	0xdc, 0xd7, 0xdf, 0x57, 0x5b, 0x75, 0xfa, 0xec, 0x7e, 0xc2, 0x37, 0x7d,
+	0xaf, 0xbd, 0xed, 0xc6, 0xef, 0x7b, 0xdd, 0x37, 0x7e, 0x3f, 0x79, 0xd3,
+	0xf3, 0xac, 0x6d, 0x5c, 0x97, 0x69, 0xa7, 0xee, 0xeb, 0x9c, 0xe4, 0x3e,
+	0x3f, 0xba, 0xeb, 0xb0, 0xd1, 0xfe, 0xb0, 0xac, 0x25, 0x40, 0x9e, 0x24,
+	0xeb, 0x7b, 0x0f, 0x0b, 0xfe, 0x68, 0x6d, 0xef, 0x64, 0x6c, 0xc9, 0x7c,
+	0x37, 0xc8, 0xd4, 0xab, 0xd7, 0x27, 0x34, 0xfc, 0xf8, 0x86, 0xfb, 0x8b,
+	0x01, 0x65, 0x47, 0x4c, 0x74, 0xca, 0x11, 0x71, 0x35, 0x41, 0xb9, 0xd3,
+	0x1f, 0xc1, 0x42, 0x7f, 0x17, 0x3e, 0xa2, 0xce, 0xb7, 0x29, 0x1a, 0xe3,
+	0xbb, 0x24, 0xe2, 0x63, 0x5e, 0x7d, 0x13, 0xb1, 0x22, 0x36, 0xf6, 0x97,
+	0x38, 0x91, 0xcc, 0xa7, 0x0e, 0x76, 0x61, 0x65, 0xd0, 0x1b, 0x18, 0xa2,
+	0xef, 0xbd, 0xa0, 0x8b, 0x9d, 0x4a, 0xed, 0xd7, 0x43, 0x0c, 0x0d, 0x08,
+	0x06, 0xaa, 0x29, 0xf1, 0xc9, 0xb4, 0x3d, 0xe1, 0xd8, 0x0e, 0xea, 0xc6,
+	0xd6, 0xe1, 0xb7, 0xd0, 0x12, 0x95, 0x7c, 0xeb, 0x71, 0x3c, 0x9a, 0xa4,
+	0x0f, 0xd2, 0x68, 0xb7, 0x8b, 0x1c, 0xd0, 0xca, 0x24, 0x27, 0xec, 0xc0,
+	0xda, 0xf8, 0x7c, 0x44, 0xaa, 0xa4, 0xae, 0xb2, 0x12, 0xdb, 0x07, 0x15,
+	0xfc, 0x56, 0x6a, 0x98, 0x8c, 0xc1, 0x5f, 0x27, 0x47, 0x9c, 0x8c, 0x6e,
+	0xc1, 0x88, 0x59, 0xa3, 0xd6, 0xfa, 0xaa, 0xed, 0xe1, 0x17, 0x4b, 0xc9,
+	0xb7, 0x13, 0xba, 0xbf, 0x9d, 0xf6, 0xe8, 0x29, 0x6a, 0xf2, 0x87, 0x63,
+	0xca, 0x57, 0xf8, 0x37, 0xf3, 0xae, 0x8d, 0xee, 0xda, 0x44, 0x5d, 0xdf,
+	0x33, 0x2c, 0xfd, 0xb8, 0xc7, 0x5b, 0xe6, 0x3a, 0xac, 0x77, 0xdd, 0xad,
+	0xbc, 0xe4, 0x5b, 0x38, 0x98, 0x76, 0xe1, 0xa9, 0xb8, 0x47, 0xb1, 0xef,
+	0x51, 0xd1, 0x12, 0xf7, 0x9e, 0xbc, 0x60, 0x37, 0x8c, 0xba, 0xc5, 0x25,
+	0x98, 0x21, 0xbf, 0xa8, 0x5c, 0x2c, 0x3e, 0xe1, 0x3f, 0x23, 0x55, 0xd5,
+	0x4c, 0x6c, 0x43, 0xa1, 0x6d, 0x89, 0x57, 0xb7, 0xd9, 0x7d, 0xad, 0x33,
+	0xd8, 0x8a, 0xbc, 0xb1, 0x07, 0xcc, 0x75, 0x7f, 0x23, 0x2e, 0xef, 0x2f,
+	0xd5, 0x53, 0xdf, 0xe8, 0x27, 0x0f, 0x89, 0x0c, 0x11, 0xa9, 0x6c, 0x82,
+	0xa7, 0xa2, 0x69, 0xd7, 0x7c, 0xe4, 0x7f, 0x45, 0xce, 0x3d, 0x8d, 0x89,
+	0xa4, 0xd6, 0x51, 0x62, 0x33, 0x70, 0x3a, 0x78, 0x27, 0x52, 0x66, 0x0d,
+	0x63, 0x25, 0xfa, 0x07, 0x25, 0x3f, 0xaf, 0x40, 0x5b, 0x54, 0x40, 0xce,
+	0xa7, 0x05, 0x5e, 0xb4, 0x49, 0xcd, 0x79, 0x0b, 0xbe, 0xc1, 0xbd, 0xde,
+	0x1f, 0x15, 0x7b, 0xd5, 0xdc, 0x6d, 0x4a, 0xf8, 0xaa, 0x9d, 0x7b, 0xfd,
+	0xb5, 0xee, 0x3f, 0xf9, 0x6b, 0xbb, 0x7f, 0x2a, 0x64, 0xd7, 0x5d, 0x93,
+	0xe3, 0x2a, 0x31, 0xc4, 0x8a, 0x31, 0xd3, 0xe4, 0xb4, 0x85, 0x1c, 0xb7,
+	0x20, 0x78, 0x89, 0xdc, 0x40, 0xc6, 0x5d, 0x3e, 0x0f, 0xc5, 0x2d, 0xe8,
+	0xdf, 0xfb, 0xa1, 0x11, 0x6e, 0x93, 0x39, 0xfe, 0xc0, 0xb8, 0xd4, 0x89,
+	0x95, 0x6b, 0x3d, 0x58, 0x11, 0x97, 0x9c, 0xea, 0x8f, 0x2b, 0x2d, 0xdd,
+	0x92, 0xef, 0x0e, 0x74, 0xe8, 0x04, 0xdb, 0xaa, 0x2f, 0x8d, 0x0a, 0x33,
+	0x66, 0xbd, 0x6f, 0xbe, 0xe8, 0x4b, 0x6f, 0xe2, 0x85, 0xf9, 0x62, 0xdf,
+	0xbd, 0x13, 0x4f, 0xbb, 0x2d, 0xbd, 0x7b, 0x99, 0xdf, 0x65, 0x2c, 0x6d,
+	0xdf, 0x16, 0x9c, 0xa9, 0x14, 0x5e, 0xf3, 0xe8, 0xf8, 0xec, 0xf6, 0x56,
+	0xbd, 0xea, 0xf5, 0x6b, 0xb9, 0x1a, 0xa9, 0x13, 0x86, 0x95, 0xb6, 0x68,
+	0xab, 0xb2, 0x3a, 0x2a, 0xb5, 0x42, 0x5b, 0xa8, 0x80, 0x1c, 0xe6, 0x98,
+	0x2e, 0xef, 0xea, 0x65, 0xeb, 0x86, 0x11, 0xa5, 0x2f, 0x44, 0xc6, 0x33,
+	0xd6, 0xac, 0xec, 0x88, 0x96, 0xc9, 0x5d, 0x07, 0xea, 0xa5, 0x83, 0x32,
+	0x75, 0x21, 0x67, 0x54, 0x62, 0xf2, 0x02, 0xe4, 0x1c, 0xd0, 0x90, 0x3b,
+	0xd6, 0x8e, 0x11, 0x32, 0xb8, 0x92, 0xda, 0x72, 0x1c, 0x0a, 0xc8, 0x5d,
+	0x8e, 0x0a, 0x14, 0x09, 0xb6, 0x6a, 0x3d, 0x78, 0xb5, 0x0d, 0x4a, 0x41,
+	0xed, 0x6c, 0x9e, 0x6a, 0xde, 0x5f, 0x57, 0xdd, 0x4d, 0xe2, 0xdb, 0x25,
+	0xc7, 0x6f, 0xd5, 0x1d, 0xcf, 0xa6, 0x37, 0x60, 0x4c, 0xe5, 0xb2, 0xb5,
+	0x7f, 0x33, 0xc6, 0x2b, 0xcc, 0x77, 0x7e, 0xc8, 0x81, 0x0f, 0x93, 0x03,
+	0x1b, 0xcb, 0xba, 0x82, 0x91, 0x9f, 0xd5, 0xc0, 0xdb, 0xa7, 0xdb, 0xbd,
+	0x9e, 0x46, 0x9b, 0xe4, 0x10, 0xa0, 0xe4, 0xd4, 0x46, 0x90, 0x5b, 0x5b,
+	0x18, 0xb1, 0x53, 0xbf, 0xcf, 0xe8, 0x22, 0xfb, 0x2e, 0xec, 0xd4, 0xf3,
+	0xe5, 0x7d, 0xf9, 0x48, 0x31, 0x79, 0x4b, 0x0c, 0x9a, 0x7a, 0x1a, 0xda,
+	0xcc, 0x27, 0xec, 0xb7, 0x82, 0xf6, 0xd0, 0x3d, 0xe6, 0x0d, 0x5f, 0x54,
+	0xbc, 0x53, 0x77, 0xd3, 0x46, 0x5e, 0x19, 0xa3, 0x1d, 0x12, 0x77, 0xfb,
+	0x69, 0x03, 0x7d, 0xb4, 0x85, 0x7d, 0x13, 0x87, 0x84, 0x47, 0xf4, 0xb5,
+	0x2b, 0xd6, 0x3d, 0x4c, 0xab, 0xde, 0x2e, 0x35, 0xb5, 0x88, 0xb2, 0x21,
+	0x24, 0x7e, 0xb0, 0x08, 0xe7, 0x93, 0xc0, 0x91, 0x74, 0x0e, 0x5e, 0x1b,
+	0x41, 0x8b, 0x0d, 0xf6, 0x5e, 0x17, 0xea, 0xd6, 0xa9, 0x78, 0xa3, 0xae,
+	0x40, 0xfe, 0x87, 0x11, 0x15, 0x9d, 0x8c, 0x09, 0xcb, 0xb0, 0x62, 0xb7,
+	0xb1, 0xec, 0xae, 0x45, 0xc6, 0xb2, 0xcd, 0xfa, 0x63, 0x58, 0x63, 0x62,
+	0x4c, 0x77, 0x7b, 0x01, 0xe3, 0xdb, 0x1f, 0x8e, 0x38, 0x91, 0x4a, 0xb1,
+	0x17, 0xe5, 0x35, 0x9c, 0xc2, 0x03, 0x0e, 0x62, 0x27, 0xfd, 0x58, 0x5d,
+	0x71, 0x93, 0xbf, 0xed, 0x6e, 0x85, 0xbc, 0x32, 0x5d, 0x81, 0x54, 0x5a,
+	0xe3, 0x5f, 0x80, 0x7f, 0x0d, 0xfc, 0x6b, 0xc4, 0x9a, 0xa8, 0xe8, 0xa8,
+	0x1b, 0x63, 0xe9, 0x22, 0x7c, 0x98, 0xd4, 0x02, 0x2e, 0xea, 0xcf, 0x88,
+	0x3e, 0x6e, 0x44, 0xda, 0xac, 0x38, 0xe4, 0xf3, 0xa4, 0xe4, 0x74, 0x8a,
+	0xf0, 0x59, 0xea, 0xf4, 0x7c, 0x8b, 0xdb, 0x77, 0xe1, 0x62, 0x30, 0x3f,
+	0x52, 0x6a, 0xfa, 0x1c, 0x6f, 0xe0, 0x35, 0x68, 0xeb, 0xae, 0x70, 0xdf,
+	0xbb, 0xc6, 0x52, 0xc6, 0xb9, 0x0a, 0xb1, 0xf5, 0xe3, 0xf8, 0x49, 0xf2,
+	0x8a, 0x51, 0x23, 0x9c, 0x33, 0x21, 0xf7, 0xf5, 0xad, 0x3c, 0x8b, 0xc4,
+	0x46, 0x85, 0x4b, 0x67, 0x9f, 0xc9, 0x71, 0xa4, 0x53, 0xb3, 0xcf, 0x05,
+	0xed, 0x8e, 0x26, 0x57, 0xc3, 0x8e, 0xa8, 0xfd, 0x4a, 0x3e, 0x79, 0xd4,
+	0xfd, 0x4b, 0x34, 0xbd, 0x4e, 0x71, 0x35, 0xf4, 0xa6, 0x5d, 0x0d, 0x7d,
+	0xd1, 0xd9, 0xe7, 0x7a, 0x44, 0xb1, 0x37, 0xc9, 0x38, 0x7e, 0xc6, 0xdc,
+	0xd9, 0xb1, 0x5c, 0x0d, 0xdd, 0xe9, 0xd9, 0x63, 0x75, 0xa1, 0x23, 0x28,
+	0x67, 0xe4, 0xdd, 0xe4, 0xbc, 0xa1, 0x6e, 0x20, 0x3e, 0xdc, 0x7c, 0xcf,
+	0xa5, 0xe3, 0xbb, 0xd7, 0xfa, 0x6a, 0xc4, 0x32, 0xfa, 0xc5, 0x89, 0xd9,
+	0xfd, 0xa7, 0xf1, 0x6e, 0xd2, 0xfc, 0x7f, 0x06, 0x74, 0x7c, 0xce, 0x18,
+	0xf1, 0x54, 0xf0, 0xb0, 0xe1, 0x29, 0x15, 0x19, 0x1f, 0xc7, 0x07, 0xdc,
+	0x5b, 0xa1, 0xb6, 0xb5, 0xdd, 0xad, 0x69, 0x27, 0x3f, 0xb6, 0x3b, 0x50,
+	0xb7, 0xf4, 0x38, 0x4e, 0xa4, 0xe4, 0x0c, 0x8b, 0xcc, 0x77, 0x6d, 0x27,
+	0x79, 0x06, 0x07, 0x53, 0xc5, 0xb7, 0xcb, 0xfd, 0x75, 0xbb, 0xdc, 0x63,
+	0xc6, 0xff, 0x07, 0xb6, 0x0b, 0xca, 0xea, 0xc4, 0x79, 0x00, 0x00, 0x00 };
 
 static const u32 bnx2_RXP_b09FwData[(0x0/4) + 1] = { 0x0 };
-static const u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = {
-	0x08004070, 0x08003f70, 0x08004014, 0x0800402c, 0x08004044, 0x08004064,
-	0x08004070, 0x08004070, 0x08003f78, 0x00000000, 0x08004a2c, 0x08004a64,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004a9c, 0x08004c60,
-	0x08004ba8, 0x08004be0, 0x08004c60, 0x08004b30, 0x08004c60, 0x08004c60,
-	0x08004be0, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c20,
-	0x08004c60, 0x08004c20, 0x08004ba8, 0x08004c60, 0x08004c60, 0x08004c20,
-	0x08004c20, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
-	0x08004b0c, 0x00000000, 0x08006078, 0x08006090, 0x08006090, 0x08006090,
-	0x08006078, 0x08006090, 0x08006090, 0x08006090, 0x08006078, 0x08006090,
-	0x08006090, 0x08006090, 0x08006078, 0x08006090, 0x08006090, 0x08006090,
-	0x08006084, 0x00000000, 0x00000000 };
+static const u32 bnx2_RXP_b09FwRodata[(0xb0/4) + 1] = {
+	0x80080100, 0x80080080, 0x80080000, 0x08005054, 0x08005054, 0x08005130,
+	0x08005104, 0x080050e8, 0x08005024, 0x08005024, 0x08005024, 0x0800505c,
+	0x080073b8, 0x08007404, 0x080073c4, 0x080072ec, 0x080073c4, 0x080073f4,
+	0x080073c4, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec,
+	0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080073e4,
+	0x080073d4, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec,
+	0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec,
+	0x080072ec, 0x080073d4, 0x00000000 };
 
 static struct fw_info bnx2_rxp_fw_09 = {
-	/* Firmware version:  3.7.1 */
-	.ver_major			= 0x3,
-	.ver_minor			= 0x7,
-	.ver_fix			= 0x1,
+	/* Firmware version: 4.0.5 */
+	.ver_major			= 0x4,
+	.ver_minor			= 0x0,
+	.ver_fix			= 0x5,
 
-	.start_addr			= 0x08003184,
+	.start_addr			= 0x080031d0,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x6788,
+	.text_len			= 0x79c0,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_RXP_b09FwText,
 	.gz_text_len			= sizeof(bnx2_RXP_b09FwText),
 
-	.data_addr			= 0x08006a20,
+	.data_addr			= 0x00000000,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_RXP_b09FwData,
 
-	.sbss_addr			= 0x08006a20,
-	.sbss_len			= 0x20,
+	.sbss_addr			= 0x08007aa0,
+	.sbss_len			= 0x58,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x08006a40,
-	.bss_len			= 0x13dc,
+	.bss_addr			= 0x08007af8,
+	.bss_len			= 0x1c,
 	.bss_index			= 0x0,
 
-	.rodata_addr			= 0x08006788,
-	.rodata_len			= 0x278,
+	.rodata_addr			= 0x080079c0,
+	.rodata_len			= 0xb0,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_RXP_b09FwRodata,
 };
 
+static u8 bnx2_xi_rv2p_proc1[] = {
+	/* Date:        12/07/2007 16:21 */
+	0xc5, 0x56, 0xcd, 0x6b, 0x13, 0x51, 0x10, 0x9f, 0xdd, 0xa4, 0xd9, 0x34,
+	0xd9, 0x64, 0x97, 0xaa, 0x25, 0xb4, 0x91, 0xa6, 0x55, 0x0f, 0x69, 0x23,
+	0xb6, 0xea, 0xc1, 0x43, 0xc1, 0xda, 0x8b, 0xa0, 0x9e, 0x7a, 0x10, 0xf1,
+	0xdb, 0x20, 0x05, 0xf1, 0x8f, 0x70, 0x51, 0xab, 0x20, 0x78, 0x28, 0x6a,
+	0xb0, 0x0a, 0xea, 0x49, 0x45, 0x3c, 0x34, 0x07, 0x41, 0x50, 0x14, 0x14,
+	0x3c, 0xe9, 0x4d, 0xf0, 0xe3, 0x50, 0x15, 0x3f, 0x0e, 0x7a, 0x13, 0x8f,
+	0xda, 0xf8, 0xde, 0xcc, 0xef, 0xd9, 0xdd, 0x4d, 0xd3, 0x14, 0x0f, 0xba,
+	0xd0, 0xfc, 0xfa, 0xde, 0x9b, 0x37, 0x6f, 0xe6, 0x37, 0xf3, 0x66, 0x9e,
+	0x4f, 0x44, 0x36, 0x05, 0xf5, 0x3e, 0x85, 0x94, 0xb5, 0x12, 0x69, 0x05,
+	0x16, 0xd1, 0x5d, 0x97, 0x31, 0xd8, 0x40, 0xf2, 0x0d, 0x09, 0x04, 0x43,
+	0xbe, 0xfa, 0xfd, 0x4e, 0x5b, 0x4b, 0x1a, 0x13, 0xb4, 0xb5, 0x5f, 0xe3,
+	0x36, 0x7a, 0x5c, 0x2a, 0x28, 0xfc, 0xd5, 0xa0, 0x40, 0x8f, 0xd7, 0xcc,
+	0xde, 0xaf, 0x67, 0x59, 0xef, 0x3b, 0xec, 0x7f, 0x9d, 0x10, 0xdc, 0x52,
+	0x49, 0x8b, 0x1e, 0x20, 0xad, 0xf7, 0x19, 0x5e, 0x4e, 0xeb, 0x71, 0xd1,
+	0x0a, 0xd6, 0xe3, 0x7c, 0x5b, 0xe6, 0xe7, 0xa6, 0x3d, 0x3d, 0x4f, 0xef,
+	0xc7, 0xf5, 0xd8, 0xcb, 0x9c, 0xae, 0xa7, 0x59, 0xaf, 0xac, 0x77, 0x65,
+	0x4e, 0xf3, 0x3e, 0xd7, 0x12, 0x7d, 0xea, 0x8f, 0xf7, 0x6f, 0x56, 0x7a,
+	0x60, 0x37, 0x89, 0x9e, 0x43, 0x25, 0x3d, 0x3f, 0x06, 0xb9, 0x51, 0xc8,
+	0x15, 0x9b, 0xe4, 0xe6, 0xa6, 0x35, 0x3a, 0x54, 0xad, 0x68, 0x7f, 0xfa,
+	0x95, 0xa1, 0xae, 0xf0, 0xd3, 0x27, 0xfe, 0x4e, 0xc2, 0xec, 0x77, 0x83,
+	0xfa, 0x1f, 0x65, 0xdb, 0xa0, 0x96, 0x9b, 0x53, 0x7e, 0x1b, 0x7f, 0x8d,
+	0xbc, 0xc8, 0x39, 0xac, 0xe7, 0xad, 0x5a, 0x37, 0x7e, 0x85, 0xfd, 0xc9,
+	0x86, 0xfc, 0x89, 0xf9, 0xd9, 0xe4, 0x57, 0x98, 0xa7, 0xf4, 0x22, 0x76,
+	0xeb, 0x73, 0x94, 0x0d, 0x7c, 0x4e, 0x0a, 0xfc, 0xa6, 0x62, 0xfb, 0x52,
+	0x2d, 0xf6, 0x7d, 0x6a, 0x2c, 0xf8, 0x69, 0xd6, 0xf5, 0xfc, 0xd3, 0x85,
+	0xf9, 0x72, 0x74, 0x5d, 0xfc, 0xef, 0x80, 0xff, 0x8f, 0xe0, 0xdf, 0x0e,
+	0x5a, 0x6b, 0x17, 0x78, 0x3d, 0xc9, 0xfb, 0x7b, 0x95, 0x3d, 0x1a, 0x57,
+	0x03, 0xfb, 0x81, 0x07, 0x81, 0x07, 0x80, 0xab, 0x80, 0x2b, 0x81, 0x2b,
+	0x80, 0x5d, 0xc0, 0xcb, 0x40, 0x1f, 0xe8, 0x01, 0xf3, 0xc0, 0x8b, 0x40,
+	0x17, 0x98, 0x05, 0xd6, 0x80, 0x57, 0x81, 0x69, 0xe0, 0x31, 0xe0, 0x23,
+	0xe0, 0x13, 0xe0, 0x37, 0xe0, 0x39, 0xa3, 0xcf, 0xc2, 0xb9, 0x40, 0x42,
+	0x3e, 0x58, 0x31, 0x9e, 0xae, 0x21, 0xef, 0x35, 0xcf, 0x58, 0x2f, 0x1b,
+	0x39, 0xc4, 0x97, 0x79, 0x9a, 0x81, 0x5c, 0xd7, 0xec, 0x8d, 0xd8, 0xfd,
+	0x28, 0xb5, 0xbd, 0x17, 0xf1, 0xb8, 0x79, 0xec, 0xcf, 0xe1, 0xed, 0x1e,
+	0x9f, 0x93, 0x4f, 0xc9, 0xbc, 0x31, 0x6b, 0x8f, 0x27, 0x78, 0x34, 0x23,
+	0xf8, 0x39, 0xd3, 0xa9, 0x7e, 0x1b, 0x8d, 0xc9, 0xac, 0x8c, 0x8f, 0xe4,
+	0x0c, 0xcf, 0x46, 0x8f, 0xb1, 0xa7, 0x9d, 0x1d, 0xad, 0xce, 0x33, 0x76,
+	0xb5, 0x3b, 0x57, 0xb0, 0x6a, 0x47, 0xfd, 0xbf, 0x32, 0x2c, 0x98, 0x1c,
+	0x61, 0xa8, 0xb8, 0xa9, 0xa4, 0xc6, 0xcd, 0xee, 0x33, 0x73, 0x8e, 0x46,
+	0xb7, 0x50, 0xe3, 0xfb, 0x92, 0xa4, 0x5a, 0x4a, 0xeb, 0xfd, 0xd9, 0x38,
+	0x2f, 0x72, 0x3d, 0x47, 0x5e, 0x30, 0x16, 0xae, 0x3c, 0x17, 0xf9, 0x57,
+	0x25, 0x97, 0x71, 0xf7, 0x10, 0xc5, 0x3e, 0xb3, 0x2e, 0xf7, 0x31, 0x60,
+	0xbb, 0x7f, 0x58, 0x41, 0xdd, 0x9c, 0x83, 0x7d, 0xc7, 0x4d, 0x1c, 0x7d,
+	0xb6, 0x73, 0x80, 0x64, 0x3c, 0x51, 0x96, 0xf5, 0x89, 0x32, 0xee, 0xf3,
+	0x40, 0x34, 0x1f, 0xe4, 0x5e, 0x24, 0x10, 0xef, 0x7d, 0xb8, 0x17, 0xf1,
+	0x7b, 0x9c, 0x9e, 0xbd, 0x31, 0x1d, 0xce, 0x97, 0x02, 0x55, 0x47, 0x60,
+	0x4f, 0x53, 0x9c, 0x4d, 0x3d, 0x36, 0xf9, 0xce, 0xd3, 0xb3, 0x41, 0x22,
+	0xc2, 0xdf, 0x18, 0x55, 0xc2, 0x71, 0xb2, 0x16, 0xc9, 0x97, 0x76, 0xe7,
+	0x44, 0xf4, 0xe5, 0x55, 0x04, 0xa8, 0x39, 0x8f, 0x1d, 0xf8, 0x35, 0x86,
+	0x3c, 0xee, 0x6d, 0xca, 0x63, 0x53, 0xe7, 0x25, 0x9f, 0x5b, 0xd5, 0xaf,
+	0xbf, 0xaf, 0xcf, 0x22, 0x17, 0x84, 0xf2, 0xd3, 0xd4, 0x43, 0xf0, 0xe4,
+	0xb0, 0x5c, 0x71, 0xee, 0x9e, 0xc4, 0x4d, 0xea, 0xb8, 0x4a, 0xc6, 0x20,
+	0x6a, 0xa7, 0x63, 0xfc, 0xeb, 0x0b, 0xd7, 0xc1, 0x75, 0x2d, 0xe2, 0x15,
+	0xae, 0xbb, 0x71, 0x5e, 0xa2, 0x79, 0x2f, 0xf1, 0xcf, 0x80, 0xa7, 0xde,
+	0x36, 0x75, 0xa1, 0x13, 0x72, 0xdd, 0x4b, 0xc8, 0x89, 0xde, 0xf1, 0x72,
+	0xb8, 0x8e, 0xf8, 0x0d, 0xd4, 0xc1, 0x3f, 0x71, 0x78, 0xd8, 0x22, 0x0e,
+	0xa3, 0xff, 0x37, 0x0e, 0xe8, 0xa7, 0xed, 0xe2, 0x40, 0xb1, 0x38, 0xfc,
+	0x98, 0x5f, 0x5e, 0x1c, 0x08, 0x3c, 0x51, 0x8b, 0x38, 0xa4, 0xc0, 0xd7,
+	0xd7, 0xf9, 0xa5, 0xe3, 0x90, 0x85, 0xdc, 0xe7, 0x90, 0x1c, 0xdb, 0x3d,
+	0x2a, 0xf7, 0xd4, 0xa9, 0x7e, 0x89, 0xf1, 0x3b, 0x52, 0xd1, 0xf5, 0xe7,
+	0x04, 0xd5, 0xe1, 0xff, 0x9b, 0x08, 0x0f, 0x39, 0x65, 0x9f, 0xbc, 0x23,
+	0x6e, 0xd7, 0x0d, 0x5f, 0xb2, 0x5c, 0xaa, 0x08, 0xde, 0x62, 0x79, 0x3f,
+	0xc4, 0x5b, 0x94, 0x5f, 0xe1, 0xcd, 0xa7, 0x9b, 0x7f, 0xea, 0x92, 0xc7,
+	0xfa, 0x86, 0x51, 0xd7, 0x0f, 0xa3, 0xbe, 0x7e, 0xc8, 0x48, 0xfd, 0xae,
+	0xee, 0xe4, 0x3a, 0x4b, 0xdd, 0xa8, 0xb3, 0xd5, 0x9c, 0x8c, 0x7b, 0x72,
+	0xf2, 0x6e, 0x19, 0x76, 0x5c, 0x96, 0xeb, 0xc9, 0x09, 0x76, 0x67, 0xf5,
+	0xbe, 0x02, 0x7d, 0xdc, 0xc5, 0xe2, 0x95, 0x19, 0x57, 0xea, 0xed, 0xcc,
+	0x73, 0xd4, 0x7f, 0xcf, 0xf0, 0x04, 0x7f, 0x37, 0xe9, 0xf9, 0x6e, 0x55,
+	0xef, 0xc2, 0xfc, 0x2a, 0x99, 0x41, 0xb1, 0xef, 0x3a, 0xac, 0x2f, 0x99,
+	0x7d, 0x7d, 0x9a, 0xcf, 0x07, 0xf3, 0xa6, 0xbf, 0x0c, 0x6c, 0xd7, 0xf6,
+	0x78, 0x94, 0x77, 0x24, 0x9e, 0x82, 0x4a, 0xce, 0x76, 0xf4, 0xb6, 0xe2,
+	0x94, 0x2d, 0xe3, 0xa9, 0x93, 0xac, 0x66, 0xd7, 0x94, 0x99, 0x1f, 0xe7,
+	0x44, 0x9e, 0xb8, 0xf3, 0x94, 0xe7, 0xf3, 0xf5, 0x84, 0xcc, 0x3b, 0x3b,
+	0x0d, 0x1f, 0x1e, 0xfb, 0x57, 0x13, 0x3e, 0xf6, 0x5f, 0x12, 0xdc, 0xab,
+	0x9e, 0x22, 0xfa, 0xcb, 0xd4, 0x5c, 0xe9, 0x3f, 0x33, 0x6e, 0x9a, 0x91,
+	0x98, 0x0f, 0x7b, 0xa3, 0xf4, 0x91, 0x0e, 0xd4, 0xff, 0xce, 0x50, 0x9c,
+	0xe2, 0x7d, 0x79, 0xb9, 0xf1, 0x0a, 0xf7, 0x0b, 0xd3, 0x47, 0xe2, 0x7d,
+	0x21, 0x87, 0x3c, 0xbb, 0xdc, 0x26, 0x1f, 0x4d, 0x9d, 0xbd, 0x80, 0x7b,
+	0xb0, 0x58, 0x3f, 0xd6, 0x98, 0x6f, 0xf1, 0x8e, 0x28, 0x22, 0xff, 0x4c,
+	0xdf, 0x5c, 0xec, 0xbd, 0x20, 0xf2, 0xcb, 0x7b, 0x27, 0xf8, 0x2d, 0xde,
+	0x09, 0xff, 0xec, 0x3d, 0x50, 0x58, 0x88, 0xa3, 0xc9, 0xd3, 0x70, 0x1c,
+	0xc3, 0xf9, 0x1a, 0xef, 0xd7, 0x4b, 0xf5, 0xe9, 0x3c, 0x78, 0x9e, 0x04,
+	0xcf, 0x49, 0xea, 0x48, 0x30, 0x31, 0x6e, 0xf2, 0x14, 0xeb, 0xb5, 0xa7,
+	0x6c, 0x16, 0x77, 0x3b, 0xce, 0x58, 0x1a, 0xf3, 0xee, 0x19, 0x91, 0x4b,
+	0xca, 0x7c, 0xc1, 0xe0, 0xd9, 0x53, 0xf2, 0x3e, 0xb4, 0xe9, 0x37, 0xf9,
+	0x0f, 0x65, 0x7b, 0x50, 0x0d, 0x00, 0x00, 0x00 };
+
+static u8 bnx2_xi_rv2p_proc2[] = {
+	/* Date:        12/07/2007 16:21 */
+	0xad, 0x58, 0x5d, 0x6c, 0xd3, 0x55, 0x14, 0xbf, 0xfd, 0x58, 0xdb, 0xb5,
+	0xff, 0xb6, 0x63, 0x9b, 0xdd, 0xa7, 0x6e, 0x6e, 0x61, 0x6c, 0xd8, 0xcd,
+	0xd1, 0x8d, 0x4f, 0x4d, 0x5c, 0x86, 0x19, 0x20, 0x26, 0x8c, 0x61, 0xd4,
+	0x37, 0xd8, 0x90, 0xb2, 0xb1, 0x8d, 0x2c, 0x8c, 0xf0, 0xc0, 0x8b, 0x0d,
+	0xd3, 0xf1, 0xd2, 0x07, 0x47, 0xb2, 0x0d, 0x8d, 0xc1, 0x45, 0x7d, 0x40,
+	0x9f, 0xec, 0x83, 0x32, 0x30, 0xc6, 0xc4, 0xe8, 0x42, 0xf0, 0x01, 0x48,
+	0x30, 0xc6, 0x68, 0x48, 0x08, 0xea, 0x32, 0x10, 0x75, 0x0c, 0xfb, 0x64,
+	0x98, 0xf7, 0x9e, 0xdf, 0xb9, 0xff, 0xfe, 0xff, 0x6d, 0x27, 0x18, 0xec,
+	0x43, 0x4f, 0xef, 0xbd, 0xe7, 0x9e, 0x7b, 0x3e, 0x7e, 0xe7, 0x9c, 0x7b,
+	0x5b, 0x24, 0x84, 0x70, 0x8a, 0x44, 0xaa, 0x46, 0x52, 0x11, 0x70, 0xb8,
+	0x04, 0x3e, 0x6b, 0x8b, 0x88, 0x5c, 0x4b, 0xf9, 0xe4, 0x77, 0x81, 0x78,
+	0xc9, 0x59, 0x4e, 0x63, 0xb7, 0x50, 0x34, 0x2c, 0x44, 0xc2, 0x4a, 0x4b,
+	0x98, 0x5e, 0x65, 0xfa, 0x3b, 0xd3, 0xc7, 0x1d, 0xa0, 0x57, 0x78, 0xbc,
+	0x85, 0xc7, 0xd7, 0x78, 0xfc, 0x23, 0xd3, 0x8d, 0x3c, 0xbf, 0x99, 0x69,
+	0x92, 0xe9, 0x76, 0x5e, 0x9f, 0x65, 0x2a, 0x3f, 0x09, 0x43, 0x7e, 0xc9,
+	0xe5, 0x26, 0xad, 0xa7, 0x81, 0xe9, 0x26, 0xe8, 0xbb, 0xa7, 0x56, 0xf1,
+	0x2d, 0x2c, 0x67, 0xf8, 0x30, 0x7f, 0x7d, 0x02, 0xb4, 0x06, 0xbb, 0x3e,
+	0x4e, 0x3c, 0xad, 0xf7, 0x83, 0xf4, 0x06, 0x41, 0xfb, 0xd8, 0xfe, 0x8e,
+	0x28, 0x91, 0xe4, 0x7e, 0x27, 0xc6, 0x5d, 0x0d, 0xca, 0x0f, 0xc5, 0xc2,
+	0xed, 0x54, 0x72, 0x5a, 0x7c, 0x9e, 0xf3, 0x98, 0x7f, 0x35, 0x0c, 0xfa,
+	0x9a, 0x1f, 0xf4, 0x17, 0x7f, 0xa1, 0xfc, 0x5e, 0x5e, 0x8e, 0x07, 0x58,
+	0xbe, 0xc1, 0x6a, 0x07, 0xb0, 0x7f, 0xce, 0x80, 0x1e, 0x2f, 0xd7, 0x42,
+	0xbf, 0xef, 0x9f, 0x52, 0xf3, 0x2e, 0x91, 0x60, 0x39, 0x42, 0x68, 0x3d,
+	0x79, 0x7d, 0x10, 0xfb, 0x56, 0xad, 0xc1, 0xea, 0x5b, 0x71, 0x8c, 0xab,
+	0x3e, 0x28, 0xa2, 0xb8, 0x9c, 0x4e, 0x69, 0xfe, 0x7c, 0x72, 0xdd, 0x52,
+	0x2e, 0xe4, 0x8b, 0x3a, 0x1f, 0x29, 0x93, 0x88, 0x82, 0x8a, 0xe6, 0xec,
+	0x73, 0x20, 0x7f, 0x6a, 0xb5, 0x9a, 0x77, 0x8a, 0x1e, 0x97, 0x9a, 0xf7,
+	0x88, 0x9e, 0x01, 0xed, 0x5f, 0xac, 0xc7, 0x3d, 0x44, 0xca, 0x7b, 0xc7,
+	0x95, 0x9d, 0x61, 0xb1, 0xcf, 0x19, 0x26, 0x7e, 0xf8, 0xc5, 0xe5, 0x33,
+	0x3e, 0x03, 0xff, 0x97, 0x35, 0x06, 0xd9, 0x12, 0x6f, 0xc3, 0xbe, 0xd2,
+	0x18, 0xe8, 0x64, 0xac, 0x40, 0x91, 0x68, 0x7c, 0x94, 0x86, 0x2d, 0x37,
+	0xd7, 0xf9, 0x88, 0x2f, 0xd1, 0xac, 0xe3, 0xa7, 0xe3, 0xa5, 0xe2, 0xf8,
+	0x89, 0x8c, 0x23, 0xbb, 0xa5, 0x1e, 0x7e, 0xfd, 0x75, 0xb5, 0xe2, 0x97,
+	0xce, 0xad, 0xc3, 0x39, 0x19, 0xfd, 0xac, 0xf1, 0xff, 0xe8, 0x3f, 0xc4,
+	0x5f, 0xc9, 0xeb, 0x60, 0xbf, 0xd4, 0x4a, 0xbf, 0x28, 0x5a, 0xed, 0x48,
+	0x34, 0xdb, 0xe3, 0x71, 0x7d, 0x22, 0x4c, 0xbf, 0x6f, 0x75, 0x16, 0x91,
+	0x5f, 0x77, 0x61, 0xfe, 0x54, 0xd7, 0x39, 0xc4, 0x63, 0x07, 0xd9, 0x2f,
+	0xfc, 0x6f, 0x7c, 0x8a, 0x5d, 0xbd, 0x41, 0x35, 0x7e, 0xa5, 0x3d, 0x7e,
+	0x01, 0xeb, 0x05, 0x63, 0xf0, 0xeb, 0x2e, 0x96, 0xba, 0xc3, 0xe5, 0x50,
+	0x24, 0xe9, 0x19, 0xa3, 0xa1, 0x31, 0x47, 0xeb, 0x86, 0x38, 0x99, 0xc2,
+	0xfa, 0xe1, 0x80, 0x1a, 0xef, 0x8a, 0x2e, 0x60, 0x1c, 0x1d, 0x18, 0xe7,
+	0x8d, 0x4e, 0xf8, 0xe1, 0x96, 0x13, 0xf2, 0x18, 0x5e, 0x7e, 0x37, 0xc5,
+	0xc1, 0x21, 0x8c, 0x2e, 0xd0, 0x37, 0x69, 0xfd, 0x6f, 0x47, 0x92, 0xec,
+	0xee, 0x0a, 0xb9, 0xcf, 0x81, 0x91, 0x71, 0x6d, 0xe2, 0x56, 0xe3, 0xfe,
+	0x61, 0xf1, 0x3b, 0x6e, 0x68, 0xbc, 0xb2, 0xff, 0xd9, 0xbf, 0xef, 0x89,
+	0x6c, 0x9c, 0x82, 0x76, 0x35, 0x80, 0x7a, 0xea, 0xb3, 0xf1, 0xaa, 0xf1,
+	0x69, 0xf7, 0x33, 0xc7, 0xc7, 0x82, 0x17, 0x22, 0x12, 0x27, 0x36, 0xdc,
+	0x30, 0x4e, 0x2b, 0xa4, 0xbf, 0x74, 0xfc, 0x95, 0x20, 0xaf, 0x18, 0x64,
+	0x79, 0x03, 0x6c, 0xd7, 0x10, 0xdb, 0x75, 0xc7, 0xaf, 0xfd, 0xaa, 0xed,
+	0x01, 0x3d, 0x69, 0xb3, 0xc7, 0x21, 0xf1, 0x64, 0xc7, 0x21, 0xeb, 0x93,
+	0xfc, 0xa6, 0x0e, 0x3f, 0xaa, 0xea, 0x41, 0x4d, 0x3b, 0x1b, 0x14, 0x9f,
+	0x27, 0x36, 0x9d, 0xb2, 0xe3, 0x50, 0xe7, 0xe3, 0x9e, 0x5a, 0x2d, 0x5f,
+	0xe1, 0x32, 0x2d, 0x71, 0x89, 0xb8, 0x9d, 0x4e, 0x59, 0xf3, 0xb3, 0x32,
+	0x4f, 0x7e, 0xda, 0xf3, 0x42, 0xfb, 0xe5, 0x70, 0x90, 0x0a, 0x54, 0xfb,
+	0xe5, 0x79, 0xfb, 0x79, 0xc0, 0xb7, 0xd7, 0xc4, 0x4f, 0xe9, 0x06, 0xf6,
+	0x1f, 0xd3, 0xc8, 0x46, 0x25, 0xaf, 0x9b, 0xe5, 0xb7, 0xb2, 0x7c, 0xc3,
+	0x92, 0x77, 0x4a, 0xbf, 0x4e, 0x33, 0xdf, 0x74, 0xdc, 0x32, 0x79, 0xa7,
+	0xfd, 0x47, 0xe7, 0x47, 0x2f, 0xcf, 0xab, 0xfd, 0x55, 0x0f, 0xc8, 0xc3,
+	0x4d, 0xa6, 0xbc, 0xef, 0xcc, 0x7c, 0x53, 0xeb, 0x01, 0xf1, 0x1c, 0x0f,
+	0xed, 0xf5, 0xe4, 0x4f, 0x59, 0x4f, 0xc8, 0x0e, 0x9f, 0x71, 0x8e, 0xeb,
+	0xc7, 0xa8, 0x3a, 0xa7, 0x9c, 0xf5, 0x2e, 0x67, 0xbd, 0x65, 0xbf, 0x6a,
+	0xe6, 0x3a, 0xb3, 0xd7, 0x5a, 0x2f, 0xd6, 0x5a, 0xf2, 0x5e, 0x8d, 0x1b,
+	0x97, 0x73, 0xfb, 0x85, 0xcd, 0x9f, 0x09, 0x41, 0xfe, 0xf7, 0x72, 0x7c,
+	0x3c, 0x79, 0xfa, 0x8b, 0xe6, 0x07, 0xbe, 0xb6, 0x11, 0xbf, 0xcf, 0xc4,
+	0xbf, 0xdd, 0xde, 0xca, 0x3c, 0x75, 0x27, 0xdb, 0x7e, 0xf8, 0xb3, 0xd7,
+	0x19, 0x24, 0xbe, 0x1b, 0x23, 0x6a, 0xdf, 0x49, 0x87, 0xf6, 0x53, 0x07,
+	0xea, 0x90, 0x03, 0xf6, 0x56, 0xb3, 0xbd, 0x72, 0xb9, 0x99, 0xf0, 0xef,
+	0xbb, 0x31, 0x62, 0xb5, 0xd7, 0xf8, 0x97, 0xf3, 0xec, 0xb8, 0x19, 0xe1,
+	0x3e, 0xd6, 0x87, 0xbc, 0xf0, 0xed, 0xff, 0x5c, 0xeb, 0xc3, 0xe7, 0x86,
+	0xf5, 0xf9, 0x4a, 0x5e, 0x95, 0x98, 0x1f, 0x55, 0xfb, 0x1f, 0x13, 0x0c,
+	0x33, 0x31, 0xdc, 0x88, 0xfa, 0x77, 0xe7, 0x00, 0xf4, 0x1f, 0x6e, 0xd0,
+	0x7d, 0x1c, 0x38, 0x16, 0x5c, 0xff, 0xbf, 0x9e, 0xc8, 0xe7, 0x97, 0x41,
+	0x07, 0xf8, 0x4a, 0xd9, 0xae, 0x22, 0xb6, 0x2b, 0x2a, 0xb2, 0xeb, 0xec,
+	0x5e, 0xca, 0x97, 0x0e, 0xe6, 0x7b, 0x56, 0xd7, 0xe3, 0x1c, 0x3e, 0xd8,
+	0x5f, 0xc0, 0xe7, 0xe7, 0xf3, 0x57, 0x3e, 0xb9, 0xb3, 0x8c, 0xa3, 0x7e,
+	0xe6, 0x73, 0xe7, 0xa9, 0xf3, 0x18, 0xa5, 0xd7, 0x50, 0x9d, 0x3f, 0x73,
+	0x7c, 0x56, 0xf1, 0x05, 0x4d, 0x9c, 0xdb, 0xed, 0xfa, 0xe9, 0xfe, 0xa3,
+	0xfb, 0x5f, 0xf1, 0x45, 0xc4, 0xc1, 0xd0, 0x4a, 0x7e, 0x76, 0xab, 0xe9,
+	0x99, 0xc5, 0x59, 0x1d, 0x27, 0x83, 0xec, 0x9c, 0x1f, 0x55, 0xe7, 0x7f,
+	0x98, 0xe5, 0x7f, 0xa7, 0xc5, 0xff, 0xe0, 0x7f, 0x22, 0xfa, 0xa8, 0x7e,
+	0xcf, 0xd7, 0x97, 0xbf, 0xb8, 0x9f, 0x9b, 0x27, 0x6a, 0xfe, 0xc2, 0x43,
+	0xfb, 0x63, 0x77, 0x9b, 0xd5, 0xfe, 0x7a, 0x31, 0x97, 0x42, 0x7e, 0x75,
+	0x33, 0x0e, 0xf7, 0x71, 0xbd, 0xbe, 0xe1, 0x57, 0x13, 0x3e, 0xd1, 0xb7,
+	0x93, 0xfc, 0x21, 0x22, 0x01, 0xf8, 0xa7, 0xef, 0x45, 0xed, 0x4f, 0xcc,
+	0x57, 0x52, 0xbf, 0x75, 0x89, 0x6e, 0xaf, 0x41, 0xfc, 0x95, 0x41, 0xd0,
+	0x08, 0xd7, 0xf9, 0x39, 0xb3, 0x8f, 0x81, 0x9e, 0xf6, 0xe8, 0xba, 0x8c,
+	0x7e, 0xfe, 0x95, 0x47, 0x31, 0xc8, 0x20, 0x35, 0xa1, 0x3e, 0x77, 0x36,
+	0x18, 0xb4, 0xde, 0xd3, 0x04, 0x3c, 0x89, 0x3a, 0xdd, 0xe7, 0xf0, 0xe1,
+	0x3e, 0x50, 0x99, 0xe9, 0x77, 0xd6, 0x7e, 0x58, 0x68, 0xe9, 0x07, 0xfa,
+	0x3c, 0xed, 0x47, 0x2d, 0x97, 0x86, 0xb2, 0xaf, 0x58, 0xfb, 0xa1, 0xee,
+	0x13, 0x4b, 0xdc, 0x27, 0x4a, 0xc4, 0xc5, 0x14, 0xec, 0x9a, 0x4b, 0x65,
+	0xe3, 0x4f, 0x9f, 0xa7, 0xe5, 0x41, 0x6f, 0x6d, 0x47, 0x46, 0x3e, 0xce,
+	0x3f, 0xc0, 0x7a, 0xfe, 0x4c, 0xf7, 0xd8, 0x08, 0xdb, 0xa3, 0xe4, 0x62,
+	0x7e, 0x3b, 0xf7, 0xe7, 0x84, 0x39, 0xb6, 0xf7, 0xd5, 0x6e, 0xd2, 0xab,
+	0x98, 0xf1, 0x16, 0xb1, 0xe4, 0x03, 0xf8, 0x4b, 0x5b, 0x41, 0x27, 0x5b,
+	0x75, 0x1c, 0x74, 0xbc, 0x74, 0x7c, 0x10, 0xc7, 0xc8, 0x3a, 0x62, 0x6b,
+	0xef, 0x5b, 0x47, 0x7d, 0xa4, 0xb5, 0x6f, 0x51, 0xe3, 0x0f, 0xfb, 0x77,
+	0x47, 0x15, 0xff, 0xeb, 0xe2, 0x2a, 0xe1, 0x50, 0x88, 0x1f, 0x98, 0x66,
+	0xfa, 0x15, 0x07, 0xc0, 0xcc, 0x57, 0x8e, 0x5f, 0x01, 0x4f, 0xb7, 0xe9,
+	0x7a, 0xae, 0xe3, 0x65, 0xcd, 0xd7, 0x78, 0x0e, 0x6e, 0x33, 0x75, 0x59,
+	0xdb, 0xa9, 0xf8, 0xa3, 0x8c, 0x47, 0x9f, 0xe8, 0xdc, 0x86, 0x7b, 0x6e,
+	0xc8, 0x8b, 0xba, 0x1f, 0xf2, 0x5a, 0xe3, 0x25, 0x71, 0x51, 0xe8, 0x55,
+	0xc3, 0xea, 0xe2, 0x42, 0xb2, 0xe7, 0xd4, 0xa5, 0x6f, 0x69, 0xf9, 0xfd,
+	0xe9, 0x00, 0xe6, 0xcb, 0x76, 0x86, 0xc9, 0x1f, 0x53, 0xc0, 0xf3, 0xbb,
+	0x93, 0xa0, 0xef, 0x88, 0x17, 0xb0, 0xbf, 0xf8, 0x04, 0xdd, 0x03, 0x7d,
+	0x65, 0x8c, 0xcf, 0x72, 0xd4, 0x89, 0xe4, 0x34, 0xdd, 0x4b, 0x96, 0x97,
+	0x45, 0x50, 0x51, 0x8f, 0xd9, 0x6f, 0x80, 0x4f, 0xb7, 0x25, 0xce, 0x0f,
+	0xc2, 0x2b, 0xdd, 0x2b, 0x25, 0x1e, 0xb1, 0x9d, 0x71, 0xeb, 0xcb, 0xc6,
+	0xad, 0xf6, 0x47, 0xb9, 0x33, 0x2f, 0x4e, 0x37, 0xd8, 0x71, 0xea, 0x61,
+	0x9c, 0xde, 0x33, 0xfb, 0x7b, 0xae, 0x5c, 0xf4, 0xf9, 0x8b, 0xff, 0x1b,
+	0x6e, 0x41, 0xb7, 0xd7, 0xab, 0xf3, 0xcb, 0x72, 0xea, 0x71, 0x8d, 0x2d,
+	0xce, 0x4d, 0xf7, 0xb5, 0x5e, 0x27, 0x3c, 0xd6, 0xf5, 0x66, 0xb3, 0x9f,
+	0x1d, 0xe1, 0x77, 0x5e, 0xda, 0xa0, 0x1f, 0xb1, 0x3b, 0x49, 0x1a, 0x1a,
+	0x15, 0x67, 0x15, 0x5f, 0x63, 0xec, 0x08, 0xd7, 0xdb, 0x4b, 0x2e, 0xd4,
+	0x9b, 0xfe, 0x03, 0x18, 0x5f, 0xe6, 0xfa, 0x71, 0x77, 0x0d, 0xd5, 0xe5,
+	0xd8, 0x91, 0xf3, 0x5a, 0x1e, 0xc9, 0x31, 0xd2, 0x5c, 0xd7, 0x9f, 0x77,
+	0x71, 0xbd, 0x25, 0xbf, 0xb9, 0x63, 0x7f, 0xd0, 0x7d, 0xc6, 0x2d, 0x3a,
+	0x9f, 0x54, 0xb4, 0x42, 0xd6, 0x6f, 0x3e, 0xff, 0x19, 0xd0, 0x1e, 0x2f,
+	0xa8, 0x68, 0xb2, 0xc7, 0x43, 0x98, 0x76, 0x61, 0xe4, 0xa9, 0x63, 0x39,
+	0xbd, 0x18, 0x7b, 0xf9, 0x5e, 0x36, 0xcd, 0x7e, 0x0a, 0x91, 0x3f, 0x8a,
+	0xa4, 0x9d, 0x8a, 0x86, 0x63, 0xa3, 0xb3, 0xd0, 0x7f, 0x68, 0x2b, 0xec,
+	0x5b, 0x62, 0xbb, 0x99, 0x86, 0xde, 0x1e, 0x23, 0xfc, 0x85, 0xc6, 0xf1,
+	0x0e, 0x09, 0x79, 0xc6, 0x60, 0xc7, 0x50, 0x1a, 0xe3, 0xa5, 0xcd, 0xa0,
+	0x7f, 0x6d, 0xc1, 0xbe, 0xa3, 0xc7, 0xd9, 0x1f, 0x5b, 0xf3, 0xef, 0xeb,
+	0xbf, 0x07, 0xbe, 0xe1, 0x46, 0x75, 0xfe, 0xe0, 0x0c, 0xbf, 0x5f, 0xc4,
+	0x80, 0x4b, 0x8d, 0x07, 0x8c, 0x34, 0x8f, 0x0f, 0x71, 0x7d, 0xbf, 0xcd,
+	0xef, 0x8d, 0xa1, 0xac, 0xf7, 0xc6, 0x02, 0xee, 0x99, 0x33, 0xe9, 0x24,
+	0x70, 0x91, 0x28, 0xcc, 0x7e, 0xaf, 0xaa, 0x71, 0x75, 0xac, 0x8c, 0xe3,
+	0x54, 0xba, 0x1e, 0x74, 0x72, 0x3d, 0xde, 0x09, 0x43, 0xc7, 0xd8, 0x2f,
+	0xed, 0x14, 0xa7, 0x96, 0xc5, 0xd9, 0x95, 0xde, 0xc9, 0xe0, 0x9b, 0xe2,
+	0x73, 0x23, 0xdc, 0x4f, 0x22, 0xc8, 0x3f, 0x51, 0x9e, 0xe4, 0x77, 0xcb,
+	0x04, 0xee, 0x9d, 0x53, 0x06, 0x68, 0x24, 0xa8, 0xf5, 0x45, 0x3e, 0x26,
+	0x52, 0xc8, 0x3b, 0xac, 0x3b, 0x2c, 0xeb, 0x7c, 0x1f, 0xc9, 0x79, 0xe7,
+	0x28, 0xba, 0xe4, 0x28, 0x71, 0x68, 0x3b, 0xb1, 0xda, 0x17, 0x54, 0xf8,
+	0xbd, 0x69, 0xe6, 0xd5, 0x02, 0xf9, 0xad, 0x6a, 0x26, 0x4d, 0xfa, 0x57,
+	0x8a, 0x12, 0xea, 0xc3, 0x15, 0xa1, 0x45, 0xf8, 0x31, 0x36, 0xcd, 0xfe,
+	0x1f, 0xd9, 0x04, 0x7a, 0x8c, 0xf1, 0xa7, 0x71, 0x75, 0x65, 0xa3, 0x41,
+	0xfb, 0xe6, 0x47, 0x71, 0x8e, 0xbe, 0x47, 0x64, 0xbf, 0xc7, 0x35, 0x1e,
+	0x2b, 0xda, 0x50, 0x48, 0xfb, 0x8f, 0xaa, 0x73, 0x82, 0x12, 0x47, 0x4a,
+	0x7f, 0xe9, 0x13, 0xce, 0x47, 0x3b, 0x4e, 0x15, 0x8e, 0x75, 0x7e, 0x58,
+	0xf1, 0x9d, 0x9d, 0xef, 0x19, 0xbc, 0x86, 0xe8, 0x5e, 0x2e, 0x8b, 0x5c,
+	0x82, 0xdf, 0x4d, 0x7c, 0x3f, 0x58, 0x29, 0x7e, 0x6f, 0x23, 0x7e, 0x31,
+	0xd6, 0xdb, 0x18, 0x18, 0x43, 0x5f, 0x1c, 0x67, 0x1c, 0x2d, 0x34, 0xf2,
+	0xfd, 0x87, 0xf5, 0xfb, 0x8d, 0xdf, 0x67, 0xc0, 0x9b, 0xd7, 0x88, 0xcf,
+	0x32, 0xbe, 0x18, 0xf7, 0x87, 0xd8, 0xee, 0xdb, 0xb0, 0xdb, 0xd0, 0x76,
+	0x0f, 0x98, 0x76, 0xeb, 0xfb, 0x95, 0x55, 0x4e, 0xb1, 0xc4, 0xad, 0xa2,
+	0xab, 0x8c, 0x2b, 0x54, 0xcf, 0x0a, 0xd8, 0x4e, 0xc9, 0xd7, 0xa6, 0xec,
+	0x09, 0xb1, 0x3d, 0x41, 0x71, 0xb0, 0xc5, 0xba, 0x2f, 0xc0, 0xfb, 0xfc,
+	0x72, 0x1f, 0xe6, 0x51, 0x17, 0x8c, 0x15, 0xfc, 0xa9, 0xfc, 0xa6, 0xe5,
+	0x66, 0xe7, 0xbd, 0xd5, 0x7f, 0x74, 0x23, 0xa5, 0x0f, 0xea, 0x9b, 0x8c,
+	0x53, 0x33, 0xfe, 0x3f, 0xd0, 0xf5, 0xed, 0x2e, 0xdd, 0x5f, 0xfd, 0x67,
+	0x86, 0x51, 0x9f, 0xce, 0x0c, 0x9f, 0xe5, 0x77, 0x07, 0xfb, 0xa5, 0x9b,
+	0xfe, 0xb7, 0x90, 0xb1, 0xab, 0xb3, 0xd7, 0x37, 0xbb, 0x1e, 0x55, 0x16,
+	0x3d, 0xf4, 0xb9, 0xff, 0x00, 0x0e, 0x4b, 0x7c, 0x26, 0x30, 0x14, 0x00,
+	0x00, 0x00 };
+
 static u8 bnx2_TPAT_b09FwText[] = {
-	0xcd, 0x58, 0x5d, 0x6c, 0x1c, 0x57, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0xde,
-	0x38, 0xf1, 0x24, 0x19, 0xca, 0xa6, 0x72, 0xe9, 0x8c, 0x3d, 0x76, 0x8c,
-	0x6c, 0x35, 0xd3, 0x76, 0xd5, 0x58, 0x68, 0xa4, 0x4e, 0x67, 0x76, 0x1d,
-	0x2b, 0xf4, 0xc1, 0x85, 0x48, 0x3c, 0xf0, 0xe2, 0xae, 0x1d, 0x05, 0x78,
-	0x2a, 0x28, 0x0f, 0x11, 0x2f, 0x59, 0x76, 0x37, 0xfd, 0x41, 0xdb, 0x2c,
-	0x35, 0xc8, 0x41, 0x02, 0xa4, 0xb0, 0x69, 0xe2, 0x97, 0xad, 0x27, 0x2d,
-	0x45, 0xea, 0x4b, 0x95, 0x28, 0x55, 0x2b, 0xc4, 0x13, 0x2f, 0x54, 0x79,
-	0xac, 0x52, 0x5a, 0xf1, 0x00, 0x28, 0x42, 0x15, 0xaa, 0x68, 0xf0, 0xe5,
-	0x3b, 0x77, 0x66, 0xdc, 0xdd, 0xc4, 0x49, 0xcb, 0x9f, 0x84, 0xa5, 0xf5,
-	0x9d, 0xb9, 0xf7, 0x9e, 0x73, 0xcf, 0x3d, 0x3f, 0xdf, 0x39, 0x67, 0xca,
-	0x2a, 0x95, 0x28, 0xfb, 0xdb, 0x8d, 0xdf, 0xc9, 0xa7, 0x9f, 0x39, 0x79,
-	0xf8, 0xa1, 0x47, 0x1d, 0xa2, 0x87, 0x1f, 0x52, 0x94, 0xa2, 0x46, 0xff,
-	0x85, 0x3f, 0x30, 0xb1, 0x72, 0xfe, 0xfc, 0x23, 0x53, 0x0d, 0x7e, 0xe3,
-	0x44, 0x1e, 0x99, 0x5a, 0xb0, 0xf4, 0xe5, 0x15, 0x8f, 0x28, 0xec, 0xcf,
-	0x3a, 0x31, 0xfd, 0x43, 0x34, 0x6c, 0x9d, 0x78, 0xfe, 0x81, 0xe0, 0xd6,
-	0xa1, 0x37, 0x0f, 0xbb, 0x37, 0xcf, 0x6b, 0x64, 0x5a, 0xc1, 0xb2, 0x69,
-	0x4d, 0x93, 0x39, 0x1e, 0x5c, 0x75, 0x7e, 0x7e, 0x30, 0x28, 0xd0, 0x9e,
-	0x9c, 0x97, 0x4d, 0xcd, 0x2e, 0x35, 0xf4, 0xc0, 0xa4, 0x5a, 0xe7, 0x94,
-	0x12, 0x75, 0x3d, 0xab, 0x0a, 0x1e, 0xa1, 0x0d, 0xfe, 0x1e, 0xde, 0x13,
-	0x5d, 0xa9, 0x9e, 0x33, 0x49, 0x0d, 0x42, 0x3c, 0xcf, 0x51, 0xab, 0x2b,
-	0xc4, 0x0f, 0x7d, 0x85, 0x56, 0x7c, 0x93, 0x96, 0x2d, 0x77, 0x31, 0x54,
-	0xb6, 0x44, 0x3c, 0x25, 0xc4, 0xb7, 0x7d, 0x95, 0x54, 0x6f, 0x41, 0x89,
-	0x36, 0x16, 0x95, 0x78, 0x63, 0x91, 0xf5, 0x01, 0xf9, 0x16, 0x94, 0x70,
-	0x83, 0xc7, 0xc0, 0x8c, 0x3b, 0x7b, 0x68, 0xd9, 0xa6, 0x31, 0xd5, 0x9b,
-	0xc3, 0x79, 0x65, 0xf0, 0x71, 0x28, 0xf2, 0x67, 0x2d, 0x95, 0x26, 0xf1,
-	0x1b, 0xa1, 0x9a, 0x4f, 0x23, 0xaa, 0xa7, 0x52, 0xdd, 0x56, 0xe8, 0xe5,
-	0x8a, 0x81, 0xdf, 0x51, 0xa5, 0xba, 0xf1, 0x9d, 0x8c, 0x0f, 0xef, 0x37,
-	0xb1, 0xc6, 0x32, 0x33, 0xfd, 0x20, 0xed, 0x6e, 0x3c, 0x7f, 0x0b, 0xfb,
-	0x0c, 0x8a, 0x2a, 0xb7, 0xaf, 0x8d, 0xe0, 0x59, 0xc1, 0xfc, 0x51, 0xc8,
-	0xc5, 0x7c, 0x1c, 0xc8, 0x31, 0x4e, 0xed, 0xee, 0x22, 0xee, 0x53, 0xa0,
-	0x86, 0x35, 0x35, 0x53, 0x27, 0x1d, 0x34, 0x1a, 0x85, 0xf6, 0x15, 0xa1,
-	0x06, 0x42, 0x44, 0x15, 0x6f, 0xa6, 0x27, 0xcf, 0x50, 0x49, 0xf3, 0x0a,
-	0x54, 0xf5, 0x77, 0x53, 0xcb, 0xd2, 0xa8, 0x39, 0x67, 0x50, 0xb8, 0xa4,
-	0xe3, 0x8e, 0xfb, 0x40, 0xa7, 0x80, 0xfe, 0xa5, 0xcc, 0xe6, 0x45, 0x6a,
-	0x5a, 0x05, 0xcc, 0x8f, 0x51, 0xd3, 0xde, 0xab, 0xa8, 0xc1, 0x0b, 0x98,
-	0x9f, 0xb2, 0x7a, 0xf4, 0x3c, 0x46, 0x05, 0xef, 0x7b, 0xb1, 0x97, 0xdf,
-	0x15, 0xf0, 0x23, 0x2b, 0x4a, 0x66, 0xa8, 0x95, 0xe4, 0xb4, 0x3c, 0x9f,
-	0xce, 0x35, 0x92, 0xdb, 0xed, 0x8d, 0x7d, 0xdd, 0x1a, 0x74, 0xcc, 0xb6,
-	0xc1, 0x9e, 0xdc, 0x2e, 0xd2, 0x07, 0x1e, 0xe7, 0x79, 0xfe, 0xc3, 0xbc,
-	0x43, 0x5a, 0xe0, 0x59, 0x31, 0x7d, 0x85, 0xd2, 0xb5, 0x54, 0xf6, 0xc8,
-	0x7f, 0x2c, 0x7b, 0xb7, 0xad, 0xe8, 0xdc, 0xa3, 0xb8, 0x9f, 0x74, 0x19,
-	0x3c, 0xdb, 0xb8, 0x7f, 0x01, 0xfe, 0xd1, 0x0c, 0x55, 0x6a, 0x94, 0x4d,
-	0x72, 0xe7, 0x57, 0xb1, 0xf2, 0x41, 0x47, 0xa3, 0x98, 0x75, 0xe5, 0xeb,
-	0x19, 0x1d, 0xfb, 0xc6, 0xbb, 0x90, 0xb3, 0x61, 0x99, 0x70, 0xbc, 0xe5,
-	0x63, 0x42, 0x5c, 0xf4, 0x85, 0x28, 0x04, 0xde, 0xcc, 0x25, 0x9a, 0x2d,
-	0x1b, 0x34, 0x6d, 0x61, 0x84, 0x8e, 0xbd, 0x72, 0x9d, 0x8c, 0x5c, 0x9e,
-	0xdc, 0x37, 0xf1, 0xd7, 0x57, 0x08, 0x3e, 0x79, 0xa3, 0xf3, 0x7b, 0xd6,
-	0xc7, 0xcc, 0x82, 0xa4, 0x11, 0xa2, 0x37, 0x7f, 0x2f, 0x9a, 0x5f, 0x67,
-	0x34, 0x42, 0xd4, 0x2a, 0x7c, 0xae, 0x8b, 0x3b, 0xb3, 0x7f, 0x13, 0xd5,
-	0xfa, 0xbe, 0x59, 0xef, 0x40, 0x3e, 0x0f, 0x63, 0x9f, 0xa8, 0xde, 0xe5,
-	0x7b, 0x98, 0xd4, 0x84, 0xde, 0x5a, 0xd8, 0xaf, 0x56, 0x76, 0xb1, 0x7f,
-	0xc0, 0xc6, 0x4b, 0x66, 0xb5, 0xe3, 0x96, 0x5f, 0xa0, 0x25, 0x33, 0xee,
-	0xcf, 0x96, 0x57, 0xe9, 0x01, 0x3e, 0xc7, 0x34, 0x82, 0x63, 0x66, 0x4f,
-	0xd2, 0x1b, 0x1a, 0x95, 0xf0, 0x0c, 0x1e, 0xcd, 0x0e, 0x29, 0x91, 0xbf,
-	0x8b, 0xef, 0x0b, 0xba, 0xc5, 0x8c, 0x6e, 0x31, 0xa3, 0x1b, 0xcb, 0xe8,
-	0x9e, 0x1c, 0xa0, 0x7b, 0x92, 0xe9, 0xb0, 0x37, 0xcc, 0xf6, 0x86, 0xd9,
-	0x5e, 0x3d, 0xdb, 0x5b, 0xcd, 0xf6, 0x62, 0xec, 0x3b, 0x90, 0xcf, 0x9d,
-	0x09, 0x15, 0xc8, 0xe8, 0x89, 0x07, 0x23, 0x9f, 0xc2, 0xd8, 0x73, 0xaf,
-	0xc7, 0xda, 0x18, 0x5d, 0xf0, 0x2d, 0x6a, 0x27, 0x0e, 0x64, 0x6f, 0x53,
-	0x94, 0xa8, 0xa0, 0x1d, 0xa3, 0x9e, 0x77, 0x53, 0xd4, 0xfc, 0x0a, 0x6c,
-	0x37, 0xca, 0x74, 0xe5, 0x1a, 0x14, 0xd1, 0x4c, 0x66, 0xad, 0x55, 0xaa,
-	0xc0, 0x5f, 0x54, 0xd8, 0x6f, 0x52, 0x3e, 0x37, 0x93, 0x0a, 0xd6, 0xa9,
-	0xa1, 0x56, 0x5c, 0xab, 0x49, 0x6e, 0x39, 0xd2, 0xc8, 0x52, 0x03, 0x1b,
-	0x7b, 0x1a, 0x54, 0x4d, 0x4c, 0x7a, 0x4f, 0x3b, 0x25, 0xe3, 0xb4, 0xd9,
-	0xbd, 0x2e, 0xde, 0x3c, 0xe8, 0xd0, 0x95, 0x64, 0x9c, 0x7e, 0x95, 0x94,
-	0xe9, 0xb5, 0xc4, 0xa6, 0x57, 0x13, 0x52, 0x23, 0x1f, 0x7e, 0x6c, 0x5b,
-	0x74, 0x39, 0x19, 0xd4, 0xfb, 0x07, 0xac, 0x77, 0x73, 0x7f, 0x40, 0xe6,
-	0xbe, 0x80, 0x1a, 0x5a, 0x90, 0xe2, 0x40, 0x9c, 0xe2, 0x80, 0xf4, 0xa9,
-	0x56, 0xb7, 0x79, 0xbf, 0x06, 0x0c, 0x5a, 0xf1, 0xc3, 0xbd, 0x1a, 0xec,
-	0x12, 0x23, 0x0a, 0xd4, 0xed, 0x51, 0xda, 0xc8, 0x5d, 0xf1, 0xdc, 0xe7,
-	0x63, 0xec, 0xf6, 0xce, 0x1a, 0x98, 0xbd, 0xdd, 0xb6, 0x7f, 0xc6, 0x19,
-	0xa3, 0xb0, 0x9b, 0x46, 0x4f, 0xe8, 0x88, 0x1f, 0xef, 0x23, 0x8d, 0x63,
-	0xc0, 0xd9, 0xb4, 0xe9, 0x4c, 0x97, 0x68, 0x62, 0xd3, 0xa4, 0x8d, 0x4e,
-	0x91, 0x9c, 0xde, 0x28, 0xad, 0x74, 0x4b, 0x34, 0x79, 0x49, 0xc7, 0xde,
-	0x5d, 0x34, 0xb9, 0xa6, 0xda, 0x1c, 0xcb, 0x31, 0x74, 0x3c, 0xd1, 0x13,
-	0xf0, 0xd1, 0x12, 0x4d, 0xac, 0xbb, 0xd2, 0x7f, 0x56, 0xbc, 0x96, 0xaf,
-	0xd1, 0x0f, 0xe8, 0xda, 0x5c, 0x01, 0x77, 0xb2, 0xc9, 0x9f, 0x1e, 0x3c,
-	0xcf, 0x80, 0x9b, 0xf1, 0x1c, 0x98, 0xee, 0x71, 0x1d, 0x52, 0x99, 0x9f,
-	0x49, 0x13, 0x97, 0x4c, 0x25, 0xee, 0xb2, 0xce, 0xd8, 0x07, 0xcd, 0xcc,
-	0x07, 0x75, 0x25, 0x3a, 0x57, 0xc4, 0x59, 0x7f, 0x12, 0x91, 0x07, 0xdf,
-	0x03, 0x96, 0xad, 0x54, 0xbe, 0x0f, 0xf9, 0x30, 0xd7, 0xe3, 0xb5, 0x9b,
-	0xd9, 0x3c, 0xf3, 0x00, 0x46, 0xf8, 0xfb, 0x29, 0x62, 0x3c, 0x38, 0xc6,
-	0x34, 0x45, 0x9a, 0x58, 0x63, 0x8c, 0xc1, 0xd8, 0xe3, 0x77, 0xbe, 0xdb,
-	0x08, 0xd5, 0xa1, 0x95, 0xfa, 0x8c, 0x0d, 0xb9, 0x54, 0x89, 0x19, 0x75,
-	0x60, 0x88, 0xea, 0x95, 0x30, 0xf2, 0x79, 0x3f, 0xd3, 0xd2, 0xf8, 0xb7,
-	0xa5, 0xbd, 0x63, 0xf8, 0xaf, 0x0e, 0x79, 0x56, 0x69, 0xaa, 0x7c, 0x5c,
-	0xae, 0x61, 0xae, 0xcf, 0x6b, 0xd6, 0x6d, 0x6b, 0x78, 0xef, 0xe7, 0x32,
-	0x20, 0xc6, 0xbd, 0x16, 0x4e, 0x31, 0x32, 0xbd, 0xf0, 0xfe, 0x46, 0x19,
-	0xb6, 0x01, 0xa6, 0x11, 0x74, 0x49, 0xd4, 0xeb, 0xe8, 0xc0, 0x1c, 0xf5,
-	0x8b, 0x2a, 0xd3, 0xd9, 0xcc, 0x07, 0xf7, 0x5f, 0xd7, 0x95, 0xf8, 0x9c,
-	0xe7, 0xfc, 0x81, 0x98, 0x7e, 0x12, 0x3a, 0x98, 0x9a, 0x6f, 0xf1, 0xfe,
-	0xbe, 0x41, 0xde, 0x5a, 0xc3, 0xd2, 0x61, 0x53, 0x15, 0x06, 0x8d, 0x7f,
-	0x34, 0x06, 0x5b, 0xbb, 0x4e, 0x8b, 0x7e, 0x07, 0x79, 0x0a, 0xe4, 0xf5,
-	0x74, 0x7a, 0xb9, 0xc3, 0xba, 0x30, 0x69, 0x72, 0x5d, 0x88, 0xe7, 0x7c,
-	0xb6, 0xc9, 0xbb, 0xd0, 0x0b, 0xe1, 0x86, 0x53, 0xf3, 0x37, 0x60, 0x9f,
-	0x8d, 0x3e, 0xdb, 0xc6, 0x90, 0x3a, 0xf1, 0xd6, 0xe6, 0x60, 0xd7, 0x99,
-	0x4c, 0x46, 0xb6, 0x97, 0x4e, 0xed, 0x8a, 0x4a, 0x17, 0x2b, 0x9f, 0x08,
-	0xd5, 0x63, 0x8c, 0x2d, 0x40, 0xb7, 0xd8, 0xd7, 0xc3, 0xbe, 0xa4, 0x00,
-	0x1d, 0xfe, 0x4d, 0x18, 0xc0, 0xdf, 0x8b, 0x15, 0xcc, 0xaf, 0x9d, 0x86,
-	0xac, 0x1a, 0x68, 0x53, 0x1f, 0x63, 0x79, 0x16, 0x3a, 0xf9, 0xfd, 0xbc,
-	0xf9, 0xb7, 0x25, 0xbf, 0x51, 0x9a, 0xde, 0x1c, 0xa5, 0x13, 0xfd, 0x51,
-	0x9a, 0x38, 0xcb, 0x34, 0x42, 0xb4, 0x2b, 0x8c, 0x91, 0xf0, 0x51, 0x4f,
-	0xea, 0xa1, 0xac, 0xa9, 0x7c, 0x4f, 0xac, 0x6f, 0x12, 0xad, 0xf6, 0xf9,
-	0x0c, 0x7d, 0x80, 0xa7, 0x4a, 0x47, 0x7e, 0x42, 0x74, 0xa4, 0xcf, 0xb4,
-	0xdb, 0xba, 0x03, 0x5f, 0x0b, 0x3c, 0x2d, 0xe2, 0x5c, 0xa4, 0x79, 0xc8,
-	0x79, 0x1b, 0x11, 0x72, 0x58, 0x15, 0xbf, 0x05, 0xe4, 0x35, 0xbe, 0xff,
-	0x1c, 0xe2, 0x8f, 0xb1, 0x7c, 0x0b, 0x77, 0x2f, 0x50, 0xdb, 0x5f, 0xc4,
-	0x1e, 0xb6, 0xf1, 0x51, 0xac, 0xef, 0x46, 0x2e, 0xc8, 0x72, 0x85, 0xc5,
-	0xb9, 0x62, 0x2f, 0xe2, 0x60, 0x04, 0xf8, 0x7f, 0xbf, 0x3e, 0x9c, 0x2b,
-	0xb0, 0xcf, 0x3e, 0x80, 0xdc, 0x80, 0x44, 0x5d, 0x62, 0x5e, 0xfb, 0x31,
-	0x8e, 0xe0, 0xfd, 0x00, 0xf6, 0x0e, 0xe6, 0x89, 0x9c, 0xee, 0x6e, 0x39,
-	0x02, 0x31, 0xb1, 0x86, 0x58, 0x59, 0x9f, 0x61, 0xcc, 0x80, 0x3d, 0xd8,
-	0xa6, 0x45, 0x60, 0xb8, 0x09, 0x1e, 0x6c, 0xdb, 0x22, 0x6c, 0xc8, 0x79,
-	0xce, 0xa2, 0xc9, 0x4d, 0x8e, 0xeb, 0x34, 0x8f, 0xc4, 0xdb, 0x79, 0x84,
-	0x64, 0x4c, 0x34, 0x13, 0xf6, 0x89, 0xd0, 0x8c, 0xce, 0x6e, 0x09, 0xc4,
-	0x70, 0x39, 0x66, 0x5c, 0xdb, 0x9c, 0x05, 0xbd, 0x86, 0xf8, 0xa8, 0x9a,
-	0xf5, 0xb3, 0x29, 0xa6, 0xd5, 0x37, 0x1d, 0xe9, 0x93, 0xcd, 0xc4, 0xc2,
-	0x3b, 0x63, 0x5a, 0x8e, 0x61, 0x4c, 0x4f, 0x61, 0x04, 0x7c, 0x8b, 0x34,
-	0x21, 0x56, 0xfc, 0x31, 0xaa, 0xc3, 0x3f, 0x43, 0xe0, 0x5a, 0x1d, 0xb8,
-	0x16, 0x0f, 0xe0, 0x5a, 0xfc, 0x99, 0xb8, 0x06, 0xcc, 0xea, 0x02, 0xb3,
-	0x50, 0x23, 0xbc, 0x06, 0x8c, 0x7f, 0x15, 0xe7, 0x5d, 0xee, 0xee, 0x84,
-	0x75, 0x8c, 0x73, 0x8c, 0x77, 0x33, 0xf4, 0xe6, 0xc1, 0x7f, 0x15, 0xef,
-	0xda, 0xc0, 0x06, 0x93, 0xbe, 0x7b, 0xf0, 0xde, 0x98, 0x77, 0x06, 0x98,
-	0x67, 0x7c, 0x36, 0xe6, 0x35, 0x18, 0xf3, 0x74, 0xf8, 0x60, 0x03, 0x78,
-	0xa0, 0xae, 0x0d, 0x9e, 0xd3, 0xc1, 0x39, 0x3c, 0xa7, 0x67, 0x79, 0x55,
-	0xa5, 0x1e, 0xfc, 0x5f, 0xf3, 0xf8, 0x9c, 0x39, 0xd6, 0xbb, 0xd4, 0xff,
-	0x13, 0xba, 0x4d, 0xc6, 0x34, 0xfc, 0x62, 0x6d, 0x94, 0xb4, 0xb3, 0x9f,
-	0xfa, 0x3d, 0x6a, 0x03, 0xc4, 0x3b, 0xfe, 0x6d, 0xe6, 0x3c, 0x4a, 0xc0,
-	0x1c, 0x9d, 0x0a, 0x6b, 0x06, 0xde, 0x95, 0xa1, 0x7d, 0x47, 0x90, 0x77,
-	0xb4, 0xc0, 0x9d, 0x7f, 0x9f, 0x9f, 0xfb, 0xbc, 0xa7, 0x44, 0xea, 0xba,
-	0xeb, 0x38, 0xaa, 0xeb, 0x5f, 0x03, 0x46, 0xbc, 0xe3, 0x31, 0x0e, 0x36,
-	0xe1, 0x0d, 0x05, 0xd2, 0xd7, 0xc4, 0x69, 0x23, 0xe0, 0xb3, 0x1b, 0x0e,
-	0xe2, 0xdd, 0x79, 0x09, 0x7e, 0xc4, 0x39, 0xf4, 0x22, 0xe2, 0xa7, 0x96,
-	0xc5, 0x6a, 0xab, 0x9f, 0x9f, 0xb9, 0x0f, 0x72, 0x1b, 0xa0, 0x19, 0xdc,
-	0xcb, 0x71, 0x20, 0xc4, 0x09, 0xdc, 0x49, 0xc3, 0x39, 0xc6, 0xba, 0x49,
-	0x85, 0x75, 0xd6, 0x8b, 0x0b, 0xfa, 0x49, 0x6b, 0x81, 0xae, 0x0f, 0xe1,
-	0xc2, 0x73, 0xfd, 0xeb, 0x3a, 0x63, 0xa9, 0x86, 0x18, 0x2d, 0xe2, 0x5c,
-	0x63, 0x9b, 0x17, 0x65, 0xbc, 0x98, 0xde, 0x2b, 0x9f, 0xd8, 0xa6, 0x67,
-	0x7c, 0x9b, 0x2a, 0x33, 0x8e, 0xb1, 0x1c, 0x9a, 0xc4, 0xd4, 0x52, 0x86,
-	0xa9, 0x93, 0xb0, 0x67, 0x49, 0xc6, 0xa7, 0xea, 0x3d, 0x98, 0xe1, 0xea,
-	0x5e, 0x8c, 0x3c, 0x27, 0xb2, 0x78, 0xd1, 0x21, 0x2f, 0xf3, 0x2d, 0x91,
-	0xb6, 0xce, 0x35, 0x04, 0xdf, 0xe9, 0xaf, 0xf0, 0x6d, 0xc6, 0x0a, 0xf6,
-	0x4f, 0x89, 0xa9, 0x98, 0x9f, 0x82, 0xcc, 0x8c, 0x0f, 0x4c, 0xc7, 0xf4,
-	0x3b, 0xd1, 0xfd, 0x05, 0x74, 0xd6, 0x0e, 0x74, 0x98, 0xdb, 0x64, 0x1a,
-	0xc6, 0x88, 0x7d, 0xd8, 0x1f, 0x31, 0x3e, 0x40, 0x67, 0x4c, 0x3b, 0x9e,
-	0xc5, 0x63, 0x15, 0x6b, 0x5c, 0x03, 0xcb, 0xf8, 0x22, 0x23, 0xe0, 0x7b,
-	0x70, 0x7d, 0xcc, 0xf9, 0x91, 0x6b, 0x52, 0xae, 0x3d, 0xf3, 0x5a, 0xd5,
-	0x9b, 0xa9, 0xdd, 0xad, 0xee, 0xb4, 0x06, 0xeb, 0xce, 0x43, 0xc6, 0xce,
-	0x75, 0xe7, 0x41, 0x23, 0xad, 0x3b, 0xa7, 0x8d, 0xbb, 0xd7, 0x9d, 0x39,
-	0xed, 0xbd, 0xeb, 0xce, 0x66, 0x97, 0xcf, 0xdc, 0x19, 0x2f, 0x56, 0xe0,
-	0xaf, 0xad, 0x24, 0xbf, 0x27, 0xf7, 0x06, 0xa1, 0x59, 0x3b, 0x9b, 0xda,
-	0xbe, 0x29, 0x7d, 0x11, 0x38, 0xb2, 0x39, 0x0b, 0x3b, 0xa2, 0xa6, 0x1e,
-	0xc2, 0x8e, 0x9c, 0x86, 0x75, 0x5a, 0x02, 0x46, 0xb3, 0x3e, 0x8b, 0x19,
-	0x4e, 0x60, 0xf4, 0x3e, 0x06, 0x4e, 0xe4, 0xf8, 0xc2, 0xfc, 0xfe, 0x9f,
-	0xf0, 0x85, 0xcc, 0x11, 0xe0, 0x84, 0x19, 0x30, 0x5e, 0x4a, 0x59, 0x50,
-	0x93, 0x0b, 0xb1, 0xe0, 0x73, 0x0c, 0x0c, 0xf6, 0x4c, 0xec, 0x0f, 0x45,
-	0x7a, 0xcb, 0x67, 0x9f, 0x40, 0xcf, 0xe4, 0x71, 0x8e, 0x64, 0x3c, 0xde,
-	0x12, 0x6f, 0x79, 0x11, 0xe6, 0xaa, 0xb0, 0x3d, 0xfb, 0xc3, 0xa2, 0x72,
-	0x64, 0xc3, 0x04, 0x1d, 0xfb, 0xc4, 0xf8, 0x1d, 0xbd, 0x50, 0xda, 0xb3,
-	0x70, 0x7d, 0xfc, 0xef, 0xfa, 0xc8, 0x1b, 0x77, 0xf1, 0x91, 0xcb, 0x99,
-	0x8f, 0x24, 0xf7, 0xf0, 0x91, 0x37, 0x3e, 0xa7, 0x8f, 0xb8, 0xe5, 0x0f,
-	0x51, 0x3f, 0xbd, 0x0d, 0x39, 0x42, 0x4b, 0x88, 0x0f, 0xfd, 0x9d, 0xfa,
-	0x94, 0xd0, 0xd4, 0x5f, 0x64, 0x9d, 0xa5, 0x79, 0xa5, 0x85, 0x77, 0xed,
-	0x15, 0xae, 0x97, 0x39, 0xe7, 0xa4, 0xb9, 0x65, 0xe2, 0xc5, 0xd4, 0x3f,
-	0x26, 0x5e, 0x11, 0xe2, 0xc2, 0x0e, 0xfe, 0xc0, 0x35, 0xf4, 0x55, 0xf8,
-	0x55, 0x8b, 0xfe, 0x17, 0x35, 0x34, 0x63, 0x78, 0xc5, 0x3c, 0xde, 0xc9,
-	0xed, 0x9f, 0xdb, 0xbe, 0x40, 0xe7, 0xad, 0x3d, 0xd0, 0xdb, 0xa3, 0xd4,
-	0xfa, 0xb1, 0xce, 0x7d, 0x05, 0xfc, 0xe2, 0x71, 0x9d, 0x63, 0x17, 0x7d,
-	0x24, 0x9e, 0x07, 0xeb, 0x6c, 0xf8, 0xa5, 0x5f, 0xc8, 0xe3, 0x65, 0x00,
-	0xfb, 0x4f, 0xa1, 0x54, 0xb9, 0x23, 0xaf, 0x0c, 0xf5, 0xd4, 0x1a, 0x7a,
-	0xea, 0x58, 0xf2, 0xe0, 0xbe, 0x2b, 0xd5, 0x63, 0x5b, 0xf6, 0xd1, 0x5b,
-	0xa2, 0x25, 0x7b, 0xe9, 0x03, 0x05, 0x2a, 0x2d, 0x66, 0x3e, 0xe3, 0x20,
-	0x1f, 0xb9, 0x7e, 0x03, 0xfc, 0xb9, 0xd6, 0x80, 0x1c, 0xb4, 0x8a, 0x58,
-	0xbc, 0x80, 0x3c, 0xbc, 0x02, 0xbd, 0xd4, 0x65, 0x6c, 0x8c, 0xd1, 0x35,
-	0xe4, 0xfe, 0x36, 0xf2, 0xf3, 0x19, 0xe8, 0xa6, 0x05, 0xdd, 0xc4, 0x49,
-	0x1a, 0x27, 0xd7, 0xa0, 0x9b, 0x85, 0x01, 0xdd, 0x2c, 0xfc, 0x47, 0xfd,
-	0xc5, 0x1f, 0x91, 0x6b, 0xcd, 0x65, 0x1d, 0xf3, 0x57, 0x12, 0x99, 0x5b,
-	0x97, 0x5a, 0x1d, 0x6a, 0xdc, 0x1f, 0x9c, 0xe6, 0xda, 0x8e, 0x6b, 0xb3,
-	0xf9, 0x95, 0x0a, 0xe6, 0xfa, 0x26, 0x45, 0xd0, 0xcf, 0x37, 0x0f, 0xd3,
-	0xb2, 0x16, 0xb0, 0x4f, 0xe3, 0x3d, 0xa1, 0x46, 0x74, 0x18, 0xf5, 0x56,
-	0x32, 0xbe, 0x8c, 0x7e, 0x1c, 0xbe, 0xd5, 0xa0, 0x10, 0x72, 0x86, 0xe0,
-	0xbd, 0xd0, 0x31, 0xcd, 0xd5, 0x0e, 0xf7, 0x51, 0x0d, 0xe2, 0x5e, 0xbd,
-	0xd7, 0xbf, 0x09, 0x7e, 0x23, 0xdf, 0x40, 0x7f, 0xeb, 0x34, 0x81, 0xd3,
-	0xcf, 0xc2, 0x6d, 0x5b, 0x36, 0x7f, 0xcb, 0x60, 0x1c, 0x1d, 0x07, 0x8f,
-	0xa7, 0x0b, 0xa9, 0xaf, 0x8e, 0x83, 0x0f, 0xc7, 0x11, 0xe1, 0x3c, 0xd6,
-	0x65, 0xee, 0x7f, 0xe5, 0x81, 0xfa, 0xbe, 0x40, 0x39, 0x86, 0x35, 0xa1,
-	0x37, 0xd6, 0x75, 0xe4, 0x9d, 0x2c, 0xe4, 0xdf, 0x6d, 0x5a, 0xc0, 0x81,
-	0xfa, 0x1c, 0x63, 0x96, 0x02, 0xdf, 0xa3, 0xb4, 0xaf, 0x44, 0x1f, 0x52,
-	0x9f, 0x43, 0xde, 0xb6, 0x8b, 0x72, 0x6c, 0x24, 0xa7, 0xb3, 0xfd, 0xaa,
-	0xdc, 0xc7, 0xf9, 0xa2, 0x99, 0xc8, 0x7e, 0x42, 0xa9, 0x76, 0xc9, 0xa9,
-	0xfb, 0xe8, 0x93, 0x50, 0x7b, 0xb4, 0x13, 0xce, 0xf5, 0x73, 0xa6, 0x2a,
-	0xb1, 0xef, 0x06, 0x68, 0xf0, 0xbc, 0x49, 0x6a, 0xdd, 0xe7, 0xef, 0x0c,
-	0xfc, 0x0d, 0x04, 0xf1, 0x63, 0xd3, 0x6e, 0xd0, 0x43, 0xae, 0x71, 0x96,
-	0x2b, 0xac, 0xcb, 0x3a, 0x85, 0x79, 0x1f, 0x52, 0xd3, 0x6f, 0x33, 0xef,
-	0x66, 0x67, 0x99, 0x88, 0x1f, 0xc6, 0x5d, 0x9f, 0x73, 0xde, 0x97, 0x34,
-	0xba, 0x49, 0x12, 0x37, 0xad, 0x87, 0x91, 0x0b, 0x0f, 0x83, 0x26, 0x94,
-	0x98, 0x93, 0xf6, 0x15, 0x39, 0x8d, 0xa7, 0x0d, 0xf3, 0x58, 0xd6, 0x87,
-	0xdf, 0x43, 0xc4, 0x59, 0x25, 0x3b, 0x6f, 0xd0, 0x67, 0xdf, 0x87, 0xcf,
-	0xde, 0xc8, 0xf6, 0x00, 0x87, 0xed, 0x02, 0xf6, 0xb1, 0x8c, 0x8c, 0x2f,
-	0x4c, 0xb3, 0x65, 0x0c, 0xf3, 0x99, 0xdc, 0x81, 0xc7, 0x47, 0x03, 0x3c,
-	0x6c, 0xbe, 0x9b, 0x55, 0x4f, 0x7b, 0x6c, 0xf9, 0x57, 0x87, 0x9e, 0xd1,
-	0x93, 0xdc, 0xa7, 0xe2, 0x1e, 0x5c, 0x9b, 0xc5, 0x72, 0xfe, 0x97, 0xc5,
-	0x61, 0xbe, 0xa7, 0xb2, 0x73, 0xfc, 0x34, 0x36, 0x3c, 0x8c, 0xc9, 0x8d,
-	0x01, 0xd9, 0x8d, 0x1d, 0xce, 0xdd, 0xa5, 0xa3, 0x35, 0x50, 0xd8, 0xdf,
-	0xb4, 0x80, 0xf3, 0x33, 0x9e, 0xb7, 0xfd, 0x83, 0x7d, 0xf5, 0xb3, 0x7d,
-	0xd4, 0xf8, 0x9c, 0x3e, 0xfa, 0x72, 0x87, 0x71, 0x23, 0xf5, 0xd1, 0xfa,
-	0x1d, 0x3e, 0x8a, 0xfa, 0xc8, 0xce, 0xfd, 0x93, 0xe3, 0x25, 0xf7, 0xcf,
-	0xfc, 0x99, 0x63, 0x1c, 0xb8, 0x9c, 0xe1, 0x5c, 0x13, 0x38, 0x57, 0x95,
-	0x79, 0xcf, 0x2d, 0x57, 0x29, 0x8d, 0xe5, 0x55, 0xc4, 0x72, 0x55, 0xe3,
-	0x3c, 0xc8, 0x31, 0xcc, 0x74, 0x1c, 0xc7, 0x4c, 0x37, 0x96, 0xd1, 0x61,
-	0x44, 0x3c, 0x57, 0xb3, 0x78, 0x6e, 0x75, 0x5d, 0xa7, 0x9a, 0xc5, 0x73,
-	0x0b, 0x31, 0xdc, 0xce, 0xe2, 0xb9, 0x95, 0xc5, 0x33, 0x7f, 0xdf, 0xd3,
-	0x2a, 0x9c, 0x1b, 0x5d, 0x27, 0x06, 0xc6, 0xb5, 0x25, 0xcf, 0x06, 0xee,
-	0x09, 0x19, 0xbb, 0x79, 0x5c, 0xdc, 0xf1, 0x1d, 0x0c, 0xf7, 0xf9, 0x34,
-	0xd7, 0xd4, 0x90, 0x6b, 0x2e, 0x20, 0xd7, 0xf4, 0x06, 0xbe, 0x83, 0x9d,
-	0x97, 0xb9, 0xe6, 0xeb, 0xc5, 0x3c, 0xd7, 0xf4, 0xb2, 0x5c, 0xd3, 0x93,
-	0xb9, 0xe6, 0xab, 0x45, 0xce, 0x35, 0x4d, 0x3a, 0x5a, 0x1c, 0xcc, 0x35,
-	0xcd, 0xa1, 0x5c, 0x93, 0xd3, 0xf2, 0xfc, 0x4e, 0xb9, 0x26, 0xd7, 0xd9,
-	0xbd, 0x6a, 0x92, 0x7c, 0x0f, 0xcb, 0xca, 0xb8, 0xc4, 0x78, 0x9c, 0xd6,
-	0xfc, 0x57, 0x92, 0x3c, 0x96, 0x4e, 0xe3, 0x1c, 0xbc, 0x77, 0x77, 0x8a,
-	0x25, 0x33, 0x8b, 0xa5, 0xdd, 0x29, 0x4d, 0x77, 0x30, 0x9e, 0x4e, 0x17,
-	0x87, 0xe3, 0x29, 0xe7, 0x93, 0xc7, 0x53, 0xca, 0xf3, 0x3d, 0xad, 0xcc,
-	0x35, 0x02, 0xfa, 0x6d, 0xd7, 0x5f, 0xc0, 0xec, 0xa5, 0xfe, 0x2c, 0x6a,
-	0x6e, 0x9d, 0xae, 0xe6, 0x78, 0x23, 0xbf, 0x09, 0x61, 0xec, 0xe7, 0xb2,
-	0x16, 0xb7, 0xd7, 0x7a, 0xa8, 0xbb, 0xdf, 0x01, 0x8e, 0x5c, 0x94, 0xeb,
-	0x9f, 0x88, 0xab, 0x68, 0x09, 0xdb, 0x5e, 0xbe, 0xef, 0x17, 0x38, 0xcf,
-	0xb5, 0xce, 0xe3, 0xe9, 0xd9, 0x7e, 0xae, 0x13, 0x5e, 0xe7, 0xb9, 0xbf,
-	0x23, 0x9f, 0xa0, 0x66, 0xdf, 0xde, 0xcb, 0xfd, 0x8f, 0x87, 0x3b, 0x3b,
-	0xf4, 0xfa, 0x50, 0x0f, 0x94, 0xf6, 0x3e, 0x75, 0xf9, 0x8d, 0x97, 0x6b,
-	0x97, 0xe8, 0x0b, 0x2a, 0x9d, 0xa2, 0xaf, 0xf9, 0x3c, 0xa7, 0x52, 0xed,
-	0x31, 0x21, 0x9e, 0x41, 0x1d, 0xf3, 0xd4, 0x50, 0x1d, 0x53, 0xa4, 0x89,
-	0x47, 0x06, 0x7b, 0xc8, 0x2d, 0x31, 0x31, 0xed, 0x9e, 0x0f, 0x29, 0x54,
-	0x6a, 0x1b, 0x5c, 0xe7, 0x6e, 0xd7, 0xb5, 0x44, 0xfb, 0x6e, 0x09, 0x75,
-	0x9a, 0xf3, 0xe2, 0x6f, 0x33, 0x5d, 0x61, 0xed, 0xdc, 0x2d, 0x60, 0x6b,
-	0x55, 0x7e, 0x0b, 0x0e, 0x37, 0xf8, 0x1c, 0x7e, 0xc7, 0x98, 0x70, 0xcd,
-	0x73, 0xb7, 0xef, 0xb3, 0x3a, 0xec, 0xe2, 0x3a, 0xc7, 0x35, 0x92, 0xdf,
-	0x37, 0x56, 0x7c, 0xf7, 0xa7, 0x2d, 0x4a, 0x71, 0xa2, 0xea, 0x2f, 0x41,
-	0x16, 0xd4, 0x9d, 0xd6, 0x32, 0x6c, 0x33, 0x0d, 0x5c, 0x72, 0x9d, 0x47,
-	0x54, 0x5b, 0xe2, 0xf8, 0x2a, 0x78, 0x6b, 0x8f, 0x70, 0x4d, 0xf9, 0xb1,
-	0x58, 0xed, 0xcb, 0x7c, 0xec, 0xb3, 0x8f, 0xc4, 0xc9, 0x5e, 0x95, 0xc7,
-	0x30, 0xe1, 0xe7, 0x02, 0x71, 0x2d, 0xb9, 0xb3, 0xff, 0xd8, 0x56, 0xf5,
-	0x9c, 0x63, 0xd5, 0xba, 0x8e, 0xb5, 0xd0, 0x55, 0xe1, 0xdd, 0xfb, 0x4c,
-	0xda, 0x03, 0x9b, 0x20, 0x1f, 0xd3, 0x7d, 0x90, 0xe5, 0x92, 0x63, 0xc5,
-	0xa8, 0x0f, 0xbf, 0xa7, 0xb9, 0xd6, 0x53, 0xa4, 0x98, 0x54, 0xba, 0x25,
-	0xd2, 0x6f, 0x33, 0x8e, 0x55, 0xdd, 0x3e, 0xfb, 0x16, 0xce, 0x66, 0x99,
-	0x38, 0x46, 0x39, 0x5f, 0x2e, 0x2a, 0x4b, 0xd0, 0xd1, 0xb1, 0x8d, 0x5d,
-	0xc0, 0x35, 0xce, 0x97, 0x07, 0xb2, 0x6f, 0x50, 0xb0, 0x0f, 0xee, 0xff,
-	0xfa, 0x1d, 0xf5, 0x67, 0x5e, 0x67, 0x32, 0xbd, 0x10, 0xcd, 0x79, 0x3e,
-	0x9f, 0x20, 0xcb, 0xd4, 0xcc, 0x25, 0xd9, 0x13, 0xcd, 0xa2, 0xee, 0xe3,
-	0x51, 0xa0, 0x26, 0xe2, 0xef, 0x61, 0xae, 0x55, 0xc7, 0x73, 0x35, 0x7b,
-	0x6e, 0x72, 0xbf, 0x34, 0xcf, 0x3c, 0xb8, 0x6f, 0xe2, 0xf8, 0xf9, 0x27,
-	0x6e, 0xb7, 0x92, 0x82, 0x90, 0x18, 0x00, 0x00, 0x00 };
+	0xbd, 0x58, 0x5d, 0x6c, 0x1c, 0xd5, 0x15, 0x3e, 0x73, 0x67, 0xd6, 0x3b,
+	0xb6, 0x9c, 0x78, 0x4c, 0xb6, 0xb0, 0x14, 0x47, 0xcc, 0xc4, 0xe3, 0x9f,
+	0xca, 0x16, 0x0c, 0xe9, 0x96, 0x1a, 0x69, 0x55, 0x0d, 0xbb, 0x1b, 0x63,
+	0xa5, 0x3c, 0x18, 0x29, 0x52, 0x91, 0xa0, 0xc8, 0x5d, 0x13, 0xe0, 0x81,
+	0x87, 0xa0, 0xf6, 0xa1, 0x15, 0x0f, 0x59, 0xd6, 0x9b, 0x90, 0x87, 0x6d,
+	0x06, 0x96, 0x2a, 0x79, 0x68, 0x55, 0x45, 0x0e, 0x8e, 0xa3, 0x76, 0xe5,
+	0x25, 0x48, 0x7d, 0x8c, 0x40, 0xa1, 0x4a, 0x5f, 0x79, 0xa0, 0x15, 0x7d,
+	0x22, 0x52, 0x5f, 0x78, 0xe8, 0x4f, 0x84, 0xd4, 0x16, 0xb5, 0x34, 0xb7,
+	0xdf, 0x77, 0x67, 0xc6, 0x6c, 0x4d, 0x22, 0xc4, 0x4b, 0x57, 0x5a, 0xdd,
+	0x99, 0x7b, 0xcf, 0x39, 0xf7, 0xdc, 0xf3, 0xf3, 0x9d, 0x73, 0xe7, 0x90,
+	0x92, 0x31, 0xc9, 0x7e, 0xfb, 0xf0, 0xaf, 0xfc, 0xe0, 0xc4, 0x8f, 0xbe,
+	0xf5, 0x40, 0xf4, 0x00, 0xdf, 0xad, 0x82, 0x38, 0xf2, 0x7f, 0xfc, 0xd9,
+	0x22, 0x5e, 0xae, 0x07, 0xff, 0xe2, 0xaa, 0xea, 0xda, 0xc1, 0x5a, 0x28,
+	0xae, 0x5d, 0x5d, 0x79, 0x60, 0x3d, 0x14, 0x89, 0xfb, 0x0b, 0x7e, 0x5d,
+	0xfe, 0xa3, 0x5b, 0x25, 0x47, 0x38, 0x7f, 0xb0, 0xfa, 0xd9, 0x83, 0x57,
+	0xbf, 0x1d, 0xdc, 0xbc, 0x60, 0x8b, 0xeb, 0x55, 0xcf, 0xb8, 0xde, 0xac,
+	0xb8, 0x53, 0xe0, 0xf9, 0xc5, 0x5c, 0x6f, 0x44, 0xf6, 0xe7, 0xb2, 0x5a,
+	0x5a, 0x85, 0x37, 0xf4, 0xd5, 0xb9, 0xd0, 0x6b, 0x4b, 0x49, 0xae, 0x0c,
+	0x7c, 0xa9, 0x0d, 0xa6, 0xe4, 0x9d, 0x41, 0x59, 0xde, 0x1e, 0x78, 0xf2,
+	0xd6, 0xc0, 0x91, 0xe3, 0x6f, 0x9c, 0x94, 0x4e, 0x14, 0x94, 0x1b, 0xb6,
+	0x2b, 0xaa, 0x1a, 0x94, 0x9b, 0xe2, 0xcb, 0x56, 0x14, 0x9c, 0x59, 0xb3,
+	0x27, 0x2d, 0xb7, 0xea, 0xca, 0xcb, 0x73, 0x4a, 0x2e, 0x94, 0x9e, 0x96,
+	0xe7, 0xc2, 0x27, 0xf1, 0x77, 0xe4, 0x50, 0xcf, 0xb1, 0xea, 0xe7, 0x1d,
+	0x09, 0x7b, 0x13, 0xf2, 0x58, 0xa4, 0xf5, 0x7a, 0x14, 0x83, 0x7f, 0x7a,
+	0xfe, 0x79, 0x19, 0x95, 0x96, 0x17, 0xac, 0x88, 0x14, 0x48, 0x23, 0xb5,
+	0xa8, 0x20, 0xb1, 0x97, 0x9e, 0xed, 0x82, 0x19, 0x3f, 0xd3, 0x5b, 0xe0,
+	0x1f, 0x0d, 0xf3, 0xf5, 0xbb, 0xb2, 0x75, 0x2f, 0x5b, 0x57, 0x72, 0xe8,
+	0x5c, 0xe0, 0x6f, 0xcb, 0x4c, 0xec, 0x58, 0xb7, 0x74, 0x2d, 0xbc, 0xdb,
+	0xab, 0x6d, 0x3b, 0x32, 0xdd, 0xe3, 0x19, 0x42, 0xaf, 0x2e, 0x1a, 0x3c,
+	0x36, 0x79, 0x1c, 0x55, 0xfd, 0x21, 0x7c, 0x37, 0x13, 0x2b, 0x4b, 0xe4,
+	0x5a, 0xb7, 0xec, 0xd5, 0x06, 0x3f, 0xb6, 0x6a, 0xc9, 0x2d, 0x1d, 0x3b,
+	0x63, 0xa2, 0xc2, 0xd8, 0xaa, 0x6d, 0x53, 0xd6, 0xa8, 0x38, 0x61, 0x11,
+	0x3c, 0xd3, 0x9e, 0x12, 0x8e, 0xb5, 0x6c, 0x9e, 0xb2, 0x1b, 0x78, 0x5e,
+	0xb6, 0xe2, 0x6d, 0xc7, 0xaa, 0x9d, 0x5f, 0xc1, 0xb3, 0x0b, 0x7e, 0xd8,
+	0x26, 0xb2, 0x24, 0x5e, 0xb5, 0xc0, 0xc7, 0x73, 0x7a, 0x78, 0x57, 0x12,
+	0x97, 0x3c, 0xd9, 0xa8, 0x04, 0xe5, 0x96, 0x1c, 0xb5, 0xea, 0xdb, 0x5f,
+	0x70, 0x9c, 0xb7, 0x32, 0xf8, 0xe2, 0x1c, 0x75, 0x79, 0xd4, 0xd1, 0x5a,
+	0x3d, 0x54, 0xcc, 0xce, 0x48, 0x79, 0x71, 0xaa, 0x7f, 0x89, 0xef, 0xd0,
+	0x39, 0x81, 0xee, 0xfd, 0x11, 0xe8, 0xa3, 0x35, 0xf7, 0xa9, 0x85, 0xed,
+	0xd7, 0x14, 0x2c, 0x78, 0x97, 0x04, 0xad, 0xa7, 0x68, 0x8d, 0xb3, 0x07,
+	0xc4, 0x9f, 0x54, 0xa1, 0x92, 0xc0, 0xdb, 0x96, 0x29, 0xd9, 0x48, 0xa6,
+	0xbc, 0x23, 0x49, 0xdb, 0x23, 0x0d, 0xe7, 0xea, 0xa0, 0x39, 0xd2, 0xd7,
+	0xfa, 0x52, 0x74, 0x5f, 0x51, 0xf6, 0xab, 0xc5, 0x82, 0x04, 0x7e, 0x6c,
+	0xf8, 0x64, 0xca, 0x11, 0xca, 0xc4, 0xf3, 0x0e, 0xdf, 0x67, 0x0c, 0xad,
+	0xda, 0xd9, 0x6b, 0xcb, 0xb9, 0x4c, 0x37, 0xfa, 0x43, 0xd1, 0x4e, 0xd9,
+	0xfb, 0xb8, 0x57, 0x3b, 0x9f, 0xdb, 0xdf, 0x9c, 0x07, 0xf6, 0x8e, 0xa4,
+	0x56, 0xc1, 0xb9, 0xee, 0x78, 0xd6, 0x9c, 0x8f, 0x3a, 0x72, 0xef, 0x88,
+	0xe7, 0xd9, 0xd5, 0xf5, 0xa9, 0x2f, 0xe8, 0xda, 0xf2, 0x71, 0x4e, 0xff,
+	0xe7, 0x98, 0xdf, 0xe8, 0x4a, 0x49, 0x09, 0xe3, 0x08, 0xcf, 0x7d, 0xbe,
+	0xcf, 0x20, 0x06, 0xf9, 0xac, 0x24, 0x3c, 0xe7, 0x4a, 0x27, 0x7c, 0xc6,
+	0x96, 0xfd, 0x5a, 0x77, 0x22, 0xc7, 0x6a, 0x9c, 0x7f, 0x31, 0x7b, 0x46,
+	0x0c, 0x27, 0x88, 0xe1, 0x04, 0x31, 0x9d, 0x20, 0x8e, 0x13, 0xf1, 0x54,
+	0xd5, 0x97, 0xab, 0x73, 0xae, 0xdc, 0xb0, 0x11, 0x0b, 0x83, 0x05, 0xef,
+	0x4d, 0xc4, 0x63, 0xec, 0x59, 0x62, 0x87, 0xf1, 0x7c, 0x41, 0xf8, 0x8e,
+	0x38, 0x74, 0xe2, 0xb2, 0x8d, 0x38, 0x8c, 0x8f, 0x71, 0xae, 0x28, 0x6b,
+	0xe6, 0xbc, 0x0b, 0xde, 0x29, 0xa1, 0x9f, 0x6b, 0x58, 0x9b, 0xf6, 0x4f,
+	0x31, 0x60, 0xc7, 0x6a, 0x58, 0xa7, 0xac, 0xc0, 0x6b, 0x81, 0xa2, 0x9d,
+	0x7c, 0x8c, 0x1c, 0x2a, 0x21, 0x6f, 0xe6, 0xca, 0x4a, 0x2c, 0x59, 0x5f,
+	0x84, 0xbd, 0x16, 0x69, 0x57, 0xe6, 0x10, 0x63, 0xf2, 0xef, 0xb3, 0x4e,
+	0x78, 0x12, 0xb1, 0x07, 0x5a, 0xd8, 0xe8, 0x54, 0x32, 0x07, 0xfe, 0xc5,
+	0x22, 0x75, 0xdd, 0x8a, 0x1c, 0xe9, 0x24, 0x57, 0x55, 0x21, 0xfc, 0xa7,
+	0x92, 0xfd, 0x41, 0x2b, 0x86, 0x7f, 0x95, 0x52, 0x25, 0x6e, 0xfd, 0xda,
+	0x00, 0x32, 0x8d, 0xfe, 0x0e, 0xf8, 0xca, 0x99, 0xfe, 0xf4, 0x8d, 0xc8,
+	0x66, 0x37, 0x88, 0x96, 0xa1, 0xdb, 0x35, 0xc4, 0x0e, 0xfd, 0x72, 0x09,
+	0xb6, 0x69, 0x77, 0x2d, 0xe6, 0xbe, 0xb4, 0xfb, 0xa4, 0x33, 0x30, 0xb1,
+	0xe6, 0x54, 0x65, 0xb5, 0xdd, 0x3d, 0xa9, 0xed, 0x50, 0xd6, 0x0a, 0x55,
+	0xfa, 0x76, 0x7c, 0x09, 0xbe, 0x5a, 0x6d, 0xf7, 0xa7, 0x1e, 0xdf, 0xec,
+	0x4a, 0xeb, 0xeb, 0x55, 0x69, 0xd9, 0x15, 0x75, 0xb7, 0x92, 0x09, 0xc8,
+	0xad, 0x62, 0x1f, 0xc6, 0x64, 0xe0, 0xd7, 0xed, 0xa9, 0xc7, 0x2f, 0x76,
+	0xef, 0x47, 0xce, 0xcb, 0x67, 0xb5, 0x4a, 0x08, 0x9b, 0x5f, 0xbb, 0xd7,
+	0x96, 0x50, 0x36, 0x06, 0xae, 0xd4, 0x92, 0x29, 0xe9, 0x0c, 0x24, 0x7e,
+	0x6a, 0x0e, 0xfb, 0x55, 0xf0, 0x3e, 0x58, 0x94, 0xd6, 0x60, 0x6a, 0x4d,
+	0x55, 0x5b, 0x12, 0x0f, 0x3a, 0xf8, 0xbb, 0xd2, 0xe8, 0xba, 0xee, 0xc5,
+	0x6e, 0x8b, 0xfc, 0xae, 0x55, 0xf5, 0xdd, 0x43, 0xfd, 0x9b, 0x8c, 0x2d,
+	0xc8, 0x19, 0xfd, 0x9e, 0xaa, 0x3a, 0xd2, 0x2c, 0x95, 0x20, 0xc3, 0x82,
+	0x4d, 0xa8, 0xeb, 0x3c, 0xf6, 0x4d, 0xc7, 0xd6, 0x80, 0xfe, 0x2b, 0x4a,
+	0x3b, 0x5a, 0x84, 0x9d, 0x60, 0x77, 0xaf, 0x28, 0x1b, 0xe1, 0xa7, 0xfa,
+	0xd9, 0x28, 0x80, 0x8f, 0xf4, 0xfd, 0x35, 0x60, 0x51, 0x0d, 0x26, 0x7d,
+	0x39, 0x2c, 0xcb, 0x29, 0xec, 0x9b, 0xf2, 0x75, 0xa0, 0x03, 0xf9, 0x26,
+	0xc0, 0xd7, 0x00, 0x5f, 0x49, 0x4e, 0x1b, 0xde, 0x09, 0xf0, 0xde, 0xcc,
+	0x78, 0x17, 0xca, 0xcb, 0x12, 0x81, 0x67, 0xda, 0x5f, 0x86, 0x3f, 0xd7,
+	0x4a, 0x0d, 0xf0, 0x36, 0xa0, 0x03, 0xc6, 0x44, 0x5a, 0x4e, 0x85, 0x72,
+	0x83, 0xf2, 0xb3, 0xcc, 0x25, 0x23, 0xb3, 0x05, 0x99, 0xd0, 0x2b, 0x71,
+	0x21, 0x67, 0x09, 0xe3, 0x07, 0xba, 0x9d, 0x00, 0xb3, 0x4a, 0x7c, 0x7e,
+	0x47, 0xab, 0x2a, 0xe2, 0xb8, 0x12, 0xfa, 0x6d, 0xe1, 0xfb, 0x88, 0xd4,
+	0x91, 0xa3, 0x2a, 0x9c, 0x90, 0xa6, 0x67, 0x59, 0xaa, 0x6a, 0x4b, 0x13,
+	0x51, 0x1c, 0xaf, 0x3a, 0x66, 0x6e, 0x0d, 0x71, 0xa6, 0xaa, 0x5b, 0x76,
+	0x5a, 0x4f, 0x0a, 0xa0, 0x19, 0xc1, 0xfc, 0x38, 0x6c, 0x30, 0x09, 0xda,
+	0x5f, 0x62, 0x7e, 0x06, 0xf8, 0x3b, 0x09, 0x1a, 0x8e, 0xcc, 0x23, 0xda,
+	0x85, 0xf4, 0x15, 0xe8, 0x98, 0xcf, 0x55, 0x60, 0x9b, 0xe1, 0xd4, 0xca,
+	0x7d, 0x0c, 0x9a, 0xc4, 0xc9, 0x72, 0x73, 0x38, 0xdf, 0xf2, 0x75, 0x1f,
+	0xeb, 0xd7, 0xbe, 0xa1, 0xe4, 0xa6, 0xbe, 0x18, 0x32, 0x86, 0xe5, 0xd3,
+	0x46, 0x18, 0x4f, 0xda, 0x06, 0x23, 0x72, 0xac, 0xe0, 0xc8, 0x5a, 0x72,
+	0xf9, 0xe0, 0x7a, 0x68, 0xd9, 0x9d, 0xc5, 0x03, 0xd2, 0x2a, 0x05, 0x51,
+	0x1d, 0xfe, 0xee, 0x24, 0xcc, 0x8d, 0x09, 0x9c, 0x3b, 0x40, 0xd4, 0x4d,
+	0xe3, 0x39, 0xbe, 0x17, 0x3c, 0xf0, 0x63, 0x0b, 0xb2, 0x38, 0x22, 0x66,
+	0x92, 0x00, 0x3a, 0xc2, 0x1e, 0xe1, 0x82, 0x77, 0x84, 0xf1, 0x58, 0xe2,
+	0x1a, 0x6b, 0xd4, 0x65, 0xd4, 0xa8, 0x20, 0x6a, 0x66, 0xb9, 0xf2, 0x2e,
+	0x6c, 0xdb, 0x4e, 0x58, 0x6f, 0xca, 0xc8, 0x15, 0xd6, 0x1b, 0xe6, 0x07,
+	0x63, 0x25, 0xc7, 0x67, 0xf0, 0x84, 0xcc, 0x4f, 0x37, 0xc3, 0xe9, 0x5a,
+	0x86, 0xc1, 0x4b, 0xd0, 0x43, 0xeb, 0x27, 0x80, 0xbf, 0xed, 0xc8, 0xc4,
+	0x67, 0xcb, 0x57, 0xb7, 0xf4, 0xf4, 0x2c, 0x6d, 0xae, 0xf5, 0x89, 0x68,
+	0x19, 0xb4, 0x7f, 0x83, 0xbd, 0x56, 0x80, 0xc1, 0xc4, 0x6d, 0xee, 0x5d,
+	0x75, 0x6b, 0xdd, 0x7d, 0xd0, 0xc5, 0x07, 0x36, 0xc2, 0x06, 0x06, 0xab,
+	0x47, 0x91, 0xef, 0xcc, 0xf9, 0xc0, 0x5f, 0x13, 0xce, 0xcb, 0xa8, 0xc2,
+	0x7b, 0x13, 0x7e, 0xea, 0x54, 0x8e, 0x5a, 0x8d, 0xed, 0x31, 0x27, 0xab,
+	0xf9, 0x13, 0x0a, 0x75, 0xa8, 0x59, 0x22, 0xdf, 0x08, 0xf8, 0xf6, 0x81,
+	0x67, 0x14, 0x6b, 0x05, 0x8c, 0xc3, 0x72, 0x0c, 0xe6, 0x63, 0x2f, 0x1f,
+	0x7b, 0xad, 0x88, 0x53, 0x7d, 0x05, 0xf8, 0x33, 0xe3, 0x37, 0xe4, 0x57,
+	0x76, 0x5a, 0x63, 0xe9, 0x9b, 0xef, 0x0c, 0xf9, 0xc6, 0x17, 0xdb, 0xe4,
+	0xe0, 0x23, 0x59, 0x4c, 0x11, 0x57, 0x1f, 0xce, 0xd6, 0x4b, 0xc0, 0xc7,
+	0x6f, 0x66, 0xf8, 0xef, 0x12, 0x2b, 0xe5, 0x8c, 0xc1, 0xca, 0x11, 0x62,
+	0x25, 0x70, 0xa5, 0xb5, 0x04, 0x7b, 0x47, 0x1f, 0x03, 0x5f, 0xea, 0xf0,
+	0xc4, 0x6f, 0xbb, 0x0e, 0xe2, 0xca, 0x06, 0x3f, 0xeb, 0xf8, 0x77, 0xa1,
+	0x5b, 0xe0, 0x7d, 0x0c, 0xbc, 0x89, 0x8f, 0x31, 0x0f, 0xb4, 0x46, 0xae,
+	0x03, 0xab, 0x66, 0xcb, 0xa7, 0x10, 0xf7, 0x36, 0x70, 0x02, 0x15, 0x19,
+	0xfb, 0xe6, 0x35, 0x37, 0xaf, 0xff, 0xfc, 0xbd, 0x6f, 0xc1, 0xcd, 0xa8,
+	0x93, 0x47, 0x21, 0x63, 0xc6, 0x3f, 0x02, 0x3f, 0x6e, 0x2c, 0x7d, 0x19,
+	0xcf, 0x1f, 0x33, 0x1e, 0xad, 0x1b, 0x15, 0xee, 0x2b, 0xd2, 0xe8, 0xd3,
+	0x0e, 0x11, 0xec, 0x60, 0x30, 0x08, 0x39, 0x1f, 0x21, 0xe7, 0x45, 0x9a,
+	0xc4, 0x0a, 0x60, 0x18, 0x71, 0x6f, 0x03, 0xf4, 0xaa, 0x52, 0x84, 0x5d,
+	0x11, 0x4b, 0x4a, 0x5c, 0xa7, 0x7a, 0xcc, 0xed, 0x80, 0xb6, 0x50, 0x5d,
+	0x75, 0xb7, 0xc2, 0x17, 0x73, 0xdb, 0x03, 0xc7, 0xc4, 0xaa, 0xa5, 0x7e,
+	0xce, 0xe8, 0x1e, 0xcf, 0xe8, 0x56, 0x86, 0xe9, 0x30, 0xdf, 0xc8, 0xe6,
+	0x63, 0xcc, 0xcf, 0x65, 0x36, 0x67, 0x3d, 0x70, 0x51, 0xa3, 0x59, 0x0b,
+	0x02, 0xdf, 0x57, 0x88, 0xb5, 0x3b, 0xd6, 0x81, 0xa5, 0x21, 0xec, 0x16,
+	0x65, 0x7a, 0x92, 0x12, 0x63, 0x72, 0xf8, 0xac, 0xa3, 0x28, 0x34, 0xbb,
+	0xf1, 0x89, 0xdf, 0xdb, 0xd9, 0x3e, 0xa4, 0x25, 0x5e, 0x0f, 0xd3, 0x22,
+	0x8d, 0x42, 0xd6, 0xd4, 0xdb, 0xd9, 0xec, 0x00, 0xd6, 0x90, 0xf3, 0x89,
+	0x2d, 0x8f, 0x3a, 0xcc, 0xef, 0xc3, 0x05, 0x73, 0x0e, 0xd6, 0xe0, 0x9d,
+	0x29, 0x83, 0x33, 0x2b, 0xdd, 0x22, 0x80, 0x7d, 0x5c, 0x8e, 0x23, 0x9f,
+	0x9f, 0x85, 0xef, 0x2f, 0x46, 0x0a, 0x9d, 0x06, 0x6b, 0x8e, 0x46, 0x1c,
+	0x06, 0xc6, 0x17, 0xb5, 0x70, 0x03, 0x91, 0xfc, 0x8a, 0x5c, 0x5b, 0x1c,
+	0x93, 0xc2, 0x25, 0xea, 0xe0, 0x88, 0xb3, 0x39, 0xbc, 0xcf, 0x02, 0xf6,
+	0x99, 0x02, 0x06, 0x3e, 0x82, 0xfa, 0x52, 0x12, 0x67, 0x16, 0x58, 0x9b,
+	0xb8, 0x56, 0x1d, 0xf2, 0xd5, 0x25, 0x9e, 0x9f, 0x18, 0xec, 0x66, 0xb5,
+	0x8d, 0xb9, 0x55, 0x14, 0xbb, 0xf7, 0x67, 0xe4, 0xae, 0x92, 0xf5, 0x8a,
+	0xd6, 0x47, 0xa2, 0xf7, 0x60, 0x5f, 0xcc, 0x6d, 0x72, 0xed, 0x26, 0xe6,
+	0x39, 0x47, 0x19, 0x8c, 0xc5, 0x03, 0xa8, 0x6b, 0xd8, 0xf3, 0x18, 0x79,
+	0x8a, 0xa2, 0x7a, 0xc4, 0x7f, 0x8c, 0x9b, 0x7c, 0xe7, 0x99, 0x88, 0x6d,
+	0x36, 0xc6, 0x31, 0x8c, 0x3c, 0xd3, 0x47, 0x99, 0xaf, 0xf8, 0xac, 0xb5,
+	0x53, 0x1d, 0x97, 0x7a, 0x37, 0x04, 0xc6, 0xce, 0x94, 0x8f, 0x0b, 0xd7,
+	0xf0, 0xde, 0xe7, 0xbc, 0x37, 0x34, 0x8f, 0xe7, 0xbe, 0xd1, 0x59, 0x9c,
+	0xdd, 0xde, 0x67, 0x03, 0x86, 0x2d, 0x60, 0x1f, 0xf6, 0x39, 0xac, 0x7f,
+	0x06, 0xb7, 0xe6, 0xd9, 0xb7, 0x5c, 0xee, 0xb2, 0x16, 0x3a, 0xcc, 0xcb,
+	0x7b, 0x94, 0x1c, 0x90, 0x7a, 0x29, 0x3f, 0x17, 0xe2, 0x38, 0x22, 0xff,
+	0x34, 0xfb, 0x19, 0x8d, 0xbc, 0x2b, 0xdb, 0xa6, 0x6f, 0x9c, 0x89, 0xd9,
+	0x3f, 0x5c, 0xee, 0x23, 0x97, 0x7b, 0x5a, 0x9a, 0xa9, 0x2c, 0x6f, 0x15,
+	0xfd, 0x6f, 0xed, 0x35, 0xd6, 0x40, 0xda, 0xf9, 0x5e, 0xf8, 0x06, 0x18,
+	0xbd, 0xe9, 0xc8, 0xc5, 0x6e, 0x2a, 0x8b, 0x39, 0xf5, 0x42, 0x26, 0xaf,
+	0x21, 0x7f, 0x80, 0x1c, 0xf6, 0x25, 0xec, 0x31, 0xd1, 0x53, 0x9e, 0x73,
+	0x20, 0x8f, 0x36, 0xc0, 0xb5, 0xa0, 0x37, 0x9f, 0xe9, 0x1b, 0x80, 0xce,
+	0x81, 0x4d, 0x69, 0x4b, 0xca, 0x62, 0xac, 0xfd, 0x5b, 0x13, 0x3f, 0x50,
+	0x37, 0xb0, 0x07, 0xde, 0x07, 0x23, 0xe0, 0x99, 0x92, 0x57, 0x13, 0x83,
+	0xa5, 0xde, 0x09, 0x60, 0x52, 0xa3, 0xfb, 0x8f, 0xbc, 0xb6, 0xc4, 0x6d,
+	0xe0, 0xeb, 0xf3, 0x32, 0x2e, 0xce, 0xce, 0xb8, 0xbc, 0x80, 0x5e, 0xb0,
+	0xd0, 0x43, 0x1d, 0x87, 0x0d, 0xd5, 0xd9, 0xd6, 0x3c, 0xfb, 0xb9, 0xb7,
+	0xd8, 0x17, 0x55, 0xc2, 0xc8, 0xb6, 0x66, 0xe5, 0xcc, 0xcf, 0x82, 0xf9,
+	0x6d, 0x93, 0xaf, 0x58, 0xdf, 0xf1, 0xe5, 0x74, 0x3f, 0x94, 0x33, 0x7d,
+	0x0f, 0x7a, 0x79, 0xbb, 0x3d, 0xaf, 0x0a, 0x89, 0xa7, 0x0d, 0xfc, 0x89,
+	0x97, 0x3c, 0x17, 0x6c, 0x5c, 0xa5, 0x4d, 0xd8, 0xe3, 0xd2, 0x7f, 0xc4,
+	0xaf, 0xa3, 0x78, 0x1e, 0x13, 0x1b, 0x67, 0x52, 0x3d, 0xda, 0x82, 0xf6,
+	0x1f, 0xee, 0x93, 0x89, 0x6d, 0x9e, 0xe9, 0x1d, 0x9b, 0x49, 0x9e, 0x7b,
+	0x79, 0x2e, 0x32, 0xcf, 0x1d, 0x6b, 0x19, 0xf6, 0xba, 0x1e, 0x31, 0x1f,
+	0x6f, 0xe9, 0xeb, 0xa6, 0x3f, 0xf3, 0xd8, 0x33, 0x0f, 0xf5, 0x67, 0x79,
+	0x5f, 0xc3, 0x78, 0x2c, 0x0f, 0xe5, 0xe3, 0x0d, 0x93, 0x8b, 0x57, 0x90,
+	0x97, 0xaf, 0x27, 0x65, 0x93, 0x93, 0x87, 0x0e, 0xdf, 0x2e, 0x27, 0x7f,
+	0xfd, 0x15, 0x72, 0xf2, 0xed, 0x2c, 0x27, 0x47, 0x4c, 0xdc, 0xaa, 0xde,
+	0xf0, 0xda, 0x6f, 0xb0, 0xc6, 0x39, 0xde, 0x37, 0x58, 0x43, 0xd1, 0xff,
+	0x3f, 0x4c, 0x1f, 0xe5, 0xfe, 0x49, 0xe3, 0xb0, 0xee, 0x90, 0x06, 0x3e,
+	0xec, 0x8d, 0x8b, 0x7d, 0x96, 0x39, 0x9b, 0xc7, 0x8c, 0x8f, 0x58, 0xcd,
+	0xf9, 0xd1, 0x4f, 0x1e, 0x63, 0x2c, 0x14, 0x4c, 0x5e, 0xd8, 0xd5, 0x9c,
+	0xa6, 0x2c, 0xcb, 0xe8, 0xd5, 0xde, 0xe3, 0xd8, 0x4f, 0x63, 0x65, 0xa4,
+	0xe7, 0xca, 0x4b, 0x73, 0xc4, 0xa6, 0x20, 0xba, 0x06, 0x9d, 0xaf, 0x87,
+	0x25, 0x29, 0xcc, 0x32, 0x5f, 0x59, 0x6d, 0x46, 0x10, 0x43, 0xb8, 0x77,
+	0x25, 0xfa, 0x24, 0xfa, 0x29, 0xdf, 0x81, 0x9f, 0x5f, 0x47, 0x1c, 0x11,
+	0x3b, 0x11, 0x13, 0xf3, 0x9b, 0x88, 0x89, 0xe3, 0x7c, 0x37, 0xfb, 0x16,
+	0x0c, 0xad, 0x6d, 0xf6, 0x2f, 0x41, 0x7f, 0x57, 0x8a, 0xe7, 0x34, 0xee,
+	0x5b, 0x9f, 0xf3, 0x9d, 0x36, 0xf1, 0x0b, 0xac, 0xc0, 0xfc, 0xba, 0x89,
+	0x5f, 0xfa, 0x34, 0xf0, 0x88, 0xf3, 0x7f, 0x32, 0xb9, 0xf1, 0xa1, 0xc9,
+	0xf1, 0xeb, 0x91, 0x89, 0xe7, 0x88, 0xfd, 0xe4, 0xe9, 0xfe, 0xfb, 0x05,
+	0x83, 0x01, 0xc8, 0x8f, 0x53, 0x91, 0x89, 0xb5, 0xf9, 0x2b, 0x38, 0xf6,
+	0x9b, 0x69, 0x2e, 0x0c, 0xc9, 0x99, 0xf6, 0x1e, 0x4b, 0x73, 0xcb, 0xdf,
+	0x30, 0x77, 0x8a, 0x19, 0xf4, 0x43, 0xa0, 0xeb, 0xef, 0xc5, 0x83, 0x49,
+	0x8c, 0xb4, 0xf7, 0x27, 0x90, 0xeb, 0xc1, 0x86, 0x94, 0x43, 0xbd, 0xa9,
+	0xd7, 0xb8, 0x84, 0x67, 0x73, 0x9d, 0x3e, 0x31, 0xba, 0xfc, 0xaf, 0x3c,
+	0xac, 0xef, 0xdc, 0x8e, 0xcf, 0x1b, 0xe2, 0xfb, 0xeb, 0x6d, 0xf8, 0xb0,
+	0xbe, 0x43, 0x9e, 0xb1, 0xdd, 0x5e, 0xa2, 0xbe, 0x1b, 0xd7, 0x31, 0xe2,
+	0x9e, 0xbc, 0x7b, 0xef, 0x79, 0xc3, 0x39, 0x90, 0xd7, 0x70, 0xc6, 0x39,
+	0xf7, 0xcc, 0x63, 0x3d, 0x8f, 0xf1, 0x3c, 0xe6, 0xf3, 0x58, 0x0f, 0xa2,
+	0xe7, 0x24, 0xf5, 0xaf, 0xd3, 0x0b, 0xb0, 0xff, 0xd8, 0x1d, 0xee, 0x26,
+	0x5f, 0x56, 0x8f, 0x24, 0xfe, 0xfc, 0x1e, 0xf8, 0xfb, 0xac, 0x67, 0x74,
+	0x99, 0x6b, 0xf8, 0xb3, 0x4f, 0xbf, 0x89, 0xfa, 0x1f, 0x65, 0xb6, 0x8d,
+	0xb3, 0x31, 0xa5, 0x49, 0xfb, 0xbd, 0x9f, 0x64, 0x98, 0xfb, 0xfd, 0xb4,
+	0xbe, 0x48, 0x9e, 0x53, 0xcc, 0x21, 0x93, 0x53, 0x3c, 0x0f, 0xee, 0xe8,
+	0x5a, 0xaf, 0xc2, 0x8f, 0x2f, 0x45, 0x79, 0x1e, 0x21, 0x9e, 0x0e, 0xe7,
+	0x39, 0x0e, 0x3b, 0x85, 0xb7, 0xb4, 0x33, 0x1b, 0xc3, 0x66, 0xbc, 0x17,
+	0x37, 0xd0, 0x1b, 0xd1, 0x4e, 0x2b, 0xd6, 0x13, 0xbb, 0x77, 0xe1, 0xbd,
+	0x7d, 0x10, 0xed, 0x46, 0xbb, 0x0e, 0xdb, 0x2d, 0x88, 0x26, 0x15, 0x31,
+	0xe0, 0x76, 0x38, 0x91, 0xd7, 0x6b, 0x60, 0xd0, 0x6c, 0x6e, 0xa7, 0xaf,
+	0x5c, 0xb3, 0xe3, 0xf4, 0x3b, 0xc2, 0x5e, 0x7c, 0xd8, 0xb4, 0x87, 0xf0,
+	0xe1, 0x36, 0x3d, 0x25, 0x65, 0xd0, 0x06, 0xa8, 0x5f, 0xa6, 0xcf, 0x60,
+	0x0f, 0x79, 0x4b, 0xdb, 0xa6, 0x9f, 0x24, 0x36, 0xb2, 0x8f, 0xec, 0x8c,
+	0xc8, 0xd8, 0x3e, 0xf3, 0x1e, 0x6f, 0x73, 0x64, 0x4c, 0x48, 0x5a, 0x97,
+	0x8c, 0xfe, 0xcf, 0x64, 0xfa, 0xa7, 0x3a, 0x8b, 0xba, 0x13, 0xa6, 0x51,
+	0x57, 0x0f, 0xba, 0x3e, 0x94, 0xdb, 0xa5, 0xa5, 0xaa, 0x27, 0xa4, 0x51,
+	0x31, 0x77, 0x5b, 0xdc, 0xa5, 0xa0, 0xc3, 0x12, 0xf5, 0x28, 0x43, 0x8f,
+	0x71, 0xdc, 0x3d, 0x82, 0x95, 0x96, 0x04, 0xf1, 0x1a, 0x08, 0xe7, 0x7e,
+	0x4a, 0xbb, 0x3d, 0xed, 0x6e, 0x75, 0x69, 0xb7, 0x27, 0xdd, 0x4e, 0x77,
+	0x1a, 0xfd, 0x5f, 0x00, 0x6f, 0x07, 0xf3, 0x97, 0x84, 0x31, 0xb6, 0x10,
+	0x71, 0x3c, 0x2d, 0xec, 0xb7, 0x9e, 0x76, 0x67, 0xfa, 0x1c, 0x9f, 0x74,
+	0xc3, 0xfe, 0xb0, 0xdc, 0xbf, 0x68, 0x60, 0x62, 0x7c, 0x03, 0x79, 0xf4,
+	0xea, 0x20, 0xdd, 0x1b, 0xf7, 0xbf, 0x4c, 0x2e, 0xe6, 0x92, 0x5c, 0xb6,
+	0x10, 0xa7, 0x28, 0x1b, 0x72, 0xa7, 0xa3, 0xdf, 0x99, 0x3d, 0x78, 0xff,
+	0xb9, 0xd3, 0x1e, 0x77, 0xe7, 0xdf, 0x2e, 0x90, 0x3b, 0x05, 0x83, 0x3d,
+	0x1b, 0x09, 0xee, 0xcc, 0x25, 0xad, 0x9b, 0xe1, 0x87, 0xb0, 0x1d, 0x7a,
+	0x80, 0x45, 0x0f, 0x7f, 0xe0, 0xea, 0x2a, 0xd7, 0xd0, 0x67, 0xe3, 0xae,
+	0xc7, 0xfb, 0xda, 0x46, 0xc2, 0x35, 0xc6, 0x38, 0x7a, 0xc1, 0xc5, 0x8f,
+	0x40, 0xfb, 0x81, 0x6e, 0x0d, 0x94, 0xb9, 0x8f, 0xab, 0x10, 0xf7, 0xac,
+	0x01, 0xfb, 0x15, 0xb1, 0x1a, 0x89, 0xf8, 0xcd, 0x68, 0xc9, 0xdc, 0xc7,
+	0x62, 0xcf, 0xe7, 0x9d, 0x13, 0x3d, 0xe6, 0xe2, 0x50, 0x8f, 0xb9, 0x88,
+	0x1e, 0xf3, 0x9e, 0x22, 0xe2, 0x3c, 0xc6, 0x3d, 0x53, 0x35, 0xd3, 0xbc,
+	0x99, 0xe0, 0x9d, 0xb2, 0x5d, 0x92, 0x7d, 0xe8, 0x9e, 0xa0, 0x5b, 0x88,
+	0xfd, 0xb9, 0x7e, 0x30, 0xfb, 0xee, 0x85, 0x4d, 0xc7, 0x62, 0xd3, 0x6f,
+	0xb5, 0x4b, 0x23, 0xa8, 0xff, 0xa4, 0xb9, 0x2f, 0xa3, 0x79, 0x6e, 0x0f,
+	0xcd, 0xd7, 0x78, 0x46, 0xca, 0x96, 0xe6, 0x1b, 0xcc, 0x3b, 0xd6, 0xd2,
+	0x91, 0x2c, 0xdf, 0x4e, 0xe0, 0xb9, 0x98, 0x3d, 0xe7, 0xf4, 0x87, 0xf7,
+	0xf0, 0x3f, 0xa2, 0xd2, 0x77, 0x3e, 0x53, 0xe7, 0x98, 0x7d, 0x30, 0xe4,
+	0x2d, 0x59, 0xe9, 0xb7, 0x92, 0xf3, 0x38, 0x3b, 0x7d, 0x92, 0xf6, 0x17,
+	0xc0, 0x60, 0x74, 0x57, 0x33, 0xb0, 0xbb, 0xd6, 0xed, 0x25, 0xe2, 0xda,
+	0xc2, 0xfc, 0x11, 0x83, 0x6f, 0x6a, 0x4a, 0x49, 0x8e, 0xb9, 0xc3, 0xcf,
+	0x18, 0x97, 0xcc, 0x37, 0x01, 0xbc, 0xa7, 0x32, 0xb6, 0x70, 0x3f, 0x16,
+	0xe4, 0x70, 0xcb, 0xe8, 0x65, 0xa5, 0xf7, 0x1e, 0xaf, 0xc6, 0x7a, 0x80,
+	0xba, 0xf1, 0x20, 0xf5, 0xda, 0xfd, 0x76, 0xb1, 0x86, 0x5a, 0xf3, 0x2e,
+	0x62, 0x1f, 0xf9, 0x69, 0x7a, 0xa8, 0x2d, 0xf3, 0xed, 0x00, 0x75, 0x08,
+	0xd7, 0xa0, 0x4e, 0xb8, 0xfb, 0x0d, 0x41, 0x2e, 0x80, 0xe6, 0x22, 0xd6,
+	0x4e, 0xf7, 0xf3, 0x9e, 0x16, 0x7d, 0x3c, 0x70, 0x6f, 0x3d, 0xfc, 0x97,
+	0x6e, 0x96, 0x86, 0x69, 0xf9, 0xfb, 0x2f, 0xb4, 0x78, 0xd5, 0x79, 0x38,
+	0x15, 0x00, 0x00, 0x00 };
 
 static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 };
-static const u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_TPAT_b09FwRodata[(0x4/4) + 1] = {
+	0x00000001, 0x00000000 };
 
 static struct fw_info bnx2_tpat_fw_09 = {
-	/* Firmware version:  3.7.1 */
-	.ver_major			= 0x3,
-	.ver_minor			= 0x7,
-	.ver_fix			= 0x1,
+	/* Firmware version: 4.0.5 */
+	.ver_major			= 0x4,
+	.ver_minor			= 0x0,
+	.ver_fix			= 0x5,
 
-	.start_addr			= 0x08000860,
+	.start_addr			= 0x08000888,
 
 	.text_addr			= 0x08000800,
-	.text_len			= 0x188c,
+	.text_len			= 0x1534,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_TPAT_b09FwText,
 	.gz_text_len			= sizeof(bnx2_TPAT_b09FwText),
 
-	.data_addr			= 0x080020c0,
+	.data_addr			= 0x00000000,
 	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_TPAT_b09FwData,
 
-	.sbss_addr			= 0x080020c8,
-	.sbss_len			= 0x30,
+	.sbss_addr			= 0x08001d60,
+	.sbss_len			= 0x48,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x08002100,
-	.bss_len			= 0x850,
+	.bss_addr			= 0x08001da8,
+	.bss_len			= 0x10a0,
 	.bss_index			= 0x0,
 
-	.rodata_addr			= 0x00000000,
-	.rodata_len			= 0x0,
+	.rodata_addr			= 0x08001d34,
+	.rodata_len			= 0x4,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_TPAT_b09FwRodata,
 };
 
 static u8 bnx2_TXP_b09FwText[] = {
-	0xbd, 0x7c, 0x7d, 0x70, 0x1c, 0xe7, 0x79, 0xdf, 0xb3, 0xbb, 0x07, 0xe0,
-	0x00, 0x82, 0xe0, 0x12, 0x39, 0x52, 0x27, 0x0a, 0xa6, 0x6e, 0x89, 0x3d,
-	0x08, 0x32, 0x20, 0x71, 0xc5, 0x20, 0x36, 0x26, 0xb9, 0xca, 0xab, 0xbb,
-	0x03, 0x78, 0x94, 0x31, 0x31, 0xc4, 0xc2, 0x16, 0xed, 0x70, 0xd4, 0xeb,
-	0x01, 0xa4, 0x95, 0x54, 0x9e, 0xb2, 0xb6, 0xda, 0x72, 0x5a, 0x35, 0x3a,
-	0x1f, 0xc0, 0x0f, 0x29, 0x47, 0x1c, 0x24, 0xc0, 0x84, 0xfe, 0x70, 0x93,
-	0x13, 0x0e, 0x24, 0x64, 0xf7, 0x88, 0x93, 0xfc, 0xd9, 0x3f, 0x62, 0x0b,
-	0x03, 0xd2, 0xb4, 0x5a, 0xbb, 0xb5, 0xda, 0x28, 0x13, 0xcf, 0xf4, 0x63,
-	0x30, 0x14, 0xa5, 0x28, 0x71, 0xa7, 0x56, 0x9b, 0x4c, 0xa2, 0x36, 0x94,
-	0xaf, 0xbf, 0xdf, 0xbb, 0xbb, 0xe0, 0x01, 0x22, 0x65, 0x51, 0x93, 0x14,
-	0x33, 0x37, 0x77, 0xfb, 0xee, 0xbb, 0xef, 0xfb, 0x7c, 0xbd, 0xcf, 0xf3,
-	0xfc, 0x9e, 0xf7, 0x5d, 0x44, 0x45, 0xda, 0xc4, 0xff, 0xdb, 0x8a, 0x4f,
-	0xec, 0xd8, 0xf1, 0xc7, 0xef, 0xfd, 0xf8, 0xbd, 0xbf, 0x8a, 0x9f, 0xf7,
-	0x89, 0xd6, 0x62, 0xf0, 0xe6, 0x5b, 0x86, 0x48, 0xf6, 0xcf, 0xe5, 0x43,
-	0xff, 0xe1, 0x71, 0x33, 0x18, 0x9f, 0x1f, 0x09, 0xeb, 0x89, 0x57, 0x87,
-	0x93, 0xb6, 0x84, 0x8d, 0x44, 0xfe, 0xa1, 0x71, 0x5b, 0xc4, 0xad, 0xf6,
-	0xc5, 0x52, 0xf2, 0x6e, 0x3d, 0x1f, 0x09, 0x09, 0xdb, 0x3f, 0x92, 0xb8,
-	0xf6, 0xe4, 0xf7, 0x3e, 0x6e, 0xbd, 0x5d, 0x36, 0x24, 0x6c, 0x26, 0xb2,
-	0x62, 0xf6, 0x48, 0xb8, 0x0b, 0xcf, 0x7c, 0xf5, 0xae, 0x47, 0x0d, 0xe9,
-	0x08, 0xc6, 0x7a, 0xab, 0xfe, 0xbd, 0xbb, 0x24, 0xbf, 0x2b, 0x51, 0x8f,
-	0x85, 0x12, 0xef, 0xd6, 0xa7, 0x06, 0xc2, 0xa2, 0x27, 0xac, 0x68, 0xd2,
-	0x88, 0xc8, 0xcb, 0x35, 0x53, 0x5e, 0xac, 0xc5, 0x64, 0xb2, 0x26, 0x1d,
-	0xe9, 0xda, 0x8d, 0x68, 0xaa, 0xa3, 0xef, 0xbb, 0xf5, 0xe4, 0x40, 0x28,
-	0x6b, 0x24, 0xa4, 0x23, 0x59, 0x93, 0xd1, 0x63, 0xc5, 0xd6, 0x87, 0x9b,
-	0x12, 0x4f, 0xd6, 0x75, 0x5b, 0xb2, 0xa1, 0x84, 0x9d, 0xd7, 0xf5, 0xf6,
-	0x41, 0xf3, 0x63, 0x68, 0xaf, 0x0e, 0x86, 0x26, 0x8b, 0xa6, 0x9c, 0x1b,
-	0x68, 0x15, 0xdd, 0x0e, 0x4b, 0xb2, 0xd6, 0xfa, 0xb0, 0x9e, 0x88, 0x88,
-	0x5b, 0xab, 0xd7, 0x8f, 0x39, 0xff, 0x64, 0xaf, 0xf9, 0xeb, 0xe1, 0xf0,
-	0x64, 0x51, 0xde, 0x0e, 0xd9, 0x76, 0x74, 0x42, 0x7a, 0xcc, 0x9c, 0x68,
-	0x92, 0xec, 0xef, 0x89, 0x1e, 0xc1, 0xf7, 0x78, 0x7f, 0xdc, 0x4c, 0xc9,
-	0x16, 0x71, 0xcd, 0x6f, 0xae, 0x98, 0x3d, 0x5d, 0x59, 0x3d, 0x11, 0x96,
-	0x74, 0x51, 0x13, 0xc3, 0x8e, 0xc8, 0x64, 0xc5, 0x96, 0xfc, 0x52, 0x87,
-	0xe4, 0x2b, 0xf2, 0xc4, 0x94, 0xd3, 0x2e, 0x53, 0x4b, 0x47, 0x7d, 0x5d,
-	0x44, 0xd0, 0xd6, 0x2b, 0xf9, 0x5a, 0x14, 0x9f, 0x9f, 0xf8, 0xfc, 0xea,
-	0x22, 0x3b, 0x05, 0xcf, 0xf7, 0xa7, 0xdd, 0xea, 0xd7, 0xc2, 0x5e, 0xdb,
-	0x7f, 0xd9, 0xe2, 0x7d, 0x83, 0xdf, 0x12, 0xf8, 0x2d, 0x85, 0x65, 0xcd,
-	0x88, 0xca, 0xf7, 0xee, 0x8a, 0xc9, 0x54, 0x69, 0x0d, 0xb2, 0x89, 0xca,
-	0x37, 0x6a, 0x11, 0x79, 0x49, 0xc9, 0x22, 0xa4, 0x0d, 0xa3, 0xcf, 0x64,
-	0x69, 0x42, 0x3f, 0x51, 0xcc, 0x4b, 0xaa, 0x96, 0xd5, 0x0b, 0x73, 0x66,
-	0x47, 0x72, 0x29, 0xa7, 0x4f, 0xce, 0x75, 0x76, 0xa4, 0x96, 0x26, 0xf4,
-	0x42, 0x31, 0x0a, 0x39, 0x98, 0x1d, 0xa9, 0xf9, 0x08, 0xae, 0x3b, 0x3b,
-	0x92, 0xf3, 0xd6, 0x0c, 0x26, 0x45, 0x9f, 0x68, 0x47, 0xaa, 0x64, 0x65,
-	0x45, 0xba, 0x9d, 0x1f, 0x48, 0x57, 0x47, 0xaa, 0xf6, 0x5b, 0xfa, 0x8a,
-	0xa9, 0x49, 0xe1, 0x1e, 0x31, 0xa3, 0x89, 0xb7, 0xeb, 0xb7, 0xdb, 0x9a,
-	0x98, 0xf6, 0x3b, 0xf5, 0xed, 0x90, 0x4d, 0x6e, 0xb6, 0x15, 0xbc, 0x92,
-	0x26, 0x53, 0x72, 0xf3, 0x7d, 0xe6, 0xaa, 0x34, 0x89, 0x1b, 0x09, 0xae,
-	0xeb, 0xf5, 0xa4, 0xf3, 0x07, 0xe4, 0x91, 0xf2, 0xee, 0x18, 0x86, 0x5e,
-	0x92, 0xa0, 0x39, 0xe9, 0xbc, 0x5b, 0xf7, 0x9e, 0x09, 0x63, 0xce, 0x50,
-	0xc7, 0x50, 0xa9, 0x5e, 0x4f, 0x3b, 0x18, 0xdf, 0x09, 0x9e, 0x6d, 0x92,
-	0x72, 0xc4, 0x2d, 0x4f, 0x3a, 0x96, 0xe1, 0xc9, 0x87, 0xba, 0xe7, 0xb5,
-	0x0b, 0x7d, 0xe4, 0x25, 0x17, 0x91, 0x72, 0xc1, 0xf9, 0x98, 0x3c, 0xe5,
-	0x44, 0xc1, 0x5f, 0x58, 0x4e, 0x39, 0xb0, 0x2f, 0xfb, 0xb8, 0x96, 0xac,
-	0x59, 0xb1, 0xac, 0x3c, 0x2d, 0xc9, 0xf9, 0x6e, 0x33, 0x2d, 0x98, 0xdb,
-	0xae, 0xdf, 0x99, 0x74, 0x30, 0x5f, 0xff, 0xff, 0xad, 0xbb, 0x11, 0x2b,
-	0x5b, 0x96, 0x5e, 0x29, 0x94, 0xba, 0x9d, 0x1f, 0x43, 0x4f, 0x61, 0x5b,
-	0xdc, 0x71, 0xdb, 0x84, 0xdc, 0xac, 0xde, 0x94, 0x51, 0x97, 0x07, 0x31,
-	0x7f, 0xd2, 0xc6, 0xfd, 0x9a, 0x6c, 0xd3, 0xed, 0x66, 0x29, 0x98, 0x12,
-	0x69, 0x93, 0xdd, 0x52, 0x98, 0x45, 0xbb, 0xe3, 0x76, 0xea, 0x78, 0x26,
-	0x33, 0xc0, 0x36, 0xd1, 0x8c, 0x04, 0x75, 0x2c, 0xb2, 0x50, 0xed, 0xc5,
-	0xfc, 0x71, 0xb7, 0x55, 0x33, 0x65, 0xcd, 0x0c, 0x49, 0xa5, 0x1a, 0x77,
-	0xa3, 0x5a, 0xb3, 0x9c, 0x8a, 0xb7, 0x41, 0xa6, 0x51, 0x8c, 0x2d, 0x5f,
-	0xd6, 0x13, 0xf1, 0x68, 0x0e, 0x4a, 0xa3, 0x1d, 0x4d, 0x81, 0x9e, 0x29,
-	0x27, 0xab, 0xa5, 0x6a, 0x9f, 0xd3, 0x92, 0x4b, 0x87, 0xb4, 0xfd, 0x4b,
-	0xe8, 0x53, 0xfb, 0x1f, 0xbe, 0x0d, 0x44, 0x41, 0x9b, 0x8e, 0x67, 0xd9,
-	0x0e, 0x9a, 0x15, 0xed, 0x68, 0x83, 0x2e, 0x57, 0xc6, 0x22, 0x1d, 0x49,
-	0xa5, 0x4b, 0xd2, 0xa6, 0x4b, 0x6e, 0x54, 0x93, 0x4e, 0xdb, 0x95, 0xf0,
-	0xaf, 0x41, 0x9f, 0xf3, 0xd0, 0xe5, 0x7c, 0x4c, 0x4e, 0x94, 0x24, 0xa2,
-	0x0b, 0xe7, 0xca, 0xea, 0x95, 0x2a, 0xed, 0x01, 0xba, 0x85, 0xee, 0x0b,
-	0x55, 0x3e, 0x0b, 0x1d, 0x96, 0xd2, 0x90, 0x4f, 0x06, 0x73, 0x1f, 0xd4,
-	0x1e, 0xac, 0x8c, 0x69, 0x19, 0xd8, 0x49, 0x61, 0xb6, 0x0f, 0xba, 0xb3,
-	0x62, 0x6b, 0xb2, 0x4d, 0x0a, 0xb6, 0x1d, 0xfb, 0xac, 0xb4, 0xcb, 0xa9,
-	0x79, 0x5b, 0x4e, 0xcc, 0xc3, 0x1e, 0x4d, 0xcb, 0x5c, 0x94, 0xae, 0xec,
-	0x96, 0x44, 0x87, 0x3c, 0x3d, 0x6b, 0x65, 0xca, 0xd2, 0xed, 0xbe, 0x81,
-	0xfb, 0xb9, 0x33, 0xd4, 0xa9, 0xe4, 0x53, 0x8e, 0x21, 0x59, 0x93, 0x76,
-	0x7d, 0x9b, 0x26, 0x6d, 0xf5, 0x27, 0x93, 0x8e, 0x15, 0xa5, 0xcd, 0xa6,
-	0x3e, 0xdd, 0x6d, 0x1e, 0x10, 0xcb, 0xcc, 0x50, 0xfe, 0x4e, 0x1f, 0xf4,
-	0xf0, 0xbf, 0x29, 0x7b, 0x8c, 0x45, 0x1d, 0xf7, 0x45, 0x4f, 0x41, 0x97,
-	0x59, 0xa5, 0xe3, 0x0e, 0xcc, 0x1f, 0xf2, 0x6d, 0x87, 0x6b, 0xe2, 0x6e,
-	0xcd, 0x93, 0x43, 0x87, 0xcc, 0x54, 0xda, 0xa5, 0x00, 0x1d, 0x16, 0xc4,
-	0x96, 0xc2, 0xd2, 0x5e, 0xbf, 0xdd, 0xc6, 0x7a, 0xf9, 0x53, 0x5d, 0xda,
-	0x8e, 0x6b, 0x87, 0x6a, 0x3f, 0xd7, 0x7c, 0xfb, 0x81, 0xfd, 0x85, 0xc5,
-	0x1d, 0x0d, 0xcb, 0xf9, 0x9a, 0x67, 0x7f, 0x0b, 0xf0, 0x3d, 0xae, 0xe9,
-	0xc2, 0x96, 0xde, 0x5c, 0xef, 0x73, 0xbe, 0xd6, 0x85, 0x67, 0xc3, 0x72,
-	0xa2, 0xc6, 0xfe, 0x79, 0xd8, 0x58, 0x58, 0x96, 0xef, 0x6a, 0x97, 0x2c,
-	0xda, 0x0b, 0xf3, 0xe2, 0x26, 0x1d, 0x1d, 0xcf, 0x74, 0x80, 0x97, 0x9d,
-	0xf8, 0xb4, 0xc9, 0x78, 0xa5, 0xc5, 0xe5, 0x7a, 0x1d, 0xaf, 0x51, 0xff,
-	0xf8, 0x2e, 0x05, 0x36, 0x40, 0xf9, 0xb2, 0x9d, 0xcf, 0xb1, 0xdd, 0x44,
-	0x7b, 0x63, 0x1b, 0x6d, 0x7b, 0x1b, 0x65, 0xda, 0xcb, 0x35, 0x9a, 0x2b,
-	0xc5, 0xcd, 0x43, 0xfc, 0xae, 0xd1, 0x1e, 0x1a, 0x6d, 0x21, 0x84, 0xfe,
-	0xd0, 0x63, 0x05, 0x73, 0xcd, 0x5e, 0xab, 0x37, 0x0d, 0xe0, 0xda, 0xfe,
-	0x1d, 0xf0, 0xc9, 0xb9, 0x43, 0xa0, 0x4b, 0x97, 0x6c, 0x45, 0xd1, 0x16,
-	0xa3, 0x0d, 0x78, 0x7c, 0x74, 0xc9, 0xe4, 0x7c, 0x7b, 0x47, 0x7a, 0x9e,
-	0xed, 0xc9, 0xa8, 0x01, 0x3e, 0xc7, 0x1d, 0x59, 0x99, 0x72, 0xf4, 0xee,
-	0x10, 0xe8, 0x9a, 0xc0, 0x82, 0x03, 0x1f, 0x3e, 0x8d, 0x2b, 0xb8, 0xdf,
-	0x29, 0xe3, 0x4b, 0xec, 0xcb, 0x39, 0x0a, 0xdb, 0x75, 0x49, 0x80, 0x36,
-	0x7c, 0x6c, 0x0b, 0xf7, 0x5b, 0x31, 0x4f, 0x3b, 0x6c, 0x67, 0x9a, 0xba,
-	0xfb, 0x44, 0xd2, 0xe9, 0x94, 0xec, 0x7a, 0x5f, 0x81, 0xdd, 0xb1, 0x7f,
-	0xef, 0xa6, 0xbe, 0x90, 0xef, 0x12, 0xc6, 0x9c, 0x6f, 0x85, 0x0c, 0xd9,
-	0xae, 0x83, 0xe6, 0x16, 0xd0, 0x00, 0x1f, 0x6c, 0x77, 0x63, 0x3d, 0xb4,
-	0x60, 0xfc, 0x2d, 0xe0, 0xa9, 0x55, 0x26, 0x66, 0x3b, 0xa1, 0x0b, 0x13,
-	0x7d, 0xc3, 0xf2, 0x74, 0xc9, 0x82, 0x0d, 0xb0, 0x3f, 0x74, 0x30, 0x6f,
-	0x45, 0x2b, 0xe2, 0xca, 0x94, 0xd3, 0x02, 0xfb, 0xaa, 0xd7, 0x8f, 0xc0,
-	0x3e, 0xbe, 0xae, 0xfc, 0x45, 0x9f, 0x39, 0xa4, 0x49, 0xbe, 0x25, 0xf1,
-	0x7d, 0xd0, 0x63, 0x3d, 0x2a, 0xc2, 0xeb, 0xbd, 0x1a, 0xd7, 0x2c, 0xe4,
-	0xc8, 0xb9, 0xe1, 0x93, 0x76, 0x42, 0x86, 0xf4, 0x5b, 0x5d, 0xb0, 0xe7,
-	0xa8, 0xf2, 0x27, 0x43, 0x37, 0xf4, 0x27, 0xd6, 0x68, 0x19, 0x73, 0x15,
-	0x96, 0x42, 0xf4, 0x61, 0x83, 0x58, 0xae, 0xb2, 0x15, 0x6b, 0x6f, 0x52,
-	0xd9, 0xc7, 0x4f, 0xc8, 0x6f, 0xfd, 0x53, 0x0e, 0xe9, 0x22, 0xbf, 0x2e,
-	0x9e, 0xa5, 0x0d, 0x5a, 0xc7, 0x5d, 0x35, 0xff, 0x4f, 0xfc, 0xf9, 0x3d,
-	0xda, 0x0b, 0xa5, 0x0e, 0x2d, 0xa5, 0x68, 0x08, 0xc6, 0x11, 0x59, 0x3d,
-	0xd3, 0x6d, 0x3e, 0x08, 0x1b, 0xa6, 0x9f, 0x5a, 0xbd, 0x40, 0x1d, 0x63,
-	0x8c, 0x01, 0xea, 0xd8, 0x54, 0xf4, 0x25, 0xe7, 0xb9, 0xf6, 0xa4, 0xcb,
-	0x10, 0xfa, 0x08, 0xf8, 0x5c, 0xac, 0xc5, 0x49, 0x7f, 0x2d, 0xe6, 0xaa,
-	0xb4, 0xbf, 0xc7, 0xf1, 0xac, 0x2e, 0x43, 0x71, 0xfa, 0x87, 0xa7, 0x25,
-	0x05, 0x1f, 0x09, 0x3d, 0x4a, 0x05, 0xbc, 0x2c, 0x94, 0x1a, 0xfd, 0x16,
-	0x6c, 0xab, 0xff, 0xaf, 0xeb, 0x9e, 0x3f, 0xa4, 0x6f, 0xa0, 0xaf, 0x29,
-	0x98, 0x3a, 0x24, 0x87, 0xc8, 0xe0, 0x42, 0x37, 0x4e, 0xd2, 0xb0, 0x32,
-	0x59, 0xc6, 0x1c, 0xbb, 0x2e, 0xf6, 0x7d, 0x82, 0x48, 0xda, 0xcb, 0xf8,
-	0xb7, 0x2f, 0xf0, 0x4f, 0xab, 0xd5, 0x40, 0x17, 0xd4, 0x2b, 0xf5, 0x10,
-	0xf8, 0x88, 0x90, 0x5c, 0x84, 0xef, 0x9a, 0x2a, 0xb5, 0xcb, 0x0a, 0x68,
-	0xba, 0x54, 0x0d, 0x6c, 0xcd, 0xf0, 0x6d, 0x8d, 0xcf, 0xb4, 0xe3, 0xf9,
-	0x10, 0xfc, 0x9a, 0xe4, 0x8d, 0x04, 0x7e, 0x17, 0x39, 0x26, 0xdb, 0x02,
-	0x3b, 0xe7, 0x9a, 0xb1, 0xdc, 0xb2, 0x34, 0x4b, 0x26, 0x8e, 0xf8, 0x31,
-	0xaf, 0x63, 0xae, 0x2e, 0xf8, 0xf2, 0x90, 0x1c, 0x2d, 0x45, 0xe4, 0xf3,
-	0x25, 0xf2, 0x95, 0xd6, 0x52, 0xd0, 0x5b, 0x72, 0xbe, 0x0e, 0x9d, 0x0f,
-	0xc3, 0xe7, 0x65, 0xb4, 0x21, 0xf8, 0x9f, 0x03, 0x95, 0xcf, 0x69, 0xe9,
-	0xa5, 0xac, 0x36, 0x5c, 0x3b, 0xa4, 0x65, 0x96, 0xc6, 0xb4, 0xfd, 0x0d,
-	0xbe, 0x48, 0xb4, 0xf7, 0xf7, 0x45, 0x4f, 0xcd, 0x72, 0xce, 0x6e, 0xe7,
-	0xc6, 0xbe, 0xe8, 0xd7, 0xf5, 0x46, 0x5f, 0xd4, 0x0d, 0x5f, 0x94, 0x81,
-	0x2f, 0x1a, 0xbe, 0x65, 0x5f, 0x34, 0xa2, 0xdf, 0xd8, 0x17, 0x1d, 0xd4,
-	0xaf, 0xfb, 0x22, 0xc6, 0x9e, 0x15, 0x5c, 0x9b, 0xb2, 0x67, 0x5f, 0x20,
-	0xe7, 0x28, 0xfc, 0xf0, 0x16, 0xc8, 0xba, 0x8d, 0x6b, 0x27, 0x56, 0x80,
-	0xdd, 0x4f, 0x60, 0xae, 0xdf, 0x86, 0xbd, 0xef, 0x89, 0xdb, 0xe6, 0x43,
-	0x6a, 0xde, 0xf7, 0xea, 0x7c, 0x68, 0x5d, 0xe7, 0xa4, 0xf1, 0x97, 0xea,
-	0xdc, 0xf5, 0x74, 0x4e, 0x5d, 0xb7, 0xca, 0x11, 0x35, 0x6f, 0x5d, 0x42,
-	0xf7, 0x09, 0xbc, 0x8a, 0x3c, 0x60, 0x24, 0x2c, 0x8c, 0xa7, 0x63, 0x7e,
-	0xea, 0x2b, 0x0e, 0x1a, 0x04, 0xfa, 0x6d, 0x57, 0xbe, 0x68, 0x3f, 0xf4,
-	0xbe, 0x5a, 0xbd, 0x35, 0x5d, 0x65, 0x1a, 0x74, 0xf5, 0xe0, 0x06, 0x5d,
-	0xb5, 0x48, 0x7f, 0x3c, 0xd0, 0xd1, 0x36, 0x49, 0xc6, 0xa9, 0xb3, 0x5b,
-	0xd1, 0xd5, 0xb9, 0xbf, 0x25, 0x5d, 0x7d, 0xf7, 0x26, 0xba, 0xfa, 0xde,
-	0x26, 0x5d, 0xd9, 0xe6, 0x33, 0x1a, 0xc7, 0x66, 0xfc, 0xa0, 0x3f, 0xaa,
-	0xdf, 0x39, 0xce, 0xfc, 0xa1, 0xc6, 0x35, 0x1d, 0xe4, 0x1d, 0x5c, 0xcf,
-	0x2f, 0xd7, 0x0d, 0xdb, 0x86, 0xec, 0xb8, 0xa6, 0x29, 0x37, 0xcb, 0xfc,
-	0x14, 0xe9, 0x47, 0xec, 0x18, 0x47, 0xac, 0xf1, 0x68, 0x68, 0x96, 0xf2,
-	0x76, 0xaf, 0xff, 0x78, 0xa9, 0xfe, 0x73, 0x3d, 0xf1, 0x0b, 0xe4, 0x95,
-	0xb6, 0x1f, 0x07, 0xc2, 0xf2, 0x85, 0x8a, 0x95, 0x75, 0xb5, 0x76, 0xc9,
-	0xef, 0x40, 0xec, 0x29, 0xd1, 0x7f, 0xed, 0xbc, 0x49, 0x8c, 0xee, 0xf2,
-	0x63, 0xf4, 0x9f, 0x81, 0x56, 0xe6, 0x57, 0xff, 0xe6, 0xdd, 0x95, 0x08,
-	0xbf, 0xe3, 0xe6, 0x41, 0xf9, 0x2c, 0x79, 0x44, 0xbc, 0x67, 0xdc, 0xb7,
-	0x99, 0xf3, 0xe4, 0x43, 0x89, 0x36, 0xc9, 0x6f, 0xe7, 0x7a, 0xa4, 0x9f,
-	0xa3, 0xef, 0x6a, 0xf6, 0xe9, 0x0e, 0x72, 0x24, 0xfe, 0xb5, 0x18, 0x60,
-	0x19, 0x7d, 0x90, 0x0f, 0x95, 0xc8, 0xc7, 0xbb, 0xbe, 0x3d, 0x31, 0x57,
-	0x90, 0x26, 0xcf, 0x37, 0x8c, 0x20, 0x17, 0xa0, 0x1d, 0x04, 0x3a, 0xa7,
-	0xbe, 0x99, 0x23, 0x48, 0x4c, 0xb7, 0x99, 0x23, 0x88, 0x69, 0x24, 0x0e,
-	0x6a, 0x2e, 0x74, 0xef, 0x42, 0xf7, 0x2e, 0x74, 0xef, 0x42, 0xf7, 0xc9,
-	0xda, 0x71, 0xdc, 0x53, 0x79, 0x08, 0x68, 0xf1, 0xc6, 0x4f, 0x7b, 0xe3,
-	0x83, 0xce, 0x9d, 0x92, 0x53, 0x3a, 0x21, 0xbf, 0xc8, 0x35, 0x94, 0xbf,
-	0x1e, 0xd6, 0x3c, 0x7f, 0xcd, 0xf1, 0x32, 0x78, 0xfe, 0x7e, 0xe4, 0x73,
-	0xae, 0xae, 0xdb, 0xd7, 0x65, 0x32, 0xd5, 0x20, 0x93, 0xc9, 0x2a, 0x65,
-	0xc4, 0xfe, 0xf4, 0xb9, 0x13, 0xfa, 0xc2, 0xba, 0x5c, 0x46, 0x40, 0x43,
-	0x0b, 0x79, 0xf7, 0xf9, 0xe0, 0xf8, 0x9d, 0xfe, 0xf8, 0xbf, 0x81, 0x31,
-	0xe9, 0x5f, 0x6f, 0x34, 0x2f, 0xe7, 0x64, 0xce, 0xf8, 0x7e, 0xfc, 0x20,
-	0x67, 0xc6, 0x1a, 0x78, 0x69, 0x3d, 0x9f, 0x8e, 0x21, 0x9f, 0x7e, 0x07,
-	0xb9, 0x74, 0xbd, 0xce, 0x38, 0x55, 0x40, 0x9e, 0x9b, 0x76, 0xb8, 0xae,
-	0x6f, 0x65, 0xdd, 0x6e, 0x58, 0xb3, 0x66, 0xd2, 0xe0, 0xb8, 0x61, 0xf1,
-	0xc6, 0xe4, 0xfd, 0x16, 0xe4, 0x82, 0xef, 0xe0, 0x37, 0x7d, 0x72, 0x90,
-	0xe7, 0xb1, 0x0f, 0x9f, 0x7f, 0x15, 0x73, 0xf7, 0x03, 0xcf, 0xf4, 0xca,
-	0x77, 0x6a, 0xb6, 0x7c, 0x1b, 0x98, 0xe6, 0x5b, 0xc8, 0x2d, 0xbe, 0x59,
-	0x0b, 0x72, 0xfb, 0xbd, 0x30, 0x75, 0xe6, 0xf7, 0x12, 0xde, 0x69, 0x13,
-	0x57, 0xe5, 0xf7, 0x7f, 0xda, 0x96, 0xad, 0x11, 0xfc, 0xfe, 0x95, 0x84,
-	0x6c, 0xeb, 0xc4, 0xf7, 0xf6, 0x04, 0x4c, 0x27, 0xc1, 0xd8, 0xa8, 0x35,
-	0xc4, 0x46, 0xd1, 0xd2, 0xe0, 0x71, 0x0a, 0xe3, 0xa5, 0xc1, 0xf7, 0x67,
-	0x6a, 0x61, 0x2d, 0x35, 0xbb, 0x1b, 0x98, 0x24, 0xc8, 0x71, 0x91, 0x47,
-	0x99, 0xab, 0xdb, 0x43, 0xf2, 0x36, 0x78, 0x4a, 0x82, 0x76, 0x17, 0x39,
-	0xc0, 0x3f, 0xc5, 0x5c, 0xd6, 0x4f, 0x3f, 0x2d, 0xff, 0xda, 0xcf, 0xc3,
-	0x9b, 0x64, 0x4e, 0xf1, 0xc8, 0x76, 0xc9, 0xfc, 0xcb, 0x9e, 0xeb, 0xed,
-	0xcf, 0xae, 0xb7, 0xc7, 0x32, 0xbf, 0xb1, 0xde, 0x7e, 0x35, 0xe4, 0xe1,
-	0x95, 0x41, 0x6d, 0xb4, 0xf6, 0x2f, 0x8c, 0x00, 0xeb, 0x14, 0x66, 0x7b,
-	0x31, 0xd7, 0x36, 0x99, 0xb4, 0xdf, 0x06, 0xf6, 0xb2, 0x63, 0x39, 0xac,
-	0xaf, 0xa7, 0x36, 0xf9, 0xfa, 0x36, 0xf8, 0x8f, 0xd3, 0xb3, 0xd6, 0x20,
-	0xfd, 0x47, 0x1c, 0x6b, 0x29, 0xf9, 0x1e, 0xff, 0xf1, 0x6d, 0xa3, 0xd1,
-	0x7f, 0x18, 0xf0, 0x1f, 0xfb, 0xdf, 0xc7, 0x7f, 0x3c, 0xf5, 0x1e, 0xff,
-	0xa1, 0xc1, 0x2e, 0xe8, 0x3f, 0x7e, 0x68, 0x04, 0xfe, 0xa3, 0xb0, 0xc1,
-	0x7f, 0x04, 0xfa, 0xb0, 0x55, 0xee, 0xe8, 0xfd, 0x26, 0xfe, 0x6c, 0xf3,
-	0x31, 0xa7, 0x84, 0x43, 0x09, 0x37, 0x33, 0x65, 0xef, 0x92, 0x26, 0xac,
-	0xd1, 0x97, 0x6b, 0x03, 0xf0, 0x25, 0xbf, 0x0f, 0x9c, 0x66, 0x39, 0x4c,
-	0x44, 0x9a, 0x12, 0xd4, 0xcd, 0x48, 0x2c, 0x69, 0xbf, 0x90, 0x59, 0xa8,
-	0xbe, 0x90, 0x39, 0xa7, 0x74, 0x35, 0x61, 0x79, 0x18, 0xf8, 0x09, 0x0b,
-	0x18, 0x18, 0xcf, 0x87, 0x80, 0x21, 0xd8, 0xde, 0x6e, 0x26, 0x91, 0xa3,
-	0x54, 0xaa, 0x2b, 0x99, 0x02, 0x3e, 0x53, 0xaa, 0xef, 0x58, 0x8c, 0x7d,
-	0x5b, 0x12, 0xe5, 0xd8, 0x9f, 0xe2, 0xbb, 0x39, 0x31, 0x67, 0x5d, 0xb6,
-	0x39, 0xee, 0x6b, 0xb1, 0x73, 0x6a, 0x8c, 0x90, 0x14, 0xd4, 0xb3, 0x5f,
-	0xb5, 0xf8, 0xec, 0x29, 0xf8, 0xf8, 0x93, 0x55, 0x53, 0x4e, 0x54, 0xd7,
-	0x32, 0x39, 0x7c, 0x88, 0x6d, 0x5e, 0x2e, 0xf1, 0xfe, 0xb7, 0x70, 0x3f,
-	0x24, 0xcc, 0x3d, 0x3e, 0x8f, 0x3e, 0x47, 0xd1, 0xe7, 0x48, 0x35, 0xc0,
-	0x8d, 0xbc, 0xef, 0x66, 0x52, 0xb8, 0x7f, 0xa4, 0xe8, 0x66, 0xd2, 0x45,
-	0xe6, 0x39, 0x7d, 0xd1, 0x13, 0x90, 0x67, 0x16, 0xb1, 0xdd, 0x15, 0xab,
-	0x37, 0x2f, 0x8f, 0xb5, 0x0e, 0x23, 0xaf, 0x3e, 0x8f, 0x98, 0xe3, 0x8e,
-	0x59, 0x4e, 0x19, 0xcc, 0x4d, 0x95, 0xee, 0x90, 0xc2, 0x0c, 0x62, 0x8c,
-	0x73, 0x0f, 0x73, 0xed, 0x8c, 0x1e, 0x77, 0xe0, 0x13, 0x06, 0x80, 0x27,
-	0xbb, 0x81, 0x85, 0xef, 0x92, 0x15, 0xd3, 0x8a, 0x0e, 0x03, 0x03, 0xa7,
-	0x42, 0xe8, 0xd3, 0x7b, 0x9b, 0x64, 0xa3, 0x94, 0xf5, 0x0e, 0xf8, 0x07,
-	0x4d, 0x5a, 0xec, 0x46, 0x5f, 0xf5, 0x17, 0x10, 0x2f, 0x92, 0xdf, 0x36,
-	0xb6, 0xb7, 0xfa, 0x3a, 0xd9, 0x22, 0xab, 0xef, 0xe9, 0xf7, 0x37, 0x0d,
-	0xfd, 0x1a, 0xdb, 0x35, 0x4d, 0xd0, 0x7f, 0x0d, 0x34, 0x84, 0xe2, 0x90,
-	0x3f, 0x78, 0x68, 0x82, 0x9d, 0x5c, 0x06, 0x3f, 0xf4, 0x9b, 0x85, 0x32,
-	0xe3, 0xa4, 0x21, 0x65, 0x13, 0xf7, 0xaa, 0xf5, 0xfa, 0x82, 0x0d, 0x5a,
-	0x2f, 0x90, 0xde, 0xb0, 0x0c, 0x57, 0x7b, 0xc4, 0x5d, 0xa4, 0x1c, 0x2c,
-	0xac, 0x8e, 0x5d, 0x6d, 0xa9, 0x79, 0xcb, 0xcd, 0x63, 0x44, 0xe3, 0x42,
-	0x57, 0x5b, 0x12, 0x71, 0x51, 0xbf, 0x10, 0x6b, 0x4b, 0xc1, 0x1f, 0x18,
-	0x17, 0x6e, 0x6f, 0x4b, 0xcf, 0x92, 0x2e, 0x03, 0x71, 0xf1, 0x4e, 0xe0,
-	0xc2, 0xba, 0x7c, 0x0d, 0xb9, 0x4f, 0xa1, 0x17, 0x31, 0x03, 0xab, 0x44,
-	0x07, 0xdd, 0x79, 0x53, 0xc2, 0x6d, 0x89, 0x79, 0xd0, 0xd7, 0xdf, 0x9a,
-	0x9c, 0xdd, 0x82, 0x3e, 0x06, 0xda, 0x7b, 0x88, 0x21, 0x1b, 0xda, 0xed,
-	0x36, 0xf8, 0x5f, 0xf8, 0x3a, 0x09, 0x27, 0x07, 0xda, 0x31, 0xfe, 0xd9,
-	0x10, 0x73, 0x87, 0x70, 0x7c, 0xbd, 0xfd, 0xcb, 0x5e, 0x7b, 0x2f, 0x68,
-	0xe1, 0x73, 0xcc, 0x21, 0x25, 0x3c, 0x3e, 0x60, 0x82, 0x06, 0xf6, 0x8d,
-	0xa8, 0xbe, 0xe9, 0x79, 0xda, 0x80, 0x9b, 0x59, 0xb0, 0x77, 0x4b, 0x6a,
-	0x6e, 0xa7, 0x0c, 0xcf, 0x75, 0xca, 0xfe, 0x39, 0xe6, 0xbc, 0xc4, 0xc0,
-	0x60, 0x05, 0x39, 0xa9, 0x7e, 0x81, 0xb9, 0x80, 0x15, 0x3d, 0x2a, 0xdd,
-	0xd1, 0xcf, 0x63, 0x1d, 0x8c, 0xdb, 0xf1, 0xd8, 0x24, 0xd6, 0x58, 0x48,
-	0x8d, 0x13, 0x0d, 0xe6, 0xa4, 0x8d, 0x6e, 0x98, 0x37, 0x3d, 0x7f, 0xb3,
-	0x71, 0xb1, 0x70, 0x2e, 0x44, 0x37, 0x8d, 0xfb, 0x3f, 0xfd, 0x71, 0x4d,
-	0x8c, 0xdb, 0x85, 0x31, 0xc9, 0xe3, 0xed, 0xad, 0x43, 0xb3, 0xe2, 0xb6,
-	0x80, 0xbe, 0x74, 0x7c, 0x97, 0x4c, 0x62, 0x9c, 0x93, 0x73, 0xf4, 0x85,
-	0xb2, 0x13, 0x9f, 0xfe, 0x26, 0x89, 0xf7, 0x2e, 0x21, 0x2f, 0x1e, 0x52,
-	0x63, 0x78, 0x39, 0xaa, 0x7e, 0x21, 0x01, 0x5c, 0xf3, 0x51, 0xd0, 0xc3,
-	0x98, 0x4c, 0x9e, 0x43, 0xe0, 0x37, 0x81, 0x75, 0x48, 0x3c, 0xce, 0xf5,
-	0x8d, 0xdf, 0x4b, 0xd1, 0xd6, 0xd4, 0x6c, 0x33, 0xd6, 0x9d, 0xec, 0x36,
-	0x54, 0xac, 0xa0, 0x5e, 0xec, 0xd6, 0x64, 0x49, 0xd1, 0xdd, 0x9a, 0x2a,
-	0x51, 0x46, 0x4e, 0x6b, 0xba, 0x44, 0x19, 0x09, 0xe8, 0x71, 0xe0, 0x63,
-	0x43, 0x12, 0xdb, 0x4e, 0x3d, 0x1e, 0x43, 0xbf, 0x95, 0x10, 0xf3, 0xfe,
-	0xa4, 0xcd, 0xdf, 0xc0, 0x2b, 0x17, 0x8e, 0xa3, 0x2f, 0x7f, 0xdf, 0x8b,
-	0x71, 0xbb, 0x7b, 0x0b, 0xd2, 0xdc, 0x7b, 0x04, 0x7e, 0x42, 0x1f, 0x00,
-	0xee, 0x50, 0x76, 0x5e, 0x07, 0x26, 0xdb, 0x0b, 0x7e, 0xb0, 0x36, 0xe2,
-	0xb6, 0x4c, 0xcc, 0x50, 0xae, 0x72, 0x1b, 0x78, 0x00, 0xff, 0x71, 0xf8,
-	0x16, 0xf2, 0xc0, 0xb9, 0x05, 0x76, 0xbf, 0x2c, 0xb9, 0x99, 0xb0, 0xc2,
-	0x3e, 0xae, 0xc9, 0xf9, 0x35, 0x4d, 0x4f, 0xb4, 0x41, 0xc7, 0xe4, 0x6d,
-	0x0a, 0xb4, 0x3d, 0x0e, 0x3f, 0x6c, 0xa9, 0x9c, 0xdb, 0x40, 0xff, 0x42,
-	0x69, 0x50, 0x4f, 0x15, 0x49, 0xbf, 0x6f, 0x7b, 0xda, 0x0a, 0x7c, 0x8a,
-	0xaa, 0x63, 0x21, 0xb7, 0x4b, 0xc0, 0x8f, 0x0c, 0xca, 0xf7, 0xe1, 0x4b,
-	0xbe, 0x5b, 0x73, 0xe0, 0xff, 0xfb, 0xe1, 0xff, 0x7b, 0xe1, 0xff, 0x6d,
-	0xf8, 0xff, 0x18, 0xfc, 0x7f, 0x17, 0xfc, 0x7f, 0x94, 0xbe, 0x5f, 0x4e,
-	0xd6, 0xf2, 0xb0, 0xb1, 0x15, 0xf8, 0x41, 0x33, 0xec, 0xd6, 0x22, 0xe1,
-	0x64, 0x2d, 0x1a, 0x4e, 0xd5, 0x42, 0xe0, 0xe9, 0x30, 0xe7, 0x04, 0x7f,
-	0xf9, 0xd6, 0xa1, 0x52, 0x3f, 0xe2, 0x8a, 0x0b, 0xbf, 0x94, 0x86, 0xdf,
-	0x77, 0x80, 0x7f, 0xf3, 0xb2, 0x3a, 0x13, 0xc3, 0x33, 0x75, 0x49, 0x3b,
-	0x4d, 0x32, 0x69, 0x3a, 0x18, 0x63, 0xbb, 0xb2, 0x53, 0x23, 0xb1, 0xab,
-	0x09, 0x76, 0x2a, 0xb9, 0x22, 0xe3, 0x73, 0x17, 0xc6, 0x6b, 0x45, 0x7c,
-	0xa0, 0x7f, 0xa0, 0x2f, 0x58, 0xc9, 0x3c, 0x6c, 0x73, 0xcd, 0xb5, 0x69,
-	0x49, 0xe0, 0x67, 0x62, 0x13, 0xc4, 0x3a, 0xd8, 0x05, 0xdb, 0xf6, 0xe0,
-	0x39, 0xfe, 0xfe, 0x6f, 0x7e, 0x8d, 0xea, 0xaf, 0x5a, 0x04, 0xc6, 0xfb,
-	0x32, 0x63, 0x8f, 0x8d, 0xf1, 0xaa, 0x8d, 0xeb, 0x75, 0x49, 0x17, 0x3b,
-	0xb8, 0xcf, 0x7a, 0x0d, 0x6b, 0x54, 0xaf, 0x80, 0xde, 0x7a, 0x7d, 0x55,
-	0x61, 0x48, 0xe4, 0x33, 0x87, 0xd6, 0xc0, 0x43, 0xe3, 0x33, 0xdf, 0xc0,
-	0x33, 0xaa, 0x2d, 0x6c, 0x26, 0x1c, 0xe6, 0x50, 0xf0, 0x9b, 0x2f, 0xc0,
-	0x47, 0x1e, 0xcb, 0xe8, 0xcb, 0x57, 0xf1, 0x2c, 0x64, 0x5a, 0x3c, 0x96,
-	0x09, 0xf5, 0xbc, 0x5a, 0x7f, 0x16, 0x39, 0xf1, 0xd0, 0xf2, 0x80, 0xa4,
-	0x96, 0xbb, 0xa3, 0x17, 0xa5, 0xf5, 0x1d, 0x17, 0xb1, 0x74, 0xb2, 0x6a,
-	0x9d, 0x76, 0x85, 0x39, 0xba, 0x29, 0x0b, 0xc0, 0xd5, 0x7b, 0xf6, 0x3d,
-	0x0f, 0xda, 0xad, 0x17, 0x45, 0x8f, 0xe1, 0x37, 0x31, 0x0c, 0x79, 0x5c,
-	0x03, 0x7f, 0x1a, 0xae, 0x5b, 0xd6, 0x6b, 0x57, 0x85, 0x12, 0xf8, 0xac,
-	0x1d, 0xcb, 0x5c, 0x9c, 0x06, 0xae, 0x83, 0x3e, 0x92, 0xd3, 0xc4, 0x9c,
-	0x5b, 0x20, 0x93, 0x21, 0xd8, 0x05, 0xf5, 0x1d, 0xc7, 0xb3, 0x75, 0xf9,
-	0x92, 0x43, 0x1b, 0x78, 0x0e, 0x72, 0xc3, 0x58, 0xa1, 0x80, 0x6e, 0x60,
-	0x80, 0x19, 0xca, 0x6a, 0x17, 0xf2, 0x36, 0x57, 0x06, 0xf6, 0x49, 0x78,
-	0x47, 0x62, 0x73, 0x4e, 0x76, 0x2c, 0xb3, 0x3a, 0x8d, 0xf1, 0x7b, 0x80,
-	0x79, 0x84, 0xb5, 0x19, 0xfa, 0x60, 0x81, 0xed, 0xec, 0x87, 0x7e, 0x98,
-	0x7b, 0x33, 0x47, 0xa3, 0x6f, 0x3a, 0xa8, 0xa5, 0x2a, 0x65, 0x43, 0x3a,
-	0x0e, 0x21, 0xb7, 0x71, 0x64, 0x71, 0x9a, 0x39, 0x1a, 0xf3, 0x99, 0x20,
-	0x7f, 0xd1, 0x90, 0x4b, 0xa0, 0x7d, 0xf9, 0x25, 0xa5, 0x07, 0x03, 0xfa,
-	0xca, 0xed, 0xbb, 0x9f, 0x7c, 0xcd, 0x18, 0x09, 0xf8, 0xbf, 0x01, 0xf2,
-	0xa2, 0x68, 0x40, 0xce, 0xc6, 0x35, 0x17, 0x03, 0x5f, 0xf8, 0x5c, 0xcf,
-	0xdd, 0xd4, 0xdf, 0x64, 0xe9, 0x04, 0xec, 0x58, 0xf2, 0x4d, 0x09, 0xf0,
-	0x36, 0x80, 0xdf, 0x58, 0xf8, 0x27, 0xa1, 0xc3, 0x73, 0x03, 0xac, 0x91,
-	0x3d, 0x07, 0xfc, 0x47, 0xfa, 0xe3, 0xb1, 0x13, 0x6a, 0xdd, 0xe2, 0xba,
-	0xca, 0x3c, 0x62, 0x8b, 0x5c, 0x54, 0x7c, 0xde, 0xc1, 0xfc, 0x14, 0x7a,
-	0xb9, 0x15, 0x3e, 0x87, 0x3f, 0x24, 0x9f, 0xde, 0x3c, 0x8c, 0x5b, 0x49,
-	0x3b, 0x26, 0xa9, 0xe2, 0xcb, 0x75, 0xaf, 0x0e, 0xfb, 0x47, 0xb0, 0x2b,
-	0x5c, 0x57, 0xc3, 0xa0, 0x87, 0x75, 0x99, 0x01, 0xa5, 0x5b, 0xd0, 0x43,
-	0x9b, 0xc9, 0x87, 0x13, 0xdb, 0xe4, 0xfc, 0x4c, 0x87, 0x2c, 0xcc, 0xbc,
-	0x26, 0x95, 0x99, 0x36, 0x59, 0x9a, 0xa9, 0xcb, 0x65, 0x47, 0xf9, 0x25,
-	0xbb, 0x59, 0xad, 0x69, 0xd9, 0xe5, 0x61, 0xf6, 0xf8, 0xe0, 0x15, 0x79,
-	0x5a, 0xce, 0x97, 0x3d, 0x1e, 0x32, 0x0d, 0x3c, 0xbc, 0x0a, 0x1b, 0xeb,
-	0xec, 0x21, 0x0f, 0xb4, 0x07, 0xf2, 0xc3, 0xdc, 0x83, 0x39, 0xe6, 0x41,
-	0xac, 0xa3, 0x11, 0x60, 0xa3, 0x83, 0x5a, 0xd2, 0xe7, 0x21, 0xe5, 0xf1,
-	0x90, 0x7d, 0x2f, 0x0f, 0x2d, 0x92, 0xdd, 0x49, 0x3e, 0xa0, 0x83, 0x69,
-	0xea, 0x25, 0xc0, 0x1b, 0x1e, 0xfd, 0xc9, 0xe5, 0x57, 0xeb, 0xfa, 0x74,
-	0x93, 0xa2, 0xdd, 0x48, 0x0c, 0xc0, 0xae, 0x5e, 0xad, 0xcb, 0x32, 0xd7,
-	0x12, 0x7e, 0x57, 0xff, 0x31, 0xfc, 0x55, 0xa7, 0xca, 0x5b, 0x72, 0x63,
-	0xed, 0xad, 0xc9, 0xf9, 0x41, 0xe8, 0xba, 0x55, 0xad, 0x45, 0xb8, 0x0e,
-	0xe8, 0xf0, 0x0f, 0xd1, 0xff, 0xab, 0x5c, 0x73, 0x4a, 0x3e, 0x69, 0xc8,
-	0xa7, 0x50, 0xbc, 0xbd, 0x19, 0x39, 0x37, 0xe6, 0x71, 0x33, 0xd9, 0x2a,
-	0x9f, 0xe9, 0x82, 0x7f, 0xe3, 0xf7, 0x07, 0xb6, 0x8f, 0x3c, 0xfc, 0x2e,
-	0x6c, 0x00, 0xb9, 0x05, 0xd7, 0xf4, 0xc0, 0x0a, 0xe2, 0x6c, 0xbc, 0x77,
-	0x41, 0xd5, 0xf4, 0x1d, 0x85, 0x9f, 0x26, 0xab, 0x5f, 0xc5, 0xc7, 0x9b,
-	0x6f, 0xa8, 0xc6, 0x39, 0x37, 0xf2, 0x84, 0x9c, 0x06, 0xb9, 0xa4, 0x8d,
-	0x71, 0x39, 0x6f, 0x5e, 0x8c, 0x84, 0x81, 0x79, 0xd9, 0xd6, 0x0e, 0x3f,
-	0x13, 0x83, 0xdf, 0xea, 0x87, 0xff, 0xe7, 0x5a, 0xa6, 0xaf, 0x0f, 0x68,
-	0xef, 0xc7, 0x98, 0xf4, 0xc1, 0xfd, 0xe0, 0x99, 0xb9, 0x34, 0x7d, 0x28,
-	0x62, 0xca, 0x62, 0xb4, 0x2d, 0x39, 0xeb, 0xd5, 0x93, 0xbc, 0xdf, 0xbc,
-	0x2f, 0xe1, 0xdd, 0x09, 0xab, 0x9c, 0x47, 0xfe, 0x97, 0xc2, 0xda, 0x4d,
-	0xda, 0xc8, 0xa7, 0x17, 0xad, 0x17, 0x88, 0xd3, 0x74, 0xca, 0x60, 0x99,
-	0x72, 0x62, 0x6d, 0xc3, 0x94, 0xfc, 0xc2, 0xef, 0x42, 0x1e, 0x61, 0xd9,
-	0x6e, 0x67, 0xe1, 0x53, 0x98, 0xb7, 0xb8, 0xe0, 0x8d, 0xbe, 0xa7, 0x1b,
-	0xb1, 0xcc, 0x80, 0x10, 0x90, 0x57, 0x2d, 0x1b, 0xf2, 0x40, 0xa8, 0x0f,
-	0x79, 0xe0, 0xa7, 0xd0, 0x37, 0x24, 0xf9, 0x65, 0xc6, 0x84, 0x90, 0x4c,
-	0x2d, 0x8b, 0x5c, 0x99, 0xa6, 0x5f, 0x51, 0x7f, 0x90, 0xb9, 0x9b, 0x99,
-	0x20, 0x3e, 0x9b, 0xa1, 0x8f, 0xa1, 0xff, 0xd8, 0x01, 0x5d, 0xc4, 0x9f,
-	0xfb, 0x12, 0xe2, 0xd3, 0x64, 0xb1, 0x1b, 0x7e, 0x53, 0x56, 0x74, 0xc8,
-	0x14, 0x71, 0x8d, 0xf5, 0xaa, 0x1b, 0xd4, 0xaa, 0x82, 0x3a, 0x55, 0x58,
-	0x0a, 0xd3, 0xac, 0x51, 0x85, 0x41, 0x0b, 0x73, 0x57, 0x43, 0xe5, 0x42,
-	0x3b, 0x94, 0x7f, 0xe5, 0x77, 0xa8, 0x61, 0xde, 0xf8, 0xe9, 0x3d, 0x3a,
-	0xfd, 0xd8, 0x6e, 0x71, 0x47, 0x8f, 0xb5, 0xee, 0x2f, 0x01, 0x8b, 0x76,
-	0xd2, 0x3e, 0xa9, 0xff, 0xac, 0x4e, 0x7f, 0x3b, 0x55, 0x1a, 0xc0, 0x78,
-	0xc4, 0x95, 0x21, 0xf4, 0x8b, 0xf8, 0xfd, 0x28, 0xd7, 0x7f, 0x25, 0xe3,
-	0xfb, 0xfe, 0x1a, 0x74, 0x79, 0xfe, 0x8e, 0x75, 0xee, 0xdc, 0x67, 0x74,
-	0xb9, 0xef, 0x63, 0x69, 0x3c, 0xcb, 0x78, 0xf8, 0xb6, 0x8f, 0xe1, 0xd8,
-	0xc6, 0xba, 0x1e, 0x72, 0xf5, 0xf3, 0x26, 0xbe, 0x3b, 0x25, 0x7f, 0x3e,
-	0x0c, 0x39, 0x20, 0x2f, 0x5e, 0xf0, 0xc6, 0x62, 0xee, 0x7b, 0x1a, 0x3a,
-	0xd2, 0xcf, 0x84, 0xa5, 0xe9, 0x4c, 0xa7, 0x84, 0xbe, 0xd2, 0x26, 0xcd,
-	0x5f, 0xe9, 0x11, 0xe3, 0x2b, 0xac, 0x3f, 0x58, 0xb1, 0x93, 0xaa, 0xf6,
-	0x91, 0x96, 0x53, 0x88, 0x61, 0x3a, 0xe2, 0xb1, 0xb2, 0x53, 0x73, 0xa7,
-	0x18, 0x48, 0x5e, 0xf5, 0x67, 0x5c, 0xf9, 0xe2, 0xbe, 0x9f, 0xab, 0xda,
-	0x1b, 0x70, 0xb3, 0xe8, 0xcf, 0x67, 0xc4, 0xad, 0xbd, 0x46, 0x3b, 0xcd,
-	0xbc, 0x7a, 0xd7, 0x1d, 0xd0, 0x39, 0x73, 0xcb, 0x5e, 0x55, 0xc7, 0xfd,
-	0xe2, 0x3e, 0xc6, 0x4c, 0x2f, 0xbf, 0x4c, 0x23, 0xbf, 0x9c, 0x94, 0x6e,
-	0xf8, 0x59, 0xf6, 0xdb, 0x29, 0x3a, 0xe6, 0xca, 0x09, 0xf3, 0xf5, 0x3b,
-	0xc5, 0x3d, 0x8c, 0x75, 0x71, 0x56, 0x66, 0xf4, 0x84, 0xa6, 0xc6, 0x34,
-	0x9e, 0xa1, 0xdf, 0xa2, 0x3f, 0xa3, 0x8d, 0xb3, 0x0e, 0x82, 0xb6, 0xe7,
-	0xe9, 0xb3, 0x3c, 0xdb, 0x1e, 0x6a, 0xf0, 0x7d, 0x53, 0xa5, 0x1a, 0x74,
-	0x88, 0xbc, 0xde, 0x6e, 0x02, 0xff, 0x88, 0xeb, 0x36, 0xaf, 0xc9, 0x3f,
-	0x7c, 0x69, 0x24, 0xa2, 0xae, 0x0b, 0x65, 0x0f, 0xf7, 0x7a, 0xe3, 0x33,
-	0x07, 0x81, 0xaf, 0xa9, 0x91, 0x0e, 0xce, 0xdb, 0x25, 0xc6, 0xd9, 0x88,
-	0x84, 0xce, 0xd2, 0xfe, 0xac, 0x58, 0x1a, 0xf2, 0x9b, 0xb2, 0x89, 0xf5,
-	0x0e, 0xc0, 0x17, 0xec, 0x16, 0xfd, 0x7c, 0x2f, 0xd6, 0x8e, 0x15, 0x2d,
-	0x4b, 0x5c, 0x8c, 0x85, 0xb0, 0xbc, 0x09, 0xdf, 0x41, 0x7b, 0x39, 0x87,
-	0x78, 0x75, 0xa2, 0xd6, 0xfa, 0xce, 0x8a, 0xa2, 0x82, 0x6d, 0x43, 0xc0,
-	0x4b, 0x56, 0xaf, 0xab, 0xb7, 0xcb, 0xeb, 0xd0, 0x77, 0x56, 0xb5, 0xed,
-	0xc6, 0xb8, 0xa0, 0xe1, 0x2c, 0xeb, 0x49, 0x1c, 0xf7, 0x1f, 0x60, 0x4c,
-	0x8e, 0xed, 0x66, 0x56, 0x99, 0x9f, 0x4e, 0xd3, 0x76, 0x3b, 0x61, 0x77,
-	0xb8, 0xae, 0x35, 0x4b, 0x76, 0x2c, 0x26, 0xfa, 0xf4, 0x83, 0xd2, 0xbd,
-	0x4f, 0xf7, 0xf8, 0x51, 0x3c, 0xb2, 0x8d, 0x75, 0xca, 0x16, 0xb5, 0x1e,
-	0xf5, 0x65, 0xd8, 0xcc, 0x41, 0xea, 0x18, 0xf1, 0x1f, 0xf1, 0x8d, 0xfe,
-	0xcc, 0x40, 0x7c, 0x4b, 0xd5, 0x3c, 0xbd, 0x97, 0x0f, 0xee, 0x94, 0x53,
-	0x67, 0x69, 0x4f, 0xb8, 0xb7, 0x6e, 0x53, 0xc1, 0x7e, 0x02, 0xef, 0xd9,
-	0x72, 0xfa, 0x59, 0xe6, 0x1f, 0xcc, 0x3b, 0x98, 0x6b, 0x59, 0xd1, 0xfd,
-	0xe0, 0x47, 0xbf, 0x8f, 0xfe, 0x40, 0x57, 0xb6, 0x9b, 0x83, 0xaf, 0x2e,
-	0xd4, 0xa8, 0xb7, 0x7e, 0xee, 0xb9, 0x98, 0xcc, 0xd9, 0xdc, 0xa8, 0x27,
-	0xef, 0x02, 0xda, 0x26, 0x11, 0x07, 0x52, 0xd5, 0x26, 0x59, 0x1b, 0x73,
-	0xa1, 0xfb, 0x8f, 0x82, 0xae, 0xc3, 0xad, 0xc4, 0xab, 0x6b, 0x63, 0x69,
-	0x5c, 0x1f, 0x56, 0x79, 0x9a, 0x71, 0x9f, 0x8b, 0x31, 0x76, 0x72, 0x1d,
-	0xf9, 0x7a, 0x72, 0xf4, 0xc2, 0xcc, 0x7d, 0xfa, 0x24, 0x7c, 0xf7, 0xb0,
-	0xc3, 0x18, 0xcf, 0xfa, 0x73, 0x0b, 0xe8, 0x68, 0x57, 0xd8, 0x42, 0xb7,
-	0xf7, 0xe9, 0x85, 0x32, 0xfd, 0x7d, 0x3e, 0xda, 0x2c, 0x0e, 0x7d, 0x96,
-	0xbe, 0x60, 0x53, 0x27, 0x9a, 0x5c, 0x54, 0xb5, 0x6a, 0x44, 0xa0, 0x6a,
-	0x0a, 0x73, 0x39, 0x7a, 0xa5, 0xbc, 0x4f, 0xcf, 0xc3, 0x55, 0xaf, 0x45,
-	0x48, 0x77, 0x4c, 0xe5, 0xf2, 0xfb, 0x94, 0xad, 0x15, 0x11, 0x53, 0x60,
-	0x33, 0xce, 0x1d, 0x98, 0x57, 0xb5, 0xc1, 0xa6, 0xa8, 0x7b, 0xea, 0x5d,
-	0xf9, 0x48, 0x5f, 0xf7, 0x37, 0x8a, 0xa1, 0x45, 0xf8, 0x5f, 0x62, 0xe9,
-	0x16, 0xbf, 0x3e, 0xf5, 0xcf, 0xfd, 0x9c, 0xe8, 0x71, 0x61, 0x9e, 0x32,
-	0x55, 0x22, 0x2d, 0x45, 0xf8, 0xc3, 0x1b, 0xd9, 0x12, 0xe5, 0xe8, 0xf9,
-	0x94, 0x63, 0xb0, 0x0b, 0x7d, 0xd9, 0xf4, 0x6d, 0x40, 0xe1, 0x67, 0xdc,
-	0x63, 0x0c, 0xc0, 0x77, 0xad, 0x09, 0xeb, 0x7d, 0x04, 0x32, 0xa2, 0x6e,
-	0xa0, 0xbf, 0x65, 0xee, 0xd5, 0x41, 0x7f, 0xcb, 0x97, 0x7e, 0xe1, 0x76,
-	0xd2, 0xe7, 0x0d, 0xc8, 0x29, 0xf8, 0xd1, 0x93, 0xf3, 0xa4, 0x27, 0xad,
-	0xd6, 0xce, 0x14, 0xe4, 0x7d, 0x42, 0xf9, 0xf8, 0x7e, 0x79, 0x73, 0xf1,
-	0x5b, 0x0a, 0x0b, 0xee, 0xd9, 0xb7, 0x22, 0x13, 0xf0, 0x0f, 0x47, 0xaa,
-	0x90, 0xb7, 0x19, 0xc3, 0xfa, 0xdc, 0xa5, 0xfc, 0xe3, 0x17, 0x3f, 0x78,
-	0xae, 0x12, 0xd2, 0x13, 0x0f, 0x7c, 0xc8, 0x18, 0xbe, 0x55, 0xdc, 0xce,
-	0x0f, 0x3c, 0x8f, 0xa1, 0x27, 0xfe, 0x10, 0x3a, 0xfb, 0x4d, 0xcc, 0x15,
-	0x06, 0x9d, 0x6a, 0x3f, 0xe4, 0x83, 0x3c, 0xa7, 0xeb, 0x89, 0x4f, 0x7e,
-	0x48, 0xfa, 0x4c, 0x59, 0x04, 0x7e, 0xc8, 0xab, 0xb8, 0xca, 0xdc, 0xb1,
-	0xc9, 0xd7, 0xe7, 0x0b, 0xc0, 0xd5, 0xc0, 0xd2, 0xc5, 0xc0, 0x17, 0xb7,
-	0x48, 0xbe, 0x33, 0xc8, 0x47, 0xe1, 0xc3, 0xd7, 0xdb, 0x83, 0x1c, 0x97,
-	0xcf, 0x67, 0x33, 0xc8, 0xa9, 0x61, 0x13, 0xb7, 0x61, 0x8d, 0xb2, 0x4d,
-	0xe5, 0xb0, 0x37, 0xa1, 0xdf, 0xa3, 0x3d, 0x57, 0x6c, 0xcc, 0x2d, 0x0e,
-	0xa8, 0xdc, 0x62, 0x68, 0x43, 0x6e, 0x11, 0xd4, 0xb4, 0x02, 0xba, 0x39,
-	0x2e, 0x70, 0x03, 0xec, 0xe0, 0xbb, 0x18, 0xff, 0x3b, 0xd0, 0xf7, 0xb7,
-	0x4b, 0xc0, 0x0d, 0x25, 0xe0, 0x86, 0x12, 0x70, 0x43, 0x09, 0xb8, 0xa1,
-	0x14, 0xf5, 0xeb, 0x5b, 0x2e, 0x71, 0xff, 0x07, 0xb4, 0xe9, 0xa0, 0xee,
-	0xb1, 0xd9, 0x5e, 0xbd, 0x3a, 0x59, 0xaa, 0x16, 0xe0, 0xe7, 0x30, 0xeb,
-	0x76, 0xc0, 0x71, 0x41, 0x4d, 0xc4, 0x8f, 0x1d, 0x8b, 0xdc, 0x43, 0x41,
-	0xec, 0x58, 0x74, 0xb1, 0x9e, 0xfa, 0xa2, 0x06, 0x70, 0xa3, 0x21, 0x51,
-	0xfc, 0x36, 0xe1, 0x93, 0xb9, 0x67, 0xde, 0x8d, 0x15, 0xd6, 0xac, 0x6a,
-	0x4f, 0x27, 0x54, 0x4d, 0xc2, 0x96, 0xc9, 0x72, 0x90, 0xdb, 0xc5, 0x65,
-	0x68, 0x86, 0x58, 0x54, 0xb6, 0xeb, 0x09, 0xe8, 0xa2, 0x4a, 0xfc, 0xc8,
-	0x3d, 0x27, 0xce, 0x1f, 0xef, 0xad, 0x60, 0xce, 0x82, 0xed, 0xd1, 0x77,
-	0xa2, 0xaa, 0xce, 0x05, 0xf8, 0xcf, 0x05, 0x67, 0x01, 0xe2, 0xb2, 0x7f,
-	0x86, 0x7b, 0xef, 0x31, 0x19, 0x2d, 0x3a, 0xc8, 0x65, 0x55, 0x8e, 0x84,
-	0x78, 0xe0, 0xc9, 0x7d, 0xc8, 0x97, 0x7b, 0x0e, 0xd8, 0x61, 0xdc, 0x0e,
-	0xe4, 0x4e, 0x79, 0x8f, 0x68, 0xc3, 0x90, 0xf5, 0x7e, 0x5f, 0xd6, 0xe9,
-	0x25, 0x31, 0x91, 0xff, 0xc4, 0x8c, 0x7d, 0x63, 0xda, 0x68, 0x4d, 0x61,
-	0x16, 0xfa, 0x23, 0x8c, 0xe5, 0x78, 0x6b, 0x1d, 0xf6, 0x92, 0xab, 0x6e,
-	0xde, 0x8f, 0x6f, 0xc4, 0x2f, 0x9f, 0xd5, 0xc4, 0x0e, 0xe4, 0xd8, 0xd8,
-	0x3e, 0xd1, 0xd0, 0xbe, 0x7e, 0xdf, 0xe7, 0x01, 0xbe, 0x72, 0xbd, 0x3e,
-	0x41, 0xbf, 0x76, 0xbd, 0x1d, 0x78, 0x4f, 0x42, 0xea, 0x3e, 0x7c, 0xfe,
-	0x62, 0x44, 0x52, 0x8b, 0xb6, 0xa4, 0xcb, 0xec, 0xc7, 0x9a, 0x07, 0xfd,
-	0xd7, 0x1f, 0x4b, 0x0a, 0x79, 0x6e, 0x36, 0x62, 0x39, 0xae, 0xfc, 0x47,
-	0x59, 0x9d, 0xcb, 0xc7, 0xb8, 0x77, 0x9d, 0x1f, 0xd5, 0xf0, 0xdc, 0x8f,
-	0x71, 0x4d, 0xda, 0x6d, 0xac, 0x0f, 0xc6, 0xa9, 0xbe, 0xe8, 0x22, 0xee,
-	0x65, 0xc7, 0x58, 0xe7, 0x79, 0x2a, 0x2c, 0x6d, 0x56, 0xac, 0x0c, 0x3b,
-	0xb8, 0x54, 0xe4, 0x7c, 0xc0, 0x52, 0x45, 0xd6, 0x82, 0x82, 0xfb, 0x7f,
-	0x0c, 0xec, 0xa8, 0x13, 0x3b, 0x79, 0x7d, 0x94, 0xbe, 0x5c, 0x33, 0x84,
-	0x35, 0xb0, 0xe2, 0xfb, 0xe7, 0x85, 0xa2, 0x57, 0x7b, 0x39, 0x47, 0x3a,
-	0xaa, 0x7f, 0x53, 0x5f, 0x89, 0x20, 0x67, 0x5a, 0xe7, 0xf1, 0x1c, 0xc7,
-	0x37, 0xe1, 0x9e, 0xe5, 0x64, 0x35, 0x90, 0x05, 0xef, 0xb3, 0x8d, 0xfb,
-	0xf3, 0xf5, 0xfa, 0x39, 0xfb, 0xc3, 0xd6, 0xd9, 0x9e, 0xbb, 0x27, 0x69,
-	0xcb, 0x81, 0x85, 0xaa, 0x1c, 0xf0, 0xea, 0x6c, 0xd1, 0xbd, 0x5e, 0x9d,
-	0x2d, 0xb6, 0x77, 0x63, 0x9d, 0xad, 0x7c, 0x8f, 0x57, 0x67, 0x33, 0x0f,
-	0xc0, 0x07, 0x1f, 0xf0, 0xea, 0x6c, 0xff, 0xf5, 0x1e, 0xaf, 0xce, 0xd6,
-	0x75, 0xaf, 0x57, 0x67, 0xeb, 0xdd, 0xeb, 0xd5, 0xd9, 0x46, 0xef, 0xdd,
-	0x58, 0x67, 0x73, 0xf6, 0x6e, 0xac, 0xb3, 0x39, 0x07, 0x72, 0xf8, 0x5c,
-	0xaf, 0xb3, 0x65, 0xf6, 0xde, 0xbc, 0xce, 0xf6, 0x4a, 0x80, 0xf1, 0xc1,
-	0xcf, 0x00, 0x78, 0x70, 0x80, 0xf1, 0xfb, 0x81, 0xf1, 0x6f, 0x56, 0xe3,
-	0x55, 0xe7, 0x37, 0xc0, 0xa7, 0xe6, 0xc7, 0x8f, 0x0f, 0x83, 0xf5, 0xb7,
-	0xfa, 0xcf, 0xba, 0xc8, 0x8f, 0x63, 0x7e, 0x6e, 0x43, 0xbc, 0xbf, 0xcd,
-	0xcf, 0xf1, 0xba, 0x5a, 0xaf, 0x9f, 0xad, 0x68, 0xfc, 0xbe, 0x0d, 0xa9,
-	0x7a, 0x50, 0x03, 0x20, 0x5f, 0x72, 0xe0, 0x61, 0x25, 0x87, 0x3b, 0xd1,
-	0xdf, 0x3c, 0xf0, 0x25, 0x9b, 0x75, 0x81, 0x27, 0xb1, 0x86, 0xdd, 0xed,
-	0x86, 0xda, 0x67, 0x66, 0x4c, 0x3b, 0x2d, 0x29, 0xf4, 0x4f, 0xa9, 0xfe,
-	0xa3, 0x0d, 0xfd, 0xb3, 0xe8, 0xcf, 0x71, 0xad, 0x7f, 0x8b, 0xcf, 0x73,
-	0xca, 0xbe, 0x6d, 0x0f, 0xf7, 0xa7, 0x4b, 0x01, 0x4e, 0x0b, 0xf9, 0x18,
-	0xdc, 0xcd, 0xb8, 0xd5, 0x7b, 0xf1, 0x8c, 0xf5, 0xa2, 0x2b, 0x57, 0x15,
-	0xde, 0x37, 0x12, 0xd6, 0x8b, 0x59, 0x95, 0xdf, 0xb9, 0x99, 0x5c, 0x75,
-	0x3d, 0x5f, 0x07, 0x0e, 0x63, 0xce, 0x03, 0x7b, 0x5f, 0xee, 0x45, 0xdc,
-	0x6b, 0xcc, 0xc9, 0x99, 0x87, 0xeb, 0x7e, 0x1e, 0x6e, 0xca, 0xfd, 0xfb,
-	0x1a, 0x31, 0xbe, 0x73, 0xe0, 0xef, 0x2b, 0x8c, 0xbf, 0x05, 0xb9, 0x3c,
-	0x31, 0x3c, 0x71, 0x0f, 0x31, 0x07, 0x71, 0x3e, 0xeb, 0x0b, 0xcc, 0x7f,
-	0x18, 0x4b, 0x99, 0x0f, 0x45, 0xf0, 0xe1, 0xb9, 0x97, 0x00, 0xeb, 0x37,
-	0xfb, 0xfe, 0x9f, 0x79, 0x54, 0x80, 0x6d, 0xac, 0x2d, 0x5e, 0x2e, 0xb5,
-	0x45, 0xf3, 0xf2, 0xd5, 0x98, 0xdf, 0x27, 0xb4, 0x8e, 0xa5, 0x43, 0xeb,
-	0x58, 0x7a, 0xc3, 0x5e, 0x89, 0xa8, 0x33, 0x36, 0x6a, 0xcf, 0x85, 0x7b,
-	0x30, 0x6e, 0xe6, 0x52, 0x0f, 0xf1, 0x30, 0xf7, 0x62, 0x80, 0x8d, 0xec,
-	0xc6, 0x58, 0xc5, 0x38, 0x45, 0x3c, 0x15, 0xec, 0xb7, 0x06, 0x7a, 0xa2,
-	0xec, 0xd8, 0xf6, 0x47, 0x1a, 0x72, 0x64, 0xa7, 0xd9, 0xde, 0x0f, 0x5a,
-	0x32, 0xf8, 0x0e, 0x64, 0xfa, 0x80, 0x8a, 0x91, 0x2d, 0xb0, 0xdd, 0x13,
-	0x25, 0x62, 0xde, 0x6d, 0xb2, 0xe8, 0xe3, 0xde, 0xf3, 0x33, 0x1e, 0xe6,
-	0x0d, 0x6d, 0xc4, 0xbc, 0xce, 0xaa, 0x78, 0x34, 0xee, 0xbf, 0x21, 0x8d,
-	0xc4, 0xb7, 0xa4, 0x8f, 0x31, 0x89, 0xfe, 0xd1, 0xcd, 0x5c, 0xee, 0x61,
-	0x3c, 0x62, 0x2c, 0x8a, 0xc9, 0xea, 0x4d, 0xe9, 0x53, 0x6d, 0xc7, 0x5a,
-	0xec, 0x30, 0x3e, 0x13, 0xf0, 0x1f, 0xa3, 0x78, 0x26, 0x23, 0x93, 0xb3,
-	0x5f, 0x00, 0x6f, 0x13, 0x72, 0x69, 0x66, 0x0c, 0xf4, 0x3d, 0x29, 0x53,
-	0x4e, 0x1e, 0x7e, 0x84, 0x7b, 0x21, 0xc4, 0x79, 0xdd, 0xfe, 0xf7, 0x84,
-	0x7e, 0xce, 0xb6, 0x88, 0x33, 0xa5, 0x52, 0xa4, 0x0f, 0xe6, 0xbe, 0x14,
-	0xf7, 0x1f, 0x69, 0x3f, 0xac, 0xc3, 0x20, 0xd7, 0x65, 0xce, 0x3b, 0xcd,
-	0xf9, 0x37, 0xea, 0x64, 0xb5, 0x4a, 0xbc, 0xe6, 0x66, 0x56, 0x96, 0x89,
-	0x37, 0x3f, 0x28, 0xf6, 0xa4, 0x1e, 0x88, 0x3f, 0x6f, 0x05, 0x77, 0x5a,
-	0x33, 0xc0, 0x9c, 0x2f, 0xac, 0xe8, 0x8d, 0xb8, 0xd3, 0xc3, 0x9c, 0xc9,
-	0xe5, 0x2c, 0xc6, 0x74, 0x14, 0xb6, 0x46, 0xde, 0x07, 0xb7, 0xd7, 0x8d,
-	0x67, 0xbb, 0x91, 0xc3, 0x7b, 0x18, 0x33, 0x05, 0x8c, 0xf9, 0x0f, 0x81,
-	0x31, 0x27, 0xe5, 0xad, 0x56, 0x62, 0x4c, 0xd7, 0xc7, 0x98, 0x69, 0xd8,
-	0x73, 0x6e, 0x83, 0x3d, 0x6b, 0xaa, 0x76, 0xc5, 0x7b, 0x39, 0x60, 0xc4,
-	0xd4, 0xb4, 0x75, 0x0b, 0xb8, 0x52, 0x93, 0x88, 0x3a, 0xfb, 0x10, 0x6a,
-	0x18, 0x33, 0xc0, 0x8f, 0x7b, 0x14, 0x2e, 0x3c, 0x50, 0xda, 0x82, 0x1c,
-	0x46, 0xe1, 0x44, 0x7f, 0x4f, 0x2e, 0xb4, 0x69, 0x9f, 0x32, 0xd4, 0xb0,
-	0x4f, 0x79, 0x1d, 0x4f, 0xe2, 0x39, 0xbf, 0x3e, 0xd8, 0x04, 0x5f, 0xf0,
-	0x7f, 0x40, 0x13, 0xd7, 0x17, 0xd7, 0x82, 0xe6, 0xad, 0x97, 0xd1, 0x46,
-	0x5c, 0xf9, 0xbf, 0x36, 0xe1, 0x4a, 0xc4, 0xae, 0xf3, 0x11, 0x49, 0x02,
-	0x53, 0xba, 0xcb, 0x1c, 0x8b, 0x6b, 0xba, 0x5f, 0x9a, 0xc1, 0x5f, 0xcb,
-	0x74, 0x27, 0xb0, 0x54, 0x9b, 0x84, 0x81, 0xa9, 0x9a, 0x14, 0xa6, 0xea,
-	0x21, 0xf6, 0xe9, 0x3d, 0x02, 0x2c, 0xb4, 0xb8, 0x8e, 0xab, 0x2c, 0xe7,
-	0x87, 0xd0, 0xcb, 0xa3, 0xca, 0xf7, 0xa4, 0xe5, 0x29, 0xf8, 0xd2, 0xe6,
-	0x65, 0xe0, 0xc1, 0xf3, 0x1e, 0xde, 0x6a, 0xda, 0x84, 0xb7, 0x8e, 0xde,
-	0x10, 0x6f, 0xa9, 0x9a, 0xff, 0x20, 0x65, 0xf2, 0x7a, 0xd5, 0xab, 0xf9,
-	0x5f, 0xa9, 0x7a, 0x35, 0xff, 0xd7, 0xab, 0x8d, 0x35, 0xff, 0x8f, 0x48,
-	0xc1, 0xb4, 0xdc, 0x35, 0xd9, 0x54, 0xf3, 0x1f, 0x65, 0x0d, 0xfd, 0xf7,
-	0xda, 0xbc, 0xda, 0x7e, 0x9b, 0x5f, 0xf3, 0xb7, 0xa4, 0xb0, 0xa1, 0xdd,
-	0x94, 0xb7, 0xec, 0xa0, 0xe6, 0xff, 0x34, 0xda, 0xda, 0x31, 0xc7, 0xc6,
-	0x7a, 0xff, 0x95, 0x2a, 0xeb, 0xfd, 0x11, 0xf6, 0xf3, 0xeb, 0xfd, 0xec,
-	0x87, 0xdc, 0xbf, 0xca, 0x5a, 0xff, 0x6e, 0xc8, 0x62, 0x27, 0xe4, 0xd0,
-	0x29, 0xcd, 0x67, 0xa3, 0xec, 0xa3, 0x6a, 0xfc, 0x6b, 0xc8, 0x37, 0xae,
-	0x54, 0xbd, 0x5a, 0xfc, 0x11, 0xd8, 0xd5, 0xd1, 0xf5, 0x1a, 0xbf, 0x37,
-	0xc7, 0xd5, 0xea, 0xc6, 0xf1, 0x37, 0x8e, 0xd3, 0xe5, 0x8f, 0x13, 0xc1,
-	0x38, 0xd1, 0x4d, 0xe3, 0x5c, 0xaf, 0xe9, 0x5f, 0xad, 0x7a, 0xf5, 0xfc,
-	0xf4, 0xac, 0xb8, 0xcd, 0xf0, 0xcd, 0x2f, 0xf6, 0xec, 0xf2, 0xc7, 0x58,
-	0xaf, 0xe7, 0xd3, 0x87, 0x00, 0xe7, 0xc7, 0xd5, 0xf9, 0x9e, 0x23, 0xff,
-	0x1f, 0xea, 0xf9, 0xac, 0xe5, 0x7b, 0x7b, 0x32, 0x5c, 0x9f, 0xc0, 0xf3,
-	0xcf, 0x7a, 0x75, 0xfc, 0xa1, 0x52, 0x50, 0x9f, 0x67, 0x5e, 0x19, 0x9c,
-	0xbd, 0xe9, 0x8e, 0x9d, 0x10, 0xda, 0x0a, 0xe9, 0xe3, 0xb8, 0xed, 0x32,
-	0xae, 0xf0, 0x14, 0x6c, 0x2a, 0x7e, 0x73, 0x4c, 0xbd, 0x30, 0x1d, 0x60,
-	0xea, 0x88, 0xc2, 0xd4, 0x0b, 0xcb, 0x01, 0xa6, 0x4e, 0xde, 0x04, 0x53,
-	0xff, 0xf7, 0x36, 0x2f, 0x0e, 0x84, 0x25, 0xaf, 0x30, 0xf5, 0xcd, 0xce,
-	0x2b, 0xf1, 0x5e, 0x1b, 0xf1, 0x82, 0x78, 0x7b, 0xd8, 0x9d, 0x37, 0x59,
-	0x6b, 0x01, 0xce, 0x66, 0xec, 0xdf, 0x29, 0xa3, 0x67, 0xaf, 0xe3, 0x6c,
-	0x0f, 0x4b, 0x5b, 0xb1, 0x63, 0x2a, 0x26, 0x02, 0xd7, 0xd5, 0x58, 0x2f,
-	0x27, 0x56, 0x66, 0xcc, 0x09, 0x29, 0x3c, 0x97, 0x2b, 0x32, 0x0f, 0x60,
-	0x1b, 0xb1, 0x73, 0x2b, 0x8f, 0xf2, 0xf8, 0x31, 0x29, 0xc0, 0xa6, 0xc1,
-	0xd9, 0x09, 0xee, 0x4b, 0xbc, 0x65, 0x24, 0x6d, 0xb4, 0x57, 0x83, 0x5c,
-	0xc1, 0x51, 0x67, 0x4e, 0x92, 0xc0, 0x3f, 0xe3, 0xeb, 0xd8, 0x93, 0xbe,
-	0xe2, 0x47, 0xbf, 0x70, 0x4d, 0xfa, 0xb5, 0x00, 0x5b, 0x22, 0x27, 0x2a,
-	0x71, 0x6d, 0x07, 0xd8, 0xd2, 0xc3, 0x95, 0xa9, 0xea, 0x0a, 0xf0, 0x75,
-	0x48, 0x86, 0x80, 0xeb, 0x57, 0x1e, 0x66, 0xcd, 0x2a, 0xc0, 0x4e, 0x2e,
-	0xbe, 0x1b, 0x6b, 0x58, 0xbc, 0x6e, 0x56, 0x7b, 0x87, 0x17, 0x7b, 0xc2,
-	0x0d, 0xed, 0xbf, 0x05, 0xff, 0x8d, 0xfc, 0x08, 0x98, 0xc5, 0xc3, 0x4c,
-	0x7b, 0xa1, 0x83, 0x01, 0x85, 0x99, 0xa6, 0xde, 0x83, 0x99, 0x36, 0xc7,
-	0x28, 0xc6, 0xcc, 0xeb, 0x31, 0x2a, 0x5d, 0xa3, 0x3f, 0xbf, 0x1e, 0xa3,
-	0x6e, 0x1e, 0x43, 0xd9, 0x06, 0xee, 0xec, 0x0c, 0x3e, 0x13, 0x52, 0xd8,
-	0x14, 0xa3, 0xa6, 0x3e, 0x44, 0x8c, 0x1a, 0x56, 0x31, 0xca, 0xa3, 0xfb,
-	0xfb, 0x90, 0xcd, 0x77, 0x21, 0xd3, 0xef, 0x00, 0x8b, 0x7d, 0x1b, 0x7c,
-	0x7d, 0x0b, 0x38, 0xe9, 0x9b, 0xa5, 0xcd, 0x67, 0x0e, 0x06, 0x85, 0xf9,
-	0xa1, 0x87, 0xa5, 0xbc, 0x1a, 0xc0, 0x11, 0xac, 0xae, 0xc5, 0xa2, 0x9b,
-	0x19, 0x2f, 0xf6, 0x99, 0x13, 0xde, 0xde, 0x6b, 0x2c, 0x2b, 0x8f, 0xb5,
-	0xa6, 0xe6, 0x19, 0x33, 0xd4, 0x75, 0x94, 0xf5, 0x4e, 0x62, 0x87, 0x8a,
-	0xca, 0x33, 0x7b, 0xa4, 0xbc, 0xe8, 0xe1, 0xb0, 0xa9, 0x79, 0x6f, 0x8c,
-	0x71, 0x1f, 0x87, 0xe5, 0x7c, 0x1c, 0x96, 0x5d, 0x5c, 0x8d, 0x85, 0xd0,
-	0x7f, 0xca, 0xd9, 0x88, 0xbd, 0x8e, 0xf8, 0xd8, 0x6b, 0xe2, 0x43, 0x61,
-	0x2f, 0x6f, 0xae, 0x1c, 0x9e, 0x19, 0x9e, 0x89, 0xc9, 0x7e, 0xc8, 0x79,
-	0xa8, 0x48, 0x7d, 0xf1, 0x9c, 0xd2, 0x2f, 0xd3, 0x19, 0xf5, 0xe5, 0xe9,
-	0x2a, 0x14, 0x3f, 0xa8, 0x0d, 0x43, 0x57, 0x43, 0xbf, 0x54, 0x57, 0x62,
-	0xbe, 0x39, 0x10, 0xc6, 0xe7, 0x6f, 0x4b, 0x57, 0xe4, 0x83, 0xfa, 0xda,
-	0x8c, 0xc5, 0x6e, 0x05, 0x93, 0x6d, 0xc4, 0x63, 0xae, 0xc2, 0x63, 0xcd,
-	0x7e, 0x9f, 0xfc, 0x81, 0x61, 0xe8, 0xf2, 0x3f, 0xa0, 0xcf, 0x8f, 0xed,
-	0x76, 0xf9, 0x11, 0xfc, 0xf7, 0xbf, 0x87, 0x4e, 0xfe, 0x1d, 0x72, 0x85,
-	0x57, 0xec, 0x2e, 0xf9, 0x21, 0xda, 0xae, 0xe3, 0x1c, 0xf6, 0x9f, 0x72,
-	0x92, 0xf6, 0x28, 0xf0, 0xc9, 0xa8, 0x8f, 0x4f, 0xde, 0x7a, 0x20, 0x69,
-	0x8f, 0xb1, 0xce, 0x0e, 0x39, 0xff, 0x34, 0x39, 0xae, 0xb0, 0x49, 0x80,
-	0x49, 0x1e, 0x4f, 0x73, 0xfe, 0xc9, 0x6a, 0x16, 0xd8, 0x27, 0xeb, 0x63,
-	0x9f, 0x9f, 0xa6, 0x3d, 0xec, 0x33, 0xf5, 0xf7, 0xa8, 0x7f, 0x0f, 0xf7,
-	0x1c, 0x76, 0x93, 0x98, 0x07, 0xb8, 0x07, 0xd7, 0x87, 0x25, 0x5f, 0x1b,
-	0x51, 0x9f, 0x13, 0x25, 0xd7, 0x6a, 0x82, 0x9c, 0x58, 0xab, 0x3d, 0xc3,
-	0x55, 0x59, 0xb5, 0xcc, 0x22, 0xbe, 0xb3, 0x55, 0x2b, 0xfa, 0x7b, 0xfe,
-	0xf5, 0xd3, 0xfe, 0xf5, 0x53, 0xfe, 0xf5, 0x69, 0xc4, 0xe1, 0x53, 0x2a,
-	0x96, 0xb2, 0x9d, 0x6d, 0x50, 0x72, 0x15, 0x63, 0x01, 0x7b, 0x9c, 0xeb,
-	0xff, 0xf3, 0x7a, 0x59, 0xe9, 0x98, 0xe3, 0x8f, 0xe2, 0x73, 0x1a, 0x9f,
-	0x09, 0x7c, 0x0e, 0xe1, 0x93, 0xc7, 0x67, 0x5d, 0xa6, 0x5a, 0xaa, 0x34,
-	0x06, 0x1b, 0xe9, 0x95, 0x54, 0xed, 0x39, 0xe8, 0xf1, 0x49, 0xe8, 0xf6,
-	0xb8, 0x14, 0x2a, 0x7f, 0x22, 0x93, 0x33, 0x9a, 0xb4, 0xd9, 0xd0, 0x69,
-	0x05, 0xb6, 0x3c, 0xe3, 0xed, 0x41, 0xb6, 0x26, 0x46, 0xd0, 0xb7, 0x2e,
-	0x8f, 0x3a, 0x4f, 0x8a, 0x7e, 0xdf, 0x14, 0xfa, 0x89, 0x5e, 0xe8, 0xbf,
-	0x5b, 0xed, 0xbf, 0x55, 0x1c, 0x4f, 0xc6, 0xfb, 0x6d, 0xd7, 0x82, 0xce,
-	0x7b, 0x4f, 0x61, 0xec, 0xa4, 0x3a, 0x7f, 0x99, 0x91, 0x93, 0xb3, 0xab,
-	0xdb, 0x3d, 0xdf, 0x6a, 0x99, 0x57, 0xa9, 0x77, 0xf0, 0xe1, 0xc2, 0x17,
-	0x66, 0x60, 0xef, 0x47, 0xab, 0x21, 0x6d, 0x08, 0xf1, 0x66, 0xa8, 0x7a,
-	0x55, 0xc5, 0x9b, 0x54, 0xd5, 0xcd, 0xc4, 0xcf, 0x44, 0x70, 0xcd, 0x73,
-	0x31, 0x88, 0x8b, 0xea, 0xfc, 0xde, 0x2a, 0xf0, 0x8d, 0xa6, 0xea, 0x86,
-	0x93, 0xeb, 0xfb, 0x4a, 0xea, 0x7c, 0x71, 0x26, 0x1e, 0xd7, 0x25, 0x37,
-	0x40, 0x9c, 0x3b, 0xa2, 0x62, 0x13, 0xd6, 0xea, 0xed, 0xcc, 0x15, 0x5f,
-	0xe7, 0xbb, 0x00, 0xf6, 0x27, 0xd0, 0xaf, 0x0b, 0xfe, 0x18, 0xf7, 0x6a,
-	0xb4, 0x4f, 0xf2, 0xca, 0x67, 0x26, 0xa4, 0x52, 0x1e, 0x04, 0xbf, 0x7e,
-	0x8e, 0xa4, 0x72, 0x89, 0x18, 0xec, 0x31, 0xd8, 0xc3, 0xf2, 0xea, 0x2a,
-	0x95, 0x6a, 0x80, 0x29, 0xda, 0xd1, 0x87, 0x79, 0x05, 0x64, 0xe4, 0xed,
-	0xbf, 0xa9, 0xbd, 0xb7, 0x42, 0x75, 0x10, 0x72, 0x4a, 0xa2, 0x9d, 0xb5,
-	0x6d, 0xfc, 0x2e, 0xeb, 0xaa, 0x26, 0xb0, 0x66, 0x1c, 0x91, 0xc5, 0x72,
-	0x1d, 0xf4, 0x22, 0xe6, 0x6e, 0x3f, 0x22, 0x0b, 0xe5, 0x09, 0x79, 0xa1,
-	0xfc, 0xcd, 0x76, 0x60, 0x2a, 0xc8, 0x94, 0xf4, 0xb7, 0xcb, 0xf5, 0x33,
-	0x9e, 0x41, 0x3b, 0xe4, 0x39, 0x9b, 0x8f, 0x7a, 0x79, 0x6e, 0x5e, 0xd5,
-	0x68, 0xbc, 0x6f, 0x57, 0x1f, 0xb7, 0xad, 0xe8, 0x24, 0x7a, 0x1e, 0x9d,
-	0x53, 0xb6, 0x39, 0x3c, 0x65, 0xef, 0x95, 0xcb, 0xce, 0x36, 0x59, 0x75,
-	0x54, 0x5e, 0x4c, 0xfc, 0x80, 0xb5, 0x6e, 0x99, 0x2b, 0xf2, 0xa0, 0x9c,
-	0xc4, 0xba, 0xbd, 0xec, 0x3c, 0x06, 0x3b, 0x7d, 0x02, 0xb6, 0xc0, 0x1a,
-	0xc0, 0x31, 0xe6, 0x5a, 0xb2, 0xa2, 0x6a, 0x68, 0xf5, 0xfa, 0xb0, 0x3a,
-	0x27, 0xdc, 0x2c, 0xab, 0x0a, 0x8b, 0x79, 0xb5, 0xf6, 0xd5, 0x31, 0x6f,
-	0x8d, 0x18, 0xca, 0xee, 0xbf, 0x01, 0x7a, 0x8a, 0xb0, 0xdd, 0x26, 0xd5,
-	0xc7, 0x48, 0xb4, 0xf8, 0x7d, 0x14, 0x06, 0x6d, 0xe8, 0x63, 0x27, 0x92,
-	0xf6, 0x6b, 0xfb, 0x92, 0xf6, 0xc4, 0x81, 0x5c, 0xd5, 0xf3, 0x99, 0xae,
-	0xb6, 0xb6, 0x5e, 0xff, 0xc9, 0x60, 0x5d, 0xbd, 0xbc, 0x8e, 0xa1, 0x61,
-	0xa4, 0xcf, 0x5f, 0x82, 0x7e, 0x43, 0xd2, 0x7c, 0xa6, 0xfe, 0x89, 0x71,
-	0xa7, 0x2f, 0x76, 0x54, 0x78, 0x32, 0x8b, 0x79, 0xb5, 0xe5, 0x64, 0xe5,
-	0x12, 0xe2, 0xe4, 0x35, 0x62, 0x87, 0xde, 0x8b, 0x72, 0xed, 0x13, 0x49,
-	0x67, 0x50, 0x5b, 0x18, 0x43, 0xd6, 0xf2, 0xfc, 0x18, 0xe3, 0xec, 0x31,
-	0x11, 0xe0, 0xcb, 0x33, 0x03, 0x92, 0x2e, 0xaa, 0x77, 0x21, 0x78, 0x96,
-	0x53, 0x9b, 0x80, 0xfc, 0xf0, 0xfc, 0x28, 0x03, 0xa3, 0x6e, 0x77, 0xc7,
-	0xd2, 0xf2, 0x18, 0x6b, 0x63, 0x92, 0x9b, 0x93, 0x3d, 0x49, 0xf8, 0x55,
-	0x77, 0xb4, 0x59, 0x26, 0x16, 0xdd, 0x4c, 0xf7, 0xf4, 0x13, 0x18, 0x63,
-	0x1c, 0x63, 0x8d, 0x20, 0x37, 0xc9, 0x22, 0x56, 0x53, 0xbe, 0xf4, 0xdd,
-	0x8f, 0x43, 0x46, 0x1f, 0xe1, 0x59, 0xd7, 0xc1, 0xac, 0x58, 0xa3, 0x79,
-	0x35, 0xee, 0xbb, 0x5a, 0xae, 0xff, 0x57, 0x10, 0xeb, 0x42, 0xb2, 0x3f,
-	0x2e, 0xfa, 0x48, 0x3c, 0xf4, 0x8b, 0x71, 0x9b, 0x6d, 0x61, 0xb6, 0xe9,
-	0x68, 0x0b, 0xfd, 0x66, 0x3c, 0xac, 0x27, 0xe3, 0xd6, 0x20, 0xcf, 0xe0,
-	0x1a, 0xf6, 0xb8, 0x18, 0xcf, 0xd7, 0x21, 0x8b, 0x11, 0xe9, 0xb8, 0x60,
-	0x0d, 0xbe, 0x0e, 0x5a, 0x42, 0xca, 0xd7, 0x8f, 0x8b, 0xee, 0xb7, 0xb7,
-	0xaf, 0xb7, 0x87, 0xfc, 0xf6, 0x11, 0x69, 0xbb, 0xd0, 0x67, 0xbe, 0x21,
-	0x47, 0x30, 0xa6, 0x21, 0x57, 0x90, 0xeb, 0xd8, 0x3d, 0xe3, 0xb0, 0xc5,
-	0x47, 0x48, 0xcb, 0x21, 0xd6, 0x1b, 0x5d, 0xd8, 0x5f, 0x8b, 0x7d, 0x87,
-	0x7c, 0xde, 0x6c, 0x95, 0x9c, 0xca, 0x75, 0x43, 0xea, 0xbd, 0x85, 0x1c,
-	0xec, 0xfd, 0xae, 0x9e, 0xa1, 0x0e, 0xaf, 0x5e, 0xc0, 0xfd, 0x91, 0x7e,
-	0xb4, 0x5d, 0xab, 0x9f, 0xb7, 0xd9, 0xc6, 0x7b, 0xd7, 0xea, 0x15, 0xbb,
-	0xcf, 0x4c, 0x69, 0x61, 0x7f, 0xff, 0xfc, 0x98, 0xe2, 0x3d, 0x5f, 0xee,
-	0x36, 0x17, 0xe4, 0x2e, 0x2d, 0xb5, 0x03, 0xf1, 0xa2, 0x9a, 0x42, 0xdf,
-	0x6b, 0x3c, 0x83, 0xa1, 0xf6, 0x03, 0x16, 0x24, 0xb8, 0xe6, 0x38, 0x7d,
-	0xe6, 0xb0, 0x7a, 0xb6, 0xcf, 0x3c, 0xa9, 0x35, 0x3e, 0x1b, 0xd5, 0x86,
-	0x37, 0x3c, 0xdb, 0xa6, 0x64, 0x64, 0xd8, 0x5e, 0x9f, 0xc9, 0xf2, 0x88,
-	0x3c, 0x5d, 0x65, 0xbf, 0x6b, 0xf5, 0x94, 0xbd, 0x55, 0x3b, 0xb9, 0x83,
-	0xbe, 0x90, 0x7d, 0xdf, 0xd9, 0x34, 0x0f, 0xaf, 0x6f, 0x36, 0x47, 0x5d,
-	0x36, 0xce, 0xb1, 0x45, 0xf5, 0xb9, 0xac, 0xfa, 0x84, 0x94, 0xac, 0x37,
-	0xce, 0xf3, 0x17, 0xb2, 0x71, 0x9e, 0xb6, 0x75, 0x9e, 0x27, 0x31, 0xe6,
-	0x29, 0xf4, 0x2d, 0x56, 0xbb, 0xa3, 0x15, 0x79, 0xa7, 0x9e, 0xb3, 0xdf,
-	0x92, 0xcb, 0xeb, 0x63, 0xff, 0x25, 0xae, 0x1b, 0x69, 0xfa, 0x4b, 0x9f,
-	0x46, 0xfe, 0x66, 0xdb, 0x3f, 0x53, 0xf2, 0xde, 0x6a, 0x77, 0x1f, 0x5a,
-	0xd0, 0xac, 0xc1, 0x9f, 0x09, 0x75, 0xf5, 0x3b, 0xca, 0xd7, 0xdc, 0x0d,
-	0x3d, 0xed, 0x79, 0x06, 0x6b, 0xb7, 0x3f, 0xa9, 0xfa, 0x5c, 0xb1, 0x47,
-	0x64, 0xcf, 0x99, 0x6e, 0xf3, 0x8a, 0xdc, 0x2f, 0xe9, 0x08, 0xaf, 0x91,
-	0x43, 0xd9, 0x7c, 0xf7, 0xe1, 0x57, 0x99, 0x17, 0x40, 0x97, 0xdd, 0xbd,
-	0x3f, 0x93, 0x27, 0xe4, 0x64, 0x69, 0x0a, 0xbe, 0x67, 0x5c, 0x7a, 0x9f,
-	0xa1, 0xff, 0xc9, 0x9b, 0x5e, 0xad, 0xc6, 0x8b, 0x89, 0x29, 0x3f, 0x26,
-	0x4e, 0x29, 0x3f, 0xf7, 0x8a, 0x7f, 0x8e, 0xa2, 0xbb, 0xf7, 0x3c, 0x9e,
-	0x7d, 0x41, 0xf9, 0x80, 0x6f, 0x48, 0x05, 0x6b, 0x21, 0xf6, 0xfc, 0x36,
-	0xd9, 0xfa, 0x10, 0x6d, 0x12, 0x19, 0xc0, 0xdd, 0x4d, 0xea, 0x5d, 0x0b,
-	0xdd, 0x6e, 0x11, 0xd9, 0x4e, 0xfb, 0x59, 0xd8, 0x2a, 0x6d, 0xe3, 0xde,
-	0x5e, 0xd9, 0x86, 0x6b, 0x6b, 0x74, 0x4d, 0xca, 0x5b, 0x69, 0x87, 0x1f,
-	0xbd, 0xe0, 0x7d, 0xf7, 0x5f, 0x40, 0xba, 0x1c, 0x1f, 0x91, 0x7b, 0x2f,
-	0x78, 0x76, 0x37, 0x39, 0xf3, 0x84, 0x92, 0xef, 0xb8, 0x92, 0x6f, 0x5d,
-	0x8e, 0x38, 0x94, 0x3d, 0x79, 0xe2, 0xb9, 0x4a, 0x4f, 0x26, 0x9f, 0xf4,
-	0xed, 0xa8, 0xfb, 0x19, 0xbe, 0x23, 0x46, 0x19, 0x91, 0xee, 0x74, 0x07,
-	0xf7, 0x6f, 0xf7, 0x5c, 0x20, 0xbf, 0x5d, 0x1b, 0xf8, 0x7d, 0x0a, 0x3e,
-	0xb6, 0xa7, 0xc7, 0xe3, 0xf9, 0x95, 0x99, 0x0f, 0xce, 0xf3, 0xd7, 0xd6,
-	0x79, 0x36, 0xa4, 0xa2, 0xf2, 0xdc, 0xd0, 0x36, 0x69, 0xcb, 0xc9, 0x0a,
-	0xec, 0xe3, 0xcf, 0x84, 0xe7, 0x92, 0x49, 0x8b, 0x37, 0xef, 0x6a, 0x95,
-	0x34, 0x05, 0x3c, 0x90, 0xae, 0xa4, 0xaf, 0x3f, 0xd2, 0xf1, 0xc4, 0x0d,
-	0xef, 0x5d, 0x11, 0x37, 0xd3, 0x8b, 0x36, 0x5d, 0xe9, 0x70, 0xc8, 0x5f,
-	0x6f, 0x23, 0xa2, 0x2b, 0x1d, 0x26, 0xd7, 0x75, 0xf8, 0x3a, 0x74, 0x58,
-	0x91, 0x8f, 0x83, 0x27, 0xac, 0xef, 0x67, 0xfa, 0xcc, 0x23, 0xb2, 0x53,
-	0xe9, 0xdf, 0xee, 0x81, 0x4f, 0xf5, 0x75, 0xd9, 0x7c, 0x0b, 0xba, 0x7c,
-	0x43, 0x94, 0x3e, 0xd5, 0xd9, 0xa3, 0x8a, 0x1a, 0x87, 0xbe, 0x8d, 0xbc,
-	0x35, 0x2b, 0x9f, 0x40, 0x1a, 0xd5, 0x59, 0x82, 0x51, 0x4f, 0xbf, 0x6a,
-	0xcd, 0xfb, 0xfa, 0xcd, 0x8e, 0x52, 0x87, 0xd1, 0x0e, 0x4f, 0x9f, 0x2d,
-	0xaa, 0xcf, 0x74, 0xfc, 0x36, 0xb5, 0xde, 0xed, 0x9e, 0x9d, 0x1d, 0xd4,
-	0xe9, 0xd3, 0x55, 0xef, 0xbb, 0x88, 0x38, 0x37, 0x5d, 0xfd, 0x65, 0x7a,
-	0xf5, 0x74, 0x3a, 0x24, 0xde, 0xba, 0xda, 0xac, 0x4f, 0xfd, 0x42, 0x48,
-	0xd9, 0xf0, 0x10, 0x64, 0x78, 0xba, 0xb4, 0xc3, 0xb7, 0x7b, 0x8f, 0xe7,
-	0x9e, 0x0f, 0xc8, 0xf3, 0x89, 0x62, 0xb7, 0xf9, 0x16, 0xee, 0x0d, 0x83,
-	0xe7, 0x23, 0xd2, 0x24, 0x29, 0x9f, 0xe7, 0xd8, 0x3a, 0xcf, 0x01, 0x8d,
-	0x5e, 0xbf, 0x14, 0xf3, 0xd8, 0x2a, 0xfd, 0xd7, 0xef, 0xaa, 0x77, 0x1a,
-	0xae, 0x16, 0xe9, 0xb7, 0x81, 0x95, 0x22, 0x9d, 0x72, 0x65, 0x31, 0x26,
-	0x57, 0x88, 0x41, 0x06, 0xf0, 0x5d, 0x9d, 0xf2, 0x63, 0x78, 0x58, 0xde,
-	0x28, 0xde, 0x88, 0x8e, 0x7e, 0x79, 0xbd, 0x18, 0xd0, 0x42, 0x2c, 0xcc,
-	0x7c, 0x61, 0x5c, 0xde, 0x9c, 0xe9, 0x96, 0x95, 0x51, 0xc4, 0xfd, 0x1e,
-	0xca, 0xa4, 0xcf, 0x7c, 0x50, 0xbd, 0xeb, 0x72, 0xad, 0x7e, 0xd1, 0xc6,
-	0xf8, 0x73, 0x75, 0x39, 0xca, 0xfd, 0x6f, 0xfe, 0x5e, 0xbc, 0x5d, 0x56,
-	0x98, 0x53, 0xf4, 0x74, 0xca, 0xc2, 0x1c, 0xf2, 0xf9, 0x22, 0xc7, 0xa7,
-	0xdc, 0x46, 0xd4, 0xef, 0x61, 0xcc, 0xf7, 0x49, 0x9e, 0x41, 0x8f, 0x50,
-	0x37, 0xd7, 0xea, 0xab, 0x36, 0xf7, 0x3f, 0xc7, 0x65, 0x11, 0xfa, 0xfb,
-	0x47, 0x71, 0xee, 0xcf, 0xe7, 0xd4, 0xfb, 0x85, 0x0b, 0x8b, 0xa3, 0xc8,
-	0x1d, 0xae, 0xd5, 0xa7, 0xec, 0x29, 0xa5, 0xb7, 0xc5, 0xf2, 0x43, 0x7e,
-	0x3b, 0xaf, 0x79, 0xcf, 0xcd, 0xec, 0xe9, 0x61, 0xbe, 0xfa, 0x10, 0xf2,
-	0x05, 0xe6, 0xaa, 0xa3, 0xc0, 0x6b, 0x94, 0x49, 0x4c, 0x26, 0x8b, 0x1c,
-	0x4b, 0x22, 0x5b, 0x90, 0xdf, 0xe7, 0x64, 0x18, 0xf4, 0xc4, 0x90, 0xdb,
-	0x33, 0x3e, 0xdc, 0x25, 0xab, 0x11, 0x2f, 0x0e, 0xf0, 0xac, 0xd8, 0x2a,
-	0x62, 0xc3, 0xea, 0x7a, 0x6c, 0xd8, 0x89, 0x6b, 0x37, 0xe3, 0xf4, 0xfc,
-	0x67, 0x8c, 0xcf, 0xba, 0x0d, 0x63, 0xc3, 0x20, 0xfa, 0xb3, 0xad, 0x53,
-	0x26, 0xe7, 0x90, 0x44, 0x20, 0x67, 0x59, 0x10, 0x9e, 0x01, 0xc9, 0xca,
-	0xf4, 0x62, 0x77, 0xf4, 0xa2, 0x96, 0x56, 0x67, 0x45, 0xe2, 0x98, 0x73,
-	0xa1, 0xd8, 0x29, 0x8b, 0x73, 0x12, 0x33, 0x12, 0x8f, 0x48, 0x75, 0xd1,
-	0xc3, 0xec, 0x53, 0x1a, 0xda, 0xab, 0xae, 0x2c, 0x6e, 0xec, 0x63, 0x1a,
-	0x89, 0xc3, 0xf2, 0x75, 0xbf, 0x4f, 0x5a, 0xf5, 0x79, 0xb5, 0x83, 0x7b,
-	0x6c, 0x8b, 0xd5, 0x0e, 0xd0, 0x40, 0xda, 0x76, 0x35, 0xce, 0x1b, 0xbb,
-	0x3e, 0x2f, 0xe7, 0x44, 0x36, 0xb3, 0xdd, 0xc5, 0xbc, 0x17, 0xf1, 0xcc,
-	0x23, 0xa0, 0xe3, 0x9a, 0xa1, 0xdb, 0x8f, 0x48, 0x61, 0x71, 0xf3, 0x1c,
-	0x8d, 0x34, 0xf0, 0x19, 0x8e, 0xcf, 0x79, 0x0e, 0x83, 0xbe, 0x6b, 0x9a,
-	0x6e, 0x1f, 0x86, 0x2c, 0xbd, 0x39, 0x8c, 0xb3, 0x96, 0xf9, 0x23, 0xe9,
-	0x11, 0xfd, 0xbc, 0xa6, 0xe4, 0xaf, 0x2f, 0xf4, 0x63, 0x81, 0x64, 0xa4,
-	0x6d, 0x79, 0x4c, 0x8c, 0x65, 0xd6, 0x10, 0x5e, 0x69, 0x4d, 0xab, 0xfd,
-	0xde, 0x2d, 0x58, 0xdf, 0xe2, 0x86, 0x6c, 0xd6, 0x0b, 0x58, 0x0f, 0xfe,
-	0xfa, 0x36, 0xe9, 0x60, 0xbd, 0x80, 0x79, 0xc3, 0x21, 0x7c, 0x33, 0x77,
-	0x78, 0xb9, 0x9e, 0x74, 0x7e, 0xa6, 0xe2, 0x6b, 0x6e, 0x91, 0xf7, 0xad,
-	0x98, 0x08, 0xef, 0xd1, 0x6f, 0x74, 0x4a, 0xd3, 0x57, 0x7a, 0xe1, 0x2b,
-	0x1e, 0x03, 0xf6, 0xc6, 0xb8, 0x67, 0x7a, 0x24, 0xe4, 0x9d, 0xb1, 0x50,
-	0xf5, 0x96, 0x37, 0xe7, 0x2c, 0xff, 0x9d, 0x21, 0xd9, 0x73, 0xd1, 0x61,
-	0x4d, 0xb4, 0x8b, 0x35, 0x1f, 0xf4, 0x13, 0x7d, 0x15, 0xf9, 0xe9, 0x95,
-	0x45, 0x63, 0x1b, 0xcf, 0x7c, 0xbe, 0x5e, 0xc5, 0x35, 0xb1, 0x7f, 0x44,
-	0x61, 0x4c, 0xff, 0x1e, 0x7f, 0x23, 0x5f, 0x7a, 0xcf, 0xf9, 0x77, 0xe6,
-	0x53, 0x63, 0xfe, 0x59, 0x3b, 0x37, 0x73, 0x72, 0x43, 0x4e, 0xd5, 0xab,
-	0xea, 0xbd, 0x2b, 0x55, 0x1b, 0xfe, 0x71, 0x00, 0xf6, 0xc9, 0x35, 0x50,
-	0xd7, 0x1e, 0x02, 0x36, 0x8b, 0x75, 0xaa, 0x9c, 0xe8, 0xf4, 0x43, 0xe2,
-	0xd9, 0x3b, 0xac, 0x4c, 0xf9, 0xb2, 0x95, 0xb2, 0x97, 0x83, 0xac, 0x96,
-	0x33, 0xf2, 0x9f, 0xaa, 0x97, 0x54, 0xad, 0x75, 0x06, 0x79, 0x49, 0x68,
-	0x5a, 0xe5, 0x64, 0x0d, 0xf8, 0x16, 0x7e, 0xef, 0xd9, 0x2f, 0x62, 0x2d,
-	0x5a, 0xea, 0x4c, 0x83, 0x7e, 0xbe, 0x5e, 0x4f, 0xc1, 0x7f, 0xe8, 0xb6,
-	0x6d, 0x16, 0x10, 0x0f, 0x53, 0xea, 0x5c, 0x0c, 0xd7, 0xf1, 0x61, 0xe5,
-	0x9f, 0x65, 0x01, 0xb2, 0x39, 0x1b, 0xc3, 0x38, 0x9a, 0xb2, 0x4f, 0x43,
-	0xe9, 0xe1, 0x21, 0x85, 0x79, 0x8d, 0xf3, 0x70, 0x58, 0xcb, 0x3d, 0x22,
-	0xe7, 0x33, 0x32, 0x85, 0x35, 0x1c, 0x5a, 0xa6, 0x0e, 0x28, 0xdb, 0x31,
-	0x69, 0x82, 0xec, 0x4f, 0x00, 0x7b, 0x18, 0xd3, 0x94, 0x71, 0x14, 0xeb,
-	0xa2, 0x53, 0x42, 0x67, 0x21, 0xe3, 0x69, 0x60, 0x84, 0xb9, 0x66, 0x79,
-	0x69, 0x31, 0x90, 0xe9, 0xcb, 0x3c, 0xef, 0xaf, 0x8f, 0x0f, 0x74, 0x11,
-	0x47, 0x49, 0x65, 0x71, 0x4a, 0xa6, 0x66, 0x99, 0xb3, 0x8f, 0xa9, 0x33,
-	0x06, 0x21, 0x75, 0xc6, 0xc5, 0xcb, 0x99, 0xbd, 0x6f, 0x0f, 0x63, 0x56,
-	0x84, 0x7b, 0x6d, 0x02, 0xdb, 0xe9, 0xc7, 0xbc, 0x37, 0x92, 0xaf, 0x97,
-	0xab, 0x0e, 0x83, 0xde, 0x8b, 0x33, 0x56, 0x26, 0x2f, 0x0e, 0xcf, 0x5b,
-	0x8f, 0xba, 0xe0, 0x7f, 0x15, 0xfe, 0x73, 0xaa, 0x74, 0x2f, 0xf8, 0x2c,
-	0x60, 0x85, 0x65, 0xe4, 0x62, 0x91, 0x39, 0xe3, 0x47, 0xa1, 0x37, 0x5e,
-	0x17, 0x06, 0x0d, 0xf8, 0x81, 0x35, 0xf5, 0x7e, 0xa1, 0xe5, 0xae, 0x20,
-	0x87, 0x8d, 0x69, 0x87, 0xa0, 0xeb, 0xbc, 0xd9, 0xe4, 0xdb, 0x03, 0xdf,
-	0x35, 0x3e, 0x07, 0x3f, 0xba, 0x24, 0x7c, 0xef, 0xe7, 0x9d, 0x3a, 0xf3,
-	0xa5, 0xcb, 0xf0, 0x7b, 0x99, 0x78, 0x06, 0x36, 0x94, 0x8f, 0xb6, 0x80,
-	0xe6, 0xdf, 0xc6, 0xbd, 0x5c, 0x95, 0xf3, 0x58, 0xce, 0x9a, 0x14, 0x62,
-	0x21, 0xe9, 0x8b, 0x5d, 0x92, 0x6d, 0xf0, 0x64, 0x9a, 0xbc, 0x61, 0x5b,
-	0x83, 0xa2, 0xa9, 0xf1, 0x7a, 0x0f, 0xc0, 0x06, 0xaf, 0xc2, 0xdf, 0x35,
-	0xfb, 0xb9, 0x7e, 0xaa, 0x48, 0x0c, 0xf5, 0x84, 0x3a, 0x8b, 0x70, 0xd9,
-	0x66, 0x1d, 0x90, 0xef, 0xfb, 0xfe, 0x95, 0x9a, 0xe3, 0xfa, 0xde, 0x1d,
-	0xeb, 0xd0, 0xa4, 0xcf, 0xe3, 0x71, 0xbf, 0xed, 0xd1, 0xc8, 0x71, 0x9a,
-	0x1a, 0xc6, 0xb9, 0xe8, 0x8f, 0x73, 0xce, 0x1f, 0x67, 0xc1, 0x1f, 0xe7,
-	0xf2, 0xfa, 0x38, 0x0f, 0xc2, 0x0e, 0xea, 0xf5, 0xa7, 0x80, 0x37, 0x92,
-	0x4e, 0xbd, 0x9e, 0x46, 0x5e, 0x36, 0xd9, 0x3f, 0xa1, 0xf6, 0x5e, 0xf5,
-	0xc4, 0x8b, 0x43, 0x49, 0xdb, 0x93, 0x3f, 0xac, 0x40, 0x26, 0x60, 0x8f,
-	0x79, 0xf1, 0xb0, 0x3a, 0xf7, 0x03, 0xbd, 0xfd, 0xc2, 0x36, 0xf8, 0x81,
-	0xc7, 0x10, 0x4b, 0x9c, 0xe1, 0x25, 0x5b, 0xf2, 0x7b, 0x7e, 0x4d, 0x87,
-	0xbd, 0x77, 0x20, 0x2e, 0xbd, 0x09, 0xdb, 0x71, 0x86, 0x2b, 0x8b, 0x8f,
-	0xa9, 0x3d, 0xe1, 0xa6, 0xc4, 0xbd, 0xd0, 0x67, 0x79, 0x78, 0x61, 0xb1,
-	0x3c, 0x7c, 0x8e, 0xfb, 0x43, 0xe8, 0xb7, 0xb0, 0xd8, 0x0e, 0xb9, 0xb7,
-	0xab, 0xba, 0xca, 0xa5, 0x62, 0x04, 0x7a, 0x34, 0x61, 0xf3, 0x11, 0xb4,
-	0x45, 0x61, 0x07, 0x5d, 0x68, 0x7f, 0x0d, 0x6b, 0x3b, 0x86, 0xf6, 0xb5,
-	0xd6, 0x61, 0x85, 0x63, 0x6d, 0x39, 0x5f, 0xbd, 0x8a, 0x98, 0xfb, 0x16,
-	0xfc, 0x68, 0x2f, 0xfa, 0xf4, 0xa3, 0xcf, 0x0e, 0x13, 0xf8, 0x2a, 0x53,
-	0xbe, 0x21, 0x4d, 0x2e, 0x68, 0xd2, 0x1b, 0x68, 0x72, 0x41, 0x0f, 0x7c,
-	0xe7, 0x19, 0xd6, 0xa0, 0xfb, 0xe5, 0x64, 0x91, 0x67, 0xaa, 0xf8, 0xee,
-	0xb5, 0x29, 0x21, 0x60, 0xd2, 0xa6, 0x33, 0x56, 0x74, 0x45, 0xd5, 0x7a,
-	0x68, 0x5b, 0x7d, 0x4e, 0x45, 0x54, 0x9c, 0x89, 0x9d, 0x44, 0xfc, 0xba,
-	0x5a, 0x6d, 0x97, 0x37, 0xfc, 0xb9, 0xd6, 0x84, 0xfb, 0x97, 0x1b, 0xe7,
-	0x3a, 0x55, 0x1a, 0x1d, 0xfe, 0x81, 0x6d, 0xf8, 0x7c, 0x75, 0x62, 0xae,
-	0x76, 0xf4, 0x1d, 0x1d, 0xbe, 0xb8, 0x78, 0xa3, 0xbe, 0x13, 0xe8, 0xdb,
-	0xd4, 0xd0, 0x77, 0x02, 0xfd, 0xda, 0x11, 0x07, 0xdb, 0x15, 0x4f, 0x93,
-	0xa0, 0xeb, 0x4a, 0x51, 0xbd, 0x0b, 0x0c, 0xb9, 0x73, 0x4e, 0x93, 0x98,
-	0x3a, 0xe3, 0xd5, 0x4a, 0x2c, 0x33, 0xa6, 0xbd, 0xa7, 0xde, 0xa3, 0x6c,
-	0x60, 0xc8, 0x06, 0xee, 0x9d, 0x19, 0xd5, 0x52, 0x95, 0x1c, 0x62, 0xd6,
-	0x2e, 0xe2, 0x27, 0xc7, 0x45, 0xcc, 0x5c, 0xc0, 0x78, 0x8b, 0xc5, 0x15,
-	0x9e, 0xc1, 0x86, 0x5d, 0xbc, 0x4d, 0x9c, 0xbd, 0xcb, 0x50, 0x67, 0x1e,
-	0xd2, 0xaa, 0x66, 0xb7, 0x50, 0x14, 0x33, 0x39, 0xc0, 0x33, 0x0e, 0xf7,
-	0x63, 0x5d, 0x7e, 0x0e, 0x6d, 0x49, 0xc4, 0xc7, 0xc3, 0x5a, 0x72, 0x69,
-	0x18, 0xd7, 0x8f, 0xe0, 0x1a, 0xfe, 0x78, 0x2e, 0x8b, 0xfb, 0x8f, 0xe0,
-	0x7a, 0x42, 0x4b, 0xd5, 0xb2, 0xb8, 0x7e, 0x14, 0xd7, 0x49, 0x93, 0x79,
-	0xca, 0x0f, 0xec, 0x8c, 0xe6, 0x62, 0x2c, 0x77, 0x69, 0x18, 0x9f, 0xc6,
-	0xf1, 0x78, 0x0f, 0x7a, 0x2a, 0x72, 0xaf, 0x2d, 0x0e, 0x9a, 0x0e, 0x6a,
-	0xe9, 0x4a, 0x1b, 0xc6, 0xe8, 0xc1, 0xf3, 0xb4, 0xa9, 0x43, 0xfe, 0xfc,
-	0xac, 0x39, 0xdd, 0xad, 0x6a, 0x4e, 0x46, 0x22, 0x03, 0x9c, 0x7c, 0x1c,
-	0x79, 0x80, 0x26, 0x69, 0xfb, 0x49, 0x29, 0x38, 0xf0, 0x2b, 0x15, 0x43,
-	0x52, 0x91, 0x3c, 0x7e, 0xe7, 0x25, 0x39, 0x88, 0xfb, 0x15, 0xda, 0x02,
-	0xfb, 0xfd, 0x89, 0x14, 0xca, 0xc4, 0xfd, 0xac, 0x33, 0xb1, 0x36, 0xc5,
-	0xfa, 0x52, 0x0e, 0x32, 0x88, 0xd0, 0x7e, 0x6f, 0x50, 0x13, 0xf3, 0xce,
-	0x55, 0x23, 0x2e, 0x6b, 0xc9, 0x0a, 0xf7, 0xfd, 0xdc, 0xcc, 0x45, 0x9b,
-	0xef, 0x28, 0x4d, 0x70, 0x1f, 0xb1, 0x60, 0x24, 0x58, 0x1f, 0x51, 0xf5,
-	0x75, 0xc7, 0xdb, 0x1f, 0xe4, 0xb8, 0x63, 0xe0, 0xb7, 0xb1, 0x6e, 0xc5,
-	0x79, 0xbf, 0x80, 0xe7, 0xbd, 0x7a, 0x56, 0xaa, 0xf6, 0x5e, 0x5d, 0xf0,
-	0xbd, 0x81, 0xf3, 0xd0, 0xc5, 0x45, 0x95, 0x1b, 0x73, 0x0f, 0xf7, 0xfd,
-	0x72, 0x2a, 0xe4, 0x30, 0x45, 0xd6, 0xc8, 0x82, 0x7d, 0xbb, 0x40, 0x8e,
-	0x9b, 0x69, 0x25, 0x9d, 0x47, 0x30, 0xa6, 0x38, 0xf4, 0xbb, 0xd9, 0x08,
-	0xf7, 0xdf, 0xf8, 0x8c, 0x7c, 0xf9, 0x3a, 0xdd, 0xa4, 0x99, 0xf2, 0x38,
-	0x0e, 0xff, 0xc9, 0x77, 0x32, 0x9e, 0x94, 0x9c, 0xc3, 0x1a, 0x8f, 0x81,
-	0xd8, 0x98, 0xc7, 0xef, 0xeb, 0xf2, 0x9b, 0xf4, 0xe5, 0x97, 0x2b, 0xbf,
-	0xa4, 0x74, 0xb8, 0x60, 0x73, 0xbe, 0xa0, 0xf6, 0x31, 0xa2, 0x74, 0xb7,
-	0xa0, 0xce, 0xfd, 0x06, 0x32, 0x08, 0xea, 0x77, 0x37, 0xb6, 0xbd, 0x61,
-	0x9b, 0xb4, 0xdd, 0xce, 0xf3, 0x10, 0xbd, 0xae, 0x90, 0x7e, 0xf2, 0xc1,
-	0x18, 0x16, 0xec, 0xb5, 0x06, 0x3c, 0x04, 0x7c, 0xde, 0xaa, 0x7c, 0x48,
-	0x6f, 0x64, 0xbb, 0xb4, 0x65, 0x4c, 0xc3, 0x66, 0x6c, 0xf8, 0x84, 0xbf,
-	0x3f, 0xf0, 0x77, 0x21, 0x67, 0x4f, 0x16, 0xa1, 0x84, 0x4c, 0xfa, 0xef,
-	0xf8, 0xde, 0xc0, 0x1e, 0x36, 0xef, 0x35, 0xbb, 0x99, 0x73, 0xf6, 0x75,
-	0xbe, 0x17, 0x6e, 0xc0, 0xf7, 0x82, 0xcf, 0x77, 0xe5, 0x16, 0xe9, 0x5d,
-	0x98, 0x71, 0xc1, 0x33, 0x6d, 0xee, 0x46, 0xf6, 0x28, 0xea, 0x7f, 0x5f,
-	0xac, 0x19, 0xe1, 0xb0, 0x5b, 0xbd, 0x59, 0x0d, 0x95, 0x79, 0xb5, 0x67,
-	0x97, 0xe7, 0x10, 0x0b, 0xcb, 0x65, 0x2f, 0xc7, 0x2e, 0x57, 0x59, 0xcb,
-	0x7e, 0x3f, 0x1a, 0xf8, 0xfe, 0xd7, 0x67, 0xd4, 0x79, 0x97, 0xc9, 0xaa,
-	0x57, 0xf7, 0x2a, 0x97, 0x1b, 0x63, 0xea, 0x0e, 0xc6, 0xd3, 0xde, 0xbc,
-	0x8c, 0xf2, 0xbd, 0x65, 0x5c, 0xef, 0x96, 0x4b, 0x73, 0x6a, 0xcf, 0xca,
-	0xdf, 0x1b, 0xe2, 0x9e, 0x8f, 0xda, 0xff, 0x86, 0x5f, 0x1b, 0x53, 0x7e,
-	0x7d, 0x75, 0x4e, 0xdd, 0xf3, 0xb0, 0x52, 0x75, 0x14, 0x7e, 0x1f, 0xb9,
-	0x84, 0xbd, 0x55, 0x0a, 0xc8, 0xb9, 0xcf, 0xd9, 0x0f, 0x6f, 0x27, 0xce,
-	0xe1, 0x58, 0xab, 0x18, 0xeb, 0xe2, 0x9c, 0x6c, 0xe7, 0x99, 0x92, 0xb2,
-	0xda, 0x67, 0xf3, 0xea, 0xe2, 0x13, 0x12, 0xfc, 0x4f, 0x88, 0xb0, 0x1f,
-	0x0b, 0x79, 0xae, 0x85, 0xef, 0xd2, 0xd2, 0x57, 0x20, 0x0f, 0x1a, 0xe5,
-	0x3e, 0x4e, 0xbd, 0xee, 0xd5, 0xcd, 0xeb, 0x58, 0x17, 0x4d, 0x7c, 0xef,
-	0x02, 0x7f, 0xc7, 0x61, 0x3f, 0x58, 0x27, 0xeb, 0xed, 0xbc, 0x66, 0xee,
-	0x11, 0x5c, 0x33, 0xb0, 0xfd, 0x3f, 0xd4, 0x46, 0x90, 0x7c, 0xb4, 0x45,
-	0x00, 0x00, 0x00 };
+	0xa5, 0x7b, 0x0b, 0x74, 0x1c, 0x55, 0x7a, 0xe6, 0x77, 0xab, 0xba, 0xa5,
+	0xea, 0x56, 0xab, 0x55, 0x92, 0xdb, 0xa6, 0x95, 0xd1, 0xe0, 0x2e, 0x77,
+	0xb5, 0xdc, 0x58, 0xc2, 0x54, 0xcb, 0x2d, 0xd3, 0x44, 0xe5, 0xb8, 0xc7,
+	0x08, 0x5b, 0x06, 0x4d, 0x46, 0x38, 0xca, 0xac, 0x98, 0xc3, 0x2e, 0x1d,
+	0x63, 0x83, 0x30, 0x06, 0x04, 0xc3, 0x66, 0x95, 0x2c, 0x89, 0x6a, 0xe4,
+	0x07, 0x7e, 0xb4, 0xba, 0xf5, 0x32, 0x32, 0xd9, 0x9c, 0xb8, 0x2d, 0xc9,
+	0x96, 0x81, 0x7e, 0xc0, 0x00, 0x33, 0x43, 0x76, 0x67, 0xe9, 0x35, 0x60,
+	0x0c, 0x8c, 0x61, 0x92, 0x3d, 0x67, 0x97, 0xc9, 0x99, 0x49, 0x7c, 0x30,
+	0x78, 0x6c, 0xde, 0x9b, 0x99, 0xdd, 0x15, 0x09, 0x93, 0xda, 0xff, 0xaf,
+	0x96, 0x8c, 0x61, 0xd8, 0x24, 0x9b, 0xd5, 0x39, 0x7d, 0x4a, 0x5d, 0x75,
+	0xeb, 0xde, 0xff, 0xfd, 0x7f, 0xff, 0x7f, 0x6f, 0x47, 0x00, 0x2f, 0x16,
+	0xfe, 0x6a, 0xe9, 0x13, 0x1f, 0x18, 0x7c, 0xb0, 0x7d, 0xb5, 0xb1, 0xda,
+	0xb9, 0xe1, 0x86, 0x8b, 0x1f, 0xae, 0x15, 0x40, 0xea, 0x5d, 0xfc, 0x8b,
+	0xfe, 0xbe, 0xfa, 0x2f, 0x7b, 0x0d, 0x32, 0xa0, 0x2e, 0xd2, 0xc4, 0x1f,
+	0x28, 0x92, 0x99, 0xfb, 0xcd, 0x0d, 0x3a, 0x14, 0xd9, 0xec, 0x5b, 0x77,
+	0xbb, 0x0e, 0x24, 0xf3, 0x2d, 0xa1, 0xeb, 0xf1, 0x2b, 0xdb, 0x0a, 0xb8,
+	0xc0, 0xf7, 0xbf, 0x6a, 0x7e, 0x3a, 0xf4, 0xc3, 0x6b, 0xb5, 0x8f, 0x73,
+	0x32, 0x14, 0xd5, 0x9c, 0x84, 0xda, 0x0c, 0xa5, 0x89, 0xde, 0xf9, 0xd3,
+	0x95, 0xdf, 0x77, 0xc1, 0xbf, 0x38, 0x17, 0x2c, 0xb7, 0x69, 0x60, 0x57,
+	0x76, 0x00, 0x73, 0x71, 0xe0, 0x42, 0x3a, 0x62, 0xec, 0x02, 0x46, 0x25,
+	0x33, 0x12, 0x3a, 0x89, 0x10, 0x66, 0xf3, 0xb0, 0xaa, 0x4d, 0x1d, 0xfb,
+	0x4a, 0x21, 0x5c, 0x4c, 0xff, 0x83, 0x1d, 0x72, 0x0f, 0xe0, 0xed, 0x38,
+	0x94, 0xa0, 0xf9, 0x10, 0x82, 0x59, 0x28, 0xb5, 0xe6, 0x20, 0x0a, 0x23,
+	0xc0, 0x9e, 0xb4, 0x36, 0x00, 0x68, 0x7d, 0x45, 0x11, 0x3e, 0x7d, 0x02,
+	0x5a, 0x4f, 0xa3, 0xdc, 0x92, 0xba, 0x45, 0x68, 0xc9, 0x9d, 0x02, 0x8a,
+	0xa0, 0xb1, 0xab, 0xf2, 0x7c, 0x1d, 0x44, 0x34, 0xaf, 0xe0, 0xac, 0xcc,
+	0xcb, 0x9a, 0x24, 0x67, 0x01, 0x97, 0x6e, 0x60, 0x4f, 0x16, 0x96, 0xcb,
+	0x14, 0xd8, 0x15, 0x8f, 0xa8, 0x33, 0xe0, 0xe7, 0x21, 0x0c, 0x3b, 0xe3,
+	0x34, 0xe2, 0xd8, 0xb6, 0x77, 0x1b, 0xb6, 0x7d, 0xcc, 0xa8, 0x86, 0xa5,
+	0x6a, 0x41, 0x40, 0x60, 0xd8, 0x90, 0x90, 0x54, 0x37, 0x84, 0x5c, 0xd0,
+	0x82, 0xdb, 0xf1, 0xf7, 0xc4, 0x6f, 0x32, 0xea, 0x46, 0x65, 0x7c, 0x0a,
+	0xd5, 0x28, 0xab, 0x15, 0x89, 0x4d, 0xa7, 0x6d, 0xfb, 0x94, 0xee, 0xc2,
+	0x31, 0x92, 0xcd, 0x70, 0xfe, 0xef, 0xed, 0x32, 0xc9, 0x65, 0xb7, 0xbe,
+	0xb8, 0xbe, 0x82, 0x9c, 0x6a, 0xdb, 0x33, 0xf4, 0x6c, 0x6f, 0x7e, 0x51,
+	0xc6, 0xb6, 0x2d, 0xe9, 0xb6, 0x7d, 0xbb, 0xfe, 0x77, 0xf6, 0xd6, 0xcf,
+	0x8d, 0x8d, 0xe1, 0xf1, 0x51, 0x15, 0x4f, 0x64, 0x93, 0xc8, 0xa7, 0x6d,
+	0xc8, 0xa6, 0x0b, 0xfd, 0x23, 0x21, 0xec, 0x2c, 0x74, 0xa2, 0x90, 0xd6,
+	0x52, 0x67, 0xe9, 0xbd, 0xad, 0x71, 0x1d, 0xf7, 0x14, 0xba, 0x30, 0x97,
+	0x86, 0xed, 0x31, 0xf5, 0xb2, 0x47, 0x44, 0x71, 0x67, 0xa1, 0x1b, 0xc5,
+	0xb4, 0x7e, 0x7a, 0x58, 0x44, 0x06, 0x1b, 0x65, 0x17, 0xee, 0x2b, 0xb4,
+	0xe2, 0xde, 0x42, 0x82, 0xde, 0xb1, 0x71, 0x63, 0xac, 0x89, 0xc6, 0xb7,
+	0xe1, 0xb1, 0x49, 0xdb, 0x8e, 0xc6, 0x54, 0xf4, 0x17, 0x0c, 0xcc, 0x8d,
+	0x4a, 0x48, 0x1d, 0x73, 0x21, 0x75, 0x14, 0xb8, 0xf3, 0x68, 0x1b, 0x66,
+	0x46, 0x6d, 0x6c, 0x35, 0x86, 0x1b, 0x25, 0x32, 0xbb, 0x94, 0x2a, 0xe0,
+	0xd6, 0xfd, 0xd8, 0xae, 0x56, 0x68, 0x3f, 0x2b, 0x0b, 0xec, 0x38, 0x1a,
+	0xc5, 0x9b, 0x69, 0x0b, 0x37, 0xb6, 0x07, 0x31, 0x58, 0x08, 0xe0, 0x8d,
+	0x74, 0x80, 0xd6, 0x30, 0xf0, 0x7a, 0x5a, 0xa1, 0x75, 0x5a, 0xf1, 0x62,
+	0x9a, 0xc7, 0xf0, 0x58, 0x1f, 0xb6, 0x15, 0x9a, 0x70, 0x26, 0x1d, 0xa4,
+	0x35, 0x03, 0x78, 0x85, 0xc6, 0xdd, 0x55, 0xd0, 0x71, 0x9a, 0xc6, 0xf5,
+	0x17, 0x42, 0x78, 0x39, 0xed, 0x23, 0x5a, 0x03, 0x38, 0x99, 0x1e, 0xc0,
+	0xae, 0x74, 0xcb, 0xe9, 0xeb, 0x49, 0x86, 0xa1, 0x25, 0xbc, 0x0e, 0xdf,
+	0x7b, 0xdb, 0xee, 0x0e, 0x38, 0x66, 0x42, 0xeb, 0x2c, 0xae, 0x3b, 0x80,
+	0xe1, 0xf4, 0x8b, 0x0b, 0x7e, 0x62, 0x60, 0xff, 0xe8, 0xbc, 0xfd, 0xc3,
+	0x95, 0x4d, 0x38, 0x91, 0x05, 0x1e, 0x9b, 0x01, 0x66, 0xb2, 0x96, 0x5d,
+	0x6b, 0xda, 0xf6, 0x74, 0x7b, 0x2b, 0xc9, 0x4b, 0xef, 0xdb, 0x4a, 0xa3,
+	0x9e, 0x28, 0xb9, 0x80, 0xa3, 0x5a, 0x5f, 0x19, 0x12, 0x72, 0x73, 0x2e,
+	0x54, 0x8d, 0x68, 0x5d, 0x39, 0x68, 0xa7, 0xef, 0x24, 0x4f, 0x3a, 0x96,
+	0xd5, 0x7a, 0x2c, 0x0c, 0xd9, 0x41, 0xb3, 0x39, 0xd4, 0x2a, 0xdb, 0xf0,
+	0x93, 0x2d, 0xa4, 0x5b, 0x6d, 0xbb, 0xee, 0x5a, 0xdb, 0x3e, 0xd3, 0x0e,
+	0x5b, 0x32, 0xf5, 0xd3, 0x25, 0xe8, 0xe5, 0x0f, 0xa0, 0x0f, 0x9e, 0x44,
+	0xf9, 0xab, 0x3e, 0x44, 0xfa, 0xc3, 0x72, 0x64, 0x60, 0x9e, 0xde, 0xad,
+	0x2d, 0x90, 0x29, 0x13, 0x2f, 0x3a, 0xd9, 0x60, 0xa1, 0xa4, 0xc0, 0x45,
+	0xfc, 0xb4, 0x8e, 0xd8, 0xb6, 0x4b, 0xf7, 0xc1, 0x47, 0xf2, 0xdd, 0x74,
+	0xc8, 0xb6, 0xcf, 0x1b, 0x2a, 0xaa, 0x48, 0x37, 0x37, 0x8c, 0xd9, 0x98,
+	0x36, 0x4e, 0x92, 0x3c, 0x05, 0x52, 0x3d, 0x71, 0x7a, 0x27, 0x40, 0xe3,
+	0x13, 0xd8, 0x34, 0x12, 0xc4, 0xe3, 0x59, 0x05, 0x3f, 0x5c, 0x19, 0x45,
+	0x0d, 0xcd, 0xe5, 0x25, 0x59, 0x55, 0x93, 0xfc, 0x50, 0x20, 0x73, 0x2b,
+	0x54, 0xec, 0x11, 0x85, 0xb3, 0xc4, 0x63, 0x10, 0xdf, 0x2d, 0x05, 0xf0,
+	0x54, 0x49, 0xc5, 0x93, 0xa5, 0x26, 0x3c, 0x5f, 0x32, 0x90, 0x1d, 0xd5,
+	0xf6, 0x95, 0x61, 0xa3, 0x96, 0xcc, 0xf9, 0x8d, 0x5c, 0x0c, 0x99, 0x51,
+	0xdb, 0xce, 0x13, 0xcd, 0x5e, 0xe2, 0xe1, 0xf5, 0xdc, 0x95, 0x38, 0x3e,
+	0xe9, 0x42, 0x68, 0x3a, 0x80, 0x27, 0xd2, 0x2e, 0x5c, 0x95, 0xd1, 0xac,
+	0x1c, 0xf4, 0xe8, 0x4e, 0xa1, 0x27, 0x57, 0x09, 0x6d, 0xd4, 0x42, 0x24,
+	0xe4, 0x16, 0x12, 0x9a, 0x8f, 0xbb, 0xa0, 0x17, 0x43, 0x70, 0x37, 0x2b,
+	0xd0, 0x9b, 0xc9, 0x8d, 0xfc, 0x12, 0xaa, 0xc8, 0x2f, 0x36, 0x8d, 0x47,
+	0xe9, 0x5e, 0x80, 0xee, 0xe1, 0xca, 0x6a, 0xc8, 0xcb, 0x64, 0x90, 0xdc,
+	0x74, 0x19, 0x49, 0x97, 0x6d, 0xcb, 0x7a, 0x1b, 0xfa, 0x1e, 0xa1, 0xeb,
+	0x1a, 0x1e, 0xaf, 0x22, 0x5c, 0x24, 0x19, 0x34, 0x13, 0x4d, 0x59, 0xa2,
+	0x31, 0x4b, 0x34, 0x66, 0x89, 0xc6, 0xac, 0x4c, 0x36, 0xa3, 0x19, 0xc0,
+	0x1f, 0x92, 0xae, 0x42, 0xc4, 0xdf, 0x9b, 0x8e, 0x9e, 0x9e, 0x2a, 0x05,
+	0x89, 0xfe, 0x90, 0x43, 0xff, 0x63, 0xa3, 0x02, 0x92, 0xae, 0xf5, 0x9c,
+	0xc5, 0x7a, 0x84, 0x63, 0x5a, 0x32, 0x87, 0x24, 0xbd, 0xa7, 0xed, 0xb3,
+	0xa0, 0x75, 0x95, 0x49, 0xff, 0x5b, 0xd5, 0x04, 0xe6, 0xb2, 0x6e, 0xd4,
+	0xe8, 0x5a, 0x88, 0xf4, 0x15, 0x2d, 0x63, 0x09, 0xee, 0x56, 0x69, 0x4e,
+	0xa9, 0x4a, 0x54, 0x62, 0xc8, 0x43, 0x88, 0x8c, 0x4b, 0x98, 0x35, 0x64,
+	0xf2, 0x4f, 0x03, 0x72, 0x33, 0x2d, 0x57, 0x8c, 0xd3, 0x95, 0xe6, 0xcf,
+	0xd2, 0x5a, 0x44, 0x0f, 0xcd, 0x47, 0x7e, 0xc9, 0x72, 0x8c, 0x12, 0x0d,
+	0x7b, 0x1c, 0x7a, 0x9f, 0x2c, 0x75, 0x8b, 0x8a, 0xfd, 0x98, 0x64, 0x2f,
+	0x5a, 0x08, 0x42, 0x8b, 0x86, 0x84, 0x66, 0x24, 0x85, 0x8a, 0x99, 0xd2,
+	0x8f, 0x68, 0x4c, 0xe0, 0xb2, 0x31, 0x3d, 0x18, 0xce, 0x0a, 0x5c, 0xaf,
+	0xdb, 0xd8, 0x60, 0xf4, 0x60, 0x57, 0x69, 0xd1, 0x2f, 0x39, 0x76, 0xa9,
+	0xfe, 0x99, 0x74, 0x27, 0x76, 0x67, 0x43, 0xd8, 0x95, 0x0f, 0xfa, 0xa7,
+	0xd3, 0xfc, 0x4c, 0x27, 0x7f, 0xe7, 0x67, 0x81, 0xcb, 0x9e, 0x35, 0x5d,
+	0xf6, 0x2c, 0x81, 0xe1, 0x89, 0xaf, 0x50, 0x0c, 0xa9, 0xc3, 0x2e, 0xfd,
+	0x63, 0xb2, 0x15, 0x3d, 0xb1, 0x0d, 0x8d, 0x38, 0xab, 0xb6, 0xe2, 0xe0,
+	0x54, 0x37, 0x76, 0x4f, 0xad, 0xc6, 0xfe, 0x89, 0xa6, 0x94, 0xd7, 0x1c,
+	0xa1, 0xf5, 0xc3, 0xc9, 0x6d, 0x42, 0x1b, 0x90, 0x45, 0x38, 0xba, 0x8d,
+	0x6c, 0xb7, 0xb9, 0xde, 0xb6, 0x4f, 0xc6, 0xc8, 0xb6, 0x8d, 0x16, 0x63,
+	0x13, 0x09, 0xa0, 0xdc, 0xa3, 0x75, 0xbd, 0x0d, 0x1f, 0xbe, 0x4e, 0x36,
+	0x37, 0x13, 0xc3, 0x36, 0x19, 0x72, 0xab, 0x0f, 0xbf, 0xb0, 0x8f, 0xba,
+	0x58, 0xee, 0xf6, 0xd0, 0xed, 0xc6, 0x1e, 0xc1, 0x71, 0xae, 0xea, 0x52,
+	0x2c, 0xe1, 0xf9, 0xf9, 0x1d, 0xdb, 0x0e, 0xd3, 0x3c, 0xfd, 0xb1, 0x96,
+	0x44, 0x3f, 0xe6, 0xed, 0xb3, 0xbd, 0xdd, 0xd8, 0x35, 0xb7, 0x1a, 0x07,
+	0x26, 0xdc, 0x48, 0xd6, 0x0b, 0xd4, 0xe9, 0xe1, 0xf2, 0xdd, 0x58, 0x0d,
+	0x6b, 0x86, 0xdf, 0xeb, 0xc6, 0xe1, 0xb9, 0xca, 0xf7, 0xec, 0xa5, 0xef,
+	0x8b, 0xf3, 0x5d, 0x20, 0x9d, 0xb2, 0x3c, 0x39, 0x4e, 0x92, 0x0a, 0xcc,
+	0x16, 0x9c, 0x98, 0x08, 0x90, 0x6e, 0x3b, 0x85, 0xeb, 0xf8, 0x32, 0xbf,
+	0xf7, 0x11, 0x1b, 0xa7, 0x0c, 0xd2, 0x73, 0x76, 0xa3, 0xf0, 0x1e, 0xef,
+	0x12, 0xee, 0xe2, 0x16, 0x51, 0x35, 0xfd, 0x2d, 0xa1, 0x1c, 0x4f, 0x89,
+	0xea, 0x62, 0x2b, 0xc9, 0xbe, 0x4f, 0x78, 0x8e, 0x6b, 0xa1, 0x90, 0xf8,
+	0x03, 0xd2, 0x67, 0xaf, 0x90, 0x8b, 0x50, 0x25, 0x73, 0x50, 0x48, 0x45,
+	0x9a, 0xc3, 0xb1, 0x21, 0x5e, 0x27, 0x48, 0x7a, 0x83, 0x25, 0x9b, 0x03,
+	0xd8, 0x4a, 0x39, 0xe2, 0xa6, 0xb4, 0x89, 0x03, 0xd9, 0x6a, 0x8a, 0x8f,
+	0xec, 0xf7, 0xf3, 0xb4, 0xae, 0x8e, 0x83, 0x25, 0x58, 0x1e, 0xf3, 0x00,
+	0x56, 0x93, 0xbf, 0x9d, 0x89, 0xb1, 0x2f, 0x02, 0xf9, 0x6c, 0x38, 0x79,
+	0x40, 0xd8, 0x76, 0x75, 0xc4, 0x5e, 0x7e, 0xde, 0x68, 0x89, 0xbe, 0x88,
+	0xff, 0x6d, 0xe7, 0x02, 0x03, 0x88, 0xb6, 0x43, 0xa9, 0x36, 0x77, 0xe3,
+	0xe7, 0x69, 0x28, 0x55, 0xa6, 0x85, 0x53, 0x69, 0xc0, 0x37, 0x32, 0xac,
+	0x7a, 0x41, 0x76, 0x80, 0x70, 0xf0, 0xa0, 0xd0, 0x7a, 0xce, 0x51, 0x3a,
+	0x4b, 0xb4, 0x5b, 0x83, 0x12, 0x28, 0x1e, 0x09, 0xad, 0xef, 0x45, 0xb2,
+	0xc7, 0x3f, 0x10, 0x9a, 0x3a, 0x2f, 0xd8, 0x4f, 0x39, 0x97, 0xec, 0x5e,
+	0xc8, 0x29, 0x16, 0xae, 0xba, 0x2c, 0xa7, 0x0c, 0x13, 0x5d, 0x7b, 0x89,
+	0xae, 0x97, 0x0c, 0x2d, 0x38, 0x0d, 0x7b, 0xf9, 0x36, 0x83, 0x9f, 0x99,
+	0xd8, 0x5d, 0xb2, 0x43, 0x2e, 0x93, 0x65, 0x05, 0x4b, 0x31, 0x7f, 0x65,
+	0x0f, 0xc7, 0x55, 0x92, 0x11, 0x79, 0x5a, 0xe1, 0xcb, 0x72, 0xad, 0x8d,
+	0xe5, 0x34, 0xe6, 0x93, 0x6b, 0xe1, 0x6f, 0x2c, 0xb8, 0x52, 0x35, 0x26,
+	0x7a, 0xee, 0x1b, 0xa1, 0xf8, 0xa4, 0x4b, 0x14, 0x9b, 0xf4, 0xc4, 0xbc,
+	0xf0, 0x25, 0xde, 0x8f, 0x7b, 0x04, 0xc5, 0xa6, 0x54, 0xb5, 0x19, 0xec,
+	0xfe, 0x20, 0xef, 0x21, 0xfd, 0xa2, 0x67, 0x67, 0x21, 0xe1, 0x7a, 0x97,
+	0x6c, 0xac, 0x8a, 0x62, 0x29, 0x0a, 0x4d, 0xdd, 0x17, 0x29, 0xff, 0xdc,
+	0x10, 0xf3, 0xfc, 0xab, 0x2a, 0x53, 0xba, 0xd2, 0x83, 0xfb, 0xaf, 0x99,
+	0x4d, 0xd4, 0x51, 0x3c, 0x57, 0x71, 0x3a, 0xde, 0x85, 0xe1, 0x52, 0x35,
+	0xd9, 0xdf, 0xd3, 0xe5, 0x3d, 0x7a, 0x53, 0xf7, 0xbb, 0xe9, 0xe5, 0xf0,
+	0x99, 0xf8, 0xf4, 0x60, 0xbb, 0xde, 0x75, 0x93, 0x38, 0xd9, 0xe8, 0x41,
+	0x9c, 0x6d, 0x5c, 0x99, 0x4f, 0xe3, 0xe3, 0x46, 0x5d, 0xa7, 0xdc, 0xd1,
+	0x3c, 0x70, 0x41, 0x34, 0x27, 0xce, 0x0b, 0x81, 0xf3, 0xad, 0x02, 0x67,
+	0xae, 0x8e, 0x24, 0xcf, 0xc0, 0x03, 0xdc, 0x9c, 0x20, 0xfb, 0x68, 0x4a,
+	0xc9, 0xa6, 0x82, 0x6d, 0x69, 0xf6, 0x63, 0xb2, 0xeb, 0x19, 0x3c, 0x74,
+	0xc4, 0xe8, 0x86, 0x35, 0xc7, 0xb6, 0xd3, 0x8a, 0x23, 0x73, 0x3d, 0xb0,
+	0x4a, 0x32, 0x72, 0x01, 0x93, 0xae, 0x48, 0xb9, 0xcd, 0xd6, 0xce, 0x5c,
+	0x7e, 0xab, 0xbb, 0xe2, 0xbb, 0x24, 0x83, 0xec, 0xbd, 0x7e, 0x78, 0x59,
+	0xbf, 0xa7, 0x49, 0x36, 0xad, 0x78, 0xba, 0x14, 0xa5, 0x18, 0x67, 0x90,
+	0x6c, 0x74, 0x8a, 0x13, 0x21, 0xb2, 0x2b, 0x05, 0x5b, 0x27, 0xb4, 0xc3,
+	0x14, 0x0f, 0x46, 0x73, 0x68, 0x47, 0x32, 0xa0, 0x52, 0xce, 0x3e, 0xb5,
+	0xe0, 0xfb, 0xdb, 0xe9, 0xaa, 0x59, 0x49, 0xe0, 0x45, 0x09, 0x68, 0x6b,
+	0x34, 0x23, 0xfb, 0x1a, 0x49, 0x0f, 0xf5, 0x45, 0x0f, 0xee, 0x9b, 0x68,
+	0xc0, 0xbd, 0x53, 0x5e, 0xec, 0x98, 0xb0, 0xf1, 0x7e, 0x8c, 0x6d, 0x42,
+	0xeb, 0x23, 0x6f, 0xea, 0xac, 0x21, 0xd9, 0x6e, 0x8e, 0x45, 0x12, 0x1e,
+	0xe1, 0x42, 0x75, 0xb1, 0x87, 0x72, 0x7f, 0x92, 0xfd, 0xc1, 0xa0, 0x39,
+	0x42, 0xbb, 0x8c, 0xaf, 0x23, 0x15, 0x50, 0xe0, 0x2e, 0xfa, 0x28, 0x86,
+	0xb0, 0xff, 0xf2, 0xb3, 0x6f, 0x60, 0x6b, 0x95, 0x0f, 0x72, 0x46, 0xc1,
+	0x28, 0xe5, 0x7d, 0x2c, 0xab, 0x42, 0x57, 0xb3, 0x44, 0x9f, 0x80, 0x7f,
+	0x76, 0xb2, 0xc9, 0x7f, 0x8c, 0xe2, 0xea, 0x9d, 0x59, 0x89, 0xd7, 0x61,
+	0x9c, 0x40, 0x73, 0xab, 0x78, 0x8c, 0x62, 0xf4, 0x03, 0x14, 0x77, 0x4e,
+	0x94, 0xf2, 0x82, 0xe3, 0x88, 0xc3, 0x4f, 0x96, 0x78, 0xcb, 0x12, 0x6f,
+	0x59, 0xe2, 0x8b, 0xe2, 0xc1, 0x93, 0x59, 0xe6, 0xe3, 0x23, 0xf2, 0xcd,
+	0x04, 0xf1, 0xee, 0xc1, 0x76, 0xa2, 0xf7, 0xfe, 0xa9, 0x1a, 0xdc, 0x43,
+	0xf4, 0x16, 0x0d, 0xad, 0xef, 0x2f, 0x84, 0x8d, 0x7c, 0x4c, 0xb3, 0x76,
+	0x0a, 0x2f, 0xa4, 0x66, 0xdb, 0xee, 0x31, 0x98, 0x67, 0xb2, 0x4f, 0xc9,
+	0xe1, 0x79, 0x5f, 0x92, 0xe4, 0xdf, 0x4f, 0xef, 0x6c, 0x9b, 0xc2, 0xa7,
+	0x12, 0xf1, 0xe4, 0x21, 0x1e, 0x0f, 0x18, 0x5a, 0x62, 0x15, 0xc5, 0xf3,
+	0x73, 0x7a, 0xa4, 0x7c, 0x4e, 0xc6, 0xd7, 0x48, 0x1e, 0x06, 0xcb, 0xa3,
+	0x99, 0xf8, 0xb9, 0x8f, 0x30, 0x8e, 0xdf, 0x64, 0x3e, 0x23, 0xd1, 0x5f,
+	0x10, 0xef, 0x91, 0x62, 0xc0, 0x7f, 0xe6, 0x50, 0x93, 0xff, 0xa5, 0x91,
+	0x0a, 0xfd, 0x3b, 0x89, 0xfe, 0xd9, 0x98, 0x8d, 0x83, 0x44, 0xff, 0x13,
+	0x44, 0x7f, 0x3f, 0xc7, 0xf1, 0x05, 0xfa, 0x4f, 0x94, 0x78, 0xdd, 0x2f,
+	0xe3, 0x61, 0x91, 0xfe, 0x06, 0x6c, 0x9d, 0x5a, 0x94, 0x97, 0x6d, 0xdf,
+	0x66, 0x3c, 0x63, 0xff, 0x1e, 0xc9, 0x6c, 0x79, 0x91, 0xe5, 0xc6, 0xf8,
+	0x2d, 0x72, 0xf8, 0x4e, 0xdc, 0x21, 0xc1, 0xeb, 0xc3, 0x92, 0x22, 0xe7,
+	0x80, 0x10, 0x9e, 0x21, 0xfd, 0x3e, 0x4f, 0x39, 0xec, 0xe9, 0xd2, 0xe5,
+	0x39, 0x8d, 0x75, 0x3d, 0x49, 0x3a, 0xd6, 0x72, 0x16, 0xc5, 0xb4, 0x54,
+	0x29, 0x89, 0x3d, 0x53, 0x48, 0xce, 0x1a, 0x7f, 0x46, 0x81, 0x65, 0x19,
+	0x64, 0xbd, 0x3a, 0xa9, 0xea, 0x5e, 0xdc, 0x3e, 0x13, 0xc0, 0x40, 0x69,
+	0x03, 0xb2, 0x14, 0x67, 0x76, 0x52, 0x5c, 0xfe, 0x30, 0x96, 0xdc, 0xe1,
+	0x47, 0x84, 0xf4, 0x1b, 0xc0, 0xdd, 0xf4, 0xce, 0x81, 0x29, 0xa6, 0x5f,
+	0x5d, 0xd0, 0x73, 0x00, 0x77, 0xd2, 0xbd, 0xbd, 0x53, 0x0a, 0x5e, 0x30,
+	0x8e, 0x10, 0x8e, 0xa9, 0xe0, 0x8a, 0x3b, 0xb2, 0x50, 0xc9, 0x2d, 0x09,
+	0xf7, 0x45, 0xa2, 0x2f, 0xd0, 0xf7, 0xed, 0x25, 0xaf, 0x7f, 0x78, 0x12,
+	0xdf, 0x59, 0x6e, 0xfa, 0xb1, 0x84, 0x30, 0xd8, 0x2d, 0x46, 0xa4, 0xbc,
+	0x9e, 0x30, 0xd3, 0x60, 0x49, 0xc2, 0xb7, 0x67, 0xbc, 0x78, 0x60, 0xe2,
+	0x53, 0xbb, 0x2a, 0xee, 0xc2, 0xcd, 0xcd, 0x5e, 0xdc, 0x3f, 0x93, 0xc4,
+	0xbe, 0x29, 0x84, 0xaa, 0x63, 0x63, 0x14, 0xb3, 0x2b, 0x79, 0xa0, 0x86,
+	0x78, 0xdf, 0x3f, 0xe5, 0xf3, 0xf7, 0x1f, 0x62, 0x19, 0x6c, 0x08, 0x92,
+	0x77, 0x94, 0xab, 0x63, 0x32, 0xb6, 0x1b, 0xf2, 0x92, 0x6a, 0x32, 0xf4,
+	0x23, 0x34, 0xdf, 0x34, 0xe4, 0x57, 0x97, 0x23, 0x72, 0xb8, 0x51, 0x2e,
+	0x8f, 0x2e, 0x41, 0x03, 0x1e, 0x98, 0x4b, 0x62, 0x8c, 0x6c, 0xf4, 0xbe,
+	0x89, 0xe1, 0xef, 0xd4, 0x53, 0xec, 0xf0, 0xb7, 0x69, 0xfd, 0x6f, 0x08,
+	0x13, 0xf9, 0x88, 0x07, 0x3b, 0x67, 0x7c, 0xfe, 0x1d, 0x87, 0xec, 0xf5,
+	0x6c, 0x4f, 0x77, 0xcd, 0x35, 0xe0, 0x9e, 0x29, 0xba, 0x37, 0xc1, 0x36,
+	0x4c, 0xb6, 0x16, 0xa9, 0x26, 0xde, 0xc2, 0x49, 0x0f, 0xe1, 0x24, 0x39,
+	0x56, 0x43, 0xf2, 0xf0, 0xe0, 0x4e, 0xc7, 0x16, 0x54, 0x6c, 0x9f, 0xb2,
+	0xf1, 0x96, 0x11, 0xc5, 0x28, 0xd9, 0xf5, 0xe1, 0x29, 0x6d, 0xbe, 0x93,
+	0x30, 0xce, 0x3b, 0xb2, 0x76, 0xb8, 0x59, 0x4e, 0xa2, 0x61, 0x0d, 0xc5,
+	0xf6, 0x06, 0xdb, 0xbe, 0xa3, 0xad, 0x65, 0xe0, 0xc7, 0x44, 0x73, 0xbd,
+	0xb9, 0x0c, 0xe5, 0x7a, 0x6d, 0x14, 0x68, 0x19, 0xac, 0x92, 0xae, 0xc6,
+	0xd9, 0xa5, 0x1c, 0xff, 0x38, 0x86, 0x07, 0xfc, 0x0d, 0x99, 0x4a, 0x6e,
+	0x6b, 0x28, 0x36, 0xf9, 0xeb, 0x33, 0x41, 0x7f, 0x7d, 0x11, 0xfe, 0xaa,
+	0x22, 0xf0, 0x03, 0x8a, 0x2f, 0x4b, 0xd6, 0xfc, 0xca, 0x4e, 0x35, 0x38,
+	0x38, 0xd0, 0xff, 0xdc, 0xa4, 0x66, 0x95, 0xa1, 0xed, 0xa3, 0x70, 0x89,
+	0x47, 0xe7, 0x5c, 0xfe, 0xe3, 0x14, 0x07, 0x1a, 0xf4, 0x28, 0xf6, 0x92,
+	0x3e, 0x87, 0xc8, 0x16, 0x7e, 0xb1, 0x06, 0xd8, 0x9f, 0x09, 0x87, 0x0c,
+	0xd1, 0x47, 0x13, 0x03, 0xbb, 0x8b, 0x14, 0xeb, 0xa5, 0xdf, 0xa2, 0x40,
+	0xa6, 0x45, 0x29, 0x9d, 0x21, 0x9d, 0x71, 0xc3, 0x5a, 0x5a, 0xd1, 0xc9,
+	0x3d, 0xd9, 0xe7, 0x6d, 0xbf, 0xae, 0xe7, 0x8a, 0xa4, 0xb3, 0x07, 0x4b,
+	0x3e, 0x0c, 0x12, 0x0e, 0x58, 0x42, 0xd8, 0xf1, 0x7e, 0xb2, 0x8b, 0xfb,
+	0x26, 0x64, 0xa2, 0x8f, 0xc7, 0x25, 0x91, 0x5c, 0x56, 0xc1, 0xa0, 0x0f,
+	0xcc, 0xb0, 0x5d, 0x92, 0x1d, 0x91, 0x2d, 0x3e, 0x43, 0xb9, 0xfe, 0xe9,
+	0xcf, 0x61, 0x0f, 0x4d, 0xb5, 0x2e, 0xe5, 0xfc, 0x8a, 0x3c, 0x86, 0xa7,
+	0x98, 0x67, 0xed, 0x30, 0xa4, 0x24, 0x6e, 0x30, 0x7e, 0x42, 0xb9, 0x80,
+	0x79, 0x27, 0xec, 0x3b, 0x15, 0xc5, 0xc3, 0x59, 0xc2, 0x32, 0xb1, 0xf7,
+	0xed, 0x3b, 0x03, 0x2c, 0x03, 0xe6, 0x27, 0x2e, 0x73, 0xde, 0x6c, 0x20,
+	0xcc, 0xfb, 0xff, 0x6f, 0x77, 0xb7, 0xdb, 0x29, 0x07, 0xc3, 0x12, 0xb6,
+	0x26, 0x7b, 0x4a, 0x5d, 0xb2, 0x9f, 0xfb, 0xed, 0xb3, 0x01, 0xce, 0xd3,
+	0x0d, 0x48, 0x5d, 0xb2, 0x05, 0xb6, 0x25, 0x2c, 0x37, 0xda, 0x76, 0xdd,
+	0xaf, 0x82, 0xed, 0x21, 0x7a, 0x99, 0x3d, 0xb8, 0x89, 0x26, 0x15, 0x3b,
+	0xe6, 0xd8, 0x7e, 0xed, 0x8f, 0x96, 0x9b, 0xff, 0x40, 0x39, 0x42, 0x3f,
+	0xfc, 0x13, 0xdc, 0x48, 0xf7, 0x03, 0xf8, 0x36, 0xf9, 0xd1, 0xdd, 0xc4,
+	0xe7, 0x8e, 0xf6, 0xbb, 0x1d, 0xbf, 0xdd, 0x51, 0xba, 0x8e, 0xee, 0xb3,
+	0xbc, 0x3b, 0xb1, 0x2f, 0x6b, 0x20, 0x9d, 0x2d, 0x3b, 0xf9, 0xc7, 0x65,
+	0xc6, 0xf1, 0x7d, 0x8a, 0xb3, 0xcf, 0x94, 0x18, 0x8b, 0x25, 0x1c, 0x1c,
+	0xf6, 0xbd, 0x52, 0x2b, 0x9e, 0x25, 0x9f, 0x7c, 0x9a, 0x62, 0xee, 0x77,
+	0x1d, 0x7c, 0xe6, 0x12, 0x07, 0xd3, 0x84, 0x45, 0x47, 0x2c, 0xa4, 0xf3,
+	0x21, 0x78, 0x0e, 0x85, 0xf7, 0xed, 0x10, 0xda, 0x0f, 0x48, 0x5e, 0xfe,
+	0xfd, 0xb3, 0x2b, 0x50, 0x7d, 0x48, 0xcb, 0x11, 0xdd, 0xfe, 0x87, 0x67,
+	0x75, 0xc2, 0xd2, 0x41, 0xff, 0xde, 0xbc, 0xea, 0xdf, 0x33, 0x19, 0xf0,
+	0xef, 0x99, 0x6d, 0x20, 0x3f, 0x5a, 0xe6, 0x1f, 0x9e, 0x0d, 0xfa, 0x77,
+	0xa5, 0x9b, 0xfc, 0xbb, 0xf2, 0x6b, 0x10, 0x6a, 0x80, 0xb5, 0x8c, 0x72,
+	0xc4, 0x3d, 0x13, 0xdf, 0x44, 0xae, 0xbe, 0x12, 0xf7, 0x07, 0xc8, 0x36,
+	0xea, 0xc8, 0x0e, 0xaf, 0x91, 0x6e, 0x46, 0x79, 0x69, 0xe5, 0xde, 0xb7,
+	0xe9, 0xde, 0x03, 0x6d, 0xf0, 0xff, 0xa5, 0x13, 0x7b, 0x81, 0x67, 0xc9,
+	0xd6, 0x9e, 0x69, 0xa3, 0x7a, 0xf2, 0x92, 0xad, 0xb9, 0x28, 0xde, 0xda,
+	0xb6, 0xb1, 0x46, 0x20, 0xd8, 0xb6, 0x11, 0x58, 0xb2, 0x58, 0x43, 0x26,
+	0x73, 0xae, 0xb6, 0x24, 0x96, 0xeb, 0x9b, 0x70, 0x44, 0xa5, 0x54, 0xd3,
+	0xf6, 0x35, 0x2c, 0xbc, 0x83, 0x6f, 0x4f, 0x78, 0x90, 0xda, 0xa2, 0x62,
+	0x96, 0x30, 0xca, 0x5d, 0x34, 0xff, 0xca, 0x58, 0x8b, 0x3a, 0x47, 0x7a,
+	0x48, 0xaa, 0x7c, 0x8f, 0x7c, 0xa2, 0x6d, 0x2d, 0xf9, 0x44, 0x65, 0xfd,
+	0xa7, 0x48, 0x5f, 0xa3, 0x73, 0x51, 0xec, 0x29, 0xfd, 0x40, 0xaa, 0xe4,
+	0x17, 0x2d, 0x97, 0xc4, 0x69, 0x67, 0xec, 0x53, 0xd9, 0x37, 0xec, 0x90,
+	0x63, 0x77, 0x02, 0x8f, 0xac, 0x8e, 0xec, 0xfb, 0xef, 0x52, 0x23, 0xf1,
+	0x45, 0xb2, 0xcb, 0x3a, 0xf5, 0x63, 0xdd, 0x15, 0xfa, 0xbf, 0xc5, 0xf7,
+	0x55, 0x96, 0xed, 0xa0, 0xd8, 0x47, 0x75, 0x2a, 0x95, 0x4c, 0x75, 0x4b,
+	0xf4, 0x43, 0x78, 0xba, 0x87, 0xef, 0x05, 0xfc, 0xfb, 0x27, 0x93, 0x52,
+	0x40, 0x87, 0xea, 0x36, 0x3b, 0xc5, 0xfe, 0xd9, 0x65, 0xfe, 0x87, 0x27,
+	0x37, 0x8a, 0x87, 0x67, 0x9b, 0xfc, 0xc3, 0xe9, 0x2e, 0x31, 0x9c, 0xdf,
+	0x22, 0xac, 0xdc, 0xb7, 0x84, 0x35, 0x9b, 0x12, 0x56, 0xbe, 0x8f, 0xae,
+	0xbd, 0x62, 0x32, 0x3f, 0x28, 0xf6, 0xe4, 0x79, 0x7e, 0xd2, 0x15, 0xad,
+	0xf1, 0x3d, 0x8a, 0xbd, 0xcf, 0x52, 0xec, 0x7d, 0x86, 0x62, 0xef, 0xd3,
+	0x64, 0xef, 0xdf, 0xbd, 0x84, 0x6d, 0xd9, 0xc6, 0x93, 0x8c, 0x49, 0xfc,
+	0x7f, 0x51, 0x3c, 0x49, 0xfa, 0x66, 0xd9, 0xfd, 0x27, 0xb2, 0x6d, 0x96,
+	0xc9, 0x03, 0x9c, 0x2b, 0x48, 0x4f, 0x17, 0x1d, 0x5b, 0x7e, 0x64, 0x35,
+	0x63, 0xa8, 0x41, 0xb1, 0x95, 0xe8, 0x4b, 0xba, 0x08, 0xfb, 0xe8, 0x84,
+	0x4b, 0xb2, 0x83, 0xe2, 0x8e, 0x3c, 0xdf, 0x3f, 0x80, 0x9d, 0x54, 0x0b,
+	0x1e, 0x8c, 0x85, 0x7b, 0xb6, 0x11, 0x66, 0xda, 0x4c, 0x98, 0x69, 0x65,
+	0x4c, 0xc1, 0x85, 0xd6, 0x4f, 0x6c, 0x2c, 0x45, 0xf2, 0xde, 0xb8, 0x96,
+	0xcb, 0x55, 0xf2, 0xed, 0x68, 0x06, 0x5c, 0xaf, 0xa3, 0xae, 0x56, 0xd7,
+	0x4e, 0x24, 0x11, 0xde, 0x17, 0x97, 0x60, 0x55, 0x99, 0x6e, 0xdc, 0xe3,
+	0xd4, 0x88, 0x1b, 0x30, 0x31, 0x21, 0xb0, 0xbd, 0x2d, 0xf9, 0x87, 0x6e,
+	0x92, 0xd5, 0x3b, 0xed, 0x08, 0x90, 0x7a, 0x85, 0x42, 0xf5, 0x7c, 0x17,
+	0x49, 0xaf, 0x93, 0x72, 0xee, 0x91, 0xec, 0x5a, 0x34, 0xb6, 0x29, 0xa4,
+	0x43, 0x17, 0x6e, 0x2b, 0xde, 0x40, 0x7a, 0x8c, 0x1c, 0x7e, 0x0e, 0x5e,
+	0xff, 0x0b, 0x93, 0x26, 0x46, 0xb2, 0xf8, 0x8e, 0x8f, 0x6a, 0xb7, 0xbb,
+	0x09, 0x37, 0x7d, 0x97, 0x68, 0xd8, 0xd4, 0x16, 0xe9, 0xa2, 0x1a, 0x5e,
+	0xf5, 0x9a, 0x55, 0x18, 0x6f, 0xf6, 0x43, 0xd5, 0x53, 0xe2, 0x95, 0x7c,
+	0xe4, 0xf0, 0x0e, 0xe9, 0x5b, 0xe2, 0xc7, 0xb3, 0x26, 0x1e, 0x2e, 0xf5,
+	0x89, 0xbf, 0x9c, 0x55, 0x40, 0xba, 0xa1, 0xb8, 0x65, 0xe0, 0x30, 0xd1,
+	0xe5, 0x26, 0x9c, 0xe4, 0xfe, 0x1d, 0x81, 0x2b, 0xf4, 0x24, 0xbe, 0xbd,
+	0x96, 0x7d, 0xa1, 0x12, 0xd3, 0x5c, 0x6b, 0x81, 0x7d, 0x64, 0x93, 0x8d,
+	0x99, 0x4e, 0xb1, 0x9c, 0xfe, 0xbf, 0x40, 0x79, 0x2d, 0x29, 0x75, 0x89,
+	0x46, 0xc2, 0xa4, 0x4b, 0xa7, 0x7b, 0xc5, 0x92, 0x22, 0x63, 0x50, 0xa8,
+	0x4b, 0x49, 0x46, 0x4b, 0x8b, 0xe7, 0xe5, 0x0a, 0xf6, 0x77, 0xb3, 0x2d,
+	0x59, 0x3e, 0x53, 0xf1, 0x1f, 0xa4, 0xd8, 0xbe, 0x23, 0xd6, 0x45, 0xf8,
+	0x98, 0xef, 0x0f, 0x8a, 0x11, 0x92, 0x63, 0xce, 0xed, 0xd8, 0x8e, 0xff,
+	0xc8, 0x24, 0xdc, 0x8d, 0x26, 0x42, 0x55, 0x94, 0x3b, 0xfe, 0xe7, 0x9a,
+	0x88, 0xf5, 0x9c, 0xd4, 0x2d, 0x46, 0xf3, 0x01, 0xff, 0xe1, 0x49, 0xce,
+	0x33, 0x9d, 0xe2, 0x30, 0xe9, 0x3c, 0x4b, 0x3a, 0xcf, 0x92, 0xce, 0x33,
+	0xa4, 0xf3, 0xcc, 0x97, 0xe8, 0x7c, 0x2f, 0xe9, 0x7c, 0x57, 0xfe, 0x63,
+	0x47, 0x87, 0x2e, 0xd3, 0x44, 0x96, 0xf2, 0xf2, 0x78, 0x73, 0x85, 0xbf,
+	0x0f, 0x49, 0x16, 0xa7, 0x62, 0x5f, 0x77, 0xc1, 0x6b, 0x52, 0x6c, 0xed,
+	0xa6, 0x77, 0xbe, 0xb2, 0x60, 0xe3, 0xaa, 0x7f, 0x6c, 0xb2, 0x53, 0x8c,
+	0x91, 0xdf, 0x8d, 0xd3, 0xfc, 0xe3, 0xe4, 0x77, 0xc3, 0xe9, 0x7f, 0x8e,
+	0xdd, 0xb0, 0xdd, 0xc1, 0xf2, 0x52, 0xde, 0xaa, 0x21, 0xbb, 0x74, 0x99,
+	0x6c, 0x43, 0x5b, 0x44, 0xf2, 0xe8, 0xb7, 0x44, 0xf2, 0x58, 0x4a, 0x24,
+	0x0b, 0x7d, 0x74, 0xed, 0x15, 0x37, 0x39, 0xf5, 0xe7, 0xa0, 0xe8, 0x2c,
+	0x04, 0xfc, 0x53, 0xb4, 0xce, 0x14, 0xf1, 0xf1, 0x08, 0xad, 0xf3, 0x88,
+	0x63, 0xbb, 0xe3, 0x2e, 0xce, 0xff, 0xcf, 0x67, 0xd9, 0xce, 0xd8, 0xbe,
+	0xde, 0x25, 0xda, 0xd9, 0x37, 0x2e, 0xf5, 0x76, 0xe8, 0xaf, 0x5d, 0x86,
+	0xbe, 0xc3, 0x55, 0xe1, 0x89, 0x73, 0x3f, 0xe7, 0x7a, 0x8e, 0xc3, 0xaa,
+	0x53, 0x03, 0x3e, 0x73, 0x09, 0x03, 0x30, 0x1e, 0x80, 0xb2, 0xc4, 0x7c,
+	0xb0, 0xe3, 0xdb, 0xcd, 0xff, 0x8b, 0xe6, 0x1b, 0x80, 0xb1, 0x16, 0x4a,
+	0xc0, 0xfc, 0x65, 0xc7, 0x64, 0x33, 0xc5, 0x69, 0x9a, 0x53, 0xc9, 0x00,
+	0x7a, 0x46, 0x60, 0x57, 0x42, 0x10, 0x8e, 0x5d, 0x46, 0x7e, 0xc9, 0xf4,
+	0x6b, 0x5d, 0x49, 0x7a, 0xb6, 0x62, 0x04, 0xca, 0x72, 0x73, 0x27, 0xec,
+	0x2c, 0x94, 0x3a, 0xb3, 0x1f, 0x1f, 0x8d, 0x84, 0x83, 0x5d, 0xd0, 0x52,
+	0xe7, 0x64, 0xad, 0x4c, 0xf9, 0x6d, 0x60, 0x97, 0xd0, 0xfa, 0xe7, 0x05,
+	0xf7, 0x87, 0x18, 0xb3, 0xef, 0x44, 0xab, 0x83, 0xdd, 0xfb, 0xd1, 0x92,
+	0x07, 0xd5, 0xdf, 0x84, 0x6b, 0x69, 0xce, 0x97, 0x8c, 0x0f, 0x38, 0x27,
+	0x24, 0x09, 0x0b, 0x7e, 0x61, 0x2e, 0x10, 0x8e, 0xe1, 0x79, 0x78, 0x8e,
+	0xb0, 0xda, 0x4f, 0xf3, 0xbe, 0x25, 0xb7, 0x0c, 0x0c, 0x0b, 0x2d, 0xf1,
+	0xc5, 0xf9, 0x56, 0xe6, 0x21, 0x56, 0x66, 0x2c, 0xbb, 0x46, 0xf7, 0x32,
+	0x1e, 0x92, 0xce, 0xeb, 0x7a, 0xf2, 0x35, 0x84, 0xb0, 0x92, 0xea, 0xe3,
+	0x68, 0x91, 0x79, 0x18, 0xc2, 0x8b, 0x86, 0xd6, 0x43, 0x55, 0x28, 0xd5,
+	0x2b, 0x9d, 0x38, 0x40, 0xb1, 0xf7, 0xe1, 0x12, 0xf7, 0xb7, 0x06, 0xc5,
+	0xaa, 0x11, 0xf2, 0x4b, 0xc7, 0x9e, 0xa0, 0x34, 0x9a, 0x0f, 0xe2, 0x3a,
+	0x5a, 0xdf, 0x4f, 0x35, 0xcf, 0xeb, 0xb4, 0xbe, 0x94, 0xd1, 0x06, 0x69,
+	0xfd, 0xd4, 0x1b, 0x22, 0x3c, 0x4f, 0x7c, 0xf5, 0xad, 0x97, 0x5b, 0xfa,
+	0x87, 0x84, 0x96, 0x24, 0xd2, 0xc9, 0x8f, 0x79, 0xed, 0x07, 0x99, 0x17,
+	0xba, 0x52, 0x7d, 0x43, 0x76, 0xd4, 0x5c, 0x50, 0x44, 0x64, 0x6c, 0x03,
+	0xf6, 0xcc, 0x6c, 0xc0, 0x6e, 0xf2, 0xc7, 0xfd, 0x46, 0x1d, 0x42, 0xf5,
+	0xa8, 0xad, 0xd3, 0x31, 0x7f, 0x4e, 0x17, 0xf2, 0x8e, 0xd6, 0x26, 0xb2,
+	0xe3, 0x93, 0x8d, 0xd5, 0xf8, 0xd8, 0xde, 0xa6, 0x6f, 0xe8, 0xa2, 0x88,
+	0x78, 0x9d, 0x07, 0x87, 0x64, 0xf2, 0xef, 0x37, 0x7f, 0x41, 0x01, 0xd5,
+	0x63, 0x32, 0x6e, 0x4b, 0x88, 0x8b, 0xf9, 0x53, 0xae, 0x8a, 0x1f, 0x34,
+	0xe3, 0x23, 0x15, 0x75, 0x41, 0x7d, 0x15, 0xe6, 0x55, 0x85, 0xe2, 0x85,
+	0xe5, 0xd4, 0x62, 0x37, 0x8e, 0xf6, 0xa0, 0x91, 0xea, 0xe2, 0xdb, 0x62,
+	0xbf, 0xb0, 0x3f, 0xb9, 0x82, 0xdf, 0xfb, 0x23, 0x4f, 0x25, 0x76, 0x7e,
+	0xd9, 0x1c, 0x71, 0x8a, 0x37, 0x2d, 0x54, 0xc7, 0xd6, 0x50, 0x90, 0xee,
+	0xa2, 0x7c, 0xa4, 0xf5, 0xa5, 0xa9, 0x0e, 0xed, 0x8f, 0xb4, 0x18, 0xb2,
+	0xa8, 0x42, 0x39, 0x10, 0x1e, 0xd8, 0x86, 0xe4, 0x5d, 0xfe, 0x05, 0x3a,
+	0x9e, 0x11, 0x2b, 0xdc, 0xf4, 0x1e, 0xcf, 0x73, 0x99, 0x3d, 0xe5, 0xc9,
+	0x9e, 0xf8, 0x39, 0xff, 0x7f, 0xe9, 0xb9, 0xf2, 0x15, 0xf3, 0x97, 0xe6,
+	0xbf, 0x5f, 0xf9, 0x65, 0xf7, 0x03, 0xeb, 0x7e, 0xfd, 0xfe, 0xff, 0xad,
+	0x9e, 0x2f, 0xd7, 0xbb, 0x1c, 0xcc, 0x90, 0x94, 0xb8, 0x7f, 0xe9, 0x32,
+	0x7d, 0x1d, 0xbb, 0xf5, 0xdf, 0xa0, 0x98, 0xc6, 0xfd, 0x0b, 0xce, 0xd3,
+	0x67, 0x9d, 0xfe, 0xc5, 0xf3, 0x9f, 0xc3, 0xac, 0x1c, 0x5b, 0x3c, 0xa2,
+	0x66, 0xdc, 0xb2, 0x1b, 0xf4, 0xdb, 0xa8, 0xae, 0x19, 0xc2, 0xb6, 0x98,
+	0x81, 0xb1, 0xac, 0xd6, 0x73, 0x33, 0xf4, 0xe4, 0x16, 0x41, 0x13, 0x15,
+	0x3d, 0x42, 0x1e, 0x5f, 0x78, 0x66, 0x58, 0x54, 0xab, 0x95, 0x51, 0x4d,
+	0xb1, 0xc9, 0xa5, 0xab, 0x0a, 0x8a, 0x01, 0xc5, 0x55, 0x0c, 0x2a, 0x55,
+	0xc5, 0x26, 0xa5, 0x9a, 0xc6, 0xf9, 0xc6, 0xb5, 0xf9, 0x9b, 0x31, 0x84,
+	0xf9, 0x35, 0x5e, 0xab, 0xd1, 0xd4, 0xd4, 0x46, 0x79, 0x08, 0xbb, 0x63,
+	0xfc, 0x6e, 0x27, 0xd5, 0x6c, 0x10, 0xf5, 0x19, 0x42, 0xc6, 0xa6, 0xc0,
+	0x9e, 0x76, 0x6d, 0x70, 0x85, 0xa4, 0x77, 0xfd, 0xad, 0x70, 0x29, 0x9e,
+	0x22, 0x84, 0x3f, 0x23, 0xe1, 0x70, 0x3b, 0x3c, 0x9e, 0xb5, 0x5a, 0xff,
+	0x49, 0x31, 0x88, 0x27, 0x62, 0x91, 0x9e, 0xed, 0x22, 0xa4, 0x78, 0xe9,
+	0x99, 0x3b, 0x43, 0xf1, 0x37, 0x63, 0x79, 0xdc, 0x6b, 0xb5, 0xa0, 0x24,
+	0x92, 0xd8, 0xa6, 0xeb, 0xc6, 0x38, 0x14, 0x5a, 0x13, 0xa2, 0x3a, 0xa3,
+	0xcd, 0xbf, 0x45, 0x98, 0xea, 0x93, 0x95, 0x83, 0x68, 0x5b, 0x13, 0xd9,
+	0xd7, 0x27, 0xe9, 0x0a, 0x61, 0x3d, 0xe1, 0xca, 0xf8, 0x70, 0xcd, 0xa1,
+	0xc5, 0x7e, 0x8e, 0x6d, 0x7f, 0x18, 0x2b, 0x93, 0x5e, 0xa0, 0xd4, 0x16,
+	0xa3, 0x8a, 0x8f, 0x70, 0x7d, 0xcb, 0x21, 0xc6, 0x59, 0xb6, 0xbd, 0x23,
+	0x56, 0xfe, 0x9a, 0x17, 0xad, 0xc4, 0x63, 0x0f, 0x66, 0xd2, 0x8c, 0xbb,
+	0x4c, 0x4c, 0x53, 0x4d, 0xa4, 0x8f, 0x34, 0xe1, 0x38, 0xc5, 0xa1, 0xb9,
+	0x34, 0xf7, 0x7d, 0xfa, 0x49, 0xc6, 0x7d, 0x44, 0x7f, 0x2f, 0xd5, 0xc1,
+	0x29, 0x8a, 0x5f, 0x2c, 0xe3, 0x6d, 0x64, 0xf7, 0x50, 0xbc, 0x66, 0xac,
+	0xe3, 0xc6, 0x31, 0x28, 0x1e, 0x73, 0x55, 0xc7, 0x55, 0x87, 0x50, 0x4f,
+	0x79, 0xdf, 0xa4, 0x8a, 0x07, 0xd1, 0x48, 0xc4, 0xb8, 0x80, 0x48, 0xf0,
+	0x25, 0xd2, 0xc7, 0xb0, 0x0e, 0xec, 0x72, 0x6a, 0x6c, 0x17, 0xac, 0x3c,
+	0xd7, 0xcf, 0xf0, 0x54, 0xb7, 0xd7, 0xe3, 0xfc, 0xa8, 0xcb, 0xe9, 0x1d,
+	0x59, 0x54, 0xff, 0xbc, 0x60, 0x68, 0xa9, 0x1c, 0xbd, 0xb7, 0x55, 0xfd,
+	0xd9, 0xde, 0x9a, 0x38, 0x14, 0x8a, 0x69, 0x64, 0x7b, 0x7f, 0xe2, 0x7d,
+	0x8b, 0x6c, 0xf4, 0x96, 0xc9, 0x3f, 0xf5, 0x7e, 0x14, 0xcf, 0x79, 0x3f,
+	0x88, 0xdb, 0x76, 0x82, 0xf0, 0x68, 0x1f, 0xd5, 0xdc, 0x1f, 0x8e, 0x58,
+	0xde, 0x0b, 0x71, 0xee, 0xff, 0xba, 0xf0, 0xdb, 0xf4, 0xfd, 0xb1, 0x11,
+	0x05, 0x9b, 0x0b, 0x8d, 0x70, 0x8f, 0xc9, 0x98, 0x31, 0xae, 0xc7, 0x36,
+	0x55, 0xc2, 0x1d, 0xd1, 0x27, 0xc9, 0x26, 0x25, 0x1a, 0x73, 0x90, 0xbe,
+	0x73, 0x2f, 0xeb, 0x11, 0x6c, 0x57, 0x67, 0xbd, 0xe7, 0xe3, 0x4c, 0x6f,
+	0x88, 0xe9, 0x55, 0x24, 0xfd, 0xeb, 0xd8, 0x7a, 0x33, 0xd7, 0x56, 0xce,
+	0xc7, 0xf3, 0x52, 0x7b, 0x03, 0x8e, 0x8f, 0x36, 0xe2, 0xb9, 0x51, 0xcb,
+	0xf3, 0x5a, 0x7b, 0x14, 0xfd, 0x23, 0x36, 0x5e, 0x36, 0xac, 0xc1, 0x6a,
+	0xb2, 0xf3, 0x04, 0xd5, 0x57, 0xe1, 0x35, 0xdc, 0x43, 0x40, 0x44, 0x46,
+	0x64, 0x80, 0x40, 0xe6, 0xad, 0x14, 0xba, 0x52, 0xb5, 0x54, 0xa7, 0x9d,
+	0x11, 0x76, 0xd5, 0x5d, 0xed, 0x2e, 0xa2, 0x01, 0xd8, 0x58, 0x68, 0x25,
+	0xb9, 0x45, 0xb1, 0x39, 0xa2, 0x60, 0x53, 0xc1, 0xc0, 0x73, 0x69, 0x1f,
+	0x6e, 0x29, 0xc4, 0x09, 0x7b, 0xab, 0x44, 0x7b, 0x02, 0xa5, 0x74, 0x00,
+	0xdf, 0x28, 0x34, 0x91, 0xbc, 0x83, 0xb8, 0xbe, 0x10, 0xc2, 0x89, 0x34,
+	0xe7, 0x6f, 0xd3, 0xb3, 0x35, 0xde, 0x84, 0xae, 0x82, 0x8e, 0xd9, 0x34,
+	0x3c, 0xf7, 0xc5, 0x43, 0xe8, 0x2c, 0x44, 0x51, 0x20, 0x0c, 0xf7, 0x75,
+	0x9a, 0xf3, 0x16, 0xd2, 0x49, 0x6b, 0x21, 0x80, 0x15, 0x11, 0xe0, 0xba,
+	0x82, 0x4f, 0x0c, 0x12, 0xb6, 0x4a, 0x14, 0x1a, 0x70, 0x61, 0x8c, 0xed,
+	0xdc, 0xe8, 0xd8, 0x3d, 0xaa, 0x22, 0x54, 0xc0, 0x35, 0x0a, 0xb0, 0x93,
+	0xaa, 0xc3, 0x54, 0x81, 0xe8, 0x3d, 0xd0, 0x5e, 0xe9, 0xdd, 0xae, 0x2a,
+	0x7c, 0xc6, 0x6f, 0x1d, 0xe9, 0xe9, 0xa3, 0x43, 0xb3, 0xde, 0x4f, 0xe2,
+	0x1c, 0x9b, 0x9a, 0x3a, 0x5e, 0x3f, 0x04, 0x44, 0xa7, 0x98, 0x37, 0x27,
+	0x36, 0x72, 0x3c, 0x6c, 0x55, 0xf0, 0xb7, 0x36, 0xd5, 0xa0, 0xa1, 0x19,
+	0xde, 0x23, 0xd0, 0x7d, 0x44, 0x87, 0x8a, 0x24, 0xad, 0x7d, 0x53, 0xe1,
+	0x7b, 0xf6, 0xd6, 0xa5, 0x41, 0xdc, 0x18, 0xa9, 0xc8, 0xea, 0x0c, 0xe9,
+	0x70, 0x7a, 0xac, 0x11, 0x73, 0x44, 0x83, 0xdb, 0x6c, 0xee, 0x38, 0x36,
+	0x69, 0x63, 0xa3, 0x61, 0x79, 0x5f, 0x6b, 0x5f, 0x85, 0x7b, 0x0f, 0x0d,
+	0x9f, 0xae, 0x22, 0xbd, 0xce, 0x1b, 0xb7, 0xe2, 0xe1, 0x29, 0x5c, 0xd9,
+	0x08, 0x3c, 0x14, 0x04, 0xf7, 0xaa, 0xb5, 0xd0, 0x09, 0x44, 0xba, 0xee,
+	0x43, 0x44, 0xd5, 0x85, 0x66, 0xbc, 0x2c, 0x90, 0xac, 0x31, 0x23, 0xa7,
+	0x6f, 0x02, 0x5e, 0xac, 0x22, 0x0f, 0xbe, 0xa5, 0xe0, 0x22, 0x19, 0x05,
+	0x51, 0x1a, 0xab, 0x82, 0x4c, 0x7e, 0x72, 0x51, 0xc7, 0xc6, 0x3a, 0x92,
+	0xb5, 0x2c, 0x14, 0xd2, 0x73, 0x2b, 0x8e, 0x8d, 0x2c, 0xca, 0xca, 0x87,
+	0x1b, 0x48, 0x86, 0x4f, 0x8c, 0xd8, 0x43, 0x7a, 0x2c, 0x40, 0xb2, 0x56,
+	0x89, 0xbe, 0x45, 0x39, 0xb1, 0xfc, 0x16, 0xe5, 0x74, 0x2b, 0x76, 0xcf,
+	0xb1, 0xdc, 0xfe, 0x5f, 0xe4, 0x35, 0xeb, 0xd8, 0xdd, 0xc6, 0xc9, 0x28,
+	0x1a, 0x0f, 0x5d, 0x92, 0x1d, 0xd3, 0xf7, 0x10, 0xf1, 0xf1, 0x1d, 0xff,
+	0xb5, 0x91, 0xfe, 0xf7, 0x84, 0x8f, 0xe8, 0x51, 0x49, 0x37, 0xef, 0xb9,
+	0x19, 0xbb, 0x93, 0x4c, 0x2e, 0xc9, 0x38, 0x48, 0x32, 0x0e, 0x4e, 0xb1,
+	0xac, 0x9b, 0x48, 0xd6, 0xc0, 0xeb, 0x84, 0xcb, 0xae, 0x8b, 0x45, 0x51,
+	0x7b, 0x48, 0x4b, 0x36, 0xca, 0xe1, 0x44, 0x9d, 0x00, 0x55, 0x25, 0x68,
+	0xad, 0xc5, 0x87, 0x2c, 0x67, 0x83, 0xe4, 0xfc, 0x9d, 0x61, 0xe2, 0x67,
+	0x03, 0xcd, 0xb7, 0x91, 0xe4, 0x9c, 0x24, 0xfe, 0x6f, 0x72, 0xe6, 0x6d,
+	0xa2, 0x79, 0x7b, 0xa9, 0xf6, 0x98, 0xf5, 0x5e, 0x24, 0x7a, 0xa2, 0x9f,
+	0xd1, 0x42, 0x68, 0x3c, 0x12, 0x7c, 0x8f, 0x6a, 0xec, 0xeb, 0x9d, 0x71,
+	0x2a, 0x8d, 0x63, 0xda, 0x7f, 0x5c, 0x2d, 0xe9, 0x5f, 0xd6, 0x67, 0xfe,
+	0x16, 0xb8, 0xe7, 0x60, 0xa1, 0x8f, 0xea, 0x88, 0x5e, 0xaa, 0x95, 0x14,
+	0xca, 0x6d, 0x16, 0xbe, 0x1b, 0xd7, 0xa2, 0xf5, 0x82, 0xe3, 0x9f, 0x45,
+	0x7e, 0x58, 0xa6, 0x3a, 0x29, 0x1c, 0x9a, 0x43, 0x50, 0x91, 0x8a, 0x0a,
+	0xe1, 0xc1, 0x26, 0x45, 0x2e, 0x92, 0xbf, 0x06, 0xfb, 0x08, 0x4f, 0xbb,
+	0xf0, 0x52, 0xde, 0x85, 0x57, 0xd2, 0xbd, 0xd8, 0x5f, 0xf2, 0x10, 0x6e,
+	0xb6, 0x3c, 0xae, 0xb5, 0x7f, 0x56, 0x55, 0x89, 0xc9, 0x2b, 0xd1, 0x3d,
+	0xfe, 0x20, 0x6a, 0x32, 0xae, 0x1e, 0xca, 0xa7, 0xc6, 0x4d, 0x24, 0x97,
+	0x8d, 0x45, 0x7e, 0xde, 0x84, 0x4c, 0x3a, 0x45, 0x18, 0x28, 0x4c, 0x35,
+	0x90, 0x0b, 0xb9, 0xc6, 0x26, 0xa7, 0x9f, 0x3b, 0x4a, 0xf7, 0x46, 0x4b,
+	0x5f, 0xec, 0x33, 0xdf, 0xba, 0xd0, 0x5f, 0xee, 0xc7, 0xde, 0x6c, 0x1f,
+	0x61, 0xd3, 0x5e, 0x8a, 0xef, 0x15, 0x1a, 0x67, 0xe3, 0x3d, 0xd8, 0x9b,
+	0x37, 0x2f, 0xc5, 0x8f, 0x69, 0x27, 0x7e, 0x0c, 0xa0, 0xba, 0x9d, 0xf7,
+	0xad, 0x7a, 0x71, 0x7b, 0x1a, 0x78, 0x37, 0xcd, 0x7d, 0x44, 0xc2, 0x14,
+	0x94, 0x0f, 0x0e, 0x1a, 0x9c, 0x43, 0x7b, 0xb1, 0x22, 0x6f, 0x23, 0x6f,
+	0xd8, 0x38, 0x6d, 0xe8, 0x94, 0xa3, 0x39, 0x57, 0x0f, 0x0a, 0x9d, 0xf2,
+	0xb3, 0xe5, 0x1a, 0x40, 0xa4, 0x9d, 0x75, 0xf4, 0xe0, 0xc2, 0xfe, 0xd3,
+	0x80, 0xb3, 0xff, 0x34, 0x97, 0x96, 0xf1, 0x04, 0x29, 0xe2, 0xb9, 0x6c,
+	0x38, 0xf4, 0x2e, 0xec, 0x21, 0xd9, 0xd4, 0x12, 0x2e, 0x99, 0xf7, 0x65,
+	0x78, 0x5f, 0x4a, 0xef, 0x59, 0x21, 0x6b, 0x46, 0x51, 0xb4, 0xf4, 0xbd,
+	0x8d, 0xf2, 0x26, 0x05, 0x5a, 0xe8, 0x35, 0x44, 0xa2, 0x5d, 0xbc, 0xf7,
+	0x50, 0xaa, 0xe4, 0xee, 0x95, 0x0b, 0xb9, 0x5b, 0xcf, 0x7b, 0x45, 0x78,
+	0x4c, 0x42, 0x6e, 0xc6, 0xb6, 0x24, 0xb2, 0xdf, 0x19, 0x9a, 0xf3, 0x07,
+	0xd9, 0x21, 0x64, 0x63, 0xb6, 0x7d, 0x4b, 0x5c, 0xef, 0x6f, 0x94, 0xf1,
+	0xfb, 0x94, 0xc9, 0x41, 0x36, 0x9f, 0x22, 0x5f, 0x0b, 0xed, 0x68, 0xb7,
+	0xec, 0x2a, 0xa7, 0xae, 0xe0, 0xbe, 0x64, 0xb7, 0x68, 0x2d, 0xf4, 0x8a,
+	0x55, 0x84, 0xdd, 0x42, 0xc7, 0xb6, 0x88, 0xe6, 0xa3, 0x15, 0xec, 0x16,
+	0x29, 0x7c, 0xd6, 0x3b, 0xbd, 0x31, 0x6d, 0x23, 0x4d, 0x7c, 0x3d, 0xf1,
+	0x6b, 0x7c, 0xb1, 0x2e, 0x06, 0x70, 0x55, 0x3b, 0xfb, 0xe2, 0x83, 0x38,
+	0x96, 0x66, 0x3b, 0x1f, 0xc0, 0x6e, 0x92, 0xcf, 0xea, 0x11, 0xde, 0x07,
+	0xd3, 0x4e, 0x0f, 0x23, 0xdc, 0xff, 0xaa, 0xd0, 0xca, 0x05, 0xb4, 0x18,
+	0xb5, 0x32, 0xc7, 0x57, 0x6d, 0xb0, 0x59, 0xae, 0xd0, 0x9f, 0xc8, 0x83,
+	0xe2, 0x69, 0x85, 0x87, 0x6b, 0xf2, 0x2b, 0xc8, 0x56, 0x2d, 0xcf, 0xc5,
+	0x78, 0xcb, 0x40, 0x0d, 0x36, 0x8a, 0x0f, 0x66, 0x43, 0xf0, 0x1e, 0x4a,
+	0x2e, 0xf5, 0xa3, 0x53, 0xbc, 0xeb, 0xd4, 0x8b, 0x5d, 0xe2, 0x7c, 0xbe,
+	0x47, 0xbc, 0x9f, 0xeb, 0x46, 0x64, 0xec, 0x1e, 0xf1, 0x4e, 0x8e, 0xe9,
+	0xec, 0x13, 0x67, 0x67, 0xb9, 0x3f, 0x6a, 0x63, 0xb7, 0xc1, 0xbd, 0xd1,
+	0xa5, 0xd5, 0xf0, 0xdb, 0x38, 0x66, 0xb0, 0x3e, 0xb9, 0x4f, 0x58, 0xe9,
+	0x2f, 0x6d, 0x8c, 0x8f, 0xda, 0x2e, 0x9d, 0x7b, 0xc4, 0x41, 0x87, 0xdf,
+	0x19, 0xc2, 0xd1, 0xb3, 0xb9, 0x5e, 0x71, 0x3c, 0x5f, 0xe1, 0x75, 0x3a,
+	0xcf, 0xf6, 0xab, 0x90, 0x8e, 0xbf, 0x98, 0xa7, 0x2d, 0xa8, 0xed, 0x41,
+	0x54, 0x39, 0xfd, 0x28, 0x1b, 0xe3, 0x46, 0x24, 0xf4, 0x32, 0x82, 0x70,
+	0x15, 0xd9, 0xb6, 0x6d, 0x3c, 0x65, 0xb8, 0x21, 0x8f, 0x2b, 0x24, 0x23,
+	0xb2, 0x25, 0xbf, 0x1b, 0xd2, 0x34, 0xd7, 0x06, 0xeb, 0xab, 0xb9, 0x4f,
+	0x11, 0x92, 0xf8, 0xff, 0x2f, 0xda, 0x9c, 0x9b, 0xf2, 0x01, 0xf7, 0xd5,
+	0xdf, 0xac, 0xaa, 0xd8, 0x5e, 0xa5, 0xb7, 0xeb, 0x31, 0xb9, 0xf7, 0xed,
+	0xac, 0xe7, 0x59, 0xd9, 0xee, 0xc1, 0x3b, 0xa3, 0x55, 0xdc, 0xa2, 0x50,
+	0x6a, 0x28, 0xbe, 0xdd, 0x7d, 0xc8, 0xa6, 0xdc, 0x02, 0x4f, 0xb4, 0xfd,
+	0x4d, 0xfb, 0x00, 0xe5, 0x1d, 0xb7, 0x9e, 0xa0, 0x7c, 0xc5, 0x7b, 0x2d,
+	0xb7, 0x62, 0x7e, 0xd2, 0x25, 0xa9, 0x26, 0xe2, 0x14, 0xf3, 0xec, 0xba,
+	0x35, 0x91, 0x81, 0x8f, 0xc9, 0x36, 0x32, 0xc4, 0xd3, 0x07, 0xa3, 0x21,
+	0xe4, 0xa9, 0x0e, 0xb3, 0x9c, 0x9a, 0xe3, 0xb7, 0x71, 0x6e, 0x54, 0x16,
+	0x3e, 0x13, 0xf2, 0x70, 0xbb, 0x8d, 0x21, 0x23, 0x72, 0xfa, 0x2d, 0x59,
+	0xa1, 0x79, 0x5c, 0x78, 0x34, 0x5f, 0x0f, 0x3f, 0xc5, 0x52, 0x69, 0x6c,
+	0x38, 0xe5, 0xa6, 0xb8, 0xf9, 0xe3, 0xd8, 0x70, 0x50, 0xa5, 0xeb, 0x6d,
+	0x06, 0x4e, 0x11, 0xb4, 0xf9, 0xd1, 0x72, 0xf0, 0x1e, 0x60, 0x64, 0xe0,
+	0xbd, 0x4a, 0xbc, 0xb4, 0x5e, 0x13, 0x6f, 0xda, 0xa3, 0xf9, 0x06, 0xc8,
+	0x63, 0x71, 0x7c, 0x92, 0xf6, 0x89, 0xf5, 0x23, 0xbc, 0xd7, 0xa7, 0x95,
+	0xbb, 0x11, 0x1e, 0x58, 0x2f, 0x63, 0x28, 0x88, 0x48, 0xdf, 0x79, 0xaa,
+	0x03, 0x5f, 0x8a, 0x59, 0xfd, 0x3e, 0x8a, 0xb7, 0xdb, 0x09, 0x6b, 0x3e,
+	0x2e, 0x42, 0x94, 0x9f, 0x58, 0x5e, 0x51, 0xa8, 0x11, 0x85, 0xe4, 0xc8,
+	0xfb, 0x41, 0x16, 0xde, 0x76, 0x64, 0xe6, 0xc1, 0xde, 0x1c, 0xd9, 0x89,
+	0xf4, 0xc5, 0xbe, 0xfd, 0x1f, 0x55, 0xc3, 0xdb, 0xc0, 0x72, 0x5a, 0xe8,
+	0xfb, 0x2d, 0xe2, 0x7d, 0x96, 0x11, 0x63, 0xfe, 0x4a, 0x3d, 0x50, 0x65,
+	0xd6, 0x88, 0x17, 0x46, 0x59, 0x2f, 0x36, 0x9e, 0x36, 0x0c, 0xa6, 0x85,
+	0xea, 0xd6, 0xdf, 0x27, 0x8c, 0xaf, 0x59, 0x0c, 0x95, 0x5f, 0x8a, 0x2b,
+	0x38, 0x31, 0x8a, 0xdf, 0x52, 0x20, 0x37, 0x57, 0xe3, 0x08, 0x15, 0x13,
+	0x2c, 0x3f, 0xb6, 0x37, 0xa3, 0x23, 0x92, 0x83, 0x55, 0x6b, 0x76, 0x21,
+	0xe7, 0xd8, 0x79, 0x8d, 0xb8, 0x9f, 0x64, 0x16, 0x69, 0x23, 0x8c, 0xa9,
+	0x72, 0x2f, 0xc5, 0xa2, 0x58, 0xaf, 0xe0, 0xb6, 0x51, 0xbc, 0xbe, 0x1c,
+	0xf2, 0xa9, 0x46, 0x1c, 0x03, 0xaa, 0x59, 0x9f, 0xfc, 0x3e, 0xe9, 0xce,
+	0xcf, 0xb8, 0x8e, 0xc7, 0xd5, 0x88, 0x1d, 0x63, 0x49, 0x6c, 0x8e, 0xc9,
+	0x84, 0x93, 0xfb, 0x08, 0xbf, 0xf5, 0x11, 0x3e, 0xb5, 0xed, 0xb1, 0x08,
+	0xeb, 0x94, 0x75, 0x66, 0x79, 0xc3, 0xed, 0xad, 0xb8, 0x77, 0xb2, 0x1e,
+	0xae, 0xb1, 0x06, 0x54, 0x8f, 0x05, 0xb1, 0x9d, 0xe8, 0x3d, 0x62, 0x70,
+	0xbf, 0xcd, 0x3a, 0x2d, 0x41, 0x2b, 0xaf, 0x97, 0xb5, 0x7e, 0x55, 0xb6,
+	0xf1, 0xa4, 0xa1, 0x19, 0x4f, 0x0a, 0x2f, 0xde, 0xa0, 0x5a, 0xf0, 0xe3,
+	0xd8, 0xad, 0xc8, 0xcc, 0x31, 0x9d, 0xcd, 0x1d, 0x57, 0xcf, 0xf2, 0x35,
+	0xda, 0xd1, 0xec, 0x5c, 0x57, 0x2d, 0x5c, 0x43, 0x1d, 0x21, 0xe7, 0xda,
+	0x44, 0xd7, 0xc5, 0x1e, 0xef, 0x7f, 0x74, 0xf3, 0x35, 0x09, 0xfe, 0x9c,
+	0x76, 0x57, 0x6c, 0xf0, 0xdf, 0xc0, 0x72, 0xfa, 0x0f, 0x1f, 0x2d, 0x8c,
+	0x81, 0x52, 0x4f, 0xbc, 0xc7, 0xc6, 0x65, 0xc4, 0xdb, 0xa8, 0xf8, 0x6d,
+	0x60, 0x7d, 0xf4, 0x21, 0x43, 0x71, 0xaf, 0x96, 0xe2, 0xde, 0xf1, 0x76,
+	0x81, 0x1f, 0x45, 0x4c, 0xfc, 0x28, 0xcf, 0x71, 0xd0, 0x85, 0x27, 0xd2,
+	0x5a, 0xc8, 0x12, 0xe1, 0x9e, 0x9d, 0x42, 0x42, 0xb2, 0x91, 0x78, 0xa3,
+	0x98, 0x3c, 0x9b, 0xe6, 0x18, 0xec, 0x72, 0xf6, 0xd8, 0xb9, 0xde, 0x48,
+	0x2c, 0xc4, 0xcc, 0x52, 0x5c, 0xb3, 0xfa, 0x28, 0x37, 0x7c, 0x5c, 0xe0,
+	0x39, 0x2d, 0xbc, 0x15, 0x67, 0x79, 0x69, 0xd1, 0x94, 0x74, 0x37, 0x92,
+	0x39, 0xf6, 0x4b, 0x5a, 0x8e, 0xd6, 0x3a, 0x92, 0xad, 0x42, 0x6f, 0xbc,
+	0x5b, 0xdc, 0x56, 0xbc, 0x85, 0xfb, 0xf9, 0xea, 0x12, 0x73, 0x8b, 0xd8,
+	0x30, 0xcd, 0xfd, 0xb8, 0x5e, 0xd1, 0x5b, 0x64, 0x3f, 0x19, 0x14, 0xbf,
+	0x53, 0xbc, 0xbc, 0x37, 0xb7, 0x68, 0x17, 0xdc, 0x93, 0xb3, 0x3c, 0x2f,
+	0x90, 0x5e, 0xee, 0x1f, 0xc5, 0x1f, 0xd7, 0x43, 0xa6, 0x98, 0xd6, 0x8e,
+	0x72, 0xa5, 0xf6, 0xa1, 0xfb, 0x5f, 0xc1, 0x10, 0xe5, 0x57, 0x69, 0x41,
+	0xbf, 0x2b, 0x72, 0x12, 0x3e, 0x59, 0xb3, 0xdf, 0x0e, 0x2d, 0x61, 0xfd,
+	0x12, 0x6e, 0x24, 0xdd, 0xec, 0xce, 0xee, 0xb1, 0xdf, 0x76, 0x7a, 0x6a,
+	0x6c, 0x8f, 0x4e, 0xc9, 0xc4, 0xba, 0xc6, 0x76, 0xf2, 0xb9, 0xc7, 0x47,
+	0x97, 0x41, 0xd1, 0xb9, 0x17, 0x5f, 0x8b, 0xa8, 0xe3, 0x37, 0x1e, 0x14,
+	0x46, 0x19, 0xaf, 0x18, 0x1d, 0xaf, 0x8f, 0x29, 0xf0, 0xd1, 0xb3, 0xd9,
+	0x98, 0xc0, 0xa9, 0xf6, 0xca, 0xfc, 0xcd, 0xb9, 0xab, 0x91, 0x56, 0xbd,
+	0xa8, 0xd3, 0x9b, 0x91, 0x55, 0x7d, 0xb4, 0xee, 0xad, 0x0b, 0x73, 0xfe,
+	0xb8, 0x9a, 0xeb, 0x56, 0xd9, 0xbc, 0xb7, 0xba, 0xa2, 0x0f, 0x45, 0xa9,
+	0xd4, 0x31, 0x8a, 0xe5, 0xa3, 0xb5, 0x0e, 0xb6, 0xf7, 0x62, 0xc7, 0x88,
+	0x4f, 0xbc, 0x92, 0xfe, 0xd7, 0x36, 0xdb, 0xcc, 0x01, 0xb2, 0xe5, 0x2a,
+	0x7d, 0x71, 0xce, 0xd7, 0x9d, 0x77, 0x6b, 0x29, 0x2e, 0x0f, 0x8c, 0x4a,
+	0x08, 0x2c, 0xdc, 0x8f, 0xe7, 0x42, 0x08, 0xb6, 0x09, 0xfa, 0xde, 0x6b,
+	0xe3, 0x0a, 0x05, 0xaa, 0xfe, 0x06, 0x8d, 0x73, 0xd1, 0x55, 0xa1, 0xfa,
+	0xd8, 0xc2, 0xc3, 0xf1, 0x04, 0x2e, 0x10, 0x06, 0xd9, 0x47, 0xf9, 0x72,
+	0x57, 0xda, 0xc4, 0xb9, 0xfc, 0x5f, 0x3b, 0xf3, 0xd4, 0x98, 0x1e, 0x4c,
+	0xe7, 0xbe, 0x48, 0x57, 0x80, 0x68, 0x7d, 0x98, 0x68, 0xe2, 0x67, 0x17,
+	0x9c, 0xda, 0xfa, 0xf9, 0xcb, 0x6a, 0x12, 0x69, 0x9c, 0xfb, 0x31, 0x95,
+	0x38, 0xda, 0x69, 0x28, 0x16, 0xf7, 0xb6, 0xe7, 0x27, 0x2c, 0x9c, 0xbb,
+	0xb6, 0x0e, 0x9f, 0x4c, 0x34, 0xe3, 0xde, 0x51, 0x2f, 0x2e, 0x4e, 0xd8,
+	0xb8, 0x66, 0x0d, 0xee, 0x08, 0x12, 0x8e, 0xa9, 0xa3, 0x78, 0xf1, 0x1a,
+	0xd5, 0x0d, 0x54, 0x53, 0x92, 0xf7, 0x44, 0x12, 0x1b, 0x85, 0x8d, 0x68,
+	0x0c, 0xa9, 0x1b, 0xe2, 0x91, 0xd0, 0x05, 0x7c, 0xc7, 0x26, 0x7d, 0xa8,
+	0xb2, 0xd9, 0x2d, 0x5c, 0xce, 0xde, 0x5c, 0xaf, 0xb3, 0x97, 0x27, 0x4d,
+	0x0f, 0x0a, 0xb9, 0x78, 0xb9, 0xbf, 0x7f, 0x59, 0x0c, 0xe7, 0xb8, 0xcd,
+	0xf5, 0xff, 0xb8, 0xed, 0xd6, 0xb9, 0xcf, 0xb1, 0x45, 0xec, 0xc9, 0x5d,
+	0x8a, 0xeb, 0x97, 0x62, 0xf9, 0xae, 0x85, 0x18, 0x3e, 0x9c, 0x7f, 0xf3,
+	0x0b, 0x18, 0x24, 0xb4, 0xb0, 0x57, 0xc0, 0xb1, 0xdb, 0x23, 0xde, 0x22,
+	0xbf, 0xdb, 0x6b, 0xb0, 0x9f, 0x9d, 0x0c, 0x52, 0x74, 0x85, 0x8b, 0xe4,
+	0x79, 0x3f, 0x9f, 0xcf, 0x08, 0xd8, 0xd8, 0x42, 0x7c, 0x7a, 0x48, 0x8e,
+	0x6b, 0xda, 0xdd, 0xe8, 0xa7, 0x78, 0xee, 0x8e, 0xf9, 0x28, 0x0e, 0xa8,
+	0x78, 0xd5, 0x60, 0x1b, 0xee, 0x59, 0x88, 0xe7, 0xbc, 0x57, 0x55, 0xd9,
+	0x1f, 0xfe, 0x7c, 0xcf, 0x78, 0xd1, 0x36, 0x0d, 0x24, 0x97, 0xc2, 0xfb,
+	0x4e, 0x5c, 0x27, 0xec, 0xad, 0x10, 0xee, 0xde, 0x84, 0xc4, 0x12, 0x8d,
+	0xdb, 0x02, 0x84, 0x5b, 0x2d, 0xfc, 0xd7, 0xf6, 0x7e, 0xdc, 0x33, 0x2e,
+	0xa1, 0x46, 0xe7, 0x3d, 0x1a, 0xb2, 0x83, 0x7a, 0x8e, 0x5f, 0xdd, 0x18,
+	0x1a, 0xf7, 0x88, 0x17, 0xa9, 0x26, 0x39, 0xd2, 0xf3, 0x10, 0x96, 0xb4,
+	0xdd, 0x09, 0x38, 0xb6, 0xc7, 0xff, 0x7f, 0x0b, 0xa9, 0x65, 0xbc, 0x3e,
+	0xf7, 0xa9, 0x04, 0x7c, 0x6d, 0xcc, 0x07, 0xbc, 0xef, 0xd1, 0xfc, 0xdb,
+	0x47, 0x5c, 0xe2, 0x42, 0xfa, 0xa7, 0xf6, 0x89, 0x00, 0xe7, 0x58, 0x7e,
+	0x56, 0x4b, 0xb1, 0x9e, 0xc7, 0xb2, 0x0e, 0x7d, 0x54, 0xd7, 0xf5, 0x63,
+	0x84, 0xe8, 0x3a, 0xe3, 0xcc, 0xf5, 0xbd, 0x05, 0xfa, 0x7d, 0xa2, 0x2e,
+	0xa3, 0x58, 0x41, 0xa2, 0x45, 0xbd, 0xb6, 0x07, 0x75, 0xc5, 0xcb, 0x73,
+	0xd5, 0x5f, 0x29, 0xdc, 0xeb, 0x63, 0xdf, 0xa9, 0x26, 0x5f, 0xf9, 0x79,
+	0x5a, 0xe0, 0xbc, 0x63, 0x7b, 0xdb, 0xd0, 0x9c, 0xa7, 0x1a, 0xda, 0x89,
+	0x21, 0x3c, 0x6e, 0x7d, 0xc5, 0xa6, 0xa5, 0x7e, 0xdc, 0x47, 0xbc, 0xd4,
+	0x12, 0x2f, 0x1f, 0xc6, 0x56, 0xd0, 0x3a, 0x7c, 0x2f, 0xa3, 0x54, 0xec,
+	0x6c, 0x71, 0x2e, 0x2a, 0xc0, 0xfd, 0x5c, 0x2b, 0x45, 0xb0, 0x73, 0x3c,
+	0xd2, 0xe7, 0x93, 0xd8, 0x0e, 0x23, 0xb8, 0x7b, 0xfa, 0x37, 0x3c, 0x54,
+	0x17, 0xd3, 0x5c, 0x41, 0xdc, 0x9e, 0x71, 0x89, 0xb7, 0xa9, 0xd6, 0x78,
+	0x3e, 0x2d, 0x2d, 0x93, 0xf1, 0xac, 0x7d, 0x24, 0x30, 0x84, 0x1b, 0x8c,
+	0x6e, 0xdc, 0x45, 0x36, 0xd8, 0xd9, 0x3c, 0x84, 0x09, 0xb2, 0x81, 0xed,
+	0x0d, 0x54, 0xff, 0xc4, 0x4a, 0xf6, 0xb6, 0x00, 0xcb, 0x51, 0xa0, 0x8b,
+	0xee, 0xd7, 0x53, 0x4d, 0x24, 0xc5, 0xc8, 0xda, 0x1a, 0x04, 0xf9, 0xac,
+	0x36, 0x9a, 0xc4, 0xcf, 0x9d, 0x35, 0xeb, 0xf5, 0xc5, 0xf8, 0xcc, 0x39,
+	0xf6, 0x8b, 0xf4, 0x58, 0x76, 0xb5, 0xae, 0x47, 0x37, 0x49, 0xcd, 0xa3,
+	0x73, 0x64, 0xb3, 0x1b, 0xda, 0x2e, 0x7f, 0x6f, 0x51, 0x46, 0x06, 0xaa,
+	0xda, 0x66, 0xec, 0xb2, 0x3a, 0x0c, 0xb5, 0xed, 0x72, 0xdd, 0x2f, 0xce,
+	0xc1, 0x34, 0x57, 0xe2, 0x5a, 0x48, 0x8a, 0xa8, 0x77, 0xe0, 0x49, 0x5a,
+	0x23, 0x88, 0xad, 0xc5, 0x6e, 0x6c, 0x1b, 0x97, 0x3f, 0xcb, 0xed, 0x7e,
+	0xb6, 0xe5, 0xcf, 0xf8, 0xdf, 0x31, 0x1e, 0xe9, 0xf2, 0x2e, 0xf0, 0x7f,
+	0xd7, 0xf4, 0x67, 0x73, 0x0d, 0x66, 0x38, 0x86, 0xf2, 0x7c, 0x9c, 0x67,
+	0x17, 0xe5, 0x1b, 0xc4, 0x7d, 0xce, 0x7c, 0x5b, 0x3d, 0xec, 0xe3, 0x6e,
+	0xca, 0x95, 0x1b, 0xdb, 0x2c, 0xbc, 0x9a, 0xb8, 0xd7, 0xde, 0xe1, 0xc8,
+	0xa0, 0xc3, 0xc3, 0xef, 0x77, 0x35, 0x9f, 0x5e, 0xd8, 0x43, 0xaf, 0xf4,
+	0x30, 0x9f, 0x2f, 0xb5, 0x3a, 0xfd, 0xf9, 0xef, 0x51, 0x7e, 0x7c, 0xf6,
+	0x73, 0x3d, 0xb2, 0x3b, 0xdd, 0xdc, 0xd7, 0x7f, 0xaa, 0xa4, 0x08, 0xd7,
+	0x78, 0x8d, 0x70, 0x8f, 0x33, 0x6d, 0xff, 0x45, 0xa9, 0xf8, 0xd8, 0x5f,
+	0x23, 0x19, 0xe0, 0x3d, 0xba, 0x8a, 0xfd, 0x47, 0xdb, 0xef, 0x06, 0x8e,
+	0x5a, 0x9e, 0xea, 0xb5, 0xa0, 0x3a, 0xb9, 0xc7, 0xb1, 0x87, 0xa5, 0x66,
+	0x7c, 0xdd, 0xb3, 0xcd, 0x5c, 0x2b, 0x73, 0x5f, 0xad, 0x73, 0xdd, 0x24,
+	0x81, 0xb7, 0xad, 0x2a, 0xaf, 0xa9, 0x9d, 0xe0, 0x5e, 0x37, 0xf7, 0xc0,
+	0x97, 0xeb, 0xf0, 0xd6, 0xaf, 0xb5, 0x3c, 0x4b, 0xd6, 0xba, 0xc4, 0x15,
+	0x99, 0x3e, 0xb2, 0x3d, 0x1d, 0x89, 0x8c, 0xe5, 0x6d, 0x5c, 0x1b, 0xc2,
+	0x03, 0x99, 0x4a, 0x0c, 0x5b, 0x9f, 0x6b, 0x45, 0xeb, 0x14, 0x59, 0x63,
+	0x26, 0x88, 0x96, 0x89, 0xf0, 0xc0, 0xd7, 0xa5, 0xf0, 0xe0, 0xbc, 0xc4,
+	0xcf, 0x7c, 0x1d, 0xd7, 0x38, 0x38, 0x56, 0xed, 0x58, 0xed, 0x5c, 0xe3,
+	0x1d, 0x57, 0xe7, 0x6f, 0x45, 0x7a, 0xce, 0x33, 0x5f, 0x96, 0x6c, 0x3c,
+	0x10, 0x93, 0x70, 0xa3, 0xf1, 0x9f, 0xc9, 0xb7, 0x04, 0xd9, 0xc6, 0xab,
+	0x9c, 0x9f, 0x9d, 0xe0, 0xbc, 0x7c, 0xad, 0x8e, 0xb5, 0x99, 0x7a, 0x8a,
+	0x49, 0x0d, 0x14, 0x9f, 0xea, 0xf1, 0x11, 0xc5, 0xa4, 0xd5, 0x6b, 0x28,
+	0x3c, 0xae, 0xb1, 0xfa, 0xaf, 0x00, 0xef, 0xdf, 0x6a, 0x56, 0x51, 0x68,
+	0x7d, 0xdd, 0x92, 0xd6, 0xd3, 0x20, 0xa9, 0xb8, 0x2b, 0xc2, 0x73, 0x27,
+	0x3a, 0xd6, 0xe6, 0x2b, 0xf9, 0x74, 0x95, 0x93, 0x3f, 0xf5, 0x8e, 0xab,
+	0x66, 0x2b, 0x79, 0xd6, 0x98, 0xd5, 0x7e, 0x90, 0x92, 0x78, 0xcf, 0xa1,
+	0x0f, 0xe3, 0xd9, 0x14, 0xf6, 0x64, 0x43, 0xf8, 0x45, 0xa6, 0x8a, 0x6c,
+	0x23, 0x6c, 0x7c, 0x17, 0x3c, 0xa6, 0xb5, 0x23, 0x96, 0x0f, 0x47, 0x1f,
+	0x90, 0xfe, 0x1c, 0x65, 0x97, 0x76, 0x98, 0x10, 0x36, 0x72, 0xae, 0x96,
+	0xd0, 0x4b, 0xf8, 0x73, 0x67, 0x8f, 0x0a, 0xa8, 0xf0, 0xd0, 0x9c, 0x07,
+	0x46, 0x33, 0x9e, 0x79, 0x38, 0xfd, 0x4c, 0xde, 0x73, 0x95, 0xb0, 0xc1,
+	0xb8, 0x97, 0xe4, 0x2c, 0xd0, 0xdc, 0x56, 0x8f, 0x72, 0xaf, 0x0b, 0xe3,
+	0x24, 0x13, 0xc5, 0x0c, 0x74, 0x28, 0x23, 0x28, 0x2f, 0xec, 0x27, 0x26,
+	0x64, 0xca, 0xd0, 0x2f, 0x17, 0x81, 0x03, 0x14, 0x3b, 0x36, 0xc7, 0x7e,
+	0x45, 0xb9, 0xa1, 0xb2, 0x7f, 0x91, 0x9e, 0x14, 0x58, 0xa2, 0x27, 0x49,
+	0x1e, 0x2e, 0xff, 0x41, 0xaa, 0xef, 0x0f, 0x96, 0xf8, 0x7d, 0xcf, 0x7c,
+	0xd2, 0x99, 0x3f, 0xb2, 0x6f, 0x85, 0x24, 0xe1, 0xea, 0xb6, 0xa3, 0xc8,
+	0x2d, 0xad, 0xd0, 0x10, 0x24, 0x4c, 0xc0, 0x75, 0x60, 0x03, 0xf1, 0xb8,
+	0xe5, 0x11, 0xee, 0x09, 0x5e, 0xd9, 0x71, 0xdd, 0x14, 0xfb, 0x75, 0xa0,
+	0xe3, 0xe7, 0x69, 0x2d, 0xd9, 0x20, 0x33, 0xae, 0x4c, 0x74, 0xdc, 0x3d,
+	0xc2, 0xb9, 0xad, 0x8d, 0x6b, 0x71, 0xca, 0xcb, 0xda, 0x60, 0xa3, 0xf0,
+	0x89, 0x1b, 0x33, 0x54, 0x8f, 0x13, 0xbd, 0xef, 0x47, 0xb4, 0x20, 0xc9,
+	0xae, 0xeb, 0x4e, 0xd1, 0xcf, 0x78, 0xdf, 0x91, 0xdb, 0x55, 0xf9, 0x0a,
+	0xee, 0x08, 0x2f, 0xe0, 0x90, 0xa8, 0x83, 0x3b, 0x6c, 0x7b, 0x77, 0x8c,
+	0xf3, 0xb8, 0xb3, 0x9f, 0x4e, 0xf7, 0x63, 0x94, 0x77, 0x15, 0x0c, 0x33,
+	0x7d, 0x7c, 0x2e, 0x42, 0xa2, 0x3a, 0x2e, 0x7b, 0x7a, 0x01, 0x97, 0xf8,
+	0xb0, 0x97, 0xee, 0x97, 0x1d, 0x7c, 0xc2, 0x67, 0xfb, 0x56, 0x75, 0xa8,
+	0x8f, 0xf0, 0x79, 0xc0, 0x2b, 0x3b, 0x36, 0x4c, 0x6a, 0x21, 0x89, 0xf8,
+	0xd8, 0xc3, 0x7b, 0xdb, 0x34, 0xe7, 0xac, 0xc1, 0x74, 0xfb, 0x3a, 0xb8,
+	0x97, 0xb9, 0x9c, 0xe8, 0xb6, 0xb3, 0x61, 0xc2, 0x49, 0x15, 0x5b, 0x49,
+	0xe4, 0xa9, 0x22, 0xbe, 0xa2, 0xc2, 0xab, 0x9b, 0x74, 0x72, 0x2c, 0x9d,
+	0xc4, 0xf3, 0xf1, 0x8a, 0x7e, 0xd6, 0xe7, 0xbf, 0x81, 0x54, 0x43, 0x27,
+	0x46, 0xb3, 0xaa, 0x7f, 0x63, 0xa6, 0x13, 0x13, 0xa4, 0xc3, 0x3b, 0x8a,
+	0x41, 0x7f, 0x67, 0x46, 0xc7, 0xb6, 0x22, 0xd7, 0x26, 0xa1, 0x8e, 0xdd,
+	0x93, 0xb9, 0x85, 0x1a, 0xb2, 0x92, 0x4b, 0xf6, 0x67, 0x2a, 0x36, 0x17,
+	0xce, 0x7b, 0xe6, 0x43, 0xa2, 0x32, 0xaf, 0x42, 0xeb, 0x28, 0x23, 0x7f,
+	0x6c, 0x63, 0x29, 0xdb, 0xc2, 0xad, 0x98, 0x9c, 0xf2, 0x5b, 0x57, 0x98,
+	0x2a, 0xd6, 0xb6, 0xbd, 0x41, 0xef, 0xb6, 0xe2, 0x97, 0xc7, 0xbf, 0x86,
+	0xf2, 0x37, 0x5d, 0x78, 0x3c, 0x93, 0x44, 0x4b, 0xdb, 0x4d, 0x48, 0xfd,
+	0xae, 0x82, 0xa7, 0x32, 0x3e, 0x3c, 0x97, 0xa9, 0xec, 0x77, 0x7f, 0x3f,
+	0x4b, 0x7e, 0x48, 0x3e, 0xf0, 0xec, 0x97, 0xee, 0x31, 0x52, 0x3c, 0x97,
+	0x79, 0xff, 0xfb, 0x9f, 0x1e, 0x77, 0xd6, 0x19, 0xe7, 0x11, 0xf5, 0xe3,
+	0x8b, 0xf3, 0xda, 0xd0, 0xdb, 0xfe, 0xb1, 0x77, 0xb4, 0x28, 0x40, 0x31,
+	0xa4, 0x72, 0x3e, 0x40, 0x28, 0xe3, 0xce, 0x9e, 0x0b, 0xe1, 0xdf, 0x88,
+	0x71, 0x0e, 0x16, 0xaa, 0x08, 0x57, 0xad, 0x20, 0x59, 0xe8, 0x99, 0x80,
+	0x5f, 0x2a, 0xaa, 0xf4, 0x69, 0xf2, 0xbb, 0x48, 0x3e, 0xae, 0xe2, 0x0f,
+	0x29, 0xa6, 0xb0, 0x4f, 0x55, 0x72, 0x9c, 0x54, 0xdc, 0xec, 0x85, 0x57,
+	0xa7, 0x6b, 0xc5, 0xa6, 0x43, 0xf9, 0xb7, 0xf9, 0x39, 0xd9, 0x75, 0xe5,
+	0x7b, 0xe4, 0xd2, 0x77, 0xd2, 0xb3, 0x23, 0xb3, 0xdb, 0x68, 0x3c, 0xcb,
+	0xe2, 0x59, 0x3b, 0xb5, 0x85, 0xe5, 0x15, 0xf0, 0xbf, 0x41, 0xf2, 0x9f,
+	0x24, 0x1a, 0xb3, 0xb4, 0xc6, 0xeb, 0xb4, 0x66, 0xa6, 0xd8, 0x47, 0x63,
+	0xf8, 0x19, 0xc9, 0xd9, 0xb1, 0xdd, 0xad, 0x5e, 0xde, 0xdb, 0x7f, 0x2e,
+	0x03, 0xaa, 0xbb, 0x2d, 0xcd, 0xb5, 0x70, 0x16, 0x72, 0x18, 0x8b, 0xf8,
+	0xf1, 0x2e, 0x5c, 0x3f, 0xaa, 0x25, 0x2d, 0xc2, 0x61, 0x29, 0x15, 0xc2,
+	0x65, 0xb2, 0x0d, 0xc7, 0xc9, 0x86, 0x9b, 0x88, 0xa7, 0x70, 0xe8, 0x1c,
+	0x8d, 0xb7, 0x5c, 0x0a, 0xf6, 0x4f, 0xc8, 0x38, 0xc7, 0xfb, 0xaf, 0xa2,
+	0xf2, 0x3e, 0x01, 0x7f, 0x1a, 0xbb, 0xf8, 0x7f, 0x0d, 0xe1, 0xf2, 0x70,
+	0x82, 0xb2, 0x2a, 0xe3, 0x5b, 0x4f, 0xbe, 0xfd, 0x21, 0x1c, 0xa4, 0x3a,
+	0x79, 0x47, 0x2c, 0x84, 0x64, 0x7d, 0x1c, 0x1e, 0xbd, 0x65, 0xe0, 0x22,
+	0xfe, 0x87, 0x5d, 0xe6, 0x3d, 0x6c, 0x11, 0x4e, 0x5c, 0xc4, 0xa7, 0xb6,
+	0xac, 0xeb, 0xa7, 0x67, 0xa0, 0x97, 0xcf, 0xa1, 0x65, 0xf0, 0x13, 0xbc,
+	0x6b, 0xf3, 0xfe, 0xb6, 0x22, 0xcb, 0x78, 0xd1, 0x08, 0xab, 0x2e, 0x04,
+	0x50, 0x0e, 0xc8, 0xd8, 0x6c, 0x30, 0xfe, 0xd7, 0x06, 0x1f, 0x83, 0x36,
+	0x70, 0x5e, 0xb4, 0xf4, 0x7f, 0x88, 0xb3, 0x76, 0xae, 0x9e, 0xd7, 0x15,
+	0x48, 0x5c, 0xdd, 0x72, 0xba, 0x0a, 0x5a, 0x97, 0x5b, 0xe8, 0x89, 0x46,
+	0xf9, 0xaf, 0xec, 0xb3, 0x81, 0x4f, 0x6d, 0x3d, 0xf2, 0x29, 0xe1, 0x20,
+	0x3d, 0x38, 0x4d, 0xb6, 0xdf, 0x8f, 0x45, 0xda, 0x5e, 0x27, 0xfe, 0xa9,
+	0xb0, 0xd3, 0x79, 0x9f, 0xc8, 0xf2, 0xec, 0x25, 0xda, 0x5e, 0x23, 0x1c,
+	0xb0, 0x23, 0x76, 0xd1, 0x4e, 0x2e, 0xe5, 0x1a, 0xe9, 0x67, 0xde, 0x4a,
+	0xff, 0x98, 0x7b, 0x0e, 0xb7, 0xe2, 0x76, 0xc2, 0x77, 0xc3, 0xd9, 0x45,
+	0xbc, 0xe6, 0xa6, 0x18, 0xcc, 0xb1, 0xbf, 0x7c, 0x15, 0x95, 0xd4, 0x12,
+	0x95, 0xc7, 0xd8, 0x4d, 0x71, 0x61, 0x97, 0x93, 0x0b, 0xe0, 0x5d, 0xbe,
+	0xb6, 0x0d, 0x9f, 0x4c, 0x95, 0xbc, 0xe4, 0x4b, 0xeb, 0xf5, 0x35, 0x10,
+	0xc1, 0x8c, 0x25, 0xea, 0x4c, 0x19, 0x1f, 0xb6, 0x6b, 0x5d, 0x92, 0x3c,
+	0x88, 0xab, 0x63, 0x96, 0xed, 0xd3, 0xf5, 0xbe, 0x56, 0x11, 0xe9, 0x29,
+	0x8a, 0x28, 0x6a, 0x8a, 0x3e, 0xa5, 0xa6, 0xd8, 0xaa, 0x78, 0x8b, 0x96,
+	0x47, 0x5d, 0x7b, 0x17, 0xd5, 0xb4, 0x43, 0x58, 0x19, 0xf3, 0x51, 0x3d,
+	0xac, 0x19, 0x17, 0x50, 0x45, 0xf2, 0x0f, 0x61, 0x6f, 0xc9, 0x84, 0x2b,
+	0xb3, 0x13, 0xee, 0x4c, 0x58, 0xdd, 0x83, 0x21, 0x24, 0x83, 0x15, 0x4c,
+	0xab, 0x90, 0xae, 0xaa, 0xdb, 0x19, 0xcb, 0xdc, 0x85, 0xb3, 0x39, 0xc6,
+	0xe7, 0x54, 0x9f, 0xa6, 0xf9, 0x3b, 0xbc, 0x2f, 0xc5, 0x4d, 0x3c, 0x49,
+	0x75, 0x95, 0xa7, 0xad, 0x91, 0xf4, 0xd0, 0x84, 0xe1, 0x92, 0x60, 0xb3,
+	0x22, 0x5d, 0xc0, 0xfb, 0x64, 0xbb, 0x82, 0x03, 0x33, 0x94, 0x48, 0x28,
+	0x5f, 0xb9, 0x32, 0x2a, 0xc5, 0x09, 0xc6, 0xd8, 0x3e, 0xfa, 0x1e, 0xe0,
+	0x33, 0x3f, 0x64, 0x67, 0x57, 0x76, 0xb4, 0x3a, 0xb1, 0xa6, 0x8d, 0x6a,
+	0x9c, 0xa7, 0xbd, 0x95, 0x9a, 0xcb, 0x44, 0xcd, 0xf8, 0x62, 0xad, 0xb8,
+	0xe1, 0xe6, 0x1a, 0xaa, 0xc5, 0x87, 0x4b, 0x8c, 0x03, 0x2b, 0x67, 0x3c,
+	0x37, 0xc4, 0xda, 0x08, 0xb3, 0x8b, 0x05, 0x8c, 0x35, 0xac, 0xf9, 0xb0,
+	0x1e, 0x07, 0xa9, 0x56, 0xf6, 0xeb, 0x5b, 0x91, 0x51, 0xcb, 0xde, 0x37,
+	0xe3, 0x8c, 0x7f, 0xe1, 0xdd, 0x46, 0x18, 0x6a, 0x24, 0xfd, 0x55, 0x8e,
+	0x99, 0x9e, 0x3b, 0xe2, 0x06, 0x0e, 0x8f, 0x52, 0x88, 0xd2, 0xd7, 0xa3,
+	0x6e, 0x4d, 0x37, 0x3e, 0xac, 0x67, 0xfc, 0x4b, 0xb1, 0x8a, 0xe8, 0xd9,
+	0x33, 0x13, 0x70, 0xce, 0x24, 0xec, 0x2d, 0x2d, 0xd2, 0x7c, 0x39, 0xad,
+	0x5f, 0x46, 0x23, 0xcb, 0xe4, 0x9f, 0xa2, 0x91, 0x6c, 0x96, 0x30, 0xcf,
+	0x68, 0x7a, 0x1b, 0x5e, 0x4e, 0xf3, 0xbc, 0xe1, 0xa4, 0x21, 0x54, 0xee,
+	0x6b, 0x3b, 0x32, 0xb1, 0x66, 0x78, 0x0d, 0x5e, 0x7f, 0x71, 0x9d, 0x00,
+	0xf6, 0x7d, 0xa9, 0x3c, 0xfe, 0x39, 0x6b, 0x51, 0xdc, 0x18, 0x5d, 0x4f,
+	0x75, 0x50, 0x14, 0xfa, 0xef, 0x94, 0x49, 0x1f, 0xdc, 0xe7, 0x5d, 0x41,
+	0x98, 0x17, 0x9e, 0x57, 0xe2, 0x7c, 0xee, 0xd7, 0x1e, 0x52, 0x4c, 0xdb,
+	0x76, 0xb7, 0xeb, 0xea, 0x3b, 0x60, 0x3b, 0xf4, 0xf1, 0x7e, 0x81, 0x67,
+	0x4f, 0xbb, 0x0f, 0x07, 0x28, 0x07, 0x3e, 0x91, 0x6e, 0xb1, 0x6e, 0x12,
+	0x7c, 0x7e, 0x89, 0x62, 0xb6, 0x48, 0xd1, 0xbb, 0x37, 0xd6, 0xb0, 0xcf,
+	0xee, 0x2e, 0xed, 0x84, 0x94, 0x89, 0xd4, 0x70, 0x3d, 0x51, 0x45, 0x35,
+	0xf4, 0x70, 0x9a, 0xe9, 0xb5, 0x87, 0x5c, 0x34, 0xd7, 0xae, 0xb8, 0x3e,
+	0x7f, 0x3d, 0xd9, 0x45, 0xa3, 0xc9, 0x72, 0x0c, 0xe0, 0x08, 0x8d, 0x0d,
+	0x95, 0x58, 0x96, 0x7d, 0x35, 0xdc, 0x33, 0xdc, 0x4b, 0xfa, 0xad, 0xcb,
+	0x56, 0xe6, 0xc9, 0x96, 0xfa, 0xb1, 0x62, 0x64, 0xdc, 0x99, 0x87, 0x7d,
+	0xe0, 0xc5, 0xf8, 0x00, 0xf6, 0xa6, 0x03, 0x98, 0x49, 0xb7, 0xa8, 0x2f,
+	0x38, 0xfb, 0xed, 0x95, 0xfe, 0xd2, 0x70, 0x7a, 0x71, 0x4c, 0x00, 0xd3,
+	0x97, 0xfe, 0x67, 0xf9, 0x54, 0xfa, 0x8e, 0x95, 0x7e, 0x80, 0x82, 0x5c,
+	0xa0, 0x82, 0x87, 0x28, 0x56, 0x78, 0x1f, 0x26, 0xbd, 0x9e, 0x27, 0xbd,
+	0x4a, 0xa4, 0xd7, 0x17, 0x8c, 0xef, 0x33, 0x66, 0xf1, 0xec, 0x8e, 0xfb,
+	0x78, 0x8f, 0xc5, 0x22, 0xd0, 0xe2, 0x8c, 0xc9, 0xc4, 0x5d, 0x38, 0x33,
+	0xc2, 0xe7, 0xf9, 0xd4, 0x8e, 0x53, 0x69, 0x7b, 0xfd, 0x5c, 0xac, 0x25,
+	0x75, 0x9e, 0xf0, 0xb4, 0xf5, 0xbb, 0x9a, 0x71, 0x96, 0xfc, 0x34, 0x3b,
+	0xf1, 0xfb, 0x38, 0x5b, 0xdf, 0xa2, 0xfe, 0x98, 0xca, 0xf9, 0x47, 0xe3,
+	0x0f, 0x21, 0x31, 0x41, 0x75, 0xc3, 0x9a, 0x7f, 0x47, 0x4e, 0x16, 0x87,
+	0xac, 0xb7, 0xcc, 0xbf, 0x80, 0xff, 0x86, 0xb3, 0x57, 0x84, 0x8d, 0x17,
+	0xc0, 0x63, 0x2a, 0xf5, 0x78, 0x78, 0xf6, 0x1e, 0x3e, 0x8b, 0x14, 0xe4,
+	0x5a, 0xdb, 0xd9, 0x0b, 0x4a, 0xf3, 0xde, 0x95, 0x40, 0xae, 0x57, 0x0b,
+	0xa5, 0x9c, 0xb3, 0x9f, 0xf0, 0x3e, 0x46, 0x7e, 0x11, 0x1d, 0xe3, 0xf1,
+	0x81, 0x0e, 0x3d, 0x1f, 0x82, 0x4c, 0x18, 0x27, 0x15, 0xd0, 0xba, 0x80,
+	0xa0, 0xff, 0xb1, 0x74, 0x10, 0xfb, 0xb2, 0x2d, 0x3d, 0x51, 0x71, 0xdb,
+	0xc2, 0x9e, 0x31, 0xe7, 0xb9, 0x00, 0xe5, 0x39, 0x2d, 0xf5, 0x18, 0x5a,
+	0xfa, 0x7c, 0xe2, 0x56, 0xa4, 0xea, 0x5b, 0xfa, 0x9f, 0x44, 0x38, 0xe1,
+	0x11, 0x5a, 0xf4, 0x2c, 0x2a, 0xf3, 0xac, 0xcc, 0xcb, 0x40, 0x03, 0xc7,
+	0x99, 0x34, 0x9e, 0x54, 0x65, 0xac, 0x6a, 0xd3, 0xe7, 0xa7, 0xb1, 0x68,
+	0x2f, 0x95, 0x31, 0xeb, 0xf3, 0x34, 0x5e, 0x56, 0xa9, 0x0e, 0xae, 0x82,
+	0xab, 0x81, 0xf7, 0xe3, 0x76, 0x62, 0x47, 0x9a, 0xf3, 0x34, 0xc9, 0x85,
+	0x7c, 0xb3, 0x27, 0xb2, 0x13, 0x03, 0xf9, 0x00, 0x0e, 0x66, 0xc3, 0xfb,
+	0xf6, 0x10, 0xae, 0x1b, 0x2b, 0x85, 0x43, 0xdb, 0x45, 0x80, 0xf4, 0x2d,
+	0x21, 0xd4, 0x10, 0x44, 0xb5, 0xae, 0xd2, 0xa7, 0x52, 0xcf, 0x9c, 0xa2,
+	0x7a, 0xe6, 0x0c, 0xf9, 0x9a, 0x6f, 0xa1, 0x46, 0x5d, 0x99, 0xb3, 0x31,
+	0x17, 0xdb, 0x84, 0xf7, 0x1d, 0x9d, 0x05, 0xc9, 0xc6, 0x38, 0x17, 0x39,
+	0x35, 0xa8, 0xd8, 0x3e, 0x66, 0x79, 0xee, 0x6f, 0x0f, 0x22, 0x9c, 0x61,
+	0xcc, 0x29, 0x7d, 0x53, 0x26, 0x79, 0xcc, 0xe8, 0x43, 0xd8, 0x18, 0x1b,
+	0xc2, 0x80, 0xf1, 0xc7, 0xa8, 0x6a, 0xe0, 0x78, 0xa4, 0x58, 0x75, 0x34,
+	0xef, 0xc5, 0xf6, 0x6e, 0x84, 0x8f, 0x72, 0x0e, 0x6e, 0xa5, 0x1c, 0xcc,
+	0xbe, 0xcb, 0xf3, 0xdf, 0xdf, 0xb1, 0x9a, 0x70, 0x45, 0x6d, 0x7b, 0x25,
+	0xcf, 0x5f, 0x9d, 0x57, 0xb9, 0x8f, 0x43, 0xb5, 0x29, 0xbc, 0x6f, 0x5f,
+	0x6b, 0xe2, 0x51, 0x8a, 0x31, 0x89, 0x35, 0x6e, 0x60, 0x09, 0x9f, 0xf7,
+	0x15, 0x0b, 0x3d, 0x80, 0x40, 0xc7, 0x8a, 0xbc, 0xc0, 0x6c, 0x9c, 0xec,
+	0xe3, 0xd7, 0xce, 0xf7, 0x84, 0x16, 0xce, 0x63, 0x72, 0xff, 0xe4, 0x90,
+	0x9d, 0xe4, 0x33, 0xfa, 0xd2, 0x3b, 0x64, 0x57, 0x5a, 0xb0, 0x8c, 0x9f,
+	0xd5, 0x70, 0x5c, 0x96, 0xf5, 0x45, 0xb9, 0xb3, 0xac, 0x4f, 0xd8, 0xb9,
+	0x05, 0x5d, 0xb8, 0xe8, 0x9d, 0xdd, 0x93, 0xda, 0xe0, 0x1e, 0xb4, 0x0c,
+	0xfc, 0x5c, 0x54, 0x3b, 0xbb, 0x7f, 0xd3, 0xad, 0x48, 0x2d, 0x37, 0x5d,
+	0xbd, 0x9f, 0x64, 0xd7, 0x13, 0x1d, 0xe7, 0x08, 0x84, 0x6e, 0x70, 0xf6,
+	0x88, 0xa6, 0x5b, 0xff, 0x84, 0xe6, 0xe6, 0xff, 0xbb, 0x7c, 0x7c, 0x5e,
+	0xf1, 0xf9, 0xec, 0x73, 0x76, 0x74, 0x69, 0x45, 0x3e, 0x27, 0xc9, 0xf7,
+	0x83, 0xa6, 0x84, 0x46, 0x3d, 0x32, 0xdf, 0x47, 0xdf, 0xff, 0x26, 0x4f,
+	0x68, 0xff, 0xda, 0x7e, 0xfc, 0x24, 0x67, 0x62, 0x3f, 0xe5, 0x81, 0x3a,
+	0x5d, 0x53, 0x73, 0x08, 0x71, 0x2d, 0xed, 0xf0, 0x7f, 0x4d, 0x8e, 0xfc,
+	0xb0, 0x5e, 0x75, 0x6a, 0x8c, 0x0a, 0x7f, 0x3e, 0xe2, 0xef, 0xb7, 0x7c,
+	0xec, 0x0b, 0x84, 0x91, 0xc8, 0x66, 0x52, 0x14, 0x57, 0x5a, 0xa2, 0x54,
+	0xc1, 0x93, 0x1f, 0x68, 0xfb, 0x40, 0xfe, 0x3a, 0x96, 0x66, 0xf9, 0x07,
+	0xfd, 0xdb, 0xf8, 0x48, 0xb0, 0xee, 0xf4, 0x24, 0x8d, 0x90, 0xc4, 0x71,
+	0xd7, 0x89, 0xa7, 0x56, 0x48, 0xfa, 0x51, 0x0d, 0xd3, 0x35, 0x5c, 0x0a,
+	0x07, 0xbd, 0x7c, 0x7e, 0x9e, 0xc0, 0xe1, 0x36, 0xa3, 0x92, 0x2b, 0xe7,
+	0x28, 0x1f, 0xbd, 0x4f, 0x74, 0x1c, 0x8c, 0x35, 0x22, 0x45, 0xf9, 0x28,
+	0xa3, 0x57, 0x6c, 0x49, 0x9f, 0x65, 0x8c, 0xd9, 0x46, 0x18, 0x53, 0x0b,
+	0xb9, 0xe5, 0x96, 0xc1, 0x17, 0xb1, 0xd3, 0x3e, 0x5b, 0xcf, 0x36, 0xe5,
+	0xc6, 0xf1, 0xd6, 0x59, 0xbb, 0x1c, 0x60, 0x7e, 0x65, 0x3c, 0x67, 0x90,
+	0xcd, 0x5c, 0x11, 0x0e, 0x3e, 0x47, 0x39, 0x75, 0x66, 0x41, 0x1f, 0xe1,
+	0xfc, 0xa2, 0x3d, 0xd6, 0xf8, 0xb8, 0x06, 0x4c, 0x41, 0x4f, 0xe4, 0x41,
+	0xc5, 0xb6, 0xb7, 0x39, 0xf8, 0xfe, 0x82, 0xad, 0xae, 0x9e, 0xfd, 0x0f,
+	0xbe, 0x85, 0xdf, 0xb2, 0x38, 0xef, 0x84, 0xf2, 0x9b, 0xe8, 0x3b, 0xcf,
+	0x19, 0x60, 0x2c, 0xc3, 0xe7, 0x9c, 0xbc, 0x3b, 0xda, 0xab, 0xd8, 0x5f,
+	0x54, 0x3e, 0xc7, 0xbf, 0x71, 0x8c, 0x7b, 0xaa, 0x36, 0xe5, 0x67, 0x19,
+	0x7b, 0x2e, 0xfd, 0xce, 0x80, 0xaf, 0x5d, 0xd8, 0x3c, 0xc6, 0xbd, 0x88,
+	0x93, 0xd7, 0x29, 0xf8, 0x3b, 0xca, 0xc3, 0xdc, 0x2b, 0x61, 0x5f, 0x6f,
+	0xea, 0x38, 0x35, 0xc9, 0x39, 0x35, 0xde, 0x71, 0x7b, 0x7a, 0x51, 0xc7,
+	0x97, 0x78, 0x3a, 0x7d, 0x07, 0xc5, 0x9d, 0x4c, 0x5a, 0x1b, 0x8c, 0xc8,
+	0xce, 0xde, 0x54, 0xaa, 0x28, 0xbe, 0x4a, 0x45, 0x1a, 0xcf, 0xa7, 0xfa,
+	0x07, 0x0f, 0x85, 0x90, 0xc9, 0x76, 0xe3, 0x1b, 0x63, 0xb6, 0x5d, 0xb5,
+	0xc6, 0x85, 0x57, 0x46, 0x6c, 0x7c, 0x10, 0x03, 0x5e, 0x1e, 0x09, 0x0f,
+	0x9e, 0x01, 0x7e, 0xaf, 0x8e, 0x6a, 0xe4, 0x56, 0xa1, 0xf5, 0x10, 0x36,
+	0x08, 0xbd, 0x8b, 0x96, 0x60, 0x1e, 0xda, 0xe9, 0x5d, 0x34, 0xdf, 0x4b,
+	0x05, 0xe0, 0x27, 0x05, 0x2f, 0xde, 0x1c, 0xe3, 0x39, 0xbd, 0x38, 0x73,
+	0xb4, 0xc1, 0xbf, 0x93, 0xe6, 0x3a, 0x40, 0xf1, 0xbd, 0xfb, 0x58, 0x02,
+	0x9b, 0x0f, 0x09, 0x44, 0x23, 0x09, 0x74, 0x1d, 0xab, 0xc5, 0xa6, 0x31,
+	0x05, 0xef, 0xc5, 0x6b, 0x71, 0xd3, 0xd1, 0x45, 0x3e, 0x2a, 0x7d, 0x0d,
+	0x3e, 0xe7, 0xc8, 0x67, 0xc8, 0x9e, 0xcc, 0x72, 0xcc, 0xa6, 0x7c, 0x91,
+	0xe5, 0x18, 0x68, 0xdb, 0xc1, 0xf6, 0x4a, 0x9f, 0xe3, 0x29, 0xca, 0x1f,
+	0x8f, 0xb6, 0xeb, 0xc1, 0xa0, 0x64, 0x62, 0xd5, 0x44, 0xf9, 0xb6, 0x3a,
+	0xd8, 0xcf, 0xf3, 0x5e, 0xc0, 0xc7, 0xad, 0xb6, 0xbd, 0x39, 0x1e, 0x99,
+	0xbf, 0xdb, 0xc1, 0xb5, 0x71, 0xf2, 0xa9, 0x26, 0x3c, 0x9a, 0x5d, 0xdc,
+	0x2f, 0xd2, 0xfb, 0x2e, 0xca, 0xd6, 0x90, 0x0a, 0xfb, 0xa3, 0x6a, 0xd3,
+	0xfe, 0xd8, 0x6d, 0x46, 0x82, 0xf7, 0x09, 0x3e, 0x67, 0x11, 0xa2, 0x1a,
+	0xc4, 0xb6, 0xdf, 0x8a, 0xdb, 0x76, 0x21, 0x6e, 0x79, 0x56, 0xaf, 0x55,
+	0x71, 0x6c, 0x25, 0xf7, 0x9c, 0xc3, 0xc9, 0x46, 0xb2, 0x2f, 0xef, 0x4a,
+	0x3d, 0xb8, 0x15, 0x9a, 0x65, 0x51, 0x90, 0x0b, 0x2d, 0xd5, 0xfa, 0x80,
+	0x26, 0xff, 0xc1, 0x91, 0x06, 0x3c, 0x3e, 0xf7, 0x9b, 0x7c, 0xf4, 0x85,
+	0x62, 0x84, 0x8d, 0x8f, 0x0c, 0xac, 0xaf, 0x43, 0x24, 0x79, 0x27, 0xe5,
+	0x02, 0xc9, 0xe4, 0xf3, 0xa0, 0x16, 0x6e, 0x8a, 0xf7, 0x63, 0xc7, 0x18,
+	0xef, 0x51, 0xc5, 0x3a, 0x3e, 0x1a, 0xb3, 0xff, 0xc6, 0x43, 0xf4, 0xaf,
+	0x6f, 0x6f, 0x49, 0x79, 0x9d, 0xdf, 0x05, 0xe9, 0x54, 0x07, 0xd4, 0xa3,
+	0x34, 0xa3, 0x97, 0x97, 0x8b, 0xe4, 0x1b, 0x3e, 0x44, 0x82, 0x8d, 0x14,
+	0xab, 0xe6, 0xc8, 0x77, 0x67, 0x4a, 0x5c, 0x07, 0xac, 0xe9, 0xb0, 0x27,
+	0x96, 0x61, 0x7a, 0x8e, 0xe6, 0xca, 0xea, 0x5d, 0x1f, 0x10, 0xce, 0xab,
+	0x31, 0xed, 0x3a, 0xaf, 0x19, 0x39, 0xdd, 0x22, 0x64, 0xcc, 0xaf, 0xb1,
+	0xed, 0xee, 0x76, 0x7d, 0xb0, 0x56, 0x60, 0x80, 0xe6, 0x4a, 0xb4, 0xca,
+	0xb8, 0x32, 0x88, 0x48, 0xd7, 0x5b, 0x88, 0xf4, 0x9d, 0xa3, 0x18, 0xf6,
+	0x44, 0x89, 0xcf, 0xd8, 0x3e, 0x84, 0xbf, 0x19, 0x5b, 0x8a, 0xe7, 0x67,
+	0x06, 0x16, 0x7a, 0x62, 0xf0, 0x5e, 0xbd, 0xd6, 0xc4, 0xf1, 0xb1, 0x10,
+	0xd9, 0x4f, 0x15, 0xc5, 0x75, 0x05, 0x52, 0x33, 0xf7, 0x48, 0x43, 0x1d,
+	0xb1, 0x47, 0x6c, 0x7b, 0x75, 0x73, 0xa5, 0xe6, 0x59, 0x3d, 0x7b, 0xf9,
+	0xef, 0x02, 0x16, 0xfb, 0x3d, 0x41, 0xd2, 0x5f, 0x4b, 0x6a, 0x87, 0x78,
+	0xd1, 0xb6, 0x7e, 0x57, 0x10, 0xcf, 0x91, 0x5a, 0x78, 0x99, 0x6f, 0x05,
+	0xbb, 0x26, 0x08, 0x94, 0x39, 0xe7, 0x56, 0xe0, 0xed, 0x8a, 0xf3, 0x5e,
+	0x33, 0xeb, 0xa8, 0xec, 0xdd, 0x18, 0xa7, 0x98, 0x28, 0xfc, 0x84, 0xa7,
+	0x2c, 0x4f, 0x27, 0xe5, 0xa7, 0xea, 0x31, 0xfe, 0x8d, 0x82, 0x0f, 0xfb,
+	0x29, 0x6e, 0xbc, 0x6f, 0xd4, 0xe0, 0x60, 0xbd, 0x96, 0xe0, 0x7a, 0xfa,
+	0xb1, 0x12, 0xf7, 0x25, 0x77, 0xe2, 0x2e, 0xfe, 0x8d, 0x47, 0xe9, 0x5a,
+	0xe7, 0x5c, 0x1e, 0xdd, 0x23, 0x6c, 0xc0, 0x74, 0x2c, 0xae, 0xdf, 0x85,
+	0xe5, 0x23, 0xac, 0xc7, 0x40, 0x47, 0x90, 0x64, 0xf4, 0x28, 0xd9, 0x85,
+	0x64, 0x76, 0x42, 0x19, 0xb1, 0xed, 0xeb, 0xe3, 0x97, 0xcf, 0xa1, 0x0f,
+	0x9c, 0x93, 0xa9, 0xbe, 0x93, 0x79, 0x4f, 0x4c, 0x4b, 0x9c, 0x10, 0x97,
+	0xcf, 0xf9, 0x87, 0x44, 0x33, 0xcf, 0x5b, 0xc9, 0x4b, 0xc7, 0x29, 0x2f,
+	0xbd, 0x3c, 0xca, 0x3e, 0xd2, 0xe6, 0xf8, 0x88, 0x44, 0xb1, 0x76, 0x43,
+	0x3a, 0x84, 0x73, 0x06, 0xf4, 0x2a, 0xc4, 0x88, 0xee, 0x48, 0x4f, 0xe7,
+	0x02, 0xe6, 0x73, 0x53, 0xfc, 0x9f, 0x19, 0xe5, 0x7d, 0x2a, 0x81, 0x5a,
+	0x9d, 0x6d, 0xc0, 0xc9, 0x05, 0x14, 0xd3, 0x06, 0x50, 0x77, 0x2d, 0x70,
+	0x71, 0x84, 0xf7, 0xcc, 0x74, 0xec, 0x2f, 0x0d, 0x8a, 0xc6, 0x91, 0x7f,
+	0xb0, 0x43, 0xd5, 0x8b, 0xfb, 0x67, 0x0f, 0xf2, 0xfe, 0x19, 0xd9, 0xc0,
+	0x80, 0x73, 0x46, 0xe6, 0xad, 0x34, 0x9f, 0x91, 0x09, 0x87, 0x36, 0x93,
+	0xef, 0x6c, 0x43, 0x8b, 0x31, 0x4b, 0xd8, 0x79, 0x9e, 0xe8, 0x6c, 0x16,
+	0x95, 0x3d, 0xa2, 0xc8, 0xc2, 0x1e, 0xd7, 0xca, 0x7c, 0x97, 0xa8, 0x2d,
+	0x30, 0x4d, 0x71, 0xa2, 0xa9, 0x53, 0xd4, 0x1c, 0xdb, 0x28, 0x7c, 0xc7,
+	0xba, 0x85, 0x54, 0xe0, 0x98, 0x1c, 0xeb, 0xd8, 0x3d, 0xca, 0xf9, 0x6c,
+	0x8b, 0x70, 0x1d, 0xed, 0x15, 0xde, 0x42, 0x9f, 0xf0, 0x1f, 0xb3, 0x70,
+	0x6f, 0xbc, 0x1b, 0x67, 0xc6, 0xf8, 0x1c, 0xd8, 0x3d, 0xa2, 0x76, 0x61,
+	0x5f, 0xcb, 0x5b, 0x68, 0xf2, 0x17, 0x68, 0x7d, 0xc2, 0x12, 0x1d, 0xe9,
+	0x91, 0x65, 0xfe, 0x27, 0x26, 0x03, 0xfe, 0xc7, 0x26, 0xb5, 0x81, 0xbd,
+	0xc2, 0xb6, 0x77, 0xc6, 0xa6, 0x59, 0x87, 0x76, 0x4b, 0xac, 0x82, 0x0f,
+	0x76, 0x91, 0x3c, 0xb6, 0x53, 0x6e, 0x99, 0x36, 0x5a, 0x16, 0xb0, 0x88,
+	0x96, 0xe2, 0xdf, 0x8b, 0xd1, 0xa7, 0x87, 0x73, 0x1b, 0xef, 0x09, 0xba,
+	0xda, 0x41, 0x71, 0xf7, 0x33, 0x5e, 0x6b, 0x47, 0xf8, 0x7c, 0xd7, 0x00,
+	0xfc, 0x5f, 0xb2, 0x27, 0x76, 0xe6, 0xb3, 0x3d, 0xb1, 0xc4, 0x63, 0x42,
+	0x2b, 0xcf, 0x11, 0xbf, 0xd5, 0xf2, 0xe7, 0xf6, 0xc3, 0x16, 0xf6, 0xc2,
+	0xba, 0x84, 0xaf, 0xc0, 0xf5, 0x79, 0xbc, 0xe3, 0xf5, 0x91, 0x4e, 0xe1,
+	0x3d, 0x36, 0x46, 0xf9, 0x71, 0x23, 0xf1, 0xcc, 0xe7, 0xae, 0xba, 0x85,
+	0xbf, 0xb0, 0x45, 0xf8, 0x88, 0xcf, 0x1a, 0xe2, 0x13, 0xc7, 0x3c, 0xc2,
+	0x4b, 0x3c, 0x7a, 0x88, 0x47, 0xef, 0x02, 0x8f, 0x9e, 0x42, 0xd0, 0x9f,
+	0x4e, 0x37, 0xf8, 0x1f, 0x9e, 0x54, 0xfd, 0x7b, 0x27, 0x6d, 0xfb, 0x3d,
+	0xe3, 0x67, 0x0e, 0x5f, 0xaf, 0x1a, 0x5f, 0xe4, 0xeb, 0x3a, 0xe2, 0xab,
+	0xb2, 0x8f, 0x49, 0x3a, 0x4c, 0xb1, 0x0e, 0xf9, 0x0c, 0xc4, 0x22, 0x5f,
+	0x07, 0xd2, 0xbc, 0x8f, 0xc1, 0x7b, 0x7e, 0x83, 0x62, 0x35, 0xf1, 0x55,
+	0x26, 0xbe, 0xae, 0xf9, 0x12, 0xbe, 0x3e, 0xbc, 0x8c, 0xaf, 0x57, 0xff,
+	0x51, 0xbe, 0x3c, 0x62, 0xd5, 0x18, 0xc7, 0xa1, 0xfb, 0x3b, 0x94, 0x31,
+	0x9b, 0xb0, 0xa3, 0x8c, 0xc7, 0x67, 0x80, 0x62, 0x76, 0x08, 0x0a, 0xc5,
+	0x9b, 0x93, 0xf1, 0x48, 0xe8, 0x15, 0xaa, 0x27, 0x67, 0x4b, 0x5e, 0xb1,
+	0xd2, 0xd9, 0xcf, 0xc4, 0x6a, 0x85, 0x68, 0x9a, 0x73, 0x7e, 0x9f, 0x05,
+	0xa3, 0x4e, 0x67, 0x5d, 0xea, 0xa7, 0xb7, 0x22, 0x52, 0x8e, 0xc8, 0xdd,
+	0x22, 0x51, 0xe0, 0xfd, 0xcb, 0x5e, 0x71, 0x8d, 0xb3, 0x77, 0xd9, 0x25,
+	0xae, 0x2e, 0x74, 0x8a, 0x56, 0xb2, 0x8b, 0x96, 0x63, 0x7c, 0x96, 0x6a,
+	0x8b, 0x68, 0x59, 0x90, 0xc7, 0x2a, 0x92, 0xc7, 0xc8, 0xe7, 0xe4, 0xb1,
+	0xc4, 0xcf, 0xf2, 0xf8, 0x91, 0x71, 0xe1, 0xb2, 0x1e, 0x1a, 0xd7, 0x55,
+	0x94, 0x0d, 0xa9, 0x76, 0xaa, 0x5b, 0xa8, 0x9d, 0xde, 0x8e, 0xf1, 0x19,
+	0x19, 0xcb, 0xae, 0xd5, 0x11, 0x72, 0x99, 0x5a, 0xdf, 0x49, 0xa1, 0xa7,
+	0xee, 0x11, 0xc9, 0xcd, 0x3e, 0xaa, 0x7f, 0x76, 0xc4, 0x22, 0xc9, 0x55,
+	0x22, 0x92, 0x70, 0x09, 0xce, 0x2b, 0x86, 0x52, 0x5d, 0xb4, 0xb0, 0x97,
+	0xe2, 0xdb, 0x4b, 0xa3, 0x12, 0x61, 0x07, 0xfe, 0xcd, 0x96, 0x0b, 0xd7,
+	0xab, 0x3e, 0x1c, 0x21, 0xdc, 0xf1, 0x68, 0xb6, 0x1f, 0x47, 0xf2, 0xdb,
+	0xf0, 0x68, 0xfe, 0xd7, 0x7e, 0x9f, 0xa2, 0x78, 0xcd, 0x9e, 0x6b, 0x2b,
+	0xfb, 0xf8, 0xd1, 0xc4, 0x55, 0x11, 0x96, 0xcd, 0x4f, 0x5b, 0x94, 0x08,
+	0xd7, 0xba, 0x89, 0xeb, 0x7e, 0xae, 0xb3, 0x2f, 0xa6, 0xdb, 0x4f, 0x39,
+	0x58, 0xe4, 0xed, 0xb6, 0x63, 0xce, 0xf9, 0xa2, 0x5f, 0xae, 0xde, 0xed,
+	0xfc, 0x7e, 0x32, 0xb9, 0xf6, 0x76, 0x9d, 0xfd, 0xe1, 0xa7, 0x6b, 0x36,
+	0x38, 0xf9, 0xd5, 0x5c, 0x57, 0xf9, 0x6d, 0x49, 0x62, 0x5d, 0xa5, 0x57,
+	0x13, 0x5f, 0x17, 0x75, 0xae, 0xc9, 0x75, 0x95, 0x7d, 0xe2, 0x9e, 0x75,
+	0xcd, 0xce, 0xb5, 0x6b, 0x5d, 0xc5, 0xa7, 0x3a, 0xd7, 0xe9, 0xce, 0xb5,
+	0x77, 0x5d, 0x25, 0x2f, 0x77, 0xaf, 0x5b, 0x71, 0xe9, 0x37, 0x29, 0xfc,
+	0xf7, 0x7f, 0x00, 0x2f, 0xc1, 0x67, 0x8a, 0x54, 0x3a, 0x00, 0x00, 0x00 };
 
-static const u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = {
-	0x00000000, 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000010,
-	0x00000030, 0x00000030, 0x00000000, 0x00000000, 0x00000000, 0x00000010,
-	0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00008002, 0x00000000,
-	0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000005, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000006,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
-	0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
+static const u32 bnx2_TXP_b09FwData[(0x0/4) + 1] = { 0x0 };
 static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = {
-	0x08003fdc, 0x08004008, 0x08004050, 0x08004050, 0x08003edc, 0x08003f08,
-	0x08003f08, 0x08004050, 0x08004050, 0x08004050, 0x08003f70, 0x00000000,
+	0x80000940, 0x80000900, 0x80080100, 0x80080080, 0x80080000, 0x800e0000,
+	0x80080080, 0x80080000, 0x80000a80, 0x80000a00, 0x80000980, 0x80000900,
 	0x00000000 };
 
 static struct fw_info bnx2_txp_fw_09 = {
-	/* Firmware version:  3.7.1 */
-	.ver_major			= 0x3,
-	.ver_minor			= 0x7,
-	.ver_fix			= 0x1,
+	/* Firmware version: 4.0.5 */
+	.ver_major			= 0x4,
+	.ver_minor			= 0x0,
+	.ver_fix			= 0x5,
 
-	.start_addr			= 0x08000060,
+	.start_addr			= 0x08000094,
 
 	.text_addr			= 0x08000000,
-	.text_len			= 0x45b0,
+	.text_len			= 0x3a50,
 	.text_index			= 0x0,
 	.gz_text			= bnx2_TXP_b09FwText,
 	.gz_text_len			= sizeof(bnx2_TXP_b09FwText),
 
-	.data_addr			= 0x08004600,
-	.data_len			= 0xd0,
+	.data_addr			= 0x00000000,
+	.data_len			= 0x0,
 	.data_index			= 0x0,
 	.data				= bnx2_TXP_b09FwData,
 
-	.sbss_addr			= 0x080046d0,
-	.sbss_len			= 0x8c,
+	.sbss_addr			= 0x08003aa0,
+	.sbss_len			= 0x6c,
 	.sbss_index			= 0x0,
 
-	.bss_addr			= 0x08004760,
-	.bss_len			= 0xa20,
+	.bss_addr			= 0x08003b0c,
+	.bss_len			= 0x24c,
 	.bss_index			= 0x0,
 
-	.rodata_addr			= 0x080045b0,
+	.rodata_addr			= 0x08003a50,
 	.rodata_len			= 0x30,
 	.rodata_index			= 0x0,
 	.rodata				= bnx2_TXP_b09FwRodata,
diff --git a/drivers/net/bnx2x.c b/drivers/net/bnx2x.c
new file mode 100644
index 000000000000..4a73c884d0c4
--- /dev/null
+++ b/drivers/net/bnx2x.c
@@ -0,0 +1,9064 @@
+/* bnx2x.c: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Eliezer Tamir <eliezert@broadcom.com>
+ * Based on code from Michael Chan's bnx2 driver
+ * UDP CSUM errata workaround by Arik Gendelman
+ * Slowpath rework by Vladislav Zolotarov
+ * Statistics and Link managment by Yitchak Gertner
+ *
+ */
+
+/* define this to make the driver freeze on error
+ * to allow getting debug info
+ * (you will need to reboot afterwords)
+ */
+/*#define BNX2X_STOP_ON_ERROR*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/device.h>  /* for dev_info() */
+#include <linux/timer.h>
+#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>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include <linux/time.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#ifdef NETIF_F_HW_VLAN_TX
+	#include <linux/if_vlan.h>
+	#define BCM_VLAN 1
+#endif
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/checksum.h>
+#include <linux/workqueue.h>
+#include <linux/crc32.h>
+#include <linux/prefetch.h>
+#include <linux/zlib.h>
+#include <linux/version.h>
+#include <linux/io.h>
+
+#include "bnx2x_reg.h"
+#include "bnx2x_fw_defs.h"
+#include "bnx2x_hsi.h"
+#include "bnx2x.h"
+#include "bnx2x_init.h"
+
+#define DRV_MODULE_VERSION      "0.40.15"
+#define DRV_MODULE_RELDATE      "$DateTime: 2007/11/15 07:28:37 $"
+#define BNX2X_BC_VER    	0x040009
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT      	(5*HZ)
+
+static const char version[] __devinitdata =
+	"Broadcom NetXtreme II 577xx 10Gigabit Ethernet Driver "
+	DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("Eliezer Tamir <eliezert@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+MODULE_INFO(cvs_version, "$Revision: #356 $");
+
+static int use_inta;
+static int poll;
+static int onefunc;
+static int nomcp;
+static int debug;
+static int use_multi;
+
+module_param(use_inta, int, 0);
+module_param(poll, int, 0);
+module_param(onefunc, int, 0);
+module_param(debug, int, 0);
+MODULE_PARM_DESC(use_inta, "use INT#A instead of MSI-X");
+MODULE_PARM_DESC(poll, "use polling (for debug)");
+MODULE_PARM_DESC(onefunc, "enable only first function");
+MODULE_PARM_DESC(nomcp, "ignore managment CPU (Implies onefunc)");
+MODULE_PARM_DESC(debug, "defualt debug msglevel");
+
+#ifdef BNX2X_MULTI
+module_param(use_multi, int, 0);
+MODULE_PARM_DESC(use_multi, "use per-CPU queues");
+#endif
+
+enum bnx2x_board_type {
+	BCM57710 = 0,
+};
+
+/* indexed by board_t, above */
+static const struct {
+	char *name;
+} board_info[] __devinitdata = {
+	{ "Broadcom NetXtreme II BCM57710 XGb" }
+};
+
+static const struct pci_device_id bnx2x_pci_tbl[] = {
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57710 },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
+
+/****************************************************************************
+* General service functions
+****************************************************************************/
+
+/* used only at init
+ * locking is done by mcp
+ */
+static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
+{
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val);
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
+			       PCICFG_VENDOR_ID_OFFSET);
+}
+
+#ifdef BNX2X_IND_RD
+static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
+{
+	u32 val;
+
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
+	pci_read_config_dword(bp->pdev, PCICFG_GRC_DATA, &val);
+	pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
+			       PCICFG_VENDOR_ID_OFFSET);
+
+	return val;
+}
+#endif
+
+static const u32 dmae_reg_go_c[] = {
+	DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3,
+	DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7,
+	DMAE_REG_GO_C8, DMAE_REG_GO_C9, DMAE_REG_GO_C10, DMAE_REG_GO_C11,
+	DMAE_REG_GO_C12, DMAE_REG_GO_C13, DMAE_REG_GO_C14, DMAE_REG_GO_C15
+};
+
+/* copy command into DMAE command memory and set DMAE command go */
+static void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae,
+			    int idx)
+{
+	u32 cmd_offset;
+	int i;
+
+	cmd_offset = (DMAE_REG_CMD_MEM + sizeof(struct dmae_command) * idx);
+	for (i = 0; i < (sizeof(struct dmae_command)/4); i++) {
+		REG_WR(bp, cmd_offset + i*4, *(((u32 *)dmae) + i));
+
+/*      	DP(NETIF_MSG_DMAE, "DMAE cmd[%d].%d (0x%08x) : 0x%08x\n",
+		   idx, i, cmd_offset + i*4, *(((u32 *)dmae) + i)); */
+	}
+	REG_WR(bp, dmae_reg_go_c[idx], 1);
+}
+
+static void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr,
+			     u32 dst_addr, u32 len32)
+{
+	struct dmae_command *dmae = &bp->dmae;
+	int port = bp->port;
+	u32 *wb_comp = bnx2x_sp(bp, wb_comp);
+	int timeout = 200;
+
+	memset(dmae, 0, sizeof(struct dmae_command));
+
+	dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+			DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+			DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+			(port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0));
+	dmae->src_addr_lo = U64_LO(dma_addr);
+	dmae->src_addr_hi = U64_HI(dma_addr);
+	dmae->dst_addr_lo = dst_addr >> 2;
+	dmae->dst_addr_hi = 0;
+	dmae->len = len32;
+	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
+	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
+	dmae->comp_val = BNX2X_WB_COMP_VAL;
+
+/*
+	DP(NETIF_MSG_DMAE, "dmae: opcode 0x%08x\n"
+	   DP_LEVEL "src_addr  [%x:%08x]  len [%d *4]  "
+		    "dst_addr [%x:%08x (%08x)]\n"
+	   DP_LEVEL "comp_addr [%x:%08x]  comp_val 0x%08x\n",
+	   dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+	   dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, dst_addr,
+	   dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val);
+*/
+/*
+	DP(NETIF_MSG_DMAE, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
+	   bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
+	   bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
+*/
+
+	*wb_comp = 0;
+
+	bnx2x_post_dmae(bp, dmae, port * 8);
+
+	udelay(5);
+	/* adjust timeout for emulation/FPGA */
+	if (CHIP_REV_IS_SLOW(bp))
+		timeout *= 100;
+	while (*wb_comp != BNX2X_WB_COMP_VAL) {
+/*      	DP(NETIF_MSG_DMAE, "wb_comp 0x%08x\n", *wb_comp); */
+		udelay(5);
+		if (!timeout) {
+			BNX2X_ERR("dmae timeout!\n");
+			break;
+		}
+		timeout--;
+	}
+}
+
+#ifdef BNX2X_DMAE_RD
+static void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
+{
+	struct dmae_command *dmae = &bp->dmae;
+	int port = bp->port;
+	u32 *wb_comp = bnx2x_sp(bp, wb_comp);
+	int timeout = 200;
+
+	memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4);
+	memset(dmae, 0, sizeof(struct dmae_command));
+
+	dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+			DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+			DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+			(port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0));
+	dmae->src_addr_lo = src_addr >> 2;
+	dmae->src_addr_hi = 0;
+	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data));
+	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data));
+	dmae->len = len32;
+	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
+	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
+	dmae->comp_val = BNX2X_WB_COMP_VAL;
+
+/*
+	DP(NETIF_MSG_DMAE, "dmae: opcode 0x%08x\n"
+	   DP_LEVEL "src_addr  [%x:%08x]  len [%d *4]  "
+		    "dst_addr [%x:%08x (%08x)]\n"
+	   DP_LEVEL "comp_addr [%x:%08x]  comp_val 0x%08x\n",
+	   dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
+	   dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, src_addr,
+	   dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val);
+*/
+
+	*wb_comp = 0;
+
+	bnx2x_post_dmae(bp, dmae, port * 8);
+
+	udelay(5);
+	while (*wb_comp != BNX2X_WB_COMP_VAL) {
+		udelay(5);
+		if (!timeout) {
+			BNX2X_ERR("dmae timeout!\n");
+			break;
+		}
+		timeout--;
+	}
+/*
+	DP(NETIF_MSG_DMAE, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
+	   bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
+	   bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
+*/
+}
+#endif
+
+static int bnx2x_mc_assert(struct bnx2x *bp)
+{
+	int i, j;
+	int rc = 0;
+	char last_idx;
+	const char storm[] = {"XTCU"};
+	const u32 intmem_base[] = {
+		BAR_XSTRORM_INTMEM,
+		BAR_TSTRORM_INTMEM,
+		BAR_CSTRORM_INTMEM,
+		BAR_USTRORM_INTMEM
+	};
+
+	/* Go through all instances of all SEMIs */
+	for (i = 0; i < 4; i++) {
+		last_idx = REG_RD8(bp, XSTORM_ASSERT_LIST_INDEX_OFFSET +
+				   intmem_base[i]);
+		BNX2X_ERR("DATA %cSTORM_ASSERT_LIST_INDEX 0x%x\n",
+			  storm[i], last_idx);
+
+		/* print the asserts */
+		for (j = 0; j < STROM_ASSERT_ARRAY_SIZE; j++) {
+			u32 row0, row1, row2, row3;
+
+			row0 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) +
+				      intmem_base[i]);
+			row1 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 4 +
+				      intmem_base[i]);
+			row2 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 8 +
+				      intmem_base[i]);
+			row3 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 12 +
+				      intmem_base[i]);
+
+			if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
+				BNX2X_ERR("DATA %cSTORM_ASSERT_INDEX 0x%x ="
+					  " 0x%08x 0x%08x 0x%08x 0x%08x\n",
+					  storm[i], j, row3, row2, row1, row0);
+				rc++;
+			} else {
+				break;
+			}
+		}
+	}
+	return rc;
+}
+static void bnx2x_fw_dump(struct bnx2x *bp)
+{
+	u32 mark, offset;
+	u32 data[9];
+	int word;
+
+	mark = REG_RD(bp, MCP_REG_MCPR_SCRATCH + 0xf104);
+	printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n", mark);
+
+	for (offset = mark - 0x08000000; offset <= 0xF900; offset += 0x8*4) {
+		for (word = 0; word < 8; word++)
+			data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
+						  offset + 4*word));
+		data[8] = 0x0;
+		printk(KERN_ERR PFX "%s", (char *)data);
+	}
+	for (offset = 0xF108; offset <= mark - 0x08000000; offset += 0x8*4) {
+		for (word = 0; word < 8; word++)
+			data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
+						  offset + 4*word));
+		data[8] = 0x0;
+		printk(KERN_ERR PFX "%s", (char *)data);
+	}
+	printk("\n" KERN_ERR PFX "end of fw dump\n");
+}
+
+static void bnx2x_panic_dump(struct bnx2x *bp)
+{
+	int i;
+	u16 j, start, end;
+
+	BNX2X_ERR("begin crash dump -----------------\n");
+
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+		struct eth_tx_db_data *hw_prods = fp->hw_tx_prods;
+
+		BNX2X_ERR("queue[%d]: tx_pkt_prod(%x)  tx_pkt_cons(%x)"
+			  "  tx_bd_prod(%x)  tx_bd_cons(%x)  *tx_cons_sb(%x)"
+			  "  *rx_cons_sb(%x)  rx_comp_prod(%x)"
+			  "  rx_comp_cons(%x)  fp_c_idx(%x)  fp_u_idx(%x)"
+			  "  bd data(%x,%x)\n",
+			  i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod,
+			  fp->tx_bd_cons, *fp->tx_cons_sb, *fp->rx_cons_sb,
+			  fp->rx_comp_prod, fp->rx_comp_cons, fp->fp_c_idx,
+			  fp->fp_u_idx, hw_prods->packets_prod,
+			  hw_prods->bds_prod);
+
+		start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10);
+		end = TX_BD(le16_to_cpu(*fp->tx_cons_sb) + 245);
+		for (j = start; j < end; j++) {
+			struct sw_tx_bd *sw_bd = &fp->tx_buf_ring[j];
+
+			BNX2X_ERR("packet[%x]=[%p,%x]\n", j,
+				  sw_bd->skb, sw_bd->first_bd);
+		}
+
+		start = TX_BD(fp->tx_bd_cons - 10);
+		end = TX_BD(fp->tx_bd_cons + 254);
+		for (j = start; j < end; j++) {
+			u32 *tx_bd = (u32 *)&fp->tx_desc_ring[j];
+
+			BNX2X_ERR("tx_bd[%x]=[%x:%x:%x:%x]\n",
+				  j, tx_bd[0], tx_bd[1], tx_bd[2], tx_bd[3]);
+		}
+
+		start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
+		end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503);
+		for (j = start; j < end; j++) {
+			u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j];
+			struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j];
+
+			BNX2X_ERR("rx_bd[%x]=[%x:%x]  sw_bd=[%p]\n",
+				  j, rx_bd[0], rx_bd[1], sw_bd->skb);
+		}
+
+		start = RCQ_BD(fp->rx_comp_cons - 10);
+		end = RCQ_BD(fp->rx_comp_cons + 503);
+		for (j = start; j < end; j++) {
+			u32 *cqe = (u32 *)&fp->rx_comp_ring[j];
+
+			BNX2X_ERR("cqe[%x]=[%x:%x:%x:%x]\n",
+				  j, cqe[0], cqe[1], cqe[2], cqe[3]);
+		}
+	}
+
+	BNX2X_ERR("def_c_idx(%u)  def_u_idx(%u)  def_t_idx(%u)"
+		  "  def_x_idx(%u)  def_att_idx(%u)  attn_state(%u)"
+		  "  spq_prod_idx(%u)\n",
+		  bp->def_c_idx, bp->def_u_idx, bp->def_t_idx, bp->def_x_idx,
+		  bp->def_att_idx, bp->attn_state, bp->spq_prod_idx);
+
+
+	bnx2x_mc_assert(bp);
+	BNX2X_ERR("end crash dump -----------------\n");
+
+	bp->stats_state = STATS_STATE_DISABLE;
+	DP(BNX2X_MSG_STATS, "stats_state - DISABLE\n");
+}
+
+static void bnx2x_enable_int(struct bnx2x *bp)
+{
+	int port = bp->port;
+	u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+	u32 val = REG_RD(bp, addr);
+	int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
+
+	if (msix) {
+		val &= ~HC_CONFIG_0_REG_SINGLE_ISR_EN_0;
+		val |= (HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+			HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+	} else {
+		val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+			HC_CONFIG_0_REG_INT_LINE_EN_0 |
+			HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+		val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0;
+	}
+
+	DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)  msi %d\n",
+	   val, port, addr, msix);
+
+	REG_WR(bp, addr, val);
+}
+
+static void bnx2x_disable_int(struct bnx2x *bp)
+{
+	int port = bp->port;
+	u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+	u32 val = REG_RD(bp, addr);
+
+	val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
+		 HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
+		 HC_CONFIG_0_REG_INT_LINE_EN_0 |
+		 HC_CONFIG_0_REG_ATTN_BIT_EN_0);
+
+	DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n",
+	   val, port, addr);
+
+	REG_WR(bp, addr, val);
+	if (REG_RD(bp, addr) != val)
+		BNX2X_ERR("BUG! proper val not read from IGU!\n");
+}
+
+static void bnx2x_disable_int_sync(struct bnx2x *bp)
+{
+
+	int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
+	int i;
+
+	atomic_inc(&bp->intr_sem);
+	/* prevent the HW from sending interrupts*/
+	bnx2x_disable_int(bp);
+
+	/* make sure all ISRs are done */
+	if (msix) {
+		for_each_queue(bp, i)
+			synchronize_irq(bp->msix_table[i].vector);
+
+		/* one more for the Slow Path IRQ */
+		synchronize_irq(bp->msix_table[i].vector);
+	} else
+		synchronize_irq(bp->pdev->irq);
+
+	/* make sure sp_task is not running */
+	cancel_work_sync(&bp->sp_task);
+
+}
+
+/* fast path code */
+
+/*
+ * general service functions
+ */
+
+static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 id,
+				u8 storm, u16 index, u8 op, u8 update)
+{
+	u32 igu_addr = (IGU_ADDR_INT_ACK + IGU_PORT_BASE * bp->port) * 8;
+	struct igu_ack_register igu_ack;
+
+	igu_ack.status_block_index = index;
+	igu_ack.sb_id_and_flags =
+			((id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) |
+			 (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) |
+			 (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) |
+			 (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT));
+
+/*      DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n",
+	   (*(u32 *)&igu_ack), BAR_IGU_INTMEM + igu_addr); */
+	REG_WR(bp, BAR_IGU_INTMEM + igu_addr, (*(u32 *)&igu_ack));
+}
+
+static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
+{
+	struct host_status_block *fpsb = fp->status_blk;
+	u16 rc = 0;
+
+	barrier(); /* status block is written to by the chip */
+	if (fp->fp_c_idx != fpsb->c_status_block.status_block_index) {
+		fp->fp_c_idx = fpsb->c_status_block.status_block_index;
+		rc |= 1;
+	}
+	if (fp->fp_u_idx != fpsb->u_status_block.status_block_index) {
+		fp->fp_u_idx = fpsb->u_status_block.status_block_index;
+		rc |= 2;
+	}
+	return rc;
+}
+
+static inline int bnx2x_has_work(struct bnx2x_fastpath *fp)
+{
+	u16 rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb);
+
+	if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
+		rx_cons_sb++;
+
+	if ((rx_cons_sb != fp->rx_comp_cons) ||
+	    (le16_to_cpu(*fp->tx_cons_sb) != fp->tx_pkt_cons))
+		return 1;
+
+	return 0;
+}
+
+static u16 bnx2x_ack_int(struct bnx2x *bp)
+{
+	u32 igu_addr = (IGU_ADDR_SIMD_MASK + IGU_PORT_BASE * bp->port) * 8;
+	u32 result = REG_RD(bp, BAR_IGU_INTMEM + igu_addr);
+
+/*      DP(NETIF_MSG_INTR, "read 0x%08x from IGU addr 0x%x\n",
+	   result, BAR_IGU_INTMEM + igu_addr); */
+
+#ifdef IGU_DEBUG
+#warning IGU_DEBUG active
+	if (result == 0) {
+		BNX2X_ERR("read %x from IGU\n", result);
+		REG_WR(bp, TM_REG_TIMER_SOFT_RST, 0);
+	}
+#endif
+	return result;
+}
+
+
+/*
+ * fast path service functions
+ */
+
+/* free skb in the packet ring at pos idx
+ * return idx of last bd freed
+ */
+static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+			     u16 idx)
+{
+	struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx];
+	struct eth_tx_bd *tx_bd;
+	struct sk_buff *skb = tx_buf->skb;
+	u16 bd_idx = tx_buf->first_bd;
+	int nbd;
+
+	DP(BNX2X_MSG_OFF, "pkt_idx %d  buff @(%p)->skb %p\n",
+	   idx, tx_buf, skb);
+
+	/* unmap first bd */
+	DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx);
+	tx_bd = &fp->tx_desc_ring[bd_idx];
+	pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_bd),
+			 BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE);
+
+	nbd = le16_to_cpu(tx_bd->nbd) - 1;
+#ifdef BNX2X_STOP_ON_ERROR
+	if (nbd > (MAX_SKB_FRAGS + 2)) {
+		BNX2X_ERR("bad nbd!\n");
+		bnx2x_panic();
+	}
+#endif
+
+	/* Skip a parse bd and the TSO split header bd
+	   since they have no mapping */
+	if (nbd)
+		bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+
+	if (tx_bd->bd_flags.as_bitfield & (ETH_TX_BD_FLAGS_IP_CSUM |
+					   ETH_TX_BD_FLAGS_TCP_CSUM |
+					   ETH_TX_BD_FLAGS_SW_LSO)) {
+		if (--nbd)
+			bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+		tx_bd = &fp->tx_desc_ring[bd_idx];
+		/* is this a TSO split header bd? */
+		if (tx_bd->bd_flags.as_bitfield & ETH_TX_BD_FLAGS_SW_LSO) {
+			if (--nbd)
+				bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+		}
+	}
+
+	/* now free frags */
+	while (nbd > 0) {
+
+		DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx);
+		tx_bd = &fp->tx_desc_ring[bd_idx];
+		pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_bd),
+			       BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE);
+		if (--nbd)
+			bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
+	}
+
+	/* release skb */
+	BUG_TRAP(skb);
+	dev_kfree_skb(skb);
+	tx_buf->first_bd = 0;
+	tx_buf->skb = NULL;
+
+	return bd_idx;
+}
+
+static inline u32 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
+{
+	u16 used;
+	u32 prod;
+	u32 cons;
+
+	/* Tell compiler that prod and cons can change */
+	barrier();
+	prod = fp->tx_bd_prod;
+	cons = fp->tx_bd_cons;
+
+	used = (NUM_TX_BD - NUM_TX_RINGS + prod - cons +
+		(cons / TX_DESC_CNT) - (prod / TX_DESC_CNT));
+
+	if (prod >= cons) {
+		/* used = prod - cons - prod/size + cons/size */
+		used -= NUM_TX_BD - NUM_TX_RINGS;
+	}
+
+	BUG_TRAP(used <= fp->bp->tx_ring_size);
+	BUG_TRAP((fp->bp->tx_ring_size - used) <= MAX_TX_AVAIL);
+
+	return (fp->bp->tx_ring_size - used);
+}
+
+static void bnx2x_tx_int(struct bnx2x_fastpath *fp, int work)
+{
+	struct bnx2x *bp = fp->bp;
+	u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons;
+	int done = 0;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return;
+#endif
+
+	hw_cons = le16_to_cpu(*fp->tx_cons_sb);
+	sw_cons = fp->tx_pkt_cons;
+
+	while (sw_cons != hw_cons) {
+		u16 pkt_cons;
+
+		pkt_cons = TX_BD(sw_cons);
+
+		/* prefetch(bp->tx_buf_ring[pkt_cons].skb); */
+
+		DP(NETIF_MSG_TX_DONE, "hw_cons %u  sw_cons %u  pkt_cons %d\n",
+		   hw_cons, sw_cons, pkt_cons);
+
+/*      	if (NEXT_TX_IDX(sw_cons) != hw_cons) {
+			rmb();
+			prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb);
+		}
+*/
+		bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons);
+		sw_cons++;
+		done++;
+
+		if (done == work)
+			break;
+	}
+
+	fp->tx_pkt_cons = sw_cons;
+	fp->tx_bd_cons = bd_cons;
+
+	/* Need to make the tx_cons update visible to start_xmit()
+	 * before checking for netif_queue_stopped().  Without the
+	 * memory barrier, there is a small possibility that start_xmit()
+	 * will miss it and cause the queue to be stopped forever.
+	 */
+	smp_mb();
+
+	/* TBD need a thresh? */
+	if (unlikely(netif_queue_stopped(bp->dev))) {
+
+		netif_tx_lock(bp->dev);
+
+		if (netif_queue_stopped(bp->dev) &&
+		    (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3))
+			netif_wake_queue(bp->dev);
+
+		netif_tx_unlock(bp->dev);
+
+	}
+}
+
+static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
+			   union eth_rx_cqe *rr_cqe)
+{
+	struct bnx2x *bp = fp->bp;
+	int cid = SW_CID(rr_cqe->ramrod_cqe.conn_and_cmd_data);
+	int command = CQE_CMD(rr_cqe->ramrod_cqe.conn_and_cmd_data);
+
+	DP(NETIF_MSG_RX_STATUS,
+	   "fp %d  cid %d  got ramrod #%d  state is %x  type is %d\n",
+	   fp->index, cid, command, bp->state, rr_cqe->ramrod_cqe.type);
+
+	bp->spq_left++;
+
+	if (fp->index) {
+		switch (command | fp->state) {
+		case (RAMROD_CMD_ID_ETH_CLIENT_SETUP |
+						BNX2X_FP_STATE_OPENING):
+			DP(NETIF_MSG_IFUP, "got MULTI[%d] setup ramrod\n",
+			   cid);
+			fp->state = BNX2X_FP_STATE_OPEN;
+			break;
+
+		case (RAMROD_CMD_ID_ETH_HALT | BNX2X_FP_STATE_HALTING):
+			DP(NETIF_MSG_IFDOWN, "got MULTI[%d] halt ramrod\n",
+			   cid);
+			fp->state = BNX2X_FP_STATE_HALTED;
+			break;
+
+		default:
+			BNX2X_ERR("unexpected MC reply(%d)  state is %x\n",
+				  command, fp->state);
+		}
+		mb(); /* force bnx2x_wait_ramrod to see the change */
+		return;
+	}
+	switch (command | bp->state) {
+	case (RAMROD_CMD_ID_ETH_PORT_SETUP | BNX2X_STATE_OPENING_WAIT4_PORT):
+		DP(NETIF_MSG_IFUP, "got setup ramrod\n");
+		bp->state = BNX2X_STATE_OPEN;
+		break;
+
+	case (RAMROD_CMD_ID_ETH_HALT | BNX2X_STATE_CLOSING_WAIT4_HALT):
+		DP(NETIF_MSG_IFDOWN, "got halt ramrod\n");
+		bp->state = BNX2X_STATE_CLOSING_WAIT4_DELETE;
+		fp->state = BNX2X_FP_STATE_HALTED;
+		break;
+
+	case (RAMROD_CMD_ID_ETH_PORT_DEL | BNX2X_STATE_CLOSING_WAIT4_DELETE):
+		DP(NETIF_MSG_IFDOWN, "got delete ramrod\n");
+		bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD;
+		break;
+
+	case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_CLOSING_WAIT4_HALT):
+		DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", cid);
+		bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_DELETED;
+		break;
+
+	case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN):
+		DP(NETIF_MSG_IFUP, "got set mac ramrod\n");
+		break;
+
+	default:
+		BNX2X_ERR("unexpected ramrod (%d)  state is %x\n",
+			  command, bp->state);
+	}
+
+	mb(); /* force bnx2x_wait_ramrod to see the change */
+}
+
+static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
+				     struct bnx2x_fastpath *fp, u16 index)
+{
+	struct sk_buff *skb;
+	struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index];
+	struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index];
+	dma_addr_t mapping;
+
+	skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
+	if (unlikely(skb == NULL))
+		return -ENOMEM;
+
+	mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
+				 PCI_DMA_FROMDEVICE);
+	if (unlikely(dma_mapping_error(mapping))) {
+
+		dev_kfree_skb(skb);
+		return -ENOMEM;
+	}
+
+	rx_buf->skb = skb;
+	pci_unmap_addr_set(rx_buf, mapping, mapping);
+
+	rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+	rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+
+	return 0;
+}
+
+/* note that we are not allocating a new skb,
+ * we are just moving one from cons to prod
+ * we are not creating a new mapping,
+ * so there is no need to check for dma_mapping_error().
+ */
+static void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
+			       struct sk_buff *skb, u16 cons, u16 prod)
+{
+	struct bnx2x *bp = fp->bp;
+	struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
+	struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod];
+	struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons];
+	struct eth_rx_bd *prod_bd = &fp->rx_desc_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));
+	*prod_bd = *cons_bd;
+}
+
+static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
+{
+	struct bnx2x *bp = fp->bp;
+	u16 bd_cons, bd_prod, comp_ring_cons;
+	u16 hw_comp_cons, sw_comp_cons, sw_comp_prod;
+	int rx_pkt = 0;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return 0;
+#endif
+
+	hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb);
+	if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
+		hw_comp_cons++;
+
+	bd_cons = fp->rx_bd_cons;
+	bd_prod = fp->rx_bd_prod;
+	sw_comp_cons = fp->rx_comp_cons;
+	sw_comp_prod = fp->rx_comp_prod;
+
+	/* Memory barrier necessary as speculative reads of the rx
+	 * buffer can be ahead of the index in the status block
+	 */
+	rmb();
+
+	DP(NETIF_MSG_RX_STATUS,
+	   "queue[%d]:  hw_comp_cons %u  sw_comp_cons %u\n",
+	   fp->index, hw_comp_cons, sw_comp_cons);
+
+	while (sw_comp_cons != hw_comp_cons) {
+		unsigned int len, pad;
+		struct sw_rx_bd *rx_buf;
+		struct sk_buff *skb;
+		union eth_rx_cqe *cqe;
+
+		comp_ring_cons = RCQ_BD(sw_comp_cons);
+		bd_prod = RX_BD(bd_prod);
+		bd_cons = RX_BD(bd_cons);
+
+		cqe = &fp->rx_comp_ring[comp_ring_cons];
+
+		DP(NETIF_MSG_RX_STATUS, "hw_comp_cons %u  sw_comp_cons %u"
+		   "  comp_ring (%u)  bd_ring (%u,%u)\n",
+		   hw_comp_cons, sw_comp_cons,
+		   comp_ring_cons, bd_prod, bd_cons);
+		DP(NETIF_MSG_RX_STATUS, "CQE type %x  err %x  status %x"
+		   "  queue %x  vlan %x  len %x\n",
+		   cqe->fast_path_cqe.type,
+		   cqe->fast_path_cqe.error_type_flags,
+		   cqe->fast_path_cqe.status_flags,
+		   cqe->fast_path_cqe.rss_hash_result,
+		   cqe->fast_path_cqe.vlan_tag, cqe->fast_path_cqe.pkt_len);
+
+		/* is this a slowpath msg? */
+		if (unlikely(cqe->fast_path_cqe.type)) {
+			bnx2x_sp_event(fp, cqe);
+			goto next_cqe;
+
+		/* this is an rx packet */
+		} else {
+			rx_buf = &fp->rx_buf_ring[bd_cons];
+			skb = rx_buf->skb;
+
+			len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
+			pad = cqe->fast_path_cqe.placement_offset;
+
+			pci_dma_sync_single_for_device(bp->pdev,
+					pci_unmap_addr(rx_buf, mapping),
+						       pad + RX_COPY_THRESH,
+						       PCI_DMA_FROMDEVICE);
+			prefetch(skb);
+			prefetch(((char *)(skb)) + 128);
+
+			/* is this an error packet? */
+			if (unlikely(cqe->fast_path_cqe.error_type_flags &
+							ETH_RX_ERROR_FALGS)) {
+			/* do we sometimes forward error packets anyway? */
+				DP(NETIF_MSG_RX_ERR,
+				   "ERROR flags(%u) Rx packet(%u)\n",
+				   cqe->fast_path_cqe.error_type_flags,
+				   sw_comp_cons);
+				/* TBD make sure MC counts this as a drop */
+				goto reuse_rx;
+			}
+
+			/* Since we don't have a jumbo ring
+			 * copy small packets if mtu > 1500
+			 */
+			if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) &&
+			    (len <= RX_COPY_THRESH)) {
+				struct sk_buff *new_skb;
+
+				new_skb = netdev_alloc_skb(bp->dev,
+							   len + pad);
+				if (new_skb == NULL) {
+					DP(NETIF_MSG_RX_ERR,
+					   "ERROR packet dropped "
+					   "because of alloc failure\n");
+					/* TBD count this as a drop? */
+					goto reuse_rx;
+				}
+
+				/* aligned copy */
+				skb_copy_from_linear_data_offset(skb, pad,
+						    new_skb->data + pad, len);
+				skb_reserve(new_skb, pad);
+				skb_put(new_skb, len);
+
+				bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
+
+				skb = new_skb;
+
+			} else if (bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0) {
+				pci_unmap_single(bp->pdev,
+					pci_unmap_addr(rx_buf, mapping),
+						 bp->rx_buf_use_size,
+						 PCI_DMA_FROMDEVICE);
+				skb_reserve(skb, pad);
+				skb_put(skb, len);
+
+			} else {
+				DP(NETIF_MSG_RX_ERR,
+				   "ERROR packet dropped because "
+				   "of alloc failure\n");
+reuse_rx:
+				bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod);
+				goto next_rx;
+			}
+
+			skb->protocol = eth_type_trans(skb, bp->dev);
+
+			skb->ip_summed = CHECKSUM_NONE;
+			if (bp->rx_csum && BNX2X_RX_SUM_OK(cqe))
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+			/* TBD do we pass bad csum packets in promisc */
+		}
+
+#ifdef BCM_VLAN
+		if ((le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags)
+				& PARSING_FLAGS_NUMBER_OF_NESTED_VLANS)
+		    && (bp->vlgrp != NULL))
+			vlan_hwaccel_receive_skb(skb, bp->vlgrp,
+				le16_to_cpu(cqe->fast_path_cqe.vlan_tag));
+		else
+#endif
+		netif_receive_skb(skb);
+
+		bp->dev->last_rx = jiffies;
+
+next_rx:
+		rx_buf->skb = NULL;
+
+		bd_cons = NEXT_RX_IDX(bd_cons);
+		bd_prod = NEXT_RX_IDX(bd_prod);
+next_cqe:
+		sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod);
+		sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons);
+		rx_pkt++;
+
+		if ((rx_pkt == budget))
+			break;
+	} /* while */
+
+	fp->rx_bd_cons = bd_cons;
+	fp->rx_bd_prod = bd_prod;
+	fp->rx_comp_cons = sw_comp_cons;
+	fp->rx_comp_prod = sw_comp_prod;
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_RCQ_PROD_OFFSET(bp->port, fp->index), sw_comp_prod);
+
+	mmiowb(); /* keep prod updates ordered */
+
+	fp->rx_pkt += rx_pkt;
+	fp->rx_calls++;
+
+	return rx_pkt;
+}
+
+static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
+{
+	struct bnx2x_fastpath *fp = fp_cookie;
+	struct bnx2x *bp = fp->bp;
+	struct net_device *dev = bp->dev;
+	int index = fp->index;
+
+	DP(NETIF_MSG_INTR, "got an msix interrupt on [%d]\n", index);
+	bnx2x_ack_sb(bp, index, USTORM_ID, 0, IGU_INT_DISABLE, 0);
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return IRQ_HANDLED;
+#endif
+
+	prefetch(fp->rx_cons_sb);
+	prefetch(fp->tx_cons_sb);
+	prefetch(&fp->status_blk->c_status_block.status_block_index);
+	prefetch(&fp->status_blk->u_status_block.status_block_index);
+
+	netif_rx_schedule(dev, &bnx2x_fp(bp, index, napi));
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
+{
+	struct net_device *dev = dev_instance;
+	struct bnx2x *bp = netdev_priv(dev);
+	u16 status = bnx2x_ack_int(bp);
+
+	if (unlikely(status == 0)) {
+		DP(NETIF_MSG_INTR, "not our interrupt!\n");
+		return IRQ_NONE;
+	}
+
+	DP(NETIF_MSG_INTR, "got an interrupt status is %u\n", status);
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return IRQ_HANDLED;
+#endif
+
+	/* Return here if interrupt is shared and is disabled */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
+		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+		return IRQ_HANDLED;
+	}
+
+	if (status & 0x2) {
+		struct bnx2x_fastpath *fp = &bp->fp[0];
+
+		prefetch(fp->rx_cons_sb);
+		prefetch(fp->tx_cons_sb);
+		prefetch(&fp->status_blk->c_status_block.status_block_index);
+		prefetch(&fp->status_blk->u_status_block.status_block_index);
+
+		netif_rx_schedule(dev, &bnx2x_fp(bp, 0, napi));
+
+		status &= ~0x2;
+		if (!status)
+			return IRQ_HANDLED;
+	}
+
+	if (unlikely(status & 0x1)) {
+
+		schedule_work(&bp->sp_task);
+
+		status &= ~0x1;
+		if (!status)
+			return IRQ_HANDLED;
+	}
+
+	DP(NETIF_MSG_INTR, "got an unknown interrupt! (status is %u)\n",
+	   status);
+
+	return IRQ_HANDLED;
+}
+
+/* end of fast path */
+
+/* PHY/MAC */
+
+/*
+ * General service functions
+ */
+
+static void bnx2x_leds_set(struct bnx2x *bp, unsigned int speed)
+{
+	int port = bp->port;
+
+	NIG_WR(NIG_REG_LED_MODE_P0 + port*4,
+	       ((bp->hw_config & SHARED_HW_CFG_LED_MODE_MASK) >>
+		SHARED_HW_CFG_LED_MODE_SHIFT));
+	NIG_WR(NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0);
+
+	/* Set blinking rate to ~15.9Hz */
+	NIG_WR(NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4,
+	       LED_BLINK_RATE_VAL);
+	NIG_WR(NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 + port*4, 1);
+
+	/* On Ax chip versions for speeds less than 10G
+	   LED scheme is different */
+	if ((CHIP_REV(bp) == CHIP_REV_Ax) && (speed < SPEED_10000)) {
+		NIG_WR(NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 1);
+		NIG_WR(NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4, 0);
+		NIG_WR(NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 + port*4, 1);
+	}
+}
+
+static void bnx2x_leds_unset(struct bnx2x *bp)
+{
+	int port = bp->port;
+
+	NIG_WR(NIG_REG_LED_10G_P0 + port*4, 0);
+	NIG_WR(NIG_REG_LED_MODE_P0 + port*4, SHARED_HW_CFG_LED_MAC1);
+}
+
+static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
+{
+	u32 val = REG_RD(bp, reg);
+
+	val |= bits;
+	REG_WR(bp, reg, val);
+	return val;
+}
+
+static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits)
+{
+	u32 val = REG_RD(bp, reg);
+
+	val &= ~bits;
+	REG_WR(bp, reg, val);
+	return val;
+}
+
+static int bnx2x_mdio22_write(struct bnx2x *bp, u32 reg, u32 val)
+{
+	int rc;
+	u32 tmp, i;
+	int port = bp->port;
+	u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+
+/*      DP(NETIF_MSG_HW, "phy_addr 0x%x  reg 0x%x  val 0x%08x\n",
+	   bp->phy_addr, reg, val); */
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+
+		tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		tmp &= ~EMAC_MDIO_MODE_AUTO_POLL;
+		EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
+		REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		udelay(40);
+	}
+
+	tmp = ((bp->phy_addr << 21) | (reg << 16) |
+	       (val & EMAC_MDIO_COMM_DATA) |
+	       EMAC_MDIO_COMM_COMMAND_WRITE_22 |
+	       EMAC_MDIO_COMM_START_BUSY);
+	EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp);
+
+	for (i = 0; i < 50; i++) {
+		udelay(10);
+
+		tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+		if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
+			udelay(5);
+			break;
+		}
+	}
+
+	if (tmp & EMAC_MDIO_COMM_START_BUSY) {
+		BNX2X_ERR("write phy register failed\n");
+
+		rc = -EBUSY;
+	} else {
+		rc = 0;
+	}
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+
+		tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		tmp |= EMAC_MDIO_MODE_AUTO_POLL;
+		EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
+	}
+
+	return rc;
+}
+
+static int bnx2x_mdio22_read(struct bnx2x *bp, u32 reg, u32 *ret_val)
+{
+	int port = bp->port;
+	u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+	u32 val, i;
+	int rc;
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+
+		val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		val &= ~EMAC_MDIO_MODE_AUTO_POLL;
+		EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
+		REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		udelay(40);
+	}
+
+	val = ((bp->phy_addr << 21) | (reg << 16) |
+	       EMAC_MDIO_COMM_COMMAND_READ_22 |
+	       EMAC_MDIO_COMM_START_BUSY);
+	EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val);
+
+	for (i = 0; i < 50; i++) {
+		udelay(10);
+
+		val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+		if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
+			val &= EMAC_MDIO_COMM_DATA;
+			break;
+		}
+	}
+
+	if (val & EMAC_MDIO_COMM_START_BUSY) {
+		BNX2X_ERR("read phy register failed\n");
+
+		*ret_val = 0x0;
+		rc = -EBUSY;
+	} else {
+		*ret_val = val;
+		rc = 0;
+	}
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+
+		val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		val |= EMAC_MDIO_MODE_AUTO_POLL;
+		EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
+	}
+
+/*      DP(NETIF_MSG_HW, "phy_addr 0x%x  reg 0x%x  ret_val 0x%08x\n",
+	   bp->phy_addr, reg, *ret_val); */
+
+	return rc;
+}
+
+static int bnx2x_mdio45_write(struct bnx2x *bp, u32 reg, u32 addr, u32 val)
+{
+	int rc = 0;
+	u32 tmp, i;
+	int port = bp->port;
+	u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+
+		tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		tmp &= ~EMAC_MDIO_MODE_AUTO_POLL;
+		EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
+		REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		udelay(40);
+	}
+
+	/* set clause 45 mode */
+	tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+	tmp |= EMAC_MDIO_MODE_CLAUSE_45;
+	EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
+
+	/* address */
+	tmp = ((bp->phy_addr << 21) | (reg << 16) | addr |
+	       EMAC_MDIO_COMM_COMMAND_ADDRESS |
+	       EMAC_MDIO_COMM_START_BUSY);
+	EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp);
+
+	for (i = 0; i < 50; i++) {
+		udelay(10);
+
+		tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+		if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
+			udelay(5);
+			break;
+		}
+	}
+
+	if (tmp & EMAC_MDIO_COMM_START_BUSY) {
+		BNX2X_ERR("write phy register failed\n");
+
+		rc = -EBUSY;
+	} else {
+		/* data */
+		tmp = ((bp->phy_addr << 21) | (reg << 16) | val |
+		       EMAC_MDIO_COMM_COMMAND_WRITE_45 |
+		       EMAC_MDIO_COMM_START_BUSY);
+		EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp);
+
+		for (i = 0; i < 50; i++) {
+			udelay(10);
+
+			tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+			if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
+				udelay(5);
+				break;
+			}
+		}
+
+		if (tmp & EMAC_MDIO_COMM_START_BUSY) {
+			BNX2X_ERR("write phy register failed\n");
+
+			rc = -EBUSY;
+		}
+	}
+
+	/* unset clause 45 mode */
+	tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+	tmp &= ~EMAC_MDIO_MODE_CLAUSE_45;
+	EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+
+		tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		tmp |= EMAC_MDIO_MODE_AUTO_POLL;
+		EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp);
+	}
+
+	return rc;
+}
+
+static int bnx2x_mdio45_read(struct bnx2x *bp, u32 reg, u32 addr,
+			     u32 *ret_val)
+{
+	int port = bp->port;
+	u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+	u32 val, i;
+	int rc = 0;
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+
+		val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		val &= ~EMAC_MDIO_MODE_AUTO_POLL;
+		EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
+		REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		udelay(40);
+	}
+
+	/* set clause 45 mode */
+	val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+	val |= EMAC_MDIO_MODE_CLAUSE_45;
+	EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
+
+	/* address */
+	val = ((bp->phy_addr << 21) | (reg << 16) | addr |
+	       EMAC_MDIO_COMM_COMMAND_ADDRESS |
+	       EMAC_MDIO_COMM_START_BUSY);
+	EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val);
+
+	for (i = 0; i < 50; i++) {
+		udelay(10);
+
+		val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+		if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
+			udelay(5);
+			break;
+		}
+	}
+
+	if (val & EMAC_MDIO_COMM_START_BUSY) {
+		BNX2X_ERR("read phy register failed\n");
+
+		*ret_val = 0;
+		rc = -EBUSY;
+	} else {
+		/* data */
+		val = ((bp->phy_addr << 21) | (reg << 16) |
+		       EMAC_MDIO_COMM_COMMAND_READ_45 |
+		       EMAC_MDIO_COMM_START_BUSY);
+		EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val);
+
+		for (i = 0; i < 50; i++) {
+			udelay(10);
+
+			val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM);
+			if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
+				val &= EMAC_MDIO_COMM_DATA;
+				break;
+			}
+		}
+
+		if (val & EMAC_MDIO_COMM_START_BUSY) {
+			BNX2X_ERR("read phy register failed\n");
+
+			val = 0;
+			rc = -EBUSY;
+		}
+
+		*ret_val = val;
+	}
+
+	/* unset clause 45 mode */
+	val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+	val &= ~EMAC_MDIO_MODE_CLAUSE_45;
+	EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
+
+	if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
+
+		val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+		val |= EMAC_MDIO_MODE_AUTO_POLL;
+		EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val);
+	}
+
+	return rc;
+}
+
+static int bnx2x_mdio45_vwrite(struct bnx2x *bp, u32 reg, u32 addr, u32 val)
+{
+	int i;
+	u32 rd_val;
+
+	might_sleep();
+	for (i = 0; i < 10; i++) {
+		bnx2x_mdio45_write(bp, reg, addr, val);
+		msleep(5);
+		bnx2x_mdio45_read(bp, reg, addr, &rd_val);
+		/* if the read value is not the same as the value we wrote,
+		   we should write it again */
+		if (rd_val == val)
+			return 0;
+	}
+	BNX2X_ERR("MDIO write in CL45 failed\n");
+	return -EBUSY;
+}
+
+/*
+ * link managment
+ */
+
+static void bnx2x_flow_ctrl_resolve(struct bnx2x *bp, u32 gp_status)
+{
+	u32 ld_pause;   /* local driver */
+	u32 lp_pause;   /* link partner */
+	u32 pause_result;
+
+	bp->flow_ctrl = 0;
+
+	/* reolve from gp_status in case of AN complete and not sgmii */
+	if ((bp->req_autoneg & AUTONEG_FLOW_CTRL) &&
+	    (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) &&
+	    (!(bp->phy_flags & PHY_SGMII_FLAG)) &&
+	    (XGXS_EXT_PHY_TYPE(bp) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) {
+
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
+		bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_AUTO_NEG_ADV,
+				  &ld_pause);
+		bnx2x_mdio22_read(bp,
+			MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1,
+				  &lp_pause);
+		pause_result = (ld_pause &
+				MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5;
+		pause_result |= (lp_pause &
+				 MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7;
+		DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result);
+
+		switch (pause_result) { 		/* ASYM P ASYM P */
+		case 0xb:       			/*   1  0   1  1 */
+			bp->flow_ctrl = FLOW_CTRL_TX;
+			break;
+
+		case 0xe:       			/*   1  1   1  0 */
+			bp->flow_ctrl = FLOW_CTRL_RX;
+			break;
+
+		case 0x5:       			/*   0  1   0  1 */
+		case 0x7:       			/*   0  1   1  1 */
+		case 0xd:       			/*   1  1   0  1 */
+		case 0xf:       			/*   1  1   1  1 */
+			bp->flow_ctrl = FLOW_CTRL_BOTH;
+			break;
+
+		default:
+			break;
+		}
+
+	} else { /* forced mode */
+		switch (bp->req_flow_ctrl) {
+		case FLOW_CTRL_AUTO:
+			if (bp->dev->mtu <= 4500)
+				bp->flow_ctrl = FLOW_CTRL_BOTH;
+			else
+				bp->flow_ctrl = FLOW_CTRL_TX;
+			break;
+
+		case FLOW_CTRL_TX:
+		case FLOW_CTRL_RX:
+		case FLOW_CTRL_BOTH:
+			bp->flow_ctrl = bp->req_flow_ctrl;
+			break;
+
+		case FLOW_CTRL_NONE:
+		default:
+			break;
+		}
+	}
+	DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", bp->flow_ctrl);
+}
+
+static void bnx2x_link_settings_status(struct bnx2x *bp, u32 gp_status)
+{
+	bp->link_status = 0;
+
+	if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) {
+		DP(NETIF_MSG_LINK, "link up\n");
+
+		bp->link_up = 1;
+		bp->link_status |= LINK_STATUS_LINK_UP;
+
+		if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS)
+			bp->duplex = DUPLEX_FULL;
+		else
+			bp->duplex = DUPLEX_HALF;
+
+		bnx2x_flow_ctrl_resolve(bp, gp_status);
+
+		switch (gp_status & GP_STATUS_SPEED_MASK) {
+		case GP_STATUS_10M:
+			bp->line_speed = SPEED_10;
+			if (bp->duplex == DUPLEX_FULL)
+				bp->link_status |= LINK_10TFD;
+			else
+				bp->link_status |= LINK_10THD;
+			break;
+
+		case GP_STATUS_100M:
+			bp->line_speed = SPEED_100;
+			if (bp->duplex == DUPLEX_FULL)
+				bp->link_status |= LINK_100TXFD;
+			else
+				bp->link_status |= LINK_100TXHD;
+			break;
+
+		case GP_STATUS_1G:
+		case GP_STATUS_1G_KX:
+			bp->line_speed = SPEED_1000;
+			if (bp->duplex == DUPLEX_FULL)
+				bp->link_status |= LINK_1000TFD;
+			else
+				bp->link_status |= LINK_1000THD;
+			break;
+
+		case GP_STATUS_2_5G:
+			bp->line_speed = SPEED_2500;
+			if (bp->duplex == DUPLEX_FULL)
+				bp->link_status |= LINK_2500TFD;
+			else
+				bp->link_status |= LINK_2500THD;
+			break;
+
+		case GP_STATUS_5G:
+		case GP_STATUS_6G:
+			BNX2X_ERR("link speed unsupported  gp_status 0x%x\n",
+				  gp_status);
+			break;
+
+		case GP_STATUS_10G_KX4:
+		case GP_STATUS_10G_HIG:
+		case GP_STATUS_10G_CX4:
+			bp->line_speed = SPEED_10000;
+			bp->link_status |= LINK_10GTFD;
+			break;
+
+		case GP_STATUS_12G_HIG:
+			bp->line_speed = SPEED_12000;
+			bp->link_status |= LINK_12GTFD;
+			break;
+
+		case GP_STATUS_12_5G:
+			bp->line_speed = SPEED_12500;
+			bp->link_status |= LINK_12_5GTFD;
+			break;
+
+		case GP_STATUS_13G:
+			bp->line_speed = SPEED_13000;
+			bp->link_status |= LINK_13GTFD;
+			break;
+
+		case GP_STATUS_15G:
+			bp->line_speed = SPEED_15000;
+			bp->link_status |= LINK_15GTFD;
+			break;
+
+		case GP_STATUS_16G:
+			bp->line_speed = SPEED_16000;
+			bp->link_status |= LINK_16GTFD;
+			break;
+
+		default:
+			BNX2X_ERR("link speed unsupported  gp_status 0x%x\n",
+				  gp_status);
+			break;
+		}
+
+		bp->link_status |= LINK_STATUS_SERDES_LINK;
+
+		if (bp->req_autoneg & AUTONEG_SPEED) {
+			bp->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
+
+			if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE)
+				bp->link_status |=
+					LINK_STATUS_AUTO_NEGOTIATE_COMPLETE;
+
+			if (bp->autoneg & AUTONEG_PARALLEL)
+				bp->link_status |=
+					LINK_STATUS_PARALLEL_DETECTION_USED;
+		}
+
+		if (bp->flow_ctrl & FLOW_CTRL_TX)
+		       bp->link_status |= LINK_STATUS_TX_FLOW_CONTROL_ENABLED;
+
+		if (bp->flow_ctrl & FLOW_CTRL_RX)
+		       bp->link_status |= LINK_STATUS_RX_FLOW_CONTROL_ENABLED;
+
+	} else { /* link_down */
+		DP(NETIF_MSG_LINK, "link down\n");
+
+		bp->link_up = 0;
+
+		bp->line_speed = 0;
+		bp->duplex = DUPLEX_FULL;
+		bp->flow_ctrl = 0;
+	}
+
+	DP(NETIF_MSG_LINK, "gp_status 0x%x  link_up %d\n"
+	   DP_LEVEL "  line_speed %d  duplex %d  flow_ctrl 0x%x"
+		    "  link_status 0x%x\n",
+	   gp_status, bp->link_up, bp->line_speed, bp->duplex, bp->flow_ctrl,
+	   bp->link_status);
+}
+
+static void bnx2x_link_int_ack(struct bnx2x *bp, int is_10g)
+{
+	int port = bp->port;
+
+	/* first reset all status
+	 * we asume only one line will be change at a time */
+	bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+		       (NIG_XGXS0_LINK_STATUS |
+			NIG_SERDES0_LINK_STATUS |
+			NIG_STATUS_INTERRUPT_XGXS0_LINK10G));
+	if (bp->link_up) {
+		if (is_10g) {
+			/* Disable the 10G link interrupt
+			 * by writing 1 to the status register
+			 */
+			DP(NETIF_MSG_LINK, "10G XGXS link up\n");
+			bnx2x_bits_en(bp,
+				      NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+				      NIG_STATUS_INTERRUPT_XGXS0_LINK10G);
+
+		} else if (bp->phy_flags & PHY_XGXS_FLAG) {
+			/* Disable the link interrupt
+			 * by writing 1 to the relevant lane
+			 * in the status register
+			 */
+			DP(NETIF_MSG_LINK, "1G XGXS link up\n");
+			bnx2x_bits_en(bp,
+				      NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+				      ((1 << bp->ser_lane) <<
+				       NIG_XGXS0_LINK_STATUS_SIZE));
+
+		} else { /* SerDes */
+			DP(NETIF_MSG_LINK, "SerDes link up\n");
+			/* Disable the link interrupt
+			 * by writing 1 to the status register
+			 */
+			bnx2x_bits_en(bp,
+				      NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+				      NIG_SERDES0_LINK_STATUS);
+		}
+
+	} else { /* link_down */
+	}
+}
+
+static int bnx2x_ext_phy_is_link_up(struct bnx2x *bp)
+{
+	u32 ext_phy_type;
+	u32 ext_phy_addr;
+	u32 local_phy;
+	u32 val = 0;
+	u32 rx_sd, pcs_status;
+
+	if (bp->phy_flags & PHY_XGXS_FLAG) {
+		local_phy = bp->phy_addr;
+		ext_phy_addr = ((bp->ext_phy_config &
+				 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+				PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+		bp->phy_addr = (u8)ext_phy_addr;
+
+		ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+			DP(NETIF_MSG_LINK, "XGXS Direct\n");
+			val = 1;
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+			DP(NETIF_MSG_LINK, "XGXS 8705\n");
+			bnx2x_mdio45_read(bp, EXT_PHY_OPT_WIS_DEVAD,
+					  EXT_PHY_OPT_LASI_STATUS, &val);
+			DP(NETIF_MSG_LINK, "8705 LASI status is %d\n", val);
+
+			bnx2x_mdio45_read(bp, EXT_PHY_OPT_WIS_DEVAD,
+					  EXT_PHY_OPT_LASI_STATUS, &val);
+			DP(NETIF_MSG_LINK, "8705 LASI status is %d\n", val);
+
+			bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+					  EXT_PHY_OPT_PMD_RX_SD, &rx_sd);
+			val = (rx_sd & 0x1);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
+			DP(NETIF_MSG_LINK, "XGXS 8706\n");
+			bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+					  EXT_PHY_OPT_LASI_STATUS, &val);
+			DP(NETIF_MSG_LINK, "8706 LASI status is %d\n", val);
+
+			bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+					  EXT_PHY_OPT_LASI_STATUS, &val);
+			DP(NETIF_MSG_LINK, "8706 LASI status is %d\n", val);
+
+			bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+					  EXT_PHY_OPT_PMD_RX_SD, &rx_sd);
+			bnx2x_mdio45_read(bp, EXT_PHY_OPT_PCS_DEVAD,
+					 EXT_PHY_OPT_PCS_STATUS, &pcs_status);
+			DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x"
+			   "  pcs_status 0x%x\n", rx_sd, pcs_status);
+			/* link is up if both bit 0 of pmd_rx and
+			 * bit 0 of pcs_status are set
+			 */
+			val = (rx_sd & pcs_status);
+			break;
+
+		default:
+			DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
+			   bp->ext_phy_config);
+			val = 0;
+			break;
+		}
+		bp->phy_addr = local_phy;
+
+	} else { /* SerDes */
+		ext_phy_type = SERDES_EXT_PHY_TYPE(bp);
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
+			DP(NETIF_MSG_LINK, "SerDes Direct\n");
+			val = 1;
+			break;
+
+		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
+			DP(NETIF_MSG_LINK, "SerDes 5482\n");
+			val = 1;
+			break;
+
+		default:
+			DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
+			   bp->ext_phy_config);
+			val = 0;
+			break;
+		}
+	}
+
+	return val;
+}
+
+static void bnx2x_bmac_enable(struct bnx2x *bp, int is_lb)
+{
+	int port = bp->port;
+	u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM :
+			       NIG_REG_INGRESS_BMAC0_MEM;
+	u32 wb_write[2];
+	u32 val;
+
+	DP(NETIF_MSG_LINK, "enableing BigMAC\n");
+	/* reset and unreset the BigMac */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+	       (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+	msleep(5);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
+	       (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+
+	/* enable access for bmac registers */
+	NIG_WR(NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
+
+	/* XGXS control */
+	wb_write[0] = 0x3c;
+	wb_write[1] = 0;
+	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL,
+		    wb_write, 2);
+
+	/* tx MAC SA */
+	wb_write[0] = ((bp->dev->dev_addr[2] << 24) |
+		       (bp->dev->dev_addr[3] << 16) |
+		       (bp->dev->dev_addr[4] << 8) |
+			bp->dev->dev_addr[5]);
+	wb_write[1] = ((bp->dev->dev_addr[0] << 8) |
+			bp->dev->dev_addr[1]);
+	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR,
+		    wb_write, 2);
+
+	/* tx control */
+	val = 0xc0;
+	if (bp->flow_ctrl & FLOW_CTRL_TX)
+		val |= 0x800000;
+	wb_write[0] = val;
+	wb_write[1] = 0;
+	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_write, 2);
+
+	/* set tx mtu */
+	wb_write[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; /* -CRC */
+	wb_write[1] = 0;
+	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_write, 2);
+
+	/* mac control */
+	val = 0x3;
+	if (is_lb) {
+		val |= 0x4;
+		DP(NETIF_MSG_LINK, "enable bmac loopback\n");
+	}
+	wb_write[0] = val;
+	wb_write[1] = 0;
+	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL,
+		    wb_write, 2);
+
+	/* rx control set to don't strip crc */
+	val = 0x14;
+	if (bp->flow_ctrl & FLOW_CTRL_RX)
+		val |= 0x20;
+	wb_write[0] = val;
+	wb_write[1] = 0;
+	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_write, 2);
+
+	/* set rx mtu */
+	wb_write[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD;
+	wb_write[1] = 0;
+	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_write, 2);
+
+	/* set cnt max size */
+	wb_write[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; /* -VLAN */
+	wb_write[1] = 0;
+	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE,
+		    wb_write, 2);
+
+	/* configure safc */
+	wb_write[0] = 0x1000200;
+	wb_write[1] = 0;
+	REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS,
+		    wb_write, 2);
+
+	/* fix for emulation */
+	if (CHIP_REV(bp) == CHIP_REV_EMUL) {
+		wb_write[0] = 0xf000;
+		wb_write[1] = 0;
+		REG_WR_DMAE(bp,
+			    bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD,
+			    wb_write, 2);
+	}
+
+	/* reset old bmac stats */
+	memset(&bp->old_bmac, 0, sizeof(struct bmac_stats));
+
+	NIG_WR(NIG_REG_XCM0_OUT_EN + port*4, 0x0);
+
+	/* select XGXS */
+	NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1);
+	NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0);
+
+	/* disable the NIG in/out to the emac */
+	NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0x0);
+	NIG_WR(NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0);
+	NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0);
+
+	/* enable the NIG in/out to the bmac */
+	NIG_WR(NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0);
+
+	NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0x1);
+	val = 0;
+	if (bp->flow_ctrl & FLOW_CTRL_TX)
+		val = 1;
+	NIG_WR(NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val);
+	NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0x1);
+
+	bp->phy_flags |= PHY_BMAC_FLAG;
+
+	bp->stats_state = STATS_STATE_ENABLE;
+}
+
+static void bnx2x_emac_enable(struct bnx2x *bp)
+{
+	int port = bp->port;
+	u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+	u32 val;
+	int timeout;
+
+	DP(NETIF_MSG_LINK, "enableing EMAC\n");
+	/* reset and unreset the emac core */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+	       (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
+	msleep(5);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
+	       (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port));
+
+	/* enable emac and not bmac */
+	NIG_WR(NIG_REG_EGRESS_EMAC0_PORT + port*4, 1);
+
+	/* for paladium */
+	if (CHIP_REV(bp) == CHIP_REV_EMUL) {
+		/* Use lane 1 (of lanes 0-3) */
+		NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
+		NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
+	}
+	/* for fpga */
+	else if (CHIP_REV(bp) == CHIP_REV_FPGA) {
+		/* Use lane 1 (of lanes 0-3) */
+		NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1);
+		NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0);
+	}
+	/* ASIC */
+	else {
+		if (bp->phy_flags & PHY_XGXS_FLAG) {
+			DP(NETIF_MSG_LINK, "XGXS\n");
+			/* select the master lanes (out of 0-3) */
+			NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4,
+			       bp->ser_lane);
+			/* select XGXS */
+			NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1);
+
+		} else { /* SerDes */
+			DP(NETIF_MSG_LINK, "SerDes\n");
+			/* select SerDes */
+			NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0);
+		}
+	}
+
+	/* enable emac */
+	NIG_WR(NIG_REG_NIG_EMAC0_EN + port*4, 1);
+
+	/* init emac - use read-modify-write */
+	/* self clear reset */
+	val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
+	EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET));
+
+	timeout = 200;
+	while (val & EMAC_MODE_RESET) {
+		val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
+		DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
+		if (!timeout) {
+			BNX2X_ERR("EMAC timeout!\n");
+			break;
+		}
+		timeout--;
+	}
+
+	/* reset tx part */
+	EMAC_WR(EMAC_REG_EMAC_TX_MODE, EMAC_TX_MODE_RESET);
+
+	timeout = 200;
+	while (val & EMAC_TX_MODE_RESET) {
+		val = REG_RD(bp, emac_base + EMAC_REG_EMAC_TX_MODE);
+		DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val);
+		if (!timeout) {
+			BNX2X_ERR("EMAC timeout!\n");
+			break;
+		}
+		timeout--;
+	}
+
+	if (CHIP_REV_IS_SLOW(bp)) {
+		/* config GMII mode */
+		val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
+		EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII));
+
+	} else { /* ASIC */
+		/* pause enable/disable */
+		bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
+			       EMAC_RX_MODE_FLOW_EN);
+		if (bp->flow_ctrl & FLOW_CTRL_RX)
+			bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE,
+				      EMAC_RX_MODE_FLOW_EN);
+
+		bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
+			       EMAC_TX_MODE_EXT_PAUSE_EN);
+		if (bp->flow_ctrl & FLOW_CTRL_TX)
+			bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE,
+				      EMAC_TX_MODE_EXT_PAUSE_EN);
+	}
+
+	/* KEEP_VLAN_TAG, promiscous */
+	val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE);
+	val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS;
+	EMAC_WR(EMAC_REG_EMAC_RX_MODE, val);
+
+	/* identify magic packets */
+	val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE);
+	EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_MPKT));
+
+	/* enable emac for jumbo packets */
+	EMAC_WR(EMAC_REG_EMAC_RX_MTU_SIZE,
+		(EMAC_RX_MTU_SIZE_JUMBO_ENA |
+		 (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD))); /* -VLAN */
+
+	/* strip CRC */
+	NIG_WR(NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1);
+
+	val = ((bp->dev->dev_addr[0] << 8) |
+		bp->dev->dev_addr[1]);
+	EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val);
+
+	val = ((bp->dev->dev_addr[2] << 24) |
+	       (bp->dev->dev_addr[3] << 16) |
+	       (bp->dev->dev_addr[4] << 8) |
+		bp->dev->dev_addr[5]);
+	EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val);
+
+	/* disable the NIG in/out to the bmac */
+	NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0x0);
+	NIG_WR(NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0);
+	NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0x0);
+
+	/* enable the NIG in/out to the emac */
+	NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0x1);
+	val = 0;
+	if (bp->flow_ctrl & FLOW_CTRL_TX)
+		val = 1;
+	NIG_WR(NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val);
+	NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1);
+
+	if (CHIP_REV(bp) == CHIP_REV_FPGA) {
+		/* take the BigMac out of reset */
+		REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
+		       (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+
+		/* enable access for bmac registers */
+		NIG_WR(NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1);
+	}
+
+	bp->phy_flags |= PHY_EMAC_FLAG;
+
+	bp->stats_state = STATS_STATE_ENABLE;
+}
+
+static void bnx2x_emac_program(struct bnx2x *bp)
+{
+	u16 mode = 0;
+	int port = bp->port;
+
+	DP(NETIF_MSG_LINK, "setting link speed & duplex\n");
+	bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
+		       (EMAC_MODE_25G_MODE |
+			EMAC_MODE_PORT_MII_10M |
+			EMAC_MODE_HALF_DUPLEX));
+	switch (bp->line_speed) {
+	case SPEED_10:
+		mode |= EMAC_MODE_PORT_MII_10M;
+		break;
+
+	case SPEED_100:
+		mode |= EMAC_MODE_PORT_MII;
+		break;
+
+	case SPEED_1000:
+		mode |= EMAC_MODE_PORT_GMII;
+		break;
+
+	case SPEED_2500:
+		mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII);
+		break;
+
+	default:
+		/* 10G not valid for EMAC */
+		BNX2X_ERR("Invalid line_speed 0x%x\n", bp->line_speed);
+		break;
+	}
+
+	if (bp->duplex == DUPLEX_HALF)
+		mode |= EMAC_MODE_HALF_DUPLEX;
+	bnx2x_bits_en(bp, GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE,
+		      mode);
+
+	bnx2x_leds_set(bp, bp->line_speed);
+}
+
+static void bnx2x_set_sgmii_tx_driver(struct bnx2x *bp)
+{
+	u32 lp_up2;
+	u32 tx_driver;
+
+	/* read precomp */
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_OVER_1G);
+	bnx2x_mdio22_read(bp, MDIO_OVER_1G_LP_UP2, &lp_up2);
+
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_TX0);
+	bnx2x_mdio22_read(bp, MDIO_TX0_TX_DRIVER, &tx_driver);
+
+	/* bits [10:7] at lp_up2, positioned at [15:12] */
+	lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >>
+		   MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) <<
+		  MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT);
+
+	if ((lp_up2 != 0) &&
+	    (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) {
+		/* replace tx_driver bits [15:12] */
+		tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK;
+		tx_driver |= lp_up2;
+		bnx2x_mdio22_write(bp, MDIO_TX0_TX_DRIVER, tx_driver);
+	}
+}
+
+static void bnx2x_pbf_update(struct bnx2x *bp)
+{
+	int port = bp->port;
+	u32 init_crd, crd;
+	u32 count = 1000;
+	u32 pause = 0;
+
+
+	/* disable port */
+	REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1);
+
+	/* wait for init credit */
+	init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4);
+	crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
+	DP(NETIF_MSG_LINK, "init_crd 0x%x  crd 0x%x\n", init_crd, crd);
+
+	while ((init_crd != crd) && count) {
+		msleep(5);
+
+		crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
+		count--;
+	}
+	crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8);
+	if (init_crd != crd)
+		BNX2X_ERR("BUG! init_crd 0x%x != crd 0x%x\n", init_crd, crd);
+
+	if (bp->flow_ctrl & FLOW_CTRL_RX)
+		pause = 1;
+	REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, pause);
+	if (pause) {
+		/* update threshold */
+		REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0);
+		/* update init credit */
+		init_crd = 778; 	/* (800-18-4) */
+
+	} else {
+		u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)/16;
+
+		/* update threshold */
+		REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh);
+		/* update init credit */
+		switch (bp->line_speed) {
+		case SPEED_10:
+		case SPEED_100:
+		case SPEED_1000:
+			init_crd = thresh + 55 - 22;
+			break;
+
+		case SPEED_2500:
+			init_crd = thresh + 138 - 22;
+			break;
+
+		case SPEED_10000:
+			init_crd = thresh + 553 - 22;
+			break;
+
+		default:
+			BNX2X_ERR("Invalid line_speed 0x%x\n",
+				  bp->line_speed);
+			break;
+		}
+	}
+	REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd);
+	DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n",
+	   bp->line_speed, init_crd);
+
+	/* probe the credit changes */
+	REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1);
+	msleep(5);
+	REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0);
+
+	/* enable port */
+	REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0);
+}
+
+static void bnx2x_update_mng(struct bnx2x *bp)
+{
+	if (!nomcp)
+		SHMEM_WR(bp, drv_fw_mb[bp->port].link_status,
+			 bp->link_status);
+}
+
+static void bnx2x_link_report(struct bnx2x *bp)
+{
+	if (bp->link_up) {
+		netif_carrier_on(bp->dev);
+		printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name);
+
+		printk("%d Mbps ", bp->line_speed);
+
+		if (bp->duplex == DUPLEX_FULL)
+			printk("full duplex");
+		else
+			printk("half duplex");
+
+		if (bp->flow_ctrl) {
+			if (bp->flow_ctrl & FLOW_CTRL_RX) {
+				printk(", receive ");
+				if (bp->flow_ctrl & FLOW_CTRL_TX)
+					printk("& transmit ");
+			} else {
+				printk(", transmit ");
+			}
+			printk("flow control ON");
+		}
+		printk("\n");
+
+	} else { /* link_down */
+		netif_carrier_off(bp->dev);
+		printk(KERN_INFO PFX "%s NIC Link is Down\n", bp->dev->name);
+	}
+}
+
+static void bnx2x_link_up(struct bnx2x *bp)
+{
+	int port = bp->port;
+
+	/* PBF - link up */
+	bnx2x_pbf_update(bp);
+
+	/* disable drain */
+	NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0);
+
+	/* update shared memory */
+	bnx2x_update_mng(bp);
+
+	/* indicate link up */
+	bnx2x_link_report(bp);
+}
+
+static void bnx2x_link_down(struct bnx2x *bp)
+{
+	int port = bp->port;
+
+	/* notify stats */
+	if (bp->stats_state != STATS_STATE_DISABLE) {
+		bp->stats_state = STATS_STATE_STOP;
+		DP(BNX2X_MSG_STATS, "stats_state - STOP\n");
+	}
+
+	/* indicate link down */
+	bp->phy_flags &= ~(PHY_BMAC_FLAG | PHY_EMAC_FLAG);
+
+	/* reset BigMac */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+	       (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
+
+	/* ignore drain flag interrupt */
+	/* activate nig drain */
+	NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
+
+	/* update shared memory */
+	bnx2x_update_mng(bp);
+
+	/* indicate link down */
+	bnx2x_link_report(bp);
+}
+
+static void bnx2x_init_mac_stats(struct bnx2x *bp);
+
+/* This function is called upon link interrupt */
+static void bnx2x_link_update(struct bnx2x *bp)
+{
+	u32 gp_status;
+	int port = bp->port;
+	int i;
+	int link_10g;
+
+	DP(NETIF_MSG_LINK, "port %x, is xgxs %x, stat_mask 0x%x,"
+	   " int_mask 0x%x, saved_mask 0x%x, MI_INT %x, SERDES_LINK %x,"
+	   " 10G %x, XGXS_LINK %x\n", port, (bp->phy_flags & PHY_XGXS_FLAG),
+	   REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4),
+	   REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), bp->nig_mask,
+	   REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18),
+	   REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c),
+	   REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68),
+	   REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)
+	);
+
+	might_sleep();
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_GP_STATUS);
+	/* avoid fast toggling */
+	for (i = 0 ; i < 10 ; i++) {
+		msleep(10);
+		bnx2x_mdio22_read(bp, MDIO_GP_STATUS_TOP_AN_STATUS1,
+				  &gp_status);
+	}
+
+	bnx2x_link_settings_status(bp, gp_status);
+
+	/* anything 10 and over uses the bmac */
+	link_10g = ((bp->line_speed >= SPEED_10000) &&
+		    (bp->line_speed <= SPEED_16000));
+
+	bnx2x_link_int_ack(bp, link_10g);
+
+	/* link is up only if both local phy and external phy are up */
+	if (bp->link_up && bnx2x_ext_phy_is_link_up(bp)) {
+		if (link_10g) {
+			bnx2x_bmac_enable(bp, 0);
+			bnx2x_leds_set(bp, SPEED_10000);
+
+		} else {
+			bnx2x_emac_enable(bp);
+			bnx2x_emac_program(bp);
+
+			/* AN complete? */
+			if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) {
+				if (!(bp->phy_flags & PHY_SGMII_FLAG))
+					bnx2x_set_sgmii_tx_driver(bp);
+			}
+		}
+		bnx2x_link_up(bp);
+
+	} else { /* link down */
+		bnx2x_leds_unset(bp);
+		bnx2x_link_down(bp);
+	}
+
+	bnx2x_init_mac_stats(bp);
+}
+
+/*
+ * Init service functions
+ */
+
+static void bnx2x_set_aer_mmd(struct bnx2x *bp)
+{
+	u16 offset = (bp->phy_flags & PHY_XGXS_FLAG) ?
+					(bp->phy_addr + bp->ser_lane) : 0;
+
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_AER_BLOCK);
+	bnx2x_mdio22_write(bp, MDIO_AER_BLOCK_AER_REG, 0x3800 + offset);
+}
+
+static void bnx2x_set_master_ln(struct bnx2x *bp)
+{
+	u32 new_master_ln;
+
+	/* set the master_ln for AN */
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_XGXS_BLOCK2);
+	bnx2x_mdio22_read(bp, MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
+			  &new_master_ln);
+	bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_TEST_MODE_LANE,
+			   (new_master_ln | bp->ser_lane));
+}
+
+static void bnx2x_reset_unicore(struct bnx2x *bp)
+{
+	u32 mii_control;
+	int i;
+
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
+	bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control);
+	/* reset the unicore */
+	bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL,
+			   (mii_control | MDIO_COMBO_IEEO_MII_CONTROL_RESET));
+
+	/* wait for the reset to self clear */
+	for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) {
+		udelay(5);
+
+		/* the reset erased the previous bank value */
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
+		bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL,
+				  &mii_control);
+
+		if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) {
+			udelay(5);
+			return;
+		}
+	}
+
+	BNX2X_ERR("BUG! unicore is still in reset!\n");
+}
+
+static void bnx2x_set_swap_lanes(struct bnx2x *bp)
+{
+	/* Each two bits represents a lane number:
+	   No swap is 0123 => 0x1b no need to enable the swap */
+
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_XGXS_BLOCK2);
+	if (bp->rx_lane_swap != 0x1b) {
+		bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_RX_LN_SWAP,
+				   (bp->rx_lane_swap |
+				    MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE |
+				   MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE));
+	} else {
+		bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0);
+	}
+
+	if (bp->tx_lane_swap != 0x1b) {
+		bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_TX_LN_SWAP,
+				   (bp->tx_lane_swap |
+				    MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE));
+	} else {
+		bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0);
+	}
+}
+
+static void bnx2x_set_parallel_detection(struct bnx2x *bp)
+{
+	u32 control2;
+
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL);
+	bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
+			  &control2);
+
+	if (bp->autoneg & AUTONEG_PARALLEL) {
+		control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
+	} else {
+		control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN;
+	}
+	bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL2,
+			   control2);
+
+	if (bp->phy_flags & PHY_XGXS_FLAG) {
+		DP(NETIF_MSG_LINK, "XGXS\n");
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_10G_PARALLEL_DETECT);
+
+		bnx2x_mdio22_write(bp,
+				   MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK,
+			       MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT);
+
+		bnx2x_mdio22_read(bp,
+				 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
+				  &control2);
+
+		if (bp->autoneg & AUTONEG_PARALLEL) {
+			control2 |=
+		    MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
+		} else {
+			control2 &=
+		   ~MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN;
+		}
+		bnx2x_mdio22_write(bp,
+				 MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL,
+				   control2);
+	}
+}
+
+static void bnx2x_set_autoneg(struct bnx2x *bp)
+{
+	u32 reg_val;
+
+	/* CL37 Autoneg */
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
+	bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
+	if ((bp->req_autoneg & AUTONEG_SPEED) &&
+	    (bp->autoneg & AUTONEG_CL37)) {
+		/* CL37 Autoneg Enabled */
+		reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN;
+	} else {
+		/* CL37 Autoneg Disabled */
+		reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
+			     MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN);
+	}
+	bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
+
+	/* Enable/Disable Autodetection */
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL);
+	bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, &reg_val);
+	reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN;
+
+	if ((bp->req_autoneg & AUTONEG_SPEED) &&
+	    (bp->autoneg & AUTONEG_SGMII_FIBER_AUTODET)) {
+		reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
+	} else {
+		reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET;
+	}
+	bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val);
+
+	/* Enable TetonII and BAM autoneg */
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_BAM_NEXT_PAGE);
+	bnx2x_mdio22_read(bp, MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
+			  &reg_val);
+	if ((bp->req_autoneg & AUTONEG_SPEED) &&
+	    (bp->autoneg & AUTONEG_CL37) && (bp->autoneg & AUTONEG_BAM)) {
+		/* Enable BAM aneg Mode and TetonII aneg Mode */
+		reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
+			    MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
+	} else {
+		/* TetonII and BAM Autoneg Disabled */
+		reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE |
+			     MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN);
+	}
+	bnx2x_mdio22_write(bp, MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL,
+			   reg_val);
+
+	/* Enable Clause 73 Aneg */
+	if ((bp->req_autoneg & AUTONEG_SPEED) &&
+	    (bp->autoneg & AUTONEG_CL73)) {
+		/* Enable BAM Station Manager */
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_USERB0);
+		bnx2x_mdio22_write(bp, MDIO_CL73_USERB0_CL73_BAM_CTRL1,
+				   (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN |
+			MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN |
+			MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN));
+
+		/* Merge CL73 and CL37 aneg resolution */
+		bnx2x_mdio22_read(bp, MDIO_CL73_USERB0_CL73_BAM_CTRL3,
+				  &reg_val);
+		bnx2x_mdio22_write(bp, MDIO_CL73_USERB0_CL73_BAM_CTRL3,
+				   (reg_val |
+			MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR));
+
+		/* Set the CL73 AN speed */
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB1);
+		bnx2x_mdio22_read(bp, MDIO_CL73_IEEEB1_AN_ADV2, &reg_val);
+		/* In the SerDes we support only the 1G.
+		   In the XGXS we support the 10G KX4
+		   but we currently do not support the KR */
+		if (bp->phy_flags & PHY_XGXS_FLAG) {
+			DP(NETIF_MSG_LINK, "XGXS\n");
+			/* 10G KX4 */
+			reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4;
+		} else {
+			DP(NETIF_MSG_LINK, "SerDes\n");
+			/* 1000M KX */
+			reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX;
+		}
+		bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB1_AN_ADV2, reg_val);
+
+		/* CL73 Autoneg Enabled */
+		reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN;
+	} else {
+		/* CL73 Autoneg Disabled */
+		reg_val = 0;
+	}
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB0);
+	bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val);
+}
+
+/* program SerDes, forced speed */
+static void bnx2x_program_serdes(struct bnx2x *bp)
+{
+	u32 reg_val;
+
+	/* program duplex, disable autoneg */
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
+	bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, &reg_val);
+	reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX |
+		     MDIO_COMBO_IEEO_MII_CONTROL_AN_EN);
+	if (bp->req_duplex == DUPLEX_FULL)
+		reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
+	bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, reg_val);
+
+	/* program speed
+	   - needed only if the speed is greater than 1G (2.5G or 10G) */
+	if (bp->req_line_speed > SPEED_1000) {
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL);
+		bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_MISC1, &reg_val);
+		/* clearing the speed value before setting the right speed */
+		reg_val &= ~MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK;
+		reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M |
+			    MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL);
+		if (bp->req_line_speed == SPEED_10000)
+			reg_val |=
+				MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4;
+		bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_MISC1, reg_val);
+	}
+}
+
+static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x *bp)
+{
+	u32 val = 0;
+
+	/* configure the 48 bits for BAM AN */
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_OVER_1G);
+
+	/* set extended capabilities */
+	if (bp->advertising & ADVERTISED_2500baseT_Full)
+		val |= MDIO_OVER_1G_UP1_2_5G;
+	if (bp->advertising & ADVERTISED_10000baseT_Full)
+		val |= MDIO_OVER_1G_UP1_10G;
+	bnx2x_mdio22_write(bp, MDIO_OVER_1G_UP1, val);
+
+	bnx2x_mdio22_write(bp, MDIO_OVER_1G_UP3, 0);
+}
+
+static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x *bp)
+{
+	u32 an_adv;
+
+	/* for AN, we are always publishing full duplex */
+	an_adv = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
+
+	/* set pause */
+	switch (bp->pause_mode) {
+	case PAUSE_SYMMETRIC:
+		an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC;
+		break;
+	case PAUSE_ASYMMETRIC:
+		an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+		break;
+	case PAUSE_BOTH:
+		an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+		break;
+	case PAUSE_NONE:
+		an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
+		break;
+	}
+
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
+	bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_AUTO_NEG_ADV, an_adv);
+}
+
+static void bnx2x_restart_autoneg(struct bnx2x *bp)
+{
+	if (bp->autoneg & AUTONEG_CL73) {
+		/* enable and restart clause 73 aneg */
+		u32 an_ctrl;
+
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB0);
+		bnx2x_mdio22_read(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
+				  &an_ctrl);
+		bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
+				   (an_ctrl |
+				    MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN |
+				MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN));
+
+	} else {
+		/* Enable and restart BAM/CL37 aneg */
+		u32 mii_control;
+
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
+		bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL,
+				  &mii_control);
+		bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL,
+				   (mii_control |
+				    MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
+				    MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN));
+	}
+}
+
+static void bnx2x_initialize_sgmii_process(struct bnx2x *bp)
+{
+	u32 control1;
+
+	/* in SGMII mode, the unicore is always slave */
+	MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL);
+	bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
+			  &control1);
+	control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT;
+	/* set sgmii mode (and not fiber) */
+	control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE |
+		      MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET |
+		      MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE);
+	bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1,
+			   control1);
+
+	/* if forced speed */
+	if (!(bp->req_autoneg & AUTONEG_SPEED)) {
+		/* set speed, disable autoneg */
+		u32 mii_control;
+
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
+		bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL,
+				  &mii_control);
+		mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN |
+			       MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK |
+				 MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX);
+
+		switch (bp->req_line_speed) {
+		case SPEED_100:
+			mii_control |=
+				MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100;
+			break;
+		case SPEED_1000:
+			mii_control |=
+				MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000;
+			break;
+		case SPEED_10:
+			/* there is nothing to set for 10M */
+			break;
+		default:
+			/* invalid speed for SGMII */
+			DP(NETIF_MSG_LINK, "Invalid req_line_speed 0x%x\n",
+			   bp->req_line_speed);
+			break;
+		}
+
+		/* setting the full duplex */
+		if (bp->req_duplex == DUPLEX_FULL)
+			mii_control |=
+				MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX;
+		bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL,
+				   mii_control);
+
+	} else { /* AN mode */
+		/* enable and restart AN */
+		bnx2x_restart_autoneg(bp);
+	}
+}
+
+static void bnx2x_link_int_enable(struct bnx2x *bp)
+{
+	int port = bp->port;
+
+	/* setting the status to report on link up
+	   for either XGXS or SerDes */
+	bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4,
+		       (NIG_XGXS0_LINK_STATUS |
+			NIG_STATUS_INTERRUPT_XGXS0_LINK10G |
+			NIG_SERDES0_LINK_STATUS));
+
+	if (bp->phy_flags & PHY_XGXS_FLAG) {
+		/* TBD -
+		 * in force mode (not AN) we can enable just the relevant
+		 * interrupt
+		 * Even in AN we might enable only one according to the AN
+		 * speed mask
+		 */
+		bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+			      (NIG_MASK_XGXS0_LINK_STATUS |
+			       NIG_MASK_XGXS0_LINK10G));
+		DP(NETIF_MSG_LINK, "enable XGXS interrupt\n");
+
+	} else { /* SerDes */
+		bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+			      NIG_MASK_SERDES0_LINK_STATUS);
+		DP(NETIF_MSG_LINK, "enable SerDes interrupt\n");
+	}
+}
+
+static void bnx2x_ext_phy_init(struct bnx2x *bp)
+{
+	int port = bp->port;
+	u32 ext_phy_type;
+	u32 ext_phy_addr;
+	u32 local_phy;
+
+	if (bp->phy_flags & PHY_XGXS_FLAG) {
+		local_phy = bp->phy_addr;
+		ext_phy_addr = ((bp->ext_phy_config &
+				 PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+				PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+		ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+			DP(NETIF_MSG_LINK, "XGXS Direct\n");
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+			DP(NETIF_MSG_LINK, "XGXS 8705\n");
+			bnx2x_bits_en(bp,
+				      NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+				      NIG_MASK_MI_INT);
+			DP(NETIF_MSG_LINK, "enabled extenal phy int\n");
+
+			bp->phy_addr = ext_phy_type;
+			bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+					    EXT_PHY_OPT_PMD_MISC_CNTL,
+					    0x8288);
+			bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+					    EXT_PHY_OPT_PHY_IDENTIFIER,
+					    0x7fbf);
+			bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+					    EXT_PHY_OPT_CMU_PLL_BYPASS,
+					    0x0100);
+			bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_WIS_DEVAD,
+					    EXT_PHY_OPT_LASI_CNTL, 0x1);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
+			DP(NETIF_MSG_LINK, "XGXS 8706\n");
+			bnx2x_bits_en(bp,
+				      NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+				      NIG_MASK_MI_INT);
+			DP(NETIF_MSG_LINK, "enabled extenal phy int\n");
+
+			bp->phy_addr = ext_phy_type;
+			bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+					    EXT_PHY_OPT_PMD_DIGITAL_CNT,
+					    0x400);
+			bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+					    EXT_PHY_OPT_LASI_CNTL, 0x1);
+			break;
+
+		default:
+			DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
+			   bp->ext_phy_config);
+			break;
+		}
+		bp->phy_addr = local_phy;
+
+	} else { /* SerDes */
+/*      	ext_phy_addr = ((bp->ext_phy_config &
+				 PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK) >>
+				PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT);
+*/
+		ext_phy_type = SERDES_EXT_PHY_TYPE(bp);
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
+			DP(NETIF_MSG_LINK, "SerDes Direct\n");
+			break;
+
+		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
+			DP(NETIF_MSG_LINK, "SerDes 5482\n");
+			bnx2x_bits_en(bp,
+				      NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+				      NIG_MASK_MI_INT);
+			DP(NETIF_MSG_LINK, "enabled extenal phy int\n");
+			break;
+
+		default:
+			DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
+			   bp->ext_phy_config);
+			break;
+		}
+	}
+}
+
+static void bnx2x_ext_phy_reset(struct bnx2x *bp)
+{
+	u32 ext_phy_type;
+	u32 ext_phy_addr;
+	u32 local_phy;
+
+	if (bp->phy_flags & PHY_XGXS_FLAG) {
+		ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+			DP(NETIF_MSG_LINK, "XGXS Direct\n");
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
+			DP(NETIF_MSG_LINK, "XGXS 8705/6\n");
+			local_phy = bp->phy_addr;
+			ext_phy_addr = ((bp->ext_phy_config &
+					PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+					PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+			bp->phy_addr = (u8)ext_phy_addr;
+			bnx2x_mdio45_write(bp, EXT_PHY_OPT_PMA_PMD_DEVAD,
+					   EXT_PHY_OPT_CNTL, 0xa040);
+			bp->phy_addr = local_phy;
+			break;
+
+		default:
+			DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n",
+			   bp->ext_phy_config);
+			break;
+		}
+
+	} else { /* SerDes */
+		ext_phy_type = SERDES_EXT_PHY_TYPE(bp);
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
+			DP(NETIF_MSG_LINK, "SerDes Direct\n");
+			break;
+
+		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
+			DP(NETIF_MSG_LINK, "SerDes 5482\n");
+			break;
+
+		default:
+			DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n",
+			   bp->ext_phy_config);
+			break;
+		}
+	}
+}
+
+static void bnx2x_link_initialize(struct bnx2x *bp)
+{
+	int port = bp->port;
+
+	/* disable attentions */
+	bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+		       (NIG_MASK_XGXS0_LINK_STATUS |
+			NIG_MASK_XGXS0_LINK10G |
+			NIG_MASK_SERDES0_LINK_STATUS |
+			NIG_MASK_MI_INT));
+
+	bnx2x_ext_phy_reset(bp);
+
+	bnx2x_set_aer_mmd(bp);
+
+	if (bp->phy_flags & PHY_XGXS_FLAG)
+		bnx2x_set_master_ln(bp);
+
+	/* reset the SerDes and wait for reset bit return low */
+	bnx2x_reset_unicore(bp);
+
+	bnx2x_set_aer_mmd(bp);
+
+	/* setting the masterLn_def again after the reset */
+	if (bp->phy_flags & PHY_XGXS_FLAG) {
+		bnx2x_set_master_ln(bp);
+		bnx2x_set_swap_lanes(bp);
+	}
+
+	/* Set Parallel Detect */
+	if (bp->req_autoneg & AUTONEG_SPEED)
+		bnx2x_set_parallel_detection(bp);
+
+	if (bp->phy_flags & PHY_XGXS_FLAG) {
+		if (bp->req_line_speed &&
+		    bp->req_line_speed < SPEED_1000) {
+			bp->phy_flags |= PHY_SGMII_FLAG;
+		} else {
+			bp->phy_flags &= ~PHY_SGMII_FLAG;
+		}
+	}
+
+	if (!(bp->phy_flags & PHY_SGMII_FLAG)) {
+		u16 bank, rx_eq;
+
+		rx_eq = ((bp->serdes_config &
+			  PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >>
+			 PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT);
+
+		DP(NETIF_MSG_LINK, "setting rx eq to %d\n", rx_eq);
+		for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL;
+			    bank += (MDIO_REG_BANK_RX1 - MDIO_REG_BANK_RX0)) {
+			MDIO_SET_REG_BANK(bp, bank);
+			bnx2x_mdio22_write(bp, MDIO_RX0_RX_EQ_BOOST,
+					   ((rx_eq &
+				MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) |
+				MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL));
+		}
+
+		/* forced speed requested? */
+		if (!(bp->req_autoneg & AUTONEG_SPEED)) {
+			DP(NETIF_MSG_LINK, "not SGMII, no AN\n");
+
+			/* disable autoneg */
+			bnx2x_set_autoneg(bp);
+
+			/* program speed and duplex */
+			bnx2x_program_serdes(bp);
+
+		} else { /* AN_mode */
+			DP(NETIF_MSG_LINK, "not SGMII, AN\n");
+
+			/* AN enabled */
+			bnx2x_set_brcm_cl37_advertisment(bp);
+
+			/* program duplex & pause advertisment (for aneg) */
+			bnx2x_set_ieee_aneg_advertisment(bp);
+
+			/* enable autoneg */
+			bnx2x_set_autoneg(bp);
+
+			/* enalbe and restart AN */
+			bnx2x_restart_autoneg(bp);
+		}
+
+	} else { /* SGMII mode */
+		DP(NETIF_MSG_LINK, "SGMII\n");
+
+		bnx2x_initialize_sgmii_process(bp);
+	}
+
+	/* enable the interrupt */
+	bnx2x_link_int_enable(bp);
+
+	/* init ext phy and enable link state int */
+	bnx2x_ext_phy_init(bp);
+}
+
+static void bnx2x_phy_deassert(struct bnx2x *bp)
+{
+	int port = bp->port;
+	u32 val;
+
+	if (bp->phy_flags & PHY_XGXS_FLAG) {
+		DP(NETIF_MSG_LINK, "XGXS\n");
+		val = XGXS_RESET_BITS;
+
+	} else { /* SerDes */
+		DP(NETIF_MSG_LINK, "SerDes\n");
+		val = SERDES_RESET_BITS;
+	}
+
+	val = val << (port*16);
+
+	/* reset and unreset the SerDes/XGXS */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val);
+	msleep(5);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val);
+}
+
+static int bnx2x_phy_init(struct bnx2x *bp)
+{
+	DP(NETIF_MSG_LINK, "started\n");
+	if (CHIP_REV(bp) == CHIP_REV_FPGA) {
+		bp->phy_flags |= PHY_EMAC_FLAG;
+		bp->link_up = 1;
+		bp->line_speed = SPEED_10000;
+		bp->duplex = DUPLEX_FULL;
+		NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + bp->port*4, 0);
+		bnx2x_emac_enable(bp);
+		bnx2x_link_report(bp);
+		return 0;
+
+	} else if (CHIP_REV(bp) == CHIP_REV_EMUL) {
+		bp->phy_flags |= PHY_BMAC_FLAG;
+		bp->link_up = 1;
+		bp->line_speed = SPEED_10000;
+		bp->duplex = DUPLEX_FULL;
+		NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + bp->port*4, 0);
+		bnx2x_bmac_enable(bp, 0);
+		bnx2x_link_report(bp);
+		return 0;
+
+	} else {
+		bnx2x_phy_deassert(bp);
+		bnx2x_link_initialize(bp);
+	}
+
+	return 0;
+}
+
+static void bnx2x_link_reset(struct bnx2x *bp)
+{
+	int port = bp->port;
+
+	/* disable attentions */
+	bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+		       (NIG_MASK_XGXS0_LINK_STATUS |
+			NIG_MASK_XGXS0_LINK10G |
+			NIG_MASK_SERDES0_LINK_STATUS |
+			NIG_MASK_MI_INT));
+
+	bnx2x_ext_phy_reset(bp);
+
+	/* reset the SerDes/XGXS */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR,
+	       (0x1ff << (port*16)));
+
+	/* reset EMAC / BMAC and disable NIG interfaces */
+	NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0);
+	NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0);
+
+	NIG_WR(NIG_REG_NIG_EMAC0_EN + port*4, 0);
+	NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0);
+	NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0);
+
+	NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1);
+}
+
+#ifdef BNX2X_XGXS_LB
+static void bnx2x_set_xgxs_loopback(struct bnx2x *bp, int is_10g)
+{
+	int port = bp->port;
+
+	if (is_10g) {
+		u32 md_devad;
+
+		DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n");
+
+		/* change the uni_phy_addr in the nig */
+		REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18),
+		       &md_devad);
+		NIG_WR(NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5);
+
+		/* change the aer mmd */
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_AER_BLOCK);
+		bnx2x_mdio22_write(bp, MDIO_AER_BLOCK_AER_REG, 0x2800);
+
+		/* config combo IEEE0 control reg for loopback */
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB0);
+		bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL,
+				   0x6041);
+
+		/* set aer mmd back */
+		bnx2x_set_aer_mmd(bp);
+
+		/* and md_devad */
+		NIG_WR(NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad);
+
+	} else {
+		u32 mii_control;
+
+		DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n");
+
+		MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0);
+		bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL,
+				  &mii_control);
+		bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL,
+				   (mii_control |
+				    MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK));
+	}
+}
+#endif
+
+/* end of PHY/MAC */
+
+/* slow path */
+
+/*
+ * General service functions
+ */
+
+/* the slow path queue is odd since completions arrive on the fastpath ring */
+static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
+			 u32 data_hi, u32 data_lo, int common)
+{
+	int port = bp->port;
+
+	DP(NETIF_MSG_TIMER,
+	   "spe (%x:%x)  command %x  hw_cid %x  data (%x:%x)  left %x\n",
+	   (u32)U64_HI(bp->spq_mapping), (u32)(U64_LO(bp->spq_mapping) +
+	   (void *)bp->spq_prod_bd - (void *)bp->spq), command,
+	   HW_CID(bp, cid), data_hi, data_lo, bp->spq_left);
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return -EIO;
+#endif
+
+	spin_lock(&bp->spq_lock);
+
+	if (!bp->spq_left) {
+		BNX2X_ERR("BUG! SPQ ring full!\n");
+		spin_unlock(&bp->spq_lock);
+		bnx2x_panic();
+		return -EBUSY;
+	}
+	/* CID needs port number to be encoded int it */
+	bp->spq_prod_bd->hdr.conn_and_cmd_data =
+			cpu_to_le32(((command << SPE_HDR_CMD_ID_SHIFT) |
+				     HW_CID(bp, cid)));
+	bp->spq_prod_bd->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
+	if (common)
+		bp->spq_prod_bd->hdr.type |=
+			cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT));
+
+	bp->spq_prod_bd->data.mac_config_addr.hi = cpu_to_le32(data_hi);
+	bp->spq_prod_bd->data.mac_config_addr.lo = cpu_to_le32(data_lo);
+
+	bp->spq_left--;
+
+	if (bp->spq_prod_bd == bp->spq_last_bd) {
+		bp->spq_prod_bd = bp->spq;
+		bp->spq_prod_idx = 0;
+		DP(NETIF_MSG_TIMER, "end of spq\n");
+
+	} else {
+		bp->spq_prod_bd++;
+		bp->spq_prod_idx++;
+	}
+
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(port),
+	       bp->spq_prod_idx);
+
+	spin_unlock(&bp->spq_lock);
+	return 0;
+}
+
+/* acquire split MCP access lock register */
+static int bnx2x_lock_alr(struct bnx2x *bp)
+{
+	int rc = 0;
+	u32 i, j, val;
+
+	might_sleep();
+	i = 100;
+	for (j = 0; j < i*10; j++) {
+		val = (1UL << 31);
+		REG_WR(bp, GRCBASE_MCP + 0x9c, val);
+		val = REG_RD(bp, GRCBASE_MCP + 0x9c);
+		if (val & (1L << 31))
+			break;
+
+		msleep(5);
+	}
+
+	if (!(val & (1L << 31))) {
+		BNX2X_ERR("Cannot acquire nvram interface\n");
+
+		rc = -EBUSY;
+	}
+
+	return rc;
+}
+
+/* Release split MCP access lock register */
+static void bnx2x_unlock_alr(struct bnx2x *bp)
+{
+	u32 val = 0;
+
+	REG_WR(bp, GRCBASE_MCP + 0x9c, val);
+}
+
+static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp)
+{
+	struct host_def_status_block *def_sb = bp->def_status_blk;
+	u16 rc = 0;
+
+	barrier(); /* status block is written to by the chip */
+
+	if (bp->def_att_idx != def_sb->atten_status_block.attn_bits_index) {
+		bp->def_att_idx = def_sb->atten_status_block.attn_bits_index;
+		rc |= 1;
+	}
+	if (bp->def_c_idx != def_sb->c_def_status_block.status_block_index) {
+		bp->def_c_idx = def_sb->c_def_status_block.status_block_index;
+		rc |= 2;
+	}
+	if (bp->def_u_idx != def_sb->u_def_status_block.status_block_index) {
+		bp->def_u_idx = def_sb->u_def_status_block.status_block_index;
+		rc |= 4;
+	}
+	if (bp->def_x_idx != def_sb->x_def_status_block.status_block_index) {
+		bp->def_x_idx = def_sb->x_def_status_block.status_block_index;
+		rc |= 8;
+	}
+	if (bp->def_t_idx != def_sb->t_def_status_block.status_block_index) {
+		bp->def_t_idx = def_sb->t_def_status_block.status_block_index;
+		rc |= 16;
+	}
+	return rc;
+}
+
+/*
+ * slow path service functions
+ */
+
+static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
+{
+	int port = bp->port;
+	u32 igu_addr = (IGU_ADDR_ATTN_BITS_SET + IGU_PORT_BASE * port) * 8;
+	u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
+			      MISC_REG_AEU_MASK_ATTN_FUNC_0;
+	u32 nig_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 :
+				   NIG_REG_MASK_INTERRUPT_PORT0;
+
+	if (~bp->aeu_mask & (asserted & 0xff))
+		BNX2X_ERR("IGU ERROR\n");
+	if (bp->attn_state & asserted)
+		BNX2X_ERR("IGU ERROR\n");
+
+	DP(NETIF_MSG_HW, "aeu_mask %x  newly asserted %x\n",
+	   bp->aeu_mask, asserted);
+	bp->aeu_mask &= ~(asserted & 0xff);
+	DP(NETIF_MSG_HW, "after masking: aeu_mask %x\n", bp->aeu_mask);
+
+	REG_WR(bp, aeu_addr, bp->aeu_mask);
+
+	bp->attn_state |= asserted;
+
+	if (asserted & ATTN_HARD_WIRED_MASK) {
+		if (asserted & ATTN_NIG_FOR_FUNC) {
+			u32 nig_status_port;
+			u32 nig_int_addr = port ?
+					NIG_REG_STATUS_INTERRUPT_PORT1 :
+					NIG_REG_STATUS_INTERRUPT_PORT0;
+
+			bp->nig_mask = REG_RD(bp, nig_mask_addr);
+			REG_WR(bp, nig_mask_addr, 0);
+
+			nig_status_port = REG_RD(bp, nig_int_addr);
+			bnx2x_link_update(bp);
+
+			/* handle unicore attn? */
+		}
+		if (asserted & ATTN_SW_TIMER_4_FUNC)
+			DP(NETIF_MSG_HW, "ATTN_SW_TIMER_4_FUNC!\n");
+
+		if (asserted & GPIO_2_FUNC)
+			DP(NETIF_MSG_HW, "GPIO_2_FUNC!\n");
+
+		if (asserted & GPIO_3_FUNC)
+			DP(NETIF_MSG_HW, "GPIO_3_FUNC!\n");
+
+		if (asserted & GPIO_4_FUNC)
+			DP(NETIF_MSG_HW, "GPIO_4_FUNC!\n");
+
+		if (port == 0) {
+			if (asserted & ATTN_GENERAL_ATTN_1) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_1!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_1, 0x0);
+			}
+			if (asserted & ATTN_GENERAL_ATTN_2) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_2!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_2, 0x0);
+			}
+			if (asserted & ATTN_GENERAL_ATTN_3) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_3!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_3, 0x0);
+			}
+		} else {
+			if (asserted & ATTN_GENERAL_ATTN_4) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_4!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_4, 0x0);
+			}
+			if (asserted & ATTN_GENERAL_ATTN_5) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_5!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_5, 0x0);
+			}
+			if (asserted & ATTN_GENERAL_ATTN_6) {
+				DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_6!\n");
+				REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_6, 0x0);
+			}
+		}
+
+	} /* if hardwired */
+
+	DP(NETIF_MSG_HW, "about to mask 0x%08x at IGU addr 0x%x\n",
+	   asserted, BAR_IGU_INTMEM + igu_addr);
+	REG_WR(bp, BAR_IGU_INTMEM + igu_addr, asserted);
+
+	/* now set back the mask */
+	if (asserted & ATTN_NIG_FOR_FUNC)
+		REG_WR(bp, nig_mask_addr, bp->nig_mask);
+}
+
+static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
+{
+	int port = bp->port;
+	int index;
+	struct attn_route attn;
+	struct attn_route group_mask;
+	u32 reg_addr;
+	u32 val;
+
+	/* need to take HW lock because MCP or other port might also
+	   try to handle this event */
+	bnx2x_lock_alr(bp);
+
+	attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4);
+	attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4);
+	attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4);
+	attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4);
+	DP(NETIF_MSG_HW, "attn %llx\n", (unsigned long long)attn.sig[0]);
+
+	for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
+		if (deasserted & (1 << index)) {
+			group_mask = bp->attn_group[index];
+
+			DP(NETIF_MSG_HW, "group[%d]: %llx\n", index,
+			   (unsigned long long)group_mask.sig[0]);
+
+			if (attn.sig[3] & group_mask.sig[3] &
+			    EVEREST_GEN_ATTN_IN_USE_MASK) {
+
+				if (attn.sig[3] & BNX2X_MC_ASSERT_BITS) {
+
+					BNX2X_ERR("MC assert!\n");
+					bnx2x_panic();
+
+				} else if (attn.sig[3] & BNX2X_MCP_ASSERT) {
+
+					BNX2X_ERR("MCP assert!\n");
+					REG_WR(bp,
+					     MISC_REG_AEU_GENERAL_ATTN_11, 0);
+					bnx2x_mc_assert(bp);
+
+				} else {
+					BNX2X_ERR("UNKOWEN HW ASSERT!\n");
+				}
+			}
+
+			if (attn.sig[1] & group_mask.sig[1] &
+			    BNX2X_DOORQ_ASSERT) {
+
+				val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR);
+				BNX2X_ERR("DB hw attention 0x%x\n", val);
+				/* DORQ discard attention */
+				if (val & 0x2)
+					BNX2X_ERR("FATAL error from DORQ\n");
+			}
+
+			if (attn.sig[2] & group_mask.sig[2] &
+			    AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) {
+
+				val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR);
+				BNX2X_ERR("CFC hw attention 0x%x\n", val);
+				/* CFC error attention */
+				if (val & 0x2)
+					BNX2X_ERR("FATAL error from CFC\n");
+			}
+
+			if (attn.sig[2] & group_mask.sig[2] &
+			    AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) {
+
+				val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0);
+				BNX2X_ERR("PXP hw attention 0x%x\n", val);
+				/* RQ_USDMDP_FIFO_OVERFLOW */
+				if (val & 0x18000)
+					BNX2X_ERR("FATAL error from PXP\n");
+			}
+
+			if (attn.sig[3] & group_mask.sig[3] &
+			    EVEREST_LATCHED_ATTN_IN_USE_MASK) {
+
+				REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL,
+				       0x7ff);
+				DP(NETIF_MSG_HW, "got latched bits 0x%x\n",
+				   attn.sig[3]);
+			}
+
+			if ((attn.sig[0] & group_mask.sig[0] &
+						HW_INTERRUT_ASSERT_SET_0) ||
+			    (attn.sig[1] & group_mask.sig[1] &
+						HW_INTERRUT_ASSERT_SET_1) ||
+			    (attn.sig[2] & group_mask.sig[2] &
+						HW_INTERRUT_ASSERT_SET_2))
+				BNX2X_ERR("FATAL HW block attention\n");
+
+			if ((attn.sig[0] & group_mask.sig[0] &
+						HW_PRTY_ASSERT_SET_0) ||
+			    (attn.sig[1] & group_mask.sig[1] &
+						HW_PRTY_ASSERT_SET_1) ||
+			    (attn.sig[2] & group_mask.sig[2] &
+						HW_PRTY_ASSERT_SET_2))
+				BNX2X_ERR("FATAL HW block parity atention\n");
+		}
+	}
+
+	bnx2x_unlock_alr(bp);
+
+	reg_addr = (IGU_ADDR_ATTN_BITS_CLR + IGU_PORT_BASE * port) * 8;
+
+	val = ~deasserted;
+/*      DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n",
+	   val, BAR_IGU_INTMEM + reg_addr); */
+	REG_WR(bp, BAR_IGU_INTMEM + reg_addr, val);
+
+	if (bp->aeu_mask & (deasserted & 0xff))
+		BNX2X_ERR("IGU BUG\n");
+	if (~bp->attn_state & deasserted)
+		BNX2X_ERR("IGU BUG\n");
+
+	reg_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
+			  MISC_REG_AEU_MASK_ATTN_FUNC_0;
+
+	DP(NETIF_MSG_HW, "aeu_mask %x\n", bp->aeu_mask);
+	bp->aeu_mask |= (deasserted & 0xff);
+
+	DP(NETIF_MSG_HW, "new mask %x\n", bp->aeu_mask);
+	REG_WR(bp, reg_addr, bp->aeu_mask);
+
+	DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state);
+	bp->attn_state &= ~deasserted;
+	DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state);
+}
+
+static void bnx2x_attn_int(struct bnx2x *bp)
+{
+	/* read local copy of bits */
+	u32 attn_bits = bp->def_status_blk->atten_status_block.attn_bits;
+	u32 attn_ack = bp->def_status_blk->atten_status_block.attn_bits_ack;
+	u32 attn_state = bp->attn_state;
+
+	/* look for changed bits */
+	u32 asserted   =  attn_bits & ~attn_ack & ~attn_state;
+	u32 deasserted = ~attn_bits &  attn_ack &  attn_state;
+
+	DP(NETIF_MSG_HW,
+	   "attn_bits %x  attn_ack %x  asserted %x  deasserted %x\n",
+	   attn_bits, attn_ack, asserted, deasserted);
+
+	if (~(attn_bits ^ attn_ack) & (attn_bits ^ attn_state))
+		BNX2X_ERR("bad attention state\n");
+
+	/* handle bits that were raised */
+	if (asserted)
+		bnx2x_attn_int_asserted(bp, asserted);
+
+	if (deasserted)
+		bnx2x_attn_int_deasserted(bp, deasserted);
+}
+
+static void bnx2x_sp_task(struct work_struct *work)
+{
+	struct bnx2x *bp = container_of(work, struct bnx2x, sp_task);
+	u16 status;
+
+	/* Return here if interrupt is disabled */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
+		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+		return;
+	}
+
+	status = bnx2x_update_dsb_idx(bp);
+	if (status == 0)
+		BNX2X_ERR("spurious slowpath interrupt!\n");
+
+	DP(NETIF_MSG_INTR, "got a slowpath interrupt (updated %x)\n", status);
+
+	if (status & 0x1) {
+		/* HW attentions */
+		bnx2x_attn_int(bp);
+	}
+
+	/* CStorm events: query_stats, cfc delete ramrods */
+	if (status & 0x2)
+		bp->stat_pending = 0;
+
+	bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, bp->def_att_idx,
+		     IGU_INT_NOP, 1);
+	bnx2x_ack_sb(bp, DEF_SB_ID, USTORM_ID, le16_to_cpu(bp->def_u_idx),
+		     IGU_INT_NOP, 1);
+	bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, le16_to_cpu(bp->def_c_idx),
+		     IGU_INT_NOP, 1);
+	bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, le16_to_cpu(bp->def_x_idx),
+		     IGU_INT_NOP, 1);
+	bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx),
+		     IGU_INT_ENABLE, 1);
+}
+
+static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
+{
+	struct net_device *dev = dev_instance;
+	struct bnx2x *bp = netdev_priv(dev);
+
+	/* Return here if interrupt is disabled */
+	if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
+		DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
+		return IRQ_HANDLED;
+	}
+
+	bnx2x_ack_sb(bp, 16, XSTORM_ID, 0, IGU_INT_DISABLE, 0);
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return IRQ_HANDLED;
+#endif
+
+	schedule_work(&bp->sp_task);
+
+	return IRQ_HANDLED;
+}
+
+/* end of slow path */
+
+/* Statistics */
+
+/****************************************************************************
+* Macros
+****************************************************************************/
+
+#define UPDATE_STAT(s, t) \
+	do { \
+		estats->t += new->s - old->s; \
+		old->s = new->s; \
+	} while (0)
+
+/* sum[hi:lo] += add[hi:lo] */
+#define ADD_64(s_hi, a_hi, s_lo, a_lo) \
+	do { \
+		s_lo += a_lo; \
+		s_hi += a_hi + (s_lo < a_lo) ? 1 : 0; \
+	} while (0)
+
+/* difference = minuend - subtrahend */
+#define DIFF_64(d_hi, m_hi, s_hi, d_lo, m_lo, s_lo) \
+	do { \
+		if (m_lo < s_lo) {      /* underflow */ \
+			d_hi = m_hi - s_hi; \
+			if (d_hi > 0) { /* we can 'loan' 1 */ \
+				d_hi--; \
+				d_lo = m_lo + (UINT_MAX - s_lo) + 1; \
+			} else {	/* m_hi <= s_hi */ \
+				d_hi = 0; \
+				d_lo = 0; \
+			} \
+		} else {		/* m_lo >= s_lo */ \
+			if (m_hi < s_hi) { \
+			    d_hi = 0; \
+			    d_lo = 0; \
+			} else {	/* m_hi >= s_hi */ \
+			    d_hi = m_hi - s_hi; \
+			    d_lo = m_lo - s_lo; \
+			} \
+		} \
+	} while (0)
+
+/* minuend -= subtrahend */
+#define SUB_64(m_hi, s_hi, m_lo, s_lo) \
+	do { \
+		DIFF_64(m_hi, m_hi, s_hi, m_lo, m_lo, s_lo); \
+	} while (0)
+
+#define UPDATE_STAT64(s_hi, t_hi, s_lo, t_lo) \
+	do { \
+		DIFF_64(diff.hi, new->s_hi, old->s_hi, \
+			diff.lo, new->s_lo, old->s_lo); \
+		old->s_hi = new->s_hi; \
+		old->s_lo = new->s_lo; \
+		ADD_64(estats->t_hi, diff.hi, \
+		       estats->t_lo, diff.lo); \
+	} while (0)
+
+/* sum[hi:lo] += add */
+#define ADD_EXTEND_64(s_hi, s_lo, a) \
+	do { \
+		s_lo += a; \
+		s_hi += (s_lo < a) ? 1 : 0; \
+	} while (0)
+
+#define UPDATE_EXTEND_STAT(s, t_hi, t_lo) \
+	do { \
+		ADD_EXTEND_64(estats->t_hi, estats->t_lo, new->s); \
+	} while (0)
+
+#define UPDATE_EXTEND_TSTAT(s, t_hi, t_lo) \
+	do { \
+		diff = le32_to_cpu(tclient->s) - old_tclient->s; \
+		old_tclient->s = le32_to_cpu(tclient->s); \
+		ADD_EXTEND_64(estats->t_hi, estats->t_lo, diff); \
+	} while (0)
+
+/*
+ * General service functions
+ */
+
+static inline long bnx2x_hilo(u32 *hiref)
+{
+	u32 lo = *(hiref + 1);
+#if (BITS_PER_LONG == 64)
+	u32 hi = *hiref;
+
+	return HILO_U64(hi, lo);
+#else
+	return lo;
+#endif
+}
+
+/*
+ * Init service functions
+ */
+
+static void bnx2x_init_mac_stats(struct bnx2x *bp)
+{
+	struct dmae_command *dmae;
+	int port = bp->port;
+	int loader_idx = port * 8;
+	u32 opcode;
+	u32 mac_addr;
+
+	bp->executer_idx = 0;
+	if (bp->fw_mb) {
+		/* MCP */
+		opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+			  DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+			  DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+			  DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+			  (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0));
+
+		if (bp->link_up)
+			opcode |= (DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE);
+
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, eth_stats) +
+					   sizeof(u32));
+		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, eth_stats) +
+					   sizeof(u32));
+		dmae->dst_addr_lo = bp->fw_mb >> 2;
+		dmae->dst_addr_hi = 0;
+		dmae->len = (offsetof(struct bnx2x_eth_stats, mac_stx_end) -
+			     sizeof(u32)) >> 2;
+		if (bp->link_up) {
+			dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+			dmae->comp_addr_hi = 0;
+			dmae->comp_val = 1;
+		} else {
+			dmae->comp_addr_lo = 0;
+			dmae->comp_addr_hi = 0;
+			dmae->comp_val = 0;
+		}
+	}
+
+	if (!bp->link_up) {
+		/* no need to collect statistics in link down */
+		return;
+	}
+
+	opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+		  DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
+		  DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+		  DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+		  DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+		  (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0));
+
+	if (bp->phy_flags & PHY_BMAC_FLAG) {
+
+		mac_addr = (port ? NIG_REG_INGRESS_BMAC1_MEM :
+				   NIG_REG_INGRESS_BMAC0_MEM);
+
+		/* BIGMAC_REGISTER_TX_STAT_GTPKT ..
+		   BIGMAC_REGISTER_TX_STAT_GTBYT */
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = (mac_addr +
+				     BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
+		dmae->src_addr_hi = 0;
+		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
+		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
+		dmae->len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT -
+			     BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+
+		/* BIGMAC_REGISTER_RX_STAT_GR64 ..
+		   BIGMAC_REGISTER_RX_STAT_GRIPJ */
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = (mac_addr +
+				     BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
+		dmae->src_addr_hi = 0;
+		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+					offsetof(struct bmac_stats, rx_gr64));
+		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+					offsetof(struct bmac_stats, rx_gr64));
+		dmae->len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ -
+			     BIGMAC_REGISTER_RX_STAT_GR64) >> 2;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+
+	} else if (bp->phy_flags & PHY_EMAC_FLAG) {
+
+		mac_addr = (port ? GRCBASE_EMAC1 : GRCBASE_EMAC0);
+
+		/* EMAC_REG_EMAC_RX_STAT_AC (EMAC_REG_EMAC_RX_STAT_AC_COUNT)*/
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = (mac_addr +
+				     EMAC_REG_EMAC_RX_STAT_AC) >> 2;
+		dmae->src_addr_hi = 0;
+		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats));
+		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats));
+		dmae->len = EMAC_REG_EMAC_RX_STAT_AC_COUNT;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+
+		/* EMAC_REG_EMAC_RX_STAT_AC_28 */
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = (mac_addr +
+				     EMAC_REG_EMAC_RX_STAT_AC_28) >> 2;
+		dmae->src_addr_hi = 0;
+		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+					   offsetof(struct emac_stats,
+						    rx_falsecarriererrors));
+		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+					   offsetof(struct emac_stats,
+						    rx_falsecarriererrors));
+		dmae->len = 1;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+
+		/* EMAC_REG_EMAC_TX_STAT_AC (EMAC_REG_EMAC_TX_STAT_AC_COUNT)*/
+		dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+		dmae->opcode = opcode;
+		dmae->src_addr_lo = (mac_addr +
+				     EMAC_REG_EMAC_TX_STAT_AC) >> 2;
+		dmae->src_addr_hi = 0;
+		dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) +
+					   offsetof(struct emac_stats,
+						    tx_ifhcoutoctets));
+		dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) +
+					   offsetof(struct emac_stats,
+						    tx_ifhcoutoctets));
+		dmae->len = EMAC_REG_EMAC_TX_STAT_AC_COUNT;
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+	}
+
+	/* NIG */
+	dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]);
+	dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
+			DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
+			DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+			DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+			DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+			(port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0));
+	dmae->src_addr_lo = (port ? NIG_REG_STAT1_BRB_DISCARD :
+				    NIG_REG_STAT0_BRB_DISCARD) >> 2;
+	dmae->src_addr_hi = 0;
+	dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig));
+	dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig));
+	dmae->len = (sizeof(struct nig_stats) - 2*sizeof(u32)) >> 2;
+	dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig) +
+				    offsetof(struct nig_stats, done));
+	dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig) +
+				    offsetof(struct nig_stats, done));
+	dmae->comp_val = 0xffffffff;
+}
+
+static void bnx2x_init_stats(struct bnx2x *bp)
+{
+	int port = bp->port;
+
+	bp->stats_state = STATS_STATE_DISABLE;
+	bp->executer_idx = 0;
+
+	bp->old_brb_discard = REG_RD(bp,
+				     NIG_REG_STAT0_BRB_DISCARD + port*0x38);
+
+	memset(&bp->old_bmac, 0, sizeof(struct bmac_stats));
+	memset(&bp->old_tclient, 0, sizeof(struct tstorm_per_client_stats));
+	memset(&bp->dev->stats, 0, sizeof(struct net_device_stats));
+
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port), 1);
+	REG_WR(bp, BAR_XSTRORM_INTMEM +
+	       XSTORM_STATS_FLAGS_OFFSET(port) + 4, 0);
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port), 1);
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_STATS_FLAGS_OFFSET(port) + 4, 0);
+
+	REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port), 0);
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       CSTORM_STATS_FLAGS_OFFSET(port) + 4, 0);
+
+	REG_WR(bp, BAR_XSTRORM_INTMEM +
+	       XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port),
+	       U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
+	REG_WR(bp, BAR_XSTRORM_INTMEM +
+	       XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port) + 4,
+	       U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port),
+	       U64_LO(bnx2x_sp_mapping(bp, fw_stats)));
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port) + 4,
+	       U64_HI(bnx2x_sp_mapping(bp, fw_stats)));
+}
+
+static void bnx2x_stop_stats(struct bnx2x *bp)
+{
+	might_sleep();
+	if (bp->stats_state != STATS_STATE_DISABLE) {
+		int timeout = 10;
+
+		bp->stats_state = STATS_STATE_STOP;
+		DP(BNX2X_MSG_STATS, "stats_state - STOP\n");
+
+		while (bp->stats_state != STATS_STATE_DISABLE) {
+			if (!timeout) {
+				BNX2X_ERR("timeout wating for stats stop\n");
+				break;
+			}
+			timeout--;
+			msleep(100);
+		}
+	}
+	DP(BNX2X_MSG_STATS, "stats_state - DISABLE\n");
+}
+
+/*
+ * Statistics service functions
+ */
+
+static void bnx2x_update_bmac_stats(struct bnx2x *bp)
+{
+	struct regp diff;
+	struct regp sum;
+	struct bmac_stats *new = bnx2x_sp(bp, mac_stats.bmac);
+	struct bmac_stats *old = &bp->old_bmac;
+	struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats);
+
+	sum.hi = 0;
+	sum.lo = 0;
+
+	UPDATE_STAT64(tx_gtbyt.hi, total_bytes_transmitted_hi,
+		      tx_gtbyt.lo, total_bytes_transmitted_lo);
+
+	UPDATE_STAT64(tx_gtmca.hi, total_multicast_packets_transmitted_hi,
+		      tx_gtmca.lo, total_multicast_packets_transmitted_lo);
+	ADD_64(sum.hi, diff.hi, sum.lo, diff.lo);
+
+	UPDATE_STAT64(tx_gtgca.hi, total_broadcast_packets_transmitted_hi,
+		      tx_gtgca.lo, total_broadcast_packets_transmitted_lo);
+	ADD_64(sum.hi, diff.hi, sum.lo, diff.lo);
+
+	UPDATE_STAT64(tx_gtpkt.hi, total_unicast_packets_transmitted_hi,
+		      tx_gtpkt.lo, total_unicast_packets_transmitted_lo);
+	SUB_64(estats->total_unicast_packets_transmitted_hi, sum.hi,
+	       estats->total_unicast_packets_transmitted_lo, sum.lo);
+
+	UPDATE_STAT(tx_gtxpf.lo, pause_xoff_frames_transmitted);
+	UPDATE_STAT(tx_gt64.lo, frames_transmitted_64_bytes);
+	UPDATE_STAT(tx_gt127.lo, frames_transmitted_65_127_bytes);
+	UPDATE_STAT(tx_gt255.lo, frames_transmitted_128_255_bytes);
+	UPDATE_STAT(tx_gt511.lo, frames_transmitted_256_511_bytes);
+	UPDATE_STAT(tx_gt1023.lo, frames_transmitted_512_1023_bytes);
+	UPDATE_STAT(tx_gt1518.lo, frames_transmitted_1024_1522_bytes);
+	UPDATE_STAT(tx_gt2047.lo, frames_transmitted_1523_9022_bytes);
+	UPDATE_STAT(tx_gt4095.lo, frames_transmitted_1523_9022_bytes);
+	UPDATE_STAT(tx_gt9216.lo, frames_transmitted_1523_9022_bytes);
+	UPDATE_STAT(tx_gt16383.lo, frames_transmitted_1523_9022_bytes);
+
+	UPDATE_STAT(rx_grfcs.lo, crc_receive_errors);
+	UPDATE_STAT(rx_grund.lo, runt_packets_received);
+	UPDATE_STAT(rx_grovr.lo, stat_Dot3statsFramesTooLong);
+	UPDATE_STAT(rx_grxpf.lo, pause_xoff_frames_received);
+	UPDATE_STAT(rx_grxcf.lo, control_frames_received);
+	/* UPDATE_STAT(rx_grxpf.lo, control_frames_received); */
+	UPDATE_STAT(rx_grfrg.lo, error_runt_packets_received);
+	UPDATE_STAT(rx_grjbr.lo, error_jabber_packets_received);
+
+	UPDATE_STAT64(rx_grerb.hi, stat_IfHCInBadOctets_hi,
+		      rx_grerb.lo, stat_IfHCInBadOctets_lo);
+	UPDATE_STAT64(tx_gtufl.hi, stat_IfHCOutBadOctets_hi,
+		      tx_gtufl.lo, stat_IfHCOutBadOctets_lo);
+	UPDATE_STAT(tx_gterr.lo, stat_Dot3statsInternalMacTransmitErrors);
+	/* UPDATE_STAT(rx_grxpf.lo, stat_XoffStateEntered); */
+	estats->stat_XoffStateEntered = estats->pause_xoff_frames_received;
+}
+
+static void bnx2x_update_emac_stats(struct bnx2x *bp)
+{
+	struct emac_stats *new = bnx2x_sp(bp, mac_stats.emac);
+	struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats);
+
+	UPDATE_EXTEND_STAT(tx_ifhcoutoctets, total_bytes_transmitted_hi,
+					     total_bytes_transmitted_lo);
+	UPDATE_EXTEND_STAT(tx_ifhcoutucastpkts,
+					total_unicast_packets_transmitted_hi,
+					total_unicast_packets_transmitted_lo);
+	UPDATE_EXTEND_STAT(tx_ifhcoutmulticastpkts,
+				      total_multicast_packets_transmitted_hi,
+				      total_multicast_packets_transmitted_lo);
+	UPDATE_EXTEND_STAT(tx_ifhcoutbroadcastpkts,
+				      total_broadcast_packets_transmitted_hi,
+				      total_broadcast_packets_transmitted_lo);
+
+	estats->pause_xon_frames_transmitted += new->tx_outxonsent;
+	estats->pause_xoff_frames_transmitted += new->tx_outxoffsent;
+	estats->single_collision_transmit_frames +=
+				new->tx_dot3statssinglecollisionframes;
+	estats->multiple_collision_transmit_frames +=
+				new->tx_dot3statsmultiplecollisionframes;
+	estats->late_collision_frames += new->tx_dot3statslatecollisions;
+	estats->excessive_collision_frames +=
+				new->tx_dot3statsexcessivecollisions;
+	estats->frames_transmitted_64_bytes += new->tx_etherstatspkts64octets;
+	estats->frames_transmitted_65_127_bytes +=
+				new->tx_etherstatspkts65octetsto127octets;
+	estats->frames_transmitted_128_255_bytes +=
+				new->tx_etherstatspkts128octetsto255octets;
+	estats->frames_transmitted_256_511_bytes +=
+				new->tx_etherstatspkts256octetsto511octets;
+	estats->frames_transmitted_512_1023_bytes +=
+				new->tx_etherstatspkts512octetsto1023octets;
+	estats->frames_transmitted_1024_1522_bytes +=
+				new->tx_etherstatspkts1024octetsto1522octet;
+	estats->frames_transmitted_1523_9022_bytes +=
+				new->tx_etherstatspktsover1522octets;
+
+	estats->crc_receive_errors += new->rx_dot3statsfcserrors;
+	estats->alignment_errors += new->rx_dot3statsalignmenterrors;
+	estats->false_carrier_detections += new->rx_falsecarriererrors;
+	estats->runt_packets_received += new->rx_etherstatsundersizepkts;
+	estats->stat_Dot3statsFramesTooLong += new->rx_dot3statsframestoolong;
+	estats->pause_xon_frames_received += new->rx_xonpauseframesreceived;
+	estats->pause_xoff_frames_received += new->rx_xoffpauseframesreceived;
+	estats->control_frames_received += new->rx_maccontrolframesreceived;
+	estats->error_runt_packets_received += new->rx_etherstatsfragments;
+	estats->error_jabber_packets_received += new->rx_etherstatsjabbers;
+
+	UPDATE_EXTEND_STAT(rx_ifhcinbadoctets, stat_IfHCInBadOctets_hi,
+					       stat_IfHCInBadOctets_lo);
+	UPDATE_EXTEND_STAT(tx_ifhcoutbadoctets, stat_IfHCOutBadOctets_hi,
+						stat_IfHCOutBadOctets_lo);
+	estats->stat_Dot3statsInternalMacTransmitErrors +=
+				new->tx_dot3statsinternalmactransmiterrors;
+	estats->stat_Dot3StatsCarrierSenseErrors +=
+				new->rx_dot3statscarriersenseerrors;
+	estats->stat_Dot3StatsDeferredTransmissions +=
+				new->tx_dot3statsdeferredtransmissions;
+	estats->stat_FlowControlDone += new->tx_flowcontroldone;
+	estats->stat_XoffStateEntered += new->rx_xoffstateentered;
+}
+
+static int bnx2x_update_storm_stats(struct bnx2x *bp)
+{
+	struct eth_stats_query *stats = bnx2x_sp(bp, fw_stats);
+	struct tstorm_common_stats *tstats = &stats->tstorm_common;
+	struct tstorm_per_client_stats *tclient =
+						&tstats->client_statistics[0];
+	struct tstorm_per_client_stats *old_tclient = &bp->old_tclient;
+	struct xstorm_common_stats *xstats = &stats->xstorm_common;
+	struct nig_stats *nstats = bnx2x_sp(bp, nig);
+	struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats);
+	u32 diff;
+
+	/* are DMAE stats valid? */
+	if (nstats->done != 0xffffffff) {
+		DP(BNX2X_MSG_STATS, "stats not updated by dmae\n");
+		return -1;
+	}
+
+	/* are storm stats valid? */
+	if (tstats->done.hi != 0xffffffff) {
+		DP(BNX2X_MSG_STATS, "stats not updated by tstorm\n");
+		return -2;
+	}
+	if (xstats->done.hi != 0xffffffff) {
+		DP(BNX2X_MSG_STATS, "stats not updated by xstorm\n");
+		return -3;
+	}
+
+	estats->total_bytes_received_hi =
+	estats->valid_bytes_received_hi =
+				le32_to_cpu(tclient->total_rcv_bytes.hi);
+	estats->total_bytes_received_lo =
+	estats->valid_bytes_received_lo =
+				le32_to_cpu(tclient->total_rcv_bytes.lo);
+	ADD_64(estats->total_bytes_received_hi,
+	       le32_to_cpu(tclient->rcv_error_bytes.hi),
+	       estats->total_bytes_received_lo,
+	       le32_to_cpu(tclient->rcv_error_bytes.lo));
+
+	UPDATE_EXTEND_TSTAT(rcv_unicast_pkts,
+					total_unicast_packets_received_hi,
+					total_unicast_packets_received_lo);
+	UPDATE_EXTEND_TSTAT(rcv_multicast_pkts,
+					total_multicast_packets_received_hi,
+					total_multicast_packets_received_lo);
+	UPDATE_EXTEND_TSTAT(rcv_broadcast_pkts,
+					total_broadcast_packets_received_hi,
+					total_broadcast_packets_received_lo);
+
+	estats->frames_received_64_bytes = MAC_STX_NA;
+	estats->frames_received_65_127_bytes = MAC_STX_NA;
+	estats->frames_received_128_255_bytes = MAC_STX_NA;
+	estats->frames_received_256_511_bytes = MAC_STX_NA;
+	estats->frames_received_512_1023_bytes = MAC_STX_NA;
+	estats->frames_received_1024_1522_bytes = MAC_STX_NA;
+	estats->frames_received_1523_9022_bytes = MAC_STX_NA;
+
+	estats->x_total_sent_bytes_hi =
+				le32_to_cpu(xstats->total_sent_bytes.hi);
+	estats->x_total_sent_bytes_lo =
+				le32_to_cpu(xstats->total_sent_bytes.lo);
+	estats->x_total_sent_pkts = le32_to_cpu(xstats->total_sent_pkts);
+
+	estats->t_rcv_unicast_bytes_hi =
+				le32_to_cpu(tclient->rcv_unicast_bytes.hi);
+	estats->t_rcv_unicast_bytes_lo =
+				le32_to_cpu(tclient->rcv_unicast_bytes.lo);
+	estats->t_rcv_broadcast_bytes_hi =
+				le32_to_cpu(tclient->rcv_broadcast_bytes.hi);
+	estats->t_rcv_broadcast_bytes_lo =
+				le32_to_cpu(tclient->rcv_broadcast_bytes.lo);
+	estats->t_rcv_multicast_bytes_hi =
+				le32_to_cpu(tclient->rcv_multicast_bytes.hi);
+	estats->t_rcv_multicast_bytes_lo =
+				le32_to_cpu(tclient->rcv_multicast_bytes.lo);
+	estats->t_total_rcv_pkt = le32_to_cpu(tclient->total_rcv_pkts);
+
+	estats->checksum_discard = le32_to_cpu(tclient->checksum_discard);
+	estats->packets_too_big_discard =
+				le32_to_cpu(tclient->packets_too_big_discard);
+	estats->jabber_packets_received = estats->packets_too_big_discard +
+					  estats->stat_Dot3statsFramesTooLong;
+	estats->no_buff_discard = le32_to_cpu(tclient->no_buff_discard);
+	estats->ttl0_discard = le32_to_cpu(tclient->ttl0_discard);
+	estats->mac_discard = le32_to_cpu(tclient->mac_discard);
+	estats->mac_filter_discard = le32_to_cpu(tstats->mac_filter_discard);
+	estats->xxoverflow_discard = le32_to_cpu(tstats->xxoverflow_discard);
+	estats->brb_truncate_discard =
+				le32_to_cpu(tstats->brb_truncate_discard);
+
+	estats->brb_discard += nstats->brb_discard - bp->old_brb_discard;
+	bp->old_brb_discard = nstats->brb_discard;
+
+	estats->brb_packet = nstats->brb_packet;
+	estats->brb_truncate = nstats->brb_truncate;
+	estats->flow_ctrl_discard = nstats->flow_ctrl_discard;
+	estats->flow_ctrl_octets = nstats->flow_ctrl_octets;
+	estats->flow_ctrl_packet = nstats->flow_ctrl_packet;
+	estats->mng_discard = nstats->mng_discard;
+	estats->mng_octet_inp = nstats->mng_octet_inp;
+	estats->mng_octet_out = nstats->mng_octet_out;
+	estats->mng_packet_inp = nstats->mng_packet_inp;
+	estats->mng_packet_out = nstats->mng_packet_out;
+	estats->pbf_octets = nstats->pbf_octets;
+	estats->pbf_packet = nstats->pbf_packet;
+	estats->safc_inp = nstats->safc_inp;
+
+	xstats->done.hi = 0;
+	tstats->done.hi = 0;
+	nstats->done = 0;
+
+	return 0;
+}
+
+static void bnx2x_update_net_stats(struct bnx2x *bp)
+{
+	struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats);
+	struct net_device_stats *nstats = &bp->dev->stats;
+
+	nstats->rx_packets =
+		bnx2x_hilo(&estats->total_unicast_packets_received_hi) +
+		bnx2x_hilo(&estats->total_multicast_packets_received_hi) +
+		bnx2x_hilo(&estats->total_broadcast_packets_received_hi);
+
+	nstats->tx_packets =
+		bnx2x_hilo(&estats->total_unicast_packets_transmitted_hi) +
+		bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi) +
+		bnx2x_hilo(&estats->total_broadcast_packets_transmitted_hi);
+
+	nstats->rx_bytes = bnx2x_hilo(&estats->total_bytes_received_hi);
+
+	nstats->tx_bytes =
+		bnx2x_hilo(&estats->total_bytes_transmitted_hi);
+
+	nstats->rx_dropped = estats->checksum_discard +
+				   estats->mac_discard;
+	nstats->tx_dropped = 0;
+
+	nstats->multicast =
+		bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi);
+
+	nstats->collisions =
+		estats->single_collision_transmit_frames +
+		estats->multiple_collision_transmit_frames +
+		estats->late_collision_frames +
+		estats->excessive_collision_frames;
+
+	nstats->rx_length_errors = estats->runt_packets_received +
+				   estats->jabber_packets_received;
+	nstats->rx_over_errors = estats->no_buff_discard;
+	nstats->rx_crc_errors = estats->crc_receive_errors;
+	nstats->rx_frame_errors = estats->alignment_errors;
+	nstats->rx_fifo_errors = estats->brb_discard +
+				       estats->brb_truncate_discard;
+	nstats->rx_missed_errors = estats->xxoverflow_discard;
+
+	nstats->rx_errors = nstats->rx_length_errors +
+			    nstats->rx_over_errors +
+			    nstats->rx_crc_errors +
+			    nstats->rx_frame_errors +
+			    nstats->rx_fifo_errors;
+
+	nstats->tx_aborted_errors = estats->late_collision_frames +
+					  estats->excessive_collision_frames;
+	nstats->tx_carrier_errors = estats->false_carrier_detections;
+	nstats->tx_fifo_errors = 0;
+	nstats->tx_heartbeat_errors = 0;
+	nstats->tx_window_errors = 0;
+
+	nstats->tx_errors = nstats->tx_aborted_errors +
+			    nstats->tx_carrier_errors;
+
+	estats->mac_stx_start = ++estats->mac_stx_end;
+}
+
+static void bnx2x_update_stats(struct bnx2x *bp)
+{
+	int i;
+
+	if (!bnx2x_update_storm_stats(bp)) {
+
+		if (bp->phy_flags & PHY_BMAC_FLAG) {
+			bnx2x_update_bmac_stats(bp);
+
+		} else if (bp->phy_flags & PHY_EMAC_FLAG) {
+			bnx2x_update_emac_stats(bp);
+
+		} else { /* unreached */
+			BNX2X_ERR("no MAC active\n");
+			return;
+		}
+
+		bnx2x_update_net_stats(bp);
+	}
+
+	if (bp->msglevel & NETIF_MSG_TIMER) {
+		struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats);
+		struct net_device_stats *nstats = &bp->dev->stats;
+
+		printk(KERN_DEBUG "%s:\n", bp->dev->name);
+		printk(KERN_DEBUG "  tx avail (%4x)  tx hc idx (%x)"
+				  "  tx pkt (%lx)\n",
+		       bnx2x_tx_avail(bp->fp),
+		       *bp->fp->tx_cons_sb, nstats->tx_packets);
+		printk(KERN_DEBUG "  rx usage (%4x)  rx hc idx (%x)"
+				  "  rx pkt (%lx)\n",
+		       (u16)(*bp->fp->rx_cons_sb - bp->fp->rx_comp_cons),
+		       *bp->fp->rx_cons_sb, nstats->rx_packets);
+		printk(KERN_DEBUG "  %s (Xoff events %u)  brb drops %u\n",
+		       netif_queue_stopped(bp->dev)? "Xoff" : "Xon",
+		       estats->driver_xoff, estats->brb_discard);
+		printk(KERN_DEBUG "tstats: checksum_discard %u  "
+			"packets_too_big_discard %u  no_buff_discard %u  "
+			"mac_discard %u  mac_filter_discard %u  "
+			"xxovrflow_discard %u  brb_truncate_discard %u  "
+			"ttl0_discard %u\n",
+		       estats->checksum_discard,
+		       estats->packets_too_big_discard,
+		       estats->no_buff_discard, estats->mac_discard,
+		       estats->mac_filter_discard, estats->xxoverflow_discard,
+		       estats->brb_truncate_discard, estats->ttl0_discard);
+
+		for_each_queue(bp, i) {
+			printk(KERN_DEBUG "[%d]: %lu\t%lu\t%lu\n", i,
+			       bnx2x_fp(bp, i, tx_pkt),
+			       bnx2x_fp(bp, i, rx_pkt),
+			       bnx2x_fp(bp, i, rx_calls));
+		}
+	}
+
+	if (bp->state != BNX2X_STATE_OPEN) {
+		DP(BNX2X_MSG_STATS, "state is %x, returning\n", bp->state);
+		return;
+	}
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return;
+#endif
+
+	/* loader */
+	if (bp->executer_idx) {
+		struct dmae_command *dmae = &bp->dmae;
+		int port = bp->port;
+		int loader_idx = port * 8;
+
+		memset(dmae, 0, sizeof(struct dmae_command));
+
+		dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
+				DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE |
+				DMAE_CMD_DST_RESET |
+#ifdef __BIG_ENDIAN
+				DMAE_CMD_ENDIANITY_B_DW_SWAP |
+#else
+				DMAE_CMD_ENDIANITY_DW_SWAP |
+#endif
+				(port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0));
+		dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, dmae[0]));
+		dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, dmae[0]));
+		dmae->dst_addr_lo = (DMAE_REG_CMD_MEM +
+				     sizeof(struct dmae_command) *
+				     (loader_idx + 1)) >> 2;
+		dmae->dst_addr_hi = 0;
+		dmae->len = sizeof(struct dmae_command) >> 2;
+		dmae->len--;    /* !!! for A0/1 only */
+		dmae->comp_addr_lo = dmae_reg_go_c[loader_idx + 1] >> 2;
+		dmae->comp_addr_hi = 0;
+		dmae->comp_val = 1;
+
+		bnx2x_post_dmae(bp, dmae, loader_idx);
+	}
+
+	if (bp->stats_state != STATS_STATE_ENABLE) {
+		bp->stats_state = STATS_STATE_DISABLE;
+		return;
+	}
+
+	if (bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_STAT_QUERY, 0, 0, 0, 0) == 0) {
+		/* stats ramrod has it's own slot on the spe */
+		bp->spq_left++;
+		bp->stat_pending = 1;
+	}
+}
+
+static void bnx2x_timer(unsigned long data)
+{
+	struct bnx2x *bp = (struct bnx2x *) data;
+
+	if (!netif_running(bp->dev))
+		return;
+
+	if (atomic_read(&bp->intr_sem) != 0)
+		goto bnx2x_restart_timer;
+
+	if (poll) {
+		struct bnx2x_fastpath *fp = &bp->fp[0];
+		int rc;
+
+		bnx2x_tx_int(fp, 1000);
+		rc = bnx2x_rx_int(fp, 1000);
+	}
+
+	if (!nomcp && (bp->bc_ver >= 0x040003)) {
+		int port = bp->port;
+		u32 drv_pulse;
+		u32 mcp_pulse;
+
+		++bp->fw_drv_pulse_wr_seq;
+		bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK;
+		/* TBD - add SYSTEM_TIME */
+		drv_pulse = bp->fw_drv_pulse_wr_seq;
+		SHMEM_WR(bp, drv_fw_mb[port].drv_pulse_mb, drv_pulse);
+
+		mcp_pulse = (SHMEM_RD(bp, drv_fw_mb[port].mcp_pulse_mb) &
+			     MCP_PULSE_SEQ_MASK);
+		/* The delta between driver pulse and mcp response
+		 * should be 1 (before mcp response) or 0 (after mcp response)
+		 */
+		if ((drv_pulse != mcp_pulse) &&
+		    (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) {
+			/* someone lost a heartbeat... */
+			BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n",
+				  drv_pulse, mcp_pulse);
+		}
+	}
+
+	if (bp->stats_state == STATS_STATE_DISABLE)
+		goto bnx2x_restart_timer;
+
+	bnx2x_update_stats(bp);
+
+bnx2x_restart_timer:
+	mod_timer(&bp->timer, jiffies + bp->current_interval);
+}
+
+/* end of Statistics */
+
+/* nic init */
+
+/*
+ * nic init service functions
+ */
+
+static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb,
+			  dma_addr_t mapping, int id)
+{
+	int port = bp->port;
+	u64 section;
+	int index;
+
+	/* USTORM */
+	section = ((u64)mapping) + offsetof(struct host_status_block,
+					    u_status_block);
+	sb->u_status_block.status_block_id = id;
+
+	REG_WR(bp, BAR_USTRORM_INTMEM +
+	       USTORM_SB_HOST_SB_ADDR_OFFSET(port, id), U64_LO(section));
+	REG_WR(bp, BAR_USTRORM_INTMEM +
+	       ((USTORM_SB_HOST_SB_ADDR_OFFSET(port, id)) + 4),
+	       U64_HI(section));
+
+	for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_USTRORM_INTMEM +
+			 USTORM_SB_HC_DISABLE_OFFSET(port, id, index), 0x1);
+
+	/* CSTORM */
+	section = ((u64)mapping) + offsetof(struct host_status_block,
+					    c_status_block);
+	sb->c_status_block.status_block_id = id;
+
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       CSTORM_SB_HOST_SB_ADDR_OFFSET(port, id), U64_LO(section));
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       ((CSTORM_SB_HOST_SB_ADDR_OFFSET(port, id)) + 4),
+	       U64_HI(section));
+
+	for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_CSTRORM_INTMEM +
+			 CSTORM_SB_HC_DISABLE_OFFSET(port, id, index), 0x1);
+
+	bnx2x_ack_sb(bp, id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+}
+
+static void bnx2x_init_def_sb(struct bnx2x *bp,
+			      struct host_def_status_block *def_sb,
+			      dma_addr_t mapping, int id)
+{
+	int port = bp->port;
+	int index, val, reg_offset;
+	u64 section;
+
+	/* ATTN */
+	section = ((u64)mapping) + offsetof(struct host_def_status_block,
+					    atten_status_block);
+	def_sb->atten_status_block.status_block_id = id;
+
+	reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+			     MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+
+	for (index = 0; index < 3; index++) {
+		bp->attn_group[index].sig[0] = REG_RD(bp,
+						     reg_offset + 0x10*index);
+		bp->attn_group[index].sig[1] = REG_RD(bp,
+					       reg_offset + 0x4 + 0x10*index);
+		bp->attn_group[index].sig[2] = REG_RD(bp,
+					       reg_offset + 0x8 + 0x10*index);
+		bp->attn_group[index].sig[3] = REG_RD(bp,
+					       reg_offset + 0xc + 0x10*index);
+	}
+
+	bp->aeu_mask = REG_RD(bp, (port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
+					  MISC_REG_AEU_MASK_ATTN_FUNC_0));
+
+	reg_offset = (port ? HC_REG_ATTN_MSG1_ADDR_L :
+			     HC_REG_ATTN_MSG0_ADDR_L);
+
+	REG_WR(bp, reg_offset, U64_LO(section));
+	REG_WR(bp, reg_offset + 4, U64_HI(section));
+
+	reg_offset = (port ? HC_REG_ATTN_NUM_P1 : HC_REG_ATTN_NUM_P0);
+
+	val = REG_RD(bp, reg_offset);
+	val |= id;
+	REG_WR(bp, reg_offset, val);
+
+	/* USTORM */
+	section = ((u64)mapping) + offsetof(struct host_def_status_block,
+					    u_def_status_block);
+	def_sb->u_def_status_block.status_block_id = id;
+
+	REG_WR(bp, BAR_USTRORM_INTMEM +
+	       USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
+	REG_WR(bp, BAR_USTRORM_INTMEM +
+	       ((USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4),
+	       U64_HI(section));
+	REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_HC_BTR_OFFSET(port),
+	       BNX2X_BTR);
+
+	for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_USTRORM_INTMEM +
+			 USTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1);
+
+	/* CSTORM */
+	section = ((u64)mapping) + offsetof(struct host_def_status_block,
+					    c_def_status_block);
+	def_sb->c_def_status_block.status_block_id = id;
+
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
+	REG_WR(bp, BAR_CSTRORM_INTMEM +
+	       ((CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4),
+	       U64_HI(section));
+	REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_OFFSET(port),
+	       BNX2X_BTR);
+
+	for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_CSTRORM_INTMEM +
+			 CSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1);
+
+	/* TSTORM */
+	section = ((u64)mapping) + offsetof(struct host_def_status_block,
+					    t_def_status_block);
+	def_sb->t_def_status_block.status_block_id = id;
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       ((TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4),
+	       U64_HI(section));
+	REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port),
+	       BNX2X_BTR);
+
+	for (index = 0; index < HC_TSTORM_DEF_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_TSTRORM_INTMEM +
+			 TSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1);
+
+	/* XSTORM */
+	section = ((u64)mapping) + offsetof(struct host_def_status_block,
+					    x_def_status_block);
+	def_sb->x_def_status_block.status_block_id = id;
+
+	REG_WR(bp, BAR_XSTRORM_INTMEM +
+	       XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section));
+	REG_WR(bp, BAR_XSTRORM_INTMEM +
+	       ((XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4),
+	       U64_HI(section));
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port),
+	       BNX2X_BTR);
+
+	for (index = 0; index < HC_XSTORM_DEF_SB_NUM_INDICES; index++)
+		REG_WR16(bp, BAR_XSTRORM_INTMEM +
+			 XSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1);
+
+	bnx2x_ack_sb(bp, id, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+}
+
+static void bnx2x_update_coalesce(struct bnx2x *bp)
+{
+	int port = bp->port;
+	int i;
+
+	for_each_queue(bp, i) {
+
+		/* HC_INDEX_U_ETH_RX_CQ_CONS */
+		REG_WR8(bp, BAR_USTRORM_INTMEM +
+			USTORM_SB_HC_TIMEOUT_OFFSET(port, i,
+						   HC_INDEX_U_ETH_RX_CQ_CONS),
+			bp->rx_ticks_int/12);
+		REG_WR16(bp, BAR_USTRORM_INTMEM +
+			 USTORM_SB_HC_DISABLE_OFFSET(port, i,
+						   HC_INDEX_U_ETH_RX_CQ_CONS),
+			 bp->rx_ticks_int ? 0 : 1);
+
+		/* HC_INDEX_C_ETH_TX_CQ_CONS */
+		REG_WR8(bp, BAR_CSTRORM_INTMEM +
+			CSTORM_SB_HC_TIMEOUT_OFFSET(port, i,
+						   HC_INDEX_C_ETH_TX_CQ_CONS),
+			bp->tx_ticks_int/12);
+		REG_WR16(bp, BAR_CSTRORM_INTMEM +
+			 CSTORM_SB_HC_DISABLE_OFFSET(port, i,
+						   HC_INDEX_C_ETH_TX_CQ_CONS),
+			 bp->tx_ticks_int ? 0 : 1);
+	}
+}
+
+static void bnx2x_init_rx_rings(struct bnx2x *bp)
+{
+	u16 ring_prod;
+	int i, j;
+	int port = bp->port;
+
+	bp->rx_buf_use_size = bp->dev->mtu;
+
+	bp->rx_buf_use_size += bp->rx_offset + ETH_OVREHEAD;
+	bp->rx_buf_size = bp->rx_buf_use_size + 64;
+
+	for_each_queue(bp, j) {
+		struct bnx2x_fastpath *fp = &bp->fp[j];
+
+		fp->rx_bd_cons = 0;
+		fp->rx_cons_sb = BNX2X_RX_SB_INDEX;
+
+		for (i = 1; i <= NUM_RX_RINGS; i++) {
+			struct eth_rx_bd *rx_bd;
+
+			rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2];
+			rx_bd->addr_hi =
+				cpu_to_le32(U64_HI(fp->rx_desc_mapping +
+					   BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
+			rx_bd->addr_lo =
+				cpu_to_le32(U64_LO(fp->rx_desc_mapping +
+					   BCM_PAGE_SIZE*(i % NUM_RX_RINGS)));
+
+		}
+
+		for (i = 1; i <= NUM_RCQ_RINGS; i++) {
+			struct eth_rx_cqe_next_page *nextpg;
+
+			nextpg = (struct eth_rx_cqe_next_page *)
+				&fp->rx_comp_ring[RCQ_DESC_CNT * i - 1];
+			nextpg->addr_hi =
+				cpu_to_le32(U64_HI(fp->rx_comp_mapping +
+					  BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
+			nextpg->addr_lo =
+				cpu_to_le32(U64_LO(fp->rx_comp_mapping +
+					  BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS)));
+		}
+
+		/* rx completion queue */
+		fp->rx_comp_cons = ring_prod = 0;
+
+		for (i = 0; i < bp->rx_ring_size; i++) {
+			if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) {
+				BNX2X_ERR("was only able to allocate "
+					  "%d rx skbs\n", i);
+				break;
+			}
+			ring_prod = NEXT_RX_IDX(ring_prod);
+			BUG_TRAP(ring_prod > i);
+		}
+
+		fp->rx_bd_prod = fp->rx_comp_prod = ring_prod;
+		fp->rx_pkt = fp->rx_calls = 0;
+
+		/* Warning! this will genrate an interrupt (to the TSTORM) */
+		/* must only be done when chip is initialized */
+		REG_WR(bp, BAR_TSTRORM_INTMEM +
+		       TSTORM_RCQ_PROD_OFFSET(port, j), ring_prod);
+		if (j != 0)
+			continue;
+
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+		       USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port),
+		       U64_LO(fp->rx_comp_mapping));
+		REG_WR(bp, BAR_USTRORM_INTMEM +
+		       USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port) + 4,
+		       U64_HI(fp->rx_comp_mapping));
+	}
+}
+
+static void bnx2x_init_tx_ring(struct bnx2x *bp)
+{
+	int i, j;
+
+	for_each_queue(bp, j) {
+		struct bnx2x_fastpath *fp = &bp->fp[j];
+
+		for (i = 1; i <= NUM_TX_RINGS; i++) {
+			struct eth_tx_bd *tx_bd =
+				&fp->tx_desc_ring[TX_DESC_CNT * i - 1];
+
+			tx_bd->addr_hi =
+				cpu_to_le32(U64_HI(fp->tx_desc_mapping +
+					   BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
+			tx_bd->addr_lo =
+				cpu_to_le32(U64_LO(fp->tx_desc_mapping +
+					   BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
+		}
+
+		fp->tx_pkt_prod = 0;
+		fp->tx_pkt_cons = 0;
+		fp->tx_bd_prod = 0;
+		fp->tx_bd_cons = 0;
+		fp->tx_cons_sb = BNX2X_TX_SB_INDEX;
+		fp->tx_pkt = 0;
+	}
+}
+
+static void bnx2x_init_sp_ring(struct bnx2x *bp)
+{
+	int port = bp->port;
+
+	spin_lock_init(&bp->spq_lock);
+
+	bp->spq_left = MAX_SPQ_PENDING;
+	bp->spq_prod_idx = 0;
+	bp->dsb_sp_prod_idx = 0;
+	bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX;
+	bp->spq_prod_bd = bp->spq;
+	bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT;
+
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PAGE_BASE_OFFSET(port),
+	       U64_LO(bp->spq_mapping));
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PAGE_BASE_OFFSET(port) + 4,
+	       U64_HI(bp->spq_mapping));
+
+	REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PROD_OFFSET(port),
+	       bp->spq_prod_idx);
+}
+
+static void bnx2x_init_context(struct bnx2x *bp)
+{
+	int i;
+
+	for_each_queue(bp, i) {
+		struct eth_context *context = bnx2x_sp(bp, context[i].eth);
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		context->xstorm_st_context.tx_bd_page_base_hi =
+						U64_HI(fp->tx_desc_mapping);
+		context->xstorm_st_context.tx_bd_page_base_lo =
+						U64_LO(fp->tx_desc_mapping);
+		context->xstorm_st_context.db_data_addr_hi =
+						U64_HI(fp->tx_prods_mapping);
+		context->xstorm_st_context.db_data_addr_lo =
+						U64_LO(fp->tx_prods_mapping);
+
+		context->ustorm_st_context.rx_bd_page_base_hi =
+						U64_HI(fp->rx_desc_mapping);
+		context->ustorm_st_context.rx_bd_page_base_lo =
+						U64_LO(fp->rx_desc_mapping);
+		context->ustorm_st_context.status_block_id = i;
+		context->ustorm_st_context.sb_index_number =
+						HC_INDEX_U_ETH_RX_CQ_CONS;
+		context->ustorm_st_context.rcq_base_address_hi =
+						U64_HI(fp->rx_comp_mapping);
+		context->ustorm_st_context.rcq_base_address_lo =
+						U64_LO(fp->rx_comp_mapping);
+		context->ustorm_st_context.flags =
+				USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT;
+		context->ustorm_st_context.mc_alignment_size = 64;
+		context->ustorm_st_context.num_rss = bp->num_queues;
+
+		context->cstorm_st_context.sb_index_number =
+						HC_INDEX_C_ETH_TX_CQ_CONS;
+		context->cstorm_st_context.status_block_id = i;
+
+		context->xstorm_ag_context.cdu_reserved =
+			CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i),
+					       CDU_REGION_NUMBER_XCM_AG,
+					       ETH_CONNECTION_TYPE);
+		context->ustorm_ag_context.cdu_usage =
+			CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i),
+					       CDU_REGION_NUMBER_UCM_AG,
+					       ETH_CONNECTION_TYPE);
+	}
+}
+
+static void bnx2x_init_ind_table(struct bnx2x *bp)
+{
+	int port = bp->port;
+	int i;
+
+	if (!is_multi(bp))
+		return;
+
+	for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++)
+		REG_WR8(bp, TSTORM_INDIRECTION_TABLE_OFFSET(port) + i,
+			i % bp->num_queues);
+
+	REG_WR(bp, PRS_REG_A_PRSU_20, 0xf);
+}
+
+static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+{
+	int mode = bp->rx_mode;
+	int port = bp->port;
+	struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0};
+	int i;
+
+	DP(NETIF_MSG_RX_STATUS, "rx mode is %d\n", mode);
+
+	switch (mode) {
+	case BNX2X_RX_MODE_NONE: /* no Rx */
+		tstorm_mac_filter.ucast_drop_all = 1;
+		tstorm_mac_filter.mcast_drop_all = 1;
+		tstorm_mac_filter.bcast_drop_all = 1;
+		break;
+	case BNX2X_RX_MODE_NORMAL:
+		tstorm_mac_filter.bcast_accept_all = 1;
+		break;
+	case BNX2X_RX_MODE_ALLMULTI:
+		tstorm_mac_filter.mcast_accept_all = 1;
+		tstorm_mac_filter.bcast_accept_all = 1;
+		break;
+	case BNX2X_RX_MODE_PROMISC:
+		tstorm_mac_filter.ucast_accept_all = 1;
+		tstorm_mac_filter.mcast_accept_all = 1;
+		tstorm_mac_filter.bcast_accept_all = 1;
+		break;
+	default:
+		BNX2X_ERR("bad rx mode (%d)\n", mode);
+	}
+
+	for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) {
+		REG_WR(bp, BAR_TSTRORM_INTMEM +
+		       TSTORM_MAC_FILTER_CONFIG_OFFSET(port) + i * 4,
+		       ((u32 *)&tstorm_mac_filter)[i]);
+
+/*      	DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i,
+		   ((u32 *)&tstorm_mac_filter)[i]); */
+	}
+}
+
+static void bnx2x_set_client_config(struct bnx2x *bp, int client_id)
+{
+#ifdef BCM_VLAN
+	int mode = bp->rx_mode;
+#endif
+	int port = bp->port;
+	struct tstorm_eth_client_config tstorm_client = {0};
+
+	tstorm_client.mtu = bp->dev->mtu;
+	tstorm_client.statistics_counter_id = 0;
+	tstorm_client.config_flags =
+		TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE;
+#ifdef BCM_VLAN
+	if (mode && bp->vlgrp) {
+		tstorm_client.config_flags |=
+				TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE;
+		DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
+	}
+#endif
+	tstorm_client.drop_flags = (TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR |
+				    TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR |
+				    TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR |
+				    TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR);
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_CLIENT_CONFIG_OFFSET(port, client_id),
+	       ((u32 *)&tstorm_client)[0]);
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_CLIENT_CONFIG_OFFSET(port, client_id) + 4,
+	       ((u32 *)&tstorm_client)[1]);
+
+/*      DP(NETIF_MSG_IFUP, "tstorm_client: 0x%08x 0x%08x\n",
+	   ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]); */
+}
+
+static void bnx2x_init_internal(struct bnx2x *bp)
+{
+	int port = bp->port;
+	struct tstorm_eth_function_common_config tstorm_config = {0};
+	struct stats_indication_flags stats_flags = {0};
+	int i;
+
+	if (is_multi(bp)) {
+		tstorm_config.config_flags = MULTI_FLAGS;
+		tstorm_config.rss_result_mask = MULTI_MASK;
+	}
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM +
+	       TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(port),
+	       (*(u32 *)&tstorm_config));
+
+/*      DP(NETIF_MSG_IFUP, "tstorm_config: 0x%08x\n",
+	   (*(u32 *)&tstorm_config)); */
+
+	bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx untill link is up */
+	bnx2x_set_storm_rx_mode(bp);
+
+	for_each_queue(bp, i)
+		bnx2x_set_client_config(bp, i);
+
+
+	stats_flags.collect_eth = cpu_to_le32(1);
+
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port),
+	       ((u32 *)&stats_flags)[0]);
+	REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port) + 4,
+	       ((u32 *)&stats_flags)[1]);
+
+	REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port),
+	       ((u32 *)&stats_flags)[0]);
+	REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port) + 4,
+	       ((u32 *)&stats_flags)[1]);
+
+	REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port),
+	       ((u32 *)&stats_flags)[0]);
+	REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port) + 4,
+	       ((u32 *)&stats_flags)[1]);
+
+/*      DP(NETIF_MSG_IFUP, "stats_flags: 0x%08x 0x%08x\n",
+	   ((u32 *)&stats_flags)[0], ((u32 *)&stats_flags)[1]); */
+}
+
+static void bnx2x_nic_init(struct bnx2x *bp)
+{
+	int i;
+
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		fp->state = BNX2X_FP_STATE_CLOSED;
+		DP(NETIF_MSG_IFUP, "bnx2x_init_sb(%p,%p,%d);\n",
+		   bp, fp->status_blk, i);
+		fp->index = i;
+		bnx2x_init_sb(bp, fp->status_blk, fp->status_blk_mapping, i);
+	}
+
+	bnx2x_init_def_sb(bp, bp->def_status_blk,
+			  bp->def_status_blk_mapping, 0x10);
+	bnx2x_update_coalesce(bp);
+	bnx2x_init_rx_rings(bp);
+	bnx2x_init_tx_ring(bp);
+	bnx2x_init_sp_ring(bp);
+	bnx2x_init_context(bp);
+	bnx2x_init_internal(bp);
+	bnx2x_init_stats(bp);
+	bnx2x_init_ind_table(bp);
+	bnx2x_enable_int(bp);
+
+}
+
+/* end of nic init */
+
+/*
+ * gzip service functions
+ */
+
+static int bnx2x_gunzip_init(struct bnx2x *bp)
+{
+	bp->gunzip_buf = pci_alloc_consistent(bp->pdev, FW_BUF_SIZE,
+					      &bp->gunzip_mapping);
+	if (bp->gunzip_buf  == NULL)
+		goto gunzip_nomem1;
+
+	bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL);
+	if (bp->strm  == NULL)
+		goto gunzip_nomem2;
+
+	bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(),
+				      GFP_KERNEL);
+	if (bp->strm->workspace == NULL)
+		goto gunzip_nomem3;
+
+	return 0;
+
+gunzip_nomem3:
+	kfree(bp->strm);
+	bp->strm = NULL;
+
+gunzip_nomem2:
+	pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf,
+			    bp->gunzip_mapping);
+	bp->gunzip_buf = NULL;
+
+gunzip_nomem1:
+	printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for"
+	       " uncompression\n", bp->dev->name);
+	return -ENOMEM;
+}
+
+static void bnx2x_gunzip_end(struct bnx2x *bp)
+{
+	kfree(bp->strm->workspace);
+
+	kfree(bp->strm);
+	bp->strm = NULL;
+
+	if (bp->gunzip_buf) {
+		pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf,
+				    bp->gunzip_mapping);
+		bp->gunzip_buf = NULL;
+	}
+}
+
+static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len)
+{
+	int n, rc;
+
+	/* check gzip header */
+	if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED))
+		return -EINVAL;
+
+	n = 10;
+
+#define FNAME   			0x8
+
+	if (zbuf[3] & FNAME)
+		while ((zbuf[n++] != 0) && (n < len));
+
+	bp->strm->next_in = zbuf + n;
+	bp->strm->avail_in = len - n;
+	bp->strm->next_out = bp->gunzip_buf;
+	bp->strm->avail_out = FW_BUF_SIZE;
+
+	rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
+	if (rc != Z_OK)
+		return rc;
+
+	rc = zlib_inflate(bp->strm, Z_FINISH);
+	if ((rc != Z_OK) && (rc != Z_STREAM_END))
+		printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
+		       bp->dev->name, bp->strm->msg);
+
+	bp->gunzip_outlen = (FW_BUF_SIZE - bp->strm->avail_out);
+	if (bp->gunzip_outlen & 0x3)
+		printk(KERN_ERR PFX "%s: Firmware decompression error:"
+				    " gunzip_outlen (%d) not aligned\n",
+		       bp->dev->name, bp->gunzip_outlen);
+	bp->gunzip_outlen >>= 2;
+
+	zlib_inflateEnd(bp->strm);
+
+	if (rc == Z_STREAM_END)
+		return 0;
+
+	return rc;
+}
+
+/* nic load/unload */
+
+/*
+ * general service functions
+ */
+
+/* send a NIG loopback debug packet */
+static void bnx2x_lb_pckt(struct bnx2x *bp)
+{
+#ifdef USE_DMAE
+	u32 wb_write[3];
+#endif
+
+	/* Ethernet source and destination addresses */
+#ifdef USE_DMAE
+	wb_write[0] = 0x55555555;
+	wb_write[1] = 0x55555555;
+	wb_write[2] = 0x20;     	/* SOP */
+	REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3);
+#else
+	REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB, 0x55555555);
+	REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 4, 0x55555555);
+	/* SOP */
+	REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 8, 0x20);
+#endif
+
+	/* NON-IP protocol */
+#ifdef USE_DMAE
+	wb_write[0] = 0x09000000;
+	wb_write[1] = 0x55555555;
+	wb_write[2] = 0x10;     	/* EOP, eop_bvalid = 0 */
+	REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3);
+#else
+	REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB, 0x09000000);
+	REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 4, 0x55555555);
+	/* EOP, eop_bvalid = 0 */
+	REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 8, 0x10);
+#endif
+}
+
+/* some of the internal memories
+ * are not directly readable from the driver
+ * to test them we send debug packets
+ */
+static int bnx2x_int_mem_test(struct bnx2x *bp)
+{
+	int factor;
+	int count, i;
+	u32 val = 0;
+
+	switch (CHIP_REV(bp)) {
+	case CHIP_REV_EMUL:
+		factor = 200;
+		break;
+	case CHIP_REV_FPGA:
+		factor = 120;
+		break;
+	default:
+		factor = 1;
+		break;
+	}
+
+	DP(NETIF_MSG_HW, "start part1\n");
+
+	/* Disable inputs of parser neighbor blocks */
+	REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0);
+	REG_WR(bp, TCM_REG_PRS_IFEN, 0x0);
+	REG_WR(bp, CFC_REG_DEBUG0, 0x1);
+	NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x0);
+
+	/*  Write 0 to parser credits for CFC search request */
+	REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0);
+
+	/* send Ethernet packet */
+	bnx2x_lb_pckt(bp);
+
+	/* TODO do i reset NIG statistic? */
+	/* Wait until NIG register shows 1 packet of size 0x10 */
+	count = 1000 * factor;
+	while (count) {
+#ifdef BNX2X_DMAE_RD
+		bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
+		val = *bnx2x_sp(bp, wb_data[0]);
+#else
+		val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET);
+		REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4);
+#endif
+		if (val == 0x10)
+			break;
+
+		msleep(10);
+		count--;
+	}
+	if (val != 0x10) {
+		BNX2X_ERR("NIG timeout  val = 0x%x\n", val);
+		return -1;
+	}
+
+	/* Wait until PRS register shows 1 packet */
+	count = 1000 * factor;
+	while (count) {
+		val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS);
+
+		if (val == 1)
+			break;
+
+		msleep(10);
+		count--;
+	}
+	if (val != 0x1) {
+		BNX2X_ERR("PRS timeout val = 0x%x\n", val);
+		return -2;
+	}
+
+	/* Reset and init BRB, PRS */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x3);
+	msleep(50);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x3);
+	msleep(50);
+	bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END);
+	bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END);
+
+	DP(NETIF_MSG_HW, "part2\n");
+
+	/* Disable inputs of parser neighbor blocks */
+	REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0);
+	REG_WR(bp, TCM_REG_PRS_IFEN, 0x0);
+	REG_WR(bp, CFC_REG_DEBUG0, 0x1);
+	NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x0);
+
+	/* Write 0 to parser credits for CFC search request */
+	REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0);
+
+	/* send 10 Ethernet packets */
+	for (i = 0; i < 10; i++)
+		bnx2x_lb_pckt(bp);
+
+	/* Wait until NIG register shows 10 + 1
+	   packets of size 11*0x10 = 0xb0 */
+	count = 1000 * factor;
+	while (count) {
+#ifdef BNX2X_DMAE_RD
+		bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
+		val = *bnx2x_sp(bp, wb_data[0]);
+#else
+		val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET);
+		REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4);
+#endif
+		if (val == 0xb0)
+			break;
+
+		msleep(10);
+		count--;
+	}
+	if (val != 0xb0) {
+		BNX2X_ERR("NIG timeout  val = 0x%x\n", val);
+		return -3;
+	}
+
+	/* Wait until PRS register shows 2 packets */
+	val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS);
+	if (val != 2)
+		BNX2X_ERR("PRS timeout  val = 0x%x\n", val);
+
+	/* Write 1 to parser credits for CFC search request */
+	REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x1);
+
+	/* Wait until PRS register shows 3 packets */
+	msleep(10 * factor);
+	/* Wait until NIG register shows 1 packet of size 0x10 */
+	val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS);
+	if (val != 3)
+		BNX2X_ERR("PRS timeout  val = 0x%x\n", val);
+
+	/* clear NIG EOP FIFO */
+	for (i = 0; i < 11; i++)
+		REG_RD(bp, NIG_REG_INGRESS_EOP_LB_FIFO);
+	val = REG_RD(bp, NIG_REG_INGRESS_EOP_LB_EMPTY);
+	if (val != 1) {
+		BNX2X_ERR("clear of NIG failed\n");
+		return -4;
+	}
+
+	/* Reset and init BRB, PRS, NIG */
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03);
+	msleep(50);
+	REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03);
+	msleep(50);
+	bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END);
+	bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END);
+#ifndef BCM_ISCSI
+	/* set NIC mode */
+	REG_WR(bp, PRS_REG_NIC_MODE, 1);
+#endif
+
+	/* Enable inputs of parser neighbor blocks */
+	REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x7fffffff);
+	REG_WR(bp, TCM_REG_PRS_IFEN, 0x1);
+	REG_WR(bp, CFC_REG_DEBUG0, 0x0);
+	NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x1);
+
+	DP(NETIF_MSG_HW, "done\n");
+
+	return 0; /* OK */
+}
+
+static void enable_blocks_attention(struct bnx2x *bp)
+{
+	REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0);
+	REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0);
+	REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0);
+	REG_WR(bp, CFC_REG_CFC_INT_MASK, 0);
+	REG_WR(bp, QM_REG_QM_INT_MASK, 0);
+	REG_WR(bp, TM_REG_TM_INT_MASK, 0);
+	REG_WR(bp, XSDM_REG_XSDM_INT_MASK_0, 0);
+	REG_WR(bp, XSDM_REG_XSDM_INT_MASK_1, 0);
+	REG_WR(bp, XCM_REG_XCM_INT_MASK, 0);
+/*      REG_WR(bp, XSEM_REG_XSEM_INT_MASK_0, 0); */
+/*      REG_WR(bp, XSEM_REG_XSEM_INT_MASK_1, 0); */
+	REG_WR(bp, USDM_REG_USDM_INT_MASK_0, 0);
+	REG_WR(bp, USDM_REG_USDM_INT_MASK_1, 0);
+	REG_WR(bp, UCM_REG_UCM_INT_MASK, 0);
+/*      REG_WR(bp, USEM_REG_USEM_INT_MASK_0, 0); */
+/*      REG_WR(bp, USEM_REG_USEM_INT_MASK_1, 0); */
+	REG_WR(bp, GRCBASE_UPB + PB_REG_PB_INT_MASK, 0);
+	REG_WR(bp, CSDM_REG_CSDM_INT_MASK_0, 0);
+	REG_WR(bp, CSDM_REG_CSDM_INT_MASK_1, 0);
+	REG_WR(bp, CCM_REG_CCM_INT_MASK, 0);
+/*      REG_WR(bp, CSEM_REG_CSEM_INT_MASK_0, 0); */
+/*      REG_WR(bp, CSEM_REG_CSEM_INT_MASK_1, 0); */
+	REG_WR(bp, PXP2_REG_PXP2_INT_MASK, 0x480000);
+	REG_WR(bp, TSDM_REG_TSDM_INT_MASK_0, 0);
+	REG_WR(bp, TSDM_REG_TSDM_INT_MASK_1, 0);
+	REG_WR(bp, TCM_REG_TCM_INT_MASK, 0);
+/*      REG_WR(bp, TSEM_REG_TSEM_INT_MASK_0, 0); */
+/*      REG_WR(bp, TSEM_REG_TSEM_INT_MASK_1, 0); */
+	REG_WR(bp, CDU_REG_CDU_INT_MASK, 0);
+	REG_WR(bp, DMAE_REG_DMAE_INT_MASK, 0);
+/*      REG_WR(bp, MISC_REG_MISC_INT_MASK, 0); */
+	REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18); 	/* bit 3,4 masked */
+}
+
+static int bnx2x_function_init(struct bnx2x *bp, int mode)
+{
+	int func = bp->port;
+	int port = func ? PORT1 : PORT0;
+	u32 val, i;
+#ifdef USE_DMAE
+	u32 wb_write[2];
+#endif
+
+	DP(BNX2X_MSG_MCP, "function is %d  mode is %x\n", func, mode);
+	if ((func != 0) && (func != 1)) {
+		BNX2X_ERR("BAD function number (%d)\n", func);
+		return -ENODEV;
+	}
+
+	bnx2x_gunzip_init(bp);
+
+	if (mode & 0x1) {       /* init common */
+		DP(BNX2X_MSG_MCP, "starting common init  func %d  mode %x\n",
+		   func, mode);
+		REG_WR(bp, MISC_REG_RESET_REG_1, 0xffffffff);
+		REG_WR(bp, MISC_REG_RESET_REG_2, 0xfffc);
+		bnx2x_init_block(bp, MISC_COMMON_START, MISC_COMMON_END);
+
+		REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100);
+		msleep(30);
+		REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x0);
+
+		bnx2x_init_block(bp, PXP_COMMON_START, PXP_COMMON_END);
+		bnx2x_init_block(bp, PXP2_COMMON_START, PXP2_COMMON_END);
+
+		bnx2x_init_pxp(bp);
+
+		if (CHIP_REV(bp) == CHIP_REV_Ax) {
+			/* enable HW interrupt from PXP on USDM
+			   overflow bit 16 on INT_MASK_0 */
+			REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0);
+		}
+
+#ifdef __BIG_ENDIAN
+		REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, 1);
+		REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, 1);
+		REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1);
+		REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1);
+		REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1);
+		REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 1);
+
+/*      	REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */
+		REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1);
+		REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, 1);
+		REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, 1);
+		REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1);
+#endif
+
+#ifndef BCM_ISCSI
+		/* set NIC mode */
+		REG_WR(bp, PRS_REG_NIC_MODE, 1);
+#endif
+
+		REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 5);
+#ifdef BCM_ISCSI
+		REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5);
+		REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5);
+		REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5);
+#endif
+
+		bnx2x_init_block(bp, DMAE_COMMON_START, DMAE_COMMON_END);
+
+		/* let the HW do it's magic ... */
+		msleep(100);
+		/* finish PXP init
+		   (can be moved up if we want to use the DMAE) */
+		val = REG_RD(bp, PXP2_REG_RQ_CFG_DONE);
+		if (val != 1) {
+			BNX2X_ERR("PXP2 CFG failed\n");
+			return -EBUSY;
+		}
+
+		val = REG_RD(bp, PXP2_REG_RD_INIT_DONE);
+		if (val != 1) {
+			BNX2X_ERR("PXP2 RD_INIT failed\n");
+			return -EBUSY;
+		}
+
+		REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0);
+		REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0);
+
+		bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8);
+
+		bnx2x_init_block(bp, TCM_COMMON_START, TCM_COMMON_END);
+		bnx2x_init_block(bp, UCM_COMMON_START, UCM_COMMON_END);
+		bnx2x_init_block(bp, CCM_COMMON_START, CCM_COMMON_END);
+		bnx2x_init_block(bp, XCM_COMMON_START, XCM_COMMON_END);
+
+#ifdef BNX2X_DMAE_RD
+		bnx2x_read_dmae(bp, XSEM_REG_PASSIVE_BUFFER, 3);
+		bnx2x_read_dmae(bp, CSEM_REG_PASSIVE_BUFFER, 3);
+		bnx2x_read_dmae(bp, TSEM_REG_PASSIVE_BUFFER, 3);
+		bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3);
+#else
+		REG_RD(bp, XSEM_REG_PASSIVE_BUFFER);
+		REG_RD(bp, XSEM_REG_PASSIVE_BUFFER + 4);
+		REG_RD(bp, XSEM_REG_PASSIVE_BUFFER + 8);
+		REG_RD(bp, CSEM_REG_PASSIVE_BUFFER);
+		REG_RD(bp, CSEM_REG_PASSIVE_BUFFER + 4);
+		REG_RD(bp, CSEM_REG_PASSIVE_BUFFER + 8);
+		REG_RD(bp, TSEM_REG_PASSIVE_BUFFER);
+		REG_RD(bp, TSEM_REG_PASSIVE_BUFFER + 4);
+		REG_RD(bp, TSEM_REG_PASSIVE_BUFFER + 8);
+		REG_RD(bp, USEM_REG_PASSIVE_BUFFER);
+		REG_RD(bp, USEM_REG_PASSIVE_BUFFER + 4);
+		REG_RD(bp, USEM_REG_PASSIVE_BUFFER + 8);
+#endif
+		bnx2x_init_block(bp, QM_COMMON_START, QM_COMMON_END);
+		/* softrest pulse */
+		REG_WR(bp, QM_REG_SOFT_RESET, 1);
+		REG_WR(bp, QM_REG_SOFT_RESET, 0);
+
+#ifdef BCM_ISCSI
+		bnx2x_init_block(bp, TIMERS_COMMON_START, TIMERS_COMMON_END);
+#endif
+		bnx2x_init_block(bp, DQ_COMMON_START, DQ_COMMON_END);
+		REG_WR(bp, DORQ_REG_DPM_CID_OFST, BCM_PAGE_BITS);
+		if (CHIP_REV(bp) == CHIP_REV_Ax) {
+			/* enable hw interrupt from doorbell Q */
+			REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0);
+		}
+
+		bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END);
+
+		if (CHIP_REV_IS_SLOW(bp)) {
+			/* fix for emulation and FPGA for no pause */
+			REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0, 513);
+			REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_1, 513);
+			REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0, 0);
+			REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_1, 0);
+		}
+
+		bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END);
+
+		bnx2x_init_block(bp, TSDM_COMMON_START, TSDM_COMMON_END);
+		bnx2x_init_block(bp, CSDM_COMMON_START, CSDM_COMMON_END);
+		bnx2x_init_block(bp, USDM_COMMON_START, USDM_COMMON_END);
+		bnx2x_init_block(bp, XSDM_COMMON_START, XSDM_COMMON_END);
+
+		bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE);
+		bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE);
+		bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE);
+		bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE);
+
+		bnx2x_init_block(bp, TSEM_COMMON_START, TSEM_COMMON_END);
+		bnx2x_init_block(bp, USEM_COMMON_START, USEM_COMMON_END);
+		bnx2x_init_block(bp, CSEM_COMMON_START, CSEM_COMMON_END);
+		bnx2x_init_block(bp, XSEM_COMMON_START, XSEM_COMMON_END);
+
+		/* sync semi rtc */
+		REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
+		       0x80000000);
+		REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET,
+		       0x80000000);
+
+		bnx2x_init_block(bp, UPB_COMMON_START, UPB_COMMON_END);
+		bnx2x_init_block(bp, XPB_COMMON_START, XPB_COMMON_END);
+		bnx2x_init_block(bp, PBF_COMMON_START, PBF_COMMON_END);
+
+		REG_WR(bp, SRC_REG_SOFT_RST, 1);
+		for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4) {
+			REG_WR(bp, i, 0xc0cac01a);
+			/* TODO: repleace with something meaningfull */
+		}
+		/* SRCH COMMON comes here */
+		REG_WR(bp, SRC_REG_SOFT_RST, 0);
+
+		if (sizeof(union cdu_context) != 1024) {
+			/* we currently assume that a context is 1024 bytes */
+			printk(KERN_ALERT PFX "please adjust the size of"
+			       " cdu_context(%ld)\n",
+			       (long)sizeof(union cdu_context));
+		}
+		val = (4 << 24) + (0 << 12) + 1024;
+		REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val);
+		bnx2x_init_block(bp, CDU_COMMON_START, CDU_COMMON_END);
+
+		bnx2x_init_block(bp, CFC_COMMON_START, CFC_COMMON_END);
+		REG_WR(bp, CFC_REG_INIT_REG, 0x7FF);
+
+		bnx2x_init_block(bp, HC_COMMON_START, HC_COMMON_END);
+		bnx2x_init_block(bp, MISC_AEU_COMMON_START,
+				 MISC_AEU_COMMON_END);
+		/* RXPCS COMMON comes here */
+		/* EMAC0 COMMON comes here */
+		/* EMAC1 COMMON comes here */
+		/* DBU COMMON comes here */
+		/* DBG COMMON comes here */
+		bnx2x_init_block(bp, NIG_COMMON_START, NIG_COMMON_END);
+
+		if (CHIP_REV_IS_SLOW(bp))
+			msleep(200);
+
+		/* finish CFC init */
+		val = REG_RD(bp, CFC_REG_LL_INIT_DONE);
+		if (val != 1) {
+			BNX2X_ERR("CFC LL_INIT failed\n");
+			return -EBUSY;
+		}
+
+		val = REG_RD(bp, CFC_REG_AC_INIT_DONE);
+		if (val != 1) {
+			BNX2X_ERR("CFC AC_INIT failed\n");
+			return -EBUSY;
+		}
+
+		val = REG_RD(bp, CFC_REG_CAM_INIT_DONE);
+		if (val != 1) {
+			BNX2X_ERR("CFC CAM_INIT failed\n");
+			return -EBUSY;
+		}
+
+		REG_WR(bp, CFC_REG_DEBUG0, 0);
+
+		/* read NIG statistic
+		   to see if this is our first up since powerup */
+#ifdef BNX2X_DMAE_RD
+		bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2);
+		val = *bnx2x_sp(bp, wb_data[0]);
+#else
+		val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET);
+		REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4);
+#endif
+		/* do internal memory self test */
+		if ((val == 0) && bnx2x_int_mem_test(bp)) {
+			BNX2X_ERR("internal mem selftest failed\n");
+			return -EBUSY;
+		}
+
+		/* clear PXP2 attentions */
+		REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR);
+
+		enable_blocks_attention(bp);
+		/* enable_blocks_parity(bp); */
+
+	} /* end of common init */
+
+	/* per port init */
+
+	/* the phys address is shifted right 12 bits and has an added
+	   1=valid bit added to the 53rd bit
+	   then since this is a wide register(TM)
+	   we split it into two 32 bit writes
+	 */
+#define RQ_ONCHIP_AT_PORT_SIZE  384
+#define ONCHIP_ADDR1(x)   ((u32)(((u64)x >> 12) & 0xFFFFFFFF))
+#define ONCHIP_ADDR2(x)   ((u32)((1 << 20) | ((u64)x >> 44)))
+#define PXP_ONE_ILT(x)    ((x << 10) | x)
+
+	DP(BNX2X_MSG_MCP, "starting per-function init port is %x\n", func);
+
+	REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + func*4, 0);
+
+	/* Port PXP comes here */
+	/* Port PXP2 comes here */
+
+	/* Offset is
+	 * Port0  0
+	 * Port1  384 */
+	i = func * RQ_ONCHIP_AT_PORT_SIZE;
+#ifdef USE_DMAE
+	wb_write[0] = ONCHIP_ADDR1(bnx2x_sp_mapping(bp, context));
+	wb_write[1] = ONCHIP_ADDR2(bnx2x_sp_mapping(bp, context));
+	REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
+#else
+	REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + i*8,
+		   ONCHIP_ADDR1(bnx2x_sp_mapping(bp, context)));
+	REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + i*8 + 4,
+		   ONCHIP_ADDR2(bnx2x_sp_mapping(bp, context)));
+#endif
+	REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4, PXP_ONE_ILT(i));
+
+#ifdef BCM_ISCSI
+	/* Port0  1
+	 * Port1  385 */
+	i++;
+	wb_write[0] = ONCHIP_ADDR1(bp->timers_mapping);
+	wb_write[1] = ONCHIP_ADDR2(bp->timers_mapping);
+	REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
+	REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i));
+
+	/* Port0  2
+	 * Port1  386 */
+	i++;
+	wb_write[0] = ONCHIP_ADDR1(bp->qm_mapping);
+	wb_write[1] = ONCHIP_ADDR2(bp->qm_mapping);
+	REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
+	REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i));
+
+	/* Port0  3
+	 * Port1  387 */
+	i++;
+	wb_write[0] = ONCHIP_ADDR1(bp->t1_mapping);
+	wb_write[1] = ONCHIP_ADDR2(bp->t1_mapping);
+	REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
+	REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i));
+#endif
+
+	/* Port TCM comes here */
+	/* Port UCM comes here */
+	/* Port CCM comes here */
+	bnx2x_init_block(bp, func ? XCM_PORT1_START : XCM_PORT0_START,
+			     func ? XCM_PORT1_END : XCM_PORT0_END);
+
+#ifdef USE_DMAE
+	wb_write[0] = 0;
+	wb_write[1] = 0;
+#endif
+	for (i = 0; i < 32; i++) {
+		REG_WR(bp, QM_REG_BASEADDR + (func*32 + i)*4, 1024 * 4 * i);
+#ifdef USE_DMAE
+		REG_WR_DMAE(bp, QM_REG_PTRTBL + (func*32 + i)*8, wb_write, 2);
+#else
+		REG_WR_IND(bp, QM_REG_PTRTBL + (func*32 + i)*8, 0);
+		REG_WR_IND(bp, QM_REG_PTRTBL + (func*32 + i)*8 + 4, 0);
+#endif
+	}
+	REG_WR(bp, QM_REG_CONNNUM_0 + func*4, 1024/16 - 1);
+
+	/* Port QM comes here */
+
+#ifdef BCM_ISCSI
+	REG_WR(bp, TM_REG_LIN0_SCAN_TIME + func*4, 1024/64*20);
+	REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + func*4, 31);
+
+	bnx2x_init_block(bp, func ? TIMERS_PORT1_START : TIMERS_PORT0_START,
+			     func ? TIMERS_PORT1_END : TIMERS_PORT0_END);
+#endif
+	/* Port DQ comes here */
+	/* Port BRB1 comes here */
+	bnx2x_init_block(bp, func ? PRS_PORT1_START : PRS_PORT0_START,
+			     func ? PRS_PORT1_END : PRS_PORT0_END);
+	/* Port TSDM comes here */
+	/* Port CSDM comes here */
+	/* Port USDM comes here */
+	/* Port XSDM comes here */
+	bnx2x_init_block(bp, func ? TSEM_PORT1_START : TSEM_PORT0_START,
+			     func ? TSEM_PORT1_END : TSEM_PORT0_END);
+	bnx2x_init_block(bp, func ? USEM_PORT1_START : USEM_PORT0_START,
+			     func ? USEM_PORT1_END : USEM_PORT0_END);
+	bnx2x_init_block(bp, func ? CSEM_PORT1_START : CSEM_PORT0_START,
+			     func ? CSEM_PORT1_END : CSEM_PORT0_END);
+	bnx2x_init_block(bp, func ? XSEM_PORT1_START : XSEM_PORT0_START,
+			     func ? XSEM_PORT1_END : XSEM_PORT0_END);
+	/* Port UPB comes here */
+	/* Port XSDM comes here */
+	bnx2x_init_block(bp, func ? PBF_PORT1_START : PBF_PORT0_START,
+			     func ? PBF_PORT1_END : PBF_PORT0_END);
+
+	/* configure PBF to work without PAUSE mtu 9000 */
+	REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + func*4, 0);
+
+	/* update threshold */
+	REG_WR(bp, PBF_REG_P0_ARB_THRSH + func*4, (9040/16));
+	/* update init credit */
+	REG_WR(bp, PBF_REG_P0_INIT_CRD + func*4, (9040/16) + 553 - 22);
+
+	/* probe changes */
+	REG_WR(bp, PBF_REG_INIT_P0 + func*4, 1);
+	msleep(5);
+	REG_WR(bp, PBF_REG_INIT_P0 + func*4, 0);
+
+#ifdef BCM_ISCSI
+	/* tell the searcher where the T2 table is */
+	REG_WR(bp, SRC_REG_COUNTFREE0 + func*4, 16*1024/64);
+
+	wb_write[0] = U64_LO(bp->t2_mapping);
+	wb_write[1] = U64_HI(bp->t2_mapping);
+	REG_WR_DMAE(bp, SRC_REG_FIRSTFREE0 + func*4, wb_write, 2);
+	wb_write[0] = U64_LO((u64)bp->t2_mapping + 16*1024 - 64);
+	wb_write[1] = U64_HI((u64)bp->t2_mapping + 16*1024 - 64);
+	REG_WR_DMAE(bp, SRC_REG_LASTFREE0 + func*4, wb_write, 2);
+
+	REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + func*4, 10);
+	/* Port SRCH comes here */
+#endif
+	/* Port CDU comes here */
+	/* Port CFC comes here */
+	bnx2x_init_block(bp, func ? HC_PORT1_START : HC_PORT0_START,
+			     func ? HC_PORT1_END : HC_PORT0_END);
+	bnx2x_init_block(bp, func ? MISC_AEU_PORT1_START :
+				    MISC_AEU_PORT0_START,
+			     func ? MISC_AEU_PORT1_END : MISC_AEU_PORT0_END);
+	/* Port PXPCS comes here */
+	/* Port EMAC0 comes here */
+	/* Port EMAC1 comes here */
+	/* Port DBU comes here */
+	/* Port DBG comes here */
+	bnx2x_init_block(bp, func ? NIG_PORT1_START : NIG_PORT0_START,
+			     func ? NIG_PORT1_END : NIG_PORT0_END);
+	REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + func*4, 1);
+	/* Port MCP comes here */
+	/* Port DMAE comes here */
+
+	bnx2x_link_reset(bp);
+
+	/* Reset pciex errors for debug */
+	REG_WR(bp, 0x2114, 0xffffffff);
+	REG_WR(bp, 0x2120, 0xffffffff);
+	REG_WR(bp, 0x2814, 0xffffffff);
+
+	/* !!! move to init_values.h */
+	REG_WR(bp, XSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1);
+	REG_WR(bp, USDM_REG_INIT_CREDIT_PXP_CTRL, 0x1);
+	REG_WR(bp, CSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1);
+	REG_WR(bp, TSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1);
+
+	REG_WR(bp, DBG_REG_PCI_REQ_CREDIT, 0x1);
+	REG_WR(bp, TM_REG_PCIARB_CRDCNT_VAL, 0x1);
+	REG_WR(bp, CDU_REG_CDU_DEBUG, 0x264);
+	REG_WR(bp, CDU_REG_CDU_DEBUG, 0x0);
+
+	bnx2x_gunzip_end(bp);
+
+	if (!nomcp) {
+		port = bp->port;
+
+		bp->fw_drv_pulse_wr_seq =
+				(SHMEM_RD(bp, drv_fw_mb[port].drv_pulse_mb) &
+				 DRV_PULSE_SEQ_MASK);
+		bp->fw_mb = SHMEM_RD(bp, drv_fw_mb[port].fw_mb_param);
+		DP(BNX2X_MSG_MCP, "drv_pulse 0x%x  fw_mb 0x%x\n",
+		   bp->fw_drv_pulse_wr_seq, bp->fw_mb);
+	} else {
+		bp->fw_mb = 0;
+	}
+
+	return 0;
+}
+
+
+/* send the MCP a request, block untill there is a reply */
+static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
+{
+	u32 rc = 0;
+	u32 seq = ++bp->fw_seq;
+	int port = bp->port;
+
+	SHMEM_WR(bp, drv_fw_mb[port].drv_mb_header, command|seq);
+	DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", command|seq);
+
+	/* let the FW do it's magic ... */
+	msleep(100); /* TBD */
+
+	if (CHIP_REV_IS_SLOW(bp))
+		msleep(900);
+
+	rc = SHMEM_RD(bp, drv_fw_mb[port].fw_mb_header);
+
+	DP(BNX2X_MSG_MCP, "read (%x) seq is (%x) from FW MB\n", rc, seq);
+
+	/* is this a reply to our command? */
+	if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) {
+		rc &= FW_MSG_CODE_MASK;
+	} else {
+		/* FW BUG! */
+		BNX2X_ERR("FW failed to respond!\n");
+		bnx2x_fw_dump(bp);
+		rc = 0;
+	}
+	return rc;
+}
+
+static void bnx2x_free_mem(struct bnx2x *bp)
+{
+
+#define BNX2X_PCI_FREE(x, y, size) \
+	do { \
+		if (x) { \
+			pci_free_consistent(bp->pdev, size, x, y); \
+			x = NULL; \
+			y = 0; \
+		} \
+	} while (0)
+
+#define BNX2X_FREE(x) \
+	do { \
+		if (x) { \
+			vfree(x); \
+			x = NULL; \
+		} \
+	} while (0)
+
+	int i;
+
+	/* fastpath */
+	for_each_queue(bp, i) {
+
+		/* Status blocks */
+		BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk),
+			       bnx2x_fp(bp, i, status_blk_mapping),
+			       sizeof(struct host_status_block) +
+			       sizeof(struct eth_tx_db_data));
+
+		/* fast path rings: tx_buf tx_desc rx_buf rx_desc rx_comp */
+		BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring));
+		BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring),
+			       bnx2x_fp(bp, i, tx_desc_mapping),
+			       sizeof(struct eth_tx_bd) * NUM_TX_BD);
+
+		BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring));
+		BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_desc_ring),
+			       bnx2x_fp(bp, i, rx_desc_mapping),
+			       sizeof(struct eth_rx_bd) * NUM_RX_BD);
+
+		BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_comp_ring),
+			       bnx2x_fp(bp, i, rx_comp_mapping),
+			       sizeof(struct eth_fast_path_rx_cqe) *
+			       NUM_RCQ_BD);
+	}
+
+	BNX2X_FREE(bp->fp);
+
+	/* end of fastpath */
+
+	BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
+		       (sizeof(struct host_def_status_block)));
+
+	BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping,
+		       (sizeof(struct bnx2x_slowpath)));
+
+#ifdef BCM_ISCSI
+	BNX2X_PCI_FREE(bp->t1, bp->t1_mapping, 64*1024);
+	BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, 16*1024);
+	BNX2X_PCI_FREE(bp->timers, bp->timers_mapping, 8*1024);
+	BNX2X_PCI_FREE(bp->qm, bp->qm_mapping, 128*1024);
+#endif
+	BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, PAGE_SIZE);
+
+#undef BNX2X_PCI_FREE
+#undef BNX2X_KFREE
+}
+
+static int bnx2x_alloc_mem(struct bnx2x *bp)
+{
+
+#define BNX2X_PCI_ALLOC(x, y, size) \
+	do { \
+		x = pci_alloc_consistent(bp->pdev, size, y); \
+		if (x == NULL) \
+			goto alloc_mem_err; \
+		memset(x, 0, size); \
+	} while (0)
+
+#define BNX2X_ALLOC(x, size) \
+	do { \
+		x = vmalloc(size); \
+		if (x == NULL) \
+			goto alloc_mem_err; \
+		memset(x, 0, size); \
+	} while (0)
+
+	int i;
+
+	/* fastpath */
+	BNX2X_ALLOC(bp->fp, sizeof(struct bnx2x_fastpath) * bp->num_queues);
+
+	for_each_queue(bp, i) {
+		bnx2x_fp(bp, i, bp) = bp;
+
+		/* Status blocks */
+		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, status_blk),
+				&bnx2x_fp(bp, i, status_blk_mapping),
+				sizeof(struct host_status_block) +
+				sizeof(struct eth_tx_db_data));
+
+		bnx2x_fp(bp, i, hw_tx_prods) =
+				(void *)(bnx2x_fp(bp, i, status_blk) + 1);
+
+		bnx2x_fp(bp, i, tx_prods_mapping) =
+				bnx2x_fp(bp, i, status_blk_mapping) +
+				sizeof(struct host_status_block);
+
+		/* fast path rings: tx_buf tx_desc rx_buf rx_desc rx_comp */
+		BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring),
+				sizeof(struct sw_tx_bd) * NUM_TX_BD);
+		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring),
+				&bnx2x_fp(bp, i, tx_desc_mapping),
+				sizeof(struct eth_tx_bd) * NUM_TX_BD);
+
+		BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring),
+				sizeof(struct sw_rx_bd) * NUM_RX_BD);
+		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_desc_ring),
+				&bnx2x_fp(bp, i, rx_desc_mapping),
+				sizeof(struct eth_rx_bd) * NUM_RX_BD);
+
+		BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_comp_ring),
+				&bnx2x_fp(bp, i, rx_comp_mapping),
+				sizeof(struct eth_fast_path_rx_cqe) *
+				NUM_RCQ_BD);
+
+	}
+	/* end of fastpath */
+
+	BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping,
+			sizeof(struct host_def_status_block));
+
+	BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
+			sizeof(struct bnx2x_slowpath));
+
+#ifdef BCM_ISCSI
+	BNX2X_PCI_ALLOC(bp->t1, &bp->t1_mapping, 64*1024);
+
+	/* Initialize T1 */
+	for (i = 0; i < 64*1024; i += 64) {
+		*(u64 *)((char *)bp->t1 + i + 56) = 0x0UL;
+		*(u64 *)((char *)bp->t1 + i + 3) = 0x0UL;
+	}
+
+	/* allocate searcher T2 table
+	   we allocate 1/4 of alloc num for T2
+	  (which is not entered into the ILT) */
+	BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, 16*1024);
+
+	/* Initialize T2 */
+	for (i = 0; i < 16*1024; i += 64)
+		* (u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
+
+	/* now sixup the last line in the block to point to the next block */
+	*(u64 *)((char *)bp->t2 + 1024*16-8) = bp->t2_mapping;
+
+	/* Timer block array (MAX_CONN*8) phys uncached for now 1024 conns */
+	BNX2X_PCI_ALLOC(bp->timers, &bp->timers_mapping, 8*1024);
+
+	/* QM queues (128*MAX_CONN) */
+	BNX2X_PCI_ALLOC(bp->qm, &bp->qm_mapping, 128*1024);
+#endif
+
+	/* Slow path ring */
+	BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);
+
+	return 0;
+
+alloc_mem_err:
+	bnx2x_free_mem(bp);
+	return -ENOMEM;
+
+#undef BNX2X_PCI_ALLOC
+#undef BNX2X_ALLOC
+}
+
+static void bnx2x_free_tx_skbs(struct bnx2x *bp)
+{
+	int i;
+
+	for_each_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+
+		u16 bd_cons = fp->tx_bd_cons;
+		u16 sw_prod = fp->tx_pkt_prod;
+		u16 sw_cons = fp->tx_pkt_cons;
+
+		BUG_TRAP(fp->tx_buf_ring != NULL);
+
+		while (sw_cons != sw_prod) {
+			bd_cons = bnx2x_free_tx_pkt(bp, fp, TX_BD(sw_cons));
+			sw_cons++;
+		}
+	}
+}
+
+static void bnx2x_free_rx_skbs(struct bnx2x *bp)
+{
+	int i, j;
+
+	for_each_queue(bp, j) {
+		struct bnx2x_fastpath *fp = &bp->fp[j];
+
+		BUG_TRAP(fp->rx_buf_ring != NULL);
+
+		for (i = 0; i < NUM_RX_BD; i++) {
+			struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i];
+			struct sk_buff *skb = rx_buf->skb;
+
+			if (skb == NULL)
+				continue;
+
+			pci_unmap_single(bp->pdev,
+					 pci_unmap_addr(rx_buf, mapping),
+					 bp->rx_buf_use_size,
+					 PCI_DMA_FROMDEVICE);
+
+			rx_buf->skb = NULL;
+			dev_kfree_skb(skb);
+		}
+	}
+}
+
+static void bnx2x_free_skbs(struct bnx2x *bp)
+{
+	bnx2x_free_tx_skbs(bp);
+	bnx2x_free_rx_skbs(bp);
+}
+
+static void bnx2x_free_msix_irqs(struct bnx2x *bp)
+{
+	int i;
+
+	free_irq(bp->msix_table[0].vector, bp->dev);
+	DP(NETIF_MSG_IFDOWN, "rleased sp irq (%d)\n",
+	   bp->msix_table[0].vector);
+
+	for_each_queue(bp, i) {
+		DP(NETIF_MSG_IFDOWN, "about to rlease fp #%d->%d irq  "
+		   "state(%x)\n", i, bp->msix_table[i + 1].vector,
+		   bnx2x_fp(bp, i, state));
+
+		if (bnx2x_fp(bp, i, state) != BNX2X_FP_STATE_CLOSED) {
+
+			free_irq(bp->msix_table[i + 1].vector, &bp->fp[i]);
+			bnx2x_fp(bp, i, state) = BNX2X_FP_STATE_CLOSED;
+
+		} else
+			DP(NETIF_MSG_IFDOWN, "irq not freed\n");
+
+	}
+
+}
+
+static void bnx2x_free_irq(struct bnx2x *bp)
+{
+
+	if (bp->flags & USING_MSIX_FLAG) {
+
+		bnx2x_free_msix_irqs(bp);
+		pci_disable_msix(bp->pdev);
+
+		bp->flags &= ~USING_MSIX_FLAG;
+
+	} else
+		free_irq(bp->pdev->irq, bp->dev);
+}
+
+static int bnx2x_enable_msix(struct bnx2x *bp)
+{
+
+	int i;
+
+	bp->msix_table[0].entry = 0;
+	for_each_queue(bp, i)
+		bp->msix_table[i + 1].entry = i + 1;
+
+	if (pci_enable_msix(bp->pdev, &bp->msix_table[0],
+				     bp->num_queues + 1)){
+		BNX2X_ERR("failed to enable msix\n");
+		return -1;
+
+	}
+
+	bp->flags |= USING_MSIX_FLAG;
+
+	return 0;
+
+}
+
+
+static int bnx2x_req_msix_irqs(struct bnx2x *bp)
+{
+
+
+	int i, rc;
+
+	DP(NETIF_MSG_IFUP, "about to request sp irq\n");
+
+	rc = request_irq(bp->msix_table[0].vector, bnx2x_msix_sp_int, 0,
+			 bp->dev->name, bp->dev);
+
+	if (rc) {
+		BNX2X_ERR("request sp irq failed\n");
+		return -EBUSY;
+	}
+
+	for_each_queue(bp, i) {
+		rc = request_irq(bp->msix_table[i + 1].vector,
+				 bnx2x_msix_fp_int, 0,
+				 bp->dev->name, &bp->fp[i]);
+
+		if (rc) {
+			BNX2X_ERR("request fp #%d irq failed\n", i);
+			bnx2x_free_msix_irqs(bp);
+			return -EBUSY;
+		}
+
+		bnx2x_fp(bp, i, state) = BNX2X_FP_STATE_IRQ;
+
+	}
+
+	return 0;
+
+}
+
+static int bnx2x_req_irq(struct bnx2x *bp)
+{
+
+	int rc = request_irq(bp->pdev->irq, bnx2x_interrupt,
+			     IRQF_SHARED, bp->dev->name, bp->dev);
+	if (!rc)
+		bnx2x_fp(bp, 0, state) = BNX2X_FP_STATE_IRQ;
+
+	return rc;
+
+}
+
+/*
+ * Init service functions
+ */
+
+static void bnx2x_set_mac_addr(struct bnx2x *bp)
+{
+	struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
+
+	/* CAM allocation
+	 * unicasts 0-31:port0 32-63:port1
+	 * multicast 64-127:port0 128-191:port1
+	 */
+	config->hdr.length_6b = 2;
+	config->hdr.offset = bp->port ? 31 : 0;
+	config->hdr.reserved0 = 0;
+	config->hdr.reserved1 = 0;
+
+	/* primary MAC */
+	config->config_table[0].cam_entry.msb_mac_addr =
+					swab16(*(u16 *)&bp->dev->dev_addr[0]);
+	config->config_table[0].cam_entry.middle_mac_addr =
+					swab16(*(u16 *)&bp->dev->dev_addr[2]);
+	config->config_table[0].cam_entry.lsb_mac_addr =
+					swab16(*(u16 *)&bp->dev->dev_addr[4]);
+	config->config_table[0].cam_entry.flags = cpu_to_le16(bp->port);
+	config->config_table[0].target_table_entry.flags = 0;
+	config->config_table[0].target_table_entry.client_id = 0;
+	config->config_table[0].target_table_entry.vlan_id = 0;
+
+	DP(NETIF_MSG_IFUP, "setting MAC (%04x:%04x:%04x)\n",
+	   config->config_table[0].cam_entry.msb_mac_addr,
+	   config->config_table[0].cam_entry.middle_mac_addr,
+	   config->config_table[0].cam_entry.lsb_mac_addr);
+
+	/* broadcast */
+	config->config_table[1].cam_entry.msb_mac_addr = 0xffff;
+	config->config_table[1].cam_entry.middle_mac_addr = 0xffff;
+	config->config_table[1].cam_entry.lsb_mac_addr = 0xffff;
+	config->config_table[1].cam_entry.flags = cpu_to_le16(bp->port);
+	config->config_table[1].target_table_entry.flags =
+				TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST;
+	config->config_table[1].target_table_entry.client_id = 0;
+	config->config_table[1].target_table_entry.vlan_id = 0;
+
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
+		      U64_HI(bnx2x_sp_mapping(bp, mac_config)),
+		      U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
+}
+
+static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
+			     int *state_p, int poll)
+{
+	/* can take a while if any port is running */
+	int timeout = 500;
+
+	/* DP("waiting for state to become %d on IDX [%d]\n",
+	state, sb_idx); */
+
+	might_sleep();
+
+	while (timeout) {
+
+		if (poll) {
+			bnx2x_rx_int(bp->fp, 10);
+			/* If index is different from 0
+			 * The reply for some commands will
+			 * be on the none default queue
+			 */
+			if (idx)
+				bnx2x_rx_int(&bp->fp[idx], 10);
+		}
+
+		mb(); /* state is changed by bnx2x_sp_event()*/
+
+		if (*state_p != state)
+			return 0;
+
+		timeout--;
+		msleep(1);
+
+	}
+
+
+	/* timeout! */
+	BNX2X_ERR("timeout waiting for ramrod %d on %d\n", state, idx);
+	return -EBUSY;
+
+}
+
+static int bnx2x_setup_leading(struct bnx2x *bp)
+{
+
+	/* reset IGU staae */
+	bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+
+	/* SETUP ramrod */
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_SETUP, 0, 0, 0, 0);
+
+	return bnx2x_wait_ramrod(bp, BNX2X_STATE_OPEN, 0, &(bp->state), 0);
+
+}
+
+static int bnx2x_setup_multi(struct bnx2x *bp, int index)
+{
+
+	/* reset IGU state */
+	bnx2x_ack_sb(bp, index, CSTORM_ID, 0, IGU_INT_ENABLE, 0);
+
+	bp->fp[index].state = BNX2X_FP_STATE_OPENING;
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_SETUP, index, 0, index, 0);
+
+	/* Wait for completion */
+	return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_OPEN, index,
+				 &(bp->fp[index].state), 1);
+
+}
+
+
+static int bnx2x_poll(struct napi_struct *napi, int budget);
+static void bnx2x_set_rx_mode(struct net_device *dev);
+
+static int bnx2x_nic_load(struct bnx2x *bp, int req_irq)
+{
+	int rc;
+	int i = 0;
+
+	bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
+
+	/* Send LOAD_REQUEST command to MCP.
+	   Returns the type of LOAD command: if it is the
+	   first port to be initialized common blocks should be
+	   initialized, otherwise - not.
+	*/
+	if (!nomcp) {
+		rc = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ);
+		if (rc == FW_MSG_CODE_DRV_LOAD_REFUSED) {
+			return -EBUSY; /* other port in diagnostic mode */
+		}
+	} else {
+		rc = FW_MSG_CODE_DRV_LOAD_COMMON;
+	}
+
+	DP(NETIF_MSG_IFUP, "set number of queues to %d\n", bp->num_queues);
+
+	/* if we can't use msix we only need one fp,
+	 * so try to enable msix with the requested number of fp's
+	 * and fallback to inta with one fp
+	 */
+	if (req_irq) {
+
+		if (use_inta) {
+			bp->num_queues = 1;
+		} else {
+			if (use_multi > 1 && use_multi <= 16)
+				/* user requested number */
+				bp->num_queues = use_multi;
+			else if (use_multi == 1)
+				bp->num_queues = num_online_cpus();
+			else
+				bp->num_queues = 1;
+
+			if (bnx2x_enable_msix(bp)) {
+				/* faild to enable msix */
+				bp->num_queues = 1;
+				if (use_multi)
+					BNX2X_ERR("Muti requested but failed"
+						  " to enable MSI-X\n");
+			}
+		}
+	}
+
+	if (bnx2x_alloc_mem(bp))
+		return -ENOMEM;
+
+	if (req_irq) {
+		if (bp->flags & USING_MSIX_FLAG) {
+			if (bnx2x_req_msix_irqs(bp)) {
+				pci_disable_msix(bp->pdev);
+				goto out_error;
+			}
+
+		} else {
+			if (bnx2x_req_irq(bp)) {
+				BNX2X_ERR("IRQ request failed, aborting\n");
+				goto out_error;
+			}
+		}
+	}
+
+	for_each_queue(bp, i)
+		netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
+			       bnx2x_poll, 128);
+
+
+	/* Initialize HW */
+	if (bnx2x_function_init(bp, (rc == FW_MSG_CODE_DRV_LOAD_COMMON))) {
+		BNX2X_ERR("HW init failed, aborting\n");
+		goto out_error;
+	}
+
+
+	atomic_set(&bp->intr_sem, 0);
+
+	/* Reenable SP tasklet */
+	/*if (bp->sp_task_en) { 	       */
+	/*        tasklet_enable(&bp->sp_task);*/
+	/*} else {      		       */
+	/*        bp->sp_task_en = 1;          */
+	/*}     			       */
+
+	/* Setup NIC internals and enable interrupts */
+	bnx2x_nic_init(bp);
+
+	/* Send LOAD_DONE command to MCP */
+	if (!nomcp) {
+		rc = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE);
+		DP(NETIF_MSG_IFUP, "rc = 0x%x\n", rc);
+		if (!rc) {
+			BNX2X_ERR("MCP response failure, unloading\n");
+			goto int_disable;
+		}
+	}
+
+	bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
+
+	/* Enable Rx interrupt handling before sending the ramrod
+	   as it's completed on Rx FP queue */
+	for_each_queue(bp, i)
+		napi_enable(&bnx2x_fp(bp, i, napi));
+
+	if (bnx2x_setup_leading(bp))
+		goto stop_netif;
+
+	for_each_nondefault_queue(bp, i)
+		if (bnx2x_setup_multi(bp, i))
+			goto stop_netif;
+
+	bnx2x_set_mac_addr(bp);
+
+	bnx2x_phy_init(bp);
+
+	/* Start fast path */
+	if (req_irq) { /* IRQ is only requested from bnx2x_open */
+		netif_start_queue(bp->dev);
+		if (bp->flags & USING_MSIX_FLAG)
+			printk(KERN_INFO PFX "%s: using MSI-X\n",
+			       bp->dev->name);
+
+	/* Otherwise Tx queue should be only reenabled */
+	} else if (netif_running(bp->dev)) {
+		netif_wake_queue(bp->dev);
+		bnx2x_set_rx_mode(bp->dev);
+	}
+
+	/* start the timer */
+	mod_timer(&bp->timer, jiffies + bp->current_interval);
+
+	return 0;
+
+stop_netif:
+	for_each_queue(bp, i)
+		napi_disable(&bnx2x_fp(bp, i, napi));
+
+int_disable:
+	bnx2x_disable_int_sync(bp);
+
+	bnx2x_free_skbs(bp);
+	bnx2x_free_irq(bp);
+
+out_error:
+	bnx2x_free_mem(bp);
+
+	/* TBD we really need to reset the chip
+	   if we want to recover from this */
+	return rc;
+}
+
+static void bnx2x_netif_stop(struct bnx2x *bp)
+{
+	int i;
+
+	bp->rx_mode = BNX2X_RX_MODE_NONE;
+	bnx2x_set_storm_rx_mode(bp);
+
+	bnx2x_disable_int_sync(bp);
+	bnx2x_link_reset(bp);
+
+	for_each_queue(bp, i)
+		napi_disable(&bnx2x_fp(bp, i, napi));
+
+	if (netif_running(bp->dev)) {
+		netif_tx_disable(bp->dev);
+		bp->dev->trans_start = jiffies; /* prevent tx timeout */
+	}
+}
+
+static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code)
+{
+	int port = bp->port;
+#ifdef USE_DMAE
+	u32 wb_write[2];
+#endif
+	int base, i;
+
+	DP(NETIF_MSG_IFDOWN, "reset called with code %x\n", reset_code);
+
+	/* Do not rcv packets to BRB */
+	REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK + port*4, 0x0);
+	/* Do not direct rcv packets that are not for MCP to the BRB */
+	REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP :
+			   NIG_REG_LLH0_BRB1_NOT_MCP), 0x0);
+
+	/* Configure IGU and AEU */
+	REG_WR(bp, HC_REG_CONFIG_0 + port*4, 0x1000);
+	REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, 0);
+
+	/* TODO: Close Doorbell port? */
+
+	/* Clear ILT */
+#ifdef USE_DMAE
+	wb_write[0] = 0;
+	wb_write[1] = 0;
+#endif
+	base = port * RQ_ONCHIP_AT_PORT_SIZE;
+	for (i = base; i < base + RQ_ONCHIP_AT_PORT_SIZE; i++) {
+#ifdef USE_DMAE
+		REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
+#else
+		REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT, 0);
+		REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + 4, 0);
+#endif
+	}
+
+	if (reset_code == FW_MSG_CODE_DRV_UNLOAD_COMMON) {
+		/* reset_common */
+		REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
+		       0xd3ffff7f);
+		REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+		       0x1403);
+	}
+}
+
+static int bnx2x_stop_multi(struct bnx2x *bp, int index)
+{
+
+	int rc;
+
+	/* halt the connnection */
+	bp->fp[index].state = BNX2X_FP_STATE_HALTING;
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, index, 0, 0, 0);
+
+
+	rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, index,
+				       &(bp->fp[index].state), 1);
+	if (rc) /* timout */
+		return rc;
+
+	/* delete cfc entry */
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CFC_DEL, index, 0, 0, 1);
+
+	return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_DELETED, index,
+				 &(bp->fp[index].state), 1);
+
+}
+
+
+static void bnx2x_stop_leading(struct bnx2x *bp)
+{
+
+	/* if the other port is hadling traffic,
+	   this can take a lot of time */
+	int timeout = 500;
+
+	might_sleep();
+
+	/* Send HALT ramrod */
+	bp->fp[0].state = BNX2X_FP_STATE_HALTING;
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, 0, 0, 0, 0);
+
+	if (bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, 0,
+			       &(bp->fp[0].state), 1))
+		return;
+
+	bp->dsb_sp_prod_idx = *bp->dsb_sp_prod;
+
+	/* Send CFC_DELETE ramrod */
+	bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_DEL, 0, 0, 0, 1);
+
+	/*
+	   Wait for completion.
+	   we are going to reset the chip anyway
+	   so there is not much to do if this times out
+	 */
+	while (bp->dsb_sp_prod_idx == *bp->dsb_sp_prod && timeout) {
+			timeout--;
+			msleep(1);
+	}
+
+}
+
+static int bnx2x_nic_unload(struct bnx2x *bp, int fre_irq)
+{
+	u32 reset_code = 0;
+	int rc;
+	int i;
+
+	bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
+
+	/* Calling flush_scheduled_work() may deadlock because
+	 * linkwatch_event() may be on the workqueue and it will try to get
+	 * the rtnl_lock which we are holding.
+	 */
+
+	while (bp->in_reset_task)
+		msleep(1);
+
+	/* Delete the timer: do it before disabling interrupts, as it
+	   may be stil STAT_QUERY ramrod pending after stopping the timer */
+	del_timer_sync(&bp->timer);
+
+	/* Wait until stat ramrod returns and all SP tasks complete */
+	while (bp->stat_pending && (bp->spq_left != MAX_SPQ_PENDING))
+		msleep(1);
+
+	/* Stop fast path, disable MAC, disable interrupts, disable napi */
+	bnx2x_netif_stop(bp);
+
+	if (bp->flags & NO_WOL_FLAG)
+		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP;
+	else if (bp->wol) {
+		u32 emac_base = bp->port ? GRCBASE_EMAC0 : GRCBASE_EMAC1;
+		u8 *mac_addr = bp->dev->dev_addr;
+		u32 val = (EMAC_MODE_MPKT | EMAC_MODE_MPKT_RCVD |
+			   EMAC_MODE_ACPI_RCVD);
+
+		EMAC_WR(EMAC_REG_EMAC_MODE, val);
+
+		val = (mac_addr[0] << 8) | mac_addr[1];
+		EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val);
+
+		val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
+		      (mac_addr[4] << 8) | mac_addr[5];
+		EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val);
+
+		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN;
+	} else
+		reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
+
+	for_each_nondefault_queue(bp, i)
+		if (bnx2x_stop_multi(bp, i))
+			goto error;
+
+
+	bnx2x_stop_leading(bp);
+
+error:
+	if (!nomcp)
+		rc = bnx2x_fw_command(bp, reset_code);
+	else
+		rc = FW_MSG_CODE_DRV_UNLOAD_COMMON;
+
+	/* Release IRQs */
+	if (fre_irq)
+		bnx2x_free_irq(bp);
+
+	/* Reset the chip */
+	bnx2x_reset_chip(bp, rc);
+
+	/* Report UNLOAD_DONE to MCP */
+	if (!nomcp)
+		bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
+
+	/* Free SKBs and driver internals */
+	bnx2x_free_skbs(bp);
+	bnx2x_free_mem(bp);
+
+	bp->state = BNX2X_STATE_CLOSED;
+	/* Set link down */
+	bp->link_up = 0;
+	netif_carrier_off(bp->dev);
+
+	return 0;
+}
+
+/* end of nic load/unload */
+
+/* ethtool_ops */
+
+/*
+ * Init service functions
+ */
+
+static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg)
+{
+	int port = bp->port;
+	u32 ext_phy_type;
+
+	bp->phy_flags = 0;
+
+	switch (switch_cfg) {
+	case SWITCH_CFG_1G:
+		BNX2X_DEV_INFO("switch_cfg 0x%x (1G)\n", switch_cfg);
+
+		ext_phy_type = SERDES_EXT_PHY_TYPE(bp);
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
+				       ext_phy_type);
+
+			bp->supported |= (SUPPORTED_10baseT_Half |
+					  SUPPORTED_10baseT_Full |
+					  SUPPORTED_100baseT_Half |
+					  SUPPORTED_100baseT_Full |
+					  SUPPORTED_1000baseT_Full |
+					  SUPPORTED_2500baseT_Full |
+					  SUPPORTED_TP | SUPPORTED_FIBRE |
+					  SUPPORTED_Autoneg |
+					  SUPPORTED_Pause |
+					  SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (5482)\n",
+				       ext_phy_type);
+
+			bp->phy_flags |= PHY_SGMII_FLAG;
+
+			bp->supported |= (/* SUPPORTED_10baseT_Half |
+					     SUPPORTED_10baseT_Full |
+					     SUPPORTED_100baseT_Half |
+					     SUPPORTED_100baseT_Full |*/
+					  SUPPORTED_1000baseT_Full |
+					  SUPPORTED_TP | SUPPORTED_FIBRE |
+					  SUPPORTED_Autoneg |
+					  SUPPORTED_Pause |
+					  SUPPORTED_Asym_Pause);
+			break;
+
+		default:
+			BNX2X_ERR("NVRAM config error. "
+				  "BAD SerDes ext_phy_config 0x%x\n",
+				  bp->ext_phy_config);
+			return;
+		}
+
+		bp->phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR +
+				      port*0x10);
+		BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->phy_addr);
+		break;
+
+	case SWITCH_CFG_10G:
+		BNX2X_DEV_INFO("switch_cfg 0x%x (10G)\n", switch_cfg);
+
+		bp->phy_flags |= PHY_XGXS_FLAG;
+
+		ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
+		switch (ext_phy_type) {
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n",
+				       ext_phy_type);
+
+			bp->supported |= (SUPPORTED_10baseT_Half |
+					  SUPPORTED_10baseT_Full |
+					  SUPPORTED_100baseT_Half |
+					  SUPPORTED_100baseT_Full |
+					  SUPPORTED_1000baseT_Full |
+					  SUPPORTED_2500baseT_Full |
+					  SUPPORTED_10000baseT_Full |
+					  SUPPORTED_TP | SUPPORTED_FIBRE |
+					  SUPPORTED_Autoneg |
+					  SUPPORTED_Pause |
+					  SUPPORTED_Asym_Pause);
+			break;
+
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
+		case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
+			BNX2X_DEV_INFO("ext_phy_type 0x%x (8705/6)\n",
+				       ext_phy_type);
+
+			bp->supported |= (SUPPORTED_10000baseT_Full |
+					  SUPPORTED_FIBRE |
+					  SUPPORTED_Pause |
+					  SUPPORTED_Asym_Pause);
+			break;
+
+		default:
+			BNX2X_ERR("NVRAM config error. "
+				  "BAD XGXS ext_phy_config 0x%x\n",
+				  bp->ext_phy_config);
+			return;
+		}
+
+		bp->phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR +
+				      port*0x18);
+		BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->phy_addr);
+
+		bp->ser_lane = ((bp->lane_config &
+				 PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
+				PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
+		bp->rx_lane_swap = ((bp->lane_config &
+				     PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >>
+				    PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT);
+		bp->tx_lane_swap = ((bp->lane_config &
+				     PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >>
+				    PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT);
+		BNX2X_DEV_INFO("rx_lane_swap 0x%x  tx_lane_swap 0x%x\n",
+			       bp->rx_lane_swap, bp->tx_lane_swap);
+		break;
+
+	default:
+		BNX2X_ERR("BAD switch_cfg link_config 0x%x\n",
+			  bp->link_config);
+		return;
+	}
+
+	/* mask what we support according to speed_cap_mask */
+	if (!(bp->speed_cap_mask &
+	      PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF))
+		bp->supported &= ~SUPPORTED_10baseT_Half;
+
+	if (!(bp->speed_cap_mask &
+	      PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL))
+		bp->supported &= ~SUPPORTED_10baseT_Full;
+
+	if (!(bp->speed_cap_mask &
+	      PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF))
+		bp->supported &= ~SUPPORTED_100baseT_Half;
+
+	if (!(bp->speed_cap_mask &
+	      PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL))
+		bp->supported &= ~SUPPORTED_100baseT_Full;
+
+	if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))
+		bp->supported &= ~(SUPPORTED_1000baseT_Half |
+				   SUPPORTED_1000baseT_Full);
+
+	if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G))
+		bp->supported &= ~SUPPORTED_2500baseT_Full;
+
+	if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G))
+		bp->supported &= ~SUPPORTED_10000baseT_Full;
+
+	BNX2X_DEV_INFO("supported 0x%x\n", bp->supported);
+}
+
+static void bnx2x_link_settings_requested(struct bnx2x *bp)
+{
+	bp->req_autoneg = 0;
+	bp->req_duplex = DUPLEX_FULL;
+
+	switch (bp->link_config & PORT_FEATURE_LINK_SPEED_MASK) {
+	case PORT_FEATURE_LINK_SPEED_AUTO:
+		if (bp->supported & SUPPORTED_Autoneg) {
+			bp->req_autoneg |= AUTONEG_SPEED;
+			bp->req_line_speed = 0;
+			bp->advertising = bp->supported;
+		} else {
+			u32 ext_phy_type;
+
+			ext_phy_type = XGXS_EXT_PHY_TYPE(bp);
+			if ((ext_phy_type ==
+				PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
+			    (ext_phy_type ==
+				PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706)) {
+				/* force 10G, no AN */
+				bp->req_line_speed = SPEED_10000;
+				bp->advertising =
+						(ADVERTISED_10000baseT_Full |
+						 ADVERTISED_FIBRE);
+				break;
+			}
+			BNX2X_ERR("NVRAM config error. "
+				  "Invalid link_config 0x%x"
+				  "  Autoneg not supported\n",
+				  bp->link_config);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_10M_FULL:
+		if (bp->speed_cap_mask &
+		    PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) {
+			bp->req_line_speed = SPEED_10;
+			bp->advertising = (ADVERTISED_10baseT_Full |
+					   ADVERTISED_TP);
+		} else {
+			BNX2X_ERR("NVRAM config error. "
+				  "Invalid link_config 0x%x"
+				  "  speed_cap_mask 0x%x\n",
+				  bp->link_config, bp->speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_10M_HALF:
+		if (bp->speed_cap_mask &
+		    PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF) {
+			bp->req_line_speed = SPEED_10;
+			bp->req_duplex = DUPLEX_HALF;
+			bp->advertising = (ADVERTISED_10baseT_Half |
+					   ADVERTISED_TP);
+		} else {
+			BNX2X_ERR("NVRAM config error. "
+				  "Invalid link_config 0x%x"
+				  "  speed_cap_mask 0x%x\n",
+				  bp->link_config, bp->speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_100M_FULL:
+		if (bp->speed_cap_mask &
+		    PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL) {
+			bp->req_line_speed = SPEED_100;
+			bp->advertising = (ADVERTISED_100baseT_Full |
+					   ADVERTISED_TP);
+		} else {
+			BNX2X_ERR("NVRAM config error. "
+				  "Invalid link_config 0x%x"
+				  "  speed_cap_mask 0x%x\n",
+				  bp->link_config, bp->speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_100M_HALF:
+		if (bp->speed_cap_mask &
+		    PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF) {
+			bp->req_line_speed = SPEED_100;
+			bp->req_duplex = DUPLEX_HALF;
+			bp->advertising = (ADVERTISED_100baseT_Half |
+					   ADVERTISED_TP);
+		} else {
+			BNX2X_ERR("NVRAM config error. "
+				  "Invalid link_config 0x%x"
+				  "  speed_cap_mask 0x%x\n",
+				  bp->link_config, bp->speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_1G:
+		if (bp->speed_cap_mask &
+		    PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) {
+			bp->req_line_speed = SPEED_1000;
+			bp->advertising = (ADVERTISED_1000baseT_Full |
+					   ADVERTISED_TP);
+		} else {
+			BNX2X_ERR("NVRAM config error. "
+				  "Invalid link_config 0x%x"
+				  "  speed_cap_mask 0x%x\n",
+				  bp->link_config, bp->speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_2_5G:
+		if (bp->speed_cap_mask &
+		    PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) {
+			bp->req_line_speed = SPEED_2500;
+			bp->advertising = (ADVERTISED_2500baseT_Full |
+					   ADVERTISED_TP);
+		} else {
+			BNX2X_ERR("NVRAM config error. "
+				  "Invalid link_config 0x%x"
+				  "  speed_cap_mask 0x%x\n",
+				  bp->link_config, bp->speed_cap_mask);
+			return;
+		}
+		break;
+
+	case PORT_FEATURE_LINK_SPEED_10G_CX4:
+	case PORT_FEATURE_LINK_SPEED_10G_KX4:
+	case PORT_FEATURE_LINK_SPEED_10G_KR:
+		if (!(bp->phy_flags & PHY_XGXS_FLAG)) {
+			BNX2X_ERR("NVRAM config error. "
+				  "Invalid link_config 0x%x"
+				  "  phy_flags 0x%x\n",
+				  bp->link_config, bp->phy_flags);
+			return;
+		}
+		if (bp->speed_cap_mask &
+		    PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) {
+			bp->req_line_speed = SPEED_10000;
+			bp->advertising = (ADVERTISED_10000baseT_Full |
+					   ADVERTISED_FIBRE);
+		} else {
+			BNX2X_ERR("NVRAM config error. "
+				  "Invalid link_config 0x%x"
+				  "  speed_cap_mask 0x%x\n",
+				  bp->link_config, bp->speed_cap_mask);
+			return;
+		}
+		break;
+
+	default:
+		BNX2X_ERR("NVRAM config error. "
+			  "BAD link speed link_config 0x%x\n",
+			  bp->link_config);
+		bp->req_autoneg |= AUTONEG_SPEED;
+		bp->req_line_speed = 0;
+		bp->advertising = bp->supported;
+		break;
+	}
+	BNX2X_DEV_INFO("req_line_speed %d  req_duplex %d\n",
+		       bp->req_line_speed, bp->req_duplex);
+
+	bp->req_flow_ctrl = (bp->link_config &
+			     PORT_FEATURE_FLOW_CONTROL_MASK);
+	/* Please refer to Table 28B-3 of the 802.3ab-1999 spec */
+	switch (bp->req_flow_ctrl) {
+	case FLOW_CTRL_AUTO:
+		bp->req_autoneg |= AUTONEG_FLOW_CTRL;
+		if (bp->dev->mtu <= 4500) {
+			bp->pause_mode = PAUSE_BOTH;
+			bp->advertising |= (ADVERTISED_Pause |
+					    ADVERTISED_Asym_Pause);
+		} else {
+			bp->pause_mode = PAUSE_ASYMMETRIC;
+			bp->advertising |= ADVERTISED_Asym_Pause;
+		}
+		break;
+
+	case FLOW_CTRL_TX:
+		bp->pause_mode = PAUSE_ASYMMETRIC;
+		bp->advertising |= ADVERTISED_Asym_Pause;
+		break;
+
+	case FLOW_CTRL_RX:
+	case FLOW_CTRL_BOTH:
+		bp->pause_mode = PAUSE_BOTH;
+		bp->advertising |= (ADVERTISED_Pause |
+				    ADVERTISED_Asym_Pause);
+		break;
+
+	case FLOW_CTRL_NONE:
+	default:
+		bp->pause_mode = PAUSE_NONE;
+		bp->advertising &= ~(ADVERTISED_Pause |
+				     ADVERTISED_Asym_Pause);
+		break;
+	}
+	BNX2X_DEV_INFO("req_autoneg 0x%x  req_flow_ctrl 0x%x\n"
+	     KERN_INFO "  pause_mode %d  advertising 0x%x\n",
+		       bp->req_autoneg, bp->req_flow_ctrl,
+		       bp->pause_mode, bp->advertising);
+}
+
+static void bnx2x_get_hwinfo(struct bnx2x *bp)
+{
+	u32 val, val2, val3, val4, id;
+	int port = bp->port;
+	u32 switch_cfg;
+
+	bp->shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+	BNX2X_DEV_INFO("shmem offset is %x\n", bp->shmem_base);
+
+	/* Get the chip revision id and number. */
+	/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
+	val = REG_RD(bp, MISC_REG_CHIP_NUM);
+	id = ((val & 0xffff) << 16);
+	val = REG_RD(bp, MISC_REG_CHIP_REV);
+	id |= ((val & 0xf) << 12);
+	val = REG_RD(bp, MISC_REG_CHIP_METAL);
+	id |= ((val & 0xff) << 4);
+	REG_RD(bp, MISC_REG_BOND_ID);
+	id |= (val & 0xf);
+	bp->chip_id = id;
+	BNX2X_DEV_INFO("chip ID is %x\n", id);
+
+	if (!bp->shmem_base || (bp->shmem_base != 0xAF900)) {
+		BNX2X_DEV_INFO("MCP not active\n");
+		nomcp = 1;
+		goto set_mac;
+	}
+
+	val = SHMEM_RD(bp, validity_map[port]);
+	if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+		!= (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+		BNX2X_ERR("MCP validity signature bad\n");
+
+	bp->fw_seq = (SHMEM_RD(bp, drv_fw_mb[port].drv_mb_header) &
+		      DRV_MSG_SEQ_NUMBER_MASK);
+
+	bp->hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config);
+
+	bp->serdes_config =
+		SHMEM_RD(bp, dev_info.port_hw_config[bp->port].serdes_config);
+	bp->lane_config =
+		SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config);
+	bp->ext_phy_config =
+		SHMEM_RD(bp,
+			 dev_info.port_hw_config[port].external_phy_config);
+	bp->speed_cap_mask =
+		SHMEM_RD(bp,
+			 dev_info.port_hw_config[port].speed_capability_mask);
+
+	bp->link_config =
+		SHMEM_RD(bp, dev_info.port_feature_config[port].link_config);
+
+	BNX2X_DEV_INFO("hw_config (%08x)  serdes_config (%08x)\n"
+	     KERN_INFO "  lane_config (%08x)  ext_phy_config (%08x)\n"
+	     KERN_INFO "  speed_cap_mask (%08x)  link_config (%08x)"
+		       "  fw_seq (%08x)\n",
+		       bp->hw_config, bp->serdes_config, bp->lane_config,
+		       bp->ext_phy_config, bp->speed_cap_mask,
+		       bp->link_config, bp->fw_seq);
+
+	switch_cfg = (bp->link_config & PORT_FEATURE_CONNECTED_SWITCH_MASK);
+	bnx2x_link_settings_supported(bp, switch_cfg);
+
+	bp->autoneg = (bp->hw_config & SHARED_HW_CFG_AN_ENABLE_MASK);
+	/* for now disable cl73 */
+	bp->autoneg &= ~SHARED_HW_CFG_AN_ENABLE_CL73;
+	BNX2X_DEV_INFO("autoneg 0x%x\n", bp->autoneg);
+
+	bnx2x_link_settings_requested(bp);
+
+	val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
+	val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
+	bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff);
+	bp->dev->dev_addr[1] = (u8)(val2 & 0xff);
+	bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff);
+	bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff);
+	bp->dev->dev_addr[4] = (u8)(val >> 8  & 0xff);
+	bp->dev->dev_addr[5] = (u8)(val & 0xff);
+
+	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, 6);
+
+
+	val = SHMEM_RD(bp, dev_info.shared_hw_config.part_num);
+	val2 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[4]);
+	val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]);
+	val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]);
+
+	printk(KERN_INFO PFX "part number %X-%X-%X-%X\n",
+	       val, val2, val3, val4);
+
+	/* bc ver */
+	if (!nomcp) {
+		bp->bc_ver = val = ((SHMEM_RD(bp, dev_info.bc_rev)) >> 8);
+		BNX2X_DEV_INFO("bc_ver %X\n", val);
+		if (val < BNX2X_BC_VER) {
+			/* for now only warn
+			 * later we might need to enforce this */
+			BNX2X_ERR("This driver needs bc_ver %X but found %X,"
+				  " please upgrade BC\n", BNX2X_BC_VER, val);
+		}
+	} else {
+		bp->bc_ver = 0;
+	}
+
+	val = REG_RD(bp, MCP_REG_MCPR_NVM_CFG4);
+	bp->flash_size = (NVRAM_1MB_SIZE << (val & MCPR_NVM_CFG4_FLASH_SIZE));
+	BNX2X_DEV_INFO("flash_size 0x%x (%d)\n",
+		       bp->flash_size, bp->flash_size);
+
+	return;
+
+set_mac: /* only supposed to happen on emulation/FPGA */
+	BNX2X_ERR("warning constant MAC workaround active\n");
+	bp->dev->dev_addr[0] = 0;
+	bp->dev->dev_addr[1] = 0x50;
+	bp->dev->dev_addr[2] = 0xc2;
+	bp->dev->dev_addr[3] = 0x2c;
+	bp->dev->dev_addr[4] = 0x71;
+	bp->dev->dev_addr[5] = port ? 0x0d : 0x0e;
+
+	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, 6);
+
+}
+
+/*
+ * ethtool service functions
+ */
+
+/* All ethtool functions called with rtnl_lock */
+
+static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	cmd->supported = bp->supported;
+	cmd->advertising = bp->advertising;
+
+	if (netif_carrier_ok(dev)) {
+		cmd->speed = bp->line_speed;
+		cmd->duplex = bp->duplex;
+	} else {
+		cmd->speed = bp->req_line_speed;
+		cmd->duplex = bp->req_duplex;
+	}
+
+	if (bp->phy_flags & PHY_XGXS_FLAG) {
+		cmd->port = PORT_FIBRE;
+	} else {
+		cmd->port = PORT_TP;
+	}
+
+	cmd->phy_address = bp->phy_addr;
+	cmd->transceiver = XCVR_INTERNAL;
+
+	if (bp->req_autoneg & AUTONEG_SPEED) {
+		cmd->autoneg = AUTONEG_ENABLE;
+	} else {
+		cmd->autoneg = AUTONEG_DISABLE;
+	}
+
+	cmd->maxtxpkt = 0;
+	cmd->maxrxpkt = 0;
+
+	DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
+	   DP_LEVEL "  supported 0x%x  advertising 0x%x  speed %d\n"
+	   DP_LEVEL "  duplex %d  port %d  phy_address %d  transceiver %d\n"
+	   DP_LEVEL "  autoneg %d  maxtxpkt %d  maxrxpkt %d\n",
+	   cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
+	   cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
+	   cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
+
+	return 0;
+}
+
+static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	u32 advertising;
+
+	DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
+	   DP_LEVEL "  supported 0x%x  advertising 0x%x  speed %d\n"
+	   DP_LEVEL "  duplex %d  port %d  phy_address %d  transceiver %d\n"
+	   DP_LEVEL "  autoneg %d  maxtxpkt %d  maxrxpkt %d\n",
+	   cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
+	   cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
+	   cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
+
+	switch (cmd->port) {
+	case PORT_TP:
+		if (!(bp->supported & SUPPORTED_TP))
+			return -EINVAL;
+
+		if (bp->phy_flags & PHY_XGXS_FLAG) {
+			bnx2x_link_reset(bp);
+			bnx2x_link_settings_supported(bp, SWITCH_CFG_1G);
+			bnx2x_phy_deassert(bp);
+		}
+		break;
+
+	case PORT_FIBRE:
+		if (!(bp->supported & SUPPORTED_FIBRE))
+			return -EINVAL;
+
+		if (!(bp->phy_flags & PHY_XGXS_FLAG)) {
+			bnx2x_link_reset(bp);
+			bnx2x_link_settings_supported(bp, SWITCH_CFG_10G);
+			bnx2x_phy_deassert(bp);
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (cmd->autoneg == AUTONEG_ENABLE) {
+		if (!(bp->supported & SUPPORTED_Autoneg))
+			return -EINVAL;
+
+		/* advertise the requested speed and duplex if supported */
+		cmd->advertising &= bp->supported;
+
+		bp->req_autoneg |= AUTONEG_SPEED;
+		bp->req_line_speed = 0;
+		bp->req_duplex = DUPLEX_FULL;
+		bp->advertising |= (ADVERTISED_Autoneg | cmd->advertising);
+
+	} else { /* forced speed */
+		/* advertise the requested speed and duplex if supported */
+		switch (cmd->speed) {
+		case SPEED_10:
+			if (cmd->duplex == DUPLEX_FULL) {
+				if (!(bp->supported & SUPPORTED_10baseT_Full))
+					return -EINVAL;
+
+				advertising = (ADVERTISED_10baseT_Full |
+					       ADVERTISED_TP);
+			} else {
+				if (!(bp->supported & SUPPORTED_10baseT_Half))
+					return -EINVAL;
+
+				advertising = (ADVERTISED_10baseT_Half |
+					       ADVERTISED_TP);
+			}
+			break;
+
+		case SPEED_100:
+			if (cmd->duplex == DUPLEX_FULL) {
+				if (!(bp->supported &
+						SUPPORTED_100baseT_Full))
+					return -EINVAL;
+
+				advertising = (ADVERTISED_100baseT_Full |
+					       ADVERTISED_TP);
+			} else {
+				if (!(bp->supported &
+						SUPPORTED_100baseT_Half))
+					return -EINVAL;
+
+				advertising = (ADVERTISED_100baseT_Half |
+					       ADVERTISED_TP);
+			}
+			break;
+
+		case SPEED_1000:
+			if (cmd->duplex != DUPLEX_FULL)
+				return -EINVAL;
+
+			if (!(bp->supported & SUPPORTED_1000baseT_Full))
+				return -EINVAL;
+
+			advertising = (ADVERTISED_1000baseT_Full |
+				       ADVERTISED_TP);
+			break;
+
+		case SPEED_2500:
+			if (cmd->duplex != DUPLEX_FULL)
+				return -EINVAL;
+
+			if (!(bp->supported & SUPPORTED_2500baseT_Full))
+				return -EINVAL;
+
+			advertising = (ADVERTISED_2500baseT_Full |
+				       ADVERTISED_TP);
+			break;
+
+		case SPEED_10000:
+			if (cmd->duplex != DUPLEX_FULL)
+				return -EINVAL;
+
+			if (!(bp->supported & SUPPORTED_10000baseT_Full))
+				return -EINVAL;
+
+			advertising = (ADVERTISED_10000baseT_Full |
+				       ADVERTISED_FIBRE);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+		bp->req_autoneg &= ~AUTONEG_SPEED;
+		bp->req_line_speed = cmd->speed;
+		bp->req_duplex = cmd->duplex;
+		bp->advertising = advertising;
+	}
+
+	DP(NETIF_MSG_LINK, "req_autoneg 0x%x  req_line_speed %d\n"
+	   DP_LEVEL "  req_duplex %d  advertising 0x%x\n",
+	   bp->req_autoneg, bp->req_line_speed, bp->req_duplex,
+	   bp->advertising);
+
+	bnx2x_stop_stats(bp);
+	bnx2x_link_initialize(bp);
+
+	return 0;
+}
+
+static void bnx2x_get_drvinfo(struct net_device *dev,
+			      struct ethtool_drvinfo *info)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	strcpy(info->driver, DRV_MODULE_NAME);
+	strcpy(info->version, DRV_MODULE_VERSION);
+	snprintf(info->fw_version, 32, "%d.%d.%d:%d (BC VER %x)",
+		 BCM_5710_FW_MAJOR_VERSION, BCM_5710_FW_MINOR_VERSION,
+		 BCM_5710_FW_REVISION_VERSION, BCM_5710_FW_COMPILE_FLAGS,
+		 bp->bc_ver);
+	strcpy(info->bus_info, pci_name(bp->pdev));
+	info->n_stats = BNX2X_NUM_STATS;
+	info->testinfo_len = BNX2X_NUM_TESTS;
+	info->eedump_len = bp->flash_size;
+	info->regdump_len = 0;
+}
+
+static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (bp->flags & NO_WOL_FLAG) {
+		wol->supported = 0;
+		wol->wolopts = 0;
+	} else {
+		wol->supported = WAKE_MAGIC;
+		if (bp->wol)
+			wol->wolopts = WAKE_MAGIC;
+		else
+			wol->wolopts = 0;
+	}
+	memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (wol->wolopts & ~WAKE_MAGIC)
+		return -EINVAL;
+
+	if (wol->wolopts & WAKE_MAGIC) {
+		if (bp->flags & NO_WOL_FLAG)
+			return -EINVAL;
+
+		bp->wol = 1;
+	} else {
+		bp->wol = 0;
+	}
+	return 0;
+}
+
+static u32 bnx2x_get_msglevel(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	return bp->msglevel;
+}
+
+static void bnx2x_set_msglevel(struct net_device *dev, u32 level)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (capable(CAP_NET_ADMIN))
+		bp->msglevel = level;
+}
+
+static int bnx2x_nway_reset(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (bp->state != BNX2X_STATE_OPEN) {
+		DP(NETIF_MSG_PROBE, "state is %x, returning\n", bp->state);
+		return -EAGAIN;
+	}
+
+	bnx2x_stop_stats(bp);
+	bnx2x_link_initialize(bp);
+
+	return 0;
+}
+
+static int bnx2x_get_eeprom_len(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	return bp->flash_size;
+}
+
+static int bnx2x_acquire_nvram_lock(struct bnx2x *bp)
+{
+	int port = bp->port;
+	int count, i;
+	u32 val = 0;
+
+	/* adjust timeout for emulation/FPGA */
+	count = NVRAM_TIMEOUT_COUNT;
+	if (CHIP_REV_IS_SLOW(bp))
+		count *= 100;
+
+	/* request access to nvram interface */
+	REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
+	       (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port));
+
+	for (i = 0; i < count*10; i++) {
+		val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB);
+		if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))
+			break;
+
+		udelay(5);
+	}
+
+	if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) {
+		DP(NETIF_MSG_NVM, "cannot get access to nvram interface\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int bnx2x_release_nvram_lock(struct bnx2x *bp)
+{
+	int port = bp->port;
+	int count, i;
+	u32 val = 0;
+
+	/* adjust timeout for emulation/FPGA */
+	count = NVRAM_TIMEOUT_COUNT;
+	if (CHIP_REV_IS_SLOW(bp))
+		count *= 100;
+
+	/* relinquish nvram interface */
+	REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB,
+	       (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port));
+
+	for (i = 0; i < count*10; i++) {
+		val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB);
+		if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)))
+			break;
+
+		udelay(5);
+	}
+
+	if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) {
+		DP(NETIF_MSG_NVM, "cannot free access to nvram interface\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void bnx2x_enable_nvram_access(struct bnx2x *bp)
+{
+	u32 val;
+
+	val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
+
+	/* enable both bits, even on read */
+	REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE,
+	       (val | MCPR_NVM_ACCESS_ENABLE_EN |
+		      MCPR_NVM_ACCESS_ENABLE_WR_EN));
+}
+
+static void bnx2x_disable_nvram_access(struct bnx2x *bp)
+{
+	u32 val;
+
+	val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE);
+
+	/* disable both bits, even after read */
+	REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE,
+	       (val & ~(MCPR_NVM_ACCESS_ENABLE_EN |
+			MCPR_NVM_ACCESS_ENABLE_WR_EN)));
+}
+
+static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, u32 *ret_val,
+				  u32 cmd_flags)
+{
+	int rc;
+	int count, i;
+	u32 val;
+
+	/* build the command word */
+	cmd_flags |= MCPR_NVM_COMMAND_DOIT;
+
+	/* need to clear DONE bit separately */
+	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
+
+	/* address of the NVRAM to read from */
+	REG_WR(bp, MCP_REG_MCPR_NVM_ADDR,
+	       (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE));
+
+	/* issue a read command */
+	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
+
+	/* adjust timeout for emulation/FPGA */
+	count = NVRAM_TIMEOUT_COUNT;
+	if (CHIP_REV_IS_SLOW(bp))
+		count *= 100;
+
+	/* wait for completion */
+	*ret_val = 0;
+	rc = -EBUSY;
+	for (i = 0; i < count; i++) {
+		udelay(5);
+		val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND);
+
+		if (val & MCPR_NVM_COMMAND_DONE) {
+			val = REG_RD(bp, MCP_REG_MCPR_NVM_READ);
+			DP(NETIF_MSG_NVM, "val 0x%08x\n", val);
+			/* we read nvram data in cpu order
+			 * but ethtool sees it as an array of bytes
+			 * converting to big-endian will do the work */
+			val = cpu_to_be32(val);
+			*ret_val = val;
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf,
+			    int buf_size)
+{
+	int rc;
+	u32 cmd_flags;
+	u32 val;
+
+	if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
+		DP(NETIF_MSG_NVM,
+		   "Invalid paramter: offset 0x%x  buf_size 0x%x\n",
+		   offset, buf_size);
+		return -EINVAL;
+	}
+
+	if (offset + buf_size > bp->flash_size) {
+		DP(NETIF_MSG_NVM, "Invalid paramter: offset (0x%x) +"
+				  " buf_size (0x%x) > flash_size (0x%x)\n",
+		   offset, buf_size, bp->flash_size);
+		return -EINVAL;
+	}
+
+	/* request access to nvram interface */
+	rc = bnx2x_acquire_nvram_lock(bp);
+	if (rc)
+		return rc;
+
+	/* enable access to nvram interface */
+	bnx2x_enable_nvram_access(bp);
+
+	/* read the first word(s) */
+	cmd_flags = MCPR_NVM_COMMAND_FIRST;
+	while ((buf_size > sizeof(u32)) && (rc == 0)) {
+		rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags);
+		memcpy(ret_buf, &val, 4);
+
+		/* advance to the next dword */
+		offset += sizeof(u32);
+		ret_buf += sizeof(u32);
+		buf_size -= sizeof(u32);
+		cmd_flags = 0;
+	}
+
+	if (rc == 0) {
+		cmd_flags |= MCPR_NVM_COMMAND_LAST;
+		rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags);
+		memcpy(ret_buf, &val, 4);
+	}
+
+	/* disable access to nvram interface */
+	bnx2x_disable_nvram_access(bp);
+	bnx2x_release_nvram_lock(bp);
+
+	return rc;
+}
+
+static int bnx2x_get_eeprom(struct net_device *dev,
+			    struct ethtool_eeprom *eeprom, u8 *eebuf)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc;
+
+	DP(NETIF_MSG_NVM, "ethtool_eeprom: cmd %d\n"
+	   DP_LEVEL "  magic 0x%x  offset 0x%x (%d)  len 0x%x (%d)\n",
+	   eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
+	   eeprom->len, eeprom->len);
+
+	/* parameters already validated in ethtool_get_eeprom */
+
+	rc = bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
+
+	return rc;
+}
+
+static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val,
+				   u32 cmd_flags)
+{
+	int rc;
+	int count, i;
+
+	/* build the command word */
+	cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR;
+
+	/* need to clear DONE bit separately */
+	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE);
+
+	/* write the data */
+	REG_WR(bp, MCP_REG_MCPR_NVM_WRITE, val);
+
+	/* address of the NVRAM to write to */
+	REG_WR(bp, MCP_REG_MCPR_NVM_ADDR,
+	       (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE));
+
+	/* issue the write command */
+	REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags);
+
+	/* adjust timeout for emulation/FPGA */
+	count = NVRAM_TIMEOUT_COUNT;
+	if (CHIP_REV_IS_SLOW(bp))
+		count *= 100;
+
+	/* wait for completion */
+	rc = -EBUSY;
+	for (i = 0; i < count; i++) {
+		udelay(5);
+		val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND);
+		if (val & MCPR_NVM_COMMAND_DONE) {
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+#define BYTE_OFFSET(offset)     	(8 * (offset & 0x03))
+
+static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
+			      int buf_size)
+{
+	int rc;
+	u32 cmd_flags;
+	u32 align_offset;
+	u32 val;
+
+	if (offset + buf_size > bp->flash_size) {
+		DP(NETIF_MSG_NVM, "Invalid paramter: offset (0x%x) +"
+				  " buf_size (0x%x) > flash_size (0x%x)\n",
+		   offset, buf_size, bp->flash_size);
+		return -EINVAL;
+	}
+
+	/* request access to nvram interface */
+	rc = bnx2x_acquire_nvram_lock(bp);
+	if (rc)
+		return rc;
+
+	/* enable access to nvram interface */
+	bnx2x_enable_nvram_access(bp);
+
+	cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST);
+	align_offset = (offset & ~0x03);
+	rc = bnx2x_nvram_read_dword(bp, align_offset, &val, cmd_flags);
+
+	if (rc == 0) {
+		val &= ~(0xff << BYTE_OFFSET(offset));
+		val |= (*data_buf << BYTE_OFFSET(offset));
+
+		/* nvram data is returned as an array of bytes
+		 * convert it back to cpu order */
+		val = be32_to_cpu(val);
+
+		DP(NETIF_MSG_NVM, "val 0x%08x\n", val);
+
+		rc = bnx2x_nvram_write_dword(bp, align_offset, val,
+					     cmd_flags);
+	}
+
+	/* disable access to nvram interface */
+	bnx2x_disable_nvram_access(bp);
+	bnx2x_release_nvram_lock(bp);
+
+	return rc;
+}
+
+static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf,
+			     int buf_size)
+{
+	int rc;
+	u32 cmd_flags;
+	u32 val;
+	u32 written_so_far;
+
+	if (buf_size == 1) {    /* ethtool */
+		return bnx2x_nvram_write1(bp, offset, data_buf, buf_size);
+	}
+
+	if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) {
+		DP(NETIF_MSG_NVM,
+		   "Invalid paramter: offset 0x%x  buf_size 0x%x\n",
+		   offset, buf_size);
+		return -EINVAL;
+	}
+
+	if (offset + buf_size > bp->flash_size) {
+		DP(NETIF_MSG_NVM, "Invalid paramter: offset (0x%x) +"
+				  " buf_size (0x%x) > flash_size (0x%x)\n",
+		   offset, buf_size, bp->flash_size);
+		return -EINVAL;
+	}
+
+	/* request access to nvram interface */
+	rc = bnx2x_acquire_nvram_lock(bp);
+	if (rc)
+		return rc;
+
+	/* enable access to nvram interface */
+	bnx2x_enable_nvram_access(bp);
+
+	written_so_far = 0;
+	cmd_flags = MCPR_NVM_COMMAND_FIRST;
+	while ((written_so_far < buf_size) && (rc == 0)) {
+		if (written_so_far == (buf_size - sizeof(u32)))
+			cmd_flags |= MCPR_NVM_COMMAND_LAST;
+		else if (((offset + 4) % NVRAM_PAGE_SIZE) == 0)
+			cmd_flags |= MCPR_NVM_COMMAND_LAST;
+		else if ((offset % NVRAM_PAGE_SIZE) == 0)
+			cmd_flags |= MCPR_NVM_COMMAND_FIRST;
+
+		memcpy(&val, data_buf, 4);
+		DP(NETIF_MSG_NVM, "val 0x%08x\n", val);
+
+		rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags);
+
+		/* advance to the next dword */
+		offset += sizeof(u32);
+		data_buf += sizeof(u32);
+		written_so_far += sizeof(u32);
+		cmd_flags = 0;
+	}
+
+	/* disable access to nvram interface */
+	bnx2x_disable_nvram_access(bp);
+	bnx2x_release_nvram_lock(bp);
+
+	return rc;
+}
+
+static int bnx2x_set_eeprom(struct net_device *dev,
+			    struct ethtool_eeprom *eeprom, u8 *eebuf)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc;
+
+	DP(NETIF_MSG_NVM, "ethtool_eeprom: cmd %d\n"
+	   DP_LEVEL "  magic 0x%x  offset 0x%x (%d)  len 0x%x (%d)\n",
+	   eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset,
+	   eeprom->len, eeprom->len);
+
+	/* parameters already validated in ethtool_set_eeprom */
+
+	rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
+
+	return rc;
+}
+
+static int bnx2x_get_coalesce(struct net_device *dev,
+			      struct ethtool_coalesce *coal)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	memset(coal, 0, sizeof(struct ethtool_coalesce));
+
+	coal->rx_coalesce_usecs = bp->rx_ticks;
+	coal->tx_coalesce_usecs = bp->tx_ticks;
+	coal->stats_block_coalesce_usecs = bp->stats_ticks;
+
+	return 0;
+}
+
+static int bnx2x_set_coalesce(struct net_device *dev,
+			      struct ethtool_coalesce *coal)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
+	if (bp->rx_ticks > 3000)
+		bp->rx_ticks = 3000;
+
+	bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
+	if (bp->tx_ticks > 0x3000)
+		bp->tx_ticks = 0x3000;
+
+	bp->stats_ticks = coal->stats_block_coalesce_usecs;
+	if (bp->stats_ticks > 0xffff00)
+		bp->stats_ticks = 0xffff00;
+	bp->stats_ticks &= 0xffff00;
+
+	if (netif_running(bp->dev))
+		bnx2x_update_coalesce(bp);
+
+	return 0;
+}
+
+static void bnx2x_get_ringparam(struct net_device *dev,
+				struct ethtool_ringparam *ering)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	ering->rx_max_pending = MAX_RX_AVAIL;
+	ering->rx_mini_max_pending = 0;
+	ering->rx_jumbo_max_pending = 0;
+
+	ering->rx_pending = bp->rx_ring_size;
+	ering->rx_mini_pending = 0;
+	ering->rx_jumbo_pending = 0;
+
+	ering->tx_max_pending = MAX_TX_AVAIL;
+	ering->tx_pending = bp->tx_ring_size;
+}
+
+static int bnx2x_set_ringparam(struct net_device *dev,
+			       struct ethtool_ringparam *ering)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if ((ering->rx_pending > MAX_RX_AVAIL) ||
+	    (ering->tx_pending > MAX_TX_AVAIL) ||
+	    (ering->tx_pending <= MAX_SKB_FRAGS + 4))
+		return -EINVAL;
+
+	bp->rx_ring_size = ering->rx_pending;
+	bp->tx_ring_size = ering->tx_pending;
+
+	if (netif_running(bp->dev)) {
+		bnx2x_nic_unload(bp, 0);
+		bnx2x_nic_load(bp, 0);
+	}
+
+	return 0;
+}
+
+static void bnx2x_get_pauseparam(struct net_device *dev,
+				 struct ethtool_pauseparam *epause)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	epause->autoneg =
+		((bp->req_autoneg & AUTONEG_FLOW_CTRL) == AUTONEG_FLOW_CTRL);
+	epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) == FLOW_CTRL_RX);
+	epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) == FLOW_CTRL_TX);
+
+	DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
+	   DP_LEVEL "  autoneg %d  rx_pause %d  tx_pause %d\n",
+	   epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
+}
+
+static int bnx2x_set_pauseparam(struct net_device *dev,
+				struct ethtool_pauseparam *epause)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n"
+	   DP_LEVEL "  autoneg %d  rx_pause %d  tx_pause %d\n",
+	   epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause);
+
+	bp->req_flow_ctrl = FLOW_CTRL_AUTO;
+	if (epause->autoneg) {
+		bp->req_autoneg |= AUTONEG_FLOW_CTRL;
+		if (bp->dev->mtu <= 4500) {
+			bp->pause_mode = PAUSE_BOTH;
+			bp->advertising |= (ADVERTISED_Pause |
+					    ADVERTISED_Asym_Pause);
+		} else {
+			bp->pause_mode = PAUSE_ASYMMETRIC;
+			bp->advertising |= ADVERTISED_Asym_Pause;
+		}
+
+	} else {
+		bp->req_autoneg &= ~AUTONEG_FLOW_CTRL;
+
+		if (epause->rx_pause)
+			bp->req_flow_ctrl |= FLOW_CTRL_RX;
+		if (epause->tx_pause)
+			bp->req_flow_ctrl |= FLOW_CTRL_TX;
+
+		switch (bp->req_flow_ctrl) {
+		case FLOW_CTRL_AUTO:
+			bp->req_flow_ctrl = FLOW_CTRL_NONE;
+			bp->pause_mode = PAUSE_NONE;
+			bp->advertising &= ~(ADVERTISED_Pause |
+					     ADVERTISED_Asym_Pause);
+			break;
+
+		case FLOW_CTRL_TX:
+			bp->pause_mode = PAUSE_ASYMMETRIC;
+			bp->advertising |= ADVERTISED_Asym_Pause;
+			break;
+
+		case FLOW_CTRL_RX:
+		case FLOW_CTRL_BOTH:
+			bp->pause_mode = PAUSE_BOTH;
+			bp->advertising |= (ADVERTISED_Pause |
+					    ADVERTISED_Asym_Pause);
+			break;
+		}
+	}
+
+	DP(NETIF_MSG_LINK, "req_autoneg 0x%x  req_flow_ctrl 0x%x\n"
+	   DP_LEVEL "  pause_mode %d  advertising 0x%x\n",
+	   bp->req_autoneg, bp->req_flow_ctrl, bp->pause_mode,
+	   bp->advertising);
+
+	bnx2x_stop_stats(bp);
+	bnx2x_link_initialize(bp);
+
+	return 0;
+}
+
+static u32 bnx2x_get_rx_csum(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	return bp->rx_csum;
+}
+
+static int bnx2x_set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	bp->rx_csum = data;
+	return 0;
+}
+
+static int bnx2x_set_tso(struct net_device *dev, u32 data)
+{
+	if (data)
+		dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+	else
+		dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
+	return 0;
+}
+
+static struct {
+	char string[ETH_GSTRING_LEN];
+} bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = {
+	{ "MC Errors  (online)" }
+};
+
+static int bnx2x_self_test_count(struct net_device *dev)
+{
+	return BNX2X_NUM_TESTS;
+}
+
+static void bnx2x_self_test(struct net_device *dev,
+			    struct ethtool_test *etest, u64 *buf)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int stats_state;
+
+	memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS);
+
+	if (bp->state != BNX2X_STATE_OPEN) {
+		DP(NETIF_MSG_PROBE, "state is %x, returning\n", bp->state);
+		return;
+	}
+
+	stats_state = bp->stats_state;
+	bnx2x_stop_stats(bp);
+
+	if (bnx2x_mc_assert(bp) != 0) {
+		buf[0] = 1;
+		etest->flags |= ETH_TEST_FL_FAILED;
+	}
+
+#ifdef BNX2X_EXTRA_DEBUG
+	bnx2x_panic_dump(bp);
+#endif
+	bp->stats_state = stats_state;
+}
+
+static struct {
+	char string[ETH_GSTRING_LEN];
+} bnx2x_stats_str_arr[BNX2X_NUM_STATS] = {
+	{ "rx_bytes"},  			 /*  0 */
+	{ "rx_error_bytes"},    		 /*  1 */
+	{ "tx_bytes"},  			 /*  2 */
+	{ "tx_error_bytes"},    		 /*  3 */
+	{ "rx_ucast_packets"},  		 /*  4 */
+	{ "rx_mcast_packets"},  		 /*  5 */
+	{ "rx_bcast_packets"},  		 /*  6 */
+	{ "tx_ucast_packets"},  		 /*  7 */
+	{ "tx_mcast_packets"},  		 /*  8 */
+	{ "tx_bcast_packets"},  		 /*  9 */
+	{ "tx_mac_errors"},     		 /* 10 */
+	{ "tx_carrier_errors"}, 		 /* 11 */
+	{ "rx_crc_errors"},     		 /* 12 */
+	{ "rx_align_errors"},   		 /* 13 */
+	{ "tx_single_collisions"},      	 /* 14 */
+	{ "tx_multi_collisions"},       	 /* 15 */
+	{ "tx_deferred"},       		 /* 16 */
+	{ "tx_excess_collisions"},      	 /* 17 */
+	{ "tx_late_collisions"},		 /* 18 */
+	{ "tx_total_collisions"},       	 /* 19 */
+	{ "rx_fragments"},      		 /* 20 */
+	{ "rx_jabbers"},			 /* 21 */
+	{ "rx_undersize_packets"},      	 /* 22 */
+	{ "rx_oversize_packets"},       	 /* 23 */
+	{ "rx_xon_frames"},     		 /* 24 */
+	{ "rx_xoff_frames"},    		 /* 25 */
+	{ "tx_xon_frames"},     		 /* 26 */
+	{ "tx_xoff_frames"},    		 /* 27 */
+	{ "rx_mac_ctrl_frames"},		 /* 28 */
+	{ "rx_filtered_packets"},       	 /* 29 */
+	{ "rx_discards"},       		 /* 30 */
+};
+
+#define STATS_OFFSET32(offset_name) \
+	(offsetof(struct bnx2x_eth_stats, offset_name) / 4)
+
+static unsigned long bnx2x_stats_offset_arr[BNX2X_NUM_STATS] = {
+	STATS_OFFSET32(total_bytes_received_hi),		     /*  0 */
+	STATS_OFFSET32(stat_IfHCInBadOctets_hi),		     /*  1 */
+	STATS_OFFSET32(total_bytes_transmitted_hi),     	     /*  2 */
+	STATS_OFFSET32(stat_IfHCOutBadOctets_hi),       	     /*  3 */
+	STATS_OFFSET32(total_unicast_packets_received_hi),           /*  4 */
+	STATS_OFFSET32(total_multicast_packets_received_hi),         /*  5 */
+	STATS_OFFSET32(total_broadcast_packets_received_hi),         /*  6 */
+	STATS_OFFSET32(total_unicast_packets_transmitted_hi),        /*  7 */
+	STATS_OFFSET32(total_multicast_packets_transmitted_hi),      /*  8 */
+	STATS_OFFSET32(total_broadcast_packets_transmitted_hi),      /*  9 */
+	STATS_OFFSET32(stat_Dot3statsInternalMacTransmitErrors),     /* 10 */
+	STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),            /* 11 */
+	STATS_OFFSET32(crc_receive_errors),     		     /* 12 */
+	STATS_OFFSET32(alignment_errors),       		     /* 13 */
+	STATS_OFFSET32(single_collision_transmit_frames),            /* 14 */
+	STATS_OFFSET32(multiple_collision_transmit_frames),          /* 15 */
+	STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),         /* 16 */
+	STATS_OFFSET32(excessive_collision_frames),     	     /* 17 */
+	STATS_OFFSET32(late_collision_frames),  		     /* 18 */
+	STATS_OFFSET32(number_of_bugs_found_in_stats_spec),          /* 19 */
+	STATS_OFFSET32(runt_packets_received),  		     /* 20 */
+	STATS_OFFSET32(jabber_packets_received),		     /* 21 */
+	STATS_OFFSET32(error_runt_packets_received),    	     /* 22 */
+	STATS_OFFSET32(error_jabber_packets_received),  	     /* 23 */
+	STATS_OFFSET32(pause_xon_frames_received),      	     /* 24 */
+	STATS_OFFSET32(pause_xoff_frames_received),     	     /* 25 */
+	STATS_OFFSET32(pause_xon_frames_transmitted),   	     /* 26 */
+	STATS_OFFSET32(pause_xoff_frames_transmitted),  	     /* 27 */
+	STATS_OFFSET32(control_frames_received),		     /* 28 */
+	STATS_OFFSET32(mac_filter_discard),     		     /* 29 */
+	STATS_OFFSET32(no_buff_discard),			     /* 30 */
+};
+
+static u8 bnx2x_stats_len_arr[BNX2X_NUM_STATS] = {
+	8, 0, 8, 0, 8, 8, 8, 8, 8, 8,
+	4, 0, 4, 4, 4, 4, 4, 4, 4, 4,
+	4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+	4,
+};
+
+static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+	switch (stringset) {
+	case ETH_SS_STATS:
+		memcpy(buf, bnx2x_stats_str_arr, sizeof(bnx2x_stats_str_arr));
+		break;
+
+	case ETH_SS_TEST:
+		memcpy(buf, bnx2x_tests_str_arr, sizeof(bnx2x_tests_str_arr));
+		break;
+	}
+}
+
+static int bnx2x_get_stats_count(struct net_device *dev)
+{
+	return BNX2X_NUM_STATS;
+}
+
+static void bnx2x_get_ethtool_stats(struct net_device *dev,
+				    struct ethtool_stats *stats, u64 *buf)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	u32 *hw_stats = (u32 *)bnx2x_sp_check(bp, eth_stats);
+	int i;
+
+	for (i = 0; i < BNX2X_NUM_STATS; i++) {
+		if (bnx2x_stats_len_arr[i] == 0) {
+			/* skip this counter */
+			buf[i] = 0;
+			continue;
+		}
+		if (!hw_stats) {
+			buf[i] = 0;
+			continue;
+		}
+		if (bnx2x_stats_len_arr[i] == 4) {
+			/* 4-byte counter */
+		       buf[i] = (u64) *(hw_stats + bnx2x_stats_offset_arr[i]);
+			continue;
+		}
+		/* 8-byte counter */
+		buf[i] = HILO_U64(*(hw_stats + bnx2x_stats_offset_arr[i]),
+				 *(hw_stats + bnx2x_stats_offset_arr[i] + 1));
+	}
+}
+
+static int bnx2x_phys_id(struct net_device *dev, u32 data)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	int i;
+
+	if (data == 0)
+		data = 2;
+
+	for (i = 0; i < (data * 2); i++) {
+		if ((i % 2) == 0) {
+			bnx2x_leds_set(bp, SPEED_1000);
+		} else {
+			bnx2x_leds_unset(bp);
+		}
+		msleep_interruptible(500);
+		if (signal_pending(current))
+			break;
+	}
+
+	if (bp->link_up)
+		bnx2x_leds_set(bp, bp->line_speed);
+
+	return 0;
+}
+
+static struct ethtool_ops bnx2x_ethtool_ops = {
+	.get_settings   	= bnx2x_get_settings,
+	.set_settings   	= bnx2x_set_settings,
+	.get_drvinfo    	= bnx2x_get_drvinfo,
+	.get_wol		= bnx2x_get_wol,
+	.set_wol		= bnx2x_set_wol,
+	.get_msglevel   	= bnx2x_get_msglevel,
+	.set_msglevel   	= bnx2x_set_msglevel,
+	.nway_reset     	= bnx2x_nway_reset,
+	.get_link       	= ethtool_op_get_link,
+	.get_eeprom_len 	= bnx2x_get_eeprom_len,
+	.get_eeprom     	= bnx2x_get_eeprom,
+	.set_eeprom     	= bnx2x_set_eeprom,
+	.get_coalesce   	= bnx2x_get_coalesce,
+	.set_coalesce   	= bnx2x_set_coalesce,
+	.get_ringparam  	= bnx2x_get_ringparam,
+	.set_ringparam  	= bnx2x_set_ringparam,
+	.get_pauseparam 	= bnx2x_get_pauseparam,
+	.set_pauseparam 	= bnx2x_set_pauseparam,
+	.get_rx_csum    	= bnx2x_get_rx_csum,
+	.set_rx_csum    	= bnx2x_set_rx_csum,
+	.get_tx_csum    	= ethtool_op_get_tx_csum,
+	.set_tx_csum    	= ethtool_op_set_tx_csum,
+	.get_sg 		= ethtool_op_get_sg,
+	.set_sg 		= ethtool_op_set_sg,
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= bnx2x_set_tso,
+	.self_test_count	= bnx2x_self_test_count,
+	.self_test      	= bnx2x_self_test,
+	.get_strings    	= bnx2x_get_strings,
+	.phys_id		= bnx2x_phys_id,
+	.get_stats_count	= bnx2x_get_stats_count,
+	.get_ethtool_stats      = bnx2x_get_ethtool_stats
+};
+
+/* end of ethtool_ops */
+
+/****************************************************************************
+* General service functions
+****************************************************************************/
+
+static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
+{
+	u16 pmcsr;
+
+	pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
+
+	switch (state) {
+	case PCI_D0:
+		pci_write_config_word(bp->pdev,
+				      bp->pm_cap + PCI_PM_CTRL,
+				      ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
+				       PCI_PM_CTRL_PME_STATUS));
+
+		if (pmcsr & PCI_PM_CTRL_STATE_MASK)
+		/* delay required during transition out of D3hot */
+			msleep(20);
+		break;
+
+	case PCI_D3hot:
+		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+		pmcsr |= 3;
+
+		if (bp->wol)
+			pmcsr |= PCI_PM_CTRL_PME_ENABLE;
+
+		pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
+				      pmcsr);
+
+		/* No more memory access after this point until
+		* device is brought back to D0.
+		*/
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * net_device service functions
+ */
+
+/* Called with rtnl_lock from vlan functions and also netif_tx_lock
+ * from set_multicast.
+ */
+static void bnx2x_set_rx_mode(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	u32 rx_mode = BNX2X_RX_MODE_NORMAL;
+
+	DP(NETIF_MSG_IFUP, "called dev->flags = %x\n", dev->flags);
+
+	if (dev->flags & IFF_PROMISC)
+		rx_mode = BNX2X_RX_MODE_PROMISC;
+
+	else if ((dev->flags & IFF_ALLMULTI) ||
+		 (dev->mc_count > BNX2X_MAX_MULTICAST))
+		rx_mode = BNX2X_RX_MODE_ALLMULTI;
+
+	else { /* some multicasts */
+		int i, old, offset;
+		struct dev_mc_list *mclist;
+		struct mac_configuration_cmd *config =
+						bnx2x_sp(bp, mcast_config);
+
+		for (i = 0, mclist = dev->mc_list;
+		     mclist && (i < dev->mc_count);
+		     i++, mclist = mclist->next) {
+
+			config->config_table[i].cam_entry.msb_mac_addr =
+					swab16(*(u16 *)&mclist->dmi_addr[0]);
+			config->config_table[i].cam_entry.middle_mac_addr =
+					swab16(*(u16 *)&mclist->dmi_addr[2]);
+			config->config_table[i].cam_entry.lsb_mac_addr =
+					swab16(*(u16 *)&mclist->dmi_addr[4]);
+			config->config_table[i].cam_entry.flags =
+							cpu_to_le16(bp->port);
+			config->config_table[i].target_table_entry.flags = 0;
+			config->config_table[i].target_table_entry.
+								client_id = 0;
+			config->config_table[i].target_table_entry.
+								vlan_id = 0;
+
+			DP(NETIF_MSG_IFUP,
+			   "setting MCAST[%d] (%04x:%04x:%04x)\n",
+			   i, config->config_table[i].cam_entry.msb_mac_addr,
+			   config->config_table[i].cam_entry.middle_mac_addr,
+			   config->config_table[i].cam_entry.lsb_mac_addr);
+		}
+		old = config->hdr.length_6b;
+		if (old > i) {
+			for (; i < old; i++) {
+				if (CAM_IS_INVALID(config->config_table[i])) {
+					i--; /* already invalidated */
+					break;
+				}
+				/* invalidate */
+				CAM_INVALIDATE(config->config_table[i]);
+			}
+		}
+
+		if (CHIP_REV_IS_SLOW(bp))
+			offset = BNX2X_MAX_EMUL_MULTI*(1 + bp->port);
+		else
+			offset = BNX2X_MAX_MULTICAST*(1 + bp->port);
+
+		config->hdr.length_6b = i;
+		config->hdr.offset = offset;
+		config->hdr.reserved0 = 0;
+		config->hdr.reserved1 = 0;
+
+		bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
+			      U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
+			      U64_LO(bnx2x_sp_mapping(bp, mcast_config)), 0);
+	}
+
+	bp->rx_mode = rx_mode;
+	bnx2x_set_storm_rx_mode(bp);
+}
+
+static int bnx2x_poll(struct napi_struct *napi, int budget)
+{
+	struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath,
+						 napi);
+	struct bnx2x *bp = fp->bp;
+	int work_done = 0;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		goto out_panic;
+#endif
+
+	prefetch(fp->tx_buf_ring[TX_BD(fp->tx_pkt_cons)].skb);
+	prefetch(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb);
+	prefetch((char *)(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb) + 256);
+
+	bnx2x_update_fpsb_idx(fp);
+
+	if (le16_to_cpu(*fp->tx_cons_sb) != fp->tx_pkt_cons)
+		bnx2x_tx_int(fp, budget);
+
+
+	if (le16_to_cpu(*fp->rx_cons_sb) != fp->rx_comp_cons)
+		work_done = bnx2x_rx_int(fp, budget);
+
+
+	rmb(); /* bnx2x_has_work() reads the status block */
+
+	/* must not complete if we consumed full budget */
+	if ((work_done < budget) && !bnx2x_has_work(fp)) {
+
+#ifdef BNX2X_STOP_ON_ERROR
+out_panic:
+#endif
+		netif_rx_complete(bp->dev, napi);
+
+		bnx2x_ack_sb(bp, fp->index, USTORM_ID,
+			     le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1);
+		bnx2x_ack_sb(bp, fp->index, CSTORM_ID,
+			     le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1);
+	}
+
+	return work_done;
+}
+
+/* Called with netif_tx_lock.
+ * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
+ * netif_wake_queue().
+ */
+static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+	struct bnx2x_fastpath *fp;
+	struct sw_tx_bd *tx_buf;
+	struct eth_tx_bd *tx_bd;
+	struct eth_tx_parse_bd *pbd = NULL;
+	u16 pkt_prod, bd_prod;
+	int nbd, fp_index = 0;
+	dma_addr_t mapping;
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (unlikely(bp->panic))
+		return NETDEV_TX_BUSY;
+#endif
+
+	fp_index = smp_processor_id() % (bp->num_queues);
+
+	fp = &bp->fp[fp_index];
+	if (unlikely(bnx2x_tx_avail(bp->fp) <
+					(skb_shinfo(skb)->nr_frags + 3))) {
+		bp->slowpath->eth_stats.driver_xoff++,
+		netif_stop_queue(dev);
+		BNX2X_ERR("BUG! Tx ring full when queue awake!\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	/*
+	This is a bit ugly. First we use one BD which we mark as start,
+	then for TSO or xsum we have a parsing info BD,
+	and only then we have the rest of the TSO bds.
+	(don't forget to mark the last one as last,
+	and to unmap only AFTER you write to the BD ...)
+	I would like to thank DovH for this mess.
+	*/
+
+	pkt_prod = fp->tx_pkt_prod++;
+	bd_prod = fp->tx_bd_prod;
+	bd_prod = TX_BD(bd_prod);
+
+	/* get a tx_buff and first bd */
+	tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)];
+	tx_bd = &fp->tx_desc_ring[bd_prod];
+
+	tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
+	tx_bd->general_data = (UNICAST_ADDRESS <<
+			       ETH_TX_BD_ETH_ADDR_TYPE_SHIFT);
+	tx_bd->general_data |= 1; /* header nbd */
+
+	/* remeber the first bd of the packet */
+	tx_buf->first_bd = bd_prod;
+
+	DP(NETIF_MSG_TX_QUEUED,
+	   "sending pkt %u @%p  next_idx %u  bd %u @%p\n",
+	   pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_bd);
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		struct iphdr *iph = ip_hdr(skb);
+		u8 len;
+
+		tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IP_CSUM;
+
+		/* turn on parsing and get a bd */
+		bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+		pbd = (void *)&fp->tx_desc_ring[bd_prod];
+		len = ((u8 *)iph - (u8 *)skb->data) / 2;
+
+		/* for now NS flag is not used in Linux */
+		pbd->global_data = (len |
+				    ((skb->protocol == ETH_P_8021Q) <<
+				     ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT));
+		pbd->ip_hlen = ip_hdrlen(skb) / 2;
+		pbd->total_hlen = cpu_to_le16(len + pbd->ip_hlen);
+		if (iph->protocol == IPPROTO_TCP) {
+			struct tcphdr *th = tcp_hdr(skb);
+
+			tx_bd->bd_flags.as_bitfield |=
+						ETH_TX_BD_FLAGS_TCP_CSUM;
+			pbd->tcp_flags = htonl(tcp_flag_word(skb)) & 0xFFFF;
+			pbd->total_hlen += cpu_to_le16(tcp_hdrlen(skb) / 2);
+			pbd->tcp_pseudo_csum = swab16(th->check);
+
+		} else if (iph->protocol == IPPROTO_UDP) {
+			struct udphdr *uh = udp_hdr(skb);
+
+			tx_bd->bd_flags.as_bitfield |=
+						ETH_TX_BD_FLAGS_TCP_CSUM;
+			pbd->total_hlen += cpu_to_le16(4);
+			pbd->global_data |= ETH_TX_PARSE_BD_CS_ANY_FLG;
+			pbd->cs_offset = 5; /* 10 >> 1 */
+			pbd->tcp_pseudo_csum = 0;
+			/* HW bug: we need to subtract 10 bytes before the
+			 * UDP header from the csum
+			 */
+			uh->check = (u16) ~csum_fold(csum_sub(uh->check,
+				csum_partial(((u8 *)(uh)-10), 10, 0)));
+		}
+	}
+
+	if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb)) {
+		tx_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb));
+		tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG;
+	} else {
+		tx_bd->vlan = cpu_to_le16(pkt_prod);
+	}
+
+	mapping = pci_map_single(bp->pdev, skb->data,
+				 skb->len, PCI_DMA_TODEVICE);
+
+	tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+	tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+	nbd = skb_shinfo(skb)->nr_frags + ((pbd == NULL)? 1 : 2);
+	tx_bd->nbd = cpu_to_le16(nbd);
+	tx_bd->nbytes = cpu_to_le16(skb_headlen(skb));
+
+	DP(NETIF_MSG_TX_QUEUED, "first bd @%p  addr (%x:%x)  nbd %d"
+	   "  nbytes %d  flags %x  vlan %u\n",
+	   tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, tx_bd->nbd,
+	   tx_bd->nbytes, tx_bd->bd_flags.as_bitfield, tx_bd->vlan);
+
+	if (skb_shinfo(skb)->gso_size &&
+	    (skb->len > (bp->dev->mtu + ETH_HLEN))) {
+		int hlen = 2 * le32_to_cpu(pbd->total_hlen);
+
+		DP(NETIF_MSG_TX_QUEUED,
+		   "TSO packet len %d  hlen %d  total len %d  tso size %d\n",
+		   skb->len, hlen, skb_headlen(skb),
+		   skb_shinfo(skb)->gso_size);
+
+		tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO;
+
+		if (tx_bd->nbytes > cpu_to_le16(hlen)) {
+			/* we split the first bd into headers and data bds
+			 * to ease the pain of our fellow micocode engineers
+			 * we use one mapping for both bds
+			 * So far this has only been observed to happen
+			 * in Other Operating Systems(TM)
+			 */
+
+			/* first fix first bd */
+			nbd++;
+			tx_bd->nbd = cpu_to_le16(nbd);
+			tx_bd->nbytes = cpu_to_le16(hlen);
+
+			/* we only print this as an error
+			 * because we don't think this will ever happen.
+			 */
+			BNX2X_ERR("TSO split header size is %d (%x:%x)"
+				  "  nbd %d\n", tx_bd->nbytes, tx_bd->addr_hi,
+				  tx_bd->addr_lo, tx_bd->nbd);
+
+			/* now get a new data bd
+			 * (after the pbd) and fill it */
+			bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+			tx_bd = &fp->tx_desc_ring[bd_prod];
+
+			tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+			tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping) + hlen);
+			tx_bd->nbytes = cpu_to_le16(skb_headlen(skb) - hlen);
+			tx_bd->vlan = cpu_to_le16(pkt_prod);
+			/* this marks the bd
+			 * as one that has no individual mapping
+			 * the FW ignors this flag in a bd not maked start
+			 */
+			tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_SW_LSO;
+			DP(NETIF_MSG_TX_QUEUED,
+			   "TSO split data size is %d (%x:%x)\n",
+			   tx_bd->nbytes, tx_bd->addr_hi, tx_bd->addr_lo);
+		}
+
+		if (!pbd) {
+			/* supposed to be unreached
+			 * (and therefore not handled properly...)
+			 */
+			BNX2X_ERR("LSO with no PBD\n");
+			BUG();
+		}
+
+		pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+		pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq);
+		pbd->ip_id = swab16(ip_hdr(skb)->id);
+		pbd->tcp_pseudo_csum =
+				swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+							  ip_hdr(skb)->daddr,
+							  0, IPPROTO_TCP, 0));
+		pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN;
+	}
+
+	{
+		int i;
+
+		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+			bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+			tx_bd = &fp->tx_desc_ring[bd_prod];
+
+			mapping = pci_map_page(bp->pdev, frag->page,
+					       frag->page_offset,
+					       frag->size, PCI_DMA_TODEVICE);
+
+			tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
+			tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
+			tx_bd->nbytes = cpu_to_le16(frag->size);
+			tx_bd->vlan = cpu_to_le16(pkt_prod);
+			tx_bd->bd_flags.as_bitfield = 0;
+			DP(NETIF_MSG_TX_QUEUED, "frag %d  bd @%p"
+			   "  addr (%x:%x)  nbytes %d  flags %x\n",
+			   i, tx_bd, tx_bd->addr_hi, tx_bd->addr_lo,
+			   tx_bd->nbytes, tx_bd->bd_flags.as_bitfield);
+		} /* for */
+	}
+
+	/* now at last mark the bd as the last bd */
+	tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_END_BD;
+
+	DP(NETIF_MSG_TX_QUEUED, "last bd @%p  flags %x\n",
+	   tx_bd, tx_bd->bd_flags.as_bitfield);
+
+	tx_buf->skb = skb;
+
+	bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+
+	/* now send a tx doorbell, counting the next bd
+	 * if the packet contains or ends with it
+	 */
+	if (TX_BD_POFF(bd_prod) < nbd)
+		nbd++;
+
+	if (pbd)
+		DP(NETIF_MSG_TX_QUEUED,
+		   "PBD @%p  ip_data %x  ip_hlen %u  ip_id %u  lso_mss %u"
+		   "  tcp_flags %x  xsum %x  seq %u  hlen %u\n",
+		   pbd, pbd->global_data, pbd->ip_hlen, pbd->ip_id,
+		   pbd->lso_mss, pbd->tcp_flags, pbd->tcp_pseudo_csum,
+		   pbd->tcp_send_seq, pbd->total_hlen);
+
+	DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %u  bd %d\n", nbd, bd_prod);
+
+	fp->hw_tx_prods->bds_prod += cpu_to_le16(nbd);
+	mb(); /* FW restriction: must not reorder writing nbd and packets */
+	fp->hw_tx_prods->packets_prod += cpu_to_le32(1);
+	DOORBELL(bp, fp_index, 0);
+
+	mmiowb();
+
+	fp->tx_bd_prod = bd_prod;
+	dev->trans_start = jiffies;
+
+	if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) {
+		netif_stop_queue(dev);
+		bp->slowpath->eth_stats.driver_xoff++;
+		if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)
+			netif_wake_queue(dev);
+	}
+	fp->tx_pkt++;
+
+	return NETDEV_TX_OK;
+}
+
+static struct net_device_stats *bnx2x_get_stats(struct net_device *dev)
+{
+	return &dev->stats;
+}
+
+/* Called with rtnl_lock */
+static int bnx2x_open(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	bnx2x_set_power_state(bp, PCI_D0);
+
+	return bnx2x_nic_load(bp, 1);
+}
+
+/* Called with rtnl_lock */
+static int bnx2x_close(struct net_device *dev)
+{
+	int rc;
+	struct bnx2x *bp = netdev_priv(dev);
+
+	/* Unload the driver, release IRQs */
+	rc = bnx2x_nic_unload(bp, 1);
+	if (rc) {
+		BNX2X_ERR("bnx2x_nic_unload failed: %d\n", rc);
+		return rc;
+	}
+	bnx2x_set_power_state(bp, PCI_D3hot);
+
+	return 0;
+}
+
+/* Called with rtnl_lock */
+static int bnx2x_change_mac_addr(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	if (netif_running(dev))
+		bnx2x_set_mac_addr(bp);
+
+	return 0;
+}
+
+/* Called with rtnl_lock */
+static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mii_ioctl_data *data = if_mii(ifr);
+	struct bnx2x *bp = netdev_priv(dev);
+	int err;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = bp->phy_addr;
+
+		/* fallthru */
+	case SIOCGMIIREG: {
+		u32 mii_regval;
+
+		spin_lock_bh(&bp->phy_lock);
+		if (bp->state == BNX2X_STATE_OPEN) {
+			err = bnx2x_mdio22_read(bp, data->reg_num & 0x1f,
+						&mii_regval);
+
+			data->val_out = mii_regval;
+		} else {
+			err = -EAGAIN;
+		}
+		spin_unlock_bh(&bp->phy_lock);
+		return err;
+	}
+
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		spin_lock_bh(&bp->phy_lock);
+		if (bp->state == BNX2X_STATE_OPEN) {
+			err = bnx2x_mdio22_write(bp, data->reg_num & 0x1f,
+						 data->val_in);
+		} else {
+			err = -EAGAIN;
+		}
+		spin_unlock_bh(&bp->phy_lock);
+		return err;
+
+	default:
+		/* do nothing */
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+/* Called with rtnl_lock */
+static int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) ||
+	    ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE))
+		return -EINVAL;
+
+	/* This does not race with packet allocation
+	 * because the actuall alloc size is
+	 * only updated as part of load
+	 */
+	dev->mtu = new_mtu;
+
+	if (netif_running(dev)) {
+		bnx2x_nic_unload(bp, 0);
+		bnx2x_nic_load(bp, 0);
+	}
+	return 0;
+}
+
+static void bnx2x_tx_timeout(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+#ifdef BNX2X_STOP_ON_ERROR
+	if (!bp->panic)
+		bnx2x_panic();
+#endif
+	/* This allows the netif to be shutdown gracefully before resetting */
+	schedule_work(&bp->reset_task);
+}
+
+#ifdef BCM_VLAN
+/* Called with rtnl_lock */
+static void bnx2x_vlan_rx_register(struct net_device *dev,
+				   struct vlan_group *vlgrp)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	bp->vlgrp = vlgrp;
+	if (netif_running(dev))
+		bnx2x_set_rx_mode(dev);
+}
+#endif
+
+#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+static void poll_bnx2x(struct net_device *dev)
+{
+	struct bnx2x *bp = netdev_priv(dev);
+
+	disable_irq(bp->pdev->irq);
+	bnx2x_interrupt(bp->pdev->irq, dev);
+	enable_irq(bp->pdev->irq);
+}
+#endif
+
+static void bnx2x_reset_task(struct work_struct *work)
+{
+	struct bnx2x *bp = container_of(work, struct bnx2x, reset_task);
+
+#ifdef BNX2X_STOP_ON_ERROR
+	BNX2X_ERR("reset task called but STOP_ON_ERROR defined"
+		  " so reset not done to allow debug dump,\n"
+	 KERN_ERR " you will need to reboot when done\n");
+	return;
+#endif
+
+	if (!netif_running(bp->dev))
+		return;
+
+	bp->in_reset_task = 1;
+
+	bnx2x_netif_stop(bp);
+
+	bnx2x_nic_unload(bp, 0);
+	bnx2x_nic_load(bp, 0);
+
+	bp->in_reset_task = 0;
+}
+
+static int __devinit bnx2x_init_board(struct pci_dev *pdev,
+				      struct net_device *dev)
+{
+	struct bnx2x *bp;
+	int rc;
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	bp = netdev_priv(dev);
+
+	bp->flags = 0;
+	bp->port = PCI_FUNC(pdev->devfn);
+
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		printk(KERN_ERR PFX "Cannot enable PCI device, aborting\n");
+		goto err_out;
+	}
+
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX "Cannot find PCI device base address,"
+		       " aborting\n");
+		rc = -ENODEV;
+		goto err_out_disable;
+	}
+
+	if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX "Cannot find second PCI device"
+		       " base address, aborting\n");
+		rc = -ENODEV;
+		goto err_out_disable;
+	}
+
+	rc = pci_request_regions(pdev, DRV_MODULE_NAME);
+	if (rc) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources,"
+		       " aborting\n");
+		goto err_out_disable;
+	}
+
+	pci_set_master(pdev);
+
+	bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (bp->pm_cap == 0) {
+		printk(KERN_ERR PFX "Cannot find power management"
+		       " capability, aborting\n");
+		rc = -EIO;
+		goto err_out_release;
+	}
+
+	bp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (bp->pcie_cap == 0) {
+		printk(KERN_ERR PFX "Cannot find PCI Express capability,"
+		       " aborting\n");
+		rc = -EIO;
+		goto err_out_release;
+	}
+
+	if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
+		bp->flags |= USING_DAC_FLAG;
+		if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
+			printk(KERN_ERR PFX "pci_set_consistent_dma_mask"
+			       " failed, aborting\n");
+			rc = -EIO;
+			goto err_out_release;
+		}
+
+	} else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
+		printk(KERN_ERR PFX "System does not support DMA,"
+		       " aborting\n");
+		rc = -EIO;
+		goto err_out_release;
+	}
+
+	bp->dev = dev;
+	bp->pdev = pdev;
+
+	spin_lock_init(&bp->phy_lock);
+
+	bp->in_reset_task = 0;
+
+	INIT_WORK(&bp->reset_task, bnx2x_reset_task);
+	INIT_WORK(&bp->sp_task, bnx2x_sp_task);
+
+	dev->base_addr = pci_resource_start(pdev, 0);
+
+	dev->irq = pdev->irq;
+
+	bp->regview = ioremap_nocache(dev->base_addr,
+				      pci_resource_len(pdev, 0));
+	if (!bp->regview) {
+		printk(KERN_ERR PFX "Cannot map register space, aborting\n");
+		rc = -ENOMEM;
+		goto err_out_release;
+	}
+
+	bp->doorbells = ioremap_nocache(pci_resource_start(pdev , 2),
+					pci_resource_len(pdev, 2));
+	if (!bp->doorbells) {
+		printk(KERN_ERR PFX "Cannot map doorbell space, aborting\n");
+		rc = -ENOMEM;
+		goto err_out_unmap;
+	}
+
+	bnx2x_set_power_state(bp, PCI_D0);
+
+	bnx2x_get_hwinfo(bp);
+
+	if (CHIP_REV(bp) == CHIP_REV_FPGA) {
+		printk(KERN_ERR PFX "FPGA detacted. MCP disabled,"
+		       " will only init first device\n");
+		onefunc = 1;
+		nomcp = 1;
+	}
+
+	if (nomcp) {
+		printk(KERN_ERR PFX "MCP disabled, will only"
+		       " init first device\n");
+		onefunc = 1;
+	}
+
+	if (onefunc && bp->port) {
+		printk(KERN_ERR PFX "Second device disabled, exiting\n");
+		rc = -ENODEV;
+		goto err_out_unmap;
+	}
+
+	bp->tx_ring_size = MAX_TX_AVAIL;
+	bp->rx_ring_size = MAX_RX_AVAIL;
+
+	bp->rx_csum = 1;
+
+	bp->rx_offset = 0;
+
+	bp->tx_quick_cons_trip_int = 0xff;
+	bp->tx_quick_cons_trip = 0xff;
+	bp->tx_ticks_int = 50;
+	bp->tx_ticks = 50;
+
+	bp->rx_quick_cons_trip_int = 0xff;
+	bp->rx_quick_cons_trip = 0xff;
+	bp->rx_ticks_int = 25;
+	bp->rx_ticks = 25;
+
+	bp->stats_ticks = 1000000 & 0xffff00;
+
+	bp->timer_interval = HZ;
+	bp->current_interval = (poll ? poll : HZ);
+
+	init_timer(&bp->timer);
+	bp->timer.expires = jiffies + bp->current_interval;
+	bp->timer.data = (unsigned long) bp;
+	bp->timer.function = bnx2x_timer;
+
+	return 0;
+
+err_out_unmap:
+	if (bp->regview) {
+		iounmap(bp->regview);
+		bp->regview = NULL;
+	}
+
+	if (bp->doorbells) {
+		iounmap(bp->doorbells);
+		bp->doorbells = NULL;
+	}
+
+err_out_release:
+	pci_release_regions(pdev);
+
+err_out_disable:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+err_out:
+	return rc;
+}
+
+static int __devinit bnx2x_init_one(struct pci_dev *pdev,
+				    const struct pci_device_id *ent)
+{
+	static int version_printed;
+	struct net_device *dev = NULL;
+	struct bnx2x *bp;
+	int rc, i;
+	int port = PCI_FUNC(pdev->devfn);
+
+	if (version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	/* dev zeroed in init_etherdev */
+	dev = alloc_etherdev(sizeof(*bp));
+	if (!dev)
+		return -ENOMEM;
+
+	netif_carrier_off(dev);
+
+	bp = netdev_priv(dev);
+	bp->msglevel = debug;
+
+	if (port && onefunc) {
+		printk(KERN_ERR PFX "second function disabled. exiting\n");
+		return 0;
+	}
+
+	rc = bnx2x_init_board(pdev, dev);
+	if (rc < 0) {
+		free_netdev(dev);
+		return rc;
+	}
+
+	dev->hard_start_xmit = bnx2x_start_xmit;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	dev->get_stats = bnx2x_get_stats;
+	dev->ethtool_ops = &bnx2x_ethtool_ops;
+	dev->open = bnx2x_open;
+	dev->stop = bnx2x_close;
+	dev->set_multicast_list = bnx2x_set_rx_mode;
+	dev->set_mac_address = bnx2x_change_mac_addr;
+	dev->do_ioctl = bnx2x_ioctl;
+	dev->change_mtu = bnx2x_change_mtu;
+	dev->tx_timeout = bnx2x_tx_timeout;
+#ifdef BCM_VLAN
+	dev->vlan_rx_register = bnx2x_vlan_rx_register;
+#endif
+#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
+	dev->poll_controller = poll_bnx2x;
+#endif
+	dev->features |= NETIF_F_SG;
+	if (bp->flags & USING_DAC_FLAG)
+		dev->features |= NETIF_F_HIGHDMA;
+	dev->features |= NETIF_F_IP_CSUM;
+#ifdef BCM_VLAN
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+#endif
+	dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
+
+	rc = register_netdev(dev);
+	if (rc) {
+		printk(KERN_ERR PFX "Cannot register net device\n");
+		if (bp->regview)
+			iounmap(bp->regview);
+		if (bp->doorbells)
+			iounmap(bp->doorbells);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+		free_netdev(dev);
+		return rc;
+	}
+
+	pci_set_drvdata(pdev, dev);
+
+	bp->name = board_info[ent->driver_data].name;
+	printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz "
+	       "found at mem %lx, IRQ %d, ",
+	       dev->name, bp->name,
+	       ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
+	       ((CHIP_ID(bp) & 0x0ff0) >> 4),
+	       ((bp->flags & PCIX_FLAG) ? "-X" : ""),
+	       ((bp->flags & PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
+	       bp->bus_speed_mhz,
+	       dev->base_addr,
+	       bp->pdev->irq);
+
+	printk("node addr ");
+	for (i = 0; i < 6; i++)
+		printk("%2.2x", dev->dev_addr[i]);
+	printk("\n");
+
+	return 0;
+}
+
+static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2x *bp = netdev_priv(dev);
+
+	flush_scheduled_work();
+	/*tasklet_kill(&bp->sp_task);*/
+	unregister_netdev(dev);
+
+	if (bp->regview)
+		iounmap(bp->regview);
+
+	if (bp->doorbells)
+		iounmap(bp->doorbells);
+
+	free_netdev(dev);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc;
+
+	if (!netif_running(dev))
+		return 0;
+
+	rc = bnx2x_nic_unload(bp, 0);
+	if (!rc)
+		return rc;
+
+	netif_device_detach(dev);
+	pci_save_state(pdev);
+
+	bnx2x_set_power_state(bp, pci_choose_state(pdev, state));
+	return 0;
+}
+
+static int bnx2x_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct bnx2x *bp = netdev_priv(dev);
+	int rc;
+
+	if (!netif_running(dev))
+		return 0;
+
+	pci_restore_state(pdev);
+
+	bnx2x_set_power_state(bp, PCI_D0);
+	netif_device_attach(dev);
+
+	rc = bnx2x_nic_load(bp, 0);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static struct pci_driver bnx2x_pci_driver = {
+	.name       = DRV_MODULE_NAME,
+	.id_table   = bnx2x_pci_tbl,
+	.probe      = bnx2x_init_one,
+	.remove     = __devexit_p(bnx2x_remove_one),
+	.suspend    = bnx2x_suspend,
+	.resume     = bnx2x_resume,
+};
+
+static int __init bnx2x_init(void)
+{
+	return pci_register_driver(&bnx2x_pci_driver);
+}
+
+static void __exit bnx2x_cleanup(void)
+{
+	pci_unregister_driver(&bnx2x_pci_driver);
+}
+
+module_init(bnx2x_init);
+module_exit(bnx2x_cleanup);
+
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
new file mode 100644
index 000000000000..4f7ae6f77452
--- /dev/null
+++ b/drivers/net/bnx2x.h
@@ -0,0 +1,1071 @@
+/* bnx2x.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Eliezer Tamir <eliezert@broadcom.com>
+ * Based on code from Michael Chan's bnx2 driver
+ */
+
+#ifndef BNX2X_H
+#define BNX2X_H
+
+/* error/debug prints */
+
+#define DRV_MODULE_NAME 	"bnx2x"
+#define PFX DRV_MODULE_NAME     ": "
+
+/* for messages that are currently off */
+#define BNX2X_MSG_OFF   		0
+#define BNX2X_MSG_MCP   		0x10000 /* was: NETIF_MSG_HW */
+#define BNX2X_MSG_STATS 		0x20000 /* was: NETIF_MSG_TIMER */
+#define NETIF_MSG_NVM   		0x40000 /* was: NETIF_MSG_HW */
+#define NETIF_MSG_DMAE  		0x80000 /* was: NETIF_MSG_HW */
+
+#define DP_LEVEL			KERN_NOTICE     /* was: KERN_DEBUG */
+
+/* regular debug print */
+#define DP(__mask, __fmt, __args...) do { \
+	if (bp->msglevel & (__mask)) \
+		printk(DP_LEVEL "[%s:%d(%s)]" __fmt, __FUNCTION__, \
+		__LINE__, bp->dev?(bp->dev->name):"?", ##__args); \
+	} while (0)
+
+/* for errors (never masked) */
+#define BNX2X_ERR(__fmt, __args...) do { \
+	printk(KERN_ERR "[%s:%d(%s)]" __fmt, __FUNCTION__, \
+		__LINE__, bp->dev?(bp->dev->name):"?", ##__args); \
+	} while (0)
+
+/* before we have a dev->name use dev_info() */
+#define BNX2X_DEV_INFO(__fmt, __args...) do { \
+	if (bp->msglevel & NETIF_MSG_PROBE) \
+		dev_info(&bp->pdev->dev, __fmt, ##__args); \
+	} while (0)
+
+
+#ifdef BNX2X_STOP_ON_ERROR
+#define bnx2x_panic() do { \
+		bp->panic = 1; \
+		BNX2X_ERR("driver assert\n"); \
+		bnx2x_disable_int(bp); \
+		bnx2x_panic_dump(bp); \
+	} while (0)
+#else
+#define bnx2x_panic() do { \
+		BNX2X_ERR("driver assert\n"); \
+		bnx2x_panic_dump(bp); \
+	} while (0)
+#endif
+
+
+#define U64_LO(x)       		(((u64)x) & 0xffffffff)
+#define U64_HI(x)       		(((u64)x) >> 32)
+#define HILO_U64(hi, lo)		(((u64)hi << 32) + lo)
+
+
+#define REG_ADDR(bp, offset)    	(bp->regview + offset)
+
+#define REG_RD(bp, offset)      	readl(REG_ADDR(bp, offset))
+#define REG_RD8(bp, offset)     	readb(REG_ADDR(bp, offset))
+#define REG_RD64(bp, offset)    	readq(REG_ADDR(bp, offset))
+
+#define REG_WR(bp, offset, val) 	writel((u32)val, REG_ADDR(bp, offset))
+#define REG_WR8(bp, offset, val)	writeb((u8)val, REG_ADDR(bp, offset))
+#define REG_WR16(bp, offset, val)       writew((u16)val, REG_ADDR(bp, offset))
+#define REG_WR32(bp, offset, val)       REG_WR(bp, offset, val)
+
+#define REG_RD_IND(bp, offset)  	bnx2x_reg_rd_ind(bp, offset)
+#define REG_WR_IND(bp, offset, val)     bnx2x_reg_wr_ind(bp, offset, val)
+
+#define REG_WR_DMAE(bp, offset, val, len32) \
+	do { \
+		memcpy(bnx2x_sp(bp, wb_data[0]), val, len32 * 4); \
+		bnx2x_write_dmae(bp, bnx2x_sp_mapping(bp, wb_data), \
+				 offset, len32); \
+	} while (0)
+
+#define SHMEM_RD(bp, type) \
+	REG_RD(bp, bp->shmem_base + offsetof(struct shmem_region, type))
+#define SHMEM_WR(bp, type, val) \
+	REG_WR(bp, bp->shmem_base + offsetof(struct shmem_region, type), val)
+
+#define NIG_WR(reg, val)	REG_WR(bp, reg, val)
+#define EMAC_WR(reg, val)       REG_WR(bp, emac_base + reg, val)
+#define BMAC_WR(reg, val)       REG_WR(bp, GRCBASE_NIG + bmac_addr + reg, val)
+
+
+#define for_each_queue(bp, var) for (var = 0; var < bp->num_queues; var++)
+
+#define for_each_nondefault_queue(bp, var) \
+				for (var = 1; var < bp->num_queues; var++)
+#define is_multi(bp)    	(bp->num_queues > 1)
+
+
+struct regp {
+	u32 lo;
+	u32 hi;
+};
+
+struct bmac_stats {
+	struct regp tx_gtpkt;
+	struct regp tx_gtxpf;
+	struct regp tx_gtfcs;
+	struct regp tx_gtmca;
+	struct regp tx_gtgca;
+	struct regp tx_gtfrg;
+	struct regp tx_gtovr;
+	struct regp tx_gt64;
+	struct regp tx_gt127;
+	struct regp tx_gt255;   /* 10 */
+	struct regp tx_gt511;
+	struct regp tx_gt1023;
+	struct regp tx_gt1518;
+	struct regp tx_gt2047;
+	struct regp tx_gt4095;
+	struct regp tx_gt9216;
+	struct regp tx_gt16383;
+	struct regp tx_gtmax;
+	struct regp tx_gtufl;
+	struct regp tx_gterr;   /* 20 */
+	struct regp tx_gtbyt;
+
+	struct regp rx_gr64;
+	struct regp rx_gr127;
+	struct regp rx_gr255;
+	struct regp rx_gr511;
+	struct regp rx_gr1023;
+	struct regp rx_gr1518;
+	struct regp rx_gr2047;
+	struct regp rx_gr4095;
+	struct regp rx_gr9216;  /* 30 */
+	struct regp rx_gr16383;
+	struct regp rx_grmax;
+	struct regp rx_grpkt;
+	struct regp rx_grfcs;
+	struct regp rx_grmca;
+	struct regp rx_grbca;
+	struct regp rx_grxcf;
+	struct regp rx_grxpf;
+	struct regp rx_grxuo;
+	struct regp rx_grjbr;   /* 40 */
+	struct regp rx_grovr;
+	struct regp rx_grflr;
+	struct regp rx_grmeg;
+	struct regp rx_grmeb;
+	struct regp rx_grbyt;
+	struct regp rx_grund;
+	struct regp rx_grfrg;
+	struct regp rx_grerb;
+	struct regp rx_grfre;
+	struct regp rx_gripj;   /* 50 */
+};
+
+struct emac_stats {
+	u32 rx_ifhcinoctets     		   ;
+	u32 rx_ifhcinbadoctets  		   ;
+	u32 rx_etherstatsfragments      	   ;
+	u32 rx_ifhcinucastpkts  		   ;
+	u32 rx_ifhcinmulticastpkts      	   ;
+	u32 rx_ifhcinbroadcastpkts      	   ;
+	u32 rx_dot3statsfcserrors       	   ;
+	u32 rx_dot3statsalignmenterrors 	   ;
+	u32 rx_dot3statscarriersenseerrors         ;
+	u32 rx_xonpauseframesreceived   	   ;    /* 10 */
+	u32 rx_xoffpauseframesreceived  	   ;
+	u32 rx_maccontrolframesreceived 	   ;
+	u32 rx_xoffstateentered 		   ;
+	u32 rx_dot3statsframestoolong   	   ;
+	u32 rx_etherstatsjabbers		   ;
+	u32 rx_etherstatsundersizepkts  	   ;
+	u32 rx_etherstatspkts64octets   	   ;
+	u32 rx_etherstatspkts65octetsto127octets   ;
+	u32 rx_etherstatspkts128octetsto255octets  ;
+	u32 rx_etherstatspkts256octetsto511octets  ;    /* 20 */
+	u32 rx_etherstatspkts512octetsto1023octets ;
+	u32 rx_etherstatspkts1024octetsto1522octets;
+	u32 rx_etherstatspktsover1522octets        ;
+
+	u32 rx_falsecarriererrors       	   ;
+
+	u32 tx_ifhcoutoctets    		   ;
+	u32 tx_ifhcoutbadoctets 		   ;
+	u32 tx_etherstatscollisions     	   ;
+	u32 tx_outxonsent       		   ;
+	u32 tx_outxoffsent      		   ;
+	u32 tx_flowcontroldone  		   ;    /* 30 */
+	u32 tx_dot3statssinglecollisionframes      ;
+	u32 tx_dot3statsmultiplecollisionframes    ;
+	u32 tx_dot3statsdeferredtransmissions      ;
+	u32 tx_dot3statsexcessivecollisions        ;
+	u32 tx_dot3statslatecollisions  	   ;
+	u32 tx_ifhcoutucastpkts 		   ;
+	u32 tx_ifhcoutmulticastpkts     	   ;
+	u32 tx_ifhcoutbroadcastpkts     	   ;
+	u32 tx_etherstatspkts64octets   	   ;
+	u32 tx_etherstatspkts65octetsto127octets   ;    /* 40 */
+	u32 tx_etherstatspkts128octetsto255octets  ;
+	u32 tx_etherstatspkts256octetsto511octets  ;
+	u32 tx_etherstatspkts512octetsto1023octets ;
+	u32 tx_etherstatspkts1024octetsto1522octet ;
+	u32 tx_etherstatspktsover1522octets        ;
+	u32 tx_dot3statsinternalmactransmiterrors  ;    /* 46 */
+};
+
+union mac_stats {
+	struct emac_stats emac;
+	struct bmac_stats bmac;
+};
+
+struct nig_stats {
+	u32 brb_discard;
+	u32 brb_packet;
+	u32 brb_truncate;
+	u32 flow_ctrl_discard;
+	u32 flow_ctrl_octets;
+	u32 flow_ctrl_packet;
+	u32 mng_discard;
+	u32 mng_octet_inp;
+	u32 mng_octet_out;
+	u32 mng_packet_inp;
+	u32 mng_packet_out;
+	u32 pbf_octets;
+	u32 pbf_packet;
+	u32 safc_inp;
+	u32 done;
+	u32 pad;
+};
+
+struct bnx2x_eth_stats {
+	u32 pad;	/* to make long counters u64 aligned */
+	u32 mac_stx_start;
+	u32 total_bytes_received_hi;
+	u32 total_bytes_received_lo;
+	u32 total_bytes_transmitted_hi;
+	u32 total_bytes_transmitted_lo;
+	u32 total_unicast_packets_received_hi;
+	u32 total_unicast_packets_received_lo;
+	u32 total_multicast_packets_received_hi;
+	u32 total_multicast_packets_received_lo;
+	u32 total_broadcast_packets_received_hi;
+	u32 total_broadcast_packets_received_lo;
+	u32 total_unicast_packets_transmitted_hi;
+	u32 total_unicast_packets_transmitted_lo;
+	u32 total_multicast_packets_transmitted_hi;
+	u32 total_multicast_packets_transmitted_lo;
+	u32 total_broadcast_packets_transmitted_hi;
+	u32 total_broadcast_packets_transmitted_lo;
+	u32 crc_receive_errors;
+	u32 alignment_errors;
+	u32 false_carrier_detections;
+	u32 runt_packets_received;
+	u32 jabber_packets_received;
+	u32 pause_xon_frames_received;
+	u32 pause_xoff_frames_received;
+	u32 pause_xon_frames_transmitted;
+	u32 pause_xoff_frames_transmitted;
+	u32 single_collision_transmit_frames;
+	u32 multiple_collision_transmit_frames;
+	u32 late_collision_frames;
+	u32 excessive_collision_frames;
+	u32 control_frames_received;
+	u32 frames_received_64_bytes;
+	u32 frames_received_65_127_bytes;
+	u32 frames_received_128_255_bytes;
+	u32 frames_received_256_511_bytes;
+	u32 frames_received_512_1023_bytes;
+	u32 frames_received_1024_1522_bytes;
+	u32 frames_received_1523_9022_bytes;
+	u32 frames_transmitted_64_bytes;
+	u32 frames_transmitted_65_127_bytes;
+	u32 frames_transmitted_128_255_bytes;
+	u32 frames_transmitted_256_511_bytes;
+	u32 frames_transmitted_512_1023_bytes;
+	u32 frames_transmitted_1024_1522_bytes;
+	u32 frames_transmitted_1523_9022_bytes;
+	u32 valid_bytes_received_hi;
+	u32 valid_bytes_received_lo;
+	u32 error_runt_packets_received;
+	u32 error_jabber_packets_received;
+	u32 mac_stx_end;
+
+	u32 pad2;
+	u32 stat_IfHCInBadOctets_hi;
+	u32 stat_IfHCInBadOctets_lo;
+	u32 stat_IfHCOutBadOctets_hi;
+	u32 stat_IfHCOutBadOctets_lo;
+	u32 stat_Dot3statsFramesTooLong;
+	u32 stat_Dot3statsInternalMacTransmitErrors;
+	u32 stat_Dot3StatsCarrierSenseErrors;
+	u32 stat_Dot3StatsDeferredTransmissions;
+	u32 stat_FlowControlDone;
+	u32 stat_XoffStateEntered;
+
+	u32 x_total_sent_bytes_hi;
+	u32 x_total_sent_bytes_lo;
+	u32 x_total_sent_pkts;
+
+	u32 t_rcv_unicast_bytes_hi;
+	u32 t_rcv_unicast_bytes_lo;
+	u32 t_rcv_broadcast_bytes_hi;
+	u32 t_rcv_broadcast_bytes_lo;
+	u32 t_rcv_multicast_bytes_hi;
+	u32 t_rcv_multicast_bytes_lo;
+	u32 t_total_rcv_pkt;
+
+	u32 checksum_discard;
+	u32 packets_too_big_discard;
+	u32 no_buff_discard;
+	u32 ttl0_discard;
+	u32 mac_discard;
+	u32 mac_filter_discard;
+	u32 xxoverflow_discard;
+	u32 brb_truncate_discard;
+
+	u32 brb_discard;
+	u32 brb_packet;
+	u32 brb_truncate;
+	u32 flow_ctrl_discard;
+	u32 flow_ctrl_octets;
+	u32 flow_ctrl_packet;
+	u32 mng_discard;
+	u32 mng_octet_inp;
+	u32 mng_octet_out;
+	u32 mng_packet_inp;
+	u32 mng_packet_out;
+	u32 pbf_octets;
+	u32 pbf_packet;
+	u32 safc_inp;
+	u32 driver_xoff;
+	u32 number_of_bugs_found_in_stats_spec; /* just kidding */
+};
+
+#define MAC_STX_NA      		0xffffffff
+
+#ifdef BNX2X_MULTI
+#define MAX_CONTEXT     		16
+#else
+#define MAX_CONTEXT     		1
+#endif
+
+union cdu_context {
+	struct eth_context eth;
+	char pad[1024];
+};
+
+#define MAX_DMAE_C      		5
+
+/* DMA memory not used in fastpath */
+struct bnx2x_slowpath {
+	union cdu_context       	context[MAX_CONTEXT];
+	struct eth_stats_query  	fw_stats;
+	struct mac_configuration_cmd    mac_config;
+	struct mac_configuration_cmd    mcast_config;
+
+	/* used by dmae command executer */
+	struct dmae_command     	dmae[MAX_DMAE_C];
+
+	union mac_stats 		mac_stats;
+	struct nig_stats		nig;
+	struct bnx2x_eth_stats  	eth_stats;
+
+	u32     			wb_comp;
+#define BNX2X_WB_COMP_VAL       	0xe0d0d0ae
+	u32     			wb_data[4];
+};
+
+#define bnx2x_sp(bp, var)       	(&bp->slowpath->var)
+#define bnx2x_sp_check(bp, var) ((bp->slowpath) ? (&bp->slowpath->var) : NULL)
+#define bnx2x_sp_mapping(bp, var) \
+		(bp->slowpath_mapping + offsetof(struct bnx2x_slowpath, var))
+
+
+struct sw_rx_bd {
+	struct sk_buff  *skb;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+};
+
+struct sw_tx_bd {
+	struct sk_buff  *skb;
+	u16     	first_bd;
+};
+
+struct bnx2x_fastpath {
+
+	struct napi_struct      napi;
+
+	struct host_status_block *status_blk;
+	dma_addr_t      	status_blk_mapping;
+
+	struct eth_tx_db_data   *hw_tx_prods;
+	dma_addr_t      	tx_prods_mapping;
+
+	struct sw_tx_bd 	*tx_buf_ring;
+
+	struct eth_tx_bd	*tx_desc_ring;
+	dma_addr_t      	tx_desc_mapping;
+
+	struct sw_rx_bd 	*rx_buf_ring;
+
+	struct eth_rx_bd	*rx_desc_ring;
+	dma_addr_t      	rx_desc_mapping;
+
+	union eth_rx_cqe	*rx_comp_ring;
+	dma_addr_t      	rx_comp_mapping;
+
+	int     		state;
+#define BNX2X_FP_STATE_CLOSED   	0
+#define BNX2X_FP_STATE_IRQ      	0x80000
+#define BNX2X_FP_STATE_OPENING  	0x90000
+#define BNX2X_FP_STATE_OPEN     	0xa0000
+#define BNX2X_FP_STATE_HALTING  	0xb0000
+#define BNX2X_FP_STATE_HALTED   	0xc0000
+#define BNX2X_FP_STATE_DELETED  	0xd0000
+#define BNX2X_FP_STATE_CLOSE_IRQ	0xe0000
+
+	int     		index;
+
+	u16     		tx_pkt_prod;
+	u16     		tx_pkt_cons;
+	u16     		tx_bd_prod;
+	u16     		tx_bd_cons;
+	u16     		*tx_cons_sb;
+
+	u16     		fp_c_idx;
+	u16     		fp_u_idx;
+
+	u16     		rx_bd_prod;
+	u16     		rx_bd_cons;
+	u16     		rx_comp_prod;
+	u16     		rx_comp_cons;
+	u16     		*rx_cons_sb;
+
+	unsigned long   	tx_pkt,
+				rx_pkt,
+				rx_calls;
+
+	struct bnx2x    	*bp; /* parent */
+};
+
+#define bnx2x_fp(bp, nr, var)   	(bp->fp[nr].var)
+
+
+/* attn group wiring */
+#define MAX_DYNAMIC_ATTN_GRPS   	8
+
+struct attn_route {
+	u32     sig[4];
+};
+
+struct bnx2x {
+	/* Fields used in the tx and intr/napi performance paths
+	 * are grouped together in the beginning of the structure
+	 */
+	struct bnx2x_fastpath   *fp;
+	void __iomem    	*regview;
+	void __iomem    	*doorbells;
+
+	struct net_device       *dev;
+	struct pci_dev  	*pdev;
+
+	atomic_t		intr_sem;
+	struct msix_entry       msix_table[MAX_CONTEXT+1];
+
+	int     		tx_ring_size;
+
+#ifdef BCM_VLAN
+	struct vlan_group       *vlgrp;
+#endif
+
+	u32     		rx_csum;
+	u32     		rx_offset;
+	u32     		rx_buf_use_size;	/* useable size */
+	u32     		rx_buf_size;    	/* with alignment */
+#define ETH_OVREHEAD    		(ETH_HLEN + 8)  /* 8 for CRC + VLAN */
+#define ETH_MIN_PACKET_SIZE     	60
+#define ETH_MAX_PACKET_SIZE     	1500
+#define ETH_MAX_JUMBO_PACKET_SIZE       9600
+
+	struct host_def_status_block *def_status_blk;
+#define DEF_SB_ID       	16
+	u16     		def_c_idx;
+	u16     		def_u_idx;
+	u16     		def_t_idx;
+	u16     		def_x_idx;
+	u16     		def_att_idx;
+	u32     		attn_state;
+	struct attn_route       attn_group[MAX_DYNAMIC_ATTN_GRPS];
+	u32     		aeu_mask;
+	u32     		nig_mask;
+
+	/* slow path ring */
+	struct eth_spe  	*spq;
+	dma_addr_t      	spq_mapping;
+	u16     		spq_prod_idx;
+	u16     		dsb_sp_prod_idx;
+	struct eth_spe  	*spq_prod_bd;
+	struct eth_spe  	*spq_last_bd;
+	u16     		*dsb_sp_prod;
+	u16     		spq_left; /* serialize spq */
+	spinlock_t      	spq_lock;
+
+	/* Flag for marking that there is either
+	 * STAT_QUERY or CFC DELETE ramrod pending
+	 */
+	u8      		stat_pending;
+
+	/* End of fileds used in the performance code paths */
+
+	int     		panic;
+	int     		msglevel;
+
+	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_MSIX_FLAG 		0x20
+#define ASF_ENABLE_FLAG 		0x40
+
+	int     		port;
+
+	int     		pm_cap;
+	int     		pcie_cap;
+
+	/* Used to synchronize phy accesses */
+	spinlock_t      	phy_lock;
+
+	struct work_struct      reset_task;
+	u16     		in_reset_task;
+
+	struct work_struct      sp_task;
+
+	struct timer_list       timer;
+	int     		timer_interval;
+	int     		current_interval;
+
+	u32     		shmem_base;
+
+	u32     		chip_id;
+/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
+#define CHIP_ID(bp)     		(((bp)->chip_id) & 0xfffffff0)
+
+#define CHIP_NUM(bp)    		(((bp)->chip_id) & 0xffff0000)
+#define CHIP_NUM_5710   		0x57100000
+
+#define CHIP_REV(bp)    		(((bp)->chip_id) & 0x0000f000)
+#define CHIP_REV_Ax     		0x00000000
+#define CHIP_REV_Bx     		0x00001000
+#define CHIP_REV_Cx     		0x00002000
+#define CHIP_REV_EMUL   		0x0000e000
+#define CHIP_REV_FPGA   		0x0000f000
+#define CHIP_REV_IS_SLOW(bp)    	((CHIP_REV(bp) == CHIP_REV_EMUL) || \
+					 (CHIP_REV(bp) == CHIP_REV_FPGA))
+
+#define CHIP_METAL(bp)  		(((bp)->chip_id) & 0x00000ff0)
+#define CHIP_BOND_ID(bp)		(((bp)->chip_id) & 0x0000000f)
+
+	u16     		fw_seq;
+	u16     		fw_drv_pulse_wr_seq;
+	u32     		fw_mb;
+
+	u32     		hw_config;
+	u32     		serdes_config;
+	u32     		lane_config;
+	u32     		ext_phy_config;
+#define XGXS_EXT_PHY_TYPE(bp)   	(bp->ext_phy_config & \
+					 PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK)
+#define SERDES_EXT_PHY_TYPE(bp) 	(bp->ext_phy_config & \
+					 PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK)
+
+	u32     		speed_cap_mask;
+	u32     		link_config;
+#define SWITCH_CFG_1G   		PORT_FEATURE_CON_SWITCH_1G_SWITCH
+#define SWITCH_CFG_10G  		PORT_FEATURE_CON_SWITCH_10G_SWITCH
+#define SWITCH_CFG_AUTO_DETECT  	PORT_FEATURE_CON_SWITCH_AUTO_DETECT
+#define SWITCH_CFG_ONE_TIME_DETECT      \
+				PORT_FEATURE_CON_SWITCH_ONE_TIME_DETECT
+
+	u8      		ser_lane;
+	u8      		rx_lane_swap;
+	u8      		tx_lane_swap;
+
+	u8      		link_up;
+
+	u32     		supported;
+/* link settings - missing defines */
+#define SUPPORTED_2500baseT_Full	(1 << 15)
+#define SUPPORTED_CX4   		(1 << 16)
+
+	u32     		phy_flags;
+/*#define PHY_SERDES_FLAG       		0x1*/
+#define PHY_BMAC_FLAG   		0x2
+#define PHY_EMAC_FLAG   		0x4
+#define PHY_XGXS_FLAG   		0x8
+#define PHY_SGMII_FLAG  		0x10
+#define PHY_INT_MODE_MASK_FLAG  	0x300
+#define PHY_INT_MODE_AUTO_POLLING_FLAG  0x100
+#define PHY_INT_MODE_LINK_READY_FLAG    0x200
+
+	u32     		phy_addr;
+	u32     		phy_id;
+
+	u32     		autoneg;
+#define AUTONEG_CL37    		SHARED_HW_CFG_AN_ENABLE_CL37
+#define AUTONEG_CL73    		SHARED_HW_CFG_AN_ENABLE_CL73
+#define AUTONEG_BAM     		SHARED_HW_CFG_AN_ENABLE_BAM
+#define AUTONEG_PARALLEL		\
+				SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION
+#define AUTONEG_SGMII_FIBER_AUTODET     \
+				SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT
+#define AUTONEG_REMOTE_PHY      	SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY
+
+	u32     		req_autoneg;
+#define AUTONEG_SPEED   		0x1
+#define AUTONEG_FLOW_CTRL       	0x2
+
+	u32     		req_line_speed;
+/* link settings - missing defines */
+#define SPEED_12000     		12000
+#define SPEED_12500     		12500
+#define SPEED_13000     		13000
+#define SPEED_15000     		15000
+#define SPEED_16000     		16000
+
+	u32     		req_duplex;
+	u32     		req_flow_ctrl;
+#define FLOW_CTRL_AUTO  		PORT_FEATURE_FLOW_CONTROL_AUTO
+#define FLOW_CTRL_TX    		PORT_FEATURE_FLOW_CONTROL_TX
+#define FLOW_CTRL_RX    		PORT_FEATURE_FLOW_CONTROL_RX
+#define FLOW_CTRL_BOTH  		PORT_FEATURE_FLOW_CONTROL_BOTH
+#define FLOW_CTRL_NONE  		PORT_FEATURE_FLOW_CONTROL_NONE
+
+	u32     		pause_mode;
+#define PAUSE_NONE      		0
+#define PAUSE_SYMMETRIC 		1
+#define PAUSE_ASYMMETRIC		2
+#define PAUSE_BOTH      		3
+
+	u32     		advertising;
+/* link settings - missing defines */
+#define ADVERTISED_2500baseT_Full       (1 << 15)
+#define ADVERTISED_CX4  		(1 << 16)
+
+	u32     		link_status;
+	u32     		line_speed;
+	u32     		duplex;
+	u32     		flow_ctrl;
+
+	u32     		bc_ver;
+
+	int     		flash_size;
+#define NVRAM_1MB_SIZE  		0x20000 /* 1M bit in bytes */
+#define NVRAM_TIMEOUT_COUNT     	30000
+#define NVRAM_PAGE_SIZE 		256
+
+	int     		rx_ring_size;
+
+	u16     		tx_quick_cons_trip_int;
+	u16     		tx_quick_cons_trip;
+	u16     		tx_ticks_int;
+	u16     		tx_ticks;
+
+	u16     		rx_quick_cons_trip_int;
+	u16     		rx_quick_cons_trip;
+	u16     		rx_ticks_int;
+	u16     		rx_ticks;
+
+	u32     		stats_ticks;
+
+	int     		state;
+#define BNX2X_STATE_CLOSED      	0x0
+#define BNX2X_STATE_OPENING_WAIT4_LOAD  0x1000
+#define BNX2X_STATE_OPENING_WAIT4_PORT  0x2000
+#define BNX2X_STATE_OPEN		0x3000
+#define BNX2X_STATE_CLOSING_WAIT4_HALT  0x4000
+#define BNX2X_STATE_CLOSING_WAIT4_DELETE 0x5000
+#define BNX2X_STATE_CLOSING_WAIT4_UNLOAD 0x6000
+#define BNX2X_STATE_ERROR       	0xF000
+
+	int     		num_queues;
+
+	u32     		rx_mode;
+#define BNX2X_RX_MODE_NONE      	0
+#define BNX2X_RX_MODE_NORMAL    	1
+#define BNX2X_RX_MODE_ALLMULTI  	2
+#define BNX2X_RX_MODE_PROMISC   	3
+#define BNX2X_MAX_MULTICAST     	64
+#define BNX2X_MAX_EMUL_MULTI    	16
+
+	dma_addr_t      	def_status_blk_mapping;
+
+	struct bnx2x_slowpath   *slowpath;
+	dma_addr_t      	slowpath_mapping;
+
+#ifdef BCM_ISCSI
+	void    		*t1;
+	dma_addr_t      	t1_mapping;
+	void    		*t2;
+	dma_addr_t      	t2_mapping;
+	void    		*timers;
+	dma_addr_t      	timers_mapping;
+	void    		*qm;
+	dma_addr_t      	qm_mapping;
+#endif
+
+	char    		*name;
+	u16     		bus_speed_mhz;
+	u8      		wol;
+	u8      		pad;
+
+	/* used to synchronize stats collecting */
+	int     		stats_state;
+#define STATS_STATE_DISABLE     	0
+#define STATS_STATE_ENABLE      	1
+#define STATS_STATE_STOP		2 /* stop stats on next iteration */
+
+	/* used by dmae command loader */
+	struct dmae_command     dmae;
+	int     		executer_idx;
+
+	u32     		old_brb_discard;
+	struct bmac_stats       old_bmac;
+	struct tstorm_per_client_stats old_tclient;
+	struct z_stream_s       *strm;
+	void    		*gunzip_buf;
+	dma_addr_t      	gunzip_mapping;
+	int     		gunzip_outlen;
+#define FW_BUF_SIZE     		0x8000
+
+};
+
+
+/* DMAE command defines */
+#define DMAE_CMD_SRC_PCI		0
+#define DMAE_CMD_SRC_GRC		DMAE_COMMAND_SRC
+
+#define DMAE_CMD_DST_PCI		(1 << DMAE_COMMAND_DST_SHIFT)
+#define DMAE_CMD_DST_GRC		(2 << DMAE_COMMAND_DST_SHIFT)
+
+#define DMAE_CMD_C_DST_PCI      	0
+#define DMAE_CMD_C_DST_GRC      	(1 << DMAE_COMMAND_C_DST_SHIFT)
+
+#define DMAE_CMD_C_ENABLE       	DMAE_COMMAND_C_TYPE_ENABLE
+
+#define DMAE_CMD_ENDIANITY_NO_SWAP      (0 << DMAE_COMMAND_ENDIANITY_SHIFT)
+#define DMAE_CMD_ENDIANITY_B_SWAP       (1 << DMAE_COMMAND_ENDIANITY_SHIFT)
+#define DMAE_CMD_ENDIANITY_DW_SWAP      (2 << DMAE_COMMAND_ENDIANITY_SHIFT)
+#define DMAE_CMD_ENDIANITY_B_DW_SWAP    (3 << DMAE_COMMAND_ENDIANITY_SHIFT)
+
+#define DMAE_CMD_PORT_0 		0
+#define DMAE_CMD_PORT_1 		DMAE_COMMAND_PORT
+
+#define DMAE_CMD_SRC_RESET      	DMAE_COMMAND_SRC_RESET
+#define DMAE_CMD_DST_RESET      	DMAE_COMMAND_DST_RESET
+
+#define DMAE_LEN32_MAX  		0x400
+
+
+/* MC hsi */
+#define RX_COPY_THRESH  		92
+#define BCM_PAGE_BITS   		12
+#define BCM_PAGE_SIZE   		(1 << BCM_PAGE_BITS)
+
+#define NUM_TX_RINGS    		16
+#define TX_DESC_CNT     	(BCM_PAGE_SIZE / sizeof(struct eth_tx_bd))
+#define MAX_TX_DESC_CNT 		(TX_DESC_CNT - 1)
+#define NUM_TX_BD       		(TX_DESC_CNT * NUM_TX_RINGS)
+#define MAX_TX_BD       		(NUM_TX_BD - 1)
+#define MAX_TX_AVAIL    		(MAX_TX_DESC_CNT * NUM_TX_RINGS - 2)
+#define NEXT_TX_IDX(x)  	((((x) & MAX_TX_DESC_CNT) == \
+				 (MAX_TX_DESC_CNT - 1)) ? (x) + 2 : (x) + 1)
+#define TX_BD(x)			((x) & MAX_TX_BD)
+#define TX_BD_POFF(x)   		((x) & MAX_TX_DESC_CNT)
+
+/* The RX BD ring is special, each bd is 8 bytes but the last one is 16 */
+#define NUM_RX_RINGS    		8
+#define RX_DESC_CNT     	(BCM_PAGE_SIZE / sizeof(struct eth_rx_bd))
+#define MAX_RX_DESC_CNT 		(RX_DESC_CNT - 2)
+#define RX_DESC_MASK    		(RX_DESC_CNT - 1)
+#define NUM_RX_BD       		(RX_DESC_CNT * NUM_RX_RINGS)
+#define MAX_RX_BD       		(NUM_RX_BD - 1)
+#define MAX_RX_AVAIL    		(MAX_RX_DESC_CNT * NUM_RX_RINGS - 2)
+#define NEXT_RX_IDX(x)  	((((x) & RX_DESC_MASK) == \
+				 (MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1)
+#define RX_BD(x)			((x) & MAX_RX_BD)
+
+#define NUM_RCQ_RINGS   		(NUM_RX_RINGS * 2)
+#define RCQ_DESC_CNT    	(BCM_PAGE_SIZE / sizeof(union eth_rx_cqe))
+#define MAX_RCQ_DESC_CNT		(RCQ_DESC_CNT - 1)
+#define NUM_RCQ_BD      		(RCQ_DESC_CNT * NUM_RCQ_RINGS)
+#define MAX_RCQ_BD      		(NUM_RCQ_BD - 1)
+#define MAX_RCQ_AVAIL   		(MAX_RCQ_DESC_CNT * NUM_RCQ_RINGS - 2)
+#define NEXT_RCQ_IDX(x) 	((((x) & MAX_RCQ_DESC_CNT) == \
+				 (MAX_RCQ_DESC_CNT - 1)) ? (x) + 2 : (x) + 1)
+#define RCQ_BD(x)       		((x) & MAX_RCQ_BD)
+
+
+/* used on a CID received from the HW */
+#define SW_CID(x)       		(le32_to_cpu(x) & \
+					 (COMMON_RAMROD_ETH_RX_CQE_CID >> 1))
+#define CQE_CMD(x)      		(le32_to_cpu(x) >> \
+					COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT)
+
+#define BD_UNMAP_ADDR(bd)       	HILO_U64(le32_to_cpu((bd)->addr_hi), \
+						 le32_to_cpu((bd)->addr_lo))
+#define BD_UNMAP_LEN(bd)		(le16_to_cpu((bd)->nbytes))
+
+
+#define STROM_ASSERT_ARRAY_SIZE 	50
+
+
+#define MDIO_INDIRECT_REG_ADDR  	0x1f
+#define MDIO_SET_REG_BANK(bp, reg_bank) \
+		bnx2x_mdio22_write(bp, MDIO_INDIRECT_REG_ADDR, reg_bank)
+
+#define MDIO_ACCESS_TIMEOUT     	1000
+
+
+/* must be used on a CID before placing it on a HW ring */
+#define HW_CID(bp, x)   		(x | (bp->port << 23))
+
+#define SP_DESC_CNT     	(BCM_PAGE_SIZE / sizeof(struct eth_spe))
+#define MAX_SP_DESC_CNT 		(SP_DESC_CNT - 1)
+
+#define ATTN_NIG_FOR_FUNC       	(1L << 8)
+#define ATTN_SW_TIMER_4_FUNC    	(1L << 9)
+#define GPIO_2_FUNC     		(1L << 10)
+#define GPIO_3_FUNC     		(1L << 11)
+#define GPIO_4_FUNC     		(1L << 12)
+#define ATTN_GENERAL_ATTN_1     	(1L << 13)
+#define ATTN_GENERAL_ATTN_2     	(1L << 14)
+#define ATTN_GENERAL_ATTN_3     	(1L << 15)
+#define ATTN_GENERAL_ATTN_4     	(1L << 13)
+#define ATTN_GENERAL_ATTN_5     	(1L << 14)
+#define ATTN_GENERAL_ATTN_6     	(1L << 15)
+
+#define ATTN_HARD_WIRED_MASK    	0xff00
+#define ATTENTION_ID    		4
+
+
+#define BNX2X_BTR       		3
+#define MAX_SPQ_PENDING 		8
+
+
+#define BNX2X_NUM_STATS 		31
+#define BNX2X_NUM_TESTS 		2
+
+
+#define DPM_TRIGER_TYPE 		0x40
+#define DOORBELL(bp, cid, val) \
+	do { \
+		writel((u32)val, (bp)->doorbells + (BCM_PAGE_SIZE * cid) + \
+		       DPM_TRIGER_TYPE); \
+	} while (0)
+
+
+/* stuff added to make the code fit 80Col */
+
+#define TPA_TYPE_START  		ETH_FAST_PATH_RX_CQE_START_FLG
+#define TPA_TYPE_END    		ETH_FAST_PATH_RX_CQE_END_FLG
+#define TPA_TYPE(cqe)   	(cqe->fast_path_cqe.error_type_flags & \
+				 (TPA_TYPE_START | TPA_TYPE_END))
+#define BNX2X_RX_SUM_OK(cqe) \
+			(!(cqe->fast_path_cqe.status_flags & \
+			 (ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG | \
+			  ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG)))
+
+#define BNX2X_RX_SUM_FIX(cqe) \
+			((le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & \
+			  PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) == \
+			 (1 << PARSING_FLAGS_OVER_ETHERNET_PROTOCOL_SHIFT))
+
+
+#define MDIO_AN_CL73_OR_37_COMPLETE \
+		(MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \
+		 MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE)
+
+#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \
+			MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE
+#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \
+			MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE
+#define GP_STATUS_SPEED_MASK \
+			MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK
+#define GP_STATUS_10M   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M
+#define GP_STATUS_100M  MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M
+#define GP_STATUS_1G    MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G
+#define GP_STATUS_2_5G  MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G
+#define GP_STATUS_5G    MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G
+#define GP_STATUS_6G    MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G
+#define GP_STATUS_10G_HIG \
+			MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG
+#define GP_STATUS_10G_CX4 \
+			MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4
+#define GP_STATUS_12G_HIG \
+			MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG
+#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G
+#define GP_STATUS_13G   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G
+#define GP_STATUS_15G   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G
+#define GP_STATUS_16G   MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G
+#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX
+#define GP_STATUS_10G_KX4 \
+			MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4
+
+#define LINK_10THD      		LINK_STATUS_SPEED_AND_DUPLEX_10THD
+#define LINK_10TFD      		LINK_STATUS_SPEED_AND_DUPLEX_10TFD
+#define LINK_100TXHD    		LINK_STATUS_SPEED_AND_DUPLEX_100TXHD
+#define LINK_100T4      		LINK_STATUS_SPEED_AND_DUPLEX_100T4
+#define LINK_100TXFD    		LINK_STATUS_SPEED_AND_DUPLEX_100TXFD
+#define LINK_1000THD    		LINK_STATUS_SPEED_AND_DUPLEX_1000THD
+#define LINK_1000TFD    		LINK_STATUS_SPEED_AND_DUPLEX_1000TFD
+#define LINK_1000XFD    		LINK_STATUS_SPEED_AND_DUPLEX_1000XFD
+#define LINK_2500THD    		LINK_STATUS_SPEED_AND_DUPLEX_2500THD
+#define LINK_2500TFD    		LINK_STATUS_SPEED_AND_DUPLEX_2500TFD
+#define LINK_2500XFD    		LINK_STATUS_SPEED_AND_DUPLEX_2500XFD
+#define LINK_10GTFD     		LINK_STATUS_SPEED_AND_DUPLEX_10GTFD
+#define LINK_10GXFD     		LINK_STATUS_SPEED_AND_DUPLEX_10GXFD
+#define LINK_12GTFD     		LINK_STATUS_SPEED_AND_DUPLEX_12GTFD
+#define LINK_12GXFD     		LINK_STATUS_SPEED_AND_DUPLEX_12GXFD
+#define LINK_12_5GTFD   		LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD
+#define LINK_12_5GXFD   		LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD
+#define LINK_13GTFD     		LINK_STATUS_SPEED_AND_DUPLEX_13GTFD
+#define LINK_13GXFD     		LINK_STATUS_SPEED_AND_DUPLEX_13GXFD
+#define LINK_15GTFD     		LINK_STATUS_SPEED_AND_DUPLEX_15GTFD
+#define LINK_15GXFD     		LINK_STATUS_SPEED_AND_DUPLEX_15GXFD
+#define LINK_16GTFD     		LINK_STATUS_SPEED_AND_DUPLEX_16GTFD
+#define LINK_16GXFD     		LINK_STATUS_SPEED_AND_DUPLEX_16GXFD
+
+#define NIG_STATUS_INTERRUPT_XGXS0_LINK10G \
+		NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G
+#define NIG_XGXS0_LINK_STATUS \
+		NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS
+#define NIG_XGXS0_LINK_STATUS_SIZE \
+		NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE
+#define NIG_SERDES0_LINK_STATUS \
+		NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS
+#define NIG_MASK_MI_INT \
+		NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT
+#define NIG_MASK_XGXS0_LINK10G \
+		NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G
+#define NIG_MASK_XGXS0_LINK_STATUS \
+		NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS
+#define NIG_MASK_SERDES0_LINK_STATUS \
+		NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS
+
+#define XGXS_RESET_BITS \
+	(MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW |   \
+	 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ |      \
+	 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN |    \
+	 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \
+	 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB)
+
+#define SERDES_RESET_BITS \
+	(MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \
+	 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ |    \
+	 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN |  \
+	 MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD)
+
+
+#define BNX2X_MC_ASSERT_BITS \
+	(GENERAL_ATTEN_OFFSET(TSTORM_FATAL_ASSERT_ATTENTION_BIT) | \
+	 GENERAL_ATTEN_OFFSET(USTORM_FATAL_ASSERT_ATTENTION_BIT) | \
+	 GENERAL_ATTEN_OFFSET(CSTORM_FATAL_ASSERT_ATTENTION_BIT) | \
+	 GENERAL_ATTEN_OFFSET(XSTORM_FATAL_ASSERT_ATTENTION_BIT))
+
+#define BNX2X_MCP_ASSERT \
+	GENERAL_ATTEN_OFFSET(MCP_FATAL_ASSERT_ATTENTION_BIT)
+
+#define BNX2X_DOORQ_ASSERT \
+	AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT
+
+#define HW_INTERRUT_ASSERT_SET_0 \
+				(AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_PBF_HW_INTERRUPT)
+#define HW_PRTY_ASSERT_SET_0    (AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR |\
+				 AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR)
+#define HW_INTERRUT_ASSERT_SET_1 \
+				(AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_TIMERS_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_XSDM_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_XCM_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_XSEMI_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_USDM_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_UCM_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_USEMI_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_UPB_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_CSDM_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT)
+#define HW_PRTY_ASSERT_SET_1    (AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR |\
+				 AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR | \
+				AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR |\
+			    AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR |\
+				 AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR)
+#define HW_INTERRUT_ASSERT_SET_2 \
+				(AEU_INPUTS_ATTN_BITS_CSEMI_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_CDU_HW_INTERRUPT | \
+				 AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT | \
+			AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_HW_INTERRUPT |\
+				 AEU_INPUTS_ATTN_BITS_MISC_HW_INTERRUPT)
+#define HW_PRTY_ASSERT_SET_2    (AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR | \
+			AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR |\
+				 AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR | \
+				 AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR)
+
+
+#define ETH_RX_ERROR_FALGS      (ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG | \
+				 ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG | \
+				 ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG)
+
+
+#define MULTI_FLAGS \
+	(TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY     | \
+	 TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY | \
+	 TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY     | \
+	 TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY | \
+	 TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE)
+
+#define MULTI_MASK      0x7f
+
+
+#define U_SB_ETH_RX_CQ_INDEX    	HC_INDEX_U_ETH_RX_CQ_CONS
+#define C_SB_ETH_TX_CQ_INDEX    	HC_INDEX_C_ETH_TX_CQ_CONS
+#define C_DEF_SB_SP_INDEX       	HC_INDEX_DEF_C_ETH_SLOW_PATH
+
+#define BNX2X_RX_SB_INDEX \
+	&fp->status_blk->u_status_block.index_values[U_SB_ETH_RX_CQ_INDEX]
+
+#define BNX2X_TX_SB_INDEX \
+	&fp->status_blk->c_status_block.index_values[C_SB_ETH_TX_CQ_INDEX]
+
+#define BNX2X_SP_DSB_INDEX \
+&bp->def_status_blk->c_def_status_block.index_values[C_DEF_SB_SP_INDEX]
+
+
+#define CAM_IS_INVALID(x) \
+(x.target_table_entry.flags == TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE)
+
+#define CAM_INVALIDATE(x) \
+x.target_table_entry.flags = TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE
+
+
+/* MISC_REG_RESET_REG - this is here for the hsi to work don't touch */
+
+#endif /* bnx2x.h */
diff --git a/drivers/net/bnx2x_fw_defs.h b/drivers/net/bnx2x_fw_defs.h
new file mode 100644
index 000000000000..62a6eb81025a
--- /dev/null
+++ b/drivers/net/bnx2x_fw_defs.h
@@ -0,0 +1,198 @@
+/* bnx2x_fw_defs.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007 Broadcom Corporation
+ *
+ * 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.
+ */
+
+
+#define CSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\
+	(0x1922 + (port * 0x40) + (index * 0x4))
+#define CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\
+	(0x1900 + (port * 0x40))
+#define CSTORM_HC_BTR_OFFSET(port)\
+	(0x1984 + (port * 0xc0))
+#define CSTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index)\
+	(0x141a + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4))
+#define CSTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index)\
+	(0x1418 + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4))
+#define CSTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id)\
+	(0x1400 + (port * 0x280) + (cpu_id * 0x28))
+#define CSTORM_STATS_FLAGS_OFFSET(port) 		(0x5108 + (port * 0x8))
+#define TSTORM_CLIENT_CONFIG_OFFSET(port, client_id)\
+	(0x1510 + (port * 0x240) + (client_id * 0x20))
+#define TSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\
+	(0x138a + (port * 0x28) + (index * 0x4))
+#define TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\
+	(0x1370 + (port * 0x28))
+#define TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port)\
+	(0x4b70 + (port * 0x8))
+#define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(function)\
+	(0x1418 + (function * 0x30))
+#define TSTORM_HC_BTR_OFFSET(port)\
+	(0x13c4 + (port * 0x18))
+#define TSTORM_INDIRECTION_TABLE_OFFSET(port)\
+	(0x22c8 + (port * 0x80))
+#define TSTORM_INDIRECTION_TABLE_SIZE			0x80
+#define TSTORM_MAC_FILTER_CONFIG_OFFSET(port)\
+	(0x1420 + (port * 0x30))
+#define TSTORM_RCQ_PROD_OFFSET(port, client_id)\
+	(0x1508 + (port * 0x240) + (client_id * 0x20))
+#define TSTORM_STATS_FLAGS_OFFSET(port) 		(0x4b90 + (port * 0x8))
+#define USTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\
+	(0x191a + (port * 0x28) + (index * 0x4))
+#define USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\
+	(0x1900 + (port * 0x28))
+#define USTORM_HC_BTR_OFFSET(port)\
+	(0x1954 + (port * 0xb8))
+#define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port)\
+	(0x5408 + (port * 0x8))
+#define USTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index)\
+	(0x141a + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4))
+#define USTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index)\
+	(0x1418 + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4))
+#define USTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id)\
+	(0x1400 + (port * 0x280) + (cpu_id * 0x28))
+#define XSTORM_ASSERT_LIST_INDEX_OFFSET 		0x1000
+#define XSTORM_ASSERT_LIST_OFFSET(idx)			(0x1020 + (idx * 0x10))
+#define XSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\
+	(0x141a + (port * 0x28) + (index * 0x4))
+#define XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\
+	(0x1400 + (port * 0x28))
+#define XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port)\
+	(0x5408 + (port * 0x8))
+#define XSTORM_HC_BTR_OFFSET(port)\
+	(0x1454 + (port * 0x18))
+#define XSTORM_SPQ_PAGE_BASE_OFFSET(port)\
+	(0x5328 + (port * 0x18))
+#define XSTORM_SPQ_PROD_OFFSET(port)\
+	(0x5330 + (port * 0x18))
+#define XSTORM_STATS_FLAGS_OFFSET(port) 		(0x53f8 + (port * 0x8))
+#define COMMON_ASM_INVALID_ASSERT_OPCODE 0x0
+
+/**
+* This file defines HSI constatnts for the ETH flow
+*/
+
+/* hash types */
+#define DEFAULT_HASH_TYPE			0
+#define IPV4_HASH_TYPE				1
+#define TCP_IPV4_HASH_TYPE			2
+#define IPV6_HASH_TYPE				3
+#define TCP_IPV6_HASH_TYPE			4
+
+/* values of command IDs in the ramrod message */
+#define RAMROD_CMD_ID_ETH_PORT_SETUP			(80)
+#define RAMROD_CMD_ID_ETH_CLIENT_SETUP			(85)
+#define RAMROD_CMD_ID_ETH_STAT_QUERY			(90)
+#define RAMROD_CMD_ID_ETH_UPDATE			(100)
+#define RAMROD_CMD_ID_ETH_HALT				(105)
+#define RAMROD_CMD_ID_ETH_SET_MAC			(110)
+#define RAMROD_CMD_ID_ETH_CFC_DEL			(115)
+#define RAMROD_CMD_ID_ETH_PORT_DEL			(120)
+#define RAMROD_CMD_ID_ETH_FORWARD_SETUP 		(125)
+
+
+/* command values for set mac command */
+#define T_ETH_MAC_COMMAND_SET				0
+#define T_ETH_MAC_COMMAND_INVALIDATE			1
+
+#define T_ETH_INDIRECTION_TABLE_SIZE			128
+
+/* Maximal L2 clients supported */
+#define ETH_MAX_RX_CLIENTS				(18)
+
+/**
+* This file defines HSI constatnts common to all microcode flows
+*/
+
+/* Connection types */
+#define ETH_CONNECTION_TYPE			0
+
+#define PROTOCOL_STATE_BIT_OFFSET		6
+
+#define ETH_STATE	(ETH_CONNECTION_TYPE << PROTOCOL_STATE_BIT_OFFSET)
+
+/* microcode fixed page page size 4K (chains and ring segments) */
+#define MC_PAGE_SIZE						(4096)
+
+/* Host coalescing constants */
+
+/* IGU constants */
+#define IGU_PORT_BASE				0x0400
+
+#define IGU_ADDR_MSIX				0x0000
+#define IGU_ADDR_INT_ACK			0x0200
+#define IGU_ADDR_PROD_UPD			0x0201
+#define IGU_ADDR_ATTN_BITS_UPD			0x0202
+#define IGU_ADDR_ATTN_BITS_SET			0x0203
+#define IGU_ADDR_ATTN_BITS_CLR			0x0204
+#define IGU_ADDR_COALESCE_NOW			0x0205
+#define IGU_ADDR_SIMD_MASK			0x0206
+#define IGU_ADDR_SIMD_NOMASK			0x0207
+#define IGU_ADDR_MSI_CTL			0x0210
+#define IGU_ADDR_MSI_ADDR_LO			0x0211
+#define IGU_ADDR_MSI_ADDR_HI			0x0212
+#define IGU_ADDR_MSI_DATA			0x0213
+
+#define IGU_INT_ENABLE				0
+#define IGU_INT_DISABLE 			1
+#define IGU_INT_NOP				2
+#define IGU_INT_NOP2				3
+
+/* index numbers */
+#define HC_USTORM_DEF_SB_NUM_INDICES		4
+#define HC_CSTORM_DEF_SB_NUM_INDICES		8
+#define HC_XSTORM_DEF_SB_NUM_INDICES		4
+#define HC_TSTORM_DEF_SB_NUM_INDICES		4
+#define HC_USTORM_SB_NUM_INDICES		4
+#define HC_CSTORM_SB_NUM_INDICES		4
+
+/* index values - which counterto update */
+
+#define HC_INDEX_U_ETH_RX_CQ_CONS		1
+
+#define HC_INDEX_C_ETH_TX_CQ_CONS		1
+
+#define HC_INDEX_DEF_X_SPQ_CONS 		0
+
+#define HC_INDEX_DEF_C_ETH_FW_TX_CQ_CONS	2
+#define HC_INDEX_DEF_C_ETH_SLOW_PATH		3
+
+/* used by the driver to get the SB offset */
+#define USTORM_ID			0
+#define CSTORM_ID			1
+#define XSTORM_ID			2
+#define TSTORM_ID			3
+#define ATTENTION_ID			4
+
+/* max number of slow path commands per port */
+#define MAX_RAMRODS_PER_PORT		(8)
+
+/* values for RX ETH CQE type field */
+#define RX_ETH_CQE_TYPE_ETH_FASTPATH	(0)
+#define RX_ETH_CQE_TYPE_ETH_RAMROD		(1)
+
+/* MAC address list size */
+#define T_MAC_ADDRESS_LIST_SIZE 	(96)
+
+#define XSTORM_IP_ID_ROLL_HALF 0x8000
+#define XSTORM_IP_ID_ROLL_ALL 0
+
+#define FW_LOG_LIST_SIZE	(50)
+
+#define NUM_OF_PROTOCOLS		4
+#define MAX_COS_NUMBER			16
+#define MAX_T_STAT_COUNTER_ID	18
+
+#define T_FAIR							1
+#define FAIR_MEM						2
+#define RS_PERIODIC_TIMEOUT_IN_SDM_TICS 25
+
+#define UNKNOWN_ADDRESS 	0
+#define UNICAST_ADDRESS 	1
+#define MULTICAST_ADDRESS	2
+#define BROADCAST_ADDRESS	3
+
diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h
new file mode 100644
index 000000000000..6fd959c34d1f
--- /dev/null
+++ b/drivers/net/bnx2x_hsi.h
@@ -0,0 +1,2176 @@
+/* bnx2x_hsi.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007 Broadcom Corporation
+ *
+ * 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.
+ */
+
+
+#define FUNC_0				0
+#define FUNC_1				1
+#define FUNC_MAX			2
+
+
+/* This value (in milliseconds) determines the frequency of the driver
+ * issuing the PULSE message code.  The firmware monitors this periodic
+ * pulse to determine when to switch to an OS-absent mode. */
+#define DRV_PULSE_PERIOD_MS		250
+
+/* This value (in milliseconds) determines how long the driver should
+ * wait for an acknowledgement from the firmware before timing out.  Once
+ * the firmware has timed out, the driver will assume there is no firmware
+ * running and there won't be any firmware-driver synchronization during a
+ * driver reset. */
+#define FW_ACK_TIME_OUT_MS		5000
+
+#define FW_ACK_POLL_TIME_MS		1
+
+#define FW_ACK_NUM_OF_POLL	(FW_ACK_TIME_OUT_MS/FW_ACK_POLL_TIME_MS)
+
+/* LED Blink rate that will achieve ~15.9Hz */
+#define LED_BLINK_RATE_VAL		480
+
+/****************************************************************************
+ * Driver <-> FW Mailbox						    *
+ ****************************************************************************/
+struct drv_fw_mb {
+	u32 drv_mb_header;
+#define DRV_MSG_CODE_MASK			0xffff0000
+#define DRV_MSG_CODE_LOAD_REQ			0x10000000
+#define DRV_MSG_CODE_LOAD_DONE			0x11000000
+#define DRV_MSG_CODE_UNLOAD_REQ_WOL_EN		0x20000000
+#define DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS 	0x20010000
+#define DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP 	0x20020000
+#define DRV_MSG_CODE_UNLOAD_DONE		0x21000000
+#define DRV_MSG_CODE_DIAG_ENTER_REQ		0x50000000
+#define DRV_MSG_CODE_DIAG_EXIT_REQ		0x60000000
+#define DRV_MSG_CODE_VALIDATE_KEY		0x70000000
+#define DRV_MSG_CODE_GET_CURR_KEY		0x80000000
+#define DRV_MSG_CODE_GET_UPGRADE_KEY		0x81000000
+#define DRV_MSG_CODE_GET_MANUF_KEY		0x82000000
+#define DRV_MSG_CODE_LOAD_L2B_PRAM		0x90000000
+
+#define DRV_MSG_SEQ_NUMBER_MASK 		0x0000ffff
+
+	u32 drv_mb_param;
+
+	u32 fw_mb_header;
+#define FW_MSG_CODE_MASK			0xffff0000
+#define FW_MSG_CODE_DRV_LOAD_COMMON		0x11000000
+#define FW_MSG_CODE_DRV_LOAD_PORT		0x12000000
+#define FW_MSG_CODE_DRV_LOAD_REFUSED		0x13000000
+#define FW_MSG_CODE_DRV_LOAD_DONE		0x14000000
+#define FW_MSG_CODE_DRV_UNLOAD_COMMON		0x21000000
+#define FW_MSG_CODE_DRV_UNLOAD_PORT		0x22000000
+#define FW_MSG_CODE_DRV_UNLOAD_DONE		0x23000000
+#define FW_MSG_CODE_DIAG_ENTER_DONE		0x50000000
+#define FW_MSG_CODE_DIAG_REFUSE 		0x51000000
+#define FW_MSG_CODE_VALIDATE_KEY_SUCCESS	0x70000000
+#define FW_MSG_CODE_VALIDATE_KEY_FAILURE	0x71000000
+#define FW_MSG_CODE_GET_KEY_DONE		0x80000000
+#define FW_MSG_CODE_NO_KEY			0x8f000000
+#define FW_MSG_CODE_LIC_INFO_NOT_READY		0x8f800000
+#define FW_MSG_CODE_L2B_PRAM_LOADED		0x90000000
+#define FW_MSG_CODE_L2B_PRAM_T_LOAD_FAILURE	0x91000000
+#define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE	0x92000000
+#define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE	0x93000000
+#define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE	0x94000000
+
+#define FW_MSG_SEQ_NUMBER_MASK			0x0000ffff
+
+	u32 fw_mb_param;
+
+	u32 link_status;
+	/* Driver should update this field on any link change event */
+
+#define LINK_STATUS_LINK_FLAG_MASK		0x00000001
+#define LINK_STATUS_LINK_UP			0x00000001
+#define LINK_STATUS_SPEED_AND_DUPLEX_MASK	0x0000001E
+#define LINK_STATUS_SPEED_AND_DUPLEX_AN_NOT_COMPLETE	(0<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_10THD		(1<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_10TFD		(2<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_100TXHD		(3<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_100T4		(4<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_100TXFD		(5<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_1000THD		(6<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_1000TFD		(7<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_1000XFD		(7<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_2500THD		(8<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_2500TFD		(9<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_2500XFD		(9<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_10GTFD		(10<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_10GXFD		(10<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_12GTFD		(11<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_12GXFD		(11<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD		(12<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD		(12<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_13GTFD		(13<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_13GXFD		(13<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_15GTFD		(14<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_15GXFD		(14<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_16GTFD		(15<<1)
+#define LINK_STATUS_SPEED_AND_DUPLEX_16GXFD		(15<<1)
+
+#define LINK_STATUS_AUTO_NEGOTIATE_FLAG_MASK		0x00000020
+#define LINK_STATUS_AUTO_NEGOTIATE_ENABLED		0x00000020
+
+#define LINK_STATUS_AUTO_NEGOTIATE_COMPLETE		0x00000040
+#define LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK	0x00000080
+#define LINK_STATUS_PARALLEL_DETECTION_USED		0x00000080
+
+#define LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE	0x00000200
+#define LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE	0x00000400
+#define LINK_STATUS_LINK_PARTNER_100T4_CAPABLE		0x00000800
+#define LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE	0x00001000
+#define LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE	0x00002000
+#define LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE		0x00004000
+#define LINK_STATUS_LINK_PARTNER_10THD_CAPABLE		0x00008000
+
+#define LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK		0x00010000
+#define LINK_STATUS_TX_FLOW_CONTROL_ENABLED		0x00010000
+
+#define LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK		0x00020000
+#define LINK_STATUS_RX_FLOW_CONTROL_ENABLED		0x00020000
+
+#define LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK	0x000C0000
+#define LINK_STATUS_LINK_PARTNER_NOT_PAUSE_CAPABLE	(0<<18)
+#define LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE	(1<<18)
+#define LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE	(2<<18)
+#define LINK_STATUS_LINK_PARTNER_BOTH_PAUSE		(3<<18)
+
+#define LINK_STATUS_SERDES_LINK 			0x00100000
+
+#define LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE	0x00200000
+#define LINK_STATUS_LINK_PARTNER_2500XHD_CAPABLE	0x00400000
+#define LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE 	0x00800000
+#define LINK_STATUS_LINK_PARTNER_12GXFD_CAPABLE 	0x01000000
+#define LINK_STATUS_LINK_PARTNER_12_5GXFD_CAPABLE	0x02000000
+#define LINK_STATUS_LINK_PARTNER_13GXFD_CAPABLE 	0x04000000
+#define LINK_STATUS_LINK_PARTNER_15GXFD_CAPABLE 	0x08000000
+#define LINK_STATUS_LINK_PARTNER_16GXFD_CAPABLE 	0x10000000
+
+	u32 drv_pulse_mb;
+#define DRV_PULSE_SEQ_MASK				0x00007fff
+#define DRV_PULSE_SYSTEM_TIME_MASK			0xffff0000
+	/* The system time is in the format of
+	 * (year-2001)*12*32 + month*32 + day. */
+#define DRV_PULSE_ALWAYS_ALIVE				0x00008000
+	/* Indicate to the firmware not to go into the
+	 * OS-absent when it is not getting driver pulse.
+	 * This is used for debugging as well for PXE(MBA). */
+
+	u32 mcp_pulse_mb;
+#define MCP_PULSE_SEQ_MASK				0x00007fff
+#define MCP_PULSE_ALWAYS_ALIVE				0x00008000
+	/* Indicates to the driver not to assert due to lack
+	 * of MCP response */
+#define MCP_EVENT_MASK					0xffff0000
+#define MCP_EVENT_OTHER_DRIVER_RESET_REQ		0x00010000
+
+};
+
+
+/****************************************************************************
+ * Shared HW configuration						    *
+ ****************************************************************************/
+struct shared_hw_cfg {					 /* NVRAM Offset */
+	/* Up to 16 bytes of NULL-terminated string */
+	u8  part_num[16];					/* 0x104 */
+
+	u32 config;						/* 0x114 */
+#define SHARED_HW_CFG_MDIO_VOLTAGE_MASK 	    0x00000001
+#define SHARED_HW_CFG_MDIO_VOLTAGE_SHIFT	    0
+#define SHARED_HW_CFG_MDIO_VOLTAGE_1_2V 	    0x00000000
+#define SHARED_HW_CFG_MDIO_VOLTAGE_2_5V 	    0x00000001
+#define SHARED_HW_CFG_MCP_RST_ON_CORE_RST_EN	    0x00000002
+
+#define SHARED_HW_CFG_PORT_SWAP 		    0x00000004
+
+#define SHARED_HW_CFG_BEACON_WOL_EN		    0x00000008
+
+#define SHARED_HW_CFG_MFW_SELECT_MASK		    0x00000700
+#define SHARED_HW_CFG_MFW_SELECT_SHIFT		    8
+	/* Whatever MFW found in NVM
+	   (if multiple found, priority order is: NC-SI, UMP, IPMI) */
+#define SHARED_HW_CFG_MFW_SELECT_DEFAULT	    0x00000000
+#define SHARED_HW_CFG_MFW_SELECT_NC_SI		    0x00000100
+#define SHARED_HW_CFG_MFW_SELECT_UMP		    0x00000200
+#define SHARED_HW_CFG_MFW_SELECT_IPMI		    0x00000300
+	/* Use SPIO4 as an arbiter between: 0-NC_SI, 1-IPMI
+	  (can only be used when an add-in board, not BMC, pulls-down SPIO4) */
+#define SHARED_HW_CFG_MFW_SELECT_SPIO4_NC_SI_IPMI   0x00000400
+	/* Use SPIO4 as an arbiter between: 0-UMP, 1-IPMI
+	  (can only be used when an add-in board, not BMC, pulls-down SPIO4) */
+#define SHARED_HW_CFG_MFW_SELECT_SPIO4_UMP_IPMI     0x00000500
+	/* Use SPIO4 as an arbiter between: 0-NC-SI, 1-UMP
+	  (can only be used when an add-in board, not BMC, pulls-down SPIO4) */
+#define SHARED_HW_CFG_MFW_SELECT_SPIO4_NC_SI_UMP    0x00000600
+
+#define SHARED_HW_CFG_LED_MODE_MASK		    0x000f0000
+#define SHARED_HW_CFG_LED_MODE_SHIFT		    16
+#define SHARED_HW_CFG_LED_MAC1			    0x00000000
+#define SHARED_HW_CFG_LED_PHY1			    0x00010000
+#define SHARED_HW_CFG_LED_PHY2			    0x00020000
+#define SHARED_HW_CFG_LED_PHY3			    0x00030000
+#define SHARED_HW_CFG_LED_MAC2			    0x00040000
+#define SHARED_HW_CFG_LED_PHY4			    0x00050000
+#define SHARED_HW_CFG_LED_PHY5			    0x00060000
+#define SHARED_HW_CFG_LED_PHY6			    0x00070000
+#define SHARED_HW_CFG_LED_MAC3			    0x00080000
+#define SHARED_HW_CFG_LED_PHY7			    0x00090000
+#define SHARED_HW_CFG_LED_PHY9			    0x000a0000
+#define SHARED_HW_CFG_LED_PHY11 		    0x000b0000
+#define SHARED_HW_CFG_LED_MAC4			    0x000c0000
+#define SHARED_HW_CFG_LED_PHY8			    0x000d0000
+
+#define SHARED_HW_CFG_AN_ENABLE_MASK		    0x3f000000
+#define SHARED_HW_CFG_AN_ENABLE_SHIFT		    24
+#define SHARED_HW_CFG_AN_ENABLE_CL37		    0x01000000
+#define SHARED_HW_CFG_AN_ENABLE_CL73		    0x02000000
+#define SHARED_HW_CFG_AN_ENABLE_BAM		    0x04000000
+#define SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION  0x08000000
+#define SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT 0x10000000
+#define SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY	    0x20000000
+
+	u32 config2;						/* 0x118 */
+	/* one time auto detect grace period (in sec) */
+#define SHARED_HW_CFG_GRACE_PERIOD_MASK 	    0x000000ff
+#define SHARED_HW_CFG_GRACE_PERIOD_SHIFT	    0
+
+#define SHARED_HW_CFG_PCIE_GEN2_ENABLED 	    0x00000100
+
+	/* The default value for the core clock is 250MHz and it is
+	   achieved by setting the clock change to 4 */
+#define SHARED_HW_CFG_CLOCK_CHANGE_MASK 	    0x00000e00
+#define SHARED_HW_CFG_CLOCK_CHANGE_SHIFT	    9
+
+#define SHARED_HW_CFG_SMBUS_TIMING_100KHZ	    0x00000000
+#define SHARED_HW_CFG_SMBUS_TIMING_400KHZ	    0x00001000
+
+#define SHARED_HW_CFG_HIDE_FUNC1		    0x00002000
+
+	u32 power_dissipated;					/* 0x11c */
+#define SHARED_HW_CFG_POWER_DIS_CMN_MASK	    0xff000000
+#define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT	    24
+
+#define SHARED_HW_CFG_POWER_MGNT_SCALE_MASK	    0x00ff0000
+#define SHARED_HW_CFG_POWER_MGNT_SCALE_SHIFT	    16
+#define SHARED_HW_CFG_POWER_MGNT_UNKNOWN_SCALE	    0x00000000
+#define SHARED_HW_CFG_POWER_MGNT_DOT_1_WATT	    0x00010000
+#define SHARED_HW_CFG_POWER_MGNT_DOT_01_WATT	    0x00020000
+#define SHARED_HW_CFG_POWER_MGNT_DOT_001_WATT	    0x00030000
+
+	u32 ump_nc_si_config;					/* 0x120 */
+#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_MASK	    0x00000003
+#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_SHIFT	    0
+#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_MAC	    0x00000000
+#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_PHY	    0x00000001
+#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_MII	    0x00000000
+#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_RMII	    0x00000002
+
+#define SHARED_HW_CFG_UMP_NC_SI_NUM_DEVS_MASK	    0x00000f00
+#define SHARED_HW_CFG_UMP_NC_SI_NUM_DEVS_SHIFT	    8
+
+#define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_MASK   0x00ff0000
+#define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_SHIFT  16
+#define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_NONE   0x00000000
+#define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_BCM5221 0x00010000
+
+	u32 board;						/* 0x124 */
+#define SHARED_HW_CFG_BOARD_TYPE_MASK		    0x0000ffff
+#define SHARED_HW_CFG_BOARD_TYPE_SHIFT		    0
+#define SHARED_HW_CFG_BOARD_TYPE_NONE		    0x00000000
+#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1000     0x00000001
+#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1001     0x00000002
+#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1002G    0x00000003
+#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1004G    0x00000004
+#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1007G    0x00000005
+#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1015G    0x00000006
+#define SHARED_HW_CFG_BOARD_TYPE_BCM957710A1020G    0x00000007
+#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1003G    0x00000008
+
+#define SHARED_HW_CFG_BOARD_VER_MASK		    0xffff0000
+#define SHARED_HW_CFG_BOARD_VER_SHIFT		    16
+#define SHARED_HW_CFG_BOARD_MAJOR_VER_MASK	    0xf0000000
+#define SHARED_HW_CFG_BOARD_MAJOR_VER_SHIFT	    28
+#define SHARED_HW_CFG_BOARD_MINOR_VER_MASK	    0x0f000000
+#define SHARED_HW_CFG_BOARD_MINOR_VER_SHIFT	    24
+#define SHARED_HW_CFG_BOARD_REV_MASK		    0x00ff0000
+#define SHARED_HW_CFG_BOARD_REV_SHIFT		    16
+
+	u32 reserved;						/* 0x128 */
+
+};
+
+/****************************************************************************
+ * Port HW configuration						    *
+ ****************************************************************************/
+struct port_hw_cfg {	/* function 0: 0x12c-0x2bb, function 1: 0x2bc-0x44b */
+
+	/* Fields below are port specific (in anticipation of dual port
+	   devices */
+	u32 pci_id;
+#define PORT_HW_CFG_PCI_VENDOR_ID_MASK		    0xffff0000
+#define PORT_HW_CFG_PCI_DEVICE_ID_MASK		    0x0000ffff
+
+	u32 pci_sub_id;
+#define PORT_HW_CFG_PCI_SUBSYS_DEVICE_ID_MASK	    0xffff0000
+#define PORT_HW_CFG_PCI_SUBSYS_VENDOR_ID_MASK	    0x0000ffff
+
+	u32 power_dissipated;
+#define PORT_HW_CFG_POWER_DIS_D3_MASK		    0xff000000
+#define PORT_HW_CFG_POWER_DIS_D3_SHIFT		    24
+#define PORT_HW_CFG_POWER_DIS_D2_MASK		    0x00ff0000
+#define PORT_HW_CFG_POWER_DIS_D2_SHIFT		    16
+#define PORT_HW_CFG_POWER_DIS_D1_MASK		    0x0000ff00
+#define PORT_HW_CFG_POWER_DIS_D1_SHIFT		    8
+#define PORT_HW_CFG_POWER_DIS_D0_MASK		    0x000000ff
+#define PORT_HW_CFG_POWER_DIS_D0_SHIFT		    0
+
+	u32 power_consumed;
+#define PORT_HW_CFG_POWER_CONS_D3_MASK		    0xff000000
+#define PORT_HW_CFG_POWER_CONS_D3_SHIFT 	    24
+#define PORT_HW_CFG_POWER_CONS_D2_MASK		    0x00ff0000
+#define PORT_HW_CFG_POWER_CONS_D2_SHIFT 	    16
+#define PORT_HW_CFG_POWER_CONS_D1_MASK		    0x0000ff00
+#define PORT_HW_CFG_POWER_CONS_D1_SHIFT 	    8
+#define PORT_HW_CFG_POWER_CONS_D0_MASK		    0x000000ff
+#define PORT_HW_CFG_POWER_CONS_D0_SHIFT 	    0
+
+	u32 mac_upper;
+#define PORT_HW_CFG_UPPERMAC_MASK		    0x0000ffff
+#define PORT_HW_CFG_UPPERMAC_SHIFT		    0
+	u32 mac_lower;
+
+	u32 iscsi_mac_upper;  /* Upper 16 bits are always zeroes */
+	u32 iscsi_mac_lower;
+
+	u32 rdma_mac_upper;   /* Upper 16 bits are always zeroes */
+	u32 rdma_mac_lower;
+
+	u32 serdes_config;
+	/* for external PHY, or forced mode or during AN */
+#define PORT_HW_CFG_SERDES_TX_DRV_PRE_EMPHASIS_MASK 0xffff0000
+#define PORT_HW_CFG_SERDES_TX_DRV_PRE_EMPHASIS_SHIFT  16
+
+#define PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK    0x0000ffff
+#define PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT   0
+
+	u16 serdes_tx_driver_pre_emphasis[16];
+	u16 serdes_rx_driver_equalizer[16];
+
+	u32 xgxs_config_lane0;
+	u32 xgxs_config_lane1;
+	u32 xgxs_config_lane2;
+	u32 xgxs_config_lane3;
+	/* for external PHY, or forced mode or during AN */
+#define PORT_HW_CFG_XGXS_TX_DRV_PRE_EMPHASIS_MASK   0xffff0000
+#define PORT_HW_CFG_XGXS_TX_DRV_PRE_EMPHASIS_SHIFT  16
+
+#define PORT_HW_CFG_XGXS_RX_DRV_EQUALIZER_MASK	    0x0000ffff
+#define PORT_HW_CFG_XGXS_RX_DRV_EQUALIZER_SHIFT     0
+
+	u16 xgxs_tx_driver_pre_emphasis_lane0[16];
+	u16 xgxs_tx_driver_pre_emphasis_lane1[16];
+	u16 xgxs_tx_driver_pre_emphasis_lane2[16];
+	u16 xgxs_tx_driver_pre_emphasis_lane3[16];
+
+	u16 xgxs_rx_driver_equalizer_lane0[16];
+	u16 xgxs_rx_driver_equalizer_lane1[16];
+	u16 xgxs_rx_driver_equalizer_lane2[16];
+	u16 xgxs_rx_driver_equalizer_lane3[16];
+
+	u32 lane_config;
+#define PORT_HW_CFG_LANE_SWAP_CFG_MASK		    0x0000ffff
+#define PORT_HW_CFG_LANE_SWAP_CFG_SHIFT 	    0
+#define PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK	    0x000000ff
+#define PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT	    0
+#define PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK	    0x0000ff00
+#define PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT	    8
+#define PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK	    0x0000c000
+#define PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT	    14
+	/* AN and forced */
+#define PORT_HW_CFG_LANE_SWAP_CFG_01230123	    0x00001b1b
+	/* forced only */
+#define PORT_HW_CFG_LANE_SWAP_CFG_01233210	    0x00001be4
+	/* forced only */
+#define PORT_HW_CFG_LANE_SWAP_CFG_31203120	    0x0000d8d8
+	/* forced only */
+#define PORT_HW_CFG_LANE_SWAP_CFG_32103210	    0x0000e4e4
+
+	u32 external_phy_config;
+#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK	    0xff000000
+#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_SHIFT	    24
+#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT	    0x00000000
+#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482     0x01000000
+#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN    0xff000000
+
+#define PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK	    0x00ff0000
+#define PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT	    16
+
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK	    0x0000ff00
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SHIFT	    8
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT	    0x00000000
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8071	    0x00000100
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072	    0x00000200
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073	    0x00000300
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705	    0x00000400
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706	    0x00000500
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8276	    0x00000600
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481	    0x00000700
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN	    0x0000ff00
+
+#define PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK	    0x000000ff
+#define PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT	    0
+
+	u32 speed_capability_mask;
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_MASK	    0xffff0000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_SHIFT	    16
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL    0x00010000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF    0x00020000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF   0x00040000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL   0x00080000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_1G	    0x00100000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G	    0x00200000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_10G	    0x00400000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_12G	    0x00800000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_12_5G	    0x01000000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_13G	    0x02000000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_15G	    0x04000000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_16G	    0x08000000
+#define PORT_HW_CFG_SPEED_CAPABILITY_D0_RESERVED    0xf0000000
+
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_MASK	    0x0000ffff
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_SHIFT	    0
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_10M_FULL    0x00000001
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_10M_HALF    0x00000002
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_100M_HALF   0x00000004
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_100M_FULL   0x00000008
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_1G	    0x00000010
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_2_5G	    0x00000020
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_10G	    0x00000040
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_12G	    0x00000080
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_12_5G	    0x00000100
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_13G	    0x00000200
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_15G	    0x00000400
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_16G	    0x00000800
+#define PORT_HW_CFG_SPEED_CAPABILITY_D3_RESERVED    0x0000f000
+
+	u32 reserved[2];
+
+};
+
+/****************************************************************************
+ * Shared Feature configuration 					    *
+ ****************************************************************************/
+struct shared_feat_cfg {				 /* NVRAM Offset */
+	u32 bmc_common; 					/* 0x450 */
+#define SHARED_FEATURE_BMC_ECHO_MODE_EN 	    0x00000001
+
+};
+
+
+/****************************************************************************
+ * Port Feature configuration						    *
+ ****************************************************************************/
+struct port_feat_cfg {	/* function 0: 0x454-0x4c7, function 1: 0x4c8-0x53b */
+	u32 config;
+#define PORT_FEATURE_BAR1_SIZE_MASK		    0x0000000f
+#define PORT_FEATURE_BAR1_SIZE_SHIFT		    0
+#define PORT_FEATURE_BAR1_SIZE_DISABLED 	    0x00000000
+#define PORT_FEATURE_BAR1_SIZE_64K		    0x00000001
+#define PORT_FEATURE_BAR1_SIZE_128K		    0x00000002
+#define PORT_FEATURE_BAR1_SIZE_256K		    0x00000003
+#define PORT_FEATURE_BAR1_SIZE_512K		    0x00000004
+#define PORT_FEATURE_BAR1_SIZE_1M		    0x00000005
+#define PORT_FEATURE_BAR1_SIZE_2M		    0x00000006
+#define PORT_FEATURE_BAR1_SIZE_4M		    0x00000007
+#define PORT_FEATURE_BAR1_SIZE_8M		    0x00000008
+#define PORT_FEATURE_BAR1_SIZE_16M		    0x00000009
+#define PORT_FEATURE_BAR1_SIZE_32M		    0x0000000a
+#define PORT_FEATURE_BAR1_SIZE_64M		    0x0000000b
+#define PORT_FEATURE_BAR1_SIZE_128M		    0x0000000c
+#define PORT_FEATURE_BAR1_SIZE_256M		    0x0000000d
+#define PORT_FEATURE_BAR1_SIZE_512M		    0x0000000e
+#define PORT_FEATURE_BAR1_SIZE_1G		    0x0000000f
+#define PORT_FEATURE_BAR2_SIZE_MASK		    0x000000f0
+#define PORT_FEATURE_BAR2_SIZE_SHIFT		    4
+#define PORT_FEATURE_BAR2_SIZE_DISABLED 	    0x00000000
+#define PORT_FEATURE_BAR2_SIZE_64K		    0x00000010
+#define PORT_FEATURE_BAR2_SIZE_128K		    0x00000020
+#define PORT_FEATURE_BAR2_SIZE_256K		    0x00000030
+#define PORT_FEATURE_BAR2_SIZE_512K		    0x00000040
+#define PORT_FEATURE_BAR2_SIZE_1M		    0x00000050
+#define PORT_FEATURE_BAR2_SIZE_2M		    0x00000060
+#define PORT_FEATURE_BAR2_SIZE_4M		    0x00000070
+#define PORT_FEATURE_BAR2_SIZE_8M		    0x00000080
+#define PORT_FEATURE_BAR2_SIZE_16M		    0x00000090
+#define PORT_FEATURE_BAR2_SIZE_32M		    0x000000a0
+#define PORT_FEATURE_BAR2_SIZE_64M		    0x000000b0
+#define PORT_FEATURE_BAR2_SIZE_128M		    0x000000c0
+#define PORT_FEATURE_BAR2_SIZE_256M		    0x000000d0
+#define PORT_FEATURE_BAR2_SIZE_512M		    0x000000e0
+#define PORT_FEATURE_BAR2_SIZE_1G		    0x000000f0
+#define PORT_FEATURE_EN_SIZE_MASK		    0x07000000
+#define PORT_FEATURE_EN_SIZE_SHIFT		    24
+#define PORT_FEATURE_WOL_ENABLED		    0x01000000
+#define PORT_FEATURE_MBA_ENABLED		    0x02000000
+#define PORT_FEATURE_MFW_ENABLED		    0x04000000
+
+	u32 wol_config;
+	/* Default is used when driver sets to "auto" mode */
+#define PORT_FEATURE_WOL_DEFAULT_MASK		    0x00000003
+#define PORT_FEATURE_WOL_DEFAULT_SHIFT		    0
+#define PORT_FEATURE_WOL_DEFAULT_DISABLE	    0x00000000
+#define PORT_FEATURE_WOL_DEFAULT_MAGIC		    0x00000001
+#define PORT_FEATURE_WOL_DEFAULT_ACPI		    0x00000002
+#define PORT_FEATURE_WOL_DEFAULT_MAGIC_AND_ACPI     0x00000003
+#define PORT_FEATURE_WOL_RES_PAUSE_CAP		    0x00000004
+#define PORT_FEATURE_WOL_RES_ASYM_PAUSE_CAP	    0x00000008
+#define PORT_FEATURE_WOL_ACPI_UPON_MGMT 	    0x00000010
+
+	u32 mba_config;
+#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_MASK	    0x00000003
+#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_SHIFT	    0
+#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_PXE	    0x00000000
+#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_RPL	    0x00000001
+#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_BOOTP	    0x00000002
+#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_ISCSIB     0x00000003
+#define PORT_FEATURE_MBA_RES_PAUSE_CAP		    0x00000100
+#define PORT_FEATURE_MBA_RES_ASYM_PAUSE_CAP	    0x00000200
+#define PORT_FEATURE_MBA_SETUP_PROMPT_ENABLE	    0x00000400
+#define PORT_FEATURE_MBA_HOTKEY_CTRL_S		    0x00000000
+#define PORT_FEATURE_MBA_HOTKEY_CTRL_B		    0x00000800
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_MASK	    0x000ff000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_SHIFT	    12
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_DISABLED	    0x00000000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_2K	    0x00001000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_4K	    0x00002000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_8K	    0x00003000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_16K	    0x00004000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_32K	    0x00005000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_64K	    0x00006000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_128K	    0x00007000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_256K	    0x00008000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_512K	    0x00009000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_1M	    0x0000a000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_2M	    0x0000b000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_4M	    0x0000c000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_8M	    0x0000d000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_16M	    0x0000e000
+#define PORT_FEATURE_MBA_EXP_ROM_SIZE_32M	    0x0000f000
+#define PORT_FEATURE_MBA_MSG_TIMEOUT_MASK	    0x00f00000
+#define PORT_FEATURE_MBA_MSG_TIMEOUT_SHIFT	    20
+#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_MASK	    0x03000000
+#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_SHIFT	    24
+#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_AUTO	    0x00000000
+#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_BBS	    0x01000000
+#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_INT18H	    0x02000000
+#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_INT19H	    0x03000000
+#define PORT_FEATURE_MBA_LINK_SPEED_MASK	    0x3c000000
+#define PORT_FEATURE_MBA_LINK_SPEED_SHIFT	    26
+#define PORT_FEATURE_MBA_LINK_SPEED_AUTO	    0x00000000
+#define PORT_FEATURE_MBA_LINK_SPEED_10HD	    0x04000000
+#define PORT_FEATURE_MBA_LINK_SPEED_10FD	    0x08000000
+#define PORT_FEATURE_MBA_LINK_SPEED_100HD	    0x0c000000
+#define PORT_FEATURE_MBA_LINK_SPEED_100FD	    0x10000000
+#define PORT_FEATURE_MBA_LINK_SPEED_1GBPS	    0x14000000
+#define PORT_FEATURE_MBA_LINK_SPEED_2_5GBPS	    0x18000000
+#define PORT_FEATURE_MBA_LINK_SPEED_10GBPS_CX4	    0x1c000000
+#define PORT_FEATURE_MBA_LINK_SPEED_10GBPS_KX4	    0x20000000
+#define PORT_FEATURE_MBA_LINK_SPEED_10GBPS_KR	    0x24000000
+#define PORT_FEATURE_MBA_LINK_SPEED_12GBPS	    0x28000000
+#define PORT_FEATURE_MBA_LINK_SPEED_12_5GBPS	    0x2c000000
+#define PORT_FEATURE_MBA_LINK_SPEED_13GBPS	    0x30000000
+#define PORT_FEATURE_MBA_LINK_SPEED_15GBPS	    0x34000000
+#define PORT_FEATURE_MBA_LINK_SPEED_16GBPS	    0x38000000
+
+	u32 bmc_config;
+#define PORT_FEATURE_BMC_LINK_OVERRIDE_DEFAULT	    0x00000000
+#define PORT_FEATURE_BMC_LINK_OVERRIDE_EN	    0x00000001
+
+	u32 mba_vlan_cfg;
+#define PORT_FEATURE_MBA_VLAN_TAG_MASK		    0x0000ffff
+#define PORT_FEATURE_MBA_VLAN_TAG_SHIFT 	    0
+#define PORT_FEATURE_MBA_VLAN_EN		    0x00010000
+
+	u32 resource_cfg;
+#define PORT_FEATURE_RESOURCE_CFG_VALID 	    0x00000001
+#define PORT_FEATURE_RESOURCE_CFG_DIAG		    0x00000002
+#define PORT_FEATURE_RESOURCE_CFG_L2		    0x00000004
+#define PORT_FEATURE_RESOURCE_CFG_ISCSI 	    0x00000008
+#define PORT_FEATURE_RESOURCE_CFG_RDMA		    0x00000010
+
+	u32 smbus_config;
+	/* Obsolete */
+#define PORT_FEATURE_SMBUS_EN			    0x00000001
+#define PORT_FEATURE_SMBUS_ADDR_MASK		    0x000000fe
+#define PORT_FEATURE_SMBUS_ADDR_SHIFT		    1
+
+	u32 iscsib_boot_cfg;
+#define PORT_FEATURE_ISCSIB_SKIP_TARGET_BOOT	    0x00000001
+
+	u32 link_config;    /* Used as HW defaults for the driver */
+#define PORT_FEATURE_CONNECTED_SWITCH_MASK	    0x03000000
+#define PORT_FEATURE_CONNECTED_SWITCH_SHIFT	    24
+	/* (forced) low speed switch (< 10G) */
+#define PORT_FEATURE_CON_SWITCH_1G_SWITCH	    0x00000000
+	/* (forced) high speed switch (>= 10G) */
+#define PORT_FEATURE_CON_SWITCH_10G_SWITCH	    0x01000000
+#define PORT_FEATURE_CON_SWITCH_AUTO_DETECT	    0x02000000
+#define PORT_FEATURE_CON_SWITCH_ONE_TIME_DETECT     0x03000000
+
+#define PORT_FEATURE_LINK_SPEED_MASK		    0x000f0000
+#define PORT_FEATURE_LINK_SPEED_SHIFT		    16
+#define PORT_FEATURE_LINK_SPEED_AUTO		    0x00000000
+#define PORT_FEATURE_LINK_SPEED_10M_FULL	    0x00010000
+#define PORT_FEATURE_LINK_SPEED_10M_HALF	    0x00020000
+#define PORT_FEATURE_LINK_SPEED_100M_HALF	    0x00030000
+#define PORT_FEATURE_LINK_SPEED_100M_FULL	    0x00040000
+#define PORT_FEATURE_LINK_SPEED_1G		    0x00050000
+#define PORT_FEATURE_LINK_SPEED_2_5G		    0x00060000
+#define PORT_FEATURE_LINK_SPEED_10G_CX4 	    0x00070000
+#define PORT_FEATURE_LINK_SPEED_10G_KX4 	    0x00080000
+#define PORT_FEATURE_LINK_SPEED_10G_KR		    0x00090000
+#define PORT_FEATURE_LINK_SPEED_12G		    0x000a0000
+#define PORT_FEATURE_LINK_SPEED_12_5G		    0x000b0000
+#define PORT_FEATURE_LINK_SPEED_13G		    0x000c0000
+#define PORT_FEATURE_LINK_SPEED_15G		    0x000d0000
+#define PORT_FEATURE_LINK_SPEED_16G		    0x000e0000
+
+#define PORT_FEATURE_FLOW_CONTROL_MASK		    0x00000700
+#define PORT_FEATURE_FLOW_CONTROL_SHIFT 	    8
+#define PORT_FEATURE_FLOW_CONTROL_AUTO		    0x00000000
+#define PORT_FEATURE_FLOW_CONTROL_TX		    0x00000100
+#define PORT_FEATURE_FLOW_CONTROL_RX		    0x00000200
+#define PORT_FEATURE_FLOW_CONTROL_BOTH		    0x00000300
+#define PORT_FEATURE_FLOW_CONTROL_NONE		    0x00000400
+
+	/* The default for MCP link configuration,
+	   uses the same defines as link_config */
+	u32 mfw_wol_link_cfg;
+
+	u32 reserved[19];
+
+};
+
+
+/****************************************************************************
+ * Device Information							    *
+ ****************************************************************************/
+struct dev_info {						    /* size */
+
+	u32    bc_rev; /* 8 bits each: major, minor, build */	       /* 4 */
+
+	struct shared_hw_cfg	 shared_hw_config;		      /* 40 */
+
+	struct port_hw_cfg	 port_hw_config[FUNC_MAX];     /* 400*2=800 */
+
+	struct shared_feat_cfg	 shared_feature_config; 	       /* 4 */
+
+	struct port_feat_cfg	 port_feature_config[FUNC_MAX];/* 116*2=232 */
+
+};
+
+
+/****************************************************************************
+ * Management firmware state						    *
+ ****************************************************************************/
+/* Allocate 320 bytes for management firmware: still not known exactly
+ * how much IMD needs. */
+#define MGMTFW_STATE_WORD_SIZE				    80
+
+struct mgmtfw_state {
+	u32 opaque[MGMTFW_STATE_WORD_SIZE];
+};
+
+
+/****************************************************************************
+ * Shared Memory Region 						    *
+ ****************************************************************************/
+struct shmem_region {			       /*   SharedMem Offset (size) */
+	u32		    validity_map[FUNC_MAX];    /* 0x0 (4 * 2 = 0x8) */
+#define SHR_MEM_VALIDITY_PCI_CFG		    0x00000001
+#define SHR_MEM_VALIDITY_MB			    0x00000002
+#define SHR_MEM_VALIDITY_DEV_INFO		    0x00000004
+	/* One licensing bit should be set */
+#define SHR_MEM_VALIDITY_LIC_KEY_IN_EFFECT_MASK     0x00000038
+#define SHR_MEM_VALIDITY_LIC_MANUF_KEY_IN_EFFECT    0x00000008
+#define SHR_MEM_VALIDITY_LIC_UPGRADE_KEY_IN_EFFECT  0x00000010
+#define SHR_MEM_VALIDITY_LIC_NO_KEY_IN_EFFECT	    0x00000020
+
+	struct drv_fw_mb    drv_fw_mb[FUNC_MAX];     /* 0x8 (28 * 2 = 0x38) */
+
+	struct dev_info     dev_info;			    /* 0x40 (0x438) */
+
+#ifdef _LICENSE_H
+	license_key_t	    drv_lic_key[FUNC_MAX]; /* 0x478 (52 * 2 = 0x68) */
+#else /* Linux! */
+	u8		    reserved[52*FUNC_MAX];
+#endif
+
+	/* FW information (for internal FW use) */
+	u32		    fw_info_fio_offset; 	   /* 0x4e0 (0x4)   */
+	struct mgmtfw_state mgmtfw_state;		   /* 0x4e4 (0x140) */
+
+};							   /* 0x624 */
+
+
+#define BCM_5710_FW_MAJOR_VERSION			4
+#define BCM_5710_FW_MINOR_VERSION			0
+#define BCM_5710_FW_REVISION_VERSION			14
+#define BCM_5710_FW_COMPILE_FLAGS			1
+
+
+/*
+ * attention bits
+ */
+struct atten_def_status_block {
+	u32 attn_bits;
+	u32 attn_bits_ack;
+#if defined(__BIG_ENDIAN)
+	u16 attn_bits_index;
+	u8 reserved0;
+	u8 status_block_id;
+#elif defined(__LITTLE_ENDIAN)
+	u8 status_block_id;
+	u8 reserved0;
+	u16 attn_bits_index;
+#endif
+	u32 reserved1;
+};
+
+
+/*
+ * common data for all protocols
+ */
+struct doorbell_hdr {
+	u8 header;
+#define DOORBELL_HDR_RX (0x1<<0)
+#define DOORBELL_HDR_RX_SHIFT 0
+#define DOORBELL_HDR_DB_TYPE (0x1<<1)
+#define DOORBELL_HDR_DB_TYPE_SHIFT 1
+#define DOORBELL_HDR_DPM_SIZE (0x3<<2)
+#define DOORBELL_HDR_DPM_SIZE_SHIFT 2
+#define DOORBELL_HDR_CONN_TYPE (0xF<<4)
+#define DOORBELL_HDR_CONN_TYPE_SHIFT 4
+};
+
+/*
+ * doorbell message send to the chip
+ */
+struct doorbell {
+#if defined(__BIG_ENDIAN)
+	u16 zero_fill2;
+	u8 zero_fill1;
+	struct doorbell_hdr header;
+#elif defined(__LITTLE_ENDIAN)
+	struct doorbell_hdr header;
+	u8 zero_fill1;
+	u16 zero_fill2;
+#endif
+};
+
+
+/*
+ * IGU driver acknowlegement register
+ */
+struct igu_ack_register {
+#if defined(__BIG_ENDIAN)
+	u16 sb_id_and_flags;
+#define IGU_ACK_REGISTER_STATUS_BLOCK_ID (0x1F<<0)
+#define IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT 0
+#define IGU_ACK_REGISTER_STORM_ID (0x7<<5)
+#define IGU_ACK_REGISTER_STORM_ID_SHIFT 5
+#define IGU_ACK_REGISTER_UPDATE_INDEX (0x1<<8)
+#define IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT 8
+#define IGU_ACK_REGISTER_INTERRUPT_MODE (0x3<<9)
+#define IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT 9
+#define IGU_ACK_REGISTER_RESERVED (0x1F<<11)
+#define IGU_ACK_REGISTER_RESERVED_SHIFT 11
+	u16 status_block_index;
+#elif defined(__LITTLE_ENDIAN)
+	u16 status_block_index;
+	u16 sb_id_and_flags;
+#define IGU_ACK_REGISTER_STATUS_BLOCK_ID (0x1F<<0)
+#define IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT 0
+#define IGU_ACK_REGISTER_STORM_ID (0x7<<5)
+#define IGU_ACK_REGISTER_STORM_ID_SHIFT 5
+#define IGU_ACK_REGISTER_UPDATE_INDEX (0x1<<8)
+#define IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT 8
+#define IGU_ACK_REGISTER_INTERRUPT_MODE (0x3<<9)
+#define IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT 9
+#define IGU_ACK_REGISTER_RESERVED (0x1F<<11)
+#define IGU_ACK_REGISTER_RESERVED_SHIFT 11
+#endif
+};
+
+
+/*
+ * Parser parsing flags field
+ */
+struct parsing_flags {
+	u16 flags;
+#define PARSING_FLAGS_ETHERNET_ADDRESS_TYPE (0x1<<0)
+#define PARSING_FLAGS_ETHERNET_ADDRESS_TYPE_SHIFT 0
+#define PARSING_FLAGS_NUMBER_OF_NESTED_VLANS (0x3<<1)
+#define PARSING_FLAGS_NUMBER_OF_NESTED_VLANS_SHIFT 1
+#define PARSING_FLAGS_OVER_ETHERNET_PROTOCOL (0x3<<3)
+#define PARSING_FLAGS_OVER_ETHERNET_PROTOCOL_SHIFT 3
+#define PARSING_FLAGS_IP_OPTIONS (0x1<<5)
+#define PARSING_FLAGS_IP_OPTIONS_SHIFT 5
+#define PARSING_FLAGS_FRAGMENTATION_STATUS (0x1<<6)
+#define PARSING_FLAGS_FRAGMENTATION_STATUS_SHIFT 6
+#define PARSING_FLAGS_OVER_IP_PROTOCOL (0x3<<7)
+#define PARSING_FLAGS_OVER_IP_PROTOCOL_SHIFT 7
+#define PARSING_FLAGS_PURE_ACK_INDICATION (0x1<<9)
+#define PARSING_FLAGS_PURE_ACK_INDICATION_SHIFT 9
+#define PARSING_FLAGS_TCP_OPTIONS_EXIST (0x1<<10)
+#define PARSING_FLAGS_TCP_OPTIONS_EXIST_SHIFT 10
+#define PARSING_FLAGS_TIME_STAMP_EXIST_FLAG (0x1<<11)
+#define PARSING_FLAGS_TIME_STAMP_EXIST_FLAG_SHIFT 11
+#define PARSING_FLAGS_CONNECTION_MATCH (0x1<<12)
+#define PARSING_FLAGS_CONNECTION_MATCH_SHIFT 12
+#define PARSING_FLAGS_LLC_SNAP (0x1<<13)
+#define PARSING_FLAGS_LLC_SNAP_SHIFT 13
+#define PARSING_FLAGS_RESERVED0 (0x3<<14)
+#define PARSING_FLAGS_RESERVED0_SHIFT 14
+};
+
+
+/*
+ * dmae command structure
+ */
+struct dmae_command {
+	u32 opcode;
+#define DMAE_COMMAND_SRC (0x1<<0)
+#define DMAE_COMMAND_SRC_SHIFT 0
+#define DMAE_COMMAND_DST (0x3<<1)
+#define DMAE_COMMAND_DST_SHIFT 1
+#define DMAE_COMMAND_C_DST (0x1<<3)
+#define DMAE_COMMAND_C_DST_SHIFT 3
+#define DMAE_COMMAND_C_TYPE_ENABLE (0x1<<4)
+#define DMAE_COMMAND_C_TYPE_ENABLE_SHIFT 4
+#define DMAE_COMMAND_C_TYPE_CRC_ENABLE (0x1<<5)
+#define DMAE_COMMAND_C_TYPE_CRC_ENABLE_SHIFT 5
+#define DMAE_COMMAND_C_TYPE_CRC_OFFSET (0x7<<6)
+#define DMAE_COMMAND_C_TYPE_CRC_OFFSET_SHIFT 6
+#define DMAE_COMMAND_ENDIANITY (0x3<<9)
+#define DMAE_COMMAND_ENDIANITY_SHIFT 9
+#define DMAE_COMMAND_PORT (0x1<<11)
+#define DMAE_COMMAND_PORT_SHIFT 11
+#define DMAE_COMMAND_CRC_RESET (0x1<<12)
+#define DMAE_COMMAND_CRC_RESET_SHIFT 12
+#define DMAE_COMMAND_SRC_RESET (0x1<<13)
+#define DMAE_COMMAND_SRC_RESET_SHIFT 13
+#define DMAE_COMMAND_DST_RESET (0x1<<14)
+#define DMAE_COMMAND_DST_RESET_SHIFT 14
+#define DMAE_COMMAND_RESERVED0 (0x1FFFF<<15)
+#define DMAE_COMMAND_RESERVED0_SHIFT 15
+	u32 src_addr_lo;
+	u32 src_addr_hi;
+	u32 dst_addr_lo;
+	u32 dst_addr_hi;
+#if defined(__BIG_ENDIAN)
+	u16 reserved1;
+	u16 len;
+#elif defined(__LITTLE_ENDIAN)
+	u16 len;
+	u16 reserved1;
+#endif
+	u32 comp_addr_lo;
+	u32 comp_addr_hi;
+	u32 comp_val;
+	u32 crc32;
+	u32 crc32_c;
+#if defined(__BIG_ENDIAN)
+	u16 crc16_c;
+	u16 crc16;
+#elif defined(__LITTLE_ENDIAN)
+	u16 crc16;
+	u16 crc16_c;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 reserved2;
+	u16 crc_t10;
+#elif defined(__LITTLE_ENDIAN)
+	u16 crc_t10;
+	u16 reserved2;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 xsum8;
+	u16 xsum16;
+#elif defined(__LITTLE_ENDIAN)
+	u16 xsum16;
+	u16 xsum8;
+#endif
+};
+
+
+struct double_regpair {
+	u32 regpair0_lo;
+	u32 regpair0_hi;
+	u32 regpair1_lo;
+	u32 regpair1_hi;
+};
+
+
+/*
+ * The eth Rx Buffer Descriptor
+ */
+struct eth_rx_bd {
+	u32 addr_lo;
+	u32 addr_hi;
+};
+
+/*
+ * The eth storm context of Ustorm
+ */
+struct ustorm_eth_st_context {
+#if defined(__BIG_ENDIAN)
+	u8 sb_index_number;
+	u8 status_block_id;
+	u8 __local_rx_bd_cons;
+	u8 __local_rx_bd_prod;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __local_rx_bd_prod;
+	u8 __local_rx_bd_cons;
+	u8 status_block_id;
+	u8 sb_index_number;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 rcq_cons;
+	u16 rx_bd_cons;
+#elif defined(__LITTLE_ENDIAN)
+	u16 rx_bd_cons;
+	u16 rcq_cons;
+#endif
+	u32 rx_bd_page_base_lo;
+	u32 rx_bd_page_base_hi;
+	u32 rcq_base_address_lo;
+	u32 rcq_base_address_hi;
+#if defined(__BIG_ENDIAN)
+	u16 __num_of_returned_cqes;
+	u8 num_rss;
+	u8 flags;
+#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT (0x1<<0)
+#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT_SHIFT 0
+#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC (0x1<<1)
+#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC_SHIFT 1
+#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA (0x1<<2)
+#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA_SHIFT 2
+#define __USTORM_ETH_ST_CONTEXT_RESERVED0 (0x1F<<3)
+#define __USTORM_ETH_ST_CONTEXT_RESERVED0_SHIFT 3
+#elif defined(__LITTLE_ENDIAN)
+	u8 flags;
+#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT (0x1<<0)
+#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT_SHIFT 0
+#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC (0x1<<1)
+#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC_SHIFT 1
+#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA (0x1<<2)
+#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA_SHIFT 2
+#define __USTORM_ETH_ST_CONTEXT_RESERVED0 (0x1F<<3)
+#define __USTORM_ETH_ST_CONTEXT_RESERVED0_SHIFT 3
+	u8 num_rss;
+	u16 __num_of_returned_cqes;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 mc_alignment_size;
+	u16 agg_threshold;
+#elif defined(__LITTLE_ENDIAN)
+	u16 agg_threshold;
+	u16 mc_alignment_size;
+#endif
+	struct eth_rx_bd __local_bd_ring[16];
+};
+
+/*
+ * The eth storm context of Tstorm
+ */
+struct tstorm_eth_st_context {
+	u32 __reserved0[28];
+};
+
+/*
+ * The eth aggregative context section of Xstorm
+ */
+struct xstorm_eth_extra_ag_context_section {
+#if defined(__BIG_ENDIAN)
+	u8 __tcp_agg_vars1;
+	u8 __reserved50;
+	u16 __mss;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __mss;
+	u8 __reserved50;
+	u8 __tcp_agg_vars1;
+#endif
+	u32 __snd_nxt;
+	u32 __tx_wnd;
+	u32 __snd_una;
+	u32 __reserved53;
+#if defined(__BIG_ENDIAN)
+	u8 __agg_val8_th;
+	u8 __agg_val8;
+	u16 __tcp_agg_vars2;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __tcp_agg_vars2;
+	u8 __agg_val8;
+	u8 __agg_val8_th;
+#endif
+	u32 __reserved58;
+	u32 __reserved59;
+	u32 __reserved60;
+	u32 __reserved61;
+#if defined(__BIG_ENDIAN)
+	u16 __agg_val7_th;
+	u16 __agg_val7;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_val7;
+	u16 __agg_val7_th;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 __tcp_agg_vars5;
+	u8 __tcp_agg_vars4;
+	u8 __tcp_agg_vars3;
+	u8 __reserved62;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __reserved62;
+	u8 __tcp_agg_vars3;
+	u8 __tcp_agg_vars4;
+	u8 __tcp_agg_vars5;
+#endif
+	u32 __tcp_agg_vars6;
+#if defined(__BIG_ENDIAN)
+	u16 __agg_misc6;
+	u16 __tcp_agg_vars7;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __tcp_agg_vars7;
+	u16 __agg_misc6;
+#endif
+	u32 __agg_val10;
+	u32 __agg_val10_th;
+#if defined(__BIG_ENDIAN)
+	u16 __reserved3;
+	u8 __reserved2;
+	u8 __agg_misc7;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __agg_misc7;
+	u8 __reserved2;
+	u16 __reserved3;
+#endif
+};
+
+/*
+ * The eth aggregative context of Xstorm
+ */
+struct xstorm_eth_ag_context {
+#if defined(__BIG_ENDIAN)
+	u16 __bd_prod;
+	u8 __agg_vars1;
+	u8 __state;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __state;
+	u8 __agg_vars1;
+	u16 __bd_prod;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 cdu_reserved;
+	u8 __agg_vars4;
+	u8 __agg_vars3;
+	u8 __agg_vars2;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __agg_vars2;
+	u8 __agg_vars3;
+	u8 __agg_vars4;
+	u8 cdu_reserved;
+#endif
+	u32 __more_packets_to_send;
+#if defined(__BIG_ENDIAN)
+	u16 __agg_vars5;
+	u16 __agg_val4_th;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_val4_th;
+	u16 __agg_vars5;
+#endif
+	struct xstorm_eth_extra_ag_context_section __extra_section;
+#if defined(__BIG_ENDIAN)
+	u16 __agg_vars7;
+	u8 __agg_val3_th;
+	u8 __agg_vars6;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __agg_vars6;
+	u8 __agg_val3_th;
+	u16 __agg_vars7;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 __agg_val11_th;
+	u16 __agg_val11;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_val11;
+	u16 __agg_val11_th;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 __reserved1;
+	u8 __agg_val6_th;
+	u16 __agg_val9;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_val9;
+	u8 __agg_val6_th;
+	u8 __reserved1;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 __agg_val2_th;
+	u16 __agg_val2;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_val2;
+	u16 __agg_val2_th;
+#endif
+	u32 __agg_vars8;
+#if defined(__BIG_ENDIAN)
+	u16 __agg_misc0;
+	u16 __agg_val4;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_val4;
+	u16 __agg_misc0;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 __agg_val3;
+	u8 __agg_val6;
+	u8 __agg_val5_th;
+	u8 __agg_val5;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __agg_val5;
+	u8 __agg_val5_th;
+	u8 __agg_val6;
+	u8 __agg_val3;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 __agg_misc1;
+	u16 __bd_ind_max_val;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __bd_ind_max_val;
+	u16 __agg_misc1;
+#endif
+	u32 __reserved57;
+	u32 __agg_misc4;
+	u32 __agg_misc5;
+};
+
+/*
+ * The eth aggregative context section of Tstorm
+ */
+struct tstorm_eth_extra_ag_context_section {
+	u32 __agg_val1;
+#if defined(__BIG_ENDIAN)
+	u8 __tcp_agg_vars2;
+	u8 __agg_val3;
+	u16 __agg_val2;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_val2;
+	u8 __agg_val3;
+	u8 __tcp_agg_vars2;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 __agg_val5;
+	u8 __agg_val6;
+	u8 __tcp_agg_vars3;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __tcp_agg_vars3;
+	u8 __agg_val6;
+	u16 __agg_val5;
+#endif
+	u32 __reserved63;
+	u32 __reserved64;
+	u32 __reserved65;
+	u32 __reserved66;
+	u32 __reserved67;
+	u32 __tcp_agg_vars1;
+	u32 __reserved61;
+	u32 __reserved62;
+	u32 __reserved2;
+};
+
+/*
+ * The eth aggregative context of Tstorm
+ */
+struct tstorm_eth_ag_context {
+#if defined(__BIG_ENDIAN)
+	u16 __reserved54;
+	u8 __agg_vars1;
+	u8 __state;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __state;
+	u8 __agg_vars1;
+	u16 __reserved54;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 __agg_val4;
+	u16 __agg_vars2;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_vars2;
+	u16 __agg_val4;
+#endif
+	struct tstorm_eth_extra_ag_context_section __extra_section;
+};
+
+/*
+ * The eth aggregative context of Cstorm
+ */
+struct cstorm_eth_ag_context {
+	u32 __agg_vars1;
+#if defined(__BIG_ENDIAN)
+	u8 __aux1_th;
+	u8 __aux1_val;
+	u16 __agg_vars2;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_vars2;
+	u8 __aux1_val;
+	u8 __aux1_th;
+#endif
+	u32 __num_of_treated_packet;
+	u32 __last_packet_treated;
+#if defined(__BIG_ENDIAN)
+	u16 __reserved58;
+	u16 __reserved57;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __reserved57;
+	u16 __reserved58;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 __reserved62;
+	u8 __reserved61;
+	u8 __reserved60;
+	u8 __reserved59;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __reserved59;
+	u8 __reserved60;
+	u8 __reserved61;
+	u8 __reserved62;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 __reserved64;
+	u16 __reserved63;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __reserved63;
+	u16 __reserved64;
+#endif
+	u32 __reserved65;
+#if defined(__BIG_ENDIAN)
+	u16 __agg_vars3;
+	u16 __rq_inv_cnt;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __rq_inv_cnt;
+	u16 __agg_vars3;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 __packet_index_th;
+	u16 __packet_index;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __packet_index;
+	u16 __packet_index_th;
+#endif
+};
+
+/*
+ * The eth aggregative context of Ustorm
+ */
+struct ustorm_eth_ag_context {
+#if defined(__BIG_ENDIAN)
+	u8 __aux_counter_flags;
+	u8 __agg_vars2;
+	u8 __agg_vars1;
+	u8 __state;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __state;
+	u8 __agg_vars1;
+	u8 __agg_vars2;
+	u8 __aux_counter_flags;
+#endif
+#if defined(__BIG_ENDIAN)
+	u8 cdu_usage;
+	u8 __agg_misc2;
+	u16 __agg_misc1;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_misc1;
+	u8 __agg_misc2;
+	u8 cdu_usage;
+#endif
+	u32 __agg_misc4;
+#if defined(__BIG_ENDIAN)
+	u8 __agg_val3_th;
+	u8 __agg_val3;
+	u16 __agg_misc3;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_misc3;
+	u8 __agg_val3;
+	u8 __agg_val3_th;
+#endif
+	u32 __agg_val1;
+	u32 __agg_misc4_th;
+#if defined(__BIG_ENDIAN)
+	u16 __agg_val2_th;
+	u16 __agg_val2;
+#elif defined(__LITTLE_ENDIAN)
+	u16 __agg_val2;
+	u16 __agg_val2_th;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 __reserved2;
+	u8 __decision_rules;
+	u8 __decision_rule_enable_bits;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __decision_rule_enable_bits;
+	u8 __decision_rules;
+	u16 __reserved2;
+#endif
+};
+
+/*
+ * Timers connection context
+ */
+struct timers_block_context {
+	u32 __reserved_0;
+	u32 __reserved_1;
+	u32 __reserved_2;
+	u32 __reserved_flags;
+};
+
+/*
+ * structure for easy accessability to assembler
+ */
+struct eth_tx_bd_flags {
+	u8 as_bitfield;
+#define ETH_TX_BD_FLAGS_VLAN_TAG (0x1<<0)
+#define ETH_TX_BD_FLAGS_VLAN_TAG_SHIFT 0
+#define ETH_TX_BD_FLAGS_IP_CSUM (0x1<<1)
+#define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT 1
+#define ETH_TX_BD_FLAGS_TCP_CSUM (0x1<<2)
+#define ETH_TX_BD_FLAGS_TCP_CSUM_SHIFT 2
+#define ETH_TX_BD_FLAGS_END_BD (0x1<<3)
+#define ETH_TX_BD_FLAGS_END_BD_SHIFT 3
+#define ETH_TX_BD_FLAGS_START_BD (0x1<<4)
+#define ETH_TX_BD_FLAGS_START_BD_SHIFT 4
+#define ETH_TX_BD_FLAGS_HDR_POOL (0x1<<5)
+#define ETH_TX_BD_FLAGS_HDR_POOL_SHIFT 5
+#define ETH_TX_BD_FLAGS_SW_LSO (0x1<<6)
+#define ETH_TX_BD_FLAGS_SW_LSO_SHIFT 6
+#define ETH_TX_BD_FLAGS_IPV6 (0x1<<7)
+#define ETH_TX_BD_FLAGS_IPV6_SHIFT 7
+};
+
+/*
+ * The eth Tx Buffer Descriptor
+ */
+struct eth_tx_bd {
+	u32 addr_lo;
+	u32 addr_hi;
+	u16 nbd;
+	u16 nbytes;
+	u16 vlan;
+	struct eth_tx_bd_flags bd_flags;
+	u8 general_data;
+#define ETH_TX_BD_HDR_NBDS (0x3F<<0)
+#define ETH_TX_BD_HDR_NBDS_SHIFT 0
+#define ETH_TX_BD_ETH_ADDR_TYPE (0x3<<6)
+#define ETH_TX_BD_ETH_ADDR_TYPE_SHIFT 6
+};
+
+/*
+ * Tx parsing BD structure for ETH,Relevant in START
+ */
+struct eth_tx_parse_bd {
+	u8 global_data;
+#define ETH_TX_PARSE_BD_IP_HDR_START_OFFSET (0xF<<0)
+#define ETH_TX_PARSE_BD_IP_HDR_START_OFFSET_SHIFT 0
+#define ETH_TX_PARSE_BD_CS_ANY_FLG (0x1<<4)
+#define ETH_TX_PARSE_BD_CS_ANY_FLG_SHIFT 4
+#define ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN (0x1<<5)
+#define ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN_SHIFT 5
+#define ETH_TX_PARSE_BD_LLC_SNAP_EN (0x1<<6)
+#define ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT 6
+#define ETH_TX_PARSE_BD_NS_FLG (0x1<<7)
+#define ETH_TX_PARSE_BD_NS_FLG_SHIFT 7
+	u8 tcp_flags;
+#define ETH_TX_PARSE_BD_FIN_FLG (0x1<<0)
+#define ETH_TX_PARSE_BD_FIN_FLG_SHIFT 0
+#define ETH_TX_PARSE_BD_SYN_FLG (0x1<<1)
+#define ETH_TX_PARSE_BD_SYN_FLG_SHIFT 1
+#define ETH_TX_PARSE_BD_RST_FLG (0x1<<2)
+#define ETH_TX_PARSE_BD_RST_FLG_SHIFT 2
+#define ETH_TX_PARSE_BD_PSH_FLG (0x1<<3)
+#define ETH_TX_PARSE_BD_PSH_FLG_SHIFT 3
+#define ETH_TX_PARSE_BD_ACK_FLG (0x1<<4)
+#define ETH_TX_PARSE_BD_ACK_FLG_SHIFT 4
+#define ETH_TX_PARSE_BD_URG_FLG (0x1<<5)
+#define ETH_TX_PARSE_BD_URG_FLG_SHIFT 5
+#define ETH_TX_PARSE_BD_ECE_FLG (0x1<<6)
+#define ETH_TX_PARSE_BD_ECE_FLG_SHIFT 6
+#define ETH_TX_PARSE_BD_CWR_FLG (0x1<<7)
+#define ETH_TX_PARSE_BD_CWR_FLG_SHIFT 7
+	u8 ip_hlen;
+	s8 cs_offset;
+	u16 total_hlen;
+	u16 lso_mss;
+	u16 tcp_pseudo_csum;
+	u16 ip_id;
+	u32 tcp_send_seq;
+};
+
+/*
+ * The last BD in the BD memory will hold a pointer to the next BD memory
+ */
+struct eth_tx_next_bd {
+	u32 addr_lo;
+	u32 addr_hi;
+	u8 reserved[8];
+};
+
+/*
+ * union for 3 Bd types
+ */
+union eth_tx_bd_types {
+	struct eth_tx_bd reg_bd;
+	struct eth_tx_parse_bd parse_bd;
+	struct eth_tx_next_bd next_bd;
+};
+
+/*
+ * The eth storm context of Xstorm
+ */
+struct xstorm_eth_st_context {
+	u32 tx_bd_page_base_lo;
+	u32 tx_bd_page_base_hi;
+#if defined(__BIG_ENDIAN)
+	u16 tx_bd_cons;
+	u8 __reserved0;
+	u8 __local_tx_bd_prod;
+#elif defined(__LITTLE_ENDIAN)
+	u8 __local_tx_bd_prod;
+	u8 __reserved0;
+	u16 tx_bd_cons;
+#endif
+	u32 db_data_addr_lo;
+	u32 db_data_addr_hi;
+	u32 __pkt_cons;
+	u32 __gso_next;
+	u32 is_eth_conn_1b;
+	union eth_tx_bd_types __bds[13];
+};
+
+/*
+ * The eth storm context of Cstorm
+ */
+struct cstorm_eth_st_context {
+#if defined(__BIG_ENDIAN)
+	u16 __reserved0;
+	u8 sb_index_number;
+	u8 status_block_id;
+#elif defined(__LITTLE_ENDIAN)
+	u8 status_block_id;
+	u8 sb_index_number;
+	u16 __reserved0;
+#endif
+	u32 __reserved1[3];
+};
+
+/*
+ * Ethernet connection context
+ */
+struct eth_context {
+	struct ustorm_eth_st_context ustorm_st_context;
+	struct tstorm_eth_st_context tstorm_st_context;
+	struct xstorm_eth_ag_context xstorm_ag_context;
+	struct tstorm_eth_ag_context tstorm_ag_context;
+	struct cstorm_eth_ag_context cstorm_ag_context;
+	struct ustorm_eth_ag_context ustorm_ag_context;
+	struct timers_block_context timers_context;
+	struct xstorm_eth_st_context xstorm_st_context;
+	struct cstorm_eth_st_context cstorm_st_context;
+};
+
+
+/*
+ * ethernet doorbell
+ */
+struct eth_tx_doorbell {
+#if defined(__BIG_ENDIAN)
+	u16 npackets;
+	u8 params;
+#define ETH_TX_DOORBELL_NUM_BDS (0x3F<<0)
+#define ETH_TX_DOORBELL_NUM_BDS_SHIFT 0
+#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG (0x1<<6)
+#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG_SHIFT 6
+#define ETH_TX_DOORBELL_SPARE (0x1<<7)
+#define ETH_TX_DOORBELL_SPARE_SHIFT 7
+	struct doorbell_hdr hdr;
+#elif defined(__LITTLE_ENDIAN)
+	struct doorbell_hdr hdr;
+	u8 params;
+#define ETH_TX_DOORBELL_NUM_BDS (0x3F<<0)
+#define ETH_TX_DOORBELL_NUM_BDS_SHIFT 0
+#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG (0x1<<6)
+#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG_SHIFT 6
+#define ETH_TX_DOORBELL_SPARE (0x1<<7)
+#define ETH_TX_DOORBELL_SPARE_SHIFT 7
+	u16 npackets;
+#endif
+};
+
+
+/*
+ * ustorm status block
+ */
+struct ustorm_def_status_block {
+	u16 index_values[HC_USTORM_DEF_SB_NUM_INDICES];
+	u16 status_block_index;
+	u8 reserved0;
+	u8 status_block_id;
+	u32 __flags;
+};
+
+/*
+ * cstorm status block
+ */
+struct cstorm_def_status_block {
+	u16 index_values[HC_CSTORM_DEF_SB_NUM_INDICES];
+	u16 status_block_index;
+	u8 reserved0;
+	u8 status_block_id;
+	u32 __flags;
+};
+
+/*
+ * xstorm status block
+ */
+struct xstorm_def_status_block {
+	u16 index_values[HC_XSTORM_DEF_SB_NUM_INDICES];
+	u16 status_block_index;
+	u8 reserved0;
+	u8 status_block_id;
+	u32 __flags;
+};
+
+/*
+ * tstorm status block
+ */
+struct tstorm_def_status_block {
+	u16 index_values[HC_TSTORM_DEF_SB_NUM_INDICES];
+	u16 status_block_index;
+	u8 reserved0;
+	u8 status_block_id;
+	u32 __flags;
+};
+
+/*
+ * host status block
+ */
+struct host_def_status_block {
+	struct atten_def_status_block atten_status_block;
+	struct ustorm_def_status_block u_def_status_block;
+	struct cstorm_def_status_block c_def_status_block;
+	struct xstorm_def_status_block x_def_status_block;
+	struct tstorm_def_status_block t_def_status_block;
+};
+
+
+/*
+ * ustorm status block
+ */
+struct ustorm_status_block {
+	u16 index_values[HC_USTORM_SB_NUM_INDICES];
+	u16 status_block_index;
+	u8 reserved0;
+	u8 status_block_id;
+	u32 __flags;
+};
+
+/*
+ * cstorm status block
+ */
+struct cstorm_status_block {
+	u16 index_values[HC_CSTORM_SB_NUM_INDICES];
+	u16 status_block_index;
+	u8 reserved0;
+	u8 status_block_id;
+	u32 __flags;
+};
+
+/*
+ * host status block
+ */
+struct host_status_block {
+	struct ustorm_status_block u_status_block;
+	struct cstorm_status_block c_status_block;
+};
+
+
+/*
+ * The data for RSS setup ramrod
+ */
+struct eth_client_setup_ramrod_data {
+	u32 client_id_5b;
+	u8 is_rdma_1b;
+	u8 reserved0;
+	u16 reserved1;
+};
+
+
+/*
+ * L2 dynamic host coalescing init parameters
+ */
+struct eth_dynamic_hc_config {
+	u32 threshold[3];
+	u8 hc_timeout[4];
+};
+
+
+/*
+ * regular eth FP CQE parameters struct
+ */
+struct eth_fast_path_rx_cqe {
+	u8 type;
+	u8 error_type_flags;
+#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG (0x1<<0)
+#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_SHIFT 0
+#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG (0x1<<1)
+#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT 1
+#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG (0x1<<2)
+#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT 2
+#define ETH_FAST_PATH_RX_CQE_START_FLG (0x1<<3)
+#define ETH_FAST_PATH_RX_CQE_START_FLG_SHIFT 3
+#define ETH_FAST_PATH_RX_CQE_END_FLG (0x1<<4)
+#define ETH_FAST_PATH_RX_CQE_END_FLG_SHIFT 4
+#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x7<<5)
+#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 5
+	u8 status_flags;
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0)
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG (0x1<<3)
+#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG_SHIFT 3
+#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG (0x1<<4)
+#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG_SHIFT 4
+#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG (0x1<<5)
+#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG_SHIFT 5
+#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG (0x1<<6)
+#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG_SHIFT 6
+#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG (0x1<<7)
+#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG_SHIFT 7
+	u8 placement_offset;
+	u32 rss_hash_result;
+	u16 vlan_tag;
+	u16 pkt_len;
+	u16 queue_index;
+	struct parsing_flags pars_flags;
+};
+
+
+/*
+ * The data for RSS setup ramrod
+ */
+struct eth_halt_ramrod_data {
+	u32 client_id_5b;
+	u32 reserved0;
+};
+
+
+/*
+ * Place holder for ramrods protocol specific data
+ */
+struct ramrod_data {
+	u32 data_lo;
+	u32 data_hi;
+};
+
+/*
+ * union for ramrod data for ethernet protocol (CQE) (force size of 16 bits)
+ */
+union eth_ramrod_data {
+	struct ramrod_data general;
+};
+
+
+/*
+ * Rx Last BD in page (in ETH)
+ */
+struct eth_rx_bd_next_page {
+	u32 addr_lo;
+	u32 addr_hi;
+	u8 reserved[8];
+};
+
+
+/*
+ * Eth Rx Cqe structure- general structure for ramrods
+ */
+struct common_ramrod_eth_rx_cqe {
+	u8 type;
+	u8 conn_type_3b;
+	u16 reserved;
+	u32 conn_and_cmd_data;
+#define COMMON_RAMROD_ETH_RX_CQE_CID (0xFFFFFF<<0)
+#define COMMON_RAMROD_ETH_RX_CQE_CID_SHIFT 0
+#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID (0xFF<<24)
+#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT 24
+	struct ramrod_data protocol_data;
+};
+
+/*
+ * Rx Last CQE in page (in ETH)
+ */
+struct eth_rx_cqe_next_page {
+	u32 addr_lo;
+	u32 addr_hi;
+	u32 reserved0;
+	u32 reserved1;
+};
+
+/*
+ * union for all eth rx cqe types (fix their sizes)
+ */
+union eth_rx_cqe {
+	struct eth_fast_path_rx_cqe fast_path_cqe;
+	struct common_ramrod_eth_rx_cqe ramrod_cqe;
+	struct eth_rx_cqe_next_page next_page_cqe;
+};
+
+
+/*
+ * common data for all protocols
+ */
+struct spe_hdr {
+	u32 conn_and_cmd_data;
+#define SPE_HDR_CID (0xFFFFFF<<0)
+#define SPE_HDR_CID_SHIFT 0
+#define SPE_HDR_CMD_ID (0xFF<<24)
+#define SPE_HDR_CMD_ID_SHIFT 24
+	u16 type;
+#define SPE_HDR_CONN_TYPE (0xFF<<0)
+#define SPE_HDR_CONN_TYPE_SHIFT 0
+#define SPE_HDR_COMMON_RAMROD (0xFF<<8)
+#define SPE_HDR_COMMON_RAMROD_SHIFT 8
+	u16 reserved;
+};
+
+struct regpair {
+	u32 lo;
+	u32 hi;
+};
+
+/*
+ * ethernet slow path element
+ */
+union eth_specific_data {
+	u8 protocol_data[8];
+	struct regpair mac_config_addr;
+	struct eth_client_setup_ramrod_data client_setup_ramrod_data;
+	struct eth_halt_ramrod_data halt_ramrod_data;
+	struct regpair leading_cqe_addr;
+	struct regpair update_data_addr;
+};
+
+/*
+ * ethernet slow path element
+ */
+struct eth_spe {
+	struct spe_hdr hdr;
+	union eth_specific_data data;
+};
+
+
+/*
+ * doorbell data in host memory
+ */
+struct eth_tx_db_data {
+	u32 packets_prod;
+	u16 bds_prod;
+	u16 reserved;
+};
+
+
+/*
+ * Common configuration parameters per port in Tstorm
+ */
+struct tstorm_eth_function_common_config {
+	u32 config_flags;
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY (0x1<<0)
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY_SHIFT 0
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY (0x1<<1)
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY_SHIFT 1
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY (0x1<<2)
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY_SHIFT 2
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY (0x1<<3)
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY_SHIFT 3
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE (0x1<<4)
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE_SHIFT 4
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE (0x1<<5)
+#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE_SHIFT 5
+#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x3FFFFFF<<6)
+#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 6
+#if defined(__BIG_ENDIAN)
+	u16 __secondary_vlan_id;
+	u8 leading_client_id;
+	u8 rss_result_mask;
+#elif defined(__LITTLE_ENDIAN)
+	u8 rss_result_mask;
+	u8 leading_client_id;
+	u16 __secondary_vlan_id;
+#endif
+};
+
+/*
+ * parameters for eth update ramrod
+ */
+struct eth_update_ramrod_data {
+	struct tstorm_eth_function_common_config func_config;
+	u8 indirectionTable[128];
+};
+
+
+/*
+ * MAC filtering configuration command header
+ */
+struct mac_configuration_hdr {
+	u8 length_6b;
+	u8 offset;
+	u16 reserved0;
+	u32 reserved1;
+};
+
+/*
+ * MAC address in list for ramrod
+ */
+struct tstorm_cam_entry {
+	u16 lsb_mac_addr;
+	u16 middle_mac_addr;
+	u16 msb_mac_addr;
+	u16 flags;
+#define TSTORM_CAM_ENTRY_PORT_ID (0x1<<0)
+#define TSTORM_CAM_ENTRY_PORT_ID_SHIFT 0
+#define TSTORM_CAM_ENTRY_RSRVVAL0 (0x7<<1)
+#define TSTORM_CAM_ENTRY_RSRVVAL0_SHIFT 1
+#define TSTORM_CAM_ENTRY_RESERVED0 (0xFFF<<4)
+#define TSTORM_CAM_ENTRY_RESERVED0_SHIFT 4
+};
+
+/*
+ * MAC filtering: CAM target table entry
+ */
+struct tstorm_cam_target_table_entry {
+	u8 flags;
+#define TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST (0x1<<0)
+#define TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST_SHIFT 0
+#define TSTORM_CAM_TARGET_TABLE_ENTRY_OVERRIDE_VLAN_REMOVAL (0x1<<1)
+#define TSTORM_CAM_TARGET_TABLE_ENTRY_OVERRIDE_VLAN_REMOVAL_SHIFT 1
+#define TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE (0x1<<2)
+#define TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE_SHIFT 2
+#define TSTORM_CAM_TARGET_TABLE_ENTRY_RDMA_MAC (0x1<<3)
+#define TSTORM_CAM_TARGET_TABLE_ENTRY_RDMA_MAC_SHIFT 3
+#define TSTORM_CAM_TARGET_TABLE_ENTRY_RESERVED0 (0xF<<4)
+#define TSTORM_CAM_TARGET_TABLE_ENTRY_RESERVED0_SHIFT 4
+	u8 client_id;
+	u16 vlan_id;
+};
+
+/*
+ * MAC address in list for ramrod
+ */
+struct mac_configuration_entry {
+	struct tstorm_cam_entry cam_entry;
+	struct tstorm_cam_target_table_entry target_table_entry;
+};
+
+/*
+ * MAC filtering configuration command
+ */
+struct mac_configuration_cmd {
+	struct mac_configuration_hdr hdr;
+	struct mac_configuration_entry config_table[64];
+};
+
+
+/*
+ * Configuration parameters per client in Tstorm
+ */
+struct tstorm_eth_client_config {
+#if defined(__BIG_ENDIAN)
+	u16 statistics_counter_id;
+	u16 mtu;
+#elif defined(__LITTLE_ENDIAN)
+	u16 mtu;
+	u16 statistics_counter_id;
+#endif
+#if defined(__BIG_ENDIAN)
+	u16 drop_flags;
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR (0x1<<0)
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR_SHIFT 0
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR (0x1<<1)
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR_SHIFT 1
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR (0x1<<2)
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR_SHIFT 2
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0 (0x1<<3)
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 3
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<4)
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 4
+#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x7FF<<5)
+#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 5
+	u16 config_flags;
+#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE (0x1<<0)
+#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE_SHIFT 0
+#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<1)
+#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 1
+#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0x3FFF<<2)
+#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 2
+#elif defined(__LITTLE_ENDIAN)
+	u16 config_flags;
+#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE (0x1<<0)
+#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE_SHIFT 0
+#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<1)
+#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 1
+#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0x3FFF<<2)
+#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 2
+	u16 drop_flags;
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR (0x1<<0)
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR_SHIFT 0
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR (0x1<<1)
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR_SHIFT 1
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR (0x1<<2)
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR_SHIFT 2
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0 (0x1<<3)
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 3
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<4)
+#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 4
+#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x7FF<<5)
+#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 5
+#endif
+};
+
+
+/*
+ * MAC filtering configuration parameters per port in Tstorm
+ */
+struct tstorm_eth_mac_filter_config {
+	u32 ucast_drop_all;
+	u32 ucast_accept_all;
+	u32 mcast_drop_all;
+	u32 mcast_accept_all;
+	u32 bcast_drop_all;
+	u32 bcast_accept_all;
+	u32 strict_vlan;
+	u32 __secondary_vlan_clients;
+};
+
+
+struct rate_shaping_per_protocol {
+#if defined(__BIG_ENDIAN)
+	u16 reserved0;
+	u16 protocol_rate;
+#elif defined(__LITTLE_ENDIAN)
+	u16 protocol_rate;
+	u16 reserved0;
+#endif
+	u32 protocol_quota;
+	s32 current_credit;
+	u32 reserved;
+};
+
+struct rate_shaping_vars {
+	struct rate_shaping_per_protocol protocol_vars[NUM_OF_PROTOCOLS];
+	u32 pause_mask;
+	u32 periodic_stop;
+	u32 rs_periodic_timeout;
+	u32 rs_threshold;
+	u32 last_periodic_time;
+	u32 reserved;
+};
+
+struct fairness_per_protocol {
+	u32 credit_delta;
+	s32 fair_credit;
+#if defined(__BIG_ENDIAN)
+	u16 reserved0;
+	u8 state;
+	u8 weight;
+#elif defined(__LITTLE_ENDIAN)
+	u8 weight;
+	u8 state;
+	u16 reserved0;
+#endif
+	u32 reserved1;
+};
+
+struct fairness_vars {
+	struct fairness_per_protocol protocol_vars[NUM_OF_PROTOCOLS];
+	u32 upper_bound;
+	u32 port_rate;
+	u32 pause_mask;
+	u32 fair_threshold;
+};
+
+struct safc_struct {
+	u32 cur_pause_mask;
+	u32 expire_time;
+#if defined(__BIG_ENDIAN)
+	u16 reserved0;
+	u8 cur_cos_types;
+	u8 safc_timeout_usec;
+#elif defined(__LITTLE_ENDIAN)
+	u8 safc_timeout_usec;
+	u8 cur_cos_types;
+	u16 reserved0;
+#endif
+	u32 reserved1;
+};
+
+struct demo_struct {
+	u8 con_number[NUM_OF_PROTOCOLS];
+#if defined(__BIG_ENDIAN)
+	u8 reserved1;
+	u8 fairness_enable;
+	u8 rate_shaping_enable;
+	u8 cmng_enable;
+#elif defined(__LITTLE_ENDIAN)
+	u8 cmng_enable;
+	u8 rate_shaping_enable;
+	u8 fairness_enable;
+	u8 reserved1;
+#endif
+};
+
+struct cmng_struct {
+	struct rate_shaping_vars rs_vars;
+	struct fairness_vars fair_vars;
+	struct safc_struct safc_vars;
+	struct demo_struct demo_vars;
+};
+
+
+struct cos_to_protocol {
+	u8 mask[MAX_COS_NUMBER];
+};
+
+
+/*
+ * Common statistics collected by the Xstorm (per port)
+ */
+struct xstorm_common_stats {
+	struct regpair total_sent_bytes;
+	u32 total_sent_pkts;
+	u32 unicast_pkts_sent;
+	struct regpair unicast_bytes_sent;
+	struct regpair multicast_bytes_sent;
+	u32 multicast_pkts_sent;
+	u32 broadcast_pkts_sent;
+	struct regpair broadcast_bytes_sent;
+	struct regpair done;
+};
+
+/*
+ * Protocol-common statistics collected by the Tstorm (per client)
+ */
+struct tstorm_per_client_stats {
+	struct regpair total_rcv_bytes;
+	struct regpair rcv_unicast_bytes;
+	struct regpair rcv_broadcast_bytes;
+	struct regpair rcv_multicast_bytes;
+	struct regpair rcv_error_bytes;
+	u32 checksum_discard;
+	u32 packets_too_big_discard;
+	u32 total_rcv_pkts;
+	u32 rcv_unicast_pkts;
+	u32 rcv_broadcast_pkts;
+	u32 rcv_multicast_pkts;
+	u32 no_buff_discard;
+	u32 ttl0_discard;
+	u32 mac_discard;
+	u32 reserved;
+};
+
+/*
+ * Protocol-common statistics collected by the Tstorm (per port)
+ */
+struct tstorm_common_stats {
+	struct tstorm_per_client_stats client_statistics[MAX_T_STAT_COUNTER_ID];
+	u32 mac_filter_discard;
+	u32 xxoverflow_discard;
+	u32 brb_truncate_discard;
+	u32 reserved;
+	struct regpair done;
+};
+
+/*
+ * Eth statistics query sturcture for the eth_stats_quesry ramrod
+ */
+struct eth_stats_query {
+	struct xstorm_common_stats xstorm_common;
+	struct tstorm_common_stats tstorm_common;
+};
+
+
+/*
+ * FW version stored in the Xstorm RAM
+ */
+struct fw_version {
+#if defined(__BIG_ENDIAN)
+	u16 patch;
+	u8 primary;
+	u8 client;
+#elif defined(__LITTLE_ENDIAN)
+	u8 client;
+	u8 primary;
+	u16 patch;
+#endif
+	u32 flags;
+#define FW_VERSION_OPTIMIZED (0x1<<0)
+#define FW_VERSION_OPTIMIZED_SHIFT 0
+#define FW_VERSION_BIG_ENDIEN (0x1<<1)
+#define FW_VERSION_BIG_ENDIEN_SHIFT 1
+#define __FW_VERSION_RESERVED (0x3FFFFFFF<<2)
+#define __FW_VERSION_RESERVED_SHIFT 2
+};
+
+
+/*
+ * FW version stored in first line of pram
+ */
+struct pram_fw_version {
+#if defined(__BIG_ENDIAN)
+	u16 patch;
+	u8 primary;
+	u8 client;
+#elif defined(__LITTLE_ENDIAN)
+	u8 client;
+	u8 primary;
+	u16 patch;
+#endif
+	u8 flags;
+#define PRAM_FW_VERSION_OPTIMIZED (0x1<<0)
+#define PRAM_FW_VERSION_OPTIMIZED_SHIFT 0
+#define PRAM_FW_VERSION_STORM_ID (0x3<<1)
+#define PRAM_FW_VERSION_STORM_ID_SHIFT 1
+#define PRAM_FW_VERSION_BIG_ENDIEN (0x1<<3)
+#define PRAM_FW_VERSION_BIG_ENDIEN_SHIFT 3
+#define __PRAM_FW_VERSION_RESERVED0 (0xF<<4)
+#define __PRAM_FW_VERSION_RESERVED0_SHIFT 4
+};
+
+
+/*
+ * The send queue element
+ */
+struct slow_path_element {
+	struct spe_hdr hdr;
+	u8 protocol_data[8];
+};
+
+
+/*
+ * eth/toe flags that indicate if to query
+ */
+struct stats_indication_flags {
+	u32 collect_eth;
+	u32 collect_toe;
+};
+
+
diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x_init.h
new file mode 100644
index 000000000000..04f93bff2ef4
--- /dev/null
+++ b/drivers/net/bnx2x_init.h
@@ -0,0 +1,564 @@
+/* bnx2x_init.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007 Broadcom Corporation
+ *
+ * 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.
+ *
+ * Written by: Eliezer Tamir <eliezert@broadcom.com>
+ */
+
+#ifndef BNX2X_INIT_H
+#define BNX2X_INIT_H
+
+#define COMMON				0x1
+#define PORT0				0x2
+#define PORT1				0x4
+
+#define INIT_EMULATION			0x1
+#define INIT_FPGA			0x2
+#define INIT_ASIC			0x4
+#define INIT_HARDWARE			0x7
+
+#define STORM_INTMEM_SIZE		(0x5800 / 4)
+#define TSTORM_INTMEM_ADDR		0x1a0000
+#define CSTORM_INTMEM_ADDR		0x220000
+#define XSTORM_INTMEM_ADDR		0x2a0000
+#define USTORM_INTMEM_ADDR		0x320000
+
+
+/* Init operation types and structures */
+
+#define OP_RD			0x1 /* read single register */
+#define OP_WR			0x2 /* write single register */
+#define OP_IW			0x3 /* write single register using mailbox */
+#define OP_SW			0x4 /* copy a string to the device */
+#define OP_SI			0x5 /* copy a string using mailbox */
+#define OP_ZR			0x6 /* clear memory */
+#define OP_ZP			0x7 /* unzip then copy with DMAE */
+#define OP_WB			0x8 /* copy a string using DMAE */
+
+struct raw_op {
+	u32 op		:8;
+	u32 offset	:24;
+	u32 raw_data;
+};
+
+struct op_read {
+	u32 op		:8;
+	u32 offset	:24;
+	u32 pad;
+};
+
+struct op_write {
+	u32 op		:8;
+	u32 offset	:24;
+	u32 val;
+};
+
+struct op_string_write {
+	u32 op		:8;
+	u32 offset	:24;
+#ifdef __LITTLE_ENDIAN
+	u16 data_off;
+	u16 data_len;
+#else /* __BIG_ENDIAN */
+	u16 data_len;
+	u16 data_off;
+#endif
+};
+
+struct op_zero {
+	u32 op		:8;
+	u32 offset	:24;
+	u32 len;
+};
+
+union init_op {
+	struct op_read		read;
+	struct op_write		write;
+	struct op_string_write	str_wr;
+	struct op_zero		zero;
+	struct raw_op		raw;
+};
+
+#include "bnx2x_init_values.h"
+
+static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val);
+
+static void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr,
+			     u32 dst_addr, u32 len32);
+
+static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len);
+
+static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, const u32 *data,
+			      u32 len)
+{
+	int i;
+
+	for (i = 0; i < len; i++) {
+		REG_WR(bp, addr + i*4, data[i]);
+		if (!(i % 10000)) {
+			touch_softlockup_watchdog();
+			cpu_relax();
+		}
+	}
+}
+
+#define INIT_MEM_WR(reg, data, reg_off, len) \
+	bnx2x_init_str_wr(bp, reg + reg_off*4, data, len)
+
+static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data,
+			      u16 len)
+{
+	int i;
+
+	for (i = 0; i < len; i++) {
+		REG_WR_IND(bp, addr + i*4, data[i]);
+		if (!(i % 10000)) {
+			touch_softlockup_watchdog();
+			cpu_relax();
+		}
+	}
+}
+
+static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data,
+			     u32 len, int gunzip)
+{
+	int offset = 0;
+
+	if (gunzip) {
+		int rc;
+#ifdef __BIG_ENDIAN
+		int i, size;
+		u32 *temp;
+
+		temp = kmalloc(len, GFP_KERNEL);
+		size = (len / 4) + ((len % 4) ? 1 : 0);
+		for (i = 0; i < size; i++)
+			temp[i] = swab32(data[i]);
+		data = temp;
+#endif
+		rc = bnx2x_gunzip(bp, (u8 *)data, len);
+		if (rc) {
+			DP(NETIF_MSG_HW, "gunzip failed ! rc %d\n", rc);
+			return;
+		}
+		len = bp->gunzip_outlen;
+#ifdef __BIG_ENDIAN
+		kfree(temp);
+		for (i = 0; i < len; i++)
+			 ((u32 *)bp->gunzip_buf)[i] =
+					swab32(((u32 *)bp->gunzip_buf)[i]);
+#endif
+	} else {
+		if ((len * 4) > FW_BUF_SIZE) {
+			BNX2X_ERR("LARGE DMAE OPERATION ! len 0x%x\n", len*4);
+			return;
+		}
+		memcpy(bp->gunzip_buf, data, len * 4);
+	}
+
+	while (len > DMAE_LEN32_MAX) {
+		bnx2x_write_dmae(bp, bp->gunzip_mapping + offset,
+				 addr + offset, DMAE_LEN32_MAX);
+		offset += DMAE_LEN32_MAX * 4;
+		len -= DMAE_LEN32_MAX;
+	}
+	bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, addr + offset, len);
+}
+
+#define INIT_MEM_WB(reg, data, reg_off, len) \
+	bnx2x_init_wr_wb(bp, reg + reg_off*4, data, len, 0)
+
+#define INIT_GUNZIP_DMAE(reg, data, reg_off, len) \
+	bnx2x_init_wr_wb(bp, reg + reg_off*4, data, len, 1)
+
+static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len)
+{
+	int offset = 0;
+
+	if ((len * 4) > FW_BUF_SIZE) {
+		BNX2X_ERR("LARGE DMAE OPERATION ! len 0x%x\n", len * 4);
+		return;
+	}
+	memset(bp->gunzip_buf, fill, len * 4);
+
+	while (len > DMAE_LEN32_MAX) {
+		bnx2x_write_dmae(bp, bp->gunzip_mapping + offset,
+				 addr + offset, DMAE_LEN32_MAX);
+		offset += DMAE_LEN32_MAX * 4;
+		len -= DMAE_LEN32_MAX;
+	}
+	bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, addr + offset, len);
+}
+
+static void bnx2x_init_block(struct bnx2x *bp, u32 op_start, u32 op_end)
+{
+	int i;
+	union init_op *op;
+	u32 op_type, addr, len;
+	const u32 *data;
+
+	for (i = op_start; i < op_end; i++) {
+
+		op = (union init_op *)&(init_ops[i]);
+
+		op_type = op->str_wr.op;
+		addr = op->str_wr.offset;
+		len = op->str_wr.data_len;
+		data = init_data + op->str_wr.data_off;
+
+		switch (op_type) {
+		case OP_RD:
+			REG_RD(bp, addr);
+			break;
+		case OP_WR:
+			REG_WR(bp, addr, op->write.val);
+			break;
+		case OP_SW:
+			bnx2x_init_str_wr(bp, addr, data, len);
+			break;
+		case OP_WB:
+			bnx2x_init_wr_wb(bp, addr, data, len, 0);
+			break;
+		case OP_SI:
+			bnx2x_init_ind_wr(bp, addr, data, len);
+			break;
+		case OP_ZR:
+			bnx2x_init_fill(bp, addr, 0, op->zero.len);
+			break;
+		case OP_ZP:
+			bnx2x_init_wr_wb(bp, addr, data, len, 1);
+			break;
+		default:
+			BNX2X_ERR("BAD init operation!\n");
+		}
+	}
+}
+
+
+/****************************************************************************
+* PXP
+****************************************************************************/
+/*
+ * This code configures the PCI read/write arbiter
+ * which implements a wighted round robin
+ * between the virtual queues in the chip.
+ *
+ * The values were derived for each PCI max payload and max request size.
+ * since max payload and max request size are only known at run time,
+ * this is done as a separate init stage.
+ */
+
+#define NUM_WR_Q			13
+#define NUM_RD_Q			29
+#define MAX_RD_ORD			3
+#define MAX_WR_ORD			2
+
+/* configuration for one arbiter queue */
+struct arb_line {
+	int l;
+	int add;
+	int ubound;
+};
+
+/* derived configuration for each read queue for each max request size */
+static const struct arb_line read_arb_data[NUM_RD_Q][MAX_RD_ORD + 1] = {
+	{{8 , 64 , 25}, {16 , 64 , 25}, {32 , 64 , 25}, {64 , 64 , 41} },
+	{{4 , 8 , 4},   {4 , 8 , 4},    {4 , 8 , 4},    {4 , 8 , 4} },
+	{{4 , 3 , 3},   {4 , 3 , 3},    {4 , 3 , 3},    {4 , 3 , 3} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {16 , 3 , 11},  {16 , 3 , 11} },
+	{{8 , 64 , 25}, {16 , 64 , 25}, {32 , 64 , 25}, {64 , 64 , 41} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {64 , 3 , 41} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {64 , 3 , 41} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {64 , 3 , 41} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {64 , 3 , 41} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 3 , 6},   {16 , 3 , 11},  {32 , 3 , 21},  {32 , 3 , 21} },
+	{{8 , 64 , 25}, {16 , 64 , 41}, {32 , 64 , 81}, {64 , 64 , 120} }
+};
+
+/* derived configuration for each write queue for each max request size */
+static const struct arb_line write_arb_data[NUM_WR_Q][MAX_WR_ORD + 1] = {
+	{{4 , 6 , 3},   {4 , 6 , 3},    {4 , 6 , 3} },
+	{{4 , 2 , 3},   {4 , 2 , 3},    {4 , 2 , 3} },
+	{{8 , 2 , 6},   {16 , 2 , 11},  {16 , 2 , 11} },
+	{{8 , 2 , 6},   {16 , 2 , 11},  {32 , 2 , 21} },
+	{{8 , 2 , 6},   {16 , 2 , 11},  {32 , 2 , 21} },
+	{{8 , 2 , 6},   {16 , 2 , 11},  {32 , 2 , 21} },
+	{{8 , 64 , 25}, {16 , 64 , 25}, {32 , 64 , 25} },
+	{{8 , 2 , 6},   {16 , 2 , 11},  {16 , 2 , 11} },
+	{{8 , 2 , 6},   {16 , 2 , 11},  {16 , 2 , 11} },
+	{{8 , 9 , 6},   {16 , 9 , 11},  {32 , 9 , 21} },
+	{{8 , 47 , 19}, {16 , 47 , 19}, {32 , 47 , 21} },
+	{{8 , 9 , 6},   {16 , 9 , 11},  {16 , 9 , 11} },
+	{{8 , 64 , 25}, {16 , 64 , 41}, {32 , 64 , 81} }
+};
+
+/* register adresses for read queues */
+static const struct arb_line read_arb_addr[NUM_RD_Q-1] = {
+	{PXP2_REG_RQ_BW_RD_L0, PXP2_REG_RQ_BW_RD_ADD0,
+		PXP2_REG_RQ_BW_RD_UBOUND0},
+	{PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1,
+		PXP2_REG_PSWRQ_BW_UB1},
+	{PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2,
+		PXP2_REG_PSWRQ_BW_UB2},
+	{PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3,
+		PXP2_REG_PSWRQ_BW_UB3},
+	{PXP2_REG_RQ_BW_RD_L4, PXP2_REG_RQ_BW_RD_ADD4,
+		PXP2_REG_RQ_BW_RD_UBOUND4},
+	{PXP2_REG_RQ_BW_RD_L5, PXP2_REG_RQ_BW_RD_ADD5,
+		PXP2_REG_RQ_BW_RD_UBOUND5},
+	{PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6,
+		PXP2_REG_PSWRQ_BW_UB6},
+	{PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7,
+		PXP2_REG_PSWRQ_BW_UB7},
+	{PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8,
+		PXP2_REG_PSWRQ_BW_UB8},
+	{PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9,
+		PXP2_REG_PSWRQ_BW_UB9},
+	{PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10,
+		PXP2_REG_PSWRQ_BW_UB10},
+	{PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11,
+		PXP2_REG_PSWRQ_BW_UB11},
+	{PXP2_REG_RQ_BW_RD_L12, PXP2_REG_RQ_BW_RD_ADD12,
+		PXP2_REG_RQ_BW_RD_UBOUND12},
+	{PXP2_REG_RQ_BW_RD_L13, PXP2_REG_RQ_BW_RD_ADD13,
+		PXP2_REG_RQ_BW_RD_UBOUND13},
+	{PXP2_REG_RQ_BW_RD_L14, PXP2_REG_RQ_BW_RD_ADD14,
+		PXP2_REG_RQ_BW_RD_UBOUND14},
+	{PXP2_REG_RQ_BW_RD_L15, PXP2_REG_RQ_BW_RD_ADD15,
+		PXP2_REG_RQ_BW_RD_UBOUND15},
+	{PXP2_REG_RQ_BW_RD_L16, PXP2_REG_RQ_BW_RD_ADD16,
+		PXP2_REG_RQ_BW_RD_UBOUND16},
+	{PXP2_REG_RQ_BW_RD_L17, PXP2_REG_RQ_BW_RD_ADD17,
+		PXP2_REG_RQ_BW_RD_UBOUND17},
+	{PXP2_REG_RQ_BW_RD_L18, PXP2_REG_RQ_BW_RD_ADD18,
+		PXP2_REG_RQ_BW_RD_UBOUND18},
+	{PXP2_REG_RQ_BW_RD_L19, PXP2_REG_RQ_BW_RD_ADD19,
+		PXP2_REG_RQ_BW_RD_UBOUND19},
+	{PXP2_REG_RQ_BW_RD_L20, PXP2_REG_RQ_BW_RD_ADD20,
+		PXP2_REG_RQ_BW_RD_UBOUND20},
+	{PXP2_REG_RQ_BW_RD_L22, PXP2_REG_RQ_BW_RD_ADD22,
+		PXP2_REG_RQ_BW_RD_UBOUND22},
+	{PXP2_REG_RQ_BW_RD_L23, PXP2_REG_RQ_BW_RD_ADD23,
+		PXP2_REG_RQ_BW_RD_UBOUND23},
+	{PXP2_REG_RQ_BW_RD_L24, PXP2_REG_RQ_BW_RD_ADD24,
+		PXP2_REG_RQ_BW_RD_UBOUND24},
+	{PXP2_REG_RQ_BW_RD_L25, PXP2_REG_RQ_BW_RD_ADD25,
+		PXP2_REG_RQ_BW_RD_UBOUND25},
+	{PXP2_REG_RQ_BW_RD_L26, PXP2_REG_RQ_BW_RD_ADD26,
+		PXP2_REG_RQ_BW_RD_UBOUND26},
+	{PXP2_REG_RQ_BW_RD_L27, PXP2_REG_RQ_BW_RD_ADD27,
+		PXP2_REG_RQ_BW_RD_UBOUND27},
+	{PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28,
+		PXP2_REG_PSWRQ_BW_UB28}
+};
+
+/* register adresses for wrtie queues */
+static const struct arb_line write_arb_addr[NUM_WR_Q-1] = {
+	{PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1,
+		PXP2_REG_PSWRQ_BW_UB1},
+	{PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2,
+		PXP2_REG_PSWRQ_BW_UB2},
+	{PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3,
+		PXP2_REG_PSWRQ_BW_UB3},
+	{PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6,
+		PXP2_REG_PSWRQ_BW_UB6},
+	{PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7,
+		PXP2_REG_PSWRQ_BW_UB7},
+	{PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8,
+		PXP2_REG_PSWRQ_BW_UB8},
+	{PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9,
+		PXP2_REG_PSWRQ_BW_UB9},
+	{PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10,
+		PXP2_REG_PSWRQ_BW_UB10},
+	{PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11,
+		PXP2_REG_PSWRQ_BW_UB11},
+	{PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28,
+		PXP2_REG_PSWRQ_BW_UB28},
+	{PXP2_REG_RQ_BW_WR_L29, PXP2_REG_RQ_BW_WR_ADD29,
+		PXP2_REG_RQ_BW_WR_UBOUND29},
+	{PXP2_REG_RQ_BW_WR_L30, PXP2_REG_RQ_BW_WR_ADD30,
+		PXP2_REG_RQ_BW_WR_UBOUND30}
+};
+
+static void bnx2x_init_pxp(struct bnx2x *bp)
+{
+	int r_order, w_order;
+	u32 val, i;
+
+	pci_read_config_word(bp->pdev,
+			     bp->pcie_cap + PCI_EXP_DEVCTL, (u16 *)&val);
+	DP(NETIF_MSG_HW, "read 0x%x from devctl\n", val);
+	w_order = ((val & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
+	r_order = ((val & PCI_EXP_DEVCTL_READRQ) >> 12);
+
+	if (r_order > MAX_RD_ORD) {
+		DP(NETIF_MSG_HW, "read order of %d  order adjusted to %d\n",
+		   r_order, MAX_RD_ORD);
+		r_order = MAX_RD_ORD;
+	}
+	if (w_order > MAX_WR_ORD) {
+		DP(NETIF_MSG_HW, "write order of %d  order adjusted to %d\n",
+		   w_order, MAX_WR_ORD);
+		w_order = MAX_WR_ORD;
+	}
+	DP(NETIF_MSG_HW, "read order %d  write order %d\n", r_order, w_order);
+
+	for (i = 0; i < NUM_RD_Q-1; i++) {
+		REG_WR(bp, read_arb_addr[i].l, read_arb_data[i][r_order].l);
+		REG_WR(bp, read_arb_addr[i].add,
+		       read_arb_data[i][r_order].add);
+		REG_WR(bp, read_arb_addr[i].ubound,
+		       read_arb_data[i][r_order].ubound);
+	}
+
+	for (i = 0; i < NUM_WR_Q-1; i++) {
+		if ((write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L29) ||
+		    (write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L30)) {
+
+			REG_WR(bp, write_arb_addr[i].l,
+			       write_arb_data[i][w_order].l);
+
+			REG_WR(bp, write_arb_addr[i].add,
+			       write_arb_data[i][w_order].add);
+
+			REG_WR(bp, write_arb_addr[i].ubound,
+			       write_arb_data[i][w_order].ubound);
+		} else {
+
+			val = REG_RD(bp, write_arb_addr[i].l);
+			REG_WR(bp, write_arb_addr[i].l,
+			       val | (write_arb_data[i][w_order].l << 10));
+
+			val = REG_RD(bp, write_arb_addr[i].add);
+			REG_WR(bp, write_arb_addr[i].add,
+			       val | (write_arb_data[i][w_order].add << 10));
+
+			val = REG_RD(bp, write_arb_addr[i].ubound);
+			REG_WR(bp, write_arb_addr[i].ubound,
+			       val | (write_arb_data[i][w_order].ubound << 7));
+		}
+	}
+
+	val =  write_arb_data[NUM_WR_Q-1][w_order].add;
+	val += write_arb_data[NUM_WR_Q-1][w_order].ubound << 10;
+	val += write_arb_data[NUM_WR_Q-1][w_order].l << 17;
+	REG_WR(bp, PXP2_REG_PSWRQ_BW_RD, val);
+
+	val =  read_arb_data[NUM_RD_Q-1][r_order].add;
+	val += read_arb_data[NUM_RD_Q-1][r_order].ubound << 10;
+	val += read_arb_data[NUM_RD_Q-1][r_order].l << 17;
+	REG_WR(bp, PXP2_REG_PSWRQ_BW_WR, val);
+
+	REG_WR(bp, PXP2_REG_RQ_WR_MBS0, w_order);
+	REG_WR(bp, PXP2_REG_RQ_WR_MBS0 + 8, w_order);
+	REG_WR(bp, PXP2_REG_RQ_RD_MBS0, r_order);
+	REG_WR(bp, PXP2_REG_RQ_RD_MBS0 + 8, r_order);
+
+	REG_WR(bp, PXP2_REG_WR_DMAE_TH, (128 << w_order)/16);
+}
+
+
+/****************************************************************************
+* CDU
+****************************************************************************/
+
+#define CDU_REGION_NUMBER_XCM_AG	2
+#define CDU_REGION_NUMBER_UCM_AG	4
+
+/**
+ * String-to-compress [31:8] = CID (all 24 bits)
+ * String-to-compress [7:4] = Region
+ * String-to-compress [3:0] = Type
+ */
+#define CDU_VALID_DATA(_cid, _region, _type) \
+		(((_cid) << 8) | (((_region) & 0xf) << 4) | (((_type) & 0xf)))
+#define CDU_CRC8(_cid, _region, _type) \
+			calc_crc8(CDU_VALID_DATA(_cid, _region, _type), 0xff)
+#define CDU_RSRVD_VALUE_TYPE_A(_cid, _region, _type) \
+			(0x80 | (CDU_CRC8(_cid, _region, _type) & 0x7f))
+#define CDU_RSRVD_VALUE_TYPE_B(_crc, _type) \
+	(0x80 | ((_type) & 0xf << 3) | (CDU_CRC8(_cid, _region, _type) & 0x7))
+#define CDU_RSRVD_INVALIDATE_CONTEXT_VALUE(_val)	((_val) & ~0x80)
+
+/*****************************************************************************
+ * Description:
+ *         Calculates crc 8 on a word value: polynomial 0-1-2-8
+ *         Code was translated from Verilog.
+ ****************************************************************************/
+static u8 calc_crc8(u32 data, u8 crc)
+{
+	u8 D[32];
+	u8 NewCRC[8];
+	u8 C[8];
+	u8 crc_res;
+	u8 i;
+
+	/* split the data into 31 bits */
+	for (i = 0; i < 32; i++) {
+		D[i] = data & 1;
+		data = data >> 1;
+	}
+
+	/* split the crc into 8 bits */
+	for (i = 0; i < 8; i++) {
+		C[i] = crc & 1;
+		crc = crc >> 1;
+	}
+
+	NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^
+		D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^
+		C[6] ^ C[7];
+	NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^
+		D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^
+		D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ C[6];
+	NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^
+		D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^
+		C[0] ^ C[1] ^ C[4] ^ C[5];
+	NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^
+		D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^
+		C[1] ^ C[2] ^ C[5] ^ C[6];
+	NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^
+		D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^
+		C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7];
+	NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^
+		D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^
+		C[3] ^ C[4] ^ C[7];
+	NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^
+		D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^
+		C[5];
+	NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^
+		D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^
+		C[6];
+
+	crc_res = 0;
+	for (i = 0; i < 8; i++)
+		crc_res |= (NewCRC[i] << i);
+
+	return crc_res;
+}
+
+
+#endif /* BNX2X_INIT_H */
+
diff --git a/drivers/net/bnx2x_init_values.h b/drivers/net/bnx2x_init_values.h
new file mode 100644
index 000000000000..bef0a9b19d68
--- /dev/null
+++ b/drivers/net/bnx2x_init_values.h
@@ -0,0 +1,6368 @@
+#ifndef __BNX2X_INIT_VALUES_H__
+#define __BNX2X_INIT_VALUES_H__
+
+/* This array contains the list of operations needed to initialize the chip.
+ *
+ * For each block in the chip there are three init stages:
+ * common - HW used by both ports,
+ * port1 and port2 - initialization for a specific Ethernet port.
+ * When a port is opened or closed, the management CPU tells the driver
+ * whether to init/disable common HW in addition to the port HW.
+ * This way the first port going up will first initializes the common HW,
+ * and the last port going down also resets the common HW
+ *
+ * For each init stage/block there is a list of actions needed in a format:
+ * {operation, register, data}
+ * where:
+ * OP_WR - write a value to the chip.
+ * OP_RD - read a register (usually a clear on read register).
+ * OP_SW - string write, write a section of consecutive addresses to the chip.
+ * OP_SI - copy a string using indirect writes.
+ * OP_ZR - clear a range of memory.
+ * OP_ZP - unzip and copy using DMAE.
+ * OP_WB - string copy using DMAE.
+ *
+ * The #defines mark the stages.
+ *
+ */
+
+static const struct raw_op init_ops[] = {
+#define PRS_COMMON_START        0
+	{OP_WR, PRS_REG_INC_VALUE, 0xf},
+	{OP_WR, PRS_REG_EVENT_ID_1, 0x45},
+	{OP_WR, PRS_REG_EVENT_ID_2, 0x84},
+	{OP_WR, PRS_REG_EVENT_ID_3, 0x6},
+	{OP_WR, PRS_REG_NO_MATCH_EVENT_ID, 0x4},
+	{OP_WR, PRS_REG_CM_HDR_TYPE_0, 0x0},
+	{OP_WR, PRS_REG_CM_HDR_TYPE_1, 0x12170000},
+	{OP_WR, PRS_REG_CM_HDR_TYPE_2, 0x22170000},
+	{OP_WR, PRS_REG_CM_HDR_TYPE_3, 0x32170000},
+	{OP_ZR, PRS_REG_CM_HDR_TYPE_4, 0x5},
+	{OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_1, 0x12150000},
+	{OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_2, 0x22150000},
+	{OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_3, 0x32150000},
+	{OP_ZR, PRS_REG_CM_HDR_LOOPBACK_TYPE_4, 0x4},
+	{OP_WR, PRS_REG_CM_NO_MATCH_HDR, 0x2100000},
+	{OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_0, 0x100000},
+	{OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_1, 0x10100000},
+	{OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_2, 0x20100000},
+	{OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_3, 0x30100000},
+	{OP_ZR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_4, 0x4},
+	{OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_0, 0x100000},
+	{OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_1, 0x12140000},
+	{OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_2, 0x22140000},
+	{OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_3, 0x32140000},
+	{OP_ZR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_4, 0x4},
+	{OP_RD, PRS_REG_NUM_OF_PACKETS, 0x0},
+	{OP_RD, PRS_REG_NUM_OF_CFC_FLUSH_MESSAGES, 0x0},
+	{OP_RD, PRS_REG_NUM_OF_TRANSPARENT_FLUSH_MESSAGES, 0x0},
+	{OP_RD, PRS_REG_NUM_OF_DEAD_CYCLES, 0x0},
+	{OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_0, 0xff},
+	{OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_1, 0xff},
+	{OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_2, 0xff},
+	{OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_3, 0xff},
+	{OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_4, 0xff},
+	{OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_5, 0xff},
+	{OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_6, 0xff},
+	{OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_7, 0xff},
+	{OP_WR, PRS_REG_PURE_REGIONS, 0x3e},
+	{OP_WR, PRS_REG_PACKET_REGIONS_TYPE_0, 0x0},
+	{OP_WR, PRS_REG_PACKET_REGIONS_TYPE_1, 0x3f},
+	{OP_WR, PRS_REG_PACKET_REGIONS_TYPE_2, 0x3f},
+	{OP_WR, PRS_REG_PACKET_REGIONS_TYPE_3, 0x3f},
+	{OP_WR, PRS_REG_PACKET_REGIONS_TYPE_4, 0x0},
+	{OP_WR, PRS_REG_PACKET_REGIONS_TYPE_5, 0x3f},
+	{OP_WR, PRS_REG_PACKET_REGIONS_TYPE_6, 0x3f},
+	{OP_WR, PRS_REG_PACKET_REGIONS_TYPE_7, 0x3f},
+#define PRS_COMMON_END          46
+#define PRS_PORT0_START         46
+	{OP_WR, PRS_REG_CID_PORT_0, 0x0},
+#define PRS_PORT0_END           47
+#define PRS_PORT1_START         47
+	{OP_WR, PRS_REG_CID_PORT_1, 0x800000},
+#define PRS_PORT1_END           48
+#define TSDM_COMMON_START       48
+	{OP_WR, TSDM_REG_CFC_RSP_START_ADDR, 0x411},
+	{OP_WR, TSDM_REG_CMP_COUNTER_START_ADDR, 0x400},
+	{OP_WR, TSDM_REG_Q_COUNTER_START_ADDR, 0x404},
+	{OP_WR, TSDM_REG_PCK_END_MSG_START_ADDR, 0x419},
+	{OP_WR, TSDM_REG_CMP_COUNTER_MAX0, 0xffff},
+	{OP_WR, TSDM_REG_CMP_COUNTER_MAX1, 0xffff},
+	{OP_WR, TSDM_REG_CMP_COUNTER_MAX2, 0xffff},
+	{OP_WR, TSDM_REG_CMP_COUNTER_MAX3, 0xffff},
+	{OP_ZR, TSDM_REG_AGG_INT_EVENT_0, 0x80},
+	{OP_WR, TSDM_REG_ENABLE_IN1, 0x7ffffff},
+	{OP_WR, TSDM_REG_ENABLE_IN2, 0x3f},
+	{OP_WR, TSDM_REG_ENABLE_OUT1, 0x7ffffff},
+	{OP_WR, TSDM_REG_ENABLE_OUT2, 0xf},
+	{OP_RD, TSDM_REG_NUM_OF_Q0_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_Q1_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_Q3_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_Q4_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_Q5_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_Q6_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_Q7_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_Q8_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_Q9_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_Q10_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_Q11_CMD, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_PKT_END_MSG, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0},
+	{OP_RD, TSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0},
+	{OP_WR, TSDM_REG_TIMER_TICK, 0x3e8},
+#define TSDM_COMMON_END         76
+#define TCM_COMMON_START        76
+	{OP_WR, TCM_REG_XX_MAX_LL_SZ, 0x20},
+	{OP_WR, TCM_REG_XX_OVFL_EVNT_ID, 0x32},
+	{OP_WR, TCM_REG_TQM_TCM_HDR_P, 0x2150020},
+	{OP_WR, TCM_REG_TQM_TCM_HDR_S, 0x2150020},
+	{OP_WR, TCM_REG_TM_TCM_HDR, 0x30},
+	{OP_WR, TCM_REG_ERR_TCM_HDR, 0x8100000},
+	{OP_WR, TCM_REG_ERR_EVNT_ID, 0x33},
+	{OP_WR, TCM_REG_EXPR_EVNT_ID, 0x30},
+	{OP_WR, TCM_REG_STOP_EVNT_ID, 0x31},
+	{OP_WR, TCM_REG_PRS_WEIGHT, 0x4},
+	{OP_WR, TCM_REG_PBF_WEIGHT, 0x5},
+	{OP_WR, TCM_REG_CP_WEIGHT, 0x0},
+	{OP_WR, TCM_REG_TSDM_WEIGHT, 0x4},
+	{OP_WR, TCM_REG_TCM_TQM_USE_Q, 0x1},
+	{OP_WR, TCM_REG_GR_ARB_TYPE, 0x1},
+	{OP_WR, TCM_REG_GR_LD0_PR, 0x1},
+	{OP_WR, TCM_REG_GR_LD1_PR, 0x2},
+	{OP_WR, TCM_REG_CFC_INIT_CRD, 0x1},
+	{OP_WR, TCM_REG_FIC0_INIT_CRD, 0x40},
+	{OP_WR, TCM_REG_FIC1_INIT_CRD, 0x40},
+	{OP_WR, TCM_REG_TQM_INIT_CRD, 0x20},
+	{OP_WR, TCM_REG_XX_INIT_CRD, 0x13},
+	{OP_WR, TCM_REG_XX_MSG_NUM, 0x20},
+	{OP_ZR, TCM_REG_XX_TABLE, 0xa},
+	{OP_SW, TCM_REG_XX_DESCR_TABLE, 0x200000},
+	{OP_WR, TCM_REG_N_SM_CTX_LD_0, 0x7},
+	{OP_WR, TCM_REG_N_SM_CTX_LD_1, 0x7},
+	{OP_WR, TCM_REG_N_SM_CTX_LD_2, 0x8},
+	{OP_WR, TCM_REG_N_SM_CTX_LD_3, 0x8},
+	{OP_ZR, TCM_REG_N_SM_CTX_LD_4, 0x4},
+	{OP_WR, TCM_REG_TCM_REG0_SZ, 0x6},
+	{OP_WR, TCM_REG_PHYS_QNUM0_0, 0xd},
+	{OP_WR, TCM_REG_PHYS_QNUM0_1, 0x2d},
+	{OP_ZR, TCM_REG_PHYS_QNUM1_0, 0x6},
+	{OP_WR, TCM_REG_TCM_STORM0_IFEN, 0x1},
+	{OP_WR, TCM_REG_TCM_STORM1_IFEN, 0x1},
+	{OP_WR, TCM_REG_TCM_TQM_IFEN, 0x1},
+	{OP_WR, TCM_REG_STORM_TCM_IFEN, 0x1},
+	{OP_WR, TCM_REG_TQM_TCM_IFEN, 0x1},
+	{OP_WR, TCM_REG_TSDM_IFEN, 0x1},
+	{OP_WR, TCM_REG_TM_TCM_IFEN, 0x1},
+	{OP_WR, TCM_REG_PRS_IFEN, 0x1},
+	{OP_WR, TCM_REG_PBF_IFEN, 0x1},
+	{OP_WR, TCM_REG_USEM_IFEN, 0x1},
+	{OP_WR, TCM_REG_CSEM_IFEN, 0x1},
+	{OP_WR, TCM_REG_CDU_AG_WR_IFEN, 0x1},
+	{OP_WR, TCM_REG_CDU_AG_RD_IFEN, 0x1},
+	{OP_WR, TCM_REG_CDU_SM_WR_IFEN, 0x1},
+	{OP_WR, TCM_REG_CDU_SM_RD_IFEN, 0x1},
+	{OP_WR, TCM_REG_TCM_CFC_IFEN, 0x1},
+#define TCM_COMMON_END          126
+#define BRB1_COMMON_START       126
+	{OP_SW, BRB1_REG_LL_RAM, 0x2000020},
+	{OP_WR, BRB1_REG_SOFT_RESET, 0x1},
+	{OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_0, 0x0},
+	{OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_1, 0x0},
+	{OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_2, 0x0},
+	{OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_3, 0x0},
+	{OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_0, 0x0},
+	{OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_1, 0x0},
+	{OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_2, 0x0},
+	{OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_3, 0x0},
+	{OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_4, 0x0},
+	{OP_SW, BRB1_REG_FREE_LIST_PRS_CRDT, 0x30220},
+	{OP_WR, BRB1_REG_SOFT_RESET, 0x0},
+#define BRB1_COMMON_END         139
+#define TSEM_COMMON_START       139
+	{OP_RD, TSEM_REG_MSG_NUM_FIC0, 0x0},
+	{OP_RD, TSEM_REG_MSG_NUM_FIC1, 0x0},
+	{OP_RD, TSEM_REG_MSG_NUM_FOC0, 0x0},
+	{OP_RD, TSEM_REG_MSG_NUM_FOC1, 0x0},
+	{OP_RD, TSEM_REG_MSG_NUM_FOC2, 0x0},
+	{OP_RD, TSEM_REG_MSG_NUM_FOC3, 0x0},
+	{OP_WR, TSEM_REG_ARB_ELEMENT0, 0x1},
+	{OP_WR, TSEM_REG_ARB_ELEMENT1, 0x2},
+	{OP_WR, TSEM_REG_ARB_ELEMENT2, 0x3},
+	{OP_WR, TSEM_REG_ARB_ELEMENT3, 0x0},
+	{OP_WR, TSEM_REG_ARB_ELEMENT4, 0x4},
+	{OP_WR, TSEM_REG_ARB_CYCLE_SIZE, 0x1},
+	{OP_WR, TSEM_REG_TS_0_AS, 0x0},
+	{OP_WR, TSEM_REG_TS_1_AS, 0x1},
+	{OP_WR, TSEM_REG_TS_2_AS, 0x4},
+	{OP_WR, TSEM_REG_TS_3_AS, 0x0},
+	{OP_WR, TSEM_REG_TS_4_AS, 0x1},
+	{OP_WR, TSEM_REG_TS_5_AS, 0x3},
+	{OP_WR, TSEM_REG_TS_6_AS, 0x0},
+	{OP_WR, TSEM_REG_TS_7_AS, 0x1},
+	{OP_WR, TSEM_REG_TS_8_AS, 0x4},
+	{OP_WR, TSEM_REG_TS_9_AS, 0x0},
+	{OP_WR, TSEM_REG_TS_10_AS, 0x1},
+	{OP_WR, TSEM_REG_TS_11_AS, 0x3},
+	{OP_WR, TSEM_REG_TS_12_AS, 0x0},
+	{OP_WR, TSEM_REG_TS_13_AS, 0x1},
+	{OP_WR, TSEM_REG_TS_14_AS, 0x4},
+	{OP_WR, TSEM_REG_TS_15_AS, 0x0},
+	{OP_WR, TSEM_REG_TS_16_AS, 0x4},
+	{OP_WR, TSEM_REG_TS_17_AS, 0x3},
+	{OP_ZR, TSEM_REG_TS_18_AS, 0x2},
+	{OP_WR, TSEM_REG_ENABLE_IN, 0x3fff},
+	{OP_WR, TSEM_REG_ENABLE_OUT, 0x3ff},
+	{OP_WR, TSEM_REG_FIC0_DISABLE, 0x0},
+	{OP_WR, TSEM_REG_FIC1_DISABLE, 0x0},
+	{OP_WR, TSEM_REG_PAS_DISABLE, 0x0},
+	{OP_WR, TSEM_REG_THREADS_LIST, 0xff},
+	{OP_ZR, TSEM_REG_PASSIVE_BUFFER, 0x400},
+	{OP_WR, TSEM_REG_FAST_MEMORY + 0x18bc0, 0x1},
+	{OP_WR, TSEM_REG_FAST_MEMORY + 0x18000, 0x34},
+	{OP_WR, TSEM_REG_FAST_MEMORY + 0x18040, 0x18},
+	{OP_WR, TSEM_REG_FAST_MEMORY + 0x18080, 0xc},
+	{OP_WR, TSEM_REG_FAST_MEMORY + 0x180c0, 0x20},
+	{OP_WR, TSEM_REG_FAST_MEMORY + 0x18300, 0x7a120},
+	{OP_WR, TSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x2000, 0x1b3},
+	{OP_SW, TSEM_REG_FAST_MEMORY + 0x2000 + 0x6cc, 0x10223},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x1020, 0xc8},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x1000, 0x2},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x800, 0x2},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x808, 0x2},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x810, 0x4},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x1fa0, 0x4},
+	{OP_SW, TSEM_REG_FAST_MEMORY + 0x4cf0, 0x80224},
+	{OP_ZP, TSEM_REG_INT_TABLE, 0x8c022c},
+	{OP_ZP, TSEM_REG_PRAM, 0x3395024f},
+	{OP_ZP, TSEM_REG_PRAM + 0x8000, 0x2c760f35},
+	{OP_ZP, TSEM_REG_PRAM + 0x10000, 0x5e1a53},
+	{OP_ZP, TSEM_REG_PRAM + 0x18000, 0x5e1a6b},
+	{OP_ZP, TSEM_REG_PRAM + 0x20000, 0x5e1a83},
+	{OP_ZP, TSEM_REG_PRAM + 0x28000, 0x5e1a9b},
+	{OP_ZP, TSEM_REG_PRAM + 0x30000, 0x5e1ab3},
+	{OP_ZP, TSEM_REG_PRAM + 0x38000, 0x5e1acb},
+#define TSEM_COMMON_END         202
+#define TSEM_PORT0_START        202
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x4000, 0x16c},
+	{OP_SW, TSEM_REG_FAST_MEMORY + 0x4000 + 0x5b0, 0x21ae3},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x1370, 0xa},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x13c0, 0x6},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x1418, 0xc},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x1478, 0x12},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x1508, 0x90},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x800, 0x2},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x820, 0x10},
+	{OP_SW, TSEM_REG_FAST_MEMORY + 0x820 + 0x40, 0x21ae5},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x2908, 0xa},
+#define TSEM_PORT0_END          213
+#define TSEM_PORT1_START        213
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x45b8, 0x16c},
+	{OP_SW, TSEM_REG_FAST_MEMORY + 0x45b8 + 0x5b0, 0x21ae7},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x1398, 0xa},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x13d8, 0x6},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x1448, 0xc},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x14c0, 0x12},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x1748, 0x90},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x808, 0x2},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x868, 0x10},
+	{OP_SW, TSEM_REG_FAST_MEMORY + 0x868 + 0x40, 0x21ae9},
+	{OP_ZR, TSEM_REG_FAST_MEMORY + 0x2930, 0xa},
+#define TSEM_PORT1_END          224
+#define MISC_COMMON_START       224
+	{OP_WR, MISC_REG_GRC_TIMEOUT_EN, 0x1},
+	{OP_WR, MISC_REG_PLL_STORM_CTRL_1, 0x71d2911},
+	{OP_WR, MISC_REG_PLL_STORM_CTRL_2, 0x0},
+	{OP_WR, MISC_REG_PLL_STORM_CTRL_3, 0x9c0424},
+	{OP_WR, MISC_REG_PLL_STORM_CTRL_4, 0x0},
+	{OP_WR, MISC_REG_LCPLL_CTRL_1, 0x209},
+#define MISC_COMMON_END         230
+#define NIG_COMMON_START        230
+	{OP_WR, NIG_REG_PBF_LB_IN_EN, 0x1},
+	{OP_WR, NIG_REG_PRS_REQ_IN_EN, 0x1},
+	{OP_WR, NIG_REG_EGRESS_DEBUG_IN_EN, 0x1},
+	{OP_WR, NIG_REG_BRB_LB_OUT_EN, 0x1},
+	{OP_WR, NIG_REG_PRS_EOP_OUT_EN, 0x1},
+#define NIG_COMMON_END          235
+#define NIG_PORT0_START         235
+	{OP_WR, NIG_REG_LLH0_CM_HEADER, 0x300000},
+	{OP_WR, NIG_REG_LLH0_EVENT_ID, 0x26},
+	{OP_WR, NIG_REG_LLH0_ERROR_MASK, 0x0},
+	{OP_WR, NIG_REG_LLH0_XCM_MASK, 0x4},
+	{OP_WR, NIG_REG_LLH0_BRB1_NOT_MCP, 0x1},
+	{OP_WR, NIG_REG_STATUS_INTERRUPT_PORT0, 0x0},
+	{OP_WR, NIG_REG_LLH0_XCM_INIT_CREDIT, 0x30},
+	{OP_WR, NIG_REG_BRB0_PAUSE_IN_EN, 0x1},
+	{OP_WR, NIG_REG_EGRESS_PBF0_IN_EN, 0x1},
+	{OP_WR, NIG_REG_BRB0_OUT_EN, 0x1},
+	{OP_WR, NIG_REG_XCM0_OUT_EN, 0x1},
+#define NIG_PORT0_END           246
+#define NIG_PORT1_START         246
+	{OP_WR, NIG_REG_LLH1_CM_HEADER, 0x300000},
+	{OP_WR, NIG_REG_LLH1_EVENT_ID, 0x26},
+	{OP_WR, NIG_REG_LLH1_ERROR_MASK, 0x0},
+	{OP_WR, NIG_REG_LLH1_XCM_MASK, 0x4},
+	{OP_WR, NIG_REG_LLH1_BRB1_NOT_MCP, 0x1},
+	{OP_WR, NIG_REG_STATUS_INTERRUPT_PORT1, 0x0},
+	{OP_WR, NIG_REG_LLH1_XCM_INIT_CREDIT, 0x30},
+	{OP_WR, NIG_REG_BRB1_PAUSE_IN_EN, 0x1},
+	{OP_WR, NIG_REG_EGRESS_PBF1_IN_EN, 0x1},
+	{OP_WR, NIG_REG_BRB1_OUT_EN, 0x1},
+	{OP_WR, NIG_REG_XCM1_OUT_EN, 0x1},
+#define NIG_PORT1_END           257
+#define UPB_COMMON_START        257
+	{OP_WR, GRCBASE_UPB + PB_REG_CONTROL, 0x20},
+#define UPB_COMMON_END          258
+#define CSDM_COMMON_START       258
+	{OP_WR, CSDM_REG_CFC_RSP_START_ADDR, 0xa11},
+	{OP_WR, CSDM_REG_CMP_COUNTER_START_ADDR, 0xa00},
+	{OP_WR, CSDM_REG_Q_COUNTER_START_ADDR, 0xa04},
+	{OP_WR, CSDM_REG_CMP_COUNTER_MAX0, 0xffff},
+	{OP_WR, CSDM_REG_CMP_COUNTER_MAX1, 0xffff},
+	{OP_WR, CSDM_REG_CMP_COUNTER_MAX2, 0xffff},
+	{OP_WR, CSDM_REG_CMP_COUNTER_MAX3, 0xffff},
+	{OP_ZR, CSDM_REG_AGG_INT_EVENT_0, 0x80},
+	{OP_WR, CSDM_REG_ENABLE_IN1, 0x7ffffff},
+	{OP_WR, CSDM_REG_ENABLE_IN2, 0x3f},
+	{OP_WR, CSDM_REG_ENABLE_OUT1, 0x7ffffff},
+	{OP_WR, CSDM_REG_ENABLE_OUT2, 0xf},
+	{OP_RD, CSDM_REG_NUM_OF_Q0_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_Q1_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_Q3_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_Q4_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_Q5_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_Q6_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_Q7_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_Q8_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_Q9_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_Q10_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_Q11_CMD, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_PKT_END_MSG, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0},
+	{OP_RD, CSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0},
+	{OP_WR, CSDM_REG_TIMER_TICK, 0x3e8},
+#define CSDM_COMMON_END         285
+#define USDM_COMMON_START       285
+	{OP_WR, USDM_REG_CFC_RSP_START_ADDR, 0xa11},
+	{OP_WR, USDM_REG_CMP_COUNTER_START_ADDR, 0xa00},
+	{OP_WR, USDM_REG_Q_COUNTER_START_ADDR, 0xa04},
+	{OP_WR, USDM_REG_PCK_END_MSG_START_ADDR, 0xa21},
+	{OP_WR, USDM_REG_CMP_COUNTER_MAX0, 0xffff},
+	{OP_WR, USDM_REG_CMP_COUNTER_MAX1, 0xffff},
+	{OP_WR, USDM_REG_CMP_COUNTER_MAX2, 0xffff},
+	{OP_WR, USDM_REG_CMP_COUNTER_MAX3, 0xffff},
+	{OP_WR, USDM_REG_AGG_INT_EVENT_0, 0x46},
+	{OP_ZR, USDM_REG_AGG_INT_EVENT_1, 0x5f},
+	{OP_WR, USDM_REG_AGG_INT_MODE_0, 0x1},
+	{OP_ZR, USDM_REG_AGG_INT_MODE_1, 0x1f},
+	{OP_WR, USDM_REG_ENABLE_IN1, 0x7ffffff},
+	{OP_WR, USDM_REG_ENABLE_IN2, 0x3f},
+	{OP_WR, USDM_REG_ENABLE_OUT1, 0x7ffffff},
+	{OP_WR, USDM_REG_ENABLE_OUT2, 0xf},
+	{OP_RD, USDM_REG_NUM_OF_Q0_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q1_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q2_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q3_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q4_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q5_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q6_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q7_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q8_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q9_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q10_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_Q11_CMD, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_PKT_END_MSG, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0},
+	{OP_RD, USDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0},
+	{OP_WR, USDM_REG_TIMER_TICK, 0x3e8},
+#define USDM_COMMON_END         317
+#define CCM_COMMON_START        317
+	{OP_WR, CCM_REG_XX_OVFL_EVNT_ID, 0x32},
+	{OP_WR, CCM_REG_CQM_CCM_HDR_P, 0x2150020},
+	{OP_WR, CCM_REG_CQM_CCM_HDR_S, 0x2150020},
+	{OP_WR, CCM_REG_ERR_CCM_HDR, 0x8100000},
+	{OP_WR, CCM_REG_ERR_EVNT_ID, 0x33},
+	{OP_WR, CCM_REG_TSEM_WEIGHT, 0x0},
+	{OP_WR, CCM_REG_XSEM_WEIGHT, 0x4},
+	{OP_WR, CCM_REG_USEM_WEIGHT, 0x4},
+	{OP_ZR, CCM_REG_PBF_WEIGHT, 0x2},
+	{OP_WR, CCM_REG_CQM_P_WEIGHT, 0x2},
+	{OP_WR, CCM_REG_CCM_CQM_USE_Q, 0x1},
+	{OP_WR, CCM_REG_CNT_AUX1_Q, 0x2},
+	{OP_WR, CCM_REG_CNT_AUX2_Q, 0x2},
+	{OP_WR, CCM_REG_INV_DONE_Q, 0x1},
+	{OP_WR, CCM_REG_GR_ARB_TYPE, 0x1},
+	{OP_WR, CCM_REG_GR_LD0_PR, 0x1},
+	{OP_WR, CCM_REG_GR_LD1_PR, 0x2},
+	{OP_WR, CCM_REG_CFC_INIT_CRD, 0x1},
+	{OP_WR, CCM_REG_CQM_INIT_CRD, 0x20},
+	{OP_WR, CCM_REG_FIC0_INIT_CRD, 0x40},
+	{OP_WR, CCM_REG_FIC1_INIT_CRD, 0x40},
+	{OP_WR, CCM_REG_XX_INIT_CRD, 0x3},
+	{OP_WR, CCM_REG_XX_MSG_NUM, 0x18},
+	{OP_ZR, CCM_REG_XX_TABLE, 0x12},
+	{OP_SW, CCM_REG_XX_DESCR_TABLE, 0x241aeb},
+	{OP_WR, CCM_REG_N_SM_CTX_LD_0, 0x1},
+	{OP_WR, CCM_REG_N_SM_CTX_LD_1, 0x2},
+	{OP_WR, CCM_REG_N_SM_CTX_LD_2, 0x8},
+	{OP_WR, CCM_REG_N_SM_CTX_LD_3, 0x8},
+	{OP_ZR, CCM_REG_N_SM_CTX_LD_4, 0x4},
+	{OP_WR, CCM_REG_CCM_REG0_SZ, 0x4},
+	{OP_WR, CCM_REG_QOS_PHYS_QNUM0_0, 0x9},
+	{OP_WR, CCM_REG_QOS_PHYS_QNUM0_1, 0x29},
+	{OP_WR, CCM_REG_QOS_PHYS_QNUM1_0, 0xa},
+	{OP_WR, CCM_REG_QOS_PHYS_QNUM1_1, 0x2a},
+	{OP_ZR, CCM_REG_QOS_PHYS_QNUM2_0, 0x4},
+	{OP_WR, CCM_REG_PHYS_QNUM1_0, 0xc},
+	{OP_WR, CCM_REG_PHYS_QNUM1_1, 0x2c},
+	{OP_WR, CCM_REG_PHYS_QNUM2_0, 0xb},
+	{OP_WR, CCM_REG_PHYS_QNUM2_1, 0x2b},
+	{OP_ZR, CCM_REG_PHYS_QNUM3_0, 0x2},
+	{OP_WR, CCM_REG_CCM_STORM0_IFEN, 0x1},
+	{OP_WR, CCM_REG_CCM_STORM1_IFEN, 0x1},
+	{OP_WR, CCM_REG_CCM_CQM_IFEN, 0x1},
+	{OP_WR, CCM_REG_STORM_CCM_IFEN, 0x1},
+	{OP_WR, CCM_REG_CQM_CCM_IFEN, 0x1},
+	{OP_WR, CCM_REG_CSDM_IFEN, 0x1},
+	{OP_WR, CCM_REG_TSEM_IFEN, 0x1},
+	{OP_WR, CCM_REG_XSEM_IFEN, 0x1},
+	{OP_WR, CCM_REG_USEM_IFEN, 0x1},
+	{OP_WR, CCM_REG_PBF_IFEN, 0x1},
+	{OP_WR, CCM_REG_CDU_AG_WR_IFEN, 0x1},
+	{OP_WR, CCM_REG_CDU_AG_RD_IFEN, 0x1},
+	{OP_WR, CCM_REG_CDU_SM_WR_IFEN, 0x1},
+	{OP_WR, CCM_REG_CDU_SM_RD_IFEN, 0x1},
+	{OP_WR, CCM_REG_CCM_CFC_IFEN, 0x1},
+#define CCM_COMMON_END          373
+#define UCM_COMMON_START        373
+	{OP_WR, UCM_REG_XX_OVFL_EVNT_ID, 0x32},
+	{OP_WR, UCM_REG_UQM_UCM_HDR_P, 0x2150020},
+	{OP_WR, UCM_REG_UQM_UCM_HDR_S, 0x2150020},
+	{OP_WR, UCM_REG_TM_UCM_HDR, 0x30},
+	{OP_WR, UCM_REG_ERR_UCM_HDR, 0x8100000},
+	{OP_WR, UCM_REG_ERR_EVNT_ID, 0x33},
+	{OP_WR, UCM_REG_EXPR_EVNT_ID, 0x30},
+	{OP_WR, UCM_REG_STOP_EVNT_ID, 0x31},
+	{OP_WR, UCM_REG_TSEM_WEIGHT, 0x3},
+	{OP_WR, UCM_REG_CSEM_WEIGHT, 0x0},
+	{OP_WR, UCM_REG_CP_WEIGHT, 0x0},
+	{OP_WR, UCM_REG_UQM_P_WEIGHT, 0x6},
+	{OP_WR, UCM_REG_UCM_UQM_USE_Q, 0x1},
+	{OP_WR, UCM_REG_INV_CFLG_Q, 0x1},
+	{OP_WR, UCM_REG_GR_ARB_TYPE, 0x1},
+	{OP_WR, UCM_REG_GR_LD0_PR, 0x1},
+	{OP_WR, UCM_REG_GR_LD1_PR, 0x2},
+	{OP_WR, UCM_REG_CFC_INIT_CRD, 0x1},
+	{OP_WR, UCM_REG_FIC0_INIT_CRD, 0x40},
+	{OP_WR, UCM_REG_FIC1_INIT_CRD, 0x40},
+	{OP_WR, UCM_REG_TM_INIT_CRD, 0x4},
+	{OP_WR, UCM_REG_UQM_INIT_CRD, 0x20},
+	{OP_WR, UCM_REG_XX_INIT_CRD, 0xc},
+	{OP_WR, UCM_REG_XX_MSG_NUM, 0x20},
+	{OP_ZR, UCM_REG_XX_TABLE, 0x12},
+	{OP_SW, UCM_REG_XX_DESCR_TABLE, 0x201b0f},
+	{OP_WR, UCM_REG_N_SM_CTX_LD_0, 0xa},
+	{OP_WR, UCM_REG_N_SM_CTX_LD_1, 0x7},
+	{OP_WR, UCM_REG_N_SM_CTX_LD_2, 0xf},
+	{OP_WR, UCM_REG_N_SM_CTX_LD_3, 0x10},
+	{OP_ZR, UCM_REG_N_SM_CTX_LD_4, 0x4},
+	{OP_WR, UCM_REG_UCM_REG0_SZ, 0x3},
+	{OP_WR, UCM_REG_PHYS_QNUM0_0, 0xf},
+	{OP_WR, UCM_REG_PHYS_QNUM0_1, 0x2f},
+	{OP_WR, UCM_REG_PHYS_QNUM1_0, 0xe},
+	{OP_WR, UCM_REG_PHYS_QNUM1_1, 0x2e},
+	{OP_WR, UCM_REG_UCM_STORM0_IFEN, 0x1},
+	{OP_WR, UCM_REG_UCM_STORM1_IFEN, 0x1},
+	{OP_WR, UCM_REG_UCM_UQM_IFEN, 0x1},
+	{OP_WR, UCM_REG_STORM_UCM_IFEN, 0x1},
+	{OP_WR, UCM_REG_UQM_UCM_IFEN, 0x1},
+	{OP_WR, UCM_REG_USDM_IFEN, 0x1},
+	{OP_WR, UCM_REG_TM_UCM_IFEN, 0x1},
+	{OP_WR, UCM_REG_UCM_TM_IFEN, 0x1},
+	{OP_WR, UCM_REG_TSEM_IFEN, 0x1},
+	{OP_WR, UCM_REG_CSEM_IFEN, 0x1},
+	{OP_WR, UCM_REG_XSEM_IFEN, 0x1},
+	{OP_WR, UCM_REG_DORQ_IFEN, 0x1},
+	{OP_WR, UCM_REG_CDU_AG_WR_IFEN, 0x1},
+	{OP_WR, UCM_REG_CDU_AG_RD_IFEN, 0x1},
+	{OP_WR, UCM_REG_CDU_SM_WR_IFEN, 0x1},
+	{OP_WR, UCM_REG_CDU_SM_RD_IFEN, 0x1},
+	{OP_WR, UCM_REG_UCM_CFC_IFEN, 0x1},
+#define UCM_COMMON_END          426
+#define USEM_COMMON_START       426
+	{OP_RD, USEM_REG_MSG_NUM_FIC0, 0x0},
+	{OP_RD, USEM_REG_MSG_NUM_FIC1, 0x0},
+	{OP_RD, USEM_REG_MSG_NUM_FOC0, 0x0},
+	{OP_RD, USEM_REG_MSG_NUM_FOC1, 0x0},
+	{OP_RD, USEM_REG_MSG_NUM_FOC2, 0x0},
+	{OP_RD, USEM_REG_MSG_NUM_FOC3, 0x0},
+	{OP_WR, USEM_REG_ARB_ELEMENT0, 0x1},
+	{OP_WR, USEM_REG_ARB_ELEMENT1, 0x2},
+	{OP_WR, USEM_REG_ARB_ELEMENT2, 0x3},
+	{OP_WR, USEM_REG_ARB_ELEMENT3, 0x0},
+	{OP_WR, USEM_REG_ARB_ELEMENT4, 0x4},
+	{OP_WR, USEM_REG_ARB_CYCLE_SIZE, 0x1},
+	{OP_WR, USEM_REG_TS_0_AS, 0x0},
+	{OP_WR, USEM_REG_TS_1_AS, 0x1},
+	{OP_WR, USEM_REG_TS_2_AS, 0x4},
+	{OP_WR, USEM_REG_TS_3_AS, 0x0},
+	{OP_WR, USEM_REG_TS_4_AS, 0x1},
+	{OP_WR, USEM_REG_TS_5_AS, 0x3},
+	{OP_WR, USEM_REG_TS_6_AS, 0x0},
+	{OP_WR, USEM_REG_TS_7_AS, 0x1},
+	{OP_WR, USEM_REG_TS_8_AS, 0x4},
+	{OP_WR, USEM_REG_TS_9_AS, 0x0},
+	{OP_WR, USEM_REG_TS_10_AS, 0x1},
+	{OP_WR, USEM_REG_TS_11_AS, 0x3},
+	{OP_WR, USEM_REG_TS_12_AS, 0x0},
+	{OP_WR, USEM_REG_TS_13_AS, 0x1},
+	{OP_WR, USEM_REG_TS_14_AS, 0x4},
+	{OP_WR, USEM_REG_TS_15_AS, 0x0},
+	{OP_WR, USEM_REG_TS_16_AS, 0x4},
+	{OP_WR, USEM_REG_TS_17_AS, 0x3},
+	{OP_ZR, USEM_REG_TS_18_AS, 0x2},
+	{OP_WR, USEM_REG_ENABLE_IN, 0x3fff},
+	{OP_WR, USEM_REG_ENABLE_OUT, 0x3ff},
+	{OP_WR, USEM_REG_FIC0_DISABLE, 0x0},
+	{OP_WR, USEM_REG_FIC1_DISABLE, 0x0},
+	{OP_WR, USEM_REG_PAS_DISABLE, 0x0},
+	{OP_WR, USEM_REG_THREADS_LIST, 0xffff},
+	{OP_ZR, USEM_REG_PASSIVE_BUFFER, 0x800},
+	{OP_WR, USEM_REG_FAST_MEMORY + 0x18bc0, 0x1},
+	{OP_WR, USEM_REG_FAST_MEMORY + 0x18000, 0x1a},
+	{OP_WR, USEM_REG_FAST_MEMORY + 0x18040, 0x4e},
+	{OP_WR, USEM_REG_FAST_MEMORY + 0x18080, 0x10},
+	{OP_WR, USEM_REG_FAST_MEMORY + 0x180c0, 0x20},
+	{OP_WR, USEM_REG_FAST_MEMORY + 0x18300, 0x7a120},
+	{OP_WR, USEM_REG_FAST_MEMORY + 0x183c0, 0x1f4},
+	{OP_WR, USEM_REG_FAST_MEMORY + 0x18380, 0x1dcd6500},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x5000, 0x102},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1020, 0xc8},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1000, 0x2},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1e20, 0x40},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3000, 0x400},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x2400, 0x2},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x2408, 0x2},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x2410, 0x6},
+	{OP_SW, USEM_REG_FAST_MEMORY + 0x2410 + 0x18, 0x21b2f},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x4b68, 0x2},
+	{OP_SW, USEM_REG_FAST_MEMORY + 0x4b68 + 0x8, 0x21b31},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x4b10, 0x2},
+	{OP_SW, USEM_REG_FAST_MEMORY + 0x2c30, 0x21b33},
+	{OP_WR, USEM_REG_FAST_MEMORY + 0x10800, 0x1000000},
+	{OP_SW, USEM_REG_FAST_MEMORY + 0x10c00, 0x101b35},
+	{OP_WR, USEM_REG_FAST_MEMORY + 0x10800, 0x0},
+	{OP_SW, USEM_REG_FAST_MEMORY + 0x10c40, 0x101b45},
+	{OP_ZP, USEM_REG_INT_TABLE, 0xb41b55},
+	{OP_ZP, USEM_REG_PRAM, 0x32d01b82},
+	{OP_ZP, USEM_REG_PRAM + 0x8000, 0x32172836},
+	{OP_ZP, USEM_REG_PRAM + 0x10000, 0x1a7a34bc},
+	{OP_ZP, USEM_REG_PRAM + 0x18000, 0x5f3b5b},
+	{OP_ZP, USEM_REG_PRAM + 0x20000, 0x5f3b73},
+	{OP_ZP, USEM_REG_PRAM + 0x28000, 0x5f3b8b},
+	{OP_ZP, USEM_REG_PRAM + 0x30000, 0x5f3ba3},
+	{OP_ZP, USEM_REG_PRAM + 0x38000, 0x5f3bbb},
+#define USEM_COMMON_END         498
+#define USEM_PORT0_START        498
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1400, 0xa0},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1900, 0xa},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1950, 0x2e},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1d00, 0x24},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3000, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3100, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3200, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3300, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3400, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3500, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3600, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3700, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3800, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3900, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3a00, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3b00, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3c00, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3d00, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3e00, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3f00, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x2400, 0x2},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x4b78, 0x52},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x4e08, 0xc},
+#define USEM_PORT0_END          521
+#define USEM_PORT1_START        521
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1680, 0xa0},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1928, 0xa},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1a08, 0x2e},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x1d90, 0x24},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3080, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3180, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3280, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3380, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3480, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3580, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3680, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3780, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3880, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3980, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3a80, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3b80, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3c80, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3d80, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3e80, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x3f80, 0x20},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x2408, 0x2},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x4cc0, 0x52},
+	{OP_ZR, USEM_REG_FAST_MEMORY + 0x4e38, 0xc},
+#define USEM_PORT1_END          544
+#define CSEM_COMMON_START       544
+	{OP_RD, CSEM_REG_MSG_NUM_FIC0, 0x0},
+	{OP_RD, CSEM_REG_MSG_NUM_FIC1, 0x0},
+	{OP_RD, CSEM_REG_MSG_NUM_FOC0, 0x0},
+	{OP_RD, CSEM_REG_MSG_NUM_FOC1, 0x0},
+	{OP_RD, CSEM_REG_MSG_NUM_FOC2, 0x0},
+	{OP_RD, CSEM_REG_MSG_NUM_FOC3, 0x0},
+	{OP_WR, CSEM_REG_ARB_ELEMENT0, 0x1},
+	{OP_WR, CSEM_REG_ARB_ELEMENT1, 0x2},
+	{OP_WR, CSEM_REG_ARB_ELEMENT2, 0x3},
+	{OP_WR, CSEM_REG_ARB_ELEMENT3, 0x0},
+	{OP_WR, CSEM_REG_ARB_ELEMENT4, 0x4},
+	{OP_WR, CSEM_REG_ARB_CYCLE_SIZE, 0x1},
+	{OP_WR, CSEM_REG_TS_0_AS, 0x0},
+	{OP_WR, CSEM_REG_TS_1_AS, 0x1},
+	{OP_WR, CSEM_REG_TS_2_AS, 0x4},
+	{OP_WR, CSEM_REG_TS_3_AS, 0x0},
+	{OP_WR, CSEM_REG_TS_4_AS, 0x1},
+	{OP_WR, CSEM_REG_TS_5_AS, 0x3},
+	{OP_WR, CSEM_REG_TS_6_AS, 0x0},
+	{OP_WR, CSEM_REG_TS_7_AS, 0x1},
+	{OP_WR, CSEM_REG_TS_8_AS, 0x4},
+	{OP_WR, CSEM_REG_TS_9_AS, 0x0},
+	{OP_WR, CSEM_REG_TS_10_AS, 0x1},
+	{OP_WR, CSEM_REG_TS_11_AS, 0x3},
+	{OP_WR, CSEM_REG_TS_12_AS, 0x0},
+	{OP_WR, CSEM_REG_TS_13_AS, 0x1},
+	{OP_WR, CSEM_REG_TS_14_AS, 0x4},
+	{OP_WR, CSEM_REG_TS_15_AS, 0x0},
+	{OP_WR, CSEM_REG_TS_16_AS, 0x4},
+	{OP_WR, CSEM_REG_TS_17_AS, 0x3},
+	{OP_ZR, CSEM_REG_TS_18_AS, 0x2},
+	{OP_WR, CSEM_REG_ENABLE_IN, 0x3fff},
+	{OP_WR, CSEM_REG_ENABLE_OUT, 0x3ff},
+	{OP_WR, CSEM_REG_FIC0_DISABLE, 0x0},
+	{OP_WR, CSEM_REG_FIC1_DISABLE, 0x0},
+	{OP_WR, CSEM_REG_PAS_DISABLE, 0x0},
+	{OP_WR, CSEM_REG_THREADS_LIST, 0xffff},
+	{OP_ZR, CSEM_REG_PASSIVE_BUFFER, 0x800},
+	{OP_WR, CSEM_REG_FAST_MEMORY + 0x18bc0, 0x1},
+	{OP_WR, CSEM_REG_FAST_MEMORY + 0x18000, 0x10},
+	{OP_WR, CSEM_REG_FAST_MEMORY + 0x18040, 0x12},
+	{OP_WR, CSEM_REG_FAST_MEMORY + 0x18080, 0x30},
+	{OP_WR, CSEM_REG_FAST_MEMORY + 0x180c0, 0xe},
+	{OP_WR, CSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x5000, 0x42},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x1020, 0xc8},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x1000, 0x2},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x2000, 0xc0},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x3070, 0x80},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x4280, 0x4},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x25c0, 0x240},
+	{OP_SW, CSEM_REG_FAST_MEMORY + 0x25c0 + 0x900, 0x83bd3},
+	{OP_WR, CSEM_REG_FAST_MEMORY + 0x10800, 0x13fffff},
+	{OP_SW, CSEM_REG_FAST_MEMORY + 0x10c00, 0x103bdb},
+	{OP_WR, CSEM_REG_FAST_MEMORY + 0x10800, 0x0},
+	{OP_SW, CSEM_REG_FAST_MEMORY + 0x10c40, 0x103beb},
+	{OP_ZP, CSEM_REG_INT_TABLE, 0x5f3bfb},
+	{OP_ZP, CSEM_REG_PRAM, 0x32423c13},
+	{OP_ZP, CSEM_REG_PRAM + 0x8000, 0xf2148a4},
+	{OP_ZP, CSEM_REG_PRAM + 0x10000, 0x5f4c6d},
+	{OP_ZP, CSEM_REG_PRAM + 0x18000, 0x5f4c85},
+	{OP_ZP, CSEM_REG_PRAM + 0x20000, 0x5f4c9d},
+	{OP_ZP, CSEM_REG_PRAM + 0x28000, 0x5f4cb5},
+	{OP_ZP, CSEM_REG_PRAM + 0x30000, 0x5f4ccd},
+	{OP_ZP, CSEM_REG_PRAM + 0x38000, 0x5f4ce5},
+#define CSEM_COMMON_END         609
+#define CSEM_PORT0_START        609
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x1400, 0xa0},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x1900, 0x10},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x1980, 0x30},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x2300, 0x2},
+	{OP_SW, CSEM_REG_FAST_MEMORY + 0x2300 + 0x8, 0x24cfd},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x3040, 0x6},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x2410, 0x30},
+#define CSEM_PORT0_END          616
+#define CSEM_PORT1_START        616
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x1680, 0xa0},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x1940, 0x10},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x1a40, 0x30},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x2310, 0x2},
+	{OP_SW, CSEM_REG_FAST_MEMORY + 0x2310 + 0x8, 0x24cff},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x3058, 0x6},
+	{OP_ZR, CSEM_REG_FAST_MEMORY + 0x24d0, 0x30},
+#define CSEM_PORT1_END          623
+#define XPB_COMMON_START        623
+	{OP_WR, GRCBASE_XPB + PB_REG_CONTROL, 0x20},
+#define XPB_COMMON_END          624
+#define DQ_COMMON_START         624
+	{OP_WR, DORQ_REG_MODE_ACT, 0x2},
+	{OP_WR, DORQ_REG_NORM_CID_OFST, 0x3},
+	{OP_WR, DORQ_REG_OUTST_REQ, 0x4},
+	{OP_WR, DORQ_REG_DPM_CID_ADDR, 0x8},
+	{OP_WR, DORQ_REG_RSP_INIT_CRD, 0x2},
+	{OP_WR, DORQ_REG_NORM_CMHEAD_TX, 0x90},
+	{OP_WR, DORQ_REG_CMHEAD_RX, 0x90},
+	{OP_WR, DORQ_REG_SHRT_CMHEAD, 0x800090},
+	{OP_WR, DORQ_REG_ERR_CMHEAD, 0x8140000},
+	{OP_WR, DORQ_REG_AGG_CMD0, 0x8a},
+	{OP_WR, DORQ_REG_AGG_CMD1, 0x80},
+	{OP_WR, DORQ_REG_AGG_CMD2, 0x90},
+	{OP_WR, DORQ_REG_AGG_CMD3, 0x80},
+	{OP_WR, DORQ_REG_SHRT_ACT_CNT, 0x6},
+	{OP_WR, DORQ_REG_DQ_FIFO_FULL_TH, 0x7d0},
+	{OP_WR, DORQ_REG_DQ_FIFO_AFULL_TH, 0x76c},
+	{OP_WR, DORQ_REG_REGN, 0x7c1004},
+	{OP_WR, DORQ_REG_IF_EN, 0xf},
+#define DQ_COMMON_END           642
+#define TIMERS_COMMON_START     642
+	{OP_ZR, TM_REG_CLIN_PRIOR0_CLIENT, 0x2},
+	{OP_WR, TM_REG_LIN_SETCLR_FIFO_ALFULL_THR, 0x1c},
+	{OP_WR, TM_REG_CFC_AC_CRDCNT_VAL, 0x1},
+	{OP_WR, TM_REG_CFC_CLD_CRDCNT_VAL, 0x1},
+	{OP_WR, TM_REG_CLOUT_CRDCNT0_VAL, 0x1},
+	{OP_WR, TM_REG_CLOUT_CRDCNT1_VAL, 0x1},
+	{OP_WR, TM_REG_CLOUT_CRDCNT2_VAL, 0x1},
+	{OP_WR, TM_REG_EXP_CRDCNT_VAL, 0x1},
+	{OP_WR, TM_REG_PCIARB_CRDCNT_VAL, 0x2},
+	{OP_WR, TM_REG_TIMER_TICK_SIZE, 0x3d090},
+	{OP_WR, TM_REG_CL0_CONT_REGION, 0x8},
+	{OP_WR, TM_REG_CL1_CONT_REGION, 0xc},
+	{OP_WR, TM_REG_CL2_CONT_REGION, 0x10},
+	{OP_WR, TM_REG_TM_CONTEXT_REGION, 0x20},
+	{OP_WR, TM_REG_EN_TIMERS, 0x1},
+	{OP_WR, TM_REG_EN_REAL_TIME_CNT, 0x1},
+	{OP_WR, TM_REG_EN_CL0_INPUT, 0x1},
+	{OP_WR, TM_REG_EN_CL1_INPUT, 0x1},
+	{OP_WR, TM_REG_EN_CL2_INPUT, 0x1},
+#define TIMERS_COMMON_END       661
+#define TIMERS_PORT0_START      661
+	{OP_ZR, TM_REG_LIN0_PHY_ADDR, 0x2},
+#define TIMERS_PORT0_END        662
+#define TIMERS_PORT1_START      662
+	{OP_ZR, TM_REG_LIN1_PHY_ADDR, 0x2},
+#define TIMERS_PORT1_END        663
+#define XSDM_COMMON_START       663
+	{OP_WR, XSDM_REG_CFC_RSP_START_ADDR, 0xa14},
+	{OP_WR, XSDM_REG_CMP_COUNTER_START_ADDR, 0xa00},
+	{OP_WR, XSDM_REG_Q_COUNTER_START_ADDR, 0xa04},
+	{OP_WR, XSDM_REG_CMP_COUNTER_MAX0, 0xffff},
+	{OP_WR, XSDM_REG_CMP_COUNTER_MAX1, 0xffff},
+	{OP_WR, XSDM_REG_CMP_COUNTER_MAX2, 0xffff},
+	{OP_WR, XSDM_REG_CMP_COUNTER_MAX3, 0xffff},
+	{OP_WR, XSDM_REG_AGG_INT_EVENT_0, 0x20},
+	{OP_WR, XSDM_REG_AGG_INT_EVENT_1, 0x20},
+	{OP_ZR, XSDM_REG_AGG_INT_EVENT_2, 0x5e},
+	{OP_WR, XSDM_REG_AGG_INT_MODE_0, 0x1},
+	{OP_ZR, XSDM_REG_AGG_INT_MODE_1, 0x1f},
+	{OP_WR, XSDM_REG_ENABLE_IN1, 0x7ffffff},
+	{OP_WR, XSDM_REG_ENABLE_IN2, 0x3f},
+	{OP_WR, XSDM_REG_ENABLE_OUT1, 0x7ffffff},
+	{OP_WR, XSDM_REG_ENABLE_OUT2, 0xf},
+	{OP_RD, XSDM_REG_NUM_OF_Q0_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_Q1_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_Q3_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_Q4_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_Q5_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_Q6_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_Q7_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_Q8_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_Q9_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_Q10_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_Q11_CMD, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_PKT_END_MSG, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0},
+	{OP_RD, XSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0},
+	{OP_WR, XSDM_REG_TIMER_TICK, 0x3e8},
+#define XSDM_COMMON_END         694
+#define QM_COMMON_START         694
+	{OP_WR, QM_REG_ACTCTRINITVAL_0, 0x6},
+	{OP_WR, QM_REG_ACTCTRINITVAL_1, 0x5},
+	{OP_WR, QM_REG_ACTCTRINITVAL_2, 0xa},
+	{OP_WR, QM_REG_ACTCTRINITVAL_3, 0x5},
+	{OP_WR, QM_REG_PCIREQAT, 0x2},
+	{OP_WR, QM_REG_CMINITCRD_0, 0x4},
+	{OP_WR, QM_REG_CMINITCRD_1, 0x4},
+	{OP_WR, QM_REG_CMINITCRD_2, 0x4},
+	{OP_WR, QM_REG_CMINITCRD_3, 0x4},
+	{OP_WR, QM_REG_CMINITCRD_4, 0x4},
+	{OP_WR, QM_REG_CMINITCRD_5, 0x4},
+	{OP_WR, QM_REG_CMINITCRD_6, 0x4},
+	{OP_WR, QM_REG_CMINITCRD_7, 0x4},
+	{OP_WR, QM_REG_OUTLDREQ, 0x4},
+	{OP_WR, QM_REG_CTXREG_0, 0x7c},
+	{OP_WR, QM_REG_CTXREG_1, 0x3d},
+	{OP_WR, QM_REG_CTXREG_2, 0x3f},
+	{OP_WR, QM_REG_CTXREG_3, 0x9c},
+	{OP_WR, QM_REG_ENSEC, 0x7},
+	{OP_ZR, QM_REG_QVOQIDX_0, 0x5},
+	{OP_WR, QM_REG_WRRWEIGHTS_0, 0x1010101},
+	{OP_WR, QM_REG_QVOQIDX_5, 0x0},
+	{OP_WR, QM_REG_QVOQIDX_6, 0x4},
+	{OP_WR, QM_REG_QVOQIDX_7, 0x4},
+	{OP_WR, QM_REG_QVOQIDX_8, 0x2},
+	{OP_WR, QM_REG_WRRWEIGHTS_1, 0x8012004},
+	{OP_WR, QM_REG_QVOQIDX_9, 0x5},
+	{OP_WR, QM_REG_QVOQIDX_10, 0x5},
+	{OP_WR, QM_REG_QVOQIDX_11, 0x5},
+	{OP_WR, QM_REG_QVOQIDX_12, 0x5},
+	{OP_WR, QM_REG_WRRWEIGHTS_2, 0x20081001},
+	{OP_WR, QM_REG_QVOQIDX_13, 0x8},
+	{OP_WR, QM_REG_QVOQIDX_14, 0x6},
+	{OP_WR, QM_REG_QVOQIDX_15, 0x7},
+	{OP_WR, QM_REG_QVOQIDX_16, 0x0},
+	{OP_WR, QM_REG_WRRWEIGHTS_3, 0x1010120},
+	{OP_ZR, QM_REG_QVOQIDX_17, 0x4},
+	{OP_WR, QM_REG_WRRWEIGHTS_4, 0x1010101},
+	{OP_ZR, QM_REG_QVOQIDX_21, 0x4},
+	{OP_WR, QM_REG_WRRWEIGHTS_5, 0x1010101},
+	{OP_ZR, QM_REG_QVOQIDX_25, 0x4},
+	{OP_WR, QM_REG_WRRWEIGHTS_6, 0x1010101},
+	{OP_ZR, QM_REG_QVOQIDX_29, 0x3},
+	{OP_WR, QM_REG_QVOQIDX_32, 0x1},
+	{OP_WR, QM_REG_WRRWEIGHTS_7, 0x1010101},
+	{OP_WR, QM_REG_QVOQIDX_33, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_34, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_35, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_36, 0x1},
+	{OP_WR, QM_REG_WRRWEIGHTS_8, 0x1010101},
+	{OP_WR, QM_REG_QVOQIDX_37, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_38, 0x4},
+	{OP_WR, QM_REG_QVOQIDX_39, 0x4},
+	{OP_WR, QM_REG_QVOQIDX_40, 0x2},
+	{OP_WR, QM_REG_WRRWEIGHTS_9, 0x8012004},
+	{OP_WR, QM_REG_QVOQIDX_41, 0x5},
+	{OP_WR, QM_REG_QVOQIDX_42, 0x5},
+	{OP_WR, QM_REG_QVOQIDX_43, 0x5},
+	{OP_WR, QM_REG_QVOQIDX_44, 0x5},
+	{OP_WR, QM_REG_WRRWEIGHTS_10, 0x20081001},
+	{OP_WR, QM_REG_QVOQIDX_45, 0x8},
+	{OP_WR, QM_REG_QVOQIDX_46, 0x6},
+	{OP_WR, QM_REG_QVOQIDX_47, 0x7},
+	{OP_WR, QM_REG_QVOQIDX_48, 0x1},
+	{OP_WR, QM_REG_WRRWEIGHTS_11, 0x1010120},
+	{OP_WR, QM_REG_QVOQIDX_49, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_50, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_51, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_52, 0x1},
+	{OP_WR, QM_REG_WRRWEIGHTS_12, 0x1010101},
+	{OP_WR, QM_REG_QVOQIDX_53, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_54, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_55, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_56, 0x1},
+	{OP_WR, QM_REG_WRRWEIGHTS_13, 0x1010101},
+	{OP_WR, QM_REG_QVOQIDX_57, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_58, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_59, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_60, 0x1},
+	{OP_WR, QM_REG_WRRWEIGHTS_14, 0x1010101},
+	{OP_WR, QM_REG_QVOQIDX_61, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_62, 0x1},
+	{OP_WR, QM_REG_QVOQIDX_63, 0x1},
+	{OP_WR, QM_REG_WRRWEIGHTS_15, 0x1010101},
+	{OP_WR, QM_REG_VOQQMASK_0_LSB, 0xffff003f},
+	{OP_ZR, QM_REG_VOQQMASK_0_MSB, 0x2},
+	{OP_WR, QM_REG_VOQQMASK_1_MSB, 0xffff003f},
+	{OP_WR, QM_REG_VOQQMASK_2_LSB, 0x100},
+	{OP_WR, QM_REG_VOQQMASK_2_MSB, 0x100},
+	{OP_ZR, QM_REG_VOQQMASK_3_LSB, 0x2},
+	{OP_WR, QM_REG_VOQQMASK_4_LSB, 0xc0},
+	{OP_WR, QM_REG_VOQQMASK_4_MSB, 0xc0},
+	{OP_WR, QM_REG_VOQQMASK_5_LSB, 0x1e00},
+	{OP_WR, QM_REG_VOQQMASK_5_MSB, 0x1e00},
+	{OP_WR, QM_REG_VOQQMASK_6_LSB, 0x4000},
+	{OP_WR, QM_REG_VOQQMASK_6_MSB, 0x4000},
+	{OP_WR, QM_REG_VOQQMASK_7_LSB, 0x8000},
+	{OP_WR, QM_REG_VOQQMASK_7_MSB, 0x8000},
+	{OP_WR, QM_REG_VOQQMASK_8_LSB, 0x2000},
+	{OP_WR, QM_REG_VOQQMASK_8_MSB, 0x2000},
+	{OP_ZR, QM_REG_VOQQMASK_9_LSB, 0x7},
+	{OP_WR, QM_REG_VOQPORT_1, 0x1},
+	{OP_ZR, QM_REG_VOQPORT_2, 0xa},
+	{OP_WR, QM_REG_CMINTVOQMASK_0, 0xc08},
+	{OP_WR, QM_REG_CMINTVOQMASK_1, 0x40},
+	{OP_WR, QM_REG_CMINTVOQMASK_2, 0x100},
+	{OP_WR, QM_REG_CMINTVOQMASK_3, 0x20},
+	{OP_WR, QM_REG_CMINTVOQMASK_4, 0x17},
+	{OP_WR, QM_REG_CMINTVOQMASK_5, 0x80},
+	{OP_WR, QM_REG_CMINTVOQMASK_6, 0x200},
+	{OP_WR, QM_REG_CMINTVOQMASK_7, 0x0},
+	{OP_WR, QM_REG_HWAEMPTYMASK_LSB, 0xffff01ff},
+	{OP_WR, QM_REG_HWAEMPTYMASK_MSB, 0xffff01ff},
+	{OP_WR, QM_REG_ENBYPVOQMASK, 0x13},
+	{OP_WR, QM_REG_VOQCREDITAFULLTHR, 0x13f},
+	{OP_WR, QM_REG_VOQINITCREDIT_0, 0x140},
+	{OP_WR, QM_REG_VOQINITCREDIT_1, 0x140},
+	{OP_ZR, QM_REG_VOQINITCREDIT_2, 0x2},
+	{OP_WR, QM_REG_VOQINITCREDIT_4, 0xc0},
+	{OP_ZR, QM_REG_VOQINITCREDIT_5, 0x7},
+	{OP_WR, QM_REG_TASKCRDCOST_0, 0x48},
+	{OP_WR, QM_REG_TASKCRDCOST_1, 0x48},
+	{OP_ZR, QM_REG_TASKCRDCOST_2, 0x2},
+	{OP_WR, QM_REG_TASKCRDCOST_4, 0x48},
+	{OP_ZR, QM_REG_TASKCRDCOST_5, 0x7},
+	{OP_WR, QM_REG_BYTECRDINITVAL, 0x8000},
+	{OP_WR, QM_REG_BYTECRDCOST, 0x25e4},
+	{OP_WR, QM_REG_BYTECREDITAFULLTHR, 0x7fff},
+	{OP_WR, QM_REG_ENBYTECRD_LSB, 0x7},
+	{OP_WR, QM_REG_ENBYTECRD_MSB, 0x7},
+	{OP_WR, QM_REG_BYTECRDPORT_LSB, 0x0},
+	{OP_WR, QM_REG_BYTECRDPORT_MSB, 0xffffffff},
+	{OP_WR, QM_REG_FUNCNUMSEL_LSB, 0x0},
+	{OP_WR, QM_REG_FUNCNUMSEL_MSB, 0xffffffff},
+	{OP_WR, QM_REG_CMINTEN, 0xff},
+#define QM_COMMON_END           829
+#define PBF_COMMON_START        829
+	{OP_WR, PBF_REG_INIT, 0x1},
+	{OP_WR, PBF_REG_INIT_P4, 0x1},
+	{OP_WR, PBF_REG_MAC_LB_ENABLE, 0x1},
+	{OP_WR, PBF_REG_IF_ENABLE_REG, 0x7fff},
+	{OP_WR, PBF_REG_INIT_P4, 0x0},
+	{OP_WR, PBF_REG_INIT, 0x0},
+	{OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P4, 0x0},
+#define PBF_COMMON_END          836
+#define PBF_PORT0_START         836
+	{OP_WR, PBF_REG_INIT_P0, 0x1},
+	{OP_WR, PBF_REG_MAC_IF0_ENABLE, 0x1},
+	{OP_WR, PBF_REG_INIT_P0, 0x0},
+	{OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P0, 0x0},
+#define PBF_PORT0_END           840
+#define PBF_PORT1_START         840
+	{OP_WR, PBF_REG_INIT_P1, 0x1},
+	{OP_WR, PBF_REG_MAC_IF1_ENABLE, 0x1},
+	{OP_WR, PBF_REG_INIT_P1, 0x0},
+	{OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P1, 0x0},
+#define PBF_PORT1_END           844
+#define XCM_COMMON_START        844
+	{OP_WR, XCM_REG_XX_OVFL_EVNT_ID, 0x32},
+	{OP_WR, XCM_REG_XQM_XCM_HDR_P, 0x3150020},
+	{OP_WR, XCM_REG_XQM_XCM_HDR_S, 0x3150020},
+	{OP_WR, XCM_REG_TM_XCM_HDR, 0x1000030},
+	{OP_WR, XCM_REG_ERR_XCM_HDR, 0x8100000},
+	{OP_WR, XCM_REG_ERR_EVNT_ID, 0x33},
+	{OP_WR, XCM_REG_EXPR_EVNT_ID, 0x30},
+	{OP_WR, XCM_REG_STOP_EVNT_ID, 0x31},
+	{OP_WR, XCM_REG_STORM_WEIGHT, 0x2},
+	{OP_WR, XCM_REG_TSEM_WEIGHT, 0x5},
+	{OP_WR, XCM_REG_CSEM_WEIGHT, 0x2},
+	{OP_WR, XCM_REG_USEM_WEIGHT, 0x2},
+	{OP_WR, XCM_REG_PBF_WEIGHT, 0x7},
+	{OP_WR, XCM_REG_NIG1_WEIGHT, 0x1},
+	{OP_WR, XCM_REG_CP_WEIGHT, 0x0},
+	{OP_WR, XCM_REG_XSDM_WEIGHT, 0x5},
+	{OP_WR, XCM_REG_XQM_P_WEIGHT, 0x3},
+	{OP_WR, XCM_REG_XCM_XQM_USE_Q, 0x1},
+	{OP_WR, XCM_REG_XQM_BYP_ACT_UPD, 0x6},
+	{OP_WR, XCM_REG_UNA_GT_NXT_Q, 0x0},
+	{OP_WR, XCM_REG_AUX1_Q, 0x2},
+	{OP_WR, XCM_REG_AUX_CNT_FLG_Q_19, 0x1},
+	{OP_WR, XCM_REG_GR_ARB_TYPE, 0x1},
+	{OP_WR, XCM_REG_GR_LD0_PR, 0x1},
+	{OP_WR, XCM_REG_GR_LD1_PR, 0x2},
+	{OP_WR, XCM_REG_CFC_INIT_CRD, 0x1},
+	{OP_WR, XCM_REG_FIC0_INIT_CRD, 0x40},
+	{OP_WR, XCM_REG_FIC1_INIT_CRD, 0x40},
+	{OP_WR, XCM_REG_TM_INIT_CRD, 0x4},
+	{OP_WR, XCM_REG_XQM_INIT_CRD, 0x20},
+	{OP_WR, XCM_REG_XX_INIT_CRD, 0x2},
+	{OP_WR, XCM_REG_XX_MSG_NUM, 0x1f},
+	{OP_ZR, XCM_REG_XX_TABLE, 0x12},
+	{OP_SW, XCM_REG_XX_DESCR_TABLE, 0x1f4d01},
+	{OP_WR, XCM_REG_N_SM_CTX_LD_0, 0xf},
+	{OP_WR, XCM_REG_N_SM_CTX_LD_1, 0x7},
+	{OP_WR, XCM_REG_N_SM_CTX_LD_2, 0xb},
+	{OP_WR, XCM_REG_N_SM_CTX_LD_3, 0xe},
+	{OP_ZR, XCM_REG_N_SM_CTX_LD_4, 0x4},
+	{OP_WR, XCM_REG_XCM_REG0_SZ, 0x4},
+	{OP_WR, XCM_REG_XCM_STORM0_IFEN, 0x1},
+	{OP_WR, XCM_REG_XCM_STORM1_IFEN, 0x1},
+	{OP_WR, XCM_REG_XCM_XQM_IFEN, 0x1},
+	{OP_WR, XCM_REG_STORM_XCM_IFEN, 0x1},
+	{OP_WR, XCM_REG_XQM_XCM_IFEN, 0x1},
+	{OP_WR, XCM_REG_XSDM_IFEN, 0x1},
+	{OP_WR, XCM_REG_TM_XCM_IFEN, 0x1},
+	{OP_WR, XCM_REG_XCM_TM_IFEN, 0x1},
+	{OP_WR, XCM_REG_TSEM_IFEN, 0x1},
+	{OP_WR, XCM_REG_CSEM_IFEN, 0x1},
+	{OP_WR, XCM_REG_USEM_IFEN, 0x1},
+	{OP_WR, XCM_REG_DORQ_IFEN, 0x1},
+	{OP_WR, XCM_REG_PBF_IFEN, 0x1},
+	{OP_WR, XCM_REG_NIG0_IFEN, 0x1},
+	{OP_WR, XCM_REG_NIG1_IFEN, 0x1},
+	{OP_WR, XCM_REG_CDU_AG_WR_IFEN, 0x1},
+	{OP_WR, XCM_REG_CDU_AG_RD_IFEN, 0x1},
+	{OP_WR, XCM_REG_CDU_SM_WR_IFEN, 0x1},
+	{OP_WR, XCM_REG_CDU_SM_RD_IFEN, 0x1},
+	{OP_WR, XCM_REG_XCM_CFC_IFEN, 0x1},
+#define XCM_COMMON_END          904
+#define XCM_PORT0_START         904
+	{OP_WR, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8},
+	{OP_WR, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2},
+	{OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0},
+	{OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0},
+	{OP_WR, XCM_REG_WU_DA_CNT_CMD00, 0x2},
+	{OP_WR, XCM_REG_WU_DA_CNT_CMD10, 0x2},
+	{OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff},
+	{OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff},
+#define XCM_PORT0_END           912
+#define XCM_PORT1_START         912
+	{OP_WR, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8},
+	{OP_WR, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2},
+	{OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0},
+	{OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0},
+	{OP_WR, XCM_REG_WU_DA_CNT_CMD01, 0x2},
+	{OP_WR, XCM_REG_WU_DA_CNT_CMD11, 0x2},
+	{OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff},
+	{OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff},
+#define XCM_PORT1_END           920
+#define XSEM_COMMON_START       920
+	{OP_RD, XSEM_REG_MSG_NUM_FIC0, 0x0},
+	{OP_RD, XSEM_REG_MSG_NUM_FIC1, 0x0},
+	{OP_RD, XSEM_REG_MSG_NUM_FOC0, 0x0},
+	{OP_RD, XSEM_REG_MSG_NUM_FOC1, 0x0},
+	{OP_RD, XSEM_REG_MSG_NUM_FOC2, 0x0},
+	{OP_RD, XSEM_REG_MSG_NUM_FOC3, 0x0},
+	{OP_WR, XSEM_REG_ARB_ELEMENT0, 0x1},
+	{OP_WR, XSEM_REG_ARB_ELEMENT1, 0x2},
+	{OP_WR, XSEM_REG_ARB_ELEMENT2, 0x3},
+	{OP_WR, XSEM_REG_ARB_ELEMENT3, 0x0},
+	{OP_WR, XSEM_REG_ARB_ELEMENT4, 0x4},
+	{OP_WR, XSEM_REG_ARB_CYCLE_SIZE, 0x1},
+	{OP_WR, XSEM_REG_TS_0_AS, 0x0},
+	{OP_WR, XSEM_REG_TS_1_AS, 0x1},
+	{OP_WR, XSEM_REG_TS_2_AS, 0x4},
+	{OP_WR, XSEM_REG_TS_3_AS, 0x0},
+	{OP_WR, XSEM_REG_TS_4_AS, 0x1},
+	{OP_WR, XSEM_REG_TS_5_AS, 0x3},
+	{OP_WR, XSEM_REG_TS_6_AS, 0x0},
+	{OP_WR, XSEM_REG_TS_7_AS, 0x1},
+	{OP_WR, XSEM_REG_TS_8_AS, 0x4},
+	{OP_WR, XSEM_REG_TS_9_AS, 0x0},
+	{OP_WR, XSEM_REG_TS_10_AS, 0x1},
+	{OP_WR, XSEM_REG_TS_11_AS, 0x3},
+	{OP_WR, XSEM_REG_TS_12_AS, 0x0},
+	{OP_WR, XSEM_REG_TS_13_AS, 0x1},
+	{OP_WR, XSEM_REG_TS_14_AS, 0x4},
+	{OP_WR, XSEM_REG_TS_15_AS, 0x0},
+	{OP_WR, XSEM_REG_TS_16_AS, 0x4},
+	{OP_WR, XSEM_REG_TS_17_AS, 0x3},
+	{OP_ZR, XSEM_REG_TS_18_AS, 0x2},
+	{OP_WR, XSEM_REG_ENABLE_IN, 0x3fff},
+	{OP_WR, XSEM_REG_ENABLE_OUT, 0x3ff},
+	{OP_WR, XSEM_REG_FIC0_DISABLE, 0x0},
+	{OP_WR, XSEM_REG_FIC1_DISABLE, 0x0},
+	{OP_WR, XSEM_REG_PAS_DISABLE, 0x0},
+	{OP_WR, XSEM_REG_THREADS_LIST, 0xffff},
+	{OP_ZR, XSEM_REG_PASSIVE_BUFFER, 0x800},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x18bc0, 0x1},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x18000, 0x0},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x18040, 0x18},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x18080, 0xc},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x180c0, 0x66},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x18300, 0x7a120},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x18340, 0x1f4},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x18380, 0x1dcd6500},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x55d8, 0x2},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x5000, 0x48},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x1020, 0xc8},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x1000, 0x2},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x5128, 0x92},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x5378, 0x0},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x5380, 0x24d20},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x5428, 0x44d22},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x1518, 0x1},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x1830, 0x0},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x1838, 0x0},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x1820, 0x24d26},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x4ac0, 0x2},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x4ad8, 0x24d28},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x4b08, 0x4},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x1f50, 0x24d2a},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x0},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x10c00, 0x104d2c},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x1000000},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x10c40, 0x84d3c},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x2000000},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x10c60, 0x84d44},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x3000000},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x10c80, 0x84d4c},
+	{OP_ZP, XSEM_REG_INT_TABLE, 0x814d54},
+	{OP_ZP, XSEM_REG_PRAM, 0x35774d75},
+	{OP_ZP, XSEM_REG_PRAM + 0x8000, 0x36525ad3},
+	{OP_ZP, XSEM_REG_PRAM + 0x10000, 0x27266868},
+	{OP_ZP, XSEM_REG_PRAM + 0x18000, 0x5e7232},
+	{OP_ZP, XSEM_REG_PRAM + 0x20000, 0x5e724a},
+	{OP_ZP, XSEM_REG_PRAM + 0x28000, 0x5e7262},
+	{OP_ZP, XSEM_REG_PRAM + 0x30000, 0x5e727a},
+	{OP_ZP, XSEM_REG_PRAM + 0x38000, 0x5e7292},
+#define XSEM_COMMON_END         1000
+#define XSEM_PORT0_START        1000
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x1400, 0xa},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x1450, 0x6},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x5388, 0xc},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x5388 + 0x30, 0x272aa},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x55e0, 0x772ac},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x5600, 0x7},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x1500, 0x0},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x1508, 0x1},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x3020, 0x2},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x3030, 0x2},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x3000, 0x2},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x3010, 0x2},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x3040, 0x0},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x3048, 0xc},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x3048 + 0x30, 0x272b3},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x30b8, 0x1},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x4ac8, 0x272b5},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x4b18, 0x42},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x4d28, 0x4},
+#define XSEM_PORT0_END          1019
+#define XSEM_PORT1_START        1019
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x1428, 0xa},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x1468, 0x6},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x53c0, 0xc},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x53c0 + 0x30, 0x272b7},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x5620, 0x772b9},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x5640, 0x7},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x1504, 0x0},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x150c, 0x1},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x3028, 0x2},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x3038, 0x2},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x3008, 0x2},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x3018, 0x2},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x3044, 0x0},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x3080, 0xc},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x3080 + 0x30, 0x272c0},
+	{OP_WR, XSEM_REG_FAST_MEMORY + 0x30bc, 0x1},
+	{OP_SW, XSEM_REG_FAST_MEMORY + 0x4ad0, 0x272c2},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x4c20, 0x42},
+	{OP_ZR, XSEM_REG_FAST_MEMORY + 0x4d38, 0x4},
+#define XSEM_PORT1_END          1038
+#define CDU_COMMON_START        1038
+	{OP_WR, CDU_REG_CDU_CONTROL0, 0x1},
+	{OP_WR, CDU_REG_CDU_CHK_MASK0, 0x3d000},
+	{OP_WR, CDU_REG_CDU_CHK_MASK1, 0x3d},
+	{OP_WB, CDU_REG_L1TT, 0x20072c4},
+	{OP_WB, CDU_REG_MATT, 0x2074c4},
+	{OP_ZR, CDU_REG_MATT + 0x80, 0x20},
+#define CDU_COMMON_END          1044
+#define DMAE_COMMON_START       1044
+	{OP_WR, DMAE_REG_CRC16C_INIT, 0x0},
+	{OP_WR, DMAE_REG_CRC16T10_INIT, 0x1},
+	{OP_WR, DMAE_REG_PXP_REQ_INIT_CRD, 0x2},
+	{OP_WR, DMAE_REG_PCI_IFEN, 0x1},
+	{OP_WR, DMAE_REG_GRC_IFEN, 0x1},
+#define DMAE_COMMON_END         1049
+#define PXP_COMMON_START        1049
+	{OP_SI, PXP_REG_HST_INBOUND_INT + 0x400, 0x574e4},
+	{OP_SI, PXP_REG_HST_INBOUND_INT + 0x420, 0x574e9},
+	{OP_SI, PXP_REG_HST_INBOUND_INT, 0x574ee},
+#define PXP_COMMON_END          1052
+#define CFC_COMMON_START        1052
+	{OP_WR, CFC_REG_CONTROL0, 0x10},
+	{OP_WR, CFC_REG_DISABLE_ON_ERROR, 0x3fff},
+	{OP_WR, CFC_REG_LCREQ_WEIGHTS, 0x84924a},
+#define CFC_COMMON_END          1055
+#define HC_COMMON_START         1055
+	{OP_ZR, HC_REG_USTORM_ADDR_FOR_COALESCE, 0x4},
+#define HC_COMMON_END           1056
+#define HC_PORT0_START          1056
+	{OP_WR, HC_REG_CONFIG_0, 0x1080},
+	{OP_ZR, HC_REG_UC_RAM_ADDR_0, 0x2},
+	{OP_WR, HC_REG_ATTN_NUM_P0, 0x10},
+	{OP_WR, HC_REG_LEADING_EDGE_0, 0xffff},
+	{OP_WR, HC_REG_TRAILING_EDGE_0, 0xffff},
+	{OP_WR, HC_REG_AGG_INT_0, 0x0},
+	{OP_WR, HC_REG_ATTN_IDX, 0x0},
+	{OP_ZR, HC_REG_ATTN_BIT, 0x2},
+	{OP_WR, HC_REG_VQID_0, 0x2b5},
+	{OP_WR, HC_REG_PCI_CONFIG_0, 0x0},
+	{OP_ZR, HC_REG_P0_PROD_CONS, 0x4a},
+	{OP_ZR, HC_REG_PBA_COMMAND, 0x2},
+	{OP_WR, HC_REG_INT_MASK, 0x1ffff},
+	{OP_WR, HC_REG_CONFIG_0, 0x1a82},
+	{OP_ZR, HC_REG_STATISTIC_COUNTERS, 0x24},
+	{OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a},
+	{OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a},
+	{OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a},
+#define HC_PORT0_END            1074
+#define HC_PORT1_START          1074
+	{OP_WR, HC_REG_CONFIG_1, 0x1080},
+	{OP_ZR, HC_REG_UC_RAM_ADDR_1, 0x2},
+	{OP_WR, HC_REG_ATTN_NUM_P1, 0x10},
+	{OP_WR, HC_REG_LEADING_EDGE_1, 0xffff},
+	{OP_WR, HC_REG_TRAILING_EDGE_1, 0xffff},
+	{OP_WR, HC_REG_AGG_INT_1, 0x0},
+	{OP_WR, HC_REG_ATTN_IDX + 0x4, 0x0},
+	{OP_ZR, HC_REG_ATTN_BIT + 0x8, 0x2},
+	{OP_WR, HC_REG_VQID_1, 0x2b5},
+	{OP_WR, HC_REG_PCI_CONFIG_1, 0x0},
+	{OP_ZR, HC_REG_P1_PROD_CONS, 0x4a},
+	{OP_ZR, HC_REG_PBA_COMMAND + 0x8, 0x2},
+	{OP_WR, HC_REG_INT_MASK + 0x4, 0x1ffff},
+	{OP_WR, HC_REG_CONFIG_1, 0x1a82},
+	{OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24},
+	{OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a},
+	{OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a},
+	{OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a},
+#define HC_PORT1_END            1092
+#define PXP2_COMMON_START       1092
+	{OP_WR, PXP2_REG_PGL_CONTROL0, 0xe38324},
+	{OP_WR, PXP2_REG_PGL_CONTROL1, 0x3c10},
+	{OP_WR, PXP2_REG_PGL_INT_TSDM_0, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_TSDM_1, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_TSDM_2, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_TSDM_3, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_TSDM_4, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_TSDM_5, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_TSDM_6, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_TSDM_7, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_USDM_1, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_USDM_2, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_USDM_3, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_USDM_4, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_USDM_5, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_USDM_6, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_USDM_7, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_XSDM_2, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_XSDM_3, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_XSDM_4, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_XSDM_5, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_XSDM_6, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_XSDM_7, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_CSDM_0, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_CSDM_1, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_CSDM_2, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_CSDM_3, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_CSDM_4, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_CSDM_5, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_CSDM_6, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_CSDM_7, 0xffffffff},
+	{OP_WR, PXP2_REG_PGL_INT_XSDM_0, 0xffff5330},
+	{OP_WR, PXP2_REG_PGL_INT_XSDM_1, 0xffff5348},
+	{OP_WR, PXP2_REG_PGL_INT_USDM_0, 0xf0003000},
+	{OP_WR, PXP2_REG_RD_MAX_BLKS_VQ6, 0x8},
+	{OP_WR, PXP2_REG_RD_MAX_BLKS_VQ9, 0x8},
+	{OP_WR, PXP2_REG_RD_MAX_BLKS_VQ10, 0x8},
+	{OP_WR, PXP2_REG_RD_MAX_BLKS_VQ11, 0x2},
+	{OP_WR, PXP2_REG_RD_MAX_BLKS_VQ17, 0x4},
+	{OP_WR, PXP2_REG_RD_MAX_BLKS_VQ18, 0x5},
+	{OP_WR, PXP2_REG_RD_MAX_BLKS_VQ19, 0x4},
+	{OP_WR, PXP2_REG_RD_MAX_BLKS_VQ22, 0x0},
+	{OP_WR, PXP2_REG_RD_START_INIT, 0x1},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD0, 0x40},
+	{OP_WR, PXP2_REG_PSWRQ_BW_ADD1, 0x1808},
+	{OP_WR, PXP2_REG_PSWRQ_BW_ADD2, 0x803},
+	{OP_WR, PXP2_REG_PSWRQ_BW_ADD3, 0x803},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD4, 0x40},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD5, 0x3},
+	{OP_WR, PXP2_REG_PSWRQ_BW_ADD6, 0x803},
+	{OP_WR, PXP2_REG_PSWRQ_BW_ADD7, 0x803},
+	{OP_WR, PXP2_REG_PSWRQ_BW_ADD8, 0x803},
+	{OP_WR, PXP2_REG_PSWRQ_BW_ADD9, 0x10003},
+	{OP_WR, PXP2_REG_PSWRQ_BW_ADD10, 0x803},
+	{OP_WR, PXP2_REG_PSWRQ_BW_ADD11, 0x803},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD12, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD13, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD14, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD15, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD16, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD17, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD18, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD19, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD20, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD22, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD23, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD24, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD25, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD26, 0x3},
+	{OP_WR, PXP2_REG_RQ_BW_RD_ADD27, 0x3},
+	{OP_WR, PXP2_REG_PSWRQ_BW_ADD28, 0x2403},
+	{OP_WR, PXP2_REG_RQ_BW_WR_ADD29, 0x2f},
+	{OP_WR, PXP2_REG_RQ_BW_WR_ADD30, 0x9},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND0, 0x19},
+	{OP_WR, PXP2_REG_PSWRQ_BW_UB1, 0x184},
+	{OP_WR, PXP2_REG_PSWRQ_BW_UB2, 0x183},
+	{OP_WR, PXP2_REG_PSWRQ_BW_UB3, 0x306},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND4, 0x19},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND5, 0x6},
+	{OP_WR, PXP2_REG_PSWRQ_BW_UB6, 0x306},
+	{OP_WR, PXP2_REG_PSWRQ_BW_UB7, 0x306},
+	{OP_WR, PXP2_REG_PSWRQ_BW_UB8, 0x306},
+	{OP_WR, PXP2_REG_PSWRQ_BW_UB9, 0xc86},
+	{OP_WR, PXP2_REG_PSWRQ_BW_UB10, 0x306},
+	{OP_WR, PXP2_REG_PSWRQ_BW_UB11, 0x306},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND12, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND13, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND14, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND15, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND16, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND17, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND18, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND19, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND20, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND22, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND23, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND24, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND25, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND26, 0x6},
+	{OP_WR, PXP2_REG_RQ_BW_RD_UBOUND27, 0x6},
+	{OP_WR, PXP2_REG_PSWRQ_BW_UB28, 0x306},
+	{OP_WR, PXP2_REG_RQ_BW_WR_UBOUND29, 0x13},
+	{OP_WR, PXP2_REG_RQ_BW_WR_UBOUND30, 0x6},
+	{OP_WR, PXP2_REG_PSWRQ_BW_L1, 0x1004},
+	{OP_WR, PXP2_REG_PSWRQ_BW_L2, 0x1004},
+	{OP_WR, PXP2_REG_PSWRQ_BW_RD, 0x106440},
+	{OP_WR, PXP2_REG_PSWRQ_BW_WR, 0x106440},
+	{OP_WR, PXP2_REG_RQ_RBC_DONE, 0x1},
+#define PXP2_COMMON_END         1200
+#define MISC_AEU_COMMON_START   1200
+	{OP_ZR, MISC_REG_AEU_GENERAL_ATTN_0, 0x16},
+#define MISC_AEU_COMMON_END     1201
+#define MISC_AEU_PORT0_START    1201
+	{OP_WR, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, 0xbf5c0000},
+	{OP_WR, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_0, 0xfff51fef},
+	{OP_WR, MISC_REG_AEU_ENABLE3_FUNC_0_OUT_0, 0xffff},
+	{OP_WR, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0, 0x500003e0},
+	{OP_WR, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1, 0x0},
+	{OP_WR, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_1, 0xa000},
+	{OP_ZR, MISC_REG_AEU_ENABLE3_FUNC_0_OUT_1, 0x5},
+	{OP_WR, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_2, 0xfe00000},
+	{OP_ZR, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3, 0x14},
+	{OP_WR, MISC_REG_AEU_ENABLE1_NIG_0, 0x55540000},
+	{OP_WR, MISC_REG_AEU_ENABLE2_NIG_0, 0x55555555},
+	{OP_WR, MISC_REG_AEU_ENABLE3_NIG_0, 0x5555},
+	{OP_WR, MISC_REG_AEU_ENABLE4_NIG_0, 0x0},
+	{OP_WR, MISC_REG_AEU_ENABLE1_PXP_0, 0x55540000},
+	{OP_WR, MISC_REG_AEU_ENABLE2_PXP_0, 0x55555555},
+	{OP_WR, MISC_REG_AEU_ENABLE3_PXP_0, 0x5555},
+	{OP_WR, MISC_REG_AEU_ENABLE4_PXP_0, 0x0},
+	{OP_WR, MISC_REG_AEU_INVERTER_1_FUNC_0, 0x0},
+	{OP_ZR, MISC_REG_AEU_INVERTER_2_FUNC_0, 0x3},
+	{OP_WR, MISC_REG_AEU_MASK_ATTN_FUNC_0, 0x7},
+#define MISC_AEU_PORT0_END      1221
+#define MISC_AEU_PORT1_START    1221
+	{OP_WR, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0, 0xbf5c0000},
+	{OP_WR, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0, 0xfff51fef},
+	{OP_WR, MISC_REG_AEU_ENABLE3_FUNC_1_OUT_0, 0xffff},
+	{OP_WR, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0, 0x500003e0},
+	{OP_WR, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1, 0x0},
+	{OP_WR, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_1, 0xa000},
+	{OP_ZR, MISC_REG_AEU_ENABLE3_FUNC_1_OUT_1, 0x5},
+	{OP_WR, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_2, 0xfe00000},
+	{OP_ZR, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3, 0x14},
+	{OP_WR, MISC_REG_AEU_ENABLE1_NIG_1, 0x55540000},
+	{OP_WR, MISC_REG_AEU_ENABLE2_NIG_1, 0x55555555},
+	{OP_WR, MISC_REG_AEU_ENABLE3_NIG_1, 0x5555},
+	{OP_WR, MISC_REG_AEU_ENABLE4_NIG_1, 0x0},
+	{OP_WR, MISC_REG_AEU_ENABLE1_PXP_1, 0x55540000},
+	{OP_WR, MISC_REG_AEU_ENABLE2_PXP_1, 0x55555555},
+	{OP_WR, MISC_REG_AEU_ENABLE3_PXP_1, 0x5555},
+	{OP_WR, MISC_REG_AEU_ENABLE4_PXP_1, 0x0},
+	{OP_WR, MISC_REG_AEU_INVERTER_1_FUNC_1, 0x0},
+	{OP_ZR, MISC_REG_AEU_INVERTER_2_FUNC_1, 0x3},
+	{OP_WR, MISC_REG_AEU_MASK_ATTN_FUNC_1, 0x7}
+#define MISC_AEU_PORT1_END      1241
+};
+
+static const u32 init_data[] = {
+	0x00010000, 0x000204c0, 0x00030980, 0x00040e40, 0x00051300, 0x000617c0,
+	0x00071c80, 0x00082140, 0x00092600, 0x000a2ac0, 0x000b2f80, 0x000c3440,
+	0x000d3900, 0x000e3dc0, 0x000f4280, 0x00104740, 0x00114c00, 0x001250c0,
+	0x00135580, 0x00145a40, 0x00155f00, 0x001663c0, 0x00176880, 0x00186d40,
+	0x00197200, 0x001a76c0, 0x001b7b80, 0x001c8040, 0x001d8500, 0x001e89c0,
+	0x001f8e80, 0x00209340, 0x00002000, 0x00004000, 0x00006000, 0x00008000,
+	0x0000a000, 0x0000c000, 0x0000e000, 0x00010000, 0x00012000, 0x00014000,
+	0x00016000, 0x00018000, 0x0001a000, 0x0001c000, 0x0001e000, 0x00020000,
+	0x00022000, 0x00024000, 0x00026000, 0x00028000, 0x0002a000, 0x0002c000,
+	0x0002e000, 0x00030000, 0x00032000, 0x00034000, 0x00036000, 0x00038000,
+	0x0003a000, 0x0003c000, 0x0003e000, 0x00040000, 0x00042000, 0x00044000,
+	0x00046000, 0x00048000, 0x0004a000, 0x0004c000, 0x0004e000, 0x00050000,
+	0x00052000, 0x00054000, 0x00056000, 0x00058000, 0x0005a000, 0x0005c000,
+	0x0005e000, 0x00060000, 0x00062000, 0x00064000, 0x00066000, 0x00068000,
+	0x0006a000, 0x0006c000, 0x0006e000, 0x00070000, 0x00072000, 0x00074000,
+	0x00076000, 0x00078000, 0x0007a000, 0x0007c000, 0x0007e000, 0x00080000,
+	0x00082000, 0x00084000, 0x00086000, 0x00088000, 0x0008a000, 0x0008c000,
+	0x0008e000, 0x00090000, 0x00092000, 0x00094000, 0x00096000, 0x00098000,
+	0x0009a000, 0x0009c000, 0x0009e000, 0x000a0000, 0x000a2000, 0x000a4000,
+	0x000a6000, 0x000a8000, 0x000aa000, 0x000ac000, 0x000ae000, 0x000b0000,
+	0x000b2000, 0x000b4000, 0x000b6000, 0x000b8000, 0x000ba000, 0x000bc000,
+	0x000be000, 0x000c0000, 0x000c2000, 0x000c4000, 0x000c6000, 0x000c8000,
+	0x000ca000, 0x000cc000, 0x000ce000, 0x000d0000, 0x000d2000, 0x000d4000,
+	0x000d6000, 0x000d8000, 0x000da000, 0x000dc000, 0x000de000, 0x000e0000,
+	0x000e2000, 0x000e4000, 0x000e6000, 0x000e8000, 0x000ea000, 0x000ec000,
+	0x000ee000, 0x000f0000, 0x000f2000, 0x000f4000, 0x000f6000, 0x000f8000,
+	0x000fa000, 0x000fc000, 0x000fe000, 0x00100000, 0x00102000, 0x00104000,
+	0x00106000, 0x00108000, 0x0010a000, 0x0010c000, 0x0010e000, 0x00110000,
+	0x00112000, 0x00114000, 0x00116000, 0x00118000, 0x0011a000, 0x0011c000,
+	0x0011e000, 0x00120000, 0x00122000, 0x00124000, 0x00126000, 0x00128000,
+	0x0012a000, 0x0012c000, 0x0012e000, 0x00130000, 0x00132000, 0x00134000,
+	0x00136000, 0x00138000, 0x0013a000, 0x0013c000, 0x0013e000, 0x00140000,
+	0x00142000, 0x00144000, 0x00146000, 0x00148000, 0x0014a000, 0x0014c000,
+	0x0014e000, 0x00150000, 0x00152000, 0x00154000, 0x00156000, 0x00158000,
+	0x0015a000, 0x0015c000, 0x0015e000, 0x00160000, 0x00162000, 0x00164000,
+	0x00166000, 0x00168000, 0x0016a000, 0x0016c000, 0x0016e000, 0x00170000,
+	0x00172000, 0x00174000, 0x00176000, 0x00178000, 0x0017a000, 0x0017c000,
+	0x0017e000, 0x00180000, 0x00182000, 0x00184000, 0x00186000, 0x00188000,
+	0x0018a000, 0x0018c000, 0x0018e000, 0x00190000, 0x00192000, 0x00194000,
+	0x00196000, 0x00198000, 0x0019a000, 0x0019c000, 0x0019e000, 0x001a0000,
+	0x001a2000, 0x001a4000, 0x001a6000, 0x001a8000, 0x001aa000, 0x001ac000,
+	0x001ae000, 0x001b0000, 0x001b2000, 0x001b4000, 0x001b6000, 0x001b8000,
+	0x001ba000, 0x001bc000, 0x001be000, 0x001c0000, 0x001c2000, 0x001c4000,
+	0x001c6000, 0x001c8000, 0x001ca000, 0x001cc000, 0x001ce000, 0x001d0000,
+	0x001d2000, 0x001d4000, 0x001d6000, 0x001d8000, 0x001da000, 0x001dc000,
+	0x001de000, 0x001e0000, 0x001e2000, 0x001e4000, 0x001e6000, 0x001e8000,
+	0x001ea000, 0x001ec000, 0x001ee000, 0x001f0000, 0x001f2000, 0x001f4000,
+	0x001f6000, 0x001f8000, 0x001fa000, 0x001fc000, 0x001fe000, 0x00200000,
+	0x00202000, 0x00204000, 0x00206000, 0x00208000, 0x0020a000, 0x0020c000,
+	0x0020e000, 0x00210000, 0x00212000, 0x00214000, 0x00216000, 0x00218000,
+	0x0021a000, 0x0021c000, 0x0021e000, 0x00220000, 0x00222000, 0x00224000,
+	0x00226000, 0x00228000, 0x0022a000, 0x0022c000, 0x0022e000, 0x00230000,
+	0x00232000, 0x00234000, 0x00236000, 0x00238000, 0x0023a000, 0x0023c000,
+	0x0023e000, 0x00240000, 0x00242000, 0x00244000, 0x00246000, 0x00248000,
+	0x0024a000, 0x0024c000, 0x0024e000, 0x00250000, 0x00252000, 0x00254000,
+	0x00256000, 0x00258000, 0x0025a000, 0x0025c000, 0x0025e000, 0x00260000,
+	0x00262000, 0x00264000, 0x00266000, 0x00268000, 0x0026a000, 0x0026c000,
+	0x0026e000, 0x00270000, 0x00272000, 0x00274000, 0x00276000, 0x00278000,
+	0x0027a000, 0x0027c000, 0x0027e000, 0x00280000, 0x00282000, 0x00284000,
+	0x00286000, 0x00288000, 0x0028a000, 0x0028c000, 0x0028e000, 0x00290000,
+	0x00292000, 0x00294000, 0x00296000, 0x00298000, 0x0029a000, 0x0029c000,
+	0x0029e000, 0x002a0000, 0x002a2000, 0x002a4000, 0x002a6000, 0x002a8000,
+	0x002aa000, 0x002ac000, 0x002ae000, 0x002b0000, 0x002b2000, 0x002b4000,
+	0x002b6000, 0x002b8000, 0x002ba000, 0x002bc000, 0x002be000, 0x002c0000,
+	0x002c2000, 0x002c4000, 0x002c6000, 0x002c8000, 0x002ca000, 0x002cc000,
+	0x002ce000, 0x002d0000, 0x002d2000, 0x002d4000, 0x002d6000, 0x002d8000,
+	0x002da000, 0x002dc000, 0x002de000, 0x002e0000, 0x002e2000, 0x002e4000,
+	0x002e6000, 0x002e8000, 0x002ea000, 0x002ec000, 0x002ee000, 0x002f0000,
+	0x002f2000, 0x002f4000, 0x002f6000, 0x002f8000, 0x002fa000, 0x002fc000,
+	0x002fe000, 0x00300000, 0x00302000, 0x00304000, 0x00306000, 0x00308000,
+	0x0030a000, 0x0030c000, 0x0030e000, 0x00310000, 0x00312000, 0x00314000,
+	0x00316000, 0x00318000, 0x0031a000, 0x0031c000, 0x0031e000, 0x00320000,
+	0x00322000, 0x00324000, 0x00326000, 0x00328000, 0x0032a000, 0x0032c000,
+	0x0032e000, 0x00330000, 0x00332000, 0x00334000, 0x00336000, 0x00338000,
+	0x0033a000, 0x0033c000, 0x0033e000, 0x00340000, 0x00342000, 0x00344000,
+	0x00346000, 0x00348000, 0x0034a000, 0x0034c000, 0x0034e000, 0x00350000,
+	0x00352000, 0x00354000, 0x00356000, 0x00358000, 0x0035a000, 0x0035c000,
+	0x0035e000, 0x00360000, 0x00362000, 0x00364000, 0x00366000, 0x00368000,
+	0x0036a000, 0x0036c000, 0x0036e000, 0x00370000, 0x00372000, 0x00374000,
+	0x00376000, 0x00378000, 0x0037a000, 0x0037c000, 0x0037e000, 0x00380000,
+	0x00382000, 0x00384000, 0x00386000, 0x00388000, 0x0038a000, 0x0038c000,
+	0x0038e000, 0x00390000, 0x00392000, 0x00394000, 0x00396000, 0x00398000,
+	0x0039a000, 0x0039c000, 0x0039e000, 0x003a0000, 0x003a2000, 0x003a4000,
+	0x003a6000, 0x003a8000, 0x003aa000, 0x003ac000, 0x003ae000, 0x003b0000,
+	0x003b2000, 0x003b4000, 0x003b6000, 0x003b8000, 0x003ba000, 0x003bc000,
+	0x003be000, 0x003c0000, 0x003c2000, 0x003c4000, 0x003c6000, 0x003c8000,
+	0x003ca000, 0x003cc000, 0x003ce000, 0x003d0000, 0x003d2000, 0x003d4000,
+	0x003d6000, 0x003d8000, 0x003da000, 0x003dc000, 0x003de000, 0x003e0000,
+	0x003e2000, 0x003e4000, 0x003e6000, 0x003e8000, 0x003ea000, 0x003ec000,
+	0x003ee000, 0x003f0000, 0x003f2000, 0x003f4000, 0x003f6000, 0x003f8000,
+	0x003fa000, 0x003fc000, 0x003fe000, 0x003fe001, 0x00000000, 0x000001ff,
+	0x00000200, 0x00000001, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00088b1f, 0x00000000,
+	0x51fbff00, 0x03f0c0cf, 0x3130ef8a, 0x22b1c430, 0x3b0143f8, 0x02ecdd01,
+	0xdc406ec4, 0x19b7c404, 0x23dfd348, 0xf1476080, 0x03343031, 0x032f3731,
+	0x423f2483, 0x4d5011fc, 0x02ef9025, 0xa40cdb15, 0x77280475, 0xf2c060fb,
+	0x77629812, 0x056c1144, 0x58c8f22c, 0x4dde4d11, 0x44af950c, 0xe340ff40,
+	0xfca8b235, 0x6d081948, 0x8b5f150b, 0x95051f26, 0xd0849577, 0xe76964eb,
+	0x00607a36, 0x2726b9d6, 0x00000400, 0x00088b1f, 0x00000000, 0x7dedff00,
+	0xd554780b, 0x333ef0b5, 0x64ccce67, 0x093c991e, 0x20f264af, 0xf09c0682,
+	0x93a8a808, 0x07be3040, 0x0e22a5e4, 0x27902018, 0xf5e8bd48, 0x620c19bf,
+	0x2f06d6b4, 0x93a45a2a, 0xb6968a80, 0x6c1a06c1, 0x822203b4, 0x6b06f5bf,
+	0x368b6d7b, 0x2062a28a, 0xa5ebd8b9, 0xaffadaf7, 0x99def6b5, 0x91332673,
+	0xfebffdaa, 0x5fa7f7df, 0xf7b3ecdd, 0xf5ed7bd9, 0xb3ef6b5e, 0xa66e6547,
+	0x97d8ce5d, 0x9be507f8, 0x232c630a, 0xa1bbd65a, 0xed58cc9c, 0x9ef8731e,
+	0xec66c65c, 0x4f2e44b1, 0x12ab7a87, 0xf4dd42b6, 0x4fda9d92, 0x7af5e56f,
+	0x9743f773, 0xb9fb3b40, 0x05053d99, 0x589bb1eb, 0x6c276309, 0xf2f5ff8c,
+	0xaf3b72fa, 0x5feeb6d6, 0x557fa0cc, 0xe1d995a7, 0x661d13fd, 0x3cd7d63f,
+	0xc01984a5, 0x3eefbb50, 0xbf8c046d, 0xdbb4ac22, 0x0a7f50bd, 0xcafb421e,
+	0xfb18730e, 0x33bbb9f7, 0x4ec64e03, 0x5798da36, 0x937ef843, 0xd8c453d9,
+	0x59eef0aa, 0xaadfa023, 0x04cf8a5d, 0xaadaacf3, 0x8c9f2e44, 0x19b095cf,
+	0xe9dea886, 0x1cb1de60, 0xcd192f86, 0xf358eb4b, 0xe30bcc24, 0x0b45b532,
+	0x4dbe70b8, 0xc515d79a, 0x0f46c9cf, 0xb5eb23cd, 0xf03cc2cf, 0x144fdd5e,
+	0xceb12e1f, 0x30ed82c4, 0xf67de9ff, 0xb89ddb85, 0xa15af5be, 0x258ebf4b,
+	0xab1d717b, 0x2cdaadc2, 0xaad5c227, 0x8e8a2f2d, 0xcd33bd57, 0xfc96d708,
+	0x7b5d4161, 0x91b2796c, 0xb4616f31, 0x7f318abe, 0x0fe113bb, 0x47c7b36b,
+	0x29641f9f, 0x9deacf44, 0x45b5e666, 0x442c67c7, 0x17cccdcf, 0x2eb2bc41,
+	0xb74f4f97, 0xdd231e33, 0x7788a4d6, 0x7df3c013, 0x024d8741, 0xf843df4f,
+	0x7bf64ca0, 0xfeb0abd6, 0xa3cc99e4, 0x26fef10c, 0x1ed85b0b, 0x900bbd67,
+	0x1630a619, 0xb7822664, 0xc26f058e, 0x50d4cfb2, 0x5fc3c005, 0xeb002b24,
+	0xefe14fbd, 0xd4bccf5f, 0x9ad1beff, 0xe9bae91f, 0xe6ed92ca, 0x7496b15c,
+	0xfa7f2fac, 0xb5321801, 0xbf10cfc2, 0x88ade22a, 0x43321e16, 0xca576bbb,
+	0x7abc07c4, 0xc72d95fc, 0x4d93dcf9, 0xa678fa06, 0xa9ea1927, 0xf0635333,
+	0xb89cf4eb, 0x4e01d440, 0x827fa9ab, 0x6958cf9a, 0xedf88db6, 0xe48d6c8e,
+	0x38cb8ee6, 0x3b64775c, 0x7fa821c3, 0x08b85f17, 0x42f05aea, 0xc07c1c4f,
+	0x859626cc, 0xa6c4d065, 0x466f6e0d, 0x941f023c, 0xf8517ce5, 0xa6f5941e,
+	0x2814c2fe, 0x21a52b57, 0xc446cbc4, 0x330e9423, 0x3b75c06b, 0xd4f08cac,
+	0x7b64a63c, 0xfba78748, 0xb94f0173, 0xb7ef71d1, 0x1f316434, 0xca840f63,
+	0xc070ea43, 0xf7102e6f, 0x3cb78462, 0xf7802a12, 0x42c8ef73, 0x9034da7c,
+	0x1afcfd03, 0xf3445fcc, 0x1f1e20b7, 0x9d8c7415, 0xcd3856df, 0xaf3dbf30,
+	0x5dbf30ca, 0x2781f983, 0x2b5d089f, 0x8e3c07e6, 0xec07ec60, 0x96df9a5a,
+	0x6fe68eb7, 0x619558d6, 0xf981a4fe, 0xd3ef38c3, 0x2e6fe609, 0xfeb8d8bc,
+	0xf5c655bc, 0xcffd7c6b, 0xf989e685, 0x3ffd6893, 0xfaf8f362, 0xebe2eef3,
+	0xfab8c2b7, 0xf803ddf9, 0xefbc476f, 0xdb7f804d, 0xeb8dd379, 0xae31afcf,
+	0x7fe7cadf, 0x988b7421, 0xfff349df, 0xd7c2dd82, 0xcd377f9f, 0xf836b56f,
+	0xcd64d03c, 0x23086a49, 0x7fe17b5f, 0x802ca0c3, 0x5942a679, 0xbc18ca94,
+	0x47961dff, 0x2923b878, 0xfff61e78, 0xcdf8093c, 0x2c0bd519, 0xb94151bc,
+	0x5d3c13af, 0xf6896bb9, 0xb2a5783d, 0x064beb93, 0xc00c74fa, 0xb3f3ba77,
+	0xf000ffcf, 0xf628ee56, 0x8f24bd99, 0x265bdf0c, 0xe66f5296, 0x902c60f8,
+	0xfa85db3d, 0x673d9029, 0x59f9353c, 0x4645e826, 0xe3e20e30, 0x13962d65,
+	0x5af93a3d, 0x5f58c5b1, 0x25d63619, 0x24c8a5dc, 0xd8ca8650, 0xf79806d8,
+	0x0623e804, 0xd07df27a, 0x647e5847, 0xdda2b761, 0x15f400f8, 0xb572f4d3,
+	0x4272e89e, 0xb13ff8e5, 0xf8f241c5, 0x1ad5a6f9, 0x1c7847cb, 0x7cdd6480,
+	0x1156f621, 0x58be73ac, 0x04b9e127, 0xcf5f15f5, 0x6bdaaefc, 0xdc02c4c0,
+	0x4ef78669, 0xd416225b, 0xf0b0b75b, 0xfe3059bd, 0xb6ee0f6d, 0xf8ff4904,
+	0xae489a47, 0xc81348d9, 0x968582f5, 0xef747bf7, 0x64d8ec2d, 0x8de50919,
+	0x9bf3e341, 0xd3f58cab, 0x84c5b096, 0xc2a57976, 0x5bfc615a, 0x72ed8c1a,
+	0x54b13f9e, 0xdf31674e, 0xf0c5a07c, 0x06575c54, 0xe1e82fd1, 0x3ebb00eb,
+	0x87da246b, 0x53df14db, 0xfb05bf50, 0x1e3a444d, 0xe2f9f0d6, 0x07be2965,
+	0x997860d8, 0xdf40930a, 0x78dd8577, 0x743cb557, 0xfe183291, 0x7e1c979e,
+	0xebc184d3, 0x56fb8588, 0xdc3a21e6, 0x7cf8ceba, 0x7d762849, 0x3bea0f9c,
+	0xd03ed34b, 0xbf6daf3d, 0x1d03ed32, 0x9cef54bf, 0x0cafa86d, 0xbfe868df,
+	0x4312cb62, 0x9596b2fb, 0x9adbf686, 0x4bea1b57, 0xfa1a7742, 0xbd6ebadf,
+	0x8696fda1, 0x37ed0dfb, 0xd4326d57, 0x6e3e0c6f, 0x6160bfe8, 0x795da1ab,
+	0xfa0e6569, 0x305af537, 0xfde03867, 0xacacefd4, 0xb1f2894d, 0x1b8ff3e4,
+	0xd93ca8b3, 0x3d72a5e8, 0xbfc82bca, 0xeb2f1f69, 0xa0e496db, 0xffbe4b9c,
+	0x8d90d2c8, 0xdfcb1272, 0xcb18f2b1, 0x6837c8c7, 0xf3d91287, 0x5005851a,
+	0x6e14fbee, 0x77f3e48f, 0xec65fe84, 0x1ab7921e, 0xcd63cb8d, 0x50cbc3f3,
+	0x48b46a5e, 0xf1338361, 0xa15dacb8, 0x46d63075, 0x830cace3, 0x9ae81854,
+	0x77b3806f, 0xafe699bf, 0x22e3e743, 0x2581f7b4, 0x791fce0a, 0xf186fb39,
+	0x297f8f08, 0x48333bd5, 0x5636f62f, 0x22a07da4, 0x7e5402fe, 0xca90b8dc,
+	0x2a418d13, 0xa2ac683f, 0x06c6fdf2, 0xd71a7b2a, 0x636ef951, 0x8d63ca88,
+	0xbefe54cd, 0xb7ca85b1, 0xf950b71b, 0x9530c6db, 0x54fd1ba7, 0xb5a9f00e,
+	0x43fd10bf, 0x432b07f6, 0x0ebd9717, 0xcdc816fe, 0x7737e919, 0xe11afaf2,
+	0x4bc22737, 0xe213dd2c, 0x434c858f, 0x89292dd1, 0xc4c923d3, 0xf9c8182a,
+	0xfaf6e303, 0x8abaf296, 0xe008032a, 0x0397fbd3, 0x860d22e3, 0xde3d357d,
+	0xf683bb41, 0xd93365ef, 0x99f9163f, 0x1e9706ef, 0xd423401f, 0x8474bf37,
+	0x35fd029f, 0x7e72f14a, 0x9cbc0af9, 0x8dddbc39, 0x964d747a, 0xa4c1f3c9,
+	0x6dabebc4, 0x7538f5cf, 0x1a77d4f0, 0x945a67eb, 0x7a0fee0a, 0x478ee793,
+	0x3e78f07e, 0x65ba4028, 0x59c72951, 0x3e79a593, 0x617ec348, 0x95db0f5a,
+	0xf105fc42, 0xb6fbf508, 0x4e3448e1, 0x760e8e14, 0x1f27de1c, 0xff713f3b,
+	0xfea17c84, 0x9a3f4349, 0x473e5975, 0xff856abb, 0x1401897f, 0xc72ea953,
+	0x87376fad, 0xf3e217ac, 0xe0f9865d, 0xf58caf3d, 0x8a1bccbe, 0x427654ff,
+	0xa4a807f2, 0xacde22a3, 0x18f769de, 0xa18a75f5, 0xdc39df5e, 0xf8dfd063,
+	0x3657900f, 0x5ed15153, 0xe8b608d5, 0x0acd9d53, 0xf90bb7c0, 0xaf52e806,
+	0xb6b57ef0, 0x8f082d1e, 0xcd3474ce, 0x3d8bc4bf, 0xb1bd685b, 0x3c6c9df0,
+	0xc4d555ec, 0xcf9b57f0, 0xe38811dc, 0xf0ae7f97, 0xc4c6a538, 0x0b665ffd,
+	0x584e51b9, 0x873dc856, 0x07399bf8, 0x0b7143f0, 0xcbaba3cc, 0xe9afc071,
+	0x7acf678f, 0x8dafdc4d, 0x526ad79d, 0x757f09ce, 0xc2ce8ebb, 0xb1e2c775,
+	0xb43ff3ae, 0xcc8dc520, 0xdf894780, 0x6ac04a5d, 0xed57f182, 0xf9434f7c,
+	0x2a12d8fa, 0xc4dce7fc, 0xbf0c19f8, 0x2384eb33, 0x7b35ceba, 0xad5fe45c,
+	0xede224d9, 0x79c6eb10, 0x13134e97, 0x74bd017f, 0x62e58070, 0x26dfa826,
+	0x5dee326a, 0xfe4d51da, 0xa42c87d5, 0x89f53fa1, 0xfd04a5b9, 0xaded5583,
+	0x3ce01f9a, 0x88154cc5, 0x4dec53af, 0xbd1d24f7, 0xd11a4c8a, 0xa366b6e9,
+	0xa6fe00df, 0xa6fe0ea1, 0xcd9cbea1, 0x7638c4c9, 0xb80b66f9, 0x434eb4be,
+	0x879328fb, 0x3582b0e8, 0x7afb446c, 0xfcd263bc, 0x3f0e904b, 0xf104b27f,
+	0x479a14bb, 0x8f1e22a6, 0xd6ff1e12, 0xfbe257f9, 0x1bcf0713, 0x7c98dbe5,
+	0xed43c080, 0x8e1fc54e, 0x991737c3, 0xfe4abf38, 0x4ff080da, 0x2dcdfa89,
+	0x4d6bf531, 0x6b724a8a, 0xe3a46666, 0x642d8f29, 0x5f76a64a, 0x7a12f004,
+	0x026beade, 0x12a3fafe, 0xbb226d98, 0x74c0991e, 0x04a8fefd, 0xf2af79e9,
+	0x013472fa, 0xc04c8d4c, 0x06d80b3c, 0xd04d3be2, 0x60f08ad7, 0x1aa59cbc,
+	0x728f59d6, 0x9dd8e30d, 0xb7df0c1d, 0xf1da637b, 0xc637681f, 0x8e1bb232,
+	0x2776c6b1, 0x87f219b0, 0xbe7c67cb, 0x180fc842, 0x4c3be222, 0xebdfa17b,
+	0x662339b6, 0x34d94bf0, 0xce2077b5, 0xc878c3c8, 0xfe91813d, 0x645e52f3,
+	0xaff787ad, 0xb5847913, 0x4b0d94ef, 0xa97fc21d, 0x84b61b3f, 0xb57574d3,
+	0xa97e435f, 0x12c3bb3f, 0xf40df49e, 0x989617a0, 0x279b9519, 0xca236094,
+	0xd49bc4ad, 0x3c3d517f, 0xcb97a3ca, 0xfef431ad, 0x03a470da, 0xec70753d,
+	0x482d8252, 0xbe3858f7, 0x8359f8f6, 0xadfadfc6, 0x68305f8e, 0xf0f19dfc,
+	0x631c7a78, 0x0337a4dd, 0xfee80cc9, 0xa8f3dd9f, 0x8ff7444c, 0x85233e41,
+	0x58f84fe8, 0x4b79e344, 0xb8f8cbac, 0x59e5ebaa, 0x81575718, 0xfe05eb7f,
+	0x485ac95d, 0x294c448f, 0xb335cfc2, 0x55de0e88, 0xfea6bf5d, 0xff783aab,
+	0xfd4ed66a, 0x3119bf31, 0xe1927bac, 0x7def293d, 0x9cd49ec2, 0x1d11612d,
+	0x790b763f, 0xe087bf00, 0x106bcf93, 0xb26bcc3e, 0xb6a79a6e, 0xcf30cd3d,
+	0xf6735f80, 0xf9d11662, 0x376ab53d, 0xd9ed77f1, 0x019e68cb, 0x6afe067b,
+	0xfc6a1b44, 0xa3b80691, 0xc0334fe3, 0x3a7f1d1b, 0xcfc72bcd, 0xca72039a,
+	0x2be513f5, 0xc293cb42, 0xb7a7804d, 0x91f7c1ac, 0x9b5cb25f, 0x76415f73,
+	0x04f1fa5a, 0x744fc7d4, 0x1d34df6c, 0xea09fae8, 0x9b975c39, 0x739eb9b9,
+	0x92174c86, 0x7c853afe, 0x18bfa030, 0x43f1afe8, 0xb7e8c7b4, 0x8c0af851,
+	0x28f59a3f, 0x3746dfa8, 0x8e50f518, 0xef84dd33, 0x3e33ace5, 0x019ea2f7,
+	0x521b95bd, 0x9f5ce263, 0x6fcfc709, 0x9f4f3e36, 0xc73aba51, 0xd3516e07,
+	0x2798a533, 0xba505f4a, 0xb187a47b, 0x7957d40b, 0xe2d299fd, 0x79ff50e1,
+	0x1532bad3, 0x7ff4d5fc, 0x86ce2d2b, 0x91b2d3ba, 0xca15abd7, 0xb7cc592b,
+	0x89be8594, 0xcac0081e, 0x6294728d, 0x0a9cfc06, 0xccbf9b1c, 0x5fb47a8b,
+	0x9e8478e3, 0xd3d19f80, 0x39467e38, 0xfc46ed8f, 0xd67a98e4, 0xc3f973a3,
+	0x052bff17, 0xe62f4643, 0x1e0f013d, 0xf483c1b6, 0xbed34781, 0x8ebfc21c,
+	0x5f2533f5, 0xf305b14c, 0x4b938e10, 0x167f7ec7, 0xeaa27d3c, 0x5b0dc500,
+	0x71f9fe44, 0xf46eb710, 0x326f55bb, 0x3364e3f2, 0x0965d7cf, 0x378ceebf,
+	0xfd487937, 0xa195959e, 0x53eae0ea, 0x9fc8ddfb, 0x5f1c5f7d, 0xd6237e8c,
+	0x13d08653, 0x32a359f5, 0xa3139254, 0x749e667e, 0xc14aa3e2, 0x5b378847,
+	0xb6cf3466, 0x7e510942, 0xc0b5fa44, 0xbf5c1e01, 0x7f31aa12, 0x8edfc179,
+	0xe0d6e3a7, 0x775866d5, 0x83c85985, 0xbdb0b98b, 0xf08f2ab7, 0xf6836e96,
+	0x6b3d688c, 0xe809cee9, 0x0398a4e7, 0xc37be2d7, 0xc6cd9f97, 0x43d98e7a,
+	0xb4a2dbf8, 0x00f8470c, 0xc3cfb48f, 0x569d82f6, 0xdcc93168, 0xcf26f64f,
+	0x69ce2219, 0x1f4acc6b, 0x55cf2fca, 0xde718b83, 0xf7bebdfc, 0xf1fc619b,
+	0xf70f9a95, 0x9bafc65b, 0xccf88e99, 0xc03d7132, 0x72f390ee, 0xf82f5f3d,
+	0xf8aacfae, 0x77ded0fd, 0x8435a7bb, 0xda0b33ed, 0xb519afd1, 0xfdc3ebce,
+	0x42873e80, 0x7a35f7ef, 0xe7282f29, 0x1c95dd1d, 0x9e49bbb1, 0xf3c8373f,
+	0xd07d633a, 0x3b7a5f7c, 0x7fbc707b, 0x9c42f8f6, 0x1d0f949e, 0x67d9e82d,
+	0x725dfbe6, 0xb42cd1be, 0x7391fd1f, 0xcc5fef9d, 0x7fda74ae, 0xba037410,
+	0x925e9084, 0xfbdf402e, 0x121b5f10, 0x78bef7d3, 0x6b6e5df4, 0x5db946c8,
+	0x659f6815, 0xe625e781, 0xafd883e0, 0x21f76166, 0x50decd0b, 0xe927fc88,
+	0x70d0d4ce, 0x740353d4, 0xfc21497f, 0x7c717667, 0xb7361fd6, 0xcb1e7ee2,
+	0x40b7ae0a, 0x42ca99fb, 0xa22627ca, 0xfe75f8f3, 0x017cbd74, 0xfce2b7dd,
+	0x9a8ebbe3, 0xef493e10, 0x49de44c7, 0xffecadca, 0xbdfa598c, 0x0f76be62,
+	0xfc55f7cd, 0x166eb457, 0x7c780b8d, 0x80dfcf56, 0xff9c76c7, 0x1fe166c7,
+	0x3b63c60f, 0x3c073ff6, 0x3c1739ee, 0x939de87e, 0xcfe30799, 0x7f093b32,
+	0x87329f2b, 0xbea4b0ad, 0xf52fd2d9, 0x333c335f, 0x5e5627aa, 0xd71fb0d4,
+	0x8549f2b9, 0x6bb2acf8, 0xc26c35c5, 0xf96378e0, 0xe3e910c2, 0xd903b8d8,
+	0x5ab2f912, 0x7f13178e, 0xff07b354, 0x734e4cc3, 0xf54ef498, 0xbffb634e,
+	0x9b30f945, 0x24ce04f2, 0xf1b1b79e, 0xf1d0b2f1, 0xe248be47, 0x8b26717c,
+	0x619e1c91, 0xd0f7c429, 0xbb608bee, 0x33fca2e6, 0xdc6291db, 0x314cac9f,
+	0x6e8e4fec, 0x4ff21930, 0xc9b1f3b1, 0x5fec4cca, 0x6730e42a, 0x6fb0c99d,
+	0xee321b97, 0xa737e5eb, 0x5a63ea1a, 0x9ffa1846, 0xd0cf25b7, 0xbe7c2e3e,
+	0x9d82fda1, 0xf1f50d13, 0xfa1b17ed, 0x6659d85f, 0xae4717a8, 0x749ff432,
+	0x3ea18e78, 0x4326fba5, 0x2f6fa9ff, 0xd45fb435, 0x7ed0cab3, 0x0c6bc7c9,
+	0xeffb4bf5, 0x2c8ff432, 0x00ac38a9, 0xff025efd, 0xe086f314, 0x67c8a857,
+	0x99acfe07, 0xfc0e4f90, 0xa8c4d0b9, 0x2bc867dd, 0xa673f81e, 0xf81f9f1f,
+	0xfb1f8973, 0xe7cb3295, 0x5952e2f1, 0xdb19b0ce, 0x0be05553, 0xc0d96fb4,
+	0x569a9817, 0x7203f28d, 0x39454235, 0x0fc3a7fb, 0x469d0215, 0x46482cac,
+	0x34f20d3b, 0xbd373d42, 0x27ef8394, 0x962da792, 0x290f1b96, 0xac7ded83,
+	0x38e590be, 0x5bade655, 0xbad37de8, 0x65a7616c, 0xb230f17d, 0x5f9f9233,
+	0x7a1c5333, 0xe3d70366, 0x86a43667, 0xdf9efef9, 0x0fe75c39, 0x24e8399e,
+	0x9efdcefe, 0xaf01db93, 0x892cebd3, 0x7f2901da, 0x323f22f9, 0x7945582a,
+	0xe3fe418f, 0xb8f59ea2, 0x1ff573ce, 0x99c6fd63, 0xff021e92, 0x05d1d709,
+	0xf1f68972, 0x27da1483, 0x7161e35a, 0x36b6eff7, 0x16770f36, 0x4b2e7e0c,
+	0xdce1cd65, 0xb40f30fb, 0xe159f14f, 0x1fd86dfd, 0xbc587bec, 0xb5ea26d7,
+	0xbd454d21, 0xebe22b56, 0x521e71d8, 0x7e466f4b, 0xdd96a1d8, 0xc5d14eac,
+	0xdc5a0dd3, 0xd077c7bc, 0x0473c089, 0x0d80efaa, 0xcf5fefe6, 0xff306d7c,
+	0x0ca78b1a, 0xf4ee6beb, 0x9af21d12, 0x7ae1667b, 0x5dc13a73, 0x73fbd9d7,
+	0xc056a780, 0xd4f08b53, 0xa714fda9, 0xb0a8bff5, 0x879c5cb6, 0x5f66bb8f,
+	0x487e432e, 0xd51ce704, 0x72057c42, 0x738e3770, 0x4ed09aa7, 0xf28e7ddf,
+	0x638d5eb0, 0xf2ec065f, 0xf15bed52, 0x137072c7, 0x9eb44a78, 0xe196d0ff,
+	0x9d39b728, 0xc0a89fa5, 0x60e039b7, 0x9f22a726, 0xd1bef632, 0xebef623f,
+	0xf344d0fc, 0x7689557e, 0xf1157def, 0x0631f7ce, 0xc7231dc1, 0xe46f75de,
+	0xebe9a417, 0x4c17e7af, 0x10950012, 0x306c14bc, 0xe5e2db88, 0x95f6738b,
+	0x2427561e, 0xbdefe786, 0x377881ce, 0x4bfd5e46, 0x7c8f5ec7, 0xb311fb77,
+	0xb2845562, 0xc84178c1, 0xe677b2eb, 0xf0e8a664, 0xe5b1b5b3, 0xaf27556a,
+	0xf7f012a3, 0x9ff72a9b, 0x5c3635b6, 0xe380595d, 0x3d7a4c7a, 0xca13dd90,
+	0xd27988dd, 0x8c2f870e, 0x9327acfa, 0x702b58f0, 0xbe0a6c90, 0xf4bcfc89,
+	0xd7ca6ec2, 0xe97c88e6, 0x297e7168, 0x2ae3be76, 0x97f847cf, 0x8c2958da,
+	0x16cda7fb, 0x34b277f2, 0x08e28798, 0x5a5b9d07, 0x0a6c0636, 0x93db2fb4,
+	0x0c53f5c6, 0xd0c6e15c, 0xa20a1bd5, 0xc71c02f3, 0x3dbc1e51, 0x7f3859c1,
+	0x4451c22e, 0xe11276f2, 0xe84d48fb, 0x473c9dcf, 0xd21beb79, 0x43c6c4fe,
+	0xf0e2fd09, 0xa7e485fd, 0x7e4dffe6, 0xa1c3fa31, 0x0c3fa8a2, 0xd058b2eb,
+	0xeb8c594e, 0x8b55d9d2, 0x95d6dce5, 0xaeda1964, 0x92416e3e, 0x32407389,
+	0x9ae1230f, 0x57f2e169, 0xe618d1ef, 0x4e51ead3, 0x54d9f0e3, 0xbb88628b,
+	0x3138adbf, 0xede6553f, 0x7887bda4, 0xe5c2e311, 0x33a3e24e, 0x0bfbd6de,
+	0x877c7327, 0xc8f7c086, 0x04322375, 0x0f887d5e, 0x16f1c789, 0xbc069ea3,
+	0xb5e2e2fa, 0x326af006, 0x57ca75e0, 0x95fc95e0, 0xa98f9daf, 0x9cefee34,
+	0xa5dff816, 0xde703304, 0x5bbc3753, 0xbab0f982, 0x086b9f79, 0x679ed7d7,
+	0xe7e9b32e, 0x981ef991, 0x9cf383c7, 0x9aafe1be, 0xe825a7d0, 0x39ed3667,
+	0x35cf192f, 0x93f38ad4, 0xfd5af6a7, 0x3e5f8e8a, 0x1e70f2fd, 0x1b4fa5ea,
+	0xf2c7ccaf, 0x5bcf2a54, 0xf53bda9e, 0xa9d5f210, 0xb12d1c9f, 0x9ea738c0,
+	0xd2a25a3f, 0x60d85b3e, 0xef2f6a7f, 0x203b412e, 0x7c03daf3, 0xdfaf8b67,
+	0xfcfe0b56, 0x4aafebda, 0xc8d5e788, 0xef1ca707, 0xebfae096, 0x0f09675c,
+	0x7cb9db0f, 0x6da1923c, 0xd32332c4, 0x17fa10f4, 0x4fc1a45a, 0x5b8788db,
+	0x75265822, 0x7971fbb7, 0x23bbb7ce, 0xfa7bba58, 0xbd7618fd, 0xe201fe05,
+	0x67b1f3d5, 0xbe1fd63f, 0x33e504f2, 0x1ab017d9, 0x80916380, 0x3b59f7e3,
+	0x3a04a91e, 0xf37d2efc, 0x7e86e423, 0xf685eb01, 0xa0dff19b, 0x1e818e87,
+	0xdc6c80f2, 0x7cfb72a4, 0xb512a553, 0x191ff853, 0xe9187947, 0x8a3545d3,
+	0xeea5aec1, 0xd3f94199, 0x6429af3e, 0x61a47581, 0xbff81a56, 0x66ceeb4f,
+	0xc5cec0df, 0x3883bf96, 0x9d9d7de5, 0x0952acfa, 0x67df30a9, 0x7fac8f42,
+	0xd3f1127d, 0x178a65e6, 0xfefb18f1, 0xcb5eeb63, 0x727a099f, 0xf3879dd8,
+	0x6efc8267, 0x90027916, 0xa7cf0537, 0x80f22c3d, 0x877b866b, 0x9ae3ede9,
+	0x8252f323, 0x46defaba, 0x89d6dfbe, 0x7ca15ee7, 0xed7b9c41, 0xfaa2cc6a,
+	0x2a5e8d4b, 0xe9638d23, 0x434b66f9, 0x7bdf9e0a, 0x3342c2cd, 0x77bf97c1,
+	0xe51bff78, 0x1ddb42e0, 0x699b2fbf, 0x33d6f187, 0xd6f8cf3a, 0x13ddefbd,
+	0x1df00e9a, 0x1929a4f8, 0xd2a740ed, 0xa61c478e, 0x23fdbe2a, 0xcb5d4f51,
+	0x75a54f48, 0x306e742a, 0x3611cbad, 0xb7d3fce9, 0x765edc2c, 0x72de785b,
+	0xb442da2a, 0x7fa5b32f, 0xef413fd7, 0x0fea0cc7, 0x7b9e1f81, 0xa98f9d8e,
+	0x4ecf94fd, 0x7c30def4, 0xbfb9fc6f, 0xad4c77d7, 0x2a89f3a0, 0x66a77fb7,
+	0x903eb667, 0xcfebfbcb, 0x79e1f497, 0xfa7238ce, 0xbdef3117, 0xc7f74e16,
+	0x64768d72, 0x8fdb9597, 0x1df316ff, 0xa392dc68, 0x9651bf3f, 0xffe8dfc0,
+	0x335ff2a6, 0xe488ff68, 0x68f596be, 0x3f72bcfc, 0x11fc49e5, 0x3619af8e,
+	0x577d470e, 0xca04b2b1, 0x97ae4e19, 0xe50eb0d2, 0xeb9c550c, 0x689cfc66,
+	0x2b56455a, 0xe28e5f9e, 0x5a73af81, 0x1c16bf4f, 0x7dc3dfcf, 0x7c0fb4df,
+	0x29ebf20a, 0x7fee39a4, 0xfd11b6cc, 0xaa825b67, 0xbc52f486, 0x9d22578f,
+	0x3a238cf6, 0xec958fd9, 0x5c3a464f, 0xde4cf2cb, 0x2dec1f28, 0x9c627a05,
+	0xb6f14fb4, 0xa73ee8b1, 0xe340bf9c, 0x23e595f8, 0xc877e04a, 0xea5a05e7,
+	0x784fdc0c, 0x82581ec4, 0x7e113247, 0x678c165b, 0x478cde0f, 0x5debedd2,
+	0xf4e0154d, 0x3b40b5ed, 0xba360bd4, 0xfe00369b, 0x4704a6f6, 0x6b9796e2,
+	0x30e9a3bd, 0xb970a7b6, 0x68e8d828, 0xd1c8b942, 0xe61f3c3c, 0x5f22e7f4,
+	0x503dd40d, 0xdbabaf1f, 0xaf2aea62, 0xbed575cb, 0xc843e7fc, 0x5c5d75a7,
+	0xd6f006be, 0xfea0ac59, 0x7e135f3c, 0xf4398392, 0x547fddfb, 0xbe341382,
+	0xedc85d8f, 0x4a07dc98, 0x81f62ed0, 0x828b58b2, 0x1e04767a, 0xff47cb60,
+	0x6cca9bba, 0xdca54fd6, 0x59dbc8df, 0xea04607c, 0x76605353, 0x35e7d239,
+	0x18f7970b, 0x72b1efbc, 0x2d6bdd3e, 0xf985659d, 0x63d01e1e, 0x46ba5f7c,
+	0x81b669e8, 0xc15eedeb, 0x9b369fbb, 0xc9c01a42, 0x79e83876, 0x553f388d,
+	0x4c81cef3, 0xd4f8d7dc, 0xc9e22acf, 0x7b085cc5, 0x5b5f8f11, 0xb946822e,
+	0xef907fa8, 0xcc7c819b, 0x21d57c45, 0xd937505c, 0x847ce9ba, 0x87f69ee5,
+	0xff3718cc, 0x73c1e2d8, 0xbeb9d58e, 0xa2fe78fd, 0x0fae5f7a, 0xc3bde555,
+	0x9d577c79, 0xd1399ed2, 0xbacbe519, 0x21d94dce, 0xfb27f7c0, 0x95f2477f,
+	0x61ec878f, 0xa38edafc, 0xd79e105a, 0xa1a7bc75, 0x4524fd61, 0xda3e81fa,
+	0xb877bdb7, 0x9c12f92f, 0x3c6657ef, 0xa7803859, 0x14ee96d1, 0xc3c979fd,
+	0xa0fde7a0, 0x3d035fcf, 0xd021e58f, 0xf3d07eff, 0xd7f8be47, 0xaf3fd44c,
+	0xccd7c25a, 0xcd9e71c1, 0xe15e60f7, 0xc1f84f53, 0xb4ff5089, 0x3d6f8c60,
+	0x6b3e57d4, 0x7fbc600e, 0x96716d44, 0x6083ff40, 0x9dfde847, 0xc2f4eaff,
+	0xdb0583f3, 0xf471bd33, 0xd36795dd, 0x60981f99, 0x7cef997b, 0x36078f94,
+	0x976c9bfa, 0xbeb9f802, 0xea18ac55, 0x0d93795a, 0xa99365e4, 0x1f62d1fd,
+	0xc73867d5, 0xce597f81, 0xf2b187e5, 0x278e52a6, 0x71b4dfaa, 0xdfdc0cd3,
+	0x8a7bbb5b, 0xc89a7c82, 0x7d9d56de, 0xc825ce8e, 0x6b263e7a, 0xd4aaef80,
+	0xaa59e510, 0xce84fece, 0x271acc33, 0x61fe68f3, 0x1f2dc68c, 0x8edd7886,
+	0x13177c7b, 0xbdf843c9, 0x68b2f6c2, 0xabc1f51d, 0xd0be02a9, 0x41334d8d,
+	0x0cb11fbe, 0xdcf1fbb4, 0xe12b9aa0, 0x523c2167, 0xfb26aafc, 0x099a6e2f,
+	0xcd76ea41, 0x36867e38, 0x02afdfd0, 0x249abe1f, 0xfc682beb, 0x6293fd41,
+	0xf1c997fa, 0xf3c2e3eb, 0xb75a3d88, 0x2ff57f41, 0x59fbe8d6, 0x3b68ff88,
+	0xc727978d, 0x56f0475f, 0xf6f3370f, 0xbf65e850, 0x4dcfa51a, 0xeb4dfdda,
+	0xdaaf6f01, 0x97a8a57d, 0xa465affa, 0x7cff916f, 0x49b87e3a, 0xb3aad9e8,
+	0x39fd3157, 0x58b49b92, 0x90c75cba, 0xde3ee76e, 0xa2f186f9, 0x7a604ce3,
+	0x7e047ffa, 0x6fb7584d, 0xedd762bf, 0x03ce90b3, 0xc510b3f3, 0xf35b55f3,
+	0x07a75859, 0x5f1c3ffe, 0x027f0e17, 0x5ffe6638, 0x61ac6386, 0x451c28be,
+	0xfefef806, 0x80259470, 0x02b7d663, 0x959dac47, 0x67617ee5, 0x0d5452fb,
+	0xbdb63bf7, 0x8ffda564, 0x96c85374, 0xceba7687, 0x5b7a7644, 0xbf1f8b6a,
+	0xc6b6d8bf, 0x1ee1e74b, 0x722a04b1, 0xdd0a7fc1, 0xabfda269, 0x6ebe796d,
+	0xf6dadfdc, 0x26be792f, 0x8b3d349c, 0x071662ec, 0x3c5b6d81, 0x087e2aff,
+	0xa3efef8d, 0x3e3b44e9, 0xf646c532, 0xe59cdb72, 0x9f4fff94, 0xda1c7673,
+	0x0a7e9d49, 0x66531d91, 0xf3353f93, 0x3c26d6be, 0x149191ef, 0x2ffd1c78,
+	0x74dad425, 0x76bc7878, 0x58667fae, 0xbe6066db, 0xcf595b68, 0x73938c38,
+	0x803e702e, 0xfcf5abaa, 0xff311311, 0xbc1adc73, 0xbb780ad6, 0x1bf22aca,
+	0xf2852c29, 0xc9051562, 0x6dd2c2a8, 0x5a253ed0, 0xa7caf87f, 0x3191cf29,
+	0xefc860af, 0xaf814b18, 0xa67a3abc, 0xf641ffa9, 0x461afeb9, 0x8bf47179,
+	0x172feff5, 0x027d7d7e, 0xb4e81dff, 0xad1ce11c, 0xd4c21cf4, 0xd1e75d61,
+	0xd45f18d9, 0x139955ae, 0xe46d496c, 0x8bffdc77, 0xfd6207f1, 0x22de595a,
+	0x7c44acfc, 0xf3958cf1, 0x25ff80e5, 0xe40fadfc, 0xb3f0a37e, 0x1ea2ed2a,
+	0x9e506e73, 0xfe13ec17, 0xfc62df4f, 0x37d61268, 0xd769978c, 0xee7ce904,
+	0xe5deb172, 0xd1334a5b, 0x7fdca9bf, 0xd963ad23, 0xf7e4d9e6, 0x84bcdf2f,
+	0x784a7bce, 0x9bfc632a, 0x51265acf, 0x1d112bbe, 0xfd221fa4, 0x273f5899,
+	0xde157bd1, 0x41cfa256, 0x58edafcf, 0xe67cc36e, 0xf67fa8c4, 0x7367c42a,
+	0xf1a6dca0, 0xb31e09ef, 0x1b6d38f3, 0xb6005f7e, 0x399650ff, 0xb957d715,
+	0xdf092329, 0x716b623f, 0xf91e5ca2, 0x61d7d7e2, 0xf093f43f, 0x9529ccbc,
+	0x9eb2a5fb, 0xb72b9e08, 0x55e93f70, 0xe1accf31, 0xeff3661f, 0x1879c4ab,
+	0xe97ca696, 0xec7efc48, 0xa69d9879, 0xaf903bb2, 0x9d7810ef, 0x873e0b62,
+	0x155793f5, 0x5ea79f12, 0xc7cdd079, 0x79d79e37, 0xd3a5c44c, 0xee4dc3fb,
+	0xbfdf3a74, 0x71e5e1db, 0x23ac1946, 0x653e4fed, 0x7f1e8ea9, 0xaf8978b1,
+	0xc528fe31, 0x47d7a438, 0x702ce0f1, 0x0579f82f, 0x7e48df23, 0xa6f3eafb,
+	0x2dff066d, 0x69f4de7a, 0x8b4edbf2, 0xacf5e5b8, 0x724be6c8, 0x51ef6c31,
+	0xdebd4e31, 0xbf416e99, 0x16bcc030, 0xf5ae4b8c, 0x16eb9cc5, 0x11aedae7,
+	0x7dc209fa, 0xfa0daefa, 0xaf15f619, 0xcfac669f, 0x37eb1bf6, 0x7effc454,
+	0xee374d8b, 0xdf169fdb, 0xf0299e75, 0xb10ca726, 0x002d82de, 0x3bbd6eb4,
+	0xae127f54, 0x9bcb4777, 0x26fe7d6e, 0xb0584f36, 0x4f212345, 0x900eee34,
+	0xbca43c0f, 0x9d688580, 0x99dda94f, 0xc0a0b8fa, 0xb579ce22, 0x12f33aff,
+	0x36c391a0, 0x9fea266c, 0xe7eb955e, 0x4afefbbe, 0x4b18ebf1, 0xcefc0de4,
+	0x168bcc78, 0x2853ee2f, 0xff285a2f, 0x4edb3f51, 0xa5bf03df, 0xf7a1935c,
+	0x3900c7c7, 0x5d33ae10, 0x5f3c8663, 0x9bacf73a, 0xb79ec5fa, 0xe7cdfbff,
+	0xcec73c24, 0xe23e5ec7, 0x16007bc6, 0xf9d1366c, 0x5c8b85ab, 0xa4889df4,
+	0x6338ec6f, 0xe171a8b6, 0x84ff844e, 0xb8f4b774, 0x74e6ff71, 0x4af299bb,
+	0x6de3edb1, 0x5f8b37ca, 0xbaf31a17, 0x43fd9ea7, 0x57d60461, 0x375cf4ab,
+	0xd8e2972e, 0x638c36f1, 0x5f719d37, 0x3fbe7a49, 0xaefba033, 0x86fdb7a9,
+	0xe3cf20a4, 0x4903be18, 0x2f128fc4, 0xea70f089, 0x7e16edf0, 0xd164327e,
+	0x28c6d7e7, 0xef9439fe, 0xa7b2a4db, 0xd1a77ce2, 0x7be71364, 0xc44c9ed5,
+	0xfda5dd57, 0x2f2ab714, 0x41eee87e, 0x7ef160bd, 0x23e0e29f, 0xe97b0710,
+	0x3c775efb, 0xfc1bfdfb, 0xc4ec10ee, 0x8fb71b02, 0x12f3edb1, 0x17f8a39c,
+	0xecdf8741, 0x9bd1e4ff, 0xd013e087, 0x6f30733c, 0xd551ef35, 0x3aaef983,
+	0xdbc90f4b, 0x3718affc, 0x76fc7f11, 0xa0f29dbf, 0xe9da160b, 0xf9d888fe,
+	0x8f3dab4e, 0x9df30cde, 0xff707806, 0x00a8f4ff, 0x66f4f1e1, 0xf6fb83d5,
+	0x983ae7f3, 0x54ffd74d, 0x08f9f1c7, 0x0cce99df, 0xba701f3a, 0x49df3e2b,
+	0xfb655d3c, 0x45c57986, 0xf209fcc6, 0x8eadca1f, 0x3c57feff, 0xc70abbfe,
+	0xd7e1c29e, 0xd53a8b9f, 0x8f1c9f91, 0x7c1f72ae, 0x1cf18b4c, 0x2ee80955,
+	0x775eb71e, 0xb180acb0, 0x0c8eb261, 0xa075f30e, 0x7071e39e, 0xfb24f104,
+	0xdd7cd43f, 0x8577dc4c, 0x03f11fba, 0x9d5bf9ef, 0x7762bfd4, 0xe8cfc211,
+	0x059ab9bb, 0x3b01e64e, 0x74a399f4, 0x54f00db3, 0x43407dd2, 0x6475857f,
+	0xc46bfad0, 0x6ef0b1fb, 0x68fd8bb3, 0xe4ca87bb, 0xc23ffdb7, 0xba3a4a7b,
+	0x49f8bc93, 0xfc6a4756, 0x5d9a0073, 0x60039c31, 0xf1e50f6a, 0x3cf06632,
+	0x473eff6b, 0x87894db8, 0x3bfcf59f, 0x2abb18af, 0x8d46b7e5, 0x11ad7d90,
+	0xe6abf5f6, 0x5bdf10ef, 0x9ac492be, 0x355df46d, 0xbfe013e0, 0xb41717fe,
+	0x7af9403d, 0x1cac9dfe, 0xf31164a7, 0x47fae9b7, 0xe33cf26c, 0x833d7cc3,
+	0xbd70e7de, 0xfb033a02, 0x4cf6a667, 0x01bff250, 0x7e316e1f, 0xeb6b5267,
+	0xf43d4429, 0x15fc1284, 0xedfeadd2, 0x77ac4c9e, 0xfc9279bc, 0x67c573ae,
+	0x7f3205ee, 0xeed0d114, 0x3a5dddac, 0xb57f286c, 0x9d40e306, 0x7de28c7e,
+	0xf187c516, 0x5abcc3c6, 0x2c11d9cd, 0xdd143694, 0x126859b2, 0x9fdf33c7,
+	0xdf8099e8, 0x6e3ac1ef, 0x2ff5039d, 0x3fccf462, 0x69e9fc2a, 0x574cffdc,
+	0x730d41d9, 0xdd376a6c, 0x214bf0bf, 0xf214bf2f, 0x33dff1d2, 0x74fa46ae,
+	0xdcf269bc, 0x97e3ab93, 0xc1b21624, 0x7b5bd77b, 0x8efe827e, 0xebf6cbac,
+	0x869d2fc1, 0x72e36afc, 0x66b5e523, 0x7d397c51, 0xfe26e6d2, 0xc476f61c,
+	0xc7ce798d, 0xff23e951, 0x7f271fb7, 0xccd3a3a1, 0x61cd93f0, 0xa0e6828b,
+	0xc1ff8a33, 0x2a3d70e3, 0x96a21de5, 0xde425c0b, 0xe57bdf91, 0x951e59f7,
+	0xc2b5c7fc, 0x3c65ec7f, 0xfb11a87e, 0xf02a7fac, 0x1afe39d3, 0x5c600b3b,
+	0x3f8f27f7, 0x78fc8539, 0xdf2d9fa3, 0xbdf67e93, 0xa55e39eb, 0x38a362de,
+	0xf266647f, 0xaf296bfd, 0xf687ab2c, 0x207f24b1, 0x03d3c4ff, 0xd47a0a97,
+	0xe819359c, 0x46a7a51a, 0xdfcf94f4, 0xd2127b07, 0xfa5cc39d, 0x377d0171,
+	0x51f31b73, 0x66b6e33e, 0xe4e90b07, 0x3e51e3b6, 0xc63dc76f, 0x798967f9,
+	0x3e38925b, 0xf877c43b, 0x91dfaa1d, 0x37d5145a, 0xae075f80, 0xabcbfd4f,
+	0x79498f14, 0x95dce390, 0x7ee1f7c4, 0xadf357f1, 0x2bb67db2, 0x76a5deba,
+	0x2f24b7d3, 0x27de437e, 0x24999f8a, 0xc5e58947, 0x92f215f3, 0x4d05f84e,
+	0xf97b46ea, 0x9f1ff09c, 0x68aa6c3b, 0xdb7fc38b, 0xe73d7c6d, 0xec01a867,
+	0xdb844177, 0x32fd44b3, 0x15f9c553, 0x3c589781, 0x3fc7e7a4, 0xd056b2ff,
+	0x7f8ca6a5, 0x22f78ccf, 0xca0c3e60, 0xd78c1f6c, 0xd10ce65b, 0xef22cbf3,
+	0xcd493ee2, 0xca2f56f3, 0xf6f3ef6f, 0xf49bcc2a, 0x6aad6f3e, 0xc7a60e73,
+	0x1e8d6fe6, 0xebfd6f7f, 0xf42bf49f, 0xbecd3b63, 0xf3c1de31, 0x845dd927,
+	0x93bd019f, 0x68d83fc0, 0x3b3c7273, 0x792d9e38, 0x5ba78f5c, 0xb1ff788d,
+	0x33748790, 0xd7a0b644, 0xfe7905a6, 0x90bb39e9, 0x5b87900f, 0x4eec2f90,
+	0x2c7efe03, 0xafa969fc, 0xc6575f1e, 0x7ee1a78e, 0x6ff6886c, 0xc91f7e3b,
+	0x4b7a79c6, 0xb56fdfe3, 0x6309f05b, 0xea6eff46, 0xfb42af4c, 0x678aede8,
+	0x9ff68b0c, 0xe7bfceda, 0x061ddb35, 0xf02cdbbf, 0x7638e521, 0x3cc40f9e,
+	0x90cfa81d, 0xc31ece2e, 0x03e4bb3e, 0x7ae4d7a9, 0xfd911da4, 0x67f82f7e,
+	0x8ccfe0ba, 0xfc1f3e26, 0xca9ac2b3, 0xdeff01ed, 0x7841eb9d, 0x9da2b21e,
+	0x78f34160, 0xaddd67a0, 0x16f7d18c, 0x33fc1f62, 0xbb2df047, 0x07e81d6e,
+	0x7e16fe92, 0xd738875f, 0xd407fd28, 0x7a9d134f, 0x0e1c43b8, 0x55f5c2b3,
+	0x70927e8c, 0x7cfc3ac0, 0x138d171c, 0x8edc6fb5, 0xb58f42a9, 0x6322ef8a,
+	0xfe7fe6e5, 0x569b911f, 0xe9025e71, 0xbcdf4f10, 0xc96eec25, 0x0562fedb,
+	0xc04c6bf8, 0x624fc3e9, 0x1ce7ba4a, 0xb0bd40b0, 0x37cb414b, 0x82855720,
+	0x45bc70df, 0x18f8a3e3, 0xf032e49d, 0x3e2a3fdf, 0x0366df0a, 0xa3a2dff0,
+	0x2e2494e7, 0xf32a19c7, 0xc3fedf13, 0x80381fc2, 0x00d4efdf, 0xdf34505d,
+	0x969bf01a, 0xbf4763dc, 0x43e66de7, 0xfb74e9bf, 0x8c78d312, 0xbf70b75f,
+	0x6e2f4065, 0xbd07ebe6, 0x6d7a8ed6, 0x477edbcc, 0x2167d411, 0x5bce30fd,
+	0xd379f8c4, 0xe3185776, 0x198f2925, 0xe0667b73, 0xa39d473e, 0xf75dbd61,
+	0x277fa07c, 0xca8dcff4, 0x35ca0d75, 0x82b53bcc, 0x2b4eb3b7, 0x8b160fdd,
+	0x47bec62f, 0xeff226f3, 0x7ae24c6e, 0xd234f50d, 0x6ec21ca9, 0x4afdc03b,
+	0x798cc86e, 0xe4c657d4, 0x957dc44e, 0xa2c14943, 0xa67ef035, 0x29983738,
+	0x26669bce, 0x126b72f1, 0x0e99cbd7, 0x5c1d065e, 0x79ba67bf, 0xef79d8ff,
+	0x54defd12, 0xed7f064c, 0x7c3c8204, 0x38af9f30, 0x327e88cb, 0xed42bf4f,
+	0x8002cdff, 0x9997456f, 0x4d3b07f2, 0xea24fac1, 0xfb1d12a7, 0x0f8b3d4c,
+	0x1ef10123, 0xf3128ba5, 0xb167d493, 0xa3ea34fe, 0xfcf20d9b, 0x3be3825d,
+	0x9190afb8, 0xfafcbfd8, 0x027e7d7c, 0xb7c26b7f, 0xfa496fe2, 0x8c80bccb,
+	0x307f25bf, 0x6bad20f6, 0xbfce4cea, 0x6177afa0, 0xbafa0afc, 0xebc91a68,
+	0x6bbc780f, 0x719178e3, 0x4f66667c, 0xc0b7c61d, 0xbc9ef487, 0xe4f729f7,
+	0xe41e749b, 0xf537248d, 0xb7f0e5db, 0x5bc9c526, 0x6869a88d, 0x8487fba2,
+	0x42f795dd, 0xafdf6a8d, 0x19be3aa8, 0xfee1c555, 0x60c59269, 0x7d443a17,
+	0xd3971277, 0xa5115551, 0xd88dfa00, 0x015143ba, 0xfced119e, 0x0688f77c,
+	0x0c9ff746, 0xf0e61bcc, 0x95870d8e, 0x70a28adb, 0x17669b37, 0xe69e0079,
+	0x09af874c, 0xe0ce699e, 0xcd77080b, 0x039d08b1, 0x5bac7a9d, 0xd32978c5,
+	0xf205ffe9, 0x6bd7849b, 0xbcc08cf6, 0x8718e3bd, 0x9fc065b3, 0x79e6c9ef,
+	0x3c0aefc9, 0xc9fb09b7, 0x4efdd30e, 0x336f6e4e, 0xa6db19ef, 0xfd26673f,
+	0xccd7e858, 0x72e3ee28, 0x614f799e, 0xb8ba03db, 0xb03f3cb1, 0x0f979f03,
+	0xbf11371b, 0x307fcfb7, 0xc73ee2a2, 0x154d5b0b, 0xf6fc38e1, 0xa75394b6,
+	0x2eb8d7ff, 0xc957ff09, 0x4967ec87, 0x1def9a1a, 0xb7060f82, 0xa5ed443f,
+	0x84dfa64f, 0xd06cd6f0, 0x48f16e18, 0x033a67bc, 0x239f1027, 0xc4155bda,
+	0x9f8e63c9, 0xae0e7828, 0xce798aba, 0xaef6d203, 0x7bc1cb6b, 0x7cee6a97,
+	0x79ef072e, 0x38c0f092, 0x98d6ef84, 0x0fd28b73, 0x67e11ff9, 0x67033b94,
+	0xcebafc70, 0xb7bfb44d, 0x5fbf0772, 0xcfbae127, 0x9eb02f11, 0xd5bfc8f5,
+	0x5478bfc0, 0x8dfb0147, 0x6859acf4, 0x6a26efa3, 0x63fe7176, 0x18f0b41b,
+	0x8eefb7ac, 0xe47da098, 0xa61f7edd, 0xed77abef, 0xf0e99656, 0x4c26b235,
+	0xb9e77bfb, 0x97227ee4, 0x4bed11f7, 0xb38f886a, 0x63e43e1c, 0x71d92fcc,
+	0xfdcecf3f, 0x1e52deaa, 0x425af49f, 0xafd0bd63, 0x87c93737, 0xbabd3bdf,
+	0xdefa0afb, 0x35bcf5d0, 0x7ca3b8a2, 0x6f7ac0f3, 0x40f9c229, 0xdf20f339,
+	0x835fde80, 0x2726f2f5, 0x1a9fbe43, 0x77a9c743, 0x3bf6be73, 0xc31ef2dc,
+	0x63d7c889, 0x81aedc1d, 0xeebf205d, 0xf3c38590, 0xdd74e33c, 0x75c8149a,
+	0x87f7e064, 0x54f18611, 0x86bb454a, 0x387608f9, 0xbd5bf095, 0x37d683b5,
+	0x7bf71772, 0x92b577aa, 0x82fd4a3c, 0x7b7bc0f8, 0x457be2a7, 0x47040fc4,
+	0x943b93e9, 0x927fd0e3, 0xbcf3ccc3, 0xc7ec775b, 0xf019887b, 0xd02fc60b,
+	0xce4affbe, 0xe96e2a3f, 0xce3dc80d, 0x59e7c453, 0x097b93a6, 0xbff91c77,
+	0x1e77e118, 0xe5c83eeb, 0x6fefc23f, 0xe921fc12, 0xf5c1c330, 0x21c7a48f,
+	0xe300e80d, 0xa24bca1c, 0xa23ca471, 0xfa11ccfc, 0xc68ce4c9, 0x090e1249,
+	0xd9472ee7, 0xb8298e15, 0x775a6eee, 0xe09556ed, 0x0502d72e, 0x3b7c75ab,
+	0xfbf9c1cf, 0xb57782c0, 0xf9be781e, 0x9f0947e7, 0x3f0a2db5, 0x5472dac7,
+	0x3e7a879b, 0xe319acf4, 0xff19ab9d, 0x51cf747b, 0x7757cfd2, 0x76d7bc70,
+	0x736f56ec, 0xf728f946, 0x74c581e4, 0x95bb751f, 0xe9923fa1, 0x788cde0c,
+	0x024fc418, 0x25cf520f, 0xf4871392, 0xf91a4253, 0xe421e029, 0xf520dc62,
+	0xdf1156e4, 0xfe7f2730, 0x515d624f, 0x41ac10fd, 0xf927947c, 0xdf50d80e,
+	0x3ce8544d, 0xe933b487, 0xf51e3833, 0x37bdc4f0, 0xd287e64f, 0xb25f8c98,
+	0x63bee8e7, 0xe2b7d018, 0x5d04bbfd, 0x3f8479e1, 0x37687967, 0x74b1dc25,
+	0x6bf081fb, 0x1351f0e2, 0x476b1fc2, 0xfac05f24, 0xf73db19a, 0x41ec89a4,
+	0x86d6c86d, 0x98af26fb, 0x75df90e6, 0xf09b8160, 0xdf90b357, 0x67f9bc63,
+	0x84d4af5c, 0x777f749c, 0x256e704d, 0xdba543ed, 0xc50fb87d, 0x79b50782,
+	0xf774c1ae, 0xce9fbf3e, 0xcedd5c31, 0x8f4060e5, 0x4bfa73b6, 0x1fd72efd,
+	0xcfc7375d, 0xec858d2c, 0x6dbc51a9, 0x7d08f24d, 0xdfe5cc10, 0x3ccd7fa3,
+	0x7b1666f7, 0x88b3d29f, 0xcf5b5a8f, 0x2faadc21, 0xd35fbb79, 0xf2c727ef,
+	0xd7baf557, 0xac2ed10a, 0xa54c3aca, 0xb7a0ff3e, 0x7d057b57, 0x8be5149e,
+	0xa7985f48, 0xc93b727a, 0x0d07f54d, 0x0ace6f24, 0xc79c67ae, 0xd6307a8c,
+	0xb4772a5f, 0xdefdc2cf, 0x9e2a1ff2, 0x5ed89626, 0xde7850ac, 0x2fada3f3,
+	0xc19cf1bb, 0xe26bbdc0, 0x0e1bf03c, 0x3bbdffce, 0x97c4e101, 0xfe50da0d,
+	0xc78d57e2, 0x74296f22, 0x7dc0808f, 0x1719aeef, 0xd2e7887d, 0x7e532677,
+	0x375dd3e7, 0xc021f9dc, 0x72e3bbdd, 0x4de943b2, 0xfe9fe201, 0xf70fbb0c,
+	0xa97e20df, 0xebee8050, 0xe3765fdb, 0x3f27e4fe, 0xda2270ba, 0x9c050fb7,
+	0x5e667f27, 0xe7b97887, 0x865e9f99, 0x2561d5ed, 0xef6cf50d, 0x15fe1fce,
+	0x8ed570f5, 0x9a9f8a7a, 0x0d4bf47e, 0xe14d39f7, 0x677cfe56, 0x7dfb07b2,
+	0x65d37db2, 0xf6a6ef88, 0xb93f6a26, 0x07ea95bd, 0x4be9f99e, 0x33f68dff,
+	0xbf61f6e0, 0x4fdb3f93, 0xaa09a974, 0x04f0defc, 0xeee8fd7c, 0xa19f5cfd,
+	0xb07287bf, 0xc919eb90, 0x3f7f92d7, 0x8bd6e679, 0xc6bbfaf4, 0x60a5181c,
+	0x1f5661ff, 0x7d07d79e, 0x15fbfa4e, 0xc4ed533b, 0xce9cadf7, 0xaf74d5e6,
+	0xd73e7943, 0xdc61883b, 0x72febaf7, 0x91477d07, 0x4afb10e1, 0x293f1176,
+	0xbcc3ed0a, 0x6d05e972, 0x217dba4d, 0x9457bf49, 0x1756a3d9, 0x8b379f45,
+	0xb8939b79, 0xf514f93d, 0xd539c430, 0xac1efc65, 0x5f6c7f4f, 0xd6b5fe48,
+	0xd76bf743, 0x34be7114, 0x9a3d393b, 0xb7e57e45, 0x39630ee0, 0xcf02e41e,
+	0x8eeb40d5, 0xfadf292f, 0x1a6fd913, 0xbed357c2, 0x784752da, 0x0e7f11f9,
+	0x8ee7c658, 0x354b06a2, 0x1b592f3c, 0xe91c5e3f, 0x3dfd3274, 0x663a2376,
+	0xde92f28f, 0xe8c6fab1, 0x5511d2fc, 0x27dc26c1, 0x906d6ab8, 0xe17ea9ee,
+	0x5ee937e3, 0x2ac667e3, 0x30df8893, 0x2f76847f, 0x6a79a4e4, 0x70078f31,
+	0x7114ef9e, 0x17a987a3, 0x32aff1eb, 0x75fb49d5, 0x6a97a4fd, 0xdc5d859b,
+	0x5b19e221, 0x6bde367f, 0x2f39ef0a, 0xc09bedd6, 0xd5274e7b, 0x8fe7b3fb,
+	0x5a143b47, 0xabc87648, 0xa527bc11, 0x09a161fe, 0xa1e2e8b7, 0xf51738d8,
+	0xca77e61b, 0xe77ea59d, 0xe3296894, 0xdd3c58df, 0x3877da25, 0xea277efd,
+	0x16e79dc7, 0x7a09d687, 0x2cf4aa3f, 0xed0e3e47, 0x2f907bb3, 0x29eb2eeb,
+	0x3bb1ebd4, 0x0b4e9e04, 0x41dfc13e, 0x64cdb8a0, 0xb5df110a, 0xa4dad05d,
+	0xe77bb60c, 0x44757f09, 0xba41e2a7, 0xc73ad88c, 0x9bf03f40, 0x7f686bd6,
+	0xe4252ac6, 0x7eae76cf, 0x11e61c6d, 0xaf586e81, 0x495d98eb, 0x833b03f8,
+	0xe75d6cfe, 0x73840eec, 0x3eb5fa64, 0x3f0797dc, 0xe77d1664, 0xa0a6c351,
+	0xda3a3efc, 0xad246fbf, 0x1e786143, 0x384b51f3, 0xa3f7ed0b, 0x787d0ae3,
+	0x582ea63e, 0x0af24359, 0x2f7d2d7e, 0xfe40dc15, 0x26f79d6b, 0xc6a7ed1f,
+	0x853ef9ca, 0x1be054fc, 0xab8b1dfa, 0x7c2cbbf1, 0x7920ec3f, 0x2dccebaf,
+	0x9eaef845, 0x9e60f3e9, 0x8fc494ed, 0xf4dd2d2c, 0xf7a7183b, 0x27485958,
+	0x03eeaf97, 0xf80266bf, 0xafc17b35, 0x3fdf8099, 0x1571d9fa, 0x0d7a71c6,
+	0x5deab779, 0xcdef74b9, 0x7f8ed129, 0x2d7ddd5e, 0xe21195b5, 0xcfe11acb,
+	0xc5fd5ba6, 0x26e8ebb7, 0xfa5894fd, 0xf6e4ee3f, 0xe727bce8, 0x00463d12,
+	0x239f103d, 0xa26e9ab6, 0x863485f5, 0x8aaabbeb, 0xbe01ea45, 0x229ab6ab,
+	0xfa884f97, 0x3de3b131, 0x4f7114e9, 0xf518a05a, 0xa702f95b, 0xca87af4f,
+	0xbb26fc93, 0x2c628fce, 0x92e31930, 0x845d338f, 0xaf4e1df7, 0x7e0c87f4,
+	0xd3b8e0cf, 0xe1f8c3ee, 0x04d0969a, 0xaf0e87dc, 0xf2885a4f, 0x49d47a08,
+	0x781eebfb, 0xb6d6e31f, 0xb8f3b64b, 0xf9d689b5, 0xc247a77d, 0xe301b937,
+	0x5ac0fcdc, 0xbe5c7f6e, 0xe5d6fb78, 0x2ee7e94e, 0xbef3c62e, 0x3e9d7375,
+	0xff36af8c, 0xe38a5942, 0x746c85d7, 0x705d6e39, 0xf2579bed, 0x5fdf8038,
+	0xbaa2fc23, 0x347d1bf4, 0x7a7e20ff, 0x4e8ddb8f, 0x4ebaaf4e, 0x1c642f6e,
+	0x5e217a8b, 0x29ca5ede, 0x6b8c63ea, 0x39497f24, 0x3c79573d, 0xfc90096d,
+	0x2375869c, 0xe1f00e3f, 0x630f9c0b, 0xff8934e3, 0x8bc2f8d8, 0xef7506c2,
+	0x8f7d0776, 0xe69af52f, 0x3d451c0c, 0x6476d754, 0xd0abb123, 0xdc2f7543,
+	0x3f94385f, 0x78f95365, 0x3d2b9036, 0x1359e0df, 0x432a44d7, 0xc0df3a4e,
+	0xc6df5fb8, 0x1d8e8fef, 0x4f42b7ef, 0xbf4a7c49, 0xcf82f319, 0xc29ff943,
+	0xfa227d7e, 0xcf29d5fd, 0xfc0d8457, 0xdf0535e7, 0x44f17dc3, 0xf7be56fa,
+	0x7226f34d, 0x63efa97c, 0x99f325e9, 0x45d98eb8, 0xecb5fb89, 0x0c48f117,
+	0x3e0b14ff, 0x80e7037e, 0x07724f75, 0xbea0b917, 0xd3f99928, 0x7e8bdf00,
+	0x29f7e569, 0xc42fed8c, 0x655aaa78, 0x5797cc21, 0xf584b4ef, 0xa1f736e7,
+	0xf5ef040f, 0x33216cb9, 0x3bb95df0, 0x0671c1e8, 0xcbbd87ee, 0xc1e1e74e,
+	0x7282994d, 0x481ed23b, 0xf7e06575, 0x4f743d89, 0x1e0e63ec, 0x311ff44f,
+	0xc5cbcf87, 0xe87bbe7b, 0xacce84f7, 0xea7ca7cd, 0x61fc2f3b, 0xede01fcf,
+	0x1a3e7b53, 0xd493cfad, 0x55364cd9, 0xad3c6f97, 0x2b67dfc4, 0x167d7176,
+	0xf3f65bcd, 0x438be5bc, 0x63eb41e7, 0xf3d1fbf2, 0xfdf9b1b3, 0x6fa878e8,
+	0xfbf263eb, 0x6f5c5d07, 0xf9e7df47, 0xf14c77fd, 0xc7bd6fbf, 0x8bafdc65,
+	0xc5cfbf6d, 0x8f23abf9, 0xe3ff45cb, 0xe4fd184a, 0x115d6be5, 0x396b8fbc,
+	0x63bf463c, 0x311427b9, 0xf9ae51b9, 0xcdfc323e, 0xbe5f81b5, 0xe807d844,
+	0xbe474ea7, 0xff68790c, 0xd0f42831, 0xff57ce92, 0x72f4f18c, 0xc3a6d995,
+	0xbe6d4b38, 0x13fbf843, 0xba673a1f, 0x7e56ed51, 0x744c86e7, 0x6a2d86e6,
+	0xf455bca0, 0xf374f57c, 0xfabe72df, 0x57302bb0, 0x7fd21bf2, 0x5f5cedd1,
+	0x9756fec8, 0xe467373c, 0xd01377b7, 0x665dc739, 0x3ababe46, 0xc698b029,
+	0x4194fdbd, 0x7a569caf, 0xf201fe9e, 0x7bfe6ae3, 0xd7efb147, 0x8afaf98a,
+	0xc53ee9bb, 0xc97fd5be, 0xebaebf26, 0xff51b7d5, 0x817bcad5, 0x7b862c3b,
+	0xfc932b81, 0xf7efc4d5, 0xfba14f4d, 0x73c186ce, 0x1ab82782, 0xf6fe41e1,
+	0xdbf9eba7, 0x2ce78c9b, 0xba01b5ea, 0x921ef7d0, 0xcb946c2e, 0x23ae8f48,
+	0x36a58f44, 0x701bdd3f, 0xf0403f9b, 0x4c8e4a2d, 0x5ff018f1, 0xf7dd37f4,
+	0xf6e42958, 0xfdfe2d1d, 0x3e09f7e2, 0x8dfb283c, 0x4efafce0, 0x1e7aab36,
+	0xff234ccb, 0x2ce42c3e, 0x71cbde2c, 0xbc421ffb, 0x18795e80, 0x8e7400f1,
+	0xcaf5e8a4, 0xe7ba7ee4, 0x374a6fa2, 0xae7d1f7d, 0x80ac66f8, 0x8e784bd6,
+	0xd1385e73, 0xf0b56f7a, 0xb5df0075, 0x47af48b9, 0x87bfebc6, 0x5b80b9ff,
+	0x493be5ca, 0x142cbc46, 0xe091fbeb, 0x87974a93, 0xfd7c1be7, 0x3bce38d9,
+	0xb8f1f1a9, 0x768f8a28, 0x7fb583c2, 0x6fd01a71, 0x6d35d83e, 0x12a7e122,
+	0x938a0f9f, 0x49ff228a, 0x5c6b6dfb, 0x0bc5ed0c, 0xfdc9be72, 0x963f8f3c,
+	0x885a0bcf, 0x57d96eff, 0xc2bd6de0, 0x3145e77f, 0x2b6844c3, 0xdf2f32c7,
+	0x7fce980f, 0x203ecaaf, 0x195c8797, 0xcec4fc51, 0xc09b0c7b, 0xc4bb779e,
+	0xe63e40f7, 0x1f16f7c3, 0x8b75ccfd, 0xf43df0d7, 0xef4e385b, 0x1fc8479d,
+	0x0a45a63b, 0xda719c5b, 0xc7b6c8b5, 0x6b3b6894, 0xadc17ee0, 0xbbe99acf,
+	0x9ea66398, 0x2d7f7047, 0xfc99a6f4, 0x3dde3fa8, 0xfa2bbe83, 0xffa30ef4,
+	0x45d0527a, 0x20309f7e, 0x830b783f, 0xc5eff079, 0xcb9ce6dc, 0x3ee629e5,
+	0x14164af6, 0xfb13fbbf, 0xe103427d, 0x893df079, 0xe73c87eb, 0x7ce6e995,
+	0xf38269f3, 0xebfb8a19, 0x3ee327da, 0xc4bed45d, 0xf1f1d3ee, 0x474e6edc,
+	0xf6fea769, 0x304aaef9, 0xe77175df, 0xba7cf393, 0xb3bafe3c, 0xd58edcdc,
+	0x461becc7, 0xb3e795c7, 0xa49fa85a, 0x2cd9fd77, 0xd2eb2e7a, 0x37be8a8f,
+	0xfd8bc68a, 0x13e6472e, 0xa7beff25, 0x9efd1b30, 0xf224db11, 0x78099e86,
+	0x687bd0bf, 0x06df412f, 0xf52f60af, 0xfe4b8800, 0x9aa17879, 0xd8efe517,
+	0x9d5f0075, 0xd51effd4, 0x4fb8b704, 0x217642ef, 0xf821177d, 0xe59df179,
+	0xf25aee74, 0x854f546f, 0x71adbc78, 0xa7319e3f, 0x18b3ff41, 0x13a4b0fb,
+	0xb204c1ec, 0xfc0e74cb, 0x12378bf8, 0x5f32571f, 0x17d1e926, 0xe93f74ad,
+	0x120bb5d7, 0x4b421b9e, 0x8adefc2c, 0x6bc7ba74, 0x86ff988e, 0x981fee2e,
+	0xfbfe7e6c, 0xf5e67e55, 0x03dff264, 0xca05fb21, 0xa5fa855d, 0x00cc8eb2,
+	0x3162e9f5, 0xf00fbe0a, 0xb64a2a5f, 0xf2859834, 0xb7ffef26, 0x961670b3,
+	0xbcf9174d, 0x04ae5e58, 0xa7070e54, 0x30d62cf3, 0x6c9bfb0a, 0xff9c663d,
+	0x58da7991, 0x4fa01fbc, 0xdf89f249, 0x74fba3fb, 0xf3f303ad, 0x9dd64bba,
+	0x0eefc32e, 0x7dc5bbd4, 0xa366360f, 0x4673ebdf, 0x057da13e, 0x616cda51,
+	0x0701ddfa, 0xcdba448b, 0x8c00fbf8, 0x614f9bbe, 0x3dfc112d, 0xff17be8c,
+	0x1e1c518b, 0x76fc0fbd, 0xef2194f7, 0xc7b6370b, 0x2a9e17dc, 0x7e634ae0,
+	0xad221fba, 0x635f78c2, 0x42ad7386, 0x3016e13f, 0xc444cf3e, 0x0b61ff43,
+	0x6f0bef63, 0xe1fc7051, 0x1b73e341, 0x5f7a463b, 0xbeb20489, 0x93de8b4c,
+	0xdf8920b4, 0x22eff44b, 0x115b9c8e, 0x6f015728, 0xafd88bf3, 0xe8de50fc,
+	0xe1177e09, 0x4370f1bf, 0x17d40d6d, 0xe3c6cebe, 0xc9c530f7, 0x185dea9e,
+	0xefcadd7f, 0x3efe2d6b, 0xec361d67, 0xf0c78a3c, 0xc9b51707, 0x2b2ace78,
+	0xb17d718c, 0xd48fb443, 0x7f18bda8, 0x3fdf1100, 0x95f74bcf, 0x74f38bd4,
+	0x9a7987f8, 0xc333f3d6, 0x67d30768, 0x7ac46ff4, 0xee8cfdff, 0x19f79059,
+	0x408ec76d, 0xbf4afa9f, 0x87da0325, 0xe23e64cf, 0x03bed149, 0xebcf9dff,
+	0xdf889797, 0x5d47c08d, 0x2733ca9b, 0xc6fa9b13, 0x5cfcc1b0, 0x18bb35df,
+	0x73f954f3, 0x297f13a7, 0xba0a2f82, 0x7c51ff14, 0x3f68c22f, 0x972bbeb5,
+	0x1c17dfce, 0x719e51f6, 0xd4e1a981, 0x1bdf5c1e, 0x13effe3c, 0xc84cc6fb,
+	0x7918d4f3, 0xafca24b9, 0xe72c5ed4, 0x7accfb97, 0x3ce046be, 0xfc44a0f0,
+	0xc7bd12c4, 0x1662ece5, 0x6671c3fd, 0xbd25c744, 0xbdb45332, 0x3fdf0b72,
+	0xf646aa9b, 0x225e1ca3, 0x4e5162ca, 0xe2330166, 0x7f73c4ab, 0x5177ce13,
+	0xf21a68e0, 0xaf9b74fd, 0x9f46af19, 0xb86150bb, 0x4e9cc4af, 0xffb17ebe,
+	0x3d8af52d, 0xfb67e799, 0xddbab3dc, 0xdf997dba, 0x30df85ba, 0xb98d8d96,
+	0x24f7ff67, 0x3bffa517, 0xdb18dc91, 0x4066e463, 0x7d3f313f, 0x7dfb18b7,
+	0xff3f3ce1, 0xc05e6a6e, 0x7e3e7cf8, 0xe71f97d7, 0x15d0ec77, 0x0b8e8ccb,
+	0x78416472, 0x6ec77f62, 0x2ab7f48e, 0xa2d6fe8c, 0x8522fa7f, 0xa7b0c0ec,
+	0xc1ccbf6b, 0xe25ce67c, 0xb12ebacb, 0x43fc0f3f, 0xfd89e3df, 0xe34efaf9,
+	0xd77d7cfe, 0x74337b92, 0x9d75f3fb, 0xcf3fb55f, 0x5bbfeeed, 0xd30f74c2,
+	0xd604afbf, 0x165e7982, 0x7107c2fb, 0x9462783f, 0x3cc5aeee, 0xe35073af,
+	0x3107f4fb, 0x4bcba37f, 0xfcf070cc, 0x340b8ce8, 0xe5573e7a, 0x2129f2fb,
+	0x0b92f927, 0x665defc4, 0x7e41d998, 0x1fe7847e, 0xeb3e22c2, 0xb40d7e16,
+	0x47fca06f, 0xa465dc8c, 0x6547ca31, 0xf2963cdc, 0x8abb0b3a, 0x0d3e6327,
+	0x7fe533f4, 0x7a5eddbb, 0x98b0617f, 0x395723f2, 0x8af3a46f, 0x6aad5df5,
+	0x7adf4ea5, 0xf5f78d93, 0x9a5df9c4, 0xfa29e482, 0xe019a5df, 0x489e7a27,
+	0xa7dfcb0f, 0x9bbe62ac, 0x7de2e597, 0x9d774001, 0x3194b79d, 0x53fb4f7e,
+	0x5d2b9d0a, 0x76483ce5, 0x630ed578, 0xd45b943f, 0x6bafd57b, 0xcd537f74,
+	0x467c41ae, 0x5de52d72, 0xa1b517de, 0x3ee0afd4, 0xe611df4f, 0x77fa436b,
+	0xc05b8cc4, 0xe04f98ed, 0xa5e858b3, 0x3666f349, 0x24e53ee1, 0x565f9713,
+	0x7fc91be9, 0xe7917377, 0xc7551d84, 0xfe50cad3, 0x63eb9f40, 0x067dfcb3,
+	0xc4531fd4, 0x717ab1f8, 0x2e03f08a, 0x137d6153, 0x0a7d76a3, 0xa683f5e3,
+	0xbddd332e, 0x3c9ce02f, 0x9fdc4720, 0xd24a7a90, 0xc6e5ef03, 0x92cb5df3,
+	0x63c87e85, 0x184f4879, 0xc157f89f, 0x8d2a73cc, 0xbca1521f, 0xf407cc44,
+	0x84df210e, 0x9dfa364c, 0x034a8d8f, 0xfa1b79e9, 0xa03e508d, 0xfd7f4904,
+	0x46642abc, 0x1ac45ebc, 0x1726b86e, 0x03b758f5, 0xb07c05e9, 0x4d1fcf52,
+	0x5bbd922c, 0xb509f031, 0xe8c4a6f7, 0x3d12a61d, 0xc238304c, 0xa5ad7669,
+	0xc42bf47d, 0x6e53a273, 0xc9d51fb4, 0x3fb4618f, 0x87c01fea, 0xf52fddb1,
+	0x93ea3309, 0x8f05f65c, 0xf43feed3, 0xfb0f8c1d, 0x8c5fc22c, 0xa1dd4ba1,
+	0x641f8b93, 0xbe49fa51, 0x983598ba, 0xca1f00b3, 0xf75e792f, 0x2a5ba462,
+	0xfc8c51fa, 0x892c69a7, 0xe64d8be4, 0x57c907f9, 0xa2255e92, 0x4fa484f6,
+	0x7841cb0e, 0x53b4ed2f, 0xa462e9de, 0x58bdd013, 0x4aed2f8c, 0x6af4e4c4,
+	0xb0174879, 0x7ec1e61b, 0x97aa665e, 0xe4c933e8, 0x614cfa27, 0xdba434be,
+	0xd7ddf6cf, 0xe8eb7084, 0xe3192db0, 0x80e80545, 0x3ed8357c, 0xe463db18,
+	0x94bbe259, 0x2c9fc979, 0x9c394665, 0x670d04e1, 0x8dcafba2, 0xa0b363f7,
+	0x7b94f08a, 0x6f8fdd06, 0x41b1d232, 0xc8ae7845, 0x444bf632, 0xa7a41ccf,
+	0x89690fb4, 0x6ae529e9, 0xa9d39db7, 0xfa84e81e, 0xd2afd266, 0x34813867,
+	0x25ccade7, 0xc53bb0fb, 0xfaf584db, 0xc5f4851a, 0xcbdf6ee4, 0x106fcf58,
+	0x337eb9ed, 0xafd683ee, 0xde53ede5, 0x7ac0cc0a, 0x5ede3ac1, 0xc9b04f7c,
+	0xaddfe385, 0x2fd8bdd0, 0xcbc7727c, 0x47be1ed8, 0xcfca5fbc, 0xe06fd6e1,
+	0xf9847fef, 0x3cf10bde, 0x7c0ccb44, 0x9739ae3e, 0xf0b00eff, 0xfc172e67,
+	0xe3695bb2, 0xc83c20f7, 0xc8715dc7, 0xce28c496, 0x65cafee1, 0x6f979d62,
+	0x3f4cebe5, 0x1785557e, 0x37b2a9f8, 0x2d95d740, 0x1109c164, 0x3372ef58,
+	0xf1f9f204, 0x10bc1be4, 0x0d288f28, 0x500aa744, 0x72fbf49d, 0xc0b67cd3,
+	0xc7ef9e78, 0x92fa79ef, 0xf329bc79, 0x35ffb8e5, 0xfb4f675b, 0x469e7992,
+	0x654ccbf6, 0x09ef3f7c, 0x91a3f917, 0x7c8298c7, 0xfec0b88f, 0x57faf289,
+	0xbd9037e4, 0xe64722ba, 0xa5d47bf3, 0x97f15f30, 0x178acd9f, 0xcc9e7f07,
+	0x62c7e4ed, 0xaf3e4f1f, 0xbdfdf30a, 0xf4cbc8dd, 0x30e9ad7d, 0xe19853d5,
+	0xb9ddab1e, 0xfe7aaebc, 0x28f35f7a, 0x06b35dfc, 0x36ca8435, 0xcc7da15b,
+	0x679fe0eb, 0xffe14627, 0x2830d93f, 0x00800092, 0x00000000, 0x00088b1f,
+	0x00000000, 0x7dedff00, 0x45947c09, 0xf37f78b2, 0x093215cd, 0x87213b93,
+	0x98884013, 0x861c2184, 0x4109264b, 0xe8098414, 0x720d7282, 0xeb22dc85,
+	0x97f75763, 0xd9110441, 0x73d6f8dd, 0x0160763d, 0x18896151, 0xc3824830,
+	0x12a20882, 0x75040411, 0x0844ae22, 0xf1e20c49, 0xabaf2e1e, 0xbe667bba,
+	0xfc38666f, 0xddbf7ffb, 0xdb2e23f7, 0xaaefafa9, 0xeaeaeaea, 0x084c8eaa,
+	0x908238b9, 0xadc4b45b, 0x9680a1cf, 0xc8401bfe, 0xd5fa25dc, 0x3f02242b,
+	0x213c6376, 0x33fe1277, 0x192d7aec, 0xf01dc844, 0x289085bb, 0x2afda4b3,
+	0x9fdefe83, 0xd328bff4, 0xf3bfcf72, 0xc84d94a3, 0x3a558caf, 0xd50a1dd2,
+	0x8459ece8, 0x9c9b359c, 0x7c84be9a, 0xcce2392e, 0x7d690903, 0x965cff76,
+	0x64beceef, 0x47e696be, 0xb048d4d0, 0xefde62df, 0x13d2e27c, 0x977cdfda,
+	0x918f0bee, 0xfd22ed0d, 0xa43a6a57, 0xae9a1a27, 0x232f7e57, 0x41e93d1e,
+	0xf2ad7948, 0xe271257b, 0xe57acaf7, 0x91d99277, 0x845efd06, 0xf69f8a1f,
+	0x5907cb67, 0xcfff6932, 0xe6147fbc, 0xb9346c57, 0x97129a65, 0xc193d5ae,
+	0x1e7ce1eb, 0x4e157f34, 0xc8fba793, 0x64246f17, 0x6cc89752, 0xbb9095d2,
+	0xe67e8ecc, 0xf99c4238, 0x146529e6, 0xe1e9cebf, 0x5c5025d6, 0x4c396536,
+	0x6308fdb4, 0x8bce9b96, 0x4cc588d8, 0x79f12df1, 0x9f0c0d4a, 0x3c52471f,
+	0x4832f8c3, 0xe699e006, 0x14d1f53b, 0x8448e3ee, 0x93881bf1, 0x88c23e00,
+	0x4252112b, 0xbf1846ac, 0x42475e1f, 0x2179adff, 0x57ccaef1, 0x1f027de1,
+	0xd36244cf, 0x47137f41, 0xa775f12b, 0xfbd22169, 0xfbf2bb4e, 0xcb1388af,
+	0xc2ac9a4f, 0x24c9b12f, 0xe0aed7de, 0xca1cbb93, 0x9e041372, 0x3cf1ab47,
+	0xc515fccc, 0x01309d2f, 0x54d24c7c, 0x58c9e3fd, 0xb30d6f0a, 0x1cf6c5ae,
+	0xb852178f, 0xbac12eb3, 0x4b44c002, 0xfdb409d7, 0x926c404a, 0x3d22ae8f,
+	0xab189d58, 0xe707e9ed, 0x93761991, 0xee389e0f, 0x1499a0d8, 0xcfe5d22e,
+	0x06913c03, 0x29837ffa, 0xd210c53f, 0xb2f80994, 0x18262574, 0x52d47107,
+	0xde92d3b8, 0xd814da35, 0x132b488f, 0xfdb4e313, 0xdb4bf8fd, 0x3e066911,
+	0xb0cf20b8, 0x2a383267, 0x53f552f3, 0xc131b4e2, 0x5acf37fa, 0x91787809,
+	0xa38e81e1, 0xadf943de, 0x2b5f7d73, 0x2a7210e5, 0x942468ce, 0xa67467de,
+	0x1f5f52e5, 0xea2ee63e, 0x4a95ed86, 0xd0b6efae, 0xc764836f, 0x52cf3023,
+	0xf8cf5b8d, 0xa13a6aa9, 0x6f3f96ed, 0xf748adb0, 0xf8d43fcd, 0x2d23f008,
+	0xc93bffa2, 0x1d7ad2d0, 0xeaeb1752, 0x0bdefc74, 0xddca2ce8, 0x2b17451f,
+	0x9185ef5d, 0xdd60278e, 0xe8b8c3b7, 0xa309697a, 0xaf8e86eb, 0x01932245,
+	0x74e2549f, 0x7e02ca2d, 0x04eba3bc, 0x951297ca, 0x81d1c953, 0x351856fd,
+	0x5e1fb764, 0x757d78db, 0x096655b9, 0x9989f7c7, 0x4dc7ff60, 0xdf30d5b6,
+	0xae293d16, 0xe96c78a5, 0x9a48d3c2, 0xa01bfad2, 0xcf2840fc, 0x70e0edea,
+	0xabe5868b, 0xbee517db, 0xdd9236ac, 0x545fac74, 0xf29bb213, 0x4369e597,
+	0x4bb68b95, 0x147fd2a6, 0xa2dbed2f, 0x453e0156, 0xbce67dbd, 0xdd1c604f,
+	0x802df64d, 0xcd35d98f, 0xfb5f877a, 0xe01f30ed, 0x579b1d13, 0x454b187b,
+	0x45ccfb7f, 0xef1e209f, 0xbcdd20f2, 0xdb0160f0, 0xe1f6fdb1, 0x1fd21e4c,
+	0x72c3ac0d, 0xc5cb0ebe, 0xae53ab7a, 0x04a64937, 0x63f9468d, 0x5aa0b941,
+	0xc67a957f, 0x17ef844f, 0x4ebac4d3, 0xfb42d089, 0x64535953, 0x1fbec35a,
+	0xa64248a5, 0x64b2c91b, 0x21a33f9a, 0x7175e501, 0x1997b3a4, 0x0cd23ce9,
+	0x0ce489fb, 0x5f862f97, 0xe4b4bf8a, 0xd93e312b, 0xa9ed6fc7, 0xf6cf384d,
+	0x81a63f55, 0x786f2ebc, 0xa875e507, 0x191f3979, 0x48f38516, 0xd6e0fb60,
+	0xd9391b6a, 0x059787d3, 0x428f3666, 0x0f40acb9, 0x313664f2, 0x7ea7e81b,
+	0xc3d3fba4, 0x57b95c28, 0x6f285c47, 0x93901a6c, 0x9c63c397, 0x7e2c435d,
+	0x72612df2, 0xf0c96217, 0x688e49c1, 0xdc5c9c05, 0xb53e514d, 0xff22bbaa,
+	0x147d45ba, 0x1ccee9f9, 0xf963dc05, 0xebf94510, 0x7015f26b, 0x536e67ef,
+	0x35c1bf94, 0xc2770141, 0x9e3f202f, 0xca4e5d97, 0xbfae37a7, 0xde7f515b,
+	0xbf4859be, 0x895ebe3a, 0x4994d6d3, 0xd05b30f1, 0x80686e9f, 0x670e52c7,
+	0x68a3ded5, 0xb725b89f, 0xe1cfcb44, 0x69bb31fc, 0xf94258ee, 0x897d6fa3,
+	0x67221fa2, 0xd28e30ca, 0xa18912ed, 0x46a73eac, 0x7bcc4fb9, 0x37170946,
+	0x992cbe3c, 0xf407ea04, 0xdb4b4327, 0xac5d2129, 0xf5a8dfa0, 0x11519e84,
+	0xdd0fc8b1, 0x57c63748, 0x79303e6a, 0x074861f1, 0xf4f5e83e, 0x3e3e01b0,
+	0x19ebe2f0, 0xb9d5f109, 0x7b8e07b7, 0xee3a36de, 0x18fc40f4, 0x10fc9512,
+	0x43f25166, 0x1f928678, 0x7e4aac22, 0xe4ab9ae8, 0xa3be3507, 0x20fe4a6c,
+	0x105ffa1e, 0x568cc77c, 0xbca94df2, 0xefe00f72, 0x5f9e7872, 0x1fe90abf,
+	0xf0a987a0, 0x1af01e3a, 0xff6bc3ee, 0x2625b6dd, 0x61df660b, 0xe478041c,
+	0x197620f8, 0x046c52e5, 0x3e561dea, 0xcca7a14e, 0x107ae288, 0xd69fa76f,
+	0xf7d613bd, 0xa049c932, 0x967fd09e, 0xdcd3bae4, 0xc639df14, 0xd520a02a,
+	0xa2b3ec6f, 0xd32c1ca8, 0xdf21b3bb, 0xefc1ef4f, 0x417bd2ad, 0xa7411ef5,
+	0x7281c439, 0xa61f0025, 0x2f50f427, 0x3f40ff80, 0xff8411ed, 0xed077ea8,
+	0x5179f256, 0x7234b93a, 0x06a4be20, 0x0d911dc9, 0x72106cd3, 0x3fb171d6,
+	0x157ca366, 0x4a0da2f8, 0xe84772fe, 0x817da28f, 0x448f211f, 0x255206bb,
+	0xab7f0227, 0x50c913e4, 0xa9371de2, 0x223ff841, 0x35e80bd8, 0x416f9bc4,
+	0x0899037e, 0xbc4de94a, 0xd30f723f, 0x06a48d4b, 0xb242b2e9, 0x7f69972e,
+	0x4be975f2, 0x7f4ba508, 0x64ffd533, 0xa69b42d8, 0xd18d77c0, 0x773ec329,
+	0xfe60b91d, 0x3f5a06ea, 0xc5f95d61, 0xbff2d098, 0x5b8d8dfc, 0x281f549d,
+	0x2464f4d9, 0x5afaf4a1, 0xa56f135b, 0x2ed6cbf5, 0xb4d1b48d, 0x7d44eb45,
+	0x3c976bea, 0x7f6415da, 0xed8a3f7e, 0x264274df, 0x7c153f90, 0x795fa72a,
+	0xd7ac1c6c, 0xccead6ef, 0xb9522d32, 0xd036e0de, 0x375151f5, 0x46c92c7f,
+	0x8fc199b8, 0x54f8037c, 0x5e4a1b9f, 0x82de327a, 0x5933a3fb, 0x3ba90893,
+	0x62b4d099, 0x81463fcd, 0x3a49567e, 0xd4b8c196, 0x1fffa0f5, 0x595afee8,
+	0x77d4cf2b, 0xe11e720d, 0xb5d05aeb, 0x6fb1eeb2, 0xcdf848e4, 0x557e07a3,
+	0xbd062f97, 0x3b67ea8e, 0x89bb3c84, 0x45eb04dc, 0xe2b883e0, 0xdf93ef50,
+	0x99bb2178, 0xf66badc2, 0x787e4a47, 0xc421e422, 0xaced674f, 0x0969bcbf,
+	0xaa36874d, 0xfe5e90d7, 0xcf585cf5, 0x9ee12f52, 0x5a581a4a, 0x0e4773a6,
+	0xb654aca5, 0x687a874a, 0xaebfc6d9, 0x33c533fb, 0x5eb06639, 0xdd2fdb4f,
+	0x43c7f6f8, 0xa6bfbe40, 0xa6cb1d8b, 0x7de29261, 0xffa4a974, 0xe8f8e516,
+	0xdbfaf250, 0xfb164b7a, 0x8fb460fe, 0xedafa51e, 0x40ac93d4, 0xeed4147c,
+	0x414c7bd4, 0x3cdb52e8, 0x1e02648a, 0xdd03d27e, 0x9121debf, 0xf820f484,
+	0xa476f55c, 0xe909e383, 0xa5e4e9c8, 0x5cfabd5b, 0x412bf4c9, 0x2bbe7527,
+	0x0afa8cca, 0xca7a87b4, 0xf6ff1b1b, 0xf14fc526, 0xcc2b0627, 0xf76ff8bf,
+	0x4e3cc245, 0x5f18ab69, 0xde34b0bf, 0xd62dfb46, 0x98cde339, 0x2fc5efb2,
+	0x6df91afe, 0x8ebf87de, 0xd93fa827, 0x38b93492, 0xdf9824cf, 0xc4efe79c,
+	0x0e25cdf9, 0x17e2bbe4, 0x9fe83b64, 0xf464b5e7, 0x45d6416b, 0x175b3441,
+	0x15d356a7, 0x4a77e74d, 0xf38044cf, 0x8b5aeca0, 0x517bd287, 0x28dafc18,
+	0x8402ffd6, 0x9d191bcf, 0xf86b45ba, 0xdf4ba2ba, 0x3cd75f9f, 0x39f404d2,
+	0x004b6a9d, 0x6892af3d, 0xd21f1c9d, 0xfcaeda45, 0xa3026161, 0x8568b10f,
+	0xa8f2a47c, 0xf943be00, 0x2c2d9d26, 0x5c8f515b, 0xbff5f74c, 0xc74ff790,
+	0xd0f405dd, 0xf5c1f153, 0xa668caf2, 0x269fd327, 0x7e5fc7e2, 0xf7ad9beb,
+	0xf5b28f35, 0xabbbd62d, 0x7fe43468, 0x1fad887b, 0x839c97a8, 0x602772e3,
+	0x243bcefe, 0xe2060794, 0xd7aeb60e, 0x56baf8e8, 0xa13e0be6, 0xb9c2d6e3,
+	0x842fcbc7, 0xf14e6f9d, 0x27dcc8f3, 0x7dbf3d68, 0x8bfa12be, 0xac4f6c0c,
+	0xfd7c79db, 0xf7cd1cdf, 0xc9febe5d, 0xcf4171f3, 0x5b73eabf, 0xeeb5ce99,
+	0xe95eb0cf, 0x605a74fa, 0x30eceabd, 0x761b33ef, 0x5d377c7d, 0xc56a6727,
+	0x4fca553a, 0xde2d3af5, 0xa7f236fc, 0xa99e9d7a, 0xe83e3b7d, 0xeded7d3a,
+	0xb0664f78, 0x2bbffa75, 0xe6fe053f, 0xa7e52b46, 0xf0a18790, 0x728796a8,
+	0xa9f105b4, 0xe7f48796, 0xc8141910, 0x04ef827f, 0x5abc95bf, 0x1dc81d7e,
+	0xbe0a5f2f, 0xe0a5f2f3, 0x957cf53b, 0x5be753f8, 0xf9472ce1, 0xf0edbec4,
+	0xcf4a64a8, 0x6ac906b2, 0x3dbd60b0, 0xd93c5300, 0x35231b70, 0xfd63927b,
+	0xae0a9761, 0xa9b79555, 0xbcaabb60, 0xa9570543, 0x5c70bbca, 0xf4bbf565,
+	0x5b81e504, 0x10f75e51, 0x3d804671, 0xad7651a1, 0xa76ca8a6, 0xeb465e63,
+	0x47486fb7, 0x12697b7d, 0xc474dbb3, 0xfc8197e9, 0x4477376a, 0x75fc5346,
+	0xb373f184, 0xca3223bd, 0xdcd32ecf, 0xf5fca320, 0xdae8c8b8, 0xaa1af620,
+	0x3cfd2249, 0x62fe5424, 0x4d90bf66, 0xef408b69, 0xa0ad91af, 0x3c5ecd0b,
+	0xcef41229, 0xe31e86f6, 0x73efd327, 0x43baa1f6, 0x903db9da, 0x49b4039e,
+	0x38b3fe94, 0xe710b63f, 0x7ce8c353, 0xa2943566, 0xa57b3e3e, 0x4d735e92,
+	0x9ccf510b, 0x1efd04fb, 0xe12fdf44, 0xaf3f14ed, 0x2b212fcc, 0x1d289f91,
+	0x297760f5, 0x77cca359, 0x2ecffb70, 0x48fde7c1, 0x87b9c53f, 0x3942d5cb,
+	0xb064fc73, 0x0995ec57, 0x836749f0, 0xdcef788c, 0x9e08b920, 0xa83d986b,
+	0x3ca07482, 0x8569f813, 0x2d0fa0f5, 0x7cb75a6f, 0x5a01e83a, 0xf1eb6ca4,
+	0xda68e7ec, 0xaf58f5ba, 0x71bf00ed, 0x0938ed24, 0x08ed3fb2, 0x64dda1b3,
+	0x00cb8447, 0x3f7c6ff4, 0xa3b401ed, 0xce30ac18, 0x67df1df6, 0x3fb4df03,
+	0x79062864, 0xecca9ed5, 0xbf1a4b23, 0xe57266cf, 0x5b57a461, 0x37e99eb4,
+	0x99fdff0d, 0x06fae704, 0xf7d82b3a, 0xf9e38477, 0x30cdf2ad, 0xbff6c117,
+	0xfd30e41f, 0xd0a9f372, 0x61f20713, 0x19bc9904, 0x704517c6, 0x07db953e,
+	0xed3175ff, 0xa76ebcbf, 0x2fcd167e, 0x6ca7eb78, 0x37db0fd8, 0x4da67d33,
+	0x5dd2b847, 0xad1e68f2, 0x61c616d7, 0x056eefe7, 0x160db77d, 0x9e423747,
+	0xab70d98e, 0x4f0c14d3, 0x5e21a53f, 0xd13f10ae, 0xfbe47a31, 0x48fc7d7f,
+	0x2bf28236, 0x609465c2, 0x767e3fde, 0x0ec1e41c, 0x98a9f203, 0xc5da99ef,
+	0x6e5c7fa8, 0xfe62fdde, 0x4ae2f85d, 0xafb92de7, 0x7ff6de64, 0xe21f7a71,
+	0x5d7aa8fb, 0xe379f204, 0x8c6f08fd, 0xaf78e2b0, 0xfeabdf90, 0x337dd1af,
+	0xe5e47ba5, 0x7fc7fde7, 0xa68779f1, 0x9ce9befb, 0xc3b066ee, 0x13f5be55,
+	0xe56aef8e, 0x537fa6dc, 0xba7a17be, 0x3890befa, 0xf0a5a225, 0x744f0e70,
+	0xd2e79e4a, 0xc388f77d, 0xd2113a79, 0xdd475048, 0xcad38f27, 0x2a4b24c3,
+	0xde132828, 0x7a071dec, 0x8aa932cb, 0x4737eca8, 0x6476d3b7, 0x940c474d,
+	0x2d0e242b, 0x217217bb, 0x3c91df1e, 0x15f9d768, 0xb4852db1, 0x9a8ed482,
+	0x3bdd6902, 0x97b42547, 0x923f2184, 0x9e3df57a, 0x0d11f516, 0x1de8019d,
+	0xce2b00a5, 0xbe9f5a77, 0x8bc20722, 0xa293d8e9, 0x313f7f2f, 0xcfccd63a,
+	0x58bd1d7d, 0xc46fd33e, 0xfbe8727d, 0x66f8e55c, 0x4ba76699, 0xf36f41dd,
+	0x8c15c71b, 0x291e0093, 0x3ca6de9e, 0x7bfaa463, 0xd1d1dc12, 0x618fecf1,
+	0x72ef2df4, 0x141b63e2, 0xe694d01b, 0xa9563f7f, 0xec193627, 0xae0d5b24,
+	0xad4fd0b5, 0x1b4ddef2, 0xa1dbcecb, 0xef13d0f1, 0x421e0453, 0x3efaabf1,
+	0x1be80665, 0x667c6103, 0x74c6f8c5, 0x29631bb1, 0xf3d47a9c, 0xd5f1a495,
+	0xd75b942f, 0x60fa073d, 0x2b7fd33d, 0xf57bb386, 0xda326d8a, 0x0c1ada0f,
+	0xb18e892e, 0xde177eb8, 0x1b56b4c7, 0x9eb7dc09, 0xab48eba6, 0x55fe04bd,
+	0x371c0df3, 0xcd67075b, 0xea86a746, 0xee5896d5, 0xb24d908f, 0x3fd31e61,
+	0xcd31173c, 0x9ede7682, 0x5e76feb1, 0xab37fdef, 0xedcf9017, 0xedef54c0,
+	0xcce2f20a, 0x65ef04fd, 0x6d23b689, 0x1cbf9642, 0x23a3ce50, 0xa9e3d186,
+	0xb4167b68, 0xf294dcd7, 0x2857b414, 0x06e9ec37, 0xcec859f8, 0xc40c2359,
+	0x64e94619, 0x56b5ef90, 0xde95c9f9, 0x9cf196bf, 0xfbc2e9fd, 0xfa6567a2,
+	0x692dedda, 0x741eecec, 0xa5bf67f3, 0x988ef4ed, 0xd3daf78a, 0x93bcec0c,
+	0xbbb87f7e, 0x6f5f5d07, 0xf81189e9, 0xeabdd74b, 0x4e70ade0, 0xabad928a,
+	0x32b17f69, 0x217c0919, 0xce1b1bc6, 0xe7be23e6, 0x0246b0bd, 0x8fbe22f9,
+	0x7fd1d258, 0xb1f54d01, 0xf8c53f8c, 0xf4741446, 0xf0f932af, 0xe7e466de,
+	0xd716b319, 0xb4c3b093, 0xec0979c1, 0xeb0e7024, 0x3db7c84b, 0x5e1f786d,
+	0x20ec4611, 0xdb35bef7, 0x7ce146ba, 0xb66f782c, 0xb7acacd0, 0x04fcd3f0,
+	0xa0571f28, 0xe91787bc, 0xc76658ac, 0x4341fb29, 0xe2767e9c, 0x0f5bad32,
+	0x1fb281f6, 0x77e9c4f4, 0x9d05fc0f, 0x5cefd3b7, 0x4f4b4f7e, 0x22cc27b4,
+	0xcc27b456, 0x9c4e1e5a, 0x3aa2e77e, 0xbd350e3e, 0x56fa71cf, 0x96896944,
+	0x2242abce, 0xdb954bf6, 0x9f764ffe, 0x23ff1eaf, 0x70e36eb0, 0x779fb87e,
+	0xab5c1a34, 0x9dcb03d3, 0xb8f6618b, 0x3dc51bf4, 0xc5cf07bf, 0x25e5b70b,
+	0x8aed2090, 0x1b07e2b4, 0xa5e1f971, 0x7983d682, 0x9230fc56, 0x6f07fab8,
+	0x66f982cf, 0x81cede05, 0x5fe81a7c, 0x4df1163f, 0xb091c44f, 0x97a95e7e,
+	0xf13d8347, 0xd19abd95, 0x678c83ab, 0x9f679f03, 0xf5f22d38, 0x5b626e8d,
+	0xa29e8415, 0xdb347c5c, 0x459f0117, 0xa8788159, 0x074cf7cb, 0x2469b87e,
+	0xefeb05b1, 0xc42f9c2f, 0x19a2ebb8, 0x18762b7e, 0xdb405ed0, 0x011455ed,
+	0x71733ddf, 0x74959b3d, 0x8d863cfb, 0x4f36eea3, 0x76d3f41a, 0x083ff72b,
+	0xe173df41, 0xe018f68e, 0x30b449c3, 0xda4187e5, 0xb7ecc92a, 0xbe94ae3e,
+	0xd6ac3f15, 0x102bd3f9, 0xae74ebef, 0xc576befe, 0x22f3643d, 0xe6def519,
+	0x95fefc83, 0x62eee3db, 0x499a4cac, 0x97b02ed5, 0x68495734, 0x41dbbbc7,
+	0xdeba22c8, 0x14b87aef, 0x97d34ded, 0x8234bebe, 0xca907f7f, 0x0912bb8d,
+	0x77a699b9, 0x09da56cf, 0xb70596a6, 0x3f7839a7, 0xfa0748d3, 0xa85f4cf9,
+	0xfb702fb2, 0xe541e383, 0x17e02ff7, 0xc60fd72a, 0x0e43bb72, 0xbd7901c9,
+	0x3d39e960, 0xf8a109a8, 0xc3ca85ba, 0x8b905a9e, 0xab5b4c46, 0x157e98cd,
+	0xf604fb6b, 0x8eb1f3a5, 0xb6ee414f, 0x52e4c87f, 0x4c73cae7, 0x418f2f9e,
+	0x2ef2c73b, 0xd78dff6c, 0xd3ea3b58, 0x3e3efe41, 0x8fc51c71, 0xeb5a2fe1,
+	0x9b878a12, 0xc0d3353c, 0x35e84525, 0x905aac8f, 0x127e8b11, 0xefc041d6,
+	0x32deafb1, 0x7133ec1a, 0x00db86af, 0x5cf22b7f, 0x62b18f78, 0xe7f41771,
+	0x0fcdd232, 0x0d8f7ae4, 0x3fb81a79, 0xb16ea1bd, 0xd76d1ba6, 0x0dd3b0dc,
+	0x35cb0efe, 0x6b3da0df, 0xf984cdf9, 0x287ef17f, 0x6919fb3e, 0x4c13f13b,
+	0x171d2f78, 0x50d44aee, 0xbd46ee38, 0x17ea0975, 0xe0a95f4c, 0x2c976834,
+	0x7e0a1c7f, 0x8264fb64, 0x16b13e7e, 0x087daf94, 0x0b92bfb3, 0x0f945f14,
+	0x8fc40c60, 0x2dab5aef, 0x92fc9f68, 0xd0fb29db, 0xce8ea1f3, 0x4f8a2be7,
+	0x6a1ecb80, 0xebe3051a, 0xabac48d8, 0xb7d89169, 0x912df292, 0xea337780,
+	0x13aba7bb, 0x16e31531, 0x6bd947fb, 0x3f41a36b, 0x9999229e, 0x43d7095f,
+	0x10121f05, 0x4c9e1456, 0x8bbf9c98, 0xa8539feb, 0xe3a30dd8, 0xd35887bd,
+	0x46dddea0, 0xf8a1a912, 0x3b50529f, 0x5299f710, 0xe7ec145d, 0xe30542a0,
+	0x8bfa5087, 0x72ea2758, 0x81af41a7, 0xc98db8f5, 0x11758a83, 0x6bbbb44e,
+	0xecffb03a, 0x7b1ebe38, 0xd22e3f31, 0xfd60d893, 0xbde8ec54, 0xa062e80a,
+	0xa5e303fc, 0x9b98ca72, 0xd19cfa83, 0x7f3fe748, 0x8a5b987b, 0xd9a7a3f4,
+	0xfa034fd6, 0x1c9484fc, 0x4a3a97f4, 0xd80447e5, 0xb8693c71, 0xeb47419e,
+	0x7d5cc306, 0x54ebdc1b, 0xfb30dc50, 0xee0ccbce, 0x2d6761c6, 0x7978d383,
+	0x777066e2, 0xdbddff51, 0xc743fec0, 0x621fcbcb, 0x1f011f70, 0x45b3e566,
+	0xce0c63f9, 0x1927f911, 0x7fb4483c, 0x1843c18a, 0xd3c9fc7c, 0x0f4139b7,
+	0x8ffae289, 0xaee783d5, 0x6b7b378a, 0xde96fdfc, 0xf3726389, 0x772b1874,
+	0x98cc9d3a, 0x08cbf400, 0x5e55fe5e, 0x02c5e85e, 0x493ea27f, 0x266f5e0c,
+	0x80bf37af, 0x64e129eb, 0x5bf31879, 0xba524675, 0xbde86eee, 0xc617ca1a,
+	0xd03a7345, 0xdaf80676, 0xed11f411, 0x244b7e89, 0xe9b497a6, 0xbbd89d98,
+	0xfdb1c66f, 0x30f3f684, 0xd293d3f6, 0x909bda15, 0x81f80fd2, 0xf39681f2,
+	0x80f81681, 0x7c6c5590, 0xc028ddb4, 0x3fa3b9b9, 0xbeedbff8, 0xfba7cb40,
+	0xcbe6adc6, 0xcddf3807, 0x81cec25f, 0x703d511d, 0xce1118bf, 0x403244f4,
+	0x380f8f39, 0x8b89de1e, 0xd2f4f362, 0x7ec24125, 0xa63c7096, 0xc84d7a78,
+	0xff79faba, 0x97e78f9e, 0xbd1fb79e, 0xd7e4326c, 0xcd9ab0df, 0xd60bd187,
+	0x85ea3447, 0x3bda2b8f, 0x3f5558bd, 0x98702e97, 0xac0f746f, 0x311848ff,
+	0xdab277e2, 0x9b3d2f5b, 0xc7a0abe9, 0x27ca2f96, 0x74ff6127, 0x85f78cde,
+	0x952a5c65, 0xe3d26f2f, 0x64ad6bfd, 0xef3cbf43, 0xe00ec73c, 0x79f334f3,
+	0x5d3cd99a, 0x87257e0a, 0x88eed23a, 0x2f63e408, 0x65edbdfe, 0x14f6f0e6,
+	0x7b582372, 0xd1422720, 0xd34bfdc5, 0x85538c45, 0x559e2f4f, 0x84f813e3,
+	0x32f58df5, 0xc6297c95, 0xf5a87af9, 0xfb33fe9d, 0xcaf563cb, 0x08e9437f,
+	0xc945a7fa, 0xe975e5d7, 0x7d327b9a, 0xae8036f5, 0xf3f3e717, 0xfdc71939,
+	0x0a485286, 0x7cce0fec, 0xfec37562, 0xfb80d9b9, 0xfd92e7fe, 0x505c5c54,
+	0xaefc20ff, 0x47b6173e, 0x1bec09e9, 0x7b40fb6a, 0x06c9b59c, 0x0967e5f7,
+	0x550edffa, 0x6fc033d9, 0x57c9b373, 0x295fb7cf, 0x4cf111e1, 0xc3b40cbf,
+	0xe68a7dd0, 0xb868300f, 0x018dd73c, 0x5c203d79, 0xf0d57705, 0xe0c8c4fd,
+	0x293b0e04, 0x2034f14c, 0x3187e459, 0x3f513af8, 0x51bf958c, 0x5f70e794,
+	0xa208fe55, 0xfdb28784, 0xb0a9e624, 0x20ff7031, 0x78d8a0f4, 0x2e43ce0b,
+	0x4be010d0, 0x80d53803, 0xc196f5be, 0xa08d7a05, 0xce94a853, 0x3dd82ab3,
+	0xf0bc6a7e, 0x977e6033, 0xbb40f2e8, 0x047615ca, 0x4761568f, 0x3a348f68,
+	0xc768aee5, 0xadf605eb, 0xf747788c, 0x32bf5a78, 0x3a7a75bc, 0xff0a1f85,
+	0x256cfd0c, 0x258fd31b, 0xa54c998b, 0x575a95e3, 0x23df41d8, 0x16a35625,
+	0x4aedc4e9, 0xe94bf770, 0xcbc77db1, 0x6eb3240f, 0xc18e30ec, 0xee54ae5c,
+	0xe3bbf1f8, 0x369fffb0, 0x7dfae159, 0xf7b3c370, 0xb838be81, 0x4c8fff61,
+	0x5fa1304f, 0x60f718ac, 0xdfa29bf0, 0x380deb73, 0x370dc1fe, 0x43f281cc,
+	0x01e86a3f, 0x84fc377c, 0x9988097b, 0x9237c6f6, 0xb91f281d, 0x25392c9f,
+	0xd5c19c41, 0x7c5e45ea, 0x7e8f43fc, 0x231f141e, 0xcc2e3e19, 0xc5b4fc05,
+	0x41e65c1d, 0x8b0a62a3, 0xe9f5e067, 0xb9fd03b9, 0x2b17493b, 0x23db5dd8,
+	0x3b6a3b58, 0x3a22d1e4, 0x787dfa3f, 0x9f811d07, 0x07e23fde, 0x3e4c1523,
+	0x29448f38, 0x926302e0, 0x39a17ca2, 0x4b7f915d, 0xfc8a0de2, 0x14fd2d5b,
+	0xc18c98f0, 0x5bb7f28a, 0xf8f014f3, 0xe5155bdc, 0x0a456c8b, 0x56bb9fb8,
+	0xdeffbe51, 0x21fe657a, 0x721d0322, 0x41775a8e, 0x1b4bf03a, 0xb507359a,
+	0x7482ed54, 0x1d0cb7f0, 0x90ec3b6a, 0xc1776a1f, 0x15876177, 0xce30f0fa,
+	0x3b2ec22f, 0xf4b93649, 0x89afedc1, 0x959e9a5a, 0x649f283c, 0xafed1d8d,
+	0x078e61c9, 0x473d29e2, 0x2814aa91, 0xb0ec0237, 0x33850894, 0xfc01fece,
+	0x32a73aad, 0x2051dc7b, 0xbbbbc80c, 0x788ed022, 0xf1b55754, 0xce43ea38,
+	0xc3a39054, 0xe62b263b, 0x8707e23d, 0x6479de62, 0xf74e8abe, 0xf342e02a,
+	0x6fe5146f, 0xc8ac5c49, 0xa8f2d5bf, 0x2b8f4e8a, 0xcfaddbe0, 0x4ab4e8aa,
+	0x1597a745, 0x1bbf82f9, 0x076c7db8, 0x3a68b5d8, 0x0054d3cc, 0xa5b9b874,
+	0xdb91e903, 0x74005354, 0x16b4721a, 0x6dc035e9, 0x3bf1002f, 0x2ed56f68,
+	0x5cf4dd48, 0x4efef503, 0xee9035cf, 0xb023e7a6, 0xcea9ed8f, 0xb56f74c0,
+	0x5bbfbf15, 0x7be98b9d, 0x3f4c36d5, 0x698d1ea8, 0xd31db553, 0x2c5aeada,
+	0x9ebab9bf, 0xf862d7d9, 0x0bf1473e, 0x38368c76, 0x9cbca253, 0x0db2f28a,
+	0x5f2850ce, 0x177066ef, 0x0c29930e, 0xebe5648e, 0xf2829a9f, 0x8cf83f74,
+	0x30bf81c4, 0xd824cf4b, 0xdd3409ec, 0x8186e70b, 0x5a89b8be, 0xe4a7688d,
+	0xb1eb9031, 0x525fbc31, 0x4296c632, 0x5ec5d2c8, 0xc18431f8, 0x2307eb28,
+	0x1bc1f8b3, 0xe21b6b61, 0xc61edfab, 0x97c6f7f2, 0x4173818c, 0xf330fae9,
+	0x29747e97, 0xc0528daf, 0xe649f595, 0x88e8fd2f, 0x7654c97e, 0xe5091492,
+	0x36c3d09f, 0x20438e48, 0x1e8dca7f, 0x1aa627f4, 0x6c2bfa30, 0x8044b16c,
+	0x85e0ea5d, 0xcf8011de, 0x672edc83, 0x3374fd23, 0xeda79a69, 0xff7d83a7,
+	0x124f4aa8, 0xef2941e9, 0x56b76853, 0xf413bd63, 0x3a6de724, 0x413ffc02,
+	0x51007662, 0xa604ddee, 0x6edfb4af, 0x21e0f3c0, 0xc60e6d8d, 0x9f024811,
+	0x149f718b, 0x11c2f7f3, 0x7489df22, 0xf9128f6b, 0xe5538e1c, 0x1d60a927,
+	0x5f19df2b, 0x05fe748d, 0x904ff9f1, 0xca7c6a0b, 0x97a66609, 0xa0a96db9,
+	0x50f808c7, 0xe41cad91, 0xdb3ca1c7, 0x83ef30f5, 0x17930376, 0xf5d708f6,
+	0x0db33768, 0xfecfd3bc, 0xc3a09d55, 0x1f00777a, 0xddc4fdc3, 0x3515ca32,
+	0x604a5ffe, 0x15f22afa, 0x0aefbb9c, 0x21cd73c7, 0x1cde290d, 0x387b5e84,
+	0x0974ce1d, 0x277df76e, 0xf9fbed81, 0x6e37cb13, 0x85cf7b81, 0xbb74d861,
+	0x93ea37bd, 0xf31255ed, 0x3aa96903, 0x560df2cb, 0x33f4128e, 0xd1bf029f,
+	0xf70d8dfc, 0xcb4c3f9d, 0xdc30b67f, 0xb9967b8a, 0x6eefe20f, 0x8c5a785e,
+	0x69bff511, 0x61f35213, 0xfdc29e1f, 0x6847a79a, 0x59bdd1e3, 0xd337a51b,
+	0xfa9b6676, 0x2418a32d, 0xf48b6373, 0x4e2e1451, 0xa41977b9, 0xd71f3d25,
+	0x595dd5c3, 0x40cb6be6, 0x22a72f0d, 0x5bca2063, 0x74d5fbcf, 0xc916335c,
+	0xe51e7616, 0xf4adb8fb, 0x045de2aa, 0xf1e21fbf, 0x78091447, 0xf1cbdede,
+	0xe5edea2d, 0xe0482af8, 0x245922f7, 0xb8aca2eb, 0x0125b8f7, 0xbda63dee,
+	0xbdc42bdf, 0xeb9f3288, 0x59eb1fbf, 0x75eba5bf, 0xb9104f2e, 0x9d812fbc,
+	0x89e90f9b, 0x9d55ee0d, 0x277db377, 0x87b9f27b, 0x67f9d206, 0xe8359837,
+	0x7ca33457, 0xb3a1d00b, 0x4751d39e, 0x4dfd61ea, 0xecfcce74, 0x96261230,
+	0x5e1fc7f8, 0x36b67f6e, 0xf7fc0b99, 0x7b1e01e7, 0x9cfeff81, 0x005351db,
+	0x8fd8b0fb, 0xbba83dc5, 0x03ef98ba, 0x77bf2855, 0x78422f57, 0xd313b54f,
+	0xf9cbd5bd, 0xf983503e, 0xc33f55ef, 0xdf1701f7, 0xf7e3d607, 0x98c9ea86,
+	0x6076a8ee, 0xbd8ba63a, 0x1df4e402, 0x47c60746, 0x81acfdbe, 0x675e7dc0,
+	0x47e30183, 0xf1788ae8, 0x538858b9, 0x58579832, 0xd495e302, 0x1f978afb,
+	0xb3fb7e54, 0x0b7ed8bb, 0x99e378fd, 0x2ebd3f40, 0x241d3f34, 0xdf390e5c,
+	0xd0743945, 0x07d6e42c, 0x7808b60c, 0xa2ad833f, 0xf72807fc, 0xbe78da0e,
+	0xed833f73, 0x601c9f3c, 0xefc043b0, 0x944ab831, 0x73dac03f, 0x063df80a,
+	0x4df288d7, 0x7831760c, 0xa21fd3ed, 0xd223cc5c, 0x056f586e, 0x2091f4c6,
+	0x79cd0b62, 0xdd9d61bb, 0x24733892, 0x826333ac, 0x56fcf905, 0x00dde2cb,
+	0xa558c98f, 0xcdba1305, 0xa861efd4, 0xa45b1f97, 0x53237a85, 0xea187dee,
+	0xb8f9ea8d, 0xe8debfd6, 0x061ed7cc, 0x9575ac78, 0x236bf416, 0xbe81c5c8,
+	0xf22c0476, 0xe2213ec5, 0xd836faf0, 0xaeca3f71, 0x247ee3b7, 0x477f9cf0,
+	0x9c3352d1, 0xb325ea03, 0x43b8e304, 0x404f06f2, 0x05c5630c, 0x1e291aba,
+	0xe13c12ea, 0x2b3ce98b, 0xf0821e01, 0xd97f8b63, 0x109dd5fd, 0xc2383f64,
+	0x2be807e5, 0x23ffb445, 0x3f835d74, 0x4bc70442, 0x88ccc365, 0x755e7899,
+	0x189e8044, 0x0490f5c3, 0x2dfe6948, 0xbfcb1d3c, 0xef6c941f, 0x30f8bc82,
+	0x03b79f81, 0x1861cde5, 0x73279507, 0xe40238d9, 0xcb9f328d, 0xdf62239b,
+	0xb2e2c01a, 0x8b0d49cb, 0x7c4cbee7, 0xb8dc405f, 0x84a71e2a, 0xa5b1eed4,
+	0x6f178b07, 0x2e2f1a0a, 0xfd031bfc, 0xb0b9f96d, 0x93cf930b, 0xc3d17641,
+	0xb9686760, 0xab971dfb, 0xcca0f0a1, 0xe0e285ff, 0xf90e2389, 0xbc3c5423,
+	0xf9c08be0, 0xb6f3b0d5, 0xea9fe196, 0x81c4c69f, 0x8823bf20, 0x6794ab1c,
+	0xcf212f87, 0x97f1f2d4, 0x6693bb92, 0xfdc1a794, 0x98b91043, 0xcb54e30a,
+	0xc93e6745, 0x7505fb80, 0x0a68f42a, 0xd3de213b, 0xed0c23b9, 0x8e31f514,
+	0x0fd0448c, 0x83be3bf3, 0xeb122d78, 0x371c3c41, 0xf6846e39, 0xbff33d25,
+	0x2dcdf110, 0x753f7d5e, 0x7923c62c, 0xfb0a7bf5, 0x9efdf7e9, 0xf20b1d49,
+	0xdec9bbad, 0x1921da1f, 0xc85d1fcc, 0xbef1508f, 0x3ed91343, 0xff92981f,
+	0x8e5838b7, 0xae7a369f, 0xf4e74dda, 0x62bf86ce, 0x57d9ccdc, 0x56c1c79a,
+	0x265dba5c, 0xb68f8a46, 0x0dc4110d, 0xe52d1be7, 0xd4969a3f, 0x2b8c36c9,
+	0x4d07bad2, 0x5bd7f08c, 0xe974ff98, 0xcadc08a6, 0x5c1b364b, 0x92fd6963,
+	0xd1b327ad, 0x0ea1f5af, 0xbe730fbc, 0x22d75922, 0x13d93cfa, 0x1b594fc1,
+	0x353e4edc, 0xad87e991, 0x8327c2db, 0xbf5a56bd, 0x25deed13, 0x707493b5,
+	0x4dca2a0f, 0x3e21d44c, 0xa7b43968, 0xb8965f3b, 0xe41eeb1e, 0xfc2caf7f,
+	0x665f5bb7, 0x7a92a976, 0xc60c2b9d, 0x36b5feb7, 0x3929c788, 0x4dfb406a,
+	0xf46ffae5, 0x4d82c740, 0x1f01231b, 0xd932f595, 0x550fbcad, 0x97ac41c6,
+	0xe3f006dd, 0x7f472baf, 0x23370a6e, 0x1e3c1b5c, 0xfafe72e8, 0xb71a9ba5,
+	0x4b0a293a, 0x12297f5f, 0x374e29e2, 0xbc048dad, 0x192f76d3, 0xf7101487,
+	0x25e8fb50, 0x134e1ee3, 0x134b03c6, 0xeb237155, 0xcb71b863, 0x3fdfc83d,
+	0x274787c9, 0xf3c6f3a3, 0x5e5c422f, 0x2f33e6eb, 0xfecb78c2, 0xf045ee79,
+	0xc23b26cf, 0xad0f60cc, 0xc630e57c, 0x7f7a8935, 0x627a6449, 0xe12fcbdb,
+	0x31db6a3d, 0x35b7afa6, 0x6dbe429e, 0x78c7ed7b, 0xd85af388, 0x0efe8858,
+	0x2414b70b, 0x02e72090, 0xbadf0291, 0x4d1e20ae, 0x755daf4d, 0xfc8fd0bb,
+	0xe837a52c, 0x9638dea1, 0x171672da, 0x2bf1e164, 0xfdc7821b, 0xd4abc405,
+	0x1c3f1c4d, 0x3a75e2ec, 0x415c85ab, 0x4a21cadc, 0x4057bec7, 0x728f0dbf,
+	0xf4e0fe7f, 0x50bf0b3b, 0x2a26353a, 0xd7ce56e3, 0x9fcbf9cd, 0x262eaf21,
+	0xfb8adc64, 0xe226f00a, 0xda24570a, 0x6c3c82f6, 0xc62afcdd, 0xc6dd0109,
+	0x6db689d2, 0xf1069f3c, 0x8eba2d98, 0xc1efdce9, 0x25acf70c, 0xfd70478d,
+	0x10f96db4, 0x8f08f6e3, 0xde236bef, 0x258f161f, 0x89ae79f1, 0x1c2ef160,
+	0x030f10ff, 0x3bf4d0f7, 0x7c617b8f, 0x4261e22c, 0x4c5cc1c5, 0x2df6ceec,
+	0xbe58ef1e, 0x2b8f38e6, 0xca4bd1f1, 0x5f353a05, 0xe048be32, 0xb8780cc1,
+	0x2bae3fc9, 0x3791bc78, 0x0bd38ffe, 0x5cf107e8, 0x0a2db8de, 0x3a58430f,
+	0x83c88242, 0x1e2c55b6, 0xe3ff7d4c, 0x3843cfa3, 0xd152ffaf, 0xf433cc59,
+	0xd3ad9239, 0x6aff8dcb, 0xd12673f1, 0x127388a2, 0x10bd6a78, 0x26a78e5c,
+	0x67eafdb1, 0x00b6b7eb, 0x092536fd, 0x66badbf4, 0xe62b7e85, 0x05754adb,
+	0xafadef90, 0x960c77b0, 0x3942eed5, 0x141796ae, 0xf760b62f, 0x98937d0d,
+	0x67a8aa9c, 0xe6eb44fb, 0xb6899708, 0x6df7fad3, 0x1b15cfc8, 0x8fb0f59a,
+	0xbaff59ef, 0xb317f99e, 0x84fb03f5, 0xadfc6fcb, 0x8d99db7f, 0x09fa1b72,
+	0xbce1d742, 0xe086ca9f, 0xf86e54fd, 0xa94fd146, 0xfccf56b3, 0xdfdd2e8d,
+	0x126dad69, 0x49ba77b4, 0x7269a607, 0x6df996ba, 0x24b7fba9, 0x4abdf8e9,
+	0xa8f7d70d, 0xc83f47bc, 0x9c271e61, 0x51c3735b, 0xc5e6b63e, 0x35a45da3,
+	0x6965af55, 0x7fff842f, 0x935bfbdb, 0xbfac8d72, 0x371f1851, 0xd6e8c62e,
+	0x8073f5d0, 0xaf513fbf, 0x00fff677, 0x8707cfee, 0x78e3dfa1, 0x4dbefcc9,
+	0x6827bc0a, 0xdf3537dd, 0x5f781d92, 0x91912ad0, 0x65279512, 0xf0a59acd,
+	0x0fef6aed, 0x477d16ca, 0xa19d1de0, 0x78102e8b, 0xefeae7df, 0xb3a29a13,
+	0x70b7602d, 0xfa6d812c, 0x829ad6a6, 0x597216ae, 0x0edcef3f, 0x67b012d7,
+	0xdec0b88c, 0xba4a18b7, 0x4daae158, 0xfccfddca, 0xbeaa79be, 0x31ae9877,
+	0x83ddf4b9, 0xe7909fbc, 0xdc82481e, 0x867b8837, 0x8ac730e4, 0xf71081a4,
+	0xc01beecf, 0xe4f915f3, 0x3fa6c7b7, 0x3081e780, 0xe71573f4, 0x27f58d99,
+	0x9fac60e3, 0xb93dc537, 0x34af7e9d, 0x79f8877f, 0x8f9f8932, 0xf28ac4ac,
+	0xf50f7e4b, 0xfb25cff8, 0xfb8a49b3, 0x08b9ef58, 0x63efabbf, 0x8cee7f85,
+	0xec276597, 0x0dbf85a3, 0xc608781b, 0x03961751, 0xc31fd8e3, 0x980641fd,
+	0xf1401f6f, 0xf5cb7673, 0x5b3fe039, 0x9eefb5e4, 0x88bcbd47, 0x338963db,
+	0xafd876f3, 0xd7bd848a, 0xdcf961e9, 0xd9febbde, 0x3ac3b7de, 0xa1c1fe14,
+	0xa2c56de4, 0x421f9137, 0xda12cbe6, 0xa6e4c939, 0xbd3f22b4, 0x072e4df9,
+	0x397efdc4, 0xa78b0bf7, 0xf68dc8d3, 0xbc5791f9, 0xba46e611, 0xcec4d97e,
+	0xe976dbc5, 0x09af1d99, 0xa78f21cf, 0x7c02de3a, 0x81da2c55, 0x762626f8,
+	0x6c96396e, 0x1d31fee6, 0x0eae5099, 0x6eb027ce, 0x7da184b6, 0xd1eb4136,
+	0x2ab8e95b, 0x8bf4128e, 0x33c7c638, 0xd40be9a8, 0x70e6bff7, 0x37e67ad7,
+	0xd7c3c6a1, 0xf1aa1149, 0xc60c37bf, 0x2231f02f, 0xfdc2d49c, 0x958f9d30,
+	0x98aac7cf, 0x814fd78f, 0x6ff74bd6, 0xebf0a2d7, 0x5b2af312, 0xdffc49d4,
+	0x1c5d6ad3, 0xe311df7c, 0x97dbdf56, 0x840f7698, 0x2ae4a37d, 0x02a7fafd,
+	0x3e01c46f, 0x871eaa59, 0x7ee32d3a, 0x17efea1d, 0xf67dc492, 0x7fae3b2f,
+	0x69bd7bb7, 0xf9153b55, 0xbbed1633, 0x713f7ba2, 0x75bff71f, 0xdeea17ff,
+	0xf66ec1ef, 0x8e946ecc, 0x29fcdfe3, 0x9df108f3, 0x1105eddb, 0xbe51c718,
+	0xc8156135, 0x7e470fe5, 0xc2f60f14, 0xf71231fd, 0x1cb4bde7, 0xf7bb52b9,
+	0x717bd567, 0x393f625c, 0x5846ed51, 0x3a9f076d, 0xa7bc31e2, 0xdb2dfc1e,
+	0xb05e8637, 0xf2c9b91d, 0xc231edf3, 0x32ec230e, 0xd4cf3b6a, 0xefe4666e,
+	0xec29bfe9, 0x9417fcca, 0xac472e7c, 0xffdc83d1, 0x17ee7cb9, 0xd65d3347,
+	0xe2877b40, 0xce89bda1, 0xb0475ee6, 0xc23de51d, 0x7b8e2e98, 0x73134e80,
+	0x88863f99, 0x5b942a5b, 0x7a049c9f, 0xfb8c934e, 0x7ddfc2d7, 0x2ce7b7f4,
+	0x34a8f481, 0x131ca277, 0x5eeb1774, 0x86a543f0, 0x14e7b1f9, 0x097fd058,
+	0x57d811e4, 0x0d34746b, 0x299ee742, 0x3c600bf9, 0x0e3afded, 0x8abf024f,
+	0x669dff2d, 0x09aebd41, 0xb39779cf, 0xbffd80df, 0xd73b105b, 0xe8393cb2,
+	0x298977fb, 0x6aceff4c, 0xbbfbb0d6, 0x7aeb92f9, 0x347973b0, 0x39acaa88,
+	0xe0192ee9, 0x559f963a, 0x2892e51e, 0x8c38359c, 0x851bdfe5, 0x88d3df71,
+	0xf3fb0747, 0xa60af00c, 0xc1624ce9, 0xf1b11674, 0xba3ae5f7, 0x9cfeb44b,
+	0x83f32306, 0x309e9e25, 0xfa10ec9f, 0xcc6eceef, 0x3bb7d3be, 0xf37ddf93,
+	0x19fc7295, 0x726eff9e, 0xef9849fe, 0x67b66ee9, 0xdd1bed21, 0x704fe2b4,
+	0x21a2dcde, 0x1a9df7a0, 0x9bb41bfc, 0x24df7a8a, 0x8dd8bfe7, 0x3124dbd6,
+	0x23674aff, 0x1d22a78f, 0xb6f6fef1, 0xd60b93d7, 0x02af7b40, 0xae3c815f,
+	0x29be462d, 0x935c3332, 0x457cec91, 0xca5da5eb, 0xf857d20e, 0x5c87c2f7,
+	0x86e117ec, 0xfdba4f3f, 0xbeef3a61, 0x073dfa1a, 0x02d8e5c6, 0xf74beae3,
+	0xff8c1373, 0x40a71e05, 0xdee0d2aa, 0x068bde6c, 0xc79bec0d, 0xbf03bca8,
+	0xa7e0e3eb, 0xb94fd34d, 0xdce7f63f, 0xfc19bb1f, 0x927a69ba, 0xe7482dca,
+	0x842560fc, 0x64c8e7f2, 0x95f2235b, 0x883bf82e, 0x21e726ef, 0xb4ebb31e,
+	0xd7678fb8, 0xfae7227b, 0x377f65d1, 0xb59a1f16, 0x5848cbe5, 0xef666d4f,
+	0xed126cbc, 0x73b71c6a, 0x0736efee, 0xb26ef5e7, 0xe7cc24ed, 0x01c764f5,
+	0xa3feb76c, 0x753f04ff, 0x7fde3eda, 0x4f1d4bb4, 0xf102950d, 0xa37f9dea,
+	0xe39fcd9e, 0xd3545379, 0x69bfa80a, 0x2cc0774b, 0x2c7ee2c9, 0x0527e804,
+	0xe7b33fc3, 0x0c74378d, 0xf8d17380, 0xff50728b, 0x3fef3131, 0xf38b3a0a,
+	0x286ba70e, 0xcf9287ba, 0x80cc78de, 0x442e1377, 0xe22f5c82, 0xbafa9376,
+	0x6fd0079e, 0xe04caf7f, 0x27ca23dd, 0x498efe0a, 0x48807a66, 0xf8f51ab3,
+	0xc6a6cf5e, 0x36ce7aaf, 0xce7a1d21, 0xe4e5e5a1, 0x507a15eb, 0xff1fe0d6,
+	0x2c58a7fc, 0x92412f0f, 0x42aac8bb, 0x629af7b8, 0x4c36f9dc, 0xb9b99a61,
+	0x66bdee10, 0x207b4a24, 0x1f49699d, 0xe25df705, 0x232b38dc, 0xecb00f6f,
+	0xca116b58, 0xc4583ce1, 0x814bfb7e, 0x1eee1c31, 0x39a170bc, 0x92df0146,
+	0x7f28ac98, 0x2287a5ab, 0x8dc64c7f, 0x9faf7c8a, 0xefbfb5bc, 0x47c0777b,
+	0xc3b07747, 0x9ca079d3, 0xb4656b21, 0x396d66db, 0x148ddb74, 0x4eeeb71e,
+	0x9b036c2b, 0xcdb8fe78, 0x4fd82e05, 0xb00a5de1, 0x3ee4b463, 0xa09fd4fa,
+	0x5f7b2d31, 0x74611e63, 0xebfc6b28, 0x799b6028, 0x3da1e6c3, 0x8c9de036,
+	0xd5dfc135, 0x52c1f610, 0x65e9ecc2, 0xbbf6d41b, 0x550ecc95, 0xe54faca7,
+	0x3c827fd1, 0x0ef5bbea, 0x6e97f833, 0x3763fc1a, 0x64d6e790, 0x284bbc65,
+	0xbff2f17e, 0x1fe03964, 0x17e6a1e7, 0xe9120761, 0x6e2c83b8, 0xc5e56ae1,
+	0xf85e403f, 0xe57917c5, 0x31fb9e98, 0xc41278f1, 0x3f1f0f47, 0x628e4b4f,
+	0x5aaf67e5, 0xd0b8ef0a, 0x13c4277c, 0x4b9db291, 0x85efaec1, 0xf32b3617,
+	0x2996941f, 0x95d387e0, 0x65bccaf0, 0xad43f5fe, 0x66fa8abb, 0xefca83bd,
+	0x39d8278a, 0x639f7024, 0x992ee8eb, 0x6fdb0554, 0x4a31fe44, 0x7853f40b,
+	0xc70bed83, 0xfef47aba, 0xc96527fe, 0xbb3b4f4c, 0x7ddff1ed, 0x6de27607,
+	0xce46fd04, 0x5cfb3146, 0x8d29dd76, 0x177ae406, 0xb36caf86, 0xec7e0347,
+	0x4ee1c5ed, 0x9cac83f0, 0x24fe811f, 0x866ce17d, 0xbfedc9e7, 0x7843d1b7,
+	0xbf09efe5, 0x03ff0f57, 0xd13f379c, 0x46fb1468, 0xff9589bb, 0x6cede48f,
+	0xeb67c8df, 0x83d03a63, 0x974261cb, 0xe252e566, 0xeeb0cb95, 0xbf003e60,
+	0xf78edcf6, 0xd37b009f, 0x5a3eb63e, 0x29e3fb89, 0x4cd8bfb8, 0x95a3ebfe,
+	0x7e77b2d4, 0x427dec2d, 0x7218bf71, 0xd1aeecbd, 0xbf8dfbc3, 0x2279baf4,
+	0x843bdf99, 0xc7071f5e, 0xdca93e50, 0x3b1afcc6, 0x4aefae1b, 0x804bd6fc,
+	0x068cf69e, 0x6dc05af9, 0x3bfdfc0d, 0xd8a17c55, 0x17b58837, 0xf78b13fa,
+	0x3ae80f3e, 0x541fa026, 0xc6fd16a3, 0x092ce816, 0x6fea9751, 0xfc5886b9,
+	0x68dbebfa, 0xe62df940, 0x73666ed1, 0x3e78dbed, 0x8171de1a, 0xc3ea3174,
+	0x87fd8a35, 0x58ba73ee, 0xec455810, 0x6370ec5e, 0xe1d03e42, 0x199c44b0,
+	0x309a9839, 0x35fb9bce, 0x27fc244d, 0xffeb4331, 0x6fd0b6ae, 0xf3bc6cef,
+	0x3e87d07a, 0xcee7bbae, 0x24fbf401, 0xe29b9778, 0xfb7740f7, 0x81df9834,
+	0x73f4255f, 0xfa91fc2a, 0x77f7acfc, 0xf307e50b, 0x65dd80c6, 0xfe83312a,
+	0xfa665e3c, 0xad8b7916, 0x2a37212b, 0xe868a6a5, 0x09e4f5ff, 0xbce99287,
+	0x01fd1613, 0x3df569f5, 0x5bea95f3, 0x26b0f285, 0xebede81b, 0x6e7f1625,
+	0x31577c65, 0x9393ccec, 0x7d508e40, 0xf28ff41e, 0x1ef89dfa, 0xe6dcfa81,
+	0xe7d5abd5, 0xf38dabef, 0xedcbd00f, 0x7071c96d, 0x7877388e, 0xcfd40912,
+	0xcd56f27d, 0x021f5477, 0xdc36b479, 0xa6aef8c5, 0x6fce94ad, 0xb364dac1,
+	0xf6e78a13, 0xa2d6f162, 0xdba7f0fc, 0xcbf3437e, 0x83370a5e, 0x9d30bdda,
+	0x818de138, 0xa37aab85, 0xdeafbbbd, 0xd006eaf2, 0xa1d65eaf, 0xe06bf45d,
+	0xbd7f0a1d, 0xd81706f9, 0x2c69e783, 0x8cf7847f, 0xf9193ac9, 0x060bd4ed,
+	0x1fe75fdc, 0x2bfb81e9, 0xa50b23ac, 0x4254a9cf, 0xfcdeb4cc, 0x5db193d7,
+	0xaf7625f9, 0x02537f3b, 0xfa0aa1c6, 0x8610bcb6, 0xd9c591f1, 0xf4dcbdb5,
+	0x47449edb, 0xbc1c4a54, 0x975ae7ff, 0xf054f144, 0xc01f4fd2, 0x537f36be,
+	0x47cbd21c, 0x61fbe0e7, 0xb60f4367, 0x84be39ce, 0xef05fedc, 0x0653120f,
+	0x87895f82, 0xeece77bf, 0x7db8720f, 0xd977cd4e, 0x7e32ffbc, 0xd840c3ce,
+	0x67cff058, 0xdca24cf1, 0x628d14a8, 0x4f942d3f, 0x3e076c54, 0xf9e037ad,
+	0xb82c35b2, 0x0a486a9d, 0x8c2b57db, 0x49ec2adf, 0x507e8b15, 0x322b13d8,
+	0xe7bbde09, 0xbff4b12c, 0x71f7a697, 0xd9c4a7fc, 0x4a7cc387, 0xfadf1f6a,
+	0xf9f1e21e, 0x7e813ffb, 0x3bd89af7, 0x7c31ef6f, 0x6f02ff0b, 0xbe0ec67b,
+	0xf429570e, 0x476db6cb, 0x7f781db2, 0x382bfc77, 0x3c6d9f0f, 0x25a654f2,
+	0xc7cc7ec8, 0x658cec2b, 0x60fede30, 0x4b8db487, 0xb473b3f1, 0x5efc1d7f,
+	0xeeaff44b, 0x53646cf7, 0xb6dbbc36, 0x07698200, 0x46cff2fa, 0x3ec36537,
+	0x4437fc2b, 0x14cccedc, 0x4a947fee, 0xfbc44352, 0x0b8949cc, 0xdf83ef1a,
+	0xe7de3aaf, 0x19f78b3c, 0x7de333fe, 0x0c9f393a, 0xef1e0988, 0x5fcf04f2,
+	0x43d96a42, 0x43ee5c72, 0x077f0dd8, 0x67bc5658, 0x8899e5c9, 0xc0da18f3,
+	0xb943ffec, 0x6364ab1f, 0x88432e71, 0x7aa7b59b, 0xe5640597, 0x89119054,
+	0x113ae237, 0xc606fdef, 0x7be13425, 0x0e9337cd, 0xacc46d4c, 0x1ba29485,
+	0x8ec491d3, 0x855228e9, 0x835268e9, 0x16a46de9, 0x09a4b1d3, 0x8dc7d253,
+	0xff78c7ef, 0xf3adc67e, 0x0cffb034, 0x6f5c1498, 0xbfaf837b, 0x5243e04b,
+	0x9578afbc, 0xd84518f8, 0xf121c5fb, 0x7e819292, 0xea2f0258, 0x9c31bfbf,
+	0x119db078, 0x80f651b0, 0xef0594f3, 0x0d880a4f, 0xc42bc2e1, 0xa1c7ae47,
+	0x2532f665, 0xe0e9025e, 0x1bd4854c, 0x19ee4607, 0x2b038ca7, 0x5e718719,
+	0x5cec39fd, 0xe26ff2c0, 0xb1f79de5, 0x2824507c, 0x82ca45fc, 0x5c71fe71,
+	0xef190f72, 0xb187261d, 0x6ef17ab8, 0x4230e4c9, 0xb5bf809a, 0xcf9438ce,
+	0xde297a8b, 0x392530f3, 0x355ca00e, 0x142d23ba, 0x16670b7f, 0xb1c6ffa2,
+	0xdb8dcb38, 0x7e3c5f25, 0xd75b0a4b, 0xc4aaa547, 0x8f1e743e, 0x77dfa7e4,
+	0xbfafba7f, 0x04e7e82b, 0x3f755bac, 0x3c3ac46f, 0xf6313fd0, 0x2cfcf3c2,
+	0xde6cafbe, 0xaadb343c, 0xaccd7e81, 0xdd67dfdf, 0x32cd3f77, 0x424edaa7,
+	0x821496f9, 0x5da44deb, 0xf02dece2, 0x893bc45d, 0xbf33edef, 0xbe26eadf,
+	0x531faa38, 0x5ca1671c, 0xd693c6a5, 0x571d0e5f, 0x5c46c4b6, 0x655be47a,
+	0x2e3a993c, 0x3df7b68b, 0xee52abcc, 0xd3fc0b98, 0xfe91f516, 0xcaefea2c,
+	0x1dc6acb8, 0x687114fb, 0xe3781d62, 0x1c593ad0, 0x438850da, 0xbff1f48b,
+	0x7c134388, 0x10c3d62c, 0x72c34388, 0xf281cc37, 0x813a3fc3, 0x4e236871,
+	0xda1c7878, 0x9a1c6511, 0x159ffbed, 0xb1de2687, 0xbd85b058, 0xdb80bfa7,
+	0xfd060077, 0x5f7894e2, 0xc4579f86, 0xdf7ca4b9, 0xdf9eecdb, 0x041bff49,
+	0xa7ec907e, 0xe859f9f8, 0x0fe0122f, 0x0cb5c279, 0x0fe01dc6, 0x09aff2a9,
+	0x568277fd, 0xe9fbf506, 0x2bcfca93, 0x5c219f7c, 0xcbc7997f, 0xaec0fcc0,
+	0x8f51a0b5, 0x1782d1fa, 0xfe82b3ee, 0x64d520b4, 0xf2b77945, 0x514be43e,
+	0xfccf3c9e, 0x9b7ac473, 0xdea09cbf, 0xac4f3de5, 0xeff0d833, 0x404bac23,
+	0x3e7bcafd, 0x0814f6e7, 0xebfb84d3, 0xdd1d514d, 0x536ddee1, 0xf4158663,
+	0x5b220fbb, 0x71b14256, 0x5e9f0ce1, 0x0e98797d, 0x9603aff5, 0x74888298,
+	0xf3b13adf, 0xf99e4275, 0x3af98335, 0x7bb136b3, 0xf6a39c85, 0xdc0b4882,
+	0x84fbb02b, 0xefc12d41, 0x4ae7c7a9, 0xc08a7b8a, 0xcb16c9f7, 0x7fb8255d,
+	0x6a10f760, 0xbfb8bd3b, 0x2985b22e, 0xdd423fee, 0x0ef38b67, 0x1e89efdd,
+	0x118d7bf6, 0xc48337fd, 0xf7233dd3, 0xf663bdf0, 0xf3c0e48e, 0xa6c61dd0,
+	0x4fabe034, 0x53731c63, 0xcb6e20e3, 0xce39416a, 0xf17ceae3, 0xbca06f40,
+	0x073ef114, 0x20e32da5, 0x54deea1e, 0xa3d40547, 0x067b30d3, 0x9947def9,
+	0xc5f27b99, 0xa7682dd7, 0xb7f54caf, 0x3bbff3d3, 0x1e2f5ea2, 0x59e3058d,
+	0x5095bf9c, 0x8d0338af, 0x15f3c60c, 0x8a674ff2, 0xdbf98729, 0x4adefeaa,
+	0xdfe5576c, 0xf167a95b, 0xad89a50d, 0x59b3af4c, 0xfa6e2cad, 0x959dfde7,
+	0x9553ddcb, 0xf428b626, 0xe621b255, 0xbea6ec8a, 0xfdae5df9, 0x5a7f6c36,
+	0x7e0a87d5, 0x98e8b198, 0x3a66cf82, 0xb5f9959b, 0xaf7838d2, 0x1567d28c,
+	0x35b3c7d0, 0x0b14d469, 0xf01801f8, 0xf7cbbf5d, 0x77f11a7b, 0xcf09baa2,
+	0x9f5e628b, 0xd8451f55, 0xc651ed53, 0xa979f067, 0x704f8bfd, 0xdc1399bf,
+	0xf704e66f, 0xfdc1399b, 0xbf704e5a, 0x7c87e116, 0x4c8aa242, 0xe47f5074,
+	0x828f8137, 0xc23723f8, 0xc8fe90f7, 0x0a71c7e4, 0xb7e7647f, 0xe47f0b08,
+	0x91e7a95d, 0xec9bbb8f, 0xc43b436f, 0x9ffbd1e6, 0x23f943bb, 0xeeca9fbf,
+	0xa5503e93, 0x22f3d29f, 0xb4f1a9fa, 0x0bd95e50, 0x37ac59df, 0xcb879010,
+	0xf1a6d924, 0xb0f18fbf, 0x16ce5377, 0x1dfc28a5, 0x8b7f962a, 0x0f7e17f8,
+	0xd0196f39, 0xdf7ca04f, 0xd7405ec1, 0xe71d53c7, 0x1dfd9952, 0xab2e87df,
+	0x5fbfb033, 0xbf21cfc7, 0xebf139e0, 0x718181d4, 0x77e6a114, 0x53d34e76,
+	0xe55e7499, 0xef153b91, 0x8af18b22, 0xfa718979, 0x5f8cb9da, 0xc50ef2c9,
+	0xf6db6b3a, 0x63e02f48, 0x9c167ef1, 0xa904275b, 0xe8c69f1f, 0x5287cf42,
+	0xa4bfed1a, 0x7d0f9d8a, 0xffb9adf4, 0x3ec7a013, 0x509dca13, 0x2cf3d5f5,
+	0xf10fb1df, 0xd2173ea1, 0x0b4d7679, 0x3b9fcf32, 0x6bf5abbf, 0x4e217437,
+	0x715097e0, 0x9b250751, 0x2d77c605, 0x4b5e96bd, 0xd2d7a5af, 0xf4b5e96b,
+	0xbd2d7a5a, 0xaf4b5e96, 0x6bd2d7a5, 0xf4e5ffe9, 0xfffd007f, 0x8000c102,
+	0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408,
+	0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382,
+	0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408,
+	0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382,
+	0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408,
+	0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382,
+	0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408,
+	0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382,
+	0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408,
+	0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382,
+	0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408,
+	0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382,
+	0x00008000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0x00002000, 0x000040c0, 0x00006180,
+	0x00008240, 0x0000a300, 0x0000c3c0, 0x0000e480, 0x00010540, 0x00012600,
+	0x000146c0, 0x00016780, 0x00018840, 0x0001a900, 0x0001c9c0, 0x0001ea80,
+	0x00020b40, 0x00022c00, 0x00024cc0, 0x00026d80, 0x00028e40, 0x0002af00,
+	0x0002cfc0, 0x0002f080, 0x00031140, 0x00033200, 0x000352c0, 0x00037380,
+	0x00039440, 0x0003b500, 0x0003d5c0, 0x0003f680, 0x00041740, 0x00043800,
+	0x000458c0, 0x00047980, 0x00049a40, 0x00008000, 0x00010300, 0x00018600,
+	0x00020900, 0x00028c00, 0x00030f00, 0x00039200, 0x00041500, 0x00049800,
+	0x00051b00, 0x00059e00, 0x00062100, 0x0006a400, 0x00072700, 0x0007aa00,
+	0x00082d00, 0x0008b000, 0x00093300, 0x0009b600, 0x000a3900, 0x000abc00,
+	0x000b3f00, 0x000bc200, 0x000c4500, 0x000cc800, 0x000d4b00, 0x000dce00,
+	0x000e5100, 0x000ed400, 0x000f5700, 0x000fda00, 0x00105d00, 0x00000028,
+	0x00000000, 0x00100000, 0x00000000, 0x00000000, 0xffffffff, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x65e21f09,
+	0x63e62860, 0x88237860, 0xcc2b4e2a, 0xfe9942ce, 0x0c0cccf3, 0x32f88117,
+	0xe2055f10, 0xe9a48cd3, 0xb045e2b7, 0x30327377, 0x7df90358, 0x9b8b5a40,
+	0xc8014181, 0xb3e201b6, 0x204bfe40, 0xadc40afe, 0xdc0c0c3c, 0x6a0c0c5c,
+	0xc4042c40, 0xcdf8bcb6, 0xff2023b7, 0xaf951b9f, 0x17ca83cd, 0x3fafc6e6,
+	0x7cbf0789, 0x6c790106, 0xf928b3f8, 0x4620e1f1, 0x2d43749f, 0xca86aeac,
+	0x6065522f, 0xe7c40df8, 0x681ae2a1, 0x10aac5f2, 0x03329cfa, 0x7e1ab243,
+	0xc80853b3, 0x000c060f, 0x4022bae9, 0x00000400, 0x00088b1f, 0x00000000,
+	0x7dedff00, 0xd554780b, 0x733ef0b5, 0x27bcce66, 0x20212793, 0xf0841e4c,
+	0x04242074, 0x11093a8c, 0x5076c403, 0xc2ab16fe, 0x25786784, 0x5ae5a911,
+	0xc0133bff, 0x51b91688, 0x7e2da5a8, 0x68bc104e, 0x01226f69, 0x903a4483,
+	0xbd08a5c0, 0x168b6ad1, 0xe088786d, 0x7e929205, 0xcfe956de, 0xe7dad6bf,
+	0x9939cccc, 0x77e8f881, 0xbf41ffbf, 0xdecfb3ba, 0xd7b5ef67, 0xcfb5ef5e,
+	0x30733d1e, 0xd7632776, 0x73941ff1, 0x4158c645, 0xf81d0ca4, 0x614b3ce2,
+	0xc18b72ec, 0x6c64cc65, 0xe8431eca, 0x68afa84e, 0xd7588214, 0x3633301d,
+	0x5b2bb181, 0xec46bd79, 0xb41b78dc, 0xb645d7b3, 0xd3b60a03, 0x8c8563a6,
+	0xfe31379d, 0xb1d76f4f, 0x9916c634, 0xe3457579, 0x7e3839c1, 0x9991ab55,
+	0x2df3fde1, 0x2beb07a2, 0x26410877, 0x27befb40, 0x7f180ca5, 0x32685071,
+	0xe3bea0bb, 0x6765c959, 0x2f81cd6c, 0x0abce0ae, 0x4dfa9f5c, 0x7c2125cc,
+	0x8d75a5ef, 0xb0696c66, 0x8c066a79, 0xe09774b3, 0x4b3cc1d6, 0x3ba10ab7,
+	0x2173e027, 0xcbb8c228, 0x2b995a76, 0x9d70c38f, 0x8eb4bcd1, 0xbcc02f95,
+	0x83670899, 0xe647b5e4, 0xa9f3f053, 0x72b981bf, 0xaf15f523, 0x5ef03cc0,
+	0x3704aff5, 0xc75ab12e, 0xff304d7c, 0xd9e67d95, 0x7d70d92f, 0x3dae5275,
+	0x7b951d7a, 0x834b1d71, 0x1b54d28d, 0x2d28d5c2, 0x6f191d1a, 0xcc4dced9,
+	0x6b828a65, 0x5f00f64b, 0xfcb6bb54, 0xf054cfd4, 0xd3cc652c, 0x83f84364,
+	0x9131ccd2, 0x22422de7, 0xbe38a963, 0xb19f1aa8, 0x99173d00, 0x6778843b,
+	0xf477766d, 0xaa755dbe, 0xa2656df7, 0x781c6efc, 0x87de45fe, 0x2a4efd67,
+	0xa9d3f937, 0x45dfb1fc, 0x9fc4fe70, 0xfd4fe547, 0x73fe7a6e, 0x2f95117f,
+	0xbe543df8, 0xb2a72fe8, 0x7ea5efd1, 0x5367f92f, 0xa3efc3b9, 0xafeaffe7,
+	0x7f15f2a2, 0x85ff3d2d, 0xbf95357f, 0xf9e807f4, 0x53d7f9bf, 0x04fb8cd9,
+	0x16ff6ee5, 0x83f8f72a, 0xff75efd4, 0xf9f72a4e, 0x33f9e89b, 0x13283f88,
+	0x3d3ace3c, 0x19424fec, 0xb0790273, 0xceb7af64, 0x59e4f500, 0xd7c03ebc,
+	0x7e012750, 0x3a802c06, 0xdaa0dfec, 0xb4233ace, 0xdbc55a0f, 0x6b9c0687,
+	0x743ed04c, 0x6ecf6f1d, 0x4331aef0, 0xde66f67b, 0xb0d83c3e, 0xc3ed02c6,
+	0x51f6f3b7, 0xac6b9d4d, 0x85aa3ed0, 0x721adfb7, 0xfd41b5ae, 0xcf5e0ed6,
+	0xb5aef4ef, 0x5dff3d43, 0xd5d89f5e, 0xef01d6b0, 0xdfc73c4f, 0xd9bde2d7,
+	0x60cf9ce0, 0xee0736af, 0x4207e8f2, 0xc23e725d, 0x1cbd8cdc, 0x77d516f8,
+	0xded4dc1b, 0x47aef81a, 0x92ea093f, 0x058fda9b, 0xc7bed47c, 0x53f6a5e0,
+	0xbed42581, 0xfb52f247, 0x6a4ac095, 0x4b50dd7f, 0x87eeaced, 0x54bafed4,
+	0x7549ed4b, 0xcfbea8eb, 0x8c196d00, 0xe33dd4e5, 0xcdfd0009, 0x511b7c11,
+	0x6aeb747e, 0x12ca18ab, 0xf91d287d, 0xcd8149e9, 0x5d80fe46, 0xf27bba23,
+	0x7c83c916, 0xc29bfcd7, 0x994cc497, 0xbeb052d6, 0x05a7e5e8, 0xd827e71a,
+	0x71825baf, 0xce3e6fb2, 0xaa4563b8, 0xab1dc671, 0x1209c652, 0x8dfe963c,
+	0xb26c7cd3, 0x4b639e1a, 0xa15e7195, 0x5bfd1c71, 0x8ab7b8d7, 0xb5bcf0d5,
+	0x35e7195c, 0x7fa9271a, 0x1b7eecf0, 0xc64423f0, 0xe036fdd9, 0xd9c69327,
+	0xf5a4e34f, 0x77fc9e0f, 0xe4e3548a, 0x8ca553bf, 0xce7841d3, 0xbb38dfe8,
+	0x86ac99df, 0xcaa59de7, 0x9c682738, 0x575bfd21, 0xd58aeffe, 0xb96efcf0,
+	0x69efce32, 0x8dfeac9c, 0x357de7b3, 0x3f79ecfd, 0xa27f3f4c, 0xb7fb7271,
+	0xd40f82ae, 0x41f053f4, 0x102e7e98, 0x6ff6479e, 0xa81f3d9c, 0x07cf67e9,
+	0x33f9fa61, 0x7fb633c1, 0xa3f82aeb, 0xfe0a7e9a, 0xcf9fa618, 0xfdf19e09,
+	0xd3f5e783, 0x7ebcfc6a, 0x511f8c3a, 0xfb0a7840, 0x33c4cf07, 0x3c4cfc6a,
+	0x8d8fc613, 0xbfdc99c6, 0xa33f5e71, 0x67ebcfc6, 0x1549f8c2, 0xf4775d70,
+	0xcf135d6f, 0xf133f1aa, 0x433f186c, 0x19529e08, 0x8ce3061e, 0xbece3f89,
+	0xecfc6a8b, 0x33f1c8bb, 0x3a27d3be, 0xce90dda0, 0xe4ce08dc, 0x0080de0b,
+	0xa814faed, 0x30f4b0bb, 0x3d3bc81f, 0xf8d1ddea, 0x84405772, 0xc4aefb76,
+	0xa2bb4ff1, 0x58e96ff5, 0x8263975c, 0x3877654e, 0x7aaa2d8b, 0x4a925952,
+	0x6454a73f, 0xb369eaa8, 0xf4f554b2, 0xdeaa4707, 0x5e3058cf, 0x7cbc1f55,
+	0x643eaab2, 0x7deaa955, 0x55d3e3d7, 0xeeeb59ed, 0x3673d555, 0xcf554f7c,
+	0x554f3cdd, 0x54badbcf, 0xedc8de35, 0xd1f5552b, 0xd5531ebb, 0x51acb6c7,
+	0x4f6dddd5, 0x3be3eaab, 0x3f8d539e, 0x54cff8e1, 0xb777c2f5, 0xa745eaa9,
+	0x3fbd555e, 0x1a6bdcf9, 0x3ce6c6fb, 0x8bae4a3f, 0xc95acf68, 0x910e33ce,
+	0x192d5ec8, 0xa3faa262, 0x7f546c43, 0x70df0ef4, 0x8fe3ec27, 0x6bd005f0,
+	0x5bbe4a8f, 0x2fec319d, 0x4b1d39d8, 0x63a7d2c7, 0xd7db7d45, 0x80ce801b,
+	0x5e874a2e, 0x650d3dcb, 0x3727ae8d, 0xe8dfca11, 0x2e916a4a, 0x4474151f,
+	0xd591567f, 0x8d58dd22, 0xfd70e88c, 0x0297c2b0, 0x54f87451, 0xcaf39726,
+	0x6a194fb8, 0x3eef51d3, 0x0066f756, 0x9993f2f5, 0x664cbc60, 0x9bc287ec,
+	0xbc0e40a1, 0x3a68f99f, 0x09268bda, 0xf9e8d0ec, 0x347f9825, 0xf9c01fcd,
+	0x6fcce3eb, 0xcd522dca, 0x52aace6f, 0x60966fcd, 0x4f63277e, 0xe7961dd7,
+	0xffde9137, 0xe6987091, 0xa6ad6537, 0xac4bd7f9, 0x25bf354a, 0xf2037f3c,
+	0x7f38f3c1, 0xe7f58c41, 0x3faf564e, 0xfd7aa96b, 0xcfff5f12, 0xf3c84eea,
+	0x3ffd685b, 0xf5f04e17, 0xd7c63d67, 0xa371846f, 0xf18477e7, 0x5ff9c41f,
+	0x69bf338e, 0xfd7ab178, 0xebd5cbd9, 0x5ff9f237, 0x9e4f7bad, 0xfff346df,
+	0xaf8f7842, 0x9a71fb3f, 0x75ac68df, 0x38c9a13b, 0x441b52d4, 0x2fe600b9,
+	0x050c801b, 0xc6444cf3, 0xde0c6248, 0xd164285f, 0x016a3c3e, 0x9ffe83ba,
+	0xd0de8059, 0x72ed977e, 0xd017ac16, 0x6996af0e, 0x4aaec17a, 0x657819e9,
+	0x57f72b41, 0xc333f818, 0xad2bbe00, 0x11fd9fbd, 0x7db05de0, 0xa025c91c,
+	0x2def8674, 0x23529794, 0xe6307c72, 0xe413321d, 0x877bd329, 0x9a863bdc,
+	0x2fd7683c, 0x1f630466, 0x60d85e3a, 0xc515df38, 0xa8b78b6f, 0xea824beb,
+	0x097702ba, 0x81940912, 0x0b579652, 0x7f079ef3, 0x7ddd8180, 0x2c6dec06,
+	0xb9b0313f, 0x0e7e785e, 0x452605fc, 0xed1d55f3, 0xabbd79cb, 0x73d61d3e,
+	0xc3704abe, 0x0d81ec88, 0x3a196395, 0x7bcf0172, 0x77ef0039, 0x852ff298,
+	0x7273e9d6, 0x003617f8, 0x7ff1477f, 0xb0bbc88d, 0x0ee08517, 0x7fbfe790,
+	0xba054573, 0x83d7d0bc, 0x5e577def, 0xc92de2f7, 0xde98f7aa, 0xa9cdef44,
+	0x1ea20c4c, 0xc36ceef8, 0x3b552eb9, 0xf1c03f30, 0xdd0fec91, 0xf1eebacf,
+	0xdfb99e82, 0x75d7eea7, 0x8dd1eac0, 0xbb4b7285, 0x3dbec181, 0x8719a550,
+	0x1f7f6879, 0xa878e192, 0x973edd56, 0x5fd42539, 0x9fab5773, 0xe3b40657,
+	0xcf00f800, 0xf81c793c, 0xe6f844e7, 0xd7f36dcb, 0x7daa021b, 0x0a947a02,
+	0xa22cf6e5, 0xbd0f5a02, 0x3fb7dd9f, 0x434041d0, 0xfb588107, 0xf9f7fffe,
+	0xae7d8dff, 0x3e492d69, 0x8ad70517, 0xe7c969a6, 0xdb2dfaa2, 0x5f555339,
+	0xd55fbc12, 0x4a96f17f, 0x86c2fb55, 0xf9f6aa25, 0xd5561feb, 0xa4ff032b,
+	0x75773fea, 0xa1fdaa9d, 0xed54a7da, 0xab3d540f, 0xfbefdfaa, 0x77ffaaa9,
+	0xdaaa3767, 0x864b0385, 0x46a8dc62, 0x881d0df2, 0x8df7aef1, 0xa1109b6c,
+	0x2fae855b, 0xfca9d3f8, 0xb2a2efd4, 0xc830e50e, 0x5e3edd75, 0x1cab6cd6,
+	0xa15bf28a, 0xb50c4ff3, 0x69fe5043, 0x672b55e9, 0x6325d0fb, 0x88bed083,
+	0x2e596717, 0xf3ca2f30, 0x19db816e, 0xb213f3ca, 0x0d6c675e, 0x8972d7f1,
+	0xd7f2dff3, 0x3f229606, 0xb942972c, 0xe3f8b6b5, 0xd68126b2, 0x1a36d8c1,
+	0x10704967, 0xfbd17918, 0xf382ad9a, 0xe69141d2, 0x6e1f46af, 0xdec1da12,
+	0x3f9c3a0d, 0xbee43ed4, 0xe78f0831, 0xc1c01d19, 0xdf49535a, 0x2797f25d,
+	0xfe23d39f, 0xf05e54bc, 0xbcf2a6cf, 0x39e547df, 0x6795157f, 0x7654b5fc,
+	0xf95357f9, 0xe5403f91, 0x2a7aff29, 0x5037f03f, 0x85bfd279, 0x83fbdfca,
+	0x7bf15e54, 0xf4e854a8, 0xb57d96ff, 0xf2bdb8e8, 0xffafb8df, 0x16afbd1e,
+	0x23c3939d, 0x0d06ebef, 0x55794abc, 0x61797027, 0xf31676e4, 0x788e2958,
+	0xc3078955, 0x94571448, 0xf0ddc1e3, 0xd3f62777, 0x1831e537, 0xcfe8eaef,
+	0x7b8e3173, 0xb191a4f5, 0xd3ebf8cc, 0x3c5c5fee, 0x46ee80b0, 0x3858b7f8,
+	0x72aa015e, 0xdcec1e36, 0xf3dd7b11, 0x92cf5d78, 0x7726fdf0, 0x3c355c74,
+	0xc072e22e, 0xd16af1cd, 0xdacf7b71, 0x847c722e, 0xb3efbb76, 0xc6b5e847,
+	0x718b93d8, 0x2347f662, 0x36c63d43, 0x055871cb, 0x575e015f, 0x3a7ff5f0,
+	0xfda04e3e, 0x1f1f105b, 0x47e0a5dd, 0x32bff0c4, 0x574aafc5, 0xae90439d,
+	0x7bf4cab6, 0x027865b5, 0xe7191d1b, 0xd38b9d6e, 0x7ef04df5, 0x0e4be8f5,
+	0xa657f3b4, 0xf2e79ceb, 0x456fe3e3, 0x16d3a653, 0xaab4a76d, 0x841b57eb,
+	0x70371e72, 0x831acc25, 0x3ce9d1f2, 0x2c728397, 0x9c654a9d, 0xf392e995,
+	0x0bf6325c, 0x2576f872, 0xea7e5f12, 0x6fbf5137, 0xe3788e1a, 0x6168e044,
+	0x247de167, 0xf1d9ebd1, 0x3ba5c7fb, 0x8c245ffd, 0xc336b0c7, 0x985f6867,
+	0xd1d7ffe0, 0xaa7a63ee, 0x34d6e32b, 0xade30189, 0x6a977cf8, 0xa5cf783e,
+	0x67ae94e4, 0xf5be88dd, 0x7f42bcec, 0xa0e7ca20, 0x1079489d, 0xbf6d53b3,
+	0x35eaaa24, 0x2a9d03ad, 0x00ff067b, 0x04cac739, 0x72c1d23d, 0xf5ba2c99,
+	0xc002f5b6, 0x2e9d0937, 0xf78147a4, 0x92ea615b, 0xafa42e7c, 0xcdb9dfb5,
+	0x681b3d85, 0x60f85abd, 0xf5ea66ff, 0x265fe1f1, 0x1bd47d5e, 0x22d7fe83,
+	0xd01ea3fd, 0x999f3f71, 0x43e40e02, 0xdc701e96, 0x6cc3fc4b, 0x9ae0fc61,
+	0x5513cc19, 0xff01c657, 0x5f6d47ad, 0xa4bbbe72, 0x76bbfee3, 0xbcf2cdde,
+	0xf55fc337, 0xe2a7b7ae, 0xac78b5ba, 0xe4b3fd6e, 0x5314fca3, 0xefc151e1,
+	0x59bbd124, 0xee97f984, 0x7f212d3c, 0x7204305d, 0xb903787f, 0x5b7e17df,
+	0x646b79fa, 0xd8f72b9d, 0xf95fbec9, 0x0bd79cac, 0x779c4eb0, 0xf13c915e,
+	0x0515e835, 0xa67c6807, 0xd3d88c2b, 0x5e6d7e4a, 0x27f232cb, 0x0901663e,
+	0xc51792e3, 0x9fb44286, 0x4a353697, 0x32f3801e, 0xbe2395d3, 0x1c77b32e,
+	0xb5fb51f9, 0x9f08944f, 0x899f6760, 0x6cec1386, 0x6cec1d55, 0xbb117d55,
+	0x51f30d37, 0xc01b368b, 0xaa75a7c5, 0x9d115fda, 0x5662ee34, 0xc9768f5b,
+	0xeffc96d9, 0xf0fb86dc, 0x88850bfa, 0x3cd079df, 0xf8f10928, 0xcbf1e136,
+	0xdf04bfce, 0xde77df1f, 0xf26add08, 0x561e328e, 0xc13c14ec, 0x44737418,
+	0x7d0ad796, 0x5f8641fd, 0xc59c0f89, 0xdea4417a, 0xa17fa9ad, 0xfe657fa9,
+	0x4bba014d, 0x24f7ec8b, 0xe91677d1, 0x38f906ad, 0x5fb7c221, 0x3ef4fc79,
+	0xa37f77e3, 0xf3560fe3, 0xc5ff8c0d, 0x4e7e3a37, 0xfa8df81f, 0x77e3be82,
+	0x59631d9b, 0xc4a9d902, 0x3a71815f, 0x1fe9bbf2, 0xd2136bda, 0xc0a69fc9,
+	0x39ddd638, 0xd9a38c41, 0x14e99dcd, 0x54bf07d7, 0x6024f30f, 0x0edf907f,
+	0xf9f016e6, 0x2cd37ed3, 0xf8ca8794, 0xe55eb776, 0xe914267f, 0x7b28fe35,
+	0x61f00737, 0x38a6a793, 0xfcedd41b, 0x5b6b666f, 0xe30b7c4c, 0x04e8fca8,
+	0x2ffe45d6, 0x9e7aa78c, 0xa1d59a38, 0xa8f44a1a, 0x6d154f9f, 0x9c4b6f14,
+	0x9c4e28c6, 0xfad7ae5c, 0xd2c315f7, 0x4740e0a2, 0x32c9ea1b, 0xcfa6e01c,
+	0x67fde014, 0xf08cf4cb, 0xc5ff8012, 0xbc593380, 0x01f9c216, 0x39df155e,
+	0x65f540f2, 0xe7aabc11, 0x4d19e700, 0xe50f207c, 0xb8b31246, 0x53801e71,
+	0xdbd1eed5, 0x0e1e2853, 0xa3e517f2, 0xc989d4cd, 0xaaef9c7f, 0xf4ebaf0a,
+	0x190b23e9, 0xfc385085, 0x942fa601, 0x83ef8bf7, 0xd313bfaa, 0x8f04d9d4,
+	0xd8361c7a, 0x6f8f2d19, 0x8309fd95, 0xe9133bc1, 0xad6870aa, 0xa717f388,
+	0xaec872bb, 0x3a214b68, 0xca5d5acc, 0x685d42ce, 0x9cf78460, 0x39ef1c0d,
+	0xf71e3a3d, 0x0e09675c, 0x268cb183, 0x9c833016, 0x301cad02, 0x8259c78c,
+	0x5ae49fb2, 0xcd3cc3a3, 0x7829a07a, 0x54a7adaf, 0xa73610b7, 0xfc609b09,
+	0x3e3de96f, 0x67c1c63d, 0xe375d2fa, 0x9ae161f0, 0xa5a0c18e, 0xb8211b19,
+	0x05080b41, 0xc2de8e87, 0xdf184a43, 0x790f4185, 0xd72ed46c, 0xdaed0859,
+	0x2faf0b06, 0xae9417d7, 0x988ff787, 0x5d71cbbc, 0x891ce4cc, 0x4a162b79,
+	0xb7c6f5a2, 0x0724024f, 0xb6f2b815, 0x4cb54d77, 0x2814fe40, 0x1ecc3fcf,
+	0x24255bb6, 0xa5361dae, 0x6ed0921e, 0x2dbcb6f5, 0xa2bb7fa1, 0xd76a6de9,
+	0xa1ca1d61, 0x07535dc9, 0xd4f88981, 0xf4d2b2ba, 0x4b5e3011, 0xd60eba65,
+	0xb2badcf5, 0x4f75ea43, 0x1c51d35b, 0x775eb759, 0x77dd66b7, 0xcfdd70df,
+	0x5d2eefe9, 0x75ffdc5f, 0x8b3fbec2, 0xa25199f8, 0xeefe510b, 0xf0282da4,
+	0xec99bb78, 0xc69c7941, 0x1287f638, 0x7e718437, 0xe850eb8a, 0xa14f7947,
+	0x9174789b, 0x79239ccd, 0x1f4d503e, 0x6d9ef4c7, 0x7a4bd708, 0x4054894f,
+	0x787b25eb, 0x2ee7cf86, 0x2dd08fcb, 0xd1f2f9b3, 0xe61832be, 0x57e702fd,
+	0xb2519ae0, 0x7802cc52, 0x21ec6177, 0xd49eb235, 0x2e7301d5, 0x03d533ac,
+	0x7be177d8, 0xcf7c66be, 0x8427bb31, 0x32262647, 0x4620be5f, 0xaf995ee8,
+	0xdf1e4dfe, 0x05d4afaf, 0xed5c90d7, 0x08bc7012, 0xe869743d, 0x43d387a1,
+	0x87a269eb, 0x9cd3b6ea, 0x4aeb5a1e, 0xdbaa9e91, 0x85d1a704, 0x8719eaeb,
+	0xebeffcfb, 0x61ea97e6, 0x7b5a879f, 0x1d0107ea, 0x69655818, 0x7af09985,
+	0xb3ebe118, 0xca7c323f, 0x6fede2ba, 0x1facd1c3, 0x707d468d, 0xe61ee75c,
+	0xe94de08a, 0xd12f4977, 0x7c906c3e, 0x295e90ef, 0xcb823aea, 0x3be8ed7f,
+	0x1c5bb40e, 0x883defc7, 0xc1663bef, 0xf322b90e, 0x535f1c36, 0x1a67e78a,
+	0x64381d60, 0xa009eb02, 0x1f1f13dd, 0xf8c25f9c, 0xf84d3968, 0x9e1d61d1,
+	0xa7e72abf, 0x5ec8cf80, 0x7ee56a19, 0x1e7ac7ee, 0x5e9bfb3f, 0xef6e4b94,
+	0x2abf1ea6, 0x5c4fd0b9, 0xa9fea3a7, 0x5e8e8e58, 0xf7ea3aff, 0x055e5437,
+	0xfb287c11, 0x4813d0a9, 0x5fe62b4a, 0x577c5996, 0x6493f4d5, 0x4f1a8acd,
+	0x9fa36f79, 0x7f8017b9, 0xde63b137, 0x81ff2823, 0xf543fe7e, 0x198318de,
+	0x47f4a6f1, 0x3fb58cfa, 0x14331ef0, 0xd05c79f0, 0xa563b9bf, 0x7f617688,
+	0xf650b5f7, 0xacad0b8f, 0xbf7835f6, 0xac4a0130, 0x01f5cb27, 0x2f107d72,
+	0x75b94fb3, 0x946f3c02, 0x6e9effb8, 0x7a92e390, 0x3bcc48e7, 0x3db81ba5,
+	0x923e9c58, 0xb7c2bee4, 0x2484be88, 0x58021b32, 0xe964f566, 0x3e14df70,
+	0x42e8f7d6, 0x594a5076, 0x0dce977a, 0x61f98fcf, 0x9ff037dd, 0xbd108fa6,
+	0xd1d1ecb1, 0xfcbf5d06, 0x5276b898, 0x6c3b1f57, 0xec9521b4, 0x42f78da3,
+	0xaf447abd, 0xc6b5fb84, 0x8ddb7d5a, 0xe169efce, 0x13ed763f, 0x577bfa07,
+	0x8f2c6afe, 0x5078f715, 0xff51dbc6, 0xb14f7a6c, 0x30ab68a3, 0x3ec0cfbe,
+	0xd70bf0e2, 0x7d92548d, 0x3c890774, 0x3e80c7dc, 0x55a7f509, 0x777e73a0,
+	0xebb3fa46, 0x8477e7c0, 0xb1b05696, 0xb72bf950, 0x3ff04c6f, 0xe98faff4,
+	0xed1e747d, 0x9a79e318, 0x3b6d6b42, 0xd33199d6, 0xf985c3bd, 0xa29e753e,
+	0x2ca1a130, 0x42489509, 0xc533cd26, 0x0e4f69a4, 0xb2fe51e8, 0xe71e4cec,
+	0x945f3062, 0x44f40e9f, 0x7c3658f9, 0x3395d924, 0x65dd2af2, 0x48bdfbf2,
+	0x731b7eac, 0xfae44426, 0xeefdd734, 0xd1dd9532, 0xfd3946e0, 0xe245dfd6,
+	0x7f1e2d6b, 0x7d7ce065, 0x9775efd4, 0x63c5f4e5, 0x67584ba9, 0xa7c5f577,
+	0xfc5a5f16, 0xc95fc3c6, 0x52597729, 0xf1693c0c, 0x46ff0c72, 0x06368f3c,
+	0x9de20203, 0x4b98e9e3, 0x78188160, 0x29d2ec52, 0xa4683176, 0x9dd90f76,
+	0x68f0c977, 0x4f17d6f1, 0xd2bb8a9e, 0x411ff022, 0x4e91e87c, 0x884aefdc,
+	0xdb0304ff, 0xdd0ceb81, 0x6ab7f949, 0x434c1fb9, 0xf93bb579, 0x8375e150,
+	0xf087707c, 0x386301bd, 0x6d55fd7d, 0xb83dde7f, 0x14a0dd72, 0xfb9803c4,
+	0xd4671f1c, 0xf1b8c374, 0x7da4cd61, 0xdba8fc07, 0x587e3993, 0xcbbf6f32,
+	0xd0d769a9, 0x0abd768d, 0x3e1bfcdd, 0x3f17d498, 0x30ecdd0a, 0x067276c8,
+	0x1e788c1b, 0x02426fbb, 0x78da2dc5, 0x4f4b5ede, 0xc37a4f13, 0x47f4c8e3,
+	0x5f3025f4, 0xfb33b9f8, 0x569bc86b, 0xf25166d0, 0x7be8b866, 0x51bc9623,
+	0x7976fff6, 0x81676e9f, 0x4b03a283, 0x74c25ffd, 0xff591993, 0xda275c21,
+	0x20d883e7, 0x8318e75c, 0x7969cb8b, 0xcb75e19d, 0xe58a09e7, 0xb64d8bf9,
+	0x7acb8e10, 0xf8c297f4, 0x5cf8a2cf, 0xc08a4a40, 0xb3fb9061, 0xdb8cb521,
+	0x79d20f5d, 0xbb0bc01c, 0xf1c08d6e, 0xa7a08307, 0xc70c9578, 0x80a69de5,
+	0x57ac2b78, 0xf511fdf4, 0xf8e125d6, 0x3e9f5a58, 0x4a7a8b94, 0xdadbdedb,
+	0xd0ed8d51, 0x93f5116f, 0x71865fe1, 0x9ea7a007, 0x6dc18d37, 0x8a48e231,
+	0x4a6c093d, 0x83e15cf2, 0x6505513b, 0x92dfa5f7, 0x1c7af1d6, 0xa5b74b5f,
+	0x1da159e0, 0xbbd7a5aa, 0x7c1ccf58, 0x4553a5ae, 0x7a597eaf, 0x30a9ec50,
+	0x74d4845d, 0xd003d0a1, 0xfa42ffc7, 0xf1f09ee8, 0x9efe68f3, 0x169bd098,
+	0xbd810f4b, 0xeca293a7, 0xb3f678e8, 0x48273762, 0xc7da333e, 0x595d797a,
+	0x9e1d2e79, 0xf25dba8f, 0x62b9f058, 0x0fccdc4f, 0x80e01d60, 0x91cc7d02,
+	0x83a4ddf1, 0xc0dbe006, 0xf288214a, 0x63d621e6, 0xaa1ef9c0, 0xc9fca835,
+	0x8f9ee639, 0xe6fd087e, 0x3d270dd4, 0xbf28c3e4, 0x38f3ef48, 0xffcf3d44,
+	0x5c9ebcb3, 0xaee6bff4, 0xd1fc6836, 0x39e3a224, 0x23ecfe4e, 0x09303be8,
+	0x4d4aedc7, 0x76f94d1a, 0xfced7f55, 0xe3b43aca, 0x91abdf6a, 0xee78b2e3,
+	0xf7851dca, 0x83b71251, 0x131ef0c2, 0x6f80bc39, 0x6aebac1d, 0xd3e088db,
+	0x2954e831, 0x8e5d267d, 0xef52393e, 0x3b38d37a, 0x955f6318, 0x3f7c1479,
+	0x7c153ac8, 0x0e8b1e7e, 0xffdc7d8b, 0x910e6dd6, 0x2f1dacbd, 0xec8ca7a7,
+	0x81269cb0, 0x4de5deec, 0x2af9ba25, 0xa3fb9bfb, 0xa6efec7d, 0xf2de3483,
+	0xfedc8396, 0x3b23aa6e, 0xf70b797e, 0xa43ec047, 0xc80463f3, 0x15cbb268,
+	0x7983d33f, 0xb79815a2, 0xbd21ede4, 0xf3d5cf0b, 0x78d235fe, 0xf21ca9f1,
+	0xc0ff7913, 0xa7e8b5c4, 0xa85afd86, 0xbab5fb47, 0x9576c2ba, 0x6c281b5f,
+	0x5b5f91bf, 0x05385f53, 0x8fe05afd, 0xcdc15245, 0xe4b663f9, 0x797fa1ba,
+	0x41ade4c4, 0x02e2533e, 0x6abffdda, 0xfd202572, 0xbdfb253d, 0x23cf57d3,
+	0xfc3cde7b, 0xa37990da, 0x7df2de51, 0x76e24c7f, 0x7be88a4b, 0x3eebc70c,
+	0xcf172d74, 0x7fb4d4cb, 0xbcf911ba, 0x1ec3ce4d, 0x5d9157f7, 0x13dfeca3,
+	0xa777b712, 0xa077688f, 0xc14f7ffd, 0xcfe81cef, 0xbcf3d65c, 0x4922a5cf,
+	0x18f66f65, 0xd7027aee, 0x1e8094ad, 0xf16ee511, 0x82938e84, 0x8ffcbe23,
+	0x808f77c8, 0x7b5d9df2, 0x5bd70d3b, 0x81d872d3, 0x7e84bef8, 0x5bc9c610,
+	0x8f30d3da, 0x77f9a2b8, 0x9e7bf40e, 0x7b5db897, 0x40e9df59, 0x1ef96ebf,
+	0x5fc9dbb0, 0x003da50a, 0x32d4ba78, 0x3e69f0bf, 0xbf5a298d, 0x85f57fe1,
+	0x76edbb11, 0xeb282053, 0x284e253b, 0xefa1875c, 0x663d116c, 0xedfb5f47,
+	0x4dacd1f2, 0xcc0fb815, 0x0f861ee0, 0xec83acf5, 0x09962539, 0x21cf0a92,
+	0xbf2b901d, 0xefbde96e, 0xe7162236, 0xda0251ba, 0x0c14be3d, 0x8db69592,
+	0x9188375b, 0x73d950be, 0x12ef7b5a, 0x1b77dd73, 0x7aa3b9ca, 0xd6b37686,
+	0xfdd163fe, 0x9f7fe387, 0xd6bcbc25, 0xfdc56d92, 0x59d320da, 0x54ef4b4d,
+	0x166a97e4, 0x6f7e0efa, 0x3a22dd55, 0x7246ec43, 0xf85bdd77, 0x9b7753fd,
+	0xd8f485c1, 0x34d876dd, 0x22adeb16, 0x4e6a99c5, 0x3a428f14, 0x2866d2ba,
+	0xbcd7bc47, 0xf903b1f9, 0x57cfd15b, 0xde7a44da, 0x9e9676dd, 0x695ee32b,
+	0x7a851e4d, 0xfdc759a5, 0x9f238ebc, 0x7fdf915b, 0x326aed7d, 0x7eb297f9,
+	0xaaa7618d, 0xddad4eec, 0x6e19e53a, 0xb5494e47, 0xec579c93, 0xf8fa3ecb,
+	0x67675b14, 0x6b1f425f, 0x4919f0f4, 0x616ef3b6, 0xd8af31e3, 0x19792d7a,
+	0x9b7765f2, 0xe286b9d5, 0xe88edc1e, 0xb9f4f8ee, 0xb8fcf819, 0xee9c7148,
+	0xf1d1226b, 0x86cb03a1, 0xf1a2d976, 0xf5fb4f5c, 0x5f3fc0d9, 0x3ffd0fd9,
+	0x07716c3b, 0xf77a7d70, 0xd63daf28, 0x78e504be, 0x97432841, 0x4320658e,
+	0xec35f457, 0xe27d93c4, 0x7f91d7f7, 0xa67a9857, 0xddcd18a2, 0xfe425a7a,
+	0x057920df, 0x2687e923, 0x8075f22b, 0x73c20e95, 0x561655cc, 0x53d4f48a,
+	0xa0db9cc7, 0x9d51cf75, 0x30fb04ce, 0x1ba64761, 0xf955edb7, 0xa692f35c,
+	0x4a332906, 0xbf912c5e, 0x0860bb3b, 0x7a8a490c, 0xcb91a4fe, 0x97870bab,
+	0xeef248be, 0x161b237d, 0x362dbf43, 0x5bb57d72, 0x85d8cc0a, 0xe8e8cefd,
+	0x238ec1fb, 0xf3c11c6f, 0xba4e4b10, 0x28bea1c6, 0x6ffa7231, 0x3d6afe3d,
+	0x3d690b9e, 0x76f478c5, 0x83a8a57b, 0x1733f779, 0xabbd3f8f, 0x1c23ff23,
+	0x649e63b7, 0x461de75c, 0x1ff6672e, 0xc74795d5, 0xe7cbf605, 0x1a356e1c,
+	0x4661fc68, 0x8ed7ca91, 0x23cf2696, 0x19e5f3be, 0x75ceef91, 0x915c3bd5,
+	0xef629578, 0xb5f77a4c, 0xcfe06319, 0x4e749749, 0xbbd76edc, 0xaf5c44db,
+	0x896302eb, 0x07fb5f42, 0xf88f1bc6, 0x7fdbc657, 0x70078f89, 0x54be421c,
+	0xf41a0ff0, 0xbea1a347, 0x849f53bf, 0xf82813df, 0xcca1d657, 0x9e626aef,
+	0x8eb11b46, 0xc41bb5e7, 0x8f52314d, 0x54ef91f4, 0x7449cef8, 0x29e486f9,
+	0x1810f4e5, 0x870bf582, 0xec57642d, 0x4b11f596, 0xf88a1caf, 0xbe69f653,
+	0x0513eb91, 0xcff3789e, 0xca54e191, 0xafd74b2f, 0xa2015c1a, 0xc5023d9b,
+	0x90815c19, 0xfb053b29, 0xe739d365, 0x37d8de48, 0xbd87f707, 0xd6ffa6ab,
+	0x8ace9d2e, 0x214df1f2, 0xfde0d291, 0x74c34fb4, 0xfa226fa6, 0x88c93d6b,
+	0x7cee978f, 0x58cdc798, 0x728e9068, 0xc84181c8, 0x9c3fc8b7, 0x0503437f,
+	0x35b52728, 0xf8441dae, 0xaf90390d, 0xbe027822, 0x41b6b2c1, 0xb25d7a42,
+	0xe58b978a, 0x6c9647ef, 0x2e7f11f1, 0x15395ada, 0x98d5a7ed, 0x28bd40f4,
+	0x59d32bd3, 0x4ebcf032, 0x85df6caf, 0xdd3897e1, 0xd4d96c5e, 0x7d02f38e,
+	0x63e233fd, 0xcfb3eb72, 0xbd0ab823, 0xa06edc5e, 0xde90aa71, 0xad74f8a3,
+	0xde7bafbc, 0x693ef4e5, 0x7bf4a1bb, 0x0149eeb0, 0xec38c4e6, 0x443bedfe,
+	0x91fbdf94, 0x9f39339e, 0x70be9ea3, 0x63eb69f8, 0xeb4ecfa8, 0x777bc618,
+	0x39aaac4b, 0x1a3a2f8a, 0xeff1575f, 0x33759dd2, 0x95dcae28, 0xa66ba024,
+	0xf782adf0, 0x1a7b92dd, 0x34b7fff1, 0xdfc65ffc, 0x81ff87df, 0xfe649b7e,
+	0xfc0e54df, 0xb7128f0f, 0xce380a27, 0x79f6296e, 0xfd8d57a1, 0x5710b73b,
+	0x23ef1eae, 0x72355f57, 0x0d91dbff, 0x73df57f3, 0x30effc95, 0x6cdd327c,
+	0x26e8532a, 0x7b71f053, 0xf8839753, 0x3d22bc02, 0xf289bd93, 0xb82b24b6,
+	0x8f45884d, 0x967c946b, 0x72236f8a, 0x5f5fe14d, 0x5853c21b, 0xed16bb56,
+	0x008ae4e4, 0xc145e9d1, 0xf4093437, 0xe7e445da, 0x67e17218, 0x333e5e32,
+	0x1be754f8, 0x32c1c2fb, 0xc0abae90, 0x69f3a2e3, 0xee27055b, 0xdaeed28f,
+	0xf782fdca, 0x9e573e65, 0xf915ffbf, 0x53f78c3e, 0xeface27d, 0x933eb91b,
+	0xdcceb04c, 0x4c67d720, 0x60be2528, 0xc819e9ba, 0x8f404b6f, 0x8f4a2f7d,
+	0x1034345d, 0x38782abd, 0x67fbd32b, 0xcfdd7c89, 0xc41e70c9, 0x5be12998,
+	0x7a0947ce, 0x5af9c0bd, 0x8bbf3814, 0xc3c5fe38, 0xdd11a793, 0xee9b13df,
+	0x246aed97, 0x772c4cfa, 0xb3b9438e, 0x2736ef49, 0x8f258e8e, 0xec765483,
+	0x49f909f8, 0xf7c8c748, 0x0aa0f8f1, 0xa0c580f9, 0x7fd020ff, 0x7429fed4,
+	0x1d717400, 0xd73ca5f1, 0x379285d2, 0x5bb2f053, 0x669b7793, 0x601a78e2,
+	0x25def2e2, 0xfa78a9cb, 0xf3ef2be5, 0x2bf87dbb, 0xe6a054cd, 0x456fdc2f,
+	0x13717c4e, 0xe2679b3e, 0xfa644fed, 0x780ede4e, 0xe4a0627a, 0xeb720b5a,
+	0xe766d809, 0xa63e48f8, 0x595f9e49, 0xa09348c7, 0xf368dbca, 0x6f830629,
+	0x9f0a2984, 0x8d73f798, 0x334bd08e, 0xd81cfce3, 0x43cf946e, 0x5f765538,
+	0xc6912981, 0x40c1ea77, 0x967fd405, 0x0361d959, 0x0ceeeeb8, 0xe1718c54,
+	0x5981db77, 0xbae264f7, 0x853e829c, 0x53ace5d6, 0xdf20ce8e, 0x7c50b71d,
+	0x3ddb3f24, 0x974cfc8a, 0xf7c71f3b, 0xeca4fbc8, 0x6b75bc67, 0xfdbc5cf5,
+	0x21e3279c, 0xcad76e55, 0x2e26418f, 0xf9657a37, 0xf83fe5a1, 0x526f9317,
+	0x3b242fb7, 0x6d8c9d90, 0x326fde07, 0xff5179f0, 0x00d4bf40, 0x23ddfeff,
+	0xdcec27ef, 0xc343c41c, 0xa39d2376, 0x31d7f850, 0xf18e9bcb, 0xe48a4713,
+	0xaeb8c176, 0x7e1a6c59, 0xe8f2efbf, 0xd651bfc8, 0x26e1ff5f, 0x7ea26fba,
+	0x7da19187, 0x57ef209f, 0x0c162cc2, 0xbaf9f109, 0xb1e80763, 0xd3fe2894,
+	0xee89eb07, 0x5103bf80, 0xd93437fc, 0x2d806e97, 0xdbfac1fe, 0xc0b74cca,
+	0x8ccc993c, 0xa82aea16, 0x347c006f, 0x96047924, 0xb675f548, 0x0fe3f181,
+	0x2e4d303f, 0xbf04f3c3, 0x6fbe7a32, 0xc438a54a, 0x1c2cb00f, 0x28b22b50,
+	0x1d99bdbe, 0xb1f955f3, 0xb0738e46, 0x69469036, 0x9ce2f8aa, 0x2f8a2e9d,
+	0x507c8d3e, 0x79fe719d, 0x8da6ae1c, 0x078beb9f, 0x678c8a47, 0x17c4e790,
+	0x115ade29, 0xcf857ffd, 0xc925379e, 0x3011ebfb, 0x1dd0aefe, 0x93da29f2,
+	0xe31d7e4a, 0x2f8a762e, 0xb0ee8907, 0xc23e309e, 0x742a1b7f, 0x61e2b1e5,
+	0xafb64cbb, 0xf23487a7, 0xb17db589, 0x4bd031f7, 0x48b7f835, 0x29976af2,
+	0x54d81eca, 0xc78d2671, 0x439d19cd, 0xe39e447e, 0xffee35c5, 0xe1f28e18,
+	0x947efcb7, 0x80294671, 0xfdc0aae7, 0xe4d33975, 0xda9d90f1, 0xfc1d9084,
+	0xd1cf9add, 0xf37f0173, 0x2f951d73, 0x3cb7b3fe, 0x56d9ed13, 0x032c1b9d,
+	0x5c93ebcc, 0x41650f70, 0x9373d013, 0x2a9b9f85, 0x9079b769, 0x1305bbfe,
+	0x13e99b9d, 0x19ea2f8f, 0xd7da0bb2, 0x411f01b6, 0xb184bbb5, 0xef57844e,
+	0x0ad0f3a6, 0xd89ec77e, 0x63df4794, 0x37dc1be9, 0xcbc55b8a, 0xb6af16df,
+	0x894adc50, 0xf4f71593, 0xb5649d10, 0x61f8ea65, 0x5e8f3e29, 0xd792af5e,
+	0xbef1926d, 0x226be8fb, 0xb2c2b1ea, 0xef68b586, 0xef7d1867, 0x2e4ddd23,
+	0x1339db56, 0x3b76da84, 0x4634d7d2, 0x1fc2827e, 0x20ec5dc9, 0x4f12a986,
+	0xcfd07976, 0x73c17c9a, 0x04a9fd10, 0x77f8132f, 0x24f3e192, 0x58ff70e7,
+	0x07b8478a, 0x13fc29c6, 0xe328bc23, 0x2a5a3eec, 0xd2919da0, 0x46b82659,
+	0x2defa5f7, 0xe04e77e8, 0x5f701ee7, 0xe8687f15, 0x6196462f, 0x2fe9487c,
+	0xbd5cb99a, 0x429be7cd, 0xafa34fa1, 0x349de717, 0xa98ed83b, 0x81558997,
+	0x84f10c76, 0xd184b3d7, 0x02ba8378, 0x27818eb4, 0x9658257d, 0xf7048948,
+	0x3a210be4, 0x96a0312f, 0x5b9231d1, 0xfb25df3a, 0x4eda96e1, 0xf771f701,
+	0xef0443d1, 0x5e0ecee0, 0x9af57cca, 0xb814ffac, 0xa27f644a, 0xd5c38e44,
+	0x8e9f9e5f, 0xecd181fe, 0xa338c12b, 0x12fa8eb2, 0xbf9e3a5f, 0x3ce782dc,
+	0xe73fc426, 0x14966691, 0x8cc1373f, 0xaeecee7e, 0x5a7b4823, 0xf8ed39bf,
+	0xb48fda19, 0xdd1ddcd5, 0x80a57c72, 0xc1e5b5f4, 0x22b37ed8, 0x71c8b62f,
+	0x14f3a8c4, 0x7ad1cd83, 0x9ac932b9, 0xc28f2515, 0x9e722672, 0x9e7cb762,
+	0x6f7aa6c2, 0xa46613cc, 0x27834ea7, 0xdf2b9f07, 0xdf2abce1, 0x71f8a01b,
+	0x961ebe0a, 0x9e68d3f7, 0x1086e749, 0xe3a04e4f, 0xbfb1cd57, 0xd6685987,
+	0xd3977ac9, 0xf4e4eb0b, 0xb688eb82, 0xb999a633, 0xe3cdbd5e, 0x74e7a29b,
+	0x9c788452, 0x476c1454, 0x1e589dba, 0xbffa4768, 0x5274c985, 0x4b44e9ce,
+	0x939bf7ef, 0xa1e93a64, 0xe0260a7b, 0xe43145f7, 0xdb998563, 0xa59d2977,
+	0x0fc03f44, 0x857ce177, 0x03456a83, 0x339cd0a5, 0xf0f8ef50, 0x9e7822f2,
+	0x4769e45f, 0xbc7a737a, 0xa8db8e22, 0xc9ba7277, 0xb8c49ef4, 0xe4aa7d77,
+	0x38d02b5e, 0xe0c736df, 0xa7e416ab, 0x4a7e11d1, 0x5a47e391, 0xc3229cba,
+	0x1cf193e5, 0x43df1e7f, 0xa74a4f38, 0x33f783ce, 0x4c25b9e0, 0x055c4e46,
+	0x96f912fa, 0xd2f9d275, 0x09672aa4, 0xe5a0ddf2, 0xf9f7016e, 0x016fbd25,
+	0x3c76b3ee, 0x350c9f45, 0xbffe8879, 0x6268deb2, 0xf2ff8d26, 0xb5db99b0,
+	0x7e512b1b, 0x8499f2bf, 0xf0a5d5f2, 0xd6f1d1e5, 0xf3745179, 0xf83a5f74,
+	0xa07458a7, 0x3a5a7f95, 0xb50bc888, 0xadbc03fc, 0xedc3fbe5, 0x55ce94dc,
+	0x6a1b9722, 0x7f6f1779, 0x0d0dc8fa, 0x3de98f1e, 0x097ae0cf, 0xf39105e9,
+	0x74f4f1db, 0xae1ff9a3, 0x31cd1ba7, 0xd4ceb4f4, 0x9f3c1bf3, 0x744da2bb,
+	0x5f225c61, 0xf6ba8f3e, 0x4f3a24f1, 0xe09362f0, 0xd1439746, 0x502244d3,
+	0x6127b2bf, 0x4a15bb2c, 0x6ae78078, 0xb2250302, 0x08c759cf, 0x24d633ca,
+	0x1bac70ca, 0xdbb7fa41, 0x51e600a9, 0x256063eb, 0x91d3fa01, 0x684b181d,
+	0xf310783a, 0x988b6b2c, 0xb77000cf, 0x80f3f1b7, 0x485bd62f, 0x7e3eef9f,
+	0x400f37f5, 0x1d71e73d, 0x0e047f1d, 0x4ab673a6, 0x03b145de, 0xe8590e3a,
+	0xb32f703c, 0x7754d1b8, 0xf8790d8b, 0x21fbec02, 0xe8d983c4, 0xe2281fcb,
+	0x77aec439, 0xf1eca38a, 0xccbfd6de, 0xe48ae439, 0x7d0e9a97, 0xdf6d185e,
+	0x14a9f929, 0x3996f7d1, 0x963fdfca, 0x77cb9677, 0x055fb9cd, 0x9c5e309e,
+	0x5da27f1c, 0x2375f04f, 0x48bf687c, 0x10fb861e, 0xe3d648f8, 0xfb94de32,
+	0x0adbba0f, 0xbe80fa4e, 0x98393c5e, 0x7b5be1c7, 0xef7768cd, 0x214ef932,
+	0xf4b7899d, 0xf6a9f9d0, 0xe811deb6, 0xf9fc834f, 0x1ef79f08, 0x9d149b3f,
+	0xeb12feff, 0x3f5a24fb, 0x729f5bc4, 0x1f4b5e3e, 0xda167dda, 0x184dfe0e,
+	0x50c07c4b, 0xb086054e, 0xf567fa20, 0x17adc663, 0x31672371, 0x341dc517,
+	0x999fb479, 0x8e65ffbc, 0x4c679fe2, 0xde21bfde, 0x4efc1e71, 0x05f9d603,
+	0x989ec7d6, 0xdb478f9f, 0xf53ac2be, 0x18fb9896, 0x215afda2, 0xe60567af,
+	0x537cf0fd, 0x3852e18b, 0xef231ddf, 0x8091fb07, 0xdd4a05e3, 0x9fb87d27,
+	0x6bdcd81f, 0x4efa1f11, 0x0091da27, 0xb3b6227f, 0x97ba4aa2, 0x50f060c7,
+	0x3ad5f47e, 0x5bbd7e7e, 0x1e31b8b0, 0x6491dcd6, 0x33f87941, 0xfb1d2f93,
+	0x9d5dd48f, 0x09fa7183, 0x3cdd5e9d, 0x41be53d2, 0xe753b216, 0x8e09eaf7,
+	0xdfda315a, 0xcfeb12fe, 0xe7dcc4b1, 0xc790fb3e, 0xa1f7c5d7, 0xf462e7df,
+	0x3e9c7bfc, 0x45d651f9, 0xfb83f6f1, 0x3cc5c93e, 0x4f81f552, 0x7ead3fc8,
+	0x5b9b48c3, 0x0488c6f6, 0x252be3a4, 0x4b89edb1, 0x1eb75afe, 0x967199ec,
+	0xcb9b922c, 0x23dd2759, 0x61e9a2b0, 0x5e4a3eb7, 0x71d3f62a, 0x8e056743,
+	0x6440bc7f, 0xbd774075, 0x580389ee, 0x94ac390c, 0x097b45bf, 0xfd1f7f60,
+	0x9f9bd4d2, 0x9de6d283, 0x338fb4fb, 0x42a11c53, 0xb3cc8763, 0x88f73d70,
+	0x8fbc325c, 0xbcbce005, 0xe0e74ed7, 0xcf7f8f2e, 0x5c4b1f81, 0x7e5df96e,
+	0xb0ffcf00, 0xbf3047ce, 0x8d8bf816, 0x718aa8fc, 0xd9d7e5ef, 0x3b76fc23,
+	0xdbb0418f, 0x70e13f5f, 0xe68aff41, 0x144094f6, 0xa1e7b4fe, 0xc7d7911e,
+	0x6e745df4, 0x98bfed84, 0x563ef786, 0x829c3bec, 0xec37fdeb, 0xaedfc318,
+	0xf44d5d58, 0x9f22d533, 0x1960caa3, 0x8bfa0f28, 0x0573ed07, 0x5dc7c70f,
+	0xf77a821c, 0xd23b1c4a, 0x75ebf72f, 0xf6801a4f, 0xca14854d, 0x55bf1589,
+	0xbc2d2bfc, 0x3b373b37, 0x58f7e243, 0xb6af9f6a, 0xebdf3d70, 0xf000b336,
+	0x068d23e9, 0xc4eeaefa, 0xcacc3fb5, 0x64f8fd87, 0x06b9c1ab, 0x85eaadf8,
+	0x309bc1f6, 0x48ce395e, 0x5c4f97f1, 0xcba41ca1, 0xf3f02fc5, 0x7d6c9fb8,
+	0xc8f30d24, 0xb5f409ff, 0xdc58e01c, 0x55e7a068, 0xe7a7df8d, 0x5bba6517,
+	0xe52a42fc, 0x3c744f97, 0xaceb869d, 0xdf93fbfa, 0x966ffe41, 0x41c6a39c,
+	0xa0977cb9, 0x74b7773a, 0x575559bb, 0xbacad2f2, 0x8f391099, 0x7e7802e7,
+	0xe79af969, 0x89f57780, 0xc2d2fe5b, 0xdd6f8bed, 0x2eaeeb07, 0xaefb25e8,
+	0x8c8588fd, 0x44db5fa8, 0x71a1dfd2, 0xadd6f5ff, 0x77f29f50, 0xd31f9bbd,
+	0xb239274d, 0xece5c4c8, 0x70fa7d94, 0xff719cbe, 0x615776dd, 0x08797cfc,
+	0xdbd200e4, 0xe18a9f94, 0x79f479bc, 0x5cde6d54, 0xf36b8fc9, 0x029c78e6,
+	0xf2cdf1e5, 0x1c3f0ae6, 0x49cf84b3, 0x1fb7dd12, 0x45f279e1, 0x2f6e45c7,
+	0xfc4e44dd, 0xe3d6e116, 0x107b1efe, 0x6427dde3, 0xf6b89c6c, 0xafbc3ac9,
+	0x012293e1, 0x93ec2033, 0x58f2c66b, 0x2287707c, 0x659cf02f, 0xef5f645e,
+	0xd7092f71, 0x5dbe0d91, 0x1ceab0f4, 0xd5e5ff68, 0x49f0f98d, 0x419eff0b,
+	0xfcb4cf2b, 0x67928ff2, 0x0f0ee315, 0x7ca9d809, 0xcd4bcb19, 0xe568ae5c,
+	0x14a7581b, 0xe4e55a87, 0xa5c0a2f4, 0x5fc57785, 0x3f3058b3, 0xf5177e1a,
+	0x94efa15b, 0xf8acbe50, 0x260b2e6b, 0x50fea37f, 0x3f8635b2, 0xf095fa04,
+	0x07d42815, 0xfd408fd1, 0xdb46fd8f, 0x0025c95c, 0x96673ad2, 0x2772e515,
+	0x416b7fe8, 0x6a313e24, 0xe50e8357, 0x376fd845, 0xc577fda8, 0x72b2c95f,
+	0x795a31ba, 0xddfc98fd, 0x5df3bc4f, 0x3c4af8ca, 0xf184bea4, 0xb91273ef,
+	0x839ca6fd, 0x3967eb5c, 0x933e3df8, 0xd26bc3bf, 0xc8f0eff1, 0xfcf5c4a7,
+	0x83fdc8d8, 0x5c5574bc, 0x29bf09f0, 0x792def07, 0xf7a4efd2, 0x53a7f29f,
+	0x8bbf23f9, 0x79fc67ca, 0x135efc39, 0xc7c8fe46, 0xd18d2c87, 0xe49b04e7,
+	0xb093cdbc, 0xd062d7de, 0xe55623e1, 0xf497a03c, 0xd8d2c2db, 0x567bfdf2,
+	0xe4a5e13d, 0xa087fbf9, 0xc1f1f1dd, 0x097dd1ef, 0x83e26b1f, 0x6e6f250b,
+	0x13f37d2c, 0xc9379f99, 0x32c7e5fa, 0xfd900d7f, 0x9e729047, 0x4f78d1e6,
+	0xff773f30, 0xc31dfcac, 0xa9abfd4f, 0xf3cad3bc, 0x8ff76923, 0xf0073b7f,
+	0x3f036e75, 0xa4ce749f, 0x6cf3bf23, 0x85bcadad, 0xfd8ef0e0, 0xde76511f,
+	0xf1dc329d, 0xfd6355d6, 0x057e726a, 0xdea072eb, 0x876fd30a, 0x5c3e1e3a,
+	0xfa432df4, 0x695d66eb, 0xe846afd8, 0x2315ddcc, 0x79209b8f, 0xff84ac6b,
+	0x5f28219e, 0xed02fd95, 0xfefa2a31, 0xe72b228c, 0x7ce38fcb, 0xa65ab6ff,
+	0xcf25dbdb, 0xfa9e3e6a, 0x195fc37e, 0xf2b43f3d, 0xb4ffe678, 0x8c02f9ca,
+	0xce4894df, 0xdb9d7c70, 0xd635dedb, 0x78997118, 0x8e16bf7e, 0x9e9c6c5b,
+	0xa500f1b4, 0xcf01e254, 0x65044da0, 0x7049d5a6, 0x1803e36b, 0x07158d27,
+	0x8f2b4ff8, 0x3c7ba61f, 0x9f15d5a2, 0xcef8272f, 0x6c9b7dd0, 0x7bf3a336,
+	0x0e9b8a03, 0x60643c62, 0xd90eb059, 0xcb513ea5, 0xc63301a7, 0xba7cb249,
+	0xa4dbcc34, 0xa33f0275, 0x6a9781bd, 0xd69d22a5, 0x4f5d21d6, 0xf168e9f0,
+	0x412c3a13, 0x54e67141, 0x660266e7, 0x0bfeef39, 0xda82f3c2, 0x1db718b5,
+	0x797fbcb4, 0x9f7936f7, 0x84d9bc95, 0xc3c206ed, 0xa63fed84, 0xed84d6fc,
+	0x2885eb77, 0x35693efe, 0x878bff50, 0xff250e97, 0xaa39ce38, 0x26dc794e,
+	0xfc417bc4, 0xadc710f3, 0x8879f8df, 0xb8a8d6e3, 0xab8af54a, 0x5a77c724,
+	0x39f8feb9, 0x9f0169e6, 0xe4a05f3f, 0xfe291b69, 0x9a6a5bb6, 0x40887986,
+	0x43ce8eb5, 0x0bdcf386, 0xf08f79f8, 0x86ef98fb, 0xe2af3fe7, 0xc181eef9,
+	0xf6df2967, 0x03e79999, 0x6461db3f, 0xf25d2798, 0xefe51376, 0xb1d72cb6,
+	0xc364f758, 0x9cf9064c, 0xefcf018e, 0x7ca3fee0, 0x081df653, 0x08fdc24b,
+	0xf9b5c3e7, 0x8bae193f, 0xe9723e72, 0x4869e6ce, 0x93cb1927, 0x563fbc04,
+	0xeaebeb81, 0xbf506f91, 0xe5f7975e, 0x6f55fa66, 0xb55fa18b, 0xe0d3b57a,
+	0x6f52da31, 0x641b5fae, 0x2ab5eafa, 0x78e406e7, 0x6247e637, 0xd633cbec,
+	0x34ce713e, 0x738857db, 0x3149adfa, 0xf7ca9ce3, 0x6c490d9e, 0xfc18ccee,
+	0x37cc98f0, 0x743dcdba, 0x4da5230e, 0x4a972988, 0x17c94924, 0xc545b08d,
+	0x35f2b5c7, 0xd8dd7e06, 0xd0aec47f, 0x3e35ec21, 0x668ac731, 0x9c73e000,
+	0xf2719f0a, 0x9533bf0c, 0xe4a27d90, 0xd49a2e15, 0x6c77dbf6, 0x6dcf3f4a,
+	0xc4b78fb8, 0x6c53db91, 0x297f0282, 0xc5594bf6, 0x2572f154, 0x1b529e4e,
+	0xaffbf010, 0x3f230f14, 0xafb26862, 0x7afd00ce, 0x36f73126, 0xe83c27a8,
+	0x9779412c, 0x883ee554, 0xcbfadda1, 0x0fcaf7f2, 0x395efa33, 0x65f5ef9c,
+	0x7883bd91, 0x4f0efe8f, 0xfaca0fd1, 0x6bdd6f40, 0xb2cd70e3, 0x7d6f40dd,
+	0xcf317c83, 0x58be3fd6, 0xf769708c, 0x81ef1b2d, 0x7fd98d4a, 0xb0feac45,
+	0xd9fdd5cf, 0xbc720de7, 0xa4f9bfbf, 0xf5f0bd46, 0xf17de5e2, 0xbc2c44f2,
+	0xe5d0a86c, 0x009479e1, 0xe963b8b3, 0x7fb62d9d, 0x8b7edc78, 0x9edc462d,
+	0xfebf24dd, 0x49773fe2, 0xe2560f18, 0x507b61cf, 0x9e575793, 0xf909b757,
+	0xb49597e8, 0xb7fb235f, 0x64e7e0fb, 0x8fcdf6ff, 0x025779f3, 0xdc7f2279,
+	0xbf6f9f25, 0xf7fb95ba, 0xa4fd7322, 0x39a8e018, 0x6841606a, 0x606f8abf,
+	0x882116fb, 0x3d5f0bf7, 0x8bea853a, 0x192c09f7, 0xe9e02409, 0x160cefc4,
+	0x425e3e30, 0x8f754e91, 0x7d47a275, 0x7972784f, 0xea9eaa92, 0x3e13df55,
+	0xaa967660, 0xa46fa07d, 0xd5507daa, 0x96fd5578, 0xe13df55a, 0x457f4143,
+	0xd30333d7, 0xd7b3fd55, 0x0faaabdf, 0x13df506b, 0xcbadf8ae, 0xdf0cf5e4,
+	0x2f7d4f32, 0x61084877, 0xbca163be, 0x38e40bdd, 0x52e088c5, 0xc4cb38d5,
+	0xbbf0470d, 0x57de9b8a, 0x7448dad4, 0x68afbdaa, 0x7d754ed9, 0x46fb89ec,
+	0x5e0cf3f1, 0xc675373a, 0xdc5f8ea6, 0xc3035f74, 0x1abed6bf, 0x6afbd5d3,
+	0x886e5976, 0x7a9e6b37, 0x6f7c999f, 0x766f168c, 0xbfff7ab7, 0xed19bc69,
+	0x0c193c6a, 0xe31d8b3e, 0x44abad80, 0x5cb2defa, 0x4bee4e7d, 0xed93ddc4,
+	0xcaeee231, 0xcf376abd, 0x0dffb4a7, 0xd04664f3, 0x173c0634, 0x8536e455,
+	0x48e627f3, 0xaf2b5d9c, 0x75e41294, 0x2af29d8e, 0x5ad3bc91, 0xff21df86,
+	0x2b708bde, 0xf7588979, 0x05ce6880, 0xbe71c68e, 0x4d0afdea, 0xd240e7f8,
+	0xae76f983, 0x51ec0b07, 0x8739507a, 0x78c1e8a2, 0x897928e3, 0x4870a578,
+	0x0f44b8a4, 0xc86257e6, 0xbfdb6ff1, 0x7be93ea6, 0xf6dbf38e, 0xe0bf2882,
+	0x5047bdfb, 0xefde039e, 0xedd9f5c5, 0x888527a0, 0xd589fc9e, 0xf3d3fc41,
+	0x3c38311b, 0x48be7233, 0xe1689fc9, 0x0f7cd62d, 0x87b9a6d9, 0xb73c7eb4,
+	0xb9dae63b, 0xdf2c3d5e, 0xd7235143, 0x7a76346b, 0x8fee7acd, 0x6d15bde2,
+	0x8d5ff651, 0xe7fd4edd, 0x106a4be8, 0xf70b46ee, 0x8105eaab, 0xa67d78f4,
+	0x6e3ef340, 0x71f6a52a, 0x5c6a92f6, 0xacb930f7, 0x2a5e58c1, 0xed443bdd,
+	0x5efb1892, 0x6e765582, 0x7896cf2f, 0xddfd2fff, 0x0ee60ad4, 0x9bbe44a5,
+	0xd3be7162, 0x3d83c6d7, 0x140ece79, 0x3bf55f8b, 0x9a1fc42a, 0x3f1d0ade,
+	0x43e70f63, 0xfaf9fbe8, 0x66e7aecc, 0x109ebee0, 0xdb1e78dd, 0x1d602a75,
+	0x57c7829b, 0xa02256f1, 0x8d6cad93, 0x038bea19, 0x18f78a2e, 0x8fb25fc0,
+	0xcbddf08f, 0xc7c24cf6, 0xd3219398, 0x789f6858, 0xe3107bca, 0x58b3b9c3,
+	0x06ed8a12, 0x7f0530d6, 0x55b0291f, 0x5ab31bce, 0x19abfdfa, 0xe8a52b25,
+	0x5ba94073, 0xe2f3a61f, 0xf87579ca, 0x28fc4167, 0x9e47dff7, 0x4338f3f3,
+	0xe32f654d, 0x98e5297e, 0xc578ec60, 0xccbbf96c, 0x5ddef587, 0x5a63dfb8,
+	0xbddee8ba, 0x5b1c8ac5, 0x9defa3a0, 0xe1f793ef, 0x0f3cadbe, 0xbf5daecc,
+	0xce46162e, 0x0cf8c1fd, 0x2cf173f9, 0xb3bbdd3b, 0xbe932db8, 0x815e668b,
+	0x6d351be2, 0xbf497b6f, 0x44e0984c, 0x01f3d37f, 0x4b7ef013, 0x039701c4,
+	0x952efbea, 0x95efd37b, 0xa77ca7d7, 0x8372f20a, 0x78bbf015, 0x81a1dd6b,
+	0x2f7bde30, 0xa18fba31, 0xf240acf0, 0x37168981, 0xcb85edda, 0x05cfba04,
+	0xbdd1f40f, 0x6d862314, 0x7e3b8e8b, 0xb78bcb2a, 0xe5a078fe, 0x9c297404,
+	0x2a48f952, 0xfda768ec, 0x5dfc54c2, 0x95fdc2a8, 0xa338648f, 0x7b2a9bea,
+	0xde11bb07, 0x80cb530b, 0xe760fe4e, 0x85d74cf0, 0xd9bbfcf4, 0x543fca4e,
+	0xd20f24d8, 0x9d2d8569, 0x80ae37ee, 0xf400bdad, 0xdfa3fd35, 0x9f2e51eb,
+	0x05f7cbb2, 0x5c5cb2e4, 0x77c3b267, 0x2accf89e, 0xaf10339f, 0x0fb68d8d,
+	0xe539f4a3, 0xacdbba47, 0xf9586994, 0x3fe53666, 0xfbb4f795, 0xdf9f9cfa,
+	0xf0ec9873, 0x57fdc79c, 0xfade81fa, 0x93ddeb1c, 0x1db97f3f, 0xfc52bdc6,
+	0x17082197, 0x677e8fe0, 0x4ebfb941, 0x296dc719, 0x3f2762b9, 0x3f717986,
+	0xf9e3936e, 0xbb6d9d93, 0xebb7dd71, 0x0e516b42, 0xa9fef9be, 0x28671c64,
+	0x3eb8e078, 0xf5d573f8, 0x4570bee4, 0xbf7abee4, 0xf9f0a70b, 0xef2bbf0b,
+	0x8bc79b9b, 0x500df7bb, 0x0eed8bc5, 0xbfb86fbe, 0xc0937fd4, 0xcfd9f1ef,
+	0x937c564b, 0x9055fef7, 0x05824f7f, 0xe577e844, 0xc00fde4d, 0x66a87f21,
+	0x13a270ff, 0xb3cb839f, 0x51e7acc9, 0xb6e4e75c, 0x87efa77f, 0xf2792b27,
+	0xb93cea0b, 0xe2a59f0f, 0xf43d23b5, 0xb5f7701d, 0x63796fde, 0x43a95bf0,
+	0xfbf0fbc9, 0x837ec3f0, 0xf87e1f7c, 0xec5342bc, 0x7197f0fb, 0x89f120ca,
+	0xc52f0fdf, 0xe12fe03a, 0xe907f9ef, 0xc166c1fc, 0xb04c798d, 0xcfef5483,
+	0x87ded3c8, 0xf17fefcf, 0xe3df93c9, 0xc91f33ee, 0x1e194adf, 0x5dff1b5f,
+	0xcf3c0e82, 0xdeea7803, 0x51377fc0, 0x777fcf7b, 0x05b7e739, 0x4ba085eb,
+	0x553bfba0, 0xd6650bed, 0x6776085e, 0x3cec9328, 0x3dc477cd, 0x5c5f6c5e,
+	0x041befcc, 0xded34fbb, 0x754fe0a0, 0xf961ec4f, 0xfe1671f7, 0xf237d658,
+	0x64f32fbd, 0x590f31f8, 0xaf591692, 0xf9147fa2, 0xe16050b9, 0x1abee9f7,
+	0xed463ef9, 0xbb95e7fa, 0x36f3cf09, 0x761c6e08, 0xd067aff1, 0x078053f7,
+	0x2f995e95, 0x837e73af, 0x6ff3e740, 0xb2a98f76, 0xeeb845ee, 0xaef6becc,
+	0x50587ef6, 0x5f842e6f, 0xc6b1f990, 0x49afe1c8, 0x885f7466, 0xba25ec90,
+	0x125dc780, 0xf83b0f94, 0x0de10b39, 0xe627c923, 0xf2937b05, 0xe44e6574,
+	0x85058143, 0xcffaa3eb, 0x30fbe1af, 0xf842e7c2, 0x12c98efb, 0xc74cdbf9,
+	0xca3b6dfd, 0xd223d01d, 0x4e10dac9, 0xf2b126b7, 0x67bc0731, 0x20f06aea,
+	0x342e58cb, 0x2cdcb085, 0x3e7bbbc7, 0xaffc1134, 0x846cbe0b, 0x2a18a27f,
+	0xe79af927, 0xee93341b, 0xcaf9e3af, 0x167f328d, 0xaefa06b1, 0xa26b3260,
+	0x527598b2, 0xa1eb0779, 0xac5f83d2, 0xe03da364, 0x798cb2a6, 0x6aca9ca9,
+	0x0d672ca9, 0x712b7e54, 0xc002625e, 0x51359d35, 0x39e402bd, 0x32890bdd,
+	0xf74de319, 0xeecec89a, 0xac1cd37e, 0x0e6af800, 0x38bcb918, 0x577d2560,
+	0x08466073, 0x1fddf9e3, 0x7bf85cd9, 0xa7b176a0, 0xbf48e29a, 0xf7f93ab6,
+	0xbdd52e34, 0x2bb935dc, 0x78e3f77b, 0x7c7f421f, 0xbaad9e90, 0xafe27ba7,
+	0x7a8f907f, 0xe1ade260, 0xe81cf27b, 0xcb6d5fcf, 0xcafe3f26, 0x9446dd40,
+	0x5219d5d3, 0x7ab7e23d, 0x95ee8598, 0x05d3cee9, 0x415b2824, 0xe9fde3fe,
+	0x05efe06f, 0xff26d940, 0xf901c05e, 0xde10f57e, 0xdab60eaf, 0x951e7f21,
+	0x95377e1d, 0x5445fc47, 0xa87bf51e, 0x397f31df, 0x5efdc795, 0x9d1eaf2a,
+	0x77c7df4f, 0x839e9fa7, 0xc87427bf, 0x19a4f951, 0xb28fe1f4, 0x44fc2e7c,
+	0xfdf4eb08, 0x45aec0c8, 0xd508fdf8, 0xd7d67f41, 0xd19dd2f9, 0x555352ed,
+	0x92ea1db8, 0x7008fdfc, 0x629e93d2, 0xea4527a8, 0x118dfdf8, 0xbc199ce3,
+	0x57f3065e, 0xfb5220bf, 0x303f7811, 0xc72bd618, 0x2e094ca3, 0x03461f2e,
+	0x74e18cbd, 0x7c65df83, 0xea99d5d8, 0x69762310, 0x4e5c13e5, 0xedc0be54,
+	0xec67cace, 0x9eeef7f2, 0xef0d2132, 0x89cb511d, 0xf94c45f9, 0xbded13fd,
+	0xea2c45a5, 0x83b9983e, 0xe60f2475, 0xd3f756ae, 0x4ce807ca, 0x95aad3bf,
+	0x643a1f0b, 0x8d9733fb, 0x97faefc1, 0x1d93b1cf, 0xa76ec976, 0x763f7a73,
+	0x0164a475, 0x44fbd5bc, 0x0ab413ca, 0xb5b07640, 0xeab8de7f, 0xced0136e,
+	0xd7a7159d, 0xbeb1b8a6, 0xaefc49fa, 0x4ff352e2, 0x233aa4a7, 0xf4ec59f5,
+	0xdda007c6, 0xddf56eb9, 0x2ffac0f7, 0xb8c0bd23, 0xfc0d5b97, 0x12939b1e,
+	0xded32efd, 0x0b21af4c, 0x763f7bea, 0xa6ff3c33, 0x99bbf5e0, 0xbddbfbfc,
+	0x2b41be99, 0xa7deab47, 0x1afd61df, 0x6bf133ef, 0x00dc2fbe, 0x8a7bed7e,
+	0x7efbdb5c, 0xa77f0dee, 0x6dead976, 0xcea27243, 0x37d32c15, 0x658279d1,
+	0x921e5fab, 0xa5cdf603, 0xe88d96e2, 0x7835ef77, 0xf942ef12, 0x71e06cd5,
+	0xec904366, 0x89af4f80, 0x02466f34, 0x0609fbd7, 0x7c249f6e, 0x3d446a68,
+	0x1382f603, 0x6bdcafbf, 0xa439f0e6, 0xc112572e, 0xc2c3ebc9, 0x86f1f1ef,
+	0xf7b97025, 0xb25eb5e9, 0xd76e7ba7, 0x8082efd3, 0xc4faa07c, 0x6884523b,
+	0x226f67bb, 0x8af3de7f, 0xcc52fd48, 0xf1e8c49e, 0x2f1debb5, 0xdcd7b7cf,
+	0xc53f1aa3, 0xd653dfc0, 0xe36f9da3, 0x9de51324, 0x496e289e, 0xb2ebfcc3,
+	0x207bfe12, 0x8abc3245, 0xa3f1357d, 0xe1a3dba9, 0xeeff289b, 0x26e4ceb0,
+	0x557079fa, 0x7dfa38e2, 0xe297a742, 0xe71e73fb, 0x38f269f5, 0xe08e4520,
+	0xdcb9e772, 0xf20cd153, 0x28657c39, 0x79e417b7, 0x8afd608f, 0xf510a7a1,
+	0x24aab886, 0x33de0030, 0x9f495e3c, 0xd5d719f7, 0x6f34b005, 0xe1036468,
+	0xcdcdc2f9, 0xa13df70c, 0x8a176cf9, 0xefe69499, 0xaf6d7c53, 0xd813a641,
+	0xfe51998f, 0xa96736d7, 0xd7e60137, 0x391db939, 0x4245ac7d, 0x467a607b,
+	0xf5f9d906, 0xcc1cc1a5, 0x308cf70f, 0x3a627c53, 0x9f80258c, 0xc5886c72,
+	0xd412fe83, 0xcf58893d, 0xa7fd4c98, 0x86591d8f, 0xc658f87a, 0xb78c74f7,
+	0x9e2bc7af, 0x5fc0658e, 0xc21fda0e, 0x8969cf57, 0x963eafbe, 0xf92a74b1,
+	0xbd382315, 0x6c78cb1f, 0xd22bf62a, 0xc2cbee05, 0xf289a176, 0x70278fae,
+	0x0c5d3f3d, 0x09efc71d, 0xcef819ef, 0x566ff471, 0xc77ec826, 0x622b9018,
+	0x5c981fc4, 0x9f8edcd4, 0xde7b15cb, 0xeaea829e, 0xb73ff28e, 0x26f1e963,
+	0x2f7aa196, 0x03ae3d9d, 0xccdf32cb, 0xe8731032, 0xf88e3caf, 0x70f55a9e,
+	0x01ffd607, 0x88e3cafe, 0x55c992e7, 0x9f37fbf4, 0xa3e5dfdd, 0x7024e93c,
+	0x7dc463d4, 0x4b09f622, 0x781af7e2, 0x485f5092, 0xdf7db86b, 0x7b244fb3,
+	0x39751582, 0xea6e5c74, 0x33aafe90, 0x9e90d2bb, 0x38f207eb, 0x976715cb,
+	0xfdf2ea83, 0xf322ff02, 0x57624541, 0xc561d21a, 0x9e0261be, 0xe1e2bd3b,
+	0x56a04a76, 0x3061e7e4, 0xff2694cb, 0xd51678ee, 0x93fceec9, 0xfcf5ebc0,
+	0xf3d676ee, 0x23ed237d, 0x2f10cf8c, 0xe30f0f3d, 0xeabe0170, 0xb92f5ef1,
+	0xb983c33f, 0x52abf748, 0x87f21ee9, 0xfc24a72c, 0xe3302469, 0xae3e50d2,
+	0xe276ca68, 0xef06cdf3, 0x15f71a4c, 0x96e389c1, 0x3c966cef, 0x2a4fd236,
+	0x90f41e3b, 0x7ba7eed6, 0x3e32e687, 0xd126dcdf, 0x9aba0663, 0x03fcd2db,
+	0xeecd2e81, 0x8ff7c832, 0x4d6bdea9, 0xfa9f74e0, 0x4fba66cb, 0x87ce1976,
+	0xee81ab65, 0xab365d95, 0xf1443245, 0x3dd6b2cb, 0x577cafd4, 0xcbc5e533,
+	0x2f64ecf3, 0xeb0d634f, 0xdf2d5f28, 0x53e3e457, 0xc9add3b0, 0x65003fcf,
+	0xbe399fc5, 0x3efc53d8, 0x0f83f9b5, 0xbb2f91d9, 0xfc53960a, 0x942143e7,
+	0xf8bd001a, 0x0ee76650, 0xc92e1ff4, 0x0fd68ef6, 0x0b1dfad1, 0xa2a7335c,
+	0xdfd7d149, 0x38e8b660, 0xb03f168a, 0xdef11b1d, 0xa24d45a3, 0xd131ef13,
+	0xfe0a23fa, 0x953f78b4, 0xc7db2290, 0x3f706320, 0x20eca69b, 0xfa71933f,
+	0xd6017b20, 0x987dc971, 0xd39ab3ee, 0x6279efc4, 0x8a14a13d, 0xb3f06b03,
+	0x8cda1f41, 0xd60549f7, 0x02fee819, 0x5c02fe1f, 0x8dfdac52, 0xec4a27ba,
+	0xeb2d3f5b, 0x5bcf3ecb, 0x7a775fb9, 0x1b9f28bd, 0xdbcfb751, 0xb3247f97,
+	0x26fbe31f, 0xeed27df0, 0xcfd002c7, 0xdf8217e4, 0xafa97287, 0xdfa5e85f,
+	0xfed9b883, 0xdffff828, 0xc7a90a29, 0x00008000, 0x00088b1f, 0x00000000,
+	0x7dedff00, 0xc554780b, 0x3d9cf0d9, 0xcd8dcd7b, 0x09c246fd, 0xb8094404,
+	0x9fb1dc24, 0x4a34021b, 0x414045d0, 0x2dc8d812, 0x088d9242, 0x59b6b696,
+	0x5a4062e4, 0x7da5aac1, 0x2c142ea8, 0x11a0d05a, 0x86ec5d43, 0xba8b4508,
+	0x8ad45cb1, 0x14178026, 0xb16d0042, 0xfbdfad1f, 0xbb2733be, 0x6a2364e7,
+	0xffefefd5, 0x27a3cbff, 0x9cccce73, 0x997ef799, 0x6318c399, 0xb17fc39f,
+	0x50dff876, 0x261d8ac6, 0xd8c21b27, 0x4fab569c, 0x8a6c61c9, 0xef74676b,
+	0xa79cc624, 0x18564c0d, 0xedfd2e6b, 0xd543262f, 0x8ad79b24, 0xcb7693f7,
+	0xcd942f0e, 0x3b58eef1, 0xdaf4b7b4, 0xd5f6c468, 0x512c490f, 0x6724ac62,
+	0x618b126f, 0x9b0e576c, 0x7783cae5, 0xd0daefe1, 0x950ed135, 0x6cdb1992,
+	0xfb622577, 0x1b32dee7, 0x1ec60f58, 0x87f5e78c, 0xe3db99bd, 0xfd5098b6,
+	0x687f5841, 0xd5b23ca8, 0x467f58c0, 0xe8c79c3f, 0xb318a30f, 0xebdfca86,
+	0xaf94d048, 0xa9a198bd, 0x68fac85f, 0x0759179e, 0xb38f9e68, 0xdfca6817,
+	0xa9ad1b4f, 0xa4529d7f, 0x3fe84f29, 0xa27f5341, 0xbca6b263, 0xeb8ac8d6,
+	0x63675e61, 0x8f4b5e8c, 0xd8463cd0, 0xb787040d, 0x478702d3, 0x683b584b,
+	0x8576c572, 0xa98d5957, 0x7dec35a3, 0x9c38da0f, 0x819c5d58, 0x4eec630d,
+	0xffa899f5, 0x58df0143, 0x7be0d599, 0xdd46a303, 0xb5bc046f, 0x160d941f,
+	0x42f32fc0, 0xcec614bb, 0x1a17768b, 0xbe207a0b, 0x7f7e01d8, 0xdfdf8d91,
+	0xded1f025, 0xc335e0df, 0x816b5bb8, 0xde85fa26, 0x660c56e3, 0xdd7e1843,
+	0x8259b28d, 0x730370f2, 0x17dd7be3, 0x1059cccd, 0x5163071a, 0xde76bdfc,
+	0xe64e3abf, 0x8defe68c, 0xaedff7e7, 0xec62e245, 0x5d2b5a9d, 0x82cf0e7f,
+	0xc0633e38, 0x691fa0cc, 0x34f8cc74, 0x06f6b7a0, 0xfa016ec9, 0x366c6cac,
+	0xed17f8e3, 0x316549cc, 0x5ea7e15d, 0x31a6d78f, 0x5aabfa05, 0xd52ab2dc,
+	0x1f6ef401, 0x682bf752, 0xe303555f, 0xb1a91200, 0x965bab0f, 0xbb62d8cb,
+	0x6716f442, 0x7f43f981, 0xbff4feef, 0xf0073ccf, 0xd4b3fe3b, 0xfd07e47c,
+	0xffb559f3, 0x17e8f4fc, 0x27f77f3c, 0x83f63f7f, 0xd3ff6a2f, 0x65fbdecf,
+	0xc6eef3d8, 0x932ebb3f, 0x30746129, 0xace1cccc, 0xe90cb7af, 0x3b3ffa0a,
+	0x358f1fea, 0xb2497f43, 0xe01d997b, 0x27cd7edc, 0xc51e0cd9, 0xcc34bf0e,
+	0x37e2131d, 0x095ffb7d, 0xb1bc037e, 0xfb338018, 0x15b7cd81, 0x0ddf06e9,
+	0x924b63e5, 0x5e906b7d, 0x669ac15d, 0x95b1f718, 0xe06b1c7d, 0x0ec7e53d,
+	0x86f7338e, 0x2f3cb1f2, 0x24cbfbc3, 0x2cfb8307, 0x3a446acd, 0x5703899d,
+	0x2b2ef868, 0xd31674e0, 0xf9d02dd2, 0x7c61adfb, 0xb6a96b33, 0x96d5ee5c,
+	0x61fce387, 0xd899cf1e, 0xbc30fab4, 0xeffcc4fb, 0x047c2f89, 0xce3b8be5,
+	0x5376e54e, 0xfac85dc7, 0xbfb4f58c, 0x81fa2d1f, 0x32008e39, 0xb7b2f1c5,
+	0x9fcf34ac, 0xf89183e1, 0xf2266f3f, 0x4f82dbe3, 0xd6c4c4cf, 0x6707c049,
+	0x6f070e14, 0xd2e1cc8d, 0xed056013, 0x6e2777ab, 0xdfc0b822, 0xb3ee5451,
+	0xa4c7cb19, 0xde17b240, 0xfb07265b, 0x28cffbe2, 0x1d630fad, 0x4668e2ef,
+	0x53b491ed, 0x10fa7c04, 0x30f3148c, 0xe7801f01, 0x69d946cc, 0xf1f0441b,
+	0x29a3e0ea, 0xa8d0fe8f, 0x43af7f29, 0xa2f6be5b, 0xb4c85cb6, 0xdaac8bed,
+	0x8e02cbf2, 0xfbdaece3, 0x96d34fdf, 0x1e3a55df, 0x1d8bf2e2, 0xf3c30dca,
+	0x259521cc, 0xcfe00e2c, 0x179c66ec, 0xb864f78c, 0xc11e2b1c, 0x3adb78e1,
+	0x21cbe7c9, 0x5f9e6afc, 0xecab1cc7, 0xdaf74879, 0x418bf0fb, 0xe82b9a7a,
+	0xed3aee67, 0x19dfebf3, 0xbc019e35, 0xe325d84e, 0x207f78fb, 0x4e78881b,
+	0x419f738c, 0xc744f03e, 0xc37d420d, 0x46b9ede4, 0xabd9ff78, 0xe3990e6c,
+	0x3b21cb81, 0x3938ff1f, 0xe7c011c6, 0x058768fe, 0xd3da2d6e, 0x8fe51527,
+	0x37cf5eda, 0x52dc800f, 0x9c7be1fa, 0x99af4867, 0x25d20559, 0x28fa021b,
+	0xe4c2c81d, 0xf6878f8c, 0xceb71dcf, 0x3be04772, 0xef955ce0, 0x77c8259c,
+	0x35f4e63f, 0x1ec8cda6, 0x352c71c7, 0x9c20b26d, 0x8fc427eb, 0xb999fa03,
+	0x5b9df38c, 0x3064ac0a, 0x647b99bf, 0x25cce782, 0x44498f92, 0xf435e72f,
+	0xbea0f022, 0x5e71f00f, 0x329a5fc7, 0xfdd12850, 0xecc62683, 0x678ebef0,
+	0x1466df25, 0x648d53d9, 0xbb6d542f, 0x337047c2, 0xef1117b2, 0x2a8f816e,
+	0xa81e2323, 0x0658fe04, 0x4bd4e7f5, 0x178fae34, 0xa8067c5b, 0x261db55f,
+	0xae3fcf08, 0x2824f931, 0x3328dc7f, 0xbeb10fce, 0x7db550be, 0x7c2f2f3b,
+	0xf82d96fc, 0xff3c5dbc, 0x2db8fb78, 0xa2b5bef8, 0x9062ef7f, 0x6ddf504b,
+	0x3e6b5664, 0x0259b75c, 0x63b7a076, 0x4757f651, 0xe8ed3d21, 0x3e0cf0f3,
+	0xc618c524, 0xab59c74f, 0x85d0e109, 0x9f03b69f, 0x2be575c5, 0xa0f1d237,
+	0x50b9f4ae, 0x839039aa, 0x9267e372, 0x95d2ab63, 0xa974f54e, 0xc17cedd2,
+	0xd9b3d01f, 0x1bca1035, 0x1d38f5f4, 0x1fd635ac, 0xb9e715b9, 0x3bfea642,
+	0xb71009e7, 0xdc2d4902, 0x28c8f7d1, 0xdabe5e78, 0x32efe884, 0x33f3aecf,
+	0x6ce6fcd1, 0x673274e7, 0xa453e4a9, 0xcfd5f3ae, 0x98bccbb3, 0xa63d956b,
+	0xcebafceb, 0x218fd383, 0xf1104876, 0xa2d1be75, 0x9dd1fda0, 0xab5d3b7e,
+	0xff411b64, 0x675adbb6, 0x238c0732, 0x2575bb7e, 0x907688c8, 0x179fa8c1,
+	0xec5ddfac, 0x2d39be05, 0x4a6f7971, 0xf95874e6, 0x5926ea74, 0x6953f50a,
+	0x4073f40e, 0x15e3bbbd, 0x81a56382, 0xc1fa09eb, 0x4e0f4e38, 0xc606bcd8,
+	0x856de601, 0x32679fa6, 0xe361c937, 0x8604b4ab, 0x3b41fa69, 0x7c9fbc26,
+	0x1c19cfde, 0x9fa85e4f, 0xf1da5daa, 0x9a839954, 0xfb0954f1, 0x0ce7ed48,
+	0x9fea078e, 0xf784f1c1, 0x3c769cf3, 0x66a09655, 0x769d553c, 0x9f27e895,
+	0xae55d3f7, 0x73f634f8, 0xb64e7d55, 0x2b4f0c31, 0xfb1631af, 0x0f4dd822,
+	0xbff973c4, 0x7ecd9b70, 0x557eac32, 0xeca6bc7d, 0x9fb74c69, 0x859fa30c,
+	0x3bc807f8, 0x032418b6, 0x314ad3c8, 0xfbb291c4, 0xa3d47881, 0x011faf49,
+	0x5b559a0b, 0xa748cc3b, 0xfcfa5d8c, 0x865861f3, 0xcf1c653f, 0x38450394,
+	0x1d93469f, 0xf00cfd59, 0x71e017bf, 0xf5f061c6, 0x7fddf986, 0x119b83e9,
+	0x4dbb313e, 0x7940f709, 0xab45e3ad, 0xdb5fe302, 0xe5f62a68, 0x67dddea1,
+	0x5f261d9d, 0xfdb93ad7, 0xeb019ccd, 0xfba181e4, 0x8f5f8331, 0x0cf17b43,
+	0x5e2316b3, 0xd6031ad7, 0x587061c1, 0x3eaa2a0b, 0xc5765c02, 0x5fd744cb,
+	0xb54b2e1b, 0x01e15170, 0xf085d9f0, 0x535b58f1, 0xffbb4ed0, 0x6871e39a,
+	0x360d15a7, 0x9ca7a44a, 0x9721e912, 0xabaff39f, 0x0d7f2644, 0x08525626,
+	0xf441bbf0, 0xfa0ad677, 0xdbf06ae9, 0xd885091c, 0xbc71c6ee, 0xd2f978dd,
+	0x9e50c9a1, 0xca993dfc, 0x4d99eeaf, 0xe2600d72, 0x27bc0008, 0xbf258d4f,
+	0x3863fa0e, 0x9fa8a9be, 0xe126d481, 0xa937682d, 0xe005f258, 0x308e377d,
+	0xf3e70f1d, 0x796d4e49, 0x0cb6b172, 0x335f91fd, 0xafbda5d5, 0xe28759da,
+	0x07de9363, 0xb1458c17, 0xfed1cf8c, 0x6632fa11, 0x1f6b5ef0, 0x11d9d718,
+	0xebcd0766, 0xeca9dfd2, 0xb6c0c6bd, 0xa7337b62, 0xb28d9ffb, 0x84e796fa,
+	0x443dfbd3, 0x030e4db7, 0x37fb6133, 0x9bd43e2c, 0xbb33db7f, 0x77a08b17,
+	0xd198ed43, 0x35e34690, 0xdcfeb832, 0xfd8c51d4, 0x067bfcff, 0x8ffa0cb6,
+	0xfb76651b, 0x27bfb422, 0x4231f85e, 0xef072dde, 0x2f2dfd0f, 0x256c728b,
+	0x3f2148bb, 0x58b7f54d, 0xab2a1f5a, 0x340c967e, 0x34fa4419, 0x9e3d1076,
+	0x81e9f7f7, 0xe68d8ce3, 0xa07f3c78, 0x2f6e1ed9, 0x047fa234, 0xd01fc676,
+	0xa36b823f, 0xb5fd7fb0, 0x00bf2a76, 0x035e0e7e, 0x4ff90ab5, 0xd3fb6b7b,
+	0x075ac5f5, 0x8ed7f75d, 0x5a81eba0, 0xb97bd527, 0x07ae98b6, 0x75745d6b,
+	0xf9f025c7, 0xec5db918, 0x920afe79, 0xdbafe073, 0x88e28612, 0x3e20066b,
+	0x793e3bcf, 0x0af0b7f2, 0xafd3a8cf, 0xacf5c116, 0x735771d4, 0x3ff9fc98,
+	0x3f074fcd, 0x7fc71728, 0xef5d7f39, 0xb73d542f, 0x70179763, 0x87a9e0b4,
+	0xfbcc18e2, 0x0a5d7194, 0xadcae1ca, 0x709ce32b, 0x0e3bb305, 0x9f29e1f5,
+	0x3e891c5c, 0xfa54134a, 0x2848c670, 0xabe718e7, 0xefb89e8f, 0xbfabe406,
+	0x51d9356d, 0x7ec0785f, 0xae7e80b1, 0xf89db86e, 0xbc6dca12, 0x1939ef7c,
+	0xfe5a8dcb, 0x87bbf059, 0xa2589452, 0xb74e4cbb, 0xdba44c81, 0x8def2dea,
+	0xb0f23a47, 0xfad3d20e, 0x8bfef876, 0xbd4f7a00, 0xbd7e8e5c, 0xffcab9fe,
+	0x9eae411e, 0xc9cefb86, 0xab57f871, 0xafaef119, 0x0e34815f, 0x41313c7c,
+	0x3670f1f0, 0x156ded1c, 0x4c97cc1e, 0xf73f2cfc, 0xa86d419b, 0x39fcb7bf,
+	0xcaebca4e, 0x67ebe7af, 0xa507fa3f, 0x176cfe7b, 0x6bd7af74, 0x200c234a,
+	0x7e7e8a15, 0xe20534ad, 0xb9fda346, 0xacf244c9, 0x1f6fc772, 0xd3da35fb,
+	0x7d1c5a6f, 0xf69bb415, 0xe505191d, 0x494d3b85, 0x311a7c25, 0x2f084a52,
+	0x696ff81e, 0x0b0f087e, 0x5667d99e, 0x77fbf206, 0xb1f08427, 0x99936770,
+	0x8f0aec0d, 0x7326faa2, 0xbc044c6b, 0x478db7d4, 0xfb9f96be, 0x7ef119a7,
+	0xa58905ea, 0xe78044e6, 0x6e717da6, 0xa3c22701, 0xde2753c0, 0x803df574,
+	0x1553a417, 0x57e7fa4f, 0xc67a7027, 0xa23c94fe, 0x00ff27e7, 0xcb78a9f0,
+	0x57f9c0e2, 0x1c67793c, 0x6303e3ce, 0xdfeba70d, 0xc2714cac, 0xde4c2b7b,
+	0xf95d3b14, 0x96478afd, 0x6fcdbd10, 0xc8c29259, 0x1ba670ee, 0xd33cd046,
+	0x37737e71, 0xcdf9a54e, 0xbba26e63, 0x2ec8df8a, 0x353e2bb4, 0x119de2b2,
+	0xc175e2f8, 0x066c1f17, 0xfbf3046d, 0xef73c840, 0xcb8fb2eb, 0xca183bcd,
+	0xdcaa25c9, 0xfca88b64, 0xe9e395a9, 0xe08304f1, 0x70f2e02b, 0x6f72dd7a,
+	0x51f3f110, 0xfd153396, 0xbf030f47, 0x7d21f797, 0x2dcafd0e, 0x7e3952e3,
+	0xed4cbdb8, 0xc2290ec0, 0x683f58fb, 0xac3b7f22, 0x273cfb1d, 0xe2c5fef4,
+	0x28ee30fd, 0x07f3e409, 0xd36edc29, 0x095fefcf, 0xbf028e3c, 0xafa30b20,
+	0xfce6fe30, 0xe73565be, 0x7ddf956f, 0xf9f18a93, 0xff388727, 0x7cccbb60,
+	0x9520571a, 0x914d379e, 0x58581e48, 0x6f5f1220, 0xd6be0931, 0x04e9573e,
+	0x38c46dc6, 0x60bd2746, 0x7f0409ff, 0x3de787b2, 0xe4c2ed08, 0x17df07a1,
+	0x953fb5d7, 0xfe0be76f, 0x3ff9057f, 0x6cffc43a, 0xeefbe723, 0xf097adf5,
+	0x3df26957, 0x57e46bf6, 0x82af4fe0, 0xe1726afc, 0xdede3fbc, 0xf456e47c,
+	0x3e55eb1b, 0x3d4fcad5, 0xbd3c569f, 0xcf53e88f, 0xefd71fa7, 0xa7c8894b,
+	0xb4a5f73b, 0xd3e245e6, 0xaa7e56ef, 0x2754fbf0, 0xd879553f, 0xf2f51c1d,
+	0x250481f0, 0xdf843ca2, 0x2bac3621, 0xa774a9fd, 0xdf82dbd2, 0xb942f557,
+	0x2a9749d3, 0xa5d275dd, 0xf9fa774a, 0x7fa7e16a, 0x158047fe, 0xb90df9e2,
+	0xf7da1863, 0x45b8c153, 0x03054dbc, 0x6b1f34a3, 0x4d5f11a5, 0xfef3e311,
+	0xb7184983, 0x79c21241, 0xf4bff54d, 0x0df7be19, 0xdfa2f313, 0x2dcf767b,
+	0xab57da0a, 0x990ead92, 0xe68f84e4, 0x5eec8efd, 0xb00f7189, 0x8e51aaa3,
+	0xdb47f74c, 0xddb96ed1, 0x32709eea, 0x7f448411, 0x8dcbe489, 0x07b2656b,
+	0x2e3c79ad, 0xf2611ae1, 0x9efa5fa1, 0x2be345c1, 0xfd5e1829, 0xf73d1a23,
+	0xb93dd1cf, 0x2157c606, 0x8c3f87c6, 0xc2ceddd7, 0x0f5faa7e, 0x46bbce5d,
+	0xa1c5440a, 0xe3b12c3f, 0xddb87061, 0xefe32da7, 0xfd4252bf, 0x777eae5e,
+	0x5f4df47c, 0x3aba05df, 0x1b787e0e, 0xba7c8d5e, 0xcb3cf4e1, 0xa9e8e1cf,
+	0x031fc894, 0x615c9bbc, 0x44bad57e, 0xbddef72e, 0xcce280bb, 0xec0ff785,
+	0x2e6de5c1, 0x423cd7c5, 0x2af79e7e, 0xa8af503d, 0x03f9eef6, 0xe8efe445,
+	0xe822d3c7, 0xdec22ffc, 0x5a563b3d, 0x9ddf0327, 0x3f641d65, 0xd8dac779,
+	0x6f7e08d6, 0x7ea7624d, 0xd430f260, 0x86afea4b, 0x4f13b0f8, 0x329e276b,
+	0x7f0aea0e, 0xe5571dfc, 0xc3effca0, 0xe109f915, 0x1d6b62d9, 0xcf308aef,
+	0x4adc047b, 0x46667ef6, 0x3f937639, 0xb8f084c7, 0xb1acac69, 0x28947f63,
+	0x2b0144e4, 0xec9571c0, 0x246e2ebd, 0xec80e3e2, 0x3d5c01b0, 0xf76673fe,
+	0x11c3cbc0, 0xf5fb47fb, 0x0f31c984, 0x67e278e1, 0x3e05e636, 0x45c44578,
+	0xf51391e0, 0x44e5741a, 0x225f7dfd, 0x9bbc078f, 0x4eb82768, 0x2534292e,
+	0x1af37bc3, 0x6f3183ec, 0xbfea2191, 0xf3d0a89b, 0xad4ed14c, 0xebc95197,
+	0xd5ed99b5, 0x23dfe691, 0x6a5f53b9, 0xdefb35f0, 0x0fe8cd3b, 0xabe16fff,
+	0xc0d8fef0, 0x8d5f8c18, 0x746e4895, 0xfc4663a5, 0x63fc1e70, 0xfbcf13f4,
+	0x7cf2bc79, 0x02c38f09, 0x735db93c, 0x8d764493, 0xf87ae74a, 0xabe0273e,
+	0x28a8ffbe, 0x9db913fb, 0x8557c2a4, 0x6abc7eab, 0xd757907d, 0x1bfbcb86,
+	0x293f071b, 0x2fc23e61, 0x55d00dd9, 0x8cd5b1b5, 0x5c69e77c, 0x667f426f,
+	0x65fbc2ba, 0x29a0d746, 0x6ef37461, 0xdbde91a2, 0x267a3f9c, 0xb585c7d2,
+	0x77f38616, 0x871739ce, 0x8315f37a, 0xc8d1b5e3, 0xe4caaf7f, 0xc707778f,
+	0xafdad6bf, 0xef0c6b1f, 0x39c68737, 0x84d0b2b9, 0x654669ea, 0x8c352993,
+	0x4c4dde8e, 0xfdeae7a0, 0xf2854a8c, 0x1a3ef062, 0x16e7f787, 0xd5e49bca,
+	0xc344c707, 0xf13519f3, 0xc02afe9c, 0x8e72a6f0, 0xbea68f26, 0x5347cf47,
+	0xe535a24a, 0x3dad45d9, 0x96252e11, 0x044762c0, 0xa926f4fa, 0xf535f9f4,
+	0x37e81382, 0x5ffedd02, 0xab1617a7, 0x9355a17a, 0xa92ebecf, 0x8d485e8b,
+	0x2d1617a4, 0x0f115253, 0xd165be6a, 0x2252e34b, 0xb5c385e9, 0x1472df3c,
+	0xcf5e19e4, 0x70bd014e, 0x985e9875, 0xd13a2362, 0xba482bb7, 0xf1505e8c,
+	0x99cb1df4, 0x2217a8c3, 0x24f8f5f0, 0xd9b85ead, 0xe17a4e5f, 0x533229e6,
+	0x497df3c2, 0x56eefec2, 0x4ca6142f, 0x11c9b2a7, 0x106e811d, 0x3a17189e,
+	0xf8eef22a, 0x3f0fd41e, 0xbc13b24e, 0x3ba27af4, 0x39799e39, 0x04bffe39,
+	0x2f8e555f, 0xbd912a9a, 0x18ee95d7, 0xe9a2efd1, 0x16ade512, 0x7c72e1ed,
+	0xf1c81951, 0xae45d61c, 0x0eae50ba, 0xbcab9709, 0xeb9bb57d, 0xce634f01,
+	0xf9e14b2f, 0x0e4cebad, 0x35bfd42b, 0x85876724, 0x271fd9cb, 0x2b672375,
+	0xe0bd9cb8, 0x45f1e82f, 0x4263cb71, 0xcafc82be, 0x8ba04475, 0x9ad1a569,
+	0x06270375, 0x19ef29ff, 0x64578fe4, 0x27bc878a, 0xc1c1fdf4, 0xf6821a7f,
+	0x0f1c61ff, 0x49b7efe0, 0x9f80ef5c, 0xe058fd71, 0xdc39a2fb, 0x2edaae5e,
+	0x1baafc13, 0x6f57bf38, 0x3d0e2893, 0x3333ff3e, 0xf0f6ede5, 0x971a86b8,
+	0xf0bff156, 0x9955d695, 0xc4937cf8, 0xfc0acce3, 0xcd87cb0b, 0xbf242c73,
+	0xad06fe64, 0xe96250ff, 0x4aed8fd8, 0x3639277e, 0xec8bfc91, 0x7e89556f,
+	0x3ed36e16, 0x16ac72af, 0xe48057fe, 0xf6bd5576, 0x5fc15ef9, 0xde40e573,
+	0x7bcf9833, 0xd244764d, 0x4ebd6a67, 0x9bfc5478, 0x780168f0, 0xf0eaf90c,
+	0x44dfddb8, 0x0baf9379, 0x5ffcfd07, 0x3e46e554, 0xf6fc821b, 0x7249c19e,
+	0xcf32fbc3, 0xdf59ce3b, 0xfe3c3537, 0x8ba0bafc, 0x55ee0c57, 0x9aaf58e9,
+	0x6fe73fe7, 0xca1a8704, 0x306cf5a5, 0x37f36efa, 0xa76bf568, 0x48506f3e,
+	0xecd6975f, 0x43cb6e94, 0x5abcf3b8, 0xf8fd6f85, 0xb65e780c, 0xd437f414,
+	0x716f9d9f, 0xc5a8fc63, 0x517241d6, 0x05cfcfa5, 0xe053fcbf, 0xc74644e3,
+	0x8d3bd258, 0x2ef89d92, 0x087ae360, 0x728362f0, 0x8fbfc8f3, 0x5bb07817,
+	0xde392f88, 0xe427803c, 0x517ef1db, 0xddf6e7ae, 0xee39ff0c, 0x4c9bfbff,
+	0x91a2aed8, 0xa0236baf, 0x8c3be986, 0x84a61447, 0x1b4f73e1, 0x92adefa7,
+	0xe0f86e83, 0xe7c197df, 0xdaa8f065, 0x9f165f23, 0x4f3e5c2a, 0xc0827e12,
+	0x582d8b6b, 0xfc798052, 0x3363923d, 0x53c7f656, 0xbae4e15c, 0xd8df843e,
+	0x3d578e64, 0x80dfa3dd, 0xf2d4a6eb, 0xfa201c24, 0x7636c5f4, 0x6f6f7d42,
+	0xcb855f6e, 0xa3be351d, 0xbe6abf5e, 0x1482c3cc, 0x66f352af, 0x83f76523,
+	0x7257a889, 0xa44f5a25, 0x4660cfe6, 0x40dfd7c4, 0xbe9313ff, 0x66967fa0,
+	0xecedebe7, 0xe13b7dea, 0x6e5136e9, 0xb4761ace, 0xa17be014, 0xbae0764e,
+	0xca0c5bb4, 0x9e506b91, 0xe43131ac, 0x4d070b8f, 0xa3df2e4e, 0xbf949f49,
+	0xfa84c272, 0x82731cb0, 0x09ffc798, 0xc4271bd7, 0x3d02de78, 0x2898c4ec,
+	0x093a1fab, 0xd1c53fde, 0x9cf30e34, 0xacb48753, 0xe4ee38c4, 0x2391fb22,
+	0x32d5cf88, 0xaf1e7c43, 0xeb3f222b, 0xe2243bce, 0x6f0037af, 0x94ea7ed8,
+	0xe047239c, 0xc97565bd, 0x75295314, 0x0d3cdf26, 0x6507a5ca, 0x66f50287,
+	0x831b18df, 0xfd09d7f1, 0x830ee665, 0xae0b194f, 0x6957f8c4, 0x71531dcd,
+	0xe7a015dc, 0xe15d1f30, 0x8a97196f, 0xb5128de5, 0xe6dd78f7, 0xe09d2054,
+	0x21e67386, 0x5079fef0, 0xd9eec10f, 0xb679ebc8, 0x754c0e48, 0x27aff3cd,
+	0x8b6f3879, 0x598970c4, 0x2b58ec10, 0x8567d7ef, 0xa11b837e, 0x63e7943d,
+	0x4b77ec7b, 0x90d3cdfc, 0xd49c618f, 0xfdb2c47e, 0x41e72f28, 0x82cc783b,
+	0xfea0ee5b, 0xb128df6e, 0x62afe834, 0x47cfce44, 0x4d077f60, 0xb47e7c0e,
+	0x671457e9, 0x4bef099f, 0xcb67fe87, 0x9d68e3ad, 0x3b258fd7, 0xb92abbad,
+	0x5677f099, 0x9b4b19f0, 0x47baf64a, 0x6f3daa62, 0x3edb8f0c, 0xe89bdc96,
+	0x65d2de78, 0xad5e70ab, 0x031ce4de, 0x5a39d5d1, 0xe0127897, 0xf43b06ed,
+	0x83c79984, 0xcc27bd9b, 0xb37261ad, 0xf10fb939, 0x42c69ce5, 0x3aea2f92,
+	0x6e32f70a, 0xb4adb467, 0x36987ad1, 0xef1b3d93, 0xd0b4af37, 0x5c1df6fd,
+	0xb567b4bf, 0xdc7e83be, 0xcc4d1b07, 0xbe5c630b, 0x88c3cfb1, 0x9bb60fc7,
+	0xdfe4de88, 0xcd8e4898, 0x5be3c1df, 0xbf791bcd, 0x72e36c1f, 0x5337e8ad,
+	0x9ebca3c7, 0x42c9f20f, 0xafcad3f3, 0x1e02ca79, 0x89b75d47, 0x9557cbf4,
+	0x53e45d53, 0x5f1455cf, 0x7aef4eec, 0x77aa8c58, 0x5ebe31f2, 0x7335955e,
+	0x196fd203, 0x03068c4f, 0x087d3fbb, 0x2c6569f5, 0x46d53bc3, 0xa712c3fb,
+	0x96c7ca07, 0x8a7e77fa, 0x6a515ff4, 0xde1e2073, 0xbf23f847, 0x78a44dac,
+	0x395f3cea, 0xab3e79c1, 0xdfcf3821, 0x356fa5a0, 0x2ddd386e, 0x9eb86733,
+	0xce6688aa, 0x7f477ab0, 0xef0a7402, 0xf928d599, 0xdb96126c, 0x42192ff6,
+	0x6b8d3b65, 0x6bfbd0a9, 0x8f8e8963, 0x4adcf0fe, 0x7799d3a4, 0x6eed0c4b,
+	0x42af75e6, 0x41bd57bd, 0xd6bd7052, 0xfb79bbfc, 0xc71ed0f9, 0x9c57f47d,
+	0x15ae809e, 0x8deafba4, 0xfd53f7eb, 0xfd82922d, 0x4e54dd1f, 0x57854276,
+	0x4b7cf466, 0xa001f91b, 0xd30f2897, 0x905395ec, 0x5857abee, 0x57d798ec,
+	0xc7a547e9, 0x661f9136, 0xc9a0c756, 0xb2516ed0, 0xe50e9112, 0xdea75269,
+	0x78f17a44, 0xedb57d39, 0x25903930, 0x7c8f4f2e, 0x6f4a825d, 0x90dbd232,
+	0x6f35bd10, 0xfd23322c, 0xebe3e07d, 0x5e908a11, 0x571f1e91, 0x262c2ae3,
+	0xe9523edc, 0x07e80ab1, 0xe8e5f4e5, 0xd3fa3bb1, 0x02f81dd3, 0xcee47eb4,
+	0x771a3695, 0x37ddaad1, 0xc47ce52f, 0xab459c70, 0x8179487e, 0xff1e4679,
+	0xeb88e156, 0xd24f30da, 0x2e0f1c65, 0x997fa733, 0xf1c6e8f1, 0x10d8e48b,
+	0x96e803fd, 0x01bac59b, 0xe5039443, 0x5698c4d3, 0x31e304a3, 0x51187525,
+	0xe14f0f3f, 0xc23979fa, 0x3325eb0a, 0x67281f5a, 0xacee081a, 0xa3d7c297,
+	0x876476e6, 0xa67b63c7, 0xb06efea8, 0x189fde27, 0x5851e50d, 0xff404db6,
+	0x5745a26e, 0x60a061ee, 0xbc516313, 0x5eca2a9c, 0x4c9d0328, 0x479f54cc,
+	0xd12f72f3, 0xebcd1bde, 0xc79f500f, 0xead5f2f0, 0x7f5e18f3, 0x99e7a334,
+	0x7013b129, 0x14cf573d, 0x237c66bb, 0xfd0d4951, 0x62d957fa, 0x6eb489a8,
+	0x9a8a6fa7, 0xaf146787, 0xf4fff976, 0x5cb5e606, 0xf90098d6, 0xe9d34e07,
+	0x867b30d6, 0x13ca7589, 0xa4b23d04, 0xae0bb238, 0x2f01bfc7, 0x26818c13,
+	0x06b06f6c, 0xb0573f08, 0xfbf7f615, 0xf65222e3, 0xdd05e7e0, 0x56a86bfb,
+	0x6ff30fde, 0x4b632725, 0xc524ae81, 0xe590f94e, 0x46db994b, 0xed4b94eb,
+	0xcc49bf68, 0xaf9cf869, 0xfbe17657, 0xefa8f1d5, 0x802e32ef, 0x7c2131b4,
+	0x1fa91b5c, 0x07675c75, 0xb798bc5b, 0xfd618ef4, 0x74e0c26b, 0xf08ae916,
+	0xe22264b4, 0x098daced, 0xac728bbc, 0x8447fcfa, 0xeaf1b3d7, 0xd64e5173,
+	0x95d74f3d, 0xa4febc4d, 0x78272b94, 0x64b3bde1, 0x6814a4e7, 0xd0c73163,
+	0x28baeaba, 0xbee5debe, 0xed17b764, 0x5a73a023, 0x32cde497, 0x76317f93,
+	0x5f0ce488, 0xd043315f, 0xb114b1f5, 0xaeb2d94e, 0x0ded05a6, 0x4196c3f0,
+	0x0ba5cf7d, 0x4c4f8c66, 0x9199b7f4, 0x401baaee, 0xcb15e26e, 0x68dd5798,
+	0xf75a4676, 0x56452a76, 0xf59a17e3, 0xfab2fbc0, 0xb9424cad, 0xafcb873c,
+	0xc7e3bb45, 0x39517961, 0xbd6ff7b7, 0x0438e766, 0x69ab9941, 0xb1675e25,
+	0x8a687dd6, 0x74517ea3, 0x4edc25fa, 0xd449ab2e, 0x03ad6794, 0x75c20e6c,
+	0xfef5da99, 0xa7b9e44c, 0xe30fd0b3, 0xde04d38d, 0xa5ada7a7, 0xb774f7bc,
+	0x44e73d76, 0x026332ff, 0x2246bb8e, 0xb8e6093d, 0xf066ed82, 0x6c35c219,
+	0x7dc0385d, 0x67d0a35c, 0x97ce5c95, 0xb4a97f0a, 0xdd17af82, 0xc2666597,
+	0x7f71f2df, 0x84d8fd6a, 0xa3f71421, 0x7f1efef5, 0xcfeb098b, 0x137e0258,
+	0x4ec97bf7, 0xda0ea598, 0x86e60ceb, 0xe3c61b8d, 0xe755fa45, 0x3ee50d35,
+	0xf5edc3ae, 0x10ed09be, 0x5d668f98, 0x6d0a8ce9, 0x5b46acb9, 0xf733afd6,
+	0x3b3908a5, 0x7e400d80, 0x19229adb, 0xf944ff89, 0x5791d674, 0xefae0a03,
+	0x194b6d74, 0x0747eb4a, 0x295ca1a1, 0xf9dca9bb, 0xe6a81cdc, 0xc78c07fb,
+	0x25cf895b, 0x26e5dfe2, 0xe310bda7, 0x0fdc5529, 0x35cf819e, 0x7d7806eb,
+	0xcb5dcb2a, 0xfee14d7f, 0x6b9b72da, 0xc12dc531, 0xc13cc54f, 0x98d3a358,
+	0x307c4790, 0x7b3c922d, 0xabffd05b, 0x8c15b40c, 0x25121fab, 0xe4dfa5e0,
+	0xcf8c3e1e, 0xb963fbf5, 0xfd53e317, 0x0aef000a, 0x779e05ca, 0xaef2209d,
+	0xb33e8037, 0x5c9fb5c1, 0xc7f48d3f, 0x176e66d5, 0x2aac7c8b, 0x6b8f9c4f,
+	0x7a13b1f3, 0xe50cf81e, 0xd61b0dce, 0xdb99ff92, 0x1ebf99c7, 0x8d9f77c6,
+	0xddbeffbf, 0xcea98fdc, 0x35f24fdb, 0xf4f229d5, 0x36ce4269, 0xe7559c82,
+	0x454df80f, 0x64fe87b9, 0x37bd1e49, 0x87bd73bd, 0x14a4e493, 0x1cf86318,
+	0x78aa57e4, 0x0a599def, 0x41652bc1, 0xcef384bd, 0x6865de62, 0x6819ff37,
+	0xd7abef0a, 0x533ebdaf, 0x56ebf491, 0x541d2067, 0xf58ab5a5, 0xdfcf5faa,
+	0xe7fe82fc, 0xf7d41ca2, 0xebe7d30f, 0xec4ced04, 0xf144b847, 0xde2e3540,
+	0xad917e9d, 0x30dc8d06, 0xf234a3d9, 0xad7f4265, 0xd0e899bc, 0x471b99ca,
+	0x9f3cd1f4, 0x79a01ce4, 0x40b8b93e, 0x1aea9e53, 0xcb7fa9ad, 0xd94d22b4,
+	0xa6bd7692, 0x49b94dbe, 0x7fee8e53, 0xac7ea6ab, 0x73cd36e3, 0x4ecf4bcb,
+	0x662e0093, 0x0dd5b7ab, 0xde03a870, 0xd2109118, 0xace2031b, 0xaa287eb4,
+	0x6c7e46c0, 0x004b60dd, 0x832ea4e9, 0xbcb0d3ef, 0x002d24b4, 0x6c7b58fd,
+	0xf5c216b7, 0x0c6f92f7, 0x62ac73c6, 0x7755f61d, 0xf95e8d33, 0x2be70665,
+	0xaa657af5, 0x5c1a687b, 0x9929b6f3, 0xf068048c, 0x358fc42a, 0x6bbb718a,
+	0x7437df17, 0x91cfea35, 0x64967ea1, 0xc54a0e15, 0xaf3b7776, 0x91b3bf23,
+	0xbd42fbd9, 0x91bf62cd, 0xda999777, 0x1ab635e5, 0xfdfc619c, 0x0f2e5487,
+	0xb98d721e, 0x32f8898e, 0x0deac3ea, 0xf7e8cdc7, 0x689bfb57, 0xd720e1dd,
+	0x16f7da71, 0x9af42fba, 0xd70a23b1, 0x1f553d3d, 0xc2e23d79, 0x6bcd3354,
+	0x65e390bf, 0x7f61644b, 0x2aa4f8f3, 0x7676cb97, 0x1b8c6404, 0x93e36954,
+	0xf20d397a, 0xded76359, 0x7140223a, 0x11d3900d, 0x0f5545fd, 0x3cd6dc80,
+	0x3af6859f, 0x7943275f, 0x9ae39023, 0x4553d3e7, 0xcb006b3c, 0x6fc275c3,
+	0xe7110cb8, 0x1e0cdbf7, 0x5dc37ebf, 0x087f7044, 0xc21216e3, 0x0e2f0f53,
+	0x69c1cbc7, 0x15bf9a87, 0x7bd7d2f8, 0x6be3832a, 0x3a723747, 0xceedca90,
+	0x1f3052cd, 0x15c7a885, 0x033af445, 0x2014a5d7, 0x0ab6fe1e, 0x67b2a8fd,
+	0xf4fa8625, 0xd12f4daf, 0xae33263a, 0xa438c24f, 0x6954bf58, 0x7fa19652,
+	0x40e0f400, 0x31baa6fb, 0xaaafe340, 0xfbc2682f, 0xce3c8d55, 0xf1e069e2,
+	0x4ad66acb, 0x6ee6dd7e, 0x2a6f75c6, 0x5207efa7, 0xc7bf1a15, 0xbd44ef0d,
+	0xf9f160de, 0x2b7fc424, 0x76ca57c5, 0x941d6c4b, 0x4eb6af37, 0x3d2f648b,
+	0xe2fde02f, 0xf5c3336a, 0x1ed095e6, 0x6b3fb1e7, 0x3be319bf, 0xca253b65,
+	0x5bea7867, 0xd6be62a6, 0xd0c4d8b3, 0x77c7508e, 0x7e482b26, 0x84739be4,
+	0xc787391f, 0xcc5cde2d, 0xee790fed, 0x9d57147b, 0xc8fc255e, 0x0e281739,
+	0xf08566f4, 0xb8f2e723, 0xd43bf4c7, 0x8e968ebc, 0xd3d53a55, 0xf56e9e9f,
+	0xe955faf4, 0xa76a4773, 0xf508319d, 0x1c7be03a, 0x1fdef1fa, 0x4c27ca32,
+	0x426cd4bb, 0x2af7bf3f, 0x281ee3bb, 0x2b7d940f, 0x9ace5e31, 0x95c1f3f9,
+	0x5f2e249b, 0x3e715b94, 0x86667599, 0x020239fb, 0x53c4014f, 0x43a94e32,
+	0x357e468a, 0x1ca37b06, 0x0175c1ca, 0xc1a7c700, 0xf949dfcf, 0x065f2e25,
+	0x69b6973e, 0xd6bd184d, 0xcaa2b908, 0xe66601bd, 0x017189de, 0xc6067d63,
+	0xf8987717, 0xd16c963e, 0x1d3edf5f, 0xb5c127e3, 0x65ffbc4d, 0x7fcb5571,
+	0x94fe10c9, 0x75c11673, 0x5da3c8a2, 0x8a5034bf, 0x744ec8f3, 0x6f315307,
+	0x12a47d99, 0xef5d5af5, 0x1fd0f397, 0xabc3d751, 0x91e6f471, 0x13bc6c1f,
+	0x32bb6be6, 0xdb69f08a, 0xf48edeb3, 0x243beb6b, 0x57de5235, 0x2a2e7abd,
+	0x53fc0dcc, 0x5d37b17d, 0xbda4f2d5, 0x6dfd68a7, 0x78dcffb5, 0x698b8fe2,
+	0xf76d5f74, 0x81ee3127, 0xf32cff62, 0x065e9127, 0x911c6cb9, 0xc2a7aa1f,
+	0x68e75d41, 0xf085bbeb, 0x3c1de775, 0x7ad8c1bf, 0x654667ea, 0xfd0e548b,
+	0x9a7262dc, 0x47de0062, 0x709b4c7a, 0xd5d71732, 0xc1c1b8f3, 0xa5c52b5a,
+	0x53b5ad5e, 0x469b5839, 0x156bd7e5, 0xec915eba, 0x34e104fa, 0xbe9ac5f5,
+	0xace6b708, 0xa7985d87, 0x44d07b3c, 0xaecc60f0, 0xc17de7d9, 0xea3c532f,
+	0x5f5f0342, 0xe67f8ea2, 0x4ee60cc5, 0x8a6371e4, 0x0bfd2c57, 0xc54739c9,
+	0xf7e8f1b9, 0x5b6cae0c, 0xd2cf6585, 0xee9d694f, 0x282fa03b, 0xe3c8d1ef,
+	0x2d8d55a7, 0xf4b9ceb4, 0xb3f50262, 0x1e31d0c3, 0x82fbccf9, 0xde3beb44,
+	0x4e673c69, 0xd288fae5, 0x7c451b3a, 0x3c5a4879, 0x1fe3c1c1, 0xe5f8e06c,
+	0x8245d579, 0xfaae9a1e, 0xc3e21c47, 0xf5a154ba, 0x6407d522, 0x19acb38a,
+	0x8f6711d3, 0x6e317720, 0xde93eb8d, 0xf494eb12, 0xbd99a7cf, 0xc07d717d,
+	0xfde44334, 0x50b48ecf, 0x75d71f7e, 0xc7f53297, 0x3f83d7f7, 0xca88eb43,
+	0x8ca745fc, 0x6ef9ad78, 0x196acff2, 0xfdf0c1fd, 0x320fe806, 0x34bdfbcd,
+	0xae564b7e, 0x85d6ef26, 0x98335bfe, 0xaeaa7802, 0x20173003, 0xd7455f9d,
+	0x2af7ddf6, 0xa8d637c8, 0x2f51878e, 0xf2067eb0, 0x5abcaa27, 0xe84b273b,
+	0xee0cacad, 0x89a7173f, 0x2fc2b2fd, 0x4267ff02, 0xe27ff71a, 0x5f8d32f6,
+	0x7e4fbfa4, 0xc7ec5591, 0x7978001e, 0xafb8c23a, 0xc2e318cc, 0x1d6cd976,
+	0xfa0337d1, 0xcfd2ba46, 0x1f1a4673, 0xd3cfca97, 0x28f39f91, 0xacfc4ece,
+	0x464877ef, 0xcfb40ce1, 0x5fb37756, 0xefc12aeb, 0xc1181b55, 0x8121b3cb,
+	0x6d8674e0, 0x7a018d70, 0xd8e3033c, 0xd678f40c, 0x878e8ae5, 0xaedd67f6,
+	0x109884e8, 0x886f57ff, 0x73ab76a2, 0x872c4a6f, 0xf7a08d72, 0x2b22c6f6,
+	0x06e679c2, 0xfbea77ce, 0x4f4c09de, 0x6a1a3e44, 0xde6330ea, 0x2dbfa7ae,
+	0xa1bbed0e, 0x222727bb, 0x4e3775ff, 0x779f3a77, 0xb445d2d5, 0xb87f155e,
+	0xd0a1627e, 0x3a7b9e63, 0xd57ca11e, 0xdbf44652, 0xd5afebb4, 0xfeedbfc8,
+	0x9e6bca68, 0x7a4d13d9, 0x3cd3ecf0, 0xd4c679af, 0xaa60eb4a, 0xf476cb77,
+	0x7c2f3d07, 0x9ff230fc, 0xa1459767, 0xdeffbd78, 0xb6aeb873, 0xad1d7fd2,
+	0xfedca8c3, 0xd541f2dd, 0xfec8bbd2, 0xd71fcb51, 0x37285d5a, 0x2e5c8ddb,
+	0x867c6c2c, 0x9785d9ec, 0xfcc20c2e, 0xff3d99ef, 0x98e50c3d, 0x86178fe7,
+	0xe7ec3ed1, 0xe7c30c2f, 0x6ba2e79e, 0xef25d922, 0x8e38f066, 0x0e731faa,
+	0x9ef13519, 0x73fe8209, 0xc62bac56, 0xb6864d73, 0xaf84714c, 0xd7da1b1b,
+	0x8617fb40, 0x389b1e1e, 0x8addac37, 0x392fdf20, 0xf46c65a4, 0x747a309c,
+	0xb8d49866, 0xd38ad7d1, 0xa11fb130, 0x34132e33, 0xd5843ed0, 0x6f3f2341,
+	0xa1f242a0, 0x8a7600ff, 0x4bd91dbe, 0xe44f6f67, 0x5d1832e7, 0x1d220613,
+	0xf697dedc, 0x75af3387, 0x3d986e5f, 0xa0683d34, 0xfcd3ddf5, 0xefd90096,
+	0xefad2341, 0x99a4ed56, 0xcd883ee7, 0x5dc42291, 0x0e3ebffa, 0xfe3eb6e5,
+	0x6ec6b3d2, 0x2fef0898, 0x08ecc15d, 0x063c7d3f, 0xfb9db17e, 0xf8d75992,
+	0xd07c128c, 0x5c95ed8a, 0xa7c71d83, 0xb78899da, 0x3efc0886, 0xb3f39d2d,
+	0x822b47ca, 0x8ac7c206, 0x2e6b18e0, 0xe789275c, 0x7136a00d, 0xff0ae8df,
+	0x1f18ade4, 0x96e97158, 0x9ef081e8, 0x626e8715, 0xdbbf20f7, 0x62fb58c7,
+	0xb7df4bbb, 0xd10bcd4e, 0x4a7dfe89, 0x2127d73a, 0x7eb2207b, 0xfbfc178b,
+	0xd8b9e95d, 0x3d6cfff4, 0x52757e07, 0xabf250fa, 0x07b8f067, 0xfaf5abf7,
+	0x6abb9541, 0x7e04e3bf, 0x53ddcabb, 0xff80bf64, 0x5c77724b, 0x7af542ba,
+	0x922527fa, 0x4a687c5f, 0xb5d312a2, 0x87463eff, 0x6baf2121, 0xe69daaff,
+	0x59f73af1, 0xf2717fd1, 0x8a6796fc, 0x90a493e4, 0x4971e75d, 0xa9649f7c,
+	0xd4f587c9, 0xf0a70571, 0xa754e9b8, 0xaa86f289, 0x87daa7fd, 0x3c1dcf9d,
+	0x8bdaa8af, 0x74185daa, 0x94ec38f1, 0x15f9fc21, 0x106beec9, 0xf588ef5e,
+	0xf247432d, 0xf6b98cfb, 0xcb747fa1, 0x7e2312cd, 0x4aa2f617, 0x527b7a9f,
+	0x1ddf6f5d, 0xba0a371e, 0x5b2bf954, 0x9eaa17c7, 0xba7a11aa, 0x2274f51a,
+	0x34cfe9ea, 0x5fbeb776, 0xf4aed3d0, 0x08c76c64, 0x1b0e43be, 0xeefc915d,
+	0x375fa213, 0x3dae0fe2, 0xe2162f83, 0x7058b378, 0xdd8bfa19, 0xb0974fe9,
+	0x5e7bba63, 0x5f9fc693, 0x08d78f8e, 0x7c577ffc, 0x9c3feabc, 0xbeed3b8f,
+	0xba23ce6e, 0x7ef0a332, 0xb928dba4, 0x7c885826, 0xc51367f7, 0x4af5f5c9,
+	0xff063e85, 0xfbbf4355, 0xf406ccb2, 0xdc153c77, 0x578bafff, 0xe4bf235e,
+	0xd5d69925, 0x0eff042c, 0x1705b3ed, 0x44ad74ed, 0x33ae183b, 0xfe50b5b6,
+	0x76854660, 0x831875fc, 0xe477f6c5, 0x32fc7ad0, 0x44e29636, 0x3b78fe65,
+	0x4baf23ee, 0x86f5a7ae, 0xb2b2adde, 0xedfebc35, 0x8f2b7d6a, 0xf74d2d9b,
+	0x6b79e72d, 0xab2fbe8d, 0x5af3dbd1, 0xc45a3ffd, 0x03b3ba7d, 0x71b26f9e,
+	0x26407279, 0x78c6aefe, 0x998cd5d1, 0x4bd5f5d5, 0xdaa39c79, 0x23f68cbf,
+	0x1fe78957, 0x4714831a, 0x5417fca2, 0x9f5fe53d, 0x9cc87c82, 0xd54f7cda,
+	0x2724c396, 0x849f79f5, 0x3c8f2e06, 0xf3c8b295, 0x7d68930c, 0xa7d8a363,
+	0x223728aa, 0xcc5c61dc, 0x863ee0a7, 0xce3fe413, 0xf325fdd8, 0x17f84e3c,
+	0x7fb3cf31, 0xf972a65f, 0x63754f3c, 0x84fd098b, 0xde7be5cb, 0xc38cef49,
+	0x97b09c50, 0x7b5fc791, 0xc63b25f9, 0xf5897a97, 0x4757c37e, 0xc77ff5f1,
+	0xdf2224e6, 0x9f6978ab, 0xfed9e1c4, 0xd88527e6, 0xa331d86e, 0x3e11d71d,
+	0xbfe2e6ff, 0xad32f264, 0x6c7f18d3, 0x25fa3471, 0x4516c7ed, 0x879f3c23,
+	0xb9e3e22b, 0xe3118c37, 0x78a1e589, 0x7bd205f2, 0xb2788b77, 0x6c5ef411,
+	0x6fa32e28, 0xd72153f7, 0x8adf30ea, 0xe79bb974, 0xddd2ebfd, 0x57f953d7,
+	0x13ff69bd, 0xbcc279c3, 0xc63a019e, 0x9800cfb8, 0x9f95e62c, 0x302b628c,
+	0xec9753cf, 0xe6f8997e, 0xf9050657, 0x7e53da06, 0x2153bbc8, 0x55a1883d,
+	0x020cc3cc, 0x7da563dd, 0x8f944979, 0x2fe04ab9, 0xf452fc1d, 0x5334610f,
+	0x403c8f30, 0x450663e4, 0x7ff62331, 0xe6bdc99f, 0x34ffcc4a, 0x88cb1d19,
+	0x93891de8, 0x85e6bb62, 0x77cf2724, 0x3521f9ab, 0x7e5dddef, 0x0cf7c248,
+	0xf945f4e2, 0x3094e620, 0x81e6ae1f, 0x4a2ecdd8, 0x511f2d4e, 0x7967e743,
+	0x9d37d8b2, 0x8b4a29ff, 0xa5719f90, 0x6bef6131, 0xfa6b81f3, 0xfa744d3f,
+	0x6b80f355, 0x71e9bfd2, 0xd5efdc2b, 0xfc487b8d, 0xa3f214f9, 0x3a77f9fe,
+	0xffb560b7, 0xb3bde902, 0x0e71161d, 0x938f2b45, 0x2f144dfb, 0x58fe0b38,
+	0xdd3e9872, 0xddfbc69e, 0xfa222feb, 0x8d8e086f, 0xc487fac6, 0xa687d5fd,
+	0xde7b464c, 0xfa3a341b, 0x7fb848d2, 0x0e3410d5, 0x1be4fb45, 0x7a694bc4,
+	0xa359f984, 0xf3d23eb8, 0xbfe09c51, 0xe70e0cb8, 0x5fb937a2, 0xf3cc59e5,
+	0x1d75761f, 0x73cf0d70, 0x914acfef, 0x6a77f8d4, 0x6ec8fca4, 0xecbd2ebe,
+	0x2df68976, 0xc8fcd97f, 0x7fb6c68c, 0x8fa23f2b, 0x219ddf3b, 0x790322f2,
+	0xdd23b9dc, 0xa84bf34e, 0xfb885c19, 0x7ef9d49e, 0x901f7083, 0x43e6edf9,
+	0xedf9efaf, 0x352fdff6, 0x837cdd02, 0xcb7d97fd, 0x96fc2ffd, 0xf52fbffb,
+	0xdb7f85db, 0xcbffdcb7, 0x8fff72df, 0xff07d244, 0xf5ebe6af, 0xfe7d78f9,
+	0xb7979f5e, 0x8bd734bc, 0xd695eecf, 0x6ae00476, 0x4d35db8d, 0x8c687902,
+	0xbd4562df, 0xe7923259, 0xb58f56af, 0xa14936fa, 0xaf0abe3c, 0x3fdc5991,
+	0xf39de7b3, 0x6ce356e2, 0x226c7067, 0x3246bbc6, 0xdacf6ff2, 0x198b1e78,
+	0xd798e9ed, 0x37e99a82, 0x67521d81, 0x7d079c8b, 0xf7f0a7af, 0x4b1bd1ba,
+	0xc8af0ab2, 0xfed5a64c, 0x59f648ce, 0xdb2f88ad, 0x17c5191b, 0xbf495199,
+	0xa4abde89, 0xe3d3fda3, 0x2e3f7e45, 0x689b9cc0, 0x4dce4a5c, 0x928f6e74,
+	0x407be383, 0xae1367e4, 0xf18397ef, 0x03b004e4, 0x1eb78f31, 0xa7e479f3,
+	0xfa9ea9da, 0xdc99ddbe, 0xc4c07a4f, 0xef305ce8, 0x11dd7c95, 0xbd9156b3,
+	0x0ee1e6a6, 0xcb27029a, 0x8dc3ca25, 0x62bff1c1, 0xce6de408, 0x449c4411,
+	0x3f296dfb, 0xdfc8eaf8, 0x7bd377f5, 0x86fecd14, 0x6187f466, 0x29ee771c,
+	0xb19dfa20, 0x6fed2477, 0x091ae4f0, 0x46fc5dce, 0x43780711, 0x38d431c4,
+	0x7a8f9a80, 0xde3fc45b, 0x3f4ab8c1, 0xa1584f3c, 0xc34caceb, 0x5a9e77bf,
+	0x159cfe57, 0x203d3f49, 0xf78fb8f1, 0x29f71e15, 0x84fa3b30, 0xccac7faf,
+	0x0f2c78e4, 0x1a83bcf0, 0xcc4279c7, 0x7287e0a7, 0x687602c0, 0x6681aac1,
+	0xab05ebd4, 0x3af0a2b2, 0xa433e9c8, 0xcfa7bc00, 0xf15069d9, 0xee8e8917,
+	0x89f114ca, 0x8f941d03, 0x9797467b, 0xd7c99ddf, 0x7165e41b, 0x64ceeefc,
+	0xafb3be54, 0x8b9a3971, 0xcbb1ae3d, 0x6541f291, 0x38e2f7e0, 0xb8f8ebcb,
+	0x05977855, 0x4f7c2294, 0x558ebedb, 0xc8afcd78, 0x79b8a229, 0xb455b9e5,
+	0x85d2e9bf, 0x1c52d7fd, 0xffa0accc, 0x1b55b330, 0xc5909b4f, 0xa0cfe7e3,
+	0xbb708dc1, 0x6ffe48ce, 0xa24675c1, 0x1b32849f, 0x2609a7f9, 0x7960c726,
+	0xf283b712, 0xb08a938b, 0x93c4a6cc, 0x407f97fd, 0x179b9f89, 0x5c256f8a,
+	0xe11938b7, 0xa8bcb974, 0x22bb271a, 0xa44bf9d9, 0x179aafdf, 0x88783aad,
+	0xf3aa7bd6, 0xe6a2e152, 0x8bcbbb37, 0x3c12ebaa, 0xd6689fc5, 0x1d8c7851,
+	0x58ae31e3, 0xaccda7b0, 0xcb4b37ee, 0x0b4de509, 0x7ca39f76, 0xf51f9aa9,
+	0x3b239cd4, 0xb199da1a, 0x3fa0017d, 0x4364e41d, 0xee9bcf2d, 0x1a7bfb12,
+	0xae78fe61, 0xfe601ff6, 0xfcc3f578, 0xb50bfef1, 0xa81ae9fd, 0x6f75d075,
+	0x7aba08ed, 0xcf28e7fc, 0x36a642fa, 0x8f99d75f, 0x084d5d93, 0x1d7cb0af,
+	0x3af9f595, 0x63c78a39, 0xee303f70, 0xb41cf21f, 0xf42efc92, 0x7f42f797,
+	0xee2d6fe0, 0x6aee385e, 0xd18597cc, 0x61d3bb45, 0xdb6c73c3, 0xe61b0e5d,
+	0x4e9a0ac9, 0x6a847ed1, 0x15ce9063, 0xa6073ce8, 0x775f1ce1, 0x21b42feb,
+	0xd79b2f7c, 0x79fffc6a, 0xd7932fad, 0x32f905ba, 0xf23f2439, 0x26e7065d,
+	0xda701ebc, 0x87c986e6, 0x179e2ed5, 0x9bdb9d59, 0x5741eff8, 0x6139f8ef,
+	0xe628adfd, 0xeb848a71, 0xf7e16d72, 0x79e2c89f, 0xb98904ac, 0xe4b1c922,
+	0xbcb8df9e, 0xef648e4e, 0xf402bfb7, 0xc3d03578, 0x5abdf9ee, 0x71b4ae89,
+	0x73c5d5b6, 0xdbb9e17a, 0xac2c37de, 0x69c38f2f, 0x974c6ce2, 0xde2eeb4f,
+	0x40d8a336, 0x7bc2e2e7, 0xeb5f51b3, 0xd8cc62e3, 0xb9f5cd91, 0xe4739c53,
+	0x582364cd, 0x5bdabc97, 0x173877cc, 0x362f4fea, 0xf3509e90, 0x46c5f96b,
+	0x99f40b56, 0xa3e4d4bf, 0xb1b15abc, 0xff0b9e8d, 0x3f3d8570, 0x3bc9e513,
+	0x8c76cd07, 0x60e3e9a3, 0x752de28e, 0xa3bda1bd, 0x6d7da252, 0x373fd65d,
+	0xf8c38d36, 0xaeb660d9, 0x1bd42c6e, 0xe3b06b9c, 0xe5cbe57a, 0x3d85f2e1,
+	0x219f8fa3, 0xa1fda15d, 0x2f5fa38f, 0xb0bd7ef0, 0xbf43ee97, 0x8fd43932,
+	0x2f4f4eda, 0xbe94f68f, 0xbf7f2e30, 0x71456fe8, 0xc45ceafe, 0xa1818967,
+	0x3c5158de, 0xd61b9ac6, 0x234f595f, 0x7986af5f, 0xbcf0a4bd, 0xe9dfcf1e,
+	0x3caa79f3, 0x8cfa682b, 0x083efff6, 0x95f51972, 0xffc78d27, 0x3c285e0b,
+	0x34227280, 0x1f9fae4e, 0x37bf534c, 0x7c6788e0, 0xd14fb45e, 0xb8a247bb,
+	0x27c97e5b, 0xcca1a37b, 0x7fb4f15c, 0x773073de, 0xef939e39, 0xc50e3129,
+	0x971e3afd, 0xc22799d4, 0xd7e4d07c, 0xf5c7ae2a, 0x075305fc, 0xa67e20b7,
+	0x9d689a96, 0xa6d7e4de, 0xaae539d1, 0xba982b9e, 0x7c289ee9, 0xf3a25fde,
+	0x56bf261a, 0x4f9f063c, 0x88c01ed8, 0xb3889b38, 0x3c193907, 0x7c88d278,
+	0xfbb24572, 0x0537c827, 0xa89e4493, 0xa9e3eb94, 0xc62649fe, 0x7e8d46ed,
+	0x1bface6c, 0xf3d479c5, 0x7d711204, 0x2f485e42, 0x7d01ec15, 0x57d21b15,
+	0x7a9eaeff, 0xe09da7b4, 0x2be83579, 0x24c24f1c, 0x62ef4f9e, 0x77fc08bf,
+	0x93ba7fa7, 0xc467a8bb, 0x529983f9, 0xad7d575a, 0x38673c60, 0x9d12e5da,
+	0xfd1dd683, 0xcfec26bd, 0xb6ec6ef8, 0x76fd04d7, 0xf1a9aebb, 0xfd13c9bb,
+	0x787fe7b9, 0x57f8489e, 0xf548be6a, 0x7b09fac7, 0x215ebd57, 0x7b7fbbfc,
+	0xd12a013f, 0x1209fb88, 0x9827ef22, 0xbda12f59, 0xd827eea4, 0x3b856667,
+	0xab3d7093, 0x73e44fd8, 0xefb41d91, 0x7aad6fd7, 0x7bce893c, 0xa0cc6dc0,
+	0x9f485af7, 0x43fd8157, 0x63ff92f6, 0xe7ad3f1e, 0x1aabb1eb, 0xd496fbb5,
+	0x5f616ceb, 0x50f9858f, 0x77ac459e, 0x91ce2f1d, 0xef21c508, 0x21c78632,
+	0x59304a3d, 0xe3eb475d, 0x5c4d1779, 0x6438bbb2, 0x75a0eb35, 0x9215d5b3,
+	0xb7c3f503, 0x91ec971d, 0xddaf5da5, 0x83cb9327, 0x42496e69, 0x706ad5fb,
+	0xf8bad255, 0x6c7ef817, 0x66fa7c3d, 0x413c7971, 0x331e31e4, 0x6c787a73,
+	0x5bfb4494, 0xe21c1f70, 0xf817b1f9, 0xf2c7973e, 0x35173ef9, 0x5feea16f,
+	0xb79432b9, 0xea6ffda0, 0x1f7517be, 0x780fba8b, 0x00a886d2, 0x99f707da,
+	0x1db8d3ea, 0x3c3a25eb, 0xf3d193dc, 0x6f3f0b28, 0xf8ce3f5d, 0x28c3c2ac,
+	0xf37f0f87, 0xac88d176, 0x25a67108, 0xaffc2fc2, 0x98fb2eac, 0x30bffb54,
+	0xfec6a86b, 0xfedeb2a7, 0x16f2a6ff, 0x6f9f0141, 0x32abde70, 0xe6f8ddbf,
+	0xfc72df67, 0x7b247cfa, 0x4b88b976, 0xd9e7e9e9, 0x68bf552c, 0xbac34bbf,
+	0xfae43fec, 0x8e524ebb, 0x2f6bb9d2, 0x542573f1, 0xcb175a39, 0xe4215ffb,
+	0x547d7aa7, 0x914ceb5c, 0x884f5fe3, 0xe764b3e7, 0x0193a472, 0xc8f1b4db,
+	0x78daf581, 0x098dd5e4, 0x40e0f29a, 0xc17ea686, 0xe79ade81, 0x69578343,
+	0x237f0f9e, 0xd91e535f, 0x7f534a3a, 0xb46387f4, 0x68755ae7, 0x5ed791e3,
+	0x2fb749bc, 0x2bf047d2, 0x6f0dca04, 0xad9d6457, 0xa15997a9, 0x8d56579d,
+	0x96bd5e76, 0x2fcee826, 0x78e6fde1, 0x53ebf3b5, 0x025f9da7, 0xbef2d3e6,
+	0xd4cd3e7e, 0xecf7a153, 0x61b1f7f5, 0x738a07bb, 0xa99f686d, 0xc1db99fb,
+	0x6411786e, 0xffb69fdf, 0x9cd7d696, 0x06eda279, 0x79e6cf3a, 0x0379e199,
+	0x5963dbed, 0xa3e3de80, 0x34162873, 0x661ef4c8, 0x1c9b0c0c, 0x9d1afe76,
+	0xe9f28f4c, 0x911258a9, 0xf8b69e0b, 0x82fda04a, 0xe106275d, 0x7bf692fe,
+	0xfbcb3e78, 0x31f14484, 0x841d6de6, 0x60584bdf, 0xa89dfc8c, 0xbcb8b2d7,
+	0x9a3bbd3b, 0xdb49ebd6, 0xbf52669a, 0x3098b7f5, 0xdbd6a69f, 0xa849fc2f,
+	0x3d3df7c7, 0x5e77d12e, 0x71e17c70, 0x27bbf54d, 0xfae71fa7, 0x89a3416f,
+	0xb059efce, 0x9e3b676d, 0x0de0bd57, 0xe65b9d0b, 0xf48e76d9, 0x3b53d16a,
+	0x469ece08, 0xd5a8bd99, 0x8273da57, 0x5db8f1b7, 0xe9154375, 0xff932841,
+	0xf91f5d55, 0x9dcbecbc, 0xa9f0bb67, 0x00bcbb3d, 0xfccf85c2, 0x1ee30e2e,
+	0xc6b7051f, 0xedbedf91, 0xeee9cf8b, 0xfd702e72, 0x173c2fea, 0x03fc23f8,
+	0x2cc5cbe4, 0xdbcab9dd, 0xa9f7c512, 0xf7c2c302, 0xe8e087f9, 0xf1de78e5,
+	0x6e7823e9, 0x3fa7e9fd, 0x5bc7047e, 0x8f0baff9, 0xadf498fc, 0xc3728ecd,
+	0x3a61c4f3, 0x976d5bf7, 0x40e5cd90, 0xa3bfe3fb, 0xdfdbd2f3, 0xb7b038b4,
+	0x641f3df6, 0xefb77d23, 0xe3052cfc, 0x8cf78b5c, 0xe2f078a3, 0xf0be8b67,
+	0xb7486b7b, 0xe3e17ebe, 0x3e7375f2, 0xcd5f16b1, 0x38d9cd0d, 0x6f8033ce,
+	0x9e75f38c, 0xc55f5cf3, 0xc456cdcf, 0x23dbcef9, 0xe5df8b9f, 0xc986e73c,
+	0xed0f7e37, 0x2e7e069e, 0x75cf65cc, 0xbc78043e, 0x6fe04bfa, 0xbe716afb,
+	0x9dfc6449, 0x4f003fc1, 0xb9ed6c8e, 0xcc369fce, 0xf8d7f47d, 0xdbb121ac,
+	0x5f039d73, 0xb9ea6e02, 0x72ccfffb, 0x3e46ce8e, 0x74f7fa7c, 0xade2368e,
+	0x3a73c144, 0x7f46cd3e, 0x075343ee, 0xb1d72b9d, 0xefc762c7, 0x73d82d37,
+	0xfda7f894, 0x64b71e59, 0x76fbfce2, 0xe7e3f9d6, 0x8a988b95, 0x3f2c4b67,
+	0x1fc05a0f, 0xe2568bcf, 0x1738bee8, 0x7ab1d39a, 0xe777745e, 0xeeca2f44,
+	0xf89cf5cd, 0x96d5401e, 0x9fb99abf, 0x3497c21a, 0x7fe9f682, 0x2adbf9e1,
+	0xbfc2ec1c, 0x96dbc4eb, 0x7771e7c8, 0xf02f8f9e, 0x73c3f885, 0x35cf3a3c,
+	0x5435f287, 0x08b28e96, 0x137da0f2, 0xbdbd2f3f, 0xeea9fd1b, 0xd6caaa0f,
+	0x6798a9f1, 0xf2a1fc77, 0xffc6e5e9, 0x3333e155, 0x8bd0d15b, 0x97d3a70a,
+	0x75f1cb22, 0xb6bfef82, 0x62ece3fd, 0xf48fdcff, 0x66d0d558, 0x44d9fbe6,
+	0xf7cc547e, 0xf4dfd834, 0x6427a4fd, 0xd557e3b2, 0xd71c9337, 0x6eea8bcb,
+	0xb39b6df2, 0x7153bac5, 0xa7e9c14e, 0xefb87d63, 0xdddef4ea, 0xf6effd7c,
+	0xfa17b336, 0x19edbfdb, 0x721b8f33, 0xe13d41fe, 0xe9ff1b0b, 0x91069b27,
+	0xdd66eedc, 0x8f78bd77, 0x3df91fc7, 0x34e7ed9e, 0xade859ef, 0x72efff27,
+	0xe8c8fbef, 0xfbfb05bc, 0x3bf7c828, 0x4ffb847e, 0x17ffbc23, 0x176126d9,
+	0x22eb13ae, 0x3f03de41, 0x9ee02bbf, 0x3cf5cbd6, 0x9d1999c2, 0xe3be1083,
+	0x2725917e, 0xaf979f01, 0x7fa8ec95, 0x4c18af67, 0x9ccf9274, 0x89652744,
+	0xfa937bfc, 0xe6cf1cf7, 0x1ab6fc7a, 0xc3fa4313, 0x280cded3, 0xb624eb7f,
+	0x3197fb86, 0xe7425313, 0x6ead56d1, 0x0abc2389, 0xef3d533f, 0x3e66a2b6,
+	0x39fd07c9, 0xdeac9538, 0x2d6fe78c, 0x2dcfcb58, 0xa38b9fd4, 0xcf5dab97,
+	0x85fb5a89, 0x956df672, 0x81cc1cef, 0x07e7377c, 0xd7e456b1, 0x4a68f0ae,
+	0xb3ca05be, 0x07a4c80f, 0x2eb0b854, 0xebcbfddf, 0x7f3cf881, 0x973f2fa0,
+	0xb152515c, 0x3c1e9cde, 0xdd19282e, 0x597ef1c3, 0x19b87ba2, 0xb19beae5,
+	0xb596c7b8, 0x7c50345d, 0x36595980, 0x59d9938e, 0x537db876, 0x60a7b26e,
+	0x16cbc4de, 0x58fc51a5, 0xeb0addff, 0x1eff20da, 0x157bf683, 0x5f9c8965,
+	0xeff3763a, 0x1e46b1ef, 0xeb32b6bf, 0x9c778c32, 0xe0a5d652, 0x95ae5411,
+	0xc53dfe26, 0x4714f1ed, 0x91456db8, 0xba5fcf19, 0xf69e21ad, 0x93af30b5,
+	0xe2a8cfbe, 0xc1456db1, 0xf7e834fe, 0x871cfab6, 0x269fc5ac, 0xaea0bc1e,
+	0xc9dbc54d, 0x64ede0cb, 0xbe01bc24, 0x7a13f734, 0xeec5f169, 0xe94cf6e6,
+	0x62fafb1d, 0x0d7ceefe, 0x77631eff, 0x340e92f2, 0x35c5094a, 0xe33a338b,
+	0xef4829b5, 0x250ed617, 0x55f1e9bc, 0xc3d9affc, 0x7b337f71, 0x05ce962b,
+	0x66c3eb2e, 0x6ff184dd, 0xd953f389, 0xa316262f, 0x8bd01ade, 0xb56bfdf3,
+	0x82d9fe3c, 0x787ecff1, 0xca9dba6e, 0xf3fc4587, 0xe13fc628, 0x3fc626fa,
+	0x7c527ae1, 0x33e5433f, 0xd7a20020, 0x7f38bdc1, 0x8925ee0d, 0x34e2ddf8,
+	0xff8a4bb4, 0x73f38b25, 0x61637d7e, 0xce878d0c, 0xa3fef9cb, 0x7bd1bebf,
+	0x3a37630d, 0x69b4f1b5, 0xb4f1b453, 0x663915f2, 0x736fd7f4, 0xa3d4d68d,
+	0x0f5abc88, 0x925e98ba, 0x337e79a8, 0xbfcc34be, 0xf0a5ee2f, 0x1f7147f8,
+	0x4b5bbd4d, 0x2a5bdfb5, 0xb3c668bf, 0x62dbd985, 0x26b3309f, 0x87bfc219,
+	0xf1ca4402, 0x3e6de762, 0x416e3a31, 0x60e4fc7a, 0x5e7284b2, 0xaf150f8f,
+	0x080037b3, 0x1b39dfa0, 0xbd97940c, 0x55e3b66b, 0xaeeccf3c, 0x7bf7f8a7,
+	0x467bae4e, 0x39805df3, 0xbf84994f, 0xa1fb2763, 0xf232c568, 0x607dca3b,
+	0xcb88022f, 0xa23ef45f, 0x467e3196, 0x0f91594b, 0x80bec90e, 0xe2727844,
+	0x4fbd83f7, 0x7e47eff0, 0x0ed86208, 0x2b7677fa, 0x1287c71f, 0x53e5815b,
+	0xfdfbb7b6, 0x6675e600, 0x0679bae2, 0x307c8dc4, 0xd3e2e499, 0x2cfa4332,
+	0xe744c3bd, 0x587ede39, 0x31f4efa6, 0xc5533f29, 0xd9cbe62b, 0x1dfe1613,
+	0x04a00e9b, 0x71f8b7a8, 0x8f9f7d0b, 0xcfcb0328, 0x11adf40e, 0xf2f48874,
+	0xc6733c61, 0xfe7960d3, 0x6496a3e0, 0x82119f5a, 0xce106f9b, 0xfae09bd7,
+	0xa3a02f51, 0x06f9e68f, 0x3bbafc91, 0x0f47f899, 0x2e6693df, 0xef48bc9f,
+	0xea2e4852, 0x26d996ed, 0xc7df7d07, 0xa3a486cb, 0x96b93a5c, 0xf40f477f,
+	0x3f5f1c4a, 0xabd134f3, 0x46939efa, 0xef8e3c65, 0xe90e5d64, 0x0ad6dbaf,
+	0x06f4137f, 0xfae3efaf, 0x46ecbd6a, 0x275bc3bb, 0xaf9db9b9, 0x4db78fa5,
+	0x688b9ede, 0xd68db1fd, 0x6809dcaf, 0x9dca3cc5, 0x2ec9533b, 0x5bec2998,
+	0x2ddbc696, 0x3b3a73b6, 0x0f4fa07f, 0xea7ad7dc, 0xea01e010, 0x75f3a7b4,
+	0xacc6a705, 0x3747861b, 0x1dec369d, 0xffb803f6, 0xfbef44f1, 0xc8dbc046,
+	0x5ee6f76c, 0xac329f18, 0x4473c6cd, 0xfc4fface, 0xf50fbf1c, 0x83930ed1,
+	0x97e974d8, 0x0c4ed3b3, 0xeb835d8d, 0xf2eb67c2, 0x3f042704, 0x5bf8293c,
+	0x8b6fcfd5, 0xa7036cf2, 0x2482f63f, 0x34c46bbe, 0x9e217872, 0xe4872a43,
+	0x2b872aa5, 0xc7fadd85, 0x3e6edc5e, 0x60a5d6c5, 0x4fa005bd, 0x3b3cfef1,
+	0xb72a4bb7, 0x7ee7eff1, 0x4c9c7c84, 0xf5c31a7d, 0xe4167cf2, 0xea014e7a,
+	0x77dd0949, 0xc0388b45, 0x409fbe3a, 0xb9e7f72f, 0xe06ffb7d, 0xa3003bfd,
+	0x7cffe45d, 0x8f1b1ae6, 0x3c6deb71, 0xff97ac9e, 0xb9b7e84c, 0x3d7a7de2,
+	0xbbe85730, 0x377d3ab9, 0xce8e71cf, 0x0edca91d, 0xb2b945ef, 0xc2efab4e,
+	0x9a44a9e6, 0x872f3ce7, 0x873f3cf7, 0x769d7bcb, 0x08fda30d, 0x3d59dc2a,
+	0x77b4d3fc, 0x791c61c5, 0xc33283fe, 0x78aa1cef, 0x823e66a8, 0xb02cc7f7,
+	0x8f18ed0a, 0x062e31bc, 0xa1f0ba70, 0x2dc7ecbf, 0xa06b944a, 0x7efef3f3,
+	0x9427b3bf, 0xa4b2f37b, 0x6f7efdfc, 0xd570aecf, 0x829bf1c3, 0x6ef9131b,
+	0x9863076a, 0x377f85bb, 0xc91eac3a, 0x0901fffb, 0x00d0a8f5, 0x0000d0a8,
+	0x00088b1f, 0x00000000, 0x3bedff00, 0xe5557469, 0x73dcfbb5, 0xe1dc8487,
+	0xc2040464, 0xc06e49b9, 0x612f4865, 0x1213d41e, 0xde0d4b22, 0x00c10580,
+	0x86120137, 0x7c07504c, 0x0040e3e2, 0xaa1a4583, 0xf50af8a5, 0x22d28342,
+	0xb04a0834, 0xc141170c, 0xd6de8ba7, 0xa44f7d6a, 0x40932861, 0xd2bb6a52,
+	0xf7b79457, 0x3b939df7, 0xed83a404, 0x58b593af, 0x9ef37efb, 0x77f7bdbf,
+	0x52015000, 0xaaa8e601, 0xd08eceb5, 0x092bd00c, 0x72c06e60, 0xd80e35b6,
+	0x37fc0ddf, 0xbb746b7f, 0x01e5e696, 0xf7473754, 0xa41c5fe3, 0xbfe6cc01,
+	0xff5616a1, 0xd845cc41, 0x766f3d12, 0xe890eadc, 0x556679a4, 0x086e17eb,
+	0xa1e6ca0c, 0x840cfada, 0x9f12a24d, 0x6e0f351b, 0xca7a01b8, 0x7773948e,
+	0xde0bc361, 0xc5c2221b, 0x002300c9, 0x5c78174a, 0x439c1cfe, 0x2186f77f,
+	0xb09e7468, 0x39cd23c0, 0x098a6584, 0x68c79cf0, 0xb1c6994f, 0x477f788d,
+	0x617c67e2, 0xc1864ef6, 0x15483f08, 0x3a6f3c54, 0xeba236e1, 0x71eb15be,
+	0xdf8841e7, 0x11f8137a, 0xcbbf5b9e, 0xfe3e47e9, 0x695dc5fe, 0x88772b04,
+	0x66084410, 0xdcf015bf, 0x2f65f582, 0x56fb833f, 0xdaf78d6c, 0x88e2bbb0,
+	0x3c7008bf, 0x252b7c0f, 0xe3d7971c, 0xe070c341, 0x71dd8445, 0x8428f23d,
+	0xdfd982fd, 0x513de68f, 0xd927efe1, 0xd187faa3, 0xf4cc4fbe, 0xee3f7cff,
+	0x04b6c4fb, 0x9248caaf, 0x44e1a682, 0x84041489, 0x7b7f0bd5, 0x04fc8cd2,
+	0x9e8f83f1, 0xf2b8014a, 0xb6c408ba, 0x817f24ec, 0xcfdc4a9c, 0x703d05eb,
+	0x5d29b89e, 0x22f6c4ca, 0xeff9ecec, 0x8d4ce7e7, 0x4fc4e59f, 0xd599e914,
+	0xf3a50e1f, 0xbe70374f, 0x4d99face, 0xf397a7e3, 0xe7e73573, 0x339f8d4c,
+	0x7e35788f, 0x4f892bca, 0x9f8d6af2, 0xeace1c0d, 0x3a7537c2, 0x4fc4f5e1,
+	0xa7155e6c, 0xa60f885c, 0x173f909a, 0x4f508a76, 0x12a80b6d, 0x4485c3da,
+	0xdf511250, 0x3f8d04ff, 0x7e610a0e, 0xe50ecdce, 0xd29e9106, 0xc49d47b5,
+	0x453bb9d7, 0x3f2c704e, 0x73eee941, 0xc81f9e44, 0x24d53c25, 0x087942df,
+	0x408aa5c0, 0xb7fbe12e, 0x825a7df2, 0x79e3e522, 0xde2dfbed, 0x36efc8cd,
+	0x85c01587, 0x8384f676, 0x227265c1, 0x3a81679b, 0x505f3c00, 0xf8845814,
+	0xdd3e50db, 0xb2159e90, 0x5905c6cc, 0x87ec5282, 0x7e13200d, 0x24288282,
+	0x1d2fed75, 0x3e462283, 0x814c3bb5, 0x67ff48cd, 0x3c80d0d6, 0xffaf187b,
+	0xe913b192, 0x03c835f8, 0xd252bce8, 0xccafc235, 0xfc8cd815, 0x6c4c0879,
+	0x0cc087df, 0x982708a5, 0xd8713541, 0xba224f60, 0x3fa85990, 0xf1bf35e3,
+	0x7410e1ed, 0xef82af21, 0x3fae7081, 0x73a55d30, 0xc14d0726, 0x1e0fe87e,
+	0x090f0732, 0xb2714d08, 0x7c73c245, 0x913c84e3, 0x660cb0e4, 0xf15decf8,
+	0x21f846db, 0x1326a5bd, 0x8129ebc7, 0x0a28f1d1, 0xdd32f89d, 0x8444470c,
+	0x4439e28f, 0x5904b4f7, 0x0816f365, 0xa30ccdde, 0x54df8614, 0x2881bf0d,
+	0x4bc87387, 0x0df76ddc, 0x3547d3d4, 0x069f707c, 0xf1cf5b27, 0x1edf9588,
+	0xad004f8d, 0xcd6be256, 0x227fef63, 0x71359d20, 0x49f920f6, 0x6e5cb168,
+	0x39f9afed, 0x48afe1e4, 0xc05f384e, 0xf4f90083, 0x04db06a8, 0xb87b3bb4,
+	0x1e0d21ff, 0xa5ace8d7, 0xde0bca36, 0xdc5b0212, 0x03e73fb7, 0xd3ad8939,
+	0x3b0347f7, 0x1026e34d, 0xed6bfc80, 0xb2562dfe, 0xbf5a79bf, 0xb22187ee,
+	0x5dacde2d, 0x169f912a, 0x41ba6fc0, 0x8b3edad0, 0x13dc2958, 0x7afb25ef,
+	0xa1ecdad4, 0x5e76277b, 0x5874df2c, 0xef53805c, 0x3e75f9a0, 0x03c03465,
+	0x0bdbd3df, 0xcbda0a7c, 0xe39de1a4, 0x8e164a8d, 0x8e7f177f, 0x7828e864,
+	0x452fc133, 0xd7253ede, 0xfce39685, 0x8a728f0a, 0xdcd39ffc, 0xa0fecc0a,
+	0x58bbf191, 0x28061324, 0x28a37d1c, 0xb858f911, 0x6c9e605b, 0xe636e8ea,
+	0x50f13a77, 0xd478619f, 0x76f413ec, 0x71bbc148, 0x36ceeeea, 0xb070a3c3,
+	0xf27c6a2b, 0x9f1a8868, 0x1be91d78, 0x6a71b5a9, 0xd194f488, 0x4a8d9ff1,
+	0x235b6c6f, 0x42dae3e6, 0x4ba74f3a, 0x65ffef0e, 0x835f19e0, 0x9d75d199,
+	0xcc5075f9, 0xba6101be, 0x91df665c, 0x5dff223f, 0xe2a48229, 0xfc5f1aba,
+	0x6117f26a, 0x3d181a7a, 0x8f9d78a1, 0xf1a37cd1, 0x06bfa442, 0x8d55f1f4,
+	0x67cdf20a, 0xd2af9cea, 0x3f3ab1fc, 0x337f7d70, 0x7d6c4973, 0x4686a6d2,
+	0x9fa61ed5, 0xbe18b3b5, 0x7c21ee49, 0x295fd339, 0xc42f48ff, 0x4ef906b3,
+	0x5ca74557, 0x5f8c75d5, 0x6d1131a1, 0xa62337c2, 0xff022ddd, 0x52fc11de,
+	0x59f949d7, 0x7cd2f811, 0x8b4a67c4, 0x127fbd10, 0xb4ddcf1f, 0x1d1d51ae,
+	0x90fc036e, 0x5e8227f1, 0x9d299fc6, 0x9be75ef2, 0x6ac7eb85, 0xfee019fc,
+	0x45e88fa1, 0x7d3972fa, 0xd2fd2881, 0x65bcaef5, 0x14b48aed, 0x2004b38a,
+	0x68f2c37a, 0xe7fc91f2, 0x9bff3a4b, 0x586f8442, 0xa13dbc1e, 0xa9bf3f59,
+	0x64abf491, 0x6f2f4eb7, 0xf70bf587, 0xbff216fb, 0xea7c7a21, 0x53f5e8f2,
+	0x667f73a0, 0xf53a5357, 0xfa43cf17, 0xbcfc69e6, 0x4853537f, 0xbf76fae5,
+	0x67ac353b, 0xad12b365, 0xed85bf74, 0x6be31b71, 0x93b8de27, 0xbc0fe380,
+	0x07c7cd1f, 0xb27b79ea, 0xc1af9b7b, 0x4d7ed91e, 0x7764e3e7, 0x7d72bd94,
+	0xc4fd1df9, 0x4024f37b, 0x161fbd94, 0x4487dba3, 0x437baf9d, 0xa750e58f,
+	0x1f5efe7e, 0xfc0fb7dd, 0x719f1a30, 0xc7bdbd36, 0x6fe91857, 0x5f1937d4,
+	0xf9f4fc74, 0xd7a25f45, 0xddaaf3c3, 0x729afa6f, 0x320cdee8, 0xc49a56ff,
+	0x71c75c21, 0xb56a47bc, 0xbf68a938, 0xbcd00be8, 0xc2cf416e, 0x873d309c,
+	0xff99169e, 0x8085eb56, 0x196cfd07, 0x04ba56c8, 0xa5628267, 0xcb90f5fb,
+	0x9c15e8b5, 0x7169f87f, 0x3df70051, 0xc59928b9, 0xadb81f9b, 0x5d87ff8c,
+	0x6366d37d, 0x0cc250fb, 0x0ef38cab, 0xc1963b3d, 0x7fe93bb7, 0x337a47d7,
+	0xc9a5ce2b, 0x97e65df9, 0xf6f0250e, 0xbedbf72a, 0xd5af28a5, 0xe7ed996e,
+	0x5ad2924f, 0x39e13f50, 0x09916c0b, 0x098fef4f, 0x6de7b2bf, 0xfc239f03,
+	0x4695de96, 0x41ff2ef2, 0x9c4f5149, 0xe2c2be57, 0xab5e7015, 0x7c274a49,
+	0x658dcffd, 0xb96b30fa, 0x18fbd506, 0x4fd5f83c, 0xcf749dea, 0x1c58146e,
+	0xcd17f773, 0xbb62e7ef, 0x4bd321b2, 0x30e81ea8, 0x9ce78481, 0x202fdf5e,
+	0x899dcaa2, 0x3c777baf, 0xbf340f9f, 0x7c7cbaf2, 0x2f9a60fc, 0xfe70cb4a,
+	0x7017ec39, 0x712adcfc, 0x397840b3, 0x2404dd1d, 0xc097dce9, 0x2b73f0ae,
+	0xb865816c, 0x7fbb69cf, 0x673a7afa, 0xd29605bd, 0x93d7413a, 0x4e5f198f,
+	0x3f5cba4b, 0xa1cfcc6e, 0x2dbd3679, 0xca9f2195, 0x157a9d4c, 0x2aefbc04,
+	0xb5fb7912, 0xb6f91f4d, 0x2f73fae0, 0xaaf163f5, 0x276ca19c, 0xa19d3d7d,
+	0x3ffb20ec, 0x462ed5f8, 0x3c4bfb5f, 0x51d03b6e, 0x111e569e, 0x315c5427,
+	0x68387d33, 0x7c231f95, 0x23eb760f, 0x6a2f2ca8, 0xf8a12e4e, 0xe28cf511,
+	0x45ebd46d, 0x1f126ebb, 0x2645ba36, 0x4ddf43af, 0xea472d1d, 0xf9867ab7,
+	0xde64e289, 0x6d6eea3e, 0x9cafd154, 0x33822db5, 0xfaf5e159, 0xe8aef9fe,
+	0x39983938, 0x81d128e1, 0xca30c679, 0xeb7cf453, 0x0733f533, 0xf533f1c9,
+	0xe3630653, 0x43a74ad4, 0xde7fe725, 0x1c9330e1, 0x9c979a4e, 0x62b938a3,
+	0xb9f985a3, 0x8ba98d8a, 0x414e29db, 0x5740f17d, 0x2c32927a, 0xda5b9e8c,
+	0x2beedaa5, 0x07191dec, 0x5dad7fb4, 0xf36a6eb6, 0x6d6fd935, 0x5b129597,
+	0x2d1b4503, 0xcaabb23e, 0xa0330e21, 0xf1b31cbf, 0xefa42d9d, 0xf3e20b95,
+	0xe578886c, 0x53931b46, 0x4aa1c3ab, 0x3a77ee38, 0xaf0889cc, 0x6e8c4dba,
+	0x60cc8657, 0xb8e60881, 0x5397063c, 0xf10d711e, 0xc5f6c649, 0xa3ac2f45,
+	0x0412e4b4, 0x3d430d26, 0xfd70a6bd, 0x0c5bb6bc, 0x66047e50, 0xf98c5cc5,
+	0x7ee01cd3, 0x5dbdfaa2, 0x39fc7cd6, 0x41f2aea7, 0xf9f965c8, 0xfcfc98e9,
+	0x8e1e7474, 0xfe51a61b, 0x30aaffcd, 0xc43b24de, 0x5e6a3d7c, 0xd51e7e44,
+	0xf2d0c96f, 0xa3c83ceb, 0x9d5aee38, 0xdd829b25, 0x13da3b4a, 0x41b059d2,
+	0x2e56f860, 0xc4360312, 0xe79920b7, 0xa0976747, 0x5e8caddc, 0x2576c255,
+	0x37c4b1e5, 0xf8710210, 0x0b0dbef3, 0x1767e4cc, 0x4ca57e6b, 0xdbe91f00,
+	0xfa6f7899, 0x36c78a02, 0x56be33c6, 0xc7ee78fe, 0xd6bae12f, 0xa229c5a5,
+	0x5e87d61c, 0xfee03e9a, 0xde149710, 0x67d2fce7, 0x0bdf49d2, 0x4857ee5e,
+	0x22657871, 0x26e298ec, 0x974cf539, 0x9579e1ed, 0xe6ce9ecb, 0x8083e2f3,
+	0x2ad970f1, 0x6f01d191, 0x521e02d8, 0x4520fec8, 0xf2d66df2, 0x1cd6acf7,
+	0xd34a5bfe, 0xfc991ee2, 0x9c5faf37, 0xced171c6, 0xc676a7f8, 0x066ff8bd,
+	0xf993d5ed, 0x57d13f09, 0x4c66126a, 0x5bb4fb60, 0x328b8ec9, 0xb7701e78,
+	0xbdd2cb06, 0xea8f09d3, 0x32ef3635, 0x1c47df37, 0xb181e1aa, 0x5429b54d,
+	0xf3c223f1, 0x0b779b4d, 0xbc796dc9, 0xb924ef12, 0x0e7af282, 0xad98c7ab,
+	0xa72fb449, 0x76e64ab3, 0x989ffd8c, 0xc1dabfb1, 0x227560fd, 0x15cedbf2,
+	0xb7fb84c4, 0xbe4cafd1, 0xf0dccf5f, 0x85f3cefa, 0xb99df8f0, 0x49e4afc4,
+	0xdb1e108f, 0xc8af6645, 0x29c3358c, 0x0e2ed96e, 0xf1a64e7a, 0x57e445c3,
+	0xc81cefe7, 0x1db2b6e2, 0x617bb21f, 0x56e726be, 0xc7296f2d, 0x33844ef6,
+	0xf8bdb832, 0x666ba845, 0xe8bf9e6d, 0xabc7d6f2, 0x9c985957, 0x937fd1aa,
+	0xfa5ea8e3, 0xb56fb65b, 0x79469423, 0x961bf556, 0xcb6fe4a1, 0x97cbfc35,
+	0x09fd19f6, 0xc5b94fea, 0x543dd125, 0xa95b16a5, 0xb028d55d, 0x6a5d7876,
+	0xe7e3e93a, 0x4938f7cb, 0x07c4ce4f, 0xb4df743d, 0x52f7882f, 0xc0da887e,
+	0x97cf93ee, 0x873f367b, 0xc85259ed, 0xacf8e021, 0xc89332c7, 0x82949f2f,
+	0xd93f1a56, 0x5b5136ec, 0xd4d1a491, 0x62dfcc56, 0x55d1cfed, 0x43fa6b35,
+	0xe046a5fe, 0xed7aacf2, 0xcf0335b0, 0xffc9a95b, 0xb30ff6ca, 0xa756cfc9,
+	0x397db287, 0x14d9de4c, 0x04cfc2ff, 0xbcd6df76, 0xba60ebc6, 0xde486bbc,
+	0x34f35f68, 0xdeecd739, 0x7de924f3, 0xaf3bc90d, 0xdea0beab, 0xaffd611e,
+	0xbe022a6f, 0xc5e908fe, 0x53cc7899, 0x05b97b79, 0xbcacc7db, 0xbfe6acfd,
+	0xf790bfb0, 0x4f3c39ab, 0xac6b79e3, 0xbe4adfbe, 0x263f244d, 0xa7f31b0f,
+	0xadbd1a4d, 0x9270deab, 0x3f6caefc, 0xc1c8eefc, 0x57e61784, 0x5ef44df2,
+	0xd12d47e3, 0xb3f864ef, 0xe896a1b8, 0xefe98675, 0xdecd73d4, 0xa7d3816a,
+	0xd66b5bd3, 0xb5c7d7e8, 0x3a345bf5, 0xd7e340ab, 0xbedc7eee, 0x7b227b34,
+	0xa749fca5, 0xd7c49fcf, 0xbef9faeb, 0x4d6edf46, 0x766a414f, 0xbe487f12,
+	0x7f5067e4, 0xcd50eb14, 0x2b94e06f, 0xfcb1373b, 0x8e979751, 0xfbe1a7ff,
+	0x0a4c4942, 0x04d5b1cb, 0x5ded9a73, 0x1a23c5ef, 0xe8ad4f1f, 0xfc82de9e,
+	0x06f31cfb, 0xbea36e96, 0xd3ce239a, 0xaf3f46f5, 0xfdc95b60, 0x86600eac,
+	0x9fafed20, 0x304d527b, 0x81273ed3, 0xbf8e87db, 0xf505976e, 0xe81feed3,
+	0x1c5779a4, 0x37443999, 0x0cd3ff3f, 0x5457ad89, 0x4af3f307, 0x7010108b,
+	0xebc094e8, 0xec56a782, 0x84e79671, 0x327ffdf5, 0x62ff4e84, 0xa78aeb4e,
+	0xfa117fae, 0x782cf0cc, 0xd4fdf276, 0x7a16f4fe, 0xd74df3a9, 0xca9c584f,
+	0x3d5893e2, 0xca7dedad, 0xf6c5e74a, 0x19caf1eb, 0xfec97bca, 0x10faf2f7,
+	0x5923872c, 0xeeb0f711, 0x0ecff1d7, 0x84f7c343, 0x65e72f7e, 0x2efa3066,
+	0x1f35b341, 0x85d578fd, 0xa6539150, 0xf5644fb8, 0x08bfbba0, 0xb3d42e8a,
+	0xbceeddaa, 0xeaad7bc8, 0xa7a611f2, 0x756210d5, 0x1f55b2cb, 0x7d230f16,
+	0x45c629fc, 0x8c5757e4, 0x3d5c52b5, 0xa1cccb77, 0x0dd3e724, 0xb8badefc,
+	0x142bc87c, 0x786e9f17, 0x0e666d21, 0x1a282bad, 0x6b65fd89, 0x9e393207,
+	0x53150f89, 0x1171fdbb, 0x6a358ea8, 0x53c590cb, 0xd1ca3db1, 0x39e89137,
+	0x8e1624d9, 0x2cfb908c, 0xa54f1690, 0x92eccc78, 0x6a4e0ec8, 0xc2deabfe,
+	0x933bd2e5, 0x277279eb, 0xa0bafee4, 0x44db3ebe, 0x7e84db7c, 0xc5aee913,
+	0xd507a018, 0xff1e054d, 0x5c42b1cc, 0x1fd63ccf, 0x4dfb13d7, 0x09aa2709,
+	0x13c7b6ff, 0x4ddbaa24, 0x883781b3, 0xfb0769ed, 0xa6e851e4, 0xc6287168,
+	0x9d5cecab, 0xbdf9fa4f, 0xc51eb932, 0xf5e20bee, 0xc76fa4a1, 0x19d63ab4,
+	0xcb8bef0d, 0xee893a7f, 0x3d5b8ba5, 0xf9f74449, 0x140df1fd, 0x70b79cc7,
+	0x7fefa57f, 0xd88f77bb, 0x77d88ef7, 0x0c65800d, 0x189901af, 0x6740253f,
+	0xe3eba4fc, 0x70baeaed, 0xcdd78d22, 0xfaf53db5, 0x5ecd1ffa, 0xd64de257,
+	0x12f2f0e9, 0xce365864, 0x9e083aa3, 0xe5f0985f, 0xd9c510ae, 0x86c9368d,
+	0xbd259ef4, 0x86fab6c6, 0x1481eac8, 0x9f9e9313, 0x8050637d, 0x138ab7f2,
+	0x2cd15dbc, 0x7884a804, 0x22b3ed64, 0x718d9fcd, 0x2221775e, 0xed717d6e,
+	0x6bff5224, 0x9ecaff5e, 0x56daff38, 0xe037bd81, 0x5e263db0, 0xfca7b77d,
+	0xf5578bef, 0xe754bffc, 0xa42ef6bb, 0x57cf5bf3, 0x0c5ea20e, 0xedf30bcf,
+	0x2c3992ea, 0xc4bcbd5e, 0x709b60cf, 0x5628cd6a, 0xbab176e7, 0x5e5a2fef,
+	0xdc917b10, 0x4ebc0f77, 0xbb48e779, 0xbdbb224b, 0x401164ba, 0x63abad36,
+	0x5ebb9750, 0xf77bb9df, 0x6aeeb621, 0xa37da0cb, 0xbb01dd70, 0xcee7f98b,
+	0xf79892f7, 0xbc58ef91, 0x7dd913dd, 0x7451dfc1, 0xd772ebf9, 0xded4abe9,
+	0x2ffc7445, 0xdee5c53d, 0xd33aded9, 0xfa1ef449, 0x11bef251, 0x9704ef24,
+	0xb9da7144, 0x5c5fdcf5, 0xf2bd7388, 0xc2fbca20, 0x80698986, 0xa1f6727e,
+	0x7f512787, 0xa2417ec5, 0xbfbbdcf8, 0xd3f949c4, 0x4eadcdef, 0xbf7ef3ca,
+	0x0abf7f5e, 0x469fe488, 0x3489838e, 0x0cd0647f, 0xe233ee32, 0x2337ae41,
+	0x0a039b2e, 0xcfd83bc5, 0xbbd716ea, 0xfe05bab1, 0xfde09725, 0xaf2f7b39,
+	0xd072e873, 0x1a51adf3, 0x9333079d, 0xfeb4ff38, 0xffbce182, 0xe35d86fc,
+	0x4d8bbf69, 0xbef08916, 0xfb6164da, 0xc93cc3cf, 0x5b33ef44, 0xed421e79,
+	0x37d93778, 0x35e637cf, 0x7aa37cf3, 0xbab14581, 0x4167eaba, 0xe7ca3cc4,
+	0x73a64fb0, 0xa7fa6ae7, 0x853cedeb, 0xef0f37d3, 0x5637a235, 0x99a1138f,
+	0x4edddbbd, 0x3d56ff9f, 0x37e31dde, 0xa982584e, 0xef9f8993, 0x77565e89,
+	0xe87e85b9, 0x403f257c, 0xc3ebac7a, 0x0517d43c, 0x079a9287, 0xea3e93e6,
+	0x9bfba1fa, 0xa5e35bf9, 0x2dfe51b3, 0xdb5daa31, 0x1b3a53d2, 0x7a69e719,
+	0x99823908, 0xe9d2abe8, 0x535d6b8b, 0xf8a6b082, 0xc421150f, 0xafe88473,
+	0x9152a4f0, 0xc05e8bef, 0xc69ed964, 0x642091de, 0x061ef601, 0x6a17ff4c,
+	0xa2b1b075, 0xe519bfbd, 0xf3742a58, 0x96d93e52, 0x2e4d50ef, 0xf9327796,
+	0x04253e96, 0xc44ffb00, 0x9ea9733b, 0x0e420330, 0xbb3fb637, 0x464d7643,
+	0xf5ebd5f9, 0x2d63b56a, 0xe65767d5, 0xfffb5a8b, 0x3aa8944a, 0x8afdffc8,
+	0x530f20ea, 0xffb5943d, 0xf6f5425a, 0x71b477b6, 0xe3425eb8, 0xab402b6d,
+	0xdbc57d8b, 0x85c7d03f, 0xdb5fb409, 0xe45c7d2a, 0xfdf5e7ed, 0x98daf6b5,
+	0xe331a5f1, 0x1ff6f12f, 0x504e227e, 0x88f5c273, 0x9ef7b527, 0x7d5a65d2,
+	0x8336f4c2, 0x93df2cf6, 0x1d17cf54, 0xe7941d67, 0x27947914, 0x7bf0dde9,
+	0xcd7ffd7d, 0x44af3844, 0x9f78ad50, 0xd9026fc1, 0xda75e7c4, 0xe1ffdd7c,
+	0xc9bac83c, 0x6f3439bc, 0xcb3cd448, 0xda7de6cd, 0x376ebf75, 0x89e2979b,
+	0xe77f4fde, 0x9c56e29d, 0x278f5f34, 0x94afef62, 0x8c471e2c, 0x699254ca,
+	0xb40b239e, 0xe9bc42b8, 0x16615a3b, 0xbb4a038f, 0x99b677f1, 0x32711d43,
+	0x37e431e2, 0xf9077afe, 0xbe3c0db3, 0x98efb57a, 0xf41fb43e, 0xc757be8e,
+	0xcc43ef21, 0x3cb3b5af, 0x86fb8ff2, 0xd1bfc8b8, 0xebaf24db, 0xea9f7da5,
+	0x759dc5ee, 0x67dfbea6, 0xacb74def, 0x409df543, 0x5f71a875, 0x66f3bd71,
+	0xc93efcf5, 0x01b0da75, 0xb48fc8dd, 0x25effba4, 0xbb0da63c, 0xf9da88bb,
+	0xaef662b6, 0xefafa3dd, 0x6b3fea1e, 0xa1089e52, 0x6346fb3e, 0x7f611b20,
+	0xa2130a13, 0x983f0fda, 0x3d844a0c, 0x57b87a4e, 0xd291fb54, 0x53f9a8cc,
+	0x3515dd67, 0x0d0b6c5e, 0xf69c7966, 0x78ab7cce, 0xc61df3a2, 0x9f3debc1,
+	0xc7d3fbed, 0x6a1fa28f, 0x5d59126b, 0x2dfeee77, 0x70828f1f, 0xec46805c,
+	0x74bdfb22, 0x93ca044c, 0x5757eb63, 0xb46eb420, 0x80f135f0, 0xe5c58474,
+	0x8d1fa8ff, 0xc6a34bc8, 0xfb4567a7, 0x1f756bd3, 0x23180ba5, 0xac7568d5,
+	0x594f7b2b, 0xbbff5e65, 0xeafd0371, 0xde90b47d, 0xfe903b3b, 0x2d7fa841,
+	0x38adaca7, 0xe64b23de, 0x05ef4779, 0xe5007966, 0x4acc0b11, 0xa1171e84,
+	0xbea8b81d, 0xde3f71d2, 0x83474878, 0x74d7d6c2, 0xb8bb5898, 0x5465b4d7,
+	0xc336aa6f, 0xc754dd80, 0x6e2c1d90, 0x7df9fe2a, 0x67e580e3, 0x63f74282,
+	0xe7c2a355, 0x4c1ebf8b, 0x1db1b0f5, 0xc53ed8e3, 0x50131c22, 0xe0281f37,
+	0x31d5d17e, 0x76d7f581, 0x6e0f9b00, 0x54ace2ff, 0x7144aefe, 0x29aefe6f,
+	0x72888985, 0x86795bb2, 0x2297ebf4, 0xfbbb222c, 0x86f7bde5, 0x5f7a1494,
+	0x32283418, 0xc59358ff, 0x6a400ddf, 0x5df74ebf, 0x990481ed, 0xc5eac8e4,
+	0xb7ed0f14, 0xec7c77b1, 0xda90f567, 0x94cdb603, 0xdb3ad5e7, 0x0afec9b3,
+	0x8907c60e, 0xe307438e, 0xcdbf2ccd, 0x73a1aff4, 0x2bf60e0b, 0xd9537ca4,
+	0xf3033367, 0x98f7ca63, 0xca589e3d, 0xd25d3ae4, 0xea37fb04, 0xbfbf6c63,
+	0x4cabf381, 0x872ebbe3, 0x7eef8d72, 0x1a659f8d, 0xdf1067df, 0xc5f2ee91,
+	0x587b6fc8, 0x29a2c52e, 0xb260fd7b, 0xca5e3e8f, 0x15bf743f, 0x8eaaf7cb,
+	0xeaf7c638, 0x7c9a1e8e, 0xa1c945bb, 0xb58323bc, 0xdb7dba07, 0x7ae2ce89,
+	0x5fee2f94, 0x287a0f6e, 0x17519a3f, 0x87f7a5ef, 0x45dd8b6b, 0xab85d7c4,
+	0xfee6e1b0, 0x8ab5ee8b, 0x74add4df, 0x4a65c844, 0xb8c82e47, 0x2c8ec4df,
+	0xebed5f06, 0x2e724bdf, 0xcecf18eb, 0x66c8ef29, 0xa95c62e7, 0x23fef8b0,
+	0xfbffbe3d, 0x20b9c7be, 0x21811b30, 0x75dfca8a, 0x26ef3602, 0xcbfdfc21,
+	0x54238c4c, 0x1696673c, 0x5b650e7f, 0x6c9b7f22, 0xf8424381, 0x72ff18fb,
+	0x9da86a91, 0x3be5d7f6, 0x678c7c99, 0x26e5dd70, 0xd543930b, 0x950f5fa1,
+	0x9092fc70, 0x4eec9ddf, 0xc47ff24d, 0x810995ee, 0xcf6c161d, 0x73977e7f,
+	0x8fd61c84, 0x43d07366, 0xf919a67e, 0xe6b5f548, 0x00b8e2d5, 0x942667af,
+	0x9eb5b80c, 0x83b8ebcc, 0xb79febf1, 0x286b4dd3, 0x66cb869f, 0xed879796,
+	0xb78ef375, 0xb8127f48, 0x6ecadcfe, 0x58912cf7, 0xbf6b167c, 0x959eddba,
+	0xf9227ffd, 0xcfadbbde, 0xfee11fe0, 0x584a5363, 0x99ef1cbd, 0x87583ca8,
+	0x7f31eec9, 0xb3b7f9a1, 0xcac7bb6f, 0xcf6b12f8, 0x6db37d7a, 0xb2019dff,
+	0xf68093f7, 0x2fb47a4f, 0xd9a2de41, 0xdd07f33b, 0xb3af815c, 0x339951f7,
+	0xddef14ed, 0x9e1ddec4, 0xdece6fd4, 0xf23939bf, 0xf85201bc, 0x1c846afb,
+	0xa43d50d7, 0xc9852db8, 0x2e9b9751, 0xba7e5d47, 0xfd963ebc, 0x637d1177,
+	0xd775fdb6, 0xd55762ff, 0x53073deb, 0x793b767c, 0xfee1e3dc, 0x8f285ff6,
+	0xf7373c7b, 0xfe7af7bf, 0x7e8bff09, 0xe26ec072, 0x5bc3a64f, 0xa3f9872f,
+	0xb741e3cb, 0x2433d8bf, 0x68241fcc, 0x6f4fd530, 0x9ee98fc7, 0x99fefc6f,
+	0x67fa0b7e, 0xfff433fc, 0x1292f9c3, 0x78b12f9d, 0x49e50466, 0x5527963e,
+	0xfc83bd53, 0x4fe818df, 0x15bd59f1, 0x9aa43e58, 0xee4979ba, 0x42d97625,
+	0xc5259771, 0x3afd216b, 0xbea211ea, 0x48f56bef, 0x2496087d, 0xbd0ddfe8,
+	0x128cf2cd, 0x43cb4997, 0x30f6f30e, 0x09bdfc7d, 0x0c94d794, 0x18e1c6d2,
+	0x6c089f1f, 0x472df9fc, 0xcdb25e59, 0xfc20aca3, 0x4c48f05e, 0x74b7173e,
+	0xfde7e3ef, 0x5747c40d, 0x04bbffb2, 0x5676ad6b, 0xda136b4f, 0xc3b91773,
+	0xdfb57ff3, 0x8817f271, 0xaca3c877, 0x502f79a1, 0x12352231, 0x16ad79f2,
+	0x84e6f748, 0x5601cbfb, 0xae58bdd0, 0x6044fd1e, 0x1c3c1df1, 0x1fbe9437,
+	0x959f7604, 0x35b1dfeb, 0x06c77f44, 0xb3e3175e, 0xfea11dfe, 0xb09de09d,
+	0xd7bed25c, 0xf92370db, 0x866ce4eb, 0xafdf1173, 0x2e9059b5, 0x22efd757,
+	0xff477d85, 0xabd6fb42, 0xf2cf1ad0, 0xd7efe8d9, 0x4f3013aa, 0x7b287e45,
+	0xca3b411c, 0x04f6e171, 0xab986756, 0xa47b8fd7, 0x31f44bb0, 0x3d03d389,
+	0xfd7dd8d2, 0xe74ba6b8, 0x2cff4097, 0x6fcdc533, 0x1e23355f, 0xeff1f66f,
+	0x99543925, 0x285f483e, 0xdea45d53, 0x95d0f749, 0x4a97a21d, 0x9d5a5530,
+	0xb5529a1e, 0xbc188afa, 0xb98fc717, 0xf54cdcef, 0xfe1ec3bd, 0x0dd9714e,
+	0x5d519dec, 0x10b6936a, 0xa70fd72e, 0x71ed8d3f, 0xe979f719, 0xcef2eefd,
+	0xa366b367, 0xc05ad01c, 0x00fae2c9, 0x36c1675b, 0xd2b91f7d, 0x96ba42fd,
+	0x4220fbbf, 0xbb9f3a1e, 0xa28f1ff0, 0x0e29bdfa, 0x09dede98, 0xc78a241b,
+	0xa58c3975, 0x838a53c7, 0xc8efe0de, 0x6ce8050b, 0x3e725c53, 0x5dfbe78e,
+	0xb0ef8beb, 0x52cd017c, 0x6cdbaa8d, 0xfcf37998, 0xa5602522, 0xbae9bfad,
+	0xf68f25e3, 0x06103e4e, 0x791deff2, 0x9b52a35d, 0x952c5633, 0x6a4f44cd,
+	0xbfe4979c, 0x77666370, 0x7c3043f2, 0x83ce441d, 0x2f4cc90d, 0x1845ba56,
+	0xb7367a8e, 0xfba4c905, 0x160ee5a8, 0x92d83df7, 0xe313a0c4, 0xf8bfea4e,
+	0x7983fbca, 0xa7cb871d, 0x63eed5f8, 0x6afb1c58, 0xf563063f, 0x4fb9fcd6,
+	0xd84b77a1, 0x123ab023, 0x75ca12f9, 0xc7563d75, 0x6eac8378, 0xeec096f7,
+	0xbf9b293d, 0x75495463, 0xd20e1dec, 0xc22f2c7d, 0x2ec94b25, 0x6cddf45d,
+	0x8faeff12, 0xf7dacce5, 0x3e4d4eb1, 0x7df9d009, 0x881bef6c, 0xccb67277,
+	0x3d208bbf, 0x264949c1, 0x5cfc9bb7, 0x393fb66a, 0xe6bde29b, 0x9f54459d,
+	0x4aea0b9a, 0x13d94770, 0x6ae848dc, 0x77b497a7, 0x2b0f5d31, 0x852173b5,
+	0xc6855feb, 0x3e8d4ad6, 0x2b5418cb, 0x4772cfa4, 0x377ae6f6, 0x80fe8691,
+	0x1f0adf7d, 0x40fe3dfc, 0x3f7407bf, 0x2cf535fd, 0xc7d2cfc6, 0x7ce3ddb9,
+	0x0ffd175e, 0x511f5021, 0x6faceac7, 0x77b0233d, 0x326ebd6d, 0xbd0a0ccd,
+	0x095422ef, 0xd2f7d296, 0x8598e104, 0x62e38b9d, 0x8cc3ab12, 0x63ebfc62,
+	0xd39d5952, 0x9830ebce, 0xfd43dc27, 0xbf66ead7, 0x7920f8cb, 0xc51bf7d9,
+	0x6c4f5e36, 0xdf644f7f, 0xee8add1f, 0x555e5af1, 0x6f62e07b, 0x5f71dbb2,
+	0xf7e27e89, 0x11e38b71, 0x67c753ca, 0xf197f7f3, 0x9828a6d9, 0xe98bfb2e,
+	0xea3b3fdc, 0x5f909ba6, 0xc167be7f, 0x8771df2b, 0xae887ae9, 0x40a7ba2c,
+	0x4d3e90b6, 0x371de504, 0xf06df56e, 0x5064f6b3, 0xf7496c19, 0xa54eca4f,
+	0xac0310ef, 0x7dc47c7d, 0x8b125eac, 0x655e2c7f, 0x2c5efcd9, 0xc14536cb,
+	0xcfdfb271, 0x5e1852f1, 0xd1365fb8, 0x24f5e3a5, 0xdfea4ee9, 0x88555f25,
+	0x7ccaef90, 0x02d7df91, 0xf2c3afbf, 0x25496b1d, 0xbd108ef9, 0x0c17ab4c,
+	0xe0f48479, 0xa5eadd9a, 0xbe5d3b77, 0x9bde8108, 0x638e72c3, 0x88ba52fa,
+	0x6c91cbeb, 0x6a0baf37, 0x580e4772, 0xf942ae28, 0x9a7c4d3f, 0x75e44237,
+	0x3fe50938, 0x4addc980, 0x82995e36, 0x2ae8cf72, 0xde2d5adf, 0x66e2d1ad,
+	0x66f51fbd, 0xeae9f105, 0x89fd61de, 0x4607b53f, 0x7a9fc4c8, 0xd4dbcf13,
+	0xd0ead6ff, 0xa38bc99a, 0x47ef62ee, 0x297af660, 0x45be2aff, 0x9355b29e,
+	0x961ef1cb, 0x5fb60171, 0x4076bbf4, 0xa6809fd3, 0x9c70ff57, 0xe2a21fd5,
+	0xffa211ac, 0x754fe265, 0xf32b55dc, 0xfe7bda63, 0x19b37a56, 0xd11fd612,
+	0xb26ff0ea, 0xf5cbe247, 0x55f9f506, 0x44e7ff5a, 0xa64ce7d4, 0xef28e7cf,
+	0x75e56e3c, 0x156456e7, 0xff107ffd, 0xccbbfccb, 0x3e9a77f0, 0xbc512b06,
+	0x8042e704, 0xbad0f9c1, 0x9fce1072, 0x469658d8, 0xfc9854f8, 0xa2ad3eec,
+	0x3be9bc2f, 0xec2f681b, 0x76fcfc81, 0x7a77d2c3, 0x5e538a20, 0x5c285b74,
+	0xb041b49b, 0x97be40f4, 0x41582d34, 0xb78fb46d, 0xb70f4e48, 0x0ee77a6c,
+	0xe39d17ec, 0x8f1c7d98, 0x1cac5391, 0x45fc6b0e, 0xd39b787b, 0x70ba30a5,
+	0xa1ed4dfd, 0xe12bdd06, 0x01ffffa5, 0xd5b93efd, 0xefd023ff, 0xe3781b15,
+	0x7a6ec8e2, 0x3fbfcc83, 0xf3e7f68f, 0xfa27df80, 0x923afa7e, 0xf397dd20,
+	0xf4979ba1, 0xfb8592ea, 0x807d4bcd, 0x0125c1d9, 0xf0bcec2f, 0xfee906fd,
+	0xe199791e, 0xf4d6a37b, 0x39f92e5a, 0xc77e57bc, 0xe699e2fc, 0xe4dd0395,
+	0x64e903ff, 0xd99f96af, 0x735ff5bc, 0x9510ccbf, 0x80ceb4d3, 0x01a03406,
+	0x0340680d, 0x0680d01a, 0x0d01a034, 0x1a034068, 0x340680d0, 0x680d01a0,
+	0xd01a0340, 0xa0340680, 0x40680d01, 0x80d01a03, 0x01a03406, 0x0340680d,
+	0x0680d01a, 0x0d01a034, 0x1a034068, 0x340680d0, 0x680d01a0, 0xd01a0340,
+	0xa0340680, 0x40680d01, 0x80d01a03, 0x01a03406, 0x0340680d, 0x055ff01a,
+	0x328d1fff, 0x800060f6, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00,
+	0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4,
+	0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6,
+	0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6,
+	0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00,
+	0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4,
+	0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6,
+	0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6,
+	0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00,
+	0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4,
+	0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6,
+	0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6,
+	0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00,
+	0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4,
+	0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6,
+	0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6,
+	0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00,
+	0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4,
+	0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6,
+	0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6,
+	0xee017e3f, 0x0014ab55, 0x000014ab, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x00088b1f, 0x00000000, 0x62f3ff00, 0x51f86063, 0x408cc10f,
+	0x7f120cb6, 0x66476028, 0x48107d08, 0xf3e2061f, 0x2fe9a48c, 0xb9b04160,
+	0x40afec80, 0xa8597833, 0x88a1bee7, 0xcfd2738f, 0x81ae792e, 0x66322ff7,
+	0xe86067e6, 0x6ff047e4, 0xb3caa3f2, 0x3dd7d3f0, 0xb000c6b4, 0x00eeff4a,
+	0x0000eeff, 0x00088b1f, 0x00000000, 0x7dd5ff00, 0xc554780b, 0x3d9cf0d9,
+	0x3764dd97, 0x2485cd9b, 0x200d8410, 0x125c40a2, 0x126e20ee, 0xc3116088,
+	0x65e28145, 0xb201ae41, 0xdb3f6911, 0x5cbb7ffa, 0xc6d6a444, 0xa0b45b4b,
+	0x06a2828b, 0x82482459, 0xa5c8ba1b, 0x5835b5b4, 0x0da978aa, 0x24c4dc88,
+	0x97f4b004, 0x3bef3fca, 0xce7bbb33, 0xf4bc4c6e, 0x7d6f9ffb, 0x7339867c,
+	0xef3bccce, 0x6779de7d, 0x313b10a2, 0x0ae42775, 0x64246efc, 0x19084c99,
+	0xbbc32d14, 0x32413cbf, 0x46bcf909, 0x08f39a75, 0x86a1d929, 0xc5f5a46f,
+	0xd400a41b, 0x0893bb4d, 0xd3484819, 0xcaf7563a, 0xa08e8f0d, 0x4ca764ed,
+	0x8482d136, 0x4592266d, 0x610b09c8, 0xd60a673f, 0xeab126e7, 0xee7b0de2,
+	0xd7e7fe82, 0xfd12499a, 0xec8d44fe, 0x4d92fa86, 0xb4488052, 0xad21eebd,
+	0x5e7fed0b, 0x39260a40, 0x63d37d69, 0x9085339a, 0x6cbfbbe5, 0x5c057182,
+	0xe2167c67, 0xbfbe00d4, 0x23f63565, 0xadb03ca4, 0xa7ed0bb4, 0x99725abc,
+	0xebe538e8, 0x038df0a4, 0x9014b9e1, 0x370bbf69, 0x0fb3895b, 0xc10ae183,
+	0x4b1e7171, 0x6971d3d6, 0xd2a9447f, 0xe3a252ca, 0xf19cfc09, 0x4471c5ad,
+	0x744bf17d, 0xc55dfa1c, 0xa60b92ab, 0x9e226158, 0xa9bf1d20, 0xf3da692e,
+	0x32df9836, 0xec4a77ad, 0x0ebe663c, 0x6c0f28f3, 0x006d4ad0, 0x6e6d06d7,
+	0x0b7f68bf, 0x0f56ff37, 0xd99edad7, 0x6376989e, 0x5147c679, 0x2f5a3bda,
+	0xb41dc427, 0x6d01fc01, 0xf3e8ff62, 0x908d295a, 0x4cbfd04e, 0xff68969c,
+	0xb9f1f884, 0xc0615c4c, 0xb8a5093b, 0xead6e962, 0x496dd3d0, 0x0db6ff1a,
+	0xe9c97e78, 0x81cf98f0, 0x1cbe13e5, 0x73e57f2c, 0xf1bf9c22, 0x29f2c1f5,
+	0xff9f0b9f, 0xcb1437d6, 0x96373ef5, 0x62c6facf, 0x8657c1b9, 0x9bef3def,
+	0x9f26e586, 0xe8bf9f07, 0x4be58f9b, 0xfe7c4abe, 0x2c7eef8a, 0xf8fcf8b7,
+	0x356fab7c, 0x557cdb96, 0xf4e76e58, 0xe00be1da, 0x9b7d3b7b, 0x05f3acb1,
+	0xbe1bf9f1, 0x017f2c5a, 0xaa65a478, 0xa14cb1db, 0x4d1d4a74, 0x484d941c,
+	0x32d95946, 0xa633d695, 0xa7b67ab0, 0xf146996a, 0xd69b3d94, 0x2b731d29,
+	0x6999961b, 0xd652ee7b, 0x58efddde, 0xddeda16e, 0x9ef6b257, 0x93cb6555,
+	0x27cf7b68, 0x8135fb59, 0xb4c9e5aa, 0xac8d9afd, 0x61b06fbd, 0xf7b695b9,
+	0xd7ed61ad, 0x6c2b1d87, 0x3efd7eb4, 0x286c2f56, 0xeb42915b, 0x7d598785,
+	0x0ad56348, 0xc87efd3b, 0x88fdf671, 0x4ceca096, 0x55db1fc0, 0xd2843dd7,
+	0x52fed7ee, 0xd68c32b7, 0xc47dd735, 0xff66c845, 0x33a56ead, 0x865a87c5,
+	0xd3fcbbed, 0xc32b5d58, 0x33fcb7f6, 0x6a9dfdf1, 0xec7fb625, 0x9df6c72f,
+	0xb7b6255a, 0xf6c3eff8, 0xdb0ab53a, 0x601ecb4d, 0xdb0aad75, 0x883d9733,
+	0x52a1bfef, 0xd2138760, 0x6ea3d97b, 0x966f853f, 0x7d02a9e4, 0x9caa6cd2,
+	0x28b7404f, 0xaf901ce1, 0x0d322487, 0xc4a7e5e4, 0xa1e6fa89, 0xc83734ab,
+	0x8343f6e1, 0xc539079f, 0xe7d4265f, 0x0f26b0be, 0xfb0a79fb, 0x3d3f68d1,
+	0xf0a7efdb, 0x7ebaa19d, 0x2f99df0a, 0xf80e79fa, 0x63b939be, 0x677f6cfd,
+	0x779e1eb8, 0xaf3f45ca, 0x8ef63f60, 0xaff0abcd, 0xfcf0f523, 0xa7e89175,
+	0xde95e706, 0xbc767831, 0x1793f14f, 0xfbc767ed, 0xf6123f14, 0x64fd8f53,
+	0x419e0c75, 0xf5d50c1f, 0xf983e833, 0xd8039fa2, 0xf58e974f, 0xe183e3b3,
+	0x283e787a, 0x8dbcfd17, 0xd8eb74fd, 0x387d06bc, 0x87cf0f52, 0x473f448b,
+	0x1d1e9fb0, 0x51e767eb, 0x1e767e3d, 0x28e7e08d, 0x63bbd3f6, 0x4c721af3,
+	0xc7219f8f, 0x8339f822, 0x63aebf74, 0xa63cecfd, 0x63cecfc7, 0x479cfc11,
+	0x363bf278, 0xe89f21af, 0x93e433f1, 0x632e7e08, 0x831d053f, 0x1eb4eea7,
+	0x23a7753f, 0x982551f8, 0xc18ee0d7, 0x1e8cec33, 0x44cec33f, 0x009763f0,
+	0xeb1de19e, 0x1e8ceea7, 0x2267753f, 0x7846c9f8, 0x5e6c7546, 0xe3d33ec3,
+	0x1167d867, 0x9e1138fc, 0x08cdcae2, 0xf4fda10f, 0x379fbb6f, 0xcff5e9ce,
+	0xfe98e71b, 0x8fc47819, 0x21cd57fa, 0x6467002e, 0xa25f994b, 0xd6932575,
+	0x89ba509d, 0x055fda87, 0xf83f70ec, 0xd32fd1b8, 0xb4ea94f6, 0x58ce3582,
+	0x02ec5c7b, 0x4d03ec78, 0x18ef7b3a, 0xa7abac99, 0xd9d74e8f, 0x5df1cceb,
+	0x29acf574, 0x9cf5743d, 0x7dd3ae3b, 0x817665df, 0xd175deae, 0xdbbd5d70,
+	0xf7dd62d2, 0xd66e07ce, 0x3958f7b5, 0xf5ef5749, 0xf5750fc8, 0xd2ce4fde,
+	0x2bacfbd5, 0xdd77f5d7, 0x7aba25c6, 0xea9feabf, 0xcb35f9ea, 0x68577575,
+	0xb05eae8d, 0xff5d71ef, 0x5a7adf03, 0xf87c1f57, 0xe87d5d39, 0xbeeb2f47,
+	0x35fc7e1f, 0xd9e47d5d, 0xc7ff065d, 0x97d138e6, 0x77f065d7, 0x9a07e8ad,
+	0xcfe869bb, 0x60b37516, 0x6cddc7fd, 0x28f1ff58, 0x4a0e35cf, 0x07c39fd7,
+	0x58fdeed4, 0x48ef5cf3, 0x25297f60, 0x4a07244d, 0x8d0c898f, 0x52ad5f6f,
+	0x527ca3be, 0xef72fddc, 0x9af4b4a3, 0xd1a77a5a, 0xa2a6eff2, 0x3f17c0a5,
+	0x97e84c95, 0x09526559, 0x1335647c, 0x57d5cbe4, 0x1fde7e0f, 0xe70fdfc3,
+	0xfd14be31, 0xe656ac3e, 0xeffe1d80, 0x83f3bf65, 0x4f287e1d, 0x93ec3b43,
+	0xf7f6177e, 0xfde7dfa2, 0x49fc0738, 0xd4fd468b, 0x3a35f1d8, 0x7f1c3f7e,
+	0xa6bf8c25, 0xbd2df18d, 0x4fc6ea87, 0x375f31ea, 0xc746927e, 0xe8f21077,
+	0xf1f3dfb2, 0x50bafe29, 0x3dfa50bf, 0x71e96f8e, 0x5abf8e3f, 0xe375f323,
+	0x7fc64727, 0x69fde412, 0x82507f18, 0xae1ef7f9, 0x728f7f9f, 0x3635fcfd,
+	0xbd9667ff, 0xc64fc7cd, 0xbd2b3ff9, 0xe3dfe6cd, 0x66fe6ca7, 0xf8ec6fda,
+	0x37fe08f6, 0xb72ff8c2, 0x9ae5be31, 0xf7f9fa91, 0xbf9fa45c, 0xeaff8d99,
+	0xf8f8f7b2, 0xab7f1c36, 0x7f9b1ef4, 0x7c7007cf, 0xe5d2b9b3, 0xeee64da0,
+	0xd00195c9, 0x263dd413, 0x746020d9, 0x2820219c, 0xefd084e9, 0x903d4817,
+	0xa64e3f0e, 0xffdf477c, 0x1bf29922, 0x6fdcf7f8, 0x12558127, 0x1dd74c19,
+	0x5767a79c, 0x417ed4cf, 0xcb5d993f, 0xae8433d6, 0xf0a6ae77, 0xff9ed535,
+	0xef0a43e2, 0x50038dec, 0x274e514f, 0x3e1cddf0, 0xf0ccaf15, 0xb7594841,
+	0x12bf5489, 0xa4dbaca5, 0x06e4d8fe, 0x411e7fbf, 0x78f8e318, 0xa27a954e,
+	0xe6fe4631, 0x17d7d5ad, 0x0175f404, 0x09301177, 0xa4c5fd2d, 0xf71d254f,
+	0x10275d18, 0x447f97ea, 0x594270fd, 0xdc9513f6, 0xf2f1465d, 0x404f5d31,
+	0x27ae91bd, 0x4cae9da0, 0x14c72e91, 0xb63bf382, 0x7a001ada, 0x0193f17c,
+	0xbb87d81a, 0x1bf2a7ef, 0x727edf2b, 0x5fc28738, 0xd339e7c6, 0x076fa19f,
+	0x4c3c53bc, 0x0b2bf3e4, 0x974f1e2d, 0xd59ee4c4, 0x459954b9, 0xf24a6bdf,
+	0x54ffd0a8, 0xe9b356e2, 0x9d2e7778, 0x5f107aa8, 0xca135cee, 0x5135c939,
+	0x56e89f39, 0xf4c6358f, 0x8066a93f, 0x93227b4a, 0xdf9feac7, 0x37afa656,
+	0x44d56ea9, 0x5134d3e9, 0xdda81b22, 0xdf4d3a99, 0x2339c62e, 0xc5fce3a5,
+	0x6e746578, 0x9e61d39d, 0xeffa63f4, 0x3cd83a1f, 0x34bc3ae8, 0x3f73d617,
+	0x689b5c90, 0x57bc2a7d, 0xa83d7400, 0xb769f3c1, 0x90d6b9a4, 0x92897878,
+	0xe11cfd83, 0xca23bceb, 0xcd0c5fa6, 0x83ff878b, 0x29b756dd, 0x461e7e3f,
+	0xa093a7b8, 0xba76f60a, 0xc67cff47, 0x18fce37c, 0x74e09c5f, 0x407c063e,
+	0x07c093cb, 0x39c7cf14, 0x2bf5441f, 0xc01383e3, 0x4eb09907, 0xa7307c66,
+	0x6ffd312a, 0x479ff4e7, 0x29676afc, 0x9ca9f74a, 0xba73b7ee, 0xe7ab5bcf,
+	0x3cf9b88f, 0x1cc1e1b9, 0x3cf98267, 0xa62547b2, 0x657979f8, 0x2ff91f06,
+	0x8e89b029, 0xbea5677b, 0xfd0376fd, 0x777e9c3c, 0x7165e846, 0xbf3e5197,
+	0x011927eb, 0x7c7133d0, 0x31f5e9c1, 0xb5b4d7a7, 0x4cefed8f, 0xe46be1e2,
+	0xf6b13af4, 0xfb44d579, 0x112f9c6b, 0xf08c6ff0, 0x9bbbe11a, 0xdfa03438,
+	0x9febf7dd, 0xa627f4cf, 0x28b6b79f, 0xf3cc78e3, 0x1971c1c5, 0x68e463c7,
+	0xba89e6e1, 0x74c082fa, 0xd6f3fbdd, 0xcfb5d4ce, 0x6ba05aa9, 0xbdf567bf,
+	0xff4cfaba, 0xdfef744f, 0x5d32ff7d, 0x0f959dfb, 0xcc67daeb, 0x9f574c7f,
+	0xf74a79ee, 0x1b69d4fe, 0x95b7ed74, 0x9f6ba4bd, 0xae9b763c, 0xa75dd13e,
+	0xbdda5f7b, 0x9fc43ba0, 0xd9e79abc, 0xbd9b886c, 0x49cf266f, 0xe84c7af1,
+	0x273ee3bb, 0xebe13f3e, 0x9f29e583, 0xf19f9f0b, 0x1972c50d, 0x176a71e8,
+	0xf4ac754c, 0x3bb33e3e, 0x07217fe8, 0x6eaea89f, 0x7a8d3fa0, 0xc4e7a8cf,
+	0x46bd46fb, 0xa7e0b97f, 0x59cf15b4, 0xb0329124, 0xf312cd0b, 0x43f3c457,
+	0xb2123edc, 0x1a45cb1c, 0xaf45d393, 0x39062e75, 0x7b85a45a, 0xeedada57,
+	0x9c250497, 0x9eaa9ccf, 0xade7383a, 0xef806bed, 0x05abe439, 0xf3dd4281,
+	0xe8479b85, 0x47bb3bbe, 0x402af846, 0xff8187b6, 0x04deb65d, 0xb7bc31f6,
+	0x00fee4db, 0x1319fbaf, 0x09db5bc0, 0xdf59eaed, 0x0ae38cd8, 0xcb0cb9e0,
+	0x5869be53, 0xb079f09e, 0x8f9bee3c, 0x255f31e5, 0xfbbe8d96, 0xe7d8fcb1,
+	0xdf23f2c7, 0xf03f2c6a, 0xc4796155, 0x77cb16b7, 0x0f2c017d, 0xf96336fb,
+	0x65882f8e, 0xcb16af83, 0x4b1b9f26, 0xfc312f21, 0x0c73bdd2, 0x277d08bf,
+	0xce29e1f4, 0x5f80672f, 0x73c5f112, 0xa938be7a, 0x185f2256, 0x0e91a1f5,
+	0x6df77d46, 0xf4dd21f9, 0x9443f0fd, 0x7a06b9de, 0xde8f6cf7, 0x397d221f,
+	0x0e4dd3bd, 0xf7a70f06, 0x45780623, 0x041281a9, 0x7e6665bd, 0x595b711e,
+	0xabc453dc, 0x7b8b3249, 0x337578f2, 0xbc0377fd, 0x10fb04a7, 0xbf6b5fda,
+	0xe21bdbff, 0xcc47adcc, 0x3db5e484, 0xdafd233f, 0x9bf103c4, 0xc9ff0ebe,
+	0x14af0cc9, 0xda84b1aa, 0xbed73587, 0xeac59aee, 0x423b010a, 0xb8d8ae82,
+	0xc05fa46f, 0x78fb7665, 0x7f31374d, 0x6657bad3, 0x776f08f8, 0xf2894e4d,
+	0xd2dcd7ab, 0x95f833bb, 0xd8099a1f, 0xe9b01233, 0xf5a7e5f1, 0xb57c51c1,
+	0xf4f68f35, 0xfc2fffde, 0xda8fa7b4, 0xa48743d3, 0x735fc7af, 0x24f75d31,
+	0x008e2f58, 0x6df41c3e, 0x1ba1b0f8, 0xf81061f0, 0x5adff69d, 0xe92a4d73,
+	0x66e7ed17, 0x13af9393, 0xde4e9ebe, 0xd37e0854, 0x1334537e, 0xcbae9eb9,
+	0xf24dcf65, 0x5dcff020, 0x6f4a7e8d, 0x6bab6eff, 0x49d61385, 0x7612fe67,
+	0x75fa17c2, 0xe7c1eb73, 0x59aeb0ed, 0x1c726392, 0x3e9b6c2f, 0x0e79838b,
+	0x547fac5b, 0x56b7afab, 0xdc596349, 0xa53a99c4, 0x8769e83f, 0xd02f78e3,
+	0x8a58399b, 0x68e4967e, 0xf019e38e, 0x79c9805e, 0x81ea1a75, 0xbe0b3e33,
+	0xd1c37df7, 0x38513f56, 0xf427c86a, 0x2b89107b, 0xbf7edb3d, 0x2e56be4d,
+	0x228f1068, 0x580bf521, 0xffd1252f, 0x7e80f4af, 0x7e8bac15, 0x6fd941bd,
+	0x579e1ebe, 0xdfa3c6eb, 0x1b1ec539, 0xfcb6d77c, 0xe084e428, 0x3f374a5f,
+	0x2fb8a7f8, 0xfbd0e494, 0xbaba696d, 0x43b3b6b7, 0x3fc1c7e7, 0x2d1cd1c0,
+	0x8b47c029, 0x2b355b38, 0x8512d5b6, 0x322c066f, 0xf6259f81, 0xa34b62de,
+	0x968fa1e6, 0x7f4148ec, 0x7c63c978, 0x1a4fcd9f, 0x4359fbe0, 0x29970779,
+	0x51fd3154, 0xb44c470b, 0x89af0f7e, 0x3559aefd, 0xff5fd10b, 0xdd71f894,
+	0x1aae5a77, 0x796a7e0c, 0xa6e68370, 0x989cfb74, 0xffbe82c6, 0x2f63bc9c,
+	0x57b7918c, 0x7be70d64, 0xffbd6acf, 0xbab1d74a, 0xeac75d3a, 0xa4c973ea,
+	0x9a17d82c, 0x974aa4fb, 0xd5aeb8d4, 0x7656ffb5, 0x91e77ce0, 0x876055ca,
+	0xbc29a93f, 0x71e0047d, 0xb0c1fae7, 0x9b459c4e, 0x29fea973, 0x03487cdf,
+	0xe3a6f939, 0x0bef802f, 0xf315c7e2, 0xe407db8a, 0x59bc5878, 0xd8120772,
+	0xf76e5abd, 0x3bfa5e84, 0x1eb31fc0, 0x23e7cd3f, 0x3f9adfea, 0x65c32932,
+	0x4339e945, 0xc1921cf6, 0xa49f008e, 0x5be2f946, 0xd7139ff7, 0xd7bfdfff,
+	0x1d12bbfe, 0x4ffed37f, 0xdefc5e83, 0x0715effa, 0xf044c5ff, 0xb22c3a0b,
+	0x17c01c34, 0xbe096e1d, 0x14dcb853, 0x7c60714d, 0x725ab9aa, 0xc4fbe999,
+	0x2c8e9c4d, 0x3d601fa6, 0x6a5afcd9, 0xe1bd413e, 0x1f3a6e20, 0x552e7f2b,
+	0xd123d9ef, 0x3b4ae175, 0xfe51a771, 0x9953e954, 0x692ad1ca, 0xe5a24580,
+	0x7f739ae2, 0x9bf68379, 0x88099214, 0xa1853374, 0xdd97f701, 0xac776069,
+	0x03b411e4, 0x257ec7b0, 0xd1a70a23, 0x0578103e, 0x8d8397ec, 0x61b6463b,
+	0x9d75a6fc, 0x9955718c, 0x919bf75c, 0x0f782f54, 0xeda2f952, 0xb405f0ad,
+	0x5d7095af, 0x04b07adf, 0x24eaf3eb, 0x6beb4192, 0x60f9ec93, 0x26dcd2af,
+	0x63373c5d, 0x4e7e3eac, 0x5806eefc, 0xf3e6cfff, 0x1c00c405, 0x53bd790b,
+	0x7de1ba59, 0x5c4c5ffa, 0xee67b66c, 0x93f14278, 0x771f4d3d, 0x723f285f,
+	0xed3ae200, 0x06ed6dca, 0x9463900d, 0xf59b85db, 0x21b78175, 0x09e64a4a,
+	0x6236c9b0, 0xadb5bc03, 0x67c1dbc7, 0x8cdfef63, 0x7c71d81c, 0xce64f11a,
+	0xc935e3d1, 0xb5abc7a9, 0x066f018f, 0xf4b8a6bc, 0x3a66a2f8, 0xa9af0890,
+	0xfae87b43, 0x7af1bef9, 0x6fb3e017, 0x57f49f14, 0xa262c966, 0x56767007,
+	0x46ffc8c2, 0x85b5c979, 0x55f7f825, 0xf8658199, 0xf5052b95, 0x5f870e40,
+	0xb3becd9a, 0x60c8bc82, 0x2f285d55, 0x3b046910, 0x391f256e, 0xf2268e80,
+	0xb7d2b909, 0x37de3a6d, 0x59d1df71, 0xc075abf4, 0x1f23d7cf, 0xe9fc5d20,
+	0x0f22b024, 0x00e5d1e4, 0x59f416bb, 0xbae9b39c, 0x711f55f1, 0xcdfea6ce,
+	0x96073e6b, 0xf7b0168f, 0x0091fb9b, 0xe1831bac, 0x884e590b, 0xeba1cf67,
+	0x1fffaa34, 0x80265ad5, 0x9517fc3f, 0x55eecfad, 0xab772c35, 0x47ffae26,
+	0x79f201ff, 0x00ffa99a, 0xd0e6a5f1, 0x50d5cb26, 0xbf3195af, 0x75569bc0,
+	0x14df8c2d, 0xb35c1952, 0xf64f182d, 0xc768abd6, 0xc48f669b, 0x9f311a7c,
+	0x163c90a6, 0xa1cdd9e2, 0xc4f7ec4f, 0xdaa69dd8, 0xbb05ae27, 0xb12994f7,
+	0x628cfbff, 0xc87e6efa, 0xfa3d38ba, 0xf509d28c, 0xe83da3e7, 0xb6262a3c,
+	0x9becbf22, 0x77ce337b, 0x9a724847, 0xf2a5dc29, 0x0fe83f1d, 0x537f86fb,
+	0xee24de98, 0x58b333f1, 0x5f563ce8, 0xabd4888c, 0x7ec32afe, 0xc3c45d25,
+	0xcac0e2be, 0x8c87e8b9, 0x0292490e, 0xc108ebfa, 0x0fc8467e, 0x7f32c094,
+	0xe3a28350, 0x0921c1c7, 0x91b836f1, 0x90d37e60, 0x61f6fa23, 0xae218a8d,
+	0x9f819016, 0x3fd29c46, 0x6d7c13af, 0xd7c05927, 0x25965e4f, 0x5b9a4ff0,
+	0x1d396b88, 0x977679bf, 0xf9a78022, 0xd046ec02, 0x363cb2f2, 0x8ff7fad1,
+	0x9e87f30a, 0xc6fed8d2, 0x816d7353, 0x6fbe9465, 0xb8c72dce, 0xf13f17c4,
+	0xbfb44f74, 0x5287a315, 0xdc83684d, 0x75cfb0a9, 0x1295c4df, 0xd552031a,
+	0xfe252cb9, 0x82bfc17d, 0x771f059f, 0x09ec9b9e, 0xb2671824, 0xe294fcca,
+	0x8d247db9, 0x5bb4d7c2, 0x4da57422, 0x747b969a, 0xe9630ef1, 0x0173cb27,
+	0x79ed6f1e, 0x2594ec0d, 0xfa0fd894, 0x3ca3b14c, 0x2ff72d34, 0x1fb5bc83,
+	0x3bf46153, 0x27dfaebf, 0x48723e31, 0x2cefb271, 0x9e813355, 0xe42c732d,
+	0xd6379639, 0xf00a5279, 0x55b8c97b, 0xcba7de14, 0x9f37684c, 0xbf085d52,
+	0x7961317f, 0xa2ff7c71, 0x61b204eb, 0x5cfc8c4d, 0x95248a54, 0x0ea92bf6,
+	0xe3c33fec, 0xd77e0092, 0x8769ffbf, 0x4be690fd, 0x1763a466, 0xdf10f71e,
+	0xfad95575, 0xfeea8371, 0xd0f58152, 0x0b944cfc, 0x9ceec797, 0xf5f2ed4d,
+	0x09ef14b5, 0xffe146fc, 0x98e87ba5, 0x9b749e14, 0xb892f909, 0xd5074edd,
+	0x7e225e77, 0x8883947e, 0xa225845c, 0x51ea8e0c, 0x53852429, 0x681c3ea8,
+	0x5a6585b1, 0xf3a7cfa6, 0x6231fd86, 0x2835fd61, 0x40fb2367, 0x7ca1aeb8,
+	0x4d821839, 0xaef587f4, 0xafd0bfd8, 0x84af2f42, 0x67ed36b8, 0x604a63e5,
+	0x9d67ed05, 0x357498d2, 0xcedcf32d, 0xba412062, 0x5003f4e2, 0x2e27cd57,
+	0xf6b1210a, 0xf1169f5c, 0x0ed0a847, 0x78c64af8, 0xd38e9180, 0xf4f2f822,
+	0xf3fce952, 0x09bcb60f, 0x892b8b6e, 0x6fdae78d, 0xca593b41, 0x4fb0eaed,
+	0x17d0014d, 0xee237c24, 0x112d799b, 0x17d3a0fd, 0xc4686ec3, 0xef61ae7c,
+	0x54a87833, 0x41fde1b9, 0x7d723c11, 0xa136fdc2, 0x8284863f, 0x2eaeb085,
+	0xb5ee1508, 0x3e0bf1d1, 0xa71b7262, 0x15d20e3f, 0xaf6f8f5b, 0x307c8c37,
+	0x90e54c20, 0x1d1fa5d3, 0x23a0f0bf, 0x52f68752, 0x7019ea95, 0xc99eb916,
+	0x1b30389c, 0x7f38bdf7, 0xe42af119, 0x05e728d9, 0x9af6bbf7, 0x0c885c19,
+	0x8a4438e3, 0x09ece1c2, 0x392de87a, 0x1157f415, 0xeb8503c5, 0x696f2e73,
+	0x60e30217, 0x6e864ffe, 0x65df224a, 0x7e99b25d, 0xc62f631d, 0x20d99ec9,
+	0xd85ed477, 0x7b150f01, 0x8f4c682e, 0x11de9185, 0x0172a7be, 0x10b909df,
+	0x6fe46efc, 0xe82b0f21, 0x189ea657, 0x4760249f, 0xce082965, 0xeb61d52e,
+	0xe157801c, 0x1a7f1337, 0x3a9663c6, 0x78eb38d8, 0x24d2ca5e, 0xd7fa7677,
+	0x25ef5fe8, 0xc4c40913, 0x8b4abc39, 0x7bd17a06, 0x8c812349, 0x8d9f80ef,
+	0xad59f871, 0xcfc78a76, 0xebf3c86c, 0xfe02bff4, 0x87fe1180, 0x5ff8519c,
+	0x421456b7, 0xe70efe9d, 0xef9bd2c4, 0x15f90a13, 0xb6b43af2, 0x9cb52f72,
+	0x2719f271, 0x0c80a197, 0x4f978a78, 0xccf41932, 0x23f33088, 0x817a728c,
+	0xf6f9a3cf, 0xefc0de96, 0x0ea7b2f9, 0xf7def7e0, 0x2fe83745, 0xc63249df,
+	0x6bf32053, 0x2bd81765, 0xb3a190d2, 0xda76f107, 0xf5c4e8cf, 0x9f9f057a,
+	0xd4f94b54, 0x9e05fb0e, 0x0affd07d, 0x41ff5b07, 0xc7f41e40, 0x7bf3c545,
+	0x852b0b90, 0xa7e2192d, 0x1879c27d, 0x45c832a7, 0x3560725b, 0xce9079f0,
+	0x9f8cec17, 0xa5ab99da, 0x5879e1b6, 0x52f0634d, 0xa23f07e9, 0x06c260eb,
+	0x8fb820ab, 0xe59f35da, 0x602d74af, 0x729fd6f9, 0x50c27e7d, 0x3eca545e,
+	0x0aa97986, 0xbe0b9bf1, 0x2a00dc3d, 0xaa4e5fc4, 0x1f008fee, 0x9c6eb196,
+	0xb883ae47, 0x72276a24, 0xa2e4a095, 0x722fa470, 0x9fc6bda2, 0xbfb49fb0,
+	0x22cef1dc, 0xd52e77a0, 0xcaf71089, 0x91247f05, 0xc22aa85c, 0x3ef9adfd,
+	0x5f07e710, 0x407f7ce1, 0x18cdf3a3, 0xbcb1a2df, 0xd4ce2a85, 0xdbf0092e,
+	0x4e3b7294, 0xc4a2e9b6, 0x8634fcfc, 0x08bae367, 0x52f30608, 0x8d41fd78,
+	0xb8e94928, 0xbec3f16e, 0xc164dfb2, 0xb8958b75, 0xbae7a082, 0xbe1e2c68,
+	0x86ad724a, 0x16952ffa, 0x78f9e40b, 0xfefd6cad, 0x2e49c8e8, 0xbf62be85,
+	0xd61f35a1, 0x3bcf949e, 0xa6fdf469, 0x57bdad91, 0xba5a0ce2, 0xcb737e31,
+	0x27c12f30, 0xb56e8215, 0x496e8eaa, 0xa1888f10, 0xad148adb, 0x4dc5f80f,
+	0xd60bb252, 0x240b4d29, 0xe164a706, 0xff9053f3, 0x1e127122, 0xf2d42857,
+	0x6f423f10, 0x86acf9d3, 0xfb0dc052, 0xf92fd0fa, 0x89b0359d, 0x8f1bfabe,
+	0x81c433a5, 0xed8e67b3, 0xaf67710c, 0x491ba5bd, 0xf3a60710, 0xcbf3001b,
+	0x40d32b56, 0x79df65cf, 0x30f40edc, 0xd7f62dc2, 0x4bfb07f0, 0x586c656f,
+	0x7125fe83, 0xe7cf7ab3, 0x05094eb0, 0x60e39978, 0x2a49cff0, 0xb7d58acb,
+	0x132cfa4f, 0xef5a2515, 0xec4bc914, 0xffe7cba3, 0x89daefb5, 0xbd7be9a3,
+	0x59372635, 0x9fe3f5a4, 0xd6e671d1, 0x3f105d58, 0x8cf65478, 0x773fb803,
+	0x70975f3b, 0x01295d1d, 0x959f8b1c, 0xf079d3c8, 0x43fb611d, 0x1f943f1c,
+	0xd98ecf3a, 0x2ef3a037, 0xd3c506d3, 0xb52559b5, 0x7212e710, 0x2ca7c999,
+	0x4ba082f4, 0xea9bd026, 0xe5465205, 0x8dce2634, 0xdc6166af, 0xe8527f0a,
+	0xbf02fff7, 0x31437ed1, 0x1ba09dca, 0x48f4c3e9, 0x4c75c812, 0xfeb9aabc,
+	0x14fcabbd, 0x9fffbf8e, 0xb68429f3, 0x496943ff, 0xf53e3901, 0xdc535fc0,
+	0x00f60f90, 0x977acf5b, 0xeebce2a4, 0x8ff77ee2, 0xb46a9e38, 0xd79872b2,
+	0x637fbedd, 0x6fa2379c, 0x8efb67ef, 0x8ffaa80b, 0x4b6a2fdd, 0x1479c32f,
+	0xfd7793a2, 0x8562ecbe, 0x7e30eb9d, 0xeb6349bf, 0x1bd505e6, 0xc0275cb4,
+	0x806ff9e3, 0x5f5f14e7, 0xf161aa9c, 0xacdf011e, 0xf81a01ea, 0x9908ffdc,
+	0x1fed9849, 0xb95f4ca9, 0xb7c5126d, 0x08d1e387, 0x179e01f7, 0x3257e739,
+	0xe933c1fa, 0xb953f758, 0x601684f7, 0xff08c71c, 0x52bcba9c, 0xf3987fc8,
+	0x29eb84b0, 0xaa01ff78, 0x3ff73d3f, 0x68e80e74, 0x9f319f9c, 0x171f18c4,
+	0x43c8b37e, 0x983c4d9b, 0x27171297, 0xfb1cfd0a, 0x9e8bc637, 0x797af8d5,
+	0xfb021930, 0xbef96725, 0x621b9c3a, 0xcb04ebfb, 0x14925072, 0x1e968b9f,
+	0xb926052a, 0xc61b72a3, 0x33f8c5eb, 0xf833f8f8, 0xaae15438, 0xe633c7c0,
+	0xf36217ab, 0xdc68b6dc, 0xc7421e6f, 0x89e3a393, 0x39731671, 0x7a0be314,
+	0xe72abe0a, 0x7f515d74, 0xd3235bb2, 0x0c498703, 0x9ff88c7d, 0xca2b3bf7,
+	0xa1cf0447, 0xfd039c5f, 0x51736738, 0xec271769, 0xc28e545f, 0xcfe269fc,
+	0xe16af961, 0x1bb7581c, 0x36a4def1, 0xd8257376, 0xfee2689f, 0xb9717b5c,
+	0x03c89a1d, 0x94f2c2a8, 0x67e07552, 0x191b87c0, 0xb9de2c1f, 0xb79075e5,
+	0xb2bfadf2, 0x569dbc83, 0xbc60b2aa, 0xb41e9b45, 0x29c57ec3, 0xbd076fc5,
+	0xe4c03a78, 0x8aefc8ce, 0x305bec59, 0xe0f6157e, 0x9f3fcbcc, 0xc5f9fc00,
+	0x7a01d526, 0x1cd9bbde, 0x547c5336, 0xd0fc30d4, 0x7f5651fa, 0xade2f108,
+	0xfe5dc3d5, 0x9cb2afe2, 0xe7969f6c, 0x9d7185f3, 0xd3f1b15f, 0x2f0f9052,
+	0x1d7dc169, 0xfe3077e3, 0x97dc74a5, 0xc6a5a99b, 0x11be0bb7, 0x8d6f05eb,
+	0x3c469be0, 0x7f7c665f, 0x172fd73e, 0xfe72bf05, 0x0120f811, 0x9de457a6,
+	0xd28ff3eb, 0x7f8dd9fa, 0x62fd4bb2, 0xbfcb09f5, 0xf3de0d68, 0xdb672eec,
+	0xe71360fe, 0x0177e8c3, 0xcb59cefc, 0xac4230f3, 0xed86a45c, 0xb4591710,
+	0xecf5c541, 0xbfcf2da2, 0xbdd834f0, 0xabaecdf7, 0xb70bff69, 0x38777fec,
+	0xa6dc2fad, 0xd3678e66, 0x763149b0, 0x5a7c0bda, 0xf943a510, 0xb39afdf6,
+	0x40fe7b3f, 0x0b1e947a, 0x48d1edb7, 0x947c78ff, 0x8c68f704, 0x09740dff,
+	0x7d852d1e, 0xbfe7796e, 0xe9fba035, 0xbc8112dd, 0x6e7c38cc, 0xd2fb8fd8,
+	0x23a42780, 0x6e8453a7, 0x94bdf786, 0x39e7682e, 0xefed8c9d, 0x3fe40e69,
+	0x5dce0fe8, 0x757e7e51, 0xfccfc517, 0x982ecc0f, 0xef57fcff, 0x4e3cc3b3,
+	0xaf8c952a, 0x05983fd7, 0xeabe6476, 0xc96072cf, 0xe67fcf9e, 0xf36fc847,
+	0x8b28fd0e, 0x99d2fd30, 0x9dfcd1c5, 0xd6737e61, 0x9bf386dd, 0x77c83c4b,
+	0x65cbd7f3, 0xa8babf10, 0x12dbb190, 0xb94fc5c8, 0xce7c9c5c, 0x27f8fb8c,
+	0xb8531ec1, 0xccc8effc, 0xa2f721cf, 0x9f11fd7d, 0x58fcb50b, 0x18e3c8bf,
+	0x1e22cd13, 0x2c72b54c, 0xa87c6ebf, 0xe673e801, 0xc436772a, 0xf144bd01,
+	0x57487c73, 0xa1f2bf68, 0x3f5cd931, 0x7f189539, 0xc39e04b7, 0x3baa0dfb,
+	0x1df75f29, 0x1d1792b9, 0x9f1f297f, 0xfb0c9dc2, 0x12b327c6, 0x305f87c7,
+	0xd611624b, 0xa303f3a0, 0x7de4cdf2, 0xbe4cc3e3, 0x2607bc85, 0x0bf6858e,
+	0xc0fc9987, 0x53c7e077, 0xd8d9c2b8, 0x848a67be, 0xc3da80fa, 0x51bd7244,
+	0x6fad72e5, 0xe1427c17, 0x897fc056, 0xfb610bf0, 0x7e7927bc, 0xe927dcfb,
+	0xc1763177, 0xe3d9e30b, 0x3b7213fb, 0x6617f84f, 0x7593fcbd, 0x5bc6129d,
+	0x22c47e8c, 0xd3c2f035, 0x3e54af20, 0xda2edf41, 0xbcc196a2, 0xfbdeab3f,
+	0x9ca90fee, 0x7214167c, 0x469fd7aa, 0xdaff9d39, 0xa34fe47e, 0xdc167e9c,
+	0x4e50959f, 0x73c7edb7, 0xfa72f1b7, 0x053fab3f, 0xf01bd6fe, 0x5b61f427,
+	0xc3ea3478, 0x4fc410e1, 0xb7090fa0, 0x13fe46c3, 0xadf8277c, 0xddc595fc,
+	0xf844ef41, 0x845df052, 0xc5df052f, 0xf0ead1e5, 0x083f3717, 0x589f01a2,
+	0x75828ed6, 0xf6c5c586, 0xcb39ae13, 0x819693e2, 0x67d6fd6c, 0x43f582ad,
+	0xb020c726, 0xec4613fb, 0xa427ecfc, 0xbef9fe6d, 0x963e9dcb, 0x65075fa3,
+	0x895f042f, 0x1090e3a5, 0x16fbd383, 0x7d40f409, 0xf76396e0, 0x930b640b,
+	0xbd1f9df7, 0x2c780856, 0xca97ee6a, 0xae1babf8, 0xb5fc445b, 0x054cefd5,
+	0xea1ada7d, 0xad4f7989, 0x4494e507, 0xe25fa5e7, 0xfb857df4, 0x491bcd5b,
+	0xadf94c95, 0xdfa0b499, 0xc168dfe0, 0xbe38b67c, 0xe67f3330, 0xe803e2bb,
+	0x2978f80f, 0x5134b1a9, 0xf9f09a3c, 0x5ff3784e, 0x0baf1f68, 0xbf81306d,
+	0x9346dd7e, 0x24be4fce, 0x1480baf8, 0x784f5f00, 0x20652933, 0x2ecaf3ee,
+	0x0dee5738, 0x093cd39d, 0xf38c95f2, 0xdfc1fe87, 0xe0716fea, 0xc1a86fb8,
+	0xdbdcf07b, 0xeb0216e7, 0x6aad3a85, 0x3b382261, 0xeb383125, 0x7cba338e,
+	0x6a29785f, 0x618b85b6, 0x61237a7f, 0x3a38f671, 0xde0eb613, 0xaa7f704c,
+	0x7ab32435, 0xa347db35, 0x2462fca0, 0xf699777c, 0xd79f231a, 0x057b6ed4,
+	0x8455e7ce, 0xb6898724, 0x1a8d2857, 0x36b78bf0, 0x363d064d, 0xcbce29c0,
+	0x894ffa3b, 0x16febfe1, 0x77b9e705, 0x00331bf8, 0x6acfe72f, 0xddd5f604,
+	0x60ec5afb, 0x0a87ceef, 0x9adadf91, 0x191f76d7, 0xfee9eb05, 0x78a77f00,
+	0x4eabf63a, 0x9447d5d6, 0x5c00ba78, 0x4b8dcc13, 0xfef0095d, 0xf7d9858a,
+	0xdb3e4bef, 0xbf2c3b2b, 0x7afc8587, 0x7c41bf70, 0x378700ff, 0x13b37e46,
+	0x6592efc9, 0xf7986cce, 0xd99efa92, 0x7f25cf80, 0xe2253b50, 0x963e2dab,
+	0xee15b4df, 0xadf90017, 0x7d7bf2a1, 0x50d6fc8c, 0xff8bcdf9, 0xfbe5ae6e,
+	0x202ddf95, 0xfbe009bf, 0x90af9f09, 0x51d0fcdf, 0x1afcdf94, 0x4acef9fd,
+	0x2bf27b4b, 0xf2c29a75, 0x04d65c60, 0x00f01afa, 0x795bb2f9, 0x038c387e,
+	0x37c2fc72, 0x24bce394, 0x4a7fef06, 0x20ec978e, 0x4f128798, 0x4bc7266f,
+	0x4b1ca8ea, 0xc7267740, 0xcb09ea4b, 0x6fc83407, 0x65f9389f, 0xd98457df,
+	0xbcdadef7, 0xc741dcdf, 0x2eab702b, 0x20bf7d0b, 0x6283cf2a, 0xb685f9e5,
+	0xc760f9e4, 0x970779e4, 0x3da72a67, 0xeae8095c, 0x63f3e90a, 0xb27618de,
+	0xe5f03b7a, 0x275c659f, 0x0f79e21d, 0x7276197f, 0x3fc5f020, 0xff8a1e00,
+	0x9a6f9c3d, 0xbfec7e7c, 0xe853f874, 0xabec9547, 0x03ec35fa, 0x12a8de2e,
+	0x351587d0, 0x328fd147, 0x5f85bfae, 0x0b875c65, 0x7e5ed23d, 0x776e61cc,
+	0x088dca26, 0xc65b792f, 0xf38c3ffb, 0xc1c5ef17, 0x5deab079, 0xc042afb8,
+	0x407c5ed9, 0xb83da3cc, 0x15debcc4, 0x148032f2, 0xe286dc42, 0xffc5e511,
+	0xb5cf1947, 0xad5d1595, 0x23e51fbb, 0xaac2cf8e, 0x870812a2, 0x37e7e44f,
+	0xf7bdaee7, 0x18af9c00, 0x0059c474, 0xe188f4ee, 0xa7ac0f66, 0x416a4a5e,
+	0x49741679, 0xb974624d, 0xa379fbc4, 0xf031654b, 0x7256b79b, 0x86f1dd80,
+	0xc1f785ff, 0x8bea7dec, 0x05a3e052, 0x8cc392f5, 0x834e787c, 0xb5295e75,
+	0x854fc0bf, 0x7eb873a1, 0x245f505b, 0xea0bf7c3, 0xa3c0bc24, 0x9474fc3d,
+	0x0edc296e, 0x6df8016f, 0xb30b6700, 0xd13e1c6b, 0x3afc55ee, 0xbe9e4bf8,
+	0xc1972ab4, 0x571704ed, 0x02283bc0, 0xe7194cef, 0x057841d5, 0x3783dbde,
+	0xc74f4935, 0x679e47b7, 0xb4a110fb, 0xbe6bad0e, 0x97887ee9, 0x4cfae034,
+	0x90cc8bec, 0xac0b663d, 0xf3e97b6f, 0xc1690995, 0xa1efebbc, 0xf5d7ff7f,
+	0x0037d91f, 0xece41dff, 0xcbae2a4f, 0xb338a497, 0x1df1dce1, 0xb75d2af0,
+	0xfb336d34, 0xff313de1, 0xabb73e13, 0xc3710297, 0xf19e58b1, 0xf57ab995,
+	0x4f6fb18a, 0xbe43b79d, 0x821f7357, 0x294d2179, 0xda274e2c, 0x0b3249dd,
+	0x587e73fa, 0xf57c34a4, 0x1b49f821, 0x5c03061b, 0xbcf32e27, 0xb1e6cb92,
+	0xd3ddd689, 0xe7109db9, 0x3802ef28, 0x2fb2249d, 0xe59f377a, 0x927e705d,
+	0xad6667ae, 0xf8852b4b, 0xa0bcf1b2, 0x83403827, 0xde31a438, 0x11b88738,
+	0xd0f9718f, 0xbf1611e4, 0xeedff034, 0x273b0724, 0x706a54aa, 0x3ac4f65e,
+	0x8829f889, 0x8f88db0b, 0xf1e24c6f, 0x1fc20ec8, 0x46b1ce77, 0x11b978c2,
+	0x971b79ee, 0x6042eaad, 0xf15e6cbe, 0xb579b3f0, 0x78d20f35, 0x8bb58923,
+	0xbcec420b, 0x3223c576, 0xaf3c83b3, 0xe02bc044, 0x2a5dc233, 0xa7ff422f,
+	0xfa8cad79, 0x607f2ef7, 0xba479c15, 0xfb84a56b, 0x54f9c62e, 0x009cced4,
+	0xdf43c0fa, 0xf3693887, 0x69ed0447, 0x00296af3, 0xd73f8c78, 0x4bfb66e9,
+	0x427bbc7c, 0x7e7351f2, 0x1ea2f4db, 0x3665d20e, 0x849acba5, 0xd5c8a3fa,
+	0x168e462b, 0x7ab9c604, 0xe20bc6e9, 0xe6e17eba, 0xbfe7ba89, 0x74f1e249,
+	0x4f6fbf1e, 0x6265489e, 0x47e422bd, 0xaf9093c8, 0x817ce0dd, 0x0702519e,
+	0x4f00f372, 0x1a7ea18f, 0x4c5e7b27, 0x8f217962, 0x54afa74e, 0xe79e753c,
+	0x0cbc7085, 0x2399f465, 0x6de7c78f, 0x078a31e9, 0xb6c0fedd, 0xe27c7d24,
+	0xcc47cebb, 0x9881c843, 0x8c0e519f, 0x21e91bdf, 0xba46c0e2, 0x6721e918,
+	0x7e40fa9b, 0x5d939121, 0xb9cb77e0, 0xe8d7caa6, 0x5a7772b8, 0xcbf703f6,
+	0x65a4cf25, 0x7928c955, 0xa8572d16, 0x30ad2f4c, 0x1898b8b1, 0x970e5dff,
+	0xcb923328, 0x3ec1270e, 0x830ddbe3, 0x0c2f2cad, 0x5c7145f7, 0x9215a78a,
+	0xe83f809b, 0xfed04fdf, 0xbd926417, 0x712b7f80, 0xd6fdc50f, 0x9e3e7124,
+	0x5fd2e1e5, 0x582e942e, 0x35a70fc7, 0x83473fff, 0x8ab2ecbf, 0x4f5625fa,
+	0x153de135, 0xab25ffc4, 0xb93af367, 0xa2b9eacc, 0xfc29d69d, 0x7bfceeae,
+	0xef566ff2, 0xcdffda2b, 0xb45ebfde, 0x21dac57f, 0x7fb69481, 0xa357f0f5,
+	0xae7f30fd, 0xbbb548c7, 0x62bbf02f, 0xe529eb62, 0xdcf30d4d, 0x15fe3e44,
+	0x96ab97ce, 0x8562bf15, 0xb762a23c, 0x67c4f213, 0xdf3b73f0, 0x90f414b6,
+	0xf7bc26ad, 0x9ba04a01, 0xc0e2cc96, 0xc6a49e82, 0xcbce17dd, 0x2fbba091,
+	0x246635e4, 0xc192927b, 0x61ab7abf, 0xcd47c814, 0x060c1f3b, 0x0ee80bff,
+	0x05be14fd, 0xfa50da77, 0x436abced, 0x46705e6c, 0x193d9172, 0x6cdd1af2,
+	0x3a724adf, 0x14051dc8, 0xadf6b80e, 0xf4d68427, 0x8035b2fb, 0xfb0f6a3a,
+	0xc1659527, 0x986ba478, 0x9cb8fbc5, 0x2e9ecbe4, 0xb8b9bcf0, 0xe061d1f1,
+	0x7ed89997, 0xef48693b, 0xe5a13f90, 0x74798fdf, 0x47b5b9e9, 0x3e3ee166,
+	0xdc90cfdb, 0x6e838c6e, 0x24179c8d, 0x25603f98, 0x6fdc2ec9, 0x7f1c9177,
+	0x307fcf16, 0x1cccbe31, 0xccffb31c, 0x1fbf45e7, 0x870fe70d, 0x375e5958,
+	0x710ca79d, 0x89c401b8, 0x33e42165, 0xf55604f4, 0x09177d60, 0xed19f91e,
+	0x7624f1ff, 0x336585ef, 0x4c87e5d1, 0xd876664f, 0x21f9656f, 0x12706ac9,
+	0x73e4ede8, 0xbb7a01c4, 0xe0a6bd79, 0xf1c50ef9, 0x3c5fcc03, 0xef002260,
+	0x01c06a8b, 0xd72d7479, 0x48e7ce2a, 0x4e66bfb4, 0xe3efd17f, 0xc85af39a,
+	0xcad078cb, 0xb1162fea, 0xd396833c, 0x5af2005a, 0x952d73d3, 0x93b3f9b1,
+	0xf13f9992, 0x78f14a62, 0x3eb043a0, 0x43f8c099, 0xa2065376, 0xbaa579f4,
+	0x63f80920, 0xe288e02b, 0xb8ecdd21, 0x3f4bfa17, 0xc3cde14f, 0xafc46ee7,
+	0x4a901ce2, 0x66fc3bf1, 0x47ee139b, 0x7829317a, 0xcb41c833, 0x839e1316,
+	0x26b9aade, 0xab6b7d42, 0x257901d3, 0x9305e62f, 0x4c5b3e71, 0xc9ad9f38,
+	0xa12dd72d, 0xa3e9af70, 0x14f8058c, 0xe92c512b, 0xcec54f20, 0x99f3e97b,
+	0xacaf4cc9, 0x7a793134, 0xf589d93c, 0x7e3a25c7, 0x8457bc01, 0x4fce24f2,
+	0x75b0b734, 0x0d29a76b, 0xf275f032, 0x25de7144, 0x3c7f832c, 0xbda08cb2,
+	0x0353691c, 0xb9538c4e, 0xfd29336d, 0x07661147, 0x08b47d46, 0x0528c3f3,
+	0xfda08f0e, 0x04a9b5ed, 0x1e7845e6, 0x4f9c8de8, 0xb28d206e, 0x70dfb685,
+	0x74c2b889, 0xe92f1bbc, 0x2ddcbff3, 0x8d14d18e, 0xb62488a4, 0x78f863c7,
+	0x00adc4c5, 0xf45894ff, 0x7b018def, 0xe318e14c, 0x49339c30, 0x1bb476e6,
+	0x2e7b16e9, 0x8dede447, 0x853dfb91, 0xcd58c0fe, 0x66d87805, 0xfb07bf73,
+	0x9506fe7f, 0x46175a24, 0x6a3ed7d6, 0x61537a39, 0x798c94b9, 0x6d1f947b,
+	0xadd707c0, 0xfdc3f2ad, 0x62f5d787, 0x81df03fd, 0x7d66b95e, 0x87d80666,
+	0x511f4e02, 0x7e033e0a, 0x7e32a472, 0x951f5c72, 0x79c9f5c7, 0xbe429fc8,
+	0x9fa0cf80, 0x46606a5d, 0xe50738a2, 0x9fc0f5cf, 0xfd046cdb, 0xb6779fdb,
+	0x12b9034c, 0xfce31ce3, 0x2d572c6f, 0x8547b25b, 0x76645f79, 0x4b977466,
+	0x3c8c635a, 0xc1852bfe, 0x4d5675eb, 0x1bf1009e, 0x2dfb8a9b, 0x162e3c59,
+	0x639d1fcb, 0x59f043f8, 0x51e58d93, 0xa9297e08, 0xbbae2bfb, 0xe2122e4a,
+	0x3f1123c8, 0x28cbf04f, 0x61f3187f, 0xd7e61147, 0xe8a5f919, 0x7d015382,
+	0xb4bf1ed4, 0x089027c5, 0xc8d27605, 0xb992072f, 0xbf26d29f, 0x5e03b65c,
+	0x6497d696, 0xa4fc5d7f, 0x5b47f396, 0x4cacc3ed, 0x5f9f19ef, 0xa8f66148,
+	0x41faab4e, 0x5b85e83e, 0x7b902e4c, 0x70b90dca, 0x325d513f, 0x95288efb,
+	0x4dbea13d, 0x5b667a61, 0x667a8cc8, 0xc1e3cd9b, 0x161cd07d, 0xa78a241f,
+	0x5c9af211, 0x35ce2c5d, 0x0cfcfc31, 0x1aa0bfe7, 0xe212761e, 0x74607f0b,
+	0x014b7a1f, 0x9d25189c, 0x1fb93367, 0x00db4a78, 0x6c3dcbf7, 0x7c0d3a2d,
+	0x04b20c95, 0x35c74f79, 0x38ad77dc, 0xdbfea1ae, 0x2950fbb9, 0x9e0afdd8,
+	0xd76431e7, 0xd062d2a1, 0x37a65627, 0x29fd71cf, 0x4e60c3ea, 0xf70d0fa0,
+	0x4c230d15, 0x53ddc54f, 0x1f937c04, 0x77bb8f6d, 0x0635d1a8, 0xef771ac8,
+	0x98f711d0, 0x7bdc2714, 0x797bc1e3, 0xe1efeee2, 0x67bc60fc, 0xc7927fa6,
+	0xf83f0562, 0x36dd8695, 0xb3276be0, 0xb2ad41c7, 0xa92bcb2f, 0x23fc09ec,
+	0x147f0ce4, 0xf7bfc15f, 0x7cf62e79, 0xbe7c2dc3, 0xb614b88f, 0x61a8dd3f,
+	0x082fe81e, 0xedc82efb, 0x1e6b6f52, 0x5f4b0bd3, 0x5d7c019d, 0xf98ddf38,
+	0xc8a58fb6, 0x2497fcf8, 0x7409e96c, 0xaf182972, 0x92ceaa0a, 0x3df45293,
+	0x81f594a2, 0x4eaed4b8, 0xfe3085c9, 0xb5cf56c3, 0x5a513f00, 0x4377c20e,
+	0x82141786, 0x580db65e, 0x4a760199, 0x1ae14dc0, 0x8516c9bb, 0x6595c043,
+	0xb0f87c65, 0xd6b5e675, 0xd03bec4e, 0x4f47b53b, 0x417be058, 0x39fd60ff,
+	0x3e18f746, 0xf947ba00, 0xea1bba40, 0xdc050f02, 0xbff2dede, 0x25c60f87,
+	0x87e103e2, 0x76ecbf51, 0x1ff78fc0, 0x73b37b97, 0x6fcf2c1d, 0x24778c88,
+	0x9b25f246, 0xb05d8a72, 0xf9d1597f, 0x3e525887, 0xa067ff3a, 0xff766ee7,
+	0x04e7f0b0, 0x45cbe4df, 0x234bafd8, 0x2e83de78, 0xe21fb0d8, 0x823cc349,
+	0x63060eed, 0x744fdff3, 0x59282ea3, 0x72674d60, 0x1bb5efc9, 0xefd09610,
+	0xc715401c, 0x75d7e81d, 0xe2e8bd45, 0x242725f8, 0x03c5ce09, 0x05c95f2b,
+	0x019c33ff, 0x8f300fe3, 0xed3ec30f, 0xb951d66b, 0xeb029f30, 0x8fc09ec8,
+	0xfa59f7af, 0xaf693027, 0x7dbf9977, 0x4fea33a3, 0x97b8fd09, 0xbfc62b77,
+	0xcbf4cadf, 0xcfb66e8d, 0x163d7a0e, 0x801f610e, 0x1487008c, 0x62ba6a9e,
+	0x6a1dbd45, 0x11be78a4, 0xd8f4a0e0, 0xf01a9123, 0xee4c8a17, 0xfbf012cc,
+	0x8015853a, 0x5ffeb9b3, 0x340e20dd, 0x23fbf43e, 0x9178ef00, 0xe7d2eb1f,
+	0x6cfd1ac7, 0xf588ffe1, 0x148ff086, 0x47e1088a, 0x7874fb41, 0xe0e9f14e,
+	0x0c8de0f7, 0xfefe305b, 0x5af3ab78, 0x85779737, 0x98bc63ce, 0x572be5c7,
+	0x4cba5246, 0x5a3f3120, 0x0a4a05bf, 0x2483f8ff, 0x82f18c9c, 0xe7f80516,
+	0x8e449716, 0xadd9f0c5, 0xf875f543, 0xf68aca8d, 0x46fbded7, 0x2242323b,
+	0xff1f9b5f, 0x3e83cb4d, 0x47f62fb6, 0x18f7db1f, 0x2bf643de, 0xed0db0e0,
+	0x1c3bf6cc, 0xb5070f0c, 0x73ed76c4, 0x4dc3ef2e, 0xef10f98d, 0x4bebb3dd,
+	0xee6fa3b4, 0xf05df2fa, 0x569d871b, 0x8767c408, 0x8a981e9f, 0x39a1d271,
+	0xf442be78, 0xc6b4fdeb, 0xe473d84a, 0xdfff711f, 0x5b8f0a01, 0x582cf803,
+	0xf1f671be, 0x0bbfa027, 0xdbc615c7, 0xcd52fc7c, 0xebe20bd3, 0xc81efca5,
+	0xa7f31203, 0x7e01fb44, 0xd6bbdaef, 0x31105e48, 0x3497d2c7, 0xe820bfa0,
+	0xb1a9cb78, 0x78fc95a7, 0x98efc0ba, 0x39afbfe0, 0x295edccf, 0x714e97f6,
+	0xefbd91bc, 0x4ddb3ee3, 0xe02af735, 0x2394dfa7, 0xb8cc7713, 0xe2569ce3,
+	0xfc6b898e, 0x63f06ac3, 0xc4f4bef6, 0xbf8b8804, 0x2f91e325, 0x9fdb686f,
+	0x20dea1f2, 0x3377dc27, 0xd0a6f5e2, 0xfdf00abd, 0x97931b38, 0x7e1fc6f6,
+	0xeb8fe51d, 0xf984de81, 0x9425837f, 0xdf5d231f, 0x8cdbf5dc, 0xf8f17ec6,
+	0x02de8b6e, 0x6f0e82ef, 0x054e2d9c, 0x0747b47c, 0xa6ee9f23, 0x79d3f3f3,
+	0xfcfce985, 0xd37b4fd4, 0x3efac0e7, 0x05d60e5f, 0x9feb7a7f, 0x4f3f00cf,
+	0x0c98e5f0, 0xeac327c6, 0xb620c89e, 0xf88c9d28, 0x74636eea, 0xc0e9fc9b,
+	0x7e3e5414, 0x6ce700d2, 0x536c38ca, 0x57ef1389, 0xbdfcfc24, 0x954dbed1,
+	0xea0318ef, 0x8cdf68d2, 0x738a6d76, 0xd7c3de26, 0x6384bdde, 0x2052aadf,
+	0x5954b3dd, 0x80fbb0aa, 0xe02e9f99, 0x6ff3d231, 0x09b6eca4, 0x19f0db52,
+	0x67071de9, 0x3d353caf, 0x3fc2bc01, 0x4e10f717, 0x78f686f9, 0xd7cf4db8,
+	0x7e8d4fe7, 0x5b6ad41b, 0x8ba46472, 0x83e85db1, 0x00a01852, 0x23f83f4b,
+	0x48596ce3, 0x1a4bd2bf, 0xb579c371, 0x93e449ae, 0xc642bb18, 0xba7e4777,
+	0xb59ec1cf, 0x97154fc5, 0x1193c44c, 0xf6b52be5, 0x55f02b31, 0x8565529d,
+	0x6c1babfd, 0x52a45713, 0xb4fe8c3c, 0x5bee0a78, 0x84089a35, 0xce84c6c6,
+	0x813885ed, 0x1c5d5f38, 0x7c0253da, 0xc0694fb8, 0x05f35375, 0xf8c61bea,
+	0x15a1b599, 0x6ac3f056, 0x0b8c6533, 0xba23481c, 0x6dc7a073, 0x3daaefcc,
+	0x9dc13ade, 0x0a73bda0, 0xdc4c9f6b, 0x6768f999, 0x51be3053, 0xf384daba,
+	0xf6b92d1f, 0x321f8267, 0xd9afdd9d, 0x7f643f5c, 0xe9b78526, 0x1fd434ce,
+	0xba1f6a63, 0x110941d7, 0x3e2177fc, 0xb929996f, 0x95efa39e, 0x2f585d3a,
+	0xeb879d9d, 0x655f21b8, 0xed0f1e4c, 0xd75c54e3, 0x2917918c, 0x3cfa6f10,
+	0xf5802a47, 0x71a92ee1, 0xe4fc1999, 0xe21c6c89, 0x7ac067f0, 0x19f19df3,
+	0xcf20d603, 0x05d5fa88, 0x75ea186b, 0x3ba5b3eb, 0xbf81efce, 0x36f4b04f,
+	0x8e51cf09, 0x7f12e471, 0xae94ff0c, 0xfea4f4a6, 0x7650a4d7, 0xe4f1f031,
+	0xc40932b1, 0x656df1f0, 0x5d881256, 0xb1f3f20f, 0xde2af52d, 0xf8e42037,
+	0x53bfce66, 0xdee865a7, 0x0ede6fa7, 0x886267f6, 0xfcb841c7, 0xd9cb80fc,
+	0x3bfd7ccd, 0x1bab93dd, 0xbf308cb7, 0x65a4cfe6, 0x671d2a74, 0x960f4a76,
+	0x70d2d51f, 0xe5f07318, 0xcf4083ae, 0x618fa0fd, 0x5a2f2b3d, 0x2390fc89,
+	0xb77f00b9, 0xb7edf4b8, 0xe3d7d50e, 0xe8353fee, 0x74e0db81, 0x0faf1c94,
+	0x56dfdc84, 0xc710ab2f, 0xe288adb9, 0xbd61fd17, 0x5eaede7f, 0x107cecb8,
+	0x5bef86dc, 0xb2a4ec2f, 0xefca9436, 0xae1fa16e, 0x7e815722, 0x3f572318,
+	0x4cd2fc01, 0x01399eed, 0x21fb08bf, 0x54a5f3d6, 0xc83f815e, 0xab8c4cd9,
+	0xe544b98e, 0x9eba2336, 0xea0be88f, 0xf812b84f, 0x7ad81f39, 0x221df6ea,
+	0xd4fe83fa, 0x9fdddfc1, 0xb550a318, 0x75700052, 0xd442fe25, 0x2c571857,
+	0x10450385, 0x8739cbdf, 0x42af1b71, 0x5768a7d7, 0x8c7a679f, 0xd2ae0bfe,
+	0xf46ffc15, 0x789c4433, 0x7ff08a52, 0x89117cf4, 0x31514e17, 0xa1f8238e,
+	0xf208f014, 0x38c6453d, 0x21fc7b7e, 0xe29fffc6, 0xe3c2920b, 0xaf48bd7f,
+	0xe083f08e, 0x4617c103, 0x4347f1fb, 0xfb2da75c, 0xf5f29691, 0x1f7f63f6,
+	0x7b74f515, 0x6764887e, 0x7363d97a, 0xb5f37960, 0x0fc0d9b7, 0x83f5c499,
+	0xf89143b0, 0x17c65ad4, 0x29671bfb, 0x05e46fb0, 0xc51790bd, 0x0adf88bb,
+	0x4d58ac3e, 0x9e397e30, 0x7aa6a5eb, 0x8ef3cf16, 0x12900396, 0xec7a1252,
+	0xf9675609, 0xb79e822e, 0x5228be70, 0xf7f028f6, 0x49756e5f, 0xb913882e,
+	0x82703c79, 0x6078c25b, 0x7f823e9c, 0xc75bf6d0, 0xd758014a, 0xa093f519,
+	0x7fde64f7, 0x7df09f1c, 0xdc9f2357, 0xbee5c290, 0x9ffee93b, 0x03c60bf4,
+	0x4db53b5d, 0x7b7df157, 0xbe0d9d74, 0x5ed9c82d, 0xfe02bf96, 0xa6f5d035,
+	0x3bf60a4b, 0xe7ef4535, 0xf05b385c, 0xf20b5c4b, 0xaf798df7, 0x37b4f9c6,
+	0xc7e124fe, 0x8c5ebf73, 0xf2c2b37b, 0xa6768df9, 0xbfc2bb5d, 0x32abd233,
+	0x26bfb125, 0xde1c6bf4, 0x8b6dfeb9, 0x5fe9ed6e, 0x53feefa1, 0x2bf457fa,
+	0xcf1882ec, 0x5adb97a8, 0xbb3d09cf, 0xe309836a, 0xf5f03727, 0xae3c0df2,
+	0xc3f70cfb, 0xdede3c02, 0xf782d17c, 0xb6550653, 0x63dfe53f, 0xd6d038c3,
+	0xe97fccdd, 0xfbe2756d, 0xc6324a0f, 0x641c1e29, 0xd74c3d42, 0x3f308526,
+	0x3e9098a5, 0x85dacfb0, 0x2b56b3ed, 0xe3d432e1, 0x7e40852e, 0xf1959e54,
+	0xfa6f83c1, 0x0fff4067, 0x5a6deb1e, 0x70e37181, 0x4331f803, 0xa7dc140a,
+	0x313b334a, 0x6f54dcce, 0xe6aabcc6, 0x03daffba, 0xf9aa277f, 0xf2c17122,
+	0x39bd5f66, 0x7a044fb2, 0x96fc8c62, 0xcd11790c, 0x0ef3042d, 0x970b4e47,
+	0x06e97ac0, 0xd602b0d2, 0x7635c3e1, 0xa788dd8e, 0xc6de7ca3, 0xbec8847d,
+	0x1bcb3d41, 0x79e14929, 0x06fb7123, 0x6fb8250d, 0x15ae48a0, 0xd33ed124,
+	0x60df667f, 0xf29ce038, 0x7a0c5ff3, 0x7fb1b488, 0xfb6355b0, 0x54872d4c,
+	0x39327e02, 0x5e309995, 0x423eded3, 0xb764eedd, 0x82fb0ed3, 0xdbaf9fcc,
+	0xccedc5dd, 0xfcfdfb6f, 0x986296c6, 0xd36ad6c6, 0x47632b4a, 0xe246bb8c,
+	0x727c4671, 0xbfedc7bc, 0x61a35c84, 0x63c462dd, 0xe2194b71, 0x4fe29bf7,
+	0x13d6c5c8, 0xebe06ec9, 0xb8ba27ad, 0x3c63dc61, 0x3b32e70e, 0xbf7604fe,
+	0x326b78ee, 0x6e6ab3ee, 0x5a1bac27, 0x762e2cd2, 0xf3e3110f, 0x78dee760,
+	0x3c07fc6f, 0xb935b7ae, 0x337d8fe5, 0xd851f763, 0xc51349be, 0x0faa3eeb,
+	0x3cfd5f7f, 0xfe7e03e6, 0x13cc51f2, 0x4c86f85a, 0xadaf102c, 0x85e7e14e,
+	0x03f81a03, 0xee3235e5, 0x18b9534f, 0x5625393c, 0x7960acdf, 0x3dd95b34,
+	0x99afe59f, 0xf7e9e303, 0x927fafe5, 0x4df6f90f, 0xc00e5bcb, 0xbff01fdf,
+	0x33bfb12c, 0x87cc6fe7, 0x95cb9afb, 0x2eb271c4, 0x9d7fe676, 0x034eb3ad,
+	0xccda40ff, 0x79605efe, 0x8e6aaa70, 0xd9a5ef59, 0xd31ef155, 0xec492f0b,
+	0x5f0a097e, 0xe2bf7dec, 0x7d9c06ef, 0xd5f06249, 0xbbf801aa, 0xb79be583,
+	0xbe39c135, 0x5c6623f2, 0x9f3779bf, 0x4b33fbc3, 0xfcc16eb6, 0x4cad6f60,
+	0x09d619f6, 0x9b53f3ba, 0x45e430e5, 0xbfb0d455, 0x98eb4023, 0x4c115527,
+	0xbdb08e7c, 0xb70b3e73, 0x87eebfd6, 0x2feda83c, 0x9dbec1da, 0x0764d869,
+	0xbf7ed3bc, 0xdc62fcf6, 0xc3e0a979, 0xea5e7b5f, 0x5a72610c, 0x379c3762,
+	0x37c19cdb, 0x6383c223, 0x78a3faf3, 0x70b9fc64, 0xe067c5cb, 0xd7d9ef3c,
+	0xe0067b3e, 0xf9d5f45d, 0x0d7f6067, 0xbd60f512, 0x6ff97dea, 0x7c521e78,
+	0xdff72777, 0x117a5e9a, 0xbd3691cf, 0x6f41766f, 0xbb27f54d, 0xa6ca79c1,
+	0x82caff6d, 0xfad2deb8, 0x2e77e831, 0xcffd41dd, 0xa2bafb04, 0x83e8326c,
+	0x1ab1ceb6, 0x66b7b5e9, 0xf380376f, 0xf06f4a73, 0xdfe7237b, 0x2ecf2c82,
+	0x3aadee72, 0xb8e179f1, 0x93356e73, 0x2061bd6f, 0xd40baa94, 0xdde7bb46,
+	0x5e3a530e, 0x55fa01df, 0xeaf3cc3f, 0x73efd312, 0xd3a507f8, 0xf3faeccf,
+	0xe66b17e6, 0xb434fb3c, 0x79b464d5, 0x01dc2dde, 0xc8f389bc, 0x55eeed63,
+	0xd79b9076, 0x85f3c15e, 0x74f1b740, 0x2e5b4da2, 0xdc738376, 0xbb96d4a7,
+	0xda836f30, 0x940b8843, 0xf287bfd7, 0x10e3b4d3, 0x3f0969c6, 0x2244dc17,
+	0x538e763f, 0x98dcf3e2, 0x71c9cec2, 0x3a39c3fc, 0x39f4e3d0, 0xf8c72f3f,
+	0x6ba39c58, 0xbd5cfceb, 0xefbf07bd, 0x77bb13ba, 0x1a87e378, 0x4a20dfbb,
+	0x3468692f, 0x3a2dbd0f, 0x00383c09, 0xcf62430f, 0xa73e2683, 0xcc373918,
+	0x03f405e9, 0xde722fff, 0x6247d693, 0x248f7a5d, 0x1b4d07d0, 0x26d239d8,
+	0xf53df135, 0xad687ce2, 0x9e62ce81, 0x9087c96d, 0xffe0f6d3, 0xc979f8a6,
+	0x8bf1d4ee, 0xcbd9d3c0, 0x87f8f589, 0xddbbe976, 0x8c96e36b, 0x607cdaf7,
+	0xd3f704ef, 0x98f9e51e, 0xcc5acf2c, 0x96f82cf7, 0xbecf4f94, 0x17fde32c,
+	0x517b82ab, 0x85f51b8f, 0xc23597d8, 0xb78739fb, 0x89d996a2, 0x04a5afb3,
+	0xb39fb46c, 0x3f21d66f, 0xd51f5457, 0xc0ef8f20, 0x8b1aede6, 0x01f933d7,
+	0xc71b113b, 0x9eeafb3a, 0x24dbd47c, 0x97f27e71, 0x437a1f5c, 0x56f1c789,
+	0xb38dd39f, 0xfbc41fd0, 0xef1bdab1, 0x0a9ee28c, 0x50699dfd, 0x4cfa3f31,
+	0x8d41c590, 0xedcc7fe3, 0x203ee466, 0xcf412f6a, 0x5768fb88, 0x3cf30468,
+	0xe79626fd, 0x6a7efc69, 0x00d3c32a, 0xee04b387, 0x82d9750b, 0x52b8b9b8,
+	0xd4cdc32e, 0x6c7b9115, 0xf6f7f85c, 0xe4977922, 0x2f309b91, 0x925de452,
+	0x50bd5927, 0x613703d4, 0xfe10e51e, 0xdac03fbe, 0xeb4c2161, 0xecf97eb3,
+	0x2c7efe4d, 0x3320b26f, 0x9cffcfea, 0x829630fa, 0xd5a67ee8, 0xa049fc4c,
+	0x3ebdf82f, 0x22b27f22, 0x3575e449, 0x9ef7f3b2, 0xfa5f9d6c, 0x77a7bb47,
+	0x5b73ec2a, 0x552776c2, 0xc6eb4b29, 0x4e2a1da0, 0xfabe2075, 0x03911f6e,
+	0xc1ffc1fb, 0x76a707f1, 0xa57f1f8a, 0x6ab7faca, 0xe074dfb4, 0x4025be97,
+	0x09ddbee7, 0x831773e6, 0xa3bf4a13, 0x9e7c14cb, 0xfec1c944, 0x073b995e,
+	0xd22b1fe2, 0x2c63cc34, 0xdd00b0a6, 0x5e5c658c, 0x72a9aa68, 0xa5c72d1b,
+	0xcdc875b2, 0x1ebe4ea9, 0x277f6169, 0xffc2d1cc, 0xe7db184e, 0x9682e597,
+	0xe981d830, 0xecbfcc29, 0xdc31f2da, 0xb4eef1ff, 0x37582ebe, 0x7a4c0d4d,
+	0x21b7e610, 0xf00933d5, 0xeeb4befb, 0x9b5f946a, 0x34fc0527, 0xfcb1ddc9,
+	0x8871f8d0, 0xdbf4fc05, 0x61057187, 0xbc18f763, 0xe955943b, 0xa7c01e78,
+	0xae323f18, 0x03d8bf21, 0x13883d71, 0xf11efbf1, 0xce3a7afe, 0xcc26e3f6,
+	0xb64a6f8f, 0x59b47bf3, 0x00b608dc, 0x3fc7def0, 0xbef9972f, 0x5f775f96,
+	0xa7bb2d5c, 0xb89eee3e, 0x08129e83, 0x8bef1839, 0x3b37de33, 0x4f300494,
+	0xdc7f78d4, 0x307ebe08, 0x40f71bde, 0x5d0fb72a, 0xbddd1748, 0x5fd616db,
+	0xf03d5beb, 0x09dc1b9c, 0x6b3c5325, 0x4d0c994e, 0x0d73ca8f, 0x3e708fd5,
+	0x4e7e75f8, 0xc761ffb8, 0x2d7f003d, 0x79435fdc, 0x1dfc177b, 0x072a2d13,
+	0xbb930ffd, 0xb9a75ec1, 0xacd4ff99, 0xd3cb7bb2, 0xbf4058e8, 0xc98fb834,
+	0x89c4fa0e, 0x9bfe1b79, 0x3c7bee09, 0xa0499729, 0x92e9721f, 0x5c47ee1b,
+	0x3dc7cfc9, 0xf6e9326a, 0xca9d7e61, 0xf96fe3f4, 0xefb1633d, 0xb7a04a4d,
+	0xeb654d9f, 0x552cdb85, 0x9f198557, 0x9f740b3d, 0x70a8f26e, 0x599a9b4f,
+	0x331c42a9, 0xce4fca35, 0x13e2092b, 0xeecedfef, 0xab5f7f4b, 0x81ebf39a,
+	0xef66f3d1, 0xc7814600, 0x6fb8e92c, 0xbee38d3b, 0x4d4ce9d5, 0xd5a7818b,
+	0x99dbe426, 0xeadb720a, 0x91e589e9, 0x1f719a1f, 0xcfa688e9, 0x02f71783,
+	0xc480fb89, 0x7da2417d, 0x291586fe, 0xe91f1fe0, 0x74e77443, 0xd2ff5c42,
+	0xf9039ef5, 0xf3a3047f, 0xa67f73fb, 0xff15dfc2, 0x82f48fab, 0xc5f187bf,
+	0x4cdd73f4, 0x73cddf14, 0xd7f8b9ff, 0x79a3ddb4, 0xdcbc04de, 0x1578db9d,
+	0x531dd7c8, 0x4dfa41ce, 0xf9bf7cdc, 0x9e3f653c, 0x61250ecb, 0xef3bc23c,
+	0x4f180acb, 0xe6f687e8, 0x1d972f9b, 0x2a70bd06, 0x8bde09f0, 0xf626c646,
+	0x8dfe8d5f, 0xe71773e0, 0x0db231f3, 0x493356ed, 0x5cac7966, 0x73ee636e,
+	0xb37ee273, 0xe209fc9b, 0x98f62b3a, 0xd99fec08, 0xe1778941, 0x87754882,
+	0x8af6165d, 0xf5942db8, 0xda1fcd21, 0xb95ea54f, 0x17c42569, 0xc8682fe0,
+	0xfa80faf1, 0x56296e2b, 0x4f2bec0f, 0x79d607ac, 0x5a96c056, 0x58607a7b,
+	0xdb7e84d8, 0x5f07d537, 0xe281f419, 0x82be2270, 0x605033e0, 0xc43e1fff,
+	0x8000938b, 0x00008000, 0x00088b1f, 0x00000000, 0x59edff00, 0xe554707b,
+	0xef773f15, 0xc3cdddde, 0x210366e4, 0x804d8404, 0x85701020, 0x5c7c0188,
+	0x94422101, 0xd6da0300, 0x02101ba9, 0x16a52d79, 0x9b8cea9d, 0x8e233480,
+	0xd29dad13, 0x542cce96, 0x2ec4952a, 0x4dd0689a, 0xd15c04ba, 0x63e02711,
+	0xb46d63a0, 0xec083a2d, 0x98f8a71a, 0xe739ec76, 0x647dd7bb, 0xeffa7471,
+	0xe5f98617, 0x7cebdfbb, 0xe3cefce7, 0x648a12fb, 0x40a50307, 0x676a733f,
+	0xf1d31c02, 0xee016bb7, 0x0d1c442a, 0x00f250e0, 0x007f73e6, 0xd63c03c6,
+	0xe9b6dc06, 0xdb007b5a, 0x2ed8c9ae, 0x95d6c801, 0xfc76edf6, 0x06dbb8fd,
+	0xbab60173, 0xc00f77f0, 0xf9e9b1f0, 0xffbf8150, 0xbe956be7, 0x16bcea57,
+	0x373f4d7c, 0xb772b025, 0xecf7000d, 0xb5ddc372, 0x9d701e34, 0x913ac4a2,
+	0x46383668, 0x9dbac401, 0xef289d7b, 0xb1b0b870, 0xddc3db13, 0x5a64d759,
+	0x1e17c2cf, 0x40074ec2, 0xf3e36e8d, 0x91bdb05c, 0x35eb8157, 0x87973cf5,
+	0x33c685c7, 0xd752e6a7, 0x64df0e9b, 0x4e7dcf1d, 0x9aee5bd9, 0xc1ed1d84,
+	0x508fa459, 0x87df2ca4, 0x43b4ccf2, 0xe47b3ec0, 0xf8ddfefa, 0xcb400e71,
+	0xcce3376e, 0x987a9cf0, 0xe223df85, 0x8687b43c, 0x817ad35d, 0xb77b17db,
+	0xff3d69bb, 0x7c4afa5f, 0x470700b9, 0xc4219dc3, 0x2e98be67, 0x4ec1dbe6,
+	0x05e9e7e3, 0xd0402f2c, 0x39170ab6, 0x9c38e1a8, 0x1b0bf177, 0x9ff6b38f,
+	0xaab37bd9, 0x222a89a3, 0xfa80031d, 0x3d3b0ac8, 0xa7accf64, 0x676e1400,
+	0xfdc14105, 0x528297fa, 0x002bfa89, 0x5dfd82af, 0x01f7f1d9, 0xa73ef1db,
+	0x67f61f67, 0xc6e01de9, 0x421cbbf5, 0x8c00d3ff, 0xdf1372e7, 0xc2b2fdad,
+	0x65c806bf, 0xea411bbb, 0x0dc077b7, 0x9b7e89b9, 0xfdcb057e, 0xa7f05d43,
+	0xcb623b2b, 0x53e23945, 0x5cb1f600, 0xf7813909, 0x169ce4b5, 0x7fb4280c,
+	0xa303ecfc, 0x9f7d2e58, 0x7210e487, 0x67aa7842, 0x0dd7cd3f, 0xee96473e,
+	0x74f8d2f1, 0x20b3fcb9, 0x9e09f908, 0x55018fe2, 0xd13b3df8, 0xfb855d76,
+	0x42de0994, 0xe2fb7660, 0xc4da93eb, 0x7cc4aaf3, 0xfb6d7ebf, 0x1db9e40e,
+	0xa9a2afed, 0x70af1073, 0x7c3d39d3, 0x31bca43e, 0x83d0b67a, 0xe394f517,
+	0x8cdffd12, 0x52e6fe47, 0xf38c573b, 0x659cf53a, 0x400feca5, 0x8202d0fe,
+	0x912af7df, 0x00a937b3, 0xcdaf1fe7, 0x9d73c0af, 0xeb6c0db7, 0xd49f71c4,
+	0xd823ca85, 0xfdf3ceae, 0x5efdc75c, 0xaedd6f7c, 0x739fa899, 0x06b79a5d,
+	0xe050c1e7, 0x8fa87189, 0xcf346786, 0x007e4923, 0xc445e3e3, 0xfc7df4df,
+	0x189eda67, 0x58747e47, 0x1db0b8f1, 0x4813e2d3, 0x47f096ee, 0x7978830e,
+	0x078703f8, 0xf81715e7, 0x543f9276, 0x222eb6f5, 0x8e83cebd, 0x0ce23aed,
+	0xaf88f81b, 0x0f5c62a1, 0xbb7e1df7, 0x926b5f7c, 0x85753a1d, 0x7dc407e3,
+	0x0a916b13, 0xfaffd361, 0xf631721f, 0x24c1f91c, 0x1347bf5a, 0xb5e6b33c,
+	0xd238c0c2, 0x631c1b7b, 0x82c7beb4, 0xd9e26af6, 0x775d778c, 0x9fe3491b,
+	0x69f9fd36, 0x41710fda, 0xc90f6f81, 0x43e478db, 0xf39d1e47, 0x8009a19f,
+	0x4f764243, 0xf97b9ebe, 0xf34fe0f8, 0xee3dbf27, 0x8ffef1a0, 0x7415df91,
+	0x079f0f1e, 0x1f23beed, 0xddf078ed, 0xd875e9de, 0xfc2a53df, 0x1dab47b1,
+	0xdf5be347, 0x086b34b9, 0x123231f1, 0xd7d4bf8e, 0x86f49138, 0x4d985ffc,
+	0xf908767e, 0x69f849ef, 0x8a29f905, 0xaffc415e, 0x8e34f6a4, 0xc18e5dc3,
+	0x3d97ec65, 0x44bf2036, 0x203fb3fe, 0x40fdf5ff, 0x781fd1e3, 0xf3f654fe,
+	0x419b41ae, 0xf1c600ed, 0xb85edc29, 0x835dda9a, 0x73f6758b, 0x3679f21b,
+	0x80646bf9, 0x4c0109d7, 0x5029d321, 0xf648aa1b, 0xa3d63cdb, 0xdba7d4cd,
+	0x55d0dff4, 0x9e2f7c9e, 0x53554723, 0xb54f23fc, 0xb502f225, 0x3fdc2bb7,
+	0xed0df1e6, 0xc13fa24f, 0x740799a0, 0x2d383bc1, 0x5d4ff9e2, 0x7d6ffe22,
+	0x4e8afe65, 0x13d6e73c, 0x13f7f72a, 0xce31ca4f, 0x78193c9b, 0xe536e748,
+	0xe7da0f05, 0xfcc543d8, 0x1b6c5afd, 0x1ae74718, 0xba51165b, 0x38eeaaa9,
+	0x36bf384a, 0xbc4348b4, 0xa3c1cefe, 0x19f3709a, 0x81eebfc4, 0x29d8675b,
+	0x42719dee, 0xfdd88a16, 0x67fdfc55, 0xfadb0f50, 0xf219ff51, 0xf9871e06,
+	0x0e3b5007, 0xc7f6478a, 0xdc8e2b14, 0xbc7c4d5f, 0xda26add8, 0x120b4828,
+	0xf417da9b, 0x6c01ed6d, 0xc46057df, 0x71bf9789, 0x8d44e2fb, 0x8aafc9d8,
+	0xde7b2dc8, 0xe28f30fe, 0x98c3b77f, 0x2ee9fc41, 0x0ca14d83, 0xd74f7d3c,
+	0x4e954f98, 0xdfa992d8, 0xa0fc205d, 0x88bb003c, 0xaadd2d47, 0x5fbb441e,
+	0xc70d56e8, 0x431f00d5, 0x8a02ed60, 0xb0630137, 0x01bff518, 0xc8031fac,
+	0xa6894d1e, 0x68daf641, 0x6b1c3736, 0xd63ca1a8, 0x20e83ea4, 0xa4f8da3f,
+	0x55d0e1f6, 0xffc6ee66, 0x27686153, 0x53ff11c5, 0xed82378a, 0xfb527b4d,
+	0x7887c21b, 0xa953c35e, 0xb13a9bdf, 0xddb44aed, 0x3a8c5705, 0x997f033b,
+	0x42b09304, 0x5c711e20, 0xdc70ecd0, 0xd97dbc89, 0x6f4953ed, 0x3f426d07,
+	0x0fd94f18, 0x2cbf2b55, 0x7e287114, 0x2fec8201, 0xf3474207, 0x9df9ae50,
+	0x63da5ea5, 0xcff45dbe, 0xfce52def, 0xbaa0f602, 0x65500d12, 0xde9096f8,
+	0x176f2f51, 0x9937b9e3, 0xfc7411f1, 0xa6cded87, 0x1e91361e, 0x073635d0,
+	0x079ee553, 0x4fb4edc1, 0x3f3c01fd, 0x903c6bce, 0xd7e96fda, 0xb4d3ae6f,
+	0x2c7464fb, 0x75287362, 0xfd1e1f9c, 0xa17aa554, 0x73fbf537, 0x5cc09bc0,
+	0x60133f4b, 0xeb07e902, 0x97b1802b, 0x8ee4678f, 0x344f97a4, 0x329c5751,
+	0xd7fab1d7, 0x41697c9a, 0x344e28f1, 0xf120d505, 0xc8129365, 0xcfb79503,
+	0xd7b943ad, 0xe0f0bc5b, 0x3dc7d43f, 0x9bd67ea6, 0xe173e0bc, 0x4a3de6fc,
+	0xeff38230, 0xfe553479, 0x25baa10d, 0x79233ce3, 0xab53a9b3, 0x6e7e6073,
+	0xb40e2d80, 0x98de48f9, 0x70e800fa, 0xe74afe50, 0xb94f8b4f, 0x6e46dc8c,
+	0x5fffdcdd, 0xe22d46ee, 0xf8da7ca0, 0x201bc52b, 0xe27fbbf9, 0xe791b280,
+	0x60dbecb0, 0xd73cc4f1, 0x56cf3df7, 0x61d3becb, 0xbab7db3a, 0x37d93bf0,
+	0x6f463ebd, 0xc618ff63, 0x9150577c, 0xfcfa4fe0, 0xbd9d6625, 0x5e303774,
+	0xcf2cfde8, 0x8362f383, 0x68c079c3, 0x47bca6ab, 0xf149c9ed, 0xcec0ada6,
+	0xfe2ceefb, 0x500b63c7, 0x690f4b3f, 0xa0e0ac5e, 0x96ad4ae9, 0x95d373f2,
+	0x4e4d14af, 0xe6ed27ca, 0x3687a5f8, 0x9c5165b4, 0x25e293f8, 0x7f858bf7,
+	0x40ed4036, 0x829de2a7, 0xc383a3f3, 0x7b202e6f, 0xa5cce714, 0xb77dfcf5,
+	0x76c2e8cc, 0xaf1cdf74, 0x17ac49ea, 0x2df38b75, 0x7ce352bd, 0xe724be79,
+	0xbf68350f, 0xfb2f6306, 0x9e97f9f1, 0xc79f9077, 0xc62814ba, 0x47c5a28d,
+	0xbea00d9f, 0xd270bfcf, 0xa2f84541, 0xa18e93ee, 0x2e03a96f, 0x50885504,
+	0x3877b03c, 0xdb52bee8, 0x10c72ff3, 0x7d4f45d5, 0x34bd20e0, 0x471c2af4,
+	0x41a8f61a, 0xb47afe0f, 0xf10745ef, 0x8153a5a8, 0xfdc9a531, 0xe663f71a,
+	0xc23e7964, 0x092adffe, 0xf933ae7e, 0xe2d3f168, 0xce333aeb, 0xe54f6fac,
+	0x763046e3, 0x0dfce096, 0x4f1c759d, 0x8e647437, 0xaabc5633, 0x28ead88f,
+	0x4eefd7ee, 0x1bf9b71d, 0x941c061e, 0xd9e3d317, 0xd3878b51, 0x70f11a60,
+	0xa26eb238, 0xe97f791d, 0xa844c364, 0x37afa918, 0xe56d7ccc, 0xf5e9cbcb,
+	0x0e67ef62, 0xf1fe73ca, 0xfc17df1a, 0x48edffe3, 0xe209c9e6, 0x25b7e609,
+	0x3ed94fe1, 0x8b23e135, 0xc0dbbf69, 0xbdfa44d7, 0x53a39c2d, 0x24335bfd,
+	0xd85976fc, 0x242a0c19, 0xdbf38d9f, 0x41da106d, 0x3bf58ff6, 0x92f03fb9,
+	0x981075c2, 0xd4deac71, 0xdfa9bd77, 0x8d5fbc7a, 0x30f54d9b, 0xfae283ea,
+	0x6ea37b55, 0xbf316fec, 0x3476bd37, 0x0cbcf48f, 0x16599c44, 0xb2c67112,
+	0xd2279597, 0xd0331cfd, 0x8ddec98f, 0x823c2761, 0x719b97e3, 0xc6277966,
+	0xdfa46519, 0x30e6c6c7, 0x423d025f, 0xd8bcf4de, 0xfe3a9dd2, 0x2ba8814c,
+	0xf67acd87, 0xd57b34cb, 0x02a721c4, 0x51e65bd7, 0x359e41bd, 0x8ffda768,
+	0xe1fe42cf, 0x933dc7fa, 0x397b1ef8, 0xd669bd3b, 0x057b56e9, 0xc3ea8b12,
+	0x5b91de90, 0xf737e490, 0x3921d860, 0x01a9e61a, 0xbdd27fd2, 0xd2ecc565,
+	0xdd16f78c, 0x1d5fe38d, 0x6bd1febf, 0xc62def92, 0xe1e272de, 0x597f8a2f,
+	0x43e29b33, 0x172788a7, 0x7cdd70ab, 0xeb81c3aa, 0x33a77f5a, 0x3f0bf748,
+	0xadea88f2, 0xf213c4a5, 0x0b72b0cf, 0xfeeb04f1, 0x4afeb4f1, 0xe146192c,
+	0x8af657f9, 0xe2e5647a, 0xaf77994f, 0x46e7164d, 0x74c98dbd, 0xffeab00f,
+	0x9d442f96, 0xb16f7d69, 0xa03df10f, 0x6f30ac25, 0x9cbe07bb, 0xc6f28a50,
+	0x509f3efa, 0x16eb5887, 0x54f5b479, 0x797d5036, 0xa0ceaff1, 0x74bce513,
+	0x1f0fe5f8, 0x2ea5f6c0, 0xf2e63117, 0xc1d95c71, 0x0da2d37e, 0x721d7115,
+	0xebbceb18, 0x7c73bd68, 0xc81ee88f, 0xbc40dbba, 0x5137ceb8, 0xb5bb16ff,
+	0xa9d71b42, 0x9183b06d, 0x3ae499ea, 0xcac75eae, 0x8d864b14, 0x566bfe66,
+	0x7bc42373, 0x57346e2b, 0x883dc625, 0x6b88dffc, 0x533b38dc, 0x5cec08fc,
+	0x1b8c8ca0, 0x777b158d, 0xfd5321ba, 0x977ce113, 0xe3dcef5e, 0x24e6de46,
+	0x1e2a1b78, 0xde84b67a, 0xa13b4e71, 0xffce94b5, 0xafb204d5, 0x9ceb7e75,
+	0x9e7e4ce7, 0xc601fba7, 0x952ad69d, 0x279b65f5, 0x708baad0, 0x7626f31e,
+	0xf5483732, 0x17fe8cfe, 0x8d0788cb, 0xb25c7007, 0x7d1da1ff, 0x90438854,
+	0x421cdcf9, 0x3ce492a1, 0x74e2ffd8, 0x97d91be2, 0xa6fc9dde, 0xb2e5d37d,
+	0xfdc45150, 0xfb88a6d5, 0x287d8f6b, 0xfe4dee8f, 0x306d6ac3, 0xfcd67ec9,
+	0x80fe4d7b, 0xefd3dc5d, 0x7c4420a7, 0xd81e0b0a, 0xef2204fa, 0x1a778ad6,
+	0x334aca0d, 0x7e442ff4, 0x035e4b7c, 0xea6d0b92, 0x33cce2d7, 0xcb1b49ff,
+	0x5c393fe3, 0x03df9c94, 0x8a18eeb4, 0xc04dad7b, 0x28072471, 0x0b1c62ce,
+	0xf97b63e4, 0x97ae2ce9, 0x6abb65a2, 0xa9956e38, 0x5b6b7140, 0xc9a9e6ff,
+	0x05bfe1f9, 0xe91738aa, 0x95aa98a1, 0xa6fec527, 0x9560da1e, 0xbc17cf79,
+	0x7888140d, 0x27a3f782, 0x47ee19dd, 0x6ddeb5df, 0x3d8273ed, 0xfa974ec9,
+	0x0dfef9ea, 0x52a6f85f, 0xef9f019c, 0xfd6dc26a, 0xfbe953f5, 0x57cdfea5,
+	0xd2a4bbf3, 0x02bf9296, 0xd5315f24, 0x7914ef45, 0xefb9bfb0, 0xd460229d,
+	0x276a7e58, 0x6efdafe7, 0x8ec4e751, 0x84fbf164, 0x07826502, 0xdd653930,
+	0xb857eea6, 0x55ea688e, 0x583e648d, 0x22dc7af3, 0x1e261e0f, 0x1486b620,
+	0x487ced83, 0xf3ef5360, 0x16a34f2c, 0x76b63b62, 0x4bbfa26a, 0x3c97d620,
+	0x00ee002f, 0x39feafc9, 0x52754c3c, 0x87964f73, 0x3eb14bde, 0xc4b1f914,
+	0xfa8fdc19, 0x99c2f459, 0xcd5b8a22, 0xf50a682f, 0xbbea50c3, 0x679b736d,
+	0xbde88fc5, 0xe81575e0, 0xda55e1dd, 0xc4b0ed02, 0x4d54d181, 0x1d66efca,
+	0x5f9bb560, 0xc8d4abaa, 0xcb06dbef, 0xe6ce512b, 0x3b4abafe, 0x78b4f419,
+	0xb634ba0f, 0x3009eb91, 0x95b65d84, 0x27f0a634, 0xf7290300, 0xb14e506e,
+	0x8d61631e, 0x03a281df, 0xfde9ca67, 0x6fe4b9a8, 0x7347e4e5, 0x537bc50a,
+	0x554bbd33, 0x7de27c90, 0x4d7f9aca, 0xafb3f0a1, 0x0b7b7f4d, 0x7bcda3bc,
+	0x9e1b2ece, 0x4d1aadff, 0x05eb847f, 0x6edd9f51, 0xb7d5cdc6, 0xbc5f5c69,
+	0xc78d1e05, 0xcca18a1b, 0xfac8bce5, 0xa78cddb9, 0xe352aa2b, 0xf03dcadb,
+	0x91a11670, 0x635b4eb9, 0x0c0abfae, 0x7575775e, 0x6635b8ea, 0x36a6b69d,
+	0x56e7fbf5, 0x930c9cdc, 0xc2ea6e39, 0x66c75b9e, 0xb90c7e71, 0x0cdef93c,
+	0xb475e279, 0xf541c78f, 0x683c0b9a, 0x1c66e3a7, 0x01c92b6d, 0x177e28f7,
+	0xa3fd9209, 0x53bfbed9, 0x719f8ade, 0x34553bf2, 0x1565ce2d, 0x29cd3f0a,
+	0x514a7114, 0x9b276ca2, 0xa3ed9c72, 0xed9baf28, 0xe7ec5237, 0x533bc4d7,
+	0xfc937914, 0xacc27c8e, 0x788aa223, 0x7b974b47, 0x8778a17c, 0x34dfa11a,
+	0x5fd08ebd, 0x36a2de9a, 0x6ec5c751, 0x5ffef856, 0xc519f58e, 0x958bb5af,
+	0x14f141a0, 0x2bfdc0f5, 0x54c3d615, 0x62704f88, 0x8f981dff, 0x4d8beea8,
+	0xb6fd7513, 0xefe2f9b5, 0x9b780124, 0x64f168ec, 0x57e45d85, 0x286b0f8b,
+	0xdf12cebf, 0x6ede9f29, 0x7755d3e6, 0x850af35e, 0xadaf4b45, 0x2f9ca7e4,
+	0xb1463146, 0x475e20be, 0x53c7eafb, 0x917d23dc, 0xf32f479f, 0xadc2742e,
+	0xa72e7eb1, 0x2fd36abf, 0xa839476e, 0x7adefdae, 0xeba5e734, 0x9530bab3,
+	0x2b581887, 0xf2138fc8, 0xc7e6333b, 0x943ca6d5, 0x47e80363, 0xedfd4d6b,
+	0x2eadf7cd, 0x0477efc4, 0x7e4c3d57, 0xb3d94675, 0xce2410ff, 0x9d187a4d,
+	0x85addeb4, 0x090c3de2, 0x9b7ef192, 0x16f0179e, 0xd7b8e016, 0x54af718f,
+	0x241777bc, 0x933eebe9, 0xb161d7d7, 0x079c764a, 0x25de9501, 0xdc3b03ae,
+	0x443b6d45, 0x200b88ec, 0xfe81dfc2, 0x4fc45608, 0x9d73fcea, 0x9944723d,
+	0xeff8e3c5, 0x9061f343, 0x7108ddc7, 0x3b740346, 0x32f042e1, 0xcb22b956,
+	0x08af6ca9, 0x4baa5485, 0x82f64523, 0x5213a8b3, 0x2473a665, 0xb38763ce,
+	0xd2a2fd56, 0x0b6011df, 0x3cfd3dd9, 0x0c79d61d, 0x0d4a4bc1, 0x555ca177,
+	0x93695210, 0x1548601b, 0x39f32ff1, 0x4ddd6016, 0x01b8b77f, 0xfacd9fed,
+	0xebf8f208, 0xa66a3ce9, 0xaf2d0cf3, 0xeb1615e0, 0x29129f24, 0xf39d7db2,
+	0x2b11cfdd, 0x6f375e02, 0x03e2fc7d, 0xfbbf8995, 0x9eafc378, 0x2a3d3fa6,
+	0xd3f70186, 0x665c4ddf, 0x9fb11add, 0x788f86ff, 0xe17dfd3f, 0x5215dfba,
+	0x7ce8f23c, 0x8781f04e, 0xf60638f8, 0xb23f74e8, 0x7142b8d1, 0x128b8fdc,
+	0x5c103bbc, 0x2f21b1e5, 0xf2e518ee, 0x43cca5aa, 0xab8d675e, 0xcf7a4ae3,
+	0xe14e4d43, 0x91e4c1ba, 0x6aab7f25, 0x2af891fc, 0x8944a251, 0x944a2512,
+	0x44a25128, 0x4a251289, 0xa2512894, 0x25128944, 0x5128944a, 0x128944a2,
+	0x28944a25, 0x8944a251, 0x944a2512, 0x44a25128, 0x4a251289, 0xa2512894,
+	0x25128944, 0x5128944a, 0x128944a2, 0x28944a25, 0x8944a251, 0x944a2512,
+	0x44a25128, 0x4a251289, 0xa2512894, 0x25128944, 0x5128944a, 0x128944a2,
+	0x28944a25, 0xffe12251, 0x72255300, 0x008000ab, 0x00000000, 0x00088b1f,
+	0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1,
+	0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f,
+	0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1,
+	0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f,
+	0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1,
+	0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f,
+	0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1,
+	0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f,
+	0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1,
+	0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f,
+	0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1,
+	0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0x00001000, 0x00002080, 0x00003100,
+	0x00004180, 0x00005200, 0x00006280, 0x00007300, 0x00008380, 0x00009400,
+	0x0000a480, 0x0000b500, 0x0000c580, 0x0000d600, 0x0000e680, 0x0000f700,
+	0x00010780, 0x00011800, 0x00012880, 0x00013900, 0x00014980, 0x00015a00,
+	0x00016a80, 0x00017b00, 0x00018b80, 0x00019c00, 0x0001ac80, 0x0001bd00,
+	0x0001cd80, 0x0001de00, 0x0001ee80, 0x0001ff00, 0x00000000, 0x00010001,
+	0x000e0004, 0xcccccccd, 0xffffffff, 0xffffffff, 0xcccc0201, 0xcccccccc,
+	0x00100000, 0x00000000, 0x00000000, 0xffffffff, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,
+	0x40000000, 0x40000000, 0x00088b1f, 0x00000000, 0x1113ff00, 0x51f86066,
+	0x423ec08f, 0xac9d0c0c, 0xc4b462a8, 0x1818990b, 0x12b102fe, 0x3c430333,
+	0x203aded0, 0x2388107d, 0x16181858, 0x2fd610b0, 0x022bd404, 0x2c4062c4,
+	0x19b7c401, 0x9cdfb348, 0x1f0f680b, 0xc8037f82, 0x3f4024be, 0x1c360fff,
+	0xfb5f40ad, 0x1819d502, 0x8aa06bfe, 0xf2a26831, 0x9bf13519, 0xcf2684c1,
+	0x2167c68c, 0x63247fa0, 0x0d75b600, 0x000400f1, 0x00000000, 0x00088b1f,
+	0x00000000, 0x7dd5ff00, 0xd554780b, 0x673ef0b5, 0xf3399cce, 0x00fde4cc,
+	0x108f0992, 0x2104e034, 0x0432b445, 0x3b69488c, 0xc514543c, 0xf791e109,
+	0xb14a3e44, 0x44033bd2, 0x350af808, 0x0380a050, 0xed168d02, 0x06823ca0,
+	0xfda2901c, 0x5a1bdedb, 0xcb6ab7bd, 0x880b851f, 0x52d11921, 0xf77ac5ea,
+	0xcc9f7b5a, 0xd0049339, 0x9fdffed6, 0xcfb3767e, 0xd6bdaf7e, 0xf7b5ebda,
+	0xa441c448, 0x84be421c, 0xfc8471bf, 0xa484205e, 0x83bf52c6, 0xa908a3a6,
+	0x2d0867d9, 0xc26425cf, 0x5c64633e, 0x136fcd0a, 0x179a2642, 0xbcb19b0f,
+	0xfbcb3373, 0xdd4f6d0d, 0x01c9cb4a, 0x1349d903, 0x49116f92, 0x1467211a,
+	0xd146fec2, 0xf321117c, 0xb35b2ccd, 0x426cc8ed, 0x98b797eb, 0x3fb69988,
+	0x81e0d7b3, 0x429dc2fc, 0xd439d088, 0x67255c1c, 0x8417fed1, 0x45d9b084,
+	0x47e93bf3, 0xd7b15e5a, 0x5dfa8210, 0xaf34b68e, 0x01f3908d, 0x9864b885,
+	0xed693bdf, 0x86548405, 0xd16494f6, 0x05bb957a, 0xa9c748b7, 0xc6442cdc,
+	0x42ef828d, 0xa8bb40c8, 0x5712b66a, 0x97c39b3e, 0x75c5c704, 0xc742dc2c,
+	0xa912fda5, 0x61daf651, 0xcbb2b5bc, 0xf9cf831e, 0x51c71380, 0xd3cf35f3,
+	0xdabb6871, 0x2c370497, 0xbe2456b1, 0xf3bf1d30, 0x73e679a0, 0x32df5836,
+	0x5daecf39, 0x587ee947, 0x9b686547, 0x7983625c, 0x17e7936d, 0x6aabfac4,
+	0x6bcfd64e, 0x9f74a0c3, 0x3d3e3ca6, 0x95c4201f, 0x1257cb17, 0x60db09e2,
+	0xea7921fe, 0x63f7d8f0, 0xb3f71124, 0x5c40d9aa, 0x427fac4a, 0x40ddf882,
+	0x2b8011dc, 0xb5bbb569, 0xa9d176fb, 0x8985b7df, 0xf31f6dbc, 0xc3ef9a79,
+	0x27a70e5a, 0x4d347e61, 0x499738f0, 0x1309fd74, 0x4ab85389, 0x3246b5fb,
+	0x7acbdc33, 0x186405ef, 0x888f884d, 0xe25adf38, 0x2ed21fbb, 0x4e9caeb1,
+	0x3245fe9e, 0xabbd74bc, 0xfbfed604, 0x57f585c4, 0xb03d900d, 0x2aef6baf,
+	0xcb90ce7a, 0xf90292d7, 0xd0d6bbf9, 0x7926932e, 0x0257c008, 0x614015b8,
+	0xcb40d07b, 0x4713bbed, 0xe16971ae, 0xc61f3c57, 0x75128c73, 0xcdbce3fb,
+	0x4d27cba2, 0xaf838a4c, 0x46e679cd, 0x34f3a79e, 0xd211d189, 0x67c64220,
+	0x8b6f882b, 0x9ba465b3, 0x79b3b7c5, 0x85b6ce2d, 0x38ff3482, 0xe685b834,
+	0xce4ddf65, 0x4741e05e, 0xa4064916, 0xe98c913e, 0x7000de59, 0x9c5078a4,
+	0x03ef2573, 0x68c5fa9a, 0x1f4d225e, 0x0107c616, 0x8e012b2e, 0x481ab534,
+	0x6adbac1d, 0x86a70822, 0x05cf4521, 0x9d5a7035, 0x1b94e14b, 0xb1b577eb,
+	0x09b8832e, 0x23bc1359, 0xf8526528, 0x1dcdd2e6, 0x23bdf30b, 0xdb4c1c12,
+	0x00ce2ee7, 0xa5322a78, 0x32f8ed03, 0xc700bf1d, 0xae38046f, 0x3f18fbe7,
+	0x463792be, 0x6079be37, 0xb37c6eb9, 0x38a7c74c, 0x5df829b9, 0x63853e3e,
+	0x233f2116, 0x95f1c5df, 0xfc704b81, 0xeb949906, 0x8f74b7c6, 0x7771821f,
+	0x437e31f5, 0xfafd58de, 0xd7ea5607, 0xbff5b32f, 0x8f9bbc10, 0xfff5c16f,
+	0xd6cddc82, 0x6c47f03f, 0xafda26fd, 0x37477c76, 0xf700c3fc, 0x5fc07dfd,
+	0x7e9b7a19, 0xf5aa83fd, 0xf1b137eb, 0xc83e0d5f, 0xf8e1b7c7, 0xd90791af,
+	0xc52d07fa, 0x3aa64df1, 0x991693b7, 0x21752c72, 0xfd176bc0, 0x074d3a5f,
+	0x45be71d3, 0x422482d3, 0x901ffb68, 0xc5870881, 0xa850df16, 0xf142c97f,
+	0x0be316cd, 0x0052b424, 0x38e5afba, 0xa977773d, 0x326d24fc, 0x4bf185b7,
+	0x10e9f942, 0x96cebf3a, 0x4fbd2f4f, 0x47773be7, 0x42e0dba1, 0x6ed0247a,
+	0xdf8a5f1e, 0x8841e0c0, 0x1daa7b37, 0x7b3793f8, 0xf22c70da, 0x40599f00,
+	0xf03d8e70, 0xf1a35e78, 0xbe86bb4c, 0xe7d06c16, 0xbcfa422b, 0x80f1ef3a,
+	0x160d3424, 0x3a3afc93, 0x8fca19ee, 0x1f93e508, 0xe9047e52, 0x08792359,
+	0x94d38dce, 0x4b59115f, 0x5f70cb57, 0xfe0c48ce, 0x91583667, 0x7dad2f1e,
+	0x60832658, 0x640a563e, 0xf24178cd, 0xff9d3e76, 0x089d7c3d, 0x57e022e7,
+	0xb4f73d6c, 0x47a14cd6, 0xb2779d2c, 0x31a75dae, 0xf5be0462, 0x963d0920,
+	0x7b2ffb41, 0x87d18f62, 0x4fd3c7fc, 0xfd26ba44, 0xf7d74a44, 0xd87e34ce,
+	0x733769ae, 0x3f635aef, 0xd3e7de9a, 0xae559f7f, 0x431a77cf, 0xe5ce1146,
+	0xa36c810a, 0xa7583ffd, 0xf9c7572f, 0x7db1248c, 0x43dde3e6, 0x049992d7,
+	0xfe91fa59, 0xeb64e7db, 0x497ae7a0, 0xca1f383f, 0x9a4ef704, 0x8dea107f,
+	0x4b7c7d84, 0xe7b3ef86, 0x90d7ba25, 0x5225f39e, 0x9273f606, 0x25271b9f,
+	0x08b753e3, 0x7edfe73d, 0x4711ead8, 0xfc475cf4, 0x4e221fbc, 0x968787dc,
+	0x0697bfe8, 0xf0c7d7e3, 0x3e32dfc0, 0x7be6b4f9, 0xe4aef84d, 0xa97c1ad3,
+	0xcbaa9e6a, 0xd3ee8457, 0xa1b05fd5, 0xaf3e5754, 0x5e5742b1, 0x2eb0f0d6,
+	0x447c1a5f, 0x25a1ff57, 0x0fe574cb, 0x95d6add6, 0xab5f2acf, 0xdbe7dfcb,
+	0xef7faba8, 0x72ba6dcc, 0x0e4570e1, 0xd97e37c8, 0xe1499397, 0x135de17e,
+	0xf0c42ed9, 0x73f3c558, 0xcf4c0c81, 0x2e985c07, 0xf4a57a03, 0xa9641e2f,
+	0x0e697b7f, 0xf78ab9d0, 0xd9758d67, 0xf8f12740, 0xf18f4f1d, 0x03780c78,
+	0xe75f50e7, 0xbc40b579, 0x025df740, 0xefd48f3b, 0x97fce67f, 0x6f48e590,
+	0xc7a332d5, 0x8b3397ea, 0xe5aa5e81, 0xad9d5e48, 0x58497eef, 0xb21075c0,
+	0x08a9fb1d, 0xedd0aa51, 0x3cdd20eb, 0x70188e3b, 0x3e105afc, 0xdef3816e,
+	0xf8c02a5b, 0xa7b23791, 0x78f9870f, 0x25be60e6, 0x4762f915, 0x69f25260,
+	0xc5e7e009, 0x26605cf4, 0x3e0267a6, 0xca074f4c, 0x5030fd31, 0x607b6987,
+	0x0327a609, 0x14ff4c41, 0xbdf4c068, 0x7fa62340, 0xf4c06c0c, 0x4c21033f,
+	0x4c1e033b, 0x14d4f1bb, 0x90f903cd, 0x20226fbc, 0x2e1492e2, 0x3372a97f,
+	0x5c85f961, 0x2e0bee6e, 0x27defbf1, 0xbc5048fc, 0x2c59beda, 0xa8e83f6c,
+	0xf3a50893, 0xbbf6c335, 0x44bcb0e7, 0xdd843f90, 0xbbb2f95a, 0xf483d85f,
+	0x9fc7ef6b, 0xf381dce1, 0x9e030def, 0x8af2247f, 0x0b5dba7b, 0xc047ba0f,
+	0x86b75e6f, 0xd5fe5276, 0x7c31705f, 0x2e5c06b9, 0x039cf5be, 0x0cc2e8f8,
+	0xe6fa79d1, 0x1357d7be, 0x34da75ce, 0xe8b7f1f3, 0x851b17f3, 0x741e4c49,
+	0x0e18cc25, 0x9e74e0f8, 0x96fb0c1e, 0xcfdaa981, 0x79d90cc2, 0x85ea193a,
+	0x77643d70, 0xd517e222, 0x3fdeb047, 0xf57d1e7b, 0x5ec79b13, 0x47b68a72,
+	0xdf507b19, 0x0bc4fbf5, 0xe41933e9, 0xbc6ad268, 0x85aae704, 0x40e5f7fe,
+	0xbcc257e8, 0x6c3fafda, 0x826e9a08, 0xe375bbef, 0x552e76d1, 0x7d7683d7,
+	0xce449fe3, 0x5941f8a8, 0x6fae09d2, 0x9d9b3556, 0xa89d7e7a, 0x325bfbcb,
+	0x0dfe3a9d, 0x4af4a0ff, 0x9c120a26, 0x2b1cd5bb, 0x835b24ba, 0x1bb7e740,
+	0x8bee86f0, 0x6af5605f, 0x47d97694, 0x67dc2d3f, 0xe17df3c7, 0x05efae5a,
+	0x9fb41b49, 0x70778633, 0xd34ace85, 0x449ce51f, 0x9e32f9a4, 0x39aef553,
+	0x7cf0ab7b, 0x94126fff, 0xc8ff3ce1, 0xe70458d0, 0x9b786553, 0x76fba1ec,
+	0x80938881, 0xbf205cef, 0x91acdc77, 0x3208afe3, 0x41acb7ae, 0x79516e7f,
+	0xf2a79747, 0x9f3f2e8e, 0x3d034b4c, 0x91937e6a, 0xff285e8a, 0x043bcae8,
+	0x80bbf627, 0xfe04add4, 0xcdef6a7e, 0x700adcf7, 0xc8a5b03c, 0x6873f347,
+	0xbf4a3f71, 0x6427cd95, 0x3aaf93a0, 0x1fb4057e, 0x755c73d9, 0x51f43d5d,
+	0x669a870e, 0x85ea13c1, 0xa6459b9f, 0x9f74a9d7, 0x72753a25, 0x7e5c5e5b,
+	0xf6fe5c64, 0xc6d7fcb8, 0x908a149f, 0xdefdb169, 0x44f2f82d, 0x478043e0,
+	0xf9bc3109, 0xf467fdda, 0x3fe47fe8, 0x44feffb5, 0xffb4ff87, 0xfda9ffdb,
+	0xff31ee0f, 0x5ff5bdc9, 0x149e8a6b, 0xdd7b1ce0, 0xe198e78c, 0x7a0839b0,
+	0x19ab7f82, 0xf637dcf5, 0xd01775fd, 0x26b3e75d, 0x8e7a6262, 0x93bff280,
+	0xdf767bf5, 0x0ffeb75f, 0x8d0b3f2d, 0xb60b7f69, 0xef80fad2, 0x64c8adbb,
+	0x184e5eba, 0x2f5d2841, 0xefd1fd78, 0x2e2f2a11, 0x91dee2b0, 0x0f4cbf05,
+	0x51fb00ad, 0x799fcb2a, 0x08284071, 0xed979e76, 0x1808c311, 0xa3ed40f7,
+	0xad2fee30, 0xa42d1e84, 0xd61375f3, 0xa305fceb, 0x2ee78a7f, 0x24415e9d,
+	0xe77e3757, 0xb5241c02, 0xe052f85c, 0xf0e22840, 0xd55ef4a1, 0x8f31e092,
+	0xfbeaf800, 0x2e8c60b9, 0x0eff2376, 0x5bc88966, 0x77205922, 0xcb53d7c7,
+	0x5540e2fd, 0xb6ec581e, 0xfd53eac5, 0x37cb3e79, 0xa0fd3166, 0x052feb0d,
+	0x958d49fa, 0xd597ecf7, 0xcec891ff, 0xac3f58db, 0x53d72d7d, 0x1572e9e3,
+	0xe6aacba7, 0xa6f6862f, 0x7f32f55f, 0xa65fbefc, 0xafdd0582, 0x10e6cbe0,
+	0x23b5616c, 0x6bef7a82, 0x6d511edc, 0x9e1ea089, 0x3905c7c5, 0x6944f20f,
+	0x8ced097f, 0xf404cc07, 0xedd79add, 0x9adfd81e, 0xf33d7ffd, 0x63bdfa33,
+	0xf80dd59f, 0x0ffaf350, 0x4c6bdf71, 0xdd02d991, 0x2a1ee8bf, 0x1dfad2ff,
+	0x4d9d7e7b, 0xc61d3f68, 0x55d27648, 0x613565ec, 0xcafc9c53, 0xe03e7de6,
+	0x98f2019e, 0x3b5447ca, 0x53fb7c5a, 0x45cff162, 0x4417970a, 0x7c88b34f,
+	0xa9df6f4b, 0x5d39525c, 0xfdabde7b, 0xbecc4a54, 0xc43f7ea4, 0x1ba87be1,
+	0x2e935fce, 0xf2e83d6d, 0x02ebcc10, 0xf3834b69, 0x13f9b6a8, 0x4aed4419,
+	0x2e813590, 0xbee032df, 0xa12b9b10, 0x4d4df937, 0x4cc605cf, 0x75de5097,
+	0xfedfea63, 0xc28b2381, 0x4f86fe7f, 0xe91ce1b2, 0x199e643a, 0x7f39fd42,
+	0xbf1834ba, 0xa0f5dca3, 0x51eb8ac1, 0xe3a4abc7, 0xf5b10bd5, 0x755c6b5f,
+	0xaefc753c, 0xcfac9f8d, 0x69f8e174, 0xb8fc7e30, 0x5c753b6a, 0xde7c572a,
+	0xd886978d, 0x414b96fe, 0x72c3ce19, 0x947ee122, 0x14797a93, 0xcd8841d2,
+	0x74ed4977, 0x97ca9f90, 0x4a5d3edc, 0xf900f366, 0x6901e60d, 0x5ef1c6d7,
+	0xfb7fa380, 0x3a520554, 0x305f5c0f, 0x221a16d3, 0x3ca0f9b0, 0x7d414c1f,
+	0x777be257, 0xe9fdf026, 0x17b87f4c, 0xb81d39fb, 0xf1c6f313, 0x1437c875,
+	0x85a988d2, 0x1ffd3184, 0x8f9c46f1, 0x90238a8d, 0x98f81aa7, 0x0e11c359,
+	0xb6245979, 0xe913f87e, 0xcdbf2b38, 0x572ddad7, 0x30e1c53d, 0x580679c5,
+	0xbe47d066, 0x08ae5da4, 0xa3f364cc, 0xbe5128f8, 0x517f84e5, 0xc79d3a78,
+	0x103826ff, 0x4a7ad9ef, 0x5d056848, 0x7c73248f, 0xbe184c99, 0x5e265c34,
+	0xdd3c1d8d, 0x090ef8c0, 0xe83e411e, 0x5fc1fde0, 0x9451e694, 0x245655a7,
+	0x7802df64, 0x089270e1, 0x91b7638c, 0xd8047588, 0x5af3a551, 0x1b79c1f9,
+	0xa8ecebcd, 0x3a78f2fa, 0xb14bed53, 0x7e70db71, 0xe2cfdfb4, 0xae2cfdfa,
+	0xd6aecfdf, 0xbf270aaf, 0x740bddb2, 0x87c058fc, 0xa78ea6fb, 0x7c28f1f0,
+	0x113f51f2, 0x429dee2d, 0xd616ae0c, 0x22633d15, 0xc0337fb8, 0xf4e14ce8,
+	0xe8e1c278, 0xb29050a3, 0xd7fe0081, 0xfd353b73, 0xed34daf3, 0x7a415388,
+	0x99c7cd5e, 0xa1fc6061, 0x9ecff39e, 0xee78cdf5, 0xee6fa8f7, 0xf7a5beab,
+	0xe6bef6fa, 0x3e75ed63, 0xd55f955f, 0xff5ffebe, 0xf869711e, 0x52829396,
+	0x30ccaf2f, 0x126b7ed0, 0x1dbdfccf, 0x0f5144bf, 0xf7ebfa51, 0x4af802cb,
+	0x5832c7f1, 0xa056ddff, 0xf05ee7df, 0xd74996c5, 0x63af9331, 0x14e97366,
+	0x86264738, 0x526496a6, 0x5abfbf3c, 0x17709b70, 0xbce8ffe9, 0xbaf3e3ee,
+	0x3a4051bf, 0x21917fb8, 0x6ec5eae4, 0x41fe0b35, 0x09d567cb, 0xd3d088a1,
+	0x1b4b057e, 0x3e760696, 0x3b4f6e36, 0xeaf1045c, 0x6cde3e21, 0x0c1a4a42,
+	0x845bed3d, 0xef2957e3, 0x35dede27, 0x2ed1b887, 0xffcf2f16, 0xe463e419,
+	0x91b921c7, 0x46c1afee, 0x31e416f1, 0xfe8dc583, 0x3037fe90, 0xdc2159fd,
+	0x2e5047ce, 0xa4040722, 0x573e8bfb, 0xec55d242, 0x33025b30, 0x62f0ced1,
+	0xd9a60360, 0xce043c8b, 0x412f6961, 0xa05b7f79, 0xdf0fbf1c, 0xd1942edb,
+	0x176ce4bc, 0x6774d3e6, 0x1f7e0960, 0x3fafaf58, 0x644baf7c, 0xd4225cf5,
+	0xc3e0367b, 0xea05cf7a, 0x7cf5bed0, 0x3ff301a0, 0xcd31040f, 0x95f3626b,
+	0x2fe82a96, 0x11a045fc, 0x18fed1eb, 0x41427aff, 0x2f7c3cfe, 0x79b797ab,
+	0x2dd6084c, 0x777e7939, 0x197fe639, 0x377f6108, 0xb5fde0ec, 0xb30b9412,
+	0xb3afdd17, 0xce96b863, 0x030fc9d1, 0xe5752beb, 0x3f063aea, 0x6f5750b1,
+	0x5890def8, 0xfdf30056, 0xe4bbee91, 0xffe0890c, 0x5cbcdfcb, 0x3b0dcfd7,
+	0x15eae8d6, 0xae89feec, 0x4ddec47c, 0x75bbbcba, 0xeeaf2ebb, 0xca65f54f,
+	0x5679e9d8, 0x4205f975, 0x2fdb3f28, 0xf4375e79, 0x075cb722, 0x76bca05e,
+	0x69f87c2d, 0x5c7083c0, 0x4840f545, 0xb3fcb833, 0x3493ec1a, 0x27d838ff,
+	0xecc82fd1, 0x3b734f54, 0x3e40dad5, 0xe0267f7e, 0xc0bafcc6, 0x0c6fcc18,
+	0xcffcc24c, 0xdfcc5e02, 0x09bf3123, 0xf00da9e0, 0xda3359f4, 0xe9671087,
+	0x525b5d7f, 0x923f2043, 0x32f1c68c, 0xa2e637e4, 0x3f709a5d, 0xb3a70543,
+	0x955687b3, 0x7122a6ac, 0x288beb55, 0x9939511f, 0x4e9adc80, 0xefd6bd79,
+	0x037f2d77, 0xfef58395, 0x0721b987, 0x258aadf0, 0x0a29c993, 0xcfcda3ef,
+	0xfae9da39, 0x432c762b, 0x3abcbb7d, 0x6d20bb28, 0xd3fd067e, 0x0dc4d5e5,
+	0xb6e547c7, 0x4b9eff6d, 0x99f55dc7, 0x0f80da40, 0x0107214b, 0x91b376bf,
+	0xde58ae72, 0x009cfcdc, 0xd93b34f3, 0xee9d98be, 0x0a79e208, 0xc5710f71,
+	0x519cdaf0, 0x7f6e7e87, 0xe825f47a, 0x3c87dcdf, 0x2ee92bfb, 0xe50d1a41,
+	0x8a30c46d, 0xf7d80cd1, 0x78582f1f, 0xe791ec04, 0x80b7201f, 0x6bf1e73f,
+	0xe74ecbcc, 0x4eeded05, 0x93bb0b06, 0xf36393fb, 0x1d96ff42, 0x9b1b95e6,
+	0xe5e89d97, 0x52bccd62, 0x772854a4, 0x4ece780a, 0xf04f1824, 0x79fa6df4,
+	0xb2f30d3d, 0x44af3df5, 0xebc02f3a, 0xc4af0e44, 0xfd42f09e, 0x5e0e3134,
+	0x6bc37d89, 0x912bcc28, 0xf4230578, 0xebc18333, 0x79fa2999, 0x780d733d,
+	0x4179d2a5, 0xaf0e54fb, 0xc2f09ed4, 0xbc1c6a7c, 0xd786fb52, 0xd2979858,
+	0x0df1d45f, 0x8e8b60cb, 0xefc0d82f, 0xfb5729a7, 0xd2ca8c73, 0xfddf4f7d,
+	0x005150b0, 0xdd40d3f2, 0x3789a4f7, 0x5329f2e8, 0x4ffaea46, 0x9756319b,
+	0x58a078cf, 0x3b9acf97, 0x7fbed759, 0x795d34f5, 0x191103fa, 0xcb9a8bf4,
+	0xd6f9e3db, 0x7c2f523d, 0x0728cbab, 0x35d7cec1, 0x4163c99c, 0xbd63ca81,
+	0x3e8baff0, 0x5b17db86, 0xff436f87, 0x39789fea, 0x1fb40bc7, 0xe0f03d83,
+	0x55f7f450, 0x13ddfa73, 0xf3be4668, 0x7c8c204a, 0x6fb71f68, 0x8738801d,
+	0x0381823c, 0xd378df68, 0x82788215, 0x19e6dfea, 0xfceb3ce0, 0xfc13329d,
+	0x8be69dae, 0xefc8230e, 0x3771d452, 0xa94107cd, 0x8905b881, 0x1f6dea4c,
+	0xb7f38dff, 0x9ecf07e5, 0x1d2f7e84, 0xb44cbb34, 0x56af09df, 0xf9a7643c,
+	0xdd98f7da, 0xfbfe2fa4, 0x63f7c92b, 0x97e62706, 0x93f97da9, 0x5f8e8411,
+	0x00d13bb8, 0x180aa7fc, 0x07f82a44, 0x1f41b3db, 0x05ec791a, 0xfd47fc1d,
+	0xfedd65f6, 0x230b1e14, 0x43f752df, 0x7ee84f3d, 0x8538c034, 0x56e3e07d,
+	0xe225db89, 0x067f74f9, 0xa7c0b3af, 0xbfe59569, 0x9697eca3, 0xda6cdfcf,
+	0xbf9ceb0e, 0xe071d961, 0x1cb767cb, 0x0bbefe38, 0xdbe3a1a7, 0xb9435f54,
+	0xe7f36bf0, 0x53dcf07f, 0xbd7e22f1, 0x119b9755, 0x70f9dd2e, 0xbdcef6ef,
+	0x7b53d312, 0x57b7d3c2, 0x18587f42, 0x2eaa8ee3, 0x7bdf84bf, 0xd42eb1ca,
+	0xd539172f, 0xfdc9b5f9, 0x601d0f80, 0x8545d97e, 0x2fc812e1, 0xbdd1317a,
+	0xf95faa02, 0x46834bf2, 0xda345ece, 0x2af0be93, 0xddea91f6, 0xc5ea1226,
+	0x4625d23e, 0x48d2996b, 0x578a50e5, 0x2768965d, 0xf5477fe4, 0x986349fa,
+	0x12e20abd, 0x62daa59a, 0xbf36ac69, 0xfaca58b0, 0x4d42faea, 0xdfc7c7eb,
+	0x817d3127, 0x427f07ea, 0xf5e814f8, 0xe84f5506, 0xae703d6b, 0x0cec3ea3,
+	0xbbaf5af7, 0x728d75dc, 0xd2e51ae5, 0x45ffca35, 0xcf29f7e3, 0x55ea66bf,
+	0xe058bf9e, 0xd03e074a, 0x76098f45, 0xe064468e, 0x2d0d555f, 0x1adf3f0c,
+	0x8ff9009d, 0x7d5abeb9, 0x72f8c439, 0x5cd79588, 0x788108a6, 0xd426e2ca,
+	0x49163f7e, 0xe17c6f79, 0x1fd32356, 0x20ff5a6b, 0x73cf80bb, 0x7ce1a93a,
+	0x4532e6a4, 0x695f4a28, 0x1bd61346, 0xfe233466, 0xef491915, 0xad8d9f72,
+	0x8027e54f, 0xce4fc093, 0x3cc5cc6e, 0xf5f227e5, 0x8e1a93f0, 0x9f955f67,
+	0x02f30adc, 0xf3da54bc, 0xf7905e30, 0xdaeebf13, 0xa9c20746, 0xfe80ce9b,
+	0xed7e066f, 0x02a63429, 0xf71809dd, 0x4262dd58, 0xa356e439, 0x5eebed8b,
+	0xbeac4fe6, 0x03f18bbc, 0x17d38d89, 0x538fc7be, 0xe3a2d8d5, 0x16f83d4b,
+	0xff8c578f, 0xf1919f7e, 0xe2848bef, 0xfc4f4147, 0xafa2f150, 0x5b2e6b7e,
+	0xdee8f374, 0x767deeef, 0xc6c73ee0, 0x953c7053, 0xa470aa1f, 0x38dbb9f0,
+	0x627c27ba, 0x38412970, 0x48fb7276, 0xc98d5f3c, 0xc55edc0f, 0x81e3d9f9,
+	0xb5adde3f, 0x38fb5af7, 0x387156c7, 0xd1040eac, 0xf51d242e, 0x5aaec138,
+	0x6f07766f, 0x49f0c437, 0xa164d8e6, 0x9d035e62, 0x849525a7, 0x16a6d196,
+	0xe7f02b98, 0x2af8825c, 0xfe1d24d9, 0xaf3429c8, 0x288db7e3, 0x13069b27,
+	0xe957f001, 0x615f2faf, 0x6b3af164, 0x4b3bb7f2, 0x927fbce9, 0xb820fbff,
+	0x6d601dd2, 0xebfda033, 0x63bfaea2, 0xca64dcd2, 0xfcf8132f, 0x72d1b79c,
+	0xc1e6f8cd, 0xade4014e, 0x76fa89a4, 0x0cb070f1, 0x8abfeba6, 0x1c524cdd,
+	0x20a197e8, 0xc2317662, 0x612230e5, 0x272ae8dc, 0xadcb47e3, 0x95d7a40e,
+	0x63ee2239, 0xadb7b713, 0xc81b3b07, 0xfc848a52, 0xeac894cb, 0xb44109cb,
+	0x4ec199a3, 0x8a7d806b, 0xda4ede60, 0xeb009f31, 0xb8f2041e, 0x4c9fd70b,
+	0x6f412b22, 0xbedf1aef, 0x164fbe18, 0xfe02cf7d, 0x3b6cca5c, 0xd53d8029,
+	0xf40a1beb, 0x2c10c1be, 0xcffad174, 0x5085a21a, 0xfd169b2f, 0x39a58931,
+	0xd3e4d710, 0xff987ff8, 0xf437963b, 0x912ce7cc, 0x5721fce2, 0x5fcb6a86,
+	0x012f3d10, 0x129ca79d, 0xba909e50, 0x09bd4de3, 0x2bf70f10, 0xb1878f23,
+	0x2fe93d31, 0x8f4cb9ad, 0xeac721ed, 0xf70537f9, 0x79ba63f4, 0x63f2e3b9,
+	0xd8d31fa6, 0x2797fdc3, 0x0ec1f8ea, 0x1d8d03a0, 0x11e4b07d, 0xa4355fc1,
+	0xcabf7e91, 0x6dd6bf7e, 0x601a0cbf, 0xf8f1f77e, 0xb3d5220b, 0x22f78f3c,
+	0xff744bb0, 0x6cd455df, 0x593bcb3d, 0xf9873fce, 0xc0f9baf3, 0xec045361,
+	0xce1eef7b, 0xdcfb062c, 0x51e8c66b, 0x3ff5c82b, 0xfdcdf260, 0x5a331cef,
+	0xedefba69, 0x4b9076ed, 0x9cfa724f, 0xd846a24d, 0x0f8f1f47, 0xaafaed53,
+	0x55ca8c5d, 0x0f9be046, 0x7f774244, 0x3c1ee697, 0x1c2efa16, 0x8adfb397,
+	0x9ad80afe, 0xb12cec2f, 0x16bb4d12, 0x679671f7, 0x45eb34ed, 0x57ad8e7c,
+	0xd668f5c1, 0x5b15fb8b, 0x50f082af, 0xfc19fbd7, 0x787ce69f, 0x14fbe8db,
+	0xdd7e33f0, 0x5b344ad5, 0xfbf8881a, 0x5a9bc057, 0x8d272f83, 0x00c2e3ae,
+	0x5854d0df, 0xf2325b4f, 0x6ff8bebf, 0xf466fc77, 0xcdb71606, 0xf386a7f1,
+	0x86fb15fb, 0xe11d8026, 0x220daffc, 0x21e7ddc8, 0xbf7e921e, 0x81343cd8,
+	0x73bec55c, 0x2e75db8e, 0xe8095d3a, 0x911d094f, 0xbec00b4b, 0x539e4471,
+	0x9a9eb3d0, 0x91ed0f2f, 0xb20ed14b, 0xa2388647, 0x1af71e1a, 0x993f7fdf,
+	0x6379c1d1, 0x20e804b8, 0x04e0a2fa, 0xeed55eff, 0x5ed1c73d, 0x247123b2,
+	0x710d2f8b, 0x08db473f, 0x908a9fd8, 0x146f1f41, 0x91057266, 0xb0cc46da,
+	0x8f52e16b, 0x63fd34ed, 0xed57dcfc, 0x31496cbf, 0xbb720539, 0xfa0f1cec,
+	0xc32b7043, 0x1e89b2cf, 0x33f69d83, 0x7f4041b6, 0xdba72de5, 0xaca98e31,
+	0xbf409129, 0x472c8f65, 0x9b6d533f, 0xf81da5ab, 0x0f704864, 0x794fe021,
+	0x14c7f0b8, 0xb28eeb1e, 0xc3fc807d, 0xb8f32fe8, 0x6fbb1a6c, 0xd0aeb187,
+	0xa0f0f409, 0x5cf203cd, 0xbbcf0ce9, 0x205957e0, 0xfe008e45, 0x7d2ceba8,
+	0x0e0635c0, 0xd9b0d285, 0x2442a983, 0xa56be50b, 0x4d205112, 0x86648997,
+	0xffcfeb7c, 0x6c289cc2, 0xa216e9bd, 0xfebfefb0, 0x8de1e01b, 0x8edeb2cd,
+	0x6fe7d619, 0x0be7d16a, 0xcdfcfa23, 0x4ff3e96f, 0xf74941c0, 0x0c2fb5f7,
+	0x37f088c4, 0x47fe0085, 0x8588990f, 0x97eaabae, 0x2703d466, 0x9cf0d954,
+	0x7305f8f8, 0xde47f208, 0xec08b57b, 0xb4bf954b, 0x6f01b8b3, 0xaf2825f8,
+	0x811fa97a, 0x0dff7273, 0x8cb7b544, 0xff64b900, 0x3ed80ddf, 0x9fed3cfa,
+	0xe0f8ffd6, 0x947a5fcf, 0xf9f8ffb6, 0x1210497e, 0xdf87d594, 0xef59aabb,
+	0x41ba1e1f, 0x2161ff3f, 0x664abe7d, 0x2f0bfafa, 0x187e2ac8, 0xdba5df18,
+	0x17f5c695, 0x907f9697, 0x6e20fd45, 0x8182e400, 0x4455efb1, 0xbf46afd3,
+	0xe1e9c89f, 0x019dc05c, 0xc88a63e7, 0x85cfeae2, 0x7a0348de, 0x1bc768fa,
+	0xe74f4069, 0x4fd04b03, 0x6767bd55, 0xd5e79c12, 0xf0e1bfcf, 0xaedf7a40,
+	0xdc82c6a7, 0x0c21bcf4, 0xd3dfa0f3, 0xf8477be0, 0xf4598e57, 0xc91db9fb,
+	0xd17def88, 0x30a8457b, 0x7c0e7b43, 0x8ee87c55, 0x383272a3, 0x9de3181c,
+	0x0fba5dfe, 0x780d9b55, 0x7c2aa65f, 0x038677f7, 0xa2366c1d, 0x8f7aabdd,
+	0xbe3ea091, 0x7bb456ed, 0x813eed55, 0x8dfec771, 0x5e5718a5, 0x61af1124,
+	0x664cba24, 0x75ae7a40, 0xb7ec039f, 0x926e7f55, 0xefc81725, 0x78a3fdfa,
+	0x548c7180, 0x069a28f2, 0xb2cf494e, 0xa9bff022, 0x57ae7bdf, 0x5f7e3edf,
+	0x78d5915e, 0xddaf9225, 0xc97af8df, 0x37688253, 0x5cb25ea9, 0x7d500f17,
+	0xfe0651ba, 0x4a0e3f1a, 0xfa739a90, 0x017f0835, 0xeb917f3a, 0x51ce5439,
+	0xc3cfa2e8, 0x3cb106bf, 0x80952b9c, 0x1bfeb047, 0x851744c8, 0x3234d547,
+	0x032cd209, 0xe42c7bc1, 0xefefe615, 0x7a0473a0, 0x237dd8e8, 0x84bab7da,
+	0xc33f5df6, 0xb7c8edfe, 0x07119c3a, 0xb6544dc4, 0xe2ee319a, 0xf2320be3,
+	0x37e1658d, 0xdc6f101c, 0x145992f1, 0xf1f5b0a9, 0x8362e49e, 0x37e7f003,
+	0x4e19aecc, 0x571d962e, 0x7b9a2fd1, 0x00f8b78f, 0xafcf49fe, 0x273d94ff,
+	0x7d678064, 0xe98b9e32, 0xbd8575c9, 0xedaafdc5, 0x42bae452, 0xb3d3c817,
+	0x5aefdc6d, 0x72f80b9f, 0x06e197d1, 0x6054a979, 0xf4480efd, 0xed7e849e,
+	0x924bd6cc, 0x076c32de, 0x70653a7c, 0xf852762f, 0x945e25cd, 0xf28ee60b,
+	0xa48740c9, 0x96fdc59e, 0x51222449, 0xf80cb039, 0xa3cc08ea, 0x59b65efc,
+	0xb9a2f8c0, 0xe775184f, 0x69e1c400, 0x1a4e57d7, 0x124adfb1, 0xb37cb4c6,
+	0xf802bcbe, 0xa5578534, 0x95e0fcc2, 0xf0718c3b, 0x5a3ea089, 0x930bfbbd,
+	0xfd751c76, 0xfaea217f, 0xd1e5973c, 0xfd45fd4c, 0xf70129be, 0xd8c8ffd9,
+	0xe65f380c, 0xf8e0f699, 0x985cfc55, 0x7e58ea4f, 0xa00c8922, 0xeba3cfe3,
+	0x9e607382, 0x918e8242, 0x92309f2c, 0xdf93c7ad, 0x0eb03d73, 0x36f277ed,
+	0x56aaafdb, 0xd61c3221, 0xf20de743, 0x5b47ac37, 0xb3af9aaf, 0xaefd377a,
+	0x7690ffb5, 0xf7bb5fac, 0x5fae930b, 0xe7a0cf6e, 0x7dd33110, 0x37cdd758,
+	0x71b4c343, 0xe1bdaa23, 0xbac78724, 0x0267e7bb, 0x720d3dbd, 0xd8071658,
+	0x8127aa18, 0x032c676f, 0xb7c742ac, 0xc79ddcdc, 0x2ce5a2f2, 0x76b4c83f,
+	0x54fe86c2, 0x32fa310f, 0x3329ae41, 0x68438f78, 0x37c54ece, 0x29c744d4,
+	0x12d93d93, 0x1e4f75f2, 0xb09659da, 0x6474fff5, 0x5ebab0dd, 0xbf7518e4,
+	0x08e10bd6, 0x641d43c6, 0xbd7c41f2, 0x4fc62671, 0x1fb68e12, 0xdd173e07,
+	0x5a11e547, 0xc1f0a36f, 0x6de3b071, 0x5645cbbc, 0xdd067cd0, 0x1b77e01f,
+	0x502f5205, 0x4bda8cb8, 0xa3d01be5, 0xd4378ef7, 0x4cdd70d8, 0x6dd6b06e,
+	0xfa47fb03, 0x0123f943, 0xb930ef5f, 0xdd741e70, 0xe5a34d0f, 0xb983cb19,
+	0x384bff60, 0x0ede6a1a, 0x8b70efe7, 0xa74bc61b, 0x6127b1b0, 0x7fe700da,
+	0x023c2906, 0xc5319574, 0x88ec1235, 0xffac1ceb, 0xd0f0d154, 0x46539054,
+	0x28d27cb2, 0xfb8ed9e2, 0x49c716b3, 0x30499137, 0xf20ef83f, 0xb3d6ed17,
+	0xc4349107, 0x5d4275f6, 0x3e9f8c21, 0x7064a588, 0x8bcbca06, 0x9eaa7cb8,
+	0xf7f59f6f, 0xea3f0024, 0x3f01f7e2, 0x201279b3, 0x1b1c8c8e, 0x9fed6a26,
+	0x0345fd6a, 0xdf50e93c, 0xc124597f, 0x287fe464, 0x5e67fa5f, 0xff857b42,
+	0x1a824cb2, 0x9cbfec3e, 0xd777cfa4, 0xb1f6c34b, 0x4a12167a, 0x839eadee,
+	0x11fd7484, 0x7f2d7f7d, 0xec24f5e5, 0x77698c8f, 0xe9d91c80, 0xdb3e476a,
+	0x46831215, 0x1174f7aa, 0x9dc1f182, 0x6d5df64e, 0x265339df, 0xa2679411,
+	0x40474fd8, 0xb2630881, 0xf413f5a9, 0x1eb7561f, 0x35ef8129, 0x7ce30da4,
+	0x1256c26b, 0xdbffc5ec, 0x970b0011, 0x3f29fce6, 0xfdd4ed8a, 0x9037b588,
+	0xb38fd690, 0x52222da2, 0xeab75a5a, 0xc00a2bd7, 0xd3947704, 0x2b37f04d,
+	0x72d1b73c, 0x23a3a883, 0xba6ea8eb, 0x275f3242, 0x061d181a, 0xe262bb7f,
+	0xaf3c9a6d, 0xf83edddf, 0x291309bb, 0x602a8ddd, 0xf55d9fed, 0x972c6fef,
+	0xae807c62, 0xd76bdb3f, 0xbcb895e4, 0x6b87e68d, 0xf2b8cef2, 0x8cf2b894,
+	0x567f7cb8, 0xc91ec3bf, 0x1ca9b836, 0x13f7eab7, 0x3a4fca24, 0xa9b32332,
+	0x309e4f04, 0x226133bc, 0x6a8f8dc4, 0x5a79c0f3, 0x59b82adb, 0x5f830fb8,
+	0xb9e19bad, 0x832eddcd, 0xaa3adf7f, 0x7688b8ed, 0x7209c12a, 0x27bc2da6,
+	0xe7687982, 0x330bb4d2, 0xfc3aa4fd, 0xb3ebb601, 0xe9117cff, 0x87fe4d7c,
+	0x765aef58, 0x8faf9274, 0x6e2bef83, 0x3be0b770, 0x92bd026a, 0x77bf9144,
+	0x992ff9ec, 0x7c633fdd, 0xf3d333ab, 0x43adf206, 0xb7cb5382, 0xa41f30fc,
+	0x0e5c65e7, 0x935c7062, 0xb886517f, 0xb787f78d, 0xa9c703be, 0xcb27d175,
+	0x73fb1e40, 0x20d1d9cd, 0x1f2d809f, 0x217af4f8, 0xd6f18664, 0x7861a18b,
+	0xc866adff, 0x7a05d111, 0xf016fb7c, 0x75574417, 0xda4ffc22, 0x284007db,
+	0x9755c5fb, 0x7db53e59, 0x5dc7ec0b, 0x009b7f0d, 0x0e4f1ef7, 0xd2201f68,
+	0x8355a5fc, 0x487e6227, 0xf7c816fb, 0x3f2c1c53, 0x81807dbc, 0x0921cfb6,
+	0x76ff6113, 0x8abf193a, 0x3967bfe7, 0xf7e755ff, 0x29cf7f4e, 0x66a90b80,
+	0x1c0b7dfc, 0xed9f94cf, 0x73b538ec, 0x9d9fdd17, 0x9fc8cc4b, 0x10bc6429,
+	0xe1ce938f, 0xf20ee78c, 0x8df50953, 0x926b384c, 0xcf68fb62, 0x7f21736e,
+	0x0f6ea1be, 0xb3e9d79c, 0xff3f900b, 0xac99ec87, 0xfdd2c6a4, 0xfad29a36,
+	0xe3271593, 0xed1106a7, 0xda8fe99e, 0xda78fe51, 0x0561d6cc, 0x1b534afe,
+	0x7c2b8fdf, 0x4c4c571d, 0xdf24b91f, 0xdacdfd81, 0x950cf946, 0x240966db,
+	0x309c80a8, 0x81394655, 0x3341a3aa, 0xdc5537cd, 0xddd27180, 0x335ad2fa,
+	0xd0a9bfce, 0x26760993, 0x9a693f55, 0xd44cc9ea, 0xdb4d65c8, 0x67cab958,
+	0x5e69729b, 0x12102e73, 0xad9779c6, 0xbb424dcf, 0xf3eec4bc, 0x743b5fac,
+	0x573c1afb, 0x9b3ae1a7, 0x68664312, 0x2fffc2a7, 0xf0c93dfd, 0xbef57efd,
+	0x7507df28, 0xd30ac9dc, 0xec0cca87, 0xf1527e3c, 0x44cb3ae1, 0x39a208cf,
+	0x4d03279f, 0xa448e068, 0xfdf0d1f6, 0x8c7843ff, 0xa3fdf586, 0xf1daf8f0,
+	0x84fc71c5, 0xa0bb8df2, 0x67259aff, 0xf30cdc79, 0x5df0a9bf, 0xe98c442f,
+	0x77b06f8c, 0xd077e804, 0x3e4c0abb, 0xe753b42f, 0x1ad1fb3d, 0xf5d4d794,
+	0x60787f58, 0x9d99dc12, 0xc5fe795d, 0xecfdb49d, 0xf775591f, 0xa4be5581,
+	0xae46bde2, 0x11eec618, 0x4fbb29ab, 0xe80a7208, 0x3aeaed77, 0xc4264f24,
+	0x18afaf8b, 0x609e8228, 0x828ff805, 0xb7432efb, 0x9c18132f, 0x9caa9e60,
+	0x08bb8843, 0x2953b3d6, 0xf97d86ae, 0xa05e2952, 0xf071b2a4, 0xa75e097c,
+	0x03d78dfd, 0x7aeae779, 0xfc72610d, 0xefa604a6, 0xd0f10249, 0x8dffcdf9,
+	0x811adb71, 0x13e21f03, 0xb0bb30b6, 0xc357972a, 0x79f74ee9, 0xe7e3973e,
+	0xc17e3973, 0x1deea306, 0x3e908a82, 0xbcd89a4f, 0x523eb9aa, 0x9fb0da45,
+	0xbd7d66aa, 0xd82faa6a, 0x83bf701d, 0x8690f1ca, 0xf9eae5f5, 0xc2f96fe1,
+	0xa0f77fa4, 0xa361f711, 0x09f1c999, 0x8fb93d23, 0xb5fc7f01, 0xffcde511,
+	0xc2a2fbe6, 0xf1624061, 0x8b5f00c3, 0x9ff84441, 0xec394916, 0x95c0676f,
+	0x93307831, 0x02f5a76f, 0x9aaf35bf, 0x361f01cb, 0xffcea22b, 0x64628f78,
+	0xcce5c37e, 0x4fbd1e9e, 0xc8133b46, 0xffbd5ac1, 0xe7d54539, 0x10ff72d7,
+	0x129a33d3, 0xa9bedc99, 0xe9077049, 0x2b4d277c, 0x5ff800af, 0xc021699c,
+	0x3d72e76a, 0x746a42f3, 0xfaadc031, 0x76bb4bbe, 0x7c37d011, 0x74be022f,
+	0xc7ecd18a, 0x967fd172, 0x0fb3fe00, 0x7cef8c43, 0xfdc0eb48, 0x9dab6098,
+	0x4f1355c5, 0xefda3ce6, 0x6ee9d5a9, 0xe3533b88, 0x641d4e49, 0x46f5cbfe,
+	0xf3dc096f, 0xfa63ee0d, 0x574687c3, 0xeb23dc36, 0xd011caf2, 0xd744cbbb,
+	0x7b2025d6, 0xaaf6b61d, 0x5a9ff85f, 0xfeae7180, 0x23dfa5ca, 0xfdd3d157,
+	0xbd3d7a2d, 0x61b34493, 0x07ca9b5d, 0xfc742386, 0x6e61d6ce, 0x40cad666,
+	0x93ad4be3, 0xd54d3dd5, 0x7187bc3a, 0xbdf088c8, 0xff91fede, 0xf0fc7ed1,
+	0x684bf06f, 0xef681fed, 0x7a43dbd0, 0xfabed9e6, 0x7e674d5f, 0xeff2b892,
+	0xb093becb, 0xf93fb50f, 0x0825c9eb, 0x37d228d7, 0x3e7a6469, 0xa144779d,
+	0xb46f4fed, 0xdda77f23, 0xf9fdbde1, 0xbe053654, 0xd194b393, 0xf486f55b,
+	0x4837606d, 0x57eac89c, 0x768a186f, 0xfedcb184, 0xea40df3b, 0x133ba015,
+	0xa1390069, 0x696ae4cc, 0x9c63c4d7, 0x5bd267b9, 0xbcb45f40, 0x0dabca1e,
+	0x82fcdeec, 0x8da2b6b6, 0xecc22f30, 0x02cde5c3, 0x78c53881, 0xdad115fb,
+	0x3560a889, 0x80cdbc36, 0x55d83f4a, 0x55df63f2, 0xbf79ee3a, 0x3d26efe5,
+	0xbf2a82dc, 0x7abd31f1, 0x9ff83a70, 0x901c7a54, 0x48cc95e8, 0xe074ae07,
+	0x3e0c67a7, 0xe02c97b4, 0xb82b1bf7, 0x478eaf9e, 0x3be30df9, 0x281fb70a,
+	0x2d70aecc, 0x47daa3fe, 0x0f403b54, 0xf294b3be, 0xf37d119d, 0x0aea421d,
+	0x80f84ed1, 0xd2740dcd, 0xfe70ff83, 0xba53eea6, 0xd8d0f8cc, 0xd10321a5,
+	0x6497b9c8, 0xcd3697cf, 0xa3ffe2b9, 0x826eb8a2, 0xb40c97bc, 0xbe365c81,
+	0xf70a91d2, 0xcebf98dc, 0xdb3c46da, 0x662df7e8, 0xfed02f2a, 0x90b871ee,
+	0x0cc8647f, 0x97928c0f, 0xa2f2d214, 0xfb9436e2, 0x09c4a9a3, 0xc6decefc,
+	0xa762dffa, 0x3b4246ed, 0xdbba77c6, 0xa2dea42b, 0x2afc5f69, 0xe9725fbb,
+	0xdfed1da0, 0x734b1297, 0xbe748f80, 0xa77e476a, 0xba53bbfa, 0x8958d5df,
+	0x1e1db9eb, 0xd5854a45, 0x3d03f715, 0xfb93088b, 0xd86277b1, 0xf46358b9,
+	0xe9ff00e5, 0x9644d778, 0xe08b7ed3, 0xbc54a231, 0xef0257b7, 0x2ebed536,
+	0xca486400, 0x8216772b, 0x5864d91d, 0xf7428f74, 0x34b0c4a7, 0x576d08fa,
+	0x04e6c033, 0x9cc4c293, 0x7de7fd3f, 0x5ed1ff34, 0xaba7de23, 0x266139d8,
+	0xa2fad1d8, 0xa2fbf8ff, 0x7975bf74, 0xbcbabfba, 0xbf9f45bf, 0x814f6cd7,
+	0x36942cfb, 0xd8cf70dd, 0xb73baa64, 0xf4d7ce8d, 0x354dc99a, 0xd9b37211,
+	0xe81980f7, 0x071e8c5d, 0x3a729978, 0xe17c8046, 0xc044fd6f, 0x559250f7,
+	0x072f80ff, 0x9992e7e8, 0xf3efb3c1, 0x9eec289b, 0x6967551d, 0xc36d94da,
+	0x597a68fd, 0x6f8c0908, 0x045d194f, 0xf7e130e7, 0x97183c4f, 0x265367e5,
+	0x4cfefc4d, 0x68437ed3, 0xded79c19, 0x5c27bc72, 0x856bcf4b, 0xb87177e6,
+	0x8b47d557, 0x53445ee0, 0x3061a4d2, 0xc90be92f, 0x0abbfb0b, 0x17c8d13a,
+	0x3fe2cdcb, 0x115a3f76, 0x2d89efe2, 0x7b873a07, 0xf8e9e39b, 0x0cf8bee3,
+	0xe8532ee3, 0xc9cfc030, 0xee376656, 0xfda21652, 0x43ae6fda, 0x44b8d5bf,
+	0x60b5d709, 0xa0242d80, 0x9f20991d, 0x3932260c, 0xcb41611a, 0xffb986cf,
+	0x0b4e0e3a, 0x9ab930b6, 0xbbe033ec, 0xc1400b31, 0xd5fbb902, 0x700f18a9,
+	0xc9a7f376, 0x5b6e01e3, 0xbb0270ef, 0xccbdf5a2, 0x8369e78f, 0xada4bbf7,
+	0xbd0172df, 0x6262db1f, 0x765448f3, 0xfb8f7ec1, 0x837280c2, 0xc81f1224,
+	0x67b24d0d, 0x6b91d018, 0x8012cef3, 0x59a9d9eb, 0x517fd622, 0x37184e20,
+	0x7c1a4971, 0x5e48205f, 0xfdfa3f46, 0xa26bf753, 0x05c99939, 0x7f782b86,
+	0x4db4d8fa, 0x3e3dcf18, 0xc6f7f367, 0x8d3b7f42, 0xd2846f78, 0x3e703dc7,
+	0xc0f5d0d4, 0xbcb66a7c, 0xb38cc693, 0x628a4484, 0xa3fcdbef, 0xaab26074,
+	0x07975c78, 0xf2c16c7c, 0x3bed3cba, 0x78f03d1e, 0x1b9ba533, 0x166078a9,
+	0xaf2097c8, 0x35ea4ff7, 0x1e5e293e, 0xc54af555, 0x6d3b3c4d, 0x08f3d768,
+	0x329d3f94, 0x4e47c84b, 0x27ac6599, 0xf3616dfd, 0x3f105cef, 0xd02dfbeb,
+	0x60f10e5f, 0xea2b853c, 0x0ee2a62c, 0x69cf0080, 0x9fc599b2, 0xf51f73d1,
+	0x44a9f5a0, 0xffd1aef7, 0x3a51fde5, 0xb2f0077e, 0xc72bddf3, 0xd9b5ae01,
+	0x8f40231d, 0x0cfe5ff0, 0x56b65eed, 0xb9b4f766, 0x0d9e64bd, 0x992a7be8,
+	0x83e3105b, 0xcfe3377e, 0xd1baebf1, 0x63f16462, 0xc7ec5129, 0xd7f4656a,
+	0x4df6f5c4, 0xf7a82c4b, 0x99094a6d, 0x955fd261, 0x573f54ce, 0x2a63b705,
+	0x7b415e3b, 0x4e09090e, 0x2e296bf0, 0xe55d2746, 0x3fcf11b3, 0x882831da,
+	0xd1e3bdf9, 0xf1db65af, 0x8040c35c, 0x83f30b53, 0x0eeddcd9, 0x3b47df58,
+	0x7d60394e, 0xb80c3be5, 0x27d0f2ee, 0x620af369, 0xf049bd74, 0xfaf3c15d,
+	0x46b59d0a, 0xc768fb4f, 0x6d7369a7, 0x730a4f4c, 0x706f417b, 0x2f1952f9,
+	0xc65c2858, 0x751d9839, 0xf7c453dc, 0x386de232, 0x4f6f6b5b, 0x6af3b0b5,
+	0x0dc9859c, 0x7ad0d6e3, 0x7c618788, 0x1ebe29cf, 0x57a32079, 0xf8fc6d3b,
+	0xb4441be7, 0x26ac56a3, 0xff3d6768, 0xf46c81fc, 0x903cee6b, 0x5f53473d,
+	0x6f8c3f8d, 0xf1616d9f, 0xa7f1a41f, 0xe20d251e, 0x7378d83d, 0x2007cabc,
+	0x3b86909f, 0x1e38fa3c, 0xbd4d130a, 0xa7c40dae, 0xefd58a0c, 0x01dcff2a,
+	0x5a736a71, 0xb413110d, 0xa70678f7, 0xebcbbc80, 0x2f77f7c7, 0x45a123c7,
+	0x5ac93d40, 0xfa3e4510, 0x1134f9b5, 0x4d3e5a6c, 0xe324f7f7, 0xf0e3d1d3,
+	0x19d813ee, 0x6b933ce1, 0xf5c8126d, 0x5e182b69, 0xa2207f45, 0xc435ddfc,
+	0xf9522f52, 0xb0cace45, 0xb14aff01, 0x01acb8b0, 0xbf58f959, 0x1a679efb,
+	0x4999e7bb, 0x8a7e30ea, 0x1f51db38, 0x38863fee, 0x580d0e41, 0x41911c98,
+	0x830c1bdc, 0x7a3c9820, 0xf10151ea, 0x8e7c03c4, 0xa9ea0a88, 0x3f185f14,
+	0xfa33e477, 0xf952f0e6, 0xa02ad0a8, 0x92db371c, 0x862bf5c8, 0xa3c2d757,
+	0x3c62ffd9, 0x778ea05a, 0x12e478bd, 0x5be1f5c8, 0x1fc2761f, 0x845fb828,
+	0xf0a771fb, 0x3628a67e, 0xb880af7c, 0xf1dd1d8d, 0xcd9fb464, 0xfd04de54,
+	0xf62bb541, 0x62ea515b, 0x76b6e07e, 0xdface790, 0x7c5cf052, 0x05cb6c5c,
+	0xcede3a79, 0x11367748, 0x533801ce, 0x1f94bd61, 0x5797fb30, 0x9d71fbc6,
+	0xe21b8f01, 0x44880607, 0xcfdf3e02, 0x35ef8b90, 0xdd380bf6, 0x59dc182b,
+	0xbb1e631c, 0xb12b5c0f, 0x075942fb, 0x1772c912, 0x5f4cc7c8, 0xcb8eface,
+	0x78b52e0d, 0x225346ff, 0x7ea987b3, 0x69ecbef7, 0x9f4f41a4, 0xcbad5daa,
+	0x537e174e, 0x0659ce0c, 0x85049f3e, 0x41ee4fdf, 0x35c00ae7, 0xff510c6d,
+	0x4b3e4036, 0x14fe37cd, 0xae957bcf, 0xbd9d7b55, 0x736b9bc0, 0x7abb9213,
+	0x8be031dd, 0xb8e7efd7, 0xfdd5e57f, 0x025dff1c, 0x9e7a0e7e, 0xb4c39776,
+	0xe6ab39e9, 0xae12203d, 0x21cac7b2, 0x11695ece, 0x2575fb78, 0xde5c4877,
+	0x3ee7f1c2, 0x3caaef06, 0xf1ba266d, 0xe293f3b4, 0x629087fa, 0xdfad4b9b,
+	0x5bfa1138, 0x83e79237, 0x5f83d41f, 0xbea369e7, 0x6f29043f, 0x029a990f,
+	0xc9f07fd6, 0x1a9fc741, 0xe1ef3b1c, 0xa97807fc, 0xf7aafee7, 0x44de34a6,
+	0x3f3ab2c7, 0xf50778c5, 0xf4a7f6fc, 0x24e22f7e, 0xff5fe3e7, 0x761e841d,
+	0x261693ca, 0xc90096df, 0xf9003d51, 0x17a97fb2, 0x9ca825e3, 0xb7cc21f1,
+	0x338eddf3, 0xe7796847, 0xf78fcfb4, 0x7d6e3c03, 0x31e83678, 0xfa03b7e0,
+	0x501b37f1, 0x055a55ce, 0x462d6f86, 0x7f1517a4, 0x7f1c9d2a, 0x7f788312,
+	0x3090e9b0, 0x5445ec1a, 0x9bbecd3f, 0xd5b165ee, 0x31c70173, 0x533fdfea,
+	0xeccad953, 0xe2fcfe56, 0xffd0798d, 0xf9c0810e, 0xc3ff26bf, 0xbfa8b9b4,
+	0x4f36907c, 0x65a2aed3, 0x691f8b1d, 0x470af636, 0xfa606ad9, 0x1e7dc1dc,
+	0x43e70be0, 0xca4b1618, 0x906ad0a5, 0x45cbcb57, 0x8546efd4, 0xbe43ef4a,
+	0x2026533d, 0x5c587787, 0xd3cd1e6c, 0xe42f1083, 0xbf81ffa7, 0x7e77936a,
+	0x3347ca29, 0xd5c41b15, 0xce2fcf9e, 0x5795fb44, 0x061c0276, 0x926537bc,
+	0x149ef80b, 0xadb4b8c6, 0x2091b6b5, 0x83efadd7, 0x63693ecf, 0x782f5cfb,
+	0x7e67df83, 0x5bb5a271, 0xf930b4e5, 0xe4cac32e, 0x867bf541, 0xb79dc995,
+	0x0026db05, 0xda961c3a, 0xfaf720ad, 0xd013e789, 0xe6d7894b, 0x0f7089da,
+	0x129ddea3, 0x4d3da170, 0xfc7f6949, 0x4dbf2826, 0x223b38c2, 0xe3033fb5,
+	0x894eae76, 0xfc850bdd, 0x6f680523, 0x1beacc7b, 0x14e3a562, 0xf3b27971,
+	0x10859de0, 0xe1ce38d7, 0xe824c9fa, 0xed0973e7, 0x8a9ee33a, 0xf8004db6,
+	0xd9903e7d, 0x08e895b9, 0x9376b9ed, 0x9e93ad95, 0x92ef286f, 0xfbf237c3,
+	0x1d9eb40a, 0x5a16f1ba, 0xb8de4153, 0xfd18f458, 0x24694c6c, 0x7d549f80,
+	0x9282bb40, 0x872025e2, 0x4a96084c, 0x271cb718, 0x71e04c87, 0xf4a4881d,
+	0xfbc7317b, 0xe1777421, 0x558a2dfd, 0xc7265ff5, 0xaeb792e4, 0xa3e090cc,
+	0x8a88af2a, 0x1399ed0f, 0xc6085a67, 0x1e8cafd3, 0x9e2ec117, 0x0a7af942,
+	0xf160cbde, 0xb32ff9a2, 0x466120fb, 0x3ffeddb7, 0xa8fd1da9, 0x7e56ad93,
+	0xfc33d7ae, 0xb7186d21, 0xb0900940, 0xd6cf68fd, 0xfd5057de, 0xf27f6a86,
+	0xad8f6672, 0x7c17f6e1, 0xdf9696f9, 0xb2ed556d, 0x467e75cb, 0xf0bedc75,
+	0xc6aac2ab, 0x804b4453, 0xd507a31e, 0x4a4f8a78, 0x8cfa2f00, 0x5778e0a7,
+	0x78f572db, 0xd195bf0a, 0x4f1d37c9, 0x913588f1, 0x11f44bc5, 0x471f114f,
+	0x911999d1, 0xda4b5ed0, 0x7d04eeb7, 0x7e84c5bc, 0x6f2d29db, 0xcbce11fe,
+	0x43090a29, 0x5cbc56dc, 0x5f4d35e1, 0x75def80e, 0xc056cce1, 0xef7775c3,
+	0xb03f3377, 0xd7885e5e, 0x7cabb60f, 0x1b73cb97, 0x1fa7d7ad, 0x29bef5a8,
+	0xcbe54eb9, 0x5187ae7e, 0xb9c072fa, 0x23d383b3, 0xd1c41250, 0xdd6dcbc5,
+	0x1c9c7ef2, 0xd19eff11, 0x9d6f69a4, 0x61a47bc1, 0xa87100b3, 0xde0919af,
+	0x63ee0dd3, 0x85b56dfa, 0xc3ea93f1, 0x2ca9fdec, 0xe3ed1793, 0xf22315e4,
+	0xf9e57f0d, 0xfd114497, 0xdc00af04, 0x27e5a653, 0x5faefd40, 0xd50e901b,
+	0x85b690f7, 0x2a74fc98, 0x94c88c5f, 0x79c1b7ce, 0xa13ce30c, 0x3d741bf7,
+	0x31f18fd9, 0x5ae837ee, 0x9706fccd, 0x6033e3cc, 0x330ecaf3, 0xb7197ffb,
+	0xf14aafff, 0xae8332fd, 0xc64ff16b, 0x1e75dda3, 0xd65a61f1, 0xc71bb7a0,
+	0xbfccbdec, 0x78af0554, 0xcc05fbb3, 0x8fb1a7df, 0xae523bc1, 0xce18a906,
+	0x5ce25ca5, 0x15d97c0e, 0x16fdd0a4, 0xbbf9eb4d, 0x802882c3, 0x4ead213c,
+	0xac7ec0b1, 0x012717aa, 0x45eb05bd, 0x5bb88f7c, 0xd7e7e00e, 0x29ffce25,
+	0x8e3042c8, 0x77f3d69a, 0x96fed57b, 0xa9023111, 0x9574b028, 0xdbd49a53,
+	0x57f6a8b9, 0xc653ac6f, 0x4034be83, 0x25ecbb44, 0xe01333d9, 0x8f29297a,
+	0xbd645c40, 0x1261aebd, 0xbf1c472b, 0xb17a8e64, 0x1312dbfc, 0x092b88d8,
+	0xfcdbd9f8, 0xdb878edc, 0x3838c6bc, 0xe3f3d9c6, 0x88cb3ee3, 0xa0e6686f,
+	0x6f92719e, 0x69733e73, 0xbfbf2e4d, 0xaeaee0c0, 0x067f597f, 0x4b007137,
+	0x9e280e07, 0x303ffb09, 0xa04d8651, 0xd223b329, 0x07fce095, 0xef053b7e,
+	0xb7cfc513, 0xc023841e, 0xbdecd5ab, 0xff3aaf8f, 0xddff79f8, 0xcce9c69a,
+	0x5f780193, 0x3df194e6, 0x17d96baf, 0x705cb972, 0xd6a1fe2d, 0x07f806fb,
+	0x1b578bd3, 0x13adbc78, 0x97bc08f9, 0x04a77f08, 0x9e08aef7, 0x79d5a1df,
+	0x06d5aeb0, 0xc27e1f7c, 0xef9e1b74, 0xfbd987b5, 0xdb4b3576, 0xad9ce1b3,
+	0xf7c76e2d, 0x0de1e36b, 0xfe5495b3, 0x49cdeb43, 0x1c6ef821, 0x79fbd069,
+	0x3cb3fa7a, 0xd3e03645, 0x37aec8c6, 0x654338e9, 0xd7c858df, 0x02ee8d2e,
+	0x91e3b579, 0x5e404af7, 0xd26f539b, 0x2792a7c5, 0xd2227ef4, 0x65768490,
+	0x5effa4d2, 0x5dae39be, 0x2351bf0f, 0xd97ae3e2, 0x7be80c37, 0xd3f9839c,
+	0xef88a549, 0x01db75fc, 0xe1ce1a9e, 0xeed3cee7, 0xee7d03ef, 0xef67ad2f,
+	0xf77aef59, 0x2fec02f7, 0xbe6ad7dd, 0x7df617bf, 0xb7f60f2b, 0xf2b7cf63,
+	0x1bd77f60, 0x3f403d1b, 0x0f9f153b, 0xefa73cfc, 0xa39ca2f0, 0x0b5c45c6,
+	0x275d172f, 0xe6fa2e5e, 0xe7aaf2f0, 0xcaa6c05a, 0x5ced5f49, 0x9ead3f83,
+	0x218af87d, 0x34bf4668, 0x3d98ffc3, 0xf077fcec, 0x0a2cb95c, 0xabe8f7e0,
+	0xae5c51bf, 0x104850cc, 0xc54513ec, 0xe8aed8ed, 0xdc809173, 0xf179caa4,
+	0x9f09f870, 0x4f36f3ff, 0x5f879c02, 0xce5aeed7, 0x4fa128eb, 0x43b9fc99,
+	0x6bbb3370, 0x1dd5c598, 0x9d82752a, 0xd9885cf5, 0xb1f76b5d, 0x422bea77,
+	0x5df0446f, 0x09c156f3, 0x8ec541fa, 0xeef01c0f, 0xae4e2690, 0x448ce819,
+	0x9deceff5, 0x40729d0b, 0xb79d1bbc, 0x6b78e415, 0x7a06544a, 0xf1172da8,
+	0x295ab3dd, 0xb5bcf18a, 0x241dc429, 0xf5ea5f20, 0x6c2e352d, 0xba465793,
+	0xdecad4d9, 0x7d934ca1, 0x0f11fdb9, 0x6dfbe3fb, 0xb7edfd2a, 0xf800fe79,
+	0x7ad3f31b, 0x8b576c5a, 0xc32ff91b, 0x617fe636, 0xccd97fe5, 0x6e3502e4,
+	0xce8ff544, 0xf3eef1e7, 0xf83bbc79, 0xf81a236d, 0x9b56df82, 0xd5b6fd57,
+	0x88322f10, 0xe5b56df9, 0x8d687edd, 0xae5b56df, 0xe889178d, 0x93234df8,
+	0x310b0d77, 0x25d2864e, 0x579163c6, 0x88ced505, 0x74a7e9f4, 0x0c6464b0,
+	0xf0fdd57f, 0x12b87f97, 0x3cfcf3e2, 0xf01ab2ee, 0x61c60477, 0x5fc04c46,
+	0x355f14c3, 0x4b6a2efc, 0x7d7374e4, 0x37e8c8f6, 0xedf1df4c, 0xe3c7573f,
+	0xb3aead74, 0x02ad5d7b, 0x75b8c3a3, 0xf189ebc5, 0xcf5569f6, 0x4bdf16bb,
+	0xdf1f5fb6, 0xabfdeb53, 0xfdb65ef9, 0xbef7c39f, 0x47fffb29, 0x3034c6ae,
+	0xe87b3e05, 0xd083df87, 0xad8312a4, 0x4c9477fb, 0xae3fe1d7, 0x437062d9,
+	0x21cd4ddc, 0xaaf21bbb, 0x7fde323f, 0x94f64958, 0xfde3c800, 0x5710d588,
+	0xfedae831, 0xb77b62c4, 0xfb573d5f, 0xb151785e, 0x61bf5f9e, 0xa7d934fb,
+	0x02e2d3c1, 0x82f7e02a, 0x24148ab7, 0xa9f638da, 0x7eb7e676, 0x9fefbf83,
+	0x88069321, 0x6eda7893, 0x14467bc5, 0xa62e306b, 0x6e9dead8, 0x9afc0d1f,
+	0x83d9efc1, 0x0b8812f7, 0xc618d67e, 0x1ac13efb, 0x5727de1b, 0xff6a23ed,
+	0xa97ea96f, 0xcd73e06b, 0xcd73e275, 0xf1cf8c37, 0xe3ab17ed, 0x61dfaf5d,
+	0x06918503, 0xb3f1e3df, 0xf17d76af, 0xef765581, 0x91d23b72, 0x5eb9ef07,
+	0x11e8ff2f, 0xf1b92987, 0x4dc41d5e, 0xfc559c42, 0x74f7a87e, 0x6b70b954,
+	0x97a1fb9f, 0xc57eb707, 0x3c96b8fd, 0x0de2a4f8, 0x8f4f7ac1, 0x3e81e4f7,
+	0xeccecabb, 0x0ccd9b2e, 0x0c0b372f, 0x13e07b1f, 0xe2a3efbf, 0xf5fb01d5,
+	0x7ad43bd9, 0x78fe6aff, 0x2d7c2ed4, 0x69fc077b, 0x886c90f1, 0x7d767be2,
+	0xfe9ec7f2, 0x5977162e, 0x517a86dc, 0xef8090f4, 0xf6f3ab33, 0xd63b31b7,
+	0xd45c39ef, 0x1cb8fbef, 0xfcf0e398, 0xf10a9ec1, 0x8f028a49, 0x59028c3b,
+	0x2f28e40e, 0x0da9378b, 0xda8fb8b3, 0x70e304a5, 0xb511fbd4, 0xc809532d,
+	0xbecd0b6d, 0x55fb433f, 0x8682d9ef, 0x4fa3b004, 0x75a72023, 0x37f2cbbe,
+	0x401f7d9b, 0x3b697fb9, 0xa69bfdda, 0xa138c79d, 0x5d3f2fa2, 0x3a5df609,
+	0xa40bb45f, 0xd3f7f498, 0xc7c60e1d, 0x50ead4d4, 0x7b41ebe1, 0xfb950778,
+	0xa7f2de40, 0x5f609c78, 0x56cded50, 0xe1da1b57, 0x6732f76b, 0xad81915f,
+	0x9fda3c87, 0x8ef6d1f9, 0xe415fc2f, 0x9042e6c3, 0xb7de8b57, 0xe3a8fda1,
+	0x138c2c91, 0xbbeacc78, 0x1f6af80c, 0xe40bba15, 0x0e3a1ccb, 0x7b1dadc8,
+	0x79842aee, 0xe0a17d77, 0xccecbaba, 0x24f5d0bf, 0xcaf88999, 0x665dd1ed,
+	0x9f022786, 0x666ad76f, 0xba1e0a9f, 0xdd03bf91, 0x38368f6d, 0xd1ecc746,
+	0xa5407cf1, 0x08fbeeff, 0x1ff414b3, 0xbd61fcab, 0xeaa39d91, 0xeece77f9,
+	0x3c16f1e2, 0x2a75aeae, 0x79e0d78b, 0xf8554f1b, 0xe3bb6f3e, 0x9cf3ac1c,
+	0xdec7fa5d, 0xe24cbec3, 0x2fd8e7fd, 0xe36939c4, 0xdfe0add5, 0x53897b01,
+	0x37b2bc46, 0xa1dfe610, 0xf9f20578, 0x09b6d16d, 0x839d7409, 0x01b7229b,
+	0x165f0fbc, 0x53a0bbd9, 0x92f78b7f, 0xde360413, 0x57da27a0, 0x8afb050f,
+	0xc36fedf3, 0x9d1abad6, 0x5b92e0c5, 0x870ef668, 0xd52241b8, 0xc578c3e5,
+	0x3c5918ef, 0xda2b21df, 0xabb29a09, 0xbb691273, 0x684cf7ce, 0x03e789af,
+	0xcb241a6a, 0x606f8e31, 0x0ed01fcb, 0xe82bdf6f, 0x93a6a6e0, 0xf7e6361c,
+	0x6095b609, 0x296dc9ac, 0x0e6e77ec, 0x7f041fbd, 0x5f1ab4bd, 0x46f52486,
+	0x7572088f, 0x7b411970, 0xa72690e4, 0xc395fb08, 0x0eba44e3, 0x1f08cfff,
+	0xddaa9f9e, 0x64a9843d, 0x7a095f6c, 0xfdacb495, 0xc7ec20f6, 0xb6b144de,
+	0xd68bfa00, 0x12b27c32, 0x5a739f38, 0x95bf2d06, 0x9c1a73e6, 0x7aea3fe8,
+	0x0de30ab5, 0x439d7483, 0xa167597a, 0xdce5c583, 0xa520e3c8, 0xfc115643,
+	0xb85ad2d2, 0x5341440d, 0xd29671ef, 0x129c43f6, 0xc38e7de2, 0xd4f00b37,
+	0x5902f9ca, 0x9c7f4162, 0x6d78625d, 0x8bdef25f, 0x55bfcf10, 0x1d4fef66,
+	0x34e37c3d, 0x96addfb4, 0xc6ab5ed0, 0x74e02e51, 0x47de13dc, 0xe0725e31,
+	0xbf303fa1, 0xfa0b1d0d, 0x3f0c8c97, 0xf829d5a4, 0xc87fe07e, 0xfd0b8c3e,
+	0x80c47d76, 0xe9e728fe, 0xaeb92667, 0xebc4b7ad, 0x891ccb29, 0x622e295f,
+	0x3d9be399, 0x3fdbe24f, 0x55f78eae, 0xd7a210f5, 0x63e87acf, 0x5c7572f1,
+	0x0ee4befb, 0xf542ee35, 0x504f1177, 0xcc526f17, 0xbe8a21c7, 0xef0b6abf,
+	0x50a3c78f, 0xf205c439, 0xd70ada4e, 0x8ebf8832, 0xdfa098fe, 0x09978d46,
+	0x9738b316, 0xbde0a8a0, 0x88d20cab, 0x48fd3271, 0x1ed01044, 0xd3b6e2c6,
+	0xb6865e21, 0x8818ef5b, 0xee216ffd, 0x41f20306, 0xa4abbe17, 0xfdd055c6,
+	0xd3243a41, 0xc13f1e64, 0x566b37f0, 0x70e2085a, 0x9f7edcfd, 0x7f1f2b35,
+	0x3f135567, 0x33feecc1, 0x7d4f882d, 0x10aa53de, 0xd6253df9, 0x1710d36f,
+	0x4d7ff3de, 0x693e6bb5, 0xe2e3ed67, 0xaa38542c, 0xfc2a1671, 0xf14c7bd4,
+	0x79314c70, 0x57bc02df, 0x7dd425e3, 0x0d8fdeee, 0x55d82ecc, 0x1cbbe221,
+	0x155d7f6a, 0xdc83679f, 0x626adc50, 0xefd712f8, 0xaefbeea6, 0x67c63321,
+	0x96bd7df3, 0xdfbeaa1c, 0x23bf9475, 0xd7bf8c75, 0xc21665de, 0x399f8006,
+	0xc9381b3a, 0xee4784f6, 0x5d817b84, 0xdc3668f6, 0x78dcdc2b, 0xa7cc24ff,
+	0xfe424f46, 0xc3ff84b5, 0x5ba243f2, 0x89e19ee1, 0x1e58b3a7, 0x908b2e70,
+	0x49848e33, 0xe07f82c1, 0xe3d73a5c, 0x022e1a77, 0xfb486b1c, 0xd3b436ca,
+	0x146973f0, 0xa26463e3, 0x44ecc429, 0x13ffdc2e, 0x631dec99, 0xbdc0fe5b,
+	0xdfde506d, 0x5a2df684, 0x627bf88e, 0xee5678c8, 0xfa4dfb62, 0x029c59db,
+	0x13d33dff, 0x1fd1e3b9, 0x4df8035e, 0x462b85e5, 0xc740989f, 0xe1b420bf,
+	0xee27593b, 0xe00161f8, 0x8ffd85eb, 0xe2b9060e, 0x77f7b94e, 0x72731ee1,
+	0x7ec8c239, 0xa34de5f7, 0xf9409acf, 0xb3ad1fc3, 0xff69124b, 0xcbc79333,
+	0xe0ef3089, 0x51eef8f3, 0xc4bfdf2a, 0x4bee4c19, 0x2015e89c, 0x3363f17e,
+	0x1f54b3a3, 0xe2063dfb, 0x3ddc219b, 0x12d7235c, 0xc4113bf6, 0x7b804ae7,
+	0x68eff108, 0x6b5e12dc, 0xf7f73900, 0x780ce881, 0xfefd5552, 0x38f7a107,
+	0xc604828b, 0x5c19a6c7, 0x141f01c3, 0x29cdf1b1, 0x2bc6c4b7, 0xfbf17048,
+	0x70a375c5, 0x51ba86dc, 0x28f4c7a0, 0xd072d1b7, 0xe5a09e93, 0x97297bc3,
+	0xd67afb78, 0x938ef35e, 0xa974e01b, 0x2fbc03f4, 0x04eb38b4, 0xc27647be,
+	0x0ef03c48, 0xfb93304e, 0x0739e8f5, 0x273c7dfb, 0x3b4fc591, 0x40704c37,
+	0xffdb107e, 0xfd0848bb, 0xb06653bc, 0x21df597b, 0xb4edf56d, 0xfa199dde,
+	0xcbb963df, 0x277fcfa5, 0xc29f9f5f, 0xebbe07e3, 0x1eff7fd6, 0x0f804a89,
+	0xffa31fdf, 0x441797dd, 0x0be0094f, 0x2f8c27e5, 0x2aee3c0a, 0xf9c20845,
+	0x2c81e37e, 0xc61a9ef5, 0xf5c0bdb3, 0x7fbf3f11, 0x91aa6701, 0x8586e3ae,
+	0x1bdc9dec, 0x93928833, 0xf92bfc04, 0xf07bbe08, 0xa729f711, 0xf4789bc0,
+	0xd713a97b, 0xf419e2af, 0x1f7c3b75, 0xe2e0cf9d, 0xd2538321, 0x418eefd8,
+	0x6b2309d9, 0x84b1fc1b, 0x7d684e7c, 0x3e2c6ff3, 0xf184bc62, 0xd7ab0277,
+	0x4ff86665, 0xfefc524f, 0xe21ede53, 0x27c89caa, 0x4abfdc2d, 0x8be85df0,
+	0x78d8d2a3, 0xfa8b0f1c, 0x5bc01629, 0x7cbb5df5, 0x1bf6e127, 0x7069a64a,
+	0xe794103e, 0xfd54bc54, 0x3c380348, 0x7f327e28, 0x1f872671, 0x06f7f091,
+	0xcfda8932, 0xadc61374, 0x04bafcf1, 0xde2a6f46, 0xb5ec7fae, 0x5f00a737,
+	0xc03f5c12, 0x3bb2ee7e, 0x74f9bd61, 0x804999ac, 0x78d829bf, 0xf449e707,
+	0x247927bb, 0x8c5d8798, 0xb09a1b18, 0xbf7f307c, 0x4fa4fa6c, 0xfe1a4866,
+	0x61adfb45, 0xfdf55afd, 0x459ba3c2, 0x68337e9a, 0x7e9a49bf, 0xf2c2689f,
+	0xbfe5fbbe, 0xe7e92147, 0xaf8fb6a7, 0xf3f5ea4f, 0x7c7dabec, 0x14f7f53d,
+	0x4df87326, 0xf329e356, 0x640f71f5, 0x7e615b8c, 0xc39c7d6c, 0x8edf1c9b,
+	0x306dff5b, 0x09250be8, 0x2844a70f, 0x1a524c3d, 0xf408dbeb, 0xd0fa461b,
+	0x802ff5d0, 0x7e652e2e, 0xb6fbbf80, 0xd989e078, 0x97a519d0, 0x7ba309dd,
+	0xe7c547ce, 0x3c5179ee, 0xf1543c06, 0xdd9e7e38, 0x30bdfc78, 0xa16d7206,
+	0xaaa407f2, 0x9d48423c, 0x0d70eb80, 0x2283ad88, 0x87528961, 0x22b37ff3,
+	0x33bdf388, 0xff8c19f1, 0x3be49319, 0x799af302, 0x3dec27d3, 0xa1d28c93,
+	0xf9d10720, 0xfd484d1e, 0x355f377f, 0xe1dc796e, 0xbd82373b, 0xe3ee9bb4,
+	0x5fed5ce8, 0xf234d395, 0x2af73b15, 0xf2be5545, 0x19642900, 0xe57cb832,
+	0xacd678c2, 0xf10dcb80, 0x8af91aaa, 0x44d547c9, 0xeece07bd, 0xa060fced,
+	0x987abe5e, 0xb76ebc60, 0x271a557c, 0xede3cd5f, 0xc42092a7, 0x93d936c5,
+	0x805e2c42, 0x162d39ce, 0x8db4dbff, 0xb74d8dc9, 0x82419cb8, 0x33d31672,
+	0xe87bf166, 0x6bde4cb9, 0x77c98fba, 0xbaea1ce3, 0x6b78fa2c, 0x133567ee,
+	0xb8b12f2a, 0x99abb40c, 0xa5d97d9d, 0xb53576f4, 0xf202ffde, 0x007f0832,
+	0x00007f08, 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd5547c09, 0x73b9f8b9,
+	0x64cacb67, 0x109848df, 0x424e3b08, 0x875b3612, 0xe22948b0, 0x3cb888b0,
+	0x4240b21c, 0x3eb44196, 0xc33fedad, 0x0d220222, 0xc168d46d, 0x2a14180e,
+	0x0431a0d8, 0xa4587049, 0x141a87d0, 0x2f1f682d, 0x48145840, 0xad88a0c6,
+	0xbefbffcb, 0xef726e73, 0xf6b42264, 0xfa7fb6ff, 0xef7397b3, 0x6df3be59,
+	0x39ce5be7, 0xd78deec3, 0x1ec658b1, 0xacc630b4, 0x98eb458c, 0xb19436b3,
+	0x96eff0ef, 0x95e5e7ae, 0x6289e63a, 0xa31574ac, 0x47d7e5e7, 0x7a83cfa6,
+	0x4c8c7697, 0x66e783cf, 0x92d433b3, 0x50e158cd, 0x2fa18a7b, 0x7b46f963,
+	0x9b19933a, 0xbeb45e64, 0xcc9eba19, 0xd393f516, 0x5b09fb18, 0xcf074c74,
+	0x48ce9151, 0xc8673fac, 0x287a2967, 0x0379f8b3, 0xfd8c611c, 0xc28f675e,
+	0x19b98cf7, 0x718535c2, 0x4398a6b8, 0xf870f2bd, 0xa5c340f7, 0xfe8c8196,
+	0x1c7183be, 0x4b6f6726, 0x1155630c, 0x67971fb5, 0xa35cf631, 0xe2b6e6c9,
+	0xec1496d7, 0x11deb18f, 0x043086e7, 0x543ce185, 0x39e814f0, 0x4cb2d13c,
+	0x040bf4f0, 0xc65e630f, 0x68e0ba72, 0x94ae8437, 0xb1e0a97a, 0x00d17eb3,
+	0xc7be24a7, 0x06895ab1, 0x6a5383f3, 0x1257e3fc, 0x33d38fd4, 0x63265877,
+	0xea97981b, 0x1ce75efd, 0xb3c6e381, 0xb8e1894a, 0x112b6c2b, 0x96e0dd4f,
+	0xbf30c901, 0x1ec977d9, 0x0ae60c13, 0x7ace1f09, 0xd4fb3d61, 0xba7f1804,
+	0x2af67f18, 0xac0884c7, 0x78e25d37, 0x00ffc2f0, 0xfbe219fe, 0xa9b2c6f4,
+	0x3198e00c, 0x13ba70c1, 0xa66ff83e, 0x0181ba65, 0xc2a6b39c, 0x7bd7737b,
+	0x61d2209c, 0x2cffd28e, 0x6c39bb6d, 0x387267cd, 0x10191696, 0xd5ee735f,
+	0x09669f7e, 0x42173e8b, 0x077c076d, 0x60603af3, 0x79f68f34, 0xe609b3cc,
+	0x82cc56f1, 0x3347f7f5, 0x43b7e036, 0x7fe86533, 0xcd716c62, 0xf4bf283a,
+	0xbf2a60dc, 0x83cf7b15, 0xf3fbf147, 0xa09e54e9, 0x6e504683, 0xb3ce99ff,
+	0x9cd01529, 0x5494d773, 0x9040ff18, 0x467ef7e8, 0x9d83e3ef, 0x5ea1d355,
+	0x99bef0fc, 0x04d3e0cb, 0x0aede323, 0xde9ff7f9, 0x9ce54614, 0x191eacfb,
+	0x6c109cba, 0x30f7d375, 0xaa09b6c9, 0xd130c91e, 0x53e361f7, 0xccbef7f9,
+	0xe7df851e, 0x23fb5185, 0x0b5e2199, 0x47f2f78c, 0x01fbe883, 0x0eb9b3e9,
+	0x595b5120, 0x52e91ea8, 0xe336689e, 0xc940c873, 0x3df0083b, 0x5f8c5221,
+	0x353de7c6, 0xca226b73, 0xdf5c84cd, 0x6850c75c, 0x670e6897, 0xfe1f1137,
+	0x8879f90c, 0x34aadc6d, 0x5f16afe4, 0x150f9a8a, 0xf8574f3a, 0xcf96826f,
+	0xc51e7e40, 0xfa9f0af6, 0x87c2a7f3, 0xea0b3e1a, 0xb97f33e2, 0xd7009e57,
+	0xb18f924a, 0x97721f20, 0xe38e747c, 0xe3fe2727, 0xf8bf24f6, 0xdca2c527,
+	0xc2777f88, 0xd0f24b57, 0xb9e9b99b, 0xcb83e501, 0x8708b3cb, 0xc56cd751,
+	0xdb247df7, 0x33c20b60, 0x0c7666ca, 0x0a372eeb, 0x783ac97c, 0x2e1dd991,
+	0x3943d3fc, 0x45fe7589, 0xb8e0e747, 0xb3b43bfc, 0xb82ec8b3, 0xa4adfc60,
+	0x7870569f, 0xb88b4836, 0xd09763bc, 0x5768b94f, 0x41b7ccae, 0x0678df3b,
+	0x2ffa8778, 0xc4967ec4, 0xfe18dddb, 0x82b87995, 0x4f81ee41, 0x611d9966,
+	0x1dd39846, 0xb724f911, 0xebf73277, 0xb38f8011, 0xc2136706, 0xae643c77,
+	0xed7e1191, 0xf757a146, 0x74285f20, 0xc7f4e052, 0x7a0f794f, 0xfe1e7fcd,
+	0x57a2e978, 0x133e0273, 0x2b2a22d8, 0x79e1bdf3, 0xae5e0ff6, 0x69bdf983,
+	0x147c9df0, 0x6fcdebe4, 0xeb3736cc, 0x20cdf382, 0xbc3d12eb, 0xd992ff77,
+	0xb3e00736, 0x051f8168, 0xb32e772e, 0xcebeb19b, 0x8a9659ec, 0xe06af674,
+	0xcfe88fca, 0x7f174c58, 0x5eeb31c5, 0x2afb3154, 0x3d56b6ec, 0x57a487ad,
+	0xcf50c2d8, 0xab9f6866, 0x99c4e5e7, 0x50a59eb1, 0xdce8f76e, 0x3c6f1806,
+	0x347375e8, 0xefe74fbe, 0x38230b59, 0xc20b3147, 0x90011559, 0xbbaaf7c2,
+	0xd1c03dd2, 0xd95bfeac, 0x7ddf041d, 0x0fa4c1c5, 0xc16032aa, 0x83efc2cb,
+	0x896efbe9, 0xd62ee38f, 0xd355b8d1, 0xeaa8feb9, 0x53b8f16f, 0x54ceb271,
+	0x8daaf7e4, 0xd04884f6, 0x5b328923, 0xa47a0b54, 0xf0ca152a, 0xeec65d8c,
+	0xf4c47d43, 0xc3d3e1f6, 0x78fbf0ba, 0x11deb8d8, 0x84b71fc0, 0x96fe75f3,
+	0x2af9ccb5, 0x29b563d6, 0xd57587d3, 0x00008a8b, 0xd4305eb0, 0x596efe83,
+	0x6286f50d, 0xac2f507f, 0x83763d7b, 0x68a7c476, 0xac608c47, 0x9f11d858,
+	0x8299dd6e, 0x9b27c476, 0xa9e4a677, 0xd8945fea, 0xbfd71c1c, 0xbc656f7d,
+	0x66ec67ca, 0xa0926f18, 0xf98724fb, 0x50eb8494, 0xe77b44fc, 0x1a7c85fa,
+	0x0235bf61, 0xef9061f5, 0xb47ba445, 0xf90e77d1, 0x6261bd8a, 0xa3ae199b,
+	0x1a5d72be, 0xf7876faf, 0x1bc8efe5, 0xdb7e0357, 0xdbfe3862, 0xbe041976,
+	0x2dff9e5b, 0x0c34af94, 0x3c61ab60, 0x0231bc17, 0xd71cbbff, 0x853d702a,
+	0xbfce333f, 0x57112854, 0x55d98983, 0xfc1b60eb, 0xc5d99457, 0xd04ced2f,
+	0xe88421b7, 0x1b372e5b, 0x75caff91, 0x70875d92, 0x59ec1c2c, 0xa7e97526,
+	0xe8af4512, 0x132972d8, 0x262cede9, 0x9827bcbe, 0xfdf0966d, 0x80c5f4e9,
+	0x9af352af, 0xa18f5c66, 0xd70901de, 0xb407a41c, 0x53ed885f, 0xbcb3e3bb,
+	0xad54e00e, 0xb4dba5f7, 0xc6642f70, 0x0784efae, 0xd7cbc937, 0xc414e706,
+	0xb730596b, 0xcd4b2e43, 0xf03f0839, 0xf017b79d, 0x2649afa9, 0xc0c426be,
+	0xbe8a79f8, 0xdc7ce6a9, 0xb3c7d55e, 0x09e7be04, 0xca35e5ba, 0x0b3c135e,
+	0x5a7bbce3, 0x2d4addb0, 0xfbc74b1d, 0x3952ea0e, 0x1ea38e1e, 0x4dc152af,
+	0xa7054e7a, 0xa25cbddc, 0x7d45eef7, 0xc63f3fe0, 0xeba935be, 0x4ab689dd,
+	0xe709f236, 0xf495667b, 0x0797d066, 0x4ca15d05, 0xe62499f3, 0xf5f23466,
+	0x14ef9fdb, 0xd08eaefc, 0x8eba3971, 0xbe412dbc, 0xbcbeb98e, 0xb3fef529,
+	0xdff56de4, 0x06ec6f29, 0x8267c1d7, 0xf8083b98, 0xd8ca5ab3, 0xfab27a8b,
+	0x465b6636, 0x37ebb55f, 0x088673ac, 0xc035fd7c, 0x85987403, 0x9d7906ff,
+	0xad3f7d1d, 0xfc97607b, 0x9cd9f516, 0x776ec201, 0x2424bb70, 0x9b19f38b,
+	0x61fd3cc0, 0x1ca2610a, 0x23d9b932, 0x1eb91f03, 0x006765ce, 0xf8fb311f,
+	0x32f5f2fb, 0xe51375d9, 0xa865d8bf, 0x659431db, 0x5cc80582, 0xd53f4417,
+	0xa633f512, 0x24fee371, 0x6e4c4728, 0x7016464e, 0x6674bc3d, 0x9c0208eb,
+	0xd058b1e8, 0xdfe1f163, 0x67c5bd50, 0x7d827979, 0x57942f60, 0x799921d7,
+	0xa1c761a0, 0x2f2c7a99, 0x28b125d8, 0x104cf718, 0xd501a397, 0xc955663a,
+	0x304f20e3, 0x75f8aab3, 0x4d4896c8, 0xa26d5879, 0x0d4dfea6, 0x33df357d,
+	0xdf3583bc, 0xd4ca1c47, 0xc79bb394, 0x3c8fea68, 0x8f29ab9e, 0xa9a2996e,
+	0x0cc2f63f, 0xbe47f94d, 0x99f535bb, 0x103cdedb, 0xe82050f0, 0x8a0ff8af,
+	0x5ae5bafe, 0x2c3da69e, 0xe8095ec7, 0xb15fc85a, 0xc80b3582, 0x2d07193f,
+	0xc896fdd4, 0x8da20e6b, 0xf5a95856, 0x6b54164f, 0x1b0dc5cb, 0x5609408d,
+	0x2fbed1ec, 0x0f2da2d9, 0x43a79e88, 0x011b3abe, 0xf820c9fe, 0x428b1447,
+	0x2ec9eff9, 0x44efa7f1, 0x00758fe1, 0x7e8098df, 0x33dface9, 0x7d234737,
+	0xdf03cc0d, 0x7e05b03b, 0xf5c1be07, 0x03d0e3a3, 0x8523e43a, 0x3278fede,
+	0x1ee96bc5, 0x3dd2d564, 0xee96a064, 0xdd2d3661, 0xd2d28d7b, 0xa5aec23d,
+	0x2d64d47b, 0x5a1c63dd, 0xd1cdc7ba, 0xa9c13dd2, 0x91527ba5, 0x8bc9ee96,
+	0xf3ef74b4, 0xa9ae96b0, 0xbe5a85ee, 0xc503e3f0, 0xb95b4b4e, 0x8e9eafd8,
+	0xe0fcd4e9, 0x40ca9a28, 0xfcaff4cf, 0x7fffa6b9, 0x45a43f36, 0x92353f0a,
+	0x7e477e45, 0x645fbd86, 0x46ff7776, 0x7f6a6bd1, 0x65d39f42, 0xefa4f67f,
+	0xd3cbd9ba, 0x47a09c78, 0xdc9ad97b, 0xf5272f65, 0x982797cc, 0x4bd689bb,
+	0xf08746b6, 0x70e165dd, 0xa357c15c, 0xd59bbb19, 0x13dfb01a, 0xc0146750,
+	0x03e7027b, 0x9acbdfe3, 0xe65cfde9, 0x5993a7a3, 0x63ccf88c, 0x30167a36,
+	0xe8a73d07, 0x1e22b79c, 0x392dcd4a, 0xceaf6fa8, 0x42527a3b, 0x21448ea0,
+	0x2f23dfd0, 0x4ea75a6e, 0xd999cc57, 0xd6b18fda, 0xb44ce70a, 0x16e33ba7,
+	0x568d6676, 0xbc6f2de1, 0x7a8f5034, 0xa1b60e56, 0xa777943d, 0xde6cf644,
+	0x3739fc97, 0xfe43af92, 0x2b0f65cf, 0xfe14ab78, 0x1e43f707, 0xbb0ab48e,
+	0xc943399e, 0x7059b3be, 0xb8fe805d, 0x9182ff3d, 0x82582eec, 0x2e80d7f5,
+	0x4f4e24db, 0x4dda2ba4, 0x7cccf4c3, 0x9843ca0d, 0x27ccfc93, 0x7892a0f4,
+	0x1fb1833f, 0xa0dbda17, 0x75234a02, 0x8e394e34, 0x3cd4f007, 0xaa20cccb,
+	0xe98126ac, 0x9afb4207, 0xf12ca225, 0xbce1fe32, 0x454cdfc9, 0x4d2b6d78,
+	0x4858af64, 0x4ccd923e, 0xe3dc91c4, 0x493ef0dc, 0xed090d06, 0xbfc01bd6,
+	0x6b942488, 0x2198c3e6, 0xfaf99ce2, 0x934c157e, 0x51f8539d, 0x0a2f7c26,
+	0x1dbfdeb4, 0x9595edc9, 0x40efc715, 0xcdef297a, 0x84b3377a, 0xf7825ea2,
+	0xeb31b92a, 0xb0f11d99, 0x533dc2a2, 0xc8d9ff5d, 0xf1e7ea48, 0x4e2d8bde,
+	0xdf723ef8, 0x720428a2, 0xd9739067, 0x10a1658f, 0xe9458962, 0x069ad46f,
+	0x1ec3fb99, 0x919afd19, 0xd4e7f5c7, 0x2dd1a471, 0x0bd8f2da, 0x0f42b2da,
+	0xc177f376, 0x82650728, 0x00f14caf, 0x195eaa97, 0x67c0f63a, 0x0fdcf165,
+	0x84c1be63, 0x1b90a377, 0x0de49d53, 0xc130f902, 0x0a61925c, 0x9ccc0c2b,
+	0xedeb7480, 0x6e5da0b4, 0xd0ebd44c, 0x2ff2603f, 0xf800ce6c, 0x78a69e53,
+	0x7eb555fd, 0x17ea03f9, 0x48d86bb0, 0xdff11236, 0x41e02f09, 0x1a3a7802,
+	0x46ae36e2, 0xcdcc9c78, 0x613603cb, 0xb3fea7b9, 0x7a59becd, 0x0b6cc110,
+	0xbc3fc67f, 0x447e9674, 0xa3af7af7, 0x64e3075d, 0xd93db8eb, 0x8e5cde9d,
+	0x6bb3e93a, 0x01646c81, 0xb0d553e8, 0x7fd4e3ff, 0x25793e9c, 0x51e22ba9,
+	0x6fc092ee, 0xcd698787, 0xf8009612, 0xc75aac2e, 0x092e3f90, 0x8f325c38,
+	0x24d7b1c3, 0xb5e8a7aa, 0x10022c97, 0x875a1af3, 0x62f04407, 0x0eb72f7a,
+	0x6bd2f2e5, 0x2fae88bd, 0xf1474efe, 0xa3cc41b8, 0x610cf9c3, 0x8c3efa5e,
+	0x26f950b5, 0x67281514, 0xdbf12b30, 0xbb23e608, 0x2b5cf411, 0xd972b9ea,
+	0x2820bbf9, 0xbe764e5f, 0xe84e7a44, 0x4fc174fd, 0xaf7e8ae9, 0xddc7fbd6,
+	0xf8a48d3e, 0xad0b6f4a, 0x54ce4223, 0x3af82674, 0x7f91448e, 0xe768e209,
+	0x544db4e5, 0xc688303e, 0x587c1429, 0x8d88ec98, 0xc5ebd154, 0xf5336b8a,
+	0x7802f92a, 0x5bbf28ec, 0x4d66822a, 0xa397bd50, 0x32071e38, 0xa18fd5df,
+	0x2175f9ff, 0xe047b436, 0xf97ec68d, 0x4729c90f, 0x5b97bc01, 0x9a3af5ac,
+	0xf50ea567, 0x24efd962, 0x33c01cf6, 0x66b97180, 0x7035e2fd, 0x9848a96d,
+	0xf9f40135, 0x0fdc917b, 0x1c7cc971, 0xe28433b6, 0x8cc98531, 0x853f4385,
+	0x7c91a7af, 0x0bd0c40d, 0xcc32b1c2, 0x8c2f7683, 0xdd95151b, 0xf1ff1e1d,
+	0x35df43df, 0xb733f49b, 0x1ef543bf, 0xdd9973f4, 0x7bc7556e, 0x19bb0b56,
+	0xe39213fc, 0x3b9fd160, 0x7aff7197, 0x84fb8f30, 0x296ae6b2, 0x62f5e7ad,
+	0x9a651a20, 0x014c02f5, 0x36ce5718, 0x16ae5c93, 0x47acc472, 0xe18fe8ad,
+	0x3a184673, 0x8f0e9cfd, 0x1cfbb187, 0x24fd7a2a, 0x3f0baf8a, 0x6a78e289,
+	0x077b7337, 0x2a19f5e3, 0x31af387f, 0x251bec9f, 0xec2edfbe, 0x9503f6c9,
+	0x27e8c1b9, 0xbe388a57, 0x058a9fb0, 0xfa682d2b, 0x4ad78e4d, 0x3e91587d,
+	0xfe7de2f9, 0x535dad4a, 0xf649c5b8, 0x24ecf5cf, 0x09c514c0, 0x49a4edfd,
+	0xd96f4251, 0xefc60658, 0x3b49accf, 0x307a8c18, 0x1e305995, 0x9abf249f,
+	0xf11428b1, 0x871cace0, 0x4f543df2, 0x67afeb72, 0x1a87041e, 0xe245b9e9,
+	0xe7f774f4, 0xd92db4f1, 0xb2dcefdc, 0x7f5a63b7, 0x58cbe7e8, 0xdda52f8e,
+	0x6a06b197, 0x38e828f7, 0xd8cb5f7c, 0x6e7e40e4, 0xc977c091, 0x7a8b2096,
+	0x8dab2a7d, 0x0d5d94d0, 0x7af51609, 0x2c28f640, 0x4c146caa, 0x7e2ba721,
+	0x72d0d653, 0x768ac430, 0xca017381, 0xbfc1fb49, 0x3a250f86, 0xff5072f8,
+	0xf9c7183d, 0x02b6e113, 0x9f743b3c, 0xffd355cd, 0x80bd28d1, 0xffa7af9b,
+	0x2d765c30, 0x1e87975c, 0xe1c29d8b, 0xd5c239fa, 0x8b1d3de6, 0x8cb805f4,
+	0xe476b86a, 0x3f9ff8f2, 0xa1fc9e9e, 0x88f564f0, 0x87df35a7, 0xc0c61da7,
+	0x74126cf0, 0x6e80f97b, 0xfac027b2, 0xcfc849b4, 0x1aef0c3f, 0x6b6dfc3f,
+	0x15618d9e, 0xe1137780, 0x9635be2f, 0x7f021672, 0xe04e22b5, 0xc6fa12ce,
+	0xfd03ba06, 0x7a468fba, 0xead40f50, 0x2c54d459, 0x96d814e7, 0x46af3cc0,
+	0x5da0fb38, 0xfe21eae4, 0x7f8091f2, 0x7014a247, 0xef881ffe, 0xf5e48f7b,
+	0x89ff75c1, 0xf28626e3, 0x09ebe0af, 0x1339ad4b, 0xe6fa37fb, 0xf59cb0db,
+	0x1a1ad9b9, 0xef1d7fa0, 0xf27e57ff, 0x3caff4a1, 0xc81a8ddf, 0x01d247e3,
+	0xfb209419, 0x9ac7cdd5, 0x7f9cc3c7, 0x9d27a595, 0x79e30ffa, 0x79fe36b9,
+	0x762c7bd9, 0x778be71a, 0x4b97df51, 0x876fc367, 0xbdf24bb2, 0x97f31433,
+	0xd7cd2746, 0x6d8991f5, 0xbce7600c, 0x9942f821, 0x057f329f, 0x151fb0ee,
+	0xee0091f4, 0x5a2613b0, 0xf5103e0c, 0x97a07595, 0x5e71a3b0, 0xacdc0eb4,
+	0x6ca071e7, 0x57f7d13d, 0x1c50c6a3, 0x27c88768, 0x291b46fa, 0x870fe95e,
+	0xff8f9a21, 0x9bf7b5c4, 0x8d3f62fb, 0x33e78a06, 0x4cfc4b7d, 0xdbd717e0,
+	0x9427877a, 0x8ef266f8, 0x4763a450, 0x753c0b78, 0xa76a06d1, 0x7287bd43,
+	0x8c9e4d71, 0xc8fdae7a, 0xc55916e7, 0xccb472e7, 0xb9ac6be3, 0xbff42c79,
+	0x30599336, 0xd62a1cbe, 0xad23d0df, 0xe87f0845, 0x249b9fa8, 0x4af6fc55,
+	0xadda8994, 0x6d62fa35, 0x09ab9fd0, 0xf78a051c, 0xb1b118b7, 0x85970782,
+	0xeb3ca1e3, 0xe866e800, 0x4760d1a7, 0x2b68e578, 0x7700a7d7, 0x1e0fbc3d,
+	0x1f25b9f4, 0x78c167bf, 0x87dabb7d, 0x833d3859, 0x439e61b3, 0xb3de5f91,
+	0x97b3c014, 0xdf081cc4, 0x3f5cd183, 0xc455702b, 0xfc02fd71, 0xf114321e,
+	0x7ca3ac9a, 0x66fae3ea, 0x96e3dfc2, 0x8c25967e, 0x79c76ef0, 0x299b46f9,
+	0xed1d56ee, 0xf9c6898c, 0x1e1cd818, 0x8c766cf7, 0x32587c27, 0x07002356,
+	0xf0bd9106, 0xc38bc133, 0xb21cf358, 0x168cb20b, 0xf594475c, 0x8ede8bf9,
+	0xcd37685e, 0xd076e68d, 0xd742b7f9, 0xc0abbae0, 0x2c02b677, 0xb957633a,
+	0x8498e6d0, 0x9ccf9978, 0xe78e502b, 0x551e0157, 0xc0de7efc, 0x16bc2dfb,
+	0xaa51bccc, 0x36eea376, 0x6bc2bb62, 0x760bcce1, 0x5e20f9f7, 0x5f187cef,
+	0xf18ac6cf, 0x33fc156f, 0xea07fa33, 0x7c9f9b31, 0x8bf3f86d, 0x8d8f5c79,
+	0x4995bc45, 0x7bb4462d, 0xabf98ed7, 0xb3e9ed11, 0x4de61615, 0x4679beff,
+	0x9c6aaf31, 0xccd77ace, 0x3ca51f34, 0x5b24f917, 0xc250df3d, 0xf88ad9c3,
+	0x4931e0eb, 0xfeaec783, 0xd8f06afb, 0x1a74ffbd, 0xc0c56cff, 0xa43ff4eb,
+	0x1aadfe87, 0xedfabbf8, 0xedb6e347, 0x04297bcb, 0x779f7bf8, 0x31bb73e9,
+	0x64c7bb1e, 0x373ca131, 0x3f22e6d4, 0xbc0edd5e, 0xd0f4fc04, 0xff28af9e,
+	0xa326d0f8, 0x3768c70d, 0x02dae6f8, 0xcc7eefe8, 0xea8dd6e2, 0xa746167a,
+	0xdffd9d11, 0x0b1ef59b, 0x03cd95c6, 0x375c16f5, 0xb3d9accc, 0x4cd7f894,
+	0x3f8944fa, 0x8b4efd28, 0xccfa3592, 0x5fd9f425, 0x9047cef5, 0x5f3aedde,
+	0x89da1e7d, 0xb70f3f03, 0x41117f92, 0x3f12ba76, 0x892383d0, 0x3989ad76,
+	0xde4de618, 0xa3ba758e, 0x82dfbfa1, 0x411c62b8, 0xc4e3561e, 0x2293fb78,
+	0x5064ffee, 0xa54dbc73, 0xeb45d697, 0xb09d987f, 0xb35f8fd2, 0xcbd17c3f,
+	0xc47583d7, 0x2bf372af, 0xb58bbf08, 0xc55c7918, 0x5e67f64a, 0x94e3c1d6,
+	0xacfc520f, 0x05fbfe95, 0xbfd02392, 0xe11de252, 0x9ae2ace8, 0xd68c36bd,
+	0x5e10fceb, 0x28b7ffce, 0x8a819fca, 0x6ac43d26, 0x162f9e65, 0x310e9671,
+	0xdaf37687, 0xda1ff414, 0xa3ab1e45, 0x46e83f71, 0x4fecae78, 0xf37fcf74,
+	0x9f6869d1, 0x79e33e83, 0x5a30a6ab, 0x624df227, 0x9106279c, 0x9123b17f,
+	0x7ab57fdb, 0xcaa6786f, 0x77bc7c1e, 0x685f736e, 0x7f656977, 0x5dcbda1d,
+	0x0efbcdfa, 0x39dae7f6, 0x574df888, 0x39e9e83f, 0xd7489718, 0xdcebb0d9,
+	0x31eaaffa, 0x16b650de, 0xef1801ec, 0xa469e812, 0xc4feae93, 0x705f5c70,
+	0xcb3f5c6c, 0x9fc893ea, 0xd1f10fcc, 0x60b293fe, 0xea05ba5b, 0x4d8fd7e5,
+	0xf33fbe47, 0x5c14a0e4, 0x58c74e0f, 0xdc4f3053, 0x192024fe, 0x69ba79e6,
+	0x6abf7f00, 0x17d470e4, 0x9c436b61, 0xadfc009e, 0x95fcf7e8, 0x14767226,
+	0xcc48ef3a, 0x7c406b68, 0x7e93320c, 0xf6450507, 0xdf21fe53, 0x17786b0c,
+	0x473f159e, 0xa15ac7c1, 0x3ffe954f, 0x79517a16, 0xd299fac2, 0x31ef7082,
+	0x1ccffd11, 0xc38d7bd1, 0xf1b21ed1, 0xd08556f1, 0x0730f978, 0x29cbc80b,
+	0x8e9d8eb1, 0xbc470eb4, 0x2832ebe7, 0xe443ba0f, 0x7c5956e5, 0xe41eb8e1,
+	0x194ad9eb, 0xbe62afea, 0xf8d508f0, 0xd7b28df9, 0xfbddf448, 0x4d5ff90e,
+	0xabe90c61, 0xfc8c337b, 0xa69bd773, 0x018f684d, 0x6821ddfe, 0x91371e17,
+	0xc9afb2df, 0xfb617644, 0xd7f21089, 0x42c3f1fc, 0x3f48297d, 0x44499bd7,
+	0xdf64f6df, 0x0c8edcf3, 0x680f9862, 0x891cea3f, 0xd1694274, 0x9ec3e3c5,
+	0xd5cd7680, 0xda2f20a6, 0x60f4f035, 0x6acdd07c, 0x9efde9e2, 0x347e8610,
+	0xa8643d3c, 0xe0f17549, 0x1082a0b3, 0xfda99bed, 0x01ce2943, 0x4a1f1fa8,
+	0xb143fe83, 0xbbd52b7d, 0x9379d7da, 0x1221c785, 0xd48978c5, 0x5fb7326f,
+	0x8d39f499, 0xef89fd03, 0x65ddf4cd, 0x79a48e72, 0x36c61c7c, 0x61679806,
+	0xa0bcb6a5, 0xf62e5b5a, 0x5b25cb68, 0x745f65b4, 0x814fd114, 0x7f73e15b,
+	0x70c4a4bc, 0x87c142bb, 0xd2769f3f, 0x61f03af3, 0xcbf1013c, 0x571d391a,
+	0x929aba0f, 0x0f2de387, 0x9753e4d6, 0x3e279d34, 0x9fd8376c, 0x77c075c1,
+	0x9136c0d4, 0xd50360fe, 0xf8ffb6fe, 0xe7adf3dd, 0xbcf5be45, 0x26dadf26,
+	0x160c2ef4, 0x5084f18e, 0xe11c359b, 0xad4ba1d8, 0x3d5f22f5, 0xbe7c4419,
+	0x21cbf716, 0x401baddf, 0x054452f0, 0xf0b3cfc6, 0xfd08cff1, 0x54c5e677,
+	0x642d33ca, 0x4b4fa4b5, 0x44bef399, 0x5887e78c, 0x57ff9073, 0xcdfb02d9,
+	0x27baf8fe, 0x34e3d386, 0x7d8ac6b3, 0x6fcc564d, 0x80bfe114, 0x74fd4504,
+	0xdfbe20f6, 0xd175f48f, 0xd481137a, 0xd8ccf7c9, 0xf3ff9655, 0x0d0077cb,
+	0x3655fe11, 0x67ae3877, 0xde7c2c17, 0x91593f60, 0x9f3245be, 0x8875fa07,
+	0x2f120bc7, 0xd942fa2b, 0xdf00b12f, 0x989e7ccb, 0x518f2fa7, 0xc7ae38fc,
+	0xf75e925c, 0xd693e830, 0xf2386b08, 0xb4aaeb53, 0xb79825c8, 0x66c6b088,
+	0x3aecf0aa, 0xd026bcc0, 0x0946d65f, 0xf0ddbf63, 0xf39223b5, 0x085d6fa3,
+	0x8eaf2bad, 0xf6ab996b, 0x8635ff13, 0xc58f91db, 0x16a6ff70, 0x40ec826d,
+	0x5a74e078, 0xcab4e820, 0xf931fce6, 0x16f57e4b, 0xf412f754, 0xb95f7bf3,
+	0x2f295ffb, 0x0fc55eb5, 0x8a4edeb0, 0x385de3e5, 0x374b7464, 0xfb4a5f91,
+	0x82eb7c9a, 0x70bf6ec8, 0xae3a4a68, 0x82eb4543, 0x155f5122, 0x8b135e1d,
+	0x8db8c8f6, 0x3ae2c58f, 0x6269b055, 0x9fe2533a, 0x482a3e2a, 0x3da3a7b1,
+	0xb6567be4, 0xd5453f60, 0x4ab5c132, 0x167e695f, 0x36ab9fde, 0x24549d90,
+	0xdbd73ae0, 0x2f788e19, 0x11bd33d2, 0xef4e7ef0, 0xf03b270c, 0x2ffc9959,
+	0xbd40f9ff, 0x00ccfa63, 0xfa0b3278, 0x00b48be2, 0x47547bfc, 0x66082a74,
+	0x36e75724, 0xb9edfcf2, 0x587de764, 0x157f056e, 0xaaad77f7, 0x0eb70e2c,
+	0x73f78eed, 0xddf12766, 0x051f3102, 0x28e3feaf, 0xbc476d78, 0xe871fda2,
+	0x2768c9b9, 0x91929eb8, 0xc6ded933, 0x8e47e42b, 0x72789a6b, 0x075fbe2c,
+	0xd7158076, 0xdcefbec7, 0x4ad4eb83, 0x909da199, 0xcb1694d7, 0x57d76a86,
+	0xdef22fb4, 0xa3ae159e, 0x90d31df7, 0x6d5b4e9f, 0xfb2a99b1, 0xcfc11dee,
+	0x5fc974fe, 0xec70b7f7, 0x818d68af, 0xdff057e0, 0xfd93630e, 0x41e21953,
+	0xedef6f3e, 0x7a157ea3, 0x2116fd28, 0x81fe15be, 0x2c63577a, 0x7c795f82,
+	0x99d535b1, 0x0fc00b63, 0xe3037ff3, 0x61d57f62, 0xdcbfcc76, 0xbccab8e8,
+	0xc8aae93b, 0xafd399ad, 0x8a54f9f5, 0xea8eeadf, 0xe9e99369, 0x50535bca,
+	0xfd61f2de, 0x5f3a7f46, 0xfe449df2, 0xe315b285, 0x4aebf9d5, 0xf2f1c3ee,
+	0xf874984f, 0xadcf75bd, 0x3f2e09c3, 0x529e01fa, 0x7b75f102, 0xa6c52faa,
+	0xfbac1fc2, 0x7ccacf24, 0x1c137054, 0xe4307fe0, 0xa054f6ff, 0xbfee4a9b,
+	0xf50f7210, 0x63e2462d, 0x5fc470fb, 0x7e2d7ce7, 0xcdf8b5f3, 0x3e2318f7,
+	0xcd273666, 0x9323e0a7, 0xfc17df0e, 0x28e9a7fa, 0xc7abad9f, 0x235abcd3,
+	0x8e51c3ed, 0xffa0535a, 0x59e7dda1, 0xe7986bf0, 0x6799efd0, 0xabd11065,
+	0xfa4679c7, 0x33df679e, 0xed58c8cf, 0xadeacf3c, 0x5c5fa8e1, 0xfb8664bb,
+	0x8ec95cc3, 0xd97963b5, 0x768614b2, 0x05d0f589, 0xd5e912fa, 0xb8a068d6,
+	0x30ef22a1, 0x83f20dde, 0x35a1f88e, 0x28f4fad7, 0x0b656f5a, 0x575bd9c6,
+	0x51e7788f, 0x95aeb728, 0xb407682d, 0x81fc72e6, 0x0f50ebdc, 0xa638a6b4,
+	0xc18f7951, 0x39fa14b2, 0x0fb7f953, 0x0c0bf225, 0x73f34656, 0xbe3b45ac,
+	0xfd45e01d, 0xcd997805, 0xcd034aed, 0xa7cad57f, 0x7777e256, 0xfe964df5,
+	0xa7eb40d6, 0x6b45cf16, 0x321c8d64, 0x73c695bd, 0x8ac93afd, 0x0cf050f3,
+	0xc67d349a, 0x607c2eb0, 0x2eb0d679, 0xfd94b8bc, 0xeb3d626c, 0x9f885bd4,
+	0xc05d7cbe, 0xafa8ea7d, 0xa77d3f70, 0x57affb3c, 0xdfc67a7e, 0xd04db89e,
+	0x16ef5fd3, 0x7ca9cbab, 0x5cbaa15f, 0x4a37a7e2, 0xbac3befd, 0xfc502d3b,
+	0x78e77774, 0x02796f1c, 0xaf5c4a6f, 0xd68949fd, 0xd5bd3cd5, 0xabc17e88,
+	0x155c78e3, 0x8ff301fc, 0x683b0e49, 0xb67a793e, 0xef8994dc, 0x994f546d,
+	0xdcb7f427, 0x8ef46b04, 0xa077ae60, 0xaaa364de, 0x0557e8ac, 0xfe44479e,
+	0xc3fe7942, 0xad64f3fe, 0xb38aacff, 0x201b123f, 0xf7299ece, 0xc608ed7d,
+	0x64c976db, 0xf30eba37, 0x7d7d8575, 0xf06de9e5, 0x1a4f7cbe, 0xe6555bed,
+	0xf6c78fef, 0x7de12b86, 0x21db7de1, 0xcbc63063, 0x72a31af2, 0xf48a2fc9,
+	0xaffbc405, 0xfe94fcc4, 0xe12df4da, 0x2df6d5d3, 0xa19f096b, 0x86bc8fe2,
+	0x164fb42b, 0x5596e7f0, 0x534cfb7a, 0x79fa2e4c, 0xcc4a7ff9, 0x55f3c1d5,
+	0x06b5cf41, 0x506b0beb, 0xc899764e, 0x3c3b6f6f, 0xdbed8747, 0xe789170e,
+	0x9e7a7643, 0xe382933d, 0x7f38eb87, 0x14bde32b, 0x7ca5edcb, 0x7fe7a9dd,
+	0x8dfefa84, 0xaa65d4b8, 0x2ebe69f8, 0x6dc4fc93, 0x845cdf06, 0x95f1ec1b,
+	0xe943efb8, 0x2b58d5e7, 0xebb6d1c1, 0x0fa8f3fc, 0xce4dacce, 0xb6d23544,
+	0xcc70c06b, 0x189db7fb, 0x3fe78e91, 0xb04c9eda, 0x66d81ea1, 0xfc443eb0,
+	0x86cc2ab6, 0x87f4ae72, 0xac7e60e3, 0x1cc8d76d, 0x4edbb3f4, 0x4ca17870,
+	0x73d4377e, 0xa50efee3, 0xf59d70df, 0x8c8fb857, 0x7940c9fd, 0xa4dfc5b4,
+	0x1abfa1c5, 0x5f9c0c6e, 0xbb5dfb40, 0xc1296a7f, 0xf1e3ecad, 0x7d95efb7,
+	0xd17efe3d, 0xf80bd07c, 0x2b7fdfde, 0x702b9562, 0x1fbf917f, 0xdc7e40c7,
+	0xfa62beca, 0xbdf5a5ab, 0x2677cb64, 0x0fb13d4d, 0xbe031a88, 0x571e40f2,
+	0xc3c65c53, 0xe52b5fe3, 0x5f42f980, 0x3ec7cf2c, 0xdcedf213, 0x4f5d1516,
+	0x1e3e98eb, 0xc8da7af0, 0x7f99f1cc, 0xaf973fbf, 0xbacc57de, 0x73a777fb,
+	0x00b9953d, 0x32d5e9d7, 0xa1fd47ed, 0x7b7f9dfe, 0xf3e88480, 0x4effb099,
+	0x3e705cc3, 0x5ab3fb3d, 0x067c1578, 0xfe057d89, 0xfe22cdf5, 0x991bf03e,
+	0x9bee51d9, 0xcfe41e0c, 0x3f9f8d90, 0x67f20f7d, 0x6a92c1a3, 0xed017ca5,
+	0x64bb6573, 0xb75c7f4f, 0x2f84cf1a, 0xd76575c4, 0xd34e3a08, 0x92ecbfe9,
+	0xd6dfee29, 0xf3162570, 0xe50fd003, 0x4f4d5d3b, 0x7b7f90d9, 0x4e312382,
+	0xeffa61fe, 0xa1f8bf66, 0x6db67bc8, 0xfa8e973c, 0x6260f41d, 0xfa67ca1c,
+	0xff9e46d7, 0x7da1c96c, 0x273f1bbf, 0x73ddbcbb, 0x7349ec95, 0x940f6ca3,
+	0x671a1c57, 0x4df061fc, 0xf007c2d0, 0x1478450c, 0x3eadcb38, 0xbd737f3a,
+	0x5d84ffbc, 0x1cf14b85, 0xd1f9e608, 0x94682fbe, 0x582add69, 0x40ac7b2f,
+	0x7e030997, 0xed082fb1, 0x8a24a7d1, 0x6f924e0b, 0xd40e70fe, 0x4ca4f05f,
+	0x1f1bbde5, 0x7480d0fa, 0xbca06f5d, 0x99a682e1, 0xfc57da46, 0x122cc494,
+	0x37d9ab8d, 0x12972c50, 0x09f6dd5c, 0x680fedf8, 0x7d0b76cb, 0xe37ef7e0,
+	0xa2fb198a, 0x9267a9f1, 0x017efbb5, 0xcb103bfc, 0xdfe047cf, 0x126bfe96,
+	0x416d0e91, 0x5ca3358c, 0x5fc85bea, 0x3e7e5e61, 0xd9d76db3, 0xeb97a414,
+	0x5e292f8d, 0xb01c93d9, 0xf33fbe46, 0xfc8938ce, 0x5cdf81d2, 0x5008e699,
+	0x6fc8b67f, 0x13b8316f, 0xb7dd3ed1, 0xe38f2af1, 0xae71e2ec, 0xee67fb1e,
+	0xf26f1e20, 0x2c1c5106, 0x0532d6ab, 0x3cec01e5, 0x36b93fcc, 0x09b198ad,
+	0x0dbb41ca, 0xabab4456, 0x05c9287f, 0xaaa141ca, 0xb61e455f, 0xb2947c88,
+	0xd8b661bf, 0x6feca397, 0xf83bf650, 0x77eca1c3, 0x3bf62d98, 0x78eb1dbc,
+	0xc19e0e28, 0xd9385f3a, 0x5ffb7eb1, 0xe2cfda7a, 0x3fd1efbf, 0x4f9fee6e,
+	0xcbecad5b, 0x47146088, 0x8dfac237, 0xcd86c395, 0xabf51778, 0xfe4c98e1,
+	0xef23ded0, 0xf1f5aac5, 0x38737d0a, 0xd72f31c6, 0xd1fe4419, 0xc316f947,
+	0xa98dcf91, 0x862597a4, 0xca0bae76, 0xb375def8, 0x338eaede, 0xe7c71d3f,
+	0x9d2e22bb, 0xfb7ab7af, 0xb7afcc21, 0x688cf259, 0x148e1b8f, 0x367e464c,
+	0xf919e7c4, 0x54e6b9f8, 0x9e844ba4, 0xa3457ff8, 0x05b36e32, 0x7bf257fb,
+	0x2cc71161, 0x598577c8, 0xbf3fbeb3, 0x4a83f227, 0xdf33af7e, 0x7be33f17,
+	0xe33b7bf3, 0x8bf71d38, 0xff71bbe7, 0x3b7bf2cf, 0x5265fe91, 0x30f1a4cb,
+	0x8ef88ac4, 0x6ebdf9c0, 0xfcb1bcf3, 0x567147de, 0x9ceb7f9e, 0xbdf90f6f,
+	0x58dffd6e, 0xff7baf7e, 0xbaf7e43d, 0xf9837ff5, 0x797ecebd, 0x50f96f7e,
+	0x5b3fed1d, 0xe3c4dc7e, 0xffbe66e4, 0x65e424c3, 0x668277b9, 0x74f284ff,
+	0x184909b3, 0x275e5f27, 0xbcfe464f, 0xa0b3c96c, 0x78221a7c, 0xb064c83c,
+	0xd43f464f, 0x85191114, 0x711ff97c, 0xabaf3469, 0x3f888b11, 0xc87982af,
+	0x722d89cf, 0xef797960, 0xca649902, 0xd6177f2f, 0xd57cf324, 0x7758b368,
+	0x87e4b7df, 0xf3fbfe52, 0x3d1e5538, 0xed00fb2c, 0xce0d648b, 0x8fbf283e,
+	0x127f405b, 0x7c50b79f, 0x7f3928c6, 0x76217187, 0xbb639f82, 0x601ce41a,
+	0x3ea5c951, 0x2eec28de, 0x33ea126f, 0xa7a2ab37, 0xe10ae1ab, 0x2a478959,
+	0x47cc5ddf, 0xa5794778, 0x7a09b8c3, 0x706f7d2b, 0xb573a00e, 0xbb4e8e02,
+	0x6ea18fe0, 0x6a69a73c, 0x8ff286fa, 0x34df7aed, 0x36d4eb8c, 0xfc6a21ca,
+	0xb973c526, 0x9cfe4dc8, 0xd8e556f2, 0x57e617ae, 0x7ca0064b, 0xc37c9b96,
+	0x7b7dee11, 0xf51c36fe, 0x92a6d5ca, 0x0b7ef83e, 0xdc75a7d4, 0xe7572be8,
+	0xaaf3fd5d, 0xf381f1d1, 0x969a5bad, 0xdb1c2225, 0xf6005e30, 0x3fc3f955,
+	0x663a73a7, 0xea0dff66, 0x837a060f, 0x99868afc, 0x93b438f2, 0x01db003e,
+	0xf8bb59ca, 0xcc959bfa, 0x2d37983c, 0x0e60fa6f, 0xdb3cabd2, 0x32974168,
+	0x6de78338, 0x16cdb383, 0x45a6ff5c, 0xe2303e71, 0xed869b3a, 0xdd214627,
+	0x3031c41e, 0x7b73b9cf, 0xb7f01bbd, 0x854f0ff0, 0x27dfc033, 0xafda4afa,
+	0xb1f9ba51, 0x2f3c3b70, 0xc714dde8, 0x0723c4fc, 0x1794ffdc, 0xf6b7f8af,
+	0xfe754950, 0x3fdfd3e0, 0x6ef88d31, 0x7982c1b3, 0x1316d77f, 0xaf2b9f9d,
+	0x33f3a62b, 0xcbc53e50, 0xfe867f8f, 0xbb41ab95, 0xe97c2f4e, 0xad2b58a9,
+	0xb124ee0b, 0x941f11ee, 0x849d9cd7, 0xc1f857f8, 0x8f8e1dbf, 0xb55de5fb,
+	0xaf633cf2, 0x7b15dfee, 0x5dff5943, 0xfb884f75, 0x3fc85a01, 0x845faff0,
+	0xb19a3232, 0xfddaf199, 0x983e0ad1, 0xa3f48627, 0xf0c373bc, 0x54be5053,
+	0x92e16ff3, 0xbf8a4f0a, 0xff9b51d3, 0x3dac37bb, 0xb06defaf, 0x7574b02e,
+	0xb3b50f3b, 0x177e0836, 0xf06a5f7c, 0x955ca386, 0xdcd8346e, 0xfb74baf0,
+	0x973e2f0b, 0xc3667245, 0xfb64ac75, 0x818e1f5b, 0x430ec972, 0x8d3e54f4,
+	0xde754950, 0x61ff05cd, 0xc3a1405e, 0x32ded7c2, 0xf7f1875a, 0xa2ec88bf,
+	0xbd8ec947, 0xfc5e7446, 0x76be31f1, 0xbbf291af, 0x3da974fe, 0xef2b7245,
+	0xbbec86fc, 0x2c48f64f, 0x3e00352e, 0xee15be37, 0x3a227814, 0xd2753a0a,
+	0x92beafcd, 0xe4e8577f, 0xde3b3dff, 0xfd85f242, 0x3f023ca1, 0xc606f2bf,
+	0xd9323ffb, 0xaf45fe70, 0xf38e103c, 0xc45faf38, 0x63c37af9, 0xb71876b1,
+	0xb58ee0c8, 0x2fbf93d0, 0xc467fe7a, 0xfe8e0b6f, 0xcc7fdb8c, 0xfca3a09e,
+	0x7bf29ba5, 0xd0efeb85, 0x0da2ffe8, 0x85ffae3c, 0x11de4d9e, 0x0b8e2e40,
+	0x937e72bd, 0xe7d9f289, 0xf6860f31, 0xdf327bcb, 0xa7eec7b7, 0xdf629078,
+	0xe54d2780, 0xfe1e842f, 0x894ebc43, 0xfc359b7f, 0x3378f35a, 0x64d3e7d2,
+	0x25ea1c7b, 0x05bbd317, 0xa0efa43e, 0xc4e8f95f, 0x1e1f4e38, 0x6076a33f,
+	0xf7c78e8f, 0x40d9bf58, 0x3b5550f1, 0x8f966e71, 0x1f18a0ff, 0x7cc60ee0,
+	0x5658f9ca, 0xd44fc814, 0xe7c67427, 0x29e7359b, 0xcb9be4bb, 0x2e2acd7b,
+	0x7bbc8adf, 0xefc64fa6, 0xf2e31f9f, 0x3292ed83, 0x1c6f2e09, 0x4b3bdf7d,
+	0x27cfce1a, 0x75c9037b, 0xb5c8418d, 0x27c2bbf6, 0xee9eb700, 0x05f85021,
+	0xfc248ffb, 0xbad2d517, 0x1dd8d26d, 0xbc2f1c2e, 0xdc8a7f7b, 0xfff2102e,
+	0x7f38bc7e, 0xad9fe425, 0xf3a1b98f, 0xcf06a545, 0xbca1cf8b, 0xbef7e09e,
+	0x90376e94, 0xdb717e5d, 0x06ef0ffe, 0xab58b939, 0x7f56a9c8, 0xd169cbfa,
+	0x7f116fab, 0xc5e9cbfa, 0x0362b7da, 0xb78ee9ca, 0x2eee0ec8, 0xfab9ffa7,
+	0xdfdfc153, 0xe8a7f0fc, 0xe8f09ec3, 0xe3ab0faf, 0x21f501ad, 0x9f531dfc,
+	0xa5f0537b, 0x6fc29df0, 0xeb2e5f0b, 0x93a77a83, 0xebbe152f, 0xef854be4,
+	0xd73bedba, 0xfbffcfe0, 0xe00df85b, 0x60faec72, 0xb3d01252, 0xc9fb91b4,
+	0x9620eed0, 0x5a764f01, 0x41e558c6, 0x55db6f3c, 0x6b95f8f6, 0xfddbeafd,
+	0xfabf0eca, 0x22f2bf4e, 0x821efabf, 0x3f61b4ab, 0xbcc96fdf, 0xa586fa9a,
+	0xdd161dcc, 0xf31e0e75, 0xcfd02b58, 0xf4f3c6df, 0xb8f0258f, 0xb8c62fa9,
+	0x891ff682, 0xe13e2a7d, 0xb43bb467, 0x354e54fb, 0x5b7fa4ca, 0xf8f3813c,
+	0x3c9209e0, 0x3fb0f4b4, 0x4d3b895e, 0x1e534394, 0x2a3a3806, 0x60a0fc79,
+	0x94e19dc9, 0xbb4c69cf, 0x850ae31d, 0x2c31f987, 0x73143f65, 0xaa09f5db,
+	0x98170efd, 0x319be9fb, 0x4258d64f, 0x35828bf1, 0x0fcd7a5a, 0x0be2907d,
+	0xf7b4abf3, 0xad7c2900, 0xd68b0bc4, 0xc42fbf6b, 0x1ee8847b, 0x47da4a85,
+	0xfb46b0b4, 0x0e7c89dd, 0x41273c7c, 0x2c1909d8, 0xf9bde443, 0x57a11239,
+	0x6f43ca27, 0x21cbfca7, 0x1da5f299, 0xbde1328d, 0xfb449b63, 0x863b9869,
+	0xf99ca5e4, 0xf8299f48, 0x60f284b9, 0x5cdf59ec, 0x73dffd7a, 0xa52a851e,
+	0xff0f1ff5, 0xd52f3c2d, 0x8ddf489f, 0x4e7f9de5, 0xaf7598f9, 0x104f7e3f,
+	0xdf6a1fed, 0x35f74613, 0x9dbd37b5, 0x85e528f2, 0x07ba364c, 0x9497cf61,
+	0x6a5f6b7f, 0xd57d422a, 0xcafdcc9e, 0x0e5f4d65, 0x39657ae7, 0xc098df3f,
+	0x34744dcf, 0x94f28dfe, 0xca268d1d, 0x84f6b933, 0x7ae11f90, 0x9cfc8823,
+	0x292fa6f6, 0x9acffcbe, 0x3788b94f, 0x3cf187b7, 0xbfb8bb4f, 0xf47bb5c4,
+	0x2d87980b, 0x446bdbab, 0x9bfc65bf, 0xdf5d90df, 0x67b72afe, 0x1eded0da,
+	0x5bae7883, 0x7dc44e33, 0x4d0ecca8, 0x0db77b45, 0xb1912385, 0x9d5dcfa1,
+	0x081a1eea, 0x5e50df4f, 0xf3f146f5, 0xfc18ffd2, 0xb9dfb448, 0x63cc31b4,
+	0x5fde7096, 0xf518fc9d, 0xd79e1ec1, 0xb17be657, 0x1fd90976, 0xc1f79bd7,
+	0xfddfee04, 0xe4b799ef, 0x9f7991bd, 0xef4e6ffd, 0x98d43c62, 0xba2e5ddd,
+	0xcf1379f3, 0xb30f6d17, 0xc837bc11, 0xffc486ef, 0x157f7465, 0xfd7e1ee8,
+	0x6ffbf779, 0xe99eef3e, 0xa0ae787e, 0xf3e305bb, 0x21bf37ae, 0x3d5efef8,
+	0xe87fe137, 0xfd3b15fc, 0x6fd7c67d, 0x91c3a257, 0xee9efb88, 0x5f02bc38,
+	0x274e74b9, 0xcd12c3c5, 0x4d9fee74, 0x8e87e28d, 0x33618ef5, 0x57877586,
+	0x25fe1bf1, 0x31273ed1, 0x07feaba6, 0xa619efb3, 0x7d57779e, 0x58d1be3e,
+	0x379d3f7b, 0xfca50b29, 0xc18f6e2c, 0x36cc2f76, 0xf713fe71, 0x990f1c3c,
+	0xa606307b, 0x738347f2, 0xe739c23e, 0xc0ac9fce, 0xca2fb4b2, 0x35e718ba,
+	0xdc4725af, 0xc710b08b, 0xfb3b352f, 0x72f9aa60, 0x2f4073b2, 0x511c47b4,
+	0x1ccb9e3c, 0xe1011cc3, 0x37ce6b77, 0x994bf62a, 0xea3aa1b0, 0xbe517ad2,
+	0x645ed5e4, 0xb8e9b57f, 0xe026d87f, 0xb767e0bd, 0x1a8e7917, 0x5c58ff31,
+	0xcea8d473, 0x7389963f, 0x3fe3fea9, 0x23f3c891, 0x87f6be9f, 0x8bf748ab,
+	0xa3a7d45f, 0x5d2256bd, 0xdd5d79a2, 0x98ae747a, 0xff9c0adf, 0x14be1d43,
+	0xb4abcc23, 0xc791af76, 0xf4fcc523, 0x9beff4be, 0x79ae9b5f, 0xaabb9d12,
+	0x8e7ce897, 0xeeacaed2, 0x93b424e8, 0xe8226a8b, 0xa7dc473e, 0xca9dcfc2,
+	0x7860fb7e, 0x8eb2493f, 0x4bf7dbf8, 0xd21bf689, 0xe9dfb41f, 0xbee0f08e,
+	0xcaee936a, 0x676899b1, 0x8ce7e30f, 0x438307d6, 0xbbc77e0f, 0xc41b5f02,
+	0xbf780779, 0x07c7df12, 0x4ff1f6f3, 0xfedf68eb, 0x9409b90b, 0x7bdd543f,
+	0x72075291, 0x36b26494, 0x49b8c0b4, 0x0f28bd15, 0xb9d13dbc, 0x5f71f105,
+	0x18e52e94, 0x421ce1c1, 0x8e6f80e7, 0x753f21ba, 0xf818b306, 0x9e7e527e,
+	0x4f85867d, 0xb5d850a5, 0xee9d9933, 0x3983b8e1, 0x6d7bdea9, 0xd7da3b46,
+	0x336e61ef, 0xa3f7ee93, 0x0f3177f7, 0x5e61ef3d, 0xac2fffaa, 0x5f0aca85,
+	0x17de3f02, 0x3cf1f9cd, 0x8e8160a6, 0x47dc226f, 0x3f278643, 0xfe9ef80c,
+	0x94fe80cc, 0x76e2ad2f, 0x9ee0f5f0, 0x574bfc2e, 0xf210f3a2, 0x2fe4c77b,
+	0x7e82af9e, 0xf12f6674, 0x91ee7283, 0x7c11884d, 0xdb72fdf1, 0x0f99d1dc,
+	0xe2bf450d, 0x5bd24156, 0x509fdced, 0x2edc0dce, 0xd9ef01e4, 0x343a0489,
+	0xa7bdf95b, 0x3dbd2acc, 0xc793ca02, 0xe59fb4c9, 0x20d6e08f, 0x4331fc7f,
+	0xd9a5f716, 0xd134fda9, 0x3371d4ef, 0x7a82f797, 0xc96ebe93, 0x9327f3c2,
+	0x8afd6b7b, 0x5c6f449f, 0x29cf011e, 0x7fefb4fd, 0x88f59aca, 0xb543a9d7,
+	0x2cb4cdfe, 0x38bdbd6d, 0x2a962466, 0x4b845ee9, 0x193fc289, 0xfdab06cc,
+	0x1d3e6513, 0xd118af53, 0xe493ec17, 0x597482bc, 0xb9d9db7c, 0xcf4ede74,
+	0x4d111ede, 0xbcd1cff7, 0xe6f02b5a, 0x55cec646, 0xa179e998, 0x20ecc2c2,
+	0xc4569ff7, 0x8552f3d3, 0x55b7de95, 0xf8e7a40c, 0x90dfc724, 0x9f95053e,
+	0x670fd1e9, 0xee34e955, 0x9acf8203, 0x9d1d5e75, 0xd124d85f, 0x82079a7e,
+	0x8ef1739a, 0xa73607ac, 0x61739c52, 0x0c41ed43, 0x1d78141f, 0xf39c9093,
+	0x883a2d0f, 0xc06bb2cf, 0x158023e9, 0x24a61c12, 0xa763eb94, 0x7ac6df67,
+	0xe37b1be6, 0xd05183a9, 0x1b0af9ff, 0xc549f5c1, 0xac5e7a28, 0xb3dc13b0,
+	0xa4961c92, 0x67d2a46c, 0x6db73fc4, 0x824fa53b, 0x12ad13fa, 0xb63f2bad,
+	0xe4078f33, 0xd7c0daab, 0xb304ea85, 0xdc74e50d, 0x1e1b19b0, 0x9df7a864,
+	0x1dc70889, 0xe2278a53, 0xcd46d338, 0xeeb47ba3, 0x7bf19afc, 0x58dc2695,
+	0xe9f988dc, 0x247bcbdd, 0x3acbcbe2, 0xff18edeb, 0xa649ff75, 0xde0740fc,
+	0xe3fe80d3, 0xe32f7e71, 0xe2d3d7e2, 0x362f3f50, 0x5fd0e358, 0x79f62ddf,
+	0xe97a045c, 0xc5eceb55, 0x9cce7fed, 0x25bfd2a7, 0xfabaecaf, 0xf2fbf411,
+	0xea1b48c9, 0xe2918bbd, 0x28b6467e, 0x9b48f504, 0x19623bc8, 0xd65015ef,
+	0x5833d45d, 0xebcc18be, 0x9492bce7, 0xe382728b, 0x7a5d8d59, 0x6795fd28,
+	0xed6a3efa, 0x6d4b6f1a, 0x41cf47e1, 0xe747b2f9, 0x723ac036, 0x61b6d599,
+	0x135dd6dc, 0x066dfb4a, 0x87e0fa4a, 0x7c3d6f89, 0xd56488bf, 0xeb6c3c63,
+	0xd1121b2b, 0x392dd80e, 0xfa823ee6, 0xffaf037b, 0xe48fd3d2, 0x53e7c2ed,
+	0x823eaf65, 0xa08a4f78, 0x2b9ff376, 0x36fc8c1e, 0x5d5efd6c, 0xa9bfbc22,
+	0x7c52d4e6, 0xc2a240ce, 0x926d8cf7, 0x8cdd778c, 0x865d4ba8, 0x1fb898af,
+	0xfbc0b06e, 0xed9ff5d0, 0xf4107703, 0x08e2ed6b, 0x525757ca, 0x671bd7bb,
+	0xc10f7fbe, 0x7bc04ee1, 0x8cf3dd35, 0xb8f03edc, 0x5c9f2237, 0x51b40e76,
+	0x7ee1cd7e, 0xd973e916, 0xf5c36b19, 0x0ee75ea0, 0x4ff5831f, 0x76087bf2,
+	0xc70d1cd6, 0xeabd11fd, 0xed082c0c, 0xad1f0c95, 0x56c9654b, 0x259659bc,
+	0x64eb7f3f, 0xd7927946, 0xa53f5237, 0x99e61b66, 0x42bf5e8b, 0x13f61cf1,
+	0xfc8feb66, 0x4fcbc751, 0xfd13b04c, 0xc17e368a, 0x2a0ecdcb, 0x2a77643b,
+	0x0f945fdd, 0xfbf40c76, 0x5877588c, 0x47d270cb, 0x2ed672c4, 0x9f013f7c,
+	0x3abdf02d, 0xfb809dd5, 0x0af594c3, 0x219f99d6, 0x839ba37f, 0xef739bed,
+	0xf775a149, 0xa519d706, 0xfc8c679f, 0x46f5bd7e, 0xb66e1ebe, 0xf42778f0,
+	0x4fe514bf, 0x64931759, 0xae1d5869, 0x6c98cf73, 0x3e37accb, 0xfee2ddce,
+	0x2af813ae, 0x430d6c41, 0xf8ffba42, 0xe9ffc636, 0xfbf23dfe, 0x15675799,
+	0xf941ecf7, 0x4fc3a4e9, 0xe619bf2e, 0xe003f82d, 0x83013820, 0xf2a7f50c,
+	0xe38b2c3e, 0xb669d233, 0x2e2b7e61, 0x33dd116a, 0xd307f0a1, 0xdda0477b,
+	0x995bfab0, 0xffb94bce, 0x7f714a1a, 0x4ddf787f, 0x7af471e2, 0x639e07c0,
+	0x7bf07772, 0x5ac31a9f, 0xf403fe5e, 0x9bdc58df, 0x0dbbc6e2, 0xf756fefc,
+	0xdc5df174, 0x5778dd27, 0xa27dc92c, 0x7601eb89, 0xd38d304f, 0x7e6cf068,
+	0x8f4fbf1a, 0x85c7f6a7, 0xde671d9c, 0x955f707b, 0x7ba467db, 0x1822ab39,
+	0xb55367dd, 0xfdc50064, 0xe07dbfea, 0xbda186df, 0x639f84b2, 0xacf0caab,
+	0x55ff7dc4, 0x70e34cbf, 0x1724de48, 0x260e2fb6, 0xdd355d3d, 0x4071809e,
+	0xba10b4e7, 0xfba7ba57, 0x28323f5e, 0x09ec89e7, 0x0ae78f88, 0xfdf533fa,
+	0xca4e7f41, 0x57748c3d, 0x3a73d1f2, 0x8ecc22f3, 0x21de5bf7, 0x6e15770a,
+	0xbb7e420e, 0x14e828a3, 0x178f6bc6, 0xb8c30d2d, 0x7e4e1de3, 0x359b273f,
+	0x8f3eaed1, 0xfb24e7f9, 0x5657e461, 0xdeedd8a0, 0x1ed3c47c, 0xbdce999f,
+	0xa847f901, 0x7f8544ed, 0xbe77aafe, 0x8ddaed87, 0x92e35ee2, 0xb6cda6af,
+	0x6bf1faaa, 0xf27edfe7, 0x37bf330c, 0x7644cea9, 0x8ec27dc1, 0xb3bc9972,
+	0xad5a0ed1, 0xf607fe73, 0xe9f85aef, 0xa277b470, 0x17fbf067, 0x09be31db,
+	0x7a0a4f75, 0xff7c649d, 0x98517ba0, 0xb2f11bc8, 0x0f28d1f3, 0x9ec7a7bf,
+	0x07e58850, 0x1f70d886, 0x99e45390, 0x7c44b958, 0xf9c2d272, 0x146364e4,
+	0xe33e8fdf, 0x30e9d3da, 0xab8e938f, 0x7a848f6f, 0x79f81b27, 0xcc3cbf8e,
+	0x2f9619cf, 0x60d2913b, 0x7baf3eed, 0xd97bf297, 0x0bf85def, 0x93da6f3a,
+	0xaa5bddfc, 0xd21987dd, 0xce15fedb, 0xb5c67a33, 0x1287a849, 0x2d9f4a4b,
+	0xdbdabd44, 0x2fbe2df9, 0x2394b637, 0xff77ca3e, 0x7fda0a7b, 0xda5ebbed,
+	0xaf9e1071, 0xdeba9d19, 0xade97df8, 0x67618fa9, 0xd72f9ec2, 0xae403d03,
+	0x34edea9f, 0x717e06f6, 0x63a6f04d, 0xe6864bbb, 0xf6378849, 0x1bb31b8b,
+	0x5cdc6d3f, 0x115fa12f, 0x4f4e58dc, 0xe11c33d9, 0xc37928b8, 0xa71e1ef1,
+	0xc97e8fd8, 0x188f0de2, 0x72c7f78a, 0x1f3ff5fe, 0x8ac5a048, 0xaed0327d,
+	0xe71656a4, 0x27143c97, 0x025faff6, 0x0ddea9ef, 0xcbce57be, 0xac344495,
+	0x66f44b1d, 0xee166f5e, 0xf74feceb, 0xfd7e5d32, 0x5fb574a5, 0x0eecffe5,
+	0x9d3f9f2f, 0xa9bcc6e7, 0x7bf7df87, 0xe4068a09, 0x71266db3, 0x51f38f8e,
+	0xc104d6db, 0xda8f9c67, 0xa8f00eb6, 0x9cf3b6e5, 0x8736ada0, 0x6bdbedf6,
+	0x501ed073, 0x6b999fe4, 0x36677ee9, 0xda3876b0, 0xc23d8add, 0xf4e9b51c,
+	0x8e9b53de, 0x3c75ebf5, 0xbb8ca73f, 0x7e24e5f0, 0xeb9998df, 0x0f2f85c5,
+	0x94c6fba1, 0xcf37af7e, 0x4d46d501, 0x5b479079, 0xef9bd69e, 0xeffdf85b,
+	0xcbf1f73b, 0x93c61ec2, 0x40f79d85, 0xbd73de76, 0xf2f05255, 0xfa0e5260,
+	0xaaf28ca3, 0x0be07bbb, 0xbd21ae05, 0xf30b3fb9, 0xbbceb863, 0xbbfae23f,
+	0xf331c33e, 0x6fd72836, 0xb6fb2348, 0xe9f8e74d, 0x79e71c30, 0x3ebaafbe,
+	0x9cf947c2, 0xfdb967fa, 0x5de62e5b, 0x424ce11f, 0xc2a17a7d, 0xffee2f16,
+	0xe96c3b26, 0x98e11589, 0x61dfaff7, 0xd5f8c0c8, 0x63fb3527, 0xad3e2f91,
+	0x37ee9878, 0x75e3bc1c, 0x6e94a3ca, 0x1c7de07d, 0x8336d2f7, 0xd2acdd0d,
+	0x8b5c5ebb, 0x56e948f6, 0x5be716b9, 0xe53f75ba, 0xbed52fc7, 0x71fb8e15,
+	0x9144d42f, 0x53f08c1f, 0x1cf7fafe, 0x2ff8fe0f, 0xabc464f6, 0xc91591f7,
+	0x7f78b5ee, 0x5a2d90c9, 0x3c7d17bc, 0xedea10e9, 0x18cff50b, 0x1fbc56f5,
+	0xa6fdfb56, 0xeff96d06, 0xe4abaf3d, 0xd4e39091, 0xdcc85c74, 0xdda9f507,
+	0xb5645feb, 0x3f18edb3, 0x9727bce8, 0xdae8edcb, 0xbb379475, 0x6e6e78fe,
+	0xe9da853c, 0xa379ab9e, 0xe231b7f8, 0xe6b65efe, 0xdbc424e8, 0x5a2427bc,
+	0x36bde6ef, 0xcfea00e0, 0x9aee3b53, 0x93d9cf42, 0xe8f91f09, 0xd67ee085,
+	0x061bc946, 0x8e28cb65, 0x9e6ac2ef, 0xee5bca17, 0x8d69ee77, 0x2af8fedf,
+	0x0d05f7ed, 0xbcc2bf7b, 0x79f99176, 0x3f741f8a, 0xfba1e3c7, 0x605e177f,
+	0xac2dcfe4, 0x2814cef9, 0xcca851be, 0xda63fdc3, 0x264dc01f, 0xfff0fff0,
+	0x4daee346, 0xe1ea3d47, 0x651b5531, 0x731957c4, 0x2349643e, 0x021bc5bf,
+	0x8137cfe3, 0xeb4992dd, 0x4ae7cd21, 0x8f3a2f75, 0x5059ef0e, 0xda03de26,
+	0xe4eb839c, 0x1b30ba95, 0x9cd69fdf, 0x02d57683, 0x21f9d328, 0x0bce2956,
+	0xf1fee87b, 0xcd06d505, 0x1ec5e07d, 0x7255996d, 0xef14b0fb, 0xfa470ed3,
+	0x92bb50b7, 0xa57ada2d, 0x91e39f30, 0xfb51ffb8, 0x5b7cc5de, 0x2b7da45f,
+	0xefd498df, 0xb1547b15, 0x0e38958f, 0xe460b228, 0x7237bb97, 0x04b77a3d,
+	0x0c3b45f3, 0xafb234ed, 0x420e3b3c, 0x2878aab9, 0xdff54fd9, 0xca5bfdf2,
+	0x0caad4f9, 0x279e3a7b, 0x88375aab, 0xb25bbfe6, 0x7a863ea7, 0xd859ba60,
+	0xe1ee8c57, 0xa44e2aaf, 0x1c23fbf5, 0x2ced0132, 0xf729ef6e, 0xeea227f5,
+	0x18e371c2, 0xb53f8fbf, 0xb37a8bd6, 0x3fae29ea, 0x81563b14, 0x4f675f3b,
+	0xb36e75c1, 0xcdebe9d9, 0x23a56ff7, 0x09bff9dc, 0x4557bc22, 0xfce8c2f8,
+	0x0dd4517f, 0xc59ba7ad, 0xabcca0fa, 0x7dd07255, 0x293d4ae8, 0x9cdbeb99,
+	0xa28bfb5c, 0x0b39c51e, 0x6fab1d72, 0x3c147c01, 0x1fa2b3ad, 0xbb6789dd,
+	0x13ef1d3d, 0x94175d68, 0xcc9cf089, 0x47367ae0, 0xf6061bdc, 0x3c137dbb,
+	0x9a759383, 0x32706578, 0xc163a7b7, 0x5af1c27f, 0x5438f227, 0xfc839658,
+	0xe6a9c079, 0x19e53c1e, 0x302be02b, 0xa3f4fe3a, 0xd274f000, 0x7bc7027b,
+	0xad12fdeb, 0xa21f3047, 0x83afce5f, 0x2ad00e28, 0x4e8503d6, 0xb4d92fc0,
+	0x54bd09ce, 0x21f80ab5, 0x2da1ed15, 0x6afa835b, 0x0be286f8, 0x3ebe2eec,
+	0x7c704554, 0x4c393d56, 0x6f82e5d8, 0xbf120c9e, 0x6cedc0c7, 0xec51fd65,
+	0x3d3e6570, 0xef40e1d9, 0x7c2ac961, 0xe999d3f9, 0x7dead93d, 0x5e74fe94,
+	0xd2986e60, 0x0bc1550a, 0x5c067825, 0x6b7d91d2, 0xde0892ce, 0x2a7ad581,
+	0xb259d51f, 0x8da6ee51, 0x11f179dd, 0x7e7857d4, 0xebf47907, 0x39bbbeef,
+	0xa951f707, 0x7dc472fe, 0xeb0fc8ca, 0xef183799, 0xd894afd9, 0xa03acd69,
+	0x8fdfe32d, 0xb9fabb63, 0xf89efd5e, 0xdcfd9ff7, 0x69d8c159, 0xf85d8590,
+	0xebc347ec, 0x4665fbd5, 0xb93c7236, 0x5f4f308e, 0x597677d2, 0x0467ef8d,
+	0xcbfcee1f, 0x6e3023ab, 0x687dae31, 0xe9679e2f, 0xd3ef53a7, 0x5ed660ed,
+	0xa3b4efb8, 0xee17ad31, 0x2438eb4b, 0xf0033987, 0x038056f5, 0x572ff1e3,
+	0x5ed9e998, 0xf0652ac3, 0x8f99da2b, 0x6bba67f6, 0x5f902ccc, 0x73b934ba,
+	0x739319ff, 0x3ba5f7d4, 0xa4ec7d68, 0x9fa9a5d3, 0xc77787e8, 0x569dfe3f,
+	0x87f913d6, 0xebf715e3, 0x06b75e20, 0x740a4cb5, 0xe04aafde, 0xafbeda6d,
+	0xe0e33f68, 0x943a8dc6, 0x3a35c1f7, 0x26b93acd, 0xca43ec59, 0xd7089964,
+	0x61417db4, 0x438f4859, 0xe6082db2, 0xccfc6ae7, 0xd7e00ce8, 0xfb11e3f9,
+	0x8702fdc7, 0xa7842d93, 0xf25a86dd, 0x365f772b, 0xbb29fdd3, 0x8125958c,
+	0x23eccce0, 0xd8ebc405, 0x5f6833f3, 0x5e157fca, 0x7a87b5c7, 0x588e3173,
+	0xbb1c78c3, 0x7d71bf1b, 0xd185b1d4, 0x710ef739, 0x1b63a80e, 0xa01ebca3,
+	0x77dc49e2, 0x8b7df203, 0x80d63f7a, 0xe32f1d86, 0x28de5efa, 0x72e4fed1,
+	0xf7118b7d, 0x221aba5b, 0x65bfcc64, 0xae3dc558, 0x59b0cb7a, 0x9c38392a,
+	0x17e7e7ac, 0x07beecc6, 0xc972bdc7, 0xec87e748, 0xef747c07, 0x11c695c0,
+	0x3cefbebd, 0x6c156bce, 0x7b3bde0a, 0x5f119938, 0xd0c1f3f8, 0xf29ac16d,
+	0x8899d958, 0xd4cd34f2, 0x002da0f2, 0xc4528add, 0x7aa370fa, 0x89fff3cc,
+	0xe8a63b1e, 0x8eaca731, 0x74a46487, 0x817163d3, 0xc962d8f4, 0x5ef8871a,
+	0x871694dc, 0xd87c5cf4, 0x8f481310, 0xac38076d, 0x007f7720, 0x7b67c3f9,
+	0x9bb1e81d, 0x0eac7a54, 0xbf0058f4, 0x3ae52924, 0x5ff3cc7a, 0x51db6f23,
+	0xe798058f, 0x1fae14f0, 0xbc363d14, 0xb1e914f1, 0xcd3a75e1, 0x29feda39,
+	0x5263d3d7, 0x2c68accc, 0x01216c1b, 0x89f106f8, 0x27c47779, 0xd41c713e,
+	0x9629f967, 0xfd9f4bbf, 0xecfa7af8, 0x8abf08bf, 0x3afc5b3e, 0x3ba37f23,
+	0xdfe231df, 0xfd18bbc5, 0x26e2cfce, 0x3716cfae, 0xcf0fbe31, 0xec0d8f4f,
+	0xff18c7a6, 0x6f2f165d, 0x7d486aef, 0x2fe85ee6, 0x99b06ed3, 0x97667ea1,
+	0xeb56cb5e, 0x1e94fcb5, 0x1ba1daf4, 0x0baf6bd3, 0xaafa06bd, 0x7f51ea2f,
+	0x6a35b0be, 0xf763977f, 0x5edbf3e8, 0x5b78f943, 0x4701f3a6, 0x9dfebe45,
+	0x90b3e7d1, 0x1e11eaaf, 0x4235d390, 0xdc2adb5e, 0x03f8ffd4, 0xdb657e7c,
+	0xca0f5a24, 0x57bdb8eb, 0xf07b235e, 0x31a4e180, 0xff3ed15f, 0xe18926e2,
+	0xa6e9b2d1, 0xfef1a7ca, 0x8192f630, 0xd4e53889, 0x143f150c, 0xf8a12a8c,
+	0x999e8161, 0xc96ddf71, 0xb73fbe28, 0x7b959444, 0xf53b0ba2, 0xcdbedfa0,
+	0xf7e9fb86, 0x7bcffc34, 0xdcf7134e, 0xf2417b4d, 0xdd5ffde0, 0x712a7bcf,
+	0x97fbed38, 0xcba77cc5, 0xf61f842d, 0xde73e06e, 0xe5e3fb2f, 0x8d4bc090,
+	0x478bc5ac, 0xe517880a, 0x8782ad5c, 0x565bb7e2, 0xf8a75c60, 0x32fc8959,
+	0x782b79ff, 0x761f76ea, 0x909dff23, 0xdb62f7ee, 0xd25bbf35, 0x144477ed,
+	0x7fcdfb3c, 0x323fa2bb, 0x37bc08d8, 0xf482f81b, 0xfc4ffb87, 0xb8c7421e,
+	0x3d6a71fe, 0xc3c09afc, 0xe371ca88, 0x2e99add1, 0xd5f98afc, 0x804c1ff7,
+	0xb71f67f9, 0x6303fdd2, 0x9ee898c7, 0x3e41adbe, 0x9f0a6fd2, 0x3e70fa19,
+	0xecfd116b, 0x4b945c4e, 0x241a74fb, 0x2e13da0b, 0x37bf106f, 0x082df805,
+	0xf67fecaa, 0x478124ea, 0x689efd0b, 0x006f5883, 0x4e57e8ef, 0xc01fd652,
+	0x88cfca3b, 0xd7074e46, 0x2c874e16, 0xe567e3c6, 0xf30d92d5, 0xf70de5ea,
+	0x8a3e711b, 0x50bf85de, 0xfc545d35, 0x27f357a9, 0x7bad547d, 0x34fbe225,
+	0x1887e553, 0xfc06993f, 0x0cd891be, 0xfc3df7fe, 0x5f77eddb, 0x2f7bf3ae,
+	0xa78e1f72, 0xf44788ed, 0xdc7d12f3, 0xbac2f26e, 0xddf5d610, 0xf06b77a5,
+	0x6bb9fe38, 0x249abf9c, 0x3b01c62b, 0xefc354f1, 0xf056cf6d, 0x788afc84,
+	0x63279c6f, 0xf8837e79, 0xf9bf1fdd, 0xb5083ee2, 0x9d37171c, 0x906ffde2,
+	0xbcc02c6c, 0x7fdfe47b, 0x927b6f90, 0x2d1f435f, 0xe413beff, 0x2efb823b,
+	0x77e24ddc, 0x34231a19, 0x7dfec279, 0x35b01db8, 0xfd1cf808, 0x1b06c3e8,
+	0x2fe0a7de, 0x3d62b1ef, 0xaadf7b43, 0x420f97ca, 0xb12e3180, 0x28ceccc5,
+	0x76e5f470, 0x6edf5aa5, 0xb331620f, 0xbfee7ab2, 0x4f5ba09f, 0x1e528df6,
+	0x5ea1e386, 0x54f1806c, 0x7d7f2cf9, 0xd7e5f8af, 0x0fc6579b, 0xce32979c,
+	0xd87e7bdf, 0xfe799ac5, 0xd0245f02, 0x26dfe179, 0x9fa9bc63, 0x7bdf57a4,
+	0xfe6fdcae, 0x3b3fe84f, 0xfee7a625, 0xf685bc59, 0x4efb2937, 0x0e3cfd94,
+	0xf3fb130b, 0xae33fe6f, 0xfcec57e3, 0x8e9641fc, 0xae33707d, 0x3a06b90f,
+	0x88e57ac7, 0x573fe281, 0x2e7bf026, 0xbf7b7f6f, 0xedf2f51e, 0xff0114a8,
+	0xe44b67b7, 0xaec51d1f, 0x6d1da347, 0x80257da6, 0x1f9811bf, 0x1ca9a8c9,
+	0x333ee78f, 0xe19678b7, 0x17de36d3, 0x6dd20efd, 0x7bf74c9c, 0xc6a3db34,
+	0xc0fa3ae3, 0x71819659, 0xa9ef5877, 0x1621e67d, 0xd8c6f583, 0x18fdc863,
+	0xb1f9f75d, 0xe8c70099, 0x0acdb223, 0x0fefa6f5, 0xf77cc50d, 0xe63af5c0,
+	0x0c6be154, 0x73c32cf3, 0xed5ba33e, 0x22ee1133, 0x2e305fb0, 0x71b8d45f,
+	0x2e439e19, 0x7b512f5a, 0x2939db97, 0xbdb3e61c, 0x4349b3fa, 0x3d401f50,
+	0x9eb5c6ec, 0x48d573d7, 0xcf394c36, 0x24675c6f, 0xefc3517d, 0x91eed86f,
+	0xebf79998, 0xdbbf4331, 0x2cfb43d7, 0xd05b638a, 0x7cd5720e, 0x5cdffb46,
+	0xdfb52700, 0xccc5cfc6, 0x94567687, 0xa9fb9a97, 0x12f5e2bf, 0x457323c3,
+	0x543af8db, 0xc360c474, 0x9f7b75ef, 0x2a74f5a5, 0x8a90978c, 0x02778eeb,
+	0x884739c5, 0xffc77b7d, 0xed5df90f, 0xd58fd38c, 0x2feb92fc, 0x9fbf2989,
+	0x4f9f57ab, 0x97d3e8eb, 0x2db10bef, 0x3f414631, 0x498a8cef, 0x7d5f11d5,
+	0x71b4e746, 0xf013935f, 0x179c547d, 0x8cea3fdb, 0x409f7d51, 0x4f3f2b2f,
+	0x8e30d05b, 0x321551ce, 0x9aa39d07, 0x8fdb9a36, 0xc828feef, 0xde33fb83,
+	0xe37af835, 0xe23ffdfb, 0xb6dcd3bf, 0xb6dfeb9d, 0x1fda16e4, 0x307f1e7b,
+	0xb65c6009, 0x717d265e, 0xce819b7e, 0x7018c90d, 0xe76dfc44, 0xf5fec5f6,
+	0x5bf3dfbc, 0x7e361db8, 0x70931dc3, 0x59b05dbd, 0xf5c46739, 0xce3fe2b3,
+	0x62f388b7, 0xfc8d1b95, 0x5fefacde, 0xac3d1477, 0xbf911efc, 0xfceb2d9e,
+	0xc92f6cfd, 0xffad594f, 0x2ed0ccf9, 0xefe9043f, 0xb9f88afd, 0xa18188fc,
+	0xb99d221f, 0x4f8ff944, 0xef871d70, 0x3b251ba3, 0x3a2a3b9e, 0x1d90f26e,
+	0xdf7799ed, 0x393d71cf, 0x3afba261, 0x1cf055ce, 0xef9328f6, 0xf781bf2f,
+	0xe3351c9f, 0x97e03cce, 0x05ef8479, 0x3be1116c, 0x473f336b, 0x2ab47597,
+	0xe7ae3e76, 0x7fdc7813, 0x9cccb541, 0x89f0fd2a, 0x37799f64, 0x1ee8175f,
+	0x598e856b, 0xb8f9cac6, 0xe562de9e, 0xd9bad8fa, 0x2fcde740, 0x760cfd08,
+	0x5103dd3e, 0xac5d6bbc, 0xe2ff4551, 0xf8b175a6, 0xc42b2853, 0xe265b439,
+	0x91b17a9c, 0x47bc538f, 0x8d546cb2, 0xf4a3f4a3, 0xdbc5dc6b, 0x67f135a5,
+	0x2317fd4f, 0x2fcf347c, 0xfc27a88c, 0x7e36e9fb, 0x7a8cfd0f, 0xee155aff,
+	0xaef51817, 0x8c72974c, 0x2d35333a, 0x0f643ef0, 0xd31fcf8f, 0x747f7e69,
+	0x35825fd4, 0x6cba91f9, 0xdfa07790, 0x4edc0d6d, 0x653ecbab, 0xb2a2cb2c,
+	0x5cbbe505, 0x27cb85c4, 0x75f57df0, 0xa3974719, 0x92cd4fbc, 0xdb981f88,
+	0x29dfc469, 0x8accbb07, 0x5905a779, 0x6802fdbc, 0xf758728f, 0xd04b972c,
+	0x1fd4560f, 0x830017ff, 0x8000007b, 0x00008000, 0x00088b1f, 0x00000000,
+	0x7cedff00, 0x55537c7b, 0x393ef0b6, 0x526d3479, 0xa0fa5b42, 0xb4db4e50,
+	0x9494b14d, 0x27457897, 0x880b5a3c, 0x46107006, 0xf4228206, 0xbd185499,
+	0x35fde338, 0x9c414415, 0x0e7c570b, 0x42d2d37a, 0x1429a2c1, 0x20d5b16c,
+	0xb47441d2, 0x3bd15ef6, 0x0f8afea3, 0x52d25a04, 0x8ef4f987, 0x6b5adfa3,
+	0xa126d39f, 0xdf7ef515, 0x37f5375f, 0xef6758b3, 0xbdeb1fb3, 0xce275ef6,
+	0x620a3b5d, 0xd67318e3, 0x319e920a, 0x6abd54d6, 0xc614f273, 0x2c8ba68a,
+	0x67e7c242, 0xf01192b4, 0x2c7133e6, 0xd3e3b187, 0x1939db3f, 0x74339dda,
+	0x7ff41d26, 0xc637d357, 0xf3ec6064, 0x991cc64a, 0x5ea5b388, 0x698459c0,
+	0x8c09e2c2, 0x060e313d, 0xead8ca99, 0x0c0599e6, 0xeccddf9e, 0xf8bfb19b,
+	0x7981f436, 0x47a20d5d, 0x2e9c0027, 0xc60dba8e, 0xc680f77d, 0x7e3b280a,
+	0xfdda8e83, 0x153da007, 0x4faed8e0, 0xdcbfc004, 0xe86e61a5, 0xc89771b0,
+	0xb2fff418, 0xc5f7a05e, 0x90597ee7, 0x3adaf804, 0x2983aac1, 0xad9aef8f,
+	0x1efec24d, 0xd9bc61c0, 0xbc6869cf, 0x7f78fbb5, 0xc5e433f8, 0xf186b633,
+	0xe2a635bf, 0x632e599b, 0x65a7cce5, 0x69efd0e9, 0x115da7cd, 0xf87bedbc,
+	0x1827b15f, 0xc60fad2f, 0x4bb6d9cb, 0x6f403462, 0x750ef3f0, 0xef386dd7,
+	0xb4f41bfa, 0xb637d9ee, 0xeb8f5e9c, 0x5c30d06e, 0xef1bece7, 0xba02ef8f,
+	0x963351ae, 0x8e90693c, 0x0cc788e5, 0x559d8eb1, 0xb31fa4da, 0x1c75909e,
+	0x3b8c6719, 0x63fc0d7b, 0x3df49b12, 0xb8dcee90, 0x628d8c91, 0x740b5dcc,
+	0xb67e0049, 0xf00f360a, 0x4765b8a5, 0xf3d616bc, 0x02fdfe3d, 0xf11db6f0,
+	0xb6d73c22, 0xbd2fd408, 0xad62c38d, 0x60aff16d, 0x0aafc51f, 0xb0696aa6,
+	0xb9ce32bf, 0x7df10271, 0xbfef3373, 0xb5e015b1, 0xac5f8fc3, 0x0ac6bedd,
+	0x65dd4a70, 0x72b864ad, 0xb17e651c, 0x739c782d, 0x8e857cb2, 0x2c1a2f97,
+	0x10bba46a, 0xaf7e4569, 0xadbcb817, 0xdc799bbf, 0xacc94f20, 0x87406042,
+	0x9013e644, 0xbd29c0df, 0x86fce41d, 0xcb55903e, 0xf17edd20, 0x1d5b0475,
+	0x6c99c740, 0x3b3e1064, 0x7fa82922, 0xa83529be, 0xecc4a6fd, 0x52b9f6a0,
+	0xdf3e105e, 0xff505d72, 0x4199d605, 0xe7d3adf8, 0x685ff506, 0xdb84185b,
+	0xeb8d4998, 0xba5cad6f, 0x999073f8, 0x041d2b57, 0x70287a15, 0xd8c54e86,
+	0xee0bc13f, 0xa036ec9b, 0x19288ccf, 0x3e397367, 0xd8d1f002, 0x06ddb37e,
+	0x20919d74, 0xc7016ce3, 0x05f69593, 0xe538ffbc, 0xfb785bfd, 0x2dfb4a35,
+	0xd2a27dbc, 0xafc72b7e, 0xf1eed467, 0x03776adc, 0x8ed1ebfe, 0xb6f8096a,
+	0x138aebe4, 0xfde9a023, 0xa77745aa, 0x45583f02, 0x18d36306, 0x0034875b,
+	0xed182ed6, 0x351a4a78, 0x7ff4aed8, 0xe357b255, 0xd14bdef3, 0x63226cb9,
+	0x51dfc80d, 0xe6321f3f, 0x716779a3, 0x1159b2d2, 0x33ea1f06, 0x0cf4d08b,
+	0x631a51e8, 0x0db18d82, 0x906f4831, 0x0477a213, 0x89a55f41, 0x8995ebe0,
+	0x94a8df04, 0x63336ad8, 0x821695ed, 0xf4ad2b27, 0x74e554fc, 0xda576f82,
+	0x5953be08, 0xd2a3b048, 0xe290504e, 0x9f1872d8, 0xa23eb1ed, 0xd5b87a41,
+	0xfcc2cf23, 0x7e40cff8, 0xd4c64286, 0x1722acec, 0xcabf79d0, 0x65f48ad6,
+	0x6ce98c6c, 0x5ef3e0d4, 0x815243a1, 0x46a7bade, 0x0f40eb58, 0xf37a0f8c,
+	0x4617a04c, 0x11bac1a7, 0xe59c6168, 0xbb43524b, 0xbad69d71, 0x029fda11,
+	0xf587ab73, 0xda991ad4, 0x1cc9f602, 0x34f1100f, 0xf7aa8d0e, 0x7fec0552,
+	0x1ff5045f, 0x0236c603, 0x196825fa, 0x7de0f7c3, 0x1ffd8116, 0xdfd81163,
+	0x684024fc, 0x10e1adaf, 0x37f48224, 0x43cde741, 0xe2e09efb, 0xd555d8eb,
+	0xee304921, 0x5c7ca9ae, 0x29f13158, 0x8119cc5f, 0x499fb2f6, 0xb8394c23,
+	0x005abd1f, 0x83d5e881, 0x2bb009df, 0x45034f59, 0xdb24f402, 0x01d4c113,
+	0xbd4d757a, 0xe09f0829, 0x3fea0c4d, 0x6a0a59b1, 0x8259f3cf, 0xb49f27da,
+	0x3b53e106, 0xbff507a6, 0x105b43f6, 0x61575d7e, 0xcfebff50, 0xfef083d9,
+	0x618fd81c, 0x94defe78, 0x9ff50428, 0x703ade0b, 0x89aac67c, 0x232df33e,
+	0x1bf79e83, 0x1b869d38, 0x78358177, 0xb71f855c, 0x7f1e0f4e, 0xdc782da1,
+	0x3d87cb1f, 0x906a27a0, 0x13d07aff, 0x4f41fb84, 0x0de720d4, 0xbf8827a0,
+	0xd0827a08, 0xcf827a0b, 0x209e820f, 0x827a04de, 0x13d011f8, 0x4f419bc4,
+	0x3d051e10, 0xa357e7c1, 0xef3cbb57, 0x53de7949, 0xed8cbcf2, 0x8d5d3a20,
+	0xefcb6f2e, 0xdfbf23bf, 0x079bef81, 0x30bcb0e5, 0xc835f543, 0xf398ccf3,
+	0x87582eda, 0x01575d6d, 0x6f7d4dc6, 0x8246ac8a, 0xc9cf0e6e, 0x5aab8c4a,
+	0x9456d962, 0x5bdf7b5f, 0xa70fc42a, 0xfb42b69b, 0x78ffe696, 0x4dfddb07,
+	0xcdf184a2, 0x459fcdeb, 0x5f3d38e3, 0x2c753247, 0x3459f7be, 0xdf654bc6,
+	0x42b7c230, 0xb9c5fa3b, 0xe5f3228d, 0xb57bbaa0, 0x5663ded8, 0xe3168f70,
+	0xa3437b33, 0x5a52f916, 0x6fed48df, 0xedc1357a, 0xed41d5f5, 0xb00fec26,
+	0x4689ed54, 0x56685e7a, 0xff51f3c6, 0xc3f73332, 0x6f8fea17, 0x5bd61ebe,
+	0x562ab8de, 0x3697f584, 0xd77f17bc, 0xe2ffd00f, 0x1c721791, 0x0b797ef0,
+	0x1c18678c, 0x2345bcaf, 0x65fd7ce3, 0x1882c6e6, 0x621a1ba0, 0x87acfcb0,
+	0xc01b676d, 0xd736942e, 0x577c6195, 0xc343b96a, 0x5ebd3e80, 0x01d710b1,
+	0x71062a7f, 0x9189995b, 0x7ef1e87f, 0x8c177d15, 0xc4f79afb, 0x7a87e82d,
+	0xe3478f5b, 0xd04dbdbc, 0xabbf803f, 0xb11c7953, 0xfc4b553a, 0x1e3a69eb,
+	0x16fb412d, 0x774e71ef, 0xfff68fb5, 0x02f78cba, 0x8b377a24, 0x5afa2e3c,
+	0xc6507c45, 0x9a33a173, 0x4619ed8a, 0x97a757dc, 0xaa7f77cf, 0x579b9fc4,
+	0x9ff5c6ad, 0x55365c4a, 0xae05fb24, 0xf1def01a, 0xc2b6ebf3, 0x30bd4a52,
+	0xf7f210ee, 0xbb6e3ca8, 0x69bf471c, 0x1a3ed43e, 0x30aa7ee8, 0x807c8f36,
+	0xaa636fdc, 0x6815fa8a, 0xe80ae61d, 0x8c9069d7, 0x160fcf28, 0xbf911ba6,
+	0xe7c423af, 0x0eb5bb85, 0x7c4d2580, 0x47534ebe, 0x675dca34, 0xe31164d3,
+	0x7fbc6551, 0x901de791, 0xb9be01ef, 0x9e454f89, 0x338e036a, 0xfcfe3fc8,
+	0xbd1354fe, 0xdef3ca77, 0x7f603b92, 0x2b28969d, 0xcb5da5f2, 0xa5fd708a,
+	0xbe7160e8, 0xa46ae4d6, 0xfddf3283, 0x2d7a3f32, 0xbfabe22a, 0xbbf72359,
+	0xf5058ea3, 0xd57e70d3, 0xe4c7af06, 0x3bfbf339, 0x73d97fa0, 0xbef8c322,
+	0x8f11534c, 0x20fcc7fb, 0x9d32dd68, 0xf8be34cb, 0x2d7900f8, 0x1bd0196b,
+	0x8b79c903, 0xf11227a2, 0xa763e153, 0x4aebe445, 0x2c1879d4, 0x8eb1acb9,
+	0xced41ae4, 0x4d3907ad, 0xff20ea8e, 0xdccffc97, 0xfc0ad54f, 0xfb2559b9,
+	0xb5c7154d, 0x3e2fd100, 0x7853fb27, 0x1f00999f, 0x00146c0b, 0x4fa614d7,
+	0x917c4155, 0x21e6362c, 0xb6a9753f, 0xff9854a6, 0xc87ec97d, 0x6489f142,
+	0x553e43b4, 0x66e0d97e, 0x7efed023, 0xdbce24f4, 0x047904df, 0xd11e5bcc,
+	0x9073ef3c, 0x282b7ecf, 0x7fb7ac08, 0x5ce28697, 0x00833b10, 0xe99acd71,
+	0x94be5f5c, 0x8844d31c, 0x54abcb17, 0xc832afb4, 0x5f98f4bf, 0x62eef6c9,
+	0x28adea63, 0x452765a7, 0x2be60453, 0x9d7fd4de, 0x86837881, 0x57a72af2,
+	0xff30fab0, 0x255a326b, 0x9deacfc0, 0x9d379869, 0xe2d3eaad, 0x3e21677b,
+	0xcbcf9c7f, 0xa7cb4f50, 0xd4519f73, 0x193da3bc, 0x57e60960, 0xafc8cfe2,
+	0x3a99f242, 0x8c75c7fc, 0xf21539fd, 0xb26f8c1a, 0x37c63659, 0x048ce2f9,
+	0x7f995fd2, 0x1710276c, 0x13f5a612, 0xdfa809ac, 0x3cd2d45b, 0xab6f77dc,
+	0x71f484c6, 0xc62a1db5, 0x22ca7b75, 0xafd82aad, 0xa251c373, 0x815fef63,
+	0xf65710ce, 0x33ca3226, 0x67a7197b, 0x6797336f, 0x44f04697, 0x9e20fbe0,
+	0xe0845e34, 0x5ea682a9, 0xd9347f77, 0x510ac621, 0xcb2dd7fe, 0x68bc6150,
+	0x80337203, 0x57b91447, 0xf5c0a5fc, 0x977546fc, 0x7bde1238, 0xe7fdc343,
+	0x48d353df, 0x9968e7ee, 0x46f5f103, 0xc62bf92b, 0x887de8aa, 0x52fe28a7,
+	0x67c435fc, 0xc7254f14, 0x147e497a, 0x6d50bc3f, 0xab8e04d2, 0x821bdfbc,
+	0x0580f32b, 0xe0ede3e1, 0xf8c0def1, 0xa6fc7923, 0x1e740f8c, 0x6afe7481,
+	0x70fc958a, 0x91f042ca, 0xa41577a4, 0xf59e8a77, 0x01cd5c80, 0x3810cab9,
+	0x1d76cabf, 0x728073a3, 0x00e741d6, 0xde7cd105, 0xf11f9c02, 0xd2130e48,
+	0xedffda04, 0xdb5e9c69, 0xa7d8a864, 0xc4b66913, 0x698d8034, 0xa469318e,
+	0xb792261f, 0x408cb2f5, 0x35d0927c, 0xf75d7d84, 0xf06e7e27, 0xda3dc815,
+	0x08575f99, 0xfe203992, 0x6ed3fd29, 0x69c34b2d, 0x18161d6c, 0xbd7188af,
+	0xc5d9e451, 0x1b95b2bb, 0x303992f4, 0x7fc3b2fe, 0x72c567a0, 0x279e117b,
+	0xd8e0fe40, 0x27992f10, 0x8f627bc3, 0x4fd73c16, 0x73577396, 0x73d3ee30,
+	0x0519f379, 0xffc9c60f, 0xf5e72694, 0xc8a7fcb2, 0x10ed58f2, 0xabdf683c,
+	0xee1355bf, 0x90782e5e, 0x8784bf07, 0x45e4621b, 0x99a2bf62, 0xbf47f41e,
+	0x8ef29404, 0x2fa4719d, 0xb9fb08d4, 0x2fffde4d, 0x0263bed5, 0xc684e7ec,
+	0xc2f98a9b, 0x2b08f289, 0x418cbf8e, 0x64f60180, 0x7820eb39, 0xd879ca3a,
+	0xc7bb8347, 0x81ff3c62, 0xf8c56743, 0x8d537aa7, 0x2e66ed11, 0x3cc264db,
+	0xff514805, 0x9f1fe4fd, 0x0b8830cf, 0x5f0aff90, 0xcbecd31b, 0x073f00d2,
+	0x749c493c, 0xefa5fbe5, 0x3e468e1f, 0xd0e6ff76, 0xda19db92, 0x3bb23e9d,
+	0x1a551525, 0xa8c41c9c, 0x906d32c3, 0xe0bf0abf, 0x1f1052df, 0x90630f61,
+	0x42cf622e, 0x177ffbd2, 0xabb1fa19, 0xf3a151f1, 0xac7e642f, 0x21f6e16d,
+	0xdd0abf94, 0xa21e676f, 0x5daff81f, 0x23a617c4, 0xffca147b, 0x0407f1ab,
+	0xcd363971, 0xe431d38e, 0xdb8ab26b, 0x2035e4ab, 0x3beeb02f, 0x0bada398,
+	0x8fa892e0, 0x32e72434, 0x7ccb969f, 0x167980fa, 0xdfff5258, 0x9a44e9f1,
+	0xe91a7b63, 0xfd4869ad, 0x32c7d50c, 0xe2aefac9, 0x67a43c6f, 0x3579fac1,
+	0xf85664bd, 0x8e7f802f, 0x7fa4d10d, 0x625d7f0a, 0xd5f7e903, 0xad18f3cf,
+	0xf059bcab, 0x847f52f8, 0x10b00a5e, 0x884363e0, 0x1afc2a3e, 0xf6291ece,
+	0xfb96b4ec, 0xa27df763, 0x8ff2f307, 0x1309df05, 0xceeca7da, 0xd282640c,
+	0x8eaae3ff, 0x38c0f7b1, 0xf0e4cf1f, 0x0159c634, 0xad922db8, 0xa49e23b4,
+	0x3f7ee373, 0xa167b216, 0xf858fe7f, 0x9e385be7, 0x5f1095a0, 0x04cb3096,
+	0xef0d69f8, 0xc57dd8af, 0xecbc7fde, 0x4fd439da, 0xbee06f60, 0x47a25c60,
+	0xa782fddf, 0x256a4406, 0x5f5c6a98, 0x0aa7acea, 0x27f9e0d3, 0x43cf4dbf,
+	0x05d6d87e, 0x2e7e878f, 0x3ce22275, 0xebf1baef, 0x9caacd3e, 0xfc0679c1,
+	0xf44b9cd4, 0xfd53f15c, 0xb25a1965, 0x2833ab53, 0x69922fde, 0x1ec98b6d,
+	0x87f829f1, 0x08fa4f7e, 0x5fa0ce55, 0xc8793fe9, 0xefa008e0, 0x4c3bf079,
+	0x3f67801b, 0x97e81296, 0x3479ed8e, 0xa451f913, 0xb9e2e775, 0x3feab9e3,
+	0x2edfa0a4, 0x2670f3da, 0xb67b8dc5, 0x5ffc6264, 0xa668f354, 0x0728f08d,
+	0x4e6a1fe5, 0xd703ee87, 0x101adeed, 0xf26526a7, 0xc47979f8, 0x1f8c7cb1,
+	0xf1735de7, 0xcbf41321, 0x4260adf8, 0xeb35f831, 0xddfd0878, 0x77970b0a,
+	0xec8233b6, 0x43678c31, 0x2f65d7be, 0x3d7d45a8, 0xb34cf965, 0x74bfe31a,
+	0x056bd135, 0x804b6cf3, 0x6088f676, 0xfd8163aa, 0xff6356c7, 0x6d049b55,
+	0xb1fa1c62, 0x97987991, 0xd247d2e9, 0x247cee3a, 0xaf9f1daf, 0x9f3f8078,
+	0x7534f3a7, 0x694f38e2, 0x37a475ad, 0x278c34f6, 0xd2ebf595, 0xcadef4b5,
+	0xcbc5026d, 0x4f193cca, 0xee0757c6, 0xfdce9753, 0x8db29b32, 0x32adcfec,
+	0xe07e6e5f, 0x611237bd, 0x1d6349dc, 0x7f6874c6, 0x66b389e7, 0x139f3c1f,
+	0xf3073e73, 0xe3ad0c86, 0x77dc62d9, 0xfb8ace8d, 0x2c9b9298, 0xdfff6026,
+	0xe11c7ccc, 0x3d5607ca, 0xf2768c5b, 0x73ca08e9, 0x13adf594, 0x83e61524,
+	0xbf6fabc7, 0xee76e913, 0x778a0889, 0x256755d7, 0xdfc81fb0, 0xa5ff02f7,
+	0x41f6c64c, 0x05f08efe, 0xd825dfc8, 0x44ca81e2, 0x94aa5fc2, 0x5ca5b208,
+	0xb899d6be, 0xbc6e193d, 0x4b9790c9, 0x3ca64760, 0x7c41e302, 0xcd9c6f38,
+	0xcaf40e92, 0xb35e5f18, 0x0657de45, 0x4ee79fbc, 0x98748d9d, 0x769ee5b2,
+	0xd2e31d0c, 0x56f2fe79, 0xa82923e7, 0x381f6bc7, 0xb4317cf3, 0xe7b74aaf,
+	0xbb11fbe1, 0x7e3e512e, 0x15e1e5bc, 0x1aa2ef48, 0xbc9fdf1d, 0x644f73ef,
+	0xe78b3c26, 0x286a6f75, 0x3aed763f, 0x8016fcf3, 0x47bb6d77, 0x3fef281b,
+	0x7113bf76, 0xba7f533d, 0x97470d9e, 0x8f67ae9f, 0xd53e90a6, 0xfce59e80,
+	0x3d733d7c, 0xdcf44550, 0x15ff6e9c, 0x8d39dbca, 0xebf5053b, 0x240df65c,
+	0x8136eef7, 0x5fd8a1f8, 0xf2a5fde5, 0xde554bfe, 0xce02336d, 0xc6432f15,
+	0xd63ef486, 0xc62665f2, 0x979b97b5, 0x47dc088d, 0xfb023c28, 0x35864c86,
+	0xda7dbd03, 0x69a7db2b, 0xd856e91d, 0x8f1534df, 0xabdb4367, 0xbdb255d2,
+	0xcf0ffc85, 0xc5ff1433, 0x0f78b43a, 0xf82ad651, 0xaa3ef122, 0x6af3a6f9,
+	0xd81257ba, 0x7de741a7, 0xe01a7d8c, 0xe75b8777, 0xc713a0d5, 0xe3da0f51,
+	0x31543f6b, 0xbdbf805f, 0xf9922bae, 0xc81de602, 0x114f6023, 0x4b7f1fc0,
+	0xd87d9052, 0xe7042e9e, 0x36aef013, 0x15f21fa0, 0x2dfc65ef, 0x9f8835d9,
+	0xfb3e72d7, 0xc47c408f, 0x389849cf, 0xe71e906d, 0xd173ba5b, 0x70f42b2e,
+	0xb926ed1e, 0xf87e6b29, 0x99f44092, 0x7b9d5e7b, 0xdb1cfa75, 0x7c8b9dd3,
+	0x9ae9af3d, 0x5f947986, 0xfc8b95db, 0xedc2be71, 0x93a54ffe, 0x11f8bcf2,
+	0x05d800d8, 0x3ca260a7, 0xa1ec5f2f, 0x927fdcbc, 0x96cee5e7, 0xfb7764dd,
+	0x88b9f95b, 0x9051d54b, 0x1508e780, 0xeed1da67, 0xfcf227f5, 0x21b7c609,
+	0xcba466bd, 0x97dd53fe, 0xdfec10b2, 0xe1390189, 0xd439da79, 0xe38e2d73,
+	0xc17b432d, 0x1d58a372, 0xf501778c, 0xd8af9e1e, 0xe519ba90, 0xd4679cff,
+	0x6fa3b424, 0x49ddfee5, 0x45af68e7, 0x638a4499, 0x7f0069e0, 0x11e1f607,
+	0x1e282d99, 0x80b6628a, 0x74ad2e7e, 0xa7bfc52b, 0x74c7ba44, 0xc67ae78d,
+	0x2b3d728e, 0x9b4c74df, 0xa35e3018, 0x7894f76c, 0x7f6bde70, 0x345d7d27,
+	0xf023b991, 0x14f597bd, 0x2031b0e7, 0x7a2f80ff, 0xf283c139, 0xdca8f7e0,
+	0x178bc81a, 0x87fee64d, 0x7ef1d21d, 0xa454d289, 0x6af31f87, 0x4c794fa0,
+	0xc00c6647, 0x2b89df23, 0x4e4f98ed, 0x2be01c02, 0xf2cf9702, 0x23991d45,
+	0xd0495cf1, 0xa4bcf0ab, 0x77b786bc, 0x54bc78aa, 0xf7dfc69e, 0x7b57dc0f,
+	0xde821653, 0x9cbdb6f5, 0x5be02772, 0x9c35be0d, 0x7c4cbe0f, 0xb99eda0e,
+	0x46efe608, 0x5cf74d9f, 0x5ed08be5, 0xdc151b75, 0xf78c71c9, 0xb5cd9ee9,
+	0x5baae508, 0xbc15e0af, 0x5c64105d, 0xe5c15f79, 0x8c8547f7, 0xb4859237,
+	0x0a4ff487, 0x3dca35c1, 0x58ff3c9c, 0xb517fefe, 0x7bc22cf7, 0xcf3af9b7,
+	0x57f44ac9, 0xd218692f, 0xf0e07f55, 0x697fa459, 0xb33bf70b, 0x39ee1c0e,
+	0xd872f288, 0xb1e6f748, 0xe3e254e6, 0xdbbd96c6, 0x375ca126, 0xada073f2,
+	0xff3fef0d, 0xc3a7ea3b, 0x57183163, 0xe69eb759, 0xebca2f9d, 0x1e39eb66,
+	0xdfb3b725, 0xb2847c72, 0x3c71dfaf, 0x6b7fb796, 0xa75a17fe, 0xfb81f0ff,
+	0x9fa05e50, 0x17a5e29b, 0xa2605e40, 0x73d94392, 0x1bf59e30, 0xfce0563b,
+	0xab3afdce, 0x09e7c25b, 0x95be30b3, 0xa4dcfccc, 0x14f6fc78, 0x4754a7cc,
+	0x1df9edf7, 0xd7efbb9e, 0x2ba139d3, 0x12a5db86, 0x3dda7ab1, 0xf7bb3f24,
+	0xb5f701fc, 0xf6e74f4f, 0x1edcd1c5, 0xa0c9ef15, 0xfe579ef3, 0x940ad9f1,
+	0xd7717c83, 0xd7fe7c1e, 0xe90abd5a, 0x8db5a9d4, 0x4cfd01b8, 0xa9e286a7,
+	0x3e2f1962, 0x13d7cb1d, 0xf24055d5, 0x653db713, 0x4948c811, 0xe0b7fdec,
+	0xdb8be7ba, 0xce7f479f, 0x0ce8eaf6, 0xa03efceb, 0xbe77bc2b, 0x2da7434e,
+	0x35467dfe, 0xb0b76bca, 0x38b3c57d, 0xd7ef1d7e, 0xf44edfad, 0x3165d776,
+	0x31fa0f9c, 0x16ea9f3c, 0x3f3d0476, 0x1737b75f, 0xfb0bade3, 0xa5dc53e7,
+	0x97a293e8, 0x20bab525, 0x293fc7fd, 0xf963f31e, 0x8666e4cf, 0xc2e9fc80,
+	0xcffc6791, 0x85f5e806, 0x0b4f8d06, 0xb1d62a34, 0xa7af784d, 0xf24963e8,
+	0xbfb8854d, 0xe6755512, 0x278bc03a, 0xbd40ad77, 0x1167af3c, 0x2defd089,
+	0x2e0f3f15, 0x885aaa69, 0xf5b87b76, 0x7c799b14, 0x9f913979, 0xd66e5f97,
+	0xa9cf027b, 0x9547e143, 0x3d5b7a4c, 0x42baff88, 0x19473e47, 0xb7ad2def,
+	0x670ee30c, 0x9fc3f70c, 0x3306ff40, 0xee6661c4, 0x086e56a7, 0x1cdcbfee,
+	0xda9dcf43, 0xcbb44cae, 0xcccbf8ca, 0xd4cf6e26, 0x9fe8995d, 0x7923df43,
+	0x82f57b47, 0xa4aaf640, 0xf7433849, 0xf8d248c7, 0x44967a41, 0xee623db8,
+	0x9c487cd0, 0xc601f326, 0x77ac87fa, 0x9b7a0d25, 0x8d29c61e, 0x7f468aec,
+	0x8aec6655, 0xff6f73c6, 0xc8d59151, 0xc6538bec, 0x4f9c1b4f, 0xbd8b8fc9,
+	0xa87e9b1a, 0x183b60f9, 0x7fc5adef, 0x32622903, 0x3514deb8, 0xcc7cd147,
+	0xe50d35d4, 0xf05768b6, 0x534fb87b, 0x9bfa3e80, 0xc607c777, 0x75c7bfa1,
+	0x8677de53, 0x1ff7a6f4, 0x1ca0a69f, 0x26d8a894, 0x20bee73c, 0xc0617bf0,
+	0x82f85ee9, 0xf25e5e7c, 0xca244337, 0x65cb85cf, 0x01fec7a4, 0xd928fb3b,
+	0x6762bf07, 0x15c70d59, 0x7076cb3b, 0xeecec07c, 0x3762b8e2, 0x42a3fe95,
+	0x1d0a4fde, 0x9077a94f, 0xe6ed93c7, 0x6e7abaa2, 0x7f7e4537, 0x4c6b76c7,
+	0xfce27f3c, 0x19d32b5a, 0x95d3b412, 0x123577e4, 0x19c5b1fa, 0x76a579ca,
+	0xa0e27e90, 0x7499fa3e, 0xbbf509a0, 0x10f940c8, 0x070d15c4, 0x59791cf1,
+	0x07ef15bc, 0x9caee943, 0x7cc5c777, 0x7cf906b3, 0x8af1d6ab, 0x7269ef19,
+	0x82afc8ba, 0x74bf90b6, 0xb8a3aabe, 0xb7d357aa, 0x965fed07, 0xf61af1d6,
+	0x6c76d32b, 0xea4b029e, 0xe3b574d1, 0x943cd091, 0x5c43b257, 0xbb39fd5e,
+	0x39527ce9, 0xe6577f2f, 0x5ea70323, 0x7025f28d, 0x7cde3939, 0x57b46de8,
+	0xf2748efe, 0x03e45703, 0xa3478fcd, 0xe210f9dd, 0x5c407714, 0xbdaae1fc,
+	0x14b50f74, 0xde011fef, 0x7f7829b9, 0xa62edffd, 0x0b6d8838, 0xbcf28e78,
+	0xa50f1833, 0x2fb5ca0b, 0x24dc8f48, 0x9ba5dfc7, 0xeace9608, 0x061d2270,
+	0x8b8045f0, 0x21ebf801, 0x667f4878, 0x1e6266f7, 0x08d61dfa, 0xc6ca3d01,
+	0xbc534efa, 0xd0c3407a, 0xbf046c3f, 0x28e1f849, 0x1d532baa, 0xc718bf00,
+	0x9bfa22fd, 0xca0ee8d2, 0x7587fceb, 0x60f0df74, 0xb82997cb, 0x8ba6bf7f,
+	0x96d295f2, 0x9e31e397, 0x344b358d, 0x78dff83e, 0xdc3d8fba, 0xb6318f12,
+	0xe54cbcf2, 0x94eb94cd, 0x28fed172, 0x5f45cbcf, 0x54bfae26, 0xf6c5c8e8,
+	0xd453b458, 0x7111701f, 0x1328fb46, 0x2d60ddb8, 0x5089f922, 0x706745be,
+	0x25f60bbb, 0x8f11ee97, 0xb15978f2, 0x605f6427, 0x79f1d7bc, 0x261fb70e,
+	0x5e14fce5, 0x31bb462d, 0xa4d99d84, 0x41564dd8, 0x06644d79, 0x3ef2b75f,
+	0x30f3cb8d, 0xd2be776a, 0x83969b9d, 0x7bf249ef, 0x7d2cf601, 0x1da13ed0,
+	0xf23b2449, 0xf61e26a0, 0x60bcf255, 0x14af08dd, 0x802aaf2f, 0xfaad6cee,
+	0x2fca029e, 0x19ee9b99, 0x8575d742, 0x7f39997e, 0xd2f3e44b, 0xbcfc3d92,
+	0x9f8682f4, 0xf2bd832f, 0x3b5afda1, 0xf500aaa7, 0x72b8eeef, 0xdcb9e06d,
+	0xb35fc6d5, 0x5b5f1833, 0x30905551, 0x6c979e84, 0x8a3ed1d8, 0x1d17e10d,
+	0xd2f105d5, 0x7595cf95, 0xeb2bd05f, 0x1519a59c, 0x55a58f48, 0xae00a305,
+	0xf4b9f88d, 0xd0befbe0, 0xdfa1f3a2, 0xf9d2fa06, 0x575f8de9, 0x5c3f9d04,
+	0xe662bc6d, 0xe1c2f3a1, 0xcb0a1fd6, 0xcc69df04, 0x57e818a3, 0xe819e91d,
+	0x2f7cc04d, 0xb4fbfeca, 0x9e78a04a, 0x871aad15, 0xac7301f9, 0x6b7e871a,
+	0x0c0178b8, 0xdd1568e5, 0x8209ba49, 0x0eb0ae1e, 0xffa50f41, 0xbcfc191d,
+	0xaf5945e1, 0x7d2fcf46, 0x9fb420e6, 0x19456c96, 0x5c28a8c0, 0x8945e623,
+	0xda183c23, 0x7203be53, 0x036394ed, 0x5f7cab43, 0xbb522858, 0x586459ab,
+	0x8d12caa7, 0x57d80c9e, 0xf54edb21, 0x7798f37b, 0xa9791506, 0x3d7f7ebb,
+	0x4d7fcfb4, 0xd195bc9c, 0x37e50f7d, 0x330e9105, 0x5fb055c6, 0x4ef43f39,
+	0x7e701859, 0x37f647b7, 0xfc814433, 0x14525f40, 0x5dced39d, 0x503cbe5a,
+	0x10853b4e, 0x72fa79ba, 0xf5f1bf29, 0x6dd206e5, 0x15516bc9, 0xbcc80e74,
+	0xcc049653, 0xaf0672f3, 0x696af89f, 0xb8979d06, 0xd27bf32e, 0x27dbf17c,
+	0xd7588f31, 0x80af7906, 0x407ea7e3, 0x2f906675, 0x0dd09c62, 0xcc1ce9f9,
+	0x66cc1df5, 0x61387b43, 0xae7be514, 0x7ac30203, 0xae8b6733, 0x9d9bef06,
+	0x8c78ae9a, 0xbf34b673, 0xec3f45af, 0x569efc3a, 0x92abbcc2, 0x2637f5c9,
+	0x05d7d215, 0x5bbf40ec, 0x01f59cde, 0x93f2b5da, 0x5cb0d4fc, 0x3fdd1efd,
+	0xce14b9e2, 0x48d4da57, 0xcc658df7, 0xd65f7247, 0xf6ff9c10, 0x075d0e27,
+	0xa76cb2f4, 0xd3ee7c14, 0x225fcf3c, 0xb72f0ab2, 0xce9f148b, 0x73a04c4d,
+	0x38f7c1d8, 0xf7626d7d, 0xdb6e7843, 0x0558269b, 0xd237aa18, 0x26e309bd,
+	0xc73f2677, 0x85f57ded, 0x7ce86b29, 0xeb0533c4, 0x73e57ba4, 0xec8fb9fc,
+	0xeb018b50, 0xebcadb99, 0x59237a17, 0xbbe211d1, 0x23f20c63, 0x92ded52b,
+	0xb6967181, 0xf1eb9def, 0xaf8e59de, 0x57b1f743, 0x253e6fbe, 0xbacae9c7,
+	0xf32727e7, 0x21e618f3, 0xf3976a39, 0xda0a9b62, 0x4cd3ee03, 0x77528299,
+	0x046befc7, 0x9c3e8f7e, 0x17bd617e, 0xbd623bd6, 0x72fdc217, 0x7bd6245d,
+	0x5ca2fe21, 0x5ef58917, 0xbdeb1cf8, 0xeb926f10, 0x0bdeb122, 0x42f7ac71,
+	0x8bae5478, 0xa54b853c, 0xbfd2eef8, 0x3edb9e61, 0xfc721f10, 0x3e084c74,
+	0xe9ffb83a, 0x1f182118, 0x33ff502d, 0xcdfe9775, 0x1675839d, 0xf0dfd926,
+	0x9ce50b3a, 0xb670b3ab, 0xb1f20779, 0x3c24c275, 0x69266747, 0xb74bea04,
+	0x56ffe7cc, 0x1da02fdb, 0xe47d1160, 0x64c4e797, 0x78bb408f, 0xba62e4f2,
+	0xd38feb87, 0x93bc3e91, 0x7ec3e8ee, 0x9e6f98ae, 0xeb06cc3f, 0x265a66e6,
+	0xfc029a6f, 0xe4106998, 0x44fb7238, 0x059f72bb, 0xbadd99fc, 0xdb9a8a6a,
+	0x994e130b, 0xc6ad962f, 0xe925d771, 0xaa1e6327, 0x1dfc734b, 0x5fe855c7,
+	0x19ad7a30, 0x48d76fe7, 0xeabc601f, 0xf3cf13fe, 0xa501fa95, 0x33a927df,
+	0xdef099f5, 0x26fa4b5c, 0x2819ebcc, 0x4dbc8a1f, 0x3e501acb, 0x6128aa6c,
+	0x4933d923, 0x67d5fb8d, 0x92cefdf2, 0x4f80fdf8, 0x6063a92b, 0xcce45f7c,
+	0xdb77cc38, 0x949fbe65, 0xe64a7ef9, 0xcdd1d63b, 0x3a3af351, 0x87475884,
+	0x20ea10f0, 0xdd2fbfcc, 0x7149931e, 0xd20a5f72, 0x984ba95d, 0xedc67a87,
+	0xf5d20a4f, 0x27c72c90, 0x99d3fb64, 0xefe24f66, 0x54acf8f1, 0x96e81fae,
+	0x7d9473cf, 0xbe0def2a, 0xfb05e7cf, 0x6ffee12d, 0x5f645510, 0x5b38e543,
+	0x788efb96, 0xbd4abde3, 0x3739c608, 0x261fdc88, 0x41dffaab, 0x6f1c93bb,
+	0x90c23694, 0x78a3b3f9, 0x09bd36bf, 0xdb6f6c4d, 0xddce7437, 0x296190fb,
+	0x30314fbf, 0x3da11efc, 0xe04d4271, 0xe51fe979, 0x908fc079, 0x9a2cba5e,
+	0x3923f61f, 0x423f01c6, 0x144e66f9, 0x9bf923dd, 0xa4fca2bf, 0x09aa75b7,
+	0xe1dfd4e5, 0x715fa031, 0xc4ffe3fd, 0xb7f0bfa3, 0x6cf5417e, 0xa4bf6ffe,
+	0x722db73a, 0xcdebe1bd, 0x87589d72, 0xbde7c464, 0x60159f85, 0x1c32adbf,
+	0x3cfc23b4, 0x686f814f, 0x681de66c, 0x51509ecf, 0x8dd8a2fe, 0x98597d50,
+	0xf78e5239, 0x676831ec, 0xc4ec5f40, 0x597d01b7, 0xc1798316, 0x12917da0,
+	0x132ea87e, 0xcd598bed, 0xb4420bed, 0xb733662f, 0x7da3882f, 0x05f68841,
+	0x417da39f, 0xe20bed1c, 0x47105f68, 0xed1082fb, 0xebff3e0b, 0xd3a75e52,
+	0x3f29810b, 0x5c5035c7, 0x7f8ebebf, 0x8dbeb27f, 0xafaddbdf, 0xac0ea816,
+	0x94dfe607, 0x509d4439, 0xe4275c93, 0xa2f741dd, 0x15a2c3ae, 0xd6017859,
+	0x6dcf09bd, 0xd0277d35, 0x051ab82f, 0xcf84956b, 0xb63ad297, 0x60fd4eb4,
+	0xd3af3e39, 0x2fe85558, 0xa3c72f5a, 0xad692bdf, 0x2735ff23, 0xbfcb4da1,
+	0x9e181197, 0x71d12f1f, 0xe11728fd, 0x3fba24e9, 0xae5ffb26, 0xad73a0eb,
+	0x0a417ad2, 0x35c08efc, 0x7fc512fd, 0xf2b9fdca, 0x57b94bdd, 0xca0ead2f,
+	0x6ebc6c9f, 0x4aff718b, 0x9e406579, 0xc3277cab, 0x74d56fc4, 0xc08afe3f,
+	0xd7ab8562, 0x36b49573, 0xaffac66e, 0xb4767bd0, 0x16d75424, 0x44febf72,
+	0x95d75ca6, 0x6f30f2c7, 0xf5627c2e, 0x5f30c381, 0xe51d76ff, 0x774f609d,
+	0x409efea1, 0x9cba0439, 0xb9d3d368, 0xb23be7db, 0xde1f1046, 0xf6489914,
+	0xb7d90c72, 0xf2811a75, 0x3597b031, 0xc2ecdef8, 0xceaec8bb, 0xfc8abb06,
+	0x93eee454, 0xca2d7b54, 0x1209bae7, 0x1d7cb9f9, 0x93c697bb, 0x9200c5eb,
+	0x146fe5de, 0x57c02a3c, 0x2f7d2b31, 0x86c812b4, 0xc6af50f1, 0x75d608f0,
+	0xaebc64ad, 0x75a39143, 0x8eef943b, 0x577d10c6, 0xd95cf4c8, 0xb06fc7fa,
+	0x1d2ee36e, 0x56490f3f, 0xe4803af1, 0xe7bebcad, 0xf5e0e66e, 0x8b4d9872,
+	0xdabd2f94, 0x511dcf05, 0x79f85263, 0xe380948f, 0xa1a53aaf, 0x84fce33a,
+	0x8a0e9905, 0xfd50e64f, 0x43bbe086, 0x1f9afefc, 0xeb83878a, 0xec684e37,
+	0x3b573df4, 0x73d925ca, 0x9553c107, 0xbb150445, 0xf63fd4ad, 0x88dcbdb6,
+	0x0cbbe7f3, 0x62b7a456, 0x83a8ae07, 0xa950e48c, 0x100b1c83, 0xc0cc0aeb,
+	0xda0c5363, 0x44ec8967, 0xb273aab2, 0x1bfffb84, 0x3f200eff, 0xe30f2da1,
+	0xfc7974a6, 0x43fd92d3, 0x9a2d9fe4, 0xbc3df1b9, 0xf40eda4f, 0x080dc02c,
+	0x6d7b2f18, 0x6dbfc622, 0x1a46a982, 0x78ee8eca, 0x5c97eb08, 0x7184c166,
+	0xf6e44159, 0xbf1878fc, 0x8ad52d20, 0xccd5dc76, 0x403f2de3, 0x3debf7ce,
+	0x55dfc0a2, 0xce9c63c7, 0xea9596f9, 0x351ccee8, 0xacbe7cf8, 0x5fadbd4f,
+	0xabe3faf1, 0x38b563c7, 0xade99bbe, 0xc8f8f275, 0x8cd7f9f7, 0x914cb8a5,
+	0x8486fe9b, 0xef9b941a, 0x7cbbff65, 0xcc1a7bf9, 0x1cd33b03, 0xaff38dff,
+	0xa1e97d58, 0xd0e7da78, 0xd3a9507e, 0x4a83f50f, 0xabfff37c, 0xcaedff3e,
+	0x54ef820a, 0x51d8206e, 0x51f6a6e9, 0x735cfc59, 0xfc0ab8b8, 0x10d65c43,
+	0xbf4294f1, 0xe4aae221, 0xae3ca9ac, 0x89473cc2, 0xa388aeab, 0x0155df40,
+	0x75bb3efa, 0x608f9de4, 0x6b53b3dc, 0xeb0090c5, 0xc81bd7a8, 0x4d64643e,
+	0x529e2a1d, 0xf8a069e8, 0x27e99fab, 0x2cb3fce1, 0x1fbc6ae9, 0x0425989f,
+	0x3fa80be5, 0x1fd46fb8, 0xea3fa884, 0x39e7b880, 0x14f6a82d, 0x29b82f1e,
+	0xbf13d05e, 0x5d815737, 0x662efc01, 0x3d2bb20a, 0x31857621, 0x1d70affb,
+	0x9d795a6b, 0x3a5f5297, 0x93d7c00b, 0x5e33b086, 0x46c6676e, 0x3ce1f77a,
+	0x54919d63, 0xc3427caf, 0x16c4eee5, 0x9ab82f5e, 0x8ff7f9d9, 0x689bda57,
+	0xb15defa4, 0x01fc9f7d, 0xa8f5dffa, 0xcd9ee281, 0xfda66b49, 0xf8cdec4f,
+	0x7f0f4e2c, 0xe7de6fa5, 0x22731f20, 0x905cf7f9, 0xee2859bb, 0x7e924555,
+	0x8ed97e40, 0x6bac57df, 0x8ed0f211, 0x77d9d1cf, 0x6a9d3ae1, 0x27167ebe,
+	0x3baa27df, 0xbf42f78a, 0x2b64f8ce, 0x1263cfe6, 0xffac308f, 0xe61577ca,
+	0x64ecbda0, 0xbf7be9db, 0x5dc73a8d, 0x39c5e7c8, 0x7b9d0215, 0x5897faca,
+	0x95b35518, 0x153591f8, 0x2708bef9, 0xe6e473a3, 0x2e8f98c5, 0xf1c10a8a,
+	0x8dce8b1e, 0x6c78e55f, 0xd2827b48, 0x1cc9e32e, 0x2f356777, 0xd2e573c6,
+	0xf3e9bd7a, 0x91cffaa0, 0x39abb841, 0x6079f4c9, 0x03fe2a7d, 0x822daecf,
+	0x93dc059a, 0x078e0837, 0x85e53f70, 0x2e39f917, 0x5abf23eb, 0x7d112595,
+	0x7ccebd47, 0x737dff28, 0x902e748d, 0x87915b10, 0x472c09e7, 0x52fd8a9a,
+	0x17147d34, 0x96ab7ef6, 0x8be8b3bf, 0xef202dbe, 0x7f95be7f, 0xcfca117f,
+	0x7b970b3c, 0x0db0d997, 0x8c4ce6f9, 0x7ad82088, 0xa616e289, 0xdef19bb6,
+	0x3a0af214, 0x3f7d08b7, 0xb7efc2dd, 0x656b3753, 0x90ff813a, 0x8e337ae4,
+	0xc674d9bb, 0x948befaa, 0x266ccae9, 0x866d3ff8, 0xfcffc64a, 0x0113e638,
+	0x7fd86dfd, 0x6b5f9db0, 0xf77bef2b, 0x26f8fbbe, 0xca1f3cb3, 0xf1461ad7,
+	0xa0f7e873, 0x06625a9f, 0x2e5033ea, 0x53d38b9e, 0xf7583f9e, 0x6ba0ebcf,
+	0x7f3d72f5, 0xf83fbd68, 0x8ae7f43b, 0x725f7b9f, 0x52bf1d50, 0xf9d4aff7,
+	0xcd2f3127, 0xe027b4a7, 0xda88baed, 0x3847a1db, 0x2193f303, 0x659376e8,
+	0x91647fe6, 0x17d9b8de, 0xfee7c1ea, 0x810de8a8, 0xe486727c, 0x66593737,
+	0xfbca7bd1, 0xb1661be5, 0x26e3262f, 0xaccc38e5, 0x14e7ff22, 0xd9021bd9,
+	0xa28f5e11, 0xec1a77bc, 0x9ff7ce3c, 0x7e11f760, 0x0bfef608, 0xc19fe7a0,
+	0x08fc21de, 0xff3e1dec, 0xc21dec04, 0xf803f02e, 0x03f053fc, 0x61dc9708,
+	0xe57a829c, 0x5f62ae6a, 0x3b3dd704, 0xd3bfe302, 0x97968733, 0x9e2a598b,
+	0xdd0ea5bf, 0xe9e596ae, 0x6f9c8df4, 0x4f3377bd, 0xdfc92a4d, 0x86178c26,
+	0xd7b7eefb, 0x5afbedc8, 0x37bc1cf9, 0xb2e7e389, 0x473cfc34, 0xf7c69ec5,
+	0x3af066d7, 0x2b8ec539, 0x1fc82af9, 0x63acaf8d, 0x29d79c9c, 0x55663cfd,
+	0x0a48f7d0, 0xfde1639c, 0x5f313e48, 0x0d4c7947, 0x44a74f90, 0x172a19f2,
+	0x1d385a9f, 0x772e3acc, 0xa09768c9, 0x9e82727f, 0xe361c6e2, 0x51ef90b0,
+	0x394f90ae, 0x32c64b1e, 0xf3e1988f, 0xf7aca363, 0x7e3f3a3f, 0x943150d8,
+	0x3ff998fd, 0x3e80ffdd, 0x8affef06, 0x8e876b7d, 0xf7db873f, 0xca2bbd40,
+	0xc1f610cf, 0xb81f603a, 0xb164dcfc, 0x1d4cb78d, 0x05483bfe, 0xebe0cdae,
+	0x6a83e456, 0xc5ee3094, 0xee0fa57d, 0x91fd6067, 0xcb5bfb21, 0x94225ee8,
+	0x13df018f, 0x05fafb29, 0x1ba147ae, 0xa38a3e58, 0xa81994c7, 0xc590fbce,
+	0x4769efc4, 0x0762b97d, 0xf645feb4, 0xf1507f13, 0x6ec51a7a, 0xc4173c0f,
+	0x82730b95, 0x513339ec, 0xfd23ad9c, 0x7bbc41f2, 0x4f7830d0, 0xb7f7eca9,
+	0xcbf63eb2, 0x6fffb5f9, 0x8ff65f3c, 0x73dfa3ee, 0xefcd3ff0, 0x9bc460d1,
+	0x6eee0eb1, 0xcc253bf9, 0x9e5ad5af, 0xcf21ab37, 0x7d2f7bf6, 0xae01f782,
+	0xaa3c4467, 0x9733e262, 0xd3fc5097, 0x7e6131a6, 0xc7e9f1be, 0x9dbca24f,
+	0x7424126d, 0xd826fed9, 0x3ba7e636, 0xf43d1e8d, 0xe7e2682f, 0x45eb6b27,
+	0xfcff048f, 0x696efe42, 0xfa1a33f6, 0x234d699e, 0xfe3977af, 0x6bca7af4,
+	0xcf207acf, 0xc40b7186, 0xbcf1da07, 0xfe39e4be, 0xfb2512bb, 0x1efc5adc,
+	0xa05aa4af, 0x97c9537c, 0xaf75e4cb, 0x6c7909d9, 0x30483dd0, 0x14bccc5e,
+	0x06d4955f, 0x086b2f3f, 0xb5ef7fce, 0x94d77c0c, 0xf9c8ebc7, 0x3f62acbd,
+	0xdcab8caf, 0xfac1a7c4, 0xe3c6bfeb, 0x76d8be79, 0x0353e539, 0xf8ca17c7,
+	0xca2fc019, 0xfacaf6e7, 0x62e8fc95, 0x85e29b12, 0x2e313afd, 0x50efe495,
+	0xc8aedf81, 0x1f485bae, 0x8c268a8f, 0x8b34b6b3, 0x7967a46e, 0x7d377eab,
+	0xf4e78537, 0x3df3a446, 0xc26ff7e4, 0x273c267b, 0x83b67c84, 0xce83a6e4,
+	0x6fad99e5, 0xb697dd0d, 0x4fe84de8, 0x683f479d, 0xfd06efc7, 0x57860587,
+	0x7cefcaf8, 0xd78679ac, 0xcddfc199, 0x229afdf8, 0x5f006217, 0x436bef91,
+	0xc33e2af8, 0x8d35f3f3, 0xdedf2823, 0xf568b4f8, 0x39785ca1, 0x17be157f,
+	0x3ce8db88, 0x7c48f805, 0xdd4cfd9e, 0x07289193, 0x05fdf8fb, 0xfdf101c8,
+	0x77ce2eec, 0xc443db6d, 0x2cb57f77, 0xf7fc2d07, 0xf8ea4a49, 0x17e81079,
+	0xf1abc9f9, 0x5f7c6aff, 0x7c83db20, 0x3889c671, 0xe5ef778c, 0xe988adf3,
+	0x9a07bf2e, 0x20bb993e, 0x7975f515, 0x26c6eee1, 0x07891980, 0xce621999,
+	0x51db3a53, 0x5cb9e04b, 0x79d79e9b, 0xca045103, 0x4bfae433, 0x53dd4ce9,
+	0x5e47af68, 0xfe31f143, 0xf79c0445, 0x60cf3f00, 0xb23bd09e, 0xd8cbc0fb,
+	0x7e8e946f, 0x55bca58f, 0xa2e5d3e7, 0x9bf2e45f, 0x715bedaf, 0xafddc60f,
+	0x433ee8ea, 0x45dff1b0, 0xe3fd6d28, 0xc84f7887, 0x416df29a, 0xff209bbf,
+	0xfe2941ae, 0x37b602ae, 0xe8067a68, 0x3fa6ed80, 0x165d7bd1, 0x9e92875e,
+	0x71848370, 0xcc65c6ec, 0x943e9911, 0xe764679d, 0x8729ef95, 0x3986c38d,
+	0x2fe2506f, 0x12331ee6, 0x7df94cf5, 0xad0ec505, 0x3c5bbf95, 0x7529df71,
+	0x96afd22c, 0x714c8eff, 0x389fd82b, 0x7922df3a, 0x38aee73b, 0xbf9782a2,
+	0x468ab944, 0x0e68fab9, 0xc7db2ff6, 0x3c0683fb, 0xdf871919, 0x4f286b29,
+	0x7937d01b, 0xa3df867c, 0x05f3bb40, 0x0ea6c581, 0xab6a2f61, 0x421e8f37,
+	0x2e214a6e, 0xca8745c3, 0xb829b38f, 0x768377df, 0xf8f7c264, 0x9726567d,
+	0x662cf72f, 0x0d5ffdc1, 0x40d8f92a, 0x947e067e, 0x19e660ea, 0xc972df29,
+	0xd5ced2e7, 0x51273a26, 0xed538dfc, 0xf299b33d, 0x43972332, 0x63dfa335,
+	0xb68d54e9, 0xef380d6e, 0x4e979ce8, 0x6fc59fdf, 0xdc70faf4, 0xb58205be,
+	0x44e69a06, 0x5f2efcf1, 0x0bdb2f65, 0xb8a86fed, 0xf30e7ddf, 0x17fd1137,
+	0xff419397, 0x93cfcfc6, 0x7f3c8d0b, 0x9adca8f3, 0xa61df489, 0xdd94eb1b,
+	0x2bd52d76, 0x1d291ced, 0x677c0268, 0xefd90e71, 0x73f1df23, 0x5a65bef4,
+	0xf33bf3f2, 0xae51cbec, 0x4f1b2e77, 0xd208afed, 0xe33f7863, 0x7da48e2e,
+	0xcfc85cec, 0x4c2e771b, 0x5967f6a4, 0xdf1a955f, 0xd9fbe6ab, 0x3a04d8f9,
+	0x39d38dff, 0xbef1b372, 0xd8c7be58, 0xc24b6a99, 0x0527d37a, 0x71bbb2fb,
+	0x1a0609bc, 0xe24590ef, 0xc6cb12f7, 0xe907b63f, 0x8a9a4634, 0x7e0fdb76,
+	0x7ff00def, 0x4dd86c7f, 0xf71732f5, 0xc705b99f, 0xe4057d2f, 0x37f7c60f,
+	0xebbe8318, 0x66efbe57, 0xc5b4df6a, 0xb0bf40c6, 0xbcb5d791, 0xeaf6e464,
+	0x3373cea0, 0xe4725fbc, 0xebb45cb3, 0xdafb07fe, 0xdaee3193, 0x243af02f,
+	0xde2e5777, 0x87a89647, 0xce6faf8e, 0x4f4bf1e6, 0x8c52d44b, 0x63fa84e7,
+	0xe252df54, 0xe7435dbd, 0xd9bf7254, 0x866e3cd9, 0xed1f747e, 0xdfc827de,
+	0x05a6f8bb, 0x752b5bde, 0xb8fb3dcd, 0x6b34951c, 0x92e47be8, 0x51ff46fa,
+	0x59d43fc4, 0xf55d7c51, 0x783ee897, 0xe8074bf6, 0x3fef02de, 0x473a08de,
+	0x3b39dfe6, 0xaae63b65, 0x395ec917, 0x77f9ca9b, 0x19e2f55f, 0xd28fbdc2,
+	0xf15d34ef, 0x27731d5d, 0x5f4912ab, 0x29e6b193, 0xa5f4bdb4, 0x206e23b6,
+	0xbda1e961, 0x2ee7e8d1, 0x2345d474, 0x55dc61dd, 0x5e7c11da, 0x2b883dfc,
+	0x7d05b5c7, 0x6ef2e69f, 0x02ebc4b9, 0x845fc8bb, 0xff80bff6, 0x6f7f3f00,
+	0xd91dfcb6, 0xf25aecb5, 0x14b1f5ff, 0xa6fac157, 0x13b77e05, 0x0f4bffea,
+	0x0dde7e5c, 0xbb073ded, 0x96f5c79f, 0xd515f77d, 0xf557b123, 0xdae6b754,
+	0x73f93eff, 0xcd7fbde5, 0x7fa871e6, 0x583ddedf, 0x2fffea97, 0xf347159d,
+	0x22997db7, 0xe36839e1, 0xf10f7437, 0xfa7cb69b, 0x8737e6de, 0xd0fc2767,
+	0xb7281177, 0x75c0cc9e, 0x92bf8879, 0xac503bfc, 0xfc218655, 0x3c74de3a,
+	0x1179d705, 0xba754df8, 0x72f73f12, 0xbee9cb7a, 0x8007f101, 0x8786cebe,
+	0xb8ffa12f, 0x4d9cff1a, 0x61bd6f8b, 0x2b43d90a, 0xf58b95aa, 0xe87ffdd1,
+	0xfb7c037b, 0xc4e3e04f, 0x86bfc11f, 0x70ff342d, 0xff88bbfc, 0x081d3e00,
+	0xa6e5dfe1, 0xeb1dffbb, 0x6c535968, 0x8128f7d0, 0x08fdf374, 0x7c0915ba,
+	0xdb66dffc, 0xf4bed19a, 0x0f617c1c, 0xdf2309d6, 0x2eb0966e, 0x330a72ed,
+	0x7d30f7e2, 0x697f282b, 0xaed099d3, 0x407db495, 0xeb97e3fa, 0x80cfe029,
+	0x06cfce7e, 0x2fc83afe, 0x55d9b6c9, 0xa2e9f46b, 0xf4efe907, 0xa2942c2c,
+	0x7a19f9e9, 0x8c72e1ee, 0x2ddfc3f4, 0xdd8e7a73, 0x97c10c26, 0x9e34ecde,
+	0xd1467927, 0xff6bcbbe, 0x00c0e3c2, 0x91d3097e, 0x6e28674f, 0x0a4f8e1c,
+	0xeff24c1d, 0xadf00d88, 0x685feb96, 0x87f0177f, 0x7e653fee, 0xf7f0ff21,
+	0xceb85cd4, 0x20cf8e68, 0x0d80f85c, 0xd5fc0f61, 0xfce3ca3a, 0x83c9f721,
+	0xd79079fc, 0xa9ea855d, 0xf4e1cfbc, 0xabd3d143, 0xd2a7ffad, 0x52d92fe7,
+	0x7428bc90, 0x6876f9ea, 0xcf1c6e3b, 0x9f67fef5, 0x3504da3f, 0x7f3a0f8b,
+	0xf3c78c34, 0x4133a6c7, 0x7eca8fe7, 0xda73e47b, 0xf922fd9e, 0xeff2cdc7,
+	0x0bda84ac, 0xd0983be5, 0xd7938ef5, 0x7f7f94eb, 0xd1a0e7a1, 0x7a718063,
+	0x79216f5e, 0xd19c3676, 0x7b6a79e2, 0x9efa21fd, 0xf41fd14e, 0xf5809e13,
+	0x2c78bcf7, 0xce36ec97, 0x275f0433, 0x33cf978c, 0xc79e875b, 0x682970d5,
+	0x57b7529e, 0x57ab754b, 0xda82ef99, 0x778e3b76, 0x7eff83a1, 0xd0ef05e1,
+	0xf1a6a9e7, 0x615cf91a, 0x2fe0873b, 0xbcfe01ed, 0x1b4db053, 0xc30c2a3f,
+	0x30c30c30, 0x0c30c30c, 0xc30c30c3, 0x30c30c30, 0x0c30c30c, 0xc30c30c3,
+	0x30c30c30, 0x0c30c30c, 0xc30c30c3, 0x30c30c30, 0x0c30c30c, 0xc30c30c3,
+	0x30c30c30, 0x0c30c30c, 0xc30c30c3, 0x30c30c30, 0xc1b7ff0c, 0x8dca0bff,
+	0x8000e737, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131,
+	0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7,
+	0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131,
+	0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7,
+	0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131,
+	0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7,
+	0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131,
+	0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7,
+	0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131,
+	0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d,
+	0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7,
+	0x8000dcb1, 0x00008000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0x00100000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x00100000, 0x00000000, 0xfffffff3, 0x314fffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd,
+	0xfffffff1, 0x30efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3,
+	0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff,
+	0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd,
+	0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3,
+	0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xfffffff7, 0x31efffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd,
+	0xfffffff5, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3,
+	0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x310fffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x310fffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd,
+	0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3,
+	0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3,
+	0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd,
+	0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3,
+	0x0010cf3c, 0xcdcdcdcd, 0xfffffff7, 0x30efffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf300, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x304fffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd,
+	0xfffffff3, 0x31efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3,
+	0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x310fffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd,
+	0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3,
+	0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd,
+	0xffffff97, 0x056fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3,
+	0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x310fffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x320fffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd,
+	0xfffffff1, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3,
+	0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff,
+	0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd,
+	0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3,
+	0x0008cf3c, 0xcdcdcdcd, 0xffffff8a, 0x042fffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cc000, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffff97, 0x05cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd,
+	0xfffffff5, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3,
+	0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd,
+	0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3,
+	0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd,
+	0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3,
+	0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd,
+	0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3,
+	0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd,
+	0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3,
+	0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd,
+	0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3,
+	0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd,
+	0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3,
+	0x0001cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd,
+	0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3,
+	0x0008cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd,
+	0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3,
+	0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd,
+	0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3,
+	0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd,
+	0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3,
+	0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3,
+	0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff,
+	0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd,
+	0x000a0000, 0x000700a0, 0x00028110, 0x000b8138, 0x000201f0, 0x00010210,
+	0x000f0220, 0x00010310, 0x00080000, 0x00080080, 0x00028100, 0x000b8128,
+	0x000201e0, 0x00010200, 0x00070210, 0x00020280, 0x000f0000, 0x000800f0,
+	0x00028170, 0x000b8198, 0x00020250, 0x00010270, 0x000b8280, 0x00080338,
+	0x00100000, 0x00080100, 0x00028180, 0x000b81a8, 0x00020260, 0x00018280,
+	0x000e8298, 0x00080380, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc,
+	0x00002000, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x00002000,
+	0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x00002000
+};
+
+#endif /*__BNX2X_INIT_VALUES_H__*/
diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h
new file mode 100644
index 000000000000..86055297ab02
--- /dev/null
+++ b/drivers/net/bnx2x_reg.h
@@ -0,0 +1,4394 @@
+/* bnx2x_reg.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2007 Broadcom Corporation
+ *
+ * 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.
+ *
+ * The registers description starts with the regsister Access type followed
+ * by size in bits. For example [RW 32]. The access types are:
+ * R  - Read only
+ * RC - Clear on read
+ * RW - Read/Write
+ * ST - Statistics register (clear on read)
+ * W  - Write only
+ * WB - Wide bus register - the size is over 32 bits and it should be
+ *      read/write in consecutive 32 bits accesses
+ * WR - Write Clear (write 1 to clear the bit)
+ *
+ */
+
+
+/* [R 19] Interrupt register #0 read */
+#define BRB1_REG_BRB1_INT_STS					 0x6011c
+/* [RW 4] Parity mask register #0 read/write */
+#define BRB1_REG_BRB1_PRTY_MASK 				 0x60138
+/* [RW 10] At address BRB1_IND_FREE_LIST_PRS_CRDT initialize free head. At
+   address BRB1_IND_FREE_LIST_PRS_CRDT+1 initialize free tail. At address
+   BRB1_IND_FREE_LIST_PRS_CRDT+2 initialize parser initial credit. */
+#define BRB1_REG_FREE_LIST_PRS_CRDT				 0x60200
+/* [RW 23] LL RAM data. */
+#define BRB1_REG_LL_RAM 					 0x61000
+/* [R 24] The number of full blocks. */
+#define BRB1_REG_NUM_OF_FULL_BLOCKS				 0x60090
+/* [ST 32] The number of cycles that the write_full signal towards MAC #0
+   was asserted. */
+#define BRB1_REG_NUM_OF_FULL_CYCLES_0				 0x600c8
+#define BRB1_REG_NUM_OF_FULL_CYCLES_1				 0x600cc
+#define BRB1_REG_NUM_OF_FULL_CYCLES_2				 0x600d0
+#define BRB1_REG_NUM_OF_FULL_CYCLES_3				 0x600d4
+#define BRB1_REG_NUM_OF_FULL_CYCLES_4				 0x600d8
+/* [ST 32] The number of cycles that the pause signal towards MAC #0 was
+   asserted. */
+#define BRB1_REG_NUM_OF_PAUSE_CYCLES_0				 0x600b8
+#define BRB1_REG_NUM_OF_PAUSE_CYCLES_1				 0x600bc
+#define BRB1_REG_NUM_OF_PAUSE_CYCLES_2				 0x600c0
+#define BRB1_REG_NUM_OF_PAUSE_CYCLES_3				 0x600c4
+/* [RW 10] Write client 0: De-assert pause threshold. */
+#define BRB1_REG_PAUSE_HIGH_THRESHOLD_0 			 0x60078
+#define BRB1_REG_PAUSE_HIGH_THRESHOLD_1 			 0x6007c
+/* [RW 10] Write client 0: Assert pause threshold. */
+#define BRB1_REG_PAUSE_LOW_THRESHOLD_0				 0x60068
+#define BRB1_REG_PAUSE_LOW_THRESHOLD_1				 0x6006c
+/* [RW 1] Reset the design by software. */
+#define BRB1_REG_SOFT_RESET					 0x600dc
+/* [R 5] Used to read the value of the XX protection CAM occupancy counter. */
+#define CCM_REG_CAM_OCCUP					 0xd0188
+/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define CCM_REG_CCM_CFC_IFEN					 0xd003c
+/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define CCM_REG_CCM_CQM_IFEN					 0xd000c
+/* [RW 1] If set the Q index; received from the QM is inserted to event ID.
+   Otherwise 0 is inserted. */
+#define CCM_REG_CCM_CQM_USE_Q					 0xd00c0
+/* [RW 11] Interrupt mask register #0 read/write */
+#define CCM_REG_CCM_INT_MASK					 0xd01e4
+/* [R 11] Interrupt register #0 read */
+#define CCM_REG_CCM_INT_STS					 0xd01d8
+/* [RW 3] The size of AG context region 0 in REG-pairs. Designates the MS
+   REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5).
+   Is used to determine the number of the AG context REG-pairs written back;
+   when the input message Reg1WbFlg isn't set. */
+#define CCM_REG_CCM_REG0_SZ					 0xd00c4
+/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define CCM_REG_CCM_STORM0_IFEN 				 0xd0004
+/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define CCM_REG_CCM_STORM1_IFEN 				 0xd0008
+/* [RW 1] CDU AG read Interface enable. If 0 - the request input is
+   disregarded; valid output is deasserted; all other signals are treated as
+   usual; if 1 - normal activity. */
+#define CCM_REG_CDU_AG_RD_IFEN					 0xd0030
+/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input
+   are disregarded; all other signals are treated as usual; if 1 - normal
+   activity. */
+#define CCM_REG_CDU_AG_WR_IFEN					 0xd002c
+/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is
+   disregarded; valid output is deasserted; all other signals are treated as
+   usual; if 1 - normal activity. */
+#define CCM_REG_CDU_SM_RD_IFEN					 0xd0038
+/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid
+   input is disregarded; all other signals are treated as usual; if 1 -
+   normal activity. */
+#define CCM_REG_CDU_SM_WR_IFEN					 0xd0034
+/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes
+   the initial credit value; read returns the current value of the credit
+   counter. Must be initialized to 1 at start-up. */
+#define CCM_REG_CFC_INIT_CRD					 0xd0204
+/* [RW 2] Auxillary counter flag Q number 1. */
+#define CCM_REG_CNT_AUX1_Q					 0xd00c8
+/* [RW 2] Auxillary counter flag Q number 2. */
+#define CCM_REG_CNT_AUX2_Q					 0xd00cc
+/* [RW 28] The CM header value for QM request (primary). */
+#define CCM_REG_CQM_CCM_HDR_P					 0xd008c
+/* [RW 28] The CM header value for QM request (secondary). */
+#define CCM_REG_CQM_CCM_HDR_S					 0xd0090
+/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define CCM_REG_CQM_CCM_IFEN					 0xd0014
+/* [RW 6] QM output initial credit. Max credit available - 32. Write writes
+   the initial credit value; read returns the current value of the credit
+   counter. Must be initialized to 32 at start-up. */
+#define CCM_REG_CQM_INIT_CRD					 0xd020c
+/* [RW 3] The weight of the QM (primary) input in the WRR mechanism. 0
+   stands for weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define CCM_REG_CQM_P_WEIGHT					 0xd00b8
+/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define CCM_REG_CSDM_IFEN					 0xd0018
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the SDM interface is detected. */
+#define CCM_REG_CSDM_LENGTH_MIS 				 0xd0170
+/* [RW 28] The CM header for QM formatting in case of an error in the QM
+   inputs. */
+#define CCM_REG_ERR_CCM_HDR					 0xd0094
+/* [RW 8] The Event ID in case the input message ErrorFlg is set. */
+#define CCM_REG_ERR_EVNT_ID					 0xd0098
+/* [RW 8] FIC0 output initial credit. Max credit available - 255. Write
+   writes the initial credit value; read returns the current value of the
+   credit counter. Must be initialized to 64 at start-up. */
+#define CCM_REG_FIC0_INIT_CRD					 0xd0210
+/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write
+   writes the initial credit value; read returns the current value of the
+   credit counter. Must be initialized to 64 at start-up. */
+#define CCM_REG_FIC1_INIT_CRD					 0xd0214
+/* [RW 1] Arbitration between Input Arbiter groups: 0 - fair Round-Robin; 1
+   - strict priority defined by ~ccm_registers_gr_ag_pr.gr_ag_pr;
+   ~ccm_registers_gr_ld0_pr.gr_ld0_pr and
+   ~ccm_registers_gr_ld1_pr.gr_ld1_pr. Groups are according to channels and
+   outputs to STORM: aggregation; load FIC0; load FIC1 and store. */
+#define CCM_REG_GR_ARB_TYPE					 0xd015c
+/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the
+   highest priority is 3. It is supposed; that the Store channel priority is
+   the compliment to 4 of the rest priorities - Aggregation channel; Load
+   (FIC0) channel and Load (FIC1). */
+#define CCM_REG_GR_LD0_PR					 0xd0164
+/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the
+   highest priority is 3. It is supposed; that the Store channel priority is
+   the compliment to 4 of the rest priorities - Aggregation channel; Load
+   (FIC0) channel and Load (FIC1). */
+#define CCM_REG_GR_LD1_PR					 0xd0168
+/* [RW 2] General flags index. */
+#define CCM_REG_INV_DONE_Q					 0xd0108
+/* [RW 4] The number of double REG-pairs(128 bits); loaded from the STORM
+   context and sent to STORM; for a specific connection type. The double
+   REG-pairs are used in order to align to STORM context row size of 128
+   bits. The offset of these data in the STORM context is always 0. Index
+   _(0..15) stands for the connection type (one of 16). */
+#define CCM_REG_N_SM_CTX_LD_0					 0xd004c
+#define CCM_REG_N_SM_CTX_LD_1					 0xd0050
+#define CCM_REG_N_SM_CTX_LD_10					 0xd0074
+#define CCM_REG_N_SM_CTX_LD_11					 0xd0078
+#define CCM_REG_N_SM_CTX_LD_12					 0xd007c
+#define CCM_REG_N_SM_CTX_LD_13					 0xd0080
+#define CCM_REG_N_SM_CTX_LD_14					 0xd0084
+#define CCM_REG_N_SM_CTX_LD_15					 0xd0088
+#define CCM_REG_N_SM_CTX_LD_2					 0xd0054
+#define CCM_REG_N_SM_CTX_LD_3					 0xd0058
+#define CCM_REG_N_SM_CTX_LD_4					 0xd005c
+/* [RW 1] Input pbf Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define CCM_REG_PBF_IFEN					 0xd0028
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the pbf interface is detected. */
+#define CCM_REG_PBF_LENGTH_MIS					 0xd0180
+/* [RW 3] The weight of the input pbf in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define CCM_REG_PBF_WEIGHT					 0xd00ac
+/* [RW 6] The physical queue number of queue number 1 per port index. */
+#define CCM_REG_PHYS_QNUM1_0					 0xd0134
+#define CCM_REG_PHYS_QNUM1_1					 0xd0138
+/* [RW 6] The physical queue number of queue number 2 per port index. */
+#define CCM_REG_PHYS_QNUM2_0					 0xd013c
+#define CCM_REG_PHYS_QNUM2_1					 0xd0140
+/* [RW 6] The physical queue number of queue number 3 per port index. */
+#define CCM_REG_PHYS_QNUM3_0					 0xd0144
+/* [RW 6] The physical queue number of queue number 0 with QOS equal 0 port
+   index 0. */
+#define CCM_REG_QOS_PHYS_QNUM0_0				 0xd0114
+#define CCM_REG_QOS_PHYS_QNUM0_1				 0xd0118
+/* [RW 6] The physical queue number of queue number 0 with QOS equal 1 port
+   index 0. */
+#define CCM_REG_QOS_PHYS_QNUM1_0				 0xd011c
+#define CCM_REG_QOS_PHYS_QNUM1_1				 0xd0120
+/* [RW 6] The physical queue number of queue number 0 with QOS equal 2 port
+   index 0. */
+#define CCM_REG_QOS_PHYS_QNUM2_0				 0xd0124
+/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define CCM_REG_STORM_CCM_IFEN					 0xd0010
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the STORM interface is detected. */
+#define CCM_REG_STORM_LENGTH_MIS				 0xd016c
+/* [RW 1] Input tsem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define CCM_REG_TSEM_IFEN					 0xd001c
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the tsem interface is detected. */
+#define CCM_REG_TSEM_LENGTH_MIS 				 0xd0174
+/* [RW 3] The weight of the input tsem in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define CCM_REG_TSEM_WEIGHT					 0xd00a0
+/* [RW 1] Input usem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define CCM_REG_USEM_IFEN					 0xd0024
+/* [RC 1] Set when message length mismatch (relative to last indication) at
+   the usem interface is detected. */
+#define CCM_REG_USEM_LENGTH_MIS 				 0xd017c
+/* [RW 3] The weight of the input usem in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define CCM_REG_USEM_WEIGHT					 0xd00a8
+/* [RW 1] Input xsem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define CCM_REG_XSEM_IFEN					 0xd0020
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the xsem interface is detected. */
+#define CCM_REG_XSEM_LENGTH_MIS 				 0xd0178
+/* [RW 3] The weight of the input xsem in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define CCM_REG_XSEM_WEIGHT					 0xd00a4
+/* [RW 19] Indirect access to the descriptor table of the XX protection
+   mechanism. The fields are: [5:0] - message length; [12:6] - message
+   pointer; 18:13] - next pointer. */
+#define CCM_REG_XX_DESCR_TABLE					 0xd0300
+/* [R 7] Used to read the value of XX protection Free counter. */
+#define CCM_REG_XX_FREE 					 0xd0184
+/* [RW 6] Initial value for the credit counter; responsible for fulfilling
+   of the Input Stage XX protection buffer by the XX protection pending
+   messages. Max credit available - 127. Write writes the initial credit
+   value; read returns the current value of the credit counter. Must be
+   initialized to maximum XX protected message size - 2 at start-up. */
+#define CCM_REG_XX_INIT_CRD					 0xd0220
+/* [RW 7] The maximum number of pending messages; which may be stored in XX
+   protection. At read the ~ccm_registers_xx_free.xx_free counter is read.
+   At write comprises the start value of the ~ccm_registers_xx_free.xx_free
+   counter. */
+#define CCM_REG_XX_MSG_NUM					 0xd0224
+/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */
+#define CCM_REG_XX_OVFL_EVNT_ID 				 0xd0044
+/* [RW 18] Indirect access to the XX table of the XX protection mechanism.
+   The fields are: [5:0] - tail pointer; 11:6] - Link List size; 17:12] -
+   header pointer. */
+#define CCM_REG_XX_TABLE					 0xd0280
+#define CDU_REG_CDU_CHK_MASK0					 0x101000
+#define CDU_REG_CDU_CHK_MASK1					 0x101004
+#define CDU_REG_CDU_CONTROL0					 0x101008
+#define CDU_REG_CDU_DEBUG					 0x101010
+#define CDU_REG_CDU_GLOBAL_PARAMS				 0x101020
+/* [RW 7] Interrupt mask register #0 read/write */
+#define CDU_REG_CDU_INT_MASK					 0x10103c
+/* [R 7] Interrupt register #0 read */
+#define CDU_REG_CDU_INT_STS					 0x101030
+/* [RW 5] Parity mask register #0 read/write */
+#define CDU_REG_CDU_PRTY_MASK					 0x10104c
+/* [RC 32] logging of error data in case of a CDU load error:
+   {expected_cid[15:0]; xpected_type[2:0]; xpected_region[2:0]; ctive_error;
+   ype_error; ctual_active; ctual_compressed_context}; */
+#define CDU_REG_ERROR_DATA					 0x101014
+/* [WB 216] L1TT ram access. each entry has the following format :
+   {mrege_regions[7:0]; ffset12[5:0]...offset0[5:0];
+   ength12[5:0]...length0[5:0]; d12[3:0]...id0[3:0]} */
+#define CDU_REG_L1TT						 0x101800
+/* [WB 24] MATT ram access. each entry has the following
+   format:{RegionLength[11:0]; egionOffset[11:0]} */
+#define CDU_REG_MATT						 0x101100
+/* [R 1] indication the initializing the activity counter by the hardware
+   was done. */
+#define CFC_REG_AC_INIT_DONE					 0x104078
+/* [RW 13] activity counter ram access */
+#define CFC_REG_ACTIVITY_COUNTER				 0x104400
+#define CFC_REG_ACTIVITY_COUNTER_SIZE				 256
+/* [R 1] indication the initializing the cams by the hardware was done. */
+#define CFC_REG_CAM_INIT_DONE					 0x10407c
+/* [RW 2] Interrupt mask register #0 read/write */
+#define CFC_REG_CFC_INT_MASK					 0x104108
+/* [R 2] Interrupt register #0 read */
+#define CFC_REG_CFC_INT_STS					 0x1040fc
+/* [RC 2] Interrupt register #0 read clear */
+#define CFC_REG_CFC_INT_STS_CLR 				 0x104100
+/* [RW 4] Parity mask register #0 read/write */
+#define CFC_REG_CFC_PRTY_MASK					 0x104118
+/* [RW 21] CID cam access (21:1 - Data; alid - 0) */
+#define CFC_REG_CID_CAM 					 0x104800
+#define CFC_REG_CONTROL0					 0x104028
+#define CFC_REG_DEBUG0						 0x104050
+/* [RW 14] indicates per error (in #cfc_registers_cfc_error_vector.cfc_error
+   vector) whether the cfc should be disabled upon it */
+#define CFC_REG_DISABLE_ON_ERROR				 0x104044
+/* [RC 14] CFC error vector. when the CFC detects an internal error it will
+   set one of these bits. the bit description can be found in CFC
+   specifications */
+#define CFC_REG_ERROR_VECTOR					 0x10403c
+#define CFC_REG_INIT_REG					 0x10404c
+/* [RW 24] {weight_load_client7[2:0] to weight_load_client0[2:0]}. this
+   field allows changing the priorities of the weighted-round-robin arbiter
+   which selects which CFC load client should be served next */
+#define CFC_REG_LCREQ_WEIGHTS					 0x104084
+/* [R 1] indication the initializing the link list by the hardware was done. */
+#define CFC_REG_LL_INIT_DONE					 0x104074
+/* [R 9] Number of allocated LCIDs which are at empty state */
+#define CFC_REG_NUM_LCIDS_ALLOC 				 0x104020
+/* [R 9] Number of Arriving LCIDs in Link List Block */
+#define CFC_REG_NUM_LCIDS_ARRIVING				 0x104004
+/* [R 9] Number of Inside LCIDs in Link List Block */
+#define CFC_REG_NUM_LCIDS_INSIDE				 0x104008
+/* [R 9] Number of Leaving LCIDs in Link List Block */
+#define CFC_REG_NUM_LCIDS_LEAVING				 0x104018
+/* [RW 8] The event id for aggregated interrupt 0 */
+#define CSDM_REG_AGG_INT_EVENT_0				 0xc2038
+/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */
+#define CSDM_REG_CFC_RSP_START_ADDR				 0xc2008
+/* [RW 16] The maximum value of the competion counter #0 */
+#define CSDM_REG_CMP_COUNTER_MAX0				 0xc201c
+/* [RW 16] The maximum value of the competion counter #1 */
+#define CSDM_REG_CMP_COUNTER_MAX1				 0xc2020
+/* [RW 16] The maximum value of the competion counter #2 */
+#define CSDM_REG_CMP_COUNTER_MAX2				 0xc2024
+/* [RW 16] The maximum value of the competion counter #3 */
+#define CSDM_REG_CMP_COUNTER_MAX3				 0xc2028
+/* [RW 13] The start address in the internal RAM for the completion
+   counters. */
+#define CSDM_REG_CMP_COUNTER_START_ADDR 			 0xc200c
+/* [RW 32] Interrupt mask register #0 read/write */
+#define CSDM_REG_CSDM_INT_MASK_0				 0xc229c
+#define CSDM_REG_CSDM_INT_MASK_1				 0xc22ac
+/* [RW 11] Parity mask register #0 read/write */
+#define CSDM_REG_CSDM_PRTY_MASK 				 0xc22bc
+#define CSDM_REG_ENABLE_IN1					 0xc2238
+#define CSDM_REG_ENABLE_IN2					 0xc223c
+#define CSDM_REG_ENABLE_OUT1					 0xc2240
+#define CSDM_REG_ENABLE_OUT2					 0xc2244
+/* [RW 4] The initial number of messages that can be sent to the pxp control
+   interface without receiving any ACK. */
+#define CSDM_REG_INIT_CREDIT_PXP_CTRL				 0xc24bc
+/* [ST 32] The number of ACK after placement messages received */
+#define CSDM_REG_NUM_OF_ACK_AFTER_PLACE 			 0xc227c
+/* [ST 32] The number of packet end messages received from the parser */
+#define CSDM_REG_NUM_OF_PKT_END_MSG				 0xc2274
+/* [ST 32] The number of requests received from the pxp async if */
+#define CSDM_REG_NUM_OF_PXP_ASYNC_REQ				 0xc2278
+/* [ST 32] The number of commands received in queue 0 */
+#define CSDM_REG_NUM_OF_Q0_CMD					 0xc2248
+/* [ST 32] The number of commands received in queue 10 */
+#define CSDM_REG_NUM_OF_Q10_CMD 				 0xc226c
+/* [ST 32] The number of commands received in queue 11 */
+#define CSDM_REG_NUM_OF_Q11_CMD 				 0xc2270
+/* [ST 32] The number of commands received in queue 1 */
+#define CSDM_REG_NUM_OF_Q1_CMD					 0xc224c
+/* [ST 32] The number of commands received in queue 3 */
+#define CSDM_REG_NUM_OF_Q3_CMD					 0xc2250
+/* [ST 32] The number of commands received in queue 4 */
+#define CSDM_REG_NUM_OF_Q4_CMD					 0xc2254
+/* [ST 32] The number of commands received in queue 5 */
+#define CSDM_REG_NUM_OF_Q5_CMD					 0xc2258
+/* [ST 32] The number of commands received in queue 6 */
+#define CSDM_REG_NUM_OF_Q6_CMD					 0xc225c
+/* [ST 32] The number of commands received in queue 7 */
+#define CSDM_REG_NUM_OF_Q7_CMD					 0xc2260
+/* [ST 32] The number of commands received in queue 8 */
+#define CSDM_REG_NUM_OF_Q8_CMD					 0xc2264
+/* [ST 32] The number of commands received in queue 9 */
+#define CSDM_REG_NUM_OF_Q9_CMD					 0xc2268
+/* [RW 13] The start address in the internal RAM for queue counters */
+#define CSDM_REG_Q_COUNTER_START_ADDR				 0xc2010
+/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */
+#define CSDM_REG_RSP_PXP_CTRL_RDATA_EMPTY			 0xc2548
+/* [R 1] parser fifo empty in sdm_sync block */
+#define CSDM_REG_SYNC_PARSER_EMPTY				 0xc2550
+/* [R 1] parser serial fifo empty in sdm_sync block */
+#define CSDM_REG_SYNC_SYNC_EMPTY				 0xc2558
+/* [RW 32] Tick for timer counter. Applicable only when
+   ~csdm_registers_timer_tick_enable.timer_tick_enable =1 */
+#define CSDM_REG_TIMER_TICK					 0xc2000
+/* [RW 5] The number of time_slots in the arbitration cycle */
+#define CSEM_REG_ARB_CYCLE_SIZE 				 0x200034
+/* [RW 3] The source that is associated with arbitration element 0. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2 */
+#define CSEM_REG_ARB_ELEMENT0					 0x200020
+/* [RW 3] The source that is associated with arbitration element 1. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~csem_registers_arb_element0.arb_element0 */
+#define CSEM_REG_ARB_ELEMENT1					 0x200024
+/* [RW 3] The source that is associated with arbitration element 2. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~csem_registers_arb_element0.arb_element0
+   and ~csem_registers_arb_element1.arb_element1 */
+#define CSEM_REG_ARB_ELEMENT2					 0x200028
+/* [RW 3] The source that is associated with arbitration element 3. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.Could
+   not be equal to register ~csem_registers_arb_element0.arb_element0 and
+   ~csem_registers_arb_element1.arb_element1 and
+   ~csem_registers_arb_element2.arb_element2 */
+#define CSEM_REG_ARB_ELEMENT3					 0x20002c
+/* [RW 3] The source that is associated with arbitration element 4. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~csem_registers_arb_element0.arb_element0
+   and ~csem_registers_arb_element1.arb_element1 and
+   ~csem_registers_arb_element2.arb_element2 and
+   ~csem_registers_arb_element3.arb_element3 */
+#define CSEM_REG_ARB_ELEMENT4					 0x200030
+/* [RW 32] Interrupt mask register #0 read/write */
+#define CSEM_REG_CSEM_INT_MASK_0				 0x200110
+#define CSEM_REG_CSEM_INT_MASK_1				 0x200120
+/* [RW 32] Parity mask register #0 read/write */
+#define CSEM_REG_CSEM_PRTY_MASK_0				 0x200130
+#define CSEM_REG_CSEM_PRTY_MASK_1				 0x200140
+#define CSEM_REG_ENABLE_IN					 0x2000a4
+#define CSEM_REG_ENABLE_OUT					 0x2000a8
+/* [RW 32] This address space contains all registers and memories that are
+   placed in SEM_FAST block. The SEM_FAST registers are described in
+   appendix B. In order to access the SEM_FAST registers the base address
+   CSEM_REGISTERS_FAST_MEMORY (Offset: 0x220000) should be added to each
+   SEM_FAST register offset. */
+#define CSEM_REG_FAST_MEMORY					 0x220000
+/* [RW 1] Disables input messages from FIC0 May be updated during run_time
+   by the microcode */
+#define CSEM_REG_FIC0_DISABLE					 0x200224
+/* [RW 1] Disables input messages from FIC1 May be updated during run_time
+   by the microcode */
+#define CSEM_REG_FIC1_DISABLE					 0x200234
+/* [RW 15] Interrupt table Read and write access to it is not possible in
+   the middle of the work */
+#define CSEM_REG_INT_TABLE					 0x200400
+/* [ST 24] Statistics register. The number of messages that entered through
+   FIC0 */
+#define CSEM_REG_MSG_NUM_FIC0					 0x200000
+/* [ST 24] Statistics register. The number of messages that entered through
+   FIC1 */
+#define CSEM_REG_MSG_NUM_FIC1					 0x200004
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC0 */
+#define CSEM_REG_MSG_NUM_FOC0					 0x200008
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC1 */
+#define CSEM_REG_MSG_NUM_FOC1					 0x20000c
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC2 */
+#define CSEM_REG_MSG_NUM_FOC2					 0x200010
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC3 */
+#define CSEM_REG_MSG_NUM_FOC3					 0x200014
+/* [RW 1] Disables input messages from the passive buffer May be updated
+   during run_time by the microcode */
+#define CSEM_REG_PAS_DISABLE					 0x20024c
+/* [WB 128] Debug only. Passive buffer memory */
+#define CSEM_REG_PASSIVE_BUFFER 				 0x202000
+/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */
+#define CSEM_REG_PRAM						 0x240000
+/* [R 16] Valid sleeping threads indication have bit per thread */
+#define CSEM_REG_SLEEP_THREADS_VALID				 0x20026c
+/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */
+#define CSEM_REG_SLOW_EXT_STORE_EMPTY				 0x2002a0
+/* [RW 16] List of free threads . There is a bit per thread. */
+#define CSEM_REG_THREADS_LIST					 0x2002e4
+/* [RW 3] The arbitration scheme of time_slot 0 */
+#define CSEM_REG_TS_0_AS					 0x200038
+/* [RW 3] The arbitration scheme of time_slot 10 */
+#define CSEM_REG_TS_10_AS					 0x200060
+/* [RW 3] The arbitration scheme of time_slot 11 */
+#define CSEM_REG_TS_11_AS					 0x200064
+/* [RW 3] The arbitration scheme of time_slot 12 */
+#define CSEM_REG_TS_12_AS					 0x200068
+/* [RW 3] The arbitration scheme of time_slot 13 */
+#define CSEM_REG_TS_13_AS					 0x20006c
+/* [RW 3] The arbitration scheme of time_slot 14 */
+#define CSEM_REG_TS_14_AS					 0x200070
+/* [RW 3] The arbitration scheme of time_slot 15 */
+#define CSEM_REG_TS_15_AS					 0x200074
+/* [RW 3] The arbitration scheme of time_slot 16 */
+#define CSEM_REG_TS_16_AS					 0x200078
+/* [RW 3] The arbitration scheme of time_slot 17 */
+#define CSEM_REG_TS_17_AS					 0x20007c
+/* [RW 3] The arbitration scheme of time_slot 18 */
+#define CSEM_REG_TS_18_AS					 0x200080
+/* [RW 3] The arbitration scheme of time_slot 1 */
+#define CSEM_REG_TS_1_AS					 0x20003c
+/* [RW 3] The arbitration scheme of time_slot 2 */
+#define CSEM_REG_TS_2_AS					 0x200040
+/* [RW 3] The arbitration scheme of time_slot 3 */
+#define CSEM_REG_TS_3_AS					 0x200044
+/* [RW 3] The arbitration scheme of time_slot 4 */
+#define CSEM_REG_TS_4_AS					 0x200048
+/* [RW 3] The arbitration scheme of time_slot 5 */
+#define CSEM_REG_TS_5_AS					 0x20004c
+/* [RW 3] The arbitration scheme of time_slot 6 */
+#define CSEM_REG_TS_6_AS					 0x200050
+/* [RW 3] The arbitration scheme of time_slot 7 */
+#define CSEM_REG_TS_7_AS					 0x200054
+/* [RW 3] The arbitration scheme of time_slot 8 */
+#define CSEM_REG_TS_8_AS					 0x200058
+/* [RW 3] The arbitration scheme of time_slot 9 */
+#define CSEM_REG_TS_9_AS					 0x20005c
+/* [RW 1] Parity mask register #0 read/write */
+#define DBG_REG_DBG_PRTY_MASK					 0xc0a8
+/* [RW 2] debug only: These bits indicate the credit for PCI request type 4
+   interface; MUST be configured AFTER pci_ext_buffer_strt_addr_lsb/msb are
+   configured */
+#define DBG_REG_PCI_REQ_CREDIT					 0xc120
+/* [RW 32] Commands memory. The address to command X; row Y is to calculated
+   as 14*X+Y. */
+#define DMAE_REG_CMD_MEM					 0x102400
+/* [RW 1] If 0 - the CRC-16c initial value is all zeroes; if 1 - the CRC-16c
+   initial value is all ones. */
+#define DMAE_REG_CRC16C_INIT					 0x10201c
+/* [RW 1] If 0 - the CRC-16 T10 initial value is all zeroes; if 1 - the
+   CRC-16 T10 initial value is all ones. */
+#define DMAE_REG_CRC16T10_INIT					 0x102020
+/* [RW 2] Interrupt mask register #0 read/write */
+#define DMAE_REG_DMAE_INT_MASK					 0x102054
+/* [RW 4] Parity mask register #0 read/write */
+#define DMAE_REG_DMAE_PRTY_MASK 				 0x102064
+/* [RW 1] Command 0 go. */
+#define DMAE_REG_GO_C0						 0x102080
+/* [RW 1] Command 1 go. */
+#define DMAE_REG_GO_C1						 0x102084
+/* [RW 1] Command 10 go. */
+#define DMAE_REG_GO_C10 					 0x102088
+#define DMAE_REG_GO_C10_SIZE					 1
+/* [RW 1] Command 11 go. */
+#define DMAE_REG_GO_C11 					 0x10208c
+#define DMAE_REG_GO_C11_SIZE					 1
+/* [RW 1] Command 12 go. */
+#define DMAE_REG_GO_C12 					 0x102090
+#define DMAE_REG_GO_C12_SIZE					 1
+/* [RW 1] Command 13 go. */
+#define DMAE_REG_GO_C13 					 0x102094
+#define DMAE_REG_GO_C13_SIZE					 1
+/* [RW 1] Command 14 go. */
+#define DMAE_REG_GO_C14 					 0x102098
+#define DMAE_REG_GO_C14_SIZE					 1
+/* [RW 1] Command 15 go. */
+#define DMAE_REG_GO_C15 					 0x10209c
+#define DMAE_REG_GO_C15_SIZE					 1
+/* [RW 1] Command 10 go. */
+#define DMAE_REG_GO_C10 					 0x102088
+/* [RW 1] Command 11 go. */
+#define DMAE_REG_GO_C11 					 0x10208c
+/* [RW 1] Command 12 go. */
+#define DMAE_REG_GO_C12 					 0x102090
+/* [RW 1] Command 13 go. */
+#define DMAE_REG_GO_C13 					 0x102094
+/* [RW 1] Command 14 go. */
+#define DMAE_REG_GO_C14 					 0x102098
+/* [RW 1] Command 15 go. */
+#define DMAE_REG_GO_C15 					 0x10209c
+/* [RW 1] Command 2 go. */
+#define DMAE_REG_GO_C2						 0x1020a0
+/* [RW 1] Command 3 go. */
+#define DMAE_REG_GO_C3						 0x1020a4
+/* [RW 1] Command 4 go. */
+#define DMAE_REG_GO_C4						 0x1020a8
+/* [RW 1] Command 5 go. */
+#define DMAE_REG_GO_C5						 0x1020ac
+/* [RW 1] Command 6 go. */
+#define DMAE_REG_GO_C6						 0x1020b0
+/* [RW 1] Command 7 go. */
+#define DMAE_REG_GO_C7						 0x1020b4
+/* [RW 1] Command 8 go. */
+#define DMAE_REG_GO_C8						 0x1020b8
+/* [RW 1] Command 9 go. */
+#define DMAE_REG_GO_C9						 0x1020bc
+/* [RW 1] DMAE GRC Interface (Target; aster) enable. If 0 - the acknowledge
+   input is disregarded; valid is deasserted; all other signals are treated
+   as usual; if 1 - normal activity. */
+#define DMAE_REG_GRC_IFEN					 0x102008
+/* [RW 1] DMAE PCI Interface (Request; ead; rite) enable. If 0 - the
+   acknowledge input is disregarded; valid is deasserted; full is asserted;
+   all other signals are treated as usual; if 1 - normal activity. */
+#define DMAE_REG_PCI_IFEN					 0x102004
+/* [RW 4] DMAE- PCI Request Interface initial credit. Write writes the
+   initial value to the credit counter; related to the address. Read returns
+   the current value of the counter. */
+#define DMAE_REG_PXP_REQ_INIT_CRD				 0x1020c0
+/* [RW 8] Aggregation command. */
+#define DORQ_REG_AGG_CMD0					 0x170060
+/* [RW 8] Aggregation command. */
+#define DORQ_REG_AGG_CMD1					 0x170064
+/* [RW 8] Aggregation command. */
+#define DORQ_REG_AGG_CMD2					 0x170068
+/* [RW 8] Aggregation command. */
+#define DORQ_REG_AGG_CMD3					 0x17006c
+/* [RW 28] UCM Header. */
+#define DORQ_REG_CMHEAD_RX					 0x170050
+/* [RW 5] Interrupt mask register #0 read/write */
+#define DORQ_REG_DORQ_INT_MASK					 0x170180
+/* [R 5] Interrupt register #0 read */
+#define DORQ_REG_DORQ_INT_STS					 0x170174
+/* [RC 5] Interrupt register #0 read clear */
+#define DORQ_REG_DORQ_INT_STS_CLR				 0x170178
+/* [RW 2] Parity mask register #0 read/write */
+#define DORQ_REG_DORQ_PRTY_MASK 				 0x170190
+/* [RW 8] The address to write the DPM CID to STORM. */
+#define DORQ_REG_DPM_CID_ADDR					 0x170044
+/* [RW 5] The DPM mode CID extraction offset. */
+#define DORQ_REG_DPM_CID_OFST					 0x170030
+/* [RW 12] The threshold of the DQ FIFO to send the almost full interrupt. */
+#define DORQ_REG_DQ_FIFO_AFULL_TH				 0x17007c
+/* [RW 12] The threshold of the DQ FIFO to send the full interrupt. */
+#define DORQ_REG_DQ_FIFO_FULL_TH				 0x170078
+/* [R 13] Current value of the DQ FIFO fill level according to following
+   pointer. The range is 0 - 256 FIFO rows; where each row stands for the
+   doorbell. */
+#define DORQ_REG_DQ_FILL_LVLF					 0x1700a4
+/* [R 1] DQ FIFO full status. Is set; when FIFO filling level is more or
+   equal to full threshold; reset on full clear. */
+#define DORQ_REG_DQ_FULL_ST					 0x1700c0
+/* [RW 28] The value sent to CM header in the case of CFC load error. */
+#define DORQ_REG_ERR_CMHEAD					 0x170058
+#define DORQ_REG_IF_EN						 0x170004
+#define DORQ_REG_MODE_ACT					 0x170008
+/* [RW 5] The normal mode CID extraction offset. */
+#define DORQ_REG_NORM_CID_OFST					 0x17002c
+/* [RW 28] TCM Header when only TCP context is loaded. */
+#define DORQ_REG_NORM_CMHEAD_TX 				 0x17004c
+/* [RW 3] The number of simultaneous outstanding requests to Context Fetch
+   Interface. */
+#define DORQ_REG_OUTST_REQ					 0x17003c
+#define DORQ_REG_REGN						 0x170038
+/* [R 4] Current value of response A counter credit. Initial credit is
+   configured through write to ~dorq_registers_rsp_init_crd.rsp_init_crd
+   register. */
+#define DORQ_REG_RSPA_CRD_CNT					 0x1700ac
+/* [R 4] Current value of response B counter credit. Initial credit is
+   configured through write to ~dorq_registers_rsp_init_crd.rsp_init_crd
+   register. */
+#define DORQ_REG_RSPB_CRD_CNT					 0x1700b0
+/* [RW 4] The initial credit at the Doorbell Response Interface. The write
+   writes the same initial credit to the rspa_crd_cnt and rspb_crd_cnt. The
+   read reads this written value. */
+#define DORQ_REG_RSP_INIT_CRD					 0x170048
+/* [RW 4] Initial activity counter value on the load request; when the
+   shortcut is done. */
+#define DORQ_REG_SHRT_ACT_CNT					 0x170070
+/* [RW 28] TCM Header when both ULP and TCP context is loaded. */
+#define DORQ_REG_SHRT_CMHEAD					 0x170054
+#define HC_CONFIG_0_REG_ATTN_BIT_EN_0				 (0x1<<4)
+#define HC_CONFIG_0_REG_INT_LINE_EN_0				 (0x1<<3)
+#define HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0			 (0x1<<2)
+#define HC_CONFIG_0_REG_SINGLE_ISR_EN_0 			 (0x1<<1)
+#define HC_REG_AGG_INT_0					 0x108050
+#define HC_REG_AGG_INT_1					 0x108054
+/* [RW 16] attention bit and attention acknowledge bits status for port 0
+   and 1 according to the following address map: addr 0 - attn_bit_0; addr 1
+   - attn_ack_bit_0; addr 2 - attn_bit_1; addr 3 - attn_ack_bit_1; */
+#define HC_REG_ATTN_BIT 					 0x108120
+/* [RW 16] attn bits status index for attn bit msg; addr 0 - function 0;
+   addr 1 - functin 1 */
+#define HC_REG_ATTN_IDX 					 0x108100
+/* [RW 32] port 0 lower 32 bits address field for attn messag. */
+#define HC_REG_ATTN_MSG0_ADDR_L 				 0x108018
+/* [RW 32] port 1 lower 32 bits address field for attn messag. */
+#define HC_REG_ATTN_MSG1_ADDR_L 				 0x108020
+/* [RW 8] status block number for attn bit msg - function 0; */
+#define HC_REG_ATTN_NUM_P0					 0x108038
+/* [RW 8] status block number for attn bit msg - function 1 */
+#define HC_REG_ATTN_NUM_P1					 0x10803c
+#define HC_REG_CONFIG_0 					 0x108000
+#define HC_REG_CONFIG_1 					 0x108004
+/* [RW 3] Parity mask register #0 read/write */
+#define HC_REG_HC_PRTY_MASK					 0x1080a0
+/* [RW 17] status block interrupt mask; one in each bit means unmask; zerow
+   in each bit means mask; bit 0 - default SB; bit 1 - SB_0; bit 2 - SB_1...
+   bit 16- SB_15; addr 0 - port 0; addr 1 - port 1 */
+#define HC_REG_INT_MASK 					 0x108108
+/* [RW 16] port 0 attn bit condition monitoring; each bit that is set will
+   lock a change fron 0 to 1 in the corresponding attention signals that
+   comes from the AEU */
+#define HC_REG_LEADING_EDGE_0					 0x108040
+#define HC_REG_LEADING_EDGE_1					 0x108048
+/* [RW 16] all producer and consumer of port 0 according to the following
+   addresses; U_prod: 0-15; C_prod: 16-31; U_cons: 32-47; C_cons:48-63;
+   Defoult_prod: U/C/X/T/Attn-64/65/66/67/68; Defoult_cons:
+   U/C/X/T/Attn-69/70/71/72/73 */
+#define HC_REG_P0_PROD_CONS					 0x108200
+/* [RW 16] all producer and consumer of port 1according to the following
+   addresses; U_prod: 0-15; C_prod: 16-31; U_cons: 32-47; C_cons:48-63;
+   Defoult_prod: U/C/X/T/Attn-64/65/66/67/68; Defoult_cons:
+   U/C/X/T/Attn-69/70/71/72/73 */
+#define HC_REG_P1_PROD_CONS					 0x108400
+/* [W 1] This register is write only and has 4 addresses as follow: 0 =
+   clear all PBA bits port 0; 1 = clear all pending interrupts request
+   port0; 2 = clear all PBA bits port 1; 3 = clear all pending interrupts
+   request port1; here is no meaning for the data in this register */
+#define HC_REG_PBA_COMMAND					 0x108140
+#define HC_REG_PCI_CONFIG_0					 0x108010
+#define HC_REG_PCI_CONFIG_1					 0x108014
+/* [RW 24] all counters acording to the following address: LSB: 0=read; 1=
+   read_clear; 0-71 = HW counters (the inside order is the same as the
+   interrupt table in the spec); 72-219 = SW counters 1 (stops after first
+   consumer upd) the inside order is: 72-103 - U_non_default_p0; 104-135
+   C_non_defaul_p0; 36-145 U/C/X/T/Attn_default_p0; 146-177
+   U_non_default_p1; 178-209 C_non_defaul_p1; 10-219 U/C/X/T/Attn_default_p1
+   ; 220-367 = SW counters 2 (stops when prod=cons) the inside order is:
+   220-251 - U_non_default_p0; 252-283 C_non_defaul_p0; 84-293
+   U/C/X/T/Attn_default_p0; 294-325 U_non_default_p1; 326-357
+   C_non_defaul_p1; 58-367 U/C/X/T/Attn_default_p1 ; 368-515 = mailbox
+   counters; (the inside order of the mailbox counter is 368-431 U and C
+   non_default_p0; 432-441 U/C/X/T/Attn_default_p0; 442-505 U and C
+   non_default_p1; 506-515 U/C/X/T/Attn_default_p1) */
+#define HC_REG_STATISTIC_COUNTERS				 0x109000
+/* [RW 16] port 0 attn bit condition monitoring; each bit that is set will
+   lock a change fron 1 to 0 in the corresponding attention signals that
+   comes from the AEU */
+#define HC_REG_TRAILING_EDGE_0					 0x108044
+#define HC_REG_TRAILING_EDGE_1					 0x10804c
+#define HC_REG_UC_RAM_ADDR_0					 0x108028
+#define HC_REG_UC_RAM_ADDR_1					 0x108030
+/* [RW 16] ustorm address for coalesc now message */
+#define HC_REG_USTORM_ADDR_FOR_COALESCE 			 0x108068
+#define HC_REG_VQID_0						 0x108008
+#define HC_REG_VQID_1						 0x10800c
+#define MCP_REG_MCPR_NVM_ACCESS_ENABLE				 0x86424
+#define MCP_REG_MCPR_NVM_ADDR					 0x8640c
+#define MCP_REG_MCPR_NVM_CFG4					 0x8642c
+#define MCP_REG_MCPR_NVM_COMMAND				 0x86400
+#define MCP_REG_MCPR_NVM_READ					 0x86410
+#define MCP_REG_MCPR_NVM_SW_ARB 				 0x86420
+#define MCP_REG_MCPR_NVM_WRITE					 0x86408
+#define MCP_REG_MCPR_NVM_WRITE1 				 0x86428
+#define MCP_REG_MCPR_SCRATCH					 0xa0000
+/* [R 32] read first 32 bit after inversion of function 0. mapped as
+   follows: [0] NIG attention for function0; [1] NIG attention for
+   function1; [2] GPIO1 mcp; [3] GPIO2 mcp; [4] GPIO3 mcp; [5] GPIO4 mcp;
+   [6] GPIO1 function 1; [7] GPIO2 function 1; [8] GPIO3 function 1; [9]
+   GPIO4 function 1; [10] PCIE glue/PXP VPD event function0; [11] PCIE
+   glue/PXP VPD event function1; [12] PCIE glue/PXP Expansion ROM event0;
+   [13] PCIE glue/PXP Expansion ROM event1; [14] SPIO4; [15] SPIO5; [16]
+   MSI/X indication for mcp; [17] MSI/X indication for function 1; [18] BRB
+   Parity error; [19] BRB Hw interrupt; [20] PRS Parity error; [21] PRS Hw
+   interrupt; [22] SRC Parity error; [23] SRC Hw interrupt; [24] TSDM Parity
+   error; [25] TSDM Hw interrupt; [26] TCM Parity error; [27] TCM Hw
+   interrupt; [28] TSEMI Parity error; [29] TSEMI Hw interrupt; [30] PBF
+   Parity error; [31] PBF Hw interrupt; */
+#define MISC_REG_AEU_AFTER_INVERT_1_FUNC_0			 0xa42c
+#define MISC_REG_AEU_AFTER_INVERT_1_FUNC_1			 0xa430
+/* [R 32] read first 32 bit after inversion of mcp. mapped as follows: [0]
+   NIG attention for function0; [1] NIG attention for function1; [2] GPIO1
+   mcp; [3] GPIO2 mcp; [4] GPIO3 mcp; [5] GPIO4 mcp; [6] GPIO1 function 1;
+   [7] GPIO2 function 1; [8] GPIO3 function 1; [9] GPIO4 function 1; [10]
+   PCIE glue/PXP VPD event function0; [11] PCIE glue/PXP VPD event
+   function1; [12] PCIE glue/PXP Expansion ROM event0; [13] PCIE glue/PXP
+   Expansion ROM event1; [14] SPIO4; [15] SPIO5; [16] MSI/X indication for
+   mcp; [17] MSI/X indication for function 1; [18] BRB Parity error; [19]
+   BRB Hw interrupt; [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC
+   Parity error; [23] SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw
+   interrupt; [26] TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI
+   Parity error; [29] TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw
+   interrupt; */
+#define MISC_REG_AEU_AFTER_INVERT_1_MCP 			 0xa434
+/* [R 32] read second 32 bit after inversion of function 0. mapped as
+   follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM
+   Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw
+   interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity
+   error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw
+   interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14]
+   NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error;
+   [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw
+   interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM
+   Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI
+   Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM
+   Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw
+   interrupt; */
+#define MISC_REG_AEU_AFTER_INVERT_2_FUNC_0			 0xa438
+#define MISC_REG_AEU_AFTER_INVERT_2_FUNC_1			 0xa43c
+/* [R 32] read second 32 bit after inversion of mcp. mapped as follows: [0]
+   PBClient Parity error; [1] PBClient Hw interrupt; [2] QM Parity error;
+   [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw interrupt;
+   [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity error; [9]
+   XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw interrupt; [12]
+   DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] NIG Parity
+   error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; [17] Vaux
+   PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw interrupt;
+   [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM Parity error;
+   [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI Hw interrupt;
+   [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM Parity error;
+   [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw interrupt; */
+#define MISC_REG_AEU_AFTER_INVERT_2_MCP 			 0xa440
+/* [R 32] read third 32 bit after inversion of function 0. mapped as
+   follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP Parity
+   error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; [5]
+   PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw
+   interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity
+   error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC)
+   Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16]
+   pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20]
+   MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23]
+   SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW
+   timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3
+   func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General
+   attn1; */
+#define MISC_REG_AEU_AFTER_INVERT_3_FUNC_0			 0xa444
+#define MISC_REG_AEU_AFTER_INVERT_3_FUNC_1			 0xa448
+/* [R 32] read third 32 bit after inversion of mcp. mapped as follows: [0]
+   CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP Parity error; [3] PXP
+   Hw interrupt; [4] PXPpciClockClient Parity error; [5] PXPpciClockClient
+   Hw interrupt; [6] CFC Parity error; [7] CFC Hw interrupt; [8] CDU Parity
+   error; [9] CDU Hw interrupt; [10] DMAE Parity error; [11] DMAE Hw
+   interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) Hw interrupt; [14]
+   MISC Parity error; [15] MISC Hw interrupt; [16] pxp_misc_mps_attn; [17]
+   Flash event; [18] SMB event; [19] MCP attn0; [20] MCP attn1; [21] SW
+   timers attn_1 func0; [22] SW timers attn_2 func0; [23] SW timers attn_3
+   func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW timers attn_1
+   func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 func1; [29] SW
+   timers attn_4 func1; [30] General attn0; [31] General attn1; */
+#define MISC_REG_AEU_AFTER_INVERT_3_MCP 			 0xa44c
+/* [R 32] read fourth 32 bit after inversion of function 0. mapped as
+   follows: [0] General attn2; [1] General attn3; [2] General attn4; [3]
+   General attn5; [4] General attn6; [5] General attn7; [6] General attn8;
+   [7] General attn9; [8] General attn10; [9] General attn11; [10] General
+   attn12; [11] General attn13; [12] General attn14; [13] General attn15;
+   [14] General attn16; [15] General attn17; [16] General attn18; [17]
+   General attn19; [18] General attn20; [19] General attn21; [20] Main power
+   interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN
+   Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC
+   Latched timeout attention; [27] GRC Latched reserved access attention;
+   [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP
+   Latched ump_tx_parity; [31] MCP Latched scpad_parity; */
+#define MISC_REG_AEU_AFTER_INVERT_4_FUNC_0			 0xa450
+#define MISC_REG_AEU_AFTER_INVERT_4_FUNC_1			 0xa454
+/* [R 32] read fourth 32 bit after inversion of mcp. mapped as follows: [0]
+   General attn2; [1] General attn3; [2] General attn4; [3] General attn5;
+   [4] General attn6; [5] General attn7; [6] General attn8; [7] General
+   attn9; [8] General attn10; [9] General attn11; [10] General attn12; [11]
+   General attn13; [12] General attn14; [13] General attn15; [14] General
+   attn16; [15] General attn17; [16] General attn18; [17] General attn19;
+   [18] General attn20; [19] General attn21; [20] Main power interrupt; [21]
+   RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN Latched attn; [24]
+   RBCU Latched attn; [25] RBCP Latched attn; [26] GRC Latched timeout
+   attention; [27] GRC Latched reserved access attention; [28] MCP Latched
+   rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP Latched
+   ump_tx_parity; [31] MCP Latched scpad_parity; */
+#define MISC_REG_AEU_AFTER_INVERT_4_MCP 			 0xa458
+/* [W 11] write to this register results with the clear of the latched
+   signals; one in d0 clears RBCR latch; one in d1 clears RBCT latch; one in
+   d2 clears RBCN latch; one in d3 clears RBCU latch; one in d4 clears RBCP
+   latch; one in d5 clears GRC Latched timeout attention; one in d6 clears
+   GRC Latched reserved access attention; one in d7 clears Latched
+   rom_parity; one in d8 clears Latched ump_rx_parity; one in d9 clears
+   Latched ump_tx_parity; one in d10 clears Latched scpad_parity; read from
+   this register return zero */
+#define MISC_REG_AEU_CLR_LATCH_SIGNAL				 0xa45c
+/* [RW 32] first 32b for enabling the output for function 0 output0. mapped
+   as follows: [0] NIG attention for function0; [1] NIG attention for
+   function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function
+   0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8]
+   GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event
+   function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP
+   Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14]
+   SPIO4; [15] SPIO5; [16] MSI/X indication for function 0; [17] MSI/X
+   indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt;
+   [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23]
+   SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26]
+   TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29]
+   TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */
+#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0			 0xa06c
+#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1			 0xa07c
+#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3			 0xa09c
+/* [RW 32] first 32b for enabling the output for function 1 output0. mapped
+   as follows: [0] NIG attention for function0; [1] NIG attention for
+   function1; [2] GPIO1 function 1; [3] GPIO2 function 1; [4] GPIO3 function
+   1; [5] GPIO4 function 1; [6] GPIO1 function 1; [7] GPIO2 function 1; [8]
+   GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event
+   function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP
+   Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14]
+   SPIO4; [15] SPIO5; [16] MSI/X indication for function 1; [17] MSI/X
+   indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt;
+   [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23]
+   SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26]
+   TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29]
+   TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */
+#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0			 0xa10c
+#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1			 0xa11c
+#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3			 0xa13c
+/* [RW 32] first 32b for enabling the output for close the gate nig 0.
+   mapped as follows: [0] NIG attention for function0; [1] NIG attention for
+   function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function
+   0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8]
+   GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event
+   function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP
+   Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14]
+   SPIO4; [15] SPIO5; [16] MSI/X indication for function 0; [17] MSI/X
+   indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt;
+   [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23]
+   SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26]
+   TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29]
+   TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */
+#define MISC_REG_AEU_ENABLE1_NIG_0				 0xa0ec
+#define MISC_REG_AEU_ENABLE1_NIG_1				 0xa18c
+/* [RW 32] first 32b for enabling the output for close the gate pxp 0.
+   mapped as follows: [0] NIG attention for function0; [1] NIG attention for
+   function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function
+   0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8]
+   GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event
+   function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP
+   Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14]
+   SPIO4; [15] SPIO5; [16] MSI/X indication for function 0; [17] MSI/X
+   indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt;
+   [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23]
+   SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26]
+   TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29]
+   TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */
+#define MISC_REG_AEU_ENABLE1_PXP_0				 0xa0fc
+#define MISC_REG_AEU_ENABLE1_PXP_1				 0xa19c
+/* [RW 32] second 32b for enabling the output for function 0 output0. mapped
+   as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM
+   Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw
+   interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity
+   error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw
+   interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14]
+   NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error;
+   [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw
+   interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM
+   Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI
+   Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM
+   Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw
+   interrupt; */
+#define MISC_REG_AEU_ENABLE2_FUNC_0_OUT_0			 0xa070
+#define MISC_REG_AEU_ENABLE2_FUNC_0_OUT_1			 0xa080
+/* [RW 32] second 32b for enabling the output for function 1 output0. mapped
+   as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM
+   Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw
+   interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity
+   error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw
+   interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14]
+   NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error;
+   [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw
+   interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM
+   Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI
+   Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM
+   Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw
+   interrupt; */
+#define MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0			 0xa110
+#define MISC_REG_AEU_ENABLE2_FUNC_1_OUT_1			 0xa120
+/* [RW 32] second 32b for enabling the output for close the gate nig 0.
+   mapped as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt;
+   [2] QM Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5]
+   Timers Hw interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8]
+   XCM Parity error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11]
+   XSEMI Hw interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw
+   interrupt; [14] NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI
+   core Parity error; [17] Vaux PCI core Hw interrupt; [18] Debug Parity
+   error; [19] Debug Hw interrupt; [20] USDM Parity error; [21] USDM Hw
+   interrupt; [22] UCM Parity error; [23] UCM Hw interrupt; [24] USEMI
+   Parity error; [25] USEMI Hw interrupt; [26] UPB Parity error; [27] UPB Hw
+   interrupt; [28] CSDM Parity error; [29] CSDM Hw interrupt; [30] CCM
+   Parity error; [31] CCM Hw interrupt; */
+#define MISC_REG_AEU_ENABLE2_NIG_0				 0xa0f0
+#define MISC_REG_AEU_ENABLE2_NIG_1				 0xa190
+/* [RW 32] second 32b for enabling the output for close the gate pxp 0.
+   mapped as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt;
+   [2] QM Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5]
+   Timers Hw interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8]
+   XCM Parity error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11]
+   XSEMI Hw interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw
+   interrupt; [14] NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI
+   core Parity error; [17] Vaux PCI core Hw interrupt; [18] Debug Parity
+   error; [19] Debug Hw interrupt; [20] USDM Parity error; [21] USDM Hw
+   interrupt; [22] UCM Parity error; [23] UCM Hw interrupt; [24] USEMI
+   Parity error; [25] USEMI Hw interrupt; [26] UPB Parity error; [27] UPB Hw
+   interrupt; [28] CSDM Parity error; [29] CSDM Hw interrupt; [30] CCM
+   Parity error; [31] CCM Hw interrupt; */
+#define MISC_REG_AEU_ENABLE2_PXP_0				 0xa100
+#define MISC_REG_AEU_ENABLE2_PXP_1				 0xa1a0
+/* [RW 32] third 32b for enabling the output for function 0 output0. mapped
+   as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP
+   Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error;
+   [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw
+   interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity
+   error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC)
+   Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16]
+   pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20]
+   MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23]
+   SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW
+   timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3
+   func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General
+   attn1; */
+#define MISC_REG_AEU_ENABLE3_FUNC_0_OUT_0			 0xa074
+#define MISC_REG_AEU_ENABLE3_FUNC_0_OUT_1			 0xa084
+/* [RW 32] third 32b for enabling the output for function 1 output0. mapped
+   as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP
+   Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error;
+   [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw
+   interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity
+   error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC)
+   Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16]
+   pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20]
+   MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23]
+   SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW
+   timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3
+   func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General
+   attn1; */
+#define MISC_REG_AEU_ENABLE3_FUNC_1_OUT_0			 0xa114
+#define MISC_REG_AEU_ENABLE3_FUNC_1_OUT_1			 0xa124
+/* [RW 32] third 32b for enabling the output for close the gate nig 0.
+   mapped as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2]
+   PXP Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity
+   error; [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC
+   Hw interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE
+   Parity error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13]
+   IGU (HC) Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt;
+   [16] pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0;
+   [20] MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0;
+   [23] SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST;
+   [26] SW timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers
+   attn_3 func1; [29] SW timers attn_4 func1; [30] General attn0; [31]
+   General attn1; */
+#define MISC_REG_AEU_ENABLE3_NIG_0				 0xa0f4
+#define MISC_REG_AEU_ENABLE3_NIG_1				 0xa194
+/* [RW 32] third 32b for enabling the output for close the gate pxp 0.
+   mapped as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2]
+   PXP Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity
+   error; [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC
+   Hw interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE
+   Parity error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13]
+   IGU (HC) Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt;
+   [16] pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0;
+   [20] MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0;
+   [23] SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST;
+   [26] SW timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers
+   attn_3 func1; [29] SW timers attn_4 func1; [30] General attn0; [31]
+   General attn1; */
+#define MISC_REG_AEU_ENABLE3_PXP_0				 0xa104
+#define MISC_REG_AEU_ENABLE3_PXP_1				 0xa1a4
+/* [RW 32] fourth 32b for enabling the output for function 0 output0.mapped
+   as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3]
+   General attn5; [4] General attn6; [5] General attn7; [6] General attn8;
+   [7] General attn9; [8] General attn10; [9] General attn11; [10] General
+   attn12; [11] General attn13; [12] General attn14; [13] General attn15;
+   [14] General attn16; [15] General attn17; [16] General attn18; [17]
+   General attn19; [18] General attn20; [19] General attn21; [20] Main power
+   interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN
+   Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC
+   Latched timeout attention; [27] GRC Latched reserved access attention;
+   [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP
+   Latched ump_tx_parity; [31] MCP Latched scpad_parity; */
+#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0			 0xa078
+#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_2			 0xa098
+/* [RW 32] fourth 32b for enabling the output for function 1 output0.mapped
+   as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3]
+   General attn5; [4] General attn6; [5] General attn7; [6] General attn8;
+   [7] General attn9; [8] General attn10; [9] General attn11; [10] General
+   attn12; [11] General attn13; [12] General attn14; [13] General attn15;
+   [14] General attn16; [15] General attn17; [16] General attn18; [17]
+   General attn19; [18] General attn20; [19] General attn21; [20] Main power
+   interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN
+   Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC
+   Latched timeout attention; [27] GRC Latched reserved access attention;
+   [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP
+   Latched ump_tx_parity; [31] MCP Latched scpad_parity; */
+#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0			 0xa118
+#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_2			 0xa138
+/* [RW 32] fourth 32b for enabling the output for close the gate nig
+   0.mapped as follows: [0] General attn2; [1] General attn3; [2] General
+   attn4; [3] General attn5; [4] General attn6; [5] General attn7; [6]
+   General attn8; [7] General attn9; [8] General attn10; [9] General attn11;
+   [10] General attn12; [11] General attn13; [12] General attn14; [13]
+   General attn15; [14] General attn16; [15] General attn17; [16] General
+   attn18; [17] General attn19; [18] General attn20; [19] General attn21;
+   [20] Main power interrupt; [21] RBCR Latched attn; [22] RBCT Latched
+   attn; [23] RBCN Latched attn; [24] RBCU Latched attn; [25] RBCP Latched
+   attn; [26] GRC Latched timeout attention; [27] GRC Latched reserved
+   access attention; [28] MCP Latched rom_parity; [29] MCP Latched
+   ump_rx_parity; [30] MCP Latched ump_tx_parity; [31] MCP Latched
+   scpad_parity; */
+#define MISC_REG_AEU_ENABLE4_NIG_0				 0xa0f8
+#define MISC_REG_AEU_ENABLE4_NIG_1				 0xa198
+/* [RW 32] fourth 32b for enabling the output for close the gate pxp
+   0.mapped as follows: [0] General attn2; [1] General attn3; [2] General
+   attn4; [3] General attn5; [4] General attn6; [5] General attn7; [6]
+   General attn8; [7] General attn9; [8] General attn10; [9] General attn11;
+   [10] General attn12; [11] General attn13; [12] General attn14; [13]
+   General attn15; [14] General attn16; [15] General attn17; [16] General
+   attn18; [17] General attn19; [18] General attn20; [19] General attn21;
+   [20] Main power interrupt; [21] RBCR Latched attn; [22] RBCT Latched
+   attn; [23] RBCN Latched attn; [24] RBCU Latched attn; [25] RBCP Latched
+   attn; [26] GRC Latched timeout attention; [27] GRC Latched reserved
+   access attention; [28] MCP Latched rom_parity; [29] MCP Latched
+   ump_rx_parity; [30] MCP Latched ump_tx_parity; [31] MCP Latched
+   scpad_parity; */
+#define MISC_REG_AEU_ENABLE4_PXP_0				 0xa108
+#define MISC_REG_AEU_ENABLE4_PXP_1				 0xa1a8
+/* [RW 1] set/clr general attention 0; this will set/clr bit 94 in the aeu
+   128 bit vector */
+#define MISC_REG_AEU_GENERAL_ATTN_0				 0xa000
+#define MISC_REG_AEU_GENERAL_ATTN_1				 0xa004
+#define MISC_REG_AEU_GENERAL_ATTN_10				 0xa028
+#define MISC_REG_AEU_GENERAL_ATTN_11				 0xa02c
+#define MISC_REG_AEU_GENERAL_ATTN_12				 0xa030
+#define MISC_REG_AEU_GENERAL_ATTN_13				 0xa034
+#define MISC_REG_AEU_GENERAL_ATTN_14				 0xa038
+#define MISC_REG_AEU_GENERAL_ATTN_15				 0xa03c
+#define MISC_REG_AEU_GENERAL_ATTN_16				 0xa040
+#define MISC_REG_AEU_GENERAL_ATTN_17				 0xa044
+#define MISC_REG_AEU_GENERAL_ATTN_18				 0xa048
+#define MISC_REG_AEU_GENERAL_ATTN_19				 0xa04c
+#define MISC_REG_AEU_GENERAL_ATTN_11				 0xa02c
+#define MISC_REG_AEU_GENERAL_ATTN_2				 0xa008
+#define MISC_REG_AEU_GENERAL_ATTN_20				 0xa050
+#define MISC_REG_AEU_GENERAL_ATTN_21				 0xa054
+#define MISC_REG_AEU_GENERAL_ATTN_3				 0xa00c
+#define MISC_REG_AEU_GENERAL_ATTN_4				 0xa010
+#define MISC_REG_AEU_GENERAL_ATTN_5				 0xa014
+#define MISC_REG_AEU_GENERAL_ATTN_6				 0xa018
+/* [RW 32] first 32b for inverting the input for function 0; for each bit:
+   0= do not invert; 1= invert; mapped as follows: [0] NIG attention for
+   function0; [1] NIG attention for function1; [2] GPIO1 mcp; [3] GPIO2 mcp;
+   [4] GPIO3 mcp; [5] GPIO4 mcp; [6] GPIO1 function 1; [7] GPIO2 function 1;
+   [8] GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event
+   function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP
+   Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14]
+   SPIO4; [15] SPIO5; [16] MSI/X indication for mcp; [17] MSI/X indication
+   for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; [20] PRS
+   Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] SRC Hw
+   interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] TCM
+   Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] TSEMI
+   Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */
+#define MISC_REG_AEU_INVERTER_1_FUNC_0				 0xa22c
+#define MISC_REG_AEU_INVERTER_1_FUNC_1				 0xa23c
+/* [RW 32] second 32b for inverting the input for function 0; for each bit:
+   0= do not invert; 1= invert. mapped as follows: [0] PBClient Parity
+   error; [1] PBClient Hw interrupt; [2] QM Parity error; [3] QM Hw
+   interrupt; [4] Timers Parity error; [5] Timers Hw interrupt; [6] XSDM
+   Parity error; [7] XSDM Hw interrupt; [8] XCM Parity error; [9] XCM Hw
+   interrupt; [10] XSEMI Parity error; [11] XSEMI Hw interrupt; [12]
+   DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] NIG Parity
+   error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; [17] Vaux
+   PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw interrupt;
+   [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM Parity error;
+   [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI Hw interrupt;
+   [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM Parity error;
+   [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw interrupt; */
+#define MISC_REG_AEU_INVERTER_2_FUNC_0				 0xa230
+#define MISC_REG_AEU_INVERTER_2_FUNC_1				 0xa240
+/* [RW 10] [7:0] = mask 8 attention output signals toward IGU function0;
+   [9:8] = mask close the gates signals of function 0 toward PXP [8] and NIG
+   [9]. Zero = mask; one = unmask */
+#define MISC_REG_AEU_MASK_ATTN_FUNC_0				 0xa060
+#define MISC_REG_AEU_MASK_ATTN_FUNC_1				 0xa064
+/* [R 4] This field indicates the type of the device. '0' - 2 Ports; '1' - 1
+   Port. */
+#define MISC_REG_BOND_ID					 0xa400
+/* [R 8] These bits indicate the metal revision of the chip. This value
+   starts at 0x00 for each all-layer tape-out and increments by one for each
+   tape-out. */
+#define MISC_REG_CHIP_METAL					 0xa404
+/* [R 16] These bits indicate the part number for the chip. */
+#define MISC_REG_CHIP_NUM					 0xa408
+/* [R 4] These bits indicate the base revision of the chip. This value
+   starts at 0x0 for the A0 tape-out and increments by one for each
+   all-layer tape-out. */
+#define MISC_REG_CHIP_REV					 0xa40c
+/* [RW 1] Setting this bit enables a timer in the GRC block to timeout any
+   access that does not finish within
+   ~misc_registers_grc_timout_val.grc_timeout_val cycles. When this bit is
+   cleared; this timeout is disabled. If this timeout occurs; the GRC shall
+   assert it attention output. */
+#define MISC_REG_GRC_TIMEOUT_EN 				 0xa280
+/* [RW 28] 28 LSB of LCPLL first register; reset val = 521. inside order of
+   the bits is: [2:0] OAC reset value 001) CML output buffer bias control;
+   111 for +40%; 011 for +20%; 001 for 0%; 000 for -20%. [5:3] Icp_ctrl
+   (reset value 001) Charge pump current control; 111 for 720u; 011 for
+   600u; 001 for 480u and 000 for 360u. [7:6] Bias_ctrl (reset value 00)
+   Global bias control; When bit 7 is high bias current will be 10 0gh; When
+   bit 6 is high bias will be 100w; Valid values are 00; 10; 01. [10:8]
+   Pll_observe (reset value 010) Bits to control observability. bit 10 is
+   for test bias; bit 9 is for test CK; bit 8 is test Vc. [12:11] Vth_ctrl
+   (reset value 00) Comparator threshold control. 00 for 0.6V; 01 for 0.54V
+   and 10 for 0.66V. [13] pllSeqStart (reset value 0) Enables VCO tuning
+   sequencer: 1= sequencer disabled; 0= sequencer enabled (inverted
+   internally). [14] reserved (reset value 0) Reset for VCO sequencer is
+   connected to RESET input directly. [15] capRetry_en (reset value 0)
+   enable retry on cap search failure (inverted). [16] freqMonitor_e (reset
+   value 0) bit to continuously monitor vco freq (inverted). [17]
+   freqDetRestart_en (reset value 0) bit to enable restart when not freq
+   locked (inverted). [18] freqDetRetry_en (reset value 0) bit to enable
+   retry on freq det failure(inverted). [19] pllForceFdone_en (reset value
+   0) bit to enable pllForceFdone & pllForceFpass into pllSeq. [20]
+   pllForceFdone (reset value 0) bit to force freqDone. [21] pllForceFpass
+   (reset value 0) bit to force freqPass. [22] pllForceDone_en (reset value
+   0) bit to enable pllForceCapDone. [23] pllForceCapDone (reset value 0)
+   bit to force capDone. [24] pllForceCapPass_en (reset value 0) bit to
+   enable pllForceCapPass. [25] pllForceCapPass (reset value 0) bit to force
+   capPass. [26] capRestart (reset value 0) bit to force cap sequencer to
+   restart. [27] capSelectM_en (reset value 0) bit to enable cap select
+   register bits. */
+#define MISC_REG_LCPLL_CTRL_1					 0xa2a4
+#define MISC_REG_LCPLL_CTRL_REG_2				 0xa2a8
+/* [RW 4] Interrupt mask register #0 read/write */
+#define MISC_REG_MISC_INT_MASK					 0xa388
+/* [RW 1] Parity mask register #0 read/write */
+#define MISC_REG_MISC_PRTY_MASK 				 0xa398
+/* [RW 32] 32 LSB of storm PLL first register; reset val = 0x 071d2911.
+   inside order of the bits is: [0] P1 divider[0] (reset value 1); [1] P1
+   divider[1] (reset value 0); [2] P1 divider[2] (reset value 0); [3] P1
+   divider[3] (reset value 0); [4] P2 divider[0] (reset value 1); [5] P2
+   divider[1] (reset value 0); [6] P2 divider[2] (reset value 0); [7] P2
+   divider[3] (reset value 0); [8] ph_det_dis (reset value 1); [9]
+   freq_det_dis (reset value 0); [10] Icpx[0] (reset value 0); [11] Icpx[1]
+   (reset value 1); [12] Icpx[2] (reset value 0); [13] Icpx[3] (reset value
+   1); [14] Icpx[4] (reset value 0); [15] Icpx[5] (reset value 0); [16]
+   Rx[0] (reset value 1); [17] Rx[1] (reset value 0); [18] vc_en (reset
+   value 1); [19] vco_rng[0] (reset value 1); [20] vco_rng[1] (reset value
+   1); [21] Kvco_xf[0] (reset value 0); [22] Kvco_xf[1] (reset value 0);
+   [23] Kvco_xf[2] (reset value 0); [24] Kvco_xs[0] (reset value 1); [25]
+   Kvco_xs[1] (reset value 1); [26] Kvco_xs[2] (reset value 1); [27]
+   testd_en (reset value 0); [28] testd_sel[0] (reset value 0); [29]
+   testd_sel[1] (reset value 0); [30] testd_sel[2] (reset value 0); [31]
+   testa_en (reset value 0); */
+#define MISC_REG_PLL_STORM_CTRL_1				 0xa294
+#define MISC_REG_PLL_STORM_CTRL_2				 0xa298
+#define MISC_REG_PLL_STORM_CTRL_3				 0xa29c
+#define MISC_REG_PLL_STORM_CTRL_4				 0xa2a0
+/* [RW 32] reset reg#1; rite/read one = the specific block is out of reset;
+   write/read zero = the specific block is in reset; addr 0-wr- the write
+   value will be written to the register; addr 1-set - one will be written
+   to all the bits that have the value of one in the data written (bits that
+   have the value of zero will not be change) ; addr 2-clear - zero will be
+   written to all the bits that have the value of one in the data written
+   (bits that have the value of zero will not be change); addr 3-ignore;
+   read ignore from all addr except addr 00; inside order of the bits is:
+   [0] rst_brb1; [1] rst_prs; [2] rst_src; [3] rst_tsdm; [4] rst_tsem; [5]
+   rst_tcm; [6] rst_rbcr; [7] rst_nig; [8] rst_usdm; [9] rst_ucm; [10]
+   rst_usem; [11] rst_upb; [12] rst_ccm; [13] rst_csem; [14] rst_csdm; [15]
+   rst_rbcu; [16] rst_pbf; [17] rst_qm; [18] rst_tm; [19] rst_dorq; [20]
+   rst_xcm; [21] rst_xsdm; [22] rst_xsem; [23] rst_rbct; [24] rst_cdu; [25]
+   rst_cfc; [26] rst_pxp; [27] rst_pxpv; [28] rst_rbcp; [29] rst_hc; [30]
+   rst_dmae; [31] rst_semi_rtc; */
+#define MISC_REG_RESET_REG_1					 0xa580
+#define MISC_REG_RESET_REG_2					 0xa590
+/* [RW 20] 20 bit GRC address where the scratch-pad of the MCP that is
+   shared with the driver resides */
+#define MISC_REG_SHARED_MEM_ADDR				 0xa2b4
+#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT	 (0x1<<0)
+#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS	 (0x1<<9)
+#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G 	 (0x1<<15)
+#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS	 (0xf<<18)
+/* [RW 1] Input enable for RX_BMAC0 IF */
+#define NIG_REG_BMAC0_IN_EN					 0x100ac
+/* [RW 1] output enable for TX_BMAC0 IF */
+#define NIG_REG_BMAC0_OUT_EN					 0x100e0
+/* [RW 1] output enable for TX BMAC pause port 0 IF */
+#define NIG_REG_BMAC0_PAUSE_OUT_EN				 0x10110
+/* [RW 1] output enable for RX_BMAC0_REGS IF */
+#define NIG_REG_BMAC0_REGS_OUT_EN				 0x100e8
+/* [RW 1] output enable for RX BRB1 port0 IF */
+#define NIG_REG_BRB0_OUT_EN					 0x100f8
+/* [RW 1] Input enable for TX BRB1 pause port 0 IF */
+#define NIG_REG_BRB0_PAUSE_IN_EN				 0x100c4
+/* [RW 1] output enable for RX BRB1 port1 IF */
+#define NIG_REG_BRB1_OUT_EN					 0x100fc
+/* [RW 1] Input enable for TX BRB1 pause port 1 IF */
+#define NIG_REG_BRB1_PAUSE_IN_EN				 0x100c8
+/* [RW 1] output enable for RX BRB1 LP IF */
+#define NIG_REG_BRB_LB_OUT_EN					 0x10100
+/* [WB_W 72] Debug packet to LP from RBC; Data spelling:[63:0] data; 64]
+   error; [67:65]eop_bvalid; [68]eop; [69]sop; [70]port_id; 71]flush */
+#define NIG_REG_DEBUG_PACKET_LB 				 0x10800
+/* [RW 1] Input enable for TX Debug packet */
+#define NIG_REG_EGRESS_DEBUG_IN_EN				 0x100dc
+/* [RW 1] If 1 - egress drain mode for port0 is active. In this mode all
+   packets from PBFare not forwarded to the MAC and just deleted from FIFO.
+   First packet may be deleted from the middle. And last packet will be
+   always deleted till the end. */
+#define NIG_REG_EGRESS_DRAIN0_MODE				 0x10060
+/* [RW 1] Output enable to EMAC0 */
+#define NIG_REG_EGRESS_EMAC0_OUT_EN				 0x10120
+/* [RW 1] MAC configuration for packets of port0. If 1 - all packet outputs
+   to emac for port0; other way to bmac for port0 */
+#define NIG_REG_EGRESS_EMAC0_PORT				 0x10058
+/* [RW 1] Input enable for TX PBF user packet port0 IF */
+#define NIG_REG_EGRESS_PBF0_IN_EN				 0x100cc
+/* [RW 1] Input enable for TX PBF user packet port1 IF */
+#define NIG_REG_EGRESS_PBF1_IN_EN				 0x100d0
+/* [RW 1] Input enable for RX_EMAC0 IF */
+#define NIG_REG_EMAC0_IN_EN					 0x100a4
+/* [RW 1] output enable for TX EMAC pause port 0 IF */
+#define NIG_REG_EMAC0_PAUSE_OUT_EN				 0x10118
+/* [R 1] status from emac0. This bit is set when MDINT from either the
+   EXT_MDINT pin or from the Copper PHY is driven low. This condition must
+   be cleared in the attached PHY device that is driving the MINT pin. */
+#define NIG_REG_EMAC0_STATUS_MISC_MI_INT			 0x10494
+/* [WB 48] This address space contains BMAC0 registers. The BMAC registers
+   are described in appendix A. In order to access the BMAC0 registers; the
+   base address; NIG_REGISTERS_INGRESS_BMAC0_MEM; Offset: 0x10c00; should be
+   added to each BMAC register offset */
+#define NIG_REG_INGRESS_BMAC0_MEM				 0x10c00
+/* [WB 48] This address space contains BMAC1 registers. The BMAC registers
+   are described in appendix A. In order to access the BMAC0 registers; the
+   base address; NIG_REGISTERS_INGRESS_BMAC1_MEM; Offset: 0x11000; should be
+   added to each BMAC register offset */
+#define NIG_REG_INGRESS_BMAC1_MEM				 0x11000
+/* [R 1] FIFO empty in EOP descriptor FIFO of LP in NIG_RX_EOP */
+#define NIG_REG_INGRESS_EOP_LB_EMPTY				 0x104e0
+/* [RW 17] Debug only. RX_EOP_DSCR_lb_FIFO in NIG_RX_EOP. Data
+   packet_length[13:0]; mac_error[14]; trunc_error[15]; parity[16] */
+#define NIG_REG_INGRESS_EOP_LB_FIFO				 0x104e4
+/* [RW 1] led 10g for port 0 */
+#define NIG_REG_LED_10G_P0					 0x10320
+/* [RW 1] Port0: This bit is set to enable the use of the
+   ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 field
+   defined below. If this bit is cleared; then the blink rate will be about
+   8Hz. */
+#define NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0			 0x10318
+/* [RW 12] Port0: Specifies the period of each blink cycle (on + off) for
+   Traffic LED in milliseconds. Must be a non-zero value. This 12-bit field
+   is reset to 0x080; giving a default blink period of approximately 8Hz. */
+#define NIG_REG_LED_CONTROL_BLINK_RATE_P0			 0x10310
+/* [RW 1] Port0: If set along with the
+   nig_registers_led_control_override_traffic_p0.led_control_override_traffic_p0
+   bit and ~nig_registers_led_control_traffic_p0.led_control_traffic_p0 LED
+   bit; the Traffic LED will blink with the blink rate specified in
+   ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 and
+   ~nig_registers_led_control_blink_rate_ena_p0.led_control_blink_rate_ena_p0
+   fields. */
+#define NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0			 0x10308
+/* [RW 1] Port0: If set overrides hardware control of the Traffic LED. The
+   Traffic LED will then be controlled via bit ~nig_registers_
+   led_control_traffic_p0.led_control_traffic_p0 and bit
+   ~nig_registers_led_control_blink_traffic_p0.led_control_blink_traffic_p0 */
+#define NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 		 0x102f8
+/* [RW 1] Port0: If set along with the led_control_override_trafic_p0 bit;
+   turns on the Traffic LED. If the led_control_blink_traffic_p0 bit is also
+   set; the LED will blink with blink rate specified in
+   ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 and
+   ~nig_regsters_led_control_blink_rate_ena_p0.led_control_blink_rate_ena_p0
+   fields. */
+#define NIG_REG_LED_CONTROL_TRAFFIC_P0				 0x10300
+/* [RW 4] led mode for port0: 0 MAC; 1-3 PHY1; 4 MAC2; 5-7 PHY4; 8-MAC3;
+   9-11PHY7; 12 MAC4; 13-15 PHY10; */
+#define NIG_REG_LED_MODE_P0					 0x102f0
+#define NIG_REG_LLH0_BRB1_DRV_MASK				 0x10244
+/* [RW 1] send to BRB1 if no match on any of RMP rules. */
+#define NIG_REG_LLH0_BRB1_NOT_MCP				 0x1025c
+/* [RW 32] cm header for llh0 */
+#define NIG_REG_LLH0_CM_HEADER					 0x1007c
+#define NIG_REG_LLH0_ERROR_MASK 				 0x1008c
+/* [RW 8] event id for llh0 */
+#define NIG_REG_LLH0_EVENT_ID					 0x10084
+/* [RW 8] init credit counter for port0 in LLH */
+#define NIG_REG_LLH0_XCM_INIT_CREDIT				 0x10554
+#define NIG_REG_LLH0_XCM_MASK					 0x10130
+/* [RW 1] send to BRB1 if no match on any of RMP rules. */
+#define NIG_REG_LLH1_BRB1_NOT_MCP				 0x102dc
+/* [RW 32] cm header for llh1 */
+#define NIG_REG_LLH1_CM_HEADER					 0x10080
+#define NIG_REG_LLH1_ERROR_MASK 				 0x10090
+/* [RW 8] event id for llh1 */
+#define NIG_REG_LLH1_EVENT_ID					 0x10088
+/* [RW 8] init credit counter for port1 in LLH */
+#define NIG_REG_LLH1_XCM_INIT_CREDIT				 0x10564
+#define NIG_REG_LLH1_XCM_MASK					 0x10134
+#define NIG_REG_MASK_INTERRUPT_PORT0				 0x10330
+#define NIG_REG_MASK_INTERRUPT_PORT1				 0x10334
+/* [RW 1] Output signal from NIG to EMAC0. When set enables the EMAC0 block. */
+#define NIG_REG_NIG_EMAC0_EN					 0x1003c
+/* [RW 1] Output signal from NIG to TX_EMAC0. When set indicates to the
+   EMAC0 to strip the CRC from the ingress packets. */
+#define NIG_REG_NIG_INGRESS_EMAC0_NO_CRC			 0x10044
+/* [RW 1] Input enable for RX PBF LP IF */
+#define NIG_REG_PBF_LB_IN_EN					 0x100b4
+/* [RW 1] output enable for RX parser descriptor IF */
+#define NIG_REG_PRS_EOP_OUT_EN					 0x10104
+/* [RW 1] Input enable for RX parser request IF */
+#define NIG_REG_PRS_REQ_IN_EN					 0x100b8
+/* [RW 5] control to serdes - CL22 PHY_ADD and CL45 PRTAD */
+#define NIG_REG_SERDES0_CTRL_PHY_ADDR				 0x10374
+/* [R 1] status from serdes0 that inputs to interrupt logic of link status */
+#define NIG_REG_SERDES0_STATUS_LINK_STATUS			 0x10578
+/* [R 32] Rx statistics : In user packets discarded due to BRB backpressure
+   for port0 */
+#define NIG_REG_STAT0_BRB_DISCARD				 0x105f0
+/* [R 32] Rx statistics : In user packets discarded due to BRB backpressure
+   for port1 */
+#define NIG_REG_STAT1_BRB_DISCARD				 0x10628
+/* [WB_R 64] Rx statistics : User octets received for LP */
+#define NIG_REG_STAT2_BRB_OCTET 				 0x107e0
+#define NIG_REG_STATUS_INTERRUPT_PORT0				 0x10328
+#define NIG_REG_STATUS_INTERRUPT_PORT1				 0x1032c
+/* [RW 1] output enable for RX_XCM0 IF */
+#define NIG_REG_XCM0_OUT_EN					 0x100f0
+/* [RW 1] output enable for RX_XCM1 IF */
+#define NIG_REG_XCM1_OUT_EN					 0x100f4
+/* [RW 5] control to xgxs - CL45 DEVAD */
+#define NIG_REG_XGXS0_CTRL_MD_DEVAD				 0x1033c
+/* [RW 5] control to xgxs - CL22 PHY_ADD and CL45 PRTAD */
+#define NIG_REG_XGXS0_CTRL_PHY_ADDR				 0x10340
+/* [R 1] status from xgxs0 that inputs to interrupt logic of link10g. */
+#define NIG_REG_XGXS0_STATUS_LINK10G				 0x10680
+/* [R 4] status from xgxs0 that inputs to interrupt logic of link status */
+#define NIG_REG_XGXS0_STATUS_LINK_STATUS			 0x10684
+/* [RW 2] selection for XGXS lane of port 0 in NIG_MUX block */
+#define NIG_REG_XGXS_LANE_SEL_P0				 0x102e8
+/* [RW 1] selection for port0 for NIG_MUX block : 0 = SerDes; 1 = XGXS */
+#define NIG_REG_XGXS_SERDES0_MODE_SEL				 0x102e0
+#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS (0x1<<9)
+#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G	 (0x1<<15)
+#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS  (0xf<<18)
+#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE 18
+/* [RW 1] Disable processing further tasks from port 0 (after ending the
+   current task in process). */
+#define PBF_REG_DISABLE_NEW_TASK_PROC_P0			 0x14005c
+/* [RW 1] Disable processing further tasks from port 1 (after ending the
+   current task in process). */
+#define PBF_REG_DISABLE_NEW_TASK_PROC_P1			 0x140060
+/* [RW 1] Disable processing further tasks from port 4 (after ending the
+   current task in process). */
+#define PBF_REG_DISABLE_NEW_TASK_PROC_P4			 0x14006c
+#define PBF_REG_IF_ENABLE_REG					 0x140044
+/* [RW 1] Init bit. When set the initial credits are copied to the credit
+   registers (except the port credits). Should be set and then reset after
+   the configuration of the block has ended. */
+#define PBF_REG_INIT						 0x140000
+/* [RW 1] Init bit for port 0. When set the initial credit of port 0 is
+   copied to the credit register. Should be set and then reset after the
+   configuration of the port has ended. */
+#define PBF_REG_INIT_P0 					 0x140004
+/* [RW 1] Init bit for port 1. When set the initial credit of port 1 is
+   copied to the credit register. Should be set and then reset after the
+   configuration of the port has ended. */
+#define PBF_REG_INIT_P1 					 0x140008
+/* [RW 1] Init bit for port 4. When set the initial credit of port 4 is
+   copied to the credit register. Should be set and then reset after the
+   configuration of the port has ended. */
+#define PBF_REG_INIT_P4 					 0x14000c
+/* [RW 1] Enable for mac interface 0. */
+#define PBF_REG_MAC_IF0_ENABLE					 0x140030
+/* [RW 1] Enable for mac interface 1. */
+#define PBF_REG_MAC_IF1_ENABLE					 0x140034
+/* [RW 1] Enable for the loopback interface. */
+#define PBF_REG_MAC_LB_ENABLE					 0x140040
+/* [RW 10] Port 0 threshold used by arbiter in 16 byte lines used when pause
+   not suppoterd. */
+#define PBF_REG_P0_ARB_THRSH					 0x1400e4
+/* [R 11] Current credit for port 0 in the tx port buffers in 16 byte lines. */
+#define PBF_REG_P0_CREDIT					 0x140200
+/* [RW 11] Initial credit for port 0 in the tx port buffers in 16 byte
+   lines. */
+#define PBF_REG_P0_INIT_CRD					 0x1400d0
+/* [RW 1] Indication that pause is enabled for port 0. */
+#define PBF_REG_P0_PAUSE_ENABLE 				 0x140014
+/* [R 8] Number of tasks in port 0 task queue. */
+#define PBF_REG_P0_TASK_CNT					 0x140204
+/* [R 11] Current credit for port 1 in the tx port buffers in 16 byte lines. */
+#define PBF_REG_P1_CREDIT					 0x140208
+/* [RW 11] Initial credit for port 1 in the tx port buffers in 16 byte
+   lines. */
+#define PBF_REG_P1_INIT_CRD					 0x1400d4
+/* [R 8] Number of tasks in port 1 task queue. */
+#define PBF_REG_P1_TASK_CNT					 0x14020c
+/* [R 11] Current credit for port 4 in the tx port buffers in 16 byte lines. */
+#define PBF_REG_P4_CREDIT					 0x140210
+/* [RW 11] Initial credit for port 4 in the tx port buffers in 16 byte
+   lines. */
+#define PBF_REG_P4_INIT_CRD					 0x1400e0
+/* [R 8] Number of tasks in port 4 task queue. */
+#define PBF_REG_P4_TASK_CNT					 0x140214
+/* [RW 5] Interrupt mask register #0 read/write */
+#define PBF_REG_PBF_INT_MASK					 0x1401d4
+/* [R 5] Interrupt register #0 read */
+#define PBF_REG_PBF_INT_STS					 0x1401c8
+#define PB_REG_CONTROL						 0
+/* [RW 2] Interrupt mask register #0 read/write */
+#define PB_REG_PB_INT_MASK					 0x28
+/* [R 2] Interrupt register #0 read */
+#define PB_REG_PB_INT_STS					 0x1c
+/* [RW 4] Parity mask register #0 read/write */
+#define PB_REG_PB_PRTY_MASK					 0x38
+#define PRS_REG_A_PRSU_20					 0x40134
+/* [R 8] debug only: CFC load request current credit. Transaction based. */
+#define PRS_REG_CFC_LD_CURRENT_CREDIT				 0x40164
+/* [R 8] debug only: CFC search request current credit. Transaction based. */
+#define PRS_REG_CFC_SEARCH_CURRENT_CREDIT			 0x40168
+/* [RW 6] The initial credit for the search message to the CFC interface.
+   Credit is transaction based. */
+#define PRS_REG_CFC_SEARCH_INITIAL_CREDIT			 0x4011c
+/* [RW 24] CID for port 0 if no match */
+#define PRS_REG_CID_PORT_0					 0x400fc
+#define PRS_REG_CID_PORT_1					 0x40100
+/* [RW 32] The CM header for flush message where 'load existed' bit in CFC
+   load response is reset and packet type is 0. Used in packet start message
+   to TCM. */
+#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_0			 0x400dc
+#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_1			 0x400e0
+#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_2			 0x400e4
+#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_3			 0x400e8
+#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_4			 0x400ec
+/* [RW 32] The CM header for flush message where 'load existed' bit in CFC
+   load response is set and packet type is 0. Used in packet start message
+   to TCM. */
+#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_0			 0x400bc
+#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_1			 0x400c0
+#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_2			 0x400c4
+#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_3			 0x400c8
+#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_4			 0x400cc
+/* [RW 32] The CM header for a match and packet type 1 for loopback port.
+   Used in packet start message to TCM. */
+#define PRS_REG_CM_HDR_LOOPBACK_TYPE_1				 0x4009c
+#define PRS_REG_CM_HDR_LOOPBACK_TYPE_2				 0x400a0
+#define PRS_REG_CM_HDR_LOOPBACK_TYPE_3				 0x400a4
+#define PRS_REG_CM_HDR_LOOPBACK_TYPE_4				 0x400a8
+/* [RW 32] The CM header for a match and packet type 0. Used in packet start
+   message to TCM. */
+#define PRS_REG_CM_HDR_TYPE_0					 0x40078
+#define PRS_REG_CM_HDR_TYPE_1					 0x4007c
+#define PRS_REG_CM_HDR_TYPE_2					 0x40080
+#define PRS_REG_CM_HDR_TYPE_3					 0x40084
+#define PRS_REG_CM_HDR_TYPE_4					 0x40088
+/* [RW 32] The CM header in case there was not a match on the connection */
+#define PRS_REG_CM_NO_MATCH_HDR 				 0x400b8
+/* [RW 8] The 8-bit event ID for a match and packet type 1. Used in packet
+   start message to TCM. */
+#define PRS_REG_EVENT_ID_1					 0x40054
+#define PRS_REG_EVENT_ID_2					 0x40058
+#define PRS_REG_EVENT_ID_3					 0x4005c
+/* [RW 8] Context region for flush packet with packet type 0. Used in CFC
+   load request message. */
+#define PRS_REG_FLUSH_REGIONS_TYPE_0				 0x40004
+#define PRS_REG_FLUSH_REGIONS_TYPE_1				 0x40008
+#define PRS_REG_FLUSH_REGIONS_TYPE_2				 0x4000c
+#define PRS_REG_FLUSH_REGIONS_TYPE_3				 0x40010
+#define PRS_REG_FLUSH_REGIONS_TYPE_4				 0x40014
+#define PRS_REG_FLUSH_REGIONS_TYPE_5				 0x40018
+#define PRS_REG_FLUSH_REGIONS_TYPE_6				 0x4001c
+#define PRS_REG_FLUSH_REGIONS_TYPE_7				 0x40020
+/* [RW 4] The increment value to send in the CFC load request message */
+#define PRS_REG_INC_VALUE					 0x40048
+/* [RW 1] If set indicates not to send messages to CFC on received packets */
+#define PRS_REG_NIC_MODE					 0x40138
+/* [RW 8] The 8-bit event ID for cases where there is no match on the
+   connection. Used in packet start message to TCM. */
+#define PRS_REG_NO_MATCH_EVENT_ID				 0x40070
+/* [ST 24] The number of input CFC flush packets */
+#define PRS_REG_NUM_OF_CFC_FLUSH_MESSAGES			 0x40128
+/* [ST 32] The number of cycles the Parser halted its operation since it
+   could not allocate the next serial number */
+#define PRS_REG_NUM_OF_DEAD_CYCLES				 0x40130
+/* [ST 24] The number of input packets */
+#define PRS_REG_NUM_OF_PACKETS					 0x40124
+/* [ST 24] The number of input transparent flush packets */
+#define PRS_REG_NUM_OF_TRANSPARENT_FLUSH_MESSAGES		 0x4012c
+/* [RW 8] Context region for received Ethernet packet with a match and
+   packet type 0. Used in CFC load request message */
+#define PRS_REG_PACKET_REGIONS_TYPE_0				 0x40028
+#define PRS_REG_PACKET_REGIONS_TYPE_1				 0x4002c
+#define PRS_REG_PACKET_REGIONS_TYPE_2				 0x40030
+#define PRS_REG_PACKET_REGIONS_TYPE_3				 0x40034
+#define PRS_REG_PACKET_REGIONS_TYPE_4				 0x40038
+#define PRS_REG_PACKET_REGIONS_TYPE_5				 0x4003c
+#define PRS_REG_PACKET_REGIONS_TYPE_6				 0x40040
+#define PRS_REG_PACKET_REGIONS_TYPE_7				 0x40044
+/* [R 2] debug only: Number of pending requests for CAC on port 0. */
+#define PRS_REG_PENDING_BRB_CAC0_RQ				 0x40174
+/* [R 2] debug only: Number of pending requests for header parsing. */
+#define PRS_REG_PENDING_BRB_PRS_RQ				 0x40170
+/* [R 1] Interrupt register #0 read */
+#define PRS_REG_PRS_INT_STS					 0x40188
+/* [RW 8] Parity mask register #0 read/write */
+#define PRS_REG_PRS_PRTY_MASK					 0x401a4
+/* [RW 8] Context region for pure acknowledge packets. Used in CFC load
+   request message */
+#define PRS_REG_PURE_REGIONS					 0x40024
+/* [R 32] debug only: Serial number status lsb 32 bits. '1' indicates this
+   serail number was released by SDM but cannot be used because a previous
+   serial number was not released. */
+#define PRS_REG_SERIAL_NUM_STATUS_LSB				 0x40154
+/* [R 32] debug only: Serial number status msb 32 bits. '1' indicates this
+   serail number was released by SDM but cannot be used because a previous
+   serial number was not released. */
+#define PRS_REG_SERIAL_NUM_STATUS_MSB				 0x40158
+/* [R 4] debug only: SRC current credit. Transaction based. */
+#define PRS_REG_SRC_CURRENT_CREDIT				 0x4016c
+/* [R 8] debug only: TCM current credit. Cycle based. */
+#define PRS_REG_TCM_CURRENT_CREDIT				 0x40160
+/* [R 8] debug only: TSDM current credit. Transaction based. */
+#define PRS_REG_TSDM_CURRENT_CREDIT				 0x4015c
+/* [R 6] Debug only: Number of used entries in the data FIFO */
+#define PXP2_REG_HST_DATA_FIFO_STATUS				 0x12047c
+/* [R 7] Debug only: Number of used entries in the header FIFO */
+#define PXP2_REG_HST_HEADER_FIFO_STATUS 			 0x120478
+#define PXP2_REG_PGL_CONTROL0					 0x120490
+#define PXP2_REG_PGL_CONTROL1					 0x120514
+/* [RW 32] Inbound interrupt table for CSDM: bits[31:16]-mask;
+   its[15:0]-address */
+#define PXP2_REG_PGL_INT_CSDM_0 				 0x1204f4
+#define PXP2_REG_PGL_INT_CSDM_1 				 0x1204f8
+#define PXP2_REG_PGL_INT_CSDM_2 				 0x1204fc
+#define PXP2_REG_PGL_INT_CSDM_3 				 0x120500
+#define PXP2_REG_PGL_INT_CSDM_4 				 0x120504
+#define PXP2_REG_PGL_INT_CSDM_5 				 0x120508
+#define PXP2_REG_PGL_INT_CSDM_6 				 0x12050c
+#define PXP2_REG_PGL_INT_CSDM_7 				 0x120510
+/* [RW 32] Inbound interrupt table for TSDM: bits[31:16]-mask;
+   its[15:0]-address */
+#define PXP2_REG_PGL_INT_TSDM_0 				 0x120494
+#define PXP2_REG_PGL_INT_TSDM_1 				 0x120498
+#define PXP2_REG_PGL_INT_TSDM_2 				 0x12049c
+#define PXP2_REG_PGL_INT_TSDM_3 				 0x1204a0
+#define PXP2_REG_PGL_INT_TSDM_4 				 0x1204a4
+#define PXP2_REG_PGL_INT_TSDM_5 				 0x1204a8
+#define PXP2_REG_PGL_INT_TSDM_6 				 0x1204ac
+#define PXP2_REG_PGL_INT_TSDM_7 				 0x1204b0
+/* [RW 32] Inbound interrupt table for USDM: bits[31:16]-mask;
+   its[15:0]-address */
+#define PXP2_REG_PGL_INT_USDM_0 				 0x1204b4
+#define PXP2_REG_PGL_INT_USDM_1 				 0x1204b8
+#define PXP2_REG_PGL_INT_USDM_2 				 0x1204bc
+#define PXP2_REG_PGL_INT_USDM_3 				 0x1204c0
+#define PXP2_REG_PGL_INT_USDM_4 				 0x1204c4
+#define PXP2_REG_PGL_INT_USDM_5 				 0x1204c8
+#define PXP2_REG_PGL_INT_USDM_6 				 0x1204cc
+#define PXP2_REG_PGL_INT_USDM_7 				 0x1204d0
+/* [RW 32] Inbound interrupt table for XSDM: bits[31:16]-mask;
+   its[15:0]-address */
+#define PXP2_REG_PGL_INT_XSDM_0 				 0x1204d4
+#define PXP2_REG_PGL_INT_XSDM_1 				 0x1204d8
+#define PXP2_REG_PGL_INT_XSDM_2 				 0x1204dc
+#define PXP2_REG_PGL_INT_XSDM_3 				 0x1204e0
+#define PXP2_REG_PGL_INT_XSDM_4 				 0x1204e4
+#define PXP2_REG_PGL_INT_XSDM_5 				 0x1204e8
+#define PXP2_REG_PGL_INT_XSDM_6 				 0x1204ec
+#define PXP2_REG_PGL_INT_XSDM_7 				 0x1204f0
+/* [R 1] this bit indicates that a read request was blocked because of
+   bus_master_en was deasserted */
+#define PXP2_REG_PGL_READ_BLOCKED				 0x120568
+/* [R 6] debug only */
+#define PXP2_REG_PGL_TXR_CDTS					 0x120528
+/* [R 18] debug only */
+#define PXP2_REG_PGL_TXW_CDTS					 0x12052c
+/* [R 1] this bit indicates that a write request was blocked because of
+   bus_master_en was deasserted */
+#define PXP2_REG_PGL_WRITE_BLOCKED				 0x120564
+#define PXP2_REG_PSWRQ_BW_ADD1					 0x1201c0
+#define PXP2_REG_PSWRQ_BW_ADD10 				 0x1201e4
+#define PXP2_REG_PSWRQ_BW_ADD11 				 0x1201e8
+#define PXP2_REG_PSWRQ_BW_ADD10 				 0x1201e4
+#define PXP2_REG_PSWRQ_BW_ADD11 				 0x1201e8
+#define PXP2_REG_PSWRQ_BW_ADD2					 0x1201c4
+#define PXP2_REG_PSWRQ_BW_ADD28 				 0x120228
+#define PXP2_REG_PSWRQ_BW_ADD28 				 0x120228
+#define PXP2_REG_PSWRQ_BW_ADD3					 0x1201c8
+#define PXP2_REG_PSWRQ_BW_ADD6					 0x1201d4
+#define PXP2_REG_PSWRQ_BW_ADD7					 0x1201d8
+#define PXP2_REG_PSWRQ_BW_ADD8					 0x1201dc
+#define PXP2_REG_PSWRQ_BW_ADD9					 0x1201e0
+#define PXP2_REG_PSWRQ_BW_CREDIT				 0x12032c
+#define PXP2_REG_PSWRQ_BW_L1					 0x1202b0
+#define PXP2_REG_PSWRQ_BW_L10					 0x1202d4
+#define PXP2_REG_PSWRQ_BW_L11					 0x1202d8
+#define PXP2_REG_PSWRQ_BW_L10					 0x1202d4
+#define PXP2_REG_PSWRQ_BW_L11					 0x1202d8
+#define PXP2_REG_PSWRQ_BW_L2					 0x1202b4
+#define PXP2_REG_PSWRQ_BW_L28					 0x120318
+#define PXP2_REG_PSWRQ_BW_L28					 0x120318
+#define PXP2_REG_PSWRQ_BW_L3					 0x1202b8
+#define PXP2_REG_PSWRQ_BW_L6					 0x1202c4
+#define PXP2_REG_PSWRQ_BW_L7					 0x1202c8
+#define PXP2_REG_PSWRQ_BW_L8					 0x1202cc
+#define PXP2_REG_PSWRQ_BW_L9					 0x1202d0
+#define PXP2_REG_PSWRQ_BW_RD					 0x120324
+#define PXP2_REG_PSWRQ_BW_UB1					 0x120238
+#define PXP2_REG_PSWRQ_BW_UB10					 0x12025c
+#define PXP2_REG_PSWRQ_BW_UB11					 0x120260
+#define PXP2_REG_PSWRQ_BW_UB10					 0x12025c
+#define PXP2_REG_PSWRQ_BW_UB11					 0x120260
+#define PXP2_REG_PSWRQ_BW_UB2					 0x12023c
+#define PXP2_REG_PSWRQ_BW_UB28					 0x1202a0
+#define PXP2_REG_PSWRQ_BW_UB28					 0x1202a0
+#define PXP2_REG_PSWRQ_BW_UB3					 0x120240
+#define PXP2_REG_PSWRQ_BW_UB6					 0x12024c
+#define PXP2_REG_PSWRQ_BW_UB7					 0x120250
+#define PXP2_REG_PSWRQ_BW_UB8					 0x120254
+#define PXP2_REG_PSWRQ_BW_UB9					 0x120258
+#define PXP2_REG_PSWRQ_BW_WR					 0x120328
+#define PXP2_REG_PSWRQ_CDU0_L2P 				 0x120000
+#define PXP2_REG_PSWRQ_QM0_L2P					 0x120038
+#define PXP2_REG_PSWRQ_SRC0_L2P 				 0x120054
+#define PXP2_REG_PSWRQ_TM0_L2P					 0x12001c
+/* [RW 25] Interrupt mask register #0 read/write */
+#define PXP2_REG_PXP2_INT_MASK					 0x120578
+/* [R 25] Interrupt register #0 read */
+#define PXP2_REG_PXP2_INT_STS					 0x12056c
+/* [RC 25] Interrupt register #0 read clear */
+#define PXP2_REG_PXP2_INT_STS_CLR				 0x120570
+/* [RW 32] Parity mask register #0 read/write */
+#define PXP2_REG_PXP2_PRTY_MASK_0				 0x120588
+#define PXP2_REG_PXP2_PRTY_MASK_1				 0x120598
+/* [R 1] Debug only: The 'almost full' indication from each fifo (gives
+   indication about backpressure) */
+#define PXP2_REG_RD_ALMOST_FULL_0				 0x120424
+/* [R 8] Debug only: The blocks counter - number of unused block ids */
+#define PXP2_REG_RD_BLK_CNT					 0x120418
+/* [RW 8] Debug only: Total number of available blocks in Tetris Buffer.
+   Must be bigger than 6. Normally should not be changed. */
+#define PXP2_REG_RD_BLK_NUM_CFG 				 0x12040c
+/* [RW 2] CDU byte swapping mode configuration for master read requests */
+#define PXP2_REG_RD_CDURD_SWAP_MODE				 0x120404
+/* [RW 1] When '1'; inputs to the PSWRD block are ignored */
+#define PXP2_REG_RD_DISABLE_INPUTS				 0x120374
+/* [R 1] PSWRD internal memories initialization is done */
+#define PXP2_REG_RD_INIT_DONE					 0x120370
+/* [RW 8] The maximum number of blocks in Tetris Buffer that can be
+   allocated for vq10 */
+#define PXP2_REG_RD_MAX_BLKS_VQ10				 0x1203a0
+/* [RW 8] The maximum number of blocks in Tetris Buffer that can be
+   allocated for vq11 */
+#define PXP2_REG_RD_MAX_BLKS_VQ11				 0x1203a4
+/* [RW 8] The maximum number of blocks in Tetris Buffer that can be
+   allocated for vq17 */
+#define PXP2_REG_RD_MAX_BLKS_VQ17				 0x1203bc
+/* [RW 8] The maximum number of blocks in Tetris Buffer that can be
+   allocated for vq18 */
+#define PXP2_REG_RD_MAX_BLKS_VQ18				 0x1203c0
+/* [RW 8] The maximum number of blocks in Tetris Buffer that can be
+   allocated for vq19 */
+#define PXP2_REG_RD_MAX_BLKS_VQ19				 0x1203c4
+/* [RW 8] The maximum number of blocks in Tetris Buffer that can be
+   allocated for vq22 */
+#define PXP2_REG_RD_MAX_BLKS_VQ22				 0x1203d0
+/* [RW 8] The maximum number of blocks in Tetris Buffer that can be
+   allocated for vq6 */
+#define PXP2_REG_RD_MAX_BLKS_VQ6				 0x120390
+/* [RW 8] The maximum number of blocks in Tetris Buffer that can be
+   allocated for vq9 */
+#define PXP2_REG_RD_MAX_BLKS_VQ9				 0x12039c
+/* [RW 2] PBF byte swapping mode configuration for master read requests */
+#define PXP2_REG_RD_PBF_SWAP_MODE				 0x1203f4
+/* [R 1] Debug only: Indication if delivery ports are idle */
+#define PXP2_REG_RD_PORT_IS_IDLE_0				 0x12041c
+#define PXP2_REG_RD_PORT_IS_IDLE_1				 0x120420
+/* [RW 2] QM byte swapping mode configuration for master read requests */
+#define PXP2_REG_RD_QM_SWAP_MODE				 0x1203f8
+/* [R 7] Debug only: The SR counter - number of unused sub request ids */
+#define PXP2_REG_RD_SR_CNT					 0x120414
+/* [RW 2] SRC byte swapping mode configuration for master read requests */
+#define PXP2_REG_RD_SRC_SWAP_MODE				 0x120400
+/* [RW 7] Debug only: Total number of available PCI read sub-requests. Must
+   be bigger than 1. Normally should not be changed. */
+#define PXP2_REG_RD_SR_NUM_CFG					 0x120408
+/* [RW 1] Signals the PSWRD block to start initializing internal memories */
+#define PXP2_REG_RD_START_INIT					 0x12036c
+/* [RW 2] TM byte swapping mode configuration for master read requests */
+#define PXP2_REG_RD_TM_SWAP_MODE				 0x1203fc
+/* [RW 10] Bandwidth addition to VQ0 write requests */
+#define PXP2_REG_RQ_BW_RD_ADD0					 0x1201bc
+/* [RW 10] Bandwidth addition to VQ12 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD12 				 0x1201ec
+/* [RW 10] Bandwidth addition to VQ13 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD13 				 0x1201f0
+/* [RW 10] Bandwidth addition to VQ14 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD14 				 0x1201f4
+/* [RW 10] Bandwidth addition to VQ15 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD15 				 0x1201f8
+/* [RW 10] Bandwidth addition to VQ16 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD16 				 0x1201fc
+/* [RW 10] Bandwidth addition to VQ17 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD17 				 0x120200
+/* [RW 10] Bandwidth addition to VQ18 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD18 				 0x120204
+/* [RW 10] Bandwidth addition to VQ19 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD19 				 0x120208
+/* [RW 10] Bandwidth addition to VQ20 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD20 				 0x12020c
+/* [RW 10] Bandwidth addition to VQ22 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD22 				 0x120210
+/* [RW 10] Bandwidth addition to VQ23 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD23 				 0x120214
+/* [RW 10] Bandwidth addition to VQ24 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD24 				 0x120218
+/* [RW 10] Bandwidth addition to VQ25 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD25 				 0x12021c
+/* [RW 10] Bandwidth addition to VQ26 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD26 				 0x120220
+/* [RW 10] Bandwidth addition to VQ27 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD27 				 0x120224
+/* [RW 10] Bandwidth addition to VQ4 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD4					 0x1201cc
+/* [RW 10] Bandwidth addition to VQ5 read requests */
+#define PXP2_REG_RQ_BW_RD_ADD5					 0x1201d0
+/* [RW 10] Bandwidth Typical L for VQ0 Read requests */
+#define PXP2_REG_RQ_BW_RD_L0					 0x1202ac
+/* [RW 10] Bandwidth Typical L for VQ12 Read requests */
+#define PXP2_REG_RQ_BW_RD_L12					 0x1202dc
+/* [RW 10] Bandwidth Typical L for VQ13 Read requests */
+#define PXP2_REG_RQ_BW_RD_L13					 0x1202e0
+/* [RW 10] Bandwidth Typical L for VQ14 Read requests */
+#define PXP2_REG_RQ_BW_RD_L14					 0x1202e4
+/* [RW 10] Bandwidth Typical L for VQ15 Read requests */
+#define PXP2_REG_RQ_BW_RD_L15					 0x1202e8
+/* [RW 10] Bandwidth Typical L for VQ16 Read requests */
+#define PXP2_REG_RQ_BW_RD_L16					 0x1202ec
+/* [RW 10] Bandwidth Typical L for VQ17 Read requests */
+#define PXP2_REG_RQ_BW_RD_L17					 0x1202f0
+/* [RW 10] Bandwidth Typical L for VQ18 Read requests */
+#define PXP2_REG_RQ_BW_RD_L18					 0x1202f4
+/* [RW 10] Bandwidth Typical L for VQ19 Read requests */
+#define PXP2_REG_RQ_BW_RD_L19					 0x1202f8
+/* [RW 10] Bandwidth Typical L for VQ20 Read requests */
+#define PXP2_REG_RQ_BW_RD_L20					 0x1202fc
+/* [RW 10] Bandwidth Typical L for VQ22 Read requests */
+#define PXP2_REG_RQ_BW_RD_L22					 0x120300
+/* [RW 10] Bandwidth Typical L for VQ23 Read requests */
+#define PXP2_REG_RQ_BW_RD_L23					 0x120304
+/* [RW 10] Bandwidth Typical L for VQ24 Read requests */
+#define PXP2_REG_RQ_BW_RD_L24					 0x120308
+/* [RW 10] Bandwidth Typical L for VQ25 Read requests */
+#define PXP2_REG_RQ_BW_RD_L25					 0x12030c
+/* [RW 10] Bandwidth Typical L for VQ26 Read requests */
+#define PXP2_REG_RQ_BW_RD_L26					 0x120310
+/* [RW 10] Bandwidth Typical L for VQ27 Read requests */
+#define PXP2_REG_RQ_BW_RD_L27					 0x120314
+/* [RW 10] Bandwidth Typical L for VQ4 Read requests */
+#define PXP2_REG_RQ_BW_RD_L4					 0x1202bc
+/* [RW 10] Bandwidth Typical L for VQ5 Read- currently not used */
+#define PXP2_REG_RQ_BW_RD_L5					 0x1202c0
+/* [RW 7] Bandwidth upper bound for VQ0 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND0				 0x120234
+/* [RW 7] Bandwidth upper bound for VQ12 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND12				 0x120264
+/* [RW 7] Bandwidth upper bound for VQ13 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND13				 0x120268
+/* [RW 7] Bandwidth upper bound for VQ14 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND14				 0x12026c
+/* [RW 7] Bandwidth upper bound for VQ15 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND15				 0x120270
+/* [RW 7] Bandwidth upper bound for VQ16 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND16				 0x120274
+/* [RW 7] Bandwidth upper bound for VQ17 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND17				 0x120278
+/* [RW 7] Bandwidth upper bound for VQ18 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND18				 0x12027c
+/* [RW 7] Bandwidth upper bound for VQ19 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND19				 0x120280
+/* [RW 7] Bandwidth upper bound for VQ20 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND20				 0x120284
+/* [RW 7] Bandwidth upper bound for VQ22 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND22				 0x120288
+/* [RW 7] Bandwidth upper bound for VQ23 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND23				 0x12028c
+/* [RW 7] Bandwidth upper bound for VQ24 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND24				 0x120290
+/* [RW 7] Bandwidth upper bound for VQ25 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND25				 0x120294
+/* [RW 7] Bandwidth upper bound for VQ26 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND26				 0x120298
+/* [RW 7] Bandwidth upper bound for VQ27 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND27				 0x12029c
+/* [RW 7] Bandwidth upper bound for VQ4 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND4				 0x120244
+/* [RW 7] Bandwidth upper bound for VQ5 read requests */
+#define PXP2_REG_RQ_BW_RD_UBOUND5				 0x120248
+/* [RW 10] Bandwidth addition to VQ29 write requests */
+#define PXP2_REG_RQ_BW_WR_ADD29 				 0x12022c
+/* [RW 10] Bandwidth addition to VQ30 write requests */
+#define PXP2_REG_RQ_BW_WR_ADD30 				 0x120230
+/* [RW 10] Bandwidth Typical L for VQ29 Write requests */
+#define PXP2_REG_RQ_BW_WR_L29					 0x12031c
+/* [RW 10] Bandwidth Typical L for VQ30 Write requests */
+#define PXP2_REG_RQ_BW_WR_L30					 0x120320
+/* [RW 7] Bandwidth upper bound for VQ29 */
+#define PXP2_REG_RQ_BW_WR_UBOUND29				 0x1202a4
+/* [RW 7] Bandwidth upper bound for VQ30 */
+#define PXP2_REG_RQ_BW_WR_UBOUND30				 0x1202a8
+/* [RW 2] Endian mode for cdu */
+#define PXP2_REG_RQ_CDU_ENDIAN_M				 0x1201a0
+/* [RW 3] page size in L2P table for CDU module; -4k; -8k; -16k; -32k; -64k;
+   -128k */
+#define PXP2_REG_RQ_CDU_P_SIZE					 0x120018
+/* [R 1] 1' indicates that the requester has finished its internal
+   configuration */
+#define PXP2_REG_RQ_CFG_DONE					 0x1201b4
+/* [RW 2] Endian mode for debug */
+#define PXP2_REG_RQ_DBG_ENDIAN_M				 0x1201a4
+/* [RW 1] When '1'; requests will enter input buffers but wont get out
+   towards the glue */
+#define PXP2_REG_RQ_DISABLE_INPUTS				 0x120330
+/* [RW 2] Endian mode for hc */
+#define PXP2_REG_RQ_HC_ENDIAN_M 				 0x1201a8
+/* [WB 53] Onchip address table */
+#define PXP2_REG_RQ_ONCHIP_AT					 0x122000
+/* [RW 2] Endian mode for qm */
+#define PXP2_REG_RQ_QM_ENDIAN_M 				 0x120194
+/* [RW 3] page size in L2P table for QM module; -4k; -8k; -16k; -32k; -64k;
+   -128k */
+#define PXP2_REG_RQ_QM_P_SIZE					 0x120050
+/* [RW 1] 1' indicates that the RBC has finished configurating the PSWRQ */
+#define PXP2_REG_RQ_RBC_DONE					 0x1201b0
+/* [RW 3] Max burst size filed for read requests port 0; 000 - 128B;
+   001:256B; 010: 512B; 11:1K:100:2K; 01:4K */
+#define PXP2_REG_RQ_RD_MBS0					 0x120160
+/* [RW 2] Endian mode for src */
+#define PXP2_REG_RQ_SRC_ENDIAN_M				 0x12019c
+/* [RW 3] page size in L2P table for SRC module; -4k; -8k; -16k; -32k; -64k;
+   -128k */
+#define PXP2_REG_RQ_SRC_P_SIZE					 0x12006c
+/* [RW 2] Endian mode for tm */
+#define PXP2_REG_RQ_TM_ENDIAN_M 				 0x120198
+/* [RW 3] page size in L2P table for TM module; -4k; -8k; -16k; -32k; -64k;
+   -128k */
+#define PXP2_REG_RQ_TM_P_SIZE					 0x120034
+/* [R 5] Number of entries in the ufifo; his fifo has l2p completions */
+#define PXP2_REG_RQ_UFIFO_NUM_OF_ENTRY				 0x12080c
+/* [R 8] Number of entries occupied by vq 0 in pswrq memory */
+#define PXP2_REG_RQ_VQ0_ENTRY_CNT				 0x120810
+/* [R 8] Number of entries occupied by vq 10 in pswrq memory */
+#define PXP2_REG_RQ_VQ10_ENTRY_CNT				 0x120818
+/* [R 8] Number of entries occupied by vq 11 in pswrq memory */
+#define PXP2_REG_RQ_VQ11_ENTRY_CNT				 0x120820
+/* [R 8] Number of entries occupied by vq 12 in pswrq memory */
+#define PXP2_REG_RQ_VQ12_ENTRY_CNT				 0x120828
+/* [R 8] Number of entries occupied by vq 13 in pswrq memory */
+#define PXP2_REG_RQ_VQ13_ENTRY_CNT				 0x120830
+/* [R 8] Number of entries occupied by vq 14 in pswrq memory */
+#define PXP2_REG_RQ_VQ14_ENTRY_CNT				 0x120838
+/* [R 8] Number of entries occupied by vq 15 in pswrq memory */
+#define PXP2_REG_RQ_VQ15_ENTRY_CNT				 0x120840
+/* [R 8] Number of entries occupied by vq 16 in pswrq memory */
+#define PXP2_REG_RQ_VQ16_ENTRY_CNT				 0x120848
+/* [R 8] Number of entries occupied by vq 17 in pswrq memory */
+#define PXP2_REG_RQ_VQ17_ENTRY_CNT				 0x120850
+/* [R 8] Number of entries occupied by vq 18 in pswrq memory */
+#define PXP2_REG_RQ_VQ18_ENTRY_CNT				 0x120858
+/* [R 8] Number of entries occupied by vq 19 in pswrq memory */
+#define PXP2_REG_RQ_VQ19_ENTRY_CNT				 0x120860
+/* [R 8] Number of entries occupied by vq 1 in pswrq memory */
+#define PXP2_REG_RQ_VQ1_ENTRY_CNT				 0x120868
+/* [R 8] Number of entries occupied by vq 20 in pswrq memory */
+#define PXP2_REG_RQ_VQ20_ENTRY_CNT				 0x120870
+/* [R 8] Number of entries occupied by vq 21 in pswrq memory */
+#define PXP2_REG_RQ_VQ21_ENTRY_CNT				 0x120878
+/* [R 8] Number of entries occupied by vq 22 in pswrq memory */
+#define PXP2_REG_RQ_VQ22_ENTRY_CNT				 0x120880
+/* [R 8] Number of entries occupied by vq 23 in pswrq memory */
+#define PXP2_REG_RQ_VQ23_ENTRY_CNT				 0x120888
+/* [R 8] Number of entries occupied by vq 24 in pswrq memory */
+#define PXP2_REG_RQ_VQ24_ENTRY_CNT				 0x120890
+/* [R 8] Number of entries occupied by vq 25 in pswrq memory */
+#define PXP2_REG_RQ_VQ25_ENTRY_CNT				 0x120898
+/* [R 8] Number of entries occupied by vq 26 in pswrq memory */
+#define PXP2_REG_RQ_VQ26_ENTRY_CNT				 0x1208a0
+/* [R 8] Number of entries occupied by vq 27 in pswrq memory */
+#define PXP2_REG_RQ_VQ27_ENTRY_CNT				 0x1208a8
+/* [R 8] Number of entries occupied by vq 28 in pswrq memory */
+#define PXP2_REG_RQ_VQ28_ENTRY_CNT				 0x1208b0
+/* [R 8] Number of entries occupied by vq 29 in pswrq memory */
+#define PXP2_REG_RQ_VQ29_ENTRY_CNT				 0x1208b8
+/* [R 8] Number of entries occupied by vq 2 in pswrq memory */
+#define PXP2_REG_RQ_VQ2_ENTRY_CNT				 0x1208c0
+/* [R 8] Number of entries occupied by vq 30 in pswrq memory */
+#define PXP2_REG_RQ_VQ30_ENTRY_CNT				 0x1208c8
+/* [R 8] Number of entries occupied by vq 31 in pswrq memory */
+#define PXP2_REG_RQ_VQ31_ENTRY_CNT				 0x1208d0
+/* [R 8] Number of entries occupied by vq 3 in pswrq memory */
+#define PXP2_REG_RQ_VQ3_ENTRY_CNT				 0x1208d8
+/* [R 8] Number of entries occupied by vq 4 in pswrq memory */
+#define PXP2_REG_RQ_VQ4_ENTRY_CNT				 0x1208e0
+/* [R 8] Number of entries occupied by vq 5 in pswrq memory */
+#define PXP2_REG_RQ_VQ5_ENTRY_CNT				 0x1208e8
+/* [R 8] Number of entries occupied by vq 6 in pswrq memory */
+#define PXP2_REG_RQ_VQ6_ENTRY_CNT				 0x1208f0
+/* [R 8] Number of entries occupied by vq 7 in pswrq memory */
+#define PXP2_REG_RQ_VQ7_ENTRY_CNT				 0x1208f8
+/* [R 8] Number of entries occupied by vq 8 in pswrq memory */
+#define PXP2_REG_RQ_VQ8_ENTRY_CNT				 0x120900
+/* [R 8] Number of entries occupied by vq 9 in pswrq memory */
+#define PXP2_REG_RQ_VQ9_ENTRY_CNT				 0x120908
+/* [RW 3] Max burst size filed for write requests port 0; 000 - 128B;
+   001:256B; 010: 512B; */
+#define PXP2_REG_RQ_WR_MBS0					 0x12015c
+/* [RW 10] if Number of entries in dmae fifo will be higer than this
+   threshold then has_payload indication will be asserted; the default value
+   should be equal to &gt;  write MBS size! */
+#define PXP2_REG_WR_DMAE_TH					 0x120368
+/* [R 1] debug only: Indication if PSWHST arbiter is idle */
+#define PXP_REG_HST_ARB_IS_IDLE 				 0x103004
+/* [R 8] debug only: A bit mask for all PSWHST arbiter clients. '1' means
+   this client is waiting for the arbiter. */
+#define PXP_REG_HST_CLIENTS_WAITING_TO_ARB			 0x103008
+/* [WB 160] Used for initialization of the inbound interrupts memory */
+#define PXP_REG_HST_INBOUND_INT 				 0x103800
+/* [RW 32] Interrupt mask register #0 read/write */
+#define PXP_REG_PXP_INT_MASK_0					 0x103074
+#define PXP_REG_PXP_INT_MASK_1					 0x103084
+/* [R 32] Interrupt register #0 read */
+#define PXP_REG_PXP_INT_STS_0					 0x103068
+#define PXP_REG_PXP_INT_STS_1					 0x103078
+/* [RC 32] Interrupt register #0 read clear */
+#define PXP_REG_PXP_INT_STS_CLR_0				 0x10306c
+/* [RW 26] Parity mask register #0 read/write */
+#define PXP_REG_PXP_PRTY_MASK					 0x103094
+/* [RW 4] The activity counter initial increment value sent in the load
+   request */
+#define QM_REG_ACTCTRINITVAL_0					 0x168040
+#define QM_REG_ACTCTRINITVAL_1					 0x168044
+#define QM_REG_ACTCTRINITVAL_2					 0x168048
+#define QM_REG_ACTCTRINITVAL_3					 0x16804c
+/* [RW 32] The base logical address (in bytes) of each physical queue. The
+   index I represents the physical queue number. The 12 lsbs are ignore and
+   considered zero so practically there are only 20 bits in this register. */
+#define QM_REG_BASEADDR 					 0x168900
+/* [RW 16] The byte credit cost for each task. This value is for both ports */
+#define QM_REG_BYTECRDCOST					 0x168234
+/* [RW 16] The initial byte credit value for both ports. */
+#define QM_REG_BYTECRDINITVAL					 0x168238
+/* [RW 32] A bit per physical queue. If the bit is cleared then the physical
+   queue uses port 0 else it uses port 1. */
+#define QM_REG_BYTECRDPORT_LSB					 0x168228
+/* [RW 32] A bit per physical queue. If the bit is cleared then the physical
+   queue uses port 0 else it uses port 1. */
+#define QM_REG_BYTECRDPORT_MSB					 0x168224
+/* [RW 16] The byte credit value that if above the QM is considered almost
+   full */
+#define QM_REG_BYTECREDITAFULLTHR				 0x168094
+/* [RW 4] The initial credit for interface */
+#define QM_REG_CMINITCRD_0					 0x1680cc
+#define QM_REG_CMINITCRD_1					 0x1680d0
+#define QM_REG_CMINITCRD_2					 0x1680d4
+#define QM_REG_CMINITCRD_3					 0x1680d8
+#define QM_REG_CMINITCRD_4					 0x1680dc
+#define QM_REG_CMINITCRD_5					 0x1680e0
+#define QM_REG_CMINITCRD_6					 0x1680e4
+#define QM_REG_CMINITCRD_7					 0x1680e8
+/* [RW 8] A mask bit per CM interface. If this bit is 0 then this interface
+   is masked */
+#define QM_REG_CMINTEN						 0x1680ec
+/* [RW 12] A bit vector which indicates which one of the queues are tied to
+   interface 0 */
+#define QM_REG_CMINTVOQMASK_0					 0x1681f4
+#define QM_REG_CMINTVOQMASK_1					 0x1681f8
+#define QM_REG_CMINTVOQMASK_2					 0x1681fc
+#define QM_REG_CMINTVOQMASK_3					 0x168200
+#define QM_REG_CMINTVOQMASK_4					 0x168204
+#define QM_REG_CMINTVOQMASK_5					 0x168208
+#define QM_REG_CMINTVOQMASK_6					 0x16820c
+#define QM_REG_CMINTVOQMASK_7					 0x168210
+/* [RW 20] The number of connections divided by 16 which dictates the size
+   of each queue per port 0 */
+#define QM_REG_CONNNUM_0					 0x168020
+/* [R 6] Keep the fill level of the fifo from write client 4 */
+#define QM_REG_CQM_WRC_FIFOLVL					 0x168018
+/* [RW 8] The context regions sent in the CFC load request */
+#define QM_REG_CTXREG_0 					 0x168030
+#define QM_REG_CTXREG_1 					 0x168034
+#define QM_REG_CTXREG_2 					 0x168038
+#define QM_REG_CTXREG_3 					 0x16803c
+/* [RW 12] The VOQ mask used to select the VOQs which needs to be full for
+   bypass enable */
+#define QM_REG_ENBYPVOQMASK					 0x16823c
+/* [RW 32] A bit mask per each physical queue. If a bit is set then the
+   physical queue uses the byte credit */
+#define QM_REG_ENBYTECRD_LSB					 0x168220
+/* [RW 32] A bit mask per each physical queue. If a bit is set then the
+   physical queue uses the byte credit */
+#define QM_REG_ENBYTECRD_MSB					 0x16821c
+/* [RW 4] If cleared then the secondary interface will not be served by the
+   RR arbiter */
+#define QM_REG_ENSEC						 0x1680f0
+/* [RW 32] A bit vector per each physical queue which selects which function
+   number to use on PCI access for that queue. */
+#define QM_REG_FUNCNUMSEL_LSB					 0x168230
+/* [RW 32] A bit vector per each physical queue which selects which function
+   number to use on PCI access for that queue. */
+#define QM_REG_FUNCNUMSEL_MSB					 0x16822c
+/* [RW 32] A mask register to mask the Almost empty signals which will not
+   be use for the almost empty indication to the HW block */
+#define QM_REG_HWAEMPTYMASK_LSB 				 0x168218
+/* [RW 32] A mask register to mask the Almost empty signals which will not
+   be use for the almost empty indication to the HW block */
+#define QM_REG_HWAEMPTYMASK_MSB 				 0x168214
+/* [RW 4] The number of outstanding request to CFC */
+#define QM_REG_OUTLDREQ 					 0x168804
+/* [RC 1] A flag to indicate that overflow error occurred in one of the
+   queues. */
+#define QM_REG_OVFERROR 					 0x16805c
+/* [RC 6] the Q were the qverflow occurs */
+#define QM_REG_OVFQNUM						 0x168058
+/* [R 32] Pause state for physical queues 31-0 */
+#define QM_REG_PAUSESTATE0					 0x168410
+/* [R 32] Pause state for physical queues 64-32 */
+#define QM_REG_PAUSESTATE1					 0x168414
+/* [RW 2] The PCI attributes field used in the PCI request. */
+#define QM_REG_PCIREQAT 					 0x168054
+/* [R 16] The byte credit of port 0 */
+#define QM_REG_PORT0BYTECRD					 0x168300
+/* [R 16] The byte credit of port 1 */
+#define QM_REG_PORT1BYTECRD					 0x168304
+/* [WB 54] Pointer Table Memory; The mapping is as follow: ptrtbl[53:30]
+   read pointer; ptrtbl[29:6] write pointer; ptrtbl[5:4] read bank0;
+   ptrtbl[3:2] read bank 1; ptrtbl[1:0] write bank; */
+#define QM_REG_PTRTBL						 0x168a00
+/* [RW 2] Interrupt mask register #0 read/write */
+#define QM_REG_QM_INT_MASK					 0x168444
+/* [R 2] Interrupt register #0 read */
+#define QM_REG_QM_INT_STS					 0x168438
+/* [RW 9] Parity mask register #0 read/write */
+#define QM_REG_QM_PRTY_MASK					 0x168454
+/* [R 32] Current queues in pipeline: Queues from 32 to 63 */
+#define QM_REG_QSTATUS_HIGH					 0x16802c
+/* [R 32] Current queues in pipeline: Queues from 0 to 31 */
+#define QM_REG_QSTATUS_LOW					 0x168028
+/* [R 24] The number of tasks queued for each queue */
+#define QM_REG_QTASKCTR_0					 0x168308
+/* [RW 4] Queue tied to VOQ */
+#define QM_REG_QVOQIDX_0					 0x1680f4
+#define QM_REG_QVOQIDX_10					 0x16811c
+#define QM_REG_QVOQIDX_11					 0x168120
+#define QM_REG_QVOQIDX_12					 0x168124
+#define QM_REG_QVOQIDX_13					 0x168128
+#define QM_REG_QVOQIDX_14					 0x16812c
+#define QM_REG_QVOQIDX_15					 0x168130
+#define QM_REG_QVOQIDX_16					 0x168134
+#define QM_REG_QVOQIDX_17					 0x168138
+#define QM_REG_QVOQIDX_21					 0x168148
+#define QM_REG_QVOQIDX_25					 0x168158
+#define QM_REG_QVOQIDX_29					 0x168168
+#define QM_REG_QVOQIDX_32					 0x168174
+#define QM_REG_QVOQIDX_33					 0x168178
+#define QM_REG_QVOQIDX_34					 0x16817c
+#define QM_REG_QVOQIDX_35					 0x168180
+#define QM_REG_QVOQIDX_36					 0x168184
+#define QM_REG_QVOQIDX_37					 0x168188
+#define QM_REG_QVOQIDX_38					 0x16818c
+#define QM_REG_QVOQIDX_39					 0x168190
+#define QM_REG_QVOQIDX_40					 0x168194
+#define QM_REG_QVOQIDX_41					 0x168198
+#define QM_REG_QVOQIDX_42					 0x16819c
+#define QM_REG_QVOQIDX_43					 0x1681a0
+#define QM_REG_QVOQIDX_44					 0x1681a4
+#define QM_REG_QVOQIDX_45					 0x1681a8
+#define QM_REG_QVOQIDX_46					 0x1681ac
+#define QM_REG_QVOQIDX_47					 0x1681b0
+#define QM_REG_QVOQIDX_48					 0x1681b4
+#define QM_REG_QVOQIDX_49					 0x1681b8
+#define QM_REG_QVOQIDX_5					 0x168108
+#define QM_REG_QVOQIDX_50					 0x1681bc
+#define QM_REG_QVOQIDX_51					 0x1681c0
+#define QM_REG_QVOQIDX_52					 0x1681c4
+#define QM_REG_QVOQIDX_53					 0x1681c8
+#define QM_REG_QVOQIDX_54					 0x1681cc
+#define QM_REG_QVOQIDX_55					 0x1681d0
+#define QM_REG_QVOQIDX_56					 0x1681d4
+#define QM_REG_QVOQIDX_57					 0x1681d8
+#define QM_REG_QVOQIDX_58					 0x1681dc
+#define QM_REG_QVOQIDX_59					 0x1681e0
+#define QM_REG_QVOQIDX_50					 0x1681bc
+#define QM_REG_QVOQIDX_51					 0x1681c0
+#define QM_REG_QVOQIDX_52					 0x1681c4
+#define QM_REG_QVOQIDX_53					 0x1681c8
+#define QM_REG_QVOQIDX_54					 0x1681cc
+#define QM_REG_QVOQIDX_55					 0x1681d0
+#define QM_REG_QVOQIDX_56					 0x1681d4
+#define QM_REG_QVOQIDX_57					 0x1681d8
+#define QM_REG_QVOQIDX_58					 0x1681dc
+#define QM_REG_QVOQIDX_59					 0x1681e0
+#define QM_REG_QVOQIDX_6					 0x16810c
+#define QM_REG_QVOQIDX_60					 0x1681e4
+#define QM_REG_QVOQIDX_61					 0x1681e8
+#define QM_REG_QVOQIDX_62					 0x1681ec
+#define QM_REG_QVOQIDX_63					 0x1681f0
+#define QM_REG_QVOQIDX_60					 0x1681e4
+#define QM_REG_QVOQIDX_61					 0x1681e8
+#define QM_REG_QVOQIDX_62					 0x1681ec
+#define QM_REG_QVOQIDX_63					 0x1681f0
+#define QM_REG_QVOQIDX_7					 0x168110
+#define QM_REG_QVOQIDX_8					 0x168114
+#define QM_REG_QVOQIDX_9					 0x168118
+/* [R 24] Remaining pause timeout for port 0 */
+#define QM_REG_REMAINPAUSETM0					 0x168418
+/* [R 24] Remaining pause timeout for port 1 */
+#define QM_REG_REMAINPAUSETM1					 0x16841c
+/* [RW 1] Initialization bit command */
+#define QM_REG_SOFT_RESET					 0x168428
+/* [RW 8] The credit cost per every task in the QM. A value per each VOQ */
+#define QM_REG_TASKCRDCOST_0					 0x16809c
+#define QM_REG_TASKCRDCOST_1					 0x1680a0
+#define QM_REG_TASKCRDCOST_10					 0x1680c4
+#define QM_REG_TASKCRDCOST_11					 0x1680c8
+#define QM_REG_TASKCRDCOST_2					 0x1680a4
+#define QM_REG_TASKCRDCOST_4					 0x1680ac
+#define QM_REG_TASKCRDCOST_5					 0x1680b0
+/* [R 6] Keep the fill level of the fifo from write client 3 */
+#define QM_REG_TQM_WRC_FIFOLVL					 0x168010
+/* [R 6] Keep the fill level of the fifo from write client 2 */
+#define QM_REG_UQM_WRC_FIFOLVL					 0x168008
+/* [RC 32] Credit update error register */
+#define QM_REG_VOQCRDERRREG					 0x168408
+/* [R 16] The credit value for each VOQ */
+#define QM_REG_VOQCREDIT_0					 0x1682d0
+#define QM_REG_VOQCREDIT_1					 0x1682d4
+#define QM_REG_VOQCREDIT_10					 0x1682f8
+#define QM_REG_VOQCREDIT_11					 0x1682fc
+#define QM_REG_VOQCREDIT_4					 0x1682e0
+/* [RW 16] The credit value that if above the QM is considered almost full */
+#define QM_REG_VOQCREDITAFULLTHR				 0x168090
+/* [RW 16] The init and maximum credit for each VoQ */
+#define QM_REG_VOQINITCREDIT_0					 0x168060
+#define QM_REG_VOQINITCREDIT_1					 0x168064
+#define QM_REG_VOQINITCREDIT_10 				 0x168088
+#define QM_REG_VOQINITCREDIT_11 				 0x16808c
+#define QM_REG_VOQINITCREDIT_2					 0x168068
+#define QM_REG_VOQINITCREDIT_4					 0x168070
+#define QM_REG_VOQINITCREDIT_5					 0x168074
+/* [RW 1] The port of which VOQ belongs */
+#define QM_REG_VOQPORT_1					 0x1682a4
+#define QM_REG_VOQPORT_10					 0x1682c8
+#define QM_REG_VOQPORT_11					 0x1682cc
+#define QM_REG_VOQPORT_2					 0x1682a8
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_0_LSB					 0x168240
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_0_MSB					 0x168244
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_1_MSB					 0x16824c
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_2_LSB					 0x168250
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_2_MSB					 0x168254
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_3_LSB					 0x168258
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_4_LSB					 0x168260
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_4_MSB					 0x168264
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_5_LSB					 0x168268
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_5_MSB					 0x16826c
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_6_LSB					 0x168270
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_6_MSB					 0x168274
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_7_LSB					 0x168278
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_7_MSB					 0x16827c
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_8_LSB					 0x168280
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_8_MSB					 0x168284
+/* [RW 32] The physical queue number associated with each VOQ */
+#define QM_REG_VOQQMASK_9_LSB					 0x168288
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_0					 0x16880c
+#define QM_REG_WRRWEIGHTS_1					 0x168810
+#define QM_REG_WRRWEIGHTS_10					 0x168814
+#define QM_REG_WRRWEIGHTS_10_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_11					 0x168818
+#define QM_REG_WRRWEIGHTS_11_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_12					 0x16881c
+#define QM_REG_WRRWEIGHTS_12_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_13					 0x168820
+#define QM_REG_WRRWEIGHTS_13_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_14					 0x168824
+#define QM_REG_WRRWEIGHTS_14_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_15					 0x168828
+#define QM_REG_WRRWEIGHTS_15_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_10					 0x168814
+#define QM_REG_WRRWEIGHTS_11					 0x168818
+#define QM_REG_WRRWEIGHTS_12					 0x16881c
+#define QM_REG_WRRWEIGHTS_13					 0x168820
+#define QM_REG_WRRWEIGHTS_14					 0x168824
+#define QM_REG_WRRWEIGHTS_15					 0x168828
+#define QM_REG_WRRWEIGHTS_2					 0x16882c
+#define QM_REG_WRRWEIGHTS_3					 0x168830
+#define QM_REG_WRRWEIGHTS_4					 0x168834
+#define QM_REG_WRRWEIGHTS_5					 0x168838
+#define QM_REG_WRRWEIGHTS_6					 0x16883c
+#define QM_REG_WRRWEIGHTS_7					 0x168840
+#define QM_REG_WRRWEIGHTS_8					 0x168844
+#define QM_REG_WRRWEIGHTS_9					 0x168848
+/* [R 6] Keep the fill level of the fifo from write client 1 */
+#define QM_REG_XQM_WRC_FIFOLVL					 0x168000
+#define DORQ_DORQ_INT_STS_REG_ADDRESS_ERROR			 (0x1<<0)
+#define DORQ_DORQ_INT_STS_REG_ADDRESS_ERROR_SIZE		 0
+#define DORQ_DORQ_INT_STS_CLR_REG_ADDRESS_ERROR 		 (0x1<<0)
+#define DORQ_DORQ_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE		 0
+#define DORQ_DORQ_INT_STS_WR_REG_ADDRESS_ERROR			 (0x1<<0)
+#define DORQ_DORQ_INT_STS_WR_REG_ADDRESS_ERROR_SIZE		 0
+#define DORQ_DORQ_INT_MASK_REG_ADDRESS_ERROR			 (0x1<<0)
+#define DORQ_DORQ_INT_MASK_REG_ADDRESS_ERROR_SIZE		 0
+#define NIG_NIG_INT_STS_0_REG_ADDRESS_ERROR			 (0x1<<0)
+#define NIG_NIG_INT_STS_0_REG_ADDRESS_ERROR_SIZE		 0
+#define NIG_NIG_INT_STS_CLR_0_REG_ADDRESS_ERROR 		 (0x1<<0)
+#define NIG_NIG_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE		 0
+#define NIG_NIG_INT_STS_WR_0_REG_ADDRESS_ERROR			 (0x1<<0)
+#define NIG_NIG_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE		 0
+#define NIG_NIG_INT_MASK_0_REG_ADDRESS_ERROR			 (0x1<<0)
+#define NIG_NIG_INT_MASK_0_REG_ADDRESS_ERROR_SIZE		 0
+#define TCM_TCM_INT_STS_REG_ADDRESS_ERROR			 (0x1<<0)
+#define TCM_TCM_INT_STS_REG_ADDRESS_ERROR_SIZE			 0
+#define TCM_TCM_INT_STS_CLR_REG_ADDRESS_ERROR			 (0x1<<0)
+#define TCM_TCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE		 0
+#define TCM_TCM_INT_STS_WR_REG_ADDRESS_ERROR			 (0x1<<0)
+#define TCM_TCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE		 0
+#define TCM_TCM_INT_MASK_REG_ADDRESS_ERROR			 (0x1<<0)
+#define TCM_TCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 		 0
+#define CFC_DEBUG1_REG_WRITE_AC 				 (0x1<<4)
+#define CFC_DEBUG1_REG_WRITE_AC_SIZE				 4
+/* [R 1] debug only: This bit indicates wheter indicates that external
+   buffer was wrapped (oldest data was thrown); Relevant only when
+   ~dbg_registers_debug_target=2 (PCI) & ~dbg_registers_full_mode=1 (wrap); */
+#define DBG_REG_WRAP_ON_EXT_BUFFER				 0xc124
+#define DBG_REG_WRAP_ON_EXT_BUFFER_SIZE 			 1
+/* [R 1] debug only: This bit indicates wheter the internal buffer was
+   wrapped (oldest data was thrown) Relevant only when
+   ~dbg_registers_debug_target=0 (internal buffer) */
+#define DBG_REG_WRAP_ON_INT_BUFFER				 0xc128
+#define DBG_REG_WRAP_ON_INT_BUFFER_SIZE 			 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_0					 0x16880c
+#define QM_REG_WRRWEIGHTS_0_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_1					 0x168810
+#define QM_REG_WRRWEIGHTS_1_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_10					 0x168814
+#define QM_REG_WRRWEIGHTS_10_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_11					 0x168818
+#define QM_REG_WRRWEIGHTS_11_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_12					 0x16881c
+#define QM_REG_WRRWEIGHTS_12_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_13					 0x168820
+#define QM_REG_WRRWEIGHTS_13_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_14					 0x168824
+#define QM_REG_WRRWEIGHTS_14_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_15					 0x168828
+#define QM_REG_WRRWEIGHTS_15_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_2					 0x16882c
+#define QM_REG_WRRWEIGHTS_2_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_3					 0x168830
+#define QM_REG_WRRWEIGHTS_3_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_4					 0x168834
+#define QM_REG_WRRWEIGHTS_4_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_5					 0x168838
+#define QM_REG_WRRWEIGHTS_5_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_6					 0x16883c
+#define QM_REG_WRRWEIGHTS_6_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_7					 0x168840
+#define QM_REG_WRRWEIGHTS_7_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_8					 0x168844
+#define QM_REG_WRRWEIGHTS_8_SIZE				 1
+/* [RW 32] Wrr weights */
+#define QM_REG_WRRWEIGHTS_9					 0x168848
+#define QM_REG_WRRWEIGHTS_9_SIZE				 1
+/* [RW 22] Number of free element in the free list of T2 entries - port 0. */
+#define SRC_REG_COUNTFREE0					 0x40500
+/* [WB 64] First free element in the free list of T2 entries - port 0. */
+#define SRC_REG_FIRSTFREE0					 0x40510
+#define SRC_REG_KEYRSS0_0					 0x40408
+#define SRC_REG_KEYRSS1_9					 0x40454
+/* [WB 64] Last free element in the free list of T2 entries - port 0. */
+#define SRC_REG_LASTFREE0					 0x40530
+/* [RW 5] The number of hash bits used for the search (h); Values can be 8
+   to 24. */
+#define SRC_REG_NUMBER_HASH_BITS0				 0x40400
+/* [RW 1] Reset internal state machines. */
+#define SRC_REG_SOFT_RST					 0x4049c
+/* [R 1] Interrupt register #0 read */
+#define SRC_REG_SRC_INT_STS					 0x404ac
+/* [RW 3] Parity mask register #0 read/write */
+#define SRC_REG_SRC_PRTY_MASK					 0x404c8
+/* [R 4] Used to read the value of the XX protection CAM occupancy counter. */
+#define TCM_REG_CAM_OCCUP					 0x5017c
+/* [RW 1] CDU AG read Interface enable. If 0 - the request input is
+   disregarded; valid output is deasserted; all other signals are treated as
+   usual; if 1 - normal activity. */
+#define TCM_REG_CDU_AG_RD_IFEN					 0x50034
+/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input
+   are disregarded; all other signals are treated as usual; if 1 - normal
+   activity. */
+#define TCM_REG_CDU_AG_WR_IFEN					 0x50030
+/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is
+   disregarded; valid output is deasserted; all other signals are treated as
+   usual; if 1 - normal activity. */
+#define TCM_REG_CDU_SM_RD_IFEN					 0x5003c
+/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid
+   input is disregarded; all other signals are treated as usual; if 1 -
+   normal activity. */
+#define TCM_REG_CDU_SM_WR_IFEN					 0x50038
+/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes
+   the initial credit value; read returns the current value of the credit
+   counter. Must be initialized to 1 at start-up. */
+#define TCM_REG_CFC_INIT_CRD					 0x50204
+/* [RW 3] The weight of the CP input in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define TCM_REG_CP_WEIGHT					 0x500c0
+/* [RW 1] Input csem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define TCM_REG_CSEM_IFEN					 0x5002c
+/* [RC 1] Message length mismatch (relative to last indication) at the In#9
+   interface. */
+#define TCM_REG_CSEM_LENGTH_MIS 				 0x50174
+/* [RW 8] The Event ID in case of ErrorFlg is set in the input message. */
+#define TCM_REG_ERR_EVNT_ID					 0x500a0
+/* [RW 28] The CM erroneous header for QM and Timers formatting. */
+#define TCM_REG_ERR_TCM_HDR					 0x5009c
+/* [RW 8] The Event ID for Timers expiration. */
+#define TCM_REG_EXPR_EVNT_ID					 0x500a4
+/* [RW 8] FIC0 output initial credit. Max credit available - 255.Write
+   writes the initial credit value; read returns the current value of the
+   credit counter. Must be initialized to 64 at start-up. */
+#define TCM_REG_FIC0_INIT_CRD					 0x5020c
+/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write
+   writes the initial credit value; read returns the current value of the
+   credit counter. Must be initialized to 64 at start-up. */
+#define TCM_REG_FIC1_INIT_CRD					 0x50210
+/* [RW 1] Arbitration between Input Arbiter groups: 0 - fair Round-Robin; 1
+   - strict priority defined by ~tcm_registers_gr_ag_pr.gr_ag_pr;
+   ~tcm_registers_gr_ld0_pr.gr_ld0_pr and
+   ~tcm_registers_gr_ld1_pr.gr_ld1_pr. */
+#define TCM_REG_GR_ARB_TYPE					 0x50114
+/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the
+   highest priority is 3. It is supposed that the Store channel is the
+   compliment of the other 3 groups. */
+#define TCM_REG_GR_LD0_PR					 0x5011c
+/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the
+   highest priority is 3. It is supposed that the Store channel is the
+   compliment of the other 3 groups. */
+#define TCM_REG_GR_LD1_PR					 0x50120
+/* [RW 4] The number of double REG-pairs; loaded from the STORM context and
+   sent to STORM; for a specific connection type. The double REG-pairs are
+   used to align to STORM context row size of 128 bits. The offset of these
+   data in the STORM context is always 0. Index _i stands for the connection
+   type (one of 16). */
+#define TCM_REG_N_SM_CTX_LD_0					 0x50050
+#define TCM_REG_N_SM_CTX_LD_1					 0x50054
+#define TCM_REG_N_SM_CTX_LD_10					 0x50078
+#define TCM_REG_N_SM_CTX_LD_11					 0x5007c
+#define TCM_REG_N_SM_CTX_LD_12					 0x50080
+#define TCM_REG_N_SM_CTX_LD_13					 0x50084
+#define TCM_REG_N_SM_CTX_LD_14					 0x50088
+#define TCM_REG_N_SM_CTX_LD_15					 0x5008c
+#define TCM_REG_N_SM_CTX_LD_2					 0x50058
+#define TCM_REG_N_SM_CTX_LD_3					 0x5005c
+#define TCM_REG_N_SM_CTX_LD_4					 0x50060
+/* [RW 1] Input pbf Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define TCM_REG_PBF_IFEN					 0x50024
+/* [RC 1] Message length mismatch (relative to last indication) at the In#7
+   interface. */
+#define TCM_REG_PBF_LENGTH_MIS					 0x5016c
+/* [RW 3] The weight of the input pbf in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define TCM_REG_PBF_WEIGHT					 0x500b4
+/* [RW 6] The physical queue number 0 per port index. */
+#define TCM_REG_PHYS_QNUM0_0					 0x500e0
+#define TCM_REG_PHYS_QNUM0_1					 0x500e4
+/* [RW 6] The physical queue number 1 per port index. */
+#define TCM_REG_PHYS_QNUM1_0					 0x500e8
+/* [RW 1] Input prs Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define TCM_REG_PRS_IFEN					 0x50020
+/* [RC 1] Message length mismatch (relative to last indication) at the In#6
+   interface. */
+#define TCM_REG_PRS_LENGTH_MIS					 0x50168
+/* [RW 3] The weight of the input prs in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define TCM_REG_PRS_WEIGHT					 0x500b0
+/* [RW 8] The Event ID for Timers formatting in case of stop done. */
+#define TCM_REG_STOP_EVNT_ID					 0x500a8
+/* [RC 1] Message length mismatch (relative to last indication) at the STORM
+   interface. */
+#define TCM_REG_STORM_LENGTH_MIS				 0x50160
+/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define TCM_REG_STORM_TCM_IFEN					 0x50010
+/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define TCM_REG_TCM_CFC_IFEN					 0x50040
+/* [RW 11] Interrupt mask register #0 read/write */
+#define TCM_REG_TCM_INT_MASK					 0x501dc
+/* [R 11] Interrupt register #0 read */
+#define TCM_REG_TCM_INT_STS					 0x501d0
+/* [RW 3] The size of AG context region 0 in REG-pairs. Designates the MS
+   REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5).
+   Is used to determine the number of the AG context REG-pairs written back;
+   when the input message Reg1WbFlg isn't set. */
+#define TCM_REG_TCM_REG0_SZ					 0x500d8
+/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define TCM_REG_TCM_STORM0_IFEN 				 0x50004
+/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define TCM_REG_TCM_STORM1_IFEN 				 0x50008
+/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define TCM_REG_TCM_TQM_IFEN					 0x5000c
+/* [RW 1] If set the Q index; received from the QM is inserted to event ID. */
+#define TCM_REG_TCM_TQM_USE_Q					 0x500d4
+/* [RW 28] The CM header for Timers expiration command. */
+#define TCM_REG_TM_TCM_HDR					 0x50098
+/* [RW 1] Timers - CM Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define TCM_REG_TM_TCM_IFEN					 0x5001c
+/* [RW 6] QM output initial credit. Max credit available - 32.Write writes
+   the initial credit value; read returns the current value of the credit
+   counter. Must be initialized to 32 at start-up. */
+#define TCM_REG_TQM_INIT_CRD					 0x5021c
+/* [RW 28] The CM header value for QM request (primary). */
+#define TCM_REG_TQM_TCM_HDR_P					 0x50090
+/* [RW 28] The CM header value for QM request (secondary). */
+#define TCM_REG_TQM_TCM_HDR_S					 0x50094
+/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define TCM_REG_TQM_TCM_IFEN					 0x50014
+/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define TCM_REG_TSDM_IFEN					 0x50018
+/* [RC 1] Message length mismatch (relative to last indication) at the SDM
+   interface. */
+#define TCM_REG_TSDM_LENGTH_MIS 				 0x50164
+/* [RW 3] The weight of the SDM input in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define TCM_REG_TSDM_WEIGHT					 0x500c4
+/* [RW 1] Input usem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define TCM_REG_USEM_IFEN					 0x50028
+/* [RC 1] Message length mismatch (relative to last indication) at the In#8
+   interface. */
+#define TCM_REG_USEM_LENGTH_MIS 				 0x50170
+/* [RW 21] Indirect access to the descriptor table of the XX protection
+   mechanism. The fields are: [5:0] - length of the message; 15:6] - message
+   pointer; 20:16] - next pointer. */
+#define TCM_REG_XX_DESCR_TABLE					 0x50280
+/* [R 6] Use to read the value of XX protection Free counter. */
+#define TCM_REG_XX_FREE 					 0x50178
+/* [RW 6] Initial value for the credit counter; responsible for fulfilling
+   of the Input Stage XX protection buffer by the XX protection pending
+   messages. Max credit available - 127.Write writes the initial credit
+   value; read returns the current value of the credit counter. Must be
+   initialized to 19 at start-up. */
+#define TCM_REG_XX_INIT_CRD					 0x50220
+/* [RW 6] Maximum link list size (messages locked) per connection in the XX
+   protection. */
+#define TCM_REG_XX_MAX_LL_SZ					 0x50044
+/* [RW 6] The maximum number of pending messages; which may be stored in XX
+   protection. ~tcm_registers_xx_free.xx_free is read on read. */
+#define TCM_REG_XX_MSG_NUM					 0x50224
+/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */
+#define TCM_REG_XX_OVFL_EVNT_ID 				 0x50048
+/* [RW 16] Indirect access to the XX table of the XX protection mechanism.
+   The fields are:[4:0] - tail pointer; [10:5] - Link List size; 15:11] -
+   header pointer. */
+#define TCM_REG_XX_TABLE					 0x50240
+/* [RW 4] Load value for for cfc ac credit cnt. */
+#define TM_REG_CFC_AC_CRDCNT_VAL				 0x164208
+/* [RW 4] Load value for cfc cld credit cnt. */
+#define TM_REG_CFC_CLD_CRDCNT_VAL				 0x164210
+/* [RW 8] Client0 context region. */
+#define TM_REG_CL0_CONT_REGION					 0x164030
+/* [RW 8] Client1 context region. */
+#define TM_REG_CL1_CONT_REGION					 0x164034
+/* [RW 8] Client2 context region. */
+#define TM_REG_CL2_CONT_REGION					 0x164038
+/* [RW 2] Client in High priority client number. */
+#define TM_REG_CLIN_PRIOR0_CLIENT				 0x164024
+/* [RW 4] Load value for clout0 cred cnt. */
+#define TM_REG_CLOUT_CRDCNT0_VAL				 0x164220
+/* [RW 4] Load value for clout1 cred cnt. */
+#define TM_REG_CLOUT_CRDCNT1_VAL				 0x164228
+/* [RW 4] Load value for clout2 cred cnt. */
+#define TM_REG_CLOUT_CRDCNT2_VAL				 0x164230
+/* [RW 1] Enable client0 input. */
+#define TM_REG_EN_CL0_INPUT					 0x164008
+/* [RW 1] Enable client1 input. */
+#define TM_REG_EN_CL1_INPUT					 0x16400c
+/* [RW 1] Enable client2 input. */
+#define TM_REG_EN_CL2_INPUT					 0x164010
+/* [RW 1] Enable real time counter. */
+#define TM_REG_EN_REAL_TIME_CNT 				 0x1640d8
+/* [RW 1] Enable for Timers state machines. */
+#define TM_REG_EN_TIMERS					 0x164000
+/* [RW 4] Load value for expiration credit cnt. CFC max number of
+   outstanding load requests for timers (expiration) context loading. */
+#define TM_REG_EXP_CRDCNT_VAL					 0x164238
+/* [RW 18] Linear0 Max active cid. */
+#define TM_REG_LIN0_MAX_ACTIVE_CID				 0x164048
+/* [WB 64] Linear0 phy address. */
+#define TM_REG_LIN0_PHY_ADDR					 0x164270
+/* [RW 24] Linear0 array scan timeout. */
+#define TM_REG_LIN0_SCAN_TIME					 0x16403c
+/* [WB 64] Linear1 phy address. */
+#define TM_REG_LIN1_PHY_ADDR					 0x164280
+/* [RW 6] Linear timer set_clear fifo threshold. */
+#define TM_REG_LIN_SETCLR_FIFO_ALFULL_THR			 0x164070
+/* [RW 2] Load value for pci arbiter credit cnt. */
+#define TM_REG_PCIARB_CRDCNT_VAL				 0x164260
+/* [RW 1] Timer software reset - active high. */
+#define TM_REG_TIMER_SOFT_RST					 0x164004
+/* [RW 20] The amount of hardware cycles for each timer tick. */
+#define TM_REG_TIMER_TICK_SIZE					 0x16401c
+/* [RW 8] Timers Context region. */
+#define TM_REG_TM_CONTEXT_REGION				 0x164044
+/* [RW 1] Interrupt mask register #0 read/write */
+#define TM_REG_TM_INT_MASK					 0x1640fc
+/* [R 1] Interrupt register #0 read */
+#define TM_REG_TM_INT_STS					 0x1640f0
+/* [RW 8] The event id for aggregated interrupt 0 */
+#define TSDM_REG_AGG_INT_EVENT_0				 0x42038
+/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */
+#define TSDM_REG_CFC_RSP_START_ADDR				 0x42008
+/* [RW 16] The maximum value of the competion counter #0 */
+#define TSDM_REG_CMP_COUNTER_MAX0				 0x4201c
+/* [RW 16] The maximum value of the competion counter #1 */
+#define TSDM_REG_CMP_COUNTER_MAX1				 0x42020
+/* [RW 16] The maximum value of the competion counter #2 */
+#define TSDM_REG_CMP_COUNTER_MAX2				 0x42024
+/* [RW 16] The maximum value of the competion counter #3 */
+#define TSDM_REG_CMP_COUNTER_MAX3				 0x42028
+/* [RW 13] The start address in the internal RAM for the completion
+   counters. */
+#define TSDM_REG_CMP_COUNTER_START_ADDR 			 0x4200c
+#define TSDM_REG_ENABLE_IN1					 0x42238
+#define TSDM_REG_ENABLE_IN2					 0x4223c
+#define TSDM_REG_ENABLE_OUT1					 0x42240
+#define TSDM_REG_ENABLE_OUT2					 0x42244
+/* [RW 4] The initial number of messages that can be sent to the pxp control
+   interface without receiving any ACK. */
+#define TSDM_REG_INIT_CREDIT_PXP_CTRL				 0x424bc
+/* [ST 32] The number of ACK after placement messages received */
+#define TSDM_REG_NUM_OF_ACK_AFTER_PLACE 			 0x4227c
+/* [ST 32] The number of packet end messages received from the parser */
+#define TSDM_REG_NUM_OF_PKT_END_MSG				 0x42274
+/* [ST 32] The number of requests received from the pxp async if */
+#define TSDM_REG_NUM_OF_PXP_ASYNC_REQ				 0x42278
+/* [ST 32] The number of commands received in queue 0 */
+#define TSDM_REG_NUM_OF_Q0_CMD					 0x42248
+/* [ST 32] The number of commands received in queue 10 */
+#define TSDM_REG_NUM_OF_Q10_CMD 				 0x4226c
+/* [ST 32] The number of commands received in queue 11 */
+#define TSDM_REG_NUM_OF_Q11_CMD 				 0x42270
+/* [ST 32] The number of commands received in queue 1 */
+#define TSDM_REG_NUM_OF_Q1_CMD					 0x4224c
+/* [ST 32] The number of commands received in queue 3 */
+#define TSDM_REG_NUM_OF_Q3_CMD					 0x42250
+/* [ST 32] The number of commands received in queue 4 */
+#define TSDM_REG_NUM_OF_Q4_CMD					 0x42254
+/* [ST 32] The number of commands received in queue 5 */
+#define TSDM_REG_NUM_OF_Q5_CMD					 0x42258
+/* [ST 32] The number of commands received in queue 6 */
+#define TSDM_REG_NUM_OF_Q6_CMD					 0x4225c
+/* [ST 32] The number of commands received in queue 7 */
+#define TSDM_REG_NUM_OF_Q7_CMD					 0x42260
+/* [ST 32] The number of commands received in queue 8 */
+#define TSDM_REG_NUM_OF_Q8_CMD					 0x42264
+/* [ST 32] The number of commands received in queue 9 */
+#define TSDM_REG_NUM_OF_Q9_CMD					 0x42268
+/* [RW 13] The start address in the internal RAM for the packet end message */
+#define TSDM_REG_PCK_END_MSG_START_ADDR 			 0x42014
+/* [RW 13] The start address in the internal RAM for queue counters */
+#define TSDM_REG_Q_COUNTER_START_ADDR				 0x42010
+/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */
+#define TSDM_REG_RSP_PXP_CTRL_RDATA_EMPTY			 0x42548
+/* [R 1] parser fifo empty in sdm_sync block */
+#define TSDM_REG_SYNC_PARSER_EMPTY				 0x42550
+/* [R 1] parser serial fifo empty in sdm_sync block */
+#define TSDM_REG_SYNC_SYNC_EMPTY				 0x42558
+/* [RW 32] Tick for timer counter. Applicable only when
+   ~tsdm_registers_timer_tick_enable.timer_tick_enable =1 */
+#define TSDM_REG_TIMER_TICK					 0x42000
+/* [RW 32] Interrupt mask register #0 read/write */
+#define TSDM_REG_TSDM_INT_MASK_0				 0x4229c
+#define TSDM_REG_TSDM_INT_MASK_1				 0x422ac
+/* [RW 11] Parity mask register #0 read/write */
+#define TSDM_REG_TSDM_PRTY_MASK 				 0x422bc
+/* [RW 5] The number of time_slots in the arbitration cycle */
+#define TSEM_REG_ARB_CYCLE_SIZE 				 0x180034
+/* [RW 3] The source that is associated with arbitration element 0. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2 */
+#define TSEM_REG_ARB_ELEMENT0					 0x180020
+/* [RW 3] The source that is associated with arbitration element 1. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~tsem_registers_arb_element0.arb_element0 */
+#define TSEM_REG_ARB_ELEMENT1					 0x180024
+/* [RW 3] The source that is associated with arbitration element 2. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~tsem_registers_arb_element0.arb_element0
+   and ~tsem_registers_arb_element1.arb_element1 */
+#define TSEM_REG_ARB_ELEMENT2					 0x180028
+/* [RW 3] The source that is associated with arbitration element 3. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.Could
+   not be equal to register ~tsem_registers_arb_element0.arb_element0 and
+   ~tsem_registers_arb_element1.arb_element1 and
+   ~tsem_registers_arb_element2.arb_element2 */
+#define TSEM_REG_ARB_ELEMENT3					 0x18002c
+/* [RW 3] The source that is associated with arbitration element 4. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~tsem_registers_arb_element0.arb_element0
+   and ~tsem_registers_arb_element1.arb_element1 and
+   ~tsem_registers_arb_element2.arb_element2 and
+   ~tsem_registers_arb_element3.arb_element3 */
+#define TSEM_REG_ARB_ELEMENT4					 0x180030
+#define TSEM_REG_ENABLE_IN					 0x1800a4
+#define TSEM_REG_ENABLE_OUT					 0x1800a8
+/* [RW 32] This address space contains all registers and memories that are
+   placed in SEM_FAST block. The SEM_FAST registers are described in
+   appendix B. In order to access the SEM_FAST registers the base address
+   TSEM_REGISTERS_FAST_MEMORY (Offset: 0x1a0000) should be added to each
+   SEM_FAST register offset. */
+#define TSEM_REG_FAST_MEMORY					 0x1a0000
+/* [RW 1] Disables input messages from FIC0 May be updated during run_time
+   by the microcode */
+#define TSEM_REG_FIC0_DISABLE					 0x180224
+/* [RW 1] Disables input messages from FIC1 May be updated during run_time
+   by the microcode */
+#define TSEM_REG_FIC1_DISABLE					 0x180234
+/* [RW 15] Interrupt table Read and write access to it is not possible in
+   the middle of the work */
+#define TSEM_REG_INT_TABLE					 0x180400
+/* [ST 24] Statistics register. The number of messages that entered through
+   FIC0 */
+#define TSEM_REG_MSG_NUM_FIC0					 0x180000
+/* [ST 24] Statistics register. The number of messages that entered through
+   FIC1 */
+#define TSEM_REG_MSG_NUM_FIC1					 0x180004
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC0 */
+#define TSEM_REG_MSG_NUM_FOC0					 0x180008
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC1 */
+#define TSEM_REG_MSG_NUM_FOC1					 0x18000c
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC2 */
+#define TSEM_REG_MSG_NUM_FOC2					 0x180010
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC3 */
+#define TSEM_REG_MSG_NUM_FOC3					 0x180014
+/* [RW 1] Disables input messages from the passive buffer May be updated
+   during run_time by the microcode */
+#define TSEM_REG_PAS_DISABLE					 0x18024c
+/* [WB 128] Debug only. Passive buffer memory */
+#define TSEM_REG_PASSIVE_BUFFER 				 0x181000
+/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */
+#define TSEM_REG_PRAM						 0x1c0000
+/* [R 8] Valid sleeping threads indication have bit per thread */
+#define TSEM_REG_SLEEP_THREADS_VALID				 0x18026c
+/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */
+#define TSEM_REG_SLOW_EXT_STORE_EMPTY				 0x1802a0
+/* [RW 8] List of free threads . There is a bit per thread. */
+#define TSEM_REG_THREADS_LIST					 0x1802e4
+/* [RW 3] The arbitration scheme of time_slot 0 */
+#define TSEM_REG_TS_0_AS					 0x180038
+/* [RW 3] The arbitration scheme of time_slot 10 */
+#define TSEM_REG_TS_10_AS					 0x180060
+/* [RW 3] The arbitration scheme of time_slot 11 */
+#define TSEM_REG_TS_11_AS					 0x180064
+/* [RW 3] The arbitration scheme of time_slot 12 */
+#define TSEM_REG_TS_12_AS					 0x180068
+/* [RW 3] The arbitration scheme of time_slot 13 */
+#define TSEM_REG_TS_13_AS					 0x18006c
+/* [RW 3] The arbitration scheme of time_slot 14 */
+#define TSEM_REG_TS_14_AS					 0x180070
+/* [RW 3] The arbitration scheme of time_slot 15 */
+#define TSEM_REG_TS_15_AS					 0x180074
+/* [RW 3] The arbitration scheme of time_slot 16 */
+#define TSEM_REG_TS_16_AS					 0x180078
+/* [RW 3] The arbitration scheme of time_slot 17 */
+#define TSEM_REG_TS_17_AS					 0x18007c
+/* [RW 3] The arbitration scheme of time_slot 18 */
+#define TSEM_REG_TS_18_AS					 0x180080
+/* [RW 3] The arbitration scheme of time_slot 1 */
+#define TSEM_REG_TS_1_AS					 0x18003c
+/* [RW 3] The arbitration scheme of time_slot 2 */
+#define TSEM_REG_TS_2_AS					 0x180040
+/* [RW 3] The arbitration scheme of time_slot 3 */
+#define TSEM_REG_TS_3_AS					 0x180044
+/* [RW 3] The arbitration scheme of time_slot 4 */
+#define TSEM_REG_TS_4_AS					 0x180048
+/* [RW 3] The arbitration scheme of time_slot 5 */
+#define TSEM_REG_TS_5_AS					 0x18004c
+/* [RW 3] The arbitration scheme of time_slot 6 */
+#define TSEM_REG_TS_6_AS					 0x180050
+/* [RW 3] The arbitration scheme of time_slot 7 */
+#define TSEM_REG_TS_7_AS					 0x180054
+/* [RW 3] The arbitration scheme of time_slot 8 */
+#define TSEM_REG_TS_8_AS					 0x180058
+/* [RW 3] The arbitration scheme of time_slot 9 */
+#define TSEM_REG_TS_9_AS					 0x18005c
+/* [RW 32] Interrupt mask register #0 read/write */
+#define TSEM_REG_TSEM_INT_MASK_0				 0x180100
+#define TSEM_REG_TSEM_INT_MASK_1				 0x180110
+/* [RW 32] Parity mask register #0 read/write */
+#define TSEM_REG_TSEM_PRTY_MASK_0				 0x180120
+#define TSEM_REG_TSEM_PRTY_MASK_1				 0x180130
+/* [R 5] Used to read the XX protection CAM occupancy counter. */
+#define UCM_REG_CAM_OCCUP					 0xe0170
+/* [RW 1] CDU AG read Interface enable. If 0 - the request input is
+   disregarded; valid output is deasserted; all other signals are treated as
+   usual; if 1 - normal activity. */
+#define UCM_REG_CDU_AG_RD_IFEN					 0xe0038
+/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input
+   are disregarded; all other signals are treated as usual; if 1 - normal
+   activity. */
+#define UCM_REG_CDU_AG_WR_IFEN					 0xe0034
+/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is
+   disregarded; valid output is deasserted; all other signals are treated as
+   usual; if 1 - normal activity. */
+#define UCM_REG_CDU_SM_RD_IFEN					 0xe0040
+/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid
+   input is disregarded; all other signals are treated as usual; if 1 -
+   normal activity. */
+#define UCM_REG_CDU_SM_WR_IFEN					 0xe003c
+/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes
+   the initial credit value; read returns the current value of the credit
+   counter. Must be initialized to 1 at start-up. */
+#define UCM_REG_CFC_INIT_CRD					 0xe0204
+/* [RW 3] The weight of the CP input in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define UCM_REG_CP_WEIGHT					 0xe00c4
+/* [RW 1] Input csem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define UCM_REG_CSEM_IFEN					 0xe0028
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the csem interface is detected. */
+#define UCM_REG_CSEM_LENGTH_MIS 				 0xe0160
+/* [RW 3] The weight of the input csem in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define UCM_REG_CSEM_WEIGHT					 0xe00b8
+/* [RW 1] Input dorq Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define UCM_REG_DORQ_IFEN					 0xe0030
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the dorq interface is detected. */
+#define UCM_REG_DORQ_LENGTH_MIS 				 0xe0168
+/* [RW 8] The Event ID in case ErrorFlg input message bit is set. */
+#define UCM_REG_ERR_EVNT_ID					 0xe00a4
+/* [RW 28] The CM erroneous header for QM and Timers formatting. */
+#define UCM_REG_ERR_UCM_HDR					 0xe00a0
+/* [RW 8] The Event ID for Timers expiration. */
+#define UCM_REG_EXPR_EVNT_ID					 0xe00a8
+/* [RW 8] FIC0 output initial credit. Max credit available - 255.Write
+   writes the initial credit value; read returns the current value of the
+   credit counter. Must be initialized to 64 at start-up. */
+#define UCM_REG_FIC0_INIT_CRD					 0xe020c
+/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write
+   writes the initial credit value; read returns the current value of the
+   credit counter. Must be initialized to 64 at start-up. */
+#define UCM_REG_FIC1_INIT_CRD					 0xe0210
+/* [RW 1] Arbitration between Input Arbiter groups: 0 - fair Round-Robin; 1
+   - strict priority defined by ~ucm_registers_gr_ag_pr.gr_ag_pr;
+   ~ucm_registers_gr_ld0_pr.gr_ld0_pr and
+   ~ucm_registers_gr_ld1_pr.gr_ld1_pr. */
+#define UCM_REG_GR_ARB_TYPE					 0xe0144
+/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the
+   highest priority is 3. It is supposed that the Store channel group is
+   compliment to the others. */
+#define UCM_REG_GR_LD0_PR					 0xe014c
+/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the
+   highest priority is 3. It is supposed that the Store channel group is
+   compliment to the others. */
+#define UCM_REG_GR_LD1_PR					 0xe0150
+/* [RW 2] The queue index for invalidate counter flag decision. */
+#define UCM_REG_INV_CFLG_Q					 0xe00e4
+/* [RW 5] The number of double REG-pairs; loaded from the STORM context and
+   sent to STORM; for a specific connection type. the double REG-pairs are
+   used in order to align to STORM context row size of 128 bits. The offset
+   of these data in the STORM context is always 0. Index _i stands for the
+   connection type (one of 16). */
+#define UCM_REG_N_SM_CTX_LD_0					 0xe0054
+#define UCM_REG_N_SM_CTX_LD_1					 0xe0058
+#define UCM_REG_N_SM_CTX_LD_10					 0xe007c
+#define UCM_REG_N_SM_CTX_LD_11					 0xe0080
+#define UCM_REG_N_SM_CTX_LD_12					 0xe0084
+#define UCM_REG_N_SM_CTX_LD_13					 0xe0088
+#define UCM_REG_N_SM_CTX_LD_14					 0xe008c
+#define UCM_REG_N_SM_CTX_LD_15					 0xe0090
+#define UCM_REG_N_SM_CTX_LD_2					 0xe005c
+#define UCM_REG_N_SM_CTX_LD_3					 0xe0060
+#define UCM_REG_N_SM_CTX_LD_4					 0xe0064
+/* [RW 6] The physical queue number 0 per port index (CID[23]) */
+#define UCM_REG_PHYS_QNUM0_0					 0xe0110
+#define UCM_REG_PHYS_QNUM0_1					 0xe0114
+/* [RW 6] The physical queue number 1 per port index (CID[23]) */
+#define UCM_REG_PHYS_QNUM1_0					 0xe0118
+#define UCM_REG_PHYS_QNUM1_1					 0xe011c
+/* [RW 8] The Event ID for Timers formatting in case of stop done. */
+#define UCM_REG_STOP_EVNT_ID					 0xe00ac
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the STORM interface is detected. */
+#define UCM_REG_STORM_LENGTH_MIS				 0xe0154
+/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define UCM_REG_STORM_UCM_IFEN					 0xe0010
+/* [RW 4] Timers output initial credit. Max credit available - 15.Write
+   writes the initial credit value; read returns the current value of the
+   credit counter. Must be initialized to 4 at start-up. */
+#define UCM_REG_TM_INIT_CRD					 0xe021c
+/* [RW 28] The CM header for Timers expiration command. */
+#define UCM_REG_TM_UCM_HDR					 0xe009c
+/* [RW 1] Timers - CM Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define UCM_REG_TM_UCM_IFEN					 0xe001c
+/* [RW 1] Input tsem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define UCM_REG_TSEM_IFEN					 0xe0024
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the tsem interface is detected. */
+#define UCM_REG_TSEM_LENGTH_MIS 				 0xe015c
+/* [RW 3] The weight of the input tsem in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define UCM_REG_TSEM_WEIGHT					 0xe00b4
+/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define UCM_REG_UCM_CFC_IFEN					 0xe0044
+/* [RW 11] Interrupt mask register #0 read/write */
+#define UCM_REG_UCM_INT_MASK					 0xe01d4
+/* [R 11] Interrupt register #0 read */
+#define UCM_REG_UCM_INT_STS					 0xe01c8
+/* [RW 2] The size of AG context region 0 in REG-pairs. Designates the MS
+   REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5).
+   Is used to determine the number of the AG context REG-pairs written back;
+   when the Reg1WbFlg isn't set. */
+#define UCM_REG_UCM_REG0_SZ					 0xe00dc
+/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define UCM_REG_UCM_STORM0_IFEN 				 0xe0004
+/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define UCM_REG_UCM_STORM1_IFEN 				 0xe0008
+/* [RW 1] CM - Timers Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define UCM_REG_UCM_TM_IFEN					 0xe0020
+/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define UCM_REG_UCM_UQM_IFEN					 0xe000c
+/* [RW 1] If set the Q index; received from the QM is inserted to event ID. */
+#define UCM_REG_UCM_UQM_USE_Q					 0xe00d8
+/* [RW 6] QM output initial credit. Max credit available - 32.Write writes
+   the initial credit value; read returns the current value of the credit
+   counter. Must be initialized to 32 at start-up. */
+#define UCM_REG_UQM_INIT_CRD					 0xe0220
+/* [RW 3] The weight of the QM (primary) input in the WRR mechanism. 0
+   stands for weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define UCM_REG_UQM_P_WEIGHT					 0xe00cc
+/* [RW 28] The CM header value for QM request (primary). */
+#define UCM_REG_UQM_UCM_HDR_P					 0xe0094
+/* [RW 28] The CM header value for QM request (secondary). */
+#define UCM_REG_UQM_UCM_HDR_S					 0xe0098
+/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define UCM_REG_UQM_UCM_IFEN					 0xe0014
+/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define UCM_REG_USDM_IFEN					 0xe0018
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the SDM interface is detected. */
+#define UCM_REG_USDM_LENGTH_MIS 				 0xe0158
+/* [RW 1] Input xsem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define UCM_REG_XSEM_IFEN					 0xe002c
+/* [RC 1] Set when the message length mismatch (relative to last indication)
+   at the xsem interface isdetected. */
+#define UCM_REG_XSEM_LENGTH_MIS 				 0xe0164
+/* [RW 20] Indirect access to the descriptor table of the XX protection
+   mechanism. The fields are:[5:0] - message length; 14:6] - message
+   pointer; 19:15] - next pointer. */
+#define UCM_REG_XX_DESCR_TABLE					 0xe0280
+/* [R 6] Use to read the XX protection Free counter. */
+#define UCM_REG_XX_FREE 					 0xe016c
+/* [RW 6] Initial value for the credit counter; responsible for fulfilling
+   of the Input Stage XX protection buffer by the XX protection pending
+   messages. Write writes the initial credit value; read returns the current
+   value of the credit counter. Must be initialized to 12 at start-up. */
+#define UCM_REG_XX_INIT_CRD					 0xe0224
+/* [RW 6] The maximum number of pending messages; which may be stored in XX
+   protection. ~ucm_registers_xx_free.xx_free read on read. */
+#define UCM_REG_XX_MSG_NUM					 0xe0228
+/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */
+#define UCM_REG_XX_OVFL_EVNT_ID 				 0xe004c
+/* [RW 16] Indirect access to the XX table of the XX protection mechanism.
+   The fields are: [4:0] - tail pointer; 10:5] - Link List size; 15:11] -
+   header pointer. */
+#define UCM_REG_XX_TABLE					 0xe0300
+/* [RW 8] The event id for aggregated interrupt 0 */
+#define USDM_REG_AGG_INT_EVENT_0				 0xc4038
+#define USDM_REG_AGG_INT_EVENT_1				 0xc403c
+#define USDM_REG_AGG_INT_EVENT_10				 0xc4060
+#define USDM_REG_AGG_INT_EVENT_11				 0xc4064
+#define USDM_REG_AGG_INT_EVENT_12				 0xc4068
+#define USDM_REG_AGG_INT_EVENT_13				 0xc406c
+#define USDM_REG_AGG_INT_EVENT_14				 0xc4070
+#define USDM_REG_AGG_INT_EVENT_15				 0xc4074
+#define USDM_REG_AGG_INT_EVENT_16				 0xc4078
+#define USDM_REG_AGG_INT_EVENT_17				 0xc407c
+#define USDM_REG_AGG_INT_EVENT_18				 0xc4080
+#define USDM_REG_AGG_INT_EVENT_19				 0xc4084
+/* [RW 1] For each aggregated interrupt index whether the mode is normal (0)
+   or auto-mask-mode (1) */
+#define USDM_REG_AGG_INT_MODE_0 				 0xc41b8
+#define USDM_REG_AGG_INT_MODE_1 				 0xc41bc
+#define USDM_REG_AGG_INT_MODE_10				 0xc41e0
+#define USDM_REG_AGG_INT_MODE_11				 0xc41e4
+#define USDM_REG_AGG_INT_MODE_12				 0xc41e8
+#define USDM_REG_AGG_INT_MODE_13				 0xc41ec
+#define USDM_REG_AGG_INT_MODE_14				 0xc41f0
+#define USDM_REG_AGG_INT_MODE_15				 0xc41f4
+#define USDM_REG_AGG_INT_MODE_16				 0xc41f8
+#define USDM_REG_AGG_INT_MODE_17				 0xc41fc
+#define USDM_REG_AGG_INT_MODE_18				 0xc4200
+#define USDM_REG_AGG_INT_MODE_19				 0xc4204
+/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */
+#define USDM_REG_CFC_RSP_START_ADDR				 0xc4008
+/* [RW 16] The maximum value of the competion counter #0 */
+#define USDM_REG_CMP_COUNTER_MAX0				 0xc401c
+/* [RW 16] The maximum value of the competion counter #1 */
+#define USDM_REG_CMP_COUNTER_MAX1				 0xc4020
+/* [RW 16] The maximum value of the competion counter #2 */
+#define USDM_REG_CMP_COUNTER_MAX2				 0xc4024
+/* [RW 16] The maximum value of the competion counter #3 */
+#define USDM_REG_CMP_COUNTER_MAX3				 0xc4028
+/* [RW 13] The start address in the internal RAM for the completion
+   counters. */
+#define USDM_REG_CMP_COUNTER_START_ADDR 			 0xc400c
+#define USDM_REG_ENABLE_IN1					 0xc4238
+#define USDM_REG_ENABLE_IN2					 0xc423c
+#define USDM_REG_ENABLE_OUT1					 0xc4240
+#define USDM_REG_ENABLE_OUT2					 0xc4244
+/* [RW 4] The initial number of messages that can be sent to the pxp control
+   interface without receiving any ACK. */
+#define USDM_REG_INIT_CREDIT_PXP_CTRL				 0xc44c0
+/* [ST 32] The number of ACK after placement messages received */
+#define USDM_REG_NUM_OF_ACK_AFTER_PLACE 			 0xc4280
+/* [ST 32] The number of packet end messages received from the parser */
+#define USDM_REG_NUM_OF_PKT_END_MSG				 0xc4278
+/* [ST 32] The number of requests received from the pxp async if */
+#define USDM_REG_NUM_OF_PXP_ASYNC_REQ				 0xc427c
+/* [ST 32] The number of commands received in queue 0 */
+#define USDM_REG_NUM_OF_Q0_CMD					 0xc4248
+/* [ST 32] The number of commands received in queue 10 */
+#define USDM_REG_NUM_OF_Q10_CMD 				 0xc4270
+/* [ST 32] The number of commands received in queue 11 */
+#define USDM_REG_NUM_OF_Q11_CMD 				 0xc4274
+/* [ST 32] The number of commands received in queue 1 */
+#define USDM_REG_NUM_OF_Q1_CMD					 0xc424c
+/* [ST 32] The number of commands received in queue 2 */
+#define USDM_REG_NUM_OF_Q2_CMD					 0xc4250
+/* [ST 32] The number of commands received in queue 3 */
+#define USDM_REG_NUM_OF_Q3_CMD					 0xc4254
+/* [ST 32] The number of commands received in queue 4 */
+#define USDM_REG_NUM_OF_Q4_CMD					 0xc4258
+/* [ST 32] The number of commands received in queue 5 */
+#define USDM_REG_NUM_OF_Q5_CMD					 0xc425c
+/* [ST 32] The number of commands received in queue 6 */
+#define USDM_REG_NUM_OF_Q6_CMD					 0xc4260
+/* [ST 32] The number of commands received in queue 7 */
+#define USDM_REG_NUM_OF_Q7_CMD					 0xc4264
+/* [ST 32] The number of commands received in queue 8 */
+#define USDM_REG_NUM_OF_Q8_CMD					 0xc4268
+/* [ST 32] The number of commands received in queue 9 */
+#define USDM_REG_NUM_OF_Q9_CMD					 0xc426c
+/* [RW 13] The start address in the internal RAM for the packet end message */
+#define USDM_REG_PCK_END_MSG_START_ADDR 			 0xc4014
+/* [RW 13] The start address in the internal RAM for queue counters */
+#define USDM_REG_Q_COUNTER_START_ADDR				 0xc4010
+/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */
+#define USDM_REG_RSP_PXP_CTRL_RDATA_EMPTY			 0xc4550
+/* [R 1] parser fifo empty in sdm_sync block */
+#define USDM_REG_SYNC_PARSER_EMPTY				 0xc4558
+/* [R 1] parser serial fifo empty in sdm_sync block */
+#define USDM_REG_SYNC_SYNC_EMPTY				 0xc4560
+/* [RW 32] Tick for timer counter. Applicable only when
+   ~usdm_registers_timer_tick_enable.timer_tick_enable =1 */
+#define USDM_REG_TIMER_TICK					 0xc4000
+/* [RW 32] Interrupt mask register #0 read/write */
+#define USDM_REG_USDM_INT_MASK_0				 0xc42a0
+#define USDM_REG_USDM_INT_MASK_1				 0xc42b0
+/* [RW 11] Parity mask register #0 read/write */
+#define USDM_REG_USDM_PRTY_MASK 				 0xc42c0
+/* [RW 5] The number of time_slots in the arbitration cycle */
+#define USEM_REG_ARB_CYCLE_SIZE 				 0x300034
+/* [RW 3] The source that is associated with arbitration element 0. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2 */
+#define USEM_REG_ARB_ELEMENT0					 0x300020
+/* [RW 3] The source that is associated with arbitration element 1. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~usem_registers_arb_element0.arb_element0 */
+#define USEM_REG_ARB_ELEMENT1					 0x300024
+/* [RW 3] The source that is associated with arbitration element 2. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~usem_registers_arb_element0.arb_element0
+   and ~usem_registers_arb_element1.arb_element1 */
+#define USEM_REG_ARB_ELEMENT2					 0x300028
+/* [RW 3] The source that is associated with arbitration element 3. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.Could
+   not be equal to register ~usem_registers_arb_element0.arb_element0 and
+   ~usem_registers_arb_element1.arb_element1 and
+   ~usem_registers_arb_element2.arb_element2 */
+#define USEM_REG_ARB_ELEMENT3					 0x30002c
+/* [RW 3] The source that is associated with arbitration element 4. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~usem_registers_arb_element0.arb_element0
+   and ~usem_registers_arb_element1.arb_element1 and
+   ~usem_registers_arb_element2.arb_element2 and
+   ~usem_registers_arb_element3.arb_element3 */
+#define USEM_REG_ARB_ELEMENT4					 0x300030
+#define USEM_REG_ENABLE_IN					 0x3000a4
+#define USEM_REG_ENABLE_OUT					 0x3000a8
+/* [RW 32] This address space contains all registers and memories that are
+   placed in SEM_FAST block. The SEM_FAST registers are described in
+   appendix B. In order to access the SEM_FAST registers... the base address
+   USEM_REGISTERS_FAST_MEMORY (Offset: 0x320000) should be added to each
+   SEM_FAST register offset. */
+#define USEM_REG_FAST_MEMORY					 0x320000
+/* [RW 1] Disables input messages from FIC0 May be updated during run_time
+   by the microcode */
+#define USEM_REG_FIC0_DISABLE					 0x300224
+/* [RW 1] Disables input messages from FIC1 May be updated during run_time
+   by the microcode */
+#define USEM_REG_FIC1_DISABLE					 0x300234
+/* [RW 15] Interrupt table Read and write access to it is not possible in
+   the middle of the work */
+#define USEM_REG_INT_TABLE					 0x300400
+/* [ST 24] Statistics register. The number of messages that entered through
+   FIC0 */
+#define USEM_REG_MSG_NUM_FIC0					 0x300000
+/* [ST 24] Statistics register. The number of messages that entered through
+   FIC1 */
+#define USEM_REG_MSG_NUM_FIC1					 0x300004
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC0 */
+#define USEM_REG_MSG_NUM_FOC0					 0x300008
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC1 */
+#define USEM_REG_MSG_NUM_FOC1					 0x30000c
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC2 */
+#define USEM_REG_MSG_NUM_FOC2					 0x300010
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC3 */
+#define USEM_REG_MSG_NUM_FOC3					 0x300014
+/* [RW 1] Disables input messages from the passive buffer May be updated
+   during run_time by the microcode */
+#define USEM_REG_PAS_DISABLE					 0x30024c
+/* [WB 128] Debug only. Passive buffer memory */
+#define USEM_REG_PASSIVE_BUFFER 				 0x302000
+/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */
+#define USEM_REG_PRAM						 0x340000
+/* [R 16] Valid sleeping threads indication have bit per thread */
+#define USEM_REG_SLEEP_THREADS_VALID				 0x30026c
+/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */
+#define USEM_REG_SLOW_EXT_STORE_EMPTY				 0x3002a0
+/* [RW 16] List of free threads . There is a bit per thread. */
+#define USEM_REG_THREADS_LIST					 0x3002e4
+/* [RW 3] The arbitration scheme of time_slot 0 */
+#define USEM_REG_TS_0_AS					 0x300038
+/* [RW 3] The arbitration scheme of time_slot 10 */
+#define USEM_REG_TS_10_AS					 0x300060
+/* [RW 3] The arbitration scheme of time_slot 11 */
+#define USEM_REG_TS_11_AS					 0x300064
+/* [RW 3] The arbitration scheme of time_slot 12 */
+#define USEM_REG_TS_12_AS					 0x300068
+/* [RW 3] The arbitration scheme of time_slot 13 */
+#define USEM_REG_TS_13_AS					 0x30006c
+/* [RW 3] The arbitration scheme of time_slot 14 */
+#define USEM_REG_TS_14_AS					 0x300070
+/* [RW 3] The arbitration scheme of time_slot 15 */
+#define USEM_REG_TS_15_AS					 0x300074
+/* [RW 3] The arbitration scheme of time_slot 16 */
+#define USEM_REG_TS_16_AS					 0x300078
+/* [RW 3] The arbitration scheme of time_slot 17 */
+#define USEM_REG_TS_17_AS					 0x30007c
+/* [RW 3] The arbitration scheme of time_slot 18 */
+#define USEM_REG_TS_18_AS					 0x300080
+/* [RW 3] The arbitration scheme of time_slot 1 */
+#define USEM_REG_TS_1_AS					 0x30003c
+/* [RW 3] The arbitration scheme of time_slot 2 */
+#define USEM_REG_TS_2_AS					 0x300040
+/* [RW 3] The arbitration scheme of time_slot 3 */
+#define USEM_REG_TS_3_AS					 0x300044
+/* [RW 3] The arbitration scheme of time_slot 4 */
+#define USEM_REG_TS_4_AS					 0x300048
+/* [RW 3] The arbitration scheme of time_slot 5 */
+#define USEM_REG_TS_5_AS					 0x30004c
+/* [RW 3] The arbitration scheme of time_slot 6 */
+#define USEM_REG_TS_6_AS					 0x300050
+/* [RW 3] The arbitration scheme of time_slot 7 */
+#define USEM_REG_TS_7_AS					 0x300054
+/* [RW 3] The arbitration scheme of time_slot 8 */
+#define USEM_REG_TS_8_AS					 0x300058
+/* [RW 3] The arbitration scheme of time_slot 9 */
+#define USEM_REG_TS_9_AS					 0x30005c
+/* [RW 32] Interrupt mask register #0 read/write */
+#define USEM_REG_USEM_INT_MASK_0				 0x300110
+#define USEM_REG_USEM_INT_MASK_1				 0x300120
+/* [RW 32] Parity mask register #0 read/write */
+#define USEM_REG_USEM_PRTY_MASK_0				 0x300130
+#define USEM_REG_USEM_PRTY_MASK_1				 0x300140
+/* [RW 2] The queue index for registration on Aux1 counter flag. */
+#define XCM_REG_AUX1_Q						 0x20134
+/* [RW 2] Per each decision rule the queue index to register to. */
+#define XCM_REG_AUX_CNT_FLG_Q_19				 0x201b0
+/* [R 5] Used to read the XX protection CAM occupancy counter. */
+#define XCM_REG_CAM_OCCUP					 0x20244
+/* [RW 1] CDU AG read Interface enable. If 0 - the request input is
+   disregarded; valid output is deasserted; all other signals are treated as
+   usual; if 1 - normal activity. */
+#define XCM_REG_CDU_AG_RD_IFEN					 0x20044
+/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input
+   are disregarded; all other signals are treated as usual; if 1 - normal
+   activity. */
+#define XCM_REG_CDU_AG_WR_IFEN					 0x20040
+/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is
+   disregarded; valid output is deasserted; all other signals are treated as
+   usual; if 1 - normal activity. */
+#define XCM_REG_CDU_SM_RD_IFEN					 0x2004c
+/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid
+   input is disregarded; all other signals are treated as usual; if 1 -
+   normal activity. */
+#define XCM_REG_CDU_SM_WR_IFEN					 0x20048
+/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes
+   the initial credit value; read returns the current value of the credit
+   counter. Must be initialized to 1 at start-up. */
+#define XCM_REG_CFC_INIT_CRD					 0x20404
+/* [RW 3] The weight of the CP input in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define XCM_REG_CP_WEIGHT					 0x200dc
+/* [RW 1] Input csem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define XCM_REG_CSEM_IFEN					 0x20028
+/* [RC 1] Set at message length mismatch (relative to last indication) at
+   the csem interface. */
+#define XCM_REG_CSEM_LENGTH_MIS 				 0x20228
+/* [RW 3] The weight of the input csem in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define XCM_REG_CSEM_WEIGHT					 0x200c4
+/* [RW 1] Input dorq Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define XCM_REG_DORQ_IFEN					 0x20030
+/* [RC 1] Set at message length mismatch (relative to last indication) at
+   the dorq interface. */
+#define XCM_REG_DORQ_LENGTH_MIS 				 0x20230
+/* [RW 8] The Event ID in case the ErrorFlg input message bit is set. */
+#define XCM_REG_ERR_EVNT_ID					 0x200b0
+/* [RW 28] The CM erroneous header for QM and Timers formatting. */
+#define XCM_REG_ERR_XCM_HDR					 0x200ac
+/* [RW 8] The Event ID for Timers expiration. */
+#define XCM_REG_EXPR_EVNT_ID					 0x200b4
+/* [RW 8] FIC0 output initial credit. Max credit available - 255.Write
+   writes the initial credit value; read returns the current value of the
+   credit counter. Must be initialized to 64 at start-up. */
+#define XCM_REG_FIC0_INIT_CRD					 0x2040c
+/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write
+   writes the initial credit value; read returns the current value of the
+   credit counter. Must be initialized to 64 at start-up. */
+#define XCM_REG_FIC1_INIT_CRD					 0x20410
+/* [RW 8] The maximum delayed ACK counter value.Must be at least 2. Per port
+   value. */
+#define XCM_REG_GLB_DEL_ACK_MAX_CNT_0				 0x20118
+#define XCM_REG_GLB_DEL_ACK_MAX_CNT_1				 0x2011c
+/* [RW 28] The delayed ACK timeout in ticks. Per port value. */
+#define XCM_REG_GLB_DEL_ACK_TMR_VAL_0				 0x20108
+#define XCM_REG_GLB_DEL_ACK_TMR_VAL_1				 0x2010c
+/* [RW 1] Arbitratiojn between Input Arbiter groups: 0 - fair Round-Robin; 1
+   - strict priority defined by ~xcm_registers_gr_ag_pr.gr_ag_pr;
+   ~xcm_registers_gr_ld0_pr.gr_ld0_pr and
+   ~xcm_registers_gr_ld1_pr.gr_ld1_pr. */
+#define XCM_REG_GR_ARB_TYPE					 0x2020c
+/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the
+   highest priority is 3. It is supposed that the Channel group is the
+   compliment of the other 3 groups. */
+#define XCM_REG_GR_LD0_PR					 0x20214
+/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the
+   highest priority is 3. It is supposed that the Channel group is the
+   compliment of the other 3 groups. */
+#define XCM_REG_GR_LD1_PR					 0x20218
+/* [RW 1] Input nig0 Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define XCM_REG_NIG0_IFEN					 0x20038
+/* [RC 1] Set at message length mismatch (relative to last indication) at
+   the nig0 interface. */
+#define XCM_REG_NIG0_LENGTH_MIS 				 0x20238
+/* [RW 1] Input nig1 Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define XCM_REG_NIG1_IFEN					 0x2003c
+/* [RC 1] Set at message length mismatch (relative to last indication) at
+   the nig1 interface. */
+#define XCM_REG_NIG1_LENGTH_MIS 				 0x2023c
+/* [RW 3] The weight of the input nig1 in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define XCM_REG_NIG1_WEIGHT					 0x200d8
+/* [RW 5] The number of double REG-pairs; loaded from the STORM context and
+   sent to STORM; for a specific connection type. The double REG-pairs are
+   used in order to align to STORM context row size of 128 bits. The offset
+   of these data in the STORM context is always 0. Index _i stands for the
+   connection type (one of 16). */
+#define XCM_REG_N_SM_CTX_LD_0					 0x20060
+#define XCM_REG_N_SM_CTX_LD_1					 0x20064
+#define XCM_REG_N_SM_CTX_LD_10					 0x20088
+#define XCM_REG_N_SM_CTX_LD_11					 0x2008c
+#define XCM_REG_N_SM_CTX_LD_12					 0x20090
+#define XCM_REG_N_SM_CTX_LD_13					 0x20094
+#define XCM_REG_N_SM_CTX_LD_14					 0x20098
+#define XCM_REG_N_SM_CTX_LD_15					 0x2009c
+#define XCM_REG_N_SM_CTX_LD_2					 0x20068
+#define XCM_REG_N_SM_CTX_LD_3					 0x2006c
+#define XCM_REG_N_SM_CTX_LD_4					 0x20070
+/* [RW 1] Input pbf Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define XCM_REG_PBF_IFEN					 0x20034
+/* [RC 1] Set at message length mismatch (relative to last indication) at
+   the pbf interface. */
+#define XCM_REG_PBF_LENGTH_MIS					 0x20234
+/* [RW 3] The weight of the input pbf in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define XCM_REG_PBF_WEIGHT					 0x200d0
+/* [RW 8] The Event ID for Timers formatting in case of stop done. */
+#define XCM_REG_STOP_EVNT_ID					 0x200b8
+/* [RC 1] Set at message length mismatch (relative to last indication) at
+   the STORM interface. */
+#define XCM_REG_STORM_LENGTH_MIS				 0x2021c
+/* [RW 3] The weight of the STORM input in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define XCM_REG_STORM_WEIGHT					 0x200bc
+/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define XCM_REG_STORM_XCM_IFEN					 0x20010
+/* [RW 4] Timers output initial credit. Max credit available - 15.Write
+   writes the initial credit value; read returns the current value of the
+   credit counter. Must be initialized to 4 at start-up. */
+#define XCM_REG_TM_INIT_CRD					 0x2041c
+/* [RW 28] The CM header for Timers expiration command. */
+#define XCM_REG_TM_XCM_HDR					 0x200a8
+/* [RW 1] Timers - CM Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define XCM_REG_TM_XCM_IFEN					 0x2001c
+/* [RW 1] Input tsem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define XCM_REG_TSEM_IFEN					 0x20024
+/* [RC 1] Set at message length mismatch (relative to last indication) at
+   the tsem interface. */
+#define XCM_REG_TSEM_LENGTH_MIS 				 0x20224
+/* [RW 3] The weight of the input tsem in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define XCM_REG_TSEM_WEIGHT					 0x200c0
+/* [RW 2] The queue index for registration on UNA greater NXT decision rule. */
+#define XCM_REG_UNA_GT_NXT_Q					 0x20120
+/* [RW 1] Input usem Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define XCM_REG_USEM_IFEN					 0x2002c
+/* [RC 1] Message length mismatch (relative to last indication) at the usem
+   interface. */
+#define XCM_REG_USEM_LENGTH_MIS 				 0x2022c
+/* [RW 3] The weight of the input usem in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define XCM_REG_USEM_WEIGHT					 0x200c8
+/* [RW 2] DA counter command; used in case of window update doorbell.The
+   first index stands for the value DaEnable of that connection. The second
+   index stands for port number. */
+#define XCM_REG_WU_DA_CNT_CMD00 				 0x201d4
+/* [RW 2] DA counter command; used in case of window update doorbell.The
+   first index stands for the value DaEnable of that connection. The second
+   index stands for port number. */
+#define XCM_REG_WU_DA_CNT_CMD01 				 0x201d8
+/* [RW 2] DA counter command; used in case of window update doorbell.The
+   first index stands for the value DaEnable of that connection. The second
+   index stands for port number. */
+#define XCM_REG_WU_DA_CNT_CMD10 				 0x201dc
+/* [RW 2] DA counter command; used in case of window update doorbell.The
+   first index stands for the value DaEnable of that connection. The second
+   index stands for port number. */
+#define XCM_REG_WU_DA_CNT_CMD11 				 0x201e0
+/* [RW 8] DA counter update value used in case of window update doorbell.The
+   first index stands for the value DaEnable of that connection. The second
+   index stands for port number. */
+#define XCM_REG_WU_DA_CNT_UPD_VAL00				 0x201e4
+/* [RW 8] DA counter update value; used in case of window update
+   doorbell.The first index stands for the value DaEnable of that
+   connection. The second index stands for port number. */
+#define XCM_REG_WU_DA_CNT_UPD_VAL01				 0x201e8
+/* [RW 8] DA counter update value; used in case of window update
+   doorbell.The first index stands for the value DaEnable of that
+   connection. The second index stands for port number. */
+#define XCM_REG_WU_DA_CNT_UPD_VAL10				 0x201ec
+/* [RW 8] DA counter update value; used in case of window update
+   doorbell.The first index stands for the value DaEnable of that
+   connection. The second index stands for port number. */
+#define XCM_REG_WU_DA_CNT_UPD_VAL11				 0x201f0
+/* [RW 1] DA timer command; used in case of window update doorbell.The first
+   index stands for the value DaEnable of that connection. The second index
+   stands for port number. */
+#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00			 0x201c4
+/* [RW 1] DA timer command; used in case of window update doorbell.The first
+   index stands for the value DaEnable of that connection. The second index
+   stands for port number. */
+#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01			 0x201c8
+/* [RW 1] DA timer command; used in case of window update doorbell.The first
+   index stands for the value DaEnable of that connection. The second index
+   stands for port number. */
+#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10			 0x201cc
+/* [RW 1] DA timer command; used in case of window update doorbell.The first
+   index stands for the value DaEnable of that connection. The second index
+   stands for port number. */
+#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11			 0x201d0
+/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define XCM_REG_XCM_CFC_IFEN					 0x20050
+/* [RW 14] Interrupt mask register #0 read/write */
+#define XCM_REG_XCM_INT_MASK					 0x202b4
+/* [R 14] Interrupt register #0 read */
+#define XCM_REG_XCM_INT_STS					 0x202a8
+/* [RW 4] The size of AG context region 0 in REG-pairs. Designates the MS
+   REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5).
+   Is used to determine the number of the AG context REG-pairs written back;
+   when the Reg1WbFlg isn't set. */
+#define XCM_REG_XCM_REG0_SZ					 0x200f4
+/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define XCM_REG_XCM_STORM0_IFEN 				 0x20004
+/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define XCM_REG_XCM_STORM1_IFEN 				 0x20008
+/* [RW 1] CM - Timers Interface enable. If 0 - the valid input is
+   disregarded; acknowledge output is deasserted; all other signals are
+   treated as usual; if 1 - normal activity. */
+#define XCM_REG_XCM_TM_IFEN					 0x20020
+/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is
+   disregarded; valid is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define XCM_REG_XCM_XQM_IFEN					 0x2000c
+/* [RW 1] If set the Q index; received from the QM is inserted to event ID. */
+#define XCM_REG_XCM_XQM_USE_Q					 0x200f0
+/* [RW 4] The value by which CFC updates the activity counter at QM bypass. */
+#define XCM_REG_XQM_BYP_ACT_UPD 				 0x200fc
+/* [RW 6] QM output initial credit. Max credit available - 32.Write writes
+   the initial credit value; read returns the current value of the credit
+   counter. Must be initialized to 32 at start-up. */
+#define XCM_REG_XQM_INIT_CRD					 0x20420
+/* [RW 3] The weight of the QM (primary) input in the WRR mechanism. 0
+   stands for weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define XCM_REG_XQM_P_WEIGHT					 0x200e4
+/* [RW 28] The CM header value for QM request (primary). */
+#define XCM_REG_XQM_XCM_HDR_P					 0x200a0
+/* [RW 28] The CM header value for QM request (secondary). */
+#define XCM_REG_XQM_XCM_HDR_S					 0x200a4
+/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define XCM_REG_XQM_XCM_IFEN					 0x20014
+/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded;
+   acknowledge output is deasserted; all other signals are treated as usual;
+   if 1 - normal activity. */
+#define XCM_REG_XSDM_IFEN					 0x20018
+/* [RC 1] Set at message length mismatch (relative to last indication) at
+   the SDM interface. */
+#define XCM_REG_XSDM_LENGTH_MIS 				 0x20220
+/* [RW 3] The weight of the SDM input in the WRR mechanism. 0 stands for
+   weight 8 (the most prioritised); 1 stands for weight 1(least
+   prioritised); 2 stands for weight 2; tc. */
+#define XCM_REG_XSDM_WEIGHT					 0x200e0
+/* [RW 17] Indirect access to the descriptor table of the XX protection
+   mechanism. The fields are: [5:0] - message length; 11:6] - message
+   pointer; 16:12] - next pointer. */
+#define XCM_REG_XX_DESCR_TABLE					 0x20480
+/* [R 6] Used to read the XX protection Free counter. */
+#define XCM_REG_XX_FREE 					 0x20240
+/* [RW 6] Initial value for the credit counter; responsible for fulfilling
+   of the Input Stage XX protection buffer by the XX protection pending
+   messages. Max credit available - 3.Write writes the initial credit value;
+   read returns the current value of the credit counter. Must be initialized
+   to 2 at start-up. */
+#define XCM_REG_XX_INIT_CRD					 0x20424
+/* [RW 6] The maximum number of pending messages; which may be stored in XX
+   protection. ~xcm_registers_xx_free.xx_free read on read. */
+#define XCM_REG_XX_MSG_NUM					 0x20428
+/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */
+#define XCM_REG_XX_OVFL_EVNT_ID 				 0x20058
+/* [RW 15] Indirect access to the XX table of the XX protection mechanism.
+   The fields are:[4:0] - tail pointer; 9:5] - Link List size; 14:10] -
+   header pointer. */
+#define XCM_REG_XX_TABLE					 0x20500
+/* [RW 8] The event id for aggregated interrupt 0 */
+#define XSDM_REG_AGG_INT_EVENT_0				 0x166038
+#define XSDM_REG_AGG_INT_EVENT_1				 0x16603c
+#define XSDM_REG_AGG_INT_EVENT_10				 0x166060
+#define XSDM_REG_AGG_INT_EVENT_11				 0x166064
+#define XSDM_REG_AGG_INT_EVENT_12				 0x166068
+#define XSDM_REG_AGG_INT_EVENT_13				 0x16606c
+#define XSDM_REG_AGG_INT_EVENT_14				 0x166070
+#define XSDM_REG_AGG_INT_EVENT_15				 0x166074
+#define XSDM_REG_AGG_INT_EVENT_16				 0x166078
+#define XSDM_REG_AGG_INT_EVENT_17				 0x16607c
+#define XSDM_REG_AGG_INT_EVENT_18				 0x166080
+#define XSDM_REG_AGG_INT_EVENT_19				 0x166084
+#define XSDM_REG_AGG_INT_EVENT_2				 0x166040
+#define XSDM_REG_AGG_INT_EVENT_20				 0x166088
+#define XSDM_REG_AGG_INT_EVENT_21				 0x16608c
+#define XSDM_REG_AGG_INT_EVENT_22				 0x166090
+#define XSDM_REG_AGG_INT_EVENT_23				 0x166094
+#define XSDM_REG_AGG_INT_EVENT_24				 0x166098
+#define XSDM_REG_AGG_INT_EVENT_25				 0x16609c
+#define XSDM_REG_AGG_INT_EVENT_26				 0x1660a0
+#define XSDM_REG_AGG_INT_EVENT_27				 0x1660a4
+#define XSDM_REG_AGG_INT_EVENT_28				 0x1660a8
+#define XSDM_REG_AGG_INT_EVENT_29				 0x1660ac
+/* [RW 1] For each aggregated interrupt index whether the mode is normal (0)
+   or auto-mask-mode (1) */
+#define XSDM_REG_AGG_INT_MODE_0 				 0x1661b8
+#define XSDM_REG_AGG_INT_MODE_1 				 0x1661bc
+#define XSDM_REG_AGG_INT_MODE_10				 0x1661e0
+#define XSDM_REG_AGG_INT_MODE_11				 0x1661e4
+#define XSDM_REG_AGG_INT_MODE_12				 0x1661e8
+#define XSDM_REG_AGG_INT_MODE_13				 0x1661ec
+#define XSDM_REG_AGG_INT_MODE_14				 0x1661f0
+#define XSDM_REG_AGG_INT_MODE_15				 0x1661f4
+#define XSDM_REG_AGG_INT_MODE_16				 0x1661f8
+#define XSDM_REG_AGG_INT_MODE_17				 0x1661fc
+#define XSDM_REG_AGG_INT_MODE_18				 0x166200
+#define XSDM_REG_AGG_INT_MODE_19				 0x166204
+/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */
+#define XSDM_REG_CFC_RSP_START_ADDR				 0x166008
+/* [RW 16] The maximum value of the competion counter #0 */
+#define XSDM_REG_CMP_COUNTER_MAX0				 0x16601c
+/* [RW 16] The maximum value of the competion counter #1 */
+#define XSDM_REG_CMP_COUNTER_MAX1				 0x166020
+/* [RW 16] The maximum value of the competion counter #2 */
+#define XSDM_REG_CMP_COUNTER_MAX2				 0x166024
+/* [RW 16] The maximum value of the competion counter #3 */
+#define XSDM_REG_CMP_COUNTER_MAX3				 0x166028
+/* [RW 13] The start address in the internal RAM for the completion
+   counters. */
+#define XSDM_REG_CMP_COUNTER_START_ADDR 			 0x16600c
+#define XSDM_REG_ENABLE_IN1					 0x166238
+#define XSDM_REG_ENABLE_IN2					 0x16623c
+#define XSDM_REG_ENABLE_OUT1					 0x166240
+#define XSDM_REG_ENABLE_OUT2					 0x166244
+/* [RW 4] The initial number of messages that can be sent to the pxp control
+   interface without receiving any ACK. */
+#define XSDM_REG_INIT_CREDIT_PXP_CTRL				 0x1664bc
+/* [ST 32] The number of ACK after placement messages received */
+#define XSDM_REG_NUM_OF_ACK_AFTER_PLACE 			 0x16627c
+/* [ST 32] The number of packet end messages received from the parser */
+#define XSDM_REG_NUM_OF_PKT_END_MSG				 0x166274
+/* [ST 32] The number of requests received from the pxp async if */
+#define XSDM_REG_NUM_OF_PXP_ASYNC_REQ				 0x166278
+/* [ST 32] The number of commands received in queue 0 */
+#define XSDM_REG_NUM_OF_Q0_CMD					 0x166248
+/* [ST 32] The number of commands received in queue 10 */
+#define XSDM_REG_NUM_OF_Q10_CMD 				 0x16626c
+/* [ST 32] The number of commands received in queue 11 */
+#define XSDM_REG_NUM_OF_Q11_CMD 				 0x166270
+/* [ST 32] The number of commands received in queue 1 */
+#define XSDM_REG_NUM_OF_Q1_CMD					 0x16624c
+/* [ST 32] The number of commands received in queue 3 */
+#define XSDM_REG_NUM_OF_Q3_CMD					 0x166250
+/* [ST 32] The number of commands received in queue 4 */
+#define XSDM_REG_NUM_OF_Q4_CMD					 0x166254
+/* [ST 32] The number of commands received in queue 5 */
+#define XSDM_REG_NUM_OF_Q5_CMD					 0x166258
+/* [ST 32] The number of commands received in queue 6 */
+#define XSDM_REG_NUM_OF_Q6_CMD					 0x16625c
+/* [ST 32] The number of commands received in queue 7 */
+#define XSDM_REG_NUM_OF_Q7_CMD					 0x166260
+/* [ST 32] The number of commands received in queue 8 */
+#define XSDM_REG_NUM_OF_Q8_CMD					 0x166264
+/* [ST 32] The number of commands received in queue 9 */
+#define XSDM_REG_NUM_OF_Q9_CMD					 0x166268
+/* [RW 13] The start address in the internal RAM for queue counters */
+#define XSDM_REG_Q_COUNTER_START_ADDR				 0x166010
+/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */
+#define XSDM_REG_RSP_PXP_CTRL_RDATA_EMPTY			 0x166548
+/* [R 1] parser fifo empty in sdm_sync block */
+#define XSDM_REG_SYNC_PARSER_EMPTY				 0x166550
+/* [R 1] parser serial fifo empty in sdm_sync block */
+#define XSDM_REG_SYNC_SYNC_EMPTY				 0x166558
+/* [RW 32] Tick for timer counter. Applicable only when
+   ~xsdm_registers_timer_tick_enable.timer_tick_enable =1 */
+#define XSDM_REG_TIMER_TICK					 0x166000
+/* [RW 32] Interrupt mask register #0 read/write */
+#define XSDM_REG_XSDM_INT_MASK_0				 0x16629c
+#define XSDM_REG_XSDM_INT_MASK_1				 0x1662ac
+/* [RW 11] Parity mask register #0 read/write */
+#define XSDM_REG_XSDM_PRTY_MASK 				 0x1662bc
+/* [RW 5] The number of time_slots in the arbitration cycle */
+#define XSEM_REG_ARB_CYCLE_SIZE 				 0x280034
+/* [RW 3] The source that is associated with arbitration element 0. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2 */
+#define XSEM_REG_ARB_ELEMENT0					 0x280020
+/* [RW 3] The source that is associated with arbitration element 1. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~xsem_registers_arb_element0.arb_element0 */
+#define XSEM_REG_ARB_ELEMENT1					 0x280024
+/* [RW 3] The source that is associated with arbitration element 2. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~xsem_registers_arb_element0.arb_element0
+   and ~xsem_registers_arb_element1.arb_element1 */
+#define XSEM_REG_ARB_ELEMENT2					 0x280028
+/* [RW 3] The source that is associated with arbitration element 3. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.Could
+   not be equal to register ~xsem_registers_arb_element0.arb_element0 and
+   ~xsem_registers_arb_element1.arb_element1 and
+   ~xsem_registers_arb_element2.arb_element2 */
+#define XSEM_REG_ARB_ELEMENT3					 0x28002c
+/* [RW 3] The source that is associated with arbitration element 4. Source
+   decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3-
+   sleeping thread with priority 1; 4- sleeping thread with priority 2.
+   Could not be equal to register ~xsem_registers_arb_element0.arb_element0
+   and ~xsem_registers_arb_element1.arb_element1 and
+   ~xsem_registers_arb_element2.arb_element2 and
+   ~xsem_registers_arb_element3.arb_element3 */
+#define XSEM_REG_ARB_ELEMENT4					 0x280030
+#define XSEM_REG_ENABLE_IN					 0x2800a4
+#define XSEM_REG_ENABLE_OUT					 0x2800a8
+/* [RW 32] This address space contains all registers and memories that are
+   placed in SEM_FAST block. The SEM_FAST registers are described in
+   appendix B. In order to access the SEM_FAST registers the base address
+   XSEM_REGISTERS_FAST_MEMORY (Offset: 0x2a0000) should be added to each
+   SEM_FAST register offset. */
+#define XSEM_REG_FAST_MEMORY					 0x2a0000
+/* [RW 1] Disables input messages from FIC0 May be updated during run_time
+   by the microcode */
+#define XSEM_REG_FIC0_DISABLE					 0x280224
+/* [RW 1] Disables input messages from FIC1 May be updated during run_time
+   by the microcode */
+#define XSEM_REG_FIC1_DISABLE					 0x280234
+/* [RW 15] Interrupt table Read and write access to it is not possible in
+   the middle of the work */
+#define XSEM_REG_INT_TABLE					 0x280400
+/* [ST 24] Statistics register. The number of messages that entered through
+   FIC0 */
+#define XSEM_REG_MSG_NUM_FIC0					 0x280000
+/* [ST 24] Statistics register. The number of messages that entered through
+   FIC1 */
+#define XSEM_REG_MSG_NUM_FIC1					 0x280004
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC0 */
+#define XSEM_REG_MSG_NUM_FOC0					 0x280008
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC1 */
+#define XSEM_REG_MSG_NUM_FOC1					 0x28000c
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC2 */
+#define XSEM_REG_MSG_NUM_FOC2					 0x280010
+/* [ST 24] Statistics register. The number of messages that were sent to
+   FOC3 */
+#define XSEM_REG_MSG_NUM_FOC3					 0x280014
+/* [RW 1] Disables input messages from the passive buffer May be updated
+   during run_time by the microcode */
+#define XSEM_REG_PAS_DISABLE					 0x28024c
+/* [WB 128] Debug only. Passive buffer memory */
+#define XSEM_REG_PASSIVE_BUFFER 				 0x282000
+/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */
+#define XSEM_REG_PRAM						 0x2c0000
+/* [R 16] Valid sleeping threads indication have bit per thread */
+#define XSEM_REG_SLEEP_THREADS_VALID				 0x28026c
+/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */
+#define XSEM_REG_SLOW_EXT_STORE_EMPTY				 0x2802a0
+/* [RW 16] List of free threads . There is a bit per thread. */
+#define XSEM_REG_THREADS_LIST					 0x2802e4
+/* [RW 3] The arbitration scheme of time_slot 0 */
+#define XSEM_REG_TS_0_AS					 0x280038
+/* [RW 3] The arbitration scheme of time_slot 10 */
+#define XSEM_REG_TS_10_AS					 0x280060
+/* [RW 3] The arbitration scheme of time_slot 11 */
+#define XSEM_REG_TS_11_AS					 0x280064
+/* [RW 3] The arbitration scheme of time_slot 12 */
+#define XSEM_REG_TS_12_AS					 0x280068
+/* [RW 3] The arbitration scheme of time_slot 13 */
+#define XSEM_REG_TS_13_AS					 0x28006c
+/* [RW 3] The arbitration scheme of time_slot 14 */
+#define XSEM_REG_TS_14_AS					 0x280070
+/* [RW 3] The arbitration scheme of time_slot 15 */
+#define XSEM_REG_TS_15_AS					 0x280074
+/* [RW 3] The arbitration scheme of time_slot 16 */
+#define XSEM_REG_TS_16_AS					 0x280078
+/* [RW 3] The arbitration scheme of time_slot 17 */
+#define XSEM_REG_TS_17_AS					 0x28007c
+/* [RW 3] The arbitration scheme of time_slot 18 */
+#define XSEM_REG_TS_18_AS					 0x280080
+/* [RW 3] The arbitration scheme of time_slot 1 */
+#define XSEM_REG_TS_1_AS					 0x28003c
+/* [RW 3] The arbitration scheme of time_slot 2 */
+#define XSEM_REG_TS_2_AS					 0x280040
+/* [RW 3] The arbitration scheme of time_slot 3 */
+#define XSEM_REG_TS_3_AS					 0x280044
+/* [RW 3] The arbitration scheme of time_slot 4 */
+#define XSEM_REG_TS_4_AS					 0x280048
+/* [RW 3] The arbitration scheme of time_slot 5 */
+#define XSEM_REG_TS_5_AS					 0x28004c
+/* [RW 3] The arbitration scheme of time_slot 6 */
+#define XSEM_REG_TS_6_AS					 0x280050
+/* [RW 3] The arbitration scheme of time_slot 7 */
+#define XSEM_REG_TS_7_AS					 0x280054
+/* [RW 3] The arbitration scheme of time_slot 8 */
+#define XSEM_REG_TS_8_AS					 0x280058
+/* [RW 3] The arbitration scheme of time_slot 9 */
+#define XSEM_REG_TS_9_AS					 0x28005c
+/* [RW 32] Interrupt mask register #0 read/write */
+#define XSEM_REG_XSEM_INT_MASK_0				 0x280110
+#define XSEM_REG_XSEM_INT_MASK_1				 0x280120
+/* [RW 32] Parity mask register #0 read/write */
+#define XSEM_REG_XSEM_PRTY_MASK_0				 0x280130
+#define XSEM_REG_XSEM_PRTY_MASK_1				 0x280140
+#define MCPR_NVM_ACCESS_ENABLE_EN				 (1L<<0)
+#define MCPR_NVM_ACCESS_ENABLE_WR_EN				 (1L<<1)
+#define MCPR_NVM_ADDR_NVM_ADDR_VALUE				 (0xffffffL<<0)
+#define MCPR_NVM_CFG4_FLASH_SIZE				 (0x7L<<0)
+#define MCPR_NVM_COMMAND_DOIT					 (1L<<4)
+#define MCPR_NVM_COMMAND_DONE					 (1L<<3)
+#define MCPR_NVM_COMMAND_FIRST					 (1L<<7)
+#define MCPR_NVM_COMMAND_LAST					 (1L<<8)
+#define MCPR_NVM_COMMAND_WR					 (1L<<5)
+#define MCPR_NVM_COMMAND_WREN					 (1L<<16)
+#define MCPR_NVM_COMMAND_WREN_BITSHIFT				 16
+#define MCPR_NVM_COMMAND_WRDI					 (1L<<17)
+#define MCPR_NVM_COMMAND_WRDI_BITSHIFT				 17
+#define MCPR_NVM_SW_ARB_ARB_ARB1				 (1L<<9)
+#define MCPR_NVM_SW_ARB_ARB_REQ_CLR1				 (1L<<5)
+#define MCPR_NVM_SW_ARB_ARB_REQ_SET1				 (1L<<1)
+#define BIGMAC_REGISTER_BMAC_CONTROL				 (0x00<<3)
+#define BIGMAC_REGISTER_BMAC_XGXS_CONTROL			 (0x01<<3)
+#define BIGMAC_REGISTER_CNT_MAX_SIZE				 (0x05<<3)
+#define BIGMAC_REGISTER_RX_CONTROL				 (0x21<<3)
+#define BIGMAC_REGISTER_RX_LLFC_MSG_FLDS			 (0x46<<3)
+#define BIGMAC_REGISTER_RX_MAX_SIZE				 (0x23<<3)
+#define BIGMAC_REGISTER_RX_STAT_GR64				 (0x26<<3)
+#define BIGMAC_REGISTER_RX_STAT_GRIPJ				 (0x42<<3)
+#define BIGMAC_REGISTER_TX_CONTROL				 (0x07<<3)
+#define BIGMAC_REGISTER_TX_MAX_SIZE				 (0x09<<3)
+#define BIGMAC_REGISTER_TX_PAUSE_THRESHOLD			 (0x0A<<3)
+#define BIGMAC_REGISTER_TX_SOURCE_ADDR				 (0x08<<3)
+#define BIGMAC_REGISTER_TX_STAT_GTBYT				 (0x20<<3)
+#define BIGMAC_REGISTER_TX_STAT_GTPKT				 (0x0C<<3)
+#define EMAC_MDIO_COMM_COMMAND_ADDRESS				 (0L<<26)
+#define EMAC_MDIO_COMM_COMMAND_READ_22				 (2L<<26)
+#define EMAC_MDIO_COMM_COMMAND_READ_45				 (3L<<26)
+#define EMAC_MDIO_COMM_COMMAND_WRITE_22 			 (1L<<26)
+#define EMAC_MDIO_COMM_COMMAND_WRITE_45 			 (1L<<26)
+#define EMAC_MDIO_COMM_DATA					 (0xffffL<<0)
+#define EMAC_MDIO_COMM_START_BUSY				 (1L<<29)
+#define EMAC_MDIO_MODE_AUTO_POLL				 (1L<<4)
+#define EMAC_MDIO_MODE_CLAUSE_45				 (1L<<31)
+#define EMAC_MODE_25G_MODE					 (1L<<5)
+#define EMAC_MODE_ACPI_RCVD					 (1L<<20)
+#define EMAC_MODE_HALF_DUPLEX					 (1L<<1)
+#define EMAC_MODE_MPKT						 (1L<<18)
+#define EMAC_MODE_MPKT_RCVD					 (1L<<19)
+#define EMAC_MODE_PORT_GMII					 (2L<<2)
+#define EMAC_MODE_PORT_MII					 (1L<<2)
+#define EMAC_MODE_PORT_MII_10M					 (3L<<2)
+#define EMAC_MODE_RESET 					 (1L<<0)
+#define EMAC_REG_EMAC_MAC_MATCH 				 0x10
+#define EMAC_REG_EMAC_MDIO_COMM 				 0xac
+#define EMAC_REG_EMAC_MDIO_MODE 				 0xb4
+#define EMAC_REG_EMAC_MODE					 0x0
+#define EMAC_REG_EMAC_RX_MODE					 0xc8
+#define EMAC_REG_EMAC_RX_MTU_SIZE				 0x9c
+#define EMAC_REG_EMAC_RX_STAT_AC				 0x180
+#define EMAC_REG_EMAC_RX_STAT_AC_28				 0x1f4
+#define EMAC_REG_EMAC_RX_STAT_AC_COUNT				 23
+#define EMAC_REG_EMAC_TX_MODE					 0xbc
+#define EMAC_REG_EMAC_TX_STAT_AC				 0x280
+#define EMAC_REG_EMAC_TX_STAT_AC_COUNT				 22
+#define EMAC_RX_MODE_FLOW_EN					 (1L<<2)
+#define EMAC_RX_MODE_KEEP_VLAN_TAG				 (1L<<10)
+#define EMAC_RX_MODE_PROMISCUOUS				 (1L<<8)
+#define EMAC_RX_MTU_SIZE_JUMBO_ENA				 (1L<<31)
+#define EMAC_TX_MODE_EXT_PAUSE_EN				 (1L<<3)
+#define EMAC_TX_MODE_RESET					 (1L<<0)
+#define MISC_REGISTERS_RESET_REG_1_CLEAR			 0x588
+#define MISC_REGISTERS_RESET_REG_1_SET				 0x584
+#define MISC_REGISTERS_RESET_REG_2_CLEAR			 0x598
+#define MISC_REGISTERS_RESET_REG_2_RST_BMAC0			 (0x1<<0)
+#define MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE		 (0x1<<14)
+#define MISC_REGISTERS_RESET_REG_2_SET				 0x594
+#define MISC_REGISTERS_RESET_REG_3_CLEAR			 0x5a8
+#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ	 (0x1<<1)
+#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN	 (0x1<<2)
+#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD (0x1<<3)
+#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW  (0x1<<0)
+#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ	 (0x1<<5)
+#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN	 (0x1<<6)
+#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD  (0x1<<7)
+#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW	 (0x1<<4)
+#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB (0x1<<8)
+#define MISC_REGISTERS_RESET_REG_3_SET				 0x5a4
+#define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR		      (1<<18)
+#define AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT		      (1<<31)
+#define AEU_INPUTS_ATTN_BITS_CDU_HW_INTERRUPT		      (1<<9)
+#define AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR		      (1<<8)
+#define AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT		      (1<<7)
+#define AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR		      (1<<6)
+#define AEU_INPUTS_ATTN_BITS_CSDM_HW_INTERRUPT		      (1<<29)
+#define AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR		      (1<<28)
+#define AEU_INPUTS_ATTN_BITS_CSEMI_HW_INTERRUPT 	      (1<<1)
+#define AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR 	      (1<<0)
+#define AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR 	      (1<<18)
+#define AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT		      (1<<11)
+#define AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT	      (1<<13)
+#define AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR	      (1<<12)
+#define AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR		      (1<<12)
+#define AEU_INPUTS_ATTN_BITS_MISC_HW_INTERRUPT		      (1<<15)
+#define AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR		      (1<<14)
+#define AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR	      (1<<20)
+#define AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR	      (1<<0)
+#define AEU_INPUTS_ATTN_BITS_PBF_HW_INTERRUPT		      (1<<31)
+#define AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT		      (1<<3)
+#define AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR		      (1<<2)
+#define AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_HW_INTERRUPT   (1<<5)
+#define AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR   (1<<4)
+#define AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT		      (1<<3)
+#define AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR		      (1<<2)
+#define AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR	      (1<<22)
+#define AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT		      (1<<27)
+#define AEU_INPUTS_ATTN_BITS_TIMERS_HW_INTERRUPT	      (1<<5)
+#define AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT		      (1<<25)
+#define AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR		      (1<<24)
+#define AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT 	      (1<<29)
+#define AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR 	      (1<<28)
+#define AEU_INPUTS_ATTN_BITS_UCM_HW_INTERRUPT		      (1<<23)
+#define AEU_INPUTS_ATTN_BITS_UPB_HW_INTERRUPT		      (1<<27)
+#define AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR		      (1<<26)
+#define AEU_INPUTS_ATTN_BITS_USDM_HW_INTERRUPT		      (1<<21)
+#define AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR		      (1<<20)
+#define AEU_INPUTS_ATTN_BITS_USEMI_HW_INTERRUPT 	      (1<<25)
+#define AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR 	      (1<<24)
+#define AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR       (1<<16)
+#define AEU_INPUTS_ATTN_BITS_XCM_HW_INTERRUPT		      (1<<9)
+#define AEU_INPUTS_ATTN_BITS_XSDM_HW_INTERRUPT		      (1<<7)
+#define AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR		      (1<<6)
+#define AEU_INPUTS_ATTN_BITS_XSEMI_HW_INTERRUPT 	      (1<<11)
+#define AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR 	      (1<<10)
+#define RESERVED_GENERAL_ATTENTION_BIT_0	0
+
+#define EVEREST_GEN_ATTN_IN_USE_MASK		0x3e0
+#define EVEREST_LATCHED_ATTN_IN_USE_MASK	0xffe00000
+
+#define RESERVED_GENERAL_ATTENTION_BIT_6	6
+#define RESERVED_GENERAL_ATTENTION_BIT_7	7
+#define RESERVED_GENERAL_ATTENTION_BIT_8	8
+#define RESERVED_GENERAL_ATTENTION_BIT_9	9
+#define RESERVED_GENERAL_ATTENTION_BIT_10	10
+#define RESERVED_GENERAL_ATTENTION_BIT_11	11
+#define RESERVED_GENERAL_ATTENTION_BIT_12	12
+#define RESERVED_GENERAL_ATTENTION_BIT_13	13
+#define RESERVED_GENERAL_ATTENTION_BIT_14	14
+#define RESERVED_GENERAL_ATTENTION_BIT_15	15
+#define RESERVED_GENERAL_ATTENTION_BIT_16	16
+#define RESERVED_GENERAL_ATTENTION_BIT_17	17
+#define RESERVED_GENERAL_ATTENTION_BIT_18	18
+#define RESERVED_GENERAL_ATTENTION_BIT_19	19
+#define RESERVED_GENERAL_ATTENTION_BIT_20	20
+#define RESERVED_GENERAL_ATTENTION_BIT_21	21
+
+/* storm asserts attention bits */
+#define TSTORM_FATAL_ASSERT_ATTENTION_BIT     RESERVED_GENERAL_ATTENTION_BIT_7
+#define USTORM_FATAL_ASSERT_ATTENTION_BIT     RESERVED_GENERAL_ATTENTION_BIT_8
+#define CSTORM_FATAL_ASSERT_ATTENTION_BIT     RESERVED_GENERAL_ATTENTION_BIT_9
+#define XSTORM_FATAL_ASSERT_ATTENTION_BIT     RESERVED_GENERAL_ATTENTION_BIT_10
+
+/* mcp error attention bit */
+#define MCP_FATAL_ASSERT_ATTENTION_BIT	      RESERVED_GENERAL_ATTENTION_BIT_11
+
+#define LATCHED_ATTN_RBCR			23
+#define LATCHED_ATTN_RBCT			24
+#define LATCHED_ATTN_RBCN			25
+#define LATCHED_ATTN_RBCU			26
+#define LATCHED_ATTN_RBCP			27
+#define LATCHED_ATTN_TIMEOUT_GRC		28
+#define LATCHED_ATTN_RSVD_GRC			29
+#define LATCHED_ATTN_ROM_PARITY_MCP		30
+#define LATCHED_ATTN_UM_RX_PARITY_MCP		31
+#define LATCHED_ATTN_UM_TX_PARITY_MCP		32
+#define LATCHED_ATTN_SCPAD_PARITY_MCP		33
+
+#define GENERAL_ATTEN_WORD(atten_name)	       ((94 + atten_name) / 32)
+#define GENERAL_ATTEN_OFFSET(atten_name)       (1 << ((94 + atten_name) % 32))
+/*
+ * This file defines GRC base address for every block.
+ * This file is included by chipsim, asm microcode and cpp microcode.
+ * These values are used in Design.xml on regBase attribute
+ * Use the base with the generated offsets of specific registers.
+ */
+
+#define GRCBASE_PXPCS		0x000000
+#define GRCBASE_PCICONFIG	0x002000
+#define GRCBASE_PCIREG		0x002400
+#define GRCBASE_EMAC0		0x008000
+#define GRCBASE_EMAC1		0x008400
+#define GRCBASE_DBU		0x008800
+#define GRCBASE_MISC		0x00A000
+#define GRCBASE_DBG		0x00C000
+#define GRCBASE_NIG		0x010000
+#define GRCBASE_XCM		0x020000
+#define GRCBASE_PRS		0x040000
+#define GRCBASE_SRCH		0x040400
+#define GRCBASE_TSDM		0x042000
+#define GRCBASE_TCM		0x050000
+#define GRCBASE_BRB1		0x060000
+#define GRCBASE_MCP		0x080000
+#define GRCBASE_UPB		0x0C1000
+#define GRCBASE_CSDM		0x0C2000
+#define GRCBASE_USDM		0x0C4000
+#define GRCBASE_CCM		0x0D0000
+#define GRCBASE_UCM		0x0E0000
+#define GRCBASE_CDU		0x101000
+#define GRCBASE_DMAE		0x102000
+#define GRCBASE_PXP		0x103000
+#define GRCBASE_CFC		0x104000
+#define GRCBASE_HC		0x108000
+#define GRCBASE_PXP2		0x120000
+#define GRCBASE_PBF		0x140000
+#define GRCBASE_XPB		0x161000
+#define GRCBASE_TIMERS		0x164000
+#define GRCBASE_XSDM		0x166000
+#define GRCBASE_QM		0x168000
+#define GRCBASE_DQ		0x170000
+#define GRCBASE_TSEM		0x180000
+#define GRCBASE_CSEM		0x200000
+#define GRCBASE_XSEM		0x280000
+#define GRCBASE_USEM		0x300000
+#define GRCBASE_MISC_AEU	GRCBASE_MISC
+
+
+/*the offset of the configuration space in the pci core register*/
+#define PCICFG_OFFSET					0x2000
+#define PCICFG_VENDOR_ID_OFFSET 			0x00
+#define PCICFG_DEVICE_ID_OFFSET 			0x02
+#define PCICFG_SUBSYSTEM_VENDOR_ID_OFFSET		0x2c
+#define PCICFG_SUBSYSTEM_ID_OFFSET			0x2e
+#define PCICFG_INT_LINE 				0x3c
+#define PCICFG_INT_PIN					0x3d
+#define PCICFG_CACHE_LINE_SIZE				0x0c
+#define PCICFG_LATENCY_TIMER				0x0d
+#define PCICFG_REVESION_ID				0x08
+#define PCICFG_BAR_1_LOW				0x10
+#define PCICFG_BAR_1_HIGH				0x14
+#define PCICFG_BAR_2_LOW				0x18
+#define PCICFG_BAR_2_HIGH				0x1c
+#define PCICFG_GRC_ADDRESS				0x78
+#define PCICFG_GRC_DATA 				0x80
+#define PCICFG_DEVICE_CONTROL				0xb4
+#define PCICFG_LINK_CONTROL				0xbc
+
+#define BAR_USTRORM_INTMEM				0x400000
+#define BAR_CSTRORM_INTMEM				0x410000
+#define BAR_XSTRORM_INTMEM				0x420000
+#define BAR_TSTRORM_INTMEM				0x430000
+
+#define BAR_IGU_INTMEM					0x440000
+
+#define BAR_DOORBELL_OFFSET				0x800000
+
+#define BAR_ME_REGISTER 				0x450000
+
+
+#define GRC_CONFIG_2_SIZE_REG		    0x408 /* config_2 offset */
+#define PCI_CONFIG_2_BAR1_SIZE			    (0xfL<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_DISABLED 	(0L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_64K		(1L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_128K		(2L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_256K		(3L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_512K		(4L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_1M		(5L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_2M		(6L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_4M		(7L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_8M		(8L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_16M		(9L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_32M		(10L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_64M		(11L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_128M		(12L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_256M		(13L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_512M		(14L<<0)
+#define PCI_CONFIG_2_BAR1_SIZE_1G		(15L<<0)
+#define PCI_CONFIG_2_BAR1_64ENA 		    (1L<<4)
+#define PCI_CONFIG_2_EXP_ROM_RETRY		    (1L<<5)
+#define PCI_CONFIG_2_CFG_CYCLE_RETRY		    (1L<<6)
+#define PCI_CONFIG_2_FIRST_CFG_DONE		    (1L<<7)
+#define PCI_CONFIG_2_EXP_ROM_SIZE		    (0xffL<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_DISABLED	(0L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_2K		(1L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_4K		(2L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_8K		(3L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_16K		(4L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_32K		(5L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_64K		(6L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_128K		(7L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_256K		(8L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_512K		(9L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_1M		(10L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_2M		(11L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_4M		(12L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_8M		(13L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_16M		(14L<<8)
+#define PCI_CONFIG_2_EXP_ROM_SIZE_32M		(15L<<8)
+#define PCI_CONFIG_2_BAR_PREFETCH		    (1L<<16)
+#define PCI_CONFIG_2_RESERVED0			    (0x7fffL<<17)
+
+/* config_3 offset */
+#define GRC_CONFIG_3_SIZE_REG				(0x40c)
+#define PCI_CONFIG_3_STICKY_BYTE		    (0xffL<<0)
+#define PCI_CONFIG_3_FORCE_PME			    (1L<<24)
+#define PCI_CONFIG_3_PME_STATUS 		    (1L<<25)
+#define PCI_CONFIG_3_PME_ENABLE 		    (1L<<26)
+#define PCI_CONFIG_3_PM_STATE			    (0x3L<<27)
+#define PCI_CONFIG_3_VAUX_PRESET		    (1L<<30)
+#define PCI_CONFIG_3_PCI_POWER			    (1L<<31)
+
+/* config_2 offset */
+#define GRC_CONFIG_2_SIZE_REG		    0x408
+
+#define GRC_BAR2_CONFIG 				0x4e0
+#define PCI_CONFIG_2_BAR2_SIZE			    (0xfL<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_DISABLED 	    (0L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_64K		    (1L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_128K		    (2L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_256K		    (3L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_512K		    (4L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_1M		    (5L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_2M		    (6L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_4M		    (7L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_8M		    (8L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_16M		    (9L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_32M		    (10L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_64M		    (11L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_128M		    (12L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_256M		    (13L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_512M		    (14L<<0)
+#define PCI_CONFIG_2_BAR2_SIZE_1G		    (15L<<0)
+#define PCI_CONFIG_2_BAR2_64ENA 		    (1L<<4)
+
+#define PCI_PM_DATA_A					(0x410)
+#define PCI_PM_DATA_B					(0x414)
+#define PCI_ID_VAL1					(0x434)
+#define PCI_ID_VAL2					(0x438)
+
+#define MDIO_REG_BANK_CL73_IEEEB0			0x0
+#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL		0x0
+#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN	0x0200
+#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN		0x1000
+#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_MAIN_RST	0x8000
+
+#define MDIO_REG_BANK_CL73_IEEEB1			0x10
+#define MDIO_CL73_IEEEB1_AN_ADV2			0x01
+#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M		0x0000
+#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX		0x0020
+#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4		0x0040
+#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KR		0x0080
+
+#define MDIO_REG_BANK_RX0				0x80b0
+#define MDIO_RX0_RX_EQ_BOOST				0x1c
+#define MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK	0x7
+#define MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL		0x10
+
+#define MDIO_REG_BANK_RX1				0x80c0
+#define MDIO_RX1_RX_EQ_BOOST				0x1c
+#define MDIO_RX1_RX_EQ_BOOST_EQUALIZER_CTRL_MASK	0x7
+#define MDIO_RX1_RX_EQ_BOOST_OFFSET_CTRL		0x10
+
+#define MDIO_REG_BANK_RX2				0x80d0
+#define MDIO_RX2_RX_EQ_BOOST				0x1c
+#define MDIO_RX2_RX_EQ_BOOST_EQUALIZER_CTRL_MASK	0x7
+#define MDIO_RX2_RX_EQ_BOOST_OFFSET_CTRL		0x10
+
+#define MDIO_REG_BANK_RX3				0x80e0
+#define MDIO_RX3_RX_EQ_BOOST				0x1c
+#define MDIO_RX3_RX_EQ_BOOST_EQUALIZER_CTRL_MASK	0x7
+#define MDIO_RX3_RX_EQ_BOOST_OFFSET_CTRL		0x10
+
+#define MDIO_REG_BANK_RX_ALL				0x80f0
+#define MDIO_RX_ALL_RX_EQ_BOOST 			0x1c
+#define MDIO_RX_ALL_RX_EQ_BOOST_EQUALIZER_CTRL_MASK	0x7
+#define MDIO_RX_ALL_RX_EQ_BOOST_OFFSET_CTRL		0x10
+
+#define MDIO_REG_BANK_TX0				0x8060
+#define MDIO_TX0_TX_DRIVER				0x17
+#define MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK		0xf000
+#define MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT		12
+#define MDIO_TX0_TX_DRIVER_IDRIVER_MASK 		0x0f00
+#define MDIO_TX0_TX_DRIVER_IDRIVER_SHIFT		8
+#define MDIO_TX0_TX_DRIVER_IPREDRIVER_MASK		0x00f0
+#define MDIO_TX0_TX_DRIVER_IPREDRIVER_SHIFT		4
+#define MDIO_TX0_TX_DRIVER_IFULLSPD_MASK		0x000e
+#define MDIO_TX0_TX_DRIVER_IFULLSPD_SHIFT		1
+#define MDIO_TX0_TX_DRIVER_ICBUF1T			1
+
+#define MDIO_REG_BANK_XGXS_BLOCK0			0x8000
+#define MDIO_BLOCK0_XGXS_CONTROL			0x10
+
+#define MDIO_REG_BANK_XGXS_BLOCK1			0x8010
+#define MDIO_BLOCK1_LANE_CTRL0				0x15
+#define MDIO_BLOCK1_LANE_CTRL1				0x16
+#define MDIO_BLOCK1_LANE_CTRL2				0x17
+#define MDIO_BLOCK1_LANE_PRBS				0x19
+
+#define MDIO_REG_BANK_XGXS_BLOCK2			0x8100
+#define MDIO_XGXS_BLOCK2_RX_LN_SWAP			0x10
+#define MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE		0x8000
+#define MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE	0x4000
+#define MDIO_XGXS_BLOCK2_TX_LN_SWAP			0x11
+#define MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE		0x8000
+#define MDIO_XGXS_BLOCK2_TEST_MODE_LANE 		0x15
+
+#define MDIO_REG_BANK_GP_STATUS 			0x8120
+#define MDIO_GP_STATUS_TOP_AN_STATUS1			    0x1B
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE 0x0001
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE 0x0002
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS	    0x0004
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS	    0x0008
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE 0x0010
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_LP_NP_BAM_ABLE   0x0020
+
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE 0x0040
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE 0x0080
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK     0x3f00
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M	    0x0000
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M     0x0100
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G	    0x0200
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G     0x0300
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G	    0x0400
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G	    0x0500
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG  0x0600
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4  0x0700
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG  0x0800
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G    0x0900
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G	    0x0A00
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G	    0x0B00
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G	    0x0C00
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX    0x0D00
+#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4  0x0E00
+
+
+#define MDIO_REG_BANK_10G_PARALLEL_DETECT		0x8130
+#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL	    0x11
+#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN 0x1
+#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK	    0x13
+#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT	    (0xb71<<1)
+
+#define MDIO_REG_BANK_SERDES_DIGITAL			0x8300
+#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1		0x10
+#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE 0x0001
+#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_TBI_IF	0x0002
+#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN	  0x0004
+#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT 0x0008
+#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET	0x0010
+#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE	0x0020
+#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2		0x11
+#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN	0x0001
+#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_AN_FST_TMR 0x0040
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1		0x14
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_DUPLEX	0x0004
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_MASK	0x0018
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_SHIFT 3
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_2_5G	0x0018
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_1G	0x0010
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_100M	0x0008
+#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_10M	0x0000
+#define MDIO_SERDES_DIGITAL_MISC1			0x18
+#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_MASK	0xE000
+#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_25M	0x0000
+#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_100M	0x2000
+#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_125M	0x4000
+#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M	0x6000
+#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_187_5M	0x8000
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL	0x0010
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK	0x000f
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_2_5G	0x0000
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_5G	0x0001
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_6G	0x0002
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_HIG	0x0003
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4	0x0004
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_12G	0x0005
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_12_5G	0x0006
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G	0x0007
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_15G	0x0008
+#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_16G	0x0009
+
+#define MDIO_REG_BANK_OVER_1G				0x8320
+#define MDIO_OVER_1G_DIGCTL_3_4 			0x14
+#define MDIO_OVER_1G_DIGCTL_3_4_MP_ID_MASK		0xffe0
+#define MDIO_OVER_1G_DIGCTL_3_4_MP_ID_SHIFT		5
+#define MDIO_OVER_1G_UP1				0x19
+#define MDIO_OVER_1G_UP1_2_5G				0x0001
+#define MDIO_OVER_1G_UP1_5G				0x0002
+#define MDIO_OVER_1G_UP1_6G				0x0004
+#define MDIO_OVER_1G_UP1_10G				0x0010
+#define MDIO_OVER_1G_UP1_10GH				0x0008
+#define MDIO_OVER_1G_UP1_12G				0x0020
+#define MDIO_OVER_1G_UP1_12_5G				0x0040
+#define MDIO_OVER_1G_UP1_13G				0x0080
+#define MDIO_OVER_1G_UP1_15G				0x0100
+#define MDIO_OVER_1G_UP1_16G				0x0200
+#define MDIO_OVER_1G_UP2				0x1A
+#define MDIO_OVER_1G_UP2_IPREDRIVER_MASK		0x0007
+#define MDIO_OVER_1G_UP2_IDRIVER_MASK			0x0038
+#define MDIO_OVER_1G_UP2_PREEMPHASIS_MASK		0x03C0
+#define MDIO_OVER_1G_UP3				0x1B
+#define MDIO_OVER_1G_UP3_HIGIG2 			0x0001
+#define MDIO_OVER_1G_LP_UP1				0x1C
+#define MDIO_OVER_1G_LP_UP2				0x1D
+#define MDIO_OVER_1G_LP_UP2_MR_ADV_OVER_1G_MASK 	0x03ff
+#define MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK		0x0780
+#define MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT		7
+#define MDIO_OVER_1G_LP_UP3				0x1E
+
+#define MDIO_REG_BANK_BAM_NEXT_PAGE			0x8350
+#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL		0x10
+#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE	0x0001
+#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN	0x0002
+
+#define MDIO_REG_BANK_CL73_USERB0			0x8370
+#define MDIO_CL73_USERB0_CL73_BAM_CTRL1 		0x12
+#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN			0x8000
+#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN	0x4000
+#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN	0x2000
+#define MDIO_CL73_USERB0_CL73_BAM_CTRL3 		0x14
+#define MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR 0x0001
+
+#define MDIO_REG_BANK_AER_BLOCK 			0xFFD0
+#define MDIO_AER_BLOCK_AER_REG				0x1E
+
+#define MDIO_REG_BANK_COMBO_IEEE0			0xFFE0
+#define MDIO_COMBO_IEEE0_MII_CONTROL			0x10
+#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK	0x2040
+#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_10	0x0000
+#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100	0x2000
+#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000	0x0040
+#define MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX 	0x0100
+#define MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN		0x0200
+#define MDIO_COMBO_IEEO_MII_CONTROL_AN_EN		0x1000
+#define MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK		0x4000
+#define MDIO_COMBO_IEEO_MII_CONTROL_RESET		0x8000
+#define MDIO_COMBO_IEEE0_MII_STATUS			0x11
+#define MDIO_COMBO_IEEE0_MII_STATUS_LINK_PASS		0x0004
+#define MDIO_COMBO_IEEE0_MII_STATUS_AUTONEG_COMPLETE	0x0020
+#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV			0x14
+#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX	0x0020
+#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_HALF_DUPLEX	0x0040
+#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK	0x0180
+#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE	0x0000
+#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC	0x0080
+#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC	0x0100
+#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH	0x0180
+#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_NEXT_PAGE 	0x8000
+#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1 0x15
+#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_NEXT_PAGE    0x8000
+#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_ACK	     0x4000
+#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_MASK   0x0180
+#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_NONE\
+	0x0000
+#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_BOTH\
+	0x0180
+#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_HALF_DUP_CAP 0x0040
+#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_FULL_DUP_CAP 0x0020
+#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_SGMII_MODE   0x0001
+
+
+#define EXT_PHY_OPT_PMA_PMD_DEVAD			0x1
+#define EXT_PHY_OPT_WIS_DEVAD				0x2
+#define EXT_PHY_OPT_PCS_DEVAD				0x3
+#define EXT_PHY_OPT_PHY_XS_DEVAD			0x4
+#define EXT_PHY_OPT_CNTL				0x0
+#define EXT_PHY_OPT_PMD_RX_SD				0xa
+#define EXT_PHY_OPT_PMD_MISC_CNTL			0xca0a
+#define EXT_PHY_OPT_PHY_IDENTIFIER			0xc800
+#define EXT_PHY_OPT_PMD_DIGITAL_CNT			0xc808
+#define EXT_PHY_OPT_PMD_DIGITAL_SATUS			0xc809
+#define EXT_PHY_OPT_CMU_PLL_BYPASS			0xca09
+#define EXT_PHY_OPT_LASI_CNTL				0x9002
+#define EXT_PHY_OPT_RX_ALARM				0x9003
+#define EXT_PHY_OPT_LASI_STATUS 			0x9005
+#define EXT_PHY_OPT_PCS_STATUS				0x0020
+#define EXT_PHY_OPT_XGXS_LANE_STATUS			0x0018
+
+#define EXT_PHY_KR_PMA_PMD_DEVAD			0x1
+#define EXT_PHY_KR_PCS_DEVAD				0x3
+#define EXT_PHY_KR_AUTO_NEG_DEVAD			0x7
+#define EXT_PHY_KR_CTRL 				0x0000
+#define EXT_PHY_KR_CTRL2				0x0007
+#define EXT_PHY_KR_PCS_STATUS				0x0020
+#define EXT_PHY_KR_PMD_CTRL				0x0096
+#define EXT_PHY_KR_LASI_CNTL				0x9002
+#define EXT_PHY_KR_LASI_STATUS				0x9005
+#define EXT_PHY_KR_MISC_CTRL1				0xca85
+#define EXT_PHY_KR_GEN_CTRL				0xca10
+#define EXT_PHY_KR_ROM_CODE				0xca19
+
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 49a198206e3d..2039f7838f2d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2517,7 +2517,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 		fl.fl4_dst = targets[i];
 		fl.fl4_tos = RTO_ONLINK;
 
-		rv = ip_route_output_key(&rt, &fl);
+		rv = ip_route_output_key(&init_net, &rt, &fl);
 		if (rv) {
 			if (net_ratelimit()) {
 				printk(KERN_WARNING DRV_NAME
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
new file mode 100644
index 000000000000..57def0d57371
--- /dev/null
+++ b/drivers/net/can/Kconfig
@@ -0,0 +1,25 @@
+menu "CAN Device Drivers"
+	depends on CAN
+
+config CAN_VCAN
+	tristate "Virtual Local CAN Interface (vcan)"
+	depends on CAN
+	default N
+	---help---
+	  Similar to the network loopback devices, vcan offers a
+	  virtual local CAN interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called vcan.
+
+config CAN_DEBUG_DEVICES
+	bool "CAN devices debugging messages"
+	depends on CAN
+	default N
+	---help---
+	  Say Y here if you want the CAN device drivers to produce a bunch of
+	  debug messages to the system log.  Select this if you are having
+	  a problem with CAN support and want to see more of what is going
+	  on.
+
+endmenu
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
new file mode 100644
index 000000000000..c4bead705cd9
--- /dev/null
+++ b/drivers/net/can/Makefile
@@ -0,0 +1,5 @@
+#
+#  Makefile for the Linux Controller Area Network drivers.
+#
+
+obj-$(CONFIG_CAN_VCAN)		+= vcan.o
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
new file mode 100644
index 000000000000..103f0f1df280
--- /dev/null
+++ b/drivers/net/can/vcan.c
@@ -0,0 +1,169 @@
+/*
+ * vcan.c - Virtual CAN interface
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/can.h>
+#include <net/rtnetlink.h>
+
+static __initdata const char banner[] =
+	KERN_INFO "vcan: Virtual CAN interface driver\n";
+
+MODULE_DESCRIPTION("virtual CAN interface");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>");
+
+
+/*
+ * CAN test feature:
+ * Enable the echo on driver level for testing the CAN core echo modes.
+ * See Documentation/networking/can.txt for details.
+ */
+
+static int echo; /* echo testing. Default: 0 (Off) */
+module_param(echo, bool, S_IRUGO);
+MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
+
+
+static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_device_stats *stats = &dev->stats;
+
+	stats->rx_packets++;
+	stats->rx_bytes += skb->len;
+
+	skb->protocol  = htons(ETH_P_CAN);
+	skb->pkt_type  = PACKET_BROADCAST;
+	skb->dev       = dev;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	netif_rx(skb);
+}
+
+static int vcan_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_device_stats *stats = &dev->stats;
+	int loop;
+
+	stats->tx_packets++;
+	stats->tx_bytes += skb->len;
+
+	/* set flag whether this packet has to be looped back */
+	loop = skb->pkt_type == PACKET_LOOPBACK;
+
+	if (!echo) {
+		/* no echo handling available inside this driver */
+
+		if (loop) {
+			/*
+			 * only count the packets here, because the
+			 * CAN core already did the echo for us
+			 */
+			stats->rx_packets++;
+			stats->rx_bytes += skb->len;
+		}
+		kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+
+	/* perform standard echo handling for CAN network interfaces */
+
+	if (loop) {
+		struct sock *srcsk = skb->sk;
+
+		skb = skb_share_check(skb, GFP_ATOMIC);
+		if (!skb)
+			return NETDEV_TX_OK;
+
+		/* receive with packet counting */
+		skb->sk = srcsk;
+		vcan_rx(skb, dev);
+	} else {
+		/* no looped packets => no counting */
+		kfree_skb(skb);
+	}
+	return NETDEV_TX_OK;
+}
+
+static void vcan_setup(struct net_device *dev)
+{
+	dev->type              = ARPHRD_CAN;
+	dev->mtu               = sizeof(struct can_frame);
+	dev->hard_header_len   = 0;
+	dev->addr_len          = 0;
+	dev->tx_queue_len      = 0;
+	dev->flags             = IFF_NOARP;
+
+	/* set flags according to driver capabilities */
+	if (echo)
+		dev->flags |= IFF_ECHO;
+
+	dev->hard_start_xmit   = vcan_tx;
+	dev->destructor        = free_netdev;
+}
+
+static struct rtnl_link_ops vcan_link_ops __read_mostly = {
+       .kind           = "vcan",
+       .setup          = vcan_setup,
+};
+
+static __init int vcan_init_module(void)
+{
+	printk(banner);
+
+	if (echo)
+		printk(KERN_INFO "vcan: enabled echo on driver level.\n");
+
+	return rtnl_link_register(&vcan_link_ops);
+}
+
+static __exit void vcan_cleanup_module(void)
+{
+	rtnl_link_unregister(&vcan_link_ops);
+}
+
+module_init(vcan_init_module);
+module_exit(vcan_cleanup_module);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index d66915d82b24..14299f8063af 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -4394,7 +4394,7 @@ static struct {
 	{"tx_fifo_errors"},
 	{"tx_packets"}
 };
-#define CAS_NUM_STAT_KEYS (sizeof(ethtool_cassini_statnames)/ETH_GSTRING_LEN)
+#define CAS_NUM_STAT_KEYS ARRAY_SIZE(ethtool_cassini_statnames)
 
 static struct {
 	const int offsets;	/* neg. values for 2nd arg to cas_read_phy */
@@ -5085,7 +5085,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
 
 	/* give us access to cassini registers */
 	cp->regs = pci_iomap(pdev, 0, casreg_len);
-	if (cp->regs == 0UL) {
+	if (!cp->regs) {
 		dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
 		goto err_out_free_res;
 	}
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 846ca5383d3c..4bd2455b0fe3 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -379,7 +379,7 @@ extern int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config
 extern const struct board_info *t1_get_board_info(unsigned int board_id);
 extern const struct board_info *t1_get_board_info_from_ids(unsigned int devid,
 						    unsigned short ssid);
-extern int t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data);
+extern int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data);
 extern int t1_get_board_rev(adapter_t *adapter, const struct board_info *bi,
 		     struct adapter_params *p);
 extern int t1_init_hw_modules(adapter_t *adapter);
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index c5975047c89b..a509337eab2d 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -814,7 +814,7 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
 
 	e->magic = EEPROM_MAGIC(adapter);
 	for (i = e->offset & ~3; i < e->offset + e->len; i += sizeof(u32))
-		t1_seeprom_read(adapter, i, (u32 *)&buf[i]);
+		t1_seeprom_read(adapter, i, (__le32 *)&buf[i]);
 	memcpy(data, buf + e->offset, e->len);
 	return 0;
 }
@@ -1042,7 +1042,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 		pci_using_dac = 1;
 
 		if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
-			CH_ERR("%s: unable to obtain 64-bit DMA for"
+			CH_ERR("%s: unable to obtain 64-bit DMA for "
 			       "consistent allocations\n", pci_name(pdev));
 			err = -ENODEV;
 			goto out_disable_pdev;
diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c
index d7c5406a6c3f..1e0749e000b0 100644
--- a/drivers/net/chelsio/espi.c
+++ b/drivers/net/chelsio/espi.c
@@ -297,6 +297,7 @@ struct peespi *t1_espi_create(adapter_t *adapter)
 	return espi;
 }
 
+#if 0
 void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
 {
 	struct peespi *espi = adapter->espi;
@@ -309,6 +310,7 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
 	writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
 	spin_unlock(&espi->lock);
 }
+#endif  /*  0  */
 
 u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
 {
diff --git a/drivers/net/chelsio/espi.h b/drivers/net/chelsio/espi.h
index 84f2c98bc4cc..5694aad4fbc0 100644
--- a/drivers/net/chelsio/espi.h
+++ b/drivers/net/chelsio/espi.h
@@ -62,7 +62,6 @@ void t1_espi_intr_disable(struct peespi *);
 int t1_espi_intr_handler(struct peespi *);
 const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi);
 
-void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val);
 u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait);
 int t1_espi_get_mon_t204(adapter_t *, u32 *, u8);
 
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index b301c0428ae0..8a7efd38e95b 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -330,6 +330,8 @@ unsigned int t1_sched_update_parms(struct sge *sge, unsigned int port,
 	return max_avail_segs * (p->mtu - 40);
 }
 
+#if 0
+
 /*
  * t1_sched_max_avail_bytes() tells the scheduler the maximum amount of
  * data that can be pushed per port.
@@ -357,6 +359,8 @@ void t1_sched_set_drain_bits_per_us(struct sge *sge, unsigned int port,
 	t1_sched_update_parms(sge, port, 0, 0);
 }
 
+#endif  /*  0  */
+
 
 /*
  * get_clock() implements a ns clock (see ktime_get)
diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h
index cced9dff91c5..8c9405123992 100644
--- a/drivers/net/chelsio/sge.h
+++ b/drivers/net/chelsio/sge.h
@@ -88,8 +88,6 @@ void t1_sge_intr_disable(struct sge *);
 void t1_sge_intr_clear(struct sge *);
 const struct sge_intr_counts *t1_sge_get_intr_counts(const struct sge *sge);
 void t1_sge_get_port_stats(const struct sge *sge, int port, struct sge_port_stats *);
-void t1_sched_set_max_avail_bytes(struct sge *, unsigned int);
-void t1_sched_set_drain_bits_per_us(struct sge *, unsigned int, unsigned int);
 unsigned int t1_sched_update_parms(struct sge *, unsigned int, unsigned int,
 			   unsigned int);
 
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index dc50151bed81..7adf30230c4f 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -563,10 +563,11 @@ struct chelsio_vpd_t {
  * written to the Control register. The hardware device will set the flag to a
  * one when 4B have been transferred to the Data register.
  */
-int t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data)
+int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data)
 {
 	int i = EEPROM_MAX_POLL;
 	u16 val;
+	u32 v;
 
 	if (addr >= EEPROMSIZE || (addr & 3))
 		return -EINVAL;
@@ -582,8 +583,8 @@ int t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data)
 		       adapter->name, addr);
 		return -EIO;
 	}
-	pci_read_config_dword(adapter->pdev, A_PCICFG_VPD_DATA, data);
-	*data = le32_to_cpu(*data);
+	pci_read_config_dword(adapter->pdev, A_PCICFG_VPD_DATA, &v);
+	*data = cpu_to_le32(v);
 	return 0;
 }
 
@@ -593,7 +594,7 @@ static int t1_eeprom_vpd_get(adapter_t *adapter, struct chelsio_vpd_t *vpd)
 
 	for (addr = 0; !ret && addr < sizeof(*vpd); addr += sizeof(u32))
 		ret = t1_seeprom_read(adapter, addr,
-				      (u32 *)((u8 *)vpd + addr));
+				      (__le32 *)((u8 *)vpd + addr));
 
 	return ret;
 }
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
index 6e12d48351b8..6ccebb830ff9 100644
--- a/drivers/net/cpmac.c
+++ b/drivers/net/cpmac.c
@@ -661,9 +661,6 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id)
 	int queue;
 	u32 status;
 
-	if (!dev)
-		return IRQ_NONE;
-
 	priv = netdev_priv(dev);
 
 	status = cpmac_read(priv->regs, CPMAC_MAC_INT_VECTOR);
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 60a62f510db7..eb305a0895fc 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -71,6 +71,7 @@ enum {				/* adapter flags */
 	USING_MSI = (1 << 1),
 	USING_MSIX = (1 << 2),
 	QUEUES_BOUND = (1 << 3),
+	TP_PARITY_INIT = (1 << 4),
 };
 
 struct fl_pg_chunk {
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 99c75d30f67a..91ee7277b813 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -681,8 +681,8 @@ int t3_phy_intr_handler(struct adapter *adapter);
 void t3_link_changed(struct adapter *adapter, int port_id);
 int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
 const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
-int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
-int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
+int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data);
+int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data);
 int t3_seeprom_wp(struct adapter *adapter, int enable);
 int t3_get_tp_version(struct adapter *adapter, u32 *vers);
 int t3_check_tpsram_version(struct adapter *adapter, int *must_load);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 61ffc925eae7..fd2e05bbb903 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -76,20 +76,20 @@ enum {
 
 #define EEPROM_MAGIC 0x38E2F10C
 
-#define CH_DEVICE(devid, ssid, idx) \
-	{ PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
+#define CH_DEVICE(devid, idx) \
+	{ PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx }
 
 static const struct pci_device_id cxgb3_pci_tbl[] = {
-	CH_DEVICE(0x20, 1, 0),	/* PE9000 */
-	CH_DEVICE(0x21, 1, 1),	/* T302E */
-	CH_DEVICE(0x22, 1, 2),	/* T310E */
-	CH_DEVICE(0x23, 1, 3),	/* T320X */
-	CH_DEVICE(0x24, 1, 1),	/* T302X */
-	CH_DEVICE(0x25, 1, 3),	/* T320E */
-	CH_DEVICE(0x26, 1, 2),	/* T310X */
-	CH_DEVICE(0x30, 1, 2),	/* T3B10 */
-	CH_DEVICE(0x31, 1, 3),	/* T3B20 */
-	CH_DEVICE(0x32, 1, 1),	/* T3B02 */
+	CH_DEVICE(0x20, 0),	/* PE9000 */
+	CH_DEVICE(0x21, 1),	/* T302E */
+	CH_DEVICE(0x22, 2),	/* T310E */
+	CH_DEVICE(0x23, 3),	/* T320X */
+	CH_DEVICE(0x24, 1),	/* T302X */
+	CH_DEVICE(0x25, 3),	/* T320E */
+	CH_DEVICE(0x26, 2),	/* T310X */
+	CH_DEVICE(0x30, 2),	/* T3B10 */
+	CH_DEVICE(0x31, 3),	/* T3B20 */
+	CH_DEVICE(0x32, 1),	/* T3B02 */
 	{0,}
 };
 
@@ -306,6 +306,77 @@ static int request_msix_data_irqs(struct adapter *adap)
 	return 0;
 }
 
+static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
+			      unsigned long n)
+{
+	int attempts = 5;
+
+	while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
+		if (!--attempts)
+			return -ETIMEDOUT;
+		msleep(10);
+	}
+	return 0;
+}
+
+static int init_tp_parity(struct adapter *adap)
+{
+	int i;
+	struct sk_buff *skb;
+	struct cpl_set_tcb_field *greq;
+	unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
+
+	t3_tp_set_offload_mode(adap, 1);
+
+	for (i = 0; i < 16; i++) {
+		struct cpl_smt_write_req *req;
+
+		skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+		req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
+		memset(req, 0, sizeof(*req));
+		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
+		req->iff = i;
+		t3_mgmt_tx(adap, skb);
+	}
+
+	for (i = 0; i < 2048; i++) {
+		struct cpl_l2t_write_req *req;
+
+		skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+		req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
+		memset(req, 0, sizeof(*req));
+		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
+		req->params = htonl(V_L2T_W_IDX(i));
+		t3_mgmt_tx(adap, skb);
+	}
+
+	for (i = 0; i < 2048; i++) {
+		struct cpl_rte_write_req *req;
+
+		skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+		req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req));
+		memset(req, 0, sizeof(*req));
+		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
+		req->l2t_idx = htonl(V_L2T_W_IDX(i));
+		t3_mgmt_tx(adap, skb);
+	}
+
+	skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL);
+	greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq));
+	memset(greq, 0, sizeof(*greq));
+	greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+	OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
+	greq->mask = cpu_to_be64(1);
+	t3_mgmt_tx(adap, skb);
+
+	i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
+	t3_tp_set_offload_mode(adap, 0);
+	return i;
+}
+
 /**
  *	setup_rss - configure RSS
  *	@adap: the adapter
@@ -336,7 +407,7 @@ static void setup_rss(struct adapter *adap)
 
 	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
 		      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
-		      V_RRCPLCPUSIZE(6), cpus, rspq_map);
+		      V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map);
 }
 
 static void init_napi(struct adapter *adap)
@@ -410,8 +481,7 @@ static int setup_sge_qsets(struct adapter *adap)
 	return 0;
 }
 
-static ssize_t attr_show(struct device *d, struct device_attribute *attr,
-			 char *buf,
+static ssize_t attr_show(struct device *d, char *buf,
 			 ssize_t(*format) (struct net_device *, char *))
 {
 	ssize_t len;
@@ -423,7 +493,7 @@ static ssize_t attr_show(struct device *d, struct device_attribute *attr,
 	return len;
 }
 
-static ssize_t attr_store(struct device *d, struct device_attribute *attr,
+static ssize_t attr_store(struct device *d,
 			  const char *buf, size_t len,
 			  ssize_t(*set) (struct net_device *, unsigned int),
 			  unsigned int min_val, unsigned int max_val)
@@ -457,7 +527,7 @@ static ssize_t format_##name(struct net_device *dev, char *buf) \
 static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
 			   char *buf) \
 { \
-	return attr_show(d, attr, buf, format_##name); \
+	return attr_show(d, buf, format_##name); \
 }
 
 static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
@@ -480,7 +550,7 @@ static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
 static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
 			      const char *buf, size_t len)
 {
-	return attr_store(d, attr, buf, len, set_nfilters, 0, ~0);
+	return attr_store(d, buf, len, set_nfilters, 0, ~0);
 }
 
 static ssize_t set_nservers(struct net_device *dev, unsigned int val)
@@ -500,7 +570,7 @@ static ssize_t set_nservers(struct net_device *dev, unsigned int val)
 static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
 			      const char *buf, size_t len)
 {
-	return attr_store(d, attr, buf, len, set_nservers, 0, ~0);
+	return attr_store(d, buf, len, set_nservers, 0, ~0);
 }
 
 #define CXGB3_ATTR_R(name, val_expr) \
@@ -524,7 +594,7 @@ static struct attribute *cxgb3_attrs[] = {
 
 static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
 
-static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
+static ssize_t tm_attr_show(struct device *d,
 			    char *buf, int sched)
 {
 	struct port_info *pi = netdev_priv(to_net_dev(d));
@@ -550,7 +620,7 @@ static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
 	return len;
 }
 
-static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
+static ssize_t tm_attr_store(struct device *d,
 			     const char *buf, size_t len, int sched)
 {
 	struct port_info *pi = netdev_priv(to_net_dev(d));
@@ -578,12 +648,12 @@ static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
 static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
 			   char *buf) \
 { \
-	return tm_attr_show(d, attr, buf, sched); \
+	return tm_attr_show(d, buf, sched); \
 } \
 static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
 			    const char *buf, size_t len) \
 { \
-	return tm_attr_store(d, attr, buf, len, sched); \
+	return tm_attr_store(d, buf, len, sched); \
 } \
 static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
 
@@ -720,7 +790,7 @@ static int upgrade_fw(struct adapter *adap)
 	else
 		dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
 			FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
-	
+
 	return ret;
 }
 
@@ -747,7 +817,7 @@ static int update_tpsram(struct adapter *adap)
 	struct device *dev = &adap->pdev->dev;
 	int ret;
 	char rev;
-	
+
 	rev = t3rev2char(adap);
 	if (!rev)
 		return 0;
@@ -761,10 +831,10 @@ static int update_tpsram(struct adapter *adap)
 			buf);
 		return ret;
 	}
-	
+
 	ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
 	if (ret)
-		goto release_tpsram;	
+		goto release_tpsram;
 
 	ret = t3_set_proto_sram(adap, tpsram->data);
 	if (ret == 0)
@@ -780,7 +850,7 @@ static int update_tpsram(struct adapter *adap)
 
 release_tpsram:
 	release_firmware(tpsram);
-	
+
 	return ret;
 }
 
@@ -818,6 +888,7 @@ static int cxgb_up(struct adapter *adap)
 		if (err)
 			goto out;
 
+		t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
 		t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
 
 		err = setup_sge_qsets(adap);
@@ -839,7 +910,8 @@ static int cxgb_up(struct adapter *adap)
 		if (err)
 			goto irq_err;
 
-		if (request_msix_data_irqs(adap)) {
+		err = request_msix_data_irqs(adap);
+		if (err) {
 			free_irq(adap->msix_info[0].vec, adap);
 			goto irq_err;
 		}
@@ -856,6 +928,16 @@ static int cxgb_up(struct adapter *adap)
 	t3_sge_start(adap);
 	t3_intr_enable(adap);
 
+	if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) &&
+	    is_offload(adap) && init_tp_parity(adap) == 0)
+		adap->flags |= TP_PARITY_INIT;
+
+	if (adap->flags & TP_PARITY_INIT) {
+		t3_write_reg(adap, A_TP_INT_CAUSE,
+			     F_CMCACHEPERR | F_ARPLUTPERR);
+		t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff);
+	}
+
 	if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
 		bind_qsets(adap);
 	adap->flags |= QUEUES_BOUND;
@@ -1560,7 +1642,7 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
 
 	e->magic = EEPROM_MAGIC;
 	for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
-		err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]);
+		err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]);
 
 	if (!err)
 		memcpy(data, buf + e->offset, e->len);
@@ -1573,7 +1655,8 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 {
 	struct port_info *pi = netdev_priv(dev);
 	struct adapter *adapter = pi->adapter;
-	u32 aligned_offset, aligned_len, *p;
+	u32 aligned_offset, aligned_len;
+	__le32 *p;
 	u8 *buf;
 	int err;
 
@@ -1587,11 +1670,11 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 		buf = kmalloc(aligned_len, GFP_KERNEL);
 		if (!buf)
 			return -ENOMEM;
-		err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf);
+		err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf);
 		if (!err && aligned_len > 4)
 			err = t3_seeprom_read(adapter,
 					      aligned_offset + aligned_len - 4,
-					      (u32 *) & buf[aligned_len - 4]);
+					      (__le32 *) & buf[aligned_len - 4]);
 		if (err)
 			goto out;
 		memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
@@ -1602,7 +1685,7 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 	if (err)
 		goto out;
 
-	for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
+	for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
 		err = t3_seeprom_write(adapter, aligned_offset, *p);
 		aligned_offset += 4;
 	}
@@ -2144,7 +2227,7 @@ static void cxgb_netpoll(struct net_device *dev)
 	for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
 		struct sge_qset *qs = &adapter->sge.qs[qidx];
 		void *source;
-		
+
 		if (adapter->flags & USING_MSIX)
 			source = qs;
 		else
@@ -2315,6 +2398,106 @@ void t3_fatal_err(struct adapter *adapter)
 
 }
 
+/**
+ * t3_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
+					     pci_channel_state_t state)
+{
+	struct adapter *adapter = pci_get_drvdata(pdev);
+	int i;
+
+	/* Stop all ports */
+	for_each_port(adapter, i) {
+		struct net_device *netdev = adapter->port[i];
+
+		if (netif_running(netdev))
+			cxgb_close(netdev);
+	}
+
+	if (is_offload(adapter) &&
+	    test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+		offload_close(&adapter->tdev);
+
+	/* Free sge resources */
+	t3_free_sge_resources(adapter);
+
+	adapter->flags &= ~FULL_INIT_DONE;
+
+	pci_disable_device(pdev);
+
+	/* Request a slot slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * t3_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev)
+{
+	struct adapter *adapter = pci_get_drvdata(pdev);
+
+	if (pci_enable_device(pdev)) {
+		dev_err(&pdev->dev,
+			"Cannot re-enable PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+	pci_set_master(pdev);
+
+	t3_prep_adapter(adapter, adapter->params.info, 1);
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * t3_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void t3_io_resume(struct pci_dev *pdev)
+{
+	struct adapter *adapter = pci_get_drvdata(pdev);
+	int i;
+
+	/* Restart the ports */
+	for_each_port(adapter, i) {
+		struct net_device *netdev = adapter->port[i];
+
+		if (netif_running(netdev)) {
+			if (cxgb_open(netdev)) {
+				dev_err(&pdev->dev,
+					"can't bring device back up"
+					" after reset\n");
+				continue;
+			}
+			netif_device_attach(netdev);
+		}
+	}
+
+	if (is_offload(adapter)) {
+		__set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
+		if (offload_open(adapter->port[0]))
+			printk(KERN_WARNING
+			       "Could not bring back offload capabilities\n");
+	}
+}
+
+static struct pci_error_handlers t3_err_handler = {
+	.error_detected = t3_io_error_detected,
+	.slot_reset = t3_io_slot_reset,
+	.resume = t3_io_resume,
+};
+
 static int __devinit cxgb_enable_msix(struct adapter *adap)
 {
 	struct msix_entry entries[SGE_QSETS + 1];
@@ -2507,7 +2690,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 		err = -ENODEV;
 		goto out_free_dev;
 	}
-		
+
 	/*
 	 * The card is now ready to go.  If any errors occur during device
 	 * registration we do not fail the whole card but rather proceed only
@@ -2584,10 +2767,6 @@ static void __devexit remove_one(struct pci_dev *pdev)
 		sysfs_remove_group(&adapter->port[0]->dev.kobj,
 				   &cxgb3_attr_group);
 
-		for_each_port(adapter, i)
-		    if (test_bit(i, &adapter->registered_device_map))
-			unregister_netdev(adapter->port[i]);
-
 		if (is_offload(adapter)) {
 			cxgb3_adapter_unofld(adapter);
 			if (test_bit(OFFLOAD_DEVMAP_BIT,
@@ -2595,6 +2774,10 @@ static void __devexit remove_one(struct pci_dev *pdev)
 				offload_close(&adapter->tdev);
 		}
 
+		for_each_port(adapter, i)
+		    if (test_bit(i, &adapter->registered_device_map))
+			unregister_netdev(adapter->port[i]);
+
 		t3_free_sge_resources(adapter);
 		cxgb_disable_msi(adapter);
 
@@ -2615,6 +2798,7 @@ static struct pci_driver driver = {
 	.id_table = cxgb3_pci_tbl,
 	.probe = init_one,
 	.remove = __devexit_p(remove_one),
+	.err_handler = &t3_err_handler,
 };
 
 static int __init cxgb3_init_module(void)
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index bd25421bc12a..d48c396bdabb 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -403,8 +403,6 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
 static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs,
 				int n)
 {
-	CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n",
-	       n, ntohl(*(__be32 *)skbs[0]->data));
 	while (n--)
 		dev_kfree_skb_any(skbs[n]);
 	return 0;
@@ -488,7 +486,7 @@ static void t3_process_tid_release_list(struct work_struct *work)
 					   tid_release_task);
 	struct sk_buff *skb;
 	struct t3cdev *tdev = td->dev;
-	
+
 
 	spin_lock_bh(&td->tid_release_lock);
 	while (td->tid_release_list) {
@@ -634,6 +632,18 @@ static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
 	return CPL_RET_BUF_DONE;
 }
 
+static int do_rte_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+	struct cpl_rte_write_rpl *rpl = cplhdr(skb);
+
+	if (rpl->status != CPL_ERR_NONE)
+		printk(KERN_ERR
+		       "Unexpected RTE_WRITE_RPL status %u for entry %u\n",
+		       rpl->status, GET_TID(rpl));
+
+	return CPL_RET_BUF_DONE;
+}
+
 static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
 {
 	struct cpl_act_open_rpl *rpl = cplhdr(skb);
@@ -1004,7 +1014,7 @@ void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
 	if (!is_offloading(olddev))
 		return;
 	if (!is_offloading(newdev)) {
-		printk(KERN_WARNING "%s: Redirect to non-offload"
+		printk(KERN_WARNING "%s: Redirect to non-offload "
 		       "device ignored.\n", __FUNCTION__);
 		return;
 	}
@@ -1257,6 +1267,7 @@ void __init cxgb3_offload_init(void)
 
 	t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
 	t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
+	t3_register_cpl_handler(CPL_RTE_WRITE_RPL, do_rte_write_rpl);
 	t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl);
 	t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl);
 	t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr);
diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h
index 6a835f6a262a..b75ddd8777fe 100644
--- a/drivers/net/cxgb3/firmware_exports.h
+++ b/drivers/net/cxgb3/firmware_exports.h
@@ -76,14 +76,14 @@
 #define FW_WROPCODE_MNGT			0x1D
 #define FW_MNGTOPCODE_PKTSCHED_SET		0x00
 
-/* Maximum size of a WR sent from the host, limited by the SGE. 
+/* Maximum size of a WR sent from the host, limited by the SGE.
  *
- * Note: WR coming from ULP or TP are only limited by CIM. 
+ * Note: WR coming from ULP or TP are only limited by CIM.
  */
 #define FW_WR_SIZE			128
 
 /* Maximum number of outstanding WRs sent from the host. Value must be
- * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by 
+ * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by
  * offload modules to limit the number of WRs per connection.
  */
 #define FW_T3_WR_NUM			16
@@ -99,7 +99,7 @@
  * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must
  * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START.
  *
- * Ingress Traffic (e.g. DMA completion credit)  for TUNNEL Queue[i] is sent 
+ * Ingress Traffic (e.g. DMA completion credit)  for TUNNEL Queue[i] is sent
  * to RESP Queue[i].
  */
 #define FW_TUNNEL_NUM			8
@@ -116,10 +116,10 @@
 #define FW_CTRL_SGEEC_START		65528
 #define FW_CTRL_TID_START		65536
 
-/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These 
- * queues must start at SGE Egress Context FW_OFLD_SGEEC_START. 
- * 
- * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for 
+/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These
+ * queues must start at SGE Egress Context FW_OFLD_SGEEC_START.
+ *
+ * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for
  * OFFLOAD Queues, as the host is responsible for providing the correct TID in
  * every WR.
  *
@@ -129,14 +129,14 @@
 #define FW_OFLD_SGEEC_START		0
 
 /*
- * 
+ *
  */
 #define FW_RI_NUM			1
 #define FW_RI_SGEEC_START		65527
 #define FW_RI_TID_START			65552
 
 /*
- * The RX_PKT_TID 
+ * The RX_PKT_TID
  */
 #define FW_RX_PKT_NUM			1
 #define FW_RX_PKT_TID_START		65553
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
index d660af74606e..17ed4c3527b7 100644
--- a/drivers/net/cxgb3/l2t.c
+++ b/drivers/net/cxgb3/l2t.c
@@ -337,7 +337,7 @@ struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
 		atomic_set(&e->refcnt, 1);
 		neigh_replace(e, neigh);
 		if (neigh->dev->priv_flags & IFF_802_1Q_VLAN)
-			e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id;
+			e->vlan = vlan_dev_info(neigh->dev)->vlan_id;
 		else
 			e->vlan = VLAN_NONE;
 		spin_unlock(&e->lock);
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index 6e12bf4bc6cf..02dbbb300929 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -1,5 +1,17 @@
 #define A_SG_CONTROL 0x0
 
+#define S_CONGMODE    29
+#define V_CONGMODE(x) ((x) << S_CONGMODE)
+#define F_CONGMODE    V_CONGMODE(1U)
+
+#define S_TNLFLMODE    28
+#define V_TNLFLMODE(x) ((x) << S_TNLFLMODE)
+#define F_TNLFLMODE    V_TNLFLMODE(1U)
+
+#define S_FATLPERREN    27
+#define V_FATLPERREN(x) ((x) << S_FATLPERREN)
+#define F_FATLPERREN    V_FATLPERREN(1U)
+
 #define S_DROPPKT    20
 #define V_DROPPKT(x) ((x) << S_DROPPKT)
 #define F_DROPPKT    V_DROPPKT(1U)
@@ -172,6 +184,64 @@
 
 #define A_SG_INT_CAUSE 0x5c
 
+#define S_HIRCQPARITYERROR    31
+#define V_HIRCQPARITYERROR(x) ((x) << S_HIRCQPARITYERROR)
+#define F_HIRCQPARITYERROR    V_HIRCQPARITYERROR(1U)
+
+#define S_LORCQPARITYERROR    30
+#define V_LORCQPARITYERROR(x) ((x) << S_LORCQPARITYERROR)
+#define F_LORCQPARITYERROR    V_LORCQPARITYERROR(1U)
+
+#define S_HIDRBPARITYERROR    29
+#define V_HIDRBPARITYERROR(x) ((x) << S_HIDRBPARITYERROR)
+#define F_HIDRBPARITYERROR    V_HIDRBPARITYERROR(1U)
+
+#define S_LODRBPARITYERROR    28
+#define V_LODRBPARITYERROR(x) ((x) << S_LODRBPARITYERROR)
+#define F_LODRBPARITYERROR    V_LODRBPARITYERROR(1U)
+
+#define S_FLPARITYERROR    22
+#define M_FLPARITYERROR    0x3f
+#define V_FLPARITYERROR(x) ((x) << S_FLPARITYERROR)
+#define G_FLPARITYERROR(x) (((x) >> S_FLPARITYERROR) & M_FLPARITYERROR)
+
+#define S_ITPARITYERROR    20
+#define M_ITPARITYERROR    0x3
+#define V_ITPARITYERROR(x) ((x) << S_ITPARITYERROR)
+#define G_ITPARITYERROR(x) (((x) >> S_ITPARITYERROR) & M_ITPARITYERROR)
+
+#define S_IRPARITYERROR    19
+#define V_IRPARITYERROR(x) ((x) << S_IRPARITYERROR)
+#define F_IRPARITYERROR    V_IRPARITYERROR(1U)
+
+#define S_RCPARITYERROR    18
+#define V_RCPARITYERROR(x) ((x) << S_RCPARITYERROR)
+#define F_RCPARITYERROR    V_RCPARITYERROR(1U)
+
+#define S_OCPARITYERROR    17
+#define V_OCPARITYERROR(x) ((x) << S_OCPARITYERROR)
+#define F_OCPARITYERROR    V_OCPARITYERROR(1U)
+
+#define S_CPPARITYERROR    16
+#define V_CPPARITYERROR(x) ((x) << S_CPPARITYERROR)
+#define F_CPPARITYERROR    V_CPPARITYERROR(1U)
+
+#define S_R_REQ_FRAMINGERROR    15
+#define V_R_REQ_FRAMINGERROR(x) ((x) << S_R_REQ_FRAMINGERROR)
+#define F_R_REQ_FRAMINGERROR    V_R_REQ_FRAMINGERROR(1U)
+
+#define S_UC_REQ_FRAMINGERROR    14
+#define V_UC_REQ_FRAMINGERROR(x) ((x) << S_UC_REQ_FRAMINGERROR)
+#define F_UC_REQ_FRAMINGERROR    V_UC_REQ_FRAMINGERROR(1U)
+
+#define S_HICTLDRBDROPERR    13
+#define V_HICTLDRBDROPERR(x) ((x) << S_HICTLDRBDROPERR)
+#define F_HICTLDRBDROPERR    V_HICTLDRBDROPERR(1U)
+
+#define S_LOCTLDRBDROPERR    12
+#define V_LOCTLDRBDROPERR(x) ((x) << S_LOCTLDRBDROPERR)
+#define F_LOCTLDRBDROPERR    V_LOCTLDRBDROPERR(1U)
+
 #define S_HIPIODRBDROPERR    11
 #define V_HIPIODRBDROPERR(x) ((x) << S_HIPIODRBDROPERR)
 #define F_HIPIODRBDROPERR    V_HIPIODRBDROPERR(1U)
@@ -286,6 +356,10 @@
 
 #define A_PCIX_CFG 0x88
 
+#define S_DMASTOPEN    19
+#define V_DMASTOPEN(x) ((x) << S_DMASTOPEN)
+#define F_DMASTOPEN    V_DMASTOPEN(1U)
+
 #define S_CLIDECEN    18
 #define V_CLIDECEN(x) ((x) << S_CLIDECEN)
 #define F_CLIDECEN    V_CLIDECEN(1U)
@@ -313,6 +387,22 @@
 
 #define V_BISTERR(x) ((x) << S_BISTERR)
 
+#define S_TXPARERR    18
+#define V_TXPARERR(x) ((x) << S_TXPARERR)
+#define F_TXPARERR    V_TXPARERR(1U)
+
+#define S_RXPARERR    17
+#define V_RXPARERR(x) ((x) << S_RXPARERR)
+#define F_RXPARERR    V_RXPARERR(1U)
+
+#define S_RETRYLUTPARERR    16
+#define V_RETRYLUTPARERR(x) ((x) << S_RETRYLUTPARERR)
+#define F_RETRYLUTPARERR    V_RETRYLUTPARERR(1U)
+
+#define S_RETRYBUFPARERR    15
+#define V_RETRYBUFPARERR(x) ((x) << S_RETRYBUFPARERR)
+#define F_RETRYBUFPARERR    V_RETRYBUFPARERR(1U)
+
 #define S_PCIE_MSIXPARERR    12
 #define M_PCIE_MSIXPARERR    0x7
 
@@ -348,6 +438,10 @@
 
 #define A_PCIE_INT_CAUSE 0x84
 
+#define S_PCIE_DMASTOPEN    24
+#define V_PCIE_DMASTOPEN(x) ((x) << S_PCIE_DMASTOPEN)
+#define F_PCIE_DMASTOPEN    V_PCIE_DMASTOPEN(1U)
+
 #define A_PCIE_CFG 0x88
 
 #define S_PCIE_CLIDECEN    16
@@ -741,6 +835,54 @@
 
 #define A_CIM_HOST_INT_ENABLE 0x298
 
+#define S_DTAGPARERR    28
+#define V_DTAGPARERR(x) ((x) << S_DTAGPARERR)
+#define F_DTAGPARERR    V_DTAGPARERR(1U)
+
+#define S_ITAGPARERR    27
+#define V_ITAGPARERR(x) ((x) << S_ITAGPARERR)
+#define F_ITAGPARERR    V_ITAGPARERR(1U)
+
+#define S_IBQTPPARERR    26
+#define V_IBQTPPARERR(x) ((x) << S_IBQTPPARERR)
+#define F_IBQTPPARERR    V_IBQTPPARERR(1U)
+
+#define S_IBQULPPARERR    25
+#define V_IBQULPPARERR(x) ((x) << S_IBQULPPARERR)
+#define F_IBQULPPARERR    V_IBQULPPARERR(1U)
+
+#define S_IBQSGEHIPARERR    24
+#define V_IBQSGEHIPARERR(x) ((x) << S_IBQSGEHIPARERR)
+#define F_IBQSGEHIPARERR    V_IBQSGEHIPARERR(1U)
+
+#define S_IBQSGELOPARERR    23
+#define V_IBQSGELOPARERR(x) ((x) << S_IBQSGELOPARERR)
+#define F_IBQSGELOPARERR    V_IBQSGELOPARERR(1U)
+
+#define S_OBQULPLOPARERR    22
+#define V_OBQULPLOPARERR(x) ((x) << S_OBQULPLOPARERR)
+#define F_OBQULPLOPARERR    V_OBQULPLOPARERR(1U)
+
+#define S_OBQULPHIPARERR    21
+#define V_OBQULPHIPARERR(x) ((x) << S_OBQULPHIPARERR)
+#define F_OBQULPHIPARERR    V_OBQULPHIPARERR(1U)
+
+#define S_OBQSGEPARERR    20
+#define V_OBQSGEPARERR(x) ((x) << S_OBQSGEPARERR)
+#define F_OBQSGEPARERR    V_OBQSGEPARERR(1U)
+
+#define S_DCACHEPARERR    19
+#define V_DCACHEPARERR(x) ((x) << S_DCACHEPARERR)
+#define F_DCACHEPARERR    V_DCACHEPARERR(1U)
+
+#define S_ICACHEPARERR    18
+#define V_ICACHEPARERR(x) ((x) << S_ICACHEPARERR)
+#define F_ICACHEPARERR    V_ICACHEPARERR(1U)
+
+#define S_DRAMPARERR    17
+#define V_DRAMPARERR(x) ((x) << S_DRAMPARERR)
+#define F_DRAMPARERR    V_DRAMPARERR(1U)
+
 #define A_CIM_HOST_INT_CAUSE 0x29c
 
 #define S_BLKWRPLINT    12
@@ -799,8 +941,42 @@
 
 #define A_CIM_HOST_ACC_DATA 0x2b4
 
+#define A_CIM_IBQ_DBG_CFG 0x2c0
+
+#define S_IBQDBGADDR    16
+#define M_IBQDBGADDR    0x1ff
+#define V_IBQDBGADDR(x) ((x) << S_IBQDBGADDR)
+#define G_IBQDBGADDR(x) (((x) >> S_IBQDBGADDR) & M_IBQDBGADDR)
+
+#define S_IBQDBGQID    3
+#define M_IBQDBGQID    0x3
+#define V_IBQDBGQID(x) ((x) << S_IBQDBGQID)
+#define G_IBQDBGQID(x) (((x) >> S_IBQDBGQID) & M_IBQDBGQID)
+
+#define S_IBQDBGWR    2
+#define V_IBQDBGWR(x) ((x) << S_IBQDBGWR)
+#define F_IBQDBGWR    V_IBQDBGWR(1U)
+
+#define S_IBQDBGBUSY    1
+#define V_IBQDBGBUSY(x) ((x) << S_IBQDBGBUSY)
+#define F_IBQDBGBUSY    V_IBQDBGBUSY(1U)
+
+#define S_IBQDBGEN    0
+#define V_IBQDBGEN(x) ((x) << S_IBQDBGEN)
+#define F_IBQDBGEN    V_IBQDBGEN(1U)
+
+#define A_CIM_IBQ_DBG_DATA 0x2c8
+
 #define A_TP_IN_CONFIG 0x300
 
+#define S_RXFBARBPRIO    25
+#define V_RXFBARBPRIO(x) ((x) << S_RXFBARBPRIO)
+#define F_RXFBARBPRIO    V_RXFBARBPRIO(1U)
+
+#define S_TXFBARBPRIO    24
+#define V_TXFBARBPRIO(x) ((x) << S_TXFBARBPRIO)
+#define F_TXFBARBPRIO    V_TXFBARBPRIO(1U)
+
 #define S_NICMODE    14
 #define V_NICMODE(x) ((x) << S_NICMODE)
 #define F_NICMODE    V_NICMODE(1U)
@@ -965,8 +1141,30 @@
 #define V_LOCKTID(x) ((x) << S_LOCKTID)
 #define F_LOCKTID    V_LOCKTID(1U)
 
+#define S_TABLELATENCYDELTA    0
+#define M_TABLELATENCYDELTA    0xf
+#define V_TABLELATENCYDELTA(x) ((x) << S_TABLELATENCYDELTA)
+#define G_TABLELATENCYDELTA(x) \
+	(((x) >> S_TABLELATENCYDELTA) & M_TABLELATENCYDELTA)
+
 #define A_TP_PC_CONFIG2 0x34c
 
+#define S_DISBLEDAPARBIT0    15
+#define V_DISBLEDAPARBIT0(x) ((x) << S_DISBLEDAPARBIT0)
+#define F_DISBLEDAPARBIT0    V_DISBLEDAPARBIT0(1U)
+
+#define S_ENABLEARPMISS    13
+#define V_ENABLEARPMISS(x) ((x) << S_ENABLEARPMISS)
+#define F_ENABLEARPMISS    V_ENABLEARPMISS(1U)
+
+#define S_ENABLENONOFDTNLSYN    12
+#define V_ENABLENONOFDTNLSYN(x) ((x) << S_ENABLENONOFDTNLSYN)
+#define F_ENABLENONOFDTNLSYN    V_ENABLENONOFDTNLSYN(1U)
+
+#define S_ENABLEIPV6RSS    11
+#define V_ENABLEIPV6RSS(x) ((x) << S_ENABLEIPV6RSS)
+#define F_ENABLEIPV6RSS    V_ENABLEIPV6RSS(1U)
+
 #define S_CHDRAFULL    4
 #define V_CHDRAFULL(x) ((x) << S_CHDRAFULL)
 #define F_CHDRAFULL    V_CHDRAFULL(1U)
@@ -1018,6 +1216,12 @@
 
 #define A_TP_PARA_REG4 0x370
 
+#define A_TP_PARA_REG5 0x374
+
+#define S_RXDDPOFFINIT    3
+#define V_RXDDPOFFINIT(x) ((x) << S_RXDDPOFFINIT)
+#define F_RXDDPOFFINIT    V_RXDDPOFFINIT(1U)
+
 #define A_TP_PARA_REG6 0x378
 
 #define S_T3A_ENABLEESND    13
@@ -1138,6 +1342,10 @@
 #define V_TNLLKPEN(x) ((x) << S_TNLLKPEN)
 #define F_TNLLKPEN    V_TNLLKPEN(1U)
 
+#define S_RRCPLMAPEN    7
+#define V_RRCPLMAPEN(x) ((x) << S_RRCPLMAPEN)
+#define F_RRCPLMAPEN    V_RRCPLMAPEN(1U)
+
 #define S_RRCPLCPUSIZE    4
 #define M_RRCPLCPUSIZE    0x7
 #define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE)
@@ -1146,6 +1354,10 @@
 #define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE)
 #define F_RQFEEDBACKENABLE    V_RQFEEDBACKENABLE(1U)
 
+#define S_HASHTOEPLITZ    2
+#define V_HASHTOEPLITZ(x) ((x) << S_HASHTOEPLITZ)
+#define F_HASHTOEPLITZ    V_HASHTOEPLITZ(1U)
+
 #define S_DISABLE    0
 
 #define A_TP_TM_PIO_ADDR 0x418
@@ -1198,6 +1410,22 @@
 
 #define A_TP_INT_ENABLE 0x470
 
+#define S_FLMTXFLSTEMPTY    30
+#define V_FLMTXFLSTEMPTY(x) ((x) << S_FLMTXFLSTEMPTY)
+#define F_FLMTXFLSTEMPTY    V_FLMTXFLSTEMPTY(1U)
+
+#define S_FLMRXFLSTEMPTY    29
+#define V_FLMRXFLSTEMPTY(x) ((x) << S_FLMRXFLSTEMPTY)
+#define F_FLMRXFLSTEMPTY    V_FLMRXFLSTEMPTY(1U)
+
+#define S_ARPLUTPERR    26
+#define V_ARPLUTPERR(x) ((x) << S_ARPLUTPERR)
+#define F_ARPLUTPERR    V_ARPLUTPERR(1U)
+
+#define S_CMCACHEPERR    24
+#define V_CMCACHEPERR(x) ((x) << S_CMCACHEPERR)
+#define F_CMCACHEPERR    V_CMCACHEPERR(1U)
+
 #define A_TP_INT_CAUSE 0x474
 
 #define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8
@@ -1241,9 +1469,37 @@
 
 #define A_ULPRX_INT_ENABLE 0x504
 
-#define S_PARERR    0
-#define V_PARERR(x) ((x) << S_PARERR)
-#define F_PARERR    V_PARERR(1U)
+#define S_DATASELFRAMEERR0    7
+#define V_DATASELFRAMEERR0(x) ((x) << S_DATASELFRAMEERR0)
+#define F_DATASELFRAMEERR0    V_DATASELFRAMEERR0(1U)
+
+#define S_DATASELFRAMEERR1    6
+#define V_DATASELFRAMEERR1(x) ((x) << S_DATASELFRAMEERR1)
+#define F_DATASELFRAMEERR1    V_DATASELFRAMEERR1(1U)
+
+#define S_PCMDMUXPERR    5
+#define V_PCMDMUXPERR(x) ((x) << S_PCMDMUXPERR)
+#define F_PCMDMUXPERR    V_PCMDMUXPERR(1U)
+
+#define S_ARBFPERR    4
+#define V_ARBFPERR(x) ((x) << S_ARBFPERR)
+#define F_ARBFPERR    V_ARBFPERR(1U)
+
+#define S_ARBPF0PERR    3
+#define V_ARBPF0PERR(x) ((x) << S_ARBPF0PERR)
+#define F_ARBPF0PERR    V_ARBPF0PERR(1U)
+
+#define S_ARBPF1PERR    2
+#define V_ARBPF1PERR(x) ((x) << S_ARBPF1PERR)
+#define F_ARBPF1PERR    V_ARBPF1PERR(1U)
+
+#define S_PARERRPCMD    1
+#define V_PARERRPCMD(x) ((x) << S_PARERRPCMD)
+#define F_PARERRPCMD    V_PARERRPCMD(1U)
+
+#define S_PARERRDATA    0
+#define V_PARERRDATA(x) ((x) << S_PARERRDATA)
+#define F_PARERRDATA    V_PARERRDATA(1U)
 
 #define A_ULPRX_INT_CAUSE 0x508
 
@@ -1291,6 +1547,10 @@
 
 #define A_ULPTX_CONFIG 0x580
 
+#define S_CFG_CQE_SOP_MASK    1
+#define V_CFG_CQE_SOP_MASK(x) ((x) << S_CFG_CQE_SOP_MASK)
+#define F_CFG_CQE_SOP_MASK    V_CFG_CQE_SOP_MASK(1U)
+
 #define S_CFG_RR_ARB    0
 #define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB)
 #define F_CFG_RR_ARB    V_CFG_RR_ARB(1U)
@@ -1537,6 +1797,10 @@
 
 #define A_CPL_INTR_ENABLE 0x650
 
+#define S_CIM_OP_MAP_PERR    5
+#define V_CIM_OP_MAP_PERR(x) ((x) << S_CIM_OP_MAP_PERR)
+#define F_CIM_OP_MAP_PERR    V_CIM_OP_MAP_PERR(1U)
+
 #define S_CIM_OVFL_ERROR    4
 #define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR)
 #define F_CIM_OVFL_ERROR    V_CIM_OVFL_ERROR(1U)
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index c15e43a8543b..cb684d30831f 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -91,6 +91,10 @@ struct rx_desc {
 
 struct tx_sw_desc {		/* SW state per Tx descriptor */
 	struct sk_buff *skb;
+	u8 eop;       /* set if last descriptor for packet */
+	u8 addr_idx;  /* buffer index of first SGL entry in descriptor */
+	u8 fragidx;   /* first page fragment associated with descriptor */
+	s8 sflit;     /* start flit of first SGL entry in descriptor */
 };
 
 struct rx_sw_desc {                /* SW state per Rx descriptor */
@@ -109,13 +113,6 @@ struct rsp_desc {		/* response queue descriptor */
 	u8 intr_gen;
 };
 
-struct unmap_info {		/* packet unmapping info, overlays skb->cb */
-	int sflit;		/* start flit of first SGL entry in Tx descriptor */
-	u16 fragidx;		/* first page fragment in current Tx descriptor */
-	u16 addr_idx;		/* buffer index of first SGL entry in descriptor */
-	u32 len;		/* mapped length of skb main body */
-};
-
 /*
  * Holds unmapping information for Tx packets that need deferred unmapping.
  * This structure lives at skb->head and must be allocated by callers.
@@ -177,6 +174,7 @@ static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx)
 static inline void refill_rspq(struct adapter *adapter,
 			       const struct sge_rspq *q, unsigned int credits)
 {
+	rmb();
 	t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN,
 		     V_RSPQ(q->cntxt_id) | V_CREDITS(credits));
 }
@@ -209,32 +207,36 @@ static inline int need_skb_unmap(void)
  *
  *	Unmap the main body of an sk_buff and its page fragments, if any.
  *	Because of the fairly complicated structure of our SGLs and the desire
- *	to conserve space for metadata, we keep the information necessary to
- *	unmap an sk_buff partly in the sk_buff itself (in its cb), and partly
- *	in the Tx descriptors (the physical addresses of the various data
- *	buffers).  The send functions initialize the state in skb->cb so we
- *	can unmap the buffers held in the first Tx descriptor here, and we
- *	have enough information at this point to update the state for the next
- *	Tx descriptor.
+ *	to conserve space for metadata, the information necessary to unmap an
+ *	sk_buff is spread across the sk_buff itself (buffer lengths), the HW Tx
+ *	descriptors (the physical addresses of the various data buffers), and
+ *	the SW descriptor state (assorted indices).  The send functions
+ *	initialize the indices for the first packet descriptor so we can unmap
+ *	the buffers held in the first Tx descriptor here, and we have enough
+ *	information at this point to set the state for the next Tx descriptor.
+ *
+ *	Note that it is possible to clean up the first descriptor of a packet
+ *	before the send routines have written the next descriptors, but this
+ *	race does not cause any problem.  We just end up writing the unmapping
+ *	info for the descriptor first.
  */
 static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q,
 			     unsigned int cidx, struct pci_dev *pdev)
 {
 	const struct sg_ent *sgp;
-	struct unmap_info *ui = (struct unmap_info *)skb->cb;
-	int nfrags, frag_idx, curflit, j = ui->addr_idx;
+	struct tx_sw_desc *d = &q->sdesc[cidx];
+	int nfrags, frag_idx, curflit, j = d->addr_idx;
 
-	sgp = (struct sg_ent *)&q->desc[cidx].flit[ui->sflit];
+	sgp = (struct sg_ent *)&q->desc[cidx].flit[d->sflit];
+	frag_idx = d->fragidx;
 
-	if (ui->len) {
-		pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), ui->len,
-				 PCI_DMA_TODEVICE);
-		ui->len = 0;	/* so we know for next descriptor for this skb */
+	if (frag_idx == 0 && skb_headlen(skb)) {
+		pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]),
+				 skb_headlen(skb), PCI_DMA_TODEVICE);
 		j = 1;
 	}
 
-	frag_idx = ui->fragidx;
-	curflit = ui->sflit + 1 + j;
+	curflit = d->sflit + 1 + j;
 	nfrags = skb_shinfo(skb)->nr_frags;
 
 	while (frag_idx < nfrags && curflit < WR_FLITS) {
@@ -250,10 +252,11 @@ static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q,
 		frag_idx++;
 	}
 
-	if (frag_idx < nfrags) {	/* SGL continues into next Tx descriptor */
-		ui->fragidx = frag_idx;
-		ui->addr_idx = j;
-		ui->sflit = curflit - WR_FLITS - j;	/* sflit can be -1 */
+	if (frag_idx < nfrags) {   /* SGL continues into next Tx descriptor */
+		d = cidx + 1 == q->size ? q->sdesc : d + 1;
+		d->fragidx = frag_idx;
+		d->addr_idx = j;
+		d->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */
 	}
 }
 
@@ -281,7 +284,7 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
 		if (d->skb) {	/* an SGL is present */
 			if (need_unmap)
 				unmap_skb(d->skb, q, cidx, pdev);
-			if (d->skb->priority == cidx)
+			if (d->eop)
 				kfree_skb(d->skb);
 		}
 		++d;
@@ -456,7 +459,7 @@ nomem:				q->alloc_failed++;
 		}
 		q->credits++;
 	}
-
+	wmb();
 	t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
 }
 
@@ -912,15 +915,13 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb,
 
 	sd->skb = skb;
 	if (need_skb_unmap()) {
-		struct unmap_info *ui = (struct unmap_info *)skb->cb;
-
-		ui->fragidx = 0;
-		ui->addr_idx = 0;
-		ui->sflit = flits;
+		sd->fragidx = 0;
+		sd->addr_idx = 0;
+		sd->sflit = flits;
 	}
 
 	if (likely(ndesc == 1)) {
-		skb->priority = pidx;
+		sd->eop = 1;
 		wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) |
 				   V_WR_SGLSFLT(flits)) | wr_hi;
 		wmb();
@@ -948,6 +949,7 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb,
 
 			fp += avail;
 			d++;
+			sd->eop = 0;
 			sd++;
 			if (++pidx == q->size) {
 				pidx = 0;
@@ -966,7 +968,7 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb,
 			wr_gen2(d, gen);
 			flits = 1;
 		}
-		skb->priority = pidx;
+		sd->eop = 1;
 		wrp->wr_hi |= htonl(F_WR_EOP);
 		wmb();
 		wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo;
@@ -1051,8 +1053,6 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
 
 	sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
 	sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev);
-	if (need_skb_unmap())
-		((struct unmap_info *)skb->cb)->len = skb_headlen(skb);
 
 	write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen,
 			 htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl),
@@ -1354,6 +1354,7 @@ static void restart_ctrlq(unsigned long data)
 	}
 
 	spin_unlock(&q->lock);
+	wmb();
 	t3_write_reg(qs->adap, A_SG_KDOORBELL,
 		     F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
 }
@@ -1363,7 +1364,12 @@ static void restart_ctrlq(unsigned long data)
  */
 int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb)
 {
-	return ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb);
+	int ret; 
+	local_bh_disable();
+	ret = ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb);
+	local_bh_enable();
+
+	return ret;
 }
 
 /**
@@ -1380,13 +1386,14 @@ static void deferred_unmap_destructor(struct sk_buff *skb)
 	const dma_addr_t *p;
 	const struct skb_shared_info *si;
 	const struct deferred_unmap_info *dui;
-	const struct unmap_info *ui = (struct unmap_info *)skb->cb;
 
 	dui = (struct deferred_unmap_info *)skb->head;
 	p = dui->addr;
 
-	if (ui->len)
-		pci_unmap_single(dui->pdev, *p++, ui->len, PCI_DMA_TODEVICE);
+	if (skb->tail - skb->transport_header)
+		pci_unmap_single(dui->pdev, *p++,
+				 skb->tail - skb->transport_header,
+				 PCI_DMA_TODEVICE);
 
 	si = skb_shinfo(skb);
 	for (i = 0; i < si->nr_frags; i++)
@@ -1451,8 +1458,6 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
 	if (need_skb_unmap()) {
 		setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits);
 		skb->destructor = deferred_unmap_destructor;
-		((struct unmap_info *)skb->cb)->len = (skb->tail -
-						       skb->transport_header);
 	}
 
 	write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits,
@@ -1574,6 +1579,7 @@ static void restart_offloadq(unsigned long data)
 	set_bit(TXQ_RUNNING, &q->flags);
 	set_bit(TXQ_LAST_PKT_DB, &q->flags);
 #endif
+	wmb();
 	t3_write_reg(adap, A_SG_KDOORBELL,
 		     F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
 }
@@ -1739,7 +1745,6 @@ static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq,
 			     struct sk_buff *skb, struct sk_buff *rx_gather[],
 			     unsigned int gather_idx)
 {
-	rq->offload_pkts++;
 	skb_reset_mac_header(skb);
 	skb_reset_network_header(skb);
 	skb_reset_transport_header(skb);
@@ -1809,7 +1814,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
 	skb->protocol = eth_type_trans(skb, adap->port[p->iff]);
 	skb->dev->last_rx = jiffies;
 	pi = netdev_priv(skb->dev);
-	if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff &&
+	if (pi->rx_csum_offload && p->csum_valid && p->csum == htons(0xffff) &&
 	    !p->fragment) {
 		rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1956,7 +1961,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
 		int eth, ethpad = 2;
 		struct sk_buff *skb = NULL;
 		u32 len, flags = ntohl(r->flags);
-		u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val;
+		__be32 rss_hi = *(const __be32 *)r, rss_lo = r->rss_hdr.rss_hash_val;
 
 		eth = r->rss_hdr.opcode == CPL_RX_PKT;
 
@@ -2033,6 +2038,7 @@ no_mem:
 			if (eth)
 				rx_eth(adap, q, skb, ethpad);
 			else {
+				q->offload_pkts++;
 				/* Preserve the RSS info in csum & priority */
 				skb->csum = rss_hi;
 				skb->priority = rss_lo;
@@ -2442,6 +2448,15 @@ irq_handler_t t3_intr_handler(struct adapter *adap, int polling)
 	return t3_intr;
 }
 
+#define SGE_PARERR (F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \
+		    F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
+		    V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
+		    F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
+		    F_HIRCQPARITYERROR)
+#define SGE_FRAMINGERR (F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR)
+#define SGE_FATALERR (SGE_PARERR | SGE_FRAMINGERR | F_RSPQCREDITOVERFOW | \
+		      F_RSPQDISABLED)
+
 /**
  *	t3_sge_err_intr_handler - SGE async event interrupt handler
  *	@adapter: the adapter
@@ -2452,6 +2467,13 @@ void t3_sge_err_intr_handler(struct adapter *adapter)
 {
 	unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE);
 
+	if (status & SGE_PARERR)
+		CH_ALERT(adapter, "SGE parity error (0x%x)\n",
+			 status & SGE_PARERR);
+	if (status & SGE_FRAMINGERR)
+		CH_ALERT(adapter, "SGE framing error (0x%x)\n",
+			 status & SGE_FRAMINGERR);
+
 	if (status & F_RSPQCREDITOVERFOW)
 		CH_ALERT(adapter, "SGE response queue credit overflow\n");
 
@@ -2468,7 +2490,7 @@ void t3_sge_err_intr_handler(struct adapter *adapter)
 			 status & F_HIPIODRBDROPERR ? "high" : "lo");
 
 	t3_write_reg(adapter, A_SG_INT_CAUSE, status);
-	if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED))
+	if (status &  SGE_FATALERR)
 		t3_fatal_err(adapter);
 }
 
@@ -2780,7 +2802,7 @@ void t3_sge_init(struct adapter *adap, struct sge_params *p)
 	unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12);
 
 	ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL |
-	    F_CQCRDTCTRL |
+	    F_CQCRDTCTRL | F_CONGMODE | F_TNLFLMODE | F_FATLPERREN |
 	    V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS |
 	    V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING;
 #if SGE_NUM_GENBITS == 1
@@ -2789,7 +2811,6 @@ void t3_sge_init(struct adapter *adap, struct sge_params *p)
 	if (adap->params.rev > 0) {
 		if (!(adap->flags & (USING_MSIX | USING_MSI)))
 			ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ;
-		ctrl |= F_CQCRDTCTRL | F_AVOIDCQOVFL;
 	}
 	t3_write_reg(adap, A_SG_CONTROL, ctrl);
 	t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) |
@@ -2797,7 +2818,8 @@ void t3_sge_init(struct adapter *adap, struct sge_params *p)
 	t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10);
 	t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) |
 		     V_TIMEOUT(200 * core_ticks_per_usec(adap)));
-	t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 1000);
+	t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH,
+		     adap->params.rev < T3_REV_C ? 1000 : 500);
 	t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256);
 	t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000);
 	t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256);
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 522834c42ae7..7469935877bd 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -62,7 +62,7 @@ int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
 			return 0;
 		}
 		if (--attempts == 0)
- 			return -EAGAIN;
+			return -EAGAIN;
 		if (delay)
 			udelay(delay);
 	}
@@ -537,10 +537,11 @@ struct t3_vpd {
  *	addres is written to the control register.  The hardware device will
  *	set the flag to 1 when 4 bytes have been read into the data register.
  */
-int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data)
+int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data)
 {
 	u16 val;
 	int attempts = EEPROM_MAX_POLL;
+	u32 v;
 	unsigned int base = adapter->params.pci.vpd_cap_addr;
 
 	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
@@ -556,8 +557,8 @@ int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data)
 		CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
 		return -EIO;
 	}
-	pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, data);
-	*data = le32_to_cpu(*data);
+	pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, &v);
+	*data = cpu_to_le32(v);
 	return 0;
 }
 
@@ -570,7 +571,7 @@ int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data)
  *	Write a 32-bit word to a location in VPD EEPROM using the card's PCI
  *	VPD ROM capability.
  */
-int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data)
+int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data)
 {
 	u16 val;
 	int attempts = EEPROM_MAX_POLL;
@@ -580,7 +581,7 @@ int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data)
 		return -EINVAL;
 
 	pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA,
-			       cpu_to_le32(data));
+			       le32_to_cpu(data));
 	pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR,
 			      addr | PCI_VPD_ADDR_F);
 	do {
@@ -631,14 +632,14 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
 	 * Card information is normally at VPD_BASE but some early cards had
 	 * it at 0.
 	 */
-	ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd);
+	ret = t3_seeprom_read(adapter, VPD_BASE, (__le32 *)&vpd);
 	if (ret)
 		return ret;
 	addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
 
 	for (i = 0; i < sizeof(vpd); i += 4) {
 		ret = t3_seeprom_read(adapter, addr + i,
-				      (u32 *)((u8 *)&vpd + i));
+				      (__le32 *)((u8 *)&vpd + i));
 		if (ret)
 			return ret;
 	}
@@ -865,7 +866,7 @@ int t3_get_tp_version(struct adapter *adapter, u32 *vers)
 			      1, 1, 5, 1);
 	if (ret)
 		return ret;
-	
+
 	*vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
 
 	return 0;
@@ -896,7 +897,7 @@ int t3_check_tpsram_version(struct adapter *adapter, int *must_load)
 	major = G_TP_VERSION_MAJOR(vers);
 	minor = G_TP_VERSION_MINOR(vers);
 
-	if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 
+	if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
 		return 0;
 
 	if (major != TP_VERSION_MAJOR)
@@ -913,7 +914,7 @@ int t3_check_tpsram_version(struct adapter *adapter, int *must_load)
 }
 
 /**
- *	t3_check_tpsram - check if provided protocol SRAM 
+ *	t3_check_tpsram - check if provided protocol SRAM
  *			  is compatible with this driver
  *	@adapter: the adapter
  *	@tp_sram: the firmware image to write
@@ -926,7 +927,7 @@ int t3_check_tpsram(struct adapter *adapter, u8 *tp_sram, unsigned int size)
 {
 	u32 csum;
 	unsigned int i;
-	const u32 *p = (const u32 *)tp_sram;
+	const __be32 *p = (const __be32 *)tp_sram;
 
 	/* Verify checksum */
 	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
@@ -988,13 +989,17 @@ int t3_check_fw_version(struct adapter *adapter, int *must_load)
 		CH_ERR(adapter, "found wrong FW version(%u.%u), "
 		       "driver needs version %u.%u\n", major, minor,
 		       FW_VERSION_MAJOR, FW_VERSION_MINOR);
-	else {
+	else if (minor < FW_VERSION_MINOR) {
 		*must_load = 0;
-		CH_WARN(adapter, "found wrong FW minor version(%u.%u), "
+		CH_WARN(adapter, "found old FW minor version(%u.%u), "
 		        "driver compiled for version %u.%u\n", major, minor,
 			FW_VERSION_MAJOR, FW_VERSION_MINOR);
+	} else {
+		CH_WARN(adapter, "found newer FW version(%u.%u), "
+		        "driver compiled for version %u.%u\n", major, minor,
+			FW_VERSION_MAJOR, FW_VERSION_MINOR);
+			return 0;
 	}
-
 	return -EINVAL;
 }
 
@@ -1036,7 +1041,7 @@ int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size)
 {
 	u32 csum;
 	unsigned int i;
-	const u32 *p = (const u32 *)fw_data;
+	const __be32 *p = (const __be32 *)fw_data;
 	int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
 
 	if ((size & 3) || size < FW_MIN_SIZE)
@@ -1259,7 +1264,13 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
 	return fatal;
 }
 
-#define SGE_INTR_MASK (F_RSPQDISABLED)
+#define SGE_INTR_MASK (F_RSPQDISABLED | \
+		       F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \
+		       F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \
+		       F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
+		       V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
+		       F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
+		       F_HIRCQPARITYERROR)
 #define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
 		       F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
 		       F_NFASRCHFAIL)
@@ -1276,16 +1287,23 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
 #define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
 			F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
 			/* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
-			V_BISTERR(M_BISTERR) | F_PEXERR)
-#define ULPRX_INTR_MASK F_PARERR
-#define ULPTX_INTR_MASK 0
-#define CPLSW_INTR_MASK (F_TP_FRAMING_ERROR | \
+			F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \
+			F_TXPARERR | V_BISTERR(M_BISTERR))
+#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \
+			 F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \
+			 F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0)
+#define ULPTX_INTR_MASK 0xfc
+#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \
 			 F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
 			 F_ZERO_SWITCH_ERROR)
 #define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
 		       F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
 		       F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
-	 	       F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT)
+	 	       F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \
+		       F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \
+		       F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \
+		       F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \
+		       F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR)
 #define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
 			V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
 			V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
@@ -1354,6 +1372,10 @@ static void pcie_intr_handler(struct adapter *adapter)
 		{F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1},
 		{V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
 		 "PCI MSI-X table/PBA parity error", -1, 1},
+		{F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1},
+		{F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1},
+		{F_RXPARERR, "PCI Rx parity error", -1, 1},
+		{F_TXPARERR, "PCI Tx parity error", -1, 1},
 		{V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1},
 		{0}
 	};
@@ -1379,8 +1401,16 @@ static void tp_intr_handler(struct adapter *adapter)
 		{0}
 	};
 
+	static struct intr_info tp_intr_info_t3c[] = {
+		{0x1fffffff, "TP parity error", -1, 1},
+		{F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1},
+		{F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1},
+		{0}
+	};
+
 	if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
-				  tp_intr_info, NULL))
+				  adapter->params.rev < T3_REV_C ?
+				  tp_intr_info : tp_intr_info_t3c, NULL))
 		t3_fatal_err(adapter);
 }
 
@@ -1402,6 +1432,18 @@ static void cim_intr_handler(struct adapter *adapter)
 		{F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1},
 		{F_BLKRDPLINT, "CIM block read from PL space", -1, 1},
 		{F_BLKWRPLINT, "CIM block write to PL space", -1, 1},
+		{F_DRAMPARERR, "CIM DRAM parity error", -1, 1},
+		{F_ICACHEPARERR, "CIM icache parity error", -1, 1},
+		{F_DCACHEPARERR, "CIM dcache parity error", -1, 1},
+		{F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1},
+		{F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1},
+		{F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1},
+		{F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1},
+		{F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1},
+		{F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1},
+		{F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1},
+		{F_ITAGPARERR, "CIM itag parity error", -1, 1},
+		{F_DTAGPARERR, "CIM dtag parity error", -1, 1},
 		{0}
 	};
 
@@ -1416,7 +1458,14 @@ static void cim_intr_handler(struct adapter *adapter)
 static void ulprx_intr_handler(struct adapter *adapter)
 {
 	static const struct intr_info ulprx_intr_info[] = {
-		{F_PARERR, "ULP RX parity error", -1, 1},
+		{F_PARERRDATA, "ULP RX data parity error", -1, 1},
+		{F_PARERRPCMD, "ULP RX command parity error", -1, 1},
+		{F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1},
+		{F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1},
+		{F_ARBFPERR, "ULP RX ArbF parity error", -1, 1},
+		{F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1},
+		{F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1},
+		{F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1},
 		{0}
 	};
 
@@ -1435,6 +1484,7 @@ static void ulptx_intr_handler(struct adapter *adapter)
 		 STAT_ULP_CH0_PBL_OOB, 0},
 		{F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
 		 STAT_ULP_CH1_PBL_OOB, 0},
+		{0xfc, "ULP TX parity error", -1, 1},
 		{0}
 	};
 
@@ -1509,7 +1559,8 @@ static void pmrx_intr_handler(struct adapter *adapter)
 static void cplsw_intr_handler(struct adapter *adapter)
 {
 	static const struct intr_info cplsw_intr_info[] = {
-/*		{ F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, */
+		{F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1},
+		{F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1},
 		{F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1},
 		{F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1},
 		{F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1},
@@ -1730,7 +1781,6 @@ void t3_intr_enable(struct adapter *adapter)
 		 MC7_INTR_MASK},
 		{A_MC5_DB_INT_ENABLE, MC5_INTR_MASK},
 		{A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK},
-		{A_TP_INT_ENABLE, 0x3bfffff},
 		{A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK},
 		{A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK},
 		{A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK},
@@ -1740,6 +1790,8 @@ void t3_intr_enable(struct adapter *adapter)
 	adapter->slow_intr_mask = PL_INTR_MASK;
 
 	t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
+	t3_write_reg(adapter, A_TP_INT_ENABLE,
+		     adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff);
 
 	if (adapter->params.rev > 0) {
 		t3_write_reg(adapter, A_CPL_INTR_ENABLE,
@@ -1894,6 +1946,16 @@ static int t3_sge_write_context(struct adapter *adapter, unsigned int id,
 			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
 }
 
+static int clear_sge_ctxt(struct adapter *adap, unsigned int id,
+			  unsigned int type)
+{
+	t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0);
+	t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0);
+	t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0);
+	t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0);
+	return t3_sge_write_context(adap, id, type);
+}
+
 /**
  *	t3_sge_init_ecntxt - initialize an SGE egress context
  *	@adapter: the adapter to configure
@@ -2395,7 +2457,7 @@ static inline unsigned int pm_num_pages(unsigned int mem_size,
 	t3_write_reg((adap), A_ ## reg, (start)); \
 	start += size
 
-/*
+/**
  *	partition_mem - partition memory and configure TP memory settings
  *	@adap: the adapter
  *	@p: the TP parameters
@@ -2480,7 +2542,7 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
 		     V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
 		     V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) |
 		     F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
-	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_IPV6ENABLE | F_NICMODE,
+	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO,
 			 F_IPV6ENABLE | F_NICMODE);
 	t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
 	t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
@@ -2492,10 +2554,12 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
 			 F_ENABLEEPCMDAFULL,
 			 F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK |
 			 F_TXCONGESTIONMODE | F_RXCONGESTIONMODE);
-	t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0);
+	t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL,
+			 F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN |
+			 F_ENABLEARPMISS | F_DISBLEDAPARBIT0);
 	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080);
 	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000);
-	
+
 	if (adap->params.rev > 0) {
 		tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
 		t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
@@ -2505,6 +2569,11 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
 	} else
 		t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
 
+	if (adap->params.rev == T3_REV_C)
+		t3_set_reg_field(adap, A_TP_PC_CONFIG,
+				 V_TABLELATENCYDELTA(M_TABLELATENCYDELTA),
+				 V_TABLELATENCYDELTA(4));
+
 	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0);
 	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0);
 	t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0);
@@ -2809,15 +2878,15 @@ static void ulp_config(struct adapter *adap, const struct tp_params *p)
 int t3_set_proto_sram(struct adapter *adap, u8 *data)
 {
 	int i;
-	u32 *buf = (u32 *)data;
+	__be32 *buf = (__be32 *)data;
 
 	for (i = 0; i < PROTO_SRAM_LINES; i++) {
-		t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++));
-		t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++));
-		t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++));
-		t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++));
-		t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++));
-		
+		t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, be32_to_cpu(*buf++));
+		t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, be32_to_cpu(*buf++));
+		t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, be32_to_cpu(*buf++));
+		t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, be32_to_cpu(*buf++));
+		t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, be32_to_cpu(*buf++));
+
 		t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31);
 		if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1))
 			return -EIO;
@@ -3194,7 +3263,8 @@ static void config_pcie(struct adapter *adap)
 			 V_REPLAYLMT(rpllmt));
 
 	t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
-	t3_set_reg_field(adap, A_PCIE_CFG, F_PCIE_CLIDECEN, F_PCIE_CLIDECEN);
+	t3_set_reg_field(adap, A_PCIE_CFG, 0,
+			 F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN);
 }
 
 /*
@@ -3207,7 +3277,7 @@ static void config_pcie(struct adapter *adap)
  */
 int t3_init_hw(struct adapter *adapter, u32 fw_params)
 {
-	int err = -EIO, attempts = 100;
+	int err = -EIO, attempts, i;
 	const struct vpd_params *vpd = &adapter->params.vpd;
 
 	if (adapter->params.rev > 0)
@@ -3225,6 +3295,10 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
 				adapter->params.mc5.nfilters,
 				adapter->params.mc5.nroutes))
 			goto out_err;
+
+		for (i = 0; i < 32; i++)
+			if (clear_sge_ctxt(adapter, i, F_CQ))
+				goto out_err;
 	}
 
 	if (tp_init(adapter, &adapter->params.tp))
@@ -3240,7 +3314,12 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
 	if (is_pcie(adapter))
 		config_pcie(adapter);
 	else
-		t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
+		t3_set_reg_field(adapter, A_PCIX_CFG, 0,
+				 F_DMASTOPEN | F_CLIDECEN);
+
+	if (adapter->params.rev == T3_REV_C)
+		t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0,
+				 F_CFG_CQE_SOP_MASK);
 
 	t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
 	t3_write_reg(adapter, A_PM1_RX_MODE, 0);
@@ -3253,6 +3332,7 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
 		     V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
 	t3_read_reg(adapter, A_CIM_BOOT_CFG);	/* flush */
 
+	attempts = 100;
 	do {			/* wait for uP to initialize */
 		msleep(20);
 	} while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
@@ -3387,6 +3467,7 @@ void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
 	t3_write_reg(adapter, A_T3DBG_GPIO_EN,
 		     ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
 	t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0);
+	t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff));
 
 	if (adapter->params.rev == 0 || !uses_xaui(adapter))
 		val |= F_ENRGMII;
@@ -3403,13 +3484,13 @@ void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
 }
 
 /*
- * Reset the adapter. 
+ * Reset the adapter.
  * Older PCIe cards lose their config space during reset, PCI-X
  * ones don't.
  */
 static int t3_reset_adapter(struct adapter *adapter)
 {
-	int i, save_and_restore_pcie = 
+	int i, save_and_restore_pcie =
 	    adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
 	uint16_t devid = 0;
 
@@ -3436,6 +3517,36 @@ static int t3_reset_adapter(struct adapter *adapter)
 	return 0;
 }
 
+static int __devinit init_parity(struct adapter *adap)
+{
+		int i, err, addr;
+
+	if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+		return -EBUSY;
+
+	for (err = i = 0; !err && i < 16; i++)
+		err = clear_sge_ctxt(adap, i, F_EGRESS);
+	for (i = 0xfff0; !err && i <= 0xffff; i++)
+		err = clear_sge_ctxt(adap, i, F_EGRESS);
+	for (i = 0; !err && i < SGE_QSETS; i++)
+		err = clear_sge_ctxt(adap, i, F_RESPONSEQ);
+	if (err)
+		return err;
+
+	t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0);
+	for (i = 0; i < 4; i++)
+		for (addr = 0; addr <= M_IBQDBGADDR; addr++) {
+			t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN |
+				     F_IBQDBGWR | V_IBQDBGQID(i) |
+				     V_IBQDBGADDR(addr));
+			err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG,
+					      F_IBQDBGBUSY, 0, 2, 1);
+			if (err)
+				return err;
+		}
+	return 0;
+}
+
 /*
  * Initialize adapter SW state for the various HW modules, set initial values
  * for some adapter tunables, take PHYs out of reset, and initialize the MDIO
@@ -3503,6 +3614,9 @@ int __devinit t3_prep_adapter(struct adapter *adapter,
 	}
 
 	early_hw_init(adapter, ai);
+	ret = init_parity(adapter);
+	if (ret)
+		return ret;
 
 	for_each_port(adapter, i) {
 		u8 hw_addr[6];
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index ef1c6339c806..229303ff6a39 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -38,7 +38,7 @@
 #define DRV_VERSION "1.0-ko"
 
 /* Firmware version */
-#define FW_VERSION_MAJOR 4
-#define FW_VERSION_MINOR 6
+#define FW_VERSION_MAJOR 5
+#define FW_VERSION_MINOR 0
 #define FW_VERSION_MICRO 0
 #endif				/* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index efcf09a709cf..ffdc0a1892bd 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -153,7 +153,7 @@ static int t3b2_mac_reset(struct cmac *mac)
 	unsigned int oft = mac->offset;
 	u32 val;
 
-	if (!macidx(mac)) 
+	if (!macidx(mac))
 		t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
 	else
 		t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
@@ -187,11 +187,11 @@ static int t3b2_mac_reset(struct cmac *mac)
 		msleep(1);
 		t3b_pcs_reset(mac);
 	}
-	t3_write_reg(adap, A_XGM_RX_CFG + oft, 
+	t3_write_reg(adap, A_XGM_RX_CFG + oft,
 		     F_DISPAUSEFRAMES | F_EN1536BFRAMES |
 		     F_RMFCS | F_ENJUMBO | F_ENHASHMCAST);
 
-	if (!macidx(mac)) 
+	if (!macidx(mac))
 		t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
 	else
 		t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
@@ -336,7 +336,7 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
 	 * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
 	 * HWM only if flow-control is enabled.
 	 */
-	hwm = max_t(unsigned int, MAC_RXFIFO_SIZE - 3 * mtu, 
+	hwm = max_t(unsigned int, MAC_RXFIFO_SIZE - 3 * mtu,
 		    MAC_RXFIFO_SIZE * 38 / 100);
 	hwm = min(hwm, MAC_RXFIFO_SIZE - 8192);
 	lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);
@@ -449,7 +449,7 @@ int t3_mac_enable(struct cmac *mac, int which)
 	struct adapter *adap = mac->adapter;
 	unsigned int oft = mac->offset;
 	struct mac_stats *s = &mac->stats;
-	
+
 	if (which & MAC_DIRECTION_TX) {
 		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
 		t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401);
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 00e0194bfef0..6b1e77cc069e 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -719,15 +719,15 @@ out:
 	spin_unlock(&lp->lock);
 }
 
-static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id)
+static irqreturn_t lance_dma_merr_int(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
 
-	printk("%s: DMA error\n", dev->name);
+	printk(KERN_ERR "%s: DMA error\n", dev->name);
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t lance_interrupt(const int irq, void *dev_id)
+static irqreturn_t lance_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
 	struct lance_private *lp = netdev_priv(dev);
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 3286d2a0a870..6a20a5491a96 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -66,6 +66,7 @@
 #include <linux/dm9000.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/irq.h>
 
 #include <asm/delay.h>
 #include <asm/irq.h>
@@ -113,7 +114,7 @@
 #define writesl	outsl
 #define DM9000_IRQ_FLAGS	(IRQF_SHARED | IRQF_TRIGGER_HIGH)
 #else
-#define DM9000_IRQ_FLAGS	IRQF_SHARED
+#define DM9000_IRQ_FLAGS	(IRQF_SHARED | IRQT_RISING)
 #endif
 
 /*
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index b87402bc8308..51cf577035be 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -106,6 +106,13 @@
  *	the RFD, the RFD must be dma_sync'ed to maintain a consistent
  *	view from software and hardware.
  *
+ *	In order to keep updates to the RFD link field from colliding with
+ *	hardware writes to mark packets complete, we use the feature that
+ *	hardware will not write to a size 0 descriptor and mark the previous
+ *	packet as end-of-list (EL).   After updating the link, we remove EL
+ *	and only then restore the size such that hardware may use the
+ *	previous-to-end RFD.
+ *
  *	Under typical operation, the  receive unit (RU) is start once,
  *	and the controller happily fills RFDs as frames arrive.  If
  *	replacement RFDs cannot be allocated, or the RU goes non-active,
@@ -281,6 +288,7 @@ struct csr {
 };
 
 enum scb_status {
+	rus_no_res       = 0x08,
 	rus_ready        = 0x10,
 	rus_mask         = 0x3C,
 };
@@ -393,12 +401,12 @@ enum cb_command {
 };
 
 struct rfd {
-	u16 status;
-	u16 command;
-	u32 link;
-	u32 rbd;
-	u16 actual_size;
-	u16 size;
+	__le16 status;
+	__le16 command;
+	__le32 link;
+	__le32 rbd;
+	__le16 actual_size;
+	__le16 size;
 };
 
 struct rx {
@@ -453,19 +461,19 @@ struct config {
 
 #define E100_MAX_MULTICAST_ADDRS	64
 struct multi {
-	u16 count;
+	__le16 count;
 	u8 addr[E100_MAX_MULTICAST_ADDRS * ETH_ALEN + 2/*pad*/];
 };
 
 /* Important: keep total struct u32-aligned */
 #define UCODE_SIZE			134
 struct cb {
-	u16 status;
-	u16 command;
-	u32 link;
+	__le16 status;
+	__le16 command;
+	__le32 link;
 	union {
 		u8 iaaddr[ETH_ALEN];
-		u32 ucode[UCODE_SIZE];
+		__le32 ucode[UCODE_SIZE];
 		struct config config;
 		struct multi multi;
 		struct {
@@ -474,12 +482,12 @@ struct cb {
 			u8 threshold;
 			u8 tbd_count;
 			struct {
-				u32 buf_addr;
-				u16 size;
+				__le32 buf_addr;
+				__le16 size;
 				u16 eol;
 			} tbd;
 		} tcb;
-		u32 dump_buffer_addr;
+		__le32 dump_buffer_addr;
 	} u;
 	struct cb *next, *prev;
 	dma_addr_t dma_addr;
@@ -491,15 +499,15 @@ enum loopback {
 };
 
 struct stats {
-	u32 tx_good_frames, tx_max_collisions, tx_late_collisions,
+	__le32 tx_good_frames, tx_max_collisions, tx_late_collisions,
 		tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
 		tx_multiple_collisions, tx_total_collisions;
-	u32 rx_good_frames, rx_crc_errors, rx_alignment_errors,
+	__le32 rx_good_frames, rx_crc_errors, rx_alignment_errors,
 		rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
 		rx_short_frame_errors;
-	u32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
-	u16 xmt_tco_frames, rcv_tco_frames;
-	u32 complete;
+	__le32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
+	__le16 xmt_tco_frames, rcv_tco_frames;
+	__le32 complete;
 };
 
 struct mem {
@@ -544,7 +552,7 @@ struct nic {
 	struct cb *cb_to_use;
 	struct cb *cb_to_send;
 	struct cb *cb_to_clean;
-	u16 tx_command;
+	__le16 tx_command;
 	/* End: frequently used values: keep adjacent for cache effect */
 
 	enum {
@@ -585,7 +593,7 @@ struct nic {
 
 	u16 leds;
 	u16 eeprom_wc;
-	u16 eeprom[256];
+	__le16 eeprom[256];
 	spinlock_t mdio_lock;
 };
 
@@ -663,7 +671,7 @@ static int e100_self_test(struct nic *nic)
 	return 0;
 }
 
-static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data)
+static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, __le16 data)
 {
 	u32 cmd_addr_data[3];
 	u8 ctrl;
@@ -672,7 +680,7 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data)
 	/* Three cmds: write/erase enable, write data, write/erase disable */
 	cmd_addr_data[0] = op_ewen << (addr_len - 2);
 	cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) |
-		cpu_to_le16(data);
+		le16_to_cpu(data);
 	cmd_addr_data[2] = op_ewds << (addr_len - 2);
 
 	/* Bit-bang cmds to write word to eeprom */
@@ -701,7 +709,7 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data)
 };
 
 /* General technique stolen from the eepro100 driver - very clever */
-static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
+static __le16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
 {
 	u32 cmd_addr_data;
 	u16 data = 0;
@@ -738,7 +746,7 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
 	iowrite8(0, &nic->csr->eeprom_ctrl_lo);
 	e100_write_flush(nic); udelay(4);
 
-	return le16_to_cpu(data);
+	return cpu_to_le16(data);
 };
 
 /* Load entire EEPROM image into driver cache and validate checksum */
@@ -753,13 +761,12 @@ static int e100_eeprom_load(struct nic *nic)
 	for(addr = 0; addr < nic->eeprom_wc; addr++) {
 		nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr);
 		if(addr < nic->eeprom_wc - 1)
-			checksum += cpu_to_le16(nic->eeprom[addr]);
+			checksum += le16_to_cpu(nic->eeprom[addr]);
 	}
 
 	/* The checksum, stored in the last word, is calculated such that
 	 * the sum of words should be 0xBABA */
-	checksum = le16_to_cpu(0xBABA - checksum);
-	if(checksum != nic->eeprom[nic->eeprom_wc - 1]) {
+	if (cpu_to_le16(0xBABA - checksum) != nic->eeprom[nic->eeprom_wc - 1]) {
 		DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
 		if (!eeprom_bad_csum_allow)
 			return -EAGAIN;
@@ -786,8 +793,8 @@ static int e100_eeprom_save(struct nic *nic, u16 start, u16 count)
 	/* The checksum, stored in the last word, is calculated such that
 	 * the sum of words should be 0xBABA */
 	for(addr = 0; addr < nic->eeprom_wc - 1; addr++)
-		checksum += cpu_to_le16(nic->eeprom[addr]);
-	nic->eeprom[nic->eeprom_wc - 1] = le16_to_cpu(0xBABA - checksum);
+		checksum += le16_to_cpu(nic->eeprom[addr]);
+	nic->eeprom[nic->eeprom_wc - 1] = cpu_to_le16(0xBABA - checksum);
 	e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1,
 		nic->eeprom[nic->eeprom_wc - 1]);
 
@@ -952,7 +959,7 @@ static void e100_get_defaults(struct nic *nic)
 		((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
 
 	/* Template for a freshly allocated RFD */
-	nic->blank_rfd.command = cpu_to_le16(cb_el);
+	nic->blank_rfd.command = 0;
 	nic->blank_rfd.rbd = 0xFFFFFFFF;
 	nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
 
@@ -1485,15 +1492,15 @@ static void e100_update_stats(struct nic *nic)
 	struct net_device *dev = nic->netdev;
 	struct net_device_stats *ns = &dev->stats;
 	struct stats *s = &nic->mem->stats;
-	u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause :
-		(nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames :
+	__le32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause :
+		(nic->mac < mac_82559_D101M) ? (__le32 *)&s->xmt_tco_frames :
 		&s->complete;
 
 	/* Device's stats reporting may take several microseconds to
 	 * complete, so where always waiting for results of the
 	 * previous command. */
 
-	if(*complete == le32_to_cpu(cuc_dump_reset_complete)) {
+	if(*complete == cpu_to_le32(cuc_dump_reset_complete)) {
 		*complete = 0;
 		nic->tx_frames = le32_to_cpu(s->tx_good_frames);
 		nic->tx_collisions = le32_to_cpu(s->tx_total_collisions);
@@ -1783,7 +1790,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
 	rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
 		RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
 
-	if(pci_dma_mapping_error(rx->dma_addr)) {
+	if (pci_dma_mapping_error(rx->dma_addr)) {
 		dev_kfree_skb_any(rx->skb);
 		rx->skb = NULL;
 		rx->dma_addr = 0;
@@ -1791,15 +1798,11 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
 	}
 
 	/* Link the RFD to end of RFA by linking previous RFD to
-	 * this one, and clearing EL bit of previous.  */
-	if(rx->prev->skb) {
+	 * this one.  We are safe to touch the previous RFD because
+	 * it is protected by the before last buffer's el bit being set */
+	if (rx->prev->skb) {
 		struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
-		put_unaligned(cpu_to_le32(rx->dma_addr),
-			(u32 *)&prev_rfd->link);
-		wmb();
-		prev_rfd->command &= ~cpu_to_le16(cb_el);
-		pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
-			sizeof(struct rfd), PCI_DMA_TODEVICE);
+		put_unaligned(cpu_to_le32(rx->dma_addr), &prev_rfd->link);
 	}
 
 	return 0;
@@ -1824,8 +1827,19 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
 	DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
 
 	/* If data isn't ready, nothing to indicate */
-	if(unlikely(!(rfd_status & cb_complete)))
+	if (unlikely(!(rfd_status & cb_complete))) {
+		/* If the next buffer has the el bit, but we think the receiver
+		 * is still running, check to see if it really stopped while
+		 * we had interrupts off.
+		 * This allows for a fast restart without re-enabling
+		 * interrupts */
+		if ((le16_to_cpu(rfd->command) & cb_el) &&
+		    (RU_RUNNING == nic->ru_running))
+
+			if (readb(&nic->csr->scb.status) & rus_no_res)
+				nic->ru_running = RU_SUSPENDED;
 		return -ENODATA;
+	}
 
 	/* Get actual data size */
 	actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
@@ -1836,9 +1850,18 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
 	pci_unmap_single(nic->pdev, rx->dma_addr,
 		RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
 
-	/* this allows for a fast restart without re-enabling interrupts */
-	if(le16_to_cpu(rfd->command) & cb_el)
+	/* If this buffer has the el bit, but we think the receiver
+	 * is still running, check to see if it really stopped while
+	 * we had interrupts off.
+	 * This allows for a fast restart without re-enabling interrupts.
+	 * This can happen when the RU sees the size change but also sees
+	 * the el bit set. */
+	if ((le16_to_cpu(rfd->command) & cb_el) &&
+	    (RU_RUNNING == nic->ru_running)) {
+
+	    if (readb(&nic->csr->scb.status) & rus_no_res)
 		nic->ru_running = RU_SUSPENDED;
+	}
 
 	/* Pull off the RFD and put the actual data (minus eth hdr) */
 	skb_reserve(skb, sizeof(struct rfd));
@@ -1870,31 +1893,30 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
 	unsigned int work_to_do)
 {
 	struct rx *rx;
-	int restart_required = 0;
-	struct rx *rx_to_start = NULL;
-
-	/* are we already rnr? then pay attention!!! this ensures that
-	 * the state machine progression never allows a start with a
-	 * partially cleaned list, avoiding a race between hardware
-	 * and rx_to_clean when in NAPI mode */
-	if(RU_SUSPENDED == nic->ru_running)
-		restart_required = 1;
+	int restart_required = 0, err = 0;
+	struct rx *old_before_last_rx, *new_before_last_rx;
+	struct rfd *old_before_last_rfd, *new_before_last_rfd;
 
 	/* Indicate newly arrived packets */
 	for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
-		int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
-		if(-EAGAIN == err) {
-			/* hit quota so have more work to do, restart once
-			 * cleanup is complete */
-			restart_required = 0;
+		err = e100_rx_indicate(nic, rx, work_done, work_to_do);
+		/* Hit quota or no more to clean */
+		if (-EAGAIN == err || -ENODATA == err)
 			break;
-		} else if(-ENODATA == err)
-			break; /* No more to clean */
 	}
 
-	/* save our starting point as the place we'll restart the receiver */
-	if(restart_required)
-		rx_to_start = nic->rx_to_clean;
+
+	/* On EAGAIN, hit quota so have more work to do, restart once
+	 * cleanup is complete.
+	 * Else, are we already rnr? then pay attention!!! this ensures that
+	 * the state machine progression never allows a start with a
+	 * partially cleaned list, avoiding a race between hardware
+	 * and rx_to_clean when in NAPI mode */
+	if (-EAGAIN != err && RU_SUSPENDED == nic->ru_running)
+		restart_required = 1;
+
+	old_before_last_rx = nic->rx_to_use->prev->prev;
+	old_before_last_rfd = (struct rfd *)old_before_last_rx->skb->data;
 
 	/* Alloc new skbs to refill list */
 	for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
@@ -1902,10 +1924,42 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
 			break; /* Better luck next time (see watchdog) */
 	}
 
+	new_before_last_rx = nic->rx_to_use->prev->prev;
+	if (new_before_last_rx != old_before_last_rx) {
+		/* Set the el-bit on the buffer that is before the last buffer.
+		 * This lets us update the next pointer on the last buffer
+		 * without worrying about hardware touching it.
+		 * We set the size to 0 to prevent hardware from touching this
+		 * buffer.
+		 * When the hardware hits the before last buffer with el-bit
+		 * and size of 0, it will RNR interrupt, the RUS will go into
+		 * the No Resources state.  It will not complete nor write to
+		 * this buffer. */
+		new_before_last_rfd =
+			(struct rfd *)new_before_last_rx->skb->data;
+		new_before_last_rfd->size = 0;
+		new_before_last_rfd->command |= cpu_to_le16(cb_el);
+		pci_dma_sync_single_for_device(nic->pdev,
+			new_before_last_rx->dma_addr, sizeof(struct rfd),
+			PCI_DMA_TODEVICE);
+
+		/* Now that we have a new stopping point, we can clear the old
+		 * stopping point.  We must sync twice to get the proper
+		 * ordering on the hardware side of things. */
+		old_before_last_rfd->command &= ~cpu_to_le16(cb_el);
+		pci_dma_sync_single_for_device(nic->pdev,
+			old_before_last_rx->dma_addr, sizeof(struct rfd),
+			PCI_DMA_TODEVICE);
+		old_before_last_rfd->size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
+		pci_dma_sync_single_for_device(nic->pdev,
+			old_before_last_rx->dma_addr, sizeof(struct rfd),
+			PCI_DMA_TODEVICE);
+	}
+
 	if(restart_required) {
 		// ack the rnr?
 		writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
-		e100_start_receiver(nic, rx_to_start);
+		e100_start_receiver(nic, nic->rx_to_clean);
 		if(work_done)
 			(*work_done)++;
 	}
@@ -1937,6 +1991,7 @@ static int e100_rx_alloc_list(struct nic *nic)
 {
 	struct rx *rx;
 	unsigned int i, count = nic->params.rfds.count;
+	struct rfd *before_last;
 
 	nic->rx_to_use = nic->rx_to_clean = NULL;
 	nic->ru_running = RU_UNINITIALIZED;
@@ -1952,6 +2007,19 @@ static int e100_rx_alloc_list(struct nic *nic)
 			return -ENOMEM;
 		}
 	}
+	/* Set the el-bit on the buffer that is before the last buffer.
+	 * This lets us update the next pointer on the last buffer without
+	 * worrying about hardware touching it.
+	 * We set the size to 0 to prevent hardware from touching this buffer.
+	 * When the hardware hits the before last buffer with el-bit and size
+	 * of 0, it will RNR interrupt, the RU will go into the No Resources
+	 * state.  It will not complete nor write to this buffer. */
+	rx = nic->rxs->prev->prev;
+	before_last = (struct rfd *)rx->skb->data;
+	before_last->command |= cpu_to_le16(cb_el);
+	before_last->size = 0;
+	pci_dma_sync_single_for_device(nic->pdev, rx->dma_addr,
+		sizeof(struct rfd), PCI_DMA_TODEVICE);
 
 	nic->rx_to_use = nic->rx_to_clean = nic->rxs;
 	nic->ru_running = RU_SUSPENDED;
@@ -2369,7 +2437,7 @@ static const char e100_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Mac loopback     (offline)",
 	"Phy loopback     (offline)",
 };
-#define E100_TEST_LEN	sizeof(e100_gstrings_test) / ETH_GSTRING_LEN
+#define E100_TEST_LEN	ARRAY_SIZE(e100_gstrings_test)
 
 static void e100_diag_test(struct net_device *netdev,
 	struct ethtool_test *test, u64 *data)
@@ -2431,7 +2499,7 @@ static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
 	"rx_flow_control_unsupported", "tx_tco_packets", "rx_tco_packets",
 };
 #define E100_NET_STATS_LEN	21
-#define E100_STATS_LEN	sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
+#define E100_STATS_LEN	ARRAY_SIZE(e100_gstrings_stats)
 
 static int e100_get_sset_count(struct net_device *netdev, int sset)
 {
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index b83ccce8a9b7..d876787ce336 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -110,7 +110,7 @@ static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Interrupt test (offline)", "Loopback test  (offline)",
 	"Link test   (on/offline)"
 };
-#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN
+#define E1000_TEST_LEN	ARRAY_SIZE(e1000_gstrings_test)
 
 static int
 e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
@@ -728,39 +728,65 @@ err_setup:
 	return err;
 }
 
-#define REG_PATTERN_TEST(R, M, W)                                              \
-{                                                                              \
-	uint32_t pat, val;                                                     \
-	const uint32_t test[] = 					       \
-		{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};              \
-	for (pat = 0; pat < ARRAY_SIZE(test); pat++) {           	       \
-		E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W));             \
-		val = E1000_READ_REG(&adapter->hw, R);                         \
-		if (val != (test[pat] & W & M)) {                              \
-			DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " \
-			        "0x%08X expected 0x%08X\n",                    \
-			        E1000_##R, val, (test[pat] & W & M));          \
-			*data = (adapter->hw.mac_type < e1000_82543) ?         \
-				E1000_82542_##R : E1000_##R;                   \
-			return 1;                                              \
-		}                                                              \
-	}                                                                      \
+static bool reg_pattern_test(struct e1000_adapter *adapter, uint64_t *data,
+			     int reg, uint32_t mask, uint32_t write)
+{
+	static const uint32_t test[] =
+		{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+	uint8_t __iomem *address = adapter->hw.hw_addr + reg;
+	uint32_t read;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(test); i++) {
+		writel(write & test[i], address);
+		read = readl(address);
+		if (read != (write & test[i] & mask)) {
+			DPRINTK(DRV, ERR, "pattern test reg %04X failed: "
+				"got 0x%08X expected 0x%08X\n",
+				reg, read, (write & test[i] & mask));
+			*data = reg;
+			return true;
+		}
+	}
+	return false;
 }
 
-#define REG_SET_AND_CHECK(R, M, W)                                             \
-{                                                                              \
-	uint32_t val;                                                          \
-	E1000_WRITE_REG(&adapter->hw, R, W & M);                               \
-	val = E1000_READ_REG(&adapter->hw, R);                                 \
-	if ((W & M) != (val & M)) {                                            \
-		DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
-		        "expected 0x%08X\n", E1000_##R, (val & M), (W & M));   \
-		*data = (adapter->hw.mac_type < e1000_82543) ?                 \
-			E1000_82542_##R : E1000_##R;                           \
-		return 1;                                                      \
-	}                                                                      \
+static bool reg_set_and_check(struct e1000_adapter *adapter, uint64_t *data,
+			      int reg, uint32_t mask, uint32_t write)
+{
+	uint8_t __iomem *address = adapter->hw.hw_addr + reg;
+	uint32_t read;
+
+	writel(write & mask, address);
+	read = readl(address);
+	if ((read & mask) != (write & mask)) {
+		DPRINTK(DRV, ERR, "set/check reg %04X test failed: "
+			"got 0x%08X expected 0x%08X\n",
+			reg, (read & mask), (write & mask));
+		*data = reg;
+		return true;
+	}
+	return false;
 }
 
+#define REG_PATTERN_TEST(reg, mask, write)			     \
+	do {							     \
+		if (reg_pattern_test(adapter, data,		     \
+			     (adapter->hw.mac_type >= e1000_82543)   \
+			     ? E1000_##reg : E1000_82542_##reg,	     \
+			     mask, write))			     \
+			return 1;				     \
+	} while (0)
+
+#define REG_SET_AND_CHECK(reg, mask, write)			     \
+	do {							     \
+		if (reg_set_and_check(adapter, data,		     \
+			      (adapter->hw.mac_type >= e1000_82543)  \
+			      ? E1000_##reg : E1000_82542_##reg,     \
+			      mask, write))			     \
+			return 1;				     \
+	} while (0)
+
 static int
 e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
 {
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index a2a86c54a75c..a6c3c34feb98 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -421,8 +421,6 @@ void e1000_tbi_adjust_stats(struct e1000_hw *hw, struct e1000_hw_stats *stats, u
 void e1000_get_bus_info(struct e1000_hw *hw);
 void e1000_pci_set_mwi(struct e1000_hw *hw);
 void e1000_pci_clear_mwi(struct e1000_hw *hw);
-void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
-void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
 int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value);
 void e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc);
 int e1000_pcix_get_mmrbc(struct e1000_hw *hw);
@@ -595,35 +593,35 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
 
 /* Receive Descriptor */
 struct e1000_rx_desc {
-    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
-    uint16_t length;     /* Length of data DMAed into data buffer */
-    uint16_t csum;       /* Packet checksum */
+    __le64 buffer_addr; /* Address of the descriptor's data buffer */
+    __le16 length;     /* Length of data DMAed into data buffer */
+    __le16 csum;       /* Packet checksum */
     uint8_t status;      /* Descriptor status */
     uint8_t errors;      /* Descriptor Errors */
-    uint16_t special;
+    __le16 special;
 };
 
 /* Receive Descriptor - Extended */
 union e1000_rx_desc_extended {
     struct {
-        uint64_t buffer_addr;
-        uint64_t reserved;
+        __le64 buffer_addr;
+        __le64 reserved;
     } read;
     struct {
         struct {
-            uint32_t mrq;              /* Multiple Rx Queues */
+            __le32 mrq;              /* Multiple Rx Queues */
             union {
-                uint32_t rss;          /* RSS Hash */
+                __le32 rss;          /* RSS Hash */
                 struct {
-                    uint16_t ip_id;    /* IP id */
-                    uint16_t csum;     /* Packet Checksum */
+                    __le16 ip_id;    /* IP id */
+                    __le16 csum;     /* Packet Checksum */
                 } csum_ip;
             } hi_dword;
         } lower;
         struct {
-            uint32_t status_error;     /* ext status/error */
-            uint16_t length;
-            uint16_t vlan;             /* VLAN tag */
+            __le32 status_error;     /* ext status/error */
+            __le16 length;
+            __le16 vlan;             /* VLAN tag */
         } upper;
     } wb;  /* writeback */
 };
@@ -633,29 +631,29 @@ union e1000_rx_desc_extended {
 union e1000_rx_desc_packet_split {
     struct {
         /* one buffer for protocol header(s), three data buffers */
-        uint64_t buffer_addr[MAX_PS_BUFFERS];
+        __le64 buffer_addr[MAX_PS_BUFFERS];
     } read;
     struct {
         struct {
-            uint32_t mrq;              /* Multiple Rx Queues */
+            __le32 mrq;              /* Multiple Rx Queues */
             union {
-                uint32_t rss;          /* RSS Hash */
+                __le32 rss;          /* RSS Hash */
                 struct {
-                    uint16_t ip_id;    /* IP id */
-                    uint16_t csum;     /* Packet Checksum */
+                    __le16 ip_id;    /* IP id */
+                    __le16 csum;     /* Packet Checksum */
                 } csum_ip;
             } hi_dword;
         } lower;
         struct {
-            uint32_t status_error;     /* ext status/error */
-            uint16_t length0;          /* length of buffer 0 */
-            uint16_t vlan;             /* VLAN tag */
+            __le32 status_error;     /* ext status/error */
+            __le16 length0;          /* length of buffer 0 */
+            __le16 vlan;             /* VLAN tag */
         } middle;
         struct {
-            uint16_t header_status;
-            uint16_t length[3];        /* length of buffers 1-3 */
+            __le16 header_status;
+            __le16 length[3];        /* length of buffers 1-3 */
         } upper;
-        uint64_t reserved;
+        __le64 reserved;
     } wb; /* writeback */
 };
 
@@ -715,21 +713,21 @@ union e1000_rx_desc_packet_split {
 
 /* Transmit Descriptor */
 struct e1000_tx_desc {
-    uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
+    __le64 buffer_addr;       /* Address of the descriptor's data buffer */
     union {
-        uint32_t data;
+        __le32 data;
         struct {
-            uint16_t length;    /* Data buffer length */
+            __le16 length;    /* Data buffer length */
             uint8_t cso;        /* Checksum offset */
             uint8_t cmd;        /* Descriptor control */
         } flags;
     } lower;
     union {
-        uint32_t data;
+        __le32 data;
         struct {
             uint8_t status;     /* Descriptor status */
             uint8_t css;        /* Checksum start */
-            uint16_t special;
+            __le16 special;
         } fields;
     } upper;
 };
@@ -759,49 +757,49 @@ struct e1000_tx_desc {
 /* Offload Context Descriptor */
 struct e1000_context_desc {
     union {
-        uint32_t ip_config;
+        __le32 ip_config;
         struct {
             uint8_t ipcss;      /* IP checksum start */
             uint8_t ipcso;      /* IP checksum offset */
-            uint16_t ipcse;     /* IP checksum end */
+            __le16 ipcse;     /* IP checksum end */
         } ip_fields;
     } lower_setup;
     union {
-        uint32_t tcp_config;
+        __le32 tcp_config;
         struct {
             uint8_t tucss;      /* TCP checksum start */
             uint8_t tucso;      /* TCP checksum offset */
-            uint16_t tucse;     /* TCP checksum end */
+            __le16 tucse;     /* TCP checksum end */
         } tcp_fields;
     } upper_setup;
-    uint32_t cmd_and_length;    /* */
+    __le32 cmd_and_length;    /* */
     union {
-        uint32_t data;
+        __le32 data;
         struct {
             uint8_t status;     /* Descriptor status */
             uint8_t hdr_len;    /* Header length */
-            uint16_t mss;       /* Maximum segment size */
+            __le16 mss;       /* Maximum segment size */
         } fields;
     } tcp_seg_setup;
 };
 
 /* Offload data descriptor */
 struct e1000_data_desc {
-    uint64_t buffer_addr;       /* Address of the descriptor's buffer address */
+    __le64 buffer_addr;       /* Address of the descriptor's buffer address */
     union {
-        uint32_t data;
+        __le32 data;
         struct {
-            uint16_t length;    /* Data buffer length */
+            __le16 length;    /* Data buffer length */
             uint8_t typ_len_ext;        /* */
             uint8_t cmd;        /* */
         } flags;
     } lower;
     union {
-        uint32_t data;
+        __le32 data;
         struct {
             uint8_t status;     /* Descriptor status */
             uint8_t popts;      /* Packet Options */
-            uint16_t special;   /* */
+            __le16 special;   /* */
         } fields;
     } upper;
 };
@@ -817,8 +815,8 @@ struct e1000_data_desc {
 
 /* Receive Address Register */
 struct e1000_rar {
-    volatile uint32_t low;      /* receive address low */
-    volatile uint32_t high;     /* receive address high */
+    volatile __le32 low;      /* receive address low */
+    volatile __le32 high;     /* receive address high */
 };
 
 /* Number of entries in the Multicast Table Array (MTA). */
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 76c0fa690cc6..8c87940a9ce8 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -47,6 +47,12 @@ static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation
  * Macro expands to...
  *   {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
  */
+#ifdef CONFIG_E1000E_ENABLED
+  #define PCIE(x) 
+#else
+  #define PCIE(x) x,
+#endif
+
 static struct pci_device_id e1000_pci_tbl[] = {
 	INTEL_E1000_ETHERNET_DEVICE(0x1000),
 	INTEL_E1000_ETHERNET_DEVICE(0x1001),
@@ -73,14 +79,14 @@ static struct pci_device_id e1000_pci_tbl[] = {
 	INTEL_E1000_ETHERNET_DEVICE(0x1026),
 	INTEL_E1000_ETHERNET_DEVICE(0x1027),
 	INTEL_E1000_ETHERNET_DEVICE(0x1028),
-	INTEL_E1000_ETHERNET_DEVICE(0x1049),
-	INTEL_E1000_ETHERNET_DEVICE(0x104A),
-	INTEL_E1000_ETHERNET_DEVICE(0x104B),
-	INTEL_E1000_ETHERNET_DEVICE(0x104C),
-	INTEL_E1000_ETHERNET_DEVICE(0x104D),
-	INTEL_E1000_ETHERNET_DEVICE(0x105E),
-	INTEL_E1000_ETHERNET_DEVICE(0x105F),
-	INTEL_E1000_ETHERNET_DEVICE(0x1060),
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x1049))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x104A))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x104B))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x104C))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x104D))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x105E))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x105F))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x1060))
 	INTEL_E1000_ETHERNET_DEVICE(0x1075),
 	INTEL_E1000_ETHERNET_DEVICE(0x1076),
 	INTEL_E1000_ETHERNET_DEVICE(0x1077),
@@ -89,28 +95,28 @@ static struct pci_device_id e1000_pci_tbl[] = {
 	INTEL_E1000_ETHERNET_DEVICE(0x107A),
 	INTEL_E1000_ETHERNET_DEVICE(0x107B),
 	INTEL_E1000_ETHERNET_DEVICE(0x107C),
-	INTEL_E1000_ETHERNET_DEVICE(0x107D),
-	INTEL_E1000_ETHERNET_DEVICE(0x107E),
-	INTEL_E1000_ETHERNET_DEVICE(0x107F),
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x107D))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x107E))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x107F))
 	INTEL_E1000_ETHERNET_DEVICE(0x108A),
-	INTEL_E1000_ETHERNET_DEVICE(0x108B),
-	INTEL_E1000_ETHERNET_DEVICE(0x108C),
-	INTEL_E1000_ETHERNET_DEVICE(0x1096),
-	INTEL_E1000_ETHERNET_DEVICE(0x1098),
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x108B))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x108C))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x1096))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x1098))
 	INTEL_E1000_ETHERNET_DEVICE(0x1099),
-	INTEL_E1000_ETHERNET_DEVICE(0x109A),
-	INTEL_E1000_ETHERNET_DEVICE(0x10A4),
-	INTEL_E1000_ETHERNET_DEVICE(0x10A5),
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x109A))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10A4))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10A5))
 	INTEL_E1000_ETHERNET_DEVICE(0x10B5),
-	INTEL_E1000_ETHERNET_DEVICE(0x10B9),
-	INTEL_E1000_ETHERNET_DEVICE(0x10BA),
-	INTEL_E1000_ETHERNET_DEVICE(0x10BB),
-	INTEL_E1000_ETHERNET_DEVICE(0x10BC),
-	INTEL_E1000_ETHERNET_DEVICE(0x10C4),
-	INTEL_E1000_ETHERNET_DEVICE(0x10C5),
-	INTEL_E1000_ETHERNET_DEVICE(0x10D5),
-	INTEL_E1000_ETHERNET_DEVICE(0x10D9),
-	INTEL_E1000_ETHERNET_DEVICE(0x10DA),
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10B9))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10BA))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10BB))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10BC))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10C4))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10C5))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10D5))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10D9))
+PCIE(	INTEL_E1000_ETHERNET_DEVICE(0x10DA))
 	/* required last entry */
 	{0,}
 };
@@ -153,7 +159,7 @@ static void e1000_clean_tx_ring(struct e1000_adapter *adapter,
                                 struct e1000_tx_ring *tx_ring);
 static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
                                 struct e1000_rx_ring *rx_ring);
-static void e1000_set_multi(struct net_device *netdev);
+static void e1000_set_rx_mode(struct net_device *netdev);
 static void e1000_update_phy_info(unsigned long data);
 static void e1000_watchdog(unsigned long data);
 static void e1000_82547_tx_fifo_stall(unsigned long data);
@@ -299,14 +305,14 @@ module_exit(e1000_exit_module);
 static int e1000_request_irq(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
-	void (*handler) = &e1000_intr;
+	irq_handler_t handler = e1000_intr;
 	int irq_flags = IRQF_SHARED;
 	int err;
 
 	if (adapter->hw.mac_type >= e1000_82571) {
 		adapter->have_msi = !pci_enable_msi(adapter->pdev);
 		if (adapter->have_msi) {
-			handler = &e1000_intr_msi;
+			handler = e1000_intr_msi;
 			irq_flags = 0;
 		}
 	}
@@ -514,7 +520,7 @@ static void e1000_configure(struct e1000_adapter *adapter)
 	struct net_device *netdev = adapter->netdev;
 	int i;
 
-	e1000_set_multi(netdev);
+	e1000_set_rx_mode(netdev);
 
 	e1000_restore_vlan(adapter);
 	e1000_init_manageability(adapter);
@@ -845,6 +851,64 @@ e1000_reset(struct e1000_adapter *adapter)
 }
 
 /**
+ *  Dump the eeprom for users having checksum issues
+ **/
+void e1000_dump_eeprom(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct ethtool_eeprom eeprom;
+	const struct ethtool_ops *ops = netdev->ethtool_ops;
+	u8 *data;
+	int i;
+	u16 csum_old, csum_new = 0;
+
+	eeprom.len = ops->get_eeprom_len(netdev);
+	eeprom.offset = 0;
+
+	data = kmalloc(eeprom.len, GFP_KERNEL);
+	if (!data) {
+		printk(KERN_ERR "Unable to allocate memory to dump EEPROM"
+		       " data\n");
+		return;
+	}
+
+	ops->get_eeprom(netdev, &eeprom, data);
+
+	csum_old = (data[EEPROM_CHECKSUM_REG * 2]) +
+		   (data[EEPROM_CHECKSUM_REG * 2 + 1] << 8);
+	for (i = 0; i < EEPROM_CHECKSUM_REG * 2; i += 2)
+		csum_new += data[i] + (data[i + 1] << 8);
+	csum_new = EEPROM_SUM - csum_new;
+
+	printk(KERN_ERR "/*********************/\n");
+	printk(KERN_ERR "Current EEPROM Checksum : 0x%04x\n", csum_old);
+	printk(KERN_ERR "Calculated              : 0x%04x\n", csum_new);
+
+	printk(KERN_ERR "Offset    Values\n");
+	printk(KERN_ERR "========  ======\n");
+	print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, data, 128, 0);
+
+	printk(KERN_ERR "Include this output when contacting your support "
+	       "provider.\n");
+	printk(KERN_ERR "This is not a software error! Something bad "
+	       "happened to your hardware or\n");
+	printk(KERN_ERR "EEPROM image. Ignoring this "
+	       "problem could result in further problems,\n");
+	printk(KERN_ERR "possibly loss of data, corruption or system hangs!\n");
+	printk(KERN_ERR "The MAC Address will be reset to 00:00:00:00:00:00, "
+	       "which is invalid\n");
+	printk(KERN_ERR "and requires you to set the proper MAC "
+	       "address manually before continuing\n");
+	printk(KERN_ERR "to enable this network device.\n");
+	printk(KERN_ERR "Please inspect the EEPROM dump and report the issue "
+	       "to your hardware vendor\n");
+	printk(KERN_ERR "or Intel Customer Support: linux-nics@intel.com\n");
+	printk(KERN_ERR "/*********************/\n");
+
+	kfree(data);
+}
+
+/**
  * e1000_probe - Device Initialization Routine
  * @pdev: PCI device information struct
  * @ent: entry in e1000_pci_tbl
@@ -927,7 +991,7 @@ e1000_probe(struct pci_dev *pdev,
 	netdev->stop = &e1000_close;
 	netdev->hard_start_xmit = &e1000_xmit_frame;
 	netdev->get_stats = &e1000_get_stats;
-	netdev->set_multicast_list = &e1000_set_multi;
+	netdev->set_rx_mode = &e1000_set_rx_mode;
 	netdev->set_mac_address = &e1000_set_mac;
 	netdev->change_mtu = &e1000_change_mtu;
 	netdev->do_ioctl = &e1000_ioctl;
@@ -995,7 +1059,6 @@ e1000_probe(struct pci_dev *pdev,
 	adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw);
 
 	/* initialize eeprom parameters */
-
 	if (e1000_init_eeprom_params(&adapter->hw)) {
 		E1000_ERR("EEPROM initialization failed\n");
 		goto err_eeprom;
@@ -1007,23 +1070,29 @@ e1000_probe(struct pci_dev *pdev,
 	e1000_reset_hw(&adapter->hw);
 
 	/* make sure the EEPROM is good */
-
 	if (e1000_validate_eeprom_checksum(&adapter->hw) < 0) {
 		DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n");
-		goto err_eeprom;
+		e1000_dump_eeprom(adapter);
+		/*
+		 * set MAC address to all zeroes to invalidate and temporary
+		 * disable this device for the user. This blocks regular
+		 * traffic while still permitting ethtool ioctls from reaching
+		 * the hardware as well as allowing the user to run the
+		 * interface after manually setting a hw addr using
+		 * `ip set address`
+		 */
+		memset(adapter->hw.mac_addr, 0, netdev->addr_len);
+	} else {
+		/* copy the MAC address out of the EEPROM */
+		if (e1000_read_mac_addr(&adapter->hw))
+			DPRINTK(PROBE, ERR, "EEPROM Read Error\n");
 	}
-
-	/* copy the MAC address out of the EEPROM */
-
-	if (e1000_read_mac_addr(&adapter->hw))
-		DPRINTK(PROBE, ERR, "EEPROM Read Error\n");
+	/* don't block initalization here due to bad MAC address */
 	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
 	memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
 
-	if (!is_valid_ether_addr(netdev->perm_addr)) {
+	if (!is_valid_ether_addr(netdev->perm_addr))
 		DPRINTK(PROBE, ERR, "Invalid MAC Address\n");
-		goto err_eeprom;
-	}
 
 	e1000_get_bus_info(&adapter->hw);
 
@@ -2410,21 +2479,22 @@ e1000_set_mac(struct net_device *netdev, void *p)
 }
 
 /**
- * e1000_set_multi - Multicast and Promiscuous mode set
+ * e1000_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
  * @netdev: network interface device structure
  *
- * The set_multi entry point is called whenever the multicast address
- * list or the network interface flags are updated.  This routine is
- * responsible for configuring the hardware for proper multicast,
+ * The set_rx_mode entry point is called whenever the unicast or multicast
+ * address lists or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper unicast, multicast,
  * promiscuous mode, and all-multi behavior.
  **/
 
 static void
-e1000_set_multi(struct net_device *netdev)
+e1000_set_rx_mode(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
-	struct dev_mc_list *mc_ptr;
+	struct dev_addr_list *uc_ptr;
+	struct dev_addr_list *mc_ptr;
 	uint32_t rctl;
 	uint32_t hash_value;
 	int i, rar_entries = E1000_RAR_ENTRIES;
@@ -2447,9 +2517,16 @@ e1000_set_multi(struct net_device *netdev)
 		rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
 	} else if (netdev->flags & IFF_ALLMULTI) {
 		rctl |= E1000_RCTL_MPE;
-		rctl &= ~E1000_RCTL_UPE;
 	} else {
-		rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+		rctl &= ~E1000_RCTL_MPE;
+	}
+
+	uc_ptr = NULL;
+	if (netdev->uc_count > rar_entries - 1) {
+		rctl |= E1000_RCTL_UPE;
+	} else if (!(netdev->flags & IFF_PROMISC)) {
+		rctl &= ~E1000_RCTL_UPE;
+		uc_ptr = netdev->uc_list;
 	}
 
 	E1000_WRITE_REG(hw, RCTL, rctl);
@@ -2459,7 +2536,10 @@ e1000_set_multi(struct net_device *netdev)
 	if (hw->mac_type == e1000_82542_rev2_0)
 		e1000_enter_82542_rst(adapter);
 
-	/* load the first 14 multicast address into the exact filters 1-14
+	/* load the first 14 addresses into the exact filters 1-14. Unicast
+	 * addresses take precedence to avoid disabling unicast filtering
+	 * when possible.
+	 *
 	 * RAR 0 is used for the station MAC adddress
 	 * if there are not 14 addresses, go ahead and clear the filters
 	 * -- with 82571 controllers only 0-13 entries are filled here
@@ -2467,8 +2547,11 @@ e1000_set_multi(struct net_device *netdev)
 	mc_ptr = netdev->mc_list;
 
 	for (i = 1; i < rar_entries; i++) {
-		if (mc_ptr) {
-			e1000_rar_set(hw, mc_ptr->dmi_addr, i);
+		if (uc_ptr) {
+			e1000_rar_set(hw, uc_ptr->da_addr, i);
+			uc_ptr = uc_ptr->next;
+		} else if (mc_ptr) {
+			e1000_rar_set(hw, mc_ptr->da_addr, i);
 			mc_ptr = mc_ptr->next;
 		} else {
 			E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
@@ -2477,6 +2560,7 @@ e1000_set_multi(struct net_device *netdev)
 			E1000_WRITE_FLUSH(hw);
 		}
 	}
+	WARN_ON(uc_ptr != NULL);
 
 	/* clear the old settings from the multicast hash table */
 
@@ -2488,7 +2572,7 @@ e1000_set_multi(struct net_device *netdev)
 	/* load any remaining addresses into the hash table */
 
 	for (; mc_ptr; mc_ptr = mc_ptr->next) {
-		hash_value = e1000_hash_mc_addr(hw, mc_ptr->dmi_addr);
+		hash_value = e1000_hash_mc_addr(hw, mc_ptr->da_addr);
 		e1000_mta_set(hw, hash_value);
 	}
 
@@ -3680,10 +3764,6 @@ e1000_update_stats(struct e1000_adapter *adapter)
 	}
 
 	/* Fill out the OS statistics structure */
-	adapter->net_stats.rx_packets = adapter->stats.gprc;
-	adapter->net_stats.tx_packets = adapter->stats.gptc;
-	adapter->net_stats.rx_bytes = adapter->stats.gorcl;
-	adapter->net_stats.tx_bytes = adapter->stats.gotcl;
 	adapter->net_stats.multicast = adapter->stats.mprc;
 	adapter->net_stats.collisions = adapter->stats.colc;
 
@@ -4059,6 +4139,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
 	}
 	adapter->total_tx_bytes += total_tx_bytes;
 	adapter->total_tx_packets += total_tx_packets;
+	adapter->net_stats.tx_bytes += total_tx_bytes;
+	adapter->net_stats.tx_packets += total_tx_packets;
 	return cleaned;
 }
 
@@ -4106,8 +4188,8 @@ e1000_rx_checksum(struct e1000_adapter *adapter,
 		/* Hardware complements the payload checksum, so we undo it
 		 * and then put the value in host order for further stack use.
 		 */
-		csum = ntohl(csum ^ 0xFFFF);
-		skb->csum = csum;
+		__sum16 sum = (__force __sum16)htons(csum);
+		skb->csum = csum_unfold(~sum);
 		skb->ip_summed = CHECKSUM_COMPLETE;
 	}
 	adapter->hw_csum_good++;
@@ -4281,6 +4363,8 @@ next_desc:
 
 	adapter->total_rx_packets += total_rx_packets;
 	adapter->total_rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_packets += total_rx_packets;
 	return cleaned;
 }
 
@@ -4468,6 +4552,8 @@ next_desc:
 
 	adapter->total_rx_packets += total_rx_packets;
 	adapter->total_rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_packets += total_rx_packets;
 	return cleaned;
 }
 
@@ -4631,7 +4717,7 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
 				rx_desc->read.buffer_addr[j+1] =
 				     cpu_to_le64(ps_page_dma->ps_page_dma[j]);
 			} else
-				rx_desc->read.buffer_addr[j+1] = ~0;
+				rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0);
 		}
 
 		skb = netdev_alloc_skb(netdev,
@@ -4874,22 +4960,6 @@ e1000_pci_clear_mwi(struct e1000_hw *hw)
 	pci_clear_mwi(adapter->pdev);
 }
 
-void
-e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
-{
-	struct e1000_adapter *adapter = hw->back;
-
-	pci_read_config_word(adapter->pdev, reg, value);
-}
-
-void
-e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
-{
-	struct e1000_adapter *adapter = hw->back;
-
-	pci_write_config_word(adapter->pdev, reg, *value);
-}
-
 int
 e1000_pcix_get_mmrbc(struct e1000_hw *hw)
 {
@@ -5095,7 +5165,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
 
 	if (wufc) {
 		e1000_setup_rctl(adapter);
-		e1000_set_multi(netdev);
+		e1000_set_rx_mode(netdev);
 
 		/* turn on all-multi mode if wake on multicast is enabled */
 		if (wufc & E1000_WUFC_MC) {
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index 14141a55eaa6..3beace55b58d 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -194,6 +194,8 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
 		break;
 	case E1000_DEV_ID_82571EB_SERDES:
 	case E1000_DEV_ID_82572EI_SERDES:
+	case E1000_DEV_ID_82571EB_SERDES_DUAL:
+	case E1000_DEV_ID_82571EB_SERDES_QUAD:
 		hw->media_type = e1000_media_type_internal_serdes;
 		break;
 	default:
@@ -260,6 +262,7 @@ static s32 e1000_get_invariants_82571(struct e1000_adapter *adapter)
 	case E1000_DEV_ID_82571EB_QUAD_COPPER:
 	case E1000_DEV_ID_82571EB_QUAD_FIBER:
 	case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+	case E1000_DEV_ID_82571PT_QUAD_COPPER:
 		adapter->flags |= FLAG_IS_QUAD_PORT;
 		/* mark the first port */
 		if (global_quad_port_a == 0)
@@ -285,6 +288,9 @@ static s32 e1000_get_invariants_82571(struct e1000_adapter *adapter)
 		if (adapter->flags & FLAG_IS_QUAD_PORT &&
 		    (!(adapter->flags & FLAG_IS_QUAD_PORT_A)))
 			adapter->flags &= ~FLAG_HAS_WOL;
+		/* Does not support WoL on any port */
+		if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)
+			adapter->flags &= ~FLAG_HAS_WOL;
 		break;
 
 	case e1000_82573:
@@ -752,6 +758,10 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
 	ew32(IMC, 0xffffffff);
 	icr = er32(ICR);
 
+	if (hw->mac.type == e1000_82571 &&
+		hw->dev_spec.e82571.alt_mac_addr_is_present)
+			e1000e_set_laa_state_82571(hw, true);
+
 	return 0;
 }
 
@@ -1339,7 +1349,6 @@ struct e1000_info e1000_82573_info = {
 				  | FLAG_HAS_STATS_ICR_ICT
 				  | FLAG_HAS_SMART_POWER_DOWN
 				  | FLAG_HAS_AMT
-				  | FLAG_HAS_ASPM
 				  | FLAG_HAS_ERT
 				  | FLAG_HAS_SWSM_ON_LOAD,
 	.pba			= 20,
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
index b32ed45b4b34..f2175ea46b83 100644
--- a/drivers/net/e1000e/defines.h
+++ b/drivers/net/e1000e/defines.h
@@ -557,6 +557,7 @@
 #define NVM_INIT_3GIO_3            0x001A
 #define NVM_INIT_CONTROL3_PORT_A   0x0024
 #define NVM_CFG                    0x0012
+#define NVM_ALT_MAC_ADDR_PTR       0x0037
 #define NVM_CHECKSUM_REG           0x003F
 
 #define E1000_NVM_CFG_DONE_PORT_0  0x40000 /* MNG config cycle done */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index 473f78de4be0..8b88c226e858 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -288,7 +288,6 @@ struct e1000_info {
 #define FLAG_HAS_CTRLEXT_ON_LOAD          (1 << 5)
 #define FLAG_HAS_SWSM_ON_LOAD             (1 << 6)
 #define FLAG_HAS_JUMBO_FRAMES             (1 << 7)
-#define FLAG_HAS_ASPM                     (1 << 8)
 #define FLAG_HAS_STATS_ICR_ICT            (1 << 9)
 #define FLAG_HAS_STATS_PTC_PRC            (1 << 10)
 #define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 87f9da1b6b4e..6d9c27fd0b53 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -95,15 +95,14 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
 	{ "tx_dma_failed", E1000_STAT(tx_dma_failed) },
 };
 
-#define E1000_GLOBAL_STATS_LEN	\
-	sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
+#define E1000_GLOBAL_STATS_LEN	ARRAY_SIZE(e1000_gstrings_stats)
 #define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN)
 static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Register test  (offline)", "Eeprom test    (offline)",
 	"Interrupt test (offline)", "Loopback test  (offline)",
 	"Link test   (on/offline)"
 };
-#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN
+#define E1000_TEST_LEN	ARRAY_SIZE(e1000_gstrings_test)
 
 static int e1000_get_settings(struct net_device *netdev,
 			      struct ethtool_cmd *ecmd)
@@ -691,41 +690,63 @@ err_setup:
 	return err;
 }
 
-#define REG_PATTERN_TEST(R, M, W) REG_PATTERN_TEST_ARRAY(R, 0, M, W)
-#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, writeable)		      \
-{									      \
-	u32 _pat;							      \
-	u32 _value;							      \
-	u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};	      \
-	for (_pat = 0; _pat < ARRAY_SIZE(_test); _pat++) {		      \
-		E1000_WRITE_REG_ARRAY(hw, reg, offset,	      \
-				      (_test[_pat] & writeable));	      \
-		_value = E1000_READ_REG_ARRAY(hw, reg, offset);     \
-		if (_value != (_test[_pat] & writeable & mask)) {	      \
-			ndev_err(netdev, "pattern test reg %04X "             \
-				 "failed: got 0x%08X expected 0x%08X\n",      \
-				 reg + offset,  \
-				 value, (_test[_pat] & writeable & mask));    \
-			*data = reg;					      \
-			return 1;					      \
-		}							      \
-	}								      \
+bool reg_pattern_test_array(struct e1000_adapter *adapter, u64 *data,
+			    int reg, int offset, u32 mask, u32 write)
+{
+	int i;
+	u32 read;
+	static const u32 test[] =
+		{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+	for (i = 0; i < ARRAY_SIZE(test); i++) {
+		E1000_WRITE_REG_ARRAY(&adapter->hw, reg, offset,
+				      (test[i] & write));
+		read = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset);
+		if (read != (test[i] & write & mask)) {
+			ndev_err(adapter->netdev, "pattern test reg %04X "
+				 "failed: got 0x%08X expected 0x%08X\n",
+				 reg + offset,
+				 read, (test[i] & write & mask));
+			*data = reg;
+			return true;
+		}
+	}
+	return false;
 }
 
-#define REG_SET_AND_CHECK(R, M, W)					      \
-{									      \
-	u32 _value;							      \
-	__ew32(hw, R, W & M);						\
-	_value = __er32(hw, R);						\
-	if ((W & M) != (_value & M)) {					      \
-		ndev_err(netdev, "set/check reg %04X test failed: "           \
-			 "got 0x%08X expected 0x%08X\n", R, (_value & M),     \
-			 (W & M));					      \
-		*data = R;						      \
-		return 1;						      \
-	}								      \
+static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data,
+			      int reg, u32 mask, u32 write)
+{
+	u32 read;
+	__ew32(&adapter->hw, reg, write & mask);
+	read = __er32(&adapter->hw, reg);
+	if ((write & mask) != (read & mask)) {
+		ndev_err(adapter->netdev, "set/check reg %04X test failed: "
+			 "got 0x%08X expected 0x%08X\n", reg, (read & mask),
+			 (write & mask));
+		*data = reg;
+		return true;
+	}
+	return false;
 }
 
+#define REG_PATTERN_TEST(R, M, W) \
+	do { \
+		if (reg_pattern_test_array(adapter, data, R, 0, M, W)) \
+			return 1; \
+	} while (0)
+
+#define REG_PATTERN_TEST_ARRAY(R, offset, M, W) \
+	do { \
+		if (reg_pattern_test_array(adapter, data, R, offset, M, W)) \
+			return 1; \
+	} while (0)
+
+#define REG_SET_AND_CHECK(R, M, W) \
+	do { \
+		if (reg_set_and_check(adapter, data, R, M, W)) \
+			return 1; \
+	} while (0)
+
 static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
 {
 	struct e1000_hw *hw = &adapter->hw;
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
index 64515789fd4d..3c5862f97dbf 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -303,8 +303,11 @@ enum e1e_registers {
 #define E1000_DEV_ID_82571EB_FIBER		0x105F
 #define E1000_DEV_ID_82571EB_SERDES		0x1060
 #define E1000_DEV_ID_82571EB_QUAD_COPPER	0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER	0x10D5
 #define E1000_DEV_ID_82571EB_QUAD_FIBER		0x10A5
 #define E1000_DEV_ID_82571EB_QUAD_COPPER_LP	0x10BC
+#define E1000_DEV_ID_82571EB_SERDES_DUAL	0x10D9
+#define E1000_DEV_ID_82571EB_SERDES_QUAD	0x10DA
 #define E1000_DEV_ID_82572EI_COPPER		0x107D
 #define E1000_DEV_ID_82572EI_FIBER		0x107E
 #define E1000_DEV_ID_82572EI_SERDES		0x107F
@@ -420,35 +423,35 @@ enum e1000_smart_speed {
 
 /* Receive Descriptor */
 struct e1000_rx_desc {
-	u64 buffer_addr; /* Address of the descriptor's data buffer */
-	u16 length;      /* Length of data DMAed into data buffer */
-	u16 csum;	/* Packet checksum */
+	__le64 buffer_addr; /* Address of the descriptor's data buffer */
+	__le16 length;      /* Length of data DMAed into data buffer */
+	__le16 csum;	/* Packet checksum */
 	u8  status;      /* Descriptor status */
 	u8  errors;      /* Descriptor Errors */
-	u16 special;
+	__le16 special;
 };
 
 /* Receive Descriptor - Extended */
 union e1000_rx_desc_extended {
 	struct {
-		u64 buffer_addr;
-		u64 reserved;
+		__le64 buffer_addr;
+		__le64 reserved;
 	} read;
 	struct {
 		struct {
-			u32 mrq;	      /* Multiple Rx Queues */
+			__le32 mrq;	      /* Multiple Rx Queues */
 			union {
-				u32 rss;	    /* RSS Hash */
+				__le32 rss;	    /* RSS Hash */
 				struct {
-					u16 ip_id;  /* IP id */
-					u16 csum;   /* Packet Checksum */
+					__le16 ip_id;  /* IP id */
+					__le16 csum;   /* Packet Checksum */
 				} csum_ip;
 			} hi_dword;
 		} lower;
 		struct {
-			u32 status_error;     /* ext status/error */
-			u16 length;
-			u16 vlan;	     /* VLAN tag */
+			__le32 status_error;     /* ext status/error */
+			__le16 length;
+			__le16 vlan;	     /* VLAN tag */
 		} upper;
 	} wb;  /* writeback */
 };
@@ -458,49 +461,49 @@ union e1000_rx_desc_extended {
 union e1000_rx_desc_packet_split {
 	struct {
 		/* one buffer for protocol header(s), three data buffers */
-		u64 buffer_addr[MAX_PS_BUFFERS];
+		__le64 buffer_addr[MAX_PS_BUFFERS];
 	} read;
 	struct {
 		struct {
-			u32 mrq;	      /* Multiple Rx Queues */
+			__le32 mrq;	      /* Multiple Rx Queues */
 			union {
-				u32 rss;	      /* RSS Hash */
+				__le32 rss;	      /* RSS Hash */
 				struct {
-					u16 ip_id;    /* IP id */
-					u16 csum;     /* Packet Checksum */
+					__le16 ip_id;    /* IP id */
+					__le16 csum;     /* Packet Checksum */
 				} csum_ip;
 			} hi_dword;
 		} lower;
 		struct {
-			u32 status_error;     /* ext status/error */
-			u16 length0;	  /* length of buffer 0 */
-			u16 vlan;	     /* VLAN tag */
+			__le32 status_error;     /* ext status/error */
+			__le16 length0;	  /* length of buffer 0 */
+			__le16 vlan;	     /* VLAN tag */
 		} middle;
 		struct {
-			u16 header_status;
-			u16 length[3];	/* length of buffers 1-3 */
+			__le16 header_status;
+			__le16 length[3];	/* length of buffers 1-3 */
 		} upper;
-		u64 reserved;
+		__le64 reserved;
 	} wb; /* writeback */
 };
 
 /* Transmit Descriptor */
 struct e1000_tx_desc {
-	u64 buffer_addr;      /* Address of the descriptor's data buffer */
+	__le64 buffer_addr;      /* Address of the descriptor's data buffer */
 	union {
-		u32 data;
+		__le32 data;
 		struct {
-			u16 length;    /* Data buffer length */
+			__le16 length;    /* Data buffer length */
 			u8 cso;	/* Checksum offset */
 			u8 cmd;	/* Descriptor control */
 		} flags;
 	} lower;
 	union {
-		u32 data;
+		__le32 data;
 		struct {
 			u8 status;     /* Descriptor status */
 			u8 css;	/* Checksum start */
-			u16 special;
+			__le16 special;
 		} fields;
 	} upper;
 };
@@ -508,49 +511,49 @@ struct e1000_tx_desc {
 /* Offload Context Descriptor */
 struct e1000_context_desc {
 	union {
-		u32 ip_config;
+		__le32 ip_config;
 		struct {
 			u8 ipcss;      /* IP checksum start */
 			u8 ipcso;      /* IP checksum offset */
-			u16 ipcse;     /* IP checksum end */
+			__le16 ipcse;     /* IP checksum end */
 		} ip_fields;
 	} lower_setup;
 	union {
-		u32 tcp_config;
+		__le32 tcp_config;
 		struct {
 			u8 tucss;      /* TCP checksum start */
 			u8 tucso;      /* TCP checksum offset */
-			u16 tucse;     /* TCP checksum end */
+			__le16 tucse;     /* TCP checksum end */
 		} tcp_fields;
 	} upper_setup;
-	u32 cmd_and_length;
+	__le32 cmd_and_length;
 	union {
-		u32 data;
+		__le32 data;
 		struct {
 			u8 status;     /* Descriptor status */
 			u8 hdr_len;    /* Header length */
-			u16 mss;       /* Maximum segment size */
+			__le16 mss;       /* Maximum segment size */
 		} fields;
 	} tcp_seg_setup;
 };
 
 /* Offload data descriptor */
 struct e1000_data_desc {
-	u64 buffer_addr;   /* Address of the descriptor's buffer address */
+	__le64 buffer_addr;   /* Address of the descriptor's buffer address */
 	union {
-		u32 data;
+		__le32 data;
 		struct {
-			u16 length;    /* Data buffer length */
+			__le16 length;    /* Data buffer length */
 			u8 typ_len_ext;
 			u8 cmd;
 		} flags;
 	} lower;
 	union {
-		u32 data;
+		__le32 data;
 		struct {
 			u8 status;     /* Descriptor status */
 			u8 popts;      /* Packet Options */
-			u16 special;   /* */
+			__le16 special;   /* */
 		} fields;
 	} upper;
 };
@@ -816,6 +819,7 @@ struct e1000_bus_info {
 
 struct e1000_dev_spec_82571 {
 	bool laa_is_present;
+	bool alt_mac_addr_is_present;
 };
 
 struct e1000_shadow_ram {
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index 0bdeca30c75f..16f35fadb74b 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -2059,9 +2059,44 @@ s32 e1000e_read_mac_addr(struct e1000_hw *hw)
 {
 	s32 ret_val;
 	u16 offset, nvm_data, i;
+	u16 mac_addr_offset = 0;
+
+	if (hw->mac.type == e1000_82571) {
+		/* Check for an alternate MAC address.  An alternate MAC
+		 * address can be setup by pre-boot software and must be
+		 * treated like a permanent address and must override the
+		 * actual permanent MAC address. */
+		ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+						&mac_addr_offset);
+		if (ret_val) {
+			hw_dbg(hw, "NVM Read Error\n");
+			return ret_val;
+		}
+		if (mac_addr_offset == 0xFFFF)
+			mac_addr_offset = 0;
+
+		if (mac_addr_offset) {
+			if (hw->bus.func == E1000_FUNC_1)
+				mac_addr_offset += ETH_ALEN/sizeof(u16);
+
+			/* make sure we have a valid mac address here
+			 * before using it */
+			ret_val = e1000_read_nvm(hw, mac_addr_offset, 1,
+						 &nvm_data);
+			if (ret_val) {
+				hw_dbg(hw, "NVM Read Error\n");
+				return ret_val;
+			}
+			if (nvm_data & 0x0001)
+				mac_addr_offset = 0;
+		}
+
+		if (mac_addr_offset)
+			hw->dev_spec.e82571.alt_mac_addr_is_present = 1;
+	}
 
 	for (i = 0; i < ETH_ALEN; i += 2) {
-		offset = i >> 1;
+		offset = mac_addr_offset + (i >> 1);
 		ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
 		if (ret_val) {
 			hw_dbg(hw, "NVM Read Error\n");
@@ -2072,7 +2107,7 @@ s32 e1000e_read_mac_addr(struct e1000_hw *hw)
 	}
 
 	/* Flip last bit of mac address if we're on second port */
-	if (hw->bus.func == E1000_FUNC_1)
+	if (!mac_addr_offset && hw->bus.func == E1000_FUNC_1)
 		hw->mac.perm_addr[5] ^= 1;
 
 	for (i = 0; i < ETH_ALEN; i++)
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 9cc5a6b01bc1..0a2cb7960c9e 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -91,7 +91,7 @@ static int e1000_desc_unused(struct e1000_ring *ring)
 static void e1000_receive_skb(struct e1000_adapter *adapter,
 			      struct net_device *netdev,
 			      struct sk_buff *skb,
-			      u8 status, u16 vlan)
+			      u8 status, __le16 vlan)
 {
 	skb->protocol = eth_type_trans(skb, netdev);
 
@@ -142,8 +142,8 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
 		/* Hardware complements the payload checksum, so we undo it
 		 * and then put the value in host order for further stack use.
 		 */
-		csum = ntohl(csum ^ 0xFFFF);
-		skb->csum = csum;
+		__sum16 sum = (__force __sum16)htons(csum);
+		skb->csum = csum_unfold(~sum);
 		skb->ip_summed = CHECKSUM_COMPLETE;
 	}
 	adapter->hw_csum_good++;
@@ -248,7 +248,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
 			ps_page = &buffer_info->ps_pages[j];
 			if (j >= adapter->rx_ps_pages) {
 				/* all unused desc entries get hw null ptr */
-				rx_desc->read.buffer_addr[j+1] = ~0;
+				rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0);
 				continue;
 			}
 			if (!ps_page->page) {
@@ -458,6 +458,8 @@ next_desc:
 
 	adapter->total_rx_packets += total_rx_packets;
 	adapter->total_rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_packets += total_rx_packets;
+	adapter->net_stats.rx_bytes += total_rx_bytes;
 	return cleaned;
 }
 
@@ -593,6 +595,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
 	}
 	adapter->total_tx_bytes += total_tx_bytes;
 	adapter->total_tx_packets += total_tx_packets;
+	adapter->net_stats.tx_packets += total_tx_packets;
+	adapter->net_stats.tx_bytes += total_tx_bytes;
 	return cleaned;
 }
 
@@ -755,6 +759,8 @@ next_desc:
 
 	adapter->total_rx_packets += total_rx_packets;
 	adapter->total_rx_bytes += total_rx_bytes;
+	adapter->net_stats.rx_packets += total_rx_packets;
+	adapter->net_stats.rx_bytes += total_rx_bytes;
 	return cleaned;
 }
 
@@ -935,7 +941,7 @@ static irqreturn_t e1000_intr(int irq, void *data)
 static int e1000_request_irq(struct e1000_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
-	void (*handler) = &e1000_intr;
+	irq_handler_t handler = e1000_intr;
 	int irq_flags = IRQF_SHARED;
 	int err;
 
@@ -945,7 +951,7 @@ static int e1000_request_irq(struct e1000_adapter *adapter)
 		 "Unable to allocate MSI interrupt Error: %d\n", err);
 	} else {
 		adapter->flags |= FLAG_MSI_ENABLED;
-		handler = &e1000_intr_msi;
+		handler = e1000_intr_msi;
 		irq_flags = 0;
 	}
 
@@ -2535,10 +2541,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
 	}
 
 	/* Fill out the OS statistics structure */
-	adapter->net_stats.rx_packets = adapter->stats.gprc;
-	adapter->net_stats.tx_packets = adapter->stats.gptc;
-	adapter->net_stats.rx_bytes = adapter->stats.gorcl;
-	adapter->net_stats.tx_bytes = adapter->stats.gotcl;
 	adapter->net_stats.multicast = adapter->stats.mprc;
 	adapter->net_stats.collisions = adapter->stats.colc;
 
@@ -3509,6 +3511,33 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
 	return 0;
 }
 
+static void e1000e_disable_l1aspm(struct pci_dev *pdev)
+{
+	int pos;
+	u32 cap;
+	u16 val;
+
+	/*
+	 * 82573 workaround - disable L1 ASPM on mobile chipsets
+	 *
+	 * L1 ASPM on various mobile (ich7) chipsets do not behave properly
+	 * resulting in lost data or garbage information on the pci-e link
+	 * level. This could result in (false) bad EEPROM checksum errors,
+	 * long ping times (up to 2s) or even a system freeze/hang.
+	 *
+	 * Unfortunately this feature saves about 1W power consumption when
+	 * active.
+	 */
+	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &cap);
+	pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &val);
+	if (val & 0x2) {
+		dev_warn(&pdev->dev, "Disabling L1 ASPM\n");
+		val &= ~0x2;
+		pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, val);
+	}
+}
+
 #ifdef CONFIG_PM
 static int e1000_resume(struct pci_dev *pdev)
 {
@@ -3519,6 +3548,7 @@ static int e1000_resume(struct pci_dev *pdev)
 
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
+	e1000e_disable_l1aspm(pdev);
 	err = pci_enable_device(pdev);
 	if (err) {
 		dev_err(&pdev->dev,
@@ -3619,6 +3649,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
 	struct e1000_adapter *adapter = netdev_priv(netdev);
 	struct e1000_hw *hw = &adapter->hw;
 
+	e1000e_disable_l1aspm(pdev);
 	if (pci_enable_device(pdev)) {
 		dev_err(&pdev->dev,
 			"Cannot re-enable PCI device after reset.\n");
@@ -3720,6 +3751,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 	u16 eeprom_data = 0;
 	u16 eeprom_apme_mask = E1000_EEPROM_APME;
 
+	e1000e_disable_l1aspm(pdev);
 	err = pci_enable_device(pdev);
 	if (err)
 		return err;
@@ -4056,16 +4088,15 @@ static struct pci_error_handlers e1000_err_handler = {
 };
 
 static struct pci_device_id e1000_pci_tbl[] = {
-	/*
-	 * Support for 82571/2/3, es2lan and ich8 will be phased in
-	 * stepwise.
-
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_DUAL), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_QUAD), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571PT_QUAD_COPPER), board_82571 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 },
@@ -4088,8 +4119,6 @@ static struct pci_device_id e1000_pci_tbl[] = {
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan },
-	*/
-
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan },
 	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan },
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
index 332789238b9c..df266c32ac4b 100644
--- a/drivers/net/e1000e/param.c
+++ b/drivers/net/e1000e/param.c
@@ -262,13 +262,6 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
 					 .max = MAX_RXDELAY } }
 		};
 
-		/* modify min and default if 82573 for slow ping w/a,
-		 * a value greater than 8 needs to be set for RDTR */
-		if (adapter->flags & FLAG_HAS_ASPM) {
-			opt.def = 32;
-			opt.arg.r.min = 8;
-		}
-
 		if (num_RxIntDelay > bd) {
 			adapter->rx_int_delay = RxIntDelay[bd];
 			e1000_validate_option(&adapter->rx_int_delay, &opt,
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index 793231810ae0..fc6fee112f1c 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -49,8 +49,7 @@ static const u16 e1000_igp_2_cable_length_table[] =
 	  100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121,
 	  124};
 #define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
-		(sizeof(e1000_igp_2_cable_length_table) / \
-		 sizeof(e1000_igp_2_cable_length_table[0]))
+		ARRAY_SIZE(e1000_igp_2_cable_length_table)
 
 /**
  *  e1000e_check_reset_block_generic - Check if PHY reset is blocked
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 1548a80f917d..e3e26c595fa3 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -304,13 +304,7 @@ enum commands {
 #if defined(__alpha__)
 # define clear_suspend(cmd)  clear_bit(30, &(cmd)->cmd_status);
 #else
-# if defined(__LITTLE_ENDIAN)
-#  define clear_suspend(cmd)  ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x4000
-# elif defined(__BIG_ENDIAN)
-#  define clear_suspend(cmd)  ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x0040
-# else
-#  error Unsupported byteorder
-# endif
+# define clear_suspend(cmd)  ((__le16 *)&(cmd)->cmd_status)[1] &= ~cpu_to_le16(1<<14)
 #endif
 
 enum SCBCmdBits {
@@ -331,17 +325,17 @@ enum SCBPort_cmds {
 
 /* The Speedo3 Rx and Tx frame/buffer descriptors. */
 struct descriptor {			    /* A generic descriptor. */
-	volatile s32 cmd_status;	/* All command and status fields. */
-	u32 link;				    /* struct descriptor *  */
+	volatile __le32 cmd_status;	/* All command and status fields. */
+	__le32 link;				    /* struct descriptor *  */
 	unsigned char params[0];
 };
 
 /* The Speedo3 Rx and Tx buffer descriptors. */
 struct RxFD {					/* Receive frame descriptor. */
-	volatile s32 status;
-	u32 link;					/* struct RxFD * */
-	u32 rx_buf_addr;			/* void * */
-	u32 count;
+	volatile __le32 status;
+	__le32 link;					/* struct RxFD * */
+	__le32 rx_buf_addr;			/* void * */
+	__le32 count;
 } RxFD_ALIGNMENT;
 
 /* Selected elements of the Tx/RxFD.status word. */
@@ -354,16 +348,16 @@ enum RxFD_bits {
 
 #define CONFIG_DATA_SIZE 22
 struct TxFD {					/* Transmit frame descriptor set. */
-	s32 status;
-	u32 link;					/* void * */
-	u32 tx_desc_addr;			/* Always points to the tx_buf_addr element. */
-	s32 count;					/* # of TBD (=1), Tx start thresh., etc. */
+	__le32 status;
+	__le32 link;					/* void * */
+	__le32 tx_desc_addr;			/* Always points to the tx_buf_addr element. */
+	__le32 count;					/* # of TBD (=1), Tx start thresh., etc. */
 	/* This constitutes two "TBD" entries -- we only use one. */
 #define TX_DESCR_BUF_OFFSET 16
-	u32 tx_buf_addr0;			/* void *, frame to be transmitted.  */
-	s32 tx_buf_size0;			/* Length of Tx frame. */
-	u32 tx_buf_addr1;			/* void *, frame to be transmitted.  */
-	s32 tx_buf_size1;			/* Length of Tx frame. */
+	__le32 tx_buf_addr0;			/* void *, frame to be transmitted.  */
+	__le32 tx_buf_size0;			/* Length of Tx frame. */
+	__le32 tx_buf_addr1;			/* void *, frame to be transmitted.  */
+	__le32 tx_buf_size1;			/* Length of Tx frame. */
 	/* the structure must have space for at least CONFIG_DATA_SIZE starting
 	 * from tx_desc_addr field */
 };
@@ -379,23 +373,23 @@ struct speedo_mc_block {
 
 /* Elements of the dump_statistics block. This block must be lword aligned. */
 struct speedo_stats {
-	u32 tx_good_frames;
-	u32 tx_coll16_errs;
-	u32 tx_late_colls;
-	u32 tx_underruns;
-	u32 tx_lost_carrier;
-	u32 tx_deferred;
-	u32 tx_one_colls;
-	u32 tx_multi_colls;
-	u32 tx_total_colls;
-	u32 rx_good_frames;
-	u32 rx_crc_errs;
-	u32 rx_align_errs;
-	u32 rx_resource_errs;
-	u32 rx_overrun_errs;
-	u32 rx_colls_errs;
-	u32 rx_runt_errs;
-	u32 done_marker;
+	__le32 tx_good_frames;
+	__le32 tx_coll16_errs;
+	__le32 tx_late_colls;
+	__le32 tx_underruns;
+	__le32 tx_lost_carrier;
+	__le32 tx_deferred;
+	__le32 tx_one_colls;
+	__le32 tx_multi_colls;
+	__le32 tx_total_colls;
+	__le32 rx_good_frames;
+	__le32 rx_crc_errs;
+	__le32 rx_align_errs;
+	__le32 rx_resource_errs;
+	__le32 rx_overrun_errs;
+	__le32 rx_colls_errs;
+	__le32 rx_runt_errs;
+	__le32 done_marker;
 };
 
 enum Rx_ring_state_bits {
@@ -1139,7 +1133,7 @@ speedo_rx_soft_reset(struct net_device *dev)
 
 	rfd = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
 
-	rfd->rx_buf_addr = 0xffffffff;
+	rfd->rx_buf_addr = cpu_to_le32(0xffffffff);
 
 	if (wait_for_cmd_done(dev, sp) != 0) {
 		printk("%s: RxAbort command stalled\n", dev->name);
@@ -1275,7 +1269,7 @@ speedo_init_rx_ring(struct net_device *dev)
 		rxf->status = cpu_to_le32(0x00000001);	/* '1' is flag value only. */
 		rxf->link = 0;						/* None yet. */
 		/* This field unused by i82557. */
-		rxf->rx_buf_addr = 0xffffffff;
+		rxf->rx_buf_addr = cpu_to_le32(0xffffffff);
 		rxf->count = cpu_to_le32(PKT_BUF_SZ << 16);
 		pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[i],
 									   sizeof(struct RxFD), PCI_DMA_TODEVICE);
@@ -1657,7 +1651,7 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
 					   PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
 	skb->dev = dev;
 	skb_reserve(skb, sizeof(struct RxFD));
-	rxf->rx_buf_addr = 0xffffffff;
+	rxf->rx_buf_addr = cpu_to_le32(0xffffffff);
 	pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry],
 								   sizeof(struct RxFD), PCI_DMA_TODEVICE);
 	return rxf;
@@ -1788,7 +1782,7 @@ speedo_rx(struct net_device *dev)
 			/* Check if the packet is long enough to just accept without
 			   copying to a properly sized skbuff. */
 			if (pkt_len < rx_copybreak
-				&& (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
+				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				/* 'skb_put()' points to the start of sk_buff data area. */
 				pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry],
@@ -1933,7 +1927,7 @@ speedo_get_stats(struct net_device *dev)
 	void __iomem *ioaddr = sp->regs;
 
 	/* Update only if the previous dump finished. */
-	if (sp->lstats->done_marker == le32_to_cpu(0xA007)) {
+	if (sp->lstats->done_marker == cpu_to_le32(0xA007)) {
 		sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats->tx_coll16_errs);
 		sp->stats.tx_window_errors += le32_to_cpu(sp->lstats->tx_late_colls);
 		sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats->tx_underruns);
@@ -2142,7 +2136,7 @@ static void set_rx_mode(struct net_device *dev)
 		/* The simple case of 0-3 multicast list entries occurs often, and
 		   fits within one tx_ring[] entry. */
 		struct dev_mc_list *mclist;
-		u16 *setup_params, *eaddrs;
+		__le16 *setup_params, *eaddrs;
 
 		spin_lock_irqsave(&sp->lock, flags);
 		entry = sp->cur_tx++ % TX_RING_SIZE;
@@ -2154,12 +2148,12 @@ static void set_rx_mode(struct net_device *dev)
 		sp->tx_ring[entry].link =
 			cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE));
 		sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */
-		setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr;
+		setup_params = (__le16 *)&sp->tx_ring[entry].tx_desc_addr;
 		*setup_params++ = cpu_to_le16(dev->mc_count*6);
 		/* Fill in the multicast addresses. */
 		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
 			 i++, mclist = mclist->next) {
-			eaddrs = (u16 *)mclist->dmi_addr;
+			eaddrs = (__le16 *)mclist->dmi_addr;
 			*setup_params++ = *eaddrs++;
 			*setup_params++ = *eaddrs++;
 			*setup_params++ = *eaddrs++;
@@ -2177,7 +2171,7 @@ static void set_rx_mode(struct net_device *dev)
 		spin_unlock_irqrestore(&sp->lock, flags);
 	} else if (new_rx_mode == 0) {
 		struct dev_mc_list *mclist;
-		u16 *setup_params, *eaddrs;
+		__le16 *setup_params, *eaddrs;
 		struct speedo_mc_block *mc_blk;
 		struct descriptor *mc_setup_frm;
 		int i;
@@ -2204,12 +2198,12 @@ static void set_rx_mode(struct net_device *dev)
 		mc_setup_frm->cmd_status =
 			cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList);
 		/* Link set below. */
-		setup_params = (u16 *)&mc_setup_frm->params;
+		setup_params = (__le16 *)&mc_setup_frm->params;
 		*setup_params++ = cpu_to_le16(dev->mc_count*6);
 		/* Fill in the multicast addresses. */
 		for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
 			 i++, mclist = mclist->next) {
-			eaddrs = (u16 *)mclist->dmi_addr;
+			eaddrs = (__le16 *)mclist->dmi_addr;
 			*setup_params++ = *eaddrs++;
 			*setup_params++ = *eaddrs++;
 			*setup_params++ = *eaddrs++;
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 70509ed6c11d..d5459a8056b1 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -456,8 +456,9 @@ static int eexp_open(struct net_device *dev)
 	if (!dev->irq || !irqrmap[dev->irq])
 		return -ENXIO;
 
-	ret = request_irq(dev->irq,&eexp_irq,0,dev->name,dev);
-	if (ret) return ret;
+	ret = request_irq(dev->irq, &eexp_irq, 0, dev->name, dev);
+	if (ret)
+		return ret;
 
 	if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) {
 		printk(KERN_WARNING "EtherExpress io port %x, is busy.\n"
@@ -768,7 +769,7 @@ static void eexp_cmd_clear(struct net_device *dev)
 	}
 }
 
-static irqreturn_t eexp_irq(int irq, void *dev_info)
+static irqreturn_t eexp_irq(int dummy, void *dev_info)
 {
 	struct net_device *dev = dev_info;
 	struct net_local *lp;
@@ -783,8 +784,7 @@ static irqreturn_t eexp_irq(int irq, void *dev_info)
 	old_read_ptr = inw(ioaddr+READ_PTR);
 	old_write_ptr = inw(ioaddr+WRITE_PTR);
 
-	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
-
+	outb(SIRQ_dis|irqrmap[dev->irq], ioaddr+SET_IRQ);
 
 	status = scb_status(dev);
 
@@ -851,7 +851,7 @@ static irqreturn_t eexp_irq(int irq, void *dev_info)
 
 	eexp_cmd_clear(dev);
 
-	outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);
+	outb(SIRQ_en|irqrmap[dev->irq], ioaddr+SET_IRQ);
 
 #if NET_DEBUG > 6
 	printk("%s: leaving eexp_irq()\n", dev->name);
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
new file mode 100644
index 000000000000..0809a6a5a286
--- /dev/null
+++ b/drivers/net/enc28j60.c
@@ -0,0 +1,1600 @@
+/*
+ * Microchip ENC28J60 ethernet driver (MAC + PHY)
+ *
+ * Copyright (C) 2007 Eurek srl
+ * Author: Claudio Lanconelli <lanconelli.claudio@eptar.com>
+ * based on enc28j60.c written by David Anders for 2.4 kernel version
+ *
+ * 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.
+ *
+ * $Id: enc28j60.c,v 1.22 2007/12/20 10:47:01 claudio Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#include "enc28j60_hw.h"
+
+#define DRV_NAME	"enc28j60"
+#define DRV_VERSION	"1.01"
+
+#define SPI_OPLEN	1
+
+#define ENC28J60_MSG_DEFAULT	\
+	(NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK)
+
+/* Buffer size required for the largest SPI transfer (i.e., reading a
+ * frame). */
+#define SPI_TRANSFER_BUF_LEN	(4 + MAX_FRAMELEN)
+
+#define TX_TIMEOUT	(4 * HZ)
+
+/* Max TX retries in case of collision as suggested by errata datasheet */
+#define MAX_TX_RETRYCOUNT	16
+
+enum {
+	RXFILTER_NORMAL,
+	RXFILTER_MULTI,
+	RXFILTER_PROMISC
+};
+
+/* Driver local data */
+struct enc28j60_net {
+	struct net_device *netdev;
+	struct spi_device *spi;
+	struct mutex lock;
+	struct sk_buff *tx_skb;
+	struct work_struct tx_work;
+	struct work_struct irq_work;
+	struct work_struct setrx_work;
+	struct work_struct restart_work;
+	u8 bank;		/* current register bank selected */
+	u16 next_pk_ptr;	/* next packet pointer within FIFO */
+	u16 max_pk_counter;	/* statistics: max packet counter */
+	u16 tx_retry_count;
+	bool hw_enable;
+	bool full_duplex;
+	int rxfilter;
+	u32 msg_enable;
+	u8 spi_transfer_buf[SPI_TRANSFER_BUF_LEN];
+};
+
+/* use ethtool to change the level for any given device */
+static struct {
+	u32 msg_enable;
+} debug = { -1 };
+
+/*
+ * SPI read buffer
+ * wait for the SPI transfer and copy received data to destination
+ */
+static int
+spi_read_buf(struct enc28j60_net *priv, int len, u8 *data)
+{
+	u8 *rx_buf = priv->spi_transfer_buf + 4;
+	u8 *tx_buf = priv->spi_transfer_buf;
+	struct spi_transfer t = {
+		.tx_buf = tx_buf,
+		.rx_buf = rx_buf,
+		.len = SPI_OPLEN + len,
+	};
+	struct spi_message msg;
+	int ret;
+
+	tx_buf[0] = ENC28J60_READ_BUF_MEM;
+	tx_buf[1] = tx_buf[2] = tx_buf[3] = 0;	/* don't care */
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&t, &msg);
+	ret = spi_sync(priv->spi, &msg);
+	if (ret == 0) {
+		memcpy(data, &rx_buf[SPI_OPLEN], len);
+		ret = msg.status;
+	}
+	if (ret && netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
+			__FUNCTION__, ret);
+
+	return ret;
+}
+
+/*
+ * SPI write buffer
+ */
+static int spi_write_buf(struct enc28j60_net *priv, int len,
+			 const u8 *data)
+{
+	int ret;
+
+	if (len > SPI_TRANSFER_BUF_LEN - 1 || len <= 0)
+		ret = -EINVAL;
+	else {
+		priv->spi_transfer_buf[0] = ENC28J60_WRITE_BUF_MEM;
+		memcpy(&priv->spi_transfer_buf[1], data, len);
+		ret = spi_write(priv->spi, priv->spi_transfer_buf, len + 1);
+		if (ret && netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
+				__FUNCTION__, ret);
+	}
+	return ret;
+}
+
+/*
+ * basic SPI read operation
+ */
+static u8 spi_read_op(struct enc28j60_net *priv, u8 op,
+			   u8 addr)
+{
+	u8 tx_buf[2];
+	u8 rx_buf[4];
+	u8 val = 0;
+	int ret;
+	int slen = SPI_OPLEN;
+
+	/* do dummy read if needed */
+	if (addr & SPRD_MASK)
+		slen++;
+
+	tx_buf[0] = op | (addr & ADDR_MASK);
+	ret = spi_write_then_read(priv->spi, tx_buf, 1, rx_buf, slen);
+	if (ret)
+		printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
+			__FUNCTION__, ret);
+	else
+		val = rx_buf[slen - 1];
+
+	return val;
+}
+
+/*
+ * basic SPI write operation
+ */
+static int spi_write_op(struct enc28j60_net *priv, u8 op,
+			u8 addr, u8 val)
+{
+	int ret;
+
+	priv->spi_transfer_buf[0] = op | (addr & ADDR_MASK);
+	priv->spi_transfer_buf[1] = val;
+	ret = spi_write(priv->spi, priv->spi_transfer_buf, 2);
+	if (ret && netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
+			__FUNCTION__, ret);
+	return ret;
+}
+
+static void enc28j60_soft_reset(struct enc28j60_net *priv)
+{
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+
+	spi_write_op(priv, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
+	/* Errata workaround #1, CLKRDY check is unreliable,
+	 * delay at least 1 mS instead */
+	udelay(2000);
+}
+
+/*
+ * select the current register bank if necessary
+ */
+static void enc28j60_set_bank(struct enc28j60_net *priv, u8 addr)
+{
+	if ((addr & BANK_MASK) != priv->bank) {
+		u8 b = (addr & BANK_MASK) >> 5;
+
+		if (b != (ECON1_BSEL1 | ECON1_BSEL0))
+			spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1,
+				     ECON1_BSEL1 | ECON1_BSEL0);
+		if (b != 0)
+			spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, b);
+		priv->bank = (addr & BANK_MASK);
+	}
+}
+
+/*
+ * Register access routines through the SPI bus.
+ * Every register access comes in two flavours:
+ * - nolock_xxx: caller needs to invoke mutex_lock, usually to access
+ *   atomically more than one register
+ * - locked_xxx: caller doesn't need to invoke mutex_lock, single access
+ *
+ * Some registers can be accessed through the bit field clear and
+ * bit field set to avoid a read modify write cycle.
+ */
+
+/*
+ * Register bit field Set
+ */
+static void nolock_reg_bfset(struct enc28j60_net *priv,
+				      u8 addr, u8 mask)
+{
+	enc28j60_set_bank(priv, addr);
+	spi_write_op(priv, ENC28J60_BIT_FIELD_SET, addr, mask);
+}
+
+static void locked_reg_bfset(struct enc28j60_net *priv,
+				      u8 addr, u8 mask)
+{
+	mutex_lock(&priv->lock);
+	nolock_reg_bfset(priv, addr, mask);
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * Register bit field Clear
+ */
+static void nolock_reg_bfclr(struct enc28j60_net *priv,
+				      u8 addr, u8 mask)
+{
+	enc28j60_set_bank(priv, addr);
+	spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, addr, mask);
+}
+
+static void locked_reg_bfclr(struct enc28j60_net *priv,
+				      u8 addr, u8 mask)
+{
+	mutex_lock(&priv->lock);
+	nolock_reg_bfclr(priv, addr, mask);
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * Register byte read
+ */
+static int nolock_regb_read(struct enc28j60_net *priv,
+				     u8 address)
+{
+	enc28j60_set_bank(priv, address);
+	return spi_read_op(priv, ENC28J60_READ_CTRL_REG, address);
+}
+
+static int locked_regb_read(struct enc28j60_net *priv,
+				     u8 address)
+{
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = nolock_regb_read(priv, address);
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+/*
+ * Register word read
+ */
+static int nolock_regw_read(struct enc28j60_net *priv,
+				     u8 address)
+{
+	int rl, rh;
+
+	enc28j60_set_bank(priv, address);
+	rl = spi_read_op(priv, ENC28J60_READ_CTRL_REG, address);
+	rh = spi_read_op(priv, ENC28J60_READ_CTRL_REG, address + 1);
+
+	return (rh << 8) | rl;
+}
+
+static int locked_regw_read(struct enc28j60_net *priv,
+				     u8 address)
+{
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = nolock_regw_read(priv, address);
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+/*
+ * Register byte write
+ */
+static void nolock_regb_write(struct enc28j60_net *priv,
+				       u8 address, u8 data)
+{
+	enc28j60_set_bank(priv, address);
+	spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, address, data);
+}
+
+static void locked_regb_write(struct enc28j60_net *priv,
+				       u8 address, u8 data)
+{
+	mutex_lock(&priv->lock);
+	nolock_regb_write(priv, address, data);
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * Register word write
+ */
+static void nolock_regw_write(struct enc28j60_net *priv,
+				       u8 address, u16 data)
+{
+	enc28j60_set_bank(priv, address);
+	spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, address, (u8) data);
+	spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, address + 1,
+		     (u8) (data >> 8));
+}
+
+static void locked_regw_write(struct enc28j60_net *priv,
+				       u8 address, u16 data)
+{
+	mutex_lock(&priv->lock);
+	nolock_regw_write(priv, address, data);
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * Buffer memory read
+ * Select the starting address and execute a SPI buffer read
+ */
+static void enc28j60_mem_read(struct enc28j60_net *priv,
+				     u16 addr, int len, u8 *data)
+{
+	mutex_lock(&priv->lock);
+	nolock_regw_write(priv, ERDPTL, addr);
+#ifdef CONFIG_ENC28J60_WRITEVERIFY
+	if (netif_msg_drv(priv)) {
+		u16 reg;
+		reg = nolock_regw_read(priv, ERDPTL);
+		if (reg != addr)
+			printk(KERN_DEBUG DRV_NAME ": %s() error writing ERDPT "
+				"(0x%04x - 0x%04x)\n", __FUNCTION__, reg, addr);
+	}
+#endif
+	spi_read_buf(priv, len, data);
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * Write packet to enc28j60 TX buffer memory
+ */
+static void
+enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data)
+{
+	mutex_lock(&priv->lock);
+	/* Set the write pointer to start of transmit buffer area */
+	nolock_regw_write(priv, EWRPTL, TXSTART_INIT);
+#ifdef CONFIG_ENC28J60_WRITEVERIFY
+	if (netif_msg_drv(priv)) {
+		u16 reg;
+		reg = nolock_regw_read(priv, EWRPTL);
+		if (reg != TXSTART_INIT)
+			printk(KERN_DEBUG DRV_NAME
+				": %s() ERWPT:0x%04x != 0x%04x\n",
+				__FUNCTION__, reg, TXSTART_INIT);
+	}
+#endif
+	/* Set the TXND pointer to correspond to the packet size given */
+	nolock_regw_write(priv, ETXNDL, TXSTART_INIT + len);
+	/* write per-packet control byte */
+	spi_write_op(priv, ENC28J60_WRITE_BUF_MEM, 0, 0x00);
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME
+			": %s() after control byte ERWPT:0x%04x\n",
+			__FUNCTION__, nolock_regw_read(priv, EWRPTL));
+	/* copy the packet into the transmit buffer */
+	spi_write_buf(priv, len, data);
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME
+			 ": %s() after write packet ERWPT:0x%04x, len=%d\n",
+			 __FUNCTION__, nolock_regw_read(priv, EWRPTL), len);
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * Wait until the PHY operation is complete.
+ */
+static int wait_phy_ready(struct enc28j60_net *priv)
+{
+	unsigned long timeout = jiffies + 20 * HZ / 1000;
+	int ret = 1;
+
+	/* 20 msec timeout read */
+	while (nolock_regb_read(priv, MISTAT) & MISTAT_BUSY) {
+		if (time_after(jiffies, timeout)) {
+			if (netif_msg_drv(priv))
+				printk(KERN_DEBUG DRV_NAME
+					": PHY ready timeout!\n");
+			ret = 0;
+			break;
+		}
+		cpu_relax();
+	}
+	return ret;
+}
+
+/*
+ * PHY register read
+ * PHY registers are not accessed directly, but through the MII
+ */
+static u16 enc28j60_phy_read(struct enc28j60_net *priv, u8 address)
+{
+	u16 ret;
+
+	mutex_lock(&priv->lock);
+	/* set the PHY register address */
+	nolock_regb_write(priv, MIREGADR, address);
+	/* start the register read operation */
+	nolock_regb_write(priv, MICMD, MICMD_MIIRD);
+	/* wait until the PHY read completes */
+	wait_phy_ready(priv);
+	/* quit reading */
+	nolock_regb_write(priv, MICMD, 0x00);
+	/* return the data */
+	ret  = nolock_regw_read(priv, MIRDL);
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int enc28j60_phy_write(struct enc28j60_net *priv, u8 address, u16 data)
+{
+	int ret;
+
+	mutex_lock(&priv->lock);
+	/* set the PHY register address */
+	nolock_regb_write(priv, MIREGADR, address);
+	/* write the PHY data */
+	nolock_regw_write(priv, MIWRL, data);
+	/* wait until the PHY write completes and return */
+	ret = wait_phy_ready(priv);
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+/*
+ * Program the hardware MAC address from dev->dev_addr.
+ */
+static int enc28j60_set_hw_macaddr(struct net_device *ndev)
+{
+	int ret;
+	struct enc28j60_net *priv = netdev_priv(ndev);
+
+	mutex_lock(&priv->lock);
+	if (!priv->hw_enable) {
+		if (netif_msg_drv(priv)) {
+			DECLARE_MAC_BUF(mac);
+			printk(KERN_INFO DRV_NAME
+				": %s: Setting MAC address to %s\n",
+				ndev->name, print_mac(mac, ndev->dev_addr));
+		}
+		/* NOTE: MAC address in ENC28J60 is byte-backward */
+		nolock_regb_write(priv, MAADR5, ndev->dev_addr[0]);
+		nolock_regb_write(priv, MAADR4, ndev->dev_addr[1]);
+		nolock_regb_write(priv, MAADR3, ndev->dev_addr[2]);
+		nolock_regb_write(priv, MAADR2, ndev->dev_addr[3]);
+		nolock_regb_write(priv, MAADR1, ndev->dev_addr[4]);
+		nolock_regb_write(priv, MAADR0, ndev->dev_addr[5]);
+		ret = 0;
+	} else {
+		if (netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME
+				": %s() Hardware must be disabled to set "
+				"Mac address\n", __FUNCTION__);
+		ret = -EBUSY;
+	}
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+/*
+ * Store the new hardware address in dev->dev_addr, and update the MAC.
+ */
+static int enc28j60_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *address = addr;
+
+	if (netif_running(dev))
+		return -EBUSY;
+	if (!is_valid_ether_addr(address->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
+	return enc28j60_set_hw_macaddr(dev);
+}
+
+/*
+ * Debug routine to dump useful register contents
+ */
+static void enc28j60_dump_regs(struct enc28j60_net *priv, const char *msg)
+{
+	mutex_lock(&priv->lock);
+	printk(KERN_DEBUG DRV_NAME " %s\n"
+		"HwRevID: 0x%02x\n"
+		"Cntrl: ECON1 ECON2 ESTAT  EIR  EIE\n"
+		"       0x%02x  0x%02x  0x%02x  0x%02x  0x%02x\n"
+		"MAC  : MACON1 MACON3 MACON4\n"
+		"       0x%02x   0x%02x   0x%02x\n"
+		"Rx   : ERXST  ERXND  ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\n"
+		"       0x%04x 0x%04x 0x%04x  0x%04x  "
+		"0x%02x    0x%02x    0x%04x\n"
+		"Tx   : ETXST  ETXND  MACLCON1 MACLCON2 MAPHSUP\n"
+		"       0x%04x 0x%04x 0x%02x     0x%02x     0x%02x\n",
+		msg, nolock_regb_read(priv, EREVID),
+		nolock_regb_read(priv, ECON1), nolock_regb_read(priv, ECON2),
+		nolock_regb_read(priv, ESTAT), nolock_regb_read(priv, EIR),
+		nolock_regb_read(priv, EIE), nolock_regb_read(priv, MACON1),
+		nolock_regb_read(priv, MACON3), nolock_regb_read(priv, MACON4),
+		nolock_regw_read(priv, ERXSTL), nolock_regw_read(priv, ERXNDL),
+		nolock_regw_read(priv, ERXWRPTL),
+		nolock_regw_read(priv, ERXRDPTL),
+		nolock_regb_read(priv, ERXFCON),
+		nolock_regb_read(priv, EPKTCNT),
+		nolock_regw_read(priv, MAMXFLL), nolock_regw_read(priv, ETXSTL),
+		nolock_regw_read(priv, ETXNDL),
+		nolock_regb_read(priv, MACLCON1),
+		nolock_regb_read(priv, MACLCON2),
+		nolock_regb_read(priv, MAPHSUP));
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * ERXRDPT need to be set always at odd addresses, refer to errata datasheet
+ */
+static u16 erxrdpt_workaround(u16 next_packet_ptr, u16 start, u16 end)
+{
+	u16 erxrdpt;
+
+	if ((next_packet_ptr - 1 < start) || (next_packet_ptr - 1 > end))
+		erxrdpt = end;
+	else
+		erxrdpt = next_packet_ptr - 1;
+
+	return erxrdpt;
+}
+
+static void nolock_rxfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
+{
+	u16 erxrdpt;
+
+	if (start > 0x1FFF || end > 0x1FFF || start > end) {
+		if (netif_msg_drv(priv))
+			printk(KERN_ERR DRV_NAME ": %s(%d, %d) RXFIFO "
+				"bad parameters!\n", __FUNCTION__, start, end);
+		return;
+	}
+	/* set receive buffer start + end */
+	priv->next_pk_ptr = start;
+	nolock_regw_write(priv, ERXSTL, start);
+	erxrdpt = erxrdpt_workaround(priv->next_pk_ptr, start, end);
+	nolock_regw_write(priv, ERXRDPTL, erxrdpt);
+	nolock_regw_write(priv, ERXNDL, end);
+}
+
+static void nolock_txfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
+{
+	if (start > 0x1FFF || end > 0x1FFF || start > end) {
+		if (netif_msg_drv(priv))
+			printk(KERN_ERR DRV_NAME ": %s(%d, %d) TXFIFO "
+				"bad parameters!\n", __FUNCTION__, start, end);
+		return;
+	}
+	/* set transmit buffer start + end */
+	nolock_regw_write(priv, ETXSTL, start);
+	nolock_regw_write(priv, ETXNDL, end);
+}
+
+static int enc28j60_hw_init(struct enc28j60_net *priv)
+{
+	u8 reg;
+
+	if (netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __FUNCTION__,
+			priv->full_duplex ? "FullDuplex" : "HalfDuplex");
+
+	mutex_lock(&priv->lock);
+	/* first reset the chip */
+	enc28j60_soft_reset(priv);
+	/* Clear ECON1 */
+	spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, ECON1, 0x00);
+	priv->bank = 0;
+	priv->hw_enable = false;
+	priv->tx_retry_count = 0;
+	priv->max_pk_counter = 0;
+	priv->rxfilter = RXFILTER_NORMAL;
+	/* enable address auto increment */
+	nolock_regb_write(priv, ECON2, ECON2_AUTOINC);
+
+	nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT);
+	nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT);
+	mutex_unlock(&priv->lock);
+
+	/*
+	 * Check the RevID.
+	 * If it's 0x00 or 0xFF probably the enc28j60 is not mounted or
+	 * damaged
+	 */
+	reg = locked_regb_read(priv, EREVID);
+	if (netif_msg_drv(priv))
+		printk(KERN_INFO DRV_NAME ": chip RevID: 0x%02x\n", reg);
+	if (reg == 0x00 || reg == 0xff) {
+		if (netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME ": %s() Invalid RevId %d\n",
+				__FUNCTION__, reg);
+		return 0;
+	}
+
+	/* default filter mode: (unicast OR broadcast) AND crc valid */
+	locked_regb_write(priv, ERXFCON,
+			    ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN);
+
+	/* enable MAC receive */
+	locked_regb_write(priv, MACON1,
+			    MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS);
+	/* enable automatic padding and CRC operations */
+	if (priv->full_duplex) {
+		locked_regb_write(priv, MACON3,
+				    MACON3_PADCFG0 | MACON3_TXCRCEN |
+				    MACON3_FRMLNEN | MACON3_FULDPX);
+		/* set inter-frame gap (non-back-to-back) */
+		locked_regb_write(priv, MAIPGL, 0x12);
+		/* set inter-frame gap (back-to-back) */
+		locked_regb_write(priv, MABBIPG, 0x15);
+	} else {
+		locked_regb_write(priv, MACON3,
+				    MACON3_PADCFG0 | MACON3_TXCRCEN |
+				    MACON3_FRMLNEN);
+		locked_regb_write(priv, MACON4, 1 << 6);	/* DEFER bit */
+		/* set inter-frame gap (non-back-to-back) */
+		locked_regw_write(priv, MAIPGL, 0x0C12);
+		/* set inter-frame gap (back-to-back) */
+		locked_regb_write(priv, MABBIPG, 0x12);
+	}
+	/*
+	 * MACLCON1 (default)
+	 * MACLCON2 (default)
+	 * Set the maximum packet size which the controller will accept
+	 */
+	locked_regw_write(priv, MAMXFLL, MAX_FRAMELEN);
+
+	/* Configure LEDs */
+	if (!enc28j60_phy_write(priv, PHLCON, ENC28J60_LAMPS_MODE))
+		return 0;
+
+	if (priv->full_duplex) {
+		if (!enc28j60_phy_write(priv, PHCON1, PHCON1_PDPXMD))
+			return 0;
+		if (!enc28j60_phy_write(priv, PHCON2, 0x00))
+			return 0;
+	} else {
+		if (!enc28j60_phy_write(priv, PHCON1, 0x00))
+			return 0;
+		if (!enc28j60_phy_write(priv, PHCON2, PHCON2_HDLDIS))
+			return 0;
+	}
+	if (netif_msg_hw(priv))
+		enc28j60_dump_regs(priv, "Hw initialized.");
+
+	return 1;
+}
+
+static void enc28j60_hw_enable(struct enc28j60_net *priv)
+{
+	/* enable interrutps */
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n",
+			__FUNCTION__);
+
+	enc28j60_phy_write(priv, PHIE, PHIE_PGEIE | PHIE_PLNKIE);
+
+	mutex_lock(&priv->lock);
+	nolock_reg_bfclr(priv, EIR, EIR_DMAIF | EIR_LINKIF |
+			 EIR_TXIF | EIR_TXERIF | EIR_RXERIF | EIR_PKTIF);
+	nolock_regb_write(priv, EIE, EIE_INTIE | EIE_PKTIE | EIE_LINKIE |
+			  EIE_TXIE | EIE_TXERIE | EIE_RXERIE);
+
+	/* enable receive logic */
+	nolock_reg_bfset(priv, ECON1, ECON1_RXEN);
+	priv->hw_enable = true;
+	mutex_unlock(&priv->lock);
+}
+
+static void enc28j60_hw_disable(struct enc28j60_net *priv)
+{
+	mutex_lock(&priv->lock);
+	/* disable interrutps and packet reception */
+	nolock_regb_write(priv, EIE, 0x00);
+	nolock_reg_bfclr(priv, ECON1, ECON1_RXEN);
+	priv->hw_enable = false;
+	mutex_unlock(&priv->lock);
+}
+
+static int
+enc28j60_setlink(struct net_device *ndev, u8 autoneg, u16 speed, u8 duplex)
+{
+	struct enc28j60_net *priv = netdev_priv(ndev);
+	int ret = 0;
+
+	if (!priv->hw_enable) {
+		if (autoneg == AUTONEG_DISABLE && speed == SPEED_10) {
+			priv->full_duplex = (duplex == DUPLEX_FULL);
+			if (!enc28j60_hw_init(priv)) {
+				if (netif_msg_drv(priv))
+					dev_err(&ndev->dev,
+						"hw_reset() failed\n");
+				ret = -EINVAL;
+			}
+		} else {
+			if (netif_msg_link(priv))
+				dev_warn(&ndev->dev,
+					"unsupported link setting\n");
+			ret = -EOPNOTSUPP;
+		}
+	} else {
+		if (netif_msg_link(priv))
+			dev_warn(&ndev->dev, "Warning: hw must be disabled "
+				"to set link mode\n");
+		ret = -EBUSY;
+	}
+	return ret;
+}
+
+/*
+ * Read the Transmit Status Vector
+ */
+static void enc28j60_read_tsv(struct enc28j60_net *priv, u8 tsv[TSV_SIZE])
+{
+	int endptr;
+
+	endptr = locked_regw_read(priv, ETXNDL);
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME ": reading TSV at addr:0x%04x\n",
+			 endptr + 1);
+	enc28j60_mem_read(priv, endptr + 1, sizeof(tsv), tsv);
+}
+
+static void enc28j60_dump_tsv(struct enc28j60_net *priv, const char *msg,
+				u8 tsv[TSV_SIZE])
+{
+	u16 tmp1, tmp2;
+
+	printk(KERN_DEBUG DRV_NAME ": %s - TSV:\n", msg);
+	tmp1 = tsv[1];
+	tmp1 <<= 8;
+	tmp1 |= tsv[0];
+
+	tmp2 = tsv[5];
+	tmp2 <<= 8;
+	tmp2 |= tsv[4];
+
+	printk(KERN_DEBUG DRV_NAME ": ByteCount: %d, CollisionCount: %d,"
+		" TotByteOnWire: %d\n", tmp1, tsv[2] & 0x0f, tmp2);
+	printk(KERN_DEBUG DRV_NAME ": TxDone: %d, CRCErr:%d, LenChkErr: %d,"
+		" LenOutOfRange: %d\n", TSV_GETBIT(tsv, TSV_TXDONE),
+		TSV_GETBIT(tsv, TSV_TXCRCERROR),
+		TSV_GETBIT(tsv, TSV_TXLENCHKERROR),
+		TSV_GETBIT(tsv, TSV_TXLENOUTOFRANGE));
+	printk(KERN_DEBUG DRV_NAME ": Multicast: %d, Broadcast: %d, "
+		"PacketDefer: %d, ExDefer: %d\n",
+		TSV_GETBIT(tsv, TSV_TXMULTICAST),
+		TSV_GETBIT(tsv, TSV_TXBROADCAST),
+		TSV_GETBIT(tsv, TSV_TXPACKETDEFER),
+		TSV_GETBIT(tsv, TSV_TXEXDEFER));
+	printk(KERN_DEBUG DRV_NAME ": ExCollision: %d, LateCollision: %d, "
+		 "Giant: %d, Underrun: %d\n",
+		 TSV_GETBIT(tsv, TSV_TXEXCOLLISION),
+		 TSV_GETBIT(tsv, TSV_TXLATECOLLISION),
+		 TSV_GETBIT(tsv, TSV_TXGIANT), TSV_GETBIT(tsv, TSV_TXUNDERRUN));
+	printk(KERN_DEBUG DRV_NAME ": ControlFrame: %d, PauseFrame: %d, "
+		 "BackPressApp: %d, VLanTagFrame: %d\n",
+		 TSV_GETBIT(tsv, TSV_TXCONTROLFRAME),
+		 TSV_GETBIT(tsv, TSV_TXPAUSEFRAME),
+		 TSV_GETBIT(tsv, TSV_BACKPRESSUREAPP),
+		 TSV_GETBIT(tsv, TSV_TXVLANTAGFRAME));
+}
+
+/*
+ * Receive Status vector
+ */
+static void enc28j60_dump_rsv(struct enc28j60_net *priv, const char *msg,
+			      u16 pk_ptr, int len, u16 sts)
+{
+	printk(KERN_DEBUG DRV_NAME ": %s - NextPk: 0x%04x - RSV:\n",
+		msg, pk_ptr);
+	printk(KERN_DEBUG DRV_NAME ": ByteCount: %d, DribbleNibble: %d\n", len,
+		 RSV_GETBIT(sts, RSV_DRIBBLENIBBLE));
+	printk(KERN_DEBUG DRV_NAME ": RxOK: %d, CRCErr:%d, LenChkErr: %d,"
+		 " LenOutOfRange: %d\n", RSV_GETBIT(sts, RSV_RXOK),
+		 RSV_GETBIT(sts, RSV_CRCERROR),
+		 RSV_GETBIT(sts, RSV_LENCHECKERR),
+		 RSV_GETBIT(sts, RSV_LENOUTOFRANGE));
+	printk(KERN_DEBUG DRV_NAME ": Multicast: %d, Broadcast: %d, "
+		 "LongDropEvent: %d, CarrierEvent: %d\n",
+		 RSV_GETBIT(sts, RSV_RXMULTICAST),
+		 RSV_GETBIT(sts, RSV_RXBROADCAST),
+		 RSV_GETBIT(sts, RSV_RXLONGEVDROPEV),
+		 RSV_GETBIT(sts, RSV_CARRIEREV));
+	printk(KERN_DEBUG DRV_NAME ": ControlFrame: %d, PauseFrame: %d,"
+		 " UnknownOp: %d, VLanTagFrame: %d\n",
+		 RSV_GETBIT(sts, RSV_RXCONTROLFRAME),
+		 RSV_GETBIT(sts, RSV_RXPAUSEFRAME),
+		 RSV_GETBIT(sts, RSV_RXUNKNOWNOPCODE),
+		 RSV_GETBIT(sts, RSV_RXTYPEVLAN));
+}
+
+static void dump_packet(const char *msg, int len, const char *data)
+{
+	printk(KERN_DEBUG DRV_NAME ": %s - packet len:%d\n", msg, len);
+	print_hex_dump(KERN_DEBUG, "pk data: ", DUMP_PREFIX_OFFSET, 16, 1,
+			data, len, true);
+}
+
+/*
+ * Hardware receive function.
+ * Read the buffer memory, update the FIFO pointer to free the buffer,
+ * check the status vector and decrement the packet counter.
+ */
+static void enc28j60_hw_rx(struct net_device *ndev)
+{
+	struct enc28j60_net *priv = netdev_priv(ndev);
+	struct sk_buff *skb = NULL;
+	u16 erxrdpt, next_packet, rxstat;
+	u8 rsv[RSV_SIZE];
+	int len;
+
+	if (netif_msg_rx_status(priv))
+		printk(KERN_DEBUG DRV_NAME ": RX pk_addr:0x%04x\n",
+			priv->next_pk_ptr);
+
+	if (unlikely(priv->next_pk_ptr > RXEND_INIT)) {
+		if (netif_msg_rx_err(priv))
+			dev_err(&ndev->dev,
+				"%s() Invalid packet address!! 0x%04x\n",
+				__FUNCTION__, priv->next_pk_ptr);
+		/* packet address corrupted: reset RX logic */
+		mutex_lock(&priv->lock);
+		nolock_reg_bfclr(priv, ECON1, ECON1_RXEN);
+		nolock_reg_bfset(priv, ECON1, ECON1_RXRST);
+		nolock_reg_bfclr(priv, ECON1, ECON1_RXRST);
+		nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT);
+		nolock_reg_bfclr(priv, EIR, EIR_RXERIF);
+		nolock_reg_bfset(priv, ECON1, ECON1_RXEN);
+		mutex_unlock(&priv->lock);
+		ndev->stats.rx_errors++;
+		return;
+	}
+	/* Read next packet pointer and rx status vector */
+	enc28j60_mem_read(priv, priv->next_pk_ptr, sizeof(rsv), rsv);
+
+	next_packet = rsv[1];
+	next_packet <<= 8;
+	next_packet |= rsv[0];
+
+	len = rsv[3];
+	len <<= 8;
+	len |= rsv[2];
+
+	rxstat = rsv[5];
+	rxstat <<= 8;
+	rxstat |= rsv[4];
+
+	if (netif_msg_rx_status(priv))
+		enc28j60_dump_rsv(priv, __FUNCTION__, next_packet, len, rxstat);
+
+	if (!RSV_GETBIT(rxstat, RSV_RXOK)) {
+		if (netif_msg_rx_err(priv))
+			dev_err(&ndev->dev, "Rx Error (%04x)\n", rxstat);
+		ndev->stats.rx_errors++;
+		if (RSV_GETBIT(rxstat, RSV_CRCERROR))
+			ndev->stats.rx_crc_errors++;
+		if (RSV_GETBIT(rxstat, RSV_LENCHECKERR))
+			ndev->stats.rx_frame_errors++;
+	} else {
+		skb = dev_alloc_skb(len);
+		if (!skb) {
+			if (netif_msg_rx_err(priv))
+				dev_err(&ndev->dev,
+					"out of memory for Rx'd frame\n");
+			ndev->stats.rx_dropped++;
+		} else {
+			skb->dev = ndev;
+			/* copy the packet from the receive buffer */
+			enc28j60_mem_read(priv, priv->next_pk_ptr + sizeof(rsv),
+					len, skb_put(skb, len));
+			if (netif_msg_pktdata(priv))
+				dump_packet(__FUNCTION__, skb->len, skb->data);
+			skb->protocol = eth_type_trans(skb, ndev);
+			/* update statistics */
+			ndev->stats.rx_packets++;
+			ndev->stats.rx_bytes += len;
+			ndev->last_rx = jiffies;
+			netif_rx(skb);
+		}
+	}
+	/*
+	 * Move the RX read pointer to the start of the next
+	 * received packet.
+	 * This frees the memory we just read out
+	 */
+	erxrdpt = erxrdpt_workaround(next_packet, RXSTART_INIT, RXEND_INIT);
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT:0x%04x\n",
+			__FUNCTION__, erxrdpt);
+
+	mutex_lock(&priv->lock);
+	nolock_regw_write(priv, ERXRDPTL, erxrdpt);
+#ifdef CONFIG_ENC28J60_WRITEVERIFY
+	if (netif_msg_drv(priv)) {
+		u16 reg;
+		reg = nolock_regw_read(priv, ERXRDPTL);
+		if (reg != erxrdpt)
+			printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT verify "
+				"error (0x%04x - 0x%04x)\n", __FUNCTION__,
+				reg, erxrdpt);
+	}
+#endif
+	priv->next_pk_ptr = next_packet;
+	/* we are done with this packet, decrement the packet counter */
+	nolock_reg_bfset(priv, ECON2, ECON2_PKTDEC);
+	mutex_unlock(&priv->lock);
+}
+
+/*
+ * Calculate free space in RxFIFO
+ */
+static int enc28j60_get_free_rxfifo(struct enc28j60_net *priv)
+{
+	int epkcnt, erxst, erxnd, erxwr, erxrd;
+	int free_space;
+
+	mutex_lock(&priv->lock);
+	epkcnt = nolock_regb_read(priv, EPKTCNT);
+	if (epkcnt >= 255)
+		free_space = -1;
+	else {
+		erxst = nolock_regw_read(priv, ERXSTL);
+		erxnd = nolock_regw_read(priv, ERXNDL);
+		erxwr = nolock_regw_read(priv, ERXWRPTL);
+		erxrd = nolock_regw_read(priv, ERXRDPTL);
+
+		if (erxwr > erxrd)
+			free_space = (erxnd - erxst) - (erxwr - erxrd);
+		else if (erxwr == erxrd)
+			free_space = (erxnd - erxst);
+		else
+			free_space = erxrd - erxwr - 1;
+	}
+	mutex_unlock(&priv->lock);
+	if (netif_msg_rx_status(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() free_space = %d\n",
+			__FUNCTION__, free_space);
+	return free_space;
+}
+
+/*
+ * Access the PHY to determine link status
+ */
+static void enc28j60_check_link_status(struct net_device *ndev)
+{
+	struct enc28j60_net *priv = netdev_priv(ndev);
+	u16 reg;
+	int duplex;
+
+	reg = enc28j60_phy_read(priv, PHSTAT2);
+	if (netif_msg_hw(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() PHSTAT1: %04x, "
+			"PHSTAT2: %04x\n", __FUNCTION__,
+			enc28j60_phy_read(priv, PHSTAT1), reg);
+	duplex = reg & PHSTAT2_DPXSTAT;
+
+	if (reg & PHSTAT2_LSTAT) {
+		netif_carrier_on(ndev);
+		if (netif_msg_ifup(priv))
+			dev_info(&ndev->dev, "link up - %s\n",
+				duplex ? "Full duplex" : "Half duplex");
+	} else {
+		if (netif_msg_ifdown(priv))
+			dev_info(&ndev->dev, "link down\n");
+		netif_carrier_off(ndev);
+	}
+}
+
+static void enc28j60_tx_clear(struct net_device *ndev, bool err)
+{
+	struct enc28j60_net *priv = netdev_priv(ndev);
+
+	if (err)
+		ndev->stats.tx_errors++;
+	else
+		ndev->stats.tx_packets++;
+
+	if (priv->tx_skb) {
+		if (!err)
+			ndev->stats.tx_bytes += priv->tx_skb->len;
+		dev_kfree_skb(priv->tx_skb);
+		priv->tx_skb = NULL;
+	}
+	locked_reg_bfclr(priv, ECON1, ECON1_TXRTS);
+	netif_wake_queue(ndev);
+}
+
+/*
+ * RX handler
+ * ignore PKTIF because is unreliable! (look at the errata datasheet)
+ * check EPKTCNT is the suggested workaround.
+ * We don't need to clear interrupt flag, automatically done when
+ * enc28j60_hw_rx() decrements the packet counter.
+ * Returns how many packet processed.
+ */
+static int enc28j60_rx_interrupt(struct net_device *ndev)
+{
+	struct enc28j60_net *priv = netdev_priv(ndev);
+	int pk_counter, ret;
+
+	pk_counter = locked_regb_read(priv, EPKTCNT);
+	if (pk_counter && netif_msg_intr(priv))
+		printk(KERN_DEBUG DRV_NAME ": intRX, pk_cnt: %d\n", pk_counter);
+	if (pk_counter > priv->max_pk_counter) {
+		/* update statistics */
+		priv->max_pk_counter = pk_counter;
+		if (netif_msg_rx_status(priv) && priv->max_pk_counter > 1)
+			printk(KERN_DEBUG DRV_NAME ": RX max_pk_cnt: %d\n",
+				priv->max_pk_counter);
+	}
+	ret = pk_counter;
+	while (pk_counter-- > 0)
+		enc28j60_hw_rx(ndev);
+
+	return ret;
+}
+
+static void enc28j60_irq_work_handler(struct work_struct *work)
+{
+	struct enc28j60_net *priv =
+		container_of(work, struct enc28j60_net, irq_work);
+	struct net_device *ndev = priv->netdev;
+	int intflags, loop;
+
+	if (netif_msg_intr(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+	/* disable further interrupts */
+	locked_reg_bfclr(priv, EIE, EIE_INTIE);
+
+	do {
+		loop = 0;
+		intflags = locked_regb_read(priv, EIR);
+		/* DMA interrupt handler (not currently used) */
+		if ((intflags & EIR_DMAIF) != 0) {
+			loop++;
+			if (netif_msg_intr(priv))
+				printk(KERN_DEBUG DRV_NAME
+					": intDMA(%d)\n", loop);
+			locked_reg_bfclr(priv, EIR, EIR_DMAIF);
+		}
+		/* LINK changed handler */
+		if ((intflags & EIR_LINKIF) != 0) {
+			loop++;
+			if (netif_msg_intr(priv))
+				printk(KERN_DEBUG DRV_NAME
+					": intLINK(%d)\n", loop);
+			enc28j60_check_link_status(ndev);
+			/* read PHIR to clear the flag */
+			enc28j60_phy_read(priv, PHIR);
+		}
+		/* TX complete handler */
+		if ((intflags & EIR_TXIF) != 0) {
+			bool err = false;
+			loop++;
+			if (netif_msg_intr(priv))
+				printk(KERN_DEBUG DRV_NAME
+					": intTX(%d)\n", loop);
+			priv->tx_retry_count = 0;
+			if (locked_regb_read(priv, ESTAT) & ESTAT_TXABRT) {
+				if (netif_msg_tx_err(priv))
+					dev_err(&ndev->dev,
+						"Tx Error (aborted)\n");
+				err = true;
+			}
+			if (netif_msg_tx_done(priv)) {
+				u8 tsv[TSV_SIZE];
+				enc28j60_read_tsv(priv, tsv);
+				enc28j60_dump_tsv(priv, "Tx Done", tsv);
+			}
+			enc28j60_tx_clear(ndev, err);
+			locked_reg_bfclr(priv, EIR, EIR_TXIF);
+		}
+		/* TX Error handler */
+		if ((intflags & EIR_TXERIF) != 0) {
+			u8 tsv[TSV_SIZE];
+
+			loop++;
+			if (netif_msg_intr(priv))
+				printk(KERN_DEBUG DRV_NAME
+					": intTXErr(%d)\n", loop);
+			locked_reg_bfclr(priv, ECON1, ECON1_TXRTS);
+			enc28j60_read_tsv(priv, tsv);
+			if (netif_msg_tx_err(priv))
+				enc28j60_dump_tsv(priv, "Tx Error", tsv);
+			/* Reset TX logic */
+			mutex_lock(&priv->lock);
+			nolock_reg_bfset(priv, ECON1, ECON1_TXRST);
+			nolock_reg_bfclr(priv, ECON1, ECON1_TXRST);
+			nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT);
+			mutex_unlock(&priv->lock);
+			/* Transmit Late collision check for retransmit */
+			if (TSV_GETBIT(tsv, TSV_TXLATECOLLISION)) {
+				if (netif_msg_tx_err(priv))
+					printk(KERN_DEBUG DRV_NAME
+						": LateCollision TXErr (%d)\n",
+						priv->tx_retry_count);
+				if (priv->tx_retry_count++ < MAX_TX_RETRYCOUNT)
+					locked_reg_bfset(priv, ECON1,
+							   ECON1_TXRTS);
+				else
+					enc28j60_tx_clear(ndev, true);
+			} else
+				enc28j60_tx_clear(ndev, true);
+			locked_reg_bfclr(priv, EIR, EIR_TXERIF);
+		}
+		/* RX Error handler */
+		if ((intflags & EIR_RXERIF) != 0) {
+			loop++;
+			if (netif_msg_intr(priv))
+				printk(KERN_DEBUG DRV_NAME
+					": intRXErr(%d)\n", loop);
+			/* Check free FIFO space to flag RX overrun */
+			if (enc28j60_get_free_rxfifo(priv) <= 0) {
+				if (netif_msg_rx_err(priv))
+					printk(KERN_DEBUG DRV_NAME
+						": RX Overrun\n");
+				ndev->stats.rx_dropped++;
+			}
+			locked_reg_bfclr(priv, EIR, EIR_RXERIF);
+		}
+		/* RX handler */
+		if (enc28j60_rx_interrupt(ndev))
+			loop++;
+	} while (loop);
+
+	/* re-enable interrupts */
+	locked_reg_bfset(priv, EIE, EIE_INTIE);
+	if (netif_msg_intr(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __FUNCTION__);
+}
+
+/*
+ * Hardware transmit function.
+ * Fill the buffer memory and send the contents of the transmit buffer
+ * onto the network
+ */
+static void enc28j60_hw_tx(struct enc28j60_net *priv)
+{
+	if (netif_msg_tx_queued(priv))
+		printk(KERN_DEBUG DRV_NAME
+			": Tx Packet Len:%d\n", priv->tx_skb->len);
+
+	if (netif_msg_pktdata(priv))
+		dump_packet(__FUNCTION__,
+			    priv->tx_skb->len, priv->tx_skb->data);
+	enc28j60_packet_write(priv, priv->tx_skb->len, priv->tx_skb->data);
+
+#ifdef CONFIG_ENC28J60_WRITEVERIFY
+	/* readback and verify written data */
+	if (netif_msg_drv(priv)) {
+		int test_len, k;
+		u8 test_buf[64]; /* limit the test to the first 64 bytes */
+		int okflag;
+
+		test_len = priv->tx_skb->len;
+		if (test_len > sizeof(test_buf))
+			test_len = sizeof(test_buf);
+
+		/* + 1 to skip control byte */
+		enc28j60_mem_read(priv, TXSTART_INIT + 1, test_len, test_buf);
+		okflag = 1;
+		for (k = 0; k < test_len; k++) {
+			if (priv->tx_skb->data[k] != test_buf[k]) {
+				printk(KERN_DEBUG DRV_NAME
+					 ": Error, %d location differ: "
+					 "0x%02x-0x%02x\n", k,
+					 priv->tx_skb->data[k], test_buf[k]);
+				okflag = 0;
+			}
+		}
+		if (!okflag)
+			printk(KERN_DEBUG DRV_NAME ": Tx write buffer, "
+				"verify ERROR!\n");
+	}
+#endif
+	/* set TX request flag */
+	locked_reg_bfset(priv, ECON1, ECON1_TXRTS);
+}
+
+static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct enc28j60_net *priv = netdev_priv(dev);
+
+	if (netif_msg_tx_queued(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+
+	/* If some error occurs while trying to transmit this
+	 * packet, you should return '1' from this function.
+	 * In such a case you _may not_ do anything to the
+	 * SKB, it is still owned by the network queueing
+	 * layer when an error is returned.  This means you
+	 * may not modify any SKB fields, you may not free
+	 * the SKB, etc.
+	 */
+	netif_stop_queue(dev);
+
+	/* save the timestamp */
+	priv->netdev->trans_start = jiffies;
+	/* Remember the skb for deferred processing */
+	priv->tx_skb = skb;
+	schedule_work(&priv->tx_work);
+
+	return 0;
+}
+
+static void enc28j60_tx_work_handler(struct work_struct *work)
+{
+	struct enc28j60_net *priv =
+		container_of(work, struct enc28j60_net, tx_work);
+
+	/* actual delivery of data */
+	enc28j60_hw_tx(priv);
+}
+
+static irqreturn_t enc28j60_irq(int irq, void *dev_id)
+{
+	struct enc28j60_net *priv = dev_id;
+
+	/*
+	 * Can't do anything in interrupt context because we need to
+	 * block (spi_sync() is blocking) so fire of the interrupt
+	 * handling workqueue.
+	 * Remember that we access enc28j60 registers through SPI bus
+	 * via spi_sync() call.
+	 */
+	schedule_work(&priv->irq_work);
+
+	return IRQ_HANDLED;
+}
+
+static void enc28j60_tx_timeout(struct net_device *ndev)
+{
+	struct enc28j60_net *priv = netdev_priv(ndev);
+
+	if (netif_msg_timer(priv))
+		dev_err(&ndev->dev, DRV_NAME " tx timeout\n");
+
+	ndev->stats.tx_errors++;
+	/* can't restart safely under softirq */
+	schedule_work(&priv->restart_work);
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+static int enc28j60_net_open(struct net_device *dev)
+{
+	struct enc28j60_net *priv = netdev_priv(dev);
+
+	if (netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		if (netif_msg_ifup(priv)) {
+			DECLARE_MAC_BUF(mac);
+			dev_err(&dev->dev, "invalid MAC address %s\n",
+				print_mac(mac, dev->dev_addr));
+		}
+		return -EADDRNOTAVAIL;
+	}
+	/* Reset the hardware here */
+	enc28j60_hw_disable(priv);
+	if (!enc28j60_hw_init(priv)) {
+		if (netif_msg_ifup(priv))
+			dev_err(&dev->dev, "hw_reset() failed\n");
+		return -EINVAL;
+	}
+	/* Update the MAC address (in case user has changed it) */
+	enc28j60_set_hw_macaddr(dev);
+	/* Enable interrupts */
+	enc28j60_hw_enable(priv);
+	/* check link status */
+	enc28j60_check_link_status(dev);
+	/* We are now ready to accept transmit requests from
+	 * the queueing layer of the networking.
+	 */
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+/* The inverse routine to net_open(). */
+static int enc28j60_net_close(struct net_device *dev)
+{
+	struct enc28j60_net *priv = netdev_priv(dev);
+
+	if (netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
+
+	enc28j60_hw_disable(priv);
+	netif_stop_queue(dev);
+
+	return 0;
+}
+
+/*
+ * Set or clear the multicast filter for this adapter
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, filter out multicast packets
+ * num_addrs > 0	Multicast mode, receive normal and MC packets
+ */
+static void enc28j60_set_multicast_list(struct net_device *dev)
+{
+	struct enc28j60_net *priv = netdev_priv(dev);
+	int oldfilter = priv->rxfilter;
+
+	if (dev->flags & IFF_PROMISC) {
+		if (netif_msg_link(priv))
+			dev_info(&dev->dev, "promiscuous mode\n");
+		priv->rxfilter = RXFILTER_PROMISC;
+	} else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count) {
+		if (netif_msg_link(priv))
+			dev_info(&dev->dev, "%smulticast mode\n",
+				(dev->flags & IFF_ALLMULTI) ? "all-" : "");
+		priv->rxfilter = RXFILTER_MULTI;
+	} else {
+		if (netif_msg_link(priv))
+			dev_info(&dev->dev, "normal mode\n");
+		priv->rxfilter = RXFILTER_NORMAL;
+	}
+
+	if (oldfilter != priv->rxfilter)
+		schedule_work(&priv->setrx_work);
+}
+
+static void enc28j60_setrx_work_handler(struct work_struct *work)
+{
+	struct enc28j60_net *priv =
+		container_of(work, struct enc28j60_net, setrx_work);
+
+	if (priv->rxfilter == RXFILTER_PROMISC) {
+		if (netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME ": promiscuous mode\n");
+		locked_regb_write(priv, ERXFCON, 0x00);
+	} else if (priv->rxfilter == RXFILTER_MULTI) {
+		if (netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME ": multicast mode\n");
+		locked_regb_write(priv, ERXFCON,
+					ERXFCON_UCEN | ERXFCON_CRCEN |
+					ERXFCON_BCEN | ERXFCON_MCEN);
+	} else {
+		if (netif_msg_drv(priv))
+			printk(KERN_DEBUG DRV_NAME ": normal mode\n");
+		locked_regb_write(priv, ERXFCON,
+					ERXFCON_UCEN | ERXFCON_CRCEN |
+					ERXFCON_BCEN);
+	}
+}
+
+static void enc28j60_restart_work_handler(struct work_struct *work)
+{
+	struct enc28j60_net *priv =
+			container_of(work, struct enc28j60_net, restart_work);
+	struct net_device *ndev = priv->netdev;
+	int ret;
+
+	rtnl_lock();
+	if (netif_running(ndev)) {
+		enc28j60_net_close(ndev);
+		ret = enc28j60_net_open(ndev);
+		if (unlikely(ret)) {
+			dev_info(&ndev->dev, " could not restart %d\n", ret);
+			dev_close(ndev);
+		}
+	}
+	rtnl_unlock();
+}
+
+/* ......................... ETHTOOL SUPPORT ........................... */
+
+static void
+enc28j60_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+	strlcpy(info->bus_info,
+		dev->dev.parent->bus_id, sizeof(info->bus_info));
+}
+
+static int
+enc28j60_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct enc28j60_net *priv = netdev_priv(dev);
+
+	cmd->transceiver = XCVR_INTERNAL;
+	cmd->supported	= SUPPORTED_10baseT_Half
+			| SUPPORTED_10baseT_Full
+			| SUPPORTED_TP;
+	cmd->speed	= SPEED_10;
+	cmd->duplex	= priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+	cmd->port	= PORT_TP;
+	cmd->autoneg	= AUTONEG_DISABLE;
+
+	return 0;
+}
+
+static int
+enc28j60_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	return enc28j60_setlink(dev, cmd->autoneg, cmd->speed, cmd->duplex);
+}
+
+static u32 enc28j60_get_msglevel(struct net_device *dev)
+{
+	struct enc28j60_net *priv = netdev_priv(dev);
+	return priv->msg_enable;
+}
+
+static void enc28j60_set_msglevel(struct net_device *dev, u32 val)
+{
+	struct enc28j60_net *priv = netdev_priv(dev);
+	priv->msg_enable = val;
+}
+
+static const struct ethtool_ops enc28j60_ethtool_ops = {
+	.get_settings	= enc28j60_get_settings,
+	.set_settings	= enc28j60_set_settings,
+	.get_drvinfo	= enc28j60_get_drvinfo,
+	.get_msglevel	= enc28j60_get_msglevel,
+	.set_msglevel	= enc28j60_set_msglevel,
+};
+
+static int enc28j60_chipset_init(struct net_device *dev)
+{
+	struct enc28j60_net *priv = netdev_priv(dev);
+
+	return enc28j60_hw_init(priv);
+}
+
+static int __devinit enc28j60_probe(struct spi_device *spi)
+{
+	struct net_device *dev;
+	struct enc28j60_net *priv;
+	int ret = 0;
+
+	if (netif_msg_drv(&debug))
+		dev_info(&spi->dev, DRV_NAME " Ethernet driver %s loaded\n",
+			DRV_VERSION);
+
+	dev = alloc_etherdev(sizeof(struct enc28j60_net));
+	if (!dev) {
+		if (netif_msg_drv(&debug))
+			dev_err(&spi->dev, DRV_NAME
+				": unable to alloc new ethernet\n");
+		ret = -ENOMEM;
+		goto error_alloc;
+	}
+	priv = netdev_priv(dev);
+
+	priv->netdev = dev;	/* priv to netdev reference */
+	priv->spi = spi;	/* priv to spi reference */
+	priv->msg_enable = netif_msg_init(debug.msg_enable,
+						ENC28J60_MSG_DEFAULT);
+	mutex_init(&priv->lock);
+	INIT_WORK(&priv->tx_work, enc28j60_tx_work_handler);
+	INIT_WORK(&priv->setrx_work, enc28j60_setrx_work_handler);
+	INIT_WORK(&priv->irq_work, enc28j60_irq_work_handler);
+	INIT_WORK(&priv->restart_work, enc28j60_restart_work_handler);
+	dev_set_drvdata(&spi->dev, priv);	/* spi to priv reference */
+	SET_NETDEV_DEV(dev, &spi->dev);
+
+	if (!enc28j60_chipset_init(dev)) {
+		if (netif_msg_probe(priv))
+			dev_info(&spi->dev, DRV_NAME " chip not found\n");
+		ret = -EIO;
+		goto error_irq;
+	}
+	random_ether_addr(dev->dev_addr);
+	enc28j60_set_hw_macaddr(dev);
+
+	ret = request_irq(spi->irq, enc28j60_irq, IRQF_TRIGGER_FALLING,
+			  DRV_NAME, priv);
+	if (ret < 0) {
+		if (netif_msg_probe(priv))
+			dev_err(&spi->dev, DRV_NAME ": request irq %d failed "
+				"(ret = %d)\n", spi->irq, ret);
+		goto error_irq;
+	}
+
+	dev->if_port = IF_PORT_10BASET;
+	dev->irq = spi->irq;
+	dev->open = enc28j60_net_open;
+	dev->stop = enc28j60_net_close;
+	dev->hard_start_xmit = enc28j60_send_packet;
+	dev->set_multicast_list = &enc28j60_set_multicast_list;
+	dev->set_mac_address = enc28j60_set_mac_address;
+	dev->tx_timeout = &enc28j60_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+	SET_ETHTOOL_OPS(dev, &enc28j60_ethtool_ops);
+
+	ret = register_netdev(dev);
+	if (ret) {
+		if (netif_msg_probe(priv))
+			dev_err(&spi->dev, "register netdev " DRV_NAME
+				" failed (ret = %d)\n", ret);
+		goto error_register;
+	}
+	dev_info(&dev->dev, DRV_NAME " driver registered\n");
+
+	return 0;
+
+error_register:
+	free_irq(spi->irq, priv);
+error_irq:
+	free_netdev(dev);
+error_alloc:
+	return ret;
+}
+
+static int enc28j60_remove(struct spi_device *spi)
+{
+	struct enc28j60_net *priv = dev_get_drvdata(&spi->dev);
+
+	if (netif_msg_drv(priv))
+		printk(KERN_DEBUG DRV_NAME ": remove\n");
+
+	unregister_netdev(priv->netdev);
+	free_irq(spi->irq, priv);
+	free_netdev(priv->netdev);
+
+	return 0;
+}
+
+static struct spi_driver enc28j60_driver = {
+	.driver = {
+		   .name = DRV_NAME,
+		   .bus = &spi_bus_type,
+		   .owner = THIS_MODULE,
+		   },
+	.probe = enc28j60_probe,
+	.remove = __devexit_p(enc28j60_remove),
+};
+
+static int __init enc28j60_init(void)
+{
+	return spi_register_driver(&enc28j60_driver);
+}
+
+module_init(enc28j60_init);
+
+static void __exit enc28j60_exit(void)
+{
+	spi_unregister_driver(&enc28j60_driver);
+}
+
+module_exit(enc28j60_exit);
+
+MODULE_DESCRIPTION(DRV_NAME " ethernet driver");
+MODULE_AUTHOR("Claudio Lanconelli <lanconelli.claudio@eptar.com>");
+MODULE_LICENSE("GPL");
+module_param_named(debug, debug.msg_enable, int, 0);
+MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., ffff=all)");
diff --git a/drivers/net/enc28j60_hw.h b/drivers/net/enc28j60_hw.h
new file mode 100644
index 000000000000..1a0b20969f80
--- /dev/null
+++ b/drivers/net/enc28j60_hw.h
@@ -0,0 +1,309 @@
+/*
+ * enc28j60_hw.h: EDTP FrameThrower style enc28j60 registers
+ *
+ * $Id: enc28j60_hw.h,v 1.9 2007/12/14 11:59:16 claudio Exp $
+ */
+
+#ifndef _ENC28J60_HW_H
+#define _ENC28J60_HW_H
+
+/*
+ * ENC28J60 Control Registers
+ * Control register definitions are a combination of address,
+ * bank number, and Ethernet/MAC/PHY indicator bits.
+ * - Register address	(bits 0-4)
+ * - Bank number	(bits 5-6)
+ * - MAC/MII indicator	(bit 7)
+ */
+#define ADDR_MASK	0x1F
+#define BANK_MASK	0x60
+#define SPRD_MASK	0x80
+/* All-bank registers */
+#define EIE		0x1B
+#define EIR		0x1C
+#define ESTAT		0x1D
+#define ECON2		0x1E
+#define ECON1		0x1F
+/* Bank 0 registers */
+#define ERDPTL		(0x00|0x00)
+#define ERDPTH		(0x01|0x00)
+#define EWRPTL		(0x02|0x00)
+#define EWRPTH		(0x03|0x00)
+#define ETXSTL		(0x04|0x00)
+#define ETXSTH		(0x05|0x00)
+#define ETXNDL		(0x06|0x00)
+#define ETXNDH		(0x07|0x00)
+#define ERXSTL		(0x08|0x00)
+#define ERXSTH		(0x09|0x00)
+#define ERXNDL		(0x0A|0x00)
+#define ERXNDH		(0x0B|0x00)
+#define ERXRDPTL	(0x0C|0x00)
+#define ERXRDPTH	(0x0D|0x00)
+#define ERXWRPTL	(0x0E|0x00)
+#define ERXWRPTH	(0x0F|0x00)
+#define EDMASTL		(0x10|0x00)
+#define EDMASTH		(0x11|0x00)
+#define EDMANDL		(0x12|0x00)
+#define EDMANDH		(0x13|0x00)
+#define EDMADSTL	(0x14|0x00)
+#define EDMADSTH	(0x15|0x00)
+#define EDMACSL		(0x16|0x00)
+#define EDMACSH		(0x17|0x00)
+/* Bank 1 registers */
+#define EHT0		(0x00|0x20)
+#define EHT1		(0x01|0x20)
+#define EHT2		(0x02|0x20)
+#define EHT3		(0x03|0x20)
+#define EHT4		(0x04|0x20)
+#define EHT5		(0x05|0x20)
+#define EHT6		(0x06|0x20)
+#define EHT7		(0x07|0x20)
+#define EPMM0		(0x08|0x20)
+#define EPMM1		(0x09|0x20)
+#define EPMM2		(0x0A|0x20)
+#define EPMM3		(0x0B|0x20)
+#define EPMM4		(0x0C|0x20)
+#define EPMM5		(0x0D|0x20)
+#define EPMM6		(0x0E|0x20)
+#define EPMM7		(0x0F|0x20)
+#define EPMCSL		(0x10|0x20)
+#define EPMCSH		(0x11|0x20)
+#define EPMOL		(0x14|0x20)
+#define EPMOH		(0x15|0x20)
+#define EWOLIE		(0x16|0x20)
+#define EWOLIR		(0x17|0x20)
+#define ERXFCON		(0x18|0x20)
+#define EPKTCNT		(0x19|0x20)
+/* Bank 2 registers */
+#define MACON1		(0x00|0x40|SPRD_MASK)
+/* #define MACON2	(0x01|0x40|SPRD_MASK) */
+#define MACON3		(0x02|0x40|SPRD_MASK)
+#define MACON4		(0x03|0x40|SPRD_MASK)
+#define MABBIPG		(0x04|0x40|SPRD_MASK)
+#define MAIPGL		(0x06|0x40|SPRD_MASK)
+#define MAIPGH		(0x07|0x40|SPRD_MASK)
+#define MACLCON1	(0x08|0x40|SPRD_MASK)
+#define MACLCON2	(0x09|0x40|SPRD_MASK)
+#define MAMXFLL		(0x0A|0x40|SPRD_MASK)
+#define MAMXFLH		(0x0B|0x40|SPRD_MASK)
+#define MAPHSUP		(0x0D|0x40|SPRD_MASK)
+#define MICON		(0x11|0x40|SPRD_MASK)
+#define MICMD		(0x12|0x40|SPRD_MASK)
+#define MIREGADR	(0x14|0x40|SPRD_MASK)
+#define MIWRL		(0x16|0x40|SPRD_MASK)
+#define MIWRH		(0x17|0x40|SPRD_MASK)
+#define MIRDL		(0x18|0x40|SPRD_MASK)
+#define MIRDH		(0x19|0x40|SPRD_MASK)
+/* Bank 3 registers */
+#define MAADR1		(0x00|0x60|SPRD_MASK)
+#define MAADR0		(0x01|0x60|SPRD_MASK)
+#define MAADR3		(0x02|0x60|SPRD_MASK)
+#define MAADR2		(0x03|0x60|SPRD_MASK)
+#define MAADR5		(0x04|0x60|SPRD_MASK)
+#define MAADR4		(0x05|0x60|SPRD_MASK)
+#define EBSTSD		(0x06|0x60)
+#define EBSTCON		(0x07|0x60)
+#define EBSTCSL		(0x08|0x60)
+#define EBSTCSH		(0x09|0x60)
+#define MISTAT		(0x0A|0x60|SPRD_MASK)
+#define EREVID		(0x12|0x60)
+#define ECOCON		(0x15|0x60)
+#define EFLOCON		(0x17|0x60)
+#define EPAUSL		(0x18|0x60)
+#define EPAUSH		(0x19|0x60)
+/* PHY registers */
+#define PHCON1		0x00
+#define PHSTAT1		0x01
+#define PHHID1		0x02
+#define PHHID2		0x03
+#define PHCON2		0x10
+#define PHSTAT2		0x11
+#define PHIE		0x12
+#define PHIR		0x13
+#define PHLCON		0x14
+
+/* ENC28J60 EIE Register Bit Definitions */
+#define EIE_INTIE	0x80
+#define EIE_PKTIE	0x40
+#define EIE_DMAIE	0x20
+#define EIE_LINKIE	0x10
+#define EIE_TXIE	0x08
+/* #define EIE_WOLIE	0x04 (reserved) */
+#define EIE_TXERIE	0x02
+#define EIE_RXERIE	0x01
+/* ENC28J60 EIR Register Bit Definitions */
+#define EIR_PKTIF	0x40
+#define EIR_DMAIF	0x20
+#define EIR_LINKIF	0x10
+#define EIR_TXIF	0x08
+/* #define EIR_WOLIF	0x04 (reserved) */
+#define EIR_TXERIF	0x02
+#define EIR_RXERIF	0x01
+/* ENC28J60 ESTAT Register Bit Definitions */
+#define ESTAT_INT	0x80
+#define ESTAT_LATECOL	0x10
+#define ESTAT_RXBUSY	0x04
+#define ESTAT_TXABRT	0x02
+#define ESTAT_CLKRDY	0x01
+/* ENC28J60 ECON2 Register Bit Definitions */
+#define ECON2_AUTOINC	0x80
+#define ECON2_PKTDEC	0x40
+#define ECON2_PWRSV	0x20
+#define ECON2_VRPS	0x08
+/* ENC28J60 ECON1 Register Bit Definitions */
+#define ECON1_TXRST	0x80
+#define ECON1_RXRST	0x40
+#define ECON1_DMAST	0x20
+#define ECON1_CSUMEN	0x10
+#define ECON1_TXRTS	0x08
+#define ECON1_RXEN	0x04
+#define ECON1_BSEL1	0x02
+#define ECON1_BSEL0	0x01
+/* ENC28J60 MACON1 Register Bit Definitions */
+#define MACON1_LOOPBK	0x10
+#define MACON1_TXPAUS	0x08
+#define MACON1_RXPAUS	0x04
+#define MACON1_PASSALL	0x02
+#define MACON1_MARXEN	0x01
+/* ENC28J60 MACON2 Register Bit Definitions */
+#define MACON2_MARST	0x80
+#define MACON2_RNDRST	0x40
+#define MACON2_MARXRST	0x08
+#define MACON2_RFUNRST	0x04
+#define MACON2_MATXRST	0x02
+#define MACON2_TFUNRST	0x01
+/* ENC28J60 MACON3 Register Bit Definitions */
+#define MACON3_PADCFG2	0x80
+#define MACON3_PADCFG1	0x40
+#define MACON3_PADCFG0	0x20
+#define MACON3_TXCRCEN	0x10
+#define MACON3_PHDRLEN	0x08
+#define MACON3_HFRMLEN	0x04
+#define MACON3_FRMLNEN	0x02
+#define MACON3_FULDPX	0x01
+/* ENC28J60 MICMD Register Bit Definitions */
+#define MICMD_MIISCAN	0x02
+#define MICMD_MIIRD	0x01
+/* ENC28J60 MISTAT Register Bit Definitions */
+#define MISTAT_NVALID	0x04
+#define MISTAT_SCAN	0x02
+#define MISTAT_BUSY	0x01
+/* ENC28J60 ERXFCON Register Bit Definitions */
+#define ERXFCON_UCEN	0x80
+#define ERXFCON_ANDOR	0x40
+#define ERXFCON_CRCEN	0x20
+#define ERXFCON_PMEN	0x10
+#define ERXFCON_MPEN	0x08
+#define ERXFCON_HTEN	0x04
+#define ERXFCON_MCEN	0x02
+#define ERXFCON_BCEN	0x01
+
+/* ENC28J60 PHY PHCON1 Register Bit Definitions */
+#define PHCON1_PRST	0x8000
+#define PHCON1_PLOOPBK	0x4000
+#define PHCON1_PPWRSV	0x0800
+#define PHCON1_PDPXMD	0x0100
+/* ENC28J60 PHY PHSTAT1 Register Bit Definitions */
+#define PHSTAT1_PFDPX	0x1000
+#define PHSTAT1_PHDPX	0x0800
+#define PHSTAT1_LLSTAT	0x0004
+#define PHSTAT1_JBSTAT	0x0002
+/* ENC28J60 PHY PHSTAT2 Register Bit Definitions */
+#define PHSTAT2_TXSTAT	(1 << 13)
+#define PHSTAT2_RXSTAT	(1 << 12)
+#define PHSTAT2_COLSTAT	(1 << 11)
+#define PHSTAT2_LSTAT	(1 << 10)
+#define PHSTAT2_DPXSTAT	(1 << 9)
+#define PHSTAT2_PLRITY	(1 << 5)
+/* ENC28J60 PHY PHCON2 Register Bit Definitions */
+#define PHCON2_FRCLINK	0x4000
+#define PHCON2_TXDIS	0x2000
+#define PHCON2_JABBER	0x0400
+#define PHCON2_HDLDIS	0x0100
+/* ENC28J60 PHY PHIE Register Bit Definitions */
+#define PHIE_PLNKIE	(1 << 4)
+#define PHIE_PGEIE	(1 << 1)
+/* ENC28J60 PHY PHIR Register Bit Definitions */
+#define PHIR_PLNKIF	(1 << 4)
+#define PHIR_PGEIF	(1 << 1)
+
+/* ENC28J60 Packet Control Byte Bit Definitions */
+#define PKTCTRL_PHUGEEN		0x08
+#define PKTCTRL_PPADEN		0x04
+#define PKTCTRL_PCRCEN		0x02
+#define PKTCTRL_POVERRIDE	0x01
+
+/* ENC28J60 Transmit Status Vector */
+#define TSV_TXBYTECNT		0
+#define TSV_TXCOLLISIONCNT	16
+#define TSV_TXCRCERROR		20
+#define TSV_TXLENCHKERROR	21
+#define TSV_TXLENOUTOFRANGE	22
+#define TSV_TXDONE		23
+#define TSV_TXMULTICAST		24
+#define TSV_TXBROADCAST		25
+#define TSV_TXPACKETDEFER	26
+#define TSV_TXEXDEFER		27
+#define TSV_TXEXCOLLISION	28
+#define TSV_TXLATECOLLISION	29
+#define TSV_TXGIANT		30
+#define TSV_TXUNDERRUN		31
+#define TSV_TOTBYTETXONWIRE	32
+#define TSV_TXCONTROLFRAME	48
+#define TSV_TXPAUSEFRAME	49
+#define TSV_BACKPRESSUREAPP	50
+#define TSV_TXVLANTAGFRAME	51
+
+#define TSV_SIZE		7
+#define TSV_BYTEOF(x)		((x) / 8)
+#define TSV_BITMASK(x)		(1 << ((x) % 8))
+#define TSV_GETBIT(x, y)	(((x)[TSV_BYTEOF(y)] & TSV_BITMASK(y)) ? 1 : 0)
+
+/* ENC28J60 Receive Status Vector */
+#define RSV_RXLONGEVDROPEV	16
+#define RSV_CARRIEREV		18
+#define RSV_CRCERROR		20
+#define RSV_LENCHECKERR		21
+#define RSV_LENOUTOFRANGE	22
+#define RSV_RXOK		23
+#define RSV_RXMULTICAST		24
+#define RSV_RXBROADCAST		25
+#define RSV_DRIBBLENIBBLE	26
+#define RSV_RXCONTROLFRAME	27
+#define RSV_RXPAUSEFRAME	28
+#define RSV_RXUNKNOWNOPCODE	29
+#define RSV_RXTYPEVLAN		30
+
+#define RSV_SIZE		6
+#define RSV_BITMASK(x)		(1 << ((x) - 16))
+#define RSV_GETBIT(x, y)	(((x) & RSV_BITMASK(y)) ? 1 : 0)
+
+
+/* SPI operation codes */
+#define ENC28J60_READ_CTRL_REG	0x00
+#define ENC28J60_READ_BUF_MEM	0x3A
+#define ENC28J60_WRITE_CTRL_REG 0x40
+#define ENC28J60_WRITE_BUF_MEM	0x7A
+#define ENC28J60_BIT_FIELD_SET	0x80
+#define ENC28J60_BIT_FIELD_CLR	0xA0
+#define ENC28J60_SOFT_RESET	0xFF
+
+
+/* buffer boundaries applied to internal 8K ram
+ * entire available packet buffer space is allocated.
+ * Give TX buffer space for one full ethernet frame (~1500 bytes)
+ * receive buffer gets the rest */
+#define TXSTART_INIT		0x1A00
+#define TXEND_INIT		0x1FFF
+
+/* Put RX buffer at 0 as suggested by the Errata datasheet */
+#define RXSTART_INIT		0x0000
+#define RXEND_INIT		0x19FF
+
+/* maximum ethernet frame length */
+#define MAX_FRAMELEN		1518
+
+/* Prefered half duplex: LEDA: Link status LEDB: Rx/Tx activity */
+#define ENC28J60_LAMPS_MODE	0x3476
+
+#endif
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index f84c752997a4..7667a62ac31f 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -712,8 +712,8 @@ static const struct nv_ethtool_str nv_etests_str[] = {
 };
 
 struct register_test {
-	__le32 reg;
-	__le32 mask;
+	__u32 reg;
+	__u32 mask;
 };
 
 static const struct register_test nv_registers_test[] = {
@@ -929,6 +929,16 @@ static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
 #define NV_SETUP_RX_RING 0x01
 #define NV_SETUP_TX_RING 0x02
 
+static inline u32 dma_low(dma_addr_t addr)
+{
+	return addr;
+}
+
+static inline u32 dma_high(dma_addr_t addr)
+{
+	return addr>>31>>1;	/* 0 if 32bit, shift down by 32 if 64bit */
+}
+
 static void setup_hw_rings(struct net_device *dev, int rxtx_flags)
 {
 	struct fe_priv *np = get_nvpriv(dev);
@@ -936,19 +946,19 @@ static void setup_hw_rings(struct net_device *dev, int rxtx_flags)
 
 	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
 		if (rxtx_flags & NV_SETUP_RX_RING) {
-			writel((u32) cpu_to_le64(np->ring_addr), base + NvRegRxRingPhysAddr);
+			writel(dma_low(np->ring_addr), base + NvRegRxRingPhysAddr);
 		}
 		if (rxtx_flags & NV_SETUP_TX_RING) {
-			writel((u32) cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
+			writel(dma_low(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr);
 		}
 	} else {
 		if (rxtx_flags & NV_SETUP_RX_RING) {
-			writel((u32) cpu_to_le64(np->ring_addr), base + NvRegRxRingPhysAddr);
-			writel((u32) (cpu_to_le64(np->ring_addr) >> 32), base + NvRegRxRingPhysAddrHigh);
+			writel(dma_low(np->ring_addr), base + NvRegRxRingPhysAddr);
+			writel(dma_high(np->ring_addr), base + NvRegRxRingPhysAddrHigh);
 		}
 		if (rxtx_flags & NV_SETUP_TX_RING) {
-			writel((u32) cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
-			writel((u32) (cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)) >> 32), base + NvRegTxRingPhysAddrHigh);
+			writel(dma_low(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr);
+			writel(dma_high(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddrHigh);
 		}
 	}
 }
@@ -1571,8 +1581,8 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
 							     skb_tailroom(skb),
 							     PCI_DMA_FROMDEVICE);
 			np->put_rx_ctx->dma_len = skb_tailroom(skb);
-			np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32;
-			np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF;
+			np->put_rx.ex->bufhigh = cpu_to_le32(dma_high(np->put_rx_ctx->dma));
+			np->put_rx.ex->buflow = cpu_to_le32(dma_low(np->put_rx_ctx->dma));
 			wmb();
 			np->put_rx.ex->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
 			if (unlikely(np->put_rx.ex++ == np->last_rx.ex))
@@ -1937,8 +1947,8 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
 		np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
 						PCI_DMA_TODEVICE);
 		np->put_tx_ctx->dma_len = bcnt;
-		put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
-		put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+		put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma));
+		put_tx->buflow = cpu_to_le32(dma_low(np->put_tx_ctx->dma));
 		put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
 
 		tx_flags = NV_TX2_VALID;
@@ -1963,8 +1973,8 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
 			np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
 							   PCI_DMA_TODEVICE);
 			np->put_tx_ctx->dma_len = bcnt;
-			put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
-			put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+			put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma));
+			put_tx->buflow = cpu_to_le32(dma_low(np->put_tx_ctx->dma));
 			put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
 
 			offset += bcnt;
@@ -2680,8 +2690,8 @@ static void nv_set_multicast(struct net_device *dev)
 				walk = dev->mc_list;
 				while (walk != NULL) {
 					u32 a, b;
-					a = le32_to_cpu(*(u32 *) walk->dmi_addr);
-					b = le16_to_cpu(*(u16 *) (&walk->dmi_addr[4]));
+					a = le32_to_cpu(*(__le32 *) walk->dmi_addr);
+					b = le16_to_cpu(*(__le16 *) (&walk->dmi_addr[4]));
 					alwaysOn[0] &= a;
 					alwaysOff[0] &= ~a;
 					alwaysOn[1] &= b;
@@ -4539,8 +4549,8 @@ static int nv_loopback_test(struct net_device *dev)
 		np->tx_ring.orig[0].buf = cpu_to_le32(test_dma_addr);
 		np->tx_ring.orig[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
 	} else {
-		np->tx_ring.ex[0].bufhigh = cpu_to_le64(test_dma_addr) >> 32;
-		np->tx_ring.ex[0].buflow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
+		np->tx_ring.ex[0].bufhigh = cpu_to_le32(dma_high(test_dma_addr));
+		np->tx_ring.ex[0].buflow = cpu_to_le32(dma_low(test_dma_addr));
 		np->tx_ring.ex[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
 	}
 	writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c
index aec9ab17a9a5..230878b94190 100644
--- a/drivers/net/gianfar_sysfs.c
+++ b/drivers/net/gianfar_sysfs.c
@@ -37,24 +37,6 @@
 
 #include "gianfar.h"
 
-#define GFAR_ATTR(_name) \
-static ssize_t gfar_show_##_name(struct device *dev, \
-	 struct device_attribute *attr, char *buf); \
-static ssize_t gfar_set_##_name(struct device *dev, \
-		struct device_attribute *attr, \
-		const char *buf, size_t count); \
-static DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name)
-
-#define GFAR_CREATE_FILE(_dev, _name) \
-	device_create_file(&_dev->dev, &dev_attr_##_name)
-
-GFAR_ATTR(bd_stash);
-GFAR_ATTR(rx_stash_size);
-GFAR_ATTR(rx_stash_index);
-GFAR_ATTR(fifo_threshold);
-GFAR_ATTR(fifo_starve);
-GFAR_ATTR(fifo_starve_off);
-
 static ssize_t gfar_show_bd_stash(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
@@ -100,6 +82,8 @@ static ssize_t gfar_set_bd_stash(struct device *dev,
 	return count;
 }
 
+DEVICE_ATTR(bd_stash, 0644, gfar_show_bd_stash, gfar_set_bd_stash);
+
 static ssize_t gfar_show_rx_stash_size(struct device *dev,
 				       struct device_attribute *attr, char *buf)
 {
@@ -146,6 +130,9 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev,
 	return count;
 }
 
+DEVICE_ATTR(rx_stash_size, 0644, gfar_show_rx_stash_size,
+	    gfar_set_rx_stash_size);
+
 /* Stashing will only be enabled when rx_stash_size != 0 */
 static ssize_t gfar_show_rx_stash_index(struct device *dev,
 					struct device_attribute *attr,
@@ -184,6 +171,9 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev,
 	return count;
 }
 
+DEVICE_ATTR(rx_stash_index, 0644, gfar_show_rx_stash_index,
+	    gfar_set_rx_stash_index);
+
 static ssize_t gfar_show_fifo_threshold(struct device *dev,
 					struct device_attribute *attr,
 					char *buf)
@@ -219,6 +209,9 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev,
 	return count;
 }
 
+DEVICE_ATTR(fifo_threshold, 0644, gfar_show_fifo_threshold,
+	    gfar_set_fifo_threshold);
+
 static ssize_t gfar_show_fifo_starve(struct device *dev,
 				     struct device_attribute *attr, char *buf)
 {
@@ -253,6 +246,8 @@ static ssize_t gfar_set_fifo_starve(struct device *dev,
 	return count;
 }
 
+DEVICE_ATTR(fifo_starve, 0644, gfar_show_fifo_starve, gfar_set_fifo_starve);
+
 static ssize_t gfar_show_fifo_starve_off(struct device *dev,
 					 struct device_attribute *attr,
 					 char *buf)
@@ -288,9 +283,13 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev,
 	return count;
 }
 
+DEVICE_ATTR(fifo_starve_off, 0644, gfar_show_fifo_starve_off,
+	    gfar_set_fifo_starve_off);
+
 void gfar_init_sysfs(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+	int rc;
 
 	/* Initialize the default values */
 	priv->rx_stash_size = DEFAULT_STASH_LENGTH;
@@ -301,11 +300,12 @@ void gfar_init_sysfs(struct net_device *dev)
 	priv->bd_stash_en = DEFAULT_BD_STASH;
 
 	/* Create our sysfs files */
-	GFAR_CREATE_FILE(dev, bd_stash);
-	GFAR_CREATE_FILE(dev, rx_stash_size);
-	GFAR_CREATE_FILE(dev, rx_stash_index);
-	GFAR_CREATE_FILE(dev, fifo_threshold);
-	GFAR_CREATE_FILE(dev, fifo_starve);
-	GFAR_CREATE_FILE(dev, fifo_starve_off);
-
+	rc = device_create_file(&dev->dev, &dev_attr_bd_stash);
+	rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_size);
+	rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_index);
+	rc |= device_create_file(&dev->dev, &dev_attr_fifo_threshold);
+	rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve);
+	rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve_off);
+	if (rc)
+		dev_err(&dev->dev, "Error creating gianfar sysfs files.\n");
 }
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 580cb4ab2af1..0a9b75139e0f 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -701,7 +701,7 @@ static void sixpack_close(struct tty_struct *tty)
 	sp = tty->disc_data;
 	tty->disc_data = NULL;
 	write_unlock(&disc_data_lock);
-	if (sp == 0)
+	if (!sp)
 		return;
 
 	/*
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 803a3bdea0af..cfcd15af501e 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -821,7 +821,7 @@ static void mkiss_close(struct tty_struct *tty)
 	tty->disc_data = NULL;
 	write_unlock(&disc_data_lock);
 
-	if (ax == 0)
+	if (!ax)
 		return;
 
 	/*
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 353d13e543ce..f90515935833 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -201,7 +201,6 @@ static void z8530_init(void);
 
 static void init_channel(struct scc_channel *scc);
 static void scc_key_trx (struct scc_channel *scc, char tx);
-static irqreturn_t scc_isr(int irq, void *dev_id);
 static void scc_init_timer(struct scc_channel *scc);
 
 static int scc_net_alloc(const char *name, struct scc_channel *scc);
@@ -629,6 +628,7 @@ static void scc_isr_dispatch(struct scc_channel *scc, int vector)
 
 static irqreturn_t scc_isr(int irq, void *dev_id)
 {
+	int chip_irq = (long) dev_id;
 	unsigned char vector;	
 	struct scc_channel *scc;
 	struct scc_ctrl *ctrl;
@@ -665,7 +665,7 @@ static irqreturn_t scc_isr(int irq, void *dev_id)
 	ctrl = SCC_ctrl;
 	while (ctrl->chan_A)
 	{
-		if (ctrl->irq != irq)
+		if (ctrl->irq != chip_irq)
 		{
 			ctrl++;
 			continue;
@@ -1732,7 +1732,9 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 				
 			if (!Ivec[hwcfg.irq].used && hwcfg.irq)
 			{
-				if (request_irq(hwcfg.irq, scc_isr, IRQF_DISABLED, "AX.25 SCC", NULL))
+				if (request_irq(hwcfg.irq, scc_isr,
+						IRQF_DISABLED, "AX.25 SCC",
+						(void *)(long) hwcfg.irq))
 					printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq);
 				else
 					Ivec[hwcfg.irq].used = 1;
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 49421d1cd3a5..571dd80fb850 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1153,7 +1153,7 @@ static void hp100_init_pdls(struct net_device *dev)
 	printk("hp100: %s: init pdls\n", dev->name);
 #endif
 
-	if (0 == lp->page_vaddr_algn)
+	if (!lp->page_vaddr_algn)
 		printk("hp100: %s: Warning: lp->page_vaddr_algn not initialised!\n", dev->name);
 	else {
 		/* pageptr shall point into the DMA accessible memory region  */
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index fced441face6..e6c69f77259b 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -1298,7 +1298,6 @@ static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	return emac_xmit_finish(dev, len);
 }
 
-#ifdef CONFIG_IBM_NEW_EMAC_TAH
 static inline int emac_xmit_split(struct emac_instance *dev, int slot,
 				  u32 pd, int len, int last, u16 base_ctrl)
 {
@@ -1411,9 +1410,6 @@ static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
 	DBG2(dev, "stopped TX queue" NL);
 	return 1;
 }
-#else
-# define emac_start_xmit_sg	emac_start_xmit
-#endif	/* !defined(CONFIG_IBM_NEW_EMAC_TAH) */
 
 /* Tx lock BHs */
 static void emac_parse_tx_error(struct emac_instance *dev, u16 ctrl)
@@ -2684,13 +2680,8 @@ static int __devinit emac_probe(struct of_device *ofdev,
 
 	/* Fill in the driver function table */
 	ndev->open = &emac_open;
-#ifdef CONFIG_IBM_NEW_EMAC_TAH
-	if (dev->tah_dev) {
-		ndev->hard_start_xmit = &emac_start_xmit_sg;
+	if (dev->tah_dev)
 		ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
-	} else
-#endif
-		ndev->hard_start_xmit = &emac_start_xmit;
 	ndev->tx_timeout = &emac_tx_timeout;
 	ndev->watchdog_timeo = 5 * HZ;
 	ndev->stop = &emac_close;
@@ -2698,8 +2689,11 @@ static int __devinit emac_probe(struct of_device *ofdev,
 	ndev->set_multicast_list = &emac_set_multicast_list;
 	ndev->do_ioctl = &emac_ioctl;
 	if (emac_phy_supports_gige(dev->phy_mode)) {
+		ndev->hard_start_xmit = &emac_start_xmit_sg;
 		ndev->change_mtu = &emac_change_mtu;
 		dev->commac.ops = &emac_commac_sg_ops;
+	} else {
+		ndev->hard_start_xmit = &emac_start_xmit;
 	}
 	SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
 
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 91d83aca6bc7..46e2c52c7862 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -83,7 +83,7 @@ History:
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/time.h>
-#include <linux/mca-legacy.h>
+#include <linux/mca.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -161,13 +161,13 @@ static void PrTime(void)
 
 /* deduce resources out of POS registers */
 
-static void getaddrs(int slot, int *base, int *memlen, int *iobase,
-		     int *irq, ibmlana_medium * medium)
+static void getaddrs(struct mca_device *mdev, int *base, int *memlen,
+		     int *iobase, int *irq, ibmlana_medium *medium)
 {
 	u_char pos0, pos1;
 
-	pos0 = mca_read_stored_pos(slot, 2);
-	pos1 = mca_read_stored_pos(slot, 3);
+	pos0 = mca_device_read_stored_pos(mdev, 2);
+	pos1 = mca_device_read_stored_pos(mdev, 3);
 
 	*base = 0xc0000 + ((pos1 & 0xf0) << 9);
 	*memlen = (pos1 & 0x01) ? 0x8000 : 0x4000;
@@ -704,9 +704,9 @@ static void irqtxerr_handler(struct net_device *dev)
 
 /* general interrupt entry */
 
-static irqreturn_t irq_handler(int irq, void *device)
+static irqreturn_t irq_handler(int dummy, void *device)
 {
-	struct net_device *dev = (struct net_device *) device;
+	struct net_device *dev = device;
 	u16 ival;
 
 	/* in case we're not meant... */
@@ -744,6 +744,7 @@ static irqreturn_t irq_handler(int irq, void *device)
 
 /* MCA info */
 
+#if 0 /* info available elsewhere, but this is kept for reference */
 static int ibmlana_getinfo(char *buf, int slot, void *d)
 {
 	int len = 0, i;
@@ -771,6 +772,7 @@ static int ibmlana_getinfo(char *buf, int slot, void *d)
 
 	return len;
 }
+#endif
 
 /* open driver.  Means also initialization and start of LANCE */
 
@@ -890,42 +892,52 @@ static void ibmlana_set_multicast_list(struct net_device *dev)
  * hardware check
  * ------------------------------------------------------------------------ */
 
+static int ibmlana_irq;
+static int ibmlana_io;
 static int startslot;		/* counts through slots when probing multiple devices */
 
-static int ibmlana_probe(struct net_device *dev)
+static short ibmlana_adapter_ids[] __initdata = {
+	IBM_LANA_ID,
+	0x0000
+};
+
+static char *ibmlana_adapter_names[] __initdata = {
+	"IBM LAN Adapter/A",
+	NULL
+};
+
+static int ibmlana_init_one(struct device *kdev)
 {
-	int slot, z;
+	struct mca_device *mdev = to_mca_device(kdev);
+	struct net_device *dev;
+	int slot = mdev->slot, z, rc;
 	int base = 0, irq = 0, iobase = 0, memlen = 0;
 	ibmlana_priv *priv;
 	ibmlana_medium medium;
 	DECLARE_MAC_BUF(mac);
 
-	/* can't work without an MCA bus ;-) */
-	if (MCA_bus == 0)
-		return -ENODEV;
+	dev = alloc_etherdev(sizeof(ibmlana_priv));
+	if (!dev)
+		return -ENOMEM;
+
+	dev->irq = ibmlana_irq;
+	dev->base_addr = ibmlana_io;
 
 	base = dev->mem_start;
 	irq = dev->irq;
 
-	for (slot = startslot; (slot = mca_find_adapter(IBM_LANA_ID, slot)) != -1; slot++) {
-		/* deduce card addresses */
-		getaddrs(slot, &base, &memlen, &iobase, &irq, &medium);
-
-		/* slot already in use ? */
-		if (mca_is_adapter_used(slot))
-			continue;
-		/* were we looking for something different ? */
-		if (dev->irq && dev->irq != irq)
-			continue;
-		if (dev->mem_start && dev->mem_start != base)
-			continue;
-		/* found something that matches */
-		break;
-	}
+	/* deduce card addresses */
+	getaddrs(mdev, &base, &memlen, &iobase, &irq, &medium);
 
-	/* nothing found ? */
-	if (slot == -1)
-		return (base != 0 || irq != 0) ? -ENXIO : -ENODEV;
+	/* were we looking for something different ? */
+	if (dev->irq && dev->irq != irq) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+	if (dev->mem_start && dev->mem_start != base) {
+		rc = -ENODEV;
+		goto err_out;
+	}
 
 	/* announce success */
 	printk(KERN_INFO "%s: IBM LAN Adapter/A found in slot %d\n", dev->name, slot + 1);
@@ -934,16 +946,16 @@ static int ibmlana_probe(struct net_device *dev)
 	if (!request_region(iobase, IBM_LANA_IORANGE, DRV_NAME)) {
 		printk(KERN_ERR "%s: cannot allocate I/O range at %#x!\n", DRV_NAME, iobase);
 		startslot = slot + 1;
-		return -EBUSY;
+		rc = -EBUSY;
+		goto err_out;
 	}
 
 	priv = netdev_priv(dev);
 	priv->slot = slot;
-	priv->realirq = irq;
+	priv->realirq = mca_device_transform_irq(mdev, irq);
 	priv->medium = medium;
 	spin_lock_init(&priv->lock);
 
-
 	/* set base + irq for this device (irq not allocated so far) */
 
 	dev->irq = 0;
@@ -955,22 +967,18 @@ static int ibmlana_probe(struct net_device *dev)
 	if (!priv->base) {
 		printk(KERN_ERR "%s: cannot remap memory!\n", DRV_NAME);
 		startslot = slot + 1;
-		release_region(iobase, IBM_LANA_IORANGE);
-		return -EBUSY;
+		rc = -EBUSY;
+		goto err_out_reg;
 	}
 
-	/* make procfs entries */
-	mca_set_adapter_name(slot, "IBM LAN Adapter/A");
-	mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmlana_getinfo, dev);
-
-	mca_mark_as_used(slot);
+	mca_device_set_name(mdev, ibmlana_adapter_names[mdev->index]);
+	mca_device_set_claim(mdev, 1);
 
 	/* set methods */
 
 	dev->open = ibmlana_open;
 	dev->stop = ibmlana_close;
 	dev->hard_start_xmit = ibmlana_tx;
-	dev->do_ioctl = NULL;
 	dev->set_multicast_list = ibmlana_set_multicast_list;
 	dev->flags |= IFF_MULTICAST;
 
@@ -996,6 +1004,35 @@ static int ibmlana_probe(struct net_device *dev)
 
 	startslot = slot + 1;
 
+	rc = register_netdev(dev);
+	if (rc)
+		goto err_out_claimed;
+
+	dev_set_drvdata(kdev, dev);
+	return 0;
+
+err_out_claimed:
+	mca_device_set_claim(mdev, 0);
+	iounmap(priv->base);
+err_out_reg:
+	release_region(iobase, IBM_LANA_IORANGE);
+err_out:
+	free_netdev(dev);
+	return rc;
+}
+
+static int ibmlana_remove_one(struct device *kdev)
+{
+	struct mca_device *mdev = to_mca_device(kdev);
+	struct net_device *dev = dev_get_drvdata(kdev);
+	ibmlana_priv *priv = netdev_priv(dev);
+
+	unregister_netdev(dev);
+	/*DeinitBoard(dev); */
+	release_region(dev->base_addr, IBM_LANA_IORANGE);
+	mca_device_set_claim(mdev, 0);
+	iounmap(priv->base);
+	free_netdev(dev);
 	return 0;
 }
 
@@ -1003,66 +1040,31 @@ static int ibmlana_probe(struct net_device *dev)
  * modularization support
  * ------------------------------------------------------------------------ */
 
-#ifdef MODULE
-
-#define DEVMAX 5
-
-static struct net_device *moddevs[DEVMAX];
-static int irq;
-static int io;
-
-module_param(irq, int, 0);
-module_param(io, int, 0);
+module_param_named(irq, ibmlana_irq, int, 0);
+module_param_named(io, ibmlana_io, int, 0);
 MODULE_PARM_DESC(irq, "IBM LAN/A IRQ number");
 MODULE_PARM_DESC(io, "IBM LAN/A I/O base address");
 MODULE_LICENSE("GPL");
 
-int init_module(void)
-{
-	int z;
+static struct mca_driver ibmlana_driver = {
+	.id_table = ibmlana_adapter_ids,
+	.driver = {
+		.name	= "ibmlana",
+		.bus	= &mca_bus_type,
+		.probe	= ibmlana_init_one,
+		.remove	= ibmlana_remove_one,
+	},
+};
 
-	startslot = 0;
-	for (z = 0; z < DEVMAX; z++) {
-		struct net_device *dev = alloc_etherdev(sizeof(ibmlana_priv));
-		if (!dev)
-			break;
-		dev->irq = irq;
-		dev->base_addr = io;
-		if (ibmlana_probe(dev)) {
-			free_netdev(dev);
-			break;
-		}
-		if (register_netdev(dev)) {
-			ibmlana_priv *priv = netdev_priv(dev);
-			release_region(dev->base_addr, IBM_LANA_IORANGE);
-			mca_mark_as_unused(priv->slot);
-			mca_set_adapter_name(priv->slot, "");
-			mca_set_adapter_procfn(priv->slot, NULL, NULL);
-			iounmap(priv->base);
-			free_netdev(dev);
-			break;
-		}
-		moddevs[z] = dev;
-	}
-	return (z > 0) ? 0 : -EIO;
+static int __init ibmlana_init_module(void)
+{
+	return mca_register_driver(&ibmlana_driver);
 }
 
-void cleanup_module(void)
+static void __exit ibmlana_cleanup_module(void)
 {
-	int z;
-	for (z = 0; z < DEVMAX; z++) {
-		struct net_device *dev = moddevs[z];
-		if (dev) {
-			ibmlana_priv *priv = netdev_priv(dev);
-			unregister_netdev(dev);
-			/*DeinitBoard(dev); */
-			release_region(dev->base_addr, IBM_LANA_IORANGE);
-			mca_mark_as_unused(priv->slot);
-			mca_set_adapter_name(priv->slot, "");
-			mca_set_adapter_procfn(priv->slot, NULL, NULL);
-			iounmap(priv->base);
-			free_netdev(dev);
-		}
-	}
+	mca_unregister_driver(&ibmlana_driver);
 }
-#endif				/* MODULE */
+
+module_init(ibmlana_init_module);
+module_exit(ibmlana_cleanup_module);
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 7d7758f3ad8c..57772bebff56 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -1179,13 +1179,15 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
 
 	for(i = 0; i<IbmVethNumBufferPools; i++) {
 		struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
+		int error;
+
 		ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i,
 					 pool_count[i], pool_size[i],
 					 pool_active[i]);
-		kobj->parent = &dev->dev.kobj;
-		kobject_set_name(kobj, "pool%d", i);
-		kobj->ktype = &ktype_veth_pool;
-		kobject_register(kobj);
+		error = kobject_init_and_add(kobj, &ktype_veth_pool,
+					     &dev->dev.kobj, "pool%d", i);
+		if (!error)
+			kobject_uevent(kobj, KOBJ_ADD);
 	}
 
 	ibmveth_debug_printk("adapter @ 0x%p\n", adapter);
@@ -1234,7 +1236,7 @@ static int __devexit ibmveth_remove(struct vio_dev *dev)
 	int i;
 
 	for(i = 0; i<IbmVethNumBufferPools; i++)
-		kobject_unregister(&adapter->rx_buff_pool[i].kobj);
+		kobject_put(&adapter->rx_buff_pool[i].kobj);
 
 	unregister_netdev(netdev);
 
diff --git a/drivers/net/igb/Makefile b/drivers/net/igb/Makefile
new file mode 100644
index 000000000000..1927b3fd6f05
--- /dev/null
+++ b/drivers/net/igb/Makefile
@@ -0,0 +1,37 @@
+################################################################################
+#
+# Intel 82575 PCI-Express Ethernet Linux driver
+# Copyright(c) 1999 - 2007 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope 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.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) 82575 PCI-Express ethernet driver
+#
+
+obj-$(CONFIG_IGB) += igb.o
+
+igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
+	    e1000_mac.o e1000_nvm.o e1000_phy.o
+
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
new file mode 100644
index 000000000000..cda3ec879090
--- /dev/null
+++ b/drivers/net/igb/e1000_82575.c
@@ -0,0 +1,1269 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_82575
+ * e1000_82576
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include "e1000_mac.h"
+#include "e1000_82575.h"
+
+static s32  igb_get_invariants_82575(struct e1000_hw *);
+static s32  igb_acquire_phy_82575(struct e1000_hw *);
+static void igb_release_phy_82575(struct e1000_hw *);
+static s32  igb_acquire_nvm_82575(struct e1000_hw *);
+static void igb_release_nvm_82575(struct e1000_hw *);
+static s32  igb_check_for_link_82575(struct e1000_hw *);
+static s32  igb_get_cfg_done_82575(struct e1000_hw *);
+static s32  igb_init_hw_82575(struct e1000_hw *);
+static s32  igb_phy_hw_reset_sgmii_82575(struct e1000_hw *);
+static s32  igb_read_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16 *);
+static void igb_rar_set_82575(struct e1000_hw *, u8 *, u32);
+static s32  igb_reset_hw_82575(struct e1000_hw *);
+static s32  igb_set_d0_lplu_state_82575(struct e1000_hw *, bool);
+static s32  igb_setup_copper_link_82575(struct e1000_hw *);
+static s32  igb_setup_fiber_serdes_link_82575(struct e1000_hw *);
+static s32  igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16);
+static void igb_clear_hw_cntrs_82575(struct e1000_hw *);
+static s32  igb_acquire_swfw_sync_82575(struct e1000_hw *, u16);
+static s32  igb_configure_pcs_link_82575(struct e1000_hw *);
+static s32  igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *, u16 *,
+						 u16 *);
+static s32  igb_get_phy_id_82575(struct e1000_hw *);
+static void igb_release_swfw_sync_82575(struct e1000_hw *, u16);
+static bool igb_sgmii_active_82575(struct e1000_hw *);
+static s32  igb_reset_init_script_82575(struct e1000_hw *);
+static s32  igb_read_mac_addr_82575(struct e1000_hw *);
+
+
+struct e1000_dev_spec_82575 {
+	bool sgmii_active;
+};
+
+static s32 igb_get_invariants_82575(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_dev_spec_82575 *dev_spec;
+	u32 eecd;
+	s32 ret_val;
+	u16 size;
+	u32 ctrl_ext = 0;
+
+	switch (hw->device_id) {
+	case E1000_DEV_ID_82575EB_COPPER:
+	case E1000_DEV_ID_82575EB_FIBER_SERDES:
+	case E1000_DEV_ID_82575GB_QUAD_COPPER:
+		mac->type = e1000_82575;
+		break;
+	default:
+		return -E1000_ERR_MAC_INIT;
+		break;
+	}
+
+	/* MAC initialization */
+	hw->dev_spec_size = sizeof(struct e1000_dev_spec_82575);
+
+	/* Device-specific structure allocation */
+	hw->dev_spec = kzalloc(hw->dev_spec_size, GFP_KERNEL);
+
+	if (!hw->dev_spec)
+		return -ENOMEM;
+
+	dev_spec = (struct e1000_dev_spec_82575 *)hw->dev_spec;
+
+	/* Set media type */
+	/*
+	 * The 82575 uses bits 22:23 for link mode. The mode can be changed
+	 * based on the EEPROM. We cannot rely upon device ID. There
+	 * is no distinguishable difference between fiber and internal
+	 * SerDes mode on the 82575. There can be an external PHY attached
+	 * on the SGMII interface. For this, we'll set sgmii_active to true.
+	 */
+	phy->media_type = e1000_media_type_copper;
+	dev_spec->sgmii_active = false;
+
+	ctrl_ext = rd32(E1000_CTRL_EXT);
+	if ((ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) ==
+	    E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES) {
+		hw->phy.media_type = e1000_media_type_internal_serdes;
+		ctrl_ext |= E1000_CTRL_I2C_ENA;
+	} else if (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII) {
+		dev_spec->sgmii_active = true;
+		ctrl_ext |= E1000_CTRL_I2C_ENA;
+	} else {
+		ctrl_ext &= ~E1000_CTRL_I2C_ENA;
+	}
+	wr32(E1000_CTRL_EXT, ctrl_ext);
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
+	/* Set if part includes ASF firmware */
+	mac->asf_firmware_present = true;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid =
+		(rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK)
+			? true : false;
+
+	/* physical interface link setup */
+	mac->ops.setup_physical_interface =
+		(hw->phy.media_type == e1000_media_type_copper)
+			? igb_setup_copper_link_82575
+			: igb_setup_fiber_serdes_link_82575;
+
+	/* NVM initialization */
+	eecd = rd32(E1000_EECD);
+
+	nvm->opcode_bits        = 8;
+	nvm->delay_usec         = 1;
+	switch (nvm->override) {
+	case e1000_nvm_override_spi_large:
+		nvm->page_size    = 32;
+		nvm->address_bits = 16;
+		break;
+	case e1000_nvm_override_spi_small:
+		nvm->page_size    = 8;
+		nvm->address_bits = 8;
+		break;
+	default:
+		nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+		break;
+	}
+
+	nvm->type = e1000_nvm_eeprom_spi;
+
+	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+		     E1000_EECD_SIZE_EX_SHIFT);
+
+	/*
+	 * Added to a constant, "size" becomes the left-shift value
+	 * for setting word_size.
+	 */
+	size += NVM_WORD_SIZE_BASE_SHIFT;
+	nvm->word_size = 1 << size;
+
+	/* setup PHY parameters */
+	if (phy->media_type != e1000_media_type_copper) {
+		phy->type = e1000_phy_none;
+		return 0;
+	}
+
+	phy->autoneg_mask        = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us      = 100;
+
+	/* PHY function pointers */
+	if (igb_sgmii_active_82575(hw)) {
+		phy->ops.reset_phy          = igb_phy_hw_reset_sgmii_82575;
+		phy->ops.read_phy_reg       = igb_read_phy_reg_sgmii_82575;
+		phy->ops.write_phy_reg      = igb_write_phy_reg_sgmii_82575;
+	} else {
+		phy->ops.reset_phy          = igb_phy_hw_reset;
+		phy->ops.read_phy_reg       = igb_read_phy_reg_igp;
+		phy->ops.write_phy_reg      = igb_write_phy_reg_igp;
+	}
+
+	/* Set phy->phy_addr and phy->id. */
+	ret_val = igb_get_phy_id_82575(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Verify phy id and set remaining function pointers */
+	switch (phy->id) {
+	case M88E1111_I_PHY_ID:
+		phy->type                   = e1000_phy_m88;
+		phy->ops.get_phy_info       = igb_get_phy_info_m88;
+		phy->ops.get_cable_length   = igb_get_cable_length_m88;
+		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
+		break;
+	case IGP03E1000_E_PHY_ID:
+		phy->type                   = e1000_phy_igp_3;
+		phy->ops.get_phy_info       = igb_get_phy_info_igp;
+		phy->ops.get_cable_length   = igb_get_cable_length_igp_2;
+		phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_igp;
+		phy->ops.set_d0_lplu_state  = igb_set_d0_lplu_state_82575;
+		phy->ops.set_d3_lplu_state  = igb_set_d3_lplu_state;
+		break;
+	default:
+		return -E1000_ERR_PHY;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_acquire_phy_82575 - Acquire rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire access rights to the correct PHY.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static s32 igb_acquire_phy_82575(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+
+	return igb_acquire_swfw_sync_82575(hw, mask);
+}
+
+/**
+ *  e1000_release_phy_82575 - Release rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  A wrapper to release access rights to the correct PHY.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static void igb_release_phy_82575(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+	igb_release_swfw_sync_82575(hw, mask);
+}
+
+/**
+ *  e1000_read_phy_reg_sgmii_82575 - Read PHY register using sgmii
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the PHY register at offset using the serial gigabit media independent
+ *  interface and stores the retrieved information in data.
+ **/
+static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
+					  u16 *data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, i2ccmd = 0;
+
+	if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
+		hw_dbg(hw, "PHY Address %u is out of range\n", offset);
+		return -E1000_ERR_PARAM;
+	}
+
+	/*
+	 * Set up Op-code, Phy Address, and register address in the I2CCMD
+	 * register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+		  (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+		  (E1000_I2CCMD_OPCODE_READ));
+
+	wr32(E1000_I2CCMD, i2ccmd);
+
+	/* Poll the ready bit to see if the I2C read completed */
+	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+		udelay(50);
+		i2ccmd = rd32(E1000_I2CCMD);
+		if (i2ccmd & E1000_I2CCMD_READY)
+			break;
+	}
+	if (!(i2ccmd & E1000_I2CCMD_READY)) {
+		hw_dbg(hw, "I2CCMD Read did not complete\n");
+		return -E1000_ERR_PHY;
+	}
+	if (i2ccmd & E1000_I2CCMD_ERROR) {
+		hw_dbg(hw, "I2CCMD Error bit set\n");
+		return -E1000_ERR_PHY;
+	}
+
+	/* Need to byte-swap the 16-bit value. */
+	*data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
+
+	return 0;
+}
+
+/**
+ *  e1000_write_phy_reg_sgmii_82575 - Write PHY register using sgmii
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Writes the data to PHY register at the offset using the serial gigabit
+ *  media independent interface.
+ **/
+static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
+					   u16 data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, i2ccmd = 0;
+	u16 phy_data_swapped;
+
+	if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
+		hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+		return -E1000_ERR_PARAM;
+	}
+
+	/* Swap the data bytes for the I2C interface */
+	phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
+
+	/*
+	 * Set up Op-code, Phy Address, and register address in the I2CCMD
+	 * register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+		  (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+		  E1000_I2CCMD_OPCODE_WRITE |
+		  phy_data_swapped);
+
+	wr32(E1000_I2CCMD, i2ccmd);
+
+	/* Poll the ready bit to see if the I2C read completed */
+	for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+		udelay(50);
+		i2ccmd = rd32(E1000_I2CCMD);
+		if (i2ccmd & E1000_I2CCMD_READY)
+			break;
+	}
+	if (!(i2ccmd & E1000_I2CCMD_READY)) {
+		hw_dbg(hw, "I2CCMD Write did not complete\n");
+		return -E1000_ERR_PHY;
+	}
+	if (i2ccmd & E1000_I2CCMD_ERROR) {
+		hw_dbg(hw, "I2CCMD Error bit set\n");
+		return -E1000_ERR_PHY;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_get_phy_id_82575 - Retreive PHY addr and id
+ *  @hw: pointer to the HW structure
+ *
+ *  Retreives the PHY address and ID for both PHY's which do and do not use
+ *  sgmi interface.
+ **/
+static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32  ret_val = 0;
+	u16 phy_id;
+
+	/*
+	 * For SGMII PHYs, we try the list of possible addresses until
+	 * we find one that works.  For non-SGMII PHYs
+	 * (e.g. integrated copper PHYs), an address of 1 should
+	 * work.  The result of this function should mean phy->phy_addr
+	 * and phy->id are set correctly.
+	 */
+	if (!(igb_sgmii_active_82575(hw))) {
+		phy->addr = 1;
+		ret_val = igb_get_phy_id(hw);
+		goto out;
+	}
+
+	/*
+	 * The address field in the I2CCMD register is 3 bits and 0 is invalid.
+	 * Therefore, we need to test 1-7
+	 */
+	for (phy->addr = 1; phy->addr < 8; phy->addr++) {
+		ret_val = igb_read_phy_reg_sgmii_82575(hw, PHY_ID1, &phy_id);
+		if (ret_val == 0) {
+			hw_dbg(hw, "Vendor ID 0x%08X read at address %u\n",
+				  phy_id,
+				  phy->addr);
+			/*
+			 * At the time of this writing, The M88 part is
+			 * the only supported SGMII PHY product.
+			 */
+			if (phy_id == M88_VENDOR)
+				break;
+		} else {
+			hw_dbg(hw, "PHY address %u was unreadable\n",
+				  phy->addr);
+		}
+	}
+
+	/* A valid PHY type couldn't be found. */
+	if (phy->addr == 8) {
+		phy->addr = 0;
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+	ret_val = igb_get_phy_id(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_hw_reset_sgmii_82575 - Performs a PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Resets the PHY using the serial gigabit media independent interface.
+ **/
+static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	/*
+	 * This isn't a true "hard" reset, but is the only reset
+	 * available to us at this time.
+	 */
+
+	hw_dbg(hw, "Soft resetting SGMII attached PHY...\n");
+
+	/*
+	 * SFP documentation requires the following to configure the SPF module
+	 * to work on SGMII.  No further documentation is given.
+	 */
+	ret_val = hw->phy.ops.write_phy_reg(hw, 0x1B, 0x8084);
+	if (ret_val)
+		goto out;
+
+	ret_val = igb_phy_sw_reset(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state
+ *  @hw: pointer to the HW structure
+ *  @active: true to enable LPLU, false to disable
+ *
+ *  Sets the LPLU D0 state according to the active flag.  When
+ *  activating LPLU this function also disables smart speed
+ *  and vice versa.  LPLU will not be activated unless the
+ *  device autonegotiation advertisement meets standards of
+ *  either 10 or 10/100 or 10/100/1000 at all duplexes.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+					   &data);
+	if (ret_val)
+		goto out;
+
+	if (active) {
+		data |= IGP02E1000_PM_D0_LPLU;
+		ret_val = hw->phy.ops.write_phy_reg(hw,
+					      IGP02E1000_PHY_POWER_MGMT,
+					      data);
+		if (ret_val)
+			goto out;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = hw->phy.ops.read_phy_reg(hw,
+					     IGP01E1000_PHY_PORT_CONFIG,
+					     &data);
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = hw->phy.ops.write_phy_reg(hw,
+					      IGP01E1000_PHY_PORT_CONFIG,
+					      data);
+		if (ret_val)
+			goto out;
+	} else {
+		data &= ~IGP02E1000_PM_D0_LPLU;
+		ret_val = hw->phy.ops.write_phy_reg(hw,
+					      IGP02E1000_PHY_POWER_MGMT,
+					      data);
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = hw->phy.ops.read_phy_reg(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = hw->phy.ops.write_phy_reg(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = hw->phy.ops.read_phy_reg(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = hw->phy.ops.write_phy_reg(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_acquire_nvm_82575 - Request for access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the necessary semaphores for exclussive access to the EEPROM.
+ *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ *  Return successful if access grant bit set, else clear the request for
+ *  EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+static s32 igb_acquire_nvm_82575(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	ret_val = igb_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+	if (ret_val)
+		goto out;
+
+	ret_val = igb_acquire_nvm(hw);
+
+	if (ret_val)
+		igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_release_nvm_82575 - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit,
+ *  then release the semaphores acquired.
+ **/
+static void igb_release_nvm_82575(struct e1000_hw *hw)
+{
+	igb_release_nvm(hw);
+	igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ *  e1000_acquire_swfw_sync_82575 - Acquire SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
+ *  will also specify which port we're acquiring the lock for.
+ **/
+static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+	u32 swmask = mask;
+	u32 fwmask = mask << 16;
+	s32 ret_val = 0;
+	s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
+
+	while (i < timeout) {
+		if (igb_get_hw_semaphore(hw)) {
+			ret_val = -E1000_ERR_SWFW_SYNC;
+			goto out;
+		}
+
+		swfw_sync = rd32(E1000_SW_FW_SYNC);
+		if (!(swfw_sync & (fwmask | swmask)))
+			break;
+
+		/*
+		 * Firmware currently using resource (fwmask)
+		 * or other software thread using resource (swmask)
+		 */
+		igb_put_hw_semaphore(hw);
+		mdelay(5);
+		i++;
+	}
+
+	if (i == timeout) {
+		hw_dbg(hw, "Can't access resource, SW_FW_SYNC timeout.\n");
+		ret_val = -E1000_ERR_SWFW_SYNC;
+		goto out;
+	}
+
+	swfw_sync |= swmask;
+	wr32(E1000_SW_FW_SYNC, swfw_sync);
+
+	igb_put_hw_semaphore(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_release_swfw_sync_82575 - Release SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
+ *  will also specify which port we're releasing the lock for.
+ **/
+static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+
+	while (igb_get_hw_semaphore(hw) != 0);
+	/* Empty */
+
+	swfw_sync = rd32(E1000_SW_FW_SYNC);
+	swfw_sync &= ~mask;
+	wr32(E1000_SW_FW_SYNC, swfw_sync);
+
+	igb_put_hw_semaphore(hw);
+}
+
+/**
+ *  e1000_get_cfg_done_82575 - Read config done bit
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the management control register for the config done bit for
+ *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
+ *  to read the config done bit, so an error is *ONLY* logged and returns
+ *  0.  If we were to return with error, EEPROM-less silicon
+ *  would not be able to be reset or change link.
+ **/
+static s32 igb_get_cfg_done_82575(struct e1000_hw *hw)
+{
+	s32 timeout = PHY_CFG_TIMEOUT;
+	s32 ret_val = 0;
+	u32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+	if (hw->bus.func == 1)
+		mask = E1000_NVM_CFG_DONE_PORT_1;
+
+	while (timeout) {
+		if (rd32(E1000_EEMNGCTL) & mask)
+			break;
+		msleep(1);
+		timeout--;
+	}
+	if (!timeout)
+		hw_dbg(hw, "MNG configuration cycle has not completed.\n");
+
+	/* If EEPROM is not marked present, init the PHY manually */
+	if (((rd32(E1000_EECD) & E1000_EECD_PRES) == 0) &&
+	    (hw->phy.type == e1000_phy_igp_3))
+		igb_phy_init_script_igp3(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_check_for_link_82575 - Check for link
+ *  @hw: pointer to the HW structure
+ *
+ *  If sgmii is enabled, then use the pcs register to determine link, otherwise
+ *  use the generic interface for determining link.
+ **/
+static s32 igb_check_for_link_82575(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 speed, duplex;
+
+	/* SGMII link check is done through the PCS register. */
+	if ((hw->phy.media_type != e1000_media_type_copper) ||
+	    (igb_sgmii_active_82575(hw)))
+		ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed,
+							       &duplex);
+	else
+		ret_val = igb_check_for_copper_link(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Using the physical coding sub-layer (PCS), retreive the current speed and
+ *  duplex, then store the values in the pointers provided.
+ **/
+static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed,
+						u16 *duplex)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 pcs;
+
+	/* Set up defaults for the return values of this function */
+	mac->serdes_has_link = false;
+	*speed = 0;
+	*duplex = 0;
+
+	/*
+	 * Read the PCS Status register for link state. For non-copper mode,
+	 * the status register is not accurate. The PCS status register is
+	 * used instead.
+	 */
+	pcs = rd32(E1000_PCS_LSTAT);
+
+	/*
+	 * The link up bit determines when link is up on autoneg. The sync ok
+	 * gets set once both sides sync up and agree upon link. Stable link
+	 * can be determined by checking for both link up and link sync ok
+	 */
+	if ((pcs & E1000_PCS_LSTS_LINK_OK) && (pcs & E1000_PCS_LSTS_SYNK_OK)) {
+		mac->serdes_has_link = true;
+
+		/* Detect and store PCS speed */
+		if (pcs & E1000_PCS_LSTS_SPEED_1000) {
+			*speed = SPEED_1000;
+		} else if (pcs & E1000_PCS_LSTS_SPEED_100) {
+			*speed = SPEED_100;
+		} else {
+			*speed = SPEED_10;
+		}
+
+		/* Detect and store PCS duplex */
+		if (pcs & E1000_PCS_LSTS_DUPLEX_FULL) {
+			*duplex = FULL_DUPLEX;
+		} else {
+			*duplex = HALF_DUPLEX;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_rar_set_82575 - Set receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address array register at index to the address passed
+ *  in by addr.
+ **/
+static void igb_rar_set_82575(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+	if (index < E1000_RAR_ENTRIES_82575)
+		igb_rar_set(hw, addr, index);
+
+	return;
+}
+
+/**
+ *  e1000_reset_hw_82575 - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static s32 igb_reset_hw_82575(struct e1000_hw *hw)
+{
+	u32 ctrl, icr;
+	s32 ret_val;
+
+	/*
+	 * Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = igb_disable_pcie_master(hw);
+	if (ret_val)
+		hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+
+	hw_dbg(hw, "Masking off all interrupts\n");
+	wr32(E1000_IMC, 0xffffffff);
+
+	wr32(E1000_RCTL, 0);
+	wr32(E1000_TCTL, E1000_TCTL_PSP);
+	wrfl();
+
+	msleep(10);
+
+	ctrl = rd32(E1000_CTRL);
+
+	hw_dbg(hw, "Issuing a global reset to MAC\n");
+	wr32(E1000_CTRL, ctrl | E1000_CTRL_RST);
+
+	ret_val = igb_get_auto_rd_done(hw);
+	if (ret_val) {
+		/*
+		 * When auto config read does not complete, do not
+		 * return with an error. This can happen in situations
+		 * where there is no eeprom and prevents getting link.
+		 */
+		hw_dbg(hw, "Auto Read Done did not complete\n");
+	}
+
+	/* If EEPROM is not present, run manual init scripts */
+	if ((rd32(E1000_EECD) & E1000_EECD_PRES) == 0)
+		igb_reset_init_script_82575(hw);
+
+	/* Clear any pending interrupt events. */
+	wr32(E1000_IMC, 0xffffffff);
+	icr = rd32(E1000_ICR);
+
+	igb_check_alt_mac_addr(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_init_hw_82575 - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 igb_init_hw_82575(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	u16 i, rar_count = mac->rar_entry_count;
+
+	/* Initialize identification LED */
+	ret_val = igb_id_led_init(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error initializing identification LED\n");
+		/* This is not fatal and we should not stop init due to this */
+	}
+
+	/* Disabling VLAN filtering */
+	hw_dbg(hw, "Initializing the IEEE VLAN\n");
+	igb_clear_vfta(hw);
+
+	/* Setup the receive address */
+	igb_init_rx_addrs(hw, rar_count);
+	/* Zero out the Multicast HASH table */
+	hw_dbg(hw, "Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		array_wr32(E1000_MTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = igb_setup_link(hw);
+
+	/*
+	 * Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	igb_clear_hw_cntrs_82575(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_copper_link_82575 - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the link for auto-neg or forced speed and duplex.  Then we check
+ *  for link, once link is established calls to configure collision distance
+ *  and flow control are called.
+ **/
+static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
+{
+	u32 ctrl, led_ctrl;
+	s32  ret_val;
+	bool link;
+
+	ctrl = rd32(E1000_CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	wr32(E1000_CTRL, ctrl);
+
+	switch (hw->phy.type) {
+	case e1000_phy_m88:
+		ret_val = igb_copper_link_setup_m88(hw);
+		break;
+	case e1000_phy_igp_3:
+		ret_val = igb_copper_link_setup_igp(hw);
+		/* Setup activity LED */
+		led_ctrl = rd32(E1000_LEDCTL);
+		led_ctrl &= IGP_ACTIVITY_LED_MASK;
+		led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+		wr32(E1000_LEDCTL, led_ctrl);
+		break;
+	default:
+		ret_val = -E1000_ERR_PHY;
+		break;
+	}
+
+	if (ret_val)
+		goto out;
+
+	if (hw->mac.autoneg) {
+		/*
+		 * Setup autoneg and flow control advertisement
+		 * and perform autonegotiation.
+		 */
+		ret_val = igb_copper_link_autoneg(hw);
+		if (ret_val)
+			goto out;
+	} else {
+		/*
+		 * PHY will be set to 10H, 10F, 100H or 100F
+		 * depending on user settings.
+		 */
+		hw_dbg(hw, "Forcing Speed and Duplex\n");
+		ret_val = igb_phy_force_speed_duplex(hw);
+		if (ret_val) {
+			hw_dbg(hw, "Error Forcing Speed and Duplex\n");
+			goto out;
+		}
+	}
+
+	ret_val = igb_configure_pcs_link_82575(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Check link status. Wait up to 100 microseconds for link to become
+	 * valid.
+	 */
+	ret_val = igb_phy_has_link(hw,
+					     COPPER_LINK_UP_LIMIT,
+					     10,
+					     &link);
+	if (ret_val)
+		goto out;
+
+	if (link) {
+		hw_dbg(hw, "Valid link established!!!\n");
+		/* Config the MAC and PHY after link is up */
+		igb_config_collision_dist(hw);
+		ret_val = igb_config_fc_after_link_up(hw);
+	} else {
+		hw_dbg(hw, "Unable to establish link!!!\n");
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_fiber_serdes_link_82575 - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures speed and duplex for fiber and serdes links.
+ **/
+static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw)
+{
+	u32 reg;
+
+	/*
+	 * On the 82575, SerDes loopback mode persists until it is
+	 * explicitly turned off or a power cycle is performed.  A read to
+	 * the register does not indicate its status.  Therefore, we ensure
+	 * loopback mode is disabled during initialization.
+	 */
+	wr32(E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+
+	/* Force link up, set 1gb, set both sw defined pins */
+	reg = rd32(E1000_CTRL);
+	reg |= E1000_CTRL_SLU |
+	       E1000_CTRL_SPD_1000 |
+	       E1000_CTRL_FRCSPD |
+	       E1000_CTRL_SWDPIN0 |
+	       E1000_CTRL_SWDPIN1;
+	wr32(E1000_CTRL, reg);
+
+	/* Set switch control to serdes energy detect */
+	reg = rd32(E1000_CONNSW);
+	reg |= E1000_CONNSW_ENRGSRC;
+	wr32(E1000_CONNSW, reg);
+
+	/*
+	 * New SerDes mode allows for forcing speed or autonegotiating speed
+	 * at 1gb. Autoneg should be default set by most drivers. This is the
+	 * mode that will be compatible with older link partners and switches.
+	 * However, both are supported by the hardware and some drivers/tools.
+	 */
+	reg = rd32(E1000_PCS_LCTL);
+
+	reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP |
+		E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);
+
+	if (hw->mac.autoneg) {
+		/* Set PCS register for autoneg */
+		reg |= E1000_PCS_LCTL_FSV_1000 |      /* Force 1000    */
+		       E1000_PCS_LCTL_FDV_FULL |      /* SerDes Full duplex */
+		       E1000_PCS_LCTL_AN_ENABLE |     /* Enable Autoneg */
+		       E1000_PCS_LCTL_AN_RESTART;     /* Restart autoneg */
+		hw_dbg(hw, "Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg);
+	} else {
+		/* Set PCS register for forced speed */
+		reg |= E1000_PCS_LCTL_FLV_LINK_UP |   /* Force link up */
+		       E1000_PCS_LCTL_FSV_1000 |      /* Force 1000    */
+		       E1000_PCS_LCTL_FDV_FULL |      /* SerDes Full duplex */
+		       E1000_PCS_LCTL_FSD |           /* Force Speed */
+		       E1000_PCS_LCTL_FORCE_LINK;     /* Force Link */
+		hw_dbg(hw, "Configuring Forced Link; PCS_LCTL = 0x%08X\n", reg);
+	}
+	wr32(E1000_PCS_LCTL, reg);
+
+	return 0;
+}
+
+/**
+ *  e1000_configure_pcs_link_82575 - Configure PCS link
+ *  @hw: pointer to the HW structure
+ *
+ *  Configure the physical coding sub-layer (PCS) link.  The PCS link is
+ *  only used on copper connections where the serialized gigabit media
+ *  independent interface (sgmii) is being used.  Configures the link
+ *  for auto-negotiation or forces speed/duplex.
+ **/
+static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 reg = 0;
+
+	if (hw->phy.media_type != e1000_media_type_copper ||
+	    !(igb_sgmii_active_82575(hw)))
+		goto out;
+
+	/* For SGMII, we need to issue a PCS autoneg restart */
+	reg = rd32(E1000_PCS_LCTL);
+
+	/* AN time out should be disabled for SGMII mode */
+	reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT);
+
+	if (mac->autoneg) {
+		/* Make sure forced speed and force link are not set */
+		reg &= ~(E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);
+
+		/*
+		 * The PHY should be setup prior to calling this function.
+		 * All we need to do is restart autoneg and enable autoneg.
+		 */
+		reg |= E1000_PCS_LCTL_AN_RESTART | E1000_PCS_LCTL_AN_ENABLE;
+	} else {
+		/* Set PCS regiseter for forced speed */
+
+		/* Turn off bits for full duplex, speed, and autoneg */
+		reg &= ~(E1000_PCS_LCTL_FSV_1000 |
+			 E1000_PCS_LCTL_FSV_100 |
+			 E1000_PCS_LCTL_FDV_FULL |
+			 E1000_PCS_LCTL_AN_ENABLE);
+
+		/* Check for duplex first */
+		if (mac->forced_speed_duplex & E1000_ALL_FULL_DUPLEX)
+			reg |= E1000_PCS_LCTL_FDV_FULL;
+
+		/* Now set speed */
+		if (mac->forced_speed_duplex & E1000_ALL_100_SPEED)
+			reg |= E1000_PCS_LCTL_FSV_100;
+
+		/* Force speed and force link */
+		reg |= E1000_PCS_LCTL_FSD |
+		       E1000_PCS_LCTL_FORCE_LINK |
+		       E1000_PCS_LCTL_FLV_LINK_UP;
+
+		hw_dbg(hw,
+		       "Wrote 0x%08X to PCS_LCTL to configure forced link\n",
+		       reg);
+	}
+	wr32(E1000_PCS_LCTL, reg);
+
+out:
+	return 0;
+}
+
+/**
+ *  e1000_sgmii_active_82575 - Return sgmii state
+ *  @hw: pointer to the HW structure
+ *
+ *  82575 silicon has a serialized gigabit media independent interface (sgmii)
+ *  which can be enabled for use in the embedded applications.  Simply
+ *  return the current state of the sgmii interface.
+ **/
+static bool igb_sgmii_active_82575(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_82575 *dev_spec;
+	bool ret_val;
+
+	if (hw->mac.type != e1000_82575) {
+		ret_val = false;
+		goto out;
+	}
+
+	dev_spec = (struct e1000_dev_spec_82575 *)hw->dev_spec;
+
+	ret_val = dev_spec->sgmii_active;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_reset_init_script_82575 - Inits HW defaults after reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Inits recommended HW defaults after a reset when there is no EEPROM
+ *  detected. This is only for the 82575.
+ **/
+static s32 igb_reset_init_script_82575(struct e1000_hw *hw)
+{
+	if (hw->mac.type == e1000_82575) {
+		hw_dbg(hw, "Running reset init script for 82575\n");
+		/* SerDes configuration via SERDESCTRL */
+		igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x00, 0x0C);
+		igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x01, 0x78);
+		igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x1B, 0x23);
+		igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x23, 0x15);
+
+		/* CCM configuration via CCMCTL register */
+		igb_write_8bit_ctrl_reg(hw, E1000_CCMCTL, 0x14, 0x00);
+		igb_write_8bit_ctrl_reg(hw, E1000_CCMCTL, 0x10, 0x00);
+
+		/* PCIe lanes configuration */
+		igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x00, 0xEC);
+		igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x61, 0xDF);
+		igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x34, 0x05);
+		igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x2F, 0x81);
+
+		/* PCIe PLL Configuration */
+		igb_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x02, 0x47);
+		igb_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x14, 0x00);
+		igb_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x10, 0x00);
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_read_mac_addr_82575 - Read device MAC address
+ *  @hw: pointer to the HW structure
+ **/
+static s32 igb_read_mac_addr_82575(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+
+	if (igb_check_alt_mac_addr(hw))
+		ret_val = igb_read_mac_addr(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_82575 - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw)
+{
+	u32 temp;
+
+	igb_clear_hw_cntrs_base(hw);
+
+	temp = rd32(E1000_PRC64);
+	temp = rd32(E1000_PRC127);
+	temp = rd32(E1000_PRC255);
+	temp = rd32(E1000_PRC511);
+	temp = rd32(E1000_PRC1023);
+	temp = rd32(E1000_PRC1522);
+	temp = rd32(E1000_PTC64);
+	temp = rd32(E1000_PTC127);
+	temp = rd32(E1000_PTC255);
+	temp = rd32(E1000_PTC511);
+	temp = rd32(E1000_PTC1023);
+	temp = rd32(E1000_PTC1522);
+
+	temp = rd32(E1000_ALGNERRC);
+	temp = rd32(E1000_RXERRC);
+	temp = rd32(E1000_TNCRS);
+	temp = rd32(E1000_CEXTERR);
+	temp = rd32(E1000_TSCTC);
+	temp = rd32(E1000_TSCTFC);
+
+	temp = rd32(E1000_MGTPRC);
+	temp = rd32(E1000_MGTPDC);
+	temp = rd32(E1000_MGTPTC);
+
+	temp = rd32(E1000_IAC);
+	temp = rd32(E1000_ICRXOC);
+
+	temp = rd32(E1000_ICRXPTC);
+	temp = rd32(E1000_ICRXATC);
+	temp = rd32(E1000_ICTXPTC);
+	temp = rd32(E1000_ICTXATC);
+	temp = rd32(E1000_ICTXQEC);
+	temp = rd32(E1000_ICTXQMTC);
+	temp = rd32(E1000_ICRXDMTC);
+
+	temp = rd32(E1000_CBTMPC);
+	temp = rd32(E1000_HTDPMC);
+	temp = rd32(E1000_CBRMPC);
+	temp = rd32(E1000_RPTHC);
+	temp = rd32(E1000_HGPTC);
+	temp = rd32(E1000_HTCBDPC);
+	temp = rd32(E1000_HGORCL);
+	temp = rd32(E1000_HGORCH);
+	temp = rd32(E1000_HGOTCL);
+	temp = rd32(E1000_HGOTCH);
+	temp = rd32(E1000_LENERRS);
+
+	/* This register should not be read in copper configurations */
+	if (hw->phy.media_type == e1000_media_type_internal_serdes)
+		temp = rd32(E1000_SCVPC);
+}
+
+static struct e1000_mac_operations e1000_mac_ops_82575 = {
+	.reset_hw             = igb_reset_hw_82575,
+	.init_hw              = igb_init_hw_82575,
+	.check_for_link       = igb_check_for_link_82575,
+	.rar_set              = igb_rar_set_82575,
+	.read_mac_addr        = igb_read_mac_addr_82575,
+	.get_speed_and_duplex = igb_get_speed_and_duplex_copper,
+};
+
+static struct e1000_phy_operations e1000_phy_ops_82575 = {
+	.acquire_phy          = igb_acquire_phy_82575,
+	.get_cfg_done         = igb_get_cfg_done_82575,
+	.release_phy          = igb_release_phy_82575,
+};
+
+static struct e1000_nvm_operations e1000_nvm_ops_82575 = {
+	.acquire_nvm          = igb_acquire_nvm_82575,
+	.read_nvm             = igb_read_nvm_eerd,
+	.release_nvm          = igb_release_nvm_82575,
+	.write_nvm            = igb_write_nvm_spi,
+};
+
+const struct e1000_info e1000_82575_info = {
+	.get_invariants = igb_get_invariants_82575,
+	.mac_ops = &e1000_mac_ops_82575,
+	.phy_ops = &e1000_phy_ops_82575,
+	.nvm_ops = &e1000_nvm_ops_82575,
+};
+
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
new file mode 100644
index 000000000000..6604d96bd567
--- /dev/null
+++ b/drivers/net/igb/e1000_82575.h
@@ -0,0 +1,150 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_82575_H_
+#define _E1000_82575_H_
+
+#define E1000_RAR_ENTRIES_82575   16
+
+/* SRRCTL bit definitions */
+#define E1000_SRRCTL_BSIZEPKT_SHIFT                     10 /* Shift _right_ */
+#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT                 2  /* Shift _left_ */
+#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF                0x02000000
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS          0x0A000000
+
+#define E1000_MRQC_ENABLE_RSS_4Q            0x00000002
+#define E1000_MRQC_RSS_FIELD_IPV4_UDP       0x00400000
+#define E1000_MRQC_RSS_FIELD_IPV6_UDP       0x00800000
+#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX    0x01000000
+
+#define E1000_EICR_TX_QUEUE ( \
+    E1000_EICR_TX_QUEUE0 |    \
+    E1000_EICR_TX_QUEUE1 |    \
+    E1000_EICR_TX_QUEUE2 |    \
+    E1000_EICR_TX_QUEUE3)
+
+#define E1000_EICR_RX_QUEUE ( \
+    E1000_EICR_RX_QUEUE0 |    \
+    E1000_EICR_RX_QUEUE1 |    \
+    E1000_EICR_RX_QUEUE2 |    \
+    E1000_EICR_RX_QUEUE3)
+
+#define E1000_EIMS_RX_QUEUE E1000_EICR_RX_QUEUE
+#define E1000_EIMS_TX_QUEUE E1000_EICR_TX_QUEUE
+
+/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */
+
+/* Receive Descriptor - Advanced */
+union e1000_adv_rx_desc {
+	struct {
+		u64 pkt_addr;             /* Packet buffer address */
+		u64 hdr_addr;             /* Header buffer address */
+	} read;
+	struct {
+		struct {
+			struct {
+				u16 pkt_info;   /* RSS type, Packet type */
+				u16 hdr_info;   /* Split Header,
+						 * header buffer length */
+			} lo_dword;
+			union {
+				u32 rss;          /* RSS Hash */
+				struct {
+					u16 ip_id;    /* IP id */
+					u16 csum;     /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			u32 status_error;     /* ext status/error */
+			u16 length;           /* Packet length */
+			u16 vlan;             /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+#define E1000_RXDADV_HDRBUFLEN_MASK      0x7FE0
+#define E1000_RXDADV_HDRBUFLEN_SHIFT     5
+
+/* RSS Hash results */
+
+/* RSS Packet Types as indicated in the receive descriptor */
+
+/* Transmit Descriptor - Advanced */
+union e1000_adv_tx_desc {
+	struct {
+		u64 buffer_addr;    /* Address of descriptor's data buf */
+		u32 cmd_type_len;
+		u32 olinfo_status;
+	} read;
+	struct {
+		u64 rsvd;       /* Reserved */
+		u32 nxtseq_seed;
+		u32 status;
+	} wb;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define E1000_ADVTXD_DTYP_CTXT    0x00200000 /* Advanced Context Descriptor */
+#define E1000_ADVTXD_DTYP_DATA    0x00300000 /* Advanced Data Descriptor */
+#define E1000_ADVTXD_DCMD_IFCS    0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_ADVTXD_DCMD_DEXT    0x20000000 /* Descriptor extension (1=Adv) */
+#define E1000_ADVTXD_DCMD_VLE     0x40000000 /* VLAN pkt enable */
+#define E1000_ADVTXD_DCMD_TSE     0x80000000 /* TCP Seg enable */
+#define E1000_ADVTXD_PAYLEN_SHIFT    14 /* Adv desc PAYLEN shift */
+
+/* Context descriptors */
+struct e1000_adv_tx_context_desc {
+	u32 vlan_macip_lens;
+	u32 seqnum_seed;
+	u32 type_tucmd_mlhl;
+	u32 mss_l4len_idx;
+};
+
+#define E1000_ADVTXD_MACLEN_SHIFT    9  /* Adv ctxt desc mac len shift */
+#define E1000_ADVTXD_TUCMD_IPV4    0x00000400  /* IP Packet Type: 1=IPv4 */
+#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800  /* L4 Packet TYPE of TCP */
+/* IPSec Encrypt Enable for ESP */
+#define E1000_ADVTXD_L4LEN_SHIFT     8  /* Adv ctxt L4LEN shift */
+#define E1000_ADVTXD_MSS_SHIFT      16  /* Adv ctxt MSS shift */
+/* Adv ctxt IPSec SA IDX mask */
+/* Adv ctxt IPSec ESP len mask */
+
+/* Additional Transmit Descriptor Control definitions */
+#define E1000_TXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Tx Queue */
+/* Tx Queue Arbitration Priority 0=low, 1=high */
+
+/* Additional Receive Descriptor Control definitions */
+#define E1000_RXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Rx Queue */
+
+/* Direct Cache Access (DCA) definitions */
+
+
+
+#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */
+
+#endif
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
new file mode 100644
index 000000000000..8da9ffedc425
--- /dev/null
+++ b/drivers/net/igb/e1000_defines.h
@@ -0,0 +1,772 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_DEFINES_H_
+#define _E1000_DEFINES_H_
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+
+/* Wake Up Packet Length */
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
+#define E1000_CTRL_EXT_EIAME          0x01000000
+#define E1000_CTRL_EXT_IRCA           0x00000001
+/* Interrupt delay cancellation */
+/* Driver loaded bit for FW */
+#define E1000_CTRL_EXT_DRV_LOAD       0x10000000
+/* Interrupt acknowledge Auto-mask */
+/* Clear Interrupt timers after IMS clear */
+/* packet buffer parity error detection enabled */
+/* descriptor FIFO parity error detection enable */
+#define E1000_CTRL_EXT_PBA_CLR        0x80000000 /* PBA Clear */
+#define E1000_I2CCMD_REG_ADDR_SHIFT   16
+#define E1000_I2CCMD_PHY_ADDR_SHIFT   24
+#define E1000_I2CCMD_OPCODE_READ      0x08000000
+#define E1000_I2CCMD_OPCODE_WRITE     0x00000000
+#define E1000_I2CCMD_READY            0x20000000
+#define E1000_I2CCMD_ERROR            0x80000000
+#define E1000_MAX_SGMII_PHY_REG_ADDR  255
+#define E1000_I2CCMD_PHY_TIMEOUT      200
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP          0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4              0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX       0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6              0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP          0x00200000
+
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+/* Enable Neighbor Discovery Filtering */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+/* Enable MAC address filtering */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000
+/* Enable MNG packets to host memory */
+#define E1000_MANC_EN_MNG2HOST   0x00200000
+/* Enable IP address filtering */
+
+
+/* Receive Control */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+
+/*
+ * Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM   0x1
+#define E1000_SWFW_PHY0_SM  0x2
+#define E1000_SWFW_PHY1_SM  0x4
+
+/* FACTPS Definitions */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+/* Defined polarity of Dock/Undock indication in SDP[0] */
+/* Reset both PHY ports, through PHYRST_N pin */
+/* enable link status from external LINK_0 and LINK_1 pins */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+/* Initiate an interrupt to manageability engine */
+#define E1000_CTRL_I2C_ENA  0x02000000  /* I2C enable */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+
+#define E1000_CONNSW_ENRGSRC             0x4
+#define E1000_PCS_LCTL_FLV_LINK_UP       1
+#define E1000_PCS_LCTL_FSV_100           2
+#define E1000_PCS_LCTL_FSV_1000          4
+#define E1000_PCS_LCTL_FDV_FULL          8
+#define E1000_PCS_LCTL_FSD               0x10
+#define E1000_PCS_LCTL_FORCE_LINK        0x20
+#define E1000_PCS_LCTL_AN_ENABLE         0x10000
+#define E1000_PCS_LCTL_AN_RESTART        0x20000
+#define E1000_PCS_LCTL_AN_TIMEOUT        0x40000
+
+#define E1000_PCS_LSTS_LINK_OK           1
+#define E1000_PCS_LSTS_SPEED_100         2
+#define E1000_PCS_LSTS_SPEED_1000        4
+#define E1000_PCS_LSTS_DUPLEX_FULL       8
+#define E1000_PCS_LSTS_SYNK_OK           0x10
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+/* Change in Dock/Undock state. Clear on write '0'. */
+/* Status of Master requests. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000
+/* BMC external code execution disabled */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+
+#define ADVERTISE_10_HALF                 0x0001
+#define ADVERTISE_10_FULL                 0x0002
+#define ADVERTISE_100_HALF                0x0004
+#define ADVERTISE_100_FULL                0x0008
+#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL               0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX (ADVERTISE_10_HALF  |  ADVERTISE_10_FULL | \
+				ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
+						      ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG      (ADVERTISE_10_HALF  |  ADVERTISE_10_FULL | \
+				ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED     (ADVERTISE_10_HALF  |  ADVERTISE_10_FULL)
+#define E1000_ALL_FULL_DUPLEX  (ADVERTISE_10_FULL  |  ADVERTISE_100_FULL | \
+						      ADVERTISE_1000_FULL)
+#define E1000_ALL_HALF_DUPLEX  (ADVERTISE_10_HALF  |  ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_IVRT            0x00000040
+#define E1000_LEDCTL_LED0_BLINK           0x00000080
+
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+/* Extended desc bits for Linksec and timesync */
+
+/* Transmit Control */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+
+/* Transmit Arbitration Count */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+#define E1000_RXCSUM_PCSD      0x00002000   /* packet checksum disabled */
+
+/* Header split receive */
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       15
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        63
+#define E1000_COLD_SHIFT                12
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+
+#define MAX_JUMBO_FRAME_SIZE    0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
+
+/* PBA constants */
+#define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_34K 0x0022
+
+#define IFS_MAX       80
+#define IFS_MIN       40
+#define IFS_RATIO     4
+#define IFS_STEP      10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+/* If this bit asserted, the driver should claim the interrupt */
+#define E1000_ICR_INT_ASSERTED  0x80000000
+/* queue 0 Rx descriptor FIFO parity error */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000
+/* queue 0 Tx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000
+/* host arb read buffer parity error */
+#define E1000_ICR_HOST_ARB_PAR  0x00400000
+#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
+/* queue 1 Rx descriptor FIFO parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000
+/* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000
+/* FW changed the status of DISSW bit in the FWSM */
+#define E1000_ICR_DSW           0x00000020
+/* LAN connected device generates an interrupt */
+#define E1000_ICR_PHYINT        0x00001000
+#define E1000_ICR_EPRST         0x00100000 /* ME handware reset occurs */
+
+/* Extended Interrupt Cause Read */
+#define E1000_EICR_RX_QUEUE0    0x00000001 /* Rx Queue 0 Interrupt */
+#define E1000_EICR_RX_QUEUE1    0x00000002 /* Rx Queue 1 Interrupt */
+#define E1000_EICR_RX_QUEUE2    0x00000004 /* Rx Queue 2 Interrupt */
+#define E1000_EICR_RX_QUEUE3    0x00000008 /* Rx Queue 3 Interrupt */
+#define E1000_EICR_TX_QUEUE0    0x00000100 /* Tx Queue 0 Interrupt */
+#define E1000_EICR_TX_QUEUE1    0x00000200 /* Tx Queue 1 Interrupt */
+#define E1000_EICR_TX_QUEUE2    0x00000400 /* Tx Queue 2 Interrupt */
+#define E1000_EICR_TX_QUEUE3    0x00000800 /* Tx Queue 3 Interrupt */
+#define E1000_EICR_TCP_TIMER    0x40000000 /* TCP Timer */
+#define E1000_EICR_OTHER        0x80000000 /* Interrupt Cause Active */
+/* TCP Timer */
+
+/*
+ * This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+/* queue 0 Rx descriptor FIFO parity error */
+/* queue 0 Tx descriptor FIFO parity error */
+/* host arb read buffer parity error */
+/* packet buffer parity error */
+/* queue 1 Rx descriptor FIFO parity error */
+/* queue 1 Tx descriptor FIFO parity error */
+
+/* Extended Interrupt Mask Set */
+#define E1000_EIMS_TCP_TIMER    E1000_EICR_TCP_TIMER /* TCP Timer */
+#define E1000_EIMS_OTHER        E1000_EICR_OTHER   /* Interrupt Cause Active */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+/* queue 0 Rx descriptor FIFO parity error */
+/* queue 0 Tx descriptor FIFO parity error */
+/* host arb read buffer parity error */
+/* packet buffer parity error */
+/* queue 1 Rx descriptor FIFO parity error */
+/* queue 1 Tx descriptor FIFO parity error */
+
+/* Extended Interrupt Cause Set */
+
+/* Transmit Descriptor Control */
+/* Enable the counting of descriptors still to be processed. */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* 802.1q VLAN Packet Size */
+#define VLAN_TAG_SIZE              4    /* 802.3ac tag (not DMA'd) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/*
+ * Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots.  However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Error Codes */
+#define E1000_ERR_NVM      1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define COPPER_LINK_UP_LIMIT              10
+#define PHY_AUTO_NEG_LIMIT                45
+#define PHY_FORCE_LIMIT                   20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT      10
+
+/* Flow Control */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP          0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
+#define E1000_GCR_TXD_NO_SNOOP          0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
+			   E1000_GCR_RXDSCW_NO_SNOOP      | \
+			   E1000_GCR_RXDSCR_NO_SNOOP      | \
+			   E1000_GCR_TXD_NO_SNOOP         | \
+			   E1000_GCR_TXDSCW_NO_SNOOP      | \
+			   E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000       0x0040
+#define MII_CR_SPEED_100        0x2000
+#define MII_CR_SPEED_10         0x0000
+
+/* PHY Status Register */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+
+/* Autoneg Expansion Register */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+					/* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+					/* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
+					/* 0=Automatic Master/Slave config */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL      0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Regiser */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+
+/* NVM Control */
+#define E1000_EECD_SK        0x00000001 /* NVM Clock */
+#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* NVM Data In */
+#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
+#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* NVM Present */
+/* NVM Addressing bits based on type 0=small, 1=large */
+#define E1000_EECD_ADDR_BITS 0x00000400
+#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
+#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT     11
+
+/* Offset to data in NVM read/write registers */
+#define E1000_NVM_RW_REG_DATA   16
+#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START  1    /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
+
+/* NVM Word Offsets */
+#define NVM_ID_LED_SETTINGS        0x0004
+/* For SERDES output amplitude adjustment. */
+#define NVM_INIT_CONTROL2_REG      0x000F
+#define NVM_INIT_CONTROL3_PORT_A   0x0024
+#define NVM_ALT_MAC_ADDR_PTR       0x0037
+#define NVM_CHECKSUM_REG           0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0  0x40000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1  0x80000 /* ...for second port */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK       0x3000
+#define NVM_WORD0F_ASM_DIR          0x2000
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM                    0xBABA
+
+#define NVM_PBA_OFFSET_0           8
+#define NVM_PBA_OFFSET_1           9
+#define NVM_WORD_SIZE_BASE_SHIFT   6
+
+/* NVM Commands - Microwire */
+
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI         0x01
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
+			      (ID_LED_OFF1_OFF2 <<  8) | \
+			      (ID_LED_DEF1_DEF2 <<  4) | \
+			      (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#define PCI_HEADER_TYPE_REGISTER     0x0E
+#define PCIE_LINK_STATUS             0x12
+
+#define PCI_HEADER_TYPE_MULTIFUNC    0x80
+#define PCIE_LINK_WIDTH_MASK         0x3F0
+#define PCIE_LINK_WIDTH_SHIFT        4
+
+#define PHY_REVISION_MASK      0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/*
+ * I = Integrated
+ * E = External
+ */
+#define M88E1111_I_PHY_ID    0x01410CC0
+#define IGP03E1000_E_PHY_ID  0x02A80390
+#define M88_VENDOR           0x0141
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+/* 1=CLK125 low, 0=CLK125 toggling */
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
+					       /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040
+/* Auto crossover enabled all speeds */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060
+/*
+ * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold
+ * 0=Normal 10BASE-T RX Threshold
+ */
+/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+/*
+ * 0 = <50M
+ * 1 = 50-80M
+ * 2 = 80-110M
+ * 3 = 110-140M
+ * 4 = >140M
+ */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+/*
+ * 1 = Lost lock detect enabled.
+ * Will assert lost lock and bring
+ * link down if idle not seen
+ * within 1ms in 1000BASE-T
+ */
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master
+ */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
+/*
+ * Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave
+ */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
+
+/* MDI Control */
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* SerDes Control */
+#define E1000_GEN_CTL_READY             0x80000000
+#define E1000_GEN_CTL_ADDRESS_SHIFT     8
+#define E1000_GEN_POLL_TIMEOUT          640
+
+#endif
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
new file mode 100644
index 000000000000..161fb68764af
--- /dev/null
+++ b/drivers/net/igb/e1000_hw.h
@@ -0,0 +1,599 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "e1000_mac.h"
+#include "e1000_regs.h"
+#include "e1000_defines.h"
+
+struct e1000_hw;
+
+#define E1000_DEV_ID_82575EB_COPPER           0x10A7
+#define E1000_DEV_ID_82575EB_FIBER_SERDES     0x10A9
+#define E1000_DEV_ID_82575GB_QUAD_COPPER      0x10D6
+
+#define E1000_REVISION_2 2
+#define E1000_REVISION_4 4
+
+#define E1000_FUNC_1     1
+
+enum e1000_mac_type {
+	e1000_undefined = 0,
+	e1000_82575,
+	e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
+};
+
+enum e1000_media_type {
+	e1000_media_type_unknown = 0,
+	e1000_media_type_copper = 1,
+	e1000_media_type_fiber = 2,
+	e1000_media_type_internal_serdes = 3,
+	e1000_num_media_types
+};
+
+enum e1000_nvm_type {
+	e1000_nvm_unknown = 0,
+	e1000_nvm_none,
+	e1000_nvm_eeprom_spi,
+	e1000_nvm_eeprom_microwire,
+	e1000_nvm_flash_hw,
+	e1000_nvm_flash_sw
+};
+
+enum e1000_nvm_override {
+	e1000_nvm_override_none = 0,
+	e1000_nvm_override_spi_small,
+	e1000_nvm_override_spi_large,
+	e1000_nvm_override_microwire_small,
+	e1000_nvm_override_microwire_large
+};
+
+enum e1000_phy_type {
+	e1000_phy_unknown = 0,
+	e1000_phy_none,
+	e1000_phy_m88,
+	e1000_phy_igp,
+	e1000_phy_igp_2,
+	e1000_phy_gg82563,
+	e1000_phy_igp_3,
+	e1000_phy_ife,
+};
+
+enum e1000_bus_type {
+	e1000_bus_type_unknown = 0,
+	e1000_bus_type_pci,
+	e1000_bus_type_pcix,
+	e1000_bus_type_pci_express,
+	e1000_bus_type_reserved
+};
+
+enum e1000_bus_speed {
+	e1000_bus_speed_unknown = 0,
+	e1000_bus_speed_33,
+	e1000_bus_speed_66,
+	e1000_bus_speed_100,
+	e1000_bus_speed_120,
+	e1000_bus_speed_133,
+	e1000_bus_speed_2500,
+	e1000_bus_speed_5000,
+	e1000_bus_speed_reserved
+};
+
+enum e1000_bus_width {
+	e1000_bus_width_unknown = 0,
+	e1000_bus_width_pcie_x1,
+	e1000_bus_width_pcie_x2,
+	e1000_bus_width_pcie_x4 = 4,
+	e1000_bus_width_pcie_x8 = 8,
+	e1000_bus_width_32,
+	e1000_bus_width_64,
+	e1000_bus_width_reserved
+};
+
+enum e1000_1000t_rx_status {
+	e1000_1000t_rx_status_not_ok = 0,
+	e1000_1000t_rx_status_ok,
+	e1000_1000t_rx_status_undefined = 0xFF
+};
+
+enum e1000_rev_polarity {
+	e1000_rev_polarity_normal = 0,
+	e1000_rev_polarity_reversed,
+	e1000_rev_polarity_undefined = 0xFF
+};
+
+enum e1000_fc_type {
+	e1000_fc_none = 0,
+	e1000_fc_rx_pause,
+	e1000_fc_tx_pause,
+	e1000_fc_full,
+	e1000_fc_default = 0xFF
+};
+
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+	u64 buffer_addr; /* Address of the descriptor's data buffer */
+	u16 length;      /* Length of data DMAed into data buffer */
+	u16 csum;        /* Packet checksum */
+	u8  status;      /* Descriptor status */
+	u8  errors;      /* Descriptor Errors */
+	u16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+	struct {
+		u64 buffer_addr;
+		u64 reserved;
+	} read;
+	struct {
+		struct {
+			u32 mrq;              /* Multiple Rx Queues */
+			union {
+				u32 rss;            /* RSS Hash */
+				struct {
+					u16 ip_id;  /* IP id */
+					u16 csum;   /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			u32 status_error;     /* ext status/error */
+			u16 length;
+			u16 vlan;             /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+	struct {
+		/* one buffer for protocol header(s), three data buffers */
+		u64 buffer_addr[MAX_PS_BUFFERS];
+	} read;
+	struct {
+		struct {
+			u32 mrq;              /* Multiple Rx Queues */
+			union {
+				u32 rss;              /* RSS Hash */
+				struct {
+					u16 ip_id;    /* IP id */
+					u16 csum;     /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			u32 status_error;     /* ext status/error */
+			u16 length0;          /* length of buffer 0 */
+			u16 vlan;             /* VLAN tag */
+		} middle;
+		struct {
+			u16 header_status;
+			u16 length[3];        /* length of buffers 1-3 */
+		} upper;
+		u64 reserved;
+	} wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+	u64 buffer_addr;      /* Address of the descriptor's data buffer */
+	union {
+		u32 data;
+		struct {
+			u16 length;    /* Data buffer length */
+			u8 cso;        /* Checksum offset */
+			u8 cmd;        /* Descriptor control */
+		} flags;
+	} lower;
+	union {
+		u32 data;
+		struct {
+			u8 status;     /* Descriptor status */
+			u8 css;        /* Checksum start */
+			u16 special;
+		} fields;
+	} upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+	union {
+		u32 ip_config;
+		struct {
+			u8 ipcss;      /* IP checksum start */
+			u8 ipcso;      /* IP checksum offset */
+			u16 ipcse;     /* IP checksum end */
+		} ip_fields;
+	} lower_setup;
+	union {
+		u32 tcp_config;
+		struct {
+			u8 tucss;      /* TCP checksum start */
+			u8 tucso;      /* TCP checksum offset */
+			u16 tucse;     /* TCP checksum end */
+		} tcp_fields;
+	} upper_setup;
+	u32 cmd_and_length;
+	union {
+		u32 data;
+		struct {
+			u8 status;     /* Descriptor status */
+			u8 hdr_len;    /* Header length */
+			u16 mss;       /* Maximum segment size */
+		} fields;
+	} tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+	u64 buffer_addr;   /* Address of the descriptor's buffer address */
+	union {
+		u32 data;
+		struct {
+			u16 length;    /* Data buffer length */
+			u8 typ_len_ext;
+			u8 cmd;
+		} flags;
+	} lower;
+	union {
+		u32 data;
+		struct {
+			u8 status;     /* Descriptor status */
+			u8 popts;      /* Packet Options */
+			u16 special;
+		} fields;
+	} upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+	u64 crcerrs;
+	u64 algnerrc;
+	u64 symerrs;
+	u64 rxerrc;
+	u64 mpc;
+	u64 scc;
+	u64 ecol;
+	u64 mcc;
+	u64 latecol;
+	u64 colc;
+	u64 dc;
+	u64 tncrs;
+	u64 sec;
+	u64 cexterr;
+	u64 rlec;
+	u64 xonrxc;
+	u64 xontxc;
+	u64 xoffrxc;
+	u64 xofftxc;
+	u64 fcruc;
+	u64 prc64;
+	u64 prc127;
+	u64 prc255;
+	u64 prc511;
+	u64 prc1023;
+	u64 prc1522;
+	u64 gprc;
+	u64 bprc;
+	u64 mprc;
+	u64 gptc;
+	u64 gorc;
+	u64 gotc;
+	u64 rnbc;
+	u64 ruc;
+	u64 rfc;
+	u64 roc;
+	u64 rjc;
+	u64 mgprc;
+	u64 mgpdc;
+	u64 mgptc;
+	u64 tor;
+	u64 tot;
+	u64 tpr;
+	u64 tpt;
+	u64 ptc64;
+	u64 ptc127;
+	u64 ptc255;
+	u64 ptc511;
+	u64 ptc1023;
+	u64 ptc1522;
+	u64 mptc;
+	u64 bptc;
+	u64 tsctc;
+	u64 tsctfc;
+	u64 iac;
+	u64 icrxptc;
+	u64 icrxatc;
+	u64 ictxptc;
+	u64 ictxatc;
+	u64 ictxqec;
+	u64 ictxqmtc;
+	u64 icrxdmtc;
+	u64 icrxoc;
+	u64 cbtmpc;
+	u64 htdpmc;
+	u64 cbrdpc;
+	u64 cbrmpc;
+	u64 rpthc;
+	u64 hgptc;
+	u64 htcbdpc;
+	u64 hgorc;
+	u64 hgotc;
+	u64 lenerrs;
+	u64 scvpc;
+	u64 hrmpc;
+};
+
+struct e1000_phy_stats {
+	u32 idle_errors;
+	u32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+	u32 signature;
+	u8  status;
+	u8  reserved0;
+	u16 vlan_id;
+	u32 reserved1;
+	u16 reserved2;
+	u8  reserved3;
+	u8  checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+	u8 command_id;
+	u8 command_length;
+	u8 command_options;
+	u8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH     252
+struct e1000_host_command_info {
+	struct e1000_host_command_header command_header;
+	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+	u8  command_id;
+	u8  checksum;
+	u16 reserved1;
+	u16 reserved2;
+	u16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+	struct e1000_host_mng_command_header command_header;
+	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+#include "e1000_mac.h"
+#include "e1000_phy.h"
+#include "e1000_nvm.h"
+
+struct e1000_mac_operations {
+	s32  (*check_for_link)(struct e1000_hw *);
+	s32  (*reset_hw)(struct e1000_hw *);
+	s32  (*init_hw)(struct e1000_hw *);
+	s32  (*setup_physical_interface)(struct e1000_hw *);
+	void (*rar_set)(struct e1000_hw *, u8 *, u32);
+	s32  (*read_mac_addr)(struct e1000_hw *);
+	s32  (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *);
+};
+
+struct e1000_phy_operations {
+	s32  (*acquire_phy)(struct e1000_hw *);
+	s32  (*force_speed_duplex)(struct e1000_hw *);
+	s32  (*get_cfg_done)(struct e1000_hw *hw);
+	s32  (*get_cable_length)(struct e1000_hw *);
+	s32  (*get_phy_info)(struct e1000_hw *);
+	s32  (*read_phy_reg)(struct e1000_hw *, u32, u16 *);
+	void (*release_phy)(struct e1000_hw *);
+	s32  (*reset_phy)(struct e1000_hw *);
+	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
+	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
+	s32  (*write_phy_reg)(struct e1000_hw *, u32, u16);
+};
+
+struct e1000_nvm_operations {
+	s32  (*acquire_nvm)(struct e1000_hw *);
+	s32  (*read_nvm)(struct e1000_hw *, u16, u16, u16 *);
+	void (*release_nvm)(struct e1000_hw *);
+	s32  (*write_nvm)(struct e1000_hw *, u16, u16, u16 *);
+};
+
+struct e1000_info {
+	s32 (*get_invariants)(struct e1000_hw *);
+	struct e1000_mac_operations *mac_ops;
+	struct e1000_phy_operations *phy_ops;
+	struct e1000_nvm_operations *nvm_ops;
+};
+
+extern const struct e1000_info e1000_82575_info;
+
+struct e1000_mac_info {
+	struct e1000_mac_operations ops;
+
+	u8 addr[6];
+	u8 perm_addr[6];
+
+	enum e1000_mac_type type;
+
+	u32 collision_delta;
+	u32 ledctl_default;
+	u32 ledctl_mode1;
+	u32 ledctl_mode2;
+	u32 mc_filter_type;
+	u32 tx_packet_delta;
+	u32 txcw;
+
+	u16 current_ifs_val;
+	u16 ifs_max_val;
+	u16 ifs_min_val;
+	u16 ifs_ratio;
+	u16 ifs_step_size;
+	u16 mta_reg_count;
+	u16 rar_entry_count;
+
+	u8  forced_speed_duplex;
+
+	bool adaptive_ifs;
+	bool arc_subsystem_valid;
+	bool asf_firmware_present;
+	bool autoneg;
+	bool autoneg_failed;
+	bool disable_av;
+	bool disable_hw_init_bits;
+	bool get_link_status;
+	bool ifs_params_forced;
+	bool in_ifs_mode;
+	bool report_tx_early;
+	bool serdes_has_link;
+	bool tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+	struct e1000_phy_operations ops;
+
+	enum e1000_phy_type type;
+
+	enum e1000_1000t_rx_status local_rx;
+	enum e1000_1000t_rx_status remote_rx;
+	enum e1000_ms_type ms_type;
+	enum e1000_ms_type original_ms_type;
+	enum e1000_rev_polarity cable_polarity;
+	enum e1000_smart_speed smart_speed;
+
+	u32 addr;
+	u32 id;
+	u32 reset_delay_us; /* in usec */
+	u32 revision;
+
+	enum e1000_media_type media_type;
+
+	u16 autoneg_advertised;
+	u16 autoneg_mask;
+	u16 cable_length;
+	u16 max_cable_length;
+	u16 min_cable_length;
+
+	u8 mdix;
+
+	bool disable_polarity_correction;
+	bool is_mdix;
+	bool polarity_correction;
+	bool reset_disable;
+	bool speed_downgraded;
+	bool autoneg_wait_to_complete;
+};
+
+struct e1000_nvm_info {
+	struct e1000_nvm_operations ops;
+
+	enum e1000_nvm_type type;
+	enum e1000_nvm_override override;
+
+	u32 flash_bank_size;
+	u32 flash_base_addr;
+
+	u16 word_size;
+	u16 delay_usec;
+	u16 address_bits;
+	u16 opcode_bits;
+	u16 page_size;
+};
+
+struct e1000_bus_info {
+	enum e1000_bus_type type;
+	enum e1000_bus_speed speed;
+	enum e1000_bus_width width;
+
+	u32 snoop;
+
+	u16 func;
+	u16 pci_cmd_word;
+};
+
+struct e1000_fc_info {
+	u32 high_water;     /* Flow control high-water mark */
+	u32 low_water;      /* Flow control low-water mark */
+	u16 pause_time;     /* Flow control pause timer */
+	bool send_xon;      /* Flow control send XON */
+	bool strict_ieee;   /* Strict IEEE mode */
+	enum e1000_fc_type type; /* Type of flow control */
+	enum e1000_fc_type original_type;
+};
+
+struct e1000_hw {
+	void *back;
+	void *dev_spec;
+
+	u8 __iomem *hw_addr;
+	u8 __iomem *flash_address;
+	unsigned long io_base;
+
+	struct e1000_mac_info  mac;
+	struct e1000_fc_info   fc;
+	struct e1000_phy_info  phy;
+	struct e1000_nvm_info  nvm;
+	struct e1000_bus_info  bus;
+	struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+	u32 dev_spec_size;
+
+	u16 device_id;
+	u16 subsystem_vendor_id;
+	u16 subsystem_device_id;
+	u16 vendor_id;
+
+	u8  revision_id;
+};
+
+#ifdef DEBUG
+extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
+#define hw_dbg(hw, format, arg...) \
+	printk(KERN_DEBUG "%s: " format, igb_get_hw_dev_name(hw), ##arg)
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+hw_dbg(struct e1000_hw *hw, const char *format, ...)
+{
+	return 0;
+}
+#endif
+
+#endif
diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c
new file mode 100644
index 000000000000..3e84a3f0c1d8
--- /dev/null
+++ b/drivers/net/igb/e1000_mac.c
@@ -0,0 +1,1505 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/if_ether.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include "e1000_mac.h"
+
+#include "igb.h"
+
+static s32 igb_set_default_fc(struct e1000_hw *hw);
+static s32 igb_set_fc_watermarks(struct e1000_hw *hw);
+static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr);
+
+/**
+ *  e1000_remove_device - Free device specific structure
+ *  @hw: pointer to the HW structure
+ *
+ *  If a device specific structure was allocated, this function will
+ *  free it.
+ **/
+void igb_remove_device(struct e1000_hw *hw)
+{
+	/* Freeing the dev_spec member of e1000_hw structure */
+	kfree(hw->dev_spec);
+}
+
+static void igb_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+	struct igb_adapter *adapter = hw->back;
+
+	pci_read_config_word(adapter->pdev, reg, value);
+}
+
+static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+	struct igb_adapter *adapter = hw->back;
+	u16 cap_offset;
+
+	cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+	if (!cap_offset)
+		return -E1000_ERR_CONFIG;
+
+	pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+
+	return 0;
+}
+
+/**
+ *  e1000_get_bus_info_pcie - Get PCIe bus information
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines and stores the system bus information for a particular
+ *  network interface.  The following bus information is determined and stored:
+ *  bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+s32 igb_get_bus_info_pcie(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	s32 ret_val;
+	u32 status;
+	u16 pcie_link_status, pci_header_type;
+
+	bus->type = e1000_bus_type_pci_express;
+	bus->speed = e1000_bus_speed_2500;
+
+	ret_val = igb_read_pcie_cap_reg(hw,
+					  PCIE_LINK_STATUS,
+					  &pcie_link_status);
+	if (ret_val)
+		bus->width = e1000_bus_width_unknown;
+	else
+		bus->width = (enum e1000_bus_width)((pcie_link_status &
+						     PCIE_LINK_WIDTH_MASK) >>
+						     PCIE_LINK_WIDTH_SHIFT);
+
+	igb_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type);
+	if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
+		status = rd32(E1000_STATUS);
+		bus->func = (status & E1000_STATUS_FUNC_MASK)
+			    >> E1000_STATUS_FUNC_SHIFT;
+	} else {
+		bus->func = 0;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_clear_vfta - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the register array which contains the VLAN filter table by
+ *  setting all the values to 0.
+ **/
+void igb_clear_vfta(struct e1000_hw *hw)
+{
+	u32 offset;
+
+	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+		array_wr32(E1000_VFTA, offset, 0);
+		wrfl();
+	}
+}
+
+/**
+ *  e1000_write_vfta - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset in VLAN filter table
+ *  @value: register value written to VLAN filter table
+ *
+ *  Writes value at the given offset in the register array which stores
+ *  the VLAN filter table.
+ **/
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	array_wr32(E1000_VFTA, offset, value);
+	wrfl();
+}
+
+/**
+ *  e1000_init_rx_addrs - Initialize receive address's
+ *  @hw: pointer to the HW structure
+ *  @rar_count: receive address registers
+ *
+ *  Setups the receive address registers by setting the base receive address
+ *  register to the devices MAC address and clearing all the other receive
+ *  address registers to 0.
+ **/
+void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
+{
+	u32 i;
+
+	/* Setup the receive address */
+	hw_dbg(hw, "Programming MAC Address into RAR[0]\n");
+
+	hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+	/* Zero out the other (rar_entry_count - 1) receive addresses */
+	hw_dbg(hw, "Clearing RAR[1-%u]\n", rar_count-1);
+	for (i = 1; i < rar_count; i++) {
+		array_wr32(E1000_RA, (i << 1), 0);
+		wrfl();
+		array_wr32(E1000_RA, ((i << 1) + 1), 0);
+		wrfl();
+	}
+}
+
+/**
+ *  e1000_check_alt_mac_addr - Check for alternate MAC addr
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the nvm for an alternate MAC address.  An alternate MAC address
+ *  can be setup by pre-boot software and must be treated like a permanent
+ *  address and must override the actual permanent MAC address.  If an
+ *  alternate MAC address is fopund it is saved in the hw struct and
+ *  prgrammed into RAR0 and the cuntion returns success, otherwise the
+ *  fucntion returns an error.
+ **/
+s32 igb_check_alt_mac_addr(struct e1000_hw *hw)
+{
+	u32 i;
+	s32 ret_val = 0;
+	u16 offset, nvm_alt_mac_addr_offset, nvm_data;
+	u8 alt_mac_addr[ETH_ALEN];
+
+	ret_val = hw->nvm.ops.read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1,
+				 &nvm_alt_mac_addr_offset);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		goto out;
+	}
+
+	if (nvm_alt_mac_addr_offset == 0xFFFF) {
+		ret_val = -(E1000_NOT_IMPLEMENTED);
+		goto out;
+	}
+
+	if (hw->bus.func == E1000_FUNC_1)
+		nvm_alt_mac_addr_offset += ETH_ALEN/sizeof(u16);
+
+	for (i = 0; i < ETH_ALEN; i += 2) {
+		offset = nvm_alt_mac_addr_offset + (i >> 1);
+		ret_val = hw->nvm.ops.read_nvm(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			hw_dbg(hw, "NVM Read Error\n");
+			goto out;
+		}
+
+		alt_mac_addr[i] = (u8)(nvm_data & 0xFF);
+		alt_mac_addr[i + 1] = (u8)(nvm_data >> 8);
+	}
+
+	/* if multicast bit is set, the alternate address will not be used */
+	if (alt_mac_addr[0] & 0x01) {
+		ret_val = -(E1000_NOT_IMPLEMENTED);
+		goto out;
+	}
+
+	for (i = 0; i < ETH_ALEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i] = alt_mac_addr[i];
+
+	hw->mac.ops.rar_set(hw, hw->mac.perm_addr, 0);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_rar_set - Set receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address array register at index to the address passed
+ *  in by addr.
+ **/
+void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+	u32 rar_low, rar_high;
+
+	/*
+	 * HW expects these in little endian so we reverse the byte order
+	 * from network order (big endian) to little endian
+	 */
+	rar_low = ((u32) addr[0] |
+		   ((u32) addr[1] << 8) |
+		    ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+	if (!hw->mac.disable_av)
+		rar_high |= E1000_RAH_AV;
+
+	array_wr32(E1000_RA, (index << 1), rar_low);
+	array_wr32(E1000_RA, ((index << 1) + 1), rar_high);
+}
+
+/**
+ *  e1000_mta_set - Set multicast filter table address
+ *  @hw: pointer to the HW structure
+ *  @hash_value: determines the MTA register and bit to set
+ *
+ *  The multicast table address is a register array of 32-bit registers.
+ *  The hash_value is used to determine what register the bit is in, the
+ *  current value is read, the new bit is OR'd in and the new value is
+ *  written back into the register.
+ **/
+static void igb_mta_set(struct e1000_hw *hw, u32 hash_value)
+{
+	u32 hash_bit, hash_reg, mta;
+
+	/*
+	 * The MTA is a register array of 32-bit registers. It is
+	 * treated like an array of (32*mta_reg_count) bits.  We want to
+	 * set bit BitArray[hash_value]. So we figure out what register
+	 * the bit is in, read it, OR in the new bit, then write
+	 * back the new value.  The (hw->mac.mta_reg_count - 1) serves as a
+	 * mask to bits 31:5 of the hash value which gives us the
+	 * register we're modifying.  The hash bit within that register
+	 * is determined by the lower 5 bits of the hash value.
+	 */
+	hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+	hash_bit = hash_value & 0x1F;
+
+	mta = array_rd32(E1000_MTA, hash_reg);
+
+	mta |= (1 << hash_bit);
+
+	array_wr32(E1000_MTA, hash_reg, mta);
+	wrfl();
+}
+
+/**
+ *  e1000_update_mc_addr_list - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *  @rar_used_count: the first RAR register free to program
+ *  @rar_count: total number of supported Receive Address Registers
+ *
+ *  Updates the Receive Address Registers and Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ *  The parameter rar_count will usually be hw->mac.rar_entry_count
+ *  unless there are workarounds that change this.
+ **/
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+			       u8 *mc_addr_list, u32 mc_addr_count,
+			       u32 rar_used_count, u32 rar_count)
+{
+	u32 hash_value;
+	u32 i;
+
+	/*
+	 * Load the first set of multicast addresses into the exact
+	 * filters (RAR).  If there are not enough to fill the RAR
+	 * array, clear the filters.
+	 */
+	for (i = rar_used_count; i < rar_count; i++) {
+		if (mc_addr_count) {
+			hw->mac.ops.rar_set(hw, mc_addr_list, i);
+			mc_addr_count--;
+			mc_addr_list += ETH_ALEN;
+		} else {
+			array_wr32(E1000_RA, i << 1, 0);
+			wrfl();
+			array_wr32(E1000_RA, (i << 1) + 1, 0);
+			wrfl();
+		}
+	}
+
+	/* Clear the old settings from the MTA */
+	hw_dbg(hw, "Clearing MTA\n");
+	for (i = 0; i < hw->mac.mta_reg_count; i++) {
+		array_wr32(E1000_MTA, i, 0);
+		wrfl();
+	}
+
+	/* Load any remaining multicast addresses into the hash table. */
+	for (; mc_addr_count > 0; mc_addr_count--) {
+		hash_value = igb_hash_mc_addr(hw, mc_addr_list);
+		hw_dbg(hw, "Hash value = 0x%03X\n", hash_value);
+		igb_mta_set(hw, hash_value);
+		mc_addr_list += ETH_ALEN;
+	}
+}
+
+/**
+ *  e1000_hash_mc_addr - Generate a multicast hash value
+ *  @hw: pointer to the HW structure
+ *  @mc_addr: pointer to a multicast address
+ *
+ *  Generates a multicast address hash value which is used to determine
+ *  the multicast filter table array address and new table value.  See
+ *  igb_mta_set()
+ **/
+static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
+{
+	u32 hash_value, hash_mask;
+	u8 bit_shift = 0;
+
+	/* Register count multiplied by bits per register */
+	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+	/*
+	 * For a mc_filter_type of 0, bit_shift is the number of left-shifts
+	 * where 0xFF would still fall within the hash mask.
+	 */
+	while (hash_mask >> bit_shift != 0xFF)
+		bit_shift++;
+
+	/*
+	 * The portion of the address that is used for the hash table
+	 * is determined by the mc_filter_type setting.
+	 * The algorithm is such that there is a total of 8 bits of shifting.
+	 * The bit_shift for a mc_filter_type of 0 represents the number of
+	 * left-shifts where the MSB of mc_addr[5] would still fall within
+	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
+	 * of 8 bits of shifting, then mc_addr[4] will shift right the
+	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
+	 * cases are a variation of this algorithm...essentially raising the
+	 * number of bits to shift mc_addr[5] left, while still keeping the
+	 * 8-bit shifting total.
+	 *
+	 * For example, given the following Destination MAC Address and an
+	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+	 * we can see that the bit_shift for case 0 is 4.  These are the hash
+	 * values resulting from each mc_filter_type...
+	 * [0] [1] [2] [3] [4] [5]
+	 * 01  AA  00  12  34  56
+	 * LSB                 MSB
+	 *
+	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+	 */
+	switch (hw->mac.mc_filter_type) {
+	default:
+	case 0:
+		break;
+	case 1:
+		bit_shift += 1;
+		break;
+	case 2:
+		bit_shift += 2;
+		break;
+	case 3:
+		bit_shift += 4;
+		break;
+	}
+
+	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+				  (((u16) mc_addr[5]) << bit_shift)));
+
+	return hash_value;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_base - Clear base hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the base hardware counters by reading the counter registers.
+ **/
+void igb_clear_hw_cntrs_base(struct e1000_hw *hw)
+{
+	u32 temp;
+
+	temp = rd32(E1000_CRCERRS);
+	temp = rd32(E1000_SYMERRS);
+	temp = rd32(E1000_MPC);
+	temp = rd32(E1000_SCC);
+	temp = rd32(E1000_ECOL);
+	temp = rd32(E1000_MCC);
+	temp = rd32(E1000_LATECOL);
+	temp = rd32(E1000_COLC);
+	temp = rd32(E1000_DC);
+	temp = rd32(E1000_SEC);
+	temp = rd32(E1000_RLEC);
+	temp = rd32(E1000_XONRXC);
+	temp = rd32(E1000_XONTXC);
+	temp = rd32(E1000_XOFFRXC);
+	temp = rd32(E1000_XOFFTXC);
+	temp = rd32(E1000_FCRUC);
+	temp = rd32(E1000_GPRC);
+	temp = rd32(E1000_BPRC);
+	temp = rd32(E1000_MPRC);
+	temp = rd32(E1000_GPTC);
+	temp = rd32(E1000_GORCL);
+	temp = rd32(E1000_GORCH);
+	temp = rd32(E1000_GOTCL);
+	temp = rd32(E1000_GOTCH);
+	temp = rd32(E1000_RNBC);
+	temp = rd32(E1000_RUC);
+	temp = rd32(E1000_RFC);
+	temp = rd32(E1000_ROC);
+	temp = rd32(E1000_RJC);
+	temp = rd32(E1000_TORL);
+	temp = rd32(E1000_TORH);
+	temp = rd32(E1000_TOTL);
+	temp = rd32(E1000_TOTH);
+	temp = rd32(E1000_TPR);
+	temp = rd32(E1000_TPT);
+	temp = rd32(E1000_MPTC);
+	temp = rd32(E1000_BPTC);
+}
+
+/**
+ *  e1000_check_for_copper_link - Check for link (Copper)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks to see of the link status of the hardware has changed.  If a
+ *  change in link status has been detected, then we read the PHY registers
+ *  to get the current speed/duplex if link exists.
+ **/
+s32 igb_check_for_copper_link(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	bool link;
+
+	/*
+	 * We only want to go out to the PHY registers to see if Auto-Neg
+	 * has completed and/or if our link status has changed.  The
+	 * get_link_status flag is set upon receiving a Link Status
+	 * Change or Rx Sequence Error interrupt.
+	 */
+	if (!mac->get_link_status) {
+		ret_val = 0;
+		goto out;
+	}
+
+	/*
+	 * First we want to see if the MII Status Register reports
+	 * link.  If so, then we want to get the current speed/duplex
+	 * of the PHY.
+	 */
+	ret_val = igb_phy_has_link(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link)
+		goto out; /* No link detected */
+
+	mac->get_link_status = false;
+
+	/*
+	 * Check if there was DownShift, must be checked
+	 * immediately after link-up
+	 */
+	igb_check_downshift(hw);
+
+	/*
+	 * If we are forcing speed/duplex, then we simply return since
+	 * we have already determined whether we have link or not.
+	 */
+	if (!mac->autoneg) {
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	/*
+	 * Auto-Neg is enabled.  Auto Speed Detection takes care
+	 * of MAC speed/duplex configuration.  So we only need to
+	 * configure Collision Distance in the MAC.
+	 */
+	igb_config_collision_dist(hw);
+
+	/*
+	 * Configure Flow Control now that Auto-Neg has completed.
+	 * First, we need to restore the desired flow control
+	 * settings because we may have had to re-autoneg with a
+	 * different link partner.
+	 */
+	ret_val = igb_config_fc_after_link_up(hw);
+	if (ret_val)
+		hw_dbg(hw, "Error configuring flow control\n");
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_link - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+s32 igb_setup_link(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+
+	/*
+	 * In the case of the phy reset being blocked, we already have a link.
+	 * We do not need to set it up again.
+	 */
+	if (igb_check_reset_block(hw))
+		goto out;
+
+	ret_val = igb_set_default_fc(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * We want to save off the original Flow Control configuration just
+	 * in case we get disconnected and then reconnected into a different
+	 * hub or switch with different Flow Control capabilities.
+	 */
+	hw->fc.original_type = hw->fc.type;
+
+	hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type);
+
+	/* Call the necessary media_type subroutine to configure the link. */
+	ret_val = hw->mac.ops.setup_physical_interface(hw);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Initialize the flow control address, type, and PAUSE timer
+	 * registers to their default values.  This is done even if flow
+	 * control is disabled, because it does not hurt anything to
+	 * initialize these registers.
+	 */
+	hw_dbg(hw,
+	       "Initializing the Flow Control address, type and timer regs\n");
+	wr32(E1000_FCT, FLOW_CONTROL_TYPE);
+	wr32(E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+	wr32(E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+	wr32(E1000_FCTTV, hw->fc.pause_time);
+
+	ret_val = igb_set_fc_watermarks(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_config_collision_dist - Configure collision distance
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the collision distance to the default value and is used
+ *  during link setup. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void igb_config_collision_dist(struct e1000_hw *hw)
+{
+	u32 tctl;
+
+	tctl = rd32(E1000_TCTL);
+
+	tctl &= ~E1000_TCTL_COLD;
+	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+	wr32(E1000_TCTL, tctl);
+	wrfl();
+}
+
+/**
+ *  e1000_set_fc_watermarks - Set flow control high/low watermarks
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the flow control high/low threshold (watermark) registers.  If
+ *  flow control XON frame transmission is enabled, then set XON frame
+ *  tansmission as well.
+ **/
+static s32 igb_set_fc_watermarks(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+	u32 fcrtl = 0, fcrth = 0;
+
+	/*
+	 * Set the flow control receive threshold registers.  Normally,
+	 * these registers will be set to a default threshold that may be
+	 * adjusted later by the driver's runtime code.  However, if the
+	 * ability to transmit pause frames is not enabled, then these
+	 * registers will be set to 0.
+	 */
+	if (hw->fc.type & e1000_fc_tx_pause) {
+		/*
+		 * We need to set up the Receive Threshold high and low water
+		 * marks as well as (optionally) enabling the transmission of
+		 * XON frames.
+		 */
+		fcrtl = hw->fc.low_water;
+		if (hw->fc.send_xon)
+			fcrtl |= E1000_FCRTL_XONE;
+
+		fcrth = hw->fc.high_water;
+	}
+	wr32(E1000_FCRTL, fcrtl);
+	wr32(E1000_FCRTH, fcrth);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_set_default_fc - Set flow control default values
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the EEPROM for the default values for flow control and store the
+ *  values.
+ **/
+static s32 igb_set_default_fc(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+	u16 nvm_data;
+
+	/*
+	 * Read and store word 0x0F of the EEPROM. This word contains bits
+	 * that determine the hardware's default PAUSE (flow control) mode,
+	 * a bit that determines whether the HW defaults to enabling or
+	 * disabling auto-negotiation, and the direction of the
+	 * SW defined pins. If there is no SW over-ride of the flow
+	 * control setting, then the variable hw->fc will
+	 * be initialized based on a value in the EEPROM.
+	 */
+	ret_val = hw->nvm.ops.read_nvm(hw, NVM_INIT_CONTROL2_REG, 1,
+				       &nvm_data);
+
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		goto out;
+	}
+
+	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+		hw->fc.type = e1000_fc_none;
+	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+		 NVM_WORD0F_ASM_DIR)
+		hw->fc.type = e1000_fc_tx_pause;
+	else
+		hw->fc.type = e1000_fc_full;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_force_mac_fc - Force the MAC's flow control settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
+ *  device control register to reflect the adapter settings.  TFCE and RFCE
+ *  need to be explicitly set by software when a copper PHY is used because
+ *  autonegotiation is managed by the PHY rather than the MAC.  Software must
+ *  also configure these bits when link is forced on a fiber connection.
+ **/
+s32 igb_force_mac_fc(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val = 0;
+
+	ctrl = rd32(E1000_CTRL);
+
+	/*
+	 * Because we didn't get link via the internal auto-negotiation
+	 * mechanism (we either forced link or we got link via PHY
+	 * auto-neg), we have to manually enable/disable transmit an
+	 * receive flow control.
+	 *
+	 * The "Case" statement below enables/disable flow control
+	 * according to the "hw->fc.type" parameter.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause
+	 *          frames but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          frames but we do not receive pause frames).
+	 *      3:  Both Rx and TX flow control (symmetric) is enabled.
+	 *  other:  No other values should be possible at this point.
+	 */
+	hw_dbg(hw, "hw->fc.type = %u\n", hw->fc.type);
+
+	switch (hw->fc.type) {
+	case e1000_fc_none:
+		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+		break;
+	case e1000_fc_rx_pause:
+		ctrl &= (~E1000_CTRL_TFCE);
+		ctrl |= E1000_CTRL_RFCE;
+		break;
+	case e1000_fc_tx_pause:
+		ctrl &= (~E1000_CTRL_RFCE);
+		ctrl |= E1000_CTRL_TFCE;
+		break;
+	case e1000_fc_full:
+		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+		break;
+	default:
+		hw_dbg(hw, "Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	wr32(E1000_CTRL, ctrl);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_config_fc_after_link_up - Configures flow control after link
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the status of auto-negotiation after link up to ensure that the
+ *  speed and duplex were not forced.  If the link needed to be forced, then
+ *  flow control needs to be forced also.  If auto-negotiation is enabled
+ *  and did not fail, then we configure flow control based on our link
+ *  partner.
+ **/
+s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = 0;
+	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+	u16 speed, duplex;
+
+	/*
+	 * Check for the case where we have fiber media and auto-neg failed
+	 * so we had to force link.  In this case, we need to force the
+	 * configuration of the MAC to match the "fc" parameter.
+	 */
+	if (mac->autoneg_failed) {
+		if (hw->phy.media_type == e1000_media_type_fiber ||
+		    hw->phy.media_type == e1000_media_type_internal_serdes)
+			ret_val = igb_force_mac_fc(hw);
+	} else {
+		if (hw->phy.media_type == e1000_media_type_copper)
+			ret_val = igb_force_mac_fc(hw);
+	}
+
+	if (ret_val) {
+		hw_dbg(hw, "Error forcing flow control settings\n");
+		goto out;
+	}
+
+	/*
+	 * Check for the case where we have copper media and auto-neg is
+	 * enabled.  In this case, we need to check and see if Auto-Neg
+	 * has completed, and if so, how the PHY and link partner has
+	 * flow control configured.
+	 */
+	if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
+		/*
+		 * Read the MII Status Register and check to see if AutoNeg
+		 * has completed.  We read this twice because this reg has
+		 * some "sticky" (latched) bits.
+		 */
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS,
+						   &mii_status_reg);
+		if (ret_val)
+			goto out;
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS,
+						   &mii_status_reg);
+		if (ret_val)
+			goto out;
+
+		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+			hw_dbg(hw, "Copper PHY and Auto Neg "
+				 "has not completed.\n");
+			goto out;
+		}
+
+		/*
+		 * The AutoNeg process has completed, so we now need to
+		 * read both the Auto Negotiation Advertisement
+		 * Register (Address 4) and the Auto_Negotiation Base
+		 * Page Ability Register (Address 5) to determine how
+		 * flow control was negotiated.
+		 */
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_AUTONEG_ADV,
+					    &mii_nway_adv_reg);
+		if (ret_val)
+			goto out;
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_LP_ABILITY,
+					    &mii_nway_lp_ability_reg);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Two bits in the Auto Negotiation Advertisement Register
+		 * (Address 4) and two bits in the Auto Negotiation Base
+		 * Page Ability Register (Address 5) determine flow control
+		 * for both the PHY and the link partner.  The following
+		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+		 * 1999, describes these PAUSE resolution bits and how flow
+		 * control is determined based upon these settings.
+		 * NOTE:  DC = Don't Care
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
+		 *   0   |    1    |   0   |   DC    | e1000_fc_none
+		 *   0   |    1    |   1   |    0    | e1000_fc_none
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 *   1   |    0    |   0   |   DC    | e1000_fc_none
+		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+		 *   1   |    1    |   0   |    0    | e1000_fc_none
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 *
+		 * Are both PAUSE bits set to 1?  If so, this implies
+		 * Symmetric Flow Control is enabled at both ends.  The
+		 * ASM_DIR bits are irrelevant per the spec.
+		 *
+		 * For Symmetric Flow Control:
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
+		 *
+		 */
+		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+			/*
+			 * Now we need to check if the user selected RX ONLY
+			 * of pause frames.  In this case, we had to advertise
+			 * FULL flow control because we could not advertise RX
+			 * ONLY. Hence, we must now check to see if we need to
+			 * turn OFF  the TRANSMISSION of PAUSE frames.
+			 */
+			if (hw->fc.original_type == e1000_fc_full) {
+				hw->fc.type = e1000_fc_full;
+				hw_dbg(hw, "Flow Control = FULL.\r\n");
+			} else {
+				hw->fc.type = e1000_fc_rx_pause;
+				hw_dbg(hw, "Flow Control = "
+					 "RX PAUSE frames only.\r\n");
+			}
+		}
+		/*
+		 * For receiving PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 */
+		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+			  (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+			  (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+			  (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			hw->fc.type = e1000_fc_tx_pause;
+			hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n");
+		}
+		/*
+		 * For transmitting PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 */
+		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+			 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			hw->fc.type = e1000_fc_rx_pause;
+			hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
+		}
+		/*
+		 * Per the IEEE spec, at this point flow control should be
+		 * disabled.  However, we want to consider that we could
+		 * be connected to a legacy switch that doesn't advertise
+		 * desired flow control, but can be forced on the link
+		 * partner.  So if we advertised no flow control, that is
+		 * what we will resolve to.  If we advertised some kind of
+		 * receive capability (Rx Pause Only or Full Flow Control)
+		 * and the link partner advertised none, we will configure
+		 * ourselves to enable Rx Flow Control only.  We can do
+		 * this safely for two reasons:  If the link partner really
+		 * didn't want flow control enabled, and we enable Rx, no
+		 * harm done since we won't be receiving any PAUSE frames
+		 * anyway.  If the intent on the link partner was to have
+		 * flow control enabled, then by us enabling RX only, we
+		 * can at least receive pause frames and process them.
+		 * This is a good idea because in most cases, since we are
+		 * predominantly a server NIC, more times than not we will
+		 * be asked to delay transmission of packets than asking
+		 * our link partner to pause transmission of frames.
+		 */
+		else if ((hw->fc.original_type == e1000_fc_none ||
+			  hw->fc.original_type == e1000_fc_tx_pause) ||
+			 hw->fc.strict_ieee) {
+			hw->fc.type = e1000_fc_none;
+			hw_dbg(hw, "Flow Control = NONE.\r\n");
+		} else {
+			hw->fc.type = e1000_fc_rx_pause;
+			hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
+		}
+
+		/*
+		 * Now we need to do one last check...  If we auto-
+		 * negotiated to HALF DUPLEX, flow control should not be
+		 * enabled per IEEE 802.3 spec.
+		 */
+		ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
+		if (ret_val) {
+			hw_dbg(hw, "Error getting link speed and duplex\n");
+			goto out;
+		}
+
+		if (duplex == HALF_DUPLEX)
+			hw->fc.type = e1000_fc_none;
+
+		/*
+		 * Now we call a subroutine to actually force the MAC
+		 * controller to use the correct flow control settings.
+		 */
+		ret_val = igb_force_mac_fc(hw);
+		if (ret_val) {
+			hw_dbg(hw, "Error forcing flow control settings\n");
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_speed_and_duplex_copper - Retreive current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Read the status register for the current speed/duplex and store the current
+ *  speed and duplex for copper connections.
+ **/
+s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
+				      u16 *duplex)
+{
+	u32 status;
+
+	status = rd32(E1000_STATUS);
+	if (status & E1000_STATUS_SPEED_1000) {
+		*speed = SPEED_1000;
+		hw_dbg(hw, "1000 Mbs, ");
+	} else if (status & E1000_STATUS_SPEED_100) {
+		*speed = SPEED_100;
+		hw_dbg(hw, "100 Mbs, ");
+	} else {
+		*speed = SPEED_10;
+		hw_dbg(hw, "10 Mbs, ");
+	}
+
+	if (status & E1000_STATUS_FD) {
+		*duplex = FULL_DUPLEX;
+		hw_dbg(hw, "Full Duplex\n");
+	} else {
+		*duplex = HALF_DUPLEX;
+		hw_dbg(hw, "Half Duplex\n");
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_get_hw_semaphore - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ **/
+s32 igb_get_hw_semaphore(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 ret_val = 0;
+	s32 timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	/* Get the SW semaphore */
+	while (i < timeout) {
+		swsm = rd32(E1000_SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+
+		udelay(50);
+		i++;
+	}
+
+	if (i == timeout) {
+		hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	/* Get the FW semaphore. */
+	for (i = 0; i < timeout; i++) {
+		swsm = rd32(E1000_SWSM);
+		wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI)
+			break;
+
+		udelay(50);
+	}
+
+	if (i == timeout) {
+		/* Release semaphores */
+		igb_put_hw_semaphore(hw);
+		hw_dbg(hw, "Driver can't access the NVM\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_put_hw_semaphore - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+void igb_put_hw_semaphore(struct e1000_hw *hw)
+{
+	u32 swsm;
+
+	swsm = rd32(E1000_SWSM);
+
+	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+
+	wr32(E1000_SWSM, swsm);
+}
+
+/**
+ *  e1000_get_auto_rd_done - Check for auto read completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Check EEPROM for Auto Read done bit.
+ **/
+s32 igb_get_auto_rd_done(struct e1000_hw *hw)
+{
+	s32 i = 0;
+	s32 ret_val = 0;
+
+
+	while (i < AUTO_READ_DONE_TIMEOUT) {
+		if (rd32(E1000_EECD) & E1000_EECD_AUTO_RD)
+			break;
+		msleep(1);
+		i++;
+	}
+
+	if (i == AUTO_READ_DONE_TIMEOUT) {
+		hw_dbg(hw, "Auto read by HW from NVM has not completed.\n");
+		ret_val = -E1000_ERR_RESET;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_valid_led_default - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	ret_val = hw->nvm.ops.read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		goto out;
+	}
+
+	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_id_led_init -
+ *  @hw: pointer to the HW structure
+ *
+ **/
+s32 igb_id_led_init(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	const u32 ledctl_mask = 0x000000FF;
+	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+	u16 data, i, temp;
+	const u16 led_mask = 0x0F;
+
+	ret_val = igb_valid_led_default(hw, &data);
+	if (ret_val)
+		goto out;
+
+	mac->ledctl_default = rd32(E1000_LEDCTL);
+	mac->ledctl_mode1 = mac->ledctl_default;
+	mac->ledctl_mode2 = mac->ledctl_default;
+
+	for (i = 0; i < 4; i++) {
+		temp = (data >> (i << 2)) & led_mask;
+		switch (temp) {
+		case ID_LED_ON1_DEF2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_ON1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_OFF1_DEF2:
+		case ID_LED_OFF1_ON2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+		switch (temp) {
+		case ID_LED_DEF1_ON2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_OFF1_ON2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_DEF1_OFF2:
+		case ID_LED_ON1_OFF2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_cleanup_led - Set LED config to default operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Remove the current LED configuration and set the LED configuration
+ *  to the default value, saved from the EEPROM.
+ **/
+s32 igb_cleanup_led(struct e1000_hw *hw)
+{
+	wr32(E1000_LEDCTL, hw->mac.ledctl_default);
+	return 0;
+}
+
+/**
+ *  e1000_blink_led - Blink LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Blink the led's which are set to be on.
+ **/
+s32 igb_blink_led(struct e1000_hw *hw)
+{
+	u32 ledctl_blink = 0;
+	u32 i;
+
+	if (hw->phy.media_type == e1000_media_type_fiber) {
+		/* always blink LED0 for PCI-E fiber */
+		ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+		     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+	} else {
+		/*
+		 * set the blink bit for each LED that's "on" (0x0E)
+		 * in ledctl_mode2
+		 */
+		ledctl_blink = hw->mac.ledctl_mode2;
+		for (i = 0; i < 4; i++)
+			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+			    E1000_LEDCTL_MODE_LED_ON)
+				ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+						 (i * 8));
+	}
+
+	wr32(E1000_LEDCTL, ledctl_blink);
+
+	return 0;
+}
+
+/**
+ *  e1000_led_off - Turn LED off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED off.
+ **/
+s32 igb_led_off(struct e1000_hw *hw)
+{
+	u32 ctrl;
+
+	switch (hw->phy.media_type) {
+	case e1000_media_type_fiber:
+		ctrl = rd32(E1000_CTRL);
+		ctrl |= E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		wr32(E1000_CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		wr32(E1000_LEDCTL, hw->mac.ledctl_mode1);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_disable_pcie_master - Disables PCI-express master access
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns 0 (0) if successful, else returns -10
+ *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued
+ *  the master requests to be disabled.
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests.
+ **/
+s32 igb_disable_pcie_master(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 timeout = MASTER_DISABLE_TIMEOUT;
+	s32 ret_val = 0;
+
+	if (hw->bus.type != e1000_bus_type_pci_express)
+		goto out;
+
+	ctrl = rd32(E1000_CTRL);
+	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+	wr32(E1000_CTRL, ctrl);
+
+	while (timeout) {
+		if (!(rd32(E1000_STATUS) &
+		      E1000_STATUS_GIO_MASTER_ENABLE))
+			break;
+		udelay(100);
+		timeout--;
+	}
+
+	if (!timeout) {
+		hw_dbg(hw, "Master requests are pending.\n");
+		ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_reset_adaptive - Reset Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void igb_reset_adaptive(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	if (!mac->adaptive_ifs) {
+		hw_dbg(hw, "Not in Adaptive IFS mode!\n");
+		goto out;
+	}
+
+	if (!mac->ifs_params_forced) {
+		mac->current_ifs_val = 0;
+		mac->ifs_min_val = IFS_MIN;
+		mac->ifs_max_val = IFS_MAX;
+		mac->ifs_step_size = IFS_STEP;
+		mac->ifs_ratio = IFS_RATIO;
+	}
+
+	mac->in_ifs_mode = false;
+	wr32(E1000_AIT, 0);
+out:
+	return;
+}
+
+/**
+ *  e1000_update_adaptive - Update Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Update the Adaptive Interframe Spacing Throttle value based on the
+ *  time between transmitted packets and time between collisions.
+ **/
+void igb_update_adaptive(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	if (!mac->adaptive_ifs) {
+		hw_dbg(hw, "Not in Adaptive IFS mode!\n");
+		goto out;
+	}
+
+	if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
+		if (mac->tx_packet_delta > MIN_NUM_XMITS) {
+			mac->in_ifs_mode = true;
+			if (mac->current_ifs_val < mac->ifs_max_val) {
+				if (!mac->current_ifs_val)
+					mac->current_ifs_val = mac->ifs_min_val;
+				else
+					mac->current_ifs_val +=
+						mac->ifs_step_size;
+				wr32(E1000_AIT,
+						mac->current_ifs_val);
+			}
+		}
+	} else {
+		if (mac->in_ifs_mode &&
+		    (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
+			mac->current_ifs_val = 0;
+			mac->in_ifs_mode = false;
+			wr32(E1000_AIT, 0);
+		}
+	}
+out:
+	return;
+}
+
+/**
+ *  e1000_validate_mdi_setting - Verify MDI/MDIx settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify that when not using auto-negotitation that MDI/MDIx is correctly
+ *  set, which is forced to MDI mode only.
+ **/
+s32 igb_validate_mdi_setting(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+
+	if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) {
+		hw_dbg(hw, "Invalid MDI setting detected\n");
+		hw->phy.mdix = 1;
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_8bit_ctrl_reg - Write a 8bit CTRL register
+ *  @hw: pointer to the HW structure
+ *  @reg: 32bit register offset such as E1000_SCTL
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Writes an address/data control type register.  There are several of these
+ *  and they all have the format address << 8 | data and bit 31 is polled for
+ *  completion.
+ **/
+s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
+			      u32 offset, u8 data)
+{
+	u32 i, regvalue = 0;
+	s32 ret_val = 0;
+
+	/* Set up the address and data */
+	regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT);
+	wr32(reg, regvalue);
+
+	/* Poll the ready bit to see if the MDI read completed */
+	for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
+		udelay(5);
+		regvalue = rd32(reg);
+		if (regvalue & E1000_GEN_CTL_READY)
+			break;
+	}
+	if (!(regvalue & E1000_GEN_CTL_READY)) {
+		hw_dbg(hw, "Reg %08x did not indicate ready\n", reg);
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_enable_mng_pass_thru - Enable processing of ARP's
+ *  @hw: pointer to the HW structure
+ *
+ *  Verifies the hardware needs to allow ARPs to be processed by the host.
+ **/
+bool igb_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+	u32 manc;
+	u32 fwsm, factps;
+	bool ret_val = false;
+
+	if (!hw->mac.asf_firmware_present)
+		goto out;
+
+	manc = rd32(E1000_MANC);
+
+	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+		goto out;
+
+	if (hw->mac.arc_subsystem_valid) {
+		fwsm = rd32(E1000_FWSM);
+		factps = rd32(E1000_FACTPS);
+
+		if (!(factps & E1000_FACTPS_MNGCG) &&
+		    ((fwsm & E1000_FWSM_MODE_MASK) ==
+		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+			ret_val = true;
+			goto out;
+		}
+	} else {
+		if ((manc & E1000_MANC_SMBUS_EN) &&
+		    !(manc & E1000_MANC_ASF_EN)) {
+			ret_val = true;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h
new file mode 100644
index 000000000000..326b6592307b
--- /dev/null
+++ b/drivers/net/igb/e1000_mac.h
@@ -0,0 +1,98 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_MAC_H_
+#define _E1000_MAC_H_
+
+#include "e1000_hw.h"
+
+#include "e1000_phy.h"
+#include "e1000_nvm.h"
+#include "e1000_defines.h"
+
+/*
+ * Functions that should not be called directly from drivers but can be used
+ * by other files in this 'shared code'
+ */
+s32  igb_blink_led(struct e1000_hw *hw);
+s32  igb_check_for_copper_link(struct e1000_hw *hw);
+s32  igb_cleanup_led(struct e1000_hw *hw);
+s32  igb_config_fc_after_link_up(struct e1000_hw *hw);
+s32  igb_disable_pcie_master(struct e1000_hw *hw);
+s32  igb_force_mac_fc(struct e1000_hw *hw);
+s32  igb_get_auto_rd_done(struct e1000_hw *hw);
+s32  igb_get_bus_info_pcie(struct e1000_hw *hw);
+s32  igb_get_hw_semaphore(struct e1000_hw *hw);
+s32  igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
+				       u16 *duplex);
+s32  igb_id_led_init(struct e1000_hw *hw);
+s32  igb_led_off(struct e1000_hw *hw);
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+			       u8 *mc_addr_list, u32 mc_addr_count,
+			       u32 rar_used_count, u32 rar_count);
+s32  igb_setup_link(struct e1000_hw *hw);
+s32  igb_validate_mdi_setting(struct e1000_hw *hw);
+s32  igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
+			       u32 offset, u8 data);
+
+void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
+void igb_clear_vfta(struct e1000_hw *hw);
+void igb_config_collision_dist(struct e1000_hw *hw);
+void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
+void igb_put_hw_semaphore(struct e1000_hw *hw);
+void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
+s32  igb_check_alt_mac_addr(struct e1000_hw *hw);
+void igb_remove_device(struct e1000_hw *hw);
+void igb_reset_adaptive(struct e1000_hw *hw);
+void igb_update_adaptive(struct e1000_hw *hw);
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
+
+bool igb_enable_mng_pass_thru(struct e1000_hw *hw);
+
+enum e1000_mng_mode {
+	e1000_mng_mode_none = 0,
+	e1000_mng_mode_asf,
+	e1000_mng_mode_pt,
+	e1000_mng_mode_ipmi,
+	e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG    0x20000000
+
+#define E1000_FWSM_MODE_MASK  0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT       10
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN    0x2
+
+#define E1000_HICR_EN              0x01  /* Enable bit - RO */
+/* Driver sets this bit when done to put command in RAM */
+#define E1000_HICR_C               0x02
+
+extern void e1000_init_function_pointers_82575(struct e1000_hw *hw);
+
+#endif
diff --git a/drivers/net/igb/e1000_nvm.c b/drivers/net/igb/e1000_nvm.c
new file mode 100644
index 000000000000..2897106fee92
--- /dev/null
+++ b/drivers/net/igb/e1000_nvm.c
@@ -0,0 +1,605 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/if_ether.h>
+#include <linux/delay.h>
+
+#include "e1000_mac.h"
+#include "e1000_nvm.h"
+
+/**
+ *  e1000_raise_eec_clk - Raise EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Enable/Raise the EEPROM clock bit.
+ **/
+static void igb_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd | E1000_EECD_SK;
+	wr32(E1000_EECD, *eecd);
+	wrfl();
+	udelay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000_lower_eec_clk - Lower EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Clear/Lower the EEPROM clock bit.
+ **/
+static void igb_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd & ~E1000_EECD_SK;
+	wr32(E1000_EECD, *eecd);
+	wrfl();
+	udelay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @data: data to send to the EEPROM
+ *  @count: number of bits to shift out
+ *
+ *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
+ *  "data" parameter will be shifted out to the EEPROM one bit at a time.
+ *  In order to do this, "data" must be broken down into bits.
+ **/
+static void igb_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = rd32(E1000_EECD);
+	u32 mask;
+
+	mask = 0x01 << (count - 1);
+	if (nvm->type == e1000_nvm_eeprom_microwire)
+		eecd &= ~E1000_EECD_DO;
+	else if (nvm->type == e1000_nvm_eeprom_spi)
+		eecd |= E1000_EECD_DO;
+
+	do {
+		eecd &= ~E1000_EECD_DI;
+
+		if (data & mask)
+			eecd |= E1000_EECD_DI;
+
+		wr32(E1000_EECD, eecd);
+		wrfl();
+
+		udelay(nvm->delay_usec);
+
+		igb_raise_eec_clk(hw, &eecd);
+		igb_lower_eec_clk(hw, &eecd);
+
+		mask >>= 1;
+	} while (mask);
+
+	eecd &= ~E1000_EECD_DI;
+	wr32(E1000_EECD, eecd);
+}
+
+/**
+ *  e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @count: number of bits to shift in
+ *
+ *  In order to read a register from the EEPROM, we need to shift 'count' bits
+ *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
+ *  the EEPROM (setting the SK bit), and then reading the value of the data out
+ *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
+ *  always be clear.
+ **/
+static u16 igb_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
+{
+	u32 eecd;
+	u32 i;
+	u16 data;
+
+	eecd = rd32(E1000_EECD);
+
+	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+	data = 0;
+
+	for (i = 0; i < count; i++) {
+		data <<= 1;
+		igb_raise_eec_clk(hw, &eecd);
+
+		eecd = rd32(E1000_EECD);
+
+		eecd &= ~E1000_EECD_DI;
+		if (eecd & E1000_EECD_DO)
+			data |= 1;
+
+		igb_lower_eec_clk(hw, &eecd);
+	}
+
+	return data;
+}
+
+/**
+ *  e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ *  @hw: pointer to the HW structure
+ *  @ee_reg: EEPROM flag for polling
+ *
+ *  Polls the EEPROM status bit for either read or write completion based
+ *  upon the value of 'ee_reg'.
+ **/
+static s32 igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+	u32 attempts = 100000;
+	u32 i, reg = 0;
+	s32 ret_val = -E1000_ERR_NVM;
+
+	for (i = 0; i < attempts; i++) {
+		if (ee_reg == E1000_NVM_POLL_READ)
+			reg = rd32(E1000_EERD);
+		else
+			reg = rd32(E1000_EEWR);
+
+		if (reg & E1000_NVM_RW_REG_DONE) {
+			ret_val = 0;
+			break;
+		}
+
+		udelay(5);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_acquire_nvm - Generic request for access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ *  Return successful if access grant bit set, else clear the request for
+ *  EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+s32 igb_acquire_nvm(struct e1000_hw *hw)
+{
+	u32 eecd = rd32(E1000_EECD);
+	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+	s32 ret_val = 0;
+
+
+	wr32(E1000_EECD, eecd | E1000_EECD_REQ);
+	eecd = rd32(E1000_EECD);
+
+	while (timeout) {
+		if (eecd & E1000_EECD_GNT)
+			break;
+		udelay(5);
+		eecd = rd32(E1000_EECD);
+		timeout--;
+	}
+
+	if (!timeout) {
+		eecd &= ~E1000_EECD_REQ;
+		wr32(E1000_EECD, eecd);
+		hw_dbg(hw, "Could not acquire NVM grant\n");
+		ret_val = -E1000_ERR_NVM;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_standby_nvm - Return EEPROM to standby state
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the EEPROM to a standby state.
+ **/
+static void igb_standby_nvm(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = rd32(E1000_EECD);
+
+	if (nvm->type == e1000_nvm_eeprom_microwire) {
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+		wr32(E1000_EECD, eecd);
+		wrfl();
+		udelay(nvm->delay_usec);
+
+		igb_raise_eec_clk(hw, &eecd);
+
+		/* Select EEPROM */
+		eecd |= E1000_EECD_CS;
+		wr32(E1000_EECD, eecd);
+		wrfl();
+		udelay(nvm->delay_usec);
+
+		igb_lower_eec_clk(hw, &eecd);
+	} else if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Toggle CS to flush commands */
+		eecd |= E1000_EECD_CS;
+		wr32(E1000_EECD, eecd);
+		wrfl();
+		udelay(nvm->delay_usec);
+		eecd &= ~E1000_EECD_CS;
+		wr32(E1000_EECD, eecd);
+		wrfl();
+		udelay(nvm->delay_usec);
+	}
+}
+
+/**
+ *  e1000_stop_nvm - Terminate EEPROM command
+ *  @hw: pointer to the HW structure
+ *
+ *  Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+static void e1000_stop_nvm(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	eecd = rd32(E1000_EECD);
+	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+		/* Pull CS high */
+		eecd |= E1000_EECD_CS;
+		igb_lower_eec_clk(hw, &eecd);
+	} else if (hw->nvm.type == e1000_nvm_eeprom_microwire) {
+		/* CS on Microcwire is active-high */
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+		wr32(E1000_EECD, eecd);
+		igb_raise_eec_clk(hw, &eecd);
+		igb_lower_eec_clk(hw, &eecd);
+	}
+}
+
+/**
+ *  e1000_release_nvm - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void igb_release_nvm(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	e1000_stop_nvm(hw);
+
+	eecd = rd32(E1000_EECD);
+	eecd &= ~E1000_EECD_REQ;
+	wr32(E1000_EECD, eecd);
+}
+
+/**
+ *  e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups the EEPROM for reading and writing.
+ **/
+static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = rd32(E1000_EECD);
+	s32 ret_val = 0;
+	u16 timeout = 0;
+	u8 spi_stat_reg;
+
+
+	if (nvm->type == e1000_nvm_eeprom_microwire) {
+		/* Clear SK and DI */
+		eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+		wr32(E1000_EECD, eecd);
+		/* Set CS */
+		eecd |= E1000_EECD_CS;
+		wr32(E1000_EECD, eecd);
+	} else if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Clear SK and CS */
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+		wr32(E1000_EECD, eecd);
+		udelay(1);
+		timeout = NVM_MAX_RETRY_SPI;
+
+		/*
+		 * Read "Status Register" repeatedly until the LSB is cleared.
+		 * The EEPROM will signal that the command has been completed
+		 * by clearing bit 0 of the internal status register.  If it's
+		 * not cleared within 'timeout', then error out.
+		 */
+		while (timeout) {
+			igb_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+						 hw->nvm.opcode_bits);
+			spi_stat_reg = (u8)igb_shift_in_eec_bits(hw, 8);
+			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+				break;
+
+			udelay(5);
+			igb_standby_nvm(hw);
+			timeout--;
+		}
+
+		if (!timeout) {
+			hw_dbg(hw, "SPI NVM Status error\n");
+			ret_val = -E1000_ERR_NVM;
+			goto out;
+		}
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_nvm_eerd - Reads EEPROM using EERD register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i, eerd = 0;
+	s32 ret_val = 0;
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	for (i = 0; i < words; i++) {
+		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+		       E1000_NVM_RW_REG_START;
+
+		wr32(E1000_EERD, eerd);
+		ret_val = igb_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+		if (ret_val)
+			break;
+
+		data[i] = (rd32(E1000_EERD) >>
+			   E1000_NVM_RW_REG_DATA);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_nvm_spi - Write to EEPROM using SPI
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  Writes data to EEPROM at offset using SPI interface.
+ *
+ *  If e1000_update_nvm_checksum is not called after this function , the
+ *  EEPROM will most likley contain an invalid checksum.
+ **/
+s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32 ret_val;
+	u16 widx = 0;
+
+	/*
+	 * A check for invalid values:  offset too large, too many words,
+	 * and not enough words.
+	 */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+	ret_val = hw->nvm.ops.acquire_nvm(hw);
+	if (ret_val)
+		goto out;
+
+	msleep(10);
+
+	while (widx < words) {
+		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+		ret_val = igb_ready_nvm_eeprom(hw);
+		if (ret_val)
+			goto release;
+
+		igb_standby_nvm(hw);
+
+		/* Send the WRITE ENABLE command (8 bit opcode) */
+		igb_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+					 nvm->opcode_bits);
+
+		igb_standby_nvm(hw);
+
+		/*
+		 * Some SPI eeproms use the 8th address bit embedded in the
+		 * opcode
+		 */
+		if ((nvm->address_bits == 8) && (offset >= 128))
+			write_opcode |= NVM_A8_OPCODE_SPI;
+
+		/* Send the Write command (8-bit opcode + addr) */
+		igb_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+		igb_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
+					 nvm->address_bits);
+
+		/* Loop to allow for up to whole page write of eeprom */
+		while (widx < words) {
+			u16 word_out = data[widx];
+			word_out = (word_out >> 8) | (word_out << 8);
+			igb_shift_out_eec_bits(hw, word_out, 16);
+			widx++;
+
+			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+				igb_standby_nvm(hw);
+				break;
+			}
+		}
+	}
+
+	msleep(10);
+release:
+	hw->nvm.ops.release_nvm(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_part_num - Read device part number
+ *  @hw: pointer to the HW structure
+ *  @part_num: pointer to device part number
+ *
+ *  Reads the product board assembly (PBA) number from the EEPROM and stores
+ *  the value in part_num.
+ **/
+s32 igb_read_part_num(struct e1000_hw *hw, u32 *part_num)
+{
+	s32  ret_val;
+	u16 nvm_data;
+
+	ret_val = hw->nvm.ops.read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		goto out;
+	}
+	*part_num = (u32)(nvm_data << 16);
+
+	ret_val = hw->nvm.ops.read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		goto out;
+	}
+	*part_num |= nvm_data;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_mac_addr - Read device MAC address
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the device MAC address from the EEPROM and stores the value.
+ *  Since devices with two ports use the same EEPROM, we increment the
+ *  last bit in the MAC address for the second port.
+ **/
+s32 igb_read_mac_addr(struct e1000_hw *hw)
+{
+	s32  ret_val = 0;
+	u16 offset, nvm_data, i;
+
+	for (i = 0; i < ETH_ALEN; i += 2) {
+		offset = i >> 1;
+		ret_val = hw->nvm.ops.read_nvm(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			hw_dbg(hw, "NVM Read Error\n");
+			goto out;
+		}
+		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
+		hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
+	}
+
+	/* Flip last bit of mac address if we're on second port */
+	if (hw->bus.func == E1000_FUNC_1)
+		hw->mac.perm_addr[5] ^= 1;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_validate_nvm_checksum - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 igb_validate_nvm_checksum(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+		ret_val = hw->nvm.ops.read_nvm(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			hw_dbg(hw, "NVM Read Error\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+
+	if (checksum != (u16) NVM_SUM) {
+		hw_dbg(hw, "NVM Checksum Invalid\n");
+		ret_val = -E1000_ERR_NVM;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_update_nvm_checksum - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ **/
+s32 igb_update_nvm_checksum(struct e1000_hw *hw)
+{
+	s32  ret_val;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+		ret_val = hw->nvm.ops.read_nvm(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			hw_dbg(hw, "NVM Read Error while updating checksum.\n");
+			goto out;
+		}
+		checksum += nvm_data;
+	}
+	checksum = (u16) NVM_SUM - checksum;
+	ret_val = hw->nvm.ops.write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum);
+	if (ret_val)
+		hw_dbg(hw, "NVM Write Error while updating checksum.\n");
+
+out:
+	return ret_val;
+}
+
diff --git a/drivers/net/igb/e1000_nvm.h b/drivers/net/igb/e1000_nvm.h
new file mode 100644
index 000000000000..1041c34dcbe1
--- /dev/null
+++ b/drivers/net/igb/e1000_nvm.h
@@ -0,0 +1,40 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_NVM_H_
+#define _E1000_NVM_H_
+
+s32  igb_acquire_nvm(struct e1000_hw *hw);
+void igb_release_nvm(struct e1000_hw *hw);
+s32  igb_read_mac_addr(struct e1000_hw *hw);
+s32  igb_read_part_num(struct e1000_hw *hw, u32 *part_num);
+s32  igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32  igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+s32  igb_validate_nvm_checksum(struct e1000_hw *hw);
+s32  igb_update_nvm_checksum(struct e1000_hw *hw);
+
+#endif
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
new file mode 100644
index 000000000000..08a86b107229
--- /dev/null
+++ b/drivers/net/igb/e1000_phy.c
@@ -0,0 +1,1807 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/if_ether.h>
+#include <linux/delay.h>
+
+#include "e1000_mac.h"
+#include "e1000_phy.h"
+
+static s32  igb_get_phy_cfg_done(struct e1000_hw *hw);
+static void igb_release_phy(struct e1000_hw *hw);
+static s32  igb_acquire_phy(struct e1000_hw *hw);
+static s32  igb_phy_reset_dsp(struct e1000_hw *hw);
+static s32  igb_phy_setup_autoneg(struct e1000_hw *hw);
+static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
+					       u16 *phy_ctrl);
+static s32  igb_wait_autoneg(struct e1000_hw *hw);
+
+/* Cable length tables */
+static const u16 e1000_m88_cable_length_table[] =
+	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
+		(sizeof(e1000_m88_cable_length_table) / \
+		 sizeof(e1000_m88_cable_length_table[0]))
+
+static const u16 e1000_igp_2_cable_length_table[] =
+    { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+      0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+      6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+      21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+      40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+      60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+      83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+      104, 109, 114, 118, 121, 124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+		(sizeof(e1000_igp_2_cable_length_table) / \
+		 sizeof(e1000_igp_2_cable_length_table[0]))
+
+/**
+ *  e1000_check_reset_block - Check if PHY reset is blocked
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the PHY management control register and check whether a PHY reset
+ *  is blocked.  If a reset is not blocked return 0, otherwise
+ *  return E1000_BLK_PHY_RESET (12).
+ **/
+s32 igb_check_reset_block(struct e1000_hw *hw)
+{
+	u32 manc;
+
+	manc = rd32(E1000_MANC);
+
+	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+	       E1000_BLK_PHY_RESET : 0;
+}
+
+/**
+ *  e1000_get_phy_id - Retrieve the PHY ID and revision
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY registers and stores the PHY ID and possibly the PHY
+ *  revision in the hardware structure.
+ **/
+s32 igb_get_phy_id(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = 0;
+	u16 phy_id;
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, PHY_ID1, &phy_id);
+	if (ret_val)
+		goto out;
+
+	phy->id = (u32)(phy_id << 16);
+	udelay(20);
+	ret_val = hw->phy.ops.read_phy_reg(hw, PHY_ID2, &phy_id);
+	if (ret_val)
+		goto out;
+
+	phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+	phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_reset_dsp - Reset PHY DSP
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the digital signal processor.
+ **/
+static s32 igb_phy_reset_dsp(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_mdic - Read MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the MDI control regsiter in the PHY at offset and stores the
+ *  information read to data.
+ **/
+static s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+	s32 ret_val = 0;
+
+	if (offset > MAX_PHY_REG_ADDRESS) {
+		hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+		ret_val = -E1000_ERR_PARAM;
+		goto out;
+	}
+
+	/*
+	 * Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+		(phy->addr << E1000_MDIC_PHY_SHIFT) |
+		(E1000_MDIC_OP_READ));
+
+	wr32(E1000_MDIC, mdic);
+
+	/*
+	 * Poll the ready bit to see if the MDI read completed
+	 * Increasing the time out as testing showed failures with
+	 * the lower time out
+	 */
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+		udelay(50);
+		mdic = rd32(E1000_MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		hw_dbg(hw, "MDI Read did not complete\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		hw_dbg(hw, "MDI Error\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	*data = (u16) mdic;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_mdic - Write MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write to register at offset
+ *
+ *  Writes data to MDI control register in the PHY at offset.
+ **/
+static s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+	s32 ret_val = 0;
+
+	if (offset > MAX_PHY_REG_ADDRESS) {
+		hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+		ret_val = -E1000_ERR_PARAM;
+		goto out;
+	}
+
+	/*
+	 * Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = (((u32)data) |
+		(offset << E1000_MDIC_REG_SHIFT) |
+		(phy->addr << E1000_MDIC_PHY_SHIFT) |
+		(E1000_MDIC_OP_WRITE));
+
+	wr32(E1000_MDIC, mdic);
+
+	/*
+	 * Poll the ready bit to see if the MDI read completed
+	 * Increasing the time out as testing showed failures with
+	 * the lower time out
+	 */
+	for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
+		udelay(50);
+		mdic = rd32(E1000_MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		hw_dbg(hw, "MDI Write did not complete\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		hw_dbg(hw, "MDI Error\n");
+		ret_val = -E1000_ERR_PHY;
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_read_phy_reg_igp - Read igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val;
+
+	ret_val = igb_acquire_phy(hw);
+	if (ret_val)
+		goto out;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = igb_write_phy_reg_mdic(hw,
+						   IGP01E1000_PHY_PAGE_SELECT,
+						   (u16)offset);
+		if (ret_val) {
+			igb_release_phy(hw);
+			goto out;
+		}
+	}
+
+	ret_val = igb_read_phy_reg_mdic(hw,
+					  MAX_PHY_REG_ADDRESS & offset,
+					  data);
+
+	igb_release_phy(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_igp - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val;
+
+	ret_val = igb_acquire_phy(hw);
+	if (ret_val)
+		goto out;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = igb_write_phy_reg_mdic(hw,
+						   IGP01E1000_PHY_PAGE_SELECT,
+						   (u16)offset);
+		if (ret_val) {
+			igb_release_phy(hw);
+			goto out;
+		}
+	}
+
+	ret_val = igb_write_phy_reg_mdic(hw,
+					   MAX_PHY_REG_ADDRESS & offset,
+					   data);
+
+	igb_release_phy(hw);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
+ *  and downshift values are set also.
+ **/
+s32 igb_copper_link_setup_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+
+	if (phy->reset_disable) {
+		ret_val = 0;
+		goto out;
+	}
+
+	/* Enable CRS on TX. This must be set for half-duplex operation. */
+	ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+					   &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+	/*
+	 * Options:
+	 *   MDI/MDI-X = 0 (default)
+	 *   0 - Auto for all speeds
+	 *   1 - MDI mode
+	 *   2 - MDI-X mode
+	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+	 */
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+	switch (phy->mdix) {
+	case 1:
+		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+		break;
+	case 2:
+		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+		break;
+	case 3:
+		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+		break;
+	case 0:
+	default:
+		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+		break;
+	}
+
+	/*
+	 * Options:
+	 *   disable_polarity_correction = 0 (default)
+	 *       Automatic Correction for Reversed Cable Polarity
+	 *   0 - Disabled
+	 *   1 - Enabled
+	 */
+	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+	if (phy->disable_polarity_correction == 1)
+		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+	ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+					    phy_data);
+	if (ret_val)
+		goto out;
+
+	if (phy->revision < E1000_REVISION_4) {
+		/*
+		 * Force TX_CLK in the Extended PHY Specific Control Register
+		 * to 25MHz clock.
+		 */
+		ret_val = hw->phy.ops.read_phy_reg(hw,
+					     M88E1000_EXT_PHY_SPEC_CTRL,
+					     &phy_data);
+		if (ret_val)
+			goto out;
+
+		phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+		if ((phy->revision == E1000_REVISION_2) &&
+		    (phy->id == M88E1111_I_PHY_ID)) {
+			/* 82573L PHY - set the downshift counter to 5x. */
+			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+		} else {
+			/* Configure Master and Slave downshift values */
+			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+				      M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+				     M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+		}
+		ret_val = hw->phy.ops.write_phy_reg(hw,
+					     M88E1000_EXT_PHY_SPEC_CTRL,
+					     phy_data);
+		if (ret_val)
+			goto out;
+	}
+
+	/* Commit the changes. */
+	ret_val = igb_phy_sw_reset(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error committing the PHY changes\n");
+		goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_copper_link_setup_igp - Setup igp PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ *  igp PHY's.
+ **/
+s32 igb_copper_link_setup_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	if (phy->reset_disable) {
+		ret_val = 0;
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.reset_phy(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error resetting the PHY.\n");
+		goto out;
+	}
+
+	/* Wait 15ms for MAC to configure PHY from NVM settings. */
+	msleep(15);
+
+	/*
+	 * The NVM settings will configure LPLU in D3 for
+	 * non-IGP1 PHYs.
+	 */
+	if (phy->type == e1000_phy_igp) {
+		/* disable lplu d3 during driver init */
+		if (hw->phy.ops.set_d3_lplu_state)
+			ret_val = hw->phy.ops.set_d3_lplu_state(hw, false);
+		if (ret_val) {
+			hw_dbg(hw, "Error Disabling LPLU D3\n");
+			goto out;
+		}
+	}
+
+	/* disable lplu d0 during driver init */
+	ret_val = hw->phy.ops.set_d0_lplu_state(hw, false);
+	if (ret_val) {
+		hw_dbg(hw, "Error Disabling LPLU D0\n");
+		goto out;
+	}
+	/* Configure mdi-mdix settings */
+	ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+	if (ret_val)
+		goto out;
+
+	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+	switch (phy->mdix) {
+	case 1:
+		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 2:
+		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 0:
+	default:
+		data |= IGP01E1000_PSCR_AUTO_MDIX;
+		break;
+	}
+	ret_val = hw->phy.ops.write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, data);
+	if (ret_val)
+		goto out;
+
+	/* set auto-master slave resolution settings */
+	if (hw->mac.autoneg) {
+		/*
+		 * when autonegotiation advertisement is only 1000Mbps then we
+		 * should disable SmartSpeed and enable Auto MasterSlave
+		 * resolution as hardware default.
+		 */
+		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+			/* Disable SmartSpeed */
+			ret_val = hw->phy.ops.read_phy_reg(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = hw->phy.ops.write_phy_reg(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				goto out;
+
+			/* Set auto Master/Slave resolution process */
+			ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_CTRL,
+							   &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~CR_1000T_MS_ENABLE;
+			ret_val = hw->phy.ops.write_phy_reg(hw, PHY_1000T_CTRL,
+							    data);
+			if (ret_val)
+				goto out;
+		}
+
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_CTRL, &data);
+		if (ret_val)
+			goto out;
+
+		/* load defaults for future use */
+		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+			((data & CR_1000T_MS_VALUE) ?
+			e1000_ms_force_master :
+			e1000_ms_force_slave) :
+			e1000_ms_auto;
+
+		switch (phy->ms_type) {
+		case e1000_ms_force_master:
+			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_force_slave:
+			data |= CR_1000T_MS_ENABLE;
+			data &= ~(CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_auto:
+			data &= ~CR_1000T_MS_ENABLE;
+		default:
+			break;
+		}
+		ret_val = hw->phy.ops.write_phy_reg(hw, PHY_1000T_CTRL, data);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs initial bounds checking on autoneg advertisement parameter, then
+ *  configure to advertise the full capability.  Setup the PHY to autoneg
+ *  and restart the negotiation process between the link partner.  If
+ *  autoneg_wait_to_complete, then wait for autoneg to complete before exiting.
+ **/
+s32 igb_copper_link_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_ctrl;
+
+	/*
+	 * Perform some bounds checking on the autoneg advertisement
+	 * parameter.
+	 */
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/*
+	 * If autoneg_advertised is zero, we assume it was not defaulted
+	 * by the calling code so we set to advertise full capability.
+	 */
+	if (phy->autoneg_advertised == 0)
+		phy->autoneg_advertised = phy->autoneg_mask;
+
+	hw_dbg(hw, "Reconfiguring auto-neg advertisement params\n");
+	ret_val = igb_phy_setup_autoneg(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error Setting up Auto-Negotiation\n");
+		goto out;
+	}
+	hw_dbg(hw, "Restarting Auto-Neg\n");
+
+	/*
+	 * Restart auto-negotiation by setting the Auto Neg Enable bit and
+	 * the Auto Neg Restart bit in the PHY control register.
+	 */
+	ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+	ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Does the user want to wait for Auto-Neg to complete here, or
+	 * check at a later time (for example, callback routine).
+	 */
+	if (phy->autoneg_wait_to_complete) {
+		ret_val = igb_wait_autoneg(hw);
+		if (ret_val) {
+			hw_dbg(hw, "Error while waiting for "
+				 "autoneg to complete\n");
+			goto out;
+		}
+	}
+
+	hw->mac.get_link_status = true;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the MII auto-neg advertisement register and/or the 1000T control
+ *  register and if the PHY is already setup for auto-negotiation, then
+ *  return successful.  Otherwise, setup advertisement and flow control to
+ *  the appropriate values for the wanted auto-negotiation.
+ **/
+static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 mii_autoneg_adv_reg;
+	u16 mii_1000t_ctrl_reg = 0;
+
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
+	ret_val = hw->phy.ops.read_phy_reg(hw, PHY_AUTONEG_ADV,
+					   &mii_autoneg_adv_reg);
+	if (ret_val)
+		goto out;
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		/* Read the MII 1000Base-T Control Register (Address 9). */
+		ret_val = hw->phy.ops.read_phy_reg(hw,
+					    PHY_1000T_CTRL,
+					    &mii_1000t_ctrl_reg);
+		if (ret_val)
+			goto out;
+	}
+
+	/*
+	 * Need to parse both autoneg_advertised and fc and set up
+	 * the appropriate PHY registers.  First we will parse for
+	 * autoneg_advertised software override.  Since we can advertise
+	 * a plethora of combinations, we need to check each bit
+	 * individually.
+	 */
+
+	/*
+	 * First we clear all the 10/100 mb speed bits in the Auto-Neg
+	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
+	 * the  1000Base-T Control Register (Address 9).
+	 */
+	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+				 NWAY_AR_100TX_HD_CAPS |
+				 NWAY_AR_10T_FD_CAPS   |
+				 NWAY_AR_10T_HD_CAPS);
+	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+	hw_dbg(hw, "autoneg_advertised %x\n", phy->autoneg_advertised);
+
+	/* Do we want to advertise 10 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+		hw_dbg(hw, "Advertise 10mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+	}
+
+	/* Do we want to advertise 10 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+		hw_dbg(hw, "Advertise 10mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+		hw_dbg(hw, "Advertise 100mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+		hw_dbg(hw, "Advertise 100mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+	}
+
+	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
+		hw_dbg(hw, "Advertise 1000mb Half duplex request denied!\n");
+
+	/* Do we want to advertise 1000 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+		hw_dbg(hw, "Advertise 1000mb Full duplex\n");
+		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+	}
+
+	/*
+	 * Check for a software override of the flow control settings, and
+	 * setup the PHY advertisement registers accordingly.  If
+	 * auto-negotiation is enabled, then software will have to set the
+	 * "PAUSE" bits to the correct value in the Auto-Negotiation
+	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+	 * negotiation.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames
+	 *          but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *          but we do not support receiving pause frames).
+	 *      3:  Both Rx and TX flow control (symmetric) are enabled.
+	 *  other:  No software override.  The flow control configuration
+	 *          in the EEPROM is used.
+	 */
+	switch (hw->fc.type) {
+	case e1000_fc_none:
+		/*
+		 * Flow control (RX & TX) is completely disabled by a
+		 * software over-ride.
+		 */
+		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_rx_pause:
+		/*
+		 * RX Flow control is enabled, and TX Flow control is
+		 * disabled, by a software over-ride.
+		 *
+		 * Since there really isn't a way to advertise that we are
+		 * capable of RX Pause ONLY, we will advertise that we
+		 * support both symmetric and asymmetric RX PAUSE.  Later
+		 * (in e1000_config_fc_after_link_up) we will disable the
+		 * hw's ability to send PAUSE frames.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_tx_pause:
+		/*
+		 * TX Flow control is enabled, and RX Flow control is
+		 * disabled, by a software over-ride.
+		 */
+		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+		break;
+	case e1000_fc_full:
+		/*
+		 * Flow control (both RX and TX) is enabled by a software
+		 * over-ride.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	default:
+		hw_dbg(hw, "Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.write_phy_reg(hw, PHY_AUTONEG_ADV,
+					    mii_autoneg_adv_reg);
+	if (ret_val)
+		goto out;
+
+	hw_dbg(hw, "Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		ret_val = hw->phy.ops.write_phy_reg(hw,
+					      PHY_1000T_CTRL,
+					      mii_1000t_ctrl_reg);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Waits for link and returns
+ *  successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	igb_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
+					   &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+	ret_val = hw->phy.ops.write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL,
+					    phy_data);
+	if (ret_val)
+		goto out;
+
+	hw_dbg(hw, "IGP PSCR: %X\n", phy_data);
+
+	udelay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		hw_dbg(hw,
+		       "Waiting for forced speed/duplex link on IGP phy.\n");
+
+		ret_val = igb_phy_has_link(hw,
+						     PHY_FORCE_LIMIT,
+						     100000,
+						     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link)
+			hw_dbg(hw, "Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = igb_phy_has_link(hw,
+						     PHY_FORCE_LIMIT,
+						     100000,
+						     &link);
+		if (ret_val)
+			goto out;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Resets the PHY to commit the
+ *  changes.  If time expires while waiting for link up, we reset the DSP.
+ *  After reset, TX_CLK and CRS on TX must be set.  Return successful upon
+ *  successful completion, else return corresponding error code.
+ **/
+s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	/*
+	 * Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+					   &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+	ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+					    phy_data);
+	if (ret_val)
+		goto out;
+
+	hw_dbg(hw, "M88E1000 PSCR: %X\n", phy_data);
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		goto out;
+
+	igb_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	/* Reset the phy to commit changes. */
+	phy_data |= MII_CR_RESET;
+
+	ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		goto out;
+
+	udelay(1);
+
+	if (phy->autoneg_wait_to_complete) {
+		hw_dbg(hw,
+		       "Waiting for forced speed/duplex link on M88 phy.\n");
+
+		ret_val = igb_phy_has_link(hw,
+						     PHY_FORCE_LIMIT,
+						     100000,
+						     &link);
+		if (ret_val)
+			goto out;
+
+		if (!link) {
+			/*
+			 * We didn't get link.
+			 * Reset the DSP and cross our fingers.
+			 */
+			ret_val = hw->phy.ops.write_phy_reg(hw,
+						      M88E1000_PHY_PAGE_SELECT,
+						      0x001d);
+			if (ret_val)
+				goto out;
+			ret_val = igb_phy_reset_dsp(hw);
+			if (ret_val)
+				goto out;
+		}
+
+		/* Try once more */
+		ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT,
+					     100000, &link);
+		if (ret_val)
+			goto out;
+	}
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+					   &phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * Resetting the phy means we need to re-force TX_CLK in the
+	 * Extended PHY Specific Control Register to 25MHz clock from
+	 * the reset value of 2.5MHz.
+	 */
+	phy_data |= M88E1000_EPSCR_TX_CLK_25;
+	ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+					    phy_data);
+	if (ret_val)
+		goto out;
+
+	/*
+	 * In addition, we must re-enable CRS on Tx for both half and full
+	 * duplex.
+	 */
+	ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+					   &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+	ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+					    phy_data);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ *  Forces speed and duplex on the PHY by doing the following: disable flow
+ *  control, force speed/duplex on the MAC, disable auto speed detection,
+ *  disable auto-negotiation, configure duplex, configure speed, configure
+ *  the collision distance, write configuration to CTRL register.  The
+ *  caller must write to the PHY_CONTROL register for these settings to
+ *  take affect.
+ **/
+static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
+					       u16 *phy_ctrl)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 ctrl;
+
+	/* Turn off flow control when forcing speed/duplex */
+	hw->fc.type = e1000_fc_none;
+
+	/* Force speed/duplex on the mac */
+	ctrl = rd32(E1000_CTRL);
+	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ctrl &= ~E1000_CTRL_SPD_SEL;
+
+	/* Disable Auto Speed Detection */
+	ctrl &= ~E1000_CTRL_ASDE;
+
+	/* Disable autoneg on the phy */
+	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+	/* Forcing Full or Half Duplex? */
+	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+		ctrl &= ~E1000_CTRL_FD;
+		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+		hw_dbg(hw, "Half Duplex\n");
+	} else {
+		ctrl |= E1000_CTRL_FD;
+		*phy_ctrl |= MII_CR_FULL_DUPLEX;
+		hw_dbg(hw, "Full Duplex\n");
+	}
+
+	/* Forcing 10mb or 100mb? */
+	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+		ctrl |= E1000_CTRL_SPD_100;
+		*phy_ctrl |= MII_CR_SPEED_100;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+		hw_dbg(hw, "Forcing 100mb\n");
+	} else {
+		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+		*phy_ctrl |= MII_CR_SPEED_10;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+		hw_dbg(hw, "Forcing 10mb\n");
+	}
+
+	igb_config_collision_dist(hw);
+
+	wr32(E1000_CTRL, ctrl);
+}
+
+/**
+ *  e1000_set_d3_lplu_state - Sets low power link up state for D3
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D3
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D3
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.
+ **/
+s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
+					   &data);
+	if (ret_val)
+		goto out;
+
+	if (!active) {
+		data &= ~IGP02E1000_PM_D3_LPLU;
+		ret_val = hw->phy.ops.write_phy_reg(hw,
+					     IGP02E1000_PHY_POWER_MGMT,
+					     data);
+		if (ret_val)
+			goto out;
+		/*
+		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained.
+		 */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = hw->phy.ops.read_phy_reg(hw,
+						    IGP01E1000_PHY_PORT_CONFIG,
+						    &data);
+			if (ret_val)
+				goto out;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = hw->phy.ops.write_phy_reg(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				goto out;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = hw->phy.ops.read_phy_reg(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     &data);
+			if (ret_val)
+				goto out;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = hw->phy.ops.write_phy_reg(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				goto out;
+		}
+	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+		data |= IGP02E1000_PM_D3_LPLU;
+		ret_val = hw->phy.ops.write_phy_reg(hw,
+					      IGP02E1000_PHY_POWER_MGMT,
+					      data);
+		if (ret_val)
+			goto out;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = hw->phy.ops.read_phy_reg(hw,
+					     IGP01E1000_PHY_PORT_CONFIG,
+					     &data);
+		if (ret_val)
+			goto out;
+
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = hw->phy.ops.write_phy_reg(hw,
+					      IGP01E1000_PHY_PORT_CONFIG,
+					      data);
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_downshift - Checks whether a downshift in speed occured
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  A downshift is detected by querying the PHY link health.
+ **/
+s32 igb_check_downshift(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	switch (phy->type) {
+	case e1000_phy_m88:
+	case e1000_phy_gg82563:
+		offset	= M88E1000_PHY_SPEC_STATUS;
+		mask	= M88E1000_PSSR_DOWNSHIFT;
+		break;
+	case e1000_phy_igp_2:
+	case e1000_phy_igp:
+	case e1000_phy_igp_3:
+		offset	= IGP01E1000_PHY_LINK_HEALTH;
+		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
+		break;
+	default:
+		/* speed downshift not supported */
+		phy->speed_downgraded = false;
+		ret_val = 0;
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->speed_downgraded = (phy_data & mask) ? true : false;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_m88 - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY specific status register.
+ **/
+static s32 igb_check_polarity_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+				      ? e1000_rev_polarity_reversed
+				      : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_igp - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY port status register, and the
+ *  current speed (since there is no polarity at 100Mbps).
+ **/
+static s32 igb_check_polarity_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data, offset, mask;
+
+	/*
+	 * Polarity is determined based on the speed of
+	 * our connection.
+	 */
+	ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+					   &data);
+	if (ret_val)
+		goto out;
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+		offset	= IGP01E1000_PHY_PCS_INIT_REG;
+		mask	= IGP01E1000_PHY_POLARITY_MASK;
+	} else {
+		/*
+		 * This really only applies to 10Mbps since
+		 * there is no polarity for 100Mbps (always 0).
+		 */
+		offset	= IGP01E1000_PHY_PORT_STATUS;
+		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
+	}
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, offset, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & mask)
+				      ? e1000_rev_polarity_reversed
+				      : e1000_rev_polarity_normal;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_wait_autoneg - Wait for auto-neg compeletion
+ *  @hw: pointer to the HW structure
+ *
+ *  Waits for auto-negotiation to complete or for the auto-negotiation time
+ *  limit to expire, which ever happens first.
+ **/
+static s32 igb_wait_autoneg(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+	u16 i, phy_status;
+
+	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_AUTONEG_COMPLETE)
+			break;
+		msleep(100);
+	}
+
+	/*
+	 * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+	 * has completed.
+	 */
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_has_link - Polls PHY for link
+ *  @hw: pointer to the HW structure
+ *  @iterations: number of times to poll for link
+ *  @usec_interval: delay between polling attempts
+ *  @success: pointer to whether polling was successful or not
+ *
+ *  Polls the PHY status register for link, 'iterations' number of times.
+ **/
+s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
+			       u32 usec_interval, bool *success)
+{
+	s32 ret_val = 0;
+	u16 i, phy_status;
+
+	for (i = 0; i < iterations; i++) {
+		/*
+		 * Some PHYs require the PHY_STATUS register to be read
+		 * twice due to the link bit being sticky.  No harm doing
+		 * it across the board.
+		 */
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_LINK_STATUS)
+			break;
+		if (usec_interval >= 1000)
+			mdelay(usec_interval/1000);
+		else
+			udelay(usec_interval);
+	}
+
+	*success = (i < iterations) ? true : false;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cable_length_m88 - Determine cable length for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY specific status register to retrieve the cable length
+ *  information.  The cable length is determined by averaging the minimum and
+ *  maximum values to get the "average" cable length.  The m88 PHY has four
+ *  possible cable length values, which are:
+ *	Register Value		Cable Length
+ *	0			< 50 meters
+ *	1			50 - 80 meters
+ *	2			80 - 110 meters
+ *	3			110 - 140 meters
+ *	4			> 140 meters
+ **/
+s32 igb_get_cable_length_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, index;
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+					   &phy_data);
+	if (ret_val)
+		goto out;
+
+	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+		M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+	phy->min_cable_length = e1000_m88_cable_length_table[index];
+	phy->max_cable_length = e1000_m88_cable_length_table[index+1];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  The automatic gain control (agc) normalizes the amplitude of the
+ *  received signal, adjusting for the attenuation produced by the
+ *  cable.  By reading the AGC registers, which reperesent the
+ *  cobination of course and fine gain value, the value can be put
+ *  into a lookup table to obtain the approximate cable length
+ *  for each channel.
+ **/
+s32 igb_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val = 0;
+	u16 phy_data, i, agc_value = 0;
+	u16 cur_agc_index, max_agc_index = 0;
+	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+							 {IGP02E1000_PHY_AGC_A,
+							  IGP02E1000_PHY_AGC_B,
+							  IGP02E1000_PHY_AGC_C,
+							  IGP02E1000_PHY_AGC_D};
+
+	/* Read the AGC registers for all channels */
+	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+		ret_val = hw->phy.ops.read_phy_reg(hw, agc_reg_array[i],
+						   &phy_data);
+		if (ret_val)
+			goto out;
+
+		/*
+		 * Getting bits 15:9, which represent the combination of
+		 * course and fine gain values.  The result is a number
+		 * that can be put into the lookup table to obtain the
+		 * approximate cable length.
+		 */
+		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+				IGP02E1000_AGC_LENGTH_MASK;
+
+		/* Array index bound check. */
+		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+		    (cur_agc_index == 0)) {
+			ret_val = -E1000_ERR_PHY;
+			goto out;
+		}
+
+		/* Remove min & max AGC values from calculation. */
+		if (e1000_igp_2_cable_length_table[min_agc_index] >
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			min_agc_index = cur_agc_index;
+		if (e1000_igp_2_cable_length_table[max_agc_index] <
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			max_agc_index = cur_agc_index;
+
+		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+	}
+
+	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+		      e1000_igp_2_cable_length_table[max_agc_index]);
+	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+	/* Calculate cable length with the error range of +/- 10 meters. */
+	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+				 (agc_value - IGP02E1000_AGC_RANGE) : 0;
+	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_phy_info_m88 - Retrieve PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Valid for only copper links.  Read the PHY status register (sticky read)
+ *  to verify that link is up.  Read the PHY special control register to
+ *  determine the polarity and 10base-T extended distance.  Read the PHY
+ *  special status register to determine MDI/MDIx and current speed.  If
+ *  speed is 1000, then determine cable length, local and remote receiver.
+ **/
+s32 igb_get_phy_info_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32  ret_val;
+	u16 phy_data;
+	bool link;
+
+	if (hw->phy.media_type != e1000_media_type_copper) {
+		hw_dbg(hw, "Phy info is only valid for copper media\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = igb_phy_has_link(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		hw_dbg(hw, "Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL,
+					   &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
+				   ? true
+				   : false;
+
+	ret_val = igb_check_polarity_m88(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+					   &phy_data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false;
+
+	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+		ret_val = hw->phy.ops.get_cable_length(hw);
+		if (ret_val)
+			goto out;
+
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS,
+						   &phy_data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+				? e1000_1000t_rx_status_ok
+				: e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+				 ? e1000_1000t_rx_status_ok
+				 : e1000_1000t_rx_status_not_ok;
+	} else {
+		/* Set values to "undefined" */
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_get_phy_info_igp - Retrieve igp PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Read PHY status to determine if link is up.  If link is up, then
+ *  set/determine 10base-T extended distance and polarity correction.  Read
+ *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
+ *  determine on the cable length, local and remote receiver.
+ **/
+s32 igb_get_phy_info_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	ret_val = igb_phy_has_link(hw, 1, 0, &link);
+	if (ret_val)
+		goto out;
+
+	if (!link) {
+		hw_dbg(hw, "Phy info is only valid if link is up\n");
+		ret_val = -E1000_ERR_CONFIG;
+		goto out;
+	}
+
+	phy->polarity_correction = true;
+
+	ret_val = igb_check_polarity_igp(hw);
+	if (ret_val)
+		goto out;
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
+					   &data);
+	if (ret_val)
+		goto out;
+
+	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false;
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+		ret_val = hw->phy.ops.get_cable_length(hw);
+		if (ret_val)
+			goto out;
+
+		ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS,
+						   &data);
+		if (ret_val)
+			goto out;
+
+		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+				? e1000_1000t_rx_status_ok
+				: e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+				 ? e1000_1000t_rx_status_ok
+				 : e1000_1000t_rx_status_not_ok;
+	} else {
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_sw_reset - PHY software reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Does a software reset of the PHY by reading the PHY control register and
+ *  setting/write the control register reset bit to the PHY.
+ **/
+s32 igb_phy_sw_reset(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 phy_ctrl;
+
+	ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	phy_ctrl |= MII_CR_RESET;
+	ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		goto out;
+
+	udelay(1);
+
+out:
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_hw_reset - PHY hardware reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify the reset block is not blocking us from resetting.  Acquire
+ *  semaphore (if necessary) and read/set/write the device control reset
+ *  bit in the PHY.  Wait the appropriate delay time for the device to
+ *  reset and relase the semaphore (if necessary).
+ **/
+s32 igb_phy_hw_reset(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32  ret_val;
+	u32 ctrl;
+
+	ret_val = igb_check_reset_block(hw);
+	if (ret_val) {
+		ret_val = 0;
+		goto out;
+	}
+
+	ret_val = igb_acquire_phy(hw);
+	if (ret_val)
+		goto out;
+
+	ctrl = rd32(E1000_CTRL);
+	wr32(E1000_CTRL, ctrl | E1000_CTRL_PHY_RST);
+	wrfl();
+
+	udelay(phy->reset_delay_us);
+
+	wr32(E1000_CTRL, ctrl);
+	wrfl();
+
+	udelay(150);
+
+	igb_release_phy(hw);
+
+	ret_val = igb_get_phy_cfg_done(hw);
+
+out:
+	return ret_val;
+}
+
+/* Internal function pointers */
+
+/**
+ *  e1000_get_phy_cfg_done - Generic PHY configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Return success if silicon family did not implement a family specific
+ *  get_cfg_done function.
+ **/
+static s32 igb_get_phy_cfg_done(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.get_cfg_done)
+		return hw->phy.ops.get_cfg_done(hw);
+
+	return 0;
+}
+
+/**
+ *  e1000_release_phy - Generic release PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Return if silicon family does not require a semaphore when accessing the
+ *  PHY.
+ **/
+static void igb_release_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.release_phy)
+		hw->phy.ops.release_phy(hw);
+}
+
+/**
+ *  e1000_acquire_phy - Generic acquire PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Return success if silicon family does not require a semaphore when
+ *  accessing the PHY.
+ **/
+static s32 igb_acquire_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.acquire_phy)
+		return hw->phy.ops.acquire_phy(hw);
+
+	return 0;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex - Generic force PHY speed/duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  When the silicon family has not implemented a forced speed/duplex
+ *  function for the PHY, simply return 0.
+ **/
+s32 igb_phy_force_speed_duplex(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.force_speed_duplex)
+		return hw->phy.ops.force_speed_duplex(hw);
+
+	return 0;
+}
+
+/**
+ *  e1000_phy_init_script_igp3 - Inits the IGP3 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
+ **/
+s32 igb_phy_init_script_igp3(struct e1000_hw *hw)
+{
+	hw_dbg(hw, "Running IGP 3 PHY init script\n");
+
+	/* PHY init IGP 3 */
+	/* Enable rise/fall, 10-mode work in class-A */
+	hw->phy.ops.write_phy_reg(hw, 0x2F5B, 0x9018);
+	/* Remove all caps from Replica path filter */
+	hw->phy.ops.write_phy_reg(hw, 0x2F52, 0x0000);
+	/* Bias trimming for ADC, AFE and Driver (Default) */
+	hw->phy.ops.write_phy_reg(hw, 0x2FB1, 0x8B24);
+	/* Increase Hybrid poly bias */
+	hw->phy.ops.write_phy_reg(hw, 0x2FB2, 0xF8F0);
+	/* Add 4% to TX amplitude in Giga mode */
+	hw->phy.ops.write_phy_reg(hw, 0x2010, 0x10B0);
+	/* Disable trimming (TTT) */
+	hw->phy.ops.write_phy_reg(hw, 0x2011, 0x0000);
+	/* Poly DC correction to 94.6% + 2% for all channels */
+	hw->phy.ops.write_phy_reg(hw, 0x20DD, 0x249A);
+	/* ABS DC correction to 95.9% */
+	hw->phy.ops.write_phy_reg(hw, 0x20DE, 0x00D3);
+	/* BG temp curve trim */
+	hw->phy.ops.write_phy_reg(hw, 0x28B4, 0x04CE);
+	/* Increasing ADC OPAMP stage 1 currents to max */
+	hw->phy.ops.write_phy_reg(hw, 0x2F70, 0x29E4);
+	/* Force 1000 ( required for enabling PHY regs configuration) */
+	hw->phy.ops.write_phy_reg(hw, 0x0000, 0x0140);
+	/* Set upd_freq to 6 */
+	hw->phy.ops.write_phy_reg(hw, 0x1F30, 0x1606);
+	/* Disable NPDFE */
+	hw->phy.ops.write_phy_reg(hw, 0x1F31, 0xB814);
+	/* Disable adaptive fixed FFE (Default) */
+	hw->phy.ops.write_phy_reg(hw, 0x1F35, 0x002A);
+	/* Enable FFE hysteresis */
+	hw->phy.ops.write_phy_reg(hw, 0x1F3E, 0x0067);
+	/* Fixed FFE for short cable lengths */
+	hw->phy.ops.write_phy_reg(hw, 0x1F54, 0x0065);
+	/* Fixed FFE for medium cable lengths */
+	hw->phy.ops.write_phy_reg(hw, 0x1F55, 0x002A);
+	/* Fixed FFE for long cable lengths */
+	hw->phy.ops.write_phy_reg(hw, 0x1F56, 0x002A);
+	/* Enable Adaptive Clip Threshold */
+	hw->phy.ops.write_phy_reg(hw, 0x1F72, 0x3FB0);
+	/* AHT reset limit to 1 */
+	hw->phy.ops.write_phy_reg(hw, 0x1F76, 0xC0FF);
+	/* Set AHT master delay to 127 msec */
+	hw->phy.ops.write_phy_reg(hw, 0x1F77, 0x1DEC);
+	/* Set scan bits for AHT */
+	hw->phy.ops.write_phy_reg(hw, 0x1F78, 0xF9EF);
+	/* Set AHT Preset bits */
+	hw->phy.ops.write_phy_reg(hw, 0x1F79, 0x0210);
+	/* Change integ_factor of channel A to 3 */
+	hw->phy.ops.write_phy_reg(hw, 0x1895, 0x0003);
+	/* Change prop_factor of channels BCD to 8 */
+	hw->phy.ops.write_phy_reg(hw, 0x1796, 0x0008);
+	/* Change cg_icount + enable integbp for channels BCD */
+	hw->phy.ops.write_phy_reg(hw, 0x1798, 0xD008);
+	/*
+	 * Change cg_icount + enable integbp + change prop_factor_master
+	 * to 8 for channel A
+	 */
+	hw->phy.ops.write_phy_reg(hw, 0x1898, 0xD918);
+	/* Disable AHT in Slave mode on channel A */
+	hw->phy.ops.write_phy_reg(hw, 0x187A, 0x0800);
+	/*
+	 * Enable LPLU and disable AN to 1000 in non-D0a states,
+	 * Enable SPD+B2B
+	 */
+	hw->phy.ops.write_phy_reg(hw, 0x0019, 0x008D);
+	/* Enable restart AN on an1000_dis change */
+	hw->phy.ops.write_phy_reg(hw, 0x001B, 0x2080);
+	/* Enable wh_fifo read clock in 10/100 modes */
+	hw->phy.ops.write_phy_reg(hw, 0x0014, 0x0045);
+	/* Restart AN, Speed selection is 1000 */
+	hw->phy.ops.write_phy_reg(hw, 0x0000, 0x1340);
+
+	return 0;
+}
+
diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h
new file mode 100644
index 000000000000..8f8fe0a780d1
--- /dev/null
+++ b/drivers/net/igb/e1000_phy.h
@@ -0,0 +1,98 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_PHY_H_
+#define _E1000_PHY_H_
+
+enum e1000_ms_type {
+	e1000_ms_hw_default = 0,
+	e1000_ms_force_master,
+	e1000_ms_force_slave,
+	e1000_ms_auto
+};
+
+enum e1000_smart_speed {
+	e1000_smart_speed_default = 0,
+	e1000_smart_speed_on,
+	e1000_smart_speed_off
+};
+
+s32  igb_check_downshift(struct e1000_hw *hw);
+s32  igb_check_reset_block(struct e1000_hw *hw);
+s32  igb_copper_link_autoneg(struct e1000_hw *hw);
+s32  igb_phy_force_speed_duplex(struct e1000_hw *hw);
+s32  igb_copper_link_setup_igp(struct e1000_hw *hw);
+s32  igb_copper_link_setup_m88(struct e1000_hw *hw);
+s32  igb_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+s32  igb_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+s32  igb_get_cable_length_m88(struct e1000_hw *hw);
+s32  igb_get_cable_length_igp_2(struct e1000_hw *hw);
+s32  igb_get_phy_id(struct e1000_hw *hw);
+s32  igb_get_phy_info_igp(struct e1000_hw *hw);
+s32  igb_get_phy_info_m88(struct e1000_hw *hw);
+s32  igb_phy_sw_reset(struct e1000_hw *hw);
+s32  igb_phy_hw_reset(struct e1000_hw *hw);
+s32  igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+s32  igb_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+s32  igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+s32  igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
+				u32 usec_interval, bool *success);
+s32  igb_phy_init_script_igp3(struct e1000_hw *hw);
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS        0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL          0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH        0x13 /* PHY Link Health */
+#define IGP02E1000_PHY_POWER_MGMT         0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT        0x1F /* Page Select */
+#define IGP01E1000_PHY_PCS_INIT_REG       0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK      0x0078
+#define IGP01E1000_PSCR_AUTO_MDIX         0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX    0x2000 /* 0=MDI, 1=MDIX */
+#define IGP01E1000_PSCFR_SMART_SPEED      0x0080
+
+/* Enable flexible speed on link-up */
+#define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
+#define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX              0x0008
+#define IGP01E1000_PSSR_SPEED_MASK        0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
+#define IGP02E1000_PHY_CHANNEL_NUM        4
+#define IGP02E1000_PHY_AGC_A              0x11B1
+#define IGP02E1000_PHY_AGC_B              0x12B1
+#define IGP02E1000_PHY_AGC_C              0x14B1
+#define IGP02E1000_PHY_AGC_D              0x18B1
+#define IGP02E1000_AGC_LENGTH_SHIFT       9   /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK        0x7F
+#define IGP02E1000_AGC_RANGE              15
+
+#define E1000_CABLE_LENGTH_UNDEFINED      0xFF
+
+#endif
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
new file mode 100644
index 000000000000..ff187b73c69e
--- /dev/null
+++ b/drivers/net/igb/e1000_regs.h
@@ -0,0 +1,270 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_REGS_H_
+#define _E1000_REGS_H_
+
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_SCTL     0x00024  /* SerDes Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#define E1000_RCTL     0x00100  /* RX Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
+#define E1000_EICR     0x01580  /* Ext. Interrupt Cause Read - R/clr */
+#define E1000_EITR(_n) (0x01680 + (0x4 * (_n)))
+#define E1000_EICS     0x01520  /* Ext. Interrupt Cause Set - W0 */
+#define E1000_EIMS     0x01524  /* Ext. Interrupt Mask Set/Read - RW */
+#define E1000_EIMC     0x01528  /* Ext. Interrupt Mask Clear - WO */
+#define E1000_EIAC     0x0152C  /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAM     0x01530  /* Ext. Interrupt Ack Auto Clear Mask - RW */
+#define E1000_TCTL     0x00400  /* TX Control - RW */
+#define E1000_TCTL_EXT 0x00404  /* Extended TX Control - RW */
+#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_I2CCMD   0x01028  /* SFPI2C Command Register - RW */
+#define E1000_FRTIMER  0x01048  /* Free Running Timer - RW */
+#define E1000_TCPTIMER 0x0104C  /* TCP Timer - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_RDFPCQ(_n)  (0x02430 + (0x4 * (_n)))
+#define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
+/* Split and Replication RX Control - RW */
+/*
+ * Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ */
+#define E1000_RDBAL(_n)   ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) \
+				    : (0x0C000 + ((_n) * 0x40)))
+#define E1000_RDBAH(_n)   ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) \
+				    : (0x0C004 + ((_n) * 0x40)))
+#define E1000_RDLEN(_n)   ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) \
+				    : (0x0C008 + ((_n) * 0x40)))
+#define E1000_SRRCTL(_n)  ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) \
+				    : (0x0C00C + ((_n) * 0x40)))
+#define E1000_RDH(_n)     ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) \
+				    : (0x0C010 + ((_n) * 0x40)))
+#define E1000_RDT(_n)     ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) \
+				    : (0x0C018 + ((_n) * 0x40)))
+#define E1000_RXDCTL(_n)  ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) \
+				    : (0x0C028 + ((_n) * 0x40)))
+#define E1000_TDBAL(_n)   ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) \
+				    : (0x0E000 + ((_n) * 0x40)))
+#define E1000_TDBAH(_n)   ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) \
+				    : (0x0E004 + ((_n) * 0x40)))
+#define E1000_TDLEN(_n)   ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) \
+				    : (0x0E008 + ((_n) * 0x40)))
+#define E1000_TDH(_n)     ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) \
+				    : (0x0E010 + ((_n) * 0x40)))
+#define E1000_TDT(_n)     ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) \
+				    : (0x0E018 + ((_n) * 0x40)))
+#define E1000_TXDCTL(_n)  ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) \
+				    : (0x0E028 + ((_n) * 0x40)))
+#define E1000_TARC(_n)    (0x03840 + (_n << 8))
+#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8))
+#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8))
+#define E1000_TDWBAL(_n)  ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) \
+				    : (0x0E038 + ((_n) * 0x40)))
+#define E1000_TDWBAH(_n)  ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) \
+				    : (0x0E03C + ((_n) * 0x40)))
+#define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFPC    0x03430  /* TX Data FIFO Packet Count - RW */
+#define E1000_DTXCTL   0x03590  /* DMA TX Control - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+/* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXPTC  0x04104
+/* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICRXATC  0x04108
+/* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXPTC  0x0410C
+/* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXATC  0x04110
+/* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQEC  0x04118
+/* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICTXQMTC 0x0411C
+/* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXDMTC 0x04120
+#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
+#define E1000_PCS_CFG0    0x04200  /* PCS Configuration 0 - RW */
+#define E1000_PCS_LCTL    0x04208  /* PCS Link Control - RW */
+#define E1000_PCS_LSTAT   0x0420C  /* PCS Link Status - RO */
+#define E1000_CBTMPC      0x0402C  /* Circuit Breaker TX Packet Count */
+#define E1000_HTDPMC      0x0403C  /* Host Transmit Discarded Packets */
+#define E1000_CBRMPC      0x040FC  /* Circuit Breaker RX Packet Count */
+#define E1000_RPTHC       0x04104  /* Rx Packets To Host */
+#define E1000_HGPTC       0x04118  /* Host Good Packets TX Count */
+#define E1000_HTCBDPC     0x04124  /* Host TX Circuit Breaker Dropped Count */
+#define E1000_HGORCL      0x04128  /* Host Good Octets Received Count Low */
+#define E1000_HGORCH      0x0412C  /* Host Good Octets Received Count High */
+#define E1000_HGOTCL      0x04130  /* Host Good Octets Transmit Count Low */
+#define E1000_HGOTCH      0x04134  /* Host Good Octets Transmit Count High */
+#define E1000_LENERRS     0x04138  /* Length Errors Count */
+#define E1000_SCVPC       0x04228  /* SerDes/SGMII Code Violation Pkt Count */
+#define E1000_PCS_ANADV   0x04218  /* AN advertisement - RW */
+#define E1000_PCS_LPAB    0x0421C  /* Link Partner Ability - RW */
+#define E1000_PCS_NPTX    0x04220  /* AN Next Page Transmit - RW */
+#define E1000_PCS_LPABNP  0x04224  /* Link Partner Ability Next Page - RW */
+#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_RLPML    0x05004  /* RX Long Packet Max Length */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_VMD_CTL  0x0581C  /* VMDq Control - RW */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
+
+#define E1000_MANC2H      0x05860 /* Management Control To Host - RW */
+#define E1000_SW_FW_SYNC  0x05B5C /* Software-Firmware Synchronization - RW */
+#define E1000_CCMCTL      0x05B48 /* CCM Control Register */
+#define E1000_GIOCTL      0x05B44 /* GIO Analog Control Register */
+#define E1000_SCCTL       0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_HICR      0x08F00 /* Host Inteface Control */
+
+/* RSS registers */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_IMIR(_i)      (0x05A80 + ((_i) * 4))  /* Immediate Interrupt */
+#define E1000_IMIREXT(_i)   (0x05AA0 + ((_i) * 4))  /* Immediate Interrupt Ext*/
+#define E1000_IMIRVP    0x05AC0 /* Immediate Interrupt RX VLAN Priority - RW */
+/* MSI-X Allocation Register (_i) - RW */
+#define E1000_MSIXBM(_i)    (0x01600 + ((_i) * 4))
+/* MSI-X Table entry addr low reg 0 - RW */
+#define E1000_MSIXTADD(_i)  (0x0C000 + ((_i) * 0x10))
+/* MSI-X Table entry addr upper reg 0 - RW */
+#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10))
+/* MSI-X Table entry message reg 0 - RW */
+#define E1000_MSIXTMSG(_i)  (0x0C008 + ((_i) * 0x10))
+/* MSI-X Table entry vector ctrl reg 0 - RW */
+#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10))
+/* Redirection Table - RW Array */
+#define E1000_RETA(_i)  (0x05C00 + ((_i) * 4))
+#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW Array */
+
+#define E1000_REGISTER(a, reg) reg
+
+#define wr32(reg, value) (writel(value, hw->hw_addr + reg))
+#define rd32(reg) (readl(hw->hw_addr + reg))
+#define wrfl() ((void)rd32(E1000_STATUS))
+
+#define array_wr32(reg, offset, value) \
+	(writel(value, hw->hw_addr + reg + ((offset) << 2)))
+#define array_rd32(reg, offset) \
+	(readl(hw->hw_addr + reg + ((offset) << 2)))
+
+#endif
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
new file mode 100644
index 000000000000..6b2e7d351d65
--- /dev/null
+++ b/drivers/net/igb/igb.h
@@ -0,0 +1,300 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _IGB_H_
+#define _IGB_H_
+
+#include "e1000_mac.h"
+#include "e1000_82575.h"
+
+struct igb_adapter;
+
+/* Interrupt defines */
+#define IGB_MAX_TX_CLEAN 72
+
+#define IGB_MIN_DYN_ITR 3000
+#define IGB_MAX_DYN_ITR 96000
+#define IGB_START_ITR 6000
+
+#define IGB_DYN_ITR_PACKET_THRESHOLD 2
+#define IGB_DYN_ITR_LENGTH_LOW 200
+#define IGB_DYN_ITR_LENGTH_HIGH 1000
+
+/* TX/RX descriptor defines */
+#define IGB_DEFAULT_TXD                  256
+#define IGB_MIN_TXD                       80
+#define IGB_MAX_TXD                     4096
+
+#define IGB_DEFAULT_RXD                  256
+#define IGB_MIN_RXD                       80
+#define IGB_MAX_RXD                     4096
+
+#define IGB_DEFAULT_ITR                    3 /* dynamic */
+#define IGB_MAX_ITR_USECS              10000
+#define IGB_MIN_ITR_USECS                 10
+
+/* Transmit and receive queues */
+#define IGB_MAX_RX_QUEUES                  4
+
+/* RX descriptor control thresholds.
+ * PTHRESH - MAC will consider prefetch if it has fewer than this number of
+ *           descriptors available in its onboard memory.
+ *           Setting this to 0 disables RX descriptor prefetch.
+ * HTHRESH - MAC will only prefetch if there are at least this many descriptors
+ *           available in host memory.
+ *           If PTHRESH is 0, this should also be 0.
+ * WTHRESH - RX descriptor writeback threshold - MAC will delay writing back
+ *           descriptors until either it has this many to write back, or the
+ *           ITR timer expires.
+ */
+#define IGB_RX_PTHRESH                    16
+#define IGB_RX_HTHRESH                     8
+#define IGB_RX_WTHRESH                     1
+
+/* this is the size past which hardware will drop packets when setting LPE=0 */
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+
+/* Supported Rx Buffer Sizes */
+#define IGB_RXBUFFER_128   128    /* Used for packet split */
+#define IGB_RXBUFFER_256   256    /* Used for packet split */
+#define IGB_RXBUFFER_512   512
+#define IGB_RXBUFFER_1024  1024
+#define IGB_RXBUFFER_2048  2048
+#define IGB_RXBUFFER_4096  4096
+#define IGB_RXBUFFER_8192  8192
+#define IGB_RXBUFFER_16384 16384
+
+/* Packet Buffer allocations */
+
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+#define IGB_TX_QUEUE_WAKE	16
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IGB_RX_BUFFER_WRITE	16	/* Must be power of 2 */
+
+#define AUTO_ALL_MODES            0
+#define IGB_EEPROM_APME         0x0400
+
+#ifndef IGB_MASTER_SLAVE
+/* Switch to override PHY master/slave setting */
+#define IGB_MASTER_SLAVE	e1000_ms_hw_default
+#endif
+
+#define IGB_MNG_VLAN_NONE -1
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct igb_buffer {
+	struct sk_buff *skb;
+	dma_addr_t dma;
+	union {
+		/* TX */
+		struct {
+			unsigned long time_stamp;
+			u32 length;
+		};
+		/* RX */
+		struct {
+			struct page *page;
+			u64 page_dma;
+		};
+	};
+};
+
+struct igb_queue_stats {
+	u64 packets;
+	u64 bytes;
+};
+
+struct igb_ring {
+	struct igb_adapter *adapter; /* backlink */
+	void *desc;                  /* descriptor ring memory */
+	dma_addr_t dma;              /* phys address of the ring */
+	unsigned int size;           /* length of desc. ring in bytes */
+	unsigned int count;          /* number of desc. in the ring */
+	u16 next_to_use;
+	u16 next_to_clean;
+	u16 head;
+	u16 tail;
+	struct igb_buffer *buffer_info; /* array of buffer info structs */
+
+	u32 eims_value;
+	u32 itr_val;
+	u16 itr_register;
+	u16 cpu;
+
+	unsigned int total_bytes;
+	unsigned int total_packets;
+
+	union {
+		/* TX */
+		struct {
+			spinlock_t tx_clean_lock;
+			spinlock_t tx_lock;
+			bool detect_tx_hung;
+		};
+		/* RX */
+		struct {
+			/* arrays of page information for packet split */
+			struct sk_buff *pending_skb;
+			int pending_skb_page;
+			int no_itr_adjust;
+			struct igb_queue_stats rx_stats;
+			struct napi_struct napi;
+		};
+	};
+
+	char name[IFNAMSIZ + 5];
+};
+
+#define IGB_DESC_UNUSED(R) \
+	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+	(R)->next_to_clean - (R)->next_to_use - 1)
+
+#define E1000_RX_DESC_ADV(R, i)	    \
+	(&(((union e1000_adv_rx_desc *)((R).desc))[i]))
+#define E1000_TX_DESC_ADV(R, i)	    \
+	(&(((union e1000_adv_tx_desc *)((R).desc))[i]))
+#define E1000_TX_CTXTDESC_ADV(R, i)	    \
+	(&(((struct e1000_adv_tx_context_desc *)((R).desc))[i]))
+#define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
+#define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
+
+/* board specific private data structure */
+
+struct igb_adapter {
+	struct timer_list watchdog_timer;
+	struct timer_list phy_info_timer;
+	struct vlan_group *vlgrp;
+	u16 mng_vlan_id;
+	u32 bd_number;
+	u32 rx_buffer_len;
+	u32 wol;
+	u32 en_mng_pt;
+	u16 link_speed;
+	u16 link_duplex;
+	unsigned int total_tx_bytes;
+	unsigned int total_tx_packets;
+	unsigned int total_rx_bytes;
+	unsigned int total_rx_packets;
+	/* Interrupt Throttle Rate */
+	u32 itr;
+	u32 itr_setting;
+	u16 tx_itr;
+	u16 rx_itr;
+	int set_itr;
+
+	struct work_struct reset_task;
+	struct work_struct watchdog_task;
+	bool fc_autoneg;
+	u8  tx_timeout_factor;
+	struct timer_list blink_timer;
+	unsigned long led_status;
+
+	/* TX */
+	struct igb_ring *tx_ring;      /* One per active queue */
+	unsigned int restart_queue;
+	unsigned long tx_queue_len;
+	u32 txd_cmd;
+	u32 gotc;
+	u64 gotc_old;
+	u64 tpt_old;
+	u64 colc_old;
+	u32 tx_timeout_count;
+
+	/* RX */
+	struct igb_ring *rx_ring;      /* One per active queue */
+	int num_tx_queues;
+	int num_rx_queues;
+
+	u64 hw_csum_err;
+	u64 hw_csum_good;
+	u64 rx_hdr_split;
+	u32 alloc_rx_buff_failed;
+	bool rx_csum;
+	u32 gorc;
+	u64 gorc_old;
+	u16 rx_ps_hdr_size;
+	u32 max_frame_size;
+	u32 min_frame_size;
+
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct napi_struct napi;
+	struct pci_dev *pdev;
+	struct net_device_stats net_stats;
+
+	/* structs defined in e1000_hw.h */
+	struct e1000_hw hw;
+	struct e1000_hw_stats stats;
+	struct e1000_phy_info phy_info;
+	struct e1000_phy_stats phy_stats;
+
+	u32 test_icr;
+	struct igb_ring test_tx_ring;
+	struct igb_ring test_rx_ring;
+
+	int msg_enable;
+	struct msix_entry *msix_entries;
+	u32 eims_enable_mask;
+
+	/* to not mess up cache alignment, always add to the bottom */
+	unsigned long state;
+	unsigned int msi_enabled;
+
+	u32 eeprom_wol;
+};
+
+enum e1000_state_t {
+	__IGB_TESTING,
+	__IGB_RESETTING,
+	__IGB_DOWN
+};
+
+enum igb_boards {
+	board_82575,
+};
+
+extern char igb_driver_name[];
+extern char igb_driver_version[];
+
+extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
+extern int igb_up(struct igb_adapter *);
+extern void igb_down(struct igb_adapter *);
+extern void igb_reinit_locked(struct igb_adapter *);
+extern void igb_reset(struct igb_adapter *);
+extern int igb_set_spd_dplx(struct igb_adapter *, u16);
+extern int igb_setup_tx_resources(struct igb_adapter *, struct igb_ring *);
+extern int igb_setup_rx_resources(struct igb_adapter *, struct igb_ring *);
+extern void igb_update_stats(struct igb_adapter *);
+extern void igb_set_ethtool_ops(struct net_device *);
+
+#endif /* _IGB_H_ */
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
new file mode 100644
index 000000000000..f69721e4eaa1
--- /dev/null
+++ b/drivers/net/igb/igb_ethtool.c
@@ -0,0 +1,1927 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for igb */
+
+#include <linux/vmalloc.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/ethtool.h>
+
+#include "igb.h"
+
+struct igb_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int stat_offset;
+};
+
+#define IGB_STAT(m) sizeof(((struct igb_adapter *)0)->m), \
+		      offsetof(struct igb_adapter, m)
+static const struct igb_stats igb_gstrings_stats[] = {
+	{ "rx_packets", IGB_STAT(stats.gprc) },
+	{ "tx_packets", IGB_STAT(stats.gptc) },
+	{ "rx_bytes", IGB_STAT(stats.gorc) },
+	{ "tx_bytes", IGB_STAT(stats.gotc) },
+	{ "rx_broadcast", IGB_STAT(stats.bprc) },
+	{ "tx_broadcast", IGB_STAT(stats.bptc) },
+	{ "rx_multicast", IGB_STAT(stats.mprc) },
+	{ "tx_multicast", IGB_STAT(stats.mptc) },
+	{ "rx_errors", IGB_STAT(net_stats.rx_errors) },
+	{ "tx_errors", IGB_STAT(net_stats.tx_errors) },
+	{ "tx_dropped", IGB_STAT(net_stats.tx_dropped) },
+	{ "multicast", IGB_STAT(stats.mprc) },
+	{ "collisions", IGB_STAT(stats.colc) },
+	{ "rx_length_errors", IGB_STAT(net_stats.rx_length_errors) },
+	{ "rx_over_errors", IGB_STAT(net_stats.rx_over_errors) },
+	{ "rx_crc_errors", IGB_STAT(stats.crcerrs) },
+	{ "rx_frame_errors", IGB_STAT(net_stats.rx_frame_errors) },
+	{ "rx_no_buffer_count", IGB_STAT(stats.rnbc) },
+	{ "rx_missed_errors", IGB_STAT(stats.mpc) },
+	{ "tx_aborted_errors", IGB_STAT(stats.ecol) },
+	{ "tx_carrier_errors", IGB_STAT(stats.tncrs) },
+	{ "tx_fifo_errors", IGB_STAT(net_stats.tx_fifo_errors) },
+	{ "tx_heartbeat_errors", IGB_STAT(net_stats.tx_heartbeat_errors) },
+	{ "tx_window_errors", IGB_STAT(stats.latecol) },
+	{ "tx_abort_late_coll", IGB_STAT(stats.latecol) },
+	{ "tx_deferred_ok", IGB_STAT(stats.dc) },
+	{ "tx_single_coll_ok", IGB_STAT(stats.scc) },
+	{ "tx_multi_coll_ok", IGB_STAT(stats.mcc) },
+	{ "tx_timeout_count", IGB_STAT(tx_timeout_count) },
+	{ "tx_restart_queue", IGB_STAT(restart_queue) },
+	{ "rx_long_length_errors", IGB_STAT(stats.roc) },
+	{ "rx_short_length_errors", IGB_STAT(stats.ruc) },
+	{ "rx_align_errors", IGB_STAT(stats.algnerrc) },
+	{ "tx_tcp_seg_good", IGB_STAT(stats.tsctc) },
+	{ "tx_tcp_seg_failed", IGB_STAT(stats.tsctfc) },
+	{ "rx_flow_control_xon", IGB_STAT(stats.xonrxc) },
+	{ "rx_flow_control_xoff", IGB_STAT(stats.xoffrxc) },
+	{ "tx_flow_control_xon", IGB_STAT(stats.xontxc) },
+	{ "tx_flow_control_xoff", IGB_STAT(stats.xofftxc) },
+	{ "rx_long_byte_count", IGB_STAT(stats.gorc) },
+	{ "rx_csum_offload_good", IGB_STAT(hw_csum_good) },
+	{ "rx_csum_offload_errors", IGB_STAT(hw_csum_err) },
+	{ "rx_header_split", IGB_STAT(rx_hdr_split) },
+	{ "alloc_rx_buff_failed", IGB_STAT(alloc_rx_buff_failed) },
+	{ "tx_smbus", IGB_STAT(stats.mgptc) },
+	{ "rx_smbus", IGB_STAT(stats.mgprc) },
+	{ "dropped_smbus", IGB_STAT(stats.mgpdc) },
+};
+
+#define IGB_QUEUE_STATS_LEN \
+	((((((struct igb_adapter *)netdev->priv)->num_rx_queues > 1) ? \
+	  ((struct igb_adapter *)netdev->priv)->num_rx_queues : 0) + \
+	 (((((struct igb_adapter *)netdev->priv)->num_tx_queues > 1) ? \
+	  ((struct igb_adapter *)netdev->priv)->num_tx_queues : 0))) * \
+	(sizeof(struct igb_queue_stats) / sizeof(u64)))
+#define IGB_GLOBAL_STATS_LEN	\
+	sizeof(igb_gstrings_stats) / sizeof(struct igb_stats)
+#define IGB_STATS_LEN (IGB_GLOBAL_STATS_LEN + IGB_QUEUE_STATS_LEN)
+static const char igb_gstrings_test[][ETH_GSTRING_LEN] = {
+	"Register test  (offline)", "Eeprom test    (offline)",
+	"Interrupt test (offline)", "Loopback test  (offline)",
+	"Link test   (on/offline)"
+};
+#define IGB_TEST_LEN sizeof(igb_gstrings_test) / ETH_GSTRING_LEN
+
+static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (hw->phy.media_type == e1000_media_type_copper) {
+
+		ecmd->supported = (SUPPORTED_10baseT_Half |
+				   SUPPORTED_10baseT_Full |
+				   SUPPORTED_100baseT_Half |
+				   SUPPORTED_100baseT_Full |
+				   SUPPORTED_1000baseT_Full|
+				   SUPPORTED_Autoneg |
+				   SUPPORTED_TP);
+		ecmd->advertising = ADVERTISED_TP;
+
+		if (hw->mac.autoneg == 1) {
+			ecmd->advertising |= ADVERTISED_Autoneg;
+			/* the e1000 autoneg seems to match ethtool nicely */
+			ecmd->advertising |= hw->phy.autoneg_advertised;
+		}
+
+		ecmd->port = PORT_TP;
+		ecmd->phy_address = hw->phy.addr;
+	} else {
+		ecmd->supported   = (SUPPORTED_1000baseT_Full |
+				     SUPPORTED_FIBRE |
+				     SUPPORTED_Autoneg);
+
+		ecmd->advertising = (ADVERTISED_1000baseT_Full |
+				     ADVERTISED_FIBRE |
+				     ADVERTISED_Autoneg);
+
+		ecmd->port = PORT_FIBRE;
+	}
+
+	ecmd->transceiver = XCVR_INTERNAL;
+
+	if (rd32(E1000_STATUS) & E1000_STATUS_LU) {
+
+		adapter->hw.mac.ops.get_speed_and_duplex(hw,
+					&adapter->link_speed,
+					&adapter->link_duplex);
+		ecmd->speed = adapter->link_speed;
+
+		/* unfortunately FULL_DUPLEX != DUPLEX_FULL
+		 *          and HALF_DUPLEX != DUPLEX_HALF */
+
+		if (adapter->link_duplex == FULL_DUPLEX)
+			ecmd->duplex = DUPLEX_FULL;
+		else
+			ecmd->duplex = DUPLEX_HALF;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+
+	ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
+			 hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+	return 0;
+}
+
+static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	/* When SoL/IDER sessions are active, autoneg/speed/duplex
+	 * cannot be changed */
+	if (igb_check_reset_block(hw)) {
+		dev_err(&adapter->pdev->dev, "Cannot change link "
+			"characteristics when SoL/IDER is active.\n");
+		return -EINVAL;
+	}
+
+	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+		msleep(1);
+
+	if (ecmd->autoneg == AUTONEG_ENABLE) {
+		hw->mac.autoneg = 1;
+		if (hw->phy.media_type == e1000_media_type_fiber)
+			hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full |
+						     ADVERTISED_FIBRE |
+						     ADVERTISED_Autoneg;
+		else
+			hw->phy.autoneg_advertised = ecmd->advertising |
+						     ADVERTISED_TP |
+						     ADVERTISED_Autoneg;
+		ecmd->advertising = hw->phy.autoneg_advertised;
+	} else
+		if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
+			clear_bit(__IGB_RESETTING, &adapter->state);
+			return -EINVAL;
+		}
+
+	/* reset the link */
+
+	if (netif_running(adapter->netdev)) {
+		igb_down(adapter);
+		igb_up(adapter);
+	} else
+		igb_reset(adapter);
+
+	clear_bit(__IGB_RESETTING, &adapter->state);
+	return 0;
+}
+
+static void igb_get_pauseparam(struct net_device *netdev,
+			       struct ethtool_pauseparam *pause)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	pause->autoneg =
+		(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+
+	if (hw->fc.type == e1000_fc_rx_pause)
+		pause->rx_pause = 1;
+	else if (hw->fc.type == e1000_fc_tx_pause)
+		pause->tx_pause = 1;
+	else if (hw->fc.type == e1000_fc_full) {
+		pause->rx_pause = 1;
+		pause->tx_pause = 1;
+	}
+}
+
+static int igb_set_pauseparam(struct net_device *netdev,
+			      struct ethtool_pauseparam *pause)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	int retval = 0;
+
+	adapter->fc_autoneg = pause->autoneg;
+
+	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+		msleep(1);
+
+	if (pause->rx_pause && pause->tx_pause)
+		hw->fc.type = e1000_fc_full;
+	else if (pause->rx_pause && !pause->tx_pause)
+		hw->fc.type = e1000_fc_rx_pause;
+	else if (!pause->rx_pause && pause->tx_pause)
+		hw->fc.type = e1000_fc_tx_pause;
+	else if (!pause->rx_pause && !pause->tx_pause)
+		hw->fc.type = e1000_fc_none;
+
+	hw->fc.original_type = hw->fc.type;
+
+	if (adapter->fc_autoneg == AUTONEG_ENABLE) {
+		if (netif_running(adapter->netdev)) {
+			igb_down(adapter);
+			igb_up(adapter);
+		} else
+			igb_reset(adapter);
+	} else
+		retval = ((hw->phy.media_type == e1000_media_type_fiber) ?
+			  igb_setup_link(hw) : igb_force_mac_fc(hw));
+
+	clear_bit(__IGB_RESETTING, &adapter->state);
+	return retval;
+}
+
+static u32 igb_get_rx_csum(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	return adapter->rx_csum;
+}
+
+static int igb_set_rx_csum(struct net_device *netdev, u32 data)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	adapter->rx_csum = data;
+
+	return 0;
+}
+
+static u32 igb_get_tx_csum(struct net_device *netdev)
+{
+	return (netdev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+static int igb_set_tx_csum(struct net_device *netdev, u32 data)
+{
+	if (data)
+		netdev->features |= NETIF_F_HW_CSUM;
+	else
+		netdev->features &= ~NETIF_F_HW_CSUM;
+
+	return 0;
+}
+
+static int igb_set_tso(struct net_device *netdev, u32 data)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	if (data)
+		netdev->features |= NETIF_F_TSO;
+	else
+		netdev->features &= ~NETIF_F_TSO;
+
+	if (data)
+		netdev->features |= NETIF_F_TSO6;
+	else
+		netdev->features &= ~NETIF_F_TSO6;
+
+	dev_info(&adapter->pdev->dev, "TSO is %s\n",
+		 data ? "Enabled" : "Disabled");
+	return 0;
+}
+
+static u32 igb_get_msglevel(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	return adapter->msg_enable;
+}
+
+static void igb_set_msglevel(struct net_device *netdev, u32 data)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	adapter->msg_enable = data;
+}
+
+static int igb_get_regs_len(struct net_device *netdev)
+{
+#define IGB_REGS_LEN 551
+	return IGB_REGS_LEN * sizeof(u32);
+}
+
+static void igb_get_regs(struct net_device *netdev,
+			 struct ethtool_regs *regs, void *p)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 *regs_buff = p;
+	u8 i;
+
+	memset(p, 0, IGB_REGS_LEN * sizeof(u32));
+
+	regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
+
+	/* General Registers */
+	regs_buff[0] = rd32(E1000_CTRL);
+	regs_buff[1] = rd32(E1000_STATUS);
+	regs_buff[2] = rd32(E1000_CTRL_EXT);
+	regs_buff[3] = rd32(E1000_MDIC);
+	regs_buff[4] = rd32(E1000_SCTL);
+	regs_buff[5] = rd32(E1000_CONNSW);
+	regs_buff[6] = rd32(E1000_VET);
+	regs_buff[7] = rd32(E1000_LEDCTL);
+	regs_buff[8] = rd32(E1000_PBA);
+	regs_buff[9] = rd32(E1000_PBS);
+	regs_buff[10] = rd32(E1000_FRTIMER);
+	regs_buff[11] = rd32(E1000_TCPTIMER);
+
+	/* NVM Register */
+	regs_buff[12] = rd32(E1000_EECD);
+
+	/* Interrupt */
+	regs_buff[13] = rd32(E1000_EICR);
+	regs_buff[14] = rd32(E1000_EICS);
+	regs_buff[15] = rd32(E1000_EIMS);
+	regs_buff[16] = rd32(E1000_EIMC);
+	regs_buff[17] = rd32(E1000_EIAC);
+	regs_buff[18] = rd32(E1000_EIAM);
+	regs_buff[19] = rd32(E1000_ICR);
+	regs_buff[20] = rd32(E1000_ICS);
+	regs_buff[21] = rd32(E1000_IMS);
+	regs_buff[22] = rd32(E1000_IMC);
+	regs_buff[23] = rd32(E1000_IAC);
+	regs_buff[24] = rd32(E1000_IAM);
+	regs_buff[25] = rd32(E1000_IMIRVP);
+
+	/* Flow Control */
+	regs_buff[26] = rd32(E1000_FCAL);
+	regs_buff[27] = rd32(E1000_FCAH);
+	regs_buff[28] = rd32(E1000_FCTTV);
+	regs_buff[29] = rd32(E1000_FCRTL);
+	regs_buff[30] = rd32(E1000_FCRTH);
+	regs_buff[31] = rd32(E1000_FCRTV);
+
+	/* Receive */
+	regs_buff[32] = rd32(E1000_RCTL);
+	regs_buff[33] = rd32(E1000_RXCSUM);
+	regs_buff[34] = rd32(E1000_RLPML);
+	regs_buff[35] = rd32(E1000_RFCTL);
+	regs_buff[36] = rd32(E1000_MRQC);
+	regs_buff[37] = rd32(E1000_VMD_CTL);
+
+	/* Transmit */
+	regs_buff[38] = rd32(E1000_TCTL);
+	regs_buff[39] = rd32(E1000_TCTL_EXT);
+	regs_buff[40] = rd32(E1000_TIPG);
+	regs_buff[41] = rd32(E1000_DTXCTL);
+
+	/* Wake Up */
+	regs_buff[42] = rd32(E1000_WUC);
+	regs_buff[43] = rd32(E1000_WUFC);
+	regs_buff[44] = rd32(E1000_WUS);
+	regs_buff[45] = rd32(E1000_IPAV);
+	regs_buff[46] = rd32(E1000_WUPL);
+
+	/* MAC */
+	regs_buff[47] = rd32(E1000_PCS_CFG0);
+	regs_buff[48] = rd32(E1000_PCS_LCTL);
+	regs_buff[49] = rd32(E1000_PCS_LSTAT);
+	regs_buff[50] = rd32(E1000_PCS_ANADV);
+	regs_buff[51] = rd32(E1000_PCS_LPAB);
+	regs_buff[52] = rd32(E1000_PCS_NPTX);
+	regs_buff[53] = rd32(E1000_PCS_LPABNP);
+
+	/* Statistics */
+	regs_buff[54] = adapter->stats.crcerrs;
+	regs_buff[55] = adapter->stats.algnerrc;
+	regs_buff[56] = adapter->stats.symerrs;
+	regs_buff[57] = adapter->stats.rxerrc;
+	regs_buff[58] = adapter->stats.mpc;
+	regs_buff[59] = adapter->stats.scc;
+	regs_buff[60] = adapter->stats.ecol;
+	regs_buff[61] = adapter->stats.mcc;
+	regs_buff[62] = adapter->stats.latecol;
+	regs_buff[63] = adapter->stats.colc;
+	regs_buff[64] = adapter->stats.dc;
+	regs_buff[65] = adapter->stats.tncrs;
+	regs_buff[66] = adapter->stats.sec;
+	regs_buff[67] = adapter->stats.htdpmc;
+	regs_buff[68] = adapter->stats.rlec;
+	regs_buff[69] = adapter->stats.xonrxc;
+	regs_buff[70] = adapter->stats.xontxc;
+	regs_buff[71] = adapter->stats.xoffrxc;
+	regs_buff[72] = adapter->stats.xofftxc;
+	regs_buff[73] = adapter->stats.fcruc;
+	regs_buff[74] = adapter->stats.prc64;
+	regs_buff[75] = adapter->stats.prc127;
+	regs_buff[76] = adapter->stats.prc255;
+	regs_buff[77] = adapter->stats.prc511;
+	regs_buff[78] = adapter->stats.prc1023;
+	regs_buff[79] = adapter->stats.prc1522;
+	regs_buff[80] = adapter->stats.gprc;
+	regs_buff[81] = adapter->stats.bprc;
+	regs_buff[82] = adapter->stats.mprc;
+	regs_buff[83] = adapter->stats.gptc;
+	regs_buff[84] = adapter->stats.gorc;
+	regs_buff[86] = adapter->stats.gotc;
+	regs_buff[88] = adapter->stats.rnbc;
+	regs_buff[89] = adapter->stats.ruc;
+	regs_buff[90] = adapter->stats.rfc;
+	regs_buff[91] = adapter->stats.roc;
+	regs_buff[92] = adapter->stats.rjc;
+	regs_buff[93] = adapter->stats.mgprc;
+	regs_buff[94] = adapter->stats.mgpdc;
+	regs_buff[95] = adapter->stats.mgptc;
+	regs_buff[96] = adapter->stats.tor;
+	regs_buff[98] = adapter->stats.tot;
+	regs_buff[100] = adapter->stats.tpr;
+	regs_buff[101] = adapter->stats.tpt;
+	regs_buff[102] = adapter->stats.ptc64;
+	regs_buff[103] = adapter->stats.ptc127;
+	regs_buff[104] = adapter->stats.ptc255;
+	regs_buff[105] = adapter->stats.ptc511;
+	regs_buff[106] = adapter->stats.ptc1023;
+	regs_buff[107] = adapter->stats.ptc1522;
+	regs_buff[108] = adapter->stats.mptc;
+	regs_buff[109] = adapter->stats.bptc;
+	regs_buff[110] = adapter->stats.tsctc;
+	regs_buff[111] = adapter->stats.iac;
+	regs_buff[112] = adapter->stats.rpthc;
+	regs_buff[113] = adapter->stats.hgptc;
+	regs_buff[114] = adapter->stats.hgorc;
+	regs_buff[116] = adapter->stats.hgotc;
+	regs_buff[118] = adapter->stats.lenerrs;
+	regs_buff[119] = adapter->stats.scvpc;
+	regs_buff[120] = adapter->stats.hrmpc;
+
+	/* These should probably be added to e1000_regs.h instead */
+	#define E1000_PSRTYPE_REG(_i) (0x05480 + ((_i) * 4))
+	#define E1000_RAL(_i)         (0x05400 + ((_i) * 8))
+	#define E1000_RAH(_i)         (0x05404 + ((_i) * 8))
+	#define E1000_IP4AT_REG(_i)   (0x05840 + ((_i) * 8))
+	#define E1000_IP6AT_REG(_i)   (0x05880 + ((_i) * 4))
+	#define E1000_WUPM_REG(_i)    (0x05A00 + ((_i) * 4))
+	#define E1000_FFMT_REG(_i)    (0x09000 + ((_i) * 8))
+	#define E1000_FFVT_REG(_i)    (0x09800 + ((_i) * 8))
+	#define E1000_FFLT_REG(_i)    (0x05F00 + ((_i) * 8))
+
+	for (i = 0; i < 4; i++)
+		regs_buff[121 + i] = rd32(E1000_SRRCTL(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[125 + i] = rd32(E1000_PSRTYPE_REG(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[129 + i] = rd32(E1000_RDBAL(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[133 + i] = rd32(E1000_RDBAH(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[137 + i] = rd32(E1000_RDLEN(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[141 + i] = rd32(E1000_RDH(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[145 + i] = rd32(E1000_RDT(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[149 + i] = rd32(E1000_RXDCTL(i));
+
+	for (i = 0; i < 10; i++)
+		regs_buff[153 + i] = rd32(E1000_EITR(i));
+	for (i = 0; i < 8; i++)
+		regs_buff[163 + i] = rd32(E1000_IMIR(i));
+	for (i = 0; i < 8; i++)
+		regs_buff[171 + i] = rd32(E1000_IMIREXT(i));
+	for (i = 0; i < 16; i++)
+		regs_buff[179 + i] = rd32(E1000_RAL(i));
+	for (i = 0; i < 16; i++)
+		regs_buff[195 + i] = rd32(E1000_RAH(i));
+
+	for (i = 0; i < 4; i++)
+		regs_buff[211 + i] = rd32(E1000_TDBAL(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[215 + i] = rd32(E1000_TDBAH(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[219 + i] = rd32(E1000_TDLEN(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[223 + i] = rd32(E1000_TDH(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[227 + i] = rd32(E1000_TDT(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[231 + i] = rd32(E1000_TXDCTL(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[235 + i] = rd32(E1000_TDWBAL(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[239 + i] = rd32(E1000_TDWBAH(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[243 + i] = rd32(E1000_DCA_TXCTRL(i));
+
+	for (i = 0; i < 4; i++)
+		regs_buff[247 + i] = rd32(E1000_IP4AT_REG(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[251 + i] = rd32(E1000_IP6AT_REG(i));
+	for (i = 0; i < 32; i++)
+		regs_buff[255 + i] = rd32(E1000_WUPM_REG(i));
+	for (i = 0; i < 128; i++)
+		regs_buff[287 + i] = rd32(E1000_FFMT_REG(i));
+	for (i = 0; i < 128; i++)
+		regs_buff[415 + i] = rd32(E1000_FFVT_REG(i));
+	for (i = 0; i < 4; i++)
+		regs_buff[543 + i] = rd32(E1000_FFLT_REG(i));
+
+	regs_buff[547] = rd32(E1000_TDFH);
+	regs_buff[548] = rd32(E1000_TDFT);
+	regs_buff[549] = rd32(E1000_TDFHS);
+	regs_buff[550] = rd32(E1000_TDFPC);
+
+}
+
+static int igb_get_eeprom_len(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	return adapter->hw.nvm.word_size * 2;
+}
+
+static int igb_get_eeprom(struct net_device *netdev,
+			  struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u16 *eeprom_buff;
+	int first_word, last_word;
+	int ret_val = 0;
+	u16 i;
+
+	if (eeprom->len == 0)
+		return -EINVAL;
+
+	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	first_word = eeprom->offset >> 1;
+	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+
+	eeprom_buff = kmalloc(sizeof(u16) *
+			(last_word - first_word + 1), GFP_KERNEL);
+	if (!eeprom_buff)
+		return -ENOMEM;
+
+	if (hw->nvm.type == e1000_nvm_eeprom_spi)
+		ret_val = hw->nvm.ops.read_nvm(hw, first_word,
+					    last_word - first_word + 1,
+					    eeprom_buff);
+	else {
+		for (i = 0; i < last_word - first_word + 1; i++) {
+			ret_val = hw->nvm.ops.read_nvm(hw, first_word + i, 1,
+						    &eeprom_buff[i]);
+			if (ret_val)
+				break;
+		}
+	}
+
+	/* Device's eeprom is always little-endian, word addressable */
+	for (i = 0; i < last_word - first_word + 1; i++)
+		le16_to_cpus(&eeprom_buff[i]);
+
+	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1),
+			eeprom->len);
+	kfree(eeprom_buff);
+
+	return ret_val;
+}
+
+static int igb_set_eeprom(struct net_device *netdev,
+			  struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u16 *eeprom_buff;
+	void *ptr;
+	int max_len, first_word, last_word, ret_val = 0;
+	u16 i;
+
+	if (eeprom->len == 0)
+		return -EOPNOTSUPP;
+
+	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
+		return -EFAULT;
+
+	max_len = hw->nvm.word_size * 2;
+
+	first_word = eeprom->offset >> 1;
+	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+	if (!eeprom_buff)
+		return -ENOMEM;
+
+	ptr = (void *)eeprom_buff;
+
+	if (eeprom->offset & 1) {
+		/* need read/modify/write of first changed EEPROM word */
+		/* only the second byte of the word is being modified */
+		ret_val = hw->nvm.ops.read_nvm(hw, first_word, 1,
+					    &eeprom_buff[0]);
+		ptr++;
+	}
+	if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
+		/* need read/modify/write of last changed EEPROM word */
+		/* only the first byte of the word is being modified */
+		ret_val = hw->nvm.ops.read_nvm(hw, last_word, 1,
+				   &eeprom_buff[last_word - first_word]);
+	}
+
+	/* Device's eeprom is always little-endian, word addressable */
+	for (i = 0; i < last_word - first_word + 1; i++)
+		le16_to_cpus(&eeprom_buff[i]);
+
+	memcpy(ptr, bytes, eeprom->len);
+
+	for (i = 0; i < last_word - first_word + 1; i++)
+		eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
+
+	ret_val = hw->nvm.ops.write_nvm(hw, first_word,
+				     last_word - first_word + 1, eeprom_buff);
+
+	/* Update the checksum over the first part of the EEPROM if needed
+	 * and flush shadow RAM for 82573 controllers */
+	if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG)))
+		igb_update_nvm_checksum(hw);
+
+	kfree(eeprom_buff);
+	return ret_val;
+}
+
+static void igb_get_drvinfo(struct net_device *netdev,
+			    struct ethtool_drvinfo *drvinfo)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	char firmware_version[32];
+	u16 eeprom_data;
+
+	strncpy(drvinfo->driver,  igb_driver_name, 32);
+	strncpy(drvinfo->version, igb_driver_version, 32);
+
+	/* EEPROM image version # is reported as firmware version # for
+	 * 82575 controllers */
+	adapter->hw.nvm.ops.read_nvm(&adapter->hw, 5, 1, &eeprom_data);
+	sprintf(firmware_version, "%d.%d-%d",
+		(eeprom_data & 0xF000) >> 12,
+		(eeprom_data & 0x0FF0) >> 4,
+		eeprom_data & 0x000F);
+
+	strncpy(drvinfo->fw_version, firmware_version, 32);
+	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+	drvinfo->n_stats = IGB_STATS_LEN;
+	drvinfo->testinfo_len = IGB_TEST_LEN;
+	drvinfo->regdump_len = igb_get_regs_len(netdev);
+	drvinfo->eedump_len = igb_get_eeprom_len(netdev);
+}
+
+static void igb_get_ringparam(struct net_device *netdev,
+			      struct ethtool_ringparam *ring)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct igb_ring *tx_ring = adapter->tx_ring;
+	struct igb_ring *rx_ring = adapter->rx_ring;
+
+	ring->rx_max_pending = IGB_MAX_RXD;
+	ring->tx_max_pending = IGB_MAX_TXD;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = rx_ring->count;
+	ring->tx_pending = tx_ring->count;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+}
+
+static int igb_set_ringparam(struct net_device *netdev,
+			     struct ethtool_ringparam *ring)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct igb_buffer *old_buf;
+	struct igb_buffer *old_rx_buf;
+	void *old_desc;
+	int i, err;
+	u32 new_rx_count, new_tx_count, old_size;
+	dma_addr_t old_dma;
+
+	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+		return -EINVAL;
+
+	new_rx_count = max(ring->rx_pending, (u32)IGB_MIN_RXD);
+	new_rx_count = min(new_rx_count, (u32)IGB_MAX_RXD);
+	new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE);
+
+	new_tx_count = max(ring->tx_pending, (u32)IGB_MIN_TXD);
+	new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD);
+	new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE);
+
+	if ((new_tx_count == adapter->tx_ring->count) &&
+	    (new_rx_count == adapter->rx_ring->count)) {
+		/* nothing to do */
+		return 0;
+	}
+
+	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+		msleep(1);
+
+	if (netif_running(adapter->netdev))
+		igb_down(adapter);
+
+	/*
+	 * We can't just free everything and then setup again,
+	 * because the ISRs in MSI-X mode get passed pointers
+	 * to the tx and rx ring structs.
+	 */
+	if (new_tx_count != adapter->tx_ring->count) {
+		for (i = 0; i < adapter->num_tx_queues; i++) {
+			/* Save existing descriptor ring */
+			old_buf = adapter->tx_ring[i].buffer_info;
+			old_desc = adapter->tx_ring[i].desc;
+			old_size = adapter->tx_ring[i].size;
+			old_dma = adapter->tx_ring[i].dma;
+			/* Try to allocate a new one */
+			adapter->tx_ring[i].buffer_info = NULL;
+			adapter->tx_ring[i].desc = NULL;
+			adapter->tx_ring[i].count = new_tx_count;
+			err = igb_setup_tx_resources(adapter,
+						&adapter->tx_ring[i]);
+			if (err) {
+				/* Restore the old one so at least
+				   the adapter still works, even if
+				   we failed the request */
+				adapter->tx_ring[i].buffer_info = old_buf;
+				adapter->tx_ring[i].desc = old_desc;
+				adapter->tx_ring[i].size = old_size;
+				adapter->tx_ring[i].dma = old_dma;
+				goto err_setup;
+			}
+			/* Free the old buffer manually */
+			vfree(old_buf);
+			pci_free_consistent(adapter->pdev, old_size,
+					    old_desc, old_dma);
+		}
+	}
+
+	if (new_rx_count != adapter->rx_ring->count) {
+		for (i = 0; i < adapter->num_rx_queues; i++) {
+
+			old_rx_buf = adapter->rx_ring[i].buffer_info;
+			old_desc = adapter->rx_ring[i].desc;
+			old_size = adapter->rx_ring[i].size;
+			old_dma = adapter->rx_ring[i].dma;
+
+			adapter->rx_ring[i].buffer_info = NULL;
+			adapter->rx_ring[i].desc = NULL;
+			adapter->rx_ring[i].dma = 0;
+			adapter->rx_ring[i].count = new_rx_count;
+			err = igb_setup_rx_resources(adapter,
+						     &adapter->rx_ring[i]);
+			if (err) {
+				adapter->rx_ring[i].buffer_info = old_rx_buf;
+				adapter->rx_ring[i].desc = old_desc;
+				adapter->rx_ring[i].size = old_size;
+				adapter->rx_ring[i].dma = old_dma;
+				goto err_setup;
+			}
+
+			vfree(old_rx_buf);
+			pci_free_consistent(adapter->pdev, old_size, old_desc,
+					    old_dma);
+		}
+	}
+
+	err = 0;
+err_setup:
+	if (netif_running(adapter->netdev))
+		igb_up(adapter);
+
+	clear_bit(__IGB_RESETTING, &adapter->state);
+	return err;
+}
+
+/* ethtool register test data */
+struct igb_reg_test {
+	u16 reg;
+	u8  array_len;
+	u8  test_type;
+	u32 mask;
+	u32 write;
+};
+
+/* In the hardware, registers are laid out either singly, in arrays
+ * spaced 0x100 bytes apart, or in contiguous tables.  We assume
+ * most tests take place on arrays or single registers (handled
+ * as a single-element array) and special-case the tables.
+ * Table tests are always pattern tests.
+ *
+ * We also make provision for some required setup steps by specifying
+ * registers to be written without any read-back testing.
+ */
+
+#define PATTERN_TEST	1
+#define SET_READ_TEST	2
+#define WRITE_NO_TEST	3
+#define TABLE32_TEST	4
+#define TABLE64_TEST_LO	5
+#define TABLE64_TEST_HI	6
+
+/* default register test */
+static struct igb_reg_test reg_test_82575[] = {
+	{ E1000_FCAL, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ E1000_FCAH, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
+	{ E1000_FCT, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
+	{ E1000_VET, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ E1000_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+	{ E1000_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ E1000_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+	/* Enable all four RX queues before testing. */
+	{ E1000_RXDCTL(0), 4, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE },
+	/* RDH is read-only for 82575, only test RDT. */
+	{ E1000_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+	{ E1000_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 },
+	{ E1000_FCRTH, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 },
+	{ E1000_FCTTV, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+	{ E1000_TIPG, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
+	{ E1000_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+	{ E1000_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ E1000_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+	{ E1000_RCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
+	{ E1000_RCTL, 1, SET_READ_TEST, 0x04CFB3FE, 0x003FFFFB },
+	{ E1000_RCTL, 1, SET_READ_TEST, 0x04CFB3FE, 0xFFFFFFFF },
+	{ E1000_TCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
+	{ E1000_TXCW, 1, PATTERN_TEST, 0xC000FFFF, 0x0000FFFF },
+	{ E1000_RA, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ E1000_RA, 16, TABLE64_TEST_HI, 0x800FFFFF, 0xFFFFFFFF },
+	{ E1000_MTA, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+	{ 0, 0, 0, 0 }
+};
+
+static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,
+			     int reg, u32 mask, u32 write)
+{
+	u32 pat, val;
+	u32 _test[] =
+		{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+	for (pat = 0; pat < ARRAY_SIZE(_test); pat++) {
+		writel((_test[pat] & write), (adapter->hw.hw_addr + reg));
+		val = readl(adapter->hw.hw_addr + reg);
+		if (val != (_test[pat] & write & mask)) {
+			dev_err(&adapter->pdev->dev, "pattern test reg %04X "
+				"failed: got 0x%08X expected 0x%08X\n",
+				reg, val, (_test[pat] & write & mask));
+			*data = reg;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data,
+			      int reg, u32 mask, u32 write)
+{
+	u32 val;
+	writel((write & mask), (adapter->hw.hw_addr + reg));
+	val = readl(adapter->hw.hw_addr + reg);
+	if ((write & mask) != (val & mask)) {
+		dev_err(&adapter->pdev->dev, "set/check reg %04X test failed:"
+			" got 0x%08X expected 0x%08X\n", reg,
+			(val & mask), (write & mask));
+		*data = reg;
+		return 1;
+	}
+	return 0;
+}
+
+#define REG_PATTERN_TEST(reg, mask, write) \
+	do { \
+		if (reg_pattern_test(adapter, data, reg, mask, write)) \
+			return 1; \
+	} while (0)
+
+#define REG_SET_AND_CHECK(reg, mask, write) \
+	do { \
+		if (reg_set_and_check(adapter, data, reg, mask, write)) \
+			return 1; \
+	} while (0)
+
+static int igb_reg_test(struct igb_adapter *adapter, u64 *data)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct igb_reg_test *test;
+	u32 value, before, after;
+	u32 i, toggle;
+
+	toggle = 0x7FFFF3FF;
+	test = reg_test_82575;
+
+	/* Because the status register is such a special case,
+	 * we handle it separately from the rest of the register
+	 * tests.  Some bits are read-only, some toggle, and some
+	 * are writable on newer MACs.
+	 */
+	before = rd32(E1000_STATUS);
+	value = (rd32(E1000_STATUS) & toggle);
+	wr32(E1000_STATUS, toggle);
+	after = rd32(E1000_STATUS) & toggle;
+	if (value != after) {
+		dev_err(&adapter->pdev->dev, "failed STATUS register test "
+			"got: 0x%08X expected: 0x%08X\n", after, value);
+		*data = 1;
+		return 1;
+	}
+	/* restore previous status */
+	wr32(E1000_STATUS, before);
+
+	/* Perform the remainder of the register test, looping through
+	 * the test table until we either fail or reach the null entry.
+	 */
+	while (test->reg) {
+		for (i = 0; i < test->array_len; i++) {
+			switch (test->test_type) {
+			case PATTERN_TEST:
+				REG_PATTERN_TEST(test->reg + (i * 0x100),
+						test->mask,
+						test->write);
+				break;
+			case SET_READ_TEST:
+				REG_SET_AND_CHECK(test->reg + (i * 0x100),
+						test->mask,
+						test->write);
+				break;
+			case WRITE_NO_TEST:
+				writel(test->write,
+				    (adapter->hw.hw_addr + test->reg)
+					+ (i * 0x100));
+				break;
+			case TABLE32_TEST:
+				REG_PATTERN_TEST(test->reg + (i * 4),
+						test->mask,
+						test->write);
+				break;
+			case TABLE64_TEST_LO:
+				REG_PATTERN_TEST(test->reg + (i * 8),
+						test->mask,
+						test->write);
+				break;
+			case TABLE64_TEST_HI:
+				REG_PATTERN_TEST((test->reg + 4) + (i * 8),
+						test->mask,
+						test->write);
+				break;
+			}
+		}
+		test++;
+	}
+
+	*data = 0;
+	return 0;
+}
+
+static int igb_eeprom_test(struct igb_adapter *adapter, u64 *data)
+{
+	u16 temp;
+	u16 checksum = 0;
+	u16 i;
+
+	*data = 0;
+	/* Read and add up the contents of the EEPROM */
+	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+		if ((adapter->hw.nvm.ops.read_nvm(&adapter->hw, i, 1, &temp))
+		    < 0) {
+			*data = 1;
+			break;
+		}
+		checksum += temp;
+	}
+
+	/* If Checksum is not Correct return error else test passed */
+	if ((checksum != (u16) NVM_SUM) && !(*data))
+		*data = 2;
+
+	return *data;
+}
+
+static irqreturn_t igb_test_intr(int irq, void *data)
+{
+	struct net_device *netdev = (struct net_device *) data;
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	adapter->test_icr |= rd32(E1000_ICR);
+
+	return IRQ_HANDLED;
+}
+
+static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	u32 mask, i = 0, shared_int = true;
+	u32 irq = adapter->pdev->irq;
+
+	*data = 0;
+
+	/* Hook up test interrupt handler just for this test */
+	if (adapter->msix_entries) {
+		/* NOTE: we don't test MSI-X interrupts here, yet */
+		return 0;
+	} else if (adapter->msi_enabled) {
+		shared_int = false;
+		if (request_irq(irq, &igb_test_intr, 0, netdev->name, netdev)) {
+			*data = 1;
+			return -1;
+		}
+	} else if (!request_irq(irq, &igb_test_intr, IRQF_PROBE_SHARED,
+				netdev->name, netdev)) {
+		shared_int = false;
+	} else if (request_irq(irq, &igb_test_intr, IRQF_SHARED,
+		 netdev->name, netdev)) {
+		*data = 1;
+		return -1;
+	}
+	dev_info(&adapter->pdev->dev, "testing %s interrupt\n",
+		(shared_int ? "shared" : "unshared"));
+
+	/* Disable all the interrupts */
+	wr32(E1000_IMC, 0xFFFFFFFF);
+	msleep(10);
+
+	/* Test each interrupt */
+	for (; i < 10; i++) {
+		/* Interrupt to test */
+		mask = 1 << i;
+
+		if (!shared_int) {
+			/* Disable the interrupt to be reported in
+			 * the cause register and then force the same
+			 * interrupt and see if one gets posted.  If
+			 * an interrupt was posted to the bus, the
+			 * test failed.
+			 */
+			adapter->test_icr = 0;
+			wr32(E1000_IMC, ~mask & 0x00007FFF);
+			wr32(E1000_ICS, ~mask & 0x00007FFF);
+			msleep(10);
+
+			if (adapter->test_icr & mask) {
+				*data = 3;
+				break;
+			}
+		}
+
+		/* Enable the interrupt to be reported in
+		 * the cause register and then force the same
+		 * interrupt and see if one gets posted.  If
+		 * an interrupt was not posted to the bus, the
+		 * test failed.
+		 */
+		adapter->test_icr = 0;
+		wr32(E1000_IMS, mask);
+		wr32(E1000_ICS, mask);
+		msleep(10);
+
+		if (!(adapter->test_icr & mask)) {
+			*data = 4;
+			break;
+		}
+
+		if (!shared_int) {
+			/* Disable the other interrupts to be reported in
+			 * the cause register and then force the other
+			 * interrupts and see if any get posted.  If
+			 * an interrupt was posted to the bus, the
+			 * test failed.
+			 */
+			adapter->test_icr = 0;
+			wr32(E1000_IMC, ~mask & 0x00007FFF);
+			wr32(E1000_ICS, ~mask & 0x00007FFF);
+			msleep(10);
+
+			if (adapter->test_icr) {
+				*data = 5;
+				break;
+			}
+		}
+	}
+
+	/* Disable all the interrupts */
+	wr32(E1000_IMC, 0xFFFFFFFF);
+	msleep(10);
+
+	/* Unhook test interrupt handler */
+	free_irq(irq, netdev);
+
+	return *data;
+}
+
+static void igb_free_desc_rings(struct igb_adapter *adapter)
+{
+	struct igb_ring *tx_ring = &adapter->test_tx_ring;
+	struct igb_ring *rx_ring = &adapter->test_rx_ring;
+	struct pci_dev *pdev = adapter->pdev;
+	int i;
+
+	if (tx_ring->desc && tx_ring->buffer_info) {
+		for (i = 0; i < tx_ring->count; i++) {
+			struct igb_buffer *buf = &(tx_ring->buffer_info[i]);
+			if (buf->dma)
+				pci_unmap_single(pdev, buf->dma, buf->length,
+						 PCI_DMA_TODEVICE);
+			if (buf->skb)
+				dev_kfree_skb(buf->skb);
+		}
+	}
+
+	if (rx_ring->desc && rx_ring->buffer_info) {
+		for (i = 0; i < rx_ring->count; i++) {
+			struct igb_buffer *buf = &(rx_ring->buffer_info[i]);
+			if (buf->dma)
+				pci_unmap_single(pdev, buf->dma,
+						 IGB_RXBUFFER_2048,
+						 PCI_DMA_FROMDEVICE);
+			if (buf->skb)
+				dev_kfree_skb(buf->skb);
+		}
+	}
+
+	if (tx_ring->desc) {
+		pci_free_consistent(pdev, tx_ring->size, tx_ring->desc,
+				    tx_ring->dma);
+		tx_ring->desc = NULL;
+	}
+	if (rx_ring->desc) {
+		pci_free_consistent(pdev, rx_ring->size, rx_ring->desc,
+				    rx_ring->dma);
+		rx_ring->desc = NULL;
+	}
+
+	kfree(tx_ring->buffer_info);
+	tx_ring->buffer_info = NULL;
+	kfree(rx_ring->buffer_info);
+	rx_ring->buffer_info = NULL;
+
+	return;
+}
+
+static int igb_setup_desc_rings(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct igb_ring *tx_ring = &adapter->test_tx_ring;
+	struct igb_ring *rx_ring = &adapter->test_rx_ring;
+	struct pci_dev *pdev = adapter->pdev;
+	u32 rctl;
+	int i, ret_val;
+
+	/* Setup Tx descriptor ring and Tx buffers */
+
+	if (!tx_ring->count)
+		tx_ring->count = IGB_DEFAULT_TXD;
+
+	tx_ring->buffer_info = kcalloc(tx_ring->count,
+				       sizeof(struct igb_buffer),
+				       GFP_KERNEL);
+	if (!tx_ring->buffer_info) {
+		ret_val = 1;
+		goto err_nomem;
+	}
+
+	tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
+	tx_ring->size = ALIGN(tx_ring->size, 4096);
+	tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
+					     &tx_ring->dma);
+	if (!tx_ring->desc) {
+		ret_val = 2;
+		goto err_nomem;
+	}
+	tx_ring->next_to_use = tx_ring->next_to_clean = 0;
+
+	wr32(E1000_TDBAL(0),
+			((u64) tx_ring->dma & 0x00000000FFFFFFFF));
+	wr32(E1000_TDBAH(0), ((u64) tx_ring->dma >> 32));
+	wr32(E1000_TDLEN(0),
+			tx_ring->count * sizeof(struct e1000_tx_desc));
+	wr32(E1000_TDH(0), 0);
+	wr32(E1000_TDT(0), 0);
+	wr32(E1000_TCTL,
+			E1000_TCTL_PSP | E1000_TCTL_EN |
+			E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
+			E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT);
+
+	for (i = 0; i < tx_ring->count; i++) {
+		struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i);
+		struct sk_buff *skb;
+		unsigned int size = 1024;
+
+		skb = alloc_skb(size, GFP_KERNEL);
+		if (!skb) {
+			ret_val = 3;
+			goto err_nomem;
+		}
+		skb_put(skb, size);
+		tx_ring->buffer_info[i].skb = skb;
+		tx_ring->buffer_info[i].length = skb->len;
+		tx_ring->buffer_info[i].dma =
+			pci_map_single(pdev, skb->data, skb->len,
+				       PCI_DMA_TODEVICE);
+		tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma);
+		tx_desc->lower.data = cpu_to_le32(skb->len);
+		tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
+						   E1000_TXD_CMD_IFCS |
+						   E1000_TXD_CMD_RS);
+		tx_desc->upper.data = 0;
+	}
+
+	/* Setup Rx descriptor ring and Rx buffers */
+
+	if (!rx_ring->count)
+		rx_ring->count = IGB_DEFAULT_RXD;
+
+	rx_ring->buffer_info = kcalloc(rx_ring->count,
+				       sizeof(struct igb_buffer),
+				       GFP_KERNEL);
+	if (!rx_ring->buffer_info) {
+		ret_val = 4;
+		goto err_nomem;
+	}
+
+	rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc);
+	rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
+					     &rx_ring->dma);
+	if (!rx_ring->desc) {
+		ret_val = 5;
+		goto err_nomem;
+	}
+	rx_ring->next_to_use = rx_ring->next_to_clean = 0;
+
+	rctl = rd32(E1000_RCTL);
+	wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
+	wr32(E1000_RDBAL(0),
+			((u64) rx_ring->dma & 0xFFFFFFFF));
+	wr32(E1000_RDBAH(0),
+			((u64) rx_ring->dma >> 32));
+	wr32(E1000_RDLEN(0), rx_ring->size);
+	wr32(E1000_RDH(0), 0);
+	wr32(E1000_RDT(0), 0);
+	rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
+		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+		(adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+	wr32(E1000_RCTL, rctl);
+	wr32(E1000_SRRCTL(0), 0);
+
+	for (i = 0; i < rx_ring->count; i++) {
+		struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i);
+		struct sk_buff *skb;
+
+		skb = alloc_skb(IGB_RXBUFFER_2048 + NET_IP_ALIGN,
+				GFP_KERNEL);
+		if (!skb) {
+			ret_val = 6;
+			goto err_nomem;
+		}
+		skb_reserve(skb, NET_IP_ALIGN);
+		rx_ring->buffer_info[i].skb = skb;
+		rx_ring->buffer_info[i].dma =
+			pci_map_single(pdev, skb->data, IGB_RXBUFFER_2048,
+				       PCI_DMA_FROMDEVICE);
+		rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
+		memset(skb->data, 0x00, skb->len);
+	}
+
+	return 0;
+
+err_nomem:
+	igb_free_desc_rings(adapter);
+	return ret_val;
+}
+
+static void igb_phy_disable_receiver(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	/* Write out to PHY registers 29 and 30 to disable the Receiver. */
+	hw->phy.ops.write_phy_reg(hw, 29, 0x001F);
+	hw->phy.ops.write_phy_reg(hw, 30, 0x8FFC);
+	hw->phy.ops.write_phy_reg(hw, 29, 0x001A);
+	hw->phy.ops.write_phy_reg(hw, 30, 0x8FF0);
+}
+
+static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_reg = 0;
+	u32 stat_reg = 0;
+
+	hw->mac.autoneg = false;
+
+	if (hw->phy.type == e1000_phy_m88) {
+		/* Auto-MDI/MDIX Off */
+		hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
+		/* reset to update Auto-MDI/MDIX */
+		hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x9140);
+		/* autoneg off */
+		hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x8140);
+	}
+
+	ctrl_reg = rd32(E1000_CTRL);
+
+	/* force 1000, set loopback */
+	hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x4140);
+
+	/* Now set up the MAC to the same speed/duplex as the PHY. */
+	ctrl_reg = rd32(E1000_CTRL);
+	ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+	ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+		     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+		     E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+		     E1000_CTRL_FD);	 /* Force Duplex to FULL */
+
+	if (hw->phy.media_type == e1000_media_type_copper &&
+	    hw->phy.type == e1000_phy_m88)
+		ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
+	else {
+		/* Set the ILOS bit on the fiber Nic if half duplex link is
+		 * detected. */
+		stat_reg = rd32(E1000_STATUS);
+		if ((stat_reg & E1000_STATUS_FD) == 0)
+			ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
+	}
+
+	wr32(E1000_CTRL, ctrl_reg);
+
+	/* Disable the receiver on the PHY so when a cable is plugged in, the
+	 * PHY does not begin to autoneg when a cable is reconnected to the NIC.
+	 */
+	if (hw->phy.type == e1000_phy_m88)
+		igb_phy_disable_receiver(adapter);
+
+	udelay(500);
+
+	return 0;
+}
+
+static int igb_set_phy_loopback(struct igb_adapter *adapter)
+{
+	return igb_integrated_phy_loopback(adapter);
+}
+
+static int igb_setup_loopback_test(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 rctl;
+
+	if (hw->phy.media_type == e1000_media_type_fiber ||
+	    hw->phy.media_type == e1000_media_type_internal_serdes) {
+		rctl = rd32(E1000_RCTL);
+		rctl |= E1000_RCTL_LBM_TCVR;
+		wr32(E1000_RCTL, rctl);
+		return 0;
+	} else if (hw->phy.media_type == e1000_media_type_copper) {
+		return igb_set_phy_loopback(adapter);
+	}
+
+	return 7;
+}
+
+static void igb_loopback_cleanup(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 rctl;
+	u16 phy_reg;
+
+	rctl = rd32(E1000_RCTL);
+	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
+	wr32(E1000_RCTL, rctl);
+
+	hw->mac.autoneg = true;
+	hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_reg);
+	if (phy_reg & MII_CR_LOOPBACK) {
+		phy_reg &= ~MII_CR_LOOPBACK;
+		hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_reg);
+		igb_phy_sw_reset(hw);
+	}
+}
+
+static void igb_create_lbtest_frame(struct sk_buff *skb,
+				    unsigned int frame_size)
+{
+	memset(skb->data, 0xFF, frame_size);
+	frame_size &= ~1;
+	memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+	memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
+	memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
+}
+
+static int igb_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size)
+{
+	frame_size &= ~1;
+	if (*(skb->data + 3) == 0xFF)
+		if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+		   (*(skb->data + frame_size / 2 + 12) == 0xAF))
+			return 0;
+	return 13;
+}
+
+static int igb_run_loopback_test(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct igb_ring *tx_ring = &adapter->test_tx_ring;
+	struct igb_ring *rx_ring = &adapter->test_rx_ring;
+	struct pci_dev *pdev = adapter->pdev;
+	int i, j, k, l, lc, good_cnt;
+	int ret_val = 0;
+	unsigned long time;
+
+	wr32(E1000_RDT(0), rx_ring->count - 1);
+
+	/* Calculate the loop count based on the largest descriptor ring
+	 * The idea is to wrap the largest ring a number of times using 64
+	 * send/receive pairs during each loop
+	 */
+
+	if (rx_ring->count <= tx_ring->count)
+		lc = ((tx_ring->count / 64) * 2) + 1;
+	else
+		lc = ((rx_ring->count / 64) * 2) + 1;
+
+	k = l = 0;
+	for (j = 0; j <= lc; j++) { /* loop count loop */
+		for (i = 0; i < 64; i++) { /* send the packets */
+			igb_create_lbtest_frame(tx_ring->buffer_info[k].skb,
+						1024);
+			pci_dma_sync_single_for_device(pdev,
+				tx_ring->buffer_info[k].dma,
+				tx_ring->buffer_info[k].length,
+				PCI_DMA_TODEVICE);
+			k++;
+			if (k == tx_ring->count)
+				k = 0;
+		}
+		wr32(E1000_TDT(0), k);
+		msleep(200);
+		time = jiffies; /* set the start time for the receive */
+		good_cnt = 0;
+		do { /* receive the sent packets */
+			pci_dma_sync_single_for_cpu(pdev,
+					rx_ring->buffer_info[l].dma,
+					IGB_RXBUFFER_2048,
+					PCI_DMA_FROMDEVICE);
+
+			ret_val = igb_check_lbtest_frame(
+					     rx_ring->buffer_info[l].skb, 1024);
+			if (!ret_val)
+				good_cnt++;
+			l++;
+			if (l == rx_ring->count)
+				l = 0;
+			/* time + 20 msecs (200 msecs on 2.4) is more than
+			 * enough time to complete the receives, if it's
+			 * exceeded, break and error off
+			 */
+		} while (good_cnt < 64 && jiffies < (time + 20));
+		if (good_cnt != 64) {
+			ret_val = 13; /* ret_val is the same as mis-compare */
+			break;
+		}
+		if (jiffies >= (time + 20)) {
+			ret_val = 14; /* error code for time out error */
+			break;
+		}
+	} /* end loop count loop */
+	return ret_val;
+}
+
+static int igb_loopback_test(struct igb_adapter *adapter, u64 *data)
+{
+	/* PHY loopback cannot be performed if SoL/IDER
+	 * sessions are active */
+	if (igb_check_reset_block(&adapter->hw)) {
+		dev_err(&adapter->pdev->dev,
+			"Cannot do PHY loopback test "
+			"when SoL/IDER is active.\n");
+		*data = 0;
+		goto out;
+	}
+	*data = igb_setup_desc_rings(adapter);
+	if (*data)
+		goto out;
+	*data = igb_setup_loopback_test(adapter);
+	if (*data)
+		goto err_loopback;
+	*data = igb_run_loopback_test(adapter);
+	igb_loopback_cleanup(adapter);
+
+err_loopback:
+	igb_free_desc_rings(adapter);
+out:
+	return *data;
+}
+
+static int igb_link_test(struct igb_adapter *adapter, u64 *data)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	*data = 0;
+	if (hw->phy.media_type == e1000_media_type_internal_serdes) {
+		int i = 0;
+		hw->mac.serdes_has_link = false;
+
+		/* On some blade server designs, link establishment
+		 * could take as long as 2-3 minutes */
+		do {
+			hw->mac.ops.check_for_link(&adapter->hw);
+			if (hw->mac.serdes_has_link)
+				return *data;
+			msleep(20);
+		} while (i++ < 3750);
+
+		*data = 1;
+	} else {
+		hw->mac.ops.check_for_link(&adapter->hw);
+		if (hw->mac.autoneg)
+			msleep(4000);
+
+		if (!(rd32(E1000_STATUS) &
+		      E1000_STATUS_LU))
+			*data = 1;
+	}
+	return *data;
+}
+
+static void igb_diag_test(struct net_device *netdev,
+			  struct ethtool_test *eth_test, u64 *data)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	u16 autoneg_advertised;
+	u8 forced_speed_duplex, autoneg;
+	bool if_running = netif_running(netdev);
+
+	set_bit(__IGB_TESTING, &adapter->state);
+	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+		/* Offline tests */
+
+		/* save speed, duplex, autoneg settings */
+		autoneg_advertised = adapter->hw.phy.autoneg_advertised;
+		forced_speed_duplex = adapter->hw.mac.forced_speed_duplex;
+		autoneg = adapter->hw.mac.autoneg;
+
+		dev_info(&adapter->pdev->dev, "offline testing starting\n");
+
+		/* Link test performed before hardware reset so autoneg doesn't
+		 * interfere with test result */
+		if (igb_link_test(adapter, &data[4]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		if (if_running)
+			/* indicate we're in test mode */
+			dev_close(netdev);
+		else
+			igb_reset(adapter);
+
+		if (igb_reg_test(adapter, &data[0]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		igb_reset(adapter);
+		if (igb_eeprom_test(adapter, &data[1]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		igb_reset(adapter);
+		if (igb_intr_test(adapter, &data[2]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		igb_reset(adapter);
+		if (igb_loopback_test(adapter, &data[3]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		/* restore speed, duplex, autoneg settings */
+		adapter->hw.phy.autoneg_advertised = autoneg_advertised;
+		adapter->hw.mac.forced_speed_duplex = forced_speed_duplex;
+		adapter->hw.mac.autoneg = autoneg;
+
+		/* force this routine to wait until autoneg complete/timeout */
+		adapter->hw.phy.autoneg_wait_to_complete = true;
+		igb_reset(adapter);
+		adapter->hw.phy.autoneg_wait_to_complete = false;
+
+		clear_bit(__IGB_TESTING, &adapter->state);
+		if (if_running)
+			dev_open(netdev);
+	} else {
+		dev_info(&adapter->pdev->dev, "online testing starting\n");
+		/* Online tests */
+		if (igb_link_test(adapter, &data[4]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		/* Online tests aren't run; pass by default */
+		data[0] = 0;
+		data[1] = 0;
+		data[2] = 0;
+		data[3] = 0;
+
+		clear_bit(__IGB_TESTING, &adapter->state);
+	}
+	msleep_interruptible(4 * 1000);
+}
+
+static int igb_wol_exclusion(struct igb_adapter *adapter,
+			     struct ethtool_wolinfo *wol)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	int retval = 1; /* fail by default */
+
+	switch (hw->device_id) {
+	case E1000_DEV_ID_82575GB_QUAD_COPPER:
+		/* WoL not supported */
+		wol->supported = 0;
+		break;
+	case E1000_DEV_ID_82575EB_FIBER_SERDES:
+		/* Wake events not supported on port B */
+		if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1) {
+			wol->supported = 0;
+			break;
+		}
+		/* return success for non excluded adapter ports */
+		retval = 0;
+		break;
+	default:
+		/* dual port cards only support WoL on port A from now on
+		 * unless it was enabled in the eeprom for port B
+		 * so exclude FUNC_1 ports from having WoL enabled */
+		if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1 &&
+		    !adapter->eeprom_wol) {
+			wol->supported = 0;
+			break;
+		}
+
+		retval = 0;
+	}
+
+	return retval;
+}
+
+static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	wol->supported = WAKE_UCAST | WAKE_MCAST |
+			 WAKE_BCAST | WAKE_MAGIC;
+	wol->wolopts = 0;
+
+	/* this function will set ->supported = 0 and return 1 if wol is not
+	 * supported by this hardware */
+	if (igb_wol_exclusion(adapter, wol))
+		return;
+
+	/* apply any specific unsupported masks here */
+	switch (adapter->hw.device_id) {
+	default:
+		break;
+	}
+
+	if (adapter->wol & E1000_WUFC_EX)
+		wol->wolopts |= WAKE_UCAST;
+	if (adapter->wol & E1000_WUFC_MC)
+		wol->wolopts |= WAKE_MCAST;
+	if (adapter->wol & E1000_WUFC_BC)
+		wol->wolopts |= WAKE_BCAST;
+	if (adapter->wol & E1000_WUFC_MAG)
+		wol->wolopts |= WAKE_MAGIC;
+
+	return;
+}
+
+static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+		return -EOPNOTSUPP;
+
+	if (igb_wol_exclusion(adapter, wol))
+		return wol->wolopts ? -EOPNOTSUPP : 0;
+
+	switch (hw->device_id) {
+	default:
+		break;
+	}
+
+	/* these settings will always override what we currently have */
+	adapter->wol = 0;
+
+	if (wol->wolopts & WAKE_UCAST)
+		adapter->wol |= E1000_WUFC_EX;
+	if (wol->wolopts & WAKE_MCAST)
+		adapter->wol |= E1000_WUFC_MC;
+	if (wol->wolopts & WAKE_BCAST)
+		adapter->wol |= E1000_WUFC_BC;
+	if (wol->wolopts & WAKE_MAGIC)
+		adapter->wol |= E1000_WUFC_MAG;
+
+	return 0;
+}
+
+/* toggle LED 4 times per second = 2 "blinks" per second */
+#define IGB_ID_INTERVAL		(HZ/4)
+
+/* bit defines for adapter->led_status */
+#define IGB_LED_ON		0
+
+static int igb_phys_id(struct net_device *netdev, u32 data)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+		data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
+	igb_blink_led(hw);
+	msleep_interruptible(data * 1000);
+
+	igb_led_off(hw);
+	clear_bit(IGB_LED_ON, &adapter->led_status);
+	igb_cleanup_led(hw);
+
+	return 0;
+}
+
+static int igb_set_coalesce(struct net_device *netdev,
+			    struct ethtool_coalesce *ec)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) ||
+	    ((ec->rx_coalesce_usecs > 3) &&
+	     (ec->rx_coalesce_usecs < IGB_MIN_ITR_USECS)) ||
+	    (ec->rx_coalesce_usecs == 2))
+		return -EINVAL;
+
+	/* convert to rate of irq's per second */
+	if (ec->rx_coalesce_usecs <= 3)
+		adapter->itr_setting = ec->rx_coalesce_usecs;
+	else
+		adapter->itr_setting = (1000000 / ec->rx_coalesce_usecs);
+
+	if (netif_running(netdev))
+		igb_reinit_locked(adapter);
+
+	return 0;
+}
+
+static int igb_get_coalesce(struct net_device *netdev,
+			    struct ethtool_coalesce *ec)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	if (adapter->itr_setting <= 3)
+		ec->rx_coalesce_usecs = adapter->itr_setting;
+	else
+		ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
+
+	return 0;
+}
+
+
+static int igb_nway_reset(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	if (netif_running(netdev))
+		igb_reinit_locked(adapter);
+	return 0;
+}
+
+static int igb_get_sset_count(struct net_device *netdev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return IGB_STATS_LEN;
+	case ETH_SS_TEST:
+		return IGB_TEST_LEN;
+	default:
+		return -ENOTSUPP;
+	}
+}
+
+static void igb_get_ethtool_stats(struct net_device *netdev,
+				  struct ethtool_stats *stats, u64 *data)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	u64 *queue_stat;
+	int stat_count = sizeof(struct igb_queue_stats) / sizeof(u64);
+	int j;
+	int i;
+
+	igb_update_stats(adapter);
+	for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
+		char *p = (char *)adapter+igb_gstrings_stats[i].stat_offset;
+		data[i] = (igb_gstrings_stats[i].sizeof_stat ==
+			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+	}
+	for (j = 0; j < adapter->num_rx_queues; j++) {
+		int k;
+		queue_stat = (u64 *)&adapter->rx_ring[j].rx_stats;
+		for (k = 0; k < stat_count; k++)
+			data[i + k] = queue_stat[k];
+		i += k;
+	}
+}
+
+static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	u8 *p = data;
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_TEST:
+		memcpy(data, *igb_gstrings_test,
+			IGB_TEST_LEN*ETH_GSTRING_LEN);
+		break;
+	case ETH_SS_STATS:
+		for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) {
+			memcpy(p, igb_gstrings_stats[i].stat_string,
+			       ETH_GSTRING_LEN);
+			p += ETH_GSTRING_LEN;
+		}
+		for (i = 0; i < adapter->num_tx_queues; i++) {
+			sprintf(p, "tx_queue_%u_packets", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "tx_queue_%u_bytes", i);
+			p += ETH_GSTRING_LEN;
+		}
+		for (i = 0; i < adapter->num_rx_queues; i++) {
+			sprintf(p, "rx_queue_%u_packets", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "rx_queue_%u_bytes", i);
+			p += ETH_GSTRING_LEN;
+		}
+/*		BUG_ON(p - data != IGB_STATS_LEN * ETH_GSTRING_LEN); */
+		break;
+	}
+}
+
+static struct ethtool_ops igb_ethtool_ops = {
+	.get_settings           = igb_get_settings,
+	.set_settings           = igb_set_settings,
+	.get_drvinfo            = igb_get_drvinfo,
+	.get_regs_len           = igb_get_regs_len,
+	.get_regs               = igb_get_regs,
+	.get_wol                = igb_get_wol,
+	.set_wol                = igb_set_wol,
+	.get_msglevel           = igb_get_msglevel,
+	.set_msglevel           = igb_set_msglevel,
+	.nway_reset             = igb_nway_reset,
+	.get_link               = ethtool_op_get_link,
+	.get_eeprom_len         = igb_get_eeprom_len,
+	.get_eeprom             = igb_get_eeprom,
+	.set_eeprom             = igb_set_eeprom,
+	.get_ringparam          = igb_get_ringparam,
+	.set_ringparam          = igb_set_ringparam,
+	.get_pauseparam         = igb_get_pauseparam,
+	.set_pauseparam         = igb_set_pauseparam,
+	.get_rx_csum            = igb_get_rx_csum,
+	.set_rx_csum            = igb_set_rx_csum,
+	.get_tx_csum            = igb_get_tx_csum,
+	.set_tx_csum            = igb_set_tx_csum,
+	.get_sg                 = ethtool_op_get_sg,
+	.set_sg                 = ethtool_op_set_sg,
+	.get_tso                = ethtool_op_get_tso,
+	.set_tso                = igb_set_tso,
+	.self_test              = igb_diag_test,
+	.get_strings            = igb_get_strings,
+	.phys_id                = igb_phys_id,
+	.get_sset_count         = igb_get_sset_count,
+	.get_ethtool_stats      = igb_get_ethtool_stats,
+	.get_coalesce           = igb_get_coalesce,
+	.set_coalesce           = igb_set_coalesce,
+};
+
+void igb_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &igb_ethtool_ops);
+}
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
new file mode 100644
index 000000000000..f3c144d5d72f
--- /dev/null
+++ b/drivers/net/igb/igb_main.c
@@ -0,0 +1,4138 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/netdevice.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+
+#include "igb.h"
+
+#define DRV_VERSION "1.0.8-k2"
+char igb_driver_name[] = "igb";
+char igb_driver_version[] = DRV_VERSION;
+static const char igb_driver_string[] =
+				"Intel(R) Gigabit Ethernet Network Driver";
+static const char igb_copyright[] = "Copyright (c) 2007 Intel Corporation.";
+
+
+static const struct e1000_info *igb_info_tbl[] = {
+	[board_82575] = &e1000_82575_info,
+};
+
+static struct pci_device_id igb_pci_tbl[] = {
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 },
+	/* required last entry */
+	{0, }
+};
+
+MODULE_DEVICE_TABLE(pci, igb_pci_tbl);
+
+void igb_reset(struct igb_adapter *);
+static int igb_setup_all_tx_resources(struct igb_adapter *);
+static int igb_setup_all_rx_resources(struct igb_adapter *);
+static void igb_free_all_tx_resources(struct igb_adapter *);
+static void igb_free_all_rx_resources(struct igb_adapter *);
+static void igb_free_tx_resources(struct igb_adapter *, struct igb_ring *);
+static void igb_free_rx_resources(struct igb_adapter *, struct igb_ring *);
+void igb_update_stats(struct igb_adapter *);
+static int igb_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit igb_remove(struct pci_dev *pdev);
+static int igb_sw_init(struct igb_adapter *);
+static int igb_open(struct net_device *);
+static int igb_close(struct net_device *);
+static void igb_configure_tx(struct igb_adapter *);
+static void igb_configure_rx(struct igb_adapter *);
+static void igb_setup_rctl(struct igb_adapter *);
+static void igb_clean_all_tx_rings(struct igb_adapter *);
+static void igb_clean_all_rx_rings(struct igb_adapter *);
+static void igb_clean_tx_ring(struct igb_adapter *, struct igb_ring *);
+static void igb_clean_rx_ring(struct igb_adapter *, struct igb_ring *);
+static void igb_set_multi(struct net_device *);
+static void igb_update_phy_info(unsigned long);
+static void igb_watchdog(unsigned long);
+static void igb_watchdog_task(struct work_struct *);
+static int igb_xmit_frame_ring_adv(struct sk_buff *, struct net_device *,
+				  struct igb_ring *);
+static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *);
+static struct net_device_stats *igb_get_stats(struct net_device *);
+static int igb_change_mtu(struct net_device *, int);
+static int igb_set_mac(struct net_device *, void *);
+static irqreturn_t igb_intr(int irq, void *);
+static irqreturn_t igb_intr_msi(int irq, void *);
+static irqreturn_t igb_msix_other(int irq, void *);
+static irqreturn_t igb_msix_rx(int irq, void *);
+static irqreturn_t igb_msix_tx(int irq, void *);
+static int igb_clean_rx_ring_msix(struct napi_struct *, int);
+static bool igb_clean_tx_irq(struct igb_adapter *, struct igb_ring *);
+static int igb_clean(struct napi_struct *, int);
+static bool igb_clean_rx_irq_adv(struct igb_adapter *,
+				 struct igb_ring *, int *, int);
+static void igb_alloc_rx_buffers_adv(struct igb_adapter *,
+				     struct igb_ring *, int);
+static int igb_ioctl(struct net_device *, struct ifreq *, int cmd);
+static void igb_tx_timeout(struct net_device *);
+static void igb_reset_task(struct work_struct *);
+static void igb_vlan_rx_register(struct net_device *, struct vlan_group *);
+static void igb_vlan_rx_add_vid(struct net_device *, u16);
+static void igb_vlan_rx_kill_vid(struct net_device *, u16);
+static void igb_restore_vlan(struct igb_adapter *);
+
+static int igb_suspend(struct pci_dev *, pm_message_t);
+#ifdef CONFIG_PM
+static int igb_resume(struct pci_dev *);
+#endif
+static void igb_shutdown(struct pci_dev *);
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/* for netdump / net console */
+static void igb_netpoll(struct net_device *);
+#endif
+
+static pci_ers_result_t igb_io_error_detected(struct pci_dev *,
+		     pci_channel_state_t);
+static pci_ers_result_t igb_io_slot_reset(struct pci_dev *);
+static void igb_io_resume(struct pci_dev *);
+
+static struct pci_error_handlers igb_err_handler = {
+	.error_detected = igb_io_error_detected,
+	.slot_reset = igb_io_slot_reset,
+	.resume = igb_io_resume,
+};
+
+
+static struct pci_driver igb_driver = {
+	.name     = igb_driver_name,
+	.id_table = igb_pci_tbl,
+	.probe    = igb_probe,
+	.remove   = __devexit_p(igb_remove),
+#ifdef CONFIG_PM
+	/* Power Managment Hooks */
+	.suspend  = igb_suspend,
+	.resume   = igb_resume,
+#endif
+	.shutdown = igb_shutdown,
+	.err_handler = &igb_err_handler
+};
+
+MODULE_AUTHOR("Intel Corporation, <e1000-devel@lists.sourceforge.net>");
+MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+#ifdef DEBUG
+/**
+ * igb_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *igb_get_hw_dev_name(struct e1000_hw *hw)
+{
+	struct igb_adapter *adapter = hw->back;
+	return adapter->netdev->name;
+}
+#endif
+
+/**
+ * igb_init_module - Driver Registration Routine
+ *
+ * igb_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init igb_init_module(void)
+{
+	int ret;
+	printk(KERN_INFO "%s - version %s\n",
+	       igb_driver_string, igb_driver_version);
+
+	printk(KERN_INFO "%s\n", igb_copyright);
+
+	ret = pci_register_driver(&igb_driver);
+	return ret;
+}
+
+module_init(igb_init_module);
+
+/**
+ * igb_exit_module - Driver Exit Cleanup Routine
+ *
+ * igb_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit igb_exit_module(void)
+{
+	pci_unregister_driver(&igb_driver);
+}
+
+module_exit(igb_exit_module);
+
+/**
+ * igb_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one ring per queue at run-time since we don't know the
+ * number of queues at compile-time.
+ **/
+static int igb_alloc_queues(struct igb_adapter *adapter)
+{
+	int i;
+
+	adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+				   sizeof(struct igb_ring), GFP_KERNEL);
+	if (!adapter->tx_ring)
+		return -ENOMEM;
+
+	adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+				   sizeof(struct igb_ring), GFP_KERNEL);
+	if (!adapter->rx_ring) {
+		kfree(adapter->tx_ring);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct igb_ring *ring = &(adapter->rx_ring[i]);
+		ring->adapter = adapter;
+		ring->itr_register = E1000_ITR;
+
+		if (!ring->napi.poll)
+			netif_napi_add(adapter->netdev, &ring->napi, igb_clean,
+				       adapter->napi.weight /
+				       adapter->num_rx_queues);
+	}
+	return 0;
+}
+
+#define IGB_N0_QUEUE -1
+static void igb_assign_vector(struct igb_adapter *adapter, int rx_queue,
+			      int tx_queue, int msix_vector)
+{
+	u32 msixbm = 0;
+	struct e1000_hw *hw = &adapter->hw;
+		/* The 82575 assigns vectors using a bitmask, which matches the
+		   bitmask for the EICR/EIMS/EIMC registers.  To assign one
+		   or more queues to a vector, we write the appropriate bits
+		   into the MSIXBM register for that vector. */
+		if (rx_queue > IGB_N0_QUEUE) {
+			msixbm = E1000_EICR_RX_QUEUE0 << rx_queue;
+			adapter->rx_ring[rx_queue].eims_value = msixbm;
+		}
+		if (tx_queue > IGB_N0_QUEUE) {
+			msixbm |= E1000_EICR_TX_QUEUE0 << tx_queue;
+			adapter->tx_ring[tx_queue].eims_value =
+				  E1000_EICR_TX_QUEUE0 << tx_queue;
+		}
+		array_wr32(E1000_MSIXBM(0), msix_vector, msixbm);
+}
+
+/**
+ * igb_configure_msix - Configure MSI-X hardware
+ *
+ * igb_configure_msix sets up the hardware to properly
+ * generate MSI-X interrupts.
+ **/
+static void igb_configure_msix(struct igb_adapter *adapter)
+{
+	u32 tmp;
+	int i, vector = 0;
+	struct e1000_hw *hw = &adapter->hw;
+
+	adapter->eims_enable_mask = 0;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct igb_ring *tx_ring = &adapter->tx_ring[i];
+		igb_assign_vector(adapter, IGB_N0_QUEUE, i, vector++);
+		adapter->eims_enable_mask |= tx_ring->eims_value;
+		if (tx_ring->itr_val)
+			writel(1000000000 / (tx_ring->itr_val * 256),
+			       hw->hw_addr + tx_ring->itr_register);
+		else
+			writel(1, hw->hw_addr + tx_ring->itr_register);
+	}
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct igb_ring *rx_ring = &adapter->rx_ring[i];
+		igb_assign_vector(adapter, i, IGB_N0_QUEUE, vector++);
+		adapter->eims_enable_mask |= rx_ring->eims_value;
+		if (rx_ring->itr_val)
+			writel(1000000000 / (rx_ring->itr_val * 256),
+			       hw->hw_addr + rx_ring->itr_register);
+		else
+			writel(1, hw->hw_addr + rx_ring->itr_register);
+	}
+
+
+	/* set vector for other causes, i.e. link changes */
+		array_wr32(E1000_MSIXBM(0), vector++,
+				      E1000_EIMS_OTHER);
+
+		/* disable IAM for ICR interrupt bits */
+		wr32(E1000_IAM, 0);
+
+		tmp = rd32(E1000_CTRL_EXT);
+		/* enable MSI-X PBA support*/
+		tmp |= E1000_CTRL_EXT_PBA_CLR;
+
+		/* Auto-Mask interrupts upon ICR read. */
+		tmp |= E1000_CTRL_EXT_EIAME;
+		tmp |= E1000_CTRL_EXT_IRCA;
+
+		wr32(E1000_CTRL_EXT, tmp);
+		adapter->eims_enable_mask |= E1000_EIMS_OTHER;
+
+	wrfl();
+}
+
+/**
+ * igb_request_msix - Initialize MSI-X interrupts
+ *
+ * igb_request_msix allocates MSI-X vectors and requests interrupts from the
+ * kernel.
+ **/
+static int igb_request_msix(struct igb_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int i, err = 0, vector = 0;
+
+	vector = 0;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct igb_ring *ring = &(adapter->tx_ring[i]);
+		sprintf(ring->name, "%s-tx%d", netdev->name, i);
+		err = request_irq(adapter->msix_entries[vector].vector,
+				  &igb_msix_tx, 0, ring->name,
+				  &(adapter->tx_ring[i]));
+		if (err)
+			goto out;
+		ring->itr_register = E1000_EITR(0) + (vector << 2);
+		ring->itr_val = adapter->itr;
+		vector++;
+	}
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct igb_ring *ring = &(adapter->rx_ring[i]);
+		if (strlen(netdev->name) < (IFNAMSIZ - 5))
+			sprintf(ring->name, "%s-rx%d", netdev->name, i);
+		else
+			memcpy(ring->name, netdev->name, IFNAMSIZ);
+		err = request_irq(adapter->msix_entries[vector].vector,
+				  &igb_msix_rx, 0, ring->name,
+				  &(adapter->rx_ring[i]));
+		if (err)
+			goto out;
+		ring->itr_register = E1000_EITR(0) + (vector << 2);
+		ring->itr_val = adapter->itr;
+		vector++;
+	}
+
+	err = request_irq(adapter->msix_entries[vector].vector,
+			  &igb_msix_other, 0, netdev->name, netdev);
+	if (err)
+		goto out;
+
+	adapter->napi.poll = igb_clean_rx_ring_msix;
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		adapter->rx_ring[i].napi.poll = adapter->napi.poll;
+	igb_configure_msix(adapter);
+	return 0;
+out:
+	return err;
+}
+
+static void igb_reset_interrupt_capability(struct igb_adapter *adapter)
+{
+	if (adapter->msix_entries) {
+		pci_disable_msix(adapter->pdev);
+		kfree(adapter->msix_entries);
+		adapter->msix_entries = NULL;
+	} else if (adapter->msi_enabled)
+		pci_disable_msi(adapter->pdev);
+	return;
+}
+
+
+/**
+ * igb_set_interrupt_capability - set MSI or MSI-X if supported
+ *
+ * Attempt to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+static void igb_set_interrupt_capability(struct igb_adapter *adapter)
+{
+	int err;
+	int numvecs, i;
+
+	numvecs = adapter->num_tx_queues + adapter->num_rx_queues + 1;
+	adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry),
+					GFP_KERNEL);
+	if (!adapter->msix_entries)
+		goto msi_only;
+
+	for (i = 0; i < numvecs; i++)
+		adapter->msix_entries[i].entry = i;
+
+	err = pci_enable_msix(adapter->pdev,
+			      adapter->msix_entries,
+			      numvecs);
+	if (err == 0)
+		return;
+
+	igb_reset_interrupt_capability(adapter);
+
+	/* If we can't do MSI-X, try MSI */
+msi_only:
+	adapter->num_rx_queues = 1;
+	if (!pci_enable_msi(adapter->pdev))
+		adapter->msi_enabled = 1;
+	return;
+}
+
+/**
+ * igb_request_irq - initialize interrupts
+ *
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+static int igb_request_irq(struct igb_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	int err = 0;
+
+	if (adapter->msix_entries) {
+		err = igb_request_msix(adapter);
+		if (!err) {
+			struct e1000_hw *hw = &adapter->hw;
+			/* enable IAM, auto-mask,
+			 * DO NOT USE EIAME or IAME in legacy mode */
+			wr32(E1000_IAM, IMS_ENABLE_MASK);
+			goto request_done;
+		}
+		/* fall back to MSI */
+		igb_reset_interrupt_capability(adapter);
+		if (!pci_enable_msi(adapter->pdev))
+			adapter->msi_enabled = 1;
+		igb_free_all_tx_resources(adapter);
+		igb_free_all_rx_resources(adapter);
+		adapter->num_rx_queues = 1;
+		igb_alloc_queues(adapter);
+	}
+	if (adapter->msi_enabled) {
+		err = request_irq(adapter->pdev->irq, &igb_intr_msi, 0,
+				  netdev->name, netdev);
+		if (!err)
+			goto request_done;
+		/* fall back to legacy interrupts */
+		igb_reset_interrupt_capability(adapter);
+		adapter->msi_enabled = 0;
+	}
+
+	err = request_irq(adapter->pdev->irq, &igb_intr, IRQF_SHARED,
+			  netdev->name, netdev);
+
+	if (err) {
+		dev_err(&adapter->pdev->dev, "Error %d getting interrupt\n",
+			err);
+		goto request_done;
+	}
+
+	/* enable IAM, auto-mask */
+	wr32(E1000_IAM, IMS_ENABLE_MASK);
+
+request_done:
+	return err;
+}
+
+static void igb_free_irq(struct igb_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	if (adapter->msix_entries) {
+		int vector = 0, i;
+
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			free_irq(adapter->msix_entries[vector++].vector,
+				&(adapter->tx_ring[i]));
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			free_irq(adapter->msix_entries[vector++].vector,
+				&(adapter->rx_ring[i]));
+
+		free_irq(adapter->msix_entries[vector++].vector, netdev);
+		return;
+	}
+
+	free_irq(adapter->pdev->irq, netdev);
+}
+
+/**
+ * igb_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static void igb_irq_disable(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (adapter->msix_entries) {
+		wr32(E1000_EIMC, ~0);
+		wr32(E1000_EIAC, 0);
+	}
+	wr32(E1000_IMC, ~0);
+	wrfl();
+	synchronize_irq(adapter->pdev->irq);
+}
+
+/**
+ * igb_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+static void igb_irq_enable(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (adapter->msix_entries) {
+		wr32(E1000_EIMS,
+				adapter->eims_enable_mask);
+		wr32(E1000_EIAC,
+				adapter->eims_enable_mask);
+		wr32(E1000_IMS, E1000_IMS_LSC);
+	} else
+	wr32(E1000_IMS, IMS_ENABLE_MASK);
+}
+
+static void igb_update_mng_vlan(struct igb_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	u16 vid = adapter->hw.mng_cookie.vlan_id;
+	u16 old_vid = adapter->mng_vlan_id;
+	if (adapter->vlgrp) {
+		if (!vlan_group_get_device(adapter->vlgrp, vid)) {
+			if (adapter->hw.mng_cookie.status &
+				E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
+				igb_vlan_rx_add_vid(netdev, vid);
+				adapter->mng_vlan_id = vid;
+			} else
+				adapter->mng_vlan_id = IGB_MNG_VLAN_NONE;
+
+			if ((old_vid != (u16)IGB_MNG_VLAN_NONE) &&
+					(vid != old_vid) &&
+			    !vlan_group_get_device(adapter->vlgrp, old_vid))
+				igb_vlan_rx_kill_vid(netdev, old_vid);
+		} else
+			adapter->mng_vlan_id = vid;
+	}
+}
+
+/**
+ * igb_release_hw_control - release control of the h/w to f/w
+ * @adapter: address of board private structure
+ *
+ * igb_release_hw_control resets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that the
+ * driver is no longer loaded.
+ *
+ **/
+static void igb_release_hw_control(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_ext;
+
+	/* Let firmware take over control of h/w */
+	ctrl_ext = rd32(E1000_CTRL_EXT);
+	wr32(E1000_CTRL_EXT,
+			ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+}
+
+
+/**
+ * igb_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded.
+ *
+ **/
+static void igb_get_hw_control(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_ext;
+
+	/* Let firmware know the driver has taken over */
+	ctrl_ext = rd32(E1000_CTRL_EXT);
+	wr32(E1000_CTRL_EXT,
+			ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+}
+
+static void igb_init_manageability(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (adapter->en_mng_pt) {
+		u32 manc2h = rd32(E1000_MANC2H);
+		u32 manc = rd32(E1000_MANC);
+
+		/* disable hardware interception of ARP */
+		manc &= ~(E1000_MANC_ARP_EN);
+
+		/* enable receiving management packets to the host */
+		/* this will probably generate destination unreachable messages
+		 * from the host OS, but the packets will be handled on SMBUS */
+		manc |= E1000_MANC_EN_MNG2HOST;
+#define E1000_MNG2HOST_PORT_623 (1 << 5)
+#define E1000_MNG2HOST_PORT_664 (1 << 6)
+		manc2h |= E1000_MNG2HOST_PORT_623;
+		manc2h |= E1000_MNG2HOST_PORT_664;
+		wr32(E1000_MANC2H, manc2h);
+
+		wr32(E1000_MANC, manc);
+	}
+}
+
+static void igb_release_manageability(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (adapter->en_mng_pt) {
+		u32 manc = rd32(E1000_MANC);
+
+		/* re-enable hardware interception of ARP */
+		manc |= E1000_MANC_ARP_EN;
+		manc &= ~E1000_MANC_EN_MNG2HOST;
+
+		/* don't explicitly have to mess with MANC2H since
+		 * MANC has an enable disable that gates MANC2H */
+
+		/* XXX stop the hardware watchdog ? */
+		wr32(E1000_MANC, manc);
+	}
+}
+
+/**
+ * igb_configure - configure the hardware for RX and TX
+ * @adapter: private board structure
+ **/
+static void igb_configure(struct igb_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int i;
+
+	igb_get_hw_control(adapter);
+	igb_set_multi(netdev);
+
+	igb_restore_vlan(adapter);
+	igb_init_manageability(adapter);
+
+	igb_configure_tx(adapter);
+	igb_setup_rctl(adapter);
+	igb_configure_rx(adapter);
+	/* call IGB_DESC_UNUSED which always leaves
+	 * at least 1 descriptor unused to make sure
+	 * next_to_use != next_to_clean */
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct igb_ring *ring = &adapter->rx_ring[i];
+		igb_alloc_rx_buffers_adv(adapter, ring, IGB_DESC_UNUSED(ring));
+	}
+
+
+	adapter->tx_queue_len = netdev->tx_queue_len;
+}
+
+
+/**
+ * igb_up - Open the interface and prepare it to handle traffic
+ * @adapter: board private structure
+ **/
+
+int igb_up(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	int i;
+
+	/* hardware has been reset, we need to reload some things */
+	igb_configure(adapter);
+
+	clear_bit(__IGB_DOWN, &adapter->state);
+
+	napi_enable(&adapter->napi);
+
+	if (adapter->msix_entries) {
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			napi_enable(&adapter->rx_ring[i].napi);
+		igb_configure_msix(adapter);
+	}
+
+	/* Clear any pending interrupts. */
+	rd32(E1000_ICR);
+	igb_irq_enable(adapter);
+
+	/* Fire a link change interrupt to start the watchdog. */
+	wr32(E1000_ICS, E1000_ICS_LSC);
+	return 0;
+}
+
+void igb_down(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	u32 tctl, rctl;
+	int i;
+
+	/* signal that we're down so the interrupt handler does not
+	 * reschedule our watchdog timer */
+	set_bit(__IGB_DOWN, &adapter->state);
+
+	/* disable receives in the hardware */
+	rctl = rd32(E1000_RCTL);
+	wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
+	/* flush and sleep below */
+
+	netif_stop_queue(netdev);
+
+	/* disable transmits in the hardware */
+	tctl = rd32(E1000_TCTL);
+	tctl &= ~E1000_TCTL_EN;
+	wr32(E1000_TCTL, tctl);
+	/* flush both disables and wait for them to finish */
+	wrfl();
+	msleep(10);
+
+	napi_disable(&adapter->napi);
+
+	if (adapter->msix_entries)
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			napi_disable(&adapter->rx_ring[i].napi);
+	igb_irq_disable(adapter);
+
+	del_timer_sync(&adapter->watchdog_timer);
+	del_timer_sync(&adapter->phy_info_timer);
+
+	netdev->tx_queue_len = adapter->tx_queue_len;
+	netif_carrier_off(netdev);
+	adapter->link_speed = 0;
+	adapter->link_duplex = 0;
+
+	igb_reset(adapter);
+	igb_clean_all_tx_rings(adapter);
+	igb_clean_all_rx_rings(adapter);
+}
+
+void igb_reinit_locked(struct igb_adapter *adapter)
+{
+	WARN_ON(in_interrupt());
+	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+		msleep(1);
+	igb_down(adapter);
+	igb_up(adapter);
+	clear_bit(__IGB_RESETTING, &adapter->state);
+}
+
+void igb_reset(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_fc_info *fc = &adapter->hw.fc;
+	u32 pba = 0, tx_space, min_tx_space, min_rx_space;
+	u16 hwm;
+
+	/* Repartition Pba for greater than 9k mtu
+	 * To take effect CTRL.RST is required.
+	 */
+	pba = E1000_PBA_34K;
+
+	if (adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) {
+		/* adjust PBA for jumbo frames */
+		wr32(E1000_PBA, pba);
+
+		/* To maintain wire speed transmits, the Tx FIFO should be
+		 * large enough to accommodate two full transmit packets,
+		 * rounded up to the next 1KB and expressed in KB.  Likewise,
+		 * the Rx FIFO should be large enough to accommodate at least
+		 * one full receive packet and is similarly rounded up and
+		 * expressed in KB. */
+		pba = rd32(E1000_PBA);
+		/* upper 16 bits has Tx packet buffer allocation size in KB */
+		tx_space = pba >> 16;
+		/* lower 16 bits has Rx packet buffer allocation size in KB */
+		pba &= 0xffff;
+		/* the tx fifo also stores 16 bytes of information about the tx
+		 * but don't include ethernet FCS because hardware appends it */
+		min_tx_space = (adapter->max_frame_size +
+				sizeof(struct e1000_tx_desc) -
+				ETH_FCS_LEN) * 2;
+		min_tx_space = ALIGN(min_tx_space, 1024);
+		min_tx_space >>= 10;
+		/* software strips receive CRC, so leave room for it */
+		min_rx_space = adapter->max_frame_size;
+		min_rx_space = ALIGN(min_rx_space, 1024);
+		min_rx_space >>= 10;
+
+		/* If current Tx allocation is less than the min Tx FIFO size,
+		 * and the min Tx FIFO size is less than the current Rx FIFO
+		 * allocation, take space away from current Rx allocation */
+		if (tx_space < min_tx_space &&
+		    ((min_tx_space - tx_space) < pba)) {
+			pba = pba - (min_tx_space - tx_space);
+
+			/* if short on rx space, rx wins and must trump tx
+			 * adjustment */
+			if (pba < min_rx_space)
+				pba = min_rx_space;
+		}
+	}
+	wr32(E1000_PBA, pba);
+
+	/* flow control settings */
+	/* The high water mark must be low enough to fit one full frame
+	 * (or the size used for early receive) above it in the Rx FIFO.
+	 * Set it to the lower of:
+	 * - 90% of the Rx FIFO size, or
+	 * - the full Rx FIFO size minus one full frame */
+	hwm = min(((pba << 10) * 9 / 10),
+		  ((pba << 10) - adapter->max_frame_size));
+
+	fc->high_water = hwm & 0xFFF8;	/* 8-byte granularity */
+	fc->low_water = fc->high_water - 8;
+	fc->pause_time = 0xFFFF;
+	fc->send_xon = 1;
+	fc->type = fc->original_type;
+
+	/* Allow time for pending master requests to run */
+	adapter->hw.mac.ops.reset_hw(&adapter->hw);
+	wr32(E1000_WUC, 0);
+
+	if (adapter->hw.mac.ops.init_hw(&adapter->hw))
+		dev_err(&adapter->pdev->dev, "Hardware Error\n");
+
+	igb_update_mng_vlan(adapter);
+
+	/* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
+	wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE);
+
+	igb_reset_adaptive(&adapter->hw);
+	adapter->hw.phy.ops.get_phy_info(&adapter->hw);
+	igb_release_manageability(adapter);
+}
+
+/**
+ * igb_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in igb_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * igb_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit igb_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *ent)
+{
+	struct net_device *netdev;
+	struct igb_adapter *adapter;
+	struct e1000_hw *hw;
+	const struct e1000_info *ei = igb_info_tbl[ent->driver_data];
+	unsigned long mmio_start, mmio_len;
+	static int cards_found;
+	int i, err, pci_using_dac;
+	u16 eeprom_data = 0;
+	u16 eeprom_apme_mask = IGB_EEPROM_APME;
+	u32 part_num;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	pci_using_dac = 0;
+	err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+	if (!err) {
+		err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+		if (!err)
+			pci_using_dac = 1;
+	} else {
+		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (err) {
+			err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+			if (err) {
+				dev_err(&pdev->dev, "No usable DMA "
+					"configuration, aborting\n");
+				goto err_dma;
+			}
+		}
+	}
+
+	err = pci_request_regions(pdev, igb_driver_name);
+	if (err)
+		goto err_pci_reg;
+
+	pci_set_master(pdev);
+
+	err = -ENOMEM;
+	netdev = alloc_etherdev(sizeof(struct igb_adapter));
+	if (!netdev)
+		goto err_alloc_etherdev;
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	pci_set_drvdata(pdev, netdev);
+	adapter = netdev_priv(netdev);
+	adapter->netdev = netdev;
+	adapter->pdev = pdev;
+	hw = &adapter->hw;
+	hw->back = adapter;
+	adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE;
+
+	mmio_start = pci_resource_start(pdev, 0);
+	mmio_len = pci_resource_len(pdev, 0);
+
+	err = -EIO;
+	adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+	if (!adapter->hw.hw_addr)
+		goto err_ioremap;
+
+	netdev->open = &igb_open;
+	netdev->stop = &igb_close;
+	netdev->get_stats = &igb_get_stats;
+	netdev->set_multicast_list = &igb_set_multi;
+	netdev->set_mac_address = &igb_set_mac;
+	netdev->change_mtu = &igb_change_mtu;
+	netdev->do_ioctl = &igb_ioctl;
+	igb_set_ethtool_ops(netdev);
+	netdev->tx_timeout = &igb_tx_timeout;
+	netdev->watchdog_timeo = 5 * HZ;
+	netif_napi_add(netdev, &adapter->napi, igb_clean, 64);
+	netdev->vlan_rx_register = igb_vlan_rx_register;
+	netdev->vlan_rx_add_vid = igb_vlan_rx_add_vid;
+	netdev->vlan_rx_kill_vid = igb_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = igb_netpoll;
+#endif
+	netdev->hard_start_xmit = &igb_xmit_frame_adv;
+
+	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+
+	netdev->mem_start = mmio_start;
+	netdev->mem_end = mmio_start + mmio_len;
+
+	adapter->bd_number = cards_found;
+
+	/* PCI config space info */
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+	hw->revision_id = pdev->revision;
+	hw->subsystem_vendor_id = pdev->subsystem_vendor;
+	hw->subsystem_device_id = pdev->subsystem_device;
+
+	/* setup the private structure */
+	hw->back = adapter;
+	/* Copy the default MAC, PHY and NVM function pointers */
+	memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));
+	memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops));
+	memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops));
+	/* Initialize skew-specific constants */
+	err = ei->get_invariants(hw);
+	if (err)
+		goto err_hw_init;
+
+	err = igb_sw_init(adapter);
+	if (err)
+		goto err_sw_init;
+
+	igb_get_bus_info_pcie(hw);
+
+	hw->phy.autoneg_wait_to_complete = false;
+	hw->mac.adaptive_ifs = true;
+
+	/* Copper options */
+	if (hw->phy.media_type == e1000_media_type_copper) {
+		hw->phy.mdix = AUTO_ALL_MODES;
+		hw->phy.disable_polarity_correction = false;
+		hw->phy.ms_type = e1000_ms_hw_default;
+	}
+
+	if (igb_check_reset_block(hw))
+		dev_info(&pdev->dev,
+			"PHY reset is blocked due to SOL/IDER session.\n");
+
+	netdev->features = NETIF_F_SG |
+			   NETIF_F_HW_CSUM |
+			   NETIF_F_HW_VLAN_TX |
+			   NETIF_F_HW_VLAN_RX |
+			   NETIF_F_HW_VLAN_FILTER;
+
+	netdev->features |= NETIF_F_TSO;
+
+	netdev->features |= NETIF_F_TSO6;
+	if (pci_using_dac)
+		netdev->features |= NETIF_F_HIGHDMA;
+
+	netdev->features |= NETIF_F_LLTX;
+	adapter->en_mng_pt = igb_enable_mng_pass_thru(&adapter->hw);
+
+	/* before reading the NVM, reset the controller to put the device in a
+	 * known good starting state */
+	hw->mac.ops.reset_hw(hw);
+
+	/* make sure the NVM is good */
+	if (igb_validate_nvm_checksum(hw) < 0) {
+		dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n");
+		err = -EIO;
+		goto err_eeprom;
+	}
+
+	/* copy the MAC address out of the NVM */
+	if (hw->mac.ops.read_mac_addr(hw))
+		dev_err(&pdev->dev, "NVM Read Error\n");
+
+	memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
+	memcpy(netdev->perm_addr, hw->mac.addr, netdev->addr_len);
+
+	if (!is_valid_ether_addr(netdev->perm_addr)) {
+		dev_err(&pdev->dev, "Invalid MAC Address\n");
+		err = -EIO;
+		goto err_eeprom;
+	}
+
+	init_timer(&adapter->watchdog_timer);
+	adapter->watchdog_timer.function = &igb_watchdog;
+	adapter->watchdog_timer.data = (unsigned long) adapter;
+
+	init_timer(&adapter->phy_info_timer);
+	adapter->phy_info_timer.function = &igb_update_phy_info;
+	adapter->phy_info_timer.data = (unsigned long) adapter;
+
+	INIT_WORK(&adapter->reset_task, igb_reset_task);
+	INIT_WORK(&adapter->watchdog_task, igb_watchdog_task);
+
+	/* Initialize link & ring properties that are user-changeable */
+	adapter->tx_ring->count = 256;
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		adapter->tx_ring[i].count = adapter->tx_ring->count;
+	adapter->rx_ring->count = 256;
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		adapter->rx_ring[i].count = adapter->rx_ring->count;
+
+	adapter->fc_autoneg = true;
+	hw->mac.autoneg = true;
+	hw->phy.autoneg_advertised = 0x2f;
+
+	hw->fc.original_type = e1000_fc_default;
+	hw->fc.type = e1000_fc_default;
+
+	adapter->itr_setting = 3;
+	adapter->itr = IGB_START_ITR;
+
+	igb_validate_mdi_setting(hw);
+
+	adapter->rx_csum = 1;
+
+	/* Initial Wake on LAN setting If APM wake is enabled in the EEPROM,
+	 * enable the ACPI Magic Packet filter
+	 */
+
+	if (hw->bus.func == 0 ||
+	    hw->device_id == E1000_DEV_ID_82575EB_COPPER)
+		hw->nvm.ops.read_nvm(hw, NVM_INIT_CONTROL3_PORT_A, 1,
+				     &eeprom_data);
+
+	if (eeprom_data & eeprom_apme_mask)
+		adapter->eeprom_wol |= E1000_WUFC_MAG;
+
+	/* now that we have the eeprom settings, apply the special cases where
+	 * the eeprom may be wrong or the board simply won't support wake on
+	 * lan on a particular port */
+	switch (pdev->device) {
+	case E1000_DEV_ID_82575GB_QUAD_COPPER:
+		adapter->eeprom_wol = 0;
+		break;
+	case E1000_DEV_ID_82575EB_FIBER_SERDES:
+		/* Wake events only supported on port A for dual fiber
+		 * regardless of eeprom setting */
+		if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1)
+			adapter->eeprom_wol = 0;
+		break;
+	}
+
+	/* initialize the wol settings based on the eeprom settings */
+	adapter->wol = adapter->eeprom_wol;
+
+	/* reset the hardware with the new settings */
+	igb_reset(adapter);
+
+	/* let the f/w know that the h/w is now under the control of the
+	 * driver. */
+	igb_get_hw_control(adapter);
+
+	/* tell the stack to leave us alone until igb_open() is called */
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	strcpy(netdev->name, "eth%d");
+	err = register_netdev(netdev);
+	if (err)
+		goto err_register;
+
+	dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");
+	/* print bus type/speed/width info */
+	dev_info(&pdev->dev,
+		 "%s: (PCIe:%s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n",
+		 netdev->name,
+		 ((hw->bus.speed == e1000_bus_speed_2500)
+		  ? "2.5Gb/s" : "unknown"),
+		 ((hw->bus.width == e1000_bus_width_pcie_x4)
+		  ? "Width x4" : (hw->bus.width == e1000_bus_width_pcie_x1)
+		  ? "Width x1" : "unknown"),
+		 netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+		 netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+
+	igb_read_part_num(hw, &part_num);
+	dev_info(&pdev->dev, "%s: PBA No: %06x-%03x\n", netdev->name,
+		(part_num >> 8), (part_num & 0xff));
+
+	dev_info(&pdev->dev,
+		"Using %s interrupts. %d rx queue(s), %d tx queue(s)\n",
+		adapter->msix_entries ? "MSI-X" :
+		adapter->msi_enabled ? "MSI" : "legacy",
+		adapter->num_rx_queues, adapter->num_tx_queues);
+
+	cards_found++;
+	return 0;
+
+err_register:
+	igb_release_hw_control(adapter);
+err_eeprom:
+	if (!igb_check_reset_block(hw))
+		hw->phy.ops.reset_phy(hw);
+
+	if (hw->flash_address)
+		iounmap(hw->flash_address);
+
+	igb_remove_device(hw);
+	kfree(adapter->tx_ring);
+	kfree(adapter->rx_ring);
+err_sw_init:
+err_hw_init:
+	iounmap(hw->hw_addr);
+err_ioremap:
+	free_netdev(netdev);
+err_alloc_etherdev:
+	pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+	pci_disable_device(pdev);
+	return err;
+}
+
+/**
+ * igb_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * igb_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit igb_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	/* flush_scheduled work may reschedule our watchdog task, so
+	 * explicitly disable watchdog tasks from being rescheduled  */
+	set_bit(__IGB_DOWN, &adapter->state);
+	del_timer_sync(&adapter->watchdog_timer);
+	del_timer_sync(&adapter->phy_info_timer);
+
+	flush_scheduled_work();
+
+
+	igb_release_manageability(adapter);
+
+	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
+	 * would have already happened in close and is redundant. */
+	igb_release_hw_control(adapter);
+
+	unregister_netdev(netdev);
+
+	if (!igb_check_reset_block(&adapter->hw))
+		adapter->hw.phy.ops.reset_phy(&adapter->hw);
+
+	igb_remove_device(&adapter->hw);
+	igb_reset_interrupt_capability(adapter);
+
+	kfree(adapter->tx_ring);
+	kfree(adapter->rx_ring);
+
+	iounmap(adapter->hw.hw_addr);
+	if (adapter->hw.flash_address)
+		iounmap(adapter->hw.flash_address);
+	pci_release_regions(pdev);
+
+	free_netdev(netdev);
+
+	pci_disable_device(pdev);
+}
+
+/**
+ * igb_sw_init - Initialize general software structures (struct igb_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * igb_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit igb_sw_init(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+
+	adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+	adapter->rx_ps_hdr_size = 0; /* disable packet split */
+	adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+	/* Number of supported queues. */
+	/* Having more queues than CPUs doesn't make sense. */
+	adapter->num_tx_queues = 1;
+	adapter->num_rx_queues = min(IGB_MAX_RX_QUEUES, num_online_cpus());
+
+	igb_set_interrupt_capability(adapter);
+
+	if (igb_alloc_queues(adapter)) {
+		dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+		return -ENOMEM;
+	}
+
+	/* Explicitly disable IRQ since the NIC can be in any state. */
+	igb_irq_disable(adapter);
+
+	set_bit(__IGB_DOWN, &adapter->state);
+	return 0;
+}
+
+/**
+ * igb_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int igb_open(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	int err;
+	int i;
+
+	/* disallow open during test */
+	if (test_bit(__IGB_TESTING, &adapter->state))
+		return -EBUSY;
+
+	/* allocate transmit descriptors */
+	err = igb_setup_all_tx_resources(adapter);
+	if (err)
+		goto err_setup_tx;
+
+	/* allocate receive descriptors */
+	err = igb_setup_all_rx_resources(adapter);
+	if (err)
+		goto err_setup_rx;
+
+	/* e1000_power_up_phy(adapter); */
+
+	adapter->mng_vlan_id = IGB_MNG_VLAN_NONE;
+	if ((adapter->hw.mng_cookie.status &
+	     E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
+		igb_update_mng_vlan(adapter);
+
+	/* before we allocate an interrupt, we must be ready to handle it.
+	 * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
+	 * as soon as we call pci_request_irq, so we have to setup our
+	 * clean_rx handler before we do so.  */
+	igb_configure(adapter);
+
+	err = igb_request_irq(adapter);
+	if (err)
+		goto err_req_irq;
+
+	/* From here on the code is the same as igb_up() */
+	clear_bit(__IGB_DOWN, &adapter->state);
+
+	napi_enable(&adapter->napi);
+	if (adapter->msix_entries)
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			napi_enable(&adapter->rx_ring[i].napi);
+
+	igb_irq_enable(adapter);
+
+	/* Clear any pending interrupts. */
+	rd32(E1000_ICR);
+	/* Fire a link status change interrupt to start the watchdog. */
+	wr32(E1000_ICS, E1000_ICS_LSC);
+
+	return 0;
+
+err_req_irq:
+	igb_release_hw_control(adapter);
+	/* e1000_power_down_phy(adapter); */
+	igb_free_all_rx_resources(adapter);
+err_setup_rx:
+	igb_free_all_tx_resources(adapter);
+err_setup_tx:
+	igb_reset(adapter);
+
+	return err;
+}
+
+/**
+ * igb_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the driver's control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int igb_close(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	WARN_ON(test_bit(__IGB_RESETTING, &adapter->state));
+	igb_down(adapter);
+
+	igb_free_irq(adapter);
+
+	igb_free_all_tx_resources(adapter);
+	igb_free_all_rx_resources(adapter);
+
+	/* kill manageability vlan ID if supported, but not if a vlan with
+	 * the same ID is registered on the host OS (let 8021q kill it) */
+	if ((adapter->hw.mng_cookie.status &
+			  E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+	     !(adapter->vlgrp &&
+	       vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id)))
+		igb_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+
+	return 0;
+}
+
+/**
+ * igb_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ * @tx_ring: tx descriptor ring (for a specific queue) to setup
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+int igb_setup_tx_resources(struct igb_adapter *adapter,
+			   struct igb_ring *tx_ring)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	int size;
+
+	size = sizeof(struct igb_buffer) * tx_ring->count;
+	tx_ring->buffer_info = vmalloc(size);
+	if (!tx_ring->buffer_info)
+		goto err;
+	memset(tx_ring->buffer_info, 0, size);
+
+	/* round up to nearest 4K */
+	tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc)
+			+ sizeof(u32);
+	tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+	tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
+					     &tx_ring->dma);
+
+	if (!tx_ring->desc)
+		goto err;
+
+	tx_ring->adapter = adapter;
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+	spin_lock_init(&tx_ring->tx_clean_lock);
+	spin_lock_init(&tx_ring->tx_lock);
+	return 0;
+
+err:
+	vfree(tx_ring->buffer_info);
+	dev_err(&adapter->pdev->dev,
+		"Unable to allocate memory for the transmit descriptor ring\n");
+	return -ENOMEM;
+}
+
+/**
+ * igb_setup_all_tx_resources - wrapper to allocate Tx resources
+ *				  (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int igb_setup_all_tx_resources(struct igb_adapter *adapter)
+{
+	int i, err = 0;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		err = igb_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"Allocation for Tx Queue %u failed\n", i);
+			for (i--; i >= 0; i--)
+				igb_free_tx_resources(adapter,
+							&adapter->tx_ring[i]);
+			break;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * igb_configure_tx - Configure transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void igb_configure_tx(struct igb_adapter *adapter)
+{
+	u64 tdba, tdwba;
+	struct e1000_hw *hw = &adapter->hw;
+	u32 tctl;
+	u32 txdctl, txctrl;
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		struct igb_ring *ring = &(adapter->tx_ring[i]);
+
+		wr32(E1000_TDLEN(i),
+				ring->count * sizeof(struct e1000_tx_desc));
+		tdba = ring->dma;
+		wr32(E1000_TDBAL(i),
+				tdba & 0x00000000ffffffffULL);
+		wr32(E1000_TDBAH(i), tdba >> 32);
+
+		tdwba = ring->dma + ring->count * sizeof(struct e1000_tx_desc);
+		tdwba |= 1; /* enable head wb */
+		wr32(E1000_TDWBAL(i),
+				tdwba & 0x00000000ffffffffULL);
+		wr32(E1000_TDWBAH(i), tdwba >> 32);
+
+		ring->head = E1000_TDH(i);
+		ring->tail = E1000_TDT(i);
+		writel(0, hw->hw_addr + ring->tail);
+		writel(0, hw->hw_addr + ring->head);
+		txdctl = rd32(E1000_TXDCTL(i));
+		txdctl |= E1000_TXDCTL_QUEUE_ENABLE;
+		wr32(E1000_TXDCTL(i), txdctl);
+
+		/* Turn off Relaxed Ordering on head write-backs.  The
+		 * writebacks MUST be delivered in order or it will
+		 * completely screw up our bookeeping.
+		 */
+		txctrl = rd32(E1000_DCA_TXCTRL(i));
+		txctrl &= ~E1000_DCA_TXCTRL_TX_WB_RO_EN;
+		wr32(E1000_DCA_TXCTRL(i), txctrl);
+	}
+
+
+
+	/* Use the default values for the Tx Inter Packet Gap (IPG) timer */
+
+	/* Program the Transmit Control Register */
+
+	tctl = rd32(E1000_TCTL);
+	tctl &= ~E1000_TCTL_CT;
+	tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+	igb_config_collision_dist(hw);
+
+	/* Setup Transmit Descriptor Settings for eop descriptor */
+	adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS;
+
+	/* Enable transmits */
+	tctl |= E1000_TCTL_EN;
+
+	wr32(E1000_TCTL, tctl);
+}
+
+/**
+ * igb_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ * @rx_ring:    rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ **/
+
+int igb_setup_rx_resources(struct igb_adapter *adapter,
+			   struct igb_ring *rx_ring)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	int size, desc_len;
+
+	size = sizeof(struct igb_buffer) * rx_ring->count;
+	rx_ring->buffer_info = vmalloc(size);
+	if (!rx_ring->buffer_info)
+		goto err;
+	memset(rx_ring->buffer_info, 0, size);
+
+	desc_len = sizeof(union e1000_adv_rx_desc);
+
+	/* Round up to nearest 4K */
+	rx_ring->size = rx_ring->count * desc_len;
+	rx_ring->size = ALIGN(rx_ring->size, 4096);
+
+	rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
+					     &rx_ring->dma);
+
+	if (!rx_ring->desc)
+		goto err;
+
+	rx_ring->next_to_clean = 0;
+	rx_ring->next_to_use = 0;
+	rx_ring->pending_skb = NULL;
+
+	rx_ring->adapter = adapter;
+	/* FIXME: do we want to setup ring->napi->poll here? */
+	rx_ring->napi.poll = adapter->napi.poll;
+
+	return 0;
+
+err:
+	vfree(rx_ring->buffer_info);
+	dev_err(&adapter->pdev->dev, "Unable to allocate memory for "
+		"the receive descriptor ring\n");
+	return -ENOMEM;
+}
+
+/**
+ * igb_setup_all_rx_resources - wrapper to allocate Rx resources
+ *				  (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int igb_setup_all_rx_resources(struct igb_adapter *adapter)
+{
+	int i, err = 0;
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		err = igb_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+		if (err) {
+			dev_err(&adapter->pdev->dev,
+				"Allocation for Rx Queue %u failed\n", i);
+			for (i--; i >= 0; i--)
+				igb_free_rx_resources(adapter,
+							&adapter->rx_ring[i]);
+			break;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * igb_setup_rctl - configure the receive control registers
+ * @adapter: Board private structure
+ **/
+static void igb_setup_rctl(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 rctl;
+	u32 srrctl = 0;
+	int i;
+
+	rctl = rd32(E1000_RCTL);
+
+	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+
+	rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
+		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+		(adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+	/* disable the stripping of CRC because it breaks
+	 * BMC firmware connected over SMBUS
+	rctl |= E1000_RCTL_SECRC;
+	*/
+
+	rctl &= ~E1000_RCTL_SBP;
+
+	if (adapter->netdev->mtu <= ETH_DATA_LEN)
+		rctl &= ~E1000_RCTL_LPE;
+	else
+		rctl |= E1000_RCTL_LPE;
+	if (adapter->rx_buffer_len <= IGB_RXBUFFER_2048) {
+		/* Setup buffer sizes */
+		rctl &= ~E1000_RCTL_SZ_4096;
+		rctl |= E1000_RCTL_BSEX;
+		switch (adapter->rx_buffer_len) {
+		case IGB_RXBUFFER_256:
+			rctl |= E1000_RCTL_SZ_256;
+			rctl &= ~E1000_RCTL_BSEX;
+			break;
+		case IGB_RXBUFFER_512:
+			rctl |= E1000_RCTL_SZ_512;
+			rctl &= ~E1000_RCTL_BSEX;
+			break;
+		case IGB_RXBUFFER_1024:
+			rctl |= E1000_RCTL_SZ_1024;
+			rctl &= ~E1000_RCTL_BSEX;
+			break;
+		case IGB_RXBUFFER_2048:
+		default:
+			rctl |= E1000_RCTL_SZ_2048;
+			rctl &= ~E1000_RCTL_BSEX;
+			break;
+		case IGB_RXBUFFER_4096:
+			rctl |= E1000_RCTL_SZ_4096;
+			break;
+		case IGB_RXBUFFER_8192:
+			rctl |= E1000_RCTL_SZ_8192;
+			break;
+		case IGB_RXBUFFER_16384:
+			rctl |= E1000_RCTL_SZ_16384;
+			break;
+		}
+	} else {
+		rctl &= ~E1000_RCTL_BSEX;
+		srrctl = adapter->rx_buffer_len >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+	}
+
+	/* 82575 and greater support packet-split where the protocol
+	 * header is placed in skb->data and the packet data is
+	 * placed in pages hanging off of skb_shinfo(skb)->nr_frags.
+	 * In the case of a non-split, skb->data is linearly filled,
+	 * followed by the page buffers.  Therefore, skb->data is
+	 * sized to hold the largest protocol header.
+	 */
+	/* allocations using alloc_page take too long for regular MTU
+	 * so only enable packet split for jumbo frames */
+	if (rctl & E1000_RCTL_LPE) {
+		adapter->rx_ps_hdr_size = IGB_RXBUFFER_128;
+		srrctl = adapter->rx_ps_hdr_size <<
+			 E1000_SRRCTL_BSIZEHDRSIZE_SHIFT;
+		/* buffer size is ALWAYS one page */
+		srrctl |= PAGE_SIZE >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+		srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+	} else {
+		adapter->rx_ps_hdr_size = 0;
+		srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
+	}
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		wr32(E1000_SRRCTL(i), srrctl);
+
+	wr32(E1000_RCTL, rctl);
+}
+
+/**
+ * igb_configure_rx - Configure receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void igb_configure_rx(struct igb_adapter *adapter)
+{
+	u64 rdba;
+	struct e1000_hw *hw = &adapter->hw;
+	u32 rctl, rxcsum;
+	u32 rxdctl;
+	int i;
+
+	/* disable receives while setting up the descriptors */
+	rctl = rd32(E1000_RCTL);
+	wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN);
+	wrfl();
+	mdelay(10);
+
+	if (adapter->itr_setting > 3)
+		wr32(E1000_ITR,
+				1000000000 / (adapter->itr * 256));
+
+	/* Setup the HW Rx Head and Tail Descriptor Pointers and
+	 * the Base and Length of the Rx Descriptor Ring */
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		struct igb_ring *ring = &(adapter->rx_ring[i]);
+		rdba = ring->dma;
+		wr32(E1000_RDBAL(i),
+				rdba & 0x00000000ffffffffULL);
+		wr32(E1000_RDBAH(i), rdba >> 32);
+		wr32(E1000_RDLEN(i),
+			       ring->count * sizeof(union e1000_adv_rx_desc));
+
+		ring->head = E1000_RDH(i);
+		ring->tail = E1000_RDT(i);
+		writel(0, hw->hw_addr + ring->tail);
+		writel(0, hw->hw_addr + ring->head);
+
+		rxdctl = rd32(E1000_RXDCTL(i));
+		rxdctl |= E1000_RXDCTL_QUEUE_ENABLE;
+		rxdctl &= 0xFFF00000;
+		rxdctl |= IGB_RX_PTHRESH;
+		rxdctl |= IGB_RX_HTHRESH << 8;
+		rxdctl |= IGB_RX_WTHRESH << 16;
+		wr32(E1000_RXDCTL(i), rxdctl);
+	}
+
+	if (adapter->num_rx_queues > 1) {
+		u32 random[10];
+		u32 mrqc;
+		u32 j, shift;
+		union e1000_reta {
+			u32 dword;
+			u8  bytes[4];
+		} reta;
+
+		get_random_bytes(&random[0], 40);
+
+		shift = 6;
+		for (j = 0; j < (32 * 4); j++) {
+			reta.bytes[j & 3] =
+				(j % adapter->num_rx_queues) << shift;
+			if ((j & 3) == 3)
+				writel(reta.dword,
+				       hw->hw_addr + E1000_RETA(0) + (j & ~3));
+		}
+		mrqc = E1000_MRQC_ENABLE_RSS_4Q;
+
+		/* Fill out hash function seeds */
+		for (j = 0; j < 10; j++)
+			array_wr32(E1000_RSSRK(0), j, random[j]);
+
+		mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 |
+			 E1000_MRQC_RSS_FIELD_IPV4_TCP);
+		mrqc |= (E1000_MRQC_RSS_FIELD_IPV6 |
+			 E1000_MRQC_RSS_FIELD_IPV6_TCP);
+		mrqc |= (E1000_MRQC_RSS_FIELD_IPV4_UDP |
+			 E1000_MRQC_RSS_FIELD_IPV6_UDP);
+		mrqc |= (E1000_MRQC_RSS_FIELD_IPV6_UDP_EX |
+			 E1000_MRQC_RSS_FIELD_IPV6_TCP_EX);
+
+
+		wr32(E1000_MRQC, mrqc);
+
+		/* Multiqueue and raw packet checksumming are mutually
+		 * exclusive.  Note that this not the same as TCP/IP
+		 * checksumming, which works fine. */
+		rxcsum = rd32(E1000_RXCSUM);
+		rxcsum |= E1000_RXCSUM_PCSD;
+		wr32(E1000_RXCSUM, rxcsum);
+	} else {
+		/* Enable Receive Checksum Offload for TCP and UDP */
+		rxcsum = rd32(E1000_RXCSUM);
+		if (adapter->rx_csum) {
+			rxcsum |= E1000_RXCSUM_TUOFL;
+
+			/* Enable IPv4 payload checksum for UDP fragments
+			 * Must be used in conjunction with packet-split. */
+			if (adapter->rx_ps_hdr_size)
+				rxcsum |= E1000_RXCSUM_IPPCSE;
+		} else {
+			rxcsum &= ~E1000_RXCSUM_TUOFL;
+			/* don't need to clear IPPCSE as it defaults to 0 */
+		}
+		wr32(E1000_RXCSUM, rxcsum);
+	}
+
+	if (adapter->vlgrp)
+		wr32(E1000_RLPML,
+				adapter->max_frame_size + VLAN_TAG_SIZE);
+	else
+		wr32(E1000_RLPML, adapter->max_frame_size);
+
+	/* Enable Receives */
+	wr32(E1000_RCTL, rctl);
+}
+
+/**
+ * igb_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+static void igb_free_tx_resources(struct igb_adapter *adapter,
+				  struct igb_ring *tx_ring)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	igb_clean_tx_ring(adapter, tx_ring);
+
+	vfree(tx_ring->buffer_info);
+	tx_ring->buffer_info = NULL;
+
+	pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+
+	tx_ring->desc = NULL;
+}
+
+/**
+ * igb_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+static void igb_free_all_tx_resources(struct igb_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		igb_free_tx_resources(adapter, &adapter->tx_ring[i]);
+}
+
+static void igb_unmap_and_free_tx_resource(struct igb_adapter *adapter,
+					   struct igb_buffer *buffer_info)
+{
+	if (buffer_info->dma) {
+		pci_unmap_page(adapter->pdev,
+				buffer_info->dma,
+				buffer_info->length,
+				PCI_DMA_TODEVICE);
+		buffer_info->dma = 0;
+	}
+	if (buffer_info->skb) {
+		dev_kfree_skb_any(buffer_info->skb);
+		buffer_info->skb = NULL;
+	}
+	buffer_info->time_stamp = 0;
+	/* buffer_info must be completely set up in the transmit path */
+}
+
+/**
+ * igb_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ * @tx_ring: ring to be cleaned
+ **/
+static void igb_clean_tx_ring(struct igb_adapter *adapter,
+			      struct igb_ring *tx_ring)
+{
+	struct igb_buffer *buffer_info;
+	unsigned long size;
+	unsigned int i;
+
+	if (!tx_ring->buffer_info)
+		return;
+	/* Free all the Tx ring sk_buffs */
+
+	for (i = 0; i < tx_ring->count; i++) {
+		buffer_info = &tx_ring->buffer_info[i];
+		igb_unmap_and_free_tx_resource(adapter, buffer_info);
+	}
+
+	size = sizeof(struct igb_buffer) * tx_ring->count;
+	memset(tx_ring->buffer_info, 0, size);
+
+	/* Zero out the descriptor ring */
+
+	memset(tx_ring->desc, 0, tx_ring->size);
+
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+
+	writel(0, adapter->hw.hw_addr + tx_ring->head);
+	writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * igb_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void igb_clean_all_tx_rings(struct igb_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		igb_clean_tx_ring(adapter, &adapter->tx_ring[i]);
+}
+
+/**
+ * igb_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ **/
+static void igb_free_rx_resources(struct igb_adapter *adapter,
+				  struct igb_ring *rx_ring)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	igb_clean_rx_ring(adapter, rx_ring);
+
+	vfree(rx_ring->buffer_info);
+	rx_ring->buffer_info = NULL;
+
+	pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
+
+	rx_ring->desc = NULL;
+}
+
+/**
+ * igb_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+static void igb_free_all_rx_resources(struct igb_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		igb_free_rx_resources(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * igb_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ * @rx_ring: ring to free buffers from
+ **/
+static void igb_clean_rx_ring(struct igb_adapter *adapter,
+			      struct igb_ring *rx_ring)
+{
+	struct igb_buffer *buffer_info;
+	struct pci_dev *pdev = adapter->pdev;
+	unsigned long size;
+	unsigned int i;
+
+	if (!rx_ring->buffer_info)
+		return;
+	/* Free all the Rx ring sk_buffs */
+	for (i = 0; i < rx_ring->count; i++) {
+		buffer_info = &rx_ring->buffer_info[i];
+		if (buffer_info->dma) {
+			if (adapter->rx_ps_hdr_size)
+				pci_unmap_single(pdev, buffer_info->dma,
+						 adapter->rx_ps_hdr_size,
+						 PCI_DMA_FROMDEVICE);
+			else
+				pci_unmap_single(pdev, buffer_info->dma,
+						 adapter->rx_buffer_len,
+						 PCI_DMA_FROMDEVICE);
+			buffer_info->dma = 0;
+		}
+
+		if (buffer_info->skb) {
+			dev_kfree_skb(buffer_info->skb);
+			buffer_info->skb = NULL;
+		}
+		if (buffer_info->page) {
+			pci_unmap_page(pdev, buffer_info->page_dma,
+				       PAGE_SIZE, PCI_DMA_FROMDEVICE);
+			put_page(buffer_info->page);
+			buffer_info->page = NULL;
+			buffer_info->page_dma = 0;
+		}
+	}
+
+	/* there also may be some cached data from a chained receive */
+	if (rx_ring->pending_skb) {
+		dev_kfree_skb(rx_ring->pending_skb);
+		rx_ring->pending_skb = NULL;
+	}
+
+	size = sizeof(struct igb_buffer) * rx_ring->count;
+	memset(rx_ring->buffer_info, 0, size);
+
+	/* Zero out the descriptor ring */
+	memset(rx_ring->desc, 0, rx_ring->size);
+
+	rx_ring->next_to_clean = 0;
+	rx_ring->next_to_use = 0;
+
+	writel(0, adapter->hw.hw_addr + rx_ring->head);
+	writel(0, adapter->hw.hw_addr + rx_ring->tail);
+}
+
+/**
+ * igb_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void igb_clean_all_rx_rings(struct igb_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		igb_clean_rx_ring(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * igb_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int igb_set_mac(struct net_device *netdev, void *p)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
+
+	adapter->hw.mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+
+	return 0;
+}
+
+/**
+ * igb_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+static void igb_set_multi(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_mac_info *mac = &hw->mac;
+	struct dev_mc_list *mc_ptr;
+	u8  *mta_list;
+	u32 rctl;
+	int i;
+
+	/* Check for Promiscuous and All Multicast modes */
+
+	rctl = rd32(E1000_RCTL);
+
+	if (netdev->flags & IFF_PROMISC)
+		rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+	else if (netdev->flags & IFF_ALLMULTI) {
+		rctl |= E1000_RCTL_MPE;
+		rctl &= ~E1000_RCTL_UPE;
+	} else
+		rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+
+	wr32(E1000_RCTL, rctl);
+
+	if (!netdev->mc_count) {
+		/* nothing to program, so clear mc list */
+		igb_update_mc_addr_list(hw, NULL, 0, 1,
+					  mac->rar_entry_count);
+		return;
+	}
+
+	mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
+	if (!mta_list)
+		return;
+
+	/* The shared function expects a packed array of only addresses. */
+	mc_ptr = netdev->mc_list;
+
+	for (i = 0; i < netdev->mc_count; i++) {
+		if (!mc_ptr)
+			break;
+		memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
+		mc_ptr = mc_ptr->next;
+	}
+	igb_update_mc_addr_list(hw, mta_list, i, 1, mac->rar_entry_count);
+	kfree(mta_list);
+}
+
+/* Need to wait a few seconds after link up to get diagnostic information from
+ * the phy */
+static void igb_update_phy_info(unsigned long data)
+{
+	struct igb_adapter *adapter = (struct igb_adapter *) data;
+	adapter->hw.phy.ops.get_phy_info(&adapter->hw);
+}
+
+/**
+ * igb_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void igb_watchdog(unsigned long data)
+{
+	struct igb_adapter *adapter = (struct igb_adapter *)data;
+	/* Do the rest outside of interrupt context */
+	schedule_work(&adapter->watchdog_task);
+}
+
+static void igb_watchdog_task(struct work_struct *work)
+{
+	struct igb_adapter *adapter = container_of(work,
+					struct igb_adapter, watchdog_task);
+	struct e1000_hw *hw = &adapter->hw;
+
+	struct net_device *netdev = adapter->netdev;
+	struct igb_ring *tx_ring = adapter->tx_ring;
+	struct e1000_mac_info *mac = &adapter->hw.mac;
+	u32 link;
+	s32 ret_val;
+
+	if ((netif_carrier_ok(netdev)) &&
+	    (rd32(E1000_STATUS) & E1000_STATUS_LU))
+		goto link_up;
+
+	ret_val = hw->mac.ops.check_for_link(&adapter->hw);
+	if ((ret_val == E1000_ERR_PHY) &&
+	    (hw->phy.type == e1000_phy_igp_3) &&
+	    (rd32(E1000_CTRL) &
+	     E1000_PHY_CTRL_GBE_DISABLE))
+		dev_info(&adapter->pdev->dev,
+			 "Gigabit has been disabled, downgrading speed\n");
+
+	if ((hw->phy.media_type == e1000_media_type_internal_serdes) &&
+	    !(rd32(E1000_TXCW) & E1000_TXCW_ANE))
+		link = mac->serdes_has_link;
+	else
+		link = rd32(E1000_STATUS) &
+				      E1000_STATUS_LU;
+
+	if (link) {
+		if (!netif_carrier_ok(netdev)) {
+			u32 ctrl;
+			hw->mac.ops.get_speed_and_duplex(&adapter->hw,
+						   &adapter->link_speed,
+						   &adapter->link_duplex);
+
+			ctrl = rd32(E1000_CTRL);
+			dev_info(&adapter->pdev->dev,
+				 "NIC Link is Up %d Mbps %s, "
+				 "Flow Control: %s\n",
+				 adapter->link_speed,
+				 adapter->link_duplex == FULL_DUPLEX ?
+				 "Full Duplex" : "Half Duplex",
+				 ((ctrl & E1000_CTRL_TFCE) && (ctrl &
+				 E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl &
+				 E1000_CTRL_RFCE) ? "RX" : ((ctrl &
+				 E1000_CTRL_TFCE) ? "TX" : "None")));
+
+			/* tweak tx_queue_len according to speed/duplex and
+			 * adjust the timeout factor */
+			netdev->tx_queue_len = adapter->tx_queue_len;
+			adapter->tx_timeout_factor = 1;
+			switch (adapter->link_speed) {
+			case SPEED_10:
+				netdev->tx_queue_len = 10;
+				adapter->tx_timeout_factor = 14;
+				break;
+			case SPEED_100:
+				netdev->tx_queue_len = 100;
+				/* maybe add some timeout factor ? */
+				break;
+			}
+
+			netif_carrier_on(netdev);
+			netif_wake_queue(netdev);
+
+			if (!test_bit(__IGB_DOWN, &adapter->state))
+				mod_timer(&adapter->phy_info_timer,
+					  round_jiffies(jiffies + 2 * HZ));
+		}
+	} else {
+		if (netif_carrier_ok(netdev)) {
+			adapter->link_speed = 0;
+			adapter->link_duplex = 0;
+			dev_info(&adapter->pdev->dev, "NIC Link is Down\n");
+			netif_carrier_off(netdev);
+			netif_stop_queue(netdev);
+			if (!test_bit(__IGB_DOWN, &adapter->state))
+				mod_timer(&adapter->phy_info_timer,
+					  round_jiffies(jiffies + 2 * HZ));
+		}
+	}
+
+link_up:
+	igb_update_stats(adapter);
+
+	mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
+	adapter->tpt_old = adapter->stats.tpt;
+	mac->collision_delta = adapter->stats.colc - adapter->colc_old;
+	adapter->colc_old = adapter->stats.colc;
+
+	adapter->gorc = adapter->stats.gorc - adapter->gorc_old;
+	adapter->gorc_old = adapter->stats.gorc;
+	adapter->gotc = adapter->stats.gotc - adapter->gotc_old;
+	adapter->gotc_old = adapter->stats.gotc;
+
+	igb_update_adaptive(&adapter->hw);
+
+	if (!netif_carrier_ok(netdev)) {
+		if (IGB_DESC_UNUSED(tx_ring) + 1 < tx_ring->count) {
+			/* We've lost link, so the controller stops DMA,
+			 * but we've got queued Tx work that's never going
+			 * to get done, so reset controller to flush Tx.
+			 * (Do the reset outside of interrupt context). */
+			adapter->tx_timeout_count++;
+			schedule_work(&adapter->reset_task);
+		}
+	}
+
+	/* Cause software interrupt to ensure rx ring is cleaned */
+	wr32(E1000_ICS, E1000_ICS_RXDMT0);
+
+	/* Force detection of hung controller every watchdog period */
+	tx_ring->detect_tx_hung = true;
+
+	/* Reset the timer */
+	if (!test_bit(__IGB_DOWN, &adapter->state))
+		mod_timer(&adapter->watchdog_timer,
+			  round_jiffies(jiffies + 2 * HZ));
+}
+
+enum latency_range {
+	lowest_latency = 0,
+	low_latency = 1,
+	bulk_latency = 2,
+	latency_invalid = 255
+};
+
+
+static void igb_lower_rx_eitr(struct igb_adapter *adapter,
+			      struct igb_ring *rx_ring)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	int new_val;
+
+	new_val = rx_ring->itr_val / 2;
+	if (new_val < IGB_MIN_DYN_ITR)
+		new_val = IGB_MIN_DYN_ITR;
+
+	if (new_val != rx_ring->itr_val) {
+		rx_ring->itr_val = new_val;
+		wr32(rx_ring->itr_register,
+				1000000000 / (new_val * 256));
+	}
+}
+
+static void igb_raise_rx_eitr(struct igb_adapter *adapter,
+			      struct igb_ring *rx_ring)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	int new_val;
+
+	new_val = rx_ring->itr_val * 2;
+	if (new_val > IGB_MAX_DYN_ITR)
+		new_val = IGB_MAX_DYN_ITR;
+
+	if (new_val != rx_ring->itr_val) {
+		rx_ring->itr_val = new_val;
+		wr32(rx_ring->itr_register,
+				1000000000 / (new_val * 256));
+	}
+}
+
+/**
+ * igb_update_itr - update the dynamic ITR value based on statistics
+ *      Stores a new ITR value based on packets and byte
+ *      counts during the last interrupt.  The advantage of per interrupt
+ *      computation is faster updates and more accurate ITR for the current
+ *      traffic pattern.  Constants in this function were computed
+ *      based on theoretical maximum wire speed and thresholds were set based
+ *      on testing data as well as attempting to minimize response time
+ *      while increasing bulk throughput.
+ *      this functionality is controlled by the InterruptThrottleRate module
+ *      parameter (see igb_param.c)
+ *      NOTE:  These calculations are only valid when operating in a single-
+ *             queue environment.
+ * @adapter: pointer to adapter
+ * @itr_setting: current adapter->itr
+ * @packets: the number of packets during this measurement interval
+ * @bytes: the number of bytes during this measurement interval
+ **/
+static unsigned int igb_update_itr(struct igb_adapter *adapter, u16 itr_setting,
+				   int packets, int bytes)
+{
+	unsigned int retval = itr_setting;
+
+	if (packets == 0)
+		goto update_itr_done;
+
+	switch (itr_setting) {
+	case lowest_latency:
+		/* handle TSO and jumbo frames */
+		if (bytes/packets > 8000)
+			retval = bulk_latency;
+		else if ((packets < 5) && (bytes > 512))
+			retval = low_latency;
+		break;
+	case low_latency:  /* 50 usec aka 20000 ints/s */
+		if (bytes > 10000) {
+			/* this if handles the TSO accounting */
+			if (bytes/packets > 8000) {
+				retval = bulk_latency;
+			} else if ((packets < 10) || ((bytes/packets) > 1200)) {
+				retval = bulk_latency;
+			} else if ((packets > 35)) {
+				retval = lowest_latency;
+			}
+		} else if (bytes/packets > 2000) {
+			retval = bulk_latency;
+		} else if (packets <= 2 && bytes < 512) {
+			retval = lowest_latency;
+		}
+		break;
+	case bulk_latency: /* 250 usec aka 4000 ints/s */
+		if (bytes > 25000) {
+			if (packets > 35)
+				retval = low_latency;
+		} else if (bytes < 6000) {
+			retval = low_latency;
+		}
+		break;
+	}
+
+update_itr_done:
+	return retval;
+}
+
+static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register,
+			int rx_only)
+{
+	u16 current_itr;
+	u32 new_itr = adapter->itr;
+
+	/* for non-gigabit speeds, just fix the interrupt rate at 4000 */
+	if (adapter->link_speed != SPEED_1000) {
+		current_itr = 0;
+		new_itr = 4000;
+		goto set_itr_now;
+	}
+
+	adapter->rx_itr = igb_update_itr(adapter,
+				    adapter->rx_itr,
+				    adapter->rx_ring->total_packets,
+				    adapter->rx_ring->total_bytes);
+	/* conservative mode (itr 3) eliminates the lowest_latency setting */
+	if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
+		adapter->rx_itr = low_latency;
+
+	if (!rx_only) {
+		adapter->tx_itr = igb_update_itr(adapter,
+					    adapter->tx_itr,
+					    adapter->tx_ring->total_packets,
+					    adapter->tx_ring->total_bytes);
+		/* conservative mode (itr 3) eliminates the
+		 * lowest_latency setting */
+		if (adapter->itr_setting == 3 &&
+		    adapter->tx_itr == lowest_latency)
+			adapter->tx_itr = low_latency;
+
+		current_itr = max(adapter->rx_itr, adapter->tx_itr);
+	} else {
+		current_itr = adapter->rx_itr;
+	}
+
+	switch (current_itr) {
+	/* counts and packets in update_itr are dependent on these numbers */
+	case lowest_latency:
+		new_itr = 70000;
+		break;
+	case low_latency:
+		new_itr = 20000; /* aka hwitr = ~200 */
+		break;
+	case bulk_latency:
+		new_itr = 4000;
+		break;
+	default:
+		break;
+	}
+
+set_itr_now:
+	if (new_itr != adapter->itr) {
+		/* this attempts to bias the interrupt rate towards Bulk
+		 * by adding intermediate steps when interrupt rate is
+		 * increasing */
+		new_itr = new_itr > adapter->itr ?
+			     min(adapter->itr + (new_itr >> 2), new_itr) :
+			     new_itr;
+		/* Don't write the value here; it resets the adapter's
+		 * internal timer, and causes us to delay far longer than
+		 * we should between interrupts.  Instead, we write the ITR
+		 * value at the beginning of the next interrupt so the timing
+		 * ends up being correct.
+		 */
+		adapter->itr = new_itr;
+		adapter->set_itr = 1;
+	}
+
+	return;
+}
+
+
+#define IGB_TX_FLAGS_CSUM		0x00000001
+#define IGB_TX_FLAGS_VLAN		0x00000002
+#define IGB_TX_FLAGS_TSO		0x00000004
+#define IGB_TX_FLAGS_IPV4		0x00000008
+#define IGB_TX_FLAGS_VLAN_MASK	0xffff0000
+#define IGB_TX_FLAGS_VLAN_SHIFT	16
+
+static inline int igb_tso_adv(struct igb_adapter *adapter,
+			      struct igb_ring *tx_ring,
+			      struct sk_buff *skb, u32 tx_flags, u8 *hdr_len)
+{
+	struct e1000_adv_tx_context_desc *context_desc;
+	unsigned int i;
+	int err;
+	struct igb_buffer *buffer_info;
+	u32 info = 0, tu_cmd = 0;
+	u32 mss_l4len_idx, l4len;
+	*hdr_len = 0;
+
+	if (skb_header_cloned(skb)) {
+		err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+		if (err)
+			return err;
+	}
+
+	l4len = tcp_hdrlen(skb);
+	*hdr_len += l4len;
+
+	if (skb->protocol == htons(ETH_P_IP)) {
+		struct iphdr *iph = ip_hdr(skb);
+		iph->tot_len = 0;
+		iph->check = 0;
+		tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+							 iph->daddr, 0,
+							 IPPROTO_TCP,
+							 0);
+	} else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+		ipv6_hdr(skb)->payload_len = 0;
+		tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+						       &ipv6_hdr(skb)->daddr,
+						       0, IPPROTO_TCP, 0);
+	}
+
+	i = tx_ring->next_to_use;
+
+	buffer_info = &tx_ring->buffer_info[i];
+	context_desc = E1000_TX_CTXTDESC_ADV(*tx_ring, i);
+	/* VLAN MACLEN IPLEN */
+	if (tx_flags & IGB_TX_FLAGS_VLAN)
+		info |= (tx_flags & IGB_TX_FLAGS_VLAN_MASK);
+	info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT);
+	*hdr_len += skb_network_offset(skb);
+	info |= skb_network_header_len(skb);
+	*hdr_len += skb_network_header_len(skb);
+	context_desc->vlan_macip_lens = cpu_to_le32(info);
+
+	/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
+	tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
+
+	if (skb->protocol == htons(ETH_P_IP))
+		tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
+	tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
+
+	context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd);
+
+	/* MSS L4LEN IDX */
+	mss_l4len_idx = (skb_shinfo(skb)->gso_size << E1000_ADVTXD_MSS_SHIFT);
+	mss_l4len_idx |= (l4len << E1000_ADVTXD_L4LEN_SHIFT);
+
+	/* Context index must be unique per ring.  Luckily, so is the interrupt
+	 * mask value. */
+	mss_l4len_idx |= tx_ring->eims_value >> 4;
+
+	context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
+	context_desc->seqnum_seed = 0;
+
+	buffer_info->time_stamp = jiffies;
+	buffer_info->dma = 0;
+	i++;
+	if (i == tx_ring->count)
+		i = 0;
+
+	tx_ring->next_to_use = i;
+
+	return true;
+}
+
+static inline bool igb_tx_csum_adv(struct igb_adapter *adapter,
+					struct igb_ring *tx_ring,
+					struct sk_buff *skb, u32 tx_flags)
+{
+	struct e1000_adv_tx_context_desc *context_desc;
+	unsigned int i;
+	struct igb_buffer *buffer_info;
+	u32 info = 0, tu_cmd = 0;
+
+	if ((skb->ip_summed == CHECKSUM_PARTIAL) ||
+	    (tx_flags & IGB_TX_FLAGS_VLAN)) {
+		i = tx_ring->next_to_use;
+		buffer_info = &tx_ring->buffer_info[i];
+		context_desc = E1000_TX_CTXTDESC_ADV(*tx_ring, i);
+
+		if (tx_flags & IGB_TX_FLAGS_VLAN)
+			info |= (tx_flags & IGB_TX_FLAGS_VLAN_MASK);
+		info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT);
+		if (skb->ip_summed == CHECKSUM_PARTIAL)
+			info |= skb_network_header_len(skb);
+
+		context_desc->vlan_macip_lens = cpu_to_le32(info);
+
+		tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
+
+		if (skb->ip_summed == CHECKSUM_PARTIAL) {
+			if (skb->protocol == htons(ETH_P_IP))
+				tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
+			if (skb->sk && (skb->sk->sk_protocol == IPPROTO_TCP))
+				tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
+		}
+
+		context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd);
+		context_desc->seqnum_seed = 0;
+		context_desc->mss_l4len_idx =
+					  cpu_to_le32(tx_ring->eims_value >> 4);
+
+		buffer_info->time_stamp = jiffies;
+		buffer_info->dma = 0;
+
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+		tx_ring->next_to_use = i;
+
+		return true;
+	}
+
+
+	return false;
+}
+
+#define IGB_MAX_TXD_PWR	16
+#define IGB_MAX_DATA_PER_TXD	(1<<IGB_MAX_TXD_PWR)
+
+static inline int igb_tx_map_adv(struct igb_adapter *adapter,
+				 struct igb_ring *tx_ring,
+				 struct sk_buff *skb)
+{
+	struct igb_buffer *buffer_info;
+	unsigned int len = skb_headlen(skb);
+	unsigned int count = 0, i;
+	unsigned int f;
+
+	i = tx_ring->next_to_use;
+
+	buffer_info = &tx_ring->buffer_info[i];
+	BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
+	buffer_info->length = len;
+	/* set time_stamp *before* dma to help avoid a possible race */
+	buffer_info->time_stamp = jiffies;
+	buffer_info->dma = pci_map_single(adapter->pdev, skb->data, len,
+					  PCI_DMA_TODEVICE);
+	count++;
+	i++;
+	if (i == tx_ring->count)
+		i = 0;
+
+	for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
+		struct skb_frag_struct *frag;
+
+		frag = &skb_shinfo(skb)->frags[f];
+		len = frag->size;
+
+		buffer_info = &tx_ring->buffer_info[i];
+		BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
+		buffer_info->length = len;
+		buffer_info->time_stamp = jiffies;
+		buffer_info->dma = pci_map_page(adapter->pdev,
+						frag->page,
+						frag->page_offset,
+						len,
+						PCI_DMA_TODEVICE);
+
+		count++;
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+	}
+
+	i = (i == 0) ? tx_ring->count - 1 : i - 1;
+	tx_ring->buffer_info[i].skb = skb;
+
+	return count;
+}
+
+static inline void igb_tx_queue_adv(struct igb_adapter *adapter,
+				    struct igb_ring *tx_ring,
+				    int tx_flags, int count, u32 paylen,
+				    u8 hdr_len)
+{
+	union e1000_adv_tx_desc *tx_desc = NULL;
+	struct igb_buffer *buffer_info;
+	u32 olinfo_status = 0, cmd_type_len;
+	unsigned int i;
+
+	cmd_type_len = (E1000_ADVTXD_DTYP_DATA | E1000_ADVTXD_DCMD_IFCS |
+			E1000_ADVTXD_DCMD_DEXT);
+
+	if (tx_flags & IGB_TX_FLAGS_VLAN)
+		cmd_type_len |= E1000_ADVTXD_DCMD_VLE;
+
+	if (tx_flags & IGB_TX_FLAGS_TSO) {
+		cmd_type_len |= E1000_ADVTXD_DCMD_TSE;
+
+		/* insert tcp checksum */
+		olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
+
+		/* insert ip checksum */
+		if (tx_flags & IGB_TX_FLAGS_IPV4)
+			olinfo_status |= E1000_TXD_POPTS_IXSM << 8;
+
+	} else if (tx_flags & IGB_TX_FLAGS_CSUM) {
+		olinfo_status |= E1000_TXD_POPTS_TXSM << 8;
+	}
+
+	if (tx_flags & (IGB_TX_FLAGS_CSUM | IGB_TX_FLAGS_TSO |
+			IGB_TX_FLAGS_VLAN))
+		olinfo_status |= tx_ring->eims_value >> 4;
+
+	olinfo_status |= ((paylen - hdr_len) << E1000_ADVTXD_PAYLEN_SHIFT);
+
+	i = tx_ring->next_to_use;
+	while (count--) {
+		buffer_info = &tx_ring->buffer_info[i];
+		tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
+		tx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma);
+		tx_desc->read.cmd_type_len =
+			cpu_to_le32(cmd_type_len | buffer_info->length);
+		tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+	}
+
+	tx_desc->read.cmd_type_len |= cpu_to_le32(adapter->txd_cmd);
+	/* Force memory writes to complete before letting h/w
+	 * know there are new descriptors to fetch.  (Only
+	 * applicable for weak-ordered memory model archs,
+	 * such as IA-64). */
+	wmb();
+
+	tx_ring->next_to_use = i;
+	writel(i, adapter->hw.hw_addr + tx_ring->tail);
+	/* we need this if more than one processor can write to our tail
+	 * at a time, it syncronizes IO on IA64/Altix systems */
+	mmiowb();
+}
+
+static int __igb_maybe_stop_tx(struct net_device *netdev,
+			       struct igb_ring *tx_ring, int size)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	netif_stop_queue(netdev);
+	/* Herbert's original patch had:
+	 *  smp_mb__after_netif_stop_queue();
+	 * but since that doesn't exist yet, just open code it. */
+	smp_mb();
+
+	/* We need to check again in a case another CPU has just
+	 * made room available. */
+	if (IGB_DESC_UNUSED(tx_ring) < size)
+		return -EBUSY;
+
+	/* A reprieve! */
+	netif_start_queue(netdev);
+	++adapter->restart_queue;
+	return 0;
+}
+
+static int igb_maybe_stop_tx(struct net_device *netdev,
+			     struct igb_ring *tx_ring, int size)
+{
+	if (IGB_DESC_UNUSED(tx_ring) >= size)
+		return 0;
+	return __igb_maybe_stop_tx(netdev, tx_ring, size);
+}
+
+#define TXD_USE_COUNT(S) (((S) >> (IGB_MAX_TXD_PWR)) + 1)
+
+static int igb_xmit_frame_ring_adv(struct sk_buff *skb,
+				   struct net_device *netdev,
+				   struct igb_ring *tx_ring)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	unsigned int tx_flags = 0;
+	unsigned int len;
+	unsigned long irq_flags;
+	u8 hdr_len = 0;
+	int tso = 0;
+
+	len = skb_headlen(skb);
+
+	if (test_bit(__IGB_DOWN, &adapter->state)) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	if (skb->len <= 0) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	if (!spin_trylock_irqsave(&tx_ring->tx_lock, irq_flags))
+		/* Collision - tell upper layer to requeue */
+		return NETDEV_TX_LOCKED;
+
+	/* need: 1 descriptor per page,
+	 *       + 2 desc gap to keep tail from touching head,
+	 *       + 1 desc for skb->data,
+	 *       + 1 desc for context descriptor,
+	 * otherwise try next time */
+	if (igb_maybe_stop_tx(netdev, tx_ring, skb_shinfo(skb)->nr_frags + 4)) {
+		/* this is a hard error */
+		spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+		tx_flags |= IGB_TX_FLAGS_VLAN;
+		tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT);
+	}
+
+	tso = skb_is_gso(skb) ? igb_tso_adv(adapter, tx_ring, skb, tx_flags,
+					      &hdr_len) : 0;
+
+	if (tso < 0) {
+		dev_kfree_skb_any(skb);
+		spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags);
+		return NETDEV_TX_OK;
+	}
+
+	if (tso)
+		tx_flags |= IGB_TX_FLAGS_TSO;
+	else if (igb_tx_csum_adv(adapter, tx_ring, skb, tx_flags))
+			if (skb->ip_summed == CHECKSUM_PARTIAL)
+				tx_flags |= IGB_TX_FLAGS_CSUM;
+
+	if (skb->protocol == htons(ETH_P_IP))
+		tx_flags |= IGB_TX_FLAGS_IPV4;
+
+	igb_tx_queue_adv(adapter, tx_ring, tx_flags,
+			 igb_tx_map_adv(adapter, tx_ring, skb),
+			 skb->len, hdr_len);
+
+	netdev->trans_start = jiffies;
+
+	/* Make sure there is space in the ring for the next send. */
+	igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4);
+
+	spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags);
+	return NETDEV_TX_OK;
+}
+
+static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct igb_ring *tx_ring = &adapter->tx_ring[0];
+
+	/* This goes back to the question of how to logically map a tx queue
+	 * to a flow.  Right now, performance is impacted slightly negatively
+	 * if using multiple tx queues.  If the stack breaks away from a
+	 * single qdisc implementation, we can look at this again. */
+	return (igb_xmit_frame_ring_adv(skb, netdev, tx_ring));
+}
+
+/**
+ * igb_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void igb_tx_timeout(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	/* Do the reset outside of interrupt context */
+	adapter->tx_timeout_count++;
+	schedule_work(&adapter->reset_task);
+	wr32(E1000_EICS, adapter->eims_enable_mask &
+		~(E1000_EIMS_TCP_TIMER | E1000_EIMS_OTHER));
+}
+
+static void igb_reset_task(struct work_struct *work)
+{
+	struct igb_adapter *adapter;
+	adapter = container_of(work, struct igb_adapter, reset_task);
+
+	igb_reinit_locked(adapter);
+}
+
+/**
+ * igb_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+static struct net_device_stats *
+igb_get_stats(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	/* only return the current stats */
+	return &adapter->net_stats;
+}
+
+/**
+ * igb_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int igb_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+
+	if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
+	    (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+		dev_err(&adapter->pdev->dev, "Invalid MTU setting\n");
+		return -EINVAL;
+	}
+
+#define MAX_STD_JUMBO_FRAME_SIZE 9234
+	if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
+		dev_err(&adapter->pdev->dev, "MTU > 9216 not supported.\n");
+		return -EINVAL;
+	}
+
+	while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
+		msleep(1);
+	/* igb_down has a dependency on max_frame_size */
+	adapter->max_frame_size = max_frame;
+	if (netif_running(netdev))
+		igb_down(adapter);
+
+	/* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
+	 * means we reserve 2 more, this pushes us to allocate from the next
+	 * larger slab size.
+	 * i.e. RXBUFFER_2048 --> size-4096 slab
+	 */
+
+	if (max_frame <= IGB_RXBUFFER_256)
+		adapter->rx_buffer_len = IGB_RXBUFFER_256;
+	else if (max_frame <= IGB_RXBUFFER_512)
+		adapter->rx_buffer_len = IGB_RXBUFFER_512;
+	else if (max_frame <= IGB_RXBUFFER_1024)
+		adapter->rx_buffer_len = IGB_RXBUFFER_1024;
+	else if (max_frame <= IGB_RXBUFFER_2048)
+		adapter->rx_buffer_len = IGB_RXBUFFER_2048;
+	else
+		adapter->rx_buffer_len = IGB_RXBUFFER_4096;
+	/* adjust allocation if LPE protects us, and we aren't using SBP */
+	if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) ||
+	     (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE))
+		adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+
+	dev_info(&adapter->pdev->dev, "changing MTU from %d to %d\n",
+		 netdev->mtu, new_mtu);
+	netdev->mtu = new_mtu;
+
+	if (netif_running(netdev))
+		igb_up(adapter);
+	else
+		igb_reset(adapter);
+
+	clear_bit(__IGB_RESETTING, &adapter->state);
+
+	return 0;
+}
+
+/**
+ * igb_update_stats - Update the board statistics counters
+ * @adapter: board private structure
+ **/
+
+void igb_update_stats(struct igb_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct pci_dev *pdev = adapter->pdev;
+	u16 phy_tmp;
+
+#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
+
+	/*
+	 * Prevent stats update while adapter is being reset, or if the pci
+	 * connection is down.
+	 */
+	if (adapter->link_speed == 0)
+		return;
+	if (pci_channel_offline(pdev))
+		return;
+
+	adapter->stats.crcerrs += rd32(E1000_CRCERRS);
+	adapter->stats.gprc += rd32(E1000_GPRC);
+	adapter->stats.gorc += rd32(E1000_GORCL);
+	rd32(E1000_GORCH); /* clear GORCL */
+	adapter->stats.bprc += rd32(E1000_BPRC);
+	adapter->stats.mprc += rd32(E1000_MPRC);
+	adapter->stats.roc += rd32(E1000_ROC);
+
+	adapter->stats.prc64 += rd32(E1000_PRC64);
+	adapter->stats.prc127 += rd32(E1000_PRC127);
+	adapter->stats.prc255 += rd32(E1000_PRC255);
+	adapter->stats.prc511 += rd32(E1000_PRC511);
+	adapter->stats.prc1023 += rd32(E1000_PRC1023);
+	adapter->stats.prc1522 += rd32(E1000_PRC1522);
+	adapter->stats.symerrs += rd32(E1000_SYMERRS);
+	adapter->stats.sec += rd32(E1000_SEC);
+
+	adapter->stats.mpc += rd32(E1000_MPC);
+	adapter->stats.scc += rd32(E1000_SCC);
+	adapter->stats.ecol += rd32(E1000_ECOL);
+	adapter->stats.mcc += rd32(E1000_MCC);
+	adapter->stats.latecol += rd32(E1000_LATECOL);
+	adapter->stats.dc += rd32(E1000_DC);
+	adapter->stats.rlec += rd32(E1000_RLEC);
+	adapter->stats.xonrxc += rd32(E1000_XONRXC);
+	adapter->stats.xontxc += rd32(E1000_XONTXC);
+	adapter->stats.xoffrxc += rd32(E1000_XOFFRXC);
+	adapter->stats.xofftxc += rd32(E1000_XOFFTXC);
+	adapter->stats.fcruc += rd32(E1000_FCRUC);
+	adapter->stats.gptc += rd32(E1000_GPTC);
+	adapter->stats.gotc += rd32(E1000_GOTCL);
+	rd32(E1000_GOTCH); /* clear GOTCL */
+	adapter->stats.rnbc += rd32(E1000_RNBC);
+	adapter->stats.ruc += rd32(E1000_RUC);
+	adapter->stats.rfc += rd32(E1000_RFC);
+	adapter->stats.rjc += rd32(E1000_RJC);
+	adapter->stats.tor += rd32(E1000_TORH);
+	adapter->stats.tot += rd32(E1000_TOTH);
+	adapter->stats.tpr += rd32(E1000_TPR);
+
+	adapter->stats.ptc64 += rd32(E1000_PTC64);
+	adapter->stats.ptc127 += rd32(E1000_PTC127);
+	adapter->stats.ptc255 += rd32(E1000_PTC255);
+	adapter->stats.ptc511 += rd32(E1000_PTC511);
+	adapter->stats.ptc1023 += rd32(E1000_PTC1023);
+	adapter->stats.ptc1522 += rd32(E1000_PTC1522);
+
+	adapter->stats.mptc += rd32(E1000_MPTC);
+	adapter->stats.bptc += rd32(E1000_BPTC);
+
+	/* used for adaptive IFS */
+
+	hw->mac.tx_packet_delta = rd32(E1000_TPT);
+	adapter->stats.tpt += hw->mac.tx_packet_delta;
+	hw->mac.collision_delta = rd32(E1000_COLC);
+	adapter->stats.colc += hw->mac.collision_delta;
+
+	adapter->stats.algnerrc += rd32(E1000_ALGNERRC);
+	adapter->stats.rxerrc += rd32(E1000_RXERRC);
+	adapter->stats.tncrs += rd32(E1000_TNCRS);
+	adapter->stats.tsctc += rd32(E1000_TSCTC);
+	adapter->stats.tsctfc += rd32(E1000_TSCTFC);
+
+	adapter->stats.iac += rd32(E1000_IAC);
+	adapter->stats.icrxoc += rd32(E1000_ICRXOC);
+	adapter->stats.icrxptc += rd32(E1000_ICRXPTC);
+	adapter->stats.icrxatc += rd32(E1000_ICRXATC);
+	adapter->stats.ictxptc += rd32(E1000_ICTXPTC);
+	adapter->stats.ictxatc += rd32(E1000_ICTXATC);
+	adapter->stats.ictxqec += rd32(E1000_ICTXQEC);
+	adapter->stats.ictxqmtc += rd32(E1000_ICTXQMTC);
+	adapter->stats.icrxdmtc += rd32(E1000_ICRXDMTC);
+
+	/* Fill out the OS statistics structure */
+	adapter->net_stats.multicast = adapter->stats.mprc;
+	adapter->net_stats.collisions = adapter->stats.colc;
+
+	/* Rx Errors */
+
+	/* RLEC on some newer hardware can be incorrect so build
+	* our own version based on RUC and ROC */
+	adapter->net_stats.rx_errors = adapter->stats.rxerrc +
+		adapter->stats.crcerrs + adapter->stats.algnerrc +
+		adapter->stats.ruc + adapter->stats.roc +
+		adapter->stats.cexterr;
+	adapter->net_stats.rx_length_errors = adapter->stats.ruc +
+					      adapter->stats.roc;
+	adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+	adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
+	adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+
+	/* Tx Errors */
+	adapter->net_stats.tx_errors = adapter->stats.ecol +
+				       adapter->stats.latecol;
+	adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
+	adapter->net_stats.tx_window_errors = adapter->stats.latecol;
+	adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+
+	/* Tx Dropped needs to be maintained elsewhere */
+
+	/* Phy Stats */
+	if (hw->phy.media_type == e1000_media_type_copper) {
+		if ((adapter->link_speed == SPEED_1000) &&
+		   (!hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS,
+					      &phy_tmp))) {
+			phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
+			adapter->phy_stats.idle_errors += phy_tmp;
+		}
+	}
+
+	/* Management Stats */
+	adapter->stats.mgptc += rd32(E1000_MGTPTC);
+	adapter->stats.mgprc += rd32(E1000_MGTPRC);
+	adapter->stats.mgpdc += rd32(E1000_MGTPDC);
+}
+
+
+static irqreturn_t igb_msix_other(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 eicr;
+	/* disable interrupts from the "other" bit, avoid re-entry */
+	wr32(E1000_EIMC, E1000_EIMS_OTHER);
+
+	eicr = rd32(E1000_EICR);
+
+	if (eicr & E1000_EIMS_OTHER) {
+		u32 icr = rd32(E1000_ICR);
+		/* reading ICR causes bit 31 of EICR to be cleared */
+		if (!(icr & E1000_ICR_LSC))
+			goto no_link_interrupt;
+		hw->mac.get_link_status = 1;
+		/* guard against interrupt when we're going down */
+		if (!test_bit(__IGB_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
+	}
+
+no_link_interrupt:
+	wr32(E1000_IMS, E1000_IMS_LSC);
+	wr32(E1000_EIMS, E1000_EIMS_OTHER);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t igb_msix_tx(int irq, void *data)
+{
+	struct igb_ring *tx_ring = data;
+	struct igb_adapter *adapter = tx_ring->adapter;
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (!tx_ring->itr_val)
+		wr32(E1000_EIMC, tx_ring->eims_value);
+
+	tx_ring->total_bytes = 0;
+	tx_ring->total_packets = 0;
+	if (!igb_clean_tx_irq(adapter, tx_ring))
+		/* Ring was not completely cleaned, so fire another interrupt */
+		wr32(E1000_EICS, tx_ring->eims_value);
+
+	if (!tx_ring->itr_val)
+		wr32(E1000_EIMS, tx_ring->eims_value);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t igb_msix_rx(int irq, void *data)
+{
+	struct igb_ring *rx_ring = data;
+	struct igb_adapter *adapter = rx_ring->adapter;
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (!rx_ring->itr_val)
+		wr32(E1000_EIMC, rx_ring->eims_value);
+
+	if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) {
+		rx_ring->total_bytes = 0;
+		rx_ring->total_packets = 0;
+		rx_ring->no_itr_adjust = 0;
+		__netif_rx_schedule(adapter->netdev, &rx_ring->napi);
+	} else {
+		if (!rx_ring->no_itr_adjust) {
+			igb_lower_rx_eitr(adapter, rx_ring);
+			rx_ring->no_itr_adjust = 1;
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+/**
+ * igb_intr_msi - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t igb_intr_msi(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct napi_struct *napi = &adapter->napi;
+	struct e1000_hw *hw = &adapter->hw;
+	/* read ICR disables interrupts using IAM */
+	u32 icr = rd32(E1000_ICR);
+
+	/* Write the ITR value calculated at the end of the
+	 * previous interrupt.
+	 */
+	if (adapter->set_itr) {
+		wr32(E1000_ITR,
+			1000000000 / (adapter->itr * 256));
+		adapter->set_itr = 0;
+	}
+
+	/* read ICR disables interrupts using IAM */
+	if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+		hw->mac.get_link_status = 1;
+		if (!test_bit(__IGB_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
+	}
+
+	if (netif_rx_schedule_prep(netdev, napi)) {
+		adapter->tx_ring->total_bytes = 0;
+		adapter->tx_ring->total_packets = 0;
+		adapter->rx_ring->total_bytes = 0;
+		adapter->rx_ring->total_packets = 0;
+		__netif_rx_schedule(netdev, napi);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * igb_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t igb_intr(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct napi_struct *napi = &adapter->napi;
+	struct e1000_hw *hw = &adapter->hw;
+	/* Interrupt Auto-Mask...upon reading ICR, interrupts are masked.  No
+	 * need for the IMC write */
+	u32 icr = rd32(E1000_ICR);
+	u32 eicr = 0;
+	if (!icr)
+		return IRQ_NONE;  /* Not our interrupt */
+
+	/* Write the ITR value calculated at the end of the
+	 * previous interrupt.
+	 */
+	if (adapter->set_itr) {
+		wr32(E1000_ITR,
+			1000000000 / (adapter->itr * 256));
+		adapter->set_itr = 0;
+	}
+
+	/* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
+	 * not set, then the adapter didn't send an interrupt */
+	if (!(icr & E1000_ICR_INT_ASSERTED))
+		return IRQ_NONE;
+
+	eicr = rd32(E1000_EICR);
+
+	if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+		hw->mac.get_link_status = 1;
+		/* guard against interrupt when we're going down */
+		if (!test_bit(__IGB_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
+	}
+
+	if (netif_rx_schedule_prep(netdev, napi)) {
+		adapter->tx_ring->total_bytes = 0;
+		adapter->rx_ring->total_bytes = 0;
+		adapter->tx_ring->total_packets = 0;
+		adapter->rx_ring->total_packets = 0;
+		__netif_rx_schedule(netdev, napi);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * igb_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ **/
+static int igb_clean(struct napi_struct *napi, int budget)
+{
+	struct igb_adapter *adapter = container_of(napi, struct igb_adapter,
+						   napi);
+	struct net_device *netdev = adapter->netdev;
+	int tx_clean_complete = 1, work_done = 0;
+	int i;
+
+	/* Must NOT use netdev_priv macro here. */
+	adapter = netdev->priv;
+
+	/* Keep link state information with original netdev */
+	if (!netif_carrier_ok(netdev))
+		goto quit_polling;
+
+	/* igb_clean is called per-cpu.  This lock protects tx_ring[i] from
+	 * being cleaned by multiple cpus simultaneously.  A failure obtaining
+	 * the lock means tx_ring[i] is currently being cleaned anyway. */
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		if (spin_trylock(&adapter->tx_ring[i].tx_clean_lock)) {
+			tx_clean_complete &= igb_clean_tx_irq(adapter,
+							&adapter->tx_ring[i]);
+			spin_unlock(&adapter->tx_ring[i].tx_clean_lock);
+		}
+	}
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		igb_clean_rx_irq_adv(adapter, &adapter->rx_ring[i], &work_done,
+				     adapter->rx_ring[i].napi.weight);
+
+	/* If no Tx and not enough Rx work done, exit the polling mode */
+	if ((tx_clean_complete && (work_done < budget)) ||
+	    !netif_running(netdev)) {
+quit_polling:
+		if (adapter->itr_setting & 3)
+			igb_set_itr(adapter, E1000_ITR, false);
+		netif_rx_complete(netdev, napi);
+		if (!test_bit(__IGB_DOWN, &adapter->state))
+			igb_irq_enable(adapter);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget)
+{
+	struct igb_ring *rx_ring = container_of(napi, struct igb_ring, napi);
+	struct igb_adapter *adapter = rx_ring->adapter;
+	struct e1000_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	int work_done = 0;
+
+	/* Keep link state information with original netdev */
+	if (!netif_carrier_ok(netdev))
+		goto quit_polling;
+
+	igb_clean_rx_irq_adv(adapter, rx_ring, &work_done, budget);
+
+
+	/* If not enough Rx work done, exit the polling mode */
+	if ((work_done == 0) || !netif_running(netdev)) {
+quit_polling:
+		netif_rx_complete(netdev, napi);
+
+		wr32(E1000_EIMS, rx_ring->eims_value);
+		if ((adapter->itr_setting & 3) && !rx_ring->no_itr_adjust &&
+		    (rx_ring->total_packets > IGB_DYN_ITR_PACKET_THRESHOLD)) {
+			int mean_size = rx_ring->total_bytes /
+					rx_ring->total_packets;
+			if (mean_size < IGB_DYN_ITR_LENGTH_LOW)
+				igb_raise_rx_eitr(adapter, rx_ring);
+			else if (mean_size > IGB_DYN_ITR_LENGTH_HIGH)
+				igb_lower_rx_eitr(adapter, rx_ring);
+		}
+		return 0;
+	}
+
+	return 1;
+}
+/**
+ * igb_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ * returns true if ring is completely cleaned
+ **/
+static bool igb_clean_tx_irq(struct igb_adapter *adapter,
+				  struct igb_ring *tx_ring)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_tx_desc *tx_desc;
+	struct igb_buffer *buffer_info;
+	struct sk_buff *skb;
+	unsigned int i;
+	u32 head, oldhead;
+	unsigned int count = 0;
+	bool cleaned = false;
+	bool retval = true;
+	unsigned int total_bytes = 0, total_packets = 0;
+
+	rmb();
+	head = *(volatile u32 *)((struct e1000_tx_desc *)tx_ring->desc
+				 + tx_ring->count);
+	head = le32_to_cpu(head);
+	i = tx_ring->next_to_clean;
+	while (1) {
+		while (i != head) {
+			cleaned = true;
+			tx_desc = E1000_TX_DESC(*tx_ring, i);
+			buffer_info = &tx_ring->buffer_info[i];
+			skb = buffer_info->skb;
+
+			if (skb) {
+				unsigned int segs, bytecount;
+				/* gso_segs is currently only valid for tcp */
+				segs = skb_shinfo(skb)->gso_segs ?: 1;
+				/* multiply data chunks by size of headers */
+				bytecount = ((segs - 1) * skb_headlen(skb)) +
+					    skb->len;
+				total_packets += segs;
+				total_bytes += bytecount;
+			}
+
+			igb_unmap_and_free_tx_resource(adapter, buffer_info);
+			tx_desc->upper.data = 0;
+
+			i++;
+			if (i == tx_ring->count)
+				i = 0;
+
+			count++;
+			if (count == IGB_MAX_TX_CLEAN) {
+				retval = false;
+				goto done_cleaning;
+			}
+		}
+		oldhead = head;
+		rmb();
+		head = *(volatile u32 *)((struct e1000_tx_desc *)tx_ring->desc
+					 + tx_ring->count);
+		head = le32_to_cpu(head);
+		if (head == oldhead)
+			goto done_cleaning;
+	}  /* while (1) */
+
+done_cleaning:
+	tx_ring->next_to_clean = i;
+
+	if (unlikely(cleaned &&
+		     netif_carrier_ok(netdev) &&
+		     IGB_DESC_UNUSED(tx_ring) >= IGB_TX_QUEUE_WAKE)) {
+		/* Make sure that anybody stopping the queue after this
+		 * sees the new next_to_clean.
+		 */
+		smp_mb();
+		if (netif_queue_stopped(netdev) &&
+		    !(test_bit(__IGB_DOWN, &adapter->state))) {
+			netif_wake_queue(netdev);
+			++adapter->restart_queue;
+		}
+	}
+
+	if (tx_ring->detect_tx_hung) {
+		/* Detect a transmit hang in hardware, this serializes the
+		 * check with the clearing of time_stamp and movement of i */
+		tx_ring->detect_tx_hung = false;
+		if (tx_ring->buffer_info[i].time_stamp &&
+		    time_after(jiffies, tx_ring->buffer_info[i].time_stamp +
+			       (adapter->tx_timeout_factor * HZ))
+		    && !(rd32(E1000_STATUS) &
+			 E1000_STATUS_TXOFF)) {
+
+			tx_desc = E1000_TX_DESC(*tx_ring, i);
+			/* detected Tx unit hang */
+			dev_err(&adapter->pdev->dev,
+				"Detected Tx Unit Hang\n"
+				"  Tx Queue             <%lu>\n"
+				"  TDH                  <%x>\n"
+				"  TDT                  <%x>\n"
+				"  next_to_use          <%x>\n"
+				"  next_to_clean        <%x>\n"
+				"  head (WB)            <%x>\n"
+				"buffer_info[next_to_clean]\n"
+				"  time_stamp           <%lx>\n"
+				"  jiffies              <%lx>\n"
+				"  desc.status          <%x>\n",
+				(unsigned long)((tx_ring - adapter->tx_ring) /
+					sizeof(struct igb_ring)),
+				readl(adapter->hw.hw_addr + tx_ring->head),
+				readl(adapter->hw.hw_addr + tx_ring->tail),
+				tx_ring->next_to_use,
+				tx_ring->next_to_clean,
+				head,
+				tx_ring->buffer_info[i].time_stamp,
+				jiffies,
+				tx_desc->upper.fields.status);
+			netif_stop_queue(netdev);
+		}
+	}
+	tx_ring->total_bytes += total_bytes;
+	tx_ring->total_packets += total_packets;
+	adapter->net_stats.tx_bytes += total_bytes;
+	adapter->net_stats.tx_packets += total_packets;
+	return retval;
+}
+
+
+/**
+ * igb_receive_skb - helper function to handle rx indications
+ * @adapter: board private structure
+ * @status: descriptor status field as written by hardware
+ * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
+ * @skb: pointer to sk_buff to be indicated to stack
+ **/
+static void igb_receive_skb(struct igb_adapter *adapter, u8 status, u16 vlan,
+			    struct sk_buff *skb)
+{
+	if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))
+		vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+					 le16_to_cpu(vlan) &
+					 E1000_RXD_SPC_VLAN_MASK);
+	else
+		netif_receive_skb(skb);
+}
+
+
+static inline void igb_rx_checksum_adv(struct igb_adapter *adapter,
+				       u32 status_err, struct sk_buff *skb)
+{
+	skb->ip_summed = CHECKSUM_NONE;
+
+	/* Ignore Checksum bit is set or checksum is disabled through ethtool */
+	if ((status_err & E1000_RXD_STAT_IXSM) || !adapter->rx_csum)
+		return;
+	/* TCP/UDP checksum error bit is set */
+	if (status_err &
+	    (E1000_RXDEXT_STATERR_TCPE | E1000_RXDEXT_STATERR_IPE)) {
+		/* let the stack verify checksum errors */
+		adapter->hw_csum_err++;
+		return;
+	}
+	/* It must be a TCP or UDP packet with a valid checksum */
+	if (status_err & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+	adapter->hw_csum_good++;
+}
+
+static bool igb_clean_rx_irq_adv(struct igb_adapter *adapter,
+				      struct igb_ring *rx_ring,
+				      int *work_done, int budget)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	union e1000_adv_rx_desc *rx_desc , *next_rxd;
+	struct igb_buffer *buffer_info , *next_buffer;
+	struct sk_buff *skb;
+	unsigned int i, j;
+	u32 length, hlen, staterr;
+	bool cleaned = false;
+	int cleaned_count = 0;
+	unsigned int total_bytes = 0, total_packets = 0;
+
+	i = rx_ring->next_to_clean;
+	rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
+	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+
+	while (staterr & E1000_RXD_STAT_DD) {
+		if (*work_done >= budget)
+			break;
+		(*work_done)++;
+		buffer_info = &rx_ring->buffer_info[i];
+
+		/* HW will not DMA in data larger than the given buffer, even
+		 * if it parses the (NFS, of course) header to be larger.  In
+		 * that case, it fills the header buffer and spills the rest
+		 * into the page.
+		 */
+		hlen = le16_to_cpu((rx_desc->wb.lower.lo_dword.hdr_info &
+		  E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT);
+		if (hlen > adapter->rx_ps_hdr_size)
+			hlen = adapter->rx_ps_hdr_size;
+
+		length = le16_to_cpu(rx_desc->wb.upper.length);
+		cleaned = true;
+		cleaned_count++;
+
+		if (rx_ring->pending_skb != NULL) {
+			skb = rx_ring->pending_skb;
+			rx_ring->pending_skb = NULL;
+			j = rx_ring->pending_skb_page;
+		} else {
+			skb = buffer_info->skb;
+			prefetch(skb->data - NET_IP_ALIGN);
+			buffer_info->skb = NULL;
+			if (hlen) {
+				pci_unmap_single(pdev, buffer_info->dma,
+						 adapter->rx_ps_hdr_size +
+						   NET_IP_ALIGN,
+						 PCI_DMA_FROMDEVICE);
+				skb_put(skb, hlen);
+			} else {
+				pci_unmap_single(pdev, buffer_info->dma,
+						 adapter->rx_buffer_len +
+						   NET_IP_ALIGN,
+						 PCI_DMA_FROMDEVICE);
+				skb_put(skb, length);
+				goto send_up;
+			}
+			j = 0;
+		}
+
+		while (length) {
+			pci_unmap_page(pdev, buffer_info->page_dma,
+				PAGE_SIZE, PCI_DMA_FROMDEVICE);
+			buffer_info->page_dma = 0;
+			skb_fill_page_desc(skb, j, buffer_info->page,
+						0, length);
+			buffer_info->page = NULL;
+
+			skb->len += length;
+			skb->data_len += length;
+			skb->truesize += length;
+			rx_desc->wb.upper.status_error = 0;
+			if (staterr & E1000_RXD_STAT_EOP)
+				break;
+
+			j++;
+			cleaned_count++;
+			i++;
+			if (i == rx_ring->count)
+				i = 0;
+
+			buffer_info = &rx_ring->buffer_info[i];
+			rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
+			staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+			length = le16_to_cpu(rx_desc->wb.upper.length);
+			if (!(staterr & E1000_RXD_STAT_DD)) {
+				rx_ring->pending_skb = skb;
+				rx_ring->pending_skb_page = j;
+				goto out;
+			}
+		}
+send_up:
+		pskb_trim(skb, skb->len - 4);
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		next_rxd = E1000_RX_DESC_ADV(*rx_ring, i);
+		prefetch(next_rxd);
+		next_buffer = &rx_ring->buffer_info[i];
+
+		if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
+			dev_kfree_skb_irq(skb);
+			goto next_desc;
+		}
+		rx_ring->no_itr_adjust |= (staterr & E1000_RXD_STAT_DYNINT);
+
+		total_bytes += skb->len;
+		total_packets++;
+
+		igb_rx_checksum_adv(adapter, staterr, skb);
+
+		skb->protocol = eth_type_trans(skb, netdev);
+
+		igb_receive_skb(adapter, staterr, rx_desc->wb.upper.vlan, skb);
+
+		netdev->last_rx = jiffies;
+
+next_desc:
+		rx_desc->wb.upper.status_error = 0;
+
+		/* return some buffers to hardware, one at a time is too slow */
+		if (cleaned_count >= IGB_RX_BUFFER_WRITE) {
+			igb_alloc_rx_buffers_adv(adapter, rx_ring,
+						 cleaned_count);
+			cleaned_count = 0;
+		}
+
+		/* use prefetched values */
+		rx_desc = next_rxd;
+		buffer_info = next_buffer;
+
+		staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+	}
+out:
+	rx_ring->next_to_clean = i;
+	cleaned_count = IGB_DESC_UNUSED(rx_ring);
+
+	if (cleaned_count)
+		igb_alloc_rx_buffers_adv(adapter, rx_ring, cleaned_count);
+
+	rx_ring->total_packets += total_packets;
+	rx_ring->total_bytes += total_bytes;
+	rx_ring->rx_stats.packets += total_packets;
+	rx_ring->rx_stats.bytes += total_bytes;
+	adapter->net_stats.rx_bytes += total_bytes;
+	adapter->net_stats.rx_packets += total_packets;
+	return cleaned;
+}
+
+
+/**
+ * igb_alloc_rx_buffers_adv - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+static void igb_alloc_rx_buffers_adv(struct igb_adapter *adapter,
+				     struct igb_ring *rx_ring,
+				     int cleaned_count)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	union e1000_adv_rx_desc *rx_desc;
+	struct igb_buffer *buffer_info;
+	struct sk_buff *skb;
+	unsigned int i;
+
+	i = rx_ring->next_to_use;
+	buffer_info = &rx_ring->buffer_info[i];
+
+	while (cleaned_count--) {
+		rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
+
+		if (adapter->rx_ps_hdr_size && !buffer_info->page) {
+			buffer_info->page = alloc_page(GFP_ATOMIC);
+			if (!buffer_info->page) {
+				adapter->alloc_rx_buff_failed++;
+				goto no_buffers;
+			}
+			buffer_info->page_dma =
+				pci_map_page(pdev,
+					     buffer_info->page,
+					     0, PAGE_SIZE,
+					     PCI_DMA_FROMDEVICE);
+		}
+
+		if (!buffer_info->skb) {
+			int bufsz;
+
+			if (adapter->rx_ps_hdr_size)
+				bufsz = adapter->rx_ps_hdr_size;
+			else
+				bufsz = adapter->rx_buffer_len;
+			bufsz += NET_IP_ALIGN;
+			skb = netdev_alloc_skb(netdev, bufsz);
+
+			if (!skb) {
+				adapter->alloc_rx_buff_failed++;
+				goto no_buffers;
+			}
+
+			/* Make buffer alignment 2 beyond a 16 byte boundary
+			 * this will result in a 16 byte aligned IP header after
+			 * the 14 byte MAC header is removed
+			 */
+			skb_reserve(skb, NET_IP_ALIGN);
+
+			buffer_info->skb = skb;
+			buffer_info->dma = pci_map_single(pdev, skb->data,
+							  bufsz,
+							  PCI_DMA_FROMDEVICE);
+
+		}
+		/* Refresh the desc even if buffer_addrs didn't change because
+		 * each write-back erases this info. */
+		if (adapter->rx_ps_hdr_size) {
+			rx_desc->read.pkt_addr =
+			     cpu_to_le64(buffer_info->page_dma);
+			rx_desc->read.hdr_addr = cpu_to_le64(buffer_info->dma);
+		} else {
+			rx_desc->read.pkt_addr =
+			     cpu_to_le64(buffer_info->dma);
+			rx_desc->read.hdr_addr = 0;
+		}
+
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		buffer_info = &rx_ring->buffer_info[i];
+	}
+
+no_buffers:
+	if (rx_ring->next_to_use != i) {
+		rx_ring->next_to_use = i;
+		if (i == 0)
+			i = (rx_ring->count - 1);
+		else
+			i--;
+
+		/* Force memory writes to complete before letting h/w
+		 * know there are new descriptors to fetch.  (Only
+		 * applicable for weak-ordered memory model archs,
+		 * such as IA-64). */
+		wmb();
+		writel(i, adapter->hw.hw_addr + rx_ring->tail);
+	}
+}
+
+/**
+ * igb_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ **/
+static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct mii_ioctl_data *data = if_mii(ifr);
+
+	if (adapter->hw.phy.media_type != e1000_media_type_copper)
+		return -EOPNOTSUPP;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = adapter->hw.phy.addr;
+		break;
+	case SIOCGMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (adapter->hw.phy.ops.read_phy_reg(&adapter->hw,
+						     data->reg_num
+						     & 0x1F, &data->val_out))
+			return -EIO;
+		break;
+	case SIOCSMIIREG:
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+/**
+ * igb_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ **/
+static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	switch (cmd) {
+	case SIOCGMIIPHY:
+	case SIOCGMIIREG:
+	case SIOCSMIIREG:
+		return igb_mii_ioctl(netdev, ifr, cmd);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void igb_vlan_rx_register(struct net_device *netdev,
+				 struct vlan_group *grp)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl, rctl;
+
+	igb_irq_disable(adapter);
+	adapter->vlgrp = grp;
+
+	if (grp) {
+		/* enable VLAN tag insert/strip */
+		ctrl = rd32(E1000_CTRL);
+		ctrl |= E1000_CTRL_VME;
+		wr32(E1000_CTRL, ctrl);
+
+		/* enable VLAN receive filtering */
+		rctl = rd32(E1000_RCTL);
+		rctl |= E1000_RCTL_VFE;
+		rctl &= ~E1000_RCTL_CFIEN;
+		wr32(E1000_RCTL, rctl);
+		igb_update_mng_vlan(adapter);
+		wr32(E1000_RLPML,
+				adapter->max_frame_size + VLAN_TAG_SIZE);
+	} else {
+		/* disable VLAN tag insert/strip */
+		ctrl = rd32(E1000_CTRL);
+		ctrl &= ~E1000_CTRL_VME;
+		wr32(E1000_CTRL, ctrl);
+
+		/* disable VLAN filtering */
+		rctl = rd32(E1000_RCTL);
+		rctl &= ~E1000_RCTL_VFE;
+		wr32(E1000_RCTL, rctl);
+		if (adapter->mng_vlan_id != (u16)IGB_MNG_VLAN_NONE) {
+			igb_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+			adapter->mng_vlan_id = IGB_MNG_VLAN_NONE;
+		}
+		wr32(E1000_RLPML,
+				adapter->max_frame_size);
+	}
+
+	if (!test_bit(__IGB_DOWN, &adapter->state))
+		igb_irq_enable(adapter);
+}
+
+static void igb_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 vfta, index;
+
+	if ((adapter->hw.mng_cookie.status &
+	     E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+	    (vid == adapter->mng_vlan_id))
+		return;
+	/* add VID to filter table */
+	index = (vid >> 5) & 0x7F;
+	vfta = array_rd32(E1000_VFTA, index);
+	vfta |= (1 << (vid & 0x1F));
+	igb_write_vfta(&adapter->hw, index, vfta);
+}
+
+static void igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 vfta, index;
+
+	igb_irq_disable(adapter);
+	vlan_group_set_device(adapter->vlgrp, vid, NULL);
+
+	if (!test_bit(__IGB_DOWN, &adapter->state))
+		igb_irq_enable(adapter);
+
+	if ((adapter->hw.mng_cookie.status &
+	     E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+	    (vid == adapter->mng_vlan_id)) {
+		/* release control to f/w */
+		igb_release_hw_control(adapter);
+		return;
+	}
+
+	/* remove VID from filter table */
+	index = (vid >> 5) & 0x7F;
+	vfta = array_rd32(E1000_VFTA, index);
+	vfta &= ~(1 << (vid & 0x1F));
+	igb_write_vfta(&adapter->hw, index, vfta);
+}
+
+static void igb_restore_vlan(struct igb_adapter *adapter)
+{
+	igb_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+	if (adapter->vlgrp) {
+		u16 vid;
+		for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+			if (!vlan_group_get_device(adapter->vlgrp, vid))
+				continue;
+			igb_vlan_rx_add_vid(adapter->netdev, vid);
+		}
+	}
+}
+
+int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx)
+{
+	struct e1000_mac_info *mac = &adapter->hw.mac;
+
+	mac->autoneg = 0;
+
+	/* Fiber NICs only allow 1000 gbps Full duplex */
+	if ((adapter->hw.phy.media_type == e1000_media_type_fiber) &&
+		spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+		dev_err(&adapter->pdev->dev,
+			"Unsupported Speed/Duplex configuration\n");
+		return -EINVAL;
+	}
+
+	switch (spddplx) {
+	case SPEED_10 + DUPLEX_HALF:
+		mac->forced_speed_duplex = ADVERTISE_10_HALF;
+		break;
+	case SPEED_10 + DUPLEX_FULL:
+		mac->forced_speed_duplex = ADVERTISE_10_FULL;
+		break;
+	case SPEED_100 + DUPLEX_HALF:
+		mac->forced_speed_duplex = ADVERTISE_100_HALF;
+		break;
+	case SPEED_100 + DUPLEX_FULL:
+		mac->forced_speed_duplex = ADVERTISE_100_FULL;
+		break;
+	case SPEED_1000 + DUPLEX_FULL:
+		mac->autoneg = 1;
+		adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL;
+		break;
+	case SPEED_1000 + DUPLEX_HALF: /* not supported */
+	default:
+		dev_err(&adapter->pdev->dev,
+			"Unsupported Speed/Duplex configuration\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+
+static int igb_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl, ctrl_ext, rctl, status;
+	u32 wufc = adapter->wol;
+#ifdef CONFIG_PM
+	int retval = 0;
+#endif
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev)) {
+		WARN_ON(test_bit(__IGB_RESETTING, &adapter->state));
+		igb_down(adapter);
+		igb_free_irq(adapter);
+	}
+
+#ifdef CONFIG_PM
+	retval = pci_save_state(pdev);
+	if (retval)
+		return retval;
+#endif
+
+	status = rd32(E1000_STATUS);
+	if (status & E1000_STATUS_LU)
+		wufc &= ~E1000_WUFC_LNKC;
+
+	if (wufc) {
+		igb_setup_rctl(adapter);
+		igb_set_multi(netdev);
+
+		/* turn on all-multi mode if wake on multicast is enabled */
+		if (wufc & E1000_WUFC_MC) {
+			rctl = rd32(E1000_RCTL);
+			rctl |= E1000_RCTL_MPE;
+			wr32(E1000_RCTL, rctl);
+		}
+
+		ctrl = rd32(E1000_CTRL);
+		/* advertise wake from D3Cold */
+		#define E1000_CTRL_ADVD3WUC 0x00100000
+		/* phy power management enable */
+		#define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
+		ctrl |= E1000_CTRL_ADVD3WUC;
+		wr32(E1000_CTRL, ctrl);
+
+		if (adapter->hw.phy.media_type == e1000_media_type_fiber ||
+		   adapter->hw.phy.media_type ==
+					e1000_media_type_internal_serdes) {
+			/* keep the laser running in D3 */
+			ctrl_ext = rd32(E1000_CTRL_EXT);
+			ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
+			wr32(E1000_CTRL_EXT, ctrl_ext);
+		}
+
+		/* Allow time for pending master requests to run */
+		igb_disable_pcie_master(&adapter->hw);
+
+		wr32(E1000_WUC, E1000_WUC_PME_EN);
+		wr32(E1000_WUFC, wufc);
+		pci_enable_wake(pdev, PCI_D3hot, 1);
+		pci_enable_wake(pdev, PCI_D3cold, 1);
+	} else {
+		wr32(E1000_WUC, 0);
+		wr32(E1000_WUFC, 0);
+		pci_enable_wake(pdev, PCI_D3hot, 0);
+		pci_enable_wake(pdev, PCI_D3cold, 0);
+	}
+
+	igb_release_manageability(adapter);
+
+	/* make sure adapter isn't asleep if manageability is enabled */
+	if (adapter->en_mng_pt) {
+		pci_enable_wake(pdev, PCI_D3hot, 1);
+		pci_enable_wake(pdev, PCI_D3cold, 1);
+	}
+
+	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
+	 * would have already happened in close and is redundant. */
+	igb_release_hw_control(adapter);
+
+	pci_disable_device(pdev);
+
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int igb_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 err;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev,
+			"igb: Cannot enable PCI device from suspend\n");
+		return err;
+	}
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	if (netif_running(netdev)) {
+		err = igb_request_irq(adapter);
+		if (err)
+			return err;
+	}
+
+	/* e1000_power_up_phy(adapter); */
+
+	igb_reset(adapter);
+	wr32(E1000_WUS, ~0);
+
+	igb_init_manageability(adapter);
+
+	if (netif_running(netdev))
+		igb_up(adapter);
+
+	netif_device_attach(netdev);
+
+	/* let the f/w know that the h/w is now under the control of the
+	 * driver. */
+	igb_get_hw_control(adapter);
+
+	return 0;
+}
+#endif
+
+static void igb_shutdown(struct pci_dev *pdev)
+{
+	igb_suspend(pdev, PMSG_SUSPEND);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void igb_netpoll(struct net_device *netdev)
+{
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	int i;
+	int work_done = 0;
+
+	igb_irq_disable(adapter);
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		igb_clean_tx_irq(adapter, &adapter->tx_ring[i]);
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		igb_clean_rx_irq_adv(adapter, &adapter->rx_ring[i],
+				     &work_done,
+				     adapter->rx_ring[i].napi.weight);
+
+	igb_irq_enable(adapter);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+/**
+ * igb_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t igb_io_error_detected(struct pci_dev *pdev,
+					      pci_channel_state_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev))
+		igb_down(adapter);
+	pci_disable_device(pdev);
+
+	/* Request a slot slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * igb_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the igb_resume routine.
+ */
+static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (pci_enable_device(pdev)) {
+		dev_err(&pdev->dev,
+			"Cannot re-enable PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	igb_reset(adapter);
+	wr32(E1000_WUS, ~0);
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * igb_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the igb_resume routine.
+ */
+static void igb_io_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	igb_init_manageability(adapter);
+
+	if (netif_running(netdev)) {
+		if (igb_up(adapter)) {
+			dev_err(&pdev->dev, "igb_up failed after reset\n");
+			return;
+		}
+	}
+
+	netif_device_attach(netdev);
+
+	/* let the f/w know that the h/w is now under the control of the
+	 * driver. */
+	igb_get_hw_control(adapter);
+
+}
+
+/* igb_main.c */
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index 50f0c17451b1..5e5d9b527ed1 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -34,9 +34,9 @@
 	 IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \
 	 IPG_AC_AUTO_INIT)
 
-#define ipg_w32(val32,reg)	iowrite32((val32), ioaddr + (reg))
-#define ipg_w16(val16,reg)	iowrite16((val16), ioaddr + (reg))
-#define ipg_w8(val8,reg)	iowrite8((val8), ioaddr + (reg))
+#define ipg_w32(val32, reg)	iowrite32((val32), ioaddr + (reg))
+#define ipg_w16(val16, reg)	iowrite16((val16), ioaddr + (reg))
+#define ipg_w8(val8, reg)	iowrite8((val8), ioaddr + (reg))
 
 #define ipg_r32(reg)		ioread32(ioaddr + (reg))
 #define ipg_r16(reg)		ioread16(ioaddr + (reg))
@@ -51,24 +51,25 @@ enum {
 #define DRV_NAME	"ipg"
 
 MODULE_AUTHOR("IC Plus Corp. 2003");
-MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver "
-		   DrvVer);
+MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver");
 MODULE_LICENSE("GPL");
 
-//variable record -- index by leading revision/length
-//Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN
+/*
+ * Variable record -- index by leading revision/length
+ * Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN
+ */
 static unsigned short DefaultPhyParam[] = {
-	// 11/12/03 IP1000A v1-3 rev=0x40
+	/* 11/12/03 IP1000A v1-3 rev=0x40 */
 	/*--------------------------------------------------------------------------
 	(0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2,
 				 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6,
 				 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7,  9, 0x0700,
 	  --------------------------------------------------------------------------*/
-	// 12/17/03 IP1000A v1-4 rev=0x40
+	/* 12/17/03 IP1000A v1-4 rev=0x40 */
 	(0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
 	    0x0000,
 	30, 0x005e, 9, 0x0700,
-	// 01/09/04 IP1000A v1-5 rev=0x41
+	/* 01/09/04 IP1000A v1-5 rev=0x41 */
 	(0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
 	    0x0000,
 	30, 0x005e, 9, 0x0700,
@@ -188,7 +189,7 @@ static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity)
 		phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL);
 }
 
-static u16 read_phy_bit(void __iomem * ioaddr, u8 phyctrlpolarity)
+static u16 read_phy_bit(void __iomem *ioaddr, u8 phyctrlpolarity)
 {
 	u16 bit_data;
 
@@ -205,7 +206,7 @@ static u16 read_phy_bit(void __iomem * ioaddr, u8 phyctrlpolarity)
  * Read a register from the Physical Layer device located
  * on the IPG NIC, using the IPG PHYCTRL register.
  */
-static int mdio_read(struct net_device * dev, int phy_id, int phy_reg)
+static int mdio_read(struct net_device *dev, int phy_id, int phy_reg)
 {
 	void __iomem *ioaddr = ipg_ioaddr(dev);
 	/*
@@ -374,7 +375,6 @@ static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val)
 	}
 }
 
-/* Set LED_Mode JES20040127EEPROM */
 static void ipg_set_led_mode(struct net_device *dev)
 {
 	struct ipg_nic_private *sp = netdev_priv(dev);
@@ -384,19 +384,18 @@ static void ipg_set_led_mode(struct net_device *dev)
 	mode = ipg_r32(ASIC_CTRL);
 	mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED);
 
-	if ((sp->LED_Mode & 0x03) > 1)
+	if ((sp->led_mode & 0x03) > 1)
 		mode |= IPG_AC_LED_MODE_BIT_1;	/* Write Asic Control Bit 29 */
 
-	if ((sp->LED_Mode & 0x01) == 1)
+	if ((sp->led_mode & 0x01) == 1)
 		mode |= IPG_AC_LED_MODE;	/* Write Asic Control Bit 14 */
 
-	if ((sp->LED_Mode & 0x08) == 8)
+	if ((sp->led_mode & 0x08) == 8)
 		mode |= IPG_AC_LED_SPEED;	/* Write Asic Control Bit 27 */
 
 	ipg_w32(mode, ASIC_CTRL);
 }
 
-/* Set PHYSet JES20040127EEPROM */
 static void ipg_set_phy_set(struct net_device *dev)
 {
 	struct ipg_nic_private *sp = netdev_priv(dev);
@@ -405,7 +404,7 @@ static void ipg_set_phy_set(struct net_device *dev)
 
 	physet = ipg_r8(PHY_SET);
 	physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET);
-	physet |= ((sp->LED_Mode & 0x70) >> 4);
+	physet |= ((sp->led_mode & 0x70) >> 4);
 	ipg_w8(physet, PHY_SET);
 }
 
@@ -415,7 +414,7 @@ static int ipg_reset(struct net_device *dev, u32 resetflags)
 	 * register as specified by the 'resetflags' input
 	 * parameter.
 	 */
-	void __iomem *ioaddr = ipg_ioaddr(dev);	//JES20040127EEPROM:
+	void __iomem *ioaddr = ipg_ioaddr(dev);
 	unsigned int timeout_count = 0;
 
 	IPG_DEBUG_MSG("_reset\n");
@@ -430,10 +429,10 @@ static int ipg_reset(struct net_device *dev, u32 resetflags)
 		if (++timeout_count > IPG_AC_RESET_TIMEOUT)
 			return -ETIME;
 	}
-	/* Set LED Mode in Asic Control JES20040127EEPROM */
+	/* Set LED Mode in Asic Control */
 	ipg_set_led_mode(dev);
 
-	/* Set PHYSet Register Value JES20040127EEPROM */
+	/* Set PHYSet Register Value */
 	ipg_set_phy_set(dev);
 	return 0;
 }
@@ -551,7 +550,7 @@ static int ipg_config_autoneg(struct net_device *dev)
 		printk("\n");
 	} else {
 		/* Configure IPG for half duplex operation. */
-	        printk(KERN_INFO "%s: setting half duplex, "
+		printk(KERN_INFO "%s: setting half duplex, "
 		       "no TX flow control, no RX flow control.\n", dev->name);
 
 		mac_ctrl_val &= ~IPG_MC_DUPLEX_SELECT_FD &
@@ -736,7 +735,7 @@ static int ipg_get_rxbuff(struct net_device *dev, int entry)
 
 	skb = netdev_alloc_skb(dev, IPG_RXSUPPORT_SIZE + NET_IP_ALIGN);
 	if (!skb) {
-		sp->RxBuff[entry] = NULL;
+		sp->rx_buff[entry] = NULL;
 		return -ENOMEM;
 	}
 
@@ -749,7 +748,7 @@ static int ipg_get_rxbuff(struct net_device *dev, int entry)
 	skb->dev = dev;
 
 	/* Save the address of the sk_buff structure. */
-	sp->RxBuff[entry] = skb;
+	sp->rx_buff[entry] = skb;
 
 	rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
 		sp->rx_buf_sz, PCI_DMA_FROMDEVICE));
@@ -772,12 +771,12 @@ static int init_rfdlist(struct net_device *dev)
 	for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
 		struct ipg_rx *rxfd = sp->rxd + i;
 
-		if (sp->RxBuff[i]) {
+		if (sp->rx_buff[i]) {
 			pci_unmap_single(sp->pdev,
 				le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
 				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-			IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
-			sp->RxBuff[i] = NULL;
+			dev_kfree_skb_irq(sp->rx_buff[i]);
+			sp->rx_buff[i] = NULL;
 		}
 
 		/* Clear out the RFS field. */
@@ -828,9 +827,9 @@ static void init_tfdlist(struct net_device *dev)
 
 		txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
 
-		if (sp->TxBuff[i]) {
-			IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
-			sp->TxBuff[i] = NULL;
+		if (sp->tx_buff[i]) {
+			dev_kfree_skb_irq(sp->tx_buff[i]);
+			sp->tx_buff[i] = NULL;
 		}
 
 		txfd->next_desc = cpu_to_le64(sp->txd_map +
@@ -847,7 +846,7 @@ static void init_tfdlist(struct net_device *dev)
 	ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0);
 	ipg_w32(0x00000000, TFD_LIST_PTR_1);
 
-	sp->ResetCurrentTFD = 1;
+	sp->reset_current_tfd = 1;
 }
 
 /*
@@ -865,7 +864,7 @@ static void ipg_nic_txfree(struct net_device *dev)
 	dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH;
 
 	for (released = 0; released < pending; released++) {
-		struct sk_buff *skb = sp->TxBuff[dirty];
+		struct sk_buff *skb = sp->tx_buff[dirty];
 		struct ipg_tx *txfd = sp->txd + dirty;
 
 		IPG_DEBUG_MSG("TFC = %16.16lx\n", (unsigned long) txfd->tfc);
@@ -884,9 +883,9 @@ static void ipg_nic_txfree(struct net_device *dev)
 				le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
 				skb->len, PCI_DMA_TODEVICE);
 
-			IPG_DEV_KFREE_SKB(skb);
+			dev_kfree_skb_irq(skb);
 
-			sp->TxBuff[dirty] = NULL;
+			sp->tx_buff[dirty] = NULL;
 		}
 		dirty = (dirty + 1) % IPG_TFDLIST_LENGTH;
 	}
@@ -1059,7 +1058,7 @@ static int ipg_nic_rxrestore(struct net_device *dev)
 		unsigned int entry = dirty % IPG_RFDLIST_LENGTH;
 
 		/* rx_copybreak may poke hole here and there. */
-		if (sp->RxBuff[entry])
+		if (sp->rx_buff[entry])
 			continue;
 
 		/* Generate a new receive buffer to replace the
@@ -1083,22 +1082,22 @@ static int ipg_nic_rxrestore(struct net_device *dev)
 #ifdef JUMBO_FRAME
 
 /* use jumboindex and jumbosize to control jumbo frame status
-   initial status is jumboindex=-1 and jumbosize=0
-   1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done.
-   2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving
-   3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump
-                previous receiving and need to continue dumping the current one
-*/
+ * initial status is jumboindex=-1 and jumbosize=0
+ * 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done.
+ * 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving
+ * 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump
+ *               previous receiving and need to continue dumping the current one
+ */
 enum {
-	NormalPacket,
-	ErrorPacket
+	NORMAL_PACKET,
+	ERROR_PACKET
 };
 
 enum {
-	Frame_NoStart_NoEnd	= 0,
-	Frame_WithStart		= 1,
-	Frame_WithEnd		= 10,
-	Frame_WithStart_WithEnd = 11
+	FRAME_NO_START_NO_END	= 0,
+	FRAME_WITH_START		= 1,
+	FRAME_WITH_END		= 10,
+	FRAME_WITH_START_WITH_END = 11
 };
 
 inline void ipg_nic_rx_free_skb(struct net_device *dev)
@@ -1106,14 +1105,14 @@ inline void ipg_nic_rx_free_skb(struct net_device *dev)
 	struct ipg_nic_private *sp = netdev_priv(dev);
 	unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
 
-	if (sp->RxBuff[entry]) {
+	if (sp->rx_buff[entry]) {
 		struct ipg_rx *rxfd = sp->rxd + entry;
 
 		pci_unmap_single(sp->pdev,
 			le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
 			sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-		IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
-		sp->RxBuff[entry] = NULL;
+		dev_kfree_skb_irq(sp->rx_buff[entry]);
+		sp->rx_buff[entry] = NULL;
 	}
 }
 
@@ -1121,12 +1120,12 @@ inline int ipg_nic_rx_check_frame_type(struct net_device *dev)
 {
 	struct ipg_nic_private *sp = netdev_priv(dev);
 	struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH);
-	int type = Frame_NoStart_NoEnd;
+	int type = FRAME_NO_START_NO_END;
 
 	if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART)
-		type += Frame_WithStart;
+		type += FRAME_WITH_START;
 	if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND)
-		type += Frame_WithEnd;
+		type += FRAME_WITH_END;
 	return type;
 }
 
@@ -1175,43 +1174,43 @@ inline int ipg_nic_rx_check_error(struct net_device *dev)
 		 * buffer since it is erroneous and we will
 		 * not pass it to higher layer processes.
 		 */
-		if (sp->RxBuff[entry]) {
+		if (sp->rx_buff[entry]) {
 			pci_unmap_single(sp->pdev,
 				le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
 				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
-			IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
-			sp->RxBuff[entry] = NULL;
+			dev_kfree_skb_irq(sp->rx_buff[entry]);
+			sp->rx_buff[entry] = NULL;
 		}
-		return ErrorPacket;
+		return ERROR_PACKET;
 	}
-	return NormalPacket;
+	return NORMAL_PACKET;
 }
 
 static void ipg_nic_rx_with_start_and_end(struct net_device *dev,
 					  struct ipg_nic_private *sp,
 					  struct ipg_rx *rxfd, unsigned entry)
 {
-	struct SJumbo *jumbo = &sp->Jumbo;
+	struct ipg_jumbo *jumbo = &sp->jumbo;
 	struct sk_buff *skb;
 	int framelen;
 
-	if (jumbo->FoundStart) {
-		IPG_DEV_KFREE_SKB(jumbo->skb);
-		jumbo->FoundStart = 0;
-		jumbo->CurrentSize = 0;
+	if (jumbo->found_start) {
+		dev_kfree_skb_irq(jumbo->skb);
+		jumbo->found_start = 0;
+		jumbo->current_size = 0;
 		jumbo->skb = NULL;
 	}
 
-	// 1: found error, 0 no error
-	if (ipg_nic_rx_check_error(dev) != NormalPacket)
+	/* 1: found error, 0 no error */
+	if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET)
 		return;
 
-	skb = sp->RxBuff[entry];
+	skb = sp->rx_buff[entry];
 	if (!skb)
 		return;
 
-	// accept this frame and send to upper layer
+	/* accept this frame and send to upper layer */
 	framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
 	if (framelen > IPG_RXFRAG_SIZE)
 		framelen = IPG_RXFRAG_SIZE;
@@ -1221,39 +1220,39 @@ static void ipg_nic_rx_with_start_and_end(struct net_device *dev,
 	skb->ip_summed = CHECKSUM_NONE;
 	netif_rx(skb);
 	dev->last_rx = jiffies;
-	sp->RxBuff[entry] = NULL;
+	sp->rx_buff[entry] = NULL;
 }
 
 static void ipg_nic_rx_with_start(struct net_device *dev,
 				  struct ipg_nic_private *sp,
 				  struct ipg_rx *rxfd, unsigned entry)
 {
-	struct SJumbo *jumbo = &sp->Jumbo;
+	struct ipg_jumbo *jumbo = &sp->jumbo;
 	struct pci_dev *pdev = sp->pdev;
 	struct sk_buff *skb;
 
-	// 1: found error, 0 no error
-	if (ipg_nic_rx_check_error(dev) != NormalPacket)
+	/* 1: found error, 0 no error */
+	if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET)
 		return;
 
-	// accept this frame and send to upper layer
-	skb = sp->RxBuff[entry];
+	/* accept this frame and send to upper layer */
+	skb = sp->rx_buff[entry];
 	if (!skb)
 		return;
 
-	if (jumbo->FoundStart)
-		IPG_DEV_KFREE_SKB(jumbo->skb);
+	if (jumbo->found_start)
+		dev_kfree_skb_irq(jumbo->skb);
 
 	pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
 			 sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
 	skb_put(skb, IPG_RXFRAG_SIZE);
 
-	jumbo->FoundStart = 1;
-	jumbo->CurrentSize = IPG_RXFRAG_SIZE;
+	jumbo->found_start = 1;
+	jumbo->current_size = IPG_RXFRAG_SIZE;
 	jumbo->skb = skb;
 
-	sp->RxBuff[entry] = NULL;
+	sp->rx_buff[entry] = NULL;
 	dev->last_rx = jiffies;
 }
 
@@ -1261,27 +1260,27 @@ static void ipg_nic_rx_with_end(struct net_device *dev,
 				struct ipg_nic_private *sp,
 				struct ipg_rx *rxfd, unsigned entry)
 {
-	struct SJumbo *jumbo = &sp->Jumbo;
+	struct ipg_jumbo *jumbo = &sp->jumbo;
 
-	//1: found error, 0 no error
-	if (ipg_nic_rx_check_error(dev) == NormalPacket) {
-		struct sk_buff *skb = sp->RxBuff[entry];
+	/* 1: found error, 0 no error */
+	if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) {
+		struct sk_buff *skb = sp->rx_buff[entry];
 
 		if (!skb)
 			return;
 
-		if (jumbo->FoundStart) {
+		if (jumbo->found_start) {
 			int framelen, endframelen;
 
 			framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
 
-			endframeLen = framelen - jumbo->CurrentSize;
+			endframeLen = framelen - jumbo->current_size;
 			/*
 			if (framelen > IPG_RXFRAG_SIZE)
 				framelen=IPG_RXFRAG_SIZE;
 			 */
 			if (framelen > IPG_RXSUPPORT_SIZE)
-				IPG_DEV_KFREE_SKB(jumbo->skb);
+				dev_kfree_skb_irq(jumbo->skb);
 			else {
 				memcpy(skb_put(jumbo->skb, endframeLen),
 				       skb->data, endframeLen);
@@ -1295,15 +1294,15 @@ static void ipg_nic_rx_with_end(struct net_device *dev,
 		}
 
 		dev->last_rx = jiffies;
-		jumbo->FoundStart = 0;
-		jumbo->CurrentSize = 0;
+		jumbo->found_start = 0;
+		jumbo->current_size = 0;
 		jumbo->skb = NULL;
 
 		ipg_nic_rx_free_skb(dev);
 	} else {
-		IPG_DEV_KFREE_SKB(jumbo->skb);
-		jumbo->FoundStart = 0;
-		jumbo->CurrentSize = 0;
+		dev_kfree_skb_irq(jumbo->skb);
+		jumbo->found_start = 0;
+		jumbo->current_size = 0;
 		jumbo->skb = NULL;
 	}
 }
@@ -1312,16 +1311,16 @@ static void ipg_nic_rx_no_start_no_end(struct net_device *dev,
 				       struct ipg_nic_private *sp,
 				       struct ipg_rx *rxfd, unsigned entry)
 {
-	struct SJumbo *jumbo = &sp->Jumbo;
+	struct ipg_jumbo *jumbo = &sp->jumbo;
 
-	//1: found error, 0 no error
-	if (ipg_nic_rx_check_error(dev) == NormalPacket) {
-		struct sk_buff *skb = sp->RxBuff[entry];
+	/* 1: found error, 0 no error */
+	if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) {
+		struct sk_buff *skb = sp->rx_buff[entry];
 
 		if (skb) {
-			if (jumbo->FoundStart) {
-				jumbo->CurrentSize += IPG_RXFRAG_SIZE;
-				if (jumbo->CurrentSize <= IPG_RXSUPPORT_SIZE) {
+			if (jumbo->found_start) {
+				jumbo->current_size += IPG_RXFRAG_SIZE;
+				if (jumbo->current_size <= IPG_RXSUPPORT_SIZE) {
 					memcpy(skb_put(jumbo->skb,
 						       IPG_RXFRAG_SIZE),
 					       skb->data, IPG_RXFRAG_SIZE);
@@ -1331,9 +1330,9 @@ static void ipg_nic_rx_no_start_no_end(struct net_device *dev,
 			ipg_nic_rx_free_skb(dev);
 		}
 	} else {
-		IPG_DEV_KFREE_SKB(jumbo->skb);
-		jumbo->FoundStart = 0;
-		jumbo->CurrentSize = 0;
+		dev_kfree_skb_irq(jumbo->skb);
+		jumbo->found_start = 0;
+		jumbo->current_size = 0;
 		jumbo->skb = NULL;
 	}
 }
@@ -1355,16 +1354,16 @@ static int ipg_nic_rx(struct net_device *dev)
 			break;
 
 		switch (ipg_nic_rx_check_frame_type(dev)) {
-		case Frame_WithStart_WithEnd:
+		case FRAME_WITH_START_WITH_END:
 			ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry);
 			break;
-		case Frame_WithStart:
+		case FRAME_WITH_START:
 			ipg_nic_rx_with_start(dev, tp, rxfd, entry);
 			break;
-		case Frame_WithEnd:
+		case FRAME_WITH_END:
 			ipg_nic_rx_with_end(dev, tp, rxfd, entry);
 			break;
-		case Frame_NoStart_NoEnd:
+		case FRAME_NO_START_NO_END:
 			ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry);
 			break;
 		}
@@ -1403,7 +1402,7 @@ static int ipg_nic_rx(struct net_device *dev)
 
 	for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
 		unsigned int entry = curr % IPG_RFDLIST_LENGTH;
-		struct sk_buff *skb = sp->RxBuff[entry];
+		struct sk_buff *skb = sp->rx_buff[entry];
 		unsigned int framelen;
 
 		rxfd = sp->rxd + entry;
@@ -1472,7 +1471,7 @@ static int ipg_nic_rx(struct net_device *dev)
 					le64_to_cpu(info) & ~IPG_RFI_FRAGLEN,
 					sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
-				IPG_DEV_KFREE_SKB(skb);
+				dev_kfree_skb_irq(skb);
 			}
 		} else {
 
@@ -1484,35 +1483,13 @@ static int ipg_nic_rx(struct net_device *dev)
 			/* Set the buffer's protocol field to Ethernet. */
 			skb->protocol = eth_type_trans(skb, dev);
 
-			/* If the frame contains an IP/TCP/UDP frame,
-			 * determine if upper layer must check IP/TCP/UDP
-			 * checksums.
-			 *
-			 * NOTE: DO NOT RELY ON THE TCP/UDP CHECKSUM
-			 *       VERIFICATION FOR SILICON REVISIONS B3
-			 *       AND EARLIER!
-			 *
-			 if ((le64_to_cpu(rxfd->rfs &
-			     (IPG_RFS_TCPDETECTED | IPG_RFS_UDPDETECTED |
-			      IPG_RFS_IPDETECTED))) &&
-			    !(le64_to_cpu(rxfd->rfs &
-			      (IPG_RFS_TCPERROR | IPG_RFS_UDPERROR |
-			       IPG_RFS_IPERROR)))) {
-				 * Indicate IP checksums were performed
-				 * by the IPG.
-				 *
-				skb->ip_summed = CHECKSUM_UNNECESSARY;
-			 } else
+			/* The IPG encountered an error with (or
+			 * there were no) IP/TCP/UDP checksums.
+			 * This may or may not indicate an invalid
+			 * IP/TCP/UDP frame was received. Let the
+			 * upper layer decide.
 			 */
-			 {
-				/* The IPG encountered an error with (or
-				 * there were no) IP/TCP/UDP checksums.
-				 * This may or may not indicate an invalid
-				 * IP/TCP/UDP frame was received. Let the
-				 * upper layer decide.
-				 */
-				skb->ip_summed = CHECKSUM_NONE;
-			}
+			skb->ip_summed = CHECKSUM_NONE;
 
 			/* Hand off frame for higher layer processing.
 			 * The function netif_rx() releases the sk_buff
@@ -1527,7 +1504,7 @@ static int ipg_nic_rx(struct net_device *dev)
 		}
 
 		/* Assure RX buffer is not reused by IPG. */
-		sp->RxBuff[entry] = NULL;
+		sp->rx_buff[entry] = NULL;
 	}
 
 	/*
@@ -1561,15 +1538,15 @@ static int ipg_nic_rx(struct net_device *dev)
 		 * buffer since it is erroneous and we will
 		 * not pass it to higher layer processes.
 		 */
-		if (sp->RxBuff[entry]) {
+		if (sp->rx_buff[entry]) {
 			pci_unmap_single(sp->pdev,
 				le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
 				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-			IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+			dev_kfree_skb_irq(sp->rx_buff[entry]);
 		}
 
 		/* Assure RX buffer is not reused by IPG. */
-		sp->RxBuff[entry] = NULL;
+		sp->rx_buff[entry] = NULL;
 	}
 
 	sp->rx_current = curr;
@@ -1735,11 +1712,11 @@ static void ipg_rx_clear(struct ipg_nic_private *sp)
 	unsigned int i;
 
 	for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
-		if (sp->RxBuff[i]) {
+		if (sp->rx_buff[i]) {
 			struct ipg_rx *rxfd = sp->rxd + i;
 
-			IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
-			sp->RxBuff[i] = NULL;
+			dev_kfree_skb_irq(sp->rx_buff[i]);
+			sp->rx_buff[i] = NULL;
 			pci_unmap_single(sp->pdev,
 				le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
 				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
@@ -1752,16 +1729,16 @@ static void ipg_tx_clear(struct ipg_nic_private *sp)
 	unsigned int i;
 
 	for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
-		if (sp->TxBuff[i]) {
+		if (sp->tx_buff[i]) {
 			struct ipg_tx *txfd = sp->txd + i;
 
 			pci_unmap_single(sp->pdev,
 				le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
-				sp->TxBuff[i]->len, PCI_DMA_TODEVICE);
+				sp->tx_buff[i]->len, PCI_DMA_TODEVICE);
 
-			IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
+			dev_kfree_skb_irq(sp->tx_buff[i]);
 
-			sp->TxBuff[i] = NULL;
+			sp->tx_buff[i] = NULL;
 		}
 	}
 }
@@ -1832,9 +1809,9 @@ static int ipg_nic_open(struct net_device *dev)
 
 #ifdef JUMBO_FRAME
 	/* initialize JUMBO Frame control variable */
-	sp->Jumbo.FoundStart = 0;
-	sp->Jumbo.CurrentSize = 0;
-	sp->Jumbo.skb = 0;
+	sp->jumbo.found_start = 0;
+	sp->jumbo.current_size = 0;
+	sp->jumbo.skb = 0;
 	dev->mtu = IPG_TXFRAG_SIZE;
 #endif
 
@@ -1909,14 +1886,14 @@ static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (sp->tenmbpsmode)
 		netif_stop_queue(dev);
 
-	if (sp->ResetCurrentTFD) {
-		sp->ResetCurrentTFD = 0;
+	if (sp->reset_current_tfd) {
+		sp->reset_current_tfd = 0;
 		entry = 0;
 	}
 
 	txfd = sp->txd + entry;
 
-	sp->TxBuff[entry] = skb;
+	sp->tx_buff[entry] = skb;
 
 	/* Clear all TFC fields, except TFDDONE. */
 	txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
@@ -2029,7 +2006,6 @@ static void ipg_set_phy_default_param(unsigned char rev,
 	}
 }
 
-/* JES20040127EEPROM */
 static int read_eeprom(struct net_device *dev, int eep_addr)
 {
 	void __iomem *ioaddr = ipg_ioaddr(dev);
@@ -2096,9 +2072,9 @@ static int ipg_hw_init(struct net_device *dev)
 	unsigned int i;
 	int rc;
 
-	/* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */
+	/* Read/Write and Reset EEPROM Value */
 	/* Read LED Mode Configuration from EEPROM */
-	sp->LED_Mode = read_eeprom(dev, 6);
+	sp->led_mode = read_eeprom(dev, 6);
 
 	/* Reset all functions within the IPG. Do not assert
 	 * RST_OUT as not compatible with some PHYs.
@@ -2202,7 +2178,7 @@ static struct ethtool_ops ipg_ethtool_ops = {
 	.nway_reset   = ipg_nway_reset,
 };
 
-static void ipg_remove(struct pci_dev *pdev)
+static void __devexit ipg_remove(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct ipg_nic_private *sp = netdev_priv(dev);
diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h
index d5d092c9d0af..cda53887d4db 100644
--- a/drivers/net/ipg.h
+++ b/drivers/net/ipg.h
@@ -1,20 +1,8 @@
 /*
- *
- * ipg.h
- *
  * Include file for Gigabit Ethernet device driver for Network
  * Interface Cards (NICs) utilizing the Tamarack Microelectronics
  * Inc. IPG Gigabit or Triple Speed Ethernet Media Access
  * Controller.
- *
- * Craig Rich
- * Sundance Technology, Inc.
- * 1485 Saratoga Avenue
- * Suite 200
- * San Jose, CA 95129
- * 408 873 4117
- * www.sundanceti.com
- * craig_rich@sundanceti.com
  */
 #ifndef __LINUX_IPG_H
 #define __LINUX_IPG_H
@@ -35,11 +23,6 @@
 #include <linux/skbuff.h>
 #include <linux/version.h>
 #include <asm/bitops.h>
-/*#include <asm/spinlock.h>*/
-
-#define DrvVer "2.09d"
-
-#define IPG_DEV_KFREE_SKB(skb) dev_kfree_skb_irq(skb)
 
 /*
  *	Constants
@@ -68,7 +51,7 @@
 /* I/O register offsets. */
 enum ipg_regs {
 	DMA_CTRL		= 0x00,
-	RX_DMA_STATUS		= 0x08, // Unused + reserved
+	RX_DMA_STATUS		= 0x08, /* Unused + reserved */
 	TFD_LIST_PTR_0		= 0x10,
 	TFD_LIST_PTR_1		= 0x14,
 	TX_DMA_BURST_THRESH	= 0x18,
@@ -81,22 +64,22 @@ enum ipg_regs {
 	RX_DMA_POLL_PERIOD	= 0x26,
 	DEBUG_CTRL		= 0x2c,
 	ASIC_CTRL		= 0x30,
-	FIFO_CTRL		= 0x38, // Unused
+	FIFO_CTRL		= 0x38, /* Unused */
 	FLOW_OFF_THRESH		= 0x3c,
 	FLOW_ON_THRESH		= 0x3e,
 	EEPROM_DATA		= 0x48,
 	EEPROM_CTRL		= 0x4a,
-	EXPROM_ADDR		= 0x4c, // Unused
-	EXPROM_DATA		= 0x50, // Unused
-	WAKE_EVENT		= 0x51, // Unused
-	COUNTDOWN		= 0x54, // Unused
+	EXPROM_ADDR		= 0x4c, /* Unused */
+	EXPROM_DATA		= 0x50, /* Unused */
+	WAKE_EVENT		= 0x51, /* Unused */
+	COUNTDOWN		= 0x54, /* Unused */
 	INT_STATUS_ACK		= 0x5a,
 	INT_ENABLE		= 0x5c,
-	INT_STATUS		= 0x5e, // Unused
+	INT_STATUS		= 0x5e, /* Unused */
 	TX_STATUS		= 0x60,
 	MAC_CTRL		= 0x6c,
-	VLAN_TAG		= 0x70, // Unused
-	PHY_SET			= 0x75,	// JES20040127EEPROM
+	VLAN_TAG		= 0x70, /* Unused */
+	PHY_SET			= 0x75,
 	PHY_CTRL		= 0x76,
 	STATION_ADDRESS_0	= 0x78,
 	STATION_ADDRESS_1	= 0x7a,
@@ -107,11 +90,11 @@ enum ipg_regs {
 	HASHTABLE_1		= 0x90,
 	RMON_STATISTICS_MASK	= 0x98,
 	STATISTICS_MASK		= 0x9c,
-	RX_JUMBO_FRAMES		= 0xbc, // Unused
-	TCP_CHECKSUM_ERRORS	= 0xc0, // Unused
-	IP_CHECKSUM_ERRORS	= 0xc2, // Unused
-	UDP_CHECKSUM_ERRORS	= 0xc4, // Unused
-	TX_JUMBO_FRAMES		= 0xf4  // Unused
+	RX_JUMBO_FRAMES		= 0xbc, /* Unused */
+	TCP_CHECKSUM_ERRORS	= 0xc0, /* Unused */
+	IP_CHECKSUM_ERRORS	= 0xc2, /* Unused */
+	UDP_CHECKSUM_ERRORS	= 0xc4, /* Unused */
+	TX_JUMBO_FRAMES		= 0xf4  /* Unused */
 };
 
 /* Ethernet MIB statistic register offsets. */
@@ -329,7 +312,7 @@ enum ipg_regs {
 #define IPG_RM_RECEIVEMULTICASTHASH     0x10
 #define IPG_RM_RECEIVEIPMULTICAST       0x20
 
-/* PhySet JES20040127EEPROM*/
+/* PhySet */
 #define IPG_PS_MEM_LENB9B               0x01
 #define IPG_PS_MEM_LEN9                 0x02
 #define IPG_PS_NON_COMPDET              0x04
@@ -386,8 +369,8 @@ enum ipg_regs {
 #define IPG_AC_RST_OUT                  0x01000000
 #define IPG_AC_INT_REQUEST              0x02000000
 #define IPG_AC_RESET_BUSY               0x04000000
-#define IPG_AC_LED_SPEED                0x08000000	//JES20040127EEPROM
-#define IPG_AC_LED_MODE_BIT_1           0x20000000	//JES20040127EEPROM
+#define IPG_AC_LED_SPEED                0x08000000
+#define IPG_AC_LED_MODE_BIT_1           0x20000000
 
 /* EepromCtrl */
 #define IPG_EC_RSVD_MASK                0x83FF
@@ -490,38 +473,34 @@ enum ipg_regs {
  *	Tune
  */
 
-/* Miscellaneous Constants. */
-#define   TRUE  1
-#define   FALSE 0
-
 /* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */
-#define         IPG_APPEND_FCS_ON_TX         TRUE
+#define         IPG_APPEND_FCS_ON_TX         1
 
 /* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */
-#define         IPG_STRIP_FCS_ON_RX          TRUE
+#define         IPG_STRIP_FCS_ON_RX          1
 
 /* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with
  * Ethernet errors.
  */
-#define         IPG_DROP_ON_RX_ETH_ERRORS    TRUE
+#define         IPG_DROP_ON_RX_ETH_ERRORS    1
 
 /* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually
  * (via TFC).
  */
-#define		IPG_INSERT_MANUAL_VLAN_TAG   FALSE
+#define		IPG_INSERT_MANUAL_VLAN_TAG   0
 
 /* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */
-#define         IPG_ADD_IPCHECKSUM_ON_TX     FALSE
+#define         IPG_ADD_IPCHECKSUM_ON_TX     0
 
 /* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX.
  * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
  */
-#define         IPG_ADD_TCPCHECKSUM_ON_TX    FALSE
+#define         IPG_ADD_TCPCHECKSUM_ON_TX    0
 
 /* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX.
  * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
  */
-#define         IPG_ADD_UDPCHECKSUM_ON_TX    FALSE
+#define         IPG_ADD_UDPCHECKSUM_ON_TX    0
 
 /* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx
  * constants as desired.
@@ -611,7 +590,7 @@ enum ipg_regs {
  * Define larger if expecting jumbo frames.
  */
 #ifdef JUMBO_FRAME
-//IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash
+/* IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash */
 #define		IPG_TXFRAG_SIZE		JUMBO_FRAME_SIZE
 #endif
 
@@ -619,7 +598,7 @@ enum ipg_regs {
  * Define larger if expecting jumbo frames.
  */
 #ifdef JUMBO_FRAME
-//4088=4096-8
+/* 4088 = 4096 - 8 */
 #define		IPG_RXFRAG_SIZE		__IPG_RXFRAG_SIZE
 #define     IPG_RXSUPPORT_SIZE   IPG_MAX_RXFRAME_SIZE
 #else
@@ -647,9 +626,9 @@ enum ipg_regs {
 #define		IPG_MINUSEDRFDSTOFREE	0x80
 
 /* specify the jumbo frame maximum size
- * per unit is 0x600 (the RxBuffer size that one RFD can carry)
+ * per unit is 0x600 (the rx_buffer size that one RFD can carry)
  */
-#define     MAX_JUMBOSIZE	        0x8	// max is 12K
+#define     MAX_JUMBOSIZE	        0x8	/* max is 12K */
 
 /* Key register values loaded at driver start up. */
 
@@ -753,8 +732,7 @@ enum ipg_regs {
  * Miscellaneous macros.
  */
 
-/* Marco for printing debug statements.
-#  define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " ## args) */
+/* Marco for printing debug statements. */
 #ifdef IPG_DEBUG
 #  define IPG_DEBUG_MSG(args...)
 #  define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " args)
@@ -789,11 +767,12 @@ struct ipg_rx {
 	__le64 frag_info;
 };
 
-struct SJumbo {
-	int FoundStart;
-	int CurrentSize;
+struct ipg_jumbo {
+	int found_start;
+	int current_size;
 	struct sk_buff *skb;
 };
+
 /* Structure of IPG NIC specific data. */
 struct ipg_nic_private {
 	void __iomem *ioaddr;
@@ -801,15 +780,14 @@ struct ipg_nic_private {
 	struct ipg_rx *rxd;
 	dma_addr_t txd_map;
 	dma_addr_t rxd_map;
-	struct sk_buff *TxBuff[IPG_TFDLIST_LENGTH];
-	struct sk_buff *RxBuff[IPG_RFDLIST_LENGTH];
+	struct sk_buff *tx_buff[IPG_TFDLIST_LENGTH];
+	struct sk_buff *rx_buff[IPG_RFDLIST_LENGTH];
 	unsigned int tx_current;
 	unsigned int tx_dirty;
 	unsigned int rx_current;
 	unsigned int rx_dirty;
-// Add by Grace 2005/05/19
 #ifdef JUMBO_FRAME
-	struct SJumbo Jumbo;
+	struct ipg_jumbo jumbo;
 #endif
 	unsigned int rx_buf_sz;
 	struct pci_dev *pdev;
@@ -818,13 +796,12 @@ struct ipg_nic_private {
 	spinlock_t lock;
 	int tenmbpsmode;
 
-	/*Jesse20040128EEPROM_VALUE */
-	u16 LED_Mode;
+	u16 led_mode;
 	u16 station_addr[3];	/* Station Address in EEPROM Reg 0x10..0x12 */
 
 	struct mutex		mii_mutex;
 	struct mii_if_info	mii_if;
-	int ResetCurrentTFD;
+	int reset_current_tfd;
 #ifdef IPG_DEBUG
 	int RFDlistendCount;
 	int RFDListCheckedCount;
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 65806956728a..ce816ba9c40d 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -190,147 +190,6 @@ config KS959_DONGLE
 	  To compile it as a module, choose M here: the module will be called
 	  ks959-sir.
 
-comment "Old SIR device drivers"
-
-config IRPORT_SIR
-	tristate "IrPORT (IrDA serial driver)"
-	depends on IRDA && BROKEN_ON_SMP
-	---help---
-	  Say Y here if you want to build support for the IrPORT IrDA device
-	  driver.  To compile it as a module, choose M here: the module will be
-	  called irport. IrPORT can be used instead of IrTTY and sometimes
-	  this can be better.  One example is if your IrDA port does not
-	  have echo-canceling, which will work OK with IrPORT since this
-	  driver is working in half-duplex mode only.  You don't need to use
-	  irattach with IrPORT, but you just insert it the same way as FIR
-	  drivers (insmod irport io=0x3e8 irq=11).  Notice that IrPORT is a
-	  SIR device driver which means that speed is limited to 115200 bps.
-
-	  If unsure, say Y.
-
-comment "Old Serial dongle support"
-
-config DONGLE_OLD
-	bool "Old Serial dongle support"
-	depends on IRPORT_SIR && BROKEN_ON_SMP
-	help
-	  Say Y here if you have an infrared device that connects to your
-	  computer's serial port. These devices are called dongles. Then say Y
-	  or M to the driver for your particular dongle below.
-
-	  Note that the answer to this question won't directly affect the
-	  kernel: saying N will just cause the configurator to skip all
-	  the questions about serial dongles.
-
-config ESI_DONGLE_OLD
-	tristate "ESI JetEye PC dongle"
-	depends on DONGLE_OLD && IRDA
-	help
-	  Say Y here if you want to build support for the Extended Systems
-	  JetEye PC dongle.  To compile it as a module, choose M here.  The ESI
-	  dongle attaches to the normal 9-pin serial port connector, and can
-	  currently only be used by IrTTY.  To activate support for ESI
-	  dongles you will have to start irattach like this:
-	  "irattach -d esi".
-
-config ACTISYS_DONGLE_OLD
-	tristate "ACTiSYS IR-220L and IR220L+ dongle"
-	depends on DONGLE_OLD && IRDA
-	help
-	  Say Y here if you want to build support for the ACTiSYS IR-220L and
-	  IR220L+ dongles.  To compile it as a module, choose M here.  The
-	  ACTiSYS dongles attaches to the normal 9-pin serial port connector,
-	  and can currently only be used by IrTTY.  To activate support for
-	  ACTiSYS dongles you will have to start irattach like this:
-	  "irattach -d actisys" or "irattach -d actisys+".
-
-config TEKRAM_DONGLE_OLD
-	tristate "Tekram IrMate 210B dongle"
-	depends on DONGLE_OLD && IRDA
-	help
-	  Say Y here if you want to build support for the Tekram IrMate 210B
-	  dongle.  To compile it as a module, choose M here.  The Tekram dongle
-	  attaches to the normal 9-pin serial port connector, and can
-	  currently only be used by IrTTY.  To activate support for Tekram
-	  dongles you will have to start irattach like this:
-	  "irattach -d tekram".
-
-config GIRBIL_DONGLE_OLD
-	tristate "Greenwich GIrBIL dongle"
-	depends on DONGLE_OLD && IRDA
-	help
-	  Say Y here if you want to build support for the Greenwich GIrBIL
-	  dongle.  To compile it as a module, choose M here.  The Greenwich
-	  dongle attaches to the normal 9-pin serial port connector, and can
-	  currently only be used by IrTTY.  To activate support for Greenwich
-	  dongles you will have to insert "irattach -d girbil" in the
-	  /etc/irda/drivers script.
-
-config LITELINK_DONGLE_OLD
-	tristate "Parallax LiteLink dongle"
-	depends on DONGLE_OLD && IRDA
-	help
-	  Say Y here if you want to build support for the Parallax Litelink
-	  dongle.  To compile it as a module, choose M here.  The Parallax
-	  dongle attaches to the normal 9-pin serial port connector, and can
-	  currently only be used by IrTTY.  To activate support for Parallax
-	  dongles you will have to start irattach like this:
-	  "irattach -d litelink".
-
-config MCP2120_DONGLE_OLD
-	tristate "Microchip MCP2120"
-	depends on DONGLE_OLD && IRDA
-	help
-	  Say Y here if you want to build support for the Microchip MCP2120
-	  dongle.  To compile it as a module, choose M here.  The MCP2120 dongle
-	  attaches to the normal 9-pin serial port connector, and can
-	  currently only be used by IrTTY.  To activate support for MCP2120
-	  dongles you will have to insert "irattach -d mcp2120" in the
-	  /etc/irda/drivers script.
-
-	  You must build this dongle yourself.  For more information see:
-	  <http://www.eyetap.org/~tangf/irda_sir_linux.html>
-
-config OLD_BELKIN_DONGLE_OLD
-	tristate "Old Belkin dongle"
-	depends on DONGLE_OLD && IRDA
-	help
-	  Say Y here if you want to build support for the Adaptec Airport 1000
-	  and 2000 dongles.  To compile it as a module, choose M here: the module
-	  will be called old_belkin.  Some information is contained in the
-	  comments at the top of <file:drivers/net/irda/old_belkin.c>.
-
-config ACT200L_DONGLE_OLD
-	tristate "ACTiSYS IR-200L dongle (EXPERIMENTAL)"
-	depends on DONGLE_OLD && EXPERIMENTAL && IRDA
-	help
-	  Say Y here if you want to build support for the ACTiSYS IR-200L
-	  dongle.  To compile it as a module, choose M here.  The ACTiSYS
-	  IR-200L dongle attaches to the normal 9-pin serial port connector,
-	  and can currently only be used by IrTTY. To activate support for
-	  ACTiSYS IR-200L dongles you will have to start irattach like this:
-	  "irattach -d act200l".
-
-config MA600_DONGLE_OLD
-	tristate "Mobile Action MA600 dongle (EXPERIMENTAL)"
-	depends on DONGLE_OLD && EXPERIMENTAL && IRDA
-	---help---
-	  Say Y here if you want to build support for the Mobile Action MA600
-	  dongle.  To compile it as a module, choose M here. The MA600 dongle
-	  attaches to the normal 9-pin serial port connector, and can
-	  currently only be tested on IrCOMM.  To activate support for MA600
-	  dongles you will have to insert "irattach -d ma600" in the
-	  /etc/irda/drivers script.  Note: irutils 0.9.15 requires no
-	  modification. irutils 0.9.9 needs modification. For more
-	  information, download the following tar gzip file.
-
-	  There is a pre-compiled module on
-	  <http://engsvr.ust.hk/~eetwl95/ma600.html>
-
-config EP7211_IR
-	tristate "EP7211 I/R support"
-	depends on DONGLE_OLD && ARCH_EP7211 && IRDA
-
 comment "FIR device drivers"
 
 config USB_IRDA
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index fefbb5909081..5d20fde32a24 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -5,8 +5,6 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-# Old SIR drivers 
-obj-$(CONFIG_IRPORT_SIR)	+= 		irport.o
 # FIR drivers
 obj-$(CONFIG_USB_IRDA)		+= irda-usb.o
 obj-$(CONFIG_SIGMATEL_FIR)	+= stir4200.o
@@ -20,21 +18,10 @@ obj-$(CONFIG_VLSI_FIR)		+= vlsi_ir.o
 obj-$(CONFIG_VIA_FIR)		+= via-ircc.o
 obj-$(CONFIG_PXA_FICP)	        += pxaficp_ir.o
 obj-$(CONFIG_MCS_FIR)	        += mcs7780.o
-# Old dongle drivers for old SIR drivers
-obj-$(CONFIG_ESI_DONGLE_OLD)		+= esi.o
-obj-$(CONFIG_TEKRAM_DONGLE_OLD)	+= tekram.o
-obj-$(CONFIG_ACTISYS_DONGLE_OLD)	+= actisys.o
-obj-$(CONFIG_GIRBIL_DONGLE_OLD)	+= girbil.o
-obj-$(CONFIG_LITELINK_DONGLE_OLD)	+= litelink.o
-obj-$(CONFIG_OLD_BELKIN_DONGLE_OLD)	+= old_belkin.o
-obj-$(CONFIG_MCP2120_DONGLE_OLD)	+= mcp2120.o
-obj-$(CONFIG_ACT200L_DONGLE_OLD)	+= act200l.o
-obj-$(CONFIG_MA600_DONGLE_OLD)	+= ma600.o
-obj-$(CONFIG_EP7211_IR)		+= ep7211_ir.o
 obj-$(CONFIG_AU1000_FIR)	+= au1k_ir.o
-# New SIR drivers
+# SIR drivers
 obj-$(CONFIG_IRTTY_SIR)		+= irtty-sir.o	sir-dev.o
-# New dongles drivers for new SIR drivers
+# dongle drivers for SIR drivers
 obj-$(CONFIG_ESI_DONGLE)	+= esi-sir.o
 obj-$(CONFIG_TEKRAM_DONGLE)	+= tekram-sir.o
 obj-$(CONFIG_ACTISYS_DONGLE)	+= actisys-sir.o
diff --git a/drivers/net/irda/act200l.c b/drivers/net/irda/act200l.c
deleted file mode 100644
index 756cd44e857a..000000000000
--- a/drivers/net/irda/act200l.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*********************************************************************
- *
- * Filename:      act200l.c
- * Version:       0.8
- * Description:   Implementation for the ACTiSYS ACT-IR200L dongle
- * Status:        Experimental.
- * Author:        SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>
- * Created at:    Fri Aug  3 17:35:42 2001
- * Modified at:   Fri Aug 17 10:22:40 2001
- * Modified by:   SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>
- *
- *     Copyright (c) 2001 SHIMIZU Takuya, 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.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-static int  act200l_reset(struct irda_task *task);
-static void act200l_open(dongle_t *self, struct qos_info *qos);
-static void act200l_close(dongle_t *self);
-static int  act200l_change_speed(struct irda_task *task);
-
-/* Regsiter 0: Control register #1 */
-#define ACT200L_REG0    0x00
-#define ACT200L_TXEN    0x01 /* Enable transmitter */
-#define ACT200L_RXEN    0x02 /* Enable receiver */
-
-/* Register 1: Control register #2 */
-#define ACT200L_REG1    0x10
-#define ACT200L_LODB    0x01 /* Load new baud rate count value */
-#define ACT200L_WIDE    0x04 /* Expand the maximum allowable pulse */
-
-/* Register 4: Output Power register */
-#define ACT200L_REG4    0x40
-#define ACT200L_OP0     0x01 /* Enable LED1C output */
-#define ACT200L_OP1     0x02 /* Enable LED2C output */
-#define ACT200L_BLKR    0x04
-
-/* Register 5: Receive Mode register */
-#define ACT200L_REG5    0x50
-#define ACT200L_RWIDL   0x01 /* fixed 1.6us pulse mode */
-
-/* Register 6: Receive Sensitivity register #1 */
-#define ACT200L_REG6    0x60
-#define ACT200L_RS0     0x01 /* receive threshold bit 0 */
-#define ACT200L_RS1     0x02 /* receive threshold bit 1 */
-
-/* Register 7: Receive Sensitivity register #2 */
-#define ACT200L_REG7    0x70
-#define ACT200L_ENPOS   0x04 /* Ignore the falling edge */
-
-/* Register 8,9: Baud Rate Dvider register #1,#2 */
-#define ACT200L_REG8    0x80
-#define ACT200L_REG9    0x90
-
-#define ACT200L_2400    0x5f
-#define ACT200L_9600    0x17
-#define ACT200L_19200   0x0b
-#define ACT200L_38400   0x05
-#define ACT200L_57600   0x03
-#define ACT200L_115200  0x01
-
-/* Register 13: Control register #3 */
-#define ACT200L_REG13   0xd0
-#define ACT200L_SHDW    0x01 /* Enable access to shadow registers */
-
-/* Register 15: Status register */
-#define ACT200L_REG15   0xf0
-
-/* Register 21: Control register #4 */
-#define ACT200L_REG21   0x50
-#define ACT200L_EXCK    0x02 /* Disable clock output driver */
-#define ACT200L_OSCL    0x04 /* oscillator in low power, medium accuracy mode */
-
-static struct dongle_reg dongle = {
-	.type = IRDA_ACT200L_DONGLE,
-	.open = act200l_open,
-	.close = act200l_close,
-	.reset = act200l_reset,
-	.change_speed = act200l_change_speed,
-	.owner = THIS_MODULE,
-};
-
-static int __init act200l_init(void)
-{
-	return irda_device_register_dongle(&dongle);
-}
-
-static void __exit act200l_cleanup(void)
-{
-	irda_device_unregister_dongle(&dongle);
-}
-
-static void act200l_open(dongle_t *self, struct qos_info *qos)
-{
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
-
-	/* Power on the dongle */
-	self->set_dtr_rts(self->dev, TRUE, TRUE);
-
-	/* Set the speeds we can accept */
-	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-	qos->min_turn_time.bits = 0x03;
-}
-
-static void act200l_close(dongle_t *self)
-{
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
-
-	/* Power off the dongle */
-	self->set_dtr_rts(self->dev, FALSE, FALSE);
-}
-
-/*
- * Function act200l_change_speed (dev, speed)
- *
- *    Set the speed for the ACTiSYS ACT-IR200L type dongle.
- *
- */
-static int act200l_change_speed(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u32 speed = (__u32) task->param;
-	__u8 control[3];
-	int ret = 0;
-
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
-
-	self->speed_task = task;
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-		if (irda_task_execute(self, act200l_reset, NULL, task,
-				(void *) speed))
-		{
-			/* Dongle need more time to reset */
-			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
-
-			/* Give reset 1 sec to finish */
-			ret = msecs_to_jiffies(1000);
-		}
-		break;
-	case IRDA_TASK_CHILD_WAIT:
-		IRDA_WARNING("%s(), resetting dongle timed out!\n",
-			     __FUNCTION__);
-		ret = -1;
-		break;
-	case IRDA_TASK_CHILD_DONE:
-		/* Clear DTR and set RTS to enter command mode */
-		self->set_dtr_rts(self->dev, FALSE, TRUE);
-
-		switch (speed) {
-		case 9600:
-		default:
-			control[0] = ACT200L_REG8 |  (ACT200L_9600       & 0x0f);
-			control[1] = ACT200L_REG9 | ((ACT200L_9600 >> 4) & 0x0f);
-			break;
-		case 19200:
-			control[0] = ACT200L_REG8 |  (ACT200L_19200       & 0x0f);
-			control[1] = ACT200L_REG9 | ((ACT200L_19200 >> 4) & 0x0f);
-			break;
-		case 38400:
-			control[0] = ACT200L_REG8 |  (ACT200L_38400       & 0x0f);
-			control[1] = ACT200L_REG9 | ((ACT200L_38400 >> 4) & 0x0f);
-			break;
-		case 57600:
-			control[0] = ACT200L_REG8 |  (ACT200L_57600       & 0x0f);
-			control[1] = ACT200L_REG9 | ((ACT200L_57600 >> 4) & 0x0f);
-			break;
-		case 115200:
-			control[0] = ACT200L_REG8 |  (ACT200L_115200       & 0x0f);
-			control[1] = ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f);
-			break;
-		}
-		control[2] = ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE;
-
-		/* Write control bytes */
-		self->write(self->dev, control, 3);
-		irda_task_next_state(task, IRDA_TASK_WAIT);
-		ret = msecs_to_jiffies(5);
-		break;
-	case IRDA_TASK_WAIT:
-		/* Go back to normal mode */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->speed_task = NULL;
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->speed_task = NULL;
-		ret = -1;
-		break;
-	}
-	return ret;
-}
-
-/*
- * Function act200l_reset (driver)
- *
- *    Reset the ACTiSYS ACT-IR200L type dongle.
- */
-static int act200l_reset(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u8 control[9] = {
-		ACT200L_REG15,
-		ACT200L_REG13 | ACT200L_SHDW,
-		ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL,
-		ACT200L_REG13,
-		ACT200L_REG7  | ACT200L_ENPOS,
-		ACT200L_REG6  | ACT200L_RS0  | ACT200L_RS1,
-		ACT200L_REG5  | ACT200L_RWIDL,
-		ACT200L_REG4  | ACT200L_OP0  | ACT200L_OP1 | ACT200L_BLKR,
-		ACT200L_REG0  | ACT200L_TXEN | ACT200L_RXEN
-	};
-	int ret = 0;
-
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
-
-	self->reset_task = task;
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-		/* Power on the dongle */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-
-		irda_task_next_state(task, IRDA_TASK_WAIT1);
-		ret = msecs_to_jiffies(50);
-		break;
-	case IRDA_TASK_WAIT1:
-		/* Reset the dongle : set RTS low for 25 ms */
-		self->set_dtr_rts(self->dev, TRUE, FALSE);
-
-		irda_task_next_state(task, IRDA_TASK_WAIT2);
-		ret = msecs_to_jiffies(50);
-		break;
-	case IRDA_TASK_WAIT2:
-		/* Clear DTR and set RTS to enter command mode */
-		self->set_dtr_rts(self->dev, FALSE, TRUE);
-
-		/* Write control bytes */
-		self->write(self->dev, control, 9);
-		irda_task_next_state(task, IRDA_TASK_WAIT3);
-		ret = msecs_to_jiffies(15);
-		break;
-	case IRDA_TASK_WAIT3:
-		/* Go back to normal mode */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->reset_task = NULL;
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->reset_task = NULL;
-		ret = -1;
-		break;
-	}
-	return ret;
-}
-
-MODULE_AUTHOR("SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>");
-MODULE_DESCRIPTION("ACTiSYS ACT-IR200L dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-10"); /* IRDA_ACT200L_DONGLE */
-
-/*
- * Function init_module (void)
- *
- *    Initialize ACTiSYS ACT-IR200L module
- *
- */
-module_init(act200l_init);
-
-/*
- * Function cleanup_module (void)
- *
- *    Cleanup ACTiSYS ACT-IR200L module
- *
- */
-module_exit(act200l_cleanup);
diff --git a/drivers/net/irda/actisys.c b/drivers/net/irda/actisys.c
deleted file mode 100644
index ae0b80a5680c..000000000000
--- a/drivers/net/irda/actisys.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      actisys.c
- * Version:       1.0
- * Description:   Implementation for the ACTiSYS IR-220L and IR-220L+ 
- *                dongles
- * Status:        Beta.
- * Authors:       Dag Brattli <dagb@cs.uit.no> (initially)
- *		  Jean Tourrilhes <jt@hpl.hp.com> (new version)
- * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Fri Dec 17 09:10:43 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
- *     Copyright (c) 1999 Jean Tourrilhes
- *      
- *     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.
- *     
- ********************************************************************/
-
-/*
- * Changelog
- *
- * 0.8 -> 0.9999 - Jean
- *	o New initialisation procedure : much safer and correct
- *	o New procedure the change speed : much faster and simpler
- *	o Other cleanups & comments
- *	Thanks to Lichen Wang @ Actisys for his excellent help...
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-/* 
- * Define the timing of the pulses we send to the dongle (to reset it, and
- * to toggle speeds). Basically, the limit here is the propagation speed of
- * the signals through the serial port, the dongle being much faster.  Any
- * serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can
- * go through cleanly . If you are on the wild side, you can try to lower
- * this value (Actisys recommended me 2 us, and 0 us work for me on a P233!)
- */
-#define MIN_DELAY 10	/* 10 us to be on the conservative side */
-
-static int  actisys_change_speed(struct irda_task *task);
-static int  actisys_reset(struct irda_task *task);
-static void actisys_open(dongle_t *self, struct qos_info *qos);
-static void actisys_close(dongle_t *self);
-
-/* These are the baudrates supported, in the order available */
-/* Note : the 220L doesn't support 38400, but we will fix that below */
-static __u32 baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
-#define MAX_SPEEDS 5
-
-static struct dongle_reg dongle = {
-	.type = IRDA_ACTISYS_DONGLE,
-	.open = actisys_open,
-	.close = actisys_close,
-	.reset = actisys_reset,
-	.change_speed = actisys_change_speed,
-	.owner = THIS_MODULE,
-};
-
-static struct dongle_reg dongle_plus = {
-	.type = IRDA_ACTISYS_PLUS_DONGLE,
-	.open = actisys_open,
-	.close = actisys_close,
-	.reset = actisys_reset,
-	.change_speed = actisys_change_speed,
-	.owner = THIS_MODULE,
-};
-
-/*
- * Function actisys_change_speed (task)
- *
- *	There is two model of Actisys dongle we are dealing with,
- * the 220L and 220L+. At this point, only irattach knows with
- * kind the user has requested (it was an argument on irattach
- * command line).
- *	So, we register a dongle of each sort and let irattach
- * pick the right one...
- */
-static int __init actisys_init(void)
-{
-	int ret;
-
-	/* First, register an Actisys 220L dongle */
-	ret = irda_device_register_dongle(&dongle);
-	if (ret < 0)
-		return ret;
-	/* Now, register an Actisys 220L+ dongle */
-	ret = irda_device_register_dongle(&dongle_plus);
-	if (ret < 0) {
-		irda_device_unregister_dongle(&dongle);
-		return ret;
-	}	
-	return 0;
-}
-
-static void __exit actisys_cleanup(void)
-{
-	/* We have to remove both dongles */
-	irda_device_unregister_dongle(&dongle);
-	irda_device_unregister_dongle(&dongle_plus);
-}
-
-static void actisys_open(dongle_t *self, struct qos_info *qos)
-{
-	/* Power on the dongle */
-	self->set_dtr_rts(self->dev, TRUE, TRUE);
-
-	/* Set the speeds we can accept */
-	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-
-	/* Remove support for 38400 if this is not a 220L+ dongle */
-	if (self->issue->type == IRDA_ACTISYS_DONGLE)
-		qos->baud_rate.bits &= ~IR_38400;
-	
-	qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
-}
-
-static void actisys_close(dongle_t *self)
-{
-	/* Power off the dongle */
-	self->set_dtr_rts(self->dev, FALSE, FALSE);
-}
-
-/*
- * Function actisys_change_speed (task)
- *
- *    Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles.
- *    To cycle through the available baud rates, pulse RTS low for a few us.
- *
- *	First, we reset the dongle to always start from a known state.
- *	Then, we cycle through the speeds by pulsing RTS low and then up.
- *	The dongle allow us to pulse quite fast, se we can set speed in one go,
- * which is must faster ( < 100 us) and less complex than what is found
- * in some other dongle drivers...
- *	Note that even if the new speed is the same as the current speed,
- * we reassert the speed. This make sure that things are all right,
- * and it's fast anyway...
- *	By the way, this function will work for both type of dongles,
- * because the additional speed is at the end of the sequence...
- */
-static int actisys_change_speed(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u32 speed = (__u32) task->param;	/* Target speed */
-	int ret = 0;
-	int i = 0;
-
-        IRDA_DEBUG(4, "%s(), speed=%d (was %d)\n", __FUNCTION__, speed, 
-		   self->speed);
-
-	/* Go to a known state by reseting the dongle */
-
-	/* Reset the dongle : set DTR low for 10 us */
-	self->set_dtr_rts(self->dev, FALSE, TRUE);
-	udelay(MIN_DELAY);
-
-	/* Go back to normal mode (we are now at 9600 b/s) */
-	self->set_dtr_rts(self->dev, TRUE, TRUE);
- 
-	/* 
-	 * Now, we can set the speed requested. Send RTS pulses until we
-         * reach the target speed 
-	 */
-	for (i=0; i<MAX_SPEEDS; i++) {
-		if (speed == baud_rates[i]) {
-			self->speed = baud_rates[i];
-			break;
-		}
-		/* Make sure previous pulse is finished */
-		udelay(MIN_DELAY);
-
-		/* Set RTS low for 10 us */
-		self->set_dtr_rts(self->dev, TRUE, FALSE);
-		udelay(MIN_DELAY);
-
-		/* Set RTS high for 10 us */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-	}
-
-	/* Check if life is sweet... */
-	if (i >= MAX_SPEEDS)
-		ret = -1;  /* This should not happen */
-
-	/* Basta lavoro, on se casse d'ici... */
-	irda_task_next_state(task, IRDA_TASK_DONE);
-
-	return ret;
-}
-
-/*
- * Function actisys_reset (task)
- *
- *      Reset the Actisys type dongle. Warning, this function must only be
- *      called with a process context!
- *
- * We need to do two things in this function :
- *	o first make sure that the dongle is in a state where it can operate
- *	o second put the dongle in a know state
- *
- *	The dongle is powered of the RTS and DTR lines. In the dongle, there
- * is a big capacitor to accommodate the current spikes. This capacitor
- * takes a least 50 ms to be charged. In theory, the Bios set those lines
- * up, so by the time we arrive here we should be set. It doesn't hurt
- * to be on the conservative side, so we will wait...
- *	Then, we set the speed to 9600 b/s to get in a known state (see in
- * change_speed for details). It is needed because the IrDA stack
- * has tried to set the speed immediately after our first return,
- * so before we can be sure the dongle is up and running.
- */
-static int actisys_reset(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	int ret = 0;
-
-	IRDA_ASSERT(task != NULL, return -1;);
-
-	self->reset_task = task;
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-		/* Set both DTR & RTS to power up the dongle */
-		/* In theory redundant with power up in actisys_open() */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-		
-		/* Sleep 50 ms to make sure capacitor is charged */
-		ret = msecs_to_jiffies(50);
-		irda_task_next_state(task, IRDA_TASK_WAIT);
-		break;
-	case IRDA_TASK_WAIT:			
-		/* Reset the dongle : set DTR low for 10 us */
-		self->set_dtr_rts(self->dev, FALSE, TRUE);
-		udelay(MIN_DELAY);
-
-		/* Go back to normal mode */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-	
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->reset_task = NULL;
-		self->speed = 9600;	/* That's the default */
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->reset_task = NULL;
-		ret = -1;
-		break;
-	}
-	return ret;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> - Jean Tourrilhes <jt@hpl.hp.com>");
-MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver");	
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-2"); /* IRDA_ACTISYS_DONGLE */
-MODULE_ALIAS("irda-dongle-3"); /* IRDA_ACTISYS_PLUS_DONGLE */
-
-		
-/*
- * Function init_module (void)
- *
- *    Initialize Actisys module
- *
- */
-module_init(actisys_init);
-
-/*
- * Function cleanup_module (void)
- *
- *    Cleanup Actisys module
- *
- */
-module_exit(actisys_cleanup);
diff --git a/drivers/net/irda/ep7211_ir.c b/drivers/net/irda/ep7211_ir.c
deleted file mode 100644
index 4cba38f7e4a8..000000000000
--- a/drivers/net/irda/ep7211_ir.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * IR port driver for the Cirrus Logic EP7211 processor.
- *
- * Copyright 2001, Blue Mug Inc.  All rights reserved.
- */
-
-#include <linux/module.h>
-#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>
-
-#include <asm/io.h>
-#include <asm/hardware.h>
-
-#define MIN_DELAY 25      /* 15 us, but wait a little more to be sure */
-#define MAX_DELAY 10000   /* 1 ms */
-
-static void ep7211_ir_open(dongle_t *self, struct qos_info *qos);
-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,
-	.close = ep7211_ir_close,
-	.reset = ep7211_ir_reset,
-	.change_speed = ep7211_ir_change_speed,
-	.owner = THIS_MODULE,
-};
-
-static void ep7211_ir_open(dongle_t *self, struct qos_info *qos)
-{
-	unsigned int syscon1, flags;
-
-	spin_lock_irqsave(&ep7211_lock, flags);
-
-	/* Turn on the SIR encoder. */
-	syscon1 = clps_readl(SYSCON1);
-	syscon1 |= SYSCON1_SIREN;
-	clps_writel(syscon1, SYSCON1);
-
-	/* XXX: We should disable modem status interrupts on the first
-		UART (interrupt #14). */
-
-	spin_unlock_irqrestore(&ep7211_lock, flags);
-}
-
-static void ep7211_ir_close(dongle_t *self)
-{
-	unsigned int syscon1, flags;
-
-	spin_lock_irqsave(&ep7211_lock, flags);
-
-	/* Turn off the SIR encoder. */
-	syscon1 = clps_readl(SYSCON1);
-	syscon1 &= ~SYSCON1_SIREN;
-	clps_writel(syscon1, SYSCON1);
-
-	/* XXX: If we've disabled the modem status interrupts, we should
-		reset them back to their original state. */
-
-	spin_unlock_irqrestore(&ep7211_lock, flags);
-}
-
-/*
- * Function ep7211_ir_change_speed (task)
- *
- *    Change speed of the EP7211 I/R port. We don't really have to do anything
- *    for the EP7211 as long as the rate is being changed at the serial port
- *    level.
- */
-static int ep7211_ir_change_speed(struct irda_task *task)
-{
-	irda_task_next_state(task, IRDA_TASK_DONE);
-	return 0;
-}
-
-/*
- * Function ep7211_ir_reset (task)
- *
- *      Reset the EP7211 I/R. We don't really have to do anything.
- *
- */
-static int ep7211_ir_reset(struct irda_task *task)
-{
-	irda_task_next_state(task, IRDA_TASK_DONE);
-	return 0;
-}
-
-/*
- * Function ep7211_ir_init(void)
- *
- *    Initialize EP7211 I/R module
- *
- */
-static int __init ep7211_ir_init(void)
-{
-	return irda_device_register_dongle(&dongle);
-}
-
-/*
- * Function ep7211_ir_cleanup(void)
- *
- *    Cleanup EP7211 I/R module
- *
- */
-static void __exit ep7211_ir_cleanup(void)
-{
-	irda_device_unregister_dongle(&dongle);
-}
-
-MODULE_AUTHOR("Jon McClintock <jonm@bluemug.com>");
-MODULE_DESCRIPTION("EP7211 I/R driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-8"); /* IRDA_EP7211_IR */
-		
-module_init(ep7211_ir_init);
-module_exit(ep7211_ir_cleanup);
diff --git a/drivers/net/irda/esi.c b/drivers/net/irda/esi.c
deleted file mode 100644
index d3a61af6402d..000000000000
--- a/drivers/net/irda/esi.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      esi.c
- * Version:       1.5
- * Description:   Driver for the Extended Systems JetEye PC dongle
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Fri Dec 17 09:14:04 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1999 Dag Brattli, <dagb@cs.uit.no>,
- *     Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>,
- *     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.
- * 
- *     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/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-static void esi_open(dongle_t *self, struct qos_info *qos);
-static void esi_close(dongle_t *self);
-static int  esi_change_speed(struct irda_task *task);
-static int  esi_reset(struct irda_task *task);
-
-static struct dongle_reg dongle = {
-	.type = IRDA_ESI_DONGLE,
-	.open = esi_open,
-	.close = esi_close,
-	.reset = esi_reset,
-	.change_speed = esi_change_speed,
-	.owner = THIS_MODULE,
-};
-
-static int __init esi_init(void)
-{
-	return irda_device_register_dongle(&dongle);
-}
-
-static void __exit esi_cleanup(void)
-{
-	irda_device_unregister_dongle(&dongle);
-}
-
-static void esi_open(dongle_t *self, struct qos_info *qos)
-{
-	qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
-	qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
-}
-
-static void esi_close(dongle_t *dongle)
-{		
-	/* Power off dongle */
-	dongle->set_dtr_rts(dongle->dev, FALSE, FALSE);
-}
-
-/*
- * Function esi_change_speed (task)
- *
- *    Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle
- *
- */
-static int esi_change_speed(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u32 speed = (__u32) task->param;
-	int dtr, rts;
-	
-	switch (speed) {
-	case 19200:
-		dtr = TRUE;
-		rts = FALSE;
-		break;
-	case 115200:
-		dtr = rts = TRUE;
-		break;
-	case 9600:
-	default:
-		dtr = FALSE;
-		rts = TRUE;
-		break;
-	}
-
-	/* Change speed of dongle */
-	self->set_dtr_rts(self->dev, dtr, rts);
-	self->speed = speed;
-
-	irda_task_next_state(task, IRDA_TASK_DONE);
-
-	return 0;
-}
-
-/*
- * Function esi_reset (task)
- *
- *    Reset dongle;
- *
- */
-static int esi_reset(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	
-	self->set_dtr_rts(self->dev, FALSE, FALSE);
-	irda_task_next_state(task, IRDA_TASK_DONE);
-
-	return 0;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-1"); /* IRDA_ESI_DONGLE */
-
-/*
- * Function init_module (void)
- *
- *    Initialize ESI module
- *
- */
-module_init(esi_init);
-
-/*
- * Function cleanup_module (void)
- *
- *    Cleanup ESI module
- *
- */
-module_exit(esi_cleanup);
-
diff --git a/drivers/net/irda/girbil.c b/drivers/net/irda/girbil.c
deleted file mode 100644
index 1f57391a618b..000000000000
--- a/drivers/net/irda/girbil.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      girbil.c
- * Version:       1.2
- * Description:   Implementation for the Greenwich GIrBIL dongle
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sat Feb  6 21:02:33 1999
- * Modified at:   Fri Dec 17 09:13:20 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1999 Dag Brattli, 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.
- *     
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-static int  girbil_reset(struct irda_task *task);
-static void girbil_open(dongle_t *self, struct qos_info *qos);
-static void girbil_close(dongle_t *self);
-static int  girbil_change_speed(struct irda_task *task);
-
-/* Control register 1 */
-#define GIRBIL_TXEN    0x01 /* Enable transmitter */
-#define GIRBIL_RXEN    0x02 /* Enable receiver */
-#define GIRBIL_ECAN    0x04 /* Cancel self emmited data */
-#define GIRBIL_ECHO    0x08 /* Echo control characters */
-
-/* LED Current Register (0x2) */
-#define GIRBIL_HIGH    0x20
-#define GIRBIL_MEDIUM  0x21
-#define GIRBIL_LOW     0x22
-
-/* Baud register (0x3) */
-#define GIRBIL_2400    0x30
-#define GIRBIL_4800    0x31	
-#define GIRBIL_9600    0x32
-#define GIRBIL_19200   0x33
-#define GIRBIL_38400   0x34	
-#define GIRBIL_57600   0x35	
-#define GIRBIL_115200  0x36
-
-/* Mode register (0x4) */
-#define GIRBIL_IRDA    0x40
-#define GIRBIL_ASK     0x41
-
-/* Control register 2 (0x5) */
-#define GIRBIL_LOAD    0x51 /* Load the new baud rate value */
-
-static struct dongle_reg dongle = {
-	.type = IRDA_GIRBIL_DONGLE,
-	.open = girbil_open,
-	.close = girbil_close,
-	.reset = girbil_reset,
-	.change_speed = girbil_change_speed,
-	.owner = THIS_MODULE,
-};
-
-static int __init girbil_init(void)
-{
-	return irda_device_register_dongle(&dongle);
-}
-
-static void __exit girbil_cleanup(void)
-{
-	irda_device_unregister_dongle(&dongle);
-}
-
-static void girbil_open(dongle_t *self, struct qos_info *qos)
-{
-	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-	qos->min_turn_time.bits = 0x03;
-}
-
-static void girbil_close(dongle_t *self)
-{
-	/* Power off dongle */
-	self->set_dtr_rts(self->dev, FALSE, FALSE);
-}
-
-/*
- * Function girbil_change_speed (dev, speed)
- *
- *    Set the speed for the Girbil type dongle.
- *
- */
-static int girbil_change_speed(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u32 speed = (__u32) task->param;
-	__u8 control[2];
-	int ret = 0;
-
-	self->speed_task = task;
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-		/* Need to reset the dongle and go to 9600 bps before
-                   programming */
-		if (irda_task_execute(self, girbil_reset, NULL, task, 
-				      (void *) speed))
-		{
-			/* Dongle need more time to reset */
-			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
-
-			/* Give reset 1 sec to finish */
-			ret = msecs_to_jiffies(1000);
-		}
-		break;
-	case IRDA_TASK_CHILD_WAIT:
-		IRDA_WARNING("%s(), resetting dongle timed out!\n",
-			     __FUNCTION__);
-		ret = -1;
-		break;
-	case IRDA_TASK_CHILD_DONE:
-		/* Set DTR and Clear RTS to enter command mode */
-		self->set_dtr_rts(self->dev, FALSE, TRUE);
-
-		switch (speed) {
-		case 9600:
-		default:
-			control[0] = GIRBIL_9600;
-			break;
-		case 19200:
-			control[0] = GIRBIL_19200;
-			break;
-		case 34800:
-			control[0] = GIRBIL_38400;
-			break;
-		case 57600:
-			control[0] = GIRBIL_57600;
-			break;
-		case 115200:
-			control[0] = GIRBIL_115200;
-			break;
-		}
-		control[1] = GIRBIL_LOAD;
-		
-		/* Write control bytes */
-		self->write(self->dev, control, 2);
-		irda_task_next_state(task, IRDA_TASK_WAIT);
-		ret = msecs_to_jiffies(100);
-		break;
-	case IRDA_TASK_WAIT:
-		/* Go back to normal mode */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->speed_task = NULL;
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->speed_task = NULL;
-		ret = -1;
-		break;
-	}
-	return ret;
-}
-
-/*
- * Function girbil_reset (driver)
- *
- *      This function resets the girbil dongle.
- *
- *      Algorithm:
- *    	  0. set RTS, and wait at least 5 ms 
- *        1. clear RTS 
- */
-static int girbil_reset(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
-	int ret = 0;
-
-	self->reset_task = task;
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-		/* Reset dongle */
-		self->set_dtr_rts(self->dev, TRUE, FALSE);
-		irda_task_next_state(task, IRDA_TASK_WAIT1);
-		/* Sleep at least 5 ms */
-		ret = msecs_to_jiffies(20);
-		break;
-	case IRDA_TASK_WAIT1:
-		/* Set DTR and clear RTS to enter command mode */
-		self->set_dtr_rts(self->dev, FALSE, TRUE);
-		irda_task_next_state(task, IRDA_TASK_WAIT2);
-		ret = msecs_to_jiffies(20);
-		break;
-	case IRDA_TASK_WAIT2:
-		/* Write control byte */
-		self->write(self->dev, &control, 1);
-		irda_task_next_state(task, IRDA_TASK_WAIT3);
-		ret = msecs_to_jiffies(20);
-		break;
-	case IRDA_TASK_WAIT3:
-		/* Go back to normal mode */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->reset_task = NULL;
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->reset_task = NULL;
-		ret = -1;
-		break;
-	}
-	return ret;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-4"); /* IRDA_GIRBIL_DONGLE */
-	
-/*
- * Function init_module (void)
- *
- *    Initialize Girbil module
- *
- */
-module_init(girbil_init);
-
-/*
- * Function cleanup_module (void)
- *
- *    Cleanup Girbil module
- *
- */
-module_exit(girbil_cleanup);
-
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
deleted file mode 100644
index c79caa5d3d71..000000000000
--- a/drivers/net/irda/irport.c
+++ /dev/null
@@ -1,1123 +0,0 @@
-/*********************************************************************
- * 
- * Filename:	  irport.c
- * Version:	  1.0
- * Description:   Half duplex serial port SIR driver for IrDA. 
- * Status:	  Experimental.
- * Author:	  Dag Brattli <dagb@cs.uit.no>
- * Created at:	  Sun Aug  3 13:49:59 1997
- * Modified at:   Fri Jan 28 20:22:38 2000
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * Sources:	  serial.c by Linus Torvalds 
- * 
- *     Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved.
- *     Copyright (c) 2000-2003 Jean Tourrilhes, 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.
- * 
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *     GNU General Public License for more details.
- * 
- *     You should have received a copy of the GNU General Public License 
- *     along with this program; if not, write to the Free Software 
- *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
- *     MA 02111-1307 USA
- *
- *     This driver is ment to be a small half duplex serial driver to be
- *     used for IR-chipsets that has a UART (16550) compatibility mode. 
- *     Eventually it will replace irtty, because of irtty has some 
- *     problems that is hard to get around when we don't have control
- *     over the serial driver. This driver may also be used by FIR 
- *     drivers to handle SIR mode for them.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/skbuff.h>
-#include <linux/serial_reg.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/rtnetlink.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/wrapper.h>
-#include "irport.h"
-
-#define IO_EXTENT 8
-
-/* 
- * Currently you'll need to set these values using insmod like this:
- * insmod irport io=0x3e8 irq=11
- */
-static unsigned int io[]  = { ~0, ~0, ~0, ~0 };
-static unsigned int irq[] = { 0, 0, 0, 0 };
-
-static unsigned int qos_mtt_bits = 0x03;
-
-static struct irport_cb *dev_self[] = { NULL, NULL, NULL, NULL};
-static char *driver_name = "irport";
-
-static inline void irport_write_wakeup(struct irport_cb *self);
-static inline int  irport_write(int iobase, int fifo_size, __u8 *buf, int len);
-static inline void irport_receive(struct irport_cb *self);
-
-static int  irport_net_ioctl(struct net_device *dev, struct ifreq *rq, 
-			     int cmd);
-static inline int  irport_is_receiving(struct irport_cb *self);
-static int  irport_set_dtr_rts(struct net_device *dev, int dtr, int rts);
-static int  irport_raw_write(struct net_device *dev, __u8 *buf, int len);
-static struct net_device_stats *irport_net_get_stats(struct net_device *dev);
-static int irport_change_speed_complete(struct irda_task *task);
-static void irport_timeout(struct net_device *dev);
-
-static irqreturn_t irport_interrupt(int irq, void *dev_id);
-static int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev);
-static void irport_change_speed(void *priv, __u32 speed);
-static int irport_net_open(struct net_device *dev);
-static int irport_net_close(struct net_device *dev);
-
-static struct irport_cb *
-irport_open(int i, unsigned int iobase, unsigned int irq)
-{
-	struct net_device *dev;
-	struct irport_cb *self;
-
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
-
-	/* Lock the port that we need */
-	if (!request_region(iobase, IO_EXTENT, driver_name)) {
-		IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n",
-			   __FUNCTION__, iobase);
-		goto err_out1;
-	}
-
-	/*
-	 *  Allocate new instance of the driver
-	 */
-	dev = alloc_irdadev(sizeof(struct irport_cb));
-	if (!dev) {
-		IRDA_ERROR("%s(), can't allocate memory for "
-			   "irda device!\n", __FUNCTION__);
-		goto err_out2;
-	}
-
-	self = dev->priv;
-	spin_lock_init(&self->lock);
-
-	/* Need to store self somewhere */
-	dev_self[i] = self;
-	self->priv = self;
-	self->index = i;
-
-	/* Initialize IO */
-	self->io.sir_base  = iobase;
-        self->io.sir_ext   = IO_EXTENT;
-        self->io.irq       = irq;
-        self->io.fifo_size = 16;		/* 16550A and compatible */
-
-	/* Initialize QoS for this device */
-	irda_init_max_qos_capabilies(&self->qos);
-	
-	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
-		IR_115200;
-
-	self->qos.min_turn_time.bits = qos_mtt_bits;
-	irda_qos_bits_to_value(&self->qos);
-	
-	/* Bootstrap ZeroCopy Rx */
-	self->rx_buff.truesize = IRDA_SKB_MAX_MTU;
-	self->rx_buff.skb = __dev_alloc_skb(self->rx_buff.truesize,
-					    GFP_KERNEL);
-	if (self->rx_buff.skb == NULL) {
-		IRDA_ERROR("%s(), can't allocate memory for "
-			   "receive buffer!\n", __FUNCTION__);
-		goto err_out3;
-	}
-	skb_reserve(self->rx_buff.skb, 1);
-	self->rx_buff.head = self->rx_buff.skb->data;
-	/* No need to memset the buffer, unless you are really pedantic */
-
-	/* Finish setup the Rx buffer descriptor */
-	self->rx_buff.in_frame = FALSE;
-	self->rx_buff.state = OUTSIDE_FRAME;
-	self->rx_buff.data = self->rx_buff.head;
-
-	/* Specify how much memory we want */
-	self->tx_buff.truesize = 4000;
-	
-	/* Allocate memory if needed */
-	if (self->tx_buff.truesize > 0) {
-		self->tx_buff.head = kzalloc(self->tx_buff.truesize,
-						      GFP_KERNEL);
-		if (self->tx_buff.head == NULL) {
-			IRDA_ERROR("%s(), can't allocate memory for "
-				   "transmit buffer!\n", __FUNCTION__);
-			goto err_out4;
-		}
-	}	
-	self->tx_buff.data = self->tx_buff.head;
-
-	self->netdev = dev;
-
-	/* May be overridden by piggyback drivers */
-	self->interrupt    = irport_interrupt;
-	self->change_speed = irport_change_speed;
-
-	/* Override the network functions we need to use */
-	dev->hard_start_xmit = irport_hard_xmit;
-	dev->tx_timeout	     = irport_timeout;
-	dev->watchdog_timeo  = HZ;  /* Allow time enough for speed change */
-	dev->open            = irport_net_open;
-	dev->stop            = irport_net_close;
-	dev->get_stats	     = irport_net_get_stats;
-	dev->do_ioctl        = irport_net_ioctl;
-
-	/* Make ifconfig display some details */
-	dev->base_addr = iobase;
-	dev->irq = irq;
-
-	if (register_netdev(dev)) {
-		IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
-		goto err_out5;
-	}
-	IRDA_MESSAGE("IrDA: Registered device %s (irport io=0x%X irq=%d)\n",
-		dev->name, iobase, irq);
-
-	return self;
- err_out5:
-	kfree(self->tx_buff.head);
- err_out4:
-	kfree_skb(self->rx_buff.skb);
- err_out3:
-	free_netdev(dev);
-	dev_self[i] = NULL;
- err_out2:
-	release_region(iobase, IO_EXTENT);
- err_out1:
-	return NULL;
-}
-
-static int irport_close(struct irport_cb *self)
-{
-	IRDA_ASSERT(self != NULL, return -1;);
-
-	/* We are not using any dongle anymore! */
-	if (self->dongle)
-		irda_device_dongle_cleanup(self->dongle);
-	self->dongle = NULL;
-	
-	/* Remove netdevice */
-	unregister_netdev(self->netdev);
-
-	/* Release the IO-port that this driver is using */
-	IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", 
-		   __FUNCTION__, self->io.sir_base);
-	release_region(self->io.sir_base, self->io.sir_ext);
-
-	kfree(self->tx_buff.head);
-	
-	if (self->rx_buff.skb)
-		kfree_skb(self->rx_buff.skb);
-	self->rx_buff.skb = NULL;
-	
-	/* Remove ourselves */
-	dev_self[self->index] = NULL;
-	free_netdev(self->netdev);
-	
-	return 0;
-}
-
-static void irport_stop(struct irport_cb *self)
-{
-	int iobase;
-
-	iobase = self->io.sir_base;
-
-	/* We can't lock, we may be called from a FIR driver - Jean II */
-
-	/* We are not transmitting any more */
-	self->transmitting = 0;
-
-	/* Reset UART */
-	outb(0, iobase+UART_MCR);
-	
-	/* Turn off interrupts */
-	outb(0, iobase+UART_IER);
-}
-
-static void irport_start(struct irport_cb *self)
-{
-	int iobase;
-
-	iobase = self->io.sir_base;
-
-	irport_stop(self);
-	
-	/* We can't lock, we may be called from a FIR driver - Jean II */
-
-	/* Initialize UART */
-	outb(UART_LCR_WLEN8, iobase+UART_LCR);  /* Reset DLAB */
-	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
-	
-	/* Turn on interrups */
-	outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER);
-}
-
-/*
- * Function irport_get_fcr (speed)
- *
- *    Compute value of fcr
- *
- */
-static inline unsigned int irport_get_fcr(__u32 speed)
-{
-	unsigned int fcr;    /* FIFO control reg */
-
-	/* Enable fifos */
-	fcr = UART_FCR_ENABLE_FIFO;
-
-	/* 
-	 * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
-	 * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
-	 * about this timeout since it will always be fast enough. 
-	 */
-	if (speed < 38400)
-		fcr |= UART_FCR_TRIGGER_1;
-	else 
-		//fcr |= UART_FCR_TRIGGER_14;
-		fcr |= UART_FCR_TRIGGER_8;
-
-	return(fcr);
-}
- 
-/*
- * Function irport_change_speed (self, speed)
- *
- *    Set speed of IrDA port to specified baudrate
- *
- * This function should be called with irq off and spin-lock.
- */
-static void irport_change_speed(void *priv, __u32 speed)
-{
-	struct irport_cb *self = (struct irport_cb *) priv;
-	int iobase; 
-	unsigned int fcr;    /* FIFO control reg */
-	unsigned int lcr;    /* Line control reg */
-	int divisor;
-
-	IRDA_ASSERT(self != NULL, return;);
-	IRDA_ASSERT(speed != 0, return;);
-
-	IRDA_DEBUG(1, "%s(), Setting speed to: %d - iobase=%#x\n",
-		    __FUNCTION__, speed, self->io.sir_base);
-
-	/* We can't lock, we may be called from a FIR driver - Jean II */
-
-	iobase = self->io.sir_base;
-	
-	/* Update accounting for new speed */
-	self->io.speed = speed;
-
-	/* Turn off interrupts */
-	outb(0, iobase+UART_IER); 
-
-	divisor = SPEED_MAX/speed;
-	
-	/* Get proper fifo configuration */
-	fcr = irport_get_fcr(speed);
-
-	/* IrDA ports use 8N1 */
-	lcr = UART_LCR_WLEN8;
-	
-	outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */
-	outb(divisor & 0xff,      iobase+UART_DLL); /* Set speed */
-	outb(divisor >> 8,	  iobase+UART_DLM);
-	outb(lcr,		  iobase+UART_LCR); /* Set 8N1	*/
-	outb(fcr,		  iobase+UART_FCR); /* Enable FIFO's */
-
-	/* Turn on interrups */
-	/* This will generate a fatal interrupt storm.
-	 * People calling us will do that properly - Jean II */
-	//outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
-}
-
-/*
- * Function __irport_change_speed (instance, state, param)
- *
- *    State machine for changing speed of the device. We do it this way since
- *    we cannot use schedule_timeout() when we are in interrupt context
- *
- */
-static int __irport_change_speed(struct irda_task *task)
-{
-	struct irport_cb *self;
-	__u32 speed = (__u32) task->param;
-	unsigned long flags = 0;
-	int wasunlocked = 0;
-	int ret = 0;
-
-	IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); 
-
-	self = (struct irport_cb *) task->instance;
-
-	IRDA_ASSERT(self != NULL, return -1;);
-
-	/* Locking notes : this function may be called from irq context with
-	 * spinlock, via irport_write_wakeup(), or from non-interrupt without
-	 * spinlock (from the task timer). Yuck !
-	 * This is ugly, and unsafe is the spinlock is not already acquired.
-	 * This will be fixed when irda-task get rewritten.
-	 * Jean II */
-	if (!spin_is_locked(&self->lock)) {
-		spin_lock_irqsave(&self->lock, flags);
-		wasunlocked = 1;
-	}
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-	case IRDA_TASK_WAIT:
-		/* Are we ready to change speed yet? */
-		if (self->tx_buff.len > 0) {
-			task->state = IRDA_TASK_WAIT;
-
-			/* Try again later */
-			ret = msecs_to_jiffies(20);
-			break;
-		}
-
-		if (self->dongle)
-			irda_task_next_state(task, IRDA_TASK_CHILD_INIT);
-		else
-			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
-		break;
-	case IRDA_TASK_CHILD_INIT:
-		/* Go to default speed */
-		self->change_speed(self->priv, 9600);
-
-		/* Change speed of dongle */
-		if (irda_task_execute(self->dongle,
-				      self->dongle->issue->change_speed, 
-				      NULL, task, (void *) speed))
-		{
-			/* Dongle need more time to change its speed */
-			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
-
-			/* Give dongle 1 sec to finish */
-			ret = msecs_to_jiffies(1000);
-		} else
-			/* Child finished immediately */
-			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
-		break;
-	case IRDA_TASK_CHILD_WAIT:
-		IRDA_WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__);
-		ret = -1;		
-		break;
-	case IRDA_TASK_CHILD_DONE:
-		/* Finally we are ready to change the speed */
-		self->change_speed(self->priv, speed);
-		
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		ret = -1;
-		break;
-	}
-	/* Put stuff in the state we found them - Jean II */
-	if(wasunlocked) {
-		spin_unlock_irqrestore(&self->lock, flags);
-	}
-
-	return ret;
-}
-
-/*
- * Function irport_change_speed_complete (task)
- *
- *    Called when the change speed operation completes
- *
- */
-static int irport_change_speed_complete(struct irda_task *task)
-{
-	struct irport_cb *self;
-
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
-
-	self = (struct irport_cb *) task->instance;
-
-	IRDA_ASSERT(self != NULL, return -1;);
-	IRDA_ASSERT(self->netdev != NULL, return -1;);
-
-	/* Finished changing speed, so we are not busy any longer */
-	/* Signal network layer so it can try to send the frame */
-
-	netif_wake_queue(self->netdev);
-	
-	return 0;
-}
-
-/*
- * Function irport_timeout (struct net_device *dev)
- *
- *    The networking layer thinks we timed out.
- *
- */
-
-static void irport_timeout(struct net_device *dev)
-{
-	struct irport_cb *self;
-	int iobase;
-	int iir, lsr;
-	unsigned long flags;
-
-	self = (struct irport_cb *) dev->priv;
-	IRDA_ASSERT(self != NULL, return;);
-	iobase = self->io.sir_base;
-	
-	IRDA_WARNING("%s: transmit timed out, jiffies = %ld, trans_start = %ld\n",
-		dev->name, jiffies, dev->trans_start);
-	spin_lock_irqsave(&self->lock, flags);
-
-	/* Debug what's happening... */
-
-	/* Get interrupt status */
-	lsr = inb(iobase+UART_LSR);
-	/* Read interrupt register */
-	iir = inb(iobase+UART_IIR);
-	IRDA_DEBUG(0, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", 
-		   __FUNCTION__, iir, lsr, iobase);
-
-	IRDA_DEBUG(0, "%s(), transmitting=%d, remain=%d, done=%td\n",
-		   __FUNCTION__, self->transmitting, self->tx_buff.len,
-		   self->tx_buff.data - self->tx_buff.head);
-
-	/* Now, restart the port */
-	irport_start(self);
-	self->change_speed(self->priv, self->io.speed);
-	/* This will re-enable irqs */
-	outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
-	dev->trans_start = jiffies;
-	spin_unlock_irqrestore(&self->lock, flags);
-
-	netif_wake_queue(dev);
-}
- 
-/*
- * Function irport_wait_hw_transmitter_finish ()
- *
- *    Wait for the real end of HW transmission
- *
- * The UART is a strict FIFO, and we get called only when we have finished
- * pushing data to the FIFO, so the maximum amount of time we must wait
- * is only for the FIFO to drain out.
- *
- * We use a simple calibrated loop. We may need to adjust the loop
- * delay (udelay) to balance I/O traffic and latency. And we also need to
- * adjust the maximum timeout.
- * It would probably be better to wait for the proper interrupt,
- * but it doesn't seem to be available.
- *
- * We can't use jiffies or kernel timers because :
- * 1) We are called from the interrupt handler, which disable softirqs,
- * so jiffies won't be increased
- * 2) Jiffies granularity is usually very coarse (10ms), and we don't
- * want to wait that long to detect stuck hardware.
- * Jean II
- */
-
-static void irport_wait_hw_transmitter_finish(struct irport_cb *self)
-{
-	int iobase;
-	int count = 1000;	/* 1 ms */
-	
-	iobase = self->io.sir_base;
-
-	/* Calibrated busy loop */
-	while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT))
-		udelay(1);
-
-	if(count == 0)
-		IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__);
-}
-
-/*
- * Function irport_hard_start_xmit (struct sk_buff *skb, struct net_device *dev)
- *
- *    Transmits the current frame until FIFO is full, then
- *    waits until the next transmitt interrupt, and continues until the
- *    frame is transmitted.
- */
-static int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct irport_cb *self;
-	unsigned long flags;
-	int iobase;
-	s32 speed;
-
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
-
-	IRDA_ASSERT(dev != NULL, return 0;);
-	
-	self = (struct irport_cb *) dev->priv;
-	IRDA_ASSERT(self != NULL, return 0;);
-
-	iobase = self->io.sir_base;
-
-	netif_stop_queue(dev);
-
-	/* Make sure tests & speed change are atomic */
-	spin_lock_irqsave(&self->lock, flags);
-
-	/* Check if we need to change the speed */
-	speed = irda_get_next_speed(skb);
-	if ((speed != self->io.speed) && (speed != -1)) {
-		/* Check for empty frame */
-		if (!skb->len) {
-			/*
-			 * We send frames one by one in SIR mode (no
-			 * pipelining), so at this point, if we were sending
-			 * a previous frame, we just received the interrupt
-			 * telling us it is finished (UART_IIR_THRI).
-			 * Therefore, waiting for the transmitter to really
-			 * finish draining the fifo won't take too long.
-			 * And the interrupt handler is not expected to run.
-			 * - Jean II */
-			irport_wait_hw_transmitter_finish(self);
-			/* Better go there already locked - Jean II */
-			irda_task_execute(self, __irport_change_speed, 
-					  irport_change_speed_complete, 
-					  NULL, (void *) speed);
-			dev->trans_start = jiffies;
-			spin_unlock_irqrestore(&self->lock, flags);
-			dev_kfree_skb(skb);
-			return 0;
-		} else
-			self->new_speed = speed;
-	}
-
-	/* Init tx buffer */
-	self->tx_buff.data = self->tx_buff.head;
-
-        /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
-	self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
-					   self->tx_buff.truesize);
-	
-	self->stats.tx_bytes += self->tx_buff.len;
-
-	/* We are transmitting */
-	self->transmitting = 1;
-
-	/* Turn on transmit finished interrupt. Will fire immediately!  */
-	outb(UART_IER_THRI, iobase+UART_IER); 
-
-	dev->trans_start = jiffies;
-	spin_unlock_irqrestore(&self->lock, flags);
-
-	dev_kfree_skb(skb);
-	
-	return 0;
-}
-        
-/*
- * Function irport_write (driver)
- *
- *    Fill Tx FIFO with transmit data
- *
- * Called only from irport_write_wakeup()
- */
-static inline int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
-{
-	int actual = 0;
-
-	/* Fill FIFO with current frame */
-	while ((actual < fifo_size) && (actual < len)) {
-		/* Transmit next byte */
-		outb(buf[actual], iobase+UART_TX);
-
-		actual++;
-	}
-        
-	return actual;
-}
-
-/*
- * Function irport_write_wakeup (tty)
- *
- *    Called by the driver when there's room for more data.  If we have
- *    more packets to send, we send them here.
- *
- * Called only from irport_interrupt()
- * Make sure this function is *not* called while we are receiving,
- * otherwise we will reset fifo and loose data :-(
- */
-static inline void irport_write_wakeup(struct irport_cb *self)
-{
-	int actual = 0;
-	int iobase;
-	unsigned int fcr;
-
-	IRDA_ASSERT(self != NULL, return;);
-
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
-
-	iobase = self->io.sir_base;
-
-	/* Finished with frame?  */
-	if (self->tx_buff.len > 0)  {
-		/* Write data left in transmit buffer */
-		actual = irport_write(iobase, self->io.fifo_size, 
-				      self->tx_buff.data, self->tx_buff.len);
-		self->tx_buff.data += actual;
-		self->tx_buff.len  -= actual;
-	} else {
-		/* 
-		 *  Now serial buffer is almost free & we can start 
-		 *  transmission of another packet. But first we must check
-		 *  if we need to change the speed of the hardware
-		 */
-		if (self->new_speed) {
-			irport_wait_hw_transmitter_finish(self);
-			irda_task_execute(self, __irport_change_speed, 
-					  irport_change_speed_complete, 
-					  NULL, (void *) self->new_speed);
-			self->new_speed = 0;
-		} else {
-			/* Tell network layer that we want more frames */
-			netif_wake_queue(self->netdev);
-		}
-		self->stats.tx_packets++;
-
-		/* 
-		 * Reset Rx FIFO to make sure that all reflected transmit data
-		 * is discarded. This is needed for half duplex operation
-		 */
-		fcr = irport_get_fcr(self->io.speed);
-		fcr |= UART_FCR_CLEAR_RCVR;
-		outb(fcr, iobase+UART_FCR);
-
-		/* Finished transmitting */
-		self->transmitting = 0;
-
-		/* Turn on receive interrupts */
-		outb(UART_IER_RDI, iobase+UART_IER);
-
-		IRDA_DEBUG(1, "%s() : finished Tx\n", __FUNCTION__);
-	}
-}
-
-/*
- * Function irport_receive (self)
- *
- *    Receive one frame from the infrared port
- *
- * Called only from irport_interrupt()
- */
-static inline void irport_receive(struct irport_cb *self) 
-{
-	int boguscount = 0;
-	int iobase;
-
-	IRDA_ASSERT(self != NULL, return;);
-
-	iobase = self->io.sir_base;
-
-	/*  
-	 * Receive all characters in Rx FIFO, unwrap and unstuff them. 
-         * async_unwrap_char will deliver all found frames  
-	 */
-	do {
-		async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, 
-				  inb(iobase+UART_RX));
-
-		/* Make sure we don't stay here too long */
-		if (boguscount++ > 32) {
-			IRDA_DEBUG(2,"%s(), breaking!\n", __FUNCTION__);
-			break;
-		}
-	} while (inb(iobase+UART_LSR) & UART_LSR_DR);	
-}
-
-/*
- * Function irport_interrupt (irq, dev_id)
- *
- *    Interrupt handler
- */
-static irqreturn_t irport_interrupt(int irq, void *dev_id) 
-{
-	struct net_device *dev = dev_id;
-	struct irport_cb *self;
-	int boguscount = 0;
-	int iobase;
-	int iir, lsr;
-	int handled = 0;
-
-	self = dev->priv;
-
-	spin_lock(&self->lock);
-
-	iobase = self->io.sir_base;
-
-	/* Cut'n'paste interrupt routine from serial.c
-	 * This version try to minimise latency and I/O operations.
-	 * Simplified and modified to enforce half duplex operation.
-	 * - Jean II */
-
-	/* Check status even is iir reg is cleared, more robust and
-	 * eliminate a read on the I/O bus - Jean II */
-	do {
-		/* Get interrupt status ; Clear interrupt */
-		lsr = inb(iobase+UART_LSR);
-		
-		/* Are we receiving or transmitting ? */
-		if(!self->transmitting) {
-			/* Received something ? */
-			if (lsr & UART_LSR_DR)
-				irport_receive(self);
-		} else {
-			/* Room in Tx fifo ? */
-			if (lsr & (UART_LSR_THRE | UART_LSR_TEMT))
-				irport_write_wakeup(self);
-		}
-
-		/* A bit hackish, but working as expected... Jean II */
-		if(lsr & (UART_LSR_THRE | UART_LSR_TEMT | UART_LSR_DR))
-			handled = 1;
-
-		/* Make sure we don't stay here to long */
-		if (boguscount++ > 10) {
-			IRDA_WARNING("%s() irq handler looping : lsr=%02x\n",
-				     __FUNCTION__, lsr);
-			break;
-		}
-
-		/* Read interrupt register */
- 	        iir = inb(iobase+UART_IIR);
-
-		/* Enable this debug only when no other options and at low
-		 * bit rates, otherwise it may cause Rx overruns (lsr=63).
-		 * - Jean II */
-		IRDA_DEBUG(6, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", 
-			    __FUNCTION__, iir, lsr, iobase);
-
-		/* As long as interrupt pending... */
-	} while ((iir & UART_IIR_NO_INT) == 0);
-
-	spin_unlock(&self->lock);
-	return IRQ_RETVAL(handled);
-}
-
-/*
- * Function irport_net_open (dev)
- *
- *    Network device is taken up. Usually this is done by "ifconfig irda0 up" 
- *   
- */
-static int irport_net_open(struct net_device *dev)
-{
-	struct irport_cb *self;
-	int iobase;
-	char hwname[16];
-	unsigned long flags;
-
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
-
-	IRDA_ASSERT(dev != NULL, return -1;);
-	self = (struct irport_cb *) dev->priv;
-
-	iobase = self->io.sir_base;
-
-	if (request_irq(self->io.irq, self->interrupt, 0, dev->name, 
-			(void *) dev)) {
-		IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",
-			   __FUNCTION__, self->io.irq);
-		return -EAGAIN;
-	}
-
-	spin_lock_irqsave(&self->lock, flags);
-	/* Init uart */
-	irport_start(self);
-	/* Set 9600 bauds per default, including at the dongle */
-	irda_task_execute(self, __irport_change_speed, 
-			  irport_change_speed_complete, 
-			  NULL, (void *) 9600);
-	spin_unlock_irqrestore(&self->lock, flags);
-
-
-	/* Give self a hardware name */
-	sprintf(hwname, "SIR @ 0x%03x", self->io.sir_base);
-
-	/* 
-	 * Open new IrLAP layer instance, now that everything should be
-	 * initialized properly 
-	 */
-	self->irlap = irlap_open(dev, &self->qos, hwname);
-
-	/* Ready to play! */
-
-	netif_start_queue(dev);
-
-	return 0;
-}
-
-/*
- * Function irport_net_close (self)
- *
- *    Network device is taken down. Usually this is done by 
- *    "ifconfig irda0 down" 
- */
-static int irport_net_close(struct net_device *dev)
-{
-	struct irport_cb *self;
-	int iobase;
-	unsigned long flags;
-
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
-
-	IRDA_ASSERT(dev != NULL, return -1;);
-	self = (struct irport_cb *) dev->priv;
-
-	IRDA_ASSERT(self != NULL, return -1;);
-
-	iobase = self->io.sir_base;
-
-	/* Stop device */
-	netif_stop_queue(dev);
-	
-	/* Stop and remove instance of IrLAP */
-	if (self->irlap)
-		irlap_close(self->irlap);
-	self->irlap = NULL;
-
-	spin_lock_irqsave(&self->lock, flags);
-	irport_stop(self);
-	spin_unlock_irqrestore(&self->lock, flags);
-
-	free_irq(self->io.irq, dev);
-
-	return 0;
-}
-
-/*
- * Function irport_is_receiving (self)
- *
- *    Returns true is we are currently receiving data
- *
- */
-static inline int irport_is_receiving(struct irport_cb *self)
-{
-	return (self->rx_buff.state != OUTSIDE_FRAME);
-}
-
-/*
- * Function irport_set_dtr_rts (tty, dtr, rts)
- *
- *    This function can be used by dongles etc. to set or reset the status
- *    of the dtr and rts lines
- */
-static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts)
-{
-	struct irport_cb *self = dev->priv;
-	int iobase;
-
-	IRDA_ASSERT(self != NULL, return -1;);
-
-	iobase = self->io.sir_base;
-
-	if (dtr)
-		dtr = UART_MCR_DTR;
-	if (rts)
-		rts = UART_MCR_RTS;
-
-	outb(dtr|rts|UART_MCR_OUT2, iobase+UART_MCR);
-
-	return 0;
-}
-
-static int irport_raw_write(struct net_device *dev, __u8 *buf, int len)
-{
-	struct irport_cb *self = (struct irport_cb *) dev->priv;
-	int actual = 0;
-	int iobase;
-
-	IRDA_ASSERT(self != NULL, return -1;);
-
-	iobase = self->io.sir_base;
-
-	/* Tx FIFO should be empty! */
-	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		IRDA_DEBUG( 0, "%s(), failed, fifo not empty!\n", __FUNCTION__);
-		return -1;
-	}
-        
-	/* Fill FIFO with current frame */
-	while (actual < len) {
-		/* Transmit next byte */
-		outb(buf[actual], iobase+UART_TX);
-		actual++;
-	}
-
-	return actual;
-}
-
-/*
- * Function irport_net_ioctl (dev, rq, cmd)
- *
- *    Process IOCTL commands for this device
- *
- */
-static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct if_irda_req *irq = (struct if_irda_req *) rq;
-	struct irport_cb *self;
-	dongle_t *dongle;
-	unsigned long flags;
-	int ret = 0;
-
-	IRDA_ASSERT(dev != NULL, return -1;);
-
-	self = dev->priv;
-
-	IRDA_ASSERT(self != NULL, return -1;);
-
-	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
-	
-	switch (cmd) {
-	case SIOCSBANDWIDTH: /* Set bandwidth */
-		if (!capable(CAP_NET_ADMIN))
-			ret = -EPERM;
-                else
-			irda_task_execute(self, __irport_change_speed, NULL, 
-					  NULL, (void *) irq->ifr_baudrate);
-		break;
-	case SIOCSDONGLE: /* Set dongle */
-		if (!capable(CAP_NET_ADMIN)) {
-			ret = -EPERM;
-			break;
-		}
-
-		/* Locking :
-		 * irda_device_dongle_init() can't be locked.
-		 * irda_task_execute() doesn't need to be locked.
-		 * Jean II
-		 */
-
-		/* Initialize dongle */
-		dongle = irda_device_dongle_init(dev, irq->ifr_dongle);
-		if (!dongle)
-			break;
-		
-		dongle->set_mode    = NULL;
-		dongle->read        = NULL;
-		dongle->write       = irport_raw_write;
-		dongle->set_dtr_rts = irport_set_dtr_rts;
-		
-		/* Now initialize the dongle!  */
-		dongle->issue->open(dongle, &self->qos);
-		
-		/* Reset dongle */
-		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
-				  NULL);	
-
-		/* Make dongle available to driver only now to avoid
-		 * race conditions - Jean II */
-		self->dongle = dongle;
-		break;
-	case SIOCSMEDIABUSY: /* Set media busy */
-		if (!capable(CAP_NET_ADMIN)) {
-			ret = -EPERM;
-			break;
-		}
-
-		irda_device_set_media_busy(self->netdev, TRUE);
-		break;
-	case SIOCGRECEIVING: /* Check if we are receiving right now */
-		irq->ifr_receiving = irport_is_receiving(self);
-		break;
-	case SIOCSDTRRTS:
-		if (!capable(CAP_NET_ADMIN)) {
-			ret = -EPERM;
-			break;
-		}
-
-		/* No real need to lock... */
-		spin_lock_irqsave(&self->lock, flags);
-		irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
-		spin_unlock_irqrestore(&self->lock, flags);
-		break;
-	default:
-		ret = -EOPNOTSUPP;
-	}
-	
-	return ret;
-}
-
-static struct net_device_stats *irport_net_get_stats(struct net_device *dev)
-{
-	struct irport_cb *self = (struct irport_cb *) dev->priv;
-	
-	return &self->stats;
-}
-
-static int __init irport_init(void)
-{
- 	int i;
-
- 	for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) {
- 		if (irport_open(i, io[i], irq[i]) != NULL)
- 			return 0;
- 	}
-	/* 
-	 * Maybe something failed, but we can still be usable for FIR drivers 
-	 */
- 	return 0;
-}
-
-/*
- * Function irport_cleanup ()
- *
- *    Close all configured ports
- *
- */
-static void __exit irport_cleanup(void)
-{
- 	int i;
-
-        IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
-
-	for (i=0; i < ARRAY_SIZE(dev_self); i++) {
- 		if (dev_self[i])
- 			irport_close(dev_self[i]);
- 	}
-}
-
-module_param_array(io, int, NULL, 0);
-MODULE_PARM_DESC(io, "Base I/O addresses");
-module_param_array(irq, int, NULL, 0);
-MODULE_PARM_DESC(irq, "IRQ lines");
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("Half duplex serial driver for IrDA SIR mode");
-MODULE_LICENSE("GPL");
-
-module_init(irport_init);
-module_exit(irport_cleanup);
-
diff --git a/drivers/net/irda/irport.h b/drivers/net/irda/irport.h
deleted file mode 100644
index 66fc2433e97d..000000000000
--- a/drivers/net/irda/irport.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irport.h
- * Version:       0.1
- * Description:   Serial driver for IrDA
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sun Aug  3 13:49:59 1997
- * Modified at:   Fri Jan 14 10:21:10 2000
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1997, 1998-2000 Dag Brattli <dagb@cs.uit.no>
- *     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.
- *
- ********************************************************************/
-
-#ifndef IRPORT_H
-#define IRPORT_H
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-#include <net/irda/irda_device.h>
-
-#define SPEED_DEFAULT 9600
-#define SPEED_MAX     115200
-
-/*
- * These are the supported serial types.
- */
-#define PORT_UNKNOWN    0
-#define PORT_8250       1
-#define PORT_16450      2
-#define PORT_16550      3
-#define PORT_16550A     4
-#define PORT_CIRRUS     5
-#define PORT_16650      6
-#define PORT_MAX        6  
-
-#define FRAME_MAX_SIZE 2048
-
-struct irport_cb {
-	struct net_device *netdev; /* Yes! we are some kind of netdevice */
-	struct net_device_stats stats;
-
-	struct irlap_cb *irlap;    /* The link layer we are attached to */
-
-	chipio_t io;               /* IrDA controller information */
-	iobuff_t tx_buff;          /* Transmit buffer */
-	iobuff_t rx_buff;          /* Receive buffer */
-
-	struct qos_info qos;       /* QoS capabilities for this device */
-	dongle_t *dongle;          /* Dongle driver */
-
- 	__u32 flags;               /* Interface flags */
-	__u32 new_speed;
-	int mode;
-	int index;                 /* Instance index */
-	int transmitting;	   /* Are we transmitting ? */
-
-	spinlock_t lock;           /* For serializing operations */
-
-	/* For piggyback drivers */
-	void *priv;                
-	void (*change_speed)(void *priv, __u32 speed);
-	irqreturn_t (*interrupt)(int irq, void *dev_id);
-};
-
-#endif /* IRPORT_H */
diff --git a/drivers/net/irda/litelink.c b/drivers/net/irda/litelink.c
deleted file mode 100644
index 7db11431d0f4..000000000000
--- a/drivers/net/irda/litelink.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      litelink.c
- * Version:       1.1
- * Description:   Driver for the Parallax LiteLink dongle
- * Status:        Stable
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Fri May  7 12:50:33 1999
- * Modified at:   Fri Dec 17 09:14:23 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1999 Dag Brattli, 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.
- * 
- *     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/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-#define MIN_DELAY 25      /* 15 us, but wait a little more to be sure */
-#define MAX_DELAY 10000   /* 1 ms */
-
-static void litelink_open(dongle_t *self, struct qos_info *qos);
-static void litelink_close(dongle_t *self);
-static int  litelink_change_speed(struct irda_task *task);
-static int  litelink_reset(struct irda_task *task);
-
-/* These are the baudrates supported */
-static __u32 baud_rates[] = { 115200, 57600, 38400, 19200, 9600 };
-
-static struct dongle_reg dongle = {
-	.type = IRDA_LITELINK_DONGLE,
-	.open = litelink_open,
-	.close = litelink_close,
-	.reset = litelink_reset,
-	.change_speed = litelink_change_speed,
-	.owner = THIS_MODULE,
-};
-
-static int __init litelink_init(void)
-{
-	return irda_device_register_dongle(&dongle);
-}
-
-static void __exit litelink_cleanup(void)
-{
-	irda_device_unregister_dongle(&dongle);
-}
-
-static void litelink_open(dongle_t *self, struct qos_info *qos)
-{
-	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-	qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
-}
-
-static void litelink_close(dongle_t *self)
-{
-	/* Power off dongle */
-	self->set_dtr_rts(self->dev, FALSE, FALSE);
-}
-
-/*
- * Function litelink_change_speed (task)
- *
- *    Change speed of the Litelink dongle. To cycle through the available 
- *    baud rates, pulse RTS low for a few ms.  
- */
-static int litelink_change_speed(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u32 speed = (__u32) task->param;
-        int i;
-	
-	/* Clear RTS to reset dongle */
-	self->set_dtr_rts(self->dev, TRUE, FALSE);
-
-	/* Sleep a minimum of 15 us */
-	udelay(MIN_DELAY);
-
-	/* Go back to normal mode */
-	self->set_dtr_rts(self->dev, TRUE, TRUE);
-	
-	/* Sleep a minimum of 15 us */
-	udelay(MIN_DELAY);
-	
-	/* Cycle through avaiable baudrates until we reach the correct one */
-	for (i=0; i<5 && baud_rates[i] != speed; i++) {
-		/* Set DTR, clear RTS */
-		self->set_dtr_rts(self->dev, FALSE, TRUE);
-		
-		/* Sleep a minimum of 15 us */
-		udelay(MIN_DELAY);
-		
-		/* Set DTR, Set RTS */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-		
-		/* Sleep a minimum of 15 us */
-		udelay(MIN_DELAY);
-        }
-	irda_task_next_state(task, IRDA_TASK_DONE);
-
-	return 0;
-}
-
-/*
- * Function litelink_reset (task)
- *
- *      Reset the Litelink type dongle.
- *
- */
-static int litelink_reset(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-
-	/* Power on dongle */
-	self->set_dtr_rts(self->dev, TRUE, TRUE);
-
-	/* Sleep a minimum of 15 us */
-	udelay(MIN_DELAY);
-
-	/* Clear RTS to reset dongle */
-	self->set_dtr_rts(self->dev, TRUE, FALSE);
-
-	/* Sleep a minimum of 15 us */
-	udelay(MIN_DELAY);
-
-	/* Go back to normal mode */
-	self->set_dtr_rts(self->dev, TRUE, TRUE);
-	
-	/* Sleep a minimum of 15 us */
-	udelay(MIN_DELAY);
-
-	/* This dongles speed defaults to 115200 bps */
-	self->speed = 115200;
-
-	irda_task_next_state(task, IRDA_TASK_DONE);
-
-	return 0;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("Parallax Litelink dongle driver");	
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-5"); /* IRDA_LITELINK_DONGLE */
-		
-/*
- * Function init_module (void)
- *
- *    Initialize Litelink module
- *
- */
-module_init(litelink_init);
-
-/*
- * Function cleanup_module (void)
- *
- *    Cleanup Litelink module
- *
- */
-module_exit(litelink_cleanup);
diff --git a/drivers/net/irda/ma600.c b/drivers/net/irda/ma600.c
deleted file mode 100644
index f5e6836667fd..000000000000
--- a/drivers/net/irda/ma600.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      ma600.c
- * Version:       0.1
- * Description:   Implementation of the MA600 dongle
- * Status:        Experimental.
- * Author:        Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95
- * Created at:    Sat Jun 10 20:02:35 2000
- * Modified at:   
- * Modified by:   
- *
- * Note: very thanks to Mr. Maru Wang <maru@mobileaction.com.tw> for providing 
- *       information on the MA600 dongle
- * 
- *     Copyright (c) 2000 Leung, 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.
- *  
- *     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
- *     
- ********************************************************************/
-
-/* define this macro for release version */
-//#define NDEBUG
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-#ifndef NDEBUG
-	#undef IRDA_DEBUG
-	#define IRDA_DEBUG(n, args...) (printk(KERN_DEBUG args))
-
-	#undef ASSERT
-	#define ASSERT(expr, func) \
-	if(!(expr)) { \
-	        printk( "Assertion failed! %s,%s,%s,line=%d\n",\
-        	#expr,__FILE__,__FUNCTION__,__LINE__); \
-	        func}
-#endif
-
-/* convert hex value to ascii hex */
-static const char hexTbl[] = "0123456789ABCDEF";
-
-
-static void ma600_open(dongle_t *self, struct qos_info *qos);
-static void ma600_close(dongle_t *self);
-static int  ma600_change_speed(struct irda_task *task);
-static int  ma600_reset(struct irda_task *task);
-
-/* control byte for MA600 */
-#define MA600_9600	0x00
-#define MA600_19200	0x01
-#define MA600_38400	0x02
-#define MA600_57600	0x03
-#define MA600_115200	0x04
-#define MA600_DEV_ID1	0x05
-#define MA600_DEV_ID2	0x06
-#define MA600_2400	0x08
-
-static struct dongle_reg dongle = {
-	.type = IRDA_MA600_DONGLE,
-	.open = ma600_open,
-	.close = ma600_close,
-	.reset = ma600_reset,
-	.change_speed = ma600_change_speed,
-	.owner = THIS_MODULE,
-};
-
-static int __init ma600_init(void)
-{
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
-	return irda_device_register_dongle(&dongle);
-}
-
-static void __exit ma600_cleanup(void)
-{
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
-	irda_device_unregister_dongle(&dongle);
-}
-
-/*
-	Power on:
-		(0) Clear RTS and DTR for 1 second
-		(1) Set RTS and DTR for 1 second
-		(2) 9600 bps now
-	Note: assume RTS, DTR are clear before
-*/
-static void ma600_open(dongle_t *self, struct qos_info *qos)
-{
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
-
-	qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400
-				|IR_57600|IR_115200;
-	qos->min_turn_time.bits = 0x01;		/* Needs at least 1 ms */	
-	irda_qos_bits_to_value(qos);
-
-	//self->set_dtr_rts(self->dev, FALSE, FALSE);
-	// should wait 1 second
-
-	self->set_dtr_rts(self->dev, TRUE, TRUE);
-	// should wait 1 second
-}
-
-static void ma600_close(dongle_t *self)
-{
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
-
-	/* Power off dongle */
-	self->set_dtr_rts(self->dev, FALSE, FALSE);
-}
-
-static __u8 get_control_byte(__u32 speed)
-{
-	__u8 byte;
-
-	switch (speed) {
-	default:
-	case 115200:
-		byte = MA600_115200;
-		break;
-	case 57600:
-		byte = MA600_57600;
-		break;
-	case 38400:
-		byte = MA600_38400;
-		break;
-	case 19200:
-		byte = MA600_19200;
-		break;
-	case 9600:
-		byte = MA600_9600;
-		break;
-	case 2400:
-		byte = MA600_2400;
-		break;
-	}
-
-	return byte;
-}
-
-/*
- * Function ma600_change_speed (dev, state, speed)
- *
- *    Set the speed for the MA600 type dongle. Warning, this 
- *    function must be called with a process context!
- *
- *    Algorithm
- *    1. Reset
- *    2. clear RTS, set DTR and wait for 1ms
- *    3. send Control Byte to the MA600 through TXD to set new baud rate
- *       wait until the stop bit of Control Byte is sent (for 9600 baud rate, 
- *       it takes about 10 msec)
- *    4. set RTS, set DTR (return to NORMAL Operation)
- *    5. wait at least 10 ms, new setting (baud rate, etc) takes effect here 
- *       after
- */
-static int ma600_change_speed(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u32 speed = (__u32) task->param;
-	static __u8 byte;
-	__u8 byte_echo;
-	int ret = 0;
-	
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
-
-	ASSERT(task != NULL, return -1;);
-
-	if (self->speed_task && self->speed_task != task) {
-		IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__);
-		return msecs_to_jiffies(10);
-	} else {
-		self->speed_task = task;
-	}
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-	case IRDA_TASK_CHILD_INIT:
-		/* 
-		 * Need to reset the dongle and go to 9600 bps before
-                 * programming 
-		 */
-		if (irda_task_execute(self, ma600_reset, NULL, task, 
-				      (void *) speed)) {
-			/* Dongle need more time to reset */
-			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
-	
-			/* give 1 second to finish */
-			ret = msecs_to_jiffies(1000);
-		} else {
-			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
-		}
-		break;
-
-	case IRDA_TASK_CHILD_WAIT:
-		IRDA_WARNING("%s(), resetting dongle timed out!\n",
-			     __FUNCTION__);
-		ret = -1;
-		break;
-
-	case IRDA_TASK_CHILD_DONE:
-		/* Set DTR, Clear RTS */
-		self->set_dtr_rts(self->dev, TRUE, FALSE);
-	
-		ret = msecs_to_jiffies(1);		/* Sleep 1 ms */
-		irda_task_next_state(task, IRDA_TASK_WAIT);
-		break;
-
-	case IRDA_TASK_WAIT:
-		speed = (__u32) task->param;
-		byte = get_control_byte(speed);
-
-		/* Write control byte */
-		self->write(self->dev, &byte, sizeof(byte));
-		
-		irda_task_next_state(task, IRDA_TASK_WAIT1);
-
-		/* Wait at least 10 ms */
-		ret = msecs_to_jiffies(15);
-		break;
-
-	case IRDA_TASK_WAIT1:
-		/* Read control byte echo */
-		self->read(self->dev, &byte_echo, sizeof(byte_echo));
-
-		if(byte != byte_echo) {
-			/* if control byte != echo, I don't know what to do */
-			printk(KERN_WARNING "%s() control byte written != read!\n", __FUNCTION__);
-			printk(KERN_WARNING "control byte = 0x%c%c\n", 
-			       hexTbl[(byte>>4)&0x0f], hexTbl[byte&0x0f]);
-			printk(KERN_WARNING "byte echo = 0x%c%c\n", 
-			       hexTbl[(byte_echo>>4) & 0x0f], 
-			       hexTbl[byte_echo & 0x0f]);
-		#ifndef NDEBUG
-		} else {
-			IRDA_DEBUG(2, "%s() control byte write read OK\n", __FUNCTION__);
-		#endif
-		}
-
-		/* Set DTR, Set RTS */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-
-		irda_task_next_state(task, IRDA_TASK_WAIT2);
-
-		/* Wait at least 10 ms */
-		ret = msecs_to_jiffies(10);
-		break;
-
-	case IRDA_TASK_WAIT2:
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->speed_task = NULL;
-		break;
-
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->speed_task = NULL;
-		ret = -1;
-		break;
-	}
-	return ret;
-}
-
-/*
- * Function ma600_reset (driver)
- *
- *      This function resets the ma600 dongle. Warning, this function 
- *      must be called with a process context!! 
- *
- *      Algorithm:
- *    	  0. DTR=0, RTS=1 and wait 10 ms
- *    	  1. DTR=1, RTS=1 and wait 10 ms
- *        2. 9600 bps now
- */
-int ma600_reset(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	int ret = 0;
-
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
-
-	ASSERT(task != NULL, return -1;);
-
-	if (self->reset_task && self->reset_task != task) {
-		IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__);
-		return msecs_to_jiffies(10);
-	} else
-		self->reset_task = task;
-	
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-		/* Clear DTR and Set RTS */
-		self->set_dtr_rts(self->dev, FALSE, TRUE);
-		irda_task_next_state(task, IRDA_TASK_WAIT1);
-		ret = msecs_to_jiffies(10);		/* Sleep 10 ms */
-		break;
-	case IRDA_TASK_WAIT1:
-		/* Set DTR and RTS */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-		irda_task_next_state(task, IRDA_TASK_WAIT2);
-		ret = msecs_to_jiffies(10);		/* Sleep 10 ms */
-		break;
-	case IRDA_TASK_WAIT2:
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->reset_task = NULL;
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);		
-		self->reset_task = NULL;
-		ret = -1;
-	}
-	return ret;
-}
-
-MODULE_AUTHOR("Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95");
-MODULE_DESCRIPTION("MA600 dongle driver version 0.1");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-11"); /* IRDA_MA600_DONGLE */
-		
-/*
- * Function init_module (void)
- *
- *    Initialize MA600 module
- *
- */
-module_init(ma600_init);
-
-/*
- * Function cleanup_module (void)
- *
- *    Cleanup MA600 module
- *
- */
-module_exit(ma600_cleanup);
-
diff --git a/drivers/net/irda/mcp2120.c b/drivers/net/irda/mcp2120.c
deleted file mode 100644
index 5e6199eeef4f..000000000000
--- a/drivers/net/irda/mcp2120.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*********************************************************************
- *            
- *    
- * Filename:      mcp2120.c
- * Version:       1.0
- * Description:   Implementation for the MCP2120 (Microchip)
- * Status:        Experimental.
- * Author:        Felix Tang (tangf@eyetap.org)
- * Created at:    Sun Mar 31 19:32:12 EST 2002
- * Based on code by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 2002 Felix Tang, 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.
- *  
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-static int  mcp2120_reset(struct irda_task *task);
-static void mcp2120_open(dongle_t *self, struct qos_info *qos);
-static void mcp2120_close(dongle_t *self);
-static int  mcp2120_change_speed(struct irda_task *task);
-
-#define MCP2120_9600    0x87
-#define MCP2120_19200   0x8B
-#define MCP2120_38400   0x85
-#define MCP2120_57600   0x83
-#define MCP2120_115200  0x81
-
-#define MCP2120_COMMIT  0x11
-
-static struct dongle_reg dongle = {
-	.type = IRDA_MCP2120_DONGLE,
-	.open = mcp2120_open,
-	.close = mcp2120_close,
-	.reset = mcp2120_reset,
-	.change_speed = mcp2120_change_speed,
-	.owner = THIS_MODULE,
-};
-
-static int __init mcp2120_init(void)
-{
-	return irda_device_register_dongle(&dongle);
-}
-
-static void __exit mcp2120_cleanup(void)
-{
-	irda_device_unregister_dongle(&dongle);
-}
-
-static void mcp2120_open(dongle_t *self, struct qos_info *qos)
-{
-	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-	qos->min_turn_time.bits = 0x01;
-}
-
-static void mcp2120_close(dongle_t *self)
-{
-	/* Power off dongle */
-        /* reset and inhibit mcp2120 */
-	self->set_dtr_rts(self->dev, TRUE, TRUE);
-	//self->set_dtr_rts(self->dev, FALSE, FALSE);
-}
-
-/*
- * Function mcp2120_change_speed (dev, speed)
- *
- *    Set the speed for the MCP2120.
- *
- */
-static int mcp2120_change_speed(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u32 speed = (__u32) task->param;
-	__u8 control[2];
-	int ret = 0;
-
-	self->speed_task = task;
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-		/* Need to reset the dongle and go to 9600 bps before
-                   programming */
-                //printk("Dmcp2120_change_speed irda_task_init\n");
-		if (irda_task_execute(self, mcp2120_reset, NULL, task, 
-				      (void *) speed))
-		{
-			/* Dongle need more time to reset */
-			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
-
-			/* Give reset 1 sec to finish */
-			ret = msecs_to_jiffies(1000);
-		}
-		break;
-	case IRDA_TASK_CHILD_WAIT:
-		IRDA_WARNING("%s(), resetting dongle timed out!\n",
-			     __FUNCTION__);
-		ret = -1;
-		break;
-	case IRDA_TASK_CHILD_DONE:
-		/* Set DTR to enter command mode */
-		self->set_dtr_rts(self->dev, TRUE, FALSE);
-                udelay(500);
-
-		switch (speed) {
-		case 9600:
-		default:
-			control[0] = MCP2120_9600;
-                        //printk("mcp2120 9600\n");
-			break;
-		case 19200:
-			control[0] = MCP2120_19200;
-                        //printk("mcp2120 19200\n");
-			break;
-		case 34800:
-			control[0] = MCP2120_38400;
-                        //printk("mcp2120 38400\n");
-			break;
-		case 57600:
-			control[0] = MCP2120_57600;
-                        //printk("mcp2120 57600\n");
-			break;
-		case 115200:
-                        control[0] = MCP2120_115200;
-                        //printk("mcp2120 115200\n");
-			break;
-		}
-	        control[1] = MCP2120_COMMIT;
-	
-		/* Write control bytes */
-                self->write(self->dev, control, 2);
- 
-                irda_task_next_state(task, IRDA_TASK_WAIT);
-		ret = msecs_to_jiffies(100);
-                //printk("mcp2120_change_speed irda_child_done\n");
-		break;
-	case IRDA_TASK_WAIT:
-		/* Go back to normal mode */
-		self->set_dtr_rts(self->dev, FALSE, FALSE);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->speed_task = NULL;
-                //printk("mcp2120_change_speed irda_task_wait\n");
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->speed_task = NULL;
-		ret = -1;
-		break;
-	}
-	return ret;
-}
-
-/*
- * Function mcp2120_reset (driver)
- *
- *      This function resets the mcp2120 dongle.
- *      
- *      Info: -set RTS to reset mcp2120
- *            -set DTR to set mcp2120 software command mode
- *            -mcp2120 defaults to 9600 baud after reset
- *
- *      Algorithm:
- *      0. Set RTS to reset mcp2120.
- *      1. Clear RTS and wait for device reset timer of 30 ms (max).
- *      
- */
-
-
-static int mcp2120_reset(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	int ret = 0;
-
-	self->reset_task = task;
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-                //printk("mcp2120_reset irda_task_init\n");
-		/* Reset dongle by setting RTS*/
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-		irda_task_next_state(task, IRDA_TASK_WAIT1);
-		ret = msecs_to_jiffies(50);
-		break;
-	case IRDA_TASK_WAIT1:
-                //printk("mcp2120_reset irda_task_wait1\n");
-                /* clear RTS and wait for at least 30 ms. */
-		self->set_dtr_rts(self->dev, FALSE, FALSE);
-		irda_task_next_state(task, IRDA_TASK_WAIT2);
-		ret = msecs_to_jiffies(50);
-		break;
-	case IRDA_TASK_WAIT2:
-                //printk("mcp2120_reset irda_task_wait2\n");
-		/* Go back to normal mode */
-		self->set_dtr_rts(self->dev, FALSE, FALSE);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->reset_task = NULL;
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->reset_task = NULL;
-		ret = -1;
-		break;
-	}
-	return ret;
-}
-
-MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>");
-MODULE_DESCRIPTION("Microchip MCP2120");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */
-	
-/*
- * Function init_module (void)
- *
- *    Initialize MCP2120 module
- *
- */
-module_init(mcp2120_init);
-
-/*
- * Function cleanup_module (void)
- *
- *    Cleanup MCP2120 module
- *
- */
-module_exit(mcp2120_cleanup);
diff --git a/drivers/net/irda/old_belkin.c b/drivers/net/irda/old_belkin.c
deleted file mode 100644
index 26f81fd28371..000000000000
--- a/drivers/net/irda/old_belkin.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      old_belkin.c
- * Version:       1.1
- * Description:   Driver for the Belkin (old) SmartBeam dongle
- * Status:        Experimental...
- * Author:        Jean Tourrilhes <jt@hpl.hp.com>
- * Created at:    22/11/99
- * Modified at:   Fri Dec 17 09:13:32 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1999 Jean Tourrilhes, 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.
- * 
- *     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/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-/*
- * Belkin is selling a dongle called the SmartBeam.
- * In fact, there is two hardware version of this dongle, of course with
- * the same name and looking the exactly same (grrr...).
- * I guess that I've got the old one, because inside I don't have
- * a jumper for IrDA/ASK...
- *
- * As far as I can make it from info on their web site, the old dongle 
- * support only 9600 b/s, which make our life much simpler as far as
- * the driver is concerned, but you might not like it very much ;-)
- * The new SmartBeam does 115 kb/s, and I've not tested it...
- *
- * Belkin claim that the correct driver for the old dongle (in Windows)
- * is the generic Parallax 9500a driver, but the Linux LiteLink driver
- * fails for me (probably because Linux-IrDA doesn't rate fallback),
- * so I created this really dumb driver...
- *
- * In fact, this driver doesn't do much. The only thing it does is to
- * prevent Linux-IrDA to use any other speed than 9600 b/s ;-) This
- * driver is called "old_belkin" so that when the new SmartBeam is supported
- * its driver can be called "belkin" instead of "new_belkin".
- *
- * Note : this driver was written without any info/help from Belkin,
- * so a lot of info here might be totally wrong. Blame me ;-)
- */
-
-/* Let's guess */
-#define MIN_DELAY 25      /* 15 us, but wait a little more to be sure */
-
-static void old_belkin_open(dongle_t *self, struct qos_info *qos);
-static void old_belkin_close(dongle_t *self);
-static int  old_belkin_change_speed(struct irda_task *task);
-static int  old_belkin_reset(struct irda_task *task);
-
-/* These are the baudrates supported */
-/* static __u32 baud_rates[] = { 9600 }; */
-
-static struct dongle_reg dongle = {
-	.type = IRDA_OLD_BELKIN_DONGLE,
-	.open = old_belkin_open,
-	.close = old_belkin_close,
-	.reset = old_belkin_reset,
-	.change_speed = old_belkin_change_speed,
-	.owner = THIS_MODULE,
-};
-
-static int __init old_belkin_init(void)
-{
-	return irda_device_register_dongle(&dongle);
-}
-
-static void __exit old_belkin_cleanup(void)
-{
-	irda_device_unregister_dongle(&dongle);
-}
-
-static void old_belkin_open(dongle_t *self, struct qos_info *qos)
-{
-	/* Not too fast, please... */
-	qos->baud_rate.bits &= IR_9600;
-	/* Needs at least 10 ms (totally wild guess, can do probably better) */
-	qos->min_turn_time.bits = 0x01;
-}
-
-static void old_belkin_close(dongle_t *self)
-{
-	/* Power off dongle */
-	self->set_dtr_rts(self->dev, FALSE, FALSE);
-}
-
-/*
- * Function old_belkin_change_speed (task)
- *
- *    With only one speed available, not much to do...
- */
-static int old_belkin_change_speed(struct irda_task *task)
-{
-	irda_task_next_state(task, IRDA_TASK_DONE);
-
-	return 0;
-}
-
-/*
- * Function old_belkin_reset (task)
- *
- *      Reset the Old-Belkin type dongle.
- *
- */
-static int old_belkin_reset(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-
-	/* Power on dongle */
-	self->set_dtr_rts(self->dev, TRUE, TRUE);
-
-	/* Sleep a minimum of 15 us */
-	udelay(MIN_DELAY);
-
-	/* This dongles speed "defaults" to 9600 bps ;-) */
-	self->speed = 9600;
-
-	irda_task_next_state(task, IRDA_TASK_DONE);
-
-	return 0;
-}
-
-MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
-MODULE_DESCRIPTION("Belkin (old) SmartBeam dongle driver");	
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-7"); /* IRDA_OLD_BELKIN_DONGLE */
-
-/*
- * Function init_module (void)
- *
- *    Initialize Old-Belkin module
- *
- */
-module_init(old_belkin_init);
-
-/*
- * Function cleanup_module (void)
- *
- *    Cleanup Old-Belkin module
- *
- */
-module_exit(old_belkin_cleanup);
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 7e7b5828214a..1f26da761e9f 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -1505,22 +1505,13 @@ static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
  *    An interrupt from the chip has arrived. Time to do some work
  *
  */
-static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id)
+static irqreturn_t smsc_ircc_interrupt(int dummy, void *dev_id)
 {
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct smsc_ircc_cb *self;
+	struct net_device *dev = dev_id;
+	struct smsc_ircc_cb *self = netdev_priv(dev);
 	int iobase, iir, lcra, lsr;
 	irqreturn_t ret = IRQ_NONE;
 
-	if (dev == NULL) {
-		printk(KERN_WARNING "%s: irq %d for unknown device.\n",
-		       driver_name, irq);
-		goto irq_ret;
-	}
-
-	self = netdev_priv(dev);
-	IRDA_ASSERT(self != NULL, return IRQ_NONE;);
-
 	/* Serialise the interrupt handler in various CPUs, stop Tx path */
 	spin_lock(&self->lock);
 
@@ -1565,7 +1556,7 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id)
 
  irq_ret_unlock:
 	spin_unlock(&self->lock);
- irq_ret:
+
 	return ret;
 }
 
diff --git a/drivers/net/irda/tekram.c b/drivers/net/irda/tekram.c
deleted file mode 100644
index 9bfd2441adbf..000000000000
--- a/drivers/net/irda/tekram.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      tekram.c
- * Version:       1.2
- * Description:   Implementation of the Tekram IrMate IR-210B dongle
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Fri Dec 17 09:13:09 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998-1999 Dag Brattli, 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.
- *     
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irda_device.h>
-
-static void tekram_open(dongle_t *self, struct qos_info *qos);
-static void tekram_close(dongle_t *self);
-static int  tekram_change_speed(struct irda_task *task);
-static int  tekram_reset(struct irda_task *task);
-
-#define TEKRAM_115200 0x00
-#define TEKRAM_57600  0x01
-#define TEKRAM_38400  0x02
-#define TEKRAM_19200  0x03
-#define TEKRAM_9600   0x04
-
-#define TEKRAM_PW     0x10 /* Pulse select bit */
-
-static struct dongle_reg dongle = {
-	.type = IRDA_TEKRAM_DONGLE,
-	.open  = tekram_open,
-	.close = tekram_close,
-	.reset = tekram_reset,
-	.change_speed = tekram_change_speed,
-	.owner = THIS_MODULE,
-};
-
-static int __init tekram_init(void)
-{
-	return irda_device_register_dongle(&dongle);
-}
-
-static void __exit tekram_cleanup(void)
-{
-	irda_device_unregister_dongle(&dongle);
-}
-
-static void tekram_open(dongle_t *self, struct qos_info *qos)
-{
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
-
-	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-	qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */	
-	irda_qos_bits_to_value(qos);
-}
-
-static void tekram_close(dongle_t *self)
-{
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
-
-	/* Power off dongle */
-	self->set_dtr_rts(self->dev, FALSE, FALSE);
-
-	if (self->reset_task)
-		irda_task_delete(self->reset_task);
-	if (self->speed_task)
-		irda_task_delete(self->speed_task);
-}
-
-/*
- * Function tekram_change_speed (dev, state, speed)
- *
- *    Set the speed for the Tekram IRMate 210 type dongle. Warning, this 
- *    function must be called with a process context!
- *
- *    Algorithm
- *    1. clear DTR 
- *    2. set RTS, and wait at least 7 us
- *    3. send Control Byte to the IR-210 through TXD to set new baud rate
- *       wait until the stop bit of Control Byte is sent (for 9600 baud rate, 
- *       it takes about 100 msec)
- *    5. clear RTS (return to NORMAL Operation)
- *    6. wait at least 50 us, new setting (baud rate, etc) takes effect here 
- *       after
- */
-static int tekram_change_speed(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u32 speed = (__u32) task->param;
-	__u8 byte;
-	int ret = 0;
-	
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
-
-	IRDA_ASSERT(task != NULL, return -1;);
-
-	if (self->speed_task && self->speed_task != task) {
-		IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__ );
-		return msecs_to_jiffies(10);
-	} else
-		self->speed_task = task;
-
-	switch (speed) {
-	default:
-	case 9600:
-		byte = TEKRAM_PW|TEKRAM_9600;
-		break;
-	case 19200:
-		byte = TEKRAM_PW|TEKRAM_19200;
-		break;
-	case 38400:
-		byte = TEKRAM_PW|TEKRAM_38400;
-		break;
-	case 57600:
-		byte = TEKRAM_PW|TEKRAM_57600;
-		break;
-	case 115200:
-		byte = TEKRAM_115200;
-		break;
-	}
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-	case IRDA_TASK_CHILD_INIT:		
-		/* 
-		 * Need to reset the dongle and go to 9600 bps before
-                 * programming 
-		 */
-		if (irda_task_execute(self, tekram_reset, NULL, task, 
-				      (void *) speed))
-		{
-			/* Dongle need more time to reset */
-			irda_task_next_state(task, IRDA_TASK_CHILD_WAIT);
-
-			/* Give reset 1 sec to finish */
-			ret = msecs_to_jiffies(1000);
-		} else
-			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
-		break;
-	case IRDA_TASK_CHILD_WAIT:
-		IRDA_WARNING("%s(), resetting dongle timed out!\n",
-			     __FUNCTION__);
-		ret = -1;
-		break;
-	case IRDA_TASK_CHILD_DONE:
-		/* Set DTR, Clear RTS */
-		self->set_dtr_rts(self->dev, TRUE, FALSE);
-	
-		/* Wait at least 7us */
-		udelay(14);
-
-		/* Write control byte */
-		self->write(self->dev, &byte, 1);
-		
-		irda_task_next_state(task, IRDA_TASK_WAIT);
-
-		/* Wait at least 100 ms */
-		ret = msecs_to_jiffies(150);
-		break;
-	case IRDA_TASK_WAIT:
-		/* Set DTR, Set RTS */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->speed_task = NULL;
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->speed_task = NULL;
-		ret = -1;
-		break;
-	}
-	return ret;
-}
-
-/*
- * Function tekram_reset (driver)
- *
- *      This function resets the tekram dongle. Warning, this function 
- *      must be called with a process context!! 
- *
- *      Algorithm:
- *    	  0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 )
- *        1. clear RTS 
- *        2. set DTR, and wait at least 1 ms 
- *        3. clear DTR to SPACE state, wait at least 50 us for further 
- *         operation
- */
-int tekram_reset(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	int ret = 0;
-
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
-
-	IRDA_ASSERT(task != NULL, return -1;);
-
-	if (self->reset_task && self->reset_task != task) {
-		IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__ );
-		return msecs_to_jiffies(10);
-	} else
-		self->reset_task = task;
-	
-	/* Power off dongle */
-	//self->set_dtr_rts(self->dev, FALSE, FALSE);
-	self->set_dtr_rts(self->dev, TRUE, TRUE);
-
-	switch (task->state) {
-	case IRDA_TASK_INIT:
-		irda_task_next_state(task, IRDA_TASK_WAIT1);
-
-		/* Sleep 50 ms */
-		ret = msecs_to_jiffies(50);
-		break;
-	case IRDA_TASK_WAIT1:
-		/* Clear DTR, Set RTS */
-		self->set_dtr_rts(self->dev, FALSE, TRUE); 
-
-		irda_task_next_state(task, IRDA_TASK_WAIT2);
-		
-		/* Should sleep 1 ms */
-		ret = msecs_to_jiffies(1);
-		break;
-	case IRDA_TASK_WAIT2:
-		/* Set DTR, Set RTS */
-		self->set_dtr_rts(self->dev, TRUE, TRUE);
-	
-		/* Wait at least 50 us */
-		udelay(75);
-
-		irda_task_next_state(task, IRDA_TASK_DONE);
-		self->reset_task = NULL;
-		break;
-	default:
-		IRDA_ERROR("%s(), unknown state %d\n",
-			   __FUNCTION__, task->state);
-		irda_task_next_state(task, IRDA_TASK_DONE);		
-		self->reset_task = NULL;
-		ret = -1;
-	}
-	return ret;
-}
-
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-0"); /* IRDA_TEKRAM_DONGLE */
-		
-/*
- * Function init_module (void)
- *
- *    Initialize Tekram module
- *
- */
-module_init(tekram_init);
-
-/*
- * Function cleanup_module (void)
- *
- *    Cleanup Tekram module
- *
- */
-module_exit(tekram_cleanup);
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 126ec7c8680e..58e128784585 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -1346,19 +1346,13 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase)
  *    An interrupt from the chip has arrived. Time to do some work
  *
  */
-static irqreturn_t via_ircc_interrupt(int irq, void *dev_id)
+static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id)
 {
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct via_ircc_cb *self;
+	struct net_device *dev = dev_id;
+	struct via_ircc_cb *self = dev->priv;
 	int iobase;
 	u8 iHostIntType, iRxIntType, iTxIntType;
 
-	if (!dev) {
-		IRDA_WARNING("%s: irq %d for unknown device.\n", driver_name,
-			     irq);
-		return IRQ_NONE;
-	}
-	self = (struct via_ircc_cb *) dev->priv;
 	iobase = self->io.fir_base;
 	spin_lock(&self->lock);
 	iHostIntType = GetHostStatus(iobase);
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 97bd9dc2e52e..419861cbc65e 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -815,7 +815,7 @@ static int veth_init_connection(u8 rlp)
 {
 	struct veth_lpar_connection *cnx;
 	struct veth_msg *msgs;
-	int i, rc;
+	int i;
 
 	if ( (rlp == this_lp)
 	     || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
@@ -844,11 +844,7 @@ static int veth_init_connection(u8 rlp)
 
 	/* This gets us 1 reference, which is held on behalf of the driver
 	 * infrastructure. It's released at module unload. */
-	kobject_init(&cnx->kobject);
-	cnx->kobject.ktype = &veth_lpar_connection_ktype;
-	rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp);
-	if (rc != 0)
-		return rc;
+	kobject_init(&cnx->kobject, &veth_lpar_connection_ktype);
 
 	msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL);
 	if (! msgs) {
@@ -1087,11 +1083,8 @@ static struct net_device * __init veth_probe_one(int vlan,
 		return NULL;
 	}
 
-	kobject_init(&port->kobject);
-	port->kobject.parent = &dev->dev.kobj;
-	port->kobject.ktype  = &veth_port_ktype;
-	kobject_set_name(&port->kobject, "veth_port");
-	if (0 != kobject_add(&port->kobject))
+	kobject_init(&port->kobject, &veth_port_ktype);
+	if (0 != kobject_add(&port->kobject, &dev->dev.kobj, "veth_port"))
 		veth_error("Failed adding port for %s to sysfs.\n", dev->name);
 
 	veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n",
@@ -1711,9 +1704,9 @@ static int __init veth_module_init(void)
 			continue;
 
 		kobj = &veth_cnx[i]->kobject;
-		kobj->parent = &veth_driver.driver.kobj;
 		/* If the add failes, complain but otherwise continue */
-		if (0 != kobject_add(kobj))
+		if (0 != driver_add_kobj(&veth_driver.driver, kobj,
+					"cnx%.2d", veth_cnx[i]->remote_lp))
 			veth_error("cnx %d: Failed adding to sysfs.\n", i);
 	}
 
diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c
index 2c6367ace3cd..80a8b9888225 100644
--- a/drivers/net/ixgb/ixgb_hw.c
+++ b/drivers/net/ixgb/ixgb_hw.c
@@ -45,6 +45,8 @@ static boolean_t ixgb_link_reset(struct ixgb_hw *hw);
 
 static void ixgb_optics_reset(struct ixgb_hw *hw);
 
+static void ixgb_optics_reset_bcm(struct ixgb_hw *hw);
+
 static ixgb_phy_type ixgb_identify_phy(struct ixgb_hw *hw);
 
 static void ixgb_clear_hw_cntrs(struct ixgb_hw *hw);
@@ -90,10 +92,20 @@ static uint32_t ixgb_mac_reset(struct ixgb_hw *hw)
 	ASSERT(!(ctrl_reg & IXGB_CTRL0_RST));
 #endif
 
-	if (hw->phy_type == ixgb_phy_type_txn17401) {
-		ixgb_optics_reset(hw);
+	if (hw->subsystem_vendor_id == SUN_SUBVENDOR_ID) {
+		ctrl_reg =  /* Enable interrupt from XFP and SerDes */
+			   IXGB_CTRL1_GPI0_EN |
+			   IXGB_CTRL1_SDP6_DIR |
+			   IXGB_CTRL1_SDP7_DIR |
+			   IXGB_CTRL1_SDP6 |
+			   IXGB_CTRL1_SDP7;
+		IXGB_WRITE_REG(hw, CTRL1, ctrl_reg);
+		ixgb_optics_reset_bcm(hw);
 	}
 
+	if (hw->phy_type == ixgb_phy_type_txn17401)
+		ixgb_optics_reset(hw);
+
 	return ctrl_reg;
 }
 
@@ -253,6 +265,10 @@ ixgb_identify_phy(struct ixgb_hw *hw)
 		break;
 	}
 
+	/* update phy type for sun specific board */
+	if (hw->subsystem_vendor_id == SUN_SUBVENDOR_ID)
+		phy_type = ixgb_phy_type_bcm;
+
 	return (phy_type);
 }
 
@@ -1225,3 +1241,65 @@ ixgb_optics_reset(struct ixgb_hw *hw)
 
 	return;
 }
+
+/******************************************************************************
+ * Resets the 10GbE optics module for Sun variant NIC.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+
+#define   IXGB_BCM8704_USER_PMD_TX_CTRL_REG         0xC803
+#define   IXGB_BCM8704_USER_PMD_TX_CTRL_REG_VAL     0x0164
+#define   IXGB_BCM8704_USER_CTRL_REG                0xC800
+#define   IXGB_BCM8704_USER_CTRL_REG_VAL            0x7FBF
+#define   IXGB_BCM8704_USER_DEV3_ADDR               0x0003
+#define   IXGB_SUN_PHY_ADDRESS                      0x0000
+#define   IXGB_SUN_PHY_RESET_DELAY                     305
+
+static void
+ixgb_optics_reset_bcm(struct ixgb_hw *hw)
+{
+	u32 ctrl = IXGB_READ_REG(hw, CTRL0);
+	ctrl &= ~IXGB_CTRL0_SDP2;
+	ctrl |= IXGB_CTRL0_SDP3;
+	IXGB_WRITE_REG(hw, CTRL0, ctrl);
+
+	/* SerDes needs extra delay */
+	msleep(IXGB_SUN_PHY_RESET_DELAY);
+
+	/* Broadcom 7408L configuration */
+	/* Reference clock config */
+	ixgb_write_phy_reg(hw,
+			   IXGB_BCM8704_USER_PMD_TX_CTRL_REG,
+			   IXGB_SUN_PHY_ADDRESS,
+			   IXGB_BCM8704_USER_DEV3_ADDR,
+			   IXGB_BCM8704_USER_PMD_TX_CTRL_REG_VAL);
+	/*  we must read the registers twice */
+	ixgb_read_phy_reg(hw,
+			  IXGB_BCM8704_USER_PMD_TX_CTRL_REG,
+			  IXGB_SUN_PHY_ADDRESS,
+			  IXGB_BCM8704_USER_DEV3_ADDR);
+	ixgb_read_phy_reg(hw,
+			  IXGB_BCM8704_USER_PMD_TX_CTRL_REG,
+			  IXGB_SUN_PHY_ADDRESS,
+			  IXGB_BCM8704_USER_DEV3_ADDR);
+
+	ixgb_write_phy_reg(hw,
+			   IXGB_BCM8704_USER_CTRL_REG,
+			   IXGB_SUN_PHY_ADDRESS,
+			   IXGB_BCM8704_USER_DEV3_ADDR,
+			   IXGB_BCM8704_USER_CTRL_REG_VAL);
+	ixgb_read_phy_reg(hw,
+			  IXGB_BCM8704_USER_CTRL_REG,
+			  IXGB_SUN_PHY_ADDRESS,
+			  IXGB_BCM8704_USER_DEV3_ADDR);
+	ixgb_read_phy_reg(hw,
+			  IXGB_BCM8704_USER_CTRL_REG,
+			  IXGB_SUN_PHY_ADDRESS,
+			  IXGB_BCM8704_USER_DEV3_ADDR);
+
+	/* SerDes needs extra delay */
+	msleep(IXGB_SUN_PHY_RESET_DELAY);
+
+	return;
+}
diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h
index af5643324ee3..4f176ff2b786 100644
--- a/drivers/net/ixgb/ixgb_hw.h
+++ b/drivers/net/ixgb/ixgb_hw.h
@@ -44,7 +44,8 @@ typedef enum {
 	ixgb_phy_type_g6005,	/* 850nm, MM fiber, XPAK transceiver */
 	ixgb_phy_type_g6104,	/* 1310nm, SM fiber, XPAK transceiver */
 	ixgb_phy_type_txn17201,	/* 850nm, MM fiber, XPAK transceiver */
-	ixgb_phy_type_txn17401	/* 1310nm, SM fiber, XENPAK transceiver */
+	ixgb_phy_type_txn17401,	/* 1310nm, SM fiber, XENPAK transceiver */
+	ixgb_phy_type_bcm	/* SUN specific board */
 } ixgb_phy_type;
 
 /* XPAK transceiver vendors, for the SR adapters */
@@ -534,12 +535,12 @@ typedef enum {
  * in which case the structure must be packed in some compiler-specific
  * manner. */
 struct ixgb_rx_desc {
-	uint64_t buff_addr;
-	uint16_t length;
-	uint16_t reserved;
+	__le64 buff_addr;
+	__le16 length;
+	__le16 reserved;
 	uint8_t status;
 	uint8_t errors;
-	uint16_t special;
+	__le16 special;
 };
 
 #define IXGB_RX_DESC_STATUS_DD    0x01
@@ -567,11 +568,11 @@ struct ixgb_rx_desc {
  * in which case the structure must be packed in some compiler-specific
  * manner. */
 struct ixgb_tx_desc {
-	uint64_t buff_addr;
-	uint32_t cmd_type_len;
+	__le64 buff_addr;
+	__le32 cmd_type_len;
 	uint8_t status;
 	uint8_t popts;
-	uint16_t vlan;
+	__le16 vlan;
 };
 
 #define IXGB_TX_DESC_LENGTH_MASK    0x000FFFFF
@@ -596,14 +597,14 @@ struct ixgb_tx_desc {
 struct ixgb_context_desc {
 	uint8_t ipcss;
 	uint8_t ipcso;
-	uint16_t ipcse;
+	__le16 ipcse;
 	uint8_t tucss;
 	uint8_t tucso;
-	uint16_t tucse;
-	uint32_t cmd_type_len;
+	__le16 tucse;
+	__le32 cmd_type_len;
 	uint8_t status;
 	uint8_t hdr_len;
-	uint16_t mss;
+	__le16 mss;
 };
 
 #define IXGB_CONTEXT_DESC_CMD_TCP 0x01000000
diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ixgb/ixgb_ids.h
index 4376e7e8fbef..180d20e793a5 100644
--- a/drivers/net/ixgb/ixgb_ids.h
+++ b/drivers/net/ixgb/ixgb_ids.h
@@ -35,7 +35,8 @@
 
 #define INTEL_VENDOR_ID             0x8086
 #define INTEL_SUBVENDOR_ID          0x8086
-
+#define SUN_VENDOR_ID               0x108E
+#define SUN_SUBVENDOR_ID            0x108E
 
 #define IXGB_DEVICE_ID_82597EX      0x1048   
 #define IXGB_DEVICE_ID_82597EX_SR   0x1A48   
@@ -46,6 +47,7 @@
 #define IXGB_DEVICE_ID_82597EX_CX4   0x109E
 #define IXGB_SUBDEVICE_ID_A00C  0xA00C
 #define IXGB_SUBDEVICE_ID_A01C  0xA01C
+#define IXGB_SUBDEVICE_ID_7036  0x7036
 
 #endif /* #ifndef _IXGB_IDS_H_ */
 /* End of File */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 4f63839051b0..269e6f805f47 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -36,7 +36,7 @@ static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-#define DRV_VERSION		"1.0.126-k2"DRIVERNAPI
+#define DRV_VERSION		"1.0.126-k4"DRIVERNAPI
 const char ixgb_driver_version[] = DRV_VERSION;
 static const char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
 
@@ -212,9 +212,11 @@ static void
 ixgb_irq_enable(struct ixgb_adapter *adapter)
 {
 	if(atomic_dec_and_test(&adapter->irq_sem)) {
-		IXGB_WRITE_REG(&adapter->hw, IMS,
-			       IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW |
-			       IXGB_INT_LSC);
+		u32 val = IXGB_INT_RXT0 | IXGB_INT_RXDMT0 |
+			  IXGB_INT_TXDW | IXGB_INT_LSC;
+		if (adapter->hw.subsystem_vendor_id == SUN_SUBVENDOR_ID)
+			val |= IXGB_INT_GPI0;
+		IXGB_WRITE_REG(&adapter->hw, IMS, val);
 		IXGB_WRITE_FLUSH(&adapter->hw);
 	}
 }
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index bc51432b8d26..a021a6e72641 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -234,14 +234,10 @@ enum ixbge_state_t {
 };
 
 enum ixgbe_boards {
-	board_82598AF,
-	board_82598EB,
-	board_82598AT,
+	board_82598,
 };
 
-extern struct ixgbe_info ixgbe_82598AF_info;
-extern struct ixgbe_info ixgbe_82598EB_info;
-extern struct ixgbe_info ixgbe_82598AT_info;
+extern struct ixgbe_info ixgbe_82598_info;
 
 extern char ixgbe_driver_name[];
 extern const char ixgbe_driver_version[];
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index 4d64673164ca..6321b059ce13 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -50,8 +50,6 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
 					    bool autoneg,
 					    bool autoneg_wait_to_complete);
 static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw);
-static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed,
-					 bool *link_up);
 static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
 					       bool autoneg,
 					       bool autoneg_wait_to_complete);
@@ -64,6 +62,28 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
 	hw->mac.num_tx_queues = IXGBE_82598_MAX_RX_QUEUES;
 	hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES;
 
+	/* PHY ops are filled in by default properly for Fiber only */
+	if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper) {
+		hw->mac.ops.setup_link = &ixgbe_setup_copper_link_82598;
+		hw->mac.ops.setup_link_speed = &ixgbe_setup_copper_link_speed_82598;
+		hw->mac.ops.get_link_settings =
+				&ixgbe_get_copper_link_settings_82598;
+
+		/* Call PHY identify routine to get the phy type */
+		ixgbe_identify_phy(hw);
+
+		switch (hw->phy.type) {
+		case ixgbe_phy_tn:
+			hw->phy.ops.setup_link = &ixgbe_setup_tnx_phy_link;
+			hw->phy.ops.check_link = &ixgbe_check_tnx_phy_link;
+			hw->phy.ops.setup_link_speed =
+					&ixgbe_setup_tnx_phy_link_speed;
+			break;
+		default:
+			break;
+		}
+	}
+
 	return 0;
 }
 
@@ -206,6 +226,7 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw)
 		autoc_reg |= hw->mac.link_mode_select;
 
 		IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+		IXGBE_WRITE_FLUSH(hw);
 		msleep(50);
 	}
 
@@ -314,7 +335,7 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw,
 		 * ixgbe_hw This will write the AUTOC register based on the new
 		 * stored values
 		 */
-		hw->phy.ops.setup(hw);
+		hw->mac.ops.setup_link(hw);
 	}
 
 	return status;
@@ -332,72 +353,18 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw,
  **/
 static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw)
 {
-	s32 status;
-	u32 speed = 0;
-	bool link_up = false;
-
-	/* Set up MAC */
-	hw->phy.ops.setup(hw);
+	s32 status = 0;
 
 	/* Restart autonegotiation on PHY */
-	status = hw->phy.ops.setup(hw);
-
-	/* Synchronize MAC to PHY speed */
-	if (status == 0)
-		status = hw->phy.ops.check(hw, &speed, &link_up);
-
-	return status;
-}
+	if (hw->phy.ops.setup_link)
+		status = hw->phy.ops.setup_link(hw);
 
-/**
- *  ixgbe_check_copper_link_82598 - Syncs MAC & PHY link settings
- *  @hw: pointer to hardware structure
- *  @speed: pointer to link speed
- *  @link_up: true if link is up, false otherwise
- *
- *  Reads the mac link, phy link, and synchronizes the MAC to PHY.
- **/
-static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed,
-					 bool *link_up)
-{
-	s32 status;
-	u32 phy_speed = 0;
-	bool phy_link = false;
+	/* Set MAC to KX/KX4 autoneg, which defaultis to Parallel detection */
+	hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX);
+	hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN;
 
-	/* This is the speed and link the MAC is set at */
-	hw->phy.ops.check(hw, speed, link_up);
-
-	/*
-	 * Check current speed and link status of the PHY register.
-	 * This is a vendor specific register and may have to
-	 * be changed for other copper PHYs.
-	 */
-	status = hw->phy.ops.check(hw, &phy_speed, &phy_link);
-
-	if ((status == 0) && (phy_link)) {
-		/*
-		 * Check current link status of the MACs link's register
-		 * matches that of the speed in the PHY register
-		 */
-		if (*speed != phy_speed) {
-			/*
-			 * The copper PHY requires 82598 attach type to be XAUI
-			 * for 10G and BX for 1G
-			 */
-			hw->mac.link_attach_type =
-				(IXGBE_AUTOC_10G_XAUI | IXGBE_AUTOC_1G_BX);
-
-			/* Synchronize the MAC speed to the PHY speed */
-			status = hw->phy.ops.setup_speed(hw, phy_speed, false,
-							  false);
-			if (status == 0)
-				hw->phy.ops.check(hw, speed, link_up);
-			else
-				status = IXGBE_ERR_LINK_SETUP;
-		}
-	} else {
-		*link_up = phy_link;
-	}
+	/* Set up MAC */
+	hw->mac.ops.setup_link(hw);
 
 	return status;
 }
@@ -415,16 +382,19 @@ static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
 					       bool autoneg,
 					       bool autoneg_wait_to_complete)
 {
-	s32 status;
-	bool link_up = 0;
+	s32 status = 0;
 
 	/* Setup the PHY according to input speed */
-	status = hw->phy.ops.setup_speed(hw, speed, autoneg,
-					  autoneg_wait_to_complete);
+	if (hw->phy.ops.setup_link_speed)
+		status = hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+						autoneg_wait_to_complete);
+
+	/* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */
+	hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX);
+	hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN;
 
-	/* Synchronize MAC to PHY speed */
-	if (status == 0)
-		status = hw->phy.ops.check(hw, &speed, &link_up);
+	/* Set up MAC */
+	hw->mac.ops.setup_link(hw);
 
 	return status;
 }
@@ -542,47 +512,15 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw)
 static struct ixgbe_mac_operations mac_ops_82598 = {
 	.reset			= &ixgbe_reset_hw_82598,
 	.get_media_type		= &ixgbe_get_media_type_82598,
+	.setup_link		= &ixgbe_setup_mac_link_82598,
+	.check_link		= &ixgbe_check_mac_link_82598,
+	.setup_link_speed	= &ixgbe_setup_mac_link_speed_82598,
+	.get_link_settings	= &ixgbe_get_link_settings_82598,
 };
 
-static struct ixgbe_phy_operations phy_ops_82598EB = {
-	.setup			= &ixgbe_setup_copper_link_82598,
-	.check			= &ixgbe_check_copper_link_82598,
-	.setup_speed		= &ixgbe_setup_copper_link_speed_82598,
-	.get_settings		= &ixgbe_get_copper_link_settings_82598,
-};
-
-struct ixgbe_info ixgbe_82598EB_info = {
-	.mac			= ixgbe_mac_82598EB,
-	.get_invariants		= &ixgbe_get_invariants_82598,
-	.mac_ops		= &mac_ops_82598,
-	.phy_ops		= &phy_ops_82598EB,
-};
-
-static struct ixgbe_phy_operations phy_ops_82598AT = {
-	.setup			= &ixgbe_setup_tnx_phy_link,
-	.check			= &ixgbe_check_tnx_phy_link,
-	.setup_speed		= &ixgbe_setup_tnx_phy_link_speed,
-	.get_settings		= &ixgbe_get_copper_link_settings_82598,
-};
-
-struct ixgbe_info ixgbe_82598AT_info = {
-	.mac			= ixgbe_mac_82598EB,
-	.get_invariants		= &ixgbe_get_invariants_82598,
-	.mac_ops		= &mac_ops_82598,
-	.phy_ops		= &phy_ops_82598AT,
-};
-
-static struct ixgbe_phy_operations phy_ops_82598AF = {
-	.setup			= &ixgbe_setup_mac_link_82598,
-	.check			= &ixgbe_check_mac_link_82598,
-	.setup_speed		= &ixgbe_setup_mac_link_speed_82598,
-	.get_settings		= &ixgbe_get_link_settings_82598,
-};
-
-struct ixgbe_info ixgbe_82598AF_info = {
+struct ixgbe_info ixgbe_82598_info = {
 	.mac			= ixgbe_mac_82598EB,
 	.get_invariants		= &ixgbe_get_invariants_82598,
 	.mac_ops		= &mac_ops_82598,
-	.phy_ops		= &phy_ops_82598AF,
 };
 
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index 512e3b22ed08..7fd6aeb1b021 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -74,7 +74,7 @@ s32 ixgbe_start_hw(struct ixgbe_hw *hw)
 	ixgbe_clear_vfta(hw);
 
 	/* Set up link */
-	hw->phy.ops.setup(hw);
+	hw->mac.ops.setup_link(hw);
 
 	/* Clear statistics registers */
 	ixgbe_clear_hw_cntrs(hw);
@@ -83,6 +83,7 @@ s32 ixgbe_start_hw(struct ixgbe_hw *hw)
 	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
 	ctrl_ext |= IXGBE_CTRL_EXT_NS_DIS;
 	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+	IXGBE_WRITE_FLUSH(hw);
 
 	/* Clear adapter stopped flag */
 	hw->adapter_stopped = false;
@@ -297,6 +298,7 @@ s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index)
 	led_reg &= ~IXGBE_LED_MODE_MASK(index);
 	led_reg |= IXGBE_LED_ON << IXGBE_LED_MODE_SHIFT(index);
 	IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+	IXGBE_WRITE_FLUSH(hw);
 
 	return 0;
 }
@@ -314,6 +316,7 @@ s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index)
 	led_reg &= ~IXGBE_LED_MODE_MASK(index);
 	led_reg |= IXGBE_LED_OFF << IXGBE_LED_MODE_SHIFT(index);
 	IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+	IXGBE_WRITE_FLUSH(hw);
 
 	return 0;
 }
@@ -496,6 +499,7 @@ static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw)
 	/* Release both semaphores by writing 0 to the bits SWESMBI and SMBI */
 	swsm &= ~(IXGBE_SWSM_SWESMBI | IXGBE_SWSM_SMBI);
 	IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+	IXGBE_WRITE_FLUSH(hw);
 }
 
 /**
@@ -950,7 +954,7 @@ s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num)
 	u32 rmcs_reg;
 
 	if (packetbuf_num < 0 || packetbuf_num > 7)
-		hw_dbg(hw, "Invalid packet buffer number [%d], expected range"
+		hw_dbg(hw, "Invalid packet buffer number [%d], expected range "
 		       "is 0-7\n", packetbuf_num);
 
 	frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL);
@@ -1132,7 +1136,7 @@ void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask)
 }
 
 /**
- *  ixgbe_read_analog_reg8- Reads 8 bit 82598 Atlas analog register
+ *  ixgbe_read_analog_reg8 - Reads 8 bit Atlas analog register
  *  @hw: pointer to hardware structure
  *  @reg: analog register to read
  *  @val: read value
@@ -1154,7 +1158,7 @@ s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val)
 }
 
 /**
- *  ixgbe_write_analog_reg8- Writes 8 bit Atlas analog register
+ *  ixgbe_write_analog_reg8 - Writes 8 bit Atlas analog register
  *  @hw: pointer to hardware structure
  *  @reg: atlas register to write
  *  @val: value to write
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index a4e576a0c543..36353447716d 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -96,8 +96,7 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
 		((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \
 		 ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \
 		 (sizeof(struct ixgbe_queue_stats) / sizeof(u64)))
-#define IXGBE_GLOBAL_STATS_LEN \
-	sizeof(ixgbe_gstrings_stats) / sizeof(struct ixgbe_stats)
+#define IXGBE_GLOBAL_STATS_LEN	ARRAY_SIZE(ixgbe_gstrings_stats)
 #define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
 
 static int ixgbe_get_settings(struct net_device *netdev,
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index a4265bc1cebb..3732dd6c4b2a 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -54,9 +54,7 @@ static const char ixgbe_copyright[] =
 	 "Copyright (c) 1999-2007 Intel Corporation.";
 
 static const struct ixgbe_info *ixgbe_info_tbl[] = {
-	[board_82598AF]			= &ixgbe_82598AF_info,
-	[board_82598EB]			= &ixgbe_82598EB_info,
-	[board_82598AT]			= &ixgbe_82598AT_info,
+	[board_82598]			= &ixgbe_82598_info,
 };
 
 /* ixgbe_pci_tbl - PCI Device ID Table
@@ -69,13 +67,13 @@ static const struct ixgbe_info *ixgbe_info_tbl[] = {
  */
 static struct pci_device_id ixgbe_pci_tbl[] = {
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT),
-	 board_82598AF },
+	 board_82598 },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT),
-	 board_82598AF },
+	 board_82598 },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT_DUAL_PORT),
-	 board_82598AT },
+	 board_82598 },
 	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4),
-	 board_82598EB },
+	 board_82598 },
 
 	/* required last entry */
 	{0, }
@@ -734,7 +732,7 @@ static int ixgbe_request_irq(struct ixgbe_adapter *adapter, u32 *num_rx_queues)
 {
 	struct net_device *netdev = adapter->netdev;
 	int flags, err;
-	irqreturn_t(*handler) (int, void *) = &ixgbe_intr;
+	irq_handler_t handler = ixgbe_intr;
 
 	flags = IRQF_SHARED;
 
@@ -1570,8 +1568,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
 		dev_err(&pdev->dev, "HW Init failed\n");
 		return -EIO;
 	}
-	if (hw->phy.ops.setup_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true,
-				   false)) {
+	if (hw->mac.ops.setup_link_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true,
+					 false)) {
 		dev_err(&pdev->dev, "Link Speed setup failed\n");
 		return -EIO;
 	}
@@ -2038,7 +2036,7 @@ static void ixgbe_watchdog(unsigned long data)
 	bool link_up;
 	u32 link_speed = 0;
 
-	adapter->hw.phy.ops.check(&adapter->hw, &(link_speed), &link_up);
+	adapter->hw.mac.ops.check_link(&adapter->hw, &(link_speed), &link_up);
 
 	if (link_up) {
 		if (!netif_carrier_ok(netdev)) {
@@ -2108,7 +2106,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
 		l4len = tcp_hdrlen(skb);
 		*hdr_len += l4len;
 
-		if (skb->protocol == ntohs(ETH_P_IP)) {
+		if (skb->protocol == htons(ETH_P_IP)) {
 			struct iphdr *iph = ip_hdr(skb);
 			iph->tot_len = 0;
 			iph->check = 0;
@@ -2149,7 +2147,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter,
 		type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
 				    IXGBE_ADVTXD_DTYP_CTXT);
 
-		if (skb->protocol == ntohs(ETH_P_IP))
+		if (skb->protocol == htons(ETH_P_IP))
 			type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
 		type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
 		context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
@@ -2204,7 +2202,7 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
 				    IXGBE_ADVTXD_DTYP_CTXT);
 
 		if (skb->ip_summed == CHECKSUM_PARTIAL) {
-			if (skb->protocol == ntohs(ETH_P_IP))
+			if (skb->protocol == htons(ETH_P_IP))
 				type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
 
 			if (skb->sk->sk_protocol == IPPROTO_TCP)
@@ -2404,7 +2402,7 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 		tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT);
 	}
 
-	if (skb->protocol == ntohs(ETH_P_IP))
+	if (skb->protocol == htons(ETH_P_IP))
 		tx_flags |= IXGBE_TX_FLAGS_IPV4;
 	first = tx_ring->next_to_use;
 	tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len);
@@ -2606,7 +2604,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
 
 	/* Setup hw api */
 	memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops));
-	memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops));
 
 	err = ii->get_invariants(hw);
 	if (err)
diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h
index 199e8f670f3a..aa3ea72e678e 100644
--- a/drivers/net/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ixgbe/ixgbe_phy.h
@@ -31,7 +31,6 @@
 
 #include "ixgbe_type.h"
 
-s32 ixgbe_init_shared_code_phy(struct ixgbe_hw *hw);
 s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw);
 s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
 s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index fdcde16a2a99..1ad7cb9c25a8 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -1003,19 +1003,19 @@
 struct ixgbe_legacy_tx_desc {
 	u64 buffer_addr;       /* Address of the descriptor's data buffer */
 	union {
-		u32 data;
+		__le32 data;
 		struct {
-			u16 length;    /* Data buffer length */
+			__le16 length;    /* Data buffer length */
 			u8 cso; /* Checksum offset */
 			u8 cmd; /* Descriptor control */
 		} flags;
 	} lower;
 	union {
-		u32 data;
+		__le32 data;
 		struct {
 			u8 status;     /* Descriptor status */
 			u8 css; /* Checksum start */
-			u16 vlan;
+			__le16 vlan;
 		} fields;
 	} upper;
 };
@@ -1023,61 +1023,61 @@ struct ixgbe_legacy_tx_desc {
 /* Transmit Descriptor - Advanced */
 union ixgbe_adv_tx_desc {
 	struct {
-		u64 buffer_addr;       /* Address of descriptor's data buf */
-		u32 cmd_type_len;
-		u32 olinfo_status;
+		__le64 buffer_addr;       /* Address of descriptor's data buf */
+		__le32 cmd_type_len;
+		__le32 olinfo_status;
 	} read;
 	struct {
-		u64 rsvd;       /* Reserved */
-		u32 nxtseq_seed;
-		u32 status;
+		__le64 rsvd;       /* Reserved */
+		__le32 nxtseq_seed;
+		__le32 status;
 	} wb;
 };
 
 /* Receive Descriptor - Legacy */
 struct ixgbe_legacy_rx_desc {
-	u64 buffer_addr; /* Address of the descriptor's data buffer */
-	u16 length;      /* Length of data DMAed into data buffer */
+	__le64 buffer_addr; /* Address of the descriptor's data buffer */
+	__le16 length;      /* Length of data DMAed into data buffer */
 	u16 csum;        /* Packet checksum */
 	u8 status;       /* Descriptor status */
 	u8 errors;       /* Descriptor Errors */
-	u16 vlan;
+	__le16 vlan;
 };
 
 /* Receive Descriptor - Advanced */
 union ixgbe_adv_rx_desc {
 	struct {
-		u64 pkt_addr; /* Packet buffer address */
-		u64 hdr_addr; /* Header buffer address */
+		__le64 pkt_addr; /* Packet buffer address */
+		__le64 hdr_addr; /* Header buffer address */
 	} read;
 	struct {
 		struct {
 			struct {
-				u16 pkt_info; /* RSS type, Packet type */
-				u16 hdr_info; /* Split Header, header len */
+				__le16 pkt_info; /* RSS type, Packet type */
+				__le16 hdr_info; /* Split Header, header len */
 			} lo_dword;
 			union {
-				u32 rss; /* RSS Hash */
+				__le32 rss; /* RSS Hash */
 				struct {
-					u16 ip_id; /* IP id */
+					__le16 ip_id; /* IP id */
 					u16 csum; /* Packet Checksum */
 				} csum_ip;
 			} hi_dword;
 		} lower;
 		struct {
-			u32 status_error; /* ext status/error */
-			u16 length; /* Packet length */
-			u16 vlan; /* VLAN tag */
+			__le32 status_error; /* ext status/error */
+			__le16 length; /* Packet length */
+			__le16 vlan; /* VLAN tag */
 		} upper;
 	} wb;  /* writeback */
 };
 
 /* Context descriptors */
 struct ixgbe_adv_tx_context_desc {
-	u32 vlan_macip_lens;
-	u32 seqnum_seed;
-	u32 type_tucmd_mlhl;
-	u32 mss_l4len_idx;
+	__le32 vlan_macip_lens;
+	__le32 seqnum_seed;
+	__le32 type_tucmd_mlhl;
+	__le32 mss_l4len_idx;
 };
 
 /* Adv Transmit Descriptor Config Masks */
@@ -1244,13 +1244,16 @@ struct ixgbe_hw;
 struct ixgbe_mac_operations {
 	s32 (*reset)(struct ixgbe_hw *);
 	enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *);
+	s32 (*setup_link)(struct ixgbe_hw *);
+	s32 (*check_link)(struct ixgbe_hw *, u32 *, bool *);
+	s32 (*setup_link_speed)(struct ixgbe_hw *, u32, bool, bool);
+	s32 (*get_link_settings)(struct ixgbe_hw *, u32 *, bool *);
 };
 
 struct ixgbe_phy_operations {
-	s32 (*setup)(struct ixgbe_hw *);
-	s32 (*check)(struct ixgbe_hw *, u32 *, bool *);
-	s32 (*setup_speed)(struct ixgbe_hw *, u32, bool, bool);
-	s32 (*get_settings)(struct ixgbe_hw *, u32 *, bool *);
+	s32 (*setup_link)(struct ixgbe_hw *);
+	s32 (*check_link)(struct ixgbe_hw *, u32 *, bool *);
+	s32 (*setup_link_speed)(struct ixgbe_hw *, u32, bool, bool);
 };
 
 struct ixgbe_mac_info {
@@ -1267,7 +1270,6 @@ struct ixgbe_mac_info {
 	bool				link_settings_loaded;
 };
 
-
 struct ixgbe_eeprom_info {
 	enum ixgbe_eeprom_type		type;
 	u16				word_size;
@@ -1290,7 +1292,6 @@ struct ixgbe_info {
 	enum ixgbe_mac_type		mac;
 	s32 				(*get_invariants)(struct ixgbe_hw *);
 	struct ixgbe_mac_operations	*mac_ops;
-	struct ixgbe_phy_operations	*phy_ops;
 };
 
 struct ixgbe_hw {
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index fa147cd5d68c..f2a6e7132241 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -64,8 +64,6 @@ struct pcpu_lstats {
 	unsigned long bytes;
 };
 
-#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
-
 /* KISS: just allocate small chunks and copy bits.
  *
  * So, in fact, this is documentation, explaining what we expect
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index c5095ecd8b11..591a7e4220c7 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -1144,14 +1144,13 @@ i596_handle_CU_completion(struct net_device *dev,
 }
 
 static irqreturn_t
-i596_interrupt (int irq, void *dev_instance) {
-	struct net_device *dev = (struct net_device *) dev_instance;
-	struct i596_private *lp;
+i596_interrupt(int irq, void *dev_instance)
+{
+	struct net_device *dev = dev_instance;
+	struct i596_private *lp = dev->priv;
 	unsigned short status, ack_cmd = 0;
 	int frames_in = 0;
 
-	lp = (struct i596_private *) dev->priv;
-
 	/*
 	 * The 82596 examines the command, performs the required action,
 	 * and then clears the SCB command word.
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index a19b5958cee9..2a66e5b7cebc 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -289,7 +289,7 @@ struct net_device * __init mac89x0_probe(int unit)
 	err = register_netdev(dev);
 	if (err)
 		goto out1;
-	return 0;
+	return NULL;
 out1:
 	nubus_writew(0, dev->base_addr + ADD_PORT);
 out:
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 95ebe72f320f..451acdca2a21 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -409,7 +409,7 @@ static inline void mace_clean_rings(struct mace_data *mp)
 
     /* free some skb's */
     for (i = 0; i < N_RX_RING; ++i) {
-	if (mp->rx_bufs[i] != 0) {
+	if (mp->rx_bufs[i] != NULL) {
 	    dev_kfree_skb(mp->rx_bufs[i]);
 	    mp->rx_bufs[i] = NULL;
 	}
@@ -441,7 +441,7 @@ static int mace_open(struct net_device *dev)
     cp = mp->rx_cmds;
     for (i = 0; i < N_RX_RING - 1; ++i) {
 	skb = dev_alloc_skb(RX_BUFLEN + 2);
-	if (skb == 0) {
+	if (!skb) {
 	    data = dummy_buf;
 	} else {
 	    skb_reserve(skb, 2);	/* so IP header lands on 4-byte bdry */
@@ -903,7 +903,7 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id)
 	out_le16(&cp->command, DBDMA_STOP);
 	/* got a packet, have a look at it */
 	skb = mp->rx_bufs[i];
-	if (skb == 0) {
+	if (!skb) {
 	    ++dev->stats.rx_dropped;
 	} else if (nb > 8) {
 	    data = skb->data;
@@ -953,9 +953,9 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id)
 	    break;
 	cp = mp->rx_cmds + i;
 	skb = mp->rx_bufs[i];
-	if (skb == 0) {
+	if (!skb) {
 	    skb = dev_alloc_skb(RX_BUFLEN + 2);
-	    if (skb != 0) {
+	    if (skb) {
 		skb_reserve(skb, 2);
 		mp->rx_bufs[i] = skb;
 	    }
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index e8dc2f44fec9..6ef6b8b39e71 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -73,8 +73,6 @@ static void macvlan_broadcast(struct sk_buff *skb,
 	for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
 		hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
 			dev = vlan->dev;
-			if (unlikely(!(dev->flags & IFF_UP)))
-				continue;
 
 			nskb = skb_clone(skb, GFP_ATOMIC);
 			if (nskb == NULL) {
@@ -215,6 +213,29 @@ static int macvlan_stop(struct net_device *dev)
 	return 0;
 }
 
+static int macvlan_set_mac_address(struct net_device *dev, void *p)
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+	struct net_device *lowerdev = vlan->lowerdev;
+	struct sockaddr *addr = p;
+	int err;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	if (!(dev->flags & IFF_UP))
+		goto out;
+
+	err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN);
+	if (err < 0)
+		return err;
+	dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+
+out:
+	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+	return 0;
+}
+
 static void macvlan_change_rx_flags(struct net_device *dev, int change)
 {
 	struct macvlan_dev *vlan = netdev_priv(dev);
@@ -302,6 +323,7 @@ static void macvlan_setup(struct net_device *dev)
 	dev->stop		= macvlan_stop;
 	dev->change_mtu		= macvlan_change_mtu;
 	dev->change_rx_flags	= macvlan_change_rx_flags;
+	dev->set_mac_address	= macvlan_set_mac_address;
 	dev->set_multicast_list	= macvlan_set_multicast_list;
 	dev->hard_start_xmit	= macvlan_hard_start_xmit;
 	dev->destructor		= free_netdev;
@@ -353,7 +375,7 @@ static void macvlan_transfer_operstate(struct net_device *dev)
 		if (!netif_carrier_ok(dev))
 			netif_carrier_on(dev);
 	} else {
-		if (netif_carrier_ok(lowerdev))
+		if (netif_carrier_ok(dev))
 			netif_carrier_off(dev);
 	}
 }
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index 50648738d679..535a4461d88c 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -202,7 +202,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET);
 	dev_cap->reserved_eqs = 1 << (field & 0xf);
 	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET);
-	dev_cap->max_eqs = 1 << (field & 0x7);
+	dev_cap->max_eqs = 1 << (field & 0xf);
 	MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET);
 	dev_cap->reserved_mtts = 1 << (field >> 4);
 	MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index c90958f6d3fe..cead81e80f0c 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -185,7 +185,7 @@ struct myri10ge_priv {
 	dma_addr_t fw_stats_bus;
 	struct pci_dev *pdev;
 	int msi_enabled;
-	__be32 link_state;
+	u32 link_state;
 	unsigned int rdma_tags_available;
 	int intr_coal_delay;
 	__be32 __iomem *intr_coal_delay_ptr;
@@ -576,7 +576,7 @@ static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp)
 	int status;
 
 	/* find running firmware header */
-	hdr_offset = ntohl(__raw_readl(mgp->sram + MCP_HEADER_PTR_OFFSET));
+	hdr_offset = swab32(readl(mgp->sram + MCP_HEADER_PTR_OFFSET));
 
 	if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > mgp->sram_size) {
 		dev_err(dev, "Running firmware has bad header offset (%d)\n",
@@ -1053,7 +1053,10 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
 		rx_frags[0].size -= MXGEFW_PAD;
 		len -= MXGEFW_PAD;
 		lro_receive_frags(&mgp->rx_done.lro_mgr, rx_frags,
-				  len, len, (void *)(unsigned long)csum, csum);
+				  len, len,
+				 /* opaque, will come back in get_frag_header */
+				  (void *)(__force unsigned long)csum,
+				  csum);
 		return 1;
 	}
 
@@ -1431,7 +1434,7 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
 };
 
 #define MYRI10GE_NET_STATS_LEN      21
-#define MYRI10GE_STATS_LEN  sizeof(myri10ge_gstrings_stats) / ETH_GSTRING_LEN
+#define MYRI10GE_STATS_LEN	ARRAY_SIZE(myri10ge_gstrings_stats)
 
 static void
 myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data)
@@ -1786,7 +1789,8 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
 	struct iphdr *iph;
 	u8 *va = page_address(frag->page) + frag->page_offset;
 	unsigned long ll_hlen;
-	__wsum csum = (__wsum) (unsigned long)priv;
+	/* passed opaque through lro_receive_frags() */
+	__wsum csum = (__force __wsum) (unsigned long)priv;
 
 	/* find the mac header, aborting if not IPv4 */
 
@@ -1967,7 +1971,7 @@ static int myri10ge_open(struct net_device *dev)
 		goto abort_with_rings;
 	}
 
-	mgp->link_state = htonl(~0U);
+	mgp->link_state = ~0U;
 	mgp->rdma_tags_available = 15;
 
 	lro_mgr = &mgp->rx_done.lro_mgr;
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 5ffbb8891647..31e047dd7bb3 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -306,9 +306,11 @@ static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
 
 static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
 {
+	struct net_device *dev = nt->np.dev;
+
 	DECLARE_MAC_BUF(mac);
 	return snprintf(buf, PAGE_SIZE, "%s\n",
-			print_mac(mac, nt->np.local_mac));
+			print_mac(mac, dev->dev_addr));
 }
 
 static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf)
@@ -667,7 +669,7 @@ static int netconsole_netdev_event(struct notifier_block *this,
 	struct netconsole_target *nt;
 	struct net_device *dev = ptr;
 
-	if (!(event == NETDEV_CHANGEADDR || event == NETDEV_CHANGENAME))
+	if (!(event == NETDEV_CHANGENAME))
 		goto done;
 
 	spin_lock_irqsave(&target_list_lock, flags);
@@ -675,10 +677,6 @@ static int netconsole_netdev_event(struct notifier_block *this,
 		netconsole_target_get(nt);
 		if (nt->np.dev == dev) {
 			switch (event) {
-			case NETDEV_CHANGEADDR:
-				memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN);
-				break;
-
 			case NETDEV_CHANGENAME:
 				strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
 				break;
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index a8f63c47b3cd..2bc5eaae141f 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -113,8 +113,8 @@
 #define FLUSH_SCHEDULED_WORK()	flush_workqueue(netxen_workq)
 extern struct workqueue_struct *netxen_workq;
 
-/* 
- * normalize a 64MB crb address to 32MB PCI window 
+/*
+ * normalize a 64MB crb address to 32MB PCI window
  * To use NETXEN_CRB_NORMALIZE, window _must_ be set to 1
  */
 #define NETXEN_CRB_NORMAL(reg)	\
@@ -736,11 +736,11 @@ struct netxen_skb_frag {
 	(config_word) &= ~__tmask;      \
 	(config_word) |= (((__tvalue) << (start)) & __tmask); \
 }
-	
+
 #define _netxen_clear_bits(config_word, start, bits) {\
 	unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));  \
 	(config_word) &= ~__tmask; \
-}		
+}
 
 /*    Following defines are for the state of the buffers    */
 #define	NETXEN_BUFFER_FREE	0
@@ -879,7 +879,7 @@ struct netxen_dummy_dma {
 
 struct netxen_adapter {
 	struct netxen_hardware_context ahw;
-	
+
 	struct netxen_adapter *master;
 	struct net_device *netdev;
 	struct pci_dev *pdev;
@@ -898,7 +898,7 @@ struct netxen_adapter {
 	u32 curr_window;
 
 	u32 cmd_producer;
-	u32 *cmd_consumer;
+	__le32 *cmd_consumer;
 
 	u32 last_cmd_consumer;
 	u32 max_tx_desc_count;
@@ -916,7 +916,7 @@ struct netxen_adapter {
 	u32 temp;
 
 	struct netxen_adapter_stats stats;
-	
+
 	u16 portno;
 	u16 link_speed;
 	u16 link_duplex;
@@ -1018,14 +1018,8 @@ int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter);
 int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter);
 int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter);
 int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter);
-int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter);
-int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter);
 void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter);
 void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter);
-void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port,
-				 long enable);
-void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port,
-				  long enable);
 int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
 			    __u32 * readval);
 int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
@@ -1048,7 +1042,6 @@ int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data,
 			   int len);
 void netxen_crb_writelit_adapter(struct netxen_adapter *adapter,
 				 unsigned long off, int data);
-int netxen_nic_erase_pxe(struct netxen_adapter *adapter);
 
 /* Functions from netxen_nic_init.c */
 void netxen_free_adapter_offload(struct netxen_adapter *adapter);
@@ -1057,9 +1050,9 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
 int netxen_load_firmware(struct netxen_adapter *adapter);
 int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose);
 int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp);
-int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, 
+int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
 				u8 *bytes, size_t size);
-int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, 
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr,
 				u8 *bytes, size_t size);
 int netxen_flash_unlock(struct netxen_adapter *adapter);
 int netxen_backup_crbinit(struct netxen_adapter *adapter);
@@ -1067,15 +1060,10 @@ int netxen_flash_erase_secondary(struct netxen_adapter *adapter);
 int netxen_flash_erase_primary(struct netxen_adapter *adapter);
 void netxen_halt_pegs(struct netxen_adapter *adapter);
 
-int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data);
 int netxen_rom_se(struct netxen_adapter *adapter, int addr);
-int netxen_do_rom_se(struct netxen_adapter *adapter, int addr);
 
 /* Functions from netxen_nic_isr.c */
 int netxen_nic_link_ok(struct netxen_adapter *adapter);
-void netxen_nic_isr_other(struct netxen_adapter *adapter);
-void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link);
-void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable);
 void netxen_initialize_adapter_sw(struct netxen_adapter *adapter);
 void netxen_initialize_adapter_hw(struct netxen_adapter *adapter);
 void *netxen_alloc(struct pci_dev *pdev, size_t sz, dma_addr_t * ptr,
@@ -1092,8 +1080,6 @@ int netxen_nic_tx_has_work(struct netxen_adapter *adapter);
 void netxen_watchdog_task(struct work_struct *work);
 void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx,
 			    u32 ringid);
-void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, u32 ctx,
-				 u32 ringid);
 int netxen_process_cmd_ring(unsigned long data);
 u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctx, int max);
 void netxen_nic_set_multi(struct net_device *netdev);
@@ -1209,7 +1195,7 @@ dma_watchdog_wakeup(struct netxen_adapter *adapter)
 
 
 int netxen_is_flash_supported(struct netxen_adapter *adapter);
-int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 mac[]);
+int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 mac[]);
 extern void netxen_change_ringparam(struct netxen_adapter *adapter);
 extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr,
 				int *valp);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index cfb847b0cae3..7a876f4b8db2 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -86,7 +86,7 @@ static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Link_Test_on_offline"
 };
 
-#define NETXEN_NIC_TEST_LEN sizeof(netxen_nic_gstrings_test) / ETH_GSTRING_LEN
+#define NETXEN_NIC_TEST_LEN	ARRAY_SIZE(netxen_nic_gstrings_test)
 
 #define NETXEN_NIC_REGS_COUNT 42
 #define NETXEN_NIC_REGS_LEN (NETXEN_NIC_REGS_COUNT * sizeof(__le32))
@@ -423,11 +423,11 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 	if (eeprom->len == 0)
 		return -EINVAL;
 
-	eeprom->magic = (adapter->pdev)->vendor | 
+	eeprom->magic = (adapter->pdev)->vendor |
 			((adapter->pdev)->device << 16);
 	offset = eeprom->offset;
 
-	ret = netxen_rom_fast_read_words(adapter, offset, bytes, 
+	ret = netxen_rom_fast_read_words(adapter, offset, bytes,
 						eeprom->len);
 	if (ret < 0)
 		return ret;
@@ -453,16 +453,16 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 				netxen_nic_driver_name);
 			return ret;
 		}
-		printk(KERN_INFO "%s: flash unlocked. \n", 
+		printk(KERN_INFO "%s: flash unlocked. \n",
 			netxen_nic_driver_name);
 		last_schedule_time = jiffies;
 		ret = netxen_flash_erase_secondary(adapter);
 		if (ret != FLASH_SUCCESS) {
-			printk(KERN_ERR "%s: Flash erase failed.\n", 
+			printk(KERN_ERR "%s: Flash erase failed.\n",
 				netxen_nic_driver_name);
 			return ret;
 		}
-		printk(KERN_INFO "%s: secondary flash erased successfully.\n", 
+		printk(KERN_INFO "%s: secondary flash erased successfully.\n",
 			netxen_nic_driver_name);
 		flash_start = 1;
 		return 0;
@@ -471,7 +471,7 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 	if (offset == NETXEN_BOOTLD_START) {
 		ret = netxen_flash_erase_primary(adapter);
 		if (ret != FLASH_SUCCESS) {
-			printk(KERN_ERR "%s: Flash erase failed.\n", 
+			printk(KERN_ERR "%s: Flash erase failed.\n",
 				netxen_nic_driver_name);
 			return ret;
 		}
@@ -483,16 +483,16 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 		if (ret != FLASH_SUCCESS)
 			return ret;
 
-		printk(KERN_INFO "%s: primary flash erased successfully\n", 
+		printk(KERN_INFO "%s: primary flash erased successfully\n",
 			netxen_nic_driver_name);
 
 		ret = netxen_backup_crbinit(adapter);
 		if (ret != FLASH_SUCCESS) {
-			printk(KERN_ERR "%s: CRBinit backup failed.\n", 
+			printk(KERN_ERR "%s: CRBinit backup failed.\n",
 				netxen_nic_driver_name);
 			return ret;
 		}
-		printk(KERN_INFO "%s: CRBinit backup done.\n", 
+		printk(KERN_INFO "%s: CRBinit backup done.\n",
 			netxen_nic_driver_name);
 		ready_to_flash = 1;
 	}
@@ -570,7 +570,7 @@ netxen_nic_get_pauseparam(struct net_device *dev,
 		else
 			pause->tx_pause = !(netxen_xg_get_xg1_mask(val));
 	} else {
-		printk(KERN_ERR"%s: Unknown board type: %x\n", 
+		printk(KERN_ERR"%s: Unknown board type: %x\n",
 				netxen_nic_driver_name, adapter->ahw.board_type);
 	}
 }
@@ -589,7 +589,7 @@ netxen_nic_set_pauseparam(struct net_device *dev,
 		/* set flow control */
 		netxen_nic_read_w0(adapter,
 					NETXEN_NIU_GB_MAC_CONFIG_0(port), &val);
-		
+
 		if (pause->rx_pause)
 			netxen_gb_rx_flowctl(val);
 		else
@@ -642,10 +642,10 @@ netxen_nic_set_pauseparam(struct net_device *dev,
 			else
 				netxen_xg_set_xg1_mask(val);
 		}
-		netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val);			
+		netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val);
 	} else {
 		printk(KERN_ERR "%s: Unknown board type: %x\n",
-				netxen_nic_driver_name, 
+				netxen_nic_driver_name,
 				adapter->ahw.board_type);
 	}
 	return 0;
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 2c19b8df98fa..01355701bf8e 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -33,7 +33,6 @@
 
 #include "netxen_nic.h"
 #include "netxen_nic_hw.h"
-#define DEFINE_GLOBAL_RECV_CRB
 #include "netxen_nic_phan_reg.h"
 
 
@@ -161,7 +160,7 @@ struct netxen_recv_crb recv_crb_registers[] = {
 	    },
 	    /* Jumbo frames */
 	    {
-	    /* crb_rcv_producer_offset: */		    
+	    /* crb_rcv_producer_offset: */
 	    NETXEN_NIC_REG(0x1f8),
 	    /* crb_rcv_consumer_offset: */
 	    NETXEN_NIC_REG(0x1fc),
@@ -210,7 +209,7 @@ struct netxen_recv_crb recv_crb_registers[] = {
 	    },
 	    /* Jumbo frames */
 	    {
-	    /* crb_rcv_producer_offset: */ 
+	    /* crb_rcv_producer_offset: */
 	    NETXEN_NIC_REG(0x23c),
 	    /* crb_rcv_consumer_offset: */
 	    NETXEN_NIC_REG(0x240),
@@ -244,12 +243,15 @@ struct netxen_recv_crb recv_crb_registers[] = {
 	},
 };
 
-u64 ctx_addr_sig_regs[][3] = {
+static u64 ctx_addr_sig_regs[][3] = {
 	{NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)},
 	{NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)},
 	{NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)},
 	{NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)}
 };
+#define CRB_CTX_ADDR_REG_LO(FUNC_ID)		(ctx_addr_sig_regs[FUNC_ID][0])
+#define CRB_CTX_ADDR_REG_HI(FUNC_ID)		(ctx_addr_sig_regs[FUNC_ID][2])
+#define CRB_CTX_SIGNATURE_REG(FUNC_ID)		(ctx_addr_sig_regs[FUNC_ID][1])
 
 
 /*  PCI Windowing for DDR regions.  */
@@ -279,8 +281,8 @@ u64 ctx_addr_sig_regs[][3] = {
 
 #define NETXEN_NIC_WINDOW_MARGIN 0x100000
 
-unsigned long netxen_nic_pci_set_window(struct netxen_adapter *adapter,
-					unsigned long long addr);
+static unsigned long netxen_nic_pci_set_window(struct netxen_adapter *adapter,
+					       unsigned long long addr);
 void netxen_free_hw_resources(struct netxen_adapter *adapter);
 
 int netxen_nic_set_mac(struct net_device *netdev, void *p)
@@ -417,7 +419,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
 	adapter->ctx_desc->cmd_consumer_offset =
 	    cpu_to_le64(adapter->ctx_desc_phys_addr +
 			sizeof(struct netxen_ring_ctx));
-	adapter->cmd_consumer = (uint32_t *) (((char *)addr) +
+	adapter->cmd_consumer = (__le32 *) (((char *)addr) +
 					      sizeof(struct netxen_ring_ctx));
 
 	addr = netxen_alloc(adapter->ahw.pdev,
@@ -584,35 +586,35 @@ int netxen_is_flash_supported(struct netxen_adapter *adapter)
 }
 
 static int netxen_get_flash_block(struct netxen_adapter *adapter, int base,
-				  int size, u32 * buf)
+				  int size, __le32 * buf)
 {
 	int i, addr;
-	u32 *ptr32;
+	__le32 *ptr32;
+	u32 v;
 
 	addr = base;
 	ptr32 = buf;
 	for (i = 0; i < size / sizeof(u32); i++) {
-		if (netxen_rom_fast_read(adapter, addr, ptr32) == -1)
+		if (netxen_rom_fast_read(adapter, addr, &v) == -1)
 			return -1;
-		*ptr32 = cpu_to_le32(*ptr32);
+		*ptr32 = cpu_to_le32(v);
 		ptr32++;
 		addr += sizeof(u32);
 	}
 	if ((char *)buf + size > (char *)ptr32) {
-		u32 local;
-
-		if (netxen_rom_fast_read(adapter, addr, &local) == -1)
+		__le32 local;
+		if (netxen_rom_fast_read(adapter, addr, &v) == -1)
 			return -1;
-		local = cpu_to_le32(local);
+		local = cpu_to_le32(v);
 		memcpy(ptr32, &local, (char *)buf + size - (char *)ptr32);
 	}
 
 	return 0;
 }
 
-int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 mac[])
+int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 mac[])
 {
-	u32 *pmac = (u32 *) & mac[0];
+	__le32 *pmac = (__le32 *) & mac[0];
 
 	if (netxen_get_flash_block(adapter,
 				   NETXEN_USER_START +
@@ -621,7 +623,7 @@ int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 mac[])
 				   FLASH_NUM_PORTS * sizeof(u64), pmac) == -1) {
 		return -1;
 	}
-	if (*mac == ~0ULL) {
+	if (*mac == cpu_to_le64(~0ULL)) {
 		if (netxen_get_flash_block(adapter,
 					   NETXEN_USER_START_OLD +
 					   offsetof(struct netxen_user_old_info,
@@ -629,7 +631,7 @@ int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 mac[])
 					   FLASH_NUM_PORTS * sizeof(u64),
 					   pmac) == -1)
 			return -1;
-		if (*mac == ~0ULL)
+		if (*mac == cpu_to_le64(~0ULL))
 			return -1;
 	}
 	return 0;
@@ -664,7 +666,7 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
 					NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F3));
 			break;
 		default:
-			printk(KERN_INFO "Changing the window for PCI function"
+			printk(KERN_INFO "Changing the window for PCI function "
 					"%d\n",	adapter->ahw.pci_func);
 			offset = PCI_OFFSET_SECOND_RANGE(adapter,
 					NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
@@ -886,11 +888,10 @@ void netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index, u32 * value)
 	netxen_nic_pci_change_crbwindow(adapter, 1);
 }
 
-int netxen_pci_set_window_warning_count = 0;
+static int netxen_pci_set_window_warning_count;
 
-unsigned long
-netxen_nic_pci_set_window(struct netxen_adapter *adapter,
-			  unsigned long long addr)
+static  unsigned long netxen_nic_pci_set_window(struct netxen_adapter *adapter,
+						unsigned long long addr)
 {
 	static int ddr_mn_window = -1;
 	static int qdr_sn_window = -1;
@@ -952,16 +953,18 @@ netxen_nic_pci_set_window(struct netxen_adapter *adapter,
 	return addr;
 }
 
+#if 0
 int
 netxen_nic_erase_pxe(struct netxen_adapter *adapter)
 {
 	if (netxen_rom_fast_write(adapter, NETXEN_PXE_START, 0) == -1) {
-		printk(KERN_ERR "%s: erase pxe failed\n", 
+		printk(KERN_ERR "%s: erase pxe failed\n",
 			netxen_nic_driver_name);
 		return -1;
 	}
 	return 0;
 }
+#endif  /*  0  */
 
 int netxen_nic_get_board_info(struct netxen_adapter *adapter)
 {
@@ -1036,9 +1039,9 @@ int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu)
 {
 	new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE;
 	if (physical_port[adapter->portnum] == 0)
-		netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, 
+		netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE,
 				new_mtu);
-	else 
+	else
 		netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE,
 				new_mtu);
 	return 0;
diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h
index 245bf13c7ba2..a3ea1dd98c41 100644
--- a/drivers/net/netxen/netxen_nic_hw.h
+++ b/drivers/net/netxen/netxen_nic_hw.h
@@ -235,7 +235,7 @@ typedef enum {
 	((config_word) |= 1 << 0)
 #define netxen_xg_set_xg1_mask(config_word)    \
 	((config_word) |= 1 << 3)
-		
+
 #define netxen_xg_get_xg0_mask(config_word)    \
 	_netxen_crb_get_bit((config_word), 0)
 #define netxen_xg_get_xg1_mask(config_word)    \
@@ -273,7 +273,7 @@ typedef enum {
 	_netxen_crb_get_bit((config_word), 4)
 #define netxen_gb_get_gb3_mask(config_word)    \
 	_netxen_crb_get_bit((config_word), 6)
-	
+
 #define netxen_gb_unset_gb0_mask(config_word)  \
 	((config_word) &= ~(1 << 0))
 #define netxen_gb_unset_gb1_mask(config_word)  \
@@ -437,7 +437,7 @@ typedef enum {
 
 /*
  * NIU GB Drop CRC Register
- * 
+ *
  * Bit 0 : drop_gb0 => 1:drop pkts with bad CRCs, 0:pass them on
  * Bit 1 : drop_gb1 => 1:drop pkts with bad CRCs, 0:pass them on
  * Bit 2 : drop_gb2 => 1:drop pkts with bad CRCs, 0:pass them on
@@ -480,7 +480,7 @@ typedef enum {
 
 /*
  * MAC Control Register
- * 
+ *
  * Bit 0-1   : id_pool0
  * Bit 2     : enable_xtnd0
  * Bit 4-5   : id_pool1
@@ -515,20 +515,16 @@ typedef enum {
 		((config) |= (((val) & 0x0f) << 28))
 
 /* Set promiscuous mode for a GbE interface */
-int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, 
+int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
 				    netxen_niu_prom_mode_t mode);
 int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
 				       netxen_niu_prom_mode_t mode);
 
-/* get/set the MAC address for a given MAC */
-int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
-			   netxen_ethernet_macaddr_t * addr);
+/* set the MAC address for a given MAC */
 int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
 			   netxen_ethernet_macaddr_t addr);
 
-/* XG versons */
-int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
-			      netxen_ethernet_macaddr_t * addr);
+/* XG version */
 int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
 			      netxen_ethernet_macaddr_t addr);
 
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 485ff9398910..9e38bcb3fba9 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -54,13 +54,17 @@ static unsigned int crb_addr_xform[NETXEN_MAX_CRB_XFORM];
 
 #define NETXEN_NIC_XDMA_RESET 0x8000ff
 
-static inline void
-netxen_nic_locked_write_reg(struct netxen_adapter *adapter,
-			    unsigned long off, int *data)
+static void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
+					uint32_t ctx, uint32_t ringid);
+
+#if 0
+static void netxen_nic_locked_write_reg(struct netxen_adapter *adapter,
+					unsigned long off, int *data)
 {
 	void __iomem *addr = pci_base_offset(adapter, off);
 	writel(*data, addr);
 }
+#endif  /*  0  */
 
 static void crb_addr_transform_setup(void)
 {
@@ -255,7 +259,7 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter)
  * netxen_decode_crb_addr(0 - utility to translate from internal Phantom CRB
  * address to external PCI CRB address.
  */
-u32 netxen_decode_crb_addr(u32 addr)
+static u32 netxen_decode_crb_addr(u32 addr)
 {
 	int i;
 	u32 base_addr, offset, pci_base;
@@ -282,7 +286,7 @@ static long rom_max_timeout = 100;
 static long rom_lock_timeout = 10000;
 static long rom_write_timeout = 700;
 
-static inline int rom_lock(struct netxen_adapter *adapter)
+static int rom_lock(struct netxen_adapter *adapter)
 {
 	int iter;
 	u32 done = 0;
@@ -312,7 +316,7 @@ static inline int rom_lock(struct netxen_adapter *adapter)
 	return 0;
 }
 
-int netxen_wait_rom_done(struct netxen_adapter *adapter)
+static int netxen_wait_rom_done(struct netxen_adapter *adapter)
 {
 	long timeout = 0;
 	long done = 0;
@@ -329,7 +333,7 @@ int netxen_wait_rom_done(struct netxen_adapter *adapter)
 	return 0;
 }
 
-static inline int netxen_rom_wren(struct netxen_adapter *adapter)
+static int netxen_rom_wren(struct netxen_adapter *adapter)
 {
 	/* Set write enable latch in ROM status register */
 	netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
@@ -341,15 +345,15 @@ static inline int netxen_rom_wren(struct netxen_adapter *adapter)
 	return 0;
 }
 
-static inline unsigned int netxen_rdcrbreg(struct netxen_adapter *adapter,
-					   unsigned int addr)
+static unsigned int netxen_rdcrbreg(struct netxen_adapter *adapter,
+				    unsigned int addr)
 {
 	unsigned int data = 0xdeaddead;
 	data = netxen_nic_reg_read(adapter, addr);
 	return data;
 }
 
-static inline int netxen_do_rom_rdsr(struct netxen_adapter *adapter)
+static int netxen_do_rom_rdsr(struct netxen_adapter *adapter)
 {
 	netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE,
 			     M25P_INSTR_RDSR);
@@ -359,7 +363,7 @@ static inline int netxen_do_rom_rdsr(struct netxen_adapter *adapter)
 	return netxen_rdcrbreg(adapter, NETXEN_ROMUSB_ROM_RDATA);
 }
 
-static inline void netxen_rom_unlock(struct netxen_adapter *adapter)
+static void netxen_rom_unlock(struct netxen_adapter *adapter)
 {
 	u32 val;
 
@@ -368,7 +372,7 @@ static inline void netxen_rom_unlock(struct netxen_adapter *adapter)
 
 }
 
-int netxen_rom_wip_poll(struct netxen_adapter *adapter)
+static int netxen_rom_wip_poll(struct netxen_adapter *adapter)
 {
 	long timeout = 0;
 	long wip = 1;
@@ -385,8 +389,8 @@ int netxen_rom_wip_poll(struct netxen_adapter *adapter)
 	return 0;
 }
 
-static inline int do_rom_fast_write(struct netxen_adapter *adapter, int addr,
-				    int data)
+static int do_rom_fast_write(struct netxen_adapter *adapter, int addr,
+			     int data)
 {
 	if (netxen_rom_wren(adapter)) {
 		return -1;
@@ -404,8 +408,8 @@ static inline int do_rom_fast_write(struct netxen_adapter *adapter, int addr,
 	return netxen_rom_wip_poll(adapter);
 }
 
-static inline int
-do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
+static int do_rom_fast_read(struct netxen_adapter *adapter,
+			    int addr, int *valp)
 {
 	cond_resched();
 
@@ -427,18 +431,18 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
 	return 0;
 }
 
-static inline int 
-do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
-			u8 *bytes, size_t size)
+static int do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+				  u8 *bytes, size_t size)
 {
 	int addridx;
 	int ret = 0;
 
 	for (addridx = addr; addridx < (addr + size); addridx += 4) {
-		ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
+		int v;
+		ret = do_rom_fast_read(adapter, addridx, &v);
 		if (ret != 0)
 			break;
-		*(int *)bytes = cpu_to_le32(*(int *)bytes);
+		*(__le32 *)bytes = cpu_to_le32(v);
 		bytes += 4;
 	}
 
@@ -446,7 +450,7 @@ do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
 }
 
 int
-netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, 
+netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
 				u8 *bytes, size_t size)
 {
 	int ret;
@@ -473,6 +477,7 @@ int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
 	return ret;
 }
 
+#if 0
 int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data)
 {
 	int ret = 0;
@@ -484,9 +489,10 @@ int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data)
 	netxen_rom_unlock(adapter);
 	return ret;
 }
+#endif  /*  0  */
 
-static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, 
-						int addr, u8 *bytes, size_t size)
+static int do_rom_fast_write_words(struct netxen_adapter *adapter,
+				   int addr, u8 *bytes, size_t size)
 {
 	int addridx = addr;
 	int ret = 0;
@@ -496,11 +502,11 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter,
 		int timeout = 0;
 		int data;
 
-		data = le32_to_cpu((*(u32*)bytes));
+		data = le32_to_cpu((*(__le32*)bytes));
 		ret = do_rom_fast_write(adapter, addridx, data);
 		if (ret < 0)
 			return ret;
-			
+
 		while(1) {
 			int data1;
 
@@ -513,7 +519,7 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter,
 
 			if (timeout++ >= rom_write_timeout) {
 				if (last_attempt++ < 4) {
-					ret = do_rom_fast_write(adapter, 
+					ret = do_rom_fast_write(adapter,
 								addridx, data);
 					if (ret < 0)
 						return ret;
@@ -533,7 +539,7 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter,
 	return ret;
 }
 
-int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, 
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr,
 					u8 *bytes, size_t size)
 {
 	int ret = 0;
@@ -548,7 +554,7 @@ int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr,
 	return ret;
 }
 
-int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
+static int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
 {
 	int ret;
 
@@ -557,7 +563,7 @@ int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
 		return ret;
 
 	netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data);
-	netxen_crb_writelit_adapter(adapter, 
+	netxen_crb_writelit_adapter(adapter,
 					NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0x1);
 
 	ret = netxen_wait_rom_done(adapter);
@@ -567,7 +573,7 @@ int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
 	return netxen_rom_wip_poll(adapter);
 }
 
-int netxen_rom_rdsr(struct netxen_adapter *adapter)
+static int netxen_rom_rdsr(struct netxen_adapter *adapter)
 {
 	int ret;
 
@@ -587,7 +593,7 @@ int netxen_backup_crbinit(struct netxen_adapter *adapter)
 	char *buffer = kmalloc(NETXEN_FLASH_SECTOR_SIZE, GFP_KERNEL);
 
 	if (!buffer)
-		return -ENOMEM;	
+		return -ENOMEM;
 	/* unlock sector 63 */
 	val = netxen_rom_rdsr(adapter);
 	val = val & 0xe3;
@@ -600,12 +606,12 @@ int netxen_backup_crbinit(struct netxen_adapter *adapter)
 		goto out_kfree;
 
 	/* copy  sector 0 to sector 63 */
-	ret = netxen_rom_fast_read_words(adapter, NETXEN_CRBINIT_START, 
+	ret = netxen_rom_fast_read_words(adapter, NETXEN_CRBINIT_START,
 					buffer, NETXEN_FLASH_SECTOR_SIZE);
 	if (ret != FLASH_SUCCESS)
 		goto out_kfree;
 
-	ret = netxen_rom_fast_write_words(adapter, NETXEN_FIXED_START, 
+	ret = netxen_rom_fast_write_words(adapter, NETXEN_FIXED_START,
 					buffer, NETXEN_FLASH_SECTOR_SIZE);
 	if (ret != FLASH_SUCCESS)
 		goto out_kfree;
@@ -632,7 +638,7 @@ out_kfree:
 	return ret;
 }
 
-int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
+static int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
 {
 	netxen_rom_wren(adapter);
 	netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
@@ -646,16 +652,16 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
 	return netxen_rom_wip_poll(adapter);
 }
 
-void check_erased_flash(struct netxen_adapter *adapter, int addr)
+static void check_erased_flash(struct netxen_adapter *adapter, int addr)
 {
 	int i;
 	int val;
 	int count = 0, erased_errors = 0;
 	int range;
 
-	range = (addr == NETXEN_USER_START) ? 
+	range = (addr == NETXEN_USER_START) ?
 		NETXEN_FIXED_START : addr + NETXEN_FLASH_SECTOR_SIZE;
-	
+
 	for (i = addr; i < range; i += 4) {
 		netxen_rom_fast_read(adapter, i, &val);
 		if (val != 0xffffffff)
@@ -682,8 +688,8 @@ int netxen_rom_se(struct netxen_adapter *adapter, int addr)
 	return ret;
 }
 
-int
-netxen_flash_erase_sections(struct netxen_adapter *adapter, int start, int end)
+static int netxen_flash_erase_sections(struct netxen_adapter *adapter,
+				       int start, int end)
 {
 	int ret = FLASH_SUCCESS;
 	int i;
@@ -990,7 +996,7 @@ int netxen_nic_rx_has_work(struct netxen_adapter *adapter)
 	return 0;
 }
 
-static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
+static int netxen_nic_check_temp(struct netxen_adapter *adapter)
 {
 	struct net_device *netdev = adapter->netdev;
 	uint32_t temp, temp_state, temp_val;
@@ -1064,9 +1070,8 @@ void netxen_watchdog_task(struct work_struct *work)
  * and if the number of receives exceeds RX_BUFFERS_REFILL, then we
  * invoke the routine to send more rx buffers to the Phantom...
  */
-void
-netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
-		   struct status_desc *desc)
+static void netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
+			       struct status_desc *desc)
 {
 	struct pci_dev *pdev = adapter->pdev;
 	struct net_device *netdev = adapter->netdev;
@@ -1103,8 +1108,8 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
 		}
 		if (buffer->lro_current_frags != buffer->lro_expected_frags) {
 			if (buffer->lro_expected_frags != 0) {
-				printk("LRO: (refhandle:%x) recv frag."
-				       "wait for last. flags: %x expected:%d"
+				printk("LRO: (refhandle:%x) recv frag. "
+				       "wait for last. flags: %x expected:%d "
 				       "have:%d\n", index,
 				       netxen_get_sts_desc_lro_last_frag(desc),
 				       buffer->lro_expected_frags,
@@ -1458,8 +1463,8 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
 	}
 }
 
-void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
-				 uint32_t ringid)
+static void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
+					uint32_t ctx, uint32_t ringid)
 {
 	struct pci_dev *pdev = adapter->ahw.pdev;
 	struct sk_buff *skb;
@@ -1491,7 +1496,7 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
 		count++;	/* now there should be no failure */
 		pdesc = &rcv_desc->desc_head[producer];
 		skb_reserve(skb, 2);
-		/* 
+		/*
 		 * This will be setup when we receive the
 		 * buffer after it has been filled
 		 * skb->dev = netdev;
diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c
index b2de6b6c2a7f..48a404aa66ce 100644
--- a/drivers/net/netxen/netxen_nic_isr.c
+++ b/drivers/net/netxen/netxen_nic_isr.c
@@ -48,7 +48,7 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
 	/* total packets received   */
 	stats->rx_packets = adapter->stats.no_rcv;
 	/* total packets transmitted    */
-	stats->tx_packets = adapter->stats.xmitedframes + 
+	stats->tx_packets = adapter->stats.xmitedframes +
 		adapter->stats.xmitfinished;
 	/* total bytes received     */
 	stats->rx_bytes = adapter->stats.rxbytes;
@@ -66,7 +66,8 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
 	return stats;
 }
 
-void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link)
+static void netxen_indicate_link_status(struct netxen_adapter *adapter,
+					u32 link)
 {
 	struct net_device *netdev = adapter->netdev;
 
@@ -76,13 +77,14 @@ void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link)
 		netif_carrier_off(netdev);
 }
 
+#if 0
 void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable)
 {
 	__u32 int_src;
 
 	/*  This should clear the interrupt source */
 	if (adapter->phy_read)
-		adapter->phy_read(adapter, 
+		adapter->phy_read(adapter,
 				  NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
 				  &int_src);
 	if (int_src == 0) {
@@ -111,7 +113,7 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable)
 		DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n");
 
 		if (adapter->phy_read
-		    && adapter->phy_read(adapter, 
+		    && adapter->phy_read(adapter,
 					 NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
 					 &status) == 0) {
 			if (netxen_get_phy_int_link_status_changed(int_src)) {
@@ -125,7 +127,7 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable)
 					       netxen_nic_driver_name,
 					       adapter->netdev->name);
 				}
-				netxen_indicate_link_status(adapter, 
+				netxen_indicate_link_status(adapter,
 							    netxen_get_phy_link
 							    (status));
 			}
@@ -134,8 +136,9 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable)
 	if (adapter->enable_phy_interrupts)
 		adapter->enable_phy_interrupts(adapter);
 }
+#endif  /*  0  */
 
-void netxen_nic_isr_other(struct netxen_adapter *adapter)
+static void netxen_nic_isr_other(struct netxen_adapter *adapter)
 {
 	int portno = adapter->portnum;
 	u32 val, linkup, qg_linksup;
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 263b55e36c7a..9737eae5ef11 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -89,8 +89,8 @@ MODULE_DEVICE_TABLE(pci, netxen_pci_tbl);
 struct workqueue_struct *netxen_workq;
 static void netxen_watchdog(unsigned long);
 
-static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
-							uint32_t crb_producer)
+static void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
+					   uint32_t crb_producer)
 {
 	switch (adapter->portnum) {
 		case 0:
@@ -118,8 +118,8 @@ static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter
 	}
 }
 
-static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter,
-							u32 crb_consumer)
+static void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter,
+					   u32 crb_consumer)
 {
 	switch (adapter->portnum) {
 		case 0:
@@ -148,7 +148,6 @@ static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter
 }
 
 #define	ADAPTER_LIST_SIZE 12
-int netxen_cards_found;
 
 static void netxen_nic_disable_int(struct netxen_adapter *adapter)
 {
@@ -278,7 +277,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	struct netxen_recv_context *recv_ctx = NULL;
 	struct netxen_rcv_desc_ctx *rcv_desc = NULL;
 	struct netxen_cmd_buffer *cmd_buf_arr = NULL;
-	u64 mac_addr[FLASH_NUM_PORTS + 1];
+	__le64 mac_addr[FLASH_NUM_PORTS + 1];
 	int valid_mac = 0;
 	u32 val;
 	int pci_func_id = PCI_FUNC(pdev->devfn);
@@ -287,7 +286,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	printk(KERN_INFO "%s \n", netxen_nic_driver_string);
 
 	if (pdev->class != 0x020000) {
-		printk(KERN_ERR"NetXen function %d, class %x will not"
+		printk(KERN_ERR"NetXen function %d, class %x will not "
 				"be enabled.\n",pci_func_id, pdev->class);
 		return -ENODEV;
 	}
@@ -351,12 +350,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		first_page_group_start = 0;
 		first_page_group_end   = 0;
 	} else {
-		err = -EIO; 
+		err = -EIO;
 		goto err_out_free_netdev;
 	}
 
-	if (((mem_ptr0 == 0UL) && (mem_len == NETXEN_PCI_128MB_SIZE)) ||
-			(mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {
+	if ((!mem_ptr0 && mem_len == NETXEN_PCI_128MB_SIZE) ||
+			!mem_ptr1 || !mem_ptr2) {
 		DPRINTK(ERR,
 			"Cannot remap adapter memory aborting.:"
 			"0 -> %p, 1 -> %p, 2 -> %p\n",
@@ -411,7 +410,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	netdev->open		   = netxen_nic_open;
 	netdev->stop		   = netxen_nic_close;
 	netdev->hard_start_xmit    = netxen_nic_xmit_frame;
-	netdev->get_stats	   = netxen_nic_get_stats;	
+	netdev->get_stats	   = netxen_nic_get_stats;
 	netdev->set_multicast_list = netxen_nic_set_multi;
 	netdev->set_mac_address    = netxen_nic_set_mac;
 	netdev->change_mtu	   = netxen_nic_change_mtu;
@@ -458,8 +457,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST;
 	if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB35_4G) ||
-			(adapter->ahw.boardcfg.board_type == 
-			 NETXEN_BRDTYPE_P2_SB31_2G)) 
+			(adapter->ahw.boardcfg.board_type ==
+			 NETXEN_BRDTYPE_P2_SB31_2G))
 		adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
 	else
 		adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
@@ -511,7 +510,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			    vmalloc(RCV_BUFFSIZE);
 
 			if (rcv_desc->rx_buf_arr == NULL) {
-				printk(KERN_ERR "%s: Could not allocate"
+				printk(KERN_ERR "%s: Could not allocate "
 				       "rcv_desc->rx_buf_arr memory:%d\n",
 				       netxen_nic_driver_name,
 				       (int)RCV_BUFFSIZE);
@@ -584,9 +583,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	if (adapter->portnum == 0) {
 		err = netxen_initialize_adapter_offload(adapter);
-		if (err) 
+		if (err)
 			goto err_out_free_rx_buffer;
-		val = readl(NETXEN_CRB_NORMALIZE(adapter, 
+		val = readl(NETXEN_CRB_NORMALIZE(adapter,
 					NETXEN_CAM_RAM(0x1fc)));
 		if (val == 0x55555555) {
 		    /* This is the first boot after power up */
@@ -620,7 +619,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		/*
 		 * Tell the hardware our version number.
 		 */
-		i = (_NETXEN_NIC_LINUX_MAJOR << 16) 
+		i = (_NETXEN_NIC_LINUX_MAJOR << 16)
 			| ((_NETXEN_NIC_LINUX_MINOR << 8))
 			| (_NETXEN_NIC_LINUX_SUBVERSION);
 		writel(i, NETXEN_CRB_NORMALIZE(adapter, CRB_DRIVER_VERSION));
@@ -660,7 +659,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			break;
 
 		case NETXEN_NIC_XGBE:
-			printk(KERN_INFO "%s: XGbE board initialized\n", 
+			printk(KERN_INFO "%s: XGbE board initialized\n",
 					netxen_nic_driver_name);
 			break;
 	}
@@ -931,7 +930,7 @@ static int netxen_nic_close(struct net_device *netdev)
 			buffrag++;
 			if (buffrag->dma) {
 				pci_unmap_page(adapter->pdev, buffrag->dma,
-					       buffrag->length, 
+					       buffrag->length,
 					       PCI_DMA_TODEVICE);
 				buffrag->dma = 0ULL;
 			}
@@ -981,7 +980,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 	}
 
 	if (frag_count > MAX_BUFFERS_PER_CMD) {
-		printk("%s: %s netxen_nic_xmit_frame: frag_count (%d)"
+		printk("%s: %s netxen_nic_xmit_frame: frag_count (%d) "
 		       "too large, can handle only %d frags\n",
 		       netxen_nic_driver_name, netdev->name,
 		       frag_count, MAX_BUFFERS_PER_CMD);
@@ -1195,7 +1194,7 @@ static void netxen_tx_timeout(struct net_device *netdev)
 
 static void netxen_tx_timeout_task(struct work_struct *work)
 {
-	struct netxen_adapter *adapter = 
+	struct netxen_adapter *adapter =
 		container_of(work, struct netxen_adapter, tx_timeout_task);
 
 	printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
@@ -1338,7 +1337,7 @@ static struct pci_driver netxen_driver = {
 
 static int __init netxen_init_module(void)
 {
-	if ((netxen_workq = create_singlethread_workqueue("netxen")) == 0)
+	if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL)
 		return -ENOMEM;
 
 	return pci_register_driver(&netxen_driver);
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index d04ecb77d08c..1c852a76c80d 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -40,7 +40,7 @@
 
 static long phy_lock_timeout = 100000000;
 
-static inline int phy_lock(struct netxen_adapter *adapter)
+static int phy_lock(struct netxen_adapter *adapter)
 {
 	int i;
 	int done = 0, timeout = 0;
@@ -68,14 +68,14 @@ static inline int phy_lock(struct netxen_adapter *adapter)
 	return 0;
 }
 
-static inline int phy_unlock(struct netxen_adapter *adapter)
+static int phy_unlock(struct netxen_adapter *adapter)
 {
 	readl(pci_base_offset(adapter, NETXEN_PCIE_REG(PCIE_SEM3_UNLOCK)));
 
 	return 0;
 }
 
-/* 
+/*
  * netxen_niu_gbe_phy_read - read a register from the GbE PHY via
  * mii management interface.
  *
@@ -88,7 +88,7 @@ static inline int phy_unlock(struct netxen_adapter *adapter)
  *	  -1 on error
  *
  */
-int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, 
+int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
 				__u32 * readval)
 {
 	long timeout = 0;
@@ -171,7 +171,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
 	return result;
 }
 
-/* 
+/*
  * netxen_niu_gbe_phy_write - write a register to the GbE PHY via
  * mii management interface.
  *
@@ -184,7 +184,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
  *	  -1 on error
  *
  */
-int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, 
+int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg,
 				__u32 val)
 {
 	long timeout = 0;
@@ -275,7 +275,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter)
 	netxen_set_phy_int_speed_changed(enable);
 
 	if (0 !=
-	    netxen_niu_gbe_phy_write(adapter, 
+	    netxen_niu_gbe_phy_write(adapter,
 				     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE,
 				     enable))
 		result = -EIO;
@@ -300,17 +300,19 @@ int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter)
 	return result;
 }
 
+#if 0
 int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter)
 {
 	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1);
 	return 0;
 }
+#endif  /*  0  */
 
-int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter)
+static int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter)
 {
 	int result = 0;
 	if (0 !=
-	    netxen_niu_gbe_phy_write(adapter, 
+	    netxen_niu_gbe_phy_write(adapter,
 				     NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
 				     -EIO))
 		result = -EIO;
@@ -318,12 +320,12 @@ int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter)
 	return result;
 }
 
-/* 
+/*
  * netxen_niu_gbe_set_mii_mode- Set 10/100 Mbit Mode for GbE MAC
  *
  */
-void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter,
-				 int port, long enable)
+static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter,
+					int port, long enable)
 {
 	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2);
 	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
@@ -342,9 +344,9 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter,
 				    NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7);
 
 	if (enable) {
-		/* 
-		 * Do NOT enable flow control until a suitable solution for 
-		 *  shutting down pause frames is found. 
+		/*
+		 * Do NOT enable flow control until a suitable solution for
+		 *  shutting down pause frames is found.
 		 */
 		netxen_crb_writelit_adapter(adapter,
 					    NETXEN_NIU_GB_MAC_CONFIG_0(port),
@@ -357,11 +359,11 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter,
 		printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
 }
 
-/* 
+/*
  * netxen_niu_gbe_set_gmii_mode- Set GbE Mode for GbE MAC
  */
-void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter,
-				  int port, long enable)
+static void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter,
+					 int port, long enable)
 {
 	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2);
 	netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
@@ -380,9 +382,9 @@ void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter,
 				    NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7);
 
 	if (enable) {
-		/* 
-		 * Do NOT enable flow control until a suitable solution for 
-		 *  shutting down pause frames is found. 
+		/*
+		 * Do NOT enable flow control until a suitable solution for
+		 *  shutting down pause frames is found.
 		 */
 		netxen_crb_writelit_adapter(adapter,
 					    NETXEN_NIU_GB_MAC_CONFIG_0(port),
@@ -464,7 +466,8 @@ int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
 	return 0;
 }
 
-/* 
+#if 0
+/*
  * netxen_niu_gbe_handle_phy_interrupt - Handles GbE PHY interrupts
  * @param enable 0 means don't enable the port
  *		 1 means enable (or re-enable) the port
@@ -544,8 +547,8 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
 								    port,
 								    enable);
 				} else {
-					printk(KERN_ERR PFX "ERROR reading"
-					       "PHY status. Illegal speed.\n");
+					printk(KERN_ERR PFX "ERROR reading "
+					       "PHY status. Invalid speed.\n");
 					result = -1;
 				}
 			} else {
@@ -559,13 +562,14 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
 	}
 	return result;
 }
+#endif  /*  0  */
 
 /*
  * Return the current station MAC address.
  * Note that the passed-in value must already be in network byte order.
  */
-int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
-			   netxen_ethernet_macaddr_t * addr)
+static int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
+				  netxen_ethernet_macaddr_t * addr)
 {
 	u32 stationhigh;
 	u32 stationlow;
@@ -619,7 +623,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
 		    (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4))
 			return -2;
 
-		netxen_niu_macaddr_get(adapter, 
+		netxen_niu_macaddr_get(adapter,
 				       (netxen_ethernet_macaddr_t *) mac_addr);
 		if (memcmp(mac_addr, addr, 6) == 0)
 			break;
@@ -636,6 +640,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
 	return 0;
 }
 
+#if 0
 /* Enable a GbE interface */
 int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter,
 			       int port, netxen_niu_gbe_ifmode_t mode)
@@ -713,6 +718,7 @@ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter,
 		return -EIO;
 	return 0;
 }
+#endif  /*  0  */
 
 /* Disable a GbE interface */
 int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter)
@@ -747,7 +753,7 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
 }
 
 /* Set promiscuous mode for a GbE interface */
-int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, 
+int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
 				    netxen_niu_prom_mode_t mode)
 {
 	__u32 reg;
@@ -853,6 +859,7 @@ int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
 	return 0;
 }
 
+#if 0
 /*
  * Return the current station MAC address.
  * Note that the passed-in value must already be in network byte order.
@@ -883,6 +890,7 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
 
 	return 0;
 }
+#endif  /*  0  */
 
 int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
 				       netxen_niu_prom_mode_t mode)
diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h
index 10fe6fafa6f6..ffa3b7215ce8 100644
--- a/drivers/net/netxen/netxen_nic_phan_reg.h
+++ b/drivers/net/netxen/netxen_nic_phan_reg.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2003 - 2006 NetXen, Inc.
  * 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
@@ -16,10 +16,10 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  * MA  02111-1307, USA.
- * 
+ *
  * The full GNU General Public License is included in this distribution
  * in the file called LICENSE.
- * 
+ *
  * Contact Information:
  *    info@netxen.com
  * NetXen,
@@ -30,7 +30,7 @@
 #ifndef __NIC_PHAN_REG_H_
 #define __NIC_PHAN_REG_H_
 
-/* 
+/*
  * CRB Registers or queue message done only at initialization time.
  */
 #define NIC_CRB_BASE               NETXEN_CAM_RAM(0x200)
@@ -165,14 +165,7 @@ struct netxen_recv_crb {
 	u32 crb_status_ring_size;
 };
 
-#if defined(DEFINE_GLOBAL_RECV_CRB)
-#else
 extern struct netxen_recv_crb recv_crb_registers[];
-extern u64 ctx_addr_sig_regs[][3];
-#endif				/* DEFINE_GLOBAL_RECEIVE_CRB */
-#define CRB_CTX_ADDR_REG_LO(FUNC_ID)		(ctx_addr_sig_regs[FUNC_ID][0])
-#define CRB_CTX_ADDR_REG_HI(FUNC_ID)		(ctx_addr_sig_regs[FUNC_ID][2])
-#define CRB_CTX_SIGNATURE_REG(FUNC_ID)		(ctx_addr_sig_regs[FUNC_ID][1])
 
 /*
  * Temperature control.
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 5f6beabf2d17..2fe14b0c5c67 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -7588,12 +7588,10 @@ static void __devinit niu_assign_netdev_ops(struct net_device *dev)
 static void __devinit niu_device_announce(struct niu *np)
 {
 	struct net_device *dev = np->dev;
-	int i;
+	DECLARE_MAC_BUF(mac);
 
-	pr_info("%s: NIU Ethernet ", dev->name);
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i],
-		       i == 5 ? '\n' : ':');
+	pr_info("%s: NIU Ethernet %s\n",
+		dev->name, print_mac(mac, dev->dev_addr));
 
 	pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n",
 		dev->name,
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index ea71f6d82661..b42c05f84be1 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -611,8 +611,7 @@ static inline int rx_refill(struct net_device *ndev, gfp_t gfp)
 	return i ? 0 : -ENOMEM;
 }
 
-static void FASTCALL(rx_refill_atomic(struct net_device *ndev));
-static void fastcall rx_refill_atomic(struct net_device *ndev)
+static void rx_refill_atomic(struct net_device *ndev)
 {
 	rx_refill(ndev, GFP_ATOMIC);
 }
@@ -633,8 +632,7 @@ static inline void clear_rx_desc(struct ns83820 *dev, unsigned i)
 	build_rx_desc(dev, dev->rx_info.descs + (DESC_SIZE * i), 0, 0, CMDSTS_OWN, 0);
 }
 
-static void FASTCALL(phy_intr(struct net_device *ndev));
-static void fastcall phy_intr(struct net_device *ndev)
+static void phy_intr(struct net_device *ndev)
 {
 	struct ns83820 *dev = PRIV(ndev);
 	static const char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" };
@@ -832,8 +830,7 @@ static void ns83820_cleanup_rx(struct ns83820 *dev)
 	}
 }
 
-static void FASTCALL(ns83820_rx_kick(struct net_device *ndev));
-static void fastcall ns83820_rx_kick(struct net_device *ndev)
+static void ns83820_rx_kick(struct net_device *ndev)
 {
 	struct ns83820 *dev = PRIV(ndev);
 	/*if (nr_rx_empty(dev) >= NR_RX_DESC/4)*/ {
@@ -854,8 +851,7 @@ static void fastcall ns83820_rx_kick(struct net_device *ndev)
 /* rx_irq
  *
  */
-static void FASTCALL(rx_irq(struct net_device *ndev));
-static void fastcall rx_irq(struct net_device *ndev)
+static void rx_irq(struct net_device *ndev)
 {
 	struct ns83820 *dev = PRIV(ndev);
 	struct rx_info *info = &dev->rx_info;
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 816a59e801b2..bb88a41b7591 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -32,9 +32,11 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <net/checksum.h>
+#include <linux/inet_lro.h>
 
 #include <asm/irq.h>
 #include <asm/firmware.h>
+#include <asm/pasemi_dma.h>
 
 #include "pasemi_mac.h"
 
@@ -55,9 +57,11 @@
 
 
 /* Must be a power of two */
-#define RX_RING_SIZE 4096
+#define RX_RING_SIZE 2048
 #define TX_RING_SIZE 4096
 
+#define LRO_MAX_AGGR 64
+
 #define DEFAULT_MSG_ENABLE	  \
 	(NETIF_MSG_DRV		| \
 	 NETIF_MSG_PROBE	| \
@@ -68,11 +72,11 @@
 	 NETIF_MSG_RX_ERR	| \
 	 NETIF_MSG_TX_ERR)
 
-#define TX_RING(mac, num)	((mac)->tx->ring[(num) & (TX_RING_SIZE-1)])
-#define TX_RING_INFO(mac, num)	((mac)->tx->ring_info[(num) & (TX_RING_SIZE-1)])
-#define RX_RING(mac, num)	((mac)->rx->ring[(num) & (RX_RING_SIZE-1)])
-#define RX_RING_INFO(mac, num)	((mac)->rx->ring_info[(num) & (RX_RING_SIZE-1)])
-#define RX_BUFF(mac, num)	((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)])
+#define TX_DESC(tx, num)	((tx)->chan.ring_virt[(num) & (TX_RING_SIZE-1)])
+#define TX_DESC_INFO(tx, num)	((tx)->ring_info[(num) & (TX_RING_SIZE-1)])
+#define RX_DESC(rx, num)	((rx)->chan.ring_virt[(num) & (RX_RING_SIZE-1)])
+#define RX_DESC_INFO(rx, num)	((rx)->ring_info[(num) & (RX_RING_SIZE-1)])
+#define RX_BUFF(rx, num)	((rx)->buffers[(num) & (RX_RING_SIZE-1)])
 
 #define RING_USED(ring)		(((ring)->next_to_fill - (ring)->next_to_clean) \
 				 & ((ring)->size - 1))
@@ -88,8 +92,6 @@ static int debug = -1;	/* -1 == use DEFAULT_MSG_ENABLE as value */
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value");
 
-static struct pasdma_status *dma_status;
-
 static int translation_enabled(void)
 {
 #if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE)
@@ -99,32 +101,78 @@ static int translation_enabled(void)
 #endif
 }
 
-static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg,
-			  unsigned int val)
+static void write_iob_reg(unsigned int reg, unsigned int val)
 {
-	out_le32(mac->iob_regs+reg, val);
+	pasemi_write_iob_reg(reg, val);
 }
 
-static unsigned int read_mac_reg(struct pasemi_mac *mac, unsigned int reg)
+static unsigned int read_mac_reg(const struct pasemi_mac *mac, unsigned int reg)
 {
-	return in_le32(mac->regs+reg);
+	return pasemi_read_mac_reg(mac->dma_if, reg);
 }
 
-static void write_mac_reg(struct pasemi_mac *mac, unsigned int reg,
+static void write_mac_reg(const struct pasemi_mac *mac, unsigned int reg,
 			  unsigned int val)
 {
-	out_le32(mac->regs+reg, val);
+	pasemi_write_mac_reg(mac->dma_if, reg, val);
 }
 
-static unsigned int read_dma_reg(struct pasemi_mac *mac, unsigned int reg)
+static unsigned int read_dma_reg(unsigned int reg)
 {
-	return in_le32(mac->dma_regs+reg);
+	return pasemi_read_dma_reg(reg);
 }
 
-static void write_dma_reg(struct pasemi_mac *mac, unsigned int reg,
-			  unsigned int val)
+static void write_dma_reg(unsigned int reg, unsigned int val)
+{
+	pasemi_write_dma_reg(reg, val);
+}
+
+static struct pasemi_mac_rxring *rx_ring(const struct pasemi_mac *mac)
 {
-	out_le32(mac->dma_regs+reg, val);
+	return mac->rx;
+}
+
+static struct pasemi_mac_txring *tx_ring(const struct pasemi_mac *mac)
+{
+	return mac->tx;
+}
+
+static inline void prefetch_skb(const struct sk_buff *skb)
+{
+	const void *d = skb;
+
+	prefetch(d);
+	prefetch(d+64);
+	prefetch(d+128);
+	prefetch(d+192);
+}
+
+static int mac_to_intf(struct pasemi_mac *mac)
+{
+	struct pci_dev *pdev = mac->pdev;
+	u32 tmp;
+	int nintf, off, i, j;
+	int devfn = pdev->devfn;
+
+	tmp = read_dma_reg(PAS_DMA_CAP_IFI);
+	nintf = (tmp & PAS_DMA_CAP_IFI_NIN_M) >> PAS_DMA_CAP_IFI_NIN_S;
+	off = (tmp & PAS_DMA_CAP_IFI_IOFF_M) >> PAS_DMA_CAP_IFI_IOFF_S;
+
+	/* IOFF contains the offset to the registers containing the
+	 * DMA interface-to-MAC-pci-id mappings, and NIN contains number
+	 * of total interfaces. Each register contains 4 devfns.
+	 * Just do a linear search until we find the devfn of the MAC
+	 * we're trying to look up.
+	 */
+
+	for (i = 0; i < (nintf+3)/4; i++) {
+		tmp = read_dma_reg(off+4*i);
+		for (j = 0; j < 4; j++) {
+			if (((tmp >> (8*j)) & 0xff) == devfn)
+				return i*4 + j;
+		}
+	}
+	return -1;
 }
 
 static int pasemi_get_mac_addr(struct pasemi_mac *mac)
@@ -161,7 +209,6 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
 		return -ENOENT;
 	}
 
-
 	if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
 		   &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
 		dev_warn(&pdev->dev,
@@ -174,21 +221,51 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
 	return 0;
 }
 
+static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
+		       void **tcph, u64 *hdr_flags, void *data)
+{
+	u64 macrx = (u64) data;
+	unsigned int ip_len;
+	struct iphdr *iph;
+
+	/* IPv4 header checksum failed */
+	if ((macrx & XCT_MACRX_HTY_M) != XCT_MACRX_HTY_IPV4_OK)
+		return -1;
+
+	/* non tcp packet */
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
+	if (iph->protocol != IPPROTO_TCP)
+		return -1;
+
+	ip_len = ip_hdrlen(skb);
+	skb_set_transport_header(skb, ip_len);
+	*tcph = tcp_hdr(skb);
+
+	/* check if ip header and tcp header are complete */
+	if (iph->tot_len < ip_len + tcp_hdrlen(skb))
+		return -1;
+
+	*hdr_flags = LRO_IPV4 | LRO_TCP;
+	*iphdr = iph;
+
+	return 0;
+}
+
 static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
+				    const int nfrags,
 				    struct sk_buff *skb,
-				    dma_addr_t *dmas)
+				    const dma_addr_t *dmas)
 {
 	int f;
-	int nfrags = skb_shinfo(skb)->nr_frags;
+	struct pci_dev *pdev = mac->dma_pdev;
 
-	pci_unmap_single(mac->dma_pdev, dmas[0], skb_headlen(skb),
-			 PCI_DMA_TODEVICE);
+	pci_unmap_single(pdev, dmas[0], skb_headlen(skb), PCI_DMA_TODEVICE);
 
 	for (f = 0; f < nfrags; f++) {
 		skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
 
-		pci_unmap_page(mac->dma_pdev, dmas[f+1], frag->size,
-			       PCI_DMA_TODEVICE);
+		pci_unmap_page(pdev, dmas[f+1], frag->size, PCI_DMA_TODEVICE);
 	}
 	dev_kfree_skb_irq(skb);
 
@@ -198,17 +275,21 @@ static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
 	return (nfrags + 3) & ~1;
 }
 
-static int pasemi_mac_setup_rx_resources(struct net_device *dev)
+static int pasemi_mac_setup_rx_resources(const struct net_device *dev)
 {
 	struct pasemi_mac_rxring *ring;
 	struct pasemi_mac *mac = netdev_priv(dev);
-	int chan_id = mac->dma_rxch;
+	int chno;
 	unsigned int cfg;
 
-	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+	ring = pasemi_dma_alloc_chan(RXCHAN, sizeof(struct pasemi_mac_rxring),
+				     offsetof(struct pasemi_mac_rxring, chan));
 
-	if (!ring)
-		goto out_ring;
+	if (!ring) {
+		dev_err(&mac->pdev->dev, "Can't allocate RX channel\n");
+		goto out_chan;
+	}
+	chno = ring->chan.chno;
 
 	spin_lock_init(&ring->lock);
 
@@ -220,85 +301,80 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev)
 		goto out_ring_info;
 
 	/* Allocate descriptors */
-	ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev,
-					RX_RING_SIZE * sizeof(u64),
-					&ring->dma, GFP_KERNEL);
-
-	if (!ring->ring)
+	if (pasemi_dma_alloc_ring(&ring->chan, RX_RING_SIZE))
 		goto out_ring_desc;
 
-	memset(ring->ring, 0, RX_RING_SIZE * sizeof(u64));
-
 	ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
 					   RX_RING_SIZE * sizeof(u64),
 					   &ring->buf_dma, GFP_KERNEL);
 	if (!ring->buffers)
-		goto out_buffers;
+		goto out_ring_desc;
 
 	memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
 
-	write_dma_reg(mac, PAS_DMA_RXCHAN_BASEL(chan_id), PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+	write_dma_reg(PAS_DMA_RXCHAN_BASEL(chno),
+		      PAS_DMA_RXCHAN_BASEL_BRBL(ring->chan.ring_dma));
 
-	write_dma_reg(mac, PAS_DMA_RXCHAN_BASEU(chan_id),
-			   PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
-			   PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3));
+	write_dma_reg(PAS_DMA_RXCHAN_BASEU(chno),
+		      PAS_DMA_RXCHAN_BASEU_BRBH(ring->chan.ring_dma >> 32) |
+		      PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3));
 
 	cfg = PAS_DMA_RXCHAN_CFG_HBU(2);
 
 	if (translation_enabled())
 		cfg |= PAS_DMA_RXCHAN_CFG_CTR;
 
-	write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), cfg);
+	write_dma_reg(PAS_DMA_RXCHAN_CFG(chno), cfg);
 
-	write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if),
-			   PAS_DMA_RXINT_BASEL_BRBL(ring->buf_dma));
+	write_dma_reg(PAS_DMA_RXINT_BASEL(mac->dma_if),
+		      PAS_DMA_RXINT_BASEL_BRBL(ring->buf_dma));
 
-	write_dma_reg(mac, PAS_DMA_RXINT_BASEU(mac->dma_if),
-			   PAS_DMA_RXINT_BASEU_BRBH(ring->buf_dma >> 32) |
-			   PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
+	write_dma_reg(PAS_DMA_RXINT_BASEU(mac->dma_if),
+		      PAS_DMA_RXINT_BASEU_BRBH(ring->buf_dma >> 32) |
+		      PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
 
-	cfg = PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 |
+	cfg = PAS_DMA_RXINT_CFG_DHL(2) | PAS_DMA_RXINT_CFG_L2 |
 	      PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP |
 	      PAS_DMA_RXINT_CFG_HEN;
 
 	if (translation_enabled())
 		cfg |= PAS_DMA_RXINT_CFG_ITRR | PAS_DMA_RXINT_CFG_ITR;
 
-	write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), cfg);
+	write_dma_reg(PAS_DMA_RXINT_CFG(mac->dma_if), cfg);
 
 	ring->next_to_fill = 0;
 	ring->next_to_clean = 0;
-
-	snprintf(ring->irq_name, sizeof(ring->irq_name),
-		 "%s rx", dev->name);
+	ring->mac = mac;
 	mac->rx = ring;
 
 	return 0;
 
-out_buffers:
-	dma_free_coherent(&mac->dma_pdev->dev,
-			  RX_RING_SIZE * sizeof(u64),
-			  mac->rx->ring, mac->rx->dma);
 out_ring_desc:
 	kfree(ring->ring_info);
 out_ring_info:
-	kfree(ring);
-out_ring:
+	pasemi_dma_free_chan(&ring->chan);
+out_chan:
 	return -ENOMEM;
 }
 
-
-static int pasemi_mac_setup_tx_resources(struct net_device *dev)
+static struct pasemi_mac_txring *
+pasemi_mac_setup_tx_resources(const struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
 	u32 val;
-	int chan_id = mac->dma_txch;
 	struct pasemi_mac_txring *ring;
 	unsigned int cfg;
+	int chno;
+
+	ring = pasemi_dma_alloc_chan(TXCHAN, sizeof(struct pasemi_mac_txring),
+				     offsetof(struct pasemi_mac_txring, chan));
 
-	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
-	if (!ring)
-		goto out_ring;
+	if (!ring) {
+		dev_err(&mac->pdev->dev, "Can't allocate TX channel\n");
+		goto out_chan;
+	}
+
+	chno = ring->chan.chno;
 
 	spin_lock_init(&ring->lock);
 
@@ -309,20 +385,15 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev)
 		goto out_ring_info;
 
 	/* Allocate descriptors */
-	ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev,
-					TX_RING_SIZE * sizeof(u64),
-					&ring->dma, GFP_KERNEL);
-	if (!ring->ring)
+	if (pasemi_dma_alloc_ring(&ring->chan, TX_RING_SIZE))
 		goto out_ring_desc;
 
-	memset(ring->ring, 0, TX_RING_SIZE * sizeof(u64));
-
-	write_dma_reg(mac, PAS_DMA_TXCHAN_BASEL(chan_id),
-			   PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
-	val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
+	write_dma_reg(PAS_DMA_TXCHAN_BASEL(chno),
+		      PAS_DMA_TXCHAN_BASEL_BRBL(ring->chan.ring_dma));
+	val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->chan.ring_dma >> 32);
 	val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 3);
 
-	write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val);
+	write_dma_reg(PAS_DMA_TXCHAN_BASEU(chno), val);
 
 	cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE |
 	      PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
@@ -332,71 +403,64 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev)
 	if (translation_enabled())
 		cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR;
 
-	write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), cfg);
+	write_dma_reg(PAS_DMA_TXCHAN_CFG(chno), cfg);
 
 	ring->next_to_fill = 0;
 	ring->next_to_clean = 0;
+	ring->mac = mac;
 
-	snprintf(ring->irq_name, sizeof(ring->irq_name),
-		 "%s tx", dev->name);
-	mac->tx = ring;
-
-	return 0;
+	return ring;
 
 out_ring_desc:
 	kfree(ring->ring_info);
 out_ring_info:
-	kfree(ring);
-out_ring:
-	return -ENOMEM;
+	pasemi_dma_free_chan(&ring->chan);
+out_chan:
+	return NULL;
 }
 
-static void pasemi_mac_free_tx_resources(struct net_device *dev)
+static void pasemi_mac_free_tx_resources(struct pasemi_mac *mac)
 {
-	struct pasemi_mac *mac = netdev_priv(dev);
+	struct pasemi_mac_txring *txring = tx_ring(mac);
 	unsigned int i, j;
 	struct pasemi_mac_buffer *info;
 	dma_addr_t dmas[MAX_SKB_FRAGS+1];
-	int freed;
+	int freed, nfrags;
 	int start, limit;
 
-	start = mac->tx->next_to_clean;
-	limit = mac->tx->next_to_fill;
+	start = txring->next_to_clean;
+	limit = txring->next_to_fill;
 
 	/* Compensate for when fill has wrapped and clean has not */
 	if (start > limit)
 		limit += TX_RING_SIZE;
 
 	for (i = start; i < limit; i += freed) {
-		info = &TX_RING_INFO(mac, i+1);
+		info = &txring->ring_info[(i+1) & (TX_RING_SIZE-1)];
 		if (info->dma && info->skb) {
-			for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++)
-				dmas[j] = TX_RING_INFO(mac, i+1+j).dma;
-			freed = pasemi_mac_unmap_tx_skb(mac, info->skb, dmas);
+			nfrags = skb_shinfo(info->skb)->nr_frags;
+			for (j = 0; j <= nfrags; j++)
+				dmas[j] = txring->ring_info[(i+1+j) &
+						(TX_RING_SIZE-1)].dma;
+			freed = pasemi_mac_unmap_tx_skb(mac, nfrags,
+							info->skb, dmas);
 		} else
 			freed = 2;
 	}
 
-	for (i = 0; i < TX_RING_SIZE; i++)
-		TX_RING(mac, i) = 0;
-
-	dma_free_coherent(&mac->dma_pdev->dev,
-			  TX_RING_SIZE * sizeof(u64),
-			  mac->tx->ring, mac->tx->dma);
+	kfree(txring->ring_info);
+	pasemi_dma_free_chan(&txring->chan);
 
-	kfree(mac->tx->ring_info);
-	kfree(mac->tx);
-	mac->tx = NULL;
 }
 
-static void pasemi_mac_free_rx_resources(struct net_device *dev)
+static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac)
 {
-	struct pasemi_mac *mac = netdev_priv(dev);
+	struct pasemi_mac_rxring *rx = rx_ring(mac);
 	unsigned int i;
 	struct pasemi_mac_buffer *info;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		info = &RX_RING_INFO(mac, i);
+		info = &RX_DESC_INFO(rx, i);
 		if (info->skb && info->dma) {
 			pci_unmap_single(mac->dma_pdev,
 					 info->dma,
@@ -409,45 +473,38 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev)
 	}
 
 	for (i = 0; i < RX_RING_SIZE; i++)
-		RX_RING(mac, i) = 0;
-
-	dma_free_coherent(&mac->dma_pdev->dev,
-			  RX_RING_SIZE * sizeof(u64),
-			  mac->rx->ring, mac->rx->dma);
+		RX_DESC(rx, i) = 0;
 
 	dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
-			  mac->rx->buffers, mac->rx->buf_dma);
+			  rx_ring(mac)->buffers, rx_ring(mac)->buf_dma);
 
-	kfree(mac->rx->ring_info);
-	kfree(mac->rx);
+	kfree(rx_ring(mac)->ring_info);
+	pasemi_dma_free_chan(&rx_ring(mac)->chan);
 	mac->rx = NULL;
 }
 
-static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit)
+static void pasemi_mac_replenish_rx_ring(const struct net_device *dev,
+					 const int limit)
 {
-	struct pasemi_mac *mac = netdev_priv(dev);
+	const struct pasemi_mac *mac = netdev_priv(dev);
+	struct pasemi_mac_rxring *rx = rx_ring(mac);
 	int fill, count;
 
 	if (limit <= 0)
 		return;
 
-	fill = mac->rx->next_to_fill;
+	fill = rx_ring(mac)->next_to_fill;
 	for (count = 0; count < limit; count++) {
-		struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill);
-		u64 *buff = &RX_BUFF(mac, fill);
+		struct pasemi_mac_buffer *info = &RX_DESC_INFO(rx, fill);
+		u64 *buff = &RX_BUFF(rx, fill);
 		struct sk_buff *skb;
 		dma_addr_t dma;
 
 		/* Entry in use? */
 		WARN_ON(*buff);
 
-		/* skb might still be in there for recycle on short receives */
-		if (info->skb)
-			skb = info->skb;
-		else {
-			skb = dev_alloc_skb(BUF_SIZE);
-			skb_reserve(skb, LOCAL_SKB_ALIGN);
-		}
+		skb = dev_alloc_skb(BUF_SIZE);
+		skb_reserve(skb, LOCAL_SKB_ALIGN);
 
 		if (unlikely(!skb))
 			break;
@@ -469,94 +526,108 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit)
 
 	wmb();
 
-	write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count);
+	write_dma_reg(PAS_DMA_RXINT_INCR(mac->dma_if), count);
 
-	mac->rx->next_to_fill = (mac->rx->next_to_fill + count) &
+	rx_ring(mac)->next_to_fill = (rx_ring(mac)->next_to_fill + count) &
 				(RX_RING_SIZE - 1);
 }
 
-static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac)
+static void pasemi_mac_restart_rx_intr(const struct pasemi_mac *mac)
 {
+	struct pasemi_mac_rxring *rx = rx_ring(mac);
 	unsigned int reg, pcnt;
 	/* Re-enable packet count interrupts: finally
 	 * ack the packet count interrupt we got in rx_intr.
 	 */
 
-	pcnt = *mac->rx_status & PAS_STATUS_PCNT_M;
+	pcnt = *rx->chan.status & PAS_STATUS_PCNT_M;
 
 	reg = PAS_IOB_DMA_RXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_RXCH_RESET_PINTC;
 
-	write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
+	if (*rx->chan.status & PAS_STATUS_TIMER)
+		reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
+
+	write_iob_reg(PAS_IOB_DMA_RXCH_RESET(mac->rx->chan.chno), reg);
 }
 
-static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac)
+static void pasemi_mac_restart_tx_intr(const struct pasemi_mac *mac)
 {
 	unsigned int reg, pcnt;
 
 	/* Re-enable packet count interrupts */
-	pcnt = *mac->tx_status & PAS_STATUS_PCNT_M;
+	pcnt = *tx_ring(mac)->chan.status & PAS_STATUS_PCNT_M;
 
 	reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC;
 
-	write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
+	write_iob_reg(PAS_IOB_DMA_TXCH_RESET(tx_ring(mac)->chan.chno), reg);
 }
 
 
-static inline void pasemi_mac_rx_error(struct pasemi_mac *mac, u64 macrx)
+static inline void pasemi_mac_rx_error(const struct pasemi_mac *mac,
+				       const u64 macrx)
 {
 	unsigned int rcmdsta, ccmdsta;
+	struct pasemi_dmachan *chan = &rx_ring(mac)->chan;
 
 	if (!netif_msg_rx_err(mac))
 		return;
 
-	rcmdsta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
-	ccmdsta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+	rcmdsta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+	ccmdsta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(chan->chno));
 
 	printk(KERN_ERR "pasemi_mac: rx error. macrx %016lx, rx status %lx\n",
-		macrx, *mac->rx_status);
+		macrx, *chan->status);
 
 	printk(KERN_ERR "pasemi_mac: rcmdsta %08x ccmdsta %08x\n",
 		rcmdsta, ccmdsta);
 }
 
-static inline void pasemi_mac_tx_error(struct pasemi_mac *mac, u64 mactx)
+static inline void pasemi_mac_tx_error(const struct pasemi_mac *mac,
+				       const u64 mactx)
 {
 	unsigned int cmdsta;
+	struct pasemi_dmachan *chan = &tx_ring(mac)->chan;
 
 	if (!netif_msg_tx_err(mac))
 		return;
 
-	cmdsta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+	cmdsta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(chan->chno));
 
 	printk(KERN_ERR "pasemi_mac: tx error. mactx 0x%016lx, "\
-		"tx status 0x%016lx\n", mactx, *mac->tx_status);
+		"tx status 0x%016lx\n", mactx, *chan->status);
 
 	printk(KERN_ERR "pasemi_mac: tcmdsta 0x%08x\n", cmdsta);
 }
 
-static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
+static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx,
+			       const int limit)
 {
+	const struct pasemi_dmachan *chan = &rx->chan;
+	struct pasemi_mac *mac = rx->mac;
+	struct pci_dev *pdev = mac->dma_pdev;
 	unsigned int n;
-	int count;
+	int count, buf_index, tot_bytes, packets;
 	struct pasemi_mac_buffer *info;
 	struct sk_buff *skb;
 	unsigned int len;
-	u64 macrx;
+	u64 macrx, eval;
 	dma_addr_t dma;
-	int buf_index;
-	u64 eval;
 
-	spin_lock(&mac->rx->lock);
+	tot_bytes = 0;
+	packets = 0;
 
-	n = mac->rx->next_to_clean;
+	spin_lock(&rx->lock);
 
-	prefetch(&RX_RING(mac, n));
+	n = rx->next_to_clean;
+
+	prefetch(&RX_DESC(rx, n));
 
 	for (count = 0; count < limit; count++) {
-		macrx = RX_RING(mac, n);
+		macrx = RX_DESC(rx, n);
+		prefetch(&RX_DESC(rx, n+4));
 
 		if ((macrx & XCT_MACRX_E) ||
-		    (*mac->rx_status & PAS_STATUS_ERROR))
+		    (*chan->status & PAS_STATUS_ERROR))
 			pasemi_mac_rx_error(mac, macrx);
 
 		if (!(macrx & XCT_MACRX_O))
@@ -566,21 +637,21 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
 
 		BUG_ON(!(macrx & XCT_MACRX_RR_8BRES));
 
-		eval = (RX_RING(mac, n+1) & XCT_RXRES_8B_EVAL_M) >>
+		eval = (RX_DESC(rx, n+1) & XCT_RXRES_8B_EVAL_M) >>
 			XCT_RXRES_8B_EVAL_S;
 		buf_index = eval-1;
 
-		dma = (RX_RING(mac, n+2) & XCT_PTR_ADDR_M);
-		info = &RX_RING_INFO(mac, buf_index);
+		dma = (RX_DESC(rx, n+2) & XCT_PTR_ADDR_M);
+		info = &RX_DESC_INFO(rx, buf_index);
 
 		skb = info->skb;
 
-		prefetch(skb);
-		prefetch(&skb->data_len);
+		prefetch_skb(skb);
 
 		len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
 
-		pci_unmap_single(mac->dma_pdev, dma, len, PCI_DMA_FROMDEVICE);
+		pci_unmap_single(pdev, dma, BUF_SIZE-LOCAL_SKB_ALIGN,
+				 PCI_DMA_FROMDEVICE);
 
 		if (macrx & XCT_MACRX_CRC) {
 			/* CRC error flagged */
@@ -590,26 +661,9 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
 			goto next;
 		}
 
-		if (len < 256) {
-			struct sk_buff *new_skb;
-
-			new_skb = netdev_alloc_skb(mac->netdev,
-						   len + LOCAL_SKB_ALIGN);
-			if (new_skb) {
-				skb_reserve(new_skb, LOCAL_SKB_ALIGN);
-				memcpy(new_skb->data, skb->data, len);
-				/* save the skb in buffer_info as good */
-				skb = new_skb;
-			}
-			/* else just continue with the old one */
-		} else
-			info->skb = NULL;
-
+		info->skb = NULL;
 		info->dma = 0;
 
-		/* Don't include CRC */
-		skb_put(skb, len-4);
-
 		if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			skb->csum = (macrx & XCT_MACRX_CSUM_M) >>
@@ -617,41 +671,49 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
 		} else
 			skb->ip_summed = CHECKSUM_NONE;
 
-		mac->netdev->stats.rx_bytes += len;
-		mac->netdev->stats.rx_packets++;
+		packets++;
+		tot_bytes += len;
+
+		/* Don't include CRC */
+		skb_put(skb, len-4);
 
 		skb->protocol = eth_type_trans(skb, mac->netdev);
-		netif_receive_skb(skb);
+		lro_receive_skb(&mac->lro_mgr, skb, (void *)macrx);
 
 next:
-		RX_RING(mac, n) = 0;
-		RX_RING(mac, n+1) = 0;
+		RX_DESC(rx, n) = 0;
+		RX_DESC(rx, n+1) = 0;
 
 		/* Need to zero it out since hardware doesn't, since the
 		 * replenish loop uses it to tell when it's done.
 		 */
-		RX_BUFF(mac, buf_index) = 0;
+		RX_BUFF(rx, buf_index) = 0;
 
 		n += 4;
 	}
 
 	if (n > RX_RING_SIZE) {
 		/* Errata 5971 workaround: L2 target of headers */
-		write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0);
+		write_iob_reg(PAS_IOB_COM_PKTHDRCNT, 0);
 		n &= (RX_RING_SIZE-1);
 	}
 
-	mac->rx->next_to_clean = n;
+	rx_ring(mac)->next_to_clean = n;
+
+	lro_flush_all(&mac->lro_mgr);
 
 	/* Increase is in number of 16-byte entries, and since each descriptor
 	 * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
 	 * count*2.
 	 */
-	write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count << 1);
+	write_dma_reg(PAS_DMA_RXCHAN_INCR(mac->rx->chan.chno), count << 1);
 
 	pasemi_mac_replenish_rx_ring(mac->netdev, count);
 
-	spin_unlock(&mac->rx->lock);
+	mac->netdev->stats.rx_bytes += tot_bytes;
+	mac->netdev->stats.rx_packets += packets;
+
+	spin_unlock(&rx_ring(mac)->lock);
 
 	return count;
 }
@@ -659,8 +721,10 @@ next:
 /* Can't make this too large or we blow the kernel stack limits */
 #define TX_CLEAN_BATCHSIZE (128/MAX_SKB_FRAGS)
 
-static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
+static int pasemi_mac_clean_tx(struct pasemi_mac_txring *txring)
 {
+	struct pasemi_dmachan *chan = &txring->chan;
+	struct pasemi_mac *mac = txring->mac;
 	int i, j;
 	unsigned int start, descr_count, buf_count, batch_limit;
 	unsigned int ring_limit;
@@ -668,14 +732,18 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
 	unsigned long flags;
 	struct sk_buff *skbs[TX_CLEAN_BATCHSIZE];
 	dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1];
+	int nf[TX_CLEAN_BATCHSIZE];
+	int nr_frags;
 
 	total_count = 0;
 	batch_limit = TX_CLEAN_BATCHSIZE;
 restart:
-	spin_lock_irqsave(&mac->tx->lock, flags);
+	spin_lock_irqsave(&txring->lock, flags);
+
+	start = txring->next_to_clean;
+	ring_limit = txring->next_to_fill;
 
-	start = mac->tx->next_to_clean;
-	ring_limit = mac->tx->next_to_fill;
+	prefetch(&TX_DESC_INFO(txring, start+1).skb);
 
 	/* Compensate for when fill has wrapped but clean has not */
 	if (start > ring_limit)
@@ -687,41 +755,45 @@ restart:
 	for (i = start;
 	     descr_count < batch_limit && i < ring_limit;
 	     i += buf_count) {
-		u64 mactx = TX_RING(mac, i);
+		u64 mactx = TX_DESC(txring, i);
 		struct sk_buff *skb;
 
+		skb = TX_DESC_INFO(txring, i+1).skb;
+		nr_frags = TX_DESC_INFO(txring, i).dma;
+
 		if ((mactx  & XCT_MACTX_E) ||
-		    (*mac->tx_status & PAS_STATUS_ERROR))
+		    (*chan->status & PAS_STATUS_ERROR))
 			pasemi_mac_tx_error(mac, mactx);
 
 		if (unlikely(mactx & XCT_MACTX_O))
 			/* Not yet transmitted */
 			break;
 
-		skb = TX_RING_INFO(mac, i+1).skb;
-		skbs[descr_count] = skb;
-
-		buf_count = 2 + skb_shinfo(skb)->nr_frags;
-		for (j = 0; j <= skb_shinfo(skb)->nr_frags; j++)
-			dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma;
-
-		TX_RING(mac, i) = 0;
-		TX_RING(mac, i+1) = 0;
-
+		buf_count = 2 + nr_frags;
 		/* Since we always fill with an even number of entries, make
 		 * sure we skip any unused one at the end as well.
 		 */
 		if (buf_count & 1)
 			buf_count++;
+
+		for (j = 0; j <= nr_frags; j++)
+			dmas[descr_count][j] = TX_DESC_INFO(txring, i+1+j).dma;
+
+		skbs[descr_count] = skb;
+		nf[descr_count] = nr_frags;
+
+		TX_DESC(txring, i) = 0;
+		TX_DESC(txring, i+1) = 0;
+
 		descr_count++;
 	}
-	mac->tx->next_to_clean = i & (TX_RING_SIZE-1);
+	txring->next_to_clean = i & (TX_RING_SIZE-1);
 
-	spin_unlock_irqrestore(&mac->tx->lock, flags);
+	spin_unlock_irqrestore(&txring->lock, flags);
 	netif_wake_queue(mac->netdev);
 
 	for (i = 0; i < descr_count; i++)
-		pasemi_mac_unmap_tx_skb(mac, skbs[i], dmas[i]);
+		pasemi_mac_unmap_tx_skb(mac, nf[i], skbs[i], dmas[i]);
 
 	total_count += descr_count;
 
@@ -735,11 +807,13 @@ restart:
 
 static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
 {
-	struct net_device *dev = data;
-	struct pasemi_mac *mac = netdev_priv(dev);
+	const struct pasemi_mac_rxring *rxring = data;
+	struct pasemi_mac *mac = rxring->mac;
+	struct net_device *dev = mac->netdev;
+	const struct pasemi_dmachan *chan = &rxring->chan;
 	unsigned int reg;
 
-	if (!(*mac->rx_status & PAS_STATUS_CAUSE_M))
+	if (!(*chan->status & PAS_STATUS_CAUSE_M))
 		return IRQ_NONE;
 
 	/* Don't reset packet count so it won't fire again but clear
@@ -747,45 +821,77 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
 	 */
 
 	reg = 0;
-	if (*mac->rx_status & PAS_STATUS_SOFT)
+	if (*chan->status & PAS_STATUS_SOFT)
 		reg |= PAS_IOB_DMA_RXCH_RESET_SINTC;
-	if (*mac->rx_status & PAS_STATUS_ERROR)
+	if (*chan->status & PAS_STATUS_ERROR)
 		reg |= PAS_IOB_DMA_RXCH_RESET_DINTC;
-	if (*mac->rx_status & PAS_STATUS_TIMER)
-		reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
 
 	netif_rx_schedule(dev, &mac->napi);
 
-	write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
+	write_iob_reg(PAS_IOB_DMA_RXCH_RESET(chan->chno), reg);
 
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
+#define TX_CLEAN_INTERVAL HZ
+
+static void pasemi_mac_tx_timer(unsigned long data)
 {
-	struct net_device *dev = data;
-	struct pasemi_mac *mac = netdev_priv(dev);
-	unsigned int reg, pcnt;
+	struct pasemi_mac_txring *txring = (struct pasemi_mac_txring *)data;
+	struct pasemi_mac *mac = txring->mac;
 
-	if (!(*mac->tx_status & PAS_STATUS_CAUSE_M))
-		return IRQ_NONE;
+	pasemi_mac_clean_tx(txring);
+
+	mod_timer(&txring->clean_timer, jiffies + TX_CLEAN_INTERVAL);
 
-	pasemi_mac_clean_tx(mac);
+	pasemi_mac_restart_tx_intr(mac);
+}
 
-	pcnt = *mac->tx_status & PAS_STATUS_PCNT_M;
+static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
+{
+	struct pasemi_mac_txring *txring = data;
+	const struct pasemi_dmachan *chan = &txring->chan;
+	struct pasemi_mac *mac = txring->mac;
+	unsigned int reg;
 
-	reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC;
+	if (!(*chan->status & PAS_STATUS_CAUSE_M))
+		return IRQ_NONE;
 
-	if (*mac->tx_status & PAS_STATUS_SOFT)
+	reg = 0;
+
+	if (*chan->status & PAS_STATUS_SOFT)
 		reg |= PAS_IOB_DMA_TXCH_RESET_SINTC;
-	if (*mac->tx_status & PAS_STATUS_ERROR)
+	if (*chan->status & PAS_STATUS_ERROR)
 		reg |= PAS_IOB_DMA_TXCH_RESET_DINTC;
 
-	write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
+	mod_timer(&txring->clean_timer, jiffies + (TX_CLEAN_INTERVAL)*2);
+
+	netif_rx_schedule(mac->netdev, &mac->napi);
+
+	if (reg)
+		write_iob_reg(PAS_IOB_DMA_TXCH_RESET(chan->chno), reg);
 
 	return IRQ_HANDLED;
 }
 
+static void pasemi_mac_intf_disable(struct pasemi_mac *mac)
+{
+	unsigned int flags;
+
+	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
+	flags &= ~PAS_MAC_CFG_PCFG_PE;
+	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
+}
+
+static void pasemi_mac_intf_enable(struct pasemi_mac *mac)
+{
+	unsigned int flags;
+
+	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
+	flags |= PAS_MAC_CFG_PCFG_PE;
+	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
+}
+
 static void pasemi_adjust_link(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
@@ -801,11 +907,14 @@ static void pasemi_adjust_link(struct net_device *dev)
 			printk(KERN_INFO "%s: Link is down.\n", dev->name);
 
 		netif_carrier_off(dev);
+		pasemi_mac_intf_disable(mac);
 		mac->link = 0;
 
 		return;
-	} else
+	} else {
+		pasemi_mac_intf_enable(mac);
 		netif_carrier_on(dev);
+	}
 
 	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
 	new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M |
@@ -897,15 +1006,14 @@ err:
 static int pasemi_mac_open(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
-	int base_irq;
 	unsigned int flags;
 	int ret;
 
 	/* enable rx section */
-	write_dma_reg(mac, PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN);
+	write_dma_reg(PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN);
 
 	/* enable tx section */
-	write_dma_reg(mac, PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN);
+	write_dma_reg(PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN);
 
 	flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) |
 		PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) |
@@ -913,62 +1021,59 @@ static int pasemi_mac_open(struct net_device *dev)
 
 	write_mac_reg(mac, PAS_MAC_CFG_TXP, flags);
 
-	write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
-			   PAS_IOB_DMA_RXCH_CFG_CNTTH(0));
+	ret = pasemi_mac_setup_rx_resources(dev);
+	if (ret)
+		goto out_rx_resources;
 
-	write_iob_reg(mac, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
-			   PAS_IOB_DMA_TXCH_CFG_CNTTH(128));
+	mac->tx = pasemi_mac_setup_tx_resources(dev);
 
-	/* Clear out any residual packet count state from firmware */
-	pasemi_mac_restart_rx_intr(mac);
-	pasemi_mac_restart_tx_intr(mac);
+	if (!mac->tx)
+		goto out_tx_ring;
 
-	/* 0xffffff is max value, about 16ms */
-	write_iob_reg(mac, PAS_IOB_DMA_COM_TIMEOUTCFG,
-			   PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff));
+	/* 0x3ff with 33MHz clock is about 31us */
+	write_iob_reg(PAS_IOB_DMA_COM_TIMEOUTCFG,
+		      PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff));
 
-	ret = pasemi_mac_setup_rx_resources(dev);
-	if (ret)
-		goto out_rx_resources;
+	write_iob_reg(PAS_IOB_DMA_RXCH_CFG(mac->rx->chan.chno),
+		      PAS_IOB_DMA_RXCH_CFG_CNTTH(256));
 
-	ret = pasemi_mac_setup_tx_resources(dev);
-	if (ret)
-		goto out_tx_resources;
+	write_iob_reg(PAS_IOB_DMA_TXCH_CFG(mac->tx->chan.chno),
+		      PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
 
 	write_mac_reg(mac, PAS_MAC_IPC_CHNL,
-			   PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
-			   PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
+		      PAS_MAC_IPC_CHNL_DCHNO(mac->rx->chan.chno) |
+		      PAS_MAC_IPC_CHNL_BCH(mac->rx->chan.chno));
 
 	/* enable rx if */
-	write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
-			   PAS_DMA_RXINT_RCMDSTA_EN |
-			   PAS_DMA_RXINT_RCMDSTA_DROPS_M |
-			   PAS_DMA_RXINT_RCMDSTA_BP |
-			   PAS_DMA_RXINT_RCMDSTA_OO |
-			   PAS_DMA_RXINT_RCMDSTA_BT);
+	write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+		      PAS_DMA_RXINT_RCMDSTA_EN |
+		      PAS_DMA_RXINT_RCMDSTA_DROPS_M |
+		      PAS_DMA_RXINT_RCMDSTA_BP |
+		      PAS_DMA_RXINT_RCMDSTA_OO |
+		      PAS_DMA_RXINT_RCMDSTA_BT);
 
 	/* enable rx channel */
-	write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
-			   PAS_DMA_RXCHAN_CCMDSTA_EN |
-			   PAS_DMA_RXCHAN_CCMDSTA_DU |
-			   PAS_DMA_RXCHAN_CCMDSTA_OD |
-			   PAS_DMA_RXCHAN_CCMDSTA_FD |
-			   PAS_DMA_RXCHAN_CCMDSTA_DT);
+	pasemi_dma_start_chan(&rx_ring(mac)->chan, PAS_DMA_RXCHAN_CCMDSTA_DU |
+						   PAS_DMA_RXCHAN_CCMDSTA_OD |
+						   PAS_DMA_RXCHAN_CCMDSTA_FD |
+						   PAS_DMA_RXCHAN_CCMDSTA_DT);
 
 	/* enable tx channel */
-	write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
-			   PAS_DMA_TXCHAN_TCMDSTA_EN |
-			   PAS_DMA_TXCHAN_TCMDSTA_SZ |
-			   PAS_DMA_TXCHAN_TCMDSTA_DB |
-			   PAS_DMA_TXCHAN_TCMDSTA_DE |
-			   PAS_DMA_TXCHAN_TCMDSTA_DA);
+	pasemi_dma_start_chan(&tx_ring(mac)->chan, PAS_DMA_TXCHAN_TCMDSTA_SZ |
+						   PAS_DMA_TXCHAN_TCMDSTA_DB |
+						   PAS_DMA_TXCHAN_TCMDSTA_DE |
+						   PAS_DMA_TXCHAN_TCMDSTA_DA);
 
 	pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE);
 
-	write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), RX_RING_SIZE>>1);
+	write_dma_reg(PAS_DMA_RXCHAN_INCR(rx_ring(mac)->chan.chno),
+		      RX_RING_SIZE>>1);
+
+	/* Clear out any residual packet count state from firmware */
+	pasemi_mac_restart_rx_intr(mac);
+	pasemi_mac_restart_tx_intr(mac);
 
-	flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
-		PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
+	flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
 
 	if (mac->type == MAC_TYPE_GMAC)
 		flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
@@ -979,55 +1084,63 @@ static int pasemi_mac_open(struct net_device *dev)
 	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
 
 	ret = pasemi_mac_phy_init(dev);
-	/* Some configs don't have PHYs (XAUI etc), so don't complain about
-	 * failed init due to -ENODEV.
-	 */
-	if (ret && ret != -ENODEV)
-		dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret);
+	if (ret) {
+		/* Since we won't get link notification, just enable RX */
+		pasemi_mac_intf_enable(mac);
+		if (mac->type == MAC_TYPE_GMAC) {
+			/* Warn for missing PHY on SGMII (1Gig) ports */
+			dev_warn(&mac->pdev->dev,
+				 "PHY init failed: %d.\n", ret);
+			dev_warn(&mac->pdev->dev,
+				 "Defaulting to 1Gbit full duplex\n");
+		}
+	}
 
 	netif_start_queue(dev);
 	napi_enable(&mac->napi);
 
-	/* Interrupts are a bit different for our DMA controller: While
-	 * it's got one a regular PCI device header, the interrupt there
-	 * is really the base of the range it's using. Each tx and rx
-	 * channel has it's own interrupt source.
-	 */
-
-	base_irq = virq_to_hw(mac->dma_pdev->irq);
+	snprintf(mac->tx_irq_name, sizeof(mac->tx_irq_name), "%s tx",
+		 dev->name);
 
-	mac->tx_irq = irq_create_mapping(NULL, base_irq + mac->dma_txch);
-	mac->rx_irq = irq_create_mapping(NULL, base_irq + 20 + mac->dma_txch);
-
-	ret = request_irq(mac->tx_irq, &pasemi_mac_tx_intr, IRQF_DISABLED,
-			  mac->tx->irq_name, dev);
+	ret = request_irq(mac->tx->chan.irq, &pasemi_mac_tx_intr, IRQF_DISABLED,
+			  mac->tx_irq_name, mac->tx);
 	if (ret) {
 		dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
-			base_irq + mac->dma_txch, ret);
+			mac->tx->chan.irq, ret);
 		goto out_tx_int;
 	}
 
-	ret = request_irq(mac->rx_irq, &pasemi_mac_rx_intr, IRQF_DISABLED,
-			  mac->rx->irq_name, dev);
+	snprintf(mac->rx_irq_name, sizeof(mac->rx_irq_name), "%s rx",
+		 dev->name);
+
+	ret = request_irq(mac->rx->chan.irq, &pasemi_mac_rx_intr, IRQF_DISABLED,
+			  mac->rx_irq_name, mac->rx);
 	if (ret) {
 		dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
-			base_irq + 20 + mac->dma_rxch, ret);
+			mac->rx->chan.irq, ret);
 		goto out_rx_int;
 	}
 
 	if (mac->phydev)
 		phy_start(mac->phydev);
 
+	init_timer(&mac->tx->clean_timer);
+	mac->tx->clean_timer.function = pasemi_mac_tx_timer;
+	mac->tx->clean_timer.data = (unsigned long)mac->tx;
+	mac->tx->clean_timer.expires = jiffies+HZ;
+	add_timer(&mac->tx->clean_timer);
+
 	return 0;
 
 out_rx_int:
-	free_irq(mac->tx_irq, dev);
+	free_irq(mac->tx->chan.irq, mac->tx);
 out_tx_int:
 	napi_disable(&mac->napi);
 	netif_stop_queue(dev);
-	pasemi_mac_free_tx_resources(dev);
-out_tx_resources:
-	pasemi_mac_free_rx_resources(dev);
+out_tx_ring:
+	if (mac->tx)
+		pasemi_mac_free_tx_resources(mac);
+	pasemi_mac_free_rx_resources(mac);
 out_rx_resources:
 
 	return ret;
@@ -1040,46 +1153,53 @@ static int pasemi_mac_close(struct net_device *dev)
 	struct pasemi_mac *mac = netdev_priv(dev);
 	unsigned int sta;
 	int retries;
+	int rxch, txch;
+
+	rxch = rx_ring(mac)->chan.chno;
+	txch = tx_ring(mac)->chan.chno;
 
 	if (mac->phydev) {
 		phy_stop(mac->phydev);
 		phy_disconnect(mac->phydev);
 	}
 
+	del_timer_sync(&mac->tx->clean_timer);
+
 	netif_stop_queue(dev);
 	napi_disable(&mac->napi);
 
-	sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+	sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
 	if (sta & (PAS_DMA_RXINT_RCMDSTA_BP |
 		      PAS_DMA_RXINT_RCMDSTA_OO |
 		      PAS_DMA_RXINT_RCMDSTA_BT))
 		printk(KERN_DEBUG "pasemi_mac: rcmdsta error: 0x%08x\n", sta);
 
-	sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+	sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch));
 	if (sta & (PAS_DMA_RXCHAN_CCMDSTA_DU |
 		     PAS_DMA_RXCHAN_CCMDSTA_OD |
 		     PAS_DMA_RXCHAN_CCMDSTA_FD |
 		     PAS_DMA_RXCHAN_CCMDSTA_DT))
 		printk(KERN_DEBUG "pasemi_mac: ccmdsta error: 0x%08x\n", sta);
 
-	sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
-	if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ |
-		      PAS_DMA_TXCHAN_TCMDSTA_DB |
-		      PAS_DMA_TXCHAN_TCMDSTA_DE |
-		      PAS_DMA_TXCHAN_TCMDSTA_DA))
+	sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch));
+	if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ | PAS_DMA_TXCHAN_TCMDSTA_DB |
+		      PAS_DMA_TXCHAN_TCMDSTA_DE | PAS_DMA_TXCHAN_TCMDSTA_DA))
 		printk(KERN_DEBUG "pasemi_mac: tcmdsta error: 0x%08x\n", sta);
 
 	/* Clean out any pending buffers */
-	pasemi_mac_clean_tx(mac);
-	pasemi_mac_clean_rx(mac, RX_RING_SIZE);
+	pasemi_mac_clean_tx(tx_ring(mac));
+	pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE);
 
 	/* Disable interface */
-	write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), PAS_DMA_TXCHAN_TCMDSTA_ST);
-	write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), PAS_DMA_RXINT_RCMDSTA_ST);
-	write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST);
+	write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch),
+		      PAS_DMA_TXCHAN_TCMDSTA_ST);
+	write_dma_reg( PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+		      PAS_DMA_RXINT_RCMDSTA_ST);
+	write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch),
+		      PAS_DMA_RXCHAN_CCMDSTA_ST);
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+		sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(rxch));
 		if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
 			break;
 		cond_resched();
@@ -1089,7 +1209,7 @@ static int pasemi_mac_close(struct net_device *dev)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+		sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch));
 		if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
 			break;
 		cond_resched();
@@ -1099,7 +1219,7 @@ static int pasemi_mac_close(struct net_device *dev)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+		sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
 		if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
 			break;
 		cond_resched();
@@ -1112,16 +1232,16 @@ static int pasemi_mac_close(struct net_device *dev)
 	 * stopping, since you can't disable when active.
 	 */
 
-	write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
-	write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
-	write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+	write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0);
+	write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0);
+	write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
 
-	free_irq(mac->tx_irq, dev);
-	free_irq(mac->rx_irq, dev);
+	free_irq(mac->tx->chan.irq, mac->tx);
+	free_irq(mac->rx->chan.irq, mac->rx);
 
 	/* Free resources */
-	pasemi_mac_free_rx_resources(dev);
-	pasemi_mac_free_tx_resources(dev);
+	pasemi_mac_free_rx_resources(mac);
+	pasemi_mac_free_tx_resources(mac);
 
 	return 0;
 }
@@ -1135,6 +1255,7 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
 	unsigned int map_size[MAX_SKB_FRAGS+1];
 	unsigned long flags;
 	int i, nfrags;
+	int fill;
 
 	dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD;
 
@@ -1178,10 +1299,12 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
 
 	mactx = dflags | XCT_MACTX_LLEN(skb->len);
 
-	txring = mac->tx;
+	txring = tx_ring(mac);
 
 	spin_lock_irqsave(&txring->lock, flags);
 
+	fill = txring->next_to_fill;
+
 	/* Avoid stepping on the same cache line that the DMA controller
 	 * is currently about to send, so leave at least 8 words available.
 	 * Total free space needed is mactx + fragments + 8
@@ -1192,13 +1315,14 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
 		goto out_err;
 	}
 
-	TX_RING(mac, txring->next_to_fill) = mactx;
-	txring->next_to_fill++;
-	TX_RING_INFO(mac, txring->next_to_fill).skb = skb;
+	TX_DESC(txring, fill) = mactx;
+	TX_DESC_INFO(txring, fill).dma = nfrags;
+	fill++;
+	TX_DESC_INFO(txring, fill).skb = skb;
 	for (i = 0; i <= nfrags; i++) {
-		TX_RING(mac, txring->next_to_fill+i) =
-		XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]);
-		TX_RING_INFO(mac, txring->next_to_fill+i).dma = map[i];
+		TX_DESC(txring, fill+i) =
+			XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]);
+		TX_DESC_INFO(txring, fill+i).dma = map[i];
 	}
 
 	/* We have to add an even number of 8-byte entries to the ring
@@ -1208,15 +1332,14 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
 	if (nfrags & 1)
 		nfrags++;
 
-	txring->next_to_fill = (txring->next_to_fill + nfrags + 1) &
-				(TX_RING_SIZE-1);
+	txring->next_to_fill = (fill + nfrags + 1) & (TX_RING_SIZE-1);
 
 	dev->stats.tx_packets++;
 	dev->stats.tx_bytes += skb->len;
 
 	spin_unlock_irqrestore(&txring->lock, flags);
 
-	write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), (nfrags+2) >> 1);
+	write_dma_reg(PAS_DMA_TXCHAN_INCR(txring->chan.chno), (nfrags+2) >> 1);
 
 	return NETDEV_TX_OK;
 
@@ -1232,7 +1355,7 @@ out_err_nolock:
 
 static void pasemi_mac_set_rx_mode(struct net_device *dev)
 {
-	struct pasemi_mac *mac = netdev_priv(dev);
+	const struct pasemi_mac *mac = netdev_priv(dev);
 	unsigned int flags;
 
 	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
@@ -1253,88 +1376,21 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget)
 	struct net_device *dev = mac->netdev;
 	int pkts;
 
-	pasemi_mac_clean_tx(mac);
-	pkts = pasemi_mac_clean_rx(mac, budget);
+	pasemi_mac_clean_tx(tx_ring(mac));
+	pkts = pasemi_mac_clean_rx(rx_ring(mac), budget);
 	if (pkts < budget) {
 		/* all done, no more packets present */
 		netif_rx_complete(dev, napi);
 
 		pasemi_mac_restart_rx_intr(mac);
+		pasemi_mac_restart_tx_intr(mac);
 	}
 	return pkts;
 }
 
-static void __iomem * __devinit map_onedev(struct pci_dev *p, int index)
-{
-	struct device_node *dn;
-	void __iomem *ret;
-
-	dn = pci_device_to_OF_node(p);
-	if (!dn)
-		goto fallback;
-
-	ret = of_iomap(dn, index);
-	if (!ret)
-		goto fallback;
-
-	return ret;
-fallback:
-	/* This is hardcoded and ugly, but we have some firmware versions
-	 * that don't provide the register space in the device tree. Luckily
-	 * they are at well-known locations so we can just do the math here.
-	 */
-	return ioremap(0xe0000000 + (p->devfn << 12), 0x2000);
-}
-
-static int __devinit pasemi_mac_map_regs(struct pasemi_mac *mac)
-{
-	struct resource res;
-	struct device_node *dn;
-	int err;
-
-	mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
-	if (!mac->dma_pdev) {
-		dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
-		return -ENODEV;
-	}
-
-	mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
-	if (!mac->iob_pdev) {
-		dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n");
-		return -ENODEV;
-	}
-
-	mac->regs = map_onedev(mac->pdev, 0);
-	mac->dma_regs = map_onedev(mac->dma_pdev, 0);
-	mac->iob_regs = map_onedev(mac->iob_pdev, 0);
-
-	if (!mac->regs || !mac->dma_regs || !mac->iob_regs) {
-		dev_err(&mac->pdev->dev, "Can't map registers\n");
-		return -ENODEV;
-	}
-
-	/* The dma status structure is located in the I/O bridge, and
-	 * is cache coherent.
-	 */
-	if (!dma_status) {
-		dn = pci_device_to_OF_node(mac->iob_pdev);
-		if (dn)
-			err = of_address_to_resource(dn, 1, &res);
-		if (!dn || err) {
-			/* Fallback for old firmware */
-			res.start = 0xfd800000;
-			res.end = res.start + 0x1000;
-		}
-		dma_status = __ioremap(res.start, res.end-res.start, 0);
-	}
-
-	return 0;
-}
-
 static int __devinit
 pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	static int index = 0;
 	struct net_device *dev;
 	struct pasemi_mac *mac;
 	int err;
@@ -1362,20 +1418,46 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64);
 
-	dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG;
+	dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG |
+			NETIF_F_HIGHDMA;
 
-	/* These should come out of the device tree eventually */
-	mac->dma_txch = index;
-	mac->dma_rxch = index;
+	mac->lro_mgr.max_aggr = LRO_MAX_AGGR;
+	mac->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
+	mac->lro_mgr.lro_arr = mac->lro_desc;
+	mac->lro_mgr.get_skb_header = get_skb_hdr;
+	mac->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
+	mac->lro_mgr.dev = mac->netdev;
+	mac->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
+	mac->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
 
-	/* We probe GMAC before XAUI, but the DMA interfaces are
-	 * in XAUI, GMAC order.
-	 */
-	if (index < 4)
-		mac->dma_if = index + 2;
-	else
-		mac->dma_if = index - 4;
-	index++;
+
+	mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
+	if (!mac->dma_pdev) {
+		dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
+		err = -ENODEV;
+		goto out;
+	}
+
+	mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
+	if (!mac->iob_pdev) {
+		dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n");
+		err = -ENODEV;
+		goto out;
+	}
+
+	/* get mac addr from device tree */
+	if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) {
+		err = -ENODEV;
+		goto out;
+	}
+	memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr));
+
+	mac->dma_if = mac_to_intf(mac);
+	if (mac->dma_if < 0) {
+		dev_err(&mac->pdev->dev, "Can't map DMA interface\n");
+		err = -ENODEV;
+		goto out;
+	}
 
 	switch (pdev->device) {
 	case 0xa005:
@@ -1389,25 +1471,14 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		goto out;
 	}
 
-	/* get mac addr from device tree */
-	if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) {
-		err = -ENODEV;
-		goto out;
-	}
-	memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr));
-
 	dev->open = pasemi_mac_open;
 	dev->stop = pasemi_mac_close;
 	dev->hard_start_xmit = pasemi_mac_start_tx;
 	dev->set_multicast_list = pasemi_mac_set_rx_mode;
 
-	err = pasemi_mac_map_regs(mac);
 	if (err)
 		goto out;
 
-	mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
-	mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
-
 	mac->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
 
 	/* Enable most messages by default */
@@ -1420,11 +1491,9 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 			err);
 		goto out;
 	} else if netif_msg_probe(mac)
-		printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "
-		       "hw addr %s\n",
+		printk(KERN_INFO "%s: PA Semi %s: intf %d, hw addr %s\n",
 		       dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
-		       mac->dma_if, mac->dma_txch, mac->dma_rxch,
-		       print_mac(mac_buf, dev->dev_addr));
+		       mac->dma_if, print_mac(mac_buf, dev->dev_addr));
 
 	return err;
 
@@ -1433,12 +1502,6 @@ out:
 		pci_dev_put(mac->iob_pdev);
 	if (mac->dma_pdev)
 		pci_dev_put(mac->dma_pdev);
-	if (mac->dma_regs)
-		iounmap(mac->dma_regs);
-	if (mac->iob_regs)
-		iounmap(mac->iob_regs);
-	if (mac->regs)
-		iounmap(mac->regs);
 
 	free_netdev(dev);
 out_disable_device:
@@ -1463,9 +1526,8 @@ static void __devexit pasemi_mac_remove(struct pci_dev *pdev)
 	pci_dev_put(mac->dma_pdev);
 	pci_dev_put(mac->iob_pdev);
 
-	iounmap(mac->regs);
-	iounmap(mac->dma_regs);
-	iounmap(mac->iob_regs);
+	pasemi_dma_free_chan(&mac->tx->chan);
+	pasemi_dma_free_chan(&mac->rx->chan);
 
 	pci_set_drvdata(pdev, NULL);
 	free_netdev(netdev);
@@ -1489,12 +1551,16 @@ static struct pci_driver pasemi_mac_driver = {
 static void __exit pasemi_mac_cleanup_module(void)
 {
 	pci_unregister_driver(&pasemi_mac_driver);
-	__iounmap(dma_status);
-	dma_status = NULL;
 }
 
 int pasemi_mac_init_module(void)
 {
+	int err;
+
+	err = pasemi_dma_init();
+	if (err)
+		return err;
+
 	return pci_register_driver(&pasemi_mac_driver);
 }
 
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
index 60368df72634..8bee2a664c83 100644
--- a/drivers/net/pasemi_mac.h
+++ b/drivers/net/pasemi_mac.h
@@ -26,60 +26,55 @@
 #include <linux/spinlock.h>
 #include <linux/phy.h>
 
+#define MAX_LRO_DESCRIPTORS 8
+
 struct pasemi_mac_txring {
+	struct pasemi_dmachan chan; /* Must be first */
 	spinlock_t	 lock;
-	u64		*ring;
-	dma_addr_t	 dma;
 	unsigned int	 size;
 	unsigned int	 next_to_fill;
 	unsigned int	 next_to_clean;
 	struct pasemi_mac_buffer *ring_info;
-	char		 irq_name[10];  /* "eth%d tx" */
+	struct pasemi_mac *mac;	/* Needed in intr handler */
+	struct timer_list clean_timer;
 };
 
 struct pasemi_mac_rxring {
+	struct pasemi_dmachan chan; /* Must be first */
 	spinlock_t	 lock;
-	u64		*ring;	/* RX channel descriptor ring */
-	dma_addr_t	 dma;
 	u64		*buffers;	/* RX interface buffer ring */
 	dma_addr_t	 buf_dma;
 	unsigned int	 size;
 	unsigned int	 next_to_fill;
 	unsigned int	 next_to_clean;
 	struct pasemi_mac_buffer *ring_info;
-	char		 irq_name[10];  /* "eth%d rx" */
+	struct pasemi_mac *mac;	/* Needed in intr handler */
 };
 
 struct pasemi_mac {
 	struct net_device *netdev;
-	void __iomem *regs;
-	void __iomem *dma_regs;
-	void __iomem *iob_regs;
 	struct pci_dev *pdev;
 	struct pci_dev *dma_pdev;
 	struct pci_dev *iob_pdev;
 	struct phy_device *phydev;
 	struct napi_struct napi;
 
-	/* Pointer to the cacheable per-channel status registers */
-	u64	*rx_status;
-	u64	*tx_status;
-
 	u8		type;
 #define MAC_TYPE_GMAC	1
 #define MAC_TYPE_XAUI	2
-	u32	dma_txch;
 	u32	dma_if;
-	u32	dma_rxch;
 
 	u8		mac_addr[6];
 
+	struct net_lro_mgr	lro_mgr;
+	struct net_lro_desc	lro_desc[MAX_LRO_DESCRIPTORS];
 	struct timer_list	rxtimer;
+	unsigned int		lro_max_aggr;
 
 	struct pasemi_mac_txring *tx;
 	struct pasemi_mac_rxring *rx;
-	unsigned long	tx_irq;
-	unsigned long	rx_irq;
+	char		tx_irq_name[10];		/* "eth%d tx" */
+	char		rx_irq_name[10];		/* "eth%d rx" */
 	int	link;
 	int	speed;
 	int	duplex;
@@ -95,11 +90,8 @@ struct pasemi_mac_buffer {
 };
 
 
-/* status register layout in IOB region, at 0xfb800000 */
-struct pasdma_status {
-	u64 rx_sta[64];
-	u64 tx_sta[20];
-};
+/* PCI register offsets and formats */
+
 
 /* MAC CFG register offsets */
 enum {
@@ -173,333 +165,4 @@ enum {
 #define PAS_MAC_IPC_CHNL_BCH(x)		(((x) << PAS_MAC_IPC_CHNL_BCH_S) & \
 					 PAS_MAC_IPC_CHNL_BCH_M)
 
-/* All these registers live in the PCI configuration space for the DMA PCI
- * device. Use the normal PCI config access functions for them.
- */
-enum {
-	PAS_DMA_COM_TXCMD = 0x100,	/* Transmit Command Register  */
-	PAS_DMA_COM_TXSTA = 0x104,	/* Transmit Status Register   */
-	PAS_DMA_COM_RXCMD = 0x108,	/* Receive Command Register   */
-	PAS_DMA_COM_RXSTA = 0x10c,	/* Receive Status Register    */
-};
-#define PAS_DMA_COM_TXCMD_EN	0x00000001 /* enable */
-#define PAS_DMA_COM_TXSTA_ACT	0x00000001 /* active */
-#define PAS_DMA_COM_RXCMD_EN	0x00000001 /* enable */
-#define PAS_DMA_COM_RXSTA_ACT	0x00000001 /* active */
-
-
-/* Per-interface and per-channel registers */
-#define _PAS_DMA_RXINT_STRIDE		0x20
-#define PAS_DMA_RXINT_RCMDSTA(i)	(0x200+(i)*_PAS_DMA_RXINT_STRIDE)
-#define    PAS_DMA_RXINT_RCMDSTA_EN	0x00000001
-#define    PAS_DMA_RXINT_RCMDSTA_ST	0x00000002
-#define    PAS_DMA_RXINT_RCMDSTA_MBT	0x00000008
-#define    PAS_DMA_RXINT_RCMDSTA_MDR	0x00000010
-#define    PAS_DMA_RXINT_RCMDSTA_MOO	0x00000020
-#define    PAS_DMA_RXINT_RCMDSTA_MBP	0x00000040
-#define    PAS_DMA_RXINT_RCMDSTA_BT	0x00000800
-#define    PAS_DMA_RXINT_RCMDSTA_DR	0x00001000
-#define    PAS_DMA_RXINT_RCMDSTA_OO	0x00002000
-#define    PAS_DMA_RXINT_RCMDSTA_BP	0x00004000
-#define    PAS_DMA_RXINT_RCMDSTA_TB	0x00008000
-#define    PAS_DMA_RXINT_RCMDSTA_ACT	0x00010000
-#define    PAS_DMA_RXINT_RCMDSTA_DROPS_M	0xfffe0000
-#define    PAS_DMA_RXINT_RCMDSTA_DROPS_S	17
-#define PAS_DMA_RXINT_CFG(i)		(0x204+(i)*_PAS_DMA_RXINT_STRIDE)
-#define    PAS_DMA_RXINT_CFG_RBP	0x80000000
-#define    PAS_DMA_RXINT_CFG_ITRR	0x40000000
-#define    PAS_DMA_RXINT_CFG_DHL_M	0x07000000
-#define    PAS_DMA_RXINT_CFG_DHL_S	24
-#define    PAS_DMA_RXINT_CFG_DHL(x)	(((x) << PAS_DMA_RXINT_CFG_DHL_S) & \
-					 PAS_DMA_RXINT_CFG_DHL_M)
-#define    PAS_DMA_RXINT_CFG_ITR	0x00400000
-#define    PAS_DMA_RXINT_CFG_LW		0x00200000
-#define    PAS_DMA_RXINT_CFG_L2		0x00100000
-#define    PAS_DMA_RXINT_CFG_HEN	0x00080000
-#define    PAS_DMA_RXINT_CFG_WIF	0x00000002
-#define    PAS_DMA_RXINT_CFG_WIL	0x00000001
-
-#define PAS_DMA_RXINT_INCR(i)		(0x210+(i)*_PAS_DMA_RXINT_STRIDE)
-#define    PAS_DMA_RXINT_INCR_INCR_M	0x0000ffff
-#define    PAS_DMA_RXINT_INCR_INCR_S	0
-#define    PAS_DMA_RXINT_INCR_INCR(x)	((x) & 0x0000ffff)
-#define PAS_DMA_RXINT_BASEL(i)		(0x218+(i)*_PAS_DMA_RXINT_STRIDE)
-#define    PAS_DMA_RXINT_BASEL_BRBL(x)	((x) & ~0x3f)
-#define PAS_DMA_RXINT_BASEU(i)		(0x21c+(i)*_PAS_DMA_RXINT_STRIDE)
-#define    PAS_DMA_RXINT_BASEU_BRBH(x)	((x) & 0xfff)
-#define    PAS_DMA_RXINT_BASEU_SIZ_M	0x3fff0000	/* # of cache lines worth of buffer ring */
-#define    PAS_DMA_RXINT_BASEU_SIZ_S	16		/* 0 = 16K */
-#define    PAS_DMA_RXINT_BASEU_SIZ(x)	(((x) << PAS_DMA_RXINT_BASEU_SIZ_S) & \
-					 PAS_DMA_RXINT_BASEU_SIZ_M)
-
-
-#define _PAS_DMA_TXCHAN_STRIDE	0x20    /* Size per channel		*/
-#define _PAS_DMA_TXCHAN_TCMDSTA	0x300	/* Command / Status		*/
-#define _PAS_DMA_TXCHAN_CFG	0x304	/* Configuration		*/
-#define _PAS_DMA_TXCHAN_DSCRBU	0x308	/* Descriptor BU Allocation	*/
-#define _PAS_DMA_TXCHAN_INCR	0x310	/* Descriptor increment		*/
-#define _PAS_DMA_TXCHAN_CNT	0x314	/* Descriptor count/offset	*/
-#define _PAS_DMA_TXCHAN_BASEL	0x318	/* Descriptor ring base (low)	*/
-#define _PAS_DMA_TXCHAN_BASEU	0x31c	/*			(high)	*/
-#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE)
-#define    PAS_DMA_TXCHAN_TCMDSTA_EN	0x00000001	/* Enabled */
-#define    PAS_DMA_TXCHAN_TCMDSTA_ST	0x00000002	/* Stop interface */
-#define    PAS_DMA_TXCHAN_TCMDSTA_ACT	0x00010000	/* Active */
-#define    PAS_DMA_TXCHAN_TCMDSTA_SZ	0x00000800
-#define    PAS_DMA_TXCHAN_TCMDSTA_DB	0x00000400
-#define    PAS_DMA_TXCHAN_TCMDSTA_DE	0x00000200
-#define    PAS_DMA_TXCHAN_TCMDSTA_DA	0x00000100
-#define PAS_DMA_TXCHAN_CFG(c)     (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
-#define    PAS_DMA_TXCHAN_CFG_TY_IFACE	0x00000000	/* Type = interface */
-#define    PAS_DMA_TXCHAN_CFG_TATTR_M	0x0000003c
-#define    PAS_DMA_TXCHAN_CFG_TATTR_S	2
-#define    PAS_DMA_TXCHAN_CFG_TATTR(x)	(((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \
-					 PAS_DMA_TXCHAN_CFG_TATTR_M)
-#define    PAS_DMA_TXCHAN_CFG_WT_M	0x000001c0
-#define    PAS_DMA_TXCHAN_CFG_WT_S	6
-#define    PAS_DMA_TXCHAN_CFG_WT(x)	(((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
-					 PAS_DMA_TXCHAN_CFG_WT_M)
-#define    PAS_DMA_TXCHAN_CFG_TRD	0x00010000	/* translate data */
-#define    PAS_DMA_TXCHAN_CFG_TRR	0x00008000	/* translate rings */
-#define    PAS_DMA_TXCHAN_CFG_UP	0x00004000	/* update tx descr when sent */
-#define    PAS_DMA_TXCHAN_CFG_CL	0x00002000	/* Clean last line */
-#define    PAS_DMA_TXCHAN_CFG_CF	0x00001000	/* Clean first line */
-#define PAS_DMA_TXCHAN_INCR(c)    (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
-#define PAS_DMA_TXCHAN_BASEL(c)   (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
-#define    PAS_DMA_TXCHAN_BASEL_BRBL_M	0xffffffc0
-#define    PAS_DMA_TXCHAN_BASEL_BRBL_S	0
-#define    PAS_DMA_TXCHAN_BASEL_BRBL(x)	(((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \
-					 PAS_DMA_TXCHAN_BASEL_BRBL_M)
-#define PAS_DMA_TXCHAN_BASEU(c)   (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE)
-#define    PAS_DMA_TXCHAN_BASEU_BRBH_M	0x00000fff
-#define    PAS_DMA_TXCHAN_BASEU_BRBH_S	0
-#define    PAS_DMA_TXCHAN_BASEU_BRBH(x)	(((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \
-					 PAS_DMA_TXCHAN_BASEU_BRBH_M)
-/* # of cache lines worth of buffer ring */
-#define    PAS_DMA_TXCHAN_BASEU_SIZ_M	0x3fff0000
-#define    PAS_DMA_TXCHAN_BASEU_SIZ_S	16		/* 0 = 16K */
-#define    PAS_DMA_TXCHAN_BASEU_SIZ(x)	(((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \
-					 PAS_DMA_TXCHAN_BASEU_SIZ_M)
-
-#define _PAS_DMA_RXCHAN_STRIDE	0x20    /* Size per channel		*/
-#define _PAS_DMA_RXCHAN_CCMDSTA	0x800	/* Command / Status		*/
-#define _PAS_DMA_RXCHAN_CFG	0x804	/* Configuration		*/
-#define _PAS_DMA_RXCHAN_INCR	0x810	/* Descriptor increment		*/
-#define _PAS_DMA_RXCHAN_CNT	0x814	/* Descriptor count/offset	*/
-#define _PAS_DMA_RXCHAN_BASEL	0x818	/* Descriptor ring base (low)	*/
-#define _PAS_DMA_RXCHAN_BASEU	0x81c	/*			(high)	*/
-#define PAS_DMA_RXCHAN_CCMDSTA(c) (0x800+(c)*_PAS_DMA_RXCHAN_STRIDE)
-#define    PAS_DMA_RXCHAN_CCMDSTA_EN	0x00000001	/* Enabled */
-#define    PAS_DMA_RXCHAN_CCMDSTA_ST	0x00000002	/* Stop interface */
-#define    PAS_DMA_RXCHAN_CCMDSTA_ACT	0x00010000	/* Active */
-#define    PAS_DMA_RXCHAN_CCMDSTA_DU	0x00020000
-#define    PAS_DMA_RXCHAN_CCMDSTA_OD	0x00002000
-#define    PAS_DMA_RXCHAN_CCMDSTA_FD	0x00001000
-#define    PAS_DMA_RXCHAN_CCMDSTA_DT	0x00000800
-#define PAS_DMA_RXCHAN_CFG(c)     (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
-#define    PAS_DMA_RXCHAN_CFG_CTR	0x00000400
-#define    PAS_DMA_RXCHAN_CFG_HBU_M	0x00000380
-#define    PAS_DMA_RXCHAN_CFG_HBU_S	7
-#define    PAS_DMA_RXCHAN_CFG_HBU(x)	(((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \
-					 PAS_DMA_RXCHAN_CFG_HBU_M)
-#define PAS_DMA_RXCHAN_INCR(c)    (0x810+(c)*_PAS_DMA_RXCHAN_STRIDE)
-#define PAS_DMA_RXCHAN_BASEL(c)   (0x818+(c)*_PAS_DMA_RXCHAN_STRIDE)
-#define    PAS_DMA_RXCHAN_BASEL_BRBL_M	0xffffffc0
-#define    PAS_DMA_RXCHAN_BASEL_BRBL_S	0
-#define    PAS_DMA_RXCHAN_BASEL_BRBL(x)	(((x) << PAS_DMA_RXCHAN_BASEL_BRBL_S) & \
-					 PAS_DMA_RXCHAN_BASEL_BRBL_M)
-#define PAS_DMA_RXCHAN_BASEU(c)   (0x81c+(c)*_PAS_DMA_RXCHAN_STRIDE)
-#define    PAS_DMA_RXCHAN_BASEU_BRBH_M	0x00000fff
-#define    PAS_DMA_RXCHAN_BASEU_BRBH_S	0
-#define    PAS_DMA_RXCHAN_BASEU_BRBH(x)	(((x) << PAS_DMA_RXCHAN_BASEU_BRBH_S) & \
-					 PAS_DMA_RXCHAN_BASEU_BRBH_M)
-/* # of cache lines worth of buffer ring */
-#define    PAS_DMA_RXCHAN_BASEU_SIZ_M	0x3fff0000
-#define    PAS_DMA_RXCHAN_BASEU_SIZ_S	16		/* 0 = 16K */
-#define    PAS_DMA_RXCHAN_BASEU_SIZ(x)	(((x) << PAS_DMA_RXCHAN_BASEU_SIZ_S) & \
-					 PAS_DMA_RXCHAN_BASEU_SIZ_M)
-
-#define    PAS_STATUS_PCNT_M		0x000000000000ffffull
-#define    PAS_STATUS_PCNT_S		0
-#define    PAS_STATUS_DCNT_M		0x00000000ffff0000ull
-#define    PAS_STATUS_DCNT_S		16
-#define    PAS_STATUS_BPCNT_M		0x0000ffff00000000ull
-#define    PAS_STATUS_BPCNT_S		32
-#define    PAS_STATUS_CAUSE_M		0xf000000000000000ull
-#define    PAS_STATUS_TIMER		0x1000000000000000ull
-#define    PAS_STATUS_ERROR		0x2000000000000000ull
-#define    PAS_STATUS_SOFT		0x4000000000000000ull
-#define    PAS_STATUS_INT		0x8000000000000000ull
-
-#define PAS_IOB_COM_PKTHDRCNT		0x120
-#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR1_M	0x0fff0000
-#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR1_S	16
-#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR0_M	0x00000fff
-#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR0_S	0
-
-#define PAS_IOB_DMA_RXCH_CFG(i)		(0x1100 + (i)*4)
-#define    PAS_IOB_DMA_RXCH_CFG_CNTTH_M		0x00000fff
-#define    PAS_IOB_DMA_RXCH_CFG_CNTTH_S		0
-#define    PAS_IOB_DMA_RXCH_CFG_CNTTH(x)	(((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \
-						 PAS_IOB_DMA_RXCH_CFG_CNTTH_M)
-#define PAS_IOB_DMA_TXCH_CFG(i)		(0x1200 + (i)*4)
-#define    PAS_IOB_DMA_TXCH_CFG_CNTTH_M		0x00000fff
-#define    PAS_IOB_DMA_TXCH_CFG_CNTTH_S		0
-#define    PAS_IOB_DMA_TXCH_CFG_CNTTH(x)	(((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \
-						 PAS_IOB_DMA_TXCH_CFG_CNTTH_M)
-#define PAS_IOB_DMA_RXCH_STAT(i)	(0x1300 + (i)*4)
-#define    PAS_IOB_DMA_RXCH_STAT_INTGEN	0x00001000
-#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL_M	0x00000fff
-#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL_S	0
-#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL(x)	(((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\
-						 PAS_IOB_DMA_RXCH_STAT_CNTDEL_M)
-#define PAS_IOB_DMA_TXCH_STAT(i)	(0x1400 + (i)*4)
-#define    PAS_IOB_DMA_TXCH_STAT_INTGEN	0x00001000
-#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL_M	0x00000fff
-#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL_S	0
-#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL(x)	(((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\
-						 PAS_IOB_DMA_TXCH_STAT_CNTDEL_M)
-#define PAS_IOB_DMA_RXCH_RESET(i)	(0x1500 + (i)*4)
-#define    PAS_IOB_DMA_RXCH_RESET_PCNT_M	0xffff0000
-#define    PAS_IOB_DMA_RXCH_RESET_PCNT_S	16
-#define    PAS_IOB_DMA_RXCH_RESET_PCNT(x)	(((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \
-						 PAS_IOB_DMA_RXCH_RESET_PCNT_M)
-#define    PAS_IOB_DMA_RXCH_RESET_PCNTRST	0x00000020
-#define    PAS_IOB_DMA_RXCH_RESET_DCNTRST	0x00000010
-#define    PAS_IOB_DMA_RXCH_RESET_TINTC		0x00000008
-#define    PAS_IOB_DMA_RXCH_RESET_DINTC		0x00000004
-#define    PAS_IOB_DMA_RXCH_RESET_SINTC		0x00000002
-#define    PAS_IOB_DMA_RXCH_RESET_PINTC		0x00000001
-#define PAS_IOB_DMA_TXCH_RESET(i)	(0x1600 + (i)*4)
-#define    PAS_IOB_DMA_TXCH_RESET_PCNT_M	0xffff0000
-#define    PAS_IOB_DMA_TXCH_RESET_PCNT_S	16
-#define    PAS_IOB_DMA_TXCH_RESET_PCNT(x)	(((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \
-						 PAS_IOB_DMA_TXCH_RESET_PCNT_M)
-#define    PAS_IOB_DMA_TXCH_RESET_PCNTRST	0x00000020
-#define    PAS_IOB_DMA_TXCH_RESET_DCNTRST	0x00000010
-#define    PAS_IOB_DMA_TXCH_RESET_TINTC		0x00000008
-#define    PAS_IOB_DMA_TXCH_RESET_DINTC		0x00000004
-#define    PAS_IOB_DMA_TXCH_RESET_SINTC		0x00000002
-#define    PAS_IOB_DMA_TXCH_RESET_PINTC		0x00000001
-
-#define PAS_IOB_DMA_COM_TIMEOUTCFG		0x1700
-#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M	0x00ffffff
-#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S	0
-#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x)	(((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \
-						 PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M)
-
-/* Transmit descriptor fields */
-#define	XCT_MACTX_T		0x8000000000000000ull
-#define	XCT_MACTX_ST		0x4000000000000000ull
-#define XCT_MACTX_NORES		0x0000000000000000ull
-#define XCT_MACTX_8BRES		0x1000000000000000ull
-#define XCT_MACTX_24BRES	0x2000000000000000ull
-#define XCT_MACTX_40BRES	0x3000000000000000ull
-#define XCT_MACTX_I		0x0800000000000000ull
-#define XCT_MACTX_O		0x0400000000000000ull
-#define XCT_MACTX_E		0x0200000000000000ull
-#define XCT_MACTX_VLAN_M	0x0180000000000000ull
-#define XCT_MACTX_VLAN_NOP	0x0000000000000000ull
-#define XCT_MACTX_VLAN_REMOVE	0x0080000000000000ull
-#define XCT_MACTX_VLAN_INSERT   0x0100000000000000ull
-#define XCT_MACTX_VLAN_REPLACE  0x0180000000000000ull
-#define XCT_MACTX_CRC_M		0x0060000000000000ull
-#define XCT_MACTX_CRC_NOP	0x0000000000000000ull
-#define XCT_MACTX_CRC_INSERT	0x0020000000000000ull
-#define XCT_MACTX_CRC_PAD	0x0040000000000000ull
-#define XCT_MACTX_CRC_REPLACE	0x0060000000000000ull
-#define XCT_MACTX_SS		0x0010000000000000ull
-#define XCT_MACTX_LLEN_M	0x00007fff00000000ull
-#define XCT_MACTX_LLEN_S	32ull
-#define XCT_MACTX_LLEN(x)	((((long)(x)) << XCT_MACTX_LLEN_S) & \
-				 XCT_MACTX_LLEN_M)
-#define XCT_MACTX_IPH_M		0x00000000f8000000ull
-#define XCT_MACTX_IPH_S		27ull
-#define XCT_MACTX_IPH(x)	((((long)(x)) << XCT_MACTX_IPH_S) & \
-				 XCT_MACTX_IPH_M)
-#define XCT_MACTX_IPO_M		0x0000000007c00000ull
-#define XCT_MACTX_IPO_S		22ull
-#define XCT_MACTX_IPO(x)	((((long)(x)) << XCT_MACTX_IPO_S) & \
-				 XCT_MACTX_IPO_M)
-#define XCT_MACTX_CSUM_M	0x0000000000000060ull
-#define XCT_MACTX_CSUM_NOP	0x0000000000000000ull
-#define XCT_MACTX_CSUM_TCP	0x0000000000000040ull
-#define XCT_MACTX_CSUM_UDP	0x0000000000000060ull
-#define XCT_MACTX_V6		0x0000000000000010ull
-#define XCT_MACTX_C		0x0000000000000004ull
-#define XCT_MACTX_AL2		0x0000000000000002ull
-
-/* Receive descriptor fields */
-#define	XCT_MACRX_T		0x8000000000000000ull
-#define	XCT_MACRX_ST		0x4000000000000000ull
-#define XCT_MACRX_RR_M		0x3000000000000000ull
-#define XCT_MACRX_RR_NORES	0x0000000000000000ull
-#define XCT_MACRX_RR_8BRES	0x1000000000000000ull
-#define XCT_MACRX_O		0x0400000000000000ull
-#define XCT_MACRX_E		0x0200000000000000ull
-#define XCT_MACRX_FF		0x0100000000000000ull
-#define XCT_MACRX_PF		0x0080000000000000ull
-#define XCT_MACRX_OB		0x0040000000000000ull
-#define XCT_MACRX_OD		0x0020000000000000ull
-#define XCT_MACRX_FS		0x0010000000000000ull
-#define XCT_MACRX_NB_M		0x000fc00000000000ull
-#define XCT_MACRX_NB_S		46ULL
-#define XCT_MACRX_NB(x)		((((long)(x)) << XCT_MACRX_NB_S) & \
-				 XCT_MACRX_NB_M)
-#define XCT_MACRX_LLEN_M	0x00003fff00000000ull
-#define XCT_MACRX_LLEN_S	32ULL
-#define XCT_MACRX_LLEN(x)	((((long)(x)) << XCT_MACRX_LLEN_S) & \
-				 XCT_MACRX_LLEN_M)
-#define XCT_MACRX_CRC		0x0000000080000000ull
-#define XCT_MACRX_LEN_M		0x0000000060000000ull
-#define XCT_MACRX_LEN_TOOSHORT	0x0000000020000000ull
-#define XCT_MACRX_LEN_BELOWMIN	0x0000000040000000ull
-#define XCT_MACRX_LEN_TRUNC	0x0000000060000000ull
-#define XCT_MACRX_CAST_M	0x0000000018000000ull
-#define XCT_MACRX_CAST_UNI	0x0000000000000000ull
-#define XCT_MACRX_CAST_MULTI	0x0000000008000000ull
-#define XCT_MACRX_CAST_BROAD	0x0000000010000000ull
-#define XCT_MACRX_CAST_PAUSE	0x0000000018000000ull
-#define XCT_MACRX_VLC_M		0x0000000006000000ull
-#define XCT_MACRX_FM		0x0000000001000000ull
-#define XCT_MACRX_HTY_M		0x0000000000c00000ull
-#define XCT_MACRX_HTY_IPV4_OK	0x0000000000000000ull
-#define XCT_MACRX_HTY_IPV6 	0x0000000000400000ull
-#define XCT_MACRX_HTY_IPV4_BAD	0x0000000000800000ull
-#define XCT_MACRX_HTY_NONIP	0x0000000000c00000ull
-#define XCT_MACRX_IPP_M		0x00000000003f0000ull
-#define XCT_MACRX_IPP_S		16
-#define XCT_MACRX_CSUM_M	0x000000000000ffffull
-#define XCT_MACRX_CSUM_S	0
-
-#define XCT_PTR_T		0x8000000000000000ull
-#define XCT_PTR_LEN_M		0x7ffff00000000000ull
-#define XCT_PTR_LEN_S		44
-#define XCT_PTR_LEN(x)		((((long)(x)) << XCT_PTR_LEN_S) & \
-				 XCT_PTR_LEN_M)
-#define XCT_PTR_ADDR_M		0x00000fffffffffffull
-#define XCT_PTR_ADDR_S		0
-#define XCT_PTR_ADDR(x)		((((long)(x)) << XCT_PTR_ADDR_S) & \
-				 XCT_PTR_ADDR_M)
-
-/* Receive interface 8byte result fields */
-#define XCT_RXRES_8B_L4O_M	0xff00000000000000ull
-#define XCT_RXRES_8B_L4O_S	56
-#define XCT_RXRES_8B_RULE_M	0x00ffff0000000000ull
-#define XCT_RXRES_8B_RULE_S	40
-#define XCT_RXRES_8B_EVAL_M	0x000000ffff000000ull
-#define XCT_RXRES_8B_EVAL_S	24
-#define XCT_RXRES_8B_HTYPE_M	0x0000000000f00000ull
-#define XCT_RXRES_8B_HASH_M	0x00000000000fffffull
-#define XCT_RXRES_8B_HASH_S	0
-
-/* Receive interface buffer fields */
-#define XCT_RXB_LEN_M		0x0ffff00000000000ull
-#define XCT_RXB_LEN_S		44
-#define XCT_RXB_LEN(x)		((((long)(x)) << XCT_PTR_LEN_S) & XCT_PTR_LEN_M)
-#define XCT_RXB_ADDR_M		0x00000fffffffffffull
-#define XCT_RXB_ADDR_S		0
-#define XCT_RXB_ADDR(x)		((((long)(x)) << XCT_PTR_ADDR_S) & XCT_PTR_ADDR_M)
-
-
 #endif /* PASEMI_MAC_H */
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 8d910a372f89..6d342f6c14f6 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -1040,15 +1040,13 @@ void ei_tx_timeout(struct net_device *dev)
 
 	/* Ugly but a reset can be slow, yet must be protected */
 		
-	disable_irq_nosync(dev->irq);
-	spin_lock(&ei_local->page_lock);
+	spin_lock_irqsave(&ei_local->page_lock, flags);
 		
 	/* Try to restart the card.  Perhaps the user has fixed something. */
 	ei_reset_8390(dev);
 	AX88190_init(dev, 1);
 		
-	spin_unlock(&ei_local->page_lock);
-	enable_irq(dev->irq);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 	netif_wake_queue(dev);
 }
     
@@ -1085,9 +1083,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	 *	Slow phase with lock held.
 	 */
 	 
-	disable_irq_nosync(dev->irq);
-	
-	spin_lock(&ei_local->page_lock);
+	spin_lock_irqsave(&ei_local->page_lock, flags);
 	
 	ei_local->irqlock = 1;
 
@@ -1125,8 +1121,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		ei_local->irqlock = 0;
 		netif_stop_queue(dev);
 		outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-		spin_unlock(&ei_local->page_lock);
-		enable_irq(dev->irq);
+		spin_unlock_irqrestore(&ei_local->page_lock, flags);
 		ei_local->stat.tx_errors++;
 		return 1;
 	}
@@ -1172,8 +1167,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	ei_local->irqlock = 0;
 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
 	
-	spin_unlock(&ei_local->page_lock);
-	enable_irq(dev->irq);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 
 	dev_kfree_skb (skb);
 	ei_local->stat.tx_bytes += send_length;
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 8c719b4df544..949c6df74c97 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -731,18 +731,13 @@ module_exit(exit_fmvj18x_cs);
 
 /*====================================================================*/
 
-static irqreturn_t fjn_interrupt(int irq, void *dev_id)
+static irqreturn_t fjn_interrupt(int dummy, void *dev_id)
 {
     struct net_device *dev = dev_id;
     local_info_t *lp = netdev_priv(dev);
     kio_addr_t ioaddr;
     unsigned short tx_stat, rx_stat;
 
-    if (lp == NULL) {
-        printk(KERN_NOTICE "fjn_interrupt(): irq %d for "
-	       "unknown device.\n", irq);
-        return IRQ_NONE;
-    }
     ioaddr = dev->base_addr;
 
     /* avoid multiple interrupts */
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 51bbd582f16c..9ba56aa26a1b 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -38,6 +38,7 @@
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
+#include <linux/log2.h>
 #include "../8390.h"
 
 #include <pcmcia/cs_types.h>
@@ -1484,8 +1485,7 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
 	window_size = 32 * 1024;
 
     /* Make sure it's a power of two.  */
-    while ((window_size & (window_size - 1)) != 0)
-	window_size += window_size & ~(window_size - 1);
+    window_size = roundup_pow_of_two(window_size);
 
     /* Allocate a memory window */
     req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 90498ffe26f2..c4b74e9fed20 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -137,7 +137,7 @@ static const char pcnet32_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Loopback test  (offline)"
 };
 
-#define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN)
+#define PCNET32_TEST_LEN	ARRAY_SIZE(pcnet32_gstrings_test)
 
 #define PCNET32_NUM_REGS 136
 
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 57c98669984d..fee3d7b1feba 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -106,6 +106,7 @@ static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n"
 #include <linux/if_plip.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
+#include <linux/completion.h>
 #include <linux/parport.h>
 #include <linux/bitops.h>
 
@@ -114,7 +115,6 @@ static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n"
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
-#include <asm/semaphore.h>
 
 /* Maximum number of devices to support. */
 #define PLIP_MAX  8
@@ -221,7 +221,7 @@ struct net_local {
 	int should_relinquish;
 	spinlock_t lock;
 	atomic_t kill_timer;
-	struct semaphore killed_timer_sem;
+	struct completion killed_timer_cmp;
 };
 
 static inline void enable_parport_interrupts (struct net_device *dev)
@@ -385,7 +385,7 @@ plip_timer_bh(struct work_struct *work)
 		schedule_delayed_work(&nl->timer, 1);
 	}
 	else {
-		up (&nl->killed_timer_sem);
+		complete(&nl->killed_timer_cmp);
 	}
 }
 
@@ -1112,9 +1112,9 @@ plip_close(struct net_device *dev)
 
 	if (dev->irq == -1)
 	{
-		init_MUTEX_LOCKED (&nl->killed_timer_sem);
+		init_completion(&nl->killed_timer_cmp);
 		atomic_set (&nl->kill_timer, 1);
-		down (&nl->killed_timer_sem);
+		wait_for_completion(&nl->killed_timer_cmp);
 	}
 
 #ifdef NOTDEF
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
index eb98b661efba..034c1c650bcb 100644
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp_deflate.c
@@ -206,7 +206,7 @@ static void z_comp_reset(void *arg)
  *	Returns the length of the compressed packet, or 0 if the
  *	packet is incompressible.
  */
-int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf,
+static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf,
 	       int isize, int osize)
 {
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
@@ -435,7 +435,7 @@ static void z_decomp_reset(void *arg)
  * bug, so we return DECOMP_FATALERROR for them in order to turn off
  * compression, even though they are detected by inspecting the input.
  */
-int z_decompress(void *arg, unsigned char *ibuf, int isize,
+static int z_decompress(void *arg, unsigned char *ibuf, int isize,
 		 unsigned char *obuf, int osize)
 {
 	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 4f690378bb77..4dc5b4b7a561 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1871,7 +1871,7 @@ ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb)
  * complete packet, or we get to the sequence number for a fragment
  * which hasn't arrived but might still do so.
  */
-struct sk_buff *
+static struct sk_buff *
 ppp_mp_reconstruct(struct ppp *ppp)
 {
 	u32 seq = ppp->nextseq;
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index f0c6a1926a02..0d80fa546719 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -42,9 +42,9 @@
 #include <linux/if_ppp.h>
 #include <linux/ppp_channel.h>
 #include <linux/spinlock.h>
+#include <linux/completion.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
 
 #define PPP_VERSION	"2.4.2"
 
@@ -70,7 +70,7 @@ struct syncppp {
 	struct tasklet_struct tsk;
 
 	atomic_t	refcnt;
-	struct semaphore dead_sem;
+	struct completion dead_cmp;
 	struct ppp_channel chan;	/* interface to generic ppp layer */
 };
 
@@ -195,7 +195,7 @@ static struct syncppp *sp_get(struct tty_struct *tty)
 static void sp_put(struct syncppp *ap)
 {
 	if (atomic_dec_and_test(&ap->refcnt))
-		up(&ap->dead_sem);
+		complete(&ap->dead_cmp);
 }
 
 /*
@@ -225,7 +225,7 @@ ppp_sync_open(struct tty_struct *tty)
 	tasklet_init(&ap->tsk, ppp_sync_process, (unsigned long) ap);
 
 	atomic_set(&ap->refcnt, 1);
-	init_MUTEX_LOCKED(&ap->dead_sem);
+	init_completion(&ap->dead_cmp);
 
 	ap->chan.private = ap;
 	ap->chan.ops = &sync_ops;
@@ -273,7 +273,7 @@ ppp_sync_close(struct tty_struct *tty)
 	 * by the time it returns.
 	 */
 	if (!atomic_dec_and_test(&ap->refcnt))
-		down(&ap->dead_sem);
+		wait_for_completion(&ap->dead_cmp);
 	tasklet_kill(&ap->tsk);
 
 	ppp_unregister_channel(&ap->chan);
@@ -560,7 +560,7 @@ static void ppp_sync_process(unsigned long arg)
  * Procedures for encapsulation and framing.
  */
 
-struct sk_buff*
+static struct sk_buff*
 ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb)
 {
 	int proto;
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index a005d8f4c38e..ac0ac98b19cd 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -989,6 +989,7 @@ out:
 }
 
 static void *pppoe_seq_start(struct seq_file *seq, loff_t *pos)
+	__acquires(pppoe_hash_lock)
 {
 	loff_t l = *pos;
 
@@ -1022,6 +1023,7 @@ out:
 }
 
 static void pppoe_seq_stop(struct seq_file *seq, void *v)
+	__releases(pppoe_hash_lock)
 {
 	read_unlock_bh(&pppoe_hash_lock);
 }
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index a7556cd2df79..1b51bb668d39 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -2489,7 +2489,7 @@ static void __exit pppol2tp_exit(void)
 module_init(pppol2tp_init);
 module_exit(pppol2tp_exit);
 
-MODULE_AUTHOR("Martijn van Oosterhout <kleptog@svana.org>,"
+MODULE_AUTHOR("Martijn van Oosterhout <kleptog@svana.org>, "
 	      "James Chapman <jchapman@katalix.com>");
 MODULE_DESCRIPTION("PPP over L2TP over UDP");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index cf0774de6c41..a6aeb9d60443 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -540,20 +540,12 @@ static void eeprom_readword(struct ql3_adapter *qdev,
 	fm93c56a_deselect(qdev);
 }
 
-static void ql_swap_mac_addr(u8 * macAddress)
-{
-#ifdef __BIG_ENDIAN
-	u8 temp;
-	temp = macAddress[0];
-	macAddress[0] = macAddress[1];
-	macAddress[1] = temp;
-	temp = macAddress[2];
-	macAddress[2] = macAddress[3];
-	macAddress[3] = temp;
-	temp = macAddress[4];
-	macAddress[4] = macAddress[5];
-	macAddress[5] = temp;
-#endif
+static void ql_set_mac_addr(struct net_device *ndev, u16 *addr)
+{
+	__le16 *p = (__le16 *)ndev->dev_addr;
+	p[0] = cpu_to_le16(addr[0]);
+	p[1] = cpu_to_le16(addr[1]);
+	p[2] = cpu_to_le16(addr[2]);
 }
 
 static int ql_get_nvram_params(struct ql3_adapter *qdev)
@@ -590,18 +582,6 @@ static int ql_get_nvram_params(struct ql3_adapter *qdev)
 		return -1;
 	}
 
-	/*
-	 * We have a problem with endianness for the MAC addresses
-	 * and the two 8-bit values version, and numPorts.  We
-	 * have to swap them on big endian systems.
-	 */
-	ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn0.macAddress);
-	ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn1.macAddress);
-	ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn2.macAddress);
-	ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn3.macAddress);
-	pEEPROMData = (u16 *) & qdev->nvram_data.version;
-	*pEEPROMData = le16_to_cpu(*pEEPROMData);
-
 	spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 	return checksum;
 }
@@ -711,7 +691,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
 	if (ql_wait_for_mii_ready(qdev)) {
 		if (netif_msg_link(qdev))
 			printk(KERN_WARNING PFX
-			       "%s: Timed out waiting for management port to"
+			       "%s: Timed out waiting for management port to "
 			       "get free before issuing command.\n",
 			       qdev->ndev->name);
 		return -1;
@@ -3035,7 +3015,7 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
 		    LS_64BITS(qdev->shadow_reg_phy_addr);
 
 		qdev->prsp_producer_index =
-		    (u32 *) (((u8 *) qdev->preq_consumer_index) + 8);
+		    (__le32 *) (((u8 *) qdev->preq_consumer_index) + 8);
 		qdev->rsp_producer_index_phy_addr_high =
 		    qdev->req_consumer_index_phy_addr_high;
 		qdev->rsp_producer_index_phy_addr_low =
@@ -3215,7 +3195,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
 	ql_write_page1_reg(qdev, &hmem_regs->reqLength, NUM_REQ_Q_ENTRIES);
 
 	/* Response Queue Registers */
-	*((u16 *) (qdev->prsp_producer_index)) = 0;
+	*((__le16 *) (qdev->prsp_producer_index)) = 0;
 	qdev->rsp_consumer_index = 0;
 	qdev->rsp_current = qdev->rsp_q_virt_addr;
 
@@ -3548,7 +3528,7 @@ static void ql_set_mac_info(struct ql3_adapter *qdev)
 		       qdev->ndev->name,value);
 		break;
 	}
-	qdev->numPorts = qdev->nvram_data.numPorts;
+	qdev->numPorts = qdev->nvram_data.version_and_numPorts >> 8;
 }
 
 static void ql_display_dev_info(struct net_device *ndev)
@@ -4051,12 +4031,10 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
 	/* Validate and set parameters */
 	if (qdev->mac_index) {
 		ndev->mtu = qdev->nvram_data.macCfg_port1.etherMtu_mac ;
-		memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn2.macAddress,
-		       ETH_ALEN);
+		ql_set_mac_addr(ndev, qdev->nvram_data.funcCfg_fn2.macAddress);
 	} else {
 		ndev->mtu = qdev->nvram_data.macCfg_port0.etherMtu_mac ;
-		memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn0.macAddress,
-		       ETH_ALEN);
+		ql_set_mac_addr(ndev, qdev->nvram_data.funcCfg_fn0.macAddress);
 	}
 	memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
 
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
index d0ffb30ef371..58a086fddec6 100644
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -50,7 +50,7 @@ struct ob_mac_iocb_req {
 #define OB_3032MAC_IOCB_REQ_UC	0x01
 	u8 reserved0;
 
-	__le32 transaction_id;
+	u32 transaction_id;	/* opaque for hardware */
 	__le16 data_len;
 	u8 ip_hdr_off;
 	u8 ip_hdr_len;
@@ -86,7 +86,7 @@ struct ob_mac_iocb_rsp {
 #define OB_MAC_IOCB_RSP_I   0x01
 
 	__le16 reserved0;
-	__le32 transaction_id;
+	u32 transaction_id;	/* opaque for hardware */
 	__le32 reserved1;
 	__le32 reserved2;
 };
@@ -953,8 +953,8 @@ struct eeprom_bios_cfg {
  */
 struct eeprom_function_cfg {
 	u8 reserved[30];
-	u8 macAddress[6];
-	u8 macAddressSecondary[6];
+	u16 macAddress[3];
+	u16 macAddressSecondary[3];
 
 	u16 subsysVendorId;
 	u16 subsysDeviceId;
@@ -965,8 +965,7 @@ struct eeprom_function_cfg {
  */
 struct eeprom_data {
 	u8 asicId[4];
-	u8 version;
-	u8 numPorts;
+	u16 version_and_numPorts; /* together to avoid endianness crap */
 	u16 boardId;
 
 #define EEPROM_BOARDID_STR_SIZE   16
@@ -1056,31 +1055,31 @@ struct eeprom_data {
  */
 struct lrg_buf_q_entry {
 
-	u32 addr0_lower;
+	__le32 addr0_lower;
 #define IAL_LAST_ENTRY 0x00000001
 #define IAL_CONT_ENTRY 0x00000002
 #define IAL_FLAG_MASK  0x00000003
-	u32 addr0_upper;
-	u32 addr1_lower;
-	u32 addr1_upper;
-	u32 addr2_lower;
-	u32 addr2_upper;
-	u32 addr3_lower;
-	u32 addr3_upper;
-	u32 addr4_lower;
-	u32 addr4_upper;
-	u32 addr5_lower;
-	u32 addr5_upper;
-	u32 addr6_lower;
-	u32 addr6_upper;
-	u32 addr7_lower;
-	u32 addr7_upper;
+	__le32 addr0_upper;
+	__le32 addr1_lower;
+	__le32 addr1_upper;
+	__le32 addr2_lower;
+	__le32 addr2_upper;
+	__le32 addr3_lower;
+	__le32 addr3_upper;
+	__le32 addr4_lower;
+	__le32 addr4_upper;
+	__le32 addr5_lower;
+	__le32 addr5_upper;
+	__le32 addr6_lower;
+	__le32 addr6_upper;
+	__le32 addr7_lower;
+	__le32 addr7_upper;
 
 };
 
 struct bufq_addr_element {
-	u32 addr_low;
-	u32 addr_high;
+	__le32 addr_low;
+	__le32 addr_high;
 };
 
 #define QL_NO_RESET			0
@@ -1116,9 +1115,9 @@ struct ql_rcv_buf_cb {
 #define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1)
 
 struct oal_entry {
-	u32 dma_lo;
-	u32 dma_hi;
-	u32 len;
+	__le32 dma_lo;
+	__le32 dma_hi;
+	__le32 len;
 #define OAL_LAST_ENTRY   0x80000000	/* Last valid buffer in list. */
 #define OAL_CONT_ENTRY   0x40000000	/* points to an OAL. (continuation) */
 };
@@ -1223,7 +1222,7 @@ struct ql3_adapter {
 	struct net_rsp_iocb *rsp_current;
 	u16 rsp_consumer_index;
 	u16 reserved_06;
-	volatile u32 *prsp_producer_index;
+	volatile __le32 *prsp_producer_index;
 	u32 rsp_producer_index_phy_addr_high;
 	u32 rsp_producer_index_phy_addr_low;
 
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
new file mode 100644
index 000000000000..2334f4ebf907
--- /dev/null
+++ b/drivers/net/r6040.c
@@ -0,0 +1,1096 @@
+/*
+ * RDC R6040 Fast Ethernet MAC support
+ *
+ * Copyright (C) 2004 Sten Wang <sten.wang@rdc.com.tw>
+ * Copyright (C) 2007
+ *	Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
+ *	Florian Fainelli <florian@openwrt.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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+
+#include <asm/processor.h>
+
+#define DRV_NAME	"r6040"
+#define DRV_VERSION	"0.16"
+#define DRV_RELDATE	"10Nov2007"
+
+/* PHY CHIP Address */
+#define PHY1_ADDR	1	/* For MAC1 */
+#define PHY2_ADDR	2	/* For MAC2 */
+#define PHY_MODE	0x3100	/* PHY CHIP Register 0 */
+#define PHY_CAP		0x01E1	/* PHY CHIP Register 4 */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT	(6000 * HZ / 1000)
+#define TIMER_WUT	(jiffies + HZ * 1)/* timer wakeup time : 1 second */
+
+/* RDC MAC I/O Size */
+#define R6040_IO_SIZE	256
+
+/* MAX RDC MAC */
+#define MAX_MAC		2
+
+/* MAC registers */
+#define MCR0		0x00	/* Control register 0 */
+#define MCR1		0x04	/* Control register 1 */
+#define  MAC_RST	0x0001	/* Reset the MAC */
+#define MBCR		0x08	/* Bus control */
+#define MT_ICR		0x0C	/* TX interrupt control */
+#define MR_ICR		0x10	/* RX interrupt control */
+#define MTPR		0x14	/* TX poll command register */
+#define MR_BSR		0x18	/* RX buffer size */
+#define MR_DCR		0x1A	/* RX descriptor control */
+#define MLSR		0x1C	/* Last status */
+#define MMDIO		0x20	/* MDIO control register */
+#define  MDIO_WRITE	0x4000	/* MDIO write */
+#define  MDIO_READ	0x2000	/* MDIO read */
+#define MMRD		0x24	/* MDIO read data register */
+#define MMWD		0x28	/* MDIO write data register */
+#define MTD_SA0		0x2C	/* TX descriptor start address 0 */
+#define MTD_SA1		0x30	/* TX descriptor start address 1 */
+#define MRD_SA0		0x34	/* RX descriptor start address 0 */
+#define MRD_SA1		0x38	/* RX descriptor start address 1 */
+#define MISR		0x3C	/* Status register */
+#define MIER		0x40	/* INT enable register */
+#define  MSK_INT	0x0000	/* Mask off interrupts */
+#define ME_CISR		0x44	/* Event counter INT status */
+#define ME_CIER		0x48	/* Event counter INT enable  */
+#define MR_CNT		0x50	/* Successfully received packet counter */
+#define ME_CNT0		0x52	/* Event counter 0 */
+#define ME_CNT1		0x54	/* Event counter 1 */
+#define ME_CNT2		0x56	/* Event counter 2 */
+#define ME_CNT3		0x58	/* Event counter 3 */
+#define MT_CNT		0x5A	/* Successfully transmit packet counter */
+#define ME_CNT4		0x5C	/* Event counter 4 */
+#define MP_CNT		0x5E	/* Pause frame counter register */
+#define MAR0		0x60	/* Hash table 0 */
+#define MAR1		0x62	/* Hash table 1 */
+#define MAR2		0x64	/* Hash table 2 */
+#define MAR3		0x66	/* Hash table 3 */
+#define MID_0L		0x68	/* Multicast address MID0 Low */
+#define MID_0M		0x6A	/* Multicast address MID0 Medium */
+#define MID_0H		0x6C	/* Multicast address MID0 High */
+#define MID_1L		0x70	/* MID1 Low */
+#define MID_1M		0x72	/* MID1 Medium */
+#define MID_1H		0x74	/* MID1 High */
+#define MID_2L		0x78	/* MID2 Low */
+#define MID_2M		0x7A	/* MID2 Medium */
+#define MID_2H		0x7C	/* MID2 High */
+#define MID_3L		0x80	/* MID3 Low */
+#define MID_3M		0x82	/* MID3 Medium */
+#define MID_3H		0x84	/* MID3 High */
+#define PHY_CC		0x88	/* PHY status change configuration register */
+#define PHY_ST		0x8A	/* PHY status register */
+#define MAC_SM		0xAC	/* MAC status machine */
+#define MAC_ID		0xBE	/* Identifier register */
+
+#define TX_DCNT		0x80	/* TX descriptor count */
+#define RX_DCNT		0x80	/* RX descriptor count */
+#define MAX_BUF_SIZE	0x600
+#define RX_DESC_SIZE	(RX_DCNT * sizeof(struct r6040_descriptor))
+#define TX_DESC_SIZE	(TX_DCNT * sizeof(struct r6040_descriptor))
+#define MBCR_DEFAULT	0x012A	/* MAC Bus Control Register */
+#define MCAST_MAX	4	/* Max number multicast addresses to filter */
+
+/* PHY settings */
+#define ICPLUS_PHY_ID	0x0243
+
+MODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>,"
+	"Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>,"
+	"Florian Fainelli <florian@openwrt.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver");
+
+#define RX_INT                         0x0001
+#define TX_INT                         0x0010
+#define RX_NO_DESC_INT                 0x0002
+#define INT_MASK                 (RX_INT | TX_INT)
+
+struct r6040_descriptor {
+	u16	status, len;		/* 0-3 */
+	__le32	buf;			/* 4-7 */
+	__le32	ndesc;			/* 8-B */
+	u32	rev1;			/* C-F */
+	char	*vbufp;			/* 10-13 */
+	struct r6040_descriptor *vndescp;	/* 14-17 */
+	struct sk_buff *skb_ptr;	/* 18-1B */
+	u32	rev2;			/* 1C-1F */
+} __attribute__((aligned(32)));
+
+struct r6040_private {
+	spinlock_t lock;		/* driver lock */
+	struct timer_list timer;
+	struct pci_dev *pdev;
+	struct r6040_descriptor *rx_insert_ptr;
+	struct r6040_descriptor *rx_remove_ptr;
+	struct r6040_descriptor *tx_insert_ptr;
+	struct r6040_descriptor *tx_remove_ptr;
+	struct r6040_descriptor *rx_ring;
+	struct r6040_descriptor *tx_ring;
+	dma_addr_t rx_ring_dma;
+	dma_addr_t tx_ring_dma;
+	u16	tx_free_desc, rx_free_desc, phy_addr, phy_mode;
+	u16	mcr0, mcr1;
+	u16	switch_sig;
+	struct net_device *dev;
+	struct mii_if_info mii_if;
+	struct napi_struct napi;
+	struct net_device_stats stats;
+	u16	napi_rx_running;
+	void __iomem *base;
+};
+
+static char version[] __devinitdata = KERN_INFO DRV_NAME
+	": RDC R6040 NAPI net driver,"
+	"version "DRV_VERSION " (" DRV_RELDATE ")\n";
+
+static int phy_table[] = { PHY1_ADDR, PHY2_ADDR };
+
+/* Read a word data from PHY Chip */
+static int phy_read(void __iomem *ioaddr, int phy_addr, int reg)
+{
+	int limit = 2048;
+	u16 cmd;
+
+	iowrite16(MDIO_READ + reg + (phy_addr << 8), ioaddr + MMDIO);
+	/* Wait for the read bit to be cleared */
+	while (limit--) {
+		cmd = ioread16(ioaddr + MMDIO);
+		if (cmd & MDIO_READ)
+			break;
+	}
+
+	return ioread16(ioaddr + MMRD);
+}
+
+/* Write a word data from PHY Chip */
+static void phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val)
+{
+	int limit = 2048;
+	u16 cmd;
+
+	iowrite16(val, ioaddr + MMWD);
+	/* Write the command to the MDIO bus */
+	iowrite16(MDIO_WRITE + reg + (phy_addr << 8), ioaddr + MMDIO);
+	/* Wait for the write bit to be cleared */
+	while (limit--) {
+		cmd = ioread16(ioaddr + MMDIO);
+		if (cmd & MDIO_WRITE)
+			break;
+	}
+}
+
+static int mdio_read(struct net_device *dev, int mii_id, int reg)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+
+	return (phy_read(ioaddr, lp->phy_addr, reg));
+}
+
+static void mdio_write(struct net_device *dev, int mii_id, int reg, int val)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+
+	phy_write(ioaddr, lp->phy_addr, reg, val);
+}
+
+static void r6040_tx_timeout(struct net_device *dev)
+{
+	struct r6040_private *priv = netdev_priv(dev);
+
+	disable_irq(dev->irq);
+	napi_disable(&priv->napi);
+	spin_lock(&priv->lock);
+	dev->stats.tx_errors++;
+	spin_unlock(&priv->lock);
+
+	netif_stop_queue(dev);
+}
+
+/* Allocate skb buffer for rx descriptor */
+static void rx_buf_alloc(struct r6040_private *lp, struct net_device *dev)
+{
+	struct r6040_descriptor *descptr;
+	void __iomem *ioaddr = lp->base;
+
+	descptr = lp->rx_insert_ptr;
+	while (lp->rx_free_desc < RX_DCNT) {
+		descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE);
+
+		if (!descptr->skb_ptr)
+			break;
+		descptr->buf = cpu_to_le32(pci_map_single(lp->pdev,
+			descptr->skb_ptr->data,
+			MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
+		descptr->status = 0x8000;
+		descptr = descptr->vndescp;
+		lp->rx_free_desc++;
+		/* Trigger RX DMA */
+		iowrite16(lp->mcr0 | 0x0002, ioaddr);
+	}
+	lp->rx_insert_ptr = descptr;
+}
+
+
+static struct net_device_stats *r6040_get_stats(struct net_device *dev)
+{
+	struct r6040_private *priv = netdev_priv(dev);
+	void __iomem *ioaddr = priv->base;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1);
+	priv->stats.multicast += ioread8(ioaddr + ME_CNT0);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return &priv->stats;
+}
+
+/* Stop RDC MAC and Free the allocated resource */
+static void r6040_down(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+	struct pci_dev *pdev = lp->pdev;
+	int i;
+	int limit = 2048;
+	u16 *adrp;
+	u16 cmd;
+
+	/* Stop MAC */
+	iowrite16(MSK_INT, ioaddr + MIER);	/* Mask Off Interrupt */
+	iowrite16(MAC_RST, ioaddr + MCR1);	/* Reset RDC MAC */
+	while (limit--) {
+		cmd = ioread16(ioaddr + MCR1);
+		if (cmd & 0x1)
+			break;
+	}
+
+	/* Restore MAC Address to MIDx */
+	adrp = (u16 *) dev->dev_addr;
+	iowrite16(adrp[0], ioaddr + MID_0L);
+	iowrite16(adrp[1], ioaddr + MID_0M);
+	iowrite16(adrp[2], ioaddr + MID_0H);
+	free_irq(dev->irq, dev);
+	/* Free RX buffer */
+	for (i = 0; i < RX_DCNT; i++) {
+		if (lp->rx_insert_ptr->skb_ptr) {
+			pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf,
+				MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(lp->rx_insert_ptr->skb_ptr);
+			lp->rx_insert_ptr->skb_ptr = NULL;
+		}
+		lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp;
+	}
+
+	/* Free TX buffer */
+	for (i = 0; i < TX_DCNT; i++) {
+		if (lp->tx_insert_ptr->skb_ptr) {
+			pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf,
+				MAX_BUF_SIZE, PCI_DMA_TODEVICE);
+			dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);
+			lp->rx_insert_ptr->skb_ptr = NULL;
+		}
+		lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;
+	}
+
+	/* Free Descriptor memory */
+	pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma);
+	pci_free_consistent(pdev, TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma);
+}
+
+static int r6040_close(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+
+	/* deleted timer */
+	del_timer_sync(&lp->timer);
+
+	spin_lock_irq(&lp->lock);
+	netif_stop_queue(dev);
+	r6040_down(dev);
+	spin_unlock_irq(&lp->lock);
+
+	return 0;
+}
+
+/* Status of PHY CHIP */
+static int phy_mode_chk(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+	int phy_dat;
+
+	/* PHY Link Status Check */
+	phy_dat = phy_read(ioaddr, lp->phy_addr, 1);
+	if (!(phy_dat & 0x4))
+		phy_dat = 0x8000;	/* Link Failed, full duplex */
+
+	/* PHY Chip Auto-Negotiation Status */
+	phy_dat = phy_read(ioaddr, lp->phy_addr, 1);
+	if (phy_dat & 0x0020) {
+		/* Auto Negotiation Mode */
+		phy_dat = phy_read(ioaddr, lp->phy_addr, 5);
+		phy_dat &= phy_read(ioaddr, lp->phy_addr, 4);
+		if (phy_dat & 0x140)
+			/* Force full duplex */
+			phy_dat = 0x8000;
+		else
+			phy_dat = 0;
+	} else {
+		/* Force Mode */
+		phy_dat = phy_read(ioaddr, lp->phy_addr, 0);
+		if (phy_dat & 0x100)
+			phy_dat = 0x8000;
+		else
+			phy_dat = 0x0000;
+	}
+
+	return phy_dat;
+};
+
+static void r6040_set_carrier(struct mii_if_info *mii)
+{
+	if (phy_mode_chk(mii->dev)) {
+		/* autoneg is off: Link is always assumed to be up */
+		if (!netif_carrier_ok(mii->dev))
+			netif_carrier_on(mii->dev);
+	} else
+		phy_mode_chk(mii->dev);
+}
+
+static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	struct mii_ioctl_data *data = if_mii(rq);
+	int rc;
+
+	if (!netif_running(dev))
+		return -EINVAL;
+	spin_lock_irq(&lp->lock);
+	rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL);
+	spin_unlock_irq(&lp->lock);
+	r6040_set_carrier(&lp->mii_if);
+	return rc;
+}
+
+static int r6040_rx(struct net_device *dev, int limit)
+{
+	struct r6040_private *priv = netdev_priv(dev);
+	int count;
+	void __iomem *ioaddr = priv->base;
+	u16 err;
+
+	for (count = 0; count < limit; ++count) {
+		struct r6040_descriptor *descptr = priv->rx_remove_ptr;
+		struct sk_buff *skb_ptr;
+
+		/* Disable RX interrupt */
+		iowrite16(ioread16(ioaddr + MIER) & (~RX_INT), ioaddr + MIER);
+		descptr = priv->rx_remove_ptr;
+
+		/* Check for errors */
+		err = ioread16(ioaddr + MLSR);
+		if (err & 0x0400) priv->stats.rx_errors++;
+		/* RX FIFO over-run */
+		if (err & 0x8000) priv->stats.rx_fifo_errors++;
+		/* RX descriptor unavailable */
+		if (err & 0x0080) priv->stats.rx_frame_errors++;
+		/* Received packet with length over buffer lenght */
+		if (err & 0x0020) priv->stats.rx_over_errors++;
+		/* Received packet with too long or short */
+		if (err & (0x0010|0x0008)) priv->stats.rx_length_errors++;
+		/* Received packet with CRC errors */
+		if (err & 0x0004) {
+			spin_lock(&priv->lock);
+			priv->stats.rx_crc_errors++;
+			spin_unlock(&priv->lock);
+		}
+
+		while (priv->rx_free_desc) {
+			/* No RX packet */
+			if (descptr->status & 0x8000)
+				break;
+			skb_ptr = descptr->skb_ptr;
+			if (!skb_ptr) {
+				printk(KERN_ERR "%s: Inconsistent RX"
+					"descriptor chain\n",
+					dev->name);
+				break;
+			}
+			descptr->skb_ptr = NULL;
+			skb_ptr->dev = priv->dev;
+			/* Do not count the CRC */
+			skb_put(skb_ptr, descptr->len - 4);
+			pci_unmap_single(priv->pdev, descptr->buf,
+				MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev);
+			/* Send to upper layer */
+			netif_receive_skb(skb_ptr);
+			dev->last_rx = jiffies;
+			priv->dev->stats.rx_packets++;
+			priv->dev->stats.rx_bytes += descptr->len;
+			/* To next descriptor */
+			descptr = descptr->vndescp;
+			priv->rx_free_desc--;
+		}
+		priv->rx_remove_ptr = descptr;
+	}
+	/* Allocate new RX buffer */
+	if (priv->rx_free_desc < RX_DCNT)
+		rx_buf_alloc(priv, priv->dev);
+
+	return count;
+}
+
+static void r6040_tx(struct net_device *dev)
+{
+	struct r6040_private *priv = netdev_priv(dev);
+	struct r6040_descriptor *descptr;
+	void __iomem *ioaddr = priv->base;
+	struct sk_buff *skb_ptr;
+	u16 err;
+
+	spin_lock(&priv->lock);
+	descptr = priv->tx_remove_ptr;
+	while (priv->tx_free_desc < TX_DCNT) {
+		/* Check for errors */
+		err = ioread16(ioaddr + MLSR);
+
+		if (err & 0x0200) priv->stats.rx_fifo_errors++;
+		if (err & (0x2000 | 0x4000)) priv->stats.tx_carrier_errors++;
+
+		if (descptr->status & 0x8000)
+			break; /* Not complte */
+		skb_ptr = descptr->skb_ptr;
+		pci_unmap_single(priv->pdev, descptr->buf,
+			skb_ptr->len, PCI_DMA_TODEVICE);
+		/* Free buffer */
+		dev_kfree_skb_irq(skb_ptr);
+		descptr->skb_ptr = NULL;
+		/* To next descriptor */
+		descptr = descptr->vndescp;
+		priv->tx_free_desc++;
+	}
+	priv->tx_remove_ptr = descptr;
+
+	if (priv->tx_free_desc)
+		netif_wake_queue(dev);
+	spin_unlock(&priv->lock);
+}
+
+static int r6040_poll(struct napi_struct *napi, int budget)
+{
+	struct r6040_private *priv =
+		container_of(napi, struct r6040_private, napi);
+	struct net_device *dev = priv->dev;
+	void __iomem *ioaddr = priv->base;
+	int work_done;
+
+	work_done = r6040_rx(dev, budget);
+
+	if (work_done < budget) {
+		netif_rx_complete(dev, napi);
+		/* Enable RX interrupt */
+		iowrite16(ioread16(ioaddr + MIER) | RX_INT, ioaddr + MIER);
+	}
+	return work_done;
+}
+
+/* The RDC interrupt handler. */
+static irqreturn_t r6040_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+	u16 status;
+	int handled = 1;
+
+	/* Mask off RDC MAC interrupt */
+	iowrite16(MSK_INT, ioaddr + MIER);
+	/* Read MISR status and clear */
+	status = ioread16(ioaddr + MISR);
+
+	if (status == 0x0000 || status == 0xffff)
+		return IRQ_NONE;
+
+	/* RX interrupt request */
+	if (status & 0x01) {
+		netif_rx_schedule(dev, &lp->napi);
+		iowrite16(TX_INT, ioaddr + MIER);
+	}
+
+	/* TX interrupt request */
+	if (status & 0x10)
+		r6040_tx(dev);
+
+	return IRQ_RETVAL(handled);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void r6040_poll_controller(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	r6040_interrupt(dev->irq, dev);
+	enable_irq(dev->irq);
+}
+#endif
+
+static void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,
+				 dma_addr_t desc_dma, int size)
+{
+	struct r6040_descriptor *desc = desc_ring;
+	dma_addr_t mapping = desc_dma;
+
+	while (size-- > 0) {
+		mapping += sizeof(sizeof(*desc));
+		desc->ndesc = cpu_to_le32(mapping);
+		desc->vndescp = desc + 1;
+		desc++;
+	}
+	desc--;
+	desc->ndesc = cpu_to_le32(desc_dma);
+	desc->vndescp = desc_ring;
+}
+
+/* Init RDC MAC */
+static void r6040_up(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+
+	/* Initialize */
+	lp->tx_free_desc = TX_DCNT;
+	lp->rx_free_desc = 0;
+	/* Init descriptor */
+	lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring;
+	lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring;
+	/* Init TX descriptor */
+	r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT);
+
+	/* Init RX descriptor */
+	r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT);
+
+	/* Allocate buffer for RX descriptor */
+	rx_buf_alloc(lp, dev);
+
+	/*
+	 * TX and RX descriptor start registers.
+	 * Lower 16-bits to MxD_SA0. Higher 16-bits to MxD_SA1.
+	 */
+	iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0);
+	iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1);
+
+	iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0);
+	iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1);
+
+	/* Buffer Size Register */
+	iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR);
+	/* Read the PHY ID */
+	lp->switch_sig = phy_read(ioaddr, 0, 2);
+
+	if (lp->switch_sig  == ICPLUS_PHY_ID) {
+		phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */
+		lp->phy_mode = 0x8000;
+	} else {
+		/* PHY Mode Check */
+		phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
+		phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
+
+		if (PHY_MODE == 0x3100)
+			lp->phy_mode = phy_mode_chk(dev);
+		else
+			lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
+	}
+	/* MAC Bus Control Register */
+	iowrite16(MBCR_DEFAULT, ioaddr + MBCR);
+
+	/* MAC TX/RX Enable */
+	lp->mcr0 |= lp->phy_mode;
+	iowrite16(lp->mcr0, ioaddr);
+
+	/* set interrupt waiting time and packet numbers */
+	iowrite16(0x0F06, ioaddr + MT_ICR);
+	iowrite16(0x0F06, ioaddr + MR_ICR);
+
+	/* improve performance (by RDC guys) */
+	phy_write(ioaddr, 30, 17, (phy_read(ioaddr, 30, 17) | 0x4000));
+	phy_write(ioaddr, 30, 17, ~((~phy_read(ioaddr, 30, 17)) | 0x2000));
+	phy_write(ioaddr, 0, 19, 0x0000);
+	phy_write(ioaddr, 0, 30, 0x01F0);
+
+	/* Interrupt Mask Register */
+	iowrite16(INT_MASK, ioaddr + MIER);
+}
+
+/*
+  A periodic timer routine
+	Polling PHY Chip Link Status
+*/
+static void r6040_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+	u16 phy_mode;
+
+	/* Polling PHY Chip Status */
+	if (PHY_MODE == 0x3100)
+		phy_mode = phy_mode_chk(dev);
+	else
+		phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
+
+	if (phy_mode != lp->phy_mode) {
+		lp->phy_mode = phy_mode;
+		lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
+		iowrite16(lp->mcr0, ioaddr);
+		printk(KERN_INFO "Link Change %x \n", ioread16(ioaddr));
+	}
+
+	/* Timer active again */
+	lp->timer.expires = TIMER_WUT;
+	add_timer(&lp->timer);
+}
+
+/* Read/set MAC address routines */
+static void r6040_mac_address(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+	u16 *adrp;
+
+	/* MAC operation register */
+	iowrite16(0x01, ioaddr + MCR1); /* Reset MAC */
+	iowrite16(2, ioaddr + MAC_SM); /* Reset internal state machine */
+	iowrite16(0, ioaddr + MAC_SM);
+	udelay(5000);
+
+	/* Restore MAC Address */
+	adrp = (u16 *) dev->dev_addr;
+	iowrite16(adrp[0], ioaddr + MID_0L);
+	iowrite16(adrp[1], ioaddr + MID_0M);
+	iowrite16(adrp[2], ioaddr + MID_0H);
+}
+
+static int r6040_open(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	int ret;
+
+	/* Request IRQ and Register interrupt handler */
+	ret = request_irq(dev->irq, &r6040_interrupt,
+		IRQF_SHARED, dev->name, dev);
+	if (ret)
+		return ret;
+
+	/* Set MAC address */
+	r6040_mac_address(dev);
+
+	/* Allocate Descriptor memory */
+	lp->rx_ring =
+		pci_alloc_consistent(lp->pdev, RX_DESC_SIZE, &lp->rx_ring_dma);
+	if (!lp->rx_ring)
+		return -ENOMEM;
+
+	lp->tx_ring =
+		pci_alloc_consistent(lp->pdev, TX_DESC_SIZE, &lp->tx_ring_dma);
+	if (!lp->tx_ring) {
+		pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring,
+				     lp->rx_ring_dma);
+		return -ENOMEM;
+	}
+
+	r6040_up(dev);
+
+	napi_enable(&lp->napi);
+	netif_start_queue(dev);
+
+	if (lp->switch_sig != ICPLUS_PHY_ID) {
+		/* set and active a timer process */
+		init_timer(&lp->timer);
+		lp->timer.expires = TIMER_WUT;
+		lp->timer.data = (unsigned long)dev;
+		lp->timer.function = &r6040_timer;
+		add_timer(&lp->timer);
+	}
+	return 0;
+}
+
+static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	struct r6040_descriptor *descptr;
+	void __iomem *ioaddr = lp->base;
+	unsigned long flags;
+	int ret = NETDEV_TX_OK;
+
+	/* Critical Section */
+	spin_lock_irqsave(&lp->lock, flags);
+
+	/* TX resource check */
+	if (!lp->tx_free_desc) {
+		spin_unlock_irqrestore(&lp->lock, flags);
+		netif_stop_queue(dev);
+		printk(KERN_ERR DRV_NAME ": no tx descriptor\n");
+		ret = NETDEV_TX_BUSY;
+		return ret;
+	}
+
+	/* Statistic Counter */
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
+	/* Set TX descriptor & Transmit it */
+	lp->tx_free_desc--;
+	descptr = lp->tx_insert_ptr;
+	if (skb->len < MISR)
+		descptr->len = MISR;
+	else
+		descptr->len = skb->len;
+
+	descptr->skb_ptr = skb;
+	descptr->buf = cpu_to_le32(pci_map_single(lp->pdev,
+		skb->data, skb->len, PCI_DMA_TODEVICE));
+	descptr->status = 0x8000;
+	/* Trigger the MAC to check the TX descriptor */
+	iowrite16(0x01, ioaddr + MTPR);
+	lp->tx_insert_ptr = descptr->vndescp;
+
+	/* If no tx resource, stop */
+	if (!lp->tx_free_desc)
+		netif_stop_queue(dev);
+
+	dev->trans_start = jiffies;
+	spin_unlock_irqrestore(&lp->lock, flags);
+	return ret;
+}
+
+static void r6040_multicast_list(struct net_device *dev)
+{
+	struct r6040_private *lp = netdev_priv(dev);
+	void __iomem *ioaddr = lp->base;
+	u16 *adrp;
+	u16 reg;
+	unsigned long flags;
+	struct dev_mc_list *dmi = dev->mc_list;
+	int i;
+
+	/* MAC Address */
+	adrp = (u16 *)dev->dev_addr;
+	iowrite16(adrp[0], ioaddr + MID_0L);
+	iowrite16(adrp[1], ioaddr + MID_0M);
+	iowrite16(adrp[2], ioaddr + MID_0H);
+
+	/* Promiscous Mode */
+	spin_lock_irqsave(&lp->lock, flags);
+
+	/* Clear AMCP & PROM bits */
+	reg = ioread16(ioaddr) & ~0x0120;
+	if (dev->flags & IFF_PROMISC) {
+		reg |= 0x0020;
+		lp->mcr0 |= 0x0020;
+	}
+	/* Too many multicast addresses
+	 * accept all traffic */
+	else if ((dev->mc_count > MCAST_MAX)
+		|| (dev->flags & IFF_ALLMULTI))
+		reg |= 0x0020;
+
+	iowrite16(reg, ioaddr);
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	/* Build the hash table */
+	if (dev->mc_count > MCAST_MAX) {
+		u16 hash_table[4];
+		u32 crc;
+
+		for (i = 0; i < 4; i++)
+			hash_table[i] = 0;
+
+		for (i = 0; i < dev->mc_count; i++) {
+			char *addrs = dmi->dmi_addr;
+
+			dmi = dmi->next;
+
+			if (!(*addrs & 1))
+				continue;
+
+			crc = ether_crc_le(6, addrs);
+			crc >>= 26;
+			hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
+		}
+		/* Write the index of the hash table */
+		for (i = 0; i < 4; i++)
+			iowrite16(hash_table[i] << 14, ioaddr + MCR1);
+		/* Fill the MAC hash tables with their values */
+		iowrite16(hash_table[0], ioaddr + MAR0);
+		iowrite16(hash_table[1], ioaddr + MAR1);
+		iowrite16(hash_table[2], ioaddr + MAR2);
+		iowrite16(hash_table[3], ioaddr + MAR3);
+	}
+	/* Multicast Address 1~4 case */
+	for (i = 0, dmi; (i < dev->mc_count) && (i < MCAST_MAX); i++) {
+		adrp = (u16 *)dmi->dmi_addr;
+		iowrite16(adrp[0], ioaddr + MID_1L + 8*i);
+		iowrite16(adrp[1], ioaddr + MID_1M + 8*i);
+		iowrite16(adrp[2], ioaddr + MID_1H + 8*i);
+		dmi = dmi->next;
+	}
+	for (i = dev->mc_count; i < MCAST_MAX; i++) {
+		iowrite16(0xffff, ioaddr + MID_0L + 8*i);
+		iowrite16(0xffff, ioaddr + MID_0M + 8*i);
+		iowrite16(0xffff, ioaddr + MID_0H + 8*i);
+	}
+}
+
+static void netdev_get_drvinfo(struct net_device *dev,
+			struct ethtool_drvinfo *info)
+{
+	struct r6040_private *rp = netdev_priv(dev);
+
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(rp->pdev));
+}
+
+static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct r6040_private *rp = netdev_priv(dev);
+	int rc;
+
+	spin_lock_irq(&rp->lock);
+	rc = mii_ethtool_gset(&rp->mii_if, cmd);
+	spin_unlock_irq(&rp->lock);
+
+	return rc;
+}
+
+static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct r6040_private *rp = netdev_priv(dev);
+	int rc;
+
+	spin_lock_irq(&rp->lock);
+	rc = mii_ethtool_sset(&rp->mii_if, cmd);
+	spin_unlock_irq(&rp->lock);
+	r6040_set_carrier(&rp->mii_if);
+
+	return rc;
+}
+
+static u32 netdev_get_link(struct net_device *dev)
+{
+	struct r6040_private *rp = netdev_priv(dev);
+
+	return mii_link_ok(&rp->mii_if);
+}
+
+static struct ethtool_ops netdev_ethtool_ops = {
+	.get_drvinfo		= netdev_get_drvinfo,
+	.get_settings		= netdev_get_settings,
+	.set_settings		= netdev_set_settings,
+	.get_link		= netdev_get_link,
+};
+
+static int __devinit r6040_init_one(struct pci_dev *pdev,
+					 const struct pci_device_id *ent)
+{
+	struct net_device *dev;
+	struct r6040_private *lp;
+	void __iomem *ioaddr;
+	int err, io_size = R6040_IO_SIZE;
+	static int card_idx = -1;
+	int bar = 0;
+	long pioaddr;
+	u16 *adrp;
+
+	printk(KERN_INFO "%s\n", version);
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	/* this should always be supported */
+	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+		printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses"
+				"not supported by the card\n");
+		return -ENODEV;
+	}
+	if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+		printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses"
+				"not supported by the card\n");
+		return -ENODEV;
+	}
+
+	/* IO Size check */
+	if (pci_resource_len(pdev, 0) < io_size) {
+		printk(KERN_ERR "Insufficient PCI resources, aborting\n");
+		return -EIO;
+	}
+
+	pioaddr = pci_resource_start(pdev, 0);	/* IO map base address */
+	pci_set_master(pdev);
+
+	dev = alloc_etherdev(sizeof(struct r6040_private));
+	if (!dev) {
+		printk(KERN_ERR "Failed to allocate etherdev\n");
+		return -ENOMEM;
+	}
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	lp = netdev_priv(dev);
+	lp->pdev = pdev;
+
+	if (pci_request_regions(pdev, DRV_NAME)) {
+		printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
+		err = -ENODEV;
+		goto err_out_disable;
+	}
+
+	ioaddr = pci_iomap(pdev, bar, io_size);
+	if (!ioaddr) {
+		printk(KERN_ERR "ioremap failed for device %s\n",
+			pci_name(pdev));
+		return -EIO;
+	}
+
+	/* Init system & device */
+	lp->base = ioaddr;
+	dev->irq = pdev->irq;
+
+	spin_lock_init(&lp->lock);
+	pci_set_drvdata(pdev, dev);
+
+	/* Set MAC address */
+	card_idx++;
+
+	adrp = (u16 *)dev->dev_addr;
+	adrp[0] = ioread16(ioaddr + MID_0L);
+	adrp[1] = ioread16(ioaddr + MID_0M);
+	adrp[2] = ioread16(ioaddr + MID_0H);
+
+	/* Link new device into r6040_root_dev */
+	lp->pdev = pdev;
+
+	/* Init RDC private data */
+	lp->mcr0 = 0x1002;
+	lp->phy_addr = phy_table[card_idx];
+	lp->switch_sig = 0;
+
+	/* The RDC-specific entries in the device structure. */
+	dev->open = &r6040_open;
+	dev->hard_start_xmit = &r6040_start_xmit;
+	dev->stop = &r6040_close;
+	dev->get_stats = r6040_get_stats;
+	dev->set_multicast_list = &r6040_multicast_list;
+	dev->do_ioctl = &r6040_ioctl;
+	dev->ethtool_ops = &netdev_ethtool_ops;
+	dev->tx_timeout = &r6040_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = r6040_poll_controller;
+#endif
+	netif_napi_add(dev, &lp->napi, r6040_poll, 64);
+	lp->mii_if.dev = dev;
+	lp->mii_if.mdio_read = mdio_read;
+	lp->mii_if.mdio_write = mdio_write;
+	lp->mii_if.phy_id = lp->phy_addr;
+	lp->mii_if.phy_id_mask = 0x1f;
+	lp->mii_if.reg_num_mask = 0x1f;
+
+	/* Register net device. After this dev->name assign */
+	err = register_netdev(dev);
+	if (err) {
+		printk(KERN_ERR DRV_NAME ": Failed to register net device\n");
+		goto err_out_res;
+	}
+	return 0;
+
+err_out_res:
+	pci_release_regions(pdev);
+err_out_disable:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(dev);
+
+	return err;
+}
+
+static void __devexit r6040_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	unregister_netdev(dev);
+	pci_release_regions(pdev);
+	free_netdev(dev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+
+static struct pci_device_id r6040_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, r6040_pci_tbl);
+
+static struct pci_driver r6040_driver = {
+	.name		= DRV_NAME,
+	.id_table	= r6040_pci_tbl,
+	.probe		= r6040_init_one,
+	.remove		= __devexit_p(r6040_remove_one),
+};
+
+
+static int __init r6040_init(void)
+{
+	return pci_register_driver(&r6040_driver);
+}
+
+
+static void __exit r6040_cleanup(void)
+{
+	pci_unregister_driver(&r6040_driver);
+}
+
+module_init(r6040_init);
+module_exit(r6040_cleanup);
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 55a590ab1e17..3dd8f1342f70 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -877,7 +877,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
 			       dev->name);
 			goto drop;
 		case E_FLG_SYN_ERR:
-			printk(KERN_WARNING "%s: Flag sync. lost during"
+			printk(KERN_WARNING "%s: Flag sync. lost during "
 			       "packet\n", dev->name);
 			goto drop;
 		case E_RX_INV_BUF:
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index f25264f2638e..2109508c047a 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -723,11 +723,17 @@ struct XENA_dev_config {
 	u64 rmac_cfg_key;
 #define RMAC_CFG_KEY(val)               vBIT(val,0,16)
 
-#define MAX_MAC_ADDRESSES           16
-#define MAX_MC_ADDRESSES            32	/* Multicast addresses */
-#define MAC_MAC_ADDR_START_OFFSET   0
-#define MAC_MC_ADDR_START_OFFSET    16
-#define MAC_MC_ALL_MC_ADDR_OFFSET   63	/* enables all multicast pkts */
+#define S2IO_MAC_ADDR_START_OFFSET	0
+
+#define S2IO_XENA_MAX_MC_ADDRESSES	64	/* multicast addresses */
+#define S2IO_HERC_MAX_MC_ADDRESSES	256
+
+#define S2IO_XENA_MAX_MAC_ADDRESSES	16
+#define S2IO_HERC_MAX_MAC_ADDRESSES	64
+
+#define S2IO_XENA_MC_ADDR_START_OFFSET	16
+#define S2IO_HERC_MC_ADDR_START_OFFSET	64
+
 	u64 rmac_addr_cmd_mem;
 #define RMAC_ADDR_CMD_MEM_WE                    s2BIT(7)
 #define RMAC_ADDR_CMD_MEM_RD                    0
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index f2ba944e035e..5fab7d7b5d74 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -84,7 +84,7 @@
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.26.17"
+#define DRV_VERSION "2.0.26.15-2"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -335,10 +335,9 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
 	{"mc_err_cnt"}
 };
 
-#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN
-#define S2IO_ENHANCED_STAT_LEN sizeof(ethtool_enhanced_stats_keys)/ \
-					ETH_GSTRING_LEN
-#define S2IO_DRIVER_STAT_LEN sizeof(ethtool_driver_stats_keys)/ ETH_GSTRING_LEN
+#define S2IO_XENA_STAT_LEN	ARRAY_SIZE(ethtool_xena_stats_keys)
+#define S2IO_ENHANCED_STAT_LEN	ARRAY_SIZE(ethtool_enhanced_stats_keys)
+#define S2IO_DRIVER_STAT_LEN	ARRAY_SIZE(ethtool_driver_stats_keys)
 
 #define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN )
 #define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN )
@@ -346,7 +345,7 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
 #define XFRAME_I_STAT_STRINGS_LEN ( XFRAME_I_STAT_LEN * ETH_GSTRING_LEN )
 #define XFRAME_II_STAT_STRINGS_LEN ( XFRAME_II_STAT_LEN * ETH_GSTRING_LEN )
 
-#define S2IO_TEST_LEN	sizeof(s2io_gstrings) / ETH_GSTRING_LEN
+#define S2IO_TEST_LEN	ARRAY_SIZE(s2io_gstrings)
 #define S2IO_STRINGS_LEN	S2IO_TEST_LEN * ETH_GSTRING_LEN
 
 #define S2IO_TIMER_CONF(timer, handle, arg, exp)		\
@@ -369,12 +368,19 @@ static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr)
 static void s2io_vlan_rx_register(struct net_device *dev,
 					struct vlan_group *grp)
 {
+	int i;
 	struct s2io_nic *nic = dev->priv;
-	unsigned long flags;
+	unsigned long flags[MAX_TX_FIFOS];
+	struct mac_info *mac_control = &nic->mac_control;
+	struct config_param *config = &nic->config;
+
+	for (i = 0; i < config->tx_fifo_num; i++)
+		spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags[i]);
 
-	spin_lock_irqsave(&nic->tx_lock, flags);
 	nic->vlgrp = grp;
-	spin_unlock_irqrestore(&nic->tx_lock, flags);
+	for (i = config->tx_fifo_num - 1; i >= 0; i--)
+		spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock,
+				flags[i]);
 }
 
 /* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
@@ -566,6 +572,21 @@ static int init_shared_mem(struct s2io_nic *nic)
 		return -EINVAL;
 	}
 
+	size = 0;
+	for (i = 0; i < config->tx_fifo_num; i++) {
+		size = config->tx_cfg[i].fifo_len;
+		/*
+		 * Legal values are from 2 to 8192
+		 */
+		if (size < 2) {
+			DBG_PRINT(ERR_DBG, "s2io: Invalid fifo len (%d)", size);
+			DBG_PRINT(ERR_DBG, "for fifo %d\n", i);
+			DBG_PRINT(ERR_DBG, "s2io: Legal values for fifo len"
+				"are 2 to 8192\n");
+			return -EINVAL;
+		}
+	}
+
 	lst_size = (sizeof(struct TxD) * config->max_txds);
 	lst_per_page = PAGE_SIZE / lst_size;
 
@@ -640,10 +661,14 @@ static int init_shared_mem(struct s2io_nic *nic)
 		}
 	}
 
-	nic->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL);
-	if (!nic->ufo_in_band_v)
-		return -ENOMEM;
-	 mem_allocated += (size * sizeof(u64));
+	for (i = 0; i < config->tx_fifo_num; i++) {
+		size = config->tx_cfg[i].fifo_len;
+		mac_control->fifos[i].ufo_in_band_v
+			= kcalloc(size, sizeof(u64), GFP_KERNEL);
+		if (!mac_control->fifos[i].ufo_in_band_v)
+			return -ENOMEM;
+		mem_allocated += (size * sizeof(u64));
+	}
 
 	/* Allocation and initialization of RXDs in Rings */
 	size = 0;
@@ -830,7 +855,6 @@ static int init_shared_mem(struct s2io_nic *nic)
 static void free_shared_mem(struct s2io_nic *nic)
 {
 	int i, j, blk_cnt, size;
-	u32 ufo_size = 0;
 	void *tmp_v_addr;
 	dma_addr_t tmp_p_addr;
 	struct mac_info *mac_control;
@@ -851,7 +875,6 @@ static void free_shared_mem(struct s2io_nic *nic)
 	lst_per_page = PAGE_SIZE / lst_size;
 
 	for (i = 0; i < config->tx_fifo_num; i++) {
-		ufo_size += config->tx_cfg[i].fifo_len;
 		page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
 							lst_per_page);
 		for (j = 0; j < page_num; j++) {
@@ -941,18 +964,21 @@ static void free_shared_mem(struct s2io_nic *nic)
 		}
 	}
 
+	for (i = 0; i < nic->config.tx_fifo_num; i++) {
+		if (mac_control->fifos[i].ufo_in_band_v) {
+			nic->mac_control.stats_info->sw_stat.mem_freed
+				+= (config->tx_cfg[i].fifo_len * sizeof(u64));
+			kfree(mac_control->fifos[i].ufo_in_band_v);
+		}
+	}
+
 	if (mac_control->stats_mem) {
+		nic->mac_control.stats_info->sw_stat.mem_freed +=
+			mac_control->stats_mem_sz;
 		pci_free_consistent(nic->pdev,
 				    mac_control->stats_mem_sz,
 				    mac_control->stats_mem,
 				    mac_control->stats_mem_phy);
-		nic->mac_control.stats_info->sw_stat.mem_freed +=
-			mac_control->stats_mem_sz;
-	}
-	if (nic->ufo_in_band_v) {
-		kfree(nic->ufo_in_band_v);
-		nic->mac_control.stats_info->sw_stat.mem_freed
-			+= (ufo_size * sizeof(u64));
 	}
 }
 
@@ -1053,8 +1079,67 @@ static int s2io_print_pci_mode(struct s2io_nic *nic)
 }
 
 /**
+ *  init_tti - Initialization transmit traffic interrupt scheme
+ *  @nic: device private variable
+ *  @link: link status (UP/DOWN) used to enable/disable continuous
+ *  transmit interrupts
+ *  Description: The function configures transmit traffic interrupts
+ *  Return Value:  SUCCESS on success and
+ *  '-1' on failure
+ */
+
+int init_tti(struct s2io_nic *nic, int link)
+{
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
+	register u64 val64 = 0;
+	int i;
+	struct config_param *config;
+
+	config = &nic->config;
+
+	for (i = 0; i < config->tx_fifo_num; i++) {
+		/*
+		 * TTI Initialization. Default Tx timer gets us about
+		 * 250 interrupts per sec. Continuous interrupts are enabled
+		 * by default.
+		 */
+		if (nic->device_type == XFRAME_II_DEVICE) {
+			int count = (nic->config.bus_speed * 125)/2;
+			val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
+		} else
+			val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
+
+		val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
+				TTI_DATA1_MEM_TX_URNG_B(0x10) |
+				TTI_DATA1_MEM_TX_URNG_C(0x30) |
+				TTI_DATA1_MEM_TX_TIMER_AC_EN;
+
+		if (use_continuous_tx_intrs && (link == LINK_UP))
+			val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
+		writeq(val64, &bar0->tti_data1_mem);
+
+		val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
+				TTI_DATA2_MEM_TX_UFC_B(0x20) |
+				TTI_DATA2_MEM_TX_UFC_C(0x40) |
+				TTI_DATA2_MEM_TX_UFC_D(0x80);
+
+		writeq(val64, &bar0->tti_data2_mem);
+
+		val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD |
+				TTI_CMD_MEM_OFFSET(i);
+		writeq(val64, &bar0->tti_command_mem);
+
+		if (wait_for_cmd_complete(&bar0->tti_command_mem,
+			TTI_CMD_MEM_STROBE_NEW_CMD, S2IO_BIT_RESET) != SUCCESS)
+			return FAILURE;
+	}
+
+	return SUCCESS;
+}
+
+/**
  *  init_nic - Initialization of hardware
- *  @nic: device peivate variable
+ *  @nic: device private variable
  *  Description: The function sequentially configures every block
  *  of the H/W from their reset values.
  *  Return Value:  SUCCESS on success and
@@ -1159,9 +1244,9 @@ static int init_nic(struct s2io_nic *nic)
 
 	for (i = 0, j = 0; i < config->tx_fifo_num; i++) {
 		val64 |=
-		    vBIT(config->tx_cfg[i].fifo_len - 1, ((i * 32) + 19),
+		    vBIT(config->tx_cfg[i].fifo_len - 1, ((j * 32) + 19),
 			 13) | vBIT(config->tx_cfg[i].fifo_priority,
-				    ((i * 32) + 5), 3);
+				    ((j * 32) + 5), 3);
 
 		if (i == (config->tx_fifo_num - 1)) {
 			if (i % 2 == 0)
@@ -1172,17 +1257,25 @@ static int init_nic(struct s2io_nic *nic)
 		case 1:
 			writeq(val64, &bar0->tx_fifo_partition_0);
 			val64 = 0;
+			j = 0;
 			break;
 		case 3:
 			writeq(val64, &bar0->tx_fifo_partition_1);
 			val64 = 0;
+			j = 0;
 			break;
 		case 5:
 			writeq(val64, &bar0->tx_fifo_partition_2);
 			val64 = 0;
+			j = 0;
 			break;
 		case 7:
 			writeq(val64, &bar0->tx_fifo_partition_3);
+			val64 = 0;
+			j = 0;
+			break;
+		default:
+			j++;
 			break;
 		}
 	}
@@ -1268,11 +1361,11 @@ static int init_nic(struct s2io_nic *nic)
 
 	/*
 	 * Filling Tx round robin registers
-	 * as per the number of FIFOs
+	 * as per the number of FIFOs for equal scheduling priority
 	 */
 	switch (config->tx_fifo_num) {
 	case 1:
-		val64 = 0x0000000000000000ULL;
+		val64 = 0x0;
 		writeq(val64, &bar0->tx_w_round_robin_0);
 		writeq(val64, &bar0->tx_w_round_robin_1);
 		writeq(val64, &bar0->tx_w_round_robin_2);
@@ -1280,87 +1373,78 @@ static int init_nic(struct s2io_nic *nic)
 		writeq(val64, &bar0->tx_w_round_robin_4);
 		break;
 	case 2:
-		val64 = 0x0000010000010000ULL;
+		val64 = 0x0001000100010001ULL;
 		writeq(val64, &bar0->tx_w_round_robin_0);
-		val64 = 0x0100000100000100ULL;
 		writeq(val64, &bar0->tx_w_round_robin_1);
-		val64 = 0x0001000001000001ULL;
 		writeq(val64, &bar0->tx_w_round_robin_2);
-		val64 = 0x0000010000010000ULL;
 		writeq(val64, &bar0->tx_w_round_robin_3);
-		val64 = 0x0100000000000000ULL;
+		val64 = 0x0001000100000000ULL;
 		writeq(val64, &bar0->tx_w_round_robin_4);
 		break;
 	case 3:
-		val64 = 0x0001000102000001ULL;
+		val64 = 0x0001020001020001ULL;
 		writeq(val64, &bar0->tx_w_round_robin_0);
-		val64 = 0x0001020000010001ULL;
+		val64 = 0x0200010200010200ULL;
 		writeq(val64, &bar0->tx_w_round_robin_1);
-		val64 = 0x0200000100010200ULL;
+		val64 = 0x0102000102000102ULL;
 		writeq(val64, &bar0->tx_w_round_robin_2);
-		val64 = 0x0001000102000001ULL;
+		val64 = 0x0001020001020001ULL;
 		writeq(val64, &bar0->tx_w_round_robin_3);
-		val64 = 0x0001020000000000ULL;
+		val64 = 0x0200010200000000ULL;
 		writeq(val64, &bar0->tx_w_round_robin_4);
 		break;
 	case 4:
-		val64 = 0x0001020300010200ULL;
+		val64 = 0x0001020300010203ULL;
 		writeq(val64, &bar0->tx_w_round_robin_0);
-		val64 = 0x0100000102030001ULL;
 		writeq(val64, &bar0->tx_w_round_robin_1);
-		val64 = 0x0200010000010203ULL;
 		writeq(val64, &bar0->tx_w_round_robin_2);
-		val64 = 0x0001020001000001ULL;
 		writeq(val64, &bar0->tx_w_round_robin_3);
-		val64 = 0x0203000100000000ULL;
+		val64 = 0x0001020300000000ULL;
 		writeq(val64, &bar0->tx_w_round_robin_4);
 		break;
 	case 5:
-		val64 = 0x0001000203000102ULL;
+		val64 = 0x0001020304000102ULL;
 		writeq(val64, &bar0->tx_w_round_robin_0);
-		val64 = 0x0001020001030004ULL;
+		val64 = 0x0304000102030400ULL;
 		writeq(val64, &bar0->tx_w_round_robin_1);
-		val64 = 0x0001000203000102ULL;
+		val64 = 0x0102030400010203ULL;
 		writeq(val64, &bar0->tx_w_round_robin_2);
-		val64 = 0x0001020001030004ULL;
+		val64 = 0x0400010203040001ULL;
 		writeq(val64, &bar0->tx_w_round_robin_3);
-		val64 = 0x0001000000000000ULL;
+		val64 = 0x0203040000000000ULL;
 		writeq(val64, &bar0->tx_w_round_robin_4);
 		break;
 	case 6:
-		val64 = 0x0001020304000102ULL;
+		val64 = 0x0001020304050001ULL;
 		writeq(val64, &bar0->tx_w_round_robin_0);
-		val64 = 0x0304050001020001ULL;
+		val64 = 0x0203040500010203ULL;
 		writeq(val64, &bar0->tx_w_round_robin_1);
-		val64 = 0x0203000100000102ULL;
+		val64 = 0x0405000102030405ULL;
 		writeq(val64, &bar0->tx_w_round_robin_2);
-		val64 = 0x0304000102030405ULL;
+		val64 = 0x0001020304050001ULL;
 		writeq(val64, &bar0->tx_w_round_robin_3);
-		val64 = 0x0001000200000000ULL;
+		val64 = 0x0203040500000000ULL;
 		writeq(val64, &bar0->tx_w_round_robin_4);
 		break;
 	case 7:
-		val64 = 0x0001020001020300ULL;
+		val64 = 0x0001020304050600ULL;
 		writeq(val64, &bar0->tx_w_round_robin_0);
-		val64 = 0x0102030400010203ULL;
+		val64 = 0x0102030405060001ULL;
 		writeq(val64, &bar0->tx_w_round_robin_1);
-		val64 = 0x0405060001020001ULL;
+		val64 = 0x0203040506000102ULL;
 		writeq(val64, &bar0->tx_w_round_robin_2);
-		val64 = 0x0304050000010200ULL;
+		val64 = 0x0304050600010203ULL;
 		writeq(val64, &bar0->tx_w_round_robin_3);
-		val64 = 0x0102030000000000ULL;
+		val64 = 0x0405060000000000ULL;
 		writeq(val64, &bar0->tx_w_round_robin_4);
 		break;
 	case 8:
-		val64 = 0x0001020300040105ULL;
+		val64 = 0x0001020304050607ULL;
 		writeq(val64, &bar0->tx_w_round_robin_0);
-		val64 = 0x0200030106000204ULL;
 		writeq(val64, &bar0->tx_w_round_robin_1);
-		val64 = 0x0103000502010007ULL;
 		writeq(val64, &bar0->tx_w_round_robin_2);
-		val64 = 0x0304010002060500ULL;
 		writeq(val64, &bar0->tx_w_round_robin_3);
-		val64 = 0x0103020400000000ULL;
+		val64 = 0x0001020300000000ULL;
 		writeq(val64, &bar0->tx_w_round_robin_4);
 		break;
 	}
@@ -1537,58 +1621,14 @@ static int init_nic(struct s2io_nic *nic)
 	    MAC_RX_LINK_UTIL_VAL(rmac_util_period);
 	writeq(val64, &bar0->mac_link_util);
 
-
 	/*
 	 * Initializing the Transmit and Receive Traffic Interrupt
 	 * Scheme.
 	 */
-	/*
-	 * TTI Initialization. Default Tx timer gets us about
-	 * 250 interrupts per sec. Continuous interrupts are enabled
-	 * by default.
-	 */
-	if (nic->device_type == XFRAME_II_DEVICE) {
-		int count = (nic->config.bus_speed * 125)/2;
-		val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
-	} else {
-
-		val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
-	}
-	val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
-	    TTI_DATA1_MEM_TX_URNG_B(0x10) |
-	    TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN;
-		if (use_continuous_tx_intrs)
-			val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
-	writeq(val64, &bar0->tti_data1_mem);
-
-	val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
-	    TTI_DATA2_MEM_TX_UFC_B(0x20) |
-	    TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
-	writeq(val64, &bar0->tti_data2_mem);
-
-	val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
-	writeq(val64, &bar0->tti_command_mem);
 
-	/*
-	 * Once the operation completes, the Strobe bit of the command
-	 * register will be reset. We poll for this particular condition
-	 * We wait for a maximum of 500ms for the operation to complete,
-	 * if it's not complete by then we return error.
-	 */
-	time = 0;
-	while (TRUE) {
-		val64 = readq(&bar0->tti_command_mem);
-		if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
-			break;
-		}
-		if (time > 10) {
-			DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n",
-				  dev->name);
-			return -ENODEV;
-		}
-		msleep(50);
-		time++;
-	}
+	/* Initialize TTI */
+	if (SUCCESS != init_tti(nic, nic->last_link_state))
+		return -ENODEV;
 
 	/* RTI Initialization */
 	if (nic->device_type == XFRAME_II_DEVICE) {
@@ -2242,7 +2282,7 @@ static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \
 	u16 j, frg_cnt;
 
 	txds = txdlp;
-	if (txds->Host_Control == (u64)(long)nic->ufo_in_band_v) {
+	if (txds->Host_Control == (u64)(long)fifo_data->ufo_in_band_v) {
 		pci_unmap_single(nic->pdev, (dma_addr_t)
 			txds->Buffer_Pointer, sizeof(u64),
 			PCI_DMA_TODEVICE);
@@ -2297,6 +2337,8 @@ static void free_tx_buffers(struct s2io_nic *nic)
 	config = &nic->config;
 
 	for (i = 0; i < config->tx_fifo_num; i++) {
+		unsigned long flags;
+		spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags);
 		for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
 			txdp = (struct TxD *) \
 			mac_control->fifos[i].list_info[j].list_virt_addr;
@@ -2313,6 +2355,7 @@ static void free_tx_buffers(struct s2io_nic *nic)
 			  dev->name, cnt, i);
 		mac_control->fifos[i].tx_curr_get_info.offset = 0;
 		mac_control->fifos[i].tx_curr_put_info.offset = 0;
+		spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock, flags);
 	}
 }
 
@@ -2933,8 +2976,12 @@ static void tx_intr_handler(struct fifo_info *fifo_data)
 	struct tx_curr_get_info get_info, put_info;
 	struct sk_buff *skb;
 	struct TxD *txdlp;
+	unsigned long flags = 0;
 	u8 err_mask;
 
+	if (!spin_trylock_irqsave(&fifo_data->tx_lock, flags))
+			return;
+
 	get_info = fifo_data->tx_curr_get_info;
 	memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
 	txdlp = (struct TxD *) fifo_data->list_info[get_info.offset].
@@ -2983,6 +3030,7 @@ static void tx_intr_handler(struct fifo_info *fifo_data)
 
 		skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset);
 		if (skb == NULL) {
+			spin_unlock_irqrestore(&fifo_data->tx_lock, flags);
 			DBG_PRINT(ERR_DBG, "%s: Null skb ",
 			__FUNCTION__);
 			DBG_PRINT(ERR_DBG, "in Tx Free Intr\n");
@@ -3003,10 +3051,10 @@ static void tx_intr_handler(struct fifo_info *fifo_data)
 		    get_info.offset;
 	}
 
-	spin_lock(&nic->tx_lock);
 	if (netif_queue_stopped(dev))
 		netif_wake_queue(dev);
-	spin_unlock(&nic->tx_lock);
+
+	spin_unlock_irqrestore(&fifo_data->tx_lock, flags);
 }
 
 /**
@@ -3376,6 +3424,9 @@ static void s2io_reset(struct s2io_nic * sp)
 	/* Set swapper to enable I/O register access */
 	s2io_set_swapper(sp);
 
+	/* restore mac_addr entries */
+	do_s2io_restore_unicast_mc(sp);
+
 	/* Restore the MSIX table entries from local variables */
 	restore_xmsi_data(sp);
 
@@ -3434,9 +3485,6 @@ static void s2io_reset(struct s2io_nic * sp)
 		writeq(val64, &bar0->pcc_err_reg);
 	}
 
-	/* restore the previously assigned mac address */
-	do_s2io_prog_unicast(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
-
 	sp->device_enabled_once = FALSE;
 }
 
@@ -3773,7 +3821,7 @@ static int s2io_test_msi(struct s2io_nic *sp)
 
 	if (!sp->msi_detected) {
 		/* MSI(X) test failed, go back to INTx mode */
-		DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated"
+		DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated "
 			"using MSI(X) during test\n", sp->dev->name,
 			pci_name(pdev));
 
@@ -3921,6 +3969,9 @@ hw_init_failed:
 static int s2io_close(struct net_device *dev)
 {
 	struct s2io_nic *sp = dev->priv;
+	struct config_param *config = &sp->config;
+	u64 tmp64;
+	int offset;
 
 	/* Return if the device is already closed               *
 	*  Can happen when s2io_card_up failed in change_mtu    *
@@ -3929,6 +3980,14 @@ static int s2io_close(struct net_device *dev)
 		return 0;
 
 	netif_stop_queue(dev);
+
+	/* delete all populated mac entries */
+	for (offset = 1; offset < config->max_mc_addr; offset++) {
+		tmp64 = do_s2io_read_unicast_mc(sp, offset);
+		if (tmp64 != S2IO_DISABLE_MAC_ENTRY)
+			do_s2io_delete_unicast_mc(sp, tmp64);
+	}
+
 	/* Reset card, kill tasklet and free Tx and Rx buffers. */
 	s2io_card_down(sp);
 
@@ -3955,9 +4014,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 	register u64 val64;
 	struct TxD *txdp;
 	struct TxFIFO_element __iomem *tx_fifo;
-	unsigned long flags;
+	unsigned long flags = 0;
 	u16 vlan_tag = 0;
 	int vlan_priority = 0;
+	struct fifo_info *fifo = NULL;
 	struct mac_info *mac_control;
 	struct config_param *config;
 	int offload_type;
@@ -3972,13 +4032,11 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 		DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
 		dev_kfree_skb_any(skb);
 		return 0;
-}
+	}
 
-	spin_lock_irqsave(&sp->tx_lock, flags);
 	if (!is_s2io_card_up(sp)) {
 		DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
 			  dev->name);
-		spin_unlock_irqrestore(&sp->tx_lock, flags);
 		dev_kfree_skb(skb);
 		return 0;
 	}
@@ -3991,19 +4049,20 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 		queue = config->fifo_mapping[vlan_priority];
 	}
 
-	put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
-	get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
-	txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off].
-		list_virt_addr;
+	fifo = &mac_control->fifos[queue];
+	spin_lock_irqsave(&fifo->tx_lock, flags);
+	put_off = (u16) fifo->tx_curr_put_info.offset;
+	get_off = (u16) fifo->tx_curr_get_info.offset;
+	txdp = (struct TxD *) fifo->list_info[put_off].list_virt_addr;
 
-	queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
+	queue_len = fifo->tx_curr_put_info.fifo_len + 1;
 	/* Avoid "put" pointer going beyond "get" pointer */
 	if (txdp->Host_Control ||
 		   ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
 		DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
 		netif_stop_queue(dev);
 		dev_kfree_skb(skb);
-		spin_unlock_irqrestore(&sp->tx_lock, flags);
+		spin_unlock_irqrestore(&fifo->tx_lock, flags);
 		return 0;
 	}
 
@@ -4019,7 +4078,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 	txdp->Control_1 |= TXD_GATHER_CODE_FIRST;
 	txdp->Control_1 |= TXD_LIST_OWN_XENA;
-	txdp->Control_2 |= config->tx_intr_type;
+	txdp->Control_2 |= TXD_INT_NUMBER(fifo->fifo_no);
 
 	if (sp->vlgrp && vlan_tx_tag_present(skb)) {
 		txdp->Control_2 |= TXD_VLAN_ENABLE;
@@ -4036,15 +4095,15 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 		txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
 		txdp->Control_1 |= TXD_BUFFER0_SIZE(8);
 #ifdef __BIG_ENDIAN
-		sp->ufo_in_band_v[put_off] =
+		fifo->ufo_in_band_v[put_off] =
 				(u64)skb_shinfo(skb)->ip6_frag_id;
 #else
-		sp->ufo_in_band_v[put_off] =
+		fifo->ufo_in_band_v[put_off] =
 				(u64)skb_shinfo(skb)->ip6_frag_id << 32;
 #endif
-		txdp->Host_Control = (unsigned long)sp->ufo_in_band_v;
+		txdp->Host_Control = (unsigned long)fifo->ufo_in_band_v;
 		txdp->Buffer_Pointer = pci_map_single(sp->pdev,
-					sp->ufo_in_band_v,
+					fifo->ufo_in_band_v,
 					sizeof(u64), PCI_DMA_TODEVICE);
 		if((txdp->Buffer_Pointer == 0) ||
 			(txdp->Buffer_Pointer == DMA_ERROR_CODE))
@@ -4084,7 +4143,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 		frg_cnt++; /* as Txd0 was used for inband header */
 
 	tx_fifo = mac_control->tx_FIFO_start[queue];
-	val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
+	val64 = fifo->list_info[put_off].list_phy_addr;
 	writeq(val64, &tx_fifo->TxDL_Pointer);
 
 	val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
@@ -4097,9 +4156,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 	mmiowb();
 
 	put_off++;
-	if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1)
+	if (put_off == fifo->tx_curr_put_info.fifo_len + 1)
 		put_off = 0;
-	mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
+	fifo->tx_curr_put_info.offset = put_off;
 
 	/* Avoid "put" pointer going beyond "get" pointer */
 	if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
@@ -4111,7 +4170,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 	mac_control->stats_info->sw_stat.mem_allocated += skb->truesize;
 	dev->trans_start = jiffies;
-	spin_unlock_irqrestore(&sp->tx_lock, flags);
+	spin_unlock_irqrestore(&fifo->tx_lock, flags);
 
 	return 0;
 pci_map_failed:
@@ -4119,7 +4178,7 @@ pci_map_failed:
 	netif_stop_queue(dev);
 	stats->mem_freed += skb->truesize;
 	dev_kfree_skb(skb);
-	spin_unlock_irqrestore(&sp->tx_lock, flags);
+	spin_unlock_irqrestore(&fifo->tx_lock, flags);
 	return 0;
 }
 
@@ -4729,8 +4788,9 @@ static void s2io_set_multicast(struct net_device *dev)
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
 	    0xfeffffffffffULL;
-	u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
+	u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, mac_addr = 0;
 	void __iomem *add;
+	struct config_param *config = &sp->config;
 
 	if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) {
 		/*  Enable all Multicast addresses */
@@ -4740,7 +4800,7 @@ static void s2io_set_multicast(struct net_device *dev)
 		       &bar0->rmac_addr_data1_mem);
 		val64 = RMAC_ADDR_CMD_MEM_WE |
 		    RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
-		    RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET);
+		    RMAC_ADDR_CMD_MEM_OFFSET(config->max_mc_addr - 1);
 		writeq(val64, &bar0->rmac_addr_cmd_mem);
 		/* Wait till command completes */
 		wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
@@ -4748,7 +4808,7 @@ static void s2io_set_multicast(struct net_device *dev)
 					S2IO_BIT_RESET);
 
 		sp->m_cast_flg = 1;
-		sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET;
+		sp->all_multi_pos = config->max_mc_addr - 1;
 	} else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) {
 		/*  Disable all Multicast addresses */
 		writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
@@ -4817,7 +4877,7 @@ static void s2io_set_multicast(struct net_device *dev)
 	/*  Update individual M_CAST address list */
 	if ((!sp->m_cast_flg) && dev->mc_count) {
 		if (dev->mc_count >
-		    (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) {
+		    (config->max_mc_addr - config->max_mac_addr)) {
 			DBG_PRINT(ERR_DBG, "%s: No more Rx filters ",
 				  dev->name);
 			DBG_PRINT(ERR_DBG, "can be added, please enable ");
@@ -4837,7 +4897,7 @@ static void s2io_set_multicast(struct net_device *dev)
 			val64 = RMAC_ADDR_CMD_MEM_WE |
 			    RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
 			    RMAC_ADDR_CMD_MEM_OFFSET
-			    (MAC_MC_ADDR_START_OFFSET + i);
+			    (config->mc_start_offset + i);
 			writeq(val64, &bar0->rmac_addr_cmd_mem);
 
 			/* Wait for command completes */
@@ -4869,7 +4929,7 @@ static void s2io_set_multicast(struct net_device *dev)
 			val64 = RMAC_ADDR_CMD_MEM_WE |
 			    RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
 			    RMAC_ADDR_CMD_MEM_OFFSET
-			    (i + MAC_MC_ADDR_START_OFFSET);
+			    (i + config->mc_start_offset);
 			writeq(val64, &bar0->rmac_addr_cmd_mem);
 
 			/* Wait for command completes */
@@ -4885,8 +4945,78 @@ static void s2io_set_multicast(struct net_device *dev)
 	}
 }
 
-/* add unicast MAC address to CAM */
-static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off)
+/* read from CAM unicast & multicast addresses and store it in
+ * def_mac_addr structure
+ */
+void do_s2io_store_unicast_mc(struct s2io_nic *sp)
+{
+	int offset;
+	u64 mac_addr = 0x0;
+	struct config_param *config = &sp->config;
+
+	/* store unicast & multicast mac addresses */
+	for (offset = 0; offset < config->max_mc_addr; offset++) {
+		mac_addr = do_s2io_read_unicast_mc(sp, offset);
+		/* if read fails disable the entry */
+		if (mac_addr == FAILURE)
+			mac_addr = S2IO_DISABLE_MAC_ENTRY;
+		do_s2io_copy_mac_addr(sp, offset, mac_addr);
+	}
+}
+
+/* restore unicast & multicast MAC to CAM from def_mac_addr structure */
+static void do_s2io_restore_unicast_mc(struct s2io_nic *sp)
+{
+	int offset;
+	struct config_param *config = &sp->config;
+	/* restore unicast mac address */
+	for (offset = 0; offset < config->max_mac_addr; offset++)
+		do_s2io_prog_unicast(sp->dev,
+			sp->def_mac_addr[offset].mac_addr);
+
+	/* restore multicast mac address */
+	for (offset = config->mc_start_offset;
+		offset < config->max_mc_addr; offset++)
+		do_s2io_add_mc(sp, sp->def_mac_addr[offset].mac_addr);
+}
+
+/* add a multicast MAC address to CAM */
+static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr)
+{
+	int i;
+	u64 mac_addr = 0;
+	struct config_param *config = &sp->config;
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		mac_addr <<= 8;
+		mac_addr |= addr[i];
+	}
+	if ((0ULL == mac_addr) || (mac_addr == S2IO_DISABLE_MAC_ENTRY))
+		return SUCCESS;
+
+	/* check if the multicast mac already preset in CAM */
+	for (i = config->mc_start_offset; i < config->max_mc_addr; i++) {
+		u64 tmp64;
+		tmp64 = do_s2io_read_unicast_mc(sp, i);
+		if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */
+			break;
+
+		if (tmp64 == mac_addr)
+			return SUCCESS;
+	}
+	if (i == config->max_mc_addr) {
+		DBG_PRINT(ERR_DBG,
+			"CAM full no space left for multicast MAC\n");
+		return FAILURE;
+	}
+	/* Update the internal structure with this new mac address */
+	do_s2io_copy_mac_addr(sp, i, mac_addr);
+
+	return (do_s2io_add_mac(sp, mac_addr, i));
+}
+
+/* add MAC address to CAM */
+static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int off)
 {
 	u64 val64;
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
@@ -4903,15 +5033,62 @@ static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off)
 	if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
 		RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
 		S2IO_BIT_RESET)) {
-		DBG_PRINT(INFO_DBG, "add_mac_addr failed\n");
+		DBG_PRINT(INFO_DBG, "do_s2io_add_mac failed\n");
 		return FAILURE;
 	}
 	return SUCCESS;
 }
+/* deletes a specified unicast/multicast mac entry from CAM */
+static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr)
+{
+	int offset;
+	u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, tmp64;
+	struct config_param *config = &sp->config;
+
+	for (offset = 1;
+		offset < config->max_mc_addr; offset++) {
+		tmp64 = do_s2io_read_unicast_mc(sp, offset);
+		if (tmp64 == addr) {
+			/* disable the entry by writing  0xffffffffffffULL */
+			if (do_s2io_add_mac(sp, dis_addr, offset) ==  FAILURE)
+				return FAILURE;
+			/* store the new mac list from CAM */
+			do_s2io_store_unicast_mc(sp);
+			return SUCCESS;
+		}
+	}
+	DBG_PRINT(ERR_DBG, "MAC address 0x%llx not found in CAM\n",
+			(unsigned long long)addr);
+	return FAILURE;
+}
+
+/* read mac entries from CAM */
+static u64 do_s2io_read_unicast_mc(struct s2io_nic *sp, int offset)
+{
+	u64 tmp64 = 0xffffffffffff0000ULL, val64;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
+
+	/* read mac addr */
+	val64 =
+		RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
+		RMAC_ADDR_CMD_MEM_OFFSET(offset);
+	writeq(val64, &bar0->rmac_addr_cmd_mem);
+
+	/* Wait till command completes */
+	if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+		RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
+		S2IO_BIT_RESET)) {
+		DBG_PRINT(INFO_DBG, "do_s2io_read_unicast_mc failed\n");
+		return FAILURE;
+	}
+	tmp64 = readq(&bar0->rmac_addr_data0_mem);
+	return (tmp64 >> 16);
+}
 
 /**
  * s2io_set_mac_addr driver entry point
  */
+
 static int s2io_set_mac_addr(struct net_device *dev, void *p)
 {
 	struct sockaddr *addr = p;
@@ -4924,7 +5101,6 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p)
 	/* store the MAC address in CAM */
 	return (do_s2io_prog_unicast(dev, dev->dev_addr));
 }
-
 /**
  *  do_s2io_prog_unicast - Programs the Xframe mac address
  *  @dev : pointer to the device structure.
@@ -4934,11 +5110,14 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p)
  *  Return value: SUCCESS on success and an appropriate (-)ve integer
  *  as defined in errno.h file on failure.
  */
+
 static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr)
 {
 	struct s2io_nic *sp = dev->priv;
 	register u64 mac_addr = 0, perm_addr = 0;
 	int i;
+	u64 tmp64;
+	struct config_param *config = &sp->config;
 
 	/*
 	* Set the new MAC address as the new unicast filter and reflect this
@@ -4956,9 +5135,26 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr)
 	if (mac_addr == perm_addr)
 		return SUCCESS;
 
+	/* check if the mac already preset in CAM */
+	for (i = 1; i < config->max_mac_addr; i++) {
+		tmp64 = do_s2io_read_unicast_mc(sp, i);
+		if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */
+			break;
+
+		if (tmp64 == mac_addr) {
+			DBG_PRINT(INFO_DBG,
+			"MAC addr:0x%llx already present in CAM\n",
+			(unsigned long long)mac_addr);
+			return SUCCESS;
+		}
+	}
+	if (i == config->max_mac_addr) {
+		DBG_PRINT(ERR_DBG, "CAM full no space left for Unicast MAC\n");
+		return FAILURE;
+	}
 	/* Update the internal structure with this new mac address */
-	do_s2io_copy_mac_addr(sp, 0, mac_addr);
-	return (do_s2io_add_unicast(sp, mac_addr, 0));
+	do_s2io_copy_mac_addr(sp, i, mac_addr);
+	return (do_s2io_add_mac(sp, mac_addr, i));
 }
 
 /**
@@ -6721,7 +6917,7 @@ static int s2io_add_isr(struct s2io_nic * sp)
 				/* If either data or addr is zero print it */
 				if(!(sp->msix_info[i].addr &&
 					sp->msix_info[i].data)) {
-					DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx"
+					DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx "
 						"Data:0x%lx\n",sp->desc[i],
 						(unsigned long long)
 						sp->msix_info[i].addr,
@@ -6739,7 +6935,7 @@ static int s2io_add_isr(struct s2io_nic * sp)
 				/* If either data or addr is zero print it */
 				if(!(sp->msix_info[i].addr &&
 					sp->msix_info[i].data)) {
-					DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx"
+					DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx "
 						"Data:0x%lx\n",sp->desc[i],
 						(unsigned long long)
 						sp->msix_info[i].addr,
@@ -6848,10 +7044,8 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
 	if (do_io)
 		s2io_reset(sp);
 
-	spin_lock_irqsave(&sp->tx_lock, flags);
 	/* Free all Tx buffers */
 	free_tx_buffers(sp);
-	spin_unlock_irqrestore(&sp->tx_lock, flags);
 
 	/* Free all Rx buffers */
 	spin_lock_irqsave(&sp->rx_lock, flags);
@@ -7263,6 +7457,7 @@ static void s2io_link(struct s2io_nic * sp, int link)
 	struct net_device *dev = (struct net_device *) sp->dev;
 
 	if (link != sp->last_link_state) {
+		init_tti(sp, link);
 		if (link == LINK_DOWN) {
 			DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
 			netif_carrier_off(dev);
@@ -7315,12 +7510,18 @@ static void s2io_init_pci(struct s2io_nic * sp)
 
 static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
 {
-	if ( tx_fifo_num > 8) {
-		DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not "
-			 "supported\n");
-		DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n");
-		tx_fifo_num = 8;
+	if ((tx_fifo_num > MAX_TX_FIFOS) ||
+		(tx_fifo_num < FIFO_DEFAULT_NUM)) {
+		DBG_PRINT(ERR_DBG, "s2io: Requested number of tx fifos "
+			"(%d) not supported\n", tx_fifo_num);
+		tx_fifo_num =
+			((tx_fifo_num > MAX_TX_FIFOS)? MAX_TX_FIFOS :
+			((tx_fifo_num < FIFO_DEFAULT_NUM) ? FIFO_DEFAULT_NUM :
+			tx_fifo_num));
+		DBG_PRINT(ERR_DBG, "s2io: Default to %d ", tx_fifo_num);
+		DBG_PRINT(ERR_DBG, "tx fifos\n");
 	}
+
 	if ( rx_ring_num > 8) {
 		DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
 			 "supported\n");
@@ -7355,7 +7556,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
 /**
  * rts_ds_steer - Receive traffic steering based on IPv4 or IPv6 TOS
  * or Traffic class respectively.
- * @nic: device peivate variable
+ * @nic: device private variable
  * Description: The function configures the receive steering to
  * desired receive ring.
  * Return Value:  SUCCESS on success and
@@ -7652,7 +7853,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 	 */
 	bar0 = sp->bar0;
 	val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
-	    RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET);
+	    RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET);
 	writeq(val64, &bar0->rmac_addr_cmd_mem);
 	wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
 		      RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET);
@@ -7672,6 +7873,20 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 	memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
 	memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
 
+	/* initialize number of multicast & unicast MAC entries variables */
+	if (sp->device_type == XFRAME_I_DEVICE) {
+		config->max_mc_addr = S2IO_XENA_MAX_MC_ADDRESSES;
+		config->max_mac_addr = S2IO_XENA_MAX_MAC_ADDRESSES;
+		config->mc_start_offset = S2IO_XENA_MC_ADDR_START_OFFSET;
+	} else if (sp->device_type == XFRAME_II_DEVICE) {
+		config->max_mc_addr = S2IO_HERC_MAX_MC_ADDRESSES;
+		config->max_mac_addr = S2IO_HERC_MAX_MAC_ADDRESSES;
+		config->mc_start_offset = S2IO_HERC_MC_ADDR_START_OFFSET;
+	}
+
+	/* store mac addresses from CAM to s2io_nic structure */
+	do_s2io_store_unicast_mc(sp);
+
 	 /* Store the values of the MSIX table in the s2io_nic structure */
 	store_xmsi_data(sp);
 	/* reset Nic and bring it to known state */
@@ -7685,7 +7900,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 	sp->state = 0;
 
 	/* Initialize spinlocks */
-	spin_lock_init(&sp->tx_lock);
+	for (i = 0; i < sp->config.tx_fifo_num; i++)
+		spin_lock_init(&mac_control->fifos[i].tx_lock);
 
 	if (!napi)
 		spin_lock_init(&sp->put_lock);
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index cc1797a071aa..9f6016c6f135 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -31,6 +31,7 @@
 #define SUCCESS 0
 #define FAILURE -1
 #define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL
+#define S2IO_DISABLE_MAC_ENTRY 0xFFFFFFFFFFFFULL
 #define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100
 #define S2IO_BIT_RESET 1
 #define S2IO_BIT_SET 2
@@ -359,6 +360,8 @@ struct stat_block {
 #define MAX_TX_FIFOS 8
 #define MAX_RX_RINGS 8
 
+#define FIFO_DEFAULT_NUM	1
+
 #define MAX_RX_DESC_1  (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 127 )
 #define MAX_RX_DESC_2  (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 85 )
 #define MAX_RX_DESC_3  (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 85 )
@@ -458,6 +461,9 @@ struct config_param {
 #define MAX_MTU_JUMBO               (MAX_PYLD_JUMBO+18)
 #define MAX_MTU_JUMBO_VLAN          (MAX_PYLD_JUMBO+22)
 	u16 bus_speed;
+	int max_mc_addr;	/* xena=64 herc=256 */
+	int max_mac_addr;	/* xena=16 herc=64 */
+	int mc_start_offset;	/* xena=16 herc=64 */
 };
 
 /* Structure representing MAC Addrs */
@@ -715,8 +721,14 @@ struct fifo_info {
 	 */
 	struct tx_curr_get_info tx_curr_get_info;
 
+	/* Per fifo lock */
+	spinlock_t tx_lock;
+
+	/* Per fifo UFO in band structure */
+	u64 *ufo_in_band_v;
+
 	struct s2io_nic *nic;
-};
+} ____cacheline_aligned;
 
 /* Information related to the Tx and Rx FIFOs and Rings of Xena
  * is maintained in this structure.
@@ -826,7 +838,7 @@ struct s2io_nic {
 #define MAX_MAC_SUPPORTED   16
 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
 
-	struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED];
+	struct mac_addr def_mac_addr[256];
 
 	struct net_device_stats stats;
 	int high_dma_flag;
@@ -844,7 +856,6 @@ struct s2io_nic {
 
 	atomic_t rx_bufs_left[MAX_RX_RINGS];
 
-	spinlock_t tx_lock;
 	spinlock_t put_lock;
 
 #define PROMISC     1
@@ -853,7 +864,7 @@ struct s2io_nic {
 #define MAX_ADDRS_SUPPORTED 64
 	u16 usr_addr_count;
 	u16 mc_addr_count;
-	struct usr_addr usr_addrs[MAX_ADDRS_SUPPORTED];
+	struct usr_addr usr_addrs[256];
 
 	u16 m_cast_flg;
 	u16 all_multi_pos;
@@ -911,7 +922,6 @@ struct s2io_nic {
 	volatile unsigned long state;
 	spinlock_t	rx_lock;
 	u64		general_int_mask;
-	u64 *ufo_in_band_v;
 #define VPD_STRING_LEN 80
 	u8  product_name[VPD_STRING_LEN];
 	u8  serial_num[VPD_STRING_LEN];
@@ -1066,6 +1076,12 @@ static int s2io_add_isr(struct s2io_nic * sp);
 static void s2io_rem_isr(struct s2io_nic * sp);
 
 static void restore_xmsi_data(struct s2io_nic *nic);
+static void do_s2io_store_unicast_mc(struct s2io_nic *sp);
+static void do_s2io_restore_unicast_mc(struct s2io_nic *sp);
+static u64 do_s2io_read_unicast_mc(struct s2io_nic *sp, int offset);
+static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr);
+static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int offset);
+static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr);
 
 static int
 s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index ff4056310356..78994ede0cb0 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -53,14 +52,27 @@ static char *sgiseeqstr = "SGI Seeq8003";
 			    sp->tx_old + (SEEQ_TX_BUFFERS - 1) - sp->tx_new : \
 			    sp->tx_old - sp->tx_new - 1)
 
+#define VIRT_TO_DMA(sp, v) ((sp)->srings_dma +                                 \
+				  (dma_addr_t)((unsigned long)(v) -            \
+					       (unsigned long)((sp)->rx_desc)))
+
+/* Copy frames shorter than rx_copybreak, otherwise pass on up in
+ * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
+ */
+static int rx_copybreak = 100;
+
+#define PAD_SIZE    (128 - sizeof(struct hpc_dma_desc) - sizeof(void *))
+
 struct sgiseeq_rx_desc {
 	volatile struct hpc_dma_desc rdma;
-	volatile signed int buf_vaddr;
+	u8 padding[PAD_SIZE];
+	struct sk_buff *skb;
 };
 
 struct sgiseeq_tx_desc {
 	volatile struct hpc_dma_desc tdma;
-	volatile signed int buf_vaddr;
+	u8 padding[PAD_SIZE];
+	struct sk_buff *skb;
 };
 
 /*
@@ -96,6 +108,18 @@ struct sgiseeq_private {
 	spinlock_t tx_lock;
 };
 
+static inline void dma_sync_desc_cpu(struct net_device *dev, void *addr)
+{
+	dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc),
+		       DMA_FROM_DEVICE);
+}
+
+static inline void dma_sync_desc_dev(struct net_device *dev, void *addr)
+{
+	dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc),
+		       DMA_TO_DEVICE);
+}
+
 static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs)
 {
 	hregs->reset = HPC3_ERST_CRESET | HPC3_ERST_CLRIRQ;
@@ -163,35 +187,55 @@ static int seeq_init_ring(struct net_device *dev)
 
 	/* Setup tx ring. */
 	for(i = 0; i < SEEQ_TX_BUFFERS; i++) {
-		if (!sp->tx_desc[i].tdma.pbuf) {
-			unsigned long buffer;
-
-			buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
-			if (!buffer)
-				return -ENOMEM;
-			sp->tx_desc[i].buf_vaddr = CKSEG1ADDR(buffer);
-			sp->tx_desc[i].tdma.pbuf = CPHYSADDR(buffer);
-		}
 		sp->tx_desc[i].tdma.cntinfo = TCNTINFO_INIT;
+		dma_sync_desc_dev(dev, &sp->tx_desc[i]);
 	}
 
 	/* And now the rx ring. */
 	for (i = 0; i < SEEQ_RX_BUFFERS; i++) {
-		if (!sp->rx_desc[i].rdma.pbuf) {
-			unsigned long buffer;
+		if (!sp->rx_desc[i].skb) {
+			dma_addr_t dma_addr;
+			struct sk_buff *skb = netdev_alloc_skb(dev, PKT_BUF_SZ);
 
-			buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
-			if (!buffer)
+			if (skb == NULL)
 				return -ENOMEM;
-			sp->rx_desc[i].buf_vaddr = CKSEG1ADDR(buffer);
-			sp->rx_desc[i].rdma.pbuf = CPHYSADDR(buffer);
+			skb_reserve(skb, 2);
+			dma_addr = dma_map_single(dev->dev.parent,
+						  skb->data - 2,
+						  PKT_BUF_SZ, DMA_FROM_DEVICE);
+			sp->rx_desc[i].skb = skb;
+			sp->rx_desc[i].rdma.pbuf = dma_addr;
 		}
 		sp->rx_desc[i].rdma.cntinfo = RCNTINFO_INIT;
+		dma_sync_desc_dev(dev, &sp->rx_desc[i]);
 	}
 	sp->rx_desc[i - 1].rdma.cntinfo |= HPCDMA_EOR;
+	dma_sync_desc_dev(dev, &sp->rx_desc[i - 1]);
 	return 0;
 }
 
+static void seeq_purge_ring(struct net_device *dev)
+{
+	struct sgiseeq_private *sp = netdev_priv(dev);
+	int i;
+
+	/* clear tx ring. */
+	for (i = 0; i < SEEQ_TX_BUFFERS; i++) {
+		if (sp->tx_desc[i].skb) {
+			dev_kfree_skb(sp->tx_desc[i].skb);
+			sp->tx_desc[i].skb = NULL;
+		}
+	}
+
+	/* And now the rx ring. */
+	for (i = 0; i < SEEQ_RX_BUFFERS; i++) {
+		if (sp->rx_desc[i].skb) {
+			dev_kfree_skb(sp->rx_desc[i].skb);
+			sp->rx_desc[i].skb = NULL;
+		}
+	}
+}
+
 #ifdef DEBUG
 static struct sgiseeq_private *gpriv;
 static struct net_device *gdev;
@@ -258,8 +302,8 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
 		sregs->tstat = TSTAT_INIT_SEEQ;
 	}
 
-	hregs->rx_ndptr = CPHYSADDR(sp->rx_desc);
-	hregs->tx_ndptr = CPHYSADDR(sp->tx_desc);
+	hregs->rx_ndptr = VIRT_TO_DMA(sp, sp->rx_desc);
+	hregs->tx_ndptr = VIRT_TO_DMA(sp, sp->tx_desc);
 
 	seeq_go(sp, hregs, sregs);
 	return 0;
@@ -283,69 +327,90 @@ static inline void rx_maybe_restart(struct sgiseeq_private *sp,
 				    struct sgiseeq_regs *sregs)
 {
 	if (!(hregs->rx_ctrl & HPC3_ERXCTRL_ACTIVE)) {
-		hregs->rx_ndptr = CPHYSADDR(sp->rx_desc + sp->rx_new);
+		hregs->rx_ndptr = VIRT_TO_DMA(sp, sp->rx_desc + sp->rx_new);
 		seeq_go(sp, hregs, sregs);
 	}
 }
 
-#define for_each_rx(rd, sp) for((rd) = &(sp)->rx_desc[(sp)->rx_new]; \
-				!((rd)->rdma.cntinfo & HPCDMA_OWN); \
-				(rd) = &(sp)->rx_desc[(sp)->rx_new])
-
 static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp,
 			      struct hpc3_ethregs *hregs,
 			      struct sgiseeq_regs *sregs)
 {
 	struct sgiseeq_rx_desc *rd;
 	struct sk_buff *skb = NULL;
+	struct sk_buff *newskb;
 	unsigned char pkt_status;
-	unsigned char *pkt_pointer = NULL;
 	int len = 0;
 	unsigned int orig_end = PREV_RX(sp->rx_new);
 
 	/* Service every received packet. */
-	for_each_rx(rd, sp) {
+	rd = &sp->rx_desc[sp->rx_new];
+	dma_sync_desc_cpu(dev, rd);
+	while (!(rd->rdma.cntinfo & HPCDMA_OWN)) {
 		len = PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3;
-		pkt_pointer = (unsigned char *)(long)rd->buf_vaddr;
-		pkt_status = pkt_pointer[len + 2];
-
+		dma_unmap_single(dev->dev.parent, rd->rdma.pbuf,
+				 PKT_BUF_SZ, DMA_FROM_DEVICE);
+		pkt_status = rd->skb->data[len];
 		if (pkt_status & SEEQ_RSTAT_FIG) {
 			/* Packet is OK. */
-			skb = dev_alloc_skb(len + 2);
-
-			if (skb) {
-				skb_reserve(skb, 2);
-				skb_put(skb, len);
-
-				/* Copy out of kseg1 to avoid silly cache flush. */
-				skb_copy_to_linear_data(skb, pkt_pointer + 2, len);
-				skb->protocol = eth_type_trans(skb, dev);
-
-				/* We don't want to receive our own packets */
-				if (memcmp(eth_hdr(skb)->h_source, dev->dev_addr, ETH_ALEN)) {
+			/* We don't want to receive our own packets */
+			if (memcmp(rd->skb->data + 6, dev->dev_addr, ETH_ALEN)) {
+				if (len > rx_copybreak) {
+					skb = rd->skb;
+					newskb = netdev_alloc_skb(dev, PKT_BUF_SZ);
+					if (!newskb) {
+						newskb = skb;
+						skb = NULL;
+						goto memory_squeeze;
+					}
+					skb_reserve(newskb, 2);
+				} else {
+					skb = netdev_alloc_skb(dev, len + 2);
+					if (skb) {
+						skb_reserve(skb, 2);
+						skb_copy_to_linear_data(skb, rd->skb->data, len);
+					}
+					newskb = rd->skb;
+				}
+memory_squeeze:
+				if (skb) {
+					skb_put(skb, len);
+					skb->protocol = eth_type_trans(skb, dev);
 					netif_rx(skb);
 					dev->last_rx = jiffies;
 					dev->stats.rx_packets++;
 					dev->stats.rx_bytes += len;
 				} else {
-					/* Silently drop my own packets */
-					dev_kfree_skb_irq(skb);
+					printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
+						dev->name);
+					dev->stats.rx_dropped++;
 				}
 			} else {
-				printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
-					dev->name);
-				dev->stats.rx_dropped++;
+				/* Silently drop my own packets */
+				newskb = rd->skb;
 			}
 		} else {
 			record_rx_errors(dev, pkt_status);
+			newskb = rd->skb;
 		}
+		rd->skb = newskb;
+		rd->rdma.pbuf = dma_map_single(dev->dev.parent,
+					       newskb->data - 2,
+					       PKT_BUF_SZ, DMA_FROM_DEVICE);
 
 		/* Return the entry to the ring pool. */
 		rd->rdma.cntinfo = RCNTINFO_INIT;
 		sp->rx_new = NEXT_RX(sp->rx_new);
+		dma_sync_desc_dev(dev, rd);
+		rd = &sp->rx_desc[sp->rx_new];
+		dma_sync_desc_cpu(dev, rd);
 	}
+	dma_sync_desc_cpu(dev, &sp->rx_desc[orig_end]);
 	sp->rx_desc[orig_end].rdma.cntinfo &= ~(HPCDMA_EOR);
+	dma_sync_desc_dev(dev, &sp->rx_desc[orig_end]);
+	dma_sync_desc_cpu(dev, &sp->rx_desc[PREV_RX(sp->rx_new)]);
 	sp->rx_desc[PREV_RX(sp->rx_new)].rdma.cntinfo |= HPCDMA_EOR;
+	dma_sync_desc_dev(dev, &sp->rx_desc[PREV_RX(sp->rx_new)]);
 	rx_maybe_restart(sp, hregs, sregs);
 }
 
@@ -358,20 +423,29 @@ static inline void tx_maybe_reset_collisions(struct sgiseeq_private *sp,
 	}
 }
 
-static inline void kick_tx(struct sgiseeq_tx_desc *td,
+static inline void kick_tx(struct net_device *dev,
+			   struct sgiseeq_private *sp,
 			   struct hpc3_ethregs *hregs)
 {
+	struct sgiseeq_tx_desc *td;
+	int i = sp->tx_old;
+
 	/* If the HPC aint doin nothin, and there are more packets
 	 * with ETXD cleared and XIU set we must make very certain
 	 * that we restart the HPC else we risk locking up the
 	 * adapter.  The following code is only safe iff the HPCDMA
 	 * is not active!
 	 */
+	td = &sp->tx_desc[i];
+	dma_sync_desc_cpu(dev, td);
 	while ((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) ==
-	      (HPCDMA_XIU | HPCDMA_ETXD))
-		td = (struct sgiseeq_tx_desc *)(long) CKSEG1ADDR(td->tdma.pnext);
+	      (HPCDMA_XIU | HPCDMA_ETXD)) {
+		i = NEXT_TX(i);
+		td = &sp->tx_desc[i];
+		dma_sync_desc_cpu(dev, td);
+	}
 	if (td->tdma.cntinfo & HPCDMA_XIU) {
-		hregs->tx_ndptr = CPHYSADDR(td);
+		hregs->tx_ndptr = VIRT_TO_DMA(sp, td);
 		hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
 	}
 }
@@ -400,11 +474,12 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp
 	for (j = sp->tx_old; j != sp->tx_new; j = NEXT_TX(j)) {
 		td = &sp->tx_desc[j];
 
+		dma_sync_desc_cpu(dev, td);
 		if (!(td->tdma.cntinfo & (HPCDMA_XIU)))
 			break;
 		if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) {
 			if (!(status & HPC3_ETXCTRL_ACTIVE)) {
-				hregs->tx_ndptr = CPHYSADDR(td);
+				hregs->tx_ndptr = VIRT_TO_DMA(sp, td);
 				hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE;
 			}
 			break;
@@ -413,6 +488,11 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp
 		sp->tx_old = NEXT_TX(sp->tx_old);
 		td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE);
 		td->tdma.cntinfo |= HPCDMA_EOX;
+		if (td->skb) {
+			dev_kfree_skb_any(td->skb);
+			td->skb = NULL;
+		}
+		dma_sync_desc_dev(dev, td);
 	}
 }
 
@@ -480,6 +560,7 @@ static int sgiseeq_close(struct net_device *dev)
 	/* Shutdown the Seeq. */
 	reset_hpc3_and_seeq(sp->hregs, sregs);
 	free_irq(irq, dev);
+	seeq_purge_ring(dev);
 
 	return 0;
 }
@@ -506,16 +587,22 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	struct hpc3_ethregs *hregs = sp->hregs;
 	unsigned long flags;
 	struct sgiseeq_tx_desc *td;
-	int skblen, len, entry;
+	int len, entry;
 
 	spin_lock_irqsave(&sp->tx_lock, flags);
 
 	/* Setup... */
-	skblen = skb->len;
-	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+	len = skb->len;
+	if (len < ETH_ZLEN) {
+		if (skb_padto(skb, ETH_ZLEN))
+			return 0;
+		len = ETH_ZLEN;
+	}
+
 	dev->stats.tx_bytes += len;
 	entry = sp->tx_new;
 	td = &sp->tx_desc[entry];
+	dma_sync_desc_cpu(dev, td);
 
 	/* Create entry.  There are so many races with adding a new
 	 * descriptor to the chain:
@@ -530,25 +617,27 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	 *    entry and the HPC got to the end of the chain before we
 	 *    added this new entry and restarted it.
 	 */
-	skb_copy_from_linear_data(skb, (char *)(long)td->buf_vaddr, skblen);
-	if (len != skblen)
-		memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen);
+	td->skb = skb;
+	td->tdma.pbuf = dma_map_single(dev->dev.parent, skb->data,
+				       len, DMA_TO_DEVICE);
 	td->tdma.cntinfo = (len & HPCDMA_BCNT) |
 	                   HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX;
+	dma_sync_desc_dev(dev, td);
 	if (sp->tx_old != sp->tx_new) {
 		struct sgiseeq_tx_desc *backend;
 
 		backend = &sp->tx_desc[PREV_TX(sp->tx_new)];
+		dma_sync_desc_cpu(dev, backend);
 		backend->tdma.cntinfo &= ~HPCDMA_EOX;
+		dma_sync_desc_dev(dev, backend);
 	}
 	sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */
 
 	/* Maybe kick the HPC back into motion. */
 	if (!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE))
-		kick_tx(&sp->tx_desc[sp->tx_old], hregs);
+		kick_tx(dev, sp, hregs);
 
 	dev->trans_start = jiffies;
-	dev_kfree_skb(skb);
 
 	if (!TX_BUFFS_AVAIL(sp))
 		netif_stop_queue(dev);
@@ -586,33 +675,41 @@ static void sgiseeq_set_multicast(struct net_device *dev)
 		sgiseeq_reset(dev);
 }
 
-static inline void setup_tx_ring(struct sgiseeq_tx_desc *buf, int nbufs)
+static inline void setup_tx_ring(struct net_device *dev,
+				 struct sgiseeq_tx_desc *buf,
+				 int nbufs)
 {
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	int i = 0;
 
 	while (i < (nbufs - 1)) {
-		buf[i].tdma.pnext = CPHYSADDR(buf + i + 1);
+		buf[i].tdma.pnext = VIRT_TO_DMA(sp, buf + i + 1);
 		buf[i].tdma.pbuf = 0;
+		dma_sync_desc_dev(dev, &buf[i]);
 		i++;
 	}
-	buf[i].tdma.pnext = CPHYSADDR(buf);
+	buf[i].tdma.pnext = VIRT_TO_DMA(sp, buf);
+	dma_sync_desc_dev(dev, &buf[i]);
 }
 
-static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs)
+static inline void setup_rx_ring(struct net_device *dev,
+				 struct sgiseeq_rx_desc *buf,
+				 int nbufs)
 {
+	struct sgiseeq_private *sp = netdev_priv(dev);
 	int i = 0;
 
 	while (i < (nbufs - 1)) {
-		buf[i].rdma.pnext = CPHYSADDR(buf + i + 1);
+		buf[i].rdma.pnext = VIRT_TO_DMA(sp, buf + i + 1);
 		buf[i].rdma.pbuf = 0;
+		dma_sync_desc_dev(dev, &buf[i]);
 		i++;
 	}
 	buf[i].rdma.pbuf = 0;
-	buf[i].rdma.pnext = CPHYSADDR(buf);
+	buf[i].rdma.pnext = VIRT_TO_DMA(sp, buf);
+	dma_sync_desc_dev(dev, &buf[i]);
 }
 
-#define ALIGNED(x)  ((((unsigned long)(x)) + 0xf) & ~(0xf))
-
 static int __init sgiseeq_probe(struct platform_device *pdev)
 {
 	struct sgiseeq_platform_data *pd = pdev->dev.platform_data;
@@ -621,7 +718,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
 	unsigned int irq = pd->irq;
 	struct sgiseeq_private *sp;
 	struct net_device *dev;
-	int err, i;
+	int err;
 	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof (struct sgiseeq_private));
@@ -635,7 +732,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
 	sp = netdev_priv(dev);
 
 	/* Make private data page aligned */
-	sr = dma_alloc_coherent(&pdev->dev, sizeof(*sp->srings),
+	sr = dma_alloc_noncoherent(&pdev->dev, sizeof(*sp->srings),
 				&sp->srings_dma, GFP_KERNEL);
 	if (!sr) {
 		printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n");
@@ -647,8 +744,8 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
 	sp->tx_desc = sp->srings->txvector;
 
 	/* A couple calculations now, saves many cycles later. */
-	setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
-	setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
+	setup_rx_ring(dev, sp->rx_desc, SEEQ_RX_BUFFERS);
+	setup_tx_ring(dev, sp->tx_desc, SEEQ_TX_BUFFERS);
 
 	memcpy(dev->dev_addr, pd->mac, ETH_ALEN);
 
@@ -716,8 +813,8 @@ static int __exit sgiseeq_remove(struct platform_device *pdev)
 	struct sgiseeq_private *sp = netdev_priv(dev);
 
 	unregister_netdev(dev);
-	dma_free_coherent(&pdev->dev, sizeof(*sp->srings), sp->srings,
-	                  sp->srings_dma);
+	dma_free_noncoherent(&pdev->dev, sizeof(*sp->srings), sp->srings,
+			     sp->srings_dma);
 	free_netdev(dev);
 	platform_set_drvdata(pdev, NULL);
 
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
deleted file mode 100644
index 228f650250f6..000000000000
--- a/drivers/net/shaper.c
+++ /dev/null
@@ -1,603 +0,0 @@
-/*
- *			Simple traffic shaper for Linux NET3.
- *
- *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
- *				http://www.redhat.com
- *
- *	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 Alan Cox nor CymruNet Ltd. admit liability nor provide
- *	warranty for any of this software. This material is provided
- *	"AS-IS" and at no charge.
- *
- *
- *	Algorithm:
- *
- *	Queue Frame:
- *		Compute time length of frame at regulated speed
- *		Add frame to queue at appropriate point
- *		Adjust time length computation for followup frames
- *		Any frame that falls outside of its boundaries is freed
- *
- *	We work to the following constants
- *
- *		SHAPER_QLEN	Maximum queued frames
- *		SHAPER_LATENCY	Bounding latency on a frame. Leaving this latency
- *				window drops the frame. This stops us queueing
- *				frames for a long time and confusing a remote
- *				host.
- *		SHAPER_MAXSLIP	Maximum time a priority frame may jump forward.
- *				That bounds the penalty we will inflict on low
- *				priority traffic.
- *		SHAPER_BURST	Time range we call "now" in order to reduce
- *				system load. The more we make this the burstier
- *				the behaviour, the better local performance you
- *				get through packet clustering on routers and the
- *				worse the remote end gets to judge rtts.
- *
- *	This is designed to handle lower speed links ( < 200K/second or so). We
- *	run off a 100-150Hz base clock typically. This gives us a resolution at
- *	200Kbit/second of about 2Kbit or 256 bytes. Above that our timer
- *	resolution may start to cause much more burstiness in the traffic. We
- *	could avoid a lot of that by calling kick_shaper() at the end of the
- *	tied device transmissions. If you run above about 100K second you
- *	may need to tune the supposed speed rate for the right values.
- *
- *	BUGS:
- *		Downing the interface under the shaper before the shaper
- *		will render your machine defunct. Don't for now shape over
- *		PPP or SLIP therefore!
- *		This will be fixed in BETA4
- *
- * Update History :
- *
- *              bh_atomic() SMP races fixes and rewritten the locking code to
- *              be SMP safe and irq-mask friendly.
- *              NOTE: we can't use start_bh_atomic() in kick_shaper()
- *              because it's going to be recalled from an irq handler,
- *              and synchronize_bh() is a nono if called from irq context.
- *						1999  Andrea Arcangeli
- *
- *              Device statistics (tx_pakets, tx_bytes,
- *              tx_drops: queue_over_time and collisions: max_queue_exceded)
- *                               1999/06/18 Jordi Murgo <savage@apostols.org>
- *
- *		Use skb->cb for private data.
- *				 2000/03 Andi Kleen
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/init.h>
-#include <linux/if_shaper.h>
-#include <linux/jiffies.h>
-
-#include <net/dst.h>
-#include <net/arp.h>
-#include <net/net_namespace.h>
-
-struct shaper_cb {
-	unsigned long	shapeclock;		/* Time it should go out */
-	unsigned long	shapestamp;		/* Stamp for shaper    */
-	__u32		shapelatency;		/* Latency on frame */
-	__u32		shapelen;		/* Frame length in clocks */
-	__u16		shapepend;		/* Pending */
-};
-#define SHAPERCB(skb) ((struct shaper_cb *) ((skb)->cb))
-
-static int sh_debug;		/* Debug flag */
-
-#define SHAPER_BANNER	"CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n"
-
-static void shaper_kick(struct shaper *sh);
-
-/*
- *	Compute clocks on a buffer
- */
-
-static int shaper_clocks(struct shaper *shaper, struct sk_buff *skb)
-{
- 	int t=skb->len/shaper->bytespertick;
- 	return t;
-}
-
-/*
- *	Set the speed of a shaper. We compute this in bytes per tick since
- *	thats how the machine wants to run. Quoted input is in bits per second
- *	as is traditional (note not BAUD). We assume 8 bit bytes.
- */
-
-static void shaper_setspeed(struct shaper *shaper, int bitspersec)
-{
-	shaper->bitspersec=bitspersec;
-	shaper->bytespertick=(bitspersec/HZ)/8;
-	if(!shaper->bytespertick)
-		shaper->bytespertick++;
-}
-
-/*
- *	Throw a frame at a shaper.
- */
-
-
-static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct shaper *shaper = dev->priv;
- 	struct sk_buff *ptr;
-
-	spin_lock(&shaper->lock);
- 	ptr=shaper->sendq.prev;
-
- 	/*
- 	 *	Set up our packet details
- 	 */
-
- 	SHAPERCB(skb)->shapelatency=0;
- 	SHAPERCB(skb)->shapeclock=shaper->recovery;
- 	if(time_before(SHAPERCB(skb)->shapeclock, jiffies))
- 		SHAPERCB(skb)->shapeclock=jiffies;
- 	skb->priority=0;	/* short term bug fix */
- 	SHAPERCB(skb)->shapestamp=jiffies;
-
- 	/*
- 	 *	Time slots for this packet.
- 	 */
-
- 	SHAPERCB(skb)->shapelen= shaper_clocks(shaper,skb);
-
-	{
-		struct sk_buff *tmp;
-		/*
-		 *	Up our shape clock by the time pending on the queue
-		 *	(Should keep this in the shaper as a variable..)
-		 */
-		for(tmp=skb_peek(&shaper->sendq); tmp!=NULL &&
-			tmp!=(struct sk_buff *)&shaper->sendq; tmp=tmp->next)
-			SHAPERCB(skb)->shapeclock+=SHAPERCB(tmp)->shapelen;
-		/*
-		 *	Queue over time. Spill packet.
-		 */
-		if(time_after(SHAPERCB(skb)->shapeclock,jiffies + SHAPER_LATENCY)) {
-			dev_kfree_skb(skb);
-			dev->stats.tx_dropped++;
-		} else
-			skb_queue_tail(&shaper->sendq, skb);
-	}
-
-	if(sh_debug)
- 		printk("Frame queued.\n");
- 	if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN)
- 	{
- 		ptr=skb_dequeue(&shaper->sendq);
-                dev_kfree_skb(ptr);
-                dev->stats.collisions++;
- 	}
-	shaper_kick(shaper);
-	spin_unlock(&shaper->lock);
- 	return 0;
-}
-
-/*
- *	Transmit from a shaper
- */
-
-static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
-{
-	struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
-	if(sh_debug)
-		printk("Kick frame on %p\n",newskb);
-	if(newskb)
-	{
-		newskb->dev=shaper->dev;
-		newskb->priority=2;
-		if(sh_debug)
-			printk("Kick new frame to %s, %d\n",
-				shaper->dev->name,newskb->priority);
-		dev_queue_xmit(newskb);
-
-                shaper->dev->stats.tx_bytes += skb->len;
-		shaper->dev->stats.tx_packets++;
-
-                if(sh_debug)
-			printk("Kicked new frame out.\n");
-		dev_kfree_skb(skb);
-	}
-}
-
-/*
- *	Timer handler for shaping clock
- */
-
-static void shaper_timer(unsigned long data)
-{
-	struct shaper *shaper = (struct shaper *)data;
-
-	spin_lock(&shaper->lock);
-	shaper_kick(shaper);
-	spin_unlock(&shaper->lock);
-}
-
-/*
- *	Kick a shaper queue and try and do something sensible with the
- *	queue.
- */
-
-static void shaper_kick(struct shaper *shaper)
-{
-	struct sk_buff *skb;
-
-	/*
-	 *	Walk the list (may be empty)
-	 */
-
-	while((skb=skb_peek(&shaper->sendq))!=NULL)
-	{
-		/*
-		 *	Each packet due to go out by now (within an error
-		 *	of SHAPER_BURST) gets kicked onto the link
-		 */
-
-		if(sh_debug)
-			printk("Clock = %ld, jiffies = %ld\n", SHAPERCB(skb)->shapeclock, jiffies);
-		if(time_before_eq(SHAPERCB(skb)->shapeclock, jiffies + SHAPER_BURST))
-		{
-			/*
-			 *	Pull the frame and get interrupts back on.
-			 */
-
-			skb_unlink(skb, &shaper->sendq);
-			if (shaper->recovery <
-			    SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen)
-				shaper->recovery = SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen;
-			/*
-			 *	Pass on to the physical target device via
-			 *	our low level packet thrower.
-			 */
-
-			SHAPERCB(skb)->shapepend=0;
-			shaper_queue_xmit(shaper, skb);	/* Fire */
-		}
-		else
-			break;
-	}
-
-	/*
-	 *	Next kick.
-	 */
-
-	if(skb!=NULL)
-		mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock);
-}
-
-
-/*
- *	Bring the interface up. We just disallow this until a
- *	bind.
- */
-
-static int shaper_open(struct net_device *dev)
-{
-	struct shaper *shaper=dev->priv;
-
-	/*
-	 *	Can't open until attached.
-	 *	Also can't open until speed is set, or we'll get
-	 *	a division by zero.
-	 */
-
-	if(shaper->dev==NULL)
-		return -ENODEV;
-	if(shaper->bitspersec==0)
-		return -EINVAL;
-	return 0;
-}
-
-/*
- *	Closing a shaper flushes the queues.
- */
-
-static int shaper_close(struct net_device *dev)
-{
-	struct shaper *shaper=dev->priv;
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&shaper->sendq)) != NULL)
-		dev_kfree_skb(skb);
-
-	spin_lock_bh(&shaper->lock);
-	shaper_kick(shaper);
-	spin_unlock_bh(&shaper->lock);
-
-	del_timer_sync(&shaper->timer);
-	return 0;
-}
-
-/*
- *	Revectored calls. We alter the parameters and call the functions
- *	for our attached device. This enables us to bandwidth allocate after
- *	ARP and other resolutions and not before.
- */
-
-static int shaper_header(struct sk_buff *skb, struct net_device *dev,
-			 unsigned short type,
-			 const void *daddr, const void *saddr, unsigned len)
-{
-	struct shaper *sh=dev->priv;
-	int v;
-	if(sh_debug)
-		printk("Shaper header\n");
-	skb->dev = sh->dev;
-	v = dev_hard_header(skb, sh->dev, type, daddr, saddr, len);
-	skb->dev = dev;
-	return v;
-}
-
-static int shaper_rebuild_header(struct sk_buff *skb)
-{
-	struct shaper *sh=skb->dev->priv;
-	struct net_device *dev=skb->dev;
-	int v;
-	if(sh_debug)
-		printk("Shaper rebuild header\n");
-	skb->dev=sh->dev;
-	v = sh->dev->header_ops->rebuild(skb);
-	skb->dev=dev;
-	return v;
-}
-
-#if 0
-static int shaper_cache(struct neighbour *neigh, struct hh_cache *hh)
-{
-	struct shaper *sh=neigh->dev->priv;
-	struct net_device *tmp;
-	int ret;
-	if(sh_debug)
-		printk("Shaper header cache bind\n");
-	tmp=neigh->dev;
-	neigh->dev=sh->dev;
-	ret=sh->hard_header_cache(neigh,hh);
-	neigh->dev=tmp;
-	return ret;
-}
-
-static void shaper_cache_update(struct hh_cache *hh, struct net_device *dev,
-	unsigned char *haddr)
-{
-	struct shaper *sh=dev->priv;
-	if(sh_debug)
-		printk("Shaper cache update\n");
-	sh->header_cache_update(hh, sh->dev, haddr);
-}
-#endif
-
-#ifdef CONFIG_INET
-
-static int shaper_neigh_setup(struct neighbour *n)
-{
-#ifdef CONFIG_INET
-	if (n->nud_state == NUD_NONE) {
-		n->ops = &arp_broken_ops;
-		n->output = n->ops->output;
-	}
-#endif
-	return 0;
-}
-
-static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
-{
-#ifdef CONFIG_INET
-	if (p->tbl->family == AF_INET) {
-		p->neigh_setup = shaper_neigh_setup;
-		p->ucast_probes = 0;
-		p->mcast_probes = 0;
-	}
-#endif
-	return 0;
-}
-
-#else /* !(CONFIG_INET) */
-
-static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
-{
-	return 0;
-}
-
-#endif
-
-static const struct header_ops shaper_ops = {
-	.create	 = shaper_header,
-	.rebuild = shaper_rebuild_header,
-};
-
-static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net_device *dev)
-{
-	sh->dev = dev;
-	sh->get_stats=dev->get_stats;
-
-	shdev->neigh_setup = shaper_neigh_setup_dev;
-	shdev->hard_header_len=dev->hard_header_len;
-	shdev->type=dev->type;
-	shdev->addr_len=dev->addr_len;
-	shdev->mtu=dev->mtu;
-	sh->bitspersec=0;
-	return 0;
-}
-
-static int shaper_ioctl(struct net_device *dev,  struct ifreq *ifr, int cmd)
-{
-	struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_ifru;
-	struct shaper *sh=dev->priv;
-
-	if(ss->ss_cmd == SHAPER_SET_DEV || ss->ss_cmd == SHAPER_SET_SPEED)
-	{
-		if(!capable(CAP_NET_ADMIN))
-			return -EPERM;
-	}
-
-	switch(ss->ss_cmd)
-	{
-		case SHAPER_SET_DEV:
-		{
-			struct net_device *them=__dev_get_by_name(&init_net, ss->ss_name);
-			if(them==NULL)
-				return -ENODEV;
-			if(sh->dev)
-				return -EBUSY;
-			return shaper_attach(dev,dev->priv, them);
-		}
-		case SHAPER_GET_DEV:
-			if(sh->dev==NULL)
-				return -ENODEV;
-			strcpy(ss->ss_name, sh->dev->name);
-			return 0;
-		case SHAPER_SET_SPEED:
-			shaper_setspeed(sh,ss->ss_speed);
-			return 0;
-		case SHAPER_GET_SPEED:
-			ss->ss_speed=sh->bitspersec;
-			return 0;
-		default:
-			return -EINVAL;
-	}
-}
-
-static void shaper_init_priv(struct net_device *dev)
-{
-	struct shaper *sh = dev->priv;
-
-	skb_queue_head_init(&sh->sendq);
-	init_timer(&sh->timer);
-	sh->timer.function=shaper_timer;
-	sh->timer.data=(unsigned long)sh;
-	spin_lock_init(&sh->lock);
-}
-
-/*
- *	Add a shaper device to the system
- */
-
-static void __init shaper_setup(struct net_device *dev)
-{
-	/*
-	 *	Set up the shaper.
-	 */
-
-	shaper_init_priv(dev);
-
-	dev->open		= shaper_open;
-	dev->stop		= shaper_close;
-	dev->hard_start_xmit 	= shaper_start_xmit;
-	dev->set_multicast_list = NULL;
-
-	/*
-	 *	Intialise the packet queues
-	 */
-
-	/*
-	 *	Handlers for when we attach to a device.
-	 */
-
-	dev->neigh_setup	= shaper_neigh_setup_dev;
-	dev->do_ioctl		= shaper_ioctl;
-	dev->hard_header_len	= 0;
-	dev->type		= ARPHRD_ETHER;	/* initially */
-	dev->set_mac_address	= NULL;
-	dev->mtu		= 1500;
-	dev->addr_len		= 0;
-	dev->tx_queue_len	= 10;
-	dev->flags		= 0;
-}
-
-static int shapers = 1;
-#ifdef MODULE
-
-module_param(shapers, int, 0);
-MODULE_PARM_DESC(shapers, "Traffic shaper: maximum number of shapers");
-
-#else /* MODULE */
-
-static int __init set_num_shapers(char *str)
-{
-	shapers = simple_strtol(str, NULL, 0);
-	return 1;
-}
-
-__setup("shapers=", set_num_shapers);
-
-#endif /* MODULE */
-
-static struct net_device **devs;
-
-static unsigned int shapers_registered = 0;
-
-static int __init shaper_init(void)
-{
-	int i;
-	size_t alloc_size;
-	struct net_device *dev;
-	char name[IFNAMSIZ];
-
-	if (shapers < 1)
-		return -ENODEV;
-
-	alloc_size = sizeof(*dev) * shapers;
-	devs = kzalloc(alloc_size, GFP_KERNEL);
-	if (!devs)
-		return -ENOMEM;
-
-	for (i = 0; i < shapers; i++) {
-
-		snprintf(name, IFNAMSIZ, "shaper%d", i);
-		dev = alloc_netdev(sizeof(struct shaper), name,
-				   shaper_setup);
-		if (!dev)
-			break;
-
-		if (register_netdev(dev)) {
-			free_netdev(dev);
-			break;
-		}
-
-		devs[i] = dev;
-		shapers_registered++;
-	}
-
-	if (!shapers_registered) {
-		kfree(devs);
-		devs = NULL;
-	}
-
-	return (shapers_registered ? 0 : -ENODEV);
-}
-
-static void __exit shaper_exit (void)
-{
-	int i;
-
-	for (i = 0; i < shapers_registered; i++) {
-		if (devs[i]) {
-			unregister_netdev(devs[i]);
-			free_netdev(devs[i]);
-		}
-	}
-
-	kfree(devs);
-	devs = NULL;
-}
-
-module_init(shaper_init);
-module_exit(shaper_exit);
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 7eab072ae792..b570402f7fed 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -372,7 +372,7 @@ static void __mdio_cmd(void __iomem *ioaddr, u32 ctl)
 		msleep(1);
 	}
 
-	if (i > 999)
+	if (i > 99)
 		printk(KERN_ERR PFX "PHY command failed !\n");
 }
 
@@ -847,10 +847,8 @@ static void sis190_soft_reset(void __iomem *ioaddr)
 {
 	SIS_W32(IntrControl, 0x8000);
 	SIS_PCI_COMMIT();
-	msleep(1);
 	SIS_W32(IntrControl, 0x0);
 	sis190_asic_down(ioaddr);
-	msleep(1);
 }
 
 static void sis190_hw_start(struct net_device *dev)
@@ -1041,8 +1039,6 @@ static int sis190_open(struct net_device *dev)
 	if (rc < 0)
 		goto err_free_rx_1;
 
-	INIT_WORK(&tp->phy_task, sis190_phy_task);
-
 	sis190_request_timer(dev);
 
 	rc = request_irq(dev->irq, sis190_interrupt, IRQF_SHARED, dev->name, dev);
@@ -1549,28 +1545,31 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
 }
 
 /**
- *	sis190_get_mac_addr_from_apc - Get MAC address for SiS965 model
+ *	sis190_get_mac_addr_from_apc - Get MAC address for SiS96x model
  *	@pdev: PCI device
  *	@dev:  network device to get address for
  *
- *	SiS965 model, use APC CMOS RAM to store MAC address.
+ *	SiS96x model, use APC CMOS RAM to store MAC address.
  *	APC CMOS RAM is accessed through ISA bridge.
  *	MAC address is read into @net_dev->dev_addr.
  */
 static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
 						  struct net_device *dev)
 {
+	static const u16 __devinitdata ids[] = { 0x0965, 0x0966, 0x0968 };
 	struct sis190_private *tp = netdev_priv(dev);
 	struct pci_dev *isa_bridge;
 	u8 reg, tmp8;
-	int i;
+	unsigned int i;
 
 	net_probe(tp, KERN_INFO "%s: Read MAC address from APC.\n",
 		  pci_name(pdev));
 
-	isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0965, NULL);
-	if (!isa_bridge)
-		isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0966, NULL);
+	for (i = 0; i < ARRAY_SIZE(ids); i++) {
+		isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, ids[i], NULL);
+		if (isa_bridge)
+			break;
+	}
 
 	if (!isa_bridge) {
 		net_probe(tp, KERN_INFO "%s: Can not find ISA bridge.\n",
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 0857d2c88aa0..ec95e493ac1c 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -419,7 +419,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
 
 	i = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK);
 	if(i){
-		printk(KERN_ERR "sis900.c: architecture does not support"
+		printk(KERN_ERR "sis900.c: architecture does not support "
 			"32bit PCI busmaster DMA\n");
 		return i;
 	}
@@ -1667,7 +1667,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
 		/* something strange happened !!! */
 		if (status & HIBERR) {
 			if(netif_msg_intr(sis_priv))
-				printk(KERN_INFO "%s: Abnormal interrupt,"
+				printk(KERN_INFO "%s: Abnormal interrupt, "
 					"status %#8.8x.\n", net_dev->name, status);
 			break;
 		}
@@ -1820,7 +1820,7 @@ refill_rx_ring:
 				 * how the hardware will react to this kind
 				 * of degenerated buffer */
 				if (netif_msg_rx_err(sis_priv))
-					printk(KERN_INFO "%s: Memory squeeze,"
+					printk(KERN_INFO "%s: Memory squeeze, "
 						"deferring packet.\n",
 						net_dev->name);
 				net_dev->stats.rx_dropped++;
diff --git a/drivers/net/sk98lin/skgemib.c b/drivers/net/sk98lin/skgemib.c
index 0a6f67a7a395..fde45083eb7b 100644
--- a/drivers/net/sk98lin/skgemib.c
+++ b/drivers/net/sk98lin/skgemib.c
@@ -82,7 +82,7 @@ PNMI_STATIC int DiagActions(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
 
 
 /* defines *******************************************************************/
-#define ID_TABLE_SIZE (sizeof(IdTable)/sizeof(IdTable[0]))
+#define ID_TABLE_SIZE	ARRAY_SIZE(IdTable)
 
 
 /* global variables **********************************************************/
diff --git a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c
index b36dd9ac6b29..876bb2158fa6 100644
--- a/drivers/net/sk98lin/skgepnmi.c
+++ b/drivers/net/sk98lin/skgepnmi.c
@@ -383,23 +383,11 @@ int Level)		/* Initialization level */
 			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR049, SK_PNMI_ERR049MSG);
 
 			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
-					   ("CounterOffset struct size (%d) differs from"
+					   ("CounterOffset struct size (%d) differs from "
 						"SK_PNMI_MAX_IDX (%d)\n",
 						SK_PNMI_CNT_NO, SK_PNMI_MAX_IDX));
 		}
 
-		if (SK_PNMI_MAX_IDX !=
-			(sizeof(StatAddr) / (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES))) {
-			
-			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR050, SK_PNMI_ERR050MSG);
-
-			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
-					   ("StatAddr table size (%d) differs from "
-						"SK_PNMI_MAX_IDX (%d)\n",
-						(sizeof(StatAddr) /
-						 (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES)),
-						 SK_PNMI_MAX_IDX));
-		}
 #endif /* SK_PNMI_CHECK */
 		break;
 
diff --git a/drivers/net/sk98lin/skgesirq.c b/drivers/net/sk98lin/skgesirq.c
index 3e7aa49afd00..e5ee6d63ba4e 100644
--- a/drivers/net/sk98lin/skgesirq.c
+++ b/drivers/net/sk98lin/skgesirq.c
@@ -892,7 +892,7 @@ int		Port)		/* Which port should be checked */
 	 */
 	RxCts = 0;
 
-	for (i = 0; i < sizeof(SkGeRxRegs)/sizeof(SkGeRxRegs[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(SkGeRxRegs); i++) {
 		
 		(void)SkXmMacStatistic(pAC, IoC, Port, SkGeRxRegs[i], &RxTmp);
 		
diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c
index 438f424e6361..8a430a366547 100644
--- a/drivers/net/skfp/hwmtm.c
+++ b/drivers/net/skfp/hwmtm.c
@@ -1746,7 +1746,7 @@ static void queue_llc_rx(struct s_smc *smc, SMbuf *mb)
 	DB_GEN("queue_llc_rx: mb = %x",(void *)mb,0,4) ;
 	smc->os.hwm.queued_rx_frames++ ;
 	mb->sm_next = (SMbuf *)NULL ;
-	if (smc->os.hwm.llc_rx_pipe == 0) {
+	if (smc->os.hwm.llc_rx_pipe == NULL) {
 		smc->os.hwm.llc_rx_pipe = mb ;
 	}
 	else {
@@ -1786,7 +1786,7 @@ static void queue_txd_mb(struct s_smc *smc, SMbuf *mb)
 	DB_GEN("_rx: queue_txd_mb = %x",(void *)mb,0,4) ;
 	smc->os.hwm.queued_txd_mb++ ;
 	mb->sm_next = (SMbuf *)NULL ;
-	if (smc->os.hwm.txd_tx_pipe == 0) {
+	if (smc->os.hwm.txd_tx_pipe == NULL) {
 		smc->os.hwm.txd_tx_pipe = mb ;
 	}
 	else {
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index ced2c8f76be7..ffbfb1b79f97 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -712,7 +712,7 @@ void smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs)
 			smc->mib.priv.fddiPRIVECF_Reply_Rx++ ;
 			DB_SMT("SMT: received ECF reply from %s\n",
 				addr_to_string(&sm->smt_source),0) ;
-			if (sm_to_para(smc,sm,SMT_P_ECHODATA) == 0) {
+			if (sm_to_para(smc,sm,SMT_P_ECHODATA) == NULL) {
 				DB_SMT("SMT: ECHODATA missing\n",0,0) ;
 				break ;
 			}
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index bc15940ce1bc..626190eb91e7 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -51,7 +51,7 @@
 #include "sky2.h"
 
 #define DRV_NAME		"sky2"
-#define DRV_VERSION		"1.20"
+#define DRV_VERSION		"1.21"
 #define PFX			DRV_NAME " "
 
 /*
@@ -64,7 +64,6 @@
 #define RX_LE_BYTES		(RX_LE_SIZE*sizeof(struct sky2_rx_le))
 #define RX_MAX_PENDING		(RX_LE_SIZE/6 - 2)
 #define RX_DEF_PENDING		RX_MAX_PENDING
-#define RX_SKB_ALIGN		8
 
 #define TX_RING_SIZE		512
 #define TX_DEF_PENDING		(TX_RING_SIZE - 1)
@@ -135,6 +134,8 @@ static const struct pci_device_id sky2_id_table[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436C) }, /* 88E8072 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436D) }, /* 88E8055 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4370) }, /* 88E8075 */
 	{ 0 }
 };
 
@@ -548,6 +549,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
 
 	case CHIP_ID_YUKON_EC_U:
 	case CHIP_ID_YUKON_EX:
+	case CHIP_ID_YUKON_SUPR:
 		pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
 
 		/* select page 3 to access LED control register */
@@ -714,23 +716,33 @@ static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
 {
 	struct net_device *dev = hw->dev[port];
 
-	if (dev->mtu <= ETH_DATA_LEN)
-		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-			     TX_JUMBO_DIS | TX_STFW_ENA);
+	if ( (hw->chip_id == CHIP_ID_YUKON_EX &&
+	      hw->chip_rev != CHIP_REV_YU_EX_A0) ||
+	     hw->chip_id == CHIP_ID_YUKON_FE_P ||
+	     hw->chip_id == CHIP_ID_YUKON_SUPR) {
+		/* Yukon-Extreme B0 and further Extreme devices */
+		/* enable Store & Forward mode for TX */
 
-	else if (hw->chip_id != CHIP_ID_YUKON_EC_U)
-		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-			     TX_STFW_ENA | TX_JUMBO_ENA);
-	else {
-		/* set Tx GMAC FIFO Almost Empty Threshold */
-		sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
-			     (ECU_JUMBO_WM << 16) | ECU_AE_THR);
+		if (dev->mtu <= ETH_DATA_LEN)
+			sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+				     TX_JUMBO_DIS | TX_STFW_ENA);
 
-		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-			     TX_JUMBO_ENA | TX_STFW_DIS);
+		else
+			sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+				     TX_JUMBO_ENA| TX_STFW_ENA);
+	} else {
+		if (dev->mtu <= ETH_DATA_LEN)
+			sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA);
+		else {
+			/* set Tx GMAC FIFO Almost Empty Threshold */
+			sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
+				     (ECU_JUMBO_WM << 16) | ECU_AE_THR);
 
-		/* Can't do offload because of lack of store/forward */
-		dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM);
+			sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS);
+
+			/* Can't do offload because of lack of store/forward */
+			dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM);
+		}
 	}
 }
 
@@ -1174,24 +1186,32 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp
 /*
  * Allocate an skb for receiving. If the MTU is large enough
  * make the skb non-linear with a fragment list of pages.
- *
- * It appears the hardware has a bug in the FIFO logic that
- * cause it to hang if the FIFO gets overrun and the receive buffer
- * is not 64 byte aligned. The buffer returned from netdev_alloc_skb is
- * aligned except if slab debugging is enabled.
  */
 static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2)
 {
 	struct sk_buff *skb;
-	unsigned long p;
 	int i;
 
-	skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + RX_SKB_ALIGN);
-	if (!skb)
-		goto nomem;
-
-	p = (unsigned long) skb->data;
-	skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p);
+	if (sky2->hw->flags & SKY2_HW_FIFO_HANG_CHECK) {
+		unsigned char *start;
+		/*
+		 * Workaround for a bug in FIFO that cause hang
+		 * if the FIFO if the receive buffer is not 64 byte aligned.
+		 * The buffer returned from netdev_alloc_skb is
+		 * aligned except if slab debugging is enabled.
+		 */
+		skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + 8);
+		if (!skb)
+			goto nomem;
+		start = PTR_ALIGN(skb->data, 8);
+		skb_reserve(skb, start - skb->data);
+	} else {
+		skb = netdev_alloc_skb(sky2->netdev,
+				       sky2->rx_data_size + NET_IP_ALIGN);
+		if (!skb)
+			goto nomem;
+		skb_reserve(skb, NET_IP_ALIGN);
+	}
 
 	for (i = 0; i < sky2->rx_nfrags; i++) {
 		struct page *page = alloc_page(GFP_ATOMIC);
@@ -1227,7 +1247,7 @@ static int sky2_rx_start(struct sky2_port *sky2)
 	struct sky2_hw *hw = sky2->hw;
 	struct rx_ring_info *re;
 	unsigned rxq = rxqaddr[sky2->port];
-	unsigned i, size, space, thresh;
+	unsigned i, size, thresh;
 
 	sky2->rx_put = sky2->rx_next = 0;
 	sky2_qset(hw, rxq);
@@ -1254,28 +1274,18 @@ static int sky2_rx_start(struct sky2_port *sky2)
 	/* Stopping point for hardware truncation */
 	thresh = (size - 8) / sizeof(u32);
 
-	/* Account for overhead of skb - to avoid order > 0 allocation */
-	space = SKB_DATA_ALIGN(size) + NET_SKB_PAD
-		+ sizeof(struct skb_shared_info);
-
-	sky2->rx_nfrags = space >> PAGE_SHIFT;
+	sky2->rx_nfrags = size >> PAGE_SHIFT;
 	BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr));
 
-	if (sky2->rx_nfrags != 0) {
-		/* Compute residue after pages */
-		space = sky2->rx_nfrags << PAGE_SHIFT;
+	/* Compute residue after pages */
+	size -= sky2->rx_nfrags << PAGE_SHIFT;
 
-		if (space < size)
-			size -= space;
-		else
-			size = 0;
+	/* Optimize to handle small packets and headers */
+	if (size < copybreak)
+		size = copybreak;
+	if (size < ETH_HLEN)
+		size = ETH_HLEN;
 
-		/* Optimize to handle small packets and headers */
-		if (size < copybreak)
-			size = copybreak;
-		if (size < ETH_HLEN)
-			size = ETH_HLEN;
-	}
 	sky2->rx_data_size = size;
 
 	/* Fill Rx ring */
@@ -2663,6 +2673,7 @@ static u32 sky2_mhz(const struct sky2_hw *hw)
 	case CHIP_ID_YUKON_EC:
 	case CHIP_ID_YUKON_EC_U:
 	case CHIP_ID_YUKON_EX:
+	case CHIP_ID_YUKON_SUPR:
 		return 125;
 
 	case CHIP_ID_YUKON_FE:
@@ -2746,6 +2757,15 @@ static int __devinit sky2_init(struct sky2_hw *hw)
 			| SKY2_HW_AUTO_TX_SUM
 			| SKY2_HW_ADV_POWER_CTL;
 		break;
+
+	case CHIP_ID_YUKON_SUPR:
+		hw->flags = SKY2_HW_GIGABIT
+			| SKY2_HW_NEWER_PHY
+			| SKY2_HW_NEW_LE
+			| SKY2_HW_AUTO_TX_SUM
+			| SKY2_HW_ADV_POWER_CTL;
+		break;
+
 	default:
 		dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
 			hw->chip_id);
@@ -2816,7 +2836,8 @@ static void sky2_reset(struct sky2_hw *hw)
 		sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
 		sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
 
-		if (hw->chip_id == CHIP_ID_YUKON_EX)
+		if (hw->chip_id == CHIP_ID_YUKON_EX ||
+		    hw->chip_id == CHIP_ID_YUKON_SUPR)
 			sky2_write16(hw, SK_REG(i, GMAC_CTRL),
 				     GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON
 				     | GMC_BYP_RETR_ON);
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index ffe9b8a50a1b..2bced1a0898f 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -425,12 +425,13 @@ enum {
 
 /*	B2_CHIP_ID		 8 bit 	Chip Identification Number */
 enum {
-	CHIP_ID_YUKON_XL   = 0xb3, /* Chip ID for YUKON-2 XL */
-	CHIP_ID_YUKON_EC_U = 0xb4, /* Chip ID for YUKON-2 EC Ultra */
-	CHIP_ID_YUKON_EX   = 0xb5, /* Chip ID for YUKON-2 Extreme */
-	CHIP_ID_YUKON_EC   = 0xb6, /* Chip ID for YUKON-2 EC */
- 	CHIP_ID_YUKON_FE   = 0xb7, /* Chip ID for YUKON-2 FE */
- 	CHIP_ID_YUKON_FE_P = 0xb8, /* Chip ID for YUKON-2 FE+ */
+	CHIP_ID_YUKON_XL   = 0xb3, /* YUKON-2 XL */
+	CHIP_ID_YUKON_EC_U = 0xb4, /* YUKON-2 EC Ultra */
+	CHIP_ID_YUKON_EX   = 0xb5, /* YUKON-2 Extreme */
+	CHIP_ID_YUKON_EC   = 0xb6, /* YUKON-2 EC */
+ 	CHIP_ID_YUKON_FE   = 0xb7, /* YUKON-2 FE */
+ 	CHIP_ID_YUKON_FE_P = 0xb8, /* YUKON-2 FE+ */
+	CHIP_ID_YUKON_SUPR = 0xb9, /* YUKON-2 Supreme */
 };
 enum yukon_ec_rev {
 	CHIP_REV_YU_EC_A1    = 0,  /* Chip Rev. for Yukon-EC A1/A0 */
diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c
index 0adab709ab68..d640c0f5470b 100644
--- a/drivers/net/slhc.c
+++ b/drivers/net/slhc.c
@@ -174,7 +174,7 @@ put16(unsigned char *cp, unsigned short x)
 
 
 /* Encode a number */
-unsigned char *
+static unsigned char *
 encode(unsigned char *cp, unsigned short n)
 {
 	if(n >= 256 || n == 0){
@@ -199,7 +199,7 @@ pull16(unsigned char **cpp)
 }
 
 /* Decode a number */
-long
+static long
 decode(unsigned char **cpp)
 {
 	register int x;
@@ -233,6 +233,7 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
 	register unsigned char *cp = new_seq;
 	struct iphdr *ip;
 	struct tcphdr *th, *oth;
+	__sum16 csum;
 
 
 	/*
@@ -428,7 +429,7 @@ found:
 	/* Grab the cksum before we overwrite it below.  Then update our
 	 * state with this packet's header.
 	 */
-	deltaA = ntohs(th->check);
+	csum = th->check;
 	memcpy(&cs->cs_ip,ip,20);
 	memcpy(&cs->cs_tcp,th,20);
 	/* We want to use the original packet as our compressed packet.
@@ -449,7 +450,8 @@ found:
 		*cpp = ocp;
 		*cp++ = changes;
 	}
-	cp = put16(cp,(short)deltaA);	/* Write TCP checksum */
+	*(__sum16 *)cp = csum;
+	cp += 2;
 /* deltaS is now the size of the change section of the compressed header */
 	memcpy(cp,new_seq,deltaS);	/* Write list of deltas */
 	memcpy(cp+deltaS,icp+hlen,isize-hlen);
@@ -519,10 +521,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
 	thp = &cs->cs_tcp;
 	ip = &cs->cs_ip;
 
-	if((x = pull16(&cp)) == -1) {	/* Read the TCP checksum */
-		goto bad;
-        }
-	thp->check = htons(x);
+	thp->check = *(__sum16 *)cp;
+	cp += 2;
 
 	thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
 /*
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 251a3ce376ac..5a55ede352f4 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -11,9 +11,11 @@
  * Fixes:
  *		Alan Cox	: 	Sanity checks and avoid tx overruns.
  *					Has a new sl->mtu field.
- *		Alan Cox	: 	Found cause of overrun. ifconfig sl0 mtu upwards.
- *					Driver now spots this and grows/shrinks its buffers(hack!).
- *					Memory leak if you run out of memory setting up a slip driver fixed.
+ *		Alan Cox	: 	Found cause of overrun. ifconfig sl0
+ *					mtu upwards. Driver now spots this
+ *					and grows/shrinks its buffers(hack!).
+ *					Memory leak if you run out of memory
+ *					setting up a slip driver fixed.
  *		Matt Dillon	:	Printable slip (borrowed from NET2E)
  *	Pauline Middelink	:	Slip driver fixes.
  *		Alan Cox	:	Honours the old SL_COMPRESSED flag
@@ -29,7 +31,8 @@
  *                                      buffering from 4096 to 256 bytes.
  *                                      Improving SLIP response time.
  *                                      CONFIG_SLIP_MODE_SLIP6.
- *                                      ifconfig sl? up & down now works correctly.
+ *                                      ifconfig sl? up & down now works
+ *					correctly.
  *					Modularization.
  *              Alan Cox        :       Oops - fix AX.25 buffer lengths
  *      Dmitry Gorodchanin      :       Even more cleanups. Preserve CSLIP
@@ -43,15 +46,18 @@
  *					device entries, just reg./unreg. them
  *					as they are needed.  We kfree() them
  *					at module cleanup.
- *					With MODULE-loading ``insmod'', user can
- *					issue parameter:   slip_maxdev=1024
- *					(Or how much he/she wants.. Default is 256)
- * *	Stanislav Voronyi	:	Slip line checking, with ideas taken
- *					from multislip BSDI driver which was written
- *					by Igor Chechik, RELCOM Corp. Only algorithms
- * 					have been ported to Linux SLIP driver.
+ *					With MODULE-loading ``insmod'', user
+ *					can issue parameter:  slip_maxdev=1024
+ *					(Or how much he/she wants.. Default
+ *					is 256)
+ *	Stanislav Voronyi	:	Slip line checking, with ideas taken
+ *					from multislip BSDI driver which was
+ *					written by Igor Chechik, RELCOM Corp.
+ *					Only algorithms have been ported to
+ *					Linux SLIP driver.
  *	Vitaly E. Lavrov	:	Sane behaviour on tty hangup.
- *	Alexey Kuznetsov	:	Cleanup interfaces to tty&netdevice modules.
+ *	Alexey Kuznetsov	:	Cleanup interfaces to tty & netdevice
+ *					modules.
  */
 
 #define SL_CHECK_TRANSMIT
@@ -99,7 +105,7 @@ static void slip_unesc6(struct slip *sl, unsigned char c);
 #ifdef CONFIG_SLIP_SMART
 static void sl_keepalive(unsigned long sls);
 static void sl_outfill(unsigned long sls);
-static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd);
+static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 #endif
 
 /********************************
@@ -117,15 +123,14 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd);
    Allocate channel buffers.
  */
 
-static int
-sl_alloc_bufs(struct slip *sl, int mtu)
+static int sl_alloc_bufs(struct slip *sl, int mtu)
 {
 	int err = -ENOBUFS;
 	unsigned long len;
-	char * rbuff = NULL;
-	char * xbuff = NULL;
+	char *rbuff = NULL;
+	char *xbuff = NULL;
 #ifdef SL_INCLUDE_CSLIP
-	char * cbuff = NULL;
+	char *cbuff = NULL;
 	struct slcompress *slcomp = NULL;
 #endif
 
@@ -195,8 +200,7 @@ err_exit:
 }
 
 /* Free a SLIP channel buffers. */
-static void
-sl_free_bufs(struct slip *sl)
+static void sl_free_bufs(struct slip *sl)
 {
 	/* Free all SLIP frame buffers. */
 	kfree(xchg(&sl->rbuff, NULL));
@@ -248,7 +252,6 @@ static int sl_realloc_bufs(struct slip *sl, int mtu)
 		}
 		goto done;
 	}
-
 	spin_lock_bh(&sl->lock);
 
 	err = -ENODEV;
@@ -298,23 +301,20 @@ done:
 
 
 /* Set the "sending" flag.  This must be atomic hence the set_bit. */
-static inline void
-sl_lock(struct slip *sl)
+static inline void sl_lock(struct slip *sl)
 {
 	netif_stop_queue(sl->dev);
 }
 
 
 /* Clear the "sending" flag.  This must be atomic, hence the ASM. */
-static inline void
-sl_unlock(struct slip *sl)
+static inline void sl_unlock(struct slip *sl)
 {
 	netif_wake_queue(sl->dev);
 }
 
 /* Send one completely decapsulated IP datagram to the IP layer. */
-static void
-sl_bump(struct slip *sl)
+static void sl_bump(struct slip *sl)
 {
 	struct sk_buff *skb;
 	int count;
@@ -322,22 +322,22 @@ sl_bump(struct slip *sl)
 	count = sl->rcount;
 #ifdef SL_INCLUDE_CSLIP
 	if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) {
-		unsigned char c;
-		if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) {
+		unsigned char c = sl->rbuff[0];
+		if (c & SL_TYPE_COMPRESSED_TCP) {
 			/* ignore compressed packets when CSLIP is off */
 			if (!(sl->mode & SL_MODE_CSLIP)) {
 				printk(KERN_WARNING "%s: compressed packet ignored\n", sl->dev->name);
 				return;
 			}
-			/* make sure we've reserved enough space for uncompress to use */
+			/* make sure we've reserved enough space for uncompress
+			   to use */
 			if (count + 80 > sl->buffsize) {
 				sl->rx_over_errors++;
 				return;
 			}
 			count = slhc_uncompress(sl->slcomp, sl->rbuff, count);
-			if (count <= 0) {
+			if (count <= 0)
 				return;
-			}
 		} else if (c >= SL_TYPE_UNCOMPRESSED_TCP) {
 			if (!(sl->mode & SL_MODE_CSLIP)) {
 				/* turn on header compression */
@@ -346,33 +346,31 @@ sl_bump(struct slip *sl)
 				printk(KERN_INFO "%s: header compression turned on\n", sl->dev->name);
 			}
 			sl->rbuff[0] &= 0x4f;
-			if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) {
+			if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0)
 				return;
-			}
 		}
 	}
 #endif  /* SL_INCLUDE_CSLIP */
 
-	sl->rx_bytes+=count;
+	sl->rx_bytes += count;
 
 	skb = dev_alloc_skb(count);
-	if (skb == NULL)  {
+	if (skb == NULL) {
 		printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", sl->dev->name);
 		sl->rx_dropped++;
 		return;
 	}
 	skb->dev = sl->dev;
-	memcpy(skb_put(skb,count), sl->rbuff, count);
+	memcpy(skb_put(skb, count), sl->rbuff, count);
 	skb_reset_mac_header(skb);
-	skb->protocol=htons(ETH_P_IP);
+	skb->protocol = htons(ETH_P_IP);
 	netif_rx(skb);
 	sl->dev->last_rx = jiffies;
 	sl->rx_packets++;
 }
 
 /* Encapsulate one IP datagram and stuff into a TTY queue. */
-static void
-sl_encaps(struct slip *sl, unsigned char *icp, int len)
+static void sl_encaps(struct slip *sl, unsigned char *icp, int len)
 {
 	unsigned char *p;
 	int actual, count;
@@ -386,12 +384,11 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len)
 
 	p = icp;
 #ifdef SL_INCLUDE_CSLIP
-	if (sl->mode & SL_MODE_CSLIP)  {
+	if (sl->mode & SL_MODE_CSLIP)
 		len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1);
-	}
 #endif
 #ifdef CONFIG_SLIP_MODE_SLIP6
-	if(sl->mode & SL_MODE_SLIP6)
+	if (sl->mode & SL_MODE_SLIP6)
 		count = slip_esc6(p, (unsigned char *) sl->xbuff, len);
 	else
 #endif
@@ -425,12 +422,12 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len)
 static void slip_write_wakeup(struct tty_struct *tty)
 {
 	int actual;
-	struct slip *sl = (struct slip *) tty->disc_data;
+	struct slip *sl = tty->disc_data;
 
 	/* First make sure we're connected. */
-	if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) {
+	if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
 		return;
-	}
+
 	if (sl->xleft <= 0)  {
 		/* Now serial buffer is almost free & we can start
 		 * transmission of another packet */
@@ -463,15 +460,15 @@ static void sl_tx_timeout(struct net_device *dev)
 			/* 20 sec timeout not reached */
 			goto out;
 		}
-		printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
-		       (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ?
-		       "bad line quality" : "driver error");
+		printk(KERN_WARNING "%s: transmit timed out, %s?\n",
+			dev->name,
+			(sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ?
+				"bad line quality" : "driver error");
 		sl->xleft = 0;
 		sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 		sl_unlock(sl);
 #endif
 	}
-
 out:
 	spin_unlock(&sl->lock);
 }
@@ -484,7 +481,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
 	struct slip *sl = netdev_priv(dev);
 
 	spin_lock(&sl->lock);
-	if (!netif_running(dev))  {
+	if (!netif_running(dev)) {
 		spin_unlock(&sl->lock);
 		printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name);
 		dev_kfree_skb(skb);
@@ -497,7 +494,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	sl_lock(sl);
-	sl->tx_bytes+=skb->len;
+	sl->tx_bytes += skb->len;
 	sl_encaps(sl, skb->data, skb->len);
 	spin_unlock(&sl->lock);
 
@@ -536,7 +533,7 @@ static int sl_open(struct net_device *dev)
 {
 	struct slip *sl = netdev_priv(dev);
 
-	if (sl->tty==NULL)
+	if (sl->tty == NULL)
 		return -ENODEV;
 
 	sl->flags &= (1 << SLF_INUSE);
@@ -657,20 +654,19 @@ static void sl_setup(struct net_device *dev)
  * in parallel
  */
 
-static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+							char *fp, int count)
 {
-	struct slip *sl = (struct slip *) tty->disc_data;
+	struct slip *sl = tty->disc_data;
 
-	if (!sl || sl->magic != SLIP_MAGIC ||
-	    !netif_running(sl->dev))
+	if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
 		return;
 
 	/* Read the characters out of the buffer */
 	while (count--) {
 		if (fp && *fp++) {
-			if (!test_and_set_bit(SLF_ERROR, &sl->flags))  {
+			if (!test_and_set_bit(SLF_ERROR, &sl->flags))
 				sl->rx_errors++;
-			}
 			cp++;
 			continue;
 		}
@@ -688,7 +684,6 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch
  ************************************/
 
 /* Collect hanged up channels */
-
 static void sl_sync(void)
 {
 	int i;
@@ -696,21 +691,21 @@ static void sl_sync(void)
 	struct slip	  *sl;
 
 	for (i = 0; i < slip_maxdev; i++) {
-		if ((dev = slip_devs[i]) == NULL)
+		dev = slip_devs[i];
+		if (dev == NULL)
 			break;
 
 		sl = netdev_priv(dev);
 		if (sl->tty || sl->leased)
 			continue;
-		if (dev->flags&IFF_UP)
+		if (dev->flags & IFF_UP)
 			dev_close(dev);
 	}
 }
 
 
 /* Find a free SLIP channel, and link in this `tty' line. */
-static struct slip *
-sl_alloc(dev_t line)
+static struct slip *sl_alloc(dev_t line)
 {
 	int i;
 	int sel = -1;
@@ -805,15 +800,15 @@ sl_alloc(dev_t line)
 	spin_lock_init(&sl->lock);
 	sl->mode        = SL_MODE_DEFAULT;
 #ifdef CONFIG_SLIP_SMART
-	init_timer(&sl->keepalive_timer);	/* initialize timer_list struct */
-	sl->keepalive_timer.data=(unsigned long)sl;
-	sl->keepalive_timer.function=sl_keepalive;
+	/* initialize timer_list struct */
+	init_timer(&sl->keepalive_timer);
+	sl->keepalive_timer.data = (unsigned long)sl;
+	sl->keepalive_timer.function = sl_keepalive;
 	init_timer(&sl->outfill_timer);
-	sl->outfill_timer.data=(unsigned long)sl;
-	sl->outfill_timer.function=sl_outfill;
+	sl->outfill_timer.data = (unsigned long)sl;
+	sl->outfill_timer.function = sl_outfill;
 #endif
 	slip_devs[i] = dev;
-
 	return sl;
 }
 
@@ -832,7 +827,7 @@ static int slip_open(struct tty_struct *tty)
 	struct slip *sl;
 	int err;
 
-	if(!capable(CAP_NET_ADMIN))
+	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
 	/* RTnetlink lock is misused here to serialize concurrent
@@ -844,7 +839,7 @@ static int slip_open(struct tty_struct *tty)
 	/* Collect hanged up channels. */
 	sl_sync();
 
-	sl = (struct slip *) tty->disc_data;
+	sl = tty->disc_data;
 
 	err = -EEXIST;
 	/* First make sure we're not already connected. */
@@ -853,7 +848,8 @@ static int slip_open(struct tty_struct *tty)
 
 	/* OK.  Find a free SLIP channel to use. */
 	err = -ENFILE;
-	if ((sl = sl_alloc(tty_devnum(tty))) == NULL)
+	sl = sl_alloc(tty_devnum(tty));
+	if (sl == NULL)
 		goto err_exit;
 
 	sl->tty = tty;
@@ -863,23 +859,25 @@ static int slip_open(struct tty_struct *tty)
 
 	if (!test_bit(SLF_INUSE, &sl->flags)) {
 		/* Perform the low-level SLIP initialization. */
-		if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0)
+		err = sl_alloc_bufs(sl, SL_MTU);
+		if (err)
 			goto err_free_chan;
 
 		set_bit(SLF_INUSE, &sl->flags);
 
-		if ((err = register_netdevice(sl->dev)))
+		err = register_netdevice(sl->dev);
+		if (err)
 			goto err_free_bufs;
 	}
 
 #ifdef CONFIG_SLIP_SMART
 	if (sl->keepalive) {
-		sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ;
-		add_timer (&sl->keepalive_timer);
+		sl->keepalive_timer.expires = jiffies + sl->keepalive * HZ;
+		add_timer(&sl->keepalive_timer);
 	}
 	if (sl->outfill) {
-		sl->outfill_timer.expires=jiffies+sl->outfill*HZ;
-		add_timer (&sl->outfill_timer);
+		sl->outfill_timer.expires = jiffies + sl->outfill * HZ;
+		add_timer(&sl->outfill_timer);
 	}
 #endif
 
@@ -928,10 +926,9 @@ err_exit:
  * This means flushing out any pending queues, and then returning. This
  * call is serialized against other ldisc functions.
  */
-static void
-slip_close(struct tty_struct *tty)
+static void slip_close(struct tty_struct *tty)
 {
-	struct slip *sl = (struct slip *) tty->disc_data;
+	struct slip *sl = tty->disc_data;
 
 	/* First make sure we're connected. */
 	if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty)
@@ -955,8 +952,7 @@ slip_close(struct tty_struct *tty)
   *			STANDARD SLIP ENCAPSULATION		  	 *
   ************************************************************************/
 
-static int
-slip_esc(unsigned char *s, unsigned char *d, int len)
+static int slip_esc(unsigned char *s, unsigned char *d, int len)
 {
 	unsigned char *ptr = d;
 	unsigned char c;
@@ -975,16 +971,16 @@ slip_esc(unsigned char *s, unsigned char *d, int len)
 	 */
 
 	while (len-- > 0) {
-		switch(c = *s++) {
-		 case END:
+		switch (c = *s++) {
+		case END:
 			*ptr++ = ESC;
 			*ptr++ = ESC_END;
 			break;
-		 case ESC:
+		case ESC:
 			*ptr++ = ESC;
 			*ptr++ = ESC_ESC;
 			break;
-		 default:
+		default:
 			*ptr++ = c;
 			break;
 		}
@@ -996,33 +992,31 @@ slip_esc(unsigned char *s, unsigned char *d, int len)
 static void slip_unesc(struct slip *sl, unsigned char s)
 {
 
-	switch(s) {
-	 case END:
+	switch (s) {
+	case END:
 #ifdef CONFIG_SLIP_SMART
 		/* drop keeptest bit = VSV */
 		if (test_bit(SLF_KEEPTEST, &sl->flags))
 			clear_bit(SLF_KEEPTEST, &sl->flags);
 #endif
 
-		if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {
+		if (!test_and_clear_bit(SLF_ERROR, &sl->flags)
+							&& (sl->rcount > 2))
 			sl_bump(sl);
-		}
 		clear_bit(SLF_ESCAPE, &sl->flags);
 		sl->rcount = 0;
 		return;
 
-	 case ESC:
+	case ESC:
 		set_bit(SLF_ESCAPE, &sl->flags);
 		return;
-	 case ESC_ESC:
-		if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))  {
+	case ESC_ESC:
+		if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
 			s = ESC;
-		}
 		break;
-	 case ESC_END:
-		if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))  {
+	case ESC_END:
+		if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
 			s = END;
-		}
 		break;
 	}
 	if (!test_bit(SLF_ERROR, &sl->flags))  {
@@ -1041,8 +1035,7 @@ static void slip_unesc(struct slip *sl, unsigned char s)
  *			 6 BIT SLIP ENCAPSULATION			*
  ************************************************************************/
 
-int
-slip_esc6(unsigned char *s, unsigned char *d, int len)
+static int slip_esc6(unsigned char *s, unsigned char *d, int len)
 {
 	unsigned char *ptr = d;
 	unsigned char c;
@@ -1079,8 +1072,7 @@ slip_esc6(unsigned char *s, unsigned char *d, int len)
 	return ptr - d;
 }
 
-void
-slip_unesc6(struct slip *sl, unsigned char s)
+static void slip_unesc6(struct slip *sl, unsigned char s)
 {
 	unsigned char c;
 
@@ -1091,13 +1083,13 @@ slip_unesc6(struct slip *sl, unsigned char s)
 			clear_bit(SLF_KEEPTEST, &sl->flags);
 #endif
 
-		if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))  {
+		if (!test_and_clear_bit(SLF_ERROR, &sl->flags)
+							&& (sl->rcount > 2))
 			sl_bump(sl);
-		}
 		sl->rcount = 0;
 		sl->xbits = 0;
 		sl->xdata = 0;
- 	} else if (s >= 0x30 && s < 0x70) {
+	} else if (s >= 0x30 && s < 0x70) {
 		sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F);
 		sl->xbits += 6;
 		if (sl->xbits >= 8) {
@@ -1112,24 +1104,24 @@ slip_unesc6(struct slip *sl, unsigned char s)
 				set_bit(SLF_ERROR, &sl->flags);
 			}
 		}
- 	}
+	}
 }
 #endif /* CONFIG_SLIP_MODE_SLIP6 */
 
 /* Perform I/O control on an active SLIP channel. */
-static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+static int slip_ioctl(struct tty_struct *tty, struct file *file,
+					unsigned int cmd, unsigned long arg)
 {
-	struct slip *sl = (struct slip *) tty->disc_data;
+	struct slip *sl = tty->disc_data;
 	unsigned int tmp;
 	int __user *p = (int __user *)arg;
 
 	/* First make sure we're connected. */
-	if (!sl || sl->magic != SLIP_MAGIC) {
+	if (!sl || sl->magic != SLIP_MAGIC)
 		return -EINVAL;
-	}
 
-	switch(cmd) {
-	 case SIOCGIFNAME:
+	switch (cmd) {
+	case SIOCGIFNAME:
 		tmp = strlen(sl->dev->name) + 1;
 		if (copy_to_user((void __user *)arg, sl->dev->name, tmp))
 			return -EFAULT;
@@ -1144,34 +1136,31 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
 		if (get_user(tmp, p))
 			return -EFAULT;
 #ifndef SL_INCLUDE_CSLIP
-		if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE))  {
+		if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE))
 			return -EINVAL;
-		}
 #else
 		if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) ==
-		    (SL_MODE_ADAPTIVE | SL_MODE_CSLIP))  {
+		    (SL_MODE_ADAPTIVE | SL_MODE_CSLIP))
 			/* return -EINVAL; */
 			tmp &= ~SL_MODE_ADAPTIVE;
-		}
 #endif
 #ifndef CONFIG_SLIP_MODE_SLIP6
-		if (tmp & SL_MODE_SLIP6)  {
+		if (tmp & SL_MODE_SLIP6)
 			return -EINVAL;
-		}
 #endif
 		sl->mode = tmp;
-		sl->dev->type = ARPHRD_SLIP+sl->mode;
+		sl->dev->type = ARPHRD_SLIP + sl->mode;
 		return 0;
 
-	 case SIOCSIFHWADDR:
+	case SIOCSIFHWADDR:
 		return -EINVAL;
 
 #ifdef CONFIG_SLIP_SMART
 	/* VSV changes start here */
-        case SIOCSKEEPALIVE:
+	case SIOCSKEEPALIVE:
 		if (get_user(tmp, p))
 			return -EFAULT;
-                if (tmp > 255) /* max for unchar */
+		if (tmp > 255) /* max for unchar */
 			return -EINVAL;
 
 		spin_lock_bh(&sl->lock);
@@ -1179,40 +1168,42 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
 			spin_unlock_bh(&sl->lock);
 			return -ENODEV;
 		}
-		if ((sl->keepalive = (unchar) tmp) != 0) {
-			mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ);
+		sl->keepalive = (u8)tmp;
+		if (sl->keepalive != 0) {
+			mod_timer(&sl->keepalive_timer,
+					jiffies + sl->keepalive * HZ);
 			set_bit(SLF_KEEPTEST, &sl->flags);
-                } else {
-                        del_timer (&sl->keepalive_timer);
-		}
+		} else
+			del_timer(&sl->keepalive_timer);
 		spin_unlock_bh(&sl->lock);
 		return 0;
 
-        case SIOCGKEEPALIVE:
+	case SIOCGKEEPALIVE:
 		if (put_user(sl->keepalive, p))
 			return -EFAULT;
 		return 0;
 
-        case SIOCSOUTFILL:
+	case SIOCSOUTFILL:
 		if (get_user(tmp, p))
 			return -EFAULT;
-                if (tmp > 255) /* max for unchar */
+		if (tmp > 255) /* max for unchar */
 			return -EINVAL;
 		spin_lock_bh(&sl->lock);
 		if (!sl->tty) {
 			spin_unlock_bh(&sl->lock);
 			return -ENODEV;
 		}
-                if ((sl->outfill = (unchar) tmp) != 0){
-			mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ);
+		sl->outfill = (u8)tmp;
+		if (sl->outfill != 0) {
+			mod_timer(&sl->outfill_timer,
+						jiffies + sl->outfill * HZ);
 			set_bit(SLF_OUTWAIT, &sl->flags);
-		} else {
-                        del_timer (&sl->outfill_timer);
-		}
+		} else
+			del_timer(&sl->outfill_timer);
 		spin_unlock_bh(&sl->lock);
-                return 0;
+		return 0;
 
-        case SIOCGOUTFILL:
+	case SIOCGOUTFILL:
 		if (put_user(sl->outfill, p))
 			return -EFAULT;
 		return 0;
@@ -1229,7 +1220,7 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
    to allow get/set outfill/keepalive parameter
    by ifconfig                                 */
 
-static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd)
+static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct slip *sl = netdev_priv(dev);
 	unsigned long *p = (unsigned long *)&rq->ifr_ifru;
@@ -1244,58 +1235,61 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd)
 		return -ENODEV;
 	}
 
-	switch(cmd){
-        case SIOCSKEEPALIVE:
+	switch (cmd) {
+	case SIOCSKEEPALIVE:
 		/* max for unchar */
-                if ((unsigned)*p > 255) {
+		if ((unsigned)*p > 255) {
 			spin_unlock_bh(&sl->lock);
 			return -EINVAL;
 		}
-		sl->keepalive = (unchar) *p;
+		sl->keepalive = (u8)*p;
 		if (sl->keepalive != 0) {
-			sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ;
-			mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ);
+			sl->keepalive_timer.expires =
+						jiffies + sl->keepalive * HZ;
+			mod_timer(&sl->keepalive_timer,
+						jiffies + sl->keepalive * HZ);
 			set_bit(SLF_KEEPTEST, &sl->flags);
-                } else {
-                        del_timer(&sl->keepalive_timer);
-		}
+		} else
+			del_timer(&sl->keepalive_timer);
 		break;
 
-        case SIOCGKEEPALIVE:
+	case SIOCGKEEPALIVE:
 		*p = sl->keepalive;
 		break;
 
-        case SIOCSOUTFILL:
-                if ((unsigned)*p > 255) { /* max for unchar */
+	case SIOCSOUTFILL:
+		if ((unsigned)*p > 255) { /* max for unchar */
 			spin_unlock_bh(&sl->lock);
 			return -EINVAL;
 		}
-                if ((sl->outfill = (unchar)*p) != 0){
-			mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ);
+		sl->outfill = (u8)*p;
+		if (sl->outfill != 0) {
+			mod_timer(&sl->outfill_timer,
+						jiffies + sl->outfill * HZ);
 			set_bit(SLF_OUTWAIT, &sl->flags);
-		} else {
-                        del_timer (&sl->outfill_timer);
-		}
-                break;
+		} else
+			del_timer(&sl->outfill_timer);
+		break;
 
-        case SIOCGOUTFILL:
+	case SIOCGOUTFILL:
 		*p = sl->outfill;
 		break;
 
-        case SIOCSLEASE:
+	case SIOCSLEASE:
 		/* Resolve race condition, when ioctl'ing hanged up
 		   and opened by another process device.
 		 */
-		if (sl->tty != current->signal->tty && sl->pid != current->pid) {
+		if (sl->tty != current->signal->tty &&
+						sl->pid != current->pid) {
 			spin_unlock_bh(&sl->lock);
 			return -EPERM;
 		}
 		sl->leased = 0;
-                if (*p)
+		if (*p)
 			sl->leased = 1;
-                break;
+		break;
 
-        case SIOCGLEASE:
+	case SIOCGLEASE:
 		*p = sl->leased;
 	};
 	spin_unlock_bh(&sl->lock);
@@ -1327,7 +1321,7 @@ static int __init slip_init(void)
 	       " (6 bit encapsulation enabled)"
 #endif
 	       ".\n",
-	       SLIP_VERSION, slip_maxdev );
+	       SLIP_VERSION, slip_maxdev);
 #if defined(SL_INCLUDE_CSLIP)
 	printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n");
 #endif
@@ -1335,14 +1329,16 @@ static int __init slip_init(void)
 	printk(KERN_INFO "SLIP linefill/keepalive option.\n");
 #endif
 
-	slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL);
+	slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev,
+								GFP_KERNEL);
 	if (!slip_devs) {
-		printk(KERN_ERR "SLIP: Can't allocate slip devices array!  Uaargh! (-> No SLIP available)\n");
+		printk(KERN_ERR "SLIP: Can't allocate slip devices array.\n");
 		return -ENOMEM;
 	}
 
 	/* Fill in our line protocol discipline, and register it */
-	if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0)  {
+	status = tty_register_ldisc(N_SLIP, &sl_ldisc);
+	if (status != 0) {
 		printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status);
 		kfree(slip_devs);
 	}
@@ -1402,10 +1398,9 @@ static void __exit slip_exit(void)
 	kfree(slip_devs);
 	slip_devs = NULL;
 
-	if ((i = tty_unregister_ldisc(N_SLIP)))
-	{
+	i = tty_unregister_ldisc(N_SLIP);
+	if (i != 0)
 		printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i);
-	}
 }
 
 module_init(slip_init);
@@ -1419,17 +1414,15 @@ module_exit(slip_exit);
 
 static void sl_outfill(unsigned long sls)
 {
-	struct slip *sl=(struct slip *)sls;
+	struct slip *sl = (struct slip *)sls;
 
 	spin_lock(&sl->lock);
 
 	if (sl->tty == NULL)
 		goto out;
 
-	if(sl->outfill)
-	{
-		if( test_bit(SLF_OUTWAIT, &sl->flags) )
-		{
+	if (sl->outfill) {
+		if (test_bit(SLF_OUTWAIT, &sl->flags)) {
 			/* no packets were transmitted, do outfill */
 #ifdef CONFIG_SLIP_MODE_SLIP6
 			unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END;
@@ -1437,13 +1430,11 @@ static void sl_outfill(unsigned long sls)
 			unsigned char s = END;
 #endif
 			/* put END into tty queue. Is it right ??? */
-			if (!netif_queue_stopped(sl->dev))
-			{
+			if (!netif_queue_stopped(sl->dev)) {
 				/* if device busy no outfill */
 				sl->tty->driver->write(sl->tty, &s, 1);
 			}
-		}
-		else
+		} else
 			set_bit(SLF_OUTWAIT, &sl->flags);
 
 		mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ);
@@ -1454,31 +1445,29 @@ out:
 
 static void sl_keepalive(unsigned long sls)
 {
-	struct slip *sl=(struct slip *)sls;
+	struct slip *sl = (struct slip *)sls;
 
 	spin_lock(&sl->lock);
 
 	if (sl->tty == NULL)
 		goto out;
 
-	if( sl->keepalive)
-	{
-		if(test_bit(SLF_KEEPTEST, &sl->flags))
-		{
+	if (sl->keepalive) {
+		if (test_bit(SLF_KEEPTEST, &sl->flags)) {
 			/* keepalive still high :(, we must hangup */
-			if( sl->outfill ) /* outfill timer must be deleted too */
+			if (sl->outfill)
+				/* outfill timer must be deleted too */
 				(void)del_timer(&sl->outfill_timer);
 			printk(KERN_DEBUG "%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name);
-			tty_hangup(sl->tty); /* this must hangup tty & close slip */
+			/* this must hangup tty & close slip */
+			tty_hangup(sl->tty);
 			/* I think we need not something else */
 			goto out;
-		}
-		else
+		} else
 			set_bit(SLF_KEEPTEST, &sl->flags);
 
 		mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ);
 	}
-
 out:
 	spin_unlock(&sl->lock);
 }
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index cb2698de5190..de67744c4a2a 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -906,7 +906,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
 	SMC_SELECT_BANK(1);
 	base_address_register = inw( ioaddr + BASE );
 	if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) )  {
-		printk(CARDNAME ": IOADDR %x doesn't match configuration (%x)."
+		printk(CARDNAME ": IOADDR %x doesn't match configuration (%x). "
 			"Probably not a SMC chip\n",
 			ioaddr, base_address_register >> 3 & 0x3E0 );
 		/* well, the base address register didn't match.  Must not have
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 7da7589d45dd..4020e9e955b3 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1775,7 +1775,8 @@ static int __init smc_findirq(void __iomem *ioaddr)
  * o  actually GRAB the irq.
  * o  GRAB the region
  */
-static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
+static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr,
+			    unsigned long irq_flags)
 {
 	struct smc_local *lp = netdev_priv(dev);
 	static int version_printed = 0;
@@ -1941,7 +1942,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
 	}
 
 	/* Grab the IRQ */
-      	retval = request_irq(dev->irq, &smc_interrupt, SMC_IRQ_FLAGS, dev->name, dev);
+	retval = request_irq(dev->irq, &smc_interrupt, irq_flags, dev->name, dev);
       	if (retval)
       		goto err_out;
 
@@ -2123,8 +2124,9 @@ static void smc_release_datacs(struct platform_device *pdev, struct net_device *
 static int smc_drv_probe(struct platform_device *pdev)
 {
 	struct net_device *ndev;
-	struct resource *res;
+	struct resource *res, *ires;
 	unsigned int __iomem *addr;
+	unsigned long irq_flags = SMC_IRQ_FLAGS;
 	int ret;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs");
@@ -2150,12 +2152,17 @@ static int smc_drv_probe(struct platform_device *pdev)
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	ndev->dma = (unsigned char)-1;
-	ndev->irq = platform_get_irq(pdev, 0);
-	if (ndev->irq < 0) {
+
+	ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!ires) {
 		ret = -ENODEV;
 		goto out_free_netdev;
 	}
 
+	ndev->irq = ires->start;
+	if (SMC_IRQ_FLAGS == -1)
+		irq_flags = ires->flags & IRQF_TRIGGER_MASK;
+
 	ret = smc_request_attrib(pdev);
 	if (ret)
 		goto out_free_netdev;
@@ -2181,7 +2188,7 @@ static int smc_drv_probe(struct platform_device *pdev)
 #endif
 
 	platform_set_drvdata(pdev, ndev);
-	ret = smc_probe(ndev, addr);
+	ret = smc_probe(ndev, addr, irq_flags);
 	if (ret != 0)
 		goto out_iounmap;
 
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 07b7f7120e37..271c28dc9baa 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -54,6 +54,7 @@
 #define SMC_outw(v, a, r)	writew(v, (a) + (r))
 #define SMC_insw(a, r, p, l)	readsw((a) + (r), p, l)
 #define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
+#define SMC_IRQ_FLAGS		(-1)	/* from resource */
 
 #elif defined(CONFIG_BLACKFIN)
 
@@ -158,7 +159,7 @@
 #define SMC_outw(v, a, r)	writew(v, (a) + (r))
 #define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
 
-#define SMC_IRQ_FLAGS		(0)
+#define SMC_IRQ_FLAGS		(-1)
 
 #elif defined(CONFIG_SA1100_ASSABET)
 
@@ -177,6 +178,7 @@
 #define SMC_outb(v, a, r)	writeb(v, (a) + (r))
 #define SMC_insb(a, r, p, l)	readsb((a) + (r), p, (l))
 #define SMC_outsb(a, r, p, l)	writesb((a) + (r), p, (l))
+#define SMC_IRQ_FLAGS		(-1)	/* from resource */
 
 #elif	defined(CONFIG_MACH_LOGICPD_PXA270)
 
@@ -194,7 +196,8 @@
 #elif	defined(CONFIG_ARCH_INNOKOM) || \
 	defined(CONFIG_MACH_MAINSTONE) || \
 	defined(CONFIG_ARCH_PXA_IDP) || \
-	defined(CONFIG_ARCH_RAMSES)
+	defined(CONFIG_ARCH_RAMSES) || \
+	defined(CONFIG_ARCH_PCM027)
 
 #define SMC_CAN_USE_8BIT	1
 #define SMC_CAN_USE_16BIT	1
@@ -210,6 +213,7 @@
 #define SMC_outl(v, a, r)	writel(v, (a) + (r))
 #define SMC_insl(a, r, p, l)	readsl((a) + (r), p, l)
 #define SMC_outsl(a, r, p, l)	writesl((a) + (r), p, l)
+#define SMC_IRQ_FLAGS		(-1)	/* from resource */
 
 /* We actually can't write halfwords properly if not word aligned */
 static inline void
@@ -238,6 +242,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #define SMC_outsw(a, r, p, l)   outsw((a) + (r), p, l)
 #define SMC_outb(v, a, r)       writeb(v, (a) + (r))
 #define SMC_outw(v, a, r)       writew(v, (a) + (r))
+#define SMC_IRQ_FLAGS		(-1)	/* from resource */
 
 #elif	defined(CONFIG_ARCH_OMAP)
 
@@ -252,17 +257,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
 #define SMC_outw(v, a, r)	writew(v, (a) + (r))
 #define SMC_insw(a, r, p, l)	readsw((a) + (r), p, l)
 #define SMC_outsw(a, r, p, l)	writesw((a) + (r), p, l)
-
-#include <asm/mach-types.h>
-#include <asm/arch/cpu.h>
-
-#define	SMC_IRQ_FLAGS (( \
-		   machine_is_omap_h2() \
-		|| machine_is_omap_h3() \
-		|| machine_is_omap_h4() \
-		|| (machine_is_omap_innovator() && !cpu_is_omap1510()) \
-	) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING)
-
+#define	SMC_IRQ_FLAGS		(-1)	/* from resource */
 
 #elif	defined(CONFIG_SH_SH4202_MICRODEV)
 
@@ -453,8 +448,7 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
 #define SMC_outl(v, a, r)	writel(v, (a) + (r))
 #define SMC_insl(a, r, p, l)	readsl((a) + (r), p, l)
 #define SMC_outsl(a, r, p, l)	writesl((a) + (r), p, l)
-
-#define SMC_IRQ_FLAGS		(0)
+#define SMC_IRQ_FLAGS		(-1)	/* from resource */
 
 #else
 
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 0a6186d4a48e..7d5561b8241c 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -1596,9 +1596,7 @@ static const struct ethtool_ops ethtool_ops = {
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct netdev_private *np = netdev_priv(dev);
-	void __iomem *ioaddr = np->base;
 	int rc;
-	int i;
 
 	if (!netif_running(dev))
 		return -EINVAL;
@@ -1606,30 +1604,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 	spin_lock_irq(&np->lock);
 	rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL);
 	spin_unlock_irq(&np->lock);
-	switch (cmd) {
-		case SIOCDEVPRIVATE:
-		for (i=0; i<TX_RING_SIZE; i++) {
-			printk(KERN_DEBUG "%02x %08llx %08x %08x(%02x) %08x %08x\n", i,
-				(unsigned long long)(np->tx_ring_dma + i*sizeof(*np->tx_ring)),
-				le32_to_cpu(np->tx_ring[i].next_desc),
-				le32_to_cpu(np->tx_ring[i].status),
-				(le32_to_cpu(np->tx_ring[i].status) >> 2)
-					& 0xff,
-				le32_to_cpu(np->tx_ring[i].frag[0].addr),
-				le32_to_cpu(np->tx_ring[i].frag[0].length));
-		}
-		printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
-			ioread32(np->base + TxListPtr),
-			netif_queue_stopped(dev));
-		printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
-			np->cur_tx, np->cur_tx % TX_RING_SIZE,
-			np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
-		printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
-		printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
-		printk(KERN_DEBUG "TxStatus=%04x\n", ioread16(ioaddr + TxStatus));
-			return 0;
-	}
-
 
 	return rc;
 }
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 68872142530b..97212799c513 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -758,6 +758,7 @@ static int gem_rx(struct gem *gp, int work_to_do)
 {
 	int entry, drops, work_done = 0;
 	u32 done;
+	__sum16 csum;
 
 	if (netif_msg_rx_status(gp))
 		printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n",
@@ -769,7 +770,7 @@ static int gem_rx(struct gem *gp, int work_to_do)
 	for (;;) {
 		struct gem_rxd *rxd = &gp->init_block->rxd[entry];
 		struct sk_buff *skb;
-		u64 status = cpu_to_le64(rxd->status_word);
+		u64 status = le64_to_cpu(rxd->status_word);
 		dma_addr_t dma_addr;
 		int len;
 
@@ -811,7 +812,7 @@ static int gem_rx(struct gem *gp, int work_to_do)
 			goto next;
 		}
 
-		dma_addr = cpu_to_le64(rxd->buffer);
+		dma_addr = le64_to_cpu(rxd->buffer);
 		if (len > RX_COPY_THRESHOLD) {
 			struct sk_buff *new_skb;
 
@@ -853,7 +854,8 @@ static int gem_rx(struct gem *gp, int work_to_do)
 			skb = copy_skb;
 		}
 
-		skb->csum = ntohs((status & RXDCTRL_TCPCSUM) ^ 0xffff);
+		csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff);
+		skb->csum = csum_unfold(csum);
 		skb->ip_summed = CHECKSUM_COMPLETE;
 		skb->protocol = eth_type_trans(skb, gp->dev);
 
@@ -3054,7 +3056,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
 	netif_carrier_off(dev);
 
 	gp->regs = ioremap(gemreg_base, gemreg_len);
-	if (gp->regs == 0UL) {
+	if (!gp->regs) {
 		printk(KERN_ERR PFX "Cannot map device registers, "
 		       "aborting.\n");
 		err = -EIO;
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index 76d760acc9e2..f7a02917ce5e 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -828,8 +828,8 @@
  * DMA mappings for a transmitted packet.
  */
 struct gem_txd {
-	u64	control_word;
-	u64	buffer;
+	__le64	control_word;
+	__le64	buffer;
 };
 
 #define TXDCTRL_BUFSZ	0x0000000000007fffULL	/* Buffer Size		*/
@@ -863,8 +863,8 @@ struct gem_txd {
  * by the host driver just as in the TX descriptor case above.
  */
 struct gem_rxd {
-	u64	status_word;
-	u64	buffer;
+	__le64	status_word;
+	__le64	buffer;
 };
 
 #define RXDCTRL_TCPCSUM	0x000000000000ffffULL	/* TCP Pseudo-CSUM	*/
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 9cc13dd8a821..b4e7f30ea4e8 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -194,21 +194,21 @@ static u32 sbus_hme_read32(void __iomem *reg)
 
 static void sbus_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr)
 {
-	rxd->rx_addr = addr;
+	rxd->rx_addr = (__force hme32)addr;
 	wmb();
-	rxd->rx_flags = flags;
+	rxd->rx_flags = (__force hme32)flags;
 }
 
 static void sbus_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr)
 {
-	txd->tx_addr = addr;
+	txd->tx_addr = (__force hme32)addr;
 	wmb();
-	txd->tx_flags = flags;
+	txd->tx_flags = (__force hme32)flags;
 }
 
-static u32 sbus_hme_read_desc32(u32 *p)
+static u32 sbus_hme_read_desc32(hme32 *p)
 {
-	return *p;
+	return (__force u32)*p;
 }
 
 static void pci_hme_write32(void __iomem *reg, u32 val)
@@ -223,21 +223,21 @@ static u32 pci_hme_read32(void __iomem *reg)
 
 static void pci_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr)
 {
-	rxd->rx_addr = cpu_to_le32(addr);
+	rxd->rx_addr = (__force hme32)cpu_to_le32(addr);
 	wmb();
-	rxd->rx_flags = cpu_to_le32(flags);
+	rxd->rx_flags = (__force hme32)cpu_to_le32(flags);
 }
 
 static void pci_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr)
 {
-	txd->tx_addr = cpu_to_le32(addr);
+	txd->tx_addr = (__force hme32)cpu_to_le32(addr);
 	wmb();
-	txd->tx_flags = cpu_to_le32(flags);
+	txd->tx_flags = (__force hme32)cpu_to_le32(flags);
 }
 
-static u32 pci_hme_read_desc32(u32 *p)
+static u32 pci_hme_read_desc32(hme32 *p)
 {
-	return cpu_to_le32p(p);
+	return le32_to_cpup((__le32 *)p);
 }
 
 #define hme_write32(__hp, __reg, __val) \
@@ -266,16 +266,16 @@ static u32 pci_hme_read_desc32(u32 *p)
 #define hme_read32(__hp, __reg) \
 	sbus_readl(__reg)
 #define hme_write_rxd(__hp, __rxd, __flags, __addr) \
-do {	(__rxd)->rx_addr = (__addr); \
+do {	(__rxd)->rx_addr = (__force hme32)(u32)(__addr); \
 	wmb(); \
-	(__rxd)->rx_flags = (__flags); \
+	(__rxd)->rx_flags = (__force hme32)(u32)(__flags); \
 } while(0)
 #define hme_write_txd(__hp, __txd, __flags, __addr) \
-do {	(__txd)->tx_addr = (__addr); \
+do {	(__txd)->tx_addr = (__force hme32)(u32)(__addr); \
 	wmb(); \
-	(__txd)->tx_flags = (__flags); \
+	(__txd)->tx_flags = (__force hme32)(u32)(__flags); \
 } while(0)
-#define hme_read_desc32(__hp, __p)	(*(__p))
+#define hme_read_desc32(__hp, __p)	((__force u32)(hme32)*(__p))
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
 	sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
@@ -291,16 +291,19 @@ do {	(__txd)->tx_addr = (__addr); \
 #define hme_read32(__hp, __reg) \
 	readl(__reg)
 #define hme_write_rxd(__hp, __rxd, __flags, __addr) \
-do {	(__rxd)->rx_addr = cpu_to_le32(__addr); \
+do {	(__rxd)->rx_addr = (__force hme32)cpu_to_le32(__addr); \
 	wmb(); \
-	(__rxd)->rx_flags = cpu_to_le32(__flags); \
+	(__rxd)->rx_flags = (__force hme32)cpu_to_le32(__flags); \
 } while(0)
 #define hme_write_txd(__hp, __txd, __flags, __addr) \
-do {	(__txd)->tx_addr = cpu_to_le32(__addr); \
+do {	(__txd)->tx_addr = (__force hme32)cpu_to_le32(__addr); \
 	wmb(); \
-	(__txd)->tx_flags = cpu_to_le32(__flags); \
+	(__txd)->tx_flags = (__force hme32)cpu_to_le32(__flags); \
 } while(0)
-#define hme_read_desc32(__hp, __p)	cpu_to_le32p(__p)
+static inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p)
+{
+	return le32_to_cpup((__le32 *)p);
+}
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
 	pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
@@ -2075,7 +2078,7 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
 		}
 
 		/* This card is _fucking_ hot... */
-		skb->csum = ntohs(csum ^ 0xffff);
+		skb->csum = csum_unfold(~(__force __sum16)htons(csum));
 		skb->ip_summed = CHECKSUM_COMPLETE;
 
 		RXD(("len=%d csum=%4x]", len, csum));
@@ -3057,7 +3060,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
 		goto err_out_clear_quattro;
 	}
 
-	if ((hpreg_base = ioremap(hpreg_res, 0x8000)) == 0) {
+	if ((hpreg_base = ioremap(hpreg_res, 0x8000)) == NULL) {
 		printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n");
 		goto err_out_free_res;
 	}
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 90f446db9ba2..4da5539fac7b 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -302,9 +302,11 @@
  * Always write the address first before setting the ownership
  * bits to avoid races with the hardware scanning the ring.
  */
+typedef u32 __bitwise__ hme32;
+
 struct happy_meal_rxd {
-	u32 rx_flags;
-	u32 rx_addr;
+	hme32 rx_flags;
+	hme32 rx_addr;
 };
 
 #define RXFLAG_OWN         0x80000000 /* 1 = hardware, 0 = software */
@@ -313,8 +315,8 @@ struct happy_meal_rxd {
 #define RXFLAG_CSUM        0x0000ffff /* HW computed checksum       */
 
 struct happy_meal_txd {
-	u32 tx_flags;
-	u32 tx_addr;
+	hme32 tx_flags;
+	hme32 tx_addr;
 };
 
 #define TXFLAG_OWN         0x80000000 /* 1 = hardware, 0 = software */
@@ -400,7 +402,7 @@ struct happy_meal {
 	struct hmeal_init_block  *happy_block;	/* RX and TX descriptors (CPU addr)  */
 
 #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
-	u32 (*read_desc32)(u32 *);
+	u32 (*read_desc32)(hme32 *);
 	void (*write_txd)(struct happy_meal_txd *, u32, u32);
 	void (*write_rxd)(struct happy_meal_rxd *, u32, u32);
 	u32 (*dma_map)(void *, void *, long, int);
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index ff1028a597df..4a0035f7a842 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -1149,6 +1149,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
 	struct vnet *vp;
 	const u64 *rmac;
 	int len, i, err, switch_port;
+	DECLARE_MAC_BUF(mac);
 
 	print_version();
 
@@ -1213,12 +1214,9 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
 
 	dev_set_drvdata(&vdev->dev, port);
 
-	printk(KERN_INFO "%s: PORT ( remote-mac ", vp->dev->name);
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", port->raddr[i], i == 5 ? ' ' : ':');
-	if (switch_port)
-		printk("switch-port ");
-	printk(")\n");
+	printk(KERN_INFO "%s: PORT ( remote-mac %s%s )\n",
+	       vp->dev->name, print_mac(mac, port->raddr),
+	       switch_port ? " switch-port" : "");
 
 	vio_port_up(&port->vio);
 
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 21230c97b2a0..17585e5eed53 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -621,7 +621,7 @@ err:
 static void __init bdx_firmware_endianess(void)
 {
 	int i;
-	for (i = 0; i < sizeof(s_firmLoad) / sizeof(u32); i++)
+	for (i = 0; i < ARRAY_SIZE(s_firmLoad); i++)
 		s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]);
 }
 
@@ -2174,8 +2174,7 @@ bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
 	strlcat(drvinfo->bus_info, pci_name(priv->pdev),
 		sizeof(drvinfo->bus_info));
 
-	drvinfo->n_stats = ((priv->stats_flag) ?
-			    (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) : 0);
+	drvinfo->n_stats = ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0);
 	drvinfo->testinfo_len = 0;
 	drvinfo->regdump_len = 0;
 	drvinfo->eedump_len = 0;
@@ -2375,10 +2374,9 @@ static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
 static int bdx_get_stats_count(struct net_device *netdev)
 {
 	struct bdx_priv *priv = netdev->priv;
-	BDX_ASSERT(sizeof(bdx_stat_names) / ETH_GSTRING_LEN
+	BDX_ASSERT(ARRAY_SIZE(bdx_stat_names)
 		   != sizeof(struct bdx_stats) / sizeof(u64));
-	return ((priv->stats_flag) ? (sizeof(bdx_stat_names) / ETH_GSTRING_LEN)
-		: 0);
+	return ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names)	: 0);
 }
 
 /*
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 22eb7c8c1a25..db606b603884 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -64,8 +64,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.86"
-#define DRV_MODULE_RELDATE	"November 9, 2007"
+#define DRV_MODULE_VERSION	"3.87"
+#define DRV_MODULE_RELDATE	"December 20, 2007"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -1602,68 +1602,113 @@ static void tg3_link_report(struct tg3 *tp)
 		       (tp->link_config.active_duplex == DUPLEX_FULL ?
 			"full" : "half"));
 
-		printk(KERN_INFO PFX "%s: Flow control is %s for TX and "
-		       "%s for RX.\n",
+		printk(KERN_INFO PFX
+		       "%s: Flow control is %s for TX and %s for RX.\n",
 		       tp->dev->name,
-		       (tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "on" : "off",
-		       (tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "on" : "off");
+		       (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ?
+		       "on" : "off",
+		       (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
+		       "on" : "off");
 	}
 }
 
-static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
+static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl)
 {
-	u32 new_tg3_flags = 0;
-	u32 old_rx_mode = tp->rx_mode;
-	u32 old_tx_mode = tp->tx_mode;
+	u16 miireg;
 
-	if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
+	if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+		miireg = ADVERTISE_PAUSE_CAP;
+	else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+		miireg = ADVERTISE_PAUSE_ASYM;
+	else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+		miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+	else
+		miireg = 0;
 
-		/* Convert 1000BaseX flow control bits to 1000BaseT
-		 * bits before resolving flow control.
-		 */
-		if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
-			local_adv &= ~(ADVERTISE_PAUSE_CAP |
-				       ADVERTISE_PAUSE_ASYM);
-			remote_adv &= ~(LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
-
-			if (local_adv & ADVERTISE_1000XPAUSE)
-				local_adv |= ADVERTISE_PAUSE_CAP;
-			if (local_adv & ADVERTISE_1000XPSE_ASYM)
-				local_adv |= ADVERTISE_PAUSE_ASYM;
-			if (remote_adv & LPA_1000XPAUSE)
-				remote_adv |= LPA_PAUSE_CAP;
-			if (remote_adv & LPA_1000XPAUSE_ASYM)
-				remote_adv |= LPA_PAUSE_ASYM;
-		}
-
-		if (local_adv & ADVERTISE_PAUSE_CAP) {
-			if (local_adv & ADVERTISE_PAUSE_ASYM) {
-				if (remote_adv & LPA_PAUSE_CAP)
-					new_tg3_flags |=
-						(TG3_FLAG_RX_PAUSE |
-					 	TG3_FLAG_TX_PAUSE);
-				else if (remote_adv & LPA_PAUSE_ASYM)
-					new_tg3_flags |=
-						(TG3_FLAG_RX_PAUSE);
-			} else {
-				if (remote_adv & LPA_PAUSE_CAP)
-					new_tg3_flags |=
-						(TG3_FLAG_RX_PAUSE |
-					 	TG3_FLAG_TX_PAUSE);
-			}
-		} else if (local_adv & ADVERTISE_PAUSE_ASYM) {
-			if ((remote_adv & LPA_PAUSE_CAP) &&
-		    	(remote_adv & LPA_PAUSE_ASYM))
-				new_tg3_flags |= TG3_FLAG_TX_PAUSE;
+	return miireg;
+}
+
+static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
+{
+	u16 miireg;
+
+	if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+		miireg = ADVERTISE_1000XPAUSE;
+	else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+		miireg = ADVERTISE_1000XPSE_ASYM;
+	else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+		miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
+	else
+		miireg = 0;
+
+	return miireg;
+}
+
+static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
+{
+	u8 cap = 0;
+
+	if (lcladv & ADVERTISE_PAUSE_CAP) {
+		if (lcladv & ADVERTISE_PAUSE_ASYM) {
+			if (rmtadv & LPA_PAUSE_CAP)
+				cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+			else if (rmtadv & LPA_PAUSE_ASYM)
+				cap = TG3_FLOW_CTRL_RX;
+		} else {
+			if (rmtadv & LPA_PAUSE_CAP)
+				cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+		}
+	} else if (lcladv & ADVERTISE_PAUSE_ASYM) {
+		if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
+			cap = TG3_FLOW_CTRL_TX;
+	}
+
+	return cap;
+}
+
+static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
+{
+	u8 cap = 0;
+
+	if (lcladv & ADVERTISE_1000XPAUSE) {
+		if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+			if (rmtadv & LPA_1000XPAUSE)
+				cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+			else if (rmtadv & LPA_1000XPAUSE_ASYM)
+				cap = TG3_FLOW_CTRL_RX;
+		} else {
+			if (rmtadv & LPA_1000XPAUSE)
+				cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
 		}
+	} else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+		if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
+			cap = TG3_FLOW_CTRL_TX;
+	}
 
-		tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
-		tp->tg3_flags |= new_tg3_flags;
+	return cap;
+}
+
+static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
+{
+	u8 new_tg3_flags = 0;
+	u32 old_rx_mode = tp->rx_mode;
+	u32 old_tx_mode = tp->tx_mode;
+
+	if (tp->link_config.autoneg == AUTONEG_ENABLE &&
+	    (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
+		if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
+			new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
+								   remote_adv);
+		else
+			new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv,
+								   remote_adv);
 	} else {
-		new_tg3_flags = tp->tg3_flags;
+		new_tg3_flags = tp->link_config.flowctrl;
 	}
 
-	if (new_tg3_flags & TG3_FLAG_RX_PAUSE)
+	tp->link_config.active_flowctrl = new_tg3_flags;
+
+	if (new_tg3_flags & TG3_FLOW_CTRL_RX)
 		tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
 	else
 		tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
@@ -1672,7 +1717,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
 		tw32_f(MAC_RX_MODE, tp->rx_mode);
 	}
 
-	if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
+	if (new_tg3_flags & TG3_FLOW_CTRL_TX)
 		tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
 	else
 		tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
@@ -1752,7 +1797,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
 				~(ADVERTISED_1000baseT_Half |
 				  ADVERTISED_1000baseT_Full);
 
-		new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+		new_adv = ADVERTISE_CSMA;
 		if (tp->link_config.advertising & ADVERTISED_10baseT_Half)
 			new_adv |= ADVERTISE_10HALF;
 		if (tp->link_config.advertising & ADVERTISED_10baseT_Full)
@@ -1761,6 +1806,9 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
 			new_adv |= ADVERTISE_100HALF;
 		if (tp->link_config.advertising & ADVERTISED_100baseT_Full)
 			new_adv |= ADVERTISE_100FULL;
+
+		new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+
 		tg3_writephy(tp, MII_ADVERTISE, new_adv);
 
 		if (tp->link_config.advertising &
@@ -1780,9 +1828,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
 			tg3_writephy(tp, MII_TG3_CTRL, 0);
 		}
 	} else {
+		new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+		new_adv |= ADVERTISE_CSMA;
+
 		/* Asking for a specific link mode. */
 		if (tp->link_config.speed == SPEED_1000) {
-			new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
 			tg3_writephy(tp, MII_ADVERTISE, new_adv);
 
 			if (tp->link_config.duplex == DUPLEX_FULL)
@@ -1793,11 +1843,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
 			    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
 				new_adv |= (MII_TG3_CTRL_AS_MASTER |
 					    MII_TG3_CTRL_ENABLE_AS_MASTER);
-			tg3_writephy(tp, MII_TG3_CTRL, new_adv);
 		} else {
-			tg3_writephy(tp, MII_TG3_CTRL, 0);
-
-			new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
 			if (tp->link_config.speed == SPEED_100) {
 				if (tp->link_config.duplex == DUPLEX_FULL)
 					new_adv |= ADVERTISE_100FULL;
@@ -1810,7 +1856,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
 					new_adv |= ADVERTISE_10HALF;
 			}
 			tg3_writephy(tp, MII_ADVERTISE, new_adv);
+
+			new_adv = 0;
 		}
+
+		tg3_writephy(tp, MII_TG3_CTRL, new_adv);
 	}
 
 	if (tp->link_config.autoneg == AUTONEG_DISABLE &&
@@ -1926,10 +1976,44 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
 	return 1;
 }
 
+static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv)
+{
+	u32 curadv, reqadv;
+
+	if (tg3_readphy(tp, MII_ADVERTISE, lcladv))
+		return 1;
+
+	curadv = *lcladv & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+	reqadv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+
+	if (tp->link_config.active_duplex == DUPLEX_FULL) {
+		if (curadv != reqadv)
+			return 0;
+
+		if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)
+			tg3_readphy(tp, MII_LPA, rmtadv);
+	} else {
+		/* Reprogram the advertisement register, even if it
+		 * does not affect the current link.  If the link
+		 * gets renegotiated in the future, we can save an
+		 * additional renegotiation cycle by advertising
+		 * it correctly in the first place.
+		 */
+		if (curadv != reqadv) {
+			*lcladv &= ~(ADVERTISE_PAUSE_CAP |
+				     ADVERTISE_PAUSE_ASYM);
+			tg3_writephy(tp, MII_ADVERTISE, *lcladv | reqadv);
+		}
+	}
+
+	return 1;
+}
+
 static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
 {
 	int current_link_up;
 	u32 bmsr, dummy;
+	u32 lcl_adv, rmt_adv;
 	u16 current_speed;
 	u8 current_duplex;
 	int i, err;
@@ -2072,56 +2156,35 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
 			udelay(10);
 		}
 
-		if (tp->link_config.autoneg == AUTONEG_ENABLE) {
-			if (bmcr & BMCR_ANENABLE) {
-				current_link_up = 1;
+		lcl_adv = 0;
+		rmt_adv = 0;
 
-				/* Force autoneg restart if we are exiting
-				 * low power mode.
-				 */
-				if (!tg3_copper_is_advertising_all(tp,
-						tp->link_config.advertising))
-					current_link_up = 0;
-			} else {
-				current_link_up = 0;
+		tp->link_config.active_speed = current_speed;
+		tp->link_config.active_duplex = current_duplex;
+
+		if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+			if ((bmcr & BMCR_ANENABLE) &&
+			    tg3_copper_is_advertising_all(tp,
+						tp->link_config.advertising)) {
+				if (tg3_adv_1000T_flowctrl_ok(tp, &lcl_adv,
+								  &rmt_adv))
+					current_link_up = 1;
 			}
 		} else {
 			if (!(bmcr & BMCR_ANENABLE) &&
 			    tp->link_config.speed == current_speed &&
-			    tp->link_config.duplex == current_duplex) {
+			    tp->link_config.duplex == current_duplex &&
+			    tp->link_config.flowctrl ==
+			    tp->link_config.active_flowctrl) {
 				current_link_up = 1;
-			} else {
-				current_link_up = 0;
 			}
 		}
 
-		tp->link_config.active_speed = current_speed;
-		tp->link_config.active_duplex = current_duplex;
+		if (current_link_up == 1 &&
+		    tp->link_config.active_duplex == DUPLEX_FULL)
+			tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
 	}
 
-	if (current_link_up == 1 &&
-	    (tp->link_config.active_duplex == DUPLEX_FULL) &&
-	    (tp->link_config.autoneg == AUTONEG_ENABLE)) {
-		u32 local_adv, remote_adv;
-
-		if (tg3_readphy(tp, MII_ADVERTISE, &local_adv))
-			local_adv = 0;
-		local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
-
-		if (tg3_readphy(tp, MII_LPA, &remote_adv))
-			remote_adv = 0;
-
-		remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
-
-		/* If we are not advertising full pause capability,
-		 * something is wrong.  Bring the link down and reconfigure.
-		 */
-		if (local_adv != ADVERTISE_PAUSE_CAP) {
-			current_link_up = 0;
-		} else {
-			tg3_setup_flow_control(tp, local_adv, remote_adv);
-		}
-	}
 relink:
 	if (current_link_up == 0 || tp->link_config.phy_is_low_power) {
 		u32 tmp;
@@ -2270,6 +2333,7 @@ struct tg3_fiber_aneginfo {
 static int tg3_fiber_aneg_smachine(struct tg3 *tp,
 				   struct tg3_fiber_aneginfo *ap)
 {
+	u16 flowctrl;
 	unsigned long delta;
 	u32 rx_cfg_reg;
 	int ret;
@@ -2369,7 +2433,12 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
 
 	case ANEG_STATE_ABILITY_DETECT_INIT:
 		ap->flags &= ~(MR_TOGGLE_TX);
-		ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
+		ap->txconfig = ANEG_CFG_FD;
+		flowctrl = tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+		if (flowctrl & ADVERTISE_1000XPAUSE)
+			ap->txconfig |= ANEG_CFG_PS1;
+		if (flowctrl & ADVERTISE_1000XPSE_ASYM)
+			ap->txconfig |= ANEG_CFG_PS2;
 		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
 		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
 		tw32_f(MAC_MODE, tp->mac_mode);
@@ -2515,7 +2584,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
 	return ret;
 }
 
-static int fiber_autoneg(struct tg3 *tp, u32 *flags)
+static int fiber_autoneg(struct tg3 *tp, u32 *txflags, u32 *rxflags)
 {
 	int res = 0;
 	struct tg3_fiber_aneginfo aninfo;
@@ -2549,7 +2618,8 @@ static int fiber_autoneg(struct tg3 *tp, u32 *flags)
 	tw32_f(MAC_MODE, tp->mac_mode);
 	udelay(40);
 
-	*flags = aninfo.flags;
+	*txflags = aninfo.txconfig;
+	*rxflags = aninfo.flags;
 
 	if (status == ANEG_DONE &&
 	    (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK |
@@ -2611,6 +2681,7 @@ static void tg3_init_bcm8002(struct tg3 *tp)
 
 static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 {
+	u16 flowctrl;
 	u32 sg_dig_ctrl, sg_dig_status;
 	u32 serdes_cfg, expected_sg_dig_ctrl;
 	int workaround, port_a;
@@ -2636,7 +2707,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 	sg_dig_ctrl = tr32(SG_DIG_CTRL);
 
 	if (tp->link_config.autoneg != AUTONEG_ENABLE) {
-		if (sg_dig_ctrl & (1 << 31)) {
+		if (sg_dig_ctrl & SG_DIG_USING_HW_AUTONEG) {
 			if (workaround) {
 				u32 val = serdes_cfg;
 
@@ -2646,7 +2717,8 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 					val |= 0x4010000;
 				tw32_f(MAC_SERDES_CFG, val);
 			}
-			tw32_f(SG_DIG_CTRL, 0x01388400);
+
+			tw32_f(SG_DIG_CTRL, SG_DIG_COMMON_SETUP);
 		}
 		if (mac_status & MAC_STATUS_PCS_SYNCED) {
 			tg3_setup_flow_control(tp, 0, 0);
@@ -2656,13 +2728,13 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 	}
 
 	/* Want auto-negotiation.  */
-	expected_sg_dig_ctrl = 0x81388400;
+	expected_sg_dig_ctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_COMMON_SETUP;
 
-	/* Pause capability */
-	expected_sg_dig_ctrl |= (1 << 11);
-
-	/* Asymettric pause */
-	expected_sg_dig_ctrl |= (1 << 12);
+	flowctrl = tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+	if (flowctrl & ADVERTISE_1000XPAUSE)
+		expected_sg_dig_ctrl |= SG_DIG_PAUSE_CAP;
+	if (flowctrl & ADVERTISE_1000XPSE_ASYM)
+		expected_sg_dig_ctrl |= SG_DIG_ASYM_PAUSE;
 
 	if (sg_dig_ctrl != expected_sg_dig_ctrl) {
 		if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
@@ -2677,7 +2749,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
 restart_autoneg:
 		if (workaround)
 			tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
-		tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
+		tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | SG_DIG_SOFT_RESET);
 		udelay(5);
 		tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
 
@@ -2688,22 +2760,25 @@ restart_autoneg:
 		sg_dig_status = tr32(SG_DIG_STATUS);
 		mac_status = tr32(MAC_STATUS);
 
-		if ((sg_dig_status & (1 << 1)) &&
+		if ((sg_dig_status & SG_DIG_AUTONEG_COMPLETE) &&
 		    (mac_status & MAC_STATUS_PCS_SYNCED)) {
-			u32 local_adv, remote_adv;
+			u32 local_adv = 0, remote_adv = 0;
+
+			if (sg_dig_ctrl & SG_DIG_PAUSE_CAP)
+				local_adv |= ADVERTISE_1000XPAUSE;
+			if (sg_dig_ctrl & SG_DIG_ASYM_PAUSE)
+				local_adv |= ADVERTISE_1000XPSE_ASYM;
 
-			local_adv = ADVERTISE_PAUSE_CAP;
-			remote_adv = 0;
-			if (sg_dig_status & (1 << 19))
-				remote_adv |= LPA_PAUSE_CAP;
-			if (sg_dig_status & (1 << 20))
-				remote_adv |= LPA_PAUSE_ASYM;
+			if (sg_dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE)
+				remote_adv |= LPA_1000XPAUSE;
+			if (sg_dig_status & SG_DIG_PARTNER_ASYM_PAUSE)
+				remote_adv |= LPA_1000XPAUSE_ASYM;
 
 			tg3_setup_flow_control(tp, local_adv, remote_adv);
 			current_link_up = 1;
 			tp->serdes_counter = 0;
 			tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
-		} else if (!(sg_dig_status & (1 << 1))) {
+		} else if (!(sg_dig_status & SG_DIG_AUTONEG_COMPLETE)) {
 			if (tp->serdes_counter)
 				tp->serdes_counter--;
 			else {
@@ -2718,7 +2793,7 @@ restart_autoneg:
 					tw32_f(MAC_SERDES_CFG, val);
 				}
 
-				tw32_f(SG_DIG_CTRL, 0x01388400);
+				tw32_f(SG_DIG_CTRL, SG_DIG_COMMON_SETUP);
 				udelay(40);
 
 				/* Link parallel detection - link is up */
@@ -2754,18 +2829,21 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
 		goto out;
 
 	if (tp->link_config.autoneg == AUTONEG_ENABLE) {
-		u32 flags;
+		u32 txflags, rxflags;
 		int i;
 
-		if (fiber_autoneg(tp, &flags)) {
-			u32 local_adv, remote_adv;
+		if (fiber_autoneg(tp, &txflags, &rxflags)) {
+			u32 local_adv = 0, remote_adv = 0;
+
+			if (txflags & ANEG_CFG_PS1)
+				local_adv |= ADVERTISE_1000XPAUSE;
+			if (txflags & ANEG_CFG_PS2)
+				local_adv |= ADVERTISE_1000XPSE_ASYM;
 
-			local_adv = ADVERTISE_PAUSE_CAP;
-			remote_adv = 0;
-			if (flags & MR_LP_ADV_SYM_PAUSE)
-				remote_adv |= LPA_PAUSE_CAP;
-			if (flags & MR_LP_ADV_ASYM_PAUSE)
-				remote_adv |= LPA_PAUSE_ASYM;
+			if (rxflags & MR_LP_ADV_SYM_PAUSE)
+				remote_adv |= LPA_1000XPAUSE;
+			if (rxflags & MR_LP_ADV_ASYM_PAUSE)
+				remote_adv |= LPA_1000XPAUSE_ASYM;
 
 			tg3_setup_flow_control(tp, local_adv, remote_adv);
 
@@ -2789,6 +2867,8 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
 		    !(mac_status & MAC_STATUS_RCVD_CFG))
 			current_link_up = 1;
 	} else {
+		tg3_setup_flow_control(tp, 0, 0);
+
 		/* Forcing 1000FD link up. */
 		current_link_up = 1;
 
@@ -2812,9 +2892,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
 	int current_link_up;
 	int i;
 
-	orig_pause_cfg =
-		(tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
-				  TG3_FLAG_TX_PAUSE));
+	orig_pause_cfg = tp->link_config.active_flowctrl;
 	orig_active_speed = tp->link_config.active_speed;
 	orig_active_duplex = tp->link_config.active_duplex;
 
@@ -2903,9 +2981,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
 			netif_carrier_off(tp->dev);
 		tg3_link_report(tp);
 	} else {
-		u32 now_pause_cfg =
-			tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
-					 TG3_FLAG_TX_PAUSE);
+		u32 now_pause_cfg = tp->link_config.active_flowctrl;
 		if (orig_pause_cfg != now_pause_cfg ||
 		    orig_active_speed != tp->link_config.active_speed ||
 		    orig_active_duplex != tp->link_config.active_duplex)
@@ -2921,6 +2997,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
 	u32 bmsr, bmcr;
 	u16 current_speed;
 	u8 current_duplex;
+	u32 local_adv, remote_adv;
 
 	tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
 	tw32_f(MAC_MODE, tp->mac_mode);
@@ -2954,7 +3031,8 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
 	err |= tg3_readphy(tp, MII_BMCR, &bmcr);
 
 	if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset &&
-	    (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
+	    (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
+	     tp->link_config.flowctrl == tp->link_config.active_flowctrl) {
 		/* do nothing, just check for link up at the end */
 	} else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
 		u32 adv, new_adv;
@@ -2965,8 +3043,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
 				  ADVERTISE_1000XPSE_ASYM |
 				  ADVERTISE_SLCT);
 
-		/* Always advertise symmetric PAUSE just like copper */
-		new_adv |= ADVERTISE_1000XPAUSE;
+		new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
 
 		if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
 			new_adv |= ADVERTISE_1000XHALF;
@@ -3037,8 +3114,11 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
 		else
 			current_duplex = DUPLEX_HALF;
 
+		local_adv = 0;
+		remote_adv = 0;
+
 		if (bmcr & BMCR_ANENABLE) {
-			u32 local_adv, remote_adv, common;
+			u32 common;
 
 			err |= tg3_readphy(tp, MII_ADVERTISE, &local_adv);
 			err |= tg3_readphy(tp, MII_LPA, &remote_adv);
@@ -3049,15 +3129,15 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
 					current_duplex = DUPLEX_FULL;
 				else
 					current_duplex = DUPLEX_HALF;
-
-				tg3_setup_flow_control(tp, local_adv,
-						       remote_adv);
 			}
 			else
 				current_link_up = 0;
 		}
 	}
 
+	if (current_link_up == 1 && current_duplex == DUPLEX_FULL)
+		tg3_setup_flow_control(tp, local_adv, remote_adv);
+
 	tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
 	if (tp->link_config.active_duplex == DUPLEX_HALF)
 		tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
@@ -8569,8 +8649,16 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
 	struct tg3 *tp = netdev_priv(dev);
 
 	epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
-	epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0;
-	epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0;
+
+	if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX)
+		epause->rx_pause = 1;
+	else
+		epause->rx_pause = 0;
+
+	if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX)
+		epause->tx_pause = 1;
+	else
+		epause->tx_pause = 0;
 }
 
 static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
@@ -8590,13 +8678,13 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
 	else
 		tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
 	if (epause->rx_pause)
-		tp->tg3_flags |= TG3_FLAG_RX_PAUSE;
+		tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
 	else
-		tp->tg3_flags &= ~TG3_FLAG_RX_PAUSE;
+		tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
 	if (epause->tx_pause)
-		tp->tg3_flags |= TG3_FLAG_TX_PAUSE;
+		tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
 	else
-		tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE;
+		tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
 
 	if (netif_running(dev)) {
 		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
@@ -12361,9 +12449,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 	unsigned long tg3reg_base, tg3reg_len;
 	struct net_device *dev;
 	struct tg3 *tp;
-	int i, err, pm_cap;
+	int err, pm_cap;
 	char str[40];
 	u64 dma_mask, persist_dma_mask;
+	DECLARE_MAC_BUF(mac);
 
 	if (tg3_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -12586,7 +12675,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 		tg3reg_len = pci_resource_len(pdev, 2);
 
 		tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len);
-		if (tp->aperegs == 0UL) {
+		if (!tp->aperegs) {
 			printk(KERN_ERR PFX "Cannot map APE registers, "
 			       "aborting.\n");
 			err = -ENOMEM;
@@ -12630,6 +12719,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
 	/* flow control autonegotiation is default behavior */
 	tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+	tp->link_config.flowctrl = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
 
 	tg3_init_coal(tp);
 
@@ -12642,7 +12732,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 		goto err_out_apeunmap;
 	}
 
-	printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ",
+	printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] "
+	       "(%s) %s Ethernet %s\n",
 	       dev->name,
 	       tp->board_part_number,
 	       tp->pci_chip_rev_id,
@@ -12650,11 +12741,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 	       tg3_bus_string(tp, str),
 	       ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" :
 		((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" :
-		 "10/100/1000Base-T")));
-
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i],
-		       i == 5 ? '\n' : ':');
+		 "10/100/1000Base-T")),
+	       print_mac(mac, dev->dev_addr));
 
 	printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] "
 	       "MIirq[%d] ASF[%d] WireSpeed[%d] TSOcap[%d]\n",
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index da18fb220712..3938eb35ce8c 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -545,6 +545,8 @@
 #define  SG_DIG_FIBER_MODE		 0x00008000
 #define  SG_DIG_REMOTE_FAULT_MASK	 0x00006000
 #define  SG_DIG_PAUSE_MASK		 0x00001800
+#define  SG_DIG_PAUSE_CAP		 0x00000800
+#define  SG_DIG_ASYM_PAUSE		 0x00001000
 #define  SG_DIG_GBIC_ENABLE		 0x00000400
 #define  SG_DIG_CHECK_END_ENABLE	 0x00000200
 #define  SG_DIG_SGMII_AUTONEG_TIMER	 0x00000100
@@ -556,6 +558,11 @@
 #define  SG_DIG_AUTONEG_LOW_ENABLE	 0x00000004
 #define  SG_DIG_REMOTE_LOOPBACK		 0x00000002
 #define  SG_DIG_LOOPBACK		 0x00000001
+#define  SG_DIG_COMMON_SETUP (SG_DIG_CRC16_CLEAR_N | \
+			      SG_DIG_LOCAL_DUPLEX_STATUS | \
+			      SG_DIG_LOCAL_LINK_STATUS | \
+			      (0x2 << SG_DIG_SPEED_STATUS_SHIFT) | \
+			      SG_DIG_FIBER_MODE | SG_DIG_GBIC_ENABLE)
 #define SG_DIG_STATUS			0x000005b4
 #define  SG_DIG_CRC16_BUS_MASK		 0xffff0000
 #define  SG_DIG_PARTNER_FAULT_MASK	 0x00600000 /* If !MRADV_CRC16_SELECT */
@@ -2103,13 +2110,18 @@ struct tg3_link_config {
 	u16				speed;
 	u8				duplex;
 	u8				autoneg;
+	u8				flowctrl;
+#define TG3_FLOW_CTRL_TX		0x01
+#define TG3_FLOW_CTRL_RX		0x02
 
 	/* Describes what we actually have. */
-	u16				active_speed;
+	u8				active_flowctrl;
+
 	u8				active_duplex;
 #define SPEED_INVALID		0xffff
 #define DUPLEX_INVALID		0xff
 #define AUTONEG_INVALID		0xff
+	u16				active_speed;
 
 	/* When we go in and out of low power mode we need
 	 * to swap with this state.
@@ -2337,8 +2349,6 @@ struct tg3 {
 #define TG3_FLAG_EEPROM_WRITE_PROT	0x00001000
 #define TG3_FLAG_NVRAM			0x00002000
 #define TG3_FLAG_NVRAM_BUFFERED		0x00004000
-#define TG3_FLAG_RX_PAUSE		0x00008000
-#define TG3_FLAG_TX_PAUSE		0x00010000
 #define TG3_FLAG_PCIX_MODE		0x00020000
 #define TG3_FLAG_PCI_HIGH_SPEED		0x00040000
 #define TG3_FLAG_PCI_32BIT		0x00080000
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 74c1f0f189f5..e7b4adc5c4e7 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -357,7 +357,7 @@ static int __devinit olympic_init(struct net_device *dev)
 
 	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) { 
 		t=jiffies;
-		while (!readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE) { 
+		while (!(readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE)) {
 			schedule() ; 
 			if(time_after(jiffies, t + 2*HZ)) {
 				printk(KERN_ERR "IBM Cardbus tokenring adapter not responsing.\n") ; 
@@ -671,7 +671,7 @@ static int olympic_open(struct net_device *dev)
 
 	writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */
 	for(i=0;i<OLYMPIC_TX_RING_SIZE;i++) 
-		olympic_priv->olympic_tx_ring[i].buffer=0xdeadbeef;
+		olympic_priv->olympic_tx_ring[i].buffer=cpu_to_le32(0xdeadbeef);
 
 	olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE;
 	olympic_priv->tx_ring_dma_addr = pci_map_single(olympic_priv->pdev,olympic_priv->olympic_tx_ring,
@@ -897,7 +897,7 @@ static void olympic_freemem(struct net_device *dev)
 			dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]);
 			olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received] = NULL;
 		}
-		if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) {
+		if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != cpu_to_le32(0xdeadbeef)) {
 			pci_unmap_single(olympic_priv->pdev, 
 			le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer),
 			olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE);
@@ -983,7 +983,7 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id)
 					le32_to_cpu(olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer), 
 					olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len,PCI_DMA_TODEVICE);
 				dev_kfree_skb_irq(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]);
-				olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef;
+				olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=cpu_to_le32(0xdeadbeef);
 				olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0;
 			}
 			netif_wake_queue(dev);
@@ -1432,7 +1432,7 @@ static void olympic_arb_cmd(struct net_device *dev)
 			buffer_len = swab16(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
 			memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ;
 			next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); 
-		} while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr)));
+		} while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + swab16(next_ptr)));
 
 		mac_frame->protocol = tr_type_trans(mac_frame, dev);
 
diff --git a/drivers/net/tokenring/olympic.h b/drivers/net/tokenring/olympic.h
index 2fc59c997468..c91956310fb2 100644
--- a/drivers/net/tokenring/olympic.h
+++ b/drivers/net/tokenring/olympic.h
@@ -216,31 +216,31 @@
 /* xxxx These structures are all little endian in hardware. */
 
 struct olympic_tx_desc {
-	u32 buffer;
-	u32 status_length;
+	__le32 buffer;
+	__le32 status_length;
 };
 
 struct olympic_tx_status {
-	u32 status;
+	__le32 status;
 };
 
 struct olympic_rx_desc {
-	u32 buffer;
-	u32 res_length; 
+	__le32 buffer;
+	__le32 res_length; 
 };
 
 struct olympic_rx_status {
-	u32 fragmentcnt_framelen;
-	u32 status_buffercnt;
+	__le32 fragmentcnt_framelen;
+	__le32 status_buffercnt;
 };
 /* xxxx END These structures are all little endian in hardware. */
 /* xxxx There may be more, but I'm pretty sure about these */
 
 struct mac_receive_buffer {
-	u16 next ; 
+	__le16 next ; 
 	u8 padding ; 
 	u8 frame_status ;
-	u16 buffer_length ; 
+	__le16 buffer_length ; 
 	u8 frame_data ; 
 };
 
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 93da3a36cde8..8909050b8ea7 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -2310,7 +2310,7 @@ static irqreturn_t smctr_interrupt(int irq, void *dev_id)
                                                 && (tp->acb_head->subcmd
                                                 == RW_TRC_STATUS_BLOCK))
                                         {
-                                                if(tp->ptr_bcn_type != 0)
+                                                if(tp->ptr_bcn_type)
                                                 {
                                                         *(tp->ptr_bcn_type)
                                                                 = (__u32)((SBlock *)tp->misc_command_data)->BCN_Type;
@@ -2980,7 +2980,7 @@ static int smctr_load_firmware(struct net_device *dev)
                 return (UCODE_PRESENT);
 
         /* Verify the firmware exists and is there in the right amount. */
-        if((tp->ptr_ucode == 0L)
+        if (!tp->ptr_ucode
                 || (*(tp->ptr_ucode + UCODE_VERSION_OFFSET) < UCODE_VERSION))
         {
                 return (UCODE_NOT_PRESENT);
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 6e8b18a3b3cc..6c6fc325c8f9 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -4168,7 +4168,7 @@ de4x5_bad_srom(struct de4x5_private *lp)
 {
     int i, status = 0;
 
-    for (i=0; i<sizeof(enet_det)/ETH_ALEN; i++) {
+    for (i = 0; i < ARRAY_SIZE(enet_det); i++) {
 	if (!de4x5_strncmp((char *)&lp->srom, (char *)&enet_det[i], 3) &&
 	    !de4x5_strncmp((char *)&lp->srom+0x10, (char *)&enet_det[i], 3)) {
 	    if (i == 0) {
@@ -4188,7 +4188,7 @@ de4x5_strncmp(char *a, char *b, int n)
 {
     int ret=0;
 
-    for (;n && !ret;n--) {
+    for (;n && !ret; n--) {
 	ret = *a++ - *b++;
     }
 
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index b4891caeae5a..656200472fa1 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -1909,7 +1909,7 @@ static void dmfe_parse_srom(struct dmfe_board_info * db)
 	if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) {
 		/* SROM V4.01 */
 		/* Get NIC support media mode */
-		db->NIC_capability = le16_to_cpup((__le16 *)srom + 34/2);
+		db->NIC_capability = le16_to_cpup((__le16 *) (srom + 34));
 		db->PHY_reg4 = 0;
 		for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
 			switch( db->NIC_capability & tmp_reg ) {
@@ -1921,8 +1921,8 @@ static void dmfe_parse_srom(struct dmfe_board_info * db)
 		}
 
 		/* Media Mode Force or not check */
-		dmfe_mode = le32_to_cpup((__le32 *)srom + 34/4) &
-				le32_to_cpup((__le32 *)srom + 36/4);
+		dmfe_mode = (le32_to_cpup((__le32 *) (srom + 34)) &
+			     le32_to_cpup((__le32 *) (srom + 36)));
 		switch(dmfe_mode) {
 		case 0x4: dmfe_media_mode = DMFE_100MHF; break;	/* 100MHF */
 		case 0x2: dmfe_media_mode = DMFE_10MFD; break;	/* 10MFD */
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index f8b8c71187a0..46339f6bcd00 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -292,17 +292,6 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
 	return count;
 }
 
-static inline size_t iov_total(const struct iovec *iv, unsigned long count)
-{
-	unsigned long i;
-	size_t len;
-
-	for (i = 0, len = 0; i < count; i++)
-		len += iv[i].iov_len;
-
-	return len;
-}
-
 static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
 			      unsigned long count, loff_t pos)
 {
@@ -313,7 +302,7 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
 
 	DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count);
 
-	return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count));
+	return tun_get_user(tun, (struct iovec *) iv, iov_length(iv, count));
 }
 
 /* Put packet to the user space buffer */
@@ -364,7 +353,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
 
 	DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name);
 
-	len = iov_total(iv, count);
+	len = iov_length(iv, count);
 	if (len < 0)
 		return -EINVAL;
 
@@ -517,7 +506,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
 		/* Be promiscuous by default to maintain previous behaviour. */
 		tun->if_flags = IFF_PROMISC;
 		/* Generate random Ethernet address. */
-		*(u16 *)tun->dev_addr = htons(0x00FF);
+		*(__be16 *)tun->dev_addr = htons(0x00FF);
 		get_random_bytes(tun->dev_addr + sizeof(u16), 4);
 		memset(tun->chr_filter, 0, sizeof tun->chr_filter);
 
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 8d456e379a86..4ffd8739f8b7 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3614,9 +3614,6 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
 
-	if (!ugeth)
-		return IRQ_NONE;
-
 	uccf = ugeth->uccf;
 	ug_info = ugeth->ug_info;
 
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 1ffdd106f4c4..633a511d6cb6 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -101,17 +101,16 @@ static void dm_write_async_callback(struct urb *urb)
 	usb_free_urb(urb);
 }
 
-static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value,
+				  u16 length, void *data)
 {
 	struct usb_ctrlrequest *req;
 	struct urb *urb;
 	int status;
 
-	devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length);
-
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urb) {
-		deverr(dev, "Error allocating URB in dm_write_async!");
+		deverr(dev, "Error allocating URB in dm_write_async_helper!");
 		return;
 	}
 
@@ -123,8 +122,8 @@ static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
 	}
 
 	req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
-	req->bRequest = DM_WRITE_REGS;
-	req->wValue = 0;
+	req->bRequest = length ? DM_WRITE_REGS : DM_WRITE_REG;
+	req->wValue = cpu_to_le16(value);
 	req->wIndex = cpu_to_le16(reg);
 	req->wLength = cpu_to_le16(length);
 
@@ -142,45 +141,19 @@ static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
 	}
 }
 
-static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
 {
-	struct usb_ctrlrequest *req;
-	struct urb *urb;
-	int status;
+	devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length);
 
+	dm_write_async_helper(dev, reg, 0, length, data);
+}
+
+static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
 	devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x",
 	       reg, value);
 
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
-	if (!urb) {
-		deverr(dev, "Error allocating URB in dm_write_async!");
-		return;
-	}
-
-	req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
-	if (!req) {
-		deverr(dev, "Failed to allocate memory for control request");
-		usb_free_urb(urb);
-		return;
-	}
-
-	req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
-	req->bRequest = DM_WRITE_REG;
-	req->wValue = cpu_to_le16(value);
-	req->wIndex = cpu_to_le16(reg);
-	req->wLength = 0;
-
-	usb_fill_control_urb(urb, dev->udev,
-			     usb_sndctrlpipe(dev->udev, 0),
-			     (void *)req, NULL, 0, dm_write_async_callback, req);
-
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status < 0) {
-		deverr(dev, "Error submitting the control message: status=%d",
-		       status);
-		kfree(req);
-		usb_free_urb(urb);
-	}
+	dm_write_async_helper(dev, reg, value, 0, NULL);
 }
 
 static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *value)
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 07263cd93f9c..87c180b563d3 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1338,7 +1338,7 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
 				if (debug > 2 &&
 				    ioread8(ioaddr+ChipCmd) & CmdTxOn)
 					printk(KERN_WARNING "%s: "
-					       "rhine_interrupt() Tx engine"
+					       "rhine_interrupt() Tx engine "
 					       "still on.\n", dev->name);
 			}
 			rhine_tx(dev);
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index ff37bf437a99..1d706eae3052 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -395,8 +395,7 @@ static int __init cosa_init(void)
 		goto out_chrdev;
 	}
 	for (i=0; i<nr_cards; i++) {
-		class_device_create(cosa_class, NULL, MKDEV(cosa_major, i),
-				NULL, "cosa%d", i);
+		device_create(cosa_class, NULL, MKDEV(cosa_major, i), "cosa%d", i);
 	}
 	err = 0;
 	goto out;
@@ -415,7 +414,7 @@ static void __exit cosa_exit(void)
 	printk(KERN_INFO "Unloading the cosa module\n");
 
 	for (i=0; i<nr_cards; i++)
-		class_device_destroy(cosa_class, MKDEV(cosa_major, i));
+		device_destroy(cosa_class, MKDEV(cosa_major, i));
 	class_destroy(cosa_class);
 	for (cosa=cosa_cards; nr_cards--; cosa++) {
 		/* Clean up the per-channel data */
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 12dae8e24844..cf27bf40d36e 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -1498,9 +1498,9 @@ do_bottom_half_rx(struct fst_card_info *card)
  *      Dev_id is our fst_card_info pointer
  */
 static irqreturn_t
-fst_intr(int irq, void *dev_id)
+fst_intr(int dummy, void *dev_id)
 {
-	struct fst_card_info *card;
+	struct fst_card_info *card = dev_id;
 	struct fst_port_info *port;
 	int rdidx;		/* Event buffer indices */
 	int wridx;
@@ -1509,17 +1509,12 @@ fst_intr(int irq, void *dev_id)
 	unsigned int do_card_interrupt;
 	unsigned int int_retry_count;
 
-	if ((card = dev_id) == NULL) {
-		dbg(DBG_INTR, "intr: spurious %d\n", irq);
-		return IRQ_NONE;
-	}
-
 	/*
 	 * Check to see if the interrupt was for this card
 	 * return if not
 	 * Note that the call to clear the interrupt is important
 	 */
-	dbg(DBG_INTR, "intr: %d %p\n", irq, card);
+	dbg(DBG_INTR, "intr: %d %p\n", card->irq, card);
 	if (card->state != FST_RUNNING) {
 		printk_err
 		    ("Interrupt received for card %d in a non running state (%d)\n",
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 3caeb528eace..519e1550e2e7 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -42,7 +42,7 @@ static inline struct ppp_state* state(hdlc_device *hdlc)
 static int ppp_open(struct net_device *dev)
 {
 	hdlc_device *hdlc = dev_to_hdlc(dev);
-	void *old_ioctl;
+	int (*old_ioctl)(struct net_device *, struct ifreq *, int);
 	int result;
 
 	dev->priv = &state(hdlc)->syncppp_ptr;
diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c
index 1a69a9aaa9b9..8895394e6006 100644
--- a/drivers/net/wan/hdlc_raw_eth.c
+++ b/drivers/net/wan/hdlc_raw_eth.c
@@ -59,7 +59,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
 	raw_hdlc_proto new_settings;
 	hdlc_device *hdlc = dev_to_hdlc(dev);
 	int result;
-	void *old_ch_mtu;
+	int (*old_ch_mtu)(struct net_device *, int);
 	int old_qlen;
 
 	switch (ifr->ifr_settings.type) {
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 37c52e131750..6635ecef36e5 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -491,13 +491,13 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
                     int pos;
                     int timeout = 500000;
 
-                    if(xc.data == 0x0){
+                    if (!xc.data) {
                             ret = -EINVAL;
                             break;
                     }
 
                     data = kmalloc(xc.len, GFP_KERNEL);
-                    if(data == 0x0){
+                    if (!data) {
                             printk(KERN_WARNING "%s: Failed to allocate memory for copy\n", dev->name);
                             ret = -ENOMEM;
                             break;
@@ -1643,7 +1643,7 @@ static int lmc_rx (struct net_device *dev) /*fold00*/
          * just allocate an skb buff and continue.
          */
         
-        if(skb == 0x0){
+        if (!skb) {
             nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
             if (nsb) {
                 sc->lmc_rxq[i] = nsb;
diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c
index c9c878cd5c72..8aa461c941ce 100644
--- a/drivers/net/wan/lmc/lmc_media.c
+++ b/drivers/net/wan/lmc/lmc_media.c
@@ -1219,10 +1219,6 @@ lmc_t1_watchdog (lmc_softc_t * const sc)
 static void
 lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl)
 {
-  if (ctl == 0)
-    {
-      sc->ictl.keepalive_onoff = LMC_CTL_ON;
-
-      return;
-    }
+	if (!ctl)
+		sc->ictl.keepalive_onoff = LMC_CTL_ON;
 }
diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
index 426c0678d983..85315758198d 100644
--- a/drivers/net/wan/lmc/lmc_proto.c
+++ b/drivers/net/wan/lmc/lmc_proto.c
@@ -208,7 +208,7 @@ void lmc_proto_close(lmc_softc_t *sc) /*FOLD00*/
     lmc_trace(sc->lmc_device, "lmc_proto_close out");
 }
 
-unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/
+__be16 lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/
 {
     lmc_trace(sc->lmc_device, "lmc_proto_type in");
     switch(sc->if_type){
diff --git a/drivers/net/wan/lmc/lmc_proto.h b/drivers/net/wan/lmc/lmc_proto.h
index 080a55773349..ccaa69e8b3c7 100644
--- a/drivers/net/wan/lmc/lmc_proto.h
+++ b/drivers/net/wan/lmc/lmc_proto.h
@@ -8,7 +8,7 @@ void lmc_proto_reopen(lmc_softc_t *sc);
 int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd);
 void lmc_proto_open(lmc_softc_t *sc);
 void lmc_proto_close(lmc_softc_t *sc);
-unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb);
+__be16 lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb);
 void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb);
 int lmc_skb_rawpackets(char *buf, char **start, off_t offset, int len, int unused);
 
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index 99fee2f1d019..57914fbd41d3 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -2365,17 +2365,17 @@ static void falc_intr(pc300_t * card)
 
 static irqreturn_t cpc_intr(int irq, void *dev_id)
 {
-	pc300_t *card;
+	pc300_t *card = dev_id;
 	volatile ucchar plx_status;
 
-	if ((card = (pc300_t *) dev_id) == 0) {
+	if (!card) {
 #ifdef PC300_DEBUG_INTR
 		printk("cpc_intr: spurious intr %d\n", irq);
 #endif
 		return IRQ_NONE;		/* spurious intr */
 	}
 
-	if (card->hw.rambase == 0) {
+	if (!card->hw.rambase) {
 #ifdef PC300_DEBUG_INTR
 		printk("cpc_intr: spurious intr2 %d\n", irq);
 #endif
@@ -3648,7 +3648,7 @@ static void __devexit cpc_remove_one(struct pci_dev *pdev)
 {
 	pc300_t *card = pci_get_drvdata(pdev);
 
-	if (card->hw.rambase != 0) {
+	if (card->hw.rambase) {
 		int i;
 
 		/* Disable interrupts on the PCI bridge */
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index e24a7b095dd6..63abfd72542d 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -313,7 +313,7 @@ static int cpc_tty_open(struct tty_struct *tty, struct file *flip)
 	if (cpc_tty->num_open == 0) { /* first open of this tty */
 		if (!cpc_tty_area[port].buf_tx){
 			cpc_tty_area[port].buf_tx = kmalloc(CPC_TTY_MAX_MTU,GFP_KERNEL);
-			if (cpc_tty_area[port].buf_tx == 0){
+			if (!cpc_tty_area[port].buf_tx) {
 				CPC_TTY_DBG("%s: error in memory allocation\n",cpc_tty->name);
 				return -ENOMEM;
 			}
@@ -678,7 +678,7 @@ static void cpc_tty_rx_work(struct work_struct *work)
 		for (j=0; j < CPC_TTY_NPORTS; j++) {
 			cpc_tty = &cpc_tty_area[port];
 		
-			if ((buf=cpc_tty->buf_rx.first) != 0) {
+			if ((buf=cpc_tty->buf_rx.first) != NULL) {
 				if (cpc_tty->tty) {
 					ld = tty_ldisc_ref(cpc_tty->tty);
 					if (ld) {
@@ -784,7 +784,7 @@ void cpc_tty_receive(pc300dev_t *pc300dev)
 		} 
 		
 		new = kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC);
-		if (new == 0) {
+		if (!new) {
 			cpc_tty_rx_disc_frame(pc300chan);
 			continue;
 		}
@@ -863,7 +863,7 @@ void cpc_tty_receive(pc300dev_t *pc300dev)
 			} 
 			new->size = rx_len;
 			new->next = NULL;
-			if (cpc_tty->buf_rx.first == 0) {
+			if (cpc_tty->buf_rx.first == NULL) {
 				cpc_tty->buf_rx.first = new;
 				cpc_tty->buf_rx.last = new;
 			} else {
@@ -891,7 +891,7 @@ static void cpc_tty_tx_work(struct work_struct *work)
 
 	CPC_TTY_DBG("%s: cpc_tty_tx_work init\n",cpc_tty->name);
 	
-	if ((tty = cpc_tty->tty) == 0) { 
+	if ((tty = cpc_tty->tty) == NULL) { 
 		CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name);
 		return; 
 	}
@@ -1027,7 +1027,7 @@ void cpc_tty_unregister_service(pc300dev_t *pc300dev)
 	ulong flags;
 	int res;
 
-	if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == 0) { 
+	if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == NULL) {
 		CPC_TTY_DBG("%s: interface is not TTY\n", pc300dev->dev->name);
 		return; 
 	}
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 2e8b5c2de887..15d5c58e57bc 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -391,8 +391,8 @@ sbni_probe1( struct net_device  *dev,  unsigned long  ioaddr,  int  irq )
 	spin_lock_init( &nl->lock );
 
 	/* store MAC address (generate if that isn't known) */
-	*(u16 *)dev->dev_addr = htons( 0x00ff );
-	*(u32 *)(dev->dev_addr + 2) = htonl( 0x01000000 |
+	*(__be16 *)dev->dev_addr = htons( 0x00ff );
+	*(__be32 *)(dev->dev_addr + 2) = htonl( 0x01000000 |
 		( (mac[num]  ?  mac[num]  :  (u32)((long)dev->priv)) & 0x00ffffff) );
 
 	/* store link settings (speed, receive level ) */
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 05df0a345b60..73e2f2780932 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -867,7 +867,7 @@ static void sdla_receive(struct net_device *dev)
 	spin_unlock_irqrestore(&sdla_lock, flags);
 }
 
-static irqreturn_t sdla_isr(int irq, void *dev_id)
+static irqreturn_t sdla_isr(int dummy, void *dev_id)
 {
 	struct net_device     *dev;
 	struct frad_local *flp;
@@ -879,7 +879,8 @@ static irqreturn_t sdla_isr(int irq, void *dev_id)
 
 	if (!flp->initialized)
 	{
-		printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq);
+		printk(KERN_WARNING "%s: irq %d for uninitialized device.\n",
+		       dev->name, dev->irq);
 		return IRQ_NONE;
 	}
 
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index 8e320b76ae0e..d4aab8a28b61 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -715,7 +715,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
 	}
 
 	for (i = 0; i < sizeof(firmware); i += 4)
-		writel(htonl(*(u32*)(firmware + i)), mem + PDM_OFFSET + i);
+		writel(ntohl(*(__be32*)(firmware + i)), mem + PDM_OFFSET + i);
 
 	for (i = 0; i < ports; i++)
 		writel(card->status_address +
@@ -743,7 +743,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
 	}while (time_after(timeout, jiffies));
 
 	if (!stat) {
-		printk(KERN_WARNING "wanXL %s: timeout while initializing card"
+		printk(KERN_WARNING "wanXL %s: timeout while initializing card "
 		       "firmware\n", pci_name(pdev));
 		wanxl_pci_remove_one(pdev);
 		return -ENODEV;
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 2c08c0a5a0df..f372960904b2 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -545,6 +545,62 @@ config USB_ZD1201
 	  To compile this driver as a module, choose M here: the
 	  module will be called zd1201.
 
+config RTL8180
+	tristate "Realtek 8180/8185 PCI support"
+	depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
+	select EEPROM_93CX6
+	---help---
+	  This is a driver for RTL8180 and RTL8185 based cards.
+	  These are PCI based chips found in cards such as:
+
+	  (RTL8185 802.11g)
+	  A-Link WL54PC
+
+	  (RTL8180 802.11b)
+	  Belkin F5D6020 v3
+	  Belkin F5D6020 v3
+	  Dlink DWL-610
+	  Dlink DWL-510
+	  Netgear MA521
+	  Level-One WPC-0101
+	  Acer Aspire 1357 LMi
+	  VCTnet PC-11B1
+	  Ovislink AirLive WL-1120PCM
+	  Mentor WL-PCI
+	  Linksys WPC11 v4
+	  TrendNET TEW-288PI
+	  D-Link DWL-520 Rev D
+	  Repotec RP-WP7126
+	  TP-Link TL-WN250/251
+	  Zonet ZEW1000
+	  Longshine LCS-8031-R
+	  HomeLine HLW-PCC200
+	  GigaFast WF721-AEX
+	  Planet WL-3553
+	  Encore ENLWI-PCI1-NT
+	  TrendNET TEW-266PC
+	  Gigabyte GN-WLMR101
+	  Siemens-fujitsu Amilo D1840W
+	  Edimax EW-7126
+	  PheeNet WL-11PCIR
+	  Tonze PC-2100T
+	  Planet WL-8303
+	  Dlink DWL-650 v M1
+	  Edimax EW-7106
+	  Q-Tec 770WC
+	  Topcom Skyr@cer 4011b
+	  Roper FreeLan 802.11b (edition 2004)
+	  Wistron Neweb Corp CB-200B
+	  Pentagram HorNET
+	  QTec 775WC
+	  TwinMOS Booming B Series
+	  Micronet SP906BB
+	  Sweex LC700010
+	  Surecom EP-9428
+	  Safecom SWLCR-1100
+
+	  Thanks to Realtek for their support!
+
 config RTL8187
 	tristate "Realtek 8187 USB support"
 	depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
@@ -648,6 +704,23 @@ config P54_PCI
 
 	  If you choose to build a module, it'll be called p54pci.
 
+config ATH5K
+	tristate "Atheros 5xxx wireless cards support"
+	depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+	---help---
+	  This module adds support for wireless adapters based on
+	  Atheros 5xxx chipset.
+
+	  Currently the following chip versions are supported:
+
+	  MAC: AR5211 AR5212
+	  PHY: RF5111/2111 RF5112/2112 RF5413/2413
+
+	  This driver uses the kernel's mac80211 subsystem.
+
+	  If you choose to build a module, it'll be called ath5k. Say M if
+	  unsure.
+
 source "drivers/net/wireless/iwlwifi/Kconfig"
 source "drivers/net/wireless/hostap/Kconfig"
 source "drivers/net/wireless/bcm43xx/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 6f32b53ee128..6af7b158624e 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -47,14 +47,20 @@ obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
 obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
 obj-$(CONFIG_LIBERTAS)		+= libertas/
 
+rtl8180-objs		:= rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o
 rtl8187-objs		:= rtl8187_dev.o rtl8187_rtl8225.o
+
+obj-$(CONFIG_RTL8180)	+= rtl8180.o
 obj-$(CONFIG_RTL8187)	+= rtl8187.o
 
 obj-$(CONFIG_ADM8211)	+= adm8211.o
 
-obj-$(CONFIG_IWLWIFI)	+= iwlwifi/
+obj-$(CONFIG_IWL3945)	+= iwlwifi/
+obj-$(CONFIG_IWL4965)	+= iwlwifi/
 obj-$(CONFIG_RT2X00)	+= rt2x00/
 
 obj-$(CONFIG_P54_COMMON)	+= p54common.o
 obj-$(CONFIG_P54_USB)		+= p54usb.o
 obj-$(CONFIG_P54_PCI)		+= p54pci.o
+
+obj-$(CONFIG_ATH5K)	+= ath5k/
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 5bf7913aadda..79796186713e 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -104,7 +104,7 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev)
 	if (!priv->eeprom)
 		return -ENOMEM;
 
-	eeprom_93cx6_multiread(&eeprom, 0, (__le16 __force *)priv->eeprom, words);
+	eeprom_93cx6_multiread(&eeprom, 0, (__le16 *)priv->eeprom, words);
 
 	cr49 = le16_to_cpu(priv->eeprom->cr49);
 	priv->rf_type = (cr49 >> 3) & 0x7;
@@ -1312,7 +1312,8 @@ static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
 	return 0;
 }
 
-static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id,
+static int adm8211_config_interface(struct ieee80211_hw *dev,
+				    struct ieee80211_vif *vif,
 				    struct ieee80211_if_conf *conf)
 {
 	struct adm8211_priv *priv = dev->priv;
@@ -1867,9 +1868,9 @@ static int __devinit adm8211_probe(struct pci_dev *pdev,
 		goto err_iounmap;
 	}
 
-	*(u32 *)perm_addr = le32_to_cpu((__force __le32)ADM8211_CSR_READ(PAR0));
-	*(u16 *)&perm_addr[4] =
-		le16_to_cpu((__force __le16)ADM8211_CSR_READ(PAR1) & 0xFFFF);
+	*(__le32 *)perm_addr = cpu_to_le32(ADM8211_CSR_READ(PAR0));
+	*(__le16 *)&perm_addr[4] =
+		cpu_to_le16(ADM8211_CSR_READ(PAR1) & 0xFFFF);
 
 	if (!is_valid_ether_addr(perm_addr)) {
 		printk(KERN_WARNING "%s (adm8211): Invalid hwaddr in EEPROM!\n",
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 074055e18c5c..932d6b1c9d0b 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -38,6 +38,7 @@
 #include <linux/crypto.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/unaligned.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -500,140 +501,143 @@ typedef struct {
 /* This structure came from an email sent to me from an engineer at
    aironet for inclusion into this driver */
 typedef struct {
-	u16 len;
-	u16 kindex;
+	__le16 len;
+	__le16 kindex;
 	u8 mac[ETH_ALEN];
-	u16 klen;
+	__le16 klen;
 	u8 key[16];
 } WepKeyRid;
 
 /* These structures are from the Aironet's PC4500 Developers Manual */
 typedef struct {
-	u16 len;
+	__le16 len;
 	u8 ssid[32];
 } Ssid;
 
 typedef struct {
-	u16 len;
+	__le16 len;
 	Ssid ssids[3];
 } SsidRid;
 
 typedef struct {
-        u16 len;
-        u16 modulation;
-#define MOD_DEFAULT 0
-#define MOD_CCK 1
-#define MOD_MOK 2
+        __le16 len;
+        __le16 modulation;
+#define MOD_DEFAULT cpu_to_le16(0)
+#define MOD_CCK cpu_to_le16(1)
+#define MOD_MOK cpu_to_le16(2)
 } ModulationRid;
 
 typedef struct {
-	u16 len; /* sizeof(ConfigRid) */
-	u16 opmode; /* operating mode */
-#define MODE_STA_IBSS 0
-#define MODE_STA_ESS 1
-#define MODE_AP 2
-#define MODE_AP_RPTR 3
-#define MODE_ETHERNET_HOST (0<<8) /* rx payloads converted */
-#define MODE_LLC_HOST (1<<8) /* rx payloads left as is */
-#define MODE_AIRONET_EXTEND (1<<9) /* enable Aironet extenstions */
-#define MODE_AP_INTERFACE (1<<10) /* enable ap interface extensions */
-#define MODE_ANTENNA_ALIGN (1<<11) /* enable antenna alignment */
-#define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */
-#define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */
-#define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */
-#define MODE_MIC (1<<15) /* enable MIC */
-	u16 rmode; /* receive mode */
-#define RXMODE_BC_MC_ADDR 0
-#define RXMODE_BC_ADDR 1 /* ignore multicasts */
-#define RXMODE_ADDR 2 /* ignore multicast and broadcast */
-#define RXMODE_RFMON 3 /* wireless monitor mode */
-#define RXMODE_RFMON_ANYBSS 4
-#define RXMODE_LANMON 5 /* lan style monitor -- data packets only */
-#define RXMODE_DISABLE_802_3_HEADER (1<<8) /* disables 802.3 header on rx */
-#define RXMODE_NORMALIZED_RSSI (1<<9) /* return normalized RSSI */
-	u16 fragThresh;
-	u16 rtsThres;
+	__le16 len; /* sizeof(ConfigRid) */
+	__le16 opmode; /* operating mode */
+#define MODE_STA_IBSS cpu_to_le16(0)
+#define MODE_STA_ESS cpu_to_le16(1)
+#define MODE_AP cpu_to_le16(2)
+#define MODE_AP_RPTR cpu_to_le16(3)
+#define MODE_CFG_MASK cpu_to_le16(0xff)
+#define MODE_ETHERNET_HOST cpu_to_le16(0<<8) /* rx payloads converted */
+#define MODE_LLC_HOST cpu_to_le16(1<<8) /* rx payloads left as is */
+#define MODE_AIRONET_EXTEND cpu_to_le16(1<<9) /* enable Aironet extenstions */
+#define MODE_AP_INTERFACE cpu_to_le16(1<<10) /* enable ap interface extensions */
+#define MODE_ANTENNA_ALIGN cpu_to_le16(1<<11) /* enable antenna alignment */
+#define MODE_ETHER_LLC cpu_to_le16(1<<12) /* enable ethernet LLC */
+#define MODE_LEAF_NODE cpu_to_le16(1<<13) /* enable leaf node bridge */
+#define MODE_CF_POLLABLE cpu_to_le16(1<<14) /* enable CF pollable */
+#define MODE_MIC cpu_to_le16(1<<15) /* enable MIC */
+	__le16 rmode; /* receive mode */
+#define RXMODE_BC_MC_ADDR cpu_to_le16(0)
+#define RXMODE_BC_ADDR cpu_to_le16(1) /* ignore multicasts */
+#define RXMODE_ADDR cpu_to_le16(2) /* ignore multicast and broadcast */
+#define RXMODE_RFMON cpu_to_le16(3) /* wireless monitor mode */
+#define RXMODE_RFMON_ANYBSS cpu_to_le16(4)
+#define RXMODE_LANMON cpu_to_le16(5) /* lan style monitor -- data packets only */
+#define RXMODE_MASK cpu_to_le16(255)
+#define RXMODE_DISABLE_802_3_HEADER cpu_to_le16(1<<8) /* disables 802.3 header on rx */
+#define RXMODE_FULL_MASK (RXMODE_MASK | RXMODE_DISABLE_802_3_HEADER)
+#define RXMODE_NORMALIZED_RSSI cpu_to_le16(1<<9) /* return normalized RSSI */
+	__le16 fragThresh;
+	__le16 rtsThres;
 	u8 macAddr[ETH_ALEN];
 	u8 rates[8];
-	u16 shortRetryLimit;
-	u16 longRetryLimit;
-	u16 txLifetime; /* in kusec */
-	u16 rxLifetime; /* in kusec */
-	u16 stationary;
-	u16 ordering;
-	u16 u16deviceType; /* for overriding device type */
-	u16 cfpRate;
-	u16 cfpDuration;
-	u16 _reserved1[3];
+	__le16 shortRetryLimit;
+	__le16 longRetryLimit;
+	__le16 txLifetime; /* in kusec */
+	__le16 rxLifetime; /* in kusec */
+	__le16 stationary;
+	__le16 ordering;
+	__le16 u16deviceType; /* for overriding device type */
+	__le16 cfpRate;
+	__le16 cfpDuration;
+	__le16 _reserved1[3];
 	/*---------- Scanning/Associating ----------*/
-	u16 scanMode;
-#define SCANMODE_ACTIVE 0
-#define SCANMODE_PASSIVE 1
-#define SCANMODE_AIROSCAN 2
-	u16 probeDelay; /* in kusec */
-	u16 probeEnergyTimeout; /* in kusec */
-        u16 probeResponseTimeout;
-	u16 beaconListenTimeout;
-	u16 joinNetTimeout;
-	u16 authTimeout;
-	u16 authType;
-#define AUTH_OPEN 0x1
-#define AUTH_ENCRYPT 0x101
-#define AUTH_SHAREDKEY 0x102
-#define AUTH_ALLOW_UNENCRYPTED 0x200
-	u16 associationTimeout;
-	u16 specifiedApTimeout;
-	u16 offlineScanInterval;
-	u16 offlineScanDuration;
-	u16 linkLossDelay;
-	u16 maxBeaconLostTime;
-	u16 refreshInterval;
-#define DISABLE_REFRESH 0xFFFF
-	u16 _reserved1a[1];
+	__le16 scanMode;
+#define SCANMODE_ACTIVE cpu_to_le16(0)
+#define SCANMODE_PASSIVE cpu_to_le16(1)
+#define SCANMODE_AIROSCAN cpu_to_le16(2)
+	__le16 probeDelay; /* in kusec */
+	__le16 probeEnergyTimeout; /* in kusec */
+        __le16 probeResponseTimeout;
+	__le16 beaconListenTimeout;
+	__le16 joinNetTimeout;
+	__le16 authTimeout;
+	__le16 authType;
+#define AUTH_OPEN cpu_to_le16(0x1)
+#define AUTH_ENCRYPT cpu_to_le16(0x101)
+#define AUTH_SHAREDKEY cpu_to_le16(0x102)
+#define AUTH_ALLOW_UNENCRYPTED cpu_to_le16(0x200)
+	__le16 associationTimeout;
+	__le16 specifiedApTimeout;
+	__le16 offlineScanInterval;
+	__le16 offlineScanDuration;
+	__le16 linkLossDelay;
+	__le16 maxBeaconLostTime;
+	__le16 refreshInterval;
+#define DISABLE_REFRESH cpu_to_le16(0xFFFF)
+	__le16 _reserved1a[1];
 	/*---------- Power save operation ----------*/
-	u16 powerSaveMode;
-#define POWERSAVE_CAM 0
-#define POWERSAVE_PSP 1
-#define POWERSAVE_PSPCAM 2
-	u16 sleepForDtims;
-	u16 listenInterval;
-	u16 fastListenInterval;
-	u16 listenDecay;
-	u16 fastListenDelay;
-	u16 _reserved2[2];
+	__le16 powerSaveMode;
+#define POWERSAVE_CAM cpu_to_le16(0)
+#define POWERSAVE_PSP cpu_to_le16(1)
+#define POWERSAVE_PSPCAM cpu_to_le16(2)
+	__le16 sleepForDtims;
+	__le16 listenInterval;
+	__le16 fastListenInterval;
+	__le16 listenDecay;
+	__le16 fastListenDelay;
+	__le16 _reserved2[2];
 	/*---------- Ap/Ibss config items ----------*/
-	u16 beaconPeriod;
-	u16 atimDuration;
-	u16 hopPeriod;
-	u16 channelSet;
-	u16 channel;
-	u16 dtimPeriod;
-	u16 bridgeDistance;
-	u16 radioID;
+	__le16 beaconPeriod;
+	__le16 atimDuration;
+	__le16 hopPeriod;
+	__le16 channelSet;
+	__le16 channel;
+	__le16 dtimPeriod;
+	__le16 bridgeDistance;
+	__le16 radioID;
 	/*---------- Radio configuration ----------*/
-	u16 radioType;
-#define RADIOTYPE_DEFAULT 0
-#define RADIOTYPE_802_11 1
-#define RADIOTYPE_LEGACY 2
+	__le16 radioType;
+#define RADIOTYPE_DEFAULT cpu_to_le16(0)
+#define RADIOTYPE_802_11 cpu_to_le16(1)
+#define RADIOTYPE_LEGACY cpu_to_le16(2)
 	u8 rxDiversity;
 	u8 txDiversity;
-	u16 txPower;
+	__le16 txPower;
 #define TXPOWER_DEFAULT 0
-	u16 rssiThreshold;
+	__le16 rssiThreshold;
 #define RSSI_DEFAULT 0
-        u16 modulation;
-#define PREAMBLE_AUTO 0
-#define PREAMBLE_LONG 1
-#define PREAMBLE_SHORT 2
-	u16 preamble;
-	u16 homeProduct;
-	u16 radioSpecific;
+        __le16 modulation;
+#define PREAMBLE_AUTO cpu_to_le16(0)
+#define PREAMBLE_LONG cpu_to_le16(1)
+#define PREAMBLE_SHORT cpu_to_le16(2)
+	__le16 preamble;
+	__le16 homeProduct;
+	__le16 radioSpecific;
 	/*---------- Aironet Extensions ----------*/
 	u8 nodeName[16];
-	u16 arlThreshold;
-	u16 arlDecay;
-	u16 arlDelay;
-	u16 _reserved4[1];
+	__le16 arlThreshold;
+	__le16 arlDecay;
+	__le16 arlDelay;
+	__le16 _reserved4[1];
 	/*---------- Aironet Extensions ----------*/
 	u8 magicAction;
 #define MAGIC_ACTION_STSCHG 1
@@ -643,34 +647,34 @@ typedef struct {
 #define MAGIC_SWITCH_TO_PSP (0<<10)
 #define MAGIC_STAY_IN_CAM (1<<10)
 	u8 magicControl;
-	u16 autoWake;
+	__le16 autoWake;
 } ConfigRid;
 
 typedef struct {
-	u16 len;
+	__le16 len;
 	u8 mac[ETH_ALEN];
-	u16 mode;
-	u16 errorCode;
-	u16 sigQuality;
-	u16 SSIDlen;
+	__le16 mode;
+	__le16 errorCode;
+	__le16 sigQuality;
+	__le16 SSIDlen;
 	char SSID[32];
 	char apName[16];
 	u8 bssid[4][ETH_ALEN];
-	u16 beaconPeriod;
-	u16 dimPeriod;
-	u16 atimDuration;
-	u16 hopPeriod;
-	u16 channelSet;
-	u16 channel;
-	u16 hopsToBackbone;
-	u16 apTotalLoad;
-	u16 generatedLoad;
-	u16 accumulatedArl;
-	u16 signalQuality;
-	u16 currentXmitRate;
-	u16 apDevExtensions;
-	u16 normalizedSignalStrength;
-	u16 shortPreamble;
+	__le16 beaconPeriod;
+	__le16 dimPeriod;
+	__le16 atimDuration;
+	__le16 hopPeriod;
+	__le16 channelSet;
+	__le16 channel;
+	__le16 hopsToBackbone;
+	__le16 apTotalLoad;
+	__le16 generatedLoad;
+	__le16 accumulatedArl;
+	__le16 signalQuality;
+	__le16 currentXmitRate;
+	__le16 apDevExtensions;
+	__le16 normalizedSignalStrength;
+	__le16 shortPreamble;
 	u8 apIP[4];
 	u8 noisePercent; /* Noise percent in last second */
 	u8 noisedBm; /* Noise dBm in last second */
@@ -678,9 +682,9 @@ typedef struct {
 	u8 noiseAvedBm; /* Noise dBm in last minute */
 	u8 noiseMaxPercent; /* Highest noise percent in last minute */
 	u8 noiseMaxdBm; /* Highest noise dbm in last minute */
-	u16 load;
+	__le16 load;
 	u8 carrier[4];
-	u16 assocStatus;
+	__le16 assocStatus;
 #define STAT_NOPACKETS 0
 #define STAT_NOCARRIERSET 10
 #define STAT_GOTCARRIERSET 11
@@ -705,82 +709,82 @@ typedef struct {
 } StatusRid;
 
 typedef struct {
-	u16 len;
-	u16 spacer;
-	u32 vals[100];
+	__le16 len;
+	__le16 spacer;
+	__le32 vals[100];
 } StatsRid;
 
 
 typedef struct {
-	u16 len;
+	__le16 len;
 	u8 ap[4][ETH_ALEN];
 } APListRid;
 
 typedef struct {
-	u16 len;
+	__le16 len;
 	char oui[3];
 	char zero;
-	u16 prodNum;
+	__le16 prodNum;
 	char manName[32];
 	char prodName[16];
 	char prodVer[8];
 	char factoryAddr[ETH_ALEN];
 	char aironetAddr[ETH_ALEN];
-	u16 radioType;
-	u16 country;
+	__le16 radioType;
+	__le16 country;
 	char callid[ETH_ALEN];
 	char supportedRates[8];
 	char rxDiversity;
 	char txDiversity;
-	u16 txPowerLevels[8];
-	u16 hardVer;
-	u16 hardCap;
-	u16 tempRange;
-	u16 softVer;
-	u16 softSubVer;
-	u16 interfaceVer;
-	u16 softCap;
-	u16 bootBlockVer;
-	u16 requiredHard;
-	u16 extSoftCap;
+	__le16 txPowerLevels[8];
+	__le16 hardVer;
+	__le16 hardCap;
+	__le16 tempRange;
+	__le16 softVer;
+	__le16 softSubVer;
+	__le16 interfaceVer;
+	__le16 softCap;
+	__le16 bootBlockVer;
+	__le16 requiredHard;
+	__le16 extSoftCap;
 } CapabilityRid;
 
 
 /* Only present on firmware >= 5.30.17 */
 typedef struct {
-  u16 unknown[4];
+  __le16 unknown[4];
   u8 fixed[12]; /* WLAN management frame */
   u8 iep[624];
 } BSSListRidExtra;
 
 typedef struct {
-  u16 len;
-  u16 index; /* First is 0 and 0xffff means end of list */
+  __le16 len;
+  __le16 index; /* First is 0 and 0xffff means end of list */
 #define RADIO_FH 1 /* Frequency hopping radio type */
 #define RADIO_DS 2 /* Direct sequence radio type */
 #define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
-  u16 radioType;
+  __le16 radioType;
   u8 bssid[ETH_ALEN]; /* Mac address of the BSS */
   u8 zero;
   u8 ssidLen;
   u8 ssid[32];
-  u16 dBm;
-#define CAP_ESS (1<<0)
-#define CAP_IBSS (1<<1)
-#define CAP_PRIVACY (1<<4)
-#define CAP_SHORTHDR (1<<5)
-  u16 cap;
-  u16 beaconInterval;
+  __le16 dBm;
+#define CAP_ESS cpu_to_le16(1<<0)
+#define CAP_IBSS cpu_to_le16(1<<1)
+#define CAP_PRIVACY cpu_to_le16(1<<4)
+#define CAP_SHORTHDR cpu_to_le16(1<<5)
+  __le16 cap;
+  __le16 beaconInterval;
   u8 rates[8]; /* Same as rates for config rid */
   struct { /* For frequency hopping only */
-    u16 dwell;
+    __le16 dwell;
     u8 hopSet;
     u8 hopPattern;
     u8 hopIndex;
     u8 fill;
   } fh;
-  u16 dsChannel;
-  u16 atimWindow;
+  __le16 dsChannel;
+  __le16 atimWindow;
 
   /* Only present on firmware >= 5.30.17 */
   BSSListRidExtra extra;
@@ -811,7 +815,7 @@ typedef struct {
 } MICRid;
 
 typedef struct {
-	u16 typelen;
+	__be16 typelen;
 
 	union {
 	    u8 snap[8];
@@ -823,8 +827,8 @@ typedef struct {
 		u8 fieldtype[2];
 	    } llc;
 	} u;
-	u32 mic;
-	u32 seq;
+	__be32 mic;
+	__be32 seq;
 } MICBuffer;
 
 typedef struct {
@@ -943,7 +947,7 @@ typedef struct {
 	int position;	// current position (byte offset) in message
 	union {
 		u8  d8[4];
-		u32 d32;
+		__be32 d32;
 	} part;	// saves partial message word across update() calls
 } emmh32_context;
 
@@ -1100,11 +1104,11 @@ static void enable_interrupts(struct airo_info*);
 static void disable_interrupts(struct airo_info*);
 static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
 static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
-static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
+static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
 			int whichbap);
-static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
+static int fast_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
 			 int whichbap);
-static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
+static int bap_write(struct airo_info*, const __le16 *pu16Src, int bytelen,
 		     int whichbap);
 static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
 static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock);
@@ -1187,7 +1191,7 @@ struct airo_info {
 #define JOB_WSTATS	8
 #define JOB_SCAN_RESULTS  9
 	unsigned long jobs;
-	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
+	int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen,
 			int whichbap);
 	unsigned short *flash;
 	tdsRssiEntry *rssi;
@@ -1235,8 +1239,9 @@ struct airo_info {
 	BSSListElement *networks;
 };
 
-static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
-			   int whichbap) {
+static inline int bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen,
+			   int whichbap)
+{
 	return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
 }
 
@@ -1635,7 +1640,7 @@ static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
 		crypto_cipher_encrypt_one(tfm, plain, plain);
 		cipher = plain;
 		for (j = 0; (j < 16) && (i < ARRAY_SIZE(context->coeff)); ) {
-			context->coeff[i++] = ntohl(*(u32 *)&cipher[j]);
+			context->coeff[i++] = ntohl(*(__be32 *)&cipher[j]);
 			j += 4;
 		}
 	}
@@ -1668,12 +1673,12 @@ static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
 			context->position++;
 			len--;
 		} while (byte_position < 4);
-		MIC_ACCUM(htonl(context->part.d32));
+		MIC_ACCUM(ntohl(context->part.d32));
 	}
 
 	/* deal with full 32-bit words */
 	while (len >= 4) {
-		MIC_ACCUM(htonl(*(u32 *)pOctets));
+		MIC_ACCUM(ntohl(*(__be32 *)pOctets));
 		context->position += 4;
 		pOctets += 4;
 		len -= 4;
@@ -1706,7 +1711,7 @@ static void emmh32_final(emmh32_context *context, u8 digest[4])
 	byte_position = context->position & 3;
 	if (byte_position) {
 		/* have a partial word in part to deal with */
-		val = htonl(context->part.d32);
+		val = ntohl(context->part.d32);
 		MIC_ACCUM(val & mask32[byte_position]);	/* zero empty bytes */
 	}
 
@@ -1726,8 +1731,8 @@ static void emmh32_final(emmh32_context *context, u8 digest[4])
 }
 
 static int readBSSListRid(struct airo_info *ai, int first,
-		      BSSListRid *list) {
-	int rc;
+		      BSSListRid *list)
+{
 	Cmd cmd;
 	Resp rsp;
 
@@ -1744,75 +1749,43 @@ static int readBSSListRid(struct airo_info *ai, int first,
 		schedule_timeout_uninterruptible(3 * HZ);
 		ai->list_bss_task = NULL;
 	}
-	rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
+	return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
 			    list, ai->bssListRidLen, 1);
-
-	list->len = le16_to_cpu(list->len);
-	list->index = le16_to_cpu(list->index);
-	list->radioType = le16_to_cpu(list->radioType);
-	list->cap = le16_to_cpu(list->cap);
-	list->beaconInterval = le16_to_cpu(list->beaconInterval);
-	list->fh.dwell = le16_to_cpu(list->fh.dwell);
-	list->dsChannel = le16_to_cpu(list->dsChannel);
-	list->atimWindow = le16_to_cpu(list->atimWindow);
-	list->dBm = le16_to_cpu(list->dBm);
-	return rc;
 }
 
-static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp, int lock) {
-	int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
+static int readWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int temp, int lock)
+{
+	return PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
 				wkr, sizeof(*wkr), lock);
-
-	wkr->len = le16_to_cpu(wkr->len);
-	wkr->kindex = le16_to_cpu(wkr->kindex);
-	wkr->klen = le16_to_cpu(wkr->klen);
-	return rc;
 }
-/* In the writeXXXRid routines we copy the rids so that we don't screwup
- * the originals when we endian them... */
-static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lock) {
-	int rc;
-	WepKeyRid wkr = *pwkr;
 
-	wkr.len = cpu_to_le16(wkr.len);
-	wkr.kindex = cpu_to_le16(wkr.kindex);
-	wkr.klen = cpu_to_le16(wkr.klen);
-	rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock);
-	if (rc!=SUCCESS) airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc);
+static int writeWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int perm, int lock)
+{
+	int rc;
+	rc = PC4500_writerid(ai, RID_WEP_TEMP, wkr, sizeof(*wkr), lock);
+	if (rc!=SUCCESS)
+		airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc);
 	if (perm) {
-		rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock);
-		if (rc!=SUCCESS) {
+		rc = PC4500_writerid(ai, RID_WEP_PERM, wkr, sizeof(*wkr), lock);
+		if (rc!=SUCCESS)
 			airo_print_err(ai->dev->name, "WEP_PERM set %x", rc);
-		}
 	}
 	return rc;
 }
 
-static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) {
-	int i;
-	int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
-
-	ssidr->len = le16_to_cpu(ssidr->len);
-	for(i = 0; i < 3; i++) {
-		ssidr->ssids[i].len = le16_to_cpu(ssidr->ssids[i].len);
-	}
-	return rc;
+static int readSsidRid(struct airo_info*ai, SsidRid *ssidr)
+{
+	return PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
 }
-static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) {
-	int rc;
-	int i;
-	SsidRid ssidr = *pssidr;
 
-	ssidr.len = cpu_to_le16(ssidr.len);
-	for(i = 0; i < 3; i++) {
-		ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len);
-	}
-	rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr), lock);
-	return rc;
+static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock)
+{
+	return PC4500_writerid(ai, RID_SSID, pssidr, sizeof(*pssidr), lock);
 }
-static int readConfigRid(struct airo_info*ai, int lock) {
+
+static int readConfigRid(struct airo_info *ai, int lock)
+{
 	int rc;
-	u16 *s;
 	ConfigRid cfg;
 
 	if (ai->config.len)
@@ -1822,24 +1795,12 @@ static int readConfigRid(struct airo_info*ai, int lock) {
 	if (rc != SUCCESS)
 		return rc;
 
-	for(s = &cfg.len; s <= &cfg.rtsThres; s++) *s = le16_to_cpu(*s);
-
-	for(s = &cfg.shortRetryLimit; s <= &cfg.radioType; s++)
-		*s = le16_to_cpu(*s);
-
-	for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++)
-		*s = le16_to_cpu(*s);
-
-	for(s = &cfg.arlThreshold; s <= &cfg._reserved4[0]; s++)
-		*s = cpu_to_le16(*s);
-
-	for(s = &cfg.autoWake; s <= &cfg.autoWake; s++)
-		*s = cpu_to_le16(*s);
-
 	ai->config = cfg;
 	return SUCCESS;
 }
-static inline void checkThrottle(struct airo_info *ai) {
+
+static inline void checkThrottle(struct airo_info *ai)
+{
 	int i;
 /* Old hardware had a limit on encryption speed */
 	if (ai->config.authType != AUTH_OPEN && maxencrypt) {
@@ -1850,8 +1811,9 @@ static inline void checkThrottle(struct airo_info *ai) {
 		}
 	}
 }
-static int writeConfigRid(struct airo_info*ai, int lock) {
-	u16 *s;
+
+static int writeConfigRid(struct airo_info *ai, int lock)
+{
 	ConfigRid cfgr;
 
 	if (!test_bit (FLAG_COMMIT, &ai->flags))
@@ -1862,70 +1824,37 @@ static int writeConfigRid(struct airo_info*ai, int lock) {
 	checkThrottle(ai);
 	cfgr = ai->config;
 
-	if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS)
+	if ((cfgr.opmode & MODE_CFG_MASK) == MODE_STA_IBSS)
 		set_bit(FLAG_ADHOC, &ai->flags);
 	else
 		clear_bit(FLAG_ADHOC, &ai->flags);
 
-	for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
-
-	for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++)
-		*s = cpu_to_le16(*s);
-
-	for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++)
-		*s = cpu_to_le16(*s);
-
-	for(s = &cfgr.arlThreshold; s <= &cfgr._reserved4[0]; s++)
-		*s = cpu_to_le16(*s);
-
-	for(s = &cfgr.autoWake; s <= &cfgr.autoWake; s++)
-		*s = cpu_to_le16(*s);
-
 	return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
 }
-static int readStatusRid(struct airo_info*ai, StatusRid *statr, int lock) {
-	int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock);
-	u16 *s;
 
-	statr->len = le16_to_cpu(statr->len);
-	for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s);
-
-	for(s = &statr->beaconPeriod; s <= &statr->shortPreamble; s++)
-		*s = le16_to_cpu(*s);
-	statr->load = le16_to_cpu(statr->load);
-	statr->assocStatus = le16_to_cpu(statr->assocStatus);
-	return rc;
+static int readStatusRid(struct airo_info *ai, StatusRid *statr, int lock)
+{
+	return PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock);
 }
-static int readAPListRid(struct airo_info*ai, APListRid *aplr) {
-	int rc =  PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
-	aplr->len = le16_to_cpu(aplr->len);
-	return rc;
+
+static int readAPListRid(struct airo_info *ai, APListRid *aplr)
+{
+	return PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
 }
-static int writeAPListRid(struct airo_info*ai, APListRid *aplr, int lock) {
-	int rc;
-	aplr->len = cpu_to_le16(aplr->len);
-	rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock);
-	return rc;
+
+static int writeAPListRid(struct airo_info *ai, APListRid *aplr, int lock)
+{
+	return PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock);
 }
-static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr, int lock) {
-	int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock);
-	u16 *s;
 
-	capr->len = le16_to_cpu(capr->len);
-	capr->prodNum = le16_to_cpu(capr->prodNum);
-	capr->radioType = le16_to_cpu(capr->radioType);
-	capr->country = le16_to_cpu(capr->country);
-	for(s = &capr->txPowerLevels[0]; s <= &capr->requiredHard; s++)
-		*s = le16_to_cpu(*s);
-	return rc;
+static int readCapabilityRid(struct airo_info *ai, CapabilityRid *capr, int lock)
+{
+	return PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock);
 }
-static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) {
-	int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
-	u32 *i;
 
-	sr->len = le16_to_cpu(sr->len);
-	for(i = &sr->vals[0]; i <= &sr->vals[99]; i++) *i = le32_to_cpu(*i);
-	return rc;
+static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock)
+{
+	return PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
 }
 
 static void try_auto_wep(struct airo_info *ai)
@@ -2026,13 +1955,14 @@ static int mpi_send_packet (struct net_device *dev)
 {
 	struct sk_buff *skb;
 	unsigned char *buffer;
-	s16 len, *payloadLen;
+	s16 len;
+	__le16 *payloadLen;
 	struct airo_info *ai = dev->priv;
 	u8 *sendbuf;
 
 	/* get a packet to send */
 
-	if ((skb = skb_dequeue(&ai->txq)) == 0) {
+	if ((skb = skb_dequeue(&ai->txq)) == NULL) {
 		airo_print_err(dev->name,
 			"%s: Dequeue'd zero in send_packet()",
 			__FUNCTION__);
@@ -2059,7 +1989,7 @@ static int mpi_send_packet (struct net_device *dev)
 	memcpy((char *)ai->txfids[0].virtual_host_addr,
 		(char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
 
-	payloadLen = (s16 *)(ai->txfids[0].virtual_host_addr +
+	payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr +
 		sizeof(wifictlhdr8023));
 	sendbuf = ai->txfids[0].virtual_host_addr +
 		sizeof(wifictlhdr8023) + 2 ;
@@ -2069,7 +1999,7 @@ static int mpi_send_packet (struct net_device *dev)
 	 * we don't need to account for it in the length
 	 */
 	if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
-		(ntohs(((u16 *)buffer)[6]) != 0x888E)) {
+		(ntohs(((__be16 *)buffer)[6]) != 0x888E)) {
 		MICBuffer pMic;
 
 		if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS)
@@ -2104,7 +2034,7 @@ static int mpi_send_packet (struct net_device *dev)
 
 static void get_tx_error(struct airo_info *ai, s32 fid)
 {
-	u16 status;
+	__le16 status;
 
 	if (fid < 0)
 		status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status;
@@ -2135,7 +2065,7 @@ static void get_tx_error(struct airo_info *ai, s32 fid)
 		/* Faster to skip over useless data than to do
 		 * another bap_setup(). We are at offset 0x6 and
 		 * need to go to 0x18 and read 6 bytes - Jean II */
-		bap_read(ai, (u16 *) junk, 0x18, BAP0);
+		bap_read(ai, (__le16 *) junk, 0x18, BAP0);
 
 		/* Copy 802.11 dest address.
 		 * We use the 802.11 header because the frame may
@@ -2289,9 +2219,10 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
 	return 0;
 }
 
-static void airo_read_stats(struct airo_info *ai) {
+static void airo_read_stats(struct airo_info *ai)
+{
 	StatsRid stats_rid;
-	u32 *vals = stats_rid.vals;
+	__le32 *vals = stats_rid.vals;
 
 	clear_bit(JOB_STATS, &ai->jobs);
 	if (ai->power.event) {
@@ -2301,20 +2232,23 @@ static void airo_read_stats(struct airo_info *ai) {
 	readStatsRid(ai, &stats_rid, RID_STATS, 0);
 	up(&ai->sem);
 
-	ai->stats.rx_packets = vals[43] + vals[44] + vals[45];
-	ai->stats.tx_packets = vals[39] + vals[40] + vals[41];
-	ai->stats.rx_bytes = vals[92];
-	ai->stats.tx_bytes = vals[91];
-	ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
-	ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors;
-	ai->stats.multicast = vals[43];
-	ai->stats.collisions = vals[89];
+	ai->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) +
+			       le32_to_cpu(vals[45]);
+	ai->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) +
+			       le32_to_cpu(vals[41]);
+	ai->stats.rx_bytes = le32_to_cpu(vals[92]);
+	ai->stats.tx_bytes = le32_to_cpu(vals[91]);
+	ai->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) +
+			      le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]);
+	ai->stats.tx_errors = le32_to_cpu(vals[42]) + ai->stats.tx_fifo_errors;
+	ai->stats.multicast = le32_to_cpu(vals[43]);
+	ai->stats.collisions = le32_to_cpu(vals[89]);
 
 	/* detailed rx_errors: */
-	ai->stats.rx_length_errors = vals[3];
-	ai->stats.rx_crc_errors = vals[4];
-	ai->stats.rx_frame_errors = vals[2];
-	ai->stats.rx_fifo_errors = vals[0];
+	ai->stats.rx_length_errors = le32_to_cpu(vals[3]);
+	ai->stats.rx_crc_errors = le32_to_cpu(vals[4]);
+	ai->stats.rx_frame_errors = le32_to_cpu(vals[2]);
+	ai->stats.rx_fifo_errors = le32_to_cpu(vals[0]);
 }
 
 static struct net_device_stats *airo_get_stats(struct net_device *dev)
@@ -2801,8 +2735,9 @@ static int airo_test_wpa_capable(struct airo_info *ai)
 	if (status != SUCCESS) return 0;
 
 	/* Only firmware versions 5.30.17 or better can do WPA */
-	if ((cap_rid.softVer > 0x530)
-	  || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) {
+	if (le16_to_cpu(cap_rid.softVer) > 0x530
+	  || (le16_to_cpu(cap_rid.softVer) == 0x530
+	      && le16_to_cpu(cap_rid.softSubVer) >= 17)) {
 		airo_print_info("", "WPA is supported.");
 		return 1;
 	}
@@ -3037,14 +2972,14 @@ static void airo_process_scan_results (struct airo_info *ai) {
 
 	/* Try to read the first entry of the scan result */
 	rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0);
-	if((rc) || (bss.index == 0xffff)) {
+	if((rc) || (bss.index == cpu_to_le16(0xffff))) {
 		/* No scan results */
 		goto out;
 	}
 
 	/* Read and parse all entries */
 	tmp_net = NULL;
-	while((!rc) && (bss.index != 0xffff)) {
+	while((!rc) && (bss.index != cpu_to_le16(0xffff))) {
 		/* Grab a network off the free list */
 		if (!list_empty(&ai->network_free_list)) {
 			tmp_net = list_entry(ai->network_free_list.next,
@@ -3177,8 +3112,24 @@ static int airo_thread(void *data) {
 	return 0;
 }
 
-static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
-	struct net_device *dev = (struct net_device *)dev_id;
+static int header_len(__le16 ctl)
+{
+	u16 fc = le16_to_cpu(ctl);
+	switch (fc & 0xc) {
+	case 4:
+		if ((fc & 0xe0) == 0xc0)
+			return 10;	/* one-address control packet */
+		return 16;	/* two-address control packet */
+	case 8:
+		if ((fc & 0x300) == 0x300)
+			return 30;	/* WDS packet */
+	}
+	return 24;
+}
+
+static irqreturn_t airo_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
 	u16 status;
 	u16 fid;
 	struct airo_info *apriv = dev->priv;
@@ -3281,19 +3232,20 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
 		/* Check to see if there is something to receive */
 		if ( status & EV_RX  ) {
 			struct sk_buff *skb = NULL;
-			u16 fc, len, hdrlen = 0;
+			__le16 fc, v;
+			u16 len, hdrlen = 0;
 #pragma pack(1)
 			struct {
-				u16 status, len;
+				__le16 status, len;
 				u8 rssi[2];
 				u8 rate;
 				u8 freq;
-				u16 tmp[4];
+				__le16 tmp[4];
 			} hdr;
 #pragma pack()
 			u16 gap;
-			u16 tmpbuf[4];
-			u16 *buffer;
+			__le16 tmpbuf[4];
+			__le16 *buffer;
 
 			if (test_bit(FLAG_MPI,&apriv->flags)) {
 				if (test_bit(FLAG_802_11, &apriv->flags))
@@ -3309,7 +3261,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
 			/* Get the packet length */
 			if (test_bit(FLAG_802_11, &apriv->flags)) {
 				bap_setup (apriv, fid, 4, BAP0);
-				bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
+				bap_read (apriv, (__le16*)&hdr, sizeof(hdr), BAP0);
 				/* Bad CRC. Ignore packet */
 				if (le16_to_cpu(hdr.status) & 2)
 					hdr.len = 0;
@@ -3317,7 +3269,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
 					hdr.len = 0;
 			} else {
 				bap_setup (apriv, fid, 0x36, BAP0);
-				bap_read (apriv, (u16*)&hdr.len, 2, BAP0);
+				bap_read (apriv, &hdr.len, 2, BAP0);
 			}
 			len = le16_to_cpu(hdr.len);
 
@@ -3329,23 +3281,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
 				goto badrx;
 
 			if (test_bit(FLAG_802_11, &apriv->flags)) {
-				bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
-				fc = le16_to_cpu(fc);
-				switch (fc & 0xc) {
-					case 4:
-						if ((fc & 0xe0) == 0xc0)
-							hdrlen = 10;
-						else
-							hdrlen = 16;
-						break;
-					case 8:
-						if ((fc&0x300)==0x300){
-							hdrlen = 30;
-							break;
-						}
-					default:
-						hdrlen = 24;
-				}
+				bap_read (apriv, &fc, sizeof(fc), BAP0);
+				hdrlen = header_len(fc);
 			} else
 				hdrlen = ETH_ALEN * 2;
 
@@ -3355,15 +3292,15 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
 				goto badrx;
 			}
 			skb_reserve(skb, 2); /* This way the IP header is aligned */
-			buffer = (u16*)skb_put (skb, len + hdrlen);
+			buffer = (__le16*)skb_put (skb, len + hdrlen);
 			if (test_bit(FLAG_802_11, &apriv->flags)) {
 				buffer[0] = fc;
 				bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
 				if (hdrlen == 24)
 					bap_read (apriv, tmpbuf, 6, BAP0);
 
-				bap_read (apriv, &gap, sizeof(gap), BAP0);
-				gap = le16_to_cpu(gap);
+				bap_read (apriv, &v, sizeof(v), BAP0);
+				gap = le16_to_cpu(v);
 				if (gap) {
 					if (gap <= 8) {
 						bap_read (apriv, tmpbuf, gap, BAP0);
@@ -3377,7 +3314,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
 				MICBuffer micbuf;
 				bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
 				if (apriv->micstats.enabled) {
-					bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
+					bap_read (apriv,(__le16*)&micbuf,sizeof(micbuf),BAP0);
 					if (ntohs(micbuf.typelen) > 0x05DC)
 						bap_setup (apriv, fid, 0x44, BAP0);
 					else {
@@ -3405,7 +3342,7 @@ badrx:
 				if (!test_bit(FLAG_802_11, &apriv->flags)) {
 					sa = (char*)buffer + 6;
 					bap_setup (apriv, fid, 8, BAP0);
-					bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
+					bap_read (apriv, (__le16*)hdr.rssi, 2, BAP0);
 				} else
 					sa = (char*)buffer + 10;
 				wstats.qual = hdr.rssi[0];
@@ -3676,14 +3613,15 @@ void mpi_receive_802_11 (struct airo_info *ai)
 {
 	RxFid rxd;
 	struct sk_buff *skb = NULL;
-	u16 fc, len, hdrlen = 0;
+	u16 len, hdrlen = 0;
+	__le16 fc;
 #pragma pack(1)
 	struct {
-		u16 status, len;
+		__le16 status, len;
 		u8 rssi[2];
 		u8 rate;
 		u8 freq;
-		u16 tmp[4];
+		__le16 tmp[4];
 	} hdr;
 #pragma pack()
 	u16 gap;
@@ -3706,23 +3644,8 @@ void mpi_receive_802_11 (struct airo_info *ai)
 	if (len == 0)
 		goto badrx;
 
-	memcpy ((char *)&fc, ptr, sizeof(fc));
-	fc = le16_to_cpu(fc);
-	switch (fc & 0xc) {
-		case 4:
-			if ((fc & 0xe0) == 0xc0)
-				hdrlen = 10;
-			else
-				hdrlen = 16;
-			break;
-		case 8:
-			if ((fc&0x300)==0x300){
-				hdrlen = 30;
-				break;
-			}
-		default:
-			hdrlen = 24;
-	}
+	fc = get_unaligned((__le16 *)ptr);
+	hdrlen = header_len(fc);
 
 	skb = dev_alloc_skb( len + hdrlen + 2 );
 	if ( !skb ) {
@@ -3734,9 +3657,8 @@ void mpi_receive_802_11 (struct airo_info *ai)
 	ptr += hdrlen;
 	if (hdrlen == 24)
 		ptr += 6;
-	memcpy ((char *)&gap, ptr, sizeof(gap));
-	ptr += sizeof(gap);
-	gap = le16_to_cpu(gap);
+	gap = le16_to_cpu(get_unaligned((__le16 *)ptr));
+	ptr += sizeof(__le16);
 	if (gap) {
 		if (gap <= 8)
 			ptr += gap;
@@ -3788,7 +3710,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
 	int status;
 	int i;
 	SsidRid mySsid;
-	u16 lastindex;
+	__le16 lastindex;
 	WepKeyRid wkr;
 	int rc;
 
@@ -3850,7 +3772,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
 		else {
 			kfree(ai->rssi);
 			ai->rssi = NULL;
-			if (cap_rid.softCap & 8)
+			if (cap_rid.softCap & cpu_to_le16(8))
 				ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
 			else
 				airo_print_warn(ai->dev->name, "unknown received signal "
@@ -3860,8 +3782,9 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
 		ai->config.authType = AUTH_OPEN;
 		ai->config.modulation = MOD_CCK;
 
-		if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) &&
-		    (micsetup(ai) == SUCCESS)) {
+		if (le16_to_cpu(cap_rid.len) >= sizeof(cap_rid) &&
+		    (cap_rid.extSoftCap & cpu_to_le16(1)) &&
+		    micsetup(ai) == SUCCESS) {
 			ai->config.opmode |= MODE_MIC;
 			set_bit(FLAG_MIC_CAPABLE, &ai->flags);
 		}
@@ -3897,13 +3820,13 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
 	if ( ssids[0] ) {
 		int i;
 		for( i = 0; i < 3 && ssids[i]; i++ ) {
-			mySsid.ssids[i].len = strlen(ssids[i]);
-			if ( mySsid.ssids[i].len > 32 )
-				mySsid.ssids[i].len = 32;
-			memcpy(mySsid.ssids[i].ssid, ssids[i],
-			       mySsid.ssids[i].len);
+			size_t len = strlen(ssids[i]);
+			if (len > 32)
+				len = 32;
+			mySsid.ssids[i].len = cpu_to_le16(len);
+			memcpy(mySsid.ssids[i].ssid, ssids[i], len);
 		}
-		mySsid.len = sizeof(mySsid);
+		mySsid.len = cpu_to_le16(sizeof(mySsid));
 	}
 
 	status = writeConfigRid(ai, lock);
@@ -3923,7 +3846,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
 	rc = readWepKeyRid(ai, &wkr, 1, lock);
 	if (rc == SUCCESS) do {
 		lastindex = wkr.kindex;
-		if (wkr.kindex == 0xffff) {
+		if (wkr.kindex == cpu_to_le16(0xffff)) {
 			ai->defindex = wkr.mac[0];
 		}
 		rc = readWepKeyRid(ai, &wkr, 0, lock);
@@ -4038,7 +3961,7 @@ static u16 aux_setup(struct airo_info *ai, u16 page,
 }
 
 /* requires call to bap_setup() first */
-static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
+static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst,
 			int bytelen, int whichbap)
 {
 	u16 len;
@@ -4075,7 +3998,7 @@ static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
 
 
 /* requires call to bap_setup() first */
-static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
+static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst,
 			 int bytelen, int whichbap)
 {
 	bytelen = (bytelen + 1) & (~1); // round up to even value
@@ -4087,7 +4010,7 @@ static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
 }
 
 /* requires call to bap_setup() first */
-static int bap_write(struct airo_info *ai, const u16 *pu16Src,
+static int bap_write(struct airo_info *ai, const __le16 *pu16Src,
 		     int bytelen, int whichbap)
 {
 	bytelen = (bytelen + 1) & (~1); // round up to even value
@@ -4163,7 +4086,7 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in
 		// read the rid length field
 		bap_read(ai, pBuf, 2, BAP1);
 		// length for remaining part of rid
-		len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2;
+		len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2;
 
 		if ( len <= 2 ) {
 			airo_print_err(ai->dev->name,
@@ -4173,7 +4096,7 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in
 	                goto done;
 		}
 		// read remainder of the rid
-		rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
+		rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1);
 	}
 done:
 	if (lock)
@@ -4189,7 +4112,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
 	u16 status;
 	int rc = SUCCESS;
 
-	*(u16*)pBuf = cpu_to_le16((u16)len);
+	*(__le16*)pBuf = cpu_to_le16((u16)len);
 
 	if (lock) {
 		if (down_interruptible(&ai->sem))
@@ -4263,7 +4186,7 @@ static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
 	Cmd cmd;
 	Resp rsp;
 	u16 txFid;
-	u16 txControl;
+	__le16 txControl;
 
 	cmd.cmd = CMD_ALLOCATETX;
 	cmd.parm0 = lenPayload;
@@ -4317,7 +4240,7 @@ done:
    Make sure the BAP1 spinlock is held when this is called. */
 static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
 {
-	u16 payloadLen;
+	__le16 payloadLen;
 	Cmd cmd;
 	Resp rsp;
 	int miclen = 0;
@@ -4333,7 +4256,7 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
 	len -= ETH_ALEN * 2;
 
 	if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && 
-	    (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
+	    (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) {
 		if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
 			return ERROR;
 		miclen = sizeof(pMic);
@@ -4345,10 +4268,10 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
 	 * we have to subtract the 12 bytes for the addresses off */
 	payloadLen = cpu_to_le16(len + miclen);
 	bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
-	bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1);
+	bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1);
 	if (miclen)
-		bap_write(ai, (const u16*)&pMic, miclen, BAP1);
-	bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
+		bap_write(ai, (__le16*)&pMic, miclen, BAP1);
+	bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1);
 	// issue the transmit command
 	memset( &cmd, 0, sizeof( cmd ) );
 	cmd.cmd = CMD_TRANSMIT;
@@ -4360,35 +4283,17 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
 
 static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
 {
-	u16 fc, payloadLen;
+	__le16 fc, payloadLen;
 	Cmd cmd;
 	Resp rsp;
 	int hdrlen;
-	struct {
-		u8 addr4[ETH_ALEN];
-		u16 gaplen;
-		u8 gap[6];
-	} gap;
+	static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6};
+	/* padding of header to full size + le16 gaplen (6) + gaplen bytes */
 	u16 txFid = len;
 	len >>= 16;
-	gap.gaplen = 6;
 
-	fc = le16_to_cpu(*(const u16*)pPacket);
-	switch (fc & 0xc) {
-		case 4:
-			if ((fc & 0xe0) == 0xc0)
-				hdrlen = 10;
-			else
-				hdrlen = 16;
-			break;
-		case 8:
-			if ((fc&0x300)==0x300){
-				hdrlen = 30;
-				break;
-			}
-		default:
-			hdrlen = 24;
-	}
+	fc = *(__le16*)pPacket;
+	hdrlen = header_len(fc);
 
 	if (len < hdrlen) {
 		airo_print_warn(ai->dev->name, "Short packet %d", len);
@@ -4403,11 +4308,10 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
 	payloadLen = cpu_to_le16(len-hdrlen);
 	bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
 	if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR;
-	bap_write(ai, (const u16*)pPacket, hdrlen, BAP1);
-	bap_write(ai, hdrlen == 30 ?
-		(const u16*)&gap.gaplen : (const u16*)&gap, 38 - hdrlen, BAP1);
+	bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1);
+	bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1);
 
-	bap_write(ai, (const u16*)(pPacket + hdrlen), len - hdrlen, BAP1);
+	bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1);
 	// issue the transmit command
 	memset( &cmd, 0, sizeof( cmd ) );
 	cmd.cmd = CMD_TRANSMIT;
@@ -4722,13 +4626,15 @@ static ssize_t proc_write( struct file *file,
 	return len;
 }
 
-static int proc_status_open( struct inode *inode, struct file *file ) {
+static int proc_status_open(struct inode *inode, struct file *file)
+{
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *apriv = dev->priv;
 	CapabilityRid cap_rid;
 	StatusRid status_rid;
+	u16 mode;
 	int i;
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
@@ -4742,16 +4648,18 @@ static int proc_status_open( struct inode *inode, struct file *file ) {
 	readStatusRid(apriv, &status_rid, 1);
 	readCapabilityRid(apriv, &cap_rid, 1);
 
+	mode = le16_to_cpu(status_rid.mode);
+
         i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
-                    status_rid.mode & 1 ? "CFG ": "",
-                    status_rid.mode & 2 ? "ACT ": "",
-                    status_rid.mode & 0x10 ? "SYN ": "",
-                    status_rid.mode & 0x20 ? "LNK ": "",
-                    status_rid.mode & 0x40 ? "LEAP ": "",
-                    status_rid.mode & 0x80 ? "PRIV ": "",
-                    status_rid.mode & 0x100 ? "KEY ": "",
-                    status_rid.mode & 0x200 ? "WEP ": "",
-                    status_rid.mode & 0x8000 ? "ERR ": "");
+                    mode & 1 ? "CFG ": "",
+                    mode & 2 ? "ACT ": "",
+                    mode & 0x10 ? "SYN ": "",
+                    mode & 0x20 ? "LNK ": "",
+                    mode & 0x40 ? "LEAP ": "",
+                    mode & 0x80 ? "PRIV ": "",
+                    mode & 0x100 ? "KEY ": "",
+                    mode & 0x200 ? "WEP ": "",
+                    mode & 0x8000 ? "ERR ": "");
 	sprintf( data->rbuffer+i, "Mode: %x\n"
 		 "Signal Strength: %d\n"
 		 "Signal Quality: %d\n"
@@ -4764,24 +4672,24 @@ static int proc_status_open( struct inode *inode, struct file *file ) {
 		 "Radio type: %x\nCountry: %x\nHardware Version: %x\n"
 		 "Software Version: %x\nSoftware Subversion: %x\n"
 		 "Boot block version: %x\n",
-		 (int)status_rid.mode,
-		 (int)status_rid.normalizedSignalStrength,
-		 (int)status_rid.signalQuality,
-		 (int)status_rid.SSIDlen,
+		 le16_to_cpu(status_rid.mode),
+		 le16_to_cpu(status_rid.normalizedSignalStrength),
+		 le16_to_cpu(status_rid.signalQuality),
+		 le16_to_cpu(status_rid.SSIDlen),
 		 status_rid.SSID,
 		 status_rid.apName,
-		 (int)status_rid.channel,
-		 (int)status_rid.currentXmitRate/2,
+		 le16_to_cpu(status_rid.channel),
+		 le16_to_cpu(status_rid.currentXmitRate) / 2,
 		 version,
 		 cap_rid.prodName,
 		 cap_rid.manName,
 		 cap_rid.prodVer,
-		 cap_rid.radioType,
-		 cap_rid.country,
-		 cap_rid.hardVer,
-		 (int)cap_rid.softVer,
-		 (int)cap_rid.softSubVer,
-		 (int)cap_rid.bootBlockVer );
+		 le16_to_cpu(cap_rid.radioType),
+		 le16_to_cpu(cap_rid.country),
+		 le16_to_cpu(cap_rid.hardVer),
+		 le16_to_cpu(cap_rid.softVer),
+		 le16_to_cpu(cap_rid.softSubVer),
+		 le16_to_cpu(cap_rid.bootBlockVer));
 	data->readlen = strlen( data->rbuffer );
 	return 0;
 }
@@ -4801,14 +4709,16 @@ static int proc_stats_open( struct inode *inode, struct file *file ) {
 
 static int proc_stats_rid_open( struct inode *inode,
 				struct file *file,
-				u16 rid ) {
+				u16 rid )
+{
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *apriv = dev->priv;
 	StatsRid stats;
 	int i, j;
-	u32 *vals = stats.vals;
+	__le32 *vals = stats.vals;
+	int len = le16_to_cpu(stats.len);
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
@@ -4821,17 +4731,17 @@ static int proc_stats_rid_open( struct inode *inode,
 	readStatsRid(apriv, &stats, rid, 1);
 
         j = 0;
-	for(i=0; statsLabels[i]!=(char *)-1 &&
-		    i*4<stats.len; i++){
+	for(i=0; statsLabels[i]!=(char *)-1 && i*4<len; i++) {
 		if (!statsLabels[i]) continue;
 		if (j+strlen(statsLabels[i])+16>4096) {
 			airo_print_warn(apriv->dev->name,
 			       "Potentially disasterous buffer overflow averted!");
 			break;
 		}
-		j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]);
+		j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i],
+				le32_to_cpu(vals[i]));
 	}
-	if (i*4>=stats.len){
+	if (i*4 >= len) {
 		airo_print_warn(apriv->dev->name, "Got a short rid");
 	}
 	data->readlen = j;
@@ -4856,7 +4766,14 @@ static int airo_config_commit(struct net_device *dev,
 			      struct iw_request_info *info, void *zwrq,
 			      char *extra);
 
-static void proc_config_on_close( struct inode *inode, struct file *file ) {
+static inline int sniffing_mode(struct airo_info *ai)
+{
+	return le16_to_cpu(ai->config.rmode & RXMODE_MASK) >=
+		le16_to_cpu(RXMODE_RFMON);
+}
+
+static void proc_config_on_close(struct inode *inode, struct file *file)
+{
 	struct proc_data *data = file->private_data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
@@ -4873,16 +4790,16 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 /*** Mode processing */
 		if ( !strncmp( line, "Mode: ", 6 ) ) {
 			line += 6;
-			if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
-					set_bit (FLAG_RESET, &ai->flags);
-			ai->config.rmode &= 0xfe00;
+			if (sniffing_mode(ai))
+				set_bit (FLAG_RESET, &ai->flags);
+			ai->config.rmode &= ~RXMODE_FULL_MASK;
 			clear_bit (FLAG_802_11, &ai->flags);
-			ai->config.opmode &= 0xFF00;
+			ai->config.opmode &= ~MODE_CFG_MASK;
 			ai->config.scanMode = SCANMODE_ACTIVE;
 			if ( line[0] == 'a' ) {
-				ai->config.opmode |= 0;
+				ai->config.opmode |= MODE_STA_IBSS;
 			} else {
-				ai->config.opmode |= 1;
+				ai->config.opmode |= MODE_STA_ESS;
 				if ( line[0] == 'r' ) {
 					ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
 					ai->config.scanMode = SCANMODE_PASSIVE;
@@ -4948,7 +4865,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 			line += 9;
 			v = get_dec_u16(line, &i, i+3);
 			if ( v != -1 ) {
-				ai->config.channelSet = (u16)v;
+				ai->config.channelSet = cpu_to_le16(v);
 				set_bit (FLAG_COMMIT, &ai->flags);
 			}
 		} else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
@@ -4956,20 +4873,20 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 			line += 11;
 			v = get_dec_u16(line, &i, i+3);
 			if ( v != -1 ) {
-				ai->config.txPower = (u16)v;
+				ai->config.txPower = cpu_to_le16(v);
 				set_bit (FLAG_COMMIT, &ai->flags);
 			}
 		} else if ( !strncmp( line, "WEP: ", 5 ) ) {
 			line += 5;
 			switch( line[0] ) {
 			case 's':
-				ai->config.authType = (u16)AUTH_SHAREDKEY;
+				ai->config.authType = AUTH_SHAREDKEY;
 				break;
 			case 'e':
-				ai->config.authType = (u16)AUTH_ENCRYPT;
+				ai->config.authType = AUTH_ENCRYPT;
 				break;
 			default:
-				ai->config.authType = (u16)AUTH_OPEN;
+				ai->config.authType = AUTH_OPEN;
 				break;
 			}
 			set_bit (FLAG_COMMIT, &ai->flags);
@@ -4979,7 +4896,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 			line += 16;
 			v = get_dec_u16(line, &i, 3);
 			v = (v<0) ? 0 : ((v>255) ? 255 : v);
-			ai->config.longRetryLimit = (u16)v;
+			ai->config.longRetryLimit = cpu_to_le16(v);
 			set_bit (FLAG_COMMIT, &ai->flags);
 		} else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
 			int v, i = 0;
@@ -4987,7 +4904,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 			line += 17;
 			v = get_dec_u16(line, &i, 3);
 			v = (v<0) ? 0 : ((v>255) ? 255 : v);
-			ai->config.shortRetryLimit = (u16)v;
+			ai->config.shortRetryLimit = cpu_to_le16(v);
 			set_bit (FLAG_COMMIT, &ai->flags);
 		} else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
 			int v, i = 0;
@@ -4995,7 +4912,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 			line += 14;
 			v = get_dec_u16(line, &i, 4);
 			v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
-			ai->config.rtsThres = (u16)v;
+			ai->config.rtsThres = cpu_to_le16(v);
 			set_bit (FLAG_COMMIT, &ai->flags);
 		} else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
 			int v, i = 0;
@@ -5003,7 +4920,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 			line += 16;
 			v = get_dec_u16(line, &i, 5);
 			v = (v<0) ? 0 : v;
-			ai->config.txLifetime = (u16)v;
+			ai->config.txLifetime = cpu_to_le16(v);
 			set_bit (FLAG_COMMIT, &ai->flags);
 		} else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
 			int v, i = 0;
@@ -5011,7 +4928,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 			line += 16;
 			v = get_dec_u16(line, &i, 5);
 			v = (v<0) ? 0 : v;
-			ai->config.rxLifetime = (u16)v;
+			ai->config.rxLifetime = cpu_to_le16(v);
 			set_bit (FLAG_COMMIT, &ai->flags);
 		} else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
 			ai->config.txDiversity =
@@ -5030,7 +4947,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 			v = get_dec_u16(line, &i, 4);
 			v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
 			v = v & 0xfffe; /* Make sure its even */
-			ai->config.fragThresh = (u16)v;
+			ai->config.fragThresh = cpu_to_le16(v);
 			set_bit (FLAG_COMMIT, &ai->flags);
 		} else if (!strncmp(line, "Modulation: ", 12)) {
 			line += 12;
@@ -5057,8 +4974,9 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 	airo_config_commit(dev, NULL, NULL, NULL);
 }
 
-static char *get_rmode(u16 mode) {
-        switch(mode&0xff) {
+static char *get_rmode(__le16 mode)
+{
+        switch(mode & RXMODE_MASK) {
         case RXMODE_RFMON:  return "rfmon";
         case RXMODE_RFMON_ANYBSS:  return "yna (any) bss rfmon";
         case RXMODE_LANMON:  return "lanmon";
@@ -5066,12 +4984,14 @@ static char *get_rmode(u16 mode) {
         return "ESS";
 }
 
-static int proc_config_open( struct inode *inode, struct file *file ) {
+static int proc_config_open(struct inode *inode, struct file *file)
+{
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = dev->priv;
 	int i;
+	__le16 mode;
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
@@ -5090,6 +5010,7 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
 
 	readConfigRid(ai, 1);
 
+	mode = ai->config.opmode & MODE_CFG_MASK;
 	i = sprintf( data->rbuffer,
 		     "Mode: %s\n"
 		     "Radio: %s\n"
@@ -5098,15 +5019,16 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
 		     "DataRates: %d %d %d %d %d %d %d %d\n"
 		     "Channel: %d\n"
 		     "XmitPower: %d\n",
-		     (ai->config.opmode & 0xFF) == 0 ? "adhoc" :
-		     (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
-		     (ai->config.opmode & 0xFF) == 2 ? "AP" :
-		     (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
+		     mode == MODE_STA_IBSS ? "adhoc" :
+		     mode == MODE_STA_ESS ? get_rmode(ai->config.rmode):
+		     mode == MODE_AP ? "AP" :
+		     mode == MODE_AP_RPTR ? "AP RPTR" : "Error",
 		     test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on",
 		     ai->config.nodeName,
-		     ai->config.powerSaveMode == 0 ? "CAM" :
-		     ai->config.powerSaveMode == 1 ? "PSP" :
-		     ai->config.powerSaveMode == 2 ? "PSPCAM" : "Error",
+		     ai->config.powerSaveMode == POWERSAVE_CAM ? "CAM" :
+		     ai->config.powerSaveMode == POWERSAVE_PSP ? "PSP" :
+		     ai->config.powerSaveMode == POWERSAVE_PSPCAM ? "PSPCAM" :
+		     "Error",
 		     (int)ai->config.rates[0],
 		     (int)ai->config.rates[1],
 		     (int)ai->config.rates[2],
@@ -5115,8 +5037,8 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
 		     (int)ai->config.rates[5],
 		     (int)ai->config.rates[6],
 		     (int)ai->config.rates[7],
-		     (int)ai->config.channelSet,
-		     (int)ai->config.txPower
+		     le16_to_cpu(ai->config.channelSet),
+		     le16_to_cpu(ai->config.txPower)
 		);
 	sprintf( data->rbuffer + i,
 		 "LongRetryLimit: %d\n"
@@ -5130,19 +5052,19 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
 		 "WEP: %s\n"
 		 "Modulation: %s\n"
 		 "Preamble: %s\n",
-		 (int)ai->config.longRetryLimit,
-		 (int)ai->config.shortRetryLimit,
-		 (int)ai->config.rtsThres,
-		 (int)ai->config.txLifetime,
-		 (int)ai->config.rxLifetime,
+		 le16_to_cpu(ai->config.longRetryLimit),
+		 le16_to_cpu(ai->config.shortRetryLimit),
+		 le16_to_cpu(ai->config.rtsThres),
+		 le16_to_cpu(ai->config.txLifetime),
+		 le16_to_cpu(ai->config.rxLifetime),
 		 ai->config.txDiversity == 1 ? "left" :
 		 ai->config.txDiversity == 2 ? "right" : "both",
 		 ai->config.rxDiversity == 1 ? "left" :
 		 ai->config.rxDiversity == 2 ? "right" : "both",
-		 (int)ai->config.fragThresh,
+		 le16_to_cpu(ai->config.fragThresh),
 		 ai->config.authType == AUTH_ENCRYPT ? "encrypt" :
 		 ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open",
-		 ai->config.modulation == 0 ? "default" :
+		 ai->config.modulation == MOD_DEFAULT ? "default" :
 		 ai->config.modulation == MOD_CCK ? "cck" :
 		 ai->config.modulation == MOD_MOK ? "mok" : "error",
 		 ai->config.preamble == PREAMBLE_AUTO ? "auto" :
@@ -5153,34 +5075,38 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
 	return 0;
 }
 
-static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
+static void proc_SSID_on_close(struct inode *inode, struct file *file)
+{
 	struct proc_data *data = (struct proc_data *)file->private_data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = dev->priv;
 	SsidRid SSID_rid;
 	int i;
-	int offset = 0;
+	char *p = data->wbuffer;
+	char *end = p + data->writelen;
 
-	if ( !data->writelen ) return;
+	if (!data->writelen)
+		return;
 
-	memset( &SSID_rid, 0, sizeof( SSID_rid ) );
+	*end = '\n'; /* sentinel; we have space for it */
 
-	for( i = 0; i < 3; i++ ) {
-		int j;
-		for( j = 0; j+offset < data->writelen && j < 32 &&
-			     data->wbuffer[offset+j] != '\n'; j++ ) {
-			SSID_rid.ssids[i].ssid[j] = data->wbuffer[offset+j];
-		}
-		if ( j == 0 ) break;
-		SSID_rid.ssids[i].len = j;
-		offset += j;
-		while( data->wbuffer[offset] != '\n' &&
-		       offset < data->writelen ) offset++;
-		offset++;
+	memset(&SSID_rid, 0, sizeof(SSID_rid));
+
+	for (i = 0; i < 3 && p < end; i++) {
+		int j = 0;
+		/* copy up to 32 characters from this line */
+		while (*p != '\n' && j < 32)
+			SSID_rid.ssids[i].ssid[j++] = *p++;
+		if (j == 0)
+			break;
+		SSID_rid.ssids[i].len = cpu_to_le16(j);
+		/* skip to the beginning of the next line */
+		while (*p++ != '\n')
+			;
 	}
 	if (i)
-		SSID_rid.len = sizeof(SSID_rid);
+		SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
 	disable_MAC(ai, 1);
 	writeSsidRid(ai, &SSID_rid, 1);
 	enable_MAC(ai, 1);
@@ -5204,7 +5130,7 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) {
 	if ( !data->writelen ) return;
 
 	memset( &APList_rid, 0, sizeof(APList_rid) );
-	APList_rid.len = sizeof(APList_rid);
+	APList_rid.len = cpu_to_le16(sizeof(APList_rid));
 
 	for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) {
 		int j;
@@ -5244,39 +5170,40 @@ static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
 static int get_wep_key(struct airo_info *ai, u16 index) {
 	WepKeyRid wkr;
 	int rc;
-	u16 lastindex;
+	__le16 lastindex;
 
 	rc = readWepKeyRid(ai, &wkr, 1, 1);
 	if (rc == SUCCESS) do {
 		lastindex = wkr.kindex;
-		if (wkr.kindex == index) {
+		if (wkr.kindex == cpu_to_le16(index)) {
 			if (index == 0xffff) {
 				return wkr.mac[0];
 			}
-			return wkr.klen;
+			return le16_to_cpu(wkr.klen);
 		}
 		readWepKeyRid(ai, &wkr, 0, 1);
-	} while(lastindex != wkr.kindex);
+	} while (lastindex != wkr.kindex);
 	return -1;
 }
 
 static int set_wep_key(struct airo_info *ai, u16 index,
-		       const char *key, u16 keylen, int perm, int lock ) {
+		       const char *key, u16 keylen, int perm, int lock )
+{
 	static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
 	WepKeyRid wkr;
 
 	memset(&wkr, 0, sizeof(wkr));
 	if (keylen == 0) {
 // We are selecting which key to use
-		wkr.len = sizeof(wkr);
-		wkr.kindex = 0xffff;
+		wkr.len = cpu_to_le16(sizeof(wkr));
+		wkr.kindex = cpu_to_le16(0xffff);
 		wkr.mac[0] = (char)index;
 		if (perm) ai->defindex = (char)index;
 	} else {
 // We are actually setting the key
-		wkr.len = sizeof(wkr);
-		wkr.kindex = index;
-		wkr.klen = keylen;
+		wkr.len = cpu_to_le16(sizeof(wkr));
+		wkr.kindex = cpu_to_le16(index);
+		wkr.klen = cpu_to_le16(keylen);
 		memcpy( wkr.key, key, keylen );
 		memcpy( wkr.mac, macaddr, ETH_ALEN );
 	}
@@ -5328,14 +5255,15 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
 	set_wep_key(ai, index, key, i/3, 1, 1);
 }
 
-static int proc_wepkey_open( struct inode *inode, struct file *file ) {
+static int proc_wepkey_open( struct inode *inode, struct file *file )
+{
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = dev->priv;
 	char *ptr;
 	WepKeyRid wkr;
-	u16 lastindex;
+	__le16 lastindex;
 	int j=0;
 	int rc;
 
@@ -5361,12 +5289,13 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) {
 	rc = readWepKeyRid(ai, &wkr, 1, 1);
 	if (rc == SUCCESS) do {
 		lastindex = wkr.kindex;
-		if (wkr.kindex == 0xffff) {
+		if (wkr.kindex == cpu_to_le16(0xffff)) {
 			j += sprintf(ptr+j, "Tx key = %d\n",
 				     (int)wkr.mac[0]);
 		} else {
 			j += sprintf(ptr+j, "Key %d set with length = %d\n",
-				     (int)wkr.kindex, (int)wkr.klen);
+				     le16_to_cpu(wkr.kindex),
+				     le16_to_cpu(wkr.klen));
 		}
 		readWepKeyRid(ai, &wkr, 0, 1);
 	} while((lastindex != wkr.kindex) && (j < 180-30));
@@ -5375,7 +5304,8 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) {
 	return 0;
 }
 
-static int proc_SSID_open( struct inode *inode, struct file *file ) {
+static int proc_SSID_open(struct inode *inode, struct file *file)
+{
 	struct proc_data *data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
@@ -5393,7 +5323,8 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) {
 	}
 	data->writelen = 0;
 	data->maxwritelen = 33*3;
-	if ((data->wbuffer = kzalloc( 33*3, GFP_KERNEL )) == NULL) {
+	/* allocate maxwritelen + 1; we'll want a sentinel */
+	if ((data->wbuffer = kzalloc(33*3 + 1, GFP_KERNEL)) == NULL) {
 		kfree (data->rbuffer);
 		kfree (file->private_data);
 		return -ENOMEM;
@@ -5402,14 +5333,15 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) {
 
 	readSsidRid(ai, &SSID_rid);
 	ptr = data->rbuffer;
-	for( i = 0; i < 3; i++ ) {
+	for (i = 0; i < 3; i++) {
 		int j;
-		if ( !SSID_rid.ssids[i].len ) break;
-		for( j = 0; j < 32 &&
-			     j < SSID_rid.ssids[i].len &&
-			     SSID_rid.ssids[i].ssid[j]; j++ ) {
+		size_t len = le16_to_cpu(SSID_rid.ssids[i].len);
+		if (!len)
+			break;
+		if (len > 32)
+			len = 32;
+		for (j = 0; j < len && SSID_rid.ssids[i].ssid[j]; j++)
 			*ptr++ = SSID_rid.ssids[i].ssid[j];
-		}
 		*ptr++ = '\n';
 	}
 	*ptr = '\0';
@@ -5505,14 +5437,14 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
            Since it is a rare condition, we'll just live with it, otherwise
            we have to add a spin lock... */
 	rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
-	while(rc == 0 && BSSList_rid.index != 0xffff) {
+	while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) {
 		ptr += sprintf(ptr, "%s %*s rssi = %d",
 			       print_mac(mac, BSSList_rid.bssid),
 				(int)BSSList_rid.ssidLen,
 				BSSList_rid.ssid,
-				(int)BSSList_rid.dBm);
+				le16_to_cpu(BSSList_rid.dBm));
 		ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
-				(int)BSSList_rid.dsChannel,
+				le16_to_cpu(BSSList_rid.dsChannel),
 				BSSList_rid.cap & CAP_ESS ? "ESS" : "",
 				BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
 				BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
@@ -5780,21 +5712,27 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
 static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
 {
 	int quality = 0;
+	u16 sq;
 
-	if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) {
-		if (memcmp(cap_rid->prodName, "350", 3))
-			if (status_rid->signalQuality > 0x20)
-				quality = 0;
-			else
-				quality = 0x20 - status_rid->signalQuality;
+	if ((status_rid->mode & cpu_to_le16(0x3f)) != cpu_to_le16(0x3f))
+		return 0;
+
+	if (!(cap_rid->hardCap & cpu_to_le16(8)))
+		return 0;
+
+	sq = le16_to_cpu(status_rid->signalQuality);
+	if (memcmp(cap_rid->prodName, "350", 3))
+		if (sq > 0x20)
+			quality = 0;
 		else
-			if (status_rid->signalQuality > 0xb0)
-				quality = 0;
-			else if (status_rid->signalQuality < 0x10)
-				quality = 0xa0;
-			else
-				quality = 0xb0 - status_rid->signalQuality;
-	}
+			quality = 0x20 - sq;
+	else
+		if (sq > 0xb0)
+			quality = 0;
+		else if (sq < 0x10)
+			quality = 0xa0;
+		else
+			quality = 0xb0 - sq;
 	return quality;
 }
 
@@ -5852,7 +5790,7 @@ static int airo_set_freq(struct net_device *dev,
 		} else {
 			readConfigRid(local, 1);
 			/* Yes ! We can set it !!! */
-			local->config.channelSet = (u16) channel;
+			local->config.channelSet = cpu_to_le16(channel);
 			set_bit (FLAG_COMMIT, &local->flags);
 		}
 	}
@@ -5873,12 +5811,12 @@ static int airo_get_freq(struct net_device *dev,
 	int ch;
 
 	readConfigRid(local, 1);
-	if ((local->config.opmode & 0xFF) == MODE_STA_ESS)
+	if ((local->config.opmode & MODE_CFG_MASK) == MODE_STA_ESS)
 		status_rid.channel = local->config.channelSet;
 	else
 		readStatusRid(local, &status_rid, 1);
 
-	ch = (int)status_rid.channel;
+	ch = le16_to_cpu(status_rid.channel);
 	if((ch > 0) && (ch < 15)) {
 		fwrq->m = frequency_list[ch - 1] * 100000;
 		fwrq->e = 1;
@@ -5925,9 +5863,9 @@ static int airo_set_essid(struct net_device *dev,
 		memset(SSID_rid.ssids[index].ssid, 0,
 		       sizeof(SSID_rid.ssids[index].ssid));
 		memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
-		SSID_rid.ssids[index].len = dwrq->length;
+		SSID_rid.ssids[index].len = cpu_to_le16(dwrq->length);
 	}
-	SSID_rid.len = sizeof(SSID_rid);
+	SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
 	/* Write it to the card */
 	disable_MAC(local, 1);
 	writeSsidRid(local, &SSID_rid, 1);
@@ -5954,11 +5892,11 @@ static int airo_get_essid(struct net_device *dev,
 	 * get the relevant SSID from the SSID list... */
 
 	/* Get the current SSID */
-	memcpy(extra, status_rid.SSID, status_rid.SSIDlen);
+	memcpy(extra, status_rid.SSID, le16_to_cpu(status_rid.SSIDlen));
 	/* If none, we may want to get the one that was set */
 
 	/* Push it out ! */
-	dwrq->length = status_rid.SSIDlen;
+	dwrq->length = le16_to_cpu(status_rid.SSIDlen);
 	dwrq->flags = 1; /* active */
 
 	return 0;
@@ -5992,7 +5930,7 @@ static int airo_set_wap(struct net_device *dev,
 		up(&local->sem);
 	} else {
 		memset(&APList_rid, 0, sizeof(APList_rid));
-		APList_rid.len = sizeof(APList_rid);
+		APList_rid.len = cpu_to_le16(sizeof(APList_rid));
 		memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
 		disable_MAC(local, 1);
 		writeAPListRid(local, &APList_rid, 1);
@@ -6148,7 +6086,7 @@ static int airo_get_rate(struct net_device *dev,
 
 	readStatusRid(local, &status_rid, 1);
 
-	vwrq->value = status_rid.currentXmitRate * 500000;
+	vwrq->value = le16_to_cpu(status_rid.currentXmitRate) * 500000;
 	/* If more than one rate, set auto */
 	readConfigRid(local, 1);
 	vwrq->fixed = (local->config.rates[1] == 0);
@@ -6174,7 +6112,7 @@ static int airo_set_rts(struct net_device *dev,
 		return -EINVAL;
 	}
 	readConfigRid(local, 1);
-	local->config.rtsThres = rthr;
+	local->config.rtsThres = cpu_to_le16(rthr);
 	set_bit (FLAG_COMMIT, &local->flags);
 
 	return -EINPROGRESS;		/* Call commit handler */
@@ -6192,7 +6130,7 @@ static int airo_get_rts(struct net_device *dev,
 	struct airo_info *local = dev->priv;
 
 	readConfigRid(local, 1);
-	vwrq->value = local->config.rtsThres;
+	vwrq->value = le16_to_cpu(local->config.rtsThres);
 	vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
 	vwrq->fixed = 1;
 
@@ -6218,7 +6156,7 @@ static int airo_set_frag(struct net_device *dev,
 	}
 	fthr &= ~0x1;	/* Get an even value - is it really needed ??? */
 	readConfigRid(local, 1);
-	local->config.fragThresh = (u16)fthr;
+	local->config.fragThresh = cpu_to_le16(fthr);
 	set_bit (FLAG_COMMIT, &local->flags);
 
 	return -EINPROGRESS;		/* Call commit handler */
@@ -6236,7 +6174,7 @@ static int airo_get_frag(struct net_device *dev,
 	struct airo_info *local = dev->priv;
 
 	readConfigRid(local, 1);
-	vwrq->value = local->config.fragThresh;
+	vwrq->value = le16_to_cpu(local->config.fragThresh);
 	vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
 	vwrq->fixed = 1;
 
@@ -6256,42 +6194,42 @@ static int airo_set_mode(struct net_device *dev,
 	int reset = 0;
 
 	readConfigRid(local, 1);
-	if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
+	if (sniffing_mode(local))
 		reset = 1;
 
 	switch(*uwrq) {
 		case IW_MODE_ADHOC:
-			local->config.opmode &= 0xFF00;
+			local->config.opmode &= ~MODE_CFG_MASK;
 			local->config.opmode |= MODE_STA_IBSS;
-			local->config.rmode &= 0xfe00;
+			local->config.rmode &= ~RXMODE_FULL_MASK;
 			local->config.scanMode = SCANMODE_ACTIVE;
 			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_INFRA:
-			local->config.opmode &= 0xFF00;
+			local->config.opmode &= ~MODE_CFG_MASK;
 			local->config.opmode |= MODE_STA_ESS;
-			local->config.rmode &= 0xfe00;
+			local->config.rmode &= ~RXMODE_FULL_MASK;
 			local->config.scanMode = SCANMODE_ACTIVE;
 			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_MASTER:
-			local->config.opmode &= 0xFF00;
+			local->config.opmode &= ~MODE_CFG_MASK;
 			local->config.opmode |= MODE_AP;
-			local->config.rmode &= 0xfe00;
+			local->config.rmode &= ~RXMODE_FULL_MASK;
 			local->config.scanMode = SCANMODE_ACTIVE;
 			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_REPEAT:
-			local->config.opmode &= 0xFF00;
+			local->config.opmode &= ~MODE_CFG_MASK;
 			local->config.opmode |= MODE_AP_RPTR;
-			local->config.rmode &= 0xfe00;
+			local->config.rmode &= ~RXMODE_FULL_MASK;
 			local->config.scanMode = SCANMODE_ACTIVE;
 			clear_bit (FLAG_802_11, &local->flags);
 			break;
 		case IW_MODE_MONITOR:
-			local->config.opmode &= 0xFF00;
+			local->config.opmode &= ~MODE_CFG_MASK;
 			local->config.opmode |= MODE_STA_ESS;
-			local->config.rmode &= 0xfe00;
+			local->config.rmode &= ~RXMODE_FULL_MASK;
 			local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
 			local->config.scanMode = SCANMODE_PASSIVE;
 			set_bit (FLAG_802_11, &local->flags);
@@ -6319,7 +6257,7 @@ static int airo_get_mode(struct net_device *dev,
 
 	readConfigRid(local, 1);
 	/* If not managed, assume it's ad-hoc */
-	switch (local->config.opmode & 0xFF) {
+	switch (local->config.opmode & MODE_CFG_MASK) {
 		case MODE_STA_ESS:
 			*uwrq = IW_MODE_INFRA;
 			break;
@@ -6336,6 +6274,13 @@ static int airo_get_mode(struct net_device *dev,
 	return 0;
 }
 
+static inline int valid_index(CapabilityRid *p, int index)
+{
+	if (index < 0)
+		return 0;
+	return index < (p->softCap & cpu_to_le16(0x80) ? 4 : 1);
+}
+
 /*------------------------------------------------------------------*/
 /*
  * Wireless Handler : set Encryption Key
@@ -6348,12 +6293,12 @@ static int airo_set_encode(struct net_device *dev,
 	struct airo_info *local = dev->priv;
 	CapabilityRid cap_rid;		/* Card capability info */
 	int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
-	u16 currentAuthType = local->config.authType;
+	__le16 currentAuthType = local->config.authType;
 
 	/* Is WEP supported ? */
 	readCapabilityRid(local, &cap_rid, 1);
 	/* Older firmware doesn't support this...
-	if(!(cap_rid.softCap & 2)) {
+	if(!(cap_rid.softCap & cpu_to_le16(2))) {
 		return -EOPNOTSUPP;
 	} */
 	readConfigRid(local, 1);
@@ -6373,7 +6318,7 @@ static int airo_set_encode(struct net_device *dev,
 			return -EINVAL;
 		}
 		/* Check the index (none -> use current) */
-		if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4:1)))
+		if (!valid_index(&cap_rid, index))
 			index = current_index;
 		/* Set the length */
 		if (dwrq->length > MIN_KEY_SIZE)
@@ -6403,13 +6348,12 @@ static int airo_set_encode(struct net_device *dev,
 	} else {
 		/* Do we want to just set the transmit key index ? */
 		int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-		if ((index >= 0) && (index < ((cap_rid.softCap & 0x80)?4:1))) {
+		if (valid_index(&cap_rid, index)) {
 			set_wep_key(local, index, NULL, 0, perm, 1);
 		} else
 			/* Don't complain if only change the mode */
-			if(!dwrq->flags & IW_ENCODE_MODE) {
+			if (!(dwrq->flags & IW_ENCODE_MODE))
 				return -EINVAL;
-			}
 	}
 	/* Read the flags */
 	if(dwrq->flags & IW_ENCODE_DISABLED)
@@ -6439,7 +6383,7 @@ static int airo_get_encode(struct net_device *dev,
 
 	/* Is it supported ? */
 	readCapabilityRid(local, &cap_rid, 1);
-	if(!(cap_rid.softCap & 2)) {
+	if(!(cap_rid.softCap & cpu_to_le16(2))) {
 		return -EOPNOTSUPP;
 	}
 	readConfigRid(local, 1);
@@ -6461,7 +6405,7 @@ static int airo_get_encode(struct net_device *dev,
 	memset(extra, 0, 16);
 
 	/* Which key do we want ? -1 -> tx index */
-	if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4 : 1)))
+	if (!valid_index(&cap_rid, index))
 		index = get_wep_key(local, 0xffff);
 	dwrq->flags |= index + 1;
 	/* Copy the key to the user buffer */
@@ -6486,14 +6430,14 @@ static int airo_set_encodeext(struct net_device *dev,
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 	CapabilityRid cap_rid;		/* Card capability info */
 	int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 );
-	u16 currentAuthType = local->config.authType;
+	__le16 currentAuthType = local->config.authType;
 	int idx, key_len, alg = ext->alg, set_key = 1;
 	wep_key_t key;
 
 	/* Is WEP supported ? */
 	readCapabilityRid(local, &cap_rid, 1);
 	/* Older firmware doesn't support this...
-	if(!(cap_rid.softCap & 2)) {
+	if(!(cap_rid.softCap & cpu_to_le16(2))) {
 		return -EOPNOTSUPP;
 	} */
 	readConfigRid(local, 1);
@@ -6501,7 +6445,7 @@ static int airo_set_encodeext(struct net_device *dev,
 	/* Determine and validate the key index */
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
-		if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
+		if (!valid_index(&cap_rid, idx - 1))
 			return -EINVAL;
 		idx--;
 	} else
@@ -6575,7 +6519,7 @@ static int airo_get_encodeext(struct net_device *dev,
 
 	/* Is it supported ? */
 	readCapabilityRid(local, &cap_rid, 1);
-	if(!(cap_rid.softCap & 2)) {
+	if(!(cap_rid.softCap & cpu_to_le16(2))) {
 		return -EOPNOTSUPP;
 	}
 	readConfigRid(local, 1);
@@ -6586,7 +6530,7 @@ static int airo_get_encodeext(struct net_device *dev,
 
 	idx = encoding->flags & IW_ENCODE_INDEX;
 	if (idx) {
-		if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
+		if (!valid_index(&cap_rid, idx - 1))
 			return -EINVAL;
 		idx--;
 	} else
@@ -6632,7 +6576,7 @@ static int airo_set_auth(struct net_device *dev,
 {
 	struct airo_info *local = dev->priv;
 	struct iw_param *param = &wrqu->param;
-	u16 currentAuthType = local->config.authType;
+	__le16 currentAuthType = local->config.authType;
 
 	switch (param->flags & IW_AUTH_INDEX) {
 	case IW_AUTH_WPA_VERSION:
@@ -6700,7 +6644,7 @@ static int airo_get_auth(struct net_device *dev,
 {
 	struct airo_info *local = dev->priv;
 	struct iw_param *param = &wrqu->param;
-	u16 currentAuthType = local->config.authType;
+	__le16 currentAuthType = local->config.authType;
 
 	switch (param->flags & IW_AUTH_INDEX) {
 	case IW_AUTH_DROP_UNENCRYPTED:
@@ -6751,6 +6695,7 @@ static int airo_set_txpow(struct net_device *dev,
 	CapabilityRid cap_rid;		/* Card capability info */
 	int i;
 	int rc = -EINVAL;
+	__le16 v = cpu_to_le16(vwrq->value);
 
 	readCapabilityRid(local, &cap_rid, 1);
 
@@ -6764,9 +6709,9 @@ static int airo_set_txpow(struct net_device *dev,
 	}
 	clear_bit (FLAG_RADIO_OFF, &local->flags);
 	for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
-		if ((vwrq->value==cap_rid.txPowerLevels[i])) {
+		if (v == cap_rid.txPowerLevels[i]) {
 			readConfigRid(local, 1);
-			local->config.txPower = vwrq->value;
+			local->config.txPower = v;
 			set_bit (FLAG_COMMIT, &local->flags);
 			rc = -EINPROGRESS;	/* Call commit handler */
 			break;
@@ -6786,7 +6731,7 @@ static int airo_get_txpow(struct net_device *dev,
 	struct airo_info *local = dev->priv;
 
 	readConfigRid(local, 1);
-	vwrq->value = local->config.txPower;
+	vwrq->value = le16_to_cpu(local->config.txPower);
 	vwrq->fixed = 1;	/* No power control */
 	vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
 	vwrq->flags = IW_TXPOW_MWATT;
@@ -6811,20 +6756,21 @@ static int airo_set_retry(struct net_device *dev,
 	}
 	readConfigRid(local, 1);
 	if(vwrq->flags & IW_RETRY_LIMIT) {
+		__le16 v = cpu_to_le16(vwrq->value);
 		if(vwrq->flags & IW_RETRY_LONG)
-			local->config.longRetryLimit = vwrq->value;
+			local->config.longRetryLimit = v;
 		else if (vwrq->flags & IW_RETRY_SHORT)
-			local->config.shortRetryLimit = vwrq->value;
+			local->config.shortRetryLimit = v;
 		else {
 			/* No modifier : set both */
-			local->config.longRetryLimit = vwrq->value;
-			local->config.shortRetryLimit = vwrq->value;
+			local->config.longRetryLimit = v;
+			local->config.shortRetryLimit = v;
 		}
 		set_bit (FLAG_COMMIT, &local->flags);
 		rc = -EINPROGRESS;		/* Call commit handler */
 	}
 	if(vwrq->flags & IW_RETRY_LIFETIME) {
-		local->config.txLifetime = vwrq->value / 1024;
+		local->config.txLifetime = cpu_to_le16(vwrq->value / 1024);
 		set_bit (FLAG_COMMIT, &local->flags);
 		rc = -EINPROGRESS;		/* Call commit handler */
 	}
@@ -6848,14 +6794,14 @@ static int airo_get_retry(struct net_device *dev,
 	/* Note : by default, display the min retry number */
 	if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
 		vwrq->flags = IW_RETRY_LIFETIME;
-		vwrq->value = (int)local->config.txLifetime * 1024;
+		vwrq->value = le16_to_cpu(local->config.txLifetime) * 1024;
 	} else if((vwrq->flags & IW_RETRY_LONG)) {
 		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
-		vwrq->value = (int)local->config.longRetryLimit;
+		vwrq->value = le16_to_cpu(local->config.longRetryLimit);
 	} else {
 		vwrq->flags = IW_RETRY_LIMIT;
-		vwrq->value = (int)local->config.shortRetryLimit;
-		if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
+		vwrq->value = le16_to_cpu(local->config.shortRetryLimit);
+		if(local->config.shortRetryLimit != local->config.longRetryLimit)
 			vwrq->flags |= IW_RETRY_SHORT;
 	}
 
@@ -6936,16 +6882,17 @@ static int airo_get_range(struct net_device *dev,
 	range->min_frag = 256;
 	range->max_frag = AIRO_DEF_MTU;
 
-	if(cap_rid.softCap & 2) {
+	if(cap_rid.softCap & cpu_to_le16(2)) {
 		// WEP: RC4 40 bits
 		range->encoding_size[0] = 5;
 		// RC4 ~128 bits
-		if (cap_rid.softCap & 0x100) {
+		if (cap_rid.softCap & cpu_to_le16(0x100)) {
 			range->encoding_size[1] = 13;
 			range->num_encoding_sizes = 2;
 		} else
 			range->num_encoding_sizes = 1;
-		range->max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1;
+		range->max_encoding_tokens =
+			cap_rid.softCap & cpu_to_le16(0x80) ? 4 : 1;
 	} else {
 		range->num_encoding_sizes = 0;
 		range->max_encoding_tokens = 0;
@@ -6960,7 +6907,7 @@ static int airo_get_range(struct net_device *dev,
 
 	/* Transmit Power - values are in mW */
 	for(i = 0 ; i < 8 ; i++) {
-		range->txpower[i] = cap_rid.txPowerLevels[i];
+		range->txpower[i] = le16_to_cpu(cap_rid.txPowerLevels[i]);
 		if(range->txpower[i] == 0)
 			break;
 	}
@@ -6999,38 +6946,37 @@ static int airo_set_power(struct net_device *dev,
 
 	readConfigRid(local, 1);
 	if (vwrq->disabled) {
-		if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
+		if (sniffing_mode(local))
 			return -EINVAL;
-		}
 		local->config.powerSaveMode = POWERSAVE_CAM;
-		local->config.rmode &= 0xFF00;
+		local->config.rmode &= ~RXMODE_MASK;
 		local->config.rmode |= RXMODE_BC_MC_ADDR;
 		set_bit (FLAG_COMMIT, &local->flags);
 		return -EINPROGRESS;		/* Call commit handler */
 	}
 	if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-		local->config.fastListenDelay = (vwrq->value + 500) / 1024;
+		local->config.fastListenDelay = cpu_to_le16((vwrq->value + 500) / 1024);
 		local->config.powerSaveMode = POWERSAVE_PSPCAM;
 		set_bit (FLAG_COMMIT, &local->flags);
 	} else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
-		local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024;
+		local->config.fastListenInterval =
+		local->config.listenInterval =
+			cpu_to_le16((vwrq->value + 500) / 1024);
 		local->config.powerSaveMode = POWERSAVE_PSPCAM;
 		set_bit (FLAG_COMMIT, &local->flags);
 	}
 	switch (vwrq->flags & IW_POWER_MODE) {
 		case IW_POWER_UNICAST_R:
-			if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
+			if (sniffing_mode(local))
 				return -EINVAL;
-			}
-			local->config.rmode &= 0xFF00;
+			local->config.rmode &= ~RXMODE_MASK;
 			local->config.rmode |= RXMODE_ADDR;
 			set_bit (FLAG_COMMIT, &local->flags);
 			break;
 		case IW_POWER_ALL_R:
-			if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
+			if (sniffing_mode(local))
 				return -EINVAL;
-			}
-			local->config.rmode &= 0xFF00;
+			local->config.rmode &= ~RXMODE_MASK;
 			local->config.rmode |= RXMODE_BC_MC_ADDR;
 			set_bit (FLAG_COMMIT, &local->flags);
 		case IW_POWER_ON:
@@ -7054,20 +7000,20 @@ static int airo_get_power(struct net_device *dev,
 			  char *extra)
 {
 	struct airo_info *local = dev->priv;
-	int mode;
+	__le16 mode;
 
 	readConfigRid(local, 1);
 	mode = local->config.powerSaveMode;
 	if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
 		return 0;
 	if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-		vwrq->value = (int)local->config.fastListenDelay * 1024;
+		vwrq->value = le16_to_cpu(local->config.fastListenDelay) * 1024;
 		vwrq->flags = IW_POWER_TIMEOUT;
 	} else {
-		vwrq->value = (int)local->config.fastListenInterval * 1024;
+		vwrq->value = le16_to_cpu(local->config.fastListenInterval) * 1024;
 		vwrq->flags = IW_POWER_PERIOD;
 	}
-	if ((local->config.rmode & 0xFF) == RXMODE_ADDR)
+	if ((local->config.rmode & RXMODE_MASK) == RXMODE_ADDR)
 		vwrq->flags |= IW_POWER_UNICAST_R;
 	else
 		vwrq->flags |= IW_POWER_ALL_R;
@@ -7087,7 +7033,8 @@ static int airo_set_sens(struct net_device *dev,
 	struct airo_info *local = dev->priv;
 
 	readConfigRid(local, 1);
-	local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
+	local->config.rssiThreshold =
+		cpu_to_le16(vwrq->disabled ? RSSI_DEFAULT : vwrq->value);
 	set_bit (FLAG_COMMIT, &local->flags);
 
 	return -EINPROGRESS;		/* Call commit handler */
@@ -7105,7 +7052,7 @@ static int airo_get_sens(struct net_device *dev,
 	struct airo_info *local = dev->priv;
 
 	readConfigRid(local, 1);
-	vwrq->value = local->config.rssiThreshold;
+	vwrq->value = le16_to_cpu(local->config.rssiThreshold);
 	vwrq->disabled = (vwrq->value == 0);
 	vwrq->fixed = 1;
 
@@ -7130,26 +7077,28 @@ static int airo_get_aplist(struct net_device *dev,
 	int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
 
 	for (i = 0; i < IW_MAX_AP; i++) {
+		u16 dBm;
 		if (readBSSListRid(local, loseSync, &BSSList))
 			break;
 		loseSync = 0;
 		memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
 		address[i].sa_family = ARPHRD_ETHER;
+		dBm = le16_to_cpu(BSSList.dBm);
 		if (local->rssi) {
-			qual[i].level = 0x100 - BSSList.dBm;
-			qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
+			qual[i].level = 0x100 - dBm;
+			qual[i].qual = airo_dbm_to_pct(local->rssi, dBm);
 			qual[i].updated = IW_QUAL_QUAL_UPDATED
 					| IW_QUAL_LEVEL_UPDATED
 					| IW_QUAL_DBM;
 		} else {
-			qual[i].level = (BSSList.dBm + 321) / 2;
+			qual[i].level = (dBm + 321) / 2;
 			qual[i].qual = 0;
 			qual[i].updated = IW_QUAL_QUAL_INVALID
 					| IW_QUAL_LEVEL_UPDATED
 					| IW_QUAL_DBM;
 		}
 		qual[i].noise = local->wstats.qual.noise;
-		if (BSSList.index == 0xffff)
+		if (BSSList.index == cpu_to_le16(0xffff))
 			break;
 	}
 	if (!i) {
@@ -7240,10 +7189,11 @@ static inline char *airo_translate_scan(struct net_device *dev,
 {
 	struct airo_info *ai = dev->priv;
 	struct iw_event		iwe;		/* Temporary buffer */
-	u16			capabilities;
+	__le16			capabilities;
 	char *			current_val;	/* For rates */
 	int			i;
 	char *		buf;
+	u16 dBm;
 
 	/* First entry *MUST* be the AP MAC address */
 	iwe.cmd = SIOCGIWAP;
@@ -7263,7 +7213,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
 
 	/* Add mode */
 	iwe.cmd = SIOCGIWMODE;
-	capabilities = le16_to_cpu(bss->cap);
+	capabilities = bss->cap;
 	if(capabilities & (CAP_ESS | CAP_IBSS)) {
 		if(capabilities & CAP_ESS)
 			iwe.u.mode = IW_MODE_MASTER;
@@ -7282,16 +7232,18 @@ static inline char *airo_translate_scan(struct net_device *dev,
 	iwe.u.freq.e = 1;
 	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
 
+	dBm = le16_to_cpu(bss->dBm);
+
 	/* Add quality statistics */
 	iwe.cmd = IWEVQUAL;
 	if (ai->rssi) {
-		iwe.u.qual.level = 0x100 - bss->dBm;
-		iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm );
+		iwe.u.qual.level = 0x100 - dBm;
+		iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm);
 		iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
 				| IW_QUAL_LEVEL_UPDATED
 				| IW_QUAL_DBM;
 	} else {
-		iwe.u.qual.level = (bss->dBm + 321) / 2;
+		iwe.u.qual.level = (dBm + 321) / 2;
 		iwe.u.qual.qual = 0;
 		iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
 				| IW_QUAL_LEVEL_UPDATED
@@ -7670,7 +7622,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
 	StatusRid status_rid;
 	StatsRid stats_rid;
 	CapabilityRid cap_rid;
-	u32 *vals = stats_rid.vals;
+	__le32 *vals = stats_rid.vals;
 
 	/* Get stats out of the card */
 	clear_bit(JOB_WSTATS, &local->jobs);
@@ -7684,18 +7636,22 @@ static void airo_read_wireless_stats(struct airo_info *local)
 	up(&local->sem);
 
 	/* The status */
-	local->wstats.status = status_rid.mode;
+	local->wstats.status = le16_to_cpu(status_rid.mode);
 
 	/* Signal quality and co */
 	if (local->rssi) {
-		local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality );
+		local->wstats.qual.level =
+			airo_rssi_to_dbm(local->rssi,
+					 le16_to_cpu(status_rid.sigQuality));
 		/* normalizedSignalStrength appears to be a percentage */
-		local->wstats.qual.qual = status_rid.normalizedSignalStrength;
+		local->wstats.qual.qual =
+			le16_to_cpu(status_rid.normalizedSignalStrength);
 	} else {
-		local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
+		local->wstats.qual.level =
+			(le16_to_cpu(status_rid.normalizedSignalStrength) + 321) / 2;
 		local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
 	}
-	if (status_rid.len >= 124) {
+	if (le16_to_cpu(status_rid.len) >= 124) {
 		local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
 		local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 	} else {
@@ -7705,12 +7661,15 @@ static void airo_read_wireless_stats(struct airo_info *local)
 
 	/* Packets discarded in the wireless adapter due to wireless
 	 * specific problems */
-	local->wstats.discard.nwid = vals[56] + vals[57] + vals[58];/* SSID Mismatch */
-	local->wstats.discard.code = vals[6];/* RxWepErr */
-	local->wstats.discard.fragment = vals[30];
-	local->wstats.discard.retries = vals[10];
-	local->wstats.discard.misc = vals[1] + vals[32];
-	local->wstats.miss.beacon = vals[34];
+	local->wstats.discard.nwid = le32_to_cpu(vals[56]) +
+				     le32_to_cpu(vals[57]) +
+				     le32_to_cpu(vals[58]); /* SSID Mismatch */
+	local->wstats.discard.code = le32_to_cpu(vals[6]);/* RxWepErr */
+	local->wstats.discard.fragment = le32_to_cpu(vals[30]);
+	local->wstats.discard.retries = le32_to_cpu(vals[10]);
+	local->wstats.discard.misc = le32_to_cpu(vals[1]) +
+				     le32_to_cpu(vals[32]);
+	local->wstats.miss.beacon = le32_to_cpu(vals[34]);
 }
 
 static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
@@ -7896,7 +7855,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
 		if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
 			cfg->opmode |= MODE_MIC;
 
-		if ((cfg->opmode & 0xFF) == MODE_STA_IBSS)
+		if ((cfg->opmode & MODE_CFG_MASK) == MODE_STA_IBSS)
 			set_bit (FLAG_ADHOC, &ai->flags);
 		else
 			clear_bit (FLAG_ADHOC, &ai->flags);
diff --git a/drivers/net/wireless/ath5k/Makefile b/drivers/net/wireless/ath5k/Makefile
new file mode 100644
index 000000000000..321641f99e13
--- /dev/null
+++ b/drivers/net/wireless/ath5k/Makefile
@@ -0,0 +1,2 @@
+ath5k-objs		= base.o hw.o regdom.o initvals.o phy.o debug.o
+obj-$(CONFIG_ATH5K)	+= ath5k.o
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
new file mode 100644
index 000000000000..c79066b38d3b
--- /dev/null
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -0,0 +1,1173 @@
+/*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _ATH5K_H
+#define _ATH5K_H
+
+/* Set this to 1 to disable regulatory domain restrictions for channel tests.
+ * WARNING: This is for debuging only and has side effects (eg. scan takes too
+ * long and results timeouts). It's also illegal to tune to some of the
+ * supported frequencies in some countries, so use this at your own risk,
+ * you've been warned. */
+#define CHAN_DEBUG	0
+
+#include <linux/io.h>
+#include <linux/types.h>
+#include <net/mac80211.h>
+
+#include "hw.h"
+#include "regdom.h"
+
+/* PCI IDs */
+#define PCI_DEVICE_ID_ATHEROS_AR5210 		0x0007 /* AR5210 */
+#define PCI_DEVICE_ID_ATHEROS_AR5311 		0x0011 /* AR5311 */
+#define PCI_DEVICE_ID_ATHEROS_AR5211 		0x0012 /* AR5211 */
+#define PCI_DEVICE_ID_ATHEROS_AR5212 		0x0013 /* AR5212 */
+#define PCI_DEVICE_ID_3COM_3CRDAG675 		0x0013 /* 3CRDAG675 (Atheros AR5212) */
+#define PCI_DEVICE_ID_3COM_2_3CRPAG175 		0x0013 /* 3CRPAG175 (Atheros AR5212) */
+#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 	0x0207 /* AR5210 (Early) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_IBM	0x1014 /* AR5212 (IBM MiniPCI) */
+#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 	0x1107 /* AR5210 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 	0x1113 /* AR5212 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 	0x1112 /* AR5211 (no eeprom) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 	0xf013 /* AR5212 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 	0xff12 /* AR5211 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 	0xf11b /* AR5211 (emulation board) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 	0x0052 /* AR5312 WMAC (AP31) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 	0x0057 /* AR5312 WMAC (AP30-040) */
+#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 	0x0058 /* AR5312 WMAC (AP43-030) */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 	0x0014 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 	0x0015 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 	0x0016 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 	0x0017 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 	0x0018 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 	0x0019 /* AR5212 compatible */
+#define PCI_DEVICE_ID_ATHEROS_AR2413 		0x001a /* AR2413 (Griffin-lite) */
+#define PCI_DEVICE_ID_ATHEROS_AR5413 		0x001b /* AR5413 (Eagle) */
+#define PCI_DEVICE_ID_ATHEROS_AR5424 		0x001c /* AR5424 (Condor PCI-E) */
+#define PCI_DEVICE_ID_ATHEROS_AR5416 		0x0023 /* AR5416 */
+#define PCI_DEVICE_ID_ATHEROS_AR5418 		0x0024 /* AR5418 */
+
+/****************************\
+  GENERIC DRIVER DEFINITIONS
+\****************************/
+
+#define ATH5K_PRINTF(fmt, ...)   printk("%s: " fmt, __func__, ##__VA_ARGS__)
+
+#define ATH5K_PRINTK(_sc, _level, _fmt, ...) \
+	printk(_level "ath5k %s: " _fmt, \
+		((_sc) && (_sc)->hw) ? wiphy_name((_sc)->hw->wiphy) : "", \
+		##__VA_ARGS__)
+
+#define ATH5K_PRINTK_LIMIT(_sc, _level, _fmt, ...) do { \
+	if (net_ratelimit()) \
+		ATH5K_PRINTK(_sc, _level, _fmt, ##__VA_ARGS__); \
+	} while (0)
+
+#define ATH5K_INFO(_sc, _fmt, ...) \
+	ATH5K_PRINTK(_sc, KERN_INFO, _fmt, ##__VA_ARGS__)
+
+#define ATH5K_WARN(_sc, _fmt, ...) \
+	ATH5K_PRINTK_LIMIT(_sc, KERN_WARNING, _fmt, ##__VA_ARGS__)
+
+#define ATH5K_ERR(_sc, _fmt, ...) \
+	ATH5K_PRINTK_LIMIT(_sc, KERN_ERR, _fmt, ##__VA_ARGS__)
+
+/*
+ * Some tuneable values (these should be changeable by the user)
+ */
+#define AR5K_TUNE_DMA_BEACON_RESP		2
+#define AR5K_TUNE_SW_BEACON_RESP		10
+#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF	0
+#define AR5K_TUNE_RADAR_ALERT			false
+#define AR5K_TUNE_MIN_TX_FIFO_THRES		1
+#define AR5K_TUNE_MAX_TX_FIFO_THRES		((IEEE80211_MAX_LEN / 64) + 1)
+#define AR5K_TUNE_REGISTER_TIMEOUT		20000
+/* Register for RSSI threshold has a mask of 0xff, so 255 seems to
+ * be the max value. */
+#define AR5K_TUNE_RSSI_THRES                   129
+/* This must be set when setting the RSSI threshold otherwise it can
+ * prevent a reset. If AR5K_RSSI_THR is read after writing to it
+ * the BMISS_THRES will be seen as 0, seems harware doesn't keep
+ * track of it. Max value depends on harware. For AR5210 this is just 7.
+ * For AR5211+ this seems to be up to 255. */
+#define AR5K_TUNE_BMISS_THRES                  7
+#define AR5K_TUNE_REGISTER_DWELL_TIME		20000
+#define AR5K_TUNE_BEACON_INTERVAL		100
+#define AR5K_TUNE_AIFS				2
+#define AR5K_TUNE_AIFS_11B			2
+#define AR5K_TUNE_AIFS_XR			0
+#define AR5K_TUNE_CWMIN				15
+#define AR5K_TUNE_CWMIN_11B			31
+#define AR5K_TUNE_CWMIN_XR			3
+#define AR5K_TUNE_CWMAX				1023
+#define AR5K_TUNE_CWMAX_11B			1023
+#define AR5K_TUNE_CWMAX_XR			7
+#define AR5K_TUNE_NOISE_FLOOR			-72
+#define AR5K_TUNE_MAX_TXPOWER			60
+#define AR5K_TUNE_DEFAULT_TXPOWER		30
+#define AR5K_TUNE_TPC_TXPOWER			true
+#define AR5K_TUNE_ANT_DIVERSITY			true
+#define AR5K_TUNE_HWTXTRIES			4
+
+/* token to use for aifs, cwmin, cwmax in MadWiFi */
+#define	AR5K_TXQ_USEDEFAULT	((u32) -1)
+
+/* GENERIC CHIPSET DEFINITIONS */
+
+/* MAC Chips */
+enum ath5k_version {
+	AR5K_AR5210	= 0,
+	AR5K_AR5211	= 1,
+	AR5K_AR5212	= 2,
+};
+
+/* PHY Chips */
+enum ath5k_radio {
+	AR5K_RF5110	= 0,
+	AR5K_RF5111	= 1,
+	AR5K_RF5112	= 2,
+	AR5K_RF5413	= 3,
+};
+
+/*
+ * Common silicon revision/version values
+ */
+
+enum ath5k_srev_type {
+	AR5K_VERSION_VER,
+	AR5K_VERSION_RAD,
+};
+
+struct ath5k_srev_name {
+	const char		*sr_name;
+	enum ath5k_srev_type	sr_type;
+	u_int			sr_val;
+};
+
+#define AR5K_SREV_UNKNOWN	0xffff
+
+#define AR5K_SREV_VER_AR5210	0x00
+#define AR5K_SREV_VER_AR5311	0x10
+#define AR5K_SREV_VER_AR5311A	0x20
+#define AR5K_SREV_VER_AR5311B	0x30
+#define AR5K_SREV_VER_AR5211	0x40
+#define AR5K_SREV_VER_AR5212	0x50
+#define AR5K_SREV_VER_AR5213	0x55
+#define AR5K_SREV_VER_AR5213A	0x59
+#define AR5K_SREV_VER_AR2424	0xa0
+#define AR5K_SREV_VER_AR5424	0xa3
+#define AR5K_SREV_VER_AR5413	0xa4
+#define AR5K_SREV_VER_AR5414	0xa5
+#define AR5K_SREV_VER_AR5416	0xc0	/* ? */
+#define AR5K_SREV_VER_AR5418	0xca
+
+#define AR5K_SREV_RAD_5110	0x00
+#define AR5K_SREV_RAD_5111	0x10
+#define AR5K_SREV_RAD_5111A	0x15
+#define AR5K_SREV_RAD_2111	0x20
+#define AR5K_SREV_RAD_5112	0x30
+#define AR5K_SREV_RAD_5112A	0x35
+#define AR5K_SREV_RAD_2112	0x40
+#define AR5K_SREV_RAD_2112A	0x45
+#define AR5K_SREV_RAD_SC1	0x63	/* Found on 5413/5414 */
+#define AR5K_SREV_RAD_SC2	0xa2	/* Found on 2424/5424 */
+#define AR5K_SREV_RAD_5133	0xc0	/* MIMO found on 5418 */
+
+/* IEEE defs */
+
+#define IEEE80211_MAX_LEN       2500
+
+/* TODO add support to mac80211 for vendor-specific rates and modes */
+
+/*
+ * Some of this information is based on Documentation from:
+ *
+ * http://madwifi.org/wiki/ChipsetFeatures/SuperAG
+ *
+ * Modulation for Atheros' eXtended Range - range enhancing extension that is
+ * supposed to double the distance an Atheros client device can keep a
+ * connection with an Atheros access point. This is achieved by increasing
+ * the receiver sensitivity up to, -105dBm, which is about 20dB above what
+ * the 802.11 specifications demand. In addition, new (proprietary) data rates
+ * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s.
+ *
+ * Please note that can you either use XR or TURBO but you cannot use both,
+ * they are exclusive.
+ *
+ */
+#define MODULATION_XR 		0x00000200
+/*
+ * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a
+ * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s
+ * signaling rate achieved through the bonding of two 54Mbit/s 802.11g
+ * channels. To use this feature your Access Point must also suport it.
+ * There is also a distinction between "static" and "dynamic" turbo modes:
+ *
+ * - Static: is the dumb version: devices set to this mode stick to it until
+ *     the mode is turned off.
+ * - Dynamic: is the intelligent version, the network decides itself if it
+ *     is ok to use turbo. As soon as traffic is detected on adjacent channels
+ *     (which would get used in turbo mode), or when a non-turbo station joins
+ *     the network, turbo mode won't be used until the situation changes again.
+ *     Dynamic mode is achieved by Atheros' Adaptive Radio (AR) feature which
+ *     monitors the used radio band in order to decide whether turbo mode may
+ *     be used or not.
+ *
+ * This article claims Super G sticks to bonding of channels 5 and 6 for
+ * USA:
+ *
+ * http://www.pcworld.com/article/id,113428-page,1/article.html
+ *
+ * The channel bonding seems to be driver specific though. In addition to
+ * deciding what channels will be used, these "Turbo" modes are accomplished
+ * by also enabling the following features:
+ *
+ * - Bursting: allows multiple frames to be sent at once, rather than pausing
+ *     after each frame. Bursting is a standards-compliant feature that can be
+ *     used with any Access Point.
+ * - Fast frames: increases the amount of information that can be sent per
+ *     frame, also resulting in a reduction of transmission overhead. It is a
+ *     proprietary feature that needs to be supported by the Access Point.
+ * - Compression: data frames are compressed in real time using a Lempel Ziv
+ *     algorithm. This is done transparently. Once this feature is enabled,
+ *     compression and decompression takes place inside the chipset, without
+ *     putting additional load on the host CPU.
+ *
+ */
+#define MODULATION_TURBO	0x00000080
+
+enum ath5k_vendor_mode {
+	MODE_ATHEROS_TURBO = NUM_IEEE80211_MODES+1,
+	MODE_ATHEROS_TURBOG
+};
+
+/* Number of supported mac80211 enum ieee80211_phymode modes by this driver */
+#define NUM_DRIVER_MODES	3
+
+/* adding this flag to rate_code enables short preamble, see ar5212_reg.h */
+#define AR5K_SET_SHORT_PREAMBLE 0x04
+
+#define HAS_SHPREAMBLE(_ix) (rt->rates[_ix].modulation == IEEE80211_RATE_CCK_2)
+#define SHPREAMBLE_FLAG(_ix) (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0)
+
+/****************\
+  TX DEFINITIONS
+\****************/
+
+/*
+ * Tx Descriptor
+ */
+struct ath5k_tx_status {
+	u16	ts_seqnum;
+	u16	ts_tstamp;
+	u8	ts_status;
+	u8	ts_rate;
+	s8	ts_rssi;
+	u8	ts_shortretry;
+	u8	ts_longretry;
+	u8	ts_virtcol;
+	u8	ts_antenna;
+};
+
+#define AR5K_TXSTAT_ALTRATE	0x80
+#define AR5K_TXERR_XRETRY	0x01
+#define AR5K_TXERR_FILT		0x02
+#define AR5K_TXERR_FIFO		0x04
+
+/**
+ * enum ath5k_tx_queue - Queue types used to classify tx queues.
+ * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue
+ * @AR5K_TX_QUEUE_DATA: A normal data queue
+ * @AR5K_TX_QUEUE_XR_DATA: An XR-data queue
+ * @AR5K_TX_QUEUE_BEACON: The beacon queue
+ * @AR5K_TX_QUEUE_CAB: The after-beacon queue
+ * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue
+ */
+enum ath5k_tx_queue {
+	AR5K_TX_QUEUE_INACTIVE = 0,
+	AR5K_TX_QUEUE_DATA,
+	AR5K_TX_QUEUE_XR_DATA,
+	AR5K_TX_QUEUE_BEACON,
+	AR5K_TX_QUEUE_CAB,
+	AR5K_TX_QUEUE_UAPSD,
+};
+
+#define	AR5K_NUM_TX_QUEUES		10
+#define	AR5K_NUM_TX_QUEUES_NOQCU	2
+
+/*
+ * Queue syb-types to classify normal data queues.
+ * These are the 4 Access Categories as defined in
+ * WME spec. 0 is the lowest priority and 4 is the
+ * highest. Normal data that hasn't been classified
+ * goes to the Best Effort AC.
+ */
+enum ath5k_tx_queue_subtype {
+	AR5K_WME_AC_BK = 0,	/*Background traffic*/
+	AR5K_WME_AC_BE, 	/*Best-effort (normal) traffic)*/
+	AR5K_WME_AC_VI, 	/*Video traffic*/
+	AR5K_WME_AC_VO, 	/*Voice traffic*/
+};
+
+/*
+ * Queue ID numbers as returned by the hw functions, each number
+ * represents a hw queue. If hw does not support hw queues
+ * (eg 5210) all data goes in one queue. These match
+ * d80211 definitions (net80211/MadWiFi don't use them).
+ */
+enum ath5k_tx_queue_id {
+	AR5K_TX_QUEUE_ID_NOQCU_DATA	= 0,
+	AR5K_TX_QUEUE_ID_NOQCU_BEACON	= 1,
+	AR5K_TX_QUEUE_ID_DATA_MIN	= 0, /*IEEE80211_TX_QUEUE_DATA0*/
+	AR5K_TX_QUEUE_ID_DATA_MAX	= 4, /*IEEE80211_TX_QUEUE_DATA4*/
+	AR5K_TX_QUEUE_ID_DATA_SVP	= 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/
+	AR5K_TX_QUEUE_ID_CAB		= 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/
+	AR5K_TX_QUEUE_ID_BEACON		= 7, /*IEEE80211_TX_QUEUE_BEACON*/
+	AR5K_TX_QUEUE_ID_UAPSD		= 8,
+	AR5K_TX_QUEUE_ID_XR_DATA	= 9,
+};
+
+
+/*
+ * Flags to set hw queue's parameters...
+ */
+#define AR5K_TXQ_FLAG_TXOKINT_ENABLE		0x0001	/* Enable TXOK interrupt */
+#define AR5K_TXQ_FLAG_TXERRINT_ENABLE		0x0002	/* Enable TXERR interrupt */
+#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE		0x0004	/* Enable TXEOL interrupt -not used- */
+#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE		0x0008	/* Enable TXDESC interrupt -not used- */
+#define AR5K_TXQ_FLAG_TXURNINT_ENABLE		0x0010	/* Enable TXURN interrupt */
+#define AR5K_TXQ_FLAG_BACKOFF_DISABLE		0x0020	/* Disable random post-backoff */
+#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE	0x0040	/* Enable ready time expiry policy (?)*/
+#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE	0x0080	/* Enable backoff while bursting */
+#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS		0x0100	/* Disable backoff while bursting */
+#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE	0x0200	/* Enable hw compression -not implemented-*/
+
+/*
+ * A struct to hold tx queue's parameters
+ */
+struct ath5k_txq_info {
+	enum ath5k_tx_queue tqi_type;
+	enum ath5k_tx_queue_subtype tqi_subtype;
+	u16	tqi_flags;	/* Tx queue flags (see above) */
+	u32	tqi_aifs;	/* Arbitrated Interframe Space */
+	s32	tqi_cw_min;	/* Minimum Contention Window */
+	s32	tqi_cw_max;	/* Maximum Contention Window */
+	u32	tqi_cbr_period; /* Constant bit rate period */
+	u32	tqi_cbr_overflow_limit;
+	u32	tqi_burst_time;
+	u32	tqi_ready_time; /* Not used */
+};
+
+/*
+ * Transmit packet types.
+ * These are not fully used inside OpenHAL yet
+ */
+enum ath5k_pkt_type {
+	AR5K_PKT_TYPE_NORMAL		= 0,
+	AR5K_PKT_TYPE_ATIM		= 1,
+	AR5K_PKT_TYPE_PSPOLL		= 2,
+	AR5K_PKT_TYPE_BEACON		= 3,
+	AR5K_PKT_TYPE_PROBE_RESP	= 4,
+	AR5K_PKT_TYPE_PIFS		= 5,
+};
+
+/*
+ * TX power and TPC settings
+ */
+#define AR5K_TXPOWER_OFDM(_r, _v)	(			\
+	((0 & 1) << ((_v) + 6)) |				\
+	(((ah->ah_txpower.txp_rates[(_r)]) & 0x3f) << (_v))	\
+)
+
+#define AR5K_TXPOWER_CCK(_r, _v)	(			\
+	(ah->ah_txpower.txp_rates[(_r)] & 0x3f) << (_v)	\
+)
+
+/*
+ * DMA size definitions (2^n+2)
+ */
+enum ath5k_dmasize {
+	AR5K_DMASIZE_4B	= 0,
+	AR5K_DMASIZE_8B,
+	AR5K_DMASIZE_16B,
+	AR5K_DMASIZE_32B,
+	AR5K_DMASIZE_64B,
+	AR5K_DMASIZE_128B,
+	AR5K_DMASIZE_256B,
+	AR5K_DMASIZE_512B
+};
+
+
+/****************\
+  RX DEFINITIONS
+\****************/
+
+/*
+ * Rx Descriptor
+ */
+struct ath5k_rx_status {
+	u16	rs_datalen;
+	u16	rs_tstamp;
+	u8	rs_status;
+	u8	rs_phyerr;
+	s8	rs_rssi;
+	u8	rs_keyix;
+	u8	rs_rate;
+	u8	rs_antenna;
+	u8	rs_more;
+};
+
+#define AR5K_RXERR_CRC		0x01
+#define AR5K_RXERR_PHY		0x02
+#define AR5K_RXERR_FIFO		0x04
+#define AR5K_RXERR_DECRYPT	0x08
+#define AR5K_RXERR_MIC		0x10
+#define AR5K_RXKEYIX_INVALID	((u8) - 1)
+#define AR5K_TXKEYIX_INVALID	((u32) - 1)
+
+struct ath5k_mib_stats {
+	u32	ackrcv_bad;
+	u32	rts_bad;
+	u32	rts_good;
+	u32	fcs_bad;
+	u32	beacons;
+};
+
+
+
+
+/**************************\
+ BEACON TIMERS DEFINITIONS
+\**************************/
+
+#define AR5K_BEACON_PERIOD	0x0000ffff
+#define AR5K_BEACON_ENA		0x00800000 /*enable beacon xmit*/
+#define AR5K_BEACON_RESET_TSF	0x01000000 /*force a TSF reset*/
+
+#if 0
+/**
+ * struct ath5k_beacon_state - Per-station beacon timer state.
+ * @bs_interval: in TU's, can also include the above flags
+ * @bs_cfp_max_duration: if non-zero hw is setup to coexist with a
+ * 	Point Coordination Function capable AP
+ */
+struct ath5k_beacon_state {
+	u32	bs_next_beacon;
+	u32	bs_next_dtim;
+	u32	bs_interval;
+	u8	bs_dtim_period;
+	u8	bs_cfp_period;
+	u16	bs_cfp_max_duration;
+	u16	bs_cfp_du_remain;
+	u16	bs_tim_offset;
+	u16	bs_sleep_duration;
+	u16	bs_bmiss_threshold;
+	u32  	bs_cfp_next;
+};
+#endif
+
+
+/*
+ * TSF to TU conversion:
+ *
+ * TSF is a 64bit value in usec (microseconds).
+ * TU is a 32bit value and defined by IEEE802.11 (page 6) as "A measurement of
+ * time equal to 1024 usec", so it's roughly milliseconds (usec / 1024).
+ */
+#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10)
+
+
+
+/********************\
+  COMMON DEFINITIONS
+\********************/
+
+/*
+ * Atheros descriptor
+ */
+struct ath5k_desc {
+	u32	ds_link;
+	u32	ds_data;
+	u32	ds_ctl0;
+	u32	ds_ctl1;
+	u32	ds_hw[4];
+
+	union {
+		struct ath5k_rx_status rx;
+		struct ath5k_tx_status tx;
+	} ds_us;
+
+#define ds_rxstat ds_us.rx
+#define ds_txstat ds_us.tx
+
+} __packed;
+
+#define AR5K_RXDESC_INTREQ	0x0020
+
+#define AR5K_TXDESC_CLRDMASK	0x0001
+#define AR5K_TXDESC_NOACK	0x0002	/*[5211+]*/
+#define AR5K_TXDESC_RTSENA	0x0004
+#define AR5K_TXDESC_CTSENA	0x0008
+#define AR5K_TXDESC_INTREQ	0x0010
+#define AR5K_TXDESC_VEOL	0x0020	/*[5211+]*/
+
+#define AR5K_SLOT_TIME_9	396
+#define AR5K_SLOT_TIME_20	880
+#define AR5K_SLOT_TIME_MAX	0xffff
+
+/* channel_flags */
+#define	CHANNEL_CW_INT	0x0008	/* Contention Window interference detected */
+#define	CHANNEL_TURBO	0x0010	/* Turbo Channel */
+#define	CHANNEL_CCK	0x0020	/* CCK channel */
+#define	CHANNEL_OFDM	0x0040	/* OFDM channel */
+#define	CHANNEL_2GHZ	0x0080	/* 2GHz channel. */
+#define	CHANNEL_5GHZ	0x0100	/* 5GHz channel */
+#define	CHANNEL_PASSIVE	0x0200	/* Only passive scan allowed */
+#define	CHANNEL_DYN	0x0400	/* Dynamic CCK-OFDM channel (for g operation) */
+#define	CHANNEL_XR	0x0800	/* XR channel */
+
+#define	CHANNEL_A	(CHANNEL_5GHZ|CHANNEL_OFDM)
+#define	CHANNEL_B	(CHANNEL_2GHZ|CHANNEL_CCK)
+#define	CHANNEL_G	(CHANNEL_2GHZ|CHANNEL_OFDM)
+#define	CHANNEL_T	(CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
+#define	CHANNEL_TG	(CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
+#define	CHANNEL_108A	CHANNEL_T
+#define	CHANNEL_108G	CHANNEL_TG
+#define	CHANNEL_X	(CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR)
+
+#define	CHANNEL_ALL 	(CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \
+		CHANNEL_TURBO)
+
+#define	CHANNEL_ALL_NOTURBO 	(CHANNEL_ALL & ~CHANNEL_TURBO)
+#define CHANNEL_MODES		CHANNEL_ALL
+
+/*
+ * Used internaly in OpenHAL (ar5211.c/ar5212.c
+ * for reset_tx_queue). Also see struct struct ieee80211_channel.
+ */
+#define IS_CHAN_XR(_c)	((_c.val & CHANNEL_XR) != 0)
+#define IS_CHAN_B(_c)	((_c.val & CHANNEL_B) != 0)
+
+/*
+ * The following structure will be used to map 2GHz channels to
+ * 5GHz Atheros channels.
+ */
+struct ath5k_athchan_2ghz {
+	u32	a2_flags;
+	u16	a2_athchan;
+};
+
+/*
+ * Rate definitions
+ * TODO: Clean them up or move them on mac80211 -most of these infos are
+ * 	 used by the rate control algorytm on MadWiFi.
+ */
+
+/* Max number of rates on the rate table and what it seems
+ * Atheros hardware supports */
+#define AR5K_MAX_RATES 32
+
+/**
+ * struct ath5k_rate - rate structure
+ * @valid: is this a valid rate for the current mode
+ * @modulation: respective mac80211 modulation
+ * @rate_kbps: rate in kbit/s
+ * @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on
+ *     &struct ath5k_rx_status.rs_rate and on TX on
+ *     &struct ath5k_tx_status.ts_rate. Seems the ar5xxx harware supports
+ *     up to 32 rates, indexed by 1-32. This means we really only need
+ *     6 bits for the rate_code.
+ * @dot11_rate: respective IEEE-802.11 rate value
+ * @control_rate: index of rate assumed to be used to send control frames.
+ *     This can be used to set override the value on the rate duration
+ *     registers. This is only useful if we can override in the harware at
+ *     what rate we want to send control frames at. Note that IEEE-802.11
+ *     Ch. 9.6 (after IEEE 802.11g changes) defines the rate at which we
+ *     should send ACK/CTS, if we change this value we can be breaking
+ *     the spec.
+ *
+ * This structure is used to get the RX rate or set the TX rate on the
+ * hardware descriptors. It is also used for internal modulation control
+ * and settings.
+ *
+ * On RX after the &struct ath5k_desc is parsed by the appropriate
+ * ah_proc_rx_desc() the respective hardware rate value is set in
+ * &struct ath5k_rx_status.rs_rate. On TX the desired rate is set in
+ * &struct ath5k_tx_status.ts_rate which is later used to setup the
+ * &struct ath5k_desc correctly. This is the hardware rate map we are
+ * aware of:
+ *
+ * rate_code   1       2       3       4       5       6       7       8
+ * rate_kbps   3000    1000    ?       ?       ?       2000    500     48000
+ *
+ * rate_code   9       10      11      12      13      14      15      16
+ * rate_kbps   24000   12000   6000    54000   36000   18000   9000    ?
+ *
+ * rate_code   17      18      19      20      21      22      23      24
+ * rate_kbps   ?       ?       ?       ?       ?       ?       ?       11000
+ *
+ * rate_code   25      26      27      28      29      30      31      32
+ * rate_kbps   5500    2000    1000    ?       ?       ?       ?       ?
+ *
+ */
+struct ath5k_rate {
+	u8	valid;
+	u32	modulation;
+	u16	rate_kbps;
+	u8	rate_code;
+	u8	dot11_rate;
+	u8	control_rate;
+};
+
+/* XXX: GRR all this stuff to get leds blinking ??? (check out setcurmode) */
+struct ath5k_rate_table {
+	u16	rate_count;
+	u8	rate_code_to_index[AR5K_MAX_RATES];	/* Back-mapping */
+	struct ath5k_rate rates[AR5K_MAX_RATES];
+};
+
+/*
+ * Rate tables...
+ */
+#define AR5K_RATES_11A { 8, {					\
+	255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0,	\
+	7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255,	\
+	255, 255, 255, 255, 255, 255, 255, 255 }, {		\
+	{ 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 0 },		\
+	{ 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 0 },		\
+	{ 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 2 },		\
+	{ 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 2 },		\
+	{ 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 4 },		\
+	{ 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 4 },		\
+	{ 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 4 },		\
+	{ 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 4 } }		\
+}
+
+#define AR5K_RATES_11B { 4, {						\
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,	\
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,	\
+	3, 2, 1, 0, 255, 255, 255, 255 }, {				\
+	{ 1, IEEE80211_RATE_CCK, 1000, 27, 130, 0 },	\
+	{ 1, IEEE80211_RATE_CCK_2, 2000, 26, 132, 1 },	\
+	{ 1, IEEE80211_RATE_CCK_2, 5500, 25, 139, 1 },	\
+	{ 1, IEEE80211_RATE_CCK_2, 11000, 24, 150, 1 } }	\
+}
+
+#define AR5K_RATES_11G { 12, {					\
+	255, 255, 255, 255, 255, 255, 255, 255, 10, 8, 6, 4,	\
+	11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255,	\
+	3, 2, 1, 0, 255, 255, 255, 255 }, {			\
+	{ 1, IEEE80211_RATE_CCK, 1000, 27, 2, 0 },		\
+	{ 1, IEEE80211_RATE_CCK_2, 2000, 26, 4, 1 },		\
+	{ 1, IEEE80211_RATE_CCK_2, 5500, 25, 11, 1 },		\
+	{ 1, IEEE80211_RATE_CCK_2, 11000, 24, 22, 1 },	\
+	{ 0, IEEE80211_RATE_OFDM, 6000, 11, 12, 4 },	\
+	{ 0, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 },	\
+	{ 1, IEEE80211_RATE_OFDM, 12000, 10, 24, 6 },	\
+	{ 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 },	\
+	{ 1, IEEE80211_RATE_OFDM, 24000, 9, 48, 8 },	\
+	{ 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 },	\
+	{ 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 },	\
+	{ 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } }	\
+}
+
+#define AR5K_RATES_TURBO { 8, {					\
+	255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0,	\
+	7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255,	\
+	255, 255, 255, 255, 255, 255, 255, 255 }, {		\
+	{ 1, MODULATION_TURBO, 6000, 11, 140, 0 },	\
+	{ 1, MODULATION_TURBO, 9000, 15, 18, 0 },	\
+	{ 1, MODULATION_TURBO, 12000, 10, 152, 2 },	\
+	{ 1, MODULATION_TURBO, 18000, 14, 36, 2 },	\
+	{ 1, MODULATION_TURBO, 24000, 9, 176, 4 },	\
+	{ 1, MODULATION_TURBO, 36000, 13, 72, 4 },	\
+	{ 1, MODULATION_TURBO, 48000, 8, 96, 4 },	\
+	{ 1, MODULATION_TURBO, 54000, 12, 108, 4 } }	\
+}
+
+#define AR5K_RATES_XR { 12, {					\
+	255, 3, 1, 255, 255, 255, 2, 0, 10, 8, 6, 4,		\
+	11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255,	\
+	255, 255, 255, 255, 255, 255, 255, 255 }, {		\
+	{ 1, MODULATION_XR, 500, 7, 129, 0 },		\
+	{ 1, MODULATION_XR, 1000, 2, 139, 1 },		\
+	{ 1, MODULATION_XR, 2000, 6, 150, 2 },		\
+	{ 1, MODULATION_XR, 3000, 1, 150, 3 },		\
+	{ 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 4 },	\
+	{ 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 },	\
+	{ 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 6 },	\
+	{ 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 },	\
+	{ 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 8 },	\
+	{ 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 },	\
+	{ 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 },	\
+	{ 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } }	\
+}
+
+/*
+ * Crypto definitions
+ */
+
+#define AR5K_KEYCACHE_SIZE	8
+
+/***********************\
+ HW RELATED DEFINITIONS
+\***********************/
+
+/*
+ * Misc definitions
+ */
+#define	AR5K_RSSI_EP_MULTIPLIER	(1<<7)
+
+#define AR5K_ASSERT_ENTRY(_e, _s) do {		\
+	if (_e >= _s)				\
+		return (false);			\
+} while (0)
+
+
+enum ath5k_ant_setting {
+	AR5K_ANT_VARIABLE	= 0,	/* variable by programming */
+	AR5K_ANT_FIXED_A	= 1,	/* fixed to 11a frequencies */
+	AR5K_ANT_FIXED_B	= 2,	/* fixed to 11b frequencies */
+	AR5K_ANT_MAX		= 3,
+};
+
+/*
+ * Hardware interrupt abstraction
+ */
+
+/**
+ * enum ath5k_int - Hardware interrupt masks helpers
+ *
+ * @AR5K_INT_RX: mask to identify received frame interrupts, of type
+ * 	AR5K_ISR_RXOK or AR5K_ISR_RXERR
+ * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?)
+ * @AR5K_INT_RXNOFRM: No frame received (?)
+ * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The
+ * 	Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's
+ * 	LinkPtr is NULL. For more details, refer to:
+ * 	http://www.freepatentsonline.com/20030225739.html
+ * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors).
+ * 	Note that Rx overrun is not always fatal, on some chips we can continue
+ * 	operation without reseting the card, that's why int_fatal is not
+ * 	common for all chips.
+ * @AR5K_INT_TX: mask to identify received frame interrupts, of type
+ * 	AR5K_ISR_TXOK or AR5K_ISR_TXERR
+ * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?)
+ * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
+ * 	We currently do increments on interrupt by
+ * 	(AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
+ * @AR5K_INT_MIB: Indicates the Management Information Base counters should be
+ * 	checked. We should do this with ath5k_hw_update_mib_counters() but
+ * 	it seems we should also then do some noise immunity work.
+ * @AR5K_INT_RXPHY: RX PHY Error
+ * @AR5K_INT_RXKCM: ??
+ * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
+ * 	beacon that must be handled in software. The alternative is if you
+ * 	have VEOL support, in that case you let the hardware deal with things.
+ * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing
+ * 	beacons from the AP have associated with, we should probably try to
+ * 	reassociate. When in IBSS mode this might mean we have not received
+ * 	any beacons from any local stations. Note that every station in an
+ * 	IBSS schedules to send beacons at the Target Beacon Transmission Time
+ * 	(TBTT) with a random backoff.
+ * @AR5K_INT_BNR: Beacon Not Ready interrupt - ??
+ * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now
+ * 	until properly handled
+ * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA
+ * 	errors. These types of errors we can enable seem to be of type
+ * 	AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR.
+ * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER
+ * @AR5K_INT_NOCARD: signals the card has been removed
+ * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same
+ * 	bit value
+ *
+ * These are mapped to take advantage of some common bits
+ * between the MACs, to be able to set intr properties
+ * easier. Some of them are not used yet inside hw.c. Most map
+ * to the respective hw interrupt value as they are common amogst different
+ * MACs.
+ */
+enum ath5k_int {
+	AR5K_INT_RX	= 0x00000001, /* Not common */
+	AR5K_INT_RXDESC	= 0x00000002,
+	AR5K_INT_RXNOFRM = 0x00000008,
+	AR5K_INT_RXEOL	= 0x00000010,
+	AR5K_INT_RXORN	= 0x00000020,
+	AR5K_INT_TX	= 0x00000040, /* Not common */
+	AR5K_INT_TXDESC	= 0x00000080,
+	AR5K_INT_TXURN	= 0x00000800,
+	AR5K_INT_MIB	= 0x00001000,
+	AR5K_INT_RXPHY	= 0x00004000,
+	AR5K_INT_RXKCM	= 0x00008000,
+	AR5K_INT_SWBA	= 0x00010000,
+	AR5K_INT_BMISS	= 0x00040000,
+	AR5K_INT_BNR	= 0x00100000, /* Not common */
+	AR5K_INT_GPIO	= 0x01000000,
+	AR5K_INT_FATAL	= 0x40000000, /* Not common */
+	AR5K_INT_GLOBAL	= 0x80000000,
+
+	AR5K_INT_COMMON  = AR5K_INT_RXNOFRM
+			| AR5K_INT_RXDESC
+			| AR5K_INT_RXEOL
+			| AR5K_INT_RXORN
+			| AR5K_INT_TXURN
+			| AR5K_INT_TXDESC
+			| AR5K_INT_MIB
+			| AR5K_INT_RXPHY
+			| AR5K_INT_RXKCM
+			| AR5K_INT_SWBA
+			| AR5K_INT_BMISS
+			| AR5K_INT_GPIO,
+	AR5K_INT_NOCARD	= 0xffffffff
+};
+
+/*
+ * Power management
+ */
+enum ath5k_power_mode {
+	AR5K_PM_UNDEFINED = 0,
+	AR5K_PM_AUTO,
+	AR5K_PM_AWAKE,
+	AR5K_PM_FULL_SLEEP,
+	AR5K_PM_NETWORK_SLEEP,
+};
+
+/*
+ * These match net80211 definitions (not used in
+ * d80211).
+ */
+#define AR5K_LED_INIT	0 /*IEEE80211_S_INIT*/
+#define AR5K_LED_SCAN	1 /*IEEE80211_S_SCAN*/
+#define AR5K_LED_AUTH	2 /*IEEE80211_S_AUTH*/
+#define AR5K_LED_ASSOC	3 /*IEEE80211_S_ASSOC*/
+#define AR5K_LED_RUN	4 /*IEEE80211_S_RUN*/
+
+/* GPIO-controlled software LED */
+#define AR5K_SOFTLED_PIN	0
+#define AR5K_SOFTLED_ON		0
+#define AR5K_SOFTLED_OFF	1
+
+/*
+ * Chipset capabilities -see ath5k_hw_get_capability-
+ * get_capability function is not yet fully implemented
+ * in OpenHAL so most of these don't work yet...
+ */
+enum ath5k_capability_type {
+	AR5K_CAP_REG_DMN		= 0,	/* Used to get current reg. domain id */
+	AR5K_CAP_TKIP_MIC		= 2,	/* Can handle TKIP MIC in hardware */
+	AR5K_CAP_TKIP_SPLIT		= 3,	/* TKIP uses split keys */
+	AR5K_CAP_PHYCOUNTERS		= 4,	/* PHY error counters */
+	AR5K_CAP_DIVERSITY		= 5,	/* Supports fast diversity */
+	AR5K_CAP_NUM_TXQUEUES		= 6,	/* Used to get max number of hw txqueues */
+	AR5K_CAP_VEOL			= 7,	/* Supports virtual EOL */
+	AR5K_CAP_COMPRESSION		= 8,	/* Supports compression */
+	AR5K_CAP_BURST			= 9,	/* Supports packet bursting */
+	AR5K_CAP_FASTFRAME		= 10,	/* Supports fast frames */
+	AR5K_CAP_TXPOW			= 11,	/* Used to get global tx power limit */
+	AR5K_CAP_TPC			= 12,	/* Can do per-packet tx power control (needed for 802.11a) */
+	AR5K_CAP_BSSIDMASK		= 13,	/* Supports bssid mask */
+	AR5K_CAP_MCAST_KEYSRCH		= 14,	/* Supports multicast key search */
+	AR5K_CAP_TSF_ADJUST		= 15,	/* Supports beacon tsf adjust */
+	AR5K_CAP_XR			= 16,	/* Supports XR mode */
+	AR5K_CAP_WME_TKIPMIC 		= 17,	/* Supports TKIP MIC when using WMM */
+	AR5K_CAP_CHAN_HALFRATE 		= 18,	/* Supports half rate channels */
+	AR5K_CAP_CHAN_QUARTERRATE 	= 19,	/* Supports quarter rate channels */
+	AR5K_CAP_RFSILENT		= 20,	/* Supports RFsilent */
+};
+
+struct ath5k_capabilities {
+	/*
+	 * Supported PHY modes
+	 * (ie. CHANNEL_A, CHANNEL_B, ...)
+	 */
+	DECLARE_BITMAP(cap_mode, NUM_DRIVER_MODES);
+
+	/*
+	 * Frequency range (without regulation restrictions)
+	 */
+	struct {
+		u16	range_2ghz_min;
+		u16	range_2ghz_max;
+		u16	range_5ghz_min;
+		u16	range_5ghz_max;
+	} cap_range;
+
+	/*
+	 * Active regulation domain settings
+	 */
+	struct {
+		enum ath5k_regdom reg_current;
+		enum ath5k_regdom reg_hw;
+	} cap_regdomain;
+
+	/*
+	 * Values stored in the EEPROM (some of them...)
+	 */
+	struct ath5k_eeprom_info	cap_eeprom;
+
+	/*
+	 * Queue information
+	 */
+	struct {
+		u8	q_tx_num;
+	} cap_queues;
+};
+
+
+/***************************************\
+  HARDWARE ABSTRACTION LAYER STRUCTURE
+\***************************************/
+
+/*
+ * Misc defines
+ */
+
+#define AR5K_MAX_GPIO		10
+#define AR5K_MAX_RF_BANKS	8
+
+struct ath5k_hw {
+	u32			ah_magic;
+
+	struct ath5k_softc	*ah_sc;
+	void __iomem		*ah_iobase;
+
+	enum ath5k_int		ah_imr;
+
+	enum ieee80211_if_types	ah_op_mode;
+	enum ath5k_power_mode	ah_power_mode;
+	struct ieee80211_channel ah_current_channel;
+	bool			ah_turbo;
+	bool			ah_calibration;
+	bool			ah_running;
+	bool			ah_single_chip;
+	enum ath5k_rfgain	ah_rf_gain;
+
+	u32			ah_mac_srev;
+	u16			ah_mac_version;
+	u16			ah_mac_revision;
+	u16			ah_phy_revision;
+	u16			ah_radio_5ghz_revision;
+	u16			ah_radio_2ghz_revision;
+
+	enum ath5k_version	ah_version;
+	enum ath5k_radio	ah_radio;
+	u32			ah_phy;
+
+	bool			ah_5ghz;
+	bool			ah_2ghz;
+
+#define ah_regdomain		ah_capabilities.cap_regdomain.reg_current
+#define ah_regdomain_hw		ah_capabilities.cap_regdomain.reg_hw
+#define ah_modes		ah_capabilities.cap_mode
+#define ah_ee_version		ah_capabilities.cap_eeprom.ee_version
+
+	u32			ah_atim_window;
+	u32			ah_aifs;
+	u32			ah_cw_min;
+	u32			ah_cw_max;
+	bool			ah_software_retry;
+	u32			ah_limit_tx_retries;
+
+	u32			ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
+	bool			ah_ant_diversity;
+
+	u8			ah_sta_id[ETH_ALEN];
+
+	/* Current BSSID we are trying to assoc to / creating.
+	 * This is passed by mac80211 on config_interface() and cached here for
+	 * use in resets */
+	u8			ah_bssid[ETH_ALEN];
+
+	u32			ah_gpio[AR5K_MAX_GPIO];
+	int			ah_gpio_npins;
+
+	struct ath5k_capabilities ah_capabilities;
+
+	struct ath5k_txq_info	ah_txq[AR5K_NUM_TX_QUEUES];
+	u32			ah_txq_status;
+	u32			ah_txq_imr_txok;
+	u32			ah_txq_imr_txerr;
+	u32			ah_txq_imr_txurn;
+	u32			ah_txq_imr_txdesc;
+	u32			ah_txq_imr_txeol;
+	u32			*ah_rf_banks;
+	size_t			ah_rf_banks_size;
+	struct ath5k_gain	ah_gain;
+	u32			ah_offset[AR5K_MAX_RF_BANKS];
+
+	struct {
+		u16		txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE];
+		u16		txp_rates[AR5K_MAX_RATES];
+		s16		txp_min;
+		s16		txp_max;
+		bool		txp_tpc;
+		s16		txp_ofdm;
+	} ah_txpower;
+
+	struct {
+		bool		r_enabled;
+		int		r_last_alert;
+		struct ieee80211_channel r_last_channel;
+	} ah_radar;
+
+	/* noise floor from last periodic calibration */
+	s32			ah_noise_floor;
+
+	/*
+	 * Function pointers
+	 */
+	int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+		unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
+		unsigned int, unsigned int, unsigned int, unsigned int,
+		unsigned int, unsigned int, unsigned int);
+	bool (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *,
+		unsigned int, unsigned int, unsigned int, unsigned int,
+		unsigned int, unsigned int);
+	int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *);
+	int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *);
+};
+
+/*
+ * Prototypes
+ */
+
+/* General Functions */
+extern int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set);
+/* Attach/Detach Functions */
+extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version);
+extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, unsigned int mode);
+extern void ath5k_hw_detach(struct ath5k_hw *ah);
+/* Reset Functions */
+extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel);
+/* Power management functions */
+extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
+/* DMA Related Functions */
+extern void ath5k_hw_start_rx(struct ath5k_hw *ah);
+extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
+extern u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah);
+extern void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr);
+extern int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
+extern u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr);
+extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase);
+/* Interrupt handling */
+extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
+extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
+extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask);
+/* EEPROM access functions */
+extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain);
+/* Protocol Control Unit Functions */
+extern int ath5k_hw_set_opmode(struct ath5k_hw *ah);
+/* BSSID Functions */
+extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac);
+extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
+extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id);
+extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
+/* Receive start/stop functions */
+extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
+extern void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah);
+/* RX Filter functions */
+extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
+extern int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index);
+extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index);
+extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
+extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
+/* Beacon related functions */
+extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah);
+extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
+extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
+extern void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
+#if 0
+extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state);
+extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah);
+extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr);
+#endif
+extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ath5k_mib_stats *statistics);
+/* ACK bit rate */
+void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
+/* ACK/CTS Timeouts */
+extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout);
+extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah);
+extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout);
+extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah);
+/* Key table (WEP) functions */
+extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
+extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry);
+extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac);
+extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac);
+/* Queue Control Unit, DFS Control Unit Functions */
+extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info);
+extern int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *queue_info);
+extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info);
+extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue);
+extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
+extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
+extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah);
+/* Hardware Descriptor Functions */
+extern int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags);
+/* GPIO Functions */
+extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
+extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
+extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
+extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
+extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
+extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
+/* Regulatory Domain/Channels Setup */
+extern u16 ath5k_get_regdomain(struct ath5k_hw *ah);
+/* Misc functions */
+extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
+
+
+/* Initial register settings functions */
+extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
+/* Initialize RF */
+extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode);
+extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq);
+extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah);
+extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah);
+
+
+/* PHY/RF channel functions */
+extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
+extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
+/* PHY calibration */
+extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
+extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
+/* Misc PHY functions */
+extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
+extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant);
+extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
+extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
+/* TX power setup */
+extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int txpower);
+extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power);
+
+
+static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
+{
+	return ioread32(ah->ah_iobase + reg);
+}
+
+static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
+{
+	iowrite32(val, ah->ah_iobase + reg);
+}
+
+#endif
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
new file mode 100644
index 000000000000..72bcf321d1ce
--- /dev/null
+++ b/drivers/net/wireless/ath5k/base.c
@@ -0,0 +1,2974 @@
+/*-
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004-2005 Atheros Communications, Inc.
+ * Copyright (c) 2006 Devicescape Software, Inc.
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/cache.h>
+#include <linux/pci.h>
+#include <linux/ethtool.h>
+#include <linux/uaccess.h>
+
+#include <net/ieee80211_radiotap.h>
+
+#include <asm/unaligned.h>
+
+#include "base.h"
+#include "reg.h"
+#include "debug.h"
+
+/* unaligned little endian access */
+#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p))))
+#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p))))
+
+enum {
+	ATH_LED_TX,
+	ATH_LED_RX,
+};
+
+static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
+
+
+/******************\
+* Internal defines *
+\******************/
+
+/* Module info */
+MODULE_AUTHOR("Jiri Slaby");
+MODULE_AUTHOR("Nick Kossifidis");
+MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards.");
+MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION("0.1.1 (EXPERIMENTAL)");
+
+
+/* Known PCI ids */
+static struct pci_device_id ath5k_pci_id_table[] __devinitdata = {
+	{ PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */
+	{ PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */
+	{ PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/
+	{ PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */
+	{ PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */
+	{ PCI_VDEVICE(3COM_2,  0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */
+	{ PCI_VDEVICE(3COM,    0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */
+	{ PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */
+	{ PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+	{ PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+	{ PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+	{ PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+	{ PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+	{ PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
+	{ PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */
+	{ PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */
+	{ PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* 5424 Condor (PCI-E)*/
+	{ PCI_VDEVICE(ATHEROS, 0x0023), .driver_data = AR5K_AR5212 }, /* 5416 */
+	{ PCI_VDEVICE(ATHEROS, 0x0024), .driver_data = AR5K_AR5212 }, /* 5418 */
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
+
+/* Known SREVs */
+static struct ath5k_srev_name srev_names[] = {
+	{ "5210",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5210 },
+	{ "5311",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5311 },
+	{ "5311A",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5311A },
+	{ "5311B",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5311B },
+	{ "5211",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5211 },
+	{ "5212",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5212 },
+	{ "5213",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5213 },
+	{ "5213A",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5213A },
+	{ "2424",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR2424 },
+	{ "5424",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5424 },
+	{ "5413",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5413 },
+	{ "5414",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5414 },
+	{ "5416",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5416 },
+	{ "5418",	AR5K_VERSION_VER,	AR5K_SREV_VER_AR5418 },
+	{ "xxxxx",	AR5K_VERSION_VER,	AR5K_SREV_UNKNOWN },
+	{ "5110",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5110 },
+	{ "5111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5111 },
+	{ "2111",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2111 },
+	{ "5112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112 },
+	{ "5112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5112A },
+	{ "2112",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112 },
+	{ "2112A",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2112A },
+	{ "SChip",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_SC1 },
+	{ "SChip",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_SC2 },
+	{ "5133",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5133 },
+	{ "xxxxx",	AR5K_VERSION_RAD,	AR5K_SREV_UNKNOWN },
+};
+
+/*
+ * Prototypes - PCI stack related functions
+ */
+static int __devinit	ath5k_pci_probe(struct pci_dev *pdev,
+				const struct pci_device_id *id);
+static void __devexit	ath5k_pci_remove(struct pci_dev *pdev);
+#ifdef CONFIG_PM
+static int		ath5k_pci_suspend(struct pci_dev *pdev,
+					pm_message_t state);
+static int		ath5k_pci_resume(struct pci_dev *pdev);
+#else
+#define ath5k_pci_suspend NULL
+#define ath5k_pci_resume NULL
+#endif /* CONFIG_PM */
+
+static struct pci_driver ath5k_pci_drv_id = {
+	.name		= "ath5k_pci",
+	.id_table	= ath5k_pci_id_table,
+	.probe		= ath5k_pci_probe,
+	.remove		= __devexit_p(ath5k_pci_remove),
+	.suspend	= ath5k_pci_suspend,
+	.resume		= ath5k_pci_resume,
+};
+
+
+
+/*
+ * Prototypes - MAC 802.11 stack related functions
+ */
+static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		struct ieee80211_tx_control *ctl);
+static int ath5k_reset(struct ieee80211_hw *hw);
+static int ath5k_start(struct ieee80211_hw *hw);
+static void ath5k_stop(struct ieee80211_hw *hw);
+static int ath5k_add_interface(struct ieee80211_hw *hw,
+		struct ieee80211_if_init_conf *conf);
+static void ath5k_remove_interface(struct ieee80211_hw *hw,
+		struct ieee80211_if_init_conf *conf);
+static int ath5k_config(struct ieee80211_hw *hw,
+		struct ieee80211_conf *conf);
+static int ath5k_config_interface(struct ieee80211_hw *hw,
+		struct ieee80211_vif *vif,
+		struct ieee80211_if_conf *conf);
+static void ath5k_configure_filter(struct ieee80211_hw *hw,
+		unsigned int changed_flags,
+		unsigned int *new_flags,
+		int mc_count, struct dev_mc_list *mclist);
+static int ath5k_set_key(struct ieee80211_hw *hw,
+		enum set_key_cmd cmd,
+		const u8 *local_addr, const u8 *addr,
+		struct ieee80211_key_conf *key);
+static int ath5k_get_stats(struct ieee80211_hw *hw,
+		struct ieee80211_low_level_stats *stats);
+static int ath5k_get_tx_stats(struct ieee80211_hw *hw,
+		struct ieee80211_tx_queue_stats *stats);
+static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
+static void ath5k_reset_tsf(struct ieee80211_hw *hw);
+static int ath5k_beacon_update(struct ieee80211_hw *hw,
+		struct sk_buff *skb,
+		struct ieee80211_tx_control *ctl);
+
+static struct ieee80211_ops ath5k_hw_ops = {
+	.tx 		= ath5k_tx,
+	.start 		= ath5k_start,
+	.stop 		= ath5k_stop,
+	.add_interface 	= ath5k_add_interface,
+	.remove_interface = ath5k_remove_interface,
+	.config 	= ath5k_config,
+	.config_interface = ath5k_config_interface,
+	.configure_filter = ath5k_configure_filter,
+	.set_key 	= ath5k_set_key,
+	.get_stats 	= ath5k_get_stats,
+	.conf_tx 	= NULL,
+	.get_tx_stats 	= ath5k_get_tx_stats,
+	.get_tsf 	= ath5k_get_tsf,
+	.reset_tsf 	= ath5k_reset_tsf,
+	.beacon_update 	= ath5k_beacon_update,
+};
+
+/*
+ * Prototypes - Internal functions
+ */
+/* Attach detach */
+static int 	ath5k_attach(struct pci_dev *pdev,
+			struct ieee80211_hw *hw);
+static void 	ath5k_detach(struct pci_dev *pdev,
+			struct ieee80211_hw *hw);
+/* Channel/mode setup */
+static inline short ath5k_ieee2mhz(short chan);
+static unsigned int ath5k_copy_rates(struct ieee80211_rate *rates,
+				const struct ath5k_rate_table *rt,
+				unsigned int max);
+static unsigned int ath5k_copy_channels(struct ath5k_hw *ah,
+				struct ieee80211_channel *channels,
+				unsigned int mode,
+				unsigned int max);
+static int 	ath5k_getchannels(struct ieee80211_hw *hw);
+static int 	ath5k_chan_set(struct ath5k_softc *sc,
+				struct ieee80211_channel *chan);
+static void	ath5k_setcurmode(struct ath5k_softc *sc,
+				unsigned int mode);
+static void	ath5k_mode_setup(struct ath5k_softc *sc);
+/* Descriptor setup */
+static int	ath5k_desc_alloc(struct ath5k_softc *sc,
+				struct pci_dev *pdev);
+static void	ath5k_desc_free(struct ath5k_softc *sc,
+				struct pci_dev *pdev);
+/* Buffers setup */
+static int 	ath5k_rxbuf_setup(struct ath5k_softc *sc,
+				struct ath5k_buf *bf);
+static int 	ath5k_txbuf_setup(struct ath5k_softc *sc,
+				struct ath5k_buf *bf,
+				struct ieee80211_tx_control *ctl);
+
+static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
+				struct ath5k_buf *bf)
+{
+	BUG_ON(!bf);
+	if (!bf->skb)
+		return;
+	pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len,
+			PCI_DMA_TODEVICE);
+	dev_kfree_skb(bf->skb);
+	bf->skb = NULL;
+}
+
+/* Queues setup */
+static struct 	ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc,
+				int qtype, int subtype);
+static int 	ath5k_beaconq_setup(struct ath5k_hw *ah);
+static int 	ath5k_beaconq_config(struct ath5k_softc *sc);
+static void 	ath5k_txq_drainq(struct ath5k_softc *sc,
+				struct ath5k_txq *txq);
+static void 	ath5k_txq_cleanup(struct ath5k_softc *sc);
+static void 	ath5k_txq_release(struct ath5k_softc *sc);
+/* Rx handling */
+static int 	ath5k_rx_start(struct ath5k_softc *sc);
+static void 	ath5k_rx_stop(struct ath5k_softc *sc);
+static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc,
+					struct ath5k_desc *ds,
+					struct sk_buff *skb);
+static void 	ath5k_tasklet_rx(unsigned long data);
+/* Tx handling */
+static void 	ath5k_tx_processq(struct ath5k_softc *sc,
+				struct ath5k_txq *txq);
+static void 	ath5k_tasklet_tx(unsigned long data);
+/* Beacon handling */
+static int 	ath5k_beacon_setup(struct ath5k_softc *sc,
+				struct ath5k_buf *bf,
+				struct ieee80211_tx_control *ctl);
+static void 	ath5k_beacon_send(struct ath5k_softc *sc);
+static void 	ath5k_beacon_config(struct ath5k_softc *sc);
+static void	ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
+
+static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
+{
+	u64 tsf = ath5k_hw_get_tsf64(ah);
+
+	if ((tsf & 0x7fff) < rstamp)
+		tsf -= 0x8000;
+
+	return (tsf & ~0x7fff) | rstamp;
+}
+
+/* Interrupt handling */
+static int 	ath5k_init(struct ath5k_softc *sc);
+static int 	ath5k_stop_locked(struct ath5k_softc *sc);
+static int 	ath5k_stop_hw(struct ath5k_softc *sc);
+static irqreturn_t ath5k_intr(int irq, void *dev_id);
+static void 	ath5k_tasklet_reset(unsigned long data);
+
+static void 	ath5k_calibrate(unsigned long data);
+/* LED functions */
+static void 	ath5k_led_off(unsigned long data);
+static void 	ath5k_led_blink(struct ath5k_softc *sc,
+				unsigned int on,
+				unsigned int off);
+static void 	ath5k_led_event(struct ath5k_softc *sc,
+				int event);
+
+
+/*
+ * Module init/exit functions
+ */
+static int __init
+init_ath5k_pci(void)
+{
+	int ret;
+
+	ath5k_debug_init();
+
+	ret = pci_register_driver(&ath5k_pci_drv_id);
+	if (ret) {
+		printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit
+exit_ath5k_pci(void)
+{
+	pci_unregister_driver(&ath5k_pci_drv_id);
+
+	ath5k_debug_finish();
+}
+
+module_init(init_ath5k_pci);
+module_exit(exit_ath5k_pci);
+
+
+/********************\
+* PCI Initialization *
+\********************/
+
+static const char *
+ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val)
+{
+	const char *name = "xxxxx";
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(srev_names); i++) {
+		if (srev_names[i].sr_type != type)
+			continue;
+		if ((val & 0xff) < srev_names[i + 1].sr_val) {
+			name = srev_names[i].sr_name;
+			break;
+		}
+	}
+
+	return name;
+}
+
+static int __devinit
+ath5k_pci_probe(struct pci_dev *pdev,
+		const struct pci_device_id *id)
+{
+	void __iomem *mem;
+	struct ath5k_softc *sc;
+	struct ieee80211_hw *hw;
+	int ret;
+	u8 csz;
+
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "can't enable device\n");
+		goto err;
+	}
+
+	/* XXX 32-bit addressing only */
+	ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (ret) {
+		dev_err(&pdev->dev, "32-bit DMA not available\n");
+		goto err_dis;
+	}
+
+	/*
+	 * Cache line size is used to size and align various
+	 * structures used to communicate with the hardware.
+	 */
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+	if (csz == 0) {
+		/*
+		 * Linux 2.4.18 (at least) writes the cache line size
+		 * register as a 16-bit wide register which is wrong.
+		 * We must have this setup properly for rx buffer
+		 * DMA to work so force a reasonable value here if it
+		 * comes up zero.
+		 */
+		csz = L1_CACHE_BYTES / sizeof(u32);
+		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+	}
+	/*
+	 * The default setting of latency timer yields poor results,
+	 * set it to the value used by other systems.  It may be worth
+	 * tweaking this setting more.
+	 */
+	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+
+	/* Enable bus mastering */
+	pci_set_master(pdev);
+
+	/*
+	 * Disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state.
+	 */
+	pci_write_config_byte(pdev, 0x41, 0);
+
+	ret = pci_request_region(pdev, 0, "ath5k");
+	if (ret) {
+		dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
+		goto err_dis;
+	}
+
+	mem = pci_iomap(pdev, 0, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
+		ret = -EIO;
+		goto err_reg;
+	}
+
+	/*
+	 * Allocate hw (mac80211 main struct)
+	 * and hw->priv (driver private data)
+	 */
+	hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops);
+	if (hw == NULL) {
+		dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n");
+		ret = -ENOMEM;
+		goto err_map;
+	}
+
+	dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy));
+
+	/* Initialize driver private data */
+	SET_IEEE80211_DEV(hw, &pdev->dev);
+	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS;
+	hw->extra_tx_headroom = 2;
+	hw->channel_change_time = 5000;
+	/* these names are misleading */
+	hw->max_rssi = -110; /* signal in dBm */
+	hw->max_noise = -110; /* noise in dBm */
+	hw->max_signal = 100; /* we will provide a percentage based on rssi */
+	sc = hw->priv;
+	sc->hw = hw;
+	sc->pdev = pdev;
+
+	ath5k_debug_init_device(sc);
+
+	/*
+	 * Mark the device as detached to avoid processing
+	 * interrupts until setup is complete.
+	 */
+	__set_bit(ATH_STAT_INVALID, sc->status);
+
+	sc->iobase = mem; /* So we can unmap it on detach */
+	sc->cachelsz = csz * sizeof(u32); /* convert to bytes */
+	sc->opmode = IEEE80211_IF_TYPE_STA;
+	mutex_init(&sc->lock);
+	spin_lock_init(&sc->rxbuflock);
+	spin_lock_init(&sc->txbuflock);
+
+	/* Set private data */
+	pci_set_drvdata(pdev, hw);
+
+	/* Enable msi for devices that support it */
+	pci_enable_msi(pdev);
+
+	/* Setup interrupt handler */
+	ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
+	if (ret) {
+		ATH5K_ERR(sc, "request_irq failed\n");
+		goto err_free;
+	}
+
+	/* Initialize device */
+	sc->ah = ath5k_hw_attach(sc, id->driver_data);
+	if (IS_ERR(sc->ah)) {
+		ret = PTR_ERR(sc->ah);
+		goto err_irq;
+	}
+
+	/* Finish private driver data initialization */
+	ret = ath5k_attach(pdev, hw);
+	if (ret)
+		goto err_ah;
+
+	ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
+			ath5k_chip_name(AR5K_VERSION_VER,sc->ah->ah_mac_srev),
+					sc->ah->ah_mac_srev,
+					sc->ah->ah_phy_revision);
+
+	if(!sc->ah->ah_single_chip){
+		/* Single chip radio (!RF5111) */
+		if(sc->ah->ah_radio_5ghz_revision && !sc->ah->ah_radio_2ghz_revision) {
+			/* No 5GHz support -> report 2GHz radio */
+			if(!test_bit(MODE_IEEE80211A, sc->ah->ah_capabilities.cap_mode)){
+				ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
+					ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
+							sc->ah->ah_radio_5ghz_revision);
+			/* No 2GHz support (5110 and some 5Ghz only cards) -> report 5Ghz radio */
+			} else if(!test_bit(MODE_IEEE80211B, sc->ah->ah_capabilities.cap_mode)){
+				ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
+					ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
+							sc->ah->ah_radio_5ghz_revision);
+			/* Multiband radio */
+			} else {
+				ATH5K_INFO(sc, "RF%s multiband radio found"
+					" (0x%x)\n",
+					ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
+							sc->ah->ah_radio_5ghz_revision);
+			}
+		}
+		/* Multi chip radio (RF5111 - RF2111) -> report both 2GHz/5GHz radios */
+		else if(sc->ah->ah_radio_5ghz_revision && sc->ah->ah_radio_2ghz_revision){
+			ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
+				ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision),
+						sc->ah->ah_radio_5ghz_revision);
+			ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
+				ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_2ghz_revision),
+						sc->ah->ah_radio_2ghz_revision);
+		}
+	}
+
+
+	/* ready to process interrupts */
+	__clear_bit(ATH_STAT_INVALID, sc->status);
+
+	return 0;
+err_ah:
+	ath5k_hw_detach(sc->ah);
+err_irq:
+	free_irq(pdev->irq, sc);
+err_free:
+	pci_disable_msi(pdev);
+	ieee80211_free_hw(hw);
+err_map:
+	pci_iounmap(pdev, mem);
+err_reg:
+	pci_release_region(pdev, 0);
+err_dis:
+	pci_disable_device(pdev);
+err:
+	return ret;
+}
+
+static void __devexit
+ath5k_pci_remove(struct pci_dev *pdev)
+{
+	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+	struct ath5k_softc *sc = hw->priv;
+
+	ath5k_debug_finish_device(sc);
+	ath5k_detach(pdev, hw);
+	ath5k_hw_detach(sc->ah);
+	free_irq(pdev->irq, sc);
+	pci_disable_msi(pdev);
+	pci_iounmap(pdev, sc->iobase);
+	pci_release_region(pdev, 0);
+	pci_disable_device(pdev);
+	ieee80211_free_hw(hw);
+}
+
+#ifdef CONFIG_PM
+static int
+ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+	struct ath5k_softc *sc = hw->priv;
+
+	if (test_bit(ATH_STAT_LEDSOFT, sc->status))
+		ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1);
+
+	ath5k_stop_hw(sc);
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	return 0;
+}
+
+static int
+ath5k_pci_resume(struct pci_dev *pdev)
+{
+	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+	struct ath5k_softc *sc = hw->priv;
+	struct ath5k_hw *ah = sc->ah;
+	int i, err;
+
+	err = pci_set_power_state(pdev, PCI_D0);
+	if (err)
+		return err;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	pci_restore_state(pdev);
+	/*
+	 * Suspend/Resume resets the PCI configuration space, so we have to
+	 * re-disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state
+	 */
+	pci_write_config_byte(pdev, 0x41, 0);
+
+	ath5k_init(sc);
+	if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
+		ath5k_hw_set_gpio_output(ah, sc->led_pin);
+		ath5k_hw_set_gpio(ah, sc->led_pin, 0);
+	}
+
+	/*
+	 * Reset the key cache since some parts do not
+	 * reset the contents on initial power up or resume.
+	 *
+	 * FIXME: This may need to be revisited when mac80211 becomes
+	 *        aware of suspend/resume.
+	 */
+	for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
+		ath5k_hw_reset_key(ah, i);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+
+
+/***********************\
+* Driver Initialization *
+\***********************/
+
+static int
+ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
+{
+	struct ath5k_softc *sc = hw->priv;
+	struct ath5k_hw *ah = sc->ah;
+	u8 mac[ETH_ALEN];
+	unsigned int i;
+	int ret;
+
+	ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
+
+	/*
+	 * Check if the MAC has multi-rate retry support.
+	 * We do this by trying to setup a fake extended
+	 * descriptor.  MAC's that don't have support will
+	 * return false w/o doing anything.  MAC's that do
+	 * support it will return true w/o doing anything.
+	 */
+	if (ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0))
+		__set_bit(ATH_STAT_MRRETRY, sc->status);
+
+	/*
+	 * Reset the key cache since some parts do not
+	 * reset the contents on initial power up.
+	 */
+	for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
+		ath5k_hw_reset_key(ah, i);
+
+	/*
+	 * Collect the channel list.  The 802.11 layer
+	 * is resposible for filtering this list based
+	 * on settings like the phy mode and regulatory
+	 * domain restrictions.
+	 */
+	ret = ath5k_getchannels(hw);
+	if (ret) {
+		ATH5K_ERR(sc, "can't get channels\n");
+		goto err;
+	}
+
+	/* NB: setup here so ath5k_rate_update is happy */
+	if (test_bit(MODE_IEEE80211A, ah->ah_modes))
+		ath5k_setcurmode(sc, MODE_IEEE80211A);
+	else
+		ath5k_setcurmode(sc, MODE_IEEE80211B);
+
+	/*
+	 * Allocate tx+rx descriptors and populate the lists.
+	 */
+	ret = ath5k_desc_alloc(sc, pdev);
+	if (ret) {
+		ATH5K_ERR(sc, "can't allocate descriptors\n");
+		goto err;
+	}
+
+	/*
+	 * Allocate hardware transmit queues: one queue for
+	 * beacon frames and one data queue for each QoS
+	 * priority.  Note that hw functions handle reseting
+	 * these queues at the needed time.
+	 */
+	ret = ath5k_beaconq_setup(ah);
+	if (ret < 0) {
+		ATH5K_ERR(sc, "can't setup a beacon xmit queue\n");
+		goto err_desc;
+	}
+	sc->bhalq = ret;
+
+	sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
+	if (IS_ERR(sc->txq)) {
+		ATH5K_ERR(sc, "can't setup xmit queue\n");
+		ret = PTR_ERR(sc->txq);
+		goto err_bhal;
+	}
+
+	tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
+	tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
+	tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
+	setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
+	setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc);
+
+	sc->led_on = 0; /* low true */
+	/*
+	 * Auto-enable soft led processing for IBM cards and for
+	 * 5211 minipci cards.
+	 */
+	if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM ||
+			pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
+		__set_bit(ATH_STAT_LEDSOFT, sc->status);
+		sc->led_pin = 0;
+	}
+	/* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
+	if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
+		__set_bit(ATH_STAT_LEDSOFT, sc->status);
+		sc->led_pin = 0;
+	}
+	if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
+		ath5k_hw_set_gpio_output(ah, sc->led_pin);
+		ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
+	}
+
+	ath5k_hw_get_lladdr(ah, mac);
+	SET_IEEE80211_PERM_ADDR(hw, mac);
+	/* All MAC address bits matter for ACKs */
+	memset(sc->bssidmask, 0xff, ETH_ALEN);
+	ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask);
+
+	ret = ieee80211_register_hw(hw);
+	if (ret) {
+		ATH5K_ERR(sc, "can't register ieee80211 hw\n");
+		goto err_queues;
+	}
+
+	return 0;
+err_queues:
+	ath5k_txq_release(sc);
+err_bhal:
+	ath5k_hw_release_tx_queue(ah, sc->bhalq);
+err_desc:
+	ath5k_desc_free(sc, pdev);
+err:
+	return ret;
+}
+
+static void
+ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
+{
+	struct ath5k_softc *sc = hw->priv;
+
+	/*
+	 * NB: the order of these is important:
+	 * o call the 802.11 layer before detaching ath5k_hw to
+	 *   insure callbacks into the driver to delete global
+	 *   key cache entries can be handled
+	 * o reclaim the tx queue data structures after calling
+	 *   the 802.11 layer as we'll get called back to reclaim
+	 *   node state and potentially want to use them
+	 * o to cleanup the tx queues the hal is called, so detach
+	 *   it last
+	 * XXX: ??? detach ath5k_hw ???
+	 * Other than that, it's straightforward...
+	 */
+	ieee80211_unregister_hw(hw);
+	ath5k_desc_free(sc, pdev);
+	ath5k_txq_release(sc);
+	ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
+
+	/*
+	 * NB: can't reclaim these until after ieee80211_ifdetach
+	 * returns because we'll get called back to reclaim node
+	 * state and potentially want to use them.
+	 */
+}
+
+
+
+
+/********************\
+* Channel/mode setup *
+\********************/
+
+/*
+ * Convert IEEE channel number to MHz frequency.
+ */
+static inline short
+ath5k_ieee2mhz(short chan)
+{
+	if (chan <= 14 || chan >= 27)
+		return ieee80211chan2mhz(chan);
+	else
+		return 2212 + chan * 20;
+}
+
+static unsigned int
+ath5k_copy_rates(struct ieee80211_rate *rates,
+		const struct ath5k_rate_table *rt,
+		unsigned int max)
+{
+	unsigned int i, count;
+
+	if (rt == NULL)
+		return 0;
+
+	for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) {
+		if (!rt->rates[i].valid)
+			continue;
+		rates->rate = rt->rates[i].rate_kbps / 100;
+		rates->val = rt->rates[i].rate_code;
+		rates->flags = rt->rates[i].modulation;
+		rates++;
+		count++;
+		max--;
+	}
+
+	return count;
+}
+
+static unsigned int
+ath5k_copy_channels(struct ath5k_hw *ah,
+		struct ieee80211_channel *channels,
+		unsigned int mode,
+		unsigned int max)
+{
+	static const struct { unsigned int mode, mask, chan; } map[] = {
+		[MODE_IEEE80211A] = { CHANNEL_OFDM, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_A },
+		[MODE_ATHEROS_TURBO] = { CHANNEL_OFDM|CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_T },
+		[MODE_IEEE80211B] = { CHANNEL_CCK, CHANNEL_CCK, CHANNEL_B },
+		[MODE_IEEE80211G] = { CHANNEL_OFDM, CHANNEL_OFDM, CHANNEL_G },
+		[MODE_ATHEROS_TURBOG] = { CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_TG },
+	};
+	static const struct ath5k_regchannel chans_2ghz[] =
+		IEEE80211_CHANNELS_2GHZ;
+	static const struct ath5k_regchannel chans_5ghz[] =
+		IEEE80211_CHANNELS_5GHZ;
+	const struct ath5k_regchannel *chans;
+	enum ath5k_regdom dmn;
+	unsigned int i, count, size, chfreq, all, f, ch;
+
+	if (!test_bit(mode, ah->ah_modes))
+		return 0;
+
+	all = ah->ah_regdomain == DMN_DEFAULT || CHAN_DEBUG == 1;
+
+	switch (mode) {
+	case MODE_IEEE80211A:
+	case MODE_ATHEROS_TURBO:
+		/* 1..220, but 2GHz frequencies are filtered by check_channel */
+		size = all ? 220 : ARRAY_SIZE(chans_5ghz);
+		chans = chans_5ghz;
+		dmn = ath5k_regdom2flag(ah->ah_regdomain,
+				IEEE80211_CHANNELS_5GHZ_MIN);
+		chfreq = CHANNEL_5GHZ;
+		break;
+	case MODE_IEEE80211B:
+	case MODE_IEEE80211G:
+	case MODE_ATHEROS_TURBOG:
+		size = all ? 26 : ARRAY_SIZE(chans_2ghz);
+		chans = chans_2ghz;
+		dmn = ath5k_regdom2flag(ah->ah_regdomain,
+				IEEE80211_CHANNELS_2GHZ_MIN);
+		chfreq = CHANNEL_2GHZ;
+		break;
+	default:
+		ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n");
+		return 0;
+	}
+
+	for (i = 0, count = 0; i < size && max > 0; i++) {
+		ch = all ? i + 1 : chans[i].chan;
+		f = ath5k_ieee2mhz(ch);
+		/* Check if channel is supported by the chipset */
+		if (!ath5k_channel_ok(ah, f, chfreq))
+			continue;
+
+		/* Match regulation domain */
+		if (!all && !(IEEE80211_DMN(chans[i].domain) &
+							IEEE80211_DMN(dmn)))
+			continue;
+
+		if (!all && (chans[i].mode & map[mode].mask) != map[mode].mode)
+			continue;
+
+		/* Write channel and increment counter */
+		channels->chan = ch;
+		channels->freq = f;
+		channels->val = map[mode].chan;
+		channels++;
+		count++;
+		max--;
+	}
+
+	return count;
+}
+
+/* Only tries to register modes our EEPROM says it can support */
+#define REGISTER_MODE(m) do { \
+	ret = ath5k_register_mode(hw, m); \
+	if (ret) \
+		return ret; \
+} while (0) \
+
+static inline int
+ath5k_register_mode(struct ieee80211_hw *hw, u8 m)
+{
+	struct ath5k_softc *sc = hw->priv;
+	struct ieee80211_hw_mode *modes = sc->modes;
+	unsigned int i;
+	int ret;
+
+	if (!test_bit(m, sc->ah->ah_capabilities.cap_mode))
+		return 0;
+
+	for (i = 0; i < NUM_DRIVER_MODES; i++) {
+		if (modes[i].mode != m || !modes[i].num_channels)
+			continue;
+		ret = ieee80211_register_hwmode(hw, &modes[i]);
+		if (ret) {
+			ATH5K_ERR(sc, "can't register hwmode %u\n", m);
+			return ret;
+		}
+		return 0;
+	}
+	BUG();
+}
+
+static int
+ath5k_getchannels(struct ieee80211_hw *hw)
+{
+	struct ath5k_softc *sc = hw->priv;
+	struct ath5k_hw *ah = sc->ah;
+	struct ieee80211_hw_mode *modes = sc->modes;
+	unsigned int i, max_r, max_c;
+	int ret;
+
+	BUILD_BUG_ON(ARRAY_SIZE(sc->modes) < 3);
+
+	/* The order here does not matter */
+	modes[0].mode = MODE_IEEE80211G;
+	modes[1].mode = MODE_IEEE80211B;
+	modes[2].mode = MODE_IEEE80211A;
+
+	max_r = ARRAY_SIZE(sc->rates);
+	max_c = ARRAY_SIZE(sc->channels);
+
+	for (i = 0; i < NUM_DRIVER_MODES; i++) {
+		struct ieee80211_hw_mode *mode = &modes[i];
+		const struct ath5k_rate_table *hw_rates;
+
+		if (i == 0) {
+			modes[0].rates	= sc->rates;
+			modes->channels	= sc->channels;
+		} else {
+			struct ieee80211_hw_mode *prev_mode = &modes[i-1];
+			int prev_num_r	= prev_mode->num_rates;
+			int prev_num_c	= prev_mode->num_channels;
+			mode->rates	= &prev_mode->rates[prev_num_r];
+			mode->channels	= &prev_mode->channels[prev_num_c];
+		}
+
+		hw_rates = ath5k_hw_get_rate_table(ah, mode->mode);
+		mode->num_rates    = ath5k_copy_rates(mode->rates, hw_rates,
+			max_r);
+		mode->num_channels = ath5k_copy_channels(ah, mode->channels,
+			mode->mode, max_c);
+		max_r -= mode->num_rates;
+		max_c -= mode->num_channels;
+	}
+
+	/* We try to register all modes this driver supports. We don't bother
+	 * with MODE_IEEE80211B for AR5212 as MODE_IEEE80211G already accounts
+	 * for that as per mac80211. Then, REGISTER_MODE() will will actually
+	 * check the eeprom reading for more reliable capability information.
+	 * Order matters here as per mac80211's latest preference. This will
+	 * all hopefullly soon go away. */
+
+	REGISTER_MODE(MODE_IEEE80211G);
+	if (ah->ah_version != AR5K_AR5212)
+		REGISTER_MODE(MODE_IEEE80211B);
+	REGISTER_MODE(MODE_IEEE80211A);
+
+	ath5k_debug_dump_modes(sc, modes);
+
+	return ret;
+}
+
+/*
+ * Set/change channels.  If the channel is really being changed,
+ * it's done by reseting the chip.  To accomplish this we must
+ * first cleanup any pending DMA, then restart stuff after a la
+ * ath5k_init.
+ */
+static int
+ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
+{
+	struct ath5k_hw *ah = sc->ah;
+	int ret;
+
+	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "%u (%u MHz) -> %u (%u MHz)\n",
+		sc->curchan->chan, sc->curchan->freq,
+		chan->chan, chan->freq);
+
+	if (chan->freq != sc->curchan->freq || chan->val != sc->curchan->val) {
+		/*
+		 * To switch channels clear any pending DMA operations;
+		 * wait long enough for the RX fifo to drain, reset the
+		 * hardware at the new frequency, and then re-enable
+		 * the relevant bits of the h/w.
+		 */
+		ath5k_hw_set_intr(ah, 0);	/* disable interrupts */
+		ath5k_txq_cleanup(sc);		/* clear pending tx frames */
+		ath5k_rx_stop(sc);		/* turn off frame recv */
+		ret = ath5k_hw_reset(ah, sc->opmode, chan, true);
+		if (ret) {
+			ATH5K_ERR(sc, "%s: unable to reset channel %u "
+				"(%u Mhz)\n", __func__, chan->chan, chan->freq);
+			return ret;
+		}
+		sc->curchan = chan;
+		ath5k_hw_set_txpower_limit(sc->ah, 0);
+
+		/*
+		 * Re-enable rx framework.
+		 */
+		ret = ath5k_rx_start(sc);
+		if (ret) {
+			ATH5K_ERR(sc, "%s: unable to restart recv logic\n",
+					__func__);
+			return ret;
+		}
+
+		/*
+		 * Change channels and update the h/w rate map
+		 * if we're switching; e.g. 11a to 11b/g.
+		 *
+		 * XXX needed?
+		 */
+/*		ath5k_chan_change(sc, chan); */
+
+		ath5k_beacon_config(sc);
+		/*
+		 * Re-enable interrupts.
+		 */
+		ath5k_hw_set_intr(ah, sc->imask);
+	}
+
+	return 0;
+}
+
+static void
+ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode)
+{
+	if (unlikely(test_bit(ATH_STAT_LEDSOFT, sc->status))) {
+		/* from Atheros NDIS driver, w/ permission */
+		static const struct {
+			u16 rate;	/* tx/rx 802.11 rate */
+			u16 timeOn;	/* LED on time (ms) */
+			u16 timeOff;	/* LED off time (ms) */
+		} blinkrates[] = {
+			{ 108,  40,  10 },
+			{  96,  44,  11 },
+			{  72,  50,  13 },
+			{  48,  57,  14 },
+			{  36,  67,  16 },
+			{  24,  80,  20 },
+			{  22, 100,  25 },
+			{  18, 133,  34 },
+			{  12, 160,  40 },
+			{  10, 200,  50 },
+			{   6, 240,  58 },
+			{   4, 267,  66 },
+			{   2, 400, 100 },
+			{   0, 500, 130 }
+		};
+		const struct ath5k_rate_table *rt =
+				ath5k_hw_get_rate_table(sc->ah, mode);
+		unsigned int i, j;
+
+		BUG_ON(rt == NULL);
+
+		memset(sc->hwmap, 0, sizeof(sc->hwmap));
+		for (i = 0; i < 32; i++) {
+			u8 ix = rt->rate_code_to_index[i];
+			if (ix == 0xff) {
+				sc->hwmap[i].ledon = msecs_to_jiffies(500);
+				sc->hwmap[i].ledoff = msecs_to_jiffies(130);
+				continue;
+			}
+			sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD;
+			if (SHPREAMBLE_FLAG(ix) || rt->rates[ix].modulation ==
+					IEEE80211_RATE_OFDM)
+				sc->hwmap[i].txflags |=
+						IEEE80211_RADIOTAP_F_SHORTPRE;
+			/* receive frames include FCS */
+			sc->hwmap[i].rxflags = sc->hwmap[i].txflags |
+					IEEE80211_RADIOTAP_F_FCS;
+			/* setup blink rate table to avoid per-packet lookup */
+			for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++)
+				if (blinkrates[j].rate == /* XXX why 7f? */
+						(rt->rates[ix].dot11_rate&0x7f))
+					break;
+
+			sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j].
+					timeOn);
+			sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j].
+					timeOff);
+		}
+	}
+
+	sc->curmode = mode;
+}
+
+static void
+ath5k_mode_setup(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	u32 rfilt;
+
+	/* configure rx filter */
+	rfilt = sc->filter_flags;
+	ath5k_hw_set_rx_filter(ah, rfilt);
+
+	if (ath5k_hw_hasbssidmask(ah))
+		ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
+
+	/* configure operational mode */
+	ath5k_hw_set_opmode(ah);
+
+	ath5k_hw_set_mcast_filter(ah, 0, 0);
+	ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);
+}
+
+
+
+
+/***************\
+* Buffers setup *
+\***************/
+
+static int
+ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct sk_buff *skb = bf->skb;
+	struct ath5k_desc *ds;
+
+	if (likely(skb == NULL)) {
+		unsigned int off;
+
+		/*
+		 * Allocate buffer with headroom_needed space for the
+		 * fake physical layer header at the start.
+		 */
+		skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1);
+		if (unlikely(skb == NULL)) {
+			ATH5K_ERR(sc, "can't alloc skbuff of size %u\n",
+					sc->rxbufsize + sc->cachelsz - 1);
+			return -ENOMEM;
+		}
+		/*
+		 * Cache-line-align.  This is important (for the
+		 * 5210 at least) as not doing so causes bogus data
+		 * in rx'd frames.
+		 */
+		off = ((unsigned long)skb->data) % sc->cachelsz;
+		if (off != 0)
+			skb_reserve(skb, sc->cachelsz - off);
+
+		bf->skb = skb;
+		bf->skbaddr = pci_map_single(sc->pdev,
+			skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE);
+		if (unlikely(pci_dma_mapping_error(bf->skbaddr))) {
+			ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
+			dev_kfree_skb(skb);
+			bf->skb = NULL;
+			return -ENOMEM;
+		}
+	}
+
+	/*
+	 * Setup descriptors.  For receive we always terminate
+	 * the descriptor list with a self-linked entry so we'll
+	 * not get overrun under high load (as can happen with a
+	 * 5212 when ANI processing enables PHY error frames).
+	 *
+	 * To insure the last descriptor is self-linked we create
+	 * each descriptor as self-linked and add it to the end.  As
+	 * each additional descriptor is added the previous self-linked
+	 * entry is ``fixed'' naturally.  This should be safe even
+	 * if DMA is happening.  When processing RX interrupts we
+	 * never remove/process the last, self-linked, entry on the
+	 * descriptor list.  This insures the hardware always has
+	 * someplace to write a new frame.
+	 */
+	ds = bf->desc;
+	ds->ds_link = bf->daddr;	/* link to self */
+	ds->ds_data = bf->skbaddr;
+	ath5k_hw_setup_rx_desc(ah, ds,
+		skb_tailroom(skb),	/* buffer size */
+		0);
+
+	if (sc->rxlink != NULL)
+		*sc->rxlink = bf->daddr;
+	sc->rxlink = &ds->ds_link;
+	return 0;
+}
+
+static int
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
+		struct ieee80211_tx_control *ctl)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_txq *txq = sc->txq;
+	struct ath5k_desc *ds = bf->desc;
+	struct sk_buff *skb = bf->skb;
+	unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID;
+	int ret;
+
+	flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
+	bf->ctl = *ctl;
+	/* XXX endianness */
+	bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
+			PCI_DMA_TODEVICE);
+
+	if (ctl->flags & IEEE80211_TXCTL_NO_ACK)
+		flags |= AR5K_TXDESC_NOACK;
+
+	pktlen = skb->len + FCS_LEN;
+
+	if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
+		keyidx = ctl->key_idx;
+		pktlen += ctl->icv_len;
+	}
+
+	ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
+		ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
+		(ctl->power_level * 2), ctl->tx_rate, ctl->retry_limit, keyidx, 0, flags, 0, 0);
+	if (ret)
+		goto err_unmap;
+
+	ds->ds_link = 0;
+	ds->ds_data = bf->skbaddr;
+
+	spin_lock_bh(&txq->lock);
+	list_add_tail(&bf->list, &txq->q);
+	sc->tx_stats.data[txq->qnum].len++;
+	if (txq->link == NULL) /* is this first packet? */
+		ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr);
+	else /* no, so only link it */
+		*txq->link = bf->daddr;
+
+	txq->link = &ds->ds_link;
+	ath5k_hw_tx_start(ah, txq->qnum);
+	spin_unlock_bh(&txq->lock);
+
+	return 0;
+err_unmap:
+	pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
+	return ret;
+}
+
+/*******************\
+* Descriptors setup *
+\*******************/
+
+static int
+ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
+{
+	struct ath5k_desc *ds;
+	struct ath5k_buf *bf;
+	dma_addr_t da;
+	unsigned int i;
+	int ret;
+
+	/* allocate descriptors */
+	sc->desc_len = sizeof(struct ath5k_desc) *
+			(ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1);
+	sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr);
+	if (sc->desc == NULL) {
+		ATH5K_ERR(sc, "can't allocate descriptors\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	ds = sc->desc;
+	da = sc->desc_daddr;
+	ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "DMA map: %p (%zu) -> %llx\n",
+		ds, sc->desc_len, (unsigned long long)sc->desc_daddr);
+
+	bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF,
+			sizeof(struct ath5k_buf), GFP_KERNEL);
+	if (bf == NULL) {
+		ATH5K_ERR(sc, "can't allocate bufptr\n");
+		ret = -ENOMEM;
+		goto err_free;
+	}
+	sc->bufptr = bf;
+
+	INIT_LIST_HEAD(&sc->rxbuf);
+	for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) {
+		bf->desc = ds;
+		bf->daddr = da;
+		list_add_tail(&bf->list, &sc->rxbuf);
+	}
+
+	INIT_LIST_HEAD(&sc->txbuf);
+	sc->txbuf_len = ATH_TXBUF;
+	for (i = 0; i < ATH_TXBUF; i++, bf++, ds++,
+			da += sizeof(*ds)) {
+		bf->desc = ds;
+		bf->daddr = da;
+		list_add_tail(&bf->list, &sc->txbuf);
+	}
+
+	/* beacon buffer */
+	bf->desc = ds;
+	bf->daddr = da;
+	sc->bbuf = bf;
+
+	return 0;
+err_free:
+	pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
+err:
+	sc->desc = NULL;
+	return ret;
+}
+
+static void
+ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
+{
+	struct ath5k_buf *bf;
+
+	ath5k_txbuf_free(sc, sc->bbuf);
+	list_for_each_entry(bf, &sc->txbuf, list)
+		ath5k_txbuf_free(sc, bf);
+	list_for_each_entry(bf, &sc->rxbuf, list)
+		ath5k_txbuf_free(sc, bf);
+
+	/* Free memory associated with all descriptors */
+	pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
+
+	kfree(sc->bufptr);
+	sc->bufptr = NULL;
+}
+
+
+
+
+
+/**************\
+* Queues setup *
+\**************/
+
+static struct ath5k_txq *
+ath5k_txq_setup(struct ath5k_softc *sc,
+		int qtype, int subtype)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_txq *txq;
+	struct ath5k_txq_info qi = {
+		.tqi_subtype = subtype,
+		.tqi_aifs = AR5K_TXQ_USEDEFAULT,
+		.tqi_cw_min = AR5K_TXQ_USEDEFAULT,
+		.tqi_cw_max = AR5K_TXQ_USEDEFAULT
+	};
+	int qnum;
+
+	/*
+	 * Enable interrupts only for EOL and DESC conditions.
+	 * We mark tx descriptors to receive a DESC interrupt
+	 * when a tx queue gets deep; otherwise waiting for the
+	 * EOL to reap descriptors.  Note that this is done to
+	 * reduce interrupt load and this only defers reaping
+	 * descriptors, never transmitting frames.  Aside from
+	 * reducing interrupts this also permits more concurrency.
+	 * The only potential downside is if the tx queue backs
+	 * up in which case the top half of the kernel may backup
+	 * due to a lack of tx descriptors.
+	 */
+	qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE |
+				AR5K_TXQ_FLAG_TXDESCINT_ENABLE;
+	qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi);
+	if (qnum < 0) {
+		/*
+		 * NB: don't print a message, this happens
+		 * normally on parts with too few tx queues
+		 */
+		return ERR_PTR(qnum);
+	}
+	if (qnum >= ARRAY_SIZE(sc->txqs)) {
+		ATH5K_ERR(sc, "hw qnum %u out of range, max %tu!\n",
+			qnum, ARRAY_SIZE(sc->txqs));
+		ath5k_hw_release_tx_queue(ah, qnum);
+		return ERR_PTR(-EINVAL);
+	}
+	txq = &sc->txqs[qnum];
+	if (!txq->setup) {
+		txq->qnum = qnum;
+		txq->link = NULL;
+		INIT_LIST_HEAD(&txq->q);
+		spin_lock_init(&txq->lock);
+		txq->setup = true;
+	}
+	return &sc->txqs[qnum];
+}
+
+static int
+ath5k_beaconq_setup(struct ath5k_hw *ah)
+{
+	struct ath5k_txq_info qi = {
+		.tqi_aifs = AR5K_TXQ_USEDEFAULT,
+		.tqi_cw_min = AR5K_TXQ_USEDEFAULT,
+		.tqi_cw_max = AR5K_TXQ_USEDEFAULT,
+		/* NB: for dynamic turbo, don't enable any other interrupts */
+		.tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE
+	};
+
+	return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi);
+}
+
+static int
+ath5k_beaconq_config(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_txq_info qi;
+	int ret;
+
+	ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi);
+	if (ret)
+		return ret;
+	if (sc->opmode == IEEE80211_IF_TYPE_AP) {
+		/*
+		 * Always burst out beacon and CAB traffic
+		 * (aifs = cwmin = cwmax = 0)
+		 */
+		qi.tqi_aifs = 0;
+		qi.tqi_cw_min = 0;
+		qi.tqi_cw_max = 0;
+	} else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+		/*
+		 * Adhoc mode; backoff between 0 and (2 * cw_min).
+		 */
+		qi.tqi_aifs = 0;
+		qi.tqi_cw_min = 0;
+		qi.tqi_cw_max = 2 * ah->ah_cw_min;
+	}
+
+	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
+		"beacon queueprops tqi_aifs:%d tqi_cw_min:%d tqi_cw_max:%d\n",
+		qi.tqi_aifs, qi.tqi_cw_min, qi.tqi_cw_max);
+
+	ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi);
+	if (ret) {
+		ATH5K_ERR(sc, "%s: unable to update parameters for beacon "
+			"hardware queue!\n", __func__);
+		return ret;
+	}
+
+	return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */;
+}
+
+static void
+ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+{
+	struct ath5k_buf *bf, *bf0;
+
+	/*
+	 * NB: this assumes output has been stopped and
+	 *     we do not need to block ath5k_tx_tasklet
+	 */
+	spin_lock_bh(&txq->lock);
+	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+		ath5k_debug_printtxbuf(sc, bf, !sc->ah->ah_proc_tx_desc(sc->ah,
+					bf->desc));
+
+		ath5k_txbuf_free(sc, bf);
+
+		spin_lock_bh(&sc->txbuflock);
+		sc->tx_stats.data[txq->qnum].len--;
+		list_move_tail(&bf->list, &sc->txbuf);
+		sc->txbuf_len++;
+		spin_unlock_bh(&sc->txbuflock);
+	}
+	txq->link = NULL;
+	spin_unlock_bh(&txq->lock);
+}
+
+/*
+ * Drain the transmit queues and reclaim resources.
+ */
+static void
+ath5k_txq_cleanup(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	unsigned int i;
+
+	/* XXX return value */
+	if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) {
+		/* don't touch the hardware if marked invalid */
+		ath5k_hw_stop_tx_dma(ah, sc->bhalq);
+		ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n",
+			ath5k_hw_get_tx_buf(ah, sc->bhalq));
+		for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
+			if (sc->txqs[i].setup) {
+				ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum);
+				ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, "
+					"link %p\n",
+					sc->txqs[i].qnum,
+					ath5k_hw_get_tx_buf(ah,
+							sc->txqs[i].qnum),
+					sc->txqs[i].link);
+			}
+	}
+	ieee80211_start_queues(sc->hw); /* XXX move to callers */
+
+	for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
+		if (sc->txqs[i].setup)
+			ath5k_txq_drainq(sc, &sc->txqs[i]);
+}
+
+static void
+ath5k_txq_release(struct ath5k_softc *sc)
+{
+	struct ath5k_txq *txq = sc->txqs;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(sc->txqs); i++, txq++)
+		if (txq->setup) {
+			ath5k_hw_release_tx_queue(sc->ah, txq->qnum);
+			txq->setup = false;
+		}
+}
+
+
+
+
+/*************\
+* RX Handling *
+\*************/
+
+/*
+ * Enable the receive h/w following a reset.
+ */
+static int
+ath5k_rx_start(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_buf *bf;
+	int ret;
+
+	sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz);
+
+	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n",
+		sc->cachelsz, sc->rxbufsize);
+
+	sc->rxlink = NULL;
+
+	spin_lock_bh(&sc->rxbuflock);
+	list_for_each_entry(bf, &sc->rxbuf, list) {
+		ret = ath5k_rxbuf_setup(sc, bf);
+		if (ret != 0) {
+			spin_unlock_bh(&sc->rxbuflock);
+			goto err;
+		}
+	}
+	bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
+	spin_unlock_bh(&sc->rxbuflock);
+
+	ath5k_hw_put_rx_buf(ah, bf->daddr);
+	ath5k_hw_start_rx(ah);		/* enable recv descriptors */
+	ath5k_mode_setup(sc);		/* set filters, etc. */
+	ath5k_hw_start_rx_pcu(ah);	/* re-enable PCU/DMA engine */
+
+	return 0;
+err:
+	return ret;
+}
+
+/*
+ * Disable the receive h/w in preparation for a reset.
+ */
+static void
+ath5k_rx_stop(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	ath5k_hw_stop_pcu_recv(ah);	/* disable PCU */
+	ath5k_hw_set_rx_filter(ah, 0);	/* clear recv filter */
+	ath5k_hw_stop_rx_dma(ah);	/* disable DMA engine */
+	mdelay(3);			/* 3ms is long enough for 1 frame */
+
+	ath5k_debug_printrxbuffs(sc, ah);
+
+	sc->rxlink = NULL;		/* just in case */
+}
+
+static unsigned int
+ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds,
+		struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (void *)skb->data;
+	unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb);
+
+	if (!(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) &&
+			ds->ds_rxstat.rs_keyix != AR5K_RXKEYIX_INVALID)
+		return RX_FLAG_DECRYPTED;
+
+	/* Apparently when a default key is used to decrypt the packet
+	   the hw does not set the index used to decrypt.  In such cases
+	   get the index from the packet. */
+	if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) &&
+			!(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) &&
+			skb->len >= hlen + 4) {
+		keyix = skb->data[hlen + 3] >> 6;
+
+		if (test_bit(keyix, sc->keymap))
+			return RX_FLAG_DECRYPTED;
+	}
+
+	return 0;
+}
+
+
+static void
+ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb)
+{
+	u32 hw_tu;
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+
+	if ((mgmt->frame_control & IEEE80211_FCTL_FTYPE) ==
+		IEEE80211_FTYPE_MGMT &&
+	    (mgmt->frame_control & IEEE80211_FCTL_STYPE) ==
+		IEEE80211_STYPE_BEACON &&
+	    mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS &&
+	    memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) {
+		/*
+		 * Received an IBSS beacon with the same BSSID. Hardware might
+		 * have updated the TSF, check if we need to update timers.
+		 */
+		hw_tu = TSF_TO_TU(ath5k_hw_get_tsf64(sc->ah));
+		if (hw_tu >= sc->nexttbtt) {
+			ath5k_beacon_update_timers(sc,
+				mgmt->u.beacon.timestamp);
+			ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+				"detected HW merge from received beacon\n");
+		}
+	}
+}
+
+
+static void
+ath5k_tasklet_rx(unsigned long data)
+{
+	struct ieee80211_rx_status rxs = {};
+	struct sk_buff *skb;
+	struct ath5k_softc *sc = (void *)data;
+	struct ath5k_buf *bf;
+	struct ath5k_desc *ds;
+	u16 len;
+	u8 stat;
+	int ret;
+	int hdrlen;
+	int pad;
+
+	spin_lock(&sc->rxbuflock);
+	do {
+		if (unlikely(list_empty(&sc->rxbuf))) {
+			ATH5K_WARN(sc, "empty rx buf pool\n");
+			break;
+		}
+		bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
+		BUG_ON(bf->skb == NULL);
+		skb = bf->skb;
+		ds = bf->desc;
+
+		/* TODO only one segment */
+		pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
+				sc->desc_len, PCI_DMA_FROMDEVICE);
+
+		if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */
+			break;
+
+		ret = sc->ah->ah_proc_rx_desc(sc->ah, ds);
+		if (unlikely(ret == -EINPROGRESS))
+			break;
+		else if (unlikely(ret)) {
+			ATH5K_ERR(sc, "error in processing rx descriptor\n");
+			return;
+		}
+
+		if (unlikely(ds->ds_rxstat.rs_more)) {
+			ATH5K_WARN(sc, "unsupported jumbo\n");
+			goto next;
+		}
+
+		stat = ds->ds_rxstat.rs_status;
+		if (unlikely(stat)) {
+			if (stat & AR5K_RXERR_PHY)
+				goto next;
+			if (stat & AR5K_RXERR_DECRYPT) {
+				/*
+				 * Decrypt error.  If the error occurred
+				 * because there was no hardware key, then
+				 * let the frame through so the upper layers
+				 * can process it.  This is necessary for 5210
+				 * parts which have no way to setup a ``clear''
+				 * key cache entry.
+				 *
+				 * XXX do key cache faulting
+				 */
+				if (ds->ds_rxstat.rs_keyix ==
+						AR5K_RXKEYIX_INVALID &&
+						!(stat & AR5K_RXERR_CRC))
+					goto accept;
+			}
+			if (stat & AR5K_RXERR_MIC) {
+				rxs.flag |= RX_FLAG_MMIC_ERROR;
+				goto accept;
+			}
+
+			/* let crypto-error packets fall through in MNTR */
+			if ((stat & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) ||
+					sc->opmode != IEEE80211_IF_TYPE_MNTR)
+				goto next;
+		}
+accept:
+		len = ds->ds_rxstat.rs_datalen;
+		pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, len,
+				PCI_DMA_FROMDEVICE);
+		pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
+				PCI_DMA_FROMDEVICE);
+		bf->skb = NULL;
+
+		skb_put(skb, len);
+
+		/*
+		 * the hardware adds a padding to 4 byte boundaries between
+		 * the header and the payload data if the header length is
+		 * not multiples of 4 - remove it
+		 */
+		hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+		if (hdrlen & 3) {
+			pad = hdrlen % 4;
+			memmove(skb->data + pad, skb->data, hdrlen);
+			skb_pull(skb, pad);
+		}
+
+		/*
+		 * always extend the mac timestamp, since this information is
+		 * also needed for proper IBSS merging.
+		 *
+		 * XXX: it might be too late to do it here, since rs_tstamp is
+		 * 15bit only. that means TSF extension has to be done within
+		 * 32768usec (about 32ms). it might be necessary to move this to
+		 * the interrupt handler, like it is done in madwifi.
+		 */
+		rxs.mactime = ath5k_extend_tsf(sc->ah, ds->ds_rxstat.rs_tstamp);
+		rxs.flag |= RX_FLAG_TSFT;
+
+		rxs.freq = sc->curchan->freq;
+		rxs.channel = sc->curchan->chan;
+		rxs.phymode = sc->curmode;
+
+		/*
+		 * signal quality:
+		 * the names here are misleading and the usage of these
+		 * values by iwconfig makes it even worse
+		 */
+		/* noise floor in dBm, from the last noise calibration */
+		rxs.noise = sc->ah->ah_noise_floor;
+		/* signal level in dBm */
+		rxs.ssi = rxs.noise + ds->ds_rxstat.rs_rssi;
+		/*
+		 * "signal" is actually displayed as Link Quality by iwconfig
+		 * we provide a percentage based on rssi (assuming max rssi 64)
+		 */
+		rxs.signal = ds->ds_rxstat.rs_rssi * 100 / 64;
+
+		rxs.antenna = ds->ds_rxstat.rs_antenna;
+		rxs.rate = ds->ds_rxstat.rs_rate;
+		rxs.flag |= ath5k_rx_decrypted(sc, ds, skb);
+
+		ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
+
+		/* check beacons in IBSS mode */
+		if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
+			ath5k_check_ibss_hw_merge(sc, skb);
+
+		__ieee80211_rx(sc->hw, skb, &rxs);
+		sc->led_rxrate = ds->ds_rxstat.rs_rate;
+		ath5k_led_event(sc, ATH_LED_RX);
+next:
+		list_move_tail(&bf->list, &sc->rxbuf);
+	} while (ath5k_rxbuf_setup(sc, bf) == 0);
+	spin_unlock(&sc->rxbuflock);
+}
+
+
+
+
+/*************\
+* TX Handling *
+\*************/
+
+static void
+ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+{
+	struct ieee80211_tx_status txs = {};
+	struct ath5k_buf *bf, *bf0;
+	struct ath5k_desc *ds;
+	struct sk_buff *skb;
+	int ret;
+
+	spin_lock(&txq->lock);
+	list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+		ds = bf->desc;
+
+		/* TODO only one segment */
+		pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
+				sc->desc_len, PCI_DMA_FROMDEVICE);
+		ret = sc->ah->ah_proc_tx_desc(sc->ah, ds);
+		if (unlikely(ret == -EINPROGRESS))
+			break;
+		else if (unlikely(ret)) {
+			ATH5K_ERR(sc, "error %d while processing queue %u\n",
+				ret, txq->qnum);
+			break;
+		}
+
+		skb = bf->skb;
+		bf->skb = NULL;
+		pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
+				PCI_DMA_TODEVICE);
+
+		txs.control = bf->ctl;
+		txs.retry_count = ds->ds_txstat.ts_shortretry +
+			ds->ds_txstat.ts_longretry / 6;
+		if (unlikely(ds->ds_txstat.ts_status)) {
+			sc->ll_stats.dot11ACKFailureCount++;
+			if (ds->ds_txstat.ts_status & AR5K_TXERR_XRETRY)
+				txs.excessive_retries = 1;
+			else if (ds->ds_txstat.ts_status & AR5K_TXERR_FILT)
+				txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED;
+		} else {
+			txs.flags |= IEEE80211_TX_STATUS_ACK;
+			txs.ack_signal = ds->ds_txstat.ts_rssi;
+		}
+
+		ieee80211_tx_status(sc->hw, skb, &txs);
+		sc->tx_stats.data[txq->qnum].count++;
+
+		spin_lock(&sc->txbuflock);
+		sc->tx_stats.data[txq->qnum].len--;
+		list_move_tail(&bf->list, &sc->txbuf);
+		sc->txbuf_len++;
+		spin_unlock(&sc->txbuflock);
+	}
+	if (likely(list_empty(&txq->q)))
+		txq->link = NULL;
+	spin_unlock(&txq->lock);
+	if (sc->txbuf_len > ATH_TXBUF / 5)
+		ieee80211_wake_queues(sc->hw);
+}
+
+static void
+ath5k_tasklet_tx(unsigned long data)
+{
+	struct ath5k_softc *sc = (void *)data;
+
+	ath5k_tx_processq(sc, sc->txq);
+
+	ath5k_led_event(sc, ATH_LED_TX);
+}
+
+
+
+
+/*****************\
+* Beacon handling *
+\*****************/
+
+/*
+ * Setup the beacon frame for transmit.
+ */
+static int
+ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
+		struct ieee80211_tx_control *ctl)
+{
+	struct sk_buff *skb = bf->skb;
+	struct ath5k_hw *ah = sc->ah;
+	struct ath5k_desc *ds;
+	int ret, antenna = 0;
+	u32 flags;
+
+	bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
+			PCI_DMA_TODEVICE);
+	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] "
+			"skbaddr %llx\n", skb, skb->data, skb->len,
+			(unsigned long long)bf->skbaddr);
+	if (pci_dma_mapping_error(bf->skbaddr)) {
+		ATH5K_ERR(sc, "beacon DMA mapping failed\n");
+		return -EIO;
+	}
+
+	ds = bf->desc;
+
+	flags = AR5K_TXDESC_NOACK;
+	if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ath5k_hw_hasveol(ah)) {
+		ds->ds_link = bf->daddr;	/* self-linked */
+		flags |= AR5K_TXDESC_VEOL;
+		/*
+		 * Let hardware handle antenna switching if txantenna is not set
+		 */
+	} else {
+		ds->ds_link = 0;
+		/*
+		 * Switch antenna every 4 beacons if txantenna is not set
+		 * XXX assumes two antennas
+		 */
+		if (antenna == 0)
+			antenna = sc->bsent & 4 ? 2 : 1;
+	}
+
+	ds->ds_data = bf->skbaddr;
+	ret = ah->ah_setup_tx_desc(ah, ds, skb->len + FCS_LEN,
+			ieee80211_get_hdrlen_from_skb(skb),
+			AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1,
+			AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0);
+	if (ret)
+		goto err_unmap;
+
+	return 0;
+err_unmap:
+	pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
+	return ret;
+}
+
+/*
+ * Transmit a beacon frame at SWBA.  Dynamic updates to the
+ * frame contents are done as needed and the slot time is
+ * also adjusted based on current state.
+ *
+ * this is usually called from interrupt context (ath5k_intr())
+ * but also from ath5k_beacon_config() in IBSS mode which in turn
+ * can be called from a tasklet and user context
+ */
+static void
+ath5k_beacon_send(struct ath5k_softc *sc)
+{
+	struct ath5k_buf *bf = sc->bbuf;
+	struct ath5k_hw *ah = sc->ah;
+
+	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "in beacon_send\n");
+
+	if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA ||
+			sc->opmode == IEEE80211_IF_TYPE_MNTR)) {
+		ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL);
+		return;
+	}
+	/*
+	 * Check if the previous beacon has gone out.  If
+	 * not don't don't try to post another, skip this
+	 * period and wait for the next.  Missed beacons
+	 * indicate a problem and should not occur.  If we
+	 * miss too many consecutive beacons reset the device.
+	 */
+	if (unlikely(ath5k_hw_num_tx_pending(ah, sc->bhalq) != 0)) {
+		sc->bmisscount++;
+		ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
+			"missed %u consecutive beacons\n", sc->bmisscount);
+		if (sc->bmisscount > 3) {		/* NB: 3 is a guess */
+			ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
+				"stuck beacon time (%u missed)\n",
+				sc->bmisscount);
+			tasklet_schedule(&sc->restq);
+		}
+		return;
+	}
+	if (unlikely(sc->bmisscount != 0)) {
+		ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC,
+			"resume beacon xmit after %u misses\n",
+			sc->bmisscount);
+		sc->bmisscount = 0;
+	}
+
+	/*
+	 * Stop any current dma and put the new frame on the queue.
+	 * This should never fail since we check above that no frames
+	 * are still pending on the queue.
+	 */
+	if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) {
+		ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq);
+		/* NB: hw still stops DMA, so proceed */
+	}
+	pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, bf->skb->len,
+			PCI_DMA_TODEVICE);
+
+	ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr);
+	ath5k_hw_tx_start(ah, sc->bhalq);
+	ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "TXDP[%u] = %llx (%p)\n",
+		sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
+
+	sc->bsent++;
+}
+
+
+/**
+ * ath5k_beacon_update_timers - update beacon timers
+ *
+ * @sc: struct ath5k_softc pointer we are operating on
+ * @bc_tsf: the timestamp of the beacon. 0 to reset the TSF. -1 to perform a
+ *          beacon timer update based on the current HW TSF.
+ *
+ * Calculate the next target beacon transmit time (TBTT) based on the timestamp
+ * of a received beacon or the current local hardware TSF and write it to the
+ * beacon timer registers.
+ *
+ * This is called in a variety of situations, e.g. when a beacon is received,
+ * when a HW merge has been detected, but also when an new IBSS is created or
+ * when we otherwise know we have to update the timers, but we keep it in this
+ * function to have it all together in one place.
+ */
+static void
+ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf)
+{
+	struct ath5k_hw *ah = sc->ah;
+	u32 nexttbtt, intval, hw_tu, bc_tu;
+	u64 hw_tsf;
+
+	intval = sc->bintval & AR5K_BEACON_PERIOD;
+	if (WARN_ON(!intval))
+		return;
+
+	/* beacon TSF converted to TU */
+	bc_tu = TSF_TO_TU(bc_tsf);
+
+	/* current TSF converted to TU */
+	hw_tsf = ath5k_hw_get_tsf64(ah);
+	hw_tu = TSF_TO_TU(hw_tsf);
+
+#define FUDGE 3
+	/* we use FUDGE to make sure the next TBTT is ahead of the current TU */
+	if (bc_tsf == -1) {
+		/*
+		 * no beacons received, called internally.
+		 * just need to refresh timers based on HW TSF.
+		 */
+		nexttbtt = roundup(hw_tu + FUDGE, intval);
+	} else if (bc_tsf == 0) {
+		/*
+		 * no beacon received, probably called by ath5k_reset_tsf().
+		 * reset TSF to start with 0.
+		 */
+		nexttbtt = intval;
+		intval |= AR5K_BEACON_RESET_TSF;
+	} else if (bc_tsf > hw_tsf) {
+		/*
+		 * beacon received, SW merge happend but HW TSF not yet updated.
+		 * not possible to reconfigure timers yet, but next time we
+		 * receive a beacon with the same BSSID, the hardware will
+		 * automatically update the TSF and then we need to reconfigure
+		 * the timers.
+		 */
+		ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+			"need to wait for HW TSF sync\n");
+		return;
+	} else {
+		/*
+		 * most important case for beacon synchronization between STA.
+		 *
+		 * beacon received and HW TSF has been already updated by HW.
+		 * update next TBTT based on the TSF of the beacon, but make
+		 * sure it is ahead of our local TSF timer.
+		 */
+		nexttbtt = bc_tu + roundup(hw_tu + FUDGE - bc_tu, intval);
+	}
+#undef FUDGE
+
+	sc->nexttbtt = nexttbtt;
+
+	intval |= AR5K_BEACON_ENA;
+	ath5k_hw_init_beacon(ah, nexttbtt, intval);
+
+	/*
+	 * debugging output last in order to preserve the time critical aspect
+	 * of this function
+	 */
+	if (bc_tsf == -1)
+		ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+			"reconfigured timers based on HW TSF\n");
+	else if (bc_tsf == 0)
+		ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+			"reset HW TSF and timers\n");
+	else
+		ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+			"updated timers based on beacon TSF\n");
+
+	ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON,
+		"bc_tsf %llx hw_tsf %llx bc_tu %u hw_tu %u nexttbtt %u\n",
+		bc_tsf, hw_tsf, bc_tu, hw_tu, nexttbtt);
+	ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "intval %u %s %s\n",
+		intval & AR5K_BEACON_PERIOD,
+		intval & AR5K_BEACON_ENA ? "AR5K_BEACON_ENA" : "",
+		intval & AR5K_BEACON_RESET_TSF ? "AR5K_BEACON_RESET_TSF" : "");
+}
+
+
+/**
+ * ath5k_beacon_config - Configure the beacon queues and interrupts
+ *
+ * @sc: struct ath5k_softc pointer we are operating on
+ *
+ * When operating in station mode we want to receive a BMISS interrupt when we
+ * stop seeing beacons from the AP we've associated with so we can look for
+ * another AP to associate with.
+ *
+ * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA
+ * interrupts to detect HW merges only.
+ *
+ * AP mode is missing.
+ */
+static void
+ath5k_beacon_config(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	ath5k_hw_set_intr(ah, 0);
+	sc->bmisscount = 0;
+
+	if (sc->opmode == IEEE80211_IF_TYPE_STA) {
+		sc->imask |= AR5K_INT_BMISS;
+	} else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+		/*
+		 * In IBSS mode we use a self-linked tx descriptor and let the
+		 * hardware send the beacons automatically. We have to load it
+		 * only once here.
+		 * We use the SWBA interrupt only to keep track of the beacon
+		 * timers in order to detect HW merges (automatic TSF updates).
+		 */
+		ath5k_beaconq_config(sc);
+
+		sc->imask |= AR5K_INT_SWBA;
+
+		if (ath5k_hw_hasveol(ah))
+			ath5k_beacon_send(sc);
+	}
+	/* TODO else AP */
+
+	ath5k_hw_set_intr(ah, sc->imask);
+}
+
+
+/********************\
+* Interrupt handling *
+\********************/
+
+static int
+ath5k_init(struct ath5k_softc *sc)
+{
+	int ret;
+
+	mutex_lock(&sc->lock);
+
+	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode);
+
+	/*
+	 * Stop anything previously setup.  This is safe
+	 * no matter this is the first time through or not.
+	 */
+	ath5k_stop_locked(sc);
+
+	/*
+	 * The basic interface to setting the hardware in a good
+	 * state is ``reset''.  On return the hardware is known to
+	 * be powered up and with interrupts disabled.  This must
+	 * be followed by initialization of the appropriate bits
+	 * and then setup of the interrupt mask.
+	 */
+	sc->curchan = sc->hw->conf.chan;
+	ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false);
+	if (ret) {
+		ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret);
+		goto done;
+	}
+	/*
+	 * This is needed only to setup initial state
+	 * but it's best done after a reset.
+	 */
+	ath5k_hw_set_txpower_limit(sc->ah, 0);
+
+	/*
+	 * Setup the hardware after reset: the key cache
+	 * is filled as needed and the receive engine is
+	 * set going.  Frame transmit is handled entirely
+	 * in the frame output path; there's nothing to do
+	 * here except setup the interrupt mask.
+	 */
+	ret = ath5k_rx_start(sc);
+	if (ret)
+		goto done;
+
+	/*
+	 * Enable interrupts.
+	 */
+	sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL |
+		AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL;
+
+	ath5k_hw_set_intr(sc->ah, sc->imask);
+	/* Set ack to be sent at low bit-rates */
+	ath5k_hw_set_ack_bitrate_high(sc->ah, false);
+
+	mod_timer(&sc->calib_tim, round_jiffies(jiffies +
+			msecs_to_jiffies(ath5k_calinterval * 1000)));
+
+	ret = 0;
+done:
+	mutex_unlock(&sc->lock);
+	return ret;
+}
+
+static int
+ath5k_stop_locked(struct ath5k_softc *sc)
+{
+	struct ath5k_hw *ah = sc->ah;
+
+	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n",
+			test_bit(ATH_STAT_INVALID, sc->status));
+
+	/*
+	 * Shutdown the hardware and driver:
+	 *    stop output from above
+	 *    disable interrupts
+	 *    turn off timers
+	 *    turn off the radio
+	 *    clear transmit machinery
+	 *    clear receive machinery
+	 *    drain and release tx queues
+	 *    reclaim beacon resources
+	 *    power down hardware
+	 *
+	 * Note that some of this work is not possible if the
+	 * hardware is gone (invalid).
+	 */
+	ieee80211_stop_queues(sc->hw);
+
+	if (!test_bit(ATH_STAT_INVALID, sc->status)) {
+		if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
+			del_timer_sync(&sc->led_tim);
+			ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on);
+			__clear_bit(ATH_STAT_LEDBLINKING, sc->status);
+		}
+		ath5k_hw_set_intr(ah, 0);
+	}
+	ath5k_txq_cleanup(sc);
+	if (!test_bit(ATH_STAT_INVALID, sc->status)) {
+		ath5k_rx_stop(sc);
+		ath5k_hw_phy_disable(ah);
+	} else
+		sc->rxlink = NULL;
+
+	return 0;
+}
+
+/*
+ * Stop the device, grabbing the top-level lock to protect
+ * against concurrent entry through ath5k_init (which can happen
+ * if another thread does a system call and the thread doing the
+ * stop is preempted).
+ */
+static int
+ath5k_stop_hw(struct ath5k_softc *sc)
+{
+	int ret;
+
+	mutex_lock(&sc->lock);
+	ret = ath5k_stop_locked(sc);
+	if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {
+		/*
+		 * Set the chip in full sleep mode.  Note that we are
+		 * careful to do this only when bringing the interface
+		 * completely to a stop.  When the chip is in this state
+		 * it must be carefully woken up or references to
+		 * registers in the PCI clock domain may freeze the bus
+		 * (and system).  This varies by chip and is mostly an
+		 * issue with newer parts that go to sleep more quickly.
+		 */
+		if (sc->ah->ah_mac_srev >= 0x78) {
+			/*
+			 * XXX
+			 * don't put newer MAC revisions > 7.8 to sleep because
+			 * of the above mentioned problems
+			 */
+			ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, "
+				"not putting device to sleep\n");
+		} else {
+			ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+				"putting device to full sleep\n");
+			ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0);
+		}
+	}
+	ath5k_txbuf_free(sc, sc->bbuf);
+	mutex_unlock(&sc->lock);
+
+	del_timer_sync(&sc->calib_tim);
+
+	return ret;
+}
+
+static irqreturn_t
+ath5k_intr(int irq, void *dev_id)
+{
+	struct ath5k_softc *sc = dev_id;
+	struct ath5k_hw *ah = sc->ah;
+	enum ath5k_int status;
+	unsigned int counter = 1000;
+
+	if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) ||
+				!ath5k_hw_is_intr_pending(ah)))
+		return IRQ_NONE;
+
+	do {
+		/*
+		 * Figure out the reason(s) for the interrupt.  Note
+		 * that get_isr returns a pseudo-ISR that may include
+		 * bits we haven't explicitly enabled so we mask the
+		 * value to insure we only process bits we requested.
+		 */
+		ath5k_hw_get_isr(ah, &status);		/* NB: clears IRQ too */
+		ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n",
+				status, sc->imask);
+		status &= sc->imask; /* discard unasked for bits */
+		if (unlikely(status & AR5K_INT_FATAL)) {
+			/*
+			 * Fatal errors are unrecoverable.
+			 * Typically these are caused by DMA errors.
+			 */
+			tasklet_schedule(&sc->restq);
+		} else if (unlikely(status & AR5K_INT_RXORN)) {
+			tasklet_schedule(&sc->restq);
+		} else {
+			if (status & AR5K_INT_SWBA) {
+				/*
+				* Software beacon alert--time to send a beacon.
+				* Handle beacon transmission directly; deferring
+				* this is too slow to meet timing constraints
+				* under load.
+				*
+				* In IBSS mode we use this interrupt just to
+				* keep track of the next TBTT (target beacon
+				* transmission time) in order to detect hardware
+				* merges (TSF updates).
+				*/
+				if (sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+					 /* XXX: only if VEOL suppported */
+					u64 tsf = ath5k_hw_get_tsf64(ah);
+					sc->nexttbtt += sc->bintval;
+					ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
+						"SWBA nexttbtt: %x hw_tu: %x "
+						"TSF: %llx\n",
+						sc->nexttbtt,
+						TSF_TO_TU(tsf), tsf);
+				} else {
+					ath5k_beacon_send(sc);
+				}
+			}
+			if (status & AR5K_INT_RXEOL) {
+				/*
+				* NB: the hardware should re-read the link when
+				*     RXE bit is written, but it doesn't work at
+				*     least on older hardware revs.
+				*/
+				sc->rxlink = NULL;
+			}
+			if (status & AR5K_INT_TXURN) {
+				/* bump tx trigger level */
+				ath5k_hw_update_tx_triglevel(ah, true);
+			}
+			if (status & AR5K_INT_RX)
+				tasklet_schedule(&sc->rxtq);
+			if (status & AR5K_INT_TX)
+				tasklet_schedule(&sc->txtq);
+			if (status & AR5K_INT_BMISS) {
+			}
+			if (status & AR5K_INT_MIB) {
+				/* TODO */
+			}
+		}
+	} while (ath5k_hw_is_intr_pending(ah) && counter-- > 0);
+
+	if (unlikely(!counter))
+		ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
+
+	return IRQ_HANDLED;
+}
+
+static void
+ath5k_tasklet_reset(unsigned long data)
+{
+	struct ath5k_softc *sc = (void *)data;
+
+	ath5k_reset(sc->hw);
+}
+
+/*
+ * Periodically recalibrate the PHY to account
+ * for temperature/environment changes.
+ */
+static void
+ath5k_calibrate(unsigned long data)
+{
+	struct ath5k_softc *sc = (void *)data;
+	struct ath5k_hw *ah = sc->ah;
+
+	ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
+		sc->curchan->chan, sc->curchan->val);
+
+	if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) {
+		/*
+		 * Rfgain is out of bounds, reset the chip
+		 * to load new gain values.
+		 */
+		ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n");
+		ath5k_reset(sc->hw);
+	}
+	if (ath5k_hw_phy_calibrate(ah, sc->curchan))
+		ATH5K_ERR(sc, "calibration of channel %u failed\n",
+				sc->curchan->chan);
+
+	mod_timer(&sc->calib_tim, round_jiffies(jiffies +
+			msecs_to_jiffies(ath5k_calinterval * 1000)));
+}
+
+
+
+/***************\
+* LED functions *
+\***************/
+
+static void
+ath5k_led_off(unsigned long data)
+{
+	struct ath5k_softc *sc = (void *)data;
+
+	if (test_bit(ATH_STAT_LEDENDBLINK, sc->status))
+		__clear_bit(ATH_STAT_LEDBLINKING, sc->status);
+	else {
+		__set_bit(ATH_STAT_LEDENDBLINK, sc->status);
+		ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on);
+		mod_timer(&sc->led_tim, jiffies + sc->led_off);
+	}
+}
+
+/*
+ * Blink the LED according to the specified on/off times.
+ */
+static void
+ath5k_led_blink(struct ath5k_softc *sc, unsigned int on,
+		unsigned int off)
+{
+	ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off);
+	ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
+	__set_bit(ATH_STAT_LEDBLINKING, sc->status);
+	__clear_bit(ATH_STAT_LEDENDBLINK, sc->status);
+	sc->led_off = off;
+	mod_timer(&sc->led_tim, jiffies + on);
+}
+
+static void
+ath5k_led_event(struct ath5k_softc *sc, int event)
+{
+	if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status)))
+		return;
+	if (unlikely(test_bit(ATH_STAT_LEDBLINKING, sc->status)))
+		return; /* don't interrupt active blink */
+	switch (event) {
+	case ATH_LED_TX:
+		ath5k_led_blink(sc, sc->hwmap[sc->led_txrate].ledon,
+			sc->hwmap[sc->led_txrate].ledoff);
+		break;
+	case ATH_LED_RX:
+		ath5k_led_blink(sc, sc->hwmap[sc->led_rxrate].ledon,
+			sc->hwmap[sc->led_rxrate].ledoff);
+		break;
+	}
+}
+
+
+
+
+/********************\
+* Mac80211 functions *
+\********************/
+
+static int
+ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+			struct ieee80211_tx_control *ctl)
+{
+	struct ath5k_softc *sc = hw->priv;
+	struct ath5k_buf *bf;
+	unsigned long flags;
+	int hdrlen;
+	int pad;
+
+	ath5k_debug_dump_skb(sc, skb, "TX  ", 1);
+
+	if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
+		ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n");
+
+	/*
+	 * the hardware expects the header padded to 4 byte boundaries
+	 * if this is not the case we add the padding after the header
+	 */
+	hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+	if (hdrlen & 3) {
+		pad = hdrlen % 4;
+		if (skb_headroom(skb) < pad) {
+			ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
+				" headroom to pad %d\n", hdrlen, pad);
+			return -1;
+		}
+		skb_push(skb, pad);
+		memmove(skb->data, skb->data+pad, hdrlen);
+	}
+
+	sc->led_txrate = ctl->tx_rate;
+
+	spin_lock_irqsave(&sc->txbuflock, flags);
+	if (list_empty(&sc->txbuf)) {
+		ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
+		spin_unlock_irqrestore(&sc->txbuflock, flags);
+		ieee80211_stop_queue(hw, ctl->queue);
+		return -1;
+	}
+	bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list);
+	list_del(&bf->list);
+	sc->txbuf_len--;
+	if (list_empty(&sc->txbuf))
+		ieee80211_stop_queues(hw);
+	spin_unlock_irqrestore(&sc->txbuflock, flags);
+
+	bf->skb = skb;
+
+	if (ath5k_txbuf_setup(sc, bf, ctl)) {
+		bf->skb = NULL;
+		spin_lock_irqsave(&sc->txbuflock, flags);
+		list_add_tail(&bf->list, &sc->txbuf);
+		sc->txbuf_len++;
+		spin_unlock_irqrestore(&sc->txbuflock, flags);
+		dev_kfree_skb_any(skb);
+		return 0;
+	}
+
+	return 0;
+}
+
+static int
+ath5k_reset(struct ieee80211_hw *hw)
+{
+	struct ath5k_softc *sc = hw->priv;
+	struct ath5k_hw *ah = sc->ah;
+	int ret;
+
+	ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
+	/*
+	 * Convert to a hw channel description with the flags
+	 * constrained to reflect the current operating mode.
+	 */
+	sc->curchan = hw->conf.chan;
+
+	ath5k_hw_set_intr(ah, 0);
+	ath5k_txq_cleanup(sc);
+	ath5k_rx_stop(sc);
+
+	ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
+	if (unlikely(ret)) {
+		ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
+		goto err;
+	}
+	ath5k_hw_set_txpower_limit(sc->ah, 0);
+
+	ret = ath5k_rx_start(sc);
+	if (unlikely(ret)) {
+		ATH5K_ERR(sc, "can't start recv logic\n");
+		goto err;
+	}
+	/*
+	 * We may be doing a reset in response to an ioctl
+	 * that changes the channel so update any state that
+	 * might change as a result.
+	 *
+	 * XXX needed?
+	 */
+/*	ath5k_chan_change(sc, c); */
+	ath5k_beacon_config(sc);
+	/* intrs are started by ath5k_beacon_config */
+
+	ieee80211_wake_queues(hw);
+
+	return 0;
+err:
+	return ret;
+}
+
+static int ath5k_start(struct ieee80211_hw *hw)
+{
+	return ath5k_init(hw->priv);
+}
+
+static void ath5k_stop(struct ieee80211_hw *hw)
+{
+	ath5k_stop_hw(hw->priv);
+}
+
+static int ath5k_add_interface(struct ieee80211_hw *hw,
+		struct ieee80211_if_init_conf *conf)
+{
+	struct ath5k_softc *sc = hw->priv;
+	int ret;
+
+	mutex_lock(&sc->lock);
+	if (sc->vif) {
+		ret = 0;
+		goto end;
+	}
+
+	sc->vif = conf->vif;
+
+	switch (conf->type) {
+	case IEEE80211_IF_TYPE_STA:
+	case IEEE80211_IF_TYPE_IBSS:
+	case IEEE80211_IF_TYPE_MNTR:
+		sc->opmode = conf->type;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		goto end;
+	}
+	ret = 0;
+end:
+	mutex_unlock(&sc->lock);
+	return ret;
+}
+
+static void
+ath5k_remove_interface(struct ieee80211_hw *hw,
+			struct ieee80211_if_init_conf *conf)
+{
+	struct ath5k_softc *sc = hw->priv;
+
+	mutex_lock(&sc->lock);
+	if (sc->vif != conf->vif)
+		goto end;
+
+	sc->vif = NULL;
+end:
+	mutex_unlock(&sc->lock);
+}
+
+static int
+ath5k_config(struct ieee80211_hw *hw,
+			struct ieee80211_conf *conf)
+{
+	struct ath5k_softc *sc = hw->priv;
+
+	sc->bintval = conf->beacon_int;
+	ath5k_setcurmode(sc, conf->phymode);
+
+	return ath5k_chan_set(sc, conf->chan);
+}
+
+static int
+ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			struct ieee80211_if_conf *conf)
+{
+	struct ath5k_softc *sc = hw->priv;
+	struct ath5k_hw *ah = sc->ah;
+	int ret;
+
+	/* Set to a reasonable value. Note that this will
+	 * be set to mac80211's value at ath5k_config(). */
+	sc->bintval = 1000;
+	mutex_lock(&sc->lock);
+	if (sc->vif != vif) {
+		ret = -EIO;
+		goto unlock;
+	}
+	if (conf->bssid) {
+		/* Cache for later use during resets */
+		memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN);
+		/* XXX: assoc id is set to 0 for now, mac80211 doesn't have
+		 * a clean way of letting us retrieve this yet. */
+		ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+	}
+	mutex_unlock(&sc->lock);
+
+	return ath5k_reset(hw);
+unlock:
+	mutex_unlock(&sc->lock);
+	return ret;
+}
+
+#define SUPPORTED_FIF_FLAGS \
+	FIF_PROMISC_IN_BSS |  FIF_ALLMULTI | FIF_FCSFAIL | \
+	FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \
+	FIF_BCN_PRBRESP_PROMISC
+/*
+ * o always accept unicast, broadcast, and multicast traffic
+ * o multicast traffic for all BSSIDs will be enabled if mac80211
+ *   says it should be
+ * o maintain current state of phy ofdm or phy cck error reception.
+ *   If the hardware detects any of these type of errors then
+ *   ath5k_hw_get_rx_filter() will pass to us the respective
+ *   hardware filters to be able to receive these type of frames.
+ * o probe request frames are accepted only when operating in
+ *   hostap, adhoc, or monitor modes
+ * o enable promiscuous mode according to the interface state
+ * o accept beacons:
+ *   - when operating in adhoc mode so the 802.11 layer creates
+ *     node table entries for peers,
+ *   - when operating in station mode for collecting rssi data when
+ *     the station is otherwise quiet, or
+ *   - when scanning
+ */
+static void ath5k_configure_filter(struct ieee80211_hw *hw,
+		unsigned int changed_flags,
+		unsigned int *new_flags,
+		int mc_count, struct dev_mc_list *mclist)
+{
+	struct ath5k_softc *sc = hw->priv;
+	struct ath5k_hw *ah = sc->ah;
+	u32 mfilt[2], val, rfilt;
+	u8 pos;
+	int i;
+
+	mfilt[0] = 0;
+	mfilt[1] = 0;
+
+	/* Only deal with supported flags */
+	changed_flags &= SUPPORTED_FIF_FLAGS;
+	*new_flags &= SUPPORTED_FIF_FLAGS;
+
+	/* If HW detects any phy or radar errors, leave those filters on.
+	 * Also, always enable Unicast, Broadcasts and Multicast
+	 * XXX: move unicast, bssid broadcasts and multicast to mac80211 */
+	rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) |
+		(AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST |
+		AR5K_RX_FILTER_MCAST);
+
+	if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
+		if (*new_flags & FIF_PROMISC_IN_BSS) {
+			rfilt |= AR5K_RX_FILTER_PROM;
+			__set_bit(ATH_STAT_PROMISC, sc->status);
+		}
+		else
+			__clear_bit(ATH_STAT_PROMISC, sc->status);
+	}
+
+	/* Note, AR5K_RX_FILTER_MCAST is already enabled */
+	if (*new_flags & FIF_ALLMULTI) {
+		mfilt[0] =  ~0;
+		mfilt[1] =  ~0;
+	} else {
+		for (i = 0; i < mc_count; i++) {
+			if (!mclist)
+				break;
+			/* calculate XOR of eight 6-bit values */
+			val = LE_READ_4(mclist->dmi_addr + 0);
+			pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+			val = LE_READ_4(mclist->dmi_addr + 3);
+			pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+			pos &= 0x3f;
+			mfilt[pos / 32] |= (1 << (pos % 32));
+			/* XXX: we might be able to just do this instead,
+			* but not sure, needs testing, if we do use this we'd
+			* neet to inform below to not reset the mcast */
+			/* ath5k_hw_set_mcast_filterindex(ah,
+			 *      mclist->dmi_addr[5]); */
+			mclist = mclist->next;
+		}
+	}
+
+	/* This is the best we can do */
+	if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))
+		rfilt |= AR5K_RX_FILTER_PHYERR;
+
+	/* FIF_BCN_PRBRESP_PROMISC really means to enable beacons
+	* and probes for any BSSID, this needs testing */
+	if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
+		rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ;
+
+	/* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not
+	 * set we should only pass on control frames for this
+	 * station. This needs testing. I believe right now this
+	 * enables *all* control frames, which is OK.. but
+	 * but we should see if we can improve on granularity */
+	if (*new_flags & FIF_CONTROL)
+		rfilt |= AR5K_RX_FILTER_CONTROL;
+
+	/* Additional settings per mode -- this is per ath5k */
+
+	/* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
+
+	if (sc->opmode == IEEE80211_IF_TYPE_MNTR)
+		rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
+			AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
+	if (sc->opmode != IEEE80211_IF_TYPE_STA)
+		rfilt |= AR5K_RX_FILTER_PROBEREQ;
+	if (sc->opmode != IEEE80211_IF_TYPE_AP &&
+		test_bit(ATH_STAT_PROMISC, sc->status))
+		rfilt |= AR5K_RX_FILTER_PROM;
+	if (sc->opmode == IEEE80211_IF_TYPE_STA ||
+		sc->opmode == IEEE80211_IF_TYPE_IBSS) {
+		rfilt |= AR5K_RX_FILTER_BEACON;
+	}
+
+	/* Set filters */
+	ath5k_hw_set_rx_filter(ah,rfilt);
+
+	/* Set multicast bits */
+	ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]);
+	/* Set the cached hw filter flags, this will alter actually
+	 * be set in HW */
+	sc->filter_flags = rfilt;
+}
+
+static int
+ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+		const u8 *local_addr, const u8 *addr,
+		struct ieee80211_key_conf *key)
+{
+	struct ath5k_softc *sc = hw->priv;
+	int ret = 0;
+
+	switch(key->alg) {
+	case ALG_WEP:
+		break;
+	case ALG_TKIP:
+	case ALG_CCMP:
+		return -EOPNOTSUPP;
+	default:
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	mutex_lock(&sc->lock);
+
+	switch (cmd) {
+	case SET_KEY:
+		ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, addr);
+		if (ret) {
+			ATH5K_ERR(sc, "can't set the key\n");
+			goto unlock;
+		}
+		__set_bit(key->keyidx, sc->keymap);
+		key->hw_key_idx = key->keyidx;
+		break;
+	case DISABLE_KEY:
+		ath5k_hw_reset_key(sc->ah, key->keyidx);
+		__clear_bit(key->keyidx, sc->keymap);
+		break;
+	default:
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+unlock:
+	mutex_unlock(&sc->lock);
+	return ret;
+}
+
+static int
+ath5k_get_stats(struct ieee80211_hw *hw,
+		struct ieee80211_low_level_stats *stats)
+{
+	struct ath5k_softc *sc = hw->priv;
+
+	memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats));
+
+	return 0;
+}
+
+static int
+ath5k_get_tx_stats(struct ieee80211_hw *hw,
+		struct ieee80211_tx_queue_stats *stats)
+{
+	struct ath5k_softc *sc = hw->priv;
+
+	memcpy(stats, &sc->tx_stats, sizeof(sc->tx_stats));
+
+	return 0;
+}
+
+static u64
+ath5k_get_tsf(struct ieee80211_hw *hw)
+{
+	struct ath5k_softc *sc = hw->priv;
+
+	return ath5k_hw_get_tsf64(sc->ah);
+}
+
+static void
+ath5k_reset_tsf(struct ieee80211_hw *hw)
+{
+	struct ath5k_softc *sc = hw->priv;
+
+	/*
+	 * in IBSS mode we need to update the beacon timers too.
+	 * this will also reset the TSF if we call it with 0
+	 */
+	if (sc->opmode == IEEE80211_IF_TYPE_IBSS)
+		ath5k_beacon_update_timers(sc, 0);
+	else
+		ath5k_hw_reset_tsf(sc->ah);
+}
+
+static int
+ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+			struct ieee80211_tx_control *ctl)
+{
+	struct ath5k_softc *sc = hw->priv;
+	int ret;
+
+	ath5k_debug_dump_skb(sc, skb, "BC  ", 1);
+
+	mutex_lock(&sc->lock);
+
+	if (sc->opmode != IEEE80211_IF_TYPE_IBSS) {
+		ret = -EIO;
+		goto end;
+	}
+
+	ath5k_txbuf_free(sc, sc->bbuf);
+	sc->bbuf->skb = skb;
+	ret = ath5k_beacon_setup(sc, sc->bbuf, ctl);
+	if (ret)
+		sc->bbuf->skb = NULL;
+	else
+		ath5k_beacon_config(sc);
+
+end:
+	mutex_unlock(&sc->lock);
+	return ret;
+}
+
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
new file mode 100644
index 000000000000..8287ae787f12
--- /dev/null
+++ b/drivers/net/wireless/ath5k/base.h
@@ -0,0 +1,179 @@
+/*-
+ * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ */
+
+/*
+ * Defintions for the Atheros Wireless LAN controller driver.
+ */
+#ifndef _DEV_ATH_ATHVAR_H
+#define _DEV_ATH_ATHVAR_H
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/wireless.h>
+#include <linux/if_ether.h>
+
+#include "ath5k.h"
+#include "debug.h"
+
+#define	ATH_RXBUF	40		/* number of RX buffers */
+#define	ATH_TXBUF	200		/* number of TX buffers */
+#define ATH_BCBUF	1		/* number of beacon buffers */
+
+struct ath5k_buf {
+	struct list_head	list;
+	unsigned int		flags;	/* tx descriptor flags */
+	struct ath5k_desc	*desc;	/* virtual addr of desc */
+	dma_addr_t		daddr;	/* physical addr of desc */
+	struct sk_buff		*skb;	/* skbuff for buf */
+	dma_addr_t		skbaddr;/* physical addr of skb data */
+	struct ieee80211_tx_control ctl;
+};
+
+/*
+ * Data transmit queue state.  One of these exists for each
+ * hardware transmit queue.  Packets sent to us from above
+ * are assigned to queues based on their priority.  Not all
+ * devices support a complete set of hardware transmit queues.
+ * For those devices the array sc_ac2q will map multiple
+ * priorities to fewer hardware queues (typically all to one
+ * hardware queue).
+ */
+struct ath5k_txq {
+	unsigned int		qnum;	/* hardware q number */
+	u32			*link;	/* link ptr in last TX desc */
+	struct list_head	q;	/* transmit queue */
+	spinlock_t		lock;	/* lock on q and link */
+	bool			setup;
+};
+
+#if CHAN_DEBUG
+#define ATH_CHAN_MAX	(26+26+26+200+200)
+#else
+#define ATH_CHAN_MAX	(14+14+14+252+20)	/* XXX what's the max? */
+#endif
+
+/* Software Carrier, keeps track of the driver state
+ * associated with an instance of a device */
+struct ath5k_softc {
+	struct pci_dev		*pdev;		/* for dma mapping */
+	void __iomem		*iobase;	/* address of the device */
+	struct mutex		lock;		/* dev-level lock */
+	struct ieee80211_tx_queue_stats tx_stats;
+	struct ieee80211_low_level_stats ll_stats;
+	struct ieee80211_hw	*hw;		/* IEEE 802.11 common */
+	struct ieee80211_hw_mode modes[NUM_DRIVER_MODES];
+	struct ieee80211_channel channels[ATH_CHAN_MAX];
+	struct ieee80211_rate	rates[AR5K_MAX_RATES * NUM_DRIVER_MODES];
+	enum ieee80211_if_types	opmode;
+	struct ath5k_hw		*ah;		/* Atheros HW */
+
+#if ATH5K_DEBUG
+	struct ath5k_dbg_info	debug;		/* debug info */
+#endif
+
+	struct ath5k_buf	*bufptr;	/* allocated buffer ptr */
+	struct ath5k_desc	*desc;		/* TX/RX descriptors */
+	dma_addr_t		desc_daddr;	/* DMA (physical) address */
+	size_t			desc_len;	/* size of TX/RX descriptors */
+	u16			cachelsz;	/* cache line size */
+
+	DECLARE_BITMAP(status, 6);
+#define ATH_STAT_INVALID	0		/* disable hardware accesses */
+#define ATH_STAT_MRRETRY	1		/* multi-rate retry support */
+#define ATH_STAT_PROMISC	2
+#define ATH_STAT_LEDBLINKING	3		/* LED blink operation active */
+#define ATH_STAT_LEDENDBLINK	4		/* finish LED blink operation */
+#define ATH_STAT_LEDSOFT	5		/* enable LED gpio status */
+
+	unsigned int		filter_flags;	/* HW flags, AR5K_RX_FILTER_* */
+	unsigned int		curmode;	/* current phy mode */
+	struct ieee80211_channel *curchan;	/* current h/w channel */
+
+	struct ieee80211_vif *vif;
+
+	struct {
+		u8	rxflags;	/* radiotap rx flags */
+		u8	txflags;	/* radiotap tx flags */
+		u16	ledon;		/* softled on time */
+		u16	ledoff;		/* softled off time */
+	} hwmap[32];				/* h/w rate ix mappings */
+
+	enum ath5k_int		imask;		/* interrupt mask copy */
+
+	DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */
+
+	u8			bssidmask[ETH_ALEN];
+
+	unsigned int		led_pin,	/* GPIO pin for driving LED */
+				led_on,		/* pin setting for LED on */
+				led_off;	/* off time for current blink */
+	struct timer_list	led_tim;	/* led off timer */
+	u8			led_rxrate;	/* current rx rate for LED */
+	u8			led_txrate;	/* current tx rate for LED */
+
+	struct tasklet_struct	restq;		/* reset tasklet */
+
+	unsigned int		rxbufsize;	/* rx size based on mtu */
+	struct list_head	rxbuf;		/* receive buffer */
+	spinlock_t		rxbuflock;
+	u32			*rxlink;	/* link ptr in last RX desc */
+	struct tasklet_struct	rxtq;		/* rx intr tasklet */
+
+	struct list_head	txbuf;		/* transmit buffer */
+	spinlock_t		txbuflock;
+	unsigned int		txbuf_len;	/* buf count in txbuf list */
+	struct ath5k_txq	txqs[2];	/* beacon and tx */
+
+	struct ath5k_txq	*txq;		/* beacon and tx*/
+	struct tasklet_struct	txtq;		/* tx intr tasklet */
+
+	struct ath5k_buf	*bbuf;		/* beacon buffer */
+	unsigned int		bhalq,		/* SW q for outgoing beacons */
+				bmisscount,	/* missed beacon transmits */
+				bintval,	/* beacon interval in TU */
+				bsent;
+	unsigned int		nexttbtt;	/* next beacon time in TU */
+
+	struct timer_list	calib_tim;	/* calibration timer */
+};
+
+#define ath5k_hw_hasbssidmask(_ah) \
+	(ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0)
+#define ath5k_hw_hasveol(_ah) \
+	(ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0)
+
+#endif
diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c
new file mode 100644
index 000000000000..4ba649e20269
--- /dev/null
+++ b/drivers/net/wireless/ath5k/debug.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 2007 Bruno Randolf <bruno@thinktube.com>
+ *
+ *  This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004-2005 Atheros Communications, Inc.
+ * Copyright (c) 2006 Devicescape Software, Inc.
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include "debug.h"
+#include "base.h"
+
+static unsigned int ath5k_debug;
+module_param_named(debug, ath5k_debug, uint, 0);
+
+
+#if ATH5K_DEBUG
+
+#include <linux/seq_file.h>
+#include "reg.h"
+
+static struct dentry *ath5k_global_debugfs;
+
+static int ath5k_debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+
+/* debugfs: registers */
+
+struct reg {
+	char *name;
+	int addr;
+};
+
+#define REG_STRUCT_INIT(r) { #r, r }
+
+/* just a few random registers, might want to add more */
+static struct reg regs[] = {
+	REG_STRUCT_INIT(AR5K_CR),
+	REG_STRUCT_INIT(AR5K_RXDP),
+	REG_STRUCT_INIT(AR5K_CFG),
+	REG_STRUCT_INIT(AR5K_IER),
+	REG_STRUCT_INIT(AR5K_BCR),
+	REG_STRUCT_INIT(AR5K_RTSD0),
+	REG_STRUCT_INIT(AR5K_RTSD1),
+	REG_STRUCT_INIT(AR5K_TXCFG),
+	REG_STRUCT_INIT(AR5K_RXCFG),
+	REG_STRUCT_INIT(AR5K_RXJLA),
+	REG_STRUCT_INIT(AR5K_MIBC),
+	REG_STRUCT_INIT(AR5K_TOPS),
+	REG_STRUCT_INIT(AR5K_RXNOFRM),
+	REG_STRUCT_INIT(AR5K_TXNOFRM),
+	REG_STRUCT_INIT(AR5K_RPGTO),
+	REG_STRUCT_INIT(AR5K_RFCNT),
+	REG_STRUCT_INIT(AR5K_MISC),
+	REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT),
+	REG_STRUCT_INIT(AR5K_ISR),
+	REG_STRUCT_INIT(AR5K_PISR),
+	REG_STRUCT_INIT(AR5K_SISR0),
+	REG_STRUCT_INIT(AR5K_SISR1),
+	REG_STRUCT_INIT(AR5K_SISR2),
+	REG_STRUCT_INIT(AR5K_SISR3),
+	REG_STRUCT_INIT(AR5K_SISR4),
+	REG_STRUCT_INIT(AR5K_IMR),
+	REG_STRUCT_INIT(AR5K_PIMR),
+	REG_STRUCT_INIT(AR5K_SIMR0),
+	REG_STRUCT_INIT(AR5K_SIMR1),
+	REG_STRUCT_INIT(AR5K_SIMR2),
+	REG_STRUCT_INIT(AR5K_SIMR3),
+	REG_STRUCT_INIT(AR5K_SIMR4),
+	REG_STRUCT_INIT(AR5K_DCM_ADDR),
+	REG_STRUCT_INIT(AR5K_DCCFG),
+	REG_STRUCT_INIT(AR5K_CCFG),
+	REG_STRUCT_INIT(AR5K_CPC0),
+	REG_STRUCT_INIT(AR5K_CPC1),
+	REG_STRUCT_INIT(AR5K_CPC2),
+	REG_STRUCT_INIT(AR5K_CPC3),
+	REG_STRUCT_INIT(AR5K_CPCORN),
+	REG_STRUCT_INIT(AR5K_RESET_CTL),
+	REG_STRUCT_INIT(AR5K_SLEEP_CTL),
+	REG_STRUCT_INIT(AR5K_INTPEND),
+	REG_STRUCT_INIT(AR5K_SFR),
+	REG_STRUCT_INIT(AR5K_PCICFG),
+	REG_STRUCT_INIT(AR5K_GPIOCR),
+	REG_STRUCT_INIT(AR5K_GPIODO),
+	REG_STRUCT_INIT(AR5K_SREV),
+};
+
+static void *reg_start(struct seq_file *seq, loff_t *pos)
+{
+	return *pos < ARRAY_SIZE(regs) ? &regs[*pos] : NULL;
+}
+
+static void reg_stop(struct seq_file *seq, void *p)
+{
+	/* nothing to do */
+}
+
+static void *reg_next(struct seq_file *seq, void *p, loff_t *pos)
+{
+	++*pos;
+	return *pos < ARRAY_SIZE(regs) ? &regs[*pos] : NULL;
+}
+
+static int reg_show(struct seq_file *seq, void *p)
+{
+	struct ath5k_softc *sc = seq->private;
+	struct reg *r = p;
+	seq_printf(seq, "%-25s0x%08x\n", r->name,
+		ath5k_hw_reg_read(sc->ah, r->addr));
+	return 0;
+}
+
+static struct seq_operations register_seq_ops = {
+	.start = reg_start,
+	.next  = reg_next,
+	.stop  = reg_stop,
+	.show  = reg_show
+};
+
+static int open_file_registers(struct inode *inode, struct file *file)
+{
+	struct seq_file *s;
+	int res;
+	res = seq_open(file, &register_seq_ops);
+	if (res == 0) {
+		s = file->private_data;
+		s->private = inode->i_private;
+	}
+	return res;
+}
+
+static const struct file_operations fops_registers = {
+	.open = open_file_registers,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release,
+	.owner = THIS_MODULE,
+};
+
+
+/* debugfs: TSF */
+
+static ssize_t read_file_tsf(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	struct ath5k_softc *sc = file->private_data;
+	char buf[100];
+	snprintf(buf, 100, "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah));
+	return simple_read_from_buffer(user_buf, count, ppos, buf, 19);
+}
+
+static ssize_t write_file_tsf(struct file *file,
+				 const char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	struct ath5k_softc *sc = file->private_data;
+	if (strncmp(userbuf, "reset", 5) == 0) {
+		ath5k_hw_reset_tsf(sc->ah);
+		printk(KERN_INFO "debugfs reset TSF\n");
+	}
+	return count;
+}
+
+static const struct file_operations fops_tsf = {
+	.read = read_file_tsf,
+	.write = write_file_tsf,
+	.open = ath5k_debugfs_open,
+	.owner = THIS_MODULE,
+};
+
+
+/* debugfs: beacons */
+
+static ssize_t read_file_beacon(struct file *file, char __user *user_buf,
+				   size_t count, loff_t *ppos)
+{
+	struct ath5k_softc *sc = file->private_data;
+	struct ath5k_hw *ah = sc->ah;
+	char buf[1000];
+	int len = 0;
+	unsigned int v;
+	u64 tsf;
+
+	v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON);
+	len += snprintf(buf+len, sizeof(buf)-len,
+		"%-24s0x%08x\tintval: %d\tTIM: 0x%x\n",
+		"AR5K_BEACON", v, v & AR5K_BEACON_PERIOD,
+		(v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S);
+
+	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n",
+		"AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP));
+
+	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n",
+		"AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT));
+
+	v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0);
+	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+		"AR5K_TIMER0 (TBTT)", v, v);
+
+	v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1);
+	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+		"AR5K_TIMER1 (DMA)", v, v >> 3);
+
+	v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2);
+	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+		"AR5K_TIMER2 (SWBA)", v, v >> 3);
+
+	v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3);
+	len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n",
+		"AR5K_TIMER3 (ATIM)", v, v);
+
+	tsf = ath5k_hw_get_tsf64(sc->ah);
+	len += snprintf(buf+len, sizeof(buf)-len,
+		"TSF\t\t0x%016llx\tTU: %08x\n", tsf, TSF_TO_TU(tsf));
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_beacon(struct file *file,
+				 const char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	struct ath5k_softc *sc = file->private_data;
+	struct ath5k_hw *ah = sc->ah;
+
+	if (strncmp(userbuf, "disable", 7) == 0) {
+		AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
+		printk(KERN_INFO "debugfs disable beacons\n");
+	} else if (strncmp(userbuf, "enable", 6) == 0) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE);
+		printk(KERN_INFO "debugfs enable beacons\n");
+	}
+	return count;
+}
+
+static const struct file_operations fops_beacon = {
+	.read = read_file_beacon,
+	.write = write_file_beacon,
+	.open = ath5k_debugfs_open,
+	.owner = THIS_MODULE,
+};
+
+
+/* debugfs: reset */
+
+static ssize_t write_file_reset(struct file *file,
+				 const char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	struct ath5k_softc *sc = file->private_data;
+	tasklet_schedule(&sc->restq);
+	return count;
+}
+
+static const struct file_operations fops_reset = {
+	.write = write_file_reset,
+	.open = ath5k_debugfs_open,
+	.owner = THIS_MODULE,
+};
+
+
+/* init */
+
+void
+ath5k_debug_init(void)
+{
+	ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL);
+}
+
+void
+ath5k_debug_init_device(struct ath5k_softc *sc)
+{
+	sc->debug.level = ath5k_debug;
+	sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
+			ath5k_global_debugfs);
+	sc->debug.debugfs_debug = debugfs_create_u32("debug",
+			0666, sc->debug.debugfs_phydir, &sc->debug.level);
+
+	sc->debug.debugfs_registers = debugfs_create_file("registers", 0444,
+				sc->debug.debugfs_phydir,
+				sc, &fops_registers);
+
+	sc->debug.debugfs_tsf = debugfs_create_file("tsf", 0666,
+				sc->debug.debugfs_phydir,
+				sc, &fops_tsf);
+
+	sc->debug.debugfs_beacon = debugfs_create_file("beacon", 0666,
+				sc->debug.debugfs_phydir,
+				sc, &fops_beacon);
+
+	sc->debug.debugfs_reset = debugfs_create_file("reset", 0222,
+				sc->debug.debugfs_phydir,
+				sc, &fops_reset);
+}
+
+void
+ath5k_debug_finish(void)
+{
+	debugfs_remove(ath5k_global_debugfs);
+}
+
+void
+ath5k_debug_finish_device(struct ath5k_softc *sc)
+{
+	debugfs_remove(sc->debug.debugfs_debug);
+	debugfs_remove(sc->debug.debugfs_registers);
+	debugfs_remove(sc->debug.debugfs_tsf);
+	debugfs_remove(sc->debug.debugfs_beacon);
+	debugfs_remove(sc->debug.debugfs_reset);
+	debugfs_remove(sc->debug.debugfs_phydir);
+}
+
+
+/* functions used in other places */
+
+void
+ath5k_debug_dump_modes(struct ath5k_softc *sc, struct ieee80211_hw_mode *modes)
+{
+	unsigned int m, i;
+
+	if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPMODES)))
+		return;
+
+	for (m = 0; m < NUM_DRIVER_MODES; m++) {
+		printk(KERN_DEBUG "Mode %u: channels %d, rates %d\n", m,
+				modes[m].num_channels, modes[m].num_rates);
+		printk(KERN_DEBUG " channels:\n");
+		for (i = 0; i < modes[m].num_channels; i++)
+			printk(KERN_DEBUG "  %3d %d %.4x %.4x\n",
+					modes[m].channels[i].chan,
+					modes[m].channels[i].freq,
+					modes[m].channels[i].val,
+					modes[m].channels[i].flag);
+		printk(KERN_DEBUG " rates:\n");
+		for (i = 0; i < modes[m].num_rates; i++)
+			printk(KERN_DEBUG "  %4d %.4x %.4x %.4x\n",
+					modes[m].rates[i].rate,
+					modes[m].rates[i].val,
+					modes[m].rates[i].flags,
+					modes[m].rates[i].val2);
+	}
+}
+
+static inline void
+ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done)
+{
+	struct ath5k_desc *ds = bf->desc;
+
+	printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n",
+		ds, (unsigned long long)bf->daddr,
+		ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1,
+		ds->ds_hw[0], ds->ds_hw[1],
+		!done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!');
+}
+
+void
+ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah)
+{
+	struct ath5k_desc *ds;
+	struct ath5k_buf *bf;
+	int status;
+
+	if (likely(!(sc->debug.level &
+	    (ATH5K_DEBUG_RESET | ATH5K_DEBUG_FATAL))))
+		return;
+
+	printk(KERN_DEBUG "rx queue %x, link %p\n",
+		ath5k_hw_get_rx_buf(ah), sc->rxlink);
+
+	spin_lock_bh(&sc->rxbuflock);
+	list_for_each_entry(bf, &sc->rxbuf, list) {
+		ds = bf->desc;
+		status = ah->ah_proc_rx_desc(ah, ds);
+		if (!status || (sc->debug.level & ATH5K_DEBUG_FATAL))
+			ath5k_debug_printrxbuf(bf, status == 0);
+	}
+	spin_unlock_bh(&sc->rxbuflock);
+}
+
+void
+ath5k_debug_dump_skb(struct ath5k_softc *sc,
+			struct sk_buff *skb, const char *prefix, int tx)
+{
+	char buf[16];
+
+	if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) ||
+		     (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX)))))
+		return;
+
+	snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix);
+
+	print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data,
+		min(200U, skb->len));
+
+	printk(KERN_DEBUG "\n");
+}
+
+void
+ath5k_debug_printtxbuf(struct ath5k_softc *sc,
+			struct ath5k_buf *bf, int done)
+{
+	struct ath5k_desc *ds = bf->desc;
+
+	if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET)))
+		return;
+
+	printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x "
+		"%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link,
+		ds->ds_data, ds->ds_ctl0, ds->ds_ctl1,
+		ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3],
+		!done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!');
+}
+
+#endif /* if ATH5K_DEBUG */
diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath5k/debug.h
new file mode 100644
index 000000000000..2b491cbc8c80
--- /dev/null
+++ b/drivers/net/wireless/ath5k/debug.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2007 Bruno Randolf <bruno@thinktube.com>
+ *
+ *  This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004-2005 Atheros Communications, Inc.
+ * Copyright (c) 2006 Devicescape Software, Inc.
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef _ATH5K_DEBUG_H
+#define _ATH5K_DEBUG_H
+
+/* set this to 1 for debugging output */
+#ifndef ATH5K_DEBUG
+#define ATH5K_DEBUG	0
+#endif
+
+struct ath5k_softc;
+struct ath5k_hw;
+struct ieee80211_hw_mode;
+struct sk_buff;
+struct ath5k_buf;
+
+struct ath5k_dbg_info {
+	unsigned int		level;		/* debug level */
+	/* debugfs entries */
+	struct dentry		*debugfs_phydir;
+	struct dentry		*debugfs_debug;
+	struct dentry		*debugfs_registers;
+	struct dentry		*debugfs_tsf;
+	struct dentry		*debugfs_beacon;
+	struct dentry		*debugfs_reset;
+};
+
+/**
+ * enum ath5k_debug_level - ath5k debug level
+ *
+ * @ATH5K_DEBUG_RESET: reset processing
+ * @ATH5K_DEBUG_INTR: interrupt handling
+ * @ATH5K_DEBUG_MODE: mode init/setup
+ * @ATH5K_DEBUG_XMIT: basic xmit operation
+ * @ATH5K_DEBUG_BEACON: beacon handling
+ * @ATH5K_DEBUG_BEACON_PROC: beacon ISR proc
+ * @ATH5K_DEBUG_CALIBRATE: periodic calibration
+ * @ATH5K_DEBUG_TXPOWER: transmit power setting
+ * @ATH5K_DEBUG_LED: led management
+ * @ATH5K_DEBUG_DUMP_RX: print received skb content
+ * @ATH5K_DEBUG_DUMP_TX: print transmit skb content
+ * @ATH5K_DEBUG_DUMPMODES: dump modes
+ * @ATH5K_DEBUG_TRACE: trace function calls
+ * @ATH5K_DEBUG_FATAL: fatal errors
+ * @ATH5K_DEBUG_ANY: show at any debug level
+ *
+ * The debug level is used to control the amount and type of debugging output
+ * we want to see. The debug level is given in calls to ATH5K_DBG to specify
+ * where the message should appear, and the user can control the debugging
+ * messages he wants to see, either by the module parameter 'debug' on module
+ * load, or dynamically by using debugfs 'ath5k/phyX/debug'. these levels can
+ * be combined together by bitwise OR.
+ */
+enum ath5k_debug_level {
+	ATH5K_DEBUG_RESET	= 0x00000001,
+	ATH5K_DEBUG_INTR	= 0x00000002,
+	ATH5K_DEBUG_MODE	= 0x00000004,
+	ATH5K_DEBUG_XMIT	= 0x00000008,
+	ATH5K_DEBUG_BEACON	= 0x00000010,
+	ATH5K_DEBUG_BEACON_PROC	= 0x00000020,
+	ATH5K_DEBUG_CALIBRATE	= 0x00000100,
+	ATH5K_DEBUG_TXPOWER	= 0x00000200,
+	ATH5K_DEBUG_LED		= 0x00000400,
+	ATH5K_DEBUG_DUMP_RX	= 0x00001000,
+	ATH5K_DEBUG_DUMP_TX	= 0x00002000,
+	ATH5K_DEBUG_DUMPMODES	= 0x00004000,
+	ATH5K_DEBUG_TRACE	= 0x00010000,
+	ATH5K_DEBUG_FATAL	= 0x80000000,
+	ATH5K_DEBUG_ANY		= 0xffffffff
+};
+
+#if ATH5K_DEBUG
+
+#define ATH5K_TRACE(_sc) do { \
+	if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \
+		printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \
+	} while (0)
+
+#define ATH5K_DBG(_sc, _m, _fmt, ...) do { \
+	if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \
+		ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \
+			__func__, __LINE__, ##__VA_ARGS__); \
+	} while (0)
+
+#define ATH5K_DBG_UNLIMIT(_sc, _m, _fmt, ...) do { \
+	if (unlikely((_sc)->debug.level & (_m))) \
+		ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \
+			__func__, __LINE__, ##__VA_ARGS__); \
+	} while (0)
+
+void
+ath5k_debug_init(void);
+
+void
+ath5k_debug_init_device(struct ath5k_softc *sc);
+
+void
+ath5k_debug_finish(void);
+
+void
+ath5k_debug_finish_device(struct ath5k_softc *sc);
+
+void
+ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah);
+
+void
+ath5k_debug_dump_modes(struct ath5k_softc *sc,
+			struct ieee80211_hw_mode *modes);
+
+void
+ath5k_debug_dump_skb(struct ath5k_softc *sc,
+			struct sk_buff *skb, const char *prefix, int tx);
+
+void
+ath5k_debug_printtxbuf(struct ath5k_softc *sc,
+			struct ath5k_buf *bf, int done);
+
+#else /* no debugging */
+
+#define ATH5K_TRACE(_sc) /* empty */
+
+static inline void __attribute__ ((format (printf, 3, 4)))
+ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {}
+
+static inline void __attribute__ ((format (printf, 3, 4)))
+ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...)
+{}
+
+static inline void
+ath5k_debug_init(void) {}
+
+static inline void
+ath5k_debug_init_device(struct ath5k_softc *sc) {}
+
+static inline void
+ath5k_debug_finish(void) {}
+
+static inline void
+ath5k_debug_finish_device(struct ath5k_softc *sc) {}
+
+static inline void
+ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {}
+
+static inline void
+ath5k_debug_dump_modes(struct ath5k_softc *sc,
+			struct ieee80211_hw_mode *modes) {}
+
+static inline void
+ath5k_debug_dump_skb(struct ath5k_softc *sc,
+			struct sk_buff *skb, const char *prefix, int tx) {}
+
+static inline void
+ath5k_debug_printtxbuf(struct ath5k_softc *sc,
+			struct ath5k_buf *bf, int done) {}
+
+#endif /* if ATH5K_DEBUG */
+
+#endif /* ifndef _ATH5K_DEBUG_H */
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c
new file mode 100644
index 000000000000..3a4bf4035a23
--- /dev/null
+++ b/drivers/net/wireless/ath5k/hw.c
@@ -0,0 +1,4351 @@
+ /*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007 Matthew W. S. Bell  <mentor@madwifi.org>
+ * Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
+ * Copyright (c) 2007 Pavel Roskin <proski@gnu.org>
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * HW related functions for Atheros Wireless LAN devices.
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "reg.h"
+#include "base.h"
+#include "debug.h"
+
+/*Rate tables*/
+static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A;
+static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B;
+static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G;
+static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO;
+static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR;
+
+/*Prototypes*/
+static int ath5k_hw_nic_reset(struct ath5k_hw *, u32);
+static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool);
+static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
+	unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
+	unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
+	unsigned int, unsigned int);
+static bool ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
+	unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
+	unsigned int);
+static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *);
+static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *,
+	unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
+	unsigned int, unsigned int, unsigned int, unsigned int, unsigned int,
+	unsigned int, unsigned int);
+static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *);
+static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *, struct ath5k_desc *);
+static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *, struct ath5k_desc *);
+static int ath5k_hw_get_capabilities(struct ath5k_hw *);
+
+static int ath5k_eeprom_init(struct ath5k_hw *);
+static int ath5k_eeprom_read_mac(struct ath5k_hw *, u8 *);
+
+static int ath5k_hw_enable_pspoll(struct ath5k_hw *, u8 *, u16);
+static int ath5k_hw_disable_pspoll(struct ath5k_hw *);
+
+/*
+ * Enable to overwrite the country code (use "00" for debug)
+ */
+#if 0
+#define COUNTRYCODE "00"
+#endif
+
+/*******************\
+  General Functions
+\*******************/
+
+/*
+ * Functions used internaly
+ */
+
+static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo)
+{
+	return turbo == true ? (usec * 80) : (usec * 40);
+}
+
+static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo)
+{
+	return turbo == true ? (clock / 80) : (clock / 40);
+}
+
+/*
+ * Check if a register write has been completed
+ */
+int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
+		bool is_set)
+{
+	int i;
+	u32 data;
+
+	for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
+		data = ath5k_hw_reg_read(ah, reg);
+		if ((is_set == true) && (data & flag))
+			break;
+		else if ((data & flag) == val)
+			break;
+		udelay(15);
+	}
+
+	return (i <= 0) ? -EAGAIN : 0;
+}
+
+
+/***************************************\
+	Attach/Detach Functions
+\***************************************/
+
+/*
+ * Check if the device is supported and initialize the needed structs
+ */
+struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
+{
+	struct ath5k_hw *ah;
+	u8 mac[ETH_ALEN];
+	int ret;
+	u32 srev;
+
+	/*If we passed the test malloc a ath5k_hw struct*/
+	ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
+	if (ah == NULL) {
+		ret = -ENOMEM;
+		ATH5K_ERR(sc, "out of memory\n");
+		goto err;
+	}
+
+	ah->ah_sc = sc;
+	ah->ah_iobase = sc->iobase;
+
+	/*
+	 * HW information
+	 */
+
+	/* Get reg domain from eeprom */
+	ath5k_get_regdomain(ah);
+
+	ah->ah_op_mode = IEEE80211_IF_TYPE_STA;
+	ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
+	ah->ah_turbo = false;
+	ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
+	ah->ah_imr = 0;
+	ah->ah_atim_window = 0;
+	ah->ah_aifs = AR5K_TUNE_AIFS;
+	ah->ah_cw_min = AR5K_TUNE_CWMIN;
+	ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
+	ah->ah_software_retry = false;
+	ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY;
+
+	/*
+	 * Set the mac revision based on the pci id
+	 */
+	ah->ah_version = mac_version;
+
+	/*Fill the ath5k_hw struct with the needed functions*/
+	if (ah->ah_version == AR5K_AR5212)
+		ah->ah_magic = AR5K_EEPROM_MAGIC_5212;
+	else if (ah->ah_version == AR5K_AR5211)
+		ah->ah_magic = AR5K_EEPROM_MAGIC_5211;
+
+	if (ah->ah_version == AR5K_AR5212) {
+		ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
+		ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc;
+		ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status;
+	} else {
+		ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc;
+		ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc;
+		ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status;
+	}
+
+	if (ah->ah_version == AR5K_AR5212)
+		ah->ah_proc_rx_desc = ath5k_hw_proc_new_rx_status;
+	else if (ah->ah_version <= AR5K_AR5211)
+		ah->ah_proc_rx_desc = ath5k_hw_proc_old_rx_status;
+
+	/* Bring device out of sleep and reset it's units */
+	ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true);
+	if (ret)
+		goto err_free;
+
+	/* Get MAC, PHY and RADIO revisions */
+	srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+	ah->ah_mac_srev = srev;
+	ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
+	ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
+	ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
+			0xffffffff;
+	ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
+			CHANNEL_5GHZ);
+
+	if (ah->ah_version == AR5K_AR5210)
+		ah->ah_radio_2ghz_revision = 0;
+	else
+		ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah,
+				CHANNEL_2GHZ);
+
+	/* Return on unsuported chips (unsupported eeprom etc) */
+	if(srev >= AR5K_SREV_VER_AR5416){
+		ATH5K_ERR(sc, "Device not yet supported.\n");
+		ret = -ENODEV;
+		goto err_free;
+	}
+
+	/* Identify single chip solutions */
+	if((srev <= AR5K_SREV_VER_AR5414) &&
+	(srev >= AR5K_SREV_VER_AR2424)) {
+		ah->ah_single_chip = true;
+	} else {
+		ah->ah_single_chip = false;
+	}
+
+	/* Single chip radio */
+	if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision)
+		ah->ah_radio_2ghz_revision = 0;
+
+	/* Identify the radio chip*/
+	if (ah->ah_version == AR5K_AR5210) {
+		ah->ah_radio = AR5K_RF5110;
+	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) {
+		ah->ah_radio = AR5K_RF5111;
+	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
+		ah->ah_radio = AR5K_RF5112;
+	} else {
+		ah->ah_radio = AR5K_RF5413;
+	}
+
+	ah->ah_phy = AR5K_PHY(0);
+
+	/*
+	 * Get card capabilities, values, ...
+	 */
+
+	ret = ath5k_eeprom_init(ah);
+	if (ret) {
+		ATH5K_ERR(sc, "unable to init EEPROM\n");
+		goto err_free;
+	}
+
+	/* Get misc capabilities */
+	ret = ath5k_hw_get_capabilities(ah);
+	if (ret) {
+		ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n",
+			sc->pdev->device);
+		goto err_free;
+	}
+
+	/* Get MAC address */
+	ret = ath5k_eeprom_read_mac(ah, mac);
+	if (ret) {
+		ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
+			sc->pdev->device);
+		goto err_free;
+	}
+
+	ath5k_hw_set_lladdr(ah, mac);
+	/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
+	memset(ah->ah_bssid, 0xff, ETH_ALEN);
+	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+	ath5k_hw_set_opmode(ah);
+
+	ath5k_hw_set_rfgain_opt(ah);
+
+	return ah;
+err_free:
+	kfree(ah);
+err:
+	return ERR_PTR(ret);
+}
+
+/*
+ * Bring up MAC + PHY Chips
+ */
+static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
+{
+	u32 turbo, mode, clock;
+	int ret;
+
+	turbo = 0;
+	mode = 0;
+	clock = 0;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* Wakeup the device */
+	ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+	if (ret) {
+		ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
+		return ret;
+	}
+
+	if (ah->ah_version != AR5K_AR5210) {
+		/*
+		 * Get channel mode flags
+		 */
+
+		if (ah->ah_radio >= AR5K_RF5112) {
+			mode = AR5K_PHY_MODE_RAD_RF5112;
+			clock = AR5K_PHY_PLL_RF5112;
+		} else {
+			mode = AR5K_PHY_MODE_RAD_RF5111;	/*Zero*/
+			clock = AR5K_PHY_PLL_RF5111;		/*Zero*/
+		}
+
+		if (flags & CHANNEL_2GHZ) {
+			mode |= AR5K_PHY_MODE_FREQ_2GHZ;
+			clock |= AR5K_PHY_PLL_44MHZ;
+
+			if (flags & CHANNEL_CCK) {
+				mode |= AR5K_PHY_MODE_MOD_CCK;
+			} else if (flags & CHANNEL_OFDM) {
+				/* XXX Dynamic OFDM/CCK is not supported by the
+				 * AR5211 so we set MOD_OFDM for plain g (no
+				 * CCK headers) operation. We need to test
+				 * this, 5211 might support ofdm-only g after
+				 * all, there are also initial register values
+				 * in the code for g mode (see initvals.c). */
+				if (ah->ah_version == AR5K_AR5211)
+					mode |= AR5K_PHY_MODE_MOD_OFDM;
+				else
+					mode |= AR5K_PHY_MODE_MOD_DYN;
+			} else {
+				ATH5K_ERR(ah->ah_sc,
+					"invalid radio modulation mode\n");
+				return -EINVAL;
+			}
+		} else if (flags & CHANNEL_5GHZ) {
+			mode |= AR5K_PHY_MODE_FREQ_5GHZ;
+			clock |= AR5K_PHY_PLL_40MHZ;
+
+			if (flags & CHANNEL_OFDM)
+				mode |= AR5K_PHY_MODE_MOD_OFDM;
+			else {
+				ATH5K_ERR(ah->ah_sc,
+					"invalid radio modulation mode\n");
+				return -EINVAL;
+			}
+		} else {
+			ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n");
+			return -EINVAL;
+		}
+
+		if (flags & CHANNEL_TURBO)
+			turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
+	} else { /* Reset the device */
+
+		/* ...enable Atheros turbo mode if requested */
+		if (flags & CHANNEL_TURBO)
+			ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
+					AR5K_PHY_TURBO);
+	}
+
+	/* ...reset chipset and PCI device */
+	if (ah->ah_single_chip == false && ath5k_hw_nic_reset(ah,
+				AR5K_RESET_CTL_CHIP | AR5K_RESET_CTL_PCI)) {
+		ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip + PCI\n");
+		return -EIO;
+	}
+
+	if (ah->ah_version == AR5K_AR5210)
+		udelay(2300);
+
+	/* ...wakeup again!*/
+	ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+	if (ret) {
+		ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
+		return ret;
+	}
+
+	/* ...final warm reset */
+	if (ath5k_hw_nic_reset(ah, 0)) {
+		ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
+		return -EIO;
+	}
+
+	if (ah->ah_version != AR5K_AR5210) {
+		/* ...set the PHY operating mode */
+		ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL);
+		udelay(300);
+
+		ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE);
+		ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO);
+	}
+
+	return 0;
+}
+
+/*
+ * Get the rate table for a specific operation mode
+ */
+const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah,
+		unsigned int mode)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (!test_bit(mode, ah->ah_capabilities.cap_mode))
+		return NULL;
+
+	/* Get rate tables */
+	switch (mode) {
+	case MODE_IEEE80211A:
+		return &ath5k_rt_11a;
+	case MODE_ATHEROS_TURBO:
+		return &ath5k_rt_turbo;
+	case MODE_IEEE80211B:
+		return &ath5k_rt_11b;
+	case MODE_IEEE80211G:
+		return &ath5k_rt_11g;
+	case MODE_ATHEROS_TURBOG:
+		return &ath5k_rt_xr;
+	}
+
+	return NULL;
+}
+
+/*
+ * Free the ath5k_hw struct
+ */
+void ath5k_hw_detach(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (ah->ah_rf_banks != NULL)
+		kfree(ah->ah_rf_banks);
+
+	/* assume interrupts are down */
+	kfree(ah);
+}
+
+/****************************\
+  Reset function and helpers
+\****************************/
+
+/**
+ * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
+ *
+ * @ah: the &struct ath5k_hw
+ * @channel: the currently set channel upon reset
+ *
+ * Write the OFDM timings for the AR5212 upon reset. This is a helper for
+ * ath5k_hw_reset(). This seems to tune the PLL a specified frequency
+ * depending on the bandwidth of the channel.
+ *
+ */
+static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
+	struct ieee80211_channel *channel)
+{
+	/* Get exponent and mantissa and set it */
+	u32 coef_scaled, coef_exp, coef_man,
+		ds_coef_exp, ds_coef_man, clock;
+
+	if (!(ah->ah_version == AR5K_AR5212) ||
+		!(channel->val & CHANNEL_OFDM))
+		BUG();
+
+	/* Seems there are two PLLs, one for baseband sampling and one
+	 * for tuning. Tuning basebands are 40 MHz or 80MHz when in
+	 * turbo. */
+	clock = channel->val & CHANNEL_TURBO ? 80 : 40;
+	coef_scaled = ((5 * (clock << 24)) / 2) /
+	channel->freq;
+
+	for (coef_exp = 31; coef_exp > 0; coef_exp--)
+		if ((coef_scaled >> coef_exp) & 0x1)
+			break;
+
+	if (!coef_exp)
+		return -EINVAL;
+
+	coef_exp = 14 - (coef_exp - 24);
+	coef_man = coef_scaled +
+		(1 << (24 - coef_exp - 1));
+	ds_coef_man = coef_man >> (24 - coef_exp);
+	ds_coef_exp = coef_exp - 16;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+		AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+		AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
+
+	return 0;
+}
+
+/**
+ * ath5k_hw_write_rate_duration - set rate duration during hw resets
+ *
+ * @ah: the &struct ath5k_hw
+ * @driver_mode: one of enum ieee80211_phymode or our one of our own
+ *     vendor modes
+ *
+ * Write the rate duration table for the current mode upon hw reset. This
+ * is a helper for ath5k_hw_reset(). It seems all this is doing is setting
+ * an ACK timeout for the hardware for the current mode for each rate. The
+ * rates which are capable of short preamble (802.11b rates 2Mbps, 5.5Mbps,
+ * and 11Mbps) have another register for the short preamble ACK timeout
+ * calculation.
+ *
+ */
+static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
+       unsigned int driver_mode)
+{
+	struct ath5k_softc *sc = ah->ah_sc;
+	const struct ath5k_rate_table *rt;
+	unsigned int i;
+
+	/* Get rate table for the current operating mode */
+	rt = ath5k_hw_get_rate_table(ah,
+		driver_mode);
+
+	/* Write rate duration table */
+	for (i = 0; i < rt->rate_count; i++) {
+		const struct ath5k_rate *rate, *control_rate;
+		u32 reg;
+		u16 tx_time;
+
+		rate = &rt->rates[i];
+		control_rate = &rt->rates[rate->control_rate];
+
+		/* Set ACK timeout */
+		reg = AR5K_RATE_DUR(rate->rate_code);
+
+		/* An ACK frame consists of 10 bytes. If you add the FCS,
+		 * which ieee80211_generic_frame_duration() adds,
+		 * its 14 bytes. Note we use the control rate and not the
+		 * actual rate for this rate. See mac80211 tx.c
+		 * ieee80211_duration() for a brief description of
+		 * what rate we should choose to TX ACKs. */
+		tx_time = ieee80211_generic_frame_duration(sc->hw,
+			sc->vif, 10, control_rate->rate_kbps/100);
+
+		ath5k_hw_reg_write(ah, tx_time, reg);
+
+		if (!HAS_SHPREAMBLE(i))
+			continue;
+
+		/*
+		 * We're not distinguishing short preamble here,
+		 * This is true, all we'll get is a longer value here
+		 * which is not necessarilly bad. We could use
+		 * export ieee80211_frame_duration() but that needs to be
+		 * fixed first to be properly used by mac802111 drivers:
+		 *
+		 *  - remove erp stuff and let the routine figure ofdm
+		 *    erp rates
+		 *  - remove passing argument ieee80211_local as
+		 *    drivers don't have access to it
+		 *  - move drivers using ieee80211_generic_frame_duration()
+		 *    to this
+		 */
+		ath5k_hw_reg_write(ah, tx_time,
+			reg + (AR5K_SET_SHORT_PREAMBLE << 2));
+	}
+}
+
+/*
+ * Main reset function
+ */
+int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
+	struct ieee80211_channel *channel, bool change_channel)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 data, s_seq, s_ant, s_led[3];
+	unsigned int i, mode, freq, ee_mode, ant[2], driver_mode = -1;
+	int ret;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	s_seq = 0;
+	s_ant = 0;
+	ee_mode = 0;
+	freq = 0;
+	mode = 0;
+
+	/*
+	 * Save some registers before a reset
+	 */
+	/*DCU/Antenna selection not available on 5210*/
+	if (ah->ah_version != AR5K_AR5210) {
+		if (change_channel == true) {
+			/* Seq number for queue 0 -do this for all queues ? */
+			s_seq = ath5k_hw_reg_read(ah,
+					AR5K_QUEUE_DFS_SEQNUM(0));
+			/*Default antenna*/
+			s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+		}
+	}
+
+	/*GPIOs*/
+	s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE;
+	s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
+	s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+	if (change_channel == true && ah->ah_rf_banks != NULL)
+		ath5k_hw_get_rf_gain(ah);
+
+
+	/*Wakeup the device*/
+	ret = ath5k_hw_nic_wakeup(ah, channel->val, false);
+	if (ret)
+		return ret;
+
+	/*
+	 * Initialize operating mode
+	 */
+	ah->ah_op_mode = op_mode;
+
+	/*
+	 * 5111/5112 Settings
+	 * 5210 only comes with RF5110
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		if (ah->ah_radio != AR5K_RF5111 &&
+			ah->ah_radio != AR5K_RF5112 &&
+			ah->ah_radio != AR5K_RF5413) {
+			ATH5K_ERR(ah->ah_sc,
+				"invalid phy radio: %u\n", ah->ah_radio);
+			return -EINVAL;
+		}
+
+		switch (channel->val & CHANNEL_MODES) {
+		case CHANNEL_A:
+			mode = AR5K_INI_VAL_11A;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			driver_mode = MODE_IEEE80211A;
+			break;
+		case CHANNEL_G:
+			mode = AR5K_INI_VAL_11G;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11G;
+			driver_mode = MODE_IEEE80211G;
+			break;
+		case CHANNEL_B:
+			mode = AR5K_INI_VAL_11B;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11B;
+			driver_mode = MODE_IEEE80211B;
+			break;
+		case CHANNEL_T:
+			mode = AR5K_INI_VAL_11A_TURBO;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			driver_mode = MODE_ATHEROS_TURBO;
+			break;
+		/*Is this ok on 5211 too ?*/
+		case CHANNEL_TG:
+			mode = AR5K_INI_VAL_11G_TURBO;
+			freq = AR5K_INI_RFGAIN_2GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11G;
+			driver_mode = MODE_ATHEROS_TURBOG;
+			break;
+		case CHANNEL_XR:
+			if (ah->ah_version == AR5K_AR5211) {
+				ATH5K_ERR(ah->ah_sc,
+					"XR mode not available on 5211");
+				return -EINVAL;
+			}
+			mode = AR5K_INI_VAL_XR;
+			freq = AR5K_INI_RFGAIN_5GHZ;
+			ee_mode = AR5K_EEPROM_MODE_11A;
+			driver_mode = MODE_IEEE80211A;
+			break;
+		default:
+			ATH5K_ERR(ah->ah_sc,
+				"invalid channel: %d\n", channel->freq);
+			return -EINVAL;
+		}
+
+		/* PHY access enable */
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+
+	}
+
+	ret = ath5k_hw_write_initvals(ah, mode, change_channel);
+	if (ret)
+		return ret;
+
+	/*
+	 * 5211/5212 Specific
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		/*
+		 * Write initial RF gain settings
+		 * This should work for both 5111/5112
+		 */
+		ret = ath5k_hw_rfgain(ah, freq);
+		if (ret)
+			return ret;
+
+		mdelay(1);
+
+		/*
+		 * Write some more initial register settings
+		 */
+		if (ah->ah_version > AR5K_AR5211){ /* found on 5213+ */
+			ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11));
+
+			if (channel->val == CHANNEL_G)
+				ath5k_hw_reg_write(ah, 0x00f80d80, AR5K_PHY(83)); /* 0x00fc0ec0 */
+			else
+				ath5k_hw_reg_write(ah, 0x00000000, AR5K_PHY(83));
+
+			ath5k_hw_reg_write(ah, 0x000001b5, 0xa228); /* 0x000009b5 */
+			ath5k_hw_reg_write(ah, 0x000009b5, 0xa228);
+			ath5k_hw_reg_write(ah, 0x0000000f, 0x8060);
+			ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
+			ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL);
+		}
+
+		/* Fix for first revision of the RF5112 RF chipset */
+		if (ah->ah_radio >= AR5K_RF5112 &&
+				ah->ah_radio_5ghz_revision <
+				AR5K_SREV_RAD_5112A) {
+			ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD,
+					AR5K_PHY_CCKTXCTL);
+			if (channel->val & CHANNEL_5GHZ)
+				data = 0xffb81020;
+			else
+				data = 0xffb80d20;
+			ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
+		}
+
+		/*
+		 * Set TX power (FIXME)
+		 */
+		ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER);
+		if (ret)
+			return ret;
+
+		/* Write rate duration table only on AR5212 and if
+		 * virtual interface has already been brought up
+		 * XXX: rethink this after new mode changes to
+		 * mac80211 are integrated */
+		if (ah->ah_version == AR5K_AR5212 &&
+			ah->ah_sc->vif != NULL)
+			ath5k_hw_write_rate_duration(ah, driver_mode);
+
+		/*
+		 * Write RF registers
+		 * TODO:Does this work on 5211 (5111) ?
+		 */
+		ret = ath5k_hw_rfregs(ah, channel, mode);
+		if (ret)
+			return ret;
+
+		/*
+		 * Configure additional registers
+		 */
+
+		/* Write OFDM timings on 5212*/
+		if (ah->ah_version == AR5K_AR5212 &&
+			channel->val & CHANNEL_OFDM) {
+			ret = ath5k_hw_write_ofdm_timings(ah, channel);
+			if (ret)
+				return ret;
+		}
+
+		/*Enable/disable 802.11b mode on 5111
+		(enable 2111 frequency converter + CCK)*/
+		if (ah->ah_radio == AR5K_RF5111) {
+			if (driver_mode == MODE_IEEE80211B)
+				AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
+				    AR5K_TXCFG_B_MODE);
+			else
+				AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+				    AR5K_TXCFG_B_MODE);
+		}
+
+		/*
+		 * Set channel and calibrate the PHY
+		 */
+		ret = ath5k_hw_channel(ah, channel);
+		if (ret)
+			return ret;
+
+		/* Set antenna mode */
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x44),
+			ah->ah_antenna[ee_mode][0], 0xfffffc06);
+
+		/*
+		 * In case a fixed antenna was set as default
+		 * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE
+		 * registers.
+		 */
+		if (s_ant != 0){
+			if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */
+				ant[0] = ant[1] = AR5K_ANT_FIXED_A;
+			else	/* 2 - Aux */
+				ant[0] = ant[1] = AR5K_ANT_FIXED_B;
+		} else {
+			ant[0] = AR5K_ANT_FIXED_A;
+			ant[1] = AR5K_ANT_FIXED_B;
+		}
+
+		ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]],
+			AR5K_PHY_ANT_SWITCH_TABLE_0);
+		ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]],
+			AR5K_PHY_ANT_SWITCH_TABLE_1);
+
+		/* Commit values from EEPROM */
+		if (ah->ah_radio == AR5K_RF5111)
+			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
+			    AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip);
+
+		ath5k_hw_reg_write(ah,
+			AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
+			AR5K_PHY(0x5a));
+
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x11),
+			(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
+			0xffffc07f);
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x12),
+			(ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
+			0xfffc0fff);
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x14),
+			(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
+			((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00),
+			0xffff0000);
+
+		ath5k_hw_reg_write(ah,
+			(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
+			(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
+			(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
+			(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY(0x0d));
+
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x0a),
+			ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x19),
+			(ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x49), 4, 0xffffff01);
+
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+		    AR5K_PHY_IQ_CORR_ENABLE |
+		    (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) |
+		    ee->ee_q_cal[ee_mode]);
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ,
+				AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX,
+				ee->ee_margin_tx_rx[ee_mode]);
+
+	} else {
+		mdelay(1);
+		/* Disable phy and wait */
+		ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+		mdelay(1);
+	}
+
+	/*
+	 * Restore saved values
+	 */
+	/*DCU/Antenna selection not available on 5210*/
+	if (ah->ah_version != AR5K_AR5210) {
+		ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0));
+		ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA);
+	}
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]);
+	ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
+	ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
+
+	/*
+	 * Misc
+	 */
+	/* XXX: add ah->aid once mac80211 gives this to us */
+	ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+
+	ath5k_hw_set_opmode(ah);
+	/*PISR/SISR Not available on 5210*/
+	if (ah->ah_version != AR5K_AR5210) {
+		ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
+		/* If we later allow tuning for this, store into sc structure */
+		data = AR5K_TUNE_RSSI_THRES |
+			AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S;
+		ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR);
+	}
+
+	/*
+	 * Set Rx/Tx DMA Configuration
+	 *(passing dma size not available on 5210)
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_SDMAMR,
+				AR5K_DMASIZE_512B | AR5K_TXCFG_DMASIZE);
+		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_SDMAMW,
+				AR5K_DMASIZE_512B);
+	}
+
+	/*
+	 * Enable the PHY and wait until completion
+	 */
+	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+
+	/*
+	 * 5111/5112 Specific
+	 */
+	if (ah->ah_version != AR5K_AR5210) {
+		data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+			AR5K_PHY_RX_DELAY_M;
+		data = (channel->val & CHANNEL_CCK) ?
+			((data << 2) / 22) : (data / 10);
+
+		udelay(100 + data);
+	} else {
+		mdelay(1);
+	}
+
+	/*
+	 * Enable calibration and wait until completion
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+				AR5K_PHY_AGCCTL_CAL);
+
+	if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+			AR5K_PHY_AGCCTL_CAL, 0, false)) {
+		ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
+			channel->freq);
+		return -EAGAIN;
+	}
+
+	ret = ath5k_hw_noise_floor_calibration(ah, channel->freq);
+	if (ret)
+		return ret;
+
+	ah->ah_calibration = false;
+
+	/* A and G modes can use QAM modulation which requires enabling
+	 * I and Q calibration. Don't bother in B mode. */
+	if (!(driver_mode == MODE_IEEE80211B)) {
+		ah->ah_calibration = true;
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+				AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+				AR5K_PHY_IQ_RUN);
+	}
+
+	/*
+	 * Reset queues and start beacon timers at the end of the reset routine
+	 */
+	for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
+		/*No QCU on 5210*/
+		if (ah->ah_version != AR5K_AR5210)
+			AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i);
+
+		ret = ath5k_hw_reset_tx_queue(ah, i);
+		if (ret) {
+			ATH5K_ERR(ah->ah_sc,
+				"failed to reset TX queue #%d\n", i);
+			return ret;
+		}
+	}
+
+	/* Pre-enable interrupts on 5211/5212*/
+	if (ah->ah_version != AR5K_AR5210)
+		ath5k_hw_set_intr(ah, AR5K_INT_RX | AR5K_INT_TX |
+				AR5K_INT_FATAL);
+
+	/*
+	 * Set RF kill flags if supported by the device (read from the EEPROM)
+	 * Disable gpio_intr for now since it results system hang.
+	 * TODO: Handle this in ath5k_intr
+	 */
+#if 0
+	if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) {
+		ath5k_hw_set_gpio_input(ah, 0);
+		ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0);
+		if (ah->ah_gpio[0] == 0)
+			ath5k_hw_set_gpio_intr(ah, 0, 1);
+		else
+			ath5k_hw_set_gpio_intr(ah, 0, 0);
+	}
+#endif
+
+	/*
+	 * Set the 32MHz reference clock on 5212 phy clock sleep register
+	 */
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR);
+		ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
+		ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL);
+		ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
+		ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
+		ath5k_hw_reg_write(ah, ah->ah_radio == AR5K_RF5111 ?
+			AR5K_PHY_SPENDING_RF5111 : AR5K_PHY_SPENDING_RF5112,
+			AR5K_PHY_SPENDING);
+	}
+
+	/*
+	 * Disable beacons and reset the register
+	 */
+	AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE |
+			AR5K_BEACON_RESET_TSF);
+
+	return 0;
+}
+
+/*
+ * Reset chipset
+ */
+static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
+{
+	int ret;
+	u32 mask = val ? val : ~0U;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* Read-and-clear RX Descriptor Pointer*/
+	ath5k_hw_reg_read(ah, AR5K_RXDP);
+
+	/*
+	 * Reset the device and wait until success
+	 */
+	ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL);
+
+	/* Wait at least 128 PCI clocks */
+	udelay(15);
+
+	if (ah->ah_version == AR5K_AR5210) {
+		val &= AR5K_RESET_CTL_CHIP;
+		mask &= AR5K_RESET_CTL_CHIP;
+	} else {
+		val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+		mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND;
+	}
+
+	ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false);
+
+	/*
+	 * Reset configuration register (for hw byte-swap). Note that this
+	 * is only set for big endian. We do the necessary magic in
+	 * AR5K_INIT_CFG.
+	 */
+	if ((val & AR5K_RESET_CTL_PCU) == 0)
+		ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
+
+	return ret;
+}
+
+/*
+ * Power management functions
+ */
+
+/*
+ * Sleep control
+ */
+int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
+		bool set_chip, u16 sleep_duration)
+{
+	unsigned int i;
+	u32 staid;
+
+	ATH5K_TRACE(ah->ah_sc);
+	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
+
+	switch (mode) {
+	case AR5K_PM_AUTO:
+		staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA;
+		/* fallthrough */
+	case AR5K_PM_NETWORK_SLEEP:
+		if (set_chip == true)
+			ath5k_hw_reg_write(ah,
+				AR5K_SLEEP_CTL_SLE | sleep_duration,
+				AR5K_SLEEP_CTL);
+
+		staid |= AR5K_STA_ID1_PWR_SV;
+		break;
+
+	case AR5K_PM_FULL_SLEEP:
+		if (set_chip == true)
+			ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP,
+				AR5K_SLEEP_CTL);
+
+		staid |= AR5K_STA_ID1_PWR_SV;
+		break;
+
+	case AR5K_PM_AWAKE:
+		if (set_chip == false)
+			goto commit;
+
+		ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
+				AR5K_SLEEP_CTL);
+
+		for (i = 5000; i > 0; i--) {
+			/* Check if the chip did wake up */
+			if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
+					AR5K_PCICFG_SPWR_DN) == 0)
+				break;
+
+			/* Wait a bit and retry */
+			udelay(200);
+			ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
+				AR5K_SLEEP_CTL);
+		}
+
+		/* Fail if the chip didn't wake up */
+		if (i <= 0)
+			return -EIO;
+
+		staid &= ~AR5K_STA_ID1_PWR_SV;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+commit:
+	ah->ah_power_mode = mode;
+	ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
+
+	return 0;
+}
+
+/***********************\
+  DMA Related Functions
+\***********************/
+
+/*
+ * Receive functions
+ */
+
+/*
+ * Start DMA receive
+ */
+void ath5k_hw_start_rx(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
+}
+
+/*
+ * Stop DMA receive
+ */
+int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
+{
+	unsigned int i;
+
+	ATH5K_TRACE(ah->ah_sc);
+	ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
+
+	/*
+	 * It may take some time to disable the DMA receive unit
+	 */
+	for (i = 2000; i > 0 &&
+			(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
+			i--)
+		udelay(10);
+
+	return i ? 0 : -EBUSY;
+}
+
+/*
+ * Get the address of the RX Descriptor
+ */
+u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah)
+{
+	return ath5k_hw_reg_read(ah, AR5K_RXDP);
+}
+
+/*
+ * Set the address of the RX Descriptor
+ */
+void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*TODO:Shouldn't we check if RX is enabled first ?*/
+	ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
+}
+
+/*
+ * Transmit functions
+ */
+
+/*
+ * Start DMA transmit for a specific queue
+ * (see also QCU/DCU functions)
+ */
+int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue)
+{
+	u32 tx_queue;
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	/* Return if queue is declared inactive */
+	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
+
+		/*
+		 * Set the queue by type on 5210
+		 */
+		switch (ah->ah_txq[queue].tqi_type) {
+		case AR5K_TX_QUEUE_DATA:
+			tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+			tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
+			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
+					AR5K_BSR);
+			break;
+		case AR5K_TX_QUEUE_CAB:
+			tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1;
+			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V |
+				AR5K_BCR_BDMAE, AR5K_BSR);
+			break;
+		default:
+			return -EINVAL;
+		}
+		/* Start queue */
+		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+	} else {
+		/* Return if queue is disabled */
+		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
+			return -EIO;
+
+		/* Start queue */
+		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue);
+	}
+
+	return 0;
+}
+
+/*
+ * Stop DMA transmit for a specific queue
+ * (see also QCU/DCU functions)
+ */
+int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+{
+	unsigned int i = 100;
+	u32 tx_queue, pending;
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	/* Return if queue is declared inactive */
+	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
+
+		/*
+		 * Set by queue type
+		 */
+		switch (ah->ah_txq[queue].tqi_type) {
+		case AR5K_TX_QUEUE_DATA:
+			tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+		case AR5K_TX_QUEUE_CAB:
+			/* XXX Fix me... */
+			tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1;
+			ath5k_hw_reg_write(ah, 0, AR5K_BSR);
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		/* Stop queue */
+		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+	} else {
+		/*
+		 * Schedule TX disable and wait until queue is empty
+		 */
+		AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
+
+		/*Check for pending frames*/
+		do {
+			pending = ath5k_hw_reg_read(ah,
+				AR5K_QUEUE_STATUS(queue)) &
+				AR5K_QCU_STS_FRMPENDCNT;
+			udelay(100);
+		} while (--i && pending);
+
+		/* Clear register */
+		ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
+	}
+
+	/* TODO: Check for success else return error */
+	return 0;
+}
+
+/*
+ * Get the address of the TX Descriptor for a specific queue
+ * (see also QCU/DCU functions)
+ */
+u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue)
+{
+	u16 tx_reg;
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	/*
+	 * Get the transmit queue descriptor pointer from the selected queue
+	 */
+	/*5210 doesn't have QCU*/
+	if (ah->ah_version == AR5K_AR5210) {
+		switch (ah->ah_txq[queue].tqi_type) {
+		case AR5K_TX_QUEUE_DATA:
+			tx_reg = AR5K_NOQCU_TXDP0;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+		case AR5K_TX_QUEUE_CAB:
+			tx_reg = AR5K_NOQCU_TXDP1;
+			break;
+		default:
+			return 0xffffffff;
+		}
+	} else {
+		tx_reg = AR5K_QUEUE_TXDP(queue);
+	}
+
+	return ath5k_hw_reg_read(ah, tx_reg);
+}
+
+/*
+ * Set the address of the TX Descriptor for a specific queue
+ * (see also QCU/DCU functions)
+ */
+int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
+{
+	u16 tx_reg;
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	/*
+	 * Set the transmit queue descriptor pointer register by type
+	 * on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		switch (ah->ah_txq[queue].tqi_type) {
+		case AR5K_TX_QUEUE_DATA:
+			tx_reg = AR5K_NOQCU_TXDP0;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+		case AR5K_TX_QUEUE_CAB:
+			tx_reg = AR5K_NOQCU_TXDP1;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		/*
+		 * Set the transmit queue descriptor pointer for
+		 * the selected queue on QCU for 5211+
+		 * (this won't work if the queue is still active)
+		 */
+		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
+			return -EIO;
+
+		tx_reg = AR5K_QUEUE_TXDP(queue);
+	}
+
+	/* Set descriptor pointer */
+	ath5k_hw_reg_write(ah, phys_addr, tx_reg);
+
+	return 0;
+}
+
+/*
+ * Update tx trigger level
+ */
+int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
+{
+	u32 trigger_level, imr;
+	int ret = -EIO;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*
+	 * Disable interrupts by setting the mask
+	 */
+	imr = ath5k_hw_set_intr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL);
+
+	/*TODO: Boundary check on trigger_level*/
+	trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG),
+			AR5K_TXCFG_TXFULL);
+
+	if (increase == false) {
+		if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES)
+			goto done;
+	} else
+		trigger_level +=
+			((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2);
+
+	/*
+	 * Update trigger level on success
+	 */
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL);
+	else
+		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+				AR5K_TXCFG_TXFULL, trigger_level);
+
+	ret = 0;
+
+done:
+	/*
+	 * Restore interrupt mask
+	 */
+	ath5k_hw_set_intr(ah, imr);
+
+	return ret;
+}
+
+/*
+ * Interrupt handling
+ */
+
+/*
+ * Check if we have pending interrupts
+ */
+bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	return ath5k_hw_reg_read(ah, AR5K_INTPEND);
+}
+
+/*
+ * Get interrupt mask (ISR)
+ */
+int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
+{
+	u32 data;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*
+	 * Read interrupt status from the Interrupt Status register
+	 * on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		data = ath5k_hw_reg_read(ah, AR5K_ISR);
+		if (unlikely(data == AR5K_INT_NOCARD)) {
+			*interrupt_mask = data;
+			return -ENODEV;
+		}
+	} else {
+		/*
+		 * Read interrupt status from the Read-And-Clear shadow register
+		 * Note: PISR/SISR Not available on 5210
+		 */
+		data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR);
+	}
+
+	/*
+	 * Get abstract interrupt mask (driver-compatible)
+	 */
+	*interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr;
+
+	if (unlikely(data == AR5K_INT_NOCARD))
+		return -ENODEV;
+
+	if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR))
+		*interrupt_mask |= AR5K_INT_RX;
+
+	if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR
+		| AR5K_ISR_TXDESC | AR5K_ISR_TXEOL))
+		*interrupt_mask |= AR5K_INT_TX;
+
+	if (ah->ah_version != AR5K_AR5210) {
+		/*HIU = Host Interface Unit (PCI etc)*/
+		if (unlikely(data & (AR5K_ISR_HIUERR)))
+			*interrupt_mask |= AR5K_INT_FATAL;
+
+		/*Beacon Not Ready*/
+		if (unlikely(data & (AR5K_ISR_BNR)))
+			*interrupt_mask |= AR5K_INT_BNR;
+	}
+
+	/*
+	 * XXX: BMISS interrupts may occur after association.
+	 * I found this on 5210 code but it needs testing. If this is
+	 * true we should disable them before assoc and re-enable them
+	 * after a successfull assoc + some jiffies.
+	 */
+#if 0
+	interrupt_mask &= ~AR5K_INT_BMISS;
+#endif
+
+	/*
+	 * In case we didn't handle anything,
+	 * print the register value.
+	 */
+	if (unlikely(*interrupt_mask == 0 && net_ratelimit()))
+		ATH5K_PRINTF("0x%08x\n", data);
+
+	return 0;
+}
+
+/*
+ * Set interrupt mask
+ */
+enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
+{
+	enum ath5k_int old_mask, int_mask;
+
+	/*
+	 * Disable card interrupts to prevent any race conditions
+	 * (they will be re-enabled afterwards).
+	 */
+	ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
+
+	old_mask = ah->ah_imr;
+
+	/*
+	 * Add additional, chipset-dependent interrupt mask flags
+	 * and write them to the IMR (interrupt mask register).
+	 */
+	int_mask = new_mask & AR5K_INT_COMMON;
+
+	if (new_mask & AR5K_INT_RX)
+		int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN |
+			AR5K_IMR_RXDESC;
+
+	if (new_mask & AR5K_INT_TX)
+		int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC |
+			AR5K_IMR_TXURN;
+
+	if (ah->ah_version != AR5K_AR5210) {
+		if (new_mask & AR5K_INT_FATAL) {
+			int_mask |= AR5K_IMR_HIUERR;
+			AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT |
+					AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR);
+		}
+	}
+
+	ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR);
+
+	/* Store new interrupt mask */
+	ah->ah_imr = new_mask;
+
+	/* ..re-enable interrupts */
+	ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
+
+	return old_mask;
+}
+
+
+/*************************\
+  EEPROM access functions
+\*************************/
+
+/*
+ * Read from eeprom
+ */
+static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
+{
+	u32 status, timeout;
+
+	ATH5K_TRACE(ah->ah_sc);
+	/*
+	 * Initialize EEPROM access
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
+		(void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
+	} else {
+		ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+				AR5K_EEPROM_CMD_READ);
+	}
+
+	for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
+		status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
+		if (status & AR5K_EEPROM_STAT_RDDONE) {
+			if (status & AR5K_EEPROM_STAT_RDERR)
+				return -EIO;
+			*data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
+					0xffff);
+			return 0;
+		}
+		udelay(15);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/*
+ * Write to eeprom - currently disabled, use at your own risk
+ */
+static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data)
+{
+#if 0
+	u32 status, timeout;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*
+	 * Initialize eeprom access
+	 */
+
+	if (ah->ah_version == AR5K_AR5210) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
+	} else {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+				AR5K_EEPROM_CMD_RESET);
+	}
+
+	/*
+	 * Write data to data register
+	 */
+
+	if (ah->ah_version == AR5K_AR5210) {
+		ath5k_hw_reg_write(ah, data, AR5K_EEPROM_BASE + (4 * offset));
+	} else {
+		ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
+		ath5k_hw_reg_write(ah, data, AR5K_EEPROM_DATA);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+				AR5K_EEPROM_CMD_WRITE);
+	}
+
+	/*
+	 * Check status
+	 */
+
+	for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
+		status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
+		if (status & AR5K_EEPROM_STAT_WRDONE) {
+			if (status & AR5K_EEPROM_STAT_WRERR)
+				return EIO;
+			return 0;
+		}
+		udelay(15);
+	}
+#endif
+	ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!");
+	return -EIO;
+}
+
+/*
+ * Translate binary channel representation in EEPROM to frequency
+ */
+static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, unsigned int mode)
+{
+	u16 val;
+
+	if (bin == AR5K_EEPROM_CHANNEL_DIS)
+		return bin;
+
+	if (mode == AR5K_EEPROM_MODE_11A) {
+		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+			val = (5 * bin) + 4800;
+		else
+			val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
+				(bin * 10) + 5100;
+	} else {
+		if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
+			val = bin + 2300;
+		else
+			val = bin + 2400;
+	}
+
+	return val;
+}
+
+/*
+ * Read antenna infos from eeprom
+ */
+static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
+		unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 o = *offset;
+	u16 val;
+	int ret, i = 0;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_switch_settling[mode]	= (val >> 8) & 0x7f;
+	ee->ee_ant_tx_rx[mode]		= (val >> 2) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
+	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= val & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	= (val >> 10) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= (val >> 4) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 2) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 14) & 0x3;
+	ee->ee_ant_control[mode][i++]	= (val >> 8) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= (val >> 2) & 0x3f;
+	ee->ee_ant_control[mode][i]	= (val << 4) & 0x3f;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_ant_control[mode][i++]	|= (val >> 12) & 0xf;
+	ee->ee_ant_control[mode][i++]	= (val >> 6) & 0x3f;
+	ee->ee_ant_control[mode][i++]	= val & 0x3f;
+
+	/* Get antenna modes */
+	ah->ah_antenna[mode][0] =
+	    (ee->ee_ant_control[mode][0] << 4) | 0x1;
+	ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
+	     ee->ee_ant_control[mode][1] 	|
+	    (ee->ee_ant_control[mode][2] << 6) 	|
+	    (ee->ee_ant_control[mode][3] << 12) |
+	    (ee->ee_ant_control[mode][4] << 18) |
+	    (ee->ee_ant_control[mode][5] << 24);
+	ah->ah_antenna[mode][AR5K_ANT_FIXED_B] =
+	     ee->ee_ant_control[mode][6] 	|
+	    (ee->ee_ant_control[mode][7] << 6) 	|
+	    (ee->ee_ant_control[mode][8] << 12) |
+	    (ee->ee_ant_control[mode][9] << 18) |
+	    (ee->ee_ant_control[mode][10] << 24);
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/*
+ * Read supported modes from eeprom
+ */
+static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
+		unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 o = *offset;
+	u16 val;
+	int ret;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_tx_end2xlna_enable[mode]	= (val >> 8) & 0xff;
+	ee->ee_thr_62[mode]		= val & 0xff;
+
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
+		ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_tx_end2xpa_disable[mode]	= (val >> 8) & 0xff;
+	ee->ee_tx_frm2xpa_enable[mode]	= val & 0xff;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_pga_desired_size[mode]	= (val >> 8) & 0xff;
+
+	if ((val & 0xff) & 0x80)
+		ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
+	else
+		ee->ee_noise_floor_thr[mode] = val & 0xff;
+
+	if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
+		ee->ee_noise_floor_thr[mode] =
+		    mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
+
+	AR5K_EEPROM_READ(o++, val);
+	ee->ee_xlna_gain[mode]		= (val >> 5) & 0xff;
+	ee->ee_x_gain[mode]		= (val >> 1) & 0xf;
+	ee->ee_xpd[mode]		= val & 0x1;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
+		ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
+
+		if (mode == AR5K_EEPROM_MODE_11A)
+			ee->ee_xr_power[mode] = val & 0x3f;
+		else {
+			ee->ee_ob[mode][0] = val & 0x7;
+			ee->ee_db[mode][0] = (val >> 3) & 0x7;
+		}
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
+		ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
+		ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
+	} else {
+		ee->ee_i_gain[mode] = (val >> 13) & 0x7;
+
+		AR5K_EEPROM_READ(o++, val);
+		ee->ee_i_gain[mode] |= (val << 3) & 0x38;
+
+		if (mode == AR5K_EEPROM_MODE_11G)
+			ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
+	}
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
+			mode == AR5K_EEPROM_MODE_11A) {
+		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+	}
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
+	    mode == AR5K_EEPROM_MODE_11G)
+		ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
+
+	/* return new offset */
+	*offset = o;
+
+	return 0;
+}
+
+/*
+ * Initialize eeprom & capabilities structs
+ */
+static int ath5k_eeprom_init(struct ath5k_hw *ah)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	unsigned int mode, i;
+	int ret;
+	u32 offset;
+	u16 val;
+
+	/* Initial TX thermal adjustment values */
+	ee->ee_tx_clip = 4;
+	ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
+	ee->ee_gain_select = 1;
+
+	/*
+	 * Read values from EEPROM and store them in the capability structure
+	 */
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
+
+	/* Return if we have an old EEPROM */
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
+		return 0;
+
+#ifdef notyet
+	/*
+	 * Validate the checksum of the EEPROM date. There are some
+	 * devices with invalid EEPROMs.
+	 */
+	for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
+		AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
+		cksum ^= val;
+	}
+	if (cksum != AR5K_EEPROM_INFO_CKSUM) {
+		ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
+		return -EIO;
+	}
+#endif
+
+	AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
+	    ee_ant_gain);
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
+		AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
+	}
+
+	if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
+
+		AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
+		ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
+		ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
+	}
+
+	/*
+	 * Get conformance test limit values
+	 */
+	offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
+	ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
+
+	for (i = 0; i < ee->ee_ctls; i++) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_ctl[i] = (val >> 8) & 0xff;
+		ee->ee_ctl[i + 1] = val & 0xff;
+	}
+
+	/*
+	 * Get values for 802.11a (5GHz)
+	 */
+	mode = AR5K_EEPROM_MODE_11A;
+
+	ee->ee_turbo_max_power[mode] =
+			AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
+
+	offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
+
+	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	AR5K_EEPROM_READ(offset++, val);
+	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
+	ee->ee_ob[mode][3]		= (val >> 5) & 0x7;
+	ee->ee_db[mode][3]		= (val >> 2) & 0x7;
+	ee->ee_ob[mode][2]		= (val << 1) & 0x7;
+
+	AR5K_EEPROM_READ(offset++, val);
+	ee->ee_ob[mode][2]		|= (val >> 15) & 0x1;
+	ee->ee_db[mode][2]		= (val >> 12) & 0x7;
+	ee->ee_ob[mode][1]		= (val >> 9) & 0x7;
+	ee->ee_db[mode][1]		= (val >> 6) & 0x7;
+	ee->ee_ob[mode][0]		= (val >> 3) & 0x7;
+	ee->ee_db[mode][0]		= val & 0x7;
+
+	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_margin_tx_rx[mode] = val & 0x3f;
+	}
+
+	/*
+	 * Get values for 802.11b (2.4GHz)
+	 */
+	mode = AR5K_EEPROM_MODE_11B;
+	offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
+
+	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	AR5K_EEPROM_READ(offset++, val);
+	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
+	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
+	ee->ee_db[mode][1]		= val & 0x7;
+
+	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_cal_pier[mode][0] =
+			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+		ee->ee_cal_pier[mode][1] =
+			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_cal_pier[mode][2] =
+			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+	}
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+		ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+	/*
+	 * Get values for 802.11g (2.4GHz)
+	 */
+	mode = AR5K_EEPROM_MODE_11G;
+	offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
+
+	ret = ath5k_eeprom_read_ants(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	AR5K_EEPROM_READ(offset++, val);
+	ee->ee_adc_desired_size[mode]	= (s8)((val >> 8) & 0xff);
+	ee->ee_ob[mode][1]		= (val >> 4) & 0x7;
+	ee->ee_db[mode][1]		= val & 0x7;
+
+	ret = ath5k_eeprom_read_modes(ah, &offset, mode);
+	if (ret)
+		return ret;
+
+	if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_cal_pier[mode][0] =
+			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+		ee->ee_cal_pier[mode][1] =
+			ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
+
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_turbo_max_power[mode] = val & 0x7f;
+		ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
+
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_cal_pier[mode][2] =
+			ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
+			ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
+
+		AR5K_EEPROM_READ(offset++, val);
+		ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
+		ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
+
+		if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
+			AR5K_EEPROM_READ(offset++, val);
+			ee->ee_cck_ofdm_gain_delta = val & 0xff;
+		}
+	}
+
+	/*
+	 * Read 5GHz EEPROM channels
+	 */
+
+	return 0;
+}
+
+/*
+ * Read the MAC address from eeprom
+ */
+static int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+	u8 mac_d[ETH_ALEN];
+	u32 total, offset;
+	u16 data;
+	int octet, ret;
+
+	memset(mac, 0, ETH_ALEN);
+	memset(mac_d, 0, ETH_ALEN);
+
+	ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
+	if (ret)
+		return ret;
+
+	for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+		ret = ath5k_hw_eeprom_read(ah, offset, &data);
+		if (ret)
+			return ret;
+
+		total += data;
+		mac_d[octet + 1] = data & 0xff;
+		mac_d[octet] = data >> 8;
+		octet += 2;
+	}
+
+	memcpy(mac, mac_d, ETH_ALEN);
+
+	if (!total || total == 3 * 0xffff)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Read/Write regulatory domain
+ */
+static bool ath5k_eeprom_regulation_domain(struct ath5k_hw *ah, bool write,
+	enum ath5k_regdom *regdomain)
+{
+	u16 ee_regdomain;
+
+	/* Read current value */
+	if (write != true) {
+		ee_regdomain = ah->ah_capabilities.cap_eeprom.ee_regdomain;
+		*regdomain = ath5k_regdom_to_ieee(ee_regdomain);
+		return true;
+	}
+
+	ee_regdomain = ath5k_regdom_from_ieee(*regdomain);
+
+	/* Try to write a new value */
+	if (ah->ah_capabilities.cap_eeprom.ee_protect &
+			AR5K_EEPROM_PROTECT_WR_128_191)
+		return false;
+	if (ath5k_hw_eeprom_write(ah, AR5K_EEPROM_REG_DOMAIN, ee_regdomain)!=0)
+		return false;
+
+	ah->ah_capabilities.cap_eeprom.ee_regdomain = ee_regdomain;
+
+	return true;
+}
+
+/*
+ * Use the above to write a new regulatory domain
+ */
+int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain)
+{
+	enum ath5k_regdom ieee_regdomain;
+
+	ieee_regdomain = ath5k_regdom_to_ieee(regdomain);
+
+	if (ath5k_eeprom_regulation_domain(ah, true, &ieee_regdomain) == true)
+		return 0;
+
+	return -EIO;
+}
+
+/*
+ * Fill the capabilities struct
+ */
+static int ath5k_hw_get_capabilities(struct ath5k_hw *ah)
+{
+	u16 ee_header;
+
+	ATH5K_TRACE(ah->ah_sc);
+	/* Capabilities stored in the EEPROM */
+	ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		/*
+		 * Set radio capabilities
+		 * (The AR5110 only supports the middle 5GHz band)
+		 */
+		ah->ah_capabilities.cap_range.range_5ghz_min = 5120;
+		ah->ah_capabilities.cap_range.range_5ghz_max = 5430;
+		ah->ah_capabilities.cap_range.range_2ghz_min = 0;
+		ah->ah_capabilities.cap_range.range_2ghz_max = 0;
+
+		/* Set supported modes */
+		__set_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode);
+		__set_bit(MODE_ATHEROS_TURBO, ah->ah_capabilities.cap_mode);
+	} else {
+		/*
+		 * XXX The tranceiver supports frequencies from 4920 to 6100GHz
+		 * XXX and from 2312 to 2732GHz. There are problems with the
+		 * XXX current ieee80211 implementation because the IEEE
+		 * XXX channel mapping does not support negative channel
+		 * XXX numbers (2312MHz is channel -19). Of course, this
+		 * XXX doesn't matter because these channels are out of range
+		 * XXX but some regulation domains like MKK (Japan) will
+		 * XXX support frequencies somewhere around 4.8GHz.
+		 */
+
+		/*
+		 * Set radio capabilities
+		 */
+
+		if (AR5K_EEPROM_HDR_11A(ee_header)) {
+			ah->ah_capabilities.cap_range.range_5ghz_min = 5005; /* 4920 */
+			ah->ah_capabilities.cap_range.range_5ghz_max = 6100;
+
+			/* Set supported modes */
+			__set_bit(MODE_IEEE80211A,
+					ah->ah_capabilities.cap_mode);
+			__set_bit(MODE_ATHEROS_TURBO,
+					ah->ah_capabilities.cap_mode);
+			if (ah->ah_version == AR5K_AR5212)
+				__set_bit(MODE_ATHEROS_TURBOG,
+						ah->ah_capabilities.cap_mode);
+		}
+
+		/* Enable  802.11b if a 2GHz capable radio (2111/5112) is
+		 * connected */
+		if (AR5K_EEPROM_HDR_11B(ee_header) ||
+				AR5K_EEPROM_HDR_11G(ee_header)) {
+			ah->ah_capabilities.cap_range.range_2ghz_min = 2412; /* 2312 */
+			ah->ah_capabilities.cap_range.range_2ghz_max = 2732;
+
+			if (AR5K_EEPROM_HDR_11B(ee_header))
+				__set_bit(MODE_IEEE80211B,
+						ah->ah_capabilities.cap_mode);
+
+			if (AR5K_EEPROM_HDR_11G(ee_header))
+				__set_bit(MODE_IEEE80211G,
+						ah->ah_capabilities.cap_mode);
+		}
+	}
+
+	/* GPIO */
+	ah->ah_gpio_npins = AR5K_NUM_GPIO;
+
+	/* Set number of supported TX queues */
+	if (ah->ah_version == AR5K_AR5210)
+		ah->ah_capabilities.cap_queues.q_tx_num =
+			AR5K_NUM_TX_QUEUES_NOQCU;
+	else
+		ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
+
+	return 0;
+}
+
+/*********************************\
+  Protocol Control Unit Functions
+\*********************************/
+
+/*
+ * Set Operation mode
+ */
+int ath5k_hw_set_opmode(struct ath5k_hw *ah)
+{
+	u32 pcu_reg, beacon_reg, low_id, high_id;
+
+	pcu_reg = 0;
+	beacon_reg = 0;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	switch (ah->ah_op_mode) {
+	case IEEE80211_IF_TYPE_IBSS:
+		pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA |
+			(ah->ah_version == AR5K_AR5210 ?
+				AR5K_STA_ID1_NO_PSPOLL : 0);
+		beacon_reg |= AR5K_BCR_ADHOC;
+		break;
+
+	case IEEE80211_IF_TYPE_AP:
+		pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA |
+			(ah->ah_version == AR5K_AR5210 ?
+				AR5K_STA_ID1_NO_PSPOLL : 0);
+		beacon_reg |= AR5K_BCR_AP;
+		break;
+
+	case IEEE80211_IF_TYPE_STA:
+		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
+			(ah->ah_version == AR5K_AR5210 ?
+				AR5K_STA_ID1_PWR_SV : 0);
+	case IEEE80211_IF_TYPE_MNTR:
+		pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA |
+			(ah->ah_version == AR5K_AR5210 ?
+				AR5K_STA_ID1_NO_PSPOLL : 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * Set PCU registers
+	 */
+	low_id = AR5K_LOW_ID(ah->ah_sta_id);
+	high_id = AR5K_HIGH_ID(ah->ah_sta_id);
+	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+
+	/*
+	 * Set Beacon Control Register on 5210
+	 */
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
+
+	return 0;
+}
+
+/*
+ * BSSID Functions
+ */
+
+/*
+ * Get station id
+ */
+void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	memcpy(mac, ah->ah_sta_id, ETH_ALEN);
+}
+
+/*
+ * Set station id
+ */
+int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
+{
+	u32 low_id, high_id;
+
+	ATH5K_TRACE(ah->ah_sc);
+	/* Set new station ID */
+	memcpy(ah->ah_sta_id, mac, ETH_ALEN);
+
+	low_id = AR5K_LOW_ID(mac);
+	high_id = AR5K_HIGH_ID(mac);
+
+	ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+	ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1);
+
+	return 0;
+}
+
+/*
+ * Set BSSID
+ */
+void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id)
+{
+	u32 low_id, high_id;
+	u16 tim_offset = 0;
+
+	/*
+	 * Set simple BSSID mask on 5212
+	 */
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM0);
+		ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM1);
+	}
+
+	/*
+	 * Set BSSID which triggers the "SME Join" operation
+	 */
+	low_id = AR5K_LOW_ID(bssid);
+	high_id = AR5K_HIGH_ID(bssid);
+	ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0);
+	ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) <<
+				AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1);
+
+	if (assoc_id == 0) {
+		ath5k_hw_disable_pspoll(ah);
+		return;
+	}
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM,
+			tim_offset ? tim_offset + 4 : 0);
+
+	ath5k_hw_enable_pspoll(ah, NULL, 0);
+}
+/**
+ * ath5k_hw_set_bssid_mask - set common bits we should listen to
+ *
+ * The bssid_mask is a utility used by AR5212 hardware to inform the hardware
+ * which bits of the interface's MAC address should be looked at when trying
+ * to decide which packets to ACK. In station mode every bit matters. In AP
+ * mode with a single BSS every bit matters as well. In AP mode with
+ * multiple BSSes not every bit matters.
+ *
+ * @ah: the &struct ath5k_hw
+ * @mask: the bssid_mask, a u8 array of size ETH_ALEN
+ *
+ * Note that this is a simple filter and *does* not filter out all
+ * relevant frames. Some non-relevant frames will get through, probability
+ * jocks are welcomed to compute.
+ *
+ * When handling multiple BSSes (or VAPs) you can get the BSSID mask by
+ * computing the set of:
+ *
+ *     ~ ( MAC XOR BSSID )
+ *
+ * When you do this you are essentially computing the common bits. Later it
+ * is assumed the harware will "and" (&) the BSSID mask with the MAC address
+ * to obtain the relevant bits which should match on the destination frame.
+ *
+ * Simple example: on your card you have have two BSSes you have created with
+ * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address.
+ * There is another BSSID-03 but you are not part of it. For simplicity's sake,
+ * assuming only 4 bits for a mac address and for BSSIDs you can then have:
+ *
+ *                  \
+ * MAC:                0001 |
+ * BSSID-01:   0100 | --> Belongs to us
+ * BSSID-02:   1001 |
+ *                  /
+ * -------------------
+ * BSSID-03:   0110  | --> External
+ * -------------------
+ *
+ * Our bssid_mask would then be:
+ *
+ *             On loop iteration for BSSID-01:
+ *             ~(0001 ^ 0100)  -> ~(0101)
+ *                             ->   1010
+ *             bssid_mask      =    1010
+ *
+ *             On loop iteration for BSSID-02:
+ *             bssid_mask &= ~(0001   ^   1001)
+ *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
+ *             bssid_mask =   (1010)  & ~(1001)
+ *             bssid_mask =   (1010)  &  (0110)
+ *             bssid_mask =   0010
+ *
+ * A bssid_mask of 0010 means "only pay attention to the second least
+ * significant bit". This is because its the only bit common
+ * amongst the MAC and all BSSIDs we support. To findout what the real
+ * common bit is we can simply "&" the bssid_mask now with any BSSID we have
+ * or our MAC address (we assume the hardware uses the MAC address).
+ *
+ * Now, suppose there's an incoming frame for BSSID-03:
+ *
+ * IFRAME-01:  0110
+ *
+ * An easy eye-inspeciton of this already should tell you that this frame
+ * will not pass our check. This is beacuse the bssid_mask tells the
+ * hardware to only look at the second least significant bit and the
+ * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB
+ * as 1, which does not match 0.
+ *
+ * So with IFRAME-01 we *assume* the hardware will do:
+ *
+ *     allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0;
+ *  --> allow = (0010) == 0000 ? 1 : 0;
+ *  --> allow = 0
+ *
+ *  Lets now test a frame that should work:
+ *
+ * IFRAME-02:  0001 (we should allow)
+ *
+ *     allow = (0001 & 1010) == 1010
+ *
+ *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
+ *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
+ *  --> allow = (0010) == (0010)
+ *  --> allow = 1
+ *
+ * Other examples:
+ *
+ * IFRAME-03:  0100 --> allowed
+ * IFRAME-04:  1001 --> allowed
+ * IFRAME-05:  1101 --> allowed but its not for us!!!
+ *
+ */
+int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
+{
+	u32 low_id, high_id;
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (ah->ah_version == AR5K_AR5212) {
+		low_id = AR5K_LOW_ID(mask);
+		high_id = AR5K_HIGH_ID(mask);
+
+		ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0);
+		ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1);
+
+		return 0;
+	}
+
+	return -EIO;
+}
+
+/*
+ * Receive start/stop functions
+ */
+
+/*
+ * Start receive on PCU
+ */
+void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/*
+ * Stop receive on PCU
+ */
+void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/*
+ * RX Filter functions
+ */
+
+/*
+ * Set multicast filter
+ */
+void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	/* Set the multicat filter */
+	ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
+	ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
+}
+
+/*
+ * Set multicast filter by index
+ */
+int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index)
+{
+
+	ATH5K_TRACE(ah->ah_sc);
+	if (index >= 64)
+		return -EINVAL;
+	else if (index >= 32)
+		AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1,
+				(1 << (index - 32)));
+	else
+		AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
+
+	return 0;
+}
+
+/*
+ * Clear Multicast filter by index
+ */
+int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
+{
+
+	ATH5K_TRACE(ah->ah_sc);
+	if (index >= 64)
+		return -EINVAL;
+	else if (index >= 32)
+		AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1,
+				(1 << (index - 32)));
+	else
+		AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
+
+	return 0;
+}
+
+/*
+ * Get current rx filter
+ */
+u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
+{
+	u32 data, filter = 0;
+
+	ATH5K_TRACE(ah->ah_sc);
+	filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
+
+	/*Radar detection for 5212*/
+	if (ah->ah_version == AR5K_AR5212) {
+		data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL);
+
+		if (data & AR5K_PHY_ERR_FIL_RADAR)
+			filter |= AR5K_RX_FILTER_RADARERR;
+		if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK))
+			filter |= AR5K_RX_FILTER_PHYERR;
+	}
+
+	return filter;
+}
+
+/*
+ * Set rx filter
+ */
+void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
+{
+	u32 data = 0;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* Set PHY error filter register on 5212*/
+	if (ah->ah_version == AR5K_AR5212) {
+		if (filter & AR5K_RX_FILTER_RADARERR)
+			data |= AR5K_PHY_ERR_FIL_RADAR;
+		if (filter & AR5K_RX_FILTER_PHYERR)
+			data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK;
+	}
+
+	/*
+	 * The AR5210 uses promiscous mode to detect radar activity
+	 */
+	if (ah->ah_version == AR5K_AR5210 &&
+			(filter & AR5K_RX_FILTER_RADARERR)) {
+		filter &= ~AR5K_RX_FILTER_RADARERR;
+		filter |= AR5K_RX_FILTER_PROM;
+	}
+
+	/*Zero length DMA*/
+	if (data)
+		AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
+	else
+		AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA);
+
+	/*Write RX Filter register*/
+	ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER);
+
+	/*Write PHY error filter register on 5212*/
+	if (ah->ah_version == AR5K_AR5212)
+		ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL);
+
+}
+
+/*
+ * Beacon related functions
+ */
+
+/*
+ * Get a 32bit TSF
+ */
+u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	return ath5k_hw_reg_read(ah, AR5K_TSF_L32);
+}
+
+/*
+ * Get the full 64bit TSF
+ */
+u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
+{
+	u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
+	ATH5K_TRACE(ah->ah_sc);
+
+	return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32);
+}
+
+/*
+ * Force a TSF reset
+ */
+void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_RESET_TSF);
+}
+
+/*
+ * Initialize beacon timers
+ */
+void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
+{
+	u32 timer1, timer2, timer3;
+
+	ATH5K_TRACE(ah->ah_sc);
+	/*
+	 * Set the additional timers by mode
+	 */
+	switch (ah->ah_op_mode) {
+	case IEEE80211_IF_TYPE_STA:
+		if (ah->ah_version == AR5K_AR5210) {
+			timer1 = 0xffffffff;
+			timer2 = 0xffffffff;
+		} else {
+			timer1 = 0x0000ffff;
+			timer2 = 0x0007ffff;
+		}
+		break;
+
+	default:
+		timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3;
+		timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3;
+	}
+
+	timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1);
+
+	/*
+	 * Set the beacon register and enable all timers.
+	 * (next beacon, DMA beacon, software beacon, ATIM window time)
+	 */
+	ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
+	ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1);
+	ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2);
+	ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3);
+
+	ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD |
+			AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE),
+		AR5K_BEACON);
+}
+
+#if 0
+/*
+ * Set beacon timers
+ */
+int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah,
+		const struct ath5k_beacon_state *state)
+{
+	u32 cfp_period, next_cfp, dtim, interval, next_beacon;
+
+	/*
+	 * TODO: should be changed through *state
+	 * review struct ath5k_beacon_state struct
+	 *
+	 * XXX: These are used for cfp period bellow, are they
+	 * ok ? Is it O.K. for tsf here to be 0 or should we use
+	 * get_tsf ?
+	 */
+	u32 dtim_count = 0; /* XXX */
+	u32 cfp_count = 0; /* XXX */
+	u32 tsf = 0; /* XXX */
+
+	ATH5K_TRACE(ah->ah_sc);
+	/* Return on an invalid beacon state */
+	if (state->bs_interval < 1)
+		return -EINVAL;
+
+	interval = state->bs_interval;
+	dtim = state->bs_dtim_period;
+
+	/*
+	 * PCF support?
+	 */
+	if (state->bs_cfp_period > 0) {
+		/*
+		 * Enable PCF mode and set the CFP
+		 * (Contention Free Period) and timer registers
+		 */
+		cfp_period = state->bs_cfp_period * state->bs_dtim_period *
+			state->bs_interval;
+		next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) *
+			state->bs_interval;
+
+		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
+				AR5K_STA_ID1_DEFAULT_ANTENNA |
+				AR5K_STA_ID1_PCF);
+		ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD);
+		ath5k_hw_reg_write(ah, state->bs_cfp_max_duration,
+				AR5K_CFP_DUR);
+		ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period :
+						next_cfp)) << 3, AR5K_TIMER2);
+	} else {
+		/* Disable PCF mode */
+		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
+				AR5K_STA_ID1_DEFAULT_ANTENNA |
+				AR5K_STA_ID1_PCF);
+	}
+
+	/*
+	 * Enable the beacon timer register
+	 */
+	ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0);
+
+	/*
+	 * Start the beacon timers
+	 */
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &~
+		(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) |
+		AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0,
+		AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval,
+		AR5K_BEACON_PERIOD), AR5K_BEACON);
+
+	/*
+	 * Write new beacon miss threshold, if it appears to be valid
+	 * XXX: Figure out right values for min <= bs_bmiss_threshold <= max
+	 * and return if its not in range. We can test this by reading value and
+	 * setting value to a largest value and seeing which values register.
+	 */
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS,
+			state->bs_bmiss_threshold);
+
+	/*
+	 * Set sleep control register
+	 * XXX: Didn't find this in 5210 code but since this register
+	 * exists also in ar5k's 5210 headers i leave it as common code.
+	 */
+	AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR,
+			(state->bs_sleep_duration - 3) << 3);
+
+	/*
+	 * Set enhanced sleep registers on 5212
+	 */
+	if (ah->ah_version == AR5K_AR5212) {
+		if (state->bs_sleep_duration > state->bs_interval &&
+				roundup(state->bs_sleep_duration, interval) ==
+				state->bs_sleep_duration)
+			interval = state->bs_sleep_duration;
+
+		if (state->bs_sleep_duration > dtim && (dtim == 0 ||
+				roundup(state->bs_sleep_duration, dtim) ==
+				state->bs_sleep_duration))
+			dtim = state->bs_sleep_duration;
+
+		if (interval > dtim)
+			return -EINVAL;
+
+		next_beacon = interval == dtim ? state->bs_next_dtim :
+			state->bs_next_beacon;
+
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM((state->bs_next_dtim - 3) << 3,
+			AR5K_SLEEP0_NEXT_DTIM) |
+			AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) |
+			AR5K_SLEEP0_ENH_SLEEP_EN |
+			AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0);
+
+		ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3,
+			AR5K_SLEEP1_NEXT_TIM) |
+			AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1);
+
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) |
+			AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2);
+	}
+
+	return 0;
+}
+
+/*
+ * Reset beacon timers
+ */
+void ath5k_hw_reset_beacon(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	/*
+	 * Disable beacon timer
+	 */
+	ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
+
+	/*
+	 * Disable some beacon register values
+	 */
+	AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
+			AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF);
+	ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON);
+}
+
+/*
+ * Wait for beacon queue to finish
+ */
+int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
+{
+	unsigned int i;
+	int ret;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* 5210 doesn't have QCU*/
+	if (ah->ah_version == AR5K_AR5210) {
+		/*
+		 * Wait for beaconn queue to finish by checking
+		 * Control Register and Beacon Status Register.
+		 */
+		for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) {
+			if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F)
+					||
+			    !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F))
+				break;
+			udelay(10);
+		}
+
+		/* Timeout... */
+		if (i <= 0) {
+			/*
+			 * Re-schedule the beacon queue
+			 */
+			ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1);
+			ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
+					AR5K_BCR);
+
+			return -EIO;
+		}
+		ret = 0;
+	} else {
+	/*5211/5212*/
+		ret = ath5k_hw_register_timeout(ah,
+			AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON),
+			AR5K_QCU_STS_FRMPENDCNT, 0, false);
+
+		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON))
+			return -EIO;
+	}
+
+	return ret;
+}
+#endif
+
+/*
+ * Update mib counters (statistics)
+ */
+void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
+		struct ath5k_mib_stats *statistics)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	/* Read-And-Clear */
+	statistics->ackrcv_bad += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
+	statistics->rts_bad += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
+	statistics->rts_good += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
+	statistics->fcs_bad += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
+	statistics->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
+
+	/* Reset profile count registers on 5212*/
+	if (ah->ah_version == AR5K_AR5212) {
+		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
+		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
+		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
+		ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
+	}
+}
+
+/** ath5k_hw_set_ack_bitrate - set bitrate for ACKs
+ *
+ * @ah: the &struct ath5k_hw
+ * @high: determines if to use low bit rate or now
+ */
+void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
+{
+	if (ah->ah_version != AR5K_AR5212)
+		return;
+	else {
+		u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
+		if (high)
+			AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
+		else
+			AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+	}
+}
+
+
+/*
+ * ACK/CTS Timeouts
+ */
+
+/*
+ * Set ACK timeout on PCU
+ */
+int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK),
+			ah->ah_turbo) <= timeout)
+		return -EINVAL;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK,
+		ath5k_hw_htoclock(timeout, ah->ah_turbo));
+
+	return 0;
+}
+
+/*
+ * Read the ACK timeout from PCU
+ */
+unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
+			AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo);
+}
+
+/*
+ * Set CTS timeout on PCU
+ */
+int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS),
+			ah->ah_turbo) <= timeout)
+		return -EINVAL;
+
+	AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS,
+			ath5k_hw_htoclock(timeout, ah->ah_turbo));
+
+	return 0;
+}
+
+/*
+ * Read CTS timeout from PCU
+ */
+unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah,
+			AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo);
+}
+
+/*
+ * Key table (WEP) functions
+ */
+
+int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
+{
+	unsigned int i;
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+
+	for (i = 0; i < AR5K_KEYCACHE_SIZE; i++)
+		ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i));
+
+	/* Set NULL encryption on non-5210*/
+	if (ah->ah_version != AR5K_AR5210)
+		ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL,
+				AR5K_KEYTABLE_TYPE(entry));
+
+	return 0;
+}
+
+int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+
+	/* Check the validation flag at the end of the entry */
+	return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) &
+		AR5K_KEYTABLE_VALID;
+}
+
+int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
+		const struct ieee80211_key_conf *key, const u8 *mac)
+{
+	unsigned int i;
+	__le32 key_v[5] = {};
+	u32 keytype;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/* key->keylen comes in from mac80211 in bytes */
+
+	if (key->keylen > AR5K_KEYTABLE_SIZE / 8)
+		return -EOPNOTSUPP;
+
+	switch (key->keylen) {
+	/* WEP 40-bit   = 40-bit  entered key + 24 bit IV = 64-bit */
+	case 40 / 8:
+		memcpy(&key_v[0], key->key, 5);
+		keytype = AR5K_KEYTABLE_TYPE_40;
+		break;
+
+	/* WEP 104-bit  = 104-bit entered key + 24-bit IV = 128-bit */
+	case 104 / 8:
+		memcpy(&key_v[0], &key->key[0], 6);
+		memcpy(&key_v[2], &key->key[6], 6);
+		memcpy(&key_v[4], &key->key[12], 1);
+		keytype = AR5K_KEYTABLE_TYPE_104;
+		break;
+	/* WEP 128-bit  = 128-bit entered key + 24 bit IV = 152-bit */
+	case 128 / 8:
+		memcpy(&key_v[0], &key->key[0], 6);
+		memcpy(&key_v[2], &key->key[6], 6);
+		memcpy(&key_v[4], &key->key[12], 4);
+		keytype = AR5K_KEYTABLE_TYPE_128;
+		break;
+
+	default:
+		return -EINVAL; /* shouldn't happen */
+	}
+
+	for (i = 0; i < ARRAY_SIZE(key_v); i++)
+		ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]),
+				AR5K_KEYTABLE_OFF(entry, i));
+
+	ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry));
+
+	return ath5k_hw_set_key_lladdr(ah, entry, mac);
+}
+
+int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
+{
+	u32 low_id, high_id;
+
+	ATH5K_TRACE(ah->ah_sc);
+	 /* Invalid entry (key table overflow) */
+	AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
+
+	/* MAC may be NULL if it's a broadcast key. In this case no need to
+	 * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */
+	if (unlikely(mac == NULL)) {
+		low_id = 0xffffffff;
+		high_id = 0xffff | AR5K_KEYTABLE_VALID;
+	} else {
+		low_id = AR5K_LOW_ID(mac);
+		high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID;
+	}
+
+	ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry));
+	ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry));
+
+	return 0;
+}
+
+
+/********************************************\
+Queue Control Unit, DFS Control Unit Functions
+\********************************************/
+
+/*
+ * Initialize a transmit queue
+ */
+int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
+		struct ath5k_txq_info *queue_info)
+{
+	unsigned int queue;
+	int ret;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*
+	 * Get queue by type
+	 */
+	/*5210 only has 2 queues*/
+	if (ah->ah_version == AR5K_AR5210) {
+		switch (queue_type) {
+		case AR5K_TX_QUEUE_DATA:
+			queue = AR5K_TX_QUEUE_ID_NOQCU_DATA;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+		case AR5K_TX_QUEUE_CAB:
+			queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		switch (queue_type) {
+		case AR5K_TX_QUEUE_DATA:
+			for (queue = AR5K_TX_QUEUE_ID_DATA_MIN;
+				ah->ah_txq[queue].tqi_type !=
+				AR5K_TX_QUEUE_INACTIVE; queue++) {
+
+				if (queue > AR5K_TX_QUEUE_ID_DATA_MAX)
+					return -EINVAL;
+			}
+			break;
+		case AR5K_TX_QUEUE_UAPSD:
+			queue = AR5K_TX_QUEUE_ID_UAPSD;
+			break;
+		case AR5K_TX_QUEUE_BEACON:
+			queue = AR5K_TX_QUEUE_ID_BEACON;
+			break;
+		case AR5K_TX_QUEUE_CAB:
+			queue = AR5K_TX_QUEUE_ID_CAB;
+			break;
+		case AR5K_TX_QUEUE_XR_DATA:
+			if (ah->ah_version != AR5K_AR5212)
+				ATH5K_ERR(ah->ah_sc,
+					"XR data queues only supported in"
+					" 5212!\n");
+			queue = AR5K_TX_QUEUE_ID_XR_DATA;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * Setup internal queue structure
+	 */
+	memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info));
+	ah->ah_txq[queue].tqi_type = queue_type;
+
+	if (queue_info != NULL) {
+		queue_info->tqi_type = queue_type;
+		ret = ath5k_hw_setup_tx_queueprops(ah, queue, queue_info);
+		if (ret)
+			return ret;
+	}
+	/*
+	 * We use ah_txq_status to hold a temp value for
+	 * the Secondary interrupt mask registers on 5211+
+	 * check out ath5k_hw_reset_tx_queue
+	 */
+	AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue);
+
+	return queue;
+}
+
+/*
+ * Setup a transmit queue
+ */
+int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue,
+				const struct ath5k_txq_info *queue_info)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return -EIO;
+
+	memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info));
+
+	/*XXX: Is this supported on 5210 ?*/
+	if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA &&
+			((queue_info->tqi_subtype == AR5K_WME_AC_VI) ||
+			(queue_info->tqi_subtype == AR5K_WME_AC_VO))) ||
+			queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD)
+		ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS;
+
+	return 0;
+}
+
+/*
+ * Get properties for a specific transmit queue
+ */
+int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
+		struct ath5k_txq_info *queue_info)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
+	return 0;
+}
+
+/*
+ * Set a transmit queue inactive
+ */
+void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
+		return;
+
+	/* This queue will be skipped in further operations */
+	ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
+	/*For SIMR setup*/
+	AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
+}
+
+/*
+ * Set DFS params for a transmit queue
+ */
+int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+	u32 cw_min, cw_max, retry_lg, retry_sh;
+	struct ath5k_txq_info *tq = &ah->ah_txq[queue];
+
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	tq = &ah->ah_txq[queue];
+
+	if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return 0;
+
+	if (ah->ah_version == AR5K_AR5210) {
+		/* Only handle data queues, others will be ignored */
+		if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
+			return 0;
+
+		/* Set Slot time */
+		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+			AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
+			AR5K_SLOT_TIME);
+		/* Set ACK_CTS timeout */
+		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+			AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
+			AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
+		/* Set Transmit Latency */
+		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+			AR5K_INIT_TRANSMIT_LATENCY_TURBO :
+			AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
+		/* Set IFS0 */
+		if (ah->ah_turbo == true)
+			 ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
+				(ah->ah_aifs + tq->tqi_aifs) *
+				AR5K_INIT_SLOT_TIME_TURBO) <<
+				AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
+				AR5K_IFS0);
+		else
+			ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
+				(ah->ah_aifs + tq->tqi_aifs) *
+				AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) |
+				AR5K_INIT_SIFS, AR5K_IFS0);
+
+		/* Set IFS1 */
+		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+			AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
+			AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
+		/* Set PHY register 0x9844 (??) */
+		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+			(ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x38 :
+			(ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x1C,
+			AR5K_PHY(17));
+		/* Set Frame Control Register */
+		ath5k_hw_reg_write(ah, ah->ah_turbo == true ?
+			(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
+			AR5K_PHY_TURBO_SHORT | 0x2020) :
+			(AR5K_PHY_FRAME_CTL_INI | 0x1020),
+			AR5K_PHY_FRAME_CTL_5210);
+	}
+
+	/*
+	 * Calculate cwmin/max by channel mode
+	 */
+	cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN;
+	cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX;
+	ah->ah_aifs = AR5K_TUNE_AIFS;
+	/*XR is only supported on 5212*/
+	if (IS_CHAN_XR(ah->ah_current_channel) &&
+			ah->ah_version == AR5K_AR5212) {
+		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR;
+		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR;
+		ah->ah_aifs = AR5K_TUNE_AIFS_XR;
+	/*B mode is not supported on 5210*/
+	} else if (IS_CHAN_B(ah->ah_current_channel) &&
+			ah->ah_version != AR5K_AR5210) {
+		cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B;
+		cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B;
+		ah->ah_aifs = AR5K_TUNE_AIFS_11B;
+	}
+
+	cw_min = 1;
+	while (cw_min < ah->ah_cw_min)
+		cw_min = (cw_min << 1) | 1;
+
+	cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) :
+		((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1);
+	cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) :
+		((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1);
+
+	/*
+	 * Calculate and set retry limits
+	 */
+	if (ah->ah_software_retry == true) {
+		/* XXX Need to test this */
+		retry_lg = ah->ah_limit_tx_retries;
+		retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ?
+			AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg;
+	} else {
+		retry_lg = AR5K_INIT_LG_RETRY;
+		retry_sh = AR5K_INIT_SH_RETRY;
+	}
+
+	/*No QCU/DCU [5210]*/
+	if (ah->ah_version == AR5K_AR5210) {
+		ath5k_hw_reg_write(ah,
+			(cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
+			| AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
+				AR5K_NODCU_RETRY_LMT_SLG_RETRY)
+			| AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
+				AR5K_NODCU_RETRY_LMT_SSH_RETRY)
+			| AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
+			| AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
+			AR5K_NODCU_RETRY_LMT);
+	} else {
+		/*QCU/DCU [5211+]*/
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
+				AR5K_DCU_RETRY_LMT_SLG_RETRY) |
+			AR5K_REG_SM(AR5K_INIT_SSH_RETRY,
+				AR5K_DCU_RETRY_LMT_SSH_RETRY) |
+			AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
+			AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
+			AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
+
+	/*===Rest is also for QCU/DCU only [5211+]===*/
+
+		/*
+		 * Set initial content window (cw_min/cw_max)
+		 * and arbitrated interframe space (aifs)...
+		 */
+		ath5k_hw_reg_write(ah,
+			AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
+			AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
+			AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs,
+				AR5K_DCU_LCL_IFS_AIFS),
+			AR5K_QUEUE_DFS_LOCAL_IFS(queue));
+
+		/*
+		 * Set misc registers
+		 */
+		ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY,
+			AR5K_QUEUE_MISC(queue));
+
+		if (tq->tqi_cbr_period) {
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
+				AR5K_QCU_CBRCFG_INTVAL) |
+				AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
+				AR5K_QCU_CBRCFG_ORN_THRES),
+				AR5K_QUEUE_CBRCFG(queue));
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+				AR5K_QCU_MISC_FRSHED_CBR);
+			if (tq->tqi_cbr_overflow_limit)
+				AR5K_REG_ENABLE_BITS(ah,
+					AR5K_QUEUE_MISC(queue),
+					AR5K_QCU_MISC_CBR_THRES_ENABLE);
+		}
+
+		if (tq->tqi_ready_time)
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
+				AR5K_QCU_RDYTIMECFG_INTVAL) |
+				AR5K_QCU_RDYTIMECFG_ENABLE,
+				AR5K_QUEUE_RDYTIMECFG(queue));
+
+		if (tq->tqi_burst_time) {
+			ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
+				AR5K_DCU_CHAN_TIME_DUR) |
+				AR5K_DCU_CHAN_TIME_ENABLE,
+				AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
+
+			if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
+				AR5K_REG_ENABLE_BITS(ah,
+					AR5K_QUEUE_MISC(queue),
+					AR5K_QCU_MISC_TXE);
+		}
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
+			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
+				AR5K_QUEUE_DFS_MISC(queue));
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
+			ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
+				AR5K_QUEUE_DFS_MISC(queue));
+
+		/*
+		 * Set registers by queue type
+		 */
+		switch (tq->tqi_type) {
+		case AR5K_TX_QUEUE_BEACON:
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+				AR5K_QCU_MISC_FRSHED_DBA_GT |
+				AR5K_QCU_MISC_CBREXP_BCN |
+				AR5K_QCU_MISC_BCN_ENABLE);
+
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
+				AR5K_DCU_MISC_ARBLOCK_CTL_S) |
+				AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
+				AR5K_DCU_MISC_BCN_ENABLE);
+
+			ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
+				(AR5K_TUNE_SW_BEACON_RESP -
+				AR5K_TUNE_DMA_BEACON_RESP) -
+				AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
+				AR5K_QCU_RDYTIMECFG_ENABLE,
+				AR5K_QUEUE_RDYTIMECFG(queue));
+			break;
+
+		case AR5K_TX_QUEUE_CAB:
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+				AR5K_QCU_MISC_FRSHED_DBA_GT |
+				AR5K_QCU_MISC_CBREXP |
+				AR5K_QCU_MISC_CBREXP_BCN);
+
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+				(AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
+				AR5K_DCU_MISC_ARBLOCK_CTL_S));
+			break;
+
+		case AR5K_TX_QUEUE_UAPSD:
+			AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+				AR5K_QCU_MISC_CBREXP);
+			break;
+
+		case AR5K_TX_QUEUE_DATA:
+		default:
+			break;
+		}
+
+		/*
+		 * Enable interrupts for this tx queue
+		 * in the secondary interrupt mask registers
+		 */
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue);
+
+		if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE)
+			AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue);
+
+
+		/* Update secondary interrupt mask registers */
+		ah->ah_txq_imr_txok &= ah->ah_txq_status;
+		ah->ah_txq_imr_txerr &= ah->ah_txq_status;
+		ah->ah_txq_imr_txurn &= ah->ah_txq_status;
+		ah->ah_txq_imr_txdesc &= ah->ah_txq_status;
+		ah->ah_txq_imr_txeol &= ah->ah_txq_status;
+
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok,
+			AR5K_SIMR0_QCU_TXOK) |
+			AR5K_REG_SM(ah->ah_txq_imr_txdesc,
+			AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
+			AR5K_SIMR1_QCU_TXERR) |
+			AR5K_REG_SM(ah->ah_txq_imr_txeol,
+			AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn,
+			AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2);
+	}
+
+	return 0;
+}
+
+/*
+ * Get number of pending frames
+ * for a specific queue [5211+]
+ */
+u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) {
+	ATH5K_TRACE(ah->ah_sc);
+	AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+	/* Return if queue is declared inactive */
+	if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+		return false;
+
+	/* XXX: How about AR5K_CFG_TXCNT ? */
+	if (ah->ah_version == AR5K_AR5210)
+		return false;
+
+	return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT;
+}
+
+/*
+ * Set slot time
+ */
+int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX)
+		return -EINVAL;
+
+	if (ah->ah_version == AR5K_AR5210)
+		ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time,
+				ah->ah_turbo), AR5K_SLOT_TIME);
+	else
+		ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT);
+
+	return 0;
+}
+
+/*
+ * Get slot time
+ */
+unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (ah->ah_version == AR5K_AR5210)
+		return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah,
+				AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo);
+	else
+		return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff;
+}
+
+
+/******************************\
+ Hardware Descriptor Functions
+\******************************/
+
+/*
+ * TX Descriptor
+ */
+
+/*
+ * Initialize the 2-word tx descriptor on 5210/5211
+ */
+static int
+ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+	unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type,
+	unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0,
+	unsigned int key_index, unsigned int antenna_mode, unsigned int flags,
+	unsigned int rtscts_rate, unsigned int rtscts_duration)
+{
+	u32 frame_type;
+	struct ath5k_hw_2w_tx_desc *tx_desc;
+	unsigned int buff_len;
+
+	tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
+
+	/*
+	 * Validate input
+	 * - Zero retries don't make sense.
+	 * - A zero rate will put the HW into a mode where it continously sends
+	 *   noise on the channel, so it is important to avoid this.
+	 */
+	if (unlikely(tx_tries0 == 0)) {
+		ATH5K_ERR(ah->ah_sc, "zero retries\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	if (unlikely(tx_rate0 == 0)) {
+		ATH5K_ERR(ah->ah_sc, "zero rate\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/* Clear status descriptor */
+	memset(desc->ds_hw, 0, sizeof(struct ath5k_hw_tx_status));
+
+	/* Initialize control descriptor */
+	tx_desc->tx_control_0 = 0;
+	tx_desc->tx_control_1 = 0;
+
+	/* Setup control descriptor */
+
+	/* Verify and set frame length */
+	if (pkt_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
+		return -EINVAL;
+
+	tx_desc->tx_control_0 = pkt_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
+
+	/* Verify and set buffer length */
+	buff_len = pkt_len - FCS_LEN;
+
+	/* NB: beacon's BufLen must be a multiple of 4 bytes */
+	if(type == AR5K_PKT_TYPE_BEACON)
+		buff_len = roundup(buff_len, 4);
+
+	if (buff_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
+		return -EINVAL;
+
+	tx_desc->tx_control_1 = buff_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
+
+	/*
+	 * Verify and set header length
+	 * XXX: I only found that on 5210 code, does it work on 5211 ?
+	 */
+	if (ah->ah_version == AR5K_AR5210) {
+		if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN)
+			return -EINVAL;
+		tx_desc->tx_control_0 |=
+			AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
+	}
+
+	/*Diferences between 5210-5211*/
+	if (ah->ah_version == AR5K_AR5210) {
+		switch (type) {
+		case AR5K_PKT_TYPE_BEACON:
+		case AR5K_PKT_TYPE_PROBE_RESP:
+			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY;
+		case AR5K_PKT_TYPE_PIFS:
+			frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS;
+		default:
+			frame_type = type /*<< 2 ?*/;
+		}
+
+		tx_desc->tx_control_0 |=
+			AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) |
+			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+	} else {
+		tx_desc->tx_control_0 |=
+			AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) |
+			AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT);
+		tx_desc->tx_control_1 |=
+			AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE);
+	}
+#define _TX_FLAGS(_c, _flag)						\
+	if (flags & AR5K_TXDESC_##_flag)				\
+		tx_desc->tx_control_##_c |=				\
+			AR5K_2W_TX_DESC_CTL##_c##_##_flag
+
+	_TX_FLAGS(0, CLRDMASK);
+	_TX_FLAGS(0, VEOL);
+	_TX_FLAGS(0, INTREQ);
+	_TX_FLAGS(0, RTSENA);
+	_TX_FLAGS(1, NOACK);
+
+#undef _TX_FLAGS
+
+	/*
+	 * WEP crap
+	 */
+	if (key_index != AR5K_TXKEYIX_INVALID) {
+		tx_desc->tx_control_0 |=
+			AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+		tx_desc->tx_control_1 |=
+			AR5K_REG_SM(key_index,
+			AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+	}
+
+	/*
+	 * RTS/CTS Duration [5210 ?]
+	 */
+	if ((ah->ah_version == AR5K_AR5210) &&
+			(flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)))
+		tx_desc->tx_control_1 |= rtscts_duration &
+				AR5K_2W_TX_DESC_CTL1_RTS_DURATION;
+
+	return 0;
+}
+
+/*
+ * Initialize the 4-word tx descriptor on 5212
+ */
+static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
+	struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len,
+	enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
+	unsigned int tx_tries0, unsigned int key_index,
+	unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate,
+	unsigned int rtscts_duration)
+{
+	struct ath5k_hw_4w_tx_desc *tx_desc;
+	struct ath5k_hw_tx_status *tx_status;
+	unsigned int buff_len;
+
+	ATH5K_TRACE(ah->ah_sc);
+	tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
+	tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2];
+
+	/*
+	 * Validate input
+	 * - Zero retries don't make sense.
+	 * - A zero rate will put the HW into a mode where it continously sends
+	 *   noise on the channel, so it is important to avoid this.
+	 */
+	if (unlikely(tx_tries0 == 0)) {
+		ATH5K_ERR(ah->ah_sc, "zero retries\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	if (unlikely(tx_rate0 == 0)) {
+		ATH5K_ERR(ah->ah_sc, "zero rate\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/* Clear status descriptor */
+	memset(tx_status, 0, sizeof(struct ath5k_hw_tx_status));
+
+	/* Initialize control descriptor */
+	tx_desc->tx_control_0 = 0;
+	tx_desc->tx_control_1 = 0;
+	tx_desc->tx_control_2 = 0;
+	tx_desc->tx_control_3 = 0;
+
+	/* Setup control descriptor */
+
+	/* Verify and set frame length */
+	if (pkt_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
+		return -EINVAL;
+
+	tx_desc->tx_control_0 = pkt_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+
+	/* Verify and set buffer length */
+	buff_len = pkt_len - FCS_LEN;
+
+	/* NB: beacon's BufLen must be a multiple of 4 bytes */
+	if(type == AR5K_PKT_TYPE_BEACON)
+		buff_len = roundup(buff_len, 4);
+
+	if (buff_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
+		return -EINVAL;
+
+	tx_desc->tx_control_1 = buff_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+
+	tx_desc->tx_control_0 |=
+		AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
+		AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
+	tx_desc->tx_control_1 |= AR5K_REG_SM(type,
+					AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
+	tx_desc->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
+					AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
+	tx_desc->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+
+#define _TX_FLAGS(_c, _flag)			\
+	if (flags & AR5K_TXDESC_##_flag)	\
+		tx_desc->tx_control_##_c |=	\
+			AR5K_4W_TX_DESC_CTL##_c##_##_flag
+
+	_TX_FLAGS(0, CLRDMASK);
+	_TX_FLAGS(0, VEOL);
+	_TX_FLAGS(0, INTREQ);
+	_TX_FLAGS(0, RTSENA);
+	_TX_FLAGS(0, CTSENA);
+	_TX_FLAGS(1, NOACK);
+
+#undef _TX_FLAGS
+
+	/*
+	 * WEP crap
+	 */
+	if (key_index != AR5K_TXKEYIX_INVALID) {
+		tx_desc->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+		tx_desc->tx_control_1 |= AR5K_REG_SM(key_index,
+				AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX);
+	}
+
+	/*
+	 * RTS/CTS
+	 */
+	if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) {
+		if ((flags & AR5K_TXDESC_RTSENA) &&
+				(flags & AR5K_TXDESC_CTSENA))
+			return -EINVAL;
+		tx_desc->tx_control_2 |= rtscts_duration &
+				AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
+		tx_desc->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
+				AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
+	}
+
+	return 0;
+}
+
+/*
+ * Initialize a 4-word multirate tx descriptor on 5212
+ */
+static bool
+ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+	unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2,
+	unsigned int tx_rate3, u_int tx_tries3)
+{
+	struct ath5k_hw_4w_tx_desc *tx_desc;
+
+	/*
+	 * Rates can be 0 as long as the retry count is 0 too.
+	 * A zero rate and nonzero retry count will put the HW into a mode where
+	 * it continously sends noise on the channel, so it is important to
+	 * avoid this.
+	 */
+	if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) ||
+		     (tx_rate2 == 0 && tx_tries2 != 0) ||
+		     (tx_rate3 == 0 && tx_tries3 != 0))) {
+		ATH5K_ERR(ah->ah_sc, "zero rate\n");
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	if (ah->ah_version == AR5K_AR5212) {
+		tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
+
+#define _XTX_TRIES(_n)							\
+	if (tx_tries##_n) {						\
+		tx_desc->tx_control_2 |=				\
+		    AR5K_REG_SM(tx_tries##_n,				\
+		    AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n);		\
+		tx_desc->tx_control_3 |=				\
+		    AR5K_REG_SM(tx_rate##_n,				\
+		    AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n);		\
+	}
+
+		_XTX_TRIES(1);
+		_XTX_TRIES(2);
+		_XTX_TRIES(3);
+
+#undef _XTX_TRIES
+
+		return true;
+	}
+
+	return false;
+}
+
+/*
+ * Proccess the tx status descriptor on 5210/5211
+ */
+static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
+		struct ath5k_desc *desc)
+{
+	struct ath5k_hw_tx_status *tx_status;
+	struct ath5k_hw_2w_tx_desc *tx_desc;
+
+	tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
+	tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[0];
+
+	/* No frame has been send or error */
+	if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
+		return -EINPROGRESS;
+
+	/*
+	 * Get descriptor status
+	 */
+	desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+	desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+	desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+	/*TODO: desc->ds_us.tx.ts_virtcol + test*/
+	desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_SEQ_NUM);
+	desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+	desc->ds_us.tx.ts_antenna = 1;
+	desc->ds_us.tx.ts_status = 0;
+	desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_0,
+		AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
+
+	if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){
+		if (tx_status->tx_status_0 &
+				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+			desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+			desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+			desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT;
+	}
+
+	return 0;
+}
+
+/*
+ * Proccess a tx descriptor on 5212
+ */
+static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
+		struct ath5k_desc *desc)
+{
+	struct ath5k_hw_tx_status *tx_status;
+	struct ath5k_hw_4w_tx_desc *tx_desc;
+
+	ATH5K_TRACE(ah->ah_sc);
+	tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
+	tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2];
+
+	/* No frame has been send or error */
+	if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0))
+		return -EINPROGRESS;
+
+	/*
+	 * Get descriptor status
+	 */
+	desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
+	desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
+	desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+		AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
+	desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_SEQ_NUM);
+	desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+		AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
+	desc->ds_us.tx.ts_antenna = (tx_status->tx_status_1 &
+		AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1;
+	desc->ds_us.tx.ts_status = 0;
+
+	switch (AR5K_REG_MS(tx_status->tx_status_1,
+			AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) {
+	case 0:
+		desc->ds_us.tx.ts_rate = tx_desc->tx_control_3 &
+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+		break;
+	case 1:
+		desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
+		desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
+			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
+		break;
+	case 2:
+		desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
+		desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
+			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
+		break;
+	case 3:
+		desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3,
+			AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
+		desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2,
+			AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3);
+		break;
+	}
+
+	if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){
+		if (tx_status->tx_status_0 &
+				AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+			desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+			desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO;
+
+		if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+			desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT;
+	}
+
+	return 0;
+}
+
+/*
+ * RX Descriptor
+ */
+
+/*
+ * Initialize an rx descriptor
+ */
+int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
+			u32 size, unsigned int flags)
+{
+	struct ath5k_rx_desc *rx_desc;
+
+	ATH5K_TRACE(ah->ah_sc);
+	rx_desc = (struct ath5k_rx_desc *)&desc->ds_ctl0;
+
+	/*
+	 *Clear ds_hw
+	 * If we don't clean the status descriptor,
+	 * while scanning we get too many results,
+	 * most of them virtual, after some secs
+	 * of scanning system hangs. M.F.
+	*/
+	memset(desc->ds_hw, 0, sizeof(desc->ds_hw));
+
+	/*Initialize rx descriptor*/
+	rx_desc->rx_control_0 = 0;
+	rx_desc->rx_control_1 = 0;
+
+	/* Setup descriptor */
+	rx_desc->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN;
+	if (unlikely(rx_desc->rx_control_1 != size))
+		return -EINVAL;
+
+	if (flags & AR5K_RXDESC_INTREQ)
+		rx_desc->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ;
+
+	return 0;
+}
+
+/*
+ * Proccess the rx status descriptor on 5210/5211
+ */
+static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah,
+		struct ath5k_desc *desc)
+{
+	struct ath5k_hw_old_rx_status *rx_status;
+
+	rx_status = (struct ath5k_hw_old_rx_status *)&desc->ds_hw[0];
+
+	/* No frame received / not ready */
+	if (unlikely((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_DONE)
+				== 0))
+		return -EINPROGRESS;
+
+	/*
+	 * Frame receive status
+	 */
+	desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 &
+		AR5K_OLD_RX_DESC_STATUS0_DATA_LEN;
+	desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+	desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE);
+	desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 &
+		AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA;
+	desc->ds_us.rx.rs_more = rx_status->rx_status_0 &
+		AR5K_OLD_RX_DESC_STATUS0_MORE;
+	desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+		AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+	desc->ds_us.rx.rs_status = 0;
+
+	/*
+	 * Key table status
+	 */
+	if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID)
+		desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
+			AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX);
+	else
+		desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID;
+
+	/*
+	 * Receive/descriptor errors
+	 */
+	if ((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK)
+			== 0) {
+		if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR)
+			desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC;
+
+		if (rx_status->rx_status_1 &
+				AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN)
+			desc->ds_us.rx.rs_status |= AR5K_RXERR_FIFO;
+
+		if (rx_status->rx_status_1 &
+				AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR) {
+			desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY;
+			desc->ds_us.rx.rs_phyerr =
+				AR5K_REG_MS(rx_status->rx_status_1,
+					AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR);
+		}
+
+		if (rx_status->rx_status_1 &
+				AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+			desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT;
+	}
+
+	return 0;
+}
+
+/*
+ * Proccess the rx status descriptor on 5212
+ */
+static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *ah,
+		struct ath5k_desc *desc)
+{
+	struct ath5k_hw_new_rx_status *rx_status;
+	struct ath5k_hw_rx_error *rx_err;
+
+	ATH5K_TRACE(ah->ah_sc);
+	rx_status = (struct ath5k_hw_new_rx_status *)&desc->ds_hw[0];
+
+	/* Overlay on error */
+	rx_err = (struct ath5k_hw_rx_error *)&desc->ds_hw[0];
+
+	/* No frame received / not ready */
+	if (unlikely((rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_DONE)
+				== 0))
+		return -EINPROGRESS;
+
+	/*
+	 * Frame receive status
+	 */
+	desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 &
+		AR5K_NEW_RX_DESC_STATUS0_DATA_LEN;
+	desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL);
+	desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+		AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE);
+	desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 &
+		AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA;
+	desc->ds_us.rx.rs_more = rx_status->rx_status_0 &
+		AR5K_NEW_RX_DESC_STATUS0_MORE;
+	desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+		AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
+	desc->ds_us.rx.rs_status = 0;
+
+	/*
+	 * Key table status
+	 */
+	if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID)
+		desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1,
+				AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX);
+	else
+		desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID;
+
+	/*
+	 * Receive/descriptor errors
+	 */
+	if ((rx_status->rx_status_1 &
+			AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) {
+		if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR)
+			desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC;
+
+		if (rx_status->rx_status_1 &
+				AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR) {
+			desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY;
+			desc->ds_us.rx.rs_phyerr =
+				AR5K_REG_MS(rx_err->rx_error_1,
+					AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
+		}
+
+		if (rx_status->rx_status_1 &
+				AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+			desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT;
+
+		if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR)
+			desc->ds_us.rx.rs_status |= AR5K_RXERR_MIC;
+	}
+
+	return 0;
+}
+
+
+/****************\
+  GPIO Functions
+\****************/
+
+/*
+ * Set led state
+ */
+void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
+{
+	u32 led;
+	/*5210 has different led mode handling*/
+	u32 led_5210;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*Reset led status*/
+	if (ah->ah_version != AR5K_AR5210)
+		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
+			AR5K_PCICFG_LEDMODE |  AR5K_PCICFG_LED);
+	else
+		AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED);
+
+	/*
+	 * Some blinking values, define at your wish
+	 */
+	switch (state) {
+	case AR5K_LED_SCAN:
+	case AR5K_LED_AUTH:
+		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND;
+		led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL;
+		break;
+
+	case AR5K_LED_INIT:
+		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE;
+		led_5210 = AR5K_PCICFG_LED_PEND;
+		break;
+
+	case AR5K_LED_ASSOC:
+	case AR5K_LED_RUN:
+		led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC;
+		led_5210 = AR5K_PCICFG_LED_ASSOC;
+		break;
+
+	default:
+		led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE;
+		led_5210 = AR5K_PCICFG_LED_PEND;
+		break;
+	}
+
+	/*Write new status to the register*/
+	if (ah->ah_version != AR5K_AR5210)
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led);
+	else
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
+}
+
+/*
+ * Set GPIO outputs
+ */
+int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (gpio > AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~
+		AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR);
+
+	return 0;
+}
+
+/*
+ * Set GPIO inputs
+ */
+int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (gpio > AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~
+		AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR);
+
+	return 0;
+}
+
+/*
+ * Get GPIO state
+ */
+u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	if (gpio > AR5K_NUM_GPIO)
+		return 0xffffffff;
+
+	/* GPIO input magic */
+	return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) &
+		0x1;
+}
+
+/*
+ * Set GPIO state
+ */
+int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
+{
+	u32 data;
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (gpio > AR5K_NUM_GPIO)
+		return -EINVAL;
+
+	/* GPIO output magic */
+	data = ath5k_hw_reg_read(ah, AR5K_GPIODO);
+
+	data &= ~(1 << gpio);
+	data |= (val & 1) << gpio;
+
+	ath5k_hw_reg_write(ah, data, AR5K_GPIODO);
+
+	return 0;
+}
+
+/*
+ * Initialize the GPIO interrupt (RFKill switch)
+ */
+void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
+		u32 interrupt_level)
+{
+	u32 data;
+
+	ATH5K_TRACE(ah->ah_sc);
+	if (gpio > AR5K_NUM_GPIO)
+		return;
+
+	/*
+	 * Set the GPIO interrupt
+	 */
+	data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &
+		~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH |
+		AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) |
+		(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA);
+
+	ath5k_hw_reg_write(ah, interrupt_level ? data :
+		(data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR);
+
+	ah->ah_imr |= AR5K_IMR_GPIO;
+
+	/* Enable GPIO interrupts */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO);
+}
+
+
+/*********************************\
+ Regulatory Domain/Channels Setup
+\*********************************/
+
+u16 ath5k_get_regdomain(struct ath5k_hw *ah)
+{
+	u16 regdomain;
+	enum ath5k_regdom ieee_regdomain;
+#ifdef COUNTRYCODE
+	u16 code;
+#endif
+
+	ath5k_eeprom_regulation_domain(ah, false, &ieee_regdomain);
+	ah->ah_capabilities.cap_regdomain.reg_hw = ieee_regdomain;
+
+#ifdef COUNTRYCODE
+	/*
+	 * Get the regulation domain by country code. This will ignore
+	 * the settings found in the EEPROM.
+	 */
+	code = ieee80211_name2countrycode(COUNTRYCODE);
+	ieee_regdomain = ieee80211_countrycode2regdomain(code);
+#endif
+
+	regdomain = ath5k_regdom_from_ieee(ieee_regdomain);
+	ah->ah_capabilities.cap_regdomain.reg_current = regdomain;
+
+	return regdomain;
+}
+
+
+/****************\
+  Misc functions
+\****************/
+
+int ath5k_hw_get_capability(struct ath5k_hw *ah,
+		enum ath5k_capability_type cap_type,
+		u32 capability, u32 *result)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	switch (cap_type) {
+	case AR5K_CAP_NUM_TXQUEUES:
+		if (result) {
+			if (ah->ah_version == AR5K_AR5210)
+				*result = AR5K_NUM_TX_QUEUES_NOQCU;
+			else
+				*result = AR5K_NUM_TX_QUEUES;
+			goto yes;
+		}
+	case AR5K_CAP_VEOL:
+		goto yes;
+	case AR5K_CAP_COMPRESSION:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	case AR5K_CAP_BURST:
+		goto yes;
+	case AR5K_CAP_TPC:
+		goto yes;
+	case AR5K_CAP_BSSIDMASK:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	case AR5K_CAP_XR:
+		if (ah->ah_version == AR5K_AR5212)
+			goto yes;
+		else
+			goto no;
+	default:
+		goto no;
+	}
+
+no:
+	return -EINVAL;
+yes:
+	return 0;
+}
+
+static int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
+		u16 assoc_id)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (ah->ah_version == AR5K_AR5210) {
+		AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
+			AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
+		return 0;
+	}
+
+	return -EIO;
+}
+
+static int ath5k_hw_disable_pspoll(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (ah->ah_version == AR5K_AR5210) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
+			AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
+		return 0;
+	}
+
+	return -EIO;
+}
diff --git a/drivers/net/wireless/ath5k/hw.h b/drivers/net/wireless/ath5k/hw.h
new file mode 100644
index 000000000000..d9a7c0973f53
--- /dev/null
+++ b/drivers/net/wireless/ath5k/hw.h
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007 Matthew W. S. Bell  <mentor@madwifi.org>
+ * Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/delay.h>
+
+/*
+ * Gain settings
+ */
+
+enum ath5k_rfgain {
+	AR5K_RFGAIN_INACTIVE = 0,
+	AR5K_RFGAIN_READ_REQUESTED,
+	AR5K_RFGAIN_NEED_CHANGE,
+};
+
+#define AR5K_GAIN_CRN_FIX_BITS_5111		4
+#define AR5K_GAIN_CRN_FIX_BITS_5112		7
+#define AR5K_GAIN_CRN_MAX_FIX_BITS		AR5K_GAIN_CRN_FIX_BITS_5112
+#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN		15
+#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN		20
+#define AR5K_GAIN_CCK_PROBE_CORR		5
+#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA		15
+#define AR5K_GAIN_STEP_COUNT			10
+#define AR5K_GAIN_PARAM_TX_CLIP			0
+#define AR5K_GAIN_PARAM_PD_90			1
+#define AR5K_GAIN_PARAM_PD_84			2
+#define AR5K_GAIN_PARAM_GAIN_SEL		3
+#define AR5K_GAIN_PARAM_MIX_ORN			0
+#define AR5K_GAIN_PARAM_PD_138			1
+#define AR5K_GAIN_PARAM_PD_137			2
+#define AR5K_GAIN_PARAM_PD_136			3
+#define AR5K_GAIN_PARAM_PD_132			4
+#define AR5K_GAIN_PARAM_PD_131			5
+#define AR5K_GAIN_PARAM_PD_130			6
+#define AR5K_GAIN_CHECK_ADJUST(_g) 		\
+	((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high)
+
+struct ath5k_gain_opt_step {
+	s16				gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS];
+	s32				gos_gain;
+};
+
+struct ath5k_gain {
+	u32			g_step_idx;
+	u32			g_current;
+	u32			g_target;
+	u32			g_low;
+	u32			g_high;
+	u32			g_f_corr;
+	u32			g_active;
+	const struct ath5k_gain_opt_step	*g_step;
+};
+
+
+/*
+ * HW SPECIFIC STRUCTS
+ */
+
+/* Some EEPROM defines */
+#define AR5K_EEPROM_EEP_SCALE		100
+#define AR5K_EEPROM_EEP_DELTA		10
+#define AR5K_EEPROM_N_MODES		3
+#define AR5K_EEPROM_N_5GHZ_CHAN		10
+#define AR5K_EEPROM_N_2GHZ_CHAN		3
+#define AR5K_EEPROM_MAX_CHAN		10
+#define AR5K_EEPROM_N_PCDAC		11
+#define AR5K_EEPROM_N_TEST_FREQ		8
+#define AR5K_EEPROM_N_EDGES		8
+#define AR5K_EEPROM_N_INTERCEPTS	11
+#define AR5K_EEPROM_FREQ_M(_v)		AR5K_EEPROM_OFF(_v, 0x7f, 0xff)
+#define AR5K_EEPROM_PCDAC_M		0x3f
+#define AR5K_EEPROM_PCDAC_START		1
+#define AR5K_EEPROM_PCDAC_STOP		63
+#define AR5K_EEPROM_PCDAC_STEP		1
+#define AR5K_EEPROM_NON_EDGE_M		0x40
+#define AR5K_EEPROM_CHANNEL_POWER	8
+#define AR5K_EEPROM_N_OBDB		4
+#define AR5K_EEPROM_OBDB_DIS		0xffff
+#define AR5K_EEPROM_CHANNEL_DIS		0xff
+#define AR5K_EEPROM_SCALE_OC_DELTA(_x)	(((_x) * 2) / 10)
+#define AR5K_EEPROM_N_CTLS(_v)		AR5K_EEPROM_OFF(_v, 16, 32)
+#define AR5K_EEPROM_MAX_CTLS		32
+#define AR5K_EEPROM_N_XPD_PER_CHANNEL	4
+#define AR5K_EEPROM_N_XPD0_POINTS	4
+#define AR5K_EEPROM_N_XPD3_POINTS	3
+#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ	35
+#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ	55
+#define AR5K_EEPROM_POWER_M		0x3f
+#define AR5K_EEPROM_POWER_MIN		0
+#define AR5K_EEPROM_POWER_MAX		3150
+#define AR5K_EEPROM_POWER_STEP		50
+#define AR5K_EEPROM_POWER_TABLE_SIZE	64
+#define AR5K_EEPROM_N_POWER_LOC_11B	4
+#define AR5K_EEPROM_N_POWER_LOC_11G	6
+#define AR5K_EEPROM_I_GAIN		10
+#define AR5K_EEPROM_CCK_OFDM_DELTA	15
+#define AR5K_EEPROM_N_IQ_CAL		2
+
+/* Struct to hold EEPROM calibration data */
+struct ath5k_eeprom_info {
+	u16	ee_magic;
+	u16	ee_protect;
+	u16	ee_regdomain;
+	u16	ee_version;
+	u16	ee_header;
+	u16	ee_ant_gain;
+	u16	ee_misc0;
+	u16	ee_misc1;
+	u16	ee_cck_ofdm_gain_delta;
+	u16	ee_cck_ofdm_power_delta;
+	u16	ee_scaled_cck_delta;
+
+	/* Used for tx thermal adjustment (eeprom_init, rfregs) */
+	u16	ee_tx_clip;
+	u16	ee_pwd_84;
+	u16	ee_pwd_90;
+	u16	ee_gain_select;
+
+	/* RF Calibration settings (reset, rfregs) */
+	u16	ee_i_cal[AR5K_EEPROM_N_MODES];
+	u16	ee_q_cal[AR5K_EEPROM_N_MODES];
+	u16	ee_fixed_bias[AR5K_EEPROM_N_MODES];
+	u16	ee_turbo_max_power[AR5K_EEPROM_N_MODES];
+	u16	ee_xr_power[AR5K_EEPROM_N_MODES];
+	u16	ee_switch_settling[AR5K_EEPROM_N_MODES];
+	u16	ee_ant_tx_rx[AR5K_EEPROM_N_MODES];
+	u16	ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC];
+	u16	ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
+	u16	ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB];
+	u16	ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES];
+	u16	ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES];
+	u16	ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES];
+	u16	ee_thr_62[AR5K_EEPROM_N_MODES];
+	u16	ee_xlna_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_xpd[AR5K_EEPROM_N_MODES];
+	u16	ee_x_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_i_gain[AR5K_EEPROM_N_MODES];
+	u16	ee_margin_tx_rx[AR5K_EEPROM_N_MODES];
+
+	/* Unused */
+	u16	ee_false_detect[AR5K_EEPROM_N_MODES];
+	u16	ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN];
+	u16	ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/
+
+	/* Conformance test limits (Unused) */
+	u16	ee_ctls;
+	u16	ee_ctl[AR5K_EEPROM_MAX_CTLS];
+
+	/* Noise Floor Calibration settings */
+	s16	ee_noise_floor_thr[AR5K_EEPROM_N_MODES];
+	s8	ee_adc_desired_size[AR5K_EEPROM_N_MODES];
+	s8	ee_pga_desired_size[AR5K_EEPROM_N_MODES];
+};
+
+/*
+ * Internal RX/TX descriptor structures
+ * (rX: reserved fields possibily used by future versions of the ar5k chipset)
+ */
+
+struct ath5k_rx_desc {
+	u32	rx_control_0; /* RX control word 0 */
+
+#define AR5K_DESC_RX_CTL0			0x00000000
+
+	u32	rx_control_1; /* RX control word 1 */
+
+#define AR5K_DESC_RX_CTL1_BUF_LEN		0x00000fff
+#define AR5K_DESC_RX_CTL1_INTREQ		0x00002000
+} __packed;
+
+/*
+ * 5210/5211 rx status descriptor
+ */
+struct ath5k_hw_old_rx_status {
+	u32	rx_status_0; /* RX status word 0 */
+
+#define AR5K_OLD_RX_DESC_STATUS0_DATA_LEN		0x00000fff
+#define AR5K_OLD_RX_DESC_STATUS0_MORE			0x00001000
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE		0x00078000
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE_S		15
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL		0x07f80000
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	19
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA	0x38000000
+#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	27
+
+	u32	rx_status_1; /* RX status word 1 */
+
+#define AR5K_OLD_RX_DESC_STATUS1_DONE			0x00000001
+#define AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
+#define AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR		0x00000004
+#define AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN		0x00000008
+#define AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000010
+#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR		0x000000e0
+#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR_S		5
+#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
+#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX		0x00007e00
+#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_S		9
+#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x0fff8000
+#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	15
+#define AR5K_OLD_RX_DESC_STATUS1_KEY_CACHE_MISS		0x10000000
+} __packed;
+
+/*
+ * 5212 rx status descriptor
+ */
+struct ath5k_hw_new_rx_status {
+	u32	rx_status_0; /* RX status word 0 */
+
+#define AR5K_NEW_RX_DESC_STATUS0_DATA_LEN		0x00000fff
+#define AR5K_NEW_RX_DESC_STATUS0_MORE			0x00001000
+#define AR5K_NEW_RX_DESC_STATUS0_DECOMP_CRC_ERROR	0x00002000
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE		0x000f8000
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE_S		15
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL		0x0ff00000
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL_S	20
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA	0xf0000000
+#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA_S	28
+
+	u32	rx_status_1; /* RX status word 1 */
+
+#define AR5K_NEW_RX_DESC_STATUS1_DONE			0x00000001
+#define AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK	0x00000002
+#define AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR		0x00000004
+#define AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR	0x00000008
+#define AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR		0x00000010
+#define AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR		0x00000020
+#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID	0x00000100
+#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX		0x0000fe00
+#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_S		9
+#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP	0x7fff0000
+#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S	16
+#define AR5K_NEW_RX_DESC_STATUS1_KEY_CACHE_MISS		0x80000000
+} __packed;
+
+struct ath5k_hw_rx_error {
+	u32	rx_error_0; /* RX error word 0 */
+
+#define AR5K_RX_DESC_ERROR0			0x00000000
+
+	u32	rx_error_1; /* RX error word 1 */
+
+#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE	0x0000ff00
+#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S	8
+} __packed;
+
+#define AR5K_DESC_RX_PHY_ERROR_NONE		0x00
+#define AR5K_DESC_RX_PHY_ERROR_TIMING		0x20
+#define AR5K_DESC_RX_PHY_ERROR_PARITY		0x40
+#define AR5K_DESC_RX_PHY_ERROR_RATE		0x60
+#define AR5K_DESC_RX_PHY_ERROR_LENGTH		0x80
+#define AR5K_DESC_RX_PHY_ERROR_64QAM		0xa0
+#define AR5K_DESC_RX_PHY_ERROR_SERVICE		0xc0
+#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR	0xe0
+
+struct ath5k_hw_2w_tx_desc {
+	u32	tx_control_0; /* TX control word 0 */
+
+#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN		0x0003f000 /*[5210 ?]*/
+#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S	12
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE		0x003c0000
+#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S	18
+#define AR5K_2W_TX_DESC_CTL0_RTSENA		0x00400000
+#define AR5K_2W_TX_DESC_CTL0_CLRDMASK		0x01000000
+#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET	0x00800000 /*[5210]*/
+#define AR5K_2W_TX_DESC_CTL0_VEOL		0x00800000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE		0x1c000000 /*[5210]*/
+#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S	26
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210	0x02000000
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211	0x1e000000
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT	(ah->ah_version == AR5K_AR5210 ? \
+						AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \
+						AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211)
+#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
+#define AR5K_2W_TX_DESC_CTL0_INTREQ		0x20000000
+#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
+
+	u32	tx_control_1; /* TX control word 1 */
+
+#define AR5K_2W_TX_DESC_CTL1_BUF_LEN		0x00000fff
+#define AR5K_2W_TX_DESC_CTL1_MORE		0x00001000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210	0x0007e000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211	0x000fe000
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	(ah->ah_version == AR5K_AR5210 ? \
+						AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \
+						AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211)
+#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE		0x00700000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S	20
+#define AR5K_2W_TX_DESC_CTL1_NOACK		0x00800000 /*[5211]*/
+#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION	0xfff80000 /*[5210 ?]*/
+} __packed;
+
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL   0x00
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM     0x04
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL   0x08
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c
+#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS     0x10
+
+/*
+ * 5212 4-word tx control descriptor
+ */
+struct ath5k_hw_4w_tx_desc {
+	u32	tx_control_0; /* TX control word 0 */
+
+#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN		0x00000fff
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER		0x003f0000
+#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S	16
+#define AR5K_4W_TX_DESC_CTL0_RTSENA		0x00400000
+#define AR5K_4W_TX_DESC_CTL0_VEOL		0x00800000
+#define AR5K_4W_TX_DESC_CTL0_CLRDMASK		0x01000000
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT	0x1e000000
+#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S	25
+#define AR5K_4W_TX_DESC_CTL0_INTREQ		0x20000000
+#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID	0x40000000
+#define AR5K_4W_TX_DESC_CTL0_CTSENA		0x80000000
+
+	u32	tx_control_1; /* TX control word 1 */
+
+#define AR5K_4W_TX_DESC_CTL1_BUF_LEN		0x00000fff
+#define AR5K_4W_TX_DESC_CTL1_MORE		0x00001000
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX	0x000fe000
+#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S	13
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE		0x00f00000
+#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S	20
+#define AR5K_4W_TX_DESC_CTL1_NOACK		0x01000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC		0x06000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S	25
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN	0x18000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S	27
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN	0x60000000
+#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S	29
+
+	u32	tx_control_2; /* TX control word 2 */
+
+#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION		0x00007fff
+#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE	0x00008000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0		0x000f0000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S		16
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1		0x00f00000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S		20
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2		0x0f000000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S		24
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3		0xf0000000
+#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S		28
+
+	u32	tx_control_3; /* TX control word 3 */
+
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0		0x0000001f
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1		0x000003e0
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S	5
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2		0x00007c00
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S	10
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3		0x000f8000
+#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S	15
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE	0x01f00000
+#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S	20
+} __packed;
+
+/*
+ * Common tx status descriptor
+ */
+struct ath5k_hw_tx_status {
+	u32	tx_status_0; /* TX status word 0 */
+
+#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK	0x00000001
+#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES	0x00000002
+#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN	0x00000004
+#define AR5K_DESC_TX_STATUS0_FILTERED		0x00000008
+/*???
+#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT	0x000000f0
+#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S	4
+*/
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT	0x000000f0
+#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S	4
+/*???
+#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT	0x00000f00
+#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S	8
+*/
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT	0x00000f00
+#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S	8
+#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT	0x0000f000
+#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S	12
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP	0xffff0000
+#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S	16
+
+	u32	tx_status_1; /* TX status word 1 */
+
+#define AR5K_DESC_TX_STATUS1_DONE		0x00000001
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM		0x00001ffe
+#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S		1
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH	0x001fe000
+#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S	13
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX	0x00600000
+#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S	21
+#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS	0x00800000
+#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA	0x01000000
+} __packed;
+
+
+/*
+ * AR5K REGISTER ACCESS
+ */
+
+/*Swap RX/TX Descriptor for big endian archs*/
+#if defined(__BIG_ENDIAN)
+#define AR5K_INIT_CFG	(		\
+	AR5K_CFG_SWTD | AR5K_CFG_SWRD	\
+)
+#else
+#define AR5K_INIT_CFG	0x00000000
+#endif
+
+/*#define AR5K_REG_READ(_reg)	ath5k_hw_reg_read(ah, _reg)
+
+#define AR5K_REG_WRITE(_reg, _val)	ath5k_hw_reg_write(ah, _val, _reg)*/
+
+#define AR5K_REG_SM(_val, _flags)					\
+	(((_val) << _flags##_S) & (_flags))
+
+#define AR5K_REG_MS(_val, _flags)					\
+	(((_val) & (_flags)) >> _flags##_S)
+
+/* Some registers can hold multiple values of interest. For this
+ * reason when we want to write to these registers we must first
+ * retrieve the values which we do not want to clear (lets call this
+ * old_data) and then set the register with this and our new_value:
+ * ( old_data | new_value) */
+#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val)			\
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \
+	    (((_val) << _flags##_S) & (_flags)), _reg)
+
+#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask)			\
+	ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) &		\
+			(_mask)) | (_flags), _reg)
+
+#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags)				\
+	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg)
+
+#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags)			\
+	ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg)
+
+#define AR5K_PHY_WRITE(ah, _reg, _val)					\
+	ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2))
+
+#define AR5K_PHY_READ(ah, _reg)					\
+	ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2))
+
+#define AR5K_REG_WAIT(_i) do {						\
+	if (_i % 64)							\
+		udelay(1);						\
+} while (0)
+
+#define AR5K_EEPROM_READ(_o, _v) do {					\
+	if ((ret = ath5k_hw_eeprom_read(ah, (_o), &(_v))) != 0)	\
+		return (ret);						\
+} while (0)
+
+#define AR5K_EEPROM_READ_HDR(_o, _v)					\
+	AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v);	\
+
+/* Read status of selected queue */
+#define AR5K_REG_READ_Q(ah, _reg, _queue)				\
+	(ath5k_hw_reg_read(ah, _reg) & (1 << _queue))			\
+
+#define AR5K_REG_WRITE_Q(ah, _reg, _queue)				\
+	ath5k_hw_reg_write(ah, (1 << _queue), _reg)
+
+#define AR5K_Q_ENABLE_BITS(_reg, _queue) do {				\
+	_reg |= 1 << _queue;						\
+} while (0)
+
+#define AR5K_Q_DISABLE_BITS(_reg, _queue) do {				\
+	_reg &= ~(1 << _queue);						\
+} while (0)
+
+#define AR5K_LOW_ID(_a)(				\
+(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24	\
+)
+
+#define AR5K_HIGH_ID(_a)	((_a)[4] | (_a)[5] << 8)
+
+/*
+ * Initial register values
+ */
+
+/*
+ * Common initial register values
+ */
+#define AR5K_INIT_MODE				CHANNEL_B
+
+#define AR5K_INIT_TX_LATENCY			502
+#define AR5K_INIT_USEC				39
+#define AR5K_INIT_USEC_TURBO			79
+#define AR5K_INIT_USEC_32			31
+#define AR5K_INIT_CARR_SENSE_EN			1
+#define AR5K_INIT_PROG_IFS			920
+#define AR5K_INIT_PROG_IFS_TURBO		960
+#define AR5K_INIT_EIFS				3440
+#define AR5K_INIT_EIFS_TURBO			6880
+#define AR5K_INIT_SLOT_TIME			396
+#define AR5K_INIT_SLOT_TIME_TURBO		480
+#define AR5K_INIT_ACK_CTS_TIMEOUT		1024
+#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO		0x08000800
+#define AR5K_INIT_SIFS				560
+#define AR5K_INIT_SIFS_TURBO			480
+#define AR5K_INIT_SH_RETRY			10
+#define AR5K_INIT_LG_RETRY			AR5K_INIT_SH_RETRY
+#define AR5K_INIT_SSH_RETRY			32
+#define AR5K_INIT_SLG_RETRY			AR5K_INIT_SSH_RETRY
+#define AR5K_INIT_TX_RETRY			10
+#define AR5K_INIT_TOPS				8
+#define AR5K_INIT_RXNOFRM			8
+#define AR5K_INIT_RPGTO				0
+#define AR5K_INIT_TXNOFRM			0
+#define AR5K_INIT_BEACON_PERIOD			65535
+#define AR5K_INIT_TIM_OFFSET			0
+#define AR5K_INIT_BEACON_EN			0
+#define AR5K_INIT_RESET_TSF			0
+
+#define AR5K_INIT_TRANSMIT_LATENCY		(			\
+	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
+	(AR5K_INIT_USEC)						\
+)
+#define AR5K_INIT_TRANSMIT_LATENCY_TURBO	(			\
+	(AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |	\
+	(AR5K_INIT_USEC_TURBO)						\
+)
+#define AR5K_INIT_PROTO_TIME_CNTRL		(			\
+	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) |	\
+	(AR5K_INIT_PROG_IFS)						\
+)
+#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO	(			\
+	(AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
+	(AR5K_INIT_PROG_IFS_TURBO)					\
+)
+#define AR5K_INIT_BEACON_CONTROL		(			\
+	(AR5K_INIT_RESET_TSF << 24) | (AR5K_INIT_BEACON_EN << 23) |	\
+	(AR5K_INIT_TIM_OFFSET << 16) | (AR5K_INIT_BEACON_PERIOD)	\
+)
+
+/*
+ * Non-common initial register values which have to be loaded into the
+ * card at boot time and after each reset.
+ */
+
+/* Register dumps are done per operation mode */
+#define AR5K_INI_RFGAIN_5GHZ		0
+#define AR5K_INI_RFGAIN_2GHZ		1
+
+#define AR5K_INI_VAL_11A		0
+#define AR5K_INI_VAL_11A_TURBO		1
+#define AR5K_INI_VAL_11B		2
+#define AR5K_INI_VAL_11G		3
+#define AR5K_INI_VAL_11G_TURBO		4
+#define AR5K_INI_VAL_XR			0
+#define AR5K_INI_VAL_MAX		5
+
+#define AR5K_RF5111_INI_RF_MAX_BANKS	AR5K_MAX_RF_BANKS
+#define AR5K_RF5112_INI_RF_MAX_BANKS	AR5K_MAX_RF_BANKS
+
+static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
+{
+	u32 retval = 0, bit, i;
+
+	for (i = 0; i < bits; i++) {
+		bit = (val >> i) & 1;
+		retval = (retval << 1) | bit;
+	}
+
+	return retval;
+}
diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c
new file mode 100644
index 000000000000..2c22f1d4ee64
--- /dev/null
+++ b/drivers/net/wireless/ath5k/initvals.c
@@ -0,0 +1,1347 @@
+/*
+ * Initial register settings functions
+ *
+ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "ath5k.h"
+#include "base.h"
+#include "reg.h"
+
+/*
+ * MAC/PHY REGISTERS
+ */
+
+
+/*
+ * Mode-independent initial register writes
+ */
+
+struct ath5k_ini {
+	u16	ini_register;
+	u32	ini_value;
+
+	enum {
+		AR5K_INI_WRITE = 0,	/* Default */
+		AR5K_INI_READ = 1,	/* Cleared on read */
+	} ini_mode;
+};
+
+/*
+ * Mode specific initial register values
+ */
+
+struct ath5k_ini_mode {
+	u16	mode_register;
+	u32	mode_value[5];
+};
+
+/* Initial register settings for AR5210 */
+static const struct ath5k_ini ar5210_ini[] = {
+	/* PCU and MAC registers */
+	{ AR5K_NOQCU_TXDP0,	0 },
+	{ AR5K_NOQCU_TXDP1,	0 },
+	{ AR5K_RXDP,		0 },
+	{ AR5K_CR,		0 },
+	{ AR5K_ISR,		0, AR5K_INI_READ },
+	{ AR5K_IMR,		0 },
+	{ AR5K_IER,		AR5K_IER_DISABLE },
+	{ AR5K_BSR,		0, AR5K_INI_READ },
+	{ AR5K_TXCFG,		AR5K_DMASIZE_128B },
+	{ AR5K_RXCFG,		AR5K_DMASIZE_128B },
+	{ AR5K_CFG,		AR5K_INIT_CFG },
+	{ AR5K_TOPS,		AR5K_INIT_TOPS },
+	{ AR5K_RXNOFRM,		AR5K_INIT_RXNOFRM },
+	{ AR5K_RPGTO,		AR5K_INIT_RPGTO },
+	{ AR5K_TXNOFRM,		AR5K_INIT_TXNOFRM },
+	{ AR5K_SFR,		0 },
+	{ AR5K_MIBC,		0 },
+	{ AR5K_MISC,		0 },
+	{ AR5K_RX_FILTER_5210,	0 },
+	{ AR5K_MCAST_FILTER0_5210, 0 },
+	{ AR5K_MCAST_FILTER1_5210, 0 },
+	{ AR5K_TX_MASK0,	0 },
+	{ AR5K_TX_MASK1,	0 },
+	{ AR5K_CLR_TMASK,	0 },
+	{ AR5K_TRIG_LVL,	AR5K_TUNE_MIN_TX_FIFO_THRES },
+	{ AR5K_DIAG_SW_5210,	0 },
+	{ AR5K_RSSI_THR,	AR5K_TUNE_RSSI_THRES },
+	{ AR5K_TSF_L32_5210,	0 },
+	{ AR5K_TIMER0_5210,	0 },
+	{ AR5K_TIMER1_5210,	0xffffffff },
+	{ AR5K_TIMER2_5210,	0xffffffff },
+	{ AR5K_TIMER3_5210,	1 },
+	{ AR5K_CFP_DUR_5210,	0 },
+	{ AR5K_CFP_PERIOD_5210,	0 },
+	/* PHY registers */
+	{ AR5K_PHY(0),	0x00000047 },
+	{ AR5K_PHY_AGC,	0x00000000 },
+	{ AR5K_PHY(3),	0x09848ea6 },
+	{ AR5K_PHY(4),	0x3d32e000 },
+	{ AR5K_PHY(5),	0x0000076b },
+	{ AR5K_PHY_ACT,	AR5K_PHY_ACT_DISABLE },
+	{ AR5K_PHY(8),	0x02020200 },
+	{ AR5K_PHY(9),	0x00000e0e },
+	{ AR5K_PHY(10),	0x0a020201 },
+	{ AR5K_PHY(11),	0x00036ffc },
+	{ AR5K_PHY(12),	0x00000000 },
+	{ AR5K_PHY(13),	0x00000e0e },
+	{ AR5K_PHY(14),	0x00000007 },
+	{ AR5K_PHY(15),	0x00020100 },
+	{ AR5K_PHY(16),	0x89630000 },
+	{ AR5K_PHY(17),	0x1372169c },
+	{ AR5K_PHY(18),	0x0018b633 },
+	{ AR5K_PHY(19),	0x1284613c },
+	{ AR5K_PHY(20),	0x0de8b8e0 },
+	{ AR5K_PHY(21),	0x00074859 },
+	{ AR5K_PHY(22),	0x7e80beba },
+	{ AR5K_PHY(23),	0x313a665e },
+	{ AR5K_PHY_AGCCTL, 0x00001d08 },
+	{ AR5K_PHY(25),	0x0001ce00 },
+	{ AR5K_PHY(26),	0x409a4190 },
+	{ AR5K_PHY(28),	0x0000000f },
+	{ AR5K_PHY(29),	0x00000080 },
+	{ AR5K_PHY(30),	0x00000004 },
+	{ AR5K_PHY(31),	0x00000018 }, 	/* 0x987c */
+	{ AR5K_PHY(64),	0x00000000 }, 	/* 0x9900 */
+	{ AR5K_PHY(65),	0x00000000 },
+	{ AR5K_PHY(66),	0x00000000 },
+	{ AR5K_PHY(67),	0x00800000 },
+	{ AR5K_PHY(68),	0x00000003 },
+	/* BB gain table (64bytes) */
+	{ AR5K_BB_GAIN(0), 0x00000000 },
+	{ AR5K_BB_GAIN(1), 0x00000020 },
+	{ AR5K_BB_GAIN(2), 0x00000010 },
+	{ AR5K_BB_GAIN(3), 0x00000030 },
+	{ AR5K_BB_GAIN(4), 0x00000008 },
+	{ AR5K_BB_GAIN(5), 0x00000028 },
+	{ AR5K_BB_GAIN(6), 0x00000028 },
+	{ AR5K_BB_GAIN(7), 0x00000004 },
+	{ AR5K_BB_GAIN(8), 0x00000024 },
+	{ AR5K_BB_GAIN(9), 0x00000014 },
+	{ AR5K_BB_GAIN(10), 0x00000034 },
+	{ AR5K_BB_GAIN(11), 0x0000000c },
+	{ AR5K_BB_GAIN(12), 0x0000002c },
+	{ AR5K_BB_GAIN(13), 0x00000002 },
+	{ AR5K_BB_GAIN(14), 0x00000022 },
+	{ AR5K_BB_GAIN(15), 0x00000012 },
+	{ AR5K_BB_GAIN(16), 0x00000032 },
+	{ AR5K_BB_GAIN(17), 0x0000000a },
+	{ AR5K_BB_GAIN(18), 0x0000002a },
+	{ AR5K_BB_GAIN(19), 0x00000001 },
+	{ AR5K_BB_GAIN(20), 0x00000021 },
+	{ AR5K_BB_GAIN(21), 0x00000011 },
+	{ AR5K_BB_GAIN(22), 0x00000031 },
+	{ AR5K_BB_GAIN(23), 0x00000009 },
+	{ AR5K_BB_GAIN(24), 0x00000029 },
+	{ AR5K_BB_GAIN(25), 0x00000005 },
+	{ AR5K_BB_GAIN(26), 0x00000025 },
+	{ AR5K_BB_GAIN(27), 0x00000015 },
+	{ AR5K_BB_GAIN(28), 0x00000035 },
+	{ AR5K_BB_GAIN(29), 0x0000000d },
+	{ AR5K_BB_GAIN(30), 0x0000002d },
+	{ AR5K_BB_GAIN(31), 0x00000003 },
+	{ AR5K_BB_GAIN(32), 0x00000023 },
+	{ AR5K_BB_GAIN(33), 0x00000013 },
+	{ AR5K_BB_GAIN(34), 0x00000033 },
+	{ AR5K_BB_GAIN(35), 0x0000000b },
+	{ AR5K_BB_GAIN(36), 0x0000002b },
+	{ AR5K_BB_GAIN(37), 0x00000007 },
+	{ AR5K_BB_GAIN(38), 0x00000027 },
+	{ AR5K_BB_GAIN(39), 0x00000017 },
+	{ AR5K_BB_GAIN(40), 0x00000037 },
+	{ AR5K_BB_GAIN(41), 0x0000000f },
+	{ AR5K_BB_GAIN(42), 0x0000002f },
+	{ AR5K_BB_GAIN(43), 0x0000002f },
+	{ AR5K_BB_GAIN(44), 0x0000002f },
+	{ AR5K_BB_GAIN(45), 0x0000002f },
+	{ AR5K_BB_GAIN(46), 0x0000002f },
+	{ AR5K_BB_GAIN(47), 0x0000002f },
+	{ AR5K_BB_GAIN(48), 0x0000002f },
+	{ AR5K_BB_GAIN(49), 0x0000002f },
+	{ AR5K_BB_GAIN(50), 0x0000002f },
+	{ AR5K_BB_GAIN(51), 0x0000002f },
+	{ AR5K_BB_GAIN(52), 0x0000002f },
+	{ AR5K_BB_GAIN(53), 0x0000002f },
+	{ AR5K_BB_GAIN(54), 0x0000002f },
+	{ AR5K_BB_GAIN(55), 0x0000002f },
+	{ AR5K_BB_GAIN(56), 0x0000002f },
+	{ AR5K_BB_GAIN(57), 0x0000002f },
+	{ AR5K_BB_GAIN(58), 0x0000002f },
+	{ AR5K_BB_GAIN(59), 0x0000002f },
+	{ AR5K_BB_GAIN(60), 0x0000002f },
+	{ AR5K_BB_GAIN(61), 0x0000002f },
+	{ AR5K_BB_GAIN(62), 0x0000002f },
+	{ AR5K_BB_GAIN(63), 0x0000002f },
+	/* 5110 RF gain table (64btes) */
+	{ AR5K_RF_GAIN(0), 0x0000001d },
+	{ AR5K_RF_GAIN(1), 0x0000005d },
+	{ AR5K_RF_GAIN(2), 0x0000009d },
+	{ AR5K_RF_GAIN(3), 0x000000dd },
+	{ AR5K_RF_GAIN(4), 0x0000011d },
+	{ AR5K_RF_GAIN(5), 0x00000021 },
+	{ AR5K_RF_GAIN(6), 0x00000061 },
+	{ AR5K_RF_GAIN(7), 0x000000a1 },
+	{ AR5K_RF_GAIN(8), 0x000000e1 },
+	{ AR5K_RF_GAIN(9), 0x00000031 },
+	{ AR5K_RF_GAIN(10), 0x00000071 },
+	{ AR5K_RF_GAIN(11), 0x000000b1 },
+	{ AR5K_RF_GAIN(12), 0x0000001c },
+	{ AR5K_RF_GAIN(13), 0x0000005c },
+	{ AR5K_RF_GAIN(14), 0x00000029 },
+	{ AR5K_RF_GAIN(15), 0x00000069 },
+	{ AR5K_RF_GAIN(16), 0x000000a9 },
+	{ AR5K_RF_GAIN(17), 0x00000020 },
+	{ AR5K_RF_GAIN(18), 0x00000019 },
+	{ AR5K_RF_GAIN(19), 0x00000059 },
+	{ AR5K_RF_GAIN(20), 0x00000099 },
+	{ AR5K_RF_GAIN(21), 0x00000030 },
+	{ AR5K_RF_GAIN(22), 0x00000005 },
+	{ AR5K_RF_GAIN(23), 0x00000025 },
+	{ AR5K_RF_GAIN(24), 0x00000065 },
+	{ AR5K_RF_GAIN(25), 0x000000a5 },
+	{ AR5K_RF_GAIN(26), 0x00000028 },
+	{ AR5K_RF_GAIN(27), 0x00000068 },
+	{ AR5K_RF_GAIN(28), 0x0000001f },
+	{ AR5K_RF_GAIN(29), 0x0000001e },
+	{ AR5K_RF_GAIN(30), 0x00000018 },
+	{ AR5K_RF_GAIN(31), 0x00000058 },
+	{ AR5K_RF_GAIN(32), 0x00000098 },
+	{ AR5K_RF_GAIN(33), 0x00000003 },
+	{ AR5K_RF_GAIN(34), 0x00000004 },
+	{ AR5K_RF_GAIN(35), 0x00000044 },
+	{ AR5K_RF_GAIN(36), 0x00000084 },
+	{ AR5K_RF_GAIN(37), 0x00000013 },
+	{ AR5K_RF_GAIN(38), 0x00000012 },
+	{ AR5K_RF_GAIN(39), 0x00000052 },
+	{ AR5K_RF_GAIN(40), 0x00000092 },
+	{ AR5K_RF_GAIN(41), 0x000000d2 },
+	{ AR5K_RF_GAIN(42), 0x0000002b },
+	{ AR5K_RF_GAIN(43), 0x0000002a },
+	{ AR5K_RF_GAIN(44), 0x0000006a },
+	{ AR5K_RF_GAIN(45), 0x000000aa },
+	{ AR5K_RF_GAIN(46), 0x0000001b },
+	{ AR5K_RF_GAIN(47), 0x0000001a },
+	{ AR5K_RF_GAIN(48), 0x0000005a },
+	{ AR5K_RF_GAIN(49), 0x0000009a },
+	{ AR5K_RF_GAIN(50), 0x000000da },
+	{ AR5K_RF_GAIN(51), 0x00000006 },
+	{ AR5K_RF_GAIN(52), 0x00000006 },
+	{ AR5K_RF_GAIN(53), 0x00000006 },
+	{ AR5K_RF_GAIN(54), 0x00000006 },
+	{ AR5K_RF_GAIN(55), 0x00000006 },
+	{ AR5K_RF_GAIN(56), 0x00000006 },
+	{ AR5K_RF_GAIN(57), 0x00000006 },
+	{ AR5K_RF_GAIN(58), 0x00000006 },
+	{ AR5K_RF_GAIN(59), 0x00000006 },
+	{ AR5K_RF_GAIN(60), 0x00000006 },
+	{ AR5K_RF_GAIN(61), 0x00000006 },
+	{ AR5K_RF_GAIN(62), 0x00000006 },
+	{ AR5K_RF_GAIN(63), 0x00000006 },
+	/* PHY activation */
+	{ AR5K_PHY(53), 0x00000020 },
+	{ AR5K_PHY(51), 0x00000004 },
+	{ AR5K_PHY(50), 0x00060106 },
+	{ AR5K_PHY(39), 0x0000006d },
+	{ AR5K_PHY(48), 0x00000000 },
+	{ AR5K_PHY(52), 0x00000014 },
+	{ AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE },
+};
+
+/* Initial register settings for AR5211 */
+static const struct ath5k_ini ar5211_ini[] = {
+	{ AR5K_RXDP,		0x00000000 },
+	{ AR5K_RTSD0,		0x84849c9c },
+	{ AR5K_RTSD1,		0x7c7c7c7c },
+	{ AR5K_RXCFG,		0x00000005 },
+	{ AR5K_MIBC,		0x00000000 },
+	{ AR5K_TOPS,		0x00000008 },
+	{ AR5K_RXNOFRM,		0x00000008 },
+	{ AR5K_TXNOFRM,		0x00000010 },
+	{ AR5K_RPGTO,		0x00000000 },
+	{ AR5K_RFCNT,		0x0000001f },
+	{ AR5K_QUEUE_TXDP(0),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(1),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(2),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(3),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(4),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(5),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(6),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(7),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(8),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(9),	0x00000000 },
+	{ AR5K_DCU_FP,		0x00000000 },
+	{ AR5K_STA_ID1,		0x00000000 },
+	{ AR5K_BSS_ID0,		0x00000000 },
+	{ AR5K_BSS_ID1,		0x00000000 },
+	{ AR5K_RSSI_THR,	0x00000000 },
+	{ AR5K_CFP_PERIOD_5211,	0x00000000 },
+	{ AR5K_TIMER0_5211,	0x00000030 },
+	{ AR5K_TIMER1_5211,	0x0007ffff },
+	{ AR5K_TIMER2_5211,	0x01ffffff },
+	{ AR5K_TIMER3_5211,	0x00000031 },
+	{ AR5K_CFP_DUR_5211,	0x00000000 },
+	{ AR5K_RX_FILTER_5211,	0x00000000 },
+	{ AR5K_MCAST_FILTER0_5211, 0x00000000 },
+	{ AR5K_MCAST_FILTER1_5211, 0x00000002 },
+	{ AR5K_DIAG_SW_5211,	0x00000000 },
+	{ AR5K_ADDAC_TEST,	0x00000000 },
+	{ AR5K_DEFAULT_ANTENNA,	0x00000000 },
+	/* PHY registers */
+	{ AR5K_PHY_AGC,	0x00000000 },
+	{ AR5K_PHY(3),	0x2d849093 },
+	{ AR5K_PHY(4),	0x7d32e000 },
+	{ AR5K_PHY(5),	0x00000f6b },
+	{ AR5K_PHY_ACT,	0x00000000 },
+	{ AR5K_PHY(11),	0x00026ffe },
+	{ AR5K_PHY(12),	0x00000000 },
+	{ AR5K_PHY(15),	0x00020100 },
+	{ AR5K_PHY(16),	0x206a017a },
+	{ AR5K_PHY(19),	0x1284613c },
+	{ AR5K_PHY(21),	0x00000859 },
+	{ AR5K_PHY(26),	0x409a4190 },	/* 0x9868 */
+	{ AR5K_PHY(27),	0x050cb081 },
+	{ AR5K_PHY(28),	0x0000000f },
+	{ AR5K_PHY(29),	0x00000080 },
+	{ AR5K_PHY(30),	0x0000000c },
+	{ AR5K_PHY(64),	0x00000000 },
+	{ AR5K_PHY(65),	0x00000000 },
+	{ AR5K_PHY(66),	0x00000000 },
+	{ AR5K_PHY(67),	0x00800000 },
+	{ AR5K_PHY(68),	0x00000001 },
+	{ AR5K_PHY(71),	0x0000092a },
+	{ AR5K_PHY_IQ,	0x00000000 },
+	{ AR5K_PHY(73),	0x00058a05 },
+	{ AR5K_PHY(74),	0x00000001 },
+	{ AR5K_PHY(75),	0x00000000 },
+	{ AR5K_PHY_PAPD_PROBE, 0x00000000 },
+	{ AR5K_PHY(77),	0x00000000 },	/* 0x9934 */
+	{ AR5K_PHY(78),	0x00000000 },	/* 0x9938 */
+	{ AR5K_PHY(79),	0x0000003f },	/* 0x993c */
+	{ AR5K_PHY(80),	0x00000004 },
+	{ AR5K_PHY(82),	0x00000000 },
+	{ AR5K_PHY(83),	0x00000000 },
+	{ AR5K_PHY(84),	0x00000000 },
+	{ AR5K_PHY_RADAR, 0x5d50f14c },
+	{ AR5K_PHY(86),	0x00000018 },
+	{ AR5K_PHY(87),	0x004b6a8e },
+	/* Initial Power table (32bytes)
+	 * common on all cards/modes.
+	 * Note: Table is rewritten during
+	 * txpower setup later using calibration
+	 * data etc. so next write is non-common
+	{ AR5K_PHY_PCDAC_TXPOWER(1), 0x06ff05ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(2), 0x07ff07ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(3), 0x08ff08ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(4), 0x09ff09ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(5), 0x0aff0aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(6), 0x0bff0bff },
+	{ AR5K_PHY_PCDAC_TXPOWER(7), 0x0cff0cff },
+	{ AR5K_PHY_PCDAC_TXPOWER(8), 0x0dff0dff },
+	{ AR5K_PHY_PCDAC_TXPOWER(9), 0x0fff0eff },
+	{ AR5K_PHY_PCDAC_TXPOWER(10), 0x12ff12ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(11), 0x14ff13ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(12), 0x16ff15ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(13), 0x19ff17ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(14), 0x1bff1aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(15), 0x1eff1dff },
+	{ AR5K_PHY_PCDAC_TXPOWER(16), 0x23ff20ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(17), 0x27ff25ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(18), 0x2cff29ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(19), 0x31ff2fff },
+	{ AR5K_PHY_PCDAC_TXPOWER(20), 0x37ff34ff },
+	{ AR5K_PHY_PCDAC_TXPOWER(21), 0x3aff3aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(22), 0x3aff3aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(23), 0x3aff3aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(24), 0x3aff3aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(25), 0x3aff3aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(26), 0x3aff3aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(27), 0x3aff3aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(28), 0x3aff3aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(29), 0x3aff3aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(30), 0x3aff3aff },
+	{ AR5K_PHY_PCDAC_TXPOWER(31), 0x3aff3aff },*/
+	{ AR5K_PHY_CCKTXCTL, 0x00000000 },
+	{ AR5K_PHY(642), 0x503e4646 },
+	{ AR5K_PHY_GAIN_2GHZ, 0x6480416c },
+	{ AR5K_PHY(644), 0x0199a003 },
+	{ AR5K_PHY(645), 0x044cd610 },
+	{ AR5K_PHY(646), 0x13800040 },
+	{ AR5K_PHY(647), 0x1be00060 },
+	{ AR5K_PHY(648), 0x0c53800a },
+	{ AR5K_PHY(649), 0x0014df3b },
+	{ AR5K_PHY(650), 0x000001b5 },
+	{ AR5K_PHY(651), 0x00000020 },
+};
+
+/* Initial mode-specific settings for AR5211
+ * XXX: how about g / gTurbo ? RF5111 supports it, how about AR5211 ?
+ * Maybe 5211 supports OFDM-only g but we need to test it !
+ */
+static const struct ath5k_ini_mode ar5211_ini_mode[] = {
+	{ AR5K_TXCFG,
+	/*	  a	      aTurbo	  b		*/
+		{ 0x00000015, 0x00000015, 0x0000001d } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } },
+	{ AR5K_DCU_GBL_IFS_SLOT,
+		{ 0x00000168, 0x000001e0, 0x000001b8 } },
+	{ AR5K_DCU_GBL_IFS_SIFS,
+		{ 0x00000230, 0x000001e0, 0x000000b0 } },
+	{ AR5K_DCU_GBL_IFS_EIFS,
+		{ 0x00000d98, 0x00001180, 0x00001f48 } },
+	{ AR5K_DCU_GBL_IFS_MISC,
+		{ 0x0000a0e0, 0x00014068, 0x00005880 } },
+	{ AR5K_TIME_OUT,
+		{ 0x04000400, 0x08000800, 0x20003000 } },
+	{ AR5K_USEC_5211,
+		{ 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95 } },
+	{ AR5K_PHY_TURBO,
+		{ 0x00000000, 0x00000003, 0x00000000 } },
+	{ AR5K_PHY(8),
+		{ 0x02020200, 0x02020200, 0x02010200 } },
+	{ AR5K_PHY(9),
+		{ 0x00000e0e, 0x00000e0e, 0x00000707 } },
+	{ AR5K_PHY(10),
+		{ 0x0a020001, 0x0a020001, 0x05010000 } },
+	{ AR5K_PHY(13),
+		{ 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY(14),
+		{ 0x00000007, 0x00000007, 0x0000000b } },
+	{ AR5K_PHY(17),
+		{ 0x1372169c, 0x137216a5, 0x137216a8 } },
+	{ AR5K_PHY(18),
+		{ 0x0018ba67, 0x0018ba67, 0x0018ba69 } },
+	{ AR5K_PHY(20),
+		{ 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
+	{ AR5K_PHY_SIG,
+		{ 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+		{ 0x31375d5e, 0x31375d5e, 0x313a5d5e } },
+	{ AR5K_PHY_AGCCTL,
+		{ 0x0000bd10, 0x0000bd10, 0x0000bd38 } },
+	{ AR5K_PHY_NF,
+		{ 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+	{ AR5K_PHY_RX_DELAY,
+		{ 0x00002710, 0x00002710, 0x0000157c } },
+	{ AR5K_PHY(70),
+		{ 0x00000190, 0x00000190, 0x00000084 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+		{ 0x6fe01020, 0x6fe01020, 0x6fe00920 } },
+	{ AR5K_PHY_PCDAC_TXPOWER_BASE_5211,
+		{ 0x05ff14ff, 0x05ff14ff, 0x05ff14ff } },
+	{ AR5K_RF_BUFFER_CONTROL_4,
+		{ 0x00000010, 0x00000014, 0x00000010 } },
+};
+
+/* Initial register settings for AR5212 */
+static const struct ath5k_ini ar5212_ini[] = {
+	{ AR5K_RXDP,		0x00000000 },
+	{ AR5K_RXCFG,		0x00000005 },
+	{ AR5K_MIBC,		0x00000000 },
+	{ AR5K_TOPS,		0x00000008 },
+	{ AR5K_RXNOFRM,		0x00000008 },
+	{ AR5K_TXNOFRM,		0x00000010 },
+	{ AR5K_RPGTO,		0x00000000 },
+	{ AR5K_RFCNT,		0x0000001f },
+	{ AR5K_QUEUE_TXDP(0),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(1),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(2),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(3),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(4),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(5),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(6),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(7),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(8),	0x00000000 },
+	{ AR5K_QUEUE_TXDP(9),	0x00000000 },
+	{ AR5K_DCU_FP,		0x00000000 },
+	{ AR5K_DCU_TXP,		0x00000000 },
+	{ AR5K_DCU_TX_FILTER,	0x00000000 },
+	/* Unknown table */
+	{ 0x1078, 0x00000000 },
+	{ 0x10b8, 0x00000000 },
+	{ 0x10f8, 0x00000000 },
+	{ 0x1138, 0x00000000 },
+	{ 0x1178, 0x00000000 },
+	{ 0x11b8, 0x00000000 },
+	{ 0x11f8, 0x00000000 },
+	{ 0x1238, 0x00000000 },
+	{ 0x1278, 0x00000000 },
+	{ 0x12b8, 0x00000000 },
+	{ 0x12f8, 0x00000000 },
+	{ 0x1338, 0x00000000 },
+	{ 0x1378, 0x00000000 },
+	{ 0x13b8, 0x00000000 },
+	{ 0x13f8, 0x00000000 },
+	{ 0x1438, 0x00000000 },
+	{ 0x1478, 0x00000000 },
+	{ 0x14b8, 0x00000000 },
+	{ 0x14f8, 0x00000000 },
+	{ 0x1538, 0x00000000 },
+	{ 0x1578, 0x00000000 },
+	{ 0x15b8, 0x00000000 },
+	{ 0x15f8, 0x00000000 },
+	{ 0x1638, 0x00000000 },
+	{ 0x1678, 0x00000000 },
+	{ 0x16b8, 0x00000000 },
+	{ 0x16f8, 0x00000000 },
+	{ 0x1738, 0x00000000 },
+	{ 0x1778, 0x00000000 },
+	{ 0x17b8, 0x00000000 },
+	{ 0x17f8, 0x00000000 },
+	{ 0x103c, 0x00000000 },
+	{ 0x107c, 0x00000000 },
+	{ 0x10bc, 0x00000000 },
+	{ 0x10fc, 0x00000000 },
+	{ 0x113c, 0x00000000 },
+	{ 0x117c, 0x00000000 },
+	{ 0x11bc, 0x00000000 },
+	{ 0x11fc, 0x00000000 },
+	{ 0x123c, 0x00000000 },
+	{ 0x127c, 0x00000000 },
+	{ 0x12bc, 0x00000000 },
+	{ 0x12fc, 0x00000000 },
+	{ 0x133c, 0x00000000 },
+	{ 0x137c, 0x00000000 },
+	{ 0x13bc, 0x00000000 },
+	{ 0x13fc, 0x00000000 },
+	{ 0x143c, 0x00000000 },
+	{ 0x147c, 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_CLR, 0x00000000 },
+	{ AR5K_DCU_TX_FILTER_SET, 0x00000000 },
+	{ AR5K_STA_ID1,		0x00000000 },
+	{ AR5K_BSS_ID0,		0x00000000 },
+	{ AR5K_BSS_ID1,		0x00000000 },
+	/*{ AR5K_RSSI_THR,	0x00000000 },*/	/* Found on SuperAG cards */
+	{ AR5K_BEACON_5211,	0x00000000 },	/* Found on SuperAG cards */
+	{ AR5K_CFP_PERIOD_5211, 0x00000000 },	/* Found on SuperAG cards */
+	{ AR5K_TIMER0_5211,	0x00000030 },	/* Found on SuperAG cards */
+	{ AR5K_TIMER1_5211,	0x0007ffff },	/* Found on SuperAG cards */
+	{ AR5K_TIMER2_5211,	0x01ffffff },	/* Found on SuperAG cards */
+	{ AR5K_TIMER3_5211,	0x00000031 },	/* Found on SuperAG cards */
+	{ AR5K_CFP_DUR_5211,	0x00000000 },	/* Found on SuperAG cards */
+	{ AR5K_RX_FILTER_5211,	0x00000000 },
+	{ AR5K_DIAG_SW_5211,	0x00000000 },
+	{ AR5K_ADDAC_TEST,	0x00000000 },
+	{ AR5K_DEFAULT_ANTENNA,	0x00000000 },
+	{ 0x8080, 0x00000000 },
+	/*{ 0x805c, 0xffffc7ff },*/ /* Old value */
+	{ 0x805c, 0x000fc78f },
+	{ AR5K_NAV_5211,	0x00000000 },	/* Not found on recent */
+	{ AR5K_RTS_OK_5211,	0x00000000 },	/* dumps but it makes  */
+	{ AR5K_RTS_FAIL_5211,	0x00000000 },	/* sense to reset counters */
+	{ AR5K_ACK_FAIL_5211,	0x00000000 },	/* since pcu registers */
+	{ AR5K_FCS_FAIL_5211,	0x00000000 },	/* are skiped during chan*/
+	{ AR5K_BEACON_CNT_5211, 0x00000000 },	/* change */
+	{ AR5K_XRMODE,		0x2a82301a },
+	{ AR5K_XRDELAY,		0x05dc01e0 },
+	{ AR5K_XRTIMEOUT,	0x1f402710 },
+	{ AR5K_XRCHIRP,		0x01f40000 },
+	{ AR5K_XRSTOMP,		0x00001e1c },
+	{ AR5K_SLEEP0,		0x0002aaaa },	/* Found on SuperAG cards */
+	{ AR5K_SLEEP1,		0x02005555 },	/* Found on SuperAG cards */
+	{ AR5K_SLEEP2,		0x00000000 },	/* Found on SuperAG cards */
+	{ AR5K_BSS_IDM0,	0xffffffff },
+	{ AR5K_BSS_IDM1,	0x0000ffff },
+	{ AR5K_TXPC,		0x00000000 },
+	{ AR5K_PROFCNT_TX,	0x00000000 },
+	{ AR5K_PROFCNT_RX,	0x00000000 },
+	{ AR5K_PROFCNT_RXCLR,	0x00000000 },
+	{ AR5K_PROFCNT_CYCLE,	0x00000000 },
+	{ 0x80fc, 0x00000088 },
+	{ AR5K_RATE_DUR(0),	0x00000000 },
+	{ AR5K_RATE_DUR(1),	0x0000008c },
+	{ AR5K_RATE_DUR(2),	0x000000e4 },
+	{ AR5K_RATE_DUR(3),	0x000002d5 },
+	{ AR5K_RATE_DUR(4),	0x00000000 },
+	{ AR5K_RATE_DUR(5),	0x00000000 },
+	{ AR5K_RATE_DUR(6),	0x000000a0 },
+	{ AR5K_RATE_DUR(7),	0x000001c9 },
+	{ AR5K_RATE_DUR(8),	0x0000002c },
+	{ AR5K_RATE_DUR(9),	0x0000002c },
+	{ AR5K_RATE_DUR(10),	0x00000030 },
+	{ AR5K_RATE_DUR(11),	0x0000003c },
+	{ AR5K_RATE_DUR(12),	0x0000002c },
+	{ AR5K_RATE_DUR(13),	0x0000002c },
+	{ AR5K_RATE_DUR(14),	0x00000030 },
+	{ AR5K_RATE_DUR(15),	0x0000003c },
+	{ AR5K_RATE_DUR(16),	0x00000000 },
+	{ AR5K_RATE_DUR(17),	0x00000000 },
+	{ AR5K_RATE_DUR(18),	0x00000000 },
+	{ AR5K_RATE_DUR(19),	0x00000000 },
+	{ AR5K_RATE_DUR(20),	0x00000000 },
+	{ AR5K_RATE_DUR(21),	0x00000000 },
+	{ AR5K_RATE_DUR(22),	0x00000000 },
+	{ AR5K_RATE_DUR(23),	0x00000000 },
+	{ AR5K_RATE_DUR(24),	0x000000d5 },
+	{ AR5K_RATE_DUR(25),	0x000000df },
+	{ AR5K_RATE_DUR(26),	0x00000102 },
+	{ AR5K_RATE_DUR(27),	0x0000013a },
+	{ AR5K_RATE_DUR(28),	0x00000075 },
+	{ AR5K_RATE_DUR(29),	0x0000007f },
+	{ AR5K_RATE_DUR(30),	0x000000a2 },
+	{ AR5K_RATE_DUR(31),	0x00000000 },
+	{ 0x8100, 0x00010002},
+	{ AR5K_TSF_PARM,	0x00000001 },
+	{ 0x8108, 0x000000c0 },
+	{ AR5K_PHY_ERR_FIL,	0x00000000 },
+	{ 0x8110, 0x00000168 },
+	{ 0x8114, 0x00000000 },
+	/* Some kind of table
+	 * also notice ...03<-02<-01<-00) */
+	{ 0x87c0, 0x03020100 },
+	{ 0x87c4, 0x07060504 },
+	{ 0x87c8, 0x0b0a0908 },
+	{ 0x87cc, 0x0f0e0d0c },
+	{ 0x87d0, 0x13121110 },
+	{ 0x87d4, 0x17161514 },
+	{ 0x87d8, 0x1b1a1918 },
+	{ 0x87dc, 0x1f1e1d1c },
+	/* loop ? */
+	{ 0x87e0, 0x03020100 },
+	{ 0x87e4, 0x07060504 },
+	{ 0x87e8, 0x0b0a0908 },
+	{ 0x87ec, 0x0f0e0d0c },
+	{ 0x87f0, 0x13121110 },
+	{ 0x87f4, 0x17161514 },
+	{ 0x87f8, 0x1b1a1918 },
+	{ 0x87fc, 0x1f1e1d1c },
+	/* PHY registers */
+	/*{ AR5K_PHY_AGC, 0x00000000 },*/
+	{ AR5K_PHY(3),	0xad848e19 },
+	{ AR5K_PHY(4),	0x7d28e000 },
+	{ AR5K_PHY_TIMING_3, 0x9c0a9f6b },
+	{ AR5K_PHY_ACT,	0x00000000 },
+	/*{ AR5K_PHY(11), 0x00022ffe },*/
+	/*{ AR5K_PHY(15), 0x00020100 },*/
+	{ AR5K_PHY(16),	0x206a017a },
+	/*{ AR5K_PHY(19), 0x1284613c },*/
+	{ AR5K_PHY(21),	0x00000859 },
+	{ AR5K_PHY(64),	0x00000000 },
+	{ AR5K_PHY(65),	0x00000000 },
+	{ AR5K_PHY(66),	0x00000000 },
+	{ AR5K_PHY(67),	0x00800000 },
+	{ AR5K_PHY(68),	0x00000001 },
+	/*{ AR5K_PHY(71), 0x0000092a },*/ /* Old value */
+	{ AR5K_PHY(71),	0x00000c80 },
+	{ AR5K_PHY_IQ,	0x05100000 },
+	{ AR5K_PHY(74), 0x00000001 },
+	{ AR5K_PHY(75), 0x00000004 },
+	{ AR5K_PHY_TXPOWER_RATE1, 0x1e1f2022 },
+	{ AR5K_PHY_TXPOWER_RATE2, 0x0a0b0c0d },
+	{ AR5K_PHY_TXPOWER_RATE_MAX, 0x0000003f },
+	/*{ AR5K_PHY(80), 0x00000004 },*/
+	{ AR5K_PHY(82), 0x9280b212 },
+	{ AR5K_PHY_RADAR, 0x5d50e188 },
+	/*{ AR5K_PHY(86), 0x000000ff },*/
+	{ AR5K_PHY(87), 0x004b6a8e },
+	{ AR5K_PHY(90),	0x000003ce },
+	{ AR5K_PHY(92),	0x192fb515 },
+	/*{ AR5K_PHY(93), 0x00000000 },*/
+	{ AR5K_PHY(94),	0x00000001 },
+	{ AR5K_PHY(95),	0x00000000 },
+	/*{ AR5K_PHY(644), 0x0080a333 },*/ /* Old value */
+	/*{ AR5K_PHY(645), 0x00206c10 },*/ /* Old value */
+	{ AR5K_PHY(644), 0x00806333 },
+	{ AR5K_PHY(645), 0x00106c10 },
+	{ AR5K_PHY(646), 0x009c4060 },
+	/*{ AR5K_PHY(647), 0x1483800a },*/ /* Old value */
+	{ AR5K_PHY(647), 0x1483800a },
+	{ AR5K_PHY(648), 0x01831061 },
+	{ AR5K_PHY(649), 0x00000400 },
+	/*{ AR5K_PHY(650), 0x000001b5 },*/
+	{ AR5K_PHY(651), 0x00000000 },
+	{ AR5K_PHY_TXPOWER_RATE3, 0x20202020 },
+	{ AR5K_PHY_TXPOWER_RATE2, 0x20202020 },
+	/*{ AR5K_PHY(655), 0x13c889af },*/
+	{ AR5K_PHY(656), 0x38490a20 },
+	{ AR5K_PHY(657), 0x00007bb6 },
+	{ AR5K_PHY(658), 0x0fff3ffc },
+	/*{ AR5K_PHY_CCKTXCTL, 0x00000000 },*/
+};
+
+/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */
+static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
+	{ AR5K_PHY(640),
+	/*	  a/XR	      aTurbo	  b	      g (DYN)	  gTurbo */
+		{ 0x00000008, 0x00000008, 0x0000000b, 0x0000000e, 0x0000000e } },
+	{ AR5K_PHY(0),
+		{ 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(0),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(1),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(2),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(3),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(4),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(5),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(6),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(7),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(8),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_QUEUE_DFS_LOCAL_IFS(9),
+		{ 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+	{ AR5K_DCU_GBL_IFS_SIFS,
+		{ 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } },
+	{ AR5K_DCU_GBL_IFS_SLOT,
+		{ 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } },
+	{ AR5K_DCU_GBL_IFS_EIFS,
+		{ 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } },
+	{ AR5K_DCU_GBL_IFS_MISC,
+		{ 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } },
+	{ AR5K_TIME_OUT,
+		{ 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } },
+	{ AR5K_PHY_TURBO,
+		{ 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } },
+	{ AR5K_PHY(8),
+		{ 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } },
+	{ AR5K_PHY(9),
+		{ 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY(17),
+		{ 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
+	{ AR5K_PHY_AGCCTL,
+		{ 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } },
+	{ AR5K_PHY_NF,
+		{ 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+	{ AR5K_PHY(26),
+		{ 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } },
+	{ AR5K_PHY(70),
+		{ 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } },
+	{ AR5K_PHY(73),
+		{ 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } },
+	{ 0xa230,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } },
+};
+
+/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */
+/* New dump pending */
+static const struct ath5k_ini_mode ar5212_rf5111_ini_mode_end[] = {
+	{ AR5K_PHY(640), /* This one differs from ar5212_ini_mode_start ! */
+	/*	  a/XR	      aTurbo	  b	      g (DYN)	  gTurbo */
+		{ 0x00000000, 0x00000000, 0x00000003, 0x00000006, 0x00000006 } },
+	{ AR5K_TXCFG,
+		{ 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+	{ AR5K_USEC_5211,
+		{ 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } },
+	{ AR5K_PHY(10),
+		{ 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY(13),
+		{ 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY(14),
+		{ 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY(18),
+		{ 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } },
+	{ AR5K_PHY(20),
+		{ 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+	{ AR5K_PHY_SIG,
+		{ 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+		{ 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } },
+	{ AR5K_PHY(27),
+		{ 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } },
+	{ AR5K_PHY_RX_DELAY,
+		{ 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+		{ 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+		{ 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } },
+	{ 0xa21c,
+		{ 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+	{ AR5K_DCU_FP,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_AGC,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY(11),
+		{ 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe } },
+	{ AR5K_PHY(15),
+		{ 0x00020100, 0x00020100, 0x00020100, 0x00020100, 0x00020100 } },
+	{ AR5K_PHY(19),
+		{ 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c } },
+	{ AR5K_PHY_PAPD_PROBE,
+		{ 0x00004883, 0x00004883, 0x00004883, 0x00004883, 0x00004883 } },
+	{ AR5K_PHY(80),
+		{ 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 } },
+	{ AR5K_PHY(86),
+		{ 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } },
+	{ AR5K_PHY(93),
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_SPENDING,
+		{ 0x00000018, 0x00000018, 0x00000018, 0x00000018, 0x00000018 } },
+	{ AR5K_PHY_CCKTXCTL,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY(642),
+		{ 0xd03e6788, 0xd03e6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ 0xa23c,
+		{ 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } },
+};
+
+/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */
+/* XXX: No dumps for turbog yet, but i found settings from old values so it should be ok */
+static const struct ath5k_ini_mode ar5212_rf5112_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	  a/XR	      aTurbo	  b	      g (DYN)	  gTurbo */
+		{ 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+	{ AR5K_USEC_5211,
+		{ 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY(10),
+		{ 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY(13),
+		{ 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY(14),
+		{ 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY(18),
+		{ 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } },
+	{ AR5K_PHY(20),
+		{ 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+	{ AR5K_PHY_SIG,
+		{ 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+		{ 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
+	{ AR5K_PHY(27),
+		{ 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	{ AR5K_PHY_RX_DELAY,
+		{ 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+		{ 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } },
+	{ AR5K_PHY_CCKTXCTL,
+		{ 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } },
+	{ AR5K_PHY(642),
+		{ 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+		{ 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } },
+	{ 0xa21c,
+		{ 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+	{ AR5K_DCU_FP,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_AGC,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY(11),
+		{ 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe } },
+	{ AR5K_PHY(15),
+		{ 0x00020100, 0x00020100, 0x00020100, 0x00020100, 0x00020100 } },
+	{ AR5K_PHY(19),
+		{ 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c } },
+	{ AR5K_PHY_PAPD_PROBE,
+		{ 0x00004882, 0x00004882, 0x00004882, 0x00004882, 0x00004882 } },
+	{ AR5K_PHY(80),
+		{ 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 } },
+	{ AR5K_PHY(86),
+		{ 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } },
+	{ AR5K_PHY(93),
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0xa228,
+		{ 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5 } },
+	{ 0xa23c,
+		{ 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } },
+};
+
+/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */
+/* XXX: No dumps for turbog yet, so turbog is the same with g here with some
+ * minor tweaking based on dumps from other chips */
+static const struct ath5k_ini_mode rf5413_ini_mode_end[] = {
+	{ AR5K_TXCFG,
+	/*	  a/XR	      aTurbo	  b	      g		  gTurbo */
+		{ 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+	{ AR5K_USEC_5211,
+		{ 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+	{ AR5K_PHY(10),
+		{ 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+	{ AR5K_PHY(13),
+		{ 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+	{ AR5K_PHY(14),
+		{ 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+	{ AR5K_PHY(18),
+		{ 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } },
+	{ AR5K_PHY(20),
+		{ 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
+	{ AR5K_PHY_SIG,
+		{ 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+	{ AR5K_PHY_AGCCOARSE,
+		{ 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+	{ AR5K_PHY(27),
+		{ 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+	{ AR5K_PHY_RX_DELAY,
+		{ 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+	{ AR5K_PHY_FRAME_CTL_5211,
+		{ 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+	{ AR5K_PHY_CCKTXCTL,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY(642),
+		{ 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+	{ AR5K_PHY_GAIN_2GHZ,
+		{ 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } },
+	{ 0xa21c,
+		{ 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+	{ 0xa300,
+		{ 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } },
+	{ 0xa304,
+		{ 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } },
+	{ 0xa308,
+		{ 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } },
+	{ 0xa30c,
+		{ 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
+	{ 0xa310,
+		{ 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } },
+	{ 0xa314,
+		{ 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
+	{ 0xa318,
+		{ 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
+	{ 0xa31c,
+		{ 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
+	{ 0xa320,
+		{ 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } },
+	{ 0xa324,
+		{ 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } },
+	{ 0xa328,
+		{ 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } },
+	{ 0xa32c,
+		{ 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } },
+	{ 0xa330,
+		{ 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } },
+	{ 0xa334,
+		{ 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
+	{ AR5K_DCU_FP,
+		{ 0x000003e0, 0x000003e0, 0x000003e0, 0x000003e0, 0x000003e0 } },
+	{ 0x4068,
+		{ 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
+	{ 0x8060,
+		{ 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f } },
+	{ 0x809c,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x80a0,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x8118,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x811c,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x8120,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x8124,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x8128,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x812c,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x8130,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x8134,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x8138,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x813c,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0x8140,
+		{ 0x800003f9, 0x800003f9, 0x800003f9, 0x800003f9, 0x800003f9 } },
+	{ 0x8144,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY_AGC,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY(11),
+		{ 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000 } },
+	{ AR5K_PHY(15),
+		{ 0x00200400, 0x00200400, 0x00200400, 0x00200400, 0x00200400 } },
+	{ AR5K_PHY(19),
+		{ 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c } },
+	{ AR5K_PHY_SCR,
+		{ 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f } },
+	{ AR5K_PHY_SLMT,
+		{ 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
+	{ AR5K_PHY_SCAL,
+		{ 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+	{ AR5K_PHY(86),
+		{ 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff } },
+	{ AR5K_PHY(96),
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY(97),
+		{ 0x02800000, 0x02800000, 0x02800000, 0x02800000, 0x02800000 } },
+	{ AR5K_PHY(104),
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY(120),
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ AR5K_PHY(121),
+		{ 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa } },
+	{ AR5K_PHY(122),
+		{ 0x3c466478, 0x3c466478, 0x3c466478, 0x3c466478, 0x3c466478 } },
+	{ AR5K_PHY(123),
+		{ 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa } },
+	{ AR5K_PHY_SCLOCK,
+		{ 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c } },
+	{ AR5K_PHY_SDELAY,
+		{ 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } },
+	{ AR5K_PHY_SPENDING,
+		{ 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000014 } },
+	{ 0xa228,
+		{ 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5 } },
+	{ 0xa23c,
+		{ 0x93c889af, 0x93c889af, 0x93c889af, 0x93c889af, 0x93c889af } },
+	{ 0xa24c,
+		{ 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
+	{ 0xa250,
+		{ 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000 } },
+	{ 0xa254,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0xa258,
+		{ 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380 } },
+	{ 0xa25c,
+		{ 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01 } },
+	{ 0xa260,
+		{ 0x5f690f01, 0x5f690f01, 0x5f690f01, 0x5f690f01, 0x5f690f01 } },
+	{ 0xa264,
+		{ 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11 } },
+	{ 0xa268,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0xa26c,
+		{ 0x0c30c16a, 0x0c30c16a, 0x0c30c16a, 0x0c30c16a, 0x0c30c16a } },
+	{ 0xa270,
+		{ 0x00820820, 0x00820820, 0x00820820, 0x00820820, 0x00820820 } },
+	{ 0xa274,
+		{ 0x081b7caa, 0x081b7caa, 0x081b7caa, 0x081b7caa, 0x081b7caa } },
+	{ 0xa278,
+		{ 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce } },
+	{ 0xa27c,
+		{ 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce } },
+	{ 0xa338,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0xa33c,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0xa340,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0xa344,
+		{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0xa348,
+		{ 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } },
+	{ 0xa34c,
+		{ 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } },
+	{ 0xa350,
+		{ 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } },
+	{ 0xa354,
+		{ 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff } },
+	{ 0xa358,
+		{ 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f } },
+	{ 0xa35c,
+		{ 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f } },
+	{ 0xa360,
+		{ 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207 } },
+	{ 0xa364,
+		{ 0x17601685, 0x17601685, 0x17601685, 0x17601685, 0x17601685 } },
+	{ 0xa368,
+		{ 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104 } },
+	{ 0xa36c,
+		{ 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03 } },
+	{ 0xa370,
+		{ 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883 } },
+	{ 0xa374,
+		{ 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803 } },
+	{ 0xa378,
+		{ 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682 } },
+	{ 0xa37c,
+		{ 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482 } },
+	{ 0xa380,
+		{ 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba } },
+	{ 0xa384,
+		{ 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } },
+};
+
+/*
+ * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with
+ * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI)
+ */
+
+/* RF5111 Initial BaseBand Gain settings */
+static const struct ath5k_ini rf5111_ini_bbgain[] = {
+	{ AR5K_BB_GAIN(0), 0x00000000 },
+	{ AR5K_BB_GAIN(1), 0x00000020 },
+	{ AR5K_BB_GAIN(2), 0x00000010 },
+	{ AR5K_BB_GAIN(3), 0x00000030 },
+	{ AR5K_BB_GAIN(4), 0x00000008 },
+	{ AR5K_BB_GAIN(5), 0x00000028 },
+	{ AR5K_BB_GAIN(6), 0x00000004 },
+	{ AR5K_BB_GAIN(7), 0x00000024 },
+	{ AR5K_BB_GAIN(8), 0x00000014 },
+	{ AR5K_BB_GAIN(9), 0x00000034 },
+	{ AR5K_BB_GAIN(10), 0x0000000c },
+	{ AR5K_BB_GAIN(11), 0x0000002c },
+	{ AR5K_BB_GAIN(12), 0x00000002 },
+	{ AR5K_BB_GAIN(13), 0x00000022 },
+	{ AR5K_BB_GAIN(14), 0x00000012 },
+	{ AR5K_BB_GAIN(15), 0x00000032 },
+	{ AR5K_BB_GAIN(16), 0x0000000a },
+	{ AR5K_BB_GAIN(17), 0x0000002a },
+	{ AR5K_BB_GAIN(18), 0x00000006 },
+	{ AR5K_BB_GAIN(19), 0x00000026 },
+	{ AR5K_BB_GAIN(20), 0x00000016 },
+	{ AR5K_BB_GAIN(21), 0x00000036 },
+	{ AR5K_BB_GAIN(22), 0x0000000e },
+	{ AR5K_BB_GAIN(23), 0x0000002e },
+	{ AR5K_BB_GAIN(24), 0x00000001 },
+	{ AR5K_BB_GAIN(25), 0x00000021 },
+	{ AR5K_BB_GAIN(26), 0x00000011 },
+	{ AR5K_BB_GAIN(27), 0x00000031 },
+	{ AR5K_BB_GAIN(28), 0x00000009 },
+	{ AR5K_BB_GAIN(29), 0x00000029 },
+	{ AR5K_BB_GAIN(30), 0x00000005 },
+	{ AR5K_BB_GAIN(31), 0x00000025 },
+	{ AR5K_BB_GAIN(32), 0x00000015 },
+	{ AR5K_BB_GAIN(33), 0x00000035 },
+	{ AR5K_BB_GAIN(34), 0x0000000d },
+	{ AR5K_BB_GAIN(35), 0x0000002d },
+	{ AR5K_BB_GAIN(36), 0x00000003 },
+	{ AR5K_BB_GAIN(37), 0x00000023 },
+	{ AR5K_BB_GAIN(38), 0x00000013 },
+	{ AR5K_BB_GAIN(39), 0x00000033 },
+	{ AR5K_BB_GAIN(40), 0x0000000b },
+	{ AR5K_BB_GAIN(41), 0x0000002b },
+	{ AR5K_BB_GAIN(42), 0x0000002b },
+	{ AR5K_BB_GAIN(43), 0x0000002b },
+	{ AR5K_BB_GAIN(44), 0x0000002b },
+	{ AR5K_BB_GAIN(45), 0x0000002b },
+	{ AR5K_BB_GAIN(46), 0x0000002b },
+	{ AR5K_BB_GAIN(47), 0x0000002b },
+	{ AR5K_BB_GAIN(48), 0x0000002b },
+	{ AR5K_BB_GAIN(49), 0x0000002b },
+	{ AR5K_BB_GAIN(50), 0x0000002b },
+	{ AR5K_BB_GAIN(51), 0x0000002b },
+	{ AR5K_BB_GAIN(52), 0x0000002b },
+	{ AR5K_BB_GAIN(53), 0x0000002b },
+	{ AR5K_BB_GAIN(54), 0x0000002b },
+	{ AR5K_BB_GAIN(55), 0x0000002b },
+	{ AR5K_BB_GAIN(56), 0x0000002b },
+	{ AR5K_BB_GAIN(57), 0x0000002b },
+	{ AR5K_BB_GAIN(58), 0x0000002b },
+	{ AR5K_BB_GAIN(59), 0x0000002b },
+	{ AR5K_BB_GAIN(60), 0x0000002b },
+	{ AR5K_BB_GAIN(61), 0x0000002b },
+	{ AR5K_BB_GAIN(62), 0x00000002 },
+	{ AR5K_BB_GAIN(63), 0x00000016 },
+};
+
+/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414) */
+static const struct ath5k_ini rf5112_ini_bbgain[] = {
+	{ AR5K_BB_GAIN(0), 0x00000000 },
+	{ AR5K_BB_GAIN(1), 0x00000001 },
+	{ AR5K_BB_GAIN(2), 0x00000002 },
+	{ AR5K_BB_GAIN(3), 0x00000003 },
+	{ AR5K_BB_GAIN(4), 0x00000004 },
+	{ AR5K_BB_GAIN(5), 0x00000005 },
+	{ AR5K_BB_GAIN(6), 0x00000008 },
+	{ AR5K_BB_GAIN(7), 0x00000009 },
+	{ AR5K_BB_GAIN(8), 0x0000000a },
+	{ AR5K_BB_GAIN(9), 0x0000000b },
+	{ AR5K_BB_GAIN(10), 0x0000000c },
+	{ AR5K_BB_GAIN(11), 0x0000000d },
+	{ AR5K_BB_GAIN(12), 0x00000010 },
+	{ AR5K_BB_GAIN(13), 0x00000011 },
+	{ AR5K_BB_GAIN(14), 0x00000012 },
+	{ AR5K_BB_GAIN(15), 0x00000013 },
+	{ AR5K_BB_GAIN(16), 0x00000014 },
+	{ AR5K_BB_GAIN(17), 0x00000015 },
+	{ AR5K_BB_GAIN(18), 0x00000018 },
+	{ AR5K_BB_GAIN(19), 0x00000019 },
+	{ AR5K_BB_GAIN(20), 0x0000001a },
+	{ AR5K_BB_GAIN(21), 0x0000001b },
+	{ AR5K_BB_GAIN(22), 0x0000001c },
+	{ AR5K_BB_GAIN(23), 0x0000001d },
+	{ AR5K_BB_GAIN(24), 0x00000020 },
+	{ AR5K_BB_GAIN(25), 0x00000021 },
+	{ AR5K_BB_GAIN(26), 0x00000022 },
+	{ AR5K_BB_GAIN(27), 0x00000023 },
+	{ AR5K_BB_GAIN(28), 0x00000024 },
+	{ AR5K_BB_GAIN(29), 0x00000025 },
+	{ AR5K_BB_GAIN(30), 0x00000028 },
+	{ AR5K_BB_GAIN(31), 0x00000029 },
+	{ AR5K_BB_GAIN(32), 0x0000002a },
+	{ AR5K_BB_GAIN(33), 0x0000002b },
+	{ AR5K_BB_GAIN(34), 0x0000002c },
+	{ AR5K_BB_GAIN(35), 0x0000002d },
+	{ AR5K_BB_GAIN(36), 0x00000030 },
+	{ AR5K_BB_GAIN(37), 0x00000031 },
+	{ AR5K_BB_GAIN(38), 0x00000032 },
+	{ AR5K_BB_GAIN(39), 0x00000033 },
+	{ AR5K_BB_GAIN(40), 0x00000034 },
+	{ AR5K_BB_GAIN(41), 0x00000035 },
+	{ AR5K_BB_GAIN(42), 0x00000035 },
+	{ AR5K_BB_GAIN(43), 0x00000035 },
+	{ AR5K_BB_GAIN(44), 0x00000035 },
+	{ AR5K_BB_GAIN(45), 0x00000035 },
+	{ AR5K_BB_GAIN(46), 0x00000035 },
+	{ AR5K_BB_GAIN(47), 0x00000035 },
+	{ AR5K_BB_GAIN(48), 0x00000035 },
+	{ AR5K_BB_GAIN(49), 0x00000035 },
+	{ AR5K_BB_GAIN(50), 0x00000035 },
+	{ AR5K_BB_GAIN(51), 0x00000035 },
+	{ AR5K_BB_GAIN(52), 0x00000035 },
+	{ AR5K_BB_GAIN(53), 0x00000035 },
+	{ AR5K_BB_GAIN(54), 0x00000035 },
+	{ AR5K_BB_GAIN(55), 0x00000035 },
+	{ AR5K_BB_GAIN(56), 0x00000035 },
+	{ AR5K_BB_GAIN(57), 0x00000035 },
+	{ AR5K_BB_GAIN(58), 0x00000035 },
+	{ AR5K_BB_GAIN(59), 0x00000035 },
+	{ AR5K_BB_GAIN(60), 0x00000035 },
+	{ AR5K_BB_GAIN(61), 0x00000035 },
+	{ AR5K_BB_GAIN(62), 0x00000010 },
+	{ AR5K_BB_GAIN(63), 0x0000001a },
+};
+
+
+/*
+ * Write initial register dump
+ */
+static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
+		const struct ath5k_ini *ini_regs, bool change_channel)
+{
+	unsigned int i;
+
+	/* Write initial registers */
+	for (i = 0; i < size; i++) {
+		/* On channel change there is
+		 * no need to mess with PCU */
+		if (change_channel &&
+				ini_regs[i].ini_register >= AR5K_PCU_MIN &&
+				ini_regs[i].ini_register <= AR5K_PCU_MAX)
+			continue;
+
+		switch (ini_regs[i].ini_mode) {
+		case AR5K_INI_READ:
+			/* Cleared on read */
+			ath5k_hw_reg_read(ah, ini_regs[i].ini_register);
+			break;
+		case AR5K_INI_WRITE:
+		default:
+			AR5K_REG_WAIT(i);
+			ath5k_hw_reg_write(ah, ini_regs[i].ini_value,
+					ini_regs[i].ini_register);
+		}
+	}
+}
+
+static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
+		unsigned int size, const struct ath5k_ini_mode *ini_mode,
+		u8 mode)
+{
+	unsigned int i;
+
+	for (i = 0; i < size; i++) {
+		AR5K_REG_WAIT(i);
+		ath5k_hw_reg_write(ah, ini_mode[i].mode_value[mode],
+			(u32)ini_mode[i].mode_register);
+	}
+
+}
+
+int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
+{
+	/*
+	 * Write initial register settings
+	 */
+
+	/* For AR5212 and combatible */
+	if (ah->ah_version == AR5K_AR5212){
+
+		/* First set of mode-specific settings */
+		ath5k_hw_ini_mode_registers(ah,
+			ARRAY_SIZE(ar5212_ini_mode_start),
+			ar5212_ini_mode_start, mode);
+
+		/*
+		 * Write initial settings common for all modes
+		 */
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini),
+					ar5212_ini, change_channel);
+
+		/* Second set of mode-specific settings */
+		if (ah->ah_radio == AR5K_RF5111){
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(ar5212_rf5111_ini_mode_end),
+					ar5212_rf5111_ini_mode_end, mode);
+			/* Baseband gain table */
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5111_ini_bbgain),
+					rf5111_ini_bbgain, change_channel);
+		} else if (ah->ah_radio == AR5K_RF5112){
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(ar5212_rf5112_ini_mode_end),
+					ar5212_rf5112_ini_mode_end, mode);
+			/* Baseband gain table */
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_bbgain),
+					rf5112_ini_bbgain, change_channel);
+		} else if (ah->ah_radio == AR5K_RF5413){
+			ath5k_hw_ini_mode_registers(ah,
+					ARRAY_SIZE(rf5413_ini_mode_end),
+					rf5413_ini_mode_end, mode);
+			/* Baseband gain table */
+			ath5k_hw_ini_registers(ah,
+					ARRAY_SIZE(rf5112_ini_bbgain),
+					rf5112_ini_bbgain, change_channel);
+		}
+	/* For AR5211 */
+	} else if (ah->ah_version == AR5K_AR5211) {
+
+		if(mode > 2){ /* AR5K_INI_VAL_11B */
+			ATH5K_ERR(ah->ah_sc,"unsupported channel mode: %d\n", mode);
+			return -EINVAL;
+		}
+
+		/* Mode-specific settings */
+		ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode),
+				ar5211_ini_mode, mode);
+
+		/*
+		 * Write initial settings common for all modes
+		 */
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini),
+				ar5211_ini, change_channel);
+
+		/* AR5211 only comes with 5111 */
+
+		/* Baseband gain table */
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain),
+				rf5111_ini_bbgain, change_channel);
+	/* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */
+	} else if (ah->ah_version == AR5K_AR5210) {
+		ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini),
+				ar5210_ini, change_channel);
+	}
+
+	return 0;
+}
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c
new file mode 100644
index 000000000000..b95941797141
--- /dev/null
+++ b/drivers/net/wireless/ath5k/phy.c
@@ -0,0 +1,2071 @@
+/*
+ * PHY functions
+ *
+ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/delay.h>
+
+#include "ath5k.h"
+#include "reg.h"
+#include "base.h"
+
+/* Struct to hold initial RF register values (RF Banks) */
+struct ath5k_ini_rf {
+	u8	rf_bank;	/* check out ath5k_reg.h */
+	u16	rf_register;	/* register address */
+	u32	rf_value[5];	/* register value for different modes (above) */
+};
+
+/*
+ * Mode-specific RF Gain table (64bytes) for RF5111/5112
+ * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial
+ * RF Gain values are included in AR5K_AR5210_INI)
+ */
+struct ath5k_ini_rfgain {
+	u16	rfg_register;	/* RF Gain register address */
+	u32	rfg_value[2];	/* [freq (see below)] */
+};
+
+struct ath5k_gain_opt {
+	u32			go_default;
+	u32			go_steps_count;
+	const struct ath5k_gain_opt_step	go_step[AR5K_GAIN_STEP_COUNT];
+};
+
+/* RF5111 mode-specific init registers */
+static const struct ath5k_ini_rf rfregs_5111[] = {
+	{ 0, 0x989c,
+	/*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 0, 0x989c,
+	    { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } },
+	{ 0, 0x989c,
+	    { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } },
+	{ 0, 0x98d4,
+	    { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } },
+	{ 1, 0x98d4,
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d4,
+	    { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } },
+	{ 3, 0x98d8,
+	    { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
+	{ 6, 0x989c,
+	    { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } },
+	{ 6, 0x989c,
+	    { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } },
+	{ 6, 0x989c,
+	    { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } },
+	{ 6, 0x989c,
+	    { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } },
+	{ 6, 0x989c,
+	    { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } },
+	{ 6, 0x98d4,
+	    { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } },
+	{ 7, 0x989c,
+	    { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } },
+	{ 7, 0x989c,
+	    { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
+	{ 7, 0x989c,
+	    { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
+	{ 7, 0x989c,
+	    { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } },
+	{ 7, 0x989c,
+	    { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } },
+	{ 7, 0x989c,
+	    { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } },
+	{ 7, 0x989c,
+	    { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } },
+};
+
+/* Initial RF Gain settings for RF5111 */
+static const struct ath5k_ini_rfgain rfgain_5111[] = {
+	/*			      5Ghz	2Ghz	*/
+	{ AR5K_RF_GAIN(0),	{ 0x000001a9, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x000001e9, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000029, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x00000069, 0x00000150 } },
+	{ AR5K_RF_GAIN(4),	{ 0x00000199, 0x00000190 } },
+	{ AR5K_RF_GAIN(5),	{ 0x000001d9, 0x000001d0 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000019, 0x00000010 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000059, 0x00000044 } },
+	{ AR5K_RF_GAIN(8),	{ 0x00000099, 0x00000084 } },
+	{ AR5K_RF_GAIN(9),	{ 0x000001a5, 0x00000148 } },
+	{ AR5K_RF_GAIN(10),	{ 0x000001e5, 0x00000188 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000025, 0x000001c8 } },
+	{ AR5K_RF_GAIN(12),	{ 0x000001c8, 0x00000014 } },
+	{ AR5K_RF_GAIN(13),	{ 0x00000008, 0x00000042 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000048, 0x00000082 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000088, 0x00000178 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000198, 0x000001b8 } },
+	{ AR5K_RF_GAIN(17),	{ 0x000001d8, 0x000001f8 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000018, 0x00000012 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000058, 0x00000052 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000098, 0x00000092 } },
+	{ AR5K_RF_GAIN(21),	{ 0x000001a4, 0x0000017c } },
+	{ AR5K_RF_GAIN(22),	{ 0x000001e4, 0x000001bc } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000024, 0x000001fc } },
+	{ AR5K_RF_GAIN(24),	{ 0x00000064, 0x0000000a } },
+	{ AR5K_RF_GAIN(25),	{ 0x000000a4, 0x0000004a } },
+	{ AR5K_RF_GAIN(26),	{ 0x000000e4, 0x0000008a } },
+	{ AR5K_RF_GAIN(27),	{ 0x0000010a, 0x0000015a } },
+	{ AR5K_RF_GAIN(28),	{ 0x0000014a, 0x0000019a } },
+	{ AR5K_RF_GAIN(29),	{ 0x0000018a, 0x000001da } },
+	{ AR5K_RF_GAIN(30),	{ 0x000001ca, 0x0000000e } },
+	{ AR5K_RF_GAIN(31),	{ 0x0000000a, 0x0000004e } },
+	{ AR5K_RF_GAIN(32),	{ 0x0000004a, 0x0000008e } },
+	{ AR5K_RF_GAIN(33),	{ 0x0000008a, 0x0000015e } },
+	{ AR5K_RF_GAIN(34),	{ 0x000001ba, 0x0000019e } },
+	{ AR5K_RF_GAIN(35),	{ 0x000001fa, 0x000001de } },
+	{ AR5K_RF_GAIN(36),	{ 0x0000003a, 0x00000009 } },
+	{ AR5K_RF_GAIN(37),	{ 0x0000007a, 0x00000049 } },
+	{ AR5K_RF_GAIN(38),	{ 0x00000186, 0x00000089 } },
+	{ AR5K_RF_GAIN(39),	{ 0x000001c6, 0x00000179 } },
+	{ AR5K_RF_GAIN(40),	{ 0x00000006, 0x000001b9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x00000046, 0x000001f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x00000086, 0x00000039 } },
+	{ AR5K_RF_GAIN(43),	{ 0x000000c6, 0x00000079 } },
+	{ AR5K_RF_GAIN(44),	{ 0x000000c6, 0x000000b9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x000000c6, 0x000001bd } },
+	{ AR5K_RF_GAIN(46),	{ 0x000000c6, 0x000001fd } },
+	{ AR5K_RF_GAIN(47),	{ 0x000000c6, 0x0000003d } },
+	{ AR5K_RF_GAIN(48),	{ 0x000000c6, 0x0000007d } },
+	{ AR5K_RF_GAIN(49),	{ 0x000000c6, 0x000000bd } },
+	{ AR5K_RF_GAIN(50),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(51),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(52),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(53),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(54),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(55),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(56),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(57),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(58),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(59),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(60),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(61),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(62),	{ 0x000000c6, 0x000000fd } },
+	{ AR5K_RF_GAIN(63),	{ 0x000000c6, 0x000000fd } },
+};
+
+static const struct ath5k_gain_opt rfgain_opt_5111 = {
+	4,
+	9,
+	{
+		{ { 4, 1, 1, 1 }, 6 },
+		{ { 4, 0, 1, 1 }, 4 },
+		{ { 3, 1, 1, 1 }, 3 },
+		{ { 4, 0, 0, 1 }, 1 },
+		{ { 4, 1, 1, 0 }, 0 },
+		{ { 4, 0, 1, 0 }, -2 },
+		{ { 3, 1, 1, 0 }, -3 },
+		{ { 4, 0, 0, 0 }, -4 },
+		{ { 2, 1, 1, 0 }, -6 }
+	}
+};
+
+/* RF5112 mode-specific init registers */
+static const struct ath5k_ini_rf rfregs_5112[] = {
+	{ 1, 0x98d4,
+	/*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
+	{ 3, 0x98dc,
+	    { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
+	{ 6, 0x989c,
+	    { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } },
+	{ 6, 0x989c,
+	    { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } },
+	{ 6, 0x989c,
+	    { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } },
+	{ 6, 0x989c,
+	    { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } },
+	{ 6, 0x989c,
+	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+	{ 6, 0x989c,
+	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+	{ 6, 0x989c,
+	    { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } },
+	{ 6, 0x989c,
+	    { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } },
+	{ 6, 0x989c,
+	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+	{ 6, 0x989c,
+	    { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
+	{ 6, 0x989c,
+	    { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } },
+	{ 6, 0x989c,
+	    { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } },
+	{ 6, 0x989c,
+	    { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
+	{ 6, 0x989c,
+	    { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } },
+	{ 6, 0x989c,
+	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+	{ 6, 0x989c,
+	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+	{ 6, 0x989c,
+	    { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } },
+	{ 6, 0x989c,
+	    { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } },
+	{ 6, 0x989c,
+	    { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
+	{ 6, 0x989c,
+	    { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } },
+	{ 6, 0x989c,
+	    { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } },
+	{ 6, 0x989c,
+	    { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } },
+	{ 6, 0x989c,
+	    { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } },
+	{ 6, 0x989c,
+	    { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } },
+	{ 6, 0x989c,
+	    { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } },
+	{ 6, 0x989c,
+	    { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } },
+	{ 6, 0x989c,
+	    { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } },
+	{ 6, 0x989c,
+	    { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } },
+	{ 6, 0x989c,
+	    { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } },
+	{ 6, 0x98d0,
+	    { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } },
+	{ 7, 0x989c,
+	    { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
+	{ 7, 0x989c,
+	    { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
+	{ 7, 0x989c,
+	    { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } },
+	{ 7, 0x989c,
+	    { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
+	{ 7, 0x989c,
+	    { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } },
+	{ 7, 0x989c,
+	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+	{ 7, 0x989c,
+	    { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
+	{ 7, 0x989c,
+	    { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } },
+	{ 7, 0x989c,
+	    { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } },
+	{ 7, 0x989c,
+	    { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
+	{ 7, 0x989c,
+	    { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
+	{ 7, 0x989c,
+	    { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
+	{ 7, 0x98c4,
+	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+};
+
+/* RF5112A mode-specific init registers */
+static const struct ath5k_ini_rf rfregs_5112a[] = {
+	{ 1, 0x98d4,
+	/*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
+	{ 3, 0x98dc,
+	    { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
+	{ 6, 0x989c,
+	    { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } },
+	{ 6, 0x989c,
+	    { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } },
+	{ 6, 0x989c,
+	    { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } },
+	{ 6, 0x989c,
+	    { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } },
+	{ 6, 0x989c,
+	    { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } },
+	{ 6, 0x989c,
+	    { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } },
+	{ 6, 0x989c,
+	    { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } },
+	{ 6, 0x989c,
+	    { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
+	{ 6, 0x989c,
+	    { 0x00190000, 0x00190000, 0x00190000, 0x00190000, 0x00190000 } },
+	{ 6, 0x989c,
+	    { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
+	{ 6, 0x989c,
+	    { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } },
+	{ 6, 0x989c,
+	    { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } },
+	{ 6, 0x989c,
+	    { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } },
+	{ 6, 0x989c,
+	    { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, 0x989c,
+	    { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
+	{ 6, 0x989c,
+	    { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } },
+	{ 6, 0x989c,
+	    { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } },
+	{ 6, 0x989c,
+	    { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
+	{ 6, 0x989c,
+	    { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } },
+	{ 6, 0x989c,
+	    { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } },
+	{ 6, 0x989c,
+	    { 0x00020080, 0x00020080, 0x00020080, 0x00020080, 0x00020080 } },
+	{ 6, 0x989c,
+	    { 0x00080009, 0x00080009, 0x00080009, 0x00080009, 0x00080009 } },
+	{ 6, 0x989c,
+	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } },
+	{ 6, 0x989c,
+	    { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } },
+	{ 6, 0x989c,
+	    { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } },
+	{ 6, 0x989c,
+	    { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } },
+	{ 6, 0x989c,
+	    { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } },
+	{ 6, 0x98d8,
+	    { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } },
+	{ 7, 0x989c,
+	    { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
+	{ 7, 0x989c,
+	    { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
+	{ 7, 0x989c,
+	    { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } },
+	{ 7, 0x989c,
+	    { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
+	{ 7, 0x989c,
+	    { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } },
+	{ 7, 0x989c,
+	    { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
+	{ 7, 0x989c,
+	    { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
+	{ 7, 0x989c,
+	    { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } },
+	{ 7, 0x989c,
+	    { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } },
+	{ 7, 0x989c,
+	    { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
+	{ 7, 0x989c,
+	    { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
+	{ 7, 0x989c,
+	    { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
+	{ 7, 0x98c4,
+	    { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+};
+
+
+static const struct ath5k_ini_rf rfregs_2112a[] = {
+	{ 1, AR5K_RF_BUFFER_CONTROL_4,
+	/*	   mode b	mode g	  mode gTurbo */
+		{ 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, AR5K_RF_BUFFER_CONTROL_3,
+		{ 0x03060408, 0x03060408, 0x03070408 } },
+	{ 3, AR5K_RF_BUFFER_CONTROL_6,
+		{ 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x0a000000, 0x0a000000, 0x0a000000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00800000, 0x00800000, 0x00800000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00010000, 0x00010000, 0x00010000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00180000, 0x00180000, 0x00180000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x006e0000, 0x006e0000, 0x006e0000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00c70000, 0x00c70000, 0x00c70000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x004b0000, 0x004b0000, 0x004b0000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x04480000, 0x04480000, 0x04480000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00e40000, 0x00e40000, 0x00e40000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x043f0000, 0x043f0000, 0x043f0000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x0c0c0000, 0x0c0c0000, 0x0c0c0000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x02190000, 0x02190000, 0x02190000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00240000, 0x00240000, 0x00240000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00b40000, 0x00b40000, 0x00b40000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00990000, 0x00990000, 0x00990000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00500000, 0x00500000, 0x00500000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x002a0000, 0x002a0000, 0x002a0000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00120000, 0x00120000, 0x00120000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0xc0320000, 0xc0320000, 0xc0320000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x01740000, 0x01740000, 0x01740000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00110000, 0x00110000, 0x00110000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x86280000, 0x86280000, 0x86280000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x31840000, 0x31840000, 0x31840000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00f20080, 0x00f20080, 0x00f20080 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00070019, 0x00070019, 0x00070019 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x000000b2, 0x000000b2, 0x000000b2 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00b02184, 0x00b02184, 0x00b02184 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x004125a4, 0x004125a4, 0x004125a4 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x00119220, 0x00119220, 0x00119220 } },
+	{ 6, AR5K_RF_BUFFER,
+		{ 0x001a4800, 0x001a4800, 0x001a4800 } },
+	{ 6, AR5K_RF_BUFFER_CONTROL_5,
+		{ 0x000b0230, 0x000b0230, 0x000b0230 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x00000094, 0x00000094, 0x00000094 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x00000091, 0x00000091, 0x00000091 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x00000012, 0x00000012, 0x00000012 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x00000080, 0x00000080, 0x00000080 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x000000d9, 0x000000d9, 0x000000d9 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x00000060, 0x00000060, 0x00000060 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x000000f0, 0x000000f0, 0x000000f0 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x000000a2, 0x000000a2, 0x000000a2 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x00000052, 0x00000052, 0x00000052 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x000000d4, 0x000000d4, 0x000000d4 } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x000014cc, 0x000014cc, 0x000014cc } },
+	{ 7, AR5K_RF_BUFFER,
+		{ 0x0000048c, 0x0000048c, 0x0000048c } },
+	{ 7, AR5K_RF_BUFFER_CONTROL_1,
+		{ 0x00000003, 0x00000003, 0x00000003 } },
+};
+
+/* RF5413/5414 mode-specific init registers */
+static const struct ath5k_ini_rf rfregs_5413[] = {
+	{ 1, 0x98d4,
+	/*    mode a/XR   mode aTurbo mode b      mode g      mode gTurbo */
+	    { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
+	{ 2, 0x98d0,
+	    { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
+	{ 3, 0x98dc,
+	    { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } },
+	{ 6, 0x989c,
+	    { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } },
+	{ 6, 0x989c,
+	    { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } },
+	{ 6, 0x989c,
+	    { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } },
+	{ 6, 0x989c,
+	    { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
+	{ 6, 0x989c,
+	    { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
+	{ 6, 0x989c,
+	    { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+	{ 6, 0x989c,
+	    { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } },
+	{ 6, 0x989c,
+	    { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } },
+	{ 6, 0x989c,
+	    { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } },
+	{ 6, 0x989c,
+	    { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } },
+	{ 6, 0x989c,
+	    { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } },
+	{ 6, 0x989c,
+	    { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } },
+	{ 6, 0x989c,
+	    { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
+	{ 6, 0x989c,
+	    { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } },
+	{ 6, 0x989c,
+	    { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
+	{ 6, 0x989c,
+	    { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } },
+	{ 6, 0x989c,
+	    { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } },
+	{ 6, 0x989c,
+	    { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } },
+	{ 6, 0x989c,
+	    { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } },
+	{ 6, 0x989c,
+	    { 0x00510040, 0x00510040, 0x005100a0, 0x005100a0, 0x005100a0 } },
+	{ 6, 0x989c,
+	    { 0x0050006a, 0x0050006a, 0x005000dd, 0x005000dd, 0x005000dd } },
+	{ 6, 0x989c,
+	    { 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } },
+	{ 6, 0x989c,
+	    { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+	{ 6, 0x989c,
+	    { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } },
+	{ 6, 0x989c,
+	    { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00003600 } },
+	{ 6, 0x98c8,
+	    { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } },
+	{ 7, 0x989c,
+	    { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
+	{ 7, 0x989c,
+	    { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
+	{ 7, 0x98cc,
+	    { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+};
+
+
+/* Initial RF Gain settings for RF5112 */
+static const struct ath5k_ini_rfgain rfgain_5112[] = {
+	/*			      5Ghz	2Ghz	*/
+	{ AR5K_RF_GAIN(0),	{ 0x00000007, 0x00000007 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000047, 0x00000047 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000087, 0x00000087 } },
+	{ AR5K_RF_GAIN(3),	{ 0x000001a0, 0x000001a0 } },
+	{ AR5K_RF_GAIN(4),	{ 0x000001e0, 0x000001e0 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000020, 0x00000020 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000060, 0x00000060 } },
+	{ AR5K_RF_GAIN(7),	{ 0x000001a1, 0x000001a1 } },
+	{ AR5K_RF_GAIN(8),	{ 0x000001e1, 0x000001e1 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000021, 0x00000021 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000061, 0x00000061 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000162, 0x00000162 } },
+	{ AR5K_RF_GAIN(12),	{ 0x000001a2, 0x000001a2 } },
+	{ AR5K_RF_GAIN(13),	{ 0x000001e2, 0x000001e2 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000022, 0x00000022 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000062, 0x00000062 } },
+	{ AR5K_RF_GAIN(16),	{ 0x00000163, 0x00000163 } },
+	{ AR5K_RF_GAIN(17),	{ 0x000001a3, 0x000001a3 } },
+	{ AR5K_RF_GAIN(18),	{ 0x000001e3, 0x000001e3 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000023, 0x00000023 } },
+	{ AR5K_RF_GAIN(20),	{ 0x00000063, 0x00000063 } },
+	{ AR5K_RF_GAIN(21),	{ 0x00000184, 0x00000184 } },
+	{ AR5K_RF_GAIN(22),	{ 0x000001c4, 0x000001c4 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000004, 0x00000004 } },
+	{ AR5K_RF_GAIN(24),	{ 0x000001ea, 0x0000000b } },
+	{ AR5K_RF_GAIN(25),	{ 0x0000002a, 0x0000004b } },
+	{ AR5K_RF_GAIN(26),	{ 0x0000006a, 0x0000008b } },
+	{ AR5K_RF_GAIN(27),	{ 0x000000aa, 0x000001ac } },
+	{ AR5K_RF_GAIN(28),	{ 0x000001ab, 0x000001ec } },
+	{ AR5K_RF_GAIN(29),	{ 0x000001eb, 0x0000002c } },
+	{ AR5K_RF_GAIN(30),	{ 0x0000002b, 0x00000012 } },
+	{ AR5K_RF_GAIN(31),	{ 0x0000006b, 0x00000052 } },
+	{ AR5K_RF_GAIN(32),	{ 0x000000ab, 0x00000092 } },
+	{ AR5K_RF_GAIN(33),	{ 0x000001ac, 0x00000193 } },
+	{ AR5K_RF_GAIN(34),	{ 0x000001ec, 0x000001d3 } },
+	{ AR5K_RF_GAIN(35),	{ 0x0000002c, 0x00000013 } },
+	{ AR5K_RF_GAIN(36),	{ 0x0000003a, 0x00000053 } },
+	{ AR5K_RF_GAIN(37),	{ 0x0000007a, 0x00000093 } },
+	{ AR5K_RF_GAIN(38),	{ 0x000000ba, 0x00000194 } },
+	{ AR5K_RF_GAIN(39),	{ 0x000001bb, 0x000001d4 } },
+	{ AR5K_RF_GAIN(40),	{ 0x000001fb, 0x00000014 } },
+	{ AR5K_RF_GAIN(41),	{ 0x0000003b, 0x0000003a } },
+	{ AR5K_RF_GAIN(42),	{ 0x0000007b, 0x0000007a } },
+	{ AR5K_RF_GAIN(43),	{ 0x000000bb, 0x000000ba } },
+	{ AR5K_RF_GAIN(44),	{ 0x000001bc, 0x000001bb } },
+	{ AR5K_RF_GAIN(45),	{ 0x000001fc, 0x000001fb } },
+	{ AR5K_RF_GAIN(46),	{ 0x0000003c, 0x0000003b } },
+	{ AR5K_RF_GAIN(47),	{ 0x0000007c, 0x0000007b } },
+	{ AR5K_RF_GAIN(48),	{ 0x000000bc, 0x000000bb } },
+	{ AR5K_RF_GAIN(49),	{ 0x000000fc, 0x000001bc } },
+	{ AR5K_RF_GAIN(50),	{ 0x000000fc, 0x000001fc } },
+	{ AR5K_RF_GAIN(51),	{ 0x000000fc, 0x0000003c } },
+	{ AR5K_RF_GAIN(52),	{ 0x000000fc, 0x0000007c } },
+	{ AR5K_RF_GAIN(53),	{ 0x000000fc, 0x000000bc } },
+	{ AR5K_RF_GAIN(54),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(55),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(56),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(57),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(58),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(59),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(60),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(61),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(62),	{ 0x000000fc, 0x000000fc } },
+	{ AR5K_RF_GAIN(63),	{ 0x000000fc, 0x000000fc } },
+};
+
+/* Initial RF Gain settings for RF5413 */
+static const struct ath5k_ini_rfgain rfgain_5413[] = {
+	/*			      5Ghz	2Ghz	*/
+	{ AR5K_RF_GAIN(0),	{ 0x00000000, 0x00000000 } },
+	{ AR5K_RF_GAIN(1),	{ 0x00000040, 0x00000040 } },
+	{ AR5K_RF_GAIN(2),	{ 0x00000080, 0x00000080 } },
+	{ AR5K_RF_GAIN(3),	{ 0x000001a1, 0x00000161 } },
+	{ AR5K_RF_GAIN(4),	{ 0x000001e1, 0x000001a1 } },
+	{ AR5K_RF_GAIN(5),	{ 0x00000021, 0x000001e1 } },
+	{ AR5K_RF_GAIN(6),	{ 0x00000061, 0x00000021 } },
+	{ AR5K_RF_GAIN(7),	{ 0x00000188, 0x00000061 } },
+	{ AR5K_RF_GAIN(8),	{ 0x000001c8, 0x00000188 } },
+	{ AR5K_RF_GAIN(9),	{ 0x00000008, 0x000001c8 } },
+	{ AR5K_RF_GAIN(10),	{ 0x00000048, 0x00000008 } },
+	{ AR5K_RF_GAIN(11),	{ 0x00000088, 0x00000048 } },
+	{ AR5K_RF_GAIN(12),	{ 0x000001a9, 0x00000088 } },
+	{ AR5K_RF_GAIN(13),	{ 0x000001e9, 0x00000169 } },
+	{ AR5K_RF_GAIN(14),	{ 0x00000029, 0x000001a9 } },
+	{ AR5K_RF_GAIN(15),	{ 0x00000069, 0x000001e9 } },
+	{ AR5K_RF_GAIN(16),	{ 0x000001d0, 0x00000029 } },
+	{ AR5K_RF_GAIN(17),	{ 0x00000010, 0x00000069 } },
+	{ AR5K_RF_GAIN(18),	{ 0x00000050, 0x00000190 } },
+	{ AR5K_RF_GAIN(19),	{ 0x00000090, 0x000001d0 } },
+	{ AR5K_RF_GAIN(20),	{ 0x000001b1, 0x00000010 } },
+	{ AR5K_RF_GAIN(21),	{ 0x000001f1, 0x00000050 } },
+	{ AR5K_RF_GAIN(22),	{ 0x00000031, 0x00000090 } },
+	{ AR5K_RF_GAIN(23),	{ 0x00000071, 0x00000171 } },
+	{ AR5K_RF_GAIN(24),	{ 0x000001b8, 0x000001b1 } },
+	{ AR5K_RF_GAIN(25),	{ 0x000001f8, 0x000001f1 } },
+	{ AR5K_RF_GAIN(26),	{ 0x00000038, 0x00000031 } },
+	{ AR5K_RF_GAIN(27),	{ 0x00000078, 0x00000071 } },
+	{ AR5K_RF_GAIN(28),	{ 0x00000199, 0x00000198 } },
+	{ AR5K_RF_GAIN(29),	{ 0x000001d9, 0x000001d8 } },
+	{ AR5K_RF_GAIN(30),	{ 0x00000019, 0x00000018 } },
+	{ AR5K_RF_GAIN(31),	{ 0x00000059, 0x00000058 } },
+	{ AR5K_RF_GAIN(32),	{ 0x00000099, 0x00000098 } },
+	{ AR5K_RF_GAIN(33),	{ 0x000000d9, 0x00000179 } },
+	{ AR5K_RF_GAIN(34),	{ 0x000000f9, 0x000001b9 } },
+	{ AR5K_RF_GAIN(35),	{ 0x000000f9, 0x000001f9 } },
+	{ AR5K_RF_GAIN(36),	{ 0x000000f9, 0x00000039 } },
+	{ AR5K_RF_GAIN(37),	{ 0x000000f9, 0x00000079 } },
+	{ AR5K_RF_GAIN(38),	{ 0x000000f9, 0x000000b9 } },
+	{ AR5K_RF_GAIN(39),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(40),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(41),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(42),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(43),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(44),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(45),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(46),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(47),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(48),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(49),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(50),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(51),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(52),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(53),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(54),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(55),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(56),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(57),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(58),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(59),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(60),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(61),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(62),	{ 0x000000f9, 0x000000f9 } },
+	{ AR5K_RF_GAIN(63),	{ 0x000000f9, 0x000000f9 } },
+};
+
+static const struct ath5k_gain_opt rfgain_opt_5112 = {
+	1,
+	8,
+	{
+		{ { 3, 0, 0, 0, 0, 0, 0 }, 6 },
+		{ { 2, 0, 0, 0, 0, 0, 0 }, 0 },
+		{ { 1, 0, 0, 0, 0, 0, 0 }, -3 },
+		{ { 0, 0, 0, 0, 0, 0, 0 }, -6 },
+		{ { 0, 1, 1, 0, 0, 0, 0 }, -8 },
+		{ { 0, 1, 1, 0, 1, 1, 0 }, -10 },
+		{ { 0, 1, 0, 1, 1, 1, 0 }, -13 },
+		{ { 0, 1, 0, 1, 1, 0, 1 }, -16 },
+	}
+};
+
+/*
+ * Used to modify RF Banks before writing them to AR5K_RF_BUFFER
+ */
+static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits,
+		u32 first, u32 col, bool set)
+{
+	u32 mask, entry, last, data, shift, position;
+	s32 left;
+	int i;
+
+	data = 0;
+
+	if (rf == NULL)
+		/* should not happen */
+		return 0;
+
+	if (!(col <= 3 && bits <= 32 && first + bits <= 319)) {
+		ATH5K_PRINTF("invalid values at offset %u\n", offset);
+		return 0;
+	}
+
+	entry = ((first - 1) / 8) + offset;
+	position = (first - 1) % 8;
+
+	if (set == true)
+		data = ath5k_hw_bitswap(reg, bits);
+
+	for (i = shift = 0, left = bits; left > 0; position = 0, entry++, i++) {
+		last = (position + left > 8) ? 8 : position + left;
+		mask = (((1 << last) - 1) ^ ((1 << position) - 1)) << (col * 8);
+
+		if (set == true) {
+			rf[entry] &= ~mask;
+			rf[entry] |= ((data << position) << (col * 8)) & mask;
+			data >>= (8 - position);
+		} else {
+			data = (((rf[entry] & mask) >> (col * 8)) >> position)
+				<< shift;
+			shift += last - position;
+		}
+
+		left -= 8 - position;
+	}
+
+	data = set == true ? 1 : ath5k_hw_bitswap(data, bits);
+
+	return data;
+}
+
+static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah)
+{
+	u32 mix, step;
+	u32 *rf;
+
+	if (ah->ah_rf_banks == NULL)
+		return 0;
+
+	rf = ah->ah_rf_banks;
+	ah->ah_gain.g_f_corr = 0;
+
+	if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1)
+		return 0;
+
+	step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false);
+	mix = ah->ah_gain.g_step->gos_param[0];
+
+	switch (mix) {
+	case 3:
+		ah->ah_gain.g_f_corr = step * 2;
+		break;
+	case 2:
+		ah->ah_gain.g_f_corr = (step - 5) * 2;
+		break;
+	case 1:
+		ah->ah_gain.g_f_corr = step;
+		break;
+	default:
+		ah->ah_gain.g_f_corr = 0;
+		break;
+	}
+
+	return ah->ah_gain.g_f_corr;
+}
+
+static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah)
+{
+	u32 step, mix, level[4];
+	u32 *rf;
+
+	if (ah->ah_rf_banks == NULL)
+		return false;
+
+	rf = ah->ah_rf_banks;
+
+	if (ah->ah_radio == AR5K_RF5111) {
+		step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0,
+				false);
+		level[0] = 0;
+		level[1] = (step == 0x3f) ? 0x32 : step + 4;
+		level[2] = (step != 0x3f) ? 0x40 : level[0];
+		level[3] = level[2] + 0x32;
+
+		ah->ah_gain.g_high = level[3] -
+			(step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
+		ah->ah_gain.g_low = level[0] +
+			(step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
+	} else {
+		mix = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0,
+				false);
+		level[0] = level[2] = 0;
+
+		if (mix == 1) {
+			level[1] = level[3] = 83;
+		} else {
+			level[1] = level[3] = 107;
+			ah->ah_gain.g_high = 55;
+		}
+	}
+
+	return (ah->ah_gain.g_current >= level[0] &&
+			ah->ah_gain.g_current <= level[1]) ||
+		(ah->ah_gain.g_current >= level[2] &&
+			ah->ah_gain.g_current <= level[3]);
+}
+
+static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah)
+{
+	const struct ath5k_gain_opt *go;
+	int ret = 0;
+
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		go = &rfgain_opt_5111;
+		break;
+	case AR5K_RF5112:
+	case AR5K_RF5413: /* ??? */
+		go = &rfgain_opt_5112;
+		break;
+	default:
+		return 0;
+	}
+
+	ah->ah_gain.g_step = &go->go_step[ah->ah_gain.g_step_idx];
+
+	if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
+		if (ah->ah_gain.g_step_idx == 0)
+			return -1;
+		for (ah->ah_gain.g_target = ah->ah_gain.g_current;
+				ah->ah_gain.g_target >=  ah->ah_gain.g_high &&
+				ah->ah_gain.g_step_idx > 0;
+				ah->ah_gain.g_step =
+					&go->go_step[ah->ah_gain.g_step_idx])
+			ah->ah_gain.g_target -= 2 *
+			    (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
+			    ah->ah_gain.g_step->gos_gain);
+
+		ret = 1;
+		goto done;
+	}
+
+	if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
+		if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
+			return -2;
+		for (ah->ah_gain.g_target = ah->ah_gain.g_current;
+				ah->ah_gain.g_target <= ah->ah_gain.g_low &&
+				ah->ah_gain.g_step_idx < go->go_steps_count-1;
+				ah->ah_gain.g_step =
+					&go->go_step[ah->ah_gain.g_step_idx])
+			ah->ah_gain.g_target -= 2 *
+			    (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
+			    ah->ah_gain.g_step->gos_gain);
+
+		ret = 2;
+		goto done;
+	}
+
+done:
+	ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+		"ret %d, gain step %u, current gain %u, target gain %u\n",
+		ret, ah->ah_gain.g_step_idx, ah->ah_gain.g_current,
+		ah->ah_gain.g_target);
+
+	return ret;
+}
+
+/*
+ * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111
+ */
+static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel, unsigned int mode)
+{
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 *rf;
+	const unsigned int rf_size = ARRAY_SIZE(rfregs_5111);
+	unsigned int i;
+	int obdb = -1, bank = -1;
+	u32 ee_mode;
+
+	AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
+
+	rf = ah->ah_rf_banks;
+
+	/* Copy values to modify them */
+	for (i = 0; i < rf_size; i++) {
+		if (rfregs_5111[i].rf_bank >= AR5K_RF5111_INI_RF_MAX_BANKS) {
+			ATH5K_ERR(ah->ah_sc, "invalid bank\n");
+			return -EINVAL;
+		}
+
+		if (bank != rfregs_5111[i].rf_bank) {
+			bank = rfregs_5111[i].rf_bank;
+			ah->ah_offset[bank] = i;
+		}
+
+		rf[i] = rfregs_5111[i].rf_value[mode];
+	}
+
+	/* Modify bank 0 */
+	if (channel->val & CHANNEL_2GHZ) {
+		if (channel->val & CHANNEL_CCK)
+			ee_mode = AR5K_EEPROM_MODE_11B;
+		else
+			ee_mode = AR5K_EEPROM_MODE_11G;
+		obdb = 0;
+
+		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0],
+				ee->ee_ob[ee_mode][obdb], 3, 119, 0, true))
+			return -EINVAL;
+
+		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0],
+				ee->ee_ob[ee_mode][obdb], 3, 122, 0, true))
+			return -EINVAL;
+
+		obdb = 1;
+	/* Modify bank 6 */
+	} else {
+		/* For 11a, Turbo and XR */
+		ee_mode = AR5K_EEPROM_MODE_11A;
+		obdb =	 channel->freq >= 5725 ? 3 :
+			(channel->freq >= 5500 ? 2 :
+			(channel->freq >= 5260 ? 1 :
+			 (channel->freq > 4000 ? 0 : -1)));
+
+		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+				ee->ee_pwd_84, 1, 51, 3, true))
+			return -EINVAL;
+
+		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+				ee->ee_pwd_90, 1, 45, 3, true))
+			return -EINVAL;
+	}
+
+	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+			!ee->ee_xpd[ee_mode], 1, 95, 0, true))
+		return -EINVAL;
+
+	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+			ee->ee_x_gain[ee_mode], 4, 96, 0, true))
+		return -EINVAL;
+
+	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ?
+			ee->ee_ob[ee_mode][obdb] : 0, 3, 104, 0, true))
+		return -EINVAL;
+
+	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ?
+			ee->ee_db[ee_mode][obdb] : 0, 3, 107, 0, true))
+		return -EINVAL;
+
+	/* Modify bank 7 */
+	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7],
+			ee->ee_i_gain[ee_mode], 6, 29, 0, true))
+		return -EINVAL;
+
+	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7],
+			ee->ee_xpd[ee_mode], 1, 4, 0, true))
+		return -EINVAL;
+
+	/* Write RF values */
+	for (i = 0; i < rf_size; i++) {
+		AR5K_REG_WAIT(i);
+		ath5k_hw_reg_write(ah, rf[i], rfregs_5111[i].rf_register);
+	}
+
+	return 0;
+}
+
+/*
+ * Read EEPROM Calibration data, modify RF Banks and Initialize RF5112
+ */
+static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel, unsigned int mode)
+{
+	const struct ath5k_ini_rf *rf_ini;
+	struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+	u32 *rf;
+	unsigned int rf_size, i;
+	int obdb = -1, bank = -1;
+	u32 ee_mode;
+
+	AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
+
+	rf = ah->ah_rf_banks;
+
+	if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_2112A
+		&& !test_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode)){
+		rf_ini = rfregs_2112a;
+		rf_size = ARRAY_SIZE(rfregs_5112a);
+		if (mode < 2) {
+			ATH5K_ERR(ah->ah_sc,"invalid channel mode: %i\n",mode);
+			return -EINVAL;
+		}
+		mode = mode - 2; /*no a/turboa modes for 2112*/
+	} else if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
+		rf_ini = rfregs_5112a;
+		rf_size = ARRAY_SIZE(rfregs_5112a);
+	} else {
+		rf_ini = rfregs_5112;
+		rf_size = ARRAY_SIZE(rfregs_5112);
+	}
+
+	/* Copy values to modify them */
+	for (i = 0; i < rf_size; i++) {
+		if (rf_ini[i].rf_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) {
+			ATH5K_ERR(ah->ah_sc, "invalid bank\n");
+			return -EINVAL;
+		}
+
+		if (bank != rf_ini[i].rf_bank) {
+			bank = rf_ini[i].rf_bank;
+			ah->ah_offset[bank] = i;
+		}
+
+		rf[i] = rf_ini[i].rf_value[mode];
+	}
+
+	/* Modify bank 6 */
+	if (channel->val & CHANNEL_2GHZ) {
+		if (channel->val & CHANNEL_OFDM)
+			ee_mode = AR5K_EEPROM_MODE_11G;
+		else
+			ee_mode = AR5K_EEPROM_MODE_11B;
+		obdb = 0;
+
+		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+				ee->ee_ob[ee_mode][obdb], 3, 287, 0, true))
+			return -EINVAL;
+
+		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+				ee->ee_ob[ee_mode][obdb], 3, 290, 0, true))
+			return -EINVAL;
+	} else {
+		/* For 11a, Turbo and XR */
+		ee_mode = AR5K_EEPROM_MODE_11A;
+		obdb = channel->freq >= 5725 ? 3 :
+		    (channel->freq >= 5500 ? 2 :
+			(channel->freq >= 5260 ? 1 :
+			    (channel->freq > 4000 ? 0 : -1)));
+
+		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+				ee->ee_ob[ee_mode][obdb], 3, 279, 0, true))
+			return -EINVAL;
+
+		if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+				ee->ee_ob[ee_mode][obdb], 3, 282, 0, true))
+			return -EINVAL;
+	}
+
+	ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+	    ee->ee_x_gain[ee_mode], 2, 270, 0, true);
+	ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+	    ee->ee_x_gain[ee_mode], 2, 257, 0, true);
+
+	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6],
+			ee->ee_xpd[ee_mode], 1, 302, 0, true))
+		return -EINVAL;
+
+	/* Modify bank 7 */
+	if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7],
+			ee->ee_i_gain[ee_mode], 6, 14, 0, true))
+		return -EINVAL;
+
+	/* Write RF values */
+	for (i = 0; i < rf_size; i++)
+		ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rf_register);
+
+	return 0;
+}
+
+/*
+ * Initialize RF5413/5414
+ */
+static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel, unsigned int mode)
+{
+	const struct ath5k_ini_rf *rf_ini;
+	u32 *rf;
+	unsigned int rf_size, i;
+	int bank = -1;
+
+	AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX);
+
+	rf = ah->ah_rf_banks;
+
+	rf_ini = rfregs_5413;
+	rf_size = ARRAY_SIZE(rfregs_5413);
+
+	/* Copy values to modify them */
+	for (i = 0; i < rf_size; i++) {
+		if (rf_ini[i].rf_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) {
+			ATH5K_ERR(ah->ah_sc, "invalid bank\n");
+			return -EINVAL;
+		}
+
+		if (bank != rf_ini[i].rf_bank) {
+			bank = rf_ini[i].rf_bank;
+			ah->ah_offset[bank] = i;
+		}
+
+		rf[i] = rf_ini[i].rf_value[mode];
+	}
+
+	/*
+	 * After compairing dumps from different cards
+	 * we get the same RF_BUFFER settings (diff returns
+	 * 0 lines). It seems that RF_BUFFER settings are static
+	 * and are written unmodified (no EEPROM stuff
+	 * is used because calibration data would be
+	 * different between different cards and would result
+	 * different RF_BUFFER settings)
+	 */
+
+	/* Write RF values */
+	for (i = 0; i < rf_size; i++)
+		ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rf_register);
+
+	return 0;
+}
+
+/*
+ * Initialize RF
+ */
+int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+		unsigned int mode)
+{
+	int (*func)(struct ath5k_hw *, struct ieee80211_channel *, unsigned int);
+	int ret;
+
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		ah->ah_rf_banks_size = sizeof(rfregs_5111);
+		func = ath5k_hw_rf5111_rfregs;
+		break;
+	case AR5K_RF5112:
+		if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
+			ah->ah_rf_banks_size = sizeof(rfregs_5112a);
+		else
+			ah->ah_rf_banks_size = sizeof(rfregs_5112);
+		func = ath5k_hw_rf5112_rfregs;
+		break;
+	case AR5K_RF5413:
+		ah->ah_rf_banks_size = sizeof(rfregs_5413);
+		func = ath5k_hw_rf5413_rfregs;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (ah->ah_rf_banks == NULL) {
+		/* XXX do extra checks? */
+		ah->ah_rf_banks = kmalloc(ah->ah_rf_banks_size, GFP_KERNEL);
+		if (ah->ah_rf_banks == NULL) {
+			ATH5K_ERR(ah->ah_sc, "out of memory\n");
+			return -ENOMEM;
+		}
+	}
+
+	ret = func(ah, channel, mode);
+	if (!ret)
+		ah->ah_rf_gain = AR5K_RFGAIN_INACTIVE;
+
+	return ret;
+}
+
+int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq)
+{
+	const struct ath5k_ini_rfgain *ath5k_rfg;
+	unsigned int i, size;
+
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		ath5k_rfg = rfgain_5111;
+		size = ARRAY_SIZE(rfgain_5111);
+		break;
+	case AR5K_RF5112:
+		ath5k_rfg = rfgain_5112;
+		size = ARRAY_SIZE(rfgain_5112);
+		break;
+	case AR5K_RF5413:
+		ath5k_rfg = rfgain_5413;
+		size = ARRAY_SIZE(rfgain_5413);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (freq) {
+	case AR5K_INI_RFGAIN_2GHZ:
+	case AR5K_INI_RFGAIN_5GHZ:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < size; i++) {
+		AR5K_REG_WAIT(i);
+		ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
+			(u32)ath5k_rfg[i].rfg_register);
+	}
+
+	return 0;
+}
+
+enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah)
+{
+	u32 data, type;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (ah->ah_rf_banks == NULL || !ah->ah_gain.g_active ||
+			ah->ah_version <= AR5K_AR5211)
+		return AR5K_RFGAIN_INACTIVE;
+
+	if (ah->ah_rf_gain != AR5K_RFGAIN_READ_REQUESTED)
+		goto done;
+
+	data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
+
+	if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
+		ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
+		type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
+
+		if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK)
+			ah->ah_gain.g_current += AR5K_GAIN_CCK_PROBE_CORR;
+
+		if (ah->ah_radio >= AR5K_RF5112) {
+			ath5k_hw_rfregs_gainf_corr(ah);
+			ah->ah_gain.g_current =
+				ah->ah_gain.g_current>=ah->ah_gain.g_f_corr ?
+				(ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
+				0;
+		}
+
+		if (ath5k_hw_rfregs_gain_readback(ah) &&
+				AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
+				ath5k_hw_rfregs_gain_adjust(ah))
+			ah->ah_rf_gain = AR5K_RFGAIN_NEED_CHANGE;
+	}
+
+done:
+	return ah->ah_rf_gain;
+}
+
+int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah)
+{
+	/* Initialize the gain optimization values */
+	switch (ah->ah_radio) {
+	case AR5K_RF5111:
+		ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
+		ah->ah_gain.g_step =
+		    &rfgain_opt_5111.go_step[ah->ah_gain.g_step_idx];
+		ah->ah_gain.g_low = 20;
+		ah->ah_gain.g_high = 35;
+		ah->ah_gain.g_active = 1;
+		break;
+	case AR5K_RF5112:
+	case AR5K_RF5413: /* ??? */
+		ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
+		ah->ah_gain.g_step =
+		    &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx];
+		ah->ah_gain.g_low = 20;
+		ah->ah_gain.g_high = 85;
+		ah->ah_gain.g_active = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**************************\
+  PHY/RF channel functions
+\**************************/
+
+/*
+ * Check if a channel is supported
+ */
+bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
+{
+	/* Check if the channel is in our supported range */
+	if (flags & CHANNEL_2GHZ) {
+		if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
+		    (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
+			return true;
+	} else if (flags & CHANNEL_5GHZ)
+		if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
+		    (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
+			return true;
+
+	return false;
+}
+
+/*
+ * Convertion needed for RF5110
+ */
+static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel)
+{
+	u32 athchan;
+
+	/*
+	 * Convert IEEE channel/MHz to an internal channel value used
+	 * by the AR5210 chipset. This has not been verified with
+	 * newer chipsets like the AR5212A who have a completely
+	 * different RF/PHY part.
+	 */
+	athchan = (ath5k_hw_bitswap((channel->chan - 24) / 2, 5) << 1) |
+		(1 << 6) | 0x1;
+
+	return athchan;
+}
+
+/*
+ * Set channel on RF5110
+ */
+static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel)
+{
+	u32 data;
+
+	/*
+	 * Set the channel and wait
+	 */
+	data = ath5k_hw_rf5110_chan2athchan(channel);
+	ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0);
+	mdelay(1);
+
+	return 0;
+}
+
+/*
+ * Convertion needed for 5111
+ */
+static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee,
+		struct ath5k_athchan_2ghz *athchan)
+{
+	int channel;
+
+	/* Cast this value to catch negative channel numbers (>= -19) */
+	channel = (int)ieee;
+
+	/*
+	 * Map 2GHz IEEE channel to 5GHz Atheros channel
+	 */
+	if (channel <= 13) {
+		athchan->a2_athchan = 115 + channel;
+		athchan->a2_flags = 0x46;
+	} else if (channel == 14) {
+		athchan->a2_athchan = 124;
+		athchan->a2_flags = 0x44;
+	} else if (channel >= 15 && channel <= 26) {
+		athchan->a2_athchan = ((channel - 14) * 4) + 132;
+		athchan->a2_flags = 0x46;
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Set channel on 5111
+ */
+static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel)
+{
+	struct ath5k_athchan_2ghz ath5k_channel_2ghz;
+	unsigned int ath5k_channel = channel->chan;
+	u32 data0, data1, clock;
+	int ret;
+
+	/*
+	 * Set the channel on the RF5111 radio
+	 */
+	data0 = data1 = 0;
+
+	if (channel->val & CHANNEL_2GHZ) {
+		/* Map 2GHz channel to 5GHz Atheros channel ID */
+		ret = ath5k_hw_rf5111_chan2athchan(channel->chan,
+				&ath5k_channel_2ghz);
+		if (ret)
+			return ret;
+
+		ath5k_channel = ath5k_channel_2ghz.a2_athchan;
+		data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff)
+		    << 5) | (1 << 4);
+	}
+
+	if (ath5k_channel < 145 || !(ath5k_channel & 1)) {
+		clock = 1;
+		data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) |
+			(clock << 1) | (1 << 10) | 1;
+	} else {
+		clock = 0;
+		data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff)
+			<< 2) | (clock << 1) | (1 << 10) | 1;
+	}
+
+	ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8),
+			AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00),
+			AR5K_RF_BUFFER_CONTROL_3);
+
+	return 0;
+}
+
+/*
+ * Set channel on 5112 and newer
+ */
+static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel)
+{
+	u32 data, data0, data1, data2;
+	u16 c;
+
+	data = data0 = data1 = data2 = 0;
+	c = channel->freq;
+
+	/*
+	 * Set the channel on the RF5112 or newer
+	 */
+	if (c < 4800) {
+		if (!((c - 2224) % 5)) {
+			data0 = ((2 * (c - 704)) - 3040) / 10;
+			data1 = 1;
+		} else if (!((c - 2192) % 5)) {
+			data0 = ((2 * (c - 672)) - 3040) / 10;
+			data1 = 0;
+		} else
+			return -EINVAL;
+
+		data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
+	} else {
+		if (!(c % 20) && c >= 5120) {
+			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
+			data2 = ath5k_hw_bitswap(3, 2);
+		} else if (!(c % 10)) {
+			data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
+			data2 = ath5k_hw_bitswap(2, 2);
+		} else if (!(c % 5)) {
+			data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
+			data2 = ath5k_hw_bitswap(1, 2);
+		} else
+			return -EINVAL;
+	}
+
+	data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
+
+	ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
+
+	return 0;
+}
+
+/*
+ * Set a channel on the radio chip
+ */
+int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
+{
+	int ret;
+
+	/*
+	 * Check bounds supported by the PHY
+	 * (don't care about regulation restrictions at this point)
+	 */
+	if ((channel->freq < ah->ah_capabilities.cap_range.range_2ghz_min ||
+	    channel->freq > ah->ah_capabilities.cap_range.range_2ghz_max) &&
+	    (channel->freq < ah->ah_capabilities.cap_range.range_5ghz_min ||
+	    channel->freq > ah->ah_capabilities.cap_range.range_5ghz_max)) {
+		ATH5K_ERR(ah->ah_sc,
+			"channel out of supported range (%u MHz)\n",
+			channel->freq);
+		return -EINVAL;
+	}
+
+	/*
+	 * Set the channel and wait
+	 */
+	switch (ah->ah_radio) {
+	case AR5K_RF5110:
+		ret = ath5k_hw_rf5110_channel(ah, channel);
+		break;
+	case AR5K_RF5111:
+		ret = ath5k_hw_rf5111_channel(ah, channel);
+		break;
+	default:
+		ret = ath5k_hw_rf5112_channel(ah, channel);
+		break;
+	}
+
+	if (ret)
+		return ret;
+
+	ah->ah_current_channel.freq = channel->freq;
+	ah->ah_current_channel.val = channel->val;
+	ah->ah_turbo = channel->val == CHANNEL_T ? true : false;
+
+	return 0;
+}
+
+/*****************\
+  PHY calibration
+\*****************/
+
+/**
+ * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
+ *
+ * @ah: struct ath5k_hw pointer we are operating on
+ * @freq: the channel frequency, just used for error logging
+ *
+ * This function performs a noise floor calibration of the PHY and waits for
+ * it to complete. Then the noise floor value is compared to some maximum
+ * noise floor we consider valid.
+ *
+ * Note that this is different from what the madwifi HAL does: it reads the
+ * noise floor and afterwards initiates the calibration. Since the noise floor
+ * calibration can take some time to finish, depending on the current channel
+ * use, that avoids the occasional timeout warnings we are seeing now.
+ *
+ * See the following link for an Atheros patent on noise floor calibration:
+ * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
+ * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
+ *
+ */
+int
+ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
+{
+	int ret;
+	unsigned int i;
+	s32 noise_floor;
+
+	/*
+	 * Enable noise floor calibration and wait until completion
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+				AR5K_PHY_AGCCTL_NF);
+
+	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+			AR5K_PHY_AGCCTL_NF, 0, false);
+	if (ret) {
+		ATH5K_ERR(ah->ah_sc,
+			"noise floor calibration timeout (%uMHz)\n", freq);
+		return ret;
+	}
+
+	/* Wait until the noise floor is calibrated and read the value */
+	for (i = 20; i > 0; i--) {
+		mdelay(1);
+		noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
+		noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
+		if (noise_floor & AR5K_PHY_NF_ACTIVE) {
+			noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
+
+			if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
+				break;
+		}
+	}
+
+	ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
+		"noise floor %d\n", noise_floor);
+
+	if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
+		ATH5K_ERR(ah->ah_sc,
+			"noise floor calibration failed (%uMHz)\n", freq);
+		return -EIO;
+	}
+
+	ah->ah_noise_floor = noise_floor;
+
+	return 0;
+}
+
+/*
+ * Perform a PHY calibration on RF5110
+ * -Fix BPSK/QAM Constellation (I/Q correction)
+ * -Calculate Noise Floor
+ */
+static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel)
+{
+	u32 phy_sig, phy_agc, phy_sat, beacon;
+	int ret;
+
+	/*
+	 * Disable beacons and RX/TX queues, wait
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210,
+		AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
+	beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
+	ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
+
+	udelay(2300);
+
+	/*
+	 * Set the channel (with AGC turned off)
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+	udelay(10);
+	ret = ath5k_hw_channel(ah, channel);
+
+	/*
+	 * Activate PHY and wait
+	 */
+	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+	mdelay(1);
+
+	AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+
+	if (ret)
+		return ret;
+
+	/*
+	 * Calibrate the radio chip
+	 */
+
+	/* Remember normal state */
+	phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG);
+	phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE);
+	phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT);
+
+	/* Update radio registers */
+	ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) |
+		AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG);
+
+	ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI |
+			AR5K_PHY_AGCCOARSE_LO)) |
+		AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) |
+		AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE);
+
+	ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT |
+			AR5K_PHY_ADCSAT_THR)) |
+		AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) |
+		AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT);
+
+	udelay(20);
+
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+	udelay(10);
+	ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG);
+	AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
+
+	mdelay(1);
+
+	/*
+	 * Enable calibration and wait until completion
+	 */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL);
+
+	ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+			AR5K_PHY_AGCCTL_CAL, 0, false);
+
+	/* Reset to normal state */
+	ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG);
+	ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE);
+	ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT);
+
+	if (ret) {
+		ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
+				channel->freq);
+		return ret;
+	}
+
+	ret = ath5k_hw_noise_floor_calibration(ah, channel->freq);
+	if (ret)
+		return ret;
+
+	/*
+	 * Re-enable RX/TX and beacons
+	 */
+	AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210,
+		AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
+	ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210);
+
+	return 0;
+}
+
+/*
+ * Perform a PHY calibration on RF5111/5112
+ */
+static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel)
+{
+	u32 i_pwr, q_pwr;
+	s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
+	ATH5K_TRACE(ah->ah_sc);
+
+	if (ah->ah_calibration == false ||
+			ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
+		goto done;
+
+	ah->ah_calibration = false;
+
+	iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
+	i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
+	q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
+	i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
+	q_coffd = q_pwr >> 6;
+
+	if (i_coffd == 0 || q_coffd == 0)
+		goto done;
+
+	i_coff = ((-iq_corr) / i_coffd) & 0x3f;
+	q_coff = (((s32)i_pwr / q_coffd) - 64) & 0x1f;
+
+	/* Commit new IQ value */
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
+		((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
+
+done:
+	ath5k_hw_noise_floor_calibration(ah, channel->freq);
+
+	/* Request RF gain */
+	if (channel->val & CHANNEL_5GHZ) {
+		ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max,
+			AR5K_PHY_PAPD_PROBE_TXPOWER) |
+			AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
+		ah->ah_rf_gain = AR5K_RFGAIN_READ_REQUESTED;
+	}
+
+	return 0;
+}
+
+/*
+ * Perform a PHY calibration
+ */
+int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel)
+{
+	int ret;
+
+	if (ah->ah_radio == AR5K_RF5110)
+		ret = ath5k_hw_rf5110_calibrate(ah, channel);
+	else
+		ret = ath5k_hw_rf511x_calibrate(ah, channel);
+
+	return ret;
+}
+
+int ath5k_hw_phy_disable(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	/*Just a try M.F.*/
+	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+
+	return 0;
+}
+
+/********************\
+  Misc PHY functions
+\********************/
+
+/*
+ * Get the PHY Chip revision
+ */
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
+{
+	unsigned int i;
+	u32 srev;
+	u16 ret;
+
+	ATH5K_TRACE(ah->ah_sc);
+
+	/*
+	 * Set the radio chip access register
+	 */
+	switch (chan) {
+	case CHANNEL_2GHZ:
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
+		break;
+	case CHANNEL_5GHZ:
+		ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+		break;
+	default:
+		return 0;
+	}
+
+	mdelay(2);
+
+	/* ...wait until PHY is ready and read the selected radio revision */
+	ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
+
+	for (i = 0; i < 8; i++)
+		ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
+
+	if (ah->ah_version == AR5K_AR5210) {
+		srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
+		ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
+	} else {
+		srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
+		ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
+				((srev & 0x0f) << 4), 8);
+	}
+
+	/* Reset to the 5GHz mode */
+	ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+
+	return ret;
+}
+
+void /*TODO:Boundary check*/
+ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	/*Just a try M.F.*/
+	if (ah->ah_version != AR5K_AR5210)
+		ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA);
+}
+
+unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah)
+{
+	ATH5K_TRACE(ah->ah_sc);
+	/*Just a try M.F.*/
+	if (ah->ah_version != AR5K_AR5210)
+		return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
+
+	return false; /*XXX: What do we return for 5210 ?*/
+}
+
+/*
+ * TX power setup
+ */
+
+/*
+ * Initialize the tx power table (not fully implemented)
+ */
+static void ath5k_txpower_table(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel, s16 max_power)
+{
+	unsigned int i, min, max, n;
+	u16 txpower, *rates;
+
+	rates = ah->ah_txpower.txp_rates;
+
+	txpower = AR5K_TUNE_DEFAULT_TXPOWER * 2;
+	if (max_power > txpower)
+		txpower = max_power > AR5K_TUNE_MAX_TXPOWER ?
+		    AR5K_TUNE_MAX_TXPOWER : max_power;
+
+	for (i = 0; i < AR5K_MAX_RATES; i++)
+		rates[i] = txpower;
+
+	/* XXX setup target powers by rate */
+
+	ah->ah_txpower.txp_min = rates[7];
+	ah->ah_txpower.txp_max = rates[0];
+	ah->ah_txpower.txp_ofdm = rates[0];
+
+	/* Calculate the power table */
+	n = ARRAY_SIZE(ah->ah_txpower.txp_pcdac);
+	min = AR5K_EEPROM_PCDAC_START;
+	max = AR5K_EEPROM_PCDAC_STOP;
+	for (i = 0; i < n; i += AR5K_EEPROM_PCDAC_STEP)
+		ah->ah_txpower.txp_pcdac[i] =
+#ifdef notyet
+		min + ((i * (max - min)) / n);
+#else
+		min;
+#endif
+}
+
+/*
+ * Set transmition power
+ */
+int /*O.K. - txpower_table is unimplemented so this doesn't work*/
+ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+		unsigned int txpower)
+{
+	bool tpc = ah->ah_txpower.txp_tpc;
+	unsigned int i;
+
+	ATH5K_TRACE(ah->ah_sc);
+	if (txpower > AR5K_TUNE_MAX_TXPOWER) {
+		ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower);
+		return -EINVAL;
+	}
+
+	/* Reset TX power values */
+	memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
+	ah->ah_txpower.txp_tpc = tpc;
+
+	/* Initialize TX power table */
+	ath5k_txpower_table(ah, channel, txpower);
+
+	/*
+	 * Write TX power values
+	 */
+	for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
+		ath5k_hw_reg_write(ah,
+			((((ah->ah_txpower.txp_pcdac[(i << 1) + 1] << 8) | 0xff) & 0xffff) << 16) |
+			(((ah->ah_txpower.txp_pcdac[(i << 1)    ] << 8) | 0xff) & 0xffff),
+			AR5K_PHY_PCDAC_TXPOWER(i));
+	}
+
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) |
+		AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) |
+		AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1);
+
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) |
+		AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) |
+		AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2);
+
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) |
+		AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) |
+		AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3);
+
+	ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) |
+		AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) |
+		AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4);
+
+	if (ah->ah_txpower.txp_tpc == true)
+		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE |
+			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
+	else
+		ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX |
+			AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
+
+	return 0;
+}
+
+int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power)
+{
+	/*Just a try M.F.*/
+	struct ieee80211_channel *channel = &ah->ah_current_channel;
+
+	ATH5K_TRACE(ah->ah_sc);
+	ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER,
+		"changing txpower to %d\n", power);
+
+	return ath5k_hw_txpower(ah, channel, power);
+}
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h
new file mode 100644
index 000000000000..2f41c8398602
--- /dev/null
+++ b/drivers/net/wireless/ath5k/reg.h
@@ -0,0 +1,1987 @@
+/*
+ * Copyright (c) 2007 Nick Kossifidis <mickflemm@gmail.com>
+ * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2007 Michael Taylor <mike.taylor@apprion.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/*
+ * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k
+ * maintained by Reyk Floeter
+ *
+ * I tried to document those registers by looking at ar5k code, some
+ * 802.11 (802.11e mostly) papers and by reading various public available
+ * Atheros presentations and papers like these:
+ *
+ * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf
+ *        http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf
+ *
+ * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf
+ */
+
+
+
+/*====MAC DMA REGISTERS====*/
+
+/*
+ * AR5210-Specific TXDP registers
+ * 5210 has only 2 transmit queues so no DCU/QCU, just
+ * 2 transmit descriptor pointers...
+ */
+#define AR5K_NOQCU_TXDP0	0x0000		/* Queue 0 - data */
+#define AR5K_NOQCU_TXDP1	0x0004		/* Queue 1 - beacons */
+
+/*
+ * Mac Control Register
+ */
+#define	AR5K_CR		0x0008			/* Register Address */
+#define AR5K_CR_TXE0	0x00000001	/* TX Enable for queue 0 on 5210 */
+#define AR5K_CR_TXE1	0x00000002	/* TX Enable for queue 1 on 5210 */
+#define	AR5K_CR_RXE	0x00000004	/* RX Enable */
+#define AR5K_CR_TXD0	0x00000008	/* TX Disable for queue 0 on 5210 */
+#define AR5K_CR_TXD1	0x00000010	/* TX Disable for queue 1 on 5210 */
+#define	AR5K_CR_RXD	0x00000020	/* RX Disable */
+#define	AR5K_CR_SWI	0x00000040
+
+/*
+ * RX Descriptor Pointer register
+ */
+#define	AR5K_RXDP	0x000c
+
+/*
+ * Configuration and status register
+ */
+#define	AR5K_CFG		0x0014			/* Register Address */
+#define	AR5K_CFG_SWTD		0x00000001	/* Byte-swap TX descriptor (for big endian archs) */
+#define	AR5K_CFG_SWTB		0x00000002	/* Byte-swap TX buffer (?) */
+#define	AR5K_CFG_SWRD		0x00000004	/* Byte-swap RX descriptor */
+#define	AR5K_CFG_SWRB		0x00000008	/* Byte-swap RX buffer (?) */
+#define	AR5K_CFG_SWRG		0x00000010	/* Byte-swap Register values (?) */
+#define AR5K_CFG_ADHOC		0x00000020 	/* [5211+] */
+#define AR5K_CFG_PHY_OK		0x00000100	/* [5211+] */
+#define AR5K_CFG_EEBS		0x00000200	/* EEPROM is busy */
+#define	AR5K_CFG_CLKGD		0x00000400	/* Clock gated (?) */
+#define AR5K_CFG_TXCNT		0x00007800	/* Tx frame count (?) [5210] */
+#define AR5K_CFG_TXCNT_S	11
+#define AR5K_CFG_TXFSTAT	0x00008000	/* Tx frame status (?) [5210] */
+#define AR5K_CFG_TXFSTRT	0x00010000	/* [5210] */
+#define	AR5K_CFG_PCI_THRES	0x00060000	/* [5211+] */
+#define	AR5K_CFG_PCI_THRES_S	17
+
+/*
+ * Interrupt enable register
+ */
+#define AR5K_IER		0x0024		/* Register Address */
+#define AR5K_IER_DISABLE	0x00000000	/* Disable card interrupts */
+#define AR5K_IER_ENABLE		0x00000001	/* Enable card interrupts */
+
+
+/*
+ * 0x0028 is Beacon Control Register on 5210
+ * and first RTS duration register on 5211
+ */
+
+/*
+ * Beacon control register [5210]
+ */
+#define AR5K_BCR		0x0028		/* Register Address */
+#define AR5K_BCR_AP		0x00000000	/* AP mode */
+#define AR5K_BCR_ADHOC		0x00000001	/* Ad-Hoc mode */
+#define AR5K_BCR_BDMAE		0x00000002	/* DMA enable */
+#define AR5K_BCR_TQ1FV		0x00000004	/* Use Queue1 for CAB traffic */
+#define AR5K_BCR_TQ1V		0x00000008	/* Use Queue1 for Beacon traffic */
+#define AR5K_BCR_BCGET		0x00000010
+
+/*
+ * First RTS duration register [5211]
+ */
+#define AR5K_RTSD0		0x0028		/* Register Address */
+#define	AR5K_RTSD0_6		0x000000ff	/* 6Mb RTS duration mask (?) */
+#define	AR5K_RTSD0_6_S		0		/* 6Mb RTS duration shift (?) */
+#define	AR5K_RTSD0_9		0x0000ff00	/* 9Mb*/
+#define	AR5K_RTSD0_9_S		8
+#define	AR5K_RTSD0_12		0x00ff0000	/* 12Mb*/
+#define	AR5K_RTSD0_12_S		16
+#define	AR5K_RTSD0_18		0xff000000	/* 16Mb*/
+#define	AR5K_RTSD0_18_S		24
+
+
+/*
+ * 0x002c is Beacon Status Register on 5210
+ * and second RTS duration register on 5211
+ */
+
+/*
+ * Beacon status register [5210]
+ *
+ * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR
+ * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning
+ * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR).
+ * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i
+ * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what
+ * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR.
+ */
+#define AR5K_BSR		0x002c			/* Register Address */
+#define AR5K_BSR_BDLYSW		0x00000001	/* SW Beacon delay (?) */
+#define AR5K_BSR_BDLYDMA	0x00000002	/* DMA Beacon delay (?) */
+#define AR5K_BSR_TXQ1F		0x00000004	/* Beacon queue (1) finished */
+#define AR5K_BSR_ATIMDLY	0x00000008	/* ATIM delay (?) */
+#define AR5K_BSR_SNPADHOC	0x00000100	/* Ad-hoc mode set (?) */
+#define AR5K_BSR_SNPBDMAE	0x00000200	/* Beacon DMA enabled (?) */
+#define AR5K_BSR_SNPTQ1FV	0x00000400	/* Queue1 is used for CAB traffic (?) */
+#define AR5K_BSR_SNPTQ1V	0x00000800	/* Queue1 is used for Beacon traffic (?) */
+#define AR5K_BSR_SNAPSHOTSVALID	0x00001000	/* BCR snapshots are valid (?) */
+#define AR5K_BSR_SWBA_CNT	0x00ff0000
+
+/*
+ * Second RTS duration register [5211]
+ */
+#define AR5K_RTSD1		0x002c			/* Register Address */
+#define	AR5K_RTSD1_24		0x000000ff	/* 24Mb */
+#define	AR5K_RTSD1_24_S		0
+#define	AR5K_RTSD1_36		0x0000ff00	/* 36Mb */
+#define	AR5K_RTSD1_36_S		8
+#define	AR5K_RTSD1_48		0x00ff0000	/* 48Mb */
+#define	AR5K_RTSD1_48_S		16
+#define	AR5K_RTSD1_54		0xff000000	/* 54Mb */
+#define	AR5K_RTSD1_54_S		24
+
+
+/*
+ * Transmit configuration register
+ */
+#define AR5K_TXCFG		0x0030			/* Register Address */
+#define AR5K_TXCFG_SDMAMR	0x00000007	/* DMA size */
+#define AR5K_TXCFG_SDMAMR_S	0
+#define AR5K_TXCFG_B_MODE	0x00000008	/* Set b mode for 5111 (enable 2111) */
+#define AR5K_TXCFG_TXFSTP	0x00000008	/* TX DMA full Stop [5210] */
+#define AR5K_TXCFG_TXFULL	0x000003f0	/* TX Triger level mask */
+#define AR5K_TXCFG_TXFULL_S	4
+#define AR5K_TXCFG_TXFULL_0B	0x00000000
+#define AR5K_TXCFG_TXFULL_64B	0x00000010
+#define AR5K_TXCFG_TXFULL_128B	0x00000020
+#define AR5K_TXCFG_TXFULL_192B	0x00000030
+#define AR5K_TXCFG_TXFULL_256B	0x00000040
+#define AR5K_TXCFG_TXCONT_EN	0x00000080
+#define AR5K_TXCFG_DMASIZE	0x00000100	/* Flag for passing DMA size [5210] */
+#define AR5K_TXCFG_JUMBO_TXE	0x00000400	/* Enable jumbo frames transmition (?) [5211+] */
+#define AR5K_TXCFG_RTSRND	0x00001000	/* [5211+] */
+#define AR5K_TXCFG_FRMPAD_DIS	0x00002000	/* [5211+] */
+#define AR5K_TXCFG_RDY_DIS	0x00004000	/* [5211+] */
+
+/*
+ * Receive configuration register
+ */
+#define AR5K_RXCFG		0x0034			/* Register Address */
+#define AR5K_RXCFG_SDMAMW	0x00000007	/* DMA size */
+#define AR5K_RXCFG_SDMAMW_S	0
+#define	AR5K_RXCFG_DEF_ANTENNA	0x00000008	/* Default antenna */
+#define AR5K_RXCFG_ZLFDMA	0x00000010	/* Zero-length DMA */
+#define AR5K_RXCFG_JUMBO_RXE	0x00000020	/* Enable jumbo frames reception (?) [5211+] */
+#define AR5K_RXCFG_JUMBO_WRAP	0x00000040	/* Wrap jumbo frames (?) [5211+] */
+
+/*
+ * Receive jumbo descriptor last address register
+ * Only found in 5211 (?)
+ */
+#define AR5K_RXJLA		0x0038
+
+/*
+ * MIB control register
+ */
+#define AR5K_MIBC		0x0040			/* Register Address */
+#define AR5K_MIBC_COW		0x00000001
+#define AR5K_MIBC_FMC		0x00000002	/* Freeze Mib Counters (?) */
+#define AR5K_MIBC_CMC		0x00000004	/* Clean Mib Counters (?) */
+#define AR5K_MIBC_MCS		0x00000008
+
+/*
+ * Timeout prescale register
+ */
+#define AR5K_TOPS		0x0044
+#define	AR5K_TOPS_M		0x0000ffff	/* [5211+] (?) */
+
+/*
+ * Receive timeout register (no frame received)
+ */
+#define AR5K_RXNOFRM		0x0048
+#define	AR5K_RXNOFRM_M		0x000003ff	/* [5211+] (?) */
+
+/*
+ * Transmit timeout register (no frame sent)
+ */
+#define AR5K_TXNOFRM		0x004c
+#define	AR5K_TXNOFRM_M		0x000003ff	/* [5211+] (?) */
+#define	AR5K_TXNOFRM_QCU	0x000ffc00	/* [5211+] (?) */
+
+/*
+ * Receive frame gap timeout register
+ */
+#define AR5K_RPGTO		0x0050
+#define AR5K_RPGTO_M		0x000003ff	/* [5211+] (?) */
+
+/*
+ * Receive frame count limit register
+ */
+#define AR5K_RFCNT		0x0054
+#define AR5K_RFCNT_M		0x0000001f	/* [5211+] (?) */
+#define AR5K_RFCNT_RFCL		0x0000000f	/* [5210] */
+
+/*
+ * Misc settings register
+ */
+#define AR5K_MISC		0x0058			/* Register Address */
+#define	AR5K_MISC_DMA_OBS_M	0x000001e0
+#define	AR5K_MISC_DMA_OBS_S	5
+#define	AR5K_MISC_MISC_OBS_M	0x00000e00
+#define	AR5K_MISC_MISC_OBS_S	9
+#define	AR5K_MISC_MAC_OBS_LSB_M	0x00007000
+#define	AR5K_MISC_MAC_OBS_LSB_S	12
+#define	AR5K_MISC_MAC_OBS_MSB_M	0x00038000
+#define	AR5K_MISC_MAC_OBS_MSB_S	15
+#define AR5K_MISC_LED_DECAY	0x001c0000	/* [5210] */
+#define AR5K_MISC_LED_BLINK	0x00e00000	/* [5210] */
+
+/*
+ * QCU/DCU clock gating register (5311)
+ */
+#define	AR5K_QCUDCU_CLKGT	0x005c			/* Register Address (?) */
+#define	AR5K_QCUDCU_CLKGT_QCU	0x0000ffff	/* Mask for QCU clock */
+#define	AR5K_QCUDCU_CLKGT_DCU	0x07ff0000	/* Mask for DCU clock */
+
+/*
+ * Interrupt Status Registers
+ *
+ * For 5210 there is only one status register but for
+ * 5211/5212 we have one primary and 4 secondary registers.
+ * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212.
+ * Most of these bits are common for all chipsets.
+ */
+#define AR5K_ISR		0x001c			/* Register Address [5210] */
+#define AR5K_PISR		0x0080			/* Register Address [5211+] */
+#define AR5K_ISR_RXOK		0x00000001	/* Frame successfuly recieved */
+#define AR5K_ISR_RXDESC		0x00000002	/* RX descriptor request */
+#define AR5K_ISR_RXERR		0x00000004	/* Receive error */
+#define AR5K_ISR_RXNOFRM	0x00000008	/* No frame received (receive timeout) */
+#define AR5K_ISR_RXEOL		0x00000010	/* Empty RX descriptor */
+#define AR5K_ISR_RXORN		0x00000020	/* Receive FIFO overrun */
+#define AR5K_ISR_TXOK		0x00000040	/* Frame successfuly transmited */
+#define AR5K_ISR_TXDESC		0x00000080	/* TX descriptor request */
+#define AR5K_ISR_TXERR		0x00000100	/* Transmit error */
+#define AR5K_ISR_TXNOFRM	0x00000200	/* No frame transmited (transmit timeout) */
+#define AR5K_ISR_TXEOL		0x00000400	/* Empty TX descriptor */
+#define AR5K_ISR_TXURN		0x00000800	/* Transmit FIFO underrun */
+#define AR5K_ISR_MIB		0x00001000	/* Update MIB counters */
+#define AR5K_ISR_SWI		0x00002000	/* Software interrupt (?) */
+#define AR5K_ISR_RXPHY		0x00004000	/* PHY error */
+#define AR5K_ISR_RXKCM		0x00008000
+#define AR5K_ISR_SWBA		0x00010000	/* Software beacon alert */
+#define AR5K_ISR_BRSSI		0x00020000
+#define AR5K_ISR_BMISS		0x00040000	/* Beacon missed */
+#define AR5K_ISR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
+#define AR5K_ISR_BNR		0x00100000 	/* Beacon not ready [5211+] */
+#define AR5K_ISR_MCABT		0x00100000	/* [5210] */
+#define AR5K_ISR_RXCHIRP	0x00200000	/* [5212+] */
+#define AR5K_ISR_SSERR		0x00200000	/* [5210] */
+#define AR5K_ISR_DPERR		0x00400000	/* [5210] */
+#define AR5K_ISR_TIM		0x00800000	/* [5210] */
+#define AR5K_ISR_BCNMISC	0x00800000	/* [5212+] */
+#define AR5K_ISR_GPIO		0x01000000	/* GPIO (rf kill)*/
+#define AR5K_ISR_QCBRORN	0x02000000	/* CBR overrun (?)  [5211+] */
+#define AR5K_ISR_QCBRURN	0x04000000	/* CBR underrun (?) [5211+] */
+#define AR5K_ISR_QTRIG		0x08000000	/* [5211+] */
+
+/*
+ * Secondary status registers [5211+] (0 - 4)
+ *
+ * I guess from the names that these give the status for each
+ * queue, that's why only masks are defined here, haven't got
+ * any info about them (couldn't find them anywhere in ar5k code).
+ */
+#define AR5K_SISR0		0x0084			/* Register Address [5211+] */
+#define AR5K_SISR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
+#define AR5K_SISR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
+
+#define AR5K_SISR1		0x0088			/* Register Address [5211+] */
+#define AR5K_SISR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
+#define AR5K_SISR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
+
+#define AR5K_SISR2		0x008c			/* Register Address [5211+] */
+#define AR5K_SISR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
+#define	AR5K_SISR2_MCABT	0x00100000
+#define	AR5K_SISR2_SSERR	0x00200000
+#define	AR5K_SISR2_DPERR	0x00400000
+#define	AR5K_SISR2_TIM		0x01000000	/* [5212+] */
+#define	AR5K_SISR2_CAB_END	0x02000000	/* [5212+] */
+#define	AR5K_SISR2_DTIM_SYNC	0x04000000	/* [5212+] */
+#define	AR5K_SISR2_BCN_TIMEOUT	0x08000000	/* [5212+] */
+#define	AR5K_SISR2_CAB_TIMEOUT	0x10000000	/* [5212+] */
+#define	AR5K_SISR2_DTIM		0x20000000	/* [5212+] */
+
+#define AR5K_SISR3		0x0090			/* Register Address [5211+] */
+#define AR5K_SISR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
+#define AR5K_SISR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
+
+#define AR5K_SISR4		0x0094			/* Register Address [5211+] */
+#define AR5K_SISR4_QTRIG	0x000003ff	/* Mask for QTRIG */
+
+/*
+ * Shadow read-and-clear interrupt status registers [5211+]
+ */
+#define AR5K_RAC_PISR		0x00c0		/* Read and clear PISR */
+#define AR5K_RAC_SISR0		0x00c4		/* Read and clear SISR0 */
+#define AR5K_RAC_SISR1		0x00c8		/* Read and clear SISR1 */
+#define AR5K_RAC_SISR2		0x00cc		/* Read and clear SISR2 */
+#define AR5K_RAC_SISR3		0x00d0		/* Read and clear SISR3 */
+#define AR5K_RAC_SISR4		0x00d4		/* Read and clear SISR4 */
+
+/*
+ * Interrupt Mask Registers
+ *
+ * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary
+ * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match.
+ */
+#define	AR5K_IMR		0x0020			/* Register Address [5210] */
+#define AR5K_PIMR		0x00a0			/* Register Address [5211+] */
+#define AR5K_IMR_RXOK		0x00000001	/* Frame successfuly recieved*/
+#define AR5K_IMR_RXDESC		0x00000002	/* RX descriptor request*/
+#define AR5K_IMR_RXERR		0x00000004	/* Receive error*/
+#define AR5K_IMR_RXNOFRM	0x00000008	/* No frame received (receive timeout)*/
+#define AR5K_IMR_RXEOL		0x00000010	/* Empty RX descriptor*/
+#define AR5K_IMR_RXORN		0x00000020	/* Receive FIFO overrun*/
+#define AR5K_IMR_TXOK		0x00000040	/* Frame successfuly transmited*/
+#define AR5K_IMR_TXDESC		0x00000080	/* TX descriptor request*/
+#define AR5K_IMR_TXERR		0x00000100	/* Transmit error*/
+#define AR5K_IMR_TXNOFRM	0x00000200	/* No frame transmited (transmit timeout)*/
+#define AR5K_IMR_TXEOL		0x00000400	/* Empty TX descriptor*/
+#define AR5K_IMR_TXURN		0x00000800	/* Transmit FIFO underrun*/
+#define AR5K_IMR_MIB		0x00001000	/* Update MIB counters*/
+#define AR5K_IMR_SWI		0x00002000
+#define AR5K_IMR_RXPHY		0x00004000	/* PHY error*/
+#define AR5K_IMR_RXKCM		0x00008000
+#define AR5K_IMR_SWBA		0x00010000	/* Software beacon alert*/
+#define AR5K_IMR_BRSSI		0x00020000
+#define AR5K_IMR_BMISS		0x00040000	/* Beacon missed*/
+#define AR5K_IMR_HIUERR		0x00080000	/* Host Interface Unit error [5211+] */
+#define AR5K_IMR_BNR		0x00100000 	/* Beacon not ready [5211+] */
+#define AR5K_IMR_MCABT		0x00100000	/* [5210] */
+#define AR5K_IMR_RXCHIRP	0x00200000	/* [5212+]*/
+#define AR5K_IMR_SSERR		0x00200000	/* [5210] */
+#define AR5K_IMR_DPERR		0x00400000	/* [5210] */
+#define AR5K_IMR_TIM		0x00800000	/* [5211+] */
+#define AR5K_IMR_BCNMISC	0x00800000	/* [5212+] */
+#define AR5K_IMR_GPIO		0x01000000	/* GPIO (rf kill)*/
+#define AR5K_IMR_QCBRORN	0x02000000	/* CBR overrun (?) [5211+] */
+#define AR5K_IMR_QCBRURN	0x04000000	/* CBR underrun (?) [5211+] */
+#define AR5K_IMR_QTRIG		0x08000000	/* [5211+] */
+
+/*
+ * Secondary interrupt mask registers [5211+] (0 - 4)
+ */
+#define AR5K_SIMR0		0x00a4			/* Register Address [5211+] */
+#define AR5K_SIMR0_QCU_TXOK	0x000003ff	/* Mask for QCU_TXOK */
+#define AR5K_SIMR0_QCU_TXOK_S	0
+#define AR5K_SIMR0_QCU_TXDESC	0x03ff0000	/* Mask for QCU_TXDESC */
+#define AR5K_SIMR0_QCU_TXDESC_S	16
+
+#define AR5K_SIMR1		0x00a8			/* Register Address [5211+] */
+#define AR5K_SIMR1_QCU_TXERR	0x000003ff	/* Mask for QCU_TXERR */
+#define AR5K_SIMR1_QCU_TXERR_S	0
+#define AR5K_SIMR1_QCU_TXEOL	0x03ff0000	/* Mask for QCU_TXEOL */
+#define AR5K_SIMR1_QCU_TXEOL_S	16
+
+#define AR5K_SIMR2		0x00ac			/* Register Address [5211+] */
+#define AR5K_SIMR2_QCU_TXURN	0x000003ff	/* Mask for QCU_TXURN */
+#define AR5K_SIMR2_QCU_TXURN_S	0
+#define	AR5K_SIMR2_MCABT	0x00100000
+#define	AR5K_SIMR2_SSERR	0x00200000
+#define	AR5K_SIMR2_DPERR	0x00400000
+#define	AR5K_SIMR2_TIM		0x01000000	/* [5212+] */
+#define	AR5K_SIMR2_CAB_END	0x02000000	/* [5212+] */
+#define	AR5K_SIMR2_DTIM_SYNC	0x04000000	/* [5212+] */
+#define	AR5K_SIMR2_BCN_TIMEOUT	0x08000000	/* [5212+] */
+#define	AR5K_SIMR2_CAB_TIMEOUT	0x10000000	/* [5212+] */
+#define	AR5K_SIMR2_DTIM		0x20000000	/* [5212+] */
+
+#define AR5K_SIMR3		0x00b0			/* Register Address [5211+] */
+#define AR5K_SIMR3_QCBRORN	0x000003ff	/* Mask for QCBRORN */
+#define AR5K_SIMR3_QCBRORN_S	0
+#define AR5K_SIMR3_QCBRURN	0x03ff0000	/* Mask for QCBRURN */
+#define AR5K_SIMR3_QCBRURN_S	16
+
+#define AR5K_SIMR4		0x00b4			/* Register Address [5211+] */
+#define AR5K_SIMR4_QTRIG	0x000003ff	/* Mask for QTRIG */
+#define AR5K_SIMR4_QTRIG_S	0
+
+
+/*
+ * Decompression mask registers [5212+]
+ */
+#define AR5K_DCM_ADDR		0x0400		/*Decompression mask address (?)*/
+#define AR5K_DCM_DATA		0x0404		/*Decompression mask data (?)*/
+
+/*
+ * Decompression configuration registers [5212+]
+ */
+#define AR5K_DCCFG		0x0420
+
+/*
+ * Compression configuration registers [5212+]
+ */
+#define AR5K_CCFG		0x0600
+#define AR5K_CCFG_CUP		0x0604
+
+/*
+ * Compression performance counter registers [5212+]
+ */
+#define AR5K_CPC0		0x0610		/* Compression performance counter 0 */
+#define AR5K_CPC1		0x0614		/* Compression performance counter 1*/
+#define AR5K_CPC2		0x0618		/* Compression performance counter 2 */
+#define AR5K_CPC3		0x061c		/* Compression performance counter 3 */
+#define AR5K_CPCORN		0x0620		/* Compression performance overrun (?) */
+
+
+/*
+ * Queue control unit (QCU) registers [5211+]
+ *
+ * Card has 12 TX Queues but i see that only 0-9 are used (?)
+ * both in binary HAL (see ah.h) and ar5k. Each queue has it's own
+ * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate)
+ * configuration register (0x08c0 - 0x08ec), a ready time configuration
+ * register (0x0900 - 0x092c), a misc configuration register (0x09c0 -
+ * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some
+ * global registers, QCU transmit enable/disable and "one shot arm (?)"
+ * set/clear, which contain status for all queues (we shift by 1 for each
+ * queue). To access these registers easily we define some macros here
+ * that are used inside HAL. For more infos check out *_tx_queue functs.
+ *
+ * TODO: Boundary checking on macros (here?)
+ */
+
+/*
+ * Generic QCU Register access macros
+ */
+#define	AR5K_QUEUE_REG(_r, _q)		(((_q) << 2) + _r)
+#define AR5K_QCU_GLOBAL_READ(_r, _q)	(AR5K_REG_READ(_r) & (1 << _q))
+#define AR5K_QCU_GLOBAL_WRITE(_r, _q)	AR5K_REG_WRITE(_r, (1 << _q))
+
+/*
+ * QCU Transmit descriptor pointer registers
+ */
+#define AR5K_QCU_TXDP_BASE	0x0800		/* Register Address - Queue0 TXDP */
+#define AR5K_QUEUE_TXDP(_q)	AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q)
+
+/*
+ * QCU Transmit enable register
+ */
+#define AR5K_QCU_TXE		0x0840
+#define AR5K_ENABLE_QUEUE(_q)	AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q)
+#define AR5K_QUEUE_ENABLED(_q)	AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q)
+
+/*
+ * QCU Transmit disable register
+ */
+#define AR5K_QCU_TXD		0x0880
+#define AR5K_DISABLE_QUEUE(_q)	AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q)
+#define AR5K_QUEUE_DISABLED(_q)	AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q)
+
+/*
+ * QCU Constant Bit Rate configuration registers
+ */
+#define	AR5K_QCU_CBRCFG_BASE		0x08c0	/* Register Address - Queue0 CBRCFG */
+#define	AR5K_QCU_CBRCFG_INTVAL		0x00ffffff	/* CBR Interval mask */
+#define AR5K_QCU_CBRCFG_INTVAL_S	0
+#define	AR5K_QCU_CBRCFG_ORN_THRES	0xff000000	/* CBR overrun threshold mask */
+#define AR5K_QCU_CBRCFG_ORN_THRES_S	24
+#define	AR5K_QUEUE_CBRCFG(_q)		AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q)
+
+/*
+ * QCU Ready time configuration registers
+ */
+#define	AR5K_QCU_RDYTIMECFG_BASE	0x0900	/* Register Address - Queue0 RDYTIMECFG */
+#define	AR5K_QCU_RDYTIMECFG_INTVAL	0x00ffffff	/* Ready time interval mask */
+#define AR5K_QCU_RDYTIMECFG_INTVAL_S	0
+#define	AR5K_QCU_RDYTIMECFG_DURATION	0x00ffffff	/* Ready time duration mask */
+#define	AR5K_QCU_RDYTIMECFG_ENABLE	0x01000000	/* Ready time enable mask */
+#define AR5K_QUEUE_RDYTIMECFG(_q)	AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q)
+
+/*
+ * QCU one shot arm set registers
+ */
+#define	AR5K_QCU_ONESHOTARM_SET		0x0940	/* Register Address -QCU "one shot arm set (?)" */
+#define	AR5K_QCU_ONESHOTARM_SET_M	0x0000ffff
+
+/*
+ * QCU one shot arm clear registers
+ */
+#define	AR5K_QCU_ONESHOTARM_CLEAR	0x0980	/* Register Address -QCU "one shot arm clear (?)" */
+#define	AR5K_QCU_ONESHOTARM_CLEAR_M	0x0000ffff
+
+/*
+ * QCU misc registers
+ */
+#define AR5K_QCU_MISC_BASE		0x09c0			/* Register Address -Queue0 MISC */
+#define	AR5K_QCU_MISC_FRSHED_M		0x0000000f	/* Frame sheduling mask */
+#define	AR5K_QCU_MISC_FRSHED_ASAP	0		/* ASAP */
+#define	AR5K_QCU_MISC_FRSHED_CBR	1		/* Constant Bit Rate */
+#define	AR5K_QCU_MISC_FRSHED_DBA_GT	2		/* DMA Beacon alert gated (?) */
+#define	AR5K_QCU_MISC_FRSHED_TIM_GT	3		/* Time gated (?) */
+#define	AR5K_QCU_MISC_FRSHED_BCN_SENT_GT	4	/* Beacon sent gated (?) */
+#define	AR5K_QCU_MISC_ONESHOT_ENABLE	0x00000010	/* Oneshot enable */
+#define	AR5K_QCU_MISC_CBREXP		0x00000020	/* CBR expired (normal queue) */
+#define	AR5K_QCU_MISC_CBREXP_BCN	0x00000040	/* CBR expired (beacon queue) */
+#define	AR5K_QCU_MISC_BCN_ENABLE	0x00000080	/* Beacons enabled */
+#define	AR5K_QCU_MISC_CBR_THRES_ENABLE	0x00000100	/* CBR threshold enabled (?) */
+#define	AR5K_QCU_MISC_TXE		0x00000200	/* TXE reset when RDYTIME enalbed (?) */
+#define	AR5K_QCU_MISC_CBR		0x00000400	/* CBR threshold reset (?) */
+#define	AR5K_QCU_MISC_DCU_EARLY		0x00000800	/* DCU reset (?) */
+#define AR5K_QUEUE_MISC(_q)		AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q)
+
+
+/*
+ * QCU status registers
+ */
+#define AR5K_QCU_STS_BASE	0x0a00			/* Register Address - Queue0 STS */
+#define	AR5K_QCU_STS_FRMPENDCNT	0x00000003	/* Frames pending counter */
+#define	AR5K_QCU_STS_CBREXPCNT	0x0000ff00	/* CBR expired counter (?) */
+#define	AR5K_QUEUE_STATUS(_q)	AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q)
+
+/*
+ * QCU ready time shutdown register
+ */
+#define AR5K_QCU_RDYTIMESHDN	0x0a40
+#define AR5K_QCU_RDYTIMESHDN_M	0x000003ff
+
+/*
+ * QCU compression buffer base registers [5212+]
+ */
+#define AR5K_QCU_CBB_SELECT	0x0b00
+#define AR5K_QCU_CBB_ADDR	0x0b04
+
+/*
+ * QCU compression buffer configuration register [5212+]
+ */
+#define AR5K_QCU_CBCFG		0x0b08
+
+
+
+/*
+ * Distributed Coordination Function (DCF) control unit (DCU)
+ * registers [5211+]
+ *
+ * These registers control the various characteristics of each queue
+ * for 802.11e (WME) combatibility so they go together with
+ * QCU registers in pairs. For each queue we have a QCU mask register,
+ * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c),
+ * a retry limit register (0x1080 - 0x10ac), a channel time register
+ * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and
+ * a sequence number register (0x1140 - 0x116c). It seems that "global"
+ * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k).
+ * We use the same macros here for easier register access.
+ *
+ */
+
+/*
+ * DCU QCU mask registers
+ */
+#define AR5K_DCU_QCUMASK_BASE	0x1000		/* Register Address -Queue0 DCU_QCUMASK */
+#define AR5K_DCU_QCUMASK_M	0x000003ff
+#define AR5K_QUEUE_QCUMASK(_q)	AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q)
+
+/*
+ * DCU local Inter Frame Space settings register
+ */
+#define AR5K_DCU_LCL_IFS_BASE		0x1040			/* Register Address -Queue0 DCU_LCL_IFS */
+#define	AR5K_DCU_LCL_IFS_CW_MIN	        0x000003ff	/* Minimum Contention Window */
+#define	AR5K_DCU_LCL_IFS_CW_MIN_S	0
+#define	AR5K_DCU_LCL_IFS_CW_MAX	        0x000ffc00	/* Maximum Contention Window */
+#define	AR5K_DCU_LCL_IFS_CW_MAX_S	10
+#define	AR5K_DCU_LCL_IFS_AIFS		0x0ff00000	/* Arbitrated Interframe Space */
+#define	AR5K_DCU_LCL_IFS_AIFS_S		20
+#define	AR5K_QUEUE_DFS_LOCAL_IFS(_q)	AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q)
+
+/*
+ * DCU retry limit registers
+ */
+#define AR5K_DCU_RETRY_LMT_BASE		0x1080			/* Register Address -Queue0 DCU_RETRY_LMT */
+#define AR5K_DCU_RETRY_LMT_SH_RETRY	0x0000000f	/* Short retry limit mask */
+#define AR5K_DCU_RETRY_LMT_SH_RETRY_S	0
+#define AR5K_DCU_RETRY_LMT_LG_RETRY	0x000000f0	/* Long retry limit mask */
+#define AR5K_DCU_RETRY_LMT_LG_RETRY_S	4
+#define AR5K_DCU_RETRY_LMT_SSH_RETRY	0x00003f00	/* Station short retry limit mask (?) */
+#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S	8
+#define AR5K_DCU_RETRY_LMT_SLG_RETRY	0x000fc000	/* Station long retry limit mask (?) */
+#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S	14
+#define	AR5K_QUEUE_DFS_RETRY_LIMIT(_q)	AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q)
+
+/*
+ * DCU channel time registers
+ */
+#define AR5K_DCU_CHAN_TIME_BASE		0x10c0			/* Register Address -Queue0 DCU_CHAN_TIME */
+#define	AR5K_DCU_CHAN_TIME_DUR		0x000fffff	/* Channel time duration */
+#define	AR5K_DCU_CHAN_TIME_DUR_S	0
+#define	AR5K_DCU_CHAN_TIME_ENABLE	0x00100000	/* Enable channel time */
+#define AR5K_QUEUE_DFS_CHANNEL_TIME(_q)	AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q)
+
+/*
+ * DCU misc registers [5211+]
+ *
+ * For some of the registers i couldn't find in the code
+ * (only backoff stuff is there realy) i tried to match the
+ * names with 802.11e parameters etc, so i guess VIRTCOL here
+ * means Virtual Collision and HCFPOLL means Hybrid Coordination
+ * factor Poll (CF- Poll). Arbiter lockout control controls the
+ * behaviour on low priority queues when we have multiple queues
+ * with pending frames. Intra-frame lockout means we wait until
+ * the queue's current frame transmits (with post frame backoff and bursting)
+ * before we transmit anything else and global lockout means we
+ * wait for the whole queue to finish before higher priority queues
+ * can transmit (this is used on beacon and CAB queues).
+ * No lockout means there is no special handling.
+ */
+#define AR5K_DCU_MISC_BASE		0x1100			/* Register Address -Queue0 DCU_MISC */
+#define	AR5K_DCU_MISC_BACKOFF		0x000007ff	/* Mask for backoff setting (?) */
+#define AR5K_DCU_MISC_BACKOFF_FRAG	0x00000200	/* Enable backoff while bursting */
+#define	AR5K_DCU_MISC_HCFPOLL_ENABLE	0x00000800	/* CF - Poll (?) */
+#define	AR5K_DCU_MISC_BACKOFF_PERSIST	0x00001000	/* Persistent backoff (?) */
+#define	AR5K_DCU_MISC_FRMPRFTCH_ENABLE	0x00002000	/* Enable frame pre-fetch (?) */
+#define	AR5K_DCU_MISC_VIRTCOL		0x0000c000	/* Mask for Virtual Collision (?) */
+#define	AR5K_DCU_MISC_VIRTCOL_NORMAL	0
+#define	AR5K_DCU_MISC_VIRTCOL_MODIFIED	1
+#define	AR5K_DCU_MISC_VIRTCOL_IGNORE	2
+#define	AR5K_DCU_MISC_BCN_ENABLE	0x00010000	/* Beacon enable (?) */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL	0x00060000	/* Arbiter lockout control mask */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_S	17
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_NONE	0		/* No arbiter lockout */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM	1	/* Intra-frame lockout */
+#define	AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL	2	/* Global lockout */
+#define	AR5K_DCU_MISC_ARBLOCK_IGNORE	0x00080000
+#define	AR5K_DCU_MISC_SEQ_NUM_INCR_DIS	0x00100000	/* Disable sequence number increment (?) */
+#define	AR5K_DCU_MISC_POST_FR_BKOFF_DIS	0x00200000	/* Disable post-frame backoff (?) */
+#define	AR5K_DCU_MISC_VIRT_COLL_POLICY	0x00400000	/* Virtual Collision policy (?) */
+#define	AR5K_DCU_MISC_BLOWN_IFS_POLICY	0x00800000
+#define	AR5K_DCU_MISC_SEQNUM_CTL	0x01000000	/* Sequence number control (?) */
+#define AR5K_QUEUE_DFS_MISC(_q)		AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q)
+
+/*
+ * DCU frame sequence number registers
+ */
+#define AR5K_DCU_SEQNUM_BASE	0x1140
+#define	AR5K_DCU_SEQNUM_M	0x00000fff
+#define	AR5K_QUEUE_DFS_SEQNUM(_q)	AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
+
+/*
+ * DCU global IFS SIFS registers
+ */
+#define AR5K_DCU_GBL_IFS_SIFS	0x1030
+#define AR5K_DCU_GBL_IFS_SIFS_M	0x0000ffff
+
+/*
+ * DCU global IFS slot interval registers
+ */
+#define AR5K_DCU_GBL_IFS_SLOT	0x1070
+#define AR5K_DCU_GBL_IFS_SLOT_M	0x0000ffff
+
+/*
+ * DCU global IFS EIFS registers
+ */
+#define AR5K_DCU_GBL_IFS_EIFS	0x10b0
+#define AR5K_DCU_GBL_IFS_EIFS_M	0x0000ffff
+
+/*
+ * DCU global IFS misc registers
+ */
+#define AR5K_DCU_GBL_IFS_MISC			0x10f0			/* Register Address */
+#define	AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE	0x00000007
+#define	AR5K_DCU_GBL_IFS_MISC_TURBO_MODE	0x00000008	/* Turbo mode (?) */
+#define	AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC	0x000003f0	/* SIFS Duration mask (?) */
+#define	AR5K_DCU_GBL_IFS_MISC_USEC_DUR		0x000ffc00
+#define	AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY	0x00300000
+
+/*
+ * DCU frame prefetch control register
+ */
+#define AR5K_DCU_FP		0x1230
+
+/*
+ * DCU transmit pause control/status register
+ */
+#define AR5K_DCU_TXP		0x1270			/* Register Address */
+#define	AR5K_DCU_TXP_M		0x000003ff	/* Tx pause mask (?) */
+#define	AR5K_DCU_TXP_STATUS	0x00010000	/* Tx pause status (?) */
+
+/*
+ * DCU transmit filter register
+ */
+#define AR5K_DCU_TX_FILTER	0x1038
+
+/*
+ * DCU clear transmit filter register
+ */
+#define AR5K_DCU_TX_FILTER_CLR	0x143c
+
+/*
+ * DCU set transmit filter register
+ */
+#define AR5K_DCU_TX_FILTER_SET	0x147c
+
+/*
+ * Reset control register
+ *
+ * 4 and 8 are not used in 5211/5212 and
+ * 2 means "baseband reset" on 5211/5212.
+ */
+#define AR5K_RESET_CTL		0x4000			/* Register Address */
+#define AR5K_RESET_CTL_PCU	0x00000001	/* Protocol Control Unit reset */
+#define AR5K_RESET_CTL_DMA	0x00000002	/* DMA (Rx/Tx) reset [5210] */
+#define	AR5K_RESET_CTL_BASEBAND	0x00000002	/* Baseband reset [5211+] */
+#define AR5K_RESET_CTL_MAC	0x00000004	/* MAC reset (PCU+Baseband ?) [5210] */
+#define AR5K_RESET_CTL_PHY	0x00000008	/* PHY reset [5210] */
+#define AR5K_RESET_CTL_PCI	0x00000010	/* PCI Core reset (interrupts etc) */
+#define AR5K_RESET_CTL_CHIP	(AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA |	\
+				AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY)
+
+/*
+ * Sleep control register
+ */
+#define AR5K_SLEEP_CTL			0x4004			/* Register Address */
+#define AR5K_SLEEP_CTL_SLDUR		0x0000ffff	/* Sleep duration mask */
+#define AR5K_SLEEP_CTL_SLDUR_S		0
+#define AR5K_SLEEP_CTL_SLE		0x00030000	/* Sleep enable mask */
+#define AR5K_SLEEP_CTL_SLE_S		16
+#define AR5K_SLEEP_CTL_SLE_WAKE		0x00000000	/* Force chip awake */
+#define AR5K_SLEEP_CTL_SLE_SLP		0x00010000	/* Force chip sleep */
+#define AR5K_SLEEP_CTL_SLE_ALLOW	0x00020000
+#define AR5K_SLEEP_CTL_SLE_UNITS	0x00000008	/* [5211+] */
+
+/*
+ * Interrupt pending register
+ */
+#define AR5K_INTPEND	0x4008
+#define AR5K_INTPEND_M	0x00000001
+
+/*
+ * Sleep force register
+ */
+#define AR5K_SFR	0x400c
+#define AR5K_SFR_M	0x00000001
+
+/*
+ * PCI configuration register
+ */
+#define AR5K_PCICFG			0x4010			/* Register Address */
+#define AR5K_PCICFG_EEAE		0x00000001	/* Eeprom access enable [5210] */
+#define AR5K_PCICFG_CLKRUNEN		0x00000004	/* CLKRUN enable [5211+] */
+#define AR5K_PCICFG_EESIZE		0x00000018	/* Mask for EEPROM size [5211+] */
+#define AR5K_PCICFG_EESIZE_S		3
+#define AR5K_PCICFG_EESIZE_4K		0		/* 4K */
+#define AR5K_PCICFG_EESIZE_8K		1		/* 8K */
+#define AR5K_PCICFG_EESIZE_16K		2		/* 16K */
+#define AR5K_PCICFG_EESIZE_FAIL		3		/* Failed to get size (?) [5211+] */
+#define AR5K_PCICFG_LED			0x00000060	/* Led status [5211+] */
+#define AR5K_PCICFG_LED_NONE		0x00000000	/* Default [5211+] */
+#define AR5K_PCICFG_LED_PEND		0x00000020	/* Scan / Auth pending */
+#define AR5K_PCICFG_LED_ASSOC		0x00000040	/* Associated */
+#define	AR5K_PCICFG_BUS_SEL		0x00000380	/* Mask for "bus select" [5211+] (?) */
+#define	AR5K_PCICFG_CBEFIX_DIS		0x00000400	/* Disable CBE fix (?) */
+#define AR5K_PCICFG_SL_INTEN		0x00000800	/* Enable interrupts when asleep (?) */
+#define AR5K_PCICFG_LED_BCTL		0x00001000	/* Led blink (?) [5210] */
+#define AR5K_PCICFG_SL_INPEN		0x00002800	/* Sleep even whith pending interrupts (?) */
+#define AR5K_PCICFG_SPWR_DN		0x00010000	/* Mask for power status */
+#define AR5K_PCICFG_LEDMODE		0x000e0000	/* Ledmode [5211+] */
+#define AR5K_PCICFG_LEDMODE_PROP	0x00000000	/* Blink on standard traffic [5211+] */
+#define AR5K_PCICFG_LEDMODE_PROM	0x00020000	/* Default mode (blink on any traffic) [5211+] */
+#define AR5K_PCICFG_LEDMODE_PWR		0x00040000	/* Some other blinking mode  (?) [5211+] */
+#define AR5K_PCICFG_LEDMODE_RAND	0x00060000	/* Random blinking (?) [5211+] */
+#define AR5K_PCICFG_LEDBLINK		0x00700000
+#define AR5K_PCICFG_LEDBLINK_S		20
+#define AR5K_PCICFG_LEDSLOW		0x00800000	/* Slow led blink rate (?) [5211+] */
+#define AR5K_PCICFG_LEDSTATE				\
+	(AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE |	\
+	AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW)
+
+/*
+ * "General Purpose Input/Output" (GPIO) control register
+ *
+ * I'm not sure about this but after looking at the code
+ * for all chipsets here is what i got.
+ *
+ * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits)
+ * Mode 0 -> always input
+ * Mode 1 -> output when GPIODO for this GPIO is set to 0
+ * Mode 2 -> output when GPIODO for this GPIO is set to 1
+ * Mode 3 -> always output
+ *
+ * For more infos check out get_gpio/set_gpio and
+ * set_gpio_input/set_gpio_output functs.
+ * For more infos on gpio interrupt check out set_gpio_intr.
+ */
+#define AR5K_NUM_GPIO	6
+
+#define AR5K_GPIOCR		0x4014				/* Register Address */
+#define AR5K_GPIOCR_INT_ENA	0x00008000		/* Enable GPIO interrupt */
+#define AR5K_GPIOCR_INT_SELL	0x00000000		/* Generate interrupt when pin is off (?) */
+#define AR5K_GPIOCR_INT_SELH	0x00010000		/* Generate interrupt when pin is on */
+#define AR5K_GPIOCR_IN(n)	(0 << ((n) * 2))	/* Mode 0 for pin n */
+#define AR5K_GPIOCR_OUT0(n)	(1 << ((n) * 2))	/* Mode 1 for pin n */
+#define AR5K_GPIOCR_OUT1(n)	(2 << ((n) * 2))	/* Mode 2 for pin n */
+#define AR5K_GPIOCR_OUT(n)	(3 << ((n) * 2))	/* Mode 3 for pin n */
+#define AR5K_GPIOCR_INT_SEL(n)	((n) << 12)		/* Interrupt for GPIO pin n */
+
+/*
+ * "General Purpose Input/Output" (GPIO) data output register
+ */
+#define AR5K_GPIODO	0x4018
+
+/*
+ * "General Purpose Input/Output" (GPIO) data input register
+ */
+#define AR5K_GPIODI	0x401c
+#define AR5K_GPIODI_M	0x0000002f
+
+
+/*
+ * Silicon revision register
+ */
+#define AR5K_SREV		0x4020			/* Register Address */
+#define AR5K_SREV_REV		0x0000000f	/* Mask for revision */
+#define AR5K_SREV_REV_S		0
+#define AR5K_SREV_VER		0x000000ff	/* Mask for version */
+#define AR5K_SREV_VER_S		4
+
+
+
+/*====EEPROM REGISTERS====*/
+
+/*
+ * EEPROM access registers
+ *
+ * Here we got a difference between 5210/5211-12
+ * read data register for 5210 is at 0x6800 and
+ * status register is at 0x6c00. There is also
+ * no eeprom command register on 5210 and the
+ * offsets are different.
+ *
+ * To read eeprom data for a specific offset:
+ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
+ *        read AR5K_EEPROM_BASE +(4 * offset)
+ *        check the eeprom status register
+ *        and read eeprom data register.
+ *
+ * 5211 - write offset to AR5K_EEPROM_BASE
+ * 5212   write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD
+ *        check the eeprom status register
+ *        and read eeprom data register.
+ *
+ * To write eeprom data for a specific offset:
+ * 5210 - enable eeprom access (AR5K_PCICFG_EEAE)
+ *        write data to AR5K_EEPROM_BASE +(4 * offset)
+ *        check the eeprom status register
+ * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD
+ * 5212   write offset to AR5K_EEPROM_BASE
+ *        write data to data register
+ *	  write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD
+ *        check the eeprom status register
+ *
+ * For more infos check eeprom_* functs and the ar5k.c
+ * file posted in madwifi-devel mailing list.
+ * http://sourceforge.net/mailarchive/message.php?msg_id=8966525
+ *
+ */
+#define AR5K_EEPROM_BASE	0x6000
+
+/*
+ * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
+ */
+#define AR5K_EEPROM_MAGIC		0x003d	/* EEPROM Magic number */
+#define AR5K_EEPROM_MAGIC_VALUE		0x5aa5	/* Default - found on EEPROM */
+#define AR5K_EEPROM_MAGIC_5212		0x0000145c /* 5212 */
+#define AR5K_EEPROM_MAGIC_5211		0x0000145b /* 5211 */
+#define AR5K_EEPROM_MAGIC_5210		0x0000145a /* 5210 */
+
+#define AR5K_EEPROM_PROTECT		0x003f	/* EEPROM protect status */
+#define AR5K_EEPROM_PROTECT_RD_0_31	0x0001	/* Read protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_WR_0_31	0x0002	/* Write protection bit for offsets 0x0 - 0x1f */
+#define AR5K_EEPROM_PROTECT_RD_32_63	0x0004	/* 0x20 - 0x3f */
+#define AR5K_EEPROM_PROTECT_WR_32_63	0x0008
+#define AR5K_EEPROM_PROTECT_RD_64_127	0x0010	/* 0x40 - 0x7f */
+#define AR5K_EEPROM_PROTECT_WR_64_127	0x0020
+#define AR5K_EEPROM_PROTECT_RD_128_191	0x0040	/* 0x80 - 0xbf (regdom) */
+#define AR5K_EEPROM_PROTECT_WR_128_191	0x0080
+#define AR5K_EEPROM_PROTECT_RD_192_207	0x0100	/* 0xc0 - 0xcf */
+#define AR5K_EEPROM_PROTECT_WR_192_207	0x0200
+#define AR5K_EEPROM_PROTECT_RD_208_223	0x0400	/* 0xd0 - 0xdf */
+#define AR5K_EEPROM_PROTECT_WR_208_223	0x0800
+#define AR5K_EEPROM_PROTECT_RD_224_239	0x1000	/* 0xe0 - 0xef */
+#define AR5K_EEPROM_PROTECT_WR_224_239	0x2000
+#define AR5K_EEPROM_PROTECT_RD_240_255	0x4000	/* 0xf0 - 0xff */
+#define AR5K_EEPROM_PROTECT_WR_240_255	0x8000
+#define AR5K_EEPROM_REG_DOMAIN		0x00bf	/* EEPROM regdom */
+#define AR5K_EEPROM_INFO_BASE		0x00c0	/* EEPROM header */
+#define AR5K_EEPROM_INFO_MAX		(0x400 - AR5K_EEPROM_INFO_BASE)
+#define AR5K_EEPROM_INFO_CKSUM		0xffff
+#define AR5K_EEPROM_INFO(_n)		(AR5K_EEPROM_INFO_BASE + (_n))
+
+#define AR5K_EEPROM_VERSION		AR5K_EEPROM_INFO(1)	/* EEPROM Version */
+#define AR5K_EEPROM_VERSION_3_0		0x3000	/* No idea what's going on before this version */
+#define AR5K_EEPROM_VERSION_3_1		0x3001	/* ob/db values for 2Ghz (ar5211_rfregs) */
+#define AR5K_EEPROM_VERSION_3_2		0x3002	/* different frequency representation (eeprom_bin2freq) */
+#define AR5K_EEPROM_VERSION_3_3		0x3003	/* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_3_4		0x3004	/* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */
+#define AR5K_EEPROM_VERSION_4_0		0x4000	/* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_1		0x4001	/* has ee_margin_tx_rx (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_2		0x4002	/* has ee_cck_ofdm_gain_delta (eeprom_init) */
+#define AR5K_EEPROM_VERSION_4_3		0x4003
+#define AR5K_EEPROM_VERSION_4_4		0x4004
+#define AR5K_EEPROM_VERSION_4_5		0x4005
+#define AR5K_EEPROM_VERSION_4_6		0x4006	/* has ee_scaled_cck_delta */
+#define AR5K_EEPROM_VERSION_4_7		0x3007
+
+#define AR5K_EEPROM_MODE_11A		0
+#define AR5K_EEPROM_MODE_11B		1
+#define AR5K_EEPROM_MODE_11G		2
+
+#define AR5K_EEPROM_HDR			AR5K_EEPROM_INFO(2)	/* Header that contains the device caps */
+#define AR5K_EEPROM_HDR_11A(_v)		(((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
+#define AR5K_EEPROM_HDR_11B(_v)		(((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
+#define AR5K_EEPROM_HDR_11G(_v)		(((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
+#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v)	(((_v) >> 3) & 0x1)	/* Disable turbo for 2Ghz (?) */
+#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v)	(((_v) >> 4) & 0x7f)	/* Max turbo power for a/XR mode (eeprom_init) */
+#define AR5K_EEPROM_HDR_DEVICE(_v)	(((_v) >> 11) & 0x7)
+#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v)	(((_v) >> 15) & 0x1)	/* Disable turbo for 5Ghz (?) */
+#define AR5K_EEPROM_HDR_RFKILL(_v)	(((_v) >> 14) & 0x1)	/* Device has RFKill support */
+
+#define AR5K_EEPROM_RFKILL_GPIO_SEL	0x0000001c
+#define AR5K_EEPROM_RFKILL_GPIO_SEL_S	2
+#define AR5K_EEPROM_RFKILL_POLARITY	0x00000002
+#define AR5K_EEPROM_RFKILL_POLARITY_S	1
+
+/* Newer EEPROMs are using a different offset */
+#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \
+	(((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0)
+
+#define AR5K_EEPROM_ANT_GAIN(_v)	AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3)
+#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v)	((int8_t)(((_v) >> 8) & 0xff))
+#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v)	((int8_t)((_v) & 0xff))
+
+/* calibration settings */
+#define AR5K_EEPROM_MODES_11A(_v)	AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
+#define AR5K_EEPROM_MODES_11B(_v)	AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2)
+#define AR5K_EEPROM_MODES_11G(_v)	AR5K_EEPROM_OFF(_v, 0x00da, 0x010d)
+#define AR5K_EEPROM_CTL(_v)		AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128)	/* Conformance test limits */
+
+/* [3.1 - 3.3] */
+#define AR5K_EEPROM_OBDB0_2GHZ		0x00ec
+#define AR5K_EEPROM_OBDB1_2GHZ		0x00ed
+
+/* Misc values available since EEPROM 4.0 */
+#define AR5K_EEPROM_MISC0		0x00c4
+#define AR5K_EEPROM_EARSTART(_v)	((_v) & 0xfff)
+#define AR5K_EEPROM_EEMAP(_v)		(((_v) >> 14) & 0x3)
+#define AR5K_EEPROM_MISC1		0x00c5
+#define AR5K_EEPROM_TARGET_PWRSTART(_v)	((_v) & 0xfff)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)	(((_v) >> 14) & 0x1)
+
+/*
+ * EEPROM data register
+ */
+#define AR5K_EEPROM_DATA_5211	0x6004
+#define AR5K_EEPROM_DATA_5210	0x6800
+#define	AR5K_EEPROM_DATA	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211)
+
+/*
+ * EEPROM command register
+ */
+#define AR5K_EEPROM_CMD		0x6008			/* Register Addres */
+#define AR5K_EEPROM_CMD_READ	0x00000001	/* EEPROM read */
+#define AR5K_EEPROM_CMD_WRITE	0x00000002	/* EEPROM write */
+#define AR5K_EEPROM_CMD_RESET	0x00000004	/* EEPROM reset */
+
+/*
+ * EEPROM status register
+ */
+#define AR5K_EEPROM_STAT_5210	0x6c00			/* Register Address [5210] */
+#define AR5K_EEPROM_STAT_5211	0x600c			/* Register Address [5211+] */
+#define	AR5K_EEPROM_STATUS	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211)
+#define AR5K_EEPROM_STAT_RDERR	0x00000001	/* EEPROM read failed */
+#define AR5K_EEPROM_STAT_RDDONE	0x00000002	/* EEPROM read successful */
+#define AR5K_EEPROM_STAT_WRERR	0x00000004	/* EEPROM write failed */
+#define AR5K_EEPROM_STAT_WRDONE	0x00000008	/* EEPROM write successful */
+
+/*
+ * EEPROM config register (?)
+ */
+#define AR5K_EEPROM_CFG	0x6010
+
+
+
+/*
+ * Protocol Control Unit (PCU) registers
+ */
+/*
+ * Used for checking initial register writes
+ * during channel reset (see reset func)
+ */
+#define AR5K_PCU_MIN	0x8000
+#define AR5K_PCU_MAX	0x8fff
+
+/*
+ * First station id register (MAC address in lower 32 bits)
+ */
+#define AR5K_STA_ID0	0x8000
+
+/*
+ * Second station id register (MAC address in upper 16 bits)
+ */
+#define AR5K_STA_ID1			0x8004			/* Register Address */
+#define AR5K_STA_ID1_AP			0x00010000	/* Set AP mode */
+#define AR5K_STA_ID1_ADHOC		0x00020000	/* Set Ad-Hoc mode */
+#define AR5K_STA_ID1_PWR_SV		0x00040000	/* Power save reporting (?) */
+#define AR5K_STA_ID1_NO_KEYSRCH		0x00080000	/* No key search */
+#define AR5K_STA_ID1_NO_PSPOLL		0x00100000	/* No power save polling [5210] */
+#define AR5K_STA_ID1_PCF_5211		0x00100000	/* Enable PCF on [5211+] */
+#define AR5K_STA_ID1_PCF_5210		0x00200000	/* Enable PCF on [5210]*/
+#define	AR5K_STA_ID1_PCF		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211)
+#define AR5K_STA_ID1_DEFAULT_ANTENNA	0x00200000	/* Use default antenna */
+#define AR5K_STA_ID1_DESC_ANTENNA	0x00400000	/* Update antenna from descriptor */
+#define AR5K_STA_ID1_RTS_DEF_ANTENNA	0x00800000	/* Use default antenna for RTS (?) */
+#define AR5K_STA_ID1_ACKCTS_6MB		0x01000000	/* Use 6Mbit/s for ACK/CTS (?) */
+#define AR5K_STA_ID1_BASE_RATE_11B	0x02000000	/* Use 11b base rate (for ACK/CTS ?) [5211+] */
+
+/*
+ * First BSSID register (MAC address, lower 32bits)
+ */
+#define AR5K_BSS_ID0	0x8008
+
+/*
+ * Second BSSID register (MAC address in upper 16 bits)
+ *
+ * AID: Association ID
+ */
+#define AR5K_BSS_ID1		0x800c
+#define AR5K_BSS_ID1_AID	0xffff0000
+#define AR5K_BSS_ID1_AID_S	16
+
+/*
+ * Backoff slot time register
+ */
+#define AR5K_SLOT_TIME	0x8010
+
+/*
+ * ACK/CTS timeout register
+ */
+#define AR5K_TIME_OUT		0x8014			/* Register Address */
+#define AR5K_TIME_OUT_ACK	0x00001fff	/* ACK timeout mask */
+#define AR5K_TIME_OUT_ACK_S	0
+#define AR5K_TIME_OUT_CTS	0x1fff0000	/* CTS timeout mask */
+#define AR5K_TIME_OUT_CTS_S	16
+
+/*
+ * RSSI threshold register
+ */
+#define AR5K_RSSI_THR			0x8018		/* Register Address */
+#define AR5K_RSSI_THR_M			0x000000ff	/* Mask for RSSI threshold [5211+] */
+#define AR5K_RSSI_THR_BMISS_5210	0x00000700	/* Mask for Beacon Missed threshold [5210] */
+#define AR5K_RSSI_THR_BMISS_5210_S	8
+#define AR5K_RSSI_THR_BMISS_5211	0x0000ff00	/* Mask for Beacon Missed threshold [5211+] */
+#define AR5K_RSSI_THR_BMISS_5211_S	8
+#define	AR5K_RSSI_THR_BMISS		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211)
+#define	AR5K_RSSI_THR_BMISS_S		8
+
+/*
+ * 5210 has more PCU registers because there is no QCU/DCU
+ * so queue parameters are set here, this way a lot common
+ * registers have different address for 5210. To make things
+ * easier we define a macro based on ah->ah_version for common
+ * registers with different addresses and common flags.
+ */
+
+/*
+ * Retry limit register
+ *
+ * Retry limit register for 5210 (no QCU/DCU so it's done in PCU)
+ */
+#define AR5K_NODCU_RETRY_LMT		0x801c			/*Register Address */
+#define AR5K_NODCU_RETRY_LMT_SH_RETRY	0x0000000f	/* Short retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SH_RETRY_S	0
+#define AR5K_NODCU_RETRY_LMT_LG_RETRY	0x000000f0	/* Long retry mask */
+#define AR5K_NODCU_RETRY_LMT_LG_RETRY_S	4
+#define AR5K_NODCU_RETRY_LMT_SSH_RETRY	0x00003f00	/* Station short retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S	8
+#define AR5K_NODCU_RETRY_LMT_SLG_RETRY	0x000fc000	/* Station long retry limit mask */
+#define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S	14
+#define AR5K_NODCU_RETRY_LMT_CW_MIN	0x3ff00000	/* Minimum contention window mask */
+#define AR5K_NODCU_RETRY_LMT_CW_MIN_S	20
+
+/*
+ * Transmit latency register
+ */
+#define AR5K_USEC_5210			0x8020			/* Register Address [5210] */
+#define AR5K_USEC_5211			0x801c			/* Register Address [5211+] */
+#define AR5K_USEC			(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_USEC_5210 : AR5K_USEC_5211)
+#define AR5K_USEC_1			0x0000007f
+#define AR5K_USEC_1_S			0
+#define AR5K_USEC_32			0x00003f80
+#define AR5K_USEC_32_S			7
+#define AR5K_USEC_TX_LATENCY_5211	0x007fc000
+#define AR5K_USEC_TX_LATENCY_5211_S	14
+#define AR5K_USEC_RX_LATENCY_5211	0x1f800000
+#define AR5K_USEC_RX_LATENCY_5211_S	23
+#define AR5K_USEC_TX_LATENCY_5210	0x000fc000	/* also for 5311 */
+#define AR5K_USEC_TX_LATENCY_5210_S	14
+#define AR5K_USEC_RX_LATENCY_5210	0x03f00000	/* also for 5311 */
+#define AR5K_USEC_RX_LATENCY_5210_S	20
+
+/*
+ * PCU beacon control register
+ */
+#define AR5K_BEACON_5210	0x8024
+#define AR5K_BEACON_5211	0x8020
+#define AR5K_BEACON		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_BEACON_5210 : AR5K_BEACON_5211)
+#define AR5K_BEACON_PERIOD	0x0000ffff
+#define AR5K_BEACON_PERIOD_S	0
+#define AR5K_BEACON_TIM		0x007f0000
+#define AR5K_BEACON_TIM_S	16
+#define AR5K_BEACON_ENABLE	0x00800000
+#define AR5K_BEACON_RESET_TSF	0x01000000
+
+/*
+ * CFP period register
+ */
+#define AR5K_CFP_PERIOD_5210	0x8028
+#define AR5K_CFP_PERIOD_5211	0x8024
+#define AR5K_CFP_PERIOD		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211)
+
+/*
+ * Next beacon time register
+ */
+#define AR5K_TIMER0_5210	0x802c
+#define AR5K_TIMER0_5211	0x8028
+#define AR5K_TIMER0		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER0_5210 : AR5K_TIMER0_5211)
+
+/*
+ * Next DMA beacon alert register
+ */
+#define AR5K_TIMER1_5210	0x8030
+#define AR5K_TIMER1_5211	0x802c
+#define AR5K_TIMER1		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER1_5210 : AR5K_TIMER1_5211)
+
+/*
+ * Next software beacon alert register
+ */
+#define AR5K_TIMER2_5210	0x8034
+#define AR5K_TIMER2_5211	0x8030
+#define AR5K_TIMER2		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER2_5210 : AR5K_TIMER2_5211)
+
+/*
+ * Next ATIM window time register
+ */
+#define AR5K_TIMER3_5210	0x8038
+#define AR5K_TIMER3_5211	0x8034
+#define AR5K_TIMER3		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TIMER3_5210 : AR5K_TIMER3_5211)
+
+
+/*
+ * 5210 First inter frame spacing register (IFS)
+ */
+#define AR5K_IFS0		0x8040
+#define AR5K_IFS0_SIFS		0x000007ff
+#define AR5K_IFS0_SIFS_S	0
+#define AR5K_IFS0_DIFS		0x007ff800
+#define AR5K_IFS0_DIFS_S	11
+
+/*
+ * 5210 Second inter frame spacing register (IFS)
+ */
+#define AR5K_IFS1		0x8044
+#define AR5K_IFS1_PIFS		0x00000fff
+#define AR5K_IFS1_PIFS_S	0
+#define AR5K_IFS1_EIFS		0x03fff000
+#define AR5K_IFS1_EIFS_S	12
+#define AR5K_IFS1_CS_EN		0x04000000
+
+
+/*
+ * CFP duration register
+ */
+#define AR5K_CFP_DUR_5210	0x8048
+#define AR5K_CFP_DUR_5211	0x8038
+#define AR5K_CFP_DUR		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211)
+
+/*
+ * Receive filter register
+ * TODO: Get these out of ar5xxx.h on ath5k
+ */
+#define AR5K_RX_FILTER_5210	0x804c			/* Register Address [5210] */
+#define AR5K_RX_FILTER_5211	0x803c			/* Register Address [5211+] */
+#define AR5K_RX_FILTER		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211)
+#define	AR5K_RX_FILTER_UCAST 	0x00000001	/* Don't filter unicast frames */
+#define	AR5K_RX_FILTER_MCAST 	0x00000002	/* Don't filter multicast frames */
+#define	AR5K_RX_FILTER_BCAST 	0x00000004	/* Don't filter broadcast frames */
+#define	AR5K_RX_FILTER_CONTROL 	0x00000008	/* Don't filter control frames */
+#define	AR5K_RX_FILTER_BEACON 	0x00000010	/* Don't filter beacon frames */
+#define	AR5K_RX_FILTER_PROM 	0x00000020	/* Set promiscuous mode */
+#define	AR5K_RX_FILTER_XRPOLL 	0x00000040	/* Don't filter XR poll frame [5212+] */
+#define	AR5K_RX_FILTER_PROBEREQ 0x00000080	/* Don't filter probe requests [5212+] */
+#define	AR5K_RX_FILTER_PHYERR_5212	0x00000100	/* Don't filter phy errors [5212+] */
+#define	AR5K_RX_FILTER_RADARERR_5212 	0x00000200	/* Don't filter phy radar errors [5212+] */
+#define AR5K_RX_FILTER_PHYERR_5211	0x00000040	/* [5211] */
+#define AR5K_RX_FILTER_RADARERR_5211	0x00000080	/* [5211] */
+#define AR5K_RX_FILTER_PHYERR  \
+	((ah->ah_version == AR5K_AR5211 ? \
+	AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212))
+#define        AR5K_RX_FILTER_RADARERR \
+	((ah->ah_version == AR5K_AR5211 ? \
+	AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212))
+
+/*
+ * Multicast filter register (lower 32 bits)
+ */
+#define AR5K_MCAST_FILTER0_5210	0x8050
+#define AR5K_MCAST_FILTER0_5211	0x8040
+#define AR5K_MCAST_FILTER0	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211)
+
+/*
+ * Multicast filter register (higher 16 bits)
+ */
+#define AR5K_MCAST_FILTER1_5210	0x8054
+#define AR5K_MCAST_FILTER1_5211	0x8044
+#define AR5K_MCAST_FILTER1	(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211)
+
+
+/*
+ * Transmit mask register (lower 32 bits) [5210]
+ */
+#define AR5K_TX_MASK0	0x8058
+
+/*
+ * Transmit mask register (higher 16 bits) [5210]
+ */
+#define AR5K_TX_MASK1	0x805c
+
+/*
+ * Clear transmit mask [5210]
+ */
+#define AR5K_CLR_TMASK	0x8060
+
+/*
+ * Trigger level register (before transmission) [5210]
+ */
+#define AR5K_TRIG_LVL	0x8064
+
+
+/*
+ * PCU control register
+ *
+ * Only DIS_RX is used in the code, the rest i guess are
+ * for tweaking/diagnostics.
+ */
+#define AR5K_DIAG_SW_5210		0x8068			/* Register Address [5210] */
+#define AR5K_DIAG_SW_5211		0x8048			/* Register Address [5211+] */
+#define AR5K_DIAG_SW			(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211)
+#define AR5K_DIAG_SW_DIS_WEP_ACK	0x00000001
+#define AR5K_DIAG_SW_DIS_ACK		0x00000002	/* Disable ACKs (?) */
+#define AR5K_DIAG_SW_DIS_CTS		0x00000004	/* Disable CTSs (?) */
+#define AR5K_DIAG_SW_DIS_ENC		0x00000008	/* Disable encryption (?) */
+#define AR5K_DIAG_SW_DIS_DEC		0x00000010	/* Disable decryption (?) */
+#define AR5K_DIAG_SW_DIS_TX		0x00000020	/* Disable transmit [5210] */
+#define AR5K_DIAG_SW_DIS_RX_5210	0x00000040	/* Disable recieve */
+#define AR5K_DIAG_SW_DIS_RX_5211	0x00000020
+#define	AR5K_DIAG_SW_DIS_RX		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211)
+#define AR5K_DIAG_SW_LOOP_BACK_5210	0x00000080	/* Loopback (i guess it goes with DIS_TX) [5210] */
+#define AR5K_DIAG_SW_LOOP_BACK_5211	0x00000040
+#define AR5K_DIAG_SW_LOOP_BACK		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211)
+#define AR5K_DIAG_SW_CORR_FCS_5210	0x00000100
+#define AR5K_DIAG_SW_CORR_FCS_5211	0x00000080
+#define AR5K_DIAG_SW_CORR_FCS		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211)
+#define AR5K_DIAG_SW_CHAN_INFO_5210	0x00000200
+#define AR5K_DIAG_SW_CHAN_INFO_5211	0x00000100
+#define AR5K_DIAG_SW_CHAN_INFO		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211)
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211	0x00000200	/* Scrambler seed (?) */
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210	0x00000400
+#define AR5K_DIAG_SW_EN_SCRAM_SEED	(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211)
+#define AR5K_DIAG_SW_ECO_ENABLE		0x00000400	/* [5211+] */
+#define AR5K_DIAG_SW_SCVRAM_SEED	0x0003f800	/* [5210] */
+#define AR5K_DIAG_SW_SCRAM_SEED_M	0x0001fc00	/* Scrambler seed mask (?) */
+#define AR5K_DIAG_SW_SCRAM_SEED_S	10
+#define AR5K_DIAG_SW_DIS_SEQ_INC	0x00040000	/* Disable seqnum increment (?)[5210] */
+#define AR5K_DIAG_SW_FRAME_NV0_5210	0x00080000
+#define AR5K_DIAG_SW_FRAME_NV0_5211	0x00020000
+#define	AR5K_DIAG_SW_FRAME_NV0		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211)
+#define AR5K_DIAG_SW_OBSPT_M		0x000c0000
+#define AR5K_DIAG_SW_OBSPT_S		18
+
+/*
+ * TSF (clock) register (lower 32 bits)
+ */
+#define AR5K_TSF_L32_5210	0x806c
+#define AR5K_TSF_L32_5211	0x804c
+#define	AR5K_TSF_L32		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211)
+
+/*
+ * TSF (clock) register (higher 32 bits)
+ */
+#define AR5K_TSF_U32_5210	0x8070
+#define AR5K_TSF_U32_5211	0x8050
+#define	AR5K_TSF_U32		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211)
+
+/*
+ * Last beacon timestamp register
+ */
+#define AR5K_LAST_TSTP	0x8080
+
+/*
+ * ADDAC test register [5211+]
+ */
+#define AR5K_ADDAC_TEST	0x8054
+#define AR5K_ADDAC_TEST_TXCONT 0x00000001
+
+/*
+ * Default antenna register [5211+]
+ */
+#define AR5K_DEFAULT_ANTENNA	0x8058
+
+
+
+/*
+ * Retry count register [5210]
+ */
+#define AR5K_RETRY_CNT		0x8084			/* Register Address [5210] */
+#define AR5K_RETRY_CNT_SSH	0x0000003f	/* Station short retry count (?) */
+#define AR5K_RETRY_CNT_SLG	0x00000fc0	/* Station long retry count (?) */
+
+/*
+ * Back-off status register [5210]
+ */
+#define AR5K_BACKOFF		0x8088			/* Register Address [5210] */
+#define AR5K_BACKOFF_CW		0x000003ff	/* Backoff Contention Window (?) */
+#define AR5K_BACKOFF_CNT	0x03ff0000	/* Backoff count (?) */
+
+
+
+/*
+ * NAV register (current)
+ */
+#define AR5K_NAV_5210		0x808c
+#define AR5K_NAV_5211		0x8084
+#define	AR5K_NAV		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_NAV_5210 : AR5K_NAV_5211)
+
+/*
+ * RTS success register
+ */
+#define AR5K_RTS_OK_5210	0x8090
+#define AR5K_RTS_OK_5211	0x8088
+#define	AR5K_RTS_OK		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211)
+
+/*
+ * RTS failure register
+ */
+#define AR5K_RTS_FAIL_5210	0x8094
+#define AR5K_RTS_FAIL_5211	0x808c
+#define	AR5K_RTS_FAIL		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211)
+
+/*
+ * ACK failure register
+ */
+#define AR5K_ACK_FAIL_5210	0x8098
+#define AR5K_ACK_FAIL_5211	0x8090
+#define	AR5K_ACK_FAIL		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211)
+
+/*
+ * FCS failure register
+ */
+#define AR5K_FCS_FAIL_5210	0x809c
+#define AR5K_FCS_FAIL_5211	0x8094
+#define	AR5K_FCS_FAIL		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211)
+
+/*
+ * Beacon count register
+ */
+#define AR5K_BEACON_CNT_5210	0x80a0
+#define AR5K_BEACON_CNT_5211	0x8098
+#define	AR5K_BEACON_CNT		(ah->ah_version == AR5K_AR5210 ? \
+				AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211)
+
+
+/*===5212 Specific PCU registers===*/
+
+/*
+ * XR (eXtended Range) mode register
+ */
+#define AR5K_XRMODE			0x80c0
+#define	AR5K_XRMODE_POLL_TYPE_M		0x0000003f
+#define	AR5K_XRMODE_POLL_TYPE_S		0
+#define	AR5K_XRMODE_POLL_SUBTYPE_M	0x0000003c
+#define	AR5K_XRMODE_POLL_SUBTYPE_S	2
+#define	AR5K_XRMODE_POLL_WAIT_ALL	0x00000080
+#define	AR5K_XRMODE_SIFS_DELAY		0x000fff00
+#define	AR5K_XRMODE_FRAME_HOLD_M	0xfff00000
+#define	AR5K_XRMODE_FRAME_HOLD_S	20
+
+/*
+ * XR delay register
+ */
+#define AR5K_XRDELAY			0x80c4
+#define AR5K_XRDELAY_SLOT_DELAY_M	0x0000ffff
+#define AR5K_XRDELAY_SLOT_DELAY_S	0
+#define AR5K_XRDELAY_CHIRP_DELAY_M	0xffff0000
+#define AR5K_XRDELAY_CHIRP_DELAY_S	16
+
+/*
+ * XR timeout register
+ */
+#define AR5K_XRTIMEOUT			0x80c8
+#define AR5K_XRTIMEOUT_CHIRP_M		0x0000ffff
+#define AR5K_XRTIMEOUT_CHIRP_S		0
+#define AR5K_XRTIMEOUT_POLL_M		0xffff0000
+#define AR5K_XRTIMEOUT_POLL_S		16
+
+/*
+ * XR chirp register
+ */
+#define AR5K_XRCHIRP			0x80cc
+#define AR5K_XRCHIRP_SEND		0x00000001
+#define AR5K_XRCHIRP_GAP		0xffff0000
+
+/*
+ * XR stomp register
+ */
+#define AR5K_XRSTOMP			0x80d0
+#define AR5K_XRSTOMP_TX			0x00000001
+#define AR5K_XRSTOMP_RX_ABORT		0x00000002
+#define AR5K_XRSTOMP_RSSI_THRES		0x0000ff00
+
+/*
+ * First enhanced sleep register
+ */
+#define AR5K_SLEEP0			0x80d4
+#define AR5K_SLEEP0_NEXT_DTIM		0x0007ffff
+#define AR5K_SLEEP0_NEXT_DTIM_S		0
+#define AR5K_SLEEP0_ASSUME_DTIM		0x00080000
+#define AR5K_SLEEP0_ENH_SLEEP_EN	0x00100000
+#define AR5K_SLEEP0_CABTO		0xff000000
+#define AR5K_SLEEP0_CABTO_S		24
+
+/*
+ * Second enhanced sleep register
+ */
+#define AR5K_SLEEP1			0x80d8
+#define AR5K_SLEEP1_NEXT_TIM		0x0007ffff
+#define AR5K_SLEEP1_NEXT_TIM_S		0
+#define AR5K_SLEEP1_BEACON_TO		0xff000000
+#define AR5K_SLEEP1_BEACON_TO_S		24
+
+/*
+ * Third enhanced sleep register
+ */
+#define AR5K_SLEEP2			0x80dc
+#define AR5K_SLEEP2_TIM_PER		0x0000ffff
+#define AR5K_SLEEP2_TIM_PER_S		0
+#define AR5K_SLEEP2_DTIM_PER		0xffff0000
+#define AR5K_SLEEP2_DTIM_PER_S		16
+
+/*
+ * BSSID mask registers
+ */
+#define AR5K_BSS_IDM0			0x80e0
+#define AR5K_BSS_IDM1			0x80e4
+
+/*
+ * TX power control (TPC) register
+ */
+#define AR5K_TXPC			0x80e8
+#define AR5K_TXPC_ACK_M			0x0000003f
+#define AR5K_TXPC_ACK_S			0
+#define AR5K_TXPC_CTS_M			0x00003f00
+#define AR5K_TXPC_CTS_S			8
+#define AR5K_TXPC_CHIRP_M		0x003f0000
+#define AR5K_TXPC_CHIRP_S		22
+
+/*
+ * Profile count registers
+ */
+#define AR5K_PROFCNT_TX			0x80ec
+#define AR5K_PROFCNT_RX			0x80f0
+#define AR5K_PROFCNT_RXCLR		0x80f4
+#define AR5K_PROFCNT_CYCLE		0x80f8
+
+/*
+ * TSF parameter register
+ */
+#define AR5K_TSF_PARM			0x8104
+#define AR5K_TSF_PARM_INC_M		0x000000ff
+#define AR5K_TSF_PARM_INC_S		0
+
+/*
+ * PHY error filter register
+ */
+#define AR5K_PHY_ERR_FIL		0x810c
+#define AR5K_PHY_ERR_FIL_RADAR		0x00000020
+#define AR5K_PHY_ERR_FIL_OFDM		0x00020000
+#define AR5K_PHY_ERR_FIL_CCK		0x02000000
+
+/*
+ * Rate duration register
+ */
+#define AR5K_RATE_DUR_BASE		0x8700
+#define AR5K_RATE_DUR(_n)		(AR5K_RATE_DUR_BASE + ((_n) << 2))
+
+/*===5212 end===*/
+
+/*
+ * Key table (WEP) register
+ */
+#define AR5K_KEYTABLE_0_5210		0x9000
+#define AR5K_KEYTABLE_0_5211		0x8800
+#define AR5K_KEYTABLE_5210(_n)		(AR5K_KEYTABLE_0_5210 + ((_n) << 5))
+#define AR5K_KEYTABLE_5211(_n)		(AR5K_KEYTABLE_0_5211 + ((_n) << 5))
+#define	AR5K_KEYTABLE(_n)		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n))
+#define AR5K_KEYTABLE_OFF(_n, x)	(AR5K_KEYTABLE(_n) + (x << 2))
+#define AR5K_KEYTABLE_TYPE(_n)		AR5K_KEYTABLE_OFF(_n, 5)
+#define AR5K_KEYTABLE_TYPE_40		0x00000000
+#define AR5K_KEYTABLE_TYPE_104		0x00000001
+#define AR5K_KEYTABLE_TYPE_128		0x00000003
+#define AR5K_KEYTABLE_TYPE_TKIP		0x00000004	/* [5212+] */
+#define AR5K_KEYTABLE_TYPE_AES		0x00000005	/* [5211+] */
+#define AR5K_KEYTABLE_TYPE_CCM		0x00000006	/* [5212+] */
+#define AR5K_KEYTABLE_TYPE_NULL		0x00000007	/* [5211+] */
+#define AR5K_KEYTABLE_ANTENNA		0x00000008	/* [5212+] */
+#define AR5K_KEYTABLE_MAC0(_n)		AR5K_KEYTABLE_OFF(_n, 6)
+#define AR5K_KEYTABLE_MAC1(_n)		AR5K_KEYTABLE_OFF(_n, 7)
+#define AR5K_KEYTABLE_VALID		0x00008000
+
+/* WEP 40-bit	= 40-bit  entered key + 24 bit IV = 64-bit
+ * WEP 104-bit	= 104-bit entered key + 24-bit IV = 128-bit
+ * WEP 128-bit	= 128-bit entered key + 24 bit IV = 152-bit
+ *
+ * Some vendors have introduced bigger WEP keys to address
+ * security vulnerabilities in WEP. This includes:
+ *
+ * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit
+ *
+ * We can expand this if we find ar5k Atheros cards with a larger
+ * key table size.
+ */
+#define AR5K_KEYTABLE_SIZE_5210		64
+#define AR5K_KEYTABLE_SIZE_5211		128
+#define	AR5K_KEYTABLE_SIZE		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211)
+
+
+/*===PHY REGISTERS===*/
+
+/*
+ * PHY register
+ */
+#define	AR5K_PHY_BASE			0x9800
+#define	AR5K_PHY(_n)			(AR5K_PHY_BASE + ((_n) << 2))
+#define AR5K_PHY_SHIFT_2GHZ		0x00004007
+#define AR5K_PHY_SHIFT_5GHZ		0x00000007
+
+/*
+ * PHY frame control register [5110] /turbo mode register [5111+]
+ *
+ * There is another frame control register for [5111+]
+ * at address 0x9944 (see below) but the 2 first flags
+ * are common here between 5110 frame control register
+ * and [5111+] turbo mode register, so this also works as
+ * a "turbo mode register" for 5110. We treat this one as
+ * a frame control register for 5110 below.
+ */
+#define	AR5K_PHY_TURBO			0x9804
+#define	AR5K_PHY_TURBO_MODE		0x00000001
+#define	AR5K_PHY_TURBO_SHORT		0x00000002
+
+/*
+ * PHY agility command register
+ */
+#define	AR5K_PHY_AGC			0x9808
+#define	AR5K_PHY_AGC_DISABLE		0x08000000
+
+/*
+ * PHY timing register [5112+]
+ */
+#define	AR5K_PHY_TIMING_3		0x9814
+#define	AR5K_PHY_TIMING_3_DSC_MAN	0xfffe0000
+#define	AR5K_PHY_TIMING_3_DSC_MAN_S	17
+#define	AR5K_PHY_TIMING_3_DSC_EXP	0x0001e000
+#define	AR5K_PHY_TIMING_3_DSC_EXP_S	13
+
+/*
+ * PHY chip revision register
+ */
+#define	AR5K_PHY_CHIP_ID		0x9818
+
+/*
+ * PHY activation register
+ */
+#define	AR5K_PHY_ACT			0x981c
+#define	AR5K_PHY_ACT_ENABLE		0x00000001
+#define	AR5K_PHY_ACT_DISABLE		0x00000002
+
+/*
+ * PHY signal register
+ */
+#define	AR5K_PHY_SIG			0x9858
+#define	AR5K_PHY_SIG_FIRSTEP		0x0003f000
+#define	AR5K_PHY_SIG_FIRSTEP_S		12
+#define	AR5K_PHY_SIG_FIRPWR		0x03fc0000
+#define	AR5K_PHY_SIG_FIRPWR_S		18
+
+/*
+ * PHY coarse agility control register
+ */
+#define	AR5K_PHY_AGCCOARSE		0x985c
+#define	AR5K_PHY_AGCCOARSE_LO		0x00007f80
+#define	AR5K_PHY_AGCCOARSE_LO_S		7
+#define	AR5K_PHY_AGCCOARSE_HI		0x003f8000
+#define	AR5K_PHY_AGCCOARSE_HI_S		15
+
+/*
+ * PHY agility control register
+ */
+#define	AR5K_PHY_AGCCTL			0x9860			/* Register address */
+#define	AR5K_PHY_AGCCTL_CAL		0x00000001	/* Enable PHY calibration */
+#define	AR5K_PHY_AGCCTL_NF		0x00000002	/* Enable Noise Floor calibration */
+
+/*
+ * PHY noise floor status register
+ */
+#define AR5K_PHY_NF			0x9864
+#define AR5K_PHY_NF_M			0x000001ff
+#define AR5K_PHY_NF_ACTIVE		0x00000100
+#define AR5K_PHY_NF_RVAL(_n)		(((_n) >> 19) & AR5K_PHY_NF_M)
+#define AR5K_PHY_NF_AVAL(_n)		(-((_n) ^ AR5K_PHY_NF_M) + 1)
+#define AR5K_PHY_NF_SVAL(_n)		(((_n) & AR5K_PHY_NF_M) | (1 << 9))
+
+/*
+ * PHY ADC saturation register [5110]
+ */
+#define	AR5K_PHY_ADCSAT			0x9868
+#define	AR5K_PHY_ADCSAT_ICNT		0x0001f800
+#define	AR5K_PHY_ADCSAT_ICNT_S		11
+#define	AR5K_PHY_ADCSAT_THR		0x000007e0
+#define	AR5K_PHY_ADCSAT_THR_S		5
+
+/*
+ * PHY sleep registers [5112+]
+ */
+#define AR5K_PHY_SCR			0x9870
+#define AR5K_PHY_SCR_32MHZ		0x0000001f
+#define AR5K_PHY_SLMT			0x9874
+#define AR5K_PHY_SLMT_32MHZ		0x0000007f
+#define AR5K_PHY_SCAL			0x9878
+#define AR5K_PHY_SCAL_32MHZ		0x0000000e
+
+/*
+ * PHY PLL (Phase Locked Loop) control register
+ */
+#define	AR5K_PHY_PLL			0x987c
+#define	AR5K_PHY_PLL_20MHZ		0x13	/* For half rate (?) [5111+] */
+#define	AR5K_PHY_PLL_40MHZ_5211		0x18	/* For 802.11a */
+#define	AR5K_PHY_PLL_40MHZ_5212		0x000000aa
+#define	AR5K_PHY_PLL_40MHZ		(ah->ah_version == AR5K_AR5211 ? \
+					AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212)
+#define	AR5K_PHY_PLL_44MHZ_5211		0x19	/* For 802.11b/g */
+#define	AR5K_PHY_PLL_44MHZ_5212		0x000000ab
+#define	AR5K_PHY_PLL_44MHZ		(ah->ah_version == AR5K_AR5211 ? \
+					AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212)
+#define AR5K_PHY_PLL_RF5111		0x00000000
+#define AR5K_PHY_PLL_RF5112		0x00000040
+
+/*
+ * RF Buffer register
+ *
+ * There are some special control registers on the RF chip
+ * that hold various operation settings related mostly to
+ * the analog parts (channel, gain adjustment etc).
+ *
+ * We don't write on those registers directly but
+ * we send a data packet on the buffer register and
+ * then write on another special register to notify hw
+ * to apply the settings. This is done so that control registers
+ * can be dynamicaly programmed during operation and the settings
+ * are applied faster on the hw.
+ *
+ * We sent such data packets during rf initialization and channel change
+ * through ath5k_hw_rf*_rfregs and ath5k_hw_rf*_channel functions.
+ *
+ * The data packets we send during initializadion are inside ath5k_ini_rf
+ * struct (see ath5k_hw.h) and each one is related to an "rf register bank".
+ * We use *rfregs functions to modify them  acording to current operation
+ * mode and eeprom values and pass them all together to the chip.
+ *
+ * It's obvious from the code that 0x989c is the buffer register but
+ * for the other special registers that we write to after sending each
+ * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers
+ * for now. It's interesting that they are also used for some other operations.
+ *
+ * Also check out hw.h and U.S. Patent 6677779 B1 (about buffer
+ * registers and control registers):
+ *
+ * http://www.google.com/patents?id=qNURAAAAEBAJ
+ */
+
+#define AR5K_RF_BUFFER			0x989c
+#define AR5K_RF_BUFFER_CONTROL_0	0x98c0	/* Channel on 5110 */
+#define AR5K_RF_BUFFER_CONTROL_1	0x98c4	/* Bank 7 on 5112 */
+#define AR5K_RF_BUFFER_CONTROL_2	0x98cc	/* Bank 7 on 5111 */
+
+#define AR5K_RF_BUFFER_CONTROL_3	0x98d0	/* Bank 2 on 5112 */
+						/* Channel set on 5111 */
+						/* Used to read radio revision*/
+
+#define AR5K_RF_BUFFER_CONTROL_4	0x98d4  /* RF Stage register on 5110 */
+						/* Bank 0,1,2,6 on 5111 */
+						/* Bank 1 on 5112 */
+						/* Used during activation on 5111 */
+
+#define AR5K_RF_BUFFER_CONTROL_5	0x98d8	/* Bank 3 on 5111 */
+						/* Used during activation on 5111 */
+						/* Channel on 5112 */
+						/* Bank 6 on 5112 */
+
+#define AR5K_RF_BUFFER_CONTROL_6	0x98dc	/* Bank 3 on 5112 */
+
+/*
+ * PHY RF stage register [5210]
+ */
+#define AR5K_PHY_RFSTG			0x98d4
+#define AR5K_PHY_RFSTG_DISABLE		0x00000021
+
+/*
+ * PHY receiver delay register [5111+]
+ */
+#define	AR5K_PHY_RX_DELAY		0x9914
+#define	AR5K_PHY_RX_DELAY_M		0x00003fff
+
+/*
+ * PHY timing I(nphase) Q(adrature) control register [5111+]
+ */
+#define	AR5K_PHY_IQ			0x9920		/* Register address */
+#define	AR5K_PHY_IQ_CORR_Q_Q_COFF	0x0000001f	/* Mask for q correction info */
+#define	AR5K_PHY_IQ_CORR_Q_I_COFF	0x000007e0	/* Mask for i correction info */
+#define	AR5K_PHY_IQ_CORR_Q_I_COFF_S	5
+#define	AR5K_PHY_IQ_CORR_ENABLE		0x00000800	/* Enable i/q correction */
+#define	AR5K_PHY_IQ_CAL_NUM_LOG_MAX	0x0000f000
+#define	AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S	12
+#define	AR5K_PHY_IQ_RUN			0x00010000	/* Run i/q calibration */
+
+
+/*
+ * PHY PAPD probe register [5111+ (?)]
+ * Is this only present in 5212 ?
+ * Because it's always 0 in 5211 initialization code
+ */
+#define	AR5K_PHY_PAPD_PROBE		0x9930
+#define	AR5K_PHY_PAPD_PROBE_TXPOWER	0x00007e00
+#define	AR5K_PHY_PAPD_PROBE_TXPOWER_S	9
+#define	AR5K_PHY_PAPD_PROBE_TX_NEXT	0x00008000
+#define	AR5K_PHY_PAPD_PROBE_TYPE	0x01800000	/* [5112+] */
+#define	AR5K_PHY_PAPD_PROBE_TYPE_S	23
+#define	AR5K_PHY_PAPD_PROBE_TYPE_OFDM	0
+#define	AR5K_PHY_PAPD_PROBE_TYPE_XR	1
+#define	AR5K_PHY_PAPD_PROBE_TYPE_CCK	2
+#define	AR5K_PHY_PAPD_PROBE_GAINF	0xfe000000
+#define	AR5K_PHY_PAPD_PROBE_GAINF_S	25
+#define	AR5K_PHY_PAPD_PROBE_INI_5111	0x00004883	/* [5212+] */
+#define	AR5K_PHY_PAPD_PROBE_INI_5112	0x00004882	/* [5212+] */
+
+
+/*
+ * PHY TX rate power registers [5112+]
+ */
+#define	AR5K_PHY_TXPOWER_RATE1			0x9934
+#define	AR5K_PHY_TXPOWER_RATE2			0x9938
+#define	AR5K_PHY_TXPOWER_RATE_MAX		0x993c
+#define	AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE	0x00000040
+#define	AR5K_PHY_TXPOWER_RATE3			0xa234
+#define	AR5K_PHY_TXPOWER_RATE4			0xa238
+
+/*
+ * PHY frame control register [5111+]
+ */
+#define	AR5K_PHY_FRAME_CTL_5210		0x9804
+#define	AR5K_PHY_FRAME_CTL_5211		0x9944
+#define	AR5K_PHY_FRAME_CTL		(ah->ah_version == AR5K_AR5210 ? \
+					AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211)
+/*---[5111+]---*/
+#define	AR5K_PHY_FRAME_CTL_TX_CLIP	0x00000038
+#define	AR5K_PHY_FRAME_CTL_TX_CLIP_S	3
+/*---[5110/5111]---*/
+#define	AR5K_PHY_FRAME_CTL_TIMING_ERR	0x01000000
+#define	AR5K_PHY_FRAME_CTL_PARITY_ERR	0x02000000
+#define	AR5K_PHY_FRAME_CTL_ILLRATE_ERR	0x04000000	/* illegal rate */
+#define	AR5K_PHY_FRAME_CTL_ILLLEN_ERR	0x08000000	/* illegal length */
+#define	AR5K_PHY_FRAME_CTL_SERVICE_ERR	0x20000000
+#define	AR5K_PHY_FRAME_CTL_TXURN_ERR	0x40000000	/* tx underrun */
+#define AR5K_PHY_FRAME_CTL_INI		AR5K_PHY_FRAME_CTL_SERVICE_ERR | \
+			AR5K_PHY_FRAME_CTL_TXURN_ERR | \
+			AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \
+			AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \
+			AR5K_PHY_FRAME_CTL_PARITY_ERR | \
+			AR5K_PHY_FRAME_CTL_TIMING_ERR
+
+/*
+ * PHY radar detection register [5111+]
+ */
+#define	AR5K_PHY_RADAR			0x9954
+
+/* Radar enable 			........ ........ ........ .......1 */
+#define	AR5K_PHY_RADAR_ENABLE		0x00000001
+#define	AR5K_PHY_RADAR_DISABLE          0x00000000
+#define	AR5K_PHY_RADAR_ENABLE_S		0
+
+/* This is the value found on the card  .1.111.1 .1.1.... 111....1 1...1...
+at power on. */
+#define	AR5K_PHY_RADAR_PWONDEF_AR5213	0x5d50e188
+
+/* This is the value found on the card 	.1.1.111 ..11...1 .1...1.1 1...11.1
+after DFS is enabled */
+#define	AR5K_PHY_RADAR_ENABLED_AR5213	0x5731458d
+
+/* Finite Impulse Response (FIR) filter .1111111 ........ ........ ........
+ * power out threshold.
+ * 7-bits, standard power range {0..127} in 1/2 dBm units. */
+#define AR5K_PHY_RADAR_FIRPWROUTTHR    	0x7f000000
+#define AR5K_PHY_RADAR_FIRPWROUTTHR_S	24
+
+/* Radar RSSI/SNR threshold.		........ 111111.. ........ ........
+ * 6-bits, dBm range {0..63} in dBm units. */
+#define AR5K_PHY_RADAR_RADARRSSITHR    	0x00fc0000
+#define AR5K_PHY_RADAR_RADARRSSITHR_S	18
+
+/* Pulse height threshold 		........ ......11 1111.... ........
+ * 6-bits, dBm range {0..63} in dBm units. */
+#define AR5K_PHY_RADAR_PULSEHEIGHTTHR   0x0003f000
+#define AR5K_PHY_RADAR_PULSEHEIGHTTHR_S	12
+
+/* Pulse RSSI/SNR threshold		........ ........ ....1111 11......
+ * 6-bits, dBm range {0..63} in dBm units. */
+#define AR5K_PHY_RADAR_PULSERSSITHR    	0x00000fc0
+#define AR5K_PHY_RADAR_PULSERSSITHR_S	6
+
+/* Inband threshold  			........ ........ ........ ..11111.
+ * 5-bits, units unknown {0..31} (? MHz ?) */
+#define AR5K_PHY_RADAR_INBANDTHR    	0x0000003e
+#define AR5K_PHY_RADAR_INBANDTHR_S	1
+
+/*
+ * PHY antenna switch table registers [5110]
+ */
+#define AR5K_PHY_ANT_SWITCH_TABLE_0	0x9960
+#define AR5K_PHY_ANT_SWITCH_TABLE_1	0x9964
+
+/*
+ * PHY clock sleep registers [5112+]
+ */
+#define AR5K_PHY_SCLOCK			0x99f0
+#define AR5K_PHY_SCLOCK_32MHZ		0x0000000c
+#define AR5K_PHY_SDELAY			0x99f4
+#define AR5K_PHY_SDELAY_32MHZ		0x000000ff
+#define AR5K_PHY_SPENDING		0x99f8
+#define AR5K_PHY_SPENDING_RF5111	0x00000018
+#define AR5K_PHY_SPENDING_RF5112	0x00000014
+
+/*
+ * Misc PHY/radio registers [5110 - 5111]
+ */
+#define	AR5K_BB_GAIN_BASE		0x9b00 /* BaseBand Amplifier Gain table base address */
+#define AR5K_BB_GAIN(_n)		(AR5K_BB_GAIN_BASE + ((_n) << 2))
+#define	AR5K_RF_GAIN_BASE		0x9a00 /* RF Amplrifier Gain table base address */
+#define AR5K_RF_GAIN(_n)		(AR5K_RF_GAIN_BASE + ((_n) << 2))
+
+/*
+ * PHY timing IQ calibration result register [5111+]
+ */
+#define	AR5K_PHY_IQRES_CAL_PWR_I	0x9c10 /* I (Inphase) power value */
+#define	AR5K_PHY_IQRES_CAL_PWR_Q	0x9c14 /* Q (Quadrature) power value */
+#define	AR5K_PHY_IQRES_CAL_CORR		0x9c18	/* I/Q Correlation */
+
+/*
+ * PHY current RSSI register [5111+]
+ */
+#define	AR5K_PHY_CURRENT_RSSI		0x9c1c
+
+/*
+ * PHY PCDAC TX power table
+ */
+#define	AR5K_PHY_PCDAC_TXPOWER_BASE_5211	0xa180
+#define AR5K_PHY_PCDAC_TXPOWER_BASE_5413	0xa280
+#define AR5K_PHY_PCDAC_TXPOWER_BASE	(ah->ah_radio >= AR5K_RF5413 ? \
+					AR5K_PHY_PCDAC_TXPOWER_BASE_5413 :\
+					AR5K_PHY_PCDAC_TXPOWER_BASE_5211)
+#define	AR5K_PHY_PCDAC_TXPOWER(_n)	(AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2))
+
+/*
+ * PHY mode register [5111+]
+ */
+#define	AR5K_PHY_MODE			0x0a200		/* Register address */
+#define	AR5K_PHY_MODE_MOD		0x00000001	/* PHY Modulation mask*/
+#define AR5K_PHY_MODE_MOD_OFDM		0
+#define AR5K_PHY_MODE_MOD_CCK		1
+#define AR5K_PHY_MODE_FREQ		0x00000002	/* Freq mode mask */
+#define	AR5K_PHY_MODE_FREQ_5GHZ		0
+#define	AR5K_PHY_MODE_FREQ_2GHZ		2
+#define AR5K_PHY_MODE_MOD_DYN		0x00000004	/* Dynamic OFDM/CCK mode mask [5112+] */
+#define AR5K_PHY_MODE_RAD		0x00000008	/* [5212+] */
+#define AR5K_PHY_MODE_RAD_RF5111	0
+#define AR5K_PHY_MODE_RAD_RF5112	8
+#define AR5K_PHY_MODE_XR		0x00000010	/* [5112+] */
+
+/*
+ * PHY CCK transmit control register [5111+ (?)]
+ */
+#define AR5K_PHY_CCKTXCTL		0xa204
+#define AR5K_PHY_CCKTXCTL_WORLD		0x00000000
+#define AR5K_PHY_CCKTXCTL_JAPAN		0x00000010
+
+/*
+ * PHY 2GHz gain register [5111+]
+ */
+#define	AR5K_PHY_GAIN_2GHZ		0xa20c
+#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX	0x00fc0000
+#define	AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S	18
+#define	AR5K_PHY_GAIN_2GHZ_INI_5111	0x6480416c
diff --git a/drivers/net/wireless/ath5k/regdom.c b/drivers/net/wireless/ath5k/regdom.c
new file mode 100644
index 000000000000..e851957dacfd
--- /dev/null
+++ b/drivers/net/wireless/ath5k/regdom.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Basic regulation domain extensions for the IEEE 802.11 stack
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include "regdom.h"
+
+static const struct ath5k_regdommap {
+	enum ath5k_regdom dmn;
+	enum ath5k_regdom dmn5;
+	enum ath5k_regdom dmn2;
+} r_map[] = {
+	{ DMN_DEFAULT,		DMN_DEBUG,	DMN_DEBUG },
+	{ DMN_NULL_WORLD,	DMN_NULL,	DMN_WORLD },
+	{ DMN_NULL_ETSIB,	DMN_NULL,	DMN_ETSIB },
+	{ DMN_NULL_ETSIC,	DMN_NULL,	DMN_ETSIC },
+	{ DMN_FCC1_FCCA,	DMN_FCC1,	DMN_FCCA },
+	{ DMN_FCC1_WORLD,	DMN_FCC1,	DMN_WORLD },
+	{ DMN_FCC2_FCCA,	DMN_FCC2,	DMN_FCCA },
+	{ DMN_FCC2_WORLD,	DMN_FCC2,	DMN_WORLD },
+	{ DMN_FCC2_ETSIC,	DMN_FCC2,	DMN_ETSIC },
+	{ DMN_FRANCE_NULL,	DMN_ETSI3,	DMN_ETSI3 },
+	{ DMN_FCC3_FCCA,	DMN_FCC3,	DMN_WORLD },
+	{ DMN_ETSI1_WORLD,	DMN_ETSI1,	DMN_WORLD },
+	{ DMN_ETSI3_ETSIA,	DMN_ETSI3,	DMN_WORLD },
+	{ DMN_ETSI2_WORLD,	DMN_ETSI2,	DMN_WORLD },
+	{ DMN_ETSI3_WORLD,	DMN_ETSI3,	DMN_WORLD },
+	{ DMN_ETSI4_WORLD,	DMN_ETSI4,	DMN_WORLD },
+	{ DMN_ETSI4_ETSIC,	DMN_ETSI4,	DMN_ETSIC },
+	{ DMN_ETSI5_WORLD,	DMN_ETSI5,	DMN_WORLD },
+	{ DMN_ETSI6_WORLD,	DMN_ETSI6,	DMN_WORLD },
+	{ DMN_ETSI_NULL,	DMN_ETSI1,	DMN_ETSI1 },
+	{ DMN_MKK1_MKKA,	DMN_MKK1,	DMN_MKKA },
+	{ DMN_MKK1_MKKB,	DMN_MKK1,	DMN_MKKA },
+	{ DMN_APL4_WORLD,	DMN_APL4,	DMN_WORLD },
+	{ DMN_MKK2_MKKA,	DMN_MKK2,	DMN_MKKA },
+	{ DMN_APL_NULL,		DMN_APL1,	DMN_NULL },
+	{ DMN_APL2_WORLD,	DMN_APL2,	DMN_WORLD },
+	{ DMN_APL2_APLC,	DMN_APL2,	DMN_WORLD },
+	{ DMN_APL3_WORLD,	DMN_APL3,	DMN_WORLD },
+	{ DMN_MKK1_FCCA,	DMN_MKK1,	DMN_FCCA },
+	{ DMN_APL2_APLD,	DMN_APL2,	DMN_APLD },
+	{ DMN_MKK1_MKKA1,	DMN_MKK1,	DMN_MKKA },
+	{ DMN_MKK1_MKKA2,	DMN_MKK1,	DMN_MKKA },
+	{ DMN_APL1_WORLD,	DMN_APL1,	DMN_WORLD },
+	{ DMN_APL1_FCCA,	DMN_APL1,	DMN_FCCA },
+	{ DMN_APL1_APLA,	DMN_APL1,	DMN_WORLD },
+	{ DMN_APL1_ETSIC,	DMN_APL1,	DMN_ETSIC },
+	{ DMN_APL2_ETSIC,	DMN_APL2,	DMN_ETSIC },
+	{ DMN_APL5_WORLD,	DMN_APL5,	DMN_WORLD },
+	{ DMN_WOR0_WORLD,	DMN_WORLD,	DMN_WORLD },
+	{ DMN_WOR1_WORLD,	DMN_WORLD,	DMN_WORLD },
+	{ DMN_WOR2_WORLD,	DMN_WORLD,	DMN_WORLD },
+	{ DMN_WOR3_WORLD,	DMN_WORLD,	DMN_WORLD },
+	{ DMN_WOR4_WORLD,	DMN_WORLD,	DMN_WORLD },
+	{ DMN_WOR5_ETSIC,	DMN_WORLD,	DMN_WORLD },
+	{ DMN_WOR01_WORLD,	DMN_WORLD,	DMN_WORLD },
+	{ DMN_WOR02_WORLD,	DMN_WORLD,	DMN_WORLD },
+	{ DMN_EU1_WORLD,	DMN_ETSI1,	DMN_WORLD },
+	{ DMN_WOR9_WORLD,	DMN_WORLD,	DMN_WORLD },
+	{ DMN_WORA_WORLD,	DMN_WORLD,	DMN_WORLD },
+};
+
+enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom dmn, u16 mhz)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(r_map); i++) {
+		if (r_map[i].dmn == dmn) {
+			if (mhz >= 2000 && mhz <= 3000)
+				return r_map[i].dmn2;
+			if (mhz >= IEEE80211_CHANNELS_5GHZ_MIN &&
+					mhz <= IEEE80211_CHANNELS_5GHZ_MAX)
+				return r_map[i].dmn5;
+		}
+	}
+
+	return DMN_DEBUG;
+}
+
+u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee)
+{
+	u32 regdomain = (u32)ieee;
+
+	/*
+	 * Use the default regulation domain if the value is empty
+	 * or not supported by the net80211 regulation code.
+	 */
+	if (ath5k_regdom2flag(regdomain, IEEE80211_CHANNELS_5GHZ_MIN) ==
+			DMN_DEBUG)
+		return (u16)AR5K_TUNE_REGDOMAIN;
+
+	/* It is supported, just return the value */
+	return regdomain;
+}
+
+enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain)
+{
+	enum ath5k_regdom ieee = (enum ath5k_regdom)regdomain;
+
+	return ieee;
+}
+
diff --git a/drivers/net/wireless/ath5k/regdom.h b/drivers/net/wireless/ath5k/regdom.h
new file mode 100644
index 000000000000..f7d3c66e594e
--- /dev/null
+++ b/drivers/net/wireless/ath5k/regdom.h
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _IEEE80211_REGDOMAIN_H_
+#define _IEEE80211_REGDOMAIN_H_
+
+#include <linux/types.h>
+
+/* Default regulation domain if stored value EEPROM value is invalid */
+#define AR5K_TUNE_REGDOMAIN	DMN_FCC2_FCCA	/* Canada */
+#define AR5K_TUNE_CTRY		CTRY_DEFAULT
+
+
+enum ath5k_regdom {
+	DMN_DEFAULT		= 0x00,
+	DMN_NULL_WORLD		= 0x03,
+	DMN_NULL_ETSIB		= 0x07,
+	DMN_NULL_ETSIC		= 0x08,
+	DMN_FCC1_FCCA		= 0x10,
+	DMN_FCC1_WORLD		= 0x11,
+	DMN_FCC2_FCCA		= 0x20,
+	DMN_FCC2_WORLD		= 0x21,
+	DMN_FCC2_ETSIC		= 0x22,
+	DMN_FRANCE_NULL		= 0x31,
+	DMN_FCC3_FCCA		= 0x3A,
+	DMN_ETSI1_WORLD		= 0x37,
+	DMN_ETSI3_ETSIA		= 0x32,
+	DMN_ETSI2_WORLD		= 0x35,
+	DMN_ETSI3_WORLD		= 0x36,
+	DMN_ETSI4_WORLD		= 0x30,
+	DMN_ETSI4_ETSIC		= 0x38,
+	DMN_ETSI5_WORLD		= 0x39,
+	DMN_ETSI6_WORLD		= 0x34,
+	DMN_ETSI_NULL		= 0x33,
+	DMN_MKK1_MKKA		= 0x40,
+	DMN_MKK1_MKKB		= 0x41,
+	DMN_APL4_WORLD		= 0x42,
+	DMN_MKK2_MKKA		= 0x43,
+	DMN_APL_NULL		= 0x44,
+	DMN_APL2_WORLD		= 0x45,
+	DMN_APL2_APLC		= 0x46,
+	DMN_APL3_WORLD		= 0x47,
+	DMN_MKK1_FCCA		= 0x48,
+	DMN_APL2_APLD		= 0x49,
+	DMN_MKK1_MKKA1		= 0x4A,
+	DMN_MKK1_MKKA2		= 0x4B,
+	DMN_APL1_WORLD		= 0x52,
+	DMN_APL1_FCCA		= 0x53,
+	DMN_APL1_APLA		= 0x54,
+	DMN_APL1_ETSIC		= 0x55,
+	DMN_APL2_ETSIC		= 0x56,
+	DMN_APL5_WORLD		= 0x58,
+	DMN_WOR0_WORLD		= 0x60,
+	DMN_WOR1_WORLD		= 0x61,
+	DMN_WOR2_WORLD		= 0x62,
+	DMN_WOR3_WORLD		= 0x63,
+	DMN_WOR4_WORLD		= 0x64,
+	DMN_WOR5_ETSIC		= 0x65,
+	DMN_WOR01_WORLD		= 0x66,
+	DMN_WOR02_WORLD		= 0x67,
+	DMN_EU1_WORLD		= 0x68,
+	DMN_WOR9_WORLD		= 0x69,
+	DMN_WORA_WORLD		= 0x6A,
+
+	DMN_APL1		= 0xf0000001,
+	DMN_APL2		= 0xf0000002,
+	DMN_APL3		= 0xf0000004,
+	DMN_APL4		= 0xf0000008,
+	DMN_APL5		= 0xf0000010,
+	DMN_ETSI1		= 0xf0000020,
+	DMN_ETSI2		= 0xf0000040,
+	DMN_ETSI3		= 0xf0000080,
+	DMN_ETSI4		= 0xf0000100,
+	DMN_ETSI5		= 0xf0000200,
+	DMN_ETSI6		= 0xf0000400,
+	DMN_ETSIA		= 0xf0000800,
+	DMN_ETSIB		= 0xf0001000,
+	DMN_ETSIC		= 0xf0002000,
+	DMN_FCC1		= 0xf0004000,
+	DMN_FCC2		= 0xf0008000,
+	DMN_FCC3		= 0xf0010000,
+	DMN_FCCA		= 0xf0020000,
+	DMN_APLD		= 0xf0040000,
+	DMN_MKK1		= 0xf0080000,
+	DMN_MKK2		= 0xf0100000,
+	DMN_MKKA		= 0xf0200000,
+	DMN_NULL		= 0xf0400000,
+	DMN_WORLD		= 0xf0800000,
+	DMN_DEBUG               = 0xf1000000	/* used for debugging */
+};
+
+#define IEEE80211_DMN(_d)	((_d) & ~0xf0000000)
+
+enum ath5k_countrycode {
+	CTRY_DEFAULT            = 0,   /* Default domain (NA) */
+	CTRY_ALBANIA            = 8,   /* Albania */
+	CTRY_ALGERIA            = 12,  /* Algeria */
+	CTRY_ARGENTINA          = 32,  /* Argentina */
+	CTRY_ARMENIA            = 51,  /* Armenia */
+	CTRY_AUSTRALIA          = 36,  /* Australia */
+	CTRY_AUSTRIA            = 40,  /* Austria */
+	CTRY_AZERBAIJAN         = 31,  /* Azerbaijan */
+	CTRY_BAHRAIN            = 48,  /* Bahrain */
+	CTRY_BELARUS            = 112, /* Belarus */
+	CTRY_BELGIUM            = 56,  /* Belgium */
+	CTRY_BELIZE             = 84,  /* Belize */
+	CTRY_BOLIVIA            = 68,  /* Bolivia */
+	CTRY_BRAZIL             = 76,  /* Brazil */
+	CTRY_BRUNEI_DARUSSALAM  = 96,  /* Brunei Darussalam */
+	CTRY_BULGARIA           = 100, /* Bulgaria */
+	CTRY_CANADA             = 124, /* Canada */
+	CTRY_CHILE              = 152, /* Chile */
+	CTRY_CHINA              = 156, /* People's Republic of China */
+	CTRY_COLOMBIA           = 170, /* Colombia */
+	CTRY_COSTA_RICA         = 188, /* Costa Rica */
+	CTRY_CROATIA            = 191, /* Croatia */
+	CTRY_CYPRUS             = 196, /* Cyprus */
+	CTRY_CZECH              = 203, /* Czech Republic */
+	CTRY_DENMARK            = 208, /* Denmark */
+	CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */
+	CTRY_ECUADOR            = 218, /* Ecuador */
+	CTRY_EGYPT              = 818, /* Egypt */
+	CTRY_EL_SALVADOR        = 222, /* El Salvador */
+	CTRY_ESTONIA            = 233, /* Estonia */
+	CTRY_FAEROE_ISLANDS     = 234, /* Faeroe Islands */
+	CTRY_FINLAND            = 246, /* Finland */
+	CTRY_FRANCE             = 250, /* France */
+	CTRY_FRANCE2            = 255, /* France2 */
+	CTRY_GEORGIA            = 268, /* Georgia */
+	CTRY_GERMANY            = 276, /* Germany */
+	CTRY_GREECE             = 300, /* Greece */
+	CTRY_GUATEMALA          = 320, /* Guatemala */
+	CTRY_HONDURAS           = 340, /* Honduras */
+	CTRY_HONG_KONG          = 344, /* Hong Kong S.A.R., P.R.C. */
+	CTRY_HUNGARY            = 348, /* Hungary */
+	CTRY_ICELAND            = 352, /* Iceland */
+	CTRY_INDIA              = 356, /* India */
+	CTRY_INDONESIA          = 360, /* Indonesia */
+	CTRY_IRAN               = 364, /* Iran */
+	CTRY_IRAQ               = 368, /* Iraq */
+	CTRY_IRELAND            = 372, /* Ireland */
+	CTRY_ISRAEL             = 376, /* Israel */
+	CTRY_ITALY              = 380, /* Italy */
+	CTRY_JAMAICA            = 388, /* Jamaica */
+	CTRY_JAPAN              = 392, /* Japan */
+	CTRY_JAPAN1             = 393, /* Japan (JP1) */
+	CTRY_JAPAN2             = 394, /* Japan (JP0) */
+	CTRY_JAPAN3             = 395, /* Japan (JP1-1) */
+	CTRY_JAPAN4             = 396, /* Japan (JE1) */
+	CTRY_JAPAN5             = 397, /* Japan (JE2) */
+	CTRY_JORDAN             = 400, /* Jordan */
+	CTRY_KAZAKHSTAN         = 398, /* Kazakhstan */
+	CTRY_KENYA              = 404, /* Kenya */
+	CTRY_KOREA_NORTH        = 408, /* North Korea */
+	CTRY_KOREA_ROC          = 410, /* South Korea */
+	CTRY_KOREA_ROC2         = 411, /* South Korea */
+	CTRY_KUWAIT             = 414, /* Kuwait */
+	CTRY_LATVIA             = 428, /* Latvia */
+	CTRY_LEBANON            = 422, /* Lebanon */
+	CTRY_LIBYA              = 434, /* Libya */
+	CTRY_LIECHTENSTEIN      = 438, /* Liechtenstein */
+	CTRY_LITHUANIA          = 440, /* Lithuania */
+	CTRY_LUXEMBOURG         = 442, /* Luxembourg */
+	CTRY_MACAU              = 446, /* Macau */
+	CTRY_MACEDONIA          = 807, /* Republic of Macedonia */
+	CTRY_MALAYSIA           = 458, /* Malaysia */
+	CTRY_MEXICO             = 484, /* Mexico */
+	CTRY_MONACO             = 492, /* Principality of Monaco */
+	CTRY_MOROCCO            = 504, /* Morocco */
+	CTRY_NETHERLANDS        = 528, /* Netherlands */
+	CTRY_NEW_ZEALAND        = 554, /* New Zealand */
+	CTRY_NICARAGUA          = 558, /* Nicaragua */
+	CTRY_NORWAY             = 578, /* Norway */
+	CTRY_OMAN               = 512, /* Oman */
+	CTRY_PAKISTAN           = 586, /* Islamic Republic of Pakistan */
+	CTRY_PANAMA             = 591, /* Panama */
+	CTRY_PARAGUAY           = 600, /* Paraguay */
+	CTRY_PERU               = 604, /* Peru */
+	CTRY_PHILIPPINES        = 608, /* Republic of the Philippines */
+	CTRY_POLAND             = 616, /* Poland */
+	CTRY_PORTUGAL           = 620, /* Portugal */
+	CTRY_PUERTO_RICO        = 630, /* Puerto Rico */
+	CTRY_QATAR              = 634, /* Qatar */
+	CTRY_ROMANIA            = 642, /* Romania */
+	CTRY_RUSSIA             = 643, /* Russia */
+	CTRY_SAUDI_ARABIA       = 682, /* Saudi Arabia */
+	CTRY_SINGAPORE          = 702, /* Singapore */
+	CTRY_SLOVAKIA           = 703, /* Slovak Republic */
+	CTRY_SLOVENIA           = 705, /* Slovenia */
+	CTRY_SOUTH_AFRICA       = 710, /* South Africa */
+	CTRY_SPAIN              = 724, /* Spain */
+	CTRY_SRI_LANKA          = 728, /* Sri Lanka */
+	CTRY_SWEDEN             = 752, /* Sweden */
+	CTRY_SWITZERLAND        = 756, /* Switzerland */
+	CTRY_SYRIA              = 760, /* Syria */
+	CTRY_TAIWAN             = 158, /* Taiwan */
+	CTRY_THAILAND           = 764, /* Thailand */
+	CTRY_TRINIDAD_Y_TOBAGO  = 780, /* Trinidad y Tobago */
+	CTRY_TUNISIA            = 788, /* Tunisia */
+	CTRY_TURKEY             = 792, /* Turkey */
+	CTRY_UAE                = 784, /* U.A.E. */
+	CTRY_UKRAINE            = 804, /* Ukraine */
+	CTRY_UNITED_KINGDOM     = 826, /* United Kingdom */
+	CTRY_UNITED_STATES      = 840, /* United States */
+	CTRY_URUGUAY            = 858, /* Uruguay */
+	CTRY_UZBEKISTAN         = 860, /* Uzbekistan */
+	CTRY_VENEZUELA          = 862, /* Venezuela */
+	CTRY_VIET_NAM           = 704, /* Viet Nam */
+	CTRY_YEMEN              = 887, /* Yemen */
+	CTRY_ZIMBABWE           = 716, /* Zimbabwe */
+};
+
+#define IEEE80211_CHANNELS_2GHZ_MIN	2412	/* 2GHz channel 1 */
+#define IEEE80211_CHANNELS_2GHZ_MAX	2732	/* 2GHz channel 26 */
+#define IEEE80211_CHANNELS_5GHZ_MIN	5005	/* 5GHz channel 1 */
+#define IEEE80211_CHANNELS_5GHZ_MAX	6100	/* 5GHz channel 220 */
+
+struct ath5k_regchannel {
+	u16 chan;
+	enum ath5k_regdom domain;
+	u32 mode;
+};
+
+#define IEEE80211_CHANNELS_2GHZ {					\
+/*2412*/ {   1, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2417*/ {   2, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2422*/ {   3, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2427*/ {   4, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2432*/ {   5, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2437*/ {   6, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2442*/ {   7, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2447*/ {   8, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2452*/ {   9, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2457*/ {  10, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2462*/ {  11, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2467*/ {  12, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2472*/ {  13, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+									\
+/*2432*/ {   5, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2437*/ {   6, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*2442*/ {   7, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM },			\
+									\
+/*2412*/ {   1, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2417*/ {   2, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2422*/ {   3, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2427*/ {   4, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2432*/ {   5, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2437*/ {   6, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*2442*/ {   7, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2447*/ {   8, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2452*/ {   9, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2457*/ {  10, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2462*/ {  11, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2467*/ {  12, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2472*/ {  13, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM },			\
+									\
+/*2412*/ {   1, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2417*/ {   2, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2422*/ {   3, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2427*/ {   4, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2432*/ {   5, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2437*/ {   6, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*2442*/ {   7, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2447*/ {   8, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2452*/ {   9, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2457*/ {  10, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2462*/ {  11, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM },			\
+									\
+/*2412*/ {   1, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2417*/ {   2, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2422*/ {   3, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2427*/ {   4, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2432*/ {   5, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2437*/ {   6, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2442*/ {   7, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2447*/ {   8, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2452*/ {   9, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2457*/ {  10, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2462*/ {  11, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2467*/ {  12, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2472*/ {  13, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2484*/ {  14, DMN_MKKA, CHANNEL_CCK },				\
+									\
+/*2412*/ {   1, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2417*/ {   2, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2422*/ {   3, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2427*/ {   4, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2432*/ {   5, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2437*/ {   6, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*2442*/ {   7, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2447*/ {   8, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2452*/ {   9, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2457*/ {  10, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2462*/ {  11, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2467*/ {  12, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+/*2472*/ {  13, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM },			\
+}
+
+#define IEEE80211_CHANNELS_5GHZ {			\
+/*5745*/ { 149, DMN_APL1, CHANNEL_OFDM },		\
+/*5765*/ { 153, DMN_APL1, CHANNEL_OFDM },		\
+/*5785*/ { 157, DMN_APL1, CHANNEL_OFDM },		\
+/*5805*/ { 161, DMN_APL1, CHANNEL_OFDM },		\
+/*5825*/ { 165, DMN_APL1, CHANNEL_OFDM },		\
+							\
+/*5745*/ { 149, DMN_APL2, CHANNEL_OFDM },		\
+/*5765*/ { 153, DMN_APL2, CHANNEL_OFDM },		\
+/*5785*/ { 157, DMN_APL2, CHANNEL_OFDM },		\
+/*5805*/ { 161, DMN_APL2, CHANNEL_OFDM },		\
+							\
+/*5280*/ {  56, DMN_APL3, CHANNEL_OFDM },		\
+/*5300*/ {  60, DMN_APL3, CHANNEL_OFDM },		\
+/*5320*/ {  64, DMN_APL3, CHANNEL_OFDM },		\
+/*5745*/ { 149, DMN_APL3, CHANNEL_OFDM },		\
+/*5765*/ { 153, DMN_APL3, CHANNEL_OFDM },		\
+/*5785*/ { 157, DMN_APL3, CHANNEL_OFDM },		\
+/*5805*/ { 161, DMN_APL3, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_APL4, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_APL4, CHANNEL_OFDM },		\
+/*5220*/ {  44, DMN_APL4, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_APL4, CHANNEL_OFDM },		\
+/*5745*/ { 149, DMN_APL4, CHANNEL_OFDM },		\
+/*5765*/ { 153, DMN_APL4, CHANNEL_OFDM },		\
+/*5785*/ { 157, DMN_APL4, CHANNEL_OFDM },		\
+/*5805*/ { 161, DMN_APL4, CHANNEL_OFDM },		\
+/*5825*/ { 165, DMN_APL4, CHANNEL_OFDM },		\
+							\
+/*5745*/ { 149, DMN_APL5, CHANNEL_OFDM },		\
+/*5765*/ { 153, DMN_APL5, CHANNEL_OFDM },		\
+/*5785*/ { 157, DMN_APL5, CHANNEL_OFDM },		\
+/*5805*/ { 161, DMN_APL5, CHANNEL_OFDM },		\
+/*5825*/ { 165, DMN_APL5, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5220*/ {  44, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5260*/ {  52, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5280*/ {  56, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5300*/ {  60, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5320*/ {  64, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5500*/ { 100, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5520*/ { 104, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5540*/ { 108, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5560*/ { 112, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5580*/ { 116, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5600*/ { 120, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5620*/ { 124, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5640*/ { 128, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5660*/ { 132, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5680*/ { 136, DMN_ETSI1, CHANNEL_OFDM },		\
+/*5700*/ { 140, DMN_ETSI1, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_ETSI2, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_ETSI2, CHANNEL_OFDM },		\
+/*5220*/ {  44, DMN_ETSI2, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_ETSI2, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_ETSI3, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_ETSI3, CHANNEL_OFDM },		\
+/*5220*/ {  44, DMN_ETSI3, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_ETSI3, CHANNEL_OFDM },		\
+/*5260*/ {  52, DMN_ETSI3, CHANNEL_OFDM },		\
+/*5280*/ {  56, DMN_ETSI3, CHANNEL_OFDM },		\
+/*5300*/ {  60, DMN_ETSI3, CHANNEL_OFDM },		\
+/*5320*/ {  64, DMN_ETSI3, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_ETSI4, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_ETSI4, CHANNEL_OFDM },		\
+/*5220*/ {  44, DMN_ETSI4, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_ETSI4, CHANNEL_OFDM },		\
+/*5260*/ {  52, DMN_ETSI4, CHANNEL_OFDM },		\
+/*5280*/ {  56, DMN_ETSI4, CHANNEL_OFDM },		\
+/*5300*/ {  60, DMN_ETSI4, CHANNEL_OFDM },		\
+/*5320*/ {  64, DMN_ETSI4, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_ETSI5, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_ETSI5, CHANNEL_OFDM },		\
+/*5220*/ {  44, DMN_ETSI5, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_ETSI5, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5220*/ {  44, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5260*/ {  52, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5280*/ {  56, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5500*/ { 100, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5520*/ { 104, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5540*/ { 108, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5560*/ { 112, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5580*/ { 116, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5600*/ { 120, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5620*/ { 124, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5640*/ { 128, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5660*/ { 132, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5680*/ { 136, DMN_ETSI6, CHANNEL_OFDM },		\
+/*5700*/ { 140, DMN_ETSI6, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_FCC1, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_FCC1, CHANNEL_OFDM },		\
+/*5210*/ {  42, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*5220*/ {  44, DMN_FCC1, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_FCC1, CHANNEL_OFDM },		\
+/*5250*/ {  50, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*5260*/ {  52, DMN_FCC1, CHANNEL_OFDM },		\
+/*5280*/ {  56, DMN_FCC1, CHANNEL_OFDM },		\
+/*5290*/ {  58, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*5300*/ {  60, DMN_FCC1, CHANNEL_OFDM },		\
+/*5320*/ {  64, DMN_FCC1, CHANNEL_OFDM },		\
+/*5745*/ { 149, DMN_FCC1, CHANNEL_OFDM },		\
+/*5760*/ { 152, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*5765*/ { 153, DMN_FCC1, CHANNEL_OFDM },		\
+/*5785*/ { 157, DMN_FCC1, CHANNEL_OFDM },		\
+/*5800*/ { 160, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*5805*/ { 161, DMN_FCC1, CHANNEL_OFDM },		\
+/*5825*/ { 165, DMN_FCC1, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_FCC2, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_FCC2, CHANNEL_OFDM },		\
+/*5220*/ {  44, DMN_FCC2, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_FCC2, CHANNEL_OFDM },		\
+/*5260*/ {  52, DMN_FCC2, CHANNEL_OFDM },		\
+/*5280*/ {  56, DMN_FCC2, CHANNEL_OFDM },		\
+/*5300*/ {  60, DMN_FCC2, CHANNEL_OFDM },		\
+/*5320*/ {  64, DMN_FCC2, CHANNEL_OFDM },		\
+/*5745*/ { 149, DMN_FCC2, CHANNEL_OFDM },		\
+/*5765*/ { 153, DMN_FCC2, CHANNEL_OFDM },		\
+/*5785*/ { 157, DMN_FCC2, CHANNEL_OFDM },		\
+/*5805*/ { 161, DMN_FCC2, CHANNEL_OFDM },		\
+/*5825*/ { 165, DMN_FCC2, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_FCC3, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_FCC3, CHANNEL_OFDM },		\
+/*5210*/ {  42, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*5220*/ {  44, DMN_FCC3, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_FCC3, CHANNEL_OFDM },		\
+/*5250*/ {  50, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*5260*/ {  52, DMN_FCC3, CHANNEL_OFDM },		\
+/*5280*/ {  56, DMN_FCC3, CHANNEL_OFDM },		\
+/*5290*/ {  58, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*5300*/ {  60, DMN_FCC3, CHANNEL_OFDM },		\
+/*5320*/ {  64, DMN_FCC3, CHANNEL_OFDM },		\
+/*5500*/ { 100, DMN_FCC3, CHANNEL_OFDM },		\
+/*5520*/ { 104, DMN_FCC3, CHANNEL_OFDM },		\
+/*5540*/ { 108, DMN_FCC3, CHANNEL_OFDM },		\
+/*5560*/ { 112, DMN_FCC3, CHANNEL_OFDM },		\
+/*5580*/ { 116, DMN_FCC3, CHANNEL_OFDM },		\
+/*5600*/ { 120, DMN_FCC3, CHANNEL_OFDM },		\
+/*5620*/ { 124, DMN_FCC3, CHANNEL_OFDM },		\
+/*5640*/ { 128, DMN_FCC3, CHANNEL_OFDM },		\
+/*5660*/ { 132, DMN_FCC3, CHANNEL_OFDM },		\
+/*5680*/ { 136, DMN_FCC3, CHANNEL_OFDM },		\
+/*5700*/ { 140, DMN_FCC3, CHANNEL_OFDM },		\
+/*5745*/ { 149, DMN_FCC3, CHANNEL_OFDM },		\
+/*5760*/ { 152, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*5765*/ { 153, DMN_FCC3, CHANNEL_OFDM },		\
+/*5785*/ { 157, DMN_FCC3, CHANNEL_OFDM },		\
+/*5800*/ { 160, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO },	\
+/*5805*/ { 161, DMN_FCC3, CHANNEL_OFDM },		\
+/*5825*/ { 165, DMN_FCC3, CHANNEL_OFDM },		\
+							\
+/*5170*/ {  34, DMN_MKK1, CHANNEL_OFDM },		\
+/*5190*/ {  38, DMN_MKK1, CHANNEL_OFDM },		\
+/*5210*/ {  42, DMN_MKK1, CHANNEL_OFDM },		\
+/*5230*/ {  46, DMN_MKK1, CHANNEL_OFDM },		\
+							\
+/*5040*/ {   8, DMN_MKK2, CHANNEL_OFDM },		\
+/*5060*/ {  12, DMN_MKK2, CHANNEL_OFDM },		\
+/*5080*/ {  16, DMN_MKK2, CHANNEL_OFDM },		\
+/*5170*/ {  34, DMN_MKK2, CHANNEL_OFDM },		\
+/*5190*/ {  38, DMN_MKK2, CHANNEL_OFDM },		\
+/*5210*/ {  42, DMN_MKK2, CHANNEL_OFDM },		\
+/*5230*/ {  46, DMN_MKK2, CHANNEL_OFDM },		\
+							\
+/*5180*/ {  36, DMN_WORLD, CHANNEL_OFDM },		\
+/*5200*/ {  40, DMN_WORLD, CHANNEL_OFDM },		\
+/*5220*/ {  44, DMN_WORLD, CHANNEL_OFDM },		\
+/*5240*/ {  48, DMN_WORLD, CHANNEL_OFDM },		\
+}
+
+enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom, u16);
+u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee);
+enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain);
+
+#endif
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 059ce3f07dba..63ec7a70ee76 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -1759,9 +1759,8 @@ static int atmel_set_encode(struct net_device *dev,
 			priv->default_key = index;
 		} else
 			/* Don't complain if only change the mode */
-			if (!dwrq->flags & IW_ENCODE_MODE) {
+			if (!(dwrq->flags & IW_ENCODE_MODE))
 				return -EINVAL;
-			}
 	}
 	/* Read the flags */
 	if (dwrq->flags & IW_ENCODE_DISABLED) {
@@ -2676,9 +2675,9 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 }
 
 struct auth_body {
-	u16 alg;
-	u16 trans_seq;
-	u16 status;
+	__le16 alg;
+	__le16 trans_seq;
+	__le16 status;
 	u8 el_id;
 	u8 chall_text_len;
 	u8 chall_text[253];
@@ -2713,9 +2712,9 @@ static void atmel_scan(struct atmel_private *priv, int specific_ssid)
 		u8 SSID[MAX_SSID_LENGTH];
 		u8 scan_type;
 		u8 channel;
-		u16 BSS_type;
-		u16 min_channel_time;
-		u16 max_channel_time;
+		__le16 BSS_type;
+		__le16 min_channel_time;
+		__le16 max_channel_time;
 		u8 options;
 		u8 SSID_size;
 	} cmd;
@@ -2758,7 +2757,7 @@ static void join(struct atmel_private *priv, int type)
 		u8 SSID[MAX_SSID_LENGTH];
 		u8 BSS_type; /* this is a short in a scan command - weird */
 		u8 channel;
-		u16 timeout;
+		__le16 timeout;
 		u8 SSID_size;
 		u8 reserved;
 	} cmd;
@@ -2863,8 +2862,8 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc)
 	int bodysize;
 	struct ieee80211_hdr_4addr header;
 	struct ass_req_format {
-		u16 capability;
-		u16 listen_interval;
+		__le16 capability;
+		__le16 listen_interval;
 		u8 ap[6]; /* nothing after here directly accessible */
 		u8 ssid_el_id;
 		u8 ssid_len;
@@ -3085,9 +3084,9 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
 static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype)
 {
 	struct ass_resp_format {
-		u16 capability;
-		u16 status;
-		u16 ass_id;
+		__le16 capability;
+		__le16 status;
+		__le16 ass_id;
 		u8 el_id;
 		u8 length;
 		u8 rates[4];
@@ -3294,9 +3293,9 @@ static void atmel_management_frame(struct atmel_private *priv,
 		   never let an engineer loose with a data structure design. */
 		{
 			struct beacon_format {
-				u64 timestamp;
-				u16 interval;
-				u16 capability;
+				__le64 timestamp;
+				__le16 interval;
+				__le16 capability;
 				u8 ssid_el_id;
 				u8 ssid_length;
 				/* ssid here */
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index fdbc351ac333..1a2141dabdc7 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -61,6 +61,16 @@ config B43_PCMCIA
 
 	  If unsure, say N.
 
+config B43_NPHY
+	bool "Pre IEEE 802.11n support (BROKEN)"
+	depends on B43 && EXPERIMENTAL && BROKEN
+	---help---
+	  Support for the IEEE 802.11n draft.
+
+	  THIS IS BROKEN AND DOES NOT WORK YET.
+
+	  SAY N.
+
 # This config option automatically enables b43 LEDS support,
 # if it's possible.
 config B43_LEDS
@@ -83,51 +93,3 @@ config B43_DEBUG
 
 	  Say Y, if you want to find out why the driver does not
 	  work for you.
-
-config B43_DMA
-	bool
-	depends on B43
-config B43_PIO
-	bool
-	depends on B43
-
-choice
-	prompt "Broadcom 43xx data transfer mode"
-	depends on B43
-	default B43_DMA_AND_PIO_MODE
-
-config B43_DMA_AND_PIO_MODE
-	bool "DMA + PIO"
-	select B43_DMA
-	select B43_PIO
-	---help---
-	  Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
-	  data transfer modes.
-	  The actually used mode is selectable through the module
-	  parameter "pio". If the module parameter is pio=0, DMA is used.
-	  Otherwise PIO is used. DMA is default.
-
-	  If unsure, choose this option.
-
-config B43_DMA_MODE
-	bool "DMA (Direct Memory Access) only"
-	select B43_DMA
-	---help---
-	  Only include Direct Memory Access (DMA).
-	  This reduces the size of the driver module, by omitting the PIO code.
-
-config B43_PIO_MODE
-	bool "PIO (Programmed I/O) only"
-	select B43_PIO
-	---help---
-	  Only include Programmed I/O (PIO).
-	  This reduces the size of the driver module, by omitting the DMA code.
-	  Please note that PIO transfers are slow (compared to DMA).
-
-	  Also note that not all devices of the 43xx series support PIO.
-	  The 4306 (Apple Airport Extreme and others) supports PIO, while
-	  the 4318 is known to _not_ support PIO.
-
-	  Only use PIO, if DMA does not work for you.
-
-endchoice
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index 485e59e2dfab..ac1329dba045 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -1,20 +1,16 @@
-# b43 core
 b43-y				+= main.o
 b43-y				+= tables.o
+b43-y				+= tables_nphy.o
 b43-y				+= phy.o
+b43-y				+= nphy.o
 b43-y				+= sysfs.o
 b43-y				+= xmit.o
 b43-y				+= lo.o
-# b43 RFKILL button support
+b43-y				+= wa.o
+b43-y				+= dma.o
 b43-$(CONFIG_B43_RFKILL)	+= rfkill.o
-# b43 LED support
 b43-$(CONFIG_B43_LEDS)		+= leds.o
-# b43 PCMCIA support
 b43-$(CONFIG_B43_PCMCIA)	+= pcmcia.o
-# b43 debugging
 b43-$(CONFIG_B43_DEBUG)		+= debugfs.o
-# b43 DMA and PIO
-b43-$(CONFIG_B43_DMA)		+= dma.o
-b43-$(CONFIG_B43_PIO)		+= pio.o
 
 obj-$(CONFIG_B43)		+= b43.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 7b6fc1ab2b90..32a24f5c4fa6 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -35,8 +35,8 @@
 #define B43_MMIO_DMA4_IRQ_MASK		0x44
 #define B43_MMIO_DMA5_REASON		0x48
 #define B43_MMIO_DMA5_IRQ_MASK		0x4C
-#define B43_MMIO_MACCTL			0x120
-#define B43_MMIO_STATUS2_BITFIELD	0x124
+#define B43_MMIO_MACCTL			0x120	/* MAC control */
+#define B43_MMIO_MACCMD			0x124	/* MAC command */
 #define B43_MMIO_GEN_IRQ_REASON		0x128
 #define B43_MMIO_GEN_IRQ_MASK		0x12C
 #define B43_MMIO_RAM_CONTROL		0x130
@@ -50,6 +50,9 @@
 #define B43_MMIO_XMITSTAT_1		0x174
 #define B43_MMIO_REV3PLUS_TSF_LOW	0x180	/* core rev >= 3 only */
 #define B43_MMIO_REV3PLUS_TSF_HIGH	0x184	/* core rev >= 3 only */
+#define B43_MMIO_TSF_CFP_REP		0x188
+#define B43_MMIO_TSF_CFP_START		0x18C
+#define B43_MMIO_TSF_CFP_MAXDUR		0x190
 
 /* 32-bit DMA */
 #define B43_MMIO_DMA32_BASE0		0x200
@@ -65,11 +68,6 @@
 #define B43_MMIO_DMA64_BASE3		0x2C0
 #define B43_MMIO_DMA64_BASE4		0x300
 #define B43_MMIO_DMA64_BASE5		0x340
-/* PIO */
-#define B43_MMIO_PIO1_BASE		0x300
-#define B43_MMIO_PIO2_BASE		0x310
-#define B43_MMIO_PIO3_BASE		0x320
-#define B43_MMIO_PIO4_BASE		0x330
 
 #define B43_MMIO_PHY_VER		0x3E0
 #define B43_MMIO_PHY_RADIO		0x3E2
@@ -88,6 +86,8 @@
 #define B43_MMIO_RADIO_HWENABLED_LO	0x49A
 #define B43_MMIO_GPIO_CONTROL		0x49C
 #define B43_MMIO_GPIO_MASK		0x49E
+#define B43_MMIO_TSF_CFP_START_LOW	0x604
+#define B43_MMIO_TSF_CFP_START_HIGH	0x606
 #define B43_MMIO_TSF_0			0x632	/* core rev < 3 only */
 #define B43_MMIO_TSF_1			0x634	/* core rev < 3 only */
 #define B43_MMIO_TSF_2			0x636	/* core rev < 3 only */
@@ -170,14 +170,17 @@ enum {
 #define B43_SHM_SH_SLOTT		0x0010	/* Slot time */
 #define B43_SHM_SH_DTIMPER		0x0012	/* DTIM period */
 #define B43_SHM_SH_NOSLPZNATDTIM	0x004C	/* NOSLPZNAT DTIM */
-/* SHM_SHARED beacon variables */
+/* SHM_SHARED beacon/AP variables */
 #define B43_SHM_SH_BTL0			0x0018	/* Beacon template length 0 */
 #define B43_SHM_SH_BTL1			0x001A	/* Beacon template length 1 */
 #define B43_SHM_SH_BTSFOFF		0x001C	/* Beacon TSF offset */
 #define B43_SHM_SH_TIMBPOS		0x001E	/* TIM B position in beacon */
+#define B43_SHM_SH_DTIMP		0x0012	/* DTIP period */
+#define B43_SHM_SH_MCASTCOOKIE		0x00A8	/* Last bcast/mcast frame ID */
 #define B43_SHM_SH_SFFBLIM		0x0044	/* Short frame fallback retry limit */
 #define B43_SHM_SH_LFFBLIM		0x0046	/* Long frame fallback retry limit */
 #define B43_SHM_SH_BEACPHYCTL		0x0054	/* Beacon PHY TX control word (see PHY TX control) */
+#define B43_SHM_SH_EXTNPHYCTL		0x00B0	/* Extended bytes for beacon PHY control (N) */
 /* SHM_SHARED ACK/CTS control */
 #define B43_SHM_SH_ACKCTSPHYCTL		0x0022	/* ACK/CTS PHY control word (see PHY TX control) */
 /* SHM_SHARED probe response variables */
@@ -321,17 +324,29 @@ enum {
 #define B43_MACCTL_DISCPMQ		0x40000000	/* Discard Power Management Queue */
 #define B43_MACCTL_GMODE		0x80000000	/* G Mode */
 
-/* 802.11 core specific TM State Low flags */
+/* MAC Command bitfield */
+#define B43_MACCMD_BEACON0_VALID	0x00000001	/* Beacon 0 in template RAM is busy/valid */
+#define B43_MACCMD_BEACON1_VALID	0x00000002	/* Beacon 1 in template RAM is busy/valid */
+#define B43_MACCMD_DFQ_VALID		0x00000004	/* Directed frame queue valid (IBSS PS mode, ATIM) */
+#define B43_MACCMD_CCA			0x00000008	/* Clear channel assessment */
+#define B43_MACCMD_BGNOISE		0x00000010	/* Background noise */
+
+/* 802.11 core specific TM State Low (SSB_TMSLOW) flags */
 #define B43_TMSLOW_GMODE		0x20000000	/* G Mode Enable */
-#define B43_TMSLOW_PLLREFSEL		0x00200000	/* PLL Frequency Reference Select */
+#define B43_TMSLOW_PHYCLKSPEED		0x00C00000	/* PHY clock speed mask (N-PHY only) */
+#define  B43_TMSLOW_PHYCLKSPEED_40MHZ	0x00000000	/* 40 MHz PHY */
+#define  B43_TMSLOW_PHYCLKSPEED_80MHZ	0x00400000	/* 80 MHz PHY */
+#define  B43_TMSLOW_PHYCLKSPEED_160MHZ	0x00800000	/* 160 MHz PHY */
+#define B43_TMSLOW_PLLREFSEL		0x00200000	/* PLL Frequency Reference Select (rev >= 5) */
 #define B43_TMSLOW_MACPHYCLKEN		0x00100000	/* MAC PHY Clock Control Enable (rev >= 5) */
 #define B43_TMSLOW_PHYRESET		0x00080000	/* PHY Reset */
 #define B43_TMSLOW_PHYCLKEN		0x00040000	/* PHY Clock Enable */
 
-/* 802.11 core specific TM State High flags */
+/* 802.11 core specific TM State High (SSB_TMSHIGH) flags */
+#define B43_TMSHIGH_DUALBAND_PHY	0x00080000	/* Dualband PHY available */
 #define B43_TMSHIGH_FCLOCK		0x00040000	/* Fast Clock Available (rev >= 5) */
-#define B43_TMSHIGH_APHY		0x00020000	/* A-PHY available (rev >= 5) */
-#define B43_TMSHIGH_GPHY		0x00010000	/* G-PHY available (rev >= 5) */
+#define B43_TMSHIGH_HAVE_5GHZ_PHY	0x00020000	/* 5 GHz PHY available (rev >= 5) */
+#define B43_TMSHIGH_HAVE_2GHZ_PHY	0x00010000	/* 2.4 GHz PHY available (rev >= 5) */
 
 /* Generic-Interrupt reasons. */
 #define B43_IRQ_MAC_SUSPENDED		0x00000001
@@ -393,6 +408,8 @@ enum {
 #define B43_DEFAULT_SHORT_RETRY_LIMIT	7
 #define B43_DEFAULT_LONG_RETRY_LIMIT	4
 
+#define B43_PHY_TX_BADNESS_LIMIT	1000
+
 /* Max size of a security key */
 #define B43_SEC_KEYSIZE			16
 /* Security algorithms. */
@@ -462,7 +479,6 @@ struct b43_phy {
 	u16 radio_ver;		/* Radio version */
 	u8 radio_rev;		/* Radio revision */
 
-	bool locked;		/* Only used in b43_phy_{un}lock() */
 	bool dyn_tssi_tbl;	/* tssi2dbm is kmalloc()ed. */
 
 	/* ACI (adjacent channel interference) flags. */
@@ -499,11 +515,6 @@ struct b43_phy {
 	s16 lna_gain;		/* LNA */
 	s16 pga_gain;		/* PGA */
 
-	/* PHY lock for core.rev < 3
-	 * This lock is only used by b43_phy_{un}lock()
-	 */
-	spinlock_t lock;
-
 	/* Desired TX power level (in dBm).
 	 * This is set by the user and adjusted in b43_phy_xmitpower(). */
 	u8 power_level;
@@ -514,9 +525,7 @@ struct b43_phy {
 	struct b43_bbatt bbatt;
 	struct b43_rfatt rfatt;
 	u8 tx_control;		/* B43_TXCTL_XXX */
-#ifdef CONFIG_B43_DEBUG
-	bool manual_txpower_control;	/* Manual TX-power control enabled? */
-#endif
+
 	/* Hardware Power Control enabled? */
 	bool hardware_power_control;
 
@@ -544,6 +553,26 @@ struct b43_phy {
 	u16 lofcal;
 
 	u16 initval;		//FIXME rename?
+
+	/* PHY TX errors counter. */
+	atomic_t txerr_cnt;
+
+	/* The device does address auto increment for the OFDM tables.
+	 * We cache the previously used address here and omit the address
+	 * write on the next table access, if possible. */
+	u16 ofdmtab_addr; /* The address currently set in hardware. */
+	enum { /* The last data flow direction. */
+		B43_OFDMTAB_DIRECTION_UNKNOWN = 0,
+		B43_OFDMTAB_DIRECTION_READ,
+		B43_OFDMTAB_DIRECTION_WRITE,
+	} ofdmtab_addr_direction;
+
+#if B43_DEBUG
+	/* Manual TX-power control enabled? */
+	bool manual_txpower_control;
+	/* PHY registers locked by b43_phy_lock()? */
+	bool phy_locked;
+#endif /* B43_DEBUG */
 };
 
 /* Data structures for DMA transmission, per 80211 core. */
@@ -559,14 +588,6 @@ struct b43_dma {
 	struct b43_dmaring *rx_ring3;	/* only available on core.rev < 5 */
 };
 
-/* Data structures for PIO transmission, per 80211 core. */
-struct b43_pio {
-	struct b43_pioqueue *queue0;
-	struct b43_pioqueue *queue1;
-	struct b43_pioqueue *queue2;
-	struct b43_pioqueue *queue3;
-};
-
 /* Context information for a noise calculation (Link Quality). */
 struct b43_noise_calculation {
 	u8 channel_at_start;
@@ -599,18 +620,18 @@ struct b43_wl {
 	/* Pointer to the ieee80211 hardware data structure */
 	struct ieee80211_hw *hw;
 
-	spinlock_t irq_lock;
 	struct mutex mutex;
+	spinlock_t irq_lock;
+	/* Lock for LEDs access. */
 	spinlock_t leds_lock;
+	/* Lock for SHM access. */
+	spinlock_t shm_lock;
 
 	/* We can only have one operating interface (802.11 core)
 	 * at a time. General information about this interface follows.
 	 */
 
-	/* Opaque ID of the operating interface from the ieee80211
-	 * subsystem. Do not modify.
-	 */
-	int if_id;
+	struct ieee80211_vif *vif;
 	/* The MAC address of the operating interface. */
 	u8 mac_addr[ETH_ALEN];
 	/* Current BSSID */
@@ -634,18 +655,33 @@ struct b43_wl {
 	/* List of all wireless devices on this chip */
 	struct list_head devlist;
 	u8 nr_devs;
+
+	bool radiotap_enabled;
+
+	/* The beacon we are currently using (AP or IBSS mode).
+	 * This beacon stuff is protected by the irq_lock. */
+	struct sk_buff *current_beacon;
+	bool beacon0_uploaded;
+	bool beacon1_uploaded;
+};
+
+/* In-memory representation of a cached microcode file. */
+struct b43_firmware_file {
+	const char *filename;
+	const struct firmware *data;
 };
 
 /* Pointers to the firmware data and meta information about it. */
 struct b43_firmware {
 	/* Microcode */
-	const struct firmware *ucode;
+	struct b43_firmware_file ucode;
 	/* PCM code */
-	const struct firmware *pcm;
+	struct b43_firmware_file pcm;
 	/* Initial MMIO values for the firmware */
-	const struct firmware *initvals;
+	struct b43_firmware_file initvals;
 	/* Initial MMIO values for the firmware, band-specific */
-	const struct firmware *initvals_band;
+	struct b43_firmware_file initvals_band;
+
 	/* Firmware revision */
 	u16 rev;
 	/* Firmware patchlevel */
@@ -683,21 +719,17 @@ struct b43_wldev {
 	/* Saved init status for handling suspend. */
 	int suspend_init_status;
 
-	bool __using_pio;	/* Internal, use b43_using_pio(). */
 	bool bad_frames_preempt;	/* Use "Bad Frames Preemption" (default off) */
-	bool reg124_set_0x4;	/* Some variable to keep track of IRQ stuff. */
+	bool dfq_valid;		/* Directed frame queue valid (IBSS PS mode, ATIM) */
 	bool short_preamble;	/* TRUE, if short preamble is enabled. */
 	bool short_slot;	/* TRUE, if short slot timing is enabled. */
 	bool radio_hw_enable;	/* saved state of radio hardware enabled state */
 
 	/* PHY/Radio device. */
 	struct b43_phy phy;
-	union {
-		/* DMA engines. */
-		struct b43_dma dma;
-		/* PIO engines. */
-		struct b43_pio pio;
-	};
+
+	/* DMA engines. */
+	struct b43_dma dma;
 
 	/* Various statistics about the physical device. */
 	struct b43_stats stats;
@@ -732,9 +764,6 @@ struct b43_wldev {
 	u8 max_nr_keys;
 	struct b43_key key[58];
 
-	/* Cached beacon template while uploading the template. */
-	struct sk_buff *cached_beacon;
-
 	/* Firmware data */
 	struct b43_firmware fw;
 
@@ -752,28 +781,6 @@ static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
 	return hw->priv;
 }
 
-/* Helper function, which returns a boolean.
- * TRUE, if PIO is used; FALSE, if DMA is used.
- */
-#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
-static inline int b43_using_pio(struct b43_wldev *dev)
-{
-	return dev->__using_pio;
-}
-#elif defined(CONFIG_B43_DMA)
-static inline int b43_using_pio(struct b43_wldev *dev)
-{
-	return 0;
-}
-#elif defined(CONFIG_B43_PIO)
-static inline int b43_using_pio(struct b43_wldev *dev)
-{
-	return 1;
-}
-#else
-# error "Using neither DMA nor PIO? Confused..."
-#endif
-
 static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
 {
 	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
index ef0075d9f9cb..e38ed0fe72e9 100644
--- a/drivers/net/wireless/b43/debugfs.c
+++ b/drivers/net/wireless/b43/debugfs.c
@@ -34,7 +34,6 @@
 #include "main.h"
 #include "debugfs.h"
 #include "dma.h"
-#include "pio.h"
 #include "xmit.h"
 
 
@@ -223,8 +222,6 @@ out:
 static int txpower_g_write_file(struct b43_wldev *dev,
 				const char *buf, size_t count)
 {
-	unsigned long phy_flags;
-
 	if (dev->phy.type != B43_PHYTYPE_G)
 		return -ENODEV;
 	if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
@@ -248,12 +245,12 @@ static int txpower_g_write_file(struct b43_wldev *dev,
 			dev->phy.tx_control |= B43_TXCTL_PA2DB;
 		if (pa3db)
 			dev->phy.tx_control |= B43_TXCTL_PA3DB;
-		b43_phy_lock(dev, phy_flags);
+		b43_phy_lock(dev);
 		b43_radio_lock(dev);
 		b43_set_txpower_g(dev, &dev->phy.bbatt,
 				  &dev->phy.rfatt, dev->phy.tx_control);
 		b43_radio_unlock(dev);
-		b43_phy_unlock(dev, phy_flags);
+		b43_phy_unlock(dev);
 	}
 
 	return 0;
@@ -352,7 +349,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
 	struct b43_wldev *dev;
 	struct b43_debugfs_fops *dfops;
 	struct b43_dfs_file *dfile;
-	ssize_t ret;
+	ssize_t uninitialized_var(ret);
 	char *buf;
 	const size_t bufsize = 1024 * 128;
 	const size_t buforder = get_order(bufsize);
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 5e8f8ac0f1dd..3e73d2a523aa 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -37,6 +37,8 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+
 
 /* 32bit DMA ops. */
 static
@@ -165,7 +167,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
 	addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
 	addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
 	    >> SSB_DMA_TRANSLATION_SHIFT;
-	addrhi |= ssb_dma_translation(ring->dev->dev);
+	addrhi |= (ssb_dma_translation(ring->dev->dev) << 1);
 	if (slot == ring->nr_slots - 1)
 		ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
 	if (start)
@@ -315,26 +317,24 @@ static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
 	case 3:
 		ring = dev->dma.tx_ring0;
 		break;
-	case 4:
-		ring = dev->dma.tx_ring4;
-		break;
-	case 5:
-		ring = dev->dma.tx_ring5;
-		break;
 	}
 
 	return ring;
 }
 
-/* Bcm43xx-ring to mac80211-queue mapping */
+/* b43-ring to mac80211-queue mapping */
 static inline int txring_to_priority(struct b43_dmaring *ring)
 {
-	static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, };
+	static const u8 idx_to_prio[] = { 3, 2, 1, 0, };
+	unsigned int index;
 
 /*FIXME: have only one queue, for now */
 	return 0;
 
-	return idx_to_prio[ring->index];
+	index = ring->index;
+	if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio)))
+		index = 0;
+	return idx_to_prio[index];
 }
 
 u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
@@ -426,9 +426,21 @@ static inline
 static int alloc_ringmemory(struct b43_dmaring *ring)
 {
 	struct device *dev = ring->dev->dev->dev;
-
+	gfp_t flags = GFP_KERNEL;
+
+	/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
+	 * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing
+	 * has shown that 4K is sufficient for the latter as long as the buffer
+	 * does not cross an 8K boundary.
+	 *
+	 * For unknown reasons - possibly a hardware error - the BCM4311 rev
+	 * 02, which uses 64-bit DMA, needs the ring buffer in very low memory,
+	 * which accounts for the GFP_DMA flag below.
+	 */
+	if (ring->dma64)
+		flags |= GFP_DMA;
 	ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
-					    &(ring->dmabase), GFP_KERNEL);
+					    &(ring->dmabase), flags);
 	if (!ring->descbase) {
 		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
 		return -ENOMEM;
@@ -483,7 +495,7 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 	return 0;
 }
 
-/* Reset the RX DMA channel */
+/* Reset the TX DMA channel */
 int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
 {
 	int i;
@@ -647,7 +659,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			b43_dma_write(ring, B43_DMA64_TXRINGHI,
 				      ((ringbase >> 32) &
 				       ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
+				      | (trans << 1));
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
 
@@ -680,8 +692,9 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			b43_dma_write(ring, B43_DMA64_RXRINGHI,
 				      ((ringbase >> 32) &
 				       ~SSB_DMA_TRANSLATION_MASK)
-				      | trans);
-			b43_dma_write(ring, B43_DMA64_RXINDEX, 200);
+				      | (trans << 1));
+			b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots *
+				      sizeof(struct b43_dmadesc64));
 		} else {
 			u32 ringbase = (u32) (ring->dmabase);
 
@@ -695,11 +708,12 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			b43_dma_write(ring, B43_DMA32_RXRING,
 				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
 				      | trans);
-			b43_dma_write(ring, B43_DMA32_RXINDEX, 200);
+			b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots *
+				      sizeof(struct b43_dmadesc32));
 		}
 	}
 
-      out:
+out:
 	return err;
 }
 
@@ -793,7 +807,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 		goto err_kfree_ring;
 	if (for_tx) {
 		ring->txhdr_cache = kcalloc(nr_slots,
-					    sizeof(struct b43_txhdr_fw4),
+					    b43_txhdr_size(dev),
 					    GFP_KERNEL);
 		if (!ring->txhdr_cache)
 			goto err_kfree_meta;
@@ -801,22 +815,21 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 		/* test for ability to dma to txhdr_cache */
 		dma_test = dma_map_single(dev->dev->dev,
 					  ring->txhdr_cache,
-					  sizeof(struct b43_txhdr_fw4),
+					  b43_txhdr_size(dev),
 					  DMA_TO_DEVICE);
 
 		if (dma_mapping_error(dma_test)) {
 			/* ugh realloc */
 			kfree(ring->txhdr_cache);
 			ring->txhdr_cache = kcalloc(nr_slots,
-						    sizeof(struct
-							   b43_txhdr_fw4),
+						    b43_txhdr_size(dev),
 						    GFP_KERNEL | GFP_DMA);
 			if (!ring->txhdr_cache)
 				goto err_kfree_meta;
 
 			dma_test = dma_map_single(dev->dev->dev,
 						  ring->txhdr_cache,
-						  sizeof(struct b43_txhdr_fw4),
+						  b43_txhdr_size(dev),
 						  DMA_TO_DEVICE);
 
 			if (dma_mapping_error(dma_test))
@@ -824,7 +837,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 		}
 
 		dma_unmap_single(dev->dev->dev,
-				 dma_test, sizeof(struct b43_txhdr_fw4),
+				 dma_test, b43_txhdr_size(dev),
 				 DMA_TO_DEVICE);
 	}
 
@@ -901,11 +914,7 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring)
 
 void b43_dma_free(struct b43_wldev *dev)
 {
-	struct b43_dma *dma;
-
-	if (b43_using_pio(dev))
-		return;
-	dma = &dev->dma;
+	struct b43_dma *dma = &dev->dma;
 
 	b43_destroy_dmaring(dma->rx_ring3);
 	dma->rx_ring3 = NULL;
@@ -940,16 +949,11 @@ int b43_dma_init(struct b43_wldev *dev)
 
 	err = ssb_dma_set_mask(dev->dev, dmamask);
 	if (err) {
-#ifdef B43_PIO
-		b43warn(dev->wl, "DMA for this device not supported. "
-			"Falling back to PIO\n");
-		dev->__using_pio = 1;
-		return -EAGAIN;
-#else
-		b43err(dev->wl, "DMA for this device not supported and "
-		       "no PIO support compiled in\n");
+		b43err(dev->wl, "The machine/kernel does not support "
+		       "the required DMA mask (0x%08X%08X)\n",
+		       (unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32),
+		       (unsigned int)(dmamask & 0x00000000FFFFFFFFULL));
 		return -EOPNOTSUPP;
-#endif
 	}
 
 	err = -ENOMEM;
@@ -1038,26 +1042,30 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot)
 	 * in the lower 12 bits.
 	 * Note that the cookie must never be 0, as this
 	 * is a special value used in RX path.
+	 * It can also not be 0xFFFF because that is special
+	 * for multicast frames.
 	 */
 	switch (ring->index) {
 	case 0:
-		cookie = 0xA000;
+		cookie = 0x1000;
 		break;
 	case 1:
-		cookie = 0xB000;
+		cookie = 0x2000;
 		break;
 	case 2:
-		cookie = 0xC000;
+		cookie = 0x3000;
 		break;
 	case 3:
-		cookie = 0xD000;
+		cookie = 0x4000;
 		break;
 	case 4:
-		cookie = 0xE000;
+		cookie = 0x5000;
 		break;
 	case 5:
-		cookie = 0xF000;
+		cookie = 0x6000;
 		break;
+	default:
+		B43_WARN_ON(1);
 	}
 	B43_WARN_ON(slot & ~0x0FFF);
 	cookie |= (u16) slot;
@@ -1073,22 +1081,22 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
 	struct b43_dmaring *ring = NULL;
 
 	switch (cookie & 0xF000) {
-	case 0xA000:
+	case 0x1000:
 		ring = dma->tx_ring0;
 		break;
-	case 0xB000:
+	case 0x2000:
 		ring = dma->tx_ring1;
 		break;
-	case 0xC000:
+	case 0x3000:
 		ring = dma->tx_ring2;
 		break;
-	case 0xD000:
+	case 0x4000:
 		ring = dma->tx_ring3;
 		break;
-	case 0xE000:
+	case 0x5000:
 		ring = dma->tx_ring4;
 		break;
-	case 0xF000:
+	case 0x6000:
 		ring = dma->tx_ring5;
 		break;
 	default:
@@ -1112,6 +1120,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 	struct b43_dmadesc_meta *meta;
 	struct b43_dmadesc_meta *meta_hdr;
 	struct sk_buff *bounce_skb;
+	u16 cookie;
+	size_t hdrsize = b43_txhdr_size(ring->dev);
 
 #define SLOTS_PER_PACKET  2
 	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
@@ -1121,17 +1131,17 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 	desc = ops->idx2desc(ring, slot, &meta_hdr);
 	memset(meta_hdr, 0, sizeof(*meta_hdr));
 
-	header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]);
+	header = &(ring->txhdr_cache[slot * hdrsize]);
+	cookie = generate_cookie(ring, slot);
 	b43_generate_txhdr(ring->dev, header,
-			   skb->data, skb->len, ctl,
-			   generate_cookie(ring, slot));
+			   skb->data, skb->len, ctl, cookie);
 
 	meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
-					   sizeof(struct b43_txhdr_fw4), 1);
+					   hdrsize, 1);
 	if (dma_mapping_error(meta_hdr->dmaaddr))
 		return -EIO;
 	ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
-			     sizeof(struct b43_txhdr_fw4), 1, 0, 0);
+			     hdrsize, 1, 0, 0);
 
 	/* Get a slot for the payload. */
 	slot = request_slot(ring);
@@ -1164,16 +1174,22 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 
 	ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
 
+	if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+		/* Tell the firmware about the cookie of the last
+		 * mcast frame, so it can clear the more-data bit in it. */
+		b43_shm_write16(ring->dev, B43_SHM_SHARED,
+				B43_SHM_SH_MCASTCOOKIE, cookie);
+	}
 	/* Now transfer the whole frame. */
 	wmb();
 	ops->poke_tx(ring, next_slot(ring, slot));
 	return 0;
 
-      out_free_bounce:
+out_free_bounce:
 	dev_kfree_skb_any(skb);
-      out_unmap_hdr:
+out_unmap_hdr:
 	unmap_descbuffer(ring, meta_hdr->dmaaddr,
-			 sizeof(struct b43_txhdr_fw4), 1);
+			 hdrsize, 1);
 	return err;
 }
 
@@ -1202,10 +1218,27 @@ int b43_dma_tx(struct b43_wldev *dev,
 	       struct sk_buff *skb, struct ieee80211_tx_control *ctl)
 {
 	struct b43_dmaring *ring;
+	struct ieee80211_hdr *hdr;
 	int err = 0;
 	unsigned long flags;
 
-	ring = priority_to_txring(dev, ctl->queue);
+	if (unlikely(skb->len < 2 + 2 + 6)) {
+		/* Too short, this can't be a valid frame. */
+		return -EINVAL;
+	}
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+	if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) {
+		/* The multicast ring will be sent after the DTIM */
+		ring = dev->dma.tx_ring4;
+		/* Set the more-data bit. Ucode will clear it on
+		 * the last frame for us. */
+		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+	} else {
+		/* Decide by priority where to put this frame. */
+		ring = priority_to_txring(dev, ctl->queue);
+	}
+
 	spin_lock_irqsave(&ring->lock, flags);
 	B43_WARN_ON(!ring->tx);
 	if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
@@ -1233,7 +1266,7 @@ int b43_dma_tx(struct b43_wldev *dev,
 			b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
 		}
 	}
-      out_unlock:
+out_unlock:
 	spin_unlock_irqrestore(&ring->lock, flags);
 
 	return err;
@@ -1265,7 +1298,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
 					 1);
 		else
 			unmap_descbuffer(ring, meta->dmaaddr,
-					 sizeof(struct b43_txhdr_fw4), 1);
+					 b43_txhdr_size(dev), 1);
 
 		if (meta->is_last_fragment) {
 			B43_WARN_ON(!meta->skb);
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index 3eed185be725..58db03ac536e 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -170,8 +170,6 @@ struct b43_dmadesc_generic {
 #define B43_DMA0_RX_BUFFERSIZE	(2304 + 100)
 #define B43_DMA3_RX_BUFFERSIZE	16
 
-#ifdef CONFIG_B43_DMA
-
 struct sk_buff;
 struct b43_private;
 struct b43_txstatus;
@@ -286,52 +284,4 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
 
 void b43_dma_rx(struct b43_dmaring *ring);
 
-#else /* CONFIG_B43_DMA */
-
-static inline int b43_dma_init(struct b43_wldev *dev)
-{
-	return 0;
-}
-static inline void b43_dma_free(struct b43_wldev *dev)
-{
-}
-static inline
-    int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
-				   u16 dmacontroller_mmio_base, int dma64)
-{
-	return 0;
-}
-static inline
-    int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
-				   u16 dmacontroller_mmio_base, int dma64)
-{
-	return 0;
-}
-static inline
-    void b43_dma_get_tx_stats(struct b43_wldev *dev,
-			      struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline
-    int b43_dma_tx(struct b43_wldev *dev,
-		   struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-	return 0;
-}
-static inline
-    void b43_dma_handle_txstatus(struct b43_wldev *dev,
-				 const struct b43_txstatus *status)
-{
-}
-static inline void b43_dma_rx(struct b43_dmaring *ring)
-{
-}
-static inline void b43_dma_tx_suspend(struct b43_wldev *dev)
-{
-}
-static inline void b43_dma_tx_resume(struct b43_wldev *dev)
-{
-}
-
-#endif /* CONFIG_B43_DMA */
 #endif /* B43_DMA_H_ */
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
index 6c0e2b9f7760..4b590d8c65ff 100644
--- a/drivers/net/wireless/b43/leds.c
+++ b/drivers/net/wireless/b43/leds.c
@@ -4,7 +4,7 @@
   LED control
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -190,10 +190,10 @@ void b43_leds_init(struct b43_wldev *dev)
 	enum b43_led_behaviour behaviour;
 	bool activelow;
 
-	sprom[0] = bus->sprom.r1.gpio0;
-	sprom[1] = bus->sprom.r1.gpio1;
-	sprom[2] = bus->sprom.r1.gpio2;
-	sprom[3] = bus->sprom.r1.gpio3;
+	sprom[0] = bus->sprom.gpio0;
+	sprom[1] = bus->sprom.gpio1;
+	sprom[2] = bus->sprom.gpio2;
+	sprom[3] = bus->sprom.gpio3;
 
 	for (i = 0; i < 4; i++) {
 		if (sprom[i] == 0xFF) {
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
index b14a1753a0d7..d890f366a23b 100644
--- a/drivers/net/wireless/b43/lo.c
+++ b/drivers/net/wireless/b43/lo.c
@@ -5,7 +5,7 @@
   G PHY LO (LocalOscillator) Measuring and Control routines
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005, 2006 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -264,8 +264,8 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev,
 		rfover |= pga;
 		rfover |= lna;
 		rfover |= trsw_rx;
-		if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) &&
-		    phy->rev > 6)
+		if ((dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
+		    && phy->rev > 6)
 			rfover |= B43_PHY_RFOVERVAL_EXTLNA;
 
 		b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
@@ -555,20 +555,20 @@ struct lo_g_saved_values {
 	u16 phy_extg_01;
 	u16 phy_dacctl_hwpctl;
 	u16 phy_dacctl;
-	u16 phy_base_14;
+	u16 phy_cck_14;
 	u16 phy_hpwr_tssictl;
 	u16 phy_analogover;
 	u16 phy_analogoverval;
 	u16 phy_rfover;
 	u16 phy_rfoverval;
 	u16 phy_classctl;
-	u16 phy_base_3E;
+	u16 phy_cck_3E;
 	u16 phy_crs0;
 	u16 phy_pgactl;
-	u16 phy_base_2A;
+	u16 phy_cck_2A;
 	u16 phy_syncctl;
-	u16 phy_base_30;
-	u16 phy_base_06;
+	u16 phy_cck_30;
+	u16 phy_cck_06;
 
 	/* Radio registers */
 	u16 radio_43;
@@ -588,7 +588,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
 		sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
 		sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
-		sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14));
+		sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14));
 		sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL);
 
 		b43_phy_write(dev, B43_PHY_HPWR_TSSICTL,
@@ -600,14 +600,14 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		b43_phy_write(dev, B43_PHY_DACCTL,
 			      b43_phy_read(dev, B43_PHY_DACCTL)
 			      | 0x40);
-		b43_phy_write(dev, B43_PHY_BASE(0x14),
-			      b43_phy_read(dev, B43_PHY_BASE(0x14))
+		b43_phy_write(dev, B43_PHY_CCK(0x14),
+			      b43_phy_read(dev, B43_PHY_CCK(0x14))
 			      | 0x200);
 	}
 	if (phy->type == B43_PHYTYPE_B &&
 	    phy->radio_ver == 0x2050 && phy->radio_rev < 6) {
-		b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410);
-		b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820);
+		b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410);
+		b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820);
 	}
 	if (!lo->rebuild && b43_has_hardware_pctl(phy))
 		lo_read_power_vector(dev);
@@ -618,7 +618,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
 		sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
 		sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
-		sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E));
+		sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E));
 		sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
 
 		b43_phy_write(dev, B43_PHY_CLASSCTL,
@@ -634,7 +634,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
 			      & 0xFFFC);
 		if (phy->type == B43_PHYTYPE_G) {
 			if ((phy->rev >= 7) &&
-			    (sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+			    (sprom->boardflags_lo & B43_BFL_EXTLNA)) {
 				b43_phy_write(dev, B43_PHY_RFOVER, 0x933);
 			} else {
 				b43_phy_write(dev, B43_PHY_RFOVER, 0x133);
@@ -642,14 +642,14 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		} else {
 			b43_phy_write(dev, B43_PHY_RFOVER, 0);
 		}
-		b43_phy_write(dev, B43_PHY_BASE(0x3E), 0);
+		b43_phy_write(dev, B43_PHY_CCK(0x3E), 0);
 	}
 	sav->reg_3F4 = b43_read16(dev, 0x3F4);
 	sav->reg_3E2 = b43_read16(dev, 0x3E2);
 	sav->radio_43 = b43_radio_read16(dev, 0x43);
 	sav->radio_7A = b43_radio_read16(dev, 0x7A);
 	sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
-	sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A));
+	sav->phy_cck_2A = b43_phy_read(dev, B43_PHY_CCK(0x2A));
 	sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
 	sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL);
 
@@ -658,10 +658,10 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		sav->radio_52 &= 0x00F0;
 	}
 	if (phy->type == B43_PHYTYPE_B) {
-		sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
-		sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06));
-		b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF);
-		b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F);
+		sav->phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
+		sav->phy_cck_06 = b43_phy_read(dev, B43_PHY_CCK(0x06));
+		b43_phy_write(dev, B43_PHY_CCK(0x30), 0x00FF);
+		b43_phy_write(dev, B43_PHY_CCK(0x06), 0x3F3F);
 	} else {
 		b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2)
 			    | 0x8000);
@@ -670,7 +670,7 @@ static void lo_measure_setup(struct b43_wldev *dev,
 		    & 0xF000);
 
 	tmp =
-	    (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E);
+	    (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_CCK(0x2E);
 	b43_phy_write(dev, tmp, 0x007F);
 
 	tmp = sav->phy_syncctl;
@@ -678,26 +678,26 @@ static void lo_measure_setup(struct b43_wldev *dev,
 	tmp = sav->radio_7A;
 	b43_radio_write16(dev, 0x007A, tmp & 0xFFF0);
 
-	b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3);
+	b43_phy_write(dev, B43_PHY_CCK(0x2A), 0x8A3);
 	if (phy->type == B43_PHYTYPE_G ||
 	    (phy->type == B43_PHYTYPE_B &&
 	     phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) {
-		b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003);
+		b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1003);
 	} else
-		b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802);
+		b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802);
 	if (phy->rev >= 2)
 		b43_dummy_transmission(dev);
 	b43_radio_selectchannel(dev, 6, 0);
 	b43_radio_read16(dev, 0x51);	/* dummy read */
 	if (phy->type == B43_PHYTYPE_G)
-		b43_phy_write(dev, B43_PHY_BASE(0x2F), 0);
+		b43_phy_write(dev, B43_PHY_CCK(0x2F), 0);
 	if (lo->rebuild)
 		lo_measure_txctl_values(dev);
 	if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
 		b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
 	} else {
 		if (phy->type == B43_PHYTYPE_B)
-			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
 		else
 			b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
 	}
@@ -732,17 +732,17 @@ static void lo_measure_restore(struct b43_wldev *dev,
 	}
 	if (phy->type == B43_PHYTYPE_G) {
 		if (phy->rev >= 3)
-			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078);
+			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078);
 		else
-			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078);
 		if (phy->rev >= 2)
-			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202);
+			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0202);
 		else
-			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101);
+			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0101);
 	}
 	b43_write16(dev, 0x3F4, sav->reg_3F4);
 	b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl);
-	b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A);
+	b43_phy_write(dev, B43_PHY_CCK(0x2A), sav->phy_cck_2A);
 	b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl);
 	b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl);
 	b43_radio_write16(dev, 0x43, sav->radio_43);
@@ -755,8 +755,8 @@ static void lo_measure_restore(struct b43_wldev *dev,
 	b43_write16(dev, 0x3E2, sav->reg_3E2);
 	if (phy->type == B43_PHYTYPE_B &&
 	    phy->radio_ver == 0x2050 && phy->radio_rev <= 5) {
-		b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30);
-		b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06);
+		b43_phy_write(dev, B43_PHY_CCK(0x30), sav->phy_cck_30);
+		b43_phy_write(dev, B43_PHY_CCK(0x06), sav->phy_cck_06);
 	}
 	if (phy->rev >= 2) {
 		b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover);
@@ -765,7 +765,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
 		b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl);
 		b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover);
 		b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval);
-		b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E);
+		b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E);
 		b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
 	}
 	if (b43_has_hardware_pctl(phy)) {
@@ -773,7 +773,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
 		b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
 		b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
 		b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl);
-		b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14);
+		b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14);
 		b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
 	}
 	b43_radio_selectchannel(dev, sav->old_channel, 1);
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 1c93b4f4bfe3..88d2c15d3fbe 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -46,7 +46,6 @@
 #include "debugfs.h"
 #include "phy.h"
 #include "dma.h"
-#include "pio.h"
 #include "sysfs.h"
 #include "xmit.h"
 #include "lo.h"
@@ -58,31 +57,12 @@ MODULE_AUTHOR("Stefano Brivio");
 MODULE_AUTHOR("Michael Buesch");
 MODULE_LICENSE("GPL");
 
-extern char *nvram_get(char *name);
-
-#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
-static int modparam_pio;
-module_param_named(pio, modparam_pio, int, 0444);
-MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
-#elif defined(CONFIG_B43_DMA)
-# define modparam_pio	0
-#elif defined(CONFIG_B43_PIO)
-# define modparam_pio	1
-#endif
 
 static int modparam_bad_frames_preempt;
 module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
 MODULE_PARM_DESC(bad_frames_preempt,
 		 "enable(1) / disable(0) Bad Frames Preemption");
 
-static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT;
-module_param_named(short_retry, modparam_short_retry, int, 0444);
-MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
-
-static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT;
-module_param_named(long_retry, modparam_long_retry, int, 0444);
-MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
-
 static char modparam_fwpostfix[16];
 module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
 MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
@@ -101,6 +81,8 @@ static const struct ssb_device_id b43_ssb_tbl[] = {
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
 	SSB_DEVTABLE_END
 };
 
@@ -150,7 +132,7 @@ static struct ieee80211_rate __b43_ratetable[] = {
 		.power_level	= 0xFF,				\
 		.antenna_max	= 0xFF,				\
 	}
-static struct ieee80211_channel b43_bg_chantable[] = {
+static struct ieee80211_channel b43_2ghz_chantable[] = {
 	CHANTAB_ENT(1, 2412),
 	CHANTAB_ENT(2, 2417),
 	CHANTAB_ENT(3, 2422),
@@ -166,9 +148,10 @@ static struct ieee80211_channel b43_bg_chantable[] = {
 	CHANTAB_ENT(13, 2472),
 	CHANTAB_ENT(14, 2484),
 };
+#define b43_2ghz_chantable_size	ARRAY_SIZE(b43_2ghz_chantable)
 
-#define b43_bg_chantable_size	ARRAY_SIZE(b43_bg_chantable)
-static struct ieee80211_channel b43_a_chantable[] = {
+#if 0
+static struct ieee80211_channel b43_5ghz_chantable[] = {
 	CHANTAB_ENT(36, 5180),
 	CHANTAB_ENT(40, 5200),
 	CHANTAB_ENT(44, 5220),
@@ -183,8 +166,8 @@ static struct ieee80211_channel b43_a_chantable[] = {
 	CHANTAB_ENT(161, 5805),
 	CHANTAB_ENT(165, 5825),
 };
-
-#define b43_a_chantable_size	ARRAY_SIZE(b43_a_chantable)
+#define b43_5ghz_chantable_size	ARRAY_SIZE(b43_5ghz_chantable)
+#endif
 
 static void b43_wireless_core_exit(struct b43_wldev *dev);
 static int b43_wireless_core_init(struct b43_wldev *dev);
@@ -269,13 +252,12 @@ static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
 	b43_write32(dev, B43_MMIO_RAM_DATA, val);
 }
 
-static inline
-    void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset)
+static inline void b43_shm_control_word(struct b43_wldev *dev,
+					u16 routing, u16 offset)
 {
 	u32 control;
 
 	/* "offset" is the WORD offset. */
-
 	control = routing;
 	control <<= 16;
 	control |= offset;
@@ -284,8 +266,11 @@ static inline
 
 u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
 {
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
 	u32 ret;
 
+	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
@@ -296,20 +281,25 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
 			b43_shm_control_word(dev, routing, (offset >> 2) + 1);
 			ret |= b43_read16(dev, B43_MMIO_SHM_DATA);
 
-			return ret;
+			goto out;
 		}
 		offset >>= 2;
 	}
 	b43_shm_control_word(dev, routing, offset);
 	ret = b43_read32(dev, B43_MMIO_SHM_DATA);
+out:
+	spin_unlock_irqrestore(&wl->shm_lock, flags);
 
 	return ret;
 }
 
 u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
 {
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
 	u16 ret;
 
+	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
@@ -317,55 +307,63 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
 			b43_shm_control_word(dev, routing, offset >> 2);
 			ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
 
-			return ret;
+			goto out;
 		}
 		offset >>= 2;
 	}
 	b43_shm_control_word(dev, routing, offset);
 	ret = b43_read16(dev, B43_MMIO_SHM_DATA);
+out:
+	spin_unlock_irqrestore(&wl->shm_lock, flags);
 
 	return ret;
 }
 
 void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
 {
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
 			/* Unaligned access */
 			b43_shm_control_word(dev, routing, offset >> 2);
-			mmiowb();
 			b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
 				    (value >> 16) & 0xffff);
-			mmiowb();
 			b43_shm_control_word(dev, routing, (offset >> 2) + 1);
-			mmiowb();
 			b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
-			return;
+			goto out;
 		}
 		offset >>= 2;
 	}
 	b43_shm_control_word(dev, routing, offset);
-	mmiowb();
 	b43_write32(dev, B43_MMIO_SHM_DATA, value);
+out:
+	spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
 void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
 {
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->shm_lock, flags);
 	if (routing == B43_SHM_SHARED) {
 		B43_WARN_ON(offset & 0x0001);
 		if (offset & 0x0003) {
 			/* Unaligned access */
 			b43_shm_control_word(dev, routing, offset >> 2);
-			mmiowb();
 			b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
-			return;
+			goto out;
 		}
 		offset >>= 2;
 	}
 	b43_shm_control_word(dev, routing, offset);
-	mmiowb();
 	b43_write16(dev, B43_MMIO_SHM_DATA, value);
+out:
+	spin_unlock_irqrestore(&wl->shm_lock, flags);
 }
 
 /* Read HostFlags */
@@ -1012,9 +1010,8 @@ static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
 static void b43_generate_noise_sample(struct b43_wldev *dev)
 {
 	b43_jssi_write(dev, 0x7F7F7F7F);
-	b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
-		    b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
-		    | (1 << 4));
+	b43_write32(dev, B43_MMIO_MACCMD,
+		    b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE);
 	B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel);
 }
 
@@ -1100,18 +1097,18 @@ static void handle_irq_tbtt_indication(struct b43_wldev *dev)
 		if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
 			b43_power_saving_ctl_bits(dev, 0);
 	}
-	dev->reg124_set_0x4 = 0;
 	if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
-		dev->reg124_set_0x4 = 1;
+		dev->dfq_valid = 1;
 }
 
 static void handle_irq_atim_end(struct b43_wldev *dev)
 {
-	if (!dev->reg124_set_0x4 /*FIXME rename this variable */ )
-		return;
-	b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
-		    b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
-		    | 0x4);
+	if (dev->dfq_valid) {
+		b43_write32(dev, B43_MMIO_MACCMD,
+			    b43_read32(dev, B43_MMIO_MACCMD)
+			    | B43_MACCMD_DFQ_VALID);
+		dev->dfq_valid = 0;
+	}
 }
 
 static void handle_irq_pmq(struct b43_wldev *dev)
@@ -1166,15 +1163,59 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
 				      u16 ram_offset,
 				      u16 shm_size_offset, u8 rate)
 {
-	int len;
-	const u8 *data;
+	unsigned int i, len, variable_len;
+	const struct ieee80211_mgmt *bcn;
+	const u8 *ie;
+	bool tim_found = 0;
 
-	B43_WARN_ON(!dev->cached_beacon);
-	len = min((size_t) dev->cached_beacon->len,
+	bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
+	len = min((size_t) dev->wl->current_beacon->len,
 		  0x200 - sizeof(struct b43_plcp_hdr6));
-	data = (const u8 *)(dev->cached_beacon->data);
-	b43_write_template_common(dev, data,
+
+	b43_write_template_common(dev, (const u8 *)bcn,
 				  len, ram_offset, shm_size_offset, rate);
+
+	/* Find the position of the TIM and the DTIM_period value
+	 * and write them to SHM. */
+	ie = bcn->u.beacon.variable;
+	variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
+	for (i = 0; i < variable_len - 2; ) {
+		uint8_t ie_id, ie_len;
+
+		ie_id = ie[i];
+		ie_len = ie[i + 1];
+		if (ie_id == 5) {
+			u16 tim_position;
+			u16 dtim_period;
+			/* This is the TIM Information Element */
+
+			/* Check whether the ie_len is in the beacon data range. */
+			if (variable_len < ie_len + 2 + i)
+				break;
+			/* A valid TIM is at least 4 bytes long. */
+			if (ie_len < 4)
+				break;
+			tim_found = 1;
+
+			tim_position = sizeof(struct b43_plcp_hdr6);
+			tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable);
+			tim_position += i;
+
+			dtim_period = ie[i + 3];
+
+			b43_shm_write16(dev, B43_SHM_SHARED,
+					B43_SHM_SH_TIMBPOS, tim_position);
+			b43_shm_write16(dev, B43_SHM_SHARED,
+					B43_SHM_SH_DTIMPER, dtim_period);
+			break;
+		}
+		i += ie_len + 2;
+	}
+	if (!tim_found) {
+		b43warn(dev->wl, "Did not find a valid TIM IE in "
+			"the beacon template packet. AP or IBSS operation "
+			"may be broken.\n");
+	}
 }
 
 static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
@@ -1187,7 +1228,7 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
 	plcp.data = 0;
 	b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
 	dur = ieee80211_generic_frame_duration(dev->wl->hw,
-					       dev->wl->if_id, size,
+					       dev->wl->vif, size,
 					       B43_RATE_TO_BASE100KBPS(rate));
 	/* Write PLCP in two parts and timing for packet transfer */
 	tmp = le32_to_cpu(plcp.data);
@@ -1202,40 +1243,43 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
  * 2) Patching duration field
  * 3) Stripping TIM
  */
-static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
-				   u16 * dest_size, u8 rate)
+static const u8 * b43_generate_probe_resp(struct b43_wldev *dev,
+					  u16 *dest_size, u8 rate)
 {
 	const u8 *src_data;
 	u8 *dest_data;
 	u16 src_size, elem_size, src_pos, dest_pos;
 	__le16 dur;
 	struct ieee80211_hdr *hdr;
+	size_t ie_start;
 
-	B43_WARN_ON(!dev->cached_beacon);
-	src_size = dev->cached_beacon->len;
-	src_data = (const u8 *)dev->cached_beacon->data;
+	src_size = dev->wl->current_beacon->len;
+	src_data = (const u8 *)dev->wl->current_beacon->data;
 
-	if (unlikely(src_size < 0x24)) {
-		b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n");
+	/* Get the start offset of the variable IEs in the packet. */
+	ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+	B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable));
+
+	if (B43_WARN_ON(src_size < ie_start))
 		return NULL;
-	}
 
 	dest_data = kmalloc(src_size, GFP_ATOMIC);
 	if (unlikely(!dest_data))
 		return NULL;
 
-	/* 0x24 is offset of first variable-len Information-Element
-	 * in beacon frame.
-	 */
-	memcpy(dest_data, src_data, 0x24);
-	src_pos = dest_pos = 0x24;
-	for (; src_pos < src_size - 2; src_pos += elem_size) {
+	/* Copy the static data and all Information Elements, except the TIM. */
+	memcpy(dest_data, src_data, ie_start);
+	src_pos = ie_start;
+	dest_pos = ie_start;
+	for ( ; src_pos < src_size - 2; src_pos += elem_size) {
 		elem_size = src_data[src_pos + 1] + 2;
-		if (src_data[src_pos] != 0x05) {	/* TIM */
-			memcpy(dest_data + dest_pos, src_data + src_pos,
-			       elem_size);
-			dest_pos += elem_size;
+		if (src_data[src_pos] == 5) {
+			/* This is the TIM. */
+			continue;
 		}
+		memcpy(dest_data + dest_pos, src_data + src_pos,
+		       elem_size);
+		dest_pos += elem_size;
 	}
 	*dest_size = dest_pos;
 	hdr = (struct ieee80211_hdr *)dest_data;
@@ -1244,7 +1288,7 @@ static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
 	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 					 IEEE80211_STYPE_PROBE_RESP);
 	dur = ieee80211_generic_frame_duration(dev->wl->hw,
-					       dev->wl->if_id, *dest_size,
+					       dev->wl->vif, *dest_size,
 					       B43_RATE_TO_BASE100KBPS(rate));
 	hdr->duration_id = dur;
 
@@ -1255,11 +1299,10 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev,
 					  u16 ram_offset,
 					  u16 shm_size_offset, u8 rate)
 {
-	u8 *probe_resp_data;
+	const u8 *probe_resp_data;
 	u16 size;
 
-	B43_WARN_ON(!dev->cached_beacon);
-	size = dev->cached_beacon->len;
+	size = dev->wl->current_beacon->len;
 	probe_resp_data = b43_generate_probe_resp(dev, &size, rate);
 	if (unlikely(!probe_resp_data))
 		return;
@@ -1278,39 +1321,21 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev,
 	kfree(probe_resp_data);
 }
 
-static int b43_refresh_cached_beacon(struct b43_wldev *dev,
-				     struct sk_buff *beacon)
-{
-	if (dev->cached_beacon)
-		kfree_skb(dev->cached_beacon);
-	dev->cached_beacon = beacon;
-
-	return 0;
-}
-
-static void b43_update_templates(struct b43_wldev *dev)
+/* Asynchronously update the packet templates in template RAM.
+ * Locking: Requires wl->irq_lock to be locked. */
+static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
 {
-	u32 status;
-
-	B43_WARN_ON(!dev->cached_beacon);
+	/* This is the top half of the ansynchronous beacon update.
+	 * The bottom half is the beacon IRQ.
+	 * Beacon update must be asynchronous to avoid sending an
+	 * invalid beacon. This can happen for example, if the firmware
+	 * transmits a beacon while we are updating it. */
 
-	b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
-	b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
-	b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB);
-
-	status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
-	status |= 0x03;
-	b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
-}
-
-static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon)
-{
-	int err;
-
-	err = b43_refresh_cached_beacon(dev, beacon);
-	if (unlikely(err))
-		return;
-	b43_update_templates(dev);
+	if (wl->current_beacon)
+		dev_kfree_skb_any(wl->current_beacon);
+	wl->current_beacon = beacon;
+	wl->beacon0_uploaded = 0;
+	wl->beacon1_uploaded = 0;
 }
 
 static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
@@ -1346,33 +1371,34 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 
 static void handle_irq_beacon(struct b43_wldev *dev)
 {
-	u32 status;
+	struct b43_wl *wl = dev->wl;
+	u32 cmd;
 
-	if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+	if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
 		return;
 
-	dev->irq_savedstate &= ~B43_IRQ_BEACON;
-	status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
+	/* This is the bottom half of the asynchronous beacon update. */
 
-	if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
-		/* ACK beacon IRQ. */
-		b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
-		dev->irq_savedstate |= B43_IRQ_BEACON;
-		if (dev->cached_beacon)
-			kfree_skb(dev->cached_beacon);
-		dev->cached_beacon = NULL;
-		return;
-	}
-	if (!(status & 0x1)) {
-		b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
-		status |= 0x1;
-		b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+	cmd = b43_read32(dev, B43_MMIO_MACCMD);
+	if (!(cmd & B43_MACCMD_BEACON0_VALID)) {
+		if (!wl->beacon0_uploaded) {
+			b43_write_beacon_template(dev, 0x68, 0x18,
+						  B43_CCK_RATE_1MB);
+			b43_write_probe_resp_template(dev, 0x268, 0x4A,
+						      B43_CCK_RATE_11MB);
+			wl->beacon0_uploaded = 1;
+		}
+		cmd |= B43_MACCMD_BEACON0_VALID;
 	}
-	if (!(status & 0x2)) {
-		b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
-		status |= 0x2;
-		b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+	if (!(cmd & B43_MACCMD_BEACON1_VALID)) {
+		if (!wl->beacon1_uploaded) {
+			b43_write_beacon_template(dev, 0x468, 0x1A,
+						  B43_CCK_RATE_1MB);
+			wl->beacon1_uploaded = 1;
+		}
+		cmd |= B43_MACCMD_BEACON1_VALID;
 	}
+	b43_write32(dev, B43_MMIO_MACCMD, cmd);
 }
 
 static void handle_irq_ucode_debug(struct b43_wldev *dev)
@@ -1402,8 +1428,17 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
 	if (unlikely(reason & B43_IRQ_MAC_TXERR))
 		b43err(dev->wl, "MAC transmission error\n");
 
-	if (unlikely(reason & B43_IRQ_PHY_TXERR))
+	if (unlikely(reason & B43_IRQ_PHY_TXERR)) {
 		b43err(dev->wl, "PHY transmission error\n");
+		rmb();
+		if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) {
+			atomic_set(&dev->phy.txerr_cnt,
+				   B43_PHY_TX_BADNESS_LIMIT);
+			b43err(dev->wl, "Too many PHY TX errors, "
+					"restarting the controller\n");
+			b43_controller_restart(dev, "PHY TX errors");
+		}
+	}
 
 	if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
 					  B43_DMAIRQ_NONFATALMASK))) {
@@ -1445,20 +1480,12 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
 		handle_irq_noise(dev);
 
 	/* Check the DMA reason registers for received data. */
-	if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
-		if (b43_using_pio(dev))
-			b43_pio_rx(dev->pio.queue0);
-		else
-			b43_dma_rx(dev->dma.rx_ring0);
-	}
+	if (dma_reason[0] & B43_DMAIRQ_RX_DONE)
+		b43_dma_rx(dev->dma.rx_ring0);
+	if (dma_reason[3] & B43_DMAIRQ_RX_DONE)
+		b43_dma_rx(dev->dma.rx_ring3);
 	B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
 	B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
-	if (dma_reason[3] & B43_DMAIRQ_RX_DONE) {
-		if (b43_using_pio(dev))
-			b43_pio_rx(dev->pio.queue3);
-		else
-			b43_dma_rx(dev->dma.rx_ring3);
-	}
 	B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
 	B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
 
@@ -1470,29 +1497,8 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev)
 	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
 }
 
-static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx)
-{
-	u16 rxctl;
-
-	rxctl = b43_read16(dev, base + B43_PIO_RXCTL);
-	if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE)
-		dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE;
-	else
-		dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE;
-}
-
 static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
 {
-	if (b43_using_pio(dev) &&
-	    (dev->dev->id.revision < 3) &&
-	    (!(reason & B43_IRQ_PIO_WORKAROUND))) {
-		/* Apply a PIO specific workaround to the dma_reasons */
-		pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0);
-		pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1);
-		pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2);
-		pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3);
-	}
-
 	b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
 
 	b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
@@ -1551,54 +1557,73 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
 	return ret;
 }
 
+static void do_release_fw(struct b43_firmware_file *fw)
+{
+	release_firmware(fw->data);
+	fw->data = NULL;
+	fw->filename = NULL;
+}
+
 static void b43_release_firmware(struct b43_wldev *dev)
 {
-	release_firmware(dev->fw.ucode);
-	dev->fw.ucode = NULL;
-	release_firmware(dev->fw.pcm);
-	dev->fw.pcm = NULL;
-	release_firmware(dev->fw.initvals);
-	dev->fw.initvals = NULL;
-	release_firmware(dev->fw.initvals_band);
-	dev->fw.initvals_band = NULL;
+	do_release_fw(&dev->fw.ucode);
+	do_release_fw(&dev->fw.pcm);
+	do_release_fw(&dev->fw.initvals);
+	do_release_fw(&dev->fw.initvals_band);
 }
 
-static void b43_print_fw_helptext(struct b43_wl *wl)
+static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
 {
-	b43err(wl, "You must go to "
+	const char *text;
+
+	text = "You must go to "
 	       "http://linuxwireless.org/en/users/Drivers/b43#devicefirmware "
-	       "and download the correct firmware (version 4).\n");
+	       "and download the latest firmware (version 4).\n";
+	if (error)
+		b43err(wl, text);
+	else
+		b43warn(wl, text);
 }
 
 static int do_request_fw(struct b43_wldev *dev,
 			 const char *name,
-			 const struct firmware **fw)
+			 struct b43_firmware_file *fw)
 {
 	char path[sizeof(modparam_fwpostfix) + 32];
+	const struct firmware *blob;
 	struct b43_fw_header *hdr;
 	u32 size;
 	int err;
 
-	if (!name)
+	if (!name) {
+		/* Don't fetch anything. Free possibly cached firmware. */
+		do_release_fw(fw);
 		return 0;
+	}
+	if (fw->filename) {
+		if (strcmp(fw->filename, name) == 0)
+			return 0; /* Already have this fw. */
+		/* Free the cached firmware first. */
+		do_release_fw(fw);
+	}
 
 	snprintf(path, ARRAY_SIZE(path),
 		 "b43%s/%s.fw",
 		 modparam_fwpostfix, name);
-	err = request_firmware(fw, path, dev->dev->dev);
+	err = request_firmware(&blob, path, dev->dev->dev);
 	if (err) {
 		b43err(dev->wl, "Firmware file \"%s\" not found "
 		       "or load failed.\n", path);
 		return err;
 	}
-	if ((*fw)->size < sizeof(struct b43_fw_header))
+	if (blob->size < sizeof(struct b43_fw_header))
 		goto err_format;
-	hdr = (struct b43_fw_header *)((*fw)->data);
+	hdr = (struct b43_fw_header *)(blob->data);
 	switch (hdr->type) {
 	case B43_FW_TYPE_UCODE:
 	case B43_FW_TYPE_PCM:
 		size = be32_to_cpu(hdr->size);
-		if (size != (*fw)->size - sizeof(struct b43_fw_header))
+		if (size != blob->size - sizeof(struct b43_fw_header))
 			goto err_format;
 		/* fallthrough */
 	case B43_FW_TYPE_IV:
@@ -1609,10 +1634,15 @@ static int do_request_fw(struct b43_wldev *dev,
 		goto err_format;
 	}
 
-	return err;
+	fw->data = blob;
+	fw->filename = name;
+
+	return 0;
 
 err_format:
 	b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
+	release_firmware(blob);
+
 	return -EPROTO;
 }
 
@@ -1624,90 +1654,101 @@ static int b43_request_firmware(struct b43_wldev *dev)
 	u32 tmshigh;
 	int err;
 
+	/* Get microcode */
 	tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
-	if (!fw->ucode) {
+	if ((rev >= 5) && (rev <= 10))
+		filename = "ucode5";
+	else if ((rev >= 11) && (rev <= 12))
+		filename = "ucode11";
+	else if (rev >= 13)
+		filename = "ucode13";
+	else
+		goto err_no_ucode;
+	err = do_request_fw(dev, filename, &fw->ucode);
+	if (err)
+		goto err_load;
+
+	/* Get PCM code */
+	if ((rev >= 5) && (rev <= 10))
+		filename = "pcm5";
+	else if (rev >= 11)
+		filename = NULL;
+	else
+		goto err_no_pcm;
+	err = do_request_fw(dev, filename, &fw->pcm);
+	if (err)
+		goto err_load;
+
+	/* Get initvals */
+	switch (dev->phy.type) {
+	case B43_PHYTYPE_A:
+		if ((rev >= 5) && (rev <= 10)) {
+			if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+				filename = "a0g1initvals5";
+			else
+				filename = "a0g0initvals5";
+		} else
+			goto err_no_initvals;
+		break;
+	case B43_PHYTYPE_G:
 		if ((rev >= 5) && (rev <= 10))
-			filename = "ucode5";
-		else if ((rev >= 11) && (rev <= 12))
-			filename = "ucode11";
+			filename = "b0g0initvals5";
 		else if (rev >= 13)
-			filename = "ucode13";
+			filename = "lp0initvals13";
 		else
-			goto err_no_ucode;
-		err = do_request_fw(dev, filename, &fw->ucode);
-		if (err)
-			goto err_load;
+			goto err_no_initvals;
+		break;
+	case B43_PHYTYPE_N:
+		if ((rev >= 11) && (rev <= 12))
+			filename = "n0initvals11";
+		else
+			goto err_no_initvals;
+		break;
+	default:
+		goto err_no_initvals;
 	}
-	if (!fw->pcm) {
+	err = do_request_fw(dev, filename, &fw->initvals);
+	if (err)
+		goto err_load;
+
+	/* Get bandswitch initvals */
+	switch (dev->phy.type) {
+	case B43_PHYTYPE_A:
+		if ((rev >= 5) && (rev <= 10)) {
+			if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
+				filename = "a0g1bsinitvals5";
+			else
+				filename = "a0g0bsinitvals5";
+		} else if (rev >= 11)
+			filename = NULL;
+		else
+			goto err_no_initvals;
+		break;
+	case B43_PHYTYPE_G:
 		if ((rev >= 5) && (rev <= 10))
-			filename = "pcm5";
+			filename = "b0g0bsinitvals5";
 		else if (rev >= 11)
 			filename = NULL;
 		else
-			goto err_no_pcm;
-		err = do_request_fw(dev, filename, &fw->pcm);
-		if (err)
-			goto err_load;
-	}
-	if (!fw->initvals) {
-		switch (dev->phy.type) {
-		case B43_PHYTYPE_A:
-			if ((rev >= 5) && (rev <= 10)) {
-				if (tmshigh & B43_TMSHIGH_GPHY)
-					filename = "a0g1initvals5";
-				else
-					filename = "a0g0initvals5";
-			} else
-				goto err_no_initvals;
-			break;
-		case B43_PHYTYPE_G:
-			if ((rev >= 5) && (rev <= 10))
-				filename = "b0g0initvals5";
-			else if (rev >= 13)
-				filename = "lp0initvals13";
-			else
-				goto err_no_initvals;
-			break;
-		default:
 			goto err_no_initvals;
-		}
-		err = do_request_fw(dev, filename, &fw->initvals);
-		if (err)
-			goto err_load;
-	}
-	if (!fw->initvals_band) {
-		switch (dev->phy.type) {
-		case B43_PHYTYPE_A:
-			if ((rev >= 5) && (rev <= 10)) {
-				if (tmshigh & B43_TMSHIGH_GPHY)
-					filename = "a0g1bsinitvals5";
-				else
-					filename = "a0g0bsinitvals5";
-			} else if (rev >= 11)
-				filename = NULL;
-			else
-				goto err_no_initvals;
-			break;
-		case B43_PHYTYPE_G:
-			if ((rev >= 5) && (rev <= 10))
-				filename = "b0g0bsinitvals5";
-			else if (rev >= 11)
-				filename = NULL;
-			else
-				goto err_no_initvals;
-			break;
-		default:
+		break;
+	case B43_PHYTYPE_N:
+		if ((rev >= 11) && (rev <= 12))
+			filename = "n0bsinitvals11";
+		else
 			goto err_no_initvals;
-		}
-		err = do_request_fw(dev, filename, &fw->initvals_band);
-		if (err)
-			goto err_load;
+		break;
+	default:
+		goto err_no_initvals;
 	}
+	err = do_request_fw(dev, filename, &fw->initvals_band);
+	if (err)
+		goto err_load;
 
 	return 0;
 
 err_load:
-	b43_print_fw_helptext(dev->wl);
+	b43_print_fw_helptext(dev->wl, 1);
 	goto error;
 
 err_no_ucode:
@@ -1737,22 +1778,33 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 	const __be32 *data;
 	unsigned int i, len;
 	u16 fwrev, fwpatch, fwdate, fwtime;
-	u32 tmp;
+	u32 tmp, macctl;
 	int err = 0;
 
+	/* Jump the microcode PSM to offset 0 */
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN);
+	macctl |= B43_MACCTL_PSM_JMP0;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+	/* Zero out all microcode PSM registers and shared memory. */
+	for (i = 0; i < 64; i++)
+		b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0);
+	for (i = 0; i < 4096; i += 2)
+		b43_shm_write16(dev, B43_SHM_SHARED, i, 0);
+
 	/* Upload Microcode. */
-	data = (__be32 *) (dev->fw.ucode->data + hdr_len);
-	len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+	data = (__be32 *) (dev->fw.ucode.data->data + hdr_len);
+	len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32);
 	b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
 	for (i = 0; i < len; i++) {
 		b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
 		udelay(10);
 	}
 
-	if (dev->fw.pcm) {
+	if (dev->fw.pcm.data) {
 		/* Upload PCM data. */
-		data = (__be32 *) (dev->fw.pcm->data + hdr_len);
-		len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+		data = (__be32 *) (dev->fw.pcm.data->data + hdr_len);
+		len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32);
 		b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
 		b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
 		/* No need for autoinc bit in SHM_HW */
@@ -1764,9 +1816,12 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 	}
 
 	b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
-	b43_write32(dev, B43_MMIO_MACCTL,
-		    B43_MACCTL_PSM_RUN |
-		    B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA);
+
+	/* Start the microcode PSM */
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl &= ~B43_MACCTL_PSM_JMP0;
+	macctl |= B43_MACCTL_PSM_RUN;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
 	/* Wait for the microcode to load and respond */
 	i = 0;
@@ -1775,13 +1830,17 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 		if (tmp == B43_IRQ_MAC_SUSPENDED)
 			break;
 		i++;
-		if (i >= 50) {
+		if (i >= 20) {
 			b43err(dev->wl, "Microcode not responding\n");
-			b43_print_fw_helptext(dev->wl);
+			b43_print_fw_helptext(dev->wl, 1);
 			err = -ENODEV;
-			goto out;
+			goto error;
+		}
+		msleep_interruptible(50);
+		if (signal_pending(current)) {
+			err = -EINTR;
+			goto error;
 		}
-		udelay(10);
 	}
 	b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);	/* dummy read */
 
@@ -1795,10 +1854,9 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 		b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
 		       "binary drivers older than version 4.x is unsupported. "
 		       "You must upgrade your firmware files.\n");
-		b43_print_fw_helptext(dev->wl);
-		b43_write32(dev, B43_MMIO_MACCTL, 0);
+		b43_print_fw_helptext(dev->wl, 1);
 		err = -EOPNOTSUPP;
-		goto out;
+		goto error;
 	}
 	b43dbg(dev->wl, "Loading firmware version %u.%u "
 	       "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
@@ -1809,7 +1867,20 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 	dev->fw.rev = fwrev;
 	dev->fw.patch = fwpatch;
 
-      out:
+	if (b43_is_old_txhdr_format(dev)) {
+		b43warn(dev->wl, "You are using an old firmware image. "
+			"Support for old firmware will be removed in July 2008.\n");
+		b43_print_fw_helptext(dev->wl, 0);
+	}
+
+	return 0;
+
+error:
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl &= ~B43_MACCTL_PSM_RUN;
+	macctl |= B43_MACCTL_PSM_JMP0;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+
 	return err;
 }
 
@@ -1869,7 +1940,7 @@ static int b43_write_initvals(struct b43_wldev *dev,
 
 err_format:
 	b43err(dev->wl, "Initial Values Firmware file-format error.\n");
-	b43_print_fw_helptext(dev->wl);
+	b43_print_fw_helptext(dev->wl, 1);
 
 	return -EPROTO;
 }
@@ -1883,19 +1954,19 @@ static int b43_upload_initvals(struct b43_wldev *dev)
 	size_t count;
 	int err;
 
-	hdr = (const struct b43_fw_header *)(fw->initvals->data);
-	ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len);
+	hdr = (const struct b43_fw_header *)(fw->initvals.data->data);
+	ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len);
 	count = be32_to_cpu(hdr->size);
 	err = b43_write_initvals(dev, ivals, count,
-				 fw->initvals->size - hdr_len);
+				 fw->initvals.data->size - hdr_len);
 	if (err)
 		goto out;
-	if (fw->initvals_band) {
-		hdr = (const struct b43_fw_header *)(fw->initvals_band->data);
-		ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len);
+	if (fw->initvals_band.data) {
+		hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data);
+		ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len);
 		count = be32_to_cpu(hdr->size);
 		err = b43_write_initvals(dev, ivals, count,
-					 fw->initvals_band->size - hdr_len);
+					 fw->initvals_band.data->size - hdr_len);
 		if (err)
 			goto out;
 	}
@@ -1932,7 +2003,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
 		mask |= 0x0180;
 		set |= 0x0180;
 	}
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
 		b43_write16(dev, B43_MMIO_GPIO_MASK,
 			    b43_read16(dev, B43_MMIO_GPIO_MASK)
 			    | 0x0200);
@@ -2102,6 +2173,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev)
 	switch (dev->phy.type) {
 	case B43_PHYTYPE_A:
 	case B43_PHYTYPE_G:
+	case B43_PHYTYPE_N:
 		b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
 		b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
@@ -2131,13 +2203,19 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 
 	switch (antenna) {
 	case B43_ANTENNA0:
-		ant |= B43_TX4_PHY_ANT0;
+		ant |= B43_TXH_PHY_ANT0;
 		break;
 	case B43_ANTENNA1:
-		ant |= B43_TX4_PHY_ANT1;
+		ant |= B43_TXH_PHY_ANT1;
+		break;
+	case B43_ANTENNA2:
+		ant |= B43_TXH_PHY_ANT2;
+		break;
+	case B43_ANTENNA3:
+		ant |= B43_TXH_PHY_ANT3;
 		break;
 	case B43_ANTENNA_AUTO:
-		ant |= B43_TX4_PHY_ANTLAST;
+		ant |= B43_TXH_PHY_ANT01AUTO;
 		break;
 	default:
 		B43_WARN_ON(1);
@@ -2147,15 +2225,15 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 
 	/* For Beacons */
 	tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
-	tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+	tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp);
 	/* For ACK/CTS */
 	tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
-	tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+	tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
 	/* For Probe Resposes */
 	tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
-	tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+	tmp = (tmp & ~B43_TXH_PHY_ANT) | ant;
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
 }
 
@@ -2174,11 +2252,15 @@ static int b43_chip_init(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
 	int err, tmp;
-	u32 value32;
+	u32 value32, macctl;
 	u16 value16;
 
-	b43_write32(dev, B43_MMIO_MACCTL,
-		    B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED);
+	/* Initialize the MAC control */
+	macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
+	if (dev->phy.gmode)
+		macctl |= B43_MACCTL_GMODE;
+	macctl |= B43_MACCTL_INFRA;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
 	err = b43_request_firmware(dev);
 	if (err)
@@ -2223,14 +2305,6 @@ static int b43_chip_init(struct b43_wldev *dev)
 	b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
 		    | B43_MACCTL_INFRA);
 
-	if (b43_using_pio(dev)) {
-		b43_write32(dev, 0x0210, 0x00000100);
-		b43_write32(dev, 0x0230, 0x00000100);
-		b43_write32(dev, 0x0250, 0x00000100);
-		b43_write32(dev, 0x0270, 0x00000100);
-		b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000);
-	}
-
 	/* Probe Response Timeout value */
 	/* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
 	b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
@@ -2292,9 +2366,11 @@ static void b43_periodic_every60sec(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
 
+	if (phy->type != B43_PHYTYPE_G)
+		return;
 	if (!b43_has_hardware_pctl(phy))
 		b43_lo_g_ctl_mark_all_unused(dev);
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
 		b43_mac_suspend(dev);
 		b43_calc_nrssi_slope(dev);
 		if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
@@ -2346,6 +2422,9 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
 	}
 	b43_phy_xmitpower(dev);	//FIXME: unless scanning?
 	//TODO for APHY (temperature?)
+
+	atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+	wmb();
 }
 
 static void do_periodic_work(struct b43_wldev *dev)
@@ -2403,32 +2482,42 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev)
 	queue_delayed_work(dev->wl->hw->workqueue, work, 0);
 }
 
-/* Validate access to the chip (SHM) */
+/* Check if communication with the device works correctly. */
 static int b43_validate_chipaccess(struct b43_wldev *dev)
 {
-	u32 value;
-	u32 shm_backup;
+	u32 v, backup;
 
-	shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
-	b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
-	if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
-		goto error;
+	backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+
+	/* Check for read/write and endianness problems. */
 	b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
 	if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
 		goto error;
-	b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup);
-
-	value = b43_read32(dev, B43_MMIO_MACCTL);
-	if ((value | B43_MACCTL_GMODE) !=
-	    (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
+	b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
+	if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
 		goto error;
 
-	value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
-	if (value)
+	b43_shm_write32(dev, B43_SHM_SHARED, 0, backup);
+
+	if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
+		/* The 32bit register shadows the two 16bit registers
+		 * with update sideeffects. Validate this. */
+		b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
+		b43_write32(dev, B43_MMIO_TSF_CFP_START, 0xCCCCBBBB);
+		if (b43_read16(dev, B43_MMIO_TSF_CFP_START_LOW) != 0xBBBB)
+			goto error;
+		if (b43_read16(dev, B43_MMIO_TSF_CFP_START_HIGH) != 0xCCCC)
+			goto error;
+	}
+	b43_write32(dev, B43_MMIO_TSF_CFP_START, 0);
+
+	v = b43_read32(dev, B43_MMIO_MACCTL);
+	v |= B43_MACCTL_GMODE;
+	if (v != (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
 		goto error;
 
 	return 0;
-      error:
+error:
 	b43err(dev->wl, "Failed to validate the chipaccess\n");
 	return -ENODEV;
 }
@@ -2491,40 +2580,35 @@ static int b43_rng_init(struct b43_wl *wl)
 	return err;
 }
 
-static int b43_tx(struct ieee80211_hw *hw,
-		  struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+static int b43_op_tx(struct ieee80211_hw *hw,
+		     struct sk_buff *skb,
+		     struct ieee80211_tx_control *ctl)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
 	int err = -ENODEV;
-	unsigned long flags;
 
 	if (unlikely(!dev))
 		goto out;
 	if (unlikely(b43_status(dev) < B43_STAT_STARTED))
 		goto out;
 	/* DMA-TX is done without a global lock. */
-	if (b43_using_pio(dev)) {
-		spin_lock_irqsave(&wl->irq_lock, flags);
-		err = b43_pio_tx(dev, skb, ctl);
-		spin_unlock_irqrestore(&wl->irq_lock, flags);
-	} else
-		err = b43_dma_tx(dev, skb, ctl);
-      out:
+	err = b43_dma_tx(dev, skb, ctl);
+out:
 	if (unlikely(err))
 		return NETDEV_TX_BUSY;
 	return NETDEV_TX_OK;
 }
 
-static int b43_conf_tx(struct ieee80211_hw *hw,
-		       int queue,
-		       const struct ieee80211_tx_queue_params *params)
+static int b43_op_conf_tx(struct ieee80211_hw *hw,
+			  int queue,
+			  const struct ieee80211_tx_queue_params *params)
 {
 	return 0;
 }
 
-static int b43_get_tx_stats(struct ieee80211_hw *hw,
-			    struct ieee80211_tx_queue_stats *stats)
+static int b43_op_get_tx_stats(struct ieee80211_hw *hw,
+			       struct ieee80211_tx_queue_stats *stats)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -2535,19 +2619,16 @@ static int b43_get_tx_stats(struct ieee80211_hw *hw,
 		goto out;
 	spin_lock_irqsave(&wl->irq_lock, flags);
 	if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
-		if (b43_using_pio(dev))
-			b43_pio_get_tx_stats(dev, stats);
-		else
-			b43_dma_get_tx_stats(dev, stats);
+		b43_dma_get_tx_stats(dev, stats);
 		err = 0;
 	}
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
-      out:
+out:
 	return err;
 }
 
-static int b43_get_stats(struct ieee80211_hw *hw,
-			 struct ieee80211_low_level_stats *stats)
+static int b43_op_get_stats(struct ieee80211_hw *hw,
+			    struct ieee80211_low_level_stats *stats)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	unsigned long flags;
@@ -2686,8 +2767,36 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)
 	return err;
 }
 
-static int b43_antenna_from_ieee80211(u8 antenna)
+/* Check if the use of the antenna that ieee80211 told us to
+ * use is possible. This will fall back to DEFAULT.
+ * "antenna_nr" is the antenna identifier we got from ieee80211. */
+u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
+				  u8 antenna_nr)
+{
+	u8 antenna_mask;
+
+	if (antenna_nr == 0) {
+		/* Zero means "use default antenna". That's always OK. */
+		return 0;
+	}
+
+	/* Get the mask of available antennas. */
+	if (dev->phy.gmode)
+		antenna_mask = dev->dev->bus->sprom.ant_available_bg;
+	else
+		antenna_mask = dev->dev->bus->sprom.ant_available_a;
+
+	if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
+		/* This antenna is not available. Fall back to default. */
+		return 0;
+	}
+
+	return antenna_nr;
+}
+
+static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna)
 {
+	antenna = b43_ieee80211_antenna_sanitize(dev, antenna);
 	switch (antenna) {
 	case 0:		/* default/diversity */
 		return B43_ANTENNA_DEFAULT;
@@ -2695,26 +2804,26 @@ static int b43_antenna_from_ieee80211(u8 antenna)
 		return B43_ANTENNA0;
 	case 2:		/* Antenna 1 */
 		return B43_ANTENNA1;
+	case 3:		/* Antenna 2 */
+		return B43_ANTENNA2;
+	case 4:		/* Antenna 3 */
+		return B43_ANTENNA3;
 	default:
 		return B43_ANTENNA_DEFAULT;
 	}
 }
 
-static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev;
 	struct b43_phy *phy;
 	unsigned long flags;
 	unsigned int new_phymode = 0xFFFF;
-	int antenna_tx;
-	int antenna_rx;
+	int antenna;
 	int err = 0;
 	u32 savedirqs;
 
-	antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx);
-	antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx);
-
 	mutex_lock(&wl->mutex);
 
 	/* Switch the PHY mode (if necessary). */
@@ -2764,6 +2873,8 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 			b43_short_slot_timing_disable(dev);
 	}
 
+	dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
 	/* Adjust the desired TX power level. */
 	if (conf->power_level != 0) {
 		if (conf->power_level != phy->power_level) {
@@ -2773,8 +2884,10 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 	}
 
 	/* Antennas for RX and management frame TX. */
-	b43_mgmtframe_txantenna(dev, antenna_tx);
-	b43_set_rx_antenna(dev, antenna_rx);
+	antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx);
+	b43_mgmtframe_txantenna(dev, antenna);
+	antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx);
+	b43_set_rx_antenna(dev, antenna);
 
 	/* Update templates for AP mode. */
 	if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
@@ -2805,23 +2918,30 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 	return err;
 }
 
-static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 			   const u8 *local_addr, const u8 *addr,
 			   struct ieee80211_key_conf *key)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
-	struct b43_wldev *dev = wl->current_dev;
+	struct b43_wldev *dev;
 	unsigned long flags;
 	u8 algorithm;
 	u8 index;
-	int err = -EINVAL;
+	int err;
 	DECLARE_MAC_BUF(mac);
 
 	if (modparam_nohwcrypt)
 		return -ENOSPC; /* User disabled HW-crypto */
 
-	if (!dev)
-		return -ENODEV;
+	mutex_lock(&wl->mutex);
+	spin_lock_irqsave(&wl->irq_lock, flags);
+
+	dev = wl->current_dev;
+	err = -ENODEV;
+	if (!dev || b43_status(dev) < B43_STAT_INITIALIZED)
+		goto out_unlock;
+
+	err = -EINVAL;
 	switch (key->alg) {
 	case ALG_WEP:
 		if (key->keylen == 5)
@@ -2837,20 +2957,11 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		break;
 	default:
 		B43_WARN_ON(1);
-		goto out;
+		goto out_unlock;
 	}
-
 	index = (u8) (key->keyidx);
 	if (index > 3)
-		goto out;
-
-	mutex_lock(&wl->mutex);
-	spin_lock_irqsave(&wl->irq_lock, flags);
-
-	if (b43_status(dev) < B43_STAT_INITIALIZED) {
-		err = -ENODEV;
 		goto out_unlock;
-	}
 
 	switch (cmd) {
 	case SET_KEY:
@@ -2896,7 +3007,6 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 out_unlock:
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 	mutex_unlock(&wl->mutex);
-out:
 	if (!err) {
 		b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
 		       "mac: %s\n",
@@ -2906,9 +3016,9 @@ out:
 	return err;
 }
 
-static void b43_configure_filter(struct ieee80211_hw *hw,
-				 unsigned int changed, unsigned int *fflags,
-				 int mc_count, struct dev_addr_list *mc_list)
+static void b43_op_configure_filter(struct ieee80211_hw *hw,
+				    unsigned int changed, unsigned int *fflags,
+				    int mc_count, struct dev_addr_list *mc_list)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -2943,8 +3053,9 @@ static void b43_configure_filter(struct ieee80211_hw *hw,
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 }
 
-static int b43_config_interface(struct ieee80211_hw *hw,
-				int if_id, struct ieee80211_if_conf *conf)
+static int b43_op_config_interface(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif,
+				   struct ieee80211_if_conf *conf)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -2954,7 +3065,7 @@ static int b43_config_interface(struct ieee80211_hw *hw,
 		return -ENODEV;
 	mutex_lock(&wl->mutex);
 	spin_lock_irqsave(&wl->irq_lock, flags);
-	B43_WARN_ON(wl->if_id != if_id);
+	B43_WARN_ON(wl->vif != vif);
 	if (conf->bssid)
 		memcpy(wl->bssid, conf->bssid, ETH_ALEN);
 	else
@@ -2964,7 +3075,7 @@ static int b43_config_interface(struct ieee80211_hw *hw,
 			B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
 			b43_set_ssid(dev, conf->ssid, conf->ssid_len);
 			if (conf->beacon)
-				b43_refresh_templates(dev, conf->beacon);
+				b43_update_templates(wl, conf->beacon);
 		}
 		b43_write_mac_bssid_templates(dev);
 	}
@@ -3067,9 +3178,15 @@ static int b43_phy_versioning(struct b43_wldev *dev)
 			unsupported = 1;
 		break;
 	case B43_PHYTYPE_G:
-		if (phy_rev > 8)
+		if (phy_rev > 9)
 			unsupported = 1;
 		break;
+#ifdef CONFIG_B43_NPHY
+	case B43_PHYTYPE_N:
+		if (phy_rev > 1)
+			unsupported = 1;
+		break;
+#endif
 	default:
 		unsupported = 1;
 	};
@@ -3092,14 +3209,15 @@ static int b43_phy_versioning(struct b43_wldev *dev)
 			tmp = 0x5205017F;
 	} else {
 		b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-		tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH);
-		tmp <<= 16;
+		tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
 		b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
-		tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+		tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
 	}
 	radio_manuf = (tmp & 0x00000FFF);
 	radio_ver = (tmp & 0x0FFFF000) >> 12;
 	radio_rev = (tmp & 0xF0000000) >> 28;
+	if (radio_manuf != 0x17F /* Broadcom */)
+		unsupported = 1;
 	switch (phy_type) {
 	case B43_PHYTYPE_A:
 		if (radio_ver != 0x2060)
@@ -3117,6 +3235,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
 		if (radio_ver != 0x2050)
 			unsupported = 1;
 		break;
+	case B43_PHYTYPE_N:
+		if (radio_ver != 0x2055)
+			unsupported = 1;
+		break;
 	default:
 		B43_WARN_ON(1);
 	}
@@ -3149,9 +3271,6 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
 	memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
 	memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
 
-	/* Flags */
-	phy->locked = 0;
-
 	phy->aci_enable = 0;
 	phy->aci_wlan_automatic = 0;
 	phy->aci_hw_rssi = 0;
@@ -3178,17 +3297,22 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
 	phy->lofcal = 0xFFFF;
 	phy->initval = 0xFFFF;
 
-	spin_lock_init(&phy->lock);
 	phy->interfmode = B43_INTERFMODE_NONE;
 	phy->channel = 0xFF;
 
 	phy->hardware_power_control = !!modparam_hwpctl;
+
+	/* PHY TX errors counter. */
+	atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+
+	/* OFDM-table address caching. */
+	phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN;
 }
 
 static void setup_struct_wldev_for_init(struct b43_wldev *dev)
 {
-	/* Flags */
-	dev->reg124_set_0x4 = 0;
+	dev->dfq_valid = 0;
+
 	/* Assume the radio is enabled. If it's not enabled, the state will
 	 * immediately get fixed on the first periodic work run. */
 	dev->radio_hw_enable = 1;
@@ -3214,13 +3338,13 @@ static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
 	struct ssb_sprom *sprom = &dev->dev->bus->sprom;
 	u32 hf;
 
-	if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST))
+	if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST))
 		return;
 	if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
 		return;
 
 	hf = b43_hf_read(dev);
-	if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD)
+	if (sprom->boardflags_lo & B43_BFL_BTCMOD)
 		hf |= B43_HF_BTCOEXALT;
 	else
 		hf |= B43_HF_BTCOEX;
@@ -3259,20 +3383,42 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
 #endif /* CONFIG_SSB_DRIVER_PCICORE */
 }
 
+/* Write the short and long frame retry limit values. */
+static void b43_set_retry_limits(struct b43_wldev *dev,
+				 unsigned int short_retry,
+				 unsigned int long_retry)
+{
+	/* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+	 * the chip-internal counter. */
+	short_retry = min(short_retry, (unsigned int)0xF);
+	long_retry = min(long_retry, (unsigned int)0xF);
+
+	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT,
+			short_retry);
+	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT,
+			long_retry);
+}
+
 /* Shutdown a wireless core */
 /* Locking: wl->mutex */
 static void b43_wireless_core_exit(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
+	u32 macctl;
 
 	B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
 	if (b43_status(dev) != B43_STAT_INITIALIZED)
 		return;
 	b43_set_status(dev, B43_STAT_UNINIT);
 
+	/* Stop the microcode PSM. */
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl &= ~B43_MACCTL_PSM_RUN;
+	macctl |= B43_MACCTL_PSM_JMP0;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+
 	b43_leds_exit(dev);
 	b43_rng_exit(dev->wl);
-	b43_pio_free(dev);
 	b43_dma_free(dev);
 	b43_chip_exit(dev);
 	b43_radio_turn_off(dev, 1);
@@ -3281,6 +3427,11 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
 		kfree(phy->tssi2dbm);
 	kfree(phy->lo_control);
 	phy->lo_control = NULL;
+	if (dev->wl->current_beacon) {
+		dev_kfree_skb_any(dev->wl->current_beacon);
+		dev->wl->current_beacon = NULL;
+	}
+
 	ssb_device_disable(dev->dev, 0);
 	ssb_bus_may_powerdown(dev->dev->bus);
 }
@@ -3335,7 +3486,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 		hf |= B43_HF_SYMW;
 		if (phy->rev == 1)
 			hf |= B43_HF_GDCW;
-		if (sprom->r1.boardflags_lo & B43_BFL_PACTRL)
+		if (sprom->boardflags_lo & B43_BFL_PACTRL)
 			hf |= B43_HF_OFDMPABOOST;
 	} else if (phy->type == B43_PHYTYPE_B) {
 		hf |= B43_HF_SYMW;
@@ -3344,15 +3495,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 	}
 	b43_hf_write(dev, hf);
 
-	/* Short/Long Retry Limit.
-	 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
-	 * the chip-internal counter.
-	 */
-	tmp = limit_value(modparam_short_retry, 0, 0xF);
-	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp);
-	tmp = limit_value(modparam_long_retry, 0, 0xF);
-	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp);
-
+	b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
+			     B43_DEFAULT_LONG_RETRY_LIMIT);
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
 
@@ -3373,17 +3517,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
 	/* Maximum Contention Window */
 	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
-	do {
-		if (b43_using_pio(dev)) {
-			err = b43_pio_init(dev);
-		} else {
-			err = b43_dma_init(dev);
-			if (!err)
-				b43_qos_init(dev);
-		}
-	} while (err == -EAGAIN);
+	err = b43_dma_init(dev);
 	if (err)
 		goto err_chip_exit;
+	b43_qos_init(dev);
 
 //FIXME
 #if 1
@@ -3421,8 +3558,8 @@ out:
 	return err;
 }
 
-static int b43_add_interface(struct ieee80211_hw *hw,
-			     struct ieee80211_if_init_conf *conf)
+static int b43_op_add_interface(struct ieee80211_hw *hw,
+				struct ieee80211_if_init_conf *conf)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev;
@@ -3445,7 +3582,7 @@ static int b43_add_interface(struct ieee80211_hw *hw,
 
 	dev = wl->current_dev;
 	wl->operating = 1;
-	wl->if_id = conf->if_id;
+	wl->vif = conf->vif;
 	wl->if_type = conf->type;
 	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
 
@@ -3461,8 +3598,8 @@ static int b43_add_interface(struct ieee80211_hw *hw,
 	return err;
 }
 
-static void b43_remove_interface(struct ieee80211_hw *hw,
-				 struct ieee80211_if_init_conf *conf)
+static void b43_op_remove_interface(struct ieee80211_hw *hw,
+				    struct ieee80211_if_init_conf *conf)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -3473,7 +3610,8 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
 	mutex_lock(&wl->mutex);
 
 	B43_WARN_ON(!wl->operating);
-	B43_WARN_ON(wl->if_id != conf->if_id);
+	B43_WARN_ON(wl->vif != conf->vif);
+	wl->vif = NULL;
 
 	wl->operating = 0;
 
@@ -3486,7 +3624,7 @@ static void b43_remove_interface(struct ieee80211_hw *hw,
 	mutex_unlock(&wl->mutex);
 }
 
-static int b43_start(struct ieee80211_hw *hw)
+static int b43_op_start(struct ieee80211_hw *hw)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -3521,7 +3659,7 @@ static int b43_start(struct ieee80211_hw *hw)
 	return err;
 }
 
-static void b43_stop(struct ieee80211_hw *hw)
+static void b43_op_stop(struct ieee80211_hw *hw)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
@@ -3535,19 +3673,76 @@ static void b43_stop(struct ieee80211_hw *hw)
 	mutex_unlock(&wl->mutex);
 }
 
+static int b43_op_set_retry_limit(struct ieee80211_hw *hw,
+				  u32 short_retry_limit, u32 long_retry_limit)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev;
+	int err = 0;
+
+	mutex_lock(&wl->mutex);
+	dev = wl->current_dev;
+	if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+	b43_set_retry_limits(dev, short_retry_limit, long_retry_limit);
+out_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct sk_buff *beacon;
+	unsigned long flags;
+
+	/* We could modify the existing beacon and set the aid bit in
+	 * the TIM field, but that would probably require resizing and
+	 * moving of data within the beacon template.
+	 * Simply request a new beacon and let mac80211 do the hard work. */
+	beacon = ieee80211_beacon_get(hw, wl->vif, NULL);
+	if (unlikely(!beacon))
+		return -ENOMEM;
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43_update_templates(wl, beacon);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	return 0;
+}
+
+static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
+				     struct sk_buff *beacon,
+				     struct ieee80211_tx_control *ctl)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43_update_templates(wl, beacon);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	return 0;
+}
+
 static const struct ieee80211_ops b43_hw_ops = {
-	.tx = b43_tx,
-	.conf_tx = b43_conf_tx,
-	.add_interface = b43_add_interface,
-	.remove_interface = b43_remove_interface,
-	.config = b43_dev_config,
-	.config_interface = b43_config_interface,
-	.configure_filter = b43_configure_filter,
-	.set_key = b43_dev_set_key,
-	.get_stats = b43_get_stats,
-	.get_tx_stats = b43_get_tx_stats,
-	.start = b43_start,
-	.stop = b43_stop,
+	.tx			= b43_op_tx,
+	.conf_tx		= b43_op_conf_tx,
+	.add_interface		= b43_op_add_interface,
+	.remove_interface	= b43_op_remove_interface,
+	.config			= b43_op_config,
+	.config_interface	= b43_op_config_interface,
+	.configure_filter	= b43_op_configure_filter,
+	.set_key		= b43_op_set_key,
+	.get_stats		= b43_op_get_stats,
+	.get_tx_stats		= b43_op_get_tx_stats,
+	.start			= b43_op_start,
+	.stop			= b43_op_stop,
+	.set_retry_limit	= b43_op_set_retry_limit,
+	.set_tim		= b43_op_beacon_set_tim,
+	.beacon_update		= b43_op_ibss_beacon_update,
 };
 
 /* Hard-reset the chip. Do not call this directly.
@@ -3592,72 +3787,30 @@ static void b43_chip_reset(struct work_struct *work)
 }
 
 static int b43_setup_modes(struct b43_wldev *dev,
-			   int have_aphy, int have_bphy, int have_gphy)
+			   bool have_2ghz_phy, bool have_5ghz_phy)
 {
 	struct ieee80211_hw *hw = dev->wl->hw;
 	struct ieee80211_hw_mode *mode;
 	struct b43_phy *phy = &dev->phy;
-	int cnt = 0;
 	int err;
 
-/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */
-	have_aphy = 0;
-
-	phy->possible_phymodes = 0;
-	for (; 1; cnt++) {
-		if (have_aphy) {
-			B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-			mode = &phy->hwmodes[cnt];
-
-			mode->mode = MODE_IEEE80211A;
-			mode->num_channels = b43_a_chantable_size;
-			mode->channels = b43_a_chantable;
-			mode->num_rates = b43_a_ratetable_size;
-			mode->rates = b43_a_ratetable;
-			err = ieee80211_register_hwmode(hw, mode);
-			if (err)
-				return err;
-
-			phy->possible_phymodes |= B43_PHYMODE_A;
-			have_aphy = 0;
-			continue;
-		}
-		if (have_bphy) {
-			B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-			mode = &phy->hwmodes[cnt];
-
-			mode->mode = MODE_IEEE80211B;
-			mode->num_channels = b43_bg_chantable_size;
-			mode->channels = b43_bg_chantable;
-			mode->num_rates = b43_b_ratetable_size;
-			mode->rates = b43_b_ratetable;
-			err = ieee80211_register_hwmode(hw, mode);
-			if (err)
-				return err;
-
-			phy->possible_phymodes |= B43_PHYMODE_B;
-			have_bphy = 0;
-			continue;
-		}
-		if (have_gphy) {
-			B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
-			mode = &phy->hwmodes[cnt];
-
-			mode->mode = MODE_IEEE80211G;
-			mode->num_channels = b43_bg_chantable_size;
-			mode->channels = b43_bg_chantable;
-			mode->num_rates = b43_g_ratetable_size;
-			mode->rates = b43_g_ratetable;
-			err = ieee80211_register_hwmode(hw, mode);
-			if (err)
-				return err;
-
-			phy->possible_phymodes |= B43_PHYMODE_G;
-			have_gphy = 0;
-			continue;
-		}
-		break;
-	}
+	/* XXX: This function will go away soon, when mac80211
+	 *      band stuff is rewritten. So this is just a hack.
+	 *      For now we always claim GPHY mode, as there is no
+	 *      support for NPHY and APHY in the device, yet.
+	 *      This assumption is OK, as any B, N or A PHY will already
+	 *      have died a horrible sanity check death earlier. */
+
+	mode = &phy->hwmodes[0];
+	mode->mode = MODE_IEEE80211G;
+	mode->num_channels = b43_2ghz_chantable_size;
+	mode->channels = b43_2ghz_chantable;
+	mode->num_rates = b43_g_ratetable_size;
+	mode->rates = b43_g_ratetable;
+	err = ieee80211_register_hwmode(hw, mode);
+	if (err)
+		return err;
+	phy->possible_phymodes |= B43_PHYMODE_G;
 
 	return 0;
 }
@@ -3675,7 +3828,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 	struct ssb_bus *bus = dev->dev->bus;
 	struct pci_dev *pdev = bus->host_pci;
 	int err;
-	int have_aphy = 0, have_bphy = 0, have_gphy = 0;
+	bool have_2ghz_phy = 0, have_5ghz_phy = 0;
 	u32 tmp;
 
 	/* Do NOT do any device initialization here.
@@ -3695,17 +3848,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 		u32 tmshigh;
 
 		tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
-		have_aphy = !!(tmshigh & B43_TMSHIGH_APHY);
-		have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY);
-		if (!have_aphy && !have_gphy)
-			have_bphy = 1;
-	} else if (dev->dev->id.revision == 4) {
-		have_gphy = 1;
-		have_aphy = 1;
+		have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
+		have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
 	} else
-		have_bphy = 1;
+		B43_WARN_ON(1);
 
-	dev->phy.gmode = (have_gphy || have_bphy);
+	dev->phy.gmode = have_2ghz_phy;
 	tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
 	b43_wireless_core_reset(dev, tmp);
 
@@ -3717,31 +3865,34 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 	    (pdev->device != 0x4312 &&
 	     pdev->device != 0x4319 && pdev->device != 0x4324)) {
 		/* No multiband support. */
-		have_aphy = 0;
-		have_bphy = 0;
-		have_gphy = 0;
+		have_2ghz_phy = 0;
+		have_5ghz_phy = 0;
 		switch (dev->phy.type) {
 		case B43_PHYTYPE_A:
-			have_aphy = 1;
-			break;
-		case B43_PHYTYPE_B:
-			have_bphy = 1;
+			have_5ghz_phy = 1;
 			break;
 		case B43_PHYTYPE_G:
-			have_gphy = 1;
+		case B43_PHYTYPE_N:
+			have_2ghz_phy = 1;
 			break;
 		default:
 			B43_WARN_ON(1);
 		}
 	}
-	dev->phy.gmode = (have_gphy || have_bphy);
+	if (dev->phy.type == B43_PHYTYPE_A) {
+		/* FIXME */
+		b43err(wl, "IEEE 802.11a devices are unsupported\n");
+		err = -EOPNOTSUPP;
+		goto err_powerdown;
+	}
+	dev->phy.gmode = have_2ghz_phy;
 	tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
 	b43_wireless_core_reset(dev, tmp);
 
 	err = b43_validate_chipaccess(dev);
 	if (err)
 		goto err_powerdown;
-	err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy);
+	err = b43_setup_modes(dev, have_2ghz_phy, have_5ghz_phy);
 	if (err)
 		goto err_powerdown;
 
@@ -3812,8 +3963,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
 	tasklet_init(&wldev->isr_tasklet,
 		     (void (*)(unsigned long))b43_interrupt_tasklet,
 		     (unsigned long)wldev);
-	if (modparam_pio)
-		wldev->__using_pio = 1;
 	INIT_LIST_HEAD(&wldev->list);
 
 	err = b43_wireless_core_attach(wldev);
@@ -3838,20 +3987,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
 	/* boardflags workarounds */
 	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
 	    bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
-		bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST;
+		bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
 	if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
 	    bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
-		bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL;
-
-	/* Handle case when gain is not set in sprom */
-	if (bus->sprom.r1.antenna_gain_a == 0xFF)
-		bus->sprom.r1.antenna_gain_a = 2;
-	if (bus->sprom.r1.antenna_gain_bg == 0xFF)
-		bus->sprom.r1.antenna_gain_bg = 2;
-
-	/* Convert Antennagain values to Q5.2 */
-	bus->sprom.r1.antenna_gain_a <<= 2;
-	bus->sprom.r1.antenna_gain_bg <<= 2;
+		bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
 }
 
 static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
@@ -3878,16 +4017,17 @@ static int b43_wireless_init(struct ssb_device *dev)
 	}
 
 	/* fill hw info */
-	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+		    IEEE80211_HW_RX_INCLUDES_FCS;
 	hw->max_signal = 100;
 	hw->max_rssi = -110;
 	hw->max_noise = -110;
 	hw->queues = 1;		/* FIXME: hardware has more queues */
 	SET_IEEE80211_DEV(hw, dev->dev);
-	if (is_valid_ether_addr(sprom->r1.et1mac))
-		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+	if (is_valid_ether_addr(sprom->et1mac))
+		SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
 	else
-		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+		SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
 
 	/* Get and initialize struct b43_wl */
 	wl = hw_to_b43_wl(hw);
@@ -3895,6 +4035,7 @@ static int b43_wireless_init(struct ssb_device *dev)
 	wl->hw = hw;
 	spin_lock_init(&wl->irq_lock);
 	spin_lock_init(&wl->leds_lock);
+	spin_lock_init(&wl->shm_lock);
 	mutex_init(&wl->mutex);
 	INIT_LIST_HEAD(&wl->devlist);
 
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index 08e2e56e48f4..2d52d9de9305 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-                     Stefano Brivio <st3@riseup.net>
+                     Stefano Brivio <stefano.brivio@polimi.it>
                      Michael Buesch <mb@bu3sch.de>
                      Danny van Dyk <kugelfang@gentoo.org>
                      Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -84,6 +84,9 @@ static inline int b43_is_ofdm_rate(int rate)
 	return !b43_is_cck_rate(rate);
 }
 
+u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
+				  u8 antenna_nr);
+
 void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
 void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
 
diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c
new file mode 100644
index 000000000000..705131ef4bfa
--- /dev/null
+++ b/drivers/net/wireless/b43/nphy.c
@@ -0,0 +1,489 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n PHY support
+
+  Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include "b43.h"
+#include "nphy.h"
+#include "tables_nphy.h"
+
+#include <linux/delay.h>
+
+
+void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
+{//TODO
+}
+
+void b43_nphy_xmitpower(struct b43_wldev *dev)
+{//TODO
+}
+
+static void b43_chantab_radio_upload(struct b43_wldev *dev,
+				     const struct b43_nphy_channeltab_entry *e)
+{
+	b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref);
+	b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
+	b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
+	b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail);
+	b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1);
+	b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2);
+	b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1);
+	b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1);
+	b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2);
+	b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
+	b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
+	b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
+	b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
+	b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
+	b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
+	b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
+	b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
+	b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
+	b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
+	b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
+	b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
+	b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
+}
+
+static void b43_chantab_phy_upload(struct b43_wldev *dev,
+				   const struct b43_nphy_channeltab_entry *e)
+{
+	b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a);
+	b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2);
+	b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3);
+	b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4);
+	b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5);
+	b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6);
+}
+
+static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
+{
+	//TODO
+}
+
+/* Tune the hardware to a new channel. Don't call this directly.
+ * Use b43_radio_selectchannel() */
+int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel)
+{
+	const struct b43_nphy_channeltab_entry *tabent;
+
+	tabent = b43_nphy_get_chantabent(dev, channel);
+	if (!tabent)
+		return -ESRCH;
+
+	//FIXME enable/disable band select upper20 in RXCTL
+	if (0 /*FIXME 5Ghz*/)
+		b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20);
+	else
+		b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50);
+	b43_chantab_radio_upload(dev, tabent);
+	udelay(50);
+	b43_radio_write16(dev, B2055_VCO_CAL10, 5);
+	b43_radio_write16(dev, B2055_VCO_CAL10, 45);
+	b43_radio_write16(dev, B2055_VCO_CAL10, 65);
+	udelay(300);
+	if (0 /*FIXME 5Ghz*/)
+		b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
+	else
+		b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
+	b43_chantab_phy_upload(dev, tabent);
+	b43_nphy_tx_power_fix(dev);
+
+	return 0;
+}
+
+static void b43_radio_init2055_pre(struct b43_wldev *dev)
+{
+	b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+		     ~B43_NPHY_RFCTL_CMD_PORFORCE);
+	b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+		    B43_NPHY_RFCTL_CMD_CHIP0PU |
+		    B43_NPHY_RFCTL_CMD_OEPORFORCE);
+	b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+		    B43_NPHY_RFCTL_CMD_PORFORCE);
+}
+
+static void b43_radio_init2055_post(struct b43_wldev *dev)
+{
+	struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+	struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo);
+	int i;
+	u16 val;
+
+	b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
+	msleep(1);
+	if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) {
+		if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) ||
+		    (binfo->type != 0x46D) ||
+		    (binfo->rev < 0x41)) {
+			b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
+			b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
+			msleep(1);
+		}
+	}
+	b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C);
+	msleep(1);
+	b43_radio_write16(dev, B2055_CAL_MISC, 0x3C);
+	msleep(1);
+	b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE);
+	msleep(1);
+	b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80);
+	msleep(1);
+	b43_radio_set(dev, B2055_CAL_MISC, 0x1);
+	msleep(1);
+	b43_radio_set(dev, B2055_CAL_MISC, 0x40);
+	msleep(1);
+	for (i = 0; i < 100; i++) {
+		val = b43_radio_read16(dev, B2055_CAL_COUT2);
+		if (val & 0x80)
+			break;
+		udelay(10);
+	}
+	msleep(1);
+	b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
+	msleep(1);
+	b43_radio_selectchannel(dev, dev->phy.channel, 0);
+	b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9);
+	b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9);
+	b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
+	b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83);
+}
+
+/* Initialize a Broadcom 2055 N-radio */
+static void b43_radio_init2055(struct b43_wldev *dev)
+{
+	b43_radio_init2055_pre(dev);
+	if (b43_status(dev) < B43_STAT_INITIALIZED)
+		b2055_upload_inittab(dev, 0, 1);
+	else
+		b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0);
+	b43_radio_init2055_post(dev);
+}
+
+void b43_nphy_radio_turn_on(struct b43_wldev *dev)
+{
+	b43_radio_init2055(dev);
+}
+
+void b43_nphy_radio_turn_off(struct b43_wldev *dev)
+{
+	b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+		     ~B43_NPHY_RFCTL_CMD_EN);
+}
+
+#define ntab_upload(dev, offset, data) do { \
+		unsigned int i;						\
+		for (i = 0; i < (offset##_SIZE); i++)			\
+			b43_ntab_write(dev, (offset) + i, (data)[i]);	\
+	} while (0)
+
+/* Upload the N-PHY tables. */
+static void b43_nphy_tables_init(struct b43_wldev *dev)
+{
+	/* Static tables */
+	ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
+	ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup);
+	ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap);
+	ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn);
+	ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel);
+	ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot);
+	ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt);
+	ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0);
+	ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1);
+	ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0);
+	ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1);
+	ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi);
+	ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest);
+	ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs);
+
+	/* Volatile tables */
+	ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10);
+	ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11);
+	ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0);
+	ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1);
+	ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0);
+	ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1);
+	ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0);
+	ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1);
+	ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0);
+	ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1);
+	ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0);
+	ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
+}
+
+static void b43_nphy_workarounds(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	unsigned int i;
+
+	b43_phy_set(dev, B43_NPHY_IQFLIP,
+		    B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
+	//FIXME the following condition is different in the specs.
+	if (1 /* FIXME band is 2.4GHz */) {
+		b43_phy_set(dev, B43_NPHY_CLASSCTL,
+			    B43_NPHY_CLASSCTL_CCKEN);
+	} else {
+		b43_phy_mask(dev, B43_NPHY_CLASSCTL,
+			     ~B43_NPHY_CLASSCTL_CCKEN);
+	}
+	b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8);
+	b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8);
+
+	/* Fixup some tables */
+	b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800);
+	b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800);
+
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+	b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+
+	//TODO set RF sequence
+
+	/* Set narrowband clip threshold */
+	b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66);
+	b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66);
+
+	/* Set wideband clip 2 threshold */
+	b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
+			~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
+			21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT);
+	b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
+			~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
+			21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT);
+
+	/* Set Clip 2 detect */
+	b43_phy_set(dev, B43_NPHY_C1_CGAINI,
+		    B43_NPHY_C1_CGAINI_CL2DETECT);
+	b43_phy_set(dev, B43_NPHY_C2_CGAINI,
+		    B43_NPHY_C2_CGAINI_CL2DETECT);
+
+	if (0 /*FIXME*/) {
+		/* Set dwell lengths */
+		b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43);
+		b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43);
+		b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9);
+		b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9);
+
+		/* Set gain backoff */
+		b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
+				~B43_NPHY_C1_CGAINI_GAINBKOFF,
+				1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT);
+		b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
+				~B43_NPHY_C2_CGAINI_GAINBKOFF,
+				1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT);
+
+		/* Set HPVGA2 index */
+		b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
+				~B43_NPHY_C1_INITGAIN_HPVGA2,
+				6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
+		b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
+				~B43_NPHY_C2_INITGAIN_HPVGA2,
+				6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+
+		//FIXME verify that the specs really mean to use autoinc here.
+		for (i = 0; i < 3; i++)
+			b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673);
+	}
+
+	/* Set minimum gain value */
+	b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN,
+			~B43_NPHY_C1_MINGAIN,
+			23 << B43_NPHY_C1_MINGAIN_SHIFT);
+	b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN,
+			~B43_NPHY_C2_MINGAIN,
+			23 << B43_NPHY_C2_MINGAIN_SHIFT);
+
+	if (phy->rev < 2) {
+		b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL,
+			     ~B43_NPHY_SCRAM_SIGCTL_SCM);
+	}
+
+	/* Set phase track alpha and beta */
+	b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125);
+	b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3);
+	b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105);
+	b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E);
+	b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
+	b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
+}
+
+static void b43_nphy_reset_cca(struct b43_wldev *dev)
+{
+	u16 bbcfg;
+
+	ssb_write32(dev->dev, SSB_TMSLOW,
+		    ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC);
+	bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
+	b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA);
+	b43_phy_write(dev, B43_NPHY_BBCFG,
+		      bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
+	ssb_write32(dev->dev, SSB_TMSLOW,
+		    ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC);
+}
+
+enum b43_nphy_rf_sequence {
+	B43_RFSEQ_RX2TX,
+	B43_RFSEQ_TX2RX,
+	B43_RFSEQ_RESET2RX,
+	B43_RFSEQ_UPDATE_GAINH,
+	B43_RFSEQ_UPDATE_GAINL,
+	B43_RFSEQ_UPDATE_GAINU,
+};
+
+static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
+				       enum b43_nphy_rf_sequence seq)
+{
+	static const u16 trigger[] = {
+		[B43_RFSEQ_RX2TX]		= B43_NPHY_RFSEQTR_RX2TX,
+		[B43_RFSEQ_TX2RX]		= B43_NPHY_RFSEQTR_TX2RX,
+		[B43_RFSEQ_RESET2RX]		= B43_NPHY_RFSEQTR_RST2RX,
+		[B43_RFSEQ_UPDATE_GAINH]	= B43_NPHY_RFSEQTR_UPGH,
+		[B43_RFSEQ_UPDATE_GAINL]	= B43_NPHY_RFSEQTR_UPGL,
+		[B43_RFSEQ_UPDATE_GAINU]	= B43_NPHY_RFSEQTR_UPGU,
+	};
+	int i;
+
+	B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
+
+	b43_phy_set(dev, B43_NPHY_RFSEQMODE,
+		    B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER);
+	b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]);
+	for (i = 0; i < 200; i++) {
+		if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq]))
+			goto ok;
+		msleep(1);
+	}
+	b43err(dev->wl, "RF sequence status timeout\n");
+ok:
+	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+		     ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER));
+}
+
+static void b43_nphy_bphy_init(struct b43_wldev *dev)
+{
+	unsigned int i;
+	u16 val;
+
+	val = 0x1E1F;
+	for (i = 0; i < 14; i++) {
+		b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
+		val -= 0x202;
+	}
+	val = 0x3E3F;
+	for (i = 0; i < 16; i++) {
+		b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val);
+		val -= 0x202;
+	}
+	b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
+}
+
+/* RSSI Calibration */
+static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type)
+{
+	//TODO
+}
+
+int b43_phy_initn(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 tmp;
+
+	//TODO: Spectral management
+	b43_nphy_tables_init(dev);
+
+	/* Clear all overrides */
+	b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0);
+	b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0);
+	b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+		     ~(B43_NPHY_RFSEQMODE_CAOVER |
+		       B43_NPHY_RFSEQMODE_TROVER));
+	b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0);
+
+	tmp = (phy->rev < 2) ? 64 : 59;
+	b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+			~B43_NPHY_BPHY_CTL3_SCALE,
+			tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT);
+
+	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
+	b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
+
+	b43_phy_write(dev, B43_NPHY_TXREALFD, 184);
+	b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200);
+	b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80);
+	b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511);
+
+	//TODO MIMO-Config
+	//TODO Update TX/RX chain
+
+	if (phy->rev < 2) {
+		b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8);
+		b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4);
+	}
+	b43_nphy_workarounds(dev);
+	b43_nphy_reset_cca(dev);
+
+	ssb_write32(dev->dev, SSB_TMSLOW,
+		    ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN);
+	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
+	b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+
+	b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */
+	//TODO read core1/2 clip1 thres regs
+
+	if (1 /* FIXME Band is 2.4GHz */)
+		b43_nphy_bphy_init(dev);
+	//TODO disable TX power control
+	//TODO Fix the TX power settings
+	//TODO Init periodic calibration with reason 3
+	b43_nphy_rssi_cal(dev, 2);
+	b43_nphy_rssi_cal(dev, 0);
+	b43_nphy_rssi_cal(dev, 1);
+	//TODO get TX gain
+	//TODO init superswitch
+	//TODO calibrate LO
+	//TODO idle TSSI TX pctl
+	//TODO TX power control power setup
+	//TODO table writes
+	//TODO TX power control coefficients
+	//TODO enable TX power control
+	//TODO control antenna selection
+	//TODO init radar detection
+	//TODO reset channel if changed
+
+	b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n");
+	return 0;
+}
diff --git a/drivers/net/wireless/b43/nphy.h b/drivers/net/wireless/b43/nphy.h
new file mode 100644
index 000000000000..5d95118b8193
--- /dev/null
+++ b/drivers/net/wireless/b43/nphy.h
@@ -0,0 +1,932 @@
+#ifndef B43_NPHY_H_
+#define B43_NPHY_H_
+
+#include "phy.h"
+
+
+/* N-PHY registers. */
+
+#define B43_NPHY_BBCFG				B43_PHY_N(0x001) /* BB config */
+#define  B43_NPHY_BBCFG_RSTCCA			0x4000 /* Reset CCA */
+#define  B43_NPHY_BBCFG_RSTRX			0x8000 /* Reset RX */
+#define B43_NPHY_CHANNEL			B43_PHY_N(0x005) /* Channel */
+#define B43_NPHY_TXERR				B43_PHY_N(0x007) /* TX error */
+#define B43_NPHY_BANDCTL			B43_PHY_N(0x009) /* Band control */
+#define  B43_NPHY_BANDCTL_5GHZ			0x0001 /* Use the 5GHz band */
+#define B43_NPHY_4WI_ADDR			B43_PHY_N(0x00B) /* Four-wire bus address */
+#define B43_NPHY_4WI_DATAHI			B43_PHY_N(0x00C) /* Four-wire bus data high */
+#define B43_NPHY_4WI_DATALO			B43_PHY_N(0x00D) /* Four-wire bus data low */
+#define B43_NPHY_BIST_STAT0			B43_PHY_N(0x00E) /* Built-in self test status 0 */
+#define B43_NPHY_BIST_STAT1			B43_PHY_N(0x00F) /* Built-in self test status 1 */
+
+#define B43_NPHY_C1_DESPWR			B43_PHY_N(0x018) /* Core 1 desired power */
+#define B43_NPHY_C1_CCK_DESPWR			B43_PHY_N(0x019) /* Core 1 CCK desired power */
+#define B43_NPHY_C1_BCLIPBKOFF			B43_PHY_N(0x01A) /* Core 1 barely clip backoff */
+#define B43_NPHY_C1_CCK_BCLIPBKOFF		B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */
+#define B43_NPHY_C1_CGAINI			B43_PHY_N(0x01C) /* Core 1 compute gain info */
+#define  B43_NPHY_C1_CGAINI_GAINBKOFF		0x001F /* Gain backoff */
+#define  B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT	0
+#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF		0x03E0 /* Clip gain backoff */
+#define  B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT	5
+#define  B43_NPHY_C1_CGAINI_GAINSTEP		0x1C00 /* Gain step */
+#define  B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT	10
+#define  B43_NPHY_C1_CGAINI_CL2DETECT		0x2000 /* Clip 2 detect mask */
+#define B43_NPHY_C1_CCK_CGAINI			B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */
+#define  B43_NPHY_C1_CCK_CGAINI_GAINBKOFF	0x001F /* Gain backoff */
+#define  B43_NPHY_C1_CCK_CGAINI_CLIPGBKOFF	0x01E0 /* CCK barely clip gain backoff */
+#define B43_NPHY_C1_MINMAX_GAIN			B43_PHY_N(0x01E) /* Core 1 min/max gain */
+#define  B43_NPHY_C1_MINGAIN			0x00FF /* Minimum gain */
+#define  B43_NPHY_C1_MINGAIN_SHIFT		0
+#define  B43_NPHY_C1_MAXGAIN			0xFF00 /* Maximum gain */
+#define  B43_NPHY_C1_MAXGAIN_SHIFT		8
+#define B43_NPHY_C1_CCK_MINMAX_GAIN		B43_PHY_N(0x01F) /* Core 1 CCK min/max gain */
+#define  B43_NPHY_C1_CCK_MINGAIN		0x00FF /* Minimum gain */
+#define  B43_NPHY_C1_CCK_MINGAIN_SHIFT		0
+#define  B43_NPHY_C1_CCK_MAXGAIN		0xFF00 /* Maximum gain */
+#define  B43_NPHY_C1_CCK_MAXGAIN_SHIFT		8
+#define B43_NPHY_C1_INITGAIN			B43_PHY_N(0x020) /* Core 1 initial gain code */
+#define  B43_NPHY_C1_INITGAIN_EXTLNA		0x0001 /* External LNA index */
+#define  B43_NPHY_C1_INITGAIN_LNA		0x0006 /* LNA index */
+#define  B43_NPHY_C1_INITGAIN_LNAIDX_SHIFT	1
+#define  B43_NPHY_C1_INITGAIN_HPVGA1		0x0078 /* HPVGA1 index */
+#define  B43_NPHY_C1_INITGAIN_HPVGA1_SHIFT	3
+#define  B43_NPHY_C1_INITGAIN_HPVGA2		0x0F80 /* HPVGA2 index */
+#define  B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT	7
+#define  B43_NPHY_C1_INITGAIN_TRRX		0x1000 /* TR RX index */
+#define  B43_NPHY_C1_INITGAIN_TRTX		0x2000 /* TR TX index */
+#define B43_NPHY_C1_CLIP1_HIGAIN		B43_PHY_N(0x021) /* Core 1 clip1 high gain code */
+#define B43_NPHY_C1_CLIP1_MEDGAIN		B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */
+#define B43_NPHY_C1_CLIP1_LOGAIN		B43_PHY_N(0x023) /* Core 1 clip1 low gain code */
+#define B43_NPHY_C1_CLIP2_GAIN			B43_PHY_N(0x024) /* Core 1 clip2 gain code */
+#define B43_NPHY_C1_FILTERGAIN			B43_PHY_N(0x025) /* Core 1 filter gain */
+#define B43_NPHY_C1_LPF_QHPF_BW			B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */
+#define B43_NPHY_C1_CLIPWBTHRES			B43_PHY_N(0x027) /* Core 1 clip wideband threshold */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2		0x003F /* Clip 2 */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT	0
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1		0x0FC0 /* Clip 1 */
+#define  B43_NPHY_C1_CLIPWBTHRES_CLIP1_SHIFT	6
+#define B43_NPHY_C1_W1THRES			B43_PHY_N(0x028) /* Core 1 W1 threshold */
+#define B43_NPHY_C1_EDTHRES			B43_PHY_N(0x029) /* Core 1 ED threshold */
+#define B43_NPHY_C1_SMSIGTHRES			B43_PHY_N(0x02A) /* Core 1 small sig threshold */
+#define B43_NPHY_C1_NBCLIPTHRES			B43_PHY_N(0x02B) /* Core 1 NB clip threshold */
+#define B43_NPHY_C1_CLIP1THRES			B43_PHY_N(0x02C) /* Core 1 clip1 threshold */
+#define B43_NPHY_C1_CLIP2THRES			B43_PHY_N(0x02D) /* Core 1 clip2 threshold */
+
+#define B43_NPHY_C2_DESPWR			B43_PHY_N(0x02E) /* Core 2 desired power */
+#define B43_NPHY_C2_CCK_DESPWR			B43_PHY_N(0x02F) /* Core 2 CCK desired power */
+#define B43_NPHY_C2_BCLIPBKOFF			B43_PHY_N(0x030) /* Core 2 barely clip backoff */
+#define B43_NPHY_C2_CCK_BCLIPBKOFF		B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */
+#define B43_NPHY_C2_CGAINI			B43_PHY_N(0x032) /* Core 2 compute gain info */
+#define  B43_NPHY_C2_CGAINI_GAINBKOFF		0x001F /* Gain backoff */
+#define  B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT	0
+#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF		0x03E0 /* Clip gain backoff */
+#define  B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT	5
+#define  B43_NPHY_C2_CGAINI_GAINSTEP		0x1C00 /* Gain step */
+#define  B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT	10
+#define  B43_NPHY_C2_CGAINI_CL2DETECT		0x2000 /* Clip 2 detect mask */
+#define B43_NPHY_C2_CCK_CGAINI			B43_PHY_N(0x033) /* Core 2 CCK compute gain info */
+#define  B43_NPHY_C2_CCK_CGAINI_GAINBKOFF	0x001F /* Gain backoff */
+#define  B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF	0x01E0 /* CCK barely clip gain backoff */
+#define B43_NPHY_C2_MINMAX_GAIN			B43_PHY_N(0x034) /* Core 2 min/max gain */
+#define  B43_NPHY_C2_MINGAIN			0x00FF /* Minimum gain */
+#define  B43_NPHY_C2_MINGAIN_SHIFT		0
+#define  B43_NPHY_C2_MAXGAIN			0xFF00 /* Maximum gain */
+#define  B43_NPHY_C2_MAXGAIN_SHIFT		8
+#define B43_NPHY_C2_CCK_MINMAX_GAIN		B43_PHY_N(0x035) /* Core 2 CCK min/max gain */
+#define  B43_NPHY_C2_CCK_MINGAIN		0x00FF /* Minimum gain */
+#define  B43_NPHY_C2_CCK_MINGAIN_SHIFT		0
+#define  B43_NPHY_C2_CCK_MAXGAIN		0xFF00 /* Maximum gain */
+#define  B43_NPHY_C2_CCK_MAXGAIN_SHIFT		8
+#define B43_NPHY_C2_INITGAIN			B43_PHY_N(0x036) /* Core 2 initial gain code */
+#define  B43_NPHY_C2_INITGAIN_EXTLNA		0x0001 /* External LNA index */
+#define  B43_NPHY_C2_INITGAIN_LNA		0x0006 /* LNA index */
+#define  B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT	1
+#define  B43_NPHY_C2_INITGAIN_HPVGA1		0x0078 /* HPVGA1 index */
+#define  B43_NPHY_C2_INITGAIN_HPVGA1_SHIFT	3
+#define  B43_NPHY_C2_INITGAIN_HPVGA2		0x0F80 /* HPVGA2 index */
+#define  B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT	7
+#define  B43_NPHY_C2_INITGAIN_TRRX		0x1000 /* TR RX index */
+#define  B43_NPHY_C2_INITGAIN_TRTX		0x2000 /* TR TX index */
+#define B43_NPHY_C2_CLIP1_HIGAIN		B43_PHY_N(0x037) /* Core 2 clip1 high gain code */
+#define B43_NPHY_C2_CLIP1_MEDGAIN		B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */
+#define B43_NPHY_C2_CLIP1_LOGAIN		B43_PHY_N(0x039) /* Core 2 clip1 low gain code */
+#define B43_NPHY_C2_CLIP2_GAIN			B43_PHY_N(0x03A) /* Core 2 clip2 gain code */
+#define B43_NPHY_C2_FILTERGAIN			B43_PHY_N(0x03B) /* Core 2 filter gain */
+#define B43_NPHY_C2_LPF_QHPF_BW			B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */
+#define B43_NPHY_C2_CLIPWBTHRES			B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2		0x003F /* Clip 2 */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT	0
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1		0x0FC0 /* Clip 1 */
+#define  B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT	6
+#define B43_NPHY_C2_W1THRES			B43_PHY_N(0x03E) /* Core 2 W1 threshold */
+#define B43_NPHY_C2_EDTHRES			B43_PHY_N(0x03F) /* Core 2 ED threshold */
+#define B43_NPHY_C2_SMSIGTHRES			B43_PHY_N(0x040) /* Core 2 small sig threshold */
+#define B43_NPHY_C2_NBCLIPTHRES			B43_PHY_N(0x041) /* Core 2 NB clip threshold */
+#define B43_NPHY_C2_CLIP1THRES			B43_PHY_N(0x042) /* Core 2 clip1 threshold */
+#define B43_NPHY_C2_CLIP2THRES			B43_PHY_N(0x043) /* Core 2 clip2 threshold */
+
+#define B43_NPHY_CRS_THRES1			B43_PHY_N(0x044) /* CRS threshold 1 */
+#define B43_NPHY_CRS_THRES2			B43_PHY_N(0x045) /* CRS threshold 2 */
+#define B43_NPHY_CRS_THRES3			B43_PHY_N(0x046) /* CRS threshold 3 */
+#define B43_NPHY_CRSCTL				B43_PHY_N(0x047) /* CRS control */
+#define B43_NPHY_DCFADDR			B43_PHY_N(0x048) /* DC filter address */
+#define B43_NPHY_RXF20_NUM0			B43_PHY_N(0x049) /* RX filter 20 numerator 0 */
+#define B43_NPHY_RXF20_NUM1			B43_PHY_N(0x04A) /* RX filter 20 numerator 1 */
+#define B43_NPHY_RXF20_NUM2			B43_PHY_N(0x04B) /* RX filter 20 numerator 2 */
+#define B43_NPHY_RXF20_DENOM0			B43_PHY_N(0x04C) /* RX filter 20 denominator 0 */
+#define B43_NPHY_RXF20_DENOM1			B43_PHY_N(0x04D) /* RX filter 20 denominator 1 */
+#define B43_NPHY_RXF20_NUM10			B43_PHY_N(0x04E) /* RX filter 20 numerator 10 */
+#define B43_NPHY_RXF20_NUM11			B43_PHY_N(0x04F) /* RX filter 20 numerator 11 */
+#define B43_NPHY_RXF20_NUM12			B43_PHY_N(0x050) /* RX filter 20 numerator 12 */
+#define B43_NPHY_RXF20_DENOM10			B43_PHY_N(0x051) /* RX filter 20 denominator 10 */
+#define B43_NPHY_RXF20_DENOM11			B43_PHY_N(0x052) /* RX filter 20 denominator 11 */
+#define B43_NPHY_RXF40_NUM0			B43_PHY_N(0x053) /* RX filter 40 numerator 0 */
+#define B43_NPHY_RXF40_NUM1			B43_PHY_N(0x054) /* RX filter 40 numerator 1 */
+#define B43_NPHY_RXF40_NUM2			B43_PHY_N(0x055) /* RX filter 40 numerator 2 */
+#define B43_NPHY_RXF40_DENOM0			B43_PHY_N(0x056) /* RX filter 40 denominator 0 */
+#define B43_NPHY_RXF40_DENOM1			B43_PHY_N(0x057) /* RX filter 40 denominator 1 */
+#define B43_NPHY_RXF40_NUM10			B43_PHY_N(0x058) /* RX filter 40 numerator 10 */
+#define B43_NPHY_RXF40_NUM11			B43_PHY_N(0x059) /* RX filter 40 numerator 11 */
+#define B43_NPHY_RXF40_NUM12			B43_PHY_N(0x05A) /* RX filter 40 numerator 12 */
+#define B43_NPHY_RXF40_DENOM10			B43_PHY_N(0x05B) /* RX filter 40 denominator 10 */
+#define B43_NPHY_RXF40_DENOM11			B43_PHY_N(0x05C) /* RX filter 40 denominator 11 */
+#define B43_NPHY_PPROC_RSTLEN			B43_PHY_N(0x060) /* Packet processing reset length */
+#define B43_NPHY_INITCARR_DLEN			B43_PHY_N(0x061) /* Initial carrier detection length */
+#define B43_NPHY_CLIP1CARR_DLEN			B43_PHY_N(0x062) /* Clip1 carrier detection length */
+#define B43_NPHY_CLIP2CARR_DLEN			B43_PHY_N(0x063) /* Clip2 carrier detection length */
+#define B43_NPHY_INITGAIN_SLEN			B43_PHY_N(0x064) /* Initial gain settle length */
+#define B43_NPHY_CLIP1GAIN_SLEN			B43_PHY_N(0x065) /* Clip1 gain settle length */
+#define B43_NPHY_CLIP2GAIN_SLEN			B43_PHY_N(0x066) /* Clip2 gain settle length */
+#define B43_NPHY_PACKGAIN_SLEN			B43_PHY_N(0x067) /* Packet gain settle length */
+#define B43_NPHY_CARRSRC_TLEN			B43_PHY_N(0x068) /* Carrier search timeout length */
+#define B43_NPHY_TISRC_TLEN			B43_PHY_N(0x069) /* Timing search timeout length */
+#define B43_NPHY_ENDROP_TLEN			B43_PHY_N(0x06A) /* Energy drop timeout length */
+#define B43_NPHY_CLIP1_NBDWELL_LEN		B43_PHY_N(0x06B) /* Clip1 NB dwell length */
+#define B43_NPHY_CLIP2_NBDWELL_LEN		B43_PHY_N(0x06C) /* Clip2 NB dwell length */
+#define B43_NPHY_W1CLIP1_DWELL_LEN		B43_PHY_N(0x06D) /* W1 clip1 dwell length */
+#define B43_NPHY_W1CLIP2_DWELL_LEN		B43_PHY_N(0x06E) /* W1 clip2 dwell length */
+#define B43_NPHY_W2CLIP1_DWELL_LEN		B43_PHY_N(0x06F) /* W2 clip1 dwell length */
+#define B43_NPHY_PLOAD_CSENSE_EXTLEN		B43_PHY_N(0x070) /* Payload carrier sense extension length */
+#define B43_NPHY_EDROP_CSENSE_EXTLEN		B43_PHY_N(0x071) /* Energy drop carrier sense extension length */
+#define B43_NPHY_TABLE_ADDR			B43_PHY_N(0x072) /* Table address */
+#define B43_NPHY_TABLE_DATALO			B43_PHY_N(0x073) /* Table data low */
+#define B43_NPHY_TABLE_DATAHI			B43_PHY_N(0x074) /* Table data high */
+#define B43_NPHY_WWISE_LENIDX			B43_PHY_N(0x075) /* WWiSE length index */
+#define B43_NPHY_TGNSYNC_LENIDX			B43_PHY_N(0x076) /* TGNsync length index */
+#define B43_NPHY_TXMACIF_HOLDOFF		B43_PHY_N(0x077) /* TX MAC IF Hold off */
+#define B43_NPHY_RFCTL_CMD			B43_PHY_N(0x078) /* RF control (command) */
+#define  B43_NPHY_RFCTL_CMD_START		0x0001 /* Start sequence */
+#define  B43_NPHY_RFCTL_CMD_RXTX		0x0002 /* RX/TX */
+#define  B43_NPHY_RFCTL_CMD_CORESEL		0x0038 /* Core select */
+#define  B43_NPHY_RFCTL_CMD_CORESEL_SHIFT	3
+#define  B43_NPHY_RFCTL_CMD_PORFORCE		0x0040 /* POR force */
+#define  B43_NPHY_RFCTL_CMD_OEPORFORCE		0x0080 /* OE POR force */
+#define  B43_NPHY_RFCTL_CMD_RXEN		0x0100 /* RX enable */
+#define  B43_NPHY_RFCTL_CMD_TXEN		0x0200 /* TX enable */
+#define  B43_NPHY_RFCTL_CMD_CHIP0PU		0x0400 /* Chip0 PU */
+#define  B43_NPHY_RFCTL_CMD_EN			0x0800 /* Radio enabled */
+#define  B43_NPHY_RFCTL_CMD_SEQENCORE		0xF000 /* Seq en core */
+#define  B43_NPHY_RFCTL_CMD_SEQENCORE_SHIFT	12
+#define B43_NPHY_RFCTL_RSSIO1			B43_PHY_N(0x07A) /* RF control (RSSI others 1) */
+#define  B43_NPHY_RFCTL_RSSIO1_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO1_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO1_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO1_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO1_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO1_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO1_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG1			B43_PHY_N(0x07B) /* RF control (RX gain 1) */
+#define B43_NPHY_RFCTL_TXG1			B43_PHY_N(0x07C) /* RF control (TX gain 1) */
+#define B43_NPHY_RFCTL_RSSIO2			B43_PHY_N(0x07D) /* RF control (RSSI others 2) */
+#define  B43_NPHY_RFCTL_RSSIO2_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO2_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO2_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO2_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO2_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO2_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO2_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG2			B43_PHY_N(0x07E) /* RF control (RX gain 2) */
+#define B43_NPHY_RFCTL_TXG2			B43_PHY_N(0x07F) /* RF control (TX gain 2) */
+#define B43_NPHY_RFCTL_RSSIO3			B43_PHY_N(0x080) /* RF control (RSSI others 3) */
+#define  B43_NPHY_RFCTL_RSSIO3_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO3_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO3_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO3_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO3_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO3_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO3_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG3			B43_PHY_N(0x081) /* RF control (RX gain 3) */
+#define B43_NPHY_RFCTL_TXG3			B43_PHY_N(0x082) /* RF control (TX gain 3) */
+#define B43_NPHY_RFCTL_RSSIO4			B43_PHY_N(0x083) /* RF control (RSSI others 4) */
+#define  B43_NPHY_RFCTL_RSSIO4_RXPD		0x0001 /* RX PD */
+#define  B43_NPHY_RFCTL_RSSIO4_TXPD		0x0002 /* TX PD */
+#define  B43_NPHY_RFCTL_RSSIO4_PAPD		0x0004 /* PA PD */
+#define  B43_NPHY_RFCTL_RSSIO4_RSSICTL		0x0030 /* RSSI control */
+#define  B43_NPHY_RFCTL_RSSIO4_LPFBW		0x00C0 /* LPF bandwidth */
+#define  B43_NPHY_RFCTL_RSSIO4_HPFBWHI		0x0100 /* HPF bandwidth high */
+#define  B43_NPHY_RFCTL_RSSIO4_HIQDISCO		0x0200 /* HIQ dis core */
+#define B43_NPHY_RFCTL_RXG4			B43_PHY_N(0x084) /* RF control (RX gain 4) */
+#define B43_NPHY_RFCTL_TXG4			B43_PHY_N(0x085) /* RF control (TX gain 4) */
+#define B43_NPHY_C1_TXIQ_COMP_OFF		B43_PHY_N(0x087) /* Core 1 TX I/Q comp offset */
+#define B43_NPHY_C2_TXIQ_COMP_OFF		B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */
+#define B43_NPHY_C1_TXCTL			B43_PHY_N(0x08B) /* Core 1 TX control */
+#define B43_NPHY_C2_TXCTL			B43_PHY_N(0x08C) /* Core 2 TX control */
+#define B43_NPHY_SCRAM_SIGCTL			B43_PHY_N(0x090) /* Scram signal control */
+#define  B43_NPHY_SCRAM_SIGCTL_INITST		0x007F /* Initial state value */
+#define  B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT	0
+#define  B43_NPHY_SCRAM_SIGCTL_SCM		0x0080 /* Scram control mode */
+#define  B43_NPHY_SCRAM_SIGCTL_SICE		0x0100 /* Scram index control enable */
+#define  B43_NPHY_SCRAM_SIGCTL_START		0xFE00 /* Scram start bit */
+#define  B43_NPHY_SCRAM_SIGCTL_START_SHIFT	9
+#define B43_NPHY_RFCTL_INTC1			B43_PHY_N(0x091) /* RF control (intc 1) */
+#define B43_NPHY_RFCTL_INTC2			B43_PHY_N(0x092) /* RF control (intc 2) */
+#define B43_NPHY_RFCTL_INTC3			B43_PHY_N(0x093) /* RF control (intc 3) */
+#define B43_NPHY_RFCTL_INTC4			B43_PHY_N(0x094) /* RF control (intc 4) */
+#define B43_NPHY_NRDTO_WWISE			B43_PHY_N(0x095) /* # datatones WWiSE */
+#define B43_NPHY_NRDTO_TGNSYNC			B43_PHY_N(0x096) /* # datatones TGNsync */
+#define B43_NPHY_SIGFMOD_WWISE			B43_PHY_N(0x097) /* Signal field mod WWiSE */
+#define B43_NPHY_LEG_SIGFMOD_11N		B43_PHY_N(0x098) /* Legacy signal field mod 11n */
+#define B43_NPHY_HT_SIGFMOD_11N			B43_PHY_N(0x099) /* HT signal field mod 11n */
+#define B43_NPHY_C1_RXIQ_COMPA0			B43_PHY_N(0x09A) /* Core 1 RX I/Q comp A0 */
+#define B43_NPHY_C1_RXIQ_COMPB0			B43_PHY_N(0x09B) /* Core 1 RX I/Q comp B0 */
+#define B43_NPHY_C2_RXIQ_COMPA1			B43_PHY_N(0x09C) /* Core 2 RX I/Q comp A1 */
+#define B43_NPHY_C2_RXIQ_COMPB1			B43_PHY_N(0x09D) /* Core 2 RX I/Q comp B1 */
+#define B43_NPHY_RXCTL				B43_PHY_N(0x0A0) /* RX control */
+#define  B43_NPHY_RXCTL_BSELU20			0x0010 /* Band select upper 20 */
+#define  B43_NPHY_RXCTL_RIFSEN			0x0080 /* RIFS enable */
+#define B43_NPHY_RFSEQMODE			B43_PHY_N(0x0A1) /* RF seq mode */
+#define  B43_NPHY_RFSEQMODE_CAOVER		0x0001 /* Core active override */
+#define  B43_NPHY_RFSEQMODE_TROVER		0x0002 /* Trigger override */
+#define B43_NPHY_RFSEQCA			B43_PHY_N(0x0A2) /* RF seq core active */
+#define  B43_NPHY_RFSEQCA_TXEN			0x000F /* TX enable */
+#define  B43_NPHY_RFSEQCA_TXEN_SHIFT		0
+#define  B43_NPHY_RFSEQCA_RXEN			0x00F0 /* RX enable */
+#define  B43_NPHY_RFSEQCA_RXEN_SHIFT		4
+#define  B43_NPHY_RFSEQCA_TXDIS			0x0F00 /* TX disable */
+#define  B43_NPHY_RFSEQCA_TXDIS_SHIFT		8
+#define  B43_NPHY_RFSEQCA_RXDIS			0xF000 /* RX disable */
+#define  B43_NPHY_RFSEQCA_RXDIS_SHIFT		12
+#define B43_NPHY_RFSEQTR			B43_PHY_N(0x0A3) /* RF seq trigger */
+#define  B43_NPHY_RFSEQTR_RX2TX			0x0001 /* RX2TX */
+#define  B43_NPHY_RFSEQTR_TX2RX			0x0002 /* TX2RX */
+#define  B43_NPHY_RFSEQTR_UPGH			0x0004 /* Update gain H */
+#define  B43_NPHY_RFSEQTR_UPGL			0x0008 /* Update gain L */
+#define  B43_NPHY_RFSEQTR_UPGU			0x0010 /* Update gain U */
+#define  B43_NPHY_RFSEQTR_RST2RX		0x0020 /* Reset to RX */
+#define B43_NPHY_RFSEQST			B43_PHY_N(0x0A4) /* RF seq status. Values same as trigger. */
+#define B43_NPHY_AFECTL_OVER			B43_PHY_N(0x0A5) /* AFE control override */
+#define B43_NPHY_AFECTL_C1			B43_PHY_N(0x0A6) /* AFE control core 1 */
+#define B43_NPHY_AFECTL_C2			B43_PHY_N(0x0A7) /* AFE control core 2 */
+#define B43_NPHY_AFECTL_C3			B43_PHY_N(0x0A8) /* AFE control core 3 */
+#define B43_NPHY_AFECTL_C4			B43_PHY_N(0x0A9) /* AFE control core 4 */
+#define B43_NPHY_AFECTL_DACGAIN1		B43_PHY_N(0x0AA) /* AFE control DAC gain 1 */
+#define B43_NPHY_AFECTL_DACGAIN2		B43_PHY_N(0x0AB) /* AFE control DAC gain 2 */
+#define B43_NPHY_AFECTL_DACGAIN3		B43_PHY_N(0x0AC) /* AFE control DAC gain 3 */
+#define B43_NPHY_AFECTL_DACGAIN4		B43_PHY_N(0x0AD) /* AFE control DAC gain 4 */
+#define B43_NPHY_STR_ADDR1			B43_PHY_N(0x0AE) /* STR address 1 */
+#define B43_NPHY_STR_ADDR2			B43_PHY_N(0x0AF) /* STR address 2 */
+#define B43_NPHY_CLASSCTL			B43_PHY_N(0x0B0) /* Classifier control */
+#define  B43_NPHY_CLASSCTL_CCKEN		0x0001 /* CCK enable */
+#define  B43_NPHY_CLASSCTL_OFDMEN		0x0002 /* OFDM enable */
+#define  B43_NPHY_CLASSCTL_WAITEDEN		0x0004 /* Waited enable */
+#define B43_NPHY_IQFLIP				B43_PHY_N(0x0B1) /* I/Q flip */
+#define  B43_NPHY_IQFLIP_ADC1			0x0001 /* ADC1 */
+#define  B43_NPHY_IQFLIP_ADC2			0x0010 /* ADC2 */
+#define B43_NPHY_SISO_SNR_THRES			B43_PHY_N(0x0B2) /* SISO SNR threshold */
+#define B43_NPHY_SIGMA_N_MULT			B43_PHY_N(0x0B3) /* Sigma N multiplier */
+#define B43_NPHY_TXMACDELAY			B43_PHY_N(0x0B4) /* TX MAC delay */
+#define B43_NPHY_TXFRAMEDELAY			B43_PHY_N(0x0B5) /* TX frame delay */
+#define B43_NPHY_MLPARM				B43_PHY_N(0x0B6) /* ML parameters */
+#define B43_NPHY_MLCTL				B43_PHY_N(0x0B7) /* ML control */
+#define B43_NPHY_WWISE_20NCYCDAT		B43_PHY_N(0x0B8) /* WWiSE 20 N cyc data */
+#define B43_NPHY_WWISE_40NCYCDAT		B43_PHY_N(0x0B9) /* WWiSE 40 N cyc data */
+#define B43_NPHY_TGNSYNC_20NCYCDAT		B43_PHY_N(0x0BA) /* TGNsync 20 N cyc data */
+#define B43_NPHY_TGNSYNC_40NCYCDAT		B43_PHY_N(0x0BB) /* TGNsync 40 N cyc data */
+#define B43_NPHY_INITSWIZP			B43_PHY_N(0x0BC) /* Initial swizzle pattern */
+#define B43_NPHY_TXTAILCNT			B43_PHY_N(0x0BD) /* TX tail count value */
+#define B43_NPHY_BPHY_CTL1			B43_PHY_N(0x0BE) /* B PHY control 1 */
+#define B43_NPHY_BPHY_CTL2			B43_PHY_N(0x0BF) /* B PHY control 2 */
+#define  B43_NPHY_BPHY_CTL2_LUT			0x001F /* LUT index */
+#define  B43_NPHY_BPHY_CTL2_LUT_SHIFT		0
+#define  B43_NPHY_BPHY_CTL2_MACDEL		0x7FE0 /* MAC delay */
+#define  B43_NPHY_BPHY_CTL2_MACDEL_SHIFT	5
+#define B43_NPHY_IQLOCAL_CMD			B43_PHY_N(0x0C0) /* I/Q LO cal command */
+#define  B43_NPHY_IQLOCAL_CMD_EN		0x8000
+#define B43_NPHY_IQLOCAL_CMDNNUM		B43_PHY_N(0x0C1) /* I/Q LO cal command N num */
+#define B43_NPHY_IQLOCAL_CMDGCTL		B43_PHY_N(0x0C2) /* I/Q LO cal command G control */
+#define B43_NPHY_SAMP_CMD			B43_PHY_N(0x0C3) /* Sample command */
+#define  B43_NPHY_SAMP_CMD_STOP			0x0002 /* Stop */
+#define B43_NPHY_SAMP_LOOPCNT			B43_PHY_N(0x0C4) /* Sample loop count */
+#define B43_NPHY_SAMP_WAITCNT			B43_PHY_N(0x0C5) /* Sample wait count */
+#define B43_NPHY_SAMP_DEPCNT			B43_PHY_N(0x0C6) /* Sample depth count */
+#define B43_NPHY_SAMP_STAT			B43_PHY_N(0x0C7) /* Sample status */
+#define B43_NPHY_GPIO_LOOEN			B43_PHY_N(0x0C8) /* GPIO low out enable */
+#define B43_NPHY_GPIO_HIOEN			B43_PHY_N(0x0C9) /* GPIO high out enable */
+#define B43_NPHY_GPIO_SEL			B43_PHY_N(0x0CA) /* GPIO select */
+#define B43_NPHY_GPIO_CLKCTL			B43_PHY_N(0x0CB) /* GPIO clock control */
+#define B43_NPHY_TXF_20CO_AS0			B43_PHY_N(0x0CC) /* TX filter 20 coeff A stage 0 */
+#define B43_NPHY_TXF_20CO_AS1			B43_PHY_N(0x0CD) /* TX filter 20 coeff A stage 1 */
+#define B43_NPHY_TXF_20CO_AS2			B43_PHY_N(0x0CE) /* TX filter 20 coeff A stage 2 */
+#define B43_NPHY_TXF_20CO_B32S0			B43_PHY_N(0x0CF) /* TX filter 20 coeff B32 stage 0 */
+#define B43_NPHY_TXF_20CO_B1S0			B43_PHY_N(0x0D0) /* TX filter 20 coeff B1 stage 0 */
+#define B43_NPHY_TXF_20CO_B32S1			B43_PHY_N(0x0D1) /* TX filter 20 coeff B32 stage 1 */
+#define B43_NPHY_TXF_20CO_B1S1			B43_PHY_N(0x0D2) /* TX filter 20 coeff B1 stage 1 */
+#define B43_NPHY_TXF_20CO_B32S2			B43_PHY_N(0x0D3) /* TX filter 20 coeff B32 stage 2 */
+#define B43_NPHY_TXF_20CO_B1S2			B43_PHY_N(0x0D4) /* TX filter 20 coeff B1 stage 2 */
+#define B43_NPHY_SIGFLDTOL			B43_PHY_N(0x0D5) /* Signal fld tolerance */
+#define B43_NPHY_TXSERFLD			B43_PHY_N(0x0D6) /* TX service field */
+#define B43_NPHY_AFESEQ_RX2TX_PUD		B43_PHY_N(0x0D7) /* AFE seq RX2TX power up/down delay */
+#define B43_NPHY_AFESEQ_TX2RX_PUD		B43_PHY_N(0x0D8) /* AFE seq TX2RX power up/down delay */
+#define B43_NPHY_TGNSYNC_SCRAMI0		B43_PHY_N(0x0D9) /* TGNsync scram init 0 */
+#define B43_NPHY_TGNSYNC_SCRAMI1		B43_PHY_N(0x0DA) /* TGNsync scram init 1 */
+#define B43_NPHY_INITSWIZPATTLEG		B43_PHY_N(0x0DB) /* Initial swizzle pattern leg */
+#define B43_NPHY_BPHY_CTL3			B43_PHY_N(0x0DC) /* B PHY control 3 */
+#define  B43_NPHY_BPHY_CTL3_SCALE		0x00FF /* Scale */
+#define  B43_NPHY_BPHY_CTL3_SCALE_SHIFT		0
+#define  B43_NPHY_BPHY_CTL3_FSC			0xFF00 /* Frame start count value */
+#define  B43_NPHY_BPHY_CTL3_FSC_SHIFT		8
+#define B43_NPHY_BPHY_CTL4			B43_PHY_N(0x0DD) /* B PHY control 4 */
+#define B43_NPHY_C1_TXBBMULT			B43_PHY_N(0x0DE) /* Core 1 TX BB multiplier */
+#define B43_NPHY_C2_TXBBMULT			B43_PHY_N(0x0DF) /* Core 2 TX BB multiplier */
+#define B43_NPHY_TXF_40CO_AS0			B43_PHY_N(0x0E1) /* TX filter 40 coeff A stage 0 */
+#define B43_NPHY_TXF_40CO_AS1			B43_PHY_N(0x0E2) /* TX filter 40 coeff A stage 1 */
+#define B43_NPHY_TXF_40CO_AS2			B43_PHY_N(0x0E3) /* TX filter 40 coeff A stage 2 */
+#define B43_NPHY_TXF_40CO_B32S0			B43_PHY_N(0x0E4) /* TX filter 40 coeff B32 stage 0 */
+#define B43_NPHY_TXF_40CO_B1S0			B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */
+#define B43_NPHY_TXF_40CO_B32S1			B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */
+#define B43_NPHY_TXF_40CO_B1S1			B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */
+#define B43_NPHY_TXF_40CO_B32S2			B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */
+#define B43_NPHY_TXF_40CO_B1S2			B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */
+#define B43_NPHY_BIST_STAT2			B43_PHY_N(0x0EA) /* BIST status 2 */
+#define B43_NPHY_BIST_STAT3			B43_PHY_N(0x0EB) /* BIST status 3 */
+#define B43_NPHY_RFCTL_OVER			B43_PHY_N(0x0EC) /* RF control override */
+#define B43_NPHY_MIMOCFG			B43_PHY_N(0x0ED) /* MIMO config */
+#define  B43_NPHY_MIMOCFG_GFMIX			0x0004 /* Greenfield or mixed mode */
+#define  B43_NPHY_MIMOCFG_AUTO			0x0100 /* Greenfield/mixed mode auto */
+#define B43_NPHY_RADAR_BLNKCTL			B43_PHY_N(0x0EE) /* Radar blank control */
+#define B43_NPHY_A0RADAR_FIFOCTL		B43_PHY_N(0x0EF) /* Antenna 0 radar FIFO control */
+#define B43_NPHY_A1RADAR_FIFOCTL		B43_PHY_N(0x0F0) /* Antenna 1 radar FIFO control */
+#define B43_NPHY_A0RADAR_FIFODAT		B43_PHY_N(0x0F1) /* Antenna 0 radar FIFO data */
+#define B43_NPHY_A1RADAR_FIFODAT		B43_PHY_N(0x0F2) /* Antenna 1 radar FIFO data */
+#define B43_NPHY_RADAR_THRES0			B43_PHY_N(0x0F3) /* Radar threshold 0 */
+#define B43_NPHY_RADAR_THRES1			B43_PHY_N(0x0F4) /* Radar threshold 1 */
+#define B43_NPHY_RADAR_THRES0R			B43_PHY_N(0x0F5) /* Radar threshold 0R */
+#define B43_NPHY_RADAR_THRES1R			B43_PHY_N(0x0F6) /* Radar threshold 1R */
+#define B43_NPHY_CSEN_20IN40_DLEN		B43_PHY_N(0x0F7) /* Carrier sense 20 in 40 dwell length */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO1		B43_PHY_N(0x0F8) /* RF control LUT TRSW lower 1 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP1		B43_PHY_N(0x0F9) /* RF control LUT TRSW upper 1 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO2		B43_PHY_N(0x0FA) /* RF control LUT TRSW lower 2 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP2		B43_PHY_N(0x0FB) /* RF control LUT TRSW upper 2 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO3		B43_PHY_N(0x0FC) /* RF control LUT TRSW lower 3 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP3		B43_PHY_N(0x0FD) /* RF control LUT TRSW upper 3 */
+#define B43_NPHY_RFCTL_LUT_TRSW_LO4		B43_PHY_N(0x0FE) /* RF control LUT TRSW lower 4 */
+#define B43_NPHY_RFCTL_LUT_TRSW_UP4		B43_PHY_N(0x0FF) /* RF control LUT TRSW upper 4 */
+#define B43_NPHY_RFCTL_LUT_LNAPA1		B43_PHY_N(0x100) /* RF control LUT LNA PA 1 */
+#define B43_NPHY_RFCTL_LUT_LNAPA2		B43_PHY_N(0x101) /* RF control LUT LNA PA 2 */
+#define B43_NPHY_RFCTL_LUT_LNAPA3		B43_PHY_N(0x102) /* RF control LUT LNA PA 3 */
+#define B43_NPHY_RFCTL_LUT_LNAPA4		B43_PHY_N(0x103) /* RF control LUT LNA PA 4 */
+#define B43_NPHY_TGNSYNC_CRCM0			B43_PHY_N(0x104) /* TGNsync CRC mask 0 */
+#define B43_NPHY_TGNSYNC_CRCM1			B43_PHY_N(0x105) /* TGNsync CRC mask 1 */
+#define B43_NPHY_TGNSYNC_CRCM2			B43_PHY_N(0x106) /* TGNsync CRC mask 2 */
+#define B43_NPHY_TGNSYNC_CRCM3			B43_PHY_N(0x107) /* TGNsync CRC mask 3 */
+#define B43_NPHY_TGNSYNC_CRCM4			B43_PHY_N(0x108) /* TGNsync CRC mask 4 */
+#define B43_NPHY_CRCPOLY			B43_PHY_N(0x109) /* CRC polynomial */
+#define B43_NPHY_SIGCNT				B43_PHY_N(0x10A) /* # sig count */
+#define B43_NPHY_SIGSTARTBIT_CTL		B43_PHY_N(0x10B) /* Sig start bit control */
+#define B43_NPHY_CRCPOLY_ORDER			B43_PHY_N(0x10C) /* CRC polynomial order */
+#define B43_NPHY_RFCTL_CST0			B43_PHY_N(0x10D) /* RF control core swap table 0 */
+#define B43_NPHY_RFCTL_CST1			B43_PHY_N(0x10E) /* RF control core swap table 1 */
+#define B43_NPHY_RFCTL_CST2O			B43_PHY_N(0x10F) /* RF control core swap table 2 + others */
+#define B43_NPHY_BPHY_CTL5			B43_PHY_N(0x111) /* B PHY control 5 */
+#define B43_NPHY_RFSEQ_LPFBW			B43_PHY_N(0x112) /* RF seq LPF bandwidth */
+#define B43_NPHY_TSSIBIAS1			B43_PHY_N(0x114) /* TSSI bias val 1 */
+#define B43_NPHY_TSSIBIAS2			B43_PHY_N(0x115) /* TSSI bias val 2 */
+#define  B43_NPHY_TSSIBIAS_BIAS			0x00FF /* Bias */
+#define  B43_NPHY_TSSIBIAS_BIAS_SHIFT		0
+#define  B43_NPHY_TSSIBIAS_VAL			0xFF00 /* Value */
+#define  B43_NPHY_TSSIBIAS_VAL_SHIFT		8
+#define B43_NPHY_ESTPWR1			B43_PHY_N(0x118) /* Estimated power 1 */
+#define B43_NPHY_ESTPWR2			B43_PHY_N(0x119) /* Estimated power 2 */
+#define  B43_NPHY_ESTPWR_PWR			0x00FF /* Estimated power */
+#define  B43_NPHY_ESTPWR_PWR_SHIFT		0
+#define  B43_NPHY_ESTPWR_VALID			0x0100 /* Estimated power valid */
+#define B43_NPHY_TSSI_MAXTXFDT			B43_PHY_N(0x11C) /* TSSI max TX frame delay time */
+#define  B43_NPHY_TSSI_MAXTXFDT_VAL		0x00FF /* max TX frame delay time */
+#define  B43_NPHY_TSSI_MAXTXFDT_VAL_SHIFT	0
+#define B43_NPHY_TSSI_MAXTDT			B43_PHY_N(0x11D) /* TSSI max TSSI delay time */
+#define  B43_NPHY_TSSI_MAXTDT_VAL		0x00FF /* max TSSI delay time */
+#define  B43_NPHY_TSSI_MAXTDT_VAL_SHIFT		0
+#define B43_NPHY_ITSSI1				B43_PHY_N(0x11E) /* TSSI idle 1 */
+#define B43_NPHY_ITSSI2				B43_PHY_N(0x11F) /* TSSI idle 2 */
+#define  B43_NPHY_ITSSI_VAL			0x00FF /* Idle TSSI */
+#define  B43_NPHY_ITSSI_VAL_SHIFT		0
+#define B43_NPHY_TSSIMODE			B43_PHY_N(0x122) /* TSSI mode */
+#define  B43_NPHY_TSSIMODE_EN			0x0001 /* TSSI enable */
+#define  B43_NPHY_TSSIMODE_PDEN			0x0002 /* Power det enable */
+#define B43_NPHY_RXMACIFM			B43_PHY_N(0x123) /* RX Macif mode */
+#define B43_NPHY_CRSIT_COCNT_LO			B43_PHY_N(0x124) /* CRS idle time CRS-on count (low) */
+#define B43_NPHY_CRSIT_COCNT_HI			B43_PHY_N(0x125) /* CRS idle time CRS-on count (high) */
+#define B43_NPHY_CRSIT_MTCNT_LO			B43_PHY_N(0x126) /* CRS idle time measure time count (low) */
+#define B43_NPHY_CRSIT_MTCNT_HI			B43_PHY_N(0x127) /* CRS idle time measure time count (high) */
+#define B43_NPHY_SAMTWC				B43_PHY_N(0x128) /* Sample tail wait count */
+#define B43_NPHY_IQEST_CMD			B43_PHY_N(0x129) /* I/Q estimate command */
+#define  B43_NPHY_IQEST_CMD_START		0x0001 /* Start */
+#define  B43_NPHY_IQEST_CMD_MODE		0x0002 /* Mode */
+#define B43_NPHY_IQEST_WT			B43_PHY_N(0x12A) /* I/Q estimate wait time */
+#define  B43_NPHY_IQEST_WT_VAL			0x00FF /* Wait time */
+#define  B43_NPHY_IQEST_WT_VAL_SHIFT		0
+#define B43_NPHY_IQEST_SAMCNT			B43_PHY_N(0x12B) /* I/Q estimate sample count */
+#define B43_NPHY_IQEST_IQACC_LO0		B43_PHY_N(0x12C) /* I/Q estimate I/Q acc lo 0 */
+#define B43_NPHY_IQEST_IQACC_HI0		B43_PHY_N(0x12D) /* I/Q estimate I/Q acc hi 0 */
+#define B43_NPHY_IQEST_IPACC_LO0		B43_PHY_N(0x12E) /* I/Q estimate I power acc lo 0 */
+#define B43_NPHY_IQEST_IPACC_HI0		B43_PHY_N(0x12F) /* I/Q estimate I power acc hi 0 */
+#define B43_NPHY_IQEST_QPACC_LO0		B43_PHY_N(0x130) /* I/Q estimate Q power acc lo 0 */
+#define B43_NPHY_IQEST_QPACC_HI0		B43_PHY_N(0x131) /* I/Q estimate Q power acc hi 0 */
+#define B43_NPHY_IQEST_IQACC_LO1		B43_PHY_N(0x134) /* I/Q estimate I/Q acc lo 1 */
+#define B43_NPHY_IQEST_IQACC_HI1		B43_PHY_N(0x135) /* I/Q estimate I/Q acc hi 1 */
+#define B43_NPHY_IQEST_IPACC_LO1		B43_PHY_N(0x136) /* I/Q estimate I power acc lo 1 */
+#define B43_NPHY_IQEST_IPACC_HI1		B43_PHY_N(0x137) /* I/Q estimate I power acc hi 1 */
+#define B43_NPHY_IQEST_QPACC_LO1		B43_PHY_N(0x138) /* I/Q estimate Q power acc lo 1 */
+#define B43_NPHY_IQEST_QPACC_HI1		B43_PHY_N(0x139) /* I/Q estimate Q power acc hi 1 */
+#define B43_NPHY_MIMO_CRSTXEXT			B43_PHY_N(0x13A) /* MIMO PHY CRS TX extension */
+#define B43_NPHY_PWRDET1			B43_PHY_N(0x13B) /* Power det 1 */
+#define B43_NPHY_PWRDET2			B43_PHY_N(0x13C) /* Power det 2 */
+#define B43_NPHY_MAXRSSI_DTIME			B43_PHY_N(0x13F) /* RSSI max RSSI delay time */
+#define B43_NPHY_PIL_DW0			B43_PHY_N(0x141) /* Pilot data weight 0 */
+#define B43_NPHY_PIL_DW1			B43_PHY_N(0x142) /* Pilot data weight 1 */
+#define B43_NPHY_PIL_DW2			B43_PHY_N(0x143) /* Pilot data weight 2 */
+#define  B43_NPHY_PIL_DW_BPSK			0x000F /* BPSK */
+#define  B43_NPHY_PIL_DW_BPSK_SHIFT		0
+#define  B43_NPHY_PIL_DW_QPSK			0x00F0 /* QPSK */
+#define  B43_NPHY_PIL_DW_QPSK_SHIFT		4
+#define  B43_NPHY_PIL_DW_16QAM			0x0F00 /* 16-QAM */
+#define  B43_NPHY_PIL_DW_16QAM_SHIFT		8
+#define  B43_NPHY_PIL_DW_64QAM			0xF000 /* 64-QAM */
+#define  B43_NPHY_PIL_DW_64QAM_SHIFT		12
+#define B43_NPHY_FMDEM_CFG			B43_PHY_N(0x144) /* FM demodulation config */
+#define B43_NPHY_PHASETR_A0			B43_PHY_N(0x145) /* Phase track alpha 0 */
+#define B43_NPHY_PHASETR_A1			B43_PHY_N(0x146) /* Phase track alpha 1 */
+#define B43_NPHY_PHASETR_A2			B43_PHY_N(0x147) /* Phase track alpha 2 */
+#define B43_NPHY_PHASETR_B0			B43_PHY_N(0x148) /* Phase track beta 0 */
+#define B43_NPHY_PHASETR_B1			B43_PHY_N(0x149) /* Phase track beta 1 */
+#define B43_NPHY_PHASETR_B2			B43_PHY_N(0x14A) /* Phase track beta 2 */
+#define B43_NPHY_PHASETR_CHG0			B43_PHY_N(0x14B) /* Phase track change 0 */
+#define B43_NPHY_PHASETR_CHG1			B43_PHY_N(0x14C) /* Phase track change 1 */
+#define B43_NPHY_PHASETW_OFF			B43_PHY_N(0x14D) /* Phase track offset */
+#define B43_NPHY_RFCTL_DBG			B43_PHY_N(0x14E) /* RF control debug */
+#define B43_NPHY_CCK_SHIFTB_REF			B43_PHY_N(0x150) /* CCK shiftbits reference var */
+#define B43_NPHY_OVER_DGAIN0			B43_PHY_N(0x152) /* Override digital gain 0 */
+#define B43_NPHY_OVER_DGAIN1			B43_PHY_N(0x153) /* Override digital gain 1 */
+#define  B43_NPHY_OVER_DGAIN_FDGV		0x0007 /* Force digital gain value */
+#define  B43_NPHY_OVER_DGAIN_FDGV_SHIFT		0
+#define  B43_NPHY_OVER_DGAIN_FDGEN		0x0008 /* Force digital gain enable */
+#define  B43_NPHY_OVER_DGAIN_CCKDGECV		0xFF00 /* CCK digital gain enable count value */
+#define  B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT	8
+#define B43_NPHY_BIST_STAT4			B43_PHY_N(0x156) /* BIST status 4 */
+#define B43_NPHY_RADAR_MAL			B43_PHY_N(0x157) /* Radar MA length */
+#define B43_NPHY_RADAR_SRCCTL			B43_PHY_N(0x158) /* Radar search control */
+#define B43_NPHY_VLD_DTSIG			B43_PHY_N(0x159) /* VLD data tones sig */
+#define B43_NPHY_VLD_DTDAT			B43_PHY_N(0x15A) /* VLD data tones data */
+#define B43_NPHY_C1_BPHY_RXIQCA0		B43_PHY_N(0x15B) /* Core 1 B PHY RX I/Q comp A0 */
+#define B43_NPHY_C1_BPHY_RXIQCB0		B43_PHY_N(0x15C) /* Core 1 B PHY RX I/Q comp B0 */
+#define B43_NPHY_C2_BPHY_RXIQCA1		B43_PHY_N(0x15D) /* Core 2 B PHY RX I/Q comp A1 */
+#define B43_NPHY_C2_BPHY_RXIQCB1		B43_PHY_N(0x15E) /* Core 2 B PHY RX I/Q comp B1 */
+#define B43_NPHY_FREQGAIN0			B43_PHY_N(0x160) /* Frequency gain 0 */
+#define B43_NPHY_FREQGAIN1			B43_PHY_N(0x161) /* Frequency gain 1 */
+#define B43_NPHY_FREQGAIN2			B43_PHY_N(0x162) /* Frequency gain 2 */
+#define B43_NPHY_FREQGAIN3			B43_PHY_N(0x163) /* Frequency gain 3 */
+#define B43_NPHY_FREQGAIN4			B43_PHY_N(0x164) /* Frequency gain 4 */
+#define B43_NPHY_FREQGAIN5			B43_PHY_N(0x165) /* Frequency gain 5 */
+#define B43_NPHY_FREQGAIN6			B43_PHY_N(0x166) /* Frequency gain 6 */
+#define B43_NPHY_FREQGAIN7			B43_PHY_N(0x167) /* Frequency gain 7 */
+#define B43_NPHY_FREQGAIN_BYPASS		B43_PHY_N(0x168) /* Frequency gain bypass */
+#define B43_NPHY_TRLOSS				B43_PHY_N(0x169) /* TR loss value */
+#define B43_NPHY_C1_ADCCLIP			B43_PHY_N(0x16A) /* Core 1 ADC clip */
+#define B43_NPHY_C2_ADCCLIP			B43_PHY_N(0x16B) /* Core 2 ADC clip */
+#define B43_NPHY_LTRN_OFFGAIN			B43_PHY_N(0x16F) /* LTRN offset gain */
+#define B43_NPHY_LTRN_OFF			B43_PHY_N(0x170) /* LTRN offset */
+#define B43_NPHY_NRDATAT_WWISE20SIG		B43_PHY_N(0x171) /* # data tones WWiSE 20 sig */
+#define B43_NPHY_NRDATAT_WWISE40SIG		B43_PHY_N(0x172) /* # data tones WWiSE 40 sig */
+#define B43_NPHY_NRDATAT_TGNSYNC20SIG		B43_PHY_N(0x173) /* # data tones TGNsync 20 sig */
+#define B43_NPHY_NRDATAT_TGNSYNC40SIG		B43_PHY_N(0x174) /* # data tones TGNsync 40 sig */
+#define B43_NPHY_WWISE_CRCM0			B43_PHY_N(0x175) /* WWiSE CRC mask 0 */
+#define B43_NPHY_WWISE_CRCM1			B43_PHY_N(0x176) /* WWiSE CRC mask 1 */
+#define B43_NPHY_WWISE_CRCM2			B43_PHY_N(0x177) /* WWiSE CRC mask 2 */
+#define B43_NPHY_WWISE_CRCM3			B43_PHY_N(0x178) /* WWiSE CRC mask 3 */
+#define B43_NPHY_WWISE_CRCM4			B43_PHY_N(0x179) /* WWiSE CRC mask 4 */
+#define B43_NPHY_CHANEST_CDDSH			B43_PHY_N(0x17A) /* Channel estimate CDD shift */
+#define B43_NPHY_HTAGC_WCNT			B43_PHY_N(0x17B) /* HT ADC wait counters */
+#define B43_NPHY_SQPARM				B43_PHY_N(0x17C) /* SQ params */
+#define B43_NPHY_MCSDUP6M			B43_PHY_N(0x17D) /* MCS dup 6M */
+#define B43_NPHY_NDATAT_DUP40			B43_PHY_N(0x17E) /* # data tones dup 40 */
+#define B43_NPHY_DUP40_TGNSYNC_CYCD		B43_PHY_N(0x17F) /* Dup40 TGNsync cycle data */
+#define B43_NPHY_DUP40_GFBL			B43_PHY_N(0x180) /* Dup40 GF format BL address */
+#define B43_NPHY_DUP40_BL			B43_PHY_N(0x181) /* Dup40 format BL address */
+#define B43_NPHY_LEGDUP_FTA			B43_PHY_N(0x182) /* Legacy dup frm table address */
+#define B43_NPHY_PACPROC_DBG			B43_PHY_N(0x183) /* Packet processing debug */
+#define B43_NPHY_PIL_CYC1			B43_PHY_N(0x184) /* Pilot cycle counter 1 */
+#define B43_NPHY_PIL_CYC2			B43_PHY_N(0x185) /* Pilot cycle counter 2 */
+#define B43_NPHY_TXF_20CO_S0A1			B43_PHY_N(0x186) /* TX filter 20 coeff stage 0 A1 */
+#define B43_NPHY_TXF_20CO_S0A2			B43_PHY_N(0x187) /* TX filter 20 coeff stage 0 A2 */
+#define B43_NPHY_TXF_20CO_S1A1			B43_PHY_N(0x188) /* TX filter 20 coeff stage 1 A1 */
+#define B43_NPHY_TXF_20CO_S1A2			B43_PHY_N(0x189) /* TX filter 20 coeff stage 1 A2 */
+#define B43_NPHY_TXF_20CO_S2A1			B43_PHY_N(0x18A) /* TX filter 20 coeff stage 2 A1 */
+#define B43_NPHY_TXF_20CO_S2A2			B43_PHY_N(0x18B) /* TX filter 20 coeff stage 2 A2 */
+#define B43_NPHY_TXF_20CO_S0B1			B43_PHY_N(0x18C) /* TX filter 20 coeff stage 0 B1 */
+#define B43_NPHY_TXF_20CO_S0B2			B43_PHY_N(0x18D) /* TX filter 20 coeff stage 0 B2 */
+#define B43_NPHY_TXF_20CO_S0B3			B43_PHY_N(0x18E) /* TX filter 20 coeff stage 0 B3 */
+#define B43_NPHY_TXF_20CO_S1B1			B43_PHY_N(0x18F) /* TX filter 20 coeff stage 1 B1 */
+#define B43_NPHY_TXF_20CO_S1B2			B43_PHY_N(0x190) /* TX filter 20 coeff stage 1 B2 */
+#define B43_NPHY_TXF_20CO_S1B3			B43_PHY_N(0x191) /* TX filter 20 coeff stage 1 B3 */
+#define B43_NPHY_TXF_20CO_S2B1			B43_PHY_N(0x192) /* TX filter 20 coeff stage 2 B1 */
+#define B43_NPHY_TXF_20CO_S2B2			B43_PHY_N(0x193) /* TX filter 20 coeff stage 2 B2 */
+#define B43_NPHY_TXF_20CO_S2B3			B43_PHY_N(0x194) /* TX filter 20 coeff stage 2 B3 */
+#define B43_NPHY_TXF_40CO_S0A1			B43_PHY_N(0x195) /* TX filter 40 coeff stage 0 A1 */
+#define B43_NPHY_TXF_40CO_S0A2			B43_PHY_N(0x196) /* TX filter 40 coeff stage 0 A2 */
+#define B43_NPHY_TXF_40CO_S1A1			B43_PHY_N(0x197) /* TX filter 40 coeff stage 1 A1 */
+#define B43_NPHY_TXF_40CO_S1A2			B43_PHY_N(0x198) /* TX filter 40 coeff stage 1 A2 */
+#define B43_NPHY_TXF_40CO_S2A1			B43_PHY_N(0x199) /* TX filter 40 coeff stage 2 A1 */
+#define B43_NPHY_TXF_40CO_S2A2			B43_PHY_N(0x19A) /* TX filter 40 coeff stage 2 A2 */
+#define B43_NPHY_TXF_40CO_S0B1			B43_PHY_N(0x19B) /* TX filter 40 coeff stage 0 B1 */
+#define B43_NPHY_TXF_40CO_S0B2			B43_PHY_N(0x19C) /* TX filter 40 coeff stage 0 B2 */
+#define B43_NPHY_TXF_40CO_S0B3			B43_PHY_N(0x19D) /* TX filter 40 coeff stage 0 B3 */
+#define B43_NPHY_TXF_40CO_S1B1			B43_PHY_N(0x19E) /* TX filter 40 coeff stage 1 B1 */
+#define B43_NPHY_TXF_40CO_S1B2			B43_PHY_N(0x19F) /* TX filter 40 coeff stage 1 B2 */
+#define B43_NPHY_TXF_40CO_S1B3			B43_PHY_N(0x1A0) /* TX filter 40 coeff stage 1 B3 */
+#define B43_NPHY_TXF_40CO_S2B1			B43_PHY_N(0x1A1) /* TX filter 40 coeff stage 2 B1 */
+#define B43_NPHY_TXF_40CO_S2B2			B43_PHY_N(0x1A2) /* TX filter 40 coeff stage 2 B2 */
+#define B43_NPHY_TXF_40CO_S2B3			B43_PHY_N(0x1A3) /* TX filter 40 coeff stage 2 B3 */
+#define B43_NPHY_RSSIMC_0I_RSSI_X		B43_PHY_N(0x1A4) /* RSSI multiplication coefficient 0 I RSSI X */
+#define B43_NPHY_RSSIMC_0I_RSSI_Y		B43_PHY_N(0x1A5) /* RSSI multiplication coefficient 0 I RSSI Y */
+#define B43_NPHY_RSSIMC_0I_RSSI_Z		B43_PHY_N(0x1A6) /* RSSI multiplication coefficient 0 I RSSI Z */
+#define B43_NPHY_RSSIMC_0I_TBD			B43_PHY_N(0x1A7) /* RSSI multiplication coefficient 0 I TBD */
+#define B43_NPHY_RSSIMC_0I_PWRDET		B43_PHY_N(0x1A8) /* RSSI multiplication coefficient 0 I power det */
+#define B43_NPHY_RSSIMC_0I_TSSI			B43_PHY_N(0x1A9) /* RSSI multiplication coefficient 0 I TSSI */
+#define B43_NPHY_RSSIMC_0Q_RSSI_X		B43_PHY_N(0x1AA) /* RSSI multiplication coefficient 0 Q RSSI X */
+#define B43_NPHY_RSSIMC_0Q_RSSI_Y		B43_PHY_N(0x1AB) /* RSSI multiplication coefficient 0 Q RSSI Y */
+#define B43_NPHY_RSSIMC_0Q_RSSI_Z		B43_PHY_N(0x1AC) /* RSSI multiplication coefficient 0 Q RSSI Z */
+#define B43_NPHY_RSSIMC_0Q_TBD			B43_PHY_N(0x1AD) /* RSSI multiplication coefficient 0 Q TBD */
+#define B43_NPHY_RSSIMC_0Q_PWRDET		B43_PHY_N(0x1AE) /* RSSI multiplication coefficient 0 Q power det */
+#define B43_NPHY_RSSIMC_0Q_TSSI			B43_PHY_N(0x1AF) /* RSSI multiplication coefficient 0 Q TSSI */
+#define B43_NPHY_RSSIMC_1I_RSSI_X		B43_PHY_N(0x1B0) /* RSSI multiplication coefficient 1 I RSSI X */
+#define B43_NPHY_RSSIMC_1I_RSSI_Y		B43_PHY_N(0x1B1) /* RSSI multiplication coefficient 1 I RSSI Y */
+#define B43_NPHY_RSSIMC_1I_RSSI_Z		B43_PHY_N(0x1B2) /* RSSI multiplication coefficient 1 I RSSI Z */
+#define B43_NPHY_RSSIMC_1I_TBD			B43_PHY_N(0x1B3) /* RSSI multiplication coefficient 1 I TBD */
+#define B43_NPHY_RSSIMC_1I_PWRDET		B43_PHY_N(0x1B4) /* RSSI multiplication coefficient 1 I power det */
+#define B43_NPHY_RSSIMC_1I_TSSI			B43_PHY_N(0x1B5) /* RSSI multiplication coefficient 1 I TSSI */
+#define B43_NPHY_RSSIMC_1Q_RSSI_X		B43_PHY_N(0x1B6) /* RSSI multiplication coefficient 1 Q RSSI X */
+#define B43_NPHY_RSSIMC_1Q_RSSI_Y		B43_PHY_N(0x1B7) /* RSSI multiplication coefficient 1 Q RSSI Y */
+#define B43_NPHY_RSSIMC_1Q_RSSI_Z		B43_PHY_N(0x1B8) /* RSSI multiplication coefficient 1 Q RSSI Z */
+#define B43_NPHY_RSSIMC_1Q_TBD			B43_PHY_N(0x1B9) /* RSSI multiplication coefficient 1 Q TBD */
+#define B43_NPHY_RSSIMC_1Q_PWRDET		B43_PHY_N(0x1BA) /* RSSI multiplication coefficient 1 Q power det */
+#define B43_NPHY_RSSIMC_1Q_TSSI			B43_PHY_N(0x1BB) /* RSSI multiplication coefficient 1 Q TSSI */
+#define B43_NPHY_SAMC_WCNT			B43_PHY_N(0x1BC) /* Sample collect wait counter */
+#define B43_NPHY_PTHROUGH_CNT			B43_PHY_N(0x1BD) /* Pass-through counter */
+#define B43_NPHY_LTRN_OFF_G20L			B43_PHY_N(0x1C4) /* LTRN offset gain 20L */
+#define B43_NPHY_LTRN_OFF_20L			B43_PHY_N(0x1C5) /* LTRN offset 20L */
+#define B43_NPHY_LTRN_OFF_G20U			B43_PHY_N(0x1C6) /* LTRN offset gain 20U */
+#define B43_NPHY_LTRN_OFF_20U			B43_PHY_N(0x1C7) /* LTRN offset 20U */
+#define B43_NPHY_DSSSCCK_GAINSL			B43_PHY_N(0x1C8) /* DSSS/CCK gain settle length */
+#define B43_NPHY_GPIO_LOOUT			B43_PHY_N(0x1C9) /* GPIO low out */
+#define B43_NPHY_GPIO_HIOUT			B43_PHY_N(0x1CA) /* GPIO high out */
+#define B43_NPHY_CRS_CHECK			B43_PHY_N(0x1CB) /* CRS check */
+#define B43_NPHY_ML_LOGSS_RAT			B43_PHY_N(0x1CC) /* ML/logss ratio */
+#define B43_NPHY_DUPSCALE			B43_PHY_N(0x1CD) /* Dup scale */
+#define B43_NPHY_BW1A				B43_PHY_N(0x1CE) /* BW 1A */
+#define B43_NPHY_BW2				B43_PHY_N(0x1CF) /* BW 2 */
+#define B43_NPHY_BW3				B43_PHY_N(0x1D0) /* BW 3 */
+#define B43_NPHY_BW4				B43_PHY_N(0x1D1) /* BW 4 */
+#define B43_NPHY_BW5				B43_PHY_N(0x1D2) /* BW 5 */
+#define B43_NPHY_BW6				B43_PHY_N(0x1D3) /* BW 6 */
+#define B43_NPHY_COALEN0			B43_PHY_N(0x1D4) /* Coarse length 0 */
+#define B43_NPHY_COALEN1			B43_PHY_N(0x1D5) /* Coarse length 1 */
+#define B43_NPHY_CRSTHRES_1U			B43_PHY_N(0x1D6) /* CRS threshold 1 U */
+#define B43_NPHY_CRSTHRES_2U			B43_PHY_N(0x1D7) /* CRS threshold 2 U */
+#define B43_NPHY_CRSTHRES_3U			B43_PHY_N(0x1D8) /* CRS threshold 3 U */
+#define B43_NPHY_CRSCTL_U			B43_PHY_N(0x1D9) /* CRS control U */
+#define B43_NPHY_CRSTHRES_1L			B43_PHY_N(0x1DA) /* CRS threshold 1 L */
+#define B43_NPHY_CRSTHRES_2L			B43_PHY_N(0x1DB) /* CRS threshold 2 L */
+#define B43_NPHY_CRSTHRES_3L			B43_PHY_N(0x1DC) /* CRS threshold 3 L */
+#define B43_NPHY_CRSCTL_L			B43_PHY_N(0x1DD) /* CRS control L */
+#define B43_NPHY_STRA_1U			B43_PHY_N(0x1DE) /* STR address 1 U */
+#define B43_NPHY_STRA_2U			B43_PHY_N(0x1DF) /* STR address 2 U */
+#define B43_NPHY_STRA_1L			B43_PHY_N(0x1E0) /* STR address 1 L */
+#define B43_NPHY_STRA_2L			B43_PHY_N(0x1E1) /* STR address 2 L */
+#define B43_NPHY_CRSCHECK1			B43_PHY_N(0x1E2) /* CRS check 1 */
+#define B43_NPHY_CRSCHECK2			B43_PHY_N(0x1E3) /* CRS check 2 */
+#define B43_NPHY_CRSCHECK3			B43_PHY_N(0x1E4) /* CRS check 3 */
+#define B43_NPHY_JMPSTP0			B43_PHY_N(0x1E5) /* Jump step 0 */
+#define B43_NPHY_JMPSTP1			B43_PHY_N(0x1E6) /* Jump step 1 */
+#define B43_NPHY_TXPCTL_CMD			B43_PHY_N(0x1E7) /* TX power control command */
+#define  B43_NPHY_TXPCTL_CMD_INIT		0x007F /* Init */
+#define  B43_NPHY_TXPCTL_CMD_INIT_SHIFT		0
+#define  B43_NPHY_TXPCTL_CMD_COEFF		0x2000 /* Power control coefficients */
+#define  B43_NPHY_TXPCTL_CMD_HWPCTLEN		0x4000 /* Hardware TX power control enable */
+#define  B43_NPHY_TXPCTL_CMD_PCTLEN		0x8000 /* TX power control enable */
+#define B43_NPHY_TXPCTL_N			B43_PHY_N(0x1E8) /* TX power control N num */
+#define  B43_NPHY_TXPCTL_N_TSSID		0x00FF /* N TSSI delay */
+#define  B43_NPHY_TXPCTL_N_TSSID_SHIFT		0
+#define  B43_NPHY_TXPCTL_N_NPTIL2		0x0700 /* N PT integer log2 */
+#define  B43_NPHY_TXPCTL_N_NPTIL2_SHIFT		8
+#define B43_NPHY_TXPCTL_ITSSI			B43_PHY_N(0x1E9) /* TX power control idle TSSI */
+#define  B43_NPHY_TXPCTL_ITSSI_0		0x003F /* Idle TSSI 0 */
+#define  B43_NPHY_TXPCTL_ITSSI_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_ITSSI_1		0x3F00 /* Idle TSSI 1 */
+#define  B43_NPHY_TXPCTL_ITSSI_1_SHIFT		8
+#define  B43_NPHY_TXPCTL_ITSSI_BINF		0x8000 /* Raw TSSI offset bin format */
+#define B43_NPHY_TXPCTL_TPWR			B43_PHY_N(0x1EA) /* TX power control target power */
+#define  B43_NPHY_TXPCTL_TPWR_0			0x00FF /* Power 0 */
+#define  B43_NPHY_TXPCTL_TPWR_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_TPWR_1			0xFF00 /* Power 1 */
+#define  B43_NPHY_TXPCTL_TPWR_1_SHIFT		8
+#define B43_NPHY_TXPCTL_BIDX			B43_PHY_N(0x1EB) /* TX power control base index */
+#define  B43_NPHY_TXPCTL_BIDX_0			0x007F /* uC base index 0 */
+#define  B43_NPHY_TXPCTL_BIDX_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_BIDX_1			0x7F00 /* uC base index 1 */
+#define  B43_NPHY_TXPCTL_BIDX_1_SHIFT		8
+#define  B43_NPHY_TXPCTL_BIDX_LOAD		0x8000 /* Load base index */
+#define B43_NPHY_TXPCTL_PIDX			B43_PHY_N(0x1EC) /* TX power control power index */
+#define  B43_NPHY_TXPCTL_PIDX_0			0x007F /* uC power index 0 */
+#define  B43_NPHY_TXPCTL_PIDX_0_SHIFT		0
+#define  B43_NPHY_TXPCTL_PIDX_1			0x7F00 /* uC power index 1 */
+#define  B43_NPHY_TXPCTL_PIDX_1_SHIFT		8
+#define B43_NPHY_C1_TXPCTL_STAT			B43_PHY_N(0x1ED) /* Core 1 TX power control status */
+#define B43_NPHY_C2_TXPCTL_STAT			B43_PHY_N(0x1EE) /* Core 2 TX power control status */
+#define  B43_NPHY_TXPCTL_STAT_EST		0x00FF /* Estimated power */
+#define  B43_NPHY_TXPCTL_STAT_EST_SHIFT		0
+#define  B43_NPHY_TXPCTL_STAT_BIDX		0x7F00 /* Base index */
+#define  B43_NPHY_TXPCTL_STAT_BIDX_SHIFT	8
+#define  B43_NPHY_TXPCTL_STAT_ESTVALID		0x8000 /* Estimated power valid */
+#define B43_NPHY_SMALLSGS_LEN			B43_PHY_N(0x1EF) /* Small sig gain settle length */
+#define B43_NPHY_PHYSTAT_GAIN0			B43_PHY_N(0x1F0) /* PHY stats gain info 0 */
+#define B43_NPHY_PHYSTAT_GAIN1			B43_PHY_N(0x1F1) /* PHY stats gain info 1 */
+#define B43_NPHY_PHYSTAT_FREQEST		B43_PHY_N(0x1F2) /* PHY stats frequency estimate */
+#define B43_NPHY_PHYSTAT_ADVRET			B43_PHY_N(0x1F3) /* PHY stats ADV retard */
+#define B43_NPHY_PHYLB_MODE			B43_PHY_N(0x1F4) /* PHY loopback mode */
+#define B43_NPHY_TONE_MIDX20_1			B43_PHY_N(0x1F5) /* Tone map index 20/1 */
+#define B43_NPHY_TONE_MIDX20_2			B43_PHY_N(0x1F6) /* Tone map index 20/2 */
+#define B43_NPHY_TONE_MIDX20_3			B43_PHY_N(0x1F7) /* Tone map index 20/3 */
+#define B43_NPHY_TONE_MIDX40_1			B43_PHY_N(0x1F8) /* Tone map index 40/1 */
+#define B43_NPHY_TONE_MIDX40_2			B43_PHY_N(0x1F9) /* Tone map index 40/2 */
+#define B43_NPHY_TONE_MIDX40_3			B43_PHY_N(0x1FA) /* Tone map index 40/3 */
+#define B43_NPHY_TONE_MIDX40_4			B43_PHY_N(0x1FB) /* Tone map index 40/4 */
+#define B43_NPHY_PILTONE_MIDX1			B43_PHY_N(0x1FC) /* Pilot tone map index 1 */
+#define B43_NPHY_PILTONE_MIDX2			B43_PHY_N(0x1FD) /* Pilot tone map index 2 */
+#define B43_NPHY_PILTONE_MIDX3			B43_PHY_N(0x1FE) /* Pilot tone map index 3 */
+#define B43_NPHY_TXRIFS_FRDEL			B43_PHY_N(0x1FF) /* TX RIFS frame delay */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_40M		B43_PHY_N(0x200) /* AFE seq rx2tx power up/down delay 40M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_40M		B43_PHY_N(0x201) /* AFE seq tx2rx power up/down delay 40M */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_20M		B43_PHY_N(0x202) /* AFE seq rx2tx power up/down delay 20M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_20M		B43_PHY_N(0x203) /* AFE seq tx2rx power up/down delay 20M */
+#define B43_NPHY_RX_SIGCTL			B43_PHY_N(0x204) /* RX signal control */
+#define B43_NPHY_RXPIL_CYCNT0			B43_PHY_N(0x205) /* RX pilot cycle counter 0 */
+#define B43_NPHY_RXPIL_CYCNT1			B43_PHY_N(0x206) /* RX pilot cycle counter 1 */
+#define B43_NPHY_RXPIL_CYCNT2			B43_PHY_N(0x207) /* RX pilot cycle counter 2 */
+#define B43_NPHY_AFESEQ_RX2TX_PUD_10M		B43_PHY_N(0x208) /* AFE seq rx2tx power up/down delay 10M */
+#define B43_NPHY_AFESEQ_TX2RX_PUD_10M		B43_PHY_N(0x209) /* AFE seq tx2rx power up/down delay 10M */
+#define B43_NPHY_DSSSCCK_CRSEXTL		B43_PHY_N(0x20A) /* DSSS/CCK CRS extension length */
+#define B43_NPHY_ML_LOGSS_RATSLOPE		B43_PHY_N(0x20B) /* ML/logss ratio slope */
+#define B43_NPHY_RIFS_SRCTL			B43_PHY_N(0x20C) /* RIFS search timeout length */
+#define B43_NPHY_TXREALFD			B43_PHY_N(0x20D) /* TX real frame delay */
+#define B43_NPHY_HPANT_SWTHRES			B43_PHY_N(0x20E) /* High power antenna switch threshold */
+#define B43_NPHY_EDCRS_ASSTHRES0		B43_PHY_N(0x210) /* ED CRS assert threshold 0 */
+#define B43_NPHY_EDCRS_ASSTHRES1		B43_PHY_N(0x211) /* ED CRS assert threshold 1 */
+#define B43_NPHY_EDCRS_DEASSTHRES0		B43_PHY_N(0x212) /* ED CRS deassert threshold 0 */
+#define B43_NPHY_EDCRS_DEASSTHRES1		B43_PHY_N(0x213) /* ED CRS deassert threshold 1 */
+#define B43_NPHY_STR_WTIME20U			B43_PHY_N(0x214) /* STR wait time 20U */
+#define B43_NPHY_STR_WTIME20L			B43_PHY_N(0x215) /* STR wait time 20L */
+#define B43_NPHY_TONE_MIDX657M			B43_PHY_N(0x216) /* Tone map index 657M */
+#define B43_NPHY_HTSIGTONES			B43_PHY_N(0x217) /* HT signal tones */
+#define B43_NPHY_RSSI1				B43_PHY_N(0x219) /* RSSI value 1 */
+#define B43_NPHY_RSSI2				B43_PHY_N(0x21A) /* RSSI value 2 */
+#define B43_NPHY_CHAN_ESTHANG			B43_PHY_N(0x21D) /* Channel estimate hang */
+#define B43_NPHY_FINERX2_CGC			B43_PHY_N(0x221) /* Fine RX 2 clock gate control */
+#define  B43_NPHY_FINERX2_CGC_DECGC		0x0008 /* Decode gated clocks */
+#define B43_NPHY_TXPCTL_INIT			B43_PHY_N(0x222) /* TX power controll init */
+#define  B43_NPHY_TXPCTL_INIT_PIDXI1		0x00FF /* Power index init 1 */
+#define  B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT	0
+
+
+
+/* Broadcom 2055 radio registers */
+
+#define B2055_GEN_SPARE			0x00 /* GEN spare */
+#define B2055_SP_PINPD			0x02 /* SP PIN PD */
+#define B2055_C1_SP_RSSI		0x03 /* SP RSSI Core 1 */
+#define B2055_C1_SP_PDMISC		0x04 /* SP PD MISC Core 1 */
+#define B2055_C2_SP_RSSI		0x05 /* SP RSSI Core 2 */
+#define B2055_C2_SP_PDMISC		0x06 /* SP PD MISC Core 2 */
+#define B2055_C1_SP_RXGC1		0x07 /* SP RX GC1 Core 1 */
+#define B2055_C1_SP_RXGC2		0x08 /* SP RX GC2 Core 1 */
+#define B2055_C2_SP_RXGC1		0x09 /* SP RX GC1 Core 2 */
+#define B2055_C2_SP_RXGC2		0x0A /* SP RX GC2 Core 2 */
+#define B2055_C1_SP_LPFBWSEL		0x0B /* SP LPF BW select Core 1 */
+#define B2055_C2_SP_LPFBWSEL		0x0C /* SP LPF BW select Core 2 */
+#define B2055_C1_SP_TXGC1		0x0D /* SP TX GC1 Core 1 */
+#define B2055_C1_SP_TXGC2		0x0E /* SP TX GC2 Core 1 */
+#define B2055_C2_SP_TXGC1		0x0F /* SP TX GC1 Core 2 */
+#define B2055_C2_SP_TXGC2		0x10 /* SP TX GC2 Core 2 */
+#define B2055_MASTER1			0x11 /* Master control 1 */
+#define B2055_MASTER2			0x12 /* Master control 2 */
+#define B2055_PD_LGEN			0x13 /* PD LGEN */
+#define B2055_PD_PLLTS			0x14 /* PD PLL TS */
+#define B2055_C1_PD_LGBUF		0x15 /* PD Core 1 LGBUF */
+#define B2055_C1_PD_TX			0x16 /* PD Core 1 TX */
+#define B2055_C1_PD_RXTX		0x17 /* PD Core 1 RXTX */
+#define B2055_C1_PD_RSSIMISC		0x18 /* PD Core 1 RSSI MISC */
+#define B2055_C2_PD_LGBUF		0x19 /* PD Core 2 LGBUF */
+#define B2055_C2_PD_TX			0x1A /* PD Core 2 TX */
+#define B2055_C2_PD_RXTX		0x1B /* PD Core 2 RXTX */
+#define B2055_C2_PD_RSSIMISC		0x1C /* PD Core 2 RSSI MISC */
+#define B2055_PWRDET_LGEN		0x1D /* PWRDET LGEN */
+#define B2055_C1_PWRDET_LGBUF		0x1E /* PWRDET LGBUF Core 1 */
+#define B2055_C1_PWRDET_RXTX		0x1F /* PWRDET RXTX Core 1 */
+#define B2055_C2_PWRDET_LGBUF		0x20 /* PWRDET LGBUF Core 2 */
+#define B2055_C2_PWRDET_RXTX		0x21 /* PWRDET RXTX Core 2 */
+#define B2055_RRCCAL_CS			0x22 /* RRCCAL Control spare */
+#define B2055_RRCCAL_NOPTSEL		0x23 /* RRCCAL N OPT SEL */
+#define B2055_CAL_MISC			0x24 /* CAL MISC */
+#define B2055_CAL_COUT			0x25 /* CAL Counter out */
+#define B2055_CAL_COUT2			0x26 /* CAL Counter out 2 */
+#define B2055_CAL_CVARCTL		0x27 /* CAL CVAR Control */
+#define B2055_CAL_RVARCTL		0x28 /* CAL RVAR Control */
+#define B2055_CAL_LPOCTL		0x29 /* CAL LPO Control */
+#define B2055_CAL_TS			0x2A /* CAL TS */
+#define B2055_CAL_RCCALRTS		0x2B /* CAL RCCAL READ TS */
+#define B2055_CAL_RCALRTS		0x2C /* CAL RCAL READ TS */
+#define B2055_PADDRV			0x2D /* PAD driver */
+#define B2055_XOCTL1			0x2E /* XO Control 1 */
+#define B2055_XOCTL2			0x2F /* XO Control 2 */
+#define B2055_XOREGUL			0x30 /* XO Regulator */
+#define B2055_XOMISC			0x31 /* XO misc */
+#define B2055_PLL_LFC1			0x32 /* PLL LF C1 */
+#define B2055_PLL_CALVTH		0x33 /* PLL CAL VTH */
+#define B2055_PLL_LFC2			0x34 /* PLL LF C2 */
+#define B2055_PLL_REF			0x35 /* PLL reference */
+#define B2055_PLL_LFR1			0x36 /* PLL LF R1 */
+#define B2055_PLL_PFDCP			0x37 /* PLL PFD CP */
+#define B2055_PLL_IDAC_CPOPAMP		0x38 /* PLL IDAC CPOPAMP */
+#define B2055_PLL_CPREG			0x39 /* PLL CP Regulator */
+#define B2055_PLL_RCAL			0x3A /* PLL RCAL */
+#define B2055_RF_PLLMOD0		0x3B /* RF PLL MOD0 */
+#define B2055_RF_PLLMOD1		0x3C /* RF PLL MOD1 */
+#define B2055_RF_MMDIDAC1		0x3D /* RF MMD IDAC 1 */
+#define B2055_RF_MMDIDAC0		0x3E /* RF MMD IDAC 0 */
+#define B2055_RF_MMDSP			0x3F /* RF MMD spare */
+#define B2055_VCO_CAL1			0x40 /* VCO cal 1 */
+#define B2055_VCO_CAL2			0x41 /* VCO cal 2 */
+#define B2055_VCO_CAL3			0x42 /* VCO cal 3 */
+#define B2055_VCO_CAL4			0x43 /* VCO cal 4 */
+#define B2055_VCO_CAL5			0x44 /* VCO cal 5 */
+#define B2055_VCO_CAL6			0x45 /* VCO cal 6 */
+#define B2055_VCO_CAL7			0x46 /* VCO cal 7 */
+#define B2055_VCO_CAL8			0x47 /* VCO cal 8 */
+#define B2055_VCO_CAL9			0x48 /* VCO cal 9 */
+#define B2055_VCO_CAL10			0x49 /* VCO cal 10 */
+#define B2055_VCO_CAL11			0x4A /* VCO cal 11 */
+#define B2055_VCO_CAL12			0x4B /* VCO cal 12 */
+#define B2055_VCO_CAL13			0x4C /* VCO cal 13 */
+#define B2055_VCO_CAL14			0x4D /* VCO cal 14 */
+#define B2055_VCO_CAL15			0x4E /* VCO cal 15 */
+#define B2055_VCO_CAL16			0x4F /* VCO cal 16 */
+#define B2055_VCO_KVCO			0x50 /* VCO KVCO */
+#define B2055_VCO_CAPTAIL		0x51 /* VCO CAP TAIL */
+#define B2055_VCO_IDACVCO		0x52 /* VCO IDAC VCO */
+#define B2055_VCO_REG			0x53 /* VCO Regulator */
+#define B2055_PLL_RFVTH			0x54 /* PLL RF VTH */
+#define B2055_LGBUF_CENBUF		0x55 /* LGBUF CEN BUF */
+#define B2055_LGEN_TUNE1		0x56 /* LGEN tune 1 */
+#define B2055_LGEN_TUNE2		0x57 /* LGEN tune 2 */
+#define B2055_LGEN_IDAC1		0x58 /* LGEN IDAC 1 */
+#define B2055_LGEN_IDAC2		0x59 /* LGEN IDAC 2 */
+#define B2055_LGEN_BIASC		0x5A /* LGEN BIAS counter */
+#define B2055_LGEN_BIASIDAC		0x5B /* LGEN BIAS IDAC */
+#define B2055_LGEN_RCAL			0x5C /* LGEN RCAL */
+#define B2055_LGEN_DIV			0x5D /* LGEN div */
+#define B2055_LGEN_SPARE2		0x5E /* LGEN spare 2 */
+#define B2055_C1_LGBUF_ATUNE		0x5F /* Core 1 LGBUF A tune */
+#define B2055_C1_LGBUF_GTUNE		0x60 /* Core 1 LGBUF G tune */
+#define B2055_C1_LGBUF_DIV		0x61 /* Core 1 LGBUF div */
+#define B2055_C1_LGBUF_AIDAC		0x62 /* Core 1 LGBUF A IDAC */
+#define B2055_C1_LGBUF_GIDAC		0x63 /* Core 1 LGBUF G IDAC */
+#define B2055_C1_LGBUF_IDACFO		0x64 /* Core 1 LGBUF IDAC filter override */
+#define B2055_C1_LGBUF_SPARE		0x65 /* Core 1 LGBUF spare */
+#define B2055_C1_RX_RFSPC1		0x66 /* Core 1 RX RF SPC1 */
+#define B2055_C1_RX_RFR1		0x67 /* Core 1 RX RF reg 1 */
+#define B2055_C1_RX_RFR2		0x68 /* Core 1 RX RF reg 2 */
+#define B2055_C1_RX_RFRCAL		0x69 /* Core 1 RX RF RCAL */
+#define B2055_C1_RX_BB_BLCMP		0x6A /* Core 1 RX Baseband BUFI LPF CMP */
+#define B2055_C1_RX_BB_LPF		0x6B /* Core 1 RX Baseband LPF */
+#define B2055_C1_RX_BB_MIDACHP		0x6C /* Core 1 RX Baseband MIDAC High-pass */
+#define B2055_C1_RX_BB_VGA1IDAC		0x6D /* Core 1 RX Baseband VGA1 IDAC */
+#define B2055_C1_RX_BB_VGA2IDAC		0x6E /* Core 1 RX Baseband VGA2 IDAC */
+#define B2055_C1_RX_BB_VGA3IDAC		0x6F /* Core 1 RX Baseband VGA3 IDAC */
+#define B2055_C1_RX_BB_BUFOCTL		0x70 /* Core 1 RX Baseband BUFO Control */
+#define B2055_C1_RX_BB_RCCALCTL		0x71 /* Core 1 RX Baseband RCCAL Control */
+#define B2055_C1_RX_BB_RSSICTL1		0x72 /* Core 1 RX Baseband RSSI Control 1 */
+#define B2055_C1_RX_BB_RSSICTL2		0x73 /* Core 1 RX Baseband RSSI Control 2 */
+#define B2055_C1_RX_BB_RSSICTL3		0x74 /* Core 1 RX Baseband RSSI Control 3 */
+#define B2055_C1_RX_BB_RSSICTL4		0x75 /* Core 1 RX Baseband RSSI Control 4 */
+#define B2055_C1_RX_BB_RSSICTL5		0x76 /* Core 1 RX Baseband RSSI Control 5 */
+#define B2055_C1_RX_BB_REG		0x77 /* Core 1 RX Baseband Regulator */
+#define B2055_C1_RX_BB_SPARE1		0x78 /* Core 1 RX Baseband spare 1 */
+#define B2055_C1_RX_TXBBRCAL		0x79 /* Core 1 RX TX BB RCAL */
+#define B2055_C1_TX_RF_SPGA		0x7A /* Core 1 TX RF SGM PGA */
+#define B2055_C1_TX_RF_SPAD		0x7B /* Core 1 TX RF SGM PAD */
+#define B2055_C1_TX_RF_CNTPGA1		0x7C /* Core 1 TX RF counter PGA 1 */
+#define B2055_C1_TX_RF_CNTPAD1		0x7D /* Core 1 TX RF counter PAD 1 */
+#define B2055_C1_TX_RF_PGAIDAC		0x7E /* Core 1 TX RF PGA IDAC */
+#define B2055_C1_TX_PGAPADTN		0x7F /* Core 1 TX PGA PAD TN */
+#define B2055_C1_TX_PADIDAC1		0x80 /* Core 1 TX PAD IDAC 1 */
+#define B2055_C1_TX_PADIDAC2		0x81 /* Core 1 TX PAD IDAC 2 */
+#define B2055_C1_TX_MXBGTRIM		0x82 /* Core 1 TX MX B/G TRIM */
+#define B2055_C1_TX_RF_RCAL		0x83 /* Core 1 TX RF RCAL */
+#define B2055_C1_TX_RF_PADTSSI1		0x84 /* Core 1 TX RF PAD TSSI1 */
+#define B2055_C1_TX_RF_PADTSSI2		0x85 /* Core 1 TX RF PAD TSSI2 */
+#define B2055_C1_TX_RF_SPARE		0x86 /* Core 1 TX RF spare */
+#define B2055_C1_TX_RF_IQCAL1		0x87 /* Core 1 TX RF I/Q CAL 1 */
+#define B2055_C1_TX_RF_IQCAL2		0x88 /* Core 1 TX RF I/Q CAL 2 */
+#define B2055_C1_TXBB_RCCAL		0x89 /* Core 1 TXBB RC CAL Control */
+#define B2055_C1_TXBB_LPF1		0x8A /* Core 1 TXBB LPF 1 */
+#define B2055_C1_TX_VOSCNCL		0x8B /* Core 1 TX VOS CNCL */
+#define B2055_C1_TX_LPF_MXGMIDAC	0x8C /* Core 1 TX LPF MXGM IDAC */
+#define B2055_C1_TX_BB_MXGM		0x8D /* Core 1 TX BB MXGM */
+#define B2055_C2_LGBUF_ATUNE		0x8E /* Core 2 LGBUF A tune */
+#define B2055_C2_LGBUF_GTUNE		0x8F /* Core 2 LGBUF G tune */
+#define B2055_C2_LGBUF_DIV		0x90 /* Core 2 LGBUF div */
+#define B2055_C2_LGBUF_AIDAC		0x91 /* Core 2 LGBUF A IDAC */
+#define B2055_C2_LGBUF_GIDAC		0x92 /* Core 2 LGBUF G IDAC */
+#define B2055_C2_LGBUF_IDACFO		0x93 /* Core 2 LGBUF IDAC filter override */
+#define B2055_C2_LGBUF_SPARE		0x94 /* Core 2 LGBUF spare */
+#define B2055_C2_RX_RFSPC1		0x95 /* Core 2 RX RF SPC1 */
+#define B2055_C2_RX_RFR1		0x96 /* Core 2 RX RF reg 1 */
+#define B2055_C2_RX_RFR2		0x97 /* Core 2 RX RF reg 2 */
+#define B2055_C2_RX_RFRCAL		0x98 /* Core 2 RX RF RCAL */
+#define B2055_C2_RX_BB_BLCMP		0x99 /* Core 2 RX Baseband BUFI LPF CMP */
+#define B2055_C2_RX_BB_LPF		0x9A /* Core 2 RX Baseband LPF */
+#define B2055_C2_RX_BB_MIDACHP		0x9B /* Core 2 RX Baseband MIDAC High-pass */
+#define B2055_C2_RX_BB_VGA1IDAC		0x9C /* Core 2 RX Baseband VGA1 IDAC */
+#define B2055_C2_RX_BB_VGA2IDAC		0x9D /* Core 2 RX Baseband VGA2 IDAC */
+#define B2055_C2_RX_BB_VGA3IDAC		0x9E /* Core 2 RX Baseband VGA3 IDAC */
+#define B2055_C2_RX_BB_BUFOCTL		0x9F /* Core 2 RX Baseband BUFO Control */
+#define B2055_C2_RX_BB_RCCALCTL		0xA0 /* Core 2 RX Baseband RCCAL Control */
+#define B2055_C2_RX_BB_RSSICTL1		0xA1 /* Core 2 RX Baseband RSSI Control 1 */
+#define B2055_C2_RX_BB_RSSICTL2		0xA2 /* Core 2 RX Baseband RSSI Control 2 */
+#define B2055_C2_RX_BB_RSSICTL3		0xA3 /* Core 2 RX Baseband RSSI Control 3 */
+#define B2055_C2_RX_BB_RSSICTL4		0xA4 /* Core 2 RX Baseband RSSI Control 4 */
+#define B2055_C2_RX_BB_RSSICTL5		0xA5 /* Core 2 RX Baseband RSSI Control 5 */
+#define B2055_C2_RX_BB_REG		0xA6 /* Core 2 RX Baseband Regulator */
+#define B2055_C2_RX_BB_SPARE1		0xA7 /* Core 2 RX Baseband spare 1 */
+#define B2055_C2_RX_TXBBRCAL		0xA8 /* Core 2 RX TX BB RCAL */
+#define B2055_C2_TX_RF_SPGA		0xA9 /* Core 2 TX RF SGM PGA */
+#define B2055_C2_TX_RF_SPAD		0xAA /* Core 2 TX RF SGM PAD */
+#define B2055_C2_TX_RF_CNTPGA1		0xAB /* Core 2 TX RF counter PGA 1 */
+#define B2055_C2_TX_RF_CNTPAD1		0xAC /* Core 2 TX RF counter PAD 1 */
+#define B2055_C2_TX_RF_PGAIDAC		0xAD /* Core 2 TX RF PGA IDAC */
+#define B2055_C2_TX_PGAPADTN		0xAE /* Core 2 TX PGA PAD TN */
+#define B2055_C2_TX_PADIDAC1		0xAF /* Core 2 TX PAD IDAC 1 */
+#define B2055_C2_TX_PADIDAC2		0xB0 /* Core 2 TX PAD IDAC 2 */
+#define B2055_C2_TX_MXBGTRIM		0xB1 /* Core 2 TX MX B/G TRIM */
+#define B2055_C2_TX_RF_RCAL		0xB2 /* Core 2 TX RF RCAL */
+#define B2055_C2_TX_RF_PADTSSI1		0xB3 /* Core 2 TX RF PAD TSSI1 */
+#define B2055_C2_TX_RF_PADTSSI2		0xB4 /* Core 2 TX RF PAD TSSI2 */
+#define B2055_C2_TX_RF_SPARE		0xB5 /* Core 2 TX RF spare */
+#define B2055_C2_TX_RF_IQCAL1		0xB6 /* Core 2 TX RF I/Q CAL 1 */
+#define B2055_C2_TX_RF_IQCAL2		0xB7 /* Core 2 TX RF I/Q CAL 2 */
+#define B2055_C2_TXBB_RCCAL		0xB8 /* Core 2 TXBB RC CAL Control */
+#define B2055_C2_TXBB_LPF1		0xB9 /* Core 2 TXBB LPF 1 */
+#define B2055_C2_TX_VOSCNCL		0xBA /* Core 2 TX VOS CNCL */
+#define B2055_C2_TX_LPF_MXGMIDAC	0xBB /* Core 2 TX LPF MXGM IDAC */
+#define B2055_C2_TX_BB_MXGM		0xBC /* Core 2 TX BB MXGM */
+#define B2055_PRG_GCHP21		0xBD /* PRG GC HPVGA23 21 */
+#define B2055_PRG_GCHP22		0xBE /* PRG GC HPVGA23 22 */
+#define B2055_PRG_GCHP23		0xBF /* PRG GC HPVGA23 23 */
+#define B2055_PRG_GCHP24		0xC0 /* PRG GC HPVGA23 24 */
+#define B2055_PRG_GCHP25		0xC1 /* PRG GC HPVGA23 25 */
+#define B2055_PRG_GCHP26		0xC2 /* PRG GC HPVGA23 26 */
+#define B2055_PRG_GCHP27		0xC3 /* PRG GC HPVGA23 27 */
+#define B2055_PRG_GCHP28		0xC4 /* PRG GC HPVGA23 28 */
+#define B2055_PRG_GCHP29		0xC5 /* PRG GC HPVGA23 29 */
+#define B2055_PRG_GCHP30		0xC6 /* PRG GC HPVGA23 30 */
+#define B2055_C1_LNA_GAINBST		0xCD /* Core 1 LNA GAINBST */
+#define B2055_C1_B0NB_RSSIVCM		0xD2 /* Core 1 B0 narrow-band RSSI VCM */
+#define B2055_C1_GENSPARE2		0xD6 /* Core 1 GEN spare 2 */
+#define B2055_C2_LNA_GAINBST		0xD9 /* Core 2 LNA GAINBST */
+#define B2055_C2_B0NB_RSSIVCM		0xDE /* Core 2 B0 narrow-band RSSI VCM */
+#define B2055_C2_GENSPARE2		0xE2 /* Core 2 GEN spare 2 */
+
+
+
+struct b43_wldev;
+
+int b43_phy_initn(struct b43_wldev *dev);
+
+void b43_nphy_radio_turn_on(struct b43_wldev *dev);
+void b43_nphy_radio_turn_off(struct b43_wldev *dev);
+
+int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel);
+
+void b43_nphy_xmitpower(struct b43_wldev *dev);
+void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna);
+
+#endif /* B43_NPHY_H_ */
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
index 7ff091e69f05..71507b260b6d 100644
--- a/drivers/net/wireless/b43/phy.c
+++ b/drivers/net/wireless/b43/phy.c
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -31,9 +31,12 @@
 
 #include "b43.h"
 #include "phy.h"
+#include "nphy.h"
 #include "main.h"
 #include "tables.h"
 #include "lo.h"
+#include "wa.h"
+
 
 static const s8 b43_tssi2dbm_b_table[] = {
 	0x4D, 0x4C, 0x4B, 0x4A,
@@ -225,42 +228,30 @@ static void b43_shm_clear_tssi(struct b43_wldev *dev)
 	}
 }
 
-void b43_raw_phy_lock(struct b43_wldev *dev)
+/* Lock the PHY registers against concurrent access from the microcode.
+ * This lock is nonrecursive. */
+void b43_phy_lock(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
-
-	B43_WARN_ON(!irqs_disabled());
-
-	/* We had a check for MACCTL==0 here, but I think that doesn't
-	 * make sense, as MACCTL is never 0 when this is called.
-	 *      --mb */
-	B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0);
+#if B43_DEBUG
+	B43_WARN_ON(dev->phy.phy_locked);
+	dev->phy.phy_locked = 1;
+#endif
+	B43_WARN_ON(dev->dev->id.revision < 3);
 
-	if (dev->dev->id.revision < 3) {
-		b43_mac_suspend(dev);
-		spin_lock(&phy->lock);
-	} else {
-		if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
-			b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
-	}
-	phy->locked = 1;
+	if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+		b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
 }
 
-void b43_raw_phy_unlock(struct b43_wldev *dev)
+void b43_phy_unlock(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
+#if B43_DEBUG
+	B43_WARN_ON(!dev->phy.phy_locked);
+	dev->phy.phy_locked = 0;
+#endif
+	B43_WARN_ON(dev->dev->id.revision < 3);
 
-	B43_WARN_ON(!irqs_disabled());
-	if (dev->dev->id.revision < 3) {
-		if (phy->locked) {
-			spin_unlock(&phy->lock);
-			b43_mac_enable(dev);
-		}
-	} else {
-		if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
-			b43_power_saving_ctl_bits(dev, 0);
-	}
-	phy->locked = 0;
+	if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+		b43_power_saving_ctl_bits(dev, 0);
 }
 
 /* Different PHYs require different register routing flags.
@@ -271,15 +262,30 @@ static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy,
 {
 	if (phy->type == B43_PHYTYPE_A) {
 		/* OFDM registers are base-registers for the A-PHY. */
-		offset &= ~B43_PHYROUTE_OFDM_GPHY;
+		if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) {
+			offset &= ~B43_PHYROUTE;
+			offset |= B43_PHYROUTE_BASE;
+		}
 	}
-	if (offset & B43_PHYROUTE_EXT_GPHY) {
+
+#if B43_DEBUG
+	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) {
 		/* Ext-G registers are only available on G-PHYs */
 		if (phy->type != B43_PHYTYPE_G) {
-			b43dbg(dev->wl, "EXT-G PHY access at "
-			       "0x%04X on %u type PHY\n", offset, phy->type);
+			b43err(dev->wl, "Invalid EXT-G PHY access at "
+			       "0x%04X on PHY type %u\n", offset, phy->type);
+			dump_stack();
 		}
 	}
+	if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) {
+		/* N-BMODE registers are only available on N-PHYs */
+		if (phy->type != B43_PHYTYPE_N) {
+			b43err(dev->wl, "Invalid N-BMODE PHY access at "
+			       "0x%04X on PHY type %u\n", offset, phy->type);
+			dump_stack();
+		}
+	}
+#endif /* B43_DEBUG */
 
 	return offset;
 }
@@ -299,11 +305,26 @@ void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val)
 
 	offset = adjust_phyreg_for_phytype(phy, offset, dev);
 	b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
-	mmiowb();
 	b43_write16(dev, B43_MMIO_PHY_DATA, val);
 }
 
-static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower);
+void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
+{
+	b43_phy_write(dev, offset,
+		      b43_phy_read(dev, offset) & mask);
+}
+
+void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
+{
+	b43_phy_write(dev, offset,
+		      b43_phy_read(dev, offset) | set);
+}
+
+void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
+{
+	b43_phy_write(dev, offset,
+		      (b43_phy_read(dev, offset) & mask) | set);
+}
 
 /* Adjust the transmission power output (G-PHY) */
 void b43_set_txpower_g(struct b43_wldev *dev,
@@ -763,366 +784,96 @@ static void b43_phy_init_pctl(struct b43_wldev *dev)
 	b43_shm_clear_tssi(dev);
 }
 
-static void b43_phy_agcsetup(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 offset = 0x0000;
-
-	if (phy->rev == 1)
-		offset = 0x4C00;
-
-	b43_ofdmtab_write16(dev, offset, 0, 0x00FE);
-	b43_ofdmtab_write16(dev, offset, 1, 0x000D);
-	b43_ofdmtab_write16(dev, offset, 2, 0x0013);
-	b43_ofdmtab_write16(dev, offset, 3, 0x0019);
-
-	if (phy->rev == 1) {
-		b43_ofdmtab_write16(dev, 0x1800, 0, 0x2710);
-		b43_ofdmtab_write16(dev, 0x1801, 0, 0x9B83);
-		b43_ofdmtab_write16(dev, 0x1802, 0, 0x9B83);
-		b43_ofdmtab_write16(dev, 0x1803, 0, 0x0F8D);
-		b43_phy_write(dev, 0x0455, 0x0004);
-	}
-
-	b43_phy_write(dev, 0x04A5, (b43_phy_read(dev, 0x04A5)
-				    & 0x00FF) | 0x5700);
-	b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
-				    & 0xFF80) | 0x000F);
-	b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
-				    & 0xC07F) | 0x2B80);
-	b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
-				    & 0xF0FF) | 0x0300);
-
-	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
-			  | 0x0008);
-
-	b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
-				    & 0xFFF0) | 0x0008);
-	b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
-				    & 0xF0FF) | 0x0600);
-	b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
-				    & 0xF0FF) | 0x0700);
-	b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
-				    & 0xF0FF) | 0x0100);
-
-	if (phy->rev == 1) {
-		b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
-					    & 0xFFF0) | 0x0007);
-	}
-
-	b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
-				    & 0xFF00) | 0x001C);
-	b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
-				    & 0xC0FF) | 0x0200);
-	b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
-				    & 0xFF00) | 0x001C);
-	b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
-				    & 0xFF00) | 0x0020);
-	b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
-				    & 0xC0FF) | 0x0200);
-	b43_phy_write(dev, 0x0482, (b43_phy_read(dev, 0x0482)
-				    & 0xFF00) | 0x002E);
-	b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
-				    & 0x00FF) | 0x1A00);
-	b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
-				    & 0xFF00) | 0x0028);
-	b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
-				    & 0x00FF) | 0x2C00);
-
-	if (phy->rev == 1) {
-		b43_phy_write(dev, 0x0430, 0x092B);
-		b43_phy_write(dev, 0x041B, (b43_phy_read(dev, 0x041B)
-					    & 0xFFE1) | 0x0002);
-	} else {
-		b43_phy_write(dev, 0x041B, b43_phy_read(dev, 0x041B)
-			      & 0xFFE1);
-		b43_phy_write(dev, 0x041F, 0x287A);
-		b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
-					    & 0xFFF0) | 0x0004);
-	}
-
-	if (phy->rev >= 6) {
-		b43_phy_write(dev, 0x0422, 0x287A);
-		b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
-					    & 0x0FFF) | 0x3000);
-	}
-
-	b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-				    & 0x8080) | 0x7874);
-	b43_phy_write(dev, 0x048E, 0x1C00);
-
-	offset = 0x0800;
-	if (phy->rev == 1) {
-		offset = 0x5400;
-		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-					    & 0xF0FF) | 0x0600);
-		b43_phy_write(dev, 0x048B, 0x005E);
-		b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
-					    & 0xFF00) | 0x001E);
-		b43_phy_write(dev, 0x048D, 0x0002);
-	}
-	b43_ofdmtab_write16(dev, offset, 0, 0x00);
-	b43_ofdmtab_write16(dev, offset, 1, 0x07);
-	b43_ofdmtab_write16(dev, offset, 2, 0x10);
-	b43_ofdmtab_write16(dev, offset, 3, 0x1C);
-
-	if (phy->rev >= 6) {
-		b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
-			      & 0xFFFC);
-		b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
-			      & 0xEFFF);
-	}
-}
-
-static void b43_phy_setupg(struct b43_wldev *dev)
+static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable)
 {
-	struct ssb_bus *bus = dev->dev->bus;
-	struct b43_phy *phy = &dev->phy;
-	u16 i;
-
-	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
-	if (phy->rev == 1) {
-		b43_phy_write(dev, 0x0406, 0x4F19);
-		b43_phy_write(dev, B43_PHY_G_CRS,
-			      (b43_phy_read(dev, B43_PHY_G_CRS) & 0xFC3F) |
-			      0x0340);
-		b43_phy_write(dev, 0x042C, 0x005A);
-		b43_phy_write(dev, 0x0427, 0x001A);
-
-		for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x5800, i,
-					    b43_tab_finefreqg[i]);
-		for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg1[i]);
-		for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x2000, i, b43_tab_rotor[i]);
-	} else {
-		/* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
-		b43_nrssi_hw_write(dev, 0xBA98, (s16) 0x7654);
-
-		if (phy->rev == 2) {
-			b43_phy_write(dev, 0x04C0, 0x1861);
-			b43_phy_write(dev, 0x04C1, 0x0271);
-		} else if (phy->rev > 2) {
-			b43_phy_write(dev, 0x04C0, 0x0098);
-			b43_phy_write(dev, 0x04C1, 0x0070);
-			b43_phy_write(dev, 0x04C9, 0x0080);
-		}
-		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x800);
-
-		for (i = 0; i < 64; i++)
-			b43_ofdmtab_write16(dev, 0x4000, i, i);
-		for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg2[i]);
-	}
-
-	if (phy->rev <= 2)
-		for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1400, i,
-					    b43_tab_noisescaleg1[i]);
-	else if ((phy->rev >= 7) && (b43_phy_read(dev, 0x0449) & 0x0200))
-		for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1400, i,
-					    b43_tab_noisescaleg3[i]);
-	else
-		for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1400, i,
-					    b43_tab_noisescaleg2[i]);
-
-	if (phy->rev == 2)
-		for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x5000, i,
-					    b43_tab_sigmasqr1[i]);
-	else if ((phy->rev > 2) && (phy->rev <= 8))
-		for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x5000, i,
-					    b43_tab_sigmasqr2[i]);
-
-	if (phy->rev == 1) {
-		for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
-			b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
-		for (i = 4; i < 20; i++)
-			b43_ofdmtab_write16(dev, 0x5400, i, 0x0020);
-		b43_phy_agcsetup(dev);
-
-		if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-		    (bus->boardinfo.type == SSB_BOARD_BU4306) &&
-		    (bus->boardinfo.rev == 0x17))
-			return;
-
-		b43_ofdmtab_write16(dev, 0x5001, 0, 0x0002);
-		b43_ofdmtab_write16(dev, 0x5002, 0, 0x0001);
-	} else {
-		for (i = 0; i < 0x20; i++)
-			b43_ofdmtab_write16(dev, 0x1000, i, 0x0820);
-		b43_phy_agcsetup(dev);
-		b43_phy_read(dev, 0x0400);	/* dummy read */
-		b43_phy_write(dev, 0x0403, 0x1000);
-		b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
-		b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
-
-		if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-		    (bus->boardinfo.type == SSB_BOARD_BU4306) &&
-		    (bus->boardinfo.rev == 0x17))
-			return;
-
-		b43_ofdmtab_write16(dev, 0x0401, 0, 0x0002);
-		b43_ofdmtab_write16(dev, 0x0402, 0, 0x0001);
-	}
-}
-
-/* Initialize the noisescaletable for APHY */
-static void b43_phy_init_noisescaletbl(struct b43_wldev *dev)
-{
-	struct b43_phy *phy = &dev->phy;
 	int i;
 
-	for (i = 0; i < 12; i++) {
-		if (phy->rev == 2)
-			b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+	if (dev->phy.rev < 3) {
+		if (enable)
+			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8);
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, 0xFFF8);
+			}
 		else
-			b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
-	}
-	if (phy->rev == 2)
-		b43_ofdmtab_write16(dev, 0x1400, i, 0x6700);
-	else
-		b43_ofdmtab_write16(dev, 0x1400, i, 0x2300);
-	for (i = 0; i < 11; i++) {
-		if (phy->rev == 2)
-			b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) {
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]);
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]);
+			}
+	} else {
+		if (enable)
+			for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++)
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, 0x0820);
 		else
-			b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
+			for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++)
+				b43_ofdmtab_write16(dev,
+					B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]);
 	}
-	if (phy->rev == 2)
-		b43_ofdmtab_write16(dev, 0x1400, i, 0x0067);
-	else
-		b43_ofdmtab_write16(dev, 0x1400, i, 0x0023);
 }
 
-static void b43_phy_setupa(struct b43_wldev *dev)
+static void b43_phy_ww(struct b43_wldev *dev)
 {
-	struct b43_phy *phy = &dev->phy;
-	u16 i;
-
-	B43_WARN_ON(phy->type != B43_PHYTYPE_A);
-	switch (phy->rev) {
-	case 2:
-		b43_phy_write(dev, 0x008E, 0x3800);
-		b43_phy_write(dev, 0x0035, 0x03FF);
-		b43_phy_write(dev, 0x0036, 0x0400);
-
-		b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
-
-		b43_phy_write(dev, 0x001C, 0x0FF9);
-		b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
-		b43_ofdmtab_write16(dev, 0x3C0C, 0, 0x07BF);
-		b43_radio_write16(dev, 0x0002, 0x07BF);
-
-		b43_phy_write(dev, 0x0024, 0x4680);
-		b43_phy_write(dev, 0x0020, 0x0003);
-		b43_phy_write(dev, 0x001D, 0x0F40);
-		b43_phy_write(dev, 0x001F, 0x1C00);
-
-		b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
-					    & 0x00FF) | 0x0400);
-		b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B)
-			      & 0xFBFF);
-		b43_phy_write(dev, 0x008E, 0x58C1);
-
-		b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
-		b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
-		b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
-		b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
-		b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
-
-		b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0000, 1, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0000, 2, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0000, 3, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0000, 4, 0x0015);
-		b43_ofdmtab_write16(dev, 0x0000, 5, 0x0015);
-		b43_ofdmtab_write16(dev, 0x0000, 6, 0x0019);
-
-		b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
-		b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
-		b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
-
-		for (i = 0; i < 16; i++)
-			b43_ofdmtab_write16(dev, 0x4000, i, (0x8 + i) & 0x000F);
-
-		b43_ofdmtab_write16(dev, 0x3003, 0, 0x1044);
-		b43_ofdmtab_write16(dev, 0x3004, 0, 0x7201);
-		b43_ofdmtab_write16(dev, 0x3006, 0, 0x0040);
-		b43_ofdmtab_write16(dev, 0x3001, 0,
-				    (b43_ofdmtab_read16(dev, 0x3001, 0) &
-				     0x0010) | 0x0008);
-
-		for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x5800, i,
-					    b43_tab_finefreqa[i]);
-		for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++)
-			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea2[i]);
-		for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
-			b43_ofdmtab_write32(dev, 0x2000, i, b43_tab_rotor[i]);
-		b43_phy_init_noisescaletbl(dev);
-		for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
-			b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
-		break;
-	case 3:
-		for (i = 0; i < 64; i++)
-			b43_ofdmtab_write16(dev, 0x4000, i, i);
-
-		b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
-
-		b43_phy_write(dev, 0x001C, 0x0FF9);
-		b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
-		b43_radio_write16(dev, 0x0002, 0x07BF);
-
-		b43_phy_write(dev, 0x0024, 0x4680);
-		b43_phy_write(dev, 0x0020, 0x0003);
-		b43_phy_write(dev, 0x001D, 0x0F40);
-		b43_phy_write(dev, 0x001F, 0x1C00);
-		b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
-					    & 0x00FF) | 0x0400);
-
-		b43_ofdmtab_write16(dev, 0x3000, 1,
-				    (b43_ofdmtab_read16(dev, 0x3000, 1)
-				     & 0x0010) | 0x0008);
-		for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) {
-			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea3[i]);
-		}
-		b43_phy_init_noisescaletbl(dev);
-		for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) {
-			b43_ofdmtab_write16(dev, 0x5000, i,
-					    b43_tab_sigmasqr1[i]);
-		}
-
-		b43_phy_write(dev, 0x0003, 0x1808);
-
-		b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
-		b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
-		b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
-		b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
-		b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
-
-		b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0001, 0, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0002, 0, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0003, 0, 0x0013);
-		b43_ofdmtab_write16(dev, 0x0004, 0, 0x0015);
-		b43_ofdmtab_write16(dev, 0x0005, 0, 0x0015);
-		b43_ofdmtab_write16(dev, 0x0006, 0, 0x0019);
-
-		b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
-		b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
-		b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
+	u16 b, curr_s, best_s = 0xFFFF;
+	int i;
 
-		b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
-		b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
-		break;
-	default:
-		B43_WARN_ON(1);
+	b43_phy_write(dev, B43_PHY_CRS0,
+		b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN);
+	b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+		b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000);
+	b43_phy_write(dev, B43_PHY_OFDM(0x82),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300);
+	b43_radio_write16(dev, 0x0009,
+		b43_radio_read16(dev, 0x0009) | 0x0080);
+	b43_radio_write16(dev, 0x0012,
+		(b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002);
+	b43_wa_initgains(dev);
+	b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5);
+	b = b43_phy_read(dev, B43_PHY_PWRDOWN);
+	b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005);
+	b43_radio_write16(dev, 0x0004,
+		b43_radio_read16(dev, 0x0004) | 0x0004);
+	for (i = 0x10; i <= 0x20; i++) {
+		b43_radio_write16(dev, 0x0013, i);
+		curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF;
+		if (!curr_s) {
+			best_s = 0x0000;
+			break;
+		} else if (curr_s >= 0x0080)
+			curr_s = 0x0100 - curr_s;
+		if (curr_s < best_s)
+			best_s = curr_s;
 	}
+	b43_phy_write(dev, B43_PHY_PWRDOWN, b);
+	b43_radio_write16(dev, 0x0004,
+		b43_radio_read16(dev, 0x0004) & 0xFFFB);
+	b43_radio_write16(dev, 0x0013, best_s);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0);
+	b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF);
+	b43_phy_write(dev, B43_PHY_OFDM(0xBB),
+		(b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
+	b43_phy_write(dev, B43_PHY_OFDM61,
+		(b43_phy_read(dev, B43_PHY_OFDM61 & 0xFE1F)) | 0x0120);
+	b43_phy_write(dev, B43_PHY_OFDM(0x13),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
+	b43_phy_write(dev, B43_PHY_OFDM(0x14),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017);
+	for (i = 0; i < 6; i++)
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013);
+	b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030);
+	b43_phy_write(dev, B43_PHY_CRS0,
+		b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
 }
 
 /* Initialize APHY. This is also called for the GPHY in some cases. */
@@ -1130,64 +881,54 @@ static void b43_phy_inita(struct b43_wldev *dev)
 {
 	struct ssb_bus *bus = dev->dev->bus;
 	struct b43_phy *phy = &dev->phy;
-	u16 tval;
 
 	might_sleep();
 
-	if (phy->type == B43_PHYTYPE_A) {
-		b43_phy_setupa(dev);
-	} else {
-		b43_phy_setupg(dev);
-		if (phy->gmode &&
-		    (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL))
-			b43_phy_write(dev, 0x046E, 0x03CF);
-		return;
+	if (phy->rev >= 6) {
+		if (phy->type == B43_PHYTYPE_A)
+			b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+				b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000);
+		if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
+			b43_phy_write(dev, B43_PHY_ENCORE,
+				b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010);
+		else
+			b43_phy_write(dev, B43_PHY_ENCORE,
+				b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010);
 	}
 
-	b43_phy_write(dev, B43_PHY_A_CRS,
-		      (b43_phy_read(dev, B43_PHY_A_CRS) & 0xF83C) | 0x0340);
-	b43_phy_write(dev, 0x0034, 0x0001);
+	b43_wa_all(dev);
 
-	//TODO: RSSI AGC
-	b43_phy_write(dev, B43_PHY_A_CRS,
-		      b43_phy_read(dev, B43_PHY_A_CRS) | (1 << 14));
-	b43_radio_init2060(dev);
+	if (phy->type == B43_PHYTYPE_A) {
+		if (phy->gmode && (phy->rev < 3))
+			b43_phy_write(dev, 0x0034,
+				b43_phy_read(dev, 0x0034) | 0x0001);
+		b43_phy_rssiagc(dev, 0);
 
-	if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-	    ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
-	     (bus->boardinfo.type == SSB_BOARD_BU4309))) {
-		if (phy->lofcal == 0xFFFF) {
-			//TODO: LOF Cal
-			b43_radio_set_tx_iq(dev);
-		} else
-			b43_radio_write16(dev, 0x001E, phy->lofcal);
-	}
+		b43_phy_write(dev, B43_PHY_CRS0,
+			b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
 
-	b43_phy_write(dev, 0x007A, 0xF111);
+		b43_radio_init2060(dev);
 
-	if (phy->cur_idle_tssi == 0) {
-		b43_radio_write16(dev, 0x0019, 0x0000);
-		b43_radio_write16(dev, 0x0017, 0x0020);
-
-		tval = b43_ofdmtab_read16(dev, 0x3001, 0);
-		if (phy->rev == 1) {
-			b43_ofdmtab_write16(dev, 0x3001, 0,
-					    (b43_ofdmtab_read16(dev, 0x3001, 0)
-					     & 0xFF87)
-					    | 0x0058);
-		} else {
-			b43_ofdmtab_write16(dev, 0x3001, 0,
-					    (b43_ofdmtab_read16(dev, 0x3001, 0)
-					     & 0xFFC3)
-					    | 0x002C);
+		if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+		    ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
+		     (bus->boardinfo.type == SSB_BOARD_BU4309))) {
+			; //TODO: A PHY LO
 		}
-		b43_dummy_transmission(dev);
-		phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_A_PCTL);
-		b43_ofdmtab_write16(dev, 0x3001, 0, tval);
 
-		b43_radio_set_txpower_a(dev, 0x0018);
+		if (phy->rev >= 3)
+			b43_phy_ww(dev);
+
+		hardware_pctl_init_aphy(dev);
+
+		//TODO: radar detection
+	}
+
+	if ((phy->type == B43_PHYTYPE_G) &&
+	    (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
+		b43_phy_write(dev, B43_PHY_OFDM(0x6E),
+				  (b43_phy_read(dev, B43_PHY_OFDM(0x6E))
+				   & 0xE000) | 0x3CF);
 	}
-	b43_shm_clear_tssi(dev);
 }
 
 static void b43_phy_initb2(struct b43_wldev *dev)
@@ -1286,7 +1027,7 @@ static void b43_phy_initb4(struct b43_wldev *dev)
 	if (phy->radio_ver == 0x2050)
 		b43_phy_write(dev, 0x002A, 0x88C2);
 	b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
 		b43_calc_nrssi_slope(dev);
 		b43_calc_nrssi_threshold(dev);
 	}
@@ -1433,7 +1174,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
 		b43_radio_write16(dev, 0x5A, 0x88);
 		b43_radio_write16(dev, 0x5B, 0x6B);
 		b43_radio_write16(dev, 0x5C, 0x0F);
-		if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_ALTIQ) {
+		if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
 			b43_radio_write16(dev, 0x5D, 0xFA);
 			b43_radio_write16(dev, 0x5E, 0xD8);
 		} else {
@@ -1525,7 +1266,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
 		b43_phy_write(dev, 0x0062, 0x0007);
 		b43_radio_init2050(dev);
 		b43_lo_g_measure(dev);
-		if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+		if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) {
 			b43_calc_nrssi_slope(dev);
 			b43_calc_nrssi_threshold(dev);
 		}
@@ -1552,14 +1293,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 		backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
 		backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
 	}
-	backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A));
-	backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59));
-	backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58));
-	backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A));
-	backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03));
+	backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A));
+	backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59));
+	backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58));
+	backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A));
+	backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03));
 	backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
 	backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
-	backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B));
+	backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B));
 	backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
 	backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
 	backup_bband = phy->bbatt.att;
@@ -1601,12 +1342,12 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 		      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
 		       & 0xFFCF) | 0x10);
 
-	b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780);
-	b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-	b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+	b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780);
+	b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
 
-	b43_phy_write(dev, B43_PHY_BASE(0x0A),
-		      b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000);
+	b43_phy_write(dev, B43_PHY_CCK(0x0A),
+		      b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000);
 	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
 		b43_phy_write(dev, B43_PHY_ANALOGOVER,
 			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
@@ -1614,8 +1355,8 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 			      b43_phy_read(dev,
 					   B43_PHY_ANALOGOVERVAL) & 0xFFFB);
 	}
-	b43_phy_write(dev, B43_PHY_BASE(0x03),
-		      (b43_phy_read(dev, B43_PHY_BASE(0x03))
+	b43_phy_write(dev, B43_PHY_CCK(0x03),
+		      (b43_phy_read(dev, B43_PHY_CCK(0x03))
 		       & 0xFF9F) | 0x40);
 
 	if (phy->radio_rev == 8) {
@@ -1633,11 +1374,11 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
 	b43_phy_write(dev, B43_PHY_LO_CTL, 0);
 
-	b43_phy_write(dev, B43_PHY_BASE(0x2B),
-		      (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+	b43_phy_write(dev, B43_PHY_CCK(0x2B),
+		      (b43_phy_read(dev, B43_PHY_CCK(0x2B))
 		       & 0xFFC0) | 0x01);
-	b43_phy_write(dev, B43_PHY_BASE(0x2B),
-		      (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+	b43_phy_write(dev, B43_PHY_CCK(0x2B),
+		      (b43_phy_read(dev, B43_PHY_CCK(0x2B))
 		       & 0xC0FF) | 0x800);
 
 	b43_phy_write(dev, B43_PHY_RFOVER,
@@ -1645,7 +1386,7 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 	b43_phy_write(dev, B43_PHY_RFOVERVAL,
 		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF);
 
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
 		if (phy->rev >= 7) {
 			b43_phy_write(dev, B43_PHY_RFOVER,
 				      b43_phy_read(dev, B43_PHY_RFOVER)
@@ -1708,14 +1449,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
 		b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
 		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
 	}
-	b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]);
-	b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]);
-	b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]);
-	b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]);
-	b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]);
+	b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]);
+	b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]);
+	b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]);
+	b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]);
 	b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
 	b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
-	b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]);
+	b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]);
 	b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
 
 	b43_phy_set_baseband_attenuation(dev, backup_bband);
@@ -1807,26 +1548,26 @@ static void b43_phy_initg(struct b43_wldev *dev)
 					  | phy->lo_control->tx_bias);
 		}
 		if (phy->rev >= 6) {
-			b43_phy_write(dev, B43_PHY_BASE(0x36),
-				      (b43_phy_read(dev, B43_PHY_BASE(0x36))
+			b43_phy_write(dev, B43_PHY_CCK(0x36),
+				      (b43_phy_read(dev, B43_PHY_CCK(0x36))
 				       & 0x0FFF) | (phy->lo_control->
 						    tx_bias << 12));
 		}
-		if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL)
-			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075);
+		if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
 		else
-			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F);
+			b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
 		if (phy->rev < 2)
-			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101);
+			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101);
 		else
-			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202);
+			b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202);
 	}
 	if (phy->gmode || phy->rev >= 2) {
 		b43_lo_g_adjust(dev);
 		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
 	}
 
-	if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+	if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
 		/* The specs state to update the NRSSI LT with
 		 * the value 0x7FFFFFFF here. I think that is some weird
 		 * compiler optimization in the original driver.
@@ -1995,7 +1736,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
 			int rfatt_delta, bbatt_delta;
 			int rfatt, bbatt;
 			u8 tx_control;
-			unsigned long phylock_flags;
 
 			tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
 			v0 = (s8) (tmp & 0x00FF);
@@ -2036,16 +1776,15 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
 			estimated_pwr =
 			    b43_phy_estimate_power_out(dev, average);
 
-			max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
-			if ((dev->dev->bus->sprom.r1.
-			     boardflags_lo & B43_BFL_PACTRL)
-			    && (phy->type == B43_PHYTYPE_G))
+			max_pwr = dev->dev->bus->sprom.maxpwr_bg;
+			if ((dev->dev->bus->sprom.boardflags_lo
+			    & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G))
 				max_pwr -= 0x3;
 			if (unlikely(max_pwr <= 0)) {
 				b43warn(dev->wl,
 					"Invalid max-TX-power value in SPROM.\n");
 				max_pwr = 60;	/* fake it */
-				dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+				dev->dev->bus->sprom.maxpwr_bg = max_pwr;
 			}
 
 			/*TODO:
@@ -2103,7 +1842,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
 						    B43_TXCTL_TXMIX;
 						rfatt += 2;
 						bbatt += 2;
-					} else if (dev->dev->bus->sprom.r1.
+					} else if (dev->dev->bus->sprom.
 						   boardflags_lo &
 						   B43_BFL_PACTRL) {
 						bbatt += 4 * (rfatt - 2);
@@ -2127,15 +1866,18 @@ void b43_phy_xmitpower(struct b43_wldev *dev)
 			phy->bbatt.att = bbatt;
 
 			/* Adjust the hardware */
-			b43_phy_lock(dev, phylock_flags);
+			b43_phy_lock(dev);
 			b43_radio_lock(dev);
 			b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
 					  phy->tx_control);
 			b43_lo_g_ctl_mark_cur_used(dev);
 			b43_radio_unlock(dev);
-			b43_phy_unlock(dev, phylock_flags);
+			b43_phy_unlock(dev);
 			break;
 		}
+	case B43_PHYTYPE_N:
+		b43_nphy_xmitpower(dev);
+		break;
 	default:
 		B43_WARN_ON(1);
 	}
@@ -2179,13 +1921,13 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
 	s8 *dyn_tssi2dbm;
 
 	if (phy->type == B43_PHYTYPE_A) {
-		pab0 = (s16) (dev->dev->bus->sprom.r1.pa1b0);
-		pab1 = (s16) (dev->dev->bus->sprom.r1.pa1b1);
-		pab2 = (s16) (dev->dev->bus->sprom.r1.pa1b2);
+		pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
+		pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
+		pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
 	} else {
-		pab0 = (s16) (dev->dev->bus->sprom.r1.pa0b0);
-		pab1 = (s16) (dev->dev->bus->sprom.r1.pa0b1);
-		pab2 = (s16) (dev->dev->bus->sprom.r1.pa0b2);
+		pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
+		pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
+		pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
 	}
 
 	if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
@@ -2198,17 +1940,17 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
 	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
 		/* The pabX values are set in SPROM. Use them. */
 		if (phy->type == B43_PHYTYPE_A) {
-			if ((s8) dev->dev->bus->sprom.r1.itssi_a != 0 &&
-			    (s8) dev->dev->bus->sprom.r1.itssi_a != -1)
+			if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
+			    (s8) dev->dev->bus->sprom.itssi_a != -1)
 				phy->tgt_idle_tssi =
-				    (s8) (dev->dev->bus->sprom.r1.itssi_a);
+				    (s8) (dev->dev->bus->sprom.itssi_a);
 			else
 				phy->tgt_idle_tssi = 62;
 		} else {
-			if ((s8) dev->dev->bus->sprom.r1.itssi_bg != 0 &&
-			    (s8) dev->dev->bus->sprom.r1.itssi_bg != -1)
+			if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
+			    (s8) dev->dev->bus->sprom.itssi_bg != -1)
 				phy->tgt_idle_tssi =
-				    (s8) (dev->dev->bus->sprom.r1.itssi_bg);
+				    (s8) (dev->dev->bus->sprom.itssi_bg);
 			else
 				phy->tgt_idle_tssi = 62;
 		}
@@ -2255,41 +1997,44 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
 int b43_phy_init(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
-	int err = -ENODEV;
+	bool unsupported = 0;
+	int err = 0;
 
 	switch (phy->type) {
 	case B43_PHYTYPE_A:
-		if (phy->rev == 2 || phy->rev == 3) {
+		if (phy->rev == 2 || phy->rev == 3)
 			b43_phy_inita(dev);
-			err = 0;
-		}
+		else
+			unsupported = 1;
 		break;
 	case B43_PHYTYPE_B:
 		switch (phy->rev) {
 		case 2:
 			b43_phy_initb2(dev);
-			err = 0;
 			break;
 		case 4:
 			b43_phy_initb4(dev);
-			err = 0;
 			break;
 		case 5:
 			b43_phy_initb5(dev);
-			err = 0;
 			break;
 		case 6:
 			b43_phy_initb6(dev);
-			err = 0;
 			break;
+		default:
+			unsupported = 1;
 		}
 		break;
 	case B43_PHYTYPE_G:
 		b43_phy_initg(dev);
-		err = 0;
 		break;
+	case B43_PHYTYPE_N:
+		err = b43_phy_initn(dev);
+		break;
+	default:
+		unsupported = 1;
 	}
-	if (err)
+	if (unsupported)
 		b43err(dev->wl, "Unknown PHYTYPE found\n");
 
 	return err;
@@ -2392,6 +2137,9 @@ void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
 		    << B43_PHY_BBANDCFG_RXANT_SHIFT;
 		b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp);
 		break;
+	case B43_PHYTYPE_N:
+		b43_nphy_set_rxantenna(dev, antenna);
+		break;
 	default:
 		B43_WARN_ON(1);
 	}
@@ -2421,6 +2169,7 @@ void b43_radio_lock(struct b43_wldev *dev)
 	u32 macctl;
 
 	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
 	macctl |= B43_MACCTL_RADIOLOCK;
 	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 	/* Commit the write and wait for the device
@@ -2437,6 +2186,7 @@ void b43_radio_unlock(struct b43_wldev *dev)
 	b43_read16(dev, B43_MMIO_PHY_VER);
 	/* unlock */
 	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
 	macctl &= ~B43_MACCTL_RADIOLOCK;
 	b43_write32(dev, B43_MMIO_MACCTL, macctl);
 }
@@ -2445,9 +2195,12 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
 {
 	struct b43_phy *phy = &dev->phy;
 
+	/* Offset 1 is a 32-bit register. */
+	B43_WARN_ON(offset == 1);
+
 	switch (phy->type) {
 	case B43_PHYTYPE_A:
-		offset |= 0x0040;
+		offset |= 0x40;
 		break;
 	case B43_PHYTYPE_B:
 		if (phy->radio_ver == 0x2053) {
@@ -2463,6 +2216,14 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
 	case B43_PHYTYPE_G:
 		offset |= 0x80;
 		break;
+	case B43_PHYTYPE_N:
+		offset |= 0x100;
+		break;
+	case B43_PHYTYPE_LP:
+		/* No adjustment required. */
+		break;
+	default:
+		B43_WARN_ON(1);
 	}
 
 	b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
@@ -2471,11 +2232,31 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
 
 void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val)
 {
+	/* Offset 1 is a 32-bit register. */
+	B43_WARN_ON(offset == 1);
+
 	b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
-	mmiowb();
 	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val);
 }
 
+void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
+{
+	b43_radio_write16(dev, offset,
+			  b43_radio_read16(dev, offset) & mask);
+}
+
+void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
+{
+	b43_radio_write16(dev, offset,
+			  b43_radio_read16(dev, offset) | set);
+}
+
+void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
+{
+	b43_radio_write16(dev, offset,
+			  (b43_radio_read16(dev, offset) & mask) | set);
+}
+
 static void b43_set_all_gains(struct b43_wldev *dev,
 			      s16 first, s16 second, s16 third)
 {
@@ -2605,12 +2386,11 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev)
 	u8 ret[13];
 	unsigned int channel = phy->channel;
 	unsigned int i, j, start, end;
-	unsigned long phylock_flags;
 
 	if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
 		return 0;
 
-	b43_phy_lock(dev, phylock_flags);
+	b43_phy_lock(dev);
 	b43_radio_lock(dev);
 	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
 	b43_phy_write(dev, B43_PHY_G_CRS,
@@ -2639,7 +2419,7 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev)
 			ret[j] = 1;
 	}
 	b43_radio_unlock(dev);
-	b43_phy_unlock(dev, phylock_flags);
+	b43_phy_unlock(dev);
 
 	return ret[channel - 1];
 }
@@ -3114,7 +2894,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
 			if (phy->radio_ver != 0x2050)
 				return;
 			if (!
-			    (dev->dev->bus->sprom.r1.
+			    (dev->dev->bus->sprom.
 			     boardflags_lo & B43_BFL_RSSI))
 				return;
 
@@ -3145,7 +2925,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev)
 		}
 	case B43_PHYTYPE_G:
 		if (!phy->gmode ||
-		    !(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+		    !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
 			tmp16 = b43_nrssi_hw_read(dev, 0x20);
 			if (tmp16 >= 0x20)
 				tmp16 -= 0x40;
@@ -3667,7 +3447,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev,
 		}
 
 		if ((phy->rev < 7) ||
-		    !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+		    !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
 			if (phy_register == B43_PHY_RFOVER) {
 				return 0x1B3;
 			} else if (phy_register == B43_PHY_RFOVERVAL) {
@@ -3707,7 +3487,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev,
 		}
 	} else {
 		if ((phy->rev < 7) ||
-		    !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+		    !(sprom->boardflags_lo & B43_BFL_EXTLNA)) {
 			if (phy_register == B43_PHY_RFOVER) {
 				return 0x1B3;
 			} else if (phy_register == B43_PHY_RFOVERVAL) {
@@ -3757,10 +3537,10 @@ struct init2050_saved_values {
 	u16 radio_52;
 	/* PHY registers */
 	u16 phy_pgactl;
-	u16 phy_base_5A;
-	u16 phy_base_59;
-	u16 phy_base_58;
-	u16 phy_base_30;
+	u16 phy_cck_5A;
+	u16 phy_cck_59;
+	u16 phy_cck_58;
+	u16 phy_cck_30;
 	u16 phy_rfover;
 	u16 phy_rfoverval;
 	u16 phy_analogover;
@@ -3788,15 +3568,15 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 	sav.radio_51 = b43_radio_read16(dev, 0x51);
 	sav.radio_52 = b43_radio_read16(dev, 0x52);
 	sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
-	sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A));
-	sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59));
-	sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58));
+	sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A));
+	sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59));
+	sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58));
 
 	if (phy->type == B43_PHYTYPE_B) {
-		sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
+		sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30));
 		sav.reg_3EC = b43_read16(dev, 0x3EC);
 
-		b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF);
+		b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF);
 		b43_write16(dev, 0x3EC, 0x3F3F);
 	} else if (phy->gmode || phy->rev >= 2) {
 		sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
@@ -3847,8 +3627,8 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 		b43_write16(dev, 0x03E6, 0x0122);
 	} else {
 		if (phy->analog >= 2) {
-			b43_phy_write(dev, B43_PHY_BASE(0x03),
-				      (b43_phy_read(dev, B43_PHY_BASE(0x03))
+			b43_phy_write(dev, B43_PHY_CCK(0x03),
+				      (b43_phy_read(dev, B43_PHY_CCK(0x03))
 				       & 0xFFBF) | 0x40);
 		}
 		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
@@ -3865,7 +3645,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 						   LPD(0, 1, 1)));
 	}
 	b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
-	b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403);
+	b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403);
 	if (phy->gmode || phy->rev >= 2) {
 		b43_phy_write(dev, B43_PHY_RFOVERVAL,
 			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
@@ -3881,12 +3661,12 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
 					      & 0xFFF0) | 0x0009);
 	}
-	b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 
 	for (i = 0; i < 16; i++) {
-		b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480);
-		b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-		b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+		b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480);
+		b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+		b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
 		if (phy->gmode || phy->rev >= 2) {
 			b43_phy_write(dev, B43_PHY_RFOVERVAL,
 				      radio2050_rfover_val(dev,
@@ -3912,7 +3692,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 		b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
 		udelay(20);
 		tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-		b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+		b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 		if (phy->gmode || phy->rev >= 2) {
 			b43_phy_write(dev, B43_PHY_RFOVERVAL,
 				      radio2050_rfover_val(dev,
@@ -3923,7 +3703,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 	}
 	udelay(10);
 
-	b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 	tmp1++;
 	tmp1 >>= 9;
 
@@ -3932,9 +3712,9 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 		b43_radio_write16(dev, 0x78, radio78);
 		udelay(10);
 		for (j = 0; j < 16; j++) {
-			b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80);
-			b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
-			b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+			b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80);
+			b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
+			b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
 			if (phy->gmode || phy->rev >= 2) {
 				b43_phy_write(dev, B43_PHY_RFOVERVAL,
 					      radio2050_rfover_val(dev,
@@ -3963,7 +3743,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 			b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
 			udelay(10);
 			tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
-			b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+			b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 			if (phy->gmode || phy->rev >= 2) {
 				b43_phy_write(dev, B43_PHY_RFOVERVAL,
 					      radio2050_rfover_val(dev,
@@ -3984,16 +3764,16 @@ u16 b43_radio_init2050(struct b43_wldev *dev)
 	b43_radio_write16(dev, 0x51, sav.radio_51);
 	b43_radio_write16(dev, 0x52, sav.radio_52);
 	b43_radio_write16(dev, 0x43, sav.radio_43);
-	b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A);
-	b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59);
-	b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58);
+	b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A);
+	b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59);
+	b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58);
 	b43_write16(dev, 0x3E6, sav.reg_3E6);
 	if (phy->analog != 0)
 		b43_write16(dev, 0x3F4, sav.reg_3F4);
 	b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
 	b43_synth_pu_workaround(dev, phy->channel);
 	if (phy->type == B43_PHYTYPE_B) {
-		b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30);
+		b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30);
 		b43_write16(dev, 0x3EC, sav.reg_3EC);
 	} else if (phy->gmode) {
 		b43_write16(dev, B43_MMIO_PHY_RADIO,
@@ -4103,7 +3883,8 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 	struct b43_phy *phy = &dev->phy;
 	u16 r8, tmp;
 	u16 freq;
-	u16 channelcookie;
+	u16 channelcookie, savedcookie;
+	int err = 0;
 
 	if (channel == 0xFF) {
 		switch (phy->type) {
@@ -4114,6 +3895,10 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 		case B43_PHYTYPE_G:
 			channel = B43_DEFAULT_CHANNEL_BG;
 			break;
+		case B43_PHYTYPE_N:
+			//FIXME check if we are on 2.4GHz or 5GHz and set a default channel.
+			channel = 1;
+			break;
 		default:
 			B43_WARN_ON(1);
 		}
@@ -4123,13 +3908,18 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 	 * firmware from sending ghost packets.
 	 */
 	channelcookie = channel;
-	if (phy->type == B43_PHYTYPE_A)
+	if (0 /*FIXME on 5Ghz */)
 		channelcookie |= 0x100;
+	//FIXME set 40Mhz flag if required
+	savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
 	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
 
-	if (phy->type == B43_PHYTYPE_A) {
-		if (channel > 200)
-			return -EINVAL;
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		if (channel > 200) {
+			err = -EINVAL;
+			goto out;
+		}
 		freq = channel2freq_a(channel);
 
 		r8 = b43_radio_read16(dev, 0x0008);
@@ -4176,9 +3966,12 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 		b43_radio_set_tx_iq(dev);
 		//TODO: TSSI2dbm workaround
 		b43_phy_xmitpower(dev);	//FIXME correct?
-	} else {
-		if ((channel < 1) || (channel > 14))
-			return -EINVAL;
+		break;
+	case B43_PHYTYPE_G:
+		if ((channel < 1) || (channel > 14)) {
+			err = -EINVAL;
+			goto out;
+		}
 
 		if (synthetic_pu_workaround)
 			b43_synth_pu_workaround(dev, channel);
@@ -4186,7 +3979,7 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 		b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
 
 		if (channel == 14) {
-			if (dev->dev->bus->sprom.r1.country_code ==
+			if (dev->dev->bus->sprom.country_code ==
 			    SSB_SPROM1CCODE_JAPAN)
 				b43_hf_write(dev,
 					     b43_hf_read(dev) & ~B43_HF_ACPR);
@@ -4201,110 +3994,25 @@ int b43_radio_selectchannel(struct b43_wldev *dev,
 				    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
 				    & 0xF7BF);
 		}
+		break;
+	case B43_PHYTYPE_N:
+		err = b43_nphy_selectchannel(dev, channel);
+		if (err)
+			goto out;
+		break;
+	default:
+		B43_WARN_ON(1);
 	}
 
 	phy->channel = channel;
 	/* Wait for the radio to tune to the channel and stabilize. */
 	msleep(8);
-
-	return 0;
-}
-
-/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
-static u16 b43_get_txgain_base_band(u16 txpower)
-{
-	u16 ret;
-
-	B43_WARN_ON(txpower > 63);
-
-	if (txpower >= 54)
-		ret = 2;
-	else if (txpower >= 49)
-		ret = 4;
-	else if (txpower >= 44)
-		ret = 5;
-	else
-		ret = 6;
-
-	return ret;
-}
-
-/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
-static u16 b43_get_txgain_freq_power_amp(u16 txpower)
-{
-	u16 ret;
-
-	B43_WARN_ON(txpower > 63);
-
-	if (txpower >= 32)
-		ret = 0;
-	else if (txpower >= 25)
-		ret = 1;
-	else if (txpower >= 20)
-		ret = 2;
-	else if (txpower >= 12)
-		ret = 3;
-	else
-		ret = 4;
-
-	return ret;
-}
-
-/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
-static u16 b43_get_txgain_dac(u16 txpower)
-{
-	u16 ret;
-
-	B43_WARN_ON(txpower > 63);
-
-	if (txpower >= 54)
-		ret = txpower - 53;
-	else if (txpower >= 49)
-		ret = txpower - 42;
-	else if (txpower >= 44)
-		ret = txpower - 37;
-	else if (txpower >= 32)
-		ret = txpower - 32;
-	else if (txpower >= 25)
-		ret = txpower - 20;
-	else if (txpower >= 20)
-		ret = txpower - 13;
-	else if (txpower >= 12)
-		ret = txpower - 8;
-	else
-		ret = txpower;
-
-	return ret;
-}
-
-static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower)
-{
-	struct b43_phy *phy = &dev->phy;
-	u16 pamp, base, dac, t;
-
-	txpower = limit_value(txpower, 0, 63);
-
-	pamp = b43_get_txgain_freq_power_amp(txpower);
-	pamp <<= 5;
-	pamp &= 0x00E0;
-	b43_phy_write(dev, 0x0019, pamp);
-
-	base = b43_get_txgain_base_band(txpower);
-	base &= 0x000F;
-	b43_phy_write(dev, 0x0017, base | 0x0020);
-
-	t = b43_ofdmtab_read16(dev, 0x3000, 1);
-	t &= 0x0007;
-
-	dac = b43_get_txgain_dac(txpower);
-	dac <<= 3;
-	dac |= t;
-
-	b43_ofdmtab_write16(dev, 0x3000, 1, dac);
-
-	phy->txpwr_offset = txpower;
-
-	//TODO: FuncPlaceholder (Adjust BB loft cancel)
+out:
+	if (err) {
+		b43_shm_write16(dev, B43_SHM_SHARED,
+				B43_SHM_SH_CHAN, savedcookie);
+	}
+	return err;
 }
 
 void b43_radio_turn_on(struct b43_wldev *dev)
@@ -4344,6 +4052,9 @@ void b43_radio_turn_on(struct b43_wldev *dev)
 		err |= b43_radio_selectchannel(dev, channel, 0);
 		B43_WARN_ON(err);
 		break;
+	case B43_PHYTYPE_N:
+		b43_nphy_radio_turn_on(dev);
+		break;
 	default:
 		B43_WARN_ON(1);
 	}
@@ -4357,13 +4068,17 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force)
 	if (!phy->radio_on && !force)
 		return;
 
-	if (phy->type == B43_PHYTYPE_A) {
+	switch (phy->type) {
+	case B43_PHYTYPE_N:
+		b43_nphy_radio_turn_off(dev);
+		break;
+	case B43_PHYTYPE_A:
 		b43_radio_write16(dev, 0x0004, 0x00FF);
 		b43_radio_write16(dev, 0x0005, 0x00FB);
 		b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
 		b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
-	}
-	if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) {
+		break;
+	case B43_PHYTYPE_G: {
 		u16 rfover, rfoverval;
 
 		rfover = b43_phy_read(dev, B43_PHY_RFOVER);
@@ -4375,7 +4090,10 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force)
 		}
 		b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
 		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
-	} else
-		b43_phy_write(dev, 0x0015, 0xAA00);
+		break;
+	}
+	default:
+		B43_WARN_ON(1);
+	}
 	phy->radio_on = 0;
 }
diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h
index c64d74504fc0..6d165d822175 100644
--- a/drivers/net/wireless/b43/phy.h
+++ b/drivers/net/wireless/b43/phy.h
@@ -9,14 +9,21 @@ struct b43_phy;
 /*** PHY Registers ***/
 
 /* Routing */
-#define B43_PHYROUTE_OFDM_GPHY		0x400
-#define B43_PHYROUTE_EXT_GPHY		0x800
-
-/* Base registers. */
-#define B43_PHY_BASE(reg)		(reg)
-/* OFDM (A) registers of a G-PHY */
+#define B43_PHYROUTE			0x0C00 /* PHY register routing bits mask */
+#define  B43_PHYROUTE_BASE		0x0000 /* Base registers */
+#define  B43_PHYROUTE_OFDM_GPHY		0x0400 /* OFDM register routing for G-PHYs */
+#define  B43_PHYROUTE_EXT_GPHY		0x0800 /* Extended G-PHY registers */
+#define  B43_PHYROUTE_N_BMODE		0x0C00 /* N-PHY BMODE registers */
+
+/* CCK (B-PHY) registers. */
+#define B43_PHY_CCK(reg)		((reg) | B43_PHYROUTE_BASE)
+/* N-PHY registers. */
+#define B43_PHY_N(reg)			((reg) | B43_PHYROUTE_BASE)
+/* N-PHY BMODE registers. */
+#define B43_PHY_N_BMODE(reg)		((reg) | B43_PHYROUTE_N_BMODE)
+/* OFDM (A-PHY) registers. */
 #define B43_PHY_OFDM(reg)		((reg) | B43_PHYROUTE_OFDM_GPHY)
-/* Extended G-PHY registers */
+/* Extended G-PHY registers. */
 #define B43_PHY_EXTG(reg)		((reg) | B43_PHYROUTE_EXT_GPHY)
 
 /* OFDM (A) PHY Registers */
@@ -25,10 +32,13 @@ struct b43_phy;
 #define  B43_PHY_BBANDCFG_RXANT		0x180	/* RX Antenna selection */
 #define  B43_PHY_BBANDCFG_RXANT_SHIFT	7
 #define B43_PHY_PWRDOWN			B43_PHY_OFDM(0x03)	/* Powerdown */
-#define B43_PHY_CRSTHRES1		B43_PHY_OFDM(0x06)	/* CRS Threshold 1 */
+#define B43_PHY_CRSTHRES1_R1		B43_PHY_OFDM(0x06)	/* CRS Threshold 1 (phy.rev 1 only) */
 #define B43_PHY_LNAHPFCTL		B43_PHY_OFDM(0x1C)	/* LNA/HPF control */
+#define B43_PHY_LPFGAINCTL		B43_PHY_OFDM(0x20)	/* LPF Gain control */
 #define B43_PHY_ADIVRELATED		B43_PHY_OFDM(0x27)	/* FIXME rename */
 #define B43_PHY_CRS0			B43_PHY_OFDM(0x29)
+#define  B43_PHY_CRS0_EN		0x4000
+#define B43_PHY_PEAK_COUNT		B43_PHY_OFDM(0x30)
 #define B43_PHY_ANTDWELL		B43_PHY_OFDM(0x2B)	/* Antenna dwell */
 #define  B43_PHY_ANTDWELL_AUTODIV1	0x0100	/* Automatic RX diversity start antenna */
 #define B43_PHY_ENCORE			B43_PHY_OFDM(0x49)	/* "Encore" (RangeMax / BroadRange) */
@@ -37,6 +47,7 @@ struct b43_phy;
 #define B43_PHY_OFDM61			B43_PHY_OFDM(0x61)	/* FIXME rename */
 #define  B43_PHY_OFDM61_10		0x0010	/* FIXME rename */
 #define B43_PHY_IQBAL			B43_PHY_OFDM(0x69)	/* I/Q balance */
+#define B43_PHY_BBTXDC_BIAS		B43_PHY_OFDM(0x6B)	/* Baseband TX DC bias */
 #define B43_PHY_OTABLECTL		B43_PHY_OFDM(0x72)	/* OFDM table control (see below) */
 #define  B43_PHY_OTABLEOFF		0x03FF	/* OFDM table offset (see below) */
 #define  B43_PHY_OTABLENR		0xFC00	/* OFDM table number (see below) */
@@ -44,6 +55,9 @@ struct b43_phy;
 #define B43_PHY_OTABLEI			B43_PHY_OFDM(0x73)	/* OFDM table data I */
 #define B43_PHY_OTABLEQ			B43_PHY_OFDM(0x74)	/* OFDM table data Q */
 #define B43_PHY_HPWR_TSSICTL		B43_PHY_OFDM(0x78)	/* Hardware power TSSI control */
+#define B43_PHY_ADCCTL			B43_PHY_OFDM(0x7A)	/* ADC control */
+#define B43_PHY_IDLE_TSSI		B43_PHY_OFDM(0x7B)
+#define B43_PHY_A_TEMP_SENSE		B43_PHY_OFDM(0x7C)	/* A PHY temperature sense */
 #define B43_PHY_NRSSITHRES		B43_PHY_OFDM(0x8A)	/* NRSSI threshold */
 #define B43_PHY_ANTWRSETT		B43_PHY_OFDM(0x8C)	/* Antenna WR settle */
 #define  B43_PHY_ANTWRSETT_ARXDIV	0x2000	/* Automatic RX diversity enabled */
@@ -54,33 +68,35 @@ struct b43_phy;
 #define B43_PHY_N1N2GAIN		B43_PHY_OFDM(0xA2)
 #define B43_PHY_CLIPTHRES		B43_PHY_OFDM(0xA3)
 #define B43_PHY_CLIPN1P2THRES		B43_PHY_OFDM(0xA4)
+#define B43_PHY_CCKSHIFTBITS_WA		B43_PHY_OFDM(0xA5)	/* CCK shiftbits workaround, FIXME rename */
+#define B43_PHY_CCKSHIFTBITS		B43_PHY_OFDM(0xA7)	/* FIXME rename */
 #define B43_PHY_DIVSRCHIDX		B43_PHY_OFDM(0xA8)	/* Divider search gain/index */
 #define B43_PHY_CLIPP2THRES		B43_PHY_OFDM(0xA9)
 #define B43_PHY_CLIPP3THRES		B43_PHY_OFDM(0xAA)
 #define B43_PHY_DIVP1P2GAIN		B43_PHY_OFDM(0xAB)
 #define B43_PHY_DIVSRCHGAINBACK		B43_PHY_OFDM(0xAD)	/* Divider search gain back */
 #define B43_PHY_DIVSRCHGAINCHNG		B43_PHY_OFDM(0xAE)	/* Divider search gain change */
-#define B43_PHY_CRSTHRES1_R1		B43_PHY_OFDM(0xC0)	/* CRS Threshold 1 (rev 1 only) */
-#define B43_PHY_CRSTHRES2_R1		B43_PHY_OFDM(0xC1)	/* CRS Threshold 2 (rev 1 only) */
+#define B43_PHY_CRSTHRES1		B43_PHY_OFDM(0xC0)	/* CRS Threshold 1 (phy.rev >= 2 only) */
+#define B43_PHY_CRSTHRES2		B43_PHY_OFDM(0xC1)	/* CRS Threshold 2 (phy.rev >= 2 only) */
 #define B43_PHY_TSSIP_LTBASE		B43_PHY_OFDM(0x380)	/* TSSI power lookup table base */
 #define B43_PHY_DC_LTBASE		B43_PHY_OFDM(0x3A0)	/* DC lookup table base */
 #define B43_PHY_GAIN_LTBASE		B43_PHY_OFDM(0x3C0)	/* Gain lookup table base */
 
 /* CCK (B) PHY Registers */
-#define B43_PHY_VERSION_CCK		B43_PHY_BASE(0x00)	/* Versioning register for B-PHY */
-#define B43_PHY_CCKBBANDCFG		B43_PHY_BASE(0x01)	/* Contains antenna 0/1 control bit */
-#define B43_PHY_PGACTL			B43_PHY_BASE(0x15)	/* PGA control */
+#define B43_PHY_VERSION_CCK		B43_PHY_CCK(0x00)	/* Versioning register for B-PHY */
+#define B43_PHY_CCKBBANDCFG		B43_PHY_CCK(0x01)	/* Contains antenna 0/1 control bit */
+#define B43_PHY_PGACTL			B43_PHY_CCK(0x15)	/* PGA control */
 #define  B43_PHY_PGACTL_LPF		0x1000	/* Low pass filter (?) */
 #define  B43_PHY_PGACTL_LOWBANDW	0x0040	/* Low bandwidth flag */
 #define  B43_PHY_PGACTL_UNKNOWN		0xEFA0
-#define B43_PHY_FBCTL1			B43_PHY_BASE(0x18)	/* Frequency bandwidth control 1 */
-#define B43_PHY_ITSSI			B43_PHY_BASE(0x29)	/* Idle TSSI */
-#define B43_PHY_LO_LEAKAGE		B43_PHY_BASE(0x2D)	/* Measured LO leakage */
-#define B43_PHY_ENERGY			B43_PHY_BASE(0x33)	/* Energy */
-#define B43_PHY_SYNCCTL			B43_PHY_BASE(0x35)
-#define B43_PHY_FBCTL2			B43_PHY_BASE(0x38)	/* Frequency bandwidth control 2 */
-#define B43_PHY_DACCTL			B43_PHY_BASE(0x60)	/* DAC control */
-#define B43_PHY_RCCALOVER		B43_PHY_BASE(0x78)	/* RC calibration override */
+#define B43_PHY_FBCTL1			B43_PHY_CCK(0x18)	/* Frequency bandwidth control 1 */
+#define B43_PHY_ITSSI			B43_PHY_CCK(0x29)	/* Idle TSSI */
+#define B43_PHY_LO_LEAKAGE		B43_PHY_CCK(0x2D)	/* Measured LO leakage */
+#define B43_PHY_ENERGY			B43_PHY_CCK(0x33)	/* Energy */
+#define B43_PHY_SYNCCTL			B43_PHY_CCK(0x35)
+#define B43_PHY_FBCTL2			B43_PHY_CCK(0x38)	/* Frequency bandwidth control 2 */
+#define B43_PHY_DACCTL			B43_PHY_CCK(0x60)	/* DAC control */
+#define B43_PHY_RCCALOVER		B43_PHY_CCK(0x78)	/* RC calibration override */
 
 /* Extended G-PHY Registers */
 #define B43_PHY_CLASSCTL		B43_PHY_EXTG(0x02)	/* Classify control */
@@ -125,13 +141,14 @@ struct b43_phy;
 #define B43_OFDMTAB_DC			B43_OFDMTAB(0x0E, 7)
 #define B43_OFDMTAB_PWRDYN2		B43_OFDMTAB(0x0E, 12)
 #define B43_OFDMTAB_LNAGAIN		B43_OFDMTAB(0x0E, 13)
-//TODO
+#define B43_OFDMTAB_UNKNOWN_0F		B43_OFDMTAB(0x0F, 0)	//TODO rename
+#define B43_OFDMTAB_UNKNOWN_APHY	B43_OFDMTAB(0x0F, 7)	//TODO rename
 #define B43_OFDMTAB_LPFGAIN		B43_OFDMTAB(0x0F, 12)
 #define B43_OFDMTAB_RSSI		B43_OFDMTAB(0x10, 0)
-//TODO
+#define B43_OFDMTAB_UNKNOWN_11		B43_OFDMTAB(0x11, 4)	//TODO rename
 #define B43_OFDMTAB_AGC1_R1		B43_OFDMTAB(0x13, 0)
-#define B43_OFDMTAB_GAINX_R1		B43_OFDMTAB(0x14, 0)	//TODO rename
-#define B43_OFDMTAB_MINSIGSQ		B43_OFDMTAB(0x14, 1)
+#define B43_OFDMTAB_GAINX_R1		B43_OFDMTAB(0x14, 0)	//TODO remove!
+#define B43_OFDMTAB_MINSIGSQ		B43_OFDMTAB(0x14, 0)
 #define B43_OFDMTAB_AGC3_R1		B43_OFDMTAB(0x15, 0)
 #define B43_OFDMTAB_WRSSI_R1		B43_OFDMTAB(0x15, 4)
 #define B43_OFDMTAB_TSSI		B43_OFDMTAB(0x15, 0)
@@ -163,6 +180,8 @@ enum {
 	B43_ANTENNA1,		/* Antenna 0 */
 	B43_ANTENNA_AUTO1,	/* Automatic, starting with antenna 1 */
 	B43_ANTENNA_AUTO0,	/* Automatic, starting with antenna 0 */
+	B43_ANTENNA2,
+	B43_ANTENNA3 = 8,
 
 	B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
 	B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
@@ -182,21 +201,21 @@ enum {
 #define B43_PHYVER_TYPE_SHIFT		8
 #define B43_PHYVER_VERSION		0x00FF
 
-void b43_raw_phy_lock(struct b43_wldev *dev);
-#define b43_phy_lock(dev, flags) \
-	do {					\
-		local_irq_save(flags);		\
-		b43_raw_phy_lock(dev);	\
-	} while (0)
-void b43_raw_phy_unlock(struct b43_wldev *dev);
-#define b43_phy_unlock(dev, flags) \
-	do {					\
-		b43_raw_phy_unlock(dev);	\
-		local_irq_restore(flags);	\
-	} while (0)
+void b43_phy_lock(struct b43_wldev *dev);
+void b43_phy_unlock(struct b43_wldev *dev);
+
 
+/* Read a value from a PHY register */
 u16 b43_phy_read(struct b43_wldev *dev, u16 offset);
+/* Write a value to a PHY register */
 void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val);
+/* Mask a PHY register with a mask */
+void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask);
+/* OR a PHY register with a bitmap */
+void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set);
+/* Mask and OR a PHY register with a mask and bitmap */
+void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
+
 
 int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev);
 
@@ -260,8 +279,18 @@ extern const u8 b43_radio_channel_codes_bg[];
 void b43_radio_lock(struct b43_wldev *dev);
 void b43_radio_unlock(struct b43_wldev *dev);
 
+
+/* Read a value from a 16bit radio register */
 u16 b43_radio_read16(struct b43_wldev *dev, u16 offset);
+/* Write a value to a 16bit radio register */
 void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val);
+/* Mask a 16bit radio register with a mask */
+void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask);
+/* OR a 16bit radio register with a bitmap */
+void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
+/* Mask and OR a PHY register with a mask and bitmap */
+void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
+
 
 u16 b43_radio_init2050(struct b43_wldev *dev);
 void b43_radio_init2060(struct b43_wldev *dev);
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
deleted file mode 100644
index 67752a28eb9c..000000000000
--- a/drivers/net/wireless/b43/pio.c
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
-
-  Broadcom B43 wireless driver
-
-  PIO Transmission
-
-  Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
-
-  This program is free software; you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation; either version 2 of the License, or
-  (at your option) any later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with this program; see the file COPYING.  If not, write to
-  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
-  Boston, MA 02110-1301, USA.
-
-*/
-
-#include "b43.h"
-#include "pio.h"
-#include "main.h"
-#include "xmit.h"
-
-#include <linux/delay.h>
-
-static void tx_start(struct b43_pioqueue *queue)
-{
-	b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT);
-}
-
-static void tx_octet(struct b43_pioqueue *queue, u8 octet)
-{
-	if (queue->need_workarounds) {
-		b43_pio_write(queue, B43_PIO_TXDATA, octet);
-		b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
-	} else {
-		b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
-		b43_pio_write(queue, B43_PIO_TXDATA, octet);
-	}
-}
-
-static u16 tx_get_next_word(const u8 * txhdr,
-			    const u8 * packet,
-			    size_t txhdr_size, unsigned int *pos)
-{
-	const u8 *source;
-	unsigned int i = *pos;
-	u16 ret;
-
-	if (i < txhdr_size) {
-		source = txhdr;
-	} else {
-		source = packet;
-		i -= txhdr_size;
-	}
-	ret = le16_to_cpu(*((__le16 *)(source + i)));
-	*pos += 2;
-
-	return ret;
-}
-
-static void tx_data(struct b43_pioqueue *queue,
-		    u8 * txhdr, const u8 * packet, unsigned int octets)
-{
-	u16 data;
-	unsigned int i = 0;
-
-	if (queue->need_workarounds) {
-		data = tx_get_next_word(txhdr, packet,
-					sizeof(struct b43_txhdr_fw4), &i);
-		b43_pio_write(queue, B43_PIO_TXDATA, data);
-	}
-	b43_pio_write(queue, B43_PIO_TXCTL,
-		      B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI);
-	while (i < octets - 1) {
-		data = tx_get_next_word(txhdr, packet,
-					sizeof(struct b43_txhdr_fw4), &i);
-		b43_pio_write(queue, B43_PIO_TXDATA, data);
-	}
-	if (octets % 2)
-		tx_octet(queue,
-			 packet[octets - sizeof(struct b43_txhdr_fw4) - 1]);
-}
-
-static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb)
-{
-	if (queue->need_workarounds) {
-		b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]);
-		b43_pio_write(queue, B43_PIO_TXCTL,
-			      B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE);
-	} else {
-		b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE);
-	}
-}
-
-static u16 generate_cookie(struct b43_pioqueue *queue,
-			   struct b43_pio_txpacket *packet)
-{
-	u16 cookie = 0x0000;
-	u16 packetindex;
-
-	/* We use the upper 4 bits for the PIO
-	 * controller ID and the lower 12 bits
-	 * for the packet index (in the cache).
-	 */
-	switch (queue->mmio_base) {
-	case B43_MMIO_PIO1_BASE:
-		break;
-	case B43_MMIO_PIO2_BASE:
-		cookie = 0x1000;
-		break;
-	case B43_MMIO_PIO3_BASE:
-		cookie = 0x2000;
-		break;
-	case B43_MMIO_PIO4_BASE:
-		cookie = 0x3000;
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-	packetindex = packet->index;
-	B43_WARN_ON(packetindex & ~0x0FFF);
-	cookie |= (u16) packetindex;
-
-	return cookie;
-}
-
-static
-struct b43_pioqueue *parse_cookie(struct b43_wldev *dev,
-				  u16 cookie, struct b43_pio_txpacket **packet)
-{
-	struct b43_pio *pio = &dev->pio;
-	struct b43_pioqueue *queue = NULL;
-	int packetindex;
-
-	switch (cookie & 0xF000) {
-	case 0x0000:
-		queue = pio->queue0;
-		break;
-	case 0x1000:
-		queue = pio->queue1;
-		break;
-	case 0x2000:
-		queue = pio->queue2;
-		break;
-	case 0x3000:
-		queue = pio->queue3;
-		break;
-	default:
-		B43_WARN_ON(1);
-	}
-	packetindex = (cookie & 0x0FFF);
-	B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS));
-	*packet = &(queue->tx_packets_cache[packetindex]);
-
-	return queue;
-}
-
-union txhdr_union {
-	struct b43_txhdr_fw4 txhdr_fw4;
-};
-
-static void pio_tx_write_fragment(struct b43_pioqueue *queue,
-				  struct sk_buff *skb,
-				  struct b43_pio_txpacket *packet,
-				  size_t txhdr_size)
-{
-	union txhdr_union txhdr_data;
-	u8 *txhdr = NULL;
-	unsigned int octets;
-
-	txhdr = (u8 *) (&txhdr_data.txhdr_fw4);
-
-	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
-	b43_generate_txhdr(queue->dev,
-			   txhdr, skb->data, skb->len,
-			   &packet->txstat.control,
-			   generate_cookie(queue, packet));
-
-	tx_start(queue);
-	octets = skb->len + txhdr_size;
-	if (queue->need_workarounds)
-		octets--;
-	tx_data(queue, txhdr, (u8 *) skb->data, octets);
-	tx_complete(queue, skb);
-}
-
-static void free_txpacket(struct b43_pio_txpacket *packet)
-{
-	struct b43_pioqueue *queue = packet->queue;
-
-	if (packet->skb)
-		dev_kfree_skb_any(packet->skb);
-	list_move(&packet->list, &queue->txfree);
-	queue->nr_txfree++;
-}
-
-static int pio_tx_packet(struct b43_pio_txpacket *packet)
-{
-	struct b43_pioqueue *queue = packet->queue;
-	struct sk_buff *skb = packet->skb;
-	u16 octets;
-
-	octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4);
-	if (queue->tx_devq_size < octets) {
-		b43warn(queue->dev->wl, "PIO queue too small. "
-			"Dropping packet.\n");
-		/* Drop it silently (return success) */
-		free_txpacket(packet);
-		return 0;
-	}
-	B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS);
-	B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
-	/* Check if there is sufficient free space on the device
-	 * TX queue. If not, return and let the TX tasklet
-	 * retry later.
-	 */
-	if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS)
-		return -EBUSY;
-	if (queue->tx_devq_used + octets > queue->tx_devq_size)
-		return -EBUSY;
-	/* Now poke the device. */
-	pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4));
-
-	/* Account for the packet size.
-	 * (We must not overflow the device TX queue)
-	 */
-	queue->tx_devq_packets++;
-	queue->tx_devq_used += octets;
-
-	/* Transmission started, everything ok, move the
-	 * packet to the txrunning list.
-	 */
-	list_move_tail(&packet->list, &queue->txrunning);
-
-	return 0;
-}
-
-static void tx_tasklet(unsigned long d)
-{
-	struct b43_pioqueue *queue = (struct b43_pioqueue *)d;
-	struct b43_wldev *dev = queue->dev;
-	unsigned long flags;
-	struct b43_pio_txpacket *packet, *tmp_packet;
-	int err;
-	u16 txctl;
-
-	spin_lock_irqsave(&dev->wl->irq_lock, flags);
-	if (queue->tx_frozen)
-		goto out_unlock;
-	txctl = b43_pio_read(queue, B43_PIO_TXCTL);
-	if (txctl & B43_PIO_TXCTL_SUSPEND)
-		goto out_unlock;
-
-	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
-		/* Try to transmit the packet. This can fail, if
-		 * the device queue is full. In case of failure, the
-		 * packet is left in the txqueue.
-		 * If transmission succeed, the packet is moved to txrunning.
-		 * If it is impossible to transmit the packet, it
-		 * is dropped.
-		 */
-		err = pio_tx_packet(packet);
-		if (err)
-			break;
-	}
-      out_unlock:
-	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
-}
-
-static void setup_txqueues(struct b43_pioqueue *queue)
-{
-	struct b43_pio_txpacket *packet;
-	int i;
-
-	queue->nr_txfree = B43_PIO_MAXTXPACKETS;
-	for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) {
-		packet = &(queue->tx_packets_cache[i]);
-
-		packet->queue = queue;
-		INIT_LIST_HEAD(&packet->list);
-		packet->index = i;
-
-		list_add(&packet->list, &queue->txfree);
-	}
-}
-
-static
-struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev,
-					u16 pio_mmio_base)
-{
-	struct b43_pioqueue *queue;
-	u16 qsize;
-
-	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
-	if (!queue)
-		goto out;
-
-	queue->dev = dev;
-	queue->mmio_base = pio_mmio_base;
-	queue->need_workarounds = (dev->dev->id.revision < 3);
-
-	INIT_LIST_HEAD(&queue->txfree);
-	INIT_LIST_HEAD(&queue->txqueue);
-	INIT_LIST_HEAD(&queue->txrunning);
-	tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue);
-
-	b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
-		    & ~B43_MACCTL_BE);
-
-	qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE);
-	if (qsize == 0) {
-		b43err(dev->wl, "This card does not support PIO "
-		       "operation mode. Please use DMA mode "
-		       "(module parameter pio=0).\n");
-		goto err_freequeue;
-	}
-	if (qsize <= B43_PIO_TXQADJUST) {
-		b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize);
-		goto err_freequeue;
-	}
-	qsize -= B43_PIO_TXQADJUST;
-	queue->tx_devq_size = qsize;
-
-	setup_txqueues(queue);
-
-      out:
-	return queue;
-
-      err_freequeue:
-	kfree(queue);
-	queue = NULL;
-	goto out;
-}
-
-static void cancel_transfers(struct b43_pioqueue *queue)
-{
-	struct b43_pio_txpacket *packet, *tmp_packet;
-
-	tasklet_disable(&queue->txtask);
-
-	list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
-	    free_txpacket(packet);
-	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
-	    free_txpacket(packet);
-}
-
-static void b43_destroy_pioqueue(struct b43_pioqueue *queue)
-{
-	if (!queue)
-		return;
-
-	cancel_transfers(queue);
-	kfree(queue);
-}
-
-void b43_pio_free(struct b43_wldev *dev)
-{
-	struct b43_pio *pio;
-
-	if (!b43_using_pio(dev))
-		return;
-	pio = &dev->pio;
-
-	b43_destroy_pioqueue(pio->queue3);
-	pio->queue3 = NULL;
-	b43_destroy_pioqueue(pio->queue2);
-	pio->queue2 = NULL;
-	b43_destroy_pioqueue(pio->queue1);
-	pio->queue1 = NULL;
-	b43_destroy_pioqueue(pio->queue0);
-	pio->queue0 = NULL;
-}
-
-int b43_pio_init(struct b43_wldev *dev)
-{
-	struct b43_pio *pio = &dev->pio;
-	struct b43_pioqueue *queue;
-	int err = -ENOMEM;
-
-	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE);
-	if (!queue)
-		goto out;
-	pio->queue0 = queue;
-
-	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE);
-	if (!queue)
-		goto err_destroy0;
-	pio->queue1 = queue;
-
-	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE);
-	if (!queue)
-		goto err_destroy1;
-	pio->queue2 = queue;
-
-	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE);
-	if (!queue)
-		goto err_destroy2;
-	pio->queue3 = queue;
-
-	if (dev->dev->id.revision < 3)
-		dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND;
-
-	b43dbg(dev->wl, "PIO initialized\n");
-	err = 0;
-      out:
-	return err;
-
-      err_destroy2:
-	b43_destroy_pioqueue(pio->queue2);
-	pio->queue2 = NULL;
-      err_destroy1:
-	b43_destroy_pioqueue(pio->queue1);
-	pio->queue1 = NULL;
-      err_destroy0:
-	b43_destroy_pioqueue(pio->queue0);
-	pio->queue0 = NULL;
-	goto out;
-}
-
-int b43_pio_tx(struct b43_wldev *dev,
-	       struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-	struct b43_pioqueue *queue = dev->pio.queue1;
-	struct b43_pio_txpacket *packet;
-
-	B43_WARN_ON(queue->tx_suspended);
-	B43_WARN_ON(list_empty(&queue->txfree));
-
-	packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list);
-	packet->skb = skb;
-
-	memset(&packet->txstat, 0, sizeof(packet->txstat));
-	memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
-
-	list_move_tail(&packet->list, &queue->txqueue);
-	queue->nr_txfree--;
-	queue->nr_tx_packets++;
-	B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS);
-
-	tasklet_schedule(&queue->txtask);
-
-	return 0;
-}
-
-void b43_pio_handle_txstatus(struct b43_wldev *dev,
-			     const struct b43_txstatus *status)
-{
-	struct b43_pioqueue *queue;
-	struct b43_pio_txpacket *packet;
-
-	queue = parse_cookie(dev, status->cookie, &packet);
-	if (B43_WARN_ON(!queue))
-		return;
-
-	queue->tx_devq_packets--;
-	queue->tx_devq_used -=
-	    (packet->skb->len + sizeof(struct b43_txhdr_fw4));
-
-	if (status->acked) {
-		packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
-	} else {
-		if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK))
-			packet->txstat.excessive_retries = 1;
-	}
-	if (status->frame_count == 0) {
-		/* The frame was not transmitted at all. */
-		packet->txstat.retry_count = 0;
-	} else
-		packet->txstat.retry_count = status->frame_count - 1;
-	ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
-				    &(packet->txstat));
-	packet->skb = NULL;
-
-	free_txpacket(packet);
-	/* If there are packets on the txqueue, poke the tasklet
-	 * to transmit them.
-	 */
-	if (!list_empty(&queue->txqueue))
-		tasklet_schedule(&queue->txtask);
-}
-
-void b43_pio_get_tx_stats(struct b43_wldev *dev,
-			  struct ieee80211_tx_queue_stats *stats)
-{
-	struct b43_pio *pio = &dev->pio;
-	struct b43_pioqueue *queue;
-	struct ieee80211_tx_queue_stats_data *data;
-
-	queue = pio->queue1;
-	data = &(stats->data[0]);
-	data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree;
-	data->limit = B43_PIO_MAXTXPACKETS;
-	data->count = queue->nr_tx_packets;
-}
-
-static void pio_rx_error(struct b43_pioqueue *queue,
-			 int clear_buffers, const char *error)
-{
-	int i;
-
-	b43err(queue->dev->wl, "PIO RX error: %s\n", error);
-	b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY);
-	if (clear_buffers) {
-		B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE);
-		for (i = 0; i < 15; i++) {
-			/* Dummy read. */
-			b43_pio_read(queue, B43_PIO_RXDATA);
-		}
-	}
-}
-
-void b43_pio_rx(struct b43_pioqueue *queue)
-{
-	__le16 preamble[21] = { 0 };
-	struct b43_rxhdr_fw4 *rxhdr;
-	u16 tmp, len;
-	u32 macstat;
-	int i, preamble_readwords;
-	struct sk_buff *skb;
-
-	tmp = b43_pio_read(queue, B43_PIO_RXCTL);
-	if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE))
-		return;
-	b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE);
-
-	for (i = 0; i < 10; i++) {
-		tmp = b43_pio_read(queue, B43_PIO_RXCTL);
-		if (tmp & B43_PIO_RXCTL_READY)
-			goto data_ready;
-		udelay(10);
-	}
-	b43dbg(queue->dev->wl, "PIO RX timed out\n");
-	return;
-data_ready:
-
-	len = b43_pio_read(queue, B43_PIO_RXDATA);
-	if (unlikely(len > 0x700)) {
-		pio_rx_error(queue, 0, "len > 0x700");
-		return;
-	}
-	if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) {
-		pio_rx_error(queue, 0, "len == 0");
-		return;
-	}
-	preamble[0] = cpu_to_le16(len);
-	if (queue->mmio_base == B43_MMIO_PIO4_BASE)
-		preamble_readwords = 14 / sizeof(u16);
-	else
-		preamble_readwords = 18 / sizeof(u16);
-	for (i = 0; i < preamble_readwords; i++) {
-		tmp = b43_pio_read(queue, B43_PIO_RXDATA);
-		preamble[i + 1] = cpu_to_le16(tmp);
-	}
-	rxhdr = (struct b43_rxhdr_fw4 *)preamble;
-	macstat = le32_to_cpu(rxhdr->mac_status);
-	if (macstat & B43_RX_MAC_FCSERR) {
-		pio_rx_error(queue,
-			     (queue->mmio_base == B43_MMIO_PIO1_BASE),
-			     "Frame FCS error");
-		return;
-	}
-	if (queue->mmio_base == B43_MMIO_PIO4_BASE) {
-		/* We received an xmit status. */
-		struct b43_hwtxstatus *hw;
-
-		hw = (struct b43_hwtxstatus *)(preamble + 1);
-		b43_handle_hwtxstatus(queue->dev, hw);
-
-		return;
-	}
-
-	skb = dev_alloc_skb(len);
-	if (unlikely(!skb)) {
-		pio_rx_error(queue, 1, "OOM");
-		return;
-	}
-	skb_put(skb, len);
-	for (i = 0; i < len - 1; i += 2) {
-		tmp = b43_pio_read(queue, B43_PIO_RXDATA);
-		*((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
-	}
-	if (len % 2) {
-		tmp = b43_pio_read(queue, B43_PIO_RXDATA);
-		skb->data[len - 1] = (tmp & 0x00FF);
-/* The specs say the following is required, but
- * it is wrong and corrupts the PLCP. If we don't do
- * this, the PLCP seems to be correct. So ifdef it out for now.
- */
-#if 0
-		if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME)
-			skb->data[2] = (tmp & 0xFF00) >> 8;
-		else
-			skb->data[0] = (tmp & 0xFF00) >> 8;
-#endif
-	}
-	b43_rx(queue->dev, skb, rxhdr);
-}
-
-void b43_pio_tx_suspend(struct b43_pioqueue *queue)
-{
-	b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE);
-	b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
-		      | B43_PIO_TXCTL_SUSPEND);
-}
-
-void b43_pio_tx_resume(struct b43_pioqueue *queue)
-{
-	b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
-		      & ~B43_PIO_TXCTL_SUSPEND);
-	b43_power_saving_ctl_bits(queue->dev, 0);
-	tasklet_schedule(&queue->txtask);
-}
-
-void b43_pio_freeze_txqueues(struct b43_wldev *dev)
-{
-	struct b43_pio *pio;
-
-	B43_WARN_ON(!b43_using_pio(dev));
-	pio = &dev->pio;
-	pio->queue0->tx_frozen = 1;
-	pio->queue1->tx_frozen = 1;
-	pio->queue2->tx_frozen = 1;
-	pio->queue3->tx_frozen = 1;
-}
-
-void b43_pio_thaw_txqueues(struct b43_wldev *dev)
-{
-	struct b43_pio *pio;
-
-	B43_WARN_ON(!b43_using_pio(dev));
-	pio = &dev->pio;
-	pio->queue0->tx_frozen = 0;
-	pio->queue1->tx_frozen = 0;
-	pio->queue2->tx_frozen = 0;
-	pio->queue3->tx_frozen = 0;
-	if (!list_empty(&pio->queue0->txqueue))
-		tasklet_schedule(&pio->queue0->txtask);
-	if (!list_empty(&pio->queue1->txqueue))
-		tasklet_schedule(&pio->queue1->txtask);
-	if (!list_empty(&pio->queue2->txqueue))
-		tasklet_schedule(&pio->queue2->txtask);
-	if (!list_empty(&pio->queue3->txqueue))
-		tasklet_schedule(&pio->queue3->txtask);
-}
diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h
deleted file mode 100644
index 3488f2447bbf..000000000000
--- a/drivers/net/wireless/b43/pio.h
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef B43_PIO_H_
-#define B43_PIO_H_
-
-#include "b43.h"
-
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/list.h>
-#include <linux/skbuff.h>
-
-#define B43_PIO_TXCTL		0x00
-#define B43_PIO_TXDATA		0x02
-#define B43_PIO_TXQBUFSIZE		0x04
-#define B43_PIO_RXCTL		0x08
-#define B43_PIO_RXDATA		0x0A
-
-#define B43_PIO_TXCTL_WRITELO	(1 << 0)
-#define B43_PIO_TXCTL_WRITEHI	(1 << 1)
-#define B43_PIO_TXCTL_COMPLETE	(1 << 2)
-#define B43_PIO_TXCTL_INIT		(1 << 3)
-#define B43_PIO_TXCTL_SUSPEND	(1 << 7)
-
-#define B43_PIO_RXCTL_DATAAVAILABLE	(1 << 0)
-#define B43_PIO_RXCTL_READY		(1 << 1)
-
-/* PIO constants */
-#define B43_PIO_MAXTXDEVQPACKETS	31
-#define B43_PIO_TXQADJUST		80
-
-/* PIO tuning knobs */
-#define B43_PIO_MAXTXPACKETS	256
-
-#ifdef CONFIG_B43_PIO
-
-struct b43_pioqueue;
-struct b43_xmitstatus;
-
-struct b43_pio_txpacket {
-	struct b43_pioqueue *queue;
-	struct sk_buff *skb;
-	struct ieee80211_tx_status txstat;
-	struct list_head list;
-	u16 index; /* Index in the tx_packets_cache */
-};
-
-struct b43_pioqueue {
-	struct b43_wldev *dev;
-	u16 mmio_base;
-
-	bool tx_suspended;
-	bool tx_frozen;
-	bool need_workarounds;	/* Workarounds needed for core.rev < 3 */
-
-	/* Adjusted size of the device internal TX buffer. */
-	u16 tx_devq_size;
-	/* Used octets of the device internal TX buffer. */
-	u16 tx_devq_used;
-	/* Used packet slots in the device internal TX buffer. */
-	u8 tx_devq_packets;
-	/* Packets from the txfree list can
-	 * be taken on incoming TX requests.
-	 */
-	struct list_head txfree;
-	unsigned int nr_txfree;
-	/* Packets on the txqueue are queued,
-	 * but not completely written to the chip, yet.
-	 */
-	struct list_head txqueue;
-	/* Packets on the txrunning queue are completely
-	 * posted to the device. We are waiting for the txstatus.
-	 */
-	struct list_head txrunning;
-	/* Total number or packets sent.
-	 * (This counter can obviously wrap).
-	 */
-	unsigned int nr_tx_packets;
-	struct tasklet_struct txtask;
-	struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS];
-};
-
-static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset)
-{
-	return b43_read16(queue->dev, queue->mmio_base + offset);
-}
-
-static inline
-    void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value)
-{
-	b43_write16(queue->dev, queue->mmio_base + offset, value);
-	mmiowb();
-}
-
-int b43_pio_init(struct b43_wldev *dev);
-void b43_pio_free(struct b43_wldev *dev);
-
-int b43_pio_tx(struct b43_wldev *dev,
-	       struct sk_buff *skb, struct ieee80211_tx_control *ctl);
-void b43_pio_handle_txstatus(struct b43_wldev *dev,
-			     const struct b43_txstatus *status);
-void b43_pio_get_tx_stats(struct b43_wldev *dev,
-			  struct ieee80211_tx_queue_stats *stats);
-void b43_pio_rx(struct b43_pioqueue *queue);
-
-/* Suspend TX queue in hardware. */
-void b43_pio_tx_suspend(struct b43_pioqueue *queue);
-void b43_pio_tx_resume(struct b43_pioqueue *queue);
-/* Suspend (freeze) the TX tasklet (software level). */
-void b43_pio_freeze_txqueues(struct b43_wldev *dev);
-void b43_pio_thaw_txqueues(struct b43_wldev *dev);
-
-#else /* CONFIG_B43_PIO */
-
-static inline int b43_pio_init(struct b43_wldev *dev)
-{
-	return 0;
-}
-static inline void b43_pio_free(struct b43_wldev *dev)
-{
-}
-static inline
-    int b43_pio_tx(struct b43_wldev *dev,
-		   struct sk_buff *skb, struct ieee80211_tx_control *ctl)
-{
-	return 0;
-}
-static inline
-    void b43_pio_handle_txstatus(struct b43_wldev *dev,
-				 const struct b43_txstatus *status)
-{
-}
-static inline
-    void b43_pio_get_tx_stats(struct b43_wldev *dev,
-			      struct ieee80211_tx_queue_stats *stats)
-{
-}
-static inline void b43_pio_rx(struct b43_pioqueue *queue)
-{
-}
-static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue)
-{
-}
-static inline void b43_pio_tx_resume(struct b43_pioqueue *queue)
-{
-}
-static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev)
-{
-}
-static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev)
-{
-}
-
-#endif /* CONFIG_B43_PIO */
-#endif /* B43_PIO_H_ */
diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c
index 15a87183a572..3f5ea06bf13c 100644
--- a/drivers/net/wireless/b43/tables.c
+++ b/drivers/net/wireless/b43/tables.c
@@ -3,7 +3,7 @@
   Broadcom B43 wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -229,7 +229,7 @@ const u16 b43_tab_noisea2[] = {
 };
 
 const u16 b43_tab_noisea3[] = {
-	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+	0x5E5E, 0x5E5E, 0x5E5E, 0x3F48,
 	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
 };
 
@@ -243,6 +243,26 @@ const u16 b43_tab_noiseg2[] = {
 	0x0000, 0x0000, 0x0000, 0x0000,
 };
 
+const u16 b43_tab_noisescalea2[] = {
+	0x6767, 0x6767, 0x6767, 0x6767, /* 0 */
+	0x6767, 0x6767, 0x6767, 0x6767,
+	0x6767, 0x6767, 0x6767, 0x6767,
+	0x6767, 0x6700, 0x6767, 0x6767,
+	0x6767, 0x6767, 0x6767, 0x6767, /* 16 */
+	0x6767, 0x6767, 0x6767, 0x6767,
+	0x6767, 0x6767, 0x0067,
+};
+
+const u16 b43_tab_noisescalea3[] = {
+	0x2323, 0x2323, 0x2323, 0x2323, /* 0 */
+	0x2323, 0x2323, 0x2323, 0x2323,
+	0x2323, 0x2323, 0x2323, 0x2323,
+	0x2323, 0x2300, 0x2323, 0x2323,
+	0x2323, 0x2323, 0x2323, 0x2323, /* 16 */
+	0x2323, 0x2323, 0x2323, 0x2323,
+	0x2323, 0x2323, 0x0023,
+};
+
 const u16 b43_tab_noisescaleg1[] = {
 	0x6C77, 0x5162, 0x3B40, 0x3335,	/* 0 */
 	0x2F2D, 0x2A2A, 0x2527, 0x1F21,
@@ -254,7 +274,7 @@ const u16 b43_tab_noisescaleg1[] = {
 };
 
 const u16 b43_tab_noisescaleg2[] = {
-	0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7,	/* 0 */
+	0xD8DD, 0xCBD4, 0xBCC0, 0xB6B7,	/* 0 */
 	0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
 	0x969B, 0x9195, 0x8F8F, 0x8A8A,
 	0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
@@ -307,6 +327,28 @@ const u16 b43_tab_sigmasqr2[] = {
 	0x00DE,
 };
 
+const u16 b43_tab_rssiagc1[] = {
+	0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8, /* 0 */
+	0xFFF8, 0xFFF9, 0xFFFC, 0xFFFE,
+	0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8,
+	0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8,
+};
+
+const u16 b43_tab_rssiagc2[] = {
+	0x0820, 0x0820, 0x0920, 0x0C38, /* 0 */
+	0x0820, 0x0820, 0x0820, 0x0820,
+	0x0820, 0x0820, 0x0920, 0x0A38,
+	0x0820, 0x0820, 0x0820, 0x0820,
+	0x0820, 0x0820, 0x0920, 0x0A38, /* 16 */
+	0x0820, 0x0820, 0x0820, 0x0820,
+	0x0820, 0x0820, 0x0920, 0x0A38,
+	0x0820, 0x0820, 0x0820, 0x0820,
+	0x0820, 0x0820, 0x0920, 0x0A38, /* 32 */
+	0x0820, 0x0820, 0x0820, 0x0820,
+	0x0820, 0x0820, 0x0920, 0x0A38,
+	0x0820, 0x0820, 0x0820, 0x0820,
+};
+
 static inline void assert_sizes(void)
 {
 	BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor));
@@ -317,36 +359,73 @@ static inline void assert_sizes(void)
 	BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3));
 	BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1));
 	BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2));
-	BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+	BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
+		     ARRAY_SIZE(b43_tab_noisescalea2));
+	BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
+		     ARRAY_SIZE(b43_tab_noisescalea3));
+	BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
 		     ARRAY_SIZE(b43_tab_noisescaleg1));
-	BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+	BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
 		     ARRAY_SIZE(b43_tab_noisescaleg2));
-	BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+	BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE !=
 		     ARRAY_SIZE(b43_tab_noisescaleg3));
 	BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1));
 	BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2));
+	BUILD_BUG_ON(B43_TAB_RSSIAGC1_SIZE != ARRAY_SIZE(b43_tab_rssiagc1));
+	BUILD_BUG_ON(B43_TAB_RSSIAGC2_SIZE != ARRAY_SIZE(b43_tab_rssiagc2));
 }
 
 u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
 {
-	assert_sizes();
+	struct b43_phy *phy = &dev->phy;
+	u16 addr;
+
+	addr = table + offset;
+	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
+	    (addr - 1 != phy->ofdmtab_addr)) {
+		/* The hardware has a different address in memory. Update it. */
+		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
+	}
+	phy->ofdmtab_addr = addr;
 
-	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
 	return b43_phy_read(dev, B43_PHY_OTABLEI);
+
+	/* Some compiletime assertions... */
+	assert_sizes();
 }
 
 void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
 			 u16 offset, u16 value)
 {
-	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+	struct b43_phy *phy = &dev->phy;
+	u16 addr;
+
+	addr = table + offset;
+	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
+	    (addr - 1 != phy->ofdmtab_addr)) {
+		/* The hardware has a different address in memory. Update it. */
+		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
+	}
+	phy->ofdmtab_addr = addr;
 	b43_phy_write(dev, B43_PHY_OTABLEI, value);
 }
 
 u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
 {
+	struct b43_phy *phy = &dev->phy;
 	u32 ret;
+	u16 addr;
 
-	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+	addr = table + offset;
+	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) ||
+	    (addr - 1 != phy->ofdmtab_addr)) {
+		/* The hardware has a different address in memory. Update it. */
+		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ;
+	}
+	phy->ofdmtab_addr = addr;
 	ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
 	ret <<= 16;
 	ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
@@ -357,7 +436,18 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
 void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
 			 u16 offset, u32 value)
 {
-	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+	struct b43_phy *phy = &dev->phy;
+	u16 addr;
+
+	addr = table + offset;
+	if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) ||
+	    (addr - 1 != phy->ofdmtab_addr)) {
+		/* The hardware has a different address in memory. Update it. */
+		b43_phy_write(dev, B43_PHY_OTABLECTL, addr);
+		phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE;
+	}
+	phy->ofdmtab_addr = addr;
+
 	b43_phy_write(dev, B43_PHY_OTABLEI, value);
 	b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));
 }
diff --git a/drivers/net/wireless/b43/tables.h b/drivers/net/wireless/b43/tables.h
index 64635d7b518c..80e73c7cbac5 100644
--- a/drivers/net/wireless/b43/tables.h
+++ b/drivers/net/wireless/b43/tables.h
@@ -1,9 +1,9 @@
 #ifndef B43_TABLES_H_
 #define B43_TABLES_H_
 
-#define B43_TAB_ROTOR_SIZE		53
+#define B43_TAB_ROTOR_SIZE	53
 extern const u32 b43_tab_rotor[];
-#define B43_TAB_RETARD_SIZE		53
+#define B43_TAB_RETARD_SIZE	53
 extern const u32 b43_tab_retard[];
 #define B43_TAB_FINEFREQA_SIZE	256
 extern const u16 b43_tab_finefreqa[];
@@ -17,12 +17,18 @@ extern const u16 b43_tab_noisea3[];
 extern const u16 b43_tab_noiseg1[];
 #define B43_TAB_NOISEG2_SIZE	8
 extern const u16 b43_tab_noiseg2[];
-#define B43_TAB_NOISESCALEG_SIZE	27
+#define B43_TAB_NOISESCALE_SIZE	27
+extern const u16 b43_tab_noisescalea2[];
+extern const u16 b43_tab_noisescalea3[];
 extern const u16 b43_tab_noisescaleg1[];
 extern const u16 b43_tab_noisescaleg2[];
 extern const u16 b43_tab_noisescaleg3[];
 #define B43_TAB_SIGMASQR_SIZE	53
 extern const u16 b43_tab_sigmasqr1[];
 extern const u16 b43_tab_sigmasqr2[];
+#define B43_TAB_RSSIAGC1_SIZE	16
+extern const u16 b43_tab_rssiagc1[];
+#define B43_TAB_RSSIAGC2_SIZE	48
+extern const u16 b43_tab_rssiagc2[];
 
 #endif /* B43_TABLES_H_ */
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
new file mode 100644
index 000000000000..2aa57551786a
--- /dev/null
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -0,0 +1,2476 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n PHY and radio device data tables
+
+  Copyright (c) 2008 Michael Buesch <mb@bu3sch.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "tables_nphy.h"
+#include "phy.h"
+#include "nphy.h"
+
+
+struct b2055_inittab_entry {
+	/* Value to write if we use the 5GHz band. */
+	u16 ghz5;
+	/* Value to write if we use the 2.4GHz band. */
+	u16 ghz2;
+	/* Flags */
+	u8 flags;
+#define B2055_INITTAB_ENTRY_OK	0x01
+#define B2055_INITTAB_UPLOAD	0x02
+};
+#define UPLOAD		.flags = B2055_INITTAB_ENTRY_OK | B2055_INITTAB_UPLOAD
+#define NOUPLOAD	.flags = B2055_INITTAB_ENTRY_OK
+
+static const struct b2055_inittab_entry b2055_inittab [] = {
+  [B2055_SP_PINPD]		= { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+  [B2055_C1_SP_RSSI]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_SP_PDMISC]		= { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, },
+  [B2055_C2_SP_RSSI]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_SP_PDMISC]		= { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, },
+  [B2055_C1_SP_RXGC1]		= { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, },
+  [B2055_C1_SP_RXGC2]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+  [B2055_C2_SP_RXGC1]		= { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, },
+  [B2055_C2_SP_RXGC2]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, },
+  [B2055_C1_SP_LPFBWSEL]	= { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C2_SP_LPFBWSEL]	= { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C1_SP_TXGC1]		= { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, },
+  [B2055_C1_SP_TXGC2]		= { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
+  [B2055_C2_SP_TXGC1]		= { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, },
+  [B2055_C2_SP_TXGC2]		= { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, },
+  [B2055_MASTER1]		= { .ghz5 = 0x00D0, .ghz2 = 0x00D0, NOUPLOAD, },
+  [B2055_MASTER2]		= { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+  [B2055_PD_LGEN]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PD_PLLTS]		= { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, },
+  [B2055_C1_PD_LGBUF]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_PD_TX]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_PD_RXTX]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_PD_RSSIMISC]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_LGBUF]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_TX]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_RXTX]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_PD_RSSIMISC]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PWRDET_LGEN]		= { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+  [B2055_C1_PWRDET_LGBUF]	= { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_C1_PWRDET_RXTX]	= { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+  [B2055_C2_PWRDET_LGBUF]	= { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_C2_PWRDET_RXTX]	= { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, },
+  [B2055_RRCCAL_CS]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_RRCCAL_NOPTSEL]	= { .ghz5 = 0x002C, .ghz2 = 0x002C, NOUPLOAD, },
+  [B2055_CAL_MISC]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_COUT]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_COUT2]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_CVARCTL]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_RVARCTL]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_LPOCTL]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_TS]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_RCCALRTS]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_CAL_RCALRTS]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PADDRV]		= { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+  [B2055_XOCTL1]		= { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, },
+  [B2055_XOCTL2]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_XOREGUL]		= { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+  [B2055_XOMISC]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PLL_LFC1]		= { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_PLL_CALVTH]		= { .ghz5 = 0x0087, .ghz2 = 0x0087, NOUPLOAD, },
+  [B2055_PLL_LFC2]		= { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, },
+  [B2055_PLL_REF]		= { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, },
+  [B2055_PLL_LFR1]		= { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, },
+  [B2055_PLL_PFDCP]		= { .ghz5 = 0x0018, .ghz2 = 0x0018, UPLOAD, },
+  [B2055_PLL_IDAC_CPOPAMP]	= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_PLL_CPREG]		= { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, },
+  [B2055_PLL_RCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_RF_PLLMOD0]		= { .ghz5 = 0x009E, .ghz2 = 0x009E, NOUPLOAD, },
+  [B2055_RF_PLLMOD1]		= { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, },
+  [B2055_RF_MMDIDAC1]		= { .ghz5 = 0x00C8, .ghz2 = 0x00C8, UPLOAD, },
+  [B2055_RF_MMDIDAC0]		= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_RF_MMDSP]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL1]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL2]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL3]		= { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, },
+  [B2055_VCO_CAL4]		= { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+  [B2055_VCO_CAL5]		= { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, },
+  [B2055_VCO_CAL6]		= { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, },
+  [B2055_VCO_CAL7]		= { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, },
+  [B2055_VCO_CAL8]		= { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, },
+  [B2055_VCO_CAL9]		= { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, },
+  [B2055_VCO_CAL10]		= { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_VCO_CAL11]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_VCO_CAL12]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL13]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL14]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL15]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_CAL16]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_VCO_KVCO]		= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_VCO_CAPTAIL]		= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_VCO_IDACVCO]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_VCO_REG]		= { .ghz5 = 0x0084, .ghz2 = 0x0084, UPLOAD, },
+  [B2055_PLL_RFVTH]		= { .ghz5 = 0x00C3, .ghz2 = 0x00C3, NOUPLOAD, },
+  [B2055_LGBUF_CENBUF]		= { .ghz5 = 0x008F, .ghz2 = 0x008F, NOUPLOAD, },
+  [B2055_LGEN_TUNE1]		= { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_LGEN_TUNE2]		= { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, },
+  [B2055_LGEN_IDAC1]		= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_LGEN_IDAC2]		= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_LGEN_BIASC]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_LGEN_BIASIDAC]		= { .ghz5 = 0x00CC, .ghz2 = 0x00CC, NOUPLOAD, },
+  [B2055_LGEN_RCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_LGEN_DIV]		= { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+  [B2055_LGEN_SPARE2]		= { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, },
+  [B2055_C1_LGBUF_ATUNE]	= { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, },
+  [B2055_C1_LGBUF_GTUNE]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_LGBUF_DIV]		= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_LGBUF_AIDAC]	= { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, },
+  [B2055_C1_LGBUF_GIDAC]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_LGBUF_IDACFO]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_LGBUF_SPARE]	= { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, },
+  [B2055_C1_RX_RFSPC1]		= { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, },
+  [B2055_C1_RX_RFR1]		= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C1_RX_RFR2]		= { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+  [B2055_C1_RX_RFRCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C1_RX_BB_BLCMP]	= { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, },
+  [B2055_C1_RX_BB_LPF]		= { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C1_RX_BB_MIDACHP]	= { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C1_RX_BB_VGA1IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_VGA2IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_VGA3IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_BUFOCTL]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_RX_BB_RCCALCTL]	= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL1]	= { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL2]	= { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL3]	= { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL4]	= { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, },
+  [B2055_C1_RX_BB_RSSICTL5]	= { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, },
+  [B2055_C1_RX_BB_REG]		= { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C1_RX_BB_SPARE1]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_RX_TXBBRCAL]	= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C1_TX_RF_SPGA]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C1_TX_RF_SPAD]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C1_TX_RF_CNTPGA1]	= { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C1_TX_RF_CNTPAD1]	= { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+  [B2055_C1_TX_RF_PGAIDAC]	= { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, },
+  [B2055_C1_TX_PGAPADTN]	= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C1_TX_PADIDAC1]	= { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, },
+  [B2055_C1_TX_PADIDAC2]	= { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, },
+  [B2055_C1_TX_MXBGTRIM]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C1_TX_RF_RCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C1_TX_RF_PADTSSI1]	= { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C1_TX_RF_PADTSSI2]	= { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C1_TX_RF_SPARE]	= { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C1_TX_RF_IQCAL1]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C1_TX_RF_IQCAL2]	= { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+  [B2055_C1_TXBB_RCCAL]		= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C1_TXBB_LPF1]		= { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, },
+  [B2055_C1_TX_VOSCNCL]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_TX_LPF_MXGMIDAC]	= { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, },
+  [B2055_C1_TX_BB_MXGM]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_LGBUF_ATUNE]	= { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, },
+  [B2055_C2_LGBUF_GTUNE]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_LGBUF_DIV]		= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_LGBUF_AIDAC]	= { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, },
+  [B2055_C2_LGBUF_GIDAC]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_LGBUF_IDACFO]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_LGBUF_SPARE]	= { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, },
+  [B2055_C2_RX_RFSPC1]		= { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, },
+  [B2055_C2_RX_RFR1]		= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C2_RX_RFR2]		= { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, },
+  [B2055_C2_RX_RFRCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C2_RX_BB_BLCMP]	= { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, },
+  [B2055_C2_RX_BB_LPF]		= { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C2_RX_BB_MIDACHP]	= { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C2_RX_BB_VGA1IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_VGA2IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_VGA3IDAC]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_BUFOCTL]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_RX_BB_RCCALCTL]	= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL1]	= { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL2]	= { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL3]	= { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL4]	= { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, },
+  [B2055_C2_RX_BB_RSSICTL5]	= { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, },
+  [B2055_C2_RX_BB_REG]		= { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, },
+  [B2055_C2_RX_BB_SPARE1]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_RX_TXBBRCAL]	= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C2_TX_RF_SPGA]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C2_TX_RF_SPAD]		= { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, },
+  [B2055_C2_TX_RF_CNTPGA1]	= { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, },
+  [B2055_C2_TX_RF_CNTPAD1]	= { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, },
+  [B2055_C2_TX_RF_PGAIDAC]	= { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, },
+  [B2055_C2_TX_PGAPADTN]	= { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, },
+  [B2055_C2_TX_PADIDAC1]	= { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, },
+  [B2055_C2_TX_PADIDAC2]	= { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, },
+  [B2055_C2_TX_MXBGTRIM]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [B2055_C2_TX_RF_RCAL]		= { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, },
+  [B2055_C2_TX_RF_PADTSSI1]	= { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C2_TX_RF_PADTSSI2]	= { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, },
+  [B2055_C2_TX_RF_SPARE]	= { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, },
+  [B2055_C2_TX_RF_IQCAL1]	= { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, },
+  [B2055_C2_TX_RF_IQCAL2]	= { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, },
+  [B2055_C2_TXBB_RCCAL]		= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C2_TXBB_LPF1]		= { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, },
+  [B2055_C2_TX_VOSCNCL]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_TX_LPF_MXGMIDAC]	= { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, },
+  [B2055_C2_TX_BB_MXGM]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_PRG_GCHP21]		= { .ghz5 = 0x0071, .ghz2 = 0x0071, NOUPLOAD, },
+  [B2055_PRG_GCHP22]		= { .ghz5 = 0x0072, .ghz2 = 0x0072, NOUPLOAD, },
+  [B2055_PRG_GCHP23]		= { .ghz5 = 0x0073, .ghz2 = 0x0073, NOUPLOAD, },
+  [B2055_PRG_GCHP24]		= { .ghz5 = 0x0074, .ghz2 = 0x0074, NOUPLOAD, },
+  [B2055_PRG_GCHP25]		= { .ghz5 = 0x0075, .ghz2 = 0x0075, NOUPLOAD, },
+  [B2055_PRG_GCHP26]		= { .ghz5 = 0x0076, .ghz2 = 0x0076, NOUPLOAD, },
+  [B2055_PRG_GCHP27]		= { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, },
+  [B2055_PRG_GCHP28]		= { .ghz5 = 0x0078, .ghz2 = 0x0078, NOUPLOAD, },
+  [B2055_PRG_GCHP29]		= { .ghz5 = 0x0079, .ghz2 = 0x0079, NOUPLOAD, },
+  [B2055_PRG_GCHP30]		= { .ghz5 = 0x007A, .ghz2 = 0x007A, NOUPLOAD, },
+  [0xC7]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xC8]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xC9]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCA]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCB]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCC]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_LNA_GAINBST]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCE]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xCF]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD0]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD1]			= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C1_B0NB_RSSIVCM]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [0xD3]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD4]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD5]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C1_GENSPARE2]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD7]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xD8]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_LNA_GAINBST]	= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDA]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDB]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDC]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xDD]			= { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, },
+  [B2055_C2_B0NB_RSSIVCM]	= { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, },
+  [0xDF]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xE0]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [0xE1]			= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+  [B2055_C2_GENSPARE2]		= { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, },
+};
+
+
+void b2055_upload_inittab(struct b43_wldev *dev,
+			  bool ghz5, bool ignore_uploadflag)
+{
+	const struct b2055_inittab_entry *e;
+	unsigned int i;
+	u16 value;
+
+	for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) {
+		e = &(b2055_inittab[i]);
+		if (!(e->flags & B2055_INITTAB_ENTRY_OK))
+			continue;
+		if ((e->flags & B2055_INITTAB_UPLOAD) || ignore_uploadflag) {
+			if (ghz5)
+				value = e->ghz5;
+			else
+				value = e->ghz2;
+			b43_radio_write16(dev, i, value);
+		}
+	}
+}
+
+
+#define RADIOREGS(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, \
+		  r12, r13, r14, r15, r16, r17, r18, r19, r20, r21) \
+	.radio_pll_ref		= r0,	\
+	.radio_rf_pllmod0	= r1,	\
+	.radio_rf_pllmod1	= r2,	\
+	.radio_vco_captail	= r3,	\
+	.radio_vco_cal1		= r4,	\
+	.radio_vco_cal2		= r5,	\
+	.radio_pll_lfc1		= r6,	\
+	.radio_pll_lfr1		= r7,	\
+	.radio_pll_lfc2		= r8,	\
+	.radio_lgbuf_cenbuf	= r9,	\
+	.radio_lgen_tune1	= r10,	\
+	.radio_lgen_tune2	= r11,	\
+	.radio_c1_lgbuf_atune	= r12,	\
+	.radio_c1_lgbuf_gtune	= r13,	\
+	.radio_c1_rx_rfr1	= r14,	\
+	.radio_c1_tx_pgapadtn	= r15,	\
+	.radio_c1_tx_mxbgtrim	= r16,	\
+	.radio_c2_lgbuf_atune	= r17,	\
+	.radio_c2_lgbuf_gtune	= r18,	\
+	.radio_c2_rx_rfr1	= r19,	\
+	.radio_c2_tx_pgapadtn	= r20,	\
+	.radio_c2_tx_mxbgtrim	= r21
+
+#define PHYREGS(r0, r1, r2, r3, r4, r5)	\
+	.phy_bw1a	= r0,		\
+	.phy_bw2	= r1,		\
+	.phy_bw3	= r2,		\
+	.phy_bw4	= r3,		\
+	.phy_bw5	= r4,		\
+	.phy_bw6	= r5
+
+static const struct b43_nphy_channeltab_entry b43_nphy_channeltab[] = {
+  {	.channel		= 184,
+	.freq			= 4920, /* MHz */
+	.unk2			= 3280,
+	RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xB407, 0xB007, 0xAC07, 0x1402, 0x1502, 0x1602),
+  },
+  {	.channel		= 186,
+	.freq			= 4930, /* MHz */
+	.unk2			= 3287,
+	RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xB807, 0xB407, 0xB007, 0x1302, 0x1402, 0x1502),
+  },
+  {	.channel		= 188,
+	.freq			= 4940, /* MHz */
+	.unk2			= 3293,
+	RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xBC07, 0xB807, 0xB407, 0x1202, 0x1302, 0x1402),
+  },
+  {	.channel		= 190,
+	.freq			= 4950, /* MHz */
+	.unk2			= 3300,
+	RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xC007, 0xBC07, 0xB807, 0x1102, 0x1202, 0x1302),
+  },
+  {	.channel		= 192,
+	.freq			= 4960, /* MHz */
+	.unk2			= 3307,
+	RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xC407, 0xC007, 0xBC07, 0x0F02, 0x1102, 0x1202),
+  },
+  {	.channel		= 194,
+	.freq			= 4970, /* MHz */
+	.unk2			= 3313,
+	RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xC807, 0xC407, 0xC007, 0x0E02, 0x0F02, 0x1102),
+  },
+  {	.channel		= 196,
+	.freq			= 4980, /* MHz */
+	.unk2			= 3320,
+	RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xCC07, 0xC807, 0xC407, 0x0D02, 0x0E02, 0x0F02),
+  },
+  {	.channel		= 198,
+	.freq			= 4990, /* MHz */
+	.unk2			= 3327,
+	RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xD007, 0xCC07, 0xC807, 0x0C02, 0x0D02, 0x0E02),
+  },
+  {	.channel		= 200,
+	.freq			= 5000, /* MHz */
+	.unk2			= 3333,
+	RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xD407, 0xD007, 0xCC07, 0x0B02, 0x0C02, 0x0D02),
+  },
+  {	.channel		= 202,
+	.freq			= 5010, /* MHz */
+	.unk2			= 3340,
+	RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xD807, 0xD407, 0xD007, 0x0A02, 0x0B02, 0x0C02),
+  },
+  {	.channel		= 204,
+	.freq			= 5020, /* MHz */
+	.unk2			= 3347,
+	RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xDC07, 0xD807, 0xD407, 0x0902, 0x0A02, 0x0B02),
+  },
+  {	.channel		= 206,
+	.freq			= 5030, /* MHz */
+	.unk2			= 3353,
+	RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xE007, 0xDC07, 0xD807, 0x0802, 0x0902, 0x0A02),
+  },
+  {	.channel		= 208,
+	.freq			= 5040, /* MHz */
+	.unk2			= 3360,
+	RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xE407, 0xE007, 0xDC07, 0x0702, 0x0802, 0x0902),
+  },
+  {	.channel		= 210,
+	.freq			= 5050, /* MHz */
+	.unk2			= 3367,
+	RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
+		  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
+	PHYREGS(0xE807, 0xE407, 0xE007, 0x0602, 0x0702, 0x0802),
+  },
+  {	.channel		= 212,
+	.freq			= 5060, /* MHz */
+	.unk2			= 3373,
+	RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
+		  0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
+	PHYREGS(0xEC07, 0xE807, 0xE407, 0x0502, 0x0602, 0x0702),
+  },
+  {	.channel		= 214,
+	.freq			= 5070, /* MHz */
+	.unk2			= 3380,
+	RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
+		  0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
+	PHYREGS(0xF007, 0xEC07, 0xE807, 0x0402, 0x0502, 0x0602),
+  },
+  {	.channel		= 216,
+	.freq			= 5080, /* MHz */
+	.unk2			= 3387,
+	RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
+		  0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
+	PHYREGS(0xF407, 0xF007, 0xEC07, 0x0302, 0x0402, 0x0502),
+  },
+  {	.channel		= 218,
+	.freq			= 5090, /* MHz */
+	.unk2			= 3393,
+	RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
+		  0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
+	PHYREGS(0xF807, 0xF407, 0xF007, 0x0202, 0x0302, 0x0402),
+  },
+  {	.channel		= 220,
+	.freq			= 5100, /* MHz */
+	.unk2			= 3400,
+	RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
+		  0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
+	PHYREGS(0xFC07, 0xF807, 0xF407, 0x0102, 0x0202, 0x0302),
+  },
+  {	.channel		= 222,
+	.freq			= 5110, /* MHz */
+	.unk2			= 3407,
+	RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
+		  0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
+	PHYREGS(0x0008, 0xFC07, 0xF807, 0x0002, 0x0102, 0x0202),
+  },
+  {	.channel		= 224,
+	.freq			= 5120, /* MHz */
+	.unk2			= 3413,
+	RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
+		  0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
+	PHYREGS(0x0408, 0x0008, 0xFC07, 0xFF01, 0x0002, 0x0102),
+  },
+  {	.channel		= 226,
+	.freq			= 5130, /* MHz */
+	.unk2			= 3420,
+	RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
+		  0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
+	PHYREGS(0x0808, 0x0408, 0x0008, 0xFE01, 0xFF01, 0x0002),
+  },
+  {	.channel		= 228,
+	.freq			= 5140, /* MHz */
+	.unk2			= 3427,
+	RADIOREGS(0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E,
+		  0x8B, 0xDD, 0x00, 0x0C, 0x0E, 0x8B),
+	PHYREGS(0x0C08, 0x0808, 0x0408, 0xFD01, 0xFE01, 0xFF01),
+  },
+  {	.channel		= 32,
+	.freq			= 5160, /* MHz */
+	.unk2			= 3440,
+	RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
+		  0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
+	PHYREGS(0x1408, 0x1008, 0x0C08, 0xFB01, 0xFC01, 0xFD01),
+  },
+  {	.channel		= 34,
+	.freq			= 5170, /* MHz */
+	.unk2			= 3447,
+	RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+		  0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
+		  0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
+	PHYREGS(0x1808, 0x1408, 0x1008, 0xFA01, 0xFB01, 0xFC01),
+  },
+  {	.channel		= 36,
+	.freq			= 5180, /* MHz */
+	.unk2			= 3453,
+	RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
+		  0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
+	PHYREGS(0x1C08, 0x1808, 0x1408, 0xF901, 0xFA01, 0xFB01),
+  },
+  {	.channel		= 38,
+	.freq			= 5190, /* MHz */
+	.unk2			= 3460,
+	RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+		  0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
+		  0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
+	PHYREGS(0x2008, 0x1C08, 0x1808, 0xF801, 0xF901, 0xFA01),
+  },
+  {	.channel		= 40,
+	.freq			= 5200, /* MHz */
+	.unk2			= 3467,
+	RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
+		  0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
+	PHYREGS(0x2408, 0x2008, 0x1C08, 0xF701, 0xF801, 0xF901),
+  },
+  {	.channel		= 42,
+	.freq			= 5210, /* MHz */
+	.unk2			= 3473,
+	RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+		  0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
+		  0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
+	PHYREGS(0x2808, 0x2408, 0x2008, 0xF601, 0xF701, 0xF801),
+  },
+  {	.channel		= 44,
+	.freq			= 5220, /* MHz */
+	.unk2			= 3480,
+	RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+		  0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
+		  0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
+	PHYREGS(0x2C08, 0x2808, 0x2408, 0xF501, 0xF601, 0xF701),
+  },
+  {	.channel		= 46,
+	.freq			= 5230, /* MHz */
+	.unk2			= 3487,
+	RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+		  0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
+		  0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
+	PHYREGS(0x3008, 0x2C08, 0x2808, 0xF401, 0xF501, 0xF601),
+  },
+  {	.channel		= 48,
+	.freq			= 5240, /* MHz */
+	.unk2			= 3493,
+	RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+		  0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
+		  0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
+	PHYREGS(0x3408, 0x3008, 0x2C08, 0xF301, 0xF401, 0xF501),
+  },
+  {	.channel		= 50,
+	.freq			= 5250, /* MHz */
+	.unk2			= 3500,
+	RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+		  0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
+		  0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
+	PHYREGS(0x3808, 0x3408, 0x3008, 0xF201, 0xF301, 0xF401),
+  },
+  {	.channel		= 52,
+	.freq			= 5260, /* MHz */
+	.unk2			= 3507,
+	RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+		  0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
+		  0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
+	PHYREGS(0x3C08, 0x3808, 0x3408, 0xF101, 0xF201, 0xF301),
+  },
+  {	.channel		= 54,
+	.freq			= 5270, /* MHz */
+	.unk2			= 3513,
+	RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+		  0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
+		  0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
+	PHYREGS(0x4008, 0x3C08, 0x3808, 0xF001, 0xF101, 0xF201),
+  },
+  {	.channel		= 56,
+	.freq			= 5280, /* MHz */
+	.unk2			= 3520,
+	RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A,
+		  0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
+		  0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
+	PHYREGS(0x4408, 0x4008, 0x3C08, 0xF001, 0xF001, 0xF101),
+  },
+  {	.channel		= 58,
+	.freq			= 5290, /* MHz */
+	.unk2			= 3527,
+	RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A,
+		  0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
+		  0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
+	PHYREGS(0x4808, 0x4408, 0x4008, 0xEF01, 0xF001, 0xF001),
+  },
+  {	.channel		= 60,
+	.freq			= 5300, /* MHz */
+	.unk2			= 3533,
+	RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+		  0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
+		  0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
+	PHYREGS(0x4C08, 0x4808, 0x4408, 0xEE01, 0xEF01, 0xF001),
+  },
+  {	.channel		= 62,
+	.freq			= 5310, /* MHz */
+	.unk2			= 3540,
+	RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+		  0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
+		  0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
+	PHYREGS(0x5008, 0x4C08, 0x4808, 0xED01, 0xEE01, 0xEF01),
+  },
+  {	.channel		= 64,
+	.freq			= 5320, /* MHz */
+	.unk2			= 3547,
+	RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A,
+		  0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
+		  0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
+	PHYREGS(0x5408, 0x5008, 0x4C08, 0xEC01, 0xED01, 0xEE01),
+  },
+  {	.channel		= 66,
+	.freq			= 5330, /* MHz */
+	.unk2			= 3553,
+	RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A,
+		  0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
+		  0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
+	PHYREGS(0x5808, 0x5408, 0x5008, 0xEB01, 0xEC01, 0xED01),
+  },
+  {	.channel		= 68,
+	.freq			= 5340, /* MHz */
+	.unk2			= 3560,
+	RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+		  0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
+		  0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
+	PHYREGS(0x5C08, 0x5808, 0x5408, 0xEA01, 0xEB01, 0xEC01),
+  },
+  {	.channel		= 70,
+	.freq			= 5350, /* MHz */
+	.unk2			= 3567,
+	RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+		  0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
+		  0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
+	PHYREGS(0x6008, 0x5C08, 0x5808, 0xE901, 0xEA01, 0xEB01),
+  },
+  {	.channel		= 72,
+	.freq			= 5360, /* MHz */
+	.unk2			= 3573,
+	RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A,
+		  0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
+		  0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
+	PHYREGS(0x6408, 0x6008, 0x5C08, 0xE801, 0xE901, 0xEA01),
+  },
+  {	.channel		= 74,
+	.freq			= 5370, /* MHz */
+	.unk2			= 3580,
+	RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A,
+		  0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
+		  0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
+	PHYREGS(0x6808, 0x6408, 0x6008, 0xE701, 0xE801, 0xE901),
+  },
+  {	.channel		= 76,
+	.freq			= 5380, /* MHz */
+	.unk2			= 3587,
+	RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+		  0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
+		  0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
+	PHYREGS(0x6C08, 0x6808, 0x6408, 0xE601, 0xE701, 0xE801),
+  },
+  {	.channel		= 78,
+	.freq			= 5390, /* MHz */
+	.unk2			= 3593,
+	RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+		  0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
+		  0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
+	PHYREGS(0x7008, 0x6C08, 0x6808, 0xE501, 0xE601, 0xE701),
+  },
+  {	.channel		= 80,
+	.freq			= 5400, /* MHz */
+	.unk2			= 3600,
+	RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A,
+		  0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
+		  0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
+	PHYREGS(0x7408, 0x7008, 0x6C08, 0xE501, 0xE501, 0xE601),
+  },
+  {	.channel		= 82,
+	.freq			= 5410, /* MHz */
+	.unk2			= 3607,
+	RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A,
+		  0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
+		  0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
+	PHYREGS(0x7808, 0x7408, 0x7008, 0xE401, 0xE501, 0xE501),
+  },
+  {	.channel		= 84,
+	.freq			= 5420, /* MHz */
+	.unk2			= 3613,
+	RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A,
+		  0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
+		  0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
+	PHYREGS(0x7C08, 0x7808, 0x7408, 0xE301, 0xE401, 0xE501),
+  },
+  {	.channel		= 86,
+	.freq			= 5430, /* MHz */
+	.unk2			= 3620,
+	RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A,
+		  0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
+		  0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
+	PHYREGS(0x8008, 0x7C08, 0x7808, 0xE201, 0xE301, 0xE401),
+  },
+  {	.channel		= 88,
+	.freq			= 5440, /* MHz */
+	.unk2			= 3627,
+	RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+		  0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
+		  0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
+	PHYREGS(0x8408, 0x8008, 0x7C08, 0xE101, 0xE201, 0xE301),
+  },
+  {	.channel		= 90,
+	.freq			= 5450, /* MHz */
+	.unk2			= 3633,
+	RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+		  0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
+		  0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
+	PHYREGS(0x8808, 0x8408, 0x8008, 0xE001, 0xE101, 0xE201),
+  },
+  {	.channel		= 92,
+	.freq			= 5460, /* MHz */
+	.unk2			= 3640,
+	RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A,
+		  0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
+		  0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
+	PHYREGS(0x8C08, 0x8808, 0x8408, 0xDF01, 0xE001, 0xE101),
+  },
+  {	.channel		= 94,
+	.freq			= 5470, /* MHz */
+	.unk2			= 3647,
+	RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A,
+		  0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
+		  0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
+	PHYREGS(0x9008, 0x8C08, 0x8808, 0xDE01, 0xDF01, 0xE001),
+  },
+  {	.channel		= 96,
+	.freq			= 5480, /* MHz */
+	.unk2			= 3653,
+	RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+		  0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
+		  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+	PHYREGS(0x9408, 0x9008, 0x8C08, 0xDD01, 0xDE01, 0xDF01),
+  },
+  {	.channel		= 98,
+	.freq			= 5490, /* MHz */
+	.unk2			= 3660,
+	RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+		  0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
+		  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+	PHYREGS(0x9808, 0x9408, 0x9008, 0xDD01, 0xDD01, 0xDE01),
+  },
+  {	.channel		= 100,
+	.freq			= 5500, /* MHz */
+	.unk2			= 3667,
+	RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A,
+		  0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
+		  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+	PHYREGS(0x9C08, 0x9808, 0x9408, 0xDC01, 0xDD01, 0xDD01),
+  },
+  {	.channel		= 102,
+	.freq			= 5510, /* MHz */
+	.unk2			= 3673,
+	RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A,
+		  0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
+		  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
+	PHYREGS(0xA008, 0x9C08, 0x9808, 0xDB01, 0xDC01, 0xDD01),
+  },
+  {	.channel		= 104,
+	.freq			= 5520, /* MHz */
+	.unk2			= 3680,
+	RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A,
+		  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+		  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+	PHYREGS(0xA408, 0xA008, 0x9C08, 0xDA01, 0xDB01, 0xDC01),
+  },
+  {	.channel		= 106,
+	.freq			= 5530, /* MHz */
+	.unk2			= 3687,
+	RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A,
+		  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+		  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+	PHYREGS(0xA808, 0xA408, 0xA008, 0xD901, 0xDA01, 0xDB01),
+  },
+  {	.channel		= 108,
+	.freq			= 5540, /* MHz */
+	.unk2			= 3693,
+	RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+		  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+		  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+	PHYREGS(0xAC08, 0xA808, 0xA408, 0xD801, 0xD901, 0xDA01),
+  },
+  {	.channel		= 110,
+	.freq			= 5550, /* MHz */
+	.unk2			= 3700,
+	RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+		  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
+		  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
+	PHYREGS(0xB008, 0xAC08, 0xA808, 0xD701, 0xD801, 0xD901),
+  },
+  {	.channel		= 112,
+	.freq			= 5560, /* MHz */
+	.unk2			= 3707,
+	RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A,
+		  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+		  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xB408, 0xB008, 0xAC08, 0xD701, 0xD701, 0xD801),
+  },
+  {	.channel		= 114,
+	.freq			= 5570, /* MHz */
+	.unk2			= 3713,
+	RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A,
+		  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+		  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xB808, 0xB408, 0xB008, 0xD601, 0xD701, 0xD701),
+  },
+  {	.channel		= 116,
+	.freq			= 5580, /* MHz */
+	.unk2			= 3720,
+	RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+		  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+		  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xBC08, 0xB808, 0xB408, 0xD501, 0xD601, 0xD701),
+  },
+  {	.channel		= 118,
+	.freq			= 5590, /* MHz */
+	.unk2			= 3727,
+	RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+		  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
+		  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xC008, 0xBC08, 0xB808, 0xD401, 0xD501, 0xD601),
+  },
+  {	.channel		= 120,
+	.freq			= 5600, /* MHz */
+	.unk2			= 3733,
+	RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A,
+		  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
+		  0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xC408, 0xC008, 0xBC08, 0xD301, 0xD401, 0xD501),
+  },
+  {	.channel		= 122,
+	.freq			= 5610, /* MHz */
+	.unk2			= 3740,
+	RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A,
+		  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
+		  0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
+	PHYREGS(0xC808, 0xC408, 0xC008, 0xD201, 0xD301, 0xD401),
+  },
+  {	.channel		= 124,
+	.freq			= 5620, /* MHz */
+	.unk2			= 3747,
+	RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A,
+		  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+		  0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xCC08, 0xC808, 0xC408, 0xD201, 0xD201, 0xD301),
+  },
+  {	.channel		= 126,
+	.freq			= 5630, /* MHz */
+	.unk2			= 3753,
+	RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A,
+		  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
+		  0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xD008, 0xCC08, 0xC808, 0xD101, 0xD201, 0xD201),
+  },
+  {	.channel		= 128,
+	.freq			= 5640, /* MHz */
+	.unk2			= 3760,
+	RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xD408, 0xD008, 0xCC08, 0xD001, 0xD101, 0xD201),
+  },
+  {	.channel		= 130,
+	.freq			= 5650, /* MHz */
+	.unk2			= 3767,
+	RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xD808, 0xD408, 0xD008, 0xCF01, 0xD001, 0xD101),
+  },
+  {	.channel		= 132,
+	.freq			= 5660, /* MHz */
+	.unk2			= 3773,
+	RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xDC08, 0xD808, 0xD408, 0xCE01, 0xCF01, 0xD001),
+  },
+  {	.channel		= 134,
+	.freq			= 5670, /* MHz */
+	.unk2			= 3780,
+	RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xE008, 0xDC08, 0xD808, 0xCE01, 0xCE01, 0xCF01),
+  },
+  {	.channel		= 136,
+	.freq			= 5680, /* MHz */
+	.unk2			= 3787,
+	RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xE408, 0xE008, 0xDC08, 0xCD01, 0xCE01, 0xCE01),
+  },
+  {	.channel		= 138,
+	.freq			= 5690, /* MHz */
+	.unk2			= 3793,
+	RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xE808, 0xE408, 0xE008, 0xCC01, 0xCD01, 0xCE01),
+  },
+  {	.channel		= 140,
+	.freq			= 5700, /* MHz */
+	.unk2			= 3800,
+	RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xEC08, 0xE808, 0xE408, 0xCB01, 0xCC01, 0xCD01),
+  },
+  {	.channel		= 142,
+	.freq			= 5710, /* MHz */
+	.unk2			= 3807,
+	RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xF008, 0xEC08, 0xE808, 0xCA01, 0xCB01, 0xCC01),
+  },
+  {	.channel		= 144,
+	.freq			= 5720, /* MHz */
+	.unk2			= 3813,
+	RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xF408, 0xF008, 0xEC08, 0xC901, 0xCA01, 0xCB01),
+  },
+  {	.channel		= 145,
+	.freq			= 5725, /* MHz */
+	.unk2			= 3817,
+	RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xF608, 0xF208, 0xEE08, 0xC901, 0xCA01, 0xCB01),
+  },
+  {	.channel		= 146,
+	.freq			= 5730, /* MHz */
+	.unk2			= 3820,
+	RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xF808, 0xF408, 0xF008, 0xC901, 0xC901, 0xCA01),
+  },
+  {	.channel		= 147,
+	.freq			= 5735, /* MHz */
+	.unk2			= 3823,
+	RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xFA08, 0xF608, 0xF208, 0xC801, 0xC901, 0xCA01),
+  },
+  {	.channel		= 148,
+	.freq			= 5740, /* MHz */
+	.unk2			= 3827,
+	RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xFC08, 0xF808, 0xF408, 0xC801, 0xC901, 0xC901),
+  },
+  {	.channel		= 149,
+	.freq			= 5745, /* MHz */
+	.unk2			= 3830,
+	RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0xFE08, 0xFA08, 0xF608, 0xC801, 0xC801, 0xC901),
+  },
+  {	.channel		= 150,
+	.freq			= 5750, /* MHz */
+	.unk2			= 3833,
+	RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0009, 0xFC08, 0xF808, 0xC701, 0xC801, 0xC901),
+  },
+  {	.channel		= 151,
+	.freq			= 5755, /* MHz */
+	.unk2			= 3837,
+	RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0209, 0xFE08, 0xFA08, 0xC701, 0xC801, 0xC801),
+  },
+  {	.channel		= 152,
+	.freq			= 5760, /* MHz */
+	.unk2			= 3840,
+	RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0409, 0x0009, 0xFC08, 0xC601, 0xC701, 0xC801),
+  },
+  {	.channel		= 153,
+	.freq			= 5765, /* MHz */
+	.unk2			= 3843,
+	RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0609, 0x0209, 0xFE08, 0xC601, 0xC701, 0xC801),
+  },
+  {	.channel		= 154,
+	.freq			= 5770, /* MHz */
+	.unk2			= 3847,
+	RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0809, 0x0409, 0x0009, 0xC601, 0xC601, 0xC701),
+  },
+  {	.channel		= 155,
+	.freq			= 5775, /* MHz */
+	.unk2			= 3850,
+	RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0A09, 0x0609, 0x0209, 0xC501, 0xC601, 0xC701),
+  },
+  {	.channel		= 156,
+	.freq			= 5780, /* MHz */
+	.unk2			= 3853,
+	RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0C09, 0x0809, 0x0409, 0xC501, 0xC601, 0xC601),
+  },
+  {	.channel		= 157,
+	.freq			= 5785, /* MHz */
+	.unk2			= 3857,
+	RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x0E09, 0x0A09, 0x0609, 0xC401, 0xC501, 0xC601),
+  },
+  {	.channel		= 158,
+	.freq			= 5790, /* MHz */
+	.unk2			= 3860,
+	RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1009, 0x0C09, 0x0809, 0xC401, 0xC501, 0xC601),
+  },
+  {	.channel		= 159,
+	.freq			= 5795, /* MHz */
+	.unk2			= 3863,
+	RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1209, 0x0E09, 0x0A09, 0xC401, 0xC401, 0xC501),
+  },
+  {	.channel		= 160,
+	.freq			= 5800, /* MHz */
+	.unk2			= 3867,
+	RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1409, 0x1009, 0x0C09, 0xC301, 0xC401, 0xC501),
+  },
+  {	.channel		= 161,
+	.freq			= 5805, /* MHz */
+	.unk2			= 3870,
+	RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1609, 0x1209, 0x0E09, 0xC301, 0xC401, 0xC401),
+  },
+  {	.channel		= 162,
+	.freq			= 5810, /* MHz */
+	.unk2			= 3873,
+	RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1809, 0x1409, 0x1009, 0xC201, 0xC301, 0xC401),
+  },
+  {	.channel		= 163,
+	.freq			= 5815, /* MHz */
+	.unk2			= 3877,
+	RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1A09, 0x1609, 0x1209, 0xC201, 0xC301, 0xC401),
+  },
+  {	.channel		= 164,
+	.freq			= 5820, /* MHz */
+	.unk2			= 3880,
+	RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1C09, 0x1809, 0x1409, 0xC201, 0xC201, 0xC301),
+  },
+  {	.channel		= 165,
+	.freq			= 5825, /* MHz */
+	.unk2			= 3883,
+	RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x1E09, 0x1A09, 0x1609, 0xC101, 0xC201, 0xC301),
+  },
+  {	.channel		= 166,
+	.freq			= 5830, /* MHz */
+	.unk2			= 3887,
+	RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x2009, 0x1C09, 0x1809, 0xC101, 0xC201, 0xC201),
+  },
+  {	.channel		= 168,
+	.freq			= 5840, /* MHz */
+	.unk2			= 3893,
+	RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x2409, 0x2009, 0x1C09, 0xC001, 0xC101, 0xC201),
+  },
+  {	.channel		= 170,
+	.freq			= 5850, /* MHz */
+	.unk2			= 3900,
+	RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x2809, 0x2409, 0x2009, 0xBF01, 0xC001, 0xC101),
+  },
+  {	.channel		= 172,
+	.freq			= 5860, /* MHz */
+	.unk2			= 3907,
+	RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x2C09, 0x2809, 0x2409, 0xBF01, 0xBF01, 0xC001),
+  },
+  {	.channel		= 174,
+	.freq			= 5870, /* MHz */
+	.unk2			= 3913,
+	RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x3009, 0x2C09, 0x2809, 0xBE01, 0xBF01, 0xBF01),
+  },
+  {	.channel		= 176,
+	.freq			= 5880, /* MHz */
+	.unk2			= 3920,
+	RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x3409, 0x3009, 0x2C09, 0xBD01, 0xBE01, 0xBF01),
+  },
+  {	.channel		= 178,
+	.freq			= 5890, /* MHz */
+	.unk2			= 3927,
+	RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x3809, 0x3409, 0x3009, 0xBC01, 0xBD01, 0xBE01),
+  },
+  {	.channel		= 180,
+	.freq			= 5900, /* MHz */
+	.unk2			= 3933,
+	RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x3C09, 0x3809, 0x3409, 0xBC01, 0xBC01, 0xBD01),
+  },
+  {	.channel		= 182,
+	.freq			= 5910, /* MHz */
+	.unk2			= 3940,
+	RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+		  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
+	PHYREGS(0x4009, 0x3C09, 0x3809, 0xBB01, 0xBC01, 0xBC01),
+  },
+  {	.channel		= 1,
+	.freq			= 2412, /* MHz */
+	.unk2			= 3216,
+	RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C,
+		  0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80),
+	PHYREGS(0xC903, 0xC503, 0xC103, 0x3A04, 0x3F04, 0x4304),
+  },
+  {	.channel		= 2,
+	.freq			= 2417, /* MHz */
+	.unk2			= 3223,
+	RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B,
+		  0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80),
+	PHYREGS(0xCB03, 0xC703, 0xC303, 0x3804, 0x3D04, 0x4104),
+  },
+  {	.channel		= 3,
+	.freq			= 2422, /* MHz */
+	.unk2			= 3229,
+	RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
+		  0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
+	PHYREGS(0xCD03, 0xC903, 0xC503, 0x3604, 0x3A04, 0x3F04),
+  },
+  {	.channel		= 4,
+	.freq			= 2427, /* MHz */
+	.unk2			= 3236,
+	RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
+		  0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
+	PHYREGS(0xCF03, 0xCB03, 0xC703, 0x3404, 0x3804, 0x3D04),
+  },
+  {	.channel		= 5,
+	.freq			= 2432, /* MHz */
+	.unk2			= 3243,
+	RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09,
+		  0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80),
+	PHYREGS(0xD103, 0xCD03, 0xC903, 0x3104, 0x3604, 0x3A04),
+  },
+  {	.channel		= 6,
+	.freq			= 2437, /* MHz */
+	.unk2			= 3249,
+	RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08,
+		  0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80),
+	PHYREGS(0xD303, 0xCF03, 0xCB03, 0x2F04, 0x3404, 0x3804),
+  },
+  {	.channel		= 7,
+	.freq			= 2442, /* MHz */
+	.unk2			= 3256,
+	RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07,
+		  0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80),
+	PHYREGS(0xD503, 0xD103, 0xCD03, 0x2D04, 0x3104, 0x3604),
+  },
+  {	.channel		= 8,
+	.freq			= 2447, /* MHz */
+	.unk2			= 3263,
+	RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06,
+		  0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80),
+	PHYREGS(0xD703, 0xD303, 0xCF03, 0x2B04, 0x2F04, 0x3404),
+  },
+  {	.channel		= 9,
+	.freq			= 2452, /* MHz */
+	.unk2			= 3269,
+	RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06,
+		  0x80, 0xFF, 0x88, 0x09, 0x06, 0x80),
+	PHYREGS(0xD903, 0xD503, 0xD103, 0x2904, 0x2D04, 0x3104),
+  },
+  {	.channel		= 10,
+	.freq			= 2457, /* MHz */
+	.unk2			= 3276,
+	RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05,
+		  0x80, 0xFF, 0x88, 0x08, 0x05, 0x80),
+	PHYREGS(0xDB03, 0xD703, 0xD303, 0x2704, 0x2B04, 0x2F04),
+  },
+  {	.channel		= 11,
+	.freq			= 2462, /* MHz */
+	.unk2			= 3283,
+	RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04,
+		  0x80, 0xFF, 0x88, 0x08, 0x04, 0x80),
+	PHYREGS(0xDD03, 0xD903, 0xD503, 0x2404, 0x2904, 0x2D04),
+  },
+  {	.channel		= 12,
+	.freq			= 2467, /* MHz */
+	.unk2			= 3289,
+	RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03,
+		  0x80, 0xFF, 0x88, 0x08, 0x03, 0x80),
+	PHYREGS(0xDF03, 0xDB03, 0xD703, 0x2204, 0x2704, 0x2B04),
+  },
+  {	.channel		= 13,
+	.freq			= 2472, /* MHz */
+	.unk2			= 3296,
+	RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03,
+		  0x80, 0xFF, 0x88, 0x07, 0x03, 0x80),
+	PHYREGS(0xE103, 0xDD03, 0xD903, 0x2004, 0x2404, 0x2904),
+  },
+  {	.channel		= 14,
+	.freq			= 2484, /* MHz */
+	.unk2			= 3312,
+	RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15,
+		  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01,
+		  0x80, 0xFF, 0x88, 0x07, 0x01, 0x80),
+	PHYREGS(0xE603, 0xE203, 0xDE03, 0x1B04, 0x1F04, 0x2404),
+  },
+};
+
+const struct b43_nphy_channeltab_entry *
+b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel)
+{
+	const struct b43_nphy_channeltab_entry *e;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab); i++) {
+		e = &(b43_nphy_channeltab[i]);
+		if (e->channel == channel)
+			return e;
+	}
+
+	return NULL;
+}
+
+
+const u8 b43_ntab_adjustpower0[] = {
+	0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+	0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
+	0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
+	0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
+	0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
+	0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B,
+	0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
+	0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
+	0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
+	0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+	0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
+	0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+	0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
+	0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B,
+	0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D,
+	0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
+};
+
+const u8 b43_ntab_adjustpower1[] = {
+	0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+	0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
+	0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
+	0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
+	0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09,
+	0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B,
+	0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
+	0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
+	0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
+	0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
+	0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
+	0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
+	0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19,
+	0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B,
+	0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D,
+	0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F,
+};
+
+const u16 b43_ntab_bdi[] = {
+	0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2,
+};
+
+const u32 b43_ntab_channelest[] = {
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x44444444, 0x44444444, 0x44444444, 0x44444444,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+	0x10101010, 0x10101010, 0x10101010, 0x10101010,
+};
+
+const u8 b43_ntab_estimatepowerlt0[] = {
+	0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
+	0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
+	0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
+	0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
+	0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29,
+	0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21,
+	0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19,
+	0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
+};
+
+const u8 b43_ntab_estimatepowerlt1[] = {
+	0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49,
+	0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41,
+	0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39,
+	0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
+	0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29,
+	0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21,
+	0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19,
+	0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
+};
+
+const u8 b43_ntab_framelookup[] = {
+	0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16,
+	0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E,
+	0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A,
+	0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A,
+};
+
+const u32 b43_ntab_framestruct[] = {
+	0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
+	0x09804506, 0x00100030, 0x09804507, 0x00100030,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028,
+	0x0980450E, 0x00100038, 0x0980450F, 0x00100038,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000A04, 0x00100000, 0x11008A05, 0x00100020,
+	0x1980C506, 0x00100030, 0x21810506, 0x00100030,
+	0x21810506, 0x00100030, 0x01800504, 0x00100030,
+	0x11808505, 0x00100030, 0x29814507, 0x01100030,
+	0x00000A04, 0x00100000, 0x11008A05, 0x00100020,
+	0x21810506, 0x00100030, 0x21810506, 0x00100030,
+	0x29814507, 0x01100030, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+	0x1980C50E, 0x00100038, 0x2181050E, 0x00100038,
+	0x2181050E, 0x00100038, 0x0180050C, 0x00100038,
+	0x1180850D, 0x00100038, 0x2981450F, 0x01100038,
+	0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+	0x2181050E, 0x00100038, 0x2181050E, 0x00100038,
+	0x2981450F, 0x01100038, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
+	0x1980C506, 0x00100030, 0x1980C506, 0x00100030,
+	0x11808504, 0x00100030, 0x3981CA05, 0x00100030,
+	0x29814507, 0x01100030, 0x00000000, 0x00000000,
+	0x10008A04, 0x00100000, 0x3981CA05, 0x00100030,
+	0x1980C506, 0x00100030, 0x29814507, 0x01100030,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028,
+	0x1980C50E, 0x00100038, 0x1980C50E, 0x00100038,
+	0x1180850C, 0x00100038, 0x3981CA0D, 0x00100038,
+	0x2981450F, 0x01100038, 0x00000000, 0x00000000,
+	0x10008A0C, 0x00100008, 0x3981CA0D, 0x00100038,
+	0x1980C50E, 0x00100038, 0x2981450F, 0x01100038,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x40021404, 0x00100000, 0x02001405, 0x00100040,
+	0x0B004A06, 0x01900060, 0x13008A06, 0x01900060,
+	0x13008A06, 0x01900060, 0x43020A04, 0x00100060,
+	0x1B00CA05, 0x00100060, 0x23010A07, 0x01500060,
+	0x40021404, 0x00100000, 0x1A00D405, 0x00100040,
+	0x13008A06, 0x01900060, 0x13008A06, 0x01900060,
+	0x23010A07, 0x01500060, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x00100010, 0x0200140D, 0x00100050,
+	0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070,
+	0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070,
+	0x1B00CA0D, 0x00100070, 0x23010A0F, 0x01500070,
+	0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+	0x13008A0E, 0x01900070, 0x13008A0E, 0x01900070,
+	0x23010A0F, 0x01500070, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x50029404, 0x00100000, 0x32019405, 0x00100040,
+	0x0B004A06, 0x01900060, 0x0B004A06, 0x01900060,
+	0x5B02CA04, 0x00100060, 0x3B01D405, 0x00100060,
+	0x23010A07, 0x01500060, 0x00000000, 0x00000000,
+	0x5802D404, 0x00100000, 0x3B01D405, 0x00100060,
+	0x0B004A06, 0x01900060, 0x23010A07, 0x01500060,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x5002940C, 0x00100010, 0x3201940D, 0x00100050,
+	0x0B004A0E, 0x01900070, 0x0B004A0E, 0x01900070,
+	0x5B02CA0C, 0x00100070, 0x3B01D40D, 0x00100070,
+	0x23010A0F, 0x01500070, 0x00000000, 0x00000000,
+	0x5802D40C, 0x00100010, 0x3B01D40D, 0x00100070,
+	0x0B004A0E, 0x01900070, 0x23010A0F, 0x01500070,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x40021404, 0x000F4800, 0x62031405, 0x00100040,
+	0x53028A06, 0x01900060, 0x53028A07, 0x01900060,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x000F4810, 0x6203140D, 0x00100050,
+	0x53028A0E, 0x01900070, 0x53028A0F, 0x01900070,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+	0x1980C50E, 0x00100038, 0x2181050E, 0x00100038,
+	0x2181050E, 0x00100038, 0x0180050C, 0x00100038,
+	0x1180850D, 0x00100038, 0x1181850D, 0x00100038,
+	0x2981450F, 0x01100038, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028,
+	0x2181050E, 0x00100038, 0x2181050E, 0x00100038,
+	0x1181850D, 0x00100038, 0x2981450F, 0x01100038,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x08004A04, 0x00100000, 0x01000A05, 0x00100020,
+	0x0180C506, 0x00100030, 0x0180C506, 0x00100030,
+	0x2180C50C, 0x00100030, 0x49820A0D, 0x0016A130,
+	0x41824A0D, 0x0016A130, 0x2981450F, 0x01100030,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x2000CA0C, 0x00100000, 0x49820A0D, 0x0016A130,
+	0x1980C50E, 0x00100030, 0x41824A0D, 0x0016A130,
+	0x2981450F, 0x01100030, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x00100010, 0x0200140D, 0x00100050,
+	0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070,
+	0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070,
+	0x1B00CA0D, 0x00100070, 0x1B014A0D, 0x00100070,
+	0x23010A0F, 0x01500070, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+	0x13008A0E, 0x01900070, 0x13008A0E, 0x01900070,
+	0x1B014A0D, 0x00100070, 0x23010A0F, 0x01500070,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x50029404, 0x00100000, 0x32019405, 0x00100040,
+	0x03004A06, 0x01900060, 0x03004A06, 0x01900060,
+	0x6B030A0C, 0x00100060, 0x4B02140D, 0x0016A160,
+	0x4302540D, 0x0016A160, 0x23010A0F, 0x01500060,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x6B03140C, 0x00100060, 0x4B02140D, 0x0016A160,
+	0x0B004A0E, 0x01900060, 0x4302540D, 0x0016A160,
+	0x23010A0F, 0x01500060, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x40021404, 0x00100000, 0x1A00D405, 0x00100040,
+	0x53028A06, 0x01900060, 0x5B02CA06, 0x01900060,
+	0x5B02CA06, 0x01900060, 0x43020A04, 0x00100060,
+	0x1B00CA05, 0x00100060, 0x53028A07, 0x0190C060,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+	0x53028A0E, 0x01900070, 0x5B02CA0E, 0x01900070,
+	0x5B02CA0E, 0x01900070, 0x43020A0C, 0x00100070,
+	0x1B00CA0D, 0x00100070, 0x53028A0F, 0x0190C070,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x40021404, 0x00100000, 0x1A00D405, 0x00100040,
+	0x5B02CA06, 0x01900060, 0x5B02CA06, 0x01900060,
+	0x53028A07, 0x0190C060, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050,
+	0x5B02CA0E, 0x01900070, 0x5B02CA0E, 0x01900070,
+	0x53028A0F, 0x0190C070, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_gainctl0[] = {
+	0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
+	0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
+	0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
+	0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38,
+	0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336,
+	0x006B0435, 0x006A0535, 0x00690634, 0x00680734,
+	0x00670833, 0x00660933, 0x00650A32, 0x00640B32,
+	0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30,
+	0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E,
+	0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C,
+	0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A,
+	0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28,
+	0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326,
+	0x004B0425, 0x004A0525, 0x00490624, 0x00480724,
+	0x00470823, 0x00460923, 0x00450A22, 0x00440B22,
+	0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20,
+	0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E,
+	0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C,
+	0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A,
+	0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18,
+	0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316,
+	0x002B0415, 0x002A0515, 0x00290614, 0x00280714,
+	0x00270813, 0x00260913, 0x00250A12, 0x00240B12,
+	0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10,
+	0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E,
+	0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C,
+	0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A,
+	0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08,
+	0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306,
+	0x000B0405, 0x000A0505, 0x00090604, 0x00080704,
+	0x00070803, 0x00060903, 0x00050A02, 0x00040B02,
+	0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
+};
+
+const u32 b43_ntab_gainctl1[] = {
+	0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E,
+	0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C,
+	0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A,
+	0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38,
+	0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336,
+	0x006B0435, 0x006A0535, 0x00690634, 0x00680734,
+	0x00670833, 0x00660933, 0x00650A32, 0x00640B32,
+	0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30,
+	0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E,
+	0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C,
+	0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A,
+	0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28,
+	0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326,
+	0x004B0425, 0x004A0525, 0x00490624, 0x00480724,
+	0x00470823, 0x00460923, 0x00450A22, 0x00440B22,
+	0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20,
+	0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E,
+	0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C,
+	0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A,
+	0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18,
+	0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316,
+	0x002B0415, 0x002A0515, 0x00290614, 0x00280714,
+	0x00270813, 0x00260913, 0x00250A12, 0x00240B12,
+	0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10,
+	0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E,
+	0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C,
+	0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A,
+	0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08,
+	0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306,
+	0x000B0405, 0x000A0505, 0x00090604, 0x00080704,
+	0x00070803, 0x00060903, 0x00050A02, 0x00040B02,
+	0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00,
+};
+
+const u32 b43_ntab_intlevel[] = {
+	0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46,
+	0x00C1188D, 0x080024D2, 0x00000070,
+};
+
+const u32 b43_ntab_iqlt0[] = {
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+};
+
+const u32 b43_ntab_iqlt1[] = {
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+	0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F,
+};
+
+const u16 b43_ntab_loftlt0[] = {
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103,
+};
+
+const u16 b43_ntab_loftlt1[] = {
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103,
+	0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101,
+	0x0002, 0x0103,
+};
+
+const u8 b43_ntab_mcs[] = {
+	0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C,
+	0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C,
+	0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C,
+	0xC0, 0xC8, 0xCA, 0xD0, 0xD2, 0xD9, 0xDA, 0xDC,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x01, 0x02, 0x04, 0x08, 0x09, 0x0A, 0x0C,
+	0x10, 0x11, 0x12, 0x14, 0x18, 0x19, 0x1A, 0x1C,
+	0x20, 0x21, 0x22, 0x24, 0x40, 0x41, 0x42, 0x44,
+	0x48, 0x49, 0x4A, 0x4C, 0x50, 0x51, 0x52, 0x54,
+	0x58, 0x59, 0x5A, 0x5C, 0x60, 0x61, 0x62, 0x64,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+const u32 b43_ntab_noisevar10[] = {
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+};
+
+const u32 b43_ntab_noisevar11[] = {
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+	0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D,
+};
+
+const u16 b43_ntab_pilot[] = {
+	0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08,
+	0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5,
+	0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82,
+	0xFFA0, 0xFF28, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+	0xFF82, 0xFFA0, 0xFF28, 0xFF0A, 0xFFFF, 0xFFFF,
+	0xFFFF, 0xFFFF, 0xF83F, 0xFA1F, 0xFA97, 0xFAB5,
+	0xF2BD, 0xF0BF, 0xFFFF, 0xFFFF, 0xF017, 0xF815,
+	0xF215, 0xF095, 0xF035, 0xF01D, 0xFFFF, 0xFFFF,
+	0xFF08, 0xFF02, 0xFF80, 0xFF20, 0xFF08, 0xFF02,
+	0xFF80, 0xFF20, 0xF01F, 0xF817, 0xFA15, 0xF295,
+	0xF0B5, 0xF03D, 0xFFFF, 0xFFFF, 0xF82A, 0xFA0A,
+	0xFA82, 0xFAA0, 0xF2A8, 0xF0AA, 0xFFFF, 0xFFFF,
+	0xF002, 0xF800, 0xF200, 0xF080, 0xF020, 0xF008,
+	0xFFFF, 0xFFFF, 0xF00A, 0xF802, 0xFA00, 0xF280,
+	0xF0A0, 0xF028, 0xFFFF, 0xFFFF,
+};
+
+const u32 b43_ntab_pilotlt[] = {
+	0x76540123, 0x62407351, 0x76543201, 0x76540213,
+	0x76540123, 0x76430521,
+};
+
+const u32 b43_ntab_tdi20a0[] = {
+	0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0,
+	0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D,
+	0x00020301, 0x00030504, 0x00040708, 0x0005090B,
+	0x00064B8E, 0x00095291, 0x000A5494, 0x000B9718,
+	0x000C9927, 0x000D9B2A, 0x000EDD2E, 0x000FDF31,
+	0x000101B4, 0x000243B7, 0x000345BB, 0x000447BE,
+	0x00058982, 0x00068C05, 0x00099309, 0x000A950C,
+	0x000BD78F, 0x000CD992, 0x000DDB96, 0x000F1D99,
+	0x00005FA8, 0x0001422C, 0x0002842F, 0x00038632,
+	0x00048835, 0x0005CA38, 0x0006CCBC, 0x0009D3BF,
+	0x000B1603, 0x000C1806, 0x000D1A0A, 0x000E1C0D,
+	0x000F5E10, 0x00008093, 0x00018297, 0x0002C49A,
+	0x0003C680, 0x0004C880, 0x00060B00, 0x00070D00,
+	0x00000000, 0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdi20a1[] = {
+	0x00014B26, 0x00028D29, 0x000393AD, 0x00049630,
+	0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D,
+	0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B,
+	0x0000488E, 0x00018B91, 0x0002D214, 0x0003D418,
+	0x0004D6A7, 0x000618AA, 0x00071AAE, 0x0009DCB1,
+	0x000B1EB4, 0x000C0137, 0x000D033B, 0x000E053E,
+	0x000F4702, 0x00008905, 0x00020C09, 0x0003128C,
+	0x0004148F, 0x00051712, 0x00065916, 0x00091B19,
+	0x000A1D28, 0x000B5F2C, 0x000C41AF, 0x000D43B2,
+	0x000E85B5, 0x000F87B8, 0x0000C9BC, 0x00024CBF,
+	0x00035303, 0x00045506, 0x0005978A, 0x0006998D,
+	0x00095B90, 0x000A5D93, 0x000B9F97, 0x000C821A,
+	0x000D8400, 0x000EC600, 0x000FC800, 0x00010A00,
+	0x00000000, 0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdi40a0[] = {
+	0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2,
+	0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C,
+	0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2,
+	0x00056447, 0x00072DD0, 0x0008B6DA, 0x000A02E3,
+	0x000B8C6C, 0x000D15F6, 0x0011E484, 0x0013AE0D,
+	0x00153717, 0x00168320, 0x00180CA9, 0x00199633,
+	0x001B6548, 0x001CEED1, 0x001EB7DB, 0x0000C3E4,
+	0x00024D6D, 0x000416F7, 0x0005A585, 0x00076F0F,
+	0x0008F818, 0x000A4421, 0x000BCDAB, 0x000D9734,
+	0x00122649, 0x0013EFD2, 0x001578DC, 0x0016C4E5,
+	0x00184E6E, 0x001A17F8, 0x001BA686, 0x001D3010,
+	0x001EF999, 0x00010522, 0x00028EAC, 0x00045835,
+	0x0005E74A, 0x0007B0D3, 0x00093A5D, 0x000A85E6,
+	0x000C0F6F, 0x000DD8F9, 0x00126787, 0x00143111,
+	0x0015BA9A, 0x00170623, 0x00188FAD, 0x001A5936,
+	0x001BE84B, 0x001DB1D4, 0x001F3B5E, 0x000146E7,
+	0x00031070, 0x000499FA, 0x00062888, 0x0007F212,
+	0x00097B9B, 0x000AC7A4, 0x000C50AE, 0x000E1A37,
+	0x0012A94C, 0x001472D5, 0x0015FC5F, 0x00174868,
+	0x0018D171, 0x001A9AFB, 0x001C2989, 0x001DF313,
+	0x001F7C9C, 0x000188A5, 0x000351AF, 0x0004DB38,
+	0x0006AA4D, 0x000833D7, 0x0009BD60, 0x000B0969,
+	0x000C9273, 0x000E5BFC, 0x00132A8A, 0x0014B414,
+	0x00163D9D, 0x001789A6, 0x001912B0, 0x001ADC39,
+	0x001C6BCE, 0x001E34D8, 0x001FBE61, 0x0001CA6A,
+	0x00039374, 0x00051CFD, 0x0006EC0B, 0x00087515,
+	0x0009FE9E, 0x000B4AA7, 0x000CD3B1, 0x000E9D3A,
+	0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdi40a1[] = {
+	0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD,
+	0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07,
+	0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D,
+	0x00155C37, 0x0016EACB, 0x00187454, 0x001A3DDE,
+	0x001B89E7, 0x001D12F0, 0x001F1CFA, 0x00016B88,
+	0x00033492, 0x0004BE1B, 0x00060A24, 0x0007D32E,
+	0x00095D38, 0x000AEC4C, 0x000C7555, 0x000E3EDF,
+	0x00124AE8, 0x001413F1, 0x0015A37B, 0x00172C89,
+	0x0018B593, 0x001A419C, 0x001BCB25, 0x001D942F,
+	0x001F63B9, 0x0001AD4D, 0x00037657, 0x0004C260,
+	0x00068BE9, 0x000814F3, 0x0009A47C, 0x000B2D8A,
+	0x000CB694, 0x000E429D, 0x00128C26, 0x001455B0,
+	0x0015E4BA, 0x00176E4E, 0x0018F758, 0x001A8361,
+	0x001C0CEA, 0x001DD674, 0x001FA57D, 0x0001EE8B,
+	0x0003B795, 0x0005039E, 0x0006CD27, 0x000856B1,
+	0x0009E5C6, 0x000B6F4F, 0x000CF859, 0x000E8462,
+	0x00130DEB, 0x00149775, 0x00162603, 0x0017AF8C,
+	0x00193896, 0x001AC49F, 0x001C4E28, 0x001E17B2,
+	0x0000A6C7, 0x00023050, 0x0003F9DA, 0x00054563,
+	0x00070EEC, 0x00089876, 0x000A2704, 0x000BB08D,
+	0x000D3A17, 0x001185A0, 0x00134F29, 0x0014D8B3,
+	0x001667C8, 0x0017F151, 0x00197ADB, 0x001B0664,
+	0x001C8FED, 0x001E5977, 0x0000E805, 0x0002718F,
+	0x00043B18, 0x000586A1, 0x0007502B, 0x0008D9B4,
+	0x000A68C9, 0x000BF252, 0x000DBBDC, 0x0011C7E5,
+	0x001390EE, 0x00151A78, 0x0016A906, 0x00183290,
+	0x0019BC19, 0x001B4822, 0x001CD12C, 0x001E9AB5,
+	0x00000000, 0x00000000,
+};
+
+const u32 b43_ntab_tdtrn[] = {
+	0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6,
+	0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68,
+	0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52,
+	0x0C380000, 0x12F6FE52, 0xFE36F592, 0xEE680050,
+	0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6,
+	0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68,
+	0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52,
+	0x0C380000, 0x12F6FE52, 0xFE36F592, 0xEE680050,
+	0x05E305E3, 0x004DEF0C, 0xF5F3FE47, 0xFE611246,
+	0x00000BC7, 0xFE611246, 0xF5F3FE47, 0x004DEF0C,
+	0x05E305E3, 0xEF0C004D, 0xFE47F5F3, 0x1246FE61,
+	0x0BC70000, 0x1246FE61, 0xFE47F5F3, 0xEF0C004D,
+	0x05E305E3, 0x004DEF0C, 0xF5F3FE47, 0xFE611246,
+	0x00000BC7, 0xFE611246, 0xF5F3FE47, 0x004DEF0C,
+	0x05E305E3, 0xEF0C004D, 0xFE47F5F3, 0x1246FE61,
+	0x0BC70000, 0x1246FE61, 0xFE47F5F3, 0xEF0C004D,
+	0xFA58FA58, 0xF895043B, 0xFF4C09C0, 0xFBC6FFA8,
+	0xFB84F384, 0x0798F6F9, 0x05760122, 0x058409F6,
+	0x0B500000, 0x05B7F542, 0x08860432, 0x06DDFEE7,
+	0xFB84F384, 0xF9D90664, 0xF7E8025C, 0x00FFF7BD,
+	0x05A805A8, 0xF7BD00FF, 0x025CF7E8, 0x0664F9D9,
+	0xF384FB84, 0xFEE706DD, 0x04320886, 0xF54205B7,
+	0x00000B50, 0x09F60584, 0x01220576, 0xF6F90798,
+	0xF384FB84, 0xFFA8FBC6, 0x09C0FF4C, 0x043BF895,
+	0x02D402D4, 0x07DE0270, 0xFC96079C, 0xF90AFE94,
+	0xFE00FF2C, 0x02D4065D, 0x092A0096, 0x0014FBB8,
+	0xFD2CFD2C, 0x076AFB3C, 0x0096F752, 0xF991FD87,
+	0xFB2C0200, 0xFEB8F960, 0x08E0FC96, 0x049802A8,
+	0xFD2CFD2C, 0x02A80498, 0xFC9608E0, 0xF960FEB8,
+	0x0200FB2C, 0xFD87F991, 0xF7520096, 0xFB3C076A,
+	0xFD2CFD2C, 0xFBB80014, 0x0096092A, 0x065D02D4,
+	0xFF2CFE00, 0xFE94F90A, 0x079CFC96, 0x027007DE,
+	0x02D402D4, 0x027007DE, 0x079CFC96, 0xFE94F90A,
+	0xFF2CFE00, 0x065D02D4, 0x0096092A, 0xFBB80014,
+	0xFD2CFD2C, 0xFB3C076A, 0xF7520096, 0xFD87F991,
+	0x0200FB2C, 0xF960FEB8, 0xFC9608E0, 0x02A80498,
+	0xFD2CFD2C, 0x049802A8, 0x08E0FC96, 0xFEB8F960,
+	0xFB2C0200, 0xF991FD87, 0x0096F752, 0x076AFB3C,
+	0xFD2CFD2C, 0x0014FBB8, 0x092A0096, 0x02D4065D,
+	0xFE00FF2C, 0xF90AFE94, 0xFC96079C, 0x07DE0270,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x062A0000, 0xFEFA0759, 0x08B80908, 0xF396FC2D,
+	0xF9D6045C, 0xFC4EF608, 0xF748F596, 0x07B207BF,
+	0x062A062A, 0xF84EF841, 0xF748F596, 0x03B209F8,
+	0xF9D6045C, 0x0C6A03D3, 0x08B80908, 0x0106F8A7,
+	0x062A0000, 0xFEFAF8A7, 0x08B8F6F8, 0xF39603D3,
+	0xF9D6FBA4, 0xFC4E09F8, 0xF7480A6A, 0x07B2F841,
+	0x062AF9D6, 0xF84E07BF, 0xF7480A6A, 0x03B2F608,
+	0xF9D6FBA4, 0x0C6AFC2D, 0x08B8F6F8, 0x01060759,
+	0x062A0000, 0xFEFA0759, 0x08B80908, 0xF396FC2D,
+	0xF9D6045C, 0xFC4EF608, 0xF748F596, 0x07B207BF,
+	0x062A062A, 0xF84EF841, 0xF748F596, 0x03B209F8,
+	0xF9D6045C, 0x0C6A03D3, 0x08B80908, 0x0106F8A7,
+	0x062A0000, 0xFEFAF8A7, 0x08B8F6F8, 0xF39603D3,
+	0xF9D6FBA4, 0xFC4E09F8, 0xF7480A6A, 0x07B2F841,
+	0x062AF9D6, 0xF84E07BF, 0xF7480A6A, 0x03B2F608,
+	0xF9D6FBA4, 0x0C6AFC2D, 0x08B8F6F8, 0x01060759,
+	0x061C061C, 0xFF30009D, 0xFFB21141, 0xFD87FB54,
+	0xF65DFE59, 0x02EEF99E, 0x0166F03C, 0xFFF809B6,
+	0x000008A4, 0x000AF42B, 0x00EFF577, 0xFA840BF2,
+	0xFC02FF51, 0x08260F67, 0xFFF0036F, 0x0842F9C3,
+	0x00000000, 0x063DF7BE, 0xFC910010, 0xF099F7DA,
+	0x00AF03FE, 0xF40E057C, 0x0A89FF11, 0x0BD5FFF6,
+	0xF75C0000, 0xF64A0008, 0x0FC4FE9A, 0x0662FD12,
+	0x01A709A3, 0x04AC0279, 0xEEBF004E, 0xFF6300D0,
+	0xF9E4F9E4, 0x00D0FF63, 0x004EEEBF, 0x027904AC,
+	0x09A301A7, 0xFD120662, 0xFE9A0FC4, 0x0008F64A,
+	0x0000F75C, 0xFFF60BD5, 0xFF110A89, 0x057CF40E,
+	0x03FE00AF, 0xF7DAF099, 0x0010FC91, 0xF7BE063D,
+	0x00000000, 0xF9C30842, 0x036FFFF0, 0x0F670826,
+	0xFF51FC02, 0x0BF2FA84, 0xF57700EF, 0xF42B000A,
+	0x08A40000, 0x09B6FFF8, 0xF03C0166, 0xF99E02EE,
+	0xFE59F65D, 0xFB54FD87, 0x1141FFB2, 0x009DFF30,
+	0x05E30000, 0xFF060705, 0x085408A0, 0xF425FC59,
+	0xFA1D042A, 0xFC78F67A, 0xF7ACF60E, 0x075A0766,
+	0x05E305E3, 0xF8A6F89A, 0xF7ACF60E, 0x03880986,
+	0xFA1D042A, 0x0BDB03A7, 0x085408A0, 0x00FAF8FB,
+	0x05E30000, 0xFF06F8FB, 0x0854F760, 0xF42503A7,
+	0xFA1DFBD6, 0xFC780986, 0xF7AC09F2, 0x075AF89A,
+	0x05E3FA1D, 0xF8A60766, 0xF7AC09F2, 0x0388F67A,
+	0xFA1DFBD6, 0x0BDBFC59, 0x0854F760, 0x00FA0705,
+	0x05E30000, 0xFF060705, 0x085408A0, 0xF425FC59,
+	0xFA1D042A, 0xFC78F67A, 0xF7ACF60E, 0x075A0766,
+	0x05E305E3, 0xF8A6F89A, 0xF7ACF60E, 0x03880986,
+	0xFA1D042A, 0x0BDB03A7, 0x085408A0, 0x00FAF8FB,
+	0x05E30000, 0xFF06F8FB, 0x0854F760, 0xF42503A7,
+	0xFA1DFBD6, 0xFC780986, 0xF7AC09F2, 0x075AF89A,
+	0x05E3FA1D, 0xF8A60766, 0xF7AC09F2, 0x0388F67A,
+	0xFA1DFBD6, 0x0BDBFC59, 0x0854F760, 0x00FA0705,
+	0xFA58FA58, 0xF8F0FE00, 0x0448073D, 0xFDC9FE46,
+	0xF9910258, 0x089D0407, 0xFD5CF71A, 0x02AFFDE0,
+	0x083E0496, 0xFF5A0740, 0xFF7AFD97, 0x00FE01F1,
+	0x0009082E, 0xFA94FF75, 0xFECDF8EA, 0xFFB0F693,
+	0xFD2CFA58, 0x0433FF16, 0xFBA405DD, 0xFA610341,
+	0x06A606CB, 0x0039FD2D, 0x0677FA97, 0x01FA05E0,
+	0xF896003E, 0x075A068B, 0x012CFC3E, 0xFA23F98D,
+	0xFC7CFD43, 0xFF90FC0D, 0x01C10982, 0x00C601D6,
+	0xFD2CFD2C, 0x01D600C6, 0x098201C1, 0xFC0DFF90,
+	0xFD43FC7C, 0xF98DFA23, 0xFC3E012C, 0x068B075A,
+	0x003EF896, 0x05E001FA, 0xFA970677, 0xFD2D0039,
+	0x06CB06A6, 0x0341FA61, 0x05DDFBA4, 0xFF160433,
+	0xFA58FD2C, 0xF693FFB0, 0xF8EAFECD, 0xFF75FA94,
+	0x082E0009, 0x01F100FE, 0xFD97FF7A, 0x0740FF5A,
+	0x0496083E, 0xFDE002AF, 0xF71AFD5C, 0x0407089D,
+	0x0258F991, 0xFE46FDC9, 0x073D0448, 0xFE00F8F0,
+	0xFD2CFD2C, 0xFCE00500, 0xFC09FDDC, 0xFE680157,
+	0x04C70571, 0xFC3AFF21, 0xFCD70228, 0x056D0277,
+	0x0200FE00, 0x0022F927, 0xFE3C032B, 0xFC44FF3C,
+	0x03E9FBDB, 0x04570313, 0x04C9FF5C, 0x000D03B8,
+	0xFA580000, 0xFBE900D2, 0xF9D0FE0B, 0x0125FDF9,
+	0x042501BF, 0x0328FA2B, 0xFFA902F0, 0xFA250157,
+	0x0200FE00, 0x03740438, 0xFF0405FD, 0x030CFE52,
+	0x0037FB39, 0xFF6904C5, 0x04F8FD23, 0xFD31FC1B,
+	0xFD2CFD2C, 0xFC1BFD31, 0xFD2304F8, 0x04C5FF69,
+	0xFB390037, 0xFE52030C, 0x05FDFF04, 0x04380374,
+	0xFE000200, 0x0157FA25, 0x02F0FFA9, 0xFA2B0328,
+	0x01BF0425, 0xFDF90125, 0xFE0BF9D0, 0x00D2FBE9,
+	0x0000FA58, 0x03B8000D, 0xFF5C04C9, 0x03130457,
+	0xFBDB03E9, 0xFF3CFC44, 0x032BFE3C, 0xF9270022,
+	0xFE000200, 0x0277056D, 0x0228FCD7, 0xFF21FC3A,
+	0x057104C7, 0x0157FE68, 0xFDDCFC09, 0x0500FCE0,
+	0xFD2CFD2C, 0x0500FCE0, 0xFDDCFC09, 0x0157FE68,
+	0x057104C7, 0xFF21FC3A, 0x0228FCD7, 0x0277056D,
+	0xFE000200, 0xF9270022, 0x032BFE3C, 0xFF3CFC44,
+	0xFBDB03E9, 0x03130457, 0xFF5C04C9, 0x03B8000D,
+	0x0000FA58, 0x00D2FBE9, 0xFE0BF9D0, 0xFDF90125,
+	0x01BF0425, 0xFA2B0328, 0x02F0FFA9, 0x0157FA25,
+	0xFE000200, 0x04380374, 0x05FDFF04, 0xFE52030C,
+	0xFB390037, 0x04C5FF69, 0xFD2304F8, 0xFC1BFD31,
+	0xFD2CFD2C, 0xFD31FC1B, 0x04F8FD23, 0xFF6904C5,
+	0x0037FB39, 0x030CFE52, 0xFF0405FD, 0x03740438,
+	0x0200FE00, 0xFA250157, 0xFFA902F0, 0x0328FA2B,
+	0x042501BF, 0x0125FDF9, 0xF9D0FE0B, 0xFBE900D2,
+	0xFA580000, 0x000D03B8, 0x04C9FF5C, 0x04570313,
+	0x03E9FBDB, 0xFC44FF3C, 0xFE3C032B, 0x0022F927,
+	0x0200FE00, 0x056D0277, 0xFCD70228, 0xFC3AFF21,
+	0x04C70571, 0xFE680157, 0xFC09FDDC, 0xFCE00500,
+	0x05A80000, 0xFF1006BE, 0x0800084A, 0xF49CFC7E,
+	0xFA580400, 0xFC9CF6DA, 0xF800F672, 0x0710071C,
+	0x05A805A8, 0xF8F0F8E4, 0xF800F672, 0x03640926,
+	0xFA580400, 0x0B640382, 0x0800084A, 0x00F0F942,
+	0x05A80000, 0xFF10F942, 0x0800F7B6, 0xF49C0382,
+	0xFA58FC00, 0xFC9C0926, 0xF800098E, 0x0710F8E4,
+	0x05A8FA58, 0xF8F0071C, 0xF800098E, 0x0364F6DA,
+	0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE,
+	0x05A80000, 0xFF1006BE, 0x0800084A, 0xF49CFC7E,
+	0xFA580400, 0xFC9CF6DA, 0xF800F672, 0x0710071C,
+	0x05A805A8, 0xF8F0F8E4, 0xF800F672, 0x03640926,
+	0xFA580400, 0x0B640382, 0x0800084A, 0x00F0F942,
+	0x05A80000, 0xFF10F942, 0x0800F7B6, 0xF49C0382,
+	0xFA58FC00, 0xFC9C0926, 0xF800098E, 0x0710F8E4,
+	0x05A8FA58, 0xF8F0071C, 0xF800098E, 0x0364F6DA,
+	0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE,
+};
+
+const u32 b43_ntab_tmap[] = {
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0xF1111110, 0x11111111, 0x11F11111, 0x00000111,
+	0x11000000, 0x1111F111, 0x11111111, 0x111111F1,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x000AA888,
+	0x88880000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+	0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+	0xA2222220, 0x22222222, 0x22C22222, 0x00000222,
+	0x22000000, 0x2222A222, 0x22222222, 0x222222A2,
+	0xF1111110, 0x11111111, 0x11F11111, 0x00011111,
+	0x11110000, 0x1111F111, 0x11111111, 0x111111F1,
+	0xA8AA88A0, 0xA88888A8, 0xA8A8A88A, 0x00088AAA,
+	0xAAAA0000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A,
+	0xAAA8AAA0, 0x8AAA8AAA, 0xAA8A8A8A, 0x000AAA88,
+	0x8AAA0000, 0xAAA8A888, 0x8AA88A8A, 0x8A88A888,
+	0x08080A00, 0x0A08080A, 0x080A0A08, 0x00080808,
+	0x080A0000, 0x080A0808, 0x080A0808, 0x0A0A0A08,
+	0xA0A0A0A0, 0x80A0A080, 0x8080A0A0, 0x00008080,
+	0x80A00000, 0x80A080A0, 0xA080A0A0, 0x8080A0A0,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x99999000, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9,
+	0x9B99BB90, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00AAA888,
+	0x22000000, 0x2222B222, 0x22222222, 0x222222B2,
+	0xB2222220, 0x22222222, 0x22D22222, 0x00000222,
+	0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+	0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+	0x33000000, 0x3333B333, 0x33333333, 0x333333B3,
+	0xB3333330, 0x33333333, 0x33D33333, 0x00000333,
+	0x22000000, 0x2222A222, 0x22222222, 0x222222A2,
+	0xA2222220, 0x22222222, 0x22C22222, 0x00000222,
+	0x99B99B00, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9,
+	0x9B99BB99, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x08AAA888,
+	0x22222200, 0x2222F222, 0x22222222, 0x222222F2,
+	0x22222222, 0x22222222, 0x22F22222, 0x00000222,
+	0x11000000, 0x1111F111, 0x11111111, 0x11111111,
+	0xF1111111, 0x11111111, 0x11F11111, 0x01111111,
+	0xBB9BB900, 0xB9B9BB99, 0xB99BBBBB, 0xBBBB9B9B,
+	0xB9BB99BB, 0xB99999B9, 0xB9B9B99B, 0x00000BBB,
+	0xAA000000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A,
+	0xA8AA88AA, 0xA88888A8, 0xA8A8A88A, 0x0A888AAA,
+	0xAA000000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A,
+	0xA8AA88A0, 0xA88888A8, 0xA8A8A88A, 0x00000AAA,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0xBBBBBB00, 0x999BBBBB, 0x9BB99B9B, 0xB9B9B9BB,
+	0xB9B99BBB, 0xB9B9B9BB, 0xB9BB9B99, 0x00000999,
+	0x8A000000, 0xAA88A888, 0xA88888AA, 0xA88A8A88,
+	0xA88AA88A, 0x88A8AAAA, 0xA8AA8AAA, 0x0888A88A,
+	0x0B0B0B00, 0x090B0B0B, 0x0B090B0B, 0x0909090B,
+	0x09090B0B, 0x09090B0B, 0x09090B09, 0x00000909,
+	0x0A000000, 0x0A080808, 0x080A080A, 0x080A0A08,
+	0x080A080A, 0x0808080A, 0x0A0A0A08, 0x0808080A,
+	0xB0B0B000, 0x9090B0B0, 0x90B09090, 0xB0B0B090,
+	0xB0B090B0, 0x90B0B0B0, 0xB0B09090, 0x00000090,
+	0x80000000, 0xA080A080, 0xA08080A0, 0xA0808080,
+	0xA080A080, 0x80A0A0A0, 0xA0A080A0, 0x00A0A0A0,
+	0x22000000, 0x2222F222, 0x22222222, 0x222222F2,
+	0xF2222220, 0x22222222, 0x22F22222, 0x00000222,
+	0x11000000, 0x1111F111, 0x11111111, 0x111111F1,
+	0xF1111110, 0x11111111, 0x11F11111, 0x00000111,
+	0x33000000, 0x3333F333, 0x33333333, 0x333333F3,
+	0xF3333330, 0x33333333, 0x33F33333, 0x00000333,
+	0x22000000, 0x2222F222, 0x22222222, 0x222222F2,
+	0xF2222220, 0x22222222, 0x22F22222, 0x00000222,
+	0x99000000, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9,
+	0x9B99BB90, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x88888000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00AAA888,
+	0x88A88A00, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x08AAA888,
+	0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+	0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+	0x11000000, 0x1111A111, 0x11111111, 0x111111A1,
+	0xA1111110, 0x11111111, 0x11C11111, 0x00000111,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8,
+	0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static inline void assert_ntab_array_sizes(void)
+{
+#undef check
+#define check(table, size)	\
+	BUILD_BUG_ON(ARRAY_SIZE(b43_ntab_##table) != B43_NTAB_##size##_SIZE)
+
+	check(adjustpower0, C0_ADJPLT);
+	check(adjustpower1, C1_ADJPLT);
+	check(bdi, BDI);
+	check(channelest, CHANEST);
+	check(estimatepowerlt0, C0_ESTPLT);
+	check(estimatepowerlt1, C1_ESTPLT);
+	check(framelookup, FRAMELT);
+	check(framestruct, FRAMESTRUCT);
+	check(gainctl0, C0_GAINCTL);
+	check(gainctl1, C1_GAINCTL);
+	check(intlevel, INTLEVEL);
+	check(iqlt0, C0_IQLT);
+	check(iqlt1, C1_IQLT);
+	check(loftlt0, C0_LOFEEDTH);
+	check(loftlt1, C1_LOFEEDTH);
+	check(mcs, MCS);
+	check(noisevar10, NOISEVAR10);
+	check(noisevar11, NOISEVAR11);
+	check(pilot, PILOT);
+	check(pilotlt, PILOTLT);
+	check(tdi20a0, TDI20A0);
+	check(tdi20a1, TDI20A1);
+	check(tdi40a0, TDI40A0);
+	check(tdi40a1, TDI40A1);
+	check(tdtrn, TDTRN);
+	check(tmap, TMAP);
+
+#undef check
+}
+
+void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value)
+{
+	u32 type;
+
+	type = offset & B43_NTAB_TYPEMASK;
+	offset &= 0xFFFF;
+
+	switch (type) {
+	case B43_NTAB_8BIT:
+		B43_WARN_ON(value & ~0xFF);
+		b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+		b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value);
+		break;
+	case B43_NTAB_16BIT:
+		B43_WARN_ON(value & ~0xFFFF);
+		b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+		b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value);
+		break;
+	case B43_NTAB_32BIT:
+		b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset);
+		b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, value >> 16);
+		b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value & 0xFFFF);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+
+	return;
+
+	/* Some compiletime assertions... */
+	assert_ntab_array_sizes();
+}
diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h
new file mode 100644
index 000000000000..4d498b053ec7
--- /dev/null
+++ b/drivers/net/wireless/b43/tables_nphy.h
@@ -0,0 +1,159 @@
+#ifndef B43_TABLES_NPHY_H_
+#define B43_TABLES_NPHY_H_
+
+#include <linux/types.h>
+
+
+struct b43_nphy_channeltab_entry {
+	/* The channel number */
+	u8 channel;
+	/* Radio register values on channelswitch */
+	u8 radio_pll_ref;
+	u8 radio_rf_pllmod0;
+	u8 radio_rf_pllmod1;
+	u8 radio_vco_captail;
+	u8 radio_vco_cal1;
+	u8 radio_vco_cal2;
+	u8 radio_pll_lfc1;
+	u8 radio_pll_lfr1;
+	u8 radio_pll_lfc2;
+	u8 radio_lgbuf_cenbuf;
+	u8 radio_lgen_tune1;
+	u8 radio_lgen_tune2;
+	u8 radio_c1_lgbuf_atune;
+	u8 radio_c1_lgbuf_gtune;
+	u8 radio_c1_rx_rfr1;
+	u8 radio_c1_tx_pgapadtn;
+	u8 radio_c1_tx_mxbgtrim;
+	u8 radio_c2_lgbuf_atune;
+	u8 radio_c2_lgbuf_gtune;
+	u8 radio_c2_rx_rfr1;
+	u8 radio_c2_tx_pgapadtn;
+	u8 radio_c2_tx_mxbgtrim;
+	/* PHY register values on channelswitch */
+	u16 phy_bw1a;
+	u16 phy_bw2;
+	u16 phy_bw3;
+	u16 phy_bw4;
+	u16 phy_bw5;
+	u16 phy_bw6;
+	/* The channel frequency in MHz */
+	u16 freq;
+	/* An unknown value */
+	u16 unk2;
+};
+
+
+struct b43_wldev;
+
+/* Upload the default register value table.
+ * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz
+ * table is uploaded. If "ignore_uploadflag" is true, we upload any value
+ * and ignore the "UPLOAD" flag. */
+void b2055_upload_inittab(struct b43_wldev *dev,
+			  bool ghz5, bool ignore_uploadflag);
+
+
+/* Get the NPHY Channel Switch Table entry for a channel number.
+ * Returns NULL on failure to find an entry. */
+const struct b43_nphy_channeltab_entry *
+b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel);
+
+
+/* The N-PHY tables. */
+
+#define B43_NTAB_TYPEMASK		0xF0000000
+#define B43_NTAB_8BIT			0x10000000
+#define B43_NTAB_16BIT			0x20000000
+#define B43_NTAB_32BIT			0x30000000
+#define B43_NTAB8(table, offset)	(((table) << 10) | (offset) | B43_NTAB_8BIT)
+#define B43_NTAB16(table, offset)	(((table) << 10) | (offset) | B43_NTAB_16BIT)
+#define B43_NTAB32(table, offset)	(((table) << 10) | (offset) | B43_NTAB_32BIT)
+
+/* Static N-PHY tables */
+#define B43_NTAB_FRAMESTRUCT		B43_NTAB32(0x0A, 0x000) /* Frame Struct Table */
+#define B43_NTAB_FRAMESTRUCT_SIZE	832
+#define B43_NTAB_FRAMELT		B43_NTAB8 (0x18, 0x000) /* Frame Lookup Table */
+#define B43_NTAB_FRAMELT_SIZE		32
+#define B43_NTAB_TMAP			B43_NTAB32(0x0C, 0x000) /* T Map Table */
+#define B43_NTAB_TMAP_SIZE		448
+#define B43_NTAB_TDTRN			B43_NTAB32(0x0E, 0x000) /* TDTRN Table */
+#define B43_NTAB_TDTRN_SIZE		704
+#define B43_NTAB_INTLEVEL		B43_NTAB32(0x0D, 0x000) /* Int Level Table */
+#define B43_NTAB_INTLEVEL_SIZE		7
+#define B43_NTAB_PILOT			B43_NTAB16(0x0B, 0x000) /* Pilot Table */
+#define B43_NTAB_PILOT_SIZE		88
+#define B43_NTAB_PILOTLT		B43_NTAB32(0x14, 0x000) /* Pilot Lookup Table */
+#define B43_NTAB_PILOTLT_SIZE		6
+#define B43_NTAB_TDI20A0		B43_NTAB32(0x13, 0x080) /* TDI Table 20 Antenna 0 */
+#define B43_NTAB_TDI20A0_SIZE		55
+#define B43_NTAB_TDI20A1		B43_NTAB32(0x13, 0x100) /* TDI Table 20 Antenna 1 */
+#define B43_NTAB_TDI20A1_SIZE		55
+#define B43_NTAB_TDI40A0		B43_NTAB32(0x13, 0x280) /* TDI Table 40 Antenna 0 */
+#define B43_NTAB_TDI40A0_SIZE		110
+#define B43_NTAB_TDI40A1		B43_NTAB32(0x13, 0x300) /* TDI Table 40 Antenna 1 */
+#define B43_NTAB_TDI40A1_SIZE		110
+#define B43_NTAB_BDI			B43_NTAB16(0x15, 0x000) /* BDI Table */
+#define B43_NTAB_BDI_SIZE		6
+#define B43_NTAB_CHANEST		B43_NTAB32(0x16, 0x000) /* Channel Estimate Table */
+#define B43_NTAB_CHANEST_SIZE		96
+#define B43_NTAB_MCS			B43_NTAB8 (0x12, 0x000) /* MCS Table */
+#define B43_NTAB_MCS_SIZE		128
+
+/* Volatile N-PHY tables */
+#define B43_NTAB_NOISEVAR10		B43_NTAB32(0x10, 0x000) /* Noise Var Table 10 */
+#define B43_NTAB_NOISEVAR10_SIZE	256
+#define B43_NTAB_NOISEVAR11		B43_NTAB32(0x10, 0x080) /* Noise Var Table 11 */
+#define B43_NTAB_NOISEVAR11_SIZE	256
+#define B43_NTAB_C0_ESTPLT		B43_NTAB8 (0x1A, 0x000) /* Estimate Power Lookup Table Core 0 */
+#define B43_NTAB_C0_ESTPLT_SIZE		64
+#define B43_NTAB_C1_ESTPLT		B43_NTAB8 (0x1B, 0x000) /* Estimate Power Lookup Table Core 1 */
+#define B43_NTAB_C1_ESTPLT_SIZE		64
+#define B43_NTAB_C0_ADJPLT		B43_NTAB8 (0x1A, 0x040) /* Adjust Power Lookup Table Core 0 */
+#define B43_NTAB_C0_ADJPLT_SIZE		128
+#define B43_NTAB_C1_ADJPLT		B43_NTAB8 (0x1B, 0x040) /* Adjust Power Lookup Table Core 1 */
+#define B43_NTAB_C1_ADJPLT_SIZE		128
+#define B43_NTAB_C0_GAINCTL		B43_NTAB32(0x1A, 0x0C0) /* Gain Control Lookup Table Core 0 */
+#define B43_NTAB_C0_GAINCTL_SIZE	128
+#define B43_NTAB_C1_GAINCTL		B43_NTAB32(0x1B, 0x0C0) /* Gain Control Lookup Table Core 1 */
+#define B43_NTAB_C1_GAINCTL_SIZE	128
+#define B43_NTAB_C0_IQLT		B43_NTAB32(0x1A, 0x140) /* IQ Lookup Table Core 0 */
+#define B43_NTAB_C0_IQLT_SIZE		128
+#define B43_NTAB_C1_IQLT		B43_NTAB32(0x1B, 0x140) /* IQ Lookup Table Core 1 */
+#define B43_NTAB_C1_IQLT_SIZE		128
+#define B43_NTAB_C0_LOFEEDTH		B43_NTAB16(0x1A, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 0 */
+#define B43_NTAB_C0_LOFEEDTH_SIZE	128
+#define B43_NTAB_C1_LOFEEDTH		B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */
+#define B43_NTAB_C1_LOFEEDTH_SIZE	128
+
+void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value);
+
+extern const u8 b43_ntab_adjustpower0[];
+extern const u8 b43_ntab_adjustpower1[];
+extern const u16 b43_ntab_bdi[];
+extern const u32 b43_ntab_channelest[];
+extern const u8 b43_ntab_estimatepowerlt0[];
+extern const u8 b43_ntab_estimatepowerlt1[];
+extern const u8 b43_ntab_framelookup[];
+extern const u32 b43_ntab_framestruct[];
+extern const u32 b43_ntab_gainctl0[];
+extern const u32 b43_ntab_gainctl1[];
+extern const u32 b43_ntab_intlevel[];
+extern const u32 b43_ntab_iqlt0[];
+extern const u32 b43_ntab_iqlt1[];
+extern const u16 b43_ntab_loftlt0[];
+extern const u16 b43_ntab_loftlt1[];
+extern const u8 b43_ntab_mcs[];
+extern const u32 b43_ntab_noisevar10[];
+extern const u32 b43_ntab_noisevar11[];
+extern const u16 b43_ntab_pilot[];
+extern const u32 b43_ntab_pilotlt[];
+extern const u32 b43_ntab_tdi20a0[];
+extern const u32 b43_ntab_tdi20a1[];
+extern const u32 b43_ntab_tdi40a0[];
+extern const u32 b43_ntab_tdi40a1[];
+extern const u32 b43_ntab_tdtrn[];
+extern const u32 b43_ntab_tmap[];
+
+
+#endif /* B43_TABLES_NPHY_H_ */
diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c
new file mode 100644
index 000000000000..e632125cb772
--- /dev/null
+++ b/drivers/net/wireless/b43/wa.c
@@ -0,0 +1,674 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  PHY workarounds.
+
+  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
+  Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "main.h"
+#include "tables.h"
+#include "phy.h"
+#include "wa.h"
+
+static void b43_wa_papd(struct b43_wldev *dev)
+{
+	u16 backup;
+
+	backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0);
+	b43_dummy_transmission(dev);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup);
+}
+
+static void b43_wa_auxclipthr(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x3800);
+}
+
+static void b43_wa_afcdac(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, 0x0035, 0x03FF);
+	b43_phy_write(dev, 0x0036, 0x0400);
+}
+
+static void b43_wa_txdc_offset(struct b43_wldev *dev)
+{
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 0, 0x0051);
+}
+
+void b43_wa_initgains(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	b43_phy_write(dev, B43_PHY_LNAHPFCTL, 0x1FF9);
+	b43_phy_write(dev, B43_PHY_LPFGAINCTL,
+		b43_phy_read(dev, B43_PHY_LPFGAINCTL) & 0xFF0F);
+	if (phy->rev <= 2)
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, 0, 0x1FBF);
+	b43_radio_write16(dev, 0x0002, 0x1FBF);
+
+	b43_phy_write(dev, 0x0024, 0x4680);
+	b43_phy_write(dev, 0x0020, 0x0003);
+	b43_phy_write(dev, 0x001D, 0x0F40);
+	b43_phy_write(dev, 0x001F, 0x1C00);
+	if (phy->rev <= 3)
+		b43_phy_write(dev, 0x002A,
+			(b43_phy_read(dev, 0x002A) & 0x00FF) | 0x0400);
+	else if (phy->rev == 5) {
+		b43_phy_write(dev, 0x002A,
+			(b43_phy_read(dev, 0x002A) & 0x00FF) | 0x1A00);
+		b43_phy_write(dev, 0x00CC, 0x2121);
+	}
+	if (phy->rev >= 3)
+		b43_phy_write(dev, 0x00BA, 0x3ED5);
+}
+
+static void b43_wa_divider(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) & ~0x0100);
+	b43_phy_write(dev, 0x008E, 0x58C1);
+}
+
+static void b43_wa_gt(struct b43_wldev *dev) /* Gain table. */
+{
+	if (dev->phy.rev <= 2) {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 0, 15);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 1, 31);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 2, 42);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 3, 48);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 4, 58);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 0, 3);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 1, 3);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 2, 7);
+	} else {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25);
+	}
+}
+
+static void b43_wa_rssi_lt(struct b43_wldev *dev) /* RSSI lookup table */
+{
+	int i;
+
+	if (0 /* FIXME: For APHY.rev=2 this might be needed */) {
+		for (i = 0; i < 8; i++)
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i + 8);
+		for (i = 8; i < 16; i++)
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i - 8);
+	} else {
+		for (i = 0; i < 64; i++)
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i);
+	}
+}
+
+static void b43_wa_analog(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 ofdmrev;
+
+	ofdmrev = b43_phy_read(dev, B43_PHY_VERSION_OFDM) & B43_PHYVER_VERSION;
+	if (ofdmrev > 2) {
+		if (phy->type == B43_PHYTYPE_A)
+			b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1808);
+		else
+			b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1000);
+	} else {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 3, 0x1044);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 4, 0x7201);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 6, 0x0040);
+	}
+}
+
+static void b43_wa_dac(struct b43_wldev *dev)
+{
+	if (dev->phy.analog == 1)
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1,
+			(b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0034) | 0x0008);
+	else
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1,
+			(b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0078) | 0x0010);
+}
+
+static void b43_wa_fft(struct b43_wldev *dev) /* Fine frequency table */
+{
+	int i;
+
+	if (dev->phy.type == B43_PHYTYPE_A)
+		for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++)
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqa[i]);
+	else
+		for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++)
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqg[i]);
+}
+
+static void b43_wa_nft(struct b43_wldev *dev) /* Noise figure table */
+{
+	struct b43_phy *phy = &dev->phy;
+	int i;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		if (phy->rev == 2)
+			for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea2[i]);
+		else
+			for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea3[i]);
+	} else {
+		if (phy->rev == 1)
+			for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg1[i]);
+		else
+			for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg2[i]);
+	}
+}
+
+static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */
+{
+	int i;
+
+	for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
+		b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]);
+}
+
+static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */
+{
+	struct b43_phy *phy = &dev->phy;
+	int i;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		if (phy->rev <= 1)
+			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+							i, 0);
+		else if (phy->rev == 2)
+			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+							i, b43_tab_noisescalea2[i]);
+		else if (phy->rev == 3)
+			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+							i, b43_tab_noisescalea3[i]);
+		else
+			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+							i, b43_tab_noisescaleg3[i]);
+	} else {
+		if (phy->rev >= 6) {
+			if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
+				for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+					b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+						i, b43_tab_noisescaleg3[i]);
+			else
+				for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+					b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+						i, b43_tab_noisescaleg2[i]);
+		} else {
+			for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++)
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE,
+							i, b43_tab_noisescaleg1[i]);
+		}
+	}
+}
+
+static void b43_wa_art(struct b43_wldev *dev) /* ADV retard table */
+{
+	int i;
+
+	for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
+			b43_ofdmtab_write32(dev, B43_OFDMTAB_ADVRETARD,
+				i, b43_tab_retard[i]);
+}
+
+static void b43_wa_txlna_gain(struct b43_wldev *dev)
+{
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 13, 0x0000);
+}
+
+static void b43_wa_crs_reset(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, 0x002C, 0x0064);
+}
+
+static void b43_wa_2060txlna_gain(struct b43_wldev *dev)
+{
+	b43_hf_write(dev, b43_hf_read(dev) |
+			 B43_HF_2060W);
+}
+
+static void b43_wa_lms(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, 0x0055,
+		(b43_phy_read(dev, 0x0055) & 0xFFC0) | 0x0004);
+}
+
+static void b43_wa_mixedsignal(struct b43_wldev *dev)
+{
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, 3);
+}
+
+static void b43_wa_msst(struct b43_wldev *dev) /* Min sigma square table */
+{
+	struct b43_phy *phy = &dev->phy;
+	int i;
+	const u16 *tab;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		tab = b43_tab_sigmasqr1;
+	} else if (phy->type == B43_PHYTYPE_G) {
+		tab = b43_tab_sigmasqr2;
+	} else {
+		B43_WARN_ON(1);
+		return;
+	}
+
+	for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_MINSIGSQ,
+					i, tab[i]);
+	}
+}
+
+static void b43_wa_iqadc(struct b43_wldev *dev)
+{
+	if (dev->phy.analog == 4)
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 0,
+			b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 0) & ~0xF000);
+}
+
+static void b43_wa_crs_ed(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->rev == 1) {
+		b43_phy_write(dev, B43_PHY_CRSTHRES1_R1, 0x4F19);
+	} else if (phy->rev == 2) {
+		b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x1861);
+		b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0271);
+		b43_phy_write(dev, B43_PHY_ANTDWELL,
+				  b43_phy_read(dev, B43_PHY_ANTDWELL)
+				  | 0x0800);
+	} else {
+		b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x0098);
+		b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0070);
+		b43_phy_write(dev, B43_PHY_OFDM(0xC9), 0x0080);
+		b43_phy_write(dev, B43_PHY_ANTDWELL,
+				  b43_phy_read(dev, B43_PHY_ANTDWELL)
+				  | 0x0800);
+	}
+}
+
+static void b43_wa_crs_thr(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, B43_PHY_CRS0,
+			(b43_phy_read(dev, B43_PHY_CRS0) & ~0x03C0) | 0xD000);
+}
+
+static void b43_wa_crs_blank(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, B43_PHY_OFDM(0x2C), 0x005A);
+}
+
+static void b43_wa_cck_shiftbits(struct b43_wldev *dev)
+{
+	b43_phy_write(dev, B43_PHY_CCKSHIFTBITS, 0x0026);
+}
+
+static void b43_wa_wrssi_offset(struct b43_wldev *dev)
+{
+	int i;
+
+	if (dev->phy.rev == 1) {
+		for (i = 0; i < 16; i++) {
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI_R1,
+						i, 0x0020);
+		}
+	} else {
+		for (i = 0; i < 32; i++) {
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI,
+						i, 0x0820);
+		}
+	}
+}
+
+static void b43_wa_txpuoff_rxpuon(struct b43_wldev *dev)
+{
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 2, 15);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 3, 20);
+}
+
+static void b43_wa_altagc(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->rev == 1) {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 254);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 1, 13);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 2, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 3, 25);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 0, 0x2710);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 1, 0x9B83);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 2, 0x9B83);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 3, 0x0F8D);
+		b43_phy_write(dev, B43_PHY_LMS, 4);
+	} else {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0, 254);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 1, 13);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 2, 19);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25);
+	}
+
+	b43_phy_write(dev, B43_PHY_CCKSHIFTBITS_WA,
+		(b43_phy_read(dev, B43_PHY_CCKSHIFTBITS_WA) & ~0xFF00) | 0x5700);
+	b43_phy_write(dev, B43_PHY_OFDM(0x1A),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x007F) | 0x000F);
+	b43_phy_write(dev, B43_PHY_OFDM(0x1A),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x3F80) | 0x2B80);
+	b43_phy_write(dev, B43_PHY_ANTWRSETT,
+		(b43_phy_read(dev, B43_PHY_ANTWRSETT) & 0xF0FF) | 0x0300);
+	b43_radio_write16(dev, 0x7A,
+		b43_radio_read16(dev, 0x7A) | 0x0008);
+	b43_phy_write(dev, B43_PHY_N1P1GAIN,
+		(b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x000F) | 0x0008);
+	b43_phy_write(dev, B43_PHY_P1P2GAIN,
+		(b43_phy_read(dev, B43_PHY_P1P2GAIN) & ~0x0F00) | 0x0600);
+	b43_phy_write(dev, B43_PHY_N1N2GAIN,
+		(b43_phy_read(dev, B43_PHY_N1N2GAIN) & ~0x0F00) | 0x0700);
+	b43_phy_write(dev, B43_PHY_N1P1GAIN,
+		(b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x0F00) | 0x0100);
+	if (phy->rev == 1) {
+		b43_phy_write(dev, B43_PHY_N1N2GAIN,
+				  (b43_phy_read(dev, B43_PHY_N1N2GAIN)
+				   & ~0x000F) | 0x0007);
+	}
+	b43_phy_write(dev, B43_PHY_OFDM(0x88),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x00FF) | 0x001C);
+	b43_phy_write(dev, B43_PHY_OFDM(0x88),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x3F00) | 0x0200);
+	b43_phy_write(dev, B43_PHY_OFDM(0x96),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0x00FF) | 0x001C);
+	b43_phy_write(dev, B43_PHY_OFDM(0x89),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x00FF) | 0x0020);
+	b43_phy_write(dev, B43_PHY_OFDM(0x89),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x3F00) | 0x0200);
+	b43_phy_write(dev, B43_PHY_OFDM(0x82),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x82)) & ~0x00FF) | 0x002E);
+	b43_phy_write(dev, B43_PHY_OFDM(0x96),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0xFF00) | 0x1A00);
+	b43_phy_write(dev, B43_PHY_OFDM(0x81),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0x00FF) | 0x0028);
+	b43_phy_write(dev, B43_PHY_OFDM(0x81),
+		(b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0xFF00) | 0x2C00);
+	if (phy->rev == 1) {
+		b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B);
+		b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+			(b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E) | 0x0002);
+	} else {
+		b43_phy_write(dev, B43_PHY_OFDM(0x1B),
+			b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E);
+		b43_phy_write(dev, B43_PHY_OFDM(0x1F), 0x287A);
+		b43_phy_write(dev, B43_PHY_LPFGAINCTL,
+			(b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0x000F) | 0x0004);
+		if (phy->rev >= 6) {
+			b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A);
+			b43_phy_write(dev, B43_PHY_LPFGAINCTL,
+				(b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0xF000) | 0x3000);
+		}
+	}
+	b43_phy_write(dev, B43_PHY_DIVSRCHIDX,
+		(b43_phy_read(dev, B43_PHY_DIVSRCHIDX) & 0x8080) | 0x7874);
+	b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x1C00);
+	if (phy->rev == 1) {
+		b43_phy_write(dev, B43_PHY_DIVP1P2GAIN,
+			(b43_phy_read(dev, B43_PHY_DIVP1P2GAIN) & ~0x0F00) | 0x0600);
+		b43_phy_write(dev, B43_PHY_OFDM(0x8B), 0x005E);
+		b43_phy_write(dev, B43_PHY_ANTWRSETT,
+			(b43_phy_read(dev, B43_PHY_ANTWRSETT) & ~0x00FF) | 0x001E);
+		b43_phy_write(dev, B43_PHY_OFDM(0x8D), 0x0002);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 0, 0);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 1, 7);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 2, 16);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 3, 28);
+	} else {
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 0, 0);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 1, 7);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 2, 16);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 3, 28);
+	}
+	if (phy->rev >= 6) {
+		b43_phy_write(dev, B43_PHY_OFDM(0x26),
+			b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x0003);
+		b43_phy_write(dev, B43_PHY_OFDM(0x26),
+			b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x1000);
+	}
+	b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */
+}
+
+static void b43_wa_tr_ltov(struct b43_wldev *dev) /* TR Lookup Table Original Values */
+{
+	b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0xC480);
+}
+
+static void b43_wa_cpll_nonpilot(struct b43_wldev *dev)
+{
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 0, 0);
+	b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 1, 0);
+}
+
+static void b43_wa_rssi_adc(struct b43_wldev *dev)
+{
+	if (dev->phy.analog == 4)
+		b43_phy_write(dev, 0x00DC, 0x7454);
+}
+
+static void b43_wa_boards_a(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+
+	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+	    bus->boardinfo.type == SSB_BOARD_BU4306 &&
+	    bus->boardinfo.rev < 0x30) {
+		b43_phy_write(dev, 0x0010, 0xE000);
+		b43_phy_write(dev, 0x0013, 0x0140);
+		b43_phy_write(dev, 0x0014, 0x0280);
+	} else {
+		if (bus->boardinfo.type == SSB_BOARD_MP4318 &&
+		    bus->boardinfo.rev < 0x20) {
+			b43_phy_write(dev, 0x0013, 0x0210);
+			b43_phy_write(dev, 0x0014, 0x0840);
+		} else {
+			b43_phy_write(dev, 0x0013, 0x0140);
+			b43_phy_write(dev, 0x0014, 0x0280);
+		}
+		if (dev->phy.rev <= 4)
+			b43_phy_write(dev, 0x0010, 0xE000);
+		else
+			b43_phy_write(dev, 0x0010, 0x2000);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 1, 0x0039);
+		b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 7, 0x0040);
+	}
+}
+
+static void b43_wa_boards_g(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+
+	if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM ||
+	    bus->boardinfo.type != SSB_BOARD_BU4306 ||
+	    bus->boardinfo.rev != 0x17) {
+		if (phy->rev < 2) {
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 1, 0x0002);
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 2, 0x0001);
+		} else {
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 1, 0x0002);
+			b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001);
+			if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
+			    (phy->rev >= 7)) {
+				b43_phy_write(dev, B43_PHY_EXTG(0x11),
+					b43_phy_read(dev, B43_PHY_EXTG(0x11)) & 0xF7FF);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0021, 0x0001);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0022, 0x0001);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0023, 0x0000);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0000, 0x0000);
+				b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0003, 0x0002);
+			}
+		}
+	}
+	if (bus->sprom.boardflags_lo & B43_BFL_FEM) {
+		b43_phy_write(dev, B43_PHY_GTABCTL, 0x3120);
+		b43_phy_write(dev, B43_PHY_GTABDATA, 0xC480);
+	}
+}
+
+void b43_wa_all(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		switch (phy->rev) {
+		case 2:
+			b43_wa_papd(dev);
+			b43_wa_auxclipthr(dev);
+			b43_wa_afcdac(dev);
+			b43_wa_txdc_offset(dev);
+			b43_wa_initgains(dev);
+			b43_wa_divider(dev);
+			b43_wa_gt(dev);
+			b43_wa_rssi_lt(dev);
+			b43_wa_analog(dev);
+			b43_wa_dac(dev);
+			b43_wa_fft(dev);
+			b43_wa_nft(dev);
+			b43_wa_rt(dev);
+			b43_wa_nst(dev);
+			b43_wa_art(dev);
+			b43_wa_txlna_gain(dev);
+			b43_wa_crs_reset(dev);
+			b43_wa_2060txlna_gain(dev);
+			b43_wa_lms(dev);
+			break;
+		case 3:
+			b43_wa_papd(dev);
+			b43_wa_mixedsignal(dev);
+			b43_wa_rssi_lt(dev);
+			b43_wa_txdc_offset(dev);
+			b43_wa_initgains(dev);
+			b43_wa_dac(dev);
+			b43_wa_nft(dev);
+			b43_wa_nst(dev);
+			b43_wa_msst(dev);
+			b43_wa_analog(dev);
+			b43_wa_gt(dev);
+			b43_wa_txpuoff_rxpuon(dev);
+			b43_wa_txlna_gain(dev);
+			break;
+		case 5:
+			b43_wa_iqadc(dev);
+		case 6:
+			b43_wa_papd(dev);
+			b43_wa_rssi_lt(dev);
+			b43_wa_txdc_offset(dev);
+			b43_wa_initgains(dev);
+			b43_wa_dac(dev);
+			b43_wa_nft(dev);
+			b43_wa_nst(dev);
+			b43_wa_msst(dev);
+			b43_wa_analog(dev);
+			b43_wa_gt(dev);
+			b43_wa_txpuoff_rxpuon(dev);
+			b43_wa_txlna_gain(dev);
+			break;
+		case 7:
+			b43_wa_iqadc(dev);
+			b43_wa_papd(dev);
+			b43_wa_rssi_lt(dev);
+			b43_wa_txdc_offset(dev);
+			b43_wa_initgains(dev);
+			b43_wa_dac(dev);
+			b43_wa_nft(dev);
+			b43_wa_nst(dev);
+			b43_wa_msst(dev);
+			b43_wa_analog(dev);
+			b43_wa_gt(dev);
+			b43_wa_txpuoff_rxpuon(dev);
+			b43_wa_txlna_gain(dev);
+			b43_wa_rssi_adc(dev);
+		default:
+			B43_WARN_ON(1);
+		}
+		b43_wa_boards_a(dev);
+	} else if (phy->type == B43_PHYTYPE_G) {
+		switch (phy->rev) {
+		case 1://XXX review rev1
+			b43_wa_crs_ed(dev);
+			b43_wa_crs_thr(dev);
+			b43_wa_crs_blank(dev);
+			b43_wa_cck_shiftbits(dev);
+			b43_wa_fft(dev);
+			b43_wa_nft(dev);
+			b43_wa_rt(dev);
+			b43_wa_nst(dev);
+			b43_wa_art(dev);
+			b43_wa_wrssi_offset(dev);
+			b43_wa_altagc(dev);
+			break;
+		case 2:
+		case 6:
+		case 7:
+		case 8:
+		case 9:
+			b43_wa_tr_ltov(dev);
+			b43_wa_crs_ed(dev);
+			b43_wa_rssi_lt(dev);
+			b43_wa_nft(dev);
+			b43_wa_nst(dev);
+			b43_wa_msst(dev);
+			b43_wa_wrssi_offset(dev);
+			b43_wa_altagc(dev);
+			b43_wa_analog(dev);
+			b43_wa_txpuoff_rxpuon(dev);
+			break;
+		default:
+			B43_WARN_ON(1);
+		}
+		b43_wa_boards_g(dev);
+	} else { /* No N PHY support so far */
+		B43_WARN_ON(1);
+	}
+
+	b43_wa_cpll_nonpilot(dev);
+}
diff --git a/drivers/net/wireless/b43/wa.h b/drivers/net/wireless/b43/wa.h
new file mode 100644
index 000000000000..e163c5e56e81
--- /dev/null
+++ b/drivers/net/wireless/b43/wa.h
@@ -0,0 +1,7 @@
+#ifndef B43_WA_H_
+#define B43_WA_H_
+
+void b43_wa_initgains(struct b43_wldev *dev);
+void b43_wa_all(struct b43_wldev *dev);
+
+#endif /* B43_WA_H_ */
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 3307ba1856b1..3fc53e8b4416 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -5,7 +5,7 @@
   Transmission (TX/RX) related functions.
 
   Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
-  Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -30,7 +30,7 @@
 #include "xmit.h"
 #include "phy.h"
 #include "dma.h"
-#include "pio.h"
+
 
 /* Extract the bitrate out of a CCK PLCP header. */
 static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
@@ -177,13 +177,15 @@ static u8 b43_calc_fallback_rate(u8 bitrate)
 	return 0;
 }
 
-static void generate_txhdr_fw4(struct b43_wldev *dev,
-			       struct b43_txhdr_fw4 *txhdr,
-			       const unsigned char *fragment_data,
-			       unsigned int fragment_len,
-			       const struct ieee80211_tx_control *txctl,
-			       u16 cookie)
+/* Generate a TX data header. */
+void b43_generate_txhdr(struct b43_wldev *dev,
+			u8 *_txhdr,
+			const unsigned char *fragment_data,
+			unsigned int fragment_len,
+			const struct ieee80211_tx_control *txctl,
+			u16 cookie)
 {
+	struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
 	const struct b43_phy *phy = &dev->phy;
 	const struct ieee80211_hdr *wlhdr =
 	    (const struct ieee80211_hdr *)fragment_data;
@@ -221,7 +223,7 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 	} else {
 		int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
 		txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
-								 dev->wl->if_id,
+								 txctl->vif,
 								 fragment_len,
 								 fbrate_base100kbps);
 	}
@@ -241,23 +243,30 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 		plcp_fragment_len += txctl->icv_len;
 
 		key_idx = b43_kidx_to_fw(dev, key_idx);
-		mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) &
-			   B43_TX4_MAC_KEYIDX;
-		mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) &
-			   B43_TX4_MAC_KEYALG;
+		mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) &
+			   B43_TXH_MAC_KEYIDX;
+		mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) &
+			   B43_TXH_MAC_KEYALG;
 		wlhdr_len = ieee80211_get_hdrlen(fctl);
 		iv_len = min((size_t) txctl->iv_len,
 			     ARRAY_SIZE(txhdr->iv));
 		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
 	}
-	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp),
-			      plcp_fragment_len, rate);
+	if (b43_is_old_txhdr_format(dev)) {
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp),
+				      plcp_fragment_len, rate);
+	} else {
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp),
+				      plcp_fragment_len, rate);
+	}
 	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
 			      plcp_fragment_len, rate_fb);
 
 	/* Extra Frame Types */
 	if (rate_fb_ofdm)
-		extra_ft |= B43_TX4_EFT_FBOFDM;
+		extra_ft |= B43_TXH_EFT_FB_OFDM;
+	else
+		extra_ft |= B43_TXH_EFT_FB_CCK;
 
 	/* Set channel radio code. Note that the micrcode ORs 0x100 to
 	 * this value before comparing it to the value in SHM, if this
@@ -267,18 +276,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 
 	/* PHY TX Control word */
 	if (rate_ofdm)
-		phy_ctl |= B43_TX4_PHY_OFDM;
+		phy_ctl |= B43_TXH_PHY_ENC_OFDM;
+	else
+		phy_ctl |= B43_TXH_PHY_ENC_CCK;
 	if (dev->short_preamble)
-		phy_ctl |= B43_TX4_PHY_SHORTPRMBL;
-	switch (txctl->antenna_sel_tx) {
-	case 0:
-		phy_ctl |= B43_TX4_PHY_ANTLAST;
+		phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
+
+	switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) {
+	case 0: /* Default */
+		phy_ctl |= B43_TXH_PHY_ANT01AUTO;
+		break;
+	case 1: /* Antenna 0 */
+		phy_ctl |= B43_TXH_PHY_ANT0;
 		break;
-	case 1:
-		phy_ctl |= B43_TX4_PHY_ANT0;
+	case 2: /* Antenna 1 */
+		phy_ctl |= B43_TXH_PHY_ANT1;
 		break;
-	case 2:
-		phy_ctl |= B43_TX4_PHY_ANT1;
+	case 3: /* Antenna 2 */
+		phy_ctl |= B43_TXH_PHY_ANT2;
+		break;
+	case 4: /* Antenna 3 */
+		phy_ctl |= B43_TXH_PHY_ANT3;
 		break;
 	default:
 		B43_WARN_ON(1);
@@ -286,14 +304,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 
 	/* MAC control */
 	if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
-		mac_ctl |= B43_TX4_MAC_ACK;
+		mac_ctl |= B43_TXH_MAC_ACK;
 	if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
 	      ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
-		mac_ctl |= B43_TX4_MAC_HWSEQ;
+		mac_ctl |= B43_TXH_MAC_HWSEQ;
 	if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
-		mac_ctl |= B43_TX4_MAC_STMSDU;
+		mac_ctl |= B43_TXH_MAC_STMSDU;
 	if (phy->type == B43_PHYTYPE_A)
-		mac_ctl |= B43_TX4_MAC_5GHZ;
+		mac_ctl |= B43_TXH_MAC_5GHZ;
+	if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
+		mac_ctl |= B43_TXH_MAC_LONGFRAME;
 
 	/* Generate the RTS or CTS-to-self frame */
 	if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
@@ -302,6 +322,7 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 		struct ieee80211_hdr *hdr;
 		int rts_rate, rts_rate_fb;
 		int rts_rate_ofdm, rts_rate_fb_ofdm;
+		struct b43_plcp_hdr6 *plcp;
 
 		rts_rate = txctl->rts_cts_rate;
 		rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
@@ -309,59 +330,84 @@ static void generate_txhdr_fw4(struct b43_wldev *dev,
 		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
 
 		if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
-			ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id,
+			struct ieee80211_cts *cts;
+
+			if (b43_is_old_txhdr_format(dev)) {
+				cts = (struct ieee80211_cts *)
+					(txhdr->old_format.rts_frame);
+			} else {
+				cts = (struct ieee80211_cts *)
+					(txhdr->new_format.rts_frame);
+			}
+			ieee80211_ctstoself_get(dev->wl->hw, txctl->vif,
 						fragment_data, fragment_len,
-						txctl,
-						(struct ieee80211_cts *)(txhdr->
-									 rts_frame));
-			mac_ctl |= B43_TX4_MAC_SENDCTS;
+						txctl, cts);
+			mac_ctl |= B43_TXH_MAC_SENDCTS;
 			len = sizeof(struct ieee80211_cts);
 		} else {
-			ieee80211_rts_get(dev->wl->hw, dev->wl->if_id,
-					  fragment_data, fragment_len, txctl,
-					  (struct ieee80211_rts *)(txhdr->
-								   rts_frame));
-			mac_ctl |= B43_TX4_MAC_SENDRTS;
+			struct ieee80211_rts *rts;
+
+			if (b43_is_old_txhdr_format(dev)) {
+				rts = (struct ieee80211_rts *)
+					(txhdr->old_format.rts_frame);
+			} else {
+				rts = (struct ieee80211_rts *)
+					(txhdr->new_format.rts_frame);
+			}
+			ieee80211_rts_get(dev->wl->hw, txctl->vif,
+					  fragment_data, fragment_len,
+					  txctl, rts);
+			mac_ctl |= B43_TXH_MAC_SENDRTS;
 			len = sizeof(struct ieee80211_rts);
 		}
 		len += FCS_LEN;
-		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
-							       rts_plcp), len,
-				      rts_rate);
-		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
-							       rts_plcp_fb),
+
+		/* Generate the PLCP headers for the RTS/CTS frame */
+		if (b43_is_old_txhdr_format(dev))
+			plcp = &txhdr->old_format.rts_plcp;
+		else
+			plcp = &txhdr->new_format.rts_plcp;
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
+				      len, rts_rate);
+		plcp = &txhdr->rts_plcp_fb;
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp,
 				      len, rts_rate_fb);
-		hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
+
+		if (b43_is_old_txhdr_format(dev)) {
+			hdr = (struct ieee80211_hdr *)
+				(&txhdr->old_format.rts_frame);
+		} else {
+			hdr = (struct ieee80211_hdr *)
+				(&txhdr->new_format.rts_frame);
+		}
 		txhdr->rts_dur_fb = hdr->duration_id;
+
 		if (rts_rate_ofdm) {
-			extra_ft |= B43_TX4_EFT_RTSOFDM;
+			extra_ft |= B43_TXH_EFT_RTS_OFDM;
 			txhdr->phy_rate_rts =
 			    b43_plcp_get_ratecode_ofdm(rts_rate);
-		} else
+		} else {
+			extra_ft |= B43_TXH_EFT_RTS_CCK;
 			txhdr->phy_rate_rts =
 			    b43_plcp_get_ratecode_cck(rts_rate);
+		}
 		if (rts_rate_fb_ofdm)
-			extra_ft |= B43_TX4_EFT_RTSFBOFDM;
-		mac_ctl |= B43_TX4_MAC_LONGFRAME;
+			extra_ft |= B43_TXH_EFT_RTSFB_OFDM;
+		else
+			extra_ft |= B43_TXH_EFT_RTSFB_CCK;
 	}
 
 	/* Magic cookie */
-	txhdr->cookie = cpu_to_le16(cookie);
+	if (b43_is_old_txhdr_format(dev))
+		txhdr->old_format.cookie = cpu_to_le16(cookie);
+	else
+		txhdr->new_format.cookie = cpu_to_le16(cookie);
 
 	/* Apply the bitfields */
 	txhdr->mac_ctl = cpu_to_le32(mac_ctl);
 	txhdr->phy_ctl = cpu_to_le16(phy_ctl);
 	txhdr->extra_ft = extra_ft;
-}
 
-void b43_generate_txhdr(struct b43_wldev *dev,
-			u8 * txhdr,
-			const unsigned char *fragment_data,
-			unsigned int fragment_len,
-			const struct ieee80211_tx_control *txctl, u16 cookie)
-{
-	generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
-			   fragment_data, fragment_len, txctl, cookie);
 }
 
 static s8 b43_rssi_postprocess(struct b43_wldev *dev,
@@ -384,7 +430,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
 			else
 				tmp -= 3;
 		} else {
-			if (dev->dev->bus->sprom.r1.
+			if (dev->dev->bus->sprom.
 			    boardflags_lo & B43_BFL_RSSI) {
 				if (in_rssi > 63)
 					in_rssi = 63;
@@ -488,7 +534,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 	}
 	wlhdr = (struct ieee80211_hdr *)(skb->data);
 	fctl = le16_to_cpu(wlhdr->frame_control);
-	skb_trim(skb, skb->len - FCS_LEN);
 
 	if (macstat & B43_RX_MAC_DEC) {
 		unsigned int keyidx;
@@ -525,7 +570,24 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 	else
 		status.rate = b43_plcp_get_bitrate_cck(plcp);
 	status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
-	status.mactime = mactime;
+
+	/*
+	 * If monitors are present get full 64-bit timestamp. This
+	 * code assumes we get to process the packet within 16 bits
+	 * of timestamp, i.e. about 65 milliseconds after the PHY
+	 * received the first symbol.
+	 */
+	if (dev->wl->radiotap_enabled) {
+		u16 low_mactime_now;
+
+		b43_tsf_read(dev, &status.mactime);
+		low_mactime_now = status.mactime;
+		status.mactime = status.mactime & ~0xFFFFULL;
+		status.mactime += mactime;
+		if (low_mactime_now <= mactime)
+			status.mactime -= 0x10000;
+		status.flag |= RX_FLAG_TSFT;
+	}
 
 	chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
 	switch (chanstat & B43_RX_CHAN_PHYTYPE) {
@@ -586,10 +648,7 @@ void b43_handle_txstatus(struct b43_wldev *dev,
 			dev->wl->ieee_stats.dot11RTSSuccessCount++;
 	}
 
-	if (b43_using_pio(dev))
-		b43_pio_handle_txstatus(dev, status);
-	else
-		b43_dma_handle_txstatus(dev, status);
+	b43_dma_handle_txstatus(dev, status);
 }
 
 /* Handle TX status report as received through DMA/PIO queues */
@@ -618,19 +677,13 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev,
 /* Stop any TX operation on the device (suspend the hardware queues) */
 void b43_tx_suspend(struct b43_wldev *dev)
 {
-	if (b43_using_pio(dev))
-		b43_pio_freeze_txqueues(dev);
-	else
-		b43_dma_tx_suspend(dev);
+	b43_dma_tx_suspend(dev);
 }
 
 /* Resume any TX operation on the device (resume the hardware queues) */
 void b43_tx_resume(struct b43_wldev *dev)
 {
-	if (b43_using_pio(dev))
-		b43_pio_thaw_txqueues(dev);
-	else
-		b43_dma_tx_resume(dev);
+	b43_dma_tx_resume(dev);
 }
 
 #if 0
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index 6dc079382f7f..ca2a2ab8654c 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -19,68 +19,160 @@ _b43_declare_plcp_hdr(6);
 #undef _b43_declare_plcp_hdr
 
 /* TX header for v4 firmware */
-struct b43_txhdr_fw4 {
-	__le32 mac_ctl;		/* MAC TX control */
-	__le16 mac_frame_ctl;	/* Copy of the FrameControl field */
+struct b43_txhdr {
+	__le32 mac_ctl;			/* MAC TX control */
+	__le16 mac_frame_ctl;		/* Copy of the FrameControl field */
 	__le16 tx_fes_time_norm;	/* TX FES Time Normal */
-	__le16 phy_ctl;		/* PHY TX control */
-	__le16 phy_ctl_0;	/* Unused */
-	__le16 phy_ctl_1;	/* Unused */
-	__le16 phy_ctl_rts_0;	/* Unused */
-	__le16 phy_ctl_rts_1;	/* Unused */
-	__u8 phy_rate;		/* PHY rate */
-	__u8 phy_rate_rts;	/* PHY rate for RTS/CTS */
-	__u8 extra_ft;		/* Extra Frame Types */
-	__u8 chan_radio_code;	/* Channel Radio Code */
-	__u8 iv[16];		/* Encryption IV */
-	__u8 tx_receiver[6];	/* TX Frame Receiver address */
-	__le16 tx_fes_time_fb;	/* TX FES Time Fallback */
-	struct b43_plcp_hdr6 rts_plcp_fb;	/* RTS fallback PLCP */
-	__le16 rts_dur_fb;	/* RTS fallback duration */
-	struct b43_plcp_hdr6 plcp_fb;	/* Fallback PLCP */
-	__le16 dur_fb;		/* Fallback duration */
-	__le16 mm_dur_time;	/* Unused */
-	__le16 mm_dur_time_fb;	/* Unused */
-	__le32 time_stamp;	/* Timestamp */
-	 PAD_BYTES(2);
-	__le16 cookie;		/* TX frame cookie */
-	__le16 tx_status;	/* TX status */
-	struct b43_plcp_hdr6 rts_plcp;	/* RTS PLCP */
-	__u8 rts_frame[16];	/* The RTS frame (if used) */
-	 PAD_BYTES(2);
-	struct b43_plcp_hdr6 plcp;	/* Main PLCP */
+	__le16 phy_ctl;			/* PHY TX control */
+	__le16 phy_ctl1;		/* PHY TX control word 1 */
+	__le16 phy_ctl1_fb;		/* PHY TX control word 1 for fallback rates */
+	__le16 phy_ctl1_rts;		/* PHY TX control word 1 RTS */
+	__le16 phy_ctl1_rts_fb;		/* PHY TX control word 1 RTS for fallback rates */
+	__u8 phy_rate;			/* PHY rate */
+	__u8 phy_rate_rts;		/* PHY rate for RTS/CTS */
+	__u8 extra_ft;			/* Extra Frame Types */
+	__u8 chan_radio_code;		/* Channel Radio Code */
+	__u8 iv[16];			/* Encryption IV */
+	__u8 tx_receiver[6];		/* TX Frame Receiver address */
+	__le16 tx_fes_time_fb;		/* TX FES Time Fallback */
+	struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP header */
+	__le16 rts_dur_fb;		/* RTS fallback duration */
+	struct b43_plcp_hdr6 plcp_fb;	/* Fallback PLCP header */
+	__le16 dur_fb;			/* Fallback duration */
+	__le16 mimo_modelen;		/* MIMO mode length */
+	__le16 mimo_ratelen_fb;		/* MIMO fallback rate length */
+	__le32 timeout;			/* Timeout */
+
+	union {
+		/* The new r410 format. */
+		struct {
+			__le16 mimo_antenna;		/* MIMO antenna select */
+			__le16 preload_size;		/* Preload size */
+			PAD_BYTES(2);
+			__le16 cookie;			/* TX frame cookie */
+			__le16 tx_status;		/* TX status */
+			struct b43_plcp_hdr6 rts_plcp;	/* RTS PLCP header */
+			__u8 rts_frame[16];		/* The RTS frame (if used) */
+			PAD_BYTES(2);
+			struct b43_plcp_hdr6 plcp;	/* Main PLCP header */
+		} new_format __attribute__ ((__packed__));
+
+		/* The old r351 format. */
+		struct {
+			PAD_BYTES(2);
+			__le16 cookie;			/* TX frame cookie */
+			__le16 tx_status;		/* TX status */
+			struct b43_plcp_hdr6 rts_plcp;	/* RTS PLCP header */
+			__u8 rts_frame[16];		/* The RTS frame (if used) */
+			PAD_BYTES(2);
+			struct b43_plcp_hdr6 plcp;	/* Main PLCP header */
+		} old_format __attribute__ ((__packed__));
+
+	} __attribute__ ((__packed__));
 } __attribute__ ((__packed__));
 
 /* MAC TX control */
-#define B43_TX4_MAC_KEYIDX		0x0FF00000	/* Security key index */
-#define B43_TX4_MAC_KEYIDX_SHIFT	20
-#define B43_TX4_MAC_KEYALG		0x00070000	/* Security key algorithm */
-#define B43_TX4_MAC_KEYALG_SHIFT	16
-#define B43_TX4_MAC_LIFETIME	0x00001000
-#define B43_TX4_MAC_FRAMEBURST	0x00000800
-#define B43_TX4_MAC_SENDCTS		0x00000400
-#define B43_TX4_MAC_AMPDU		0x00000300
-#define B43_TX4_MAC_AMPDU_SHIFT	8
-#define B43_TX4_MAC_5GHZ		0x00000080
-#define B43_TX4_MAC_IGNPMQ		0x00000020
-#define B43_TX4_MAC_HWSEQ		0x00000010	/* Use Hardware Sequence Number */
-#define B43_TX4_MAC_STMSDU		0x00000008	/* Start MSDU */
-#define B43_TX4_MAC_SENDRTS		0x00000004
-#define B43_TX4_MAC_LONGFRAME	0x00000002
-#define B43_TX4_MAC_ACK		0x00000001
+#define B43_TXH_MAC_USEFBR		0x10000000 /* Use fallback rate for this AMPDU */
+#define B43_TXH_MAC_KEYIDX		0x0FF00000 /* Security key index */
+#define B43_TXH_MAC_KEYIDX_SHIFT	20
+#define B43_TXH_MAC_KEYALG		0x00070000 /* Security key algorithm */
+#define B43_TXH_MAC_KEYALG_SHIFT	16
+#define B43_TXH_MAC_AMIC		0x00008000 /* AMIC */
+#define B43_TXH_MAC_RIFS		0x00004000 /* Use RIFS */
+#define B43_TXH_MAC_LIFETIME		0x00002000 /* Lifetime */
+#define B43_TXH_MAC_FRAMEBURST		0x00001000 /* Frameburst */
+#define B43_TXH_MAC_SENDCTS		0x00000800 /* Send CTS-to-self */
+#define B43_TXH_MAC_AMPDU		0x00000600 /* AMPDU status */
+#define  B43_TXH_MAC_AMPDU_MPDU		0x00000000 /* Regular MPDU, not an AMPDU */
+#define  B43_TXH_MAC_AMPDU_FIRST	0x00000200 /* First MPDU or AMPDU */
+#define  B43_TXH_MAC_AMPDU_INTER	0x00000400 /* Intermediate MPDU or AMPDU */
+#define  B43_TXH_MAC_AMPDU_LAST		0x00000600 /* Last (or only) MPDU of AMPDU */
+#define B43_TXH_MAC_40MHZ		0x00000100 /* Use 40 MHz bandwidth */
+#define B43_TXH_MAC_5GHZ		0x00000080 /* 5GHz band */
+#define B43_TXH_MAC_DFCS		0x00000040 /* DFCS */
+#define B43_TXH_MAC_IGNPMQ		0x00000020 /* Ignore PMQ */
+#define B43_TXH_MAC_HWSEQ		0x00000010 /* Use Hardware Sequence Number */
+#define B43_TXH_MAC_STMSDU		0x00000008 /* Start MSDU */
+#define B43_TXH_MAC_SENDRTS		0x00000004 /* Send RTS */
+#define B43_TXH_MAC_LONGFRAME		0x00000002 /* Long frame */
+#define B43_TXH_MAC_ACK			0x00000001 /* Immediate ACK */
 
 /* Extra Frame Types */
-#define B43_TX4_EFT_FBOFDM		0x0001	/* Data frame fallback rate type */
-#define B43_TX4_EFT_RTSOFDM		0x0004	/* RTS/CTS rate type */
-#define B43_TX4_EFT_RTSFBOFDM	0x0010	/* RTS/CTS fallback rate type */
+#define B43_TXH_EFT_FB			0x03 /* Data frame fallback encoding */
+#define  B43_TXH_EFT_FB_CCK		0x00 /* CCK */
+#define  B43_TXH_EFT_FB_OFDM		0x01 /* OFDM */
+#define  B43_TXH_EFT_FB_EWC		0x02 /* EWC */
+#define  B43_TXH_EFT_FB_N		0x03 /* N */
+#define B43_TXH_EFT_RTS			0x0C /* RTS/CTS encoding */
+#define  B43_TXH_EFT_RTS_CCK		0x00 /* CCK */
+#define  B43_TXH_EFT_RTS_OFDM		0x04 /* OFDM */
+#define  B43_TXH_EFT_RTS_EWC		0x08 /* EWC */
+#define  B43_TXH_EFT_RTS_N		0x0C /* N */
+#define B43_TXH_EFT_RTSFB		0x30 /* RTS/CTS fallback encoding */
+#define  B43_TXH_EFT_RTSFB_CCK		0x00 /* CCK */
+#define  B43_TXH_EFT_RTSFB_OFDM		0x10 /* OFDM */
+#define  B43_TXH_EFT_RTSFB_EWC		0x20 /* EWC */
+#define  B43_TXH_EFT_RTSFB_N		0x30 /* N */
 
 /* PHY TX control word */
-#define B43_TX4_PHY_OFDM		0x0001	/* Data frame rate type */
-#define B43_TX4_PHY_SHORTPRMBL	0x0010	/* Use short preamble */
-#define B43_TX4_PHY_ANT		0x03C0	/* Antenna selection */
-#define  B43_TX4_PHY_ANT0		0x0000	/* Use antenna 0 */
-#define  B43_TX4_PHY_ANT1		0x0100	/* Use antenna 1 */
-#define  B43_TX4_PHY_ANTLAST	0x0300	/* Use last used antenna */
+#define B43_TXH_PHY_ENC			0x0003 /* Data frame encoding */
+#define  B43_TXH_PHY_ENC_CCK		0x0000 /* CCK */
+#define  B43_TXH_PHY_ENC_OFDM		0x0001 /* OFDM */
+#define  B43_TXH_PHY_ENC_EWC		0x0002 /* EWC */
+#define  B43_TXH_PHY_ENC_N		0x0003 /* N */
+#define B43_TXH_PHY_SHORTPRMBL		0x0010 /* Use short preamble */
+#define B43_TXH_PHY_ANT			0x03C0 /* Antenna selection */
+#define  B43_TXH_PHY_ANT0		0x0000 /* Use antenna 0 */
+#define  B43_TXH_PHY_ANT1		0x0040 /* Use antenna 1 */
+#define  B43_TXH_PHY_ANT01AUTO		0x00C0 /* Use antenna 0/1 auto */
+#define  B43_TXH_PHY_ANT2		0x0100 /* Use antenna 2 */
+#define  B43_TXH_PHY_ANT3		0x0200 /* Use antenna 3 */
+#define B43_TXH_PHY_TXPWR		0xFC00 /* TX power */
+#define B43_TXH_PHY_TXPWR_SHIFT		10
+
+/* PHY TX control word 1 */
+#define B43_TXH_PHY1_BW			0x0007 /* Bandwidth */
+#define  B43_TXH_PHY1_BW_10		0x0000 /* 10 MHz */
+#define  B43_TXH_PHY1_BW_10U		0x0001 /* 10 MHz upper */
+#define  B43_TXH_PHY1_BW_20		0x0002 /* 20 MHz */
+#define  B43_TXH_PHY1_BW_20U		0x0003 /* 20 MHz upper */
+#define  B43_TXH_PHY1_BW_40		0x0004 /* 40 MHz */
+#define  B43_TXH_PHY1_BW_40DUP		0x0005 /* 50 MHz duplicate */
+#define B43_TXH_PHY1_MODE		0x0038 /* Mode */
+#define  B43_TXH_PHY1_MODE_SISO		0x0000 /* SISO */
+#define  B43_TXH_PHY1_MODE_CDD		0x0008 /* CDD */
+#define  B43_TXH_PHY1_MODE_STBC		0x0010 /* STBC */
+#define  B43_TXH_PHY1_MODE_SDM		0x0018 /* SDM */
+#define B43_TXH_PHY1_CRATE		0x0700 /* Coding rate */
+#define  B43_TXH_PHY1_CRATE_1_2		0x0000 /* 1/2 */
+#define  B43_TXH_PHY1_CRATE_2_3		0x0100 /* 2/3 */
+#define  B43_TXH_PHY1_CRATE_3_4		0x0200 /* 3/4 */
+#define  B43_TXH_PHY1_CRATE_4_5		0x0300 /* 4/5 */
+#define  B43_TXH_PHY1_CRATE_5_6		0x0400 /* 5/6 */
+#define  B43_TXH_PHY1_CRATE_7_8		0x0600 /* 7/8 */
+#define B43_TXH_PHY1_MODUL		0x3800 /* Modulation scheme */
+#define  B43_TXH_PHY1_MODUL_BPSK	0x0000 /* BPSK */
+#define  B43_TXH_PHY1_MODUL_QPSK	0x0800 /* QPSK */
+#define  B43_TXH_PHY1_MODUL_QAM16	0x1000 /* QAM16 */
+#define  B43_TXH_PHY1_MODUL_QAM64	0x1800 /* QAM64 */
+#define  B43_TXH_PHY1_MODUL_QAM256	0x2000 /* QAM256 */
+
+
+/* r351 firmware compatibility stuff. */
+static inline
+bool b43_is_old_txhdr_format(struct b43_wldev *dev)
+{
+	return (dev->fw.rev <= 351);
+}
+
+static inline
+size_t b43_txhdr_size(struct b43_wldev *dev)
+{
+	if (b43_is_old_txhdr_format(dev))
+		return 100 + sizeof(struct b43_plcp_hdr6);
+	return 104 + sizeof(struct b43_plcp_hdr6);
+}
+
 
 void b43_generate_txhdr(struct b43_wldev *dev,
 			u8 * txhdr,
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig
index 7e23ec23fc98..6745579ba96d 100644
--- a/drivers/net/wireless/b43legacy/Kconfig
+++ b/drivers/net/wireless/b43legacy/Kconfig
@@ -34,6 +34,22 @@ config B43LEGACY_PCICORE_AUTOSELECT
 	select SSB_DRIVER_PCICORE
 	default y
 
+# LED support
+# This config option automatically enables b43legacy LEDS support,
+# if it's possible.
+config B43LEGACY_LEDS
+	bool
+	depends on B43LEGACY && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43LEGACY)
+	default y
+
+# RFKILL support
+# This config option automatically enables b43legacy RFKILL support,
+# if it's possible.
+config B43LEGACY_RFKILL
+	bool
+	depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY)
+	default y
+
 config B43LEGACY_DEBUG
 	bool "Broadcom 43xx-legacy debugging"
 	depends on B43LEGACY
diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile
index ec3a2482bbad..80cdb73bd140 100644
--- a/drivers/net/wireless/b43legacy/Makefile
+++ b/drivers/net/wireless/b43legacy/Makefile
@@ -1,14 +1,19 @@
-obj-$(CONFIG_B43LEGACY) += b43legacy.o
-b43legacy-obj-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o
+# b43legacy core
+b43legacy-y				+= main.o
+b43legacy-y				+= ilt.o
+b43legacy-y				+= phy.o
+b43legacy-y				+= radio.o
+b43legacy-y				+= sysfs.o
+b43legacy-y				+= xmit.o
+# b43 RFKILL button support
+b43legacy-$(CONFIG_B43LEGACY_RFKILL)	+= rfkill.o
+# b43legacy LED support
+b43legacy-$(CONFIG_B43LEGACY_LEDS)	+= leds.o
+# b43legacy debugging
+b43legacy-$(CONFIG_B43LEGACY_DEBUG)	+= debugfs.o
+# b43legacy DMA and PIO
+b43legacy-$(CONFIG_B43LEGACY_DMA)	+= dma.o
+b43legacy-$(CONFIG_B43LEGACY_PIO)	+= pio.o
 
-b43legacy-obj-$(CONFIG_B43LEGACY_DMA) += dma.o
-b43legacy-obj-$(CONFIG_B43LEGACY_PIO) += pio.o
+obj-$(CONFIG_B43LEGACY)			+= b43legacy.o
 
-b43legacy-objs := main.o \
-		ilt.o \
-		leds.o \
-		phy.o \
-		radio.o \
-		sysfs.o \
-		xmit.o \
-		$(b43legacy-obj-y)
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index afe145cec067..93419adb925e 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -19,6 +19,7 @@
 
 #include "debugfs.h"
 #include "leds.h"
+#include "rfkill.h"
 #include "phy.h"
 
 
@@ -275,6 +276,8 @@
 #define B43legacy_DEFAULT_SHORT_RETRY_LIMIT	7
 #define B43legacy_DEFAULT_LONG_RETRY_LIMIT	4
 
+#define B43legacy_PHY_TX_BADNESS_LIMIT		1000
+
 /* Max size of a security key */
 #define B43legacy_SEC_KEYSIZE		16
 /* Security algorithms. */
@@ -412,7 +415,6 @@ struct b43legacy_phy {
 	u8 calibrated:1;
 	u8 radio_rev;		/* Radio revision */
 
-	bool locked;		/* Only used in b43legacy_phy_{un}lock() */
 	bool dyn_tssi_tbl;	/* tssi2dbm is kmalloc()ed. */
 
 	/* ACI (adjacent channel interference) flags. */
@@ -455,11 +457,6 @@ struct b43legacy_phy {
 	s16 lna_gain;		/* LNA */
 	s16 pga_gain;		/* PGA */
 
-	/* PHY lock for core.rev < 3
-	 * This lock is only used by b43legacy_phy_{un}lock()
-	 */
-	spinlock_t lock;
-
 	/* Desired TX power level (in dBm). This is set by the user and
 	 * adjusted in b43legacy_phy_xmitpower(). */
 	u8 power_level;
@@ -483,9 +480,6 @@ struct b43legacy_phy {
 		u16 txpwr_offset;
 	};
 
-#ifdef CONFIG_B43LEGACY_DEBUG
-	bool manual_txpower_control; /* Manual TX-power control enabled? */
-#endif
 	/* Current Interference Mitigation mode */
 	int interfmode;
 	/* Stack of saved values from the Interference Mitigation code.
@@ -510,6 +504,16 @@ struct b43legacy_phy {
 	u16 lofcal;
 
 	u16 initval;
+
+	/* PHY TX errors counter. */
+	atomic_t txerr_cnt;
+
+#if B43legacy_DEBUG
+	/* Manual TX-power control enabled? */
+	bool manual_txpower_control;
+	/* PHY registers locked by b43legacy_phy_lock()? */
+	bool phy_locked;
+#endif /* B43legacy_DEBUG */
 };
 
 /* Data structures for DMA transmission, per 80211 core. */
@@ -571,10 +575,7 @@ struct b43legacy_wl {
 	 * at a time. General information about this interface follows.
 	 */
 
-	/* Opaque ID of the operating interface from the ieee80211
-	 * subsystem. Do not modify.
-	 */
-	int if_id;
+	struct ieee80211_vif *vif;
 	/* MAC address (can be NULL). */
 	u8 mac_addr[ETH_ALEN];
 	/* Current BSSID (can be NULL). */
@@ -592,9 +593,14 @@ struct b43legacy_wl {
 	u8 rng_initialized;
 	char rng_name[30 + 1];
 
+	/* The RF-kill button */
+	struct b43legacy_rfkill rfkill;
+
 	/* List of all wireless devices on this chip */
 	struct list_head devlist;
 	u8 nr_devs;
+
+	bool radiotap_enabled;
 };
 
 /* Pointers to the firmware data and meta information about it. */
@@ -663,8 +669,11 @@ struct b43legacy_wldev {
 	/* Various statistics about the physical device. */
 	struct b43legacy_stats stats;
 
-#define B43legacy_NR_LEDS		4
-	struct b43legacy_led leds[B43legacy_NR_LEDS];
+	/* The device LEDs. */
+	struct b43legacy_led led_tx;
+	struct b43legacy_led led_rx;
+	struct b43legacy_led led_assoc;
+	struct b43legacy_led led_radio;
 
 	/* Reason code of the last interrupt. */
 	u32 irq_reason;
diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c
index 619b4534ef09..03ce0821a60e 100644
--- a/drivers/net/wireless/b43legacy/debugfs.c
+++ b/drivers/net/wireless/b43legacy/debugfs.c
@@ -209,7 +209,7 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
 	struct b43legacy_wldev *dev;
 	struct b43legacy_debugfs_fops *dfops;
 	struct b43legacy_dfs_file *dfile;
-	ssize_t ret = 0;
+	ssize_t uninitialized_var(ret);
 	char *buf;
 	const size_t bufsize = 1024 * 128;
 	const size_t buforder = get_order(bufsize);
diff --git a/drivers/net/wireless/b43legacy/ilt.c b/drivers/net/wireless/b43legacy/ilt.c
index 247fc780ffdb..a849078aea69 100644
--- a/drivers/net/wireless/b43legacy/ilt.c
+++ b/drivers/net/wireless/b43legacy/ilt.c
@@ -3,7 +3,7 @@
   Broadcom B43legacy wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-		     Stefano Brivio <st3@riseup.net>
+		     Stefano Brivio <stefano.brivio@polimi.it>
 		     Michael Buesch <mbuesch@freenet.de>
 		     Danny van Dyk <kugelfang@gentoo.org>
 		     Andreas Jaggi <andreas.jaggi@waterwave.ch>
diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c
index a584ea810502..cacb786d9713 100644
--- a/drivers/net/wireless/b43legacy/leds.c
+++ b/drivers/net/wireless/b43legacy/leds.c
@@ -1,13 +1,13 @@
 /*
 
-  Broadcom B43legacy wireless driver
+  Broadcom B43 wireless driver
+  LED control
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-		     Stefano Brivio <st3@riseup.net>
-		     Michael Buesch <mb@bu3sch.de>
-		     Danny van Dyk <kugelfang@gentoo.org>
-		     Andreas Jaggi <andreas.jaggi@waterwave.ch>
-  Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
+  Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+  Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.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
@@ -26,273 +26,216 @@
 
 */
 
-#include "leds.h"
 #include "b43legacy.h"
-#include "main.h"
-
-static void b43legacy_led_changestate(struct b43legacy_led *led)
-{
-	struct b43legacy_wldev *dev = led->dev;
-	const int index = led->index;
-	u16 ledctl;
+#include "leds.h"
 
-	B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS));
-	B43legacy_WARN_ON(!led->blink_interval);
-	ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
-	ledctl ^= (1 << index);
-	b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
-}
 
-static void b43legacy_led_blink(unsigned long d)
+static void b43legacy_led_turn_on(struct b43legacy_wldev *dev, u8 led_index,
+			    bool activelow)
 {
-	struct b43legacy_led *led = (struct b43legacy_led *)d;
-	struct b43legacy_wldev *dev = led->dev;
+	struct b43legacy_wl *wl = dev->wl;
 	unsigned long flags;
+	u16 ctl;
 
-	spin_lock_irqsave(&dev->wl->leds_lock, flags);
-	if (led->blink_interval) {
-		b43legacy_led_changestate(led);
-		mod_timer(&led->blink_timer, jiffies + led->blink_interval);
-	}
-	spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+	spin_lock_irqsave(&wl->leds_lock, flags);
+	ctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+	if (activelow)
+		ctl &= ~(1 << led_index);
+	else
+		ctl |= (1 << led_index);
+	b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ctl);
+	spin_unlock_irqrestore(&wl->leds_lock, flags);
 }
 
-static void b43legacy_led_blink_start(struct b43legacy_led *led,
-				      unsigned long interval)
+static void b43legacy_led_turn_off(struct b43legacy_wldev *dev, u8 led_index,
+			     bool activelow)
 {
-	if (led->blink_interval)
-		return;
-	led->blink_interval = interval;
-	b43legacy_led_changestate(led);
-	led->blink_timer.expires = jiffies + interval;
-	add_timer(&led->blink_timer);
+	struct b43legacy_wl *wl = dev->wl;
+	unsigned long flags;
+	u16 ctl;
+
+	spin_lock_irqsave(&wl->leds_lock, flags);
+	ctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+	if (activelow)
+		ctl |= (1 << led_index);
+	else
+		ctl &= ~(1 << led_index);
+	b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ctl);
+	spin_unlock_irqrestore(&wl->leds_lock, flags);
 }
 
-static void b43legacy_led_blink_stop(struct b43legacy_led *led, int sync)
+/* Callback from the LED subsystem. */
+static void b43legacy_led_brightness_set(struct led_classdev *led_dev,
+				   enum led_brightness brightness)
 {
+	struct b43legacy_led *led = container_of(led_dev, struct b43legacy_led,
+				    led_dev);
 	struct b43legacy_wldev *dev = led->dev;
-	const int index = led->index;
-	u16 ledctl;
+	bool radio_enabled;
 
-	if (!led->blink_interval)
-		return;
-	if (unlikely(sync))
-		del_timer_sync(&led->blink_timer);
-	else
-		del_timer(&led->blink_timer);
-	led->blink_interval = 0;
+	/* Checking the radio-enabled status here is slightly racy,
+	 * but we want to avoid the locking overhead and we don't care
+	 * whether the LED has the wrong state for a second. */
+	radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable);
 
-	/* Make sure the LED is turned off. */
-	B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS));
-	ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
-	if (led->activelow)
-		ledctl |= (1 << index);
+	if (brightness == LED_OFF || !radio_enabled)
+		b43legacy_led_turn_off(dev, led->index, led->activelow);
 	else
-		ledctl &= ~(1 << index);
-	b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+		b43legacy_led_turn_on(dev, led->index, led->activelow);
 }
 
-static void b43legacy_led_init_hardcoded(struct b43legacy_wldev *dev,
-					 struct b43legacy_led *led,
-					 int led_index)
+static int b43legacy_register_led(struct b43legacy_wldev *dev,
+				  struct b43legacy_led *led,
+				  const char *name, char *default_trigger,
+				  u8 led_index, bool activelow)
 {
-	struct ssb_bus *bus = dev->dev->bus;
+	int err;
+
+	b43legacy_led_turn_off(dev, led_index, activelow);
+	if (led->dev)
+		return -EEXIST;
+	if (!default_trigger)
+		return -EINVAL;
+	led->dev = dev;
+	led->index = led_index;
+	led->activelow = activelow;
+	strncpy(led->name, name, sizeof(led->name));
+
+	led->led_dev.name = led->name;
+	led->led_dev.default_trigger = default_trigger;
+	led->led_dev.brightness_set = b43legacy_led_brightness_set;
+
+	err = led_classdev_register(dev->dev->dev, &led->led_dev);
+	if (err) {
+		b43legacywarn(dev->wl, "LEDs: Failed to register %s\n", name);
+		led->dev = NULL;
+		return err;
+	}
+	return 0;
+}
 
-	/* This function is called, if the behaviour (and activelow)
-	 * information for a LED is missing in the SPROM.
-	 * We hardcode the behaviour values for various devices here.
-	 * Note that the B43legacy_LED_TEST_XXX behaviour values can
-	 * be used to figure out which led is mapped to which index.
-	 */
+static void b43legacy_unregister_led(struct b43legacy_led *led)
+{
+	if (!led->dev)
+		return;
+	led_classdev_unregister(&led->led_dev);
+	b43legacy_led_turn_off(led->dev, led->index, led->activelow);
+	led->dev = NULL;
+}
+
+static void b43legacy_map_led(struct b43legacy_wldev *dev,
+			u8 led_index,
+			enum b43legacy_led_behaviour behaviour,
+			bool activelow)
+{
+	struct ieee80211_hw *hw = dev->wl->hw;
+	char name[B43legacy_LED_MAX_NAME_LEN + 1];
 
-	switch (led_index) {
-	case 0:
-		led->behaviour = B43legacy_LED_ACTIVITY;
-		led->activelow = 1;
-		if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
-			led->behaviour = B43legacy_LED_RADIO_ALL;
+	/* Map the b43 specific LED behaviour value to the
+	 * generic LED triggers. */
+	switch (behaviour) {
+	case B43legacy_LED_INACTIVE:
 		break;
-	case 1:
-		led->behaviour = B43legacy_LED_RADIO_B;
-		if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
-			led->behaviour = B43legacy_LED_ASSOC;
+	case B43legacy_LED_OFF:
+		b43legacy_led_turn_off(dev, led_index, activelow);
 		break;
-	case 2:
-		led->behaviour = B43legacy_LED_RADIO_A;
+	case B43legacy_LED_ON:
+		b43legacy_led_turn_on(dev, led_index, activelow);
 		break;
-	case 3:
-		led->behaviour = B43legacy_LED_OFF;
+	case B43legacy_LED_ACTIVITY:
+	case B43legacy_LED_TRANSFER:
+	case B43legacy_LED_APTRANSFER:
+		snprintf(name, sizeof(name),
+			 "b43legacy-%s:tx", wiphy_name(hw->wiphy));
+		b43legacy_register_led(dev, &dev->led_tx, name,
+				 ieee80211_get_tx_led_name(hw),
+				 led_index, activelow);
+		snprintf(name, sizeof(name),
+			 "b43legacy-%s:rx", wiphy_name(hw->wiphy));
+		b43legacy_register_led(dev, &dev->led_rx, name,
+				 ieee80211_get_rx_led_name(hw),
+				 led_index, activelow);
+		break;
+	case B43legacy_LED_RADIO_ALL:
+	case B43legacy_LED_RADIO_A:
+	case B43legacy_LED_RADIO_B:
+	case B43legacy_LED_MODE_BG:
+		snprintf(name, sizeof(name),
+			 "b43legacy-%s:radio", wiphy_name(hw->wiphy));
+		b43legacy_register_led(dev, &dev->led_radio, name,
+				 b43legacy_rfkill_led_name(dev),
+				 led_index, activelow);
+		/* Sync the RF-kill LED state with the switch state. */
+		if (dev->radio_hw_enable)
+			b43legacy_led_turn_on(dev, led_index, activelow);
+		break;
+	case B43legacy_LED_WEIRD:
+	case B43legacy_LED_ASSOC:
+		snprintf(name, sizeof(name),
+			 "b43legacy-%s:assoc", wiphy_name(hw->wiphy));
+		b43legacy_register_led(dev, &dev->led_assoc, name,
+				 ieee80211_get_assoc_led_name(hw),
+				 led_index, activelow);
 		break;
 	default:
-		B43legacy_BUG_ON(1);
+		b43legacywarn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n",
+			behaviour);
+		break;
 	}
 }
 
-int b43legacy_leds_init(struct b43legacy_wldev *dev)
+void b43legacy_leds_init(struct b43legacy_wldev *dev)
 {
-	struct b43legacy_led *led;
+	struct ssb_bus *bus = dev->dev->bus;
 	u8 sprom[4];
 	int i;
-
-	sprom[0] = dev->dev->bus->sprom.r1.gpio0;
-	sprom[1] = dev->dev->bus->sprom.r1.gpio1;
-	sprom[2] = dev->dev->bus->sprom.r1.gpio2;
-	sprom[3] = dev->dev->bus->sprom.r1.gpio3;
-
-	for (i = 0; i < B43legacy_NR_LEDS; i++) {
-		led = &(dev->leds[i]);
-		led->index = i;
-		led->dev = dev;
-		setup_timer(&led->blink_timer,
-			    b43legacy_led_blink,
-			    (unsigned long)led);
-
-		if (sprom[i] == 0xFF)
-			b43legacy_led_init_hardcoded(dev, led, i);
-		else {
-			led->behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR;
-			led->activelow = !!(sprom[i] &
-					   B43legacy_LED_ACTIVELOW);
+	enum b43legacy_led_behaviour behaviour;
+	bool activelow;
+
+	sprom[0] = bus->sprom.gpio0;
+	sprom[1] = bus->sprom.gpio1;
+	sprom[2] = bus->sprom.gpio2;
+	sprom[3] = bus->sprom.gpio3;
+
+	for (i = 0; i < 4; i++) {
+		if (sprom[i] == 0xFF) {
+			/* There is no LED information in the SPROM
+			 * for this LED. Hardcode it here. */
+			activelow = 0;
+			switch (i) {
+			case 0:
+				behaviour = B43legacy_LED_ACTIVITY;
+				activelow = 1;
+				if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
+					behaviour = B43legacy_LED_RADIO_ALL;
+				break;
+			case 1:
+				behaviour = B43legacy_LED_RADIO_B;
+				if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
+					behaviour = B43legacy_LED_ASSOC;
+				break;
+			case 2:
+				behaviour = B43legacy_LED_RADIO_A;
+				break;
+			case 3:
+				behaviour = B43legacy_LED_OFF;
+				break;
+			default:
+				B43legacy_WARN_ON(1);
+				return;
+			}
+		} else {
+			behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR;
+			activelow = !!(sprom[i] & B43legacy_LED_ACTIVELOW);
 		}
+		b43legacy_map_led(dev, i, behaviour, activelow);
 	}
-
-	return 0;
 }
 
 void b43legacy_leds_exit(struct b43legacy_wldev *dev)
 {
-	struct b43legacy_led *led;
-	int i;
-
-	for (i = 0; i < B43legacy_NR_LEDS; i++) {
-		led = &(dev->leds[i]);
-		b43legacy_led_blink_stop(led, 1);
-	}
-	b43legacy_leds_switch_all(dev, 0);
-}
-
-void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity)
-{
-	struct b43legacy_led *led;
-	struct b43legacy_phy *phy = &dev->phy;
-	const int transferring = (jiffies - dev->stats.last_tx)
-				  < B43legacy_LED_XFER_THRES;
-	int i;
-	int turn_on;
-	unsigned long interval = 0;
-	u16 ledctl;
-	unsigned long flags;
-	bool radio_enabled = (phy->radio_on && dev->radio_hw_enable);
-
-	spin_lock_irqsave(&dev->wl->leds_lock, flags);
-	ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
-	for (i = 0; i < B43legacy_NR_LEDS; i++) {
-		led = &(dev->leds[i]);
-
-		turn_on = 0;
-		switch (led->behaviour) {
-		case B43legacy_LED_INACTIVE:
-			continue;
-		case B43legacy_LED_OFF:
-			break;
-		case B43legacy_LED_ON:
-			turn_on = 1;
-			break;
-		case B43legacy_LED_ACTIVITY:
-			turn_on = activity;
-			break;
-		case B43legacy_LED_RADIO_ALL:
-			turn_on = radio_enabled;
-			break;
-		case B43legacy_LED_RADIO_A:
-			break;
-		case B43legacy_LED_RADIO_B:
-			turn_on = radio_enabled;
-			break;
-		case B43legacy_LED_MODE_BG:
-			if (phy->type == B43legacy_PHYTYPE_G && radio_enabled)
-				turn_on = 1;
-			break;
-		case B43legacy_LED_TRANSFER:
-			if (transferring)
-				b43legacy_led_blink_start(led,
-						B43legacy_LEDBLINK_MEDIUM);
-			else
-				b43legacy_led_blink_stop(led, 0);
-			continue;
-		case B43legacy_LED_APTRANSFER:
-			if (b43legacy_is_mode(dev->wl,
-						IEEE80211_IF_TYPE_AP)) {
-				if (transferring) {
-					interval = B43legacy_LEDBLINK_FAST;
-					turn_on = 1;
-				}
-			} else {
-				turn_on = 1;
-				if (transferring)
-					interval = B43legacy_LEDBLINK_FAST;
-				else
-					turn_on = 0;
-			}
-			if (turn_on)
-				b43legacy_led_blink_start(led, interval);
-			else
-				b43legacy_led_blink_stop(led, 0);
-			continue;
-		case B43legacy_LED_WEIRD:
-			break;
-		case B43legacy_LED_ASSOC:
-			turn_on = 1;
-#ifdef CONFIG_B43LEGACY_DEBUG
-		case B43legacy_LED_TEST_BLINKSLOW:
-			b43legacy_led_blink_start(led, B43legacy_LEDBLINK_SLOW);
-			continue;
-		case B43legacy_LED_TEST_BLINKMEDIUM:
-			b43legacy_led_blink_start(led,
-						   B43legacy_LEDBLINK_MEDIUM);
-			continue;
-		case B43legacy_LED_TEST_BLINKFAST:
-			b43legacy_led_blink_start(led, B43legacy_LEDBLINK_FAST);
-			continue;
-#endif /* CONFIG_B43LEGACY_DEBUG */
-		default:
-			B43legacy_BUG_ON(1);
-		};
-
-		if (led->activelow)
-			turn_on = !turn_on;
-		if (turn_on)
-			ledctl |= (1 << i);
-		else
-			ledctl &= ~(1 << i);
-	}
-	b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
-	spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
-}
-
-void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on)
-{
-	struct b43legacy_led *led;
-	u16 ledctl;
-	int i;
-	int bit_on;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->wl->leds_lock, flags);
-	ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
-	for (i = 0; i < B43legacy_NR_LEDS; i++) {
-		led = &(dev->leds[i]);
-		if (led->behaviour == B43legacy_LED_INACTIVE)
-			continue;
-		if (on)
-			bit_on = led->activelow ? 0 : 1;
-		else
-			bit_on = led->activelow ? 1 : 0;
-		if (bit_on)
-			ledctl |= (1 << i);
-		else
-			ledctl &= ~(1 << i);
-	}
-	b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
-	spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+	b43legacy_unregister_led(&dev->led_tx);
+	b43legacy_unregister_led(&dev->led_rx);
+	b43legacy_unregister_led(&dev->led_assoc);
+	b43legacy_unregister_led(&dev->led_radio);
 }
diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h
index b989f503e684..82167a90088f 100644
--- a/drivers/net/wireless/b43legacy/leds.h
+++ b/drivers/net/wireless/b43legacy/leds.h
@@ -1,30 +1,33 @@
 #ifndef B43legacy_LEDS_H_
 #define B43legacy_LEDS_H_
 
+struct b43legacy_wldev;
+
+#ifdef CONFIG_B43LEGACY_LEDS
+
 #include <linux/types.h>
-#include <linux/timer.h>
+#include <linux/leds.h>
 
 
+#define B43legacy_LED_MAX_NAME_LEN	31
+
 struct b43legacy_led {
-	u8 behaviour;
-	bool activelow;
-	/* Index in the "leds" array in b43legacy_wldev */
-	u8 index;
 	struct b43legacy_wldev *dev;
-	struct timer_list blink_timer;
-	unsigned long blink_interval;
+	/* The LED class device */
+	struct led_classdev led_dev;
+	/* The index number of the LED. */
+	u8 index;
+	/* If activelow is true, the LED is ON if the
+	 * bit is switched off. */
+	bool activelow;
+	/* The unique name string for this LED device. */
+	char name[B43legacy_LED_MAX_NAME_LEN + 1];
 };
 
-/* Delay between state changes when blinking in jiffies */
-#define B43legacy_LEDBLINK_SLOW		(HZ / 1)
-#define B43legacy_LEDBLINK_MEDIUM	(HZ / 4)
-#define B43legacy_LEDBLINK_FAST		(HZ / 8)
-
-#define B43legacy_LED_XFER_THRES	(HZ / 100)
-
 #define B43legacy_LED_BEHAVIOUR		0x7F
 #define B43legacy_LED_ACTIVELOW		0x80
-enum { /* LED behaviour values */
+/* LED behaviour values */
+enum b43legacy_led_behaviour {
 	B43legacy_LED_OFF,
 	B43legacy_LED_ON,
 	B43legacy_LED_ACTIVITY,
@@ -37,20 +40,24 @@ enum { /* LED behaviour values */
 	B43legacy_LED_WEIRD,
 	B43legacy_LED_ASSOC,
 	B43legacy_LED_INACTIVE,
-
-	/* Behaviour values for testing.
-	 * With these values it is easier to figure out
-	 * the real behaviour of leds, in case the SPROM
-	 * is missing information.
-	 */
-	B43legacy_LED_TEST_BLINKSLOW,
-	B43legacy_LED_TEST_BLINKMEDIUM,
-	B43legacy_LED_TEST_BLINKFAST,
 };
 
-int b43legacy_leds_init(struct b43legacy_wldev *dev);
+void b43legacy_leds_init(struct b43legacy_wldev *dev);
 void b43legacy_leds_exit(struct b43legacy_wldev *dev);
-void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity);
-void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on);
+
+#else /* CONFIG_B43EGACY_LEDS */
+/* LED support disabled */
+
+struct b43legacy_led {
+	/* empty */
+};
+
+static inline void b43legacy_leds_init(struct b43legacy_wldev *dev)
+{
+}
+static inline void b43legacy_leds_exit(struct b43legacy_wldev *dev)
+{
+}
+#endif /* CONFIG_B43LEGACY_LEDS */
 
 #endif /* B43legacy_LEDS_H_ */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 32d5e1785bda..4ed4243feeaa 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -3,7 +3,7 @@
  *  Broadcom B43legacy wireless driver
  *
  *  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
- *  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ *  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
  *  Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
  *  Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
  *  Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -75,18 +75,6 @@ module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
 MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames"
 		 " Preemption");
 
-static int modparam_short_retry = B43legacy_DEFAULT_SHORT_RETRY_LIMIT;
-module_param_named(short_retry, modparam_short_retry, int, 0444);
-MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
-
-static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT;
-module_param_named(long_retry, modparam_long_retry, int, 0444);
-MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
-
-static int modparam_noleds;
-module_param_named(noleds, modparam_noleds, int, 0444);
-MODULE_PARM_DESC(noleds, "Turn off all LED activity");
-
 static char modparam_fwpostfix[16];
 module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
 MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load.");
@@ -988,7 +976,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
 	plcp.data = 0;
 	b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
 	dur = ieee80211_generic_frame_duration(dev->wl->hw,
-					       dev->wl->if_id,
+					       dev->wl->vif,
 					       size,
 					       B43legacy_RATE_TO_100KBPS(rate));
 	/* Write PLCP in two parts and timing for packet transfer */
@@ -1054,7 +1042,7 @@ static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev,
 	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 					 IEEE80211_STYPE_PROBE_RESP);
 	dur = ieee80211_generic_frame_duration(dev->wl->hw,
-					       dev->wl->if_id,
+					       dev->wl->vif,
 					       *dest_size,
 					       B43legacy_RATE_TO_100KBPS(rate));
 	hdr->duration_id = dur;
@@ -1217,7 +1205,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
 	u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
 	u32 merged_dma_reason = 0;
 	int i;
-	int activity = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->wl->irq_lock, flags);
@@ -1234,8 +1221,15 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
 	if (unlikely(reason & B43legacy_IRQ_MAC_TXERR))
 		b43legacyerr(dev->wl, "MAC transmission error\n");
 
-	if (unlikely(reason & B43legacy_IRQ_PHY_TXERR))
+	if (unlikely(reason & B43legacy_IRQ_PHY_TXERR)) {
 		b43legacyerr(dev->wl, "PHY transmission error\n");
+		rmb();
+		if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) {
+			b43legacyerr(dev->wl, "Too many PHY TX errors, "
+					      "restarting the controller\n");
+			b43legacy_controller_restart(dev, "PHY TX errors");
+		}
+	}
 
 	if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK |
 					  B43legacy_DMAIRQ_NONFATALMASK))) {
@@ -1281,7 +1275,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
 			b43legacy_pio_rx(dev->pio.queue0);
 		else
 			b43legacy_dma_rx(dev->dma.rx_ring0);
-		/* We intentionally don't set "activity" to 1, here. */
 	}
 	B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE);
 	B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE);
@@ -1290,20 +1283,13 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
 			b43legacy_pio_rx(dev->pio.queue3);
 		else
 			b43legacy_dma_rx(dev->dma.rx_ring3);
-		activity = 1;
 	}
 	B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE);
 	B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE);
 
-	if (reason & B43legacy_IRQ_TX_OK) {
+	if (reason & B43legacy_IRQ_TX_OK)
 		handle_irq_transmit_status(dev);
-		activity = 1;
-		/* TODO: In AP mode, this also causes sending of powersave
-			 responses. */
-	}
 
-	if (!modparam_noleds)
-		b43legacy_leds_update(dev, activity);
 	b43legacy_interrupt_enable(dev, dev->irq_savedstate);
 	mmiowb();
 	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
@@ -1755,7 +1741,6 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
 			  B43legacy_MMIO_STATUS_BITFIELD)
 			  & 0xFFFF3FFF);
 
-	b43legacy_leds_switch_all(dev, 0);
 	b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
 			  b43legacy_read16(dev,
 			  B43legacy_MMIO_GPIO_MASK)
@@ -1767,7 +1752,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
 		mask |= 0x0060;
 		set |= 0x0060;
 	}
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) {
 		b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
 				  b43legacy_read16(dev,
 				  B43legacy_MMIO_GPIO_MASK)
@@ -1811,6 +1796,7 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev)
 {
 	dev->mac_suspended--;
 	B43legacy_WARN_ON(dev->mac_suspended < 0);
+	B43legacy_WARN_ON(irqs_disabled());
 	if (dev->mac_suspended == 0) {
 		b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
 				  b43legacy_read32(dev,
@@ -1822,6 +1808,11 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev)
 		b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
 		b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
 		b43legacy_power_saving_ctl_bits(dev, -1, -1);
+
+		/* Re-enable IRQs. */
+		spin_lock_irq(&dev->wl->irq_lock);
+		b43legacy_interrupt_enable(dev, dev->irq_savedstate);
+		spin_unlock_irq(&dev->wl->irq_lock);
 	}
 }
 
@@ -1831,20 +1822,31 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev)
 	int i;
 	u32 tmp;
 
+	might_sleep();
+	B43legacy_WARN_ON(irqs_disabled());
 	B43legacy_WARN_ON(dev->mac_suspended < 0);
+
 	if (dev->mac_suspended == 0) {
+		/* Mask IRQs before suspending MAC. Otherwise
+		 * the MAC stays busy and won't suspend. */
+		spin_lock_irq(&dev->wl->irq_lock);
+		tmp = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
+		spin_unlock_irq(&dev->wl->irq_lock);
+		b43legacy_synchronize_irq(dev);
+		dev->irq_savedstate = tmp;
+
 		b43legacy_power_saving_ctl_bits(dev, -1, 1);
 		b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
 				  b43legacy_read32(dev,
 				  B43legacy_MMIO_STATUS_BITFIELD)
 				  & ~B43legacy_SBF_MAC_ENABLED);
 		b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
-		for (i = 10000; i; i--) {
+		for (i = 40; i; i--) {
 			tmp = b43legacy_read32(dev,
 					       B43legacy_MMIO_GEN_IRQ_REASON);
 			if (tmp & B43legacy_IRQ_MAC_SUSPENDED)
 				goto out;
-			udelay(1);
+			msleep(1);
 		}
 		b43legacyerr(dev->wl, "MAC suspend failed\n");
 	}
@@ -1989,27 +1991,10 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev,
 			      B43legacy_SHM_SH_PRPHYCTL, tmp);
 }
 
-/* Returns TRUE, if the radio is enabled in hardware. */
-static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
-{
-	if (dev->phy.rev >= 3) {
-		if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI)
-		      & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK))
-			return 1;
-	} else {
-		if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO)
-		    & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK)
-			return 1;
-	}
-	return 0;
-}
-
 /* This is the opposite of b43legacy_chip_init() */
 static void b43legacy_chip_exit(struct b43legacy_wldev *dev)
 {
-	b43legacy_radio_turn_off(dev);
-	if (!modparam_noleds)
-		b43legacy_leds_exit(dev);
+	b43legacy_radio_turn_off(dev, 1);
 	b43legacy_gpio_cleanup(dev);
 	/* firmware is released later */
 }
@@ -2039,9 +2024,10 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
 	err = b43legacy_gpio_init(dev);
 	if (err)
 		goto out; /* firmware is released later */
+
 	err = b43legacy_upload_initvals(dev);
 	if (err)
-		goto err_gpio_cleanup;
+		goto err_gpio_clean;
 	b43legacy_radio_turn_on(dev);
 
 	b43legacy_write16(dev, 0x03E6, 0x0000);
@@ -2113,14 +2099,17 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
 	b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY,
 			  dev->dev->bus->chipco.fast_pwrup_delay);
 
+	/* PHY TX errors counter. */
+	atomic_set(&phy->txerr_cnt, B43legacy_PHY_TX_BADNESS_LIMIT);
+
 	B43legacy_WARN_ON(err != 0);
 	b43legacydbg(dev->wl, "Chip initialized\n");
 out:
 	return err;
 
 err_radio_off:
-	b43legacy_radio_turn_off(dev);
-err_gpio_cleanup:
+	b43legacy_radio_turn_off(dev, 1);
+err_gpio_clean:
 	b43legacy_gpio_cleanup(dev);
 	goto out;
 }
@@ -2140,7 +2129,7 @@ static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev)
 static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev)
 {
 	b43legacy_phy_lo_mark_all_unused(dev);
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) {
 		b43legacy_mac_suspend(dev);
 		b43legacy_calc_nrssi_slope(dev);
 		b43legacy_mac_enable(dev);
@@ -2156,20 +2145,9 @@ static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev)
 static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev)
 {
 	b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */
-}
-
-static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev)
-{
-	bool radio_hw_enable;
 
-	/* check if radio hardware enabled status changed */
-	radio_hw_enable = b43legacy_is_hw_radio_enabled(dev);
-	if (unlikely(dev->radio_hw_enable != radio_hw_enable)) {
-		dev->radio_hw_enable = radio_hw_enable;
-		b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n",
-		       (radio_hw_enable) ? "enabled" : "disabled");
-		b43legacy_leds_update(dev, 0);
-	}
+	atomic_set(&dev->phy.txerr_cnt, B43legacy_PHY_TX_BADNESS_LIMIT);
+	wmb();
 }
 
 static void do_periodic_work(struct b43legacy_wldev *dev)
@@ -2177,94 +2155,45 @@ static void do_periodic_work(struct b43legacy_wldev *dev)
 	unsigned int state;
 
 	state = dev->periodic_state;
-	if (state % 120 == 0)
+	if (state % 8 == 0)
 		b43legacy_periodic_every120sec(dev);
-	if (state % 60 == 0)
+	if (state % 4 == 0)
 		b43legacy_periodic_every60sec(dev);
-	if (state % 30 == 0)
+	if (state % 2 == 0)
 		b43legacy_periodic_every30sec(dev);
-	if (state % 15 == 0)
-		b43legacy_periodic_every15sec(dev);
-	b43legacy_periodic_every1sec(dev);
+	b43legacy_periodic_every15sec(dev);
 }
 
-/* Estimate a "Badness" value based on the periodic work
- * state-machine state. "Badness" is worse (bigger), if the
- * periodic work will take longer.
+/* Periodic work locking policy:
+ * 	The whole periodic work handler is protected by
+ * 	wl->mutex. If another lock is needed somewhere in the
+ * 	pwork callchain, it's aquired in-place, where it's needed.
  */
-static int estimate_periodic_work_badness(unsigned int state)
-{
-	int badness = 0;
-
-	if (state % 120 == 0) /* every 120 sec */
-		badness += 10;
-	if (state % 60 == 0) /* every 60 sec */
-		badness += 5;
-	if (state % 30 == 0) /* every 30 sec */
-		badness += 1;
-	if (state % 15 == 0) /* every 15 sec */
-		badness += 1;
-
-#define BADNESS_LIMIT	4
-	return badness;
-}
-
 static void b43legacy_periodic_work_handler(struct work_struct *work)
 {
-	struct b43legacy_wldev *dev =
-			     container_of(work, struct b43legacy_wldev,
-			     periodic_work.work);
-	unsigned long flags;
+	struct b43legacy_wldev *dev = container_of(work, struct b43legacy_wldev,
+					     periodic_work.work);
+	struct b43legacy_wl *wl = dev->wl;
 	unsigned long delay;
-	u32 savedirqs = 0;
-	int badness;
 
-	mutex_lock(&dev->wl->mutex);
+	mutex_lock(&wl->mutex);
 
 	if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED))
 		goto out;
 	if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP))
 		goto out_requeue;
 
-	badness = estimate_periodic_work_badness(dev->periodic_state);
-	if (badness > BADNESS_LIMIT) {
-		spin_lock_irqsave(&dev->wl->irq_lock, flags);
-		/* Suspend TX as we don't want to transmit packets while
-		 * we recalibrate the hardware. */
-		b43legacy_tx_suspend(dev);
-		savedirqs = b43legacy_interrupt_disable(dev,
-							  B43legacy_IRQ_ALL);
-		/* Periodic work will take a long time, so we want it to
-		 * be preemtible and release the spinlock. */
-		spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
-		b43legacy_synchronize_irq(dev);
-
-		do_periodic_work(dev);
+	do_periodic_work(dev);
 
-		spin_lock_irqsave(&dev->wl->irq_lock, flags);
-		b43legacy_interrupt_enable(dev, savedirqs);
-		b43legacy_tx_resume(dev);
-		mmiowb();
-		spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
-	} else {
-		/* Take the global driver lock. This will lock any operation. */
-		spin_lock_irqsave(&dev->wl->irq_lock, flags);
-
-		do_periodic_work(dev);
-
-		mmiowb();
-		spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
-	}
 	dev->periodic_state++;
 out_requeue:
 	if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST))
 		delay = msecs_to_jiffies(50);
 	else
-		delay = round_jiffies_relative(HZ);
-	queue_delayed_work(dev->wl->hw->workqueue,
-			   &dev->periodic_work, delay);
+		delay = round_jiffies_relative(HZ * 15);
+	queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
 out:
-	mutex_unlock(&dev->wl->mutex);
+	mutex_unlock(&wl->mutex);
 }
 
 static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev)
@@ -2366,9 +2295,9 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl)
 	return err;
 }
 
-static int b43legacy_tx(struct ieee80211_hw *hw,
-			struct sk_buff *skb,
-			struct ieee80211_tx_control *ctl)
+static int b43legacy_op_tx(struct ieee80211_hw *hw,
+			   struct sk_buff *skb,
+			   struct ieee80211_tx_control *ctl)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev = wl->current_dev;
@@ -2392,15 +2321,15 @@ out:
 	return NETDEV_TX_OK;
 }
 
-static int b43legacy_conf_tx(struct ieee80211_hw *hw,
-			     int queue,
-			     const struct ieee80211_tx_queue_params *params)
+static int b43legacy_op_conf_tx(struct ieee80211_hw *hw,
+				int queue,
+				const struct ieee80211_tx_queue_params *params)
 {
 	return 0;
 }
 
-static int b43legacy_get_tx_stats(struct ieee80211_hw *hw,
-				  struct ieee80211_tx_queue_stats *stats)
+static int b43legacy_op_get_tx_stats(struct ieee80211_hw *hw,
+				     struct ieee80211_tx_queue_stats *stats)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev = wl->current_dev;
@@ -2422,8 +2351,8 @@ out:
 	return err;
 }
 
-static int b43legacy_get_stats(struct ieee80211_hw *hw,
-			       struct ieee80211_low_level_stats *stats)
+static int b43legacy_op_get_stats(struct ieee80211_hw *hw,
+				  struct ieee80211_low_level_stats *stats)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	unsigned long flags;
@@ -2572,8 +2501,8 @@ static int b43legacy_antenna_from_ieee80211(u8 antenna)
 	}
 }
 
-static int b43legacy_dev_config(struct ieee80211_hw *hw,
-				struct ieee80211_conf *conf)
+static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
+				   struct ieee80211_conf *conf)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev;
@@ -2634,6 +2563,8 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw,
 			b43legacy_short_slot_timing_disable(dev);
 	}
 
+	dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
 	/* Adjust the desired TX power level. */
 	if (conf->power_level != 0) {
 		if (conf->power_level != phy->power_level) {
@@ -2660,7 +2591,7 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw,
 					      " physically off. Press the"
 					      " button to turn it on.\n");
 		} else {
-			b43legacy_radio_turn_off(dev);
+			b43legacy_radio_turn_off(dev, 0);
 			b43legacyinfo(dev->wl, "Radio turned off by"
 				      " software\n");
 		}
@@ -2676,37 +2607,11 @@ out_unlock_mutex:
 	return err;
 }
 
-static int b43legacy_dev_set_key(struct ieee80211_hw *hw,
-				 enum set_key_cmd cmd,
-				 const u8 *local_addr, const u8 *addr,
-				 struct ieee80211_key_conf *key)
-{
-	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
-	struct b43legacy_wldev *dev = wl->current_dev;
-	unsigned long flags;
-	int err = -EOPNOTSUPP;
-	DECLARE_MAC_BUF(mac);
-
-	if (!dev)
-		return -ENODEV;
-	mutex_lock(&wl->mutex);
-	spin_lock_irqsave(&wl->irq_lock, flags);
-
-	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
-		err = -ENODEV;
-	}
-	spin_unlock_irqrestore(&wl->irq_lock, flags);
-	mutex_unlock(&wl->mutex);
-	b43legacydbg(wl, "Using software based encryption for "
-		     "mac: %s\n", print_mac(mac, addr));
-	return err;
-}
-
-static void b43legacy_configure_filter(struct ieee80211_hw *hw,
-				       unsigned int changed,
-				       unsigned int *fflags,
-				       int mc_count,
-				       struct dev_addr_list *mc_list)
+static void b43legacy_op_configure_filter(struct ieee80211_hw *hw,
+					  unsigned int changed,
+					  unsigned int *fflags,
+					  int mc_count,
+					  struct dev_addr_list *mc_list)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev = wl->current_dev;
@@ -2741,9 +2646,9 @@ static void b43legacy_configure_filter(struct ieee80211_hw *hw,
 	spin_unlock_irqrestore(&wl->irq_lock, flags);
 }
 
-static int b43legacy_config_interface(struct ieee80211_hw *hw,
-				      int if_id,
-				      struct ieee80211_if_conf *conf)
+static int b43legacy_op_config_interface(struct ieee80211_hw *hw,
+					 struct ieee80211_vif *vif,
+					 struct ieee80211_if_conf *conf)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev = wl->current_dev;
@@ -2753,7 +2658,7 @@ static int b43legacy_config_interface(struct ieee80211_hw *hw,
 		return -ENODEV;
 	mutex_lock(&wl->mutex);
 	spin_lock_irqsave(&wl->irq_lock, flags);
-	B43legacy_WARN_ON(wl->if_id != if_id);
+	B43legacy_WARN_ON(wl->vif != vif);
 	if (conf->bssid)
 		memcpy(wl->bssid, conf->bssid, ETH_ALEN);
 	else
@@ -2942,8 +2847,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
 	memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
 	memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
 
-	/* Flags */
-	phy->locked = 0;
 	/* Assume the radio is enabled. If it's not enabled, the state will
 	 * immediately get fixed on the first periodic work run. */
 	dev->radio_hw_enable = 1;
@@ -2976,7 +2879,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
 	phy->lofcal = 0xFFFF;
 	phy->initval = 0xFFFF;
 
-	spin_lock_init(&phy->lock);
 	phy->interfmode = B43legacy_INTERFMODE_NONE;
 	phy->channel = 0xFF;
 }
@@ -3029,6 +2931,20 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
 #endif /* CONFIG_SSB_DRIVER_PCICORE */
 }
 
+/* Write the short and long frame retry limit values. */
+static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev,
+				       unsigned int short_retry,
+				       unsigned int long_retry)
+{
+	/* The retry limit is a 4-bit counter. Enforce this to avoid overflowing
+	 * the chip-internal counter. */
+	short_retry = min(short_retry, (unsigned int)0xF);
+	long_retry = min(long_retry, (unsigned int)0xF);
+
+	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry);
+	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry);
+}
+
 /* Shutdown a wireless core */
 /* Locking: wl->mutex */
 static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
@@ -3047,11 +2963,12 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
 	cancel_work_sync(&dev->restart_work);
 	mutex_lock(&wl->mutex);
 
+	b43legacy_leds_exit(dev);
 	b43legacy_rng_exit(dev->wl);
 	b43legacy_pio_free(dev);
 	b43legacy_dma_free(dev);
 	b43legacy_chip_exit(dev);
-	b43legacy_radio_turn_off(dev);
+	b43legacy_radio_turn_off(dev, 1);
 	b43legacy_switch_analog(dev, 0);
 	if (phy->dyn_tssi_tbl)
 		kfree(phy->tssi2dbm);
@@ -3093,7 +3010,6 @@ static void prepare_phy_data_for_init(struct b43legacy_wldev *dev)
 
 	/* Flags */
 	phy->calibrated = 0;
-	phy->locked = 0;
 
 	if (phy->_lo_pairs)
 		memset(phy->_lo_pairs, 0,
@@ -3153,7 +3069,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
 		hf |= B43legacy_HF_SYMW;
 		if (phy->rev == 1)
 			hf |= B43legacy_HF_GDCW;
-		if (sprom->r1.boardflags_lo & B43legacy_BFL_PACTRL)
+		if (sprom->boardflags_lo & B43legacy_BFL_PACTRL)
 			hf |= B43legacy_HF_OFDMPABOOST;
 	} else if (phy->type == B43legacy_PHYTYPE_B) {
 		hf |= B43legacy_HF_SYMW;
@@ -3162,16 +3078,9 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
 	}
 	b43legacy_hf_write(dev, hf);
 
-	/* Short/Long Retry Limit.
-	 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
-	 * the chip-internal counter.
-	 */
-	tmp = limit_value(modparam_short_retry, 0, 0xF);
-	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
-			      0x0006, tmp);
-	tmp = limit_value(modparam_long_retry, 0, 0xF);
-	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
-			      0x0007, tmp);
+	b43legacy_set_retry_limits(dev,
+				   B43legacy_DEFAULT_SHORT_RETRY_LIMIT,
+				   B43legacy_DEFAULT_LONG_RETRY_LIMIT);
 
 	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
 			      0x0044, 3);
@@ -3223,6 +3132,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
 
 	b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
 
+	b43legacy_leds_init(dev);
 out:
 	return err;
 
@@ -3239,8 +3149,8 @@ err_kfree_lo_control:
 	return err;
 }
 
-static int b43legacy_add_interface(struct ieee80211_hw *hw,
-				   struct ieee80211_if_init_conf *conf)
+static int b43legacy_op_add_interface(struct ieee80211_hw *hw,
+				      struct ieee80211_if_init_conf *conf)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev;
@@ -3263,7 +3173,7 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw,
 
 	dev = wl->current_dev;
 	wl->operating = 1;
-	wl->if_id = conf->if_id;
+	wl->vif = conf->vif;
 	wl->if_type = conf->type;
 	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
 
@@ -3279,8 +3189,8 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw,
 	return err;
 }
 
-static void b43legacy_remove_interface(struct ieee80211_hw *hw,
-				       struct ieee80211_if_init_conf *conf)
+static void b43legacy_op_remove_interface(struct ieee80211_hw *hw,
+					  struct ieee80211_if_init_conf *conf)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev = wl->current_dev;
@@ -3291,7 +3201,8 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw,
 	mutex_lock(&wl->mutex);
 
 	B43legacy_WARN_ON(!wl->operating);
-	B43legacy_WARN_ON(wl->if_id != conf->if_id);
+	B43legacy_WARN_ON(wl->vif != conf->vif);
+	wl->vif = NULL;
 
 	wl->operating = 0;
 
@@ -3304,13 +3215,17 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw,
 	mutex_unlock(&wl->mutex);
 }
 
-static int b43legacy_start(struct ieee80211_hw *hw)
+static int b43legacy_op_start(struct ieee80211_hw *hw)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev = wl->current_dev;
 	int did_init = 0;
 	int err = 0;
 
+	/* First register RFkill.
+	 * LEDs that are registered later depend on it. */
+	b43legacy_rfkill_init(dev);
+
 	mutex_lock(&wl->mutex);
 
 	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
@@ -3335,11 +3250,13 @@ out_mutex_unlock:
 	return err;
 }
 
-static void b43legacy_stop(struct ieee80211_hw *hw)
+static void b43legacy_op_stop(struct ieee80211_hw *hw)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev = wl->current_dev;
 
+	b43legacy_rfkill_exit(dev);
+
 	mutex_lock(&wl->mutex);
 	if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
 		b43legacy_wireless_core_stop(dev);
@@ -3347,20 +3264,41 @@ static void b43legacy_stop(struct ieee80211_hw *hw)
 	mutex_unlock(&wl->mutex);
 }
 
+static int b43legacy_op_set_retry_limit(struct ieee80211_hw *hw,
+					u32 short_retry_limit,
+					u32 long_retry_limit)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev;
+	int err = 0;
+
+	mutex_lock(&wl->mutex);
+	dev = wl->current_dev;
+	if (unlikely(!dev ||
+		     (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+	b43legacy_set_retry_limits(dev, short_retry_limit, long_retry_limit);
+out_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
 
 static const struct ieee80211_ops b43legacy_hw_ops = {
-	.tx = b43legacy_tx,
-	.conf_tx = b43legacy_conf_tx,
-	.add_interface = b43legacy_add_interface,
-	.remove_interface = b43legacy_remove_interface,
-	.config = b43legacy_dev_config,
-	.config_interface = b43legacy_config_interface,
-	.set_key = b43legacy_dev_set_key,
-	.configure_filter = b43legacy_configure_filter,
-	.get_stats = b43legacy_get_stats,
-	.get_tx_stats = b43legacy_get_tx_stats,
-	.start = b43legacy_start,
-	.stop = b43legacy_stop,
+	.tx			= b43legacy_op_tx,
+	.conf_tx		= b43legacy_op_conf_tx,
+	.add_interface		= b43legacy_op_add_interface,
+	.remove_interface	= b43legacy_op_remove_interface,
+	.config			= b43legacy_op_dev_config,
+	.config_interface	= b43legacy_op_config_interface,
+	.configure_filter	= b43legacy_op_configure_filter,
+	.get_stats		= b43legacy_op_get_stats,
+	.get_tx_stats		= b43legacy_op_get_tx_stats,
+	.start			= b43legacy_op_start,
+	.stop			= b43legacy_op_stop,
+	.set_retry_limit	= b43legacy_op_set_retry_limit,
 };
 
 /* Hard-reset the chip. Do not call this directly.
@@ -3498,18 +3436,13 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
 	else
 		have_bphy = 1;
 
-	/* Initialize LEDs structs. */
-	err = b43legacy_leds_init(dev);
-	if (err)
-		goto err_powerdown;
-
 	dev->phy.gmode = (have_gphy || have_bphy);
 	tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
 	b43legacy_wireless_core_reset(dev, tmp);
 
 	err = b43legacy_phy_versioning(dev);
 	if (err)
-		goto err_leds_exit;
+		goto err_powerdown;
 	/* Check if this device supports multiband. */
 	if (!pdev ||
 	    (pdev->device != 0x4312 &&
@@ -3535,17 +3468,17 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
 
 	err = b43legacy_validate_chipaccess(dev);
 	if (err)
-		goto err_leds_exit;
+		goto err_powerdown;
 	err = b43legacy_setup_modes(dev, have_bphy, have_gphy);
 	if (err)
-		goto err_leds_exit;
+		goto err_powerdown;
 
 	/* Now set some default "current_dev" */
 	if (!wl->current_dev)
 		wl->current_dev = dev;
 	INIT_WORK(&dev->restart_work, b43legacy_chip_reset);
 
-	b43legacy_radio_turn_off(dev);
+	b43legacy_radio_turn_off(dev, 1);
 	b43legacy_switch_analog(dev, 0);
 	ssb_device_disable(dev->dev, 0);
 	ssb_bus_may_powerdown(bus);
@@ -3553,8 +3486,6 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
 out:
 	return err;
 
-err_leds_exit:
-	b43legacy_leds_exit(dev);
 err_powerdown:
 	ssb_bus_may_powerdown(bus);
 	return err;
@@ -3637,12 +3568,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus)
 	if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
 	    bus->boardinfo.type == 0x4E &&
 	    bus->boardinfo.rev > 0x40)
-		bus->sprom.r1.boardflags_lo |= B43legacy_BFL_PACTRL;
-
-	/* Convert Antennagain values to Q5.2 */
-	if (bus->sprom.r1.antenna_gain_bg == 0xFF)
-		bus->sprom.r1.antenna_gain_bg = 2; /* if unset, use 2 dBm */
-	bus->sprom.r1.antenna_gain_bg <<= 2;
+		bus->sprom.boardflags_lo |= B43legacy_BFL_PACTRL;
 }
 
 static void b43legacy_wireless_exit(struct ssb_device *dev,
@@ -3677,10 +3603,10 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
 	hw->max_noise = -110;
 	hw->queues = 1; /* FIXME: hardware has more queues */
 	SET_IEEE80211_DEV(hw, dev->dev);
-	if (is_valid_ether_addr(sprom->r1.et1mac))
-		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+	if (is_valid_ether_addr(sprom->et1mac))
+		SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
 	else
-		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+		SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac);
 
 	/* Get and initialize struct b43legacy_wl */
 	wl = hw_to_b43legacy_wl(hw);
diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h
index 68435c50d8e0..1f0e2e379b02 100644
--- a/drivers/net/wireless/b43legacy/main.h
+++ b/drivers/net/wireless/b43legacy/main.h
@@ -3,7 +3,7 @@
   Broadcom B43legacy wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (c) 2005  Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005  Andreas Jaggi <andreas.jaggi@waterwave.ch>
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
index 491e518e4aeb..c16febbdbf5d 100644
--- a/drivers/net/wireless/b43legacy/phy.c
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -3,7 +3,7 @@
   Broadcom B43legacy wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-		     Stefano Brivio <st3@riseup.net>
+		     Stefano Brivio <stefano.brivio@polimi.it>
 		     Michael Buesch <mbuesch@freenet.de>
 		     Danny van Dyk <kugelfang@gentoo.org>
      Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -91,40 +91,36 @@ void b43legacy_voluntary_preempt(void)
 #endif /* CONFIG_PREEMPT */
 }
 
-void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev)
+/* Lock the PHY registers against concurrent access from the microcode.
+ * This lock is nonrecursive. */
+void b43legacy_phy_lock(struct b43legacy_wldev *dev)
 {
-	struct b43legacy_phy *phy = &dev->phy;
+#if B43legacy_DEBUG
+	B43legacy_WARN_ON(dev->phy.phy_locked);
+	dev->phy.phy_locked = 1;
+#endif
 
-	B43legacy_WARN_ON(!irqs_disabled());
-	if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) {
-		phy->locked = 0;
-		return;
-	}
 	if (dev->dev->id.revision < 3) {
 		b43legacy_mac_suspend(dev);
-		spin_lock(&phy->lock);
 	} else {
 		if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
 			b43legacy_power_saving_ctl_bits(dev, -1, 1);
 	}
-	phy->locked = 1;
 }
 
-void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev)
+void b43legacy_phy_unlock(struct b43legacy_wldev *dev)
 {
-	struct b43legacy_phy *phy = &dev->phy;
+#if B43legacy_DEBUG
+	B43legacy_WARN_ON(!dev->phy.phy_locked);
+	dev->phy.phy_locked = 0;
+#endif
 
-	B43legacy_WARN_ON(!irqs_disabled());
 	if (dev->dev->id.revision < 3) {
-		if (phy->locked) {
-			spin_unlock(&phy->lock);
-			b43legacy_mac_enable(dev);
-		}
+		b43legacy_mac_enable(dev);
 	} else {
 		if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
 			b43legacy_power_saving_ctl_bits(dev, -1, -1);
 	}
-	phy->locked = 0;
 }
 
 u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset)
@@ -441,7 +437,7 @@ static void b43legacy_phy_inita(struct b43legacy_wldev *dev)
 	might_sleep();
 
 	b43legacy_phy_setupg(dev);
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL)
+	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL)
 		b43legacy_phy_write(dev, 0x046E, 0x03CF);
 }
 
@@ -543,7 +539,7 @@ static void b43legacy_phy_initb4(struct b43legacy_wldev *dev)
 	if (phy->radio_ver == 0x2050)
 		b43legacy_phy_write(dev, 0x002A, 0x88C2);
 	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) {
 		b43legacy_calc_nrssi_slope(dev);
 		b43legacy_calc_nrssi_threshold(dev);
 	}
@@ -699,7 +695,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev)
 		b43legacy_radio_write16(dev, 0x005A, 0x0088);
 		b43legacy_radio_write16(dev, 0x005B, 0x006B);
 		b43legacy_radio_write16(dev, 0x005C, 0x000F);
-		if (dev->dev->bus->sprom.r1.boardflags_lo & 0x8000) {
+		if (dev->dev->bus->sprom.boardflags_lo & 0x8000) {
 			b43legacy_radio_write16(dev, 0x005D, 0x00FA);
 			b43legacy_radio_write16(dev, 0x005E, 0x00D8);
 		} else {
@@ -797,7 +793,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev)
 		b43legacy_phy_write(dev, 0x0062, 0x0007);
 		b43legacy_radio_init2050(dev);
 		b43legacy_phy_lo_g_measure(dev);
-		if (dev->dev->bus->sprom.r1.boardflags_lo &
+		if (dev->dev->bus->sprom.boardflags_lo &
 		    B43legacy_BFL_RSSI) {
 			b43legacy_calc_nrssi_slope(dev);
 			b43legacy_calc_nrssi_threshold(dev);
@@ -921,7 +917,7 @@ static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev)
 			    b43legacy_phy_read(dev, 0x0811) | 0x0100);
 	b43legacy_phy_write(dev, 0x0812,
 			    b43legacy_phy_read(dev, 0x0812) & 0xCFFF);
-	if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_EXTLNA) {
+	if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA) {
 		if (phy->rev >= 7) {
 			b43legacy_phy_write(dev, 0x0811,
 					    b43legacy_phy_read(dev, 0x0811)
@@ -1072,7 +1068,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev)
 			b43legacy_phy_write(dev, 0x0036,
 					    (b43legacy_phy_read(dev, 0x0036)
 					     & 0x0FFF) | (phy->txctl2 << 12));
-		if (dev->dev->bus->sprom.r1.boardflags_lo &
+		if (dev->dev->bus->sprom.boardflags_lo &
 		    B43legacy_BFL_PACTRL)
 			b43legacy_phy_write(dev, 0x002E, 0x8075);
 		else
@@ -1087,7 +1083,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev)
 		b43legacy_phy_write(dev, 0x080F, 0x8078);
 	}
 
-	if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) {
+	if (!(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) {
 		/* The specs state to update the NRSSI LT with
 		 * the value 0x7FFFFFFF here. I think that is some weird
 		 * compiler optimization in the original driver.
@@ -1789,7 +1785,6 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
 	s16 baseband_att_delta;
 	s16 radio_attenuation;
 	s16 baseband_attenuation;
-	unsigned long phylock_flags;
 
 	if (phy->savedpctlreg == 0xFFFF)
 		return;
@@ -1838,9 +1833,9 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
 
 	estimated_pwr = b43legacy_phy_estimate_power_out(dev, average);
 
-	max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
+	max_pwr = dev->dev->bus->sprom.maxpwr_bg;
 
-	if ((dev->dev->bus->sprom.r1.boardflags_lo
+	if ((dev->dev->bus->sprom.boardflags_lo
 	     & B43legacy_BFL_PACTRL) &&
 	    (phy->type == B43legacy_PHYTYPE_G))
 		max_pwr -= 0x3;
@@ -1848,7 +1843,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
 		b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM."
 			"\n");
 		max_pwr = 74; /* fake it */
-		dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+		dev->dev->bus->sprom.maxpwr_bg = max_pwr;
 	}
 
 	/* Use regulatory information to get the maximum power.
@@ -1858,7 +1853,8 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
 	 * and 1.5 dBm (a safety factor??). The result is in Q5.2 format
 	 * which accounts for the factor of 4 */
 #define REG_MAX_PWR 20
-	max_pwr = min(REG_MAX_PWR * 4 - dev->dev->bus->sprom.r1.antenna_gain_bg
+	max_pwr = min(REG_MAX_PWR * 4
+		      - dev->dev->bus->sprom.antenna_gain.ghz24.a0
 		      - 0x6, max_pwr);
 
 	/* find the desired power in Q5.2 - power_level is in dBm
@@ -1918,7 +1914,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
 				txpower = 3;
 				radio_attenuation += 2;
 				baseband_attenuation += 2;
-			} else if (dev->dev->bus->sprom.r1.boardflags_lo
+			} else if (dev->dev->bus->sprom.boardflags_lo
 				   & B43legacy_BFL_PACTRL) {
 				baseband_attenuation += 4 *
 						     (radio_attenuation - 2);
@@ -1943,13 +1939,13 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
 	phy->bbatt = baseband_attenuation;
 
 	/* Adjust the hardware */
-	b43legacy_phy_lock(dev, phylock_flags);
+	b43legacy_phy_lock(dev);
 	b43legacy_radio_lock(dev);
 	b43legacy_radio_set_txpower_bg(dev, baseband_attenuation,
 				       radio_attenuation, txpower);
 	b43legacy_phy_lo_mark_current_used(dev);
 	b43legacy_radio_unlock(dev);
-	b43legacy_phy_unlock(dev, phylock_flags);
+	b43legacy_phy_unlock(dev);
 }
 
 static inline
@@ -2000,9 +1996,9 @@ int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev)
 
 	B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B ||
 			  phy->type == B43legacy_PHYTYPE_G));
-	pab0 = (s16)(dev->dev->bus->sprom.r1.pa0b0);
-	pab1 = (s16)(dev->dev->bus->sprom.r1.pa0b1);
-	pab2 = (s16)(dev->dev->bus->sprom.r1.pa0b2);
+	pab0 = (s16)(dev->dev->bus->sprom.pa0b0);
+	pab1 = (s16)(dev->dev->bus->sprom.pa0b1);
+	pab2 = (s16)(dev->dev->bus->sprom.pa0b2);
 
 	if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
 		phy->idle_tssi = 0x34;
@@ -2013,9 +2009,10 @@ int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev)
 	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
 	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
 		/* The pabX values are set in SPROM. Use them. */
-		if ((s8)dev->dev->bus->sprom.r1.itssi_bg != 0 &&
-		    (s8)dev->dev->bus->sprom.r1.itssi_bg != -1)
-			phy->idle_tssi = (s8)(dev->dev->bus->sprom.r1.itssi_bg);
+		if ((s8)dev->dev->bus->sprom.itssi_bg != 0 &&
+		    (s8)dev->dev->bus->sprom.itssi_bg != -1)
+			phy->idle_tssi = (s8)(dev->dev->bus->sprom.
+					  itssi_bg);
 		else
 			phy->idle_tssi = 62;
 		dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h
index f11b4271714c..ecbe409f9a94 100644
--- a/drivers/net/wireless/b43legacy/phy.h
+++ b/drivers/net/wireless/b43legacy/phy.h
@@ -3,7 +3,7 @@
   Broadcom B43legacy wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-		     Stefano Brivio <st3@riseup.net>
+		     Stefano Brivio <stefano.brivio@polimi.it>
 		     Michael Buesch <mbuesch@freenet.de>
 		     Danny van Dyk <kugelfang@gentoo.org>
 		     Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -171,18 +171,8 @@ void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt);
 
 struct b43legacy_wldev;
 
-void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev);
-#define b43legacy_phy_lock(bcm, flags) 		\
-	do {					\
-		local_irq_save(flags);		\
-		b43legacy_raw_phy_lock(bcm);	\
-	} while (0)
-void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev);
-#define b43legacy_phy_unlock(bcm, flags)	\
-	do {					\
-		b43legacy_raw_phy_unlock(bcm);	\
-		local_irq_restore(flags);	\
-	} while (0)
+void b43legacy_phy_lock(struct b43legacy_wldev *dev);
+void b43legacy_phy_unlock(struct b43legacy_wldev *dev);
 
 /* Card uses the loopback gain stuff */
 #define has_loopback_gain(phy)			 \
diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
index a361dee664af..318a270cf9b4 100644
--- a/drivers/net/wireless/b43legacy/radio.c
+++ b/drivers/net/wireless/b43legacy/radio.c
@@ -3,7 +3,7 @@
   Broadcom B43legacy wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-		     Stefano Brivio <st3@riseup.net>
+		     Stefano Brivio <stefano.brivio@polimi.it>
 		     Michael Buesch <mbuesch@freenet.de>
 		     Danny van Dyk <kugelfang@gentoo.org>
 		     Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -92,6 +92,7 @@ void b43legacy_radio_lock(struct b43legacy_wldev *dev)
 	u32 status;
 
 	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	B43legacy_WARN_ON(status & B43legacy_SBF_RADIOREG_LOCK);
 	status |= B43legacy_SBF_RADIOREG_LOCK;
 	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
 	mmiowb();
@@ -104,6 +105,7 @@ void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
 
 	b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
 	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	B43legacy_WARN_ON(!(status & B43legacy_SBF_RADIOREG_LOCK));
 	status &= ~B43legacy_SBF_RADIOREG_LOCK;
 	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
 	mmiowb();
@@ -284,12 +286,11 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
 	unsigned int j;
 	unsigned int start;
 	unsigned int end;
-	unsigned long phylock_flags;
 
 	if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))
 		return 0;
 
-	b43legacy_phy_lock(dev, phylock_flags);
+	b43legacy_phy_lock(dev);
 	b43legacy_radio_lock(dev);
 	b43legacy_phy_write(dev, 0x0802,
 			    b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
@@ -323,7 +324,7 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
 			ret[j] = 1;
 	}
 	b43legacy_radio_unlock(dev);
-	b43legacy_phy_unlock(dev, phylock_flags);
+	b43legacy_phy_unlock(dev);
 
 	return ret[channel - 1];
 }
@@ -827,7 +828,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
 	case B43legacy_PHYTYPE_B: {
 		if (phy->radio_ver != 0x2050)
 			return;
-		if (!(dev->dev->bus->sprom.r1.boardflags_lo &
+		if (!(dev->dev->bus->sprom.boardflags_lo &
 		    B43legacy_BFL_RSSI))
 			return;
 
@@ -857,7 +858,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
 	}
 	case B43legacy_PHYTYPE_G:
 		if (!phy->gmode ||
-		    !(dev->dev->bus->sprom.r1.boardflags_lo &
+		    !(dev->dev->bus->sprom.boardflags_lo &
 		    B43legacy_BFL_RSSI)) {
 			tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);
 			if (tmp16 >= 0x20)
@@ -1406,7 +1407,7 @@ static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)
 	if (!phy->gmode)
 		return 0;
 	if (!has_loopback_gain(phy)) {
-		if (phy->rev < 7 || !(dev->dev->bus->sprom.r1.boardflags_lo
+		if (phy->rev < 7 || !(dev->dev->bus->sprom.boardflags_lo
 		    & B43legacy_BFL_EXTLNA)) {
 			switch (lpd) {
 			case LPD(0, 1, 1):
@@ -1459,7 +1460,7 @@ static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)
 		}
 
 		loop_or = (loop << 8) | extern_lna_control;
-		if (phy->rev >= 7 && dev->dev->bus->sprom.r1.boardflags_lo
+		if (phy->rev >= 7 && dev->dev->bus->sprom.boardflags_lo
 		    & B43legacy_BFL_EXTLNA) {
 			if (extern_lna_control)
 				loop_or |= 0x8000;
@@ -1550,7 +1551,7 @@ u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)
 					    b43legacy_get_812_value(dev,
 					    LPD(0, 1, 1)));
 			if (phy->rev < 7 ||
-			    !(dev->dev->bus->sprom.r1.boardflags_lo
+			    !(dev->dev->bus->sprom.boardflags_lo
 			    & B43legacy_BFL_EXTLNA))
 				b43legacy_phy_write(dev, 0x0811, 0x01B3);
 			else
@@ -1786,7 +1787,7 @@ int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
 			  channel2freq_bg(channel));
 
 	if (channel == 14) {
-		if (dev->dev->bus->sprom.r1.country_code == 5)   /* JAPAN) */
+		if (dev->dev->bus->sprom.country_code == 5)   /* JAPAN) */
 			b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
 					      B43legacy_UCODEFLAGS_OFFSET,
 					      b43legacy_shm_read32(dev,
@@ -2113,21 +2114,25 @@ void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
 		B43legacy_BUG_ON(1);
 	}
 	phy->radio_on = 1;
-	b43legacy_leds_update(dev, 0);
 }
 
-void b43legacy_radio_turn_off(struct b43legacy_wldev *dev)
+void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force)
 {
 	struct b43legacy_phy *phy = &dev->phy;
 
+	if (!phy->radio_on && !force)
+		return;
+
 	if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
 		u16 rfover, rfoverval;
 
 		rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);
 		rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);
-		phy->radio_off_context.rfover = rfover;
-		phy->radio_off_context.rfoverval = rfoverval;
-		phy->radio_off_context.valid = 1;
+		if (!force) {
+			phy->radio_off_context.rfover = rfover;
+			phy->radio_off_context.rfoverval = rfoverval;
+			phy->radio_off_context.valid = 1;
+		}
 		b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);
 		b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
 				    rfoverval & 0xFF73);
@@ -2135,7 +2140,6 @@ void b43legacy_radio_turn_off(struct b43legacy_wldev *dev)
 		b43legacy_phy_write(dev, 0x0015, 0xAA00);
 	phy->radio_on = 0;
 	b43legacydbg(dev->wl, "Radio initialized\n");
-	b43legacy_leds_update(dev, 0);
 }
 
 void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h
index 6c6a203439e1..ec4de2811c52 100644
--- a/drivers/net/wireless/b43legacy/radio.h
+++ b/drivers/net/wireless/b43legacy/radio.h
@@ -3,7 +3,7 @@
   Broadcom B43legacy wireless driver
 
   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
-		     Stefano Brivio <st3@riseup.net>
+		     Stefano Brivio <stefano.brivio@polimi.it>
 		     Michael Buesch <mbuesch@freenet.de>
 		     Danny van Dyk <kugelfang@gentoo.org>
 		     Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -61,7 +61,7 @@ void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val);
 u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev);
 
 void b43legacy_radio_turn_on(struct b43legacy_wldev *dev);
-void b43legacy_radio_turn_off(struct b43legacy_wldev *dev);
+void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force);
 
 int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel,
 				  int synthetic_pu_workaround);
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c
new file mode 100644
index 000000000000..d178dfbb1c9f
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/rfkill.c
@@ -0,0 +1,205 @@
+/*
+
+  Broadcom B43 wireless driver
+  RFKILL support
+
+  Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "rfkill.h"
+#include "radio.h"
+#include "b43legacy.h"
+
+#include <linux/kmod.h>
+
+
+/* Returns TRUE, if the radio is enabled in hardware. */
+static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
+{
+	if (dev->phy.rev >= 3) {
+		if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI)
+		      & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK))
+			return 1;
+	} else {
+		if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO)
+		    & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK)
+			return 1;
+	}
+	return 0;
+}
+
+/* The poll callback for the hardware button. */
+static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
+{
+	struct b43legacy_wldev *dev = poll_dev->private;
+	struct b43legacy_wl *wl = dev->wl;
+	bool enabled;
+	bool report_change = 0;
+
+	mutex_lock(&wl->mutex);
+	if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) {
+		mutex_unlock(&wl->mutex);
+		return;
+	}
+	enabled = b43legacy_is_hw_radio_enabled(dev);
+	if (unlikely(enabled != dev->radio_hw_enable)) {
+		dev->radio_hw_enable = enabled;
+		report_change = 1;
+		b43legacyinfo(wl, "Radio hardware status changed to %s\n",
+			enabled ? "ENABLED" : "DISABLED");
+	}
+	mutex_unlock(&wl->mutex);
+
+	/* send the radio switch event to the system - note both a key press
+	 * and a release are required */
+	if (unlikely(report_change)) {
+		input_report_key(poll_dev->input, KEY_WLAN, 1);
+		input_report_key(poll_dev->input, KEY_WLAN, 0);
+	}
+}
+
+/* Called when the RFKILL toggled in software.
+ * This is called without locking. */
+static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
+{
+	struct b43legacy_wldev *dev = data;
+	struct b43legacy_wl *wl = dev->wl;
+	int err = -EBUSY;
+
+	if (!wl->rfkill.registered)
+		return 0;
+
+	mutex_lock(&wl->mutex);
+	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
+		goto out_unlock;
+	err = 0;
+	switch (state) {
+	case RFKILL_STATE_ON:
+		if (!dev->radio_hw_enable) {
+			/* No luck. We can't toggle the hardware RF-kill
+			 * button from software. */
+			err = -EBUSY;
+			goto out_unlock;
+		}
+		if (!dev->phy.radio_on)
+			b43legacy_radio_turn_on(dev);
+		break;
+	case RFKILL_STATE_OFF:
+		if (dev->phy.radio_on)
+			b43legacy_radio_turn_off(dev, 0);
+		break;
+	}
+
+out_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
+
+	if (!rfk->registered)
+		return NULL;
+	return rfkill_get_led_name(rfk->rfkill);
+}
+
+void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_wl *wl = dev->wl;
+	struct b43legacy_rfkill *rfk = &(wl->rfkill);
+	int err;
+
+	rfk->registered = 0;
+
+	rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
+	if (!rfk->rfkill)
+		goto out_error;
+	snprintf(rfk->name, sizeof(rfk->name),
+		 "b43legacy-%s", wiphy_name(wl->hw->wiphy));
+	rfk->rfkill->name = rfk->name;
+	rfk->rfkill->state = RFKILL_STATE_ON;
+	rfk->rfkill->data = dev;
+	rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle;
+	rfk->rfkill->user_claim_unsupported = 1;
+
+	rfk->poll_dev = input_allocate_polled_device();
+	if (!rfk->poll_dev) {
+		rfkill_free(rfk->rfkill);
+		goto err_freed_rfk;
+	}
+
+	rfk->poll_dev->private = dev;
+	rfk->poll_dev->poll = b43legacy_rfkill_poll;
+	rfk->poll_dev->poll_interval = 1000; /* msecs */
+
+	rfk->poll_dev->input->name = rfk->name;
+	rfk->poll_dev->input->id.bustype = BUS_HOST;
+	rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
+	rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
+	set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
+
+	err = rfkill_register(rfk->rfkill);
+	if (err)
+		goto err_free_polldev;
+
+#ifdef CONFIG_RFKILL_INPUT_MODULE
+	/* B43legacy RF-kill isn't useful without the rfkill-input subsystem.
+	 * Try to load the module. */
+	err = request_module("rfkill-input");
+	if (err)
+		b43legacywarn(wl, "Failed to load the rfkill-input module."
+			"The built-in radio LED will not work.\n");
+#endif /* CONFIG_RFKILL_INPUT */
+
+	err = input_register_polled_device(rfk->poll_dev);
+	if (err)
+		goto err_unreg_rfk;
+
+	rfk->registered = 1;
+
+	return;
+err_unreg_rfk:
+	rfkill_unregister(rfk->rfkill);
+err_free_polldev:
+	input_free_polled_device(rfk->poll_dev);
+	rfk->poll_dev = NULL;
+err_freed_rfk:
+	rfk->rfkill = NULL;
+out_error:
+	rfk->registered = 0;
+	b43legacywarn(wl, "RF-kill button init failed\n");
+}
+
+void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
+
+	if (!rfk->registered)
+		return;
+	rfk->registered = 0;
+
+	input_unregister_polled_device(rfk->poll_dev);
+	rfkill_unregister(rfk->rfkill);
+	input_free_polled_device(rfk->poll_dev);
+	rfk->poll_dev = NULL;
+	rfk->rfkill = NULL;
+}
+
diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h
new file mode 100644
index 000000000000..11150a8032f0
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/rfkill.h
@@ -0,0 +1,59 @@
+#ifndef B43legacy_RFKILL_H_
+#define B43legacy_RFKILL_H_
+
+struct b43legacy_wldev;
+
+#ifdef CONFIG_B43LEGACY_RFKILL
+
+#include <linux/rfkill.h>
+#include <linux/workqueue.h>
+#include <linux/input-polldev.h>
+
+
+
+struct b43legacy_rfkill {
+	/* The RFKILL subsystem data structure */
+	struct rfkill *rfkill;
+	/* The poll device for the RFKILL input button */
+	struct input_polled_dev *poll_dev;
+	/* Did initialization succeed? Used for freeing. */
+	bool registered;
+	/* The unique name of this rfkill switch */
+	char name[sizeof("b43legacy-phy4294967295")];
+};
+
+/* The init function returns void, because we are not interested
+ * in failing the b43 init process when rfkill init failed. */
+void b43legacy_rfkill_init(struct b43legacy_wldev *dev);
+void b43legacy_rfkill_exit(struct b43legacy_wldev *dev);
+
+char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev);
+
+
+#else /* CONFIG_B43LEGACY_RFKILL */
+/* No RFKILL support. */
+
+struct b43legacy_rfkill {
+	/* empty */
+};
+
+static inline void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev)
+{
+}
+static inline void b43legacy_rfkill_free(struct b43legacy_wldev *dev)
+{
+}
+static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
+{
+}
+static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
+{
+}
+static inline char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)
+{
+	return NULL;
+}
+
+#endif /* CONFIG_B43LEGACY_RFKILL */
+
+#endif /* B43legacy_RFKILL_H_ */
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index fa1e65687a63..e20c552442d5 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -5,7 +5,7 @@
   Transmission (TX/RX) related functions.
 
   Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
-  Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it>
   Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
   Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
@@ -223,7 +223,7 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
 	} else {
 		int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb);
 		txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
-							 dev->wl->if_id,
+							 txctl->vif,
 							 fragment_len,
 							 fbrate_base100kbps);
 	}
@@ -290,6 +290,8 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
 		mac_ctl |= B43legacy_TX4_MAC_STMSDU;
 	if (rate_fb_ofdm)
 		mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
+	if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)
+		mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
 
 	/* Generate the RTS or CTS-to-self frame */
 	if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
@@ -310,7 +312,7 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
 
 		if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
 			ieee80211_ctstoself_get(dev->wl->hw,
-						dev->wl->if_id,
+						txctl->vif,
 						fragment_data,
 						fragment_len, txctl,
 						(struct ieee80211_cts *)
@@ -319,7 +321,7 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
 			len = sizeof(struct ieee80211_cts);
 		} else {
 			ieee80211_rts_get(dev->wl->hw,
-					  dev->wl->if_id,
+					  txctl->vif,
 					  fragment_data, fragment_len, txctl,
 					  (struct ieee80211_rts *)
 					  (txhdr->rts_frame));
@@ -335,7 +337,6 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
 					    len, rts_rate_fb);
 		hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
 		txhdr->rts_dur_fb = hdr->duration_id;
-		mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
 	}
 
 	/* Magic cookie */
@@ -378,7 +379,7 @@ static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev,
 			else
 				tmp -= 3;
 		} else {
-			if (dev->dev->bus->sprom.r1.boardflags_lo
+			if (dev->dev->bus->sprom.boardflags_lo
 			    & B43legacy_BFL_RSSI) {
 				if (in_rssi > 63)
 					in_rssi = 63;
@@ -531,7 +532,24 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
 	else
 		status.rate = b43legacy_plcp_get_bitrate_cck(plcp);
 	status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT);
-	status.mactime = mactime;
+
+	/*
+	 * If monitors are present get full 64-bit timestamp. This
+	 * code assumes we get to process the packet within 16 bits
+	 * of timestamp, i.e. about 65 milliseconds after the PHY
+	 * received the first symbol.
+	 */
+	if (dev->wl->radiotap_enabled) {
+		u16 low_mactime_now;
+
+		b43legacy_tsf_read(dev, &status.mactime);
+		low_mactime_now = status.mactime;
+		status.mactime = status.mactime & ~0xFFFFULL;
+		status.mactime += mactime;
+		if (low_mactime_now <= mactime)
+			status.mactime -= 0x10000;
+		status.flag |= RX_FLAG_TSFT;
+	}
 
 	chanid = (chanstat & B43legacy_RX_CHAN_ID) >>
 		  B43legacy_RX_CHAN_ID_SHIFT;
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig
index ce397e4284f4..0159701e8456 100644
--- a/drivers/net/wireless/bcm43xx/Kconfig
+++ b/drivers/net/wireless/bcm43xx/Kconfig
@@ -1,12 +1,15 @@
 config BCM43XX
-	tristate "Broadcom BCM43xx wireless support"
+	tristate "Broadcom BCM43xx wireless support (DEPRECATED)"
 	depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL
 	select WIRELESS_EXT
 	select FW_LOADER
 	select HW_RANDOM
 	---help---
-	  This is an experimental driver for the Broadcom 43xx wireless chip,
-	  found in the Apple Airport Extreme and various other devices.
+	  This is an experimental driver for the Broadcom 43xx wireless
+	  chip, found in the Apple Airport Extreme and various other
+	  devices.  This driver is deprecated and will be removed
+	  from the kernel in the near future.  It has been replaced
+	  by the b43 and b43legacy drivers.
 
 config BCM43XX_DEBUG
 	bool "Broadcom BCM43xx debugging (RECOMMENDED)"
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 5fdbf24d2443..2ebd2edf5862 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -481,9 +481,9 @@ struct bcm43xx_dmaring;
 struct bcm43xx_pioqueue;
 
 struct bcm43xx_initval {
-	u16 offset;
-	u16 size;
-	u32 value;
+	__be16 offset;
+	__be16 size;
+	__be32 value;
 } __attribute__((__packed__));
 
 /* Values for bcm430x_sprominfo.locale */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 45683437a98d..b96a325b6ec8 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -793,27 +793,27 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
 
 	/* il0macaddr */
 	value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];
-	*(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
+	*(((__be16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);
 	value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];
-	*(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
+	*(((__be16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);
 	value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];
-	*(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
+	*(((__be16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);
 
 	/* et0macaddr */
 	value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];
-	*(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
+	*(((__be16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);
 	value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];
-	*(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
+	*(((__be16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);
 	value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];
-	*(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
+	*(((__be16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);
 
 	/* et1macaddr */
 	value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];
-	*(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
+	*(((__be16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);
 	value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];
-	*(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
+	*(((__be16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);
 	value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];
-	*(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
+	*(((__be16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);
 
 	/* ethernet phy settings */
 	value = sprom[BCM43xx_SPROM_ETHPHY];
@@ -1059,7 +1059,7 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm)
 }
 
 static void key_write(struct bcm43xx_private *bcm,
-		      u8 index, u8 algorithm, const u16 *key)
+		      u8 index, u8 algorithm, const __le16 *key)
 {
 	unsigned int i, basic_wep = 0;
 	u32 offset;
@@ -1077,7 +1077,7 @@ static void key_write(struct bcm43xx_private *bcm,
 	/* Write key payload, 8 little endian words */
 	offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE);
 	for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) {
-		value = cpu_to_le16(key[i]);
+		value = le16_to_cpu(key[i]);
 		bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
 				    offset + (i * 2), value);
  
@@ -1091,7 +1091,7 @@ static void key_write(struct bcm43xx_private *bcm,
 }
 
 static void keymac_write(struct bcm43xx_private *bcm,
-			 u8 index, const u32 *addr)
+			 u8 index, const __be32 *addr)
 {
 	/* for keys 0-3 there is no associated mac address */
 	if (index < 4)
@@ -1102,11 +1102,11 @@ static void keymac_write(struct bcm43xx_private *bcm,
 		bcm43xx_shm_write32(bcm,
 				    BCM43xx_SHM_HWMAC,
 				    index * 2,
-				    cpu_to_be32(*addr));
+				    be32_to_cpu(*addr));
 		bcm43xx_shm_write16(bcm,
 				    BCM43xx_SHM_HWMAC,
 				    (index * 2) + 1,
-				    cpu_to_be16(*((u16 *)(addr + 1))));
+				    be16_to_cpu(*((__be16 *)(addr + 1))));
 	} else {
 		if (index < 8) {
 			TODO(); /* Put them in the macaddress filter */
@@ -1133,8 +1133,8 @@ static int bcm43xx_key_write(struct bcm43xx_private *bcm,
 		return -EINVAL;
 
 	memcpy(key, _key, key_len);
-	key_write(bcm, index, algorithm, (const u16 *)key);
-	keymac_write(bcm, index, (const u32 *)mac_addr);
+	key_write(bcm, index, algorithm, (const __le16 *)key);
+	keymac_write(bcm, index, (const __be32 *)mac_addr);
 
 	bcm->key[index].algorithm = algorithm;
 
@@ -1143,7 +1143,7 @@ static int bcm43xx_key_write(struct bcm43xx_private *bcm,
 
 static void bcm43xx_clear_keys(struct bcm43xx_private *bcm)
 {
-	static const u32 zero_mac[2] = { 0 };
+	static const __be32 zero_mac[2] = { 0 };
 	unsigned int i,j, nr_keys = 54;
 	u16 offset;
 
@@ -2011,11 +2011,11 @@ err_noinitval:
 static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
 {
 	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
-	const u32 *data;
+	const __be32 *data;
 	unsigned int i, len;
 
 	/* Upload Microcode. */
-	data = (u32 *)(phy->ucode->data);
+	data = (__be32 *)(phy->ucode->data);
 	len = phy->ucode->size / sizeof(u32);
 	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
 	for (i = 0; i < len; i++) {
@@ -2025,7 +2025,7 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
 	}
 
 	/* Upload PCM data. */
-	data = (u32 *)(phy->pcm->data);
+	data = (__be32 *)(phy->pcm->data);
 	len = phy->pcm->size / sizeof(u32);
 	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
 	bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index c60c1743ea06..76ab109cd2db 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -68,7 +68,7 @@ static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr,
 		source = packet;
 		i -= sizeof(*txhdr);
 	}
-	ret = le16_to_cpu( *((u16 *)(source + i)) );
+	ret = le16_to_cpu( *((__le16 *)(source + i)) );
 	*pos += 2;
 
 	return ret;
@@ -526,7 +526,7 @@ static void pio_rx_error(struct bcm43xx_pioqueue *queue,
 
 void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)
 {
-	u16 preamble[21] = { 0 };
+	__le16 preamble[21] = { 0 };
 	struct bcm43xx_rxhdr *rxhdr;
 	u16 tmp, len, rxflags2;
 	int i, preamble_readwords;
@@ -601,7 +601,7 @@ data_ready:
 	skb_put(skb, len);
 	for (i = 0; i < len - 1; i += 2) {
 		tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
-		*((u16 *)(skb->data + i)) = cpu_to_le16(tmp);
+		*((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
 	}
 	if (len % 2) {
 		tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index 3e2462671690..f79fe11f9e81 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -122,10 +122,10 @@ static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
 	__u8 *raw = plcp->raw;
 
 	if (ofdm_modulation) {
-		*data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
+		u32 val = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
 		assert(!(octets & 0xF000));
-		*data |= (octets << 5);
-		*data = cpu_to_le32(*data);
+		val |= (octets << 5);
+		*data = cpu_to_le32(val);
 	} else {
 		u32 plen;
 
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
index cc1ee7f4f5f8..d6b9362a3d5c 100644
--- a/drivers/net/wireless/hostap/hostap_80211.h
+++ b/drivers/net/wireless/hostap/hostap_80211.h
@@ -5,52 +5,52 @@
 #include <net/ieee80211_crypt.h>
 
 struct hostap_ieee80211_mgmt {
-	u16 frame_control;
-	u16 duration;
+	__le16 frame_control;
+	__le16 duration;
 	u8 da[6];
 	u8 sa[6];
 	u8 bssid[6];
-	u16 seq_ctrl;
+	__le16 seq_ctrl;
 	union {
 		struct {
-			u16 auth_alg;
-			u16 auth_transaction;
-			u16 status_code;
+			__le16 auth_alg;
+			__le16 auth_transaction;
+			__le16 status_code;
 			/* possibly followed by Challenge text */
 			u8 variable[0];
 		} __attribute__ ((packed)) auth;
 		struct {
-			u16 reason_code;
+			__le16 reason_code;
 		} __attribute__ ((packed)) deauth;
 		struct {
-			u16 capab_info;
-			u16 listen_interval;
+			__le16 capab_info;
+			__le16 listen_interval;
 			/* followed by SSID and Supported rates */
 			u8 variable[0];
 		} __attribute__ ((packed)) assoc_req;
 		struct {
-			u16 capab_info;
-			u16 status_code;
-			u16 aid;
+			__le16 capab_info;
+			__le16 status_code;
+			__le16 aid;
 			/* followed by Supported rates */
 			u8 variable[0];
 		} __attribute__ ((packed)) assoc_resp, reassoc_resp;
 		struct {
-			u16 capab_info;
-			u16 listen_interval;
+			__le16 capab_info;
+			__le16 listen_interval;
 			u8 current_ap[6];
 			/* followed by SSID and Supported rates */
 			u8 variable[0];
 		} __attribute__ ((packed)) reassoc_req;
 		struct {
-			u16 reason_code;
+			__le16 reason_code;
 		} __attribute__ ((packed)) disassoc;
 		struct {
 		} __attribute__ ((packed)) probe_req;
 		struct {
 			u8 timestamp[8];
-			u16 beacon_int;
-			u16 capab_info;
+			__le16 beacon_int;
+			__le16 capab_info;
 			/* followed by some of SSID, Supported rates,
 			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
 			u8 variable[0];
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index ef084df3d48e..49978bdb4324 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -1039,7 +1039,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
 		memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
 		memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
 	} else {
-		u16 len;
+		__be16 len;
 		/* Leave Ethernet header part of hdr and full payload */
 		skb_pull(skb, hdrlen);
 		len = htons(skb->len);
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 6bbdb76b32df..ad040a3bb8a7 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -258,7 +258,7 @@ static void ap_handle_timer(unsigned long data)
 				 sta->addr, ap->tx_callback_poll);
 	} else {
 		int deauth = sta->timeout_next == STA_DEAUTH;
-		u16 resp;
+		__le16 resp;
 		PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s"
 		       "(last=%lu, jiffies=%lu)\n",
 		       local->dev->name,
@@ -300,13 +300,13 @@ void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
 			    int resend)
 {
 	u8 addr[ETH_ALEN];
-	u16 resp;
+	__le16 resp;
 	int i;
 
 	PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name);
 	memset(addr, 0xff, ETH_ALEN);
 
-	resp = __constant_cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+	resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
 
 	/* deauth message sent; try to resend it few times; the message is
 	 * broadcast, so it may be delayed until next DTIM; there is not much
@@ -462,7 +462,7 @@ void ap_control_flush_macs(struct mac_restrictions *mac_restrictions)
 int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac)
 {
 	struct sta_info *sta;
-	u16 resp;
+	__le16 resp;
 
 	spin_lock_bh(&ap->sta_table_lock);
 	sta = ap_get_sta(ap, mac);
@@ -628,7 +628,8 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
 	struct ap_data *ap = data;
 	struct net_device *dev = ap->local->dev;
 	struct ieee80211_hdr_4addr *hdr;
-	u16 fc, *pos, auth_alg, auth_transaction, status;
+	u16 fc, auth_alg, auth_transaction, status;
+	__le16 *pos;
 	struct sta_info *sta = NULL;
 	char *txt = NULL;
 	DECLARE_MAC_BUF(mac);
@@ -649,7 +650,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
 		return;
 	}
 
-	pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+	pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
 	auth_alg = le16_to_cpu(*pos++);
 	auth_transaction = le16_to_cpu(*pos++);
 	status = le16_to_cpu(*pos++);
@@ -698,7 +699,8 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
 	struct ap_data *ap = data;
 	struct net_device *dev = ap->local->dev;
 	struct ieee80211_hdr_4addr *hdr;
-	u16 fc, *pos, status;
+	u16 fc, status;
+	__le16 *pos;
 	struct sta_info *sta = NULL;
 	char *txt = NULL;
 	DECLARE_MAC_BUF(mac);
@@ -736,7 +738,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
 		goto done;
 	}
 
-	pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+	pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
 	pos++;
 	status = le16_to_cpu(*pos++);
 	if (status == WLAN_STATUS_SUCCESS) {
@@ -1298,7 +1300,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
 	struct ap_data *ap = local->ap;
 	char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL;
 	int len, olen;
-	u16 auth_alg, auth_transaction, status_code, *pos;
+	u16 auth_alg, auth_transaction, status_code;
+	__le16 *pos;
 	u16 resp = WLAN_STATUS_SUCCESS, fc;
 	struct sta_info *sta = NULL;
 	struct ieee80211_crypt_data *crypt;
@@ -1332,7 +1335,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
 		crypt = local->crypt[idx];
 	}
 
-	pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+	pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
 	auth_alg = __le16_to_cpu(*pos);
 	pos++;
 	auth_transaction = __le16_to_cpu(*pos);
@@ -1465,7 +1468,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
 	}
 
  fail:
-	pos = (u16 *) body;
+	pos = (__le16 *) body;
 	*pos = cpu_to_le16(auth_alg);
 	pos++;
 	*pos = cpu_to_le16(auth_transaction + 1);
@@ -1510,7 +1513,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
 	struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
 	char body[12], *p, *lpos;
 	int len, left;
-	u16 *pos;
+	__le16 *pos;
 	u16 resp = WLAN_STATUS_SUCCESS;
 	struct sta_info *sta = NULL;
 	int send_deauth = 0;
@@ -1540,7 +1543,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
 	atomic_inc(&sta->users);
 	spin_unlock_bh(&local->ap->sta_table_lock);
 
-	pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
+	pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
 	sta->capability = __le16_to_cpu(*pos);
 	pos++; left -= 2;
 	sta->listen_interval = __le16_to_cpu(*pos);
@@ -1636,25 +1639,24 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
 	}
 
  fail:
-	pos = (u16 *) body;
+	pos = (__le16 *) body;
 
 	if (send_deauth) {
-		*pos = __constant_cpu_to_le16(
-			WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH);
+		*pos = cpu_to_le16(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH);
 		pos++;
 	} else {
 		/* FIX: CF-Pollable and CF-PollReq should be set to match the
 		 * values in beacons/probe responses */
 		/* FIX: how about privacy and WEP? */
 		/* capability */
-		*pos = __constant_cpu_to_le16(WLAN_CAPABILITY_ESS);
+		*pos = cpu_to_le16(WLAN_CAPABILITY_ESS);
 		pos++;
 
 		/* status_code */
-		*pos = __cpu_to_le16(resp);
+		*pos = cpu_to_le16(resp);
 		pos++;
 
-		*pos = __cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) |
+		*pos = cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) |
 				     BIT(14) | BIT(15)); /* AID */
 		pos++;
 
@@ -1681,7 +1683,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
 				0x96 : 0x16;
 			(*lpos)++;
 		}
-		pos = (u16 *) p;
+		pos = (__le16 *) p;
 	}
 
 	prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
@@ -1718,7 +1720,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
 	struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
 	char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN);
 	int len;
-	u16 reason_code, *pos;
+	u16 reason_code;
+	__le16 *pos;
 	struct sta_info *sta = NULL;
 	DECLARE_MAC_BUF(mac);
 
@@ -1729,8 +1732,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
 		return;
 	}
 
-	pos = (u16 *) body;
-	reason_code = __le16_to_cpu(*pos);
+	pos = (__le16 *) body;
+	reason_code = le16_to_cpu(*pos);
 
 	PDEBUG(DEBUG_AP, "%s: deauthentication: %s len=%d, "
 	       "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len,
@@ -1760,7 +1763,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
 	struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
 	char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
 	int len;
-	u16 reason_code, *pos;
+	u16 reason_code;
+	__le16 *pos;
 	struct sta_info *sta = NULL;
 	DECLARE_MAC_BUF(mac);
 
@@ -1771,8 +1775,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
 		return;
 	}
 
-	pos = (u16 *) body;
-	reason_code = __le16_to_cpu(*pos);
+	pos = (__le16 *) body;
+	reason_code = le16_to_cpu(*pos);
 
 	PDEBUG(DEBUG_AP, "%s: disassociation: %s len=%d, "
 	       "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len,
@@ -1817,7 +1821,7 @@ static void ap_handle_dropped_data(local_info_t *local,
 {
 	struct net_device *dev = local->dev;
 	struct sta_info *sta;
-	u16 reason;
+	__le16 reason;
 
 	spin_lock_bh(&local->ap->sta_table_lock);
 	sta = ap_get_sta(local->ap, hdr->addr2);
@@ -1831,8 +1835,7 @@ static void ap_handle_dropped_data(local_info_t *local,
 		return;
 	}
 
-	reason = __constant_cpu_to_le16(
-		WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+	reason = cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
 	prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
 			 ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ?
 			  IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC),
@@ -1892,7 +1895,7 @@ static void handle_pspoll(local_info_t *local,
 		return;
 	}
 
-	aid = __le16_to_cpu(hdr->duration_id);
+	aid = le16_to_cpu(hdr->duration_id);
 	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) {
 		PDEBUG(DEBUG_PS, "   PSPOLL and AID[15:14] not set\n");
 		return;
@@ -1998,7 +2001,8 @@ static void handle_beacon(local_info_t *local, struct sk_buff *skb,
 	struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
 	char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
 	int len, left;
-	u16 *pos, beacon_int, capability;
+	u16 beacon_int, capability;
+	__le16 *pos;
 	char *ssid = NULL;
 	unsigned char *supp_rates = NULL;
 	int ssid_len = 0, supp_rates_len = 0;
@@ -2013,16 +2017,16 @@ static void handle_beacon(local_info_t *local, struct sk_buff *skb,
 		return;
 	}
 
-	pos = (u16 *) body;
+	pos = (__le16 *) body;
 	left = len;
 
 	/* Timestamp (8 octets) */
 	pos += 4; left -= 8;
 	/* Beacon interval (2 octets) */
-	beacon_int = __le16_to_cpu(*pos);
+	beacon_int = le16_to_cpu(*pos);
 	pos++; left -= 2;
 	/* Capability information (2 octets) */
-	capability = __le16_to_cpu(*pos);
+	capability = le16_to_cpu(*pos);
 	pos++; left -= 2;
 
 	if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS &&
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index 517f89845144..b470c743c2d1 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -188,10 +188,10 @@
 
 struct hfa384x_comp_ident
 {
-	u16 id;
-	u16 variant;
-	u16 major;
-	u16 minor;
+	__le16 id;
+	__le16 variant;
+	__le16 major;
+	__le16 minor;
 } __attribute__ ((packed));
 
 #define HFA384X_COMP_ID_PRI 0x15
@@ -200,33 +200,33 @@ struct hfa384x_comp_ident
 
 struct hfa384x_sup_range
 {
-	u16 role;
-	u16 id;
-	u16 variant;
-	u16 bottom;
-	u16 top;
+	__le16 role;
+	__le16 id;
+	__le16 variant;
+	__le16 bottom;
+	__le16 top;
 } __attribute__ ((packed));
 
 
 struct hfa384x_build_id
 {
-	u16 pri_seq;
-	u16 sec_seq;
+	__le16 pri_seq;
+	__le16 sec_seq;
 } __attribute__ ((packed));
 
 /* FD01 - Download Buffer */
 struct hfa384x_rid_download_buffer
 {
-	u16 page;
-	u16 offset;
-	u16 length;
+	__le16 page;
+	__le16 offset;
+	__le16 length;
 } __attribute__ ((packed));
 
 /* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
 struct hfa384x_comms_quality {
-	u16 comm_qual; /* 0 .. 92 */
-	u16 signal_level; /* 27 .. 154 */
-	u16 noise_level; /* 27 .. 154 */
+	__le16 comm_qual; /* 0 .. 92 */
+	__le16 signal_level; /* 27 .. 154 */
+	__le16 noise_level; /* 27 .. 154 */
 } __attribute__ ((packed));
 
 
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 877d3bdd37a0..07593803065a 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -845,15 +845,13 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
 					 0x4b801a17),
 	PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
 				    0x7a954bd9, 0x74be00c6),
-	PCMCIA_DEVICE_PROD_ID1234(
+	PCMCIA_DEVICE_PROD_ID123(
 		"Intersil", "PRISM 2_5 PCMCIA ADAPTER",	"ISL37300P",
-		"Eval-RevA",
-		0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e),
+		0x4b801a17, 0x6345a0bf, 0xc9049a39),
 	/* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */
-	PCMCIA_DEVICE_PROD_ID1234(
+	PCMCIA_DEVICE_PROD_ID123(
 		"D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10",
-		"A3",
-		0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52),
+		0x1a424a1c, 0x6ea57632, 0xdd97a26b),
 	PCMCIA_DEVICE_PROD_ID123(
 		"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
 		0xe6ec52ce, 0x08649af2, 0x4b74baa0),
@@ -890,10 +888,9 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
 	PCMCIA_DEVICE_PROD_ID123(
 		"corega", "WL PCCL-11", "ISL37300P",
 		0xa21501a, 0x59868926, 0xc9049a39),
-	PCMCIA_DEVICE_PROD_ID1234(
+	PCMCIA_DEVICE_PROD_ID123(
 		"The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P",
-		"RevA",
-		0xa5f472c2, 0x9c05598d, 0xc9049a39, 0x57a66194),
+		0xa5f472c2, 0x9c05598d, 0xc9049a39),
 	PCMCIA_DEVICE_NULL
 };
 MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
diff --git a/drivers/net/wireless/hostap/hostap_download.c b/drivers/net/wireless/hostap/hostap_download.c
index c7678e67697d..89d3849abfe0 100644
--- a/drivers/net/wireless/hostap/hostap_download.c
+++ b/drivers/net/wireless/hostap/hostap_download.c
@@ -100,7 +100,7 @@ static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
 
 #ifdef PRISM2_PCI
 	{
-		u16 *pos = (u16 *) buf;
+		__le16 *pos = (__le16 *) buf;
 		while (len > 0) {
 			*pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
 			len -= 2;
@@ -131,7 +131,7 @@ static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
 
 #ifdef PRISM2_PCI
 	{
-		u16 *pos = (u16 *) buf;
+		__le16 *pos = (__le16 *) buf;
 		while (len > 0) {
 			HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
 			len -= 2;
@@ -147,7 +147,7 @@ static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
 
 static int prism2_pda_ok(u8 *buf)
 {
-	u16 *pda = (u16 *) buf;
+	__le16 *pda = (__le16 *) buf;
 	int pos;
 	u16 len, pdr;
 
@@ -544,9 +544,9 @@ static int prism2_download_nonvolatile(local_info_t *local,
 	struct net_device *dev = local->dev;
 	int ret = 0, i;
 	struct {
-		u16 page;
-		u16 offset;
-		u16 len;
+		__le16 page;
+		__le16 offset;
+		__le16 len;
 	} dlbuffer;
 	u32 bufaddr;
 
@@ -565,14 +565,12 @@ static int prism2_download_nonvolatile(local_info_t *local,
 		goto out;
 	}
 
-	dlbuffer.page = le16_to_cpu(dlbuffer.page);
-	dlbuffer.offset = le16_to_cpu(dlbuffer.offset);
-	dlbuffer.len = le16_to_cpu(dlbuffer.len);
-
 	printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
-	       dlbuffer.len, dlbuffer.page, dlbuffer.offset);
+	       le16_to_cpu(dlbuffer.len),
+	       le16_to_cpu(dlbuffer.page),
+	       le16_to_cpu(dlbuffer.offset));
 
-	bufaddr = (dlbuffer.page << 7) + dlbuffer.offset;
+	bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset);
 
 	local->hw_downloading = 1;
 
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index c592641e914e..7be68db6f300 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -1075,7 +1075,7 @@ static int prism2_setup_rids(struct net_device *dev)
 {
 	struct hostap_interface *iface;
 	local_info_t *local;
-	u16 tmp;
+	__le16 tmp;
 	int ret = 0;
 
 	iface = netdev_priv(dev);
@@ -1084,11 +1084,11 @@ static int prism2_setup_rids(struct net_device *dev)
 	hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000);
 
 	if (!local->fw_ap) {
-		tmp = hostap_get_porttype(local);
-		ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp);
+		u16 tmp1 = hostap_get_porttype(local);
+		ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp1);
 		if (ret) {
 			printk("%s: Port type setting to %d failed\n",
-			       dev->name, tmp);
+			       dev->name, tmp1);
 			goto fail;
 		}
 	}
@@ -1117,7 +1117,7 @@ static int prism2_setup_rids(struct net_device *dev)
 		ret = -EINVAL;
 		goto fail;
 	}
-	local->channel_mask = __le16_to_cpu(tmp);
+	local->channel_mask = le16_to_cpu(tmp);
 
 	if (local->channel < 1 || local->channel > 14 ||
 	    !(local->channel_mask & (1 << (local->channel - 1)))) {
@@ -1852,7 +1852,7 @@ static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev)
 	tx_control = local->tx_control;
 	if (meta->tx_cb_idx) {
 		tx_control |= HFA384X_TX_CTRL_TX_OK;
-		txdesc.sw_support = cpu_to_le16(meta->tx_cb_idx);
+		txdesc.sw_support = cpu_to_le32(meta->tx_cb_idx);
 	}
 	txdesc.tx_control = cpu_to_le16(tx_control);
 	txdesc.tx_rate = meta->rate;
@@ -2190,7 +2190,7 @@ static void hostap_tx_callback(local_info_t *local,
 		return;
 	}
 
-	sw_support = le16_to_cpu(txdesc->sw_support);
+	sw_support = le32_to_cpu(txdesc->sw_support);
 
 	spin_lock(&local->lock);
 	cb = local->tx_callback;
@@ -2448,18 +2448,16 @@ static void prism2_info(local_info_t *local)
 		goto out;
 	}
 
-	le16_to_cpus(&info.len);
-	le16_to_cpus(&info.type);
-	left = (info.len - 1) * 2;
+	left = (le16_to_cpu(info.len) - 1) * 2;
 
-	if (info.len & 0x8000 || info.len == 0 || left > 2060) {
+	if (info.len & cpu_to_le16(0x8000) || info.len == 0 || left > 2060) {
 		/* data register seems to give 0x8000 in some error cases even
 		 * though busy bit is not set in offset register;
 		 * in addition, length must be at least 1 due to type field */
 		spin_unlock(&local->baplock);
 		printk(KERN_DEBUG "%s: Received info frame with invalid "
-		       "length 0x%04x (type 0x%04x)\n", dev->name, info.len,
-		       info.type);
+		       "length 0x%04x (type 0x%04x)\n", dev->name,
+		       le16_to_cpu(info.len), le16_to_cpu(info.type));
 		goto out;
 	}
 
@@ -2476,8 +2474,8 @@ static void prism2_info(local_info_t *local)
 	{
 		spin_unlock(&local->baplock);
 		printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, "
-		       "len=0x%04x, type=0x%04x\n",
-		       dev->name, fid, info.len, info.type);
+		       "len=0x%04x, type=0x%04x\n", dev->name, fid,
+		       le16_to_cpu(info.len), le16_to_cpu(info.type));
 		dev_kfree_skb(skb);
 		goto out;
 	}
@@ -2624,7 +2622,7 @@ static void prism2_check_magic(local_info_t *local)
 /* Called only from hardware IRQ */
 static irqreturn_t prism2_interrupt(int irq, void *dev_id)
 {
-	struct net_device *dev = (struct net_device *) dev_id;
+	struct net_device *dev = dev_id;
 	struct hostap_interface *iface;
 	local_info_t *local;
 	int events = 0;
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c
index 636f4b2382ea..7cd3fb79230e 100644
--- a/drivers/net/wireless/hostap/hostap_info.c
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -303,7 +303,7 @@ static void prism2_info_hostscanresults(local_info_t *local,
 	int i, result_size, copy_len, new_count;
 	struct hfa384x_hostscan_result *results, *prev;
 	unsigned long flags;
-	u16 *pos;
+	__le16 *pos;
 	u8 *ptr;
 
 	wake_up_interruptible(&local->hostscan_wq);
@@ -314,7 +314,7 @@ static void prism2_info_hostscanresults(local_info_t *local,
 		return;
 	}
 
-	pos = (u16 *) buf;
+	pos = (__le16 *) buf;
 	copy_len = result_size = le16_to_cpu(*pos);
 	if (result_size == 0) {
 		printk(KERN_DEBUG "%s: invalid result_size (0) in "
@@ -373,7 +373,7 @@ void hostap_info_process(local_info_t *local, struct sk_buff *skb)
 	buf = skb->data + sizeof(*info);
 	left = skb->len - sizeof(*info);
 
-	switch (info->type) {
+	switch (le16_to_cpu(info->type)) {
 	case HFA384X_INFO_COMMTALLIES:
 		prism2_info_commtallies(local, buf, left);
 		break;
@@ -395,7 +395,8 @@ void hostap_info_process(local_info_t *local, struct sk_buff *skb)
 #ifndef PRISM2_NO_DEBUG
 	default:
 		PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n",
-		       local->dev->name, info->len, info->type);
+		       local->dev->name, le16_to_cpu(info->len),
+		       le16_to_cpu(info->type));
 		PDEBUG(DEBUG_EXTRA, "Unknown info frame:");
 		for (i = 0; i < (left < 100 ? left : 100); i++)
 			PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]);
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index d8f5efcfcab9..0ca0bfeb0ada 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -84,7 +84,7 @@ static int prism2_get_datarates(struct net_device *dev, u8 *rates)
 	if (len < 2)
 		return 0;
 
-	val = le16_to_cpu(*(u16 *) buf); /* string length */
+	val = le16_to_cpu(*(__le16 *) buf); /* string length */
 
 	if (len - 2 < val || val > 10)
 		return 0;
@@ -496,7 +496,7 @@ static int prism2_ioctl_giwsens(struct net_device *dev,
 {
 	struct hostap_interface *iface;
 	local_info_t *local;
-	u16 val;
+	__le16 val;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -506,7 +506,7 @@ static int prism2_ioctl_giwsens(struct net_device *dev,
 	    0)
 		return -EINVAL;
 
-	sens->value = __le16_to_cpu(val);
+	sens->value = le16_to_cpu(val);
 	sens->fixed = 1;
 
 	return 0;
@@ -561,17 +561,17 @@ static int prism2_ioctl_siwrts(struct net_device *dev,
 {
 	struct hostap_interface *iface;
 	local_info_t *local;
-	u16 val;
+	__le16 val;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
 
 	if (rts->disabled)
-		val = __constant_cpu_to_le16(2347);
+		val = cpu_to_le16(2347);
 	else if (rts->value < 0 || rts->value > 2347)
 		return -EINVAL;
 	else
-		val = __cpu_to_le16(rts->value);
+		val = cpu_to_le16(rts->value);
 
 	if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) ||
 	    local->func->reset_port(dev))
@@ -588,7 +588,7 @@ static int prism2_ioctl_giwrts(struct net_device *dev,
 {
 	struct hostap_interface *iface;
 	local_info_t *local;
-	u16 val;
+	__le16 val;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -597,7 +597,7 @@ static int prism2_ioctl_giwrts(struct net_device *dev,
 	    0)
 		return -EINVAL;
 
-	rts->value = __le16_to_cpu(val);
+	rts->value = le16_to_cpu(val);
 	rts->disabled = (rts->value == 2347);
 	rts->fixed = 1;
 
@@ -611,17 +611,17 @@ static int prism2_ioctl_siwfrag(struct net_device *dev,
 {
 	struct hostap_interface *iface;
 	local_info_t *local;
-	u16 val;
+	__le16 val;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
 
 	if (rts->disabled)
-		val = __constant_cpu_to_le16(2346);
+		val = cpu_to_le16(2346);
 	else if (rts->value < 256 || rts->value > 2346)
 		return -EINVAL;
 	else
-		val = __cpu_to_le16(rts->value & ~0x1); /* even numbers only */
+		val = cpu_to_le16(rts->value & ~0x1); /* even numbers only */
 
 	local->fragm_threshold = rts->value & ~0x1;
 	if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val,
@@ -638,7 +638,7 @@ static int prism2_ioctl_giwfrag(struct net_device *dev,
 {
 	struct hostap_interface *iface;
 	local_info_t *local;
-	u16 val;
+	__le16 val;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -647,7 +647,7 @@ static int prism2_ioctl_giwfrag(struct net_device *dev,
 				 &val, 2, 1) < 0)
 		return -EINVAL;
 
-	rts->value = __le16_to_cpu(val);
+	rts->value = le16_to_cpu(val);
 	rts->disabled = (rts->value == 2346);
 	rts->fixed = 1;
 
@@ -718,8 +718,8 @@ static int prism2_ioctl_siwap(struct net_device *dev,
 	if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) {
 		struct hfa384x_scan_request scan_req;
 		memset(&scan_req, 0, sizeof(scan_req));
-		scan_req.channel_list = __constant_cpu_to_le16(0x3fff);
-		scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS);
+		scan_req.channel_list = cpu_to_le16(0x3fff);
+		scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS);
 		if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST,
 					 &scan_req, sizeof(scan_req))) {
 			printk(KERN_DEBUG "%s: ScanResults request failed - "
@@ -812,7 +812,7 @@ static int prism2_ioctl_giwnickn(struct net_device *dev,
 
 	len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME,
 				   &name, MAX_NAME_LEN + 2, 0);
-	val = __le16_to_cpu(*(u16 *) name);
+	val = le16_to_cpu(*(__le16 *) name);
 	if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN)
 		return -EOPNOTSUPP;
 
@@ -963,7 +963,7 @@ static int prism2_ioctl_giwessid(struct net_device *dev,
 		memset(ssid, 0, sizeof(ssid));
 		len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID,
 					   &ssid, MAX_SSID_LEN + 2, 0);
-		val = __le16_to_cpu(*(u16 *) ssid);
+		val = le16_to_cpu(*(__le16 *) ssid);
 		if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) {
 			return -EOPNOTSUPP;
 		}
@@ -1089,6 +1089,9 @@ static int prism2_ioctl_giwrange(struct net_device *dev,
 	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
 		IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
 
+	if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1))
+		range->scan_capa = IW_SCAN_CAPA_ESSID;
+
 	return 0;
 }
 
@@ -1316,7 +1319,7 @@ static int prism2_ioctl_giwpower(struct net_device *dev,
 #else /* PRISM2_NO_STATION_MODES */
 	struct hostap_interface *iface;
 	local_info_t *local;
-	u16 enable, mcast;
+	__le16 enable, mcast;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -1325,7 +1328,7 @@ static int prism2_ioctl_giwpower(struct net_device *dev,
 	    < 0)
 		return -EINVAL;
 
-	if (!__le16_to_cpu(enable)) {
+	if (!le16_to_cpu(enable)) {
 		rrq->disabled = 1;
 		return 0;
 	}
@@ -1333,29 +1336,29 @@ static int prism2_ioctl_giwpower(struct net_device *dev,
 	rrq->disabled = 0;
 
 	if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-		u16 timeout;
+		__le16 timeout;
 		if (local->func->get_rid(dev,
 					 HFA384X_RID_CNFPMHOLDOVERDURATION,
 					 &timeout, 2, 1) < 0)
 			return -EINVAL;
 
 		rrq->flags = IW_POWER_TIMEOUT;
-		rrq->value = __le16_to_cpu(timeout) * 1024;
+		rrq->value = le16_to_cpu(timeout) * 1024;
 	} else {
-		u16 period;
+		__le16 period;
 		if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
 					 &period, 2, 1) < 0)
 			return -EINVAL;
 
 		rrq->flags = IW_POWER_PERIOD;
-		rrq->value = __le16_to_cpu(period) * 1024;
+		rrq->value = le16_to_cpu(period) * 1024;
 	}
 
 	if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast,
 				 2, 1) < 0)
 		return -EINVAL;
 
-	if (__le16_to_cpu(mcast))
+	if (le16_to_cpu(mcast))
 		rrq->flags |= IW_POWER_ALL_R;
 	else
 		rrq->flags |= IW_POWER_UNICAST_R;
@@ -1432,7 +1435,7 @@ static int prism2_ioctl_giwretry(struct net_device *dev,
 {
 	struct hostap_interface *iface;
 	local_info_t *local;
-	u16 shortretry, longretry, lifetime, altretry;
+	__le16 shortretry, longretry, lifetime, altretry;
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -1445,15 +1448,11 @@ static int prism2_ioctl_giwretry(struct net_device *dev,
 				 &lifetime, 2, 1) < 0)
 		return -EINVAL;
 
-	le16_to_cpus(&shortretry);
-	le16_to_cpus(&longretry);
-	le16_to_cpus(&lifetime);
-
 	rrq->disabled = 0;
 
 	if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
 		rrq->flags = IW_RETRY_LIFETIME;
-		rrq->value = lifetime * 1024;
+		rrq->value = le16_to_cpu(lifetime) * 1024;
 	} else {
 		if (local->manual_retry_count >= 0) {
 			rrq->flags = IW_RETRY_LIMIT;
@@ -1465,10 +1464,10 @@ static int prism2_ioctl_giwretry(struct net_device *dev,
 				rrq->value = local->manual_retry_count;
 		} else if ((rrq->flags & IW_RETRY_LONG)) {
 			rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
-			rrq->value = longretry;
+			rrq->value = le16_to_cpu(longretry);
 		} else {
 			rrq->flags = IW_RETRY_LIMIT;
-			rrq->value = shortretry;
+			rrq->value = le16_to_cpu(shortretry);
 			if (shortretry != longretry)
 				rrq->flags |= IW_RETRY_SHORT;
 		}
@@ -3098,7 +3097,7 @@ static int prism2_set_genericelement(struct net_device *dev, u8 *elem,
 	if (buf == NULL)
 		return -ENOMEM;
 
-	*((u16 *) buf) = cpu_to_le16(len);
+	*((__le16 *) buf) = cpu_to_le16(len);
 	memcpy(buf + 2, elem, len);
 
 	kfree(local->generic_elem);
@@ -3758,7 +3757,7 @@ static int prism2_ioctl_siwmlme(struct net_device *dev,
 	struct hostap_interface *iface = netdev_priv(dev);
 	local_info_t *local = iface->local;
 	struct iw_mlme *mlme = (struct iw_mlme *) extra;
-	u16 reason;
+	__le16 reason;
 
 	reason = cpu_to_le16(mlme->reason_code);
 
@@ -3780,7 +3779,7 @@ static int prism2_ioctl_siwmlme(struct net_device *dev,
 static int prism2_ioctl_mlme(local_info_t *local,
 			     struct prism2_hostapd_param *param)
 {
-	u16 reason;
+	__le16 reason;
 
 	reason = cpu_to_le16(param->u.mlme.reason_code);
 	switch (param->u.mlme.cmd) {
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 17c58e9bdad5..20d387f6658c 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -296,7 +296,7 @@ int hostap_tx_callback_unregister(local_info_t *local, u16 idx)
 int hostap_set_word(struct net_device *dev, int rid, u16 val)
 {
 	struct hostap_interface *iface;
-	u16 tmp = cpu_to_le16(val);
+	__le16 tmp = cpu_to_le16(val);
 	iface = netdev_priv(dev);
 	return iface->local->func->set_rid(dev, rid, &tmp, 2);
 }
@@ -1095,15 +1095,15 @@ int prism2_sta_deauth(local_info_t *local, u16 reason)
 {
 	union iwreq_data wrqu;
 	int ret;
+	__le16 val = cpu_to_le16(reason);
 
 	if (local->iw_mode != IW_MODE_INFRA ||
 	    memcmp(local->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 ||
 	    memcmp(local->bssid, "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == 0)
 		return 0;
 
-	reason = cpu_to_le16(reason);
 	ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH,
-				   (u8 *) &reason, 2);
+				   (u8 *) &val, 2);
 	memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
 	wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
 	return ret;
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index fc876ba18572..3a874fc621d3 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -128,8 +128,8 @@ static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
 #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
 #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
 #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
-#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), cpu_to_le16((v)))
-#define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw_debug(dev, (a)))
+#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v)))
+#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a)))
 
 #else /* PRISM2_IO_DEBUG */
 
@@ -173,8 +173,8 @@ static inline u16 hfa384x_inw(struct net_device *dev, int a)
 #define HFA384X_INB(a) hfa384x_inb(dev, (a))
 #define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v))
 #define HFA384X_INW(a) hfa384x_inw(dev, (a))
-#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), cpu_to_le16((v)))
-#define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw(dev, (a)))
+#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v)))
+#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a)))
 
 #endif /* PRISM2_IO_DEBUG */
 
@@ -183,10 +183,10 @@ static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
 			    int len)
 {
 	u16 d_off;
-	u16 *pos;
+	__le16 *pos;
 
 	d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
-	pos = (u16 *) buf;
+	pos = (__le16 *) buf;
 
 	for ( ; len > 1; len -= 2)
 		*pos++ = HFA384X_INW_DATA(d_off);
@@ -201,10 +201,10 @@ static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
 static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
 {
 	u16 d_off;
-	u16 *pos;
+	__le16 *pos;
 
 	d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
-	pos = (u16 *) buf;
+	pos = (__le16 *) buf;
 
 	for ( ; len > 1; len -= 2)
 		HFA384X_OUTW_DATA(*pos++, d_off);
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index e6516a186d0e..15445bce2ac7 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -39,20 +39,20 @@ struct linux_wlan_ng_prism_hdr {
 } __attribute__ ((packed));
 
 struct linux_wlan_ng_cap_hdr {
-	u32 version;
-	u32 length;
-	u64 mactime;
-	u64 hosttime;
-	u32 phytype;
-	u32 channel;
-	u32 datarate;
-	u32 antenna;
-	u32 priority;
-	u32 ssi_type;
-	s32 ssi_signal;
-	s32 ssi_noise;
-	u32 preamble;
-	u32 encoding;
+	__be32 version;
+	__be32 length;
+	__be64 mactime;
+	__be64 hosttime;
+	__be32 phytype;
+	__be32 channel;
+	__be32 datarate;
+	__be32 antenna;
+	__be32 priority;
+	__be32 ssi_type;
+	__be32 ssi_signal;
+	__be32 ssi_noise;
+	__be32 preamble;
+	__be32 encoding;
 } __attribute__ ((packed));
 
 #define LWNG_CAP_DID_BASE   (4 | (1 << 6)) /* section 4, group 1 */
@@ -60,28 +60,28 @@ struct linux_wlan_ng_cap_hdr {
 
 struct hfa384x_rx_frame {
 	/* HFA384X RX frame descriptor */
-	u16 status; /* HFA384X_RX_STATUS_ flags */
-	u32 time; /* timestamp, 1 microsecond resolution */
+	__le16 status; /* HFA384X_RX_STATUS_ flags */
+	__le32 time; /* timestamp, 1 microsecond resolution */
 	u8 silence; /* 27 .. 154; seems to be 0 */
 	u8 signal; /* 27 .. 154 */
 	u8 rate; /* 10, 20, 55, or 110 */
 	u8 rxflow;
-	u32 reserved;
+	__le32 reserved;
 
 	/* 802.11 */
-	u16 frame_control;
-	u16 duration_id;
+	__le16 frame_control;
+	__le16 duration_id;
 	u8 addr1[6];
 	u8 addr2[6];
 	u8 addr3[6];
-	u16 seq_ctrl;
+	__le16 seq_ctrl;
 	u8 addr4[6];
-	u16 data_len;
+	__le16 data_len;
 
 	/* 802.3 */
 	u8 dst_addr[6];
 	u8 src_addr[6];
-	u16 len;
+	__be16 len;
 
 	/* followed by frame data; max 2304 bytes */
 } __attribute__ ((packed));
@@ -89,28 +89,28 @@ struct hfa384x_rx_frame {
 
 struct hfa384x_tx_frame {
 	/* HFA384X TX frame descriptor */
-	u16 status; /* HFA384X_TX_STATUS_ flags */
-	u16 reserved1;
-	u16 reserved2;
-	u32 sw_support;
+	__le16 status; /* HFA384X_TX_STATUS_ flags */
+	__le16 reserved1;
+	__le16 reserved2;
+	__le32 sw_support;
 	u8 retry_count; /* not yet implemented */
 	u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */
-	u16 tx_control; /* HFA384X_TX_CTRL_ flags */
+	__le16 tx_control; /* HFA384X_TX_CTRL_ flags */
 
 	/* 802.11 */
-	u16 frame_control; /* parts not used */
-	u16 duration_id;
+	__le16 frame_control; /* parts not used */
+	__le16 duration_id;
 	u8 addr1[6];
 	u8 addr2[6]; /* filled by firmware */
 	u8 addr3[6];
-	u16 seq_ctrl; /* filled by firmware */
+	__le16 seq_ctrl; /* filled by firmware */
 	u8 addr4[6];
-	u16 data_len;
+	__le16 data_len;
 
 	/* 802.3 */
 	u8 dst_addr[6];
 	u8 src_addr[6];
-	u16 len;
+	__be16 len;
 
 	/* followed by frame data; max 2304 bytes */
 } __attribute__ ((packed));
@@ -118,8 +118,8 @@ struct hfa384x_tx_frame {
 
 struct hfa384x_rid_hdr
 {
-	u16 len;
-	u16 rid;
+	__le16 len;
+	__le16 rid;
 } __attribute__ ((packed));
 
 
@@ -130,78 +130,78 @@ struct hfa384x_rid_hdr
 #define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100
 
 struct hfa384x_scan_request {
-	u16 channel_list;
-	u16 txrate; /* HFA384X_RATES_* */
+	__le16 channel_list;
+	__le16 txrate; /* HFA384X_RATES_* */
 } __attribute__ ((packed));
 
 struct hfa384x_hostscan_request {
-	u16 channel_list;
-	u16 txrate;
-	u16 target_ssid_len;
+	__le16 channel_list;
+	__le16 txrate;
+	__le16 target_ssid_len;
 	u8 target_ssid[32];
 } __attribute__ ((packed));
 
 struct hfa384x_join_request {
 	u8 bssid[6];
-	u16 channel;
+	__le16 channel;
 } __attribute__ ((packed));
 
 struct hfa384x_info_frame {
-	u16 len;
-	u16 type;
+	__le16 len;
+	__le16 type;
 } __attribute__ ((packed));
 
 struct hfa384x_comm_tallies {
-	u16 tx_unicast_frames;
-	u16 tx_multicast_frames;
-	u16 tx_fragments;
-	u16 tx_unicast_octets;
-	u16 tx_multicast_octets;
-	u16 tx_deferred_transmissions;
-	u16 tx_single_retry_frames;
-	u16 tx_multiple_retry_frames;
-	u16 tx_retry_limit_exceeded;
-	u16 tx_discards;
-	u16 rx_unicast_frames;
-	u16 rx_multicast_frames;
-	u16 rx_fragments;
-	u16 rx_unicast_octets;
-	u16 rx_multicast_octets;
-	u16 rx_fcs_errors;
-	u16 rx_discards_no_buffer;
-	u16 tx_discards_wrong_sa;
-	u16 rx_discards_wep_undecryptable;
-	u16 rx_message_in_msg_fragments;
-	u16 rx_message_in_bad_msg_fragments;
+	__le16 tx_unicast_frames;
+	__le16 tx_multicast_frames;
+	__le16 tx_fragments;
+	__le16 tx_unicast_octets;
+	__le16 tx_multicast_octets;
+	__le16 tx_deferred_transmissions;
+	__le16 tx_single_retry_frames;
+	__le16 tx_multiple_retry_frames;
+	__le16 tx_retry_limit_exceeded;
+	__le16 tx_discards;
+	__le16 rx_unicast_frames;
+	__le16 rx_multicast_frames;
+	__le16 rx_fragments;
+	__le16 rx_unicast_octets;
+	__le16 rx_multicast_octets;
+	__le16 rx_fcs_errors;
+	__le16 rx_discards_no_buffer;
+	__le16 tx_discards_wrong_sa;
+	__le16 rx_discards_wep_undecryptable;
+	__le16 rx_message_in_msg_fragments;
+	__le16 rx_message_in_bad_msg_fragments;
 } __attribute__ ((packed));
 
 struct hfa384x_comm_tallies32 {
-	u32 tx_unicast_frames;
-	u32 tx_multicast_frames;
-	u32 tx_fragments;
-	u32 tx_unicast_octets;
-	u32 tx_multicast_octets;
-	u32 tx_deferred_transmissions;
-	u32 tx_single_retry_frames;
-	u32 tx_multiple_retry_frames;
-	u32 tx_retry_limit_exceeded;
-	u32 tx_discards;
-	u32 rx_unicast_frames;
-	u32 rx_multicast_frames;
-	u32 rx_fragments;
-	u32 rx_unicast_octets;
-	u32 rx_multicast_octets;
-	u32 rx_fcs_errors;
-	u32 rx_discards_no_buffer;
-	u32 tx_discards_wrong_sa;
-	u32 rx_discards_wep_undecryptable;
-	u32 rx_message_in_msg_fragments;
-	u32 rx_message_in_bad_msg_fragments;
+	__le32 tx_unicast_frames;
+	__le32 tx_multicast_frames;
+	__le32 tx_fragments;
+	__le32 tx_unicast_octets;
+	__le32 tx_multicast_octets;
+	__le32 tx_deferred_transmissions;
+	__le32 tx_single_retry_frames;
+	__le32 tx_multiple_retry_frames;
+	__le32 tx_retry_limit_exceeded;
+	__le32 tx_discards;
+	__le32 rx_unicast_frames;
+	__le32 rx_multicast_frames;
+	__le32 rx_fragments;
+	__le32 rx_unicast_octets;
+	__le32 rx_multicast_octets;
+	__le32 rx_fcs_errors;
+	__le32 rx_discards_no_buffer;
+	__le32 tx_discards_wrong_sa;
+	__le32 rx_discards_wep_undecryptable;
+	__le32 rx_message_in_msg_fragments;
+	__le32 rx_message_in_bad_msg_fragments;
 } __attribute__ ((packed));
 
 struct hfa384x_scan_result_hdr {
-	u16 reserved;
-	u16 scan_reason;
+	__le16 reserved;
+	__le16 scan_reason;
 #define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */
 #define HFA384X_SCAN_HOST_INITIATED 1
 #define HFA384X_SCAN_FIRMWARE_INITIATED 2
@@ -211,30 +211,30 @@ struct hfa384x_scan_result_hdr {
 #define HFA384X_SCAN_MAX_RESULTS 32
 
 struct hfa384x_scan_result {
-	u16 chid;
-	u16 anl;
-	u16 sl;
+	__le16 chid;
+	__le16 anl;
+	__le16 sl;
 	u8 bssid[6];
-	u16 beacon_interval;
-	u16 capability;
-	u16 ssid_len;
+	__le16 beacon_interval;
+	__le16 capability;
+	__le16 ssid_len;
 	u8 ssid[32];
 	u8 sup_rates[10];
-	u16 rate;
+	__le16 rate;
 } __attribute__ ((packed));
 
 struct hfa384x_hostscan_result {
-	u16 chid;
-	u16 anl;
-	u16 sl;
+	__le16 chid;
+	__le16 anl;
+	__le16 sl;
 	u8 bssid[6];
-	u16 beacon_interval;
-	u16 capability;
-	u16 ssid_len;
+	__le16 beacon_interval;
+	__le16 capability;
+	__le16 ssid_len;
 	u8 ssid[32];
 	u8 sup_rates[10];
-	u16 rate;
-	u16 atim;
+	__le16 rate;
+	__le16 atim;
 } __attribute__ ((packed));
 
 struct comm_tallies_sums {
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index fc6cdd8086c1..2ab107f45793 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -2509,9 +2509,9 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
 
 	ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
 	ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
-	ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total hdr+data */
+	ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */
 
-	ipw_rt->rt_hdr.it_present = 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL;
+	ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
 
 	ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM;
 
@@ -2558,7 +2558,7 @@ static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
 #ifdef CONFIG_IPW2100_MONITOR
 		return 0;
 #else
-		switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) {
+		switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
 		case IEEE80211_FTYPE_MGMT:
 		case IEEE80211_FTYPE_CTL:
 			return 0;
@@ -2677,7 +2677,7 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv)
 #endif
 			if (stats.len < sizeof(struct ieee80211_hdr_3addr))
 				break;
-			switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) {
+			switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
 			case IEEE80211_FTYPE_MGMT:
 				ieee80211_rx_mgt(priv->ieee,
 						 &u->rx_data.header, &stats);
@@ -6591,8 +6591,7 @@ static const long ipw2100_frequencies[] = {
 	2472, 2484
 };
 
-#define FREQ_COUNT (sizeof(ipw2100_frequencies) / \
-                    sizeof(ipw2100_frequencies[0]))
+#define FREQ_COUNT	ARRAY_SIZE(ipw2100_frequencies)
 
 static const long ipw2100_rates_11b[] = {
 	1000000,
@@ -7796,7 +7795,7 @@ static int ipw2100_wx_set_mlme(struct net_device *dev,
 {
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
 	struct iw_mlme *mlme = (struct iw_mlme *)extra;
-	u16 reason;
+	__le16 reason;
 
 	reason = cpu_to_le16(mlme->reason_code);
 
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 003f73f89efa..3e6ad7b92c83 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -2352,27 +2352,13 @@ static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
 static int ipw_send_associate(struct ipw_priv *priv,
 			      struct ipw_associate *associate)
 {
-	struct ipw_associate tmp_associate;
-
 	if (!priv || !associate) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	memcpy(&tmp_associate, associate, sizeof(*associate));
-	tmp_associate.policy_support =
-	    cpu_to_le16(tmp_associate.policy_support);
-	tmp_associate.assoc_tsf_msw = cpu_to_le32(tmp_associate.assoc_tsf_msw);
-	tmp_associate.assoc_tsf_lsw = cpu_to_le32(tmp_associate.assoc_tsf_lsw);
-	tmp_associate.capability = cpu_to_le16(tmp_associate.capability);
-	tmp_associate.listen_interval =
-	    cpu_to_le16(tmp_associate.listen_interval);
-	tmp_associate.beacon_interval =
-	    cpu_to_le16(tmp_associate.beacon_interval);
-	tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window);
-
-	return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(tmp_associate),
-				&tmp_associate);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(*associate),
+				associate);
 }
 
 static int ipw_send_supported_rates(struct ipw_priv *priv,
@@ -2403,14 +2389,13 @@ static int ipw_set_random_seed(struct ipw_priv *priv)
 
 static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
 {
+	__le32 v = cpu_to_le32(phy_off);
 	if (!priv) {
 		IPW_ERROR("Invalid args\n");
 		return -1;
 	}
 
-	phy_off = cpu_to_le32(phy_off);
-	return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(phy_off),
-				&phy_off);
+	return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(v), &v);
 }
 
 static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
@@ -2499,7 +2484,7 @@ static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
 
 static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
 {
-	u32 param;
+	__le32 param;
 
 	if (!priv) {
 		IPW_ERROR("Invalid args\n");
@@ -2510,17 +2495,16 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
 	 * level */
 	switch (mode) {
 	case IPW_POWER_BATTERY:
-		param = IPW_POWER_INDEX_3;
+		param = cpu_to_le32(IPW_POWER_INDEX_3);
 		break;
 	case IPW_POWER_AC:
-		param = IPW_POWER_MODE_CAM;
+		param = cpu_to_le32(IPW_POWER_MODE_CAM);
 		break;
 	default:
-		param = mode;
+		param = cpu_to_le32(mode);
 		break;
 	}
 
-	param = cpu_to_le32(param);
 	return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
 				&param);
 }
@@ -2654,13 +2638,13 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
 static void ipw_eeprom_init_sram(struct ipw_priv *priv)
 {
 	int i;
-	u16 *eeprom = (u16 *) priv->eeprom;
+	__le16 *eeprom = (__le16 *) priv->eeprom;
 
 	IPW_DEBUG_TRACE(">>\n");
 
 	/* read entire contents of eeprom into private buffer */
 	for (i = 0; i < 128; i++)
-		eeprom[i] = le16_to_cpu(eeprom_read_u16(priv, (u8) i));
+		eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
 
 	/*
 	   If the data looks correct, then copy it to our private
@@ -3040,17 +3024,17 @@ static void ipw_arc_release(struct ipw_priv *priv)
 }
 
 struct fw_chunk {
-	u32 address;
-	u32 length;
+	__le32 address;
+	__le32 length;
 };
 
 static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
 {
 	int rc = 0, i, addr;
 	u8 cr = 0;
-	u16 *image;
+	__le16 *image;
 
-	image = (u16 *) data;
+	image = (__le16 *) data;
 
 	IPW_DEBUG_TRACE(">> \n");
 
@@ -3097,7 +3081,7 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
 	/* load new ipw uCode */
 	for (i = 0; i < len / 2; i++)
 		ipw_write_reg16(priv, IPW_BASEBAND_CONTROL_STORE,
-				cpu_to_le16(image[i]));
+				le16_to_cpu(image[i]));
 
 	/* enable DINO */
 	ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
@@ -3116,11 +3100,11 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
 
 	if (cr & DINO_RXFIFO_DATA) {
 		/* alive_command_responce size is NOT multiple of 4 */
-		u32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4];
+		__le32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4];
 
 		for (i = 0; i < ARRAY_SIZE(response_buffer); i++)
 			response_buffer[i] =
-			    le32_to_cpu(ipw_read_reg32(priv,
+			    cpu_to_le32(ipw_read_reg32(priv,
 						       IPW_BASEBAND_RX_FIFO_READ));
 		memcpy(&priv->dino_alive, response_buffer,
 		       sizeof(priv->dino_alive));
@@ -4170,7 +4154,7 @@ static void ipw_gather_stats(struct ipw_priv *priv)
 	priv->last_missed_beacons = priv->missed_beacons;
 	if (priv->assoc_request.beacon_interval) {
 		missed_beacons_percent = missed_beacons_delta *
-		    (HZ * priv->assoc_request.beacon_interval) /
+		    (HZ * le16_to_cpu(priv->assoc_request.beacon_interval)) /
 		    (IPW_STATS_INTERVAL * 10);
 	} else {
 		missed_beacons_percent = 0;
@@ -4396,9 +4380,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 				       struct ipw_rx_notification *notif)
 {
 	DECLARE_MAC_BUF(mac);
+	u16 size = le16_to_cpu(notif->size);
 	notif->size = le16_to_cpu(notif->size);
 
-	IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size);
+	IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
 
 	switch (notif->subtype) {
 	case HOST_NOTIFICATION_STATUS_ASSOCIATED:{
@@ -4433,9 +4418,9 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 								   workqueue,
 								   &priv->
 								   adhoc_check,
-								   priv->
+								   le16_to_cpu(priv->
 								   assoc_request.
-								   beacon_interval);
+								   beacon_interval));
 						break;
 					}
 
@@ -4453,20 +4438,17 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 						if ((sizeof
 						     (struct
 						      ieee80211_assoc_response)
-						     <= notif->size)
-						    && (notif->size <= 2314)) {
+						     <= size)
+						    && (size <= 2314)) {
 							struct
 							ieee80211_rx_stats
 							    stats = {
-								.len =
-								    notif->
-								    size - 1,
+								.len = size - 1,
 							};
 
 							IPW_DEBUG_QOS
 							    ("QoS Associate "
-							     "size %d\n",
-							     notif->size);
+							     "size %d\n", size);
 							ieee80211_rx_mgt(priv->
 									 ieee,
 									 (struct
@@ -4671,20 +4653,20 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 			struct notif_channel_result *x =
 			    &notif->u.channel_result;
 
-			if (notif->size == sizeof(*x)) {
+			if (size == sizeof(*x)) {
 				IPW_DEBUG_SCAN("Scan result for channel %d\n",
 					       x->channel_num);
 			} else {
 				IPW_DEBUG_SCAN("Scan result of wrong size %d "
 					       "(should be %zd)\n",
-					       notif->size, sizeof(*x));
+					       size, sizeof(*x));
 			}
 			break;
 		}
 
 	case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED:{
 			struct notif_scan_complete *x = &notif->u.scan_complete;
-			if (notif->size == sizeof(*x)) {
+			if (size == sizeof(*x)) {
 				IPW_DEBUG_SCAN
 				    ("Scan completed: type %d, %d channels, "
 				     "%d status\n", x->scan_type,
@@ -4692,7 +4674,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 			} else {
 				IPW_ERROR("Scan completed of wrong size %d "
 					  "(should be %zd)\n",
-					  notif->size, sizeof(*x));
+					  size, sizeof(*x));
 			}
 
 			priv->status &=
@@ -4758,13 +4740,13 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 	case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{
 			struct notif_frag_length *x = &notif->u.frag_len;
 
-			if (notif->size == sizeof(*x))
+			if (size == sizeof(*x))
 				IPW_ERROR("Frag length: %d\n",
 					  le16_to_cpu(x->frag_length));
 			else
 				IPW_ERROR("Frag length of wrong size %d "
 					  "(should be %zd)\n",
-					  notif->size, sizeof(*x));
+					  size, sizeof(*x));
 			break;
 		}
 
@@ -4772,7 +4754,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 			struct notif_link_deterioration *x =
 			    &notif->u.link_deterioration;
 
-			if (notif->size == sizeof(*x)) {
+			if (size == sizeof(*x)) {
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
 					"link deterioration: type %d, cnt %d\n",
 					x->silence_notification_type,
@@ -4782,7 +4764,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 			} else {
 				IPW_ERROR("Link Deterioration of wrong size %d "
 					  "(should be %zd)\n",
-					  notif->size, sizeof(*x));
+					  size, sizeof(*x));
 			}
 			break;
 		}
@@ -4798,10 +4780,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 
 	case HOST_NOTIFICATION_STATUS_BEACON_STATE:{
 			struct notif_beacon_state *x = &notif->u.beacon_state;
-			if (notif->size != sizeof(*x)) {
+			if (size != sizeof(*x)) {
 				IPW_ERROR
 				    ("Beacon state of wrong size %d (should "
-				     "be %zd)\n", notif->size, sizeof(*x));
+				     "be %zd)\n", size, sizeof(*x));
 				break;
 			}
 
@@ -4816,7 +4798,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 
 	case HOST_NOTIFICATION_STATUS_TGI_TX_KEY:{
 			struct notif_tgi_tx_key *x = &notif->u.tgi_tx_key;
-			if (notif->size == sizeof(*x)) {
+			if (size == sizeof(*x)) {
 				IPW_ERROR("TGi Tx Key: state 0x%02x sec type "
 					  "0x%02x station %d\n",
 					  x->key_state, x->security_type,
@@ -4826,14 +4808,14 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 
 			IPW_ERROR
 			    ("TGi Tx Key of wrong size %d (should be %zd)\n",
-			     notif->size, sizeof(*x));
+			     size, sizeof(*x));
 			break;
 		}
 
 	case HOST_NOTIFICATION_CALIB_KEEP_RESULTS:{
 			struct notif_calibration *x = &notif->u.calibration;
 
-			if (notif->size == sizeof(*x)) {
+			if (size == sizeof(*x)) {
 				memcpy(&priv->calib, x, sizeof(*x));
 				IPW_DEBUG_INFO("TODO: Calibration\n");
 				break;
@@ -4841,12 +4823,12 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 
 			IPW_ERROR
 			    ("Calibration of wrong size %d (should be %zd)\n",
-			     notif->size, sizeof(*x));
+			     size, sizeof(*x));
 			break;
 		}
 
 	case HOST_NOTIFICATION_NOISE_STATS:{
-			if (notif->size == sizeof(u32)) {
+			if (size == sizeof(u32)) {
 				priv->exp_avg_noise =
 				    exponential_average(priv->exp_avg_noise,
 				    (u8) (le32_to_cpu(notif->u.noise.value) & 0xff),
@@ -4856,14 +4838,14 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 
 			IPW_ERROR
 			    ("Noise stat is wrong size %d (should be %zd)\n",
-			     notif->size, sizeof(u32));
+			     size, sizeof(u32));
 			break;
 		}
 
 	default:
 		IPW_DEBUG_NOTIF("Unknown notification: "
 				"subtype=%d,flags=0x%2x,size=%d\n",
-				notif->subtype, notif->flags, notif->size);
+				notif->subtype, notif->flags, size);
 	}
 }
 
@@ -6048,7 +6030,7 @@ static void ipw_adhoc_check(void *data)
 	}
 
 	queue_delayed_work(priv->workqueue, &priv->adhoc_check,
-			   priv->assoc_request.beacon_interval);
+			   le16_to_cpu(priv->assoc_request.beacon_interval));
 }
 
 static void ipw_bg_adhoc_check(struct work_struct *work)
@@ -6767,7 +6749,7 @@ static int ipw_wx_set_mlme(struct net_device *dev,
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	struct iw_mlme *mlme = (struct iw_mlme *)extra;
-	u16 reason;
+	__le16 reason;
 
 	reason = cpu_to_le16(mlme->reason_code);
 
@@ -6904,7 +6886,7 @@ static int ipw_qos_activate(struct ipw_priv *priv,
 		burst_duration = ipw_qos_get_burst_duration(priv);
 		for (i = 0; i < QOS_QUEUE_NUM; i++)
 			qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] =
-			    (u16)burst_duration;
+			    cpu_to_le16(burst_duration);
 	} else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
 		if (type == IEEE_B) {
 			IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n",
@@ -6936,20 +6918,11 @@ static int ipw_qos_activate(struct ipw_priv *priv,
 			burst_duration = ipw_qos_get_burst_duration(priv);
 			for (i = 0; i < QOS_QUEUE_NUM; i++)
 				qos_parameters[QOS_PARAM_SET_ACTIVE].
-				    tx_op_limit[i] = (u16)burst_duration;
+				    tx_op_limit[i] = cpu_to_le16(burst_duration);
 		}
 	}
 
 	IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
-	for (i = 0; i < 3; i++) {
-		int j;
-		for (j = 0; j < QOS_QUEUE_NUM; j++) {
-			qos_parameters[i].cw_min[j] = cpu_to_le16(qos_parameters[i].cw_min[j]);
-			qos_parameters[i].cw_max[j] = cpu_to_le16(qos_parameters[i].cw_max[j]);
-			qos_parameters[i].tx_op_limit[j] = cpu_to_le16(qos_parameters[i].tx_op_limit[j]);
-		}
-	}
-
 	err = ipw_send_qos_params_command(priv,
 					  (struct ieee80211_qos_parameters *)
 					  &(qos_parameters[0]));
@@ -7300,7 +7273,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
 		priv->assoc_request.auth_type = AUTH_OPEN;
 
 	if (priv->ieee->wpa_ie_len) {
-		priv->assoc_request.policy_support = 0x02;	/* RSN active */
+		priv->assoc_request.policy_support = cpu_to_le16(0x02);	/* RSN active */
 		ipw_set_rsn_capa(priv, priv->ieee->wpa_ie,
 				 priv->ieee->wpa_ie_len);
 	}
@@ -7317,7 +7290,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
 	else if (network->mode & priv->ieee->mode & IEEE_B)
 		priv->assoc_request.ieee_mode = IPW_B_MODE;
 
-	priv->assoc_request.capability = network->capability;
+	priv->assoc_request.capability = cpu_to_le16(network->capability);
 	if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
 	    && !(priv->config & CFG_PREAMBLE_LONG)) {
 		priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE;
@@ -7326,13 +7299,13 @@ static int ipw_associate_network(struct ipw_priv *priv,
 
 		/* Clear the short preamble if we won't be supporting it */
 		priv->assoc_request.capability &=
-		    ~WLAN_CAPABILITY_SHORT_PREAMBLE;
+		    ~cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
 	}
 
 	/* Clear capability bits that aren't used in Ad Hoc */
 	if (priv->ieee->iw_mode == IW_MODE_ADHOC)
 		priv->assoc_request.capability &=
-		    ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
+		    ~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
 
 	IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, "
 			"802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
@@ -7354,7 +7327,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
 			'1' + priv->ieee->sec.active_key : '.',
 			priv->capability & CAP_PRIVACY_ON ? '.' : ' ');
 
-	priv->assoc_request.beacon_interval = network->beacon_interval;
+	priv->assoc_request.beacon_interval = cpu_to_le16(network->beacon_interval);
 	if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
 	    (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) {
 		priv->assoc_request.assoc_type = HC_IBSS_START;
@@ -7365,21 +7338,21 @@ static int ipw_associate_network(struct ipw_priv *priv,
 			priv->assoc_request.assoc_type = HC_REASSOCIATE;
 		else
 			priv->assoc_request.assoc_type = HC_ASSOCIATE;
-		priv->assoc_request.assoc_tsf_msw = network->time_stamp[1];
-		priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0];
+		priv->assoc_request.assoc_tsf_msw = cpu_to_le32(network->time_stamp[1]);
+		priv->assoc_request.assoc_tsf_lsw = cpu_to_le32(network->time_stamp[0]);
 	}
 
 	memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN);
 
 	if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
 		memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN);
-		priv->assoc_request.atim_window = network->atim_window;
+		priv->assoc_request.atim_window = cpu_to_le16(network->atim_window);
 	} else {
 		memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN);
 		priv->assoc_request.atim_window = 0;
 	}
 
-	priv->assoc_request.listen_interval = network->listen_interval;
+	priv->assoc_request.listen_interval = cpu_to_le16(network->listen_interval);
 
 	err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
 	if (err) {
@@ -7768,11 +7741,11 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
 
 	ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
 	ipw_rt->rt_hdr.it_pad = 0;	/* always good to zero */
-	ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr);	/* total header+data */
+	ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr));	/* total header+data */
 
 	/* Big bitfield of all the fields we provide in radiotap */
-	ipw_rt->rt_hdr.it_present =
-	    ((1 << IEEE80211_RADIOTAP_TSFT) |
+	ipw_rt->rt_hdr.it_present = cpu_to_le32(
+	     (1 << IEEE80211_RADIOTAP_TSFT) |
 	     (1 << IEEE80211_RADIOTAP_FLAGS) |
 	     (1 << IEEE80211_RADIOTAP_RATE) |
 	     (1 << IEEE80211_RADIOTAP_CHANNEL) |
@@ -7801,7 +7774,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
 		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
 	} else {		/* 802.11g */
 		ipw_rt->rt_chbitmask =
-		    (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
+		    cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
 	}
 
 	/* set the rate in multiples of 500k/s */
@@ -7982,14 +7955,14 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
 
 	ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
 	ipw_rt->rt_hdr.it_pad = 0;	/* always good to zero */
-	ipw_rt->rt_hdr.it_len = sizeof(*ipw_rt);	/* total header+data */
+	ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt));	/* total header+data */
 
 	/* Set the size of the skb to the size of the frame */
-	skb_put(skb, ipw_rt->rt_hdr.it_len + len);
+	skb_put(skb, sizeof(*ipw_rt) + len);
 
 	/* Big bitfield of all the fields we provide in radiotap */
-	ipw_rt->rt_hdr.it_present =
-	    ((1 << IEEE80211_RADIOTAP_TSFT) |
+	ipw_rt->rt_hdr.it_present = cpu_to_le32(
+	     (1 << IEEE80211_RADIOTAP_TSFT) |
 	     (1 << IEEE80211_RADIOTAP_FLAGS) |
 	     (1 << IEEE80211_RADIOTAP_RATE) |
 	     (1 << IEEE80211_RADIOTAP_CHANNEL) |
@@ -8018,7 +7991,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
 		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
 	} else {		/* 802.11g */
 		ipw_rt->rt_chbitmask =
-		    (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
+		    cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
 	}
 
 	/* set the rate in multiples of 500k/s */
@@ -8912,6 +8885,8 @@ static int ipw_wx_get_range(struct net_device *dev,
 	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
 		IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
 
+	range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE;
+
 	IPW_DEBUG_WX("GET Range\n");
 	return 0;
 }
@@ -10348,7 +10323,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
 			tfd->u.data.chunk_ptr[i] =
 			    cpu_to_le32(pci_map_single
 					(priv->pci_dev, skb->data,
-					 tfd->u.data.chunk_len[i],
+					 remaining_bytes,
 					 PCI_DMA_TODEVICE));
 
 			tfd->u.data.num_chunks =
@@ -10443,24 +10418,24 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
 		rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION;
 		rt_hdr->it_pad = 0;
 		rt_hdr->it_present = 0; /* after all, it's just an idea */
-		rt_hdr->it_present |=  (1 << IEEE80211_RADIOTAP_CHANNEL);
+		rt_hdr->it_present |=  cpu_to_le32(1 << IEEE80211_RADIOTAP_CHANNEL);
 
-		*(u16*)skb_put(dst, sizeof(u16)) = cpu_to_le16(
+		*(__le16*)skb_put(dst, sizeof(u16)) = cpu_to_le16(
 			ieee80211chan2mhz(priv->channel));
 		if (priv->channel > 14) 	/* 802.11a */
-			*(u16*)skb_put(dst, sizeof(u16)) =
+			*(__le16*)skb_put(dst, sizeof(u16)) =
 				cpu_to_le16(IEEE80211_CHAN_OFDM |
 					     IEEE80211_CHAN_5GHZ);
 		else if (priv->ieee->mode == IEEE_B) /* 802.11b */
-			*(u16*)skb_put(dst, sizeof(u16)) =
+			*(__le16*)skb_put(dst, sizeof(u16)) =
 				cpu_to_le16(IEEE80211_CHAN_CCK |
 					     IEEE80211_CHAN_2GHZ);
 		else 		/* 802.11g */
-			*(u16*)skb_put(dst, sizeof(u16)) =
+			*(__le16*)skb_put(dst, sizeof(u16)) =
 				cpu_to_le16(IEEE80211_CHAN_OFDM |
 				 IEEE80211_CHAN_2GHZ);
 
-		rt_hdr->it_len = dst->len;
+		rt_hdr->it_len = cpu_to_le16(dst->len);
 
 		skb_copy_from_linear_data(src, skb_put(dst, len), len);
 
@@ -10873,9 +10848,9 @@ static void shim__set_security(struct net_device *dev,
 #if 0
 	if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) &&
 	    (((priv->assoc_request.capability &
-	       WLAN_CAPABILITY_PRIVACY) && !sec->enabled) ||
+	       cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && !sec->enabled) ||
 	     (!(priv->assoc_request.capability &
-		WLAN_CAPABILITY_PRIVACY) && sec->enabled))) {
+		cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && sec->enabled))) {
 		IPW_DEBUG_ASSOC("Disassociating due to capability "
 				"change.\n");
 		ipw_disassociate(priv);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index bec8e37a1738..fdc187e0769d 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -267,25 +267,25 @@ enum connection_manager_assoc_states {
 #define CW_MIN_CCK           31
 #define CW_MAX_CCK           1023
 
-#define QOS_TX0_CW_MIN_OFDM      CW_MIN_OFDM
-#define QOS_TX1_CW_MIN_OFDM      CW_MIN_OFDM
-#define QOS_TX2_CW_MIN_OFDM      ( (CW_MIN_OFDM + 1) / 2 - 1 )
-#define QOS_TX3_CW_MIN_OFDM      ( (CW_MIN_OFDM + 1) / 4 - 1 )
-
-#define QOS_TX0_CW_MIN_CCK       CW_MIN_CCK
-#define QOS_TX1_CW_MIN_CCK       CW_MIN_CCK
-#define QOS_TX2_CW_MIN_CCK       ( (CW_MIN_CCK + 1) / 2 - 1 )
-#define QOS_TX3_CW_MIN_CCK       ( (CW_MIN_CCK + 1) / 4 - 1 )
-
-#define QOS_TX0_CW_MAX_OFDM      CW_MAX_OFDM
-#define QOS_TX1_CW_MAX_OFDM      CW_MAX_OFDM
-#define QOS_TX2_CW_MAX_OFDM      CW_MIN_OFDM
-#define QOS_TX3_CW_MAX_OFDM      ( (CW_MIN_OFDM + 1) / 2 - 1 )
-
-#define QOS_TX0_CW_MAX_CCK       CW_MAX_CCK
-#define QOS_TX1_CW_MAX_CCK       CW_MAX_CCK
-#define QOS_TX2_CW_MAX_CCK       CW_MIN_CCK
-#define QOS_TX3_CW_MAX_CCK       ( (CW_MIN_CCK + 1) / 2 - 1 )
+#define QOS_TX0_CW_MIN_OFDM      cpu_to_le16(CW_MIN_OFDM)
+#define QOS_TX1_CW_MIN_OFDM      cpu_to_le16(CW_MIN_OFDM)
+#define QOS_TX2_CW_MIN_OFDM      cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1)
+#define QOS_TX3_CW_MIN_OFDM      cpu_to_le16((CW_MIN_OFDM + 1)/4 - 1)
+
+#define QOS_TX0_CW_MIN_CCK       cpu_to_le16(CW_MIN_CCK)
+#define QOS_TX1_CW_MIN_CCK       cpu_to_le16(CW_MIN_CCK)
+#define QOS_TX2_CW_MIN_CCK       cpu_to_le16((CW_MIN_CCK + 1)/2 - 1)
+#define QOS_TX3_CW_MIN_CCK       cpu_to_le16((CW_MIN_CCK + 1)/4 - 1)
+
+#define QOS_TX0_CW_MAX_OFDM      cpu_to_le16(CW_MAX_OFDM)
+#define QOS_TX1_CW_MAX_OFDM      cpu_to_le16(CW_MAX_OFDM)
+#define QOS_TX2_CW_MAX_OFDM      cpu_to_le16(CW_MIN_OFDM)
+#define QOS_TX3_CW_MAX_OFDM      cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1)
+
+#define QOS_TX0_CW_MAX_CCK       cpu_to_le16(CW_MAX_CCK)
+#define QOS_TX1_CW_MAX_CCK       cpu_to_le16(CW_MAX_CCK)
+#define QOS_TX2_CW_MAX_CCK       cpu_to_le16(CW_MIN_CCK)
+#define QOS_TX3_CW_MAX_CCK       cpu_to_le16((CW_MIN_CCK + 1)/2 - 1)
 
 #define QOS_TX0_AIFS            (3 - QOS_AIFSN_MIN_VALUE)
 #define QOS_TX1_AIFS            (7 - QOS_AIFSN_MIN_VALUE)
@@ -299,33 +299,33 @@ enum connection_manager_assoc_states {
 
 #define QOS_TX0_TXOP_LIMIT_CCK          0
 #define QOS_TX1_TXOP_LIMIT_CCK          0
-#define QOS_TX2_TXOP_LIMIT_CCK          6016
-#define QOS_TX3_TXOP_LIMIT_CCK          3264
+#define QOS_TX2_TXOP_LIMIT_CCK          cpu_to_le16(6016)
+#define QOS_TX3_TXOP_LIMIT_CCK          cpu_to_le16(3264)
 
 #define QOS_TX0_TXOP_LIMIT_OFDM      0
 #define QOS_TX1_TXOP_LIMIT_OFDM      0
-#define QOS_TX2_TXOP_LIMIT_OFDM      3008
-#define QOS_TX3_TXOP_LIMIT_OFDM      1504
+#define QOS_TX2_TXOP_LIMIT_OFDM      cpu_to_le16(3008)
+#define QOS_TX3_TXOP_LIMIT_OFDM      cpu_to_le16(1504)
 
-#define DEF_TX0_CW_MIN_OFDM      CW_MIN_OFDM
-#define DEF_TX1_CW_MIN_OFDM      CW_MIN_OFDM
-#define DEF_TX2_CW_MIN_OFDM      CW_MIN_OFDM
-#define DEF_TX3_CW_MIN_OFDM      CW_MIN_OFDM
+#define DEF_TX0_CW_MIN_OFDM      cpu_to_le16(CW_MIN_OFDM)
+#define DEF_TX1_CW_MIN_OFDM      cpu_to_le16(CW_MIN_OFDM)
+#define DEF_TX2_CW_MIN_OFDM      cpu_to_le16(CW_MIN_OFDM)
+#define DEF_TX3_CW_MIN_OFDM      cpu_to_le16(CW_MIN_OFDM)
 
-#define DEF_TX0_CW_MIN_CCK       CW_MIN_CCK
-#define DEF_TX1_CW_MIN_CCK       CW_MIN_CCK
-#define DEF_TX2_CW_MIN_CCK       CW_MIN_CCK
-#define DEF_TX3_CW_MIN_CCK       CW_MIN_CCK
+#define DEF_TX0_CW_MIN_CCK       cpu_to_le16(CW_MIN_CCK)
+#define DEF_TX1_CW_MIN_CCK       cpu_to_le16(CW_MIN_CCK)
+#define DEF_TX2_CW_MIN_CCK       cpu_to_le16(CW_MIN_CCK)
+#define DEF_TX3_CW_MIN_CCK       cpu_to_le16(CW_MIN_CCK)
 
-#define DEF_TX0_CW_MAX_OFDM      CW_MAX_OFDM
-#define DEF_TX1_CW_MAX_OFDM      CW_MAX_OFDM
-#define DEF_TX2_CW_MAX_OFDM      CW_MAX_OFDM
-#define DEF_TX3_CW_MAX_OFDM      CW_MAX_OFDM
+#define DEF_TX0_CW_MAX_OFDM      cpu_to_le16(CW_MAX_OFDM)
+#define DEF_TX1_CW_MAX_OFDM      cpu_to_le16(CW_MAX_OFDM)
+#define DEF_TX2_CW_MAX_OFDM      cpu_to_le16(CW_MAX_OFDM)
+#define DEF_TX3_CW_MAX_OFDM      cpu_to_le16(CW_MAX_OFDM)
 
-#define DEF_TX0_CW_MAX_CCK       CW_MAX_CCK
-#define DEF_TX1_CW_MAX_CCK       CW_MAX_CCK
-#define DEF_TX2_CW_MAX_CCK       CW_MAX_CCK
-#define DEF_TX3_CW_MAX_CCK       CW_MAX_CCK
+#define DEF_TX0_CW_MAX_CCK       cpu_to_le16(CW_MAX_CCK)
+#define DEF_TX1_CW_MAX_CCK       cpu_to_le16(CW_MAX_CCK)
+#define DEF_TX2_CW_MAX_CCK       cpu_to_le16(CW_MAX_CCK)
+#define DEF_TX3_CW_MAX_CCK       cpu_to_le16(CW_MAX_CCK)
 
 #define DEF_TX0_AIFS            0
 #define DEF_TX1_AIFS            0
@@ -388,18 +388,18 @@ struct clx2_queue {
 } __attribute__ ((packed));
 
 struct machdr32 {
-	u16 frame_ctl;
+	__le16 frame_ctl;
 	u16 duration;		// watch out for endians!
 	u8 addr1[MACADRR_BYTE_LEN];
 	u8 addr2[MACADRR_BYTE_LEN];
 	u8 addr3[MACADRR_BYTE_LEN];
 	u16 seq_ctrl;		// more endians!
 	u8 addr4[MACADRR_BYTE_LEN];
-	u16 qos_ctrl;
+	__le16 qos_ctrl;
 } __attribute__ ((packed));
 
 struct machdr30 {
-	u16 frame_ctl;
+	__le16 frame_ctl;
 	u16 duration;		// watch out for endians!
 	u8 addr1[MACADRR_BYTE_LEN];
 	u8 addr2[MACADRR_BYTE_LEN];
@@ -409,17 +409,17 @@ struct machdr30 {
 } __attribute__ ((packed));
 
 struct machdr26 {
-	u16 frame_ctl;
+	__le16 frame_ctl;
 	u16 duration;		// watch out for endians!
 	u8 addr1[MACADRR_BYTE_LEN];
 	u8 addr2[MACADRR_BYTE_LEN];
 	u8 addr3[MACADRR_BYTE_LEN];
 	u16 seq_ctrl;		// more endians!
-	u16 qos_ctrl;
+	__le16 qos_ctrl;
 } __attribute__ ((packed));
 
 struct machdr24 {
-	u16 frame_ctl;
+	__le16 frame_ctl;
 	u16 duration;		// watch out for endians!
 	u8 addr1[MACADRR_BYTE_LEN];
 	u8 addr2[MACADRR_BYTE_LEN];
@@ -466,15 +466,15 @@ struct tfd_command {
 
 struct tfd_data {
 	/* Header */
-	u32 work_area_ptr;
+	__le32 work_area_ptr;
 	u8 station_number;	/* 0 for BSS */
 	u8 reserved1;
-	u16 reserved2;
+	__le16 reserved2;
 
 	/* Tx Parameters */
 	u8 cmd_id;
 	u8 seq_num;
-	u16 len;
+	__le16 len;
 	u8 priority;
 	u8 tx_flags;
 	u8 tx_flags_ext;
@@ -482,11 +482,11 @@ struct tfd_data {
 	u8 wepkey[DCT_WEP_KEY_FIELD_LENGTH];
 	u8 rate;
 	u8 antenna;
-	u16 next_packet_duration;
-	u16 next_frag_len;
-	u16 back_off_counter;	//////txop;
+	__le16 next_packet_duration;
+	__le16 next_frag_len;
+	__le16 back_off_counter;	//////txop;
 	u8 retrylimit;
-	u16 cwcurrent;
+	__le16 cwcurrent;
 	u8 reserved3;
 
 	/* 802.11 MAC Header */
@@ -498,9 +498,9 @@ struct tfd_data {
 	} tfd;
 
 	/* Payload DMA info */
-	u32 num_chunks;
-	u32 chunk_ptr[NUM_TFD_CHUNKS];
-	u16 chunk_len[NUM_TFD_CHUNKS];
+	__le32 num_chunks;
+	__le32 chunk_ptr[NUM_TFD_CHUNKS];
+	__le16 chunk_len[NUM_TFD_CHUNKS];
 } __attribute__ ((packed));
 
 struct txrx_control_flags {
@@ -547,14 +547,14 @@ struct clx2_tx_queue {
 // Used for passing to driver number of successes and failures per rate
 struct rate_histogram {
 	union {
-		u32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
-		u32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
-		u32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
 	} success;
 	union {
-		u32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
-		u32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
-		u32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
 	} failed;
 } __attribute__ ((packed));
 
@@ -602,13 +602,13 @@ struct notif_scan_complete {
 } __attribute__ ((packed));
 
 struct notif_frag_length {
-	u16 frag_length;
-	u16 reserved;
+	__le16 frag_length;
+	__le16 reserved;
 } __attribute__ ((packed));
 
 struct notif_beacon_state {
-	u32 state;
-	u32 number;
+	__le32 state;
+	__le32 number;
 } __attribute__ ((packed));
 
 struct notif_tgi_tx_key {
@@ -627,7 +627,7 @@ struct notif_link_deterioration {
 	u8 modulation;
 	struct rate_histogram histogram;
 	u8 silence_notification_type;	/* SILENCE_OVER/UNDER_THRESH */
-	u16 silence_count;
+	__le16 silence_count;
 } __attribute__ ((packed));
 
 struct notif_association {
@@ -645,14 +645,14 @@ struct notif_calibration {
 } __attribute__ ((packed));
 
 struct notif_noise {
-	u32 value;
+	__le32 value;
 } __attribute__ ((packed));
 
 struct ipw_rx_notification {
 	u8 reserved[8];
 	u8 subtype;
 	u8 flags;
-	u16 size;
+	__le16 size;
 	union {
 		struct notif_association assoc;
 		struct notif_authenticate auth;
@@ -669,7 +669,7 @@ struct ipw_rx_notification {
 } __attribute__ ((packed));
 
 struct ipw_rx_frame {
-	u32 reserved1;
+	__le32 reserved1;
 	u8 parent_tsf[4];	// fw_use[0] is boolean for OUR_TSF_IS_GREATER
 	u8 received_channel;	// The channel that this frame was received on.
 	// Note that for .11b this does not have to be
@@ -680,14 +680,14 @@ struct ipw_rx_frame {
 	u8 rssi;
 	u8 agc;
 	u8 rssi_dbm;
-	u16 signal;
-	u16 noise;
+	__le16 signal;
+	__le16 noise;
 	u8 antennaAndPhy;
 	u8 control;		// control bit should be on in bg
 	u8 rtscts_rate;		// rate of rts or cts (in rts cts sequence rate
 	// is identical)
 	u8 rtscts_seen;		// 0x1 RTS seen ; 0x2 CTS seen
-	u16 length;
+	__le16 length;
 	u8 data[0];
 } __attribute__ ((packed));
 
@@ -827,14 +827,14 @@ struct ipw_tgi_tx_key {
 	u8 station_index;
 	u8 flags;
 	u8 key[16];
-	u32 tx_counter[2];
+	__le32 tx_counter[2];
 } __attribute__ ((packed));
 
 #define IPW_SCAN_CHANNELS 54
 
 struct ipw_scan_request {
 	u8 scan_type;
-	u16 dwell_time;
+	__le16 dwell_time;
 	u8 channels_list[IPW_SCAN_CHANNELS];
 	u8 channels_reserved[3];
 } __attribute__ ((packed));
@@ -849,11 +849,11 @@ enum {
 };
 
 struct ipw_scan_request_ext {
-	u32 full_scan_index;
+	__le32 full_scan_index;
 	u8 channels_list[IPW_SCAN_CHANNELS];
 	u8 scan_type[IPW_SCAN_CHANNELS / 2];
 	u8 reserved;
-	u16 dwell_time[IPW_SCAN_TYPES];
+	__le16 dwell_time[IPW_SCAN_TYPES];
 } __attribute__ ((packed));
 
 static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
@@ -881,20 +881,20 @@ struct ipw_associate {
 	u8 auth_type:4, auth_key:4;
 	u8 assoc_type;
 	u8 reserved;
-	u16 policy_support;
+	__le16 policy_support;
 	u8 preamble_length;
 	u8 ieee_mode;
 	u8 bssid[ETH_ALEN];
-	u32 assoc_tsf_msw;
-	u32 assoc_tsf_lsw;
-	u16 capability;
-	u16 listen_interval;
-	u16 beacon_interval;
+	__le32 assoc_tsf_msw;
+	__le32 assoc_tsf_lsw;
+	__le16 capability;
+	__le16 listen_interval;
+	__le16 beacon_interval;
 	u8 dest[ETH_ALEN];
-	u16 atim_window;
+	__le16 atim_window;
 	u8 smr;
 	u8 reserved1;
-	u16 reserved2;
+	__le16 reserved2;
 } __attribute__ ((packed));
 
 struct ipw_supported_rates {
@@ -906,13 +906,13 @@ struct ipw_supported_rates {
 } __attribute__ ((packed));
 
 struct ipw_rts_threshold {
-	u16 rts_threshold;
-	u16 reserved;
+	__le16 rts_threshold;
+	__le16 reserved;
 } __attribute__ ((packed));
 
 struct ipw_frag_threshold {
-	u16 frag_threshold;
-	u16 reserved;
+	__le16 frag_threshold;
+	__le16 reserved;
 } __attribute__ ((packed));
 
 struct ipw_retry_limit {
@@ -931,7 +931,7 @@ struct ipw_dino_config {
 struct ipw_aironet_info {
 	u8 id;
 	u8 length;
-	u16 reserved;
+	__le16 reserved;
 } __attribute__ ((packed));
 
 struct ipw_rx_key {
@@ -977,12 +977,12 @@ struct ipw_tx_power {
 struct ipw_rsn_capabilities {
 	u8 id;
 	u8 length;
-	u16 version;
+	__le16 version;
 } __attribute__ ((packed));
 
 struct ipw_sensitivity_calib {
-	u16 beacon_rssi_raw;
-	u16 reserved;
+	__le16 beacon_rssi_raw;
+	__le16 reserved;
 } __attribute__ ((packed));
 
 /**
@@ -1156,8 +1156,8 @@ struct ipw_rt_hdr {
 	u64 rt_tsf;      /* TSF */
 	u8 rt_flags;	/* radiotap packet flags */
 	u8 rt_rate;	/* rate in 500kb/s */
-	u16 rt_channel;	/* channel in mhz */
-	u16 rt_chbitmask;	/* channel bitfield */
+	__le16 rt_channel;	/* channel in mhz */
+	__le16 rt_chbitmask;	/* channel bitfield */
 	s8 rt_dbmsignal;	/* signal in dbM, kluged to signed */
 	s8 rt_dbmnoise;
 	u8 rt_antenna;	/* antenna number */
@@ -1759,7 +1759,7 @@ enum {
 #define HC_IBSS_RECONF    4
 #define HC_DISASSOC_QUIET 5
 
-#define HC_QOS_SUPPORT_ASSOC  0x01
+#define HC_QOS_SUPPORT_ASSOC  cpu_to_le16(0x01)
 
 #define IPW_RATE_CAPABILITIES 1
 #define IPW_RATE_CONNECT      0
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 8d52a26c248a..d1af938b9aa6 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -1,24 +1,64 @@
-config IWLWIFI
-	bool "Intel Wireless WiFi Link Drivers"
+config IWL4965
+	tristate "Intel Wireless WiFi 4965AGN"
 	depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
 	select FW_LOADER
-	default n
 	---help---
-	  Select to enable drivers based on the iwlwifi project.  This
-	  project provides a common foundation for Intel's wireless
-	  drivers designed to use the mac80211 subsystem.
-
-	  See <file:Documentation/networking/README.iwlwifi> for
-	  information on the capabilities currently enabled in this
-	  driver and for tips for debugging issues and problems.
-
-config IWLWIFI_DEBUG
-	bool "Enable full debugging output in iwlwifi drivers"
-	depends on IWLWIFI
-	default y
+	  Select to build the driver supporting the:
+
+	  Intel Wireless WiFi Link 4965AGN
+
+	  This driver uses the kernel's mac80211 subsystem.
+
+	  In order to use this driver, you will need a microcode (uCode)
+	  image for it. You can obtain the microcode from:
+
+	          <http://intellinuxwireless.org/>.
+
+	  The microcode is typically installed in /lib/firmware. You can
+	  look in the hotplug script /etc/hotplug/firmware.agent to
+	  determine which directory FIRMWARE_DIR is set to when the script
+	  runs.
+
+	  If you want to compile the driver as a module ( = code which can be
+	  inserted in and remvoed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/kbuild/modules.txt>.  The
+	  module will be called iwl4965.ko.
+
+config IWL4965_QOS
+	bool "Enable Wireless QoS in iwl4965 driver"
+	depends on IWL4965
 	---help---
-	  This option will enable debug tracing output for the iwlwifi
-	  drivers.
+	  This option will enable wireless quality of service (QoS) for the
+	  iwl4965 driver.
+
+config IWL4965_HT
+	bool "Enable 802.11n HT features in iwl4965 driver"
+	depends on EXPERIMENTAL
+	depends on IWL4965 && IWL4965_QOS
+	depends on n
+	---help---
+	  This option enables IEEE 802.11n High Throughput features
+	  for the iwl4965 driver.
+
+config IWL4965_SPECTRUM_MEASUREMENT
+	bool "Enable Spectrum Measurement in iwl4965 driver"
+	depends on IWL4965
+	---help---
+	  This option will enable spectrum measurement for the iwl4965 driver.
+
+config IWL4965_SENSITIVITY
+	bool "Enable Sensitivity Calibration in iwl4965 driver"
+	depends on IWL4965
+	---help---
+	  This option will enable sensitivity calibration for the iwl4965
+	  driver.
+
+config IWL4965_DEBUG
+	bool "Enable full debugging output in iwl4965 driver"
+	depends on IWL4965
+	---help---
+	  This option will enable debug tracing output for the iwl4965
+	  driver.
 
 	  This will result in the kernel module being ~100k larger.  You can
 	  control which debug output is sent to the kernel log by setting the
@@ -33,96 +73,74 @@ config IWLWIFI_DEBUG
 		  % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level
 
 	  You can find the list of debug mask values in:
-		  drivers/net/wireless/mac80211/iwlwifi/iwl-debug.h
+		  drivers/net/wireless/iwlwifi/iwl-4965-debug.h
 
 	  If this is your first time using this driver, you should say Y here
 	  as the debug information can assist others in helping you resolve
 	  any problems you may encounter.
 
-config IWLWIFI_SENSITIVITY
-	bool "Enable Sensitivity Calibration in iwlwifi drivers"
-	depends on IWLWIFI
-	default y
-	---help---
-	  This option will enable sensitivity calibration for the iwlwifi
-	  drivers.
-
-config IWLWIFI_SPECTRUM_MEASUREMENT
-	bool "Enable Spectrum Measurement in iwlwifi drivers"
-	depends on IWLWIFI
-	default y
-	---help---
-	  This option will enable spectrum measurement for the iwlwifi drivers.
-
-config IWLWIFI_QOS
-	bool "Enable Wireless QoS in iwlwifi drivers"
-	depends on IWLWIFI
-	default y
-	---help---
-	  This option will enable wireless quality of service (QoS) for the
-	  iwlwifi drivers.
-
-config IWLWIFI_HT
-	bool "Enable 802.11n HT features in iwlwifi drivers"
-	depends on EXPERIMENTAL
-	depends on IWLWIFI && MAC80211_HT
-	default n
-	---help---
-	  This option enables IEEE 802.11n High Throughput features
-	  for the iwlwifi drivers.
-
-config IWL4965
-	tristate "Intel Wireless WiFi 4965AGN"
-	depends on m && IWLWIFI && EXPERIMENTAL
-	default m
+config IWL3945
+	tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
+	depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+	select FW_LOADER
 	---help---
 	  Select to build the driver supporting the:
 
-	  Intel Wireless WiFi Link 4965AGN
+	  Intel PRO/Wireless 3945ABG/BG Network Connection
 
 	  This driver uses the kernel's mac80211 subsystem.
 
-	  See <file:Documentation/networking/README.iwlwifi> for
-	  information on the capabilities currently enabled in this
-	  driver and for tips for debugging any issues or problems.
-
 	  In order to use this driver, you will need a microcode (uCode)
 	  image for it. You can obtain the microcode from:
 
 	          <http://intellinuxwireless.org/>.
 
-	  See the above referenced README.iwlwifi for information on where
-	  to install the microcode images.
+	  The microcode is typically installed in /lib/firmware. You can
+	  look in the hotplug script /etc/hotplug/firmware.agent to
+	  determine which directory FIRMWARE_DIR is set to when the script
+	  runs.
 
 	  If you want to compile the driver as a module ( = code which can be
 	  inserted in and remvoed from the running kernel whenever you want),
 	  say M here and read <file:Documentation/kbuild/modules.txt>.  The
-	  module will be called iwl4965.ko.
+	  module will be called iwl3945.ko.
 
-config IWL3945
-	tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
-	depends on m && IWLWIFI && EXPERIMENTAL
-	default m
+config IWL3945_QOS
+	bool "Enable Wireless QoS in iwl3945 driver"
+	depends on IWL3945
 	---help---
-	  Select to build the driver supporting the:
+	  This option will enable wireless quality of service (QoS) for the
+	  iwl3945 driver.
 
-	  Intel PRO/Wireless 3945ABG/BG Network Connection
+config IWL3945_SPECTRUM_MEASUREMENT
+	bool "Enable Spectrum Measurement in iwl3945 drivers"
+	depends on IWL3945
+	---help---
+	  This option will enable spectrum measurement for the iwl3945 driver.
 
-	  This driver uses the kernel's mac80211 subsystem.
+config IWL3945_DEBUG
+	bool "Enable full debugging output in iwl3945 driver"
+	depends on IWL3945
+	---help---
+	  This option will enable debug tracing output for the iwl3945
+	  driver.
+
+	  This will result in the kernel module being ~100k larger.  You can
+	  control which debug output is sent to the kernel log by setting the
+	  value in
 
-	  See <file:Documentation/networking/README.iwlwifi> for
-	  information on the capabilities currently enabled in this
-	  driver and for tips for debugging any issues or problems.
+	          /sys/bus/pci/drivers/${DRIVER}/debug_level
 
-	  In order to use this driver, you will need a microcode (uCode)
-	  image for it. You can obtain the microcode from:
+	  This entry will only exist if this option is enabled.
 
-	          <http://intellinuxwireless.org/>.
+	  To set a value, simply echo an 8-byte hex value to the same file:
+
+		  % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level
 
-	  See the above referenced README.iwlwifi for information on where
-	  to install the microcode images.
+	  You can find the list of debug mask values in:
+		  drivers/net/wireless/iwlwifi/iwl-3945-debug.h
+
+	  If this is your first time using this driver, you should say Y here
+	  as the debug information can assist others in helping you resolve
+	  any problems you may encounter.
 
-	  If you want to compile the driver as a module ( = code which can be
-	  inserted in and remvoed from the running kernel whenever you want),
-	  say M here and read <file:Documentation/kbuild/modules.txt>.  The
-	  module will be called iwl3945.ko.
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h
index 9de8d7f6efa3..46bb2c7d11dd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h
@@ -8,7 +8,7 @@
  * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU Geeral Public License as
+ * it under the terms of version 2 of the GNU General Public License as
  * published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful, but
@@ -60,9 +60,14 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *****************************************************************************/
+/*
+ * Please use this file (iwl-3945-commands.h) only for uCode API definitions.
+ * Please use iwl-3945-hw.h for hardware-related definitions.
+ * Please use iwl-3945.h for driver implementation definitions.
+ */
 
-#ifndef __iwl_commands_h__
-#define __iwl_commands_h__
+#ifndef __iwl_3945_commands_h__
+#define __iwl_3945_commands_h__
 
 enum {
 	REPLY_ALIVE = 0x1,
@@ -80,9 +85,7 @@ enum {
 	REPLY_REMOVE_ALL_STA = 0x1a,	/* not used */
 
 	/* RX, TX, LEDs */
-#if IWL == 3945
 	REPLY_3945_RX = 0x1b,		/* 3945 only */
-#endif
 	REPLY_TX = 0x1c,
 	REPLY_RATE_SCALE = 0x47,	/* 3945 only */
 	REPLY_LEDS_CMD = 0x48,
@@ -118,10 +121,10 @@ enum {
 	REPLY_TX_PWR_TABLE_CMD = 0x97,
 	MEASURE_ABORT_NOTIFICATION = 0x99,	/* not used */
 
-	/* BT config command */
+	/* Bluetooth device coexistance config command */
 	REPLY_BT_CONFIG = 0x9b,
 
-	/* 4965 Statistics */
+	/* Statistics */
 	REPLY_STATISTICS_CMD = 0x9c,
 	STATISTICS_NOTIFICATION = 0x9d,
 
@@ -132,46 +135,85 @@ enum {
 	/* Missed beacons notification */
 	MISSED_BEACONS_NOTIFICATION = 0xa2,
 
-#if IWL == 4965
-	REPLY_CT_KILL_CONFIG_CMD = 0xa4,
-	SENSITIVITY_CMD = 0xa8,
-	REPLY_PHY_CALIBRATION_CMD = 0xb0,
-	REPLY_RX_PHY_CMD = 0xc0,
-	REPLY_RX_MPDU_CMD = 0xc1,
-	REPLY_4965_RX = 0xc3,
-	REPLY_COMPRESSED_BA = 0xc5,
-#endif
 	REPLY_MAX = 0xff
 };
 
 /******************************************************************************
  * (0)
- * Header
+ * Commonly used structures and definitions:
+ * Command header, txpower
  *
  *****************************************************************************/
 
+/* iwl3945_cmd_header flags value */
 #define IWL_CMD_FAILED_MSK 0x40
 
-struct iwl_cmd_header {
-	u8 cmd;
-	u8 flags;
-	/* We have 15 LSB to use as we please (MSB indicates
-	 * a frame Rx'd from the HW).  We encode the following
-	 * information into the sequence field:
+/**
+ * struct iwl3945_cmd_header
+ *
+ * This header format appears in the beginning of each command sent from the
+ * driver, and each response/notification received from uCode.
+ */
+struct iwl3945_cmd_header {
+	u8 cmd;		/* Command ID:  REPLY_RXON, etc. */
+	u8 flags;	/* IWL_CMD_* */
+	/*
+	 * The driver sets up the sequence number to values of its chosing.
+	 * uCode does not use this value, but passes it back to the driver
+	 * when sending the response to each driver-originated command, so
+	 * the driver can match the response to the command.  Since the values
+	 * don't get used by uCode, the driver may set up an arbitrary format.
 	 *
-	 *  0:7    index in fifo
-	 *  8:13   fifo selection
-	 * 14:14   bit indicating if this packet references the 'extra'
-	 *         storage at the end of the memory queue
-	 * 15:15   (Rx indication)
+	 * There is one exception:  uCode sets bit 15 when it originates
+	 * the response/notification, i.e. when the response/notification
+	 * is not a direct response to a command sent by the driver.  For
+	 * example, uCode issues REPLY_3945_RX when it sends a received frame
+	 * to the driver; it is not a direct response to any driver command.
 	 *
+	 * The Linux driver uses the following format:
+	 *
+	 *  0:7    index/position within Tx queue
+	 *  8:13   Tx queue selection
+	 * 14:14   driver sets this to indicate command is in the 'huge'
+	 *         storage at the end of the command buffers, i.e. scan cmd
+	 * 15:15   uCode sets this in uCode-originated response/notification
 	 */
 	__le16 sequence;
 
-	/* command data follows immediately */
+	/* command or response/notification data follows immediately */
 	u8 data[0];
 } __attribute__ ((packed));
 
+/**
+ * struct iwl3945_tx_power
+ *
+ * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH
+ *
+ * Each entry contains two values:
+ * 1)  DSP gain (or sometimes called DSP attenuation).  This is a fine-grained
+ *     linear value that multiplies the output of the digital signal processor,
+ *     before being sent to the analog radio.
+ * 2)  Radio gain.  This sets the analog gain of the radio Tx path.
+ *     It is a coarser setting, and behaves in a logarithmic (dB) fashion.
+ *
+ * Driver obtains values from struct iwl3945_tx_power power_gain_table[][].
+ */
+struct iwl3945_tx_power {
+	u8 tx_gain;		/* gain for analog radio */
+	u8 dsp_atten;		/* gain for DSP */
+} __attribute__ ((packed));
+
+/**
+ * struct iwl3945_power_per_rate
+ *
+ * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ */
+struct iwl3945_power_per_rate {
+	u8 rate;		/* plcp */
+	struct iwl3945_tx_power tpc;
+	u8 reserved;
+} __attribute__ ((packed));
+
 /******************************************************************************
  * (0a)
  * Alive and Error Commands & Responses:
@@ -182,15 +224,22 @@ struct iwl_cmd_header {
 #define INITIALIZE_SUBTYPE    (9)
 
 /*
- * REPLY_ALIVE = 0x1 (response only, not a command)
+ * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "initialize alive" notification once the initialization
+ * uCode image has completed its work, and is ready to load the runtime image.
+ * This is the *first* "alive" notification that the driver will receive after
+ * rebooting uCode; the "initialize" alive is indicated by subtype field == 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
  */
-struct iwl_alive_resp {
+struct iwl3945_init_alive_resp {
 	u8 ucode_minor;
 	u8 ucode_major;
 	__le16 reserved1;
 	u8 sw_rev[8];
 	u8 ver_type;
-	u8 ver_subtype;
+	u8 ver_subtype;			/* "9" for initialize alive */
 	__le16 reserved2;
 	__le32 log_event_table_ptr;
 	__le32 error_event_table_ptr;
@@ -198,29 +247,41 @@ struct iwl_alive_resp {
 	__le32 is_valid;
 } __attribute__ ((packed));
 
-struct iwl_init_alive_resp {
+
+/**
+ * REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "alive" notification once the runtime image is ready
+ * to receive commands from the driver.  This is the *second* "alive"
+ * notification that the driver will receive after rebooting uCode;
+ * this "alive" is indicated by subtype field != 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ *
+ * This response includes two pointers to structures within the device's
+ * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging:
+ *
+ * 1)  log_event_table_ptr indicates base of the event log.  This traces
+ *     a 256-entry history of uCode execution within a circular buffer.
+ *
+ * 2)  error_event_table_ptr indicates base of the error log.  This contains
+ *     information about any uCode error that occurs.
+ *
+ * The Linux driver can print both logs to the system log when a uCode error
+ * occurs.
+ */
+struct iwl3945_alive_resp {
 	u8 ucode_minor;
 	u8 ucode_major;
 	__le16 reserved1;
 	u8 sw_rev[8];
 	u8 ver_type;
-	u8 ver_subtype;
+	u8 ver_subtype;			/* not "9" for runtime alive */
 	__le16 reserved2;
-	__le32 log_event_table_ptr;
-	__le32 error_event_table_ptr;
+	__le32 log_event_table_ptr;	/* SRAM address for event log */
+	__le32 error_event_table_ptr;	/* SRAM address for error log */
 	__le32 timestamp;
 	__le32 is_valid;
-
-#if IWL == 4965
-	/* calibration values from "initialize" uCode */
-	__le32 voltage;		/* signed */
-	__le32 therm_r1[2];	/* signed 1st for normal, 2nd for FAT channel */
-	__le32 therm_r2[2];	/* signed */
-	__le32 therm_r3[2];	/* signed */
-	__le32 therm_r4[2];	/* signed */
-	__le32 tx_atten[5][2];	/* signed MIMO gain comp, 5 freq groups,
-				 * 2 Tx chains */
-#endif
 } __attribute__ ((packed));
 
 union tsf {
@@ -232,14 +293,12 @@ union tsf {
 /*
  * REPLY_ERROR = 0x2 (response only, not a command)
  */
-struct iwl_error_resp {
+struct iwl3945_error_resp {
 	__le32 error_type;
 	u8 cmd_id;
 	u8 reserved1;
 	__le16 bad_cmd_seq_num;
-#if IWL == 3945
 	__le16 reserved2;
-#endif
 	__le32 error_info;
 	union tsf timestamp;
 } __attribute__ ((packed));
@@ -300,10 +359,24 @@ enum {
 /* transfer to host non bssid beacons in associated state */
 #define RXON_FILTER_BCON_AWARE_MSK      __constant_cpu_to_le32(1 << 6)
 
-/*
+/**
  * REPLY_RXON = 0x10 (command, has simple generic response)
+ *
+ * RXON tunes the radio tuner to a service channel, and sets up a number
+ * of parameters that are used primarily for Rx, but also for Tx operations.
+ *
+ * NOTE:  When tuning to a new channel, driver must set the
+ *        RXON_FILTER_ASSOC_MSK to 0.  This will clear station-dependent
+ *        info within the device, including the station tables, tx retry
+ *        rate tables, and txpower tables.  Driver must build a new station
+ *        table and txpower table before transmitting anything on the RXON
+ *        channel.
+ *
+ * NOTE:  All RXONs wipe clean the internal txpower table.  Driver must
+ *        issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10),
+ *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
  */
-struct iwl_rxon_cmd {
+struct iwl3945_rxon_cmd {
 	u8 node_addr[6];
 	__le16 reserved1;
 	u8 bssid_addr[6];
@@ -312,45 +385,31 @@ struct iwl_rxon_cmd {
 	__le16 reserved3;
 	u8 dev_type;
 	u8 air_propagation;
-#if IWL == 3945
 	__le16 reserved4;
-#elif IWL == 4965
-	__le16 rx_chain;
-#endif
 	u8 ofdm_basic_rates;
 	u8 cck_basic_rates;
 	__le16 assoc_id;
 	__le32 flags;
 	__le32 filter_flags;
 	__le16 channel;
-#if IWL == 3945
 	__le16 reserved5;
-#elif IWL == 4965
-	u8 ofdm_ht_single_stream_basic_rates;
-	u8 ofdm_ht_dual_stream_basic_rates;
-#endif
 } __attribute__ ((packed));
 
 /*
  * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
  */
-struct iwl_rxon_assoc_cmd {
+struct iwl3945_rxon_assoc_cmd {
 	__le32 flags;
 	__le32 filter_flags;
 	u8 ofdm_basic_rates;
 	u8 cck_basic_rates;
-#if IWL == 4965
-	u8 ofdm_ht_single_stream_basic_rates;
-	u8 ofdm_ht_dual_stream_basic_rates;
-	__le16 rx_chain_select_flags;
-#endif
 	__le16 reserved;
 } __attribute__ ((packed));
 
 /*
  * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
  */
-struct iwl_rxon_time_cmd {
+struct iwl3945_rxon_time_cmd {
 	union tsf timestamp;
 	__le16 beacon_interval;
 	__le16 atim_window;
@@ -359,52 +418,23 @@ struct iwl_rxon_time_cmd {
 	__le16 reserved;
 } __attribute__ ((packed));
 
-struct iwl_tx_power {
-	u8 tx_gain;		/* gain for analog radio */
-	u8 dsp_atten;		/* gain for DSP */
-} __attribute__ ((packed));
-
-#if IWL == 3945
-struct iwl_power_per_rate {
-	u8 rate;		/* plcp */
-	struct iwl_tx_power tpc;
-	u8 reserved;
-} __attribute__ ((packed));
-
-#elif IWL == 4965
-#define POWER_TABLE_NUM_ENTRIES			33
-#define POWER_TABLE_NUM_HT_OFDM_ENTRIES		32
-#define POWER_TABLE_CCK_ENTRY			32
-struct tx_power_dual_stream {
-	__le32 dw;
-} __attribute__ ((packed));
-
-struct iwl_tx_power_db {
-	struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
-} __attribute__ ((packed));
-#endif
-
 /*
  * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
  */
-struct iwl_channel_switch_cmd {
+struct iwl3945_channel_switch_cmd {
 	u8 band;
 	u8 expect_beacon;
 	__le16 channel;
 	__le32 rxon_flags;
 	__le32 rxon_filter_flags;
 	__le32 switch_time;
-#if IWL == 3945
-	struct iwl_power_per_rate power[IWL_MAX_RATES];
-#elif IWL == 4965
-	struct iwl_tx_power_db tx_power;
-#endif
+	struct iwl3945_power_per_rate power[IWL_MAX_RATES];
 } __attribute__ ((packed));
 
 /*
  * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
  */
-struct iwl_csa_notification {
+struct iwl3945_csa_notification {
 	__le16 band;
 	__le16 channel;
 	__le32 status;		/* 0 - OK, 1 - fail */
@@ -415,7 +445,24 @@ struct iwl_csa_notification {
  * Quality-of-Service (QOS) Commands & Responses:
  *
  *****************************************************************************/
-struct iwl_ac_qos {
+
+/**
+ * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM
+ * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd
+ *
+ * @cw_min: Contention window, start value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x0f.
+ * @cw_max: Contention window, max value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x3f.
+ * @aifsn:  Number of slots in Arbitration Interframe Space (before
+ *          performing random backoff timing prior to Tx).  Device default 1.
+ * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
+ *
+ * Device will automatically increase contention window by (2*CW) + 1 for each
+ * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
+ * value, to cap the CW value.
+ */
+struct iwl3945_ac_qos {
 	__le16 cw_min;
 	__le16 cw_max;
 	u8 aifsn;
@@ -428,18 +475,18 @@ struct iwl_ac_qos {
 #define QOS_PARAM_FLG_TGN_MSK		__constant_cpu_to_le32(0x02)
 #define QOS_PARAM_FLG_TXOP_TYPE_MSK	__constant_cpu_to_le32(0x10)
 
-/*
- *  TXFIFO Queue number defines
- */
-/* number of Access categories (AC) (EDCA), queues 0..3 */
+/* Number of Access Categories (AC) (EDCA), queues 0..3 */
 #define AC_NUM                4
 
 /*
  * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ *
+ * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
+ * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
  */
-struct iwl_qosparam_cmd {
+struct iwl3945_qosparam_cmd {
 	__le32 qos_flags;
-	struct iwl_ac_qos ac[AC_NUM];
+	struct iwl3945_ac_qos ac[AC_NUM];
 } __attribute__ ((packed));
 
 /******************************************************************************
@@ -450,24 +497,21 @@ struct iwl_qosparam_cmd {
 /*
  * Multi station support
  */
+
+/* Special, dedicated locations within device's station table */
 #define	IWL_AP_ID		0
 #define IWL_MULTICAST_ID	1
 #define	IWL_STA_ID		2
-
 #define	IWL3945_BROADCAST_ID	24
 #define IWL3945_STATION_COUNT	25
 
-#define IWL4965_BROADCAST_ID	31
-#define	IWL4965_STATION_COUNT	32
-
 #define	IWL_STATION_COUNT	32 	/* MAX(3945,4965)*/
 #define	IWL_INVALID_STATION 	255
 
-#if IWL == 3945
-#define STA_FLG_TX_RATE_MSK		__constant_cpu_to_le32(1<<2);
-#endif
-#define STA_FLG_PWR_SAVE_MSK		__constant_cpu_to_le32(1<<8);
+#define STA_FLG_TX_RATE_MSK		__constant_cpu_to_le32(1 << 2);
+#define STA_FLG_PWR_SAVE_MSK		__constant_cpu_to_le32(1 << 8);
 
+/* Use in mode field.  1: modify existing entry, 0: add new station entry */
 #define STA_CONTROL_MODIFY_MSK		0x01
 
 /* key flags __le16*/
@@ -480,13 +524,10 @@ struct iwl_qosparam_cmd {
 #define STA_KEY_FLG_KEYID_POS	8
 #define STA_KEY_FLG_INVALID 	__constant_cpu_to_le16(0x0800)
 
-/* modify flags  */
+/* Flags indicate whether to modify vs. don't change various station params */
 #define	STA_MODIFY_KEY_MASK		0x01
 #define	STA_MODIFY_TID_DISABLE_TX	0x02
 #define	STA_MODIFY_TX_RATE_MSK		0x04
-#define STA_MODIFY_ADDBA_TID_MSK	0x08
-#define STA_MODIFY_DELBA_TID_MSK	0x10
-#define BUILD_RAxTID(sta_id, tid)	(((sta_id) << 4) + (tid))
 
 /*
  * Antenna masks:
@@ -500,7 +541,7 @@ struct iwl_qosparam_cmd {
 #define RATE_MCS_ANT_B_MSK	0x8000
 #define RATE_MCS_ANT_AB_MSK	0xc000
 
-struct iwl_keyinfo {
+struct iwl3945_keyinfo {
 	__le16 key_flags;
 	u8 tkip_rx_tsc_byte2;	/* TSC[2] for key mix ph1 detection */
 	u8 reserved1;
@@ -509,6 +550,18 @@ struct iwl_keyinfo {
 	u8 key[16];		/* 16-byte unicast decryption key */
 } __attribute__ ((packed));
 
+/**
+ * struct sta_id_modify
+ * @addr[ETH_ALEN]: station's MAC address
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change
+ *
+ * Driver selects unused table index when adding new station,
+ * or the index to a pre-existing station entry when modifying that station.
+ * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP).
+ *
+ * modify_mask flags select which parameters to modify vs. leave alone.
+ */
 struct sta_id_modify {
 	u8 addr[ETH_ALEN];
 	__le16 reserved1;
@@ -519,36 +572,67 @@ struct sta_id_modify {
 
 /*
  * REPLY_ADD_STA = 0x18 (command)
+ *
+ * The device contains an internal table of per-station information,
+ * with info on security keys, aggregation parameters, and Tx rates for
+ * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD,
+ * 3945 uses REPLY_RATE_SCALE to set up rate tables).
+ *
+ * REPLY_ADD_STA sets up the table entry for one station, either creating
+ * a new entry, or modifying a pre-existing one.
+ *
+ * NOTE:  RXON command (without "associated" bit set) wipes the station table
+ *        clean.  Moving into RF_KILL state does this also.  Driver must set up
+ *        new station table before transmitting anything on the RXON channel
+ *        (except active scans or active measurements; those commands carry
+ *        their own txpower/rate setup data).
+ *
+ *        When getting started on a new channel, driver must set up the
+ *        IWL_BROADCAST_ID entry (last entry in the table).  For a client
+ *        station in a BSS, once an AP is selected, driver sets up the AP STA
+ *        in the IWL_AP_ID entry (1st entry in the table).  BROADCAST and AP
+ *        are all that are needed for a BSS client station.  If the device is
+ *        used as AP, or in an IBSS network, driver must set up station table
+ *        entries for all STAs in network, starting with index IWL_STA_ID.
  */
-struct iwl_addsta_cmd {
-	u8 mode;
+struct iwl3945_addsta_cmd {
+	u8 mode;		/* 1: modify existing, 0: add new station */
 	u8 reserved[3];
 	struct sta_id_modify sta;
-	struct iwl_keyinfo key;
-	__le32 station_flags;
-	__le32 station_flags_msk;
+	struct iwl3945_keyinfo key;
+	__le32 station_flags;		/* STA_FLG_* */
+	__le32 station_flags_msk;	/* STA_FLG_* */
+
+	/* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
+	 * corresponding to bit (e.g. bit 5 controls TID 5).
+	 * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
 	__le16 tid_disable_tx;
-#if IWL == 3945
+
 	__le16 rate_n_flags;
-#else
-	__le16	reserved1;
-#endif
+
+	/* TID for which to add block-ack support.
+	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
 	u8 add_immediate_ba_tid;
+
+	/* TID for which to remove block-ack support.
+	 * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
 	u8 remove_immediate_ba_tid;
+
+	/* Starting Sequence Number for added block-ack support.
+	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
 	__le16 add_immediate_ba_ssn;
-#if IWL == 4965
-	__le32 reserved2;
-#endif
 } __attribute__ ((packed));
 
+#define ADD_STA_SUCCESS_MSK		0x1
+#define ADD_STA_NO_ROOM_IN_TABLE	0x2
+#define ADD_STA_NO_BLOCK_ACK_RESOURCE	0x4
 /*
  * REPLY_ADD_STA = 0x18 (response)
  */
-struct iwl_add_sta_resp {
-	u8 status;
+struct iwl3945_add_sta_resp {
+	u8 status;	/* ADD_STA_* */
 } __attribute__ ((packed));
 
-#define ADD_STA_SUCCESS_MSK              0x1
 
 /******************************************************************************
  * (4)
@@ -556,7 +640,7 @@ struct iwl_add_sta_resp {
  *
  *****************************************************************************/
 
-struct iwl_rx_frame_stats {
+struct iwl3945_rx_frame_stats {
 	u8 phy_count;
 	u8 id;
 	u8 rssi;
@@ -566,7 +650,7 @@ struct iwl_rx_frame_stats {
 	u8 payload[0];
 } __attribute__ ((packed));
 
-struct iwl_rx_frame_hdr {
+struct iwl3945_rx_frame_hdr {
 	__le16 channel;
 	__le16 phy_flags;
 	u8 reserved1;
@@ -596,7 +680,7 @@ struct iwl_rx_frame_hdr {
 #define	RX_RES_STATUS_BAD_ICV_MIC	(0x1 << 11)
 #define	RX_RES_STATUS_BAD_KEY_TTAK	(0x2 << 11)
 
-struct iwl_rx_frame_end {
+struct iwl3945_rx_frame_end {
 	__le32 status;
 	__le64 timestamp;
 	__le32 beacon_timestamp;
@@ -610,10 +694,10 @@ struct iwl_rx_frame_end {
  * The actual offsets of the hdr and end are dynamic based on
  * stats.phy_count
  */
-struct iwl_rx_frame {
-	struct iwl_rx_frame_stats stats;
-	struct iwl_rx_frame_hdr hdr;
-	struct iwl_rx_frame_end end;
+struct iwl3945_rx_frame {
+	struct iwl3945_rx_frame_stats stats;
+	struct iwl3945_rx_frame_hdr hdr;
+	struct iwl3945_rx_frame_end end;
 } __attribute__ ((packed));
 
 /* Fixed (non-configurable) rx data from phy */
@@ -659,36 +743,86 @@ struct iwl4965_rx_mpdu_res_start {
  * (5)
  * Tx Commands & Responses:
  *
+ * Driver must place each REPLY_TX command into one of the prioritized Tx
+ * queues in host DRAM, shared between driver and device.  When the device's
+ * Tx scheduler and uCode are preparing to transmit, the device pulls the
+ * Tx command over the PCI bus via one of the device's Tx DMA channels,
+ * to fill an internal FIFO from which data will be transmitted.
+ *
+ * uCode handles all timing and protocol related to control frames
+ * (RTS/CTS/ACK), based on flags in the Tx command.
+ *
+ * uCode handles retrying Tx when an ACK is expected but not received.
+ * This includes trying lower data rates than the one requested in the Tx
+ * command, as set up by the REPLY_RATE_SCALE (for 3945) or
+ * REPLY_TX_LINK_QUALITY_CMD (4965).
+ *
+ * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
+ * This command must be executed after every RXON command, before Tx can occur.
  *****************************************************************************/
 
-/* Tx flags */
+/* REPLY_TX Tx flags field */
+
+/* 1: Use Request-To-Send protocol before this frame.
+ * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
 #define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+
+/* 1: Transmit Clear-To-Send to self before this frame.
+ * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
+ * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
 #define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+
+/* 1: Expect ACK from receiving station
+ * 0: Don't expect ACK (MAC header's duration field s/b 0)
+ * Set this for unicast frames, but not broadcast/multicast. */
 #define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+
+/* 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
+ *    Tx command's initial_rate_index indicates first rate to try;
+ *    uCode walks through table for additional Tx attempts.
+ * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
+ *    This rate will be used for all Tx attempts; it will not be scaled. */
 #define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+
+/* 1: Expect immediate block-ack.
+ * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
 #define TX_CMD_FLG_IMM_BA_RSP_MASK  __constant_cpu_to_le32(1 << 6)
+
+/* 1: Frame requires full Tx-Op protection.
+ * Set this if either RTS or CTS Tx Flag gets set. */
 #define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+
+/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
+ * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
 #define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
 #define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
 #define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
 
-/* ucode ignores BT priority for this frame */
+/* 1: Ignore Bluetooth priority for this frame.
+ * 0: Delay Tx until Bluetooth device is done (normal usage). */
 #define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
 
-/* ucode overrides sequence control */
+/* 1: uCode overrides sequence control field in MAC header.
+ * 0: Driver provides sequence control field in MAC header.
+ * Set this for management frames, non-QOS data frames, non-unicast frames,
+ * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
 #define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
 
-/* signal that this frame is non-last MPDU */
+/* 1: This frame is non-last MPDU; more fragments are coming.
+ * 0: Last fragment, or not using fragmentation. */
 #define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
 
-/* calculate TSF in outgoing frame */
+/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
+ * 0: No TSF required in outgoing frame.
+ * Set this for transmitting beacons and probe responses. */
 #define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
 
-/* activate TX calibration. */
-#define TX_CMD_FLG_CALIB_MSK __constant_cpu_to_le32(1 << 17)
-
-/* signals that 2 bytes pad was inserted
-   after the MAC header */
+/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
+ *    alignment of frame's payload data field.
+ * 0: No pad
+ * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
+ * field (but not both).  Driver must align frame data (i.e. data following
+ * MAC header) to DWORD boundary. */
 #define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
 
 /* HCCA-AP - disable duration overwriting. */
@@ -705,68 +839,65 @@ struct iwl4965_rx_mpdu_res_start {
 #define TX_CMD_SEC_KEY128	0x08
 
 /*
- * TX command Frame life time
- */
-
-struct iwl_dram_scratch {
-	u8 try_cnt;
-	u8 bt_kill_cnt;
-	__le16 reserved;
-} __attribute__ ((packed));
-
-/*
  * REPLY_TX = 0x1c (command)
  */
-struct iwl_tx_cmd {
+struct iwl3945_tx_cmd {
+	/*
+	 * MPDU byte count:
+	 * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
+	 * + 8 byte IV for CCM or TKIP (not used for WEP)
+	 * + Data payload
+	 * + 8-byte MIC (not used for CCM/WEP)
+	 * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
+	 *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
+	 * Range: 14-2342 bytes.
+	 */
 	__le16 len;
+
+	/*
+	 * MPDU or MSDU byte count for next frame.
+	 * Used for fragmentation and bursting, but not 11n aggregation.
+	 * Same as "len", but for next frame.  Set to 0 if not applicable.
+	 */
 	__le16 next_frame_len;
-	__le32 tx_flags;
-#if IWL == 3945
+
+	__le32 tx_flags;	/* TX_CMD_FLG_* */
+
 	u8 rate;
+
+	/* Index of recipient station in uCode's station table */
 	u8 sta_id;
 	u8 tid_tspec;
-#elif IWL == 4965
-	struct iwl_dram_scratch scratch;
-	__le32 rate_n_flags;
-	u8 sta_id;
-#endif
 	u8 sec_ctl;
-#if IWL == 4965
-	u8 initial_rate_index;
-	u8 reserved;
-#endif
 	u8 key[16];
-#if IWL == 3945
 	union {
 		u8 byte[8];
 		__le16 word[4];
 		__le32 dw[2];
 	} tkip_mic;
 	__le32 next_frame_info;
-#elif IWL == 4965
-	__le16 next_frame_flags;
-	__le16 reserved2;
-#endif
 	union {
 		__le32 life_time;
 		__le32 attempt;
 	} stop_time;
-#if IWL == 3945
 	u8 supp_rates[2];
-#elif IWL == 4965
-	__le32 dram_lsb_ptr;
-	u8 dram_msb_ptr;
-#endif
 	u8 rts_retry_limit;	/*byte 50 */
 	u8 data_retry_limit;	/*byte 51 */
-#if IWL == 4965
-	u8 tid_tspec;
-#endif
 	union {
 		__le16 pm_frame_timeout;
 		__le16 attempt_duration;
 	} timeout;
+
+	/*
+	 * Duration of EDCA burst Tx Opportunity, in 32-usec units.
+	 * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
+	 */
 	__le16 driver_txop;
+
+	/*
+	 * MAC header goes here, followed by 2 bytes padding if MAC header
+	 * length is 26 or 30 bytes, followed by payload data
+	 */
 	u8 payload[0];
 	struct ieee80211_hdr hdr[0];
 } __attribute__ ((packed));
@@ -838,104 +969,36 @@ enum {
 	TX_ABORT_REQUIRED_MSK = 0x80000000,	/* bits 31:31 */
 };
 
-/* *******************************
- * TX aggregation state
- ******************************* */
-
-enum {
-	AGG_TX_STATE_TRANSMITTED = 0x00,
-	AGG_TX_STATE_UNDERRUN_MSK = 0x01,
-	AGG_TX_STATE_BT_PRIO_MSK = 0x02,
-	AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
-	AGG_TX_STATE_ABORT_MSK = 0x08,
-	AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
-	AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
-	AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
-	AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
-	AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
-	AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
-	AGG_TX_STATE_DUMP_TX_MSK = 0x200,
-	AGG_TX_STATE_DELAY_TX_MSK = 0x400
-};
-
-#define AGG_TX_STATE_LAST_SENT_MSK \
-(AGG_TX_STATE_LAST_SENT_TTL_MSK | \
- AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
- AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
-
-#define AGG_TX_STATE_TRY_CNT_POS 12
-#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
-
-#define AGG_TX_STATE_SEQ_NUM_POS 16
-#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
-
 /*
  * REPLY_TX = 0x1c (response)
  */
-#if IWL == 4965
-struct iwl_tx_resp {
-	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
-	u8 bt_kill_count;
-	u8 failure_rts;
-	u8 failure_frame;
-	__le32 rate_n_flags;
-	__le16 wireless_media_time;
-	__le16 reserved;
-	__le32 pa_power1;
-	__le32 pa_power2;
-	__le32 status;	/* TX status (for aggregation status of 1st frame) */
-} __attribute__ ((packed));
-
-#elif IWL == 3945
-struct iwl_tx_resp {
+struct iwl3945_tx_resp {
 	u8 failure_rts;
 	u8 failure_frame;
 	u8 bt_kill_count;
 	u8 rate;
 	__le32 wireless_media_time;
-	__le32 status;	/* TX status (for aggregation status of 1st frame) */
-} __attribute__ ((packed));
-#endif
-
-/*
- * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
- */
-struct iwl_compressed_ba_resp {
-	__le32 sta_addr_lo32;
-	__le16 sta_addr_hi16;
-	__le16 reserved;
-	u8 sta_id;
-	u8 tid;
-	__le16 ba_seq_ctl;
-	__le32 ba_bitmap0;
-	__le32 ba_bitmap1;
-	__le16 scd_flow;
-	__le16 scd_ssn;
+	__le32 status;		/* TX status */
 } __attribute__ ((packed));
 
 /*
  * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
  */
-struct iwl_txpowertable_cmd {
+struct iwl3945_txpowertable_cmd {
 	u8 band;		/* 0: 5 GHz, 1: 2.4 GHz */
 	u8 reserved;
 	__le16 channel;
-#if IWL == 3945
-	struct iwl_power_per_rate power[IWL_MAX_RATES];
-#elif IWL == 4965
-	struct iwl_tx_power_db tx_power;
-#endif
+	struct iwl3945_power_per_rate power[IWL_MAX_RATES];
 } __attribute__ ((packed));
 
-#if IWL == 3945
-struct iwl_rate_scaling_info {
+struct iwl3945_rate_scaling_info {
 	__le16 rate_n_flags;
 	u8 try_cnt;
 	u8 next_rate_index;
 } __attribute__ ((packed));
 
 /**
- * struct iwl_rate_scaling_cmd - Rate Scaling Command & Response
+ * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response
  *
  * REPLY_RATE_SCALE = 0x47 (command, has simple generic response)
  *
@@ -947,61 +1010,22 @@ struct iwl_rate_scaling_info {
  * For example, if you set 9MB (PLCP 0x0f) as the first
  * rate in the rate table, the bit mask for that rate
  * when passed through ofdm_basic_rates on the REPLY_RXON
- * command would be bit 0 (1<<0)
+ * command would be bit 0 (1 << 0)
  */
-struct iwl_rate_scaling_cmd {
+struct iwl3945_rate_scaling_cmd {
 	u8 table_id;
 	u8 reserved[3];
-	struct iwl_rate_scaling_info table[IWL_MAX_RATES];
-} __attribute__ ((packed));
-
-#elif IWL == 4965
-
-/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
-#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK	(1<<0)
-
-#define  LINK_QUAL_AC_NUM AC_NUM
-#define  LINK_QUAL_MAX_RETRY_NUM 16
-
-#define  LINK_QUAL_ANT_A_MSK (1<<0)
-#define  LINK_QUAL_ANT_B_MSK (1<<1)
-#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
-
-struct iwl_link_qual_general_params {
-	u8 flags;
-	u8 mimo_delimiter;
-	u8 single_stream_ant_msk;
-	u8 dual_stream_ant_msk;
-	u8 start_rate_index[LINK_QUAL_AC_NUM];
-} __attribute__ ((packed));
-
-struct iwl_link_qual_agg_params {
-	__le16 agg_time_limit;
-	u8 agg_dis_start_th;
-	u8 agg_frame_cnt_limit;
-	__le32 reserved;
-} __attribute__ ((packed));
-
-/*
- * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
- */
-struct iwl_link_quality_cmd {
-	u8 sta_id;
-	u8 reserved1;
-	__le16 control;
-	struct iwl_link_qual_general_params general_params;
-	struct iwl_link_qual_agg_params agg_params;
-	struct {
-		__le32 rate_n_flags;
-	} rs_table[LINK_QUAL_MAX_RETRY_NUM];
-	__le32 reserved2;
+	struct iwl3945_rate_scaling_info table[IWL_MAX_RATES];
 } __attribute__ ((packed));
-#endif
 
 /*
  * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ *
+ * 3945 and 4965 support hardware handshake with Bluetooth device on
+ * same platform.  Bluetooth device alerts wireless device when it will Tx;
+ * wireless device can delay or kill its own Tx to accomodate.
  */
-struct iwl_bt_cmd {
+struct iwl3945_bt_cmd {
 	u8 flags;
 	u8 lead_time;
 	u8 max_kill;
@@ -1027,18 +1051,18 @@ struct iwl_bt_cmd {
 				 RXON_FILTER_ASSOC_MSK           | \
 				 RXON_FILTER_BCON_AWARE_MSK)
 
-struct iwl_measure_channel {
+struct iwl3945_measure_channel {
 	__le32 duration;	/* measurement duration in extended beacon
 				 * format */
 	u8 channel;		/* channel to measure */
-	u8 type;		/* see enum iwl_measure_type */
+	u8 type;		/* see enum iwl3945_measure_type */
 	__le16 reserved;
 } __attribute__ ((packed));
 
 /*
  * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
  */
-struct iwl_spectrum_cmd {
+struct iwl3945_spectrum_cmd {
 	__le16 len;		/* number of bytes starting from token */
 	u8 token;		/* token id */
 	u8 id;			/* measurement id -- 0 or 1 */
@@ -1051,13 +1075,13 @@ struct iwl_spectrum_cmd {
 	__le32 filter_flags;	/* rxon filter flags */
 	__le16 channel_count;	/* minimum 1, maximum 10 */
 	__le16 reserved3;
-	struct iwl_measure_channel channels[10];
+	struct iwl3945_measure_channel channels[10];
 } __attribute__ ((packed));
 
 /*
  * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
  */
-struct iwl_spectrum_resp {
+struct iwl3945_spectrum_resp {
 	u8 token;
 	u8 id;			/* id of the prior command replaced, or 0xff */
 	__le16 status;		/* 0 - command will be handled
@@ -1065,12 +1089,12 @@ struct iwl_spectrum_resp {
 				 *     measurement) */
 } __attribute__ ((packed));
 
-enum iwl_measurement_state {
+enum iwl3945_measurement_state {
 	IWL_MEASUREMENT_START = 0,
 	IWL_MEASUREMENT_STOP = 1,
 };
 
-enum iwl_measurement_status {
+enum iwl3945_measurement_status {
 	IWL_MEASUREMENT_OK = 0,
 	IWL_MEASUREMENT_CONCURRENT = 1,
 	IWL_MEASUREMENT_CSA_CONFLICT = 2,
@@ -1083,18 +1107,18 @@ enum iwl_measurement_status {
 
 #define NUM_ELEMENTS_IN_HISTOGRAM 8
 
-struct iwl_measurement_histogram {
+struct iwl3945_measurement_histogram {
 	__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 0.8usec counts */
 	__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 1usec counts */
 } __attribute__ ((packed));
 
 /* clear channel availability counters */
-struct iwl_measurement_cca_counters {
+struct iwl3945_measurement_cca_counters {
 	__le32 ofdm;
 	__le32 cck;
 } __attribute__ ((packed));
 
-enum iwl_measure_type {
+enum iwl3945_measure_type {
 	IWL_MEASURE_BASIC = (1 << 0),
 	IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
 	IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
@@ -1107,7 +1131,7 @@ enum iwl_measure_type {
 /*
  * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
  */
-struct iwl_spectrum_notification {
+struct iwl3945_spectrum_notification {
 	u8 id;			/* measurement id -- 0 or 1 */
 	u8 token;
 	u8 channel_index;	/* index in measurement channel list */
@@ -1115,7 +1139,7 @@ struct iwl_spectrum_notification {
 	__le32 start_time;	/* lower 32-bits of TSF */
 	u8 band;		/* 0 - 5.2GHz, 1 - 2.4GHz */
 	u8 channel;
-	u8 type;		/* see enum iwl_measurement_type */
+	u8 type;		/* see enum iwl3945_measurement_type */
 	u8 reserved1;
 	/* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
 	 * valid if applicable for measurement type requested. */
@@ -1125,9 +1149,9 @@ struct iwl_spectrum_notification {
 	u8 basic_type;		/* 0 - bss, 1 - ofdm preamble, 2 -
 				 * unidentified */
 	u8 reserved2[3];
-	struct iwl_measurement_histogram histogram;
+	struct iwl3945_measurement_histogram histogram;
 	__le32 stop_time;	/* lower 32-bits of TSF */
-	__le32 status;		/* see iwl_measurement_status */
+	__le32 status;		/* see iwl3945_measurement_status */
 } __attribute__ ((packed));
 
 /******************************************************************************
@@ -1137,7 +1161,7 @@ struct iwl_spectrum_notification {
  *****************************************************************************/
 
 /**
- * struct iwl_powertable_cmd - Power Table Command
+ * struct iwl3945_powertable_cmd - Power Table Command
  * @flags: See below:
  *
  * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
@@ -1166,41 +1190,21 @@ struct iwl_spectrum_notification {
  */
 #define IWL_POWER_VEC_SIZE 5
 
-
-#if IWL == 3945
-
-#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le32(1<<0)
-#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le32(1<<2)
-#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le32(1<<3)
-struct iwl_powertable_cmd {
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le32(1 << 0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le32(1 << 2)
+#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le32(1 << 3)
+struct iwl3945_powertable_cmd {
 	__le32 flags;
 	__le32 rx_data_timeout;
 	__le32 tx_data_timeout;
 	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
 } __attribute__((packed));
 
-#elif IWL == 4965
-
-#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le16(1<<0)
-#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le16(1<<2)
-#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le16(1<<3)
-
-struct iwl_powertable_cmd {
-	__le16 flags;
-	u8 keep_alive_seconds;
-	u8 debug_flags;
-	__le32 rx_data_timeout;
-	__le32 tx_data_timeout;
-	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
-	__le32 keep_alive_beacons;
-} __attribute__ ((packed));
-#endif
-
 /*
  * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
  * 3945 and 4965 identical.
  */
-struct iwl_sleep_notification {
+struct iwl3945_sleep_notification {
 	u8 pm_sleep_mode;
 	u8 pm_wakeup_src;
 	__le16 reserved;
@@ -1230,14 +1234,14 @@ enum {
 #define CARD_STATE_CMD_DISABLE 0x00	/* Put card to sleep */
 #define CARD_STATE_CMD_ENABLE  0x01	/* Wake up card */
 #define CARD_STATE_CMD_HALT    0x02	/* Power down permanently */
-struct iwl_card_state_cmd {
+struct iwl3945_card_state_cmd {
 	__le32 status;		/* CARD_STATE_CMD_* request new power state */
 } __attribute__ ((packed));
 
 /*
  * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
  */
-struct iwl_card_state_notif {
+struct iwl3945_card_state_notif {
 	__le32 flags;
 } __attribute__ ((packed));
 
@@ -1246,7 +1250,7 @@ struct iwl_card_state_notif {
 #define RF_CARD_DISABLED   0x04
 #define RXON_CARD_DISABLED 0x10
 
-struct iwl_ct_kill_config {
+struct iwl3945_ct_kill_config {
 	__le32   reserved;
 	__le32   critical_temperature_M;
 	__le32   critical_temperature_R;
@@ -1258,21 +1262,48 @@ struct iwl_ct_kill_config {
  *
  *****************************************************************************/
 
-struct iwl_scan_channel {
-	/* type is defined as:
-	 * 0:0 active (0 - passive)
-	 * 1:4 SSID direct
-	 *     If 1 is set then corresponding SSID IE is transmitted in probe
+/**
+ * struct iwl3945_scan_channel - entry in REPLY_SCAN_CMD channel table
+ *
+ * One for each channel in the scan list.
+ * Each channel can independently select:
+ * 1)  SSID for directed active scans
+ * 2)  Txpower setting (for rate specified within Tx command)
+ * 3)  How long to stay on-channel (behavior may be modified by quiet_time,
+ *     quiet_plcp_th, good_CRC_th)
+ *
+ * To avoid uCode errors, make sure the following are true (see comments
+ * under struct iwl3945_scan_cmd about max_out_time and quiet_time):
+ * 1)  If using passive_dwell (i.e. passive_dwell != 0):
+ *     active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
+ * 2)  quiet_time <= active_dwell
+ * 3)  If restricting off-channel time (i.e. max_out_time !=0):
+ *     passive_dwell < max_out_time
+ *     active_dwell < max_out_time
+ */
+struct iwl3945_scan_channel {
+	/*
+	 * type is defined as:
+	 * 0:0 1 = active, 0 = passive
+	 * 1:4 SSID direct bit map; if a bit is set, then corresponding
+	 *     SSID IE is transmitted in probe request.
 	 * 5:7 reserved
 	 */
 	u8 type;
-	u8 channel;
-	struct iwl_tx_power tpc;
-	__le16 active_dwell;
-	__le16 passive_dwell;
+	u8 channel;	/* band is selected by iwl3945_scan_cmd "flags" field */
+	struct iwl3945_tx_power tpc;
+	__le16 active_dwell;	/* in 1024-uSec TU (time units), typ 5-50 */
+	__le16 passive_dwell;	/* in 1024-uSec TU (time units), typ 20-500 */
 } __attribute__ ((packed));
 
-struct iwl_ssid_ie {
+/**
+ * struct iwl3945_ssid_ie - directed scan network information element
+ *
+ * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field
+ * in struct iwl3945_scan_channel; each channel may select different ssids from
+ * among the 4 entries.  SSID IEs get transmitted in reverse order of entry.
+ */
+struct iwl3945_ssid_ie {
 	u8 id;
 	u8 len;
 	u8 ssid[32];
@@ -1285,44 +1316,98 @@ struct iwl_ssid_ie {
 
 /*
  * REPLY_SCAN_CMD = 0x80 (command)
+ *
+ * The hardware scan command is very powerful; the driver can set it up to
+ * maintain (relatively) normal network traffic while doing a scan in the
+ * background.  The max_out_time and suspend_time control the ratio of how
+ * long the device stays on an associated network channel ("service channel")
+ * vs. how long it's away from the service channel, tuned to other channels
+ * for scanning.
+ *
+ * max_out_time is the max time off-channel (in usec), and suspend_time
+ * is how long (in "extended beacon" format) that the scan is "suspended"
+ * after returning to the service channel.  That is, suspend_time is the
+ * time that we stay on the service channel, doing normal work, between
+ * scan segments.  The driver may set these parameters differently to support
+ * scanning when associated vs. not associated, and light vs. heavy traffic
+ * loads when associated.
+ *
+ * After receiving this command, the device's scan engine does the following;
+ *
+ * 1)  Sends SCAN_START notification to driver
+ * 2)  Checks to see if it has time to do scan for one channel
+ * 3)  Sends NULL packet, with power-save (PS) bit set to 1,
+ *     to tell AP that we're going off-channel
+ * 4)  Tunes to first channel in scan list, does active or passive scan
+ * 5)  Sends SCAN_RESULT notification to driver
+ * 6)  Checks to see if it has time to do scan on *next* channel in list
+ * 7)  Repeats 4-6 until it no longer has time to scan the next channel
+ *     before max_out_time expires
+ * 8)  Returns to service channel
+ * 9)  Sends NULL packet with PS=0 to tell AP that we're back
+ * 10) Stays on service channel until suspend_time expires
+ * 11) Repeats entire process 2-10 until list is complete
+ * 12) Sends SCAN_COMPLETE notification
+ *
+ * For fast, efficient scans, the scan command also has support for staying on
+ * a channel for just a short time, if doing active scanning and getting no
+ * responses to the transmitted probe request.  This time is controlled by
+ * quiet_time, and the number of received packets below which a channel is
+ * considered "quiet" is controlled by quiet_plcp_threshold.
+ *
+ * For active scanning on channels that have regulatory restrictions against
+ * blindly transmitting, the scan can listen before transmitting, to make sure
+ * that there is already legitimate activity on the channel.  If enough
+ * packets are cleanly received on the channel (controlled by good_CRC_th,
+ * typical value 1), the scan engine starts transmitting probe requests.
+ *
+ * Driver must use separate scan commands for 2.4 vs. 5 GHz bands.
+ *
+ * To avoid uCode errors, see timing restrictions described under
+ * struct iwl3945_scan_channel.
  */
-struct iwl_scan_cmd {
+struct iwl3945_scan_cmd {
 	__le16 len;
 	u8 reserved0;
-	u8 channel_count;
-	__le16 quiet_time;     /* dwell only this long on quiet chnl
-				* (active scan) */
-	__le16 quiet_plcp_th;  /* quiet chnl is < this # pkts (typ. 1) */
-	__le16 good_CRC_th;    /* passive -> active promotion threshold */
-#if IWL == 3945
+	u8 channel_count;	/* # channels in channel list */
+	__le16 quiet_time;	/* dwell only this # millisecs on quiet channel
+				 * (only for active scan) */
+	__le16 quiet_plcp_th;	/* quiet chnl is < this # pkts (typ. 1) */
+	__le16 good_CRC_th;	/* passive -> active promotion threshold */
 	__le16 reserved1;
-#elif IWL == 4965
-	__le16 rx_chain;
-#endif
-	__le32 max_out_time;   /* max usec to be out of associated (service)
-				* chnl */
-	__le32 suspend_time;   /* pause scan this long when returning to svc
-				* chnl.
-				* 3945 -- 31:24 # beacons, 19:0 additional usec,
-				* 4965 -- 31:22 # beacons, 21:0 additional usec.
-				*/
-	__le32 flags;
-	__le32 filter_flags;
+	__le32 max_out_time;	/* max usec to be away from associated (service)
+				 * channel */
+	__le32 suspend_time;	/* pause scan this long (in "extended beacon
+				 * format") when returning to service channel:
+				 * 3945; 31:24 # beacons, 19:0 additional usec,
+				 * 4965; 31:22 # beacons, 21:0 additional usec.
+				 */
+	__le32 flags;		/* RXON_FLG_* */
+	__le32 filter_flags;	/* RXON_FILTER_* */
+
+	/* For active scans (set to all-0s for passive scans).
+	 * Does not include payload.  Must specify Tx rate; no rate scaling. */
+	struct iwl3945_tx_cmd tx_cmd;
+
+	/* For directed active scans (set to all-0s otherwise) */
+	struct iwl3945_ssid_ie direct_scan[PROBE_OPTION_MAX];
 
-	struct iwl_tx_cmd tx_cmd;
-	struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
-
-	u8 data[0];
 	/*
-	 * The channels start after the probe request payload and are of type:
+	 * Probe request frame, followed by channel list.
 	 *
-	 * struct iwl_scan_channel channels[0];
+	 * Size of probe request frame is specified by byte count in tx_cmd.
+	 * Channel list follows immediately after probe request frame.
+	 * Number of channels in list is specified by channel_count.
+	 * Each channel in list is of type:
 	 *
-	 * NOTE:  Only one band of channels can be scanned per pass.  You
-	 * can not mix 2.4GHz channels and 5.2GHz channels and must
-	 * request a scan multiple times (not concurrently)
+	 * struct iwl3945_scan_channel channels[0];
 	 *
+	 * NOTE:  Only one band of channels can be scanned per pass.  You
+	 * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
+	 * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
+	 * before requesting another scan.
 	 */
+	u8 data[0];
 } __attribute__ ((packed));
 
 /* Can abort will notify by complete notification with abort status. */
@@ -1333,14 +1418,14 @@ struct iwl_scan_cmd {
 /*
  * REPLY_SCAN_CMD = 0x80 (response)
  */
-struct iwl_scanreq_notification {
+struct iwl3945_scanreq_notification {
 	__le32 status;		/* 1: okay, 2: cannot fulfill request */
 } __attribute__ ((packed));
 
 /*
  * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
  */
-struct iwl_scanstart_notification {
+struct iwl3945_scanstart_notification {
 	__le32 tsf_low;
 	__le32 tsf_high;
 	__le32 beacon_timer;
@@ -1357,7 +1442,7 @@ struct iwl_scanstart_notification {
 /*
  * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
  */
-struct iwl_scanresults_notification {
+struct iwl3945_scanresults_notification {
 	u8 channel;
 	u8 band;
 	u8 reserved[2];
@@ -1369,7 +1454,7 @@ struct iwl_scanresults_notification {
 /*
  * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
  */
-struct iwl_scancomplete_notification {
+struct iwl3945_scancomplete_notification {
 	u8 scanned_channels;
 	u8 status;
 	u8 reserved;
@@ -1388,8 +1473,8 @@ struct iwl_scancomplete_notification {
 /*
  * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
  */
-struct iwl_beacon_notif {
-	struct iwl_tx_resp beacon_notify_hdr;
+struct iwl3945_beacon_notif {
+	struct iwl3945_tx_resp beacon_notify_hdr;
 	__le32 low_tsf;
 	__le32 high_tsf;
 	__le32 ibss_mgr_status;
@@ -1398,8 +1483,8 @@ struct iwl_beacon_notif {
 /*
  * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
  */
-struct iwl_tx_beacon_cmd {
-	struct iwl_tx_cmd tx;
+struct iwl3945_tx_beacon_cmd {
+	struct iwl3945_tx_cmd tx;
 	__le16 tim_idx;
 	u8 tim_size;
 	u8 reserved1;
@@ -1450,30 +1535,8 @@ struct statistics_rx_phy {
 	__le32 rxe_frame_limit_overrun;
 	__le32 sent_ack_cnt;
 	__le32 sent_cts_cnt;
-#if IWL == 4965
-	__le32 sent_ba_rsp_cnt;
-	__le32 dsp_self_kill;
-	__le32 mh_format_err;
-	__le32 re_acq_main_rssi_sum;
-	__le32 reserved3;
-#endif
 } __attribute__ ((packed));
 
-#if IWL == 4965
-struct statistics_rx_ht_phy {
-	__le32 plcp_err;
-	__le32 overrun_err;
-	__le32 early_overrun_err;
-	__le32 crc32_good;
-	__le32 crc32_err;
-	__le32 mh_format_err;
-	__le32 agg_crc32_good;
-	__le32 agg_mpdu_cnt;
-	__le32 agg_cnt;
-	__le32 reserved2;
-} __attribute__ ((packed));
-#endif
-
 struct statistics_rx_non_phy {
 	__le32 bogus_cts;	/* CTS received when not expecting CTS */
 	__le32 bogus_ack;	/* ACK received when not expecting ACK */
@@ -1483,57 +1546,13 @@ struct statistics_rx_non_phy {
 				 * filtering process */
 	__le32 non_channel_beacons;	/* beacons with our bss id but not on
 					 * our serving channel */
-#if IWL == 4965
-	__le32 channel_beacons;	/* beacons with our bss id and in our
-				 * serving channel */
-	__le32 num_missed_bcon;	/* number of missed beacons */
-	__le32 adc_rx_saturation_time;	/* count in 0.8us units the time the
-					 * ADC was in saturation */
-	__le32 ina_detection_search_time;/* total time (in 0.8us) searched
-					  * for INA */
-	__le32 beacon_silence_rssi_a;	/* RSSI silence after beacon frame */
-	__le32 beacon_silence_rssi_b;	/* RSSI silence after beacon frame */
-	__le32 beacon_silence_rssi_c;	/* RSSI silence after beacon frame */
-	__le32 interference_data_flag;	/* flag for interference data
-					 * availability. 1 when data is
-					 * available. */
-	__le32 channel_load;	/* counts RX Enable time */
-	__le32 dsp_false_alarms;	/* DSP false alarm (both OFDM
-					 * and CCK) counter */
-	__le32 beacon_rssi_a;
-	__le32 beacon_rssi_b;
-	__le32 beacon_rssi_c;
-	__le32 beacon_energy_a;
-	__le32 beacon_energy_b;
-	__le32 beacon_energy_c;
-#endif
 } __attribute__ ((packed));
 
 struct statistics_rx {
 	struct statistics_rx_phy ofdm;
 	struct statistics_rx_phy cck;
 	struct statistics_rx_non_phy general;
-#if IWL == 4965
-	struct statistics_rx_ht_phy ofdm_ht;
-#endif
-} __attribute__ ((packed));
-
-#if IWL == 4965
-struct statistics_tx_non_phy_agg {
-	__le32 ba_timeout;
-	__le32 ba_reschedule_frames;
-	__le32 scd_query_agg_frame_cnt;
-	__le32 scd_query_no_agg;
-	__le32 scd_query_agg;
-	__le32 scd_query_mismatch;
-	__le32 frame_not_ready;
-	__le32 underrun;
-	__le32 bt_prio_kill;
-	__le32 rx_ba_rsp_cnt;
-	__le32 reserved2;
-	__le32 reserved3;
 } __attribute__ ((packed));
-#endif
 
 struct statistics_tx {
 	__le32 preamble_cnt;
@@ -1545,14 +1564,6 @@ struct statistics_tx {
 	__le32 ack_timeout;
 	__le32 expected_ack_cnt;
 	__le32 actual_ack_cnt;
-#if IWL == 4965
-	__le32 dump_msdu_cnt;
-	__le32 burst_abort_next_frame_mismatch_cnt;
-	__le32 burst_abort_missing_next_frame_cnt;
-	__le32 cts_timeout_collision;
-	__le32 ack_or_ba_timeout_collision;
-	struct statistics_tx_non_phy_agg agg;
-#endif
 } __attribute__ ((packed));
 
 struct statistics_dbg {
@@ -1566,29 +1577,16 @@ struct statistics_div {
 	__le32 tx_on_b;
 	__le32 exec_time;
 	__le32 probe_time;
-#if IWL == 4965
-	__le32 reserved1;
-	__le32 reserved2;
-#endif
 } __attribute__ ((packed));
 
 struct statistics_general {
 	__le32 temperature;
-#if IWL == 4965
-	__le32 temperature_m;
-#endif
 	struct statistics_dbg dbg;
 	__le32 sleep_time;
 	__le32 slots_out;
 	__le32 slots_idle;
 	__le32 ttl_timestamp;
 	struct statistics_div div;
-#if IWL == 4965
-	__le32 rx_enable_counter;
-	__le32 reserved1;
-	__le32 reserved2;
-	__le32 reserved3;
-#endif
 } __attribute__ ((packed));
 
 /*
@@ -1608,7 +1606,7 @@ struct statistics_general {
  */
 #define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1)	/* see above */
 #define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
-struct iwl_statistics_cmd {
+struct iwl3945_statistics_cmd {
 	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
 } __attribute__ ((packed));
 
@@ -1629,7 +1627,7 @@ struct iwl_statistics_cmd {
  */
 #define STATISTICS_REPLY_FLG_BAND_24G_MSK         __constant_cpu_to_le32(0x2)
 #define STATISTICS_REPLY_FLG_FAT_MODE_MSK         __constant_cpu_to_le32(0x8)
-struct iwl_notif_statistics {
+struct iwl3945_notif_statistics {
 	__le32 flag;
 	struct statistics_rx rx;
 	struct statistics_tx tx;
@@ -1644,7 +1642,7 @@ struct iwl_notif_statistics {
  * then this notification will be sent. */
 #define CONSECUTIVE_MISSED_BCONS_TH 20
 
-struct iwl_missed_beacon_notif {
+struct iwl3945_missed_beacon_notif {
 	__le32 consequtive_missed_beacons;
 	__le32 total_missed_becons;
 	__le32 num_expected_beacons;
@@ -1660,12 +1658,12 @@ struct iwl_missed_beacon_notif {
 #define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
 #define HD_TABLE_SIZE  (11)
 
-struct iwl_sensitivity_cmd {
+struct iwl3945_sensitivity_cmd {
 	__le16 control;
 	__le16 table[HD_TABLE_SIZE];
 } __attribute__ ((packed));
 
-struct iwl_calibration_cmd {
+struct iwl3945_calibration_cmd {
 	u8 opCode;
 	u8 flags;
 	__le16 reserved;
@@ -1688,7 +1686,7 @@ struct iwl_calibration_cmd {
  * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
  * this command turns it on or off, or sets up a periodic blinking cycle.
  */
-struct iwl_led_cmd {
+struct iwl3945_led_cmd {
 	__le32 interval;	/* "interval" in uSec */
 	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
 	u8 off;			/* # intervals off while blinking;
@@ -1704,31 +1702,27 @@ struct iwl_led_cmd {
  *
  *****************************************************************************/
 
-struct iwl_rx_packet {
+struct iwl3945_rx_packet {
 	__le32 len;
-	struct iwl_cmd_header hdr;
+	struct iwl3945_cmd_header hdr;
 	union {
-		struct iwl_alive_resp alive_frame;
-		struct iwl_rx_frame rx_frame;
-		struct iwl_tx_resp tx_resp;
-		struct iwl_spectrum_notification spectrum_notif;
-		struct iwl_csa_notification csa_notif;
-		struct iwl_error_resp err_resp;
-		struct iwl_card_state_notif card_state_notif;
-		struct iwl_beacon_notif beacon_status;
-		struct iwl_add_sta_resp add_sta;
-		struct iwl_sleep_notification sleep_notif;
-		struct iwl_spectrum_resp spectrum;
-		struct iwl_notif_statistics stats;
-#if IWL == 4965
-		struct iwl_compressed_ba_resp compressed_ba;
-		struct iwl_missed_beacon_notif missed_beacon;
-#endif
+		struct iwl3945_alive_resp alive_frame;
+		struct iwl3945_rx_frame rx_frame;
+		struct iwl3945_tx_resp tx_resp;
+		struct iwl3945_spectrum_notification spectrum_notif;
+		struct iwl3945_csa_notification csa_notif;
+		struct iwl3945_error_resp err_resp;
+		struct iwl3945_card_state_notif card_state_notif;
+		struct iwl3945_beacon_notif beacon_status;
+		struct iwl3945_add_sta_resp add_sta;
+		struct iwl3945_sleep_notification sleep_notif;
+		struct iwl3945_spectrum_resp spectrum;
+		struct iwl3945_notif_statistics stats;
 		__le32 status;
 		u8 raw[0];
 	} u;
 } __attribute__ ((packed));
 
-#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl_rx_frame))
+#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl3945_rx_frame))
 
-#endif				/* __iwl_commands_h__ */
+#endif				/* __iwl3945_3945_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
index 72318d78957e..f853c6b9f76e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h
@@ -26,18 +26,18 @@
  *
  *****************************************************************************/
 
-#ifndef __iwl_debug_h__
-#define __iwl_debug_h__
+#ifndef __iwl3945_debug_h__
+#define __iwl3945_debug_h__
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-extern u32 iwl_debug_level;
+#ifdef CONFIG_IWL3945_DEBUG
+extern u32 iwl3945_debug_level;
 #define IWL_DEBUG(level, fmt, args...) \
-do { if (iwl_debug_level & (level)) \
+do { if (iwl3945_debug_level & (level)) \
   printk(KERN_ERR DRV_NAME": %c %s " fmt, \
 	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
 
 #define IWL_DEBUG_LIMIT(level, fmt, args...) \
-do { if ((iwl_debug_level & (level)) && net_ratelimit()) \
+do { if ((iwl3945_debug_level & (level)) && net_ratelimit()) \
   printk(KERN_ERR DRV_NAME": %c %s " fmt, \
 	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
 #else
@@ -47,7 +47,7 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...)
 static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
 {
 }
-#endif				/* CONFIG_IWLWIFI_DEBUG */
+#endif				/* CONFIG_IWL3945_DEBUG */
 
 /*
  * To use the debug system;
@@ -68,51 +68,51 @@ static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
  *
  * % cat /proc/net/iwl/debug_level
  *
- * you simply need to add your entry to the iwl_debug_levels array.
+ * you simply need to add your entry to the iwl3945_debug_levels array.
  *
  * If you do not see debug_level in /proc/net/iwl then you do not have
- * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration
+ * CONFIG_IWL3945_DEBUG defined in your kernel configuration
  *
  */
 
-#define IWL_DL_INFO          (1<<0)
-#define IWL_DL_MAC80211      (1<<1)
-#define IWL_DL_HOST_COMMAND  (1<<2)
-#define IWL_DL_STATE         (1<<3)
+#define IWL_DL_INFO          (1 << 0)
+#define IWL_DL_MAC80211      (1 << 1)
+#define IWL_DL_HOST_COMMAND  (1 << 2)
+#define IWL_DL_STATE         (1 << 3)
 
-#define IWL_DL_RADIO         (1<<7)
-#define IWL_DL_POWER         (1<<8)
-#define IWL_DL_TEMP          (1<<9)
+#define IWL_DL_RADIO         (1 << 7)
+#define IWL_DL_POWER         (1 << 8)
+#define IWL_DL_TEMP          (1 << 9)
 
-#define IWL_DL_NOTIF         (1<<10)
-#define IWL_DL_SCAN          (1<<11)
-#define IWL_DL_ASSOC         (1<<12)
-#define IWL_DL_DROP          (1<<13)
+#define IWL_DL_NOTIF         (1 << 10)
+#define IWL_DL_SCAN          (1 << 11)
+#define IWL_DL_ASSOC         (1 << 12)
+#define IWL_DL_DROP          (1 << 13)
 
-#define IWL_DL_TXPOWER       (1<<14)
+#define IWL_DL_TXPOWER       (1 << 14)
 
-#define IWL_DL_AP            (1<<15)
+#define IWL_DL_AP            (1 << 15)
 
-#define IWL_DL_FW            (1<<16)
-#define IWL_DL_RF_KILL       (1<<17)
-#define IWL_DL_FW_ERRORS     (1<<18)
+#define IWL_DL_FW            (1 << 16)
+#define IWL_DL_RF_KILL       (1 << 17)
+#define IWL_DL_FW_ERRORS     (1 << 18)
 
-#define IWL_DL_LED           (1<<19)
+#define IWL_DL_LED           (1 << 19)
 
-#define IWL_DL_RATE          (1<<20)
+#define IWL_DL_RATE          (1 << 20)
 
-#define IWL_DL_CALIB         (1<<21)
-#define IWL_DL_WEP           (1<<22)
-#define IWL_DL_TX            (1<<23)
-#define IWL_DL_RX            (1<<24)
-#define IWL_DL_ISR           (1<<25)
-#define IWL_DL_HT            (1<<26)
-#define IWL_DL_IO            (1<<27)
-#define IWL_DL_11H           (1<<28)
+#define IWL_DL_CALIB         (1 << 21)
+#define IWL_DL_WEP           (1 << 22)
+#define IWL_DL_TX            (1 << 23)
+#define IWL_DL_RX            (1 << 24)
+#define IWL_DL_ISR           (1 << 25)
+#define IWL_DL_HT            (1 << 26)
+#define IWL_DL_IO            (1 << 27)
+#define IWL_DL_11H           (1 << 28)
 
-#define IWL_DL_STATS         (1<<29)
-#define IWL_DL_TX_REPLY      (1<<30)
-#define IWL_DL_QOS           (1<<31)
+#define IWL_DL_STATS         (1 << 29)
+#define IWL_DL_TX_REPLY      (1 << 30)
+#define IWL_DL_QOS           (1 << 31)
 
 #define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
 #define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index fb5f0649f4f6..6e0187393af4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -8,7 +8,7 @@
  * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU Geeral Public License as
+ * it under the terms of version 2 of the GNU General Public License as
  * published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful, but
@@ -60,58 +60,646 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *****************************************************************************/
+/*
+ * Please use this file (iwl-3945-hw.h) only for hardware-related definitions.
+ * Please use iwl-3945-commands.h for uCode API definitions.
+ * Please use iwl-3945.h for driver implementation definitions.
+ */
 
 #ifndef __iwl_3945_hw__
 #define __iwl_3945_hw__
 
-#define IWL_RX_BUF_SIZE 3000
-/* card static random access memory (SRAM) for processor data and instructs */
+/*
+ * uCode queue management definitions ...
+ * Queue #4 is the command queue for 3945 and 4965.
+ */
+#define IWL_CMD_QUEUE_NUM       4
+
+/* Tx rates */
+#define IWL_CCK_RATES 4
+#define IWL_OFDM_RATES 8
+#define IWL_HT_RATES 0
+#define IWL_MAX_RATES  (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
+
+/* Time constants */
+#define SHORT_SLOT_TIME 9
+#define LONG_SLOT_TIME 20
+
+/* RSSI to dBm */
+#define IWL_RSSI_OFFSET	95
+
+/*
+ * EEPROM related constants, enums, and structures.
+ */
+
+/*
+ * EEPROM access time values:
+ *
+ * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG,
+ *   then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit
+ *   CSR_EEPROM_REG_BIT_CMD (0x2).
+ * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
+ * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
+ * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
+ */
+#define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
+#define IWL_EEPROM_ACCESS_DELAY		10   /* uSec */
+
+/*
+ * Regulatory channel usage flags in EEPROM struct iwl_eeprom_channel.flags.
+ *
+ * IBSS and/or AP operation is allowed *only* on those channels with
+ * (VALID && IBSS && ACTIVE && !RADAR).  This restriction is in place because
+ * RADAR detection is not supported by the 3945 driver, but is a
+ * requirement for establishing a new network for legal operation on channels
+ * requiring RADAR detection or restricting ACTIVE scanning.
+ *
+ * NOTE:  "WIDE" flag indicates that 20 MHz channel is supported;
+ *        3945 does not support FAT 40 MHz-wide channels.
+ *
+ * NOTE:  Using a channel inappropriately will result in a uCode error!
+ */
+enum {
+	EEPROM_CHANNEL_VALID = (1 << 0),	/* usable for this SKU/geo */
+	EEPROM_CHANNEL_IBSS = (1 << 1),		/* usable as an IBSS channel */
+	/* Bit 2 Reserved */
+	EEPROM_CHANNEL_ACTIVE = (1 << 3),	/* active scanning allowed */
+	EEPROM_CHANNEL_RADAR = (1 << 4),	/* radar detection required */
+	EEPROM_CHANNEL_WIDE = (1 << 5),		/* 20 MHz channel okay */
+	EEPROM_CHANNEL_NARROW = (1 << 6),	/* 10 MHz channel (not used) */
+	EEPROM_CHANNEL_DFS = (1 << 7),	/* dynamic freq selection candidate */
+};
+
+/* SKU Capabilities */
+#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE                (1 << 0)
+#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE                (1 << 1)
+#define EEPROM_SKU_CAP_OP_MODE_MRC                      (1 << 7)
+
+/* *regulatory* channel data from eeprom, one for each channel */
+struct iwl3945_eeprom_channel {
+	u8 flags;		/* flags copied from EEPROM */
+	s8 max_power_avg;	/* max power (dBm) on this chnl, limit 31 */
+} __attribute__ ((packed));
+
+/*
+ * Mapping of a Tx power level, at factory calibration temperature,
+ *   to a radio/DSP gain table index.
+ * One for each of 5 "sample" power levels in each band.
+ * v_det is measured at the factory, using the 3945's built-in power amplifier
+ *   (PA) output voltage detector.  This same detector is used during Tx of
+ *   long packets in normal operation to provide feedback as to proper output
+ *   level.
+ * Data copied from EEPROM.
+ * DO NOT ALTER THIS STRUCTURE!!!
+ */
+struct iwl3945_eeprom_txpower_sample {
+	u8 gain_index;		/* index into power (gain) setup table ... */
+	s8 power;		/* ... for this pwr level for this chnl group */
+	u16 v_det;		/* PA output voltage */
+} __attribute__ ((packed));
+
+/*
+ * Mappings of Tx power levels -> nominal radio/DSP gain table indexes.
+ * One for each channel group (a.k.a. "band") (1 for BG, 4 for A).
+ * Tx power setup code interpolates between the 5 "sample" power levels
+ *    to determine the nominal setup for a requested power level.
+ * Data copied from EEPROM.
+ * DO NOT ALTER THIS STRUCTURE!!!
+ */
+struct iwl3945_eeprom_txpower_group {
+	struct iwl3945_eeprom_txpower_sample samples[5];  /* 5 power levels */
+	s32 a, b, c, d, e;	/* coefficients for voltage->power
+				 * formula (signed) */
+	s32 Fa, Fb, Fc, Fd, Fe;	/* these modify coeffs based on
+				 * frequency (signed) */
+	s8 saturation_power;	/* highest power possible by h/w in this
+				 * band */
+	u8 group_channel;	/* "representative" channel # in this band */
+	s16 temperature;	/* h/w temperature at factory calib this band
+				 * (signed) */
+} __attribute__ ((packed));
+
+/*
+ * Temperature-based Tx-power compensation data, not band-specific.
+ * These coefficients are use to modify a/b/c/d/e coeffs based on
+ *   difference between current temperature and factory calib temperature.
+ * Data copied from EEPROM.
+ */
+struct iwl3945_eeprom_temperature_corr {
+	u32 Ta;
+	u32 Tb;
+	u32 Tc;
+	u32 Td;
+	u32 Te;
+} __attribute__ ((packed));
+
+/*
+ * EEPROM map
+ */
+struct iwl3945_eeprom {
+	u8 reserved0[16];
+#define EEPROM_DEVICE_ID                    (2*0x08)	/* 2 bytes */
+	u16 device_id;	/* abs.ofs: 16 */
+	u8 reserved1[2];
+#define EEPROM_PMC                          (2*0x0A)	/* 2 bytes */
+	u16 pmc;		/* abs.ofs: 20 */
+	u8 reserved2[20];
+#define EEPROM_MAC_ADDRESS                  (2*0x15)	/* 6  bytes */
+	u8 mac_address[6];	/* abs.ofs: 42 */
+	u8 reserved3[58];
+#define EEPROM_BOARD_REVISION               (2*0x35)	/* 2  bytes */
+	u16 board_revision;	/* abs.ofs: 106 */
+	u8 reserved4[11];
+#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1)	/* 9  bytes */
+	u8 board_pba_number[9];	/* abs.ofs: 119 */
+	u8 reserved5[8];
+#define EEPROM_VERSION                      (2*0x44)	/* 2  bytes */
+	u16 version;		/* abs.ofs: 136 */
+#define EEPROM_SKU_CAP                      (2*0x45)	/* 1  bytes */
+	u8 sku_cap;		/* abs.ofs: 138 */
+#define EEPROM_LEDS_MODE                    (2*0x45+1)	/* 1  bytes */
+	u8 leds_mode;		/* abs.ofs: 139 */
+#define EEPROM_OEM_MODE                     (2*0x46)	/* 2  bytes */
+	u16 oem_mode;
+#define EEPROM_WOWLAN_MODE                  (2*0x47)	/* 2  bytes */
+	u16 wowlan_mode;	/* abs.ofs: 142 */
+#define EEPROM_LEDS_TIME_INTERVAL           (2*0x48)	/* 2  bytes */
+	u16 leds_time_interval;	/* abs.ofs: 144 */
+#define EEPROM_LEDS_OFF_TIME                (2*0x49)	/* 1  bytes */
+	u8 leds_off_time;	/* abs.ofs: 146 */
+#define EEPROM_LEDS_ON_TIME                 (2*0x49+1)	/* 1  bytes */
+	u8 leds_on_time;	/* abs.ofs: 147 */
+#define EEPROM_ALMGOR_M_VERSION             (2*0x4A)	/* 1  bytes */
+	u8 almgor_m_version;	/* abs.ofs: 148 */
+#define EEPROM_ANTENNA_SWITCH_TYPE          (2*0x4A+1)	/* 1  bytes */
+	u8 antenna_switch_type;	/* abs.ofs: 149 */
+	u8 reserved6[42];
+#define EEPROM_REGULATORY_SKU_ID            (2*0x60)	/* 4  bytes */
+	u8 sku_id[4];		/* abs.ofs: 192 */
+
+/*
+ * Per-channel regulatory data.
+ *
+ * Each channel that *might* be supported by 3945 or 4965 has a fixed location
+ * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
+ * txpower (MSB).
+ *
+ * Entries immediately below are for 20 MHz channel width.  FAT (40 MHz)
+ * channels (only for 4965, not supported by 3945) appear later in the EEPROM.
+ *
+ * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+ */
+#define EEPROM_REGULATORY_BAND_1            (2*0x62)	/* 2  bytes */
+	u16 band_1_count;	/* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_1_CHANNELS   (2*0x63)	/* 28 bytes */
+	struct iwl3945_eeprom_channel band_1_channels[14];  /* abs.ofs: 196 */
+
+/*
+ * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196,
+ * 5.0 GHz channels 7, 8, 11, 12, 16
+ * (4915-5080MHz) (none of these is ever supported)
+ */
+#define EEPROM_REGULATORY_BAND_2            (2*0x71)	/* 2  bytes */
+	u16 band_2_count;	/* abs.ofs: 226 */
+#define EEPROM_REGULATORY_BAND_2_CHANNELS   (2*0x72)	/* 26 bytes */
+	struct iwl3945_eeprom_channel band_2_channels[13];  /* abs.ofs: 228 */
+
+/*
+ * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+ * (5170-5320MHz)
+ */
+#define EEPROM_REGULATORY_BAND_3            (2*0x7F)	/* 2  bytes */
+	u16 band_3_count;	/* abs.ofs: 254 */
+#define EEPROM_REGULATORY_BAND_3_CHANNELS   (2*0x80)	/* 24 bytes */
+	struct iwl3945_eeprom_channel band_3_channels[12];  /* abs.ofs: 256 */
+
+/*
+ * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+ * (5500-5700MHz)
+ */
+#define EEPROM_REGULATORY_BAND_4            (2*0x8C)	/* 2  bytes */
+	u16 band_4_count;	/* abs.ofs: 280 */
+#define EEPROM_REGULATORY_BAND_4_CHANNELS   (2*0x8D)	/* 22 bytes */
+	struct iwl3945_eeprom_channel band_4_channels[11];  /* abs.ofs: 282 */
+
+/*
+ * 5.7 GHz channels 145, 149, 153, 157, 161, 165
+ * (5725-5825MHz)
+ */
+#define EEPROM_REGULATORY_BAND_5            (2*0x98)	/* 2  bytes */
+	u16 band_5_count;	/* abs.ofs: 304 */
+#define EEPROM_REGULATORY_BAND_5_CHANNELS   (2*0x99)	/* 12 bytes */
+	struct iwl3945_eeprom_channel band_5_channels[6];  /* abs.ofs: 306 */
+
+	u8 reserved9[194];
+
+/*
+ * 3945 Txpower calibration data.
+ */
+#define EEPROM_TXPOWER_CALIB_GROUP0 0x200
+#define EEPROM_TXPOWER_CALIB_GROUP1 0x240
+#define EEPROM_TXPOWER_CALIB_GROUP2 0x280
+#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0
+#define EEPROM_TXPOWER_CALIB_GROUP4 0x300
+#define IWL_NUM_TX_CALIB_GROUPS 5
+	struct iwl3945_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS];
+/* abs.ofs: 512 */
+#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340
+	struct iwl3945_eeprom_temperature_corr corrections;  /* abs.ofs: 832 */
+	u8 reserved16[172];	/* fill out to full 1024 byte block */
+} __attribute__ ((packed));
+
+#define IWL_EEPROM_IMAGE_SIZE 1024
+
+/* End of EEPROM */
+
+
+#include "iwl-3945-commands.h"
+
+#define PCI_LINK_CTRL      0x0F0
+#define PCI_POWER_SOURCE   0x0C8
+#define PCI_REG_WUM8       0x0E8
+#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
+
+/*=== CSR (control and status registers) ===*/
+#define CSR_BASE    (0x000)
+
+#define CSR_SW_VER              (CSR_BASE+0x000)
+#define CSR_HW_IF_CONFIG_REG    (CSR_BASE+0x000) /* hardware interface config */
+#define CSR_INT_COALESCING      (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT                 (CSR_BASE+0x008) /* host interrupt status/ack */
+#define CSR_INT_MASK            (CSR_BASE+0x00c) /* host interrupt enable */
+#define CSR_FH_INT_STATUS       (CSR_BASE+0x010) /* busmaster int status/ack*/
+#define CSR_GPIO_IN             (CSR_BASE+0x018) /* read external chip pins */
+#define CSR_RESET               (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
+#define CSR_GP_CNTRL            (CSR_BASE+0x024)
+
+/*
+ * Hardware revision info
+ * Bit fields:
+ * 31-8:  Reserved
+ *  7-4:  Type of device:  0x0 = 4965, 0xd = 3945
+ *  3-2:  Revision step:  0 = A, 1 = B, 2 = C, 3 = D
+ *  1-0:  "Dash" value, as in A-1, etc.
+ */
+#define CSR_HW_REV              (CSR_BASE+0x028)
+
+/* EEPROM reads */
+#define CSR_EEPROM_REG          (CSR_BASE+0x02c)
+#define CSR_EEPROM_GP           (CSR_BASE+0x030)
+#define CSR_GP_UCODE		(CSR_BASE+0x044)
+#define CSR_UCODE_DRV_GP1       (CSR_BASE+0x054)
+#define CSR_UCODE_DRV_GP1_SET   (CSR_BASE+0x058)
+#define CSR_UCODE_DRV_GP1_CLR   (CSR_BASE+0x05c)
+#define CSR_UCODE_DRV_GP2       (CSR_BASE+0x060)
+#define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
+
+/* Analog phase-lock-loop configuration (3945 only)
+ * Set bit 24. */
+#define CSR_ANA_PLL_CFG         (CSR_BASE+0x20c)
+
+/* Bits for CSR_HW_IF_CONFIG_REG */
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB         (0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM         (0x00000200)
+#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC            (0x00000400)
+#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE         (0x00000800)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A    (0x00000000)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B    (0x00001000)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM     (0x00200000)
+
+/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
+ * acknowledged (reset) by host writing "1" to flagged bits. */
+#define CSR_INT_BIT_FH_RX        (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */
+#define CSR_INT_BIT_HW_ERR       (1 << 29) /* DMA hardware error FH_INT[31] */
+#define CSR_INT_BIT_DNLD         (1 << 28) /* uCode Download */
+#define CSR_INT_BIT_FH_TX        (1 << 27) /* Tx DMA FH_INT[1:0] */
+#define CSR_INT_BIT_MAC_CLK_ACTV (1 << 26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SW_ERR       (1 << 25) /* uCode error */
+#define CSR_INT_BIT_RF_KILL      (1 << 7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
+#define CSR_INT_BIT_CT_KILL      (1 << 6)  /* Critical temp (chip too hot) rfkill */
+#define CSR_INT_BIT_SW_RX        (1 << 3)  /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_WAKEUP       (1 << 1)  /* NIC controller waking up (pwr mgmt) */
+#define CSR_INT_BIT_ALIVE        (1 << 0)  /* uCode interrupts once it initializes */
+
+#define CSR_INI_SET_MASK	(CSR_INT_BIT_FH_RX   | \
+				 CSR_INT_BIT_HW_ERR  | \
+				 CSR_INT_BIT_FH_TX   | \
+				 CSR_INT_BIT_SW_ERR  | \
+				 CSR_INT_BIT_RF_KILL | \
+				 CSR_INT_BIT_SW_RX   | \
+				 CSR_INT_BIT_WAKEUP  | \
+				 CSR_INT_BIT_ALIVE)
+
+/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
+#define CSR_FH_INT_BIT_ERR       (1 << 31) /* Error */
+#define CSR_FH_INT_BIT_HI_PRIOR  (1 << 30) /* High priority Rx, bypass coalescing */
+#define CSR_FH_INT_BIT_RX_CHNL2  (1 << 18) /* Rx channel 2 (3945 only) */
+#define CSR_FH_INT_BIT_RX_CHNL1  (1 << 17) /* Rx channel 1 */
+#define CSR_FH_INT_BIT_RX_CHNL0  (1 << 16) /* Rx channel 0 */
+#define CSR_FH_INT_BIT_TX_CHNL6  (1 << 6)  /* Tx channel 6 (3945 only) */
+#define CSR_FH_INT_BIT_TX_CHNL1  (1 << 1)  /* Tx channel 1 */
+#define CSR_FH_INT_BIT_TX_CHNL0  (1 << 0)  /* Tx channel 0 */
+
+#define CSR_FH_INT_RX_MASK	(CSR_FH_INT_BIT_HI_PRIOR | \
+				 CSR_FH_INT_BIT_RX_CHNL2 | \
+				 CSR_FH_INT_BIT_RX_CHNL1 | \
+				 CSR_FH_INT_BIT_RX_CHNL0)
+
+#define CSR_FH_INT_TX_MASK	(CSR_FH_INT_BIT_TX_CHNL6 | \
+				 CSR_FH_INT_BIT_TX_CHNL1 | \
+				 CSR_FH_INT_BIT_TX_CHNL0)
+
+
+/* RESET */
+#define CSR_RESET_REG_FLAG_NEVO_RESET                (0x00000001)
+#define CSR_RESET_REG_FLAG_FORCE_NMI                 (0x00000002)
+#define CSR_RESET_REG_FLAG_SW_RESET                  (0x00000080)
+#define CSR_RESET_REG_FLAG_MASTER_DISABLED           (0x00000100)
+#define CSR_RESET_REG_FLAG_STOP_MASTER               (0x00000200)
+
+/* GP (general purpose) CONTROL */
+#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY        (0x00000001)
+#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE              (0x00000004)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ         (0x00000008)
+#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP         (0x00000010)
+
+#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN           (0x00000001)
+
+#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE         (0x07000000)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE         (0x04000000)
+#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW          (0x08000000)
+
+
+/* EEPROM REG */
+#define CSR_EEPROM_REG_READ_VALID_MSK	(0x00000001)
+#define CSR_EEPROM_REG_BIT_CMD		(0x00000002)
+
+/* EEPROM GP */
+#define CSR_EEPROM_GP_VALID_MSK		(0x00000006)
+#define CSR_EEPROM_GP_BAD_SIGNATURE	(0x00000000)
+#define CSR_EEPROM_GP_IF_OWNER_MSK	(0x00000180)
+
+/* UCODE DRV GP */
+#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP             (0x00000001)
+#define CSR_UCODE_SW_BIT_RFKILL                     (0x00000002)
+#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED           (0x00000004)
+#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT      (0x00000008)
+
+/* GPIO */
+#define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
+#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC                (0x00000000)
+#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC		CSR_GPIO_IN_BIT_AUX_POWER
+
+/* GI Chicken Bits */
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER  (0x20000000)
+
+/* CSR_ANA_PLL_CFG */
+#define CSR_ANA_PLL_CFG_SH		(0x00880300)
+
+/*=== HBUS (Host-side Bus) ===*/
+#define HBUS_BASE	(0x400)
+
+/*
+ * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
+ * structures, error log, event log, verifying uCode load).
+ * First write to address register, then read from or write to data register
+ * to complete the job.  Once the address register is set up, accesses to
+ * data registers auto-increment the address by one dword.
+ * Bit usage for address registers (read or write):
+ *  0-31:  memory address within device
+ */
+#define HBUS_TARG_MEM_RADDR     (HBUS_BASE+0x00c)
+#define HBUS_TARG_MEM_WADDR     (HBUS_BASE+0x010)
+#define HBUS_TARG_MEM_WDAT      (HBUS_BASE+0x018)
+#define HBUS_TARG_MEM_RDAT      (HBUS_BASE+0x01c)
+
+/*
+ * Registers for accessing device's internal peripheral registers
+ * (e.g. SCD, BSM, etc.).  First write to address register,
+ * then read from or write to data register to complete the job.
+ * Bit usage for address registers (read or write):
+ *  0-15:  register address (offset) within device
+ * 24-25:  (# bytes - 1) to read or write (e.g. 3 for dword)
+ */
+#define HBUS_TARG_PRPH_WADDR    (HBUS_BASE+0x044)
+#define HBUS_TARG_PRPH_RADDR    (HBUS_BASE+0x048)
+#define HBUS_TARG_PRPH_WDAT     (HBUS_BASE+0x04c)
+#define HBUS_TARG_PRPH_RDAT     (HBUS_BASE+0x050)
+
+/*
+ * Per-Tx-queue write pointer (index, really!) (3945 and 4965).
+ * Indicates index to next TFD that driver will fill (1 past latest filled).
+ * Bit usage:
+ *  0-7:  queue write index
+ * 11-8:  queue selector
+ */
+#define HBUS_TARG_WRPTR         (HBUS_BASE+0x060)
+
+/* SCD (3945 Tx Frame Scheduler) */
+#define SCD_BASE                        (CSR_BASE + 0x2E00)
+
+#define SCD_MODE_REG                    (SCD_BASE + 0x000)
+#define SCD_ARASTAT_REG                 (SCD_BASE + 0x004)
+#define SCD_TXFACT_REG                  (SCD_BASE + 0x010)
+#define SCD_TXF4MF_REG                  (SCD_BASE + 0x014)
+#define SCD_TXF5MF_REG                  (SCD_BASE + 0x020)
+#define SCD_SBYP_MODE_1_REG             (SCD_BASE + 0x02C)
+#define SCD_SBYP_MODE_2_REG             (SCD_BASE + 0x030)
+
+/*=== FH (data Flow Handler) ===*/
+#define FH_BASE     (0x800)
+
+#define FH_CBCC_TABLE           (FH_BASE+0x140)
+#define FH_TFDB_TABLE           (FH_BASE+0x180)
+#define FH_RCSR_TABLE           (FH_BASE+0x400)
+#define FH_RSSR_TABLE           (FH_BASE+0x4c0)
+#define FH_TCSR_TABLE           (FH_BASE+0x500)
+#define FH_TSSR_TABLE           (FH_BASE+0x680)
+
+/* TFDB (Transmit Frame Buffer Descriptor) */
+#define FH_TFDB(_channel, buf) \
+	(FH_TFDB_TABLE+((_channel)*2+(buf))*0x28)
+#define ALM_FH_TFDB_CHNL_BUF_CTRL_REG(_channel) \
+	(FH_TFDB_TABLE + 0x50 * _channel)
+/* CBCC _channel is [0,2] */
+#define FH_CBCC(_channel)           (FH_CBCC_TABLE+(_channel)*0x8)
+#define FH_CBCC_CTRL(_channel)      (FH_CBCC(_channel)+0x00)
+#define FH_CBCC_BASE(_channel)      (FH_CBCC(_channel)+0x04)
+
+/* RCSR _channel is [0,2] */
+#define FH_RCSR(_channel)           (FH_RCSR_TABLE+(_channel)*0x40)
+#define FH_RCSR_CONFIG(_channel)    (FH_RCSR(_channel)+0x00)
+#define FH_RCSR_RBD_BASE(_channel)  (FH_RCSR(_channel)+0x04)
+#define FH_RCSR_WPTR(_channel)      (FH_RCSR(_channel)+0x20)
+#define FH_RCSR_RPTR_ADDR(_channel) (FH_RCSR(_channel)+0x24)
+
+#define FH_RSCSR_CHNL0_WPTR        (FH_RCSR_WPTR(0))
+
+/* RSSR */
+#define FH_RSSR_CTRL            (FH_RSSR_TABLE+0x000)
+#define FH_RSSR_STATUS          (FH_RSSR_TABLE+0x004)
+/* TCSR */
+#define FH_TCSR(_channel)           (FH_TCSR_TABLE+(_channel)*0x20)
+#define FH_TCSR_CONFIG(_channel)    (FH_TCSR(_channel)+0x00)
+#define FH_TCSR_CREDIT(_channel)    (FH_TCSR(_channel)+0x04)
+#define FH_TCSR_BUFF_STTS(_channel) (FH_TCSR(_channel)+0x08)
+/* TSSR */
+#define FH_TSSR_CBB_BASE        (FH_TSSR_TABLE+0x000)
+#define FH_TSSR_MSG_CONFIG      (FH_TSSR_TABLE+0x008)
+#define FH_TSSR_TX_STATUS       (FH_TSSR_TABLE+0x010)
+
+
+/* DBM */
+
+#define ALM_FH_SRVC_CHNL                            (6)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE     (20)
+#define ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH      (4)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN    (0x08000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE        (0x80000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE           (0x20000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128         (0x01000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST         (0x00001000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH               (0x00000000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF              (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER           (0x00000001)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT            (0x00000000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
+
+#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00004000)
+
+#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR           (0x00000001)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON      (0xFF000000)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON      (0x00FF0000)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B    (0x00000400)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON       (0x00000100)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON       (0x00000080)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH     (0x00000020)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH           (0x00000005)
+
+#define ALM_TB_MAX_BYTES_COUNT      (0xFFF0)
+
+#define ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) \
+	((1LU << _channel) << 24)
+#define ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel) \
+	((1LU << _channel) << 16)
+
+#define ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_channel) \
+	(ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) | \
+	 ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel))
+#define PCI_CFG_REV_ID_BIT_BASIC_SKU                (0x40)	/* bit 6    */
+#define PCI_CFG_REV_ID_BIT_RTP                      (0x80)	/* bit 7    */
+
+#define TFD_QUEUE_MIN           0
+#define TFD_QUEUE_MAX           6
+#define TFD_QUEUE_SIZE_MAX      (256)
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+#define IWL_DEFAULT_TX_RETRY  15
+
+/*********************************************/
+
+#define RFD_SIZE                              4
+#define NUM_TFD_CHUNKS                        4
+
+#define RX_QUEUE_SIZE                         256
+#define RX_QUEUE_MASK                         255
+#define RX_QUEUE_SIZE_LOG                     8
+
+#define U32_PAD(n)		((4-(n))&0x3)
+
+#define TFD_CTL_COUNT_SET(n)       (n << 24)
+#define TFD_CTL_COUNT_GET(ctl)     ((ctl >> 24) & 7)
+#define TFD_CTL_PAD_SET(n)         (n << 28)
+#define TFD_CTL_PAD_GET(ctl)       (ctl >> 28)
+
+#define TFD_TX_CMD_SLOTS 256
+#define TFD_CMD_SLOTS 32
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl3945_cmd) - \
+			      sizeof(struct iwl3945_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+/* Sizes and addresses for instruction and data memory (SRAM) in
+ * 3945's embedded processor.  Driver access is via HBUS_TARG_MEM_* regs. */
+#define RTC_INST_LOWER_BOUND			(0x000000)
 #define ALM_RTC_INST_UPPER_BOUND		(0x014000)
+
+#define RTC_DATA_LOWER_BOUND			(0x800000)
 #define ALM_RTC_DATA_UPPER_BOUND		(0x808000)
 
 #define ALM_RTC_INST_SIZE (ALM_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
 #define ALM_RTC_DATA_SIZE (ALM_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
 
-#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE
 #define IWL_MAX_INST_SIZE ALM_RTC_INST_SIZE
 #define IWL_MAX_DATA_SIZE ALM_RTC_DATA_SIZE
+
+/* Size of uCode instruction memory in bootstrap state machine */
+#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE
+
 #define IWL_MAX_NUM_QUEUES	8
 
-static inline int iwl_hw_valid_rtc_data_addr(u32 addr)
+static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
 {
 	return (addr >= RTC_DATA_LOWER_BOUND) &&
 	       (addr < ALM_RTC_DATA_UPPER_BOUND);
 }
 
-/* Base physical address of iwl_shared is provided to FH_TSSR_CBB_BASE
- * and &iwl_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */
-struct iwl_shared {
+/* Base physical address of iwl3945_shared is provided to FH_TSSR_CBB_BASE
+ * and &iwl3945_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */
+struct iwl3945_shared {
 	__le32 tx_base_ptr[8];
 	__le32 rx_read_ptr[3];
 } __attribute__ ((packed));
 
-struct iwl_tfd_frame_data {
+struct iwl3945_tfd_frame_data {
 	__le32 addr;
 	__le32 len;
 } __attribute__ ((packed));
 
-struct iwl_tfd_frame {
+struct iwl3945_tfd_frame {
 	__le32 control_flags;
-	struct iwl_tfd_frame_data pa[4];
+	struct iwl3945_tfd_frame_data pa[4];
 	u8 reserved[28];
 } __attribute__ ((packed));
 
-static inline u8 iwl_hw_get_rate(__le16 rate_n_flags)
+static inline u8 iwl3945_hw_get_rate(__le16 rate_n_flags)
 {
 	return le16_to_cpu(rate_n_flags) & 0xFF;
 }
 
-static inline u16 iwl_hw_get_rate_n_flags(__le16 rate_n_flags)
+static inline u16 iwl3945_hw_get_rate_n_flags(__le16 rate_n_flags)
 {
 	return le16_to_cpu(rate_n_flags);
 }
 
-static inline __le16 iwl_hw_set_rate_n_flags(u8 rate, u16 flags)
+static inline __le16 iwl3945_hw_set_rate_n_flags(u8 rate, u16 flags)
 {
 	return cpu_to_le16((u16)rate|flags);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
new file mode 100644
index 000000000000..75e20d0a20d1
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h
@@ -0,0 +1,431 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl3945_io_h__
+#define __iwl3945_io_h__
+
+#include <linux/io.h>
+
+#include "iwl-3945-debug.h"
+
+/*
+ * IO, register, and NIC memory access functions
+ *
+ * NOTE on naming convention and macro usage for these
+ *
+ * A single _ prefix before a an access function means that no state
+ * check or debug information is printed when that function is called.
+ *
+ * A double __ prefix before an access function means that state is checked
+ * and the current line number is printed in addition to any other debug output.
+ *
+ * The non-prefixed name is the #define that maps the caller into a
+ * #define that provides the caller's __LINE__ to the double prefix version.
+ *
+ * If you wish to call the function without any debug or state checking,
+ * you should use the single _ prefix version (as is used by dependent IO
+ * routines, for example _iwl3945_read_direct32 calls the non-check version of
+ * _iwl3945_read32.)
+ *
+ * These declarations are *extremely* useful in quickly isolating code deltas
+ * which result in misconfiguring of the hardware I/O.  In combination with
+ * git-bisect and the IO debug level you can quickly determine the specific
+ * commit which breaks the IO sequence to the hardware.
+ *
+ */
+
+#define _iwl3945_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *iwl,
+				 u32 ofs, u32 val)
+{
+	IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l);
+	_iwl3945_write32(iwl, ofs, val);
+}
+#define iwl3945_write32(iwl, ofs, val) \
+	__iwl3945_write32(__FILE__, __LINE__, iwl, ofs, val)
+#else
+#define iwl3945_write32(iwl, ofs, val) _iwl3945_write32(iwl, ofs, val)
+#endif
+
+#define _iwl3945_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWL3945_DEBUG
+static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *iwl, u32 ofs)
+{
+	IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
+	return _iwl3945_read32(iwl, ofs);
+}
+#define iwl3945_read32(iwl, ofs) __iwl3945_read32(__FILE__, __LINE__, iwl, ofs)
+#else
+#define iwl3945_read32(p, o) _iwl3945_read32(p, o)
+#endif
+
+static inline int _iwl3945_poll_bit(struct iwl3945_priv *priv, u32 addr,
+				u32 bits, u32 mask, int timeout)
+{
+	int i = 0;
+
+	do {
+		if ((_iwl3945_read32(priv, addr) & mask) == (bits & mask))
+			return i;
+		mdelay(10);
+		i += 10;
+	} while (i < timeout);
+
+	return -ETIMEDOUT;
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline int __iwl3945_poll_bit(const char *f, u32 l,
+				 struct iwl3945_priv *priv, u32 addr,
+				 u32 bits, u32 mask, int timeout)
+{
+	int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout);
+	if (unlikely(ret  == -ETIMEDOUT))
+		IWL_DEBUG_IO
+		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n",
+		     addr, bits, mask, f, l);
+	else
+		IWL_DEBUG_IO
+		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n",
+		     addr, bits, mask, ret, f, l);
+	return ret;
+}
+#define iwl3945_poll_bit(iwl, addr, bits, mask, timeout) \
+	__iwl3945_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
+#else
+#define iwl3945_poll_bit(p, a, b, m, t) _iwl3945_poll_bit(p, a, b, m, t)
+#endif
+
+static inline void _iwl3945_set_bit(struct iwl3945_priv *priv, u32 reg, u32 mask)
+{
+	_iwl3945_write32(priv, reg, _iwl3945_read32(priv, reg) | mask);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_set_bit(const char *f, u32 l,
+				 struct iwl3945_priv *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl3945_read32(priv, reg) | mask;
+	IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+	_iwl3945_write32(priv, reg, val);
+}
+#define iwl3945_set_bit(p, r, m) __iwl3945_set_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl3945_set_bit(p, r, m) _iwl3945_set_bit(p, r, m)
+#endif
+
+static inline void _iwl3945_clear_bit(struct iwl3945_priv *priv, u32 reg, u32 mask)
+{
+	_iwl3945_write32(priv, reg, _iwl3945_read32(priv, reg) & ~mask);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_clear_bit(const char *f, u32 l,
+				   struct iwl3945_priv *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl3945_read32(priv, reg) & ~mask;
+	IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+	_iwl3945_write32(priv, reg, val);
+}
+#define iwl3945_clear_bit(p, r, m) __iwl3945_clear_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl3945_clear_bit(p, r, m) _iwl3945_clear_bit(p, r, m)
+#endif
+
+static inline int _iwl3945_grab_nic_access(struct iwl3945_priv *priv)
+{
+	int ret;
+	u32 gp_ctl;
+
+#ifdef CONFIG_IWL3945_DEBUG
+	if (atomic_read(&priv->restrict_refcnt))
+		return 0;
+#endif
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+	    test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+		IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
+			"wakes up NIC\n");
+
+		/* 10 msec allows time for NIC to complete its data save */
+		gp_ctl = _iwl3945_read32(priv, CSR_GP_CNTRL);
+		if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
+			IWL_DEBUG_RF_KILL("Wait for complete power-down, "
+				"gpctl = 0x%08x\n", gp_ctl);
+			mdelay(10);
+		} else
+			IWL_DEBUG_RF_KILL("power-down complete, "
+					  "gpctl = 0x%08x\n", gp_ctl);
+	}
+
+	/* this bit wakes up the NIC */
+	_iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	ret = _iwl3945_poll_bit(priv, CSR_GP_CNTRL,
+			   CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50);
+	if (ret < 0) {
+		IWL_ERROR("MAC is in deep sleep!\n");
+		return -EIO;
+	}
+
+#ifdef CONFIG_IWL3945_DEBUG
+	atomic_inc(&priv->restrict_refcnt);
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_IWL3945_DEBUG
+static inline int __iwl3945_grab_nic_access(const char *f, u32 l,
+					       struct iwl3945_priv *priv)
+{
+	if (atomic_read(&priv->restrict_refcnt))
+		IWL_DEBUG_INFO("Grabbing access while already held at "
+			       "line %d.\n", l);
+
+	IWL_DEBUG_IO("grabbing nic access - %s %d\n", f, l);
+	return _iwl3945_grab_nic_access(priv);
+}
+#define iwl3945_grab_nic_access(priv) \
+	__iwl3945_grab_nic_access(__FILE__, __LINE__, priv)
+#else
+#define iwl3945_grab_nic_access(priv) \
+	_iwl3945_grab_nic_access(priv)
+#endif
+
+static inline void _iwl3945_release_nic_access(struct iwl3945_priv *priv)
+{
+#ifdef CONFIG_IWL3945_DEBUG
+	if (atomic_dec_and_test(&priv->restrict_refcnt))
+#endif
+		_iwl3945_clear_bit(priv, CSR_GP_CNTRL,
+			       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_release_nic_access(const char *f, u32 l,
+					    struct iwl3945_priv *priv)
+{
+	if (atomic_read(&priv->restrict_refcnt) <= 0)
+		IWL_ERROR("Release unheld nic access at line %d.\n", l);
+
+	IWL_DEBUG_IO("releasing nic access - %s %d\n", f, l);
+	_iwl3945_release_nic_access(priv);
+}
+#define iwl3945_release_nic_access(priv) \
+	__iwl3945_release_nic_access(__FILE__, __LINE__, priv)
+#else
+#define iwl3945_release_nic_access(priv) \
+	_iwl3945_release_nic_access(priv)
+#endif
+
+static inline u32 _iwl3945_read_direct32(struct iwl3945_priv *priv, u32 reg)
+{
+	return _iwl3945_read32(priv, reg);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline u32 __iwl3945_read_direct32(const char *f, u32 l,
+					struct iwl3945_priv *priv, u32 reg)
+{
+	u32 value = _iwl3945_read_direct32(priv, reg);
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from %s %d\n", f, l);
+	IWL_DEBUG_IO("read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value,
+		     f, l);
+	return value;
+}
+#define iwl3945_read_direct32(priv, reg) \
+	__iwl3945_read_direct32(__FILE__, __LINE__, priv, reg)
+#else
+#define iwl3945_read_direct32 _iwl3945_read_direct32
+#endif
+
+static inline void _iwl3945_write_direct32(struct iwl3945_priv *priv,
+					 u32 reg, u32 value)
+{
+	_iwl3945_write32(priv, reg, value);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static void __iwl3945_write_direct32(u32 line,
+				   struct iwl3945_priv *priv, u32 reg, u32 value)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	_iwl3945_write_direct32(priv, reg, value);
+}
+#define iwl3945_write_direct32(priv, reg, value) \
+	__iwl3945_write_direct32(__LINE__, priv, reg, value)
+#else
+#define iwl3945_write_direct32 _iwl3945_write_direct32
+#endif
+
+static inline void iwl3945_write_reg_buf(struct iwl3945_priv *priv,
+					       u32 reg, u32 len, u32 *values)
+{
+	u32 count = sizeof(u32);
+
+	if ((priv != NULL) && (values != NULL)) {
+		for (; 0 < len; len -= count, reg += count, values++)
+			_iwl3945_write_direct32(priv, reg, *values);
+	}
+}
+
+static inline int _iwl3945_poll_direct_bit(struct iwl3945_priv *priv,
+					   u32 addr, u32 mask, int timeout)
+{
+	int i = 0;
+
+	do {
+		if ((_iwl3945_read_direct32(priv, addr) & mask) == mask)
+			return i;
+		mdelay(10);
+		i += 10;
+	} while (i < timeout);
+
+	return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_IWL3945_DEBUG
+static inline int __iwl3945_poll_direct_bit(const char *f, u32 l,
+					    struct iwl3945_priv *priv,
+					    u32 addr, u32 mask, int timeout)
+{
+	int ret  = _iwl3945_poll_direct_bit(priv, addr, mask, timeout);
+
+	if (unlikely(ret == -ETIMEDOUT))
+		IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) - "
+			     "timedout - %s %d\n", addr, mask, f, l);
+	else
+		IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) = 0x%08X "
+			     "- %s %d\n", addr, mask, ret, f, l);
+	return ret;
+}
+#define iwl3945_poll_direct_bit(iwl, addr, mask, timeout) \
+	__iwl3945_poll_direct_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
+#else
+#define iwl3945_poll_direct_bit _iwl3945_poll_direct_bit
+#endif
+
+static inline u32 _iwl3945_read_prph(struct iwl3945_priv *priv, u32 reg)
+{
+	_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+	return _iwl3945_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline u32 __iwl3945_read_prph(u32 line, struct iwl3945_priv *priv, u32 reg)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	return _iwl3945_read_prph(priv, reg);
+}
+
+#define iwl3945_read_prph(priv, reg) \
+	__iwl3945_read_prph(__LINE__, priv, reg)
+#else
+#define iwl3945_read_prph _iwl3945_read_prph
+#endif
+
+static inline void _iwl3945_write_prph(struct iwl3945_priv *priv,
+					     u32 addr, u32 val)
+{
+	_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
+			      ((addr & 0x0000FFFF) | (3 << 24)));
+	_iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
+}
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_write_prph(u32 line, struct iwl3945_priv *priv,
+					      u32 addr, u32 val)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access from line %d\n", line);
+	_iwl3945_write_prph(priv, addr, val);
+}
+
+#define iwl3945_write_prph(priv, addr, val) \
+	__iwl3945_write_prph(__LINE__, priv, addr, val);
+#else
+#define iwl3945_write_prph _iwl3945_write_prph
+#endif
+
+#define _iwl3945_set_bits_prph(priv, reg, mask) \
+	_iwl3945_write_prph(priv, reg, (_iwl3945_read_prph(priv, reg) | mask))
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_set_bits_prph(u32 line, struct iwl3945_priv *priv,
+					u32 reg, u32 mask)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+
+	_iwl3945_set_bits_prph(priv, reg, mask);
+}
+#define iwl3945_set_bits_prph(priv, reg, mask) \
+	__iwl3945_set_bits_prph(__LINE__, priv, reg, mask)
+#else
+#define iwl3945_set_bits_prph _iwl3945_set_bits_prph
+#endif
+
+#define _iwl3945_set_bits_mask_prph(priv, reg, bits, mask) \
+	_iwl3945_write_prph(priv, reg, ((_iwl3945_read_prph(priv, reg) & mask) | bits))
+
+#ifdef CONFIG_IWL3945_DEBUG
+static inline void __iwl3945_set_bits_mask_prph(u32 line,
+		struct iwl3945_priv *priv, u32 reg, u32 bits, u32 mask)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	_iwl3945_set_bits_mask_prph(priv, reg, bits, mask);
+}
+#define iwl3945_set_bits_mask_prph(priv, reg, bits, mask) \
+	__iwl3945_set_bits_mask_prph(__LINE__, priv, reg, bits, mask)
+#else
+#define iwl3945_set_bits_mask_prph _iwl3945_set_bits_mask_prph
+#endif
+
+static inline void iwl3945_clear_bits_prph(struct iwl3945_priv
+						 *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl3945_read_prph(priv, reg);
+	_iwl3945_write_prph(priv, reg, (val & ~mask));
+}
+
+static inline u32 iwl3945_read_targ_mem(struct iwl3945_priv *priv, u32 addr)
+{
+	iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
+	return iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+}
+
+static inline void iwl3945_write_targ_mem(struct iwl3945_priv *priv, u32 addr, u32 val)
+{
+	iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
+}
+
+static inline void iwl3945_write_targ_mem_buf(struct iwl3945_priv *priv, u32 addr,
+					  u32 len, u32 *values)
+{
+	iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	for (; 0 < len; len -= sizeof(u32), values++)
+		iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index c48b1b537d2b..80d31ae51e77 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -37,15 +37,13 @@
 
 #include <linux/workqueue.h>
 
-#define IWL 3945
-
 #include "../net/mac80211/ieee80211_rate.h"
 
-#include "iwlwifi.h"
+#include "iwl-3945.h"
 
 #define RS_NAME "iwl-3945-rs"
 
-struct iwl_rate_scale_data {
+struct iwl3945_rate_scale_data {
 	u64 data;
 	s32 success_counter;
 	s32 success_ratio;
@@ -54,7 +52,7 @@ struct iwl_rate_scale_data {
 	unsigned long stamp;
 };
 
-struct iwl_rate_scale_priv {
+struct iwl3945_rs_sta {
 	spinlock_t lock;
 	s32 *expected_tpt;
 	unsigned long last_partial_flush;
@@ -67,31 +65,31 @@ struct iwl_rate_scale_priv {
 	u8 start_rate;
 	u8 ibss_sta_added;
 	struct timer_list rate_scale_flush;
-	struct iwl_rate_scale_data win[IWL_RATE_COUNT];
+	struct iwl3945_rate_scale_data win[IWL_RATE_COUNT];
 };
 
-static s32 iwl_expected_tpt_g[IWL_RATE_COUNT] = {
+static s32 iwl3945_expected_tpt_g[IWL_RATE_COUNT] = {
 	7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202
 };
 
-static s32 iwl_expected_tpt_g_prot[IWL_RATE_COUNT] = {
+static s32 iwl3945_expected_tpt_g_prot[IWL_RATE_COUNT] = {
 	7, 13, 35, 58, 0, 0, 0, 80, 93, 113, 123, 125
 };
 
-static s32 iwl_expected_tpt_a[IWL_RATE_COUNT] = {
+static s32 iwl3945_expected_tpt_a[IWL_RATE_COUNT] = {
 	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186
 };
 
-static s32 iwl_expected_tpt_b[IWL_RATE_COUNT] = {
+static s32 iwl3945_expected_tpt_b[IWL_RATE_COUNT] = {
 	7, 13, 35, 58, 0, 0, 0, 0, 0, 0, 0, 0
 };
 
-struct iwl_tpt_entry {
+struct iwl3945_tpt_entry {
 	s8 min_rssi;
 	u8 index;
 };
 
-static struct iwl_tpt_entry iwl_tpt_table_a[] = {
+static struct iwl3945_tpt_entry iwl3945_tpt_table_a[] = {
 	{-60, IWL_RATE_54M_INDEX},
 	{-64, IWL_RATE_48M_INDEX},
 	{-72, IWL_RATE_36M_INDEX},
@@ -102,7 +100,7 @@ static struct iwl_tpt_entry iwl_tpt_table_a[] = {
 	{-89, IWL_RATE_6M_INDEX}
 };
 
-static struct iwl_tpt_entry iwl_tpt_table_b[] = {
+static struct iwl3945_tpt_entry iwl3945_tpt_table_b[] = {
 	{-86, IWL_RATE_11M_INDEX},
 	{-88, IWL_RATE_5M_INDEX},
 	{-90, IWL_RATE_2M_INDEX},
@@ -110,7 +108,7 @@ static struct iwl_tpt_entry iwl_tpt_table_b[] = {
 
 };
 
-static struct iwl_tpt_entry iwl_tpt_table_g[] = {
+static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = {
 	{-60, IWL_RATE_54M_INDEX},
 	{-64, IWL_RATE_48M_INDEX},
 	{-68, IWL_RATE_36M_INDEX},
@@ -131,30 +129,30 @@ static struct iwl_tpt_entry iwl_tpt_table_g[] = {
 #define IWL_RATE_MIN_SUCCESS_TH       8
 #define IWL_RATE_DECREASE_TH       1920
 
-static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode)
+static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, u8 mode)
 {
 	u32 index = 0;
 	u32 table_size = 0;
-	struct iwl_tpt_entry *tpt_table = NULL;
+	struct iwl3945_tpt_entry *tpt_table = NULL;
 
 	if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL))
 		rssi = IWL_MIN_RSSI_VAL;
 
 	switch (mode) {
 	case MODE_IEEE80211G:
-		tpt_table = iwl_tpt_table_g;
-		table_size = ARRAY_SIZE(iwl_tpt_table_g);
+		tpt_table = iwl3945_tpt_table_g;
+		table_size = ARRAY_SIZE(iwl3945_tpt_table_g);
 		break;
 
 	case MODE_IEEE80211A:
-		tpt_table = iwl_tpt_table_a;
-		table_size = ARRAY_SIZE(iwl_tpt_table_a);
+		tpt_table = iwl3945_tpt_table_a;
+		table_size = ARRAY_SIZE(iwl3945_tpt_table_a);
 		break;
 
 	default:
 	case MODE_IEEE80211B:
-		tpt_table = iwl_tpt_table_b;
-		table_size = ARRAY_SIZE(iwl_tpt_table_b);
+		tpt_table = iwl3945_tpt_table_b;
+		table_size = ARRAY_SIZE(iwl3945_tpt_table_b);
 		break;
 	}
 
@@ -166,7 +164,7 @@ static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode)
 	return tpt_table[index].index;
 }
 
-static void iwl_clear_window(struct iwl_rate_scale_data *window)
+static void iwl3945_clear_window(struct iwl3945_rate_scale_data *window)
 {
 	window->data = 0;
 	window->success_counter = 0;
@@ -177,13 +175,13 @@ static void iwl_clear_window(struct iwl_rate_scale_data *window)
 }
 
 /**
- * iwl_rate_scale_flush_windows - flush out the rate scale windows
+ * iwl3945_rate_scale_flush_windows - flush out the rate scale windows
  *
  * Returns the number of windows that have gathered data but were
  * not flushed.  If there were any that were not flushed, then
  * reschedule the rate flushing routine.
  */
-static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv)
+static int iwl3945_rate_scale_flush_windows(struct iwl3945_rs_sta *rs_sta)
 {
 	int unflushed = 0;
 	int i;
@@ -195,19 +193,19 @@ static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv)
 	 * since we flushed, clear out the gathered statistics
 	 */
 	for (i = 0; i < IWL_RATE_COUNT; i++) {
-		if (!rs_priv->win[i].counter)
+		if (!rs_sta->win[i].counter)
 			continue;
 
-		spin_lock_irqsave(&rs_priv->lock, flags);
-		if (time_after(jiffies, rs_priv->win[i].stamp +
+		spin_lock_irqsave(&rs_sta->lock, flags);
+		if (time_after(jiffies, rs_sta->win[i].stamp +
 			       IWL_RATE_WIN_FLUSH)) {
 			IWL_DEBUG_RATE("flushing %d samples of rate "
 				       "index %d\n",
-				       rs_priv->win[i].counter, i);
-			iwl_clear_window(&rs_priv->win[i]);
+				       rs_sta->win[i].counter, i);
+			iwl3945_clear_window(&rs_sta->win[i]);
 		} else
 			unflushed++;
-		spin_unlock_irqrestore(&rs_priv->lock, flags);
+		spin_unlock_irqrestore(&rs_sta->lock, flags);
 	}
 
 	return unflushed;
@@ -216,30 +214,30 @@ static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv)
 #define IWL_RATE_FLUSH_MAX              5000	/* msec */
 #define IWL_RATE_FLUSH_MIN              50	/* msec */
 
-static void iwl_bg_rate_scale_flush(unsigned long data)
+static void iwl3945_bg_rate_scale_flush(unsigned long data)
 {
-	struct iwl_rate_scale_priv *rs_priv = (void *)data;
+	struct iwl3945_rs_sta *rs_sta = (void *)data;
 	int unflushed = 0;
 	unsigned long flags;
 	u32 packet_count, duration, pps;
 
 	IWL_DEBUG_RATE("enter\n");
 
-	unflushed = iwl_rate_scale_flush_windows(rs_priv);
+	unflushed = iwl3945_rate_scale_flush_windows(rs_sta);
 
-	spin_lock_irqsave(&rs_priv->lock, flags);
+	spin_lock_irqsave(&rs_sta->lock, flags);
 
-	rs_priv->flush_pending = 0;
+	rs_sta->flush_pending = 0;
 
 	/* Number of packets Rx'd since last time this timer ran */
-	packet_count = (rs_priv->tx_packets - rs_priv->last_tx_packets) + 1;
+	packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1;
 
-	rs_priv->last_tx_packets = rs_priv->tx_packets + 1;
+	rs_sta->last_tx_packets = rs_sta->tx_packets + 1;
 
 	if (unflushed) {
 		duration =
-		    jiffies_to_msecs(jiffies - rs_priv->last_partial_flush);
-/*              duration = jiffies_to_msecs(rs_priv->flush_time); */
+		    jiffies_to_msecs(jiffies - rs_sta->last_partial_flush);
+/*              duration = jiffies_to_msecs(rs_sta->flush_time); */
 
 		IWL_DEBUG_RATE("Tx'd %d packets in %dms\n",
 			       packet_count, duration);
@@ -257,36 +255,36 @@ static void iwl_bg_rate_scale_flush(unsigned long data)
 		} else
 			duration = IWL_RATE_FLUSH_MAX;
 
-		rs_priv->flush_time = msecs_to_jiffies(duration);
+		rs_sta->flush_time = msecs_to_jiffies(duration);
 
 		IWL_DEBUG_RATE("new flush period: %d msec ave %d\n",
 			       duration, packet_count);
 
-		mod_timer(&rs_priv->rate_scale_flush, jiffies +
-			  rs_priv->flush_time);
+		mod_timer(&rs_sta->rate_scale_flush, jiffies +
+			  rs_sta->flush_time);
 
-		rs_priv->last_partial_flush = jiffies;
+		rs_sta->last_partial_flush = jiffies;
 	}
 
 	/* If there weren't any unflushed entries, we don't schedule the timer
 	 * to run again */
 
-	rs_priv->last_flush = jiffies;
+	rs_sta->last_flush = jiffies;
 
-	spin_unlock_irqrestore(&rs_priv->lock, flags);
+	spin_unlock_irqrestore(&rs_sta->lock, flags);
 
 	IWL_DEBUG_RATE("leave\n");
 }
 
 /**
- * iwl_collect_tx_data - Update the success/failure sliding window
+ * iwl3945_collect_tx_data - Update the success/failure sliding window
  *
  * We keep a sliding window of the last 64 packets transmitted
  * at this rate.  window->data contains the bitmask of successful
  * packets.
  */
-static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv,
-				struct iwl_rate_scale_data *window,
+static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta,
+				struct iwl3945_rate_scale_data *window,
 				int success, int retries)
 {
 	unsigned long flags;
@@ -297,7 +295,7 @@ static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv,
 	}
 
 	while (retries--) {
-		spin_lock_irqsave(&rs_priv->lock, flags);
+		spin_lock_irqsave(&rs_sta->lock, flags);
 
 		/* If we have filled up the window then subtract one from the
 		 * success counter if the high-bit is counting toward
@@ -325,7 +323,7 @@ static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv,
 		/* Tag this window as having been updated */
 		window->stamp = jiffies;
 
-		spin_unlock_irqrestore(&rs_priv->lock, flags);
+		spin_unlock_irqrestore(&rs_sta->lock, flags);
 	}
 }
 
@@ -362,7 +360,7 @@ static void *rs_alloc(struct ieee80211_local *local)
 	return local->hw.priv;
 }
 
-/* rate scale requires free function to be implmented */
+/* rate scale requires free function to be implemented */
 static void rs_free(void *priv)
 {
 	return;
@@ -375,49 +373,49 @@ static void rs_clear(void *priv)
 
 static void *rs_alloc_sta(void *priv, gfp_t gfp)
 {
-	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl3945_rs_sta *rs_sta;
 	int i;
 
 	IWL_DEBUG_RATE("enter\n");
 
-	rs_priv = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp);
-	if (!rs_priv) {
+	rs_sta = kzalloc(sizeof(struct iwl3945_rs_sta), gfp);
+	if (!rs_sta) {
 		IWL_DEBUG_RATE("leave: ENOMEM\n");
 		return NULL;
 	}
 
-	spin_lock_init(&rs_priv->lock);
+	spin_lock_init(&rs_sta->lock);
 
-	rs_priv->start_rate = IWL_RATE_INVALID;
+	rs_sta->start_rate = IWL_RATE_INVALID;
 
 	/* default to just 802.11b */
-	rs_priv->expected_tpt = iwl_expected_tpt_b;
+	rs_sta->expected_tpt = iwl3945_expected_tpt_b;
 
-	rs_priv->last_partial_flush = jiffies;
-	rs_priv->last_flush = jiffies;
-	rs_priv->flush_time = IWL_RATE_FLUSH;
-	rs_priv->last_tx_packets = 0;
-	rs_priv->ibss_sta_added = 0;
+	rs_sta->last_partial_flush = jiffies;
+	rs_sta->last_flush = jiffies;
+	rs_sta->flush_time = IWL_RATE_FLUSH;
+	rs_sta->last_tx_packets = 0;
+	rs_sta->ibss_sta_added = 0;
 
-	init_timer(&rs_priv->rate_scale_flush);
-	rs_priv->rate_scale_flush.data = (unsigned long)rs_priv;
-	rs_priv->rate_scale_flush.function = &iwl_bg_rate_scale_flush;
+	init_timer(&rs_sta->rate_scale_flush);
+	rs_sta->rate_scale_flush.data = (unsigned long)rs_sta;
+	rs_sta->rate_scale_flush.function = &iwl3945_bg_rate_scale_flush;
 
 	for (i = 0; i < IWL_RATE_COUNT; i++)
-		iwl_clear_window(&rs_priv->win[i]);
+		iwl3945_clear_window(&rs_sta->win[i]);
 
 	IWL_DEBUG_RATE("leave\n");
 
-	return rs_priv;
+	return rs_sta;
 }
 
 static void rs_free_sta(void *priv, void *priv_sta)
 {
-	struct iwl_rate_scale_priv *rs_priv = priv_sta;
+	struct iwl3945_rs_sta *rs_sta = priv_sta;
 
 	IWL_DEBUG_RATE("enter\n");
-	del_timer_sync(&rs_priv->rate_scale_flush);
-	kfree(rs_priv);
+	del_timer_sync(&rs_sta->rate_scale_flush);
+	kfree(rs_sta);
 	IWL_DEBUG_RATE("leave\n");
 }
 
@@ -427,9 +425,9 @@ static void rs_free_sta(void *priv, void *priv_sta)
  * for A and B mode we need to overright prev
  * value
  */
-static int rs_adjust_next_rate(struct iwl_priv *priv, int rate)
+static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
 {
-	int next_rate = iwl_get_prev_ieee_rate(rate);
+	int next_rate = iwl3945_get_prev_ieee_rate(rate);
 
 	switch (priv->phymode) {
 	case MODE_IEEE80211A:
@@ -451,7 +449,7 @@ static int rs_adjust_next_rate(struct iwl_priv *priv, int rate)
 /**
  * rs_tx_status - Update rate control values based on Tx results
  *
- * NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by
+ * NOTE: Uses iwl3945_priv->retry_rate for the # of retries attempted by
  * the hardware for each rate.
  */
 static void rs_tx_status(void *priv_rate,
@@ -464,9 +462,9 @@ static void rs_tx_status(void *priv_rate,
 	unsigned long flags;
 	struct sta_info *sta;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl3945_rs_sta *rs_sta;
 
 	IWL_DEBUG_RATE("enter\n");
 
@@ -487,9 +485,9 @@ static void rs_tx_status(void *priv_rate,
 		return;
 	}
 
-	rs_priv = (void *)sta->rate_ctrl_priv;
+	rs_sta = (void *)sta->rate_ctrl_priv;
 
-	rs_priv->tx_packets++;
+	rs_sta->tx_packets++;
 
 	scale_rate_index = first_index;
 	last_index = first_index;
@@ -516,8 +514,8 @@ static void rs_tx_status(void *priv_rate,
 
 		/* Update this rate accounting for as many retries
 		 * as was used for it (per current_count) */
-		iwl_collect_tx_data(rs_priv,
-				    &rs_priv->win[scale_rate_index],
+		iwl3945_collect_tx_data(rs_sta,
+				    &rs_sta->win[scale_rate_index],
 				    0, current_count);
 		IWL_DEBUG_RATE("Update rate %d for %d retries.\n",
 			       scale_rate_index, current_count);
@@ -535,25 +533,25 @@ static void rs_tx_status(void *priv_rate,
 		       last_index,
 		       (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ?
 		       "success" : "failure");
-	iwl_collect_tx_data(rs_priv,
-			    &rs_priv->win[last_index],
+	iwl3945_collect_tx_data(rs_sta,
+			    &rs_sta->win[last_index],
 			    tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1);
 
 	/* We updated the rate scale window -- if its been more than
 	 * flush_time since the last run, schedule the flush
 	 * again */
-	spin_lock_irqsave(&rs_priv->lock, flags);
+	spin_lock_irqsave(&rs_sta->lock, flags);
 
-	if (!rs_priv->flush_pending &&
-	    time_after(jiffies, rs_priv->last_partial_flush +
-		       rs_priv->flush_time)) {
+	if (!rs_sta->flush_pending &&
+	    time_after(jiffies, rs_sta->last_partial_flush +
+		       rs_sta->flush_time)) {
 
-		rs_priv->flush_pending = 1;
-		mod_timer(&rs_priv->rate_scale_flush,
-			  jiffies + rs_priv->flush_time);
+		rs_sta->flush_pending = 1;
+		mod_timer(&rs_sta->rate_scale_flush,
+			  jiffies + rs_sta->flush_time);
 	}
 
-	spin_unlock_irqrestore(&rs_priv->lock, flags);
+	spin_unlock_irqrestore(&rs_sta->lock, flags);
 
 	sta_info_put(sta);
 
@@ -562,29 +560,13 @@ static void rs_tx_status(void *priv_rate,
 	return;
 }
 
-static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local
-						  *local)
-{
-	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
-	int i;
-
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *rate = &mode->rates[i];
-
-		if (rate->flags & IEEE80211_RATE_SUPPORTED)
-			return rate;
-	}
-
-	return &mode->rates[0];
-}
-
-static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
+static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta,
 				 u8 index, u16 rate_mask, int phymode)
 {
 	u8 high = IWL_RATE_INVALID;
 	u8 low = IWL_RATE_INVALID;
 
-	/* 802.11A walks to the next literal adjascent rate in
+	/* 802.11A walks to the next literal adjacent rate in
 	 * the rate table */
 	if (unlikely(phymode == MODE_IEEE80211A)) {
 		int i;
@@ -613,10 +595,10 @@ static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
 
 	low = index;
 	while (low != IWL_RATE_INVALID) {
-		if (rs_priv->tgg)
-			low = iwl_rates[low].prev_rs_tgg;
+		if (rs_sta->tgg)
+			low = iwl3945_rates[low].prev_rs_tgg;
 		else
-			low = iwl_rates[low].prev_rs;
+			low = iwl3945_rates[low].prev_rs;
 		if (low == IWL_RATE_INVALID)
 			break;
 		if (rate_mask & (1 << low))
@@ -626,10 +608,10 @@ static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
 
 	high = index;
 	while (high != IWL_RATE_INVALID) {
-		if (rs_priv->tgg)
-			high = iwl_rates[high].next_rs_tgg;
+		if (rs_sta->tgg)
+			high = iwl3945_rates[high].next_rs_tgg;
 		else
-			high = iwl_rates[high].next_rs;
+			high = iwl3945_rates[high].next_rs;
 		if (high == IWL_RATE_INVALID)
 			break;
 		if (rate_mask & (1 << high))
@@ -656,17 +638,16 @@ static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
  * rate table and must reference the driver allocated rate table
  *
  */
-static struct ieee80211_rate *rs_get_rate(void *priv_rate,
-					  struct net_device *dev,
-					  struct sk_buff *skb,
-					  struct rate_control_extra *extra)
+static void rs_get_rate(void *priv_rate, struct net_device *dev,
+			struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+			struct rate_selection *sel)
 {
 	u8 low = IWL_RATE_INVALID;
 	u8 high = IWL_RATE_INVALID;
 	u16 high_low;
 	int index;
-	struct iwl_rate_scale_priv *rs_priv;
-	struct iwl_rate_scale_data *window = NULL;
+	struct iwl3945_rs_sta *rs_sta;
+	struct iwl3945_rate_scale_data *window = NULL;
 	int current_tpt = IWL_INVALID_VALUE;
 	int low_tpt = IWL_INVALID_VALUE;
 	int high_tpt = IWL_INVALID_VALUE;
@@ -677,31 +658,24 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct sta_info *sta;
 	u16 fc, rate_mask;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
 	DECLARE_MAC_BUF(mac);
 
 	IWL_DEBUG_RATE("enter\n");
 
-	memset(extra, 0, sizeof(*extra));
+	sta = sta_info_get(local, hdr->addr1);
 
+	/* Send management frames and broadcast/multicast data using lowest
+	 * rate. */
 	fc = le16_to_cpu(hdr->frame_control);
-	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
-	    (is_multicast_ether_addr(hdr->addr1))) {
-		/* Send management frames and broadcast/multicast data using
-		 * lowest rate. */
-		/* TODO: this could probably be improved.. */
-		IWL_DEBUG_RATE("leave: lowest rate (not data or is "
-			       "multicast)\n");
-
-		return iwl_get_lowest_rate(local);
-	}
-
-	sta = sta_info_get(local, hdr->addr1);
-	if (!sta || !sta->rate_ctrl_priv) {
+	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+	    is_multicast_ether_addr(hdr->addr1) ||
+	    !sta || !sta->rate_ctrl_priv) {
 		IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
+		sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
 		if (sta)
 			sta_info_put(sta);
-		return NULL;
+		return;
 	}
 
 	rate_mask = sta->supp_rates;
@@ -710,37 +684,37 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 	if (priv->phymode == (u8) MODE_IEEE80211A)
 		rate_mask = rate_mask << IWL_FIRST_OFDM_RATE;
 
-	rs_priv = (void *)sta->rate_ctrl_priv;
+	rs_sta = (void *)sta->rate_ctrl_priv;
 
 	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
-	    !rs_priv->ibss_sta_added) {
-		u8 sta_id = iwl_hw_find_station(priv, hdr->addr1);
+	    !rs_sta->ibss_sta_added) {
+		u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
 
 		if (sta_id == IWL_INVALID_STATION) {
 			IWL_DEBUG_RATE("LQ: ADD station %s\n",
 				       print_mac(mac, hdr->addr1));
-			sta_id = iwl_add_station(priv,
+			sta_id = iwl3945_add_station(priv,
 				    hdr->addr1, 0, CMD_ASYNC);
 		}
 		if (sta_id != IWL_INVALID_STATION)
-			rs_priv->ibss_sta_added = 1;
+			rs_sta->ibss_sta_added = 1;
 	}
 
-	spin_lock_irqsave(&rs_priv->lock, flags);
+	spin_lock_irqsave(&rs_sta->lock, flags);
 
-	if (rs_priv->start_rate != IWL_RATE_INVALID) {
-		index = rs_priv->start_rate;
-		rs_priv->start_rate = IWL_RATE_INVALID;
+	if (rs_sta->start_rate != IWL_RATE_INVALID) {
+		index = rs_sta->start_rate;
+		rs_sta->start_rate = IWL_RATE_INVALID;
 	}
 
-	window = &(rs_priv->win[index]);
+	window = &(rs_sta->win[index]);
 
 	fail_count = window->counter - window->success_counter;
 
 	if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) &&
 	     (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) {
 		window->average_tpt = IWL_INVALID_VALUE;
-		spin_unlock_irqrestore(&rs_priv->lock, flags);
+		spin_unlock_irqrestore(&rs_sta->lock, flags);
 
 		IWL_DEBUG_RATE("Invalid average_tpt on rate %d: "
 			       "counter: %d, success_counter: %d, "
@@ -748,27 +722,27 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 			       index,
 			       window->counter,
 			       window->success_counter,
-			       rs_priv->expected_tpt ? "not " : "");
+			       rs_sta->expected_tpt ? "not " : "");
 		goto out;
 
 	}
 
 	window->average_tpt = ((window->success_ratio *
-				rs_priv->expected_tpt[index] + 64) / 128);
+				rs_sta->expected_tpt[index] + 64) / 128);
 	current_tpt = window->average_tpt;
 
-	high_low = iwl_get_adjacent_rate(rs_priv, index, rate_mask,
+	high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask,
 					 local->hw.conf.phymode);
 	low = high_low & 0xff;
 	high = (high_low >> 8) & 0xff;
 
 	if (low != IWL_RATE_INVALID)
-		low_tpt = rs_priv->win[low].average_tpt;
+		low_tpt = rs_sta->win[low].average_tpt;
 
 	if (high != IWL_RATE_INVALID)
-		high_tpt = rs_priv->win[high].average_tpt;
+		high_tpt = rs_sta->win[high].average_tpt;
 
-	spin_unlock_irqrestore(&rs_priv->lock, flags);
+	spin_unlock_irqrestore(&rs_sta->lock, flags);
 
 	scale_action = 1;
 
@@ -846,7 +820,7 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 
 	IWL_DEBUG_RATE("leave: %d\n", index);
 
-	return &priv->ieee_rates[index];
+	sel->rate = &priv->ieee_rates[index];
 }
 
 static struct rate_control_ops rs_ops = {
@@ -862,11 +836,11 @@ static struct rate_control_ops rs_ops = {
 	.free_sta = rs_free_sta,
 };
 
-int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
+int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct iwl_priv *priv = hw->priv;
-	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl3945_priv *priv = hw->priv;
+	struct iwl3945_rs_sta *rs_sta;
 	struct sta_info *sta;
 	unsigned long flags;
 	int count = 0, i;
@@ -884,28 +858,29 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 		return sprintf(buf, "station %d not found\n", sta_id);
 	}
 
-	rs_priv = (void *)sta->rate_ctrl_priv;
-	spin_lock_irqsave(&rs_priv->lock, flags);
+	rs_sta = (void *)sta->rate_ctrl_priv;
+	spin_lock_irqsave(&rs_sta->lock, flags);
 	i = IWL_RATE_54M_INDEX;
 	while (1) {
 		u64 mask;
 		int j;
 
 		count +=
-		    sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2);
+		    sprintf(&buf[count], " %2dMbs: ", iwl3945_rates[i].ieee / 2);
 
 		mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
 		for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
 			buf[count++] =
-			    (rs_priv->win[i].data & mask) ? '1' : '0';
+			    (rs_sta->win[i].data & mask) ? '1' : '0';
 
-		samples += rs_priv->win[i].counter;
-		good += rs_priv->win[i].success_counter;
-		success += rs_priv->win[i].success_counter * iwl_rates[i].ieee;
+		samples += rs_sta->win[i].counter;
+		good += rs_sta->win[i].success_counter;
+		success += rs_sta->win[i].success_counter *
+						iwl3945_rates[i].ieee;
 
-		if (rs_priv->win[i].stamp) {
+		if (rs_sta->win[i].stamp) {
 			int delta =
-			    jiffies_to_msecs(now - rs_priv->win[i].stamp);
+			    jiffies_to_msecs(now - rs_sta->win[i].stamp);
 
 			if (delta > max_time)
 				max_time = delta;
@@ -914,18 +889,18 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 		} else
 			buf[count++] = '\n';
 
-		j = iwl_get_prev_ieee_rate(i);
+		j = iwl3945_get_prev_ieee_rate(i);
 		if (j == i)
 			break;
 		i = j;
 	}
-	spin_unlock_irqrestore(&rs_priv->lock, flags);
+	spin_unlock_irqrestore(&rs_sta->lock, flags);
 	sta_info_put(sta);
 
 	/* Display the average rate of all samples taken.
 	 *
 	 * NOTE:  We multiple # of samples by 2 since the IEEE measurement
-	 * added from iwl_rates is actually 2X the rate */
+	 * added from iwl3945_rates is actually 2X the rate */
 	if (samples)
 		count += sprintf(
 			&buf[count],
@@ -939,13 +914,13 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 	return count;
 }
 
-void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
+void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 	s32 rssi = 0;
 	unsigned long flags;
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl3945_rs_sta *rs_sta;
 	struct sta_info *sta;
 
 	IWL_DEBUG_RATE("enter\n");
@@ -965,33 +940,33 @@ void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 		return;
 	}
 
-	rs_priv = (void *)sta->rate_ctrl_priv;
+	rs_sta = (void *)sta->rate_ctrl_priv;
 
-	spin_lock_irqsave(&rs_priv->lock, flags);
+	spin_lock_irqsave(&rs_sta->lock, flags);
 
-	rs_priv->tgg = 0;
+	rs_sta->tgg = 0;
 	switch (priv->phymode) {
 	case MODE_IEEE80211G:
 		if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) {
-			rs_priv->tgg = 1;
-			rs_priv->expected_tpt = iwl_expected_tpt_g_prot;
+			rs_sta->tgg = 1;
+			rs_sta->expected_tpt = iwl3945_expected_tpt_g_prot;
 		} else
-			rs_priv->expected_tpt = iwl_expected_tpt_g;
+			rs_sta->expected_tpt = iwl3945_expected_tpt_g;
 		break;
 
 	case MODE_IEEE80211A:
-		rs_priv->expected_tpt = iwl_expected_tpt_a;
+		rs_sta->expected_tpt = iwl3945_expected_tpt_a;
 		break;
 
 	default:
 		IWL_WARNING("Invalid phymode.  Defaulting to 802.11b\n");
 	case MODE_IEEE80211B:
-		rs_priv->expected_tpt = iwl_expected_tpt_b;
+		rs_sta->expected_tpt = iwl3945_expected_tpt_b;
 		break;
 	}
 
 	sta_info_put(sta);
-	spin_unlock_irqrestore(&rs_priv->lock, flags);
+	spin_unlock_irqrestore(&rs_sta->lock, flags);
 
 	rssi = priv->last_rx_rssi;
 	if (rssi == 0)
@@ -999,19 +974,20 @@ void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 
 	IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi);
 
-	rs_priv->start_rate = iwl_get_rate_index_by_rssi(rssi, priv->phymode);
+	rs_sta->start_rate =
+			iwl3945_get_rate_index_by_rssi(rssi, priv->phymode);
 
 	IWL_DEBUG_RATE("leave: rssi %d assign rate index: "
-		       "%d (plcp 0x%x)\n", rssi, rs_priv->start_rate,
-		       iwl_rates[rs_priv->start_rate].plcp);
+		       "%d (plcp 0x%x)\n", rssi, rs_sta->start_rate,
+		       iwl3945_rates[rs_sta->start_rate].plcp);
 }
 
-void iwl_rate_control_register(struct ieee80211_hw *hw)
+void iwl3945_rate_control_register(struct ieee80211_hw *hw)
 {
 	ieee80211_rate_control_register(&rs_ops);
 }
 
-void iwl_rate_control_unregister(struct ieee80211_hw *hw)
+void iwl3945_rate_control_unregister(struct ieee80211_hw *hw)
 {
 	ieee80211_rate_control_unregister(&rs_ops);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
index bec4d3ffca1d..d5e9220f871d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
@@ -27,9 +27,9 @@
 #ifndef __iwl_3945_rs_h__
 #define __iwl_3945_rs_h__
 
-struct iwl_rate_info {
-	u8 plcp;
-	u8 ieee;
+struct iwl3945_rate_info {
+	u8 plcp;		/* uCode API:  IWL_RATE_6M_PLCP, etc. */
+	u8 ieee;		/* MAC header:  IWL_RATE_6M_IEEE, etc. */
 	u8 prev_ieee;		/* previous rate in IEEE speeds */
 	u8 next_ieee;		/* next rate in IEEE speeds */
 	u8 prev_rs;		/* previous rate used in rs algo */
@@ -38,9 +38,12 @@ struct iwl_rate_info {
 	u8 next_rs_tgg;		/* next rate used in TGG rs algo */
         u8 table_rs_index;	/* index in rate scale table cmd */
         u8 prev_table_rs;	/* prev in rate table cmd */
-
 };
 
+/*
+ * These serve as indexes into
+ * struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT];
+ */
 enum {
 	IWL_RATE_1M_INDEX = 0,
 	IWL_RATE_2M_INDEX,
@@ -83,19 +86,20 @@ enum {
 };
 
 /* #define vs. enum to keep from defaulting to 'large integer' */
-#define	IWL_RATE_6M_MASK   (1<<IWL_RATE_6M_INDEX)
-#define	IWL_RATE_9M_MASK   (1<<IWL_RATE_9M_INDEX)
-#define	IWL_RATE_12M_MASK  (1<<IWL_RATE_12M_INDEX)
-#define	IWL_RATE_18M_MASK  (1<<IWL_RATE_18M_INDEX)
-#define	IWL_RATE_24M_MASK  (1<<IWL_RATE_24M_INDEX)
-#define	IWL_RATE_36M_MASK  (1<<IWL_RATE_36M_INDEX)
-#define	IWL_RATE_48M_MASK  (1<<IWL_RATE_48M_INDEX)
-#define	IWL_RATE_54M_MASK  (1<<IWL_RATE_54M_INDEX)
-#define	IWL_RATE_1M_MASK   (1<<IWL_RATE_1M_INDEX)
-#define	IWL_RATE_2M_MASK   (1<<IWL_RATE_2M_INDEX)
-#define	IWL_RATE_5M_MASK   (1<<IWL_RATE_5M_INDEX)
-#define	IWL_RATE_11M_MASK  (1<<IWL_RATE_11M_INDEX)
-
+#define	IWL_RATE_6M_MASK   (1 << IWL_RATE_6M_INDEX)
+#define	IWL_RATE_9M_MASK   (1 << IWL_RATE_9M_INDEX)
+#define	IWL_RATE_12M_MASK  (1 << IWL_RATE_12M_INDEX)
+#define	IWL_RATE_18M_MASK  (1 << IWL_RATE_18M_INDEX)
+#define	IWL_RATE_24M_MASK  (1 << IWL_RATE_24M_INDEX)
+#define	IWL_RATE_36M_MASK  (1 << IWL_RATE_36M_INDEX)
+#define	IWL_RATE_48M_MASK  (1 << IWL_RATE_48M_INDEX)
+#define	IWL_RATE_54M_MASK  (1 << IWL_RATE_54M_INDEX)
+#define	IWL_RATE_1M_MASK   (1 << IWL_RATE_1M_INDEX)
+#define	IWL_RATE_2M_MASK   (1 << IWL_RATE_2M_INDEX)
+#define	IWL_RATE_5M_MASK   (1 << IWL_RATE_5M_INDEX)
+#define	IWL_RATE_11M_MASK  (1 << IWL_RATE_11M_INDEX)
+
+/* 3945 uCode API values for (legacy) bit rates, both OFDM and CCK */
 enum {
 	IWL_RATE_6M_PLCP = 13,
 	IWL_RATE_9M_PLCP = 15,
@@ -111,6 +115,7 @@ enum {
 	IWL_RATE_11M_PLCP = 110,
 };
 
+/* MAC header values for bit rates */
 enum {
 	IWL_RATE_6M_IEEE = 12,
 	IWL_RATE_9M_IEEE = 18,
@@ -152,18 +157,18 @@ enum {
 	(IWL_OFDM_BASIC_RATES_MASK | \
 	 IWL_CCK_BASIC_RATES_MASK)
 
-#define IWL_RATES_MASK ((1<<IWL_RATE_COUNT)-1)
+#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
 
 #define IWL_INVALID_VALUE    -1
 
 #define IWL_MIN_RSSI_VAL                 -100
 #define IWL_MAX_RSSI_VAL                    0
 
-extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+extern const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT];
 
-static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
+static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index)
 {
-	u8 rate = iwl_rates[rate_index].prev_ieee;
+	u8 rate = iwl3945_rates[rate_index].prev_ieee;
 
 	if (rate == IWL_RATE_INVALID)
 		rate = rate_index;
@@ -171,40 +176,40 @@ static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
 }
 
 /**
- * iwl_fill_rs_info - Fill an output text buffer with the rate representation
+ * iwl3945_fill_rs_info - Fill an output text buffer with the rate representation
  *
  * NOTE:  This is provided as a quick mechanism for a user to visualize
- * the performance of the rate control alogirthm and is not meant to be
+ * the performance of the rate control algorithm and is not meant to be
  * parsed software.
  */
-extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
+extern int iwl3945_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
 
 /**
- * iwl_rate_scale_init - Initialize the rate scale table based on assoc info
+ * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info
  *
- * The specific througput table used is based on the type of network
+ * The specific throughput table used is based on the type of network
  * the associated with, including A, B, G, and G w/ TGG protection
  */
-extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
+extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
 
 /**
- * iwl_rate_control_register - Register the rate control algorithm callbacks
+ * iwl3945_rate_control_register - Register the rate control algorithm callbacks
  *
  * Since the rate control algorithm is hardware specific, there is no need
  * or reason to place it as a stand alone module.  The driver can call
- * iwl_rate_control_register in order to register the rate control callbacks
+ * iwl3945_rate_control_register in order to register the rate control callbacks
  * with the mac80211 subsystem.  This should be performed prior to calling
  * ieee80211_register_hw
  *
  */
-extern void iwl_rate_control_register(struct ieee80211_hw *hw);
+extern void iwl3945_rate_control_register(struct ieee80211_hw *hw);
 
 /**
- * iwl_rate_control_unregister - Unregister the rate control callbacks
+ * iwl3945_rate_control_unregister - Unregister the rate control callbacks
  *
  * This should be called after calling ieee80211_unregister_hw, but before
  * the driver is unloaded.
  */
-extern void iwl_rate_control_unregister(struct ieee80211_hw *hw);
+extern void iwl3945_rate_control_unregister(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 3a45fe99a83e..76c4ed1135f2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -35,15 +35,12 @@
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <linux/firmware.h>
-#include <net/mac80211.h>
-
 #include <linux/etherdevice.h>
+#include <asm/unaligned.h>
+#include <net/mac80211.h>
 
-#define IWL 3945
-
-#include "iwlwifi.h"
-#include "iwl-helpers.h"
 #include "iwl-3945.h"
+#include "iwl-helpers.h"
 #include "iwl-3945-rs.h"
 
 #define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
@@ -66,7 +63,7 @@
  * maps to IWL_RATE_INVALID
  *
  */
-const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT] = {
 	IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2),    /*  1mbps */
 	IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5),          /*  2mbps */
 	IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
@@ -81,12 +78,12 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
 	IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */
 };
 
-/* 1 = enable the iwl_disable_events() function */
+/* 1 = enable the iwl3945_disable_events() function */
 #define IWL_EVT_DISABLE (0)
 #define IWL_EVT_DISABLE_SIZE (1532/32)
 
 /**
- * iwl_disable_events - Disable selected events in uCode event log
+ * iwl3945_disable_events - Disable selected events in uCode event log
  *
  * Disable an event by writing "1"s into "disable"
  *   bitmap in SRAM.  Bit position corresponds to Event # (id/type).
@@ -94,9 +91,9 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
  * Use for only special debugging.  This function is just a placeholder as-is,
  *   you'll need to provide the special bits! ...
  *   ... and set IWL_EVT_DISABLE to 1. */
-void iwl_disable_events(struct iwl_priv *priv)
+void iwl3945_disable_events(struct iwl3945_priv *priv)
 {
-	int rc;
+	int ret;
 	int i;
 	u32 base;		/* SRAM address of event log header */
 	u32 disable_ptr;	/* SRAM address of event-disable bitmap array */
@@ -152,32 +149,31 @@ void iwl_disable_events(struct iwl_priv *priv)
 	};
 
 	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-	if (!iwl_hw_valid_rtc_data_addr(base)) {
+	if (!iwl3945_hw_valid_rtc_data_addr(base)) {
 		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
 		return;
 	}
 
-	rc = iwl_grab_restricted_access(priv);
-	if (rc) {
+	ret = iwl3945_grab_nic_access(priv);
+	if (ret) {
 		IWL_WARNING("Can not read from adapter at this time.\n");
 		return;
 	}
 
-	disable_ptr = iwl_read_restricted_mem(priv, base + (4 * sizeof(u32)));
-	array_size = iwl_read_restricted_mem(priv, base + (5 * sizeof(u32)));
-	iwl_release_restricted_access(priv);
+	disable_ptr = iwl3945_read_targ_mem(priv, base + (4 * sizeof(u32)));
+	array_size = iwl3945_read_targ_mem(priv, base + (5 * sizeof(u32)));
+	iwl3945_release_nic_access(priv);
 
 	if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) {
 		IWL_DEBUG_INFO("Disabling selected uCode log events at 0x%x\n",
 			       disable_ptr);
-		rc = iwl_grab_restricted_access(priv);
+		ret = iwl3945_grab_nic_access(priv);
 		for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++)
-			iwl_write_restricted_mem(priv,
-						 disable_ptr +
-						 (i * sizeof(u32)),
-						 evt_disable[i]);
+			iwl3945_write_targ_mem(priv,
+					   disable_ptr + (i * sizeof(u32)),
+					   evt_disable[i]);
 
-		iwl_release_restricted_access(priv);
+		iwl3945_release_nic_access(priv);
 	} else {
 		IWL_DEBUG_INFO("Selected uCode log events may be disabled\n");
 		IWL_DEBUG_INFO("  by writing \"1\"s into disable bitmap\n");
@@ -198,7 +194,7 @@ void iwl_disable_events(struct iwl_priv *priv)
  * IWL_ANTENNA_MAIN      - Force MAIN antenna
  * IWL_ANTENNA_AUX       - Force AUX antenna
  */
-__le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv)
+__le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv)
 {
 	switch (priv->antenna) {
 	case IWL_ANTENNA_DIVERSITY:
@@ -230,11 +226,11 @@ __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv)
  *
  *****************************************************************************/
 
-void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
 	IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n",
-		     (int)sizeof(struct iwl_notif_statistics),
+		     (int)sizeof(struct iwl3945_notif_statistics),
 		     le32_to_cpu(pkt->len));
 
 	memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics));
@@ -242,15 +238,107 @@ void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	priv->last_statistics_time = jiffies;
 }
 
-static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data,
-				   struct iwl_rx_mem_buffer *rxb,
-				   struct ieee80211_rx_status *stats,
-				   u16 phy_flags)
+void iwl3945_add_radiotap(struct iwl3945_priv *priv, struct sk_buff *skb,
+			  struct iwl3945_rx_frame_hdr *rx_hdr,
+			  struct ieee80211_rx_status *stats)
+{
+	/* First cache any information we need before we overwrite
+	 * the information provided in the skb from the hardware */
+	s8 signal = stats->ssi;
+	s8 noise = 0;
+	int rate = stats->rate;
+	u64 tsf = stats->mactime;
+	__le16 phy_flags_hw = rx_hdr->phy_flags;
+
+	struct iwl3945_rt_rx_hdr {
+		struct ieee80211_radiotap_header rt_hdr;
+		__le64 rt_tsf;		/* TSF */
+		u8 rt_flags;		/* radiotap packet flags */
+		u8 rt_rate;		/* rate in 500kb/s */
+		__le16 rt_channelMHz;	/* channel in MHz */
+		__le16 rt_chbitmask;	/* channel bitfield */
+		s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
+		s8 rt_dbmnoise;
+		u8 rt_antenna;		/* antenna number */
+	} __attribute__ ((packed)) *iwl3945_rt;
+
+	if (skb_headroom(skb) < sizeof(*iwl3945_rt)) {
+		if (net_ratelimit())
+			printk(KERN_ERR "not enough headroom [%d] for "
+			       "radiotap head [%zd]\n",
+			       skb_headroom(skb), sizeof(*iwl3945_rt));
+		return;
+	}
+
+	/* put radiotap header in front of 802.11 header and data */
+	iwl3945_rt = (void *)skb_push(skb, sizeof(*iwl3945_rt));
+
+	/* initialise radiotap header */
+	iwl3945_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+	iwl3945_rt->rt_hdr.it_pad = 0;
+
+	/* total header + data */
+	put_unaligned(cpu_to_le16(sizeof(*iwl3945_rt)),
+		      &iwl3945_rt->rt_hdr.it_len);
+
+	/* Indicate all the fields we add to the radiotap header */
+	put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+				  (1 << IEEE80211_RADIOTAP_FLAGS) |
+				  (1 << IEEE80211_RADIOTAP_RATE) |
+				  (1 << IEEE80211_RADIOTAP_CHANNEL) |
+				  (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+				  (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+				  (1 << IEEE80211_RADIOTAP_ANTENNA)),
+		      &iwl3945_rt->rt_hdr.it_present);
+
+	/* Zero the flags, we'll add to them as we go */
+	iwl3945_rt->rt_flags = 0;
+
+	put_unaligned(cpu_to_le64(tsf), &iwl3945_rt->rt_tsf);
+
+	iwl3945_rt->rt_dbmsignal = signal;
+	iwl3945_rt->rt_dbmnoise = noise;
+
+	/* Convert the channel frequency and set the flags */
+	put_unaligned(cpu_to_le16(stats->freq), &iwl3945_rt->rt_channelMHz);
+	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
+		put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
+					  IEEE80211_CHAN_5GHZ),
+			      &iwl3945_rt->rt_chbitmask);
+	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
+		put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK |
+					  IEEE80211_CHAN_2GHZ),
+			      &iwl3945_rt->rt_chbitmask);
+	else	/* 802.11g */
+		put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
+					  IEEE80211_CHAN_2GHZ),
+			      &iwl3945_rt->rt_chbitmask);
+
+	rate = iwl3945_rate_index_from_plcp(rate);
+	if (rate == -1)
+		iwl3945_rt->rt_rate = 0;
+	else
+		iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee;
+
+	/* antenna number */
+	iwl3945_rt->rt_antenna =
+		le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+	/* set the preamble flag if we have it */
+	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+		iwl3945_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+	stats->flag |= RX_FLAG_RADIOTAP;
+}
+
+static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
+				   struct iwl3945_rx_mem_buffer *rxb,
+				   struct ieee80211_rx_status *stats)
 {
 	struct ieee80211_hdr *hdr;
-	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
-	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
+	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
 	short len = le16_to_cpu(rx_hdr->len);
 
 	/* We received data from the HW, so stop the watchdog */
@@ -265,15 +353,6 @@ static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data,
 		    ("Dropping packet while interface is not open.\n");
 		return;
 	}
-	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
-		if (iwl_param_hwcrypto)
-			iwl_set_decrypted_flag(priv, rxb->skb,
-					       le32_to_cpu(rx_end->status),
-					       stats);
-		iwl_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt),
-					       len, stats, phy_flags);
-		return;
-	}
 
 	skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt);
 	/* Set the size of the skb to the size of the frame */
@@ -281,23 +360,27 @@ static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data,
 
 	hdr = (void *)rxb->skb->data;
 
-	if (iwl_param_hwcrypto)
-		iwl_set_decrypted_flag(priv, rxb->skb,
+	if (iwl3945_param_hwcrypto)
+		iwl3945_set_decrypted_flag(priv, rxb->skb,
 				       le32_to_cpu(rx_end->status), stats);
 
+	if (priv->add_radiotap)
+		iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats);
+
 	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
 	rxb->skb = NULL;
 }
 
-static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
+#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
+
+static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
+				struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
-	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
-	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
 	struct ieee80211_hdr *header;
-	u16 phy_flags = le16_to_cpu(rx_hdr->phy_flags);
 	u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);
 	u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
 	struct ieee80211_rx_status stats = {
@@ -327,7 +410,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 	}
 
 	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
-		iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags);
+		iwl3945_handle_data_packet(priv, 1, rxb, &stats);
 		return;
 	}
 
@@ -351,14 +434,14 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 	 * Calculate stats.signal (quality indicator in %) based on SNR. */
 	if (rx_stats_noise_diff) {
 		snr = rx_stats_sig_avg / rx_stats_noise_diff;
-		stats.noise = stats.ssi - iwl_calc_db_from_ratio(snr);
-		stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise);
+		stats.noise = stats.ssi - iwl3945_calc_db_from_ratio(snr);
+		stats.signal = iwl3945_calc_sig_qual(stats.ssi, stats.noise);
 
 	/* If noise info not available, calculate signal quality indicator (%)
 	 *   using just the dBm signal level. */
 	} else {
 		stats.noise = priv->last_rx_noise;
-		stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
+		stats.signal = iwl3945_calc_sig_qual(stats.ssi, 0);
 	}
 
 
@@ -368,24 +451,24 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 
 	stats.freq = ieee80211chan2mhz(stats.channel);
 
-	/* can be covered by iwl_report_frame() in most cases */
+	/* can be covered by iwl3945_report_frame() in most cases */
 /*      IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */
 
 	header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
 
-	network_packet = iwl_is_network_packet(priv, header);
+	network_packet = iwl3945_is_network_packet(priv, header);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & IWL_DL_STATS && net_ratelimit())
+#ifdef CONFIG_IWL3945_DEBUG
+	if (iwl3945_debug_level & IWL_DL_STATS && net_ratelimit())
 		IWL_DEBUG_STATS
 		    ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n",
 		     network_packet ? '*' : ' ',
 		     stats.channel, stats.ssi, stats.ssi,
 		     stats.ssi, stats.rate);
 
-	if (iwl_debug_level & (IWL_DL_RX))
+	if (iwl3945_debug_level & (IWL_DL_RX))
 		/* Set "1" to report good data frames in groups of 100 */
-		iwl_report_frame(priv, pkt, header, 1);
+		iwl3945_report_frame(priv, pkt, header, 1);
 #endif
 
 	if (network_packet) {
@@ -437,15 +520,20 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 			break;
 
 			/*
-			 * TODO: There is no callback function from upper
-			 * stack to inform us when associated status. this
-			 * work around to sniff assoc_resp management frame
-			 * and finish the association process.
+			 * TODO: Use the new callback function from
+			 * mac80211 instead of sniffing these packets.
 			 */
 		case IEEE80211_STYPE_ASSOC_RESP:
 		case IEEE80211_STYPE_REASSOC_RESP:{
 				struct ieee80211_mgmt *mgnt =
 				    (struct ieee80211_mgmt *)header;
+
+				/* We have just associated, give some
+				 * time for the 4-way handshake if
+				 * any. Don't start scan too early. */
+				priv->next_scan_jiffies = jiffies +
+					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
+
 				priv->assoc_id = (~((1 << 15) | (1 << 14)) &
 						  le16_to_cpu(mgnt->u.
 							      assoc_resp.aid));
@@ -474,7 +562,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 			}
 		}
 
-		iwl3945_handle_data_packet(priv, 0, rxb, &stats, phy_flags);
+		iwl3945_handle_data_packet(priv, 0, rxb, &stats);
 		break;
 
 	case IEEE80211_FTYPE_CTL:
@@ -485,25 +573,24 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
 		DECLARE_MAC_BUF(mac2);
 		DECLARE_MAC_BUF(mac3);
 
-		if (unlikely(is_duplicate_packet(priv, header)))
+		if (unlikely(iwl3945_is_duplicate_packet(priv, header)))
 			IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
 				       print_mac(mac1, header->addr1),
 				       print_mac(mac2, header->addr2),
 				       print_mac(mac3, header->addr3));
 		else
-			iwl3945_handle_data_packet(priv, 1, rxb, &stats,
-						   phy_flags);
+			iwl3945_handle_data_packet(priv, 1, rxb, &stats);
 		break;
 	}
 	}
 }
 
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr,
 				 dma_addr_t addr, u16 len)
 {
 	int count;
 	u32 pad;
-	struct iwl_tfd_frame *tfd = (struct iwl_tfd_frame *)ptr;
+	struct iwl3945_tfd_frame *tfd = (struct iwl3945_tfd_frame *)ptr;
 
 	count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags));
 	pad = TFD_CTL_PAD_GET(le32_to_cpu(tfd->control_flags));
@@ -526,14 +613,14 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
 }
 
 /**
- * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used]
+ * iwl3945_hw_txq_free_tfd - Free one TFD, those at index [txq->q.read_ptr]
  *
  * Does NOT advance any indexes
  */
-int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq)
 {
-	struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
-	struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used];
+	struct iwl3945_tfd_frame *bd_tmp = (struct iwl3945_tfd_frame *)&txq->bd[0];
+	struct iwl3945_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
 	struct pci_dev *dev = priv->pci_dev;
 	int i;
 	int counter;
@@ -556,19 +643,19 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 	for (i = 1; i < counter; i++) {
 		pci_unmap_single(dev, le32_to_cpu(bd->pa[i].addr),
 				 le32_to_cpu(bd->pa[i].len), PCI_DMA_TODEVICE);
-		if (txq->txb[txq->q.last_used].skb[0]) {
-			struct sk_buff *skb = txq->txb[txq->q.last_used].skb[0];
-			if (txq->txb[txq->q.last_used].skb[0]) {
+		if (txq->txb[txq->q.read_ptr].skb[0]) {
+			struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[0];
+			if (txq->txb[txq->q.read_ptr].skb[0]) {
 				/* Can be called from interrupt context */
 				dev_kfree_skb_any(skb);
-				txq->txb[txq->q.last_used].skb[0] = NULL;
+				txq->txb[txq->q.read_ptr].skb[0] = NULL;
 			}
 		}
 	}
 	return 0;
 }
 
-u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr)
+u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr)
 {
 	int i;
 	int ret = IWL_INVALID_STATION;
@@ -592,11 +679,11 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr)
 }
 
 /**
- * iwl_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
+ * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
  *
 */
-void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
-			      struct iwl_cmd *cmd,
+void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
+			      struct iwl3945_cmd *cmd,
 			      struct ieee80211_tx_control *ctrl,
 			      struct ieee80211_hdr *hdr, int sta_id, int tx_id)
 {
@@ -609,7 +696,7 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 	__le32 tx_flags;
 	u16 fc = le16_to_cpu(hdr->frame_control);
 
-	rate = iwl_rates[rate_index].plcp;
+	rate = iwl3945_rates[rate_index].plcp;
 	tx_flags = cmd->cmd.tx.tx_flags;
 
 	/* We need to figure out how to get the sta->supp_rates while
@@ -676,10 +763,10 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 		       cmd->cmd.tx.supp_rates[1], cmd->cmd.tx.supp_rates[0]);
 }
 
-u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
+u8 iwl3945_sync_sta(struct iwl3945_priv *priv, int sta_id, u16 tx_rate, u8 flags)
 {
 	unsigned long flags_spin;
-	struct iwl_station_entry *station;
+	struct iwl3945_station_entry *station;
 
 	if (sta_id == IWL_INVALID_STATION)
 		return IWL_INVALID_STATION;
@@ -694,34 +781,19 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
 
 	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 
-	iwl_send_add_station(priv, &station->sta, flags);
+	iwl3945_send_add_station(priv, &station->sta, flags);
 	IWL_DEBUG_RATE("SCALE sync station %d to rate %d\n",
 			sta_id, tx_rate);
 	return sta_id;
 }
 
-void iwl_hw_card_show_info(struct iwl_priv *priv)
-{
-	IWL_DEBUG_INFO("3945ABG HW Version %u.%u.%u\n",
-		       ((priv->eeprom.board_revision >> 8) & 0x0F),
-		       ((priv->eeprom.board_revision >> 8) >> 4),
-		       (priv->eeprom.board_revision & 0x00FF));
-
-	IWL_DEBUG_INFO("3945ABG PBA Number %.*s\n",
-		       (int)sizeof(priv->eeprom.board_pba_number),
-		       priv->eeprom.board_pba_number);
-
-	IWL_DEBUG_INFO("EEPROM_ANTENNA_SWITCH_TYPE is 0x%02X\n",
-		       priv->eeprom.antenna_switch_type);
-}
-
-static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+static int iwl3945_nic_set_pwr_src(struct iwl3945_priv *priv, int pwr_max)
 {
 	int rc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
@@ -733,23 +805,23 @@ static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
 		rc = pci_read_config_dword(priv->pci_dev,
 				PCI_POWER_SOURCE, &val);
 		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
-			iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG,
+			iwl3945_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
 					APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
 					~APMG_PS_CTRL_MSK_PWR_SRC);
-			iwl_release_restricted_access(priv);
+			iwl3945_release_nic_access(priv);
 
-			iwl_poll_bit(priv, CSR_GPIO_IN,
+			iwl3945_poll_bit(priv, CSR_GPIO_IN,
 				     CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
 				     CSR_GPIO_IN_BIT_AUX_POWER, 5000);
 		} else
-			iwl_release_restricted_access(priv);
+			iwl3945_release_nic_access(priv);
 	} else {
-		iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG,
+		iwl3945_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
 				APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
 				~APMG_PS_CTRL_MSK_PWR_SRC);
 
-		iwl_release_restricted_access(priv);
-		iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
+		iwl3945_release_nic_access(priv);
+		iwl3945_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
 			     CSR_GPIO_IN_BIT_AUX_POWER, 5000);	/* uS */
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -757,24 +829,24 @@ static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
 	return rc;
 }
 
-static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+static int iwl3945_rx_init(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq)
 {
 	int rc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	iwl_write_restricted(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr);
-	iwl_write_restricted(priv, FH_RCSR_RPTR_ADDR(0),
+	iwl3945_write_direct32(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr);
+	iwl3945_write_direct32(priv, FH_RCSR_RPTR_ADDR(0),
 			     priv->hw_setting.shared_phys +
-			     offsetof(struct iwl_shared, rx_read_ptr[0]));
-	iwl_write_restricted(priv, FH_RCSR_WPTR(0), 0);
-	iwl_write_restricted(priv, FH_RCSR_CONFIG(0),
+			     offsetof(struct iwl3945_shared, rx_read_ptr[0]));
+	iwl3945_write_direct32(priv, FH_RCSR_WPTR(0), 0);
+	iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0),
 		ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE |
 		ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE |
 		ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN |
@@ -785,44 +857,44 @@ static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
 		ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH);
 
 	/* fake read to flush all prev I/O */
-	iwl_read_restricted(priv, FH_RSSR_CTRL);
+	iwl3945_read_direct32(priv, FH_RSSR_CTRL);
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-static int iwl3945_tx_reset(struct iwl_priv *priv)
+static int iwl3945_tx_reset(struct iwl3945_priv *priv)
 {
 	int rc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
 	/* bypass mode */
-	iwl_write_restricted_reg(priv, SCD_MODE_REG, 0x2);
+	iwl3945_write_prph(priv, ALM_SCD_MODE_REG, 0x2);
 
 	/* RA 0 is active */
-	iwl_write_restricted_reg(priv, SCD_ARASTAT_REG, 0x01);
+	iwl3945_write_prph(priv, ALM_SCD_ARASTAT_REG, 0x01);
 
 	/* all 6 fifo are active */
-	iwl_write_restricted_reg(priv, SCD_TXFACT_REG, 0x3f);
+	iwl3945_write_prph(priv, ALM_SCD_TXFACT_REG, 0x3f);
 
-	iwl_write_restricted_reg(priv, SCD_SBYP_MODE_1_REG, 0x010000);
-	iwl_write_restricted_reg(priv, SCD_SBYP_MODE_2_REG, 0x030002);
-	iwl_write_restricted_reg(priv, SCD_TXF4MF_REG, 0x000004);
-	iwl_write_restricted_reg(priv, SCD_TXF5MF_REG, 0x000005);
+	iwl3945_write_prph(priv, ALM_SCD_SBYP_MODE_1_REG, 0x010000);
+	iwl3945_write_prph(priv, ALM_SCD_SBYP_MODE_2_REG, 0x030002);
+	iwl3945_write_prph(priv, ALM_SCD_TXF4MF_REG, 0x000004);
+	iwl3945_write_prph(priv, ALM_SCD_TXF5MF_REG, 0x000005);
 
-	iwl_write_restricted(priv, FH_TSSR_CBB_BASE,
+	iwl3945_write_direct32(priv, FH_TSSR_CBB_BASE,
 			     priv->hw_setting.shared_phys);
 
-	iwl_write_restricted(priv, FH_TSSR_MSG_CONFIG,
+	iwl3945_write_direct32(priv, FH_TSSR_MSG_CONFIG,
 		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON |
 		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON |
 		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B |
@@ -831,7 +903,7 @@ static int iwl3945_tx_reset(struct iwl_priv *priv)
 		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH |
 		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH);
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
@@ -842,12 +914,12 @@ static int iwl3945_tx_reset(struct iwl_priv *priv)
  *
  * Destroys all DMA structures and initialize them again
  */
-static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
+static int iwl3945_txq_ctx_reset(struct iwl3945_priv *priv)
 {
 	int rc;
 	int txq_id, slots_num;
 
-	iwl_hw_txq_ctx_free(priv);
+	iwl3945_hw_txq_ctx_free(priv);
 
 	/* Tx CMD queue */
 	rc = iwl3945_tx_reset(priv);
@@ -858,7 +930,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
 	for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) {
 		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
 				TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-		rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+		rc = iwl3945_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
 				txq_id);
 		if (rc) {
 			IWL_ERROR("Tx %d queue init failed\n", txq_id);
@@ -869,26 +941,26 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
 	return rc;
 
  error:
-	iwl_hw_txq_ctx_free(priv);
+	iwl3945_hw_txq_ctx_free(priv);
 	return rc;
 }
 
-int iwl_hw_nic_init(struct iwl_priv *priv)
+int iwl3945_hw_nic_init(struct iwl3945_priv *priv)
 {
 	u8 rev_id;
 	int rc;
 	unsigned long flags;
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl3945_rx_queue *rxq = &priv->rxq;
 
-	iwl_power_init_handle(priv);
+	iwl3945_power_init_handle(priv);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24));
-	iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+	iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24));
+	iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
 		    CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
 
-	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+	iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 	if (rc < 0) {
@@ -897,18 +969,18 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 		return rc;
 	}
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
-	iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+	iwl3945_write_prph(priv, APMG_CLK_EN_REG,
 				 APMG_CLK_VAL_DMA_CLK_RQT |
 				 APMG_CLK_VAL_BSM_CLK_RQT);
 	udelay(20);
-	iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+	iwl3945_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
 				    APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* Determine HW type */
@@ -924,25 +996,17 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 		IWL_DEBUG_INFO("RTP type \n");
 	else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
 		IWL_DEBUG_INFO("ALM-MB type\n");
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB);
 	} else {
 		IWL_DEBUG_INFO("ALM-MM type\n");
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM);
 	}
 
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	/* Initialize the EEPROM */
-	rc = iwl_eeprom_init(priv);
-	if (rc)
-		return rc;
-
-	spin_lock_irqsave(&priv->lock, flags);
 	if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) {
 		IWL_DEBUG_INFO("SKU OP mode is mrc\n");
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC);
 	} else
 		IWL_DEBUG_INFO("SKU OP mode is basic\n");
@@ -950,24 +1014,24 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 	if ((priv->eeprom.board_revision & 0xF0) == 0xD0) {
 		IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
 			       priv->eeprom.board_revision);
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
 	} else {
 		IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
 			       priv->eeprom.board_revision);
-		iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
 			      CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
 	}
 
 	if (priv->eeprom.almgor_m_version <= 1) {
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
 		IWL_DEBUG_INFO("Card M type A version is 0x%X\n",
 			       priv->eeprom.almgor_m_version);
 	} else {
 		IWL_DEBUG_INFO("Card M type B version is 0x%X\n",
 			       priv->eeprom.almgor_m_version);
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			    CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -980,15 +1044,15 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 
 	/* Allocate the RX queue, or reset if it is already allocated */
 	if (!rxq->bd) {
-		rc = iwl_rx_queue_alloc(priv);
+		rc = iwl3945_rx_queue_alloc(priv);
 		if (rc) {
 			IWL_ERROR("Unable to initialize Rx queue\n");
 			return -ENOMEM;
 		}
 	} else
-		iwl_rx_queue_reset(priv, rxq);
+		iwl3945_rx_queue_reset(priv, rxq);
 
-	iwl_rx_replenish(priv);
+	iwl3945_rx_replenish(priv);
 
 	iwl3945_rx_init(priv, rxq);
 
@@ -996,16 +1060,16 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 
 	/* Look at using this instead:
 	rxq->need_update = 1;
-	iwl_rx_queue_update_write_ptr(priv, rxq);
+	iwl3945_rx_queue_update_write_ptr(priv, rxq);
 	*/
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
-	iwl_write_restricted(priv, FH_RCSR_WPTR(0), rxq->write & ~7);
-	iwl_release_restricted_access(priv);
+	iwl3945_write_direct32(priv, FH_RCSR_WPTR(0), rxq->write & ~7);
+	iwl3945_release_nic_access(priv);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -1019,49 +1083,49 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 }
 
 /**
- * iwl_hw_txq_ctx_free - Free TXQ Context
+ * iwl3945_hw_txq_ctx_free - Free TXQ Context
  *
  * Destroy all TX DMA queues and structures
  */
-void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+void iwl3945_hw_txq_ctx_free(struct iwl3945_priv *priv)
 {
 	int txq_id;
 
 	/* Tx queues */
 	for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++)
-		iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+		iwl3945_tx_queue_free(priv, &priv->txq[txq_id]);
 }
 
-void iwl_hw_txq_ctx_stop(struct iwl_priv *priv)
+void iwl3945_hw_txq_ctx_stop(struct iwl3945_priv *priv)
 {
 	int queue;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if (iwl_grab_restricted_access(priv)) {
+	if (iwl3945_grab_nic_access(priv)) {
 		spin_unlock_irqrestore(&priv->lock, flags);
-		iwl_hw_txq_ctx_free(priv);
+		iwl3945_hw_txq_ctx_free(priv);
 		return;
 	}
 
 	/* stop SCD */
-	iwl_write_restricted_reg(priv, SCD_MODE_REG, 0);
+	iwl3945_write_prph(priv, ALM_SCD_MODE_REG, 0);
 
 	/* reset TFD queues */
 	for (queue = TFD_QUEUE_MIN; queue < TFD_QUEUE_MAX; queue++) {
-		iwl_write_restricted(priv, FH_TCSR_CONFIG(queue), 0x0);
-		iwl_poll_restricted_bit(priv, FH_TSSR_TX_STATUS,
+		iwl3945_write_direct32(priv, FH_TCSR_CONFIG(queue), 0x0);
+		iwl3945_poll_direct_bit(priv, FH_TSSR_TX_STATUS,
 				ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(queue),
 				1000);
 	}
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	iwl_hw_txq_ctx_free(priv);
+	iwl3945_hw_txq_ctx_free(priv);
 }
 
-int iwl_hw_nic_stop_master(struct iwl_priv *priv)
+int iwl3945_hw_nic_stop_master(struct iwl3945_priv *priv)
 {
 	int rc = 0;
 	u32 reg_val;
@@ -1070,16 +1134,16 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv)
 	spin_lock_irqsave(&priv->lock, flags);
 
 	/* set stop master bit */
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+	iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
-	reg_val = iwl_read32(priv, CSR_GP_CNTRL);
+	reg_val = iwl3945_read32(priv, CSR_GP_CNTRL);
 
 	if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
 	    (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
 		IWL_DEBUG_INFO("Card in power save, master is already "
 			       "stopped\n");
 	else {
-		rc = iwl_poll_bit(priv, CSR_RESET,
+		rc = iwl3945_poll_bit(priv, CSR_RESET,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
 		if (rc < 0) {
@@ -1094,47 +1158,47 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv)
 	return rc;
 }
 
-int iwl_hw_nic_reset(struct iwl_priv *priv)
+int iwl3945_hw_nic_reset(struct iwl3945_priv *priv)
 {
 	int rc;
 	unsigned long flags;
 
-	iwl_hw_nic_stop_master(priv);
+	iwl3945_hw_nic_stop_master(priv);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+	iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
-	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+	rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (!rc) {
-		iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,
+		iwl3945_write_prph(priv, APMG_CLK_CTRL_REG,
 					 APMG_CLK_VAL_BSM_CLK_RQT);
 
 		udelay(10);
 
-		iwl_set_bit(priv, CSR_GP_CNTRL,
+		iwl3945_set_bit(priv, CSR_GP_CNTRL,
 			    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
-		iwl_write_restricted_reg(priv, APMG_RTC_INT_MSK_REG, 0x0);
-		iwl_write_restricted_reg(priv, APMG_RTC_INT_STT_REG,
+		iwl3945_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0);
+		iwl3945_write_prph(priv, APMG_RTC_INT_STT_REG,
 					0xFFFFFFFF);
 
 		/* enable DMA */
-		iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+		iwl3945_write_prph(priv, APMG_CLK_EN_REG,
 					 APMG_CLK_VAL_DMA_CLK_RQT |
 					 APMG_CLK_VAL_BSM_CLK_RQT);
 		udelay(10);
 
-		iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+		iwl3945_set_bits_prph(priv, APMG_PS_CTRL_REG,
 				APMG_PS_CTRL_VAL_RESET_REQ);
 		udelay(5);
-		iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+		iwl3945_clear_bits_prph(priv, APMG_PS_CTRL_REG,
 				APMG_PS_CTRL_VAL_RESET_REQ);
-		iwl_release_restricted_access(priv);
+		iwl3945_release_nic_access(priv);
 	}
 
 	/* Clear the 'host command active' bit... */
@@ -1147,41 +1211,43 @@ int iwl_hw_nic_reset(struct iwl_priv *priv)
 }
 
 /**
- * iwl_hw_reg_adjust_power_by_temp - return index delta into power gain settings table
- */
-static int iwl_hw_reg_adjust_power_by_temp(int new_reading, int old_reading)
+ * iwl3945_hw_reg_adjust_power_by_temp
+ * return index delta into power gain settings table
+*/
+static int iwl3945_hw_reg_adjust_power_by_temp(int new_reading, int old_reading)
 {
 	return (new_reading - old_reading) * (-11) / 100;
 }
 
 /**
- * iwl_hw_reg_temp_out_of_range - Keep temperature in sane range
+ * iwl3945_hw_reg_temp_out_of_range - Keep temperature in sane range
  */
-static inline int iwl_hw_reg_temp_out_of_range(int temperature)
+static inline int iwl3945_hw_reg_temp_out_of_range(int temperature)
 {
 	return (((temperature < -260) || (temperature > 25)) ? 1 : 0);
 }
 
-int iwl_hw_get_temperature(struct iwl_priv *priv)
+int iwl3945_hw_get_temperature(struct iwl3945_priv *priv)
 {
-	return iwl_read32(priv, CSR_UCODE_DRV_GP2);
+	return iwl3945_read32(priv, CSR_UCODE_DRV_GP2);
 }
 
 /**
- * iwl_hw_reg_txpower_get_temperature - get current temperature by reading from NIC
- */
-static int iwl_hw_reg_txpower_get_temperature(struct iwl_priv *priv)
+ * iwl3945_hw_reg_txpower_get_temperature
+ * get the current temperature by reading from NIC
+*/
+static int iwl3945_hw_reg_txpower_get_temperature(struct iwl3945_priv *priv)
 {
 	int temperature;
 
-	temperature = iwl_hw_get_temperature(priv);
+	temperature = iwl3945_hw_get_temperature(priv);
 
 	/* driver's okay range is -260 to +25.
 	 *   human readable okay range is 0 to +285 */
 	IWL_DEBUG_INFO("Temperature: %d\n", temperature + IWL_TEMP_CONVERT);
 
 	/* handle insane temp reading */
-	if (iwl_hw_reg_temp_out_of_range(temperature)) {
+	if (iwl3945_hw_reg_temp_out_of_range(temperature)) {
 		IWL_ERROR("Error bad temperature value  %d\n", temperature);
 
 		/* if really really hot(?),
@@ -1206,11 +1272,11 @@ static int iwl_hw_reg_txpower_get_temperature(struct iwl_priv *priv)
  * records new temperature in tx_mgr->temperature.
  * replaces tx_mgr->last_temperature *only* if calib needed
  *    (assumes caller will actually do the calibration!). */
-static int is_temp_calib_needed(struct iwl_priv *priv)
+static int is_temp_calib_needed(struct iwl3945_priv *priv)
 {
 	int temp_diff;
 
-	priv->temperature = iwl_hw_reg_txpower_get_temperature(priv);
+	priv->temperature = iwl3945_hw_reg_txpower_get_temperature(priv);
 	temp_diff = priv->temperature - priv->last_temperature;
 
 	/* get absolute value */
@@ -1242,7 +1308,7 @@ static int is_temp_calib_needed(struct iwl_priv *priv)
 
 /* radio and DSP power table, each step is 1/2 dB.
  * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */
-static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = {
+static struct iwl3945_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = {
 	{
 	 {251, 127},		/* 2.4 GHz, highest power */
 	 {251, 127},
@@ -1403,7 +1469,7 @@ static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = {
 	 {3, 120} }		/* 5.x GHz, lowest power */
 };
 
-static inline u8 iwl_hw_reg_fix_power_index(int index)
+static inline u8 iwl3945_hw_reg_fix_power_index(int index)
 {
 	if (index < 0)
 		return 0;
@@ -1416,17 +1482,17 @@ static inline u8 iwl_hw_reg_fix_power_index(int index)
 #define REG_RECALIB_PERIOD (60)
 
 /**
- * iwl_hw_reg_set_scan_power - Set Tx power for scan probe requests
+ * iwl3945_hw_reg_set_scan_power - Set Tx power for scan probe requests
  *
  * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK)
  * or 6 Mbit (OFDM) rates.
  */
-static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
+static void iwl3945_hw_reg_set_scan_power(struct iwl3945_priv *priv, u32 scan_tbl_index,
 			       s32 rate_index, const s8 *clip_pwrs,
-			       struct iwl_channel_info *ch_info,
+			       struct iwl3945_channel_info *ch_info,
 			       int band_index)
 {
-	struct iwl_scan_power_info *scan_power_info;
+	struct iwl3945_scan_power_info *scan_power_info;
 	s8 power;
 	u8 power_index;
 
@@ -1462,7 +1528,7 @@ static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
 	 *   of the table. */
 
 	/* don't exceed table bounds for "real" setting */
-	power_index = iwl_hw_reg_fix_power_index(power_index);
+	power_index = iwl3945_hw_reg_fix_power_index(power_index);
 
 	scan_power_info->power_table_index = power_index;
 	scan_power_info->tpc.tx_gain =
@@ -1472,21 +1538,21 @@ static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
 }
 
 /**
- * iwl_hw_reg_send_txpower - fill in Tx Power command with gain settings
+ * iwl3945_hw_reg_send_txpower - fill in Tx Power command with gain settings
  *
  * Configures power settings for all rates for the current channel,
  * using values from channel info struct, and send to NIC
  */
-int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
+int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv)
 {
 	int rate_idx, i;
-	const struct iwl_channel_info *ch_info = NULL;
-	struct iwl_txpowertable_cmd txpower = {
+	const struct iwl3945_channel_info *ch_info = NULL;
+	struct iwl3945_txpowertable_cmd txpower = {
 		.channel = priv->active_rxon.channel,
 	};
 
 	txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1;
-	ch_info = iwl_get_channel_info(priv,
+	ch_info = iwl3945_get_channel_info(priv,
 				       priv->phymode,
 				       le16_to_cpu(priv->active_rxon.channel));
 	if (!ch_info) {
@@ -1508,7 +1574,7 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 	     rate_idx <= IWL_LAST_OFDM_RATE; rate_idx++, i++) {
 
 		txpower.power[i].tpc = ch_info->power_info[i].tpc;
-		txpower.power[i].rate = iwl_rates[rate_idx].plcp;
+		txpower.power[i].rate = iwl3945_rates[rate_idx].plcp;
 
 		IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
 				le16_to_cpu(txpower.channel),
@@ -1521,7 +1587,7 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 	for (rate_idx = IWL_FIRST_CCK_RATE;
 	     rate_idx <= IWL_LAST_CCK_RATE; rate_idx++, i++) {
 		txpower.power[i].tpc = ch_info->power_info[i].tpc;
-		txpower.power[i].rate = iwl_rates[rate_idx].plcp;
+		txpower.power[i].rate = iwl3945_rates[rate_idx].plcp;
 
 		IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
 				le16_to_cpu(txpower.channel),
@@ -1531,13 +1597,13 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 				txpower.power[i].rate);
 	}
 
-	return iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD,
-			sizeof(struct iwl_txpowertable_cmd), &txpower);
+	return iwl3945_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD,
+			sizeof(struct iwl3945_txpowertable_cmd), &txpower);
 
 }
 
 /**
- * iwl_hw_reg_set_new_power - Configures power tables at new levels
+ * iwl3945_hw_reg_set_new_power - Configures power tables at new levels
  * @ch_info: Channel to update.  Uses power_info.requested_power.
  *
  * Replace requested_power and base_power_index ch_info fields for
@@ -1552,10 +1618,10 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
  *	 properly fill out the scan powers, and actual h/w gain settings,
  *	 and send changes to NIC
  */
-static int iwl_hw_reg_set_new_power(struct iwl_priv *priv,
-			     struct iwl_channel_info *ch_info)
+static int iwl3945_hw_reg_set_new_power(struct iwl3945_priv *priv,
+			     struct iwl3945_channel_info *ch_info)
 {
-	struct iwl_channel_power_info *power_info;
+	struct iwl3945_channel_power_info *power_info;
 	int power_changed = 0;
 	int i;
 	const s8 *clip_pwrs;
@@ -1595,7 +1661,7 @@ static int iwl_hw_reg_set_new_power(struct iwl_priv *priv,
 		    ch_info->power_info[IWL_RATE_12M_INDEX_TABLE].
 		    requested_power + IWL_CCK_FROM_OFDM_POWER_DIFF;
 
-		/* do all CCK rates' iwl_channel_power_info structures */
+		/* do all CCK rates' iwl3945_channel_power_info structures */
 		for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++) {
 			power_info->requested_power = power;
 			power_info->base_power_index =
@@ -1609,13 +1675,13 @@ static int iwl_hw_reg_set_new_power(struct iwl_priv *priv,
 }
 
 /**
- * iwl_hw_reg_get_ch_txpower_limit - returns new power limit for channel
+ * iwl3945_hw_reg_get_ch_txpower_limit - returns new power limit for channel
  *
  * NOTE: Returned power limit may be less (but not more) than requested,
  *	 based strictly on regulatory (eeprom and spectrum mgt) limitations
  *	 (no consideration for h/w clipping limitations).
  */
-static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info)
+static int iwl3945_hw_reg_get_ch_txpower_limit(struct iwl3945_channel_info *ch_info)
 {
 	s8 max_power;
 
@@ -1634,7 +1700,7 @@ static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info)
 }
 
 /**
- * iwl_hw_reg_comp_txpower_temp - Compensate for temperature
+ * iwl3945_hw_reg_comp_txpower_temp - Compensate for temperature
  *
  * Compensate txpower settings of *all* channels for temperature.
  * This only accounts for the difference between current temperature
@@ -1643,9 +1709,9 @@ static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info)
  *
  * If RxOn is "associated", this sends the new Txpower to NIC!
  */
-static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
+static int iwl3945_hw_reg_comp_txpower_temp(struct iwl3945_priv *priv)
 {
-	struct iwl_channel_info *ch_info = NULL;
+	struct iwl3945_channel_info *ch_info = NULL;
 	int delta_index;
 	const s8 *clip_pwrs; /* array of h/w max power levels for each rate */
 	u8 a_band;
@@ -1666,7 +1732,7 @@ static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
 
 		/* get power index adjustment based on curr and factory
 		 * temps */
-		delta_index = iwl_hw_reg_adjust_power_by_temp(temperature,
+		delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature,
 							      ref_temp);
 
 		/* set tx power value for all rates, OFDM and CCK */
@@ -1679,7 +1745,7 @@ static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
 			power_idx += delta_index;
 
 			/* stay within table range */
-			power_idx = iwl_hw_reg_fix_power_index(power_idx);
+			power_idx = iwl3945_hw_reg_fix_power_index(power_idx);
 			ch_info->power_info[rate_index].
 			    power_table_index = (u8) power_idx;
 			ch_info->power_info[rate_index].tpc =
@@ -1694,19 +1760,19 @@ static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
 		     scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) {
 			s32 actual_index = (scan_tbl_index == 0) ?
 			    IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE;
-			iwl_hw_reg_set_scan_power(priv, scan_tbl_index,
+			iwl3945_hw_reg_set_scan_power(priv, scan_tbl_index,
 					   actual_index, clip_pwrs,
 					   ch_info, a_band);
 		}
 	}
 
 	/* send Txpower command for current channel to ucode */
-	return iwl_hw_reg_send_txpower(priv);
+	return iwl3945_hw_reg_send_txpower(priv);
 }
 
-int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
+int iwl3945_hw_reg_set_txpower(struct iwl3945_priv *priv, s8 power)
 {
-	struct iwl_channel_info *ch_info;
+	struct iwl3945_channel_info *ch_info;
 	s8 max_power;
 	u8 a_band;
 	u8 i;
@@ -1728,26 +1794,26 @@ int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
 
 		/* find minimum power of all user and regulatory constraints
 		 *    (does not consider h/w clipping limitations) */
-		max_power = iwl_hw_reg_get_ch_txpower_limit(ch_info);
+		max_power = iwl3945_hw_reg_get_ch_txpower_limit(ch_info);
 		max_power = min(power, max_power);
 		if (max_power != ch_info->curr_txpow) {
 			ch_info->curr_txpow = max_power;
 
 			/* this considers the h/w clipping limitations */
-			iwl_hw_reg_set_new_power(priv, ch_info);
+			iwl3945_hw_reg_set_new_power(priv, ch_info);
 		}
 	}
 
 	/* update txpower settings for all channels,
 	 *   send to NIC if associated. */
 	is_temp_calib_needed(priv);
-	iwl_hw_reg_comp_txpower_temp(priv);
+	iwl3945_hw_reg_comp_txpower_temp(priv);
 
 	return 0;
 }
 
 /* will add 3945 channel switch cmd handling later */
-int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+int iwl3945_hw_channel_switch(struct iwl3945_priv *priv, u16 channel)
 {
 	return 0;
 }
@@ -1762,26 +1828,26 @@ int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel)
  *     -- send new set of gain settings to NIC
  * NOTE:  This should continue working, even when we're not associated,
  *   so we can keep our internal table of scan powers current. */
-void iwl3945_reg_txpower_periodic(struct iwl_priv *priv)
+void iwl3945_reg_txpower_periodic(struct iwl3945_priv *priv)
 {
 	/* This will kick in the "brute force"
-	 * iwl_hw_reg_comp_txpower_temp() below */
+	 * iwl3945_hw_reg_comp_txpower_temp() below */
 	if (!is_temp_calib_needed(priv))
 		goto reschedule;
 
 	/* Set up a new set of temp-adjusted TxPowers, send to NIC.
 	 * This is based *only* on current temperature,
 	 * ignoring any previous power measurements */
-	iwl_hw_reg_comp_txpower_temp(priv);
+	iwl3945_hw_reg_comp_txpower_temp(priv);
 
  reschedule:
 	queue_delayed_work(priv->workqueue,
 			   &priv->thermal_periodic, REG_RECALIB_PERIOD * HZ);
 }
 
-void iwl3945_bg_reg_txpower_periodic(struct work_struct *work)
+static void iwl3945_bg_reg_txpower_periodic(struct work_struct *work)
 {
-	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+	struct iwl3945_priv *priv = container_of(work, struct iwl3945_priv,
 					     thermal_periodic.work);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -1793,7 +1859,7 @@ void iwl3945_bg_reg_txpower_periodic(struct work_struct *work)
 }
 
 /**
- * iwl_hw_reg_get_ch_grp_index - find the channel-group index (0-4)
+ * iwl3945_hw_reg_get_ch_grp_index - find the channel-group index (0-4)
  * 				   for the channel.
  *
  * This function is used when initializing channel-info structs.
@@ -1803,10 +1869,10 @@ void iwl3945_bg_reg_txpower_periodic(struct work_struct *work)
  *	 on A-band, EEPROM's "group frequency" entries represent the top
  *	 channel in each group 1-4.  Group 5 All B/G channels are in group 0.
  */
-static u16 iwl_hw_reg_get_ch_grp_index(struct iwl_priv *priv,
-				       const struct iwl_channel_info *ch_info)
+static u16 iwl3945_hw_reg_get_ch_grp_index(struct iwl3945_priv *priv,
+				       const struct iwl3945_channel_info *ch_info)
 {
-	struct iwl_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0];
+	struct iwl3945_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0];
 	u8 group;
 	u16 group_index = 0;	/* based on factory calib frequencies */
 	u8 grp_channel;
@@ -1832,20 +1898,20 @@ static u16 iwl_hw_reg_get_ch_grp_index(struct iwl_priv *priv,
 }
 
 /**
- * iwl_hw_reg_get_matched_power_index - Interpolate to get nominal index
+ * iwl3945_hw_reg_get_matched_power_index - Interpolate to get nominal index
  *
  * Interpolate to get nominal (i.e. at factory calibration temperature) index
  *   into radio/DSP gain settings table for requested power.
  */
-static int iwl_hw_reg_get_matched_power_index(struct iwl_priv *priv,
+static int iwl3945_hw_reg_get_matched_power_index(struct iwl3945_priv *priv,
 				       s8 requested_power,
 				       s32 setting_index, s32 *new_index)
 {
-	const struct iwl_eeprom_txpower_group *chnl_grp = NULL;
+	const struct iwl3945_eeprom_txpower_group *chnl_grp = NULL;
 	s32 index0, index1;
 	s32 power = 2 * requested_power;
 	s32 i;
-	const struct iwl_eeprom_txpower_sample *samples;
+	const struct iwl3945_eeprom_txpower_sample *samples;
 	s32 gains0, gains1;
 	s32 res;
 	s32 denominator;
@@ -1885,11 +1951,11 @@ static int iwl_hw_reg_get_matched_power_index(struct iwl_priv *priv,
 	return 0;
 }
 
-static void iwl_hw_reg_init_channel_groups(struct iwl_priv *priv)
+static void iwl3945_hw_reg_init_channel_groups(struct iwl3945_priv *priv)
 {
 	u32 i;
 	s32 rate_index;
-	const struct iwl_eeprom_txpower_group *group;
+	const struct iwl3945_eeprom_txpower_group *group;
 
 	IWL_DEBUG_POWER("Initializing factory calib info from EEPROM\n");
 
@@ -1965,10 +2031,10 @@ static void iwl_hw_reg_init_channel_groups(struct iwl_priv *priv)
  *
  * This does *not* write values to NIC, just sets up our internal table.
  */
-int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
+int iwl3945_txpower_set_from_eeprom(struct iwl3945_priv *priv)
 {
-	struct iwl_channel_info *ch_info = NULL;
-	struct iwl_channel_power_info *pwr_info;
+	struct iwl3945_channel_info *ch_info = NULL;
+	struct iwl3945_channel_power_info *pwr_info;
 	int delta_index;
 	u8 rate_index;
 	u8 scan_tbl_index;
@@ -1981,10 +2047,10 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 
 	/* save temperature reference,
 	 *   so we can determine next time to calibrate */
-	temperature = iwl_hw_reg_txpower_get_temperature(priv);
+	temperature = iwl3945_hw_reg_txpower_get_temperature(priv);
 	priv->last_temperature = temperature;
 
-	iwl_hw_reg_init_channel_groups(priv);
+	iwl3945_hw_reg_init_channel_groups(priv);
 
 	/* initialize Tx power info for each and every channel, 2.4 and 5.x */
 	for (i = 0, ch_info = priv->channel_info; i < priv->channel_count;
@@ -1995,14 +2061,14 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 
 		/* find this channel's channel group (*not* "band") index */
 		ch_info->group_index =
-			iwl_hw_reg_get_ch_grp_index(priv, ch_info);
+			iwl3945_hw_reg_get_ch_grp_index(priv, ch_info);
 
 		/* Get this chnlgrp's rate->max/clip-powers table */
 		clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
 
 		/* calculate power index *adjustment* value according to
 		 *  diff between current temperature and factory temperature */
-		delta_index = iwl_hw_reg_adjust_power_by_temp(temperature,
+		delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature,
 				priv->eeprom.groups[ch_info->group_index].
 				temperature);
 
@@ -2025,7 +2091,7 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 
 			/* get base (i.e. at factory-measured temperature)
 			 *    power table index for this rate's power */
-			rc = iwl_hw_reg_get_matched_power_index(priv, pwr,
+			rc = iwl3945_hw_reg_get_matched_power_index(priv, pwr,
 							 ch_info->group_index,
 							 &power_idx);
 			if (rc) {
@@ -2038,9 +2104,9 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 			power_idx += delta_index;
 
 			/* stay within range of gain table */
-			power_idx = iwl_hw_reg_fix_power_index(power_idx);
+			power_idx = iwl3945_hw_reg_fix_power_index(power_idx);
 
-			/* fill 1 OFDM rate's iwl_channel_power_info struct */
+			/* fill 1 OFDM rate's iwl3945_channel_power_info struct */
 			pwr_info->requested_power = pwr;
 			pwr_info->power_table_index = (u8) power_idx;
 			pwr_info->tpc.tx_gain =
@@ -2059,11 +2125,11 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 			IWL_CCK_FROM_OFDM_INDEX_DIFF;
 
 		/* stay within table range */
-		pwr_index = iwl_hw_reg_fix_power_index(pwr_index);
+		pwr_index = iwl3945_hw_reg_fix_power_index(pwr_index);
 		gain = power_gain_table[a_band][pwr_index].tx_gain;
 		dsp_atten = power_gain_table[a_band][pwr_index].dsp_atten;
 
-		/* fill each CCK rate's iwl_channel_power_info structure
+		/* fill each CCK rate's iwl3945_channel_power_info structure
 		 * NOTE:  All CCK-rate Txpwrs are the same for a given chnl!
 		 * NOTE:  CCK rates start at end of OFDM rates! */
 		for (rate_index = 0;
@@ -2081,7 +2147,7 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 		     scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) {
 			s32 actual_index = (scan_tbl_index == 0) ?
 				IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE;
-			iwl_hw_reg_set_scan_power(priv, scan_tbl_index,
+			iwl3945_hw_reg_set_scan_power(priv, scan_tbl_index,
 				actual_index, clip_pwrs, ch_info, a_band);
 		}
 	}
@@ -2089,66 +2155,66 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
 	return 0;
 }
 
-int iwl_hw_rxq_stop(struct iwl_priv *priv)
+int iwl3945_hw_rxq_stop(struct iwl3945_priv *priv)
 {
 	int rc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	iwl_write_restricted(priv, FH_RCSR_CONFIG(0), 0);
-	rc = iwl_poll_restricted_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000);
+	iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0), 0);
+	rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000);
 	if (rc < 0)
 		IWL_ERROR("Can't stop Rx DMA.\n");
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+int iwl3945_hw_tx_queue_init(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq)
 {
 	int rc;
 	unsigned long flags;
 	int txq_id = txq->q.id;
 
-	struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+	struct iwl3945_shared *shared_data = priv->hw_setting.shared_virt;
 
 	shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
-	iwl_write_restricted(priv, FH_CBCC_CTRL(txq_id), 0);
-	iwl_write_restricted(priv, FH_CBCC_BASE(txq_id), 0);
+	iwl3945_write_direct32(priv, FH_CBCC_CTRL(txq_id), 0);
+	iwl3945_write_direct32(priv, FH_CBCC_BASE(txq_id), 0);
 
-	iwl_write_restricted(priv, FH_TCSR_CONFIG(txq_id),
+	iwl3945_write_direct32(priv, FH_TCSR_CONFIG(txq_id),
 		ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT |
 		ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF |
 		ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD |
 		ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL |
 		ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE);
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 
 	/* fake read to flush all prev. writes */
-	iwl_read32(priv, FH_TSSR_CBB_BASE);
+	iwl3945_read32(priv, FH_TSSR_CBB_BASE);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-int iwl_hw_get_rx_read(struct iwl_priv *priv)
+int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv)
 {
-	struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+	struct iwl3945_shared *shared_data = priv->hw_setting.shared_virt;
 
 	return le32_to_cpu(shared_data->rx_read_ptr[0]);
 }
@@ -2156,22 +2222,22 @@ int iwl_hw_get_rx_read(struct iwl_priv *priv)
 /**
  * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table
  */
-int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
+int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv)
 {
 	int rc, i, index, prev_index;
-	struct iwl_rate_scaling_cmd rate_cmd = {
+	struct iwl3945_rate_scaling_cmd rate_cmd = {
 		.reserved = {0, 0, 0},
 	};
-	struct iwl_rate_scaling_info *table = rate_cmd.table;
+	struct iwl3945_rate_scaling_info *table = rate_cmd.table;
 
-	for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) {
-		index = iwl_rates[i].table_rs_index;
+	for (i = 0; i < ARRAY_SIZE(iwl3945_rates); i++) {
+		index = iwl3945_rates[i].table_rs_index;
 
 		table[index].rate_n_flags =
-			iwl_hw_set_rate_n_flags(iwl_rates[i].plcp, 0);
+			iwl3945_hw_set_rate_n_flags(iwl3945_rates[i].plcp, 0);
 		table[index].try_cnt = priv->retry_rate;
-		prev_index = iwl_get_prev_ieee_rate(i);
-		table[index].next_rate_index = iwl_rates[prev_index].table_rs_index;
+		prev_index = iwl3945_get_prev_ieee_rate(i);
+		table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index;
 	}
 
 	switch (priv->phymode) {
@@ -2180,14 +2246,14 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
 		/* If one of the following CCK rates is used,
 		 * have it fall back to the 6M OFDM rate */
 		for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++)
-			table[i].next_rate_index = iwl_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
+			table[i].next_rate_index = iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
 
 		/* Don't fall back to CCK rates */
 		table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = IWL_RATE_9M_INDEX_TABLE;
 
 		/* Don't drop out of OFDM rates */
 		table[IWL_RATE_6M_INDEX_TABLE].next_rate_index =
-		    iwl_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
+		    iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
 		break;
 
 	case MODE_IEEE80211B:
@@ -2195,7 +2261,7 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
 		/* If an OFDM rate is used, have it fall back to the
 		 * 1M CCK rates */
 		for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++)
-			table[i].next_rate_index = iwl_rates[IWL_FIRST_CCK_RATE].table_rs_index;
+			table[i].next_rate_index = iwl3945_rates[IWL_FIRST_CCK_RATE].table_rs_index;
 
 		/* CCK shouldn't fall back to OFDM... */
 		table[IWL_RATE_11M_INDEX_TABLE].next_rate_index = IWL_RATE_5M_INDEX_TABLE;
@@ -2208,25 +2274,26 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
 
 	/* Update the rate scaling for control frame Tx */
 	rate_cmd.table_id = 0;
-	rc = iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
+	rc = iwl3945_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
 			      &rate_cmd);
 	if (rc)
 		return rc;
 
 	/* Update the rate scaling for data frame Tx */
 	rate_cmd.table_id = 1;
-	return iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
+	return iwl3945_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
 				&rate_cmd);
 }
 
-int iwl_hw_set_hw_setting(struct iwl_priv *priv)
+/* Called when initializing driver */
+int iwl3945_hw_set_hw_setting(struct iwl3945_priv *priv)
 {
 	memset((void *)&priv->hw_setting, 0,
-	       sizeof(struct iwl_driver_hw_info));
+	       sizeof(struct iwl3945_driver_hw_info));
 
 	priv->hw_setting.shared_virt =
 	    pci_alloc_consistent(priv->pci_dev,
-				 sizeof(struct iwl_shared),
+				 sizeof(struct iwl3945_shared),
 				 &priv->hw_setting.shared_phys);
 
 	if (!priv->hw_setting.shared_virt) {
@@ -2236,31 +2303,31 @@ int iwl_hw_set_hw_setting(struct iwl_priv *priv)
 	}
 
 	priv->hw_setting.ac_queue_count = AC_NUM;
-	priv->hw_setting.rx_buffer_size = IWL_RX_BUF_SIZE;
-	priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd);
+	priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE;
+	priv->hw_setting.max_pkt_size = 2342;
+	priv->hw_setting.tx_cmd_len = sizeof(struct iwl3945_tx_cmd);
 	priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
 	priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
-	priv->hw_setting.cck_flag = 0;
 	priv->hw_setting.max_stations = IWL3945_STATION_COUNT;
 	priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID;
 	return 0;
 }
 
-unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
-			  struct iwl_frame *frame, u8 rate)
+unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
+			  struct iwl3945_frame *frame, u8 rate)
 {
-	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+	struct iwl3945_tx_beacon_cmd *tx_beacon_cmd;
 	unsigned int frame_size;
 
-	tx_beacon_cmd = (struct iwl_tx_beacon_cmd *)&frame->u;
+	tx_beacon_cmd = (struct iwl3945_tx_beacon_cmd *)&frame->u;
 	memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
 
 	tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID;
 	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
-	frame_size = iwl_fill_beacon_frame(priv,
+	frame_size = iwl3945_fill_beacon_frame(priv,
 				tx_beacon_cmd->frame,
-				BROADCAST_ADDR,
+				iwl3945_broadcast_addr,
 				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 
 	BUG_ON(frame_size > MAX_MPDU_SIZE);
@@ -2277,35 +2344,43 @@ unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
 	tx_beacon_cmd->tx.supp_rates[1] =
 		(IWL_CCK_BASIC_RATES_MASK & 0xF);
 
-	return (sizeof(struct iwl_tx_beacon_cmd) + frame_size);
+	return (sizeof(struct iwl3945_tx_beacon_cmd) + frame_size);
 }
 
-void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
+void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv)
 {
 	priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx;
 }
 
-void iwl_hw_setup_deferred_work(struct iwl_priv *priv)
+void iwl3945_hw_setup_deferred_work(struct iwl3945_priv *priv)
 {
 	INIT_DELAYED_WORK(&priv->thermal_periodic,
 			  iwl3945_bg_reg_txpower_periodic);
 }
 
-void iwl_hw_cancel_deferred_work(struct iwl_priv *priv)
+void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv)
 {
 	cancel_delayed_work(&priv->thermal_periodic);
 }
 
-struct pci_device_id iwl_hw_card_ids[] = {
-	{0x8086, 0x4222, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x4227, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+struct pci_device_id iwl3945_hw_card_ids[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4222)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4227)},
 	{0}
 };
 
-inline int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
+/*
+ * Clear the OWNER_MSK, to establish driver (instead of uCode running on
+ * embedded controller) as EEPROM reader; each read is a series of pulses
+ * to/from the EEPROM chip, not a single event, so even reads could conflict
+ * if they weren't arbitrated by some ownership mechanism.  Here, the driver
+ * simply claims ownership, which should be safe when this function is called
+ * (i.e. before loading uCode!).
+ */
+inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv)
 {
-	_iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
+	_iwl3945_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
 	return 0;
 }
 
-MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
+MODULE_DEVICE_TABLE(pci, iwl3945_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 813902e9f8c2..20b925f57e35 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -23,19 +23,955 @@
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
+/*
+ * Please use this file (iwl-3945.h) for driver implementation definitions.
+ * Please use iwl-3945-commands.h for uCode API definitions.
+ * Please use iwl-3945-hw.h for hardware-related definitions.
+ */
 
 #ifndef __iwl_3945_h__
 #define __iwl_3945_h__
 
+#include <linux/pci.h> /* for struct pci_device_id */
+#include <linux/kernel.h>
+#include <net/ieee80211_radiotap.h>
+
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+extern struct pci_device_id iwl3945_hw_card_ids[];
+
+#define DRV_NAME	"iwl3945"
+#include "iwl-3945-hw.h"
+#include "iwl-prph.h"
+#include "iwl-3945-debug.h"
+
+/* Default noise level to report when noise measurement is not available.
+ *   This may be because we're:
+ *   1)  Not associated (4965, no beacon statistics being sent to driver)
+ *   2)  Scanning (noise measurement does not apply to associated channel)
+ *   3)  Receiving CCK (3945 delivers noise info only for OFDM frames)
+ * Use default noise value of -127 ... this is below the range of measurable
+ *   Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
+ *   Also, -127 works better than 0 when averaging frames with/without
+ *   noise info (e.g. averaging might be done in app); measured dBm values are
+ *   always negative ... using a negative value as the default keeps all
+ *   averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
+
+/* Module parameters accessible from iwl-*.c */
+extern int iwl3945_param_hwcrypto;
+extern int iwl3945_param_queues_num;
+
+enum iwl3945_antenna {
+	IWL_ANTENNA_DIVERSITY,
+	IWL_ANTENNA_MAIN,
+	IWL_ANTENNA_AUX
+};
+
+/*
+ * RTS threshold here is total size [2347] minus 4 FCS bytes
+ * Per spec:
+ *   a value of 0 means RTS on all data/management packets
+ *   a value > max MSDU size means no RTS
+ * else RTS for data/management frames where MPDU is larger
+ *   than RTS value.
+ */
+#define IWL_RX_BUF_SIZE           3000U
+#define DEFAULT_RTS_THRESHOLD     2347U
+#define MIN_RTS_THRESHOLD         0U
+#define MAX_RTS_THRESHOLD         2347U
+#define MAX_MSDU_SIZE		  2304U
+#define MAX_MPDU_SIZE		  2346U
+#define DEFAULT_BEACON_INTERVAL   100U
+#define	DEFAULT_SHORT_RETRY_LIMIT 7U
+#define	DEFAULT_LONG_RETRY_LIMIT  4U
+
+struct iwl3945_rx_mem_buffer {
+	dma_addr_t dma_addr;
+	struct sk_buff *skb;
+	struct list_head list;
+};
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+struct iwl3945_queue {
+	int n_bd;              /* number of BDs in this queue */
+	int write_ptr;       /* 1-st empty entry (index) host_w*/
+	int read_ptr;         /* last used entry (index) host_r*/
+	dma_addr_t dma_addr;   /* physical addr for BD's */
+	int n_window;	       /* safe queue window */
+	u32 id;
+	int low_mark;	       /* low watermark, resume queue if free
+				* space more than this */
+	int high_mark;         /* high watermark, stop queue if free
+				* space less than this */
+} __attribute__ ((packed));
+
+#define MAX_NUM_OF_TBS          (20)
+
+/* One for each TFD */
+struct iwl3945_tx_info {
+	struct ieee80211_tx_status status;
+	struct sk_buff *skb[MAX_NUM_OF_TBS];
+};
+
+/**
+ * struct iwl3945_tx_queue - Tx Queue for DMA
+ * @q: generic Rx/Tx queue descriptor
+ * @bd: base of circular buffer of TFDs
+ * @cmd: array of command/Tx buffers
+ * @dma_addr_cmd: physical address of cmd/tx buffer array
+ * @txb: array of per-TFD driver data
+ * @need_update: indicates need to update read/write index
+ *
+ * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
+ * descriptors) and required locking structures.
+ */
+struct iwl3945_tx_queue {
+	struct iwl3945_queue q;
+	struct iwl3945_tfd_frame *bd;
+	struct iwl3945_cmd *cmd;
+	dma_addr_t dma_addr_cmd;
+	struct iwl3945_tx_info *txb;
+	int need_update;
+	int active;
+};
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+struct iwl3945_channel_tgd_info {
+	u8 type;
+	s8 max_power;
+};
+
+struct iwl3945_channel_tgh_info {
+	s64 last_radar_time;
+};
+
+/* current Tx power values to use, one for each rate for each channel.
+ * requested power is limited by:
+ * -- regulatory EEPROM limits for this channel
+ * -- hardware capabilities (clip-powers)
+ * -- spectrum management
+ * -- user preference (e.g. iwconfig)
+ * when requested power is set, base power index must also be set. */
+struct iwl3945_channel_power_info {
+	struct iwl3945_tx_power tpc;	/* actual radio and DSP gain settings */
+	s8 power_table_index;	/* actual (compenst'd) index into gain table */
+	s8 base_power_index;	/* gain index for power at factory temp. */
+	s8 requested_power;	/* power (dBm) requested for this chnl/rate */
+};
+
+/* current scan Tx power values to use, one for each scan rate for each
+ * channel. */
+struct iwl3945_scan_power_info {
+	struct iwl3945_tx_power tpc;	/* actual radio and DSP gain settings */
+	s8 power_table_index;	/* actual (compenst'd) index into gain table */
+	s8 requested_power;	/* scan pwr (dBm) requested for chnl/rate */
+};
+
+/*
+ * One for each channel, holds all channel setup data
+ * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
+ *     with one another!
+ */
+#define IWL4965_MAX_RATE (33)
+
+struct iwl3945_channel_info {
+	struct iwl3945_channel_tgd_info tgd;
+	struct iwl3945_channel_tgh_info tgh;
+	struct iwl3945_eeprom_channel eeprom;	/* EEPROM regulatory limit */
+	struct iwl3945_eeprom_channel fat_eeprom;	/* EEPROM regulatory limit for
+						 * FAT channel */
+
+	u8 channel;	  /* channel number */
+	u8 flags;	  /* flags copied from EEPROM */
+	s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+	s8 curr_txpow;	  /* (dBm) regulatory/spectrum/user (not h/w) */
+	s8 min_power;	  /* always 0 */
+	s8 scan_power;	  /* (dBm) regul. eeprom, direct scans, any rate */
+
+	u8 group_index;	  /* 0-4, maps channel to group1/2/3/4/5 */
+	u8 band_index;	  /* 0-4, maps channel to band1/2/3/4/5 */
+	u8 phymode;	  /* MODE_IEEE80211{A,B,G} */
+
+	/* Radio/DSP gain settings for each "normal" data Tx rate.
+	 * These include, in addition to RF and DSP gain, a few fields for
+	 *   remembering/modifying gain settings (indexes). */
+	struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE];
+
+	/* Radio/DSP gain settings for each scan rate, for directed scans. */
+	struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
+};
+
+struct iwl3945_clip_group {
+	/* maximum power level to prevent clipping for each rate, derived by
+	 *   us from this band's saturation power in EEPROM */
+	const s8 clip_powers[IWL_MAX_RATES];
+};
+
+#include "iwl-3945-rs.h"
+
+#define IWL_TX_FIFO_AC0	0
+#define IWL_TX_FIFO_AC1	1
+#define IWL_TX_FIFO_AC2	2
+#define IWL_TX_FIFO_AC3	3
+#define IWL_TX_FIFO_HCCA_1	5
+#define IWL_TX_FIFO_HCCA_2	6
+#define IWL_TX_FIFO_NONE	7
+
+/* Minimum number of queues. MAX_NUM is defined in hw specific files */
+#define IWL_MIN_NUM_QUEUES	4
+
+/* Power management (not Tx power) structures */
+
+struct iwl3945_power_vec_entry {
+	struct iwl3945_powertable_cmd cmd;
+	u8 no_dtim;
+};
+#define IWL_POWER_RANGE_0  (0)
+#define IWL_POWER_RANGE_1  (1)
+
+#define IWL_POWER_MODE_CAM	0x00	/* Continuously Aware Mode, always on */
+#define IWL_POWER_INDEX_3	0x03
+#define IWL_POWER_INDEX_5	0x05
+#define IWL_POWER_AC		0x06
+#define IWL_POWER_BATTERY	0x07
+#define IWL_POWER_LIMIT		0x07
+#define IWL_POWER_MASK		0x0F
+#define IWL_POWER_ENABLED	0x10
+#define IWL_POWER_LEVEL(x)	((x) & IWL_POWER_MASK)
+
+struct iwl3945_power_mgr {
+	spinlock_t lock;
+	struct iwl3945_power_vec_entry pwr_range_0[IWL_POWER_AC];
+	struct iwl3945_power_vec_entry pwr_range_1[IWL_POWER_AC];
+	u8 active_index;
+	u32 dtim_val;
+};
+
+#define IEEE80211_DATA_LEN              2304
+#define IEEE80211_4ADDR_LEN             30
+#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct iwl3945_frame {
+	union {
+		struct ieee80211_hdr frame;
+		struct iwl3945_tx_beacon_cmd beacon;
+		u8 raw[IEEE80211_FRAME_LEN];
+		u8 cmd[360];
+	} u;
+	struct list_head list;
+};
+
+#define SEQ_TO_QUEUE(x)  ((x >> 8) & 0xbf)
+#define QUEUE_TO_SEQ(x)  ((x & 0xbf) << 8)
+#define SEQ_TO_INDEX(x) (x & 0xff)
+#define INDEX_TO_SEQ(x) (x & 0xff)
+#define SEQ_HUGE_FRAME  (0x4000)
+#define SEQ_RX_FRAME    __constant_cpu_to_le16(0x8000)
+#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+
+enum {
+	/* CMD_SIZE_NORMAL = 0, */
+	CMD_SIZE_HUGE = (1 << 0),
+	/* CMD_SYNC = 0, */
+	CMD_ASYNC = (1 << 1),
+	/* CMD_NO_SKB = 0, */
+	CMD_WANT_SKB = (1 << 2),
+};
+
+struct iwl3945_cmd;
+struct iwl3945_priv;
+
+struct iwl3945_cmd_meta {
+	struct iwl3945_cmd_meta *source;
+	union {
+		struct sk_buff *skb;
+		int (*callback)(struct iwl3945_priv *priv,
+				struct iwl3945_cmd *cmd, struct sk_buff *skb);
+	} __attribute__ ((packed)) u;
+
+	/* The CMD_SIZE_HUGE flag bit indicates that the command
+	 * structure is stored at the end of the shared queue memory. */
+	u32 flags;
+
+} __attribute__ ((packed));
+
+/**
+ * struct iwl3945_cmd
+ *
+ * For allocation of the command and tx queues, this establishes the overall
+ * size of the largest command we send to uCode, except for a scan command
+ * (which is relatively huge; space is allocated separately).
+ */
+struct iwl3945_cmd {
+	struct iwl3945_cmd_meta meta;
+	struct iwl3945_cmd_header hdr;
+	union {
+		struct iwl3945_addsta_cmd addsta;
+		struct iwl3945_led_cmd led;
+		u32 flags;
+		u8 val8;
+		u16 val16;
+		u32 val32;
+		struct iwl3945_bt_cmd bt;
+		struct iwl3945_rxon_time_cmd rxon_time;
+		struct iwl3945_powertable_cmd powertable;
+		struct iwl3945_qosparam_cmd qosparam;
+		struct iwl3945_tx_cmd tx;
+		struct iwl3945_tx_beacon_cmd tx_beacon;
+		struct iwl3945_rxon_assoc_cmd rxon_assoc;
+		u8 *indirect;
+		u8 payload[360];
+	} __attribute__ ((packed)) cmd;
+} __attribute__ ((packed));
+
+struct iwl3945_host_cmd {
+	u8 id;
+	u16 len;
+	struct iwl3945_cmd_meta meta;
+	const void *data;
+};
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl3945_cmd) - \
+			      sizeof(struct iwl3945_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/**
+ * struct iwl3945_rx_queue - Rx queue
+ * @processed: Internal index to last handled Rx packet
+ * @read: Shared index to newest available Rx buffer
+ * @write: Shared index to oldest written Rx packet
+ * @free_count: Number of pre-allocated buffers in rx_free
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
+ * @need_update: flag to indicate we need to update read/write index
+ *
+ * NOTE:  rx_free and rx_used are used as a FIFO for iwl3945_rx_mem_buffers
+ */
+struct iwl3945_rx_queue {
+	__le32 *bd;
+	dma_addr_t dma_addr;
+	struct iwl3945_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+	struct iwl3945_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+	u32 processed;
+	u32 read;
+	u32 write;
+	u32 free_count;
+	struct list_head rx_free;
+	struct list_head rx_used;
+	int need_update;
+	spinlock_t lock;
+};
+
+#define IWL_SUPPORTED_RATES_IE_LEN         8
+
+#define SCAN_INTERVAL 100
+
+#define MAX_A_CHANNELS  252
+#define MIN_A_CHANNELS  7
+
+#define MAX_B_CHANNELS  14
+#define MIN_B_CHANNELS  1
+
+#define STATUS_HCMD_ACTIVE	0	/* host command in progress */
+#define STATUS_INT_ENABLED	1
+#define STATUS_RF_KILL_HW	2
+#define STATUS_RF_KILL_SW	3
+#define STATUS_INIT		4
+#define STATUS_ALIVE		5
+#define STATUS_READY		6
+#define STATUS_TEMPERATURE	7
+#define STATUS_GEO_CONFIGURED	8
+#define STATUS_EXIT_PENDING	9
+#define STATUS_IN_SUSPEND	10
+#define STATUS_STATISTICS	11
+#define STATUS_SCANNING		12
+#define STATUS_SCAN_ABORTING	13
+#define STATUS_SCAN_HW		14
+#define STATUS_POWER_PMI	15
+#define STATUS_FW_ERROR		16
+#define STATUS_CONF_PENDING	17
+
+#define MAX_TID_COUNT        9
+
+#define IWL_INVALID_RATE     0xFF
+#define IWL_INVALID_VALUE    -1
+
+struct iwl3945_tid_data {
+	u16 seq_number;
+};
+
+struct iwl3945_hw_key {
+	enum ieee80211_key_alg alg;
+	int keylen;
+	u8 key[32];
+};
+
+union iwl3945_ht_rate_supp {
+	u16 rates;
+	struct {
+		u8 siso_rate;
+		u8 mimo_rate;
+	};
+};
+
+#ifdef CONFIG_IWL3945_QOS
+
+union iwl3945_qos_capabity {
+	struct {
+		u8 edca_count:4;	/* bit 0-3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 queue_request:1;	/* bit 5 */
+		u8 txop_request:1;	/* bit 6 */
+		u8 reserved:1;		/* bit 7 */
+	} q_AP;
+	struct {
+		u8 acvo_APSD:1;		/* bit 0 */
+		u8 acvi_APSD:1;		/* bit 1 */
+		u8 ac_bk_APSD:1;	/* bit 2 */
+		u8 ac_be_APSD:1;	/* bit 3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 max_len:2;		/* bit 5-6 */
+		u8 more_data_ack:1;	/* bit 7 */
+	} q_STA;
+	u8 val;
+};
+
+/* QoS structures */
+struct iwl3945_qos_info {
+	int qos_enable;
+	int qos_active;
+	union iwl3945_qos_capabity qos_cap;
+	struct iwl3945_qosparam_cmd def_qos_parm;
+};
+#endif /*CONFIG_IWL3945_QOS */
+
+#define STA_PS_STATUS_WAKE             0
+#define STA_PS_STATUS_SLEEP            1
+
+struct iwl3945_station_entry {
+	struct iwl3945_addsta_cmd sta;
+	struct iwl3945_tid_data tid[MAX_TID_COUNT];
+	union {
+		struct {
+			u8 rate;
+			u8 flags;
+		} s;
+		u16 rate_n_flags;
+	} current_rate;
+	u8 used;
+	u8 ps_status;
+	struct iwl3945_hw_key keyinfo;
+};
+
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_desc {
+	void *v_addr;		/* access by driver */
+	dma_addr_t p_addr;	/* access by card's busmaster DMA */
+	u32 len;		/* bytes */
+};
+
+/* uCode file layout */
+struct iwl3945_ucode {
+	__le32 ver;		/* major/minor/subminor */
+	__le32 inst_size;	/* bytes of runtime instructions */
+	__le32 data_size;	/* bytes of runtime data */
+	__le32 init_size;	/* bytes of initialization instructions */
+	__le32 init_data_size;	/* bytes of initialization data */
+	__le32 boot_size;	/* bytes of bootstrap instructions */
+	u8 data[0];		/* data in same order as "size" elements */
+};
+
+#define IWL_IBSS_MAC_HASH_SIZE 32
+
+struct iwl3945_ibss_seq {
+	u8 mac[ETH_ALEN];
+	u16 seq_num;
+	u16 frag_num;
+	unsigned long packet_time;
+	struct list_head list;
+};
+
+/**
+ * struct iwl3945_driver_hw_info
+ * @max_txq_num: Max # Tx queues supported
+ * @ac_queue_count: # Tx queues for EDCA Access Categories (AC)
+ * @tx_cmd_len: Size of Tx command (but not including frame itself)
+ * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
+ * @rx_buf_size:
+ * @max_pkt_size:
+ * @max_rxq_log: Log-base-2 of max_rxq_size
+ * @max_stations:
+ * @bcast_sta_id:
+ * @shared_virt: Pointer to driver/uCode shared Tx Byte Counts and Rx status
+ * @shared_phys: Physical Pointer to Tx Byte Counts and Rx status
+ */
+struct iwl3945_driver_hw_info {
+	u16 max_txq_num;
+	u16 ac_queue_count;
+	u16 tx_cmd_len;
+	u16 max_rxq_size;
+	u32 rx_buf_size;
+	u32 max_pkt_size;
+	u16 max_rxq_log;
+	u8  max_stations;
+	u8  bcast_sta_id;
+	void *shared_virt;
+	dma_addr_t shared_phys;
+};
+
+#define IWL_RX_HDR(x) ((struct iwl3945_rx_frame_hdr *)(\
+		       x->u.rx_frame.stats.payload + \
+		       x->u.rx_frame.stats.phy_count))
+#define IWL_RX_END(x) ((struct iwl3945_rx_frame_end *)(\
+		       IWL_RX_HDR(x)->payload + \
+		       le16_to_cpu(IWL_RX_HDR(x)->len)))
+#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
+#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
+
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-base.c which are forward declared here
+ * for use by iwl-*.c
+ *
+ *****************************************************************************/
+struct iwl3945_addsta_cmd;
+extern int iwl3945_send_add_station(struct iwl3945_priv *priv,
+				struct iwl3945_addsta_cmd *sta, u8 flags);
+extern u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *bssid,
+			  int is_ap, u8 flags);
+extern int iwl3945_is_network_packet(struct iwl3945_priv *priv,
+				 struct ieee80211_hdr *header);
+extern int iwl3945_power_init_handle(struct iwl3945_priv *priv);
+extern int iwl3945_eeprom_init(struct iwl3945_priv *priv);
+#ifdef CONFIG_IWL3945_DEBUG
+extern void iwl3945_report_frame(struct iwl3945_priv *priv,
+			     struct iwl3945_rx_packet *pkt,
+			     struct ieee80211_hdr *header, int group100);
+#else
+static inline void iwl3945_report_frame(struct iwl3945_priv *priv,
+				    struct iwl3945_rx_packet *pkt,
+				    struct ieee80211_hdr *header,
+				    int group100) {}
+#endif
+extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv,
+					   struct iwl3945_rx_mem_buffer *rxb,
+					   void *data, short len,
+					   struct ieee80211_rx_status *stats,
+					   u16 phy_flags);
+extern int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv,
+				       struct ieee80211_hdr *header);
+extern int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv);
+extern void iwl3945_rx_queue_reset(struct iwl3945_priv *priv,
+			       struct iwl3945_rx_queue *rxq);
+extern int iwl3945_calc_db_from_ratio(int sig_ratio);
+extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm);
+extern int iwl3945_tx_queue_init(struct iwl3945_priv *priv,
+			     struct iwl3945_tx_queue *txq, int count, u32 id);
+extern void iwl3945_rx_replenish(void *data);
+extern void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq);
+extern int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len,
+			    const void *data);
+extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv,
+		struct iwl3945_host_cmd *cmd);
+extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
+					struct ieee80211_hdr *hdr,
+					const u8 *dest, int left);
+extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv,
+					 struct iwl3945_rx_queue *q);
+extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv);
+extern void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb,
+				   u32 decrypt_res,
+				   struct ieee80211_rx_status *stats);
+extern const u8 iwl3945_broadcast_addr[ETH_ALEN];
+
+/*
+ * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
+ * call this... todo... fix that.
+*/
+extern u8 iwl3945_sync_station(struct iwl3945_priv *priv, int sta_id,
+			   u16 tx_rate, u8 flags);
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-[34]*.c which are forward declared here
+ * for use by iwl-base.c
+ *
+ * NOTE:  The implementation of these functions are hardware specific
+ * which is why they are in the hardware specific files (vs. iwl-base.c)
+ *
+ * Naming convention --
+ * iwl3945_         <-- Its part of iwlwifi (should be changed to iwl3945_)
+ * iwl3945_hw_      <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
+ * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
+ * iwl3945_bg_      <-- Called from work queue context
+ * iwl3945_mac_     <-- mac80211 callback
+ *
+ ****************************************************************************/
+extern void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv);
+extern void iwl3945_hw_setup_deferred_work(struct iwl3945_priv *priv);
+extern void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv);
+extern int iwl3945_hw_rxq_stop(struct iwl3945_priv *priv);
+extern int iwl3945_hw_set_hw_setting(struct iwl3945_priv *priv);
+extern int iwl3945_hw_nic_init(struct iwl3945_priv *priv);
+extern int iwl3945_hw_nic_stop_master(struct iwl3945_priv *priv);
+extern void iwl3945_hw_txq_ctx_free(struct iwl3945_priv *priv);
+extern void iwl3945_hw_txq_ctx_stop(struct iwl3945_priv *priv);
+extern int iwl3945_hw_nic_reset(struct iwl3945_priv *priv);
+extern int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *tfd,
+					dma_addr_t addr, u16 len);
+extern int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq);
+extern int iwl3945_hw_get_temperature(struct iwl3945_priv *priv);
+extern int iwl3945_hw_tx_queue_init(struct iwl3945_priv *priv,
+				struct iwl3945_tx_queue *txq);
+extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
+				 struct iwl3945_frame *frame, u8 rate);
+extern int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv);
+extern void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv,
+				     struct iwl3945_cmd *cmd,
+				     struct ieee80211_tx_control *ctrl,
+				     struct ieee80211_hdr *hdr,
+				     int sta_id, int tx_id);
+extern int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv);
+extern int iwl3945_hw_reg_set_txpower(struct iwl3945_priv *priv, s8 power);
+extern void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv,
+				 struct iwl3945_rx_mem_buffer *rxb);
+extern void iwl3945_disable_events(struct iwl3945_priv *priv);
+extern int iwl4965_get_temperature(const struct iwl3945_priv *priv);
+
+/**
+ * iwl3945_hw_find_station - Find station id for a given BSSID
+ * @bssid: MAC address of station ID to find
+ *
+ * NOTE:  This should not be hardware specific but the code has
+ * not yet been merged into a single common layer for managing the
+ * station tables.
+ */
+extern u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *bssid);
+
+extern int iwl3945_hw_channel_switch(struct iwl3945_priv *priv, u16 channel);
+
 /*
  * Forward declare iwl-3945.c functions for iwl-base.c
  */
-extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv);
-extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv);
-extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv);
-extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv);
-extern void iwl3945_bg_reg_txpower_periodic(struct work_struct *work);
-extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv);
-extern u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
+extern int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv);
+extern __le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv);
+extern int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv);
+extern void iwl3945_reg_txpower_periodic(struct iwl3945_priv *priv);
+extern int iwl3945_txpower_set_from_eeprom(struct iwl3945_priv *priv);
+extern u8 iwl3945_sync_sta(struct iwl3945_priv *priv, int sta_id,
 		 u16 tx_rate, u8 flags);
+
+
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
+
+enum {
+	MEASUREMENT_READY = (1 << 0),
+	MEASUREMENT_ACTIVE = (1 << 1),
+};
+
+#endif
+
+struct iwl3945_priv {
+
+	/* ieee device used by generic ieee processing code */
+	struct ieee80211_hw *hw;
+	struct ieee80211_channel *ieee_channels;
+	struct ieee80211_rate *ieee_rates;
+
+	/* temporary frame storage list */
+	struct list_head free_frames;
+	int frames_count;
+
+	u8 phymode;
+	int alloc_rxb_skb;
+	bool add_radiotap;
+
+	void (*rx_handlers[REPLY_MAX])(struct iwl3945_priv *priv,
+				       struct iwl3945_rx_mem_buffer *rxb);
+
+	const struct ieee80211_hw_mode *modes;
+
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
+	/* spectrum measurement report caching */
+	struct iwl3945_spectrum_notification measure_report;
+	u8 measurement_status;
+#endif
+	/* ucode beacon time */
+	u32 ucode_beacon_time;
+
+	/* we allocate array of iwl3945_channel_info for NIC's valid channels.
+	 *    Access via channel # using indirect index array */
+	struct iwl3945_channel_info *channel_info;	/* channel info array */
+	u8 channel_count;	/* # of channels */
+
+	/* each calibration channel group in the EEPROM has a derived
+	 * clip setting for each rate. */
+	const struct iwl3945_clip_group clip_groups[5];
+
+	/* thermal calibration */
+	s32 temperature;	/* degrees Kelvin */
+	s32 last_temperature;
+
+	/* Scan related variables */
+	unsigned long last_scan_jiffies;
+	unsigned long next_scan_jiffies;
+	unsigned long scan_start;
+	unsigned long scan_pass_start;
+	unsigned long scan_start_tsf;
+	int scan_bands;
+	int one_direct_scan;
+	u8 direct_ssid_len;
+	u8 direct_ssid[IW_ESSID_MAX_SIZE];
+	struct iwl3945_scan_cmd *scan;
+	u8 only_active_channel;
+
+	/* spinlock */
+	spinlock_t lock;	/* protect general shared data */
+	spinlock_t hcmd_lock;	/* protect hcmd */
+	struct mutex mutex;
+
+	/* basic pci-network driver stuff */
+	struct pci_dev *pci_dev;
+
+	/* pci hardware address support */
+	void __iomem *hw_base;
+
+	/* uCode images, save to reload in case of failure */
+	struct fw_desc ucode_code;	/* runtime inst */
+	struct fw_desc ucode_data;	/* runtime data original */
+	struct fw_desc ucode_data_backup;	/* runtime data save/restore */
+	struct fw_desc ucode_init;	/* initialization inst */
+	struct fw_desc ucode_init_data;	/* initialization data */
+	struct fw_desc ucode_boot;	/* bootstrap inst */
+
+
+	struct iwl3945_rxon_time_cmd rxon_timing;
+
+	/* We declare this const so it can only be
+	 * changed via explicit cast within the
+	 * routines that actually update the physical
+	 * hardware */
+	const struct iwl3945_rxon_cmd active_rxon;
+	struct iwl3945_rxon_cmd staging_rxon;
+
+	int error_recovering;
+	struct iwl3945_rxon_cmd recovery_rxon;
+
+	/* 1st responses from initialize and runtime uCode images.
+	 * 4965's initialize alive response contains some calibration data. */
+	struct iwl3945_init_alive_resp card_alive_init;
+	struct iwl3945_alive_resp card_alive;
+
+#ifdef LED
+	/* LED related variables */
+	struct iwl3945_activity_blink activity;
+	unsigned long led_packets;
+	int led_state;
+#endif
+
+	u16 active_rate;
+	u16 active_rate_basic;
+
+	u8 call_post_assoc_from_beacon;
+	u8 assoc_station_added;
+	/* Rate scaling data */
+	s8 data_retry_limit;
+	u8 retry_rate;
+
+	wait_queue_head_t wait_command_queue;
+
+	int activity_timer_active;
+
+	/* Rx and Tx DMA processing queues */
+	struct iwl3945_rx_queue rxq;
+	struct iwl3945_tx_queue txq[IWL_MAX_NUM_QUEUES];
+
+	unsigned long status;
+	u32 config;
+
+	int last_rx_rssi;	/* From Rx packet statisitics */
+	int last_rx_noise;	/* From beacon statistics */
+
+	struct iwl3945_power_mgr power_data;
+
+	struct iwl3945_notif_statistics statistics;
+	unsigned long last_statistics_time;
+
+	/* context information */
+	u8 essid[IW_ESSID_MAX_SIZE];
+	u8 essid_len;
+	u16 rates_mask;
+
+	u32 power_mode;
+	u32 antenna;
+	u8 bssid[ETH_ALEN];
+	u16 rts_threshold;
+	u8 mac_addr[ETH_ALEN];
+
+	/*station table variables */
+	spinlock_t sta_lock;
+	int num_stations;
+	struct iwl3945_station_entry stations[IWL_STATION_COUNT];
+
+	/* Indication if ieee80211_ops->open has been called */
+	int is_open;
+
+	u8 mac80211_registered;
+	int is_abg;
+
+	u32 notif_missed_beacons;
+
+	/* Rx'd packet timing information */
+	u32 last_beacon_time;
+	u64 last_tsf;
+
+	/* Duplicate packet detection */
+	u16 last_seq_num;
+	u16 last_frag_num;
+	unsigned long last_packet_time;
+
+	/* Hash table for finding stations in IBSS network */
+	struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
+
+	/* eeprom */
+	struct iwl3945_eeprom eeprom;
+
+	int iw_mode;
+
+	struct sk_buff *ibss_beacon;
+
+	/* Last Rx'd beacon timestamp */
+	u32 timestamp0;
+	u32 timestamp1;
+	u16 beacon_int;
+	struct iwl3945_driver_hw_info hw_setting;
+	struct ieee80211_vif *vif;
+
+	/* Current association information needed to configure the
+	 * hardware */
+	u16 assoc_id;
+	u16 assoc_capability;
+	u8 ps_mode;
+
+#ifdef CONFIG_IWL3945_QOS
+	struct iwl3945_qos_info qos_data;
+#endif /*CONFIG_IWL3945_QOS */
+
+	struct workqueue_struct *workqueue;
+
+	struct work_struct up;
+	struct work_struct restart;
+	struct work_struct calibrated_work;
+	struct work_struct scan_completed;
+	struct work_struct rx_replenish;
+	struct work_struct rf_kill;
+	struct work_struct abort_scan;
+	struct work_struct update_link_led;
+	struct work_struct auth_work;
+	struct work_struct report_work;
+	struct work_struct request_scan;
+	struct work_struct beacon_update;
+
+	struct tasklet_struct irq_tasklet;
+
+	struct delayed_work init_alive_start;
+	struct delayed_work alive_start;
+	struct delayed_work activity_timer;
+	struct delayed_work thermal_periodic;
+	struct delayed_work gather_stats;
+	struct delayed_work scan_check;
+	struct delayed_work post_associate;
+
+#define IWL_DEFAULT_TX_POWER 0x0F
+	s8 user_txpower_limit;
+	s8 max_channel_txpower_limit;
+
+#ifdef CONFIG_PM
+	u32 pm_state[16];
+#endif
+
+#ifdef CONFIG_IWL3945_DEBUG
+	/* debugging info */
+	u32 framecnt_to_us;
+	atomic_t restrict_refcnt;
+#endif
+};				/*iwl3945_priv */
+
+static inline int iwl3945_is_associated(struct iwl3945_priv *priv)
+{
+	return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+static inline int is_channel_valid(const struct iwl3945_channel_info *ch_info)
+{
+	if (ch_info == NULL)
+		return 0;
+	return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
+}
+
+static inline int is_channel_narrow(const struct iwl3945_channel_info *ch_info)
+{
+	return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
+}
+
+static inline int is_channel_radar(const struct iwl3945_channel_info *ch_info)
+{
+	return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
+}
+
+static inline u8 is_channel_a_band(const struct iwl3945_channel_info *ch_info)
+{
+	return ch_info->phymode == MODE_IEEE80211A;
+}
+
+static inline u8 is_channel_bg_band(const struct iwl3945_channel_info *ch_info)
+{
+	return ((ch_info->phymode == MODE_IEEE80211B) ||
+		(ch_info->phymode == MODE_IEEE80211G));
+}
+
+static inline int is_channel_passive(const struct iwl3945_channel_info *ch)
+{
+	return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
+}
+
+static inline int is_channel_ibss(const struct iwl3945_channel_info *ch)
+{
+	return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
+}
+
+static inline int iwl3945_rate_index_from_plcp(int plcp)
+{
+	int i;
+
+	for (i = 0; i < IWL_RATE_COUNT; i++)
+		if (iwl3945_rates[i].plcp == plcp)
+			return i;
+	return -1;
+}
+
+extern const struct iwl3945_channel_info *iwl3945_get_channel_info(
+	const struct iwl3945_priv *priv, int phymode, u16 channel);
+
+/* Requires full declaration of iwl3945_priv before including */
+#include "iwl-3945-io.h"
+
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
new file mode 100644
index 000000000000..f3470c896d9a
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
@@ -0,0 +1,2651 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+/*
+ * Please use this file (iwl-4965-commands.h) only for uCode API definitions.
+ * Please use iwl-4965-hw.h for hardware-related definitions.
+ * Please use iwl-4965.h for driver implementation definitions.
+ */
+
+#ifndef __iwl4965_commands_h__
+#define __iwl4965_commands_h__
+
+enum {
+	REPLY_ALIVE = 0x1,
+	REPLY_ERROR = 0x2,
+
+	/* RXON and QOS commands */
+	REPLY_RXON = 0x10,
+	REPLY_RXON_ASSOC = 0x11,
+	REPLY_QOS_PARAM = 0x13,
+	REPLY_RXON_TIMING = 0x14,
+
+	/* Multi-Station support */
+	REPLY_ADD_STA = 0x18,
+	REPLY_REMOVE_STA = 0x19,	/* not used */
+	REPLY_REMOVE_ALL_STA = 0x1a,	/* not used */
+
+	/* RX, TX, LEDs */
+	REPLY_TX = 0x1c,
+	REPLY_RATE_SCALE = 0x47,	/* 3945 only */
+	REPLY_LEDS_CMD = 0x48,
+	REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
+
+	/* 802.11h related */
+	RADAR_NOTIFICATION = 0x70,	/* not used */
+	REPLY_QUIET_CMD = 0x71,		/* not used */
+	REPLY_CHANNEL_SWITCH = 0x72,
+	CHANNEL_SWITCH_NOTIFICATION = 0x73,
+	REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
+	SPECTRUM_MEASURE_NOTIFICATION = 0x75,
+
+	/* Power Management */
+	POWER_TABLE_CMD = 0x77,
+	PM_SLEEP_NOTIFICATION = 0x7A,
+	PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
+
+	/* Scan commands and notifications */
+	REPLY_SCAN_CMD = 0x80,
+	REPLY_SCAN_ABORT_CMD = 0x81,
+	SCAN_START_NOTIFICATION = 0x82,
+	SCAN_RESULTS_NOTIFICATION = 0x83,
+	SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+	/* IBSS/AP commands */
+	BEACON_NOTIFICATION = 0x90,
+	REPLY_TX_BEACON = 0x91,
+	WHO_IS_AWAKE_NOTIFICATION = 0x94,	/* not used */
+
+	/* Miscellaneous commands */
+	QUIET_NOTIFICATION = 0x96,		/* not used */
+	REPLY_TX_PWR_TABLE_CMD = 0x97,
+	MEASURE_ABORT_NOTIFICATION = 0x99,	/* not used */
+
+	/* Bluetooth device coexistance config command */
+	REPLY_BT_CONFIG = 0x9b,
+
+	/* Statistics */
+	REPLY_STATISTICS_CMD = 0x9c,
+	STATISTICS_NOTIFICATION = 0x9d,
+
+	/* RF-KILL commands and notifications */
+	REPLY_CARD_STATE_CMD = 0xa0,
+	CARD_STATE_NOTIFICATION = 0xa1,
+
+	/* Missed beacons notification */
+	MISSED_BEACONS_NOTIFICATION = 0xa2,
+
+	REPLY_CT_KILL_CONFIG_CMD = 0xa4,
+	SENSITIVITY_CMD = 0xa8,
+	REPLY_PHY_CALIBRATION_CMD = 0xb0,
+	REPLY_RX_PHY_CMD = 0xc0,
+	REPLY_RX_MPDU_CMD = 0xc1,
+	REPLY_4965_RX = 0xc3,
+	REPLY_COMPRESSED_BA = 0xc5,
+	REPLY_MAX = 0xff
+};
+
+/******************************************************************************
+ * (0)
+ * Commonly used structures and definitions:
+ * Command header, rate_n_flags, txpower
+ *
+ *****************************************************************************/
+
+/* iwl4965_cmd_header flags value */
+#define IWL_CMD_FAILED_MSK 0x40
+
+/**
+ * struct iwl4965_cmd_header
+ *
+ * This header format appears in the beginning of each command sent from the
+ * driver, and each response/notification received from uCode.
+ */
+struct iwl4965_cmd_header {
+	u8 cmd;		/* Command ID:  REPLY_RXON, etc. */
+	u8 flags;	/* IWL_CMD_* */
+	/*
+	 * The driver sets up the sequence number to values of its chosing.
+	 * uCode does not use this value, but passes it back to the driver
+	 * when sending the response to each driver-originated command, so
+	 * the driver can match the response to the command.  Since the values
+	 * don't get used by uCode, the driver may set up an arbitrary format.
+	 *
+	 * There is one exception:  uCode sets bit 15 when it originates
+	 * the response/notification, i.e. when the response/notification
+	 * is not a direct response to a command sent by the driver.  For
+	 * example, uCode issues REPLY_3945_RX when it sends a received frame
+	 * to the driver; it is not a direct response to any driver command.
+	 *
+	 * The Linux driver uses the following format:
+	 *
+	 *  0:7    index/position within Tx queue
+	 *  8:13   Tx queue selection
+	 * 14:14   driver sets this to indicate command is in the 'huge'
+	 *         storage at the end of the command buffers, i.e. scan cmd
+	 * 15:15   uCode sets this in uCode-originated response/notification
+	 */
+	__le16 sequence;
+
+	/* command or response/notification data follows immediately */
+	u8 data[0];
+} __attribute__ ((packed));
+
+/**
+ * 4965 rate_n_flags bit fields
+ *
+ * rate_n_flags format is used in following 4965 commands:
+ *  REPLY_4965_RX (response only)
+ *  REPLY_TX (both command and response)
+ *  REPLY_TX_LINK_QUALITY_CMD
+ *
+ * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"):
+ *  2-0:  0)   6 Mbps
+ *        1)  12 Mbps
+ *        2)  18 Mbps
+ *        3)  24 Mbps
+ *        4)  36 Mbps
+ *        5)  48 Mbps
+ *        6)  54 Mbps
+ *        7)  60 Mbps
+ *
+ *    3:  0)  Single stream (SISO)
+ *        1)  Dual stream (MIMO)
+ *
+ *    5:  Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data
+ *
+ * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"):
+ *  3-0:  0xD)   6 Mbps
+ *        0xF)   9 Mbps
+ *        0x5)  12 Mbps
+ *        0x7)  18 Mbps
+ *        0x9)  24 Mbps
+ *        0xB)  36 Mbps
+ *        0x1)  48 Mbps
+ *        0x3)  54 Mbps
+ *
+ * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"):
+ *  3-0:   10)  1 Mbps
+ *         20)  2 Mbps
+ *         55)  5.5 Mbps
+ *        110)  11 Mbps
+ */
+#define RATE_MCS_CODE_MSK 0x7
+#define RATE_MCS_MIMO_POS 3
+#define RATE_MCS_MIMO_MSK 0x8
+#define RATE_MCS_HT_DUP_POS 5
+#define RATE_MCS_HT_DUP_MSK 0x20
+
+/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */
+#define RATE_MCS_FLAGS_POS 8
+#define RATE_MCS_HT_POS 8
+#define RATE_MCS_HT_MSK 0x100
+
+/* Bit 9: (1) CCK, (0) OFDM.  HT (bit 8) must be "0" for this bit to be valid */
+#define RATE_MCS_CCK_POS 9
+#define RATE_MCS_CCK_MSK 0x200
+
+/* Bit 10: (1) Use Green Field preamble */
+#define RATE_MCS_GF_POS 10
+#define RATE_MCS_GF_MSK 0x400
+
+/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */
+#define RATE_MCS_FAT_POS 11
+#define RATE_MCS_FAT_MSK 0x800
+
+/* Bit 12: (1) Duplicate data on both 20MHz chnls.  FAT (bit 11) must be set. */
+#define RATE_MCS_DUP_POS 12
+#define RATE_MCS_DUP_MSK 0x1000
+
+/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */
+#define RATE_MCS_SGI_POS 13
+#define RATE_MCS_SGI_MSK 0x2000
+
+/**
+ * rate_n_flags Tx antenna masks (4965 has 2 transmitters):
+ * bit14:15 01 B inactive, A active
+ *          10 B active, A inactive
+ *          11 Both active
+ */
+#define RATE_MCS_ANT_A_POS	14
+#define RATE_MCS_ANT_B_POS	15
+#define RATE_MCS_ANT_A_MSK	0x4000
+#define RATE_MCS_ANT_B_MSK	0x8000
+#define RATE_MCS_ANT_AB_MSK	0xc000
+
+
+/**
+ * struct iwl4965_tx_power - txpower format used in REPLY_SCAN_CMD
+ *
+ * Scan uses only one transmitter, so only one analog/dsp gain pair is needed.
+ */
+struct iwl4965_tx_power {
+	u8 tx_gain;		/* gain for analog radio */
+	u8 dsp_atten;		/* gain for DSP */
+} __attribute__ ((packed));
+
+#define POWER_TABLE_NUM_ENTRIES			33
+#define POWER_TABLE_NUM_HT_OFDM_ENTRIES		32
+#define POWER_TABLE_CCK_ENTRY			32
+
+/**
+ * union iwl4965_tx_power_dual_stream
+ *
+ * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ * Use __le32 version (struct tx_power_dual_stream) when building command.
+ *
+ * Driver provides radio gain and DSP attenuation settings to device in pairs,
+ * one value for each transmitter chain.  The first value is for transmitter A,
+ * second for transmitter B.
+ *
+ * For SISO bit rates, both values in a pair should be identical.
+ * For MIMO rates, one value may be different from the other,
+ * in order to balance the Tx output between the two transmitters.
+ *
+ * See more details in doc for TXPOWER in iwl-4965-hw.h.
+ */
+union iwl4965_tx_power_dual_stream {
+	struct {
+		u8 radio_tx_gain[2];
+		u8 dsp_predis_atten[2];
+	} s;
+	u32 dw;
+};
+
+/**
+ * struct tx_power_dual_stream
+ *
+ * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ *
+ * Same format as iwl_tx_power_dual_stream, but __le32
+ */
+struct tx_power_dual_stream {
+	__le32 dw;
+} __attribute__ ((packed));
+
+/**
+ * struct iwl4965_tx_power_db
+ *
+ * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
+ */
+struct iwl4965_tx_power_db {
+	struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (0a)
+ * Alive and Error Commands & Responses:
+ *
+ *****************************************************************************/
+
+#define UCODE_VALID_OK	__constant_cpu_to_le32(0x1)
+#define INITIALIZE_SUBTYPE    (9)
+
+/*
+ * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "initialize alive" notification once the initialization
+ * uCode image has completed its work, and is ready to load the runtime image.
+ * This is the *first* "alive" notification that the driver will receive after
+ * rebooting uCode; the "initialize" alive is indicated by subtype field == 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ *
+ * For 4965, this notification contains important calibration data for
+ * calculating txpower settings:
+ *
+ * 1)  Power supply voltage indication.  The voltage sensor outputs higher
+ *     values for lower voltage, and vice versa.
+ *
+ * 2)  Temperature measurement parameters, for each of two channel widths
+ *     (20 MHz and 40 MHz) supported by the radios.  Temperature sensing
+ *     is done via one of the receiver chains, and channel width influences
+ *     the results.
+ *
+ * 3)  Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation,
+ *     for each of 5 frequency ranges.
+ */
+struct iwl4965_init_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;		/* "9" for initialize alive */
+	__le16 reserved2;
+	__le32 log_event_table_ptr;
+	__le32 error_event_table_ptr;
+	__le32 timestamp;
+	__le32 is_valid;
+
+	/* calibration values from "initialize" uCode */
+	__le32 voltage;		/* signed, higher value is lower voltage */
+	__le32 therm_r1[2];	/* signed, 1st for normal, 2nd for FAT channel*/
+	__le32 therm_r2[2];	/* signed */
+	__le32 therm_r3[2];	/* signed */
+	__le32 therm_r4[2];	/* signed */
+	__le32 tx_atten[5][2];	/* signed MIMO gain comp, 5 freq groups,
+				 * 2 Tx chains */
+} __attribute__ ((packed));
+
+
+/**
+ * REPLY_ALIVE = 0x1 (response only, not a command)
+ *
+ * uCode issues this "alive" notification once the runtime image is ready
+ * to receive commands from the driver.  This is the *second* "alive"
+ * notification that the driver will receive after rebooting uCode;
+ * this "alive" is indicated by subtype field != 9.
+ *
+ * See comments documenting "BSM" (bootstrap state machine).
+ *
+ * This response includes two pointers to structures within the device's
+ * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging:
+ *
+ * 1)  log_event_table_ptr indicates base of the event log.  This traces
+ *     a 256-entry history of uCode execution within a circular buffer.
+ *     Its header format is:
+ *
+ *	__le32 log_size;     log capacity (in number of entries)
+ *	__le32 type;         (1) timestamp with each entry, (0) no timestamp
+ *	__le32 wraps;        # times uCode has wrapped to top of circular buffer
+ *      __le32 write_index;  next circular buffer entry that uCode would fill
+ *
+ *     The header is followed by the circular buffer of log entries.  Entries
+ *     with timestamps have the following format:
+ *
+ *	__le32 event_id;     range 0 - 1500
+ *	__le32 timestamp;    low 32 bits of TSF (of network, if associated)
+ *	__le32 data;         event_id-specific data value
+ *
+ *     Entries without timestamps contain only event_id and data.
+ *
+ * 2)  error_event_table_ptr indicates base of the error log.  This contains
+ *     information about any uCode error that occurs.  For 4965, the format
+ *     of the error log is:
+ *
+ *	__le32 valid;        (nonzero) valid, (0) log is empty
+ *	__le32 error_id;     type of error
+ *	__le32 pc;           program counter
+ *	__le32 blink1;       branch link
+ *	__le32 blink2;       branch link
+ *	__le32 ilink1;       interrupt link
+ *	__le32 ilink2;       interrupt link
+ *	__le32 data1;        error-specific data
+ *	__le32 data2;        error-specific data
+ *	__le32 line;         source code line of error
+ *	__le32 bcon_time;    beacon timer
+ *	__le32 tsf_low;      network timestamp function timer
+ *	__le32 tsf_hi;       network timestamp function timer
+ *
+ * The Linux driver can print both logs to the system log when a uCode error
+ * occurs.
+ */
+struct iwl4965_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;			/* not "9" for runtime alive */
+	__le16 reserved2;
+	__le32 log_event_table_ptr;	/* SRAM address for event log */
+	__le32 error_event_table_ptr;	/* SRAM address for error log */
+	__le32 timestamp;
+	__le32 is_valid;
+} __attribute__ ((packed));
+
+
+union tsf {
+	u8 byte[8];
+	__le16 word[4];
+	__le32 dw[2];
+};
+
+/*
+ * REPLY_ERROR = 0x2 (response only, not a command)
+ */
+struct iwl4965_error_resp {
+	__le32 error_type;
+	u8 cmd_id;
+	u8 reserved1;
+	__le16 bad_cmd_seq_num;
+	__le32 error_info;
+	union tsf timestamp;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (1)
+ * RXON Commands & Responses:
+ *
+ *****************************************************************************/
+
+/*
+ * Rx config defines & structure
+ */
+/* rx_config device types  */
+enum {
+	RXON_DEV_TYPE_AP = 1,
+	RXON_DEV_TYPE_ESS = 3,
+	RXON_DEV_TYPE_IBSS = 4,
+	RXON_DEV_TYPE_SNIFFER = 6,
+};
+
+
+#define RXON_RX_CHAIN_DRIVER_FORCE_MSK		__constant_cpu_to_le16(0x1 << 0)
+#define RXON_RX_CHAIN_VALID_MSK			__constant_cpu_to_le16(0x7 << 1)
+#define RXON_RX_CHAIN_VALID_POS			(1)
+#define RXON_RX_CHAIN_FORCE_SEL_MSK		__constant_cpu_to_le16(0x7 << 4)
+#define RXON_RX_CHAIN_FORCE_SEL_POS		(4)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK	__constant_cpu_to_le16(0x7 << 7)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS	(7)
+#define RXON_RX_CHAIN_CNT_MSK			__constant_cpu_to_le16(0x3 << 10)
+#define RXON_RX_CHAIN_CNT_POS			(10)
+#define RXON_RX_CHAIN_MIMO_CNT_MSK		__constant_cpu_to_le16(0x3 << 12)
+#define RXON_RX_CHAIN_MIMO_CNT_POS		(12)
+#define RXON_RX_CHAIN_MIMO_FORCE_MSK		__constant_cpu_to_le16(0x1 << 14)
+#define RXON_RX_CHAIN_MIMO_FORCE_POS		(14)
+
+/* rx_config flags */
+/* band & modulation selection */
+#define RXON_FLG_BAND_24G_MSK           __constant_cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK                __constant_cpu_to_le32(1 << 1)
+/* auto detection enable */
+#define RXON_FLG_AUTO_DETECT_MSK        __constant_cpu_to_le32(1 << 2)
+/* TGg protection when tx */
+#define RXON_FLG_TGG_PROTECT_MSK        __constant_cpu_to_le32(1 << 3)
+/* cck short slot & preamble */
+#define RXON_FLG_SHORT_SLOT_MSK          __constant_cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK     __constant_cpu_to_le32(1 << 5)
+/* antenna selection */
+#define RXON_FLG_DIS_DIV_MSK            __constant_cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK            __constant_cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK              __constant_cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK              __constant_cpu_to_le32(1 << 9)
+/* radar detection enable */
+#define RXON_FLG_RADAR_DETECT_MSK       __constant_cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK    __constant_cpu_to_le32(1 << 13)
+/* rx response to host with 8-byte TSF
+* (according to ON_AIR deassertion) */
+#define RXON_FLG_TSF2HOST_MSK           __constant_cpu_to_le32(1 << 15)
+
+
+/* HT flags */
+#define RXON_FLG_CTRL_CHANNEL_LOC_POS		(22)
+#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK	__constant_cpu_to_le32(0x1 << 22)
+
+#define RXON_FLG_HT_OPERATING_MODE_POS		(23)
+
+#define RXON_FLG_HT_PROT_MSK			__constant_cpu_to_le32(0x1 << 23)
+#define RXON_FLG_FAT_PROT_MSK			__constant_cpu_to_le32(0x2 << 23)
+
+#define RXON_FLG_CHANNEL_MODE_POS		(25)
+#define RXON_FLG_CHANNEL_MODE_MSK		__constant_cpu_to_le32(0x3 << 25)
+#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK	__constant_cpu_to_le32(0x1 << 25)
+#define RXON_FLG_CHANNEL_MODE_MIXED_MSK		__constant_cpu_to_le32(0x2 << 25)
+
+/* rx_config filter flags */
+/* accept all data frames */
+#define RXON_FILTER_PROMISC_MSK         __constant_cpu_to_le32(1 << 0)
+/* pass control & management to host */
+#define RXON_FILTER_CTL2HOST_MSK        __constant_cpu_to_le32(1 << 1)
+/* accept multi-cast */
+#define RXON_FILTER_ACCEPT_GRP_MSK      __constant_cpu_to_le32(1 << 2)
+/* don't decrypt uni-cast frames */
+#define RXON_FILTER_DIS_DECRYPT_MSK     __constant_cpu_to_le32(1 << 3)
+/* don't decrypt multi-cast frames */
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+/* STA is associated */
+#define RXON_FILTER_ASSOC_MSK           __constant_cpu_to_le32(1 << 5)
+/* transfer to host non bssid beacons in associated state */
+#define RXON_FILTER_BCON_AWARE_MSK      __constant_cpu_to_le32(1 << 6)
+
+/**
+ * REPLY_RXON = 0x10 (command, has simple generic response)
+ *
+ * RXON tunes the radio tuner to a service channel, and sets up a number
+ * of parameters that are used primarily for Rx, but also for Tx operations.
+ *
+ * NOTE:  When tuning to a new channel, driver must set the
+ *        RXON_FILTER_ASSOC_MSK to 0.  This will clear station-dependent
+ *        info within the device, including the station tables, tx retry
+ *        rate tables, and txpower tables.  Driver must build a new station
+ *        table and txpower table before transmitting anything on the RXON
+ *        channel.
+ *
+ * NOTE:  All RXONs wipe clean the internal txpower table.  Driver must
+ *        issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10),
+ *        regardless of whether RXON_FILTER_ASSOC_MSK is set.
+ */
+struct iwl4965_rxon_cmd {
+	u8 node_addr[6];
+	__le16 reserved1;
+	u8 bssid_addr[6];
+	__le16 reserved2;
+	u8 wlap_bssid_addr[6];
+	__le16 reserved3;
+	u8 dev_type;
+	u8 air_propagation;
+	__le16 rx_chain;
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+	__le16 assoc_id;
+	__le32 flags;
+	__le32 filter_flags;
+	__le16 channel;
+	u8 ofdm_ht_single_stream_basic_rates;
+	u8 ofdm_ht_dual_stream_basic_rates;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
+ */
+struct iwl4965_rxon_assoc_cmd {
+	__le32 flags;
+	__le32 filter_flags;
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+	u8 ofdm_ht_single_stream_basic_rates;
+	u8 ofdm_ht_dual_stream_basic_rates;
+	__le16 rx_chain_select_flags;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
+ */
+struct iwl4965_rxon_time_cmd {
+	union tsf timestamp;
+	__le16 beacon_interval;
+	__le16 atim_window;
+	__le32 beacon_init_val;
+	__le16 listen_interval;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
+ */
+struct iwl4965_channel_switch_cmd {
+	u8 band;
+	u8 expect_beacon;
+	__le16 channel;
+	__le32 rxon_flags;
+	__le32 rxon_filter_flags;
+	__le32 switch_time;
+	struct iwl4965_tx_power_db tx_power;
+} __attribute__ ((packed));
+
+/*
+ * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
+ */
+struct iwl4965_csa_notification {
+	__le16 band;
+	__le16 channel;
+	__le32 status;		/* 0 - OK, 1 - fail */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (2)
+ * Quality-of-Service (QOS) Commands & Responses:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM
+ * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd
+ *
+ * @cw_min: Contention window, start value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x0f.
+ * @cw_max: Contention window, max value in numbers of slots.
+ *          Should be a power-of-2, minus 1.  Device's default is 0x3f.
+ * @aifsn:  Number of slots in Arbitration Interframe Space (before
+ *          performing random backoff timing prior to Tx).  Device default 1.
+ * @edca_txop:  Length of Tx opportunity, in uSecs.  Device default is 0.
+ *
+ * Device will automatically increase contention window by (2*CW) + 1 for each
+ * transmission retry.  Device uses cw_max as a bit mask, ANDed with new CW
+ * value, to cap the CW value.
+ */
+struct iwl4965_ac_qos {
+	__le16 cw_min;
+	__le16 cw_max;
+	u8 aifsn;
+	u8 reserved1;
+	__le16 edca_txop;
+} __attribute__ ((packed));
+
+/* QoS flags defines */
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	__constant_cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK		__constant_cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK	__constant_cpu_to_le32(0x10)
+
+/* Number of Access Categories (AC) (EDCA), queues 0..3 */
+#define AC_NUM                4
+
+/*
+ * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ *
+ * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
+ * 0: Background, 1: Best Effort, 2: Video, 3: Voice.
+ */
+struct iwl4965_qosparam_cmd {
+	__le32 qos_flags;
+	struct iwl4965_ac_qos ac[AC_NUM];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (3)
+ * Add/Modify Stations Commands & Responses:
+ *
+ *****************************************************************************/
+/*
+ * Multi station support
+ */
+
+/* Special, dedicated locations within device's station table */
+#define	IWL_AP_ID		0
+#define IWL_MULTICAST_ID	1
+#define	IWL_STA_ID		2
+#define IWL4965_BROADCAST_ID	31
+#define	IWL4965_STATION_COUNT	32
+
+#define	IWL_STATION_COUNT	32 	/* MAX(3945,4965)*/
+#define	IWL_INVALID_STATION 	255
+
+#define STA_FLG_PWR_SAVE_MSK		__constant_cpu_to_le32(1 << 8);
+#define STA_FLG_RTS_MIMO_PROT_MSK	__constant_cpu_to_le32(1 << 17)
+#define STA_FLG_AGG_MPDU_8US_MSK	__constant_cpu_to_le32(1 << 18)
+#define STA_FLG_MAX_AGG_SIZE_POS	(19)
+#define STA_FLG_MAX_AGG_SIZE_MSK	__constant_cpu_to_le32(3 << 19)
+#define STA_FLG_FAT_EN_MSK		__constant_cpu_to_le32(1 << 21)
+#define STA_FLG_MIMO_DIS_MSK		__constant_cpu_to_le32(1 << 22)
+#define STA_FLG_AGG_MPDU_DENSITY_POS	(23)
+#define STA_FLG_AGG_MPDU_DENSITY_MSK	__constant_cpu_to_le32(7 << 23)
+
+/* Use in mode field.  1: modify existing entry, 0: add new station entry */
+#define STA_CONTROL_MODIFY_MSK		0x01
+
+/* key flags __le16*/
+#define STA_KEY_FLG_ENCRYPT_MSK	__constant_cpu_to_le16(0x7)
+#define STA_KEY_FLG_NO_ENC	__constant_cpu_to_le16(0x0)
+#define STA_KEY_FLG_WEP		__constant_cpu_to_le16(0x1)
+#define STA_KEY_FLG_CCMP	__constant_cpu_to_le16(0x2)
+#define STA_KEY_FLG_TKIP	__constant_cpu_to_le16(0x3)
+
+#define STA_KEY_FLG_KEYID_POS	8
+#define STA_KEY_FLG_INVALID 	__constant_cpu_to_le16(0x0800)
+
+/* Flags indicate whether to modify vs. don't change various station params */
+#define	STA_MODIFY_KEY_MASK		0x01
+#define	STA_MODIFY_TID_DISABLE_TX	0x02
+#define	STA_MODIFY_TX_RATE_MSK		0x04
+#define STA_MODIFY_ADDBA_TID_MSK	0x08
+#define STA_MODIFY_DELBA_TID_MSK	0x10
+
+/* Receiver address (actually, Rx station's index into station table),
+ * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
+#define BUILD_RAxTID(sta_id, tid)	(((sta_id) << 4) + (tid))
+
+struct iwl4965_keyinfo {
+	__le16 key_flags;
+	u8 tkip_rx_tsc_byte2;	/* TSC[2] for key mix ph1 detection */
+	u8 reserved1;
+	__le16 tkip_rx_ttak[5];	/* 10-byte unicast TKIP TTAK */
+	__le16 reserved2;
+	u8 key[16];		/* 16-byte unicast decryption key */
+} __attribute__ ((packed));
+
+/**
+ * struct sta_id_modify
+ * @addr[ETH_ALEN]: station's MAC address
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change
+ *
+ * Driver selects unused table index when adding new station,
+ * or the index to a pre-existing station entry when modifying that station.
+ * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP).
+ *
+ * modify_mask flags select which parameters to modify vs. leave alone.
+ */
+struct sta_id_modify {
+	u8 addr[ETH_ALEN];
+	__le16 reserved1;
+	u8 sta_id;
+	u8 modify_mask;
+	__le16 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (command)
+ *
+ * The device contains an internal table of per-station information,
+ * with info on security keys, aggregation parameters, and Tx rates for
+ * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD,
+ * 3945 uses REPLY_RATE_SCALE to set up rate tables).
+ *
+ * REPLY_ADD_STA sets up the table entry for one station, either creating
+ * a new entry, or modifying a pre-existing one.
+ *
+ * NOTE:  RXON command (without "associated" bit set) wipes the station table
+ *        clean.  Moving into RF_KILL state does this also.  Driver must set up
+ *        new station table before transmitting anything on the RXON channel
+ *        (except active scans or active measurements; those commands carry
+ *        their own txpower/rate setup data).
+ *
+ *        When getting started on a new channel, driver must set up the
+ *        IWL_BROADCAST_ID entry (last entry in the table).  For a client
+ *        station in a BSS, once an AP is selected, driver sets up the AP STA
+ *        in the IWL_AP_ID entry (1st entry in the table).  BROADCAST and AP
+ *        are all that are needed for a BSS client station.  If the device is
+ *        used as AP, or in an IBSS network, driver must set up station table
+ *        entries for all STAs in network, starting with index IWL_STA_ID.
+ */
+struct iwl4965_addsta_cmd {
+	u8 mode;		/* 1: modify existing, 0: add new station */
+	u8 reserved[3];
+	struct sta_id_modify sta;
+	struct iwl4965_keyinfo key;
+	__le32 station_flags;		/* STA_FLG_* */
+	__le32 station_flags_msk;	/* STA_FLG_* */
+
+	/* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
+	 * corresponding to bit (e.g. bit 5 controls TID 5).
+	 * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
+	__le16 tid_disable_tx;
+
+	__le16	reserved1;
+
+	/* TID for which to add block-ack support.
+	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+	u8 add_immediate_ba_tid;
+
+	/* TID for which to remove block-ack support.
+	 * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
+	u8 remove_immediate_ba_tid;
+
+	/* Starting Sequence Number for added block-ack support.
+	 * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
+	__le16 add_immediate_ba_ssn;
+
+	__le32 reserved2;
+} __attribute__ ((packed));
+
+#define ADD_STA_SUCCESS_MSK		0x1
+#define ADD_STA_NO_ROOM_IN_TABLE	0x2
+#define ADD_STA_NO_BLOCK_ACK_RESOURCE	0x4
+#define ADD_STA_MODIFY_NON_EXIST_STA	0x8
+/*
+ * REPLY_ADD_STA = 0x18 (response)
+ */
+struct iwl4965_add_sta_resp {
+	u8 status;	/* ADD_STA_* */
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (4)
+ * Rx Responses:
+ *
+ *****************************************************************************/
+
+struct iwl4965_rx_frame_stats {
+	u8 phy_count;
+	u8 id;
+	u8 rssi;
+	u8 agc;
+	__le16 sig_avg;
+	__le16 noise_diff;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+struct iwl4965_rx_frame_hdr {
+	__le16 channel;
+	__le16 phy_flags;
+	u8 reserved1;
+	u8 rate;
+	__le16 len;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+#define	RX_RES_STATUS_NO_CRC32_ERROR	__constant_cpu_to_le32(1 << 0)
+#define	RX_RES_STATUS_NO_RXE_OVERFLOW	__constant_cpu_to_le32(1 << 1)
+
+#define	RX_RES_PHY_FLAGS_BAND_24_MSK	__constant_cpu_to_le16(1 << 0)
+#define	RX_RES_PHY_FLAGS_MOD_CCK_MSK		__constant_cpu_to_le16(1 << 1)
+#define	RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	__constant_cpu_to_le16(1 << 2)
+#define	RX_RES_PHY_FLAGS_NARROW_BAND_MSK	__constant_cpu_to_le16(1 << 3)
+#define	RX_RES_PHY_FLAGS_ANTENNA_MSK		__constant_cpu_to_le16(0xf0)
+
+#define	RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_WEP	(0x1 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_CCMP	(0x2 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_TKIP	(0x3 << 8)
+
+#define	RX_RES_STATUS_DECRYPT_TYPE_MSK	(0x3 << 11)
+#define	RX_RES_STATUS_NOT_DECRYPT	(0x0 << 11)
+#define	RX_RES_STATUS_DECRYPT_OK	(0x3 << 11)
+#define	RX_RES_STATUS_BAD_ICV_MIC	(0x1 << 11)
+#define	RX_RES_STATUS_BAD_KEY_TTAK	(0x2 << 11)
+
+struct iwl4965_rx_frame_end {
+	__le32 status;
+	__le64 timestamp;
+	__le32 beacon_timestamp;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_3945_RX = 0x1b (response only, not a command)
+ *
+ * NOTE:  DO NOT dereference from casts to this structure
+ * It is provided only for calculating minimum data set size.
+ * The actual offsets of the hdr and end are dynamic based on
+ * stats.phy_count
+ */
+struct iwl4965_rx_frame {
+	struct iwl4965_rx_frame_stats stats;
+	struct iwl4965_rx_frame_hdr hdr;
+	struct iwl4965_rx_frame_end end;
+} __attribute__ ((packed));
+
+/* Fixed (non-configurable) rx data from phy */
+#define RX_PHY_FLAGS_ANTENNAE_OFFSET		(4)
+#define RX_PHY_FLAGS_ANTENNAE_MASK		(0x70)
+#define IWL_AGC_DB_MASK 	(0x3f80)	/* MASK(7,13) */
+#define IWL_AGC_DB_POS		(7)
+struct iwl4965_rx_non_cfg_phy {
+	__le16 ant_selection;	/* ant A bit 4, ant B bit 5, ant C bit 6 */
+	__le16 agc_info;	/* agc code 0:6, agc dB 7:13, reserved 14:15 */
+	u8 rssi_info[6];	/* we use even entries, 0/2/4 for A/B/C rssi */
+	u8 pad[0];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_4965_RX = 0xc3 (response only, not a command)
+ * Used only for legacy (non 11n) frames.
+ */
+#define RX_RES_PHY_CNT 14
+struct iwl4965_rx_phy_res {
+	u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
+	u8 cfg_phy_cnt;		/* configurable DSP phy data byte count */
+	u8 stat_id;		/* configurable DSP phy data set ID */
+	u8 reserved1;
+	__le64 timestamp;	/* TSF at on air rise */
+	__le32 beacon_time_stamp; /* beacon at on-air rise */
+	__le16 phy_flags;	/* general phy flags: band, modulation, ... */
+	__le16 channel;		/* channel number */
+	__le16 non_cfg_phy[RX_RES_PHY_CNT];	/* upto 14 phy entries */
+	__le32 reserved2;
+	__le32 rate_n_flags;	/* RATE_MCS_* */
+	__le16 byte_count;	/* frame's byte-count */
+	__le16 reserved3;
+} __attribute__ ((packed));
+
+struct iwl4965_rx_mpdu_res_start {
+	__le16 byte_count;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (5)
+ * Tx Commands & Responses:
+ *
+ * Driver must place each REPLY_TX command into one of the prioritized Tx
+ * queues in host DRAM, shared between driver and device (see comments for
+ * SCD registers and Tx/Rx Queues).  When the device's Tx scheduler and uCode
+ * are preparing to transmit, the device pulls the Tx command over the PCI
+ * bus via one of the device's Tx DMA channels, to fill an internal FIFO
+ * from which data will be transmitted.
+ *
+ * uCode handles all timing and protocol related to control frames
+ * (RTS/CTS/ACK), based on flags in the Tx command.  uCode and Tx scheduler
+ * handle reception of block-acks; uCode updates the host driver via
+ * REPLY_COMPRESSED_BA (4965).
+ *
+ * uCode handles retrying Tx when an ACK is expected but not received.
+ * This includes trying lower data rates than the one requested in the Tx
+ * command, as set up by the REPLY_RATE_SCALE (for 3945) or
+ * REPLY_TX_LINK_QUALITY_CMD (4965).
+ *
+ * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD.
+ * This command must be executed after every RXON command, before Tx can occur.
+ *****************************************************************************/
+
+/* REPLY_TX Tx flags field */
+
+/* 1: Use Request-To-Send protocol before this frame.
+ * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
+#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+
+/* 1: Transmit Clear-To-Send to self before this frame.
+ * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.
+ * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */
+#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+
+/* 1: Expect ACK from receiving station
+ * 0: Don't expect ACK (MAC header's duration field s/b 0)
+ * Set this for unicast frames, but not broadcast/multicast. */
+#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+
+/* For 4965:
+ * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD).
+ *    Tx command's initial_rate_index indicates first rate to try;
+ *    uCode walks through table for additional Tx attempts.
+ * 0: Use Tx rate/MCS from Tx command's rate_n_flags field.
+ *    This rate will be used for all Tx attempts; it will not be scaled. */
+#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+
+/* 1: Expect immediate block-ack.
+ * Set when Txing a block-ack request frame.  Also set TX_CMD_FLG_ACK_MSK. */
+#define TX_CMD_FLG_IMM_BA_RSP_MASK  __constant_cpu_to_le32(1 << 6)
+
+/* 1: Frame requires full Tx-Op protection.
+ * Set this if either RTS or CTS Tx Flag gets set. */
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+
+/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
+ * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */
+#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+
+/* 1: Ignore Bluetooth priority for this frame.
+ * 0: Delay Tx until Bluetooth device is done (normal usage). */
+#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+
+/* 1: uCode overrides sequence control field in MAC header.
+ * 0: Driver provides sequence control field in MAC header.
+ * Set this for management frames, non-QOS data frames, non-unicast frames,
+ * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */
+#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
+
+/* 1: This frame is non-last MPDU; more fragments are coming.
+ * 0: Last fragment, or not using fragmentation. */
+#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
+
+/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame.
+ * 0: No TSF required in outgoing frame.
+ * Set this for transmitting beacons and probe responses. */
+#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
+
+/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword
+ *    alignment of frame's payload data field.
+ * 0: No pad
+ * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4
+ * field (but not both).  Driver must align frame data (i.e. data following
+ * MAC header) to DWORD boundary. */
+#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
+
+/* HCCA-AP - disable duration overwriting. */
+#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP  	0x01
+#define TX_CMD_SEC_CCM  	0x02
+#define TX_CMD_SEC_TKIP		0x03
+#define TX_CMD_SEC_MSK		0x03
+#define TX_CMD_SEC_SHIFT	6
+#define TX_CMD_SEC_KEY128	0x08
+
+/*
+ * 4965 uCode updates these Tx attempt count values in host DRAM.
+ * Used for managing Tx retries when expecting block-acks.
+ * Driver should set these fields to 0.
+ */
+struct iwl4965_dram_scratch {
+	u8 try_cnt;		/* Tx attempts */
+	u8 bt_kill_cnt;		/* Tx attempts blocked by Bluetooth device */
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX = 0x1c (command)
+ */
+struct iwl4965_tx_cmd {
+	/*
+	 * MPDU byte count:
+	 * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
+	 * + 8 byte IV for CCM or TKIP (not used for WEP)
+	 * + Data payload
+	 * + 8-byte MIC (not used for CCM/WEP)
+	 * NOTE:  Does not include Tx command bytes, post-MAC pad bytes,
+	 *        MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
+	 * Range: 14-2342 bytes.
+	 */
+	__le16 len;
+
+	/*
+	 * MPDU or MSDU byte count for next frame.
+	 * Used for fragmentation and bursting, but not 11n aggregation.
+	 * Same as "len", but for next frame.  Set to 0 if not applicable.
+	 */
+	__le16 next_frame_len;
+
+	__le32 tx_flags;	/* TX_CMD_FLG_* */
+
+	/* 4965's uCode may modify this field of the Tx command (in host DRAM!).
+	 * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */
+	struct iwl4965_dram_scratch scratch;
+
+	/* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */
+	__le32 rate_n_flags;	/* RATE_MCS_* */
+
+	/* Index of destination station in uCode's station table */
+	u8 sta_id;
+
+	/* Type of security encryption:  CCM or TKIP */
+	u8 sec_ctl;		/* TX_CMD_SEC_* */
+
+	/*
+	 * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial
+	 * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set.  Normally "0" for
+	 * data frames, this field may be used to selectively reduce initial
+	 * rate (via non-0 value) for special frames (e.g. management), while
+	 * still supporting rate scaling for all frames.
+	 */
+	u8 initial_rate_index;
+	u8 reserved;
+	u8 key[16];
+	__le16 next_frame_flags;
+	__le16 reserved2;
+	union {
+		__le32 life_time;
+		__le32 attempt;
+	} stop_time;
+
+	/* Host DRAM physical address pointer to "scratch" in this command.
+	 * Must be dword aligned.  "0" in dram_lsb_ptr disables usage. */
+	__le32 dram_lsb_ptr;
+	u8 dram_msb_ptr;
+
+	u8 rts_retry_limit;	/*byte 50 */
+	u8 data_retry_limit;	/*byte 51 */
+	u8 tid_tspec;
+	union {
+		__le16 pm_frame_timeout;
+		__le16 attempt_duration;
+	} timeout;
+
+	/*
+	 * Duration of EDCA burst Tx Opportunity, in 32-usec units.
+	 * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
+	 */
+	__le16 driver_txop;
+
+	/*
+	 * MAC header goes here, followed by 2 bytes padding if MAC header
+	 * length is 26 or 30 bytes, followed by payload data
+	 */
+	u8 payload[0];
+	struct ieee80211_hdr hdr[0];
+} __attribute__ ((packed));
+
+/* TX command response is sent after *all* transmission attempts.
+ *
+ * NOTES:
+ *
+ * TX_STATUS_FAIL_NEXT_FRAG
+ *
+ * If the fragment flag in the MAC header for the frame being transmitted
+ * is set and there is insufficient time to transmit the next frame, the
+ * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
+ *
+ * TX_STATUS_FIFO_UNDERRUN
+ *
+ * Indicates the host did not provide bytes to the FIFO fast enough while
+ * a TX was in progress.
+ *
+ * TX_STATUS_FAIL_MGMNT_ABORT
+ *
+ * This status is only possible if the ABORT ON MGMT RX parameter was
+ * set to true with the TX command.
+ *
+ * If the MSB of the status parameter is set then an abort sequence is
+ * required.  This sequence consists of the host activating the TX Abort
+ * control line, and then waiting for the TX Abort command response.  This
+ * indicates that a the device is no longer in a transmit state, and that the
+ * command FIFO has been cleared.  The host must then deactivate the TX Abort
+ * control line.  Receiving is still allowed in this case.
+ */
+enum {
+	TX_STATUS_SUCCESS = 0x01,
+	TX_STATUS_DIRECT_DONE = 0x02,
+	TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+	TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+	TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+	TX_STATUS_FAIL_MGMNT_ABORT = 0x85,
+	TX_STATUS_FAIL_NEXT_FRAG = 0x86,
+	TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+	TX_STATUS_FAIL_DEST_PS = 0x88,
+	TX_STATUS_FAIL_ABORTED = 0x89,
+	TX_STATUS_FAIL_BT_RETRY = 0x8a,
+	TX_STATUS_FAIL_STA_INVALID = 0x8b,
+	TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+	TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+	TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+	TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+	TX_STATUS_FAIL_TX_LOCKED = 0x90,
+	TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+#define	TX_PACKET_MODE_REGULAR		0x0000
+#define	TX_PACKET_MODE_BURST_SEQ	0x0100
+#define	TX_PACKET_MODE_BURST_FIRST	0x0200
+
+enum {
+	TX_POWER_PA_NOT_ACTIVE = 0x0,
+};
+
+enum {
+	TX_STATUS_MSK = 0x000000ff,	/* bits 0:7 */
+	TX_STATUS_DELAY_MSK = 0x00000040,
+	TX_STATUS_ABORT_MSK = 0x00000080,
+	TX_PACKET_MODE_MSK = 0x0000ff00,	/* bits 8:15 */
+	TX_FIFO_NUMBER_MSK = 0x00070000,	/* bits 16:18 */
+	TX_RESERVED = 0x00780000,	/* bits 19:22 */
+	TX_POWER_PA_DETECT_MSK = 0x7f800000,	/* bits 23:30 */
+	TX_ABORT_REQUIRED_MSK = 0x80000000,	/* bits 31:31 */
+};
+
+/* *******************************
+ * TX aggregation status
+ ******************************* */
+
+enum {
+	AGG_TX_STATE_TRANSMITTED = 0x00,
+	AGG_TX_STATE_UNDERRUN_MSK = 0x01,
+	AGG_TX_STATE_BT_PRIO_MSK = 0x02,
+	AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
+	AGG_TX_STATE_ABORT_MSK = 0x08,
+	AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
+	AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
+	AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
+	AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
+	AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
+	AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
+	AGG_TX_STATE_DUMP_TX_MSK = 0x200,
+	AGG_TX_STATE_DELAY_TX_MSK = 0x400
+};
+
+#define AGG_TX_STATE_LAST_SENT_MSK \
+(AGG_TX_STATE_LAST_SENT_TTL_MSK | \
+ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
+ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
+
+/* # tx attempts for first frame in aggregation */
+#define AGG_TX_STATE_TRY_CNT_POS 12
+#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
+
+/* Command ID and sequence number of Tx command for this frame */
+#define AGG_TX_STATE_SEQ_NUM_POS 16
+#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
+
+/*
+ * REPLY_TX = 0x1c (response)
+ *
+ * This response may be in one of two slightly different formats, indicated
+ * by the frame_count field:
+ *
+ * 1)  No aggregation (frame_count == 1).  This reports Tx results for
+ *     a single frame.  Multiple attempts, at various bit rates, may have
+ *     been made for this frame.
+ *
+ * 2)  Aggregation (frame_count > 1).  This reports Tx results for
+ *     2 or more frames that used block-acknowledge.  All frames were
+ *     transmitted at same rate.  Rate scaling may have been used if first
+ *     frame in this new agg block failed in previous agg block(s).
+ *
+ *     Note that, for aggregation, ACK (block-ack) status is not delivered here;
+ *     block-ack has not been received by the time the 4965 records this status.
+ *     This status relates to reasons the tx might have been blocked or aborted
+ *     within the sending station (this 4965), rather than whether it was
+ *     received successfully by the destination station.
+ */
+struct iwl4965_tx_resp {
+	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
+	u8 bt_kill_count;	/* # blocked by bluetooth (unused for agg) */
+	u8 failure_rts;		/* # failures due to unsuccessful RTS */
+	u8 failure_frame;	/* # failures due to no ACK (unused for agg) */
+
+	/* For non-agg:  Rate at which frame was successful.
+	 * For agg:  Rate at which all frames were transmitted. */
+	__le32 rate_n_flags;	/* RATE_MCS_*  */
+
+	/* For non-agg:  RTS + CTS + frame tx attempts time + ACK.
+	 * For agg:  RTS + CTS + aggregation tx time + block-ack time. */
+	__le16 wireless_media_time;	/* uSecs */
+
+	__le16 reserved;
+	__le32 pa_power1;	/* RF power amplifier measurement (not used) */
+	__le32 pa_power2;
+
+	/*
+	 * For non-agg:  frame status TX_STATUS_*
+	 * For agg:  status of 1st frame, AGG_TX_STATE_*; other frame status
+	 *           fields follow this one, up to frame_count.
+	 *           Bit fields:
+	 *           11- 0:  AGG_TX_STATE_* status code
+	 *           15-12:  Retry count for 1st frame in aggregation (retries
+	 *                   occur if tx failed for this frame when it was a
+	 *                   member of a previous aggregation block).  If rate
+	 *                   scaling is used, retry count indicates the rate
+	 *                   table entry used for all frames in the new agg.
+	 *           31-16:  Sequence # for this frame's Tx cmd (not SSN!)
+	 */
+	__le32 status;	/* TX status (for aggregation status of 1st frame) */
+} __attribute__ ((packed));
+
+/*
+ * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
+ *
+ * Reports Block-Acknowledge from recipient station
+ */
+struct iwl4965_compressed_ba_resp {
+	__le32 sta_addr_lo32;
+	__le16 sta_addr_hi16;
+	__le16 reserved;
+
+	/* Index of recipient (BA-sending) station in uCode's station table */
+	u8 sta_id;
+	u8 tid;
+	__le16 ba_seq_ctl;
+	__le32 ba_bitmap0;
+	__le32 ba_bitmap1;
+	__le16 scd_flow;
+	__le16 scd_ssn;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
+ *
+ * See details under "TXPOWER" in iwl-4965-hw.h.
+ */
+struct iwl4965_txpowertable_cmd {
+	u8 band;		/* 0: 5 GHz, 1: 2.4 GHz */
+	u8 reserved;
+	__le16 channel;
+	struct iwl4965_tx_power_db tx_power;
+} __attribute__ ((packed));
+
+/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
+#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK	(1 << 0)
+
+/* # of EDCA prioritized tx fifos */
+#define  LINK_QUAL_AC_NUM AC_NUM
+
+/* # entries in rate scale table to support Tx retries */
+#define  LINK_QUAL_MAX_RETRY_NUM 16
+
+/* Tx antenna selection values */
+#define  LINK_QUAL_ANT_A_MSK (1 << 0)
+#define  LINK_QUAL_ANT_B_MSK (1 << 1)
+#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
+
+
+/**
+ * struct iwl4965_link_qual_general_params
+ *
+ * Used in REPLY_TX_LINK_QUALITY_CMD
+ */
+struct iwl4965_link_qual_general_params {
+	u8 flags;
+
+	/* No entries at or above this (driver chosen) index contain MIMO */
+	u8 mimo_delimiter;
+
+	/* Best single antenna to use for single stream (legacy, SISO). */
+	u8 single_stream_ant_msk;	/* LINK_QUAL_ANT_* */
+
+	/* Best antennas to use for MIMO (unused for 4965, assumes both). */
+	u8 dual_stream_ant_msk;		/* LINK_QUAL_ANT_* */
+
+	/*
+	 * If driver needs to use different initial rates for different
+	 * EDCA QOS access categories (as implemented by tx fifos 0-3),
+	 * this table will set that up, by indicating the indexes in the
+	 * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start.
+	 * Otherwise, driver should set all entries to 0.
+	 *
+	 * Entry usage:
+	 * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice
+	 * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
+	 */
+	u8 start_rate_index[LINK_QUAL_AC_NUM];
+} __attribute__ ((packed));
+
+/**
+ * struct iwl4965_link_qual_agg_params
+ *
+ * Used in REPLY_TX_LINK_QUALITY_CMD
+ */
+struct iwl4965_link_qual_agg_params {
+
+	/* Maximum number of uSec in aggregation.
+	 * Driver should set this to 4000 (4 milliseconds). */
+	__le16 agg_time_limit;
+
+	/*
+	 * Number of Tx retries allowed for a frame, before that frame will
+	 * no longer be considered for the start of an aggregation sequence
+	 * (scheduler will then try to tx it as single frame).
+	 * Driver should set this to 3.
+	 */
+	u8 agg_dis_start_th;
+
+	/*
+	 * Maximum number of frames in aggregation.
+	 * 0 = no limit (default).  1 = no aggregation.
+	 * Other values = max # frames in aggregation.
+	 */
+	u8 agg_frame_cnt_limit;
+
+	__le32 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
+ *
+ * For 4965 only; 3945 uses REPLY_RATE_SCALE.
+ *
+ * Each station in the 4965's internal station table has its own table of 16
+ * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when
+ * an ACK is not received.  This command replaces the entire table for
+ * one station.
+ *
+ * NOTE:  Station must already be in 4965's station table.  Use REPLY_ADD_STA.
+ *
+ * The rate scaling procedures described below work well.  Of course, other
+ * procedures are possible, and may work better for particular environments.
+ *
+ *
+ * FILLING THE RATE TABLE
+ *
+ * Given a particular initial rate and mode, as determined by the rate
+ * scaling algorithm described below, the Linux driver uses the following
+ * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the
+ * Link Quality command:
+ *
+ *
+ * 1)  If using High-throughput (HT) (SISO or MIMO) initial rate:
+ *     a) Use this same initial rate for first 3 entries.
+ *     b) Find next lower available rate using same mode (SISO or MIMO),
+ *        use for next 3 entries.  If no lower rate available, switch to
+ *        legacy mode (no FAT channel, no MIMO, no short guard interval).
+ *     c) If using MIMO, set command's mimo_delimiter to number of entries
+ *        using MIMO (3 or 6).
+ *     d) After trying 2 HT rates, switch to legacy mode (no FAT channel,
+ *        no MIMO, no short guard interval), at the next lower bit rate
+ *        (e.g. if second HT bit rate was 54, try 48 legacy), and follow
+ *        legacy procedure for remaining table entries.
+ *
+ * 2)  If using legacy initial rate:
+ *     a) Use the initial rate for only one entry.
+ *     b) For each following entry, reduce the rate to next lower available
+ *        rate, until reaching the lowest available rate.
+ *     c) When reducing rate, also switch antenna selection.
+ *     d) Once lowest available rate is reached, repeat this rate until
+ *        rate table is filled (16 entries), switching antenna each entry.
+ *
+ *
+ * ACCUMULATING HISTORY
+ *
+ * The rate scaling algorithm for 4965, as implemented in Linux driver, uses
+ * two sets of frame Tx success history:  One for the current/active modulation
+ * mode, and one for a speculative/search mode that is being attempted.  If the
+ * speculative mode turns out to be more effective (i.e. actual transfer
+ * rate is better), then the driver continues to use the speculative mode
+ * as the new current active mode.
+ *
+ * Each history set contains, separately for each possible rate, data for a
+ * sliding window of the 62 most recent tx attempts at that rate.  The data
+ * includes a shifting bitmap of success(1)/failure(0), and sums of successful
+ * and attempted frames, from which the driver can additionally calculate a
+ * success ratio (success / attempted) and number of failures
+ * (attempted - success), and control the size of the window (attempted).
+ * The driver uses the bit map to remove successes from the success sum, as
+ * the oldest tx attempts fall out of the window.
+ *
+ * When the 4965 makes multiple tx attempts for a given frame, each attempt
+ * might be at a different rate, and have different modulation characteristics
+ * (e.g. antenna, fat channel, short guard interval), as set up in the rate
+ * scaling table in the Link Quality command.  The driver must determine
+ * which rate table entry was used for each tx attempt, to determine which
+ * rate-specific history to update, and record only those attempts that
+ * match the modulation characteristics of the history set.
+ *
+ * When using block-ack (aggregation), all frames are transmitted at the same
+ * rate, since there is no per-attempt acknowledgement from the destination
+ * station.  The Tx response struct iwl_tx_resp indicates the Tx rate in
+ * rate_n_flags field.  After receiving a block-ack, the driver can update
+ * history for the entire block all at once.
+ *
+ *
+ * FINDING BEST STARTING RATE:
+ *
+ * When working with a selected initial modulation mode (see below), the
+ * driver attempts to find a best initial rate.  The initial rate is the
+ * first entry in the Link Quality command's rate table.
+ *
+ * 1)  Calculate actual throughput (success ratio * expected throughput, see
+ *     table below) for current initial rate.  Do this only if enough frames
+ *     have been attempted to make the value meaningful:  at least 6 failed
+ *     tx attempts, or at least 8 successes.  If not enough, don't try rate
+ *     scaling yet.
+ *
+ * 2)  Find available rates adjacent to current initial rate.  Available means:
+ *     a)  supported by hardware &&
+ *     b)  supported by association &&
+ *     c)  within any constraints selected by user
+ *
+ * 3)  Gather measured throughputs for adjacent rates.  These might not have
+ *     enough history to calculate a throughput.  That's okay, we might try
+ *     using one of them anyway!
+ *
+ * 4)  Try decreasing rate if, for current rate:
+ *     a)  success ratio is < 15% ||
+ *     b)  lower adjacent rate has better measured throughput ||
+ *     c)  higher adjacent rate has worse throughput, and lower is unmeasured
+ *
+ *     As a sanity check, if decrease was determined above, leave rate
+ *     unchanged if:
+ *     a)  lower rate unavailable
+ *     b)  success ratio at current rate > 85% (very good)
+ *     c)  current measured throughput is better than expected throughput
+ *         of lower rate (under perfect 100% tx conditions, see table below)
+ *
+ * 5)  Try increasing rate if, for current rate:
+ *     a)  success ratio is < 15% ||
+ *     b)  both adjacent rates' throughputs are unmeasured (try it!) ||
+ *     b)  higher adjacent rate has better measured throughput ||
+ *     c)  lower adjacent rate has worse throughput, and higher is unmeasured
+ *
+ *     As a sanity check, if increase was determined above, leave rate
+ *     unchanged if:
+ *     a)  success ratio at current rate < 70%.  This is not particularly
+ *         good performance; higher rate is sure to have poorer success.
+ *
+ * 6)  Re-evaluate the rate after each tx frame.  If working with block-
+ *     acknowledge, history and statistics may be calculated for the entire
+ *     block (including prior history that fits within the history windows),
+ *     before re-evaluation.
+ *
+ * FINDING BEST STARTING MODULATION MODE:
+ *
+ * After working with a modulation mode for a "while" (and doing rate scaling),
+ * the driver searches for a new initial mode in an attempt to improve
+ * throughput.  The "while" is measured by numbers of attempted frames:
+ *
+ * For legacy mode, search for new mode after:
+ *   480 successful frames, or 160 failed frames
+ * For high-throughput modes (SISO or MIMO), search for new mode after:
+ *   4500 successful frames, or 400 failed frames
+ *
+ * Mode switch possibilities are (3 for each mode):
+ *
+ * For legacy:
+ *   Change antenna, try SISO (if HT association), try MIMO (if HT association)
+ * For SISO:
+ *   Change antenna, try MIMO, try shortened guard interval (SGI)
+ * For MIMO:
+ *   Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI)
+ *
+ * When trying a new mode, use the same bit rate as the old/current mode when
+ * trying antenna switches and shortened guard interval.  When switching to
+ * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate
+ * for which the expected throughput (under perfect conditions) is about the
+ * same or slightly better than the actual measured throughput delivered by
+ * the old/current mode.
+ *
+ * Actual throughput can be estimated by multiplying the expected throughput
+ * by the success ratio (successful / attempted tx frames).  Frame size is
+ * not considered in this calculation; it assumes that frame size will average
+ * out to be fairly consistent over several samples.  The following are
+ * metric values for expected throughput assuming 100% success ratio.
+ * Only G band has support for CCK rates:
+ *
+ *           RATE:  1    2    5   11    6   9   12   18   24   36   48   54   60
+ *
+ *              G:  7   13   35   58   40  57   72   98  121  154  177  186  186
+ *              A:  0    0    0    0   40  57   72   98  121  154  177  186  186
+ *     SISO 20MHz:  0    0    0    0   42  42   76  102  124  159  183  193  202
+ * SGI SISO 20MHz:  0    0    0    0   46  46   82  110  132  168  192  202  211
+ *     MIMO 20MHz:  0    0    0    0   74  74  123  155  179  214  236  244  251
+ * SGI MIMO 20MHz:  0    0    0    0   81  81  131  164  188  222  243  251  257
+ *     SISO 40MHz:  0    0    0    0   77  77  127  160  184  220  242  250  257
+ * SGI SISO 40MHz:  0    0    0    0   83  83  135  169  193  229  250  257  264
+ *     MIMO 40MHz:  0    0    0    0  123 123  182  214  235  264  279  285  289
+ * SGI MIMO 40MHz:  0    0    0    0  131 131  191  222  242  270  284  289  293
+ *
+ * After the new mode has been tried for a short while (minimum of 6 failed
+ * frames or 8 successful frames), compare success ratio and actual throughput
+ * estimate of the new mode with the old.  If either is better with the new
+ * mode, continue to use the new mode.
+ *
+ * Continue comparing modes until all 3 possibilities have been tried.
+ * If moving from legacy to HT, try all 3 possibilities from the new HT
+ * mode.  After trying all 3, a best mode is found.  Continue to use this mode
+ * for the longer "while" described above (e.g. 480 successful frames for
+ * legacy), and then repeat the search process.
+ *
+ */
+struct iwl4965_link_quality_cmd {
+
+	/* Index of destination/recipient station in uCode's station table */
+	u8 sta_id;
+	u8 reserved1;
+	__le16 control;		/* not used */
+	struct iwl4965_link_qual_general_params general_params;
+	struct iwl4965_link_qual_agg_params agg_params;
+
+	/*
+	 * Rate info; when using rate-scaling, Tx command's initial_rate_index
+	 * specifies 1st Tx rate attempted, via index into this table.
+	 * 4965 works its way through table when retrying Tx.
+	 */
+	struct {
+		__le32 rate_n_flags;	/* RATE_MCS_*, IWL_RATE_* */
+	} rs_table[LINK_QUAL_MAX_RETRY_NUM];
+	__le32 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ *
+ * 3945 and 4965 support hardware handshake with Bluetooth device on
+ * same platform.  Bluetooth device alerts wireless device when it will Tx;
+ * wireless device can delay or kill its own Tx to accomodate.
+ */
+struct iwl4965_bt_cmd {
+	u8 flags;
+	u8 lead_time;
+	u8 max_kill;
+	u8 reserved;
+	__le32 kill_ack_mask;
+	__le32 kill_cts_mask;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (6)
+ * Spectrum Management (802.11h) Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * Spectrum Management
+ */
+#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
+				 RXON_FILTER_CTL2HOST_MSK        | \
+				 RXON_FILTER_ACCEPT_GRP_MSK      | \
+				 RXON_FILTER_DIS_DECRYPT_MSK     | \
+				 RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
+				 RXON_FILTER_ASSOC_MSK           | \
+				 RXON_FILTER_BCON_AWARE_MSK)
+
+struct iwl4965_measure_channel {
+	__le32 duration;	/* measurement duration in extended beacon
+				 * format */
+	u8 channel;		/* channel to measure */
+	u8 type;		/* see enum iwl4965_measure_type */
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
+ */
+struct iwl4965_spectrum_cmd {
+	__le16 len;		/* number of bytes starting from token */
+	u8 token;		/* token id */
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 origin;		/* 0 = TGh, 1 = other, 2 = TGk */
+	u8 periodic;		/* 1 = periodic */
+	__le16 path_loss_timeout;
+	__le32 start_time;	/* start time in extended beacon format */
+	__le32 reserved2;
+	__le32 flags;		/* rxon flags */
+	__le32 filter_flags;	/* rxon filter flags */
+	__le16 channel_count;	/* minimum 1, maximum 10 */
+	__le16 reserved3;
+	struct iwl4965_measure_channel channels[10];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
+ */
+struct iwl4965_spectrum_resp {
+	u8 token;
+	u8 id;			/* id of the prior command replaced, or 0xff */
+	__le16 status;		/* 0 - command will be handled
+				 * 1 - cannot handle (conflicts with another
+				 *     measurement) */
+} __attribute__ ((packed));
+
+enum iwl4965_measurement_state {
+	IWL_MEASUREMENT_START = 0,
+	IWL_MEASUREMENT_STOP = 1,
+};
+
+enum iwl4965_measurement_status {
+	IWL_MEASUREMENT_OK = 0,
+	IWL_MEASUREMENT_CONCURRENT = 1,
+	IWL_MEASUREMENT_CSA_CONFLICT = 2,
+	IWL_MEASUREMENT_TGH_CONFLICT = 3,
+	/* 4-5 reserved */
+	IWL_MEASUREMENT_STOPPED = 6,
+	IWL_MEASUREMENT_TIMEOUT = 7,
+	IWL_MEASUREMENT_PERIODIC_FAILED = 8,
+};
+
+#define NUM_ELEMENTS_IN_HISTOGRAM 8
+
+struct iwl4965_measurement_histogram {
+	__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 0.8usec counts */
+	__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 1usec counts */
+} __attribute__ ((packed));
+
+/* clear channel availability counters */
+struct iwl4965_measurement_cca_counters {
+	__le32 ofdm;
+	__le32 cck;
+} __attribute__ ((packed));
+
+enum iwl4965_measure_type {
+	IWL_MEASURE_BASIC = (1 << 0),
+	IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
+	IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
+	IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
+	IWL_MEASURE_FRAME = (1 << 4),
+	/* bits 5:6 are reserved */
+	IWL_MEASURE_IDLE = (1 << 7),
+};
+
+/*
+ * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
+ */
+struct iwl4965_spectrum_notification {
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 token;
+	u8 channel_index;	/* index in measurement channel list */
+	u8 state;		/* 0 - start, 1 - stop */
+	__le32 start_time;	/* lower 32-bits of TSF */
+	u8 band;		/* 0 - 5.2GHz, 1 - 2.4GHz */
+	u8 channel;
+	u8 type;		/* see enum iwl4965_measurement_type */
+	u8 reserved1;
+	/* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
+	 * valid if applicable for measurement type requested. */
+	__le32 cca_ofdm;	/* cca fraction time in 40Mhz clock periods */
+	__le32 cca_cck;		/* cca fraction time in 44Mhz clock periods */
+	__le32 cca_time;	/* channel load time in usecs */
+	u8 basic_type;		/* 0 - bss, 1 - ofdm preamble, 2 -
+				 * unidentified */
+	u8 reserved2[3];
+	struct iwl4965_measurement_histogram histogram;
+	__le32 stop_time;	/* lower 32-bits of TSF */
+	__le32 status;		/* see iwl4965_measurement_status */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (7)
+ * Power Management Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl4965_powertable_cmd - Power Table Command
+ * @flags: See below:
+ *
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * PM allow:
+ *   bit 0 - '0' Driver not allow power management
+ *           '1' Driver allow PM (use rest of parameters)
+ * uCode send sleep notifications:
+ *   bit 1 - '0' Don't send sleep notification
+ *           '1' send sleep notification (SEND_PM_NOTIFICATION)
+ * Sleep over DTIM
+ *   bit 2 - '0' PM have to walk up every DTIM
+ *           '1' PM could sleep over DTIM till listen Interval.
+ * PCI power managed
+ *   bit 3 - '0' (PCI_LINK_CTRL & 0x1)
+ *           '1' !(PCI_LINK_CTRL & 0x1)
+ * Force sleep Modes
+ *   bit 31/30- '00' use both mac/xtal sleeps
+ *              '01' force Mac sleep
+ *              '10' force xtal sleep
+ *              '11' Illegal set
+ *
+ * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
+ * ucode assume sleep over DTIM is allowed and we don't need to wakeup
+ * for every DTIM.
+ */
+#define IWL_POWER_VEC_SIZE 5
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le16(1 << 0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le16(1 << 2)
+#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le16(1 << 3)
+
+struct iwl4965_powertable_cmd {
+	__le16 flags;
+	u8 keep_alive_seconds;
+	u8 debug_flags;
+	__le32 rx_data_timeout;
+	__le32 tx_data_timeout;
+	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
+	__le32 keep_alive_beacons;
+} __attribute__ ((packed));
+
+/*
+ * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
+ * 3945 and 4965 identical.
+ */
+struct iwl4965_sleep_notification {
+	u8 pm_sleep_mode;
+	u8 pm_wakeup_src;
+	__le16 reserved;
+	__le32 sleep_time;
+	__le32 tsf_low;
+	__le32 bcon_timer;
+} __attribute__ ((packed));
+
+/* Sleep states.  3945 and 4965 identical. */
+enum {
+	IWL_PM_NO_SLEEP = 0,
+	IWL_PM_SLP_MAC = 1,
+	IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
+	IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
+	IWL_PM_SLP_PHY = 4,
+	IWL_PM_SLP_REPENT = 5,
+	IWL_PM_WAKEUP_BY_TIMER = 6,
+	IWL_PM_WAKEUP_BY_DRIVER = 7,
+	IWL_PM_WAKEUP_BY_RFKILL = 8,
+	/* 3 reserved */
+	IWL_PM_NUM_OF_MODES = 12,
+};
+
+/*
+ * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
+ */
+#define CARD_STATE_CMD_DISABLE 0x00	/* Put card to sleep */
+#define CARD_STATE_CMD_ENABLE  0x01	/* Wake up card */
+#define CARD_STATE_CMD_HALT    0x02	/* Power down permanently */
+struct iwl4965_card_state_cmd {
+	__le32 status;		/* CARD_STATE_CMD_* request new power state */
+} __attribute__ ((packed));
+
+/*
+ * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
+ */
+struct iwl4965_card_state_notif {
+	__le32 flags;
+} __attribute__ ((packed));
+
+#define HW_CARD_DISABLED   0x01
+#define SW_CARD_DISABLED   0x02
+#define RF_CARD_DISABLED   0x04
+#define RXON_CARD_DISABLED 0x10
+
+struct iwl4965_ct_kill_config {
+	__le32   reserved;
+	__le32   critical_temperature_M;
+	__le32   critical_temperature_R;
+}  __attribute__ ((packed));
+
+/******************************************************************************
+ * (8)
+ * Scan Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl4965_scan_channel - entry in REPLY_SCAN_CMD channel table
+ *
+ * One for each channel in the scan list.
+ * Each channel can independently select:
+ * 1)  SSID for directed active scans
+ * 2)  Txpower setting (for rate specified within Tx command)
+ * 3)  How long to stay on-channel (behavior may be modified by quiet_time,
+ *     quiet_plcp_th, good_CRC_th)
+ *
+ * To avoid uCode errors, make sure the following are true (see comments
+ * under struct iwl4965_scan_cmd about max_out_time and quiet_time):
+ * 1)  If using passive_dwell (i.e. passive_dwell != 0):
+ *     active_dwell <= passive_dwell (< max_out_time if max_out_time != 0)
+ * 2)  quiet_time <= active_dwell
+ * 3)  If restricting off-channel time (i.e. max_out_time !=0):
+ *     passive_dwell < max_out_time
+ *     active_dwell < max_out_time
+ */
+struct iwl4965_scan_channel {
+	/*
+	 * type is defined as:
+	 * 0:0 1 = active, 0 = passive
+	 * 1:4 SSID direct bit map; if a bit is set, then corresponding
+	 *     SSID IE is transmitted in probe request.
+	 * 5:7 reserved
+	 */
+	u8 type;
+	u8 channel;	/* band is selected by iwl4965_scan_cmd "flags" field */
+	struct iwl4965_tx_power tpc;
+	__le16 active_dwell;	/* in 1024-uSec TU (time units), typ 5-50 */
+	__le16 passive_dwell;	/* in 1024-uSec TU (time units), typ 20-500 */
+} __attribute__ ((packed));
+
+/**
+ * struct iwl4965_ssid_ie - directed scan network information element
+ *
+ * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field
+ * in struct iwl4965_scan_channel; each channel may select different ssids from
+ * among the 4 entries.  SSID IEs get transmitted in reverse order of entry.
+ */
+struct iwl4965_ssid_ie {
+	u8 id;
+	u8 len;
+	u8 ssid[32];
+} __attribute__ ((packed));
+
+#define PROBE_OPTION_MAX        0x4
+#define TX_CMD_LIFE_TIME_INFINITE	__constant_cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH		__constant_cpu_to_le16(1)
+#define IWL_MAX_SCAN_SIZE 1024
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (command)
+ *
+ * The hardware scan command is very powerful; the driver can set it up to
+ * maintain (relatively) normal network traffic while doing a scan in the
+ * background.  The max_out_time and suspend_time control the ratio of how
+ * long the device stays on an associated network channel ("service channel")
+ * vs. how long it's away from the service channel, i.e. tuned to other channels
+ * for scanning.
+ *
+ * max_out_time is the max time off-channel (in usec), and suspend_time
+ * is how long (in "extended beacon" format) that the scan is "suspended"
+ * after returning to the service channel.  That is, suspend_time is the
+ * time that we stay on the service channel, doing normal work, between
+ * scan segments.  The driver may set these parameters differently to support
+ * scanning when associated vs. not associated, and light vs. heavy traffic
+ * loads when associated.
+ *
+ * After receiving this command, the device's scan engine does the following;
+ *
+ * 1)  Sends SCAN_START notification to driver
+ * 2)  Checks to see if it has time to do scan for one channel
+ * 3)  Sends NULL packet, with power-save (PS) bit set to 1,
+ *     to tell AP that we're going off-channel
+ * 4)  Tunes to first channel in scan list, does active or passive scan
+ * 5)  Sends SCAN_RESULT notification to driver
+ * 6)  Checks to see if it has time to do scan on *next* channel in list
+ * 7)  Repeats 4-6 until it no longer has time to scan the next channel
+ *     before max_out_time expires
+ * 8)  Returns to service channel
+ * 9)  Sends NULL packet with PS=0 to tell AP that we're back
+ * 10) Stays on service channel until suspend_time expires
+ * 11) Repeats entire process 2-10 until list is complete
+ * 12) Sends SCAN_COMPLETE notification
+ *
+ * For fast, efficient scans, the scan command also has support for staying on
+ * a channel for just a short time, if doing active scanning and getting no
+ * responses to the transmitted probe request.  This time is controlled by
+ * quiet_time, and the number of received packets below which a channel is
+ * considered "quiet" is controlled by quiet_plcp_threshold.
+ *
+ * For active scanning on channels that have regulatory restrictions against
+ * blindly transmitting, the scan can listen before transmitting, to make sure
+ * that there is already legitimate activity on the channel.  If enough
+ * packets are cleanly received on the channel (controlled by good_CRC_th,
+ * typical value 1), the scan engine starts transmitting probe requests.
+ *
+ * Driver must use separate scan commands for 2.4 vs. 5 GHz bands.
+ *
+ * To avoid uCode errors, see timing restrictions described under
+ * struct iwl4965_scan_channel.
+ */
+struct iwl4965_scan_cmd {
+	__le16 len;
+	u8 reserved0;
+	u8 channel_count;	/* # channels in channel list */
+	__le16 quiet_time;	/* dwell only this # millisecs on quiet channel
+				 * (only for active scan) */
+	__le16 quiet_plcp_th;	/* quiet chnl is < this # pkts (typ. 1) */
+	__le16 good_CRC_th;	/* passive -> active promotion threshold */
+	__le16 rx_chain;	/* RXON_RX_CHAIN_* */
+	__le32 max_out_time;	/* max usec to be away from associated (service)
+				 * channel */
+	__le32 suspend_time;	/* pause scan this long (in "extended beacon
+				 * format") when returning to service chnl:
+				 * 3945; 31:24 # beacons, 19:0 additional usec,
+				 * 4965; 31:22 # beacons, 21:0 additional usec.
+				 */
+	__le32 flags;		/* RXON_FLG_* */
+	__le32 filter_flags;	/* RXON_FILTER_* */
+
+	/* For active scans (set to all-0s for passive scans).
+	 * Does not include payload.  Must specify Tx rate; no rate scaling. */
+	struct iwl4965_tx_cmd tx_cmd;
+
+	/* For directed active scans (set to all-0s otherwise) */
+	struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX];
+
+	/*
+	 * Probe request frame, followed by channel list.
+	 *
+	 * Size of probe request frame is specified by byte count in tx_cmd.
+	 * Channel list follows immediately after probe request frame.
+	 * Number of channels in list is specified by channel_count.
+	 * Each channel in list is of type:
+	 *
+	 * struct iwl4965_scan_channel channels[0];
+	 *
+	 * NOTE:  Only one band of channels can be scanned per pass.  You
+	 * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
+	 * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
+	 * before requesting another scan.
+	 */
+	u8 data[0];
+} __attribute__ ((packed));
+
+/* Can abort will notify by complete notification with abort status. */
+#define CAN_ABORT_STATUS	__constant_cpu_to_le32(0x1)
+/* complete notification statuses */
+#define ABORT_STATUS            0x2
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (response)
+ */
+struct iwl4965_scanreq_notification {
+	__le32 status;		/* 1: okay, 2: cannot fulfill request */
+} __attribute__ ((packed));
+
+/*
+ * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
+ */
+struct iwl4965_scanstart_notification {
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 beacon_timer;
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 status;
+} __attribute__ ((packed));
+
+#define  SCAN_OWNER_STATUS 0x1;
+#define  MEASURE_OWNER_STATUS 0x2;
+
+#define NUMBER_OF_STATISTICS 1	/* first __le32 is good CRC */
+/*
+ * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
+ */
+struct iwl4965_scanresults_notification {
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 statistics[NUMBER_OF_STATISTICS];
+} __attribute__ ((packed));
+
+/*
+ * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
+ */
+struct iwl4965_scancomplete_notification {
+	u8 scanned_channels;
+	u8 status;
+	u8 reserved;
+	u8 last_channel;
+	__le32 tsf_low;
+	__le32 tsf_high;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (9)
+ * IBSS/AP Commands and Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
+ */
+struct iwl4965_beacon_notif {
+	struct iwl4965_tx_resp beacon_notify_hdr;
+	__le32 low_tsf;
+	__le32 high_tsf;
+	__le32 ibss_mgr_status;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
+ */
+struct iwl4965_tx_beacon_cmd {
+	struct iwl4965_tx_cmd tx;
+	__le16 tim_idx;
+	u8 tim_size;
+	u8 reserved1;
+	struct ieee80211_hdr frame[0];	/* beacon frame */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (10)
+ * Statistics Commands and Notifications:
+ *
+ *****************************************************************************/
+
+#define IWL_TEMP_CONVERT 260
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/* Used for passing to driver number of successes and failures per rate */
+struct rate_histogram {
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} success;
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} failed;
+} __attribute__ ((packed));
+
+/* statistics command response */
+
+struct statistics_rx_phy {
+	__le32 ina_cnt;
+	__le32 fina_cnt;
+	__le32 plcp_err;
+	__le32 crc32_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 false_alarm_cnt;
+	__le32 fina_sync_err_cnt;
+	__le32 sfd_timeout;
+	__le32 fina_timeout;
+	__le32 unresponded_rts;
+	__le32 rxe_frame_limit_overrun;
+	__le32 sent_ack_cnt;
+	__le32 sent_cts_cnt;
+	__le32 sent_ba_rsp_cnt;
+	__le32 dsp_self_kill;
+	__le32 mh_format_err;
+	__le32 re_acq_main_rssi_sum;
+	__le32 reserved3;
+} __attribute__ ((packed));
+
+struct statistics_rx_ht_phy {
+	__le32 plcp_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 crc32_err;
+	__le32 mh_format_err;
+	__le32 agg_crc32_good;
+	__le32 agg_mpdu_cnt;
+	__le32 agg_cnt;
+	__le32 reserved2;
+} __attribute__ ((packed));
+
+struct statistics_rx_non_phy {
+	__le32 bogus_cts;	/* CTS received when not expecting CTS */
+	__le32 bogus_ack;	/* ACK received when not expecting ACK */
+	__le32 non_bssid_frames;	/* number of frames with BSSID that
+					 * doesn't belong to the STA BSSID */
+	__le32 filtered_frames;	/* count frames that were dumped in the
+				 * filtering process */
+	__le32 non_channel_beacons;	/* beacons with our bss id but not on
+					 * our serving channel */
+	__le32 channel_beacons;	/* beacons with our bss id and in our
+				 * serving channel */
+	__le32 num_missed_bcon;	/* number of missed beacons */
+	__le32 adc_rx_saturation_time;	/* count in 0.8us units the time the
+					 * ADC was in saturation */
+	__le32 ina_detection_search_time;/* total time (in 0.8us) searched
+					  * for INA */
+	__le32 beacon_silence_rssi_a;	/* RSSI silence after beacon frame */
+	__le32 beacon_silence_rssi_b;	/* RSSI silence after beacon frame */
+	__le32 beacon_silence_rssi_c;	/* RSSI silence after beacon frame */
+	__le32 interference_data_flag;	/* flag for interference data
+					 * availability. 1 when data is
+					 * available. */
+	__le32 channel_load;		/* counts RX Enable time in uSec */
+	__le32 dsp_false_alarms;	/* DSP false alarm (both OFDM
+					 * and CCK) counter */
+	__le32 beacon_rssi_a;
+	__le32 beacon_rssi_b;
+	__le32 beacon_rssi_c;
+	__le32 beacon_energy_a;
+	__le32 beacon_energy_b;
+	__le32 beacon_energy_c;
+} __attribute__ ((packed));
+
+struct statistics_rx {
+	struct statistics_rx_phy ofdm;
+	struct statistics_rx_phy cck;
+	struct statistics_rx_non_phy general;
+	struct statistics_rx_ht_phy ofdm_ht;
+} __attribute__ ((packed));
+
+struct statistics_tx_non_phy_agg {
+	__le32 ba_timeout;
+	__le32 ba_reschedule_frames;
+	__le32 scd_query_agg_frame_cnt;
+	__le32 scd_query_no_agg;
+	__le32 scd_query_agg;
+	__le32 scd_query_mismatch;
+	__le32 frame_not_ready;
+	__le32 underrun;
+	__le32 bt_prio_kill;
+	__le32 rx_ba_rsp_cnt;
+	__le32 reserved2;
+	__le32 reserved3;
+} __attribute__ ((packed));
+
+struct statistics_tx {
+	__le32 preamble_cnt;
+	__le32 rx_detected_cnt;
+	__le32 bt_prio_defer_cnt;
+	__le32 bt_prio_kill_cnt;
+	__le32 few_bytes_cnt;
+	__le32 cts_timeout;
+	__le32 ack_timeout;
+	__le32 expected_ack_cnt;
+	__le32 actual_ack_cnt;
+	__le32 dump_msdu_cnt;
+	__le32 burst_abort_next_frame_mismatch_cnt;
+	__le32 burst_abort_missing_next_frame_cnt;
+	__le32 cts_timeout_collision;
+	__le32 ack_or_ba_timeout_collision;
+	struct statistics_tx_non_phy_agg agg;
+} __attribute__ ((packed));
+
+struct statistics_dbg {
+	__le32 burst_check;
+	__le32 burst_count;
+	__le32 reserved[4];
+} __attribute__ ((packed));
+
+struct statistics_div {
+	__le32 tx_on_a;
+	__le32 tx_on_b;
+	__le32 exec_time;
+	__le32 probe_time;
+	__le32 reserved1;
+	__le32 reserved2;
+} __attribute__ ((packed));
+
+struct statistics_general {
+	__le32 temperature;
+	__le32 temperature_m;
+	struct statistics_dbg dbg;
+	__le32 sleep_time;
+	__le32 slots_out;
+	__le32 slots_idle;
+	__le32 ttl_timestamp;
+	struct statistics_div div;
+	__le32 rx_enable_counter;
+	__le32 reserved1;
+	__le32 reserved2;
+	__le32 reserved3;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_STATISTICS_CMD = 0x9c,
+ * 3945 and 4965 identical.
+ *
+ * This command triggers an immediate response containing uCode statistics.
+ * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
+ *
+ * If the CLEAR_STATS configuration flag is set, uCode will clear its
+ * internal copy of the statistics (counters) after issuing the response.
+ * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
+ *
+ * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
+ * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
+ * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
+ */
+#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1)	/* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+struct iwl4965_statistics_cmd {
+	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
+} __attribute__ ((packed));
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans.  uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK         __constant_cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         __constant_cpu_to_le32(0x8)
+struct iwl4965_notif_statistics {
+	__le32 flag;
+	struct statistics_rx rx;
+	struct statistics_tx tx;
+	struct statistics_general general;
+} __attribute__ ((packed));
+
+
+/*
+ * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ */
+/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
+ * then this notification will be sent. */
+#define CONSECUTIVE_MISSED_BCONS_TH 20
+
+struct iwl4965_missed_beacon_notif {
+	__le32 consequtive_missed_beacons;
+	__le32 total_missed_becons;
+	__le32 num_expected_beacons;
+	__le32 num_recvd_beacons;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (11)
+ * Rx Calibration Commands:
+ *
+ * With the uCode used for open source drivers, most Tx calibration (except
+ * for Tx Power) and most Rx calibration is done by uCode during the
+ * "initialize" phase of uCode boot.  Driver must calibrate only:
+ *
+ * 1)  Tx power (depends on temperature), described elsewhere
+ * 2)  Receiver gain balance (optimize MIMO, and detect disconnected antennas)
+ * 3)  Receiver sensitivity (to optimize signal detection)
+ *
+ *****************************************************************************/
+
+/**
+ * SENSITIVITY_CMD = 0xa8 (command, has simple generic response)
+ *
+ * This command sets up the Rx signal detector for a sensitivity level that
+ * is high enough to lock onto all signals within the associated network,
+ * but low enough to ignore signals that are below a certain threshold, so as
+ * not to have too many "false alarms".  False alarms are signals that the
+ * Rx DSP tries to lock onto, but then discards after determining that they
+ * are noise.
+ *
+ * The optimum number of false alarms is between 5 and 50 per 200 TUs
+ * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e.
+ * time listening, not transmitting).  Driver must adjust sensitivity so that
+ * the ratio of actual false alarms to actual Rx time falls within this range.
+ *
+ * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each
+ * received beacon.  These provide information to the driver to analyze the
+ * sensitivity.  Don't analyze statistics that come in from scanning, or any
+ * other non-associated-network source.  Pertinent statistics include:
+ *
+ * From "general" statistics (struct statistics_rx_non_phy):
+ *
+ * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level)
+ *   Measure of energy of desired signal.  Used for establishing a level
+ *   below which the device does not detect signals.
+ *
+ * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB)
+ *   Measure of background noise in silent period after beacon.
+ *
+ * channel_load
+ *   uSecs of actual Rx time during beacon period (varies according to
+ *   how much time was spent transmitting).
+ *
+ * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately:
+ *
+ * false_alarm_cnt
+ *   Signal locks abandoned early (before phy-level header).
+ *
+ * plcp_err
+ *   Signal locks abandoned late (during phy-level header).
+ *
+ * NOTE:  Both false_alarm_cnt and plcp_err increment monotonically from
+ *        beacon to beacon, i.e. each value is an accumulation of all errors
+ *        before and including the latest beacon.  Values will wrap around to 0
+ *        after counting up to 2^32 - 1.  Driver must differentiate vs.
+ *        previous beacon's values to determine # false alarms in the current
+ *        beacon period.
+ *
+ * Total number of false alarms = false_alarms + plcp_errs
+ *
+ * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd
+ * (notice that the start points for OFDM are at or close to settings for
+ * maximum sensitivity):
+ *
+ *                                             START  /  MIN  /  MAX
+ *   HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          90   /   85  /  120
+ *   HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX     170   /  170  /  210
+ *   HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX         105   /  105  /  140
+ *   HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX     220   /  220  /  270
+ *
+ *   If actual rate of OFDM false alarms (+ plcp_errors) is too high
+ *   (greater than 50 for each 204.8 msecs listening), reduce sensitivity
+ *   by *adding* 1 to all 4 of the table entries above, up to the max for
+ *   each entry.  Conversely, if false alarm rate is too low (less than 5
+ *   for each 204.8 msecs listening), *subtract* 1 from each entry to
+ *   increase sensitivity.
+ *
+ * For CCK sensitivity, keep track of the following:
+ *
+ *   1).  20-beacon history of maximum background noise, indicated by
+ *        (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the
+ *        3 receivers.  For any given beacon, the "silence reference" is
+ *        the maximum of last 60 samples (20 beacons * 3 receivers).
+ *
+ *   2).  10-beacon history of strongest signal level, as indicated
+ *        by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers,
+ *        i.e. the strength of the signal through the best receiver at the
+ *        moment.  These measurements are "upside down", with lower values
+ *        for stronger signals, so max energy will be *minimum* value.
+ *
+ *        Then for any given beacon, the driver must determine the *weakest*
+ *        of the strongest signals; this is the minimum level that needs to be
+ *        successfully detected, when using the best receiver at the moment.
+ *        "Max cck energy" is the maximum (higher value means lower energy!)
+ *        of the last 10 minima.  Once this is determined, driver must add
+ *        a little margin by adding "6" to it.
+ *
+ *   3).  Number of consecutive beacon periods with too few false alarms.
+ *        Reset this to 0 at the first beacon period that falls within the
+ *        "good" range (5 to 50 false alarms per 204.8 milliseconds rx).
+ *
+ * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd
+ * (notice that the start points for CCK are at maximum sensitivity):
+ *
+ *                                             START  /  MIN  /  MAX
+ *   HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX         125   /  125  /  200
+ *   HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX     200   /  200  /  400
+ *   HD_MIN_ENERGY_CCK_DET_INDEX                100   /    0  /  100
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is too high
+ *   (greater than 50 for each 204.8 msecs listening), method for reducing
+ *   sensitivity is:
+ *
+ *   1)  *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
+ *       up to max 400.
+ *
+ *   2)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160,
+ *       sensitivity has been reduced a significant amount; bring it up to
+ *       a moderate 161.  Otherwise, *add* 3, up to max 200.
+ *
+ *   3)  a)  If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160,
+ *       sensitivity has been reduced only a moderate or small amount;
+ *       *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX,
+ *       down to min 0.  Otherwise (if gain has been significantly reduced),
+ *       don't change the HD_MIN_ENERGY_CCK_DET_INDEX value.
+ *
+ *       b)  Save a snapshot of the "silence reference".
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is too low
+ *   (less than 5 for each 204.8 msecs listening), method for increasing
+ *   sensitivity is used only if:
+ *
+ *   1a)  Previous beacon did not have too many false alarms
+ *   1b)  AND difference between previous "silence reference" and current
+ *        "silence reference" (prev - current) is 2 or more,
+ *   OR 2)  100 or more consecutive beacon periods have had rate of
+ *          less than 5 false alarms per 204.8 milliseconds rx time.
+ *
+ *   Method for increasing sensitivity:
+ *
+ *   1)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX,
+ *       down to min 125.
+ *
+ *   2)  *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX,
+ *       down to min 200.
+ *
+ *   3)  *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100.
+ *
+ *   If actual rate of CCK false alarms (+ plcp_errors) is within good range
+ *   (between 5 and 50 for each 204.8 msecs listening):
+ *
+ *   1)  Save a snapshot of the silence reference.
+ *
+ *   2)  If previous beacon had too many CCK false alarms (+ plcp_errors),
+ *       give some extra margin to energy threshold by *subtracting* 8
+ *       from value in HD_MIN_ENERGY_CCK_DET_INDEX.
+ *
+ *   For all cases (too few, too many, good range), make sure that the CCK
+ *   detection threshold (energy) is below the energy level for robust
+ *   detection over the past 10 beacon periods, the "Max cck energy".
+ *   Lower values mean higher energy; this means making sure that the value
+ *   in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy".
+ *
+ * Driver should set the following entries to fixed values:
+ *
+ *   HD_MIN_ENERGY_OFDM_DET_INDEX               100
+ *   HD_BARKER_CORR_TH_ADD_MIN_INDEX            190
+ *   HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX        390
+ *   HD_OFDM_ENERGY_TH_IN_INDEX                  62
+ */
+
+/*
+ * Table entries in SENSITIVITY_CMD (struct iwl4965_sensitivity_cmd)
+ */
+#define HD_TABLE_SIZE  (11)	/* number of entries */
+#define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)	/* table indexes */
+#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
+#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
+#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX          (9)
+#define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
+
+/* Control field in struct iwl4965_sensitivity_cmd */
+#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE	__constant_cpu_to_le16(0)
+#define SENSITIVITY_CMD_CONTROL_WORK_TABLE	__constant_cpu_to_le16(1)
+
+/**
+ * struct iwl4965_sensitivity_cmd
+ * @control:  (1) updates working table, (0) updates default table
+ * @table:  energy threshold values, use HD_* as index into table
+ *
+ * Always use "1" in "control" to update uCode's working table and DSP.
+ */
+struct iwl4965_sensitivity_cmd {
+	__le16 control;			/* always use "1" */
+	__le16 table[HD_TABLE_SIZE];	/* use HD_* as index */
+} __attribute__ ((packed));
+
+
+/**
+ * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response)
+ *
+ * This command sets the relative gains of 4965's 3 radio receiver chains.
+ *
+ * After the first association, driver should accumulate signal and noise
+ * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20
+ * beacons from the associated network (don't collect statistics that come
+ * in from scanning, or any other non-network source).
+ *
+ * DISCONNECTED ANTENNA:
+ *
+ * Driver should determine which antennas are actually connected, by comparing
+ * average beacon signal levels for the 3 Rx chains.  Accumulate (add) the
+ * following values over 20 beacons, one accumulator for each of the chains
+ * a/b/c, from struct statistics_rx_non_phy:
+ *
+ * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB)
+ *
+ * Find the strongest signal from among a/b/c.  Compare the other two to the
+ * strongest.  If any signal is more than 15 dB (times 20, unless you
+ * divide the accumulated values by 20) below the strongest, the driver
+ * considers that antenna to be disconnected, and should not try to use that
+ * antenna/chain for Rx or Tx.  If both A and B seem to be disconnected,
+ * driver should declare the stronger one as connected, and attempt to use it
+ * (A and B are the only 2 Tx chains!).
+ *
+ *
+ * RX BALANCE:
+ *
+ * Driver should balance the 3 receivers (but just the ones that are connected
+ * to antennas, see above) for gain, by comparing the average signal levels
+ * detected during the silence after each beacon (background noise).
+ * Accumulate (add) the following values over 20 beacons, one accumulator for
+ * each of the chains a/b/c, from struct statistics_rx_non_phy:
+ *
+ * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB)
+ *
+ * Find the weakest background noise level from among a/b/c.  This Rx chain
+ * will be the reference, with 0 gain adjustment.  Attenuate other channels by
+ * finding noise difference:
+ *
+ * (accum_noise[i] - accum_noise[reference]) / 30
+ *
+ * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB.
+ * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the
+ * driver should limit the difference results to a range of 0-3 (0-4.5 dB),
+ * and set bit 2 to indicate "reduce gain".  The value for the reference
+ * (weakest) chain should be "0".
+ *
+ * diff_gain_[abc] bit fields:
+ *   2: (1) reduce gain, (0) increase gain
+ * 1-0: amount of gain, units of 1.5 dB
+ */
+
+/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */
+#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
+
+struct iwl4965_calibration_cmd {
+	u8 opCode;		/* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
+	u8 flags;		/* not used */
+	__le16 reserved;
+	s8 diff_gain_a;		/* see above */
+	s8 diff_gain_b;
+	s8 diff_gain_c;
+	u8 reserved1;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (12)
+ * Miscellaneous Commands:
+ *
+ *****************************************************************************/
+
+/*
+ * LEDs Command & Response
+ * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
+ *
+ * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
+ * this command turns it on or off, or sets up a periodic blinking cycle.
+ */
+struct iwl4965_led_cmd {
+	__le32 interval;	/* "interval" in uSec */
+	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
+	u8 off;			/* # intervals off while blinking;
+				 * "0", with >0 "on" value, turns LED on */
+	u8 on;			/* # intervals on while blinking;
+				 * "0", regardless of "off", turns LED off */
+	u8 reserved;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (13)
+ * Union of all expected notifications/responses:
+ *
+ *****************************************************************************/
+
+struct iwl4965_rx_packet {
+	__le32 len;
+	struct iwl4965_cmd_header hdr;
+	union {
+		struct iwl4965_alive_resp alive_frame;
+		struct iwl4965_rx_frame rx_frame;
+		struct iwl4965_tx_resp tx_resp;
+		struct iwl4965_spectrum_notification spectrum_notif;
+		struct iwl4965_csa_notification csa_notif;
+		struct iwl4965_error_resp err_resp;
+		struct iwl4965_card_state_notif card_state_notif;
+		struct iwl4965_beacon_notif beacon_status;
+		struct iwl4965_add_sta_resp add_sta;
+		struct iwl4965_sleep_notification sleep_notif;
+		struct iwl4965_spectrum_resp spectrum;
+		struct iwl4965_notif_statistics stats;
+		struct iwl4965_compressed_ba_resp compressed_ba;
+		struct iwl4965_missed_beacon_notif missed_beacon;
+		__le32 status;
+		u8 raw[0];
+	} u;
+} __attribute__ ((packed));
+
+#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl4965_rx_frame))
+
+#endif				/* __iwl4965_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-debug.h b/drivers/net/wireless/iwlwifi/iwl-4965-debug.h
new file mode 100644
index 000000000000..36696bbf170c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-debug.h
@@ -0,0 +1,152 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl4965_debug_h__
+#define __iwl4965_debug_h__
+
+#ifdef CONFIG_IWL4965_DEBUG
+extern u32 iwl4965_debug_level;
+#define IWL_DEBUG(level, fmt, args...) \
+do { if (iwl4965_debug_level & (level)) \
+  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+#define IWL_DEBUG_LIMIT(level, fmt, args...) \
+do { if ((iwl4965_debug_level & (level)) && net_ratelimit()) \
+  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+static inline void IWL_DEBUG(int level, const char *fmt, ...)
+{
+}
+static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
+{
+}
+#endif				/* CONFIG_IWL4965_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IWL_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry.  xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IWL_xxxx_DEBUG() macro definition for your
+ * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/iwl/debug_level
+ *
+ * you simply need to add your entry to the iwl4965_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/iwl then you do not have
+ * CONFIG_IWL4965_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IWL_DL_INFO          (1 << 0)
+#define IWL_DL_MAC80211      (1 << 1)
+#define IWL_DL_HOST_COMMAND  (1 << 2)
+#define IWL_DL_STATE         (1 << 3)
+
+#define IWL_DL_RADIO         (1 << 7)
+#define IWL_DL_POWER         (1 << 8)
+#define IWL_DL_TEMP          (1 << 9)
+
+#define IWL_DL_NOTIF         (1 << 10)
+#define IWL_DL_SCAN          (1 << 11)
+#define IWL_DL_ASSOC         (1 << 12)
+#define IWL_DL_DROP          (1 << 13)
+
+#define IWL_DL_TXPOWER       (1 << 14)
+
+#define IWL_DL_AP            (1 << 15)
+
+#define IWL_DL_FW            (1 << 16)
+#define IWL_DL_RF_KILL       (1 << 17)
+#define IWL_DL_FW_ERRORS     (1 << 18)
+
+#define IWL_DL_LED           (1 << 19)
+
+#define IWL_DL_RATE          (1 << 20)
+
+#define IWL_DL_CALIB         (1 << 21)
+#define IWL_DL_WEP           (1 << 22)
+#define IWL_DL_TX            (1 << 23)
+#define IWL_DL_RX            (1 << 24)
+#define IWL_DL_ISR           (1 << 25)
+#define IWL_DL_HT            (1 << 26)
+#define IWL_DL_IO            (1 << 27)
+#define IWL_DL_11H           (1 << 28)
+
+#define IWL_DL_STATS         (1 << 29)
+#define IWL_DL_TX_REPLY      (1 << 30)
+#define IWL_DL_QOS           (1 << 31)
+
+#define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
+#define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
+#define IWL_DEBUG_INFO(f, a...)    IWL_DEBUG(IWL_DL_INFO, f, ## a)
+
+#define IWL_DEBUG_MAC80211(f, a...)     IWL_DEBUG(IWL_DL_MAC80211, f, ## a)
+#define IWL_DEBUG_TEMP(f, a...)   IWL_DEBUG(IWL_DL_TEMP, f, ## a)
+#define IWL_DEBUG_SCAN(f, a...)   IWL_DEBUG(IWL_DL_SCAN, f, ## a)
+#define IWL_DEBUG_RX(f, a...)     IWL_DEBUG(IWL_DL_RX, f, ## a)
+#define IWL_DEBUG_TX(f, a...)     IWL_DEBUG(IWL_DL_TX, f, ## a)
+#define IWL_DEBUG_ISR(f, a...)    IWL_DEBUG(IWL_DL_ISR, f, ## a)
+#define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a)
+#define IWL_DEBUG_WEP(f, a...)    IWL_DEBUG(IWL_DL_WEP, f, ## a)
+#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a)
+#define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a)
+#define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a)
+#define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a)
+#define IWL_DEBUG_DROP(f, a...) IWL_DEBUG(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_DROP_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_AP(f, a...) IWL_DEBUG(IWL_DL_AP, f, ## a)
+#define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a)
+#define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a)
+#define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_RATE_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a)
+#define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_ASSOC_LIMIT(f, a...) \
+	IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a)
+#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
+#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
+#define IWL_DEBUG_QOS(f, a...)   IWL_DEBUG(IWL_DL_QOS, f, ## a)
+#define IWL_DEBUG_RADIO(f, a...)  IWL_DEBUG(IWL_DL_RADIO, f, ## a)
+#define IWL_DEBUG_POWER(f, a...)  IWL_DEBUG(IWL_DL_POWER, f, ## a)
+#define IWL_DEBUG_11H(f, a...)  IWL_DEBUG(IWL_DL_11H, f, ## a)
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index 99a19ef4c743..ff71c09ab1a7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -8,7 +8,7 @@
  * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU Geeral Public License as
+ * it under the terms of version 2 of the GNU General Public License as
  * published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful, but
@@ -60,48 +60,618 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *****************************************************************************/
+/*
+ * Please use this file (iwl-4965-hw.h) only for hardware-related definitions.
+ * Use iwl-4965-commands.h for uCode API definitions.
+ * Use iwl-4965.h for driver implementation definitions.
+ */
 
 #ifndef __iwl_4965_hw_h__
 #define __iwl_4965_hw_h__
 
-#define IWL_RX_BUF_SIZE (4 * 1024)
-#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE
+/*
+ * uCode queue management definitions ...
+ * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4.
+ * The first queue used for block-ack aggregation is #7 (4965 only).
+ * All block-ack aggregation queues should map to Tx DMA/FIFO channel 7.
+ */
+#define IWL_CMD_QUEUE_NUM       4
+#define IWL_CMD_FIFO_NUM        4
+#define IWL_BACK_QUEUE_FIRST_ID 7
+
+/* Tx rates */
+#define IWL_CCK_RATES 4
+#define IWL_OFDM_RATES 8
+#define IWL_HT_RATES 16
+#define IWL_MAX_RATES  (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
+
+/* Time constants */
+#define SHORT_SLOT_TIME 9
+#define LONG_SLOT_TIME 20
+
+/* RSSI to dBm */
+#define IWL_RSSI_OFFSET	44
+
+/*
+ * EEPROM related constants, enums, and structures.
+ */
+
+/*
+ * EEPROM access time values:
+ *
+ * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG,
+ *   then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit
+ *   CSR_EEPROM_REG_BIT_CMD (0x2).
+ * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1).
+ * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec.
+ * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG.
+ */
+#define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
+#define IWL_EEPROM_ACCESS_DELAY		10   /* uSec */
+
+/*
+ * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags.
+ *
+ * IBSS and/or AP operation is allowed *only* on those channels with
+ * (VALID && IBSS && ACTIVE && !RADAR).  This restriction is in place because
+ * RADAR detection is not supported by the 4965 driver, but is a
+ * requirement for establishing a new network for legal operation on channels
+ * requiring RADAR detection or restricting ACTIVE scanning.
+ *
+ * NOTE:  "WIDE" flag does not indicate anything about "FAT" 40 MHz channels.
+ *        It only indicates that 20 MHz channel use is supported; FAT channel
+ *        usage is indicated by a separate set of regulatory flags for each
+ *        FAT channel pair.
+ *
+ * NOTE:  Using a channel inappropriately will result in a uCode error!
+ */
+enum {
+	EEPROM_CHANNEL_VALID = (1 << 0),	/* usable for this SKU/geo */
+	EEPROM_CHANNEL_IBSS = (1 << 1),		/* usable as an IBSS channel */
+	/* Bit 2 Reserved */
+	EEPROM_CHANNEL_ACTIVE = (1 << 3),	/* active scanning allowed */
+	EEPROM_CHANNEL_RADAR = (1 << 4),	/* radar detection required */
+	EEPROM_CHANNEL_WIDE = (1 << 5),		/* 20 MHz channel okay */
+	EEPROM_CHANNEL_NARROW = (1 << 6),	/* 10 MHz channel (not used) */
+	EEPROM_CHANNEL_DFS = (1 << 7),	/* dynamic freq selection candidate */
+};
+
+/* SKU Capabilities */
+#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE                (1 << 0)
+#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE                (1 << 1)
+
+/* *regulatory* channel data format in eeprom, one for each channel.
+ * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */
+struct iwl4965_eeprom_channel {
+	u8 flags;		/* EEPROM_CHANNEL_* flags copied from EEPROM */
+	s8 max_power_avg;	/* max power (dBm) on this chnl, limit 31 */
+} __attribute__ ((packed));
+
+/* 4965 has two radio transmitters (and 3 radio receivers) */
+#define EEPROM_TX_POWER_TX_CHAINS      (2)
+
+/* 4965 has room for up to 8 sets of txpower calibration data */
+#define EEPROM_TX_POWER_BANDS          (8)
+
+/* 4965 factory calibration measures txpower gain settings for
+ * each of 3 target output levels */
+#define EEPROM_TX_POWER_MEASUREMENTS   (3)
+
+/* 4965 driver does not work with txpower calibration version < 5.
+ * Look for this in calib_version member of struct iwl4965_eeprom. */
+#define EEPROM_TX_POWER_VERSION_NEW    (5)
+
+
+/*
+ * 4965 factory calibration data for one txpower level, on one channel,
+ * measured on one of the 2 tx chains (radio transmitter and associated
+ * antenna).  EEPROM contains:
+ *
+ * 1)  Temperature (degrees Celsius) of device when measurement was made.
+ *
+ * 2)  Gain table index used to achieve the target measurement power.
+ *     This refers to the "well-known" gain tables (see iwl-4965-hw.h).
+ *
+ * 3)  Actual measured output power, in half-dBm ("34" = 17 dBm).
+ *
+ * 4)  RF power amplifier detector level measurement (not used).
+ */
+struct iwl4965_eeprom_calib_measure {
+	u8 temperature;		/* Device temperature (Celsius) */
+	u8 gain_idx;		/* Index into gain table */
+	u8 actual_pow;		/* Measured RF output power, half-dBm */
+	s8 pa_det;		/* Power amp detector level (not used) */
+} __attribute__ ((packed));
+
+
+/*
+ * 4965 measurement set for one channel.  EEPROM contains:
+ *
+ * 1)  Channel number measured
+ *
+ * 2)  Measurements for each of 3 power levels for each of 2 radio transmitters
+ *     (a.k.a. "tx chains") (6 measurements altogether)
+ */
+struct iwl4965_eeprom_calib_ch_info {
+	u8 ch_num;
+	struct iwl4965_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS]
+		[EEPROM_TX_POWER_MEASUREMENTS];
+} __attribute__ ((packed));
+
+/*
+ * 4965 txpower subband info.
+ *
+ * For each frequency subband, EEPROM contains the following:
+ *
+ * 1)  First and last channels within range of the subband.  "0" values
+ *     indicate that this sample set is not being used.
+ *
+ * 2)  Sample measurement sets for 2 channels close to the range endpoints.
+ */
+struct iwl4965_eeprom_calib_subband_info {
+	u8 ch_from;	/* channel number of lowest channel in subband */
+	u8 ch_to;	/* channel number of highest channel in subband */
+	struct iwl4965_eeprom_calib_ch_info ch1;
+	struct iwl4965_eeprom_calib_ch_info ch2;
+} __attribute__ ((packed));
+
+
+/*
+ * 4965 txpower calibration info.  EEPROM contains:
+ *
+ * 1)  Factory-measured saturation power levels (maximum levels at which
+ *     tx power amplifier can output a signal without too much distortion).
+ *     There is one level for 2.4 GHz band and one for 5 GHz band.  These
+ *     values apply to all channels within each of the bands.
+ *
+ * 2)  Factory-measured power supply voltage level.  This is assumed to be
+ *     constant (i.e. same value applies to all channels/bands) while the
+ *     factory measurements are being made.
+ *
+ * 3)  Up to 8 sets of factory-measured txpower calibration values.
+ *     These are for different frequency ranges, since txpower gain
+ *     characteristics of the analog radio circuitry vary with frequency.
+ *
+ *     Not all sets need to be filled with data;
+ *     struct iwl4965_eeprom_calib_subband_info contains range of channels
+ *     (0 if unused) for each set of data.
+ */
+struct iwl4965_eeprom_calib_info {
+	u8 saturation_power24;	/* half-dBm (e.g. "34" = 17 dBm) */
+	u8 saturation_power52;	/* half-dBm */
+	s16 voltage;		/* signed */
+	struct iwl4965_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS];
+} __attribute__ ((packed));
+
+
+/*
+ * 4965 EEPROM map
+ */
+struct iwl4965_eeprom {
+	u8 reserved0[16];
+#define EEPROM_DEVICE_ID                    (2*0x08)	/* 2 bytes */
+	u16 device_id;		/* abs.ofs: 16 */
+	u8 reserved1[2];
+#define EEPROM_PMC                          (2*0x0A)	/* 2 bytes */
+	u16 pmc;		/* abs.ofs: 20 */
+	u8 reserved2[20];
+#define EEPROM_MAC_ADDRESS                  (2*0x15)	/* 6  bytes */
+	u8 mac_address[6];	/* abs.ofs: 42 */
+	u8 reserved3[58];
+#define EEPROM_BOARD_REVISION               (2*0x35)	/* 2  bytes */
+	u16 board_revision;	/* abs.ofs: 106 */
+	u8 reserved4[11];
+#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1)	/* 9  bytes */
+	u8 board_pba_number[9];	/* abs.ofs: 119 */
+	u8 reserved5[8];
+#define EEPROM_VERSION                      (2*0x44)	/* 2  bytes */
+	u16 version;		/* abs.ofs: 136 */
+#define EEPROM_SKU_CAP                      (2*0x45)	/* 1  bytes */
+	u8 sku_cap;		/* abs.ofs: 138 */
+#define EEPROM_LEDS_MODE                    (2*0x45+1)	/* 1  bytes */
+	u8 leds_mode;		/* abs.ofs: 139 */
+#define EEPROM_OEM_MODE                     (2*0x46)	/* 2  bytes */
+	u16 oem_mode;
+#define EEPROM_WOWLAN_MODE                  (2*0x47)	/* 2  bytes */
+	u16 wowlan_mode;	/* abs.ofs: 142 */
+#define EEPROM_LEDS_TIME_INTERVAL           (2*0x48)	/* 2  bytes */
+	u16 leds_time_interval;	/* abs.ofs: 144 */
+#define EEPROM_LEDS_OFF_TIME                (2*0x49)	/* 1  bytes */
+	u8 leds_off_time;	/* abs.ofs: 146 */
+#define EEPROM_LEDS_ON_TIME                 (2*0x49+1)	/* 1  bytes */
+	u8 leds_on_time;	/* abs.ofs: 147 */
+#define EEPROM_ALMGOR_M_VERSION             (2*0x4A)	/* 1  bytes */
+	u8 almgor_m_version;	/* abs.ofs: 148 */
+#define EEPROM_ANTENNA_SWITCH_TYPE          (2*0x4A+1)	/* 1  bytes */
+	u8 antenna_switch_type;	/* abs.ofs: 149 */
+	u8 reserved6[8];
+#define EEPROM_4965_BOARD_REVISION          (2*0x4F)	/* 2 bytes */
+	u16 board_revision_4965;	/* abs.ofs: 158 */
+	u8 reserved7[13];
+#define EEPROM_4965_BOARD_PBA               (2*0x56+1)	/* 9 bytes */
+	u8 board_pba_number_4965[9];	/* abs.ofs: 173 */
+	u8 reserved8[10];
+#define EEPROM_REGULATORY_SKU_ID            (2*0x60)	/* 4  bytes */
+	u8 sku_id[4];		/* abs.ofs: 192 */
+
+/*
+ * Per-channel regulatory data.
+ *
+ * Each channel that *might* be supported by 3945 or 4965 has a fixed location
+ * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
+ * txpower (MSB).
+ *
+ * Entries immediately below are for 20 MHz channel width.  FAT (40 MHz)
+ * channels (only for 4965, not supported by 3945) appear later in the EEPROM.
+ *
+ * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+ */
+#define EEPROM_REGULATORY_BAND_1            (2*0x62)	/* 2  bytes */
+	u16 band_1_count;	/* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_1_CHANNELS   (2*0x63)	/* 28 bytes */
+	struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */
+
+/*
+ * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196,
+ * 5.0 GHz channels 7, 8, 11, 12, 16
+ * (4915-5080MHz) (none of these is ever supported)
+ */
+#define EEPROM_REGULATORY_BAND_2            (2*0x71)	/* 2  bytes */
+	u16 band_2_count;	/* abs.ofs: 226 */
+#define EEPROM_REGULATORY_BAND_2_CHANNELS   (2*0x72)	/* 26 bytes */
+	struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */
+
+/*
+ * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+ * (5170-5320MHz)
+ */
+#define EEPROM_REGULATORY_BAND_3            (2*0x7F)	/* 2  bytes */
+	u16 band_3_count;	/* abs.ofs: 254 */
+#define EEPROM_REGULATORY_BAND_3_CHANNELS   (2*0x80)	/* 24 bytes */
+	struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */
+
+/*
+ * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+ * (5500-5700MHz)
+ */
+#define EEPROM_REGULATORY_BAND_4            (2*0x8C)	/* 2  bytes */
+	u16 band_4_count;	/* abs.ofs: 280 */
+#define EEPROM_REGULATORY_BAND_4_CHANNELS   (2*0x8D)	/* 22 bytes */
+	struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */
+
+/*
+ * 5.7 GHz channels 145, 149, 153, 157, 161, 165
+ * (5725-5825MHz)
+ */
+#define EEPROM_REGULATORY_BAND_5            (2*0x98)	/* 2  bytes */
+	u16 band_5_count;	/* abs.ofs: 304 */
+#define EEPROM_REGULATORY_BAND_5_CHANNELS   (2*0x99)	/* 12 bytes */
+	struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */
+
+	u8 reserved10[2];
+
+
+/*
+ * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
+ *
+ * The channel listed is the center of the lower 20 MHz half of the channel.
+ * The overall center frequency is actually 2 channels (10 MHz) above that,
+ * and the upper half of each FAT channel is centered 4 channels (20 MHz) away
+ * from the lower half; e.g. the upper half of FAT channel 1 is channel 5,
+ * and the overall FAT channel width centers on channel 3.
+ *
+ * NOTE:  The RXON command uses 20 MHz channel numbers to specify the
+ *        control channel to which to tune.  RXON also specifies whether the
+ *        control channel is the upper or lower half of a FAT channel.
+ *
+ * NOTE:  4965 does not support FAT channels on 2.4 GHz.
+ */
+#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0)	/* 14 bytes */
+	struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */
+	u8 reserved11[2];
+
+/*
+ * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64),
+ * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161)
+ */
+#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8)	/* 22 bytes */
+	struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */
+	u8 reserved12[6];
+
+/*
+ * 4965 driver requires txpower calibration format version 5 or greater.
+ * Driver does not work with txpower calibration version < 5.
+ * This value is simply a 16-bit number, no major/minor versions here.
+ */
+#define EEPROM_CALIB_VERSION_OFFSET            (2*0xB6)	/* 2 bytes */
+	u16 calib_version;	/* abs.ofs: 364 */
+	u8 reserved13[2];
+	u8 reserved14[96];	/* abs.ofs: 368 */
+
+/*
+ * 4965 Txpower calibration data.
+ */
+#define EEPROM_IWL_CALIB_TXPOWER_OFFSET        (2*0xE8)	/* 48  bytes */
+	struct iwl4965_eeprom_calib_info calib_info;	/* abs.ofs: 464 */
+
+	u8 reserved16[140];	/* fill out to full 1024 byte block */
+
+
+} __attribute__ ((packed));
+
+#define IWL_EEPROM_IMAGE_SIZE 1024
+
+/* End of EEPROM */
+
+#include "iwl-4965-commands.h"
+
+#define PCI_LINK_CTRL      0x0F0
+#define PCI_POWER_SOURCE   0x0C8
+#define PCI_REG_WUM8       0x0E8
+#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
+
+/*=== CSR (control and status registers) ===*/
+#define CSR_BASE    (0x000)
+
+#define CSR_SW_VER              (CSR_BASE+0x000)
+#define CSR_HW_IF_CONFIG_REG    (CSR_BASE+0x000) /* hardware interface config */
+#define CSR_INT_COALESCING      (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT                 (CSR_BASE+0x008) /* host interrupt status/ack */
+#define CSR_INT_MASK            (CSR_BASE+0x00c) /* host interrupt enable */
+#define CSR_FH_INT_STATUS       (CSR_BASE+0x010) /* busmaster int status/ack*/
+#define CSR_GPIO_IN             (CSR_BASE+0x018) /* read external chip pins */
+#define CSR_RESET               (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
+#define CSR_GP_CNTRL            (CSR_BASE+0x024)
+
+/*
+ * Hardware revision info
+ * Bit fields:
+ * 31-8:  Reserved
+ *  7-4:  Type of device:  0x0 = 4965, 0xd = 3945
+ *  3-2:  Revision step:  0 = A, 1 = B, 2 = C, 3 = D
+ *  1-0:  "Dash" value, as in A-1, etc.
+ *
+ * NOTE:  Revision step affects calculation of CCK txpower for 4965.
+ */
+#define CSR_HW_REV              (CSR_BASE+0x028)
+
+/* EEPROM reads */
+#define CSR_EEPROM_REG          (CSR_BASE+0x02c)
+#define CSR_EEPROM_GP           (CSR_BASE+0x030)
+#define CSR_GP_UCODE		(CSR_BASE+0x044)
+#define CSR_UCODE_DRV_GP1       (CSR_BASE+0x054)
+#define CSR_UCODE_DRV_GP1_SET   (CSR_BASE+0x058)
+#define CSR_UCODE_DRV_GP1_CLR   (CSR_BASE+0x05c)
+#define CSR_UCODE_DRV_GP2       (CSR_BASE+0x060)
+#define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
+
+/*
+ * Indicates hardware rev, to determine CCK backoff for txpower calculation.
+ * Bit fields:
+ *  3-2:  0 = A, 1 = B, 2 = C, 3 = D step
+ */
+#define CSR_HW_REV_WA_REG	(CSR_BASE+0x22C)
+
+/* Hardware interface configuration bits */
+#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R	(0x00000010)
+#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER	(0x00000C00)
+#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI		(0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI	(0x00000200)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
+
+/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
+ * acknowledged (reset) by host writing "1" to flagged bits. */
+#define CSR_INT_BIT_FH_RX        (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */
+#define CSR_INT_BIT_HW_ERR       (1 << 29) /* DMA hardware error FH_INT[31] */
+#define CSR_INT_BIT_DNLD         (1 << 28) /* uCode Download */
+#define CSR_INT_BIT_FH_TX        (1 << 27) /* Tx DMA FH_INT[1:0] */
+#define CSR_INT_BIT_MAC_CLK_ACTV (1 << 26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SW_ERR       (1 << 25) /* uCode error */
+#define CSR_INT_BIT_RF_KILL      (1 << 7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
+#define CSR_INT_BIT_CT_KILL      (1 << 6)  /* Critical temp (chip too hot) rfkill */
+#define CSR_INT_BIT_SW_RX        (1 << 3)  /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_WAKEUP       (1 << 1)  /* NIC controller waking up (pwr mgmt) */
+#define CSR_INT_BIT_ALIVE        (1 << 0)  /* uCode interrupts once it initializes */
+
+#define CSR_INI_SET_MASK	(CSR_INT_BIT_FH_RX   | \
+				 CSR_INT_BIT_HW_ERR  | \
+				 CSR_INT_BIT_FH_TX   | \
+				 CSR_INT_BIT_SW_ERR  | \
+				 CSR_INT_BIT_RF_KILL | \
+				 CSR_INT_BIT_SW_RX   | \
+				 CSR_INT_BIT_WAKEUP  | \
+				 CSR_INT_BIT_ALIVE)
+
+/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
+#define CSR_FH_INT_BIT_ERR       (1 << 31) /* Error */
+#define CSR_FH_INT_BIT_HI_PRIOR  (1 << 30) /* High priority Rx, bypass coalescing */
+#define CSR_FH_INT_BIT_RX_CHNL1  (1 << 17) /* Rx channel 1 */
+#define CSR_FH_INT_BIT_RX_CHNL0  (1 << 16) /* Rx channel 0 */
+#define CSR_FH_INT_BIT_TX_CHNL1  (1 << 1)  /* Tx channel 1 */
+#define CSR_FH_INT_BIT_TX_CHNL0  (1 << 0)  /* Tx channel 0 */
+
+#define CSR_FH_INT_RX_MASK	(CSR_FH_INT_BIT_HI_PRIOR | \
+				 CSR_FH_INT_BIT_RX_CHNL1 | \
+				 CSR_FH_INT_BIT_RX_CHNL0)
+
+#define CSR_FH_INT_TX_MASK	(CSR_FH_INT_BIT_TX_CHNL1 | \
+				 CSR_FH_INT_BIT_TX_CHNL0)
+
+
+/* RESET */
+#define CSR_RESET_REG_FLAG_NEVO_RESET                (0x00000001)
+#define CSR_RESET_REG_FLAG_FORCE_NMI                 (0x00000002)
+#define CSR_RESET_REG_FLAG_SW_RESET                  (0x00000080)
+#define CSR_RESET_REG_FLAG_MASTER_DISABLED           (0x00000100)
+#define CSR_RESET_REG_FLAG_STOP_MASTER               (0x00000200)
+
+/* GP (general purpose) CONTROL */
+#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY        (0x00000001)
+#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE              (0x00000004)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ         (0x00000008)
+#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP         (0x00000010)
+
+#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN           (0x00000001)
+
+#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE         (0x07000000)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE         (0x04000000)
+#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW          (0x08000000)
+
+
+/* EEPROM REG */
+#define CSR_EEPROM_REG_READ_VALID_MSK	(0x00000001)
+#define CSR_EEPROM_REG_BIT_CMD		(0x00000002)
+
+/* EEPROM GP */
+#define CSR_EEPROM_GP_VALID_MSK		(0x00000006)
+#define CSR_EEPROM_GP_BAD_SIGNATURE	(0x00000000)
+#define CSR_EEPROM_GP_IF_OWNER_MSK	(0x00000180)
+
+/* UCODE DRV GP */
+#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP             (0x00000001)
+#define CSR_UCODE_SW_BIT_RFKILL                     (0x00000002)
+#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED           (0x00000004)
+#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT      (0x00000008)
+
+/* GPIO */
+#define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
+#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC                (0x00000000)
+#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC		CSR_GPIO_IN_BIT_AUX_POWER
+
+/* GI Chicken Bits */
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER  (0x20000000)
+
+/*=== HBUS (Host-side Bus) ===*/
+#define HBUS_BASE	(0x400)
+
+/*
+ * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM
+ * structures, error log, event log, verifying uCode load).
+ * First write to address register, then read from or write to data register
+ * to complete the job.  Once the address register is set up, accesses to
+ * data registers auto-increment the address by one dword.
+ * Bit usage for address registers (read or write):
+ *  0-31:  memory address within device
+ */
+#define HBUS_TARG_MEM_RADDR     (HBUS_BASE+0x00c)
+#define HBUS_TARG_MEM_WADDR     (HBUS_BASE+0x010)
+#define HBUS_TARG_MEM_WDAT      (HBUS_BASE+0x018)
+#define HBUS_TARG_MEM_RDAT      (HBUS_BASE+0x01c)
+
+/*
+ * Registers for accessing device's internal peripheral registers
+ * (e.g. SCD, BSM, etc.).  First write to address register,
+ * then read from or write to data register to complete the job.
+ * Bit usage for address registers (read or write):
+ *  0-15:  register address (offset) within device
+ * 24-25:  (# bytes - 1) to read or write (e.g. 3 for dword)
+ */
+#define HBUS_TARG_PRPH_WADDR    (HBUS_BASE+0x044)
+#define HBUS_TARG_PRPH_RADDR    (HBUS_BASE+0x048)
+#define HBUS_TARG_PRPH_WDAT     (HBUS_BASE+0x04c)
+#define HBUS_TARG_PRPH_RDAT     (HBUS_BASE+0x050)
+
+/*
+ * Per-Tx-queue write pointer (index, really!) (3945 and 4965).
+ * Driver sets this to indicate index to next TFD that driver will fill
+ * (1 past latest filled).
+ * Bit usage:
+ *  0-7:  queue write index (0-255)
+ * 11-8:  queue selector (0-15)
+ */
+#define HBUS_TARG_WRPTR         (HBUS_BASE+0x060)
+
+#define HBUS_TARG_MBX_C         (HBUS_BASE+0x030)
+
+#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED         (0x00000004)
+
+#define TFD_QUEUE_SIZE_MAX      (256)
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+#define IWL_DEFAULT_TX_RETRY  15
+
+#define RX_QUEUE_SIZE                         256
+#define RX_QUEUE_MASK                         255
+#define RX_QUEUE_SIZE_LOG                     8
+
+#define TFD_TX_CMD_SLOTS 256
+#define TFD_CMD_SLOTS 32
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl4965_cmd) - \
+			      sizeof(struct iwl4965_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+/* Size of one Rx buffer in host DRAM */
+#define IWL_RX_BUF_SIZE_4K (4 * 1024)
+#define IWL_RX_BUF_SIZE_8K (8 * 1024)
+
+/* Sizes and addresses for instruction and data memory (SRAM) in
+ * 4965's embedded processor.  Driver access is via HBUS_TARG_MEM_* regs. */
+#define RTC_INST_LOWER_BOUND			(0x000000)
 #define KDR_RTC_INST_UPPER_BOUND		(0x018000)
+
+#define RTC_DATA_LOWER_BOUND			(0x800000)
 #define KDR_RTC_DATA_UPPER_BOUND		(0x80A000)
+
 #define KDR_RTC_INST_SIZE    (KDR_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
 #define KDR_RTC_DATA_SIZE    (KDR_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
 
 #define IWL_MAX_INST_SIZE KDR_RTC_INST_SIZE
 #define IWL_MAX_DATA_SIZE KDR_RTC_DATA_SIZE
 
-static inline int iwl_hw_valid_rtc_data_addr(u32 addr)
+/* Size of uCode instruction memory in bootstrap state machine */
+#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE
+
+static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr)
 {
 	return (addr >= RTC_DATA_LOWER_BOUND) &&
 	       (addr < KDR_RTC_DATA_UPPER_BOUND);
 }
 
-/********************* START TXPOWER *****************************************/
-enum {
-	HT_IE_EXT_CHANNEL_NONE = 0,
-	HT_IE_EXT_CHANNEL_ABOVE,
-	HT_IE_EXT_CHANNEL_INVALID,
-	HT_IE_EXT_CHANNEL_BELOW,
-	HT_IE_EXT_CHANNEL_MAX
-};
-
-enum {
-	CALIB_CH_GROUP_1 = 0,
-	CALIB_CH_GROUP_2 = 1,
-	CALIB_CH_GROUP_3 = 2,
-	CALIB_CH_GROUP_4 = 3,
-	CALIB_CH_GROUP_5 = 4,
-	CALIB_CH_GROUP_MAX
-};
+/********************* START TEMPERATURE *************************************/
 
-/* Temperature calibration offset is 3% 0C in Kelvin */
+/**
+ * 4965 temperature calculation.
+ *
+ * The driver must calculate the device temperature before calculating
+ * a txpower setting (amplifier gain is temperature dependent).  The
+ * calculation uses 4 measurements, 3 of which (R1, R2, R3) are calibration
+ * values used for the life of the driver, and one of which (R4) is the
+ * real-time temperature indicator.
+ *
+ * uCode provides all 4 values to the driver via the "initialize alive"
+ * notification (see struct iwl4965_init_alive_resp).  After the runtime uCode
+ * image loads, uCode updates the R4 value via statistics notifications
+ * (see STATISTICS_NOTIFICATION), which occur after each received beacon
+ * when associated, or can be requested via REPLY_STATISTICS_CMD.
+ *
+ * NOTE:  uCode provides the R4 value as a 23-bit signed value.  Driver
+ *        must sign-extend to 32 bits before applying formula below.
+ *
+ * Formula:
+ *
+ * degrees Kelvin = ((97 * 259 * (R4 - R2) / (R3 - R1)) / 100) + 8
+ *
+ * NOTE:  The basic formula is 259 * (R4-R2) / (R3-R1).  The 97/100 is
+ * an additional correction, which should be centered around 0 degrees
+ * Celsius (273 degrees Kelvin).  The 8 (3 percent of 273) compensates for
+ * centering the 97/100 correction around 0 degrees K.
+ *
+ * Add 273 to Kelvin value to find degrees Celsius, for comparing current
+ * temperature with factory-measured temperatures when calculating txpower
+ * settings.
+ */
 #define TEMPERATURE_CALIB_KELVIN_OFFSET 8
 #define TEMPERATURE_CALIB_A_VAL 259
 
+/* Limit range of calculated temperature to be between these Kelvin values */
 #define IWL_TX_POWER_TEMPERATURE_MIN  (263)
 #define IWL_TX_POWER_TEMPERATURE_MAX  (410)
 
@@ -109,228 +679,875 @@ enum {
 	(((t) < IWL_TX_POWER_TEMPERATURE_MIN) || \
 	 ((t) > IWL_TX_POWER_TEMPERATURE_MAX))
 
-#define IWL_TX_POWER_ILLEGAL_TEMPERATURE (300)
+/********************* END TEMPERATURE ***************************************/
 
-#define IWL_TX_POWER_TEMPERATURE_DIFFERENCE (2)
+/********************* START TXPOWER *****************************************/
 
-#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6)
+/**
+ * 4965 txpower calculations rely on information from three sources:
+ *
+ *     1) EEPROM
+ *     2) "initialize" alive notification
+ *     3) statistics notifications
+ *
+ * EEPROM data consists of:
+ *
+ * 1)  Regulatory information (max txpower and channel usage flags) is provided
+ *     separately for each channel that can possibly supported by 4965.
+ *     40 MHz wide (.11n fat) channels are listed separately from 20 MHz
+ *     (legacy) channels.
+ *
+ *     See struct iwl4965_eeprom_channel for format, and struct iwl4965_eeprom
+ *     for locations in EEPROM.
+ *
+ * 2)  Factory txpower calibration information is provided separately for
+ *     sub-bands of contiguous channels.  2.4GHz has just one sub-band,
+ *     but 5 GHz has several sub-bands.
+ *
+ *     In addition, per-band (2.4 and 5 Ghz) saturation txpowers are provided.
+ *
+ *     See struct iwl4965_eeprom_calib_info (and the tree of structures
+ *     contained within it) for format, and struct iwl4965_eeprom for
+ *     locations in EEPROM.
+ *
+ * "Initialization alive" notification (see struct iwl4965_init_alive_resp)
+ * consists of:
+ *
+ * 1)  Temperature calculation parameters.
+ *
+ * 2)  Power supply voltage measurement.
+ *
+ * 3)  Tx gain compensation to balance 2 transmitters for MIMO use.
+ *
+ * Statistics notifications deliver:
+ *
+ * 1)  Current values for temperature param R4.
+ */
+
+/**
+ * To calculate a txpower setting for a given desired target txpower, channel,
+ * modulation bit rate, and transmitter chain (4965 has 2 transmitters to
+ * support MIMO and transmit diversity), driver must do the following:
+ *
+ * 1)  Compare desired txpower vs. (EEPROM) regulatory limit for this channel.
+ *     Do not exceed regulatory limit; reduce target txpower if necessary.
+ *
+ *     If setting up txpowers for MIMO rates (rate indexes 8-15, 24-31),
+ *     2 transmitters will be used simultaneously; driver must reduce the
+ *     regulatory limit by 3 dB (half-power) for each transmitter, so the
+ *     combined total output of the 2 transmitters is within regulatory limits.
+ *
+ *
+ * 2)  Compare target txpower vs. (EEPROM) saturation txpower *reduced by
+ *     backoff for this bit rate*.  Do not exceed (saturation - backoff[rate]);
+ *     reduce target txpower if necessary.
+ *
+ *     Backoff values below are in 1/2 dB units (equivalent to steps in
+ *     txpower gain tables):
+ *
+ *     OFDM 6 - 36 MBit:  10 steps (5 dB)
+ *     OFDM 48 MBit:      15 steps (7.5 dB)
+ *     OFDM 54 MBit:      17 steps (8.5 dB)
+ *     OFDM 60 MBit:      20 steps (10 dB)
+ *     CCK all rates:     10 steps (5 dB)
+ *
+ *     Backoff values apply to saturation txpower on a per-transmitter basis;
+ *     when using MIMO (2 transmitters), each transmitter uses the same
+ *     saturation level provided in EEPROM, and the same backoff values;
+ *     no reduction (such as with regulatory txpower limits) is required.
+ *
+ *     Saturation and Backoff values apply equally to 20 Mhz (legacy) channel
+ *     widths and 40 Mhz (.11n fat) channel widths; there is no separate
+ *     factory measurement for fat channels.
+ *
+ *     The result of this step is the final target txpower.  The rest of
+ *     the steps figure out the proper settings for the device to achieve
+ *     that target txpower.
+ *
+ *
+ * 3)  Determine (EEPROM) calibration subband for the target channel, by
+ *     comparing against first and last channels in each subband
+ *     (see struct iwl4965_eeprom_calib_subband_info).
+ *
+ *
+ * 4)  Linearly interpolate (EEPROM) factory calibration measurement sets,
+ *     referencing the 2 factory-measured (sample) channels within the subband.
+ *
+ *     Interpolation is based on difference between target channel's frequency
+ *     and the sample channels' frequencies.  Since channel numbers are based
+ *     on frequency (5 MHz between each channel number), this is equivalent
+ *     to interpolating based on channel number differences.
+ *
+ *     Note that the sample channels may or may not be the channels at the
+ *     edges of the subband.  The target channel may be "outside" of the
+ *     span of the sampled channels.
+ *
+ *     Driver may choose the pair (for 2 Tx chains) of measurements (see
+ *     struct iwl4965_eeprom_calib_ch_info) for which the actual measured
+ *     txpower comes closest to the desired txpower.  Usually, though,
+ *     the middle set of measurements is closest to the regulatory limits,
+ *     and is therefore a good choice for all txpower calculations (this
+ *     assumes that high accuracy is needed for maximizing legal txpower,
+ *     while lower txpower configurations do not need as much accuracy).
+ *
+ *     Driver should interpolate both members of the chosen measurement pair,
+ *     i.e. for both Tx chains (radio transmitters), unless the driver knows
+ *     that only one of the chains will be used (e.g. only one tx antenna
+ *     connected, but this should be unusual).  The rate scaling algorithm
+ *     switches antennas to find best performance, so both Tx chains will
+ *     be used (although only one at a time) even for non-MIMO transmissions.
+ *
+ *     Driver should interpolate factory values for temperature, gain table
+ *     index, and actual power.  The power amplifier detector values are
+ *     not used by the driver.
+ *
+ *     Sanity check:  If the target channel happens to be one of the sample
+ *     channels, the results should agree with the sample channel's
+ *     measurements!
+ *
+ *
+ * 5)  Find difference between desired txpower and (interpolated)
+ *     factory-measured txpower.  Using (interpolated) factory gain table index
+ *     (shown elsewhere) as a starting point, adjust this index lower to
+ *     increase txpower, or higher to decrease txpower, until the target
+ *     txpower is reached.  Each step in the gain table is 1/2 dB.
+ *
+ *     For example, if factory measured txpower is 16 dBm, and target txpower
+ *     is 13 dBm, add 6 steps to the factory gain index to reduce txpower
+ *     by 3 dB.
+ *
+ *
+ * 6)  Find difference between current device temperature and (interpolated)
+ *     factory-measured temperature for sub-band.  Factory values are in
+ *     degrees Celsius.  To calculate current temperature, see comments for
+ *     "4965 temperature calculation".
+ *
+ *     If current temperature is higher than factory temperature, driver must
+ *     increase gain (lower gain table index), and vice versa.
+ *
+ *     Temperature affects gain differently for different channels:
+ *
+ *     2.4 GHz all channels:  3.5 degrees per half-dB step
+ *     5 GHz channels 34-43:  4.5 degrees per half-dB step
+ *     5 GHz channels >= 44:  4.0 degrees per half-dB step
+ *
+ *     NOTE:  Temperature can increase rapidly when transmitting, especially
+ *            with heavy traffic at high txpowers.  Driver should update
+ *            temperature calculations often under these conditions to
+ *            maintain strong txpower in the face of rising temperature.
+ *
+ *
+ * 7)  Find difference between current power supply voltage indicator
+ *     (from "initialize alive") and factory-measured power supply voltage
+ *     indicator (EEPROM).
+ *
+ *     If the current voltage is higher (indicator is lower) than factory
+ *     voltage, gain should be reduced (gain table index increased) by:
+ *
+ *     (eeprom - current) / 7
+ *
+ *     If the current voltage is lower (indicator is higher) than factory
+ *     voltage, gain should be increased (gain table index decreased) by:
+ *
+ *     2 * (current - eeprom) / 7
+ *
+ *     If number of index steps in either direction turns out to be > 2,
+ *     something is wrong ... just use 0.
+ *
+ *     NOTE:  Voltage compensation is independent of band/channel.
+ *
+ *     NOTE:  "Initialize" uCode measures current voltage, which is assumed
+ *            to be constant after this initial measurement.  Voltage
+ *            compensation for txpower (number of steps in gain table)
+ *            may be calculated once and used until the next uCode bootload.
+ *
+ *
+ * 8)  If setting up txpowers for MIMO rates (rate indexes 8-15, 24-31),
+ *     adjust txpower for each transmitter chain, so txpower is balanced
+ *     between the two chains.  There are 5 pairs of tx_atten[group][chain]
+ *     values in "initialize alive", one pair for each of 5 channel ranges:
+ *
+ *     Group 0:  5 GHz channel 34-43
+ *     Group 1:  5 GHz channel 44-70
+ *     Group 2:  5 GHz channel 71-124
+ *     Group 3:  5 GHz channel 125-200
+ *     Group 4:  2.4 GHz all channels
+ *
+ *     Add the tx_atten[group][chain] value to the index for the target chain.
+ *     The values are signed, but are in pairs of 0 and a non-negative number,
+ *     so as to reduce gain (if necessary) of the "hotter" channel.  This
+ *     avoids any need to double-check for regulatory compliance after
+ *     this step.
+ *
+ *
+ * 9)  If setting up for a CCK rate, lower the gain by adding a CCK compensation
+ *     value to the index:
+ *
+ *     Hardware rev B:  9 steps (4.5 dB)
+ *     Hardware rev C:  5 steps (2.5 dB)
+ *
+ *     Hardware rev for 4965 can be determined by reading CSR_HW_REV_WA_REG,
+ *     bits [3:2], 1 = B, 2 = C.
+ *
+ *     NOTE:  This compensation is in addition to any saturation backoff that
+ *            might have been applied in an earlier step.
+ *
+ *
+ * 10) Select the gain table, based on band (2.4 vs 5 GHz).
+ *
+ *     Limit the adjusted index to stay within the table!
+ *
+ *
+ * 11) Read gain table entries for DSP and radio gain, place into appropriate
+ *     location(s) in command (struct iwl4965_txpowertable_cmd).
+ */
 
+/* Limit range of txpower output target to be between these values */
 #define IWL_TX_POWER_TARGET_POWER_MIN       (0)	/* 0 dBm = 1 milliwatt */
 #define IWL_TX_POWER_TARGET_POWER_MAX      (16)	/* 16 dBm */
 
-/* timeout equivalent to 3 minutes */
-#define IWL_TX_POWER_TIMELIMIT_NOCALIB 1800000000
-
-#define IWL_TX_POWER_CCK_COMPENSATION (9)
-
-#define MIN_TX_GAIN_INDEX		(0)
-#define MIN_TX_GAIN_INDEX_52GHZ_EXT	(-9)
-#define MAX_TX_GAIN_INDEX_52GHZ		(98)
-#define MIN_TX_GAIN_52GHZ		(98)
-#define MAX_TX_GAIN_INDEX_24GHZ		(98)
-#define MIN_TX_GAIN_24GHZ		(98)
-#define MAX_TX_GAIN			(0)
-#define MAX_TX_GAIN_52GHZ_EXT		(-9)
+/**
+ * When MIMO is used (2 transmitters operating simultaneously), driver should
+ * limit each transmitter to deliver a max of 3 dB below the regulatory limit
+ * for the device.  That is, use half power for each transmitter, so total
+ * txpower is within regulatory limits.
+ *
+ * The value "6" represents number of steps in gain table to reduce power 3 dB.
+ * Each step is 1/2 dB.
+ */
+#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6)
 
+/**
+ * CCK gain compensation.
+ *
+ * When calculating txpowers for CCK, after making sure that the target power
+ * is within regulatory and saturation limits, driver must additionally
+ * back off gain by adding these values to the gain table index.
+ *
+ * Hardware rev for 4965 can be determined by reading CSR_HW_REV_WA_REG,
+ * bits [3:2], 1 = B, 2 = C.
+ */
+#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9)
+#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5)
+
+/*
+ * 4965 power supply voltage compensation for txpower
+ */
+#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V   (7)
+
+/**
+ * Gain tables.
+ *
+ * The following tables contain pair of values for setting txpower, i.e.
+ * gain settings for the output of the device's digital signal processor (DSP),
+ * and for the analog gain structure of the transmitter.
+ *
+ * Each entry in the gain tables represents a step of 1/2 dB.  Note that these
+ * are *relative* steps, not indications of absolute output power.  Output
+ * power varies with temperature, voltage, and channel frequency, and also
+ * requires consideration of average power (to satisfy regulatory constraints),
+ * and peak power (to avoid distortion of the output signal).
+ *
+ * Each entry contains two values:
+ * 1)  DSP gain (or sometimes called DSP attenuation).  This is a fine-grained
+ *     linear value that multiplies the output of the digital signal processor,
+ *     before being sent to the analog radio.
+ * 2)  Radio gain.  This sets the analog gain of the radio Tx path.
+ *     It is a coarser setting, and behaves in a logarithmic (dB) fashion.
+ *
+ * EEPROM contains factory calibration data for txpower.  This maps actual
+ * measured txpower levels to gain settings in the "well known" tables
+ * below ("well-known" means here that both factory calibration *and* the
+ * driver work with the same table).
+ *
+ * There are separate tables for 2.4 GHz and 5 GHz bands.  The 5 GHz table
+ * has an extension (into negative indexes), in case the driver needs to
+ * boost power setting for high device temperatures (higher than would be
+ * present during factory calibration).  A 5 Ghz EEPROM index of "40"
+ * corresponds to the 49th entry in the table used by the driver.
+ */
+#define MIN_TX_GAIN_INDEX		(0)  /* highest gain, lowest idx, 2.4 */
+#define MIN_TX_GAIN_INDEX_52GHZ_EXT	(-9) /* highest gain, lowest idx, 5 */
+
+/**
+ * 2.4 GHz gain table
+ *
+ * Index    Dsp gain   Radio gain
+ *   0        110         0x3f      (highest gain)
+ *   1        104         0x3f
+ *   2         98         0x3f
+ *   3        110         0x3e
+ *   4        104         0x3e
+ *   5         98         0x3e
+ *   6        110         0x3d
+ *   7        104         0x3d
+ *   8         98         0x3d
+ *   9        110         0x3c
+ *  10        104         0x3c
+ *  11         98         0x3c
+ *  12        110         0x3b
+ *  13        104         0x3b
+ *  14         98         0x3b
+ *  15        110         0x3a
+ *  16        104         0x3a
+ *  17         98         0x3a
+ *  18        110         0x39
+ *  19        104         0x39
+ *  20         98         0x39
+ *  21        110         0x38
+ *  22        104         0x38
+ *  23         98         0x38
+ *  24        110         0x37
+ *  25        104         0x37
+ *  26         98         0x37
+ *  27        110         0x36
+ *  28        104         0x36
+ *  29         98         0x36
+ *  30        110         0x35
+ *  31        104         0x35
+ *  32         98         0x35
+ *  33        110         0x34
+ *  34        104         0x34
+ *  35         98         0x34
+ *  36        110         0x33
+ *  37        104         0x33
+ *  38         98         0x33
+ *  39        110         0x32
+ *  40        104         0x32
+ *  41         98         0x32
+ *  42        110         0x31
+ *  43        104         0x31
+ *  44         98         0x31
+ *  45        110         0x30
+ *  46        104         0x30
+ *  47         98         0x30
+ *  48        110          0x6
+ *  49        104          0x6
+ *  50         98          0x6
+ *  51        110          0x5
+ *  52        104          0x5
+ *  53         98          0x5
+ *  54        110          0x4
+ *  55        104          0x4
+ *  56         98          0x4
+ *  57        110          0x3
+ *  58        104          0x3
+ *  59         98          0x3
+ *  60        110          0x2
+ *  61        104          0x2
+ *  62         98          0x2
+ *  63        110          0x1
+ *  64        104          0x1
+ *  65         98          0x1
+ *  66        110          0x0
+ *  67        104          0x0
+ *  68         98          0x0
+ *  69         97            0
+ *  70         96            0
+ *  71         95            0
+ *  72         94            0
+ *  73         93            0
+ *  74         92            0
+ *  75         91            0
+ *  76         90            0
+ *  77         89            0
+ *  78         88            0
+ *  79         87            0
+ *  80         86            0
+ *  81         85            0
+ *  82         84            0
+ *  83         83            0
+ *  84         82            0
+ *  85         81            0
+ *  86         80            0
+ *  87         79            0
+ *  88         78            0
+ *  89         77            0
+ *  90         76            0
+ *  91         75            0
+ *  92         74            0
+ *  93         73            0
+ *  94         72            0
+ *  95         71            0
+ *  96         70            0
+ *  97         69            0
+ *  98         68            0
+ */
+
+/**
+ * 5 GHz gain table
+ *
+ * Index    Dsp gain   Radio gain
+ *  -9 	      123         0x3F      (highest gain)
+ *  -8 	      117         0x3F
+ *  -7        110         0x3F
+ *  -6        104         0x3F
+ *  -5         98         0x3F
+ *  -4        110         0x3E
+ *  -3        104         0x3E
+ *  -2         98         0x3E
+ *  -1        110         0x3D
+ *   0        104         0x3D
+ *   1         98         0x3D
+ *   2        110         0x3C
+ *   3        104         0x3C
+ *   4         98         0x3C
+ *   5        110         0x3B
+ *   6        104         0x3B
+ *   7         98         0x3B
+ *   8        110         0x3A
+ *   9        104         0x3A
+ *  10         98         0x3A
+ *  11        110         0x39
+ *  12        104         0x39
+ *  13         98         0x39
+ *  14        110         0x38
+ *  15        104         0x38
+ *  16         98         0x38
+ *  17        110         0x37
+ *  18        104         0x37
+ *  19         98         0x37
+ *  20        110         0x36
+ *  21        104         0x36
+ *  22         98         0x36
+ *  23        110         0x35
+ *  24        104         0x35
+ *  25         98         0x35
+ *  26        110         0x34
+ *  27        104         0x34
+ *  28         98         0x34
+ *  29        110         0x33
+ *  30        104         0x33
+ *  31         98         0x33
+ *  32        110         0x32
+ *  33        104         0x32
+ *  34         98         0x32
+ *  35        110         0x31
+ *  36        104         0x31
+ *  37         98         0x31
+ *  38        110         0x30
+ *  39        104         0x30
+ *  40         98         0x30
+ *  41        110         0x25
+ *  42        104         0x25
+ *  43         98         0x25
+ *  44        110         0x24
+ *  45        104         0x24
+ *  46         98         0x24
+ *  47        110         0x23
+ *  48        104         0x23
+ *  49         98         0x23
+ *  50        110         0x22
+ *  51        104         0x18
+ *  52         98         0x18
+ *  53        110         0x17
+ *  54        104         0x17
+ *  55         98         0x17
+ *  56        110         0x16
+ *  57        104         0x16
+ *  58         98         0x16
+ *  59        110         0x15
+ *  60        104         0x15
+ *  61         98         0x15
+ *  62        110         0x14
+ *  63        104         0x14
+ *  64         98         0x14
+ *  65        110         0x13
+ *  66        104         0x13
+ *  67         98         0x13
+ *  68        110         0x12
+ *  69        104         0x08
+ *  70         98         0x08
+ *  71        110         0x07
+ *  72        104         0x07
+ *  73         98         0x07
+ *  74        110         0x06
+ *  75        104         0x06
+ *  76         98         0x06
+ *  77        110         0x05
+ *  78        104         0x05
+ *  79         98         0x05
+ *  80        110         0x04
+ *  81        104         0x04
+ *  82         98         0x04
+ *  83        110         0x03
+ *  84        104         0x03
+ *  85         98         0x03
+ *  86        110         0x02
+ *  87        104         0x02
+ *  88         98         0x02
+ *  89        110         0x01
+ *  90        104         0x01
+ *  91         98         0x01
+ *  92        110         0x00
+ *  93        104         0x00
+ *  94         98         0x00
+ *  95         93         0x00
+ *  96         88         0x00
+ *  97         83         0x00
+ *  98         78         0x00
+ */
+
+
+/**
+ * Sanity checks and default values for EEPROM regulatory levels.
+ * If EEPROM values fall outside MIN/MAX range, use default values.
+ *
+ * Regulatory limits refer to the maximum average txpower allowed by
+ * regulatory agencies in the geographies in which the device is meant
+ * to be operated.  These limits are SKU-specific (i.e. geography-specific),
+ * and channel-specific; each channel has an individual regulatory limit
+ * listed in the EEPROM.
+ *
+ * Units are in half-dBm (i.e. "34" means 17 dBm).
+ */
 #define IWL_TX_POWER_DEFAULT_REGULATORY_24   (34)
 #define IWL_TX_POWER_DEFAULT_REGULATORY_52   (34)
 #define IWL_TX_POWER_REGULATORY_MIN          (0)
 #define IWL_TX_POWER_REGULATORY_MAX          (34)
+
+/**
+ * Sanity checks and default values for EEPROM saturation levels.
+ * If EEPROM values fall outside MIN/MAX range, use default values.
+ *
+ * Saturation is the highest level that the output power amplifier can produce
+ * without significant clipping distortion.  This is a "peak" power level.
+ * Different types of modulation (i.e. various "rates", and OFDM vs. CCK)
+ * require differing amounts of backoff, relative to their average power output,
+ * in order to avoid clipping distortion.
+ *
+ * Driver must make sure that it is violating neither the saturation limit,
+ * nor the regulatory limit, when calculating Tx power settings for various
+ * rates.
+ *
+ * Units are in half-dBm (i.e. "38" means 19 dBm).
+ */
 #define IWL_TX_POWER_DEFAULT_SATURATION_24   (38)
 #define IWL_TX_POWER_DEFAULT_SATURATION_52   (38)
 #define IWL_TX_POWER_SATURATION_MIN          (20)
 #define IWL_TX_POWER_SATURATION_MAX          (50)
 
-/* dv *0.4 = dt; so that 5 degrees temperature diff equals
- * 12.5 in voltage diff */
-#define IWL_TX_TEMPERATURE_UPDATE_LIMIT 9
-
-#define IWL_INVALID_CHANNEL                 (0xffffffff)
-#define IWL_TX_POWER_REGITRY_BIT            (2)
-
-#define MIN_IWL_TX_POWER_CALIB_DUR          (100)
-#define IWL_CCK_FROM_OFDM_POWER_DIFF        (-5)
-#define IWL_CCK_FROM_OFDM_INDEX_DIFF (9)
-
-/* Number of entries in the gain table */
-#define POWER_GAIN_NUM_ENTRIES 78
-#define TX_POW_MAX_SESSION_NUM 5
-/*  timeout equivalent to 3 minutes */
-#define TX_IWL_TIMELIMIT_NOCALIB 1800000000
-
-/* Kedron TX_CALIB_STATES */
-#define IWL_TX_CALIB_STATE_SEND_TX        0x00000001
-#define IWL_TX_CALIB_WAIT_TX_RESPONSE     0x00000002
-#define IWL_TX_CALIB_ENABLED              0x00000004
-#define IWL_TX_CALIB_XVT_ON               0x00000008
-#define IWL_TX_CALIB_TEMPERATURE_CORRECT  0x00000010
-#define IWL_TX_CALIB_WORKING_WITH_XVT     0x00000020
-#define IWL_TX_CALIB_XVT_PERIODICAL       0x00000040
-
-#define NUM_IWL_TX_CALIB_SETTINS 5	/* Number of tx correction groups */
-
-#define IWL_MIN_POWER_IN_VP_TABLE 1	/* 0.5dBm multiplied by 2 */
-#define IWL_MAX_POWER_IN_VP_TABLE 40	/* 20dBm - multiplied by 2 (because
-					 * entries are for each 0.5dBm) */
-#define IWL_STEP_IN_VP_TABLE 1	/* 0.5dB - multiplied by 2 */
-#define IWL_NUM_POINTS_IN_VPTABLE \
-	(1 + IWL_MAX_POWER_IN_VP_TABLE - IWL_MIN_POWER_IN_VP_TABLE)
-
-#define MIN_TX_GAIN_INDEX         (0)
-#define MAX_TX_GAIN_INDEX_52GHZ   (98)
-#define MIN_TX_GAIN_52GHZ         (98)
-#define MAX_TX_GAIN_INDEX_24GHZ   (98)
-#define MIN_TX_GAIN_24GHZ         (98)
-#define MAX_TX_GAIN               (0)
-
-/* First and last channels of all groups */
+/**
+ * Channel groups used for Tx Attenuation calibration (MIMO tx channel balance)
+ * and thermal Txpower calibration.
+ *
+ * When calculating txpower, driver must compensate for current device
+ * temperature; higher temperature requires higher gain.  Driver must calculate
+ * current temperature (see "4965 temperature calculation"), then compare vs.
+ * factory calibration temperature in EEPROM; if current temperature is higher
+ * than factory temperature, driver must *increase* gain by proportions shown
+ * in table below.  If current temperature is lower than factory, driver must
+ * *decrease* gain.
+ *
+ * Different frequency ranges require different compensation, as shown below.
+ */
+/* Group 0, 5.2 GHz ch 34-43:  4.5 degrees per 1/2 dB. */
 #define CALIB_IWL_TX_ATTEN_GR1_FCH 34
 #define CALIB_IWL_TX_ATTEN_GR1_LCH 43
+
+/* Group 1, 5.3 GHz ch 44-70:  4.0 degrees per 1/2 dB. */
 #define CALIB_IWL_TX_ATTEN_GR2_FCH 44
 #define CALIB_IWL_TX_ATTEN_GR2_LCH 70
+
+/* Group 2, 5.5 GHz ch 71-124:  4.0 degrees per 1/2 dB. */
 #define CALIB_IWL_TX_ATTEN_GR3_FCH 71
 #define CALIB_IWL_TX_ATTEN_GR3_LCH 124
+
+/* Group 3, 5.7 GHz ch 125-200:  4.0 degrees per 1/2 dB. */
 #define CALIB_IWL_TX_ATTEN_GR4_FCH 125
 #define CALIB_IWL_TX_ATTEN_GR4_LCH 200
+
+/* Group 4, 2.4 GHz all channels:  3.5 degrees per 1/2 dB. */
 #define CALIB_IWL_TX_ATTEN_GR5_FCH 1
 #define CALIB_IWL_TX_ATTEN_GR5_LCH 20
 
-
-union iwl_tx_power_dual_stream {
-	struct {
-		u8 radio_tx_gain[2];
-		u8 dsp_predis_atten[2];
-	} s;
-	u32 dw;
+enum {
+	CALIB_CH_GROUP_1 = 0,
+	CALIB_CH_GROUP_2 = 1,
+	CALIB_CH_GROUP_3 = 2,
+	CALIB_CH_GROUP_4 = 3,
+	CALIB_CH_GROUP_5 = 4,
+	CALIB_CH_GROUP_MAX
 };
 
 /********************* END TXPOWER *****************************************/
 
-/* HT flags */
-#define RXON_FLG_CTRL_CHANNEL_LOC_POS		(22)
-#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK	__constant_cpu_to_le32(0x1<<22)
-
-#define RXON_FLG_HT_OPERATING_MODE_POS		(23)
-
-#define RXON_FLG_HT_PROT_MSK			__constant_cpu_to_le32(0x1<<23)
-#define RXON_FLG_FAT_PROT_MSK			__constant_cpu_to_le32(0x2<<23)
-
-#define RXON_FLG_CHANNEL_MODE_POS		(25)
-#define RXON_FLG_CHANNEL_MODE_MSK		__constant_cpu_to_le32(0x3<<25)
-#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK	__constant_cpu_to_le32(0x1<<25)
-#define RXON_FLG_CHANNEL_MODE_MIXED_MSK		__constant_cpu_to_le32(0x2<<25)
-
-#define RXON_RX_CHAIN_DRIVER_FORCE_MSK		__constant_cpu_to_le16(0x1<<0)
-#define RXON_RX_CHAIN_VALID_MSK			__constant_cpu_to_le16(0x7<<1)
-#define RXON_RX_CHAIN_VALID_POS			(1)
-#define RXON_RX_CHAIN_FORCE_SEL_MSK		__constant_cpu_to_le16(0x7<<4)
-#define RXON_RX_CHAIN_FORCE_SEL_POS		(4)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK	__constant_cpu_to_le16(0x7<<7)
-#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS	(7)
-#define RXON_RX_CHAIN_CNT_MSK			__constant_cpu_to_le16(0x3<<10)
-#define RXON_RX_CHAIN_CNT_POS			(10)
-#define RXON_RX_CHAIN_MIMO_CNT_MSK		__constant_cpu_to_le16(0x3<<12)
-#define RXON_RX_CHAIN_MIMO_CNT_POS		(12)
-#define RXON_RX_CHAIN_MIMO_FORCE_MSK		__constant_cpu_to_le16(0x1<<14)
-#define RXON_RX_CHAIN_MIMO_FORCE_POS		(14)
-
-
-#define MCS_DUP_6M_PLCP 0x20
-
-/* OFDM HT rate masks */
-/* ***************************************** */
-#define R_MCS_6M_MSK 0x1
-#define R_MCS_12M_MSK 0x2
-#define R_MCS_18M_MSK 0x4
-#define R_MCS_24M_MSK 0x8
-#define R_MCS_36M_MSK 0x10
-#define R_MCS_48M_MSK 0x20
-#define R_MCS_54M_MSK 0x40
-#define R_MCS_60M_MSK 0x80
-#define R_MCS_12M_DUAL_MSK 0x100
-#define R_MCS_24M_DUAL_MSK 0x200
-#define R_MCS_36M_DUAL_MSK 0x400
-#define R_MCS_48M_DUAL_MSK 0x800
-
-#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
-#define is_siso(tbl) (((tbl) == LQ_SISO))
-#define is_mimo(tbl) (((tbl) == LQ_MIMO))
-#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
-#define is_a_band(tbl) (((tbl) == LQ_A))
-#define is_g_and(tbl) (((tbl) == LQ_G))
-
+/****************************/
 /* Flow Handler Definitions */
+/****************************/
 
-/**********************/
-/*     Addresses      */
-/**********************/
-
+/**
+ * This I/O area is directly read/writable by driver (e.g. Linux uses writel())
+ * Addresses are offsets from device's PCI hardware base address.
+ */
 #define FH_MEM_LOWER_BOUND                   (0x1000)
 #define FH_MEM_UPPER_BOUND                   (0x1EF0)
 
-#define IWL_FH_REGS_LOWER_BOUND		     (0x1000)
-#define IWL_FH_REGS_UPPER_BOUND		     (0x2000)
-
+/**
+ * Keep-Warm (KW) buffer base address.
+ *
+ * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the
+ * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency
+ * DRAM access when 4965 is Txing or Rxing.  The dummy accesses prevent host
+ * from going into a power-savings mode that would cause higher DRAM latency,
+ * and possible data over/under-runs, before all Tx/Rx is complete.
+ *
+ * Driver loads IWL_FH_KW_MEM_ADDR_REG with the physical address (bits 35:4)
+ * of the buffer, which must be 4K aligned.  Once this is set up, the 4965
+ * automatically invokes keep-warm accesses when normal accesses might not
+ * be sufficient to maintain fast DRAM response.
+ *
+ * Bit fields:
+ *  31-0:  Keep-warm buffer physical base address [35:4], must be 4K aligned
+ */
 #define IWL_FH_KW_MEM_ADDR_REG		     (FH_MEM_LOWER_BOUND + 0x97C)
 
-/* CBBC Area - Circular buffers base address cache pointers table */
+
+/**
+ * TFD Circular Buffers Base (CBBC) addresses
+ *
+ * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident
+ * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs)
+ * (see struct iwl_tfd_frame).  These 16 pointer registers are offset by 0x04
+ * bytes from one another.  Each TFD circular buffer in DRAM must be 256-byte
+ * aligned (address bits 0-7 must be 0).
+ *
+ * Bit fields in each pointer register:
+ *  27-0: TFD CB physical base address [35:8], must be 256-byte aligned
+ */
 #define FH_MEM_CBBC_LOWER_BOUND              (FH_MEM_LOWER_BOUND + 0x9D0)
 #define FH_MEM_CBBC_UPPER_BOUND              (FH_MEM_LOWER_BOUND + 0xA10)
-/* queues 0 - 15 */
+
+/* Find TFD CB base pointer for given queue (range 0-15). */
 #define FH_MEM_CBBC_QUEUE(x)  (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4)
 
-/* RSCSR Area */
+
+/**
+ * Rx SRAM Control and Status Registers (RSCSR)
+ *
+ * These registers provide handshake between driver and 4965 for the Rx queue
+ * (this queue handles *all* command responses, notifications, Rx data, etc.
+ * sent from 4965 uCode to host driver).  Unlike Tx, there is only one Rx
+ * queue, and only one Rx DMA/FIFO channel.  Also unlike Tx, which can
+ * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer
+ * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1
+ * mapping between RBDs and RBs.
+ *
+ * Driver must allocate host DRAM memory for the following, and set the
+ * physical address of each into 4965 registers:
+ *
+ * 1)  Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256
+ *     entries (although any power of 2, up to 4096, is selectable by driver).
+ *     Each entry (1 dword) points to a receive buffer (RB) of consistent size
+ *     (typically 4K, although 8K or 16K are also selectable by driver).
+ *     Driver sets up RB size and number of RBDs in the CB via Rx config
+ *     register FH_MEM_RCSR_CHNL0_CONFIG_REG.
+ *
+ *     Bit fields within one RBD:
+ *     27-0:  Receive Buffer physical address bits [35:8], 256-byte aligned
+ *
+ *     Driver sets physical address [35:8] of base of RBD circular buffer
+ *     into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0].
+ *
+ * 2)  Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers
+ *     (RBs) have been filled, via a "write pointer", actually the index of
+ *     the RB's corresponding RBD within the circular buffer.  Driver sets
+ *     physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0].
+ *
+ *     Bit fields in lower dword of Rx status buffer (upper dword not used
+ *     by driver; see struct iwl4965_shared, val0):
+ *     31-12:  Not used by driver
+ *     11- 0:  Index of last filled Rx buffer descriptor
+ *             (4965 writes, driver reads this value)
+ *
+ * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must
+ * enter pointers to these RBs into contiguous RBD circular buffer entries,
+ * and update the 4965's "write" index register, FH_RSCSR_CHNL0_RBDCB_WPTR_REG.
+ *
+ * This "write" index corresponds to the *next* RBD that the driver will make
+ * available, i.e. one RBD past the tail of the ready-to-fill RBDs within
+ * the circular buffer.  This value should initially be 0 (before preparing any
+ * RBs), should be 8 after preparing the first 8 RBs (for example), and must
+ * wrap back to 0 at the end of the circular buffer (but don't wrap before
+ * "read" index has advanced past 1!  See below).
+ * NOTE:  4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8.
+ *
+ * As the 4965 fills RBs (referenced from contiguous RBDs within the circular
+ * buffer), it updates the Rx status buffer in host DRAM, 2) described above,
+ * to tell the driver the index of the latest filled RBD.  The driver must
+ * read this "read" index from DRAM after receiving an Rx interrupt from 4965.
+ *
+ * The driver must also internally keep track of a third index, which is the
+ * next RBD to process.  When receiving an Rx interrupt, driver should process
+ * all filled but unprocessed RBs up to, but not including, the RB
+ * corresponding to the "read" index.  For example, if "read" index becomes "1",
+ * driver may process the RB pointed to by RBD 0.  Depending on volume of
+ * traffic, there may be many RBs to process.
+ *
+ * If read index == write index, 4965 thinks there is no room to put new data.
+ * Due to this, the maximum number of filled RBs is 255, instead of 256.  To
+ * be safe, make sure that there is a gap of at least 2 RBDs between "write"
+ * and "read" indexes; that is, make sure that there are no more than 254
+ * buffers waiting to be filled.
+ */
 #define FH_MEM_RSCSR_LOWER_BOUND	(FH_MEM_LOWER_BOUND + 0xBC0)
 #define FH_MEM_RSCSR_UPPER_BOUND	(FH_MEM_LOWER_BOUND + 0xC00)
 #define FH_MEM_RSCSR_CHNL0		(FH_MEM_RSCSR_LOWER_BOUND)
 
+/**
+ * Physical base address of 8-byte Rx Status buffer.
+ * Bit fields:
+ *  31-0: Rx status buffer physical base address [35:4], must 16-byte aligned.
+ */
 #define FH_RSCSR_CHNL0_STTS_WPTR_REG		(FH_MEM_RSCSR_CHNL0)
+
+/**
+ * Physical base address of Rx Buffer Descriptor Circular Buffer.
+ * Bit fields:
+ *  27-0:  RBD CD physical base address [35:8], must be 256-byte aligned.
+ */
 #define FH_RSCSR_CHNL0_RBDCB_BASE_REG		(FH_MEM_RSCSR_CHNL0 + 0x004)
+
+/**
+ * Rx write pointer (index, really!).
+ * Bit fields:
+ *  11-0:  Index of driver's most recent prepared-to-be-filled RBD, + 1.
+ *         NOTE:  For 256-entry circular buffer, use only bits [7:0].
+ */
 #define FH_RSCSR_CHNL0_RBDCB_WPTR_REG		(FH_MEM_RSCSR_CHNL0 + 0x008)
+#define FH_RSCSR_CHNL0_WPTR        (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
+
 
-/* RCSR Area - Registers address map */
+/**
+ * Rx Config/Status Registers (RCSR)
+ * Rx Config Reg for channel 0 (only channel used)
+ *
+ * Driver must initialize FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for
+ * normal operation (see bit fields).
+ *
+ * Clearing FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA.
+ * Driver should poll FH_MEM_RSSR_RX_STATUS_REG	for
+ * FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing.
+ *
+ * Bit fields:
+ * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame,
+ *        '10' operate normally
+ * 29-24: reserved
+ * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal),
+ *        min "5" for 32 RBDs, max "12" for 4096 RBDs.
+ * 19-18: reserved
+ * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K,
+ *        '10' 12K, '11' 16K.
+ * 15-14: reserved
+ * 13-12: IRQ destination; '00' none, '01' host driver (normal operation)
+ * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec)
+ *        typical value 0x10 (about 1/2 msec)
+ *  3- 0: reserved
+ */
 #define FH_MEM_RCSR_LOWER_BOUND      (FH_MEM_LOWER_BOUND + 0xC00)
 #define FH_MEM_RCSR_UPPER_BOUND      (FH_MEM_LOWER_BOUND + 0xCC0)
 #define FH_MEM_RCSR_CHNL0            (FH_MEM_RCSR_LOWER_BOUND)
 
 #define FH_MEM_RCSR_CHNL0_CONFIG_REG	(FH_MEM_RCSR_CHNL0)
 
-/* RSSR Area - Rx shared ctrl & status registers */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK   (0x00000FF0) /* bit 4-11 */
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK     (0x00001000) /* bit 12 */
+#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK	  (0x00030000) /* bits 16-17 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK   (0x00F00000) /* bits 20-23 */
+#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK  (0xC0000000) /* bits 30-31 */
+
+#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT	(20)
+#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT	(4)
+#define RX_RB_TIMEOUT	(0x10)
+
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL         (0x00000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL     (0x40000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL        (0x80000000)
+
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K    (0x00000000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K    (0x00010000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K   (0x00020000)
+#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K   (0x00030000)
+
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL       (0x00000000)
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL     (0x00001000)
+
+
+/**
+ * Rx Shared Status Registers (RSSR)
+ *
+ * After stopping Rx DMA channel (writing 0 to FH_MEM_RCSR_CHNL0_CONFIG_REG),
+ * driver must poll FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle.
+ *
+ * Bit fields:
+ *  24:  1 = Channel 0 is idle
+ *
+ * FH_MEM_RSSR_SHARED_CTRL_REG and FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV contain
+ * default values that should not be altered by the driver.
+ */
 #define FH_MEM_RSSR_LOWER_BOUND                	(FH_MEM_LOWER_BOUND + 0xC40)
 #define FH_MEM_RSSR_UPPER_BOUND               	(FH_MEM_LOWER_BOUND + 0xD00)
+
 #define FH_MEM_RSSR_SHARED_CTRL_REG           	(FH_MEM_RSSR_LOWER_BOUND)
 #define FH_MEM_RSSR_RX_STATUS_REG	(FH_MEM_RSSR_LOWER_BOUND + 0x004)
 #define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV  (FH_MEM_RSSR_LOWER_BOUND + 0x008)
 
-/* TCSR */
-#define IWL_FH_TCSR_LOWER_BOUND  (IWL_FH_REGS_LOWER_BOUND + 0xD00)
-#define IWL_FH_TCSR_UPPER_BOUND  (IWL_FH_REGS_LOWER_BOUND + 0xE60)
+#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE	(0x01000000)
+
 
-#define IWL_FH_TCSR_CHNL_NUM                            (7)
+/**
+ * Transmit DMA Channel Control/Status Registers (TCSR)
+ *
+ * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels
+ * supported in hardware (don't confuse these with the 16 Tx queues in DRAM,
+ * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes.
+ *
+ * To use a Tx DMA channel, driver must initialize its
+ * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with:
+ *
+ * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL
+ *
+ * All other bits should be 0.
+ *
+ * Bit fields:
+ * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame,
+ *        '10' operate normally
+ * 29- 4: Reserved, set to "0"
+ *     3: Enable internal DMA requests (1, normal operation), disable (0)
+ *  2- 0: Reserved, set to "0"
+ */
+#define IWL_FH_TCSR_LOWER_BOUND  (FH_MEM_LOWER_BOUND + 0xD00)
+#define IWL_FH_TCSR_UPPER_BOUND  (FH_MEM_LOWER_BOUND + 0xE60)
+
+/* Find Control/Status reg for given Tx DMA/FIFO channel */
 #define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
 	(IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
 
-/* TSSR Area - Tx shared status registers */
-/* TSSR */
-#define IWL_FH_TSSR_LOWER_BOUND		(IWL_FH_REGS_LOWER_BOUND + 0xEA0)
-#define IWL_FH_TSSR_UPPER_BOUND		(IWL_FH_REGS_LOWER_BOUND + 0xEC0)
-
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG	(IWL_FH_TSSR_LOWER_BOUND + 0x008)
-#define IWL_FH_TSSR_TX_STATUS_REG	(IWL_FH_TSSR_LOWER_BOUND + 0x010)
-
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON	(0xFF000000)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON	(0x00FF0000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
 
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_64B	(0x00000000)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B	(0x00000400)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_256B	(0x00000800)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_512B	(0x00000C00)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF        (0x40000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
 
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON	(0x00000100)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON	(0x00000080)
+/**
+ * Tx Shared Status Registers (TSSR)
+ *
+ * After stopping Tx DMA channel (writing 0 to
+ * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll
+ * IWL_FH_TSSR_TX_STATUS_REG until selected Tx channel is idle
+ * (channel's buffers empty | no pending requests).
+ *
+ * Bit fields:
+ * 31-24:  1 = Channel buffers empty (channel 7:0)
+ * 23-16:  1 = No pending requests (channel 7:0)
+ */
+#define IWL_FH_TSSR_LOWER_BOUND		(FH_MEM_LOWER_BOUND + 0xEA0)
+#define IWL_FH_TSSR_UPPER_BOUND		(FH_MEM_LOWER_BOUND + 0xEC0)
 
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH	(0x00000020)
-#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH		(0x00000005)
+#define IWL_FH_TSSR_TX_STATUS_REG	(IWL_FH_TSSR_LOWER_BOUND + 0x010)
 
 #define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl)	\
 	((1 << (_chnl)) << 24)
@@ -341,147 +1558,347 @@ union iwl_tx_power_dual_stream {
 	(IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
 	IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
 
-/* TCSR: tx_config register values */
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF              (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER           (0x00000001)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_ARC              (0x00000002)
-
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
-
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT           (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD          (0x00100000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
-
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT            (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD           (0x00400000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD            (0x00800000)
 
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF        (0x40000000)
-#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
-
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY          (0x00000000)
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT           (0x00002000)
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00000003)
-
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR           (0x00000001)
-
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM              (20)
-#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX              (12)
-
-/* RCSR:  channel 0 rx_config register defines */
-#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK  (0xC0000000) /* bits 30-31 */
-#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK   (0x00F00000) /* bits 20-23 */
-#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK	  (0x00030000) /* bits 16-17 */
-#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK     (0x00001000) /* bit 12 */
-#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK   (0x00000FF0) /* bit 4-11 */
-
-#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT       (20)
-#define FH_RCSR_RX_CONFIG_RB_SIZE_BITSHIFT			(16)
-
-/* RCSR: rx_config register values */
-#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL         (0x00000000)
-#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL     (0x40000000)
-#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL        (0x80000000)
-
-#define IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K    (0x00000000)
-
-/* RCSR channel 0 config register values */
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL       (0x00000000)
-#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL     (0x00001000)
-
-/* RSCSR: defs used in normal mode */
-#define FH_RSCSR_CHNL0_RBDCB_WPTR_MASK		(0x00000FFF)	/* bits 0-11 */
+/********************* START TX SCHEDULER *************************************/
 
+/**
+ * 4965 Tx Scheduler
+ *
+ * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs
+ * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in
+ * host DRAM.  It steers each frame's Tx command (which contains the frame
+ * data) into one of up to 7 prioritized Tx DMA FIFO channels within the
+ * device.  A queue maps to only one (selectable by driver) Tx DMA channel,
+ * but one DMA channel may take input from several queues.
+ *
+ * Tx DMA channels have dedicated purposes.  For 4965, they are used as follows:
+ *
+ * 0 -- EDCA BK (background) frames, lowest priority
+ * 1 -- EDCA BE (best effort) frames, normal priority
+ * 2 -- EDCA VI (video) frames, higher priority
+ * 3 -- EDCA VO (voice) and management frames, highest priority
+ * 4 -- Commands (e.g. RXON, etc.)
+ * 5 -- HCCA short frames
+ * 6 -- HCCA long frames
+ * 7 -- not used by driver (device-internal only)
+ *
+ * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6.
+ * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to
+ * support 11n aggregation via EDCA DMA channels.
+ *
+ * The driver sets up each queue to work in one of two modes:
+ *
+ * 1)  Scheduler-Ack, in which the scheduler automatically supports a
+ *     block-ack (BA) window of up to 64 TFDs.  In this mode, each queue
+ *     contains TFDs for a unique combination of Recipient Address (RA)
+ *     and Traffic Identifier (TID), that is, traffic of a given
+ *     Quality-Of-Service (QOS) priority, destined for a single station.
+ *
+ *     In scheduler-ack mode, the scheduler keeps track of the Tx status of
+ *     each frame within the BA window, including whether it's been transmitted,
+ *     and whether it's been acknowledged by the receiving station.  The device
+ *     automatically processes block-acks received from the receiving STA,
+ *     and reschedules un-acked frames to be retransmitted (successful
+ *     Tx completion may end up being out-of-order).
+ *
+ *     The driver must maintain the queue's Byte Count table in host DRAM
+ *     (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode.
+ *     This mode does not support fragmentation.
+ *
+ * 2)  FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order.
+ *     The device may automatically retry Tx, but will retry only one frame
+ *     at a time, until receiving ACK from receiving station, or reaching
+ *     retry limit and giving up.
+ *
+ *     The command queue (#4) must use this mode!
+ *     This mode does not require use of the Byte Count table in host DRAM.
+ *
+ * Driver controls scheduler operation via 3 means:
+ * 1)  Scheduler registers
+ * 2)  Shared scheduler data base in internal 4956 SRAM
+ * 3)  Shared data in host DRAM
+ *
+ * Initialization:
+ *
+ * When loading, driver should allocate memory for:
+ * 1)  16 TFD circular buffers, each with space for (typically) 256 TFDs.
+ * 2)  16 Byte Count circular buffers in 16 KBytes contiguous memory
+ *     (1024 bytes for each queue).
+ *
+ * After receiving "Alive" response from uCode, driver must initialize
+ * the scheduler (especially for queue #4, the command queue, otherwise
+ * the driver can't issue commands!):
+ */
+
+/**
+ * Max Tx window size is the max number of contiguous TFDs that the scheduler
+ * can keep track of at one time when creating block-ack chains of frames.
+ * Note that "64" matches the number of ack bits in a block-ack packet.
+ * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize
+ * SCD_CONTEXT_QUEUE_OFFSET(x) values.
+ */
 #define SCD_WIN_SIZE				64
 #define SCD_FRAME_LIMIT				64
 
-/* memory mapped registers */
+/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */
 #define SCD_START_OFFSET		0xa02c00
 
+/*
+ * 4965 tells driver SRAM address for internal scheduler structs via this reg.
+ * Value is valid only after "Alive" response from uCode.
+ */
 #define SCD_SRAM_BASE_ADDR           (SCD_START_OFFSET + 0x0)
+
+/*
+ * Driver may need to update queue-empty bits after changing queue's
+ * write and read pointers (indexes) during (re-)initialization (i.e. when
+ * scheduler is not tracking what's happening).
+ * Bit fields:
+ * 31-16:  Write mask -- 1: update empty bit, 0: don't change empty bit
+ * 15-00:  Empty state, one for each queue -- 1: empty, 0: non-empty
+ * NOTE:  This register is not used by Linux driver.
+ */
 #define SCD_EMPTY_BITS               (SCD_START_OFFSET + 0x4)
+
+/*
+ * Physical base address of array of byte count (BC) circular buffers (CBs).
+ * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode.
+ * This register points to BC CB for queue 0, must be on 1024-byte boundary.
+ * Others are spaced by 1024 bytes.
+ * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad.
+ * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff).
+ * Bit fields:
+ * 25-00:  Byte Count CB physical address [35:10], must be 1024-byte aligned.
+ */
 #define SCD_DRAM_BASE_ADDR           (SCD_START_OFFSET + 0x10)
-#define SCD_AIT                      (SCD_START_OFFSET + 0x18)
+
+/*
+ * Enables any/all Tx DMA/FIFO channels.
+ * Scheduler generates requests for only the active channels.
+ * Set this to 0xff to enable all 8 channels (normal usage).
+ * Bit fields:
+ *  7- 0:  Enable (1), disable (0), one bit for each channel 0-7
+ */
 #define SCD_TXFACT                   (SCD_START_OFFSET + 0x1c)
+
+/* Mask to enable contiguous Tx DMA/FIFO channels between "lo" and "hi". */
+#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \
+       ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
+
+/*
+ * Queue (x) Write Pointers (indexes, really!), one for each Tx queue.
+ * Initialized and updated by driver as new TFDs are added to queue.
+ * NOTE:  If using Block Ack, index must correspond to frame's
+ *        Start Sequence Number; index = (SSN & 0xff)
+ * NOTE:  Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses?
+ */
 #define SCD_QUEUE_WRPTR(x)           (SCD_START_OFFSET + 0x24 + (x) * 4)
-#define SCD_QUEUE_RDPTR(x)           (SCD_START_OFFSET + 0x64 + (x) * 4)
-#define SCD_SETQUEUENUM              (SCD_START_OFFSET + 0xa4)
-#define SCD_SET_TXSTAT_TXED          (SCD_START_OFFSET + 0xa8)
-#define SCD_SET_TXSTAT_DONE          (SCD_START_OFFSET + 0xac)
-#define SCD_SET_TXSTAT_NOT_SCHD      (SCD_START_OFFSET + 0xb0)
-#define SCD_DECREASE_CREDIT          (SCD_START_OFFSET + 0xb4)
-#define SCD_DECREASE_SCREDIT         (SCD_START_OFFSET + 0xb8)
-#define SCD_LOAD_CREDIT              (SCD_START_OFFSET + 0xbc)
-#define SCD_LOAD_SCREDIT             (SCD_START_OFFSET + 0xc0)
-#define SCD_BAR                      (SCD_START_OFFSET + 0xc4)
-#define SCD_BAR_DW0                  (SCD_START_OFFSET + 0xc8)
-#define SCD_BAR_DW1                  (SCD_START_OFFSET + 0xcc)
-#define SCD_QUEUECHAIN_SEL           (SCD_START_OFFSET + 0xd0)
-#define SCD_QUERY_REQ                (SCD_START_OFFSET + 0xd8)
-#define SCD_QUERY_RES                (SCD_START_OFFSET + 0xdc)
-#define SCD_PENDING_FRAMES           (SCD_START_OFFSET + 0xe0)
-#define SCD_INTERRUPT_MASK           (SCD_START_OFFSET + 0xe4)
-#define SCD_INTERRUPT_THRESHOLD      (SCD_START_OFFSET + 0xe8)
-#define SCD_QUERY_MIN_FRAME_SIZE     (SCD_START_OFFSET + 0x100)
-#define SCD_QUEUE_STATUS_BITS(x)     (SCD_START_OFFSET + 0x104 + (x) * 4)
 
-/* SRAM structures */
-#define SCD_CONTEXT_DATA_OFFSET			0x380
-#define SCD_TX_STTS_BITMAP_OFFSET		0x400
-#define SCD_TRANSLATE_TBL_OFFSET		0x500
-#define SCD_CONTEXT_QUEUE_OFFSET(x)	(SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
-#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
-	((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
+/*
+ * Queue (x) Read Pointers (indexes, really!), one for each Tx queue.
+ * For FIFO mode, index indicates next frame to transmit.
+ * For Scheduler-ACK mode, index indicates first frame in Tx window.
+ * Initialized by driver, updated by scheduler.
+ */
+#define SCD_QUEUE_RDPTR(x)           (SCD_START_OFFSET + 0x64 + (x) * 4)
 
-#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \
-       ((1<<(hi))|((1<<(hi))-(1<<(lo))))
+/*
+ * Select which queues work in chain mode (1) vs. not (0).
+ * Use chain mode to build chains of aggregated frames.
+ * Bit fields:
+ * 31-16:  Reserved
+ * 15-00:  Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time
+ * NOTE:  If driver sets up queue for chain mode, it should be also set up
+ *        Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x).
+ */
+#define SCD_QUEUECHAIN_SEL           (SCD_START_OFFSET + 0xd0)
 
+/*
+ * Select which queues interrupt driver when scheduler increments
+ * a queue's read pointer (index).
+ * Bit fields:
+ * 31-16:  Reserved
+ * 15-00:  Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled
+ * NOTE:  This functionality is apparently a no-op; driver relies on interrupts
+ *        from Rx queue to read Tx command responses and update Tx queues.
+ */
+#define SCD_INTERRUPT_MASK           (SCD_START_OFFSET + 0xe4)
 
-#define SCD_MODE_REG_BIT_SEARCH_MODE		(1<<0)
-#define SCD_MODE_REG_BIT_SBYP_MODE		(1<<1)
+/*
+ * Queue search status registers.  One for each queue.
+ * Sets up queue mode and assigns queue to Tx DMA channel.
+ * Bit fields:
+ * 19-10: Write mask/enable bits for bits 0-9
+ *     9: Driver should init to "0"
+ *     8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0).
+ *        Driver should init to "1" for aggregation mode, or "0" otherwise.
+ *   7-6: Driver should init to "0"
+ *     5: Window Size Left; indicates whether scheduler can request
+ *        another TFD, based on window size, etc.  Driver should init
+ *        this bit to "1" for aggregation mode, or "0" for non-agg.
+ *   4-1: Tx FIFO to use (range 0-7).
+ *     0: Queue is active (1), not active (0).
+ * Other bits should be written as "0"
+ *
+ * NOTE:  If enabling Scheduler-ACK mode, chain mode should also be enabled
+ *        via SCD_QUEUECHAIN_SEL.
+ */
+#define SCD_QUEUE_STATUS_BITS(x)     (SCD_START_OFFSET + 0x104 + (x) * 4)
 
-#define SCD_TXFIFO_POS_TID			(0)
-#define SCD_TXFIFO_POS_RA			(4)
+/* Bit field positions */
 #define SCD_QUEUE_STTS_REG_POS_ACTIVE		(0)
 #define SCD_QUEUE_STTS_REG_POS_TXF		(1)
 #define SCD_QUEUE_STTS_REG_POS_WSL		(5)
 #define SCD_QUEUE_STTS_REG_POS_SCD_ACK		(8)
+
+/* Write masks */
 #define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN	(10)
 #define SCD_QUEUE_STTS_REG_MSK			(0x0007FC00)
 
-#define SCD_QUEUE_RA_TID_MAP_RATID_MSK		(0x01FF)
+/**
+ * 4965 internal SRAM structures for scheduler, shared with driver ...
+ *
+ * Driver should clear and initialize the following areas after receiving
+ * "Alive" response from 4965 uCode, i.e. after initial
+ * uCode load, or after a uCode load done for error recovery:
+ *
+ * SCD_CONTEXT_DATA_OFFSET (size 128 bytes)
+ * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes)
+ * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes)
+ *
+ * Driver accesses SRAM via HBUS_TARG_MEM_* registers.
+ * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR.
+ * All OFFSET values must be added to this base address.
+ */
+
+/*
+ * Queue context.  One 8-byte entry for each of 16 queues.
+ *
+ * Driver should clear this entire area (size 0x80) to 0 after receiving
+ * "Alive" notification from uCode.  Additionally, driver should init
+ * each queue's entry as follows:
+ *
+ * LS Dword bit fields:
+ *  0-06:  Max Tx window size for Scheduler-ACK.  Driver should init to 64.
+ *
+ * MS Dword bit fields:
+ * 16-22:  Frame limit.  Driver should init to 10 (0xa).
+ *
+ * Driver should init all other bits to 0.
+ *
+ * Init must be done after driver receives "Alive" response from 4965 uCode,
+ * and when setting up queue for aggregation.
+ */
+#define SCD_CONTEXT_DATA_OFFSET			0x380
+#define SCD_CONTEXT_QUEUE_OFFSET(x)	(SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
 
 #define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS		(0)
 #define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK		(0x0000007F)
-#define SCD_QUEUE_CTX_REG1_CREDIT_POS		(8)
-#define SCD_QUEUE_CTX_REG1_CREDIT_MSK		(0x00FFFF00)
-#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS	(24)
-#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK	(0xFF000000)
 #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS	(16)
 #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK	(0x007F0000)
 
-#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R	(0x00000010)
-#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER	(0x00000C00)
-#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI		(0x00000100)
-#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI	(0x00000200)
+/*
+ * Tx Status Bitmap
+ *
+ * Driver should clear this entire area (size 0x100) to 0 after receiving
+ * "Alive" notification from uCode.  Area is used only by device itself;
+ * no other support (besides clearing) is required from driver.
+ */
+#define SCD_TX_STTS_BITMAP_OFFSET		0x400
 
-static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
+/*
+ * RAxTID to queue translation mapping.
+ *
+ * When queue is in Scheduler-ACK mode, frames placed in a that queue must be
+ * for only one combination of receiver address (RA) and traffic ID (TID), i.e.
+ * one QOS priority level destined for one station (for this wireless link,
+ * not final destination).  The SCD_TRANSLATE_TABLE area provides 16 16-bit
+ * mappings, one for each of the 16 queues.  If queue is not in Scheduler-ACK
+ * mode, the device ignores the mapping value.
+ *
+ * Bit fields, for each 16-bit map:
+ * 15-9:  Reserved, set to 0
+ *  8-4:  Index into device's station table for recipient station
+ *  3-0:  Traffic ID (tid), range 0-15
+ *
+ * Driver should clear this entire area (size 32 bytes) to 0 after receiving
+ * "Alive" notification from uCode.  To update a 16-bit map value, driver
+ * must read a dword-aligned value from device SRAM, replace the 16-bit map
+ * value of interest, and write the dword value back into device SRAM.
+ */
+#define SCD_TRANSLATE_TBL_OFFSET		0x500
+
+/* Find translation table dword to read/write for given queue */
+#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
+	((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
+
+#define SCD_TXFIFO_POS_TID			(0)
+#define SCD_TXFIFO_POS_RA			(4)
+#define SCD_QUEUE_RA_TID_MAP_RATID_MSK		(0x01FF)
+
+/*********************** END TX SCHEDULER *************************************/
+
+static inline u8 iwl4965_hw_get_rate(__le32 rate_n_flags)
 {
 	return le32_to_cpu(rate_n_flags) & 0xFF;
 }
-static inline u16 iwl_hw_get_rate_n_flags(__le32 rate_n_flags)
+static inline u16 iwl4965_hw_get_rate_n_flags(__le32 rate_n_flags)
 {
 	return le32_to_cpu(rate_n_flags) & 0xFFFF;
 }
-static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u16 flags)
+static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags)
 {
 	return cpu_to_le32(flags|(u16)rate);
 }
 
-struct iwl_tfd_frame_data {
+
+/**
+ * Tx/Rx Queues
+ *
+ * Most communication between driver and 4965 is via queues of data buffers.
+ * For example, all commands that the driver issues to device's embedded
+ * controller (uCode) are via the command queue (one of the Tx queues).  All
+ * uCode command responses/replies/notifications, including Rx frames, are
+ * conveyed from uCode to driver via the Rx queue.
+ *
+ * Most support for these queues, including handshake support, resides in
+ * structures in host DRAM, shared between the driver and the device.  When
+ * allocating this memory, the driver must make sure that data written by
+ * the host CPU updates DRAM immediately (and does not get "stuck" in CPU's
+ * cache memory), so DRAM and cache are consistent, and the device can
+ * immediately see changes made by the driver.
+ *
+ * 4965 supports up to 16 DRAM-based Tx queues, and services these queues via
+ * up to 7 DMA channels (FIFOs).  Each Tx queue is supported by a circular array
+ * in DRAM containing 256 Transmit Frame Descriptors (TFDs).
+ */
+#define IWL4965_MAX_WIN_SIZE              64
+#define IWL4965_QUEUE_SIZE               256
+#define IWL4965_NUM_FIFOS                  7
+#define IWL_MAX_NUM_QUEUES                16
+
+
+/**
+ * struct iwl4965_tfd_frame_data
+ *
+ * Describes up to 2 buffers containing (contiguous) portions of a Tx frame.
+ * Each buffer must be on dword boundary.
+ * Up to 10 iwl_tfd_frame_data structures, describing up to 20 buffers,
+ * may be filled within a TFD (iwl_tfd_frame).
+ *
+ * Bit fields in tb1_addr:
+ * 31- 0: Tx buffer 1 address bits [31:0]
+ *
+ * Bit fields in val1:
+ * 31-16: Tx buffer 2 address bits [15:0]
+ * 15- 4: Tx buffer 1 length (bytes)
+ *  3- 0: Tx buffer 1 address bits [32:32]
+ *
+ * Bit fields in val2:
+ * 31-20: Tx buffer 2 length (bytes)
+ * 19- 0: Tx buffer 2 address bits [35:16]
+ */
+struct iwl4965_tfd_frame_data {
 	__le32 tb1_addr;
 
 	__le32 val1;
@@ -509,7 +1926,36 @@ struct iwl_tfd_frame_data {
 #define IWL_tb2_len_SYM val2
 } __attribute__ ((packed));
 
-struct iwl_tfd_frame {
+
+/**
+ * struct iwl4965_tfd_frame
+ *
+ * Transmit Frame Descriptor (TFD)
+ *
+ * 4965 supports up to 16 Tx queues resident in host DRAM.
+ * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM.
+ * Both driver and device share these circular buffers, each of which must be
+ * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes for 4965.
+ *
+ * Driver must indicate the physical address of the base of each
+ * circular buffer via the 4965's FH_MEM_CBBC_QUEUE registers.
+ *
+ * Each TFD contains pointer/size information for up to 20 data buffers
+ * in host DRAM.  These buffers collectively contain the (one) frame described
+ * by the TFD.  Each buffer must be a single contiguous block of memory within
+ * itself, but buffers may be scattered in host DRAM.  Each buffer has max size
+ * of (4K - 4).  The 4965 concatenates all of a TFD's buffers into a single
+ * Tx frame, up to 8 KBytes in size.
+ *
+ * Bit fields in the control dword (val0):
+ * 31-30: # dwords (0-3) of padding required at end of frame for 16-byte bound
+ *    29: reserved
+ * 28-24: # Transmit Buffer Descriptors in TFD
+ * 23- 0: reserved
+ *
+ * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx.
+ */
+struct iwl4965_tfd_frame {
 	__le32 val0;
 	/* __le32 rsvd1:24; */
 	/* __le32 num_tbs:5; */
@@ -518,15 +1964,20 @@ struct iwl_tfd_frame {
 #define IWL_num_tbs_SYM val0
 	/* __le32 rsvd2:1; */
 	/* __le32 padding:2; */
-	struct iwl_tfd_frame_data pa[10];
+	struct iwl4965_tfd_frame_data pa[10];
 	__le32 reserved;
 } __attribute__ ((packed));
 
-#define IWL4965_MAX_WIN_SIZE              64
-#define IWL4965_QUEUE_SIZE               256
-#define IWL4965_NUM_FIFOS                  7
-#define IWL_MAX_NUM_QUEUES                16
 
+/**
+ * struct iwl4965_queue_byte_cnt_entry
+ *
+ * Byte Count Table Entry
+ *
+ * Bit fields:
+ * 15-12: reserved
+ * 11- 0: total to-be-transmitted byte count of frame (does not include command)
+ */
 struct iwl4965_queue_byte_cnt_entry {
 	__le16 val;
 	/* __le16 byte_cnt:12; */
@@ -536,6 +1987,25 @@ struct iwl4965_queue_byte_cnt_entry {
 	/* __le16 rsvd:4; */
 } __attribute__ ((packed));
 
+
+/**
+ * struct iwl4965_sched_queue_byte_cnt_tbl
+ *
+ * Byte Count table
+ *
+ * Each Tx queue uses a byte-count table containing 320 entries:
+ * one 16-bit entry for each of 256 TFDs, plus an additional 64 entries that
+ * duplicate the first 64 entries (to avoid wrap-around within a Tx window;
+ * max Tx window is 64 TFDs).
+ *
+ * When driver sets up a new TFD, it must also enter the total byte count
+ * of the frame to be transmitted into the corresponding entry in the byte
+ * count table for the chosen Tx queue.  If the TFD index is 0-63, the driver
+ * must duplicate the byte count entry in corresponding index 256-319.
+ *
+ * "dont_care" padding puts each byte count table on a 1024-byte boundary;
+ * 4965 assumes tables are separated by 1024 bytes.
+ */
 struct iwl4965_sched_queue_byte_cnt_tbl {
 	struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE +
 						       IWL4965_MAX_WIN_SIZE];
@@ -544,9 +2014,31 @@ struct iwl4965_sched_queue_byte_cnt_tbl {
 		     sizeof(__le16)];
 } __attribute__ ((packed));
 
-/* Base physical address of iwl_shared is provided to SCD_DRAM_BASE_ADDR
- * and &iwl_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */
-struct iwl_shared {
+
+/**
+ * struct iwl4965_shared - handshake area for Tx and Rx
+ *
+ * For convenience in allocating memory, this structure combines 2 areas of
+ * DRAM which must be shared between driver and 4965.  These do not need to
+ * be combined, if better allocation would result from keeping them separate:
+ *
+ * 1)  The Tx byte count tables occupy 1024 bytes each (16 KBytes total for
+ *     16 queues).  Driver uses SCD_DRAM_BASE_ADDR to tell 4965 where to find
+ *     the first of these tables.  4965 assumes tables are 1024 bytes apart.
+ *
+ * 2)  The Rx status (val0 and val1) occupies only 8 bytes.  Driver uses
+ *     FH_RSCSR_CHNL0_STTS_WPTR_REG to tell 4965 where to find this area.
+ *     Driver reads val0 to determine the latest Receive Buffer Descriptor (RBD)
+ *     that has been filled by the 4965.
+ *
+ * Bit fields val0:
+ * 31-12:  Not used
+ * 11- 0:  Index of last filled Rx buffer descriptor (4965 writes, driver reads)
+ *
+ * Bit fields val1:
+ * 31- 0:  Not used
+ */
+struct iwl4965_shared {
 	struct iwl4965_sched_queue_byte_cnt_tbl
 	 queues_byte_cnt_tbls[IWL_MAX_NUM_QUEUES];
 	__le32 val0;
@@ -578,4 +2070,4 @@ struct iwl_shared {
 	__le32 padding2;
 } __attribute__ ((packed));
 
-#endif /* __iwl_4965_hw_h__ */
+#endif /* __iwl4965_4965_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-io.h b/drivers/net/wireless/iwlwifi/iwl-4965-io.h
new file mode 100644
index 000000000000..34a0b57eea0c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-io.h
@@ -0,0 +1,431 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl4965_io_h__
+#define __iwl4965_io_h__
+
+#include <linux/io.h>
+
+#include "iwl-4965-debug.h"
+
+/*
+ * IO, register, and NIC memory access functions
+ *
+ * NOTE on naming convention and macro usage for these
+ *
+ * A single _ prefix before a an access function means that no state
+ * check or debug information is printed when that function is called.
+ *
+ * A double __ prefix before an access function means that state is checked
+ * and the current line number is printed in addition to any other debug output.
+ *
+ * The non-prefixed name is the #define that maps the caller into a
+ * #define that provides the caller's __LINE__ to the double prefix version.
+ *
+ * If you wish to call the function without any debug or state checking,
+ * you should use the single _ prefix version (as is used by dependent IO
+ * routines, for example _iwl4965_read_direct32 calls the non-check version of
+ * _iwl4965_read32.)
+ *
+ * These declarations are *extremely* useful in quickly isolating code deltas
+ * which result in misconfiguring of the hardware I/O.  In combination with
+ * git-bisect and the IO debug level you can quickly determine the specific
+ * commit which breaks the IO sequence to the hardware.
+ *
+ */
+
+#define _iwl4965_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_write32(const char *f, u32 l, struct iwl4965_priv *iwl,
+				 u32 ofs, u32 val)
+{
+	IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l);
+	_iwl4965_write32(iwl, ofs, val);
+}
+#define iwl4965_write32(iwl, ofs, val) \
+	__iwl4965_write32(__FILE__, __LINE__, iwl, ofs, val)
+#else
+#define iwl4965_write32(iwl, ofs, val) _iwl4965_write32(iwl, ofs, val)
+#endif
+
+#define _iwl4965_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWL4965_DEBUG
+static inline u32 __iwl4965_read32(char *f, u32 l, struct iwl4965_priv *iwl, u32 ofs)
+{
+	IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
+	return _iwl4965_read32(iwl, ofs);
+}
+#define iwl4965_read32(iwl, ofs) __iwl4965_read32(__FILE__, __LINE__, iwl, ofs)
+#else
+#define iwl4965_read32(p, o) _iwl4965_read32(p, o)
+#endif
+
+static inline int _iwl4965_poll_bit(struct iwl4965_priv *priv, u32 addr,
+				u32 bits, u32 mask, int timeout)
+{
+	int i = 0;
+
+	do {
+		if ((_iwl4965_read32(priv, addr) & mask) == (bits & mask))
+			return i;
+		mdelay(10);
+		i += 10;
+	} while (i < timeout);
+
+	return -ETIMEDOUT;
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline int __iwl4965_poll_bit(const char *f, u32 l,
+				 struct iwl4965_priv *priv, u32 addr,
+				 u32 bits, u32 mask, int timeout)
+{
+	int ret = _iwl4965_poll_bit(priv, addr, bits, mask, timeout);
+	if (unlikely(ret  == -ETIMEDOUT))
+		IWL_DEBUG_IO
+		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n",
+		     addr, bits, mask, f, l);
+	else
+		IWL_DEBUG_IO
+		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n",
+		     addr, bits, mask, ret, f, l);
+	return ret;
+}
+#define iwl4965_poll_bit(iwl, addr, bits, mask, timeout) \
+	__iwl4965_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
+#else
+#define iwl4965_poll_bit(p, a, b, m, t) _iwl4965_poll_bit(p, a, b, m, t)
+#endif
+
+static inline void _iwl4965_set_bit(struct iwl4965_priv *priv, u32 reg, u32 mask)
+{
+	_iwl4965_write32(priv, reg, _iwl4965_read32(priv, reg) | mask);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_set_bit(const char *f, u32 l,
+				 struct iwl4965_priv *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl4965_read32(priv, reg) | mask;
+	IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+	_iwl4965_write32(priv, reg, val);
+}
+#define iwl4965_set_bit(p, r, m) __iwl4965_set_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl4965_set_bit(p, r, m) _iwl4965_set_bit(p, r, m)
+#endif
+
+static inline void _iwl4965_clear_bit(struct iwl4965_priv *priv, u32 reg, u32 mask)
+{
+	_iwl4965_write32(priv, reg, _iwl4965_read32(priv, reg) & ~mask);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_clear_bit(const char *f, u32 l,
+				   struct iwl4965_priv *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl4965_read32(priv, reg) & ~mask;
+	IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+	_iwl4965_write32(priv, reg, val);
+}
+#define iwl4965_clear_bit(p, r, m) __iwl4965_clear_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl4965_clear_bit(p, r, m) _iwl4965_clear_bit(p, r, m)
+#endif
+
+static inline int _iwl4965_grab_nic_access(struct iwl4965_priv *priv)
+{
+	int ret;
+	u32 gp_ctl;
+
+#ifdef CONFIG_IWL4965_DEBUG
+	if (atomic_read(&priv->restrict_refcnt))
+		return 0;
+#endif
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+	    test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+		IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
+			"wakes up NIC\n");
+
+		/* 10 msec allows time for NIC to complete its data save */
+		gp_ctl = _iwl4965_read32(priv, CSR_GP_CNTRL);
+		if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
+			IWL_DEBUG_RF_KILL("Wait for complete power-down, "
+				"gpctl = 0x%08x\n", gp_ctl);
+			mdelay(10);
+		} else
+			IWL_DEBUG_RF_KILL("power-down complete, "
+					  "gpctl = 0x%08x\n", gp_ctl);
+	}
+
+	/* this bit wakes up the NIC */
+	_iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	ret = _iwl4965_poll_bit(priv, CSR_GP_CNTRL,
+			   CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50);
+	if (ret < 0) {
+		IWL_ERROR("MAC is in deep sleep!\n");
+		return -EIO;
+	}
+
+#ifdef CONFIG_IWL4965_DEBUG
+	atomic_inc(&priv->restrict_refcnt);
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_IWL4965_DEBUG
+static inline int __iwl4965_grab_nic_access(const char *f, u32 l,
+					       struct iwl4965_priv *priv)
+{
+	if (atomic_read(&priv->restrict_refcnt))
+		IWL_DEBUG_INFO("Grabbing access while already held at "
+			       "line %d.\n", l);
+
+	IWL_DEBUG_IO("grabbing nic access - %s %d\n", f, l);
+	return _iwl4965_grab_nic_access(priv);
+}
+#define iwl4965_grab_nic_access(priv) \
+	__iwl4965_grab_nic_access(__FILE__, __LINE__, priv)
+#else
+#define iwl4965_grab_nic_access(priv) \
+	_iwl4965_grab_nic_access(priv)
+#endif
+
+static inline void _iwl4965_release_nic_access(struct iwl4965_priv *priv)
+{
+#ifdef CONFIG_IWL4965_DEBUG
+	if (atomic_dec_and_test(&priv->restrict_refcnt))
+#endif
+		_iwl4965_clear_bit(priv, CSR_GP_CNTRL,
+			       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_release_nic_access(const char *f, u32 l,
+					    struct iwl4965_priv *priv)
+{
+	if (atomic_read(&priv->restrict_refcnt) <= 0)
+		IWL_ERROR("Release unheld nic access at line %d.\n", l);
+
+	IWL_DEBUG_IO("releasing nic access - %s %d\n", f, l);
+	_iwl4965_release_nic_access(priv);
+}
+#define iwl4965_release_nic_access(priv) \
+	__iwl4965_release_nic_access(__FILE__, __LINE__, priv)
+#else
+#define iwl4965_release_nic_access(priv) \
+	_iwl4965_release_nic_access(priv)
+#endif
+
+static inline u32 _iwl4965_read_direct32(struct iwl4965_priv *priv, u32 reg)
+{
+	return _iwl4965_read32(priv, reg);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline u32 __iwl4965_read_direct32(const char *f, u32 l,
+					struct iwl4965_priv *priv, u32 reg)
+{
+	u32 value = _iwl4965_read_direct32(priv, reg);
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from %s %d\n", f, l);
+	IWL_DEBUG_IO("read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value,
+		     f, l);
+	return value;
+}
+#define iwl4965_read_direct32(priv, reg) \
+	__iwl4965_read_direct32(__FILE__, __LINE__, priv, reg)
+#else
+#define iwl4965_read_direct32 _iwl4965_read_direct32
+#endif
+
+static inline void _iwl4965_write_direct32(struct iwl4965_priv *priv,
+					 u32 reg, u32 value)
+{
+	_iwl4965_write32(priv, reg, value);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static void __iwl4965_write_direct32(u32 line,
+				   struct iwl4965_priv *priv, u32 reg, u32 value)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	_iwl4965_write_direct32(priv, reg, value);
+}
+#define iwl4965_write_direct32(priv, reg, value) \
+	__iwl4965_write_direct32(__LINE__, priv, reg, value)
+#else
+#define iwl4965_write_direct32 _iwl4965_write_direct32
+#endif
+
+static inline void iwl4965_write_reg_buf(struct iwl4965_priv *priv,
+					       u32 reg, u32 len, u32 *values)
+{
+	u32 count = sizeof(u32);
+
+	if ((priv != NULL) && (values != NULL)) {
+		for (; 0 < len; len -= count, reg += count, values++)
+			_iwl4965_write_direct32(priv, reg, *values);
+	}
+}
+
+static inline int _iwl4965_poll_direct_bit(struct iwl4965_priv *priv,
+					   u32 addr, u32 mask, int timeout)
+{
+	int i = 0;
+
+	do {
+		if ((_iwl4965_read_direct32(priv, addr) & mask) == mask)
+			return i;
+		mdelay(10);
+		i += 10;
+	} while (i < timeout);
+
+	return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_IWL4965_DEBUG
+static inline int __iwl4965_poll_direct_bit(const char *f, u32 l,
+					    struct iwl4965_priv *priv,
+					    u32 addr, u32 mask, int timeout)
+{
+	int ret  = _iwl4965_poll_direct_bit(priv, addr, mask, timeout);
+
+	if (unlikely(ret == -ETIMEDOUT))
+		IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) - "
+			     "timedout - %s %d\n", addr, mask, f, l);
+	else
+		IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) = 0x%08X "
+			     "- %s %d\n", addr, mask, ret, f, l);
+	return ret;
+}
+#define iwl4965_poll_direct_bit(iwl, addr, mask, timeout) \
+	__iwl4965_poll_direct_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
+#else
+#define iwl4965_poll_direct_bit _iwl4965_poll_direct_bit
+#endif
+
+static inline u32 _iwl4965_read_prph(struct iwl4965_priv *priv, u32 reg)
+{
+	_iwl4965_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+	return _iwl4965_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline u32 __iwl4965_read_prph(u32 line, struct iwl4965_priv *priv, u32 reg)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	return _iwl4965_read_prph(priv, reg);
+}
+
+#define iwl4965_read_prph(priv, reg) \
+	__iwl4965_read_prph(__LINE__, priv, reg)
+#else
+#define iwl4965_read_prph _iwl4965_read_prph
+#endif
+
+static inline void _iwl4965_write_prph(struct iwl4965_priv *priv,
+					     u32 addr, u32 val)
+{
+	_iwl4965_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
+			      ((addr & 0x0000FFFF) | (3 << 24)));
+	_iwl4965_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
+}
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_write_prph(u32 line, struct iwl4965_priv *priv,
+					      u32 addr, u32 val)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access from line %d\n", line);
+	_iwl4965_write_prph(priv, addr, val);
+}
+
+#define iwl4965_write_prph(priv, addr, val) \
+	__iwl4965_write_prph(__LINE__, priv, addr, val);
+#else
+#define iwl4965_write_prph _iwl4965_write_prph
+#endif
+
+#define _iwl4965_set_bits_prph(priv, reg, mask) \
+	_iwl4965_write_prph(priv, reg, (_iwl4965_read_prph(priv, reg) | mask))
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_set_bits_prph(u32 line, struct iwl4965_priv *priv,
+					u32 reg, u32 mask)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+
+	_iwl4965_set_bits_prph(priv, reg, mask);
+}
+#define iwl4965_set_bits_prph(priv, reg, mask) \
+	__iwl4965_set_bits_prph(__LINE__, priv, reg, mask)
+#else
+#define iwl4965_set_bits_prph _iwl4965_set_bits_prph
+#endif
+
+#define _iwl4965_set_bits_mask_prph(priv, reg, bits, mask) \
+	_iwl4965_write_prph(priv, reg, ((_iwl4965_read_prph(priv, reg) & mask) | bits))
+
+#ifdef CONFIG_IWL4965_DEBUG
+static inline void __iwl4965_set_bits_mask_prph(u32 line,
+		struct iwl4965_priv *priv, u32 reg, u32 bits, u32 mask)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Nic access not held from line %d\n", line);
+	_iwl4965_set_bits_mask_prph(priv, reg, bits, mask);
+}
+#define iwl4965_set_bits_mask_prph(priv, reg, bits, mask) \
+	__iwl4965_set_bits_mask_prph(__LINE__, priv, reg, bits, mask)
+#else
+#define iwl4965_set_bits_mask_prph _iwl4965_set_bits_mask_prph
+#endif
+
+static inline void iwl4965_clear_bits_prph(struct iwl4965_priv
+						 *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl4965_read_prph(priv, reg);
+	_iwl4965_write_prph(priv, reg, (val & ~mask));
+}
+
+static inline u32 iwl4965_read_targ_mem(struct iwl4965_priv *priv, u32 addr)
+{
+	iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
+	return iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+}
+
+static inline void iwl4965_write_targ_mem(struct iwl4965_priv *priv, u32 addr, u32 val)
+{
+	iwl4965_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	iwl4965_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
+}
+
+static inline void iwl4965_write_targ_mem_buf(struct iwl4965_priv *priv, u32 addr,
+					  u32 len, u32 *values)
+{
+	iwl4965_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
+	for (; 0 < len; len -= sizeof(u32), values++)
+		iwl4965_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index 8dc78c0bf1ff..d06462264147 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -36,11 +36,9 @@
 
 #include <linux/workqueue.h>
 
-#define IWL 4965
-
 #include "../net/mac80211/ieee80211_rate.h"
 
-#include "iwlwifi.h"
+#include "iwl-4965.h"
 #include "iwl-helpers.h"
 
 #define RS_NAME "iwl-4965-rs"
@@ -49,13 +47,12 @@
 #define IWL_NUMBER_TRY      1
 #define IWL_HT_NUMBER_TRY   3
 
-#define IWL_RATE_MAX_WINDOW		62
-#define IWL_RATE_HIGH_TH		10880
-#define IWL_RATE_MIN_FAILURE_TH		6
-#define IWL_RATE_MIN_SUCCESS_TH		8
-#define IWL_RATE_DECREASE_TH		1920
-#define IWL_RATE_INCREASE_TH            8960
-#define IWL_RATE_SCALE_FLUSH_INTVL   (2*HZ)        /*2 seconds */
+#define IWL_RATE_MAX_WINDOW		62	/* # tx in history window */
+#define IWL_RATE_MIN_FAILURE_TH		6	/* min failures to calc tpt */
+#define IWL_RATE_MIN_SUCCESS_TH		8	/* min successes to calc tpt */
+
+/* max time to accum history 2 seconds */
+#define IWL_RATE_SCALE_FLUSH_INTVL   (2*HZ)
 
 static u8 rs_ht_to_legacy[] = {
 	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
@@ -67,83 +64,109 @@ static u8 rs_ht_to_legacy[] = {
 	IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
 };
 
-struct iwl_rate {
+struct iwl4965_rate {
 	u32 rate_n_flags;
 } __attribute__ ((packed));
 
-struct iwl_rate_scale_data {
-	u64 data;
-	s32 success_counter;
-	s32 success_ratio;
-	s32 counter;
-	s32 average_tpt;
+/**
+ * struct iwl4965_rate_scale_data -- tx success history for one rate
+ */
+struct iwl4965_rate_scale_data {
+	u64 data;		/* bitmap of successful frames */
+	s32 success_counter;	/* number of frames successful */
+	s32 success_ratio;	/* per-cent * 128  */
+	s32 counter;		/* number of frames attempted */
+	s32 average_tpt;	/* success ratio * expected throughput */
 	unsigned long stamp;
 };
 
-struct iwl_scale_tbl_info {
-	enum iwl_table_type lq_type;
-	enum iwl_antenna_type antenna_type;
-	u8 is_SGI;
-	u8 is_fat;
-	u8 is_dup;
-	u8 action;
-	s32 *expected_tpt;
-	struct iwl_rate current_rate;
-	struct iwl_rate_scale_data win[IWL_RATE_COUNT];
+/**
+ * struct iwl4965_scale_tbl_info -- tx params and success history for all rates
+ *
+ * There are two of these in struct iwl_rate_scale_priv,
+ * one for "active", and one for "search".
+ */
+struct iwl4965_scale_tbl_info {
+	enum iwl4965_table_type lq_type;
+	enum iwl4965_antenna_type antenna_type;
+	u8 is_SGI;	/* 1 = short guard interval */
+	u8 is_fat;	/* 1 = 40 MHz channel width */
+	u8 is_dup;	/* 1 = duplicated data streams */
+	u8 action;	/* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
+	s32 *expected_tpt;	/* throughput metrics; expected_tpt_G, etc. */
+	struct iwl4965_rate current_rate;  /* rate_n_flags, uCode API format */
+	struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
 };
 
-struct iwl_rate_scale_priv {
-	u8 active_tbl;
-	u8 enable_counter;
-	u8 stay_in_tbl;
-	u8 search_better_tbl;
+/**
+ * struct iwl_rate_scale_priv -- driver's rate scaling private structure
+ *
+ * Pointer to this gets passed back and forth between driver and mac80211.
+ */
+struct iwl4965_lq_sta {
+	u8 active_tbl;		/* index of active table, range 0-1 */
+	u8 enable_counter;	/* indicates HT mode */
+	u8 stay_in_tbl;		/* 1: disallow, 0: allow search for new mode */
+	u8 search_better_tbl;	/* 1: currently trying alternate mode */
 	s32 last_tpt;
+
+	/* The following determine when to search for a new mode */
 	u32 table_count_limit;
-	u32 max_failure_limit;
-	u32 max_success_limit;
+	u32 max_failure_limit;	/* # failed frames before new search */
+	u32 max_success_limit;	/* # successful frames before new search */
 	u32 table_count;
-	u32 total_failed;
-	u32 total_success;
-	u32 flush_timer;
-	u8 action_counter;
+	u32 total_failed;	/* total failed frames, any/all rates */
+	u32 total_success;	/* total successful frames, any/all rates */
+	u32 flush_timer;	/* time staying in mode before new search */
+
+	u8 action_counter;	/* # mode-switch actions tried */
 	u8 antenna;
 	u8 valid_antenna;
 	u8 is_green;
 	u8 is_dup;
 	u8 phymode;
 	u8 ibss_sta_added;
+
+	/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
 	u32 supp_rates;
 	u16 active_rate;
 	u16 active_siso_rate;
 	u16 active_mimo_rate;
 	u16 active_rate_basic;
-	struct iwl_link_quality_cmd lq;
-	struct iwl_scale_tbl_info lq_info[LQ_SIZE];
+
+	struct iwl4965_link_quality_cmd lq;
+	struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct dentry *rs_sta_dbgfs_scale_table_file;
 	struct dentry *rs_sta_dbgfs_stats_table_file;
-	struct iwl_rate dbg_fixed;
-	struct iwl_priv *drv;
+	struct iwl4965_rate dbg_fixed;
+	struct iwl4965_priv *drv;
 #endif
 };
 
-static void rs_rate_scale_perform(struct iwl_priv *priv,
+static void rs_rate_scale_perform(struct iwl4965_priv *priv,
 				   struct net_device *dev,
 				   struct ieee80211_hdr *hdr,
 				   struct sta_info *sta);
-static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
-			     struct iwl_rate *tx_mcs,
-			     struct iwl_link_quality_cmd *tbl);
+static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
+			     struct iwl4965_rate *tx_mcs,
+			     struct iwl4965_link_quality_cmd *tbl);
 
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
-				struct iwl_rate *mcs, int index);
+static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
+				struct iwl4965_rate *mcs, int index);
 #else
-static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
-				struct iwl_rate *mcs, int index)
+static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
+				struct iwl4965_rate *mcs, int index)
 {}
 #endif
+
+/*
+ * Expected throughput metrics for following rates:
+ * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits
+ * "G" is the only table that supports CCK (the first 4 rates).
+ */
 static s32 expected_tpt_A[IWL_RATE_COUNT] = {
 	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
 };
@@ -184,36 +207,34 @@ static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
 	0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
 };
 
-static int iwl_lq_sync_callback(struct iwl_priv *priv,
-				struct iwl_cmd *cmd, struct sk_buff *skb)
+static int iwl4965_lq_sync_callback(struct iwl4965_priv *priv,
+				struct iwl4965_cmd *cmd, struct sk_buff *skb)
 {
 	/*We didn't cache the SKB; let the caller free it */
 	return 1;
 }
 
-static inline u8 iwl_rate_get_rate(u32 rate_n_flags)
+static inline u8 iwl4965_rate_get_rate(u32 rate_n_flags)
 {
 	return (u8)(rate_n_flags & 0xFF);
 }
 
-static int rs_send_lq_cmd(struct iwl_priv *priv,
-			  struct iwl_link_quality_cmd *lq, u8 flags)
+static int rs_send_lq_cmd(struct iwl4965_priv *priv,
+			  struct iwl4965_link_quality_cmd *lq, u8 flags)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL4965_DEBUG
 	int i;
 #endif
-	int rc = -1;
-
-	struct iwl_host_cmd cmd = {
+	struct iwl4965_host_cmd cmd = {
 		.id = REPLY_TX_LINK_QUALITY_CMD,
-		.len = sizeof(struct iwl_link_quality_cmd),
+		.len = sizeof(struct iwl4965_link_quality_cmd),
 		.meta.flags = flags,
 		.data = lq,
 	};
 
 	if ((lq->sta_id == 0xFF) &&
 	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
-		return rc;
+		return -EINVAL;
 
 	if (lq->sta_id == 0xFF)
 		lq->sta_id = IWL_AP_ID;
@@ -222,23 +243,23 @@ static int rs_send_lq_cmd(struct iwl_priv *priv,
 	IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
 		       lq->general_params.single_stream_ant_msk,
 		       lq->general_params.dual_stream_ant_msk);
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL4965_DEBUG
 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
 		IWL_DEBUG_RATE("lq index %d 0x%X\n",
 				i, lq->rs_table[i].rate_n_flags);
 #endif
 
 	if (flags & CMD_ASYNC)
-		cmd.meta.u.callback = iwl_lq_sync_callback;
+		cmd.meta.u.callback = iwl4965_lq_sync_callback;
 
-	if (iwl_is_associated(priv) && priv->assoc_station_added &&
+	if (iwl4965_is_associated(priv) && priv->assoc_station_added &&
 	    priv->lq_mngr.lq_ready)
-		rc = iwl_send_cmd(priv, &cmd);
+		return  iwl4965_send_cmd(priv, &cmd);
 
-	return rc;
+	return 0;
 }
 
-static int rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
+static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window)
 {
 	window->data = 0;
 	window->success_counter = 0;
@@ -246,29 +267,38 @@ static int rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
 	window->counter = 0;
 	window->average_tpt = IWL_INVALID_VALUE;
 	window->stamp = 0;
-
-	return 0;
 }
 
-static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
+/**
+ * rs_collect_tx_data - Update the success/failure sliding window
+ *
+ * We keep a sliding window of the last 62 packets transmitted
+ * at this rate.  window->data contains the bitmask of successful
+ * packets.
+ */
+static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows,
 			      int scale_index, s32 tpt, u32 status)
 {
-	int rc = 0;
-	struct iwl_rate_scale_data *window = NULL;
+	struct iwl4965_rate_scale_data *window = NULL;
 	u64 mask;
 	u8 win_size = IWL_RATE_MAX_WINDOW;
 	s32 fail_count;
 
-	if (scale_index < 0)
-		return -1;
-
-	if (scale_index >= IWL_RATE_COUNT)
-		return -1;
+	if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
+		return -EINVAL;
 
+	/* Select data for current tx bit rate */
 	window = &(windows[scale_index]);
 
+	/*
+	 * Keep track of only the latest 62 tx frame attempts in this rate's
+	 * history window; anything older isn't really relevant any more.
+	 * If we have filled up the sliding window, drop the oldest attempt;
+	 * if the oldest attempt (highest bit in bitmap) shows "success",
+	 * subtract "1" from the success counter (this is the main reason
+	 * we keep these bitmaps!).
+	 */
 	if (window->counter >= win_size) {
-
 		window->counter = win_size - 1;
 		mask = 1;
 		mask = (mask << (win_size - 1));
@@ -278,7 +308,11 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
 		}
 	}
 
+	/* Increment frames-attempted counter */
 	window->counter = window->counter + 1;
+
+	/* Shift bitmap by one frame (throw away oldest history),
+	 * OR in "1", and increment "success" if this frame was successful. */
 	mask = window->data;
 	window->data = (mask << 1);
 	if (status != 0) {
@@ -286,6 +320,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
 		window->data |= 0x1;
 	}
 
+	/* Calculate current success ratio, avoid divide-by-0! */
 	if (window->counter > 0)
 		window->success_ratio = 128 * (100 * window->success_counter)
 					/ window->counter;
@@ -294,37 +329,40 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
 
 	fail_count = window->counter - window->success_counter;
 
+	/* Calculate average throughput, if we have enough history. */
 	if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
 	    (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
 		window->average_tpt = (window->success_ratio * tpt + 64) / 128;
 	else
 		window->average_tpt = IWL_INVALID_VALUE;
 
+	/* Tag this window as having been updated */
 	window->stamp = jiffies;
 
-	return rc;
+	return 0;
 }
 
-int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate,
-			   struct iwl_scale_tbl_info *tbl,
+/*
+ * Fill uCode API rate_n_flags field, based on "search" or "active" table.
+ */
+static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate,
+			   struct iwl4965_scale_tbl_info *tbl,
 			   int index, u8 use_green)
 {
-	int rc = 0;
-
 	if (is_legacy(tbl->lq_type)) {
-		mcs_rate->rate_n_flags = iwl_rates[index].plcp;
+		mcs_rate->rate_n_flags = iwl4965_rates[index].plcp;
 		if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
 			mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK;
 
 	} else if (is_siso(tbl->lq_type)) {
 		if (index > IWL_LAST_OFDM_RATE)
 			index = IWL_LAST_OFDM_RATE;
-		 mcs_rate->rate_n_flags = iwl_rates[index].plcp_siso |
+		 mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_siso |
 					  RATE_MCS_HT_MSK;
 	} else {
 		if (index > IWL_LAST_OFDM_RATE)
 			index = IWL_LAST_OFDM_RATE;
-		mcs_rate->rate_n_flags = iwl_rates[index].plcp_mimo |
+		mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_mimo |
 					 RATE_MCS_HT_MSK;
 	}
 
@@ -343,7 +381,7 @@ int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate,
 	}
 
 	if (is_legacy(tbl->lq_type))
-		return rc;
+		return;
 
 	if (tbl->is_fat) {
 		if (tbl->is_dup)
@@ -359,27 +397,31 @@ int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate,
 		if (is_siso(tbl->lq_type))
 			mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK;
 	}
-	return rc;
 }
 
-static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate,
-				    int phymode, struct iwl_scale_tbl_info *tbl,
+/*
+ * Interpret uCode API's rate_n_flags format,
+ * fill "search" or "active" tx mode table.
+ */
+static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate,
+				    int phymode, struct iwl4965_scale_tbl_info *tbl,
 				    int *rate_idx)
 {
 	int index;
 	u32 ant_msk;
 
-	index = iwl_rate_index_from_plcp(mcs_rate->rate_n_flags);
+	index = iwl4965_rate_index_from_plcp(mcs_rate->rate_n_flags);
 
 	if (index  == IWL_RATE_INVALID) {
 		*rate_idx = -1;
-		return -1;
+		return -EINVAL;
 	}
-	tbl->is_SGI = 0;
+	tbl->is_SGI = 0;	/* default legacy setup */
 	tbl->is_fat = 0;
 	tbl->is_dup = 0;
-	tbl->antenna_type = ANT_BOTH;
+	tbl->antenna_type = ANT_BOTH;	/* default MIMO setup */
 
+	/* legacy rate format */
 	if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) {
 		ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
 
@@ -399,7 +441,8 @@ static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate,
 		}
 		*rate_idx = index;
 
-	} else if (iwl_rate_get_rate(mcs_rate->rate_n_flags)
+	/* HT rate format, SISO (might be 20 MHz legacy or 40 MHz fat width) */
+	} else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags)
 					<= IWL_RATE_SISO_60M_PLCP) {
 		tbl->lq_type = LQ_SISO;
 
@@ -423,6 +466,8 @@ static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate,
 			tbl->is_dup = 1;
 
 		*rate_idx = index;
+
+	/* HT rate format, MIMO (might be 20 MHz legacy or 40 MHz fat width) */
 	} else {
 		tbl->lq_type = LQ_MIMO;
 		if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
@@ -439,8 +484,8 @@ static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate,
 	return 0;
 }
 
-static inline void rs_toggle_antenna(struct iwl_rate *new_rate,
-				     struct iwl_scale_tbl_info *tbl)
+static inline void rs_toggle_antenna(struct iwl4965_rate *new_rate,
+				     struct iwl4965_scale_tbl_info *tbl)
 {
 	if (tbl->antenna_type == ANT_AUX) {
 		tbl->antenna_type = ANT_MAIN;
@@ -453,18 +498,15 @@ static inline void rs_toggle_antenna(struct iwl_rate *new_rate,
 	}
 }
 
-static inline s8 rs_use_green(struct iwl_priv *priv)
+static inline u8 rs_use_green(struct iwl4965_priv *priv,
+			      struct ieee80211_conf *conf)
 {
-	s8 rc = 0;
-#ifdef CONFIG_IWLWIFI_HT
-	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
-		return 0;
-
-	if ((priv->current_assoc_ht.is_green_field) &&
-	    !(priv->current_assoc_ht.operating_mode & 0x4))
-		rc = 1;
-#endif	/*CONFIG_IWLWIFI_HT */
-	return rc;
+#ifdef CONFIG_IWL4965_HT
+	return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+		priv->current_ht_config.is_green_field &&
+		!priv->current_ht_config.non_GF_STA_present);
+#endif	/* CONFIG_IWL4965_HT */
+	return 0;
 }
 
 /**
@@ -474,23 +516,24 @@ static inline s8 rs_use_green(struct iwl_priv *priv)
  * basic available rates.
  *
  */
-static void rs_get_supported_rates(struct iwl_rate_scale_priv *lq_data,
+static void rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta,
 				   struct ieee80211_hdr *hdr,
-				   enum iwl_table_type rate_type,
+				   enum iwl4965_table_type rate_type,
 				   u16 *data_rate)
 {
 	if (is_legacy(rate_type))
-		*data_rate = lq_data->active_rate;
+		*data_rate = lq_sta->active_rate;
 	else {
 		if (is_siso(rate_type))
-			*data_rate = lq_data->active_siso_rate;
+			*data_rate = lq_sta->active_siso_rate;
 		else
-			*data_rate = lq_data->active_mimo_rate;
+			*data_rate = lq_sta->active_mimo_rate;
 	}
 
 	if (hdr && is_multicast_ether_addr(hdr->addr1) &&
-	    lq_data->active_rate_basic)
-		*data_rate = lq_data->active_rate_basic;
+	    lq_sta->active_rate_basic) {
+		*data_rate = lq_sta->active_rate_basic;
+	}
 }
 
 static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
@@ -498,7 +541,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
 	u8 high = IWL_RATE_INVALID;
 	u8 low = IWL_RATE_INVALID;
 
-	/* 802.11A or ht walks to the next literal adjascent rate in
+	/* 802.11A or ht walks to the next literal adjacent rate in
 	 * the rate table */
 	if (is_a_band(rate_type) || !is_legacy(rate_type)) {
 		int i;
@@ -527,7 +570,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
 
 	low = index;
 	while (low != IWL_RATE_INVALID) {
-		low = iwl_rates[low].prev_rs;
+		low = iwl4965_rates[low].prev_rs;
 		if (low == IWL_RATE_INVALID)
 			break;
 		if (rate_mask & (1 << low))
@@ -537,7 +580,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
 
 	high = index;
 	while (high != IWL_RATE_INVALID) {
-		high = iwl_rates[high].next_rs;
+		high = iwl4965_rates[high].next_rs;
 		if (high == IWL_RATE_INVALID)
 			break;
 		if (rate_mask & (1 << high))
@@ -548,15 +591,15 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
 	return (high << 8) | low;
 }
 
-static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data,
-			     struct iwl_scale_tbl_info *tbl, u8 scale_index,
-			     u8 ht_possible, struct iwl_rate *mcs_rate)
+static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta,
+			     struct iwl4965_scale_tbl_info *tbl, u8 scale_index,
+			     u8 ht_possible, struct iwl4965_rate *mcs_rate)
 {
 	s32 low;
 	u16 rate_mask;
 	u16 high_low;
 	u8 switch_to_legacy = 0;
-	u8 is_green = lq_data->is_green;
+	u8 is_green = lq_sta->is_green;
 
 	/* check if we need to switch from HT to legacy rates.
 	 * assumption is that mandatory rates (1Mbps or 6Mbps)
@@ -564,7 +607,7 @@ static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data,
 	if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
 		switch_to_legacy = 1;
 		scale_index = rs_ht_to_legacy[scale_index];
-		if (lq_data->phymode == MODE_IEEE80211A)
+		if (lq_sta->phymode == MODE_IEEE80211A)
 			tbl->lq_type = LQ_A;
 		else
 			tbl->lq_type = LQ_G;
@@ -577,22 +620,22 @@ static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data,
 		tbl->is_SGI = 0;
 	}
 
-	rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask);
+	rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, &rate_mask);
 
-	/* mask with station rate restriction */
+	/* Mask with station rate restriction */
 	if (is_legacy(tbl->lq_type)) {
-		if (lq_data->phymode == (u8) MODE_IEEE80211A)
+		/* supp_rates has no CCK bits in A mode */
+		if (lq_sta->phymode == (u8) MODE_IEEE80211A)
 			rate_mask  = (u16)(rate_mask &
-			   (lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
+			   (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
 		else
-			rate_mask = (u16)(rate_mask & lq_data->supp_rates);
+			rate_mask = (u16)(rate_mask & lq_sta->supp_rates);
 	}
 
-	/* if we did switched from HT to legacy check current rate */
-	if ((switch_to_legacy) &&
-	    (rate_mask & (1 << scale_index))) {
+	/* If we switched from HT to legacy, check current rate */
+	if (switch_to_legacy && (rate_mask & (1 << scale_index))) {
 		rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
-		return 0;
+		return;
 	}
 
 	high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type);
@@ -602,29 +645,29 @@ static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data,
 		rs_mcs_from_tbl(mcs_rate, tbl, low, is_green);
 	else
 		rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
-
-	return 0;
 }
 
-static void rs_tx_status(void *priv_rate,
-			 struct net_device *dev,
+/*
+ * mac80211 sends us Tx status
+ */
+static void rs_tx_status(void *priv_rate, struct net_device *dev,
 			 struct sk_buff *skb,
 			 struct ieee80211_tx_status *tx_resp)
 {
 	int status;
 	u8 retries;
 	int rs_index, index = 0;
-	struct iwl_rate_scale_priv *lq;
-	struct iwl_link_quality_cmd *table;
+	struct iwl4965_lq_sta *lq_sta;
+	struct iwl4965_link_quality_cmd *table;
 	struct sta_info *sta;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct iwl_rate_scale_data *window = NULL;
-	struct iwl_rate_scale_data *search_win = NULL;
-	struct iwl_rate tx_mcs;
-	struct iwl_scale_tbl_info tbl_type;
-	struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
+	struct iwl4965_rate_scale_data *window = NULL;
+	struct iwl4965_rate_scale_data *search_win = NULL;
+	struct iwl4965_rate tx_mcs;
+	struct iwl4965_scale_tbl_info tbl_type;
+	struct iwl4965_scale_tbl_info *curr_tbl, *search_tbl;
 	u8 active_index = 0;
 	u16 fc = le16_to_cpu(hdr->frame_control);
 	s32 tpt = 0;
@@ -648,27 +691,32 @@ static void rs_tx_status(void *priv_rate,
 		return;
 	}
 
-	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+	lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
 
 	if (!priv->lq_mngr.lq_ready)
 		return;
 
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added)
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	    !lq_sta->ibss_sta_added)
 		return;
 
-	table = &lq->lq;
-	active_index = lq->active_tbl;
+	table = &lq_sta->lq;
+	active_index = lq_sta->active_tbl;
 
-	lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx);
-	if (!lq->antenna)
-		lq->antenna = lq->valid_antenna;
+	/* Get mac80211 antenna info */
+	lq_sta->antenna =
+		(lq_sta->valid_antenna & local->hw.conf.antenna_sel_tx);
+	if (!lq_sta->antenna)
+		lq_sta->antenna = lq_sta->valid_antenna;
 
-	lq->antenna = lq->valid_antenna;
-	curr_tbl = &(lq->lq_info[active_index]);
-	search_tbl = &(lq->lq_info[(1 - active_index)]);
-	window = (struct iwl_rate_scale_data *)
+	/* Ignore mac80211 antenna info for now */
+	lq_sta->antenna = lq_sta->valid_antenna;
+
+	curr_tbl = &(lq_sta->lq_info[active_index]);
+	search_tbl = &(lq_sta->lq_info[(1 - active_index)]);
+	window = (struct iwl4965_rate_scale_data *)
 	    &(curr_tbl->win[0]);
-	search_win = (struct iwl_rate_scale_data *)
+	search_win = (struct iwl4965_rate_scale_data *)
 	    &(search_tbl->win[0]);
 
 	tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
@@ -682,6 +730,14 @@ static void rs_tx_status(void *priv_rate,
 		return;
 	}
 
+	/*
+	 * Ignore this Tx frame response if its initial rate doesn't match
+	 * that of latest Link Quality command.  There may be stragglers
+	 * from a previous Link Quality command, but we're no longer interested
+	 * in those; they're either from the "active" mode while we're trying
+	 * to check "search" mode, or a prior "search" mode after we've moved
+	 * to a new "search" mode (which might become the new "active" mode).
+	 */
 	if (retries &&
 	    (tx_mcs.rate_n_flags !=
 				le32_to_cpu(table->rs_table[0].rate_n_flags))) {
@@ -692,12 +748,17 @@ static void rs_tx_status(void *priv_rate,
 		return;
 	}
 
+	/* Update frame history window with "failure" for each Tx retry. */
 	while (retries) {
+		/* Look up the rate and other info used for each tx attempt.
+		 * Each tx attempt steps one entry deeper in the rate table. */
 		tx_mcs.rate_n_flags =
 		    le32_to_cpu(table->rs_table[index].rate_n_flags);
 		rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
 					  &tbl_type, &rs_index);
 
+		/* If type matches "search" table,
+		 * add failure to "search" history */
 		if ((tbl_type.lq_type == search_tbl->lq_type) &&
 		    (tbl_type.antenna_type == search_tbl->antenna_type) &&
 		    (tbl_type.is_SGI == search_tbl->is_SGI)) {
@@ -705,8 +766,10 @@ static void rs_tx_status(void *priv_rate,
 				tpt = search_tbl->expected_tpt[rs_index];
 			else
 				tpt = 0;
-			rs_collect_tx_data(search_win,
-					    rs_index, tpt, 0);
+			rs_collect_tx_data(search_win, rs_index, tpt, 0);
+
+		/* Else if type matches "current/active" table,
+		 * add failure to "current/active" history */
 		} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
 			   (tbl_type.antenna_type == curr_tbl->antenna_type) &&
 			   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
@@ -716,13 +779,21 @@ static void rs_tx_status(void *priv_rate,
 				tpt = 0;
 			rs_collect_tx_data(window, rs_index, tpt, 0);
 		}
-		if (lq->stay_in_tbl)
-			lq->total_failed++;
+
+		/* If not searching for a new mode, increment failed counter
+		 * ... this helps determine when to start searching again */
+		if (lq_sta->stay_in_tbl)
+			lq_sta->total_failed++;
 		--retries;
 		index++;
 
 	}
 
+	/*
+	 * Find (by rate) the history window to update with final Tx attempt;
+	 * if Tx was successful first try, use original rate,
+	 * else look up the rate that was, finally, successful.
+	 */
 	if (!tx_resp->retry_count)
 		tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
 	else
@@ -732,11 +803,14 @@ static void rs_tx_status(void *priv_rate,
 	rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
 				  &tbl_type, &rs_index);
 
+	/* Update frame history window with "success" if Tx got ACKed ... */
 	if (tx_resp->flags & IEEE80211_TX_STATUS_ACK)
 		status = 1;
 	else
 		status = 0;
 
+	/* If type matches "search" table,
+	 * add final tx status to "search" history */
 	if ((tbl_type.lq_type == search_tbl->lq_type) &&
 	    (tbl_type.antenna_type == search_tbl->antenna_type) &&
 	    (tbl_type.is_SGI == search_tbl->is_SGI)) {
@@ -746,6 +820,9 @@ static void rs_tx_status(void *priv_rate,
 			tpt = 0;
 		rs_collect_tx_data(search_win,
 				    rs_index, tpt, status);
+
+	/* Else if type matches "current/active" table,
+	 * add final tx status to "current/active" history */
 	} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
 		   (tbl_type.antenna_type == curr_tbl->antenna_type) &&
 		   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
@@ -756,67 +833,77 @@ static void rs_tx_status(void *priv_rate,
 		rs_collect_tx_data(window, rs_index, tpt, status);
 	}
 
-	if (lq->stay_in_tbl) {
+	/* If not searching for new mode, increment success/failed counter
+	 * ... these help determine when to start searching again */
+	if (lq_sta->stay_in_tbl) {
 		if (status)
-			lq->total_success++;
+			lq_sta->total_success++;
 		else
-			lq->total_failed++;
+			lq_sta->total_failed++;
 	}
 
+	/* See if there's a better rate or modulation mode to try. */
 	rs_rate_scale_perform(priv, dev, hdr, sta);
 	sta_info_put(sta);
 	return;
 }
 
 static u8 rs_is_ant_connected(u8 valid_antenna,
-			      enum iwl_antenna_type antenna_type)
+			      enum iwl4965_antenna_type antenna_type)
 {
 	if (antenna_type == ANT_AUX)
 		return ((valid_antenna & 0x2) ? 1:0);
 	else if (antenna_type == ANT_MAIN)
 		return ((valid_antenna & 0x1) ? 1:0);
-	else if (antenna_type == ANT_BOTH) {
-		if ((valid_antenna & 0x3) == 0x3)
-			return 1;
-		else
-			return 0;
-	}
+	else if (antenna_type == ANT_BOTH)
+		return ((valid_antenna & 0x3) == 0x3);
 
 	return 1;
 }
 
 static u8 rs_is_other_ant_connected(u8 valid_antenna,
-				    enum iwl_antenna_type antenna_type)
+				    enum iwl4965_antenna_type antenna_type)
 {
 	if (antenna_type == ANT_AUX)
-		return (rs_is_ant_connected(valid_antenna, ANT_MAIN));
+		return rs_is_ant_connected(valid_antenna, ANT_MAIN);
 	else
-		return (rs_is_ant_connected(valid_antenna, ANT_AUX));
+		return rs_is_ant_connected(valid_antenna, ANT_AUX);
 
 	return 0;
 }
 
+/*
+ * Begin a period of staying with a selected modulation mode.
+ * Set "stay_in_tbl" flag to prevent any mode switches.
+ * Set frame tx success limits according to legacy vs. high-throughput,
+ * and reset overall (spanning all rates) tx success history statistics.
+ * These control how long we stay using same modulation mode before
+ * searching for a new mode.
+ */
 static void rs_set_stay_in_table(u8 is_legacy,
-				 struct iwl_rate_scale_priv *lq_data)
+				 struct iwl4965_lq_sta *lq_sta)
 {
 	IWL_DEBUG_HT("we are staying in the same table\n");
-	lq_data->stay_in_tbl = 1;
+	lq_sta->stay_in_tbl = 1;	/* only place this gets set */
 	if (is_legacy) {
-		lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT;
-		lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
-		lq_data->max_success_limit = IWL_LEGACY_TABLE_COUNT;
+		lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
+		lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
+		lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
 	} else {
-		lq_data->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
-		lq_data->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
-		lq_data->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
+		lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
+		lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
+		lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
 	}
-	lq_data->table_count = 0;
-	lq_data->total_failed = 0;
-	lq_data->total_success = 0;
+	lq_sta->table_count = 0;
+	lq_sta->total_failed = 0;
+	lq_sta->total_success = 0;
 }
 
-static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data,
-				      struct iwl_scale_tbl_info *tbl)
+/*
+ * Find correct throughput table for given mode of modulation
+ */
+static void rs_get_expected_tpt_table(struct iwl4965_lq_sta *lq_sta,
+				      struct iwl4965_scale_tbl_info *tbl)
 {
 	if (is_legacy(tbl->lq_type)) {
 		if (!is_a_band(tbl->lq_type))
@@ -824,7 +911,7 @@ static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data,
 		else
 			tbl->expected_tpt = expected_tpt_A;
 	} else if (is_siso(tbl->lq_type)) {
-		if (tbl->is_fat && !lq_data->is_dup)
+		if (tbl->is_fat && !lq_sta->is_dup)
 			if (tbl->is_SGI)
 				tbl->expected_tpt = expected_tpt_siso40MHzSGI;
 			else
@@ -835,7 +922,7 @@ static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data,
 			tbl->expected_tpt = expected_tpt_siso20MHz;
 
 	} else if (is_mimo(tbl->lq_type)) {
-		if (tbl->is_fat && !lq_data->is_dup)
+		if (tbl->is_fat && !lq_sta->is_dup)
 			if (tbl->is_SGI)
 				tbl->expected_tpt = expected_tpt_mimo40MHzSGI;
 			else
@@ -848,18 +935,34 @@ static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data,
 		tbl->expected_tpt = expected_tpt_G;
 }
 
-#ifdef CONFIG_IWLWIFI_HT
-static s32 rs_get_best_rate(struct iwl_priv *priv,
-			    struct iwl_rate_scale_priv *lq_data,
-			    struct iwl_scale_tbl_info *tbl,
+#ifdef CONFIG_IWL4965_HT
+/*
+ * Find starting rate for new "search" high-throughput mode of modulation.
+ * Goal is to find lowest expected rate (under perfect conditions) that is
+ * above the current measured throughput of "active" mode, to give new mode
+ * a fair chance to prove itself without too many challenges.
+ *
+ * This gets called when transitioning to more aggressive modulation
+ * (i.e. legacy to SISO or MIMO, or SISO to MIMO), as well as less aggressive
+ * (i.e. MIMO to SISO).  When moving to MIMO, bit rate will typically need
+ * to decrease to match "active" throughput.  When moving from MIMO to SISO,
+ * bit rate will typically need to increase, but not if performance was bad.
+ */
+static s32 rs_get_best_rate(struct iwl4965_priv *priv,
+			    struct iwl4965_lq_sta *lq_sta,
+			    struct iwl4965_scale_tbl_info *tbl,	/* "search" */
 			    u16 rate_mask, s8 index, s8 rate)
 {
-	struct iwl_scale_tbl_info *active_tbl =
-	    &(lq_data->lq_info[lq_data->active_tbl]);
-	s32 new_rate, high, low, start_hi;
+	/* "active" values */
+	struct iwl4965_scale_tbl_info *active_tbl =
+	    &(lq_sta->lq_info[lq_sta->active_tbl]);
 	s32 active_sr = active_tbl->win[index].success_ratio;
-	s32 *tpt_tbl = tbl->expected_tpt;
 	s32 active_tpt = active_tbl->expected_tpt[index];
+
+	/* expected "search" throughput */
+	s32 *tpt_tbl = tbl->expected_tpt;
+
+	s32 new_rate, high, low, start_hi;
 	u16 high_low;
 
 	new_rate = high = low = start_hi = IWL_RATE_INVALID;
@@ -870,28 +973,60 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
 		low = high_low & 0xff;
 		high = (high_low >> 8) & 0xff;
 
-		if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) &&
+		/*
+		 * Lower the "search" bit rate, to give new "search" mode
+		 * approximately the same throughput as "active" if:
+		 *
+		 * 1) "Active" mode has been working modestly well (but not
+		 *    great), and expected "search" throughput (under perfect
+		 *    conditions) at candidate rate is above the actual
+		 *    measured "active" throughput (but less than expected
+		 *    "active" throughput under perfect conditions).
+		 * OR
+		 * 2) "Active" mode has been working perfectly or very well
+		 *    and expected "search" throughput (under perfect
+		 *    conditions) at candidate rate is above expected
+		 *    "active" throughput (under perfect conditions).
+		 */
+		if ((((100 * tpt_tbl[rate]) > lq_sta->last_tpt) &&
 		     ((active_sr > IWL_RATE_DECREASE_TH) &&
 		      (active_sr <= IWL_RATE_HIGH_TH) &&
 		      (tpt_tbl[rate] <= active_tpt))) ||
 		    ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
 		     (tpt_tbl[rate] > active_tpt))) {
 
+			/* (2nd or later pass)
+			 * If we've already tried to raise the rate, and are
+			 * now trying to lower it, use the higher rate. */
 			if (start_hi != IWL_RATE_INVALID) {
 				new_rate = start_hi;
 				break;
 			}
+
 			new_rate = rate;
+
+			/* Loop again with lower rate */
 			if (low != IWL_RATE_INVALID)
 				rate = low;
+
+			/* Lower rate not available, use the original */
 			else
 				break;
+
+		/* Else try to raise the "search" rate to match "active" */
 		} else {
+			/* (2nd or later pass)
+			 * If we've already tried to lower the rate, and are
+			 * now trying to raise it, use the lower rate. */
 			if (new_rate != IWL_RATE_INVALID)
 				break;
+
+			/* Loop again with higher rate */
 			else if (high != IWL_RATE_INVALID) {
 				start_hi = high;
 				rate = high;
+
+			/* Higher rate not available, use the original */
 			} else {
 				new_rate = rate;
 				break;
@@ -901,58 +1036,64 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
 
 	return new_rate;
 }
-#endif				/* CONFIG_IWLWIFI_HT */
+#endif				/* CONFIG_IWL4965_HT */
 
 static inline u8 rs_is_both_ant_supp(u8 valid_antenna)
 {
 	return (rs_is_ant_connected(valid_antenna, ANT_BOTH));
 }
 
-static int rs_switch_to_mimo(struct iwl_priv *priv,
-			     struct iwl_rate_scale_priv *lq_data,
-			     struct iwl_scale_tbl_info *tbl, int index)
+/*
+ * Set up search table for MIMO
+ */
+static int rs_switch_to_mimo(struct iwl4965_priv *priv,
+			     struct iwl4965_lq_sta *lq_sta,
+			     struct ieee80211_conf *conf,
+			     struct sta_info *sta,
+			     struct iwl4965_scale_tbl_info *tbl, int index)
 {
-	int rc = -1;
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 	u16 rate_mask;
 	s32 rate;
-	s8 is_green = lq_data->is_green;
+	s8 is_green = lq_sta->is_green;
 
-	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
+	    !sta->ht_info.ht_supported)
 		return -1;
 
 	IWL_DEBUG_HT("LQ: try to switch to MIMO\n");
 	tbl->lq_type = LQ_MIMO;
-	rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
+	rs_get_supported_rates(lq_sta, NULL, tbl->lq_type,
 				&rate_mask);
 
-	if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
+	if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
 		return -1;
 
-	if (!rs_is_both_ant_supp(lq_data->antenna))
+	/* Need both Tx chains/antennas to support MIMO */
+	if (!rs_is_both_ant_supp(lq_sta->antenna))
 		return -1;
 
-	rc = 0;
-	tbl->is_dup = lq_data->is_dup;
+	tbl->is_dup = lq_sta->is_dup;
 	tbl->action = 0;
-	if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
+	if (priv->current_ht_config.supported_chan_width
+	    == IWL_CHANNEL_WIDTH_40MHZ)
 		tbl->is_fat = 1;
 	else
 		tbl->is_fat = 0;
 
 	if (tbl->is_fat) {
-		if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
+		if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
 			tbl->is_SGI = 1;
 		else
 			tbl->is_SGI = 0;
-	} else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
+	} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
 		tbl->is_SGI = 1;
 	else
 		tbl->is_SGI = 0;
 
-	rs_get_expected_tpt_table(lq_data, tbl);
+	rs_get_expected_tpt_table(lq_sta, tbl);
 
-	rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);
+	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index);
 
 	IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask);
 	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask))
@@ -961,43 +1102,49 @@ static int rs_switch_to_mimo(struct iwl_priv *priv,
 
 	IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
 		     tbl->current_rate.rate_n_flags, is_green);
-
-#endif				/*CONFIG_IWLWIFI_HT */
-	return rc;
+	return 0;
+#else
+	return -1;
+#endif				/*CONFIG_IWL4965_HT */
 }
 
-static int rs_switch_to_siso(struct iwl_priv *priv,
-			     struct iwl_rate_scale_priv *lq_data,
-			     struct iwl_scale_tbl_info *tbl, int index)
+/*
+ * Set up search table for SISO
+ */
+static int rs_switch_to_siso(struct iwl4965_priv *priv,
+			     struct iwl4965_lq_sta *lq_sta,
+			     struct ieee80211_conf *conf,
+			     struct sta_info *sta,
+			     struct iwl4965_scale_tbl_info *tbl, int index)
 {
-	int rc = -1;
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 	u16 rate_mask;
-	u8 is_green = lq_data->is_green;
+	u8 is_green = lq_sta->is_green;
 	s32 rate;
 
 	IWL_DEBUG_HT("LQ: try to switch to SISO\n");
-	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) ||
+	    !sta->ht_info.ht_supported)
 		return -1;
 
-	rc = 0;
-	tbl->is_dup = lq_data->is_dup;
+	tbl->is_dup = lq_sta->is_dup;
 	tbl->lq_type = LQ_SISO;
 	tbl->action = 0;
-	rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
+	rs_get_supported_rates(lq_sta, NULL, tbl->lq_type,
 				&rate_mask);
 
-	if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
+	if (priv->current_ht_config.supported_chan_width
+	    == IWL_CHANNEL_WIDTH_40MHZ)
 		tbl->is_fat = 1;
 	else
 		tbl->is_fat = 0;
 
 	if (tbl->is_fat) {
-		if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
+		if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY)
 			tbl->is_SGI = 1;
 		else
 			tbl->is_SGI = 0;
-	} else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
+	} else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY)
 		tbl->is_SGI = 1;
 	else
 		tbl->is_SGI = 0;
@@ -1005,8 +1152,8 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
 	if (is_green)
 		tbl->is_SGI = 0;
 
-	rs_get_expected_tpt_table(lq_data, tbl);
-	rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);
+	rs_get_expected_tpt_table(lq_sta, tbl);
+	rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index);
 
 	IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask);
 	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
@@ -1017,23 +1164,30 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
 	rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
 	IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
 		     tbl->current_rate.rate_n_flags, is_green);
+	return 0;
+#else
+	return -1;
 
-#endif				/*CONFIG_IWLWIFI_HT */
-	return rc;
+#endif				/*CONFIG_IWL4965_HT */
 }
 
-static int rs_move_legacy_other(struct iwl_priv *priv,
-				struct iwl_rate_scale_priv *lq_data,
+/*
+ * Try to switch to new modulation mode from legacy
+ */
+static int rs_move_legacy_other(struct iwl4965_priv *priv,
+				struct iwl4965_lq_sta *lq_sta,
+				struct ieee80211_conf *conf,
+				struct sta_info *sta,
 				int index)
 {
-	int rc = 0;
-	struct iwl_scale_tbl_info *tbl =
-	    &(lq_data->lq_info[lq_data->active_tbl]);
-	struct iwl_scale_tbl_info *search_tbl =
-	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
-	struct iwl_rate_scale_data *window = &(tbl->win[index]);
-	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	int ret = 0;
+	struct iwl4965_scale_tbl_info *tbl =
+	    &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl4965_scale_tbl_info *search_tbl =
+	    &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl4965_rate_scale_data *window = &(tbl->win[index]);
+	u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
+		  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
 
 	for (; ;) {
@@ -1042,52 +1196,59 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
 			IWL_DEBUG_HT("LQ Legacy switch Antenna\n");
 
 			search_tbl->lq_type = LQ_NONE;
-			lq_data->action_counter++;
+			lq_sta->action_counter++;
+
+			/* Don't change antenna if success has been great */
 			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
 				break;
-			if (!rs_is_other_ant_connected(lq_data->antenna,
+
+			/* Don't change antenna if other one is not connected */
+			if (!rs_is_other_ant_connected(lq_sta->antenna,
 							tbl->antenna_type))
 				break;
 
+			/* Set up search table to try other antenna */
 			memcpy(search_tbl, tbl, sz);
 
 			rs_toggle_antenna(&(search_tbl->current_rate),
 					   search_tbl);
-			rs_get_expected_tpt_table(lq_data, search_tbl);
-			lq_data->search_better_tbl = 1;
+			rs_get_expected_tpt_table(lq_sta, search_tbl);
+			lq_sta->search_better_tbl = 1;
 			goto out;
 
 		case IWL_LEGACY_SWITCH_SISO:
 			IWL_DEBUG_HT("LQ: Legacy switch to SISO\n");
+
+			/* Set up search table to try SISO */
 			memcpy(search_tbl, tbl, sz);
 			search_tbl->lq_type = LQ_SISO;
 			search_tbl->is_SGI = 0;
 			search_tbl->is_fat = 0;
-			rc = rs_switch_to_siso(priv, lq_data, search_tbl,
-					       index);
-			if (!rc) {
-				lq_data->search_better_tbl = 1;
-				lq_data->action_counter = 0;
-			}
-			if (!rc)
+			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret) {
+				lq_sta->search_better_tbl = 1;
+				lq_sta->action_counter = 0;
 				goto out;
+			}
 
 			break;
 		case IWL_LEGACY_SWITCH_MIMO:
 			IWL_DEBUG_HT("LQ: Legacy switch MIMO\n");
+
+			/* Set up search table to try MIMO */
 			memcpy(search_tbl, tbl, sz);
 			search_tbl->lq_type = LQ_MIMO;
 			search_tbl->is_SGI = 0;
 			search_tbl->is_fat = 0;
 			search_tbl->antenna_type = ANT_BOTH;
-			rc = rs_switch_to_mimo(priv, lq_data, search_tbl,
-					       index);
-			if (!rc) {
-				lq_data->search_better_tbl = 1;
-				lq_data->action_counter = 0;
-			}
-			if (!rc)
+			ret = rs_switch_to_mimo(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret) {
+				lq_sta->search_better_tbl = 1;
+				lq_sta->action_counter = 0;
 				goto out;
+			}
 			break;
 		}
 		tbl->action++;
@@ -1108,30 +1269,35 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
 
 }
 
-static int rs_move_siso_to_other(struct iwl_priv *priv,
-				 struct iwl_rate_scale_priv *lq_data,
+/*
+ * Try to switch to new modulation mode from SISO
+ */
+static int rs_move_siso_to_other(struct iwl4965_priv *priv,
+				 struct iwl4965_lq_sta *lq_sta,
+				 struct ieee80211_conf *conf,
+				 struct sta_info *sta,
 				 int index)
 {
-	int rc = -1;
-	u8 is_green = lq_data->is_green;
-	struct iwl_scale_tbl_info *tbl =
-	    &(lq_data->lq_info[lq_data->active_tbl]);
-	struct iwl_scale_tbl_info *search_tbl =
-	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
-	struct iwl_rate_scale_data *window = &(tbl->win[index]);
-	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	int ret;
+	u8 is_green = lq_sta->is_green;
+	struct iwl4965_scale_tbl_info *tbl =
+	    &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl4965_scale_tbl_info *search_tbl =
+	    &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	struct iwl4965_rate_scale_data *window = &(tbl->win[index]);
+	u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
+		  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
 
 	for (;;) {
-		lq_data->action_counter++;
+		lq_sta->action_counter++;
 		switch (tbl->action) {
 		case IWL_SISO_SWITCH_ANTENNA:
 			IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n");
 			search_tbl->lq_type = LQ_NONE;
 			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
 				break;
-			if (!rs_is_other_ant_connected(lq_data->antenna,
+			if (!rs_is_other_ant_connected(lq_sta->antenna,
 						       tbl->antenna_type))
 				break;
 
@@ -1139,7 +1305,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
 			search_tbl->action = IWL_SISO_SWITCH_MIMO;
 			rs_toggle_antenna(&(search_tbl->current_rate),
 					   search_tbl);
-			lq_data->search_better_tbl = 1;
+			lq_sta->search_better_tbl = 1;
 
 			goto out;
 
@@ -1150,13 +1316,12 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
 			search_tbl->is_SGI = 0;
 			search_tbl->is_fat = 0;
 			search_tbl->antenna_type = ANT_BOTH;
-			rc = rs_switch_to_mimo(priv, lq_data, search_tbl,
-					       index);
-			if (!rc)
-				lq_data->search_better_tbl = 1;
-
-			if (!rc)
+			ret = rs_switch_to_mimo(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret) {
+				lq_sta->search_better_tbl = 1;
 				goto out;
+			}
 			break;
 		case IWL_SISO_SWITCH_GI:
 			IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");
@@ -1168,17 +1333,17 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
 				search_tbl->is_SGI = 1;
 			else
 				break;
-			lq_data->search_better_tbl = 1;
+			lq_sta->search_better_tbl = 1;
 			if ((tbl->lq_type == LQ_SISO) &&
 			    (tbl->is_SGI)) {
-				s32 tpt = lq_data->last_tpt / 100;
+				s32 tpt = lq_sta->last_tpt / 100;
 				if (((!tbl->is_fat) &&
 				     (tpt >= expected_tpt_siso20MHz[index])) ||
 				    ((tbl->is_fat) &&
 				     (tpt >= expected_tpt_siso40MHz[index])))
-					lq_data->search_better_tbl = 0;
+					lq_sta->search_better_tbl = 0;
 			}
-			rs_get_expected_tpt_table(lq_data, search_tbl);
+			rs_get_expected_tpt_table(lq_sta, search_tbl);
 			rs_mcs_from_tbl(&search_tbl->current_rate,
 					     search_tbl, index, is_green);
 			goto out;
@@ -1199,26 +1364,33 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
 	return 0;
 }
 
-static int rs_move_mimo_to_other(struct iwl_priv *priv,
-				 struct iwl_rate_scale_priv *lq_data,
+/*
+ * Try to switch to new modulation mode from MIMO
+ */
+static int rs_move_mimo_to_other(struct iwl4965_priv *priv,
+				 struct iwl4965_lq_sta *lq_sta,
+				 struct ieee80211_conf *conf,
+				 struct sta_info *sta,
 				 int index)
 {
-	int rc = -1;
-	s8 is_green = lq_data->is_green;
-	struct iwl_scale_tbl_info *tbl =
-	    &(lq_data->lq_info[lq_data->active_tbl]);
-	struct iwl_scale_tbl_info *search_tbl =
-	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
-	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
-		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	int ret;
+	s8 is_green = lq_sta->is_green;
+	struct iwl4965_scale_tbl_info *tbl =
+	    &(lq_sta->lq_info[lq_sta->active_tbl]);
+	struct iwl4965_scale_tbl_info *search_tbl =
+	    &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+	u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
+		  (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
 	u8 start_action = tbl->action;
 
 	for (;;) {
-		lq_data->action_counter++;
+		lq_sta->action_counter++;
 		switch (tbl->action) {
 		case IWL_MIMO_SWITCH_ANTENNA_A:
 		case IWL_MIMO_SWITCH_ANTENNA_B:
 			IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n");
+
+			/* Set up new search table for SISO */
 			memcpy(search_tbl, tbl, sz);
 			search_tbl->lq_type = LQ_SISO;
 			search_tbl->is_SGI = 0;
@@ -1228,16 +1400,18 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
 			else
 				search_tbl->antenna_type = ANT_AUX;
 
-			rc = rs_switch_to_siso(priv, lq_data, search_tbl,
-					       index);
-			if (!rc) {
-				lq_data->search_better_tbl = 1;
+			ret = rs_switch_to_siso(priv, lq_sta, conf, sta,
+						 search_tbl, index);
+			if (!ret) {
+				lq_sta->search_better_tbl = 1;
 				goto out;
 			}
 			break;
 
 		case IWL_MIMO_SWITCH_GI:
 			IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n");
+
+			/* Set up new search table for MIMO */
 			memcpy(search_tbl, tbl, sz);
 			search_tbl->lq_type = LQ_MIMO;
 			search_tbl->antenna_type = ANT_BOTH;
@@ -1246,17 +1420,24 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
 				search_tbl->is_SGI = 0;
 			else
 				search_tbl->is_SGI = 1;
-			lq_data->search_better_tbl = 1;
+			lq_sta->search_better_tbl = 1;
+
+			/*
+			 * If active table already uses the fastest possible
+			 * modulation (dual stream with short guard interval),
+			 * and it's working well, there's no need to look
+			 * for a better type of modulation!
+			 */
 			if ((tbl->lq_type == LQ_MIMO) &&
 			    (tbl->is_SGI)) {
-				s32 tpt = lq_data->last_tpt / 100;
+				s32 tpt = lq_sta->last_tpt / 100;
 				if (((!tbl->is_fat) &&
 				     (tpt >= expected_tpt_mimo20MHz[index])) ||
 				    ((tbl->is_fat) &&
 				     (tpt >= expected_tpt_mimo40MHz[index])))
-					lq_data->search_better_tbl = 0;
+					lq_sta->search_better_tbl = 0;
 			}
-			rs_get_expected_tpt_table(lq_data, search_tbl);
+			rs_get_expected_tpt_table(lq_sta, search_tbl);
 			rs_mcs_from_tbl(&search_tbl->current_rate,
 					     search_tbl, index, is_green);
 			goto out;
@@ -1279,43 +1460,71 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
 
 }
 
-static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data)
+/*
+ * Check whether we should continue using same modulation mode, or
+ * begin search for a new mode, based on:
+ * 1) # tx successes or failures while using this mode
+ * 2) # times calling this function
+ * 3) elapsed time in this mode (not used, for now)
+ */
+static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta)
 {
-	struct iwl_scale_tbl_info *tbl;
+	struct iwl4965_scale_tbl_info *tbl;
 	int i;
 	int active_tbl;
 	int flush_interval_passed = 0;
 
-	active_tbl = lq_data->active_tbl;
+	active_tbl = lq_sta->active_tbl;
 
-	tbl = &(lq_data->lq_info[active_tbl]);
+	tbl = &(lq_sta->lq_info[active_tbl]);
 
-	if (lq_data->stay_in_tbl) {
+	/* If we've been disallowing search, see if we should now allow it */
+	if (lq_sta->stay_in_tbl) {
 
-		if (lq_data->flush_timer)
+		/* Elapsed time using current modulation mode */
+		if (lq_sta->flush_timer)
 			flush_interval_passed =
 			    time_after(jiffies,
-				       (unsigned long)(lq_data->flush_timer +
+				       (unsigned long)(lq_sta->flush_timer +
 					IWL_RATE_SCALE_FLUSH_INTVL));
 
+		/* For now, disable the elapsed time criterion */
 		flush_interval_passed = 0;
-		if ((lq_data->total_failed > lq_data->max_failure_limit) ||
-		    (lq_data->total_success > lq_data->max_success_limit) ||
-		    ((!lq_data->search_better_tbl) && (lq_data->flush_timer)
+
+		/*
+		 * Check if we should allow search for new modulation mode.
+		 * If many frames have failed or succeeded, or we've used
+		 * this same modulation for a long time, allow search, and
+		 * reset history stats that keep track of whether we should
+		 * allow a new search.  Also (below) reset all bitmaps and
+		 * stats in active history.
+		 */
+		if ((lq_sta->total_failed > lq_sta->max_failure_limit) ||
+		    (lq_sta->total_success > lq_sta->max_success_limit) ||
+		    ((!lq_sta->search_better_tbl) && (lq_sta->flush_timer)
 		     && (flush_interval_passed))) {
 			IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:",
-				     lq_data->total_failed,
-				     lq_data->total_success,
+				     lq_sta->total_failed,
+				     lq_sta->total_success,
 				     flush_interval_passed);
-			lq_data->stay_in_tbl = 0;
-			lq_data->total_failed = 0;
-			lq_data->total_success = 0;
-			lq_data->flush_timer = 0;
-		} else if (lq_data->table_count > 0) {
-			lq_data->table_count++;
-			if (lq_data->table_count >=
-			    lq_data->table_count_limit) {
-				lq_data->table_count = 0;
+
+			/* Allow search for new mode */
+			lq_sta->stay_in_tbl = 0;	/* only place reset */
+			lq_sta->total_failed = 0;
+			lq_sta->total_success = 0;
+			lq_sta->flush_timer = 0;
+
+		/*
+		 * Else if we've used this modulation mode enough repetitions
+		 * (regardless of elapsed time or success/failure), reset
+		 * history bitmaps and rate-specific stats for all rates in
+		 * active table.
+		 */
+		} else {
+			lq_sta->table_count++;
+			if (lq_sta->table_count >=
+			    lq_sta->table_count_limit) {
+				lq_sta->table_count = 0;
 
 				IWL_DEBUG_HT("LQ: stay in table clear win\n");
 				for (i = 0; i < IWL_RATE_COUNT; i++)
@@ -1324,23 +1533,32 @@ static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data)
 			}
 		}
 
-		if (!lq_data->stay_in_tbl) {
+		/* If transitioning to allow "search", reset all history
+		 * bitmaps and stats in active table (this will become the new
+		 * "search" table). */
+		if (!lq_sta->stay_in_tbl) {
 			for (i = 0; i < IWL_RATE_COUNT; i++)
 				rs_rate_scale_clear_window(&(tbl->win[i]));
 		}
 	}
 }
 
-static void rs_rate_scale_perform(struct iwl_priv *priv,
+/*
+ * Do rate scaling and search for new modulation mode.
+ */
+static void rs_rate_scale_perform(struct iwl4965_priv *priv,
 				  struct net_device *dev,
 				  struct ieee80211_hdr *hdr,
 				  struct sta_info *sta)
 {
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = local_to_hw(local);
+	struct ieee80211_conf *conf = &hw->conf;
 	int low = IWL_RATE_INVALID;
 	int high = IWL_RATE_INVALID;
 	int index;
 	int i;
-	struct iwl_rate_scale_data *window = NULL;
+	struct iwl4965_rate_scale_data *window = NULL;
 	int current_tpt = IWL_INVALID_VALUE;
 	int low_tpt = IWL_INVALID_VALUE;
 	int high_tpt = IWL_INVALID_VALUE;
@@ -1348,10 +1566,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 	s8 scale_action = 0;
 	u16 fc, rate_mask;
 	u8 update_lq = 0;
-	struct iwl_rate_scale_priv *lq_data;
-	struct iwl_scale_tbl_info *tbl, *tbl1;
+	struct iwl4965_lq_sta *lq_sta;
+	struct iwl4965_scale_tbl_info *tbl, *tbl1;
 	u16 rate_scale_index_msk = 0;
-	struct iwl_rate mcs_rate;
+	struct iwl4965_rate mcs_rate;
 	u8 is_green = 0;
 	u8 active_tbl = 0;
 	u8 done_search = 0;
@@ -1374,34 +1592,42 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 		IWL_DEBUG_RATE("still rate scaling not ready\n");
 		return;
 	}
-	lq_data = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+	lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
 
-	if (!lq_data->search_better_tbl)
-		active_tbl = lq_data->active_tbl;
+	/*
+	 * Select rate-scale / modulation-mode table to work with in
+	 * the rest of this function:  "search" if searching for better
+	 * modulation mode, or "active" if doing rate scaling within a mode.
+	 */
+	if (!lq_sta->search_better_tbl)
+		active_tbl = lq_sta->active_tbl;
 	else
-		active_tbl = 1 - lq_data->active_tbl;
+		active_tbl = 1 - lq_sta->active_tbl;
 
-	tbl = &(lq_data->lq_info[active_tbl]);
-	is_green = lq_data->is_green;
+	tbl = &(lq_sta->lq_info[active_tbl]);
+	is_green = lq_sta->is_green;
 
+	/* current tx rate */
 	index = sta->last_txrate;
 
 	IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index,
 		       tbl->lq_type);
 
-	rs_get_supported_rates(lq_data, hdr, tbl->lq_type,
+	/* rates available for this association, and for modulation mode */
+	rs_get_supported_rates(lq_sta, hdr, tbl->lq_type,
 				&rate_mask);
 
 	IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask);
 
 	/* mask with station rate restriction */
 	if (is_legacy(tbl->lq_type)) {
-		if (lq_data->phymode == (u8) MODE_IEEE80211A)
+		if (lq_sta->phymode == (u8) MODE_IEEE80211A)
+			/* supp_rates has no CCK bits in A mode */
 			rate_scale_index_msk = (u16) (rate_mask &
-				(lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
+				(lq_sta->supp_rates << IWL_FIRST_OFDM_RATE));
 		else
 			rate_scale_index_msk = (u16) (rate_mask &
-						      lq_data->supp_rates);
+						      lq_sta->supp_rates);
 
 	} else
 		rate_scale_index_msk = rate_mask;
@@ -1409,11 +1635,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 	if (!rate_scale_index_msk)
 		rate_scale_index_msk = rate_mask;
 
+	/* If current rate is no longer supported on current association,
+	 * or user changed preferences for rates, find a new supported rate. */
 	if (index < 0 || !((1 << index) & rate_scale_index_msk)) {
 		index = IWL_INVALID_VALUE;
 		update_lq = 1;
 
-		/* get the lowest availabe rate */
+		/* get the highest available rate */
 		for (i = 0; i <= IWL_RATE_COUNT; i++) {
 			if ((1 << i) & rate_scale_index_msk)
 				index = i;
@@ -1425,11 +1653,19 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 		}
 	}
 
+	/* Get expected throughput table and history window for current rate */
 	if (!tbl->expected_tpt)
-		rs_get_expected_tpt_table(lq_data, tbl);
+		rs_get_expected_tpt_table(lq_sta, tbl);
 
 	window = &(tbl->win[index]);
 
+	/*
+	 * If there is not enough history to calculate actual average
+	 * throughput, keep analyzing results of more tx frames, without
+	 * changing rate or mode (bypass most of the rest of this function).
+	 * Set up new rate table in uCode only if old rate is not supported
+	 * in current association (use new rate found above).
+	 */
 	fail_count = window->counter - window->success_counter;
 	if (((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
 	     (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))
@@ -1437,82 +1673,118 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 		IWL_DEBUG_RATE("LQ: still below TH succ %d total %d "
 			       "for index %d\n",
 			       window->success_counter, window->counter, index);
+
+		/* Can't calculate this yet; not enough history */
 		window->average_tpt = IWL_INVALID_VALUE;
-		rs_stay_in_table(lq_data);
+
+		/* Should we stay with this modulation mode,
+		 * or search for a new one? */
+		rs_stay_in_table(lq_sta);
+
+		/* Set up new rate table in uCode, if needed */
 		if (update_lq) {
 			rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
-			rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
-			rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+			rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
+			rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
 		}
 		goto out;
 
+	/* Else we have enough samples; calculate estimate of
+	 * actual average throughput */
 	} else
 		window->average_tpt = ((window->success_ratio *
 					tbl->expected_tpt[index] + 64) / 128);
 
-	if (lq_data->search_better_tbl) {
+	/* If we are searching for better modulation mode, check success. */
+	if (lq_sta->search_better_tbl) {
 		int success_limit = IWL_RATE_SCALE_SWITCH;
 
+		/* If good success, continue using the "search" mode;
+		 * no need to send new link quality command, since we're
+		 * continuing to use the setup that we've been trying. */
 		if ((window->success_ratio > success_limit) ||
-		    (window->average_tpt > lq_data->last_tpt)) {
+		    (window->average_tpt > lq_sta->last_tpt)) {
 			if (!is_legacy(tbl->lq_type)) {
 				IWL_DEBUG_HT("LQ: we are switching to HT"
 					     " rate suc %d current tpt %d"
 					     " old tpt %d\n",
 					     window->success_ratio,
 					     window->average_tpt,
-					     lq_data->last_tpt);
-				lq_data->enable_counter = 1;
+					     lq_sta->last_tpt);
+				lq_sta->enable_counter = 1;
 			}
-			lq_data->active_tbl = active_tbl;
+			/* Swap tables; "search" becomes "active" */
+			lq_sta->active_tbl = active_tbl;
 			current_tpt = window->average_tpt;
+
+		/* Else poor success; go back to mode in "active" table */
 		} else {
+			/* Nullify "search" table */
 			tbl->lq_type = LQ_NONE;
-			active_tbl = lq_data->active_tbl;
-			tbl = &(lq_data->lq_info[active_tbl]);
 
-			index = iwl_rate_index_from_plcp(
+			/* Revert to "active" table */
+			active_tbl = lq_sta->active_tbl;
+			tbl = &(lq_sta->lq_info[active_tbl]);
+
+			/* Revert to "active" rate and throughput info */
+			index = iwl4965_rate_index_from_plcp(
 				tbl->current_rate.rate_n_flags);
+			current_tpt = lq_sta->last_tpt;
 
+			/* Need to set up a new rate table in uCode */
 			update_lq = 1;
-			current_tpt = lq_data->last_tpt;
 			IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n");
 		}
-		lq_data->search_better_tbl = 0;
-		done_search = 1;
+
+		/* Either way, we've made a decision; modulation mode
+		 * search is done, allow rate adjustment next time. */
+		lq_sta->search_better_tbl = 0;
+		done_search = 1;	/* Don't switch modes below! */
 		goto lq_update;
 	}
 
+	/* (Else) not in search of better modulation mode, try for better
+	 * starting rate, while staying in this mode. */
 	high_low = rs_get_adjacent_rate(index, rate_scale_index_msk,
 					tbl->lq_type);
 	low = high_low & 0xff;
 	high = (high_low >> 8) & 0xff;
 
+	/* Collect measured throughputs for current and adjacent rates */
 	current_tpt = window->average_tpt;
-
 	if (low != IWL_RATE_INVALID)
 		low_tpt = tbl->win[low].average_tpt;
-
 	if (high != IWL_RATE_INVALID)
 		high_tpt = tbl->win[high].average_tpt;
 
-
+	/* Assume rate increase */
 	scale_action = 1;
 
+	/* Too many failures, decrease rate */
 	if ((window->success_ratio <= IWL_RATE_DECREASE_TH) ||
 	    (current_tpt == 0)) {
 		IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
 		scale_action = -1;
+
+	/* No throughput measured yet for adjacent rates; try increase. */
 	} else if ((low_tpt == IWL_INVALID_VALUE) &&
 		   (high_tpt == IWL_INVALID_VALUE))
 		scale_action = 1;
+
+	/* Both adjacent throughputs are measured, but neither one has better
+	 * throughput; we're using the best rate, don't change it! */
 	else if ((low_tpt != IWL_INVALID_VALUE) &&
 		 (high_tpt != IWL_INVALID_VALUE) &&
 		 (low_tpt < current_tpt) &&
 		 (high_tpt < current_tpt))
 		scale_action = 0;
+
+	/* At least one adjacent rate's throughput is measured,
+	 * and may have better performance. */
 	else {
+		/* Higher adjacent rate's throughput is measured */
 		if (high_tpt != IWL_INVALID_VALUE) {
+			/* Higher rate has better throughput */
 			if (high_tpt > current_tpt)
 				scale_action = 1;
 			else {
@@ -1520,7 +1792,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 				    ("decrease rate because of high tpt\n");
 				scale_action = -1;
 			}
+
+		/* Lower adjacent rate's throughput is measured */
 		} else if (low_tpt != IWL_INVALID_VALUE) {
+			/* Lower rate has better throughput */
 			if (low_tpt > current_tpt) {
 				IWL_DEBUG_RATE
 				    ("decrease rate because of low tpt\n");
@@ -1530,23 +1805,30 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 		}
 	}
 
+	/* Sanity check; asked for decrease, but success rate or throughput
+	 * has been good at old rate.  Don't change it. */
 	if (scale_action == -1) {
 		if ((low != IWL_RATE_INVALID) &&
 		    ((window->success_ratio > IWL_RATE_HIGH_TH) ||
 		     (current_tpt > (100 * tbl->expected_tpt[low]))))
 			scale_action = 0;
+
+	/* Sanity check; asked for increase, but success rate has not been great
+	 * even at old rate, higher rate will be worse.  Don't change it. */
 	} else if ((scale_action == 1) &&
 		   (window->success_ratio < IWL_RATE_INCREASE_TH))
 		scale_action = 0;
 
 	switch (scale_action) {
 	case -1:
+		/* Decrease starting rate, update uCode's rate table */
 		if (low != IWL_RATE_INVALID) {
 			update_lq = 1;
 			index = low;
 		}
 		break;
 	case 1:
+		/* Increase starting rate, update uCode's rate table */
 		if (high != IWL_RATE_INVALID) {
 			update_lq = 1;
 			index = high;
@@ -1554,6 +1836,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 
 		break;
 	case 0:
+		/* No change */
 	default:
 		break;
 	}
@@ -1563,65 +1846,97 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 		     index, scale_action, low, high, tbl->lq_type);
 
  lq_update:
+	/* Replace uCode's rate table for the destination station. */
 	if (update_lq) {
 		rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
-		rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
-		rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+		rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
+		rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
 	}
-	rs_stay_in_table(lq_data);
 
-	if (!update_lq && !done_search && !lq_data->stay_in_tbl) {
-		lq_data->last_tpt = current_tpt;
+	/* Should we stay with this modulation mode, or search for a new one? */
+	rs_stay_in_table(lq_sta);
 
+	/*
+	 * Search for new modulation mode if we're:
+	 * 1)  Not changing rates right now
+	 * 2)  Not just finishing up a search
+	 * 3)  Allowing a new search
+	 */
+	if (!update_lq && !done_search && !lq_sta->stay_in_tbl) {
+		/* Save current throughput to compare with "search" throughput*/
+		lq_sta->last_tpt = current_tpt;
+
+		/* Select a new "search" modulation mode to try.
+		 * If one is found, set up the new "search" table. */
 		if (is_legacy(tbl->lq_type))
-			rs_move_legacy_other(priv, lq_data, index);
+			rs_move_legacy_other(priv, lq_sta, conf, sta, index);
 		else if (is_siso(tbl->lq_type))
-			rs_move_siso_to_other(priv, lq_data, index);
+			rs_move_siso_to_other(priv, lq_sta, conf, sta, index);
 		else
-			rs_move_mimo_to_other(priv, lq_data, index);
+			rs_move_mimo_to_other(priv, lq_sta, conf, sta, index);
 
-		if (lq_data->search_better_tbl) {
-			tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+		/* If new "search" mode was selected, set up in uCode table */
+		if (lq_sta->search_better_tbl) {
+			/* Access the "search" table, clear its history. */
+			tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
 			for (i = 0; i < IWL_RATE_COUNT; i++)
 				rs_rate_scale_clear_window(&(tbl->win[i]));
 
-			index = iwl_rate_index_from_plcp(
+			/* Use new "search" start rate */
+			index = iwl4965_rate_index_from_plcp(
 					tbl->current_rate.rate_n_flags);
 
 			IWL_DEBUG_HT("Switch current  mcs: %X index: %d\n",
 				     tbl->current_rate.rate_n_flags, index);
-			rs_fill_link_cmd(lq_data, &tbl->current_rate,
-					 &lq_data->lq);
-			rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+			rs_fill_link_cmd(lq_sta, &tbl->current_rate,
+					 &lq_sta->lq);
+			rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
 		}
-		tbl1 = &(lq_data->lq_info[lq_data->active_tbl]);
 
+		/* If the "active" (non-search) mode was legacy,
+		 * and we've tried switching antennas,
+		 * but we haven't been able to try HT modes (not available),
+		 * stay with best antenna legacy modulation for a while
+		 * before next round of mode comparisons. */
+		tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
 		if (is_legacy(tbl1->lq_type) &&
-#ifdef CONFIG_IWLWIFI_HT
-		    !priv->current_assoc_ht.is_ht &&
+#ifdef CONFIG_IWL4965_HT
+		   (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) &&
 #endif
-		    (lq_data->action_counter >= 1)) {
-			lq_data->action_counter = 0;
+		    (lq_sta->action_counter >= 1)) {
+			lq_sta->action_counter = 0;
 			IWL_DEBUG_HT("LQ: STAY in legacy table\n");
-			rs_set_stay_in_table(1, lq_data);
+			rs_set_stay_in_table(1, lq_sta);
 		}
 
-		if (lq_data->enable_counter &&
-		    (lq_data->action_counter >= IWL_ACTION_LIMIT)) {
-#ifdef CONFIG_IWLWIFI_HT_AGG
-			if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) &&
+		/* If we're in an HT mode, and all 3 mode switch actions
+		 * have been tried and compared, stay in this best modulation
+		 * mode for a while before next round of mode comparisons. */
+		if (lq_sta->enable_counter &&
+		    (lq_sta->action_counter >= IWL_ACTION_LIMIT)) {
+#ifdef CONFIG_IWL4965_HT_AGG
+			/* If appropriate, set up aggregation! */
+			if ((lq_sta->last_tpt > TID_AGG_TPT_THREHOLD) &&
 			    (priv->lq_mngr.agg_ctrl.auto_agg)) {
 				priv->lq_mngr.agg_ctrl.tid_retry =
 				    TID_ALL_SPECIFIED;
 				schedule_work(&priv->agg_work);
 			}
-#endif /*CONFIG_IWLWIFI_HT_AGG */
-			lq_data->action_counter = 0;
-			rs_set_stay_in_table(0, lq_data);
+#endif /*CONFIG_IWL4965_HT_AGG */
+			lq_sta->action_counter = 0;
+			rs_set_stay_in_table(0, lq_sta);
 		}
+
+	/*
+	 * Else, don't search for a new modulation mode.
+	 * Put new timestamp in stay-in-modulation-mode flush timer if:
+	 * 1)  Not changing rates right now
+	 * 2)  Not just finishing up a search
+	 * 3)  flush timer is empty
+	 */
 	} else {
-		if ((!update_lq) && (!done_search) && (!lq_data->flush_timer))
-			lq_data->flush_timer = jiffies;
+		if ((!update_lq) && (!done_search) && (!lq_sta->flush_timer))
+			lq_sta->flush_timer = jiffies;
 	}
 
 out:
@@ -1632,7 +1947,7 @@ out:
 	/* sta->txrate is an index to A mode rates which start
 	 * at IWL_FIRST_OFDM_RATE
 	 */
-	if (lq_data->phymode == (u8) MODE_IEEE80211A)
+	if (lq_sta->phymode == (u8) MODE_IEEE80211A)
 		sta->txrate = i - IWL_FIRST_OFDM_RATE;
 	else
 		sta->txrate = i;
@@ -1641,38 +1956,39 @@ out:
 }
 
 
-static void rs_initialize_lq(struct iwl_priv *priv,
+static void rs_initialize_lq(struct iwl4965_priv *priv,
+			     struct ieee80211_conf *conf,
 			     struct sta_info *sta)
 {
 	int i;
-	struct iwl_rate_scale_priv *lq;
-	struct iwl_scale_tbl_info *tbl;
+	struct iwl4965_lq_sta *lq_sta;
+	struct iwl4965_scale_tbl_info *tbl;
 	u8 active_tbl = 0;
 	int rate_idx;
-	u8 use_green = rs_use_green(priv);
-	struct iwl_rate mcs_rate;
+	u8 use_green = rs_use_green(priv, conf);
+	struct iwl4965_rate mcs_rate;
 
 	if (!sta || !sta->rate_ctrl_priv)
 		goto out;
 
-	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+	lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
 	i = sta->last_txrate;
 
-	if ((lq->lq.sta_id == 0xff) &&
+	if ((lq_sta->lq.sta_id == 0xff) &&
 	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
 		goto out;
 
-	if (!lq->search_better_tbl)
-		active_tbl = lq->active_tbl;
+	if (!lq_sta->search_better_tbl)
+		active_tbl = lq_sta->active_tbl;
 	else
-		active_tbl = 1 - lq->active_tbl;
+		active_tbl = 1 - lq_sta->active_tbl;
 
-	tbl = &(lq->lq_info[active_tbl]);
+	tbl = &(lq_sta->lq_info[active_tbl]);
 
 	if ((i < 0) || (i >= IWL_RATE_COUNT))
 		i = 0;
 
-	mcs_rate.rate_n_flags = iwl_rates[i].plcp ;
+	mcs_rate.rate_n_flags = iwl4965_rates[i].plcp ;
 	mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;
 	mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
 
@@ -1686,114 +2002,95 @@ static void rs_initialize_lq(struct iwl_priv *priv,
 
 	rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green);
 	tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;
-	rs_get_expected_tpt_table(lq, tbl);
-	rs_fill_link_cmd(lq, &mcs_rate, &lq->lq);
-	rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC);
+	rs_get_expected_tpt_table(lq_sta, tbl);
+	rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq);
+	rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
  out:
 	return;
 }
 
-static struct ieee80211_rate *rs_get_lowest_rate(struct ieee80211_local
-						 *local)
-{
-	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
-	int i;
-
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *rate = &mode->rates[i];
-
-		if (rate->flags & IEEE80211_RATE_SUPPORTED)
-			return rate;
-	}
-
-	return &mode->rates[0];
-}
-
-static struct ieee80211_rate *rs_get_rate(void *priv_rate,
-					       struct net_device *dev,
-					       struct sk_buff *skb,
-					       struct rate_control_extra
-					       *extra)
+static void rs_get_rate(void *priv_rate, struct net_device *dev,
+			struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+			struct rate_selection *sel)
 {
 
 	int i;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_conf *conf = &local->hw.conf;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	struct sta_info *sta;
 	u16 fc;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
-	struct iwl_rate_scale_priv *lq;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
+	struct iwl4965_lq_sta *lq_sta;
 
 	IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
 
-	memset(extra, 0, sizeof(*extra));
-
-	fc = le16_to_cpu(hdr->frame_control);
-	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
-		/* Send management frames and broadcast/multicast data using
-		 * lowest rate. */
-		/* TODO: this could probably be improved.. */
-		return rs_get_lowest_rate(local);
-	}
-
 	sta = sta_info_get(local, hdr->addr1);
 
-	if (!sta || !sta->rate_ctrl_priv) {
+	/* Send management frames and broadcast/multicast data using lowest
+	 * rate. */
+	fc = le16_to_cpu(hdr->frame_control);
+	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
+	    !sta || !sta->rate_ctrl_priv) {
+		sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
 		if (sta)
 			sta_info_put(sta);
-		return rs_get_lowest_rate(local);
+		return;
 	}
 
-	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+	lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
 	i = sta->last_txrate;
 
-	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) {
-		u8 sta_id = iwl_hw_find_station(priv, hdr->addr1);
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	    !lq_sta->ibss_sta_added) {
+		u8 sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
 		DECLARE_MAC_BUF(mac);
 
 		if (sta_id == IWL_INVALID_STATION) {
 			IWL_DEBUG_RATE("LQ: ADD station %s\n",
 				       print_mac(mac, hdr->addr1));
-			sta_id = iwl_add_station(priv,
-						 hdr->addr1, 0, CMD_ASYNC);
+			sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
+							0, CMD_ASYNC, NULL);
 		}
 		if ((sta_id != IWL_INVALID_STATION)) {
-			lq->lq.sta_id = sta_id;
-			lq->lq.rs_table[0].rate_n_flags = 0;
-			lq->ibss_sta_added = 1;
-			rs_initialize_lq(priv, sta);
+			lq_sta->lq.sta_id = sta_id;
+			lq_sta->lq.rs_table[0].rate_n_flags = 0;
+			lq_sta->ibss_sta_added = 1;
+			rs_initialize_lq(priv, conf, sta);
 		}
-		if (!lq->ibss_sta_added)
+		if (!lq_sta->ibss_sta_added)
 			goto done;
 	}
 
  done:
+	if ((i < 0) || (i > IWL_RATE_COUNT)) {
+		sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
+		return;
+	}
 	sta_info_put(sta);
-	if ((i < 0) || (i > IWL_RATE_COUNT))
-		return rs_get_lowest_rate(local);
 
-	return &priv->ieee_rates[i];
+	sel->rate = &priv->ieee_rates[i];
 }
 
 static void *rs_alloc_sta(void *priv, gfp_t gfp)
 {
-	struct iwl_rate_scale_priv *crl;
+	struct iwl4965_lq_sta *lq_sta;
 	int i, j;
 
 	IWL_DEBUG_RATE("create station rate scale window\n");
 
-	crl = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp);
+	lq_sta = kzalloc(sizeof(struct iwl4965_lq_sta), gfp);
 
-	if (crl == NULL)
+	if (lq_sta == NULL)
 		return NULL;
-	crl->lq.sta_id = 0xff;
+	lq_sta->lq.sta_id = 0xff;
 
 
 	for (j = 0; j < LQ_SIZE; j++)
 		for (i = 0; i < IWL_RATE_COUNT; i++)
-			rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));
+			rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i]));
 
-	return crl;
+	return lq_sta;
 }
 
 static void rs_rate_init(void *priv_rate, void *priv_sta,
@@ -1801,16 +2098,17 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
 			 struct sta_info *sta)
 {
 	int i, j;
+	struct ieee80211_conf *conf = &local->hw.conf;
 	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
-	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
-	struct iwl_rate_scale_priv *crl = priv_sta;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate;
+	struct iwl4965_lq_sta *lq_sta = priv_sta;
 
-	crl->flush_timer = 0;
-	crl->supp_rates = sta->supp_rates;
+	lq_sta->flush_timer = 0;
+	lq_sta->supp_rates = sta->supp_rates;
 	sta->txrate = 3;
 	for (j = 0; j < LQ_SIZE; j++)
 		for (i = 0; i < IWL_RATE_COUNT; i++)
-			rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));
+			rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i]));
 
 	IWL_DEBUG_RATE("rate scale global init\n");
 	/* TODO: what is a good starting rate for STA? About middle? Maybe not
@@ -1818,9 +2116,9 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
 	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
 	 * after assoc.. */
 
-	crl->ibss_sta_added = 0;
+	lq_sta->ibss_sta_added = 0;
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
-		u8 sta_id = iwl_hw_find_station(priv, sta->addr);
+		u8 sta_id = iwl4965_hw_find_station(priv, sta->addr);
 		DECLARE_MAC_BUF(mac);
 
 		/* for IBSS the call are from tasklet */
@@ -1830,77 +2128,89 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
 		if (sta_id == IWL_INVALID_STATION) {
 			IWL_DEBUG_RATE("LQ: ADD station %s\n",
 				       print_mac(mac, sta->addr));
-			sta_id = iwl_add_station(priv,
-						 sta->addr, 0, CMD_ASYNC);
+			sta_id = iwl4965_add_station_flags(priv, sta->addr,
+							0, CMD_ASYNC, NULL);
 		}
 		if ((sta_id != IWL_INVALID_STATION)) {
-			crl->lq.sta_id = sta_id;
-			crl->lq.rs_table[0].rate_n_flags = 0;
+			lq_sta->lq.sta_id = sta_id;
+			lq_sta->lq.rs_table[0].rate_n_flags = 0;
 		}
 		/* FIXME: this is w/a remove it later */
 		priv->assoc_station_added = 1;
 	}
 
+	/* Find highest tx rate supported by hardware and destination station */
 	for (i = 0; i < mode->num_rates; i++) {
 		if ((sta->supp_rates & BIT(i)) &&
 		    (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
 			sta->txrate = i;
 	}
 	sta->last_txrate = sta->txrate;
-	/* For MODE_IEEE80211A mode cck rate are at end
-	 * rate table
-	 */
+	/* For MODE_IEEE80211A, cck rates are at end of rate table */
 	if (local->hw.conf.phymode == MODE_IEEE80211A)
 		sta->last_txrate += IWL_FIRST_OFDM_RATE;
 
-	crl->is_dup = priv->is_dup;
-	crl->valid_antenna = priv->valid_antenna;
-	crl->antenna = priv->antenna;
-	crl->is_green = rs_use_green(priv);
-	crl->active_rate = priv->active_rate;
-	crl->active_rate &= ~(0x1000);
-	crl->active_rate_basic = priv->active_rate_basic;
-	crl->phymode = priv->phymode;
-#ifdef CONFIG_IWLWIFI_HT
-	crl->active_siso_rate = (priv->current_assoc_ht.supp_rates[0] << 1);
-	crl->active_siso_rate |= (priv->current_assoc_ht.supp_rates[0] & 0x1);
-	crl->active_siso_rate &= ~((u16)0x2);
-	crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE;
-
-	crl->active_mimo_rate = (priv->current_assoc_ht.supp_rates[1] << 1);
-	crl->active_mimo_rate |= (priv->current_assoc_ht.supp_rates[1] & 0x1);
-	crl->active_mimo_rate &= ~((u16)0x2);
-	crl->active_mimo_rate = crl->active_mimo_rate << IWL_FIRST_OFDM_RATE;
-	IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate,
-		     crl->active_mimo_rate);
-#endif /*CONFIG_IWLWIFI_HT*/
+	lq_sta->is_dup = 0;
+	lq_sta->valid_antenna = priv->valid_antenna;
+	lq_sta->antenna = priv->antenna;
+	lq_sta->is_green = rs_use_green(priv, conf);
+	lq_sta->active_rate = priv->active_rate;
+	lq_sta->active_rate &= ~(0x1000);
+	lq_sta->active_rate_basic = priv->active_rate_basic;
+	lq_sta->phymode = priv->phymode;
+#ifdef CONFIG_IWL4965_HT
+	/*
+	 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
+	 * supp_rates[] does not; shift to convert format, force 9 MBits off.
+	 */
+	lq_sta->active_siso_rate = (priv->current_ht_config.supp_mcs_set[0] << 1);
+	lq_sta->active_siso_rate |=
+			(priv->current_ht_config.supp_mcs_set[0] & 0x1);
+	lq_sta->active_siso_rate &= ~((u16)0x2);
+	lq_sta->active_siso_rate =
+			lq_sta->active_siso_rate << IWL_FIRST_OFDM_RATE;
+
+	/* Same here */
+	lq_sta->active_mimo_rate = (priv->current_ht_config.supp_mcs_set[1] << 1);
+	lq_sta->active_mimo_rate |=
+			(priv->current_ht_config.supp_mcs_set[1] & 0x1);
+	lq_sta->active_mimo_rate &= ~((u16)0x2);
+	lq_sta->active_mimo_rate =
+			lq_sta->active_mimo_rate << IWL_FIRST_OFDM_RATE;
+	IWL_DEBUG_HT("SISO RATE 0x%X MIMO RATE 0x%X\n",
+		     lq_sta->active_siso_rate,
+		     lq_sta->active_mimo_rate);
+#endif /*CONFIG_IWL4965_HT*/
 #ifdef CONFIG_MAC80211_DEBUGFS
-	crl->drv = priv;
+	lq_sta->drv = priv;
 #endif
 
 	if (priv->assoc_station_added)
 		priv->lq_mngr.lq_ready = 1;
 
-	rs_initialize_lq(priv, sta);
+	rs_initialize_lq(priv, conf, sta);
 }
 
-static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
-			    struct iwl_rate *tx_mcs,
-			    struct iwl_link_quality_cmd *lq_cmd)
+static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta,
+			    struct iwl4965_rate *tx_mcs,
+			    struct iwl4965_link_quality_cmd *lq_cmd)
 {
 	int index = 0;
 	int rate_idx;
 	int repeat_rate = 0;
 	u8 ant_toggle_count = 0;
 	u8 use_ht_possible = 1;
-	struct iwl_rate new_rate;
-	struct iwl_scale_tbl_info tbl_type = { 0 };
+	struct iwl4965_rate new_rate;
+	struct iwl4965_scale_tbl_info tbl_type = { 0 };
 
-	rs_dbgfs_set_mcs(lq_data, tx_mcs, index);
+	/* Override starting rate (index 0) if needed for debug purposes */
+	rs_dbgfs_set_mcs(lq_sta, tx_mcs, index);
 
-	rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode,
+	/* Interpret rate_n_flags */
+	rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->phymode,
 				  &tbl_type, &rate_idx);
 
+	/* How many times should we repeat the initial rate? */
 	if (is_legacy(tbl_type.lq_type)) {
 		ant_toggle_count = 1;
 		repeat_rate = IWL_NUMBER_TRY;
@@ -1909,19 +2219,27 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
 
 	lq_cmd->general_params.mimo_delimiter =
 			is_mimo(tbl_type.lq_type) ? 1 : 0;
+
+	/* Fill 1st table entry (index 0) */
 	lq_cmd->rs_table[index].rate_n_flags =
 			cpu_to_le32(tx_mcs->rate_n_flags);
 	new_rate.rate_n_flags = tx_mcs->rate_n_flags;
 
 	if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN))
-		lq_cmd->general_params.single_stream_ant_msk = 1;
+		lq_cmd->general_params.single_stream_ant_msk
+			= LINK_QUAL_ANT_A_MSK;
 	else
-		lq_cmd->general_params.single_stream_ant_msk = 2;
+		lq_cmd->general_params.single_stream_ant_msk
+			= LINK_QUAL_ANT_B_MSK;
 
 	index++;
 	repeat_rate--;
 
+	/* Fill rest of rate table */
 	while (index < LINK_QUAL_MAX_RETRY_NUM) {
+		/* Repeat initial/next rate.
+		 * For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
+		 * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
 		while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
 			if (is_legacy(tbl_type.lq_type)) {
 				if (ant_toggle_count <
@@ -1933,22 +2251,30 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
 				}
 			}
 
-			rs_dbgfs_set_mcs(lq_data, &new_rate, index);
+			/* Override next rate if needed for debug purposes */
+			rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+			/* Fill next table entry */
 			lq_cmd->rs_table[index].rate_n_flags =
 					cpu_to_le32(new_rate.rate_n_flags);
 			repeat_rate--;
 			index++;
 		}
 
-		rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type,
+		rs_get_tbl_info_from_mcs(&new_rate, lq_sta->phymode, &tbl_type,
 						&rate_idx);
 
+		/* Indicate to uCode which entries might be MIMO.
+		 * If initial rate was MIMO, this will finally end up
+		 * as (IWL_HT_NUMBER_TRY * 2), after 2nd pass, otherwise 0. */
 		if (is_mimo(tbl_type.lq_type))
 			lq_cmd->general_params.mimo_delimiter = index;
 
-		rs_get_lower_rate(lq_data, &tbl_type, rate_idx,
+		/* Get next rate */
+		rs_get_lower_rate(lq_sta, &tbl_type, rate_idx,
 				  use_ht_possible, &new_rate);
 
+		/* How many times should we repeat the next rate? */
 		if (is_legacy(tbl_type.lq_type)) {
 			if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE)
 				ant_toggle_count++;
@@ -1960,9 +2286,14 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
 		} else
 			repeat_rate = IWL_HT_NUMBER_TRY;
 
+		/* Don't allow HT rates after next pass.
+		 * rs_get_lower_rate() will change type to LQ_A or LQ_G. */
 		use_ht_possible = 0;
 
-		rs_dbgfs_set_mcs(lq_data, &new_rate, index);
+		/* Override next rate if needed for debug purposes */
+		rs_dbgfs_set_mcs(lq_sta, &new_rate, index);
+
+		/* Fill next table entry */
 		lq_cmd->rs_table[index].rate_n_flags =
 				cpu_to_le32(new_rate.rate_n_flags);
 
@@ -1987,27 +2318,27 @@ static void rs_free(void *priv_rate)
 
 static void rs_clear(void *priv_rate)
 {
-	struct iwl_priv *priv = (struct iwl_priv *) priv_rate;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *) priv_rate;
 
 	IWL_DEBUG_RATE("enter\n");
 
 	priv->lq_mngr.lq_ready = 0;
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 	if (priv->lq_mngr.agg_ctrl.granted_ba)
 		iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);
-#endif /*CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
+#endif /*CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 
 	IWL_DEBUG_RATE("leave\n");
 }
 
 static void rs_free_sta(void *priv, void *priv_sta)
 {
-	struct iwl_rate_scale_priv *rs_priv = priv_sta;
+	struct iwl4965_lq_sta *lq_sta = priv_sta;
 
 	IWL_DEBUG_RATE("enter\n");
-	kfree(rs_priv);
+	kfree(lq_sta);
 	IWL_DEBUG_RATE("leave\n");
 }
 
@@ -2018,19 +2349,19 @@ static int open_file_generic(struct inode *inode, struct file *file)
 	file->private_data = inode->i_private;
 	return 0;
 }
-static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
-				struct iwl_rate *mcs, int index)
+static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
+				struct iwl4965_rate *mcs, int index)
 {
 	u32 base_rate;
 
-	if (rs_priv->phymode == (u8) MODE_IEEE80211A)
+	if (lq_sta->phymode == (u8) MODE_IEEE80211A)
 		base_rate = 0x800D;
 	else
 		base_rate = 0x820A;
 
-	if (rs_priv->dbg_fixed.rate_n_flags) {
+	if (lq_sta->dbg_fixed.rate_n_flags) {
 		if (index < 12)
-			mcs->rate_n_flags = rs_priv->dbg_fixed.rate_n_flags;
+			mcs->rate_n_flags = lq_sta->dbg_fixed.rate_n_flags;
 		else
 			mcs->rate_n_flags = base_rate;
 		IWL_DEBUG_RATE("Fixed rate ON\n");
@@ -2043,7 +2374,7 @@ static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
 static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
 			const char __user *user_buf, size_t count, loff_t *ppos)
 {
-	struct iwl_rate_scale_priv *rs_priv = file->private_data;
+	struct iwl4965_lq_sta *lq_sta = file->private_data;
 	char buf[64];
 	int buf_size;
 	u32 parsed_rate;
@@ -2054,20 +2385,20 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
 		return -EFAULT;
 
 	if (sscanf(buf, "%x", &parsed_rate) == 1)
-		rs_priv->dbg_fixed.rate_n_flags = parsed_rate;
+		lq_sta->dbg_fixed.rate_n_flags = parsed_rate;
 	else
-		rs_priv->dbg_fixed.rate_n_flags = 0;
+		lq_sta->dbg_fixed.rate_n_flags = 0;
 
-	rs_priv->active_rate = 0x0FFF;
-	rs_priv->active_siso_rate = 0x1FD0;
-	rs_priv->active_mimo_rate = 0x1FD0;
+	lq_sta->active_rate = 0x0FFF;	/* 1 - 54 MBits, includes CCK */
+	lq_sta->active_siso_rate = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
+	lq_sta->active_mimo_rate = 0x1FD0;	/* 6 - 60 MBits, no 9, no CCK */
 
 	IWL_DEBUG_RATE("sta_id %d rate 0x%X\n",
-		rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags);
+		lq_sta->lq.sta_id, lq_sta->dbg_fixed.rate_n_flags);
 
-	if (rs_priv->dbg_fixed.rate_n_flags) {
-		rs_fill_link_cmd(rs_priv, &rs_priv->dbg_fixed, &rs_priv->lq);
-		rs_send_lq_cmd(rs_priv->drv, &rs_priv->lq, CMD_ASYNC);
+	if (lq_sta->dbg_fixed.rate_n_flags) {
+		rs_fill_link_cmd(lq_sta, &lq_sta->dbg_fixed, &lq_sta->lq);
+		rs_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC);
 	}
 
 	return count;
@@ -2080,38 +2411,38 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
 	int desc = 0;
 	int i = 0;
 
-	struct iwl_rate_scale_priv *rs_priv = file->private_data;
+	struct iwl4965_lq_sta *lq_sta = file->private_data;
 
-	desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id);
+	desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
 	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
-			rs_priv->total_failed, rs_priv->total_success,
-			rs_priv->active_rate);
+			lq_sta->total_failed, lq_sta->total_success,
+			lq_sta->active_rate);
 	desc += sprintf(buff+desc, "fixed rate 0x%X\n",
-			rs_priv->dbg_fixed.rate_n_flags);
+			lq_sta->dbg_fixed.rate_n_flags);
 	desc += sprintf(buff+desc, "general:"
 		"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
-		rs_priv->lq.general_params.flags,
-		rs_priv->lq.general_params.mimo_delimiter,
-		rs_priv->lq.general_params.single_stream_ant_msk,
-		rs_priv->lq.general_params.dual_stream_ant_msk);
+		lq_sta->lq.general_params.flags,
+		lq_sta->lq.general_params.mimo_delimiter,
+		lq_sta->lq.general_params.single_stream_ant_msk,
+		lq_sta->lq.general_params.dual_stream_ant_msk);
 
 	desc += sprintf(buff+desc, "agg:"
 			"time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
-			le16_to_cpu(rs_priv->lq.agg_params.agg_time_limit),
-			rs_priv->lq.agg_params.agg_dis_start_th,
-			rs_priv->lq.agg_params.agg_frame_cnt_limit);
+			le16_to_cpu(lq_sta->lq.agg_params.agg_time_limit),
+			lq_sta->lq.agg_params.agg_dis_start_th,
+			lq_sta->lq.agg_params.agg_frame_cnt_limit);
 
 	desc += sprintf(buff+desc,
 			"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
-			rs_priv->lq.general_params.start_rate_index[0],
-			rs_priv->lq.general_params.start_rate_index[1],
-			rs_priv->lq.general_params.start_rate_index[2],
-			rs_priv->lq.general_params.start_rate_index[3]);
+			lq_sta->lq.general_params.start_rate_index[0],
+			lq_sta->lq.general_params.start_rate_index[1],
+			lq_sta->lq.general_params.start_rate_index[2],
+			lq_sta->lq.general_params.start_rate_index[3]);
 
 
 	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
 		desc += sprintf(buff+desc, " rate[%d] 0x%X\n",
-			i, le32_to_cpu(rs_priv->lq.rs_table[i].rate_n_flags));
+			i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
 
 	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
 }
@@ -2128,22 +2459,22 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
 	int desc = 0;
 	int i, j;
 
-	struct iwl_rate_scale_priv *rs_priv = file->private_data;
+	struct iwl4965_lq_sta *lq_sta = file->private_data;
 	for (i = 0; i < LQ_SIZE; i++) {
 		desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
 				"rate=0x%X\n",
-				rs_priv->active_tbl == i?"*":"x",
-				rs_priv->lq_info[i].lq_type,
-				rs_priv->lq_info[i].is_SGI,
-				rs_priv->lq_info[i].is_fat,
-				rs_priv->lq_info[i].is_dup,
-				rs_priv->lq_info[i].current_rate.rate_n_flags);
+				lq_sta->active_tbl == i?"*":"x",
+				lq_sta->lq_info[i].lq_type,
+				lq_sta->lq_info[i].is_SGI,
+				lq_sta->lq_info[i].is_fat,
+				lq_sta->lq_info[i].is_dup,
+				lq_sta->lq_info[i].current_rate.rate_n_flags);
 		for (j = 0; j < IWL_RATE_COUNT; j++) {
 			desc += sprintf(buff+desc,
-					"counter=%d success=%d %%=%d\n",
-					rs_priv->lq_info[i].win[j].counter,
-					rs_priv->lq_info[i].win[j].success_counter,
-					rs_priv->lq_info[i].win[j].success_ratio);
+				"counter=%d success=%d %%=%d\n",
+				lq_sta->lq_info[i].win[j].counter,
+				lq_sta->lq_info[i].win[j].success_counter,
+				lq_sta->lq_info[i].win[j].success_ratio);
 		}
 	}
 	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
@@ -2157,20 +2488,20 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
 static void rs_add_debugfs(void *priv, void *priv_sta,
 					struct dentry *dir)
 {
-	struct iwl_rate_scale_priv *rs_priv = priv_sta;
-	rs_priv->rs_sta_dbgfs_scale_table_file =
+	struct iwl4965_lq_sta *lq_sta = priv_sta;
+	lq_sta->rs_sta_dbgfs_scale_table_file =
 		debugfs_create_file("rate_scale_table", 0600, dir,
-				rs_priv, &rs_sta_dbgfs_scale_table_ops);
-	rs_priv->rs_sta_dbgfs_stats_table_file =
+				lq_sta, &rs_sta_dbgfs_scale_table_ops);
+	lq_sta->rs_sta_dbgfs_stats_table_file =
 		debugfs_create_file("rate_stats_table", 0600, dir,
-			rs_priv, &rs_sta_dbgfs_stats_table_ops);
+			lq_sta, &rs_sta_dbgfs_stats_table_ops);
 }
 
 static void rs_remove_debugfs(void *priv, void *priv_sta)
 {
-	struct iwl_rate_scale_priv *rs_priv = priv_sta;
-	debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file);
-	debugfs_remove(rs_priv->rs_sta_dbgfs_stats_table_file);
+	struct iwl4965_lq_sta *lq_sta = priv_sta;
+	debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
+	debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
 }
 #endif
 
@@ -2191,13 +2522,13 @@ static struct rate_control_ops rs_ops = {
 #endif
 };
 
-int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
+int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
-	struct iwl_priv *priv = hw->priv;
-	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl4965_priv *priv = hw->priv;
+	struct iwl4965_lq_sta *lq_sta;
 	struct sta_info *sta;
-	int count = 0, i;
+	int cnt = 0, i;
 	u32 samples = 0, success = 0, good = 0;
 	unsigned long now = jiffies;
 	u32 max_time = 0;
@@ -2213,10 +2544,10 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 		return sprintf(buf, "station %d not found\n", sta_id);
 	}
 
-	rs_priv = (void *)sta->rate_ctrl_priv;
+	lq_sta = (void *)sta->rate_ctrl_priv;
 
-	lq_type = rs_priv->lq_info[rs_priv->active_tbl].lq_type;
-	antenna = rs_priv->lq_info[rs_priv->active_tbl].antenna_type;
+	lq_type = lq_sta->lq_info[lq_sta->active_tbl].lq_type;
+	antenna = lq_sta->lq_info[lq_sta->active_tbl].antenna_type;
 
 	if (is_legacy(lq_type))
 		i = IWL_RATE_54M_INDEX;
@@ -2225,35 +2556,35 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 	while (1) {
 		u64 mask;
 		int j;
-		int active = rs_priv->active_tbl;
+		int active = lq_sta->active_tbl;
 
-		count +=
-		    sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2);
+		cnt +=
+		    sprintf(&buf[cnt], " %2dMbs: ", iwl4965_rates[i].ieee / 2);
 
 		mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
 		for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
-			buf[count++] =
-				(rs_priv->lq_info[active].win[i].data & mask)
+			buf[cnt++] =
+				(lq_sta->lq_info[active].win[i].data & mask)
 				? '1' : '0';
 
-		samples += rs_priv->lq_info[active].win[i].counter;
-		good += rs_priv->lq_info[active].win[i].success_counter;
-		success += rs_priv->lq_info[active].win[i].success_counter *
-			   iwl_rates[i].ieee;
+		samples += lq_sta->lq_info[active].win[i].counter;
+		good += lq_sta->lq_info[active].win[i].success_counter;
+		success += lq_sta->lq_info[active].win[i].success_counter *
+			   iwl4965_rates[i].ieee;
 
-		if (rs_priv->lq_info[active].win[i].stamp) {
+		if (lq_sta->lq_info[active].win[i].stamp) {
 			int delta =
 				   jiffies_to_msecs(now -
-				   rs_priv->lq_info[active].win[i].stamp);
+				   lq_sta->lq_info[active].win[i].stamp);
 
 			if (delta > max_time)
 				max_time = delta;
 
-			count += sprintf(&buf[count], "%5dms\n", delta);
+			cnt += sprintf(&buf[cnt], "%5dms\n", delta);
 		} else
-			buf[count++] = '\n';
+			buf[cnt++] = '\n';
 
-		j = iwl_get_prev_ieee_rate(i);
+		j = iwl4965_get_prev_ieee_rate(i);
 		if (j == i)
 			break;
 		i = j;
@@ -2261,37 +2592,38 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
 
 	/* Display the average rate of all samples taken.
 	 *
-	 * NOTE:  We multiple # of samples by 2 since the IEEE measurement
-	 * added from iwl_rates is actually 2X the rate */
+	 * NOTE:  We multiply # of samples by 2 since the IEEE measurement
+	 * added from iwl4965_rates is actually 2X the rate */
 	if (samples)
-		count += sprintf(&buf[count],
+		cnt += sprintf(&buf[cnt],
 			 "\nAverage rate is %3d.%02dMbs over last %4dms\n"
 			 "%3d%% success (%d good packets over %d tries)\n",
 			 success / (2 * samples), (success * 5 / samples) % 10,
 			 max_time, good * 100 / samples, good, samples);
 	else
-		count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
-	count += sprintf(&buf[count], "\nrate scale type %d anntena %d "
+		cnt += sprintf(&buf[cnt], "\nAverage rate: 0Mbs\n");
+
+	cnt += sprintf(&buf[cnt], "\nrate scale type %d antenna %d "
 			 "active_search %d rate index %d\n", lq_type, antenna,
-			 rs_priv->search_better_tbl, sta->last_txrate);
+			 lq_sta->search_better_tbl, sta->last_txrate);
 
 	sta_info_put(sta);
-	return count;
+	return cnt;
 }
 
-void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
+void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 
 	priv->lq_mngr.lq_ready = 1;
 }
 
-void iwl_rate_control_register(struct ieee80211_hw *hw)
+void iwl4965_rate_control_register(struct ieee80211_hw *hw)
 {
 	ieee80211_rate_control_register(&rs_ops);
 }
 
-void iwl_rate_control_unregister(struct ieee80211_hw *hw)
+void iwl4965_rate_control_unregister(struct ieee80211_hw *hw)
 {
 	ieee80211_rate_control_unregister(&rs_ops);
 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
index c6325f72df68..55f707382787 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
@@ -29,11 +29,11 @@
 
 #include "iwl-4965.h"
 
-struct iwl_rate_info {
-	u8 plcp;
-	u8 plcp_siso;
-	u8 plcp_mimo;
-	u8 ieee;
+struct iwl4965_rate_info {
+	u8 plcp;	/* uCode API:  IWL_RATE_6M_PLCP, etc. */
+	u8 plcp_siso;	/* uCode API:  IWL_RATE_SISO_6M_PLCP, etc. */
+	u8 plcp_mimo;	/* uCode API:  IWL_RATE_MIMO_6M_PLCP, etc. */
+	u8 ieee;	/* MAC header:  IWL_RATE_6M_IEEE, etc. */
 	u8 prev_ieee;    /* previous rate in IEEE speeds */
 	u8 next_ieee;    /* next rate in IEEE speeds */
 	u8 prev_rs;      /* previous rate used in rs algo */
@@ -42,6 +42,10 @@ struct iwl_rate_info {
 	u8 next_rs_tgg;  /* next rate used in TGG rs algo */
 };
 
+/*
+ * These serve as indexes into
+ * struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT];
+ */
 enum {
 	IWL_RATE_1M_INDEX = 0,
 	IWL_RATE_2M_INDEX,
@@ -69,20 +73,21 @@ enum {
 };
 
 /* #define vs. enum to keep from defaulting to 'large integer' */
-#define	IWL_RATE_6M_MASK   (1<<IWL_RATE_6M_INDEX)
-#define	IWL_RATE_9M_MASK   (1<<IWL_RATE_9M_INDEX)
-#define	IWL_RATE_12M_MASK  (1<<IWL_RATE_12M_INDEX)
-#define	IWL_RATE_18M_MASK  (1<<IWL_RATE_18M_INDEX)
-#define	IWL_RATE_24M_MASK  (1<<IWL_RATE_24M_INDEX)
-#define	IWL_RATE_36M_MASK  (1<<IWL_RATE_36M_INDEX)
-#define	IWL_RATE_48M_MASK  (1<<IWL_RATE_48M_INDEX)
-#define	IWL_RATE_54M_MASK  (1<<IWL_RATE_54M_INDEX)
-#define IWL_RATE_60M_MASK  (1<<IWL_RATE_60M_INDEX)
-#define	IWL_RATE_1M_MASK   (1<<IWL_RATE_1M_INDEX)
-#define	IWL_RATE_2M_MASK   (1<<IWL_RATE_2M_INDEX)
-#define	IWL_RATE_5M_MASK   (1<<IWL_RATE_5M_INDEX)
-#define	IWL_RATE_11M_MASK  (1<<IWL_RATE_11M_INDEX)
-
+#define	IWL_RATE_6M_MASK   (1 << IWL_RATE_6M_INDEX)
+#define	IWL_RATE_9M_MASK   (1 << IWL_RATE_9M_INDEX)
+#define	IWL_RATE_12M_MASK  (1 << IWL_RATE_12M_INDEX)
+#define	IWL_RATE_18M_MASK  (1 << IWL_RATE_18M_INDEX)
+#define	IWL_RATE_24M_MASK  (1 << IWL_RATE_24M_INDEX)
+#define	IWL_RATE_36M_MASK  (1 << IWL_RATE_36M_INDEX)
+#define	IWL_RATE_48M_MASK  (1 << IWL_RATE_48M_INDEX)
+#define	IWL_RATE_54M_MASK  (1 << IWL_RATE_54M_INDEX)
+#define IWL_RATE_60M_MASK  (1 << IWL_RATE_60M_INDEX)
+#define	IWL_RATE_1M_MASK   (1 << IWL_RATE_1M_INDEX)
+#define	IWL_RATE_2M_MASK   (1 << IWL_RATE_2M_INDEX)
+#define	IWL_RATE_5M_MASK   (1 << IWL_RATE_5M_INDEX)
+#define	IWL_RATE_11M_MASK  (1 << IWL_RATE_11M_INDEX)
+
+/* 4965 uCode API values for legacy bit rates, both OFDM and CCK */
 enum {
 	IWL_RATE_6M_PLCP  = 13,
 	IWL_RATE_9M_PLCP  = 15,
@@ -99,7 +104,7 @@ enum {
 	IWL_RATE_11M_PLCP = 110,
 };
 
-/* OFDM HT rate plcp */
+/* 4965 uCode API values for OFDM high-throughput (HT) bit rates */
 enum {
 	IWL_RATE_SISO_6M_PLCP = 0,
 	IWL_RATE_SISO_12M_PLCP = 1,
@@ -121,6 +126,7 @@ enum {
 	IWL_RATE_MIMO_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
 };
 
+/* MAC header values for bit rates */
 enum {
 	IWL_RATE_6M_IEEE  = 12,
 	IWL_RATE_9M_IEEE  = 18,
@@ -163,20 +169,15 @@ enum {
 	(IWL_OFDM_BASIC_RATES_MASK | \
 	 IWL_CCK_BASIC_RATES_MASK)
 
-#define IWL_RATES_MASK ((1<<IWL_RATE_COUNT)-1)
+#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
 
 #define IWL_INVALID_VALUE    -1
 
 #define IWL_MIN_RSSI_VAL                 -100
 #define IWL_MAX_RSSI_VAL                    0
 
-#define IWL_LEGACY_SWITCH_ANTENNA	0
-#define IWL_LEGACY_SWITCH_SISO		1
-#define IWL_LEGACY_SWITCH_MIMO	        2
-
-#define IWL_RS_GOOD_RATIO		12800
-
-#define IWL_ACTION_LIMIT		3
+/* These values specify how many Tx frame attempts before
+ * searching for a new modulation mode */
 #define IWL_LEGACY_FAILURE_LIMIT	160
 #define IWL_LEGACY_SUCCESS_LIMIT	480
 #define IWL_LEGACY_TABLE_COUNT		160
@@ -185,82 +186,104 @@ enum {
 #define IWL_NONE_LEGACY_SUCCESS_LIMIT	4500
 #define IWL_NONE_LEGACY_TABLE_COUNT	1500
 
-#define IWL_RATE_SCALE_SWITCH		(10880)
+/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
+#define IWL_RS_GOOD_RATIO		12800	/* 100% */
+#define IWL_RATE_SCALE_SWITCH		10880	/*  85% */
+#define IWL_RATE_HIGH_TH		10880	/*  85% */
+#define IWL_RATE_INCREASE_TH            8960	/*  70% */
+#define IWL_RATE_DECREASE_TH		1920	/*  15% */
 
+/* possible actions when in legacy mode */
+#define IWL_LEGACY_SWITCH_ANTENNA	0
+#define IWL_LEGACY_SWITCH_SISO		1
+#define IWL_LEGACY_SWITCH_MIMO	        2
+
+/* possible actions when in siso mode */
 #define IWL_SISO_SWITCH_ANTENNA		0
 #define IWL_SISO_SWITCH_MIMO		1
 #define IWL_SISO_SWITCH_GI		2
 
+/* possible actions when in mimo mode */
 #define IWL_MIMO_SWITCH_ANTENNA_A	0
 #define IWL_MIMO_SWITCH_ANTENNA_B	1
 #define IWL_MIMO_SWITCH_GI		2
 
-#define LQ_SIZE		2
+#define IWL_ACTION_LIMIT		3	/* # possible actions */
+
+#define LQ_SIZE		2	/* 2 mode tables:  "Active" and "Search" */
 
-extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT];
 
-enum iwl_table_type {
+enum iwl4965_table_type {
 	LQ_NONE,
-	LQ_G,
+	LQ_G,		/* legacy types */
 	LQ_A,
-	LQ_SISO,
+	LQ_SISO,	/* high-throughput types */
 	LQ_MIMO,
 	LQ_MAX,
 };
 
-enum iwl_antenna_type {
+#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
+#define is_siso(tbl) (((tbl) == LQ_SISO))
+#define is_mimo(tbl) (((tbl) == LQ_MIMO))
+#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
+#define is_a_band(tbl) (((tbl) == LQ_A))
+#define is_g_and(tbl) (((tbl) == LQ_G))
+
+/* 4965 has 2 antennas/chains for Tx (but 3 for Rx) */
+enum iwl4965_antenna_type {
 	ANT_NONE,
 	ANT_MAIN,
 	ANT_AUX,
 	ANT_BOTH,
 };
 
-static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
+static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
 {
-	u8 rate = iwl_rates[rate_index].prev_ieee;
+	u8 rate = iwl4965_rates[rate_index].prev_ieee;
 
 	if (rate == IWL_RATE_INVALID)
 		rate = rate_index;
 	return rate;
 }
 
-extern int iwl_rate_index_from_plcp(int plcp);
+extern int iwl4965_rate_index_from_plcp(int plcp);
 
 /**
- * iwl_fill_rs_info - Fill an output text buffer with the rate representation
+ * iwl4965_fill_rs_info - Fill an output text buffer with the rate representation
  *
  * NOTE:  This is provided as a quick mechanism for a user to visualize
- * the performance of the rate control alogirthm and is not meant to be
+ * the performance of the rate control algorithm and is not meant to be
  * parsed software.
  */
-extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
+extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
 
 /**
- * iwl_rate_scale_init - Initialize the rate scale table based on assoc info
+ * iwl4965_rate_scale_init - Initialize the rate scale table based on assoc info
  *
- * The specific througput table used is based on the type of network
+ * The specific throughput table used is based on the type of network
  * the associated with, including A, B, G, and G w/ TGG protection
  */
-extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
+extern void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
 
 /**
- * iwl_rate_control_register - Register the rate control algorithm callbacks
+ * iwl4965_rate_control_register - Register the rate control algorithm callbacks
  *
  * Since the rate control algorithm is hardware specific, there is no need
  * or reason to place it as a stand alone module.  The driver can call
- * iwl_rate_control_register in order to register the rate control callbacks
+ * iwl4965_rate_control_register in order to register the rate control callbacks
  * with the mac80211 subsystem.  This should be performed prior to calling
  * ieee80211_register_hw
  *
  */
-extern void iwl_rate_control_register(struct ieee80211_hw *hw);
+extern void iwl4965_rate_control_register(struct ieee80211_hw *hw);
 
 /**
- * iwl_rate_control_unregister - Unregister the rate control callbacks
+ * iwl4965_rate_control_unregister - Unregister the rate control callbacks
  *
  * This should be called after calling ieee80211_unregister_hw, but before
  * the driver is unloaded.
  */
-extern void iwl_rate_control_unregister(struct ieee80211_hw *hw);
+extern void iwl4965_rate_control_unregister(struct ieee80211_hw *hw);
 
 #endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 891f90d2f019..04db34ba814b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -36,13 +36,13 @@
 #include <linux/wireless.h>
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
+#include <asm/unaligned.h>
 
-#define IWL 4965
-
-#include "iwlwifi.h"
 #include "iwl-4965.h"
 #include "iwl-helpers.h"
 
+static void iwl4965_hw_card_show_info(struct iwl4965_priv *priv);
+
 #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
 	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
 				    IWL_RATE_SISO_##s##M_PLCP, \
@@ -63,7 +63,7 @@
  * maps to IWL_RATE_INVALID
  *
  */
-const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = {
 	IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
 	IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
 	IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
@@ -85,16 +85,16 @@ static int is_fat_channel(__le32 rxon_flags)
 		(rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK);
 }
 
-static u8 is_single_stream(struct iwl_priv *priv)
+static u8 is_single_stream(struct iwl4965_priv *priv)
 {
-#ifdef CONFIG_IWLWIFI_HT
-	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht ||
-	    (priv->active_rate_ht[1] == 0) ||
+#ifdef CONFIG_IWL4965_HT
+	if (!priv->current_ht_config.is_ht ||
+	    (priv->current_ht_config.supp_mcs_set[1] == 0) ||
 	    (priv->ps_mode == IWL_MIMO_PS_STATIC))
 		return 1;
 #else
 	return 1;
-#endif	/*CONFIG_IWLWIFI_HT */
+#endif	/*CONFIG_IWL4965_HT */
 	return 0;
 }
 
@@ -104,7 +104,7 @@ static u8 is_single_stream(struct iwl_priv *priv)
  * MIMO (dual stream) requires at least 2, but works better with 3.
  * This does not determine *which* chains to use, just how many.
  */
-static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,
+static int iwl4965_get_rx_chain_counter(struct iwl4965_priv *priv,
 					u8 *idle_state, u8 *rx_state)
 {
 	u8 is_single = is_single_stream(priv);
@@ -133,32 +133,32 @@ static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,
 	return 0;
 }
 
-int iwl_hw_rxq_stop(struct iwl_priv *priv)
+int iwl4965_hw_rxq_stop(struct iwl4965_priv *priv)
 {
 	int rc;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	/* stop HW */
-	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-	rc = iwl_poll_restricted_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+	/* stop Rx DMA */
+	iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+	rc = iwl4965_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
 				     (1 << 24), 1000);
 	if (rc < 0)
 		IWL_ERROR("Can't stop Rx DMA.\n");
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr)
+u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *addr)
 {
 	int i;
 	int start = 0;
@@ -190,104 +190,114 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr)
 	return ret;
 }
 
-static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+static int iwl4965_nic_set_pwr_src(struct iwl4965_priv *priv, int pwr_max)
 {
-	int rc = 0;
+	int ret;
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
-	if (rc) {
+	ret = iwl4965_grab_nic_access(priv);
+	if (ret) {
 		spin_unlock_irqrestore(&priv->lock, flags);
-		return rc;
+		return ret;
 	}
 
 	if (!pwr_max) {
 		u32 val;
 
-		rc = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
+		ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
 					   &val);
 
 		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
-			iwl_set_bits_mask_restricted_reg(
-				priv, APMG_PS_CTRL_REG,
+			iwl4965_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
 				APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
 				~APMG_PS_CTRL_MSK_PWR_SRC);
 	} else
-		iwl_set_bits_mask_restricted_reg(
-			priv, APMG_PS_CTRL_REG,
+		iwl4965_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
 			APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
 			~APMG_PS_CTRL_MSK_PWR_SRC);
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	return rc;
+	return ret;
 }
 
-static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+static int iwl4965_rx_init(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq)
 {
 	int rc;
 	unsigned long flags;
+	unsigned int rb_size;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	/* stop HW */
-	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+	if (iwl4965_param_amsdu_size_8K)
+		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+	else
+		rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+	/* Stop Rx DMA */
+	iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+	/* Reset driver's Rx queue write index */
+	iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
 
-	iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-	iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+	/* Tell device where to find RBD circular buffer in DRAM */
+	iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
 			     rxq->dma_addr >> 8);
 
-	iwl_write_restricted(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+	/* Tell device where in DRAM to update its Rx status */
+	iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
 			     (priv->hw_setting.shared_phys +
-			      offsetof(struct iwl_shared, val0)) >> 4);
+			      offsetof(struct iwl4965_shared, val0)) >> 4);
 
-	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+	/* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */
+	iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
 			     FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
 			     FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-			     IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
+			     rb_size |
 			     /*0x10 << 4 | */
 			     (RX_QUEUE_SIZE_LOG <<
 			      FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
 
 	/*
-	 * iwl_write32(priv,CSR_INT_COAL_REG,0);
+	 * iwl4965_write32(priv,CSR_INT_COAL_REG,0);
 	 */
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-static int iwl4965_kw_init(struct iwl_priv *priv)
+/* Tell 4965 where to find the "keep warm" buffer */
+static int iwl4965_kw_init(struct iwl4965_priv *priv)
 {
 	unsigned long flags;
 	int rc;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc)
 		goto out;
 
-	iwl_write_restricted(priv, IWL_FH_KW_MEM_ADDR_REG,
+	iwl4965_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG,
 			     priv->kw.dma_addr >> 4);
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 out:
 	spin_unlock_irqrestore(&priv->lock, flags);
 	return rc;
 }
 
-static int iwl4965_kw_alloc(struct iwl_priv *priv)
+static int iwl4965_kw_alloc(struct iwl4965_priv *priv)
 {
 	struct pci_dev *dev = priv->pci_dev;
-	struct iwl_kw *kw = &priv->kw;
+	struct iwl4965_kw *kw = &priv->kw;
 
 	kw->size = IWL4965_KW_SIZE;	/* TBW need set somewhere else */
 	kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
@@ -300,14 +310,19 @@ static int iwl4965_kw_alloc(struct iwl_priv *priv)
 #define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \
 			    ? # x " " : "")
 
-int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, u16 channel,
-			      const struct iwl_eeprom_channel *eeprom_ch,
+/**
+ * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv.
+ *
+ * Does not set up a command, or touch hardware.
+ */
+int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, u16 channel,
+			      const struct iwl4965_eeprom_channel *eeprom_ch,
 			      u8 fat_extension_channel)
 {
-	struct iwl_channel_info *ch_info;
+	struct iwl4965_channel_info *ch_info;
 
-	ch_info = (struct iwl_channel_info *)
-			iwl_get_channel_info(priv, phymode, channel);
+	ch_info = (struct iwl4965_channel_info *)
+			iwl4965_get_channel_info(priv, phymode, channel);
 
 	if (!is_channel_valid(ch_info))
 		return -1;
@@ -340,10 +355,13 @@ int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, u16 channel,
 	return 0;
 }
 
-static void iwl4965_kw_free(struct iwl_priv *priv)
+/**
+ * iwl4965_kw_free - Free the "keep warm" buffer
+ */
+static void iwl4965_kw_free(struct iwl4965_priv *priv)
 {
 	struct pci_dev *dev = priv->pci_dev;
-	struct iwl_kw *kw = &priv->kw;
+	struct iwl4965_kw *kw = &priv->kw;
 
 	if (kw->v_addr) {
 		pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
@@ -358,7 +376,7 @@ static void iwl4965_kw_free(struct iwl_priv *priv)
  * @param priv
  * @return error code
  */
-static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
+static int iwl4965_txq_ctx_reset(struct iwl4965_priv *priv)
 {
 	int rc = 0;
 	int txq_id, slots_num;
@@ -366,9 +384,10 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
 
 	iwl4965_kw_free(priv);
 
-	iwl_hw_txq_ctx_free(priv);
+	/* Free all tx/cmd queues and keep-warm buffer */
+	iwl4965_hw_txq_ctx_free(priv);
 
-	/* Tx CMD queue */
+	/* Alloc keep-warm buffer */
 	rc = iwl4965_kw_alloc(priv);
 	if (rc) {
 		IWL_ERROR("Keep Warm allocation failed");
@@ -377,28 +396,31 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (unlikely(rc)) {
 		IWL_ERROR("TX reset failed");
 		spin_unlock_irqrestore(&priv->lock, flags);
 		goto error_reset;
 	}
 
-	iwl_write_restricted_reg(priv, SCD_TXFACT, 0);
-	iwl_release_restricted_access(priv);
+	/* Turn off all Tx DMA channels */
+	iwl4965_write_prph(priv, KDR_SCD_TXFACT, 0);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
+	/* Tell 4965 where to find the keep-warm buffer */
 	rc = iwl4965_kw_init(priv);
 	if (rc) {
 		IWL_ERROR("kw_init failed\n");
 		goto error_reset;
 	}
 
-	/* Tx queue(s) */
+	/* Alloc and init all (default 16) Tx queues,
+	 * including the command queue (#4) */
 	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
 		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
 					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-		rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+		rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
 				       txq_id);
 		if (rc) {
 			IWL_ERROR("Tx %d queue init failed\n", txq_id);
@@ -409,32 +431,32 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
 	return rc;
 
  error:
-	iwl_hw_txq_ctx_free(priv);
+	iwl4965_hw_txq_ctx_free(priv);
  error_reset:
 	iwl4965_kw_free(priv);
  error_kw:
 	return rc;
 }
 
-int iwl_hw_nic_init(struct iwl_priv *priv)
+int iwl4965_hw_nic_init(struct iwl4965_priv *priv)
 {
 	int rc;
 	unsigned long flags;
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl4965_rx_queue *rxq = &priv->rxq;
 	u8 rev_id;
 	u32 val;
 	u8 val_link;
 
-	iwl_power_init_handle(priv);
+	iwl4965_power_init_handle(priv);
 
 	/* nic_init */
 	spin_lock_irqsave(&priv->lock, flags);
 
-	iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+	iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS,
 		    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
 
-	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+	iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	rc = iwl4965_poll_bit(priv, CSR_GP_CNTRL,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
 	if (rc < 0) {
@@ -443,26 +465,26 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 		return rc;
 	}
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);
+	iwl4965_read_prph(priv, APMG_CLK_CTRL_REG);
 
-	iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,
+	iwl4965_write_prph(priv, APMG_CLK_CTRL_REG,
 				 APMG_CLK_VAL_DMA_CLK_RQT |
 				 APMG_CLK_VAL_BSM_CLK_RQT);
-	iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);
+	iwl4965_read_prph(priv, APMG_CLK_CTRL_REG);
 
 	udelay(20);
 
-	iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+	iwl4965_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
 				    APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-	iwl_release_restricted_access(priv);
-	iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
+	iwl4965_release_nic_access(priv);
+	iwl4965_write32(priv, CSR_INT_COALESCING, 512 / 32);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* Determine HW type */
@@ -484,11 +506,6 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	/* Read the EEPROM */
-	rc = iwl_eeprom_init(priv);
-	if (rc)
-		return rc;
-
 	if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) {
 		IWL_ERROR("Older EEPROM detected!  Aborting.\n");
 		return -EINVAL;
@@ -503,51 +520,53 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 
 	/* set CSR_HW_CONFIG_REG for uCode use */
 
-	iwl_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R |
+	iwl4965_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R |
 		    CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
 		    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc < 0) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		IWL_DEBUG_INFO("Failed to init the card\n");
 		return rc;
 	}
 
-	iwl_read_restricted_reg(priv, APMG_PS_CTRL_REG);
-	iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+	iwl4965_read_prph(priv, APMG_PS_CTRL_REG);
+	iwl4965_set_bits_prph(priv, APMG_PS_CTRL_REG,
 				    APMG_PS_CTRL_VAL_RESET_REQ);
 	udelay(5);
-	iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+	iwl4965_clear_bits_prph(priv, APMG_PS_CTRL_REG,
 				      APMG_PS_CTRL_VAL_RESET_REQ);
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	iwl_hw_card_show_info(priv);
+	iwl4965_hw_card_show_info(priv);
 
 	/* end nic_init */
 
 	/* Allocate the RX queue, or reset if it is already allocated */
 	if (!rxq->bd) {
-		rc = iwl_rx_queue_alloc(priv);
+		rc = iwl4965_rx_queue_alloc(priv);
 		if (rc) {
 			IWL_ERROR("Unable to initialize Rx queue\n");
 			return -ENOMEM;
 		}
 	} else
-		iwl_rx_queue_reset(priv, rxq);
+		iwl4965_rx_queue_reset(priv, rxq);
 
-	iwl_rx_replenish(priv);
+	iwl4965_rx_replenish(priv);
 
 	iwl4965_rx_init(priv, rxq);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
 	rxq->need_update = 1;
-	iwl_rx_queue_update_write_ptr(priv, rxq);
+	iwl4965_rx_queue_update_write_ptr(priv, rxq);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Allocate and init all Tx and Command queues */
 	rc = iwl4965_txq_ctx_reset(priv);
 	if (rc)
 		return rc;
@@ -563,7 +582,7 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 	return 0;
 }
 
-int iwl_hw_nic_stop_master(struct iwl_priv *priv)
+int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv)
 {
 	int rc = 0;
 	u32 reg_val;
@@ -572,16 +591,16 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv)
 	spin_lock_irqsave(&priv->lock, flags);
 
 	/* set stop master bit */
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+	iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
 
-	reg_val = iwl_read32(priv, CSR_GP_CNTRL);
+	reg_val = iwl4965_read32(priv, CSR_GP_CNTRL);
 
 	if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
 	    (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
 		IWL_DEBUG_INFO("Card in power save, master is already "
 			       "stopped\n");
 	else {
-		rc = iwl_poll_bit(priv, CSR_RESET,
+		rc = iwl4965_poll_bit(priv, CSR_RESET,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED,
 				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
 		if (rc < 0) {
@@ -596,65 +615,69 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv)
 	return rc;
 }
 
-void iwl_hw_txq_ctx_stop(struct iwl_priv *priv)
+/**
+ * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
+ */
+void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv)
 {
 
 	int txq_id;
 	unsigned long flags;
 
-	/* reset TFD queues */
+	/* Stop each Tx DMA channel, and wait for it to be idle */
 	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
 		spin_lock_irqsave(&priv->lock, flags);
-		if (iwl_grab_restricted_access(priv)) {
+		if (iwl4965_grab_nic_access(priv)) {
 			spin_unlock_irqrestore(&priv->lock, flags);
 			continue;
 		}
 
-		iwl_write_restricted(priv,
+		iwl4965_write_direct32(priv,
 				     IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
 				     0x0);
-		iwl_poll_restricted_bit(priv, IWL_FH_TSSR_TX_STATUS_REG,
+		iwl4965_poll_direct_bit(priv, IWL_FH_TSSR_TX_STATUS_REG,
 					IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
 					(txq_id), 200);
-		iwl_release_restricted_access(priv);
+		iwl4965_release_nic_access(priv);
 		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 
-	iwl_hw_txq_ctx_free(priv);
+	/* Deallocate memory for all Tx queues */
+	iwl4965_hw_txq_ctx_free(priv);
 }
 
-int iwl_hw_nic_reset(struct iwl_priv *priv)
+int iwl4965_hw_nic_reset(struct iwl4965_priv *priv)
 {
 	int rc = 0;
 	unsigned long flags;
 
-	iwl_hw_nic_stop_master(priv);
+	iwl4965_hw_nic_stop_master(priv);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+	iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
 	udelay(10);
 
-	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-	rc = iwl_poll_bit(priv, CSR_RESET,
+	iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	rc = iwl4965_poll_bit(priv, CSR_RESET,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
 			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
 
 	udelay(10);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (!rc) {
-		iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+		iwl4965_write_prph(priv, APMG_CLK_EN_REG,
 					 APMG_CLK_VAL_DMA_CLK_RQT |
 					 APMG_CLK_VAL_BSM_CLK_RQT);
 
 		udelay(10);
 
-		iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+		iwl4965_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
 				APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
-		iwl_release_restricted_access(priv);
+		iwl4965_release_nic_access(priv);
 	}
 
 	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
@@ -684,7 +707,7 @@ int iwl_hw_nic_reset(struct iwl_priv *priv)
  */
 static void iwl4965_bg_statistics_periodic(unsigned long data)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)data;
 
 	queue_work(priv->workqueue, &priv->statistics_work);
 }
@@ -692,27 +715,27 @@ static void iwl4965_bg_statistics_periodic(unsigned long data)
 /**
  * iwl4965_bg_statistics_work - Send the statistics request to the hardware.
  *
- * This is queued by iwl_bg_statistics_periodic.
+ * This is queued by iwl4965_bg_statistics_periodic.
  */
 static void iwl4965_bg_statistics_work(struct work_struct *work)
 {
-	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+	struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv,
 					     statistics_work);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
-	iwl_send_statistics_request(priv);
+	iwl4965_send_statistics_request(priv);
 	mutex_unlock(&priv->mutex);
 }
 
 #define CT_LIMIT_CONST		259
 #define TM_CT_KILL_THRESHOLD	110
 
-void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
+void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv)
 {
-	struct iwl_ct_kill_config cmd;
+	struct iwl4965_ct_kill_config cmd;
 	u32 R1, R2, R3;
 	u32 temp_th;
 	u32 crit_temperature;
@@ -720,7 +743,7 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
 	int rc = 0;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+	iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR,
 		    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -738,7 +761,7 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
 
 	crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2;
 	cmd.critical_temperature_R =  cpu_to_le32(crit_temperature);
-	rc = iwl_send_cmd_pdu(priv,
+	rc = iwl4965_send_cmd_pdu(priv,
 			      REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd);
 	if (rc)
 		IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n");
@@ -746,7 +769,7 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
 		IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n");
 }
 
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
+#ifdef CONFIG_IWL4965_SENSITIVITY
 
 /* "false alarms" are signals that our DSP tries to lock onto,
  *   but then determines that they are either noise, or transmissions
@@ -756,7 +779,7 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
  *   enough to receive all of our own network traffic, but not so
  *   high that our DSP gets too busy trying to lock onto non-network
  *   activity/noise. */
-static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
+static int iwl4965_sens_energy_cck(struct iwl4965_priv *priv,
 				   u32 norm_fa,
 				   u32 rx_enable_time,
 				   struct statistics_general_data *rx_info)
@@ -782,7 +805,7 @@ static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
 	u32 false_alarms = norm_fa * 200 * 1024;
 	u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
 	u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
-	struct iwl_sensitivity_data *data = NULL;
+	struct iwl4965_sensitivity_data *data = NULL;
 
 	data = &(priv->sensitivity_data);
 
@@ -792,11 +815,11 @@ static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
 	 * This is background noise, which may include transmissions from other
 	 *    networks, measured during silence before our network's beacon */
 	silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
-			    ALL_BAND_FILTER)>>8);
+			    ALL_BAND_FILTER) >> 8);
 	silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
-			    ALL_BAND_FILTER)>>8);
+			    ALL_BAND_FILTER) >> 8);
 	silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
-			    ALL_BAND_FILTER)>>8);
+			    ALL_BAND_FILTER) >> 8);
 
 	val = max(silence_rssi_b, silence_rssi_c);
 	max_silence_rssi = max(silence_rssi_a, (u8) val);
@@ -947,7 +970,7 @@ static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
 }
 
 
-static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
+static int iwl4965_sens_auto_corr_ofdm(struct iwl4965_priv *priv,
 				       u32 norm_fa,
 				       u32 rx_enable_time)
 {
@@ -955,7 +978,7 @@ static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
 	u32 false_alarms = norm_fa * 200 * 1024;
 	u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
 	u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
-	struct iwl_sensitivity_data *data = NULL;
+	struct iwl4965_sensitivity_data *data = NULL;
 
 	data = &(priv->sensitivity_data);
 
@@ -1012,22 +1035,22 @@ static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
 	return 0;
 }
 
-static int iwl_sensitivity_callback(struct iwl_priv *priv,
-				    struct iwl_cmd *cmd, struct sk_buff *skb)
+static int iwl4965_sensitivity_callback(struct iwl4965_priv *priv,
+				    struct iwl4965_cmd *cmd, struct sk_buff *skb)
 {
 	/* We didn't cache the SKB; let the caller free it */
 	return 1;
 }
 
 /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
-static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
+static int iwl4965_sensitivity_write(struct iwl4965_priv *priv, u8 flags)
 {
 	int rc = 0;
-	struct iwl_sensitivity_cmd cmd ;
-	struct iwl_sensitivity_data *data = NULL;
-	struct iwl_host_cmd cmd_out = {
+	struct iwl4965_sensitivity_cmd cmd ;
+	struct iwl4965_sensitivity_data *data = NULL;
+	struct iwl4965_host_cmd cmd_out = {
 		.id = SENSITIVITY_CMD,
-		.len = sizeof(struct iwl_sensitivity_cmd),
+		.len = sizeof(struct iwl4965_sensitivity_cmd),
 		.meta.flags = flags,
 		.data = &cmd,
 	};
@@ -1071,10 +1094,11 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
 			data->auto_corr_cck, data->auto_corr_cck_mrc,
 			data->nrg_th_cck);
 
+	/* Update uCode's "work" table, and copy it to DSP */
 	cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
 
 	if (flags & CMD_ASYNC)
-		cmd_out.meta.u.callback = iwl_sensitivity_callback;
+		cmd_out.meta.u.callback = iwl4965_sensitivity_callback;
 
 	/* Don't send command to uCode if nothing has changed */
 	if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
@@ -1087,7 +1111,7 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
 	memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
 	       sizeof(u16)*HD_TABLE_SIZE);
 
-	rc = iwl_send_cmd(priv, &cmd_out);
+	rc = iwl4965_send_cmd(priv, &cmd_out);
 	if (!rc) {
 		IWL_DEBUG_CALIB("SENSITIVITY_CMD succeeded\n");
 		return rc;
@@ -1096,11 +1120,11 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
 	return 0;
 }
 
-void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force)
+void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags, u8 force)
 {
 	int rc = 0;
 	int i;
-	struct iwl_sensitivity_data *data = NULL;
+	struct iwl4965_sensitivity_data *data = NULL;
 
 	IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n");
 
@@ -1110,7 +1134,7 @@ void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force)
 
 	/* Clear driver's sensitivity algo data */
 	data = &(priv->sensitivity_data);
-	memset(data, 0, sizeof(struct iwl_sensitivity_data));
+	memset(data, 0, sizeof(struct iwl4965_sensitivity_data));
 
 	data->num_in_cck_no_fa = 0;
 	data->nrg_curr_state = IWL_FA_TOO_MANY;
@@ -1154,21 +1178,21 @@ void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force)
 /* Reset differential Rx gains in NIC to prepare for chain noise calibration.
  * Called after every association, but this runs only once!
  *  ... once chain noise is calibrated the first time, it's good forever.  */
-void iwl4965_chain_noise_reset(struct iwl_priv *priv)
+void iwl4965_chain_noise_reset(struct iwl4965_priv *priv)
 {
-	struct iwl_chain_noise_data *data = NULL;
+	struct iwl4965_chain_noise_data *data = NULL;
 	int rc = 0;
 
 	data = &(priv->chain_noise_data);
-	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
-		struct iwl_calibration_cmd cmd;
+	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl4965_is_associated(priv)) {
+		struct iwl4965_calibration_cmd cmd;
 
 		memset(&cmd, 0, sizeof(cmd));
 		cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
 		cmd.diff_gain_a = 0;
 		cmd.diff_gain_b = 0;
 		cmd.diff_gain_c = 0;
-		rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+		rc = iwl4965_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
 				 sizeof(cmd), &cmd);
 		msleep(4);
 		data->state = IWL_CHAIN_NOISE_ACCUMULATE;
@@ -1183,10 +1207,10 @@ void iwl4965_chain_noise_reset(struct iwl_priv *priv)
  * 1)  Which antennas are connected.
  * 2)  Differential rx gain settings to balance the 3 receivers.
  */
-static void iwl4965_noise_calibration(struct iwl_priv *priv,
-				      struct iwl_notif_statistics *stat_resp)
+static void iwl4965_noise_calibration(struct iwl4965_priv *priv,
+				      struct iwl4965_notif_statistics *stat_resp)
 {
-	struct iwl_chain_noise_data *data = NULL;
+	struct iwl4965_chain_noise_data *data = NULL;
 	int rc = 0;
 
 	u32 chain_noise_a;
@@ -1385,7 +1409,7 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv,
 
 		/* Differential gain gets sent to uCode only once */
 		if (!data->radio_write) {
-			struct iwl_calibration_cmd cmd;
+			struct iwl4965_calibration_cmd cmd;
 			data->radio_write = 1;
 
 			memset(&cmd, 0, sizeof(cmd));
@@ -1393,7 +1417,7 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv,
 			cmd.diff_gain_a = data->delta_gain_code[0];
 			cmd.diff_gain_b = data->delta_gain_code[1];
 			cmd.diff_gain_c = data->delta_gain_code[2];
-			rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+			rc = iwl4965_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
 					      sizeof(cmd), &cmd);
 			if (rc)
 				IWL_DEBUG_CALIB("fail sending cmd "
@@ -1416,8 +1440,8 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv,
 	return;
 }
 
-static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
-					    struct iwl_notif_statistics *resp)
+static void iwl4965_sensitivity_calibration(struct iwl4965_priv *priv,
+					    struct iwl4965_notif_statistics *resp)
 {
 	int rc = 0;
 	u32 rx_enable_time;
@@ -1427,7 +1451,7 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
 	u32 bad_plcp_ofdm;
 	u32 norm_fa_ofdm;
 	u32 norm_fa_cck;
-	struct iwl_sensitivity_data *data = NULL;
+	struct iwl4965_sensitivity_data *data = NULL;
 	struct statistics_rx_non_phy *rx_info = &(resp->rx.general);
 	struct statistics_rx *statistics = &(resp->rx);
 	unsigned long flags;
@@ -1435,7 +1459,7 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
 
 	data = &(priv->sensitivity_data);
 
-	if (!iwl_is_associated(priv)) {
+	if (!iwl4965_is_associated(priv)) {
 		IWL_DEBUG_CALIB("<< - not associated\n");
 		return;
 	}
@@ -1523,7 +1547,7 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
 
 static void iwl4965_bg_sensitivity_work(struct work_struct *work)
 {
-	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+	struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv,
 			sensitivity_work);
 
 	mutex_lock(&priv->mutex);
@@ -1549,11 +1573,11 @@ static void iwl4965_bg_sensitivity_work(struct work_struct *work)
 	mutex_unlock(&priv->mutex);
 	return;
 }
-#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+#endif /*CONFIG_IWL4965_SENSITIVITY*/
 
 static void iwl4965_bg_txpower_work(struct work_struct *work)
 {
-	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+	struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv,
 			txpower_work);
 
 	/* If a scan happened to start before we got here
@@ -1569,7 +1593,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work)
 	/* Regardless of if we are assocaited, we must reconfigure the
 	 * TX power since frames can be sent on non-radar channels while
 	 * not associated */
-	iwl_hw_reg_send_txpower(priv);
+	iwl4965_hw_reg_send_txpower(priv);
 
 	/* Update last_temperature to keep is_calib_needed from running
 	 * when it isn't needed... */
@@ -1581,24 +1605,31 @@ static void iwl4965_bg_txpower_work(struct work_struct *work)
 /*
  * Acquire priv->lock before calling this function !
  */
-static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index)
+static void iwl4965_set_wr_ptrs(struct iwl4965_priv *priv, int txq_id, u32 index)
 {
-	iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+	iwl4965_write_direct32(priv, HBUS_TARG_WRPTR,
 			     (index & 0xff) | (txq_id << 8));
-	iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(txq_id), index);
+	iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(txq_id), index);
 }
 
-/*
- * Acquire priv->lock before calling this function !
+/**
+ * iwl4965_tx_queue_set_status - (optionally) start Tx/Cmd queue
+ * @tx_fifo_id: Tx DMA/FIFO channel (range 0-7) that the queue will feed
+ * @scd_retry: (1) Indicates queue will be used in aggregation mode
+ *
+ * NOTE:  Acquire priv->lock before calling this function !
  */
-static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
-					struct iwl_tx_queue *txq,
+static void iwl4965_tx_queue_set_status(struct iwl4965_priv *priv,
+					struct iwl4965_tx_queue *txq,
 					int tx_fifo_id, int scd_retry)
 {
 	int txq_id = txq->q.id;
+
+	/* Find out whether to activate Tx queue */
 	int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
 
-	iwl_write_restricted_reg(priv, SCD_QUEUE_STATUS_BITS(txq_id),
+	/* Set up and activate */
+	iwl4965_write_prph(priv, KDR_SCD_QUEUE_STATUS_BITS(txq_id),
 				 (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
 				 (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
 				 (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) |
@@ -1608,7 +1639,7 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
 	txq->sched_retry = scd_retry;
 
 	IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n",
-		       active ? "Activete" : "Deactivate",
+		       active ? "Activate" : "Deactivate",
 		       scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
 }
 
@@ -1622,17 +1653,17 @@ static const u16 default_queue_to_tx_fifo[] = {
 	IWL_TX_FIFO_HCCA_2
 };
 
-static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
+static inline void iwl4965_txq_ctx_activate(struct iwl4965_priv *priv, int txq_id)
 {
 	set_bit(txq_id, &priv->txq_ctx_active_msk);
 }
 
-static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
+static inline void iwl4965_txq_ctx_deactivate(struct iwl4965_priv *priv, int txq_id)
 {
 	clear_bit(txq_id, &priv->txq_ctx_active_msk);
 }
 
-int iwl4965_alive_notify(struct iwl_priv *priv)
+int iwl4965_alive_notify(struct iwl4965_priv *priv)
 {
 	u32 a;
 	int i = 0;
@@ -1641,45 +1672,55 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
+#ifdef CONFIG_IWL4965_SENSITIVITY
 	memset(&(priv->sensitivity_data), 0,
-	       sizeof(struct iwl_sensitivity_data));
+	       sizeof(struct iwl4965_sensitivity_data));
 	memset(&(priv->chain_noise_data), 0,
-	       sizeof(struct iwl_chain_noise_data));
+	       sizeof(struct iwl4965_chain_noise_data));
 	for (i = 0; i < NUM_RX_CHAINS; i++)
 		priv->chain_noise_data.delta_gain_code[i] =
 				CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
-#endif /* CONFIG_IWLWIFI_SENSITIVITY*/
-	rc = iwl_grab_restricted_access(priv);
+#endif /* CONFIG_IWL4965_SENSITIVITY*/
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	priv->scd_base_addr = iwl_read_restricted_reg(priv, SCD_SRAM_BASE_ADDR);
+	/* Clear 4965's internal Tx Scheduler data base */
+	priv->scd_base_addr = iwl4965_read_prph(priv, KDR_SCD_SRAM_BASE_ADDR);
 	a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET;
 	for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4)
-		iwl_write_restricted_mem(priv, a, 0);
+		iwl4965_write_targ_mem(priv, a, 0);
 	for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4)
-		iwl_write_restricted_mem(priv, a, 0);
+		iwl4965_write_targ_mem(priv, a, 0);
 	for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4)
-		iwl_write_restricted_mem(priv, a, 0);
+		iwl4965_write_targ_mem(priv, a, 0);
 
-	iwl_write_restricted_reg(priv, SCD_DRAM_BASE_ADDR,
+	/* Tel 4965 where to find Tx byte count tables */
+	iwl4965_write_prph(priv, KDR_SCD_DRAM_BASE_ADDR,
 		(priv->hw_setting.shared_phys +
-		 offsetof(struct iwl_shared, queues_byte_cnt_tbls)) >> 10);
-	iwl_write_restricted_reg(priv, SCD_QUEUECHAIN_SEL, 0);
+		 offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10);
 
-	/* initiate the queues */
+	/* Disable chain mode for all queues */
+	iwl4965_write_prph(priv, KDR_SCD_QUEUECHAIN_SEL, 0);
+
+	/* Initialize each Tx queue (including the command queue) */
 	for (i = 0; i < priv->hw_setting.max_txq_num; i++) {
-		iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(i), 0);
-		iwl_write_restricted(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
-		iwl_write_restricted_mem(priv, priv->scd_base_addr +
+
+		/* TFD circular buffer read/write indexes */
+		iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(i), 0);
+		iwl4965_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
+
+		/* Max Tx Window size for Scheduler-ACK mode */
+		iwl4965_write_targ_mem(priv, priv->scd_base_addr +
 					SCD_CONTEXT_QUEUE_OFFSET(i),
 					(SCD_WIN_SIZE <<
 					SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
 					SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
-		iwl_write_restricted_mem(priv, priv->scd_base_addr +
+
+		/* Frame limit */
+		iwl4965_write_targ_mem(priv, priv->scd_base_addr +
 					SCD_CONTEXT_QUEUE_OFFSET(i) +
 					sizeof(u32),
 					(SCD_FRAME_LIMIT <<
@@ -1687,87 +1728,98 @@ int iwl4965_alive_notify(struct iwl_priv *priv)
 					SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
 
 	}
-	iwl_write_restricted_reg(priv, SCD_INTERRUPT_MASK,
+	iwl4965_write_prph(priv, KDR_SCD_INTERRUPT_MASK,
 				 (1 << priv->hw_setting.max_txq_num) - 1);
 
-	iwl_write_restricted_reg(priv, SCD_TXFACT,
+	/* Activate all Tx DMA/FIFO channels */
+	iwl4965_write_prph(priv, KDR_SCD_TXFACT,
 				 SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
 
 	iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
-	/* map qos queues to fifos one-to-one */
+
+	/* Map each Tx/cmd queue to its corresponding fifo */
 	for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
 		int ac = default_queue_to_tx_fifo[i];
 		iwl4965_txq_ctx_activate(priv, i);
 		iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
 	}
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-int iwl_hw_set_hw_setting(struct iwl_priv *priv)
+/**
+ * iwl4965_hw_set_hw_setting
+ *
+ * Called when initializing driver
+ */
+int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv)
 {
+	/* Allocate area for Tx byte count tables and Rx queue status */
 	priv->hw_setting.shared_virt =
 	    pci_alloc_consistent(priv->pci_dev,
-				 sizeof(struct iwl_shared),
+				 sizeof(struct iwl4965_shared),
 				 &priv->hw_setting.shared_phys);
 
 	if (!priv->hw_setting.shared_virt)
 		return -1;
 
-	memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl_shared));
+	memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl4965_shared));
 
-	priv->hw_setting.max_txq_num = iwl_param_queues_num;
+	priv->hw_setting.max_txq_num = iwl4965_param_queues_num;
 	priv->hw_setting.ac_queue_count = AC_NUM;
-
-	priv->hw_setting.cck_flag = RATE_MCS_CCK_MSK;
-	priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd);
+	priv->hw_setting.tx_cmd_len = sizeof(struct iwl4965_tx_cmd);
 	priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
 	priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
-
+	if (iwl4965_param_amsdu_size_8K)
+		priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_8K;
+	else
+		priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_4K;
+	priv->hw_setting.max_pkt_size = priv->hw_setting.rx_buf_size - 256;
 	priv->hw_setting.max_stations = IWL4965_STATION_COUNT;
 	priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID;
 	return 0;
 }
 
 /**
- * iwl_hw_txq_ctx_free - Free TXQ Context
+ * iwl4965_hw_txq_ctx_free - Free TXQ Context
  *
  * Destroy all TX DMA queues and structures
  */
-void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+void iwl4965_hw_txq_ctx_free(struct iwl4965_priv *priv)
 {
 	int txq_id;
 
 	/* Tx queues */
 	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
-		iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+		iwl4965_tx_queue_free(priv, &priv->txq[txq_id]);
 
+	/* Keep-warm buffer */
 	iwl4965_kw_free(priv);
 }
 
 /**
- * iwl_hw_txq_free_tfd -  Free one TFD, those at index [txq->q.last_used]
+ * iwl4965_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
  *
- * Does NOT advance any indexes
+ * Does NOT advance any TFD circular buffer read/write indexes
+ * Does NOT free the TFD itself (which is within circular buffer)
  */
-int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq)
 {
-	struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
-	struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used];
+	struct iwl4965_tfd_frame *bd_tmp = (struct iwl4965_tfd_frame *)&txq->bd[0];
+	struct iwl4965_tfd_frame *bd = &bd_tmp[txq->q.read_ptr];
 	struct pci_dev *dev = priv->pci_dev;
 	int i;
 	int counter = 0;
 	int index, is_odd;
 
-	/* classify bd */
+	/* Host command buffers stay mapped in memory, nothing to clean */
 	if (txq->q.id == IWL_CMD_QUEUE_NUM)
-		/* nothing to cleanup after for host commands */
 		return 0;
 
-	/* sanity check */
+	/* Sanity check on number of chunks */
 	counter = IWL_GET_BITS(*bd, num_tbs);
 	if (counter > MAX_NUM_OF_TBS) {
 		IWL_ERROR("Too many chunks: %i\n", counter);
@@ -1775,8 +1827,8 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 		return 0;
 	}
 
-	/* unmap chunks if any */
-
+	/* Unmap chunks, if any.
+	 * TFD info for odd chunks is different format than for even chunks. */
 	for (i = 0; i < counter; i++) {
 		index = i / 2;
 		is_odd = i & 0x1;
@@ -1796,19 +1848,20 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 					 IWL_GET_BITS(bd->pa[index], tb1_len),
 					 PCI_DMA_TODEVICE);
 
-		if (txq->txb[txq->q.last_used].skb[i]) {
-			struct sk_buff *skb = txq->txb[txq->q.last_used].skb[i];
+		/* Free SKB, if any, for this chunk */
+		if (txq->txb[txq->q.read_ptr].skb[i]) {
+			struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i];
 
 			dev_kfree_skb(skb);
-			txq->txb[txq->q.last_used].skb[i] = NULL;
+			txq->txb[txq->q.read_ptr].skb[i] = NULL;
 		}
 	}
 	return 0;
 }
 
-int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
+int iwl4965_hw_reg_set_txpower(struct iwl4965_priv *priv, s8 power)
 {
-	IWL_ERROR("TODO: Implement iwl_hw_reg_set_txpower!\n");
+	IWL_ERROR("TODO: Implement iwl4965_hw_reg_set_txpower!\n");
 	return -EINVAL;
 }
 
@@ -1830,6 +1883,17 @@ static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res)
 	return 1;
 }
 
+/**
+ * iwl4965_get_voltage_compensation - Power supply voltage comp for txpower
+ *
+ * Determines power supply voltage compensation for txpower calculations.
+ * Returns number of 1/2-dB steps to subtract from gain table index,
+ * to compensate for difference between power supply voltage during
+ * factory measurements, vs. current power supply voltage.
+ *
+ * Voltage indication is higher for lower voltage.
+ * Lower voltage requires more gain (lower gain table index).
+ */
 static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage,
 					    s32 current_voltage)
 {
@@ -1850,12 +1914,12 @@ static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage,
 	return comp;
 }
 
-static const struct iwl_channel_info *
-iwl4965_get_channel_txpower_info(struct iwl_priv *priv, u8 phymode, u16 channel)
+static const struct iwl4965_channel_info *
+iwl4965_get_channel_txpower_info(struct iwl4965_priv *priv, u8 phymode, u16 channel)
 {
-	const struct iwl_channel_info *ch_info;
+	const struct iwl4965_channel_info *ch_info;
 
-	ch_info = iwl_get_channel_info(priv, phymode, channel);
+	ch_info = iwl4965_get_channel_info(priv, phymode, channel);
 
 	if (!is_channel_valid(ch_info))
 		return NULL;
@@ -1889,7 +1953,7 @@ static s32 iwl4965_get_tx_atten_grp(u16 channel)
 	return -1;
 }
 
-static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel)
+static u32 iwl4965_get_sub_band(const struct iwl4965_priv *priv, u32 channel)
 {
 	s32 b = -1;
 
@@ -1917,15 +1981,23 @@ static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
 	}
 }
 
-static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
-				    struct iwl_eeprom_calib_ch_info *chan_info)
+/**
+ * iwl4965_interpolate_chan - Interpolate factory measurements for one channel
+ *
+ * Interpolates factory measurements from the two sample channels within a
+ * sub-band, to apply to channel of interest.  Interpolation is proportional to
+ * differences in channel frequencies, which is proportional to differences
+ * in channel number.
+ */
+static int iwl4965_interpolate_chan(struct iwl4965_priv *priv, u32 channel,
+				    struct iwl4965_eeprom_calib_ch_info *chan_info)
 {
 	s32 s = -1;
 	u32 c;
 	u32 m;
-	const struct iwl_eeprom_calib_measure *m1;
-	const struct iwl_eeprom_calib_measure *m2;
-	struct iwl_eeprom_calib_measure *omeas;
+	const struct iwl4965_eeprom_calib_measure *m1;
+	const struct iwl4965_eeprom_calib_measure *m2;
+	struct iwl4965_eeprom_calib_measure *omeas;
 	u32 ch_i1;
 	u32 ch_i2;
 
@@ -2000,7 +2072,7 @@ static s32 back_off_table[] = {
 
 /* Thermal compensation values for txpower for various frequency ranges ...
  *   ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */
-static struct iwl_txpower_comp_entry {
+static struct iwl4965_txpower_comp_entry {
 	s32 degrees_per_05db_a;
 	s32 degrees_per_05db_a_denom;
 } tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = {
@@ -2250,9 +2322,9 @@ static const struct gain_entry gain_table[2][108] = {
 	 }
 };
 
-static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
+static int iwl4965_fill_txpower_tbl(struct iwl4965_priv *priv, u8 band, u16 channel,
 				    u8 is_fat, u8 ctrl_chan_high,
-				    struct iwl_tx_power_db *tx_power_tbl)
+				    struct iwl4965_tx_power_db *tx_power_tbl)
 {
 	u8 saturation_power;
 	s32 target_power;
@@ -2264,9 +2336,9 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
 	s32 txatten_grp = CALIB_CH_GROUP_MAX;
 	int i;
 	int c;
-	const struct iwl_channel_info *ch_info = NULL;
-	struct iwl_eeprom_calib_ch_info ch_eeprom_info;
-	const struct iwl_eeprom_calib_measure *measurement;
+	const struct iwl4965_channel_info *ch_info = NULL;
+	struct iwl4965_eeprom_calib_ch_info ch_eeprom_info;
+	const struct iwl4965_eeprom_calib_measure *measurement;
 	s16 voltage;
 	s32 init_voltage;
 	s32 voltage_compensation;
@@ -2405,7 +2477,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
 	/* for each of 33 bit-rates (including 1 for CCK) */
 	for (i = 0; i < POWER_TABLE_NUM_ENTRIES; i++) {
 		u8 is_mimo_rate;
-		union iwl_tx_power_dual_stream tx_power;
+		union iwl4965_tx_power_dual_stream tx_power;
 
 		/* for mimo, reduce each chain's txpower by half
 		 * (3dB, 6 steps), so total output power is regulatory
@@ -2502,14 +2574,14 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
 }
 
 /**
- * iwl_hw_reg_send_txpower - Configure the TXPOWER level user limit
+ * iwl4965_hw_reg_send_txpower - Configure the TXPOWER level user limit
  *
  * Uses the active RXON for channel, band, and characteristics (fat, high)
  * The power limit is taken from priv->user_txpower_limit.
  */
-int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
+int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv)
 {
-	struct iwl_txpowertable_cmd cmd = { 0 };
+	struct iwl4965_txpowertable_cmd cmd = { 0 };
 	int rc = 0;
 	u8 band = 0;
 	u8 is_fat = 0;
@@ -2541,23 +2613,23 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
 	if (rc)
 		return rc;
 
-	rc = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd);
+	rc = iwl4965_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd);
 	return rc;
 }
 
-int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel)
 {
 	int rc;
 	u8 band = 0;
 	u8 is_fat = 0;
 	u8 ctrl_chan_high = 0;
-	struct iwl_channel_switch_cmd cmd = { 0 };
-	const struct iwl_channel_info *ch_info;
+	struct iwl4965_channel_switch_cmd cmd = { 0 };
+	const struct iwl4965_channel_info *ch_info;
 
 	band = ((priv->phymode == MODE_IEEE80211B) ||
 		(priv->phymode == MODE_IEEE80211G));
 
-	ch_info = iwl_get_channel_info(priv, priv->phymode, channel);
+	ch_info = iwl4965_get_channel_info(priv, priv->phymode, channel);
 
 	is_fat = is_fat_channel(priv->staging_rxon.flags);
 
@@ -2583,32 +2655,36 @@ int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel)
 		return rc;
 	}
 
-	rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
+	rc = iwl4965_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
 	return rc;
 }
 
 #define RTS_HCCA_RETRY_LIMIT		3
 #define RTS_DFAULT_RETRY_LIMIT		60
 
-void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
-			      struct iwl_cmd *cmd,
+void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv,
+			      struct iwl4965_cmd *cmd,
 			      struct ieee80211_tx_control *ctrl,
 			      struct ieee80211_hdr *hdr, int sta_id,
 			      int is_hcca)
 {
-	u8 rate;
+	struct iwl4965_tx_cmd *tx = &cmd->cmd.tx;
 	u8 rts_retry_limit = 0;
 	u8 data_retry_limit = 0;
-	__le32 tx_flags;
 	u16 fc = le16_to_cpu(hdr->frame_control);
+	u8 rate_plcp;
+	u16 rate_flags = 0;
+	int rate_idx = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
 
-	tx_flags = cmd->cmd.tx.tx_flags;
-
-	rate = iwl_rates[ctrl->tx_rate].plcp;
+	rate_plcp = iwl4965_rates[rate_idx].plcp;
 
 	rts_retry_limit = (is_hcca) ?
 	    RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
 
+	if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
+		rate_flags |= RATE_MCS_CCK_MSK;
+
+
 	if (ieee80211_is_probe_response(fc)) {
 		data_retry_limit = 3;
 		if (data_retry_limit < rts_retry_limit)
@@ -2619,44 +2695,56 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
 	if (priv->data_retry_limit != -1)
 		data_retry_limit = priv->data_retry_limit;
 
-	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+
+	if (ieee80211_is_data(fc)) {
+		tx->initial_rate_index = 0;
+		tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+	} else {
 		switch (fc & IEEE80211_FCTL_STYPE) {
 		case IEEE80211_STYPE_AUTH:
 		case IEEE80211_STYPE_DEAUTH:
 		case IEEE80211_STYPE_ASSOC_REQ:
 		case IEEE80211_STYPE_REASSOC_REQ:
-			if (tx_flags & TX_CMD_FLG_RTS_MSK) {
-				tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-				tx_flags |= TX_CMD_FLG_CTS_MSK;
+			if (tx->tx_flags & TX_CMD_FLG_RTS_MSK) {
+				tx->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+				tx->tx_flags |= TX_CMD_FLG_CTS_MSK;
 			}
 			break;
 		default:
 			break;
 		}
+
+		/* Alternate between antenna A and B for successive frames */
+		if (priv->use_ant_b_for_management_frame) {
+			priv->use_ant_b_for_management_frame = 0;
+			rate_flags |= RATE_MCS_ANT_B_MSK;
+		} else {
+			priv->use_ant_b_for_management_frame = 1;
+			rate_flags |= RATE_MCS_ANT_A_MSK;
+		}
 	}
 
-	cmd->cmd.tx.rts_retry_limit = rts_retry_limit;
-	cmd->cmd.tx.data_retry_limit = data_retry_limit;
-	cmd->cmd.tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, 0);
-	cmd->cmd.tx.tx_flags = tx_flags;
+	tx->rts_retry_limit = rts_retry_limit;
+	tx->data_retry_limit = data_retry_limit;
+	tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags);
 }
 
-int iwl_hw_get_rx_read(struct iwl_priv *priv)
+int iwl4965_hw_get_rx_read(struct iwl4965_priv *priv)
 {
-	struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+	struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt;
 
 	return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num);
 }
 
-int iwl_hw_get_temperature(struct iwl_priv *priv)
+int iwl4965_hw_get_temperature(struct iwl4965_priv *priv)
 {
 	return priv->temperature;
 }
 
-unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
-			  struct iwl_frame *frame, u8 rate)
+unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv,
+			  struct iwl4965_frame *frame, u8 rate)
 {
-	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+	struct iwl4965_tx_beacon_cmd *tx_beacon_cmd;
 	unsigned int frame_size;
 
 	tx_beacon_cmd = &frame->u.beacon;
@@ -2665,9 +2753,9 @@ unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
 	tx_beacon_cmd->tx.sta_id = IWL4965_BROADCAST_ID;
 	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
-	frame_size = iwl_fill_beacon_frame(priv,
+	frame_size = iwl4965_fill_beacon_frame(priv,
 				tx_beacon_cmd->frame,
-				BROADCAST_ADDR,
+				iwl4965_broadcast_addr,
 				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
 
 	BUG_ON(frame_size > MAX_MPDU_SIZE);
@@ -2675,53 +2763,59 @@ unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
 
 	if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
 		tx_beacon_cmd->tx.rate_n_flags =
-			iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
+			iwl4965_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
 	else
 		tx_beacon_cmd->tx.rate_n_flags =
-			iwl_hw_set_rate_n_flags(rate, 0);
+			iwl4965_hw_set_rate_n_flags(rate, 0);
 
 	tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
 				TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK);
 	return (sizeof(*tx_beacon_cmd) + frame_size);
 }
 
-int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+/*
+ * Tell 4965 where to find circular buffer of Tx Frame Descriptors for
+ * given Tx queue, and enable the DMA channel used for that queue.
+ *
+ * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
+ * channels supported in hardware.
+ */
+int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq)
 {
 	int rc;
 	unsigned long flags;
 	int txq_id = txq->q.id;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
-	iwl_write_restricted(priv, FH_MEM_CBBC_QUEUE(txq_id),
+	/* Circular buffer (TFD queue in DRAM) physical base address */
+	iwl4965_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
 			     txq->q.dma_addr >> 8);
-	iwl_write_restricted(
+
+	/* Enable DMA channel, using same id as for TFD queue */
+	iwl4965_write_direct32(
 		priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
 		IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
 		IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-static inline u8 iwl4965_get_dma_hi_address(dma_addr_t addr)
-{
-	return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0;
-}
-
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl4965_priv *priv, void *ptr,
 				 dma_addr_t addr, u16 len)
 {
 	int index, is_odd;
-	struct iwl_tfd_frame *tfd = ptr;
+	struct iwl4965_tfd_frame *tfd = ptr;
 	u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
 
+	/* Each TFD can point to a maximum 20 Tx buffers */
 	if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) {
 		IWL_ERROR("Error can not send more than %d chunks\n",
 			  MAX_NUM_OF_TBS);
@@ -2734,7 +2828,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
 	if (!is_odd) {
 		tfd->pa[index].tb1_addr = cpu_to_le32(addr);
 		IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
-			     iwl4965_get_dma_hi_address(addr));
+			     iwl_get_dma_hi_address(addr));
 		IWL_SET_BITS(tfd->pa[index], tb1_len, len);
 	} else {
 		IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16,
@@ -2748,7 +2842,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
 	return 0;
 }
 
-void iwl_hw_card_show_info(struct iwl_priv *priv)
+static void iwl4965_hw_card_show_info(struct iwl4965_priv *priv)
 {
 	u16 hw_version = priv->eeprom.board_revision_4965;
 
@@ -2763,32 +2857,41 @@ void iwl_hw_card_show_info(struct iwl_priv *priv)
 #define IWL_TX_CRC_SIZE		4
 #define IWL_TX_DELIMITER_SIZE	4
 
-int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
-				   struct iwl_tx_queue *txq, u16 byte_cnt)
+/**
+ * iwl4965_tx_queue_update_wr_ptr - Set up entry in Tx byte-count array
+ */
+int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv,
+				   struct iwl4965_tx_queue *txq, u16 byte_cnt)
 {
 	int len;
 	int txq_id = txq->q.id;
-	struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+	struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt;
 
 	if (txq->need_update == 0)
 		return 0;
 
 	len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
 
+	/* Set up byte count within first 256 entries */
 	IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
-		       tfd_offset[txq->q.first_empty], byte_cnt, len);
+		       tfd_offset[txq->q.write_ptr], byte_cnt, len);
 
-	if (txq->q.first_empty < IWL4965_MAX_WIN_SIZE)
+	/* If within first 64 entries, duplicate at end */
+	if (txq->q.write_ptr < IWL4965_MAX_WIN_SIZE)
 		IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
-			tfd_offset[IWL4965_QUEUE_SIZE + txq->q.first_empty],
+			tfd_offset[IWL4965_QUEUE_SIZE + txq->q.write_ptr],
 			byte_cnt, len);
 
 	return 0;
 }
 
-/* Set up Rx receiver/antenna/chain usage in "staging" RXON image.
- * This should not be used for scan command ... it puts data in wrong place.  */
-void iwl4965_set_rxon_chain(struct iwl_priv *priv)
+/**
+ * iwl4965_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
+ *
+ * Selects how many and which Rx receivers/antennas/chains to use.
+ * This should not be used for scan command ... it puts data in wrong place.
+ */
+void iwl4965_set_rxon_chain(struct iwl4965_priv *priv)
 {
 	u8 is_single = is_single_stream(priv);
 	u8 idle_state, rx_state;
@@ -2819,19 +2922,19 @@ void iwl4965_set_rxon_chain(struct iwl_priv *priv)
 	IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
 }
 
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 /*
 	get the traffic load value for tid
 */
-static u32 iwl4965_tl_get_load(struct iwl_priv *priv, u8 tid)
+static u32 iwl4965_tl_get_load(struct iwl4965_priv *priv, u8 tid)
 {
 	u32 load = 0;
 	u32 current_time = jiffies_to_msecs(jiffies);
 	u32 time_diff;
 	s32 index;
 	unsigned long flags;
-	struct iwl_traffic_load *tid_ptr = NULL;
+	struct iwl4965_traffic_load *tid_ptr = NULL;
 
 	if (tid >= TID_MAX_LOAD_COUNT)
 		return 0;
@@ -2872,13 +2975,13 @@ static u32 iwl4965_tl_get_load(struct iwl_priv *priv, u8 tid)
 	increment traffic load value for tid and also remove
 	any old values if passed the certian time period
 */
-static void iwl4965_tl_add_packet(struct iwl_priv *priv, u8 tid)
+static void iwl4965_tl_add_packet(struct iwl4965_priv *priv, u8 tid)
 {
 	u32 current_time = jiffies_to_msecs(jiffies);
 	u32 time_diff;
 	s32 index;
 	unsigned long flags;
-	struct iwl_traffic_load *tid_ptr = NULL;
+	struct iwl4965_traffic_load *tid_ptr = NULL;
 
 	if (tid >= TID_MAX_LOAD_COUNT)
 		return;
@@ -2935,14 +3038,19 @@ enum HT_STATUS {
 	BA_STATUS_ACTIVE,
 };
 
-static u8 iwl4964_tl_ba_avail(struct iwl_priv *priv)
+/**
+ * iwl4964_tl_ba_avail - Find out if an unused aggregation queue is available
+ */
+static u8 iwl4964_tl_ba_avail(struct iwl4965_priv *priv)
 {
 	int i;
-	struct iwl_lq_mngr *lq;
+	struct iwl4965_lq_mngr *lq;
 	u8 count = 0;
 	u16 msk;
 
-	lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+	lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
+
+	/* Find out how many agg queues are in use */
 	for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) {
 		msk = 1 << i;
 		if ((lq->agg_ctrl.granted_ba & msk) ||
@@ -2956,10 +3064,10 @@ static u8 iwl4964_tl_ba_avail(struct iwl_priv *priv)
 	return 0;
 }
 
-static void iwl4965_ba_status(struct iwl_priv *priv,
+static void iwl4965_ba_status(struct iwl4965_priv *priv,
 			      u8 tid, enum HT_STATUS status);
 
-static int iwl4965_perform_addba(struct iwl_priv *priv, u8 tid, u32 length,
+static int iwl4965_perform_addba(struct iwl4965_priv *priv, u8 tid, u32 length,
 				 u32 ba_timeout)
 {
 	int rc;
@@ -2971,7 +3079,7 @@ static int iwl4965_perform_addba(struct iwl_priv *priv, u8 tid, u32 length,
 	return rc;
 }
 
-static int iwl4965_perform_delba(struct iwl_priv *priv, u8 tid)
+static int iwl4965_perform_delba(struct iwl4965_priv *priv, u8 tid)
 {
 	int rc;
 
@@ -2982,8 +3090,8 @@ static int iwl4965_perform_delba(struct iwl_priv *priv, u8 tid)
 	return rc;
 }
 
-static void iwl4965_turn_on_agg_for_tid(struct iwl_priv *priv,
-					struct iwl_lq_mngr *lq,
+static void iwl4965_turn_on_agg_for_tid(struct iwl4965_priv *priv,
+					struct iwl4965_lq_mngr *lq,
 					u8 auto_agg, u8 tid)
 {
 	u32 tid_msk = (1 << tid);
@@ -3030,12 +3138,12 @@ static void iwl4965_turn_on_agg_for_tid(struct iwl_priv *priv,
 	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
 }
 
-static void iwl4965_turn_on_agg(struct iwl_priv *priv, u8 tid)
+static void iwl4965_turn_on_agg(struct iwl4965_priv *priv, u8 tid)
 {
-	struct iwl_lq_mngr *lq;
+	struct iwl4965_lq_mngr *lq;
 	unsigned long flags;
 
-	lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+	lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
 
 	if ((tid < TID_MAX_LOAD_COUNT))
 		iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg,
@@ -3055,13 +3163,13 @@ static void iwl4965_turn_on_agg(struct iwl_priv *priv, u8 tid)
 
 }
 
-void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid)
+void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid)
 {
 	u32 tid_msk;
-	struct iwl_lq_mngr *lq;
+	struct iwl4965_lq_mngr *lq;
 	unsigned long flags;
 
-	lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+	lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
 
 	if ((tid < TID_MAX_LOAD_COUNT)) {
 		tid_msk = 1 << tid;
@@ -3084,14 +3192,17 @@ void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid)
 	}
 }
 
-static void iwl4965_ba_status(struct iwl_priv *priv,
+/**
+ * iwl4965_ba_status - Update driver's link quality mgr with tid's HT status
+ */
+static void iwl4965_ba_status(struct iwl4965_priv *priv,
 				u8 tid, enum HT_STATUS status)
 {
-	struct iwl_lq_mngr *lq;
+	struct iwl4965_lq_mngr *lq;
 	u32 tid_msk = (1 << tid);
 	unsigned long flags;
 
-	lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+	lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
 
 	if ((tid >= TID_MAX_LOAD_COUNT))
 		goto out;
@@ -3124,14 +3235,14 @@ static void iwl4965_ba_status(struct iwl_priv *priv,
 
 static void iwl4965_bg_agg_work(struct work_struct *work)
 {
-	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+	struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv,
 					agg_work);
 
 	u32 tid;
 	u32 retry_tid;
 	u32 tid_msk;
 	unsigned long flags;
-	struct iwl_lq_mngr *lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+	struct iwl4965_lq_mngr *lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr);
 
 	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
 	retry_tid = lq->agg_ctrl.tid_retry;
@@ -3154,90 +3265,13 @@ static void iwl4965_bg_agg_work(struct work_struct *work)
 	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
 	return;
 }
-#endif /*CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
 
-int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
-		   u8 sta_id, dma_addr_t txcmd_phys,
-		   struct ieee80211_hdr *hdr, u8 hdr_len,
-		   struct ieee80211_tx_control *ctrl, void *sta_in)
+/* TODO: move this functionality to rate scaling */
+void iwl4965_tl_get_stats(struct iwl4965_priv *priv,
+		   struct ieee80211_hdr *hdr)
 {
-	struct iwl_tx_cmd cmd;
-	struct iwl_tx_cmd *tx = (struct iwl_tx_cmd *)&out_cmd->cmd.payload[0];
-	dma_addr_t scratch_phys;
-	u8 unicast = 0;
-	u8 is_data = 1;
-	u16 fc;
-	u16 rate_flags;
-	int rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
-	__le16 *qc;
-#endif /*CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
-
-	unicast = !is_multicast_ether_addr(hdr->addr1);
-
-	fc = le16_to_cpu(hdr->frame_control);
-	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
-		is_data = 0;
-
-	memcpy(&cmd, &(out_cmd->cmd.tx), sizeof(struct iwl_tx_cmd));
-	memset(tx, 0, sizeof(struct iwl_tx_cmd));
-	memcpy(tx->hdr, hdr, hdr_len);
-
-	tx->len = cmd.len;
-	tx->driver_txop = cmd.driver_txop;
-	tx->stop_time.life_time = cmd.stop_time.life_time;
-	tx->tx_flags = cmd.tx_flags;
-	tx->sta_id = cmd.sta_id;
-	tx->tid_tspec = cmd.tid_tspec;
-	tx->timeout.pm_frame_timeout = cmd.timeout.pm_frame_timeout;
-	tx->next_frame_len = cmd.next_frame_len;
-
-	tx->sec_ctl = cmd.sec_ctl;
-	memcpy(&(tx->key[0]), &(cmd.key[0]), 16);
-	tx->tx_flags = cmd.tx_flags;
-
-	tx->rts_retry_limit = cmd.rts_retry_limit;
-	tx->data_retry_limit = cmd.data_retry_limit;
-
-	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
-	    offsetof(struct iwl_tx_cmd, scratch);
-	tx->dram_lsb_ptr = cpu_to_le32(scratch_phys);
-	tx->dram_msb_ptr = iwl4965_get_dma_hi_address(scratch_phys);
-
-	/* Hard coded to start at the highest retry fallback position
-	 * until the 4965 specific rate control algorithm is tied in */
-	tx->initial_rate_index = LINK_QUAL_MAX_RETRY_NUM - 1;
-
-	/* Alternate between antenna A and B for successive frames */
-	if (priv->use_ant_b_for_management_frame) {
-		priv->use_ant_b_for_management_frame = 0;
-		rate_flags = RATE_MCS_ANT_B_MSK;
-	} else {
-		priv->use_ant_b_for_management_frame = 1;
-		rate_flags = RATE_MCS_ANT_A_MSK;
-	}
+	__le16 *qc = ieee80211_get_qos_ctrl(hdr);
 
-	if (!unicast || !is_data) {
-		if ((rate_index >= IWL_FIRST_CCK_RATE) &&
-		    (rate_index <= IWL_LAST_CCK_RATE))
-			rate_flags |= RATE_MCS_CCK_MSK;
-	} else {
-		tx->initial_rate_index = 0;
-		tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
-	}
-
-	tx->rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[rate_index].plcp,
-						rate_flags);
-
-	if (ieee80211_is_back_request(fc))
-		tx->tx_flags |= TX_CMD_FLG_ACK_MSK |
-			TX_CMD_FLG_IMM_BA_RSP_MASK;
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
-	qc = ieee80211_get_qos_ctrl(hdr);
 	if (qc &&
 	    (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) {
 		u8 tid = 0;
@@ -3255,11 +3289,11 @@ int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
 		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
 		schedule_work(&priv->agg_work);
 	}
-#endif
-#endif
-	return 0;
 }
 
+#endif /*CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+
 /**
  * sign_extend - Sign extend a value using specified bit as sign-bit
  *
@@ -3282,7 +3316,7 @@ static s32 sign_extend(u32 oper, int index)
  *
  * A return of <0 indicates bogus data in the statistics
  */
-int iwl4965_get_temperature(const struct iwl_priv *priv)
+int iwl4965_get_temperature(const struct iwl4965_priv *priv)
 {
 	s32 temperature;
 	s32 vt;
@@ -3305,11 +3339,12 @@ int iwl4965_get_temperature(const struct iwl_priv *priv)
 	}
 
 	/*
-	 * Temperature is only 23 bits so sign extend out to 32
+	 * Temperature is only 23 bits, so sign extend out to 32.
 	 *
 	 * NOTE If we haven't received a statistics notification yet
 	 * with an updated temperature, use R4 provided to us in the
-	 * ALIVE response. */
+	 * "initialize" ALIVE response.
+	 */
 	if (!test_bit(STATUS_TEMPERATURE, &priv->status))
 		vt = sign_extend(R4, 23);
 	else
@@ -3349,7 +3384,7 @@ int iwl4965_get_temperature(const struct iwl_priv *priv)
  * Assumes caller will replace priv->last_temperature once calibration
  * executed.
  */
-static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv)
+static int iwl4965_is_temp_calib_needed(struct iwl4965_priv *priv)
 {
 	int temp_diff;
 
@@ -3382,7 +3417,7 @@ static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv)
 /* Calculate noise level, based on measurements during network silence just
  *   before arriving beacon.  This measurement can be done only if we know
  *   exactly when to expect beacons, therefore only when we're associated. */
-static void iwl4965_rx_calc_noise(struct iwl_priv *priv)
+static void iwl4965_rx_calc_noise(struct iwl4965_priv *priv)
 {
 	struct statistics_rx_non_phy *rx_info
 				= &(priv->statistics.rx.general);
@@ -3419,9 +3454,9 @@ static void iwl4965_rx_calc_noise(struct iwl_priv *priv)
 			priv->last_rx_noise);
 }
 
-void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+void iwl4965_hw_rx_statistics(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 	int change;
 	s32 temp;
 
@@ -3448,7 +3483,7 @@ void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 	if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
 	    (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
 		iwl4965_rx_calc_noise(priv);
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
+#ifdef CONFIG_IWL4965_SENSITIVITY
 		queue_work(priv->workqueue, &priv->sensitivity_work);
 #endif
 	}
@@ -3483,12 +3518,117 @@ void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 		queue_work(priv->workqueue, &priv->txpower_work);
 }
 
-static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
+static void iwl4965_add_radiotap(struct iwl4965_priv *priv,
+				 struct sk_buff *skb,
+				 struct iwl4965_rx_phy_res *rx_start,
+				 struct ieee80211_rx_status *stats,
+				 u32 ampdu_status)
+{
+	s8 signal = stats->ssi;
+	s8 noise = 0;
+	int rate = stats->rate;
+	u64 tsf = stats->mactime;
+	__le16 phy_flags_hw = rx_start->phy_flags;
+	struct iwl4965_rt_rx_hdr {
+		struct ieee80211_radiotap_header rt_hdr;
+		__le64 rt_tsf;		/* TSF */
+		u8 rt_flags;		/* radiotap packet flags */
+		u8 rt_rate;		/* rate in 500kb/s */
+		__le16 rt_channelMHz;	/* channel in MHz */
+		__le16 rt_chbitmask;	/* channel bitfield */
+		s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
+		s8 rt_dbmnoise;
+		u8 rt_antenna;		/* antenna number */
+	} __attribute__ ((packed)) *iwl4965_rt;
+
+	/* TODO: We won't have enough headroom for HT frames. Fix it later. */
+	if (skb_headroom(skb) < sizeof(*iwl4965_rt)) {
+		if (net_ratelimit())
+			printk(KERN_ERR "not enough headroom [%d] for "
+			       "radiotap head [%zd]\n",
+			       skb_headroom(skb), sizeof(*iwl4965_rt));
+		return;
+	}
+
+	/* put radiotap header in front of 802.11 header and data */
+	iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt));
+
+	/* initialise radiotap header */
+	iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+	iwl4965_rt->rt_hdr.it_pad = 0;
+
+	/* total header + data */
+	put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)),
+		      &iwl4965_rt->rt_hdr.it_len);
+
+	/* Indicate all the fields we add to the radiotap header */
+	put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+				  (1 << IEEE80211_RADIOTAP_FLAGS) |
+				  (1 << IEEE80211_RADIOTAP_RATE) |
+				  (1 << IEEE80211_RADIOTAP_CHANNEL) |
+				  (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+				  (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+				  (1 << IEEE80211_RADIOTAP_ANTENNA)),
+		      &iwl4965_rt->rt_hdr.it_present);
+
+	/* Zero the flags, we'll add to them as we go */
+	iwl4965_rt->rt_flags = 0;
+
+	put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf);
+
+	iwl4965_rt->rt_dbmsignal = signal;
+	iwl4965_rt->rt_dbmnoise = noise;
+
+	/* Convert the channel frequency and set the flags */
+	put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz);
+	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
+		put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
+					  IEEE80211_CHAN_5GHZ),
+			      &iwl4965_rt->rt_chbitmask);
+	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
+		put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK |
+					  IEEE80211_CHAN_2GHZ),
+			      &iwl4965_rt->rt_chbitmask);
+	else	/* 802.11g */
+		put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
+					  IEEE80211_CHAN_2GHZ),
+			      &iwl4965_rt->rt_chbitmask);
+
+	rate = iwl4965_rate_index_from_plcp(rate);
+	if (rate == -1)
+		iwl4965_rt->rt_rate = 0;
+	else
+		iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee;
+
+	/*
+	 * "antenna number"
+	 *
+	 * It seems that the antenna field in the phy flags value
+	 * is actually a bitfield. This is undefined by radiotap,
+	 * it wants an actual antenna number but I always get "7"
+	 * for most legacy frames I receive indicating that the
+	 * same frame was received on all three RX chains.
+	 *
+	 * I think this field should be removed in favour of a
+	 * new 802.11n radiotap field "RX chains" that is defined
+	 * as a bitmask.
+	 */
+	iwl4965_rt->rt_antenna =
+		le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+	/* set the preamble flag if appropriate */
+	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+		iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+	stats->flag |= RX_FLAG_RADIOTAP;
+}
+
+static void iwl4965_handle_data_packet(struct iwl4965_priv *priv, int is_data,
 				       int include_phy,
-				       struct iwl_rx_mem_buffer *rxb,
+				       struct iwl4965_rx_mem_buffer *rxb,
 				       struct ieee80211_rx_status *stats)
 {
-	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
 	struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
 	    (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
 	struct ieee80211_hdr *hdr;
@@ -3524,9 +3664,8 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
 		rx_start->byte_count = amsdu->byte_count;
 		rx_end = (__le32 *) (((u8 *) hdr) + len);
 	}
-	if (len > 2342 || len < 16) {
-		IWL_DEBUG_DROP("byte count out of range [16,2342]"
-			       " : %d\n", len);
+	if (len > priv->hw_setting.max_pkt_size || len < 16) {
+		IWL_WARNING("byte count out of range [16,4K] : %d\n", len);
 		return;
 	}
 
@@ -3544,26 +3683,21 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
 		return;
 	}
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
-		if (iwl_param_hwcrypto)
-			iwl_set_decrypted_flag(priv, rxb->skb,
-					       ampdu_status, stats);
-		iwl_handle_data_packet_monitor(priv, rxb, hdr, len, stats, 0);
-		return;
-	}
-
 	stats->flag = 0;
 	hdr = (struct ieee80211_hdr *)rxb->skb->data;
 
-	if (iwl_param_hwcrypto)
-		iwl_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats);
+	if (iwl4965_param_hwcrypto)
+		iwl4965_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats);
+
+	if (priv->add_radiotap)
+		iwl4965_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status);
 
 	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
 	priv->alloc_rxb_skb--;
 	rxb->skb = NULL;
 #ifdef LED
 	priv->led_packets += len;
-	iwl_setup_activity_timer(priv);
+	iwl4965_setup_activity_timer(priv);
 #endif
 }
 
@@ -3601,7 +3735,7 @@ static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp)
 	return (max_rssi - agc - IWL_RSSI_OFFSET);
 }
 
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 
 /* Parsed Information Elements */
 struct ieee802_11_elems {
@@ -3673,9 +3807,37 @@ static int parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems)
 
 	return 0;
 }
-#endif /* CONFIG_IWLWIFI_HT */
 
-static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, int mode)
+{
+	ht_info->cap = 0;
+	memset(ht_info->supp_mcs_set, 0, 16);
+
+	ht_info->ht_supported = 1;
+
+	if (mode == MODE_IEEE80211A) {
+		ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH;
+		ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40;
+		ht_info->supp_mcs_set[4] = 0x01;
+	}
+	ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD;
+	ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20;
+	ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS &
+			     (IWL_MIMO_PS_NONE << 2));
+	if (iwl4965_param_amsdu_size_8K) {
+		printk(KERN_DEBUG "iwl4965 in A-MSDU 8K support mode\n");
+		ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU;
+	}
+
+	ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+	ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF;
+
+	ht_info->supp_mcs_set[0] = 0xFF;
+	ht_info->supp_mcs_set[1] = 0xFF;
+}
+#endif /* CONFIG_IWL4965_HT */
+
+static void iwl4965_sta_modify_ps_wake(struct iwl4965_priv *priv, int sta_id)
 {
 	unsigned long flags;
 
@@ -3686,13 +3848,13 @@ static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
 	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
 
-static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
+static void iwl4965_update_ps_mode(struct iwl4965_priv *priv, u16 ps_bit, u8 *addr)
 {
 	/* FIXME: need locking over ps_status ??? */
-	u8 sta_id = iwl_hw_find_station(priv, addr);
+	u8 sta_id = iwl4965_hw_find_station(priv, addr);
 
 	if (sta_id != IWL_INVALID_STATION) {
 		u8 sta_awake = priv->stations[sta_id].
@@ -3707,12 +3869,14 @@ static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
 	}
 }
 
+#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
+
 /* Called for REPLY_4965_RX (legacy ABG frames), or
  * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
-static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv,
+				struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 	/* Use phy data (Rx signal strength, etc.) contained within
 	 *   this rx packet for legacy frames,
 	 *   or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
@@ -3731,11 +3895,8 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 			(rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
 			MODE_IEEE80211G : MODE_IEEE80211A,
 		.antenna = 0,
-		.rate = iwl_hw_get_rate(rx_start->rate_n_flags),
+		.rate = iwl4965_hw_get_rate(rx_start->rate_n_flags),
 		.flag = 0,
-#ifdef CONFIG_IWLWIFI_HT_AGG
-		.ordered = 0
-#endif /* CONFIG_IWLWIFI_HT_AGG */
 	};
 	u8 network_packet;
 
@@ -3794,32 +3955,32 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 	 *   which are gathered only when associated, and indicate noise
 	 *   only for the associated network channel ...
 	 * Ignore these noise values while scanning (other channels) */
-	if (iwl_is_associated(priv) &&
+	if (iwl4965_is_associated(priv) &&
 	    !test_bit(STATUS_SCANNING, &priv->status)) {
 		stats.noise = priv->last_rx_noise;
-		stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise);
+		stats.signal = iwl4965_calc_sig_qual(stats.ssi, stats.noise);
 	} else {
 		stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-		stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
+		stats.signal = iwl4965_calc_sig_qual(stats.ssi, 0);
 	}
 
 	/* Reset beacon noise level if not associated. */
-	if (!iwl_is_associated(priv))
+	if (!iwl4965_is_associated(priv))
 		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	/* TODO:  Parts of iwl_report_frame are broken for 4965 */
-	if (iwl_debug_level & (IWL_DL_RX))
+#ifdef CONFIG_IWL4965_DEBUG
+	/* TODO:  Parts of iwl4965_report_frame are broken for 4965 */
+	if (iwl4965_debug_level & (IWL_DL_RX))
 		/* Set "1" to report good data frames in groups of 100 */
-		iwl_report_frame(priv, pkt, header, 1);
+		iwl4965_report_frame(priv, pkt, header, 1);
 
-	if (iwl_debug_level & (IWL_DL_RX | IWL_DL_STATS))
+	if (iwl4965_debug_level & (IWL_DL_RX | IWL_DL_STATS))
 	IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n",
 		stats.ssi, stats.noise, stats.signal,
 		 (long unsigned int)le64_to_cpu(rx_start->timestamp));
 #endif
 
-	network_packet = iwl_is_network_packet(priv, header);
+	network_packet = iwl4965_is_network_packet(priv, header);
 	if (network_packet) {
 		priv->last_rx_rssi = stats.ssi;
 		priv->last_beacon_time =  priv->ucode_beacon_time;
@@ -3863,27 +4024,31 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 			break;
 
 			/*
-			 * TODO: There is no callback function from upper
-			 * stack to inform us when associated status. this
-			 * work around to sniff assoc_resp management frame
-			 * and finish the association process.
+			 * TODO: Use the new callback function from
+			 * mac80211 instead of sniffing these packets.
 			 */
 		case IEEE80211_STYPE_ASSOC_RESP:
 		case IEEE80211_STYPE_REASSOC_RESP:
 			if (network_packet) {
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 				u8 *pos = NULL;
 				struct ieee802_11_elems elems;
-#endif				/*CONFIG_IWLWIFI_HT */
+#endif				/*CONFIG_IWL4965_HT */
 				struct ieee80211_mgmt *mgnt =
 					(struct ieee80211_mgmt *)header;
 
+				/* We have just associated, give some
+				 * time for the 4-way handshake if
+				 * any. Don't start scan too early. */
+				priv->next_scan_jiffies = jiffies +
+					IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
+
 				priv->assoc_id = (~((1 << 15) | (1 << 14))
 					& le16_to_cpu(mgnt->u.assoc_resp.aid));
 				priv->assoc_capability =
 					le16_to_cpu(
 						mgnt->u.assoc_resp.capab_info);
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 				pos = mgnt->u.assoc_resp.variable;
 				if (!parse_elems(pos,
 						 len - (pos - (u8 *) mgnt),
@@ -3892,7 +4057,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 					    elems.ht_cap_param)
 						break;
 				}
-#endif				/*CONFIG_IWLWIFI_HT */
+#endif				/*CONFIG_IWL4965_HT */
 				/* assoc_id is 0 no association */
 				if (!priv->assoc_id)
 					break;
@@ -3907,7 +4072,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 
 		case IEEE80211_STYPE_PROBE_REQ:
 			if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
-			    !iwl_is_associated(priv)) {
+			    !iwl4965_is_associated(priv)) {
 				DECLARE_MAC_BUF(mac1);
 				DECLARE_MAC_BUF(mac2);
 				DECLARE_MAC_BUF(mac3);
@@ -3924,7 +4089,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 		break;
 
 	case IEEE80211_FTYPE_CTL:
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
 		switch (fc & IEEE80211_FCTL_STYPE) {
 		case IEEE80211_STYPE_BACK_REQ:
 			IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n");
@@ -3935,7 +4100,6 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 			break;
 		}
 #endif
-
 		break;
 
 	case IEEE80211_FTYPE_DATA: {
@@ -3953,7 +4117,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 				       print_mac(mac1, header->addr1),
 				       print_mac(mac2, header->addr2),
 				       print_mac(mac3, header->addr3));
-		else if (unlikely(is_duplicate_packet(priv, header)))
+		else if (unlikely(iwl4965_is_duplicate_packet(priv, header)))
 			IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
 				       print_mac(mac1, header->addr1),
 				       print_mac(mac2, header->addr2),
@@ -3971,22 +4135,22 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 
 /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
  * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
-static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_reply_rx_phy(struct iwl4965_priv *priv,
+				    struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 	priv->last_phy_res[0] = 1;
 	memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
 	       sizeof(struct iwl4965_rx_phy_res));
 }
 
-static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
-					   struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_missed_beacon_notif(struct iwl4965_priv *priv,
+					   struct iwl4965_rx_mem_buffer *rxb)
 
 {
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_missed_beacon_notif *missed_beacon;
+#ifdef CONFIG_IWL4965_SENSITIVITY
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_missed_beacon_notif *missed_beacon;
 
 	missed_beacon = &pkt->u.missed_beacon;
 	if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
@@ -3999,13 +4163,18 @@ static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
 		if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)))
 			queue_work(priv->workqueue, &priv->sensitivity_work);
 	}
-#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+#endif /*CONFIG_IWL4965_SENSITIVITY*/
 }
 
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 
-static void iwl4965_set_tx_status(struct iwl_priv *priv, int txq_id, int idx,
+/**
+ * iwl4965_set_tx_status - Update driver's record of one Tx frame's status
+ *
+ * This will get sent to mac80211.
+ */
+static void iwl4965_set_tx_status(struct iwl4965_priv *priv, int txq_id, int idx,
 				  u32 status, u32 retry_count, u32 rate)
 {
 	struct ieee80211_tx_status *tx_status =
@@ -4017,24 +4186,34 @@ static void iwl4965_set_tx_status(struct iwl_priv *priv, int txq_id, int idx,
 }
 
 
-static void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv,
+/**
+ * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table
+ */
+static void iwl4965_sta_modify_enable_tid_tx(struct iwl4965_priv *priv,
 					 int sta_id, int tid)
 {
 	unsigned long flags;
 
+	/* Remove "disable" flag, to enable Tx for this TID */
 	spin_lock_irqsave(&priv->sta_lock, flags);
 	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
 	priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
 	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
 
 
-static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
-						 struct iwl_ht_agg *agg,
-						 struct iwl_compressed_ba_resp*
+/**
+ * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack
+ *
+ * Go through block-ack's bitmap of ACK'd frames, update driver's record of
+ * ACK vs. not.  This gets sent to mac80211, then to rate scaling algo.
+ */
+static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv,
+						 struct iwl4965_ht_agg *agg,
+						 struct iwl4965_compressed_ba_resp*
 						 ba_resp)
 
 {
@@ -4048,16 +4227,20 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
 		IWL_ERROR("Received BA when not expected\n");
 		return -EINVAL;
 	}
+
+	/* Mark that the expected block-ack response arrived */
 	agg->wait_for_ba = 0;
 	IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl);
-	sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl>>4);
-	if (sh < 0) /* tbw something is wrong with indeces */
+
+	/* Calculate shift to align block-ack bits with our Tx window bits */
+	sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl >> 4);
+	if (sh < 0) /* tbw something is wrong with indices */
 		sh += 0x100;
 
-	/* don't use 64 bits for now */
+	/* don't use 64-bit values for now */
 	bitmap0 = resp_bitmap0 >> sh;
 	bitmap1 = resp_bitmap1 >> sh;
-	bitmap0 |= (resp_bitmap1 & ((1<<sh)|((1<<sh)-1))) << (32 - sh);
+	bitmap0 |= (resp_bitmap1 & ((1 << sh) | ((1 << sh) - 1))) << (32 - sh);
 
 	if (agg->frame_count > (64 - sh)) {
 		IWL_DEBUG_TX_REPLY("more frames than bitmap size");
@@ -4065,10 +4248,12 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
 	}
 
 	/* check for success or failure according to the
-	 * transmitted bitmap and back bitmap */
+	 * transmitted bitmap and block-ack bitmap */
 	bitmap0 &= agg->bitmap0;
 	bitmap1 &= agg->bitmap1;
 
+	/* For each frame attempted in aggregation,
+	 * update driver's record of tx frame's status. */
 	for (i = 0; i < agg->frame_count ; i++) {
 		int idx = (agg->start_idx + i) & 0xff;
 		ack = bitmap0 & (1 << i);
@@ -4084,20 +4269,36 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
 	return 0;
 }
 
-static inline int iwl_queue_dec_wrap(int index, int n_bd)
+/**
+ * iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (s/b power of 2)
+ */
+static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
 {
 	return (index == 0) ? n_bd - 1 : index - 1;
 }
 
-static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
-					   struct iwl_rx_mem_buffer *rxb)
+/**
+ * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
+ *
+ * Handles block-acknowledge notification from device, which reports success
+ * of frames sent via aggregation.
+ */
+static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv,
+					   struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
 	int index;
-	struct iwl_tx_queue *txq = NULL;
-	struct iwl_ht_agg *agg;
+	struct iwl4965_tx_queue *txq = NULL;
+	struct iwl4965_ht_agg *agg;
+
+	/* "flow" corresponds to Tx queue */
 	u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow);
+
+	/* "ssn" is start of block-ack Tx window, corresponds to index
+	 * (in Tx queue's circular buffer) of first TFD/frame in window */
 	u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
 
 	if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) {
@@ -4107,9 +4308,11 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
 
 	txq = &priv->txq[ba_resp_scd_flow];
 	agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
-	index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
 
-	/* TODO: Need to get this copy more sefely - now good for debug */
+	/* Find index just before block-ack window */
+	index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
+
+	/* TODO: Need to get this copy more safely - now good for debug */
 /*
 	{
 	DECLARE_MAC_BUF(mac);
@@ -4132,23 +4335,36 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
 			   agg->bitmap0);
 	}
 */
+
+	/* Update driver's record of ACK vs. not for each frame in window */
 	iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp);
-	/* releases all the TFDs until the SSN */
-	if (txq->q.last_used != (ba_resp_scd_ssn & 0xff))
-		iwl_tx_queue_reclaim(priv, ba_resp_scd_flow, index);
+
+	/* Release all TFDs before the SSN, i.e. all TFDs in front of
+	 * block-ack window (we assume that they've been successfully
+	 * transmitted ... if not, it's too late anyway). */
+	if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff))
+		iwl4965_tx_queue_reclaim(priv, ba_resp_scd_flow, index);
 
 }
 
 
-static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
+/**
+ * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration
+ */
+static void iwl4965_tx_queue_stop_scheduler(struct iwl4965_priv *priv, u16 txq_id)
 {
-	iwl_write_restricted_reg(priv,
-		SCD_QUEUE_STATUS_BITS(txq_id),
+	/* Simply stop the queue, but don't change any configuration;
+	 * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
+	iwl4965_write_prph(priv,
+		KDR_SCD_QUEUE_STATUS_BITS(txq_id),
 		(0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
 		(1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
 }
 
-static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
+/**
+ * iwl4965_tx_queue_set_q2ratid - Map unique receiver/tid combination to a queue
+ */
+static int iwl4965_tx_queue_set_q2ratid(struct iwl4965_priv *priv, u16 ra_tid,
 					u16 txq_id)
 {
 	u32 tbl_dw_addr;
@@ -4160,22 +4376,25 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
 	tbl_dw_addr = priv->scd_base_addr +
 			SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
 
-	tbl_dw = iwl_read_restricted_mem(priv, tbl_dw_addr);
+	tbl_dw = iwl4965_read_targ_mem(priv, tbl_dw_addr);
 
 	if (txq_id & 0x1)
 		tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
 	else
 		tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
 
-	iwl_write_restricted_mem(priv, tbl_dw_addr, tbl_dw);
+	iwl4965_write_targ_mem(priv, tbl_dw_addr, tbl_dw);
 
 	return 0;
 }
 
 /**
- * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
+ * iwl4965_tx_queue_agg_enable - Set up & enable aggregation for selected queue
+ *
+ * NOTE:  txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID,
+ *        i.e. it must be one of the higher queues used for aggregation
  */
-static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
+static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id,
 				       int tx_fifo, int sta_id, int tid,
 				       u16 ssn_idx)
 {
@@ -4189,43 +4408,48 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
 
 	ra_tid = BUILD_RAxTID(sta_id, tid);
 
-	iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+	/* Modify device's station table to Tx this TID */
+	iwl4965_sta_modify_enable_tid_tx(priv, sta_id, tid);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
+	/* Stop this Tx queue before configuring it */
 	iwl4965_tx_queue_stop_scheduler(priv, txq_id);
 
+	/* Map receiver-address / traffic-ID to this queue */
 	iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
 
+	/* Set this queue as a chain-building queue */
+	iwl4965_set_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id));
 
-	iwl_set_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1<<txq_id));
-
-	priv->txq[txq_id].q.last_used = (ssn_idx & 0xff);
-	priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff);
-
-	/* supposes that ssn_idx is valid (!= 0xFFF) */
+	/* Place first TFD at index corresponding to start sequence number.
+	 * Assumes that ssn_idx is valid (!= 0xFFF) */
+	priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+	priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
 	iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
 
-	iwl_write_restricted_mem(priv,
+	/* Set up Tx window size and frame limit for this queue */
+	iwl4965_write_targ_mem(priv,
 			priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id),
 			(SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
 			SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
 
-	iwl_write_restricted_mem(priv, priv->scd_base_addr +
+	iwl4965_write_targ_mem(priv, priv->scd_base_addr +
 			SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
 			(SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS)
 			& SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
 
-	iwl_set_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
+	iwl4965_set_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id));
 
+	/* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
 	iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
@@ -4234,7 +4458,7 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
 /**
  * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
  */
-static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
+static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id,
 					u16 ssn_idx, u8 tx_fifo)
 {
 	unsigned long flags;
@@ -4247,7 +4471,7 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
@@ -4255,56 +4479,50 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
 
 	iwl4965_tx_queue_stop_scheduler(priv, txq_id);
 
-	iwl_clear_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1 << txq_id));
+	iwl4965_clear_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id));
 
-	priv->txq[txq_id].q.last_used = (ssn_idx & 0xff);
-	priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff);
+	priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+	priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
 	/* supposes that ssn_idx is valid (!= 0xFFF) */
 	iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
 
-	iwl_clear_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
+	iwl4965_clear_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id));
 	iwl4965_txq_ctx_deactivate(priv, txq_id);
 	iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	return 0;
 }
 
-#endif/* CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
-/*
- * RATE SCALE CODE
- */
-int iwl4965_init_hw_rates(struct iwl_priv *priv, struct ieee80211_rate *rates)
-{
-	return 0;
-}
-
+#endif/* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 
 /**
  * iwl4965_add_station - Initialize a station's hardware rate table
  *
- * The uCode contains a table of fallback rates and retries per rate
+ * The uCode's station table contains a table of fallback rates
  * for automatic fallback during transmission.
  *
- * NOTE: This initializes the table for a single retry per data rate
- * which is not optimal.  Setting up an intelligent retry per rate
- * requires feedback from transmission, which isn't exposed through
- * rc80211_simple which is what this driver is currently using.
+ * NOTE: This sets up a default set of values.  These will be replaced later
+ *       if the driver's iwl-4965-rs rate scaling algorithm is used, instead of
+ *       rc80211_simple.
  *
+ * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
+ *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
+ *       which requires station table entry to exist).
  */
-void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap)
 {
 	int i, r;
-	struct iwl_link_quality_cmd link_cmd = {
+	struct iwl4965_link_quality_cmd link_cmd = {
 		.reserved1 = 0,
 	};
 	u16 rate_flags;
 
-	/* Set up the rate scaling to start at 54M and fallback
-	 * all the way to 1M in IEEE order and then spin on IEEE */
+	/* Set up the rate scaling to start at selected rate, fall back
+	 * all the way down to 1M in IEEE order, and then spin on 1M */
 	if (is_ap)
 		r = IWL_RATE_54M_INDEX;
 	else if (priv->phymode == MODE_IEEE80211A)
@@ -4317,11 +4535,13 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
 		if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
 			rate_flags |= RATE_MCS_CCK_MSK;
 
+		/* Use Tx antenna B only */
 		rate_flags |= RATE_MCS_ANT_B_MSK;
 		rate_flags &= ~RATE_MCS_ANT_A_MSK;
+
 		link_cmd.rs_table[i].rate_n_flags =
-			iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
-		r = iwl_get_prev_ieee_rate(r);
+			iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags);
+		r = iwl4965_get_prev_ieee_rate(r);
 	}
 
 	link_cmd.general_params.single_stream_ant_msk = 2;
@@ -4332,18 +4552,18 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
 	/* Update the rate scaling for control frame Tx to AP */
 	link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL4965_BROADCAST_ID;
 
-	iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd),
+	iwl4965_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd),
 			 &link_cmd);
 }
 
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 
-static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode,
+static u8 iwl4965_is_channel_extension(struct iwl4965_priv *priv, int phymode,
 				   u16 channel, u8 extension_chan_offset)
 {
-	const struct iwl_channel_info *ch_info;
+	const struct iwl4965_channel_info *ch_info;
 
-	ch_info = iwl_get_channel_info(priv, phymode, channel);
+	ch_info = iwl4965_get_channel_info(priv, phymode, channel);
 	if (!is_channel_valid(ch_info))
 		return 0;
 
@@ -4357,36 +4577,37 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode,
 	return 0;
 }
 
-static u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
-				const struct sta_ht_info *ht_info)
+static u8 iwl4965_is_fat_tx_allowed(struct iwl4965_priv *priv,
+				struct ieee80211_ht_info *sta_ht_inf)
 {
+	struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config;
 
-	if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
+	if ((!iwl_ht_conf->is_ht) ||
+	   (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) ||
+	   (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO))
 		return 0;
 
-	if (ht_info->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)
-		return 0;
-
-	if (ht_info->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)
-		return 0;
+	if (sta_ht_inf) {
+		if ((!sta_ht_inf->ht_supported) ||
+		   (!sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH))
+			return 0;
+	}
 
-	/* no fat tx allowed on 2.4GHZ */
-	if (priv->phymode != MODE_IEEE80211A)
-		return 0;
-	return (iwl_is_channel_extension(priv, priv->phymode,
-					 ht_info->control_channel,
-					 ht_info->extension_chan_offset));
+	return (iwl4965_is_channel_extension(priv, priv->phymode,
+					 iwl_ht_conf->control_channel,
+					 iwl_ht_conf->extension_chan_offset));
 }
 
-void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info)
+void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, struct iwl_ht_info *ht_info)
 {
-	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+	struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
 	u32 val;
 
 	if (!ht_info->is_ht)
 		return;
 
-	if (iwl_is_fat_tx_allowed(priv, ht_info))
+	/* Set up channel bandwidth:  20 MHz only, or 20/40 mixed if fat ok */
+	if (iwl4965_is_fat_tx_allowed(priv, NULL))
 		rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
 	else
 		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
@@ -4400,7 +4621,7 @@ void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info)
 		return;
 	}
 
-	/* Note: control channel is oposit to extension channel */
+	/* Note: control channel is opposite of extension channel */
 	switch (ht_info->extension_chan_offset) {
 	case IWL_EXT_CHANNEL_OFFSET_ABOVE:
 		rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
@@ -4416,66 +4637,56 @@ void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info)
 		break;
 	}
 
-	val = ht_info->operating_mode;
+	val = ht_info->ht_protection;
 
 	rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
 
-	priv->active_rate_ht[0] = ht_info->supp_rates[0];
-	priv->active_rate_ht[1] = ht_info->supp_rates[1];
 	iwl4965_set_rxon_chain(priv);
 
 	IWL_DEBUG_ASSOC("supported HT rate 0x%X %X "
 			"rxon flags 0x%X operation mode :0x%X "
 			"extension channel offset 0x%x "
 			"control chan %d\n",
-			priv->active_rate_ht[0], priv->active_rate_ht[1],
-			le32_to_cpu(rxon->flags), ht_info->operating_mode,
+			ht_info->supp_mcs_set[0], ht_info->supp_mcs_set[1],
+			le32_to_cpu(rxon->flags), ht_info->ht_protection,
 			ht_info->extension_chan_offset,
 			ht_info->control_channel);
 	return;
 }
 
-void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index)
+void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index,
+				struct ieee80211_ht_info *sta_ht_inf)
 {
 	__le32 sta_flags;
-	struct sta_ht_info *ht_info = &priv->current_assoc_ht;
 
-	priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
-	if (!ht_info->is_ht)
+	if (!sta_ht_inf || !sta_ht_inf->ht_supported)
 		goto done;
 
 	sta_flags = priv->stations[index].sta.station_flags;
 
-	if (ht_info->tx_mimo_ps_mode == IWL_MIMO_PS_DYNAMIC)
+	if (((sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS >> 2))
+						== IWL_MIMO_PS_DYNAMIC)
 		sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
 	else
 		sta_flags &= ~STA_FLG_RTS_MIMO_PROT_MSK;
 
 	sta_flags |= cpu_to_le32(
-		(u32)ht_info->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
+	      (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
 
 	sta_flags |= cpu_to_le32(
-		(u32)ht_info->mpdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
-
-	sta_flags &= (~STA_FLG_FAT_EN_MSK);
-	ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_20MHZ;
-	ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_20MHZ;
+	      (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
 
-	if (iwl_is_fat_tx_allowed(priv, ht_info)) {
+	if (iwl4965_is_fat_tx_allowed(priv, sta_ht_inf))
 		sta_flags |= STA_FLG_FAT_EN_MSK;
-		ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_40MHZ;
-		if (ht_info->supported_chan_width == IWL_CHANNEL_WIDTH_40MHZ)
-			ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_40MHZ;
-	}
-	priv->current_channel_width = ht_info->tx_chan_width;
+	else
+		sta_flags &= (~STA_FLG_FAT_EN_MSK);
+
 	priv->stations[index].sta.station_flags = sta_flags;
  done:
 	return;
 }
 
-#ifdef CONFIG_IWLWIFI_HT_AGG
-
-static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv,
+static void iwl4965_sta_modify_add_ba_tid(struct iwl4965_priv *priv,
 					  int sta_id, int tid, u16 ssn)
 {
 	unsigned long flags;
@@ -4488,10 +4699,10 @@ static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv,
 	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
 
-static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv,
+static void iwl4965_sta_modify_del_ba_tid(struct iwl4965_priv *priv,
 					  int sta_id, int tid)
 {
 	unsigned long flags;
@@ -4503,9 +4714,39 @@ static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv,
 	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
+			     enum ieee80211_ampdu_mlme_action action,
+			     const u8 *addr, u16 tid, u16 ssn)
+{
+	struct iwl4965_priv *priv = hw->priv;
+	int sta_id;
+	DECLARE_MAC_BUF(mac);
+
+	IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ",
+			print_mac(mac, addr), tid);
+	sta_id = iwl4965_hw_find_station(priv, addr);
+	switch (action) {
+	case IEEE80211_AMPDU_RX_START:
+		IWL_DEBUG_HT("start Rx\n");
+		iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, ssn);
+		break;
+	case IEEE80211_AMPDU_RX_STOP:
+		IWL_DEBUG_HT("stop Rx\n");
+		iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid);
+		break;
+	default:
+		IWL_DEBUG_HT("unknown\n");
+		return -EINVAL;
+		break;
+	}
+	return 0;
 }
 
+#ifdef CONFIG_IWL4965_HT_AGG
+
 static const u16 default_tid_to_tx_fifo[] = {
 	IWL_TX_FIFO_AC1,
 	IWL_TX_FIFO_AC0,
@@ -4526,7 +4767,13 @@ static const u16 default_tid_to_tx_fifo[] = {
 	IWL_TX_FIFO_AC3
 };
 
-static int iwl_txq_ctx_activate_free(struct iwl_priv *priv)
+/*
+ * Find first available (lowest unused) Tx Queue, mark it "active".
+ * Called only when finding queue for aggregation.
+ * Should never return anything < 7, because they should already
+ * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6).
+ */
+static int iwl4965_txq_ctx_activate_free(struct iwl4965_priv *priv)
 {
 	int txq_id;
 
@@ -4536,55 +4783,65 @@ static int iwl_txq_ctx_activate_free(struct iwl_priv *priv)
 	return -1;
 }
 
-int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid,
+int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid,
 			    u16 *start_seq_num)
 {
 
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 	int sta_id;
 	int tx_fifo;
 	int txq_id;
 	int ssn = -1;
 	unsigned long flags;
-	struct iwl_tid_data *tid_data;
+	struct iwl4965_tid_data *tid_data;
 	DECLARE_MAC_BUF(mac);
 
+	/* Determine Tx DMA/FIFO channel for this Traffic ID */
 	if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
 		tx_fifo = default_tid_to_tx_fifo[tid];
 	else
 		return -EINVAL;
 
-	IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=%s"
+	IWL_WARNING("iwl-AGG iwl4965_mac_ht_tx_agg_start on da=%s"
 		    " tid=%d\n", print_mac(mac, da), tid);
 
-	sta_id = iwl_hw_find_station(priv, da);
+	/* Get index into station table */
+	sta_id = iwl4965_hw_find_station(priv, da);
 	if (sta_id == IWL_INVALID_STATION)
 		return -ENXIO;
 
-	txq_id = iwl_txq_ctx_activate_free(priv);
+	/* Find available Tx queue for aggregation */
+	txq_id = iwl4965_txq_ctx_activate_free(priv);
 	if (txq_id == -1)
 		return -ENXIO;
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
 	tid_data = &priv->stations[sta_id].tid[tid];
+
+	/* Get starting sequence number for 1st frame in block ack window.
+	 * We'll use least signif byte as 1st frame's index into Tx queue. */
 	ssn = SEQ_TO_SN(tid_data->seq_number);
 	tid_data->agg.txq_id = txq_id;
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
 	*start_seq_num = ssn;
+
+	/* Update driver's link quality manager */
 	iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE);
+
+	/* Set up and enable aggregation for selected Tx queue and FIFO */
 	return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo,
 					   sta_id, tid, ssn);
 }
 
 
-int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid,
+int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid,
 			   int generator)
 {
 
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 	int tx_fifo_id, txq_id, sta_id, ssn = -1;
-	struct iwl_tid_data *tid_data;
+	struct iwl4965_tid_data *tid_data;
 	int rc;
 	DECLARE_MAC_BUF(mac);
 
@@ -4598,7 +4855,7 @@ int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid,
 	else
 		return -EINVAL;
 
-	sta_id = iwl_hw_find_station(priv, da);
+	sta_id = iwl4965_hw_find_station(priv, da);
 
 	if (sta_id == IWL_INVALID_STATION)
 		return -ENXIO;
@@ -4613,45 +4870,18 @@ int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid,
 		return rc;
 
 	iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA);
-	IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=%s tid=%d\n",
+	IWL_DEBUG_INFO("iwl4965_mac_ht_tx_agg_stop on da=%s tid=%d\n",
 		       print_mac(mac, da), tid);
 
 	return 0;
 }
 
-int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da,
-			    u16 tid, u16 start_seq_num)
-{
-	struct iwl_priv *priv = hw->priv;
-	int sta_id;
-	DECLARE_MAC_BUF(mac);
 
-	IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=%s"
-		    " tid=%d\n", print_mac(mac, da), tid);
-	sta_id = iwl_hw_find_station(priv, da);
-	iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, start_seq_num);
-	return 0;
-}
-
-int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da,
-			   u16 tid, int generator)
-{
-	struct iwl_priv *priv = hw->priv;
-	int sta_id;
-	DECLARE_MAC_BUF(mac);
-
-	IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=%s tid=%d\n",
-		    print_mac(mac, da), tid);
-	sta_id = iwl_hw_find_station(priv, da);
-	iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid);
-	return 0;
-}
-
-#endif /* CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 
 /* Set up 4965-specific Rx frame reply handlers */
-void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
+void iwl4965_hw_rx_handler_setup(struct iwl4965_priv *priv)
 {
 	/* Legacy Rx frames */
 	priv->rx_handlers[REPLY_4965_RX] = iwl4965_rx_reply_rx;
@@ -4663,57 +4893,66 @@ void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
 	priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
 	    iwl4965_rx_missed_beacon_notif;
 
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 	priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba;
-#endif /* CONFIG_IWLWIFI_AGG */
-#endif /* CONFIG_IWLWIFI */
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 }
 
-void iwl_hw_setup_deferred_work(struct iwl_priv *priv)
+void iwl4965_hw_setup_deferred_work(struct iwl4965_priv *priv)
 {
 	INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work);
 	INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work);
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
+#ifdef CONFIG_IWL4965_SENSITIVITY
 	INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work);
 #endif
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 	INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work);
-#endif /* CONFIG_IWLWIFI_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 	init_timer(&priv->statistics_periodic);
 	priv->statistics_periodic.data = (unsigned long)priv;
 	priv->statistics_periodic.function = iwl4965_bg_statistics_periodic;
 }
 
-void iwl_hw_cancel_deferred_work(struct iwl_priv *priv)
+void iwl4965_hw_cancel_deferred_work(struct iwl4965_priv *priv)
 {
 	del_timer_sync(&priv->statistics_periodic);
 
 	cancel_delayed_work(&priv->init_alive_start);
 }
 
-struct pci_device_id iwl_hw_card_ids[] = {
-	{0x8086, 0x4229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x4230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+struct pci_device_id iwl4965_hw_card_ids[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4229)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4230)},
 	{0}
 };
 
-int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
+/*
+ * The device's EEPROM semaphore prevents conflicts between driver and uCode
+ * when accessing the EEPROM; each access is a series of pulses to/from the
+ * EEPROM chip, not a single event, so even reads could conflict if they
+ * weren't arbitrated by the semaphore.
+ */
+int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv)
 {
 	u16 count;
 	int rc;
 
 	for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
-		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+		/* Request semaphore */
+		iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG,
 			CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-		rc = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+
+		/* See if we got it */
+		rc = iwl4965_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
 					CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
 					CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
 					EEPROM_SEM_TIMEOUT);
 		if (rc >= 0) {
-			IWL_DEBUG_IO("Aqcuired semaphore after %d tries.\n",
+			IWL_DEBUG_IO("Acquired semaphore after %d tries.\n",
 				count+1);
 			return rc;
 		}
@@ -4722,11 +4961,11 @@ int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
 	return rc;
 }
 
-inline void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
+inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv)
 {
-	iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+	iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
 		CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 }
 
 
-MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
+MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index 4c700812b45b..78bc148c9f7f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -23,64 +23,777 @@
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
+/*
+ * Please use this file (iwl-4965.h) for driver implementation definitions.
+ * Please use iwl-4965-commands.h for uCode API definitions.
+ * Please use iwl-4965-hw.h for hardware-related definitions.
+ */
+
 #ifndef __iwl_4965_h__
 #define __iwl_4965_h__
 
-struct iwl_priv;
-struct sta_ht_info;
+#include <linux/pci.h> /* for struct pci_device_id */
+#include <linux/kernel.h>
+#include <net/ieee80211_radiotap.h>
+
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+extern struct pci_device_id iwl4965_hw_card_ids[];
+
+#define DRV_NAME        "iwl4965"
+#include "iwl-4965-hw.h"
+#include "iwl-prph.h"
+#include "iwl-4965-debug.h"
+
+/* Default noise level to report when noise measurement is not available.
+ *   This may be because we're:
+ *   1)  Not associated (4965, no beacon statistics being sent to driver)
+ *   2)  Scanning (noise measurement does not apply to associated channel)
+ *   3)  Receiving CCK (3945 delivers noise info only for OFDM frames)
+ * Use default noise value of -127 ... this is below the range of measurable
+ *   Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
+ *   Also, -127 works better than 0 when averaging frames with/without
+ *   noise info (e.g. averaging might be done in app); measured dBm values are
+ *   always negative ... using a negative value as the default keeps all
+ *   averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
+
+/* Module parameters accessible from iwl-*.c */
+extern int iwl4965_param_hwcrypto;
+extern int iwl4965_param_queues_num;
+extern int iwl4965_param_amsdu_size_8K;
+
+enum iwl4965_antenna {
+	IWL_ANTENNA_DIVERSITY,
+	IWL_ANTENNA_MAIN,
+	IWL_ANTENNA_AUX
+};
+
+/*
+ * RTS threshold here is total size [2347] minus 4 FCS bytes
+ * Per spec:
+ *   a value of 0 means RTS on all data/management packets
+ *   a value > max MSDU size means no RTS
+ * else RTS for data/management frames where MPDU is larger
+ *   than RTS value.
+ */
+#define DEFAULT_RTS_THRESHOLD     2347U
+#define MIN_RTS_THRESHOLD         0U
+#define MAX_RTS_THRESHOLD         2347U
+#define MAX_MSDU_SIZE		  2304U
+#define MAX_MPDU_SIZE		  2346U
+#define DEFAULT_BEACON_INTERVAL   100U
+#define	DEFAULT_SHORT_RETRY_LIMIT 7U
+#define	DEFAULT_LONG_RETRY_LIMIT  4U
+
+struct iwl4965_rx_mem_buffer {
+	dma_addr_t dma_addr;
+	struct sk_buff *skb;
+	struct list_head list;
+};
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+struct iwl4965_queue {
+	int n_bd;              /* number of BDs in this queue */
+	int write_ptr;       /* 1-st empty entry (index) host_w*/
+	int read_ptr;         /* last used entry (index) host_r*/
+	dma_addr_t dma_addr;   /* physical addr for BD's */
+	int n_window;	       /* safe queue window */
+	u32 id;
+	int low_mark;	       /* low watermark, resume queue if free
+				* space more than this */
+	int high_mark;         /* high watermark, stop queue if free
+				* space less than this */
+} __attribute__ ((packed));
+
+#define MAX_NUM_OF_TBS          (20)
+
+/* One for each TFD */
+struct iwl4965_tx_info {
+	struct ieee80211_tx_status status;
+	struct sk_buff *skb[MAX_NUM_OF_TBS];
+};
+
+/**
+ * struct iwl4965_tx_queue - Tx Queue for DMA
+ * @q: generic Rx/Tx queue descriptor
+ * @bd: base of circular buffer of TFDs
+ * @cmd: array of command/Tx buffers
+ * @dma_addr_cmd: physical address of cmd/tx buffer array
+ * @txb: array of per-TFD driver data
+ * @need_update: indicates need to update read/write index
+ * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled
+ *
+ * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
+ * descriptors) and required locking structures.
+ */
+struct iwl4965_tx_queue {
+	struct iwl4965_queue q;
+	struct iwl4965_tfd_frame *bd;
+	struct iwl4965_cmd *cmd;
+	dma_addr_t dma_addr_cmd;
+	struct iwl4965_tx_info *txb;
+	int need_update;
+	int sched_retry;
+	int active;
+};
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+struct iwl4965_channel_tgd_info {
+	u8 type;
+	s8 max_power;
+};
+
+struct iwl4965_channel_tgh_info {
+	s64 last_radar_time;
+};
+
+/* current Tx power values to use, one for each rate for each channel.
+ * requested power is limited by:
+ * -- regulatory EEPROM limits for this channel
+ * -- hardware capabilities (clip-powers)
+ * -- spectrum management
+ * -- user preference (e.g. iwconfig)
+ * when requested power is set, base power index must also be set. */
+struct iwl4965_channel_power_info {
+	struct iwl4965_tx_power tpc;	/* actual radio and DSP gain settings */
+	s8 power_table_index;	/* actual (compenst'd) index into gain table */
+	s8 base_power_index;	/* gain index for power at factory temp. */
+	s8 requested_power;	/* power (dBm) requested for this chnl/rate */
+};
+
+/* current scan Tx power values to use, one for each scan rate for each
+ * channel. */
+struct iwl4965_scan_power_info {
+	struct iwl4965_tx_power tpc;	/* actual radio and DSP gain settings */
+	s8 power_table_index;	/* actual (compenst'd) index into gain table */
+	s8 requested_power;	/* scan pwr (dBm) requested for chnl/rate */
+};
+
+/* For fat_extension_channel */
+enum {
+	HT_IE_EXT_CHANNEL_NONE = 0,
+	HT_IE_EXT_CHANNEL_ABOVE,
+	HT_IE_EXT_CHANNEL_INVALID,
+	HT_IE_EXT_CHANNEL_BELOW,
+	HT_IE_EXT_CHANNEL_MAX
+};
+
+/*
+ * One for each channel, holds all channel setup data
+ * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
+ *     with one another!
+ */
+#define IWL4965_MAX_RATE (33)
+
+struct iwl4965_channel_info {
+	struct iwl4965_channel_tgd_info tgd;
+	struct iwl4965_channel_tgh_info tgh;
+	struct iwl4965_eeprom_channel eeprom;	  /* EEPROM regulatory limit */
+	struct iwl4965_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
+						   * FAT channel */
+
+	u8 channel;	  /* channel number */
+	u8 flags;	  /* flags copied from EEPROM */
+	s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+	s8 curr_txpow;	  /* (dBm) regulatory/spectrum/user (not h/w) limit */
+	s8 min_power;	  /* always 0 */
+	s8 scan_power;	  /* (dBm) regul. eeprom, direct scans, any rate */
+
+	u8 group_index;	  /* 0-4, maps channel to group1/2/3/4/5 */
+	u8 band_index;	  /* 0-4, maps channel to band1/2/3/4/5 */
+	u8 phymode;	  /* MODE_IEEE80211{A,B,G} */
+
+	/* Radio/DSP gain settings for each "normal" data Tx rate.
+	 * These include, in addition to RF and DSP gain, a few fields for
+	 *   remembering/modifying gain settings (indexes). */
+	struct iwl4965_channel_power_info power_info[IWL4965_MAX_RATE];
+
+	/* FAT channel info */
+	s8 fat_max_power_avg;	/* (dBm) regul. eeprom, normal Tx, any rate */
+	s8 fat_curr_txpow;	/* (dBm) regulatory/spectrum/user (not h/w) */
+	s8 fat_min_power;	/* always 0 */
+	s8 fat_scan_power;	/* (dBm) eeprom, direct scans, any rate */
+	u8 fat_flags;		/* flags copied from EEPROM */
+	u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */
+
+	/* Radio/DSP gain settings for each scan rate, for directed scans. */
+	struct iwl4965_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
+};
+
+struct iwl4965_clip_group {
+	/* maximum power level to prevent clipping for each rate, derived by
+	 *   us from this band's saturation power in EEPROM */
+	const s8 clip_powers[IWL_MAX_RATES];
+};
+
+#include "iwl-4965-rs.h"
+
+#define IWL_TX_FIFO_AC0	0
+#define IWL_TX_FIFO_AC1	1
+#define IWL_TX_FIFO_AC2	2
+#define IWL_TX_FIFO_AC3	3
+#define IWL_TX_FIFO_HCCA_1	5
+#define IWL_TX_FIFO_HCCA_2	6
+#define IWL_TX_FIFO_NONE	7
+
+/* Minimum number of queues. MAX_NUM is defined in hw specific files */
+#define IWL_MIN_NUM_QUEUES	4
+
+/* Power management (not Tx power) structures */
+
+struct iwl4965_power_vec_entry {
+	struct iwl4965_powertable_cmd cmd;
+	u8 no_dtim;
+};
+#define IWL_POWER_RANGE_0  (0)
+#define IWL_POWER_RANGE_1  (1)
+
+#define IWL_POWER_MODE_CAM	0x00	/* Continuously Aware Mode, always on */
+#define IWL_POWER_INDEX_3	0x03
+#define IWL_POWER_INDEX_5	0x05
+#define IWL_POWER_AC		0x06
+#define IWL_POWER_BATTERY	0x07
+#define IWL_POWER_LIMIT		0x07
+#define IWL_POWER_MASK		0x0F
+#define IWL_POWER_ENABLED	0x10
+#define IWL_POWER_LEVEL(x)	((x) & IWL_POWER_MASK)
+
+struct iwl4965_power_mgr {
+	spinlock_t lock;
+	struct iwl4965_power_vec_entry pwr_range_0[IWL_POWER_AC];
+	struct iwl4965_power_vec_entry pwr_range_1[IWL_POWER_AC];
+	u8 active_index;
+	u32 dtim_val;
+};
+
+#define IEEE80211_DATA_LEN              2304
+#define IEEE80211_4ADDR_LEN             30
+#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct iwl4965_frame {
+	union {
+		struct ieee80211_hdr frame;
+		struct iwl4965_tx_beacon_cmd beacon;
+		u8 raw[IEEE80211_FRAME_LEN];
+		u8 cmd[360];
+	} u;
+	struct list_head list;
+};
+
+#define SEQ_TO_QUEUE(x)  ((x >> 8) & 0xbf)
+#define QUEUE_TO_SEQ(x)  ((x & 0xbf) << 8)
+#define SEQ_TO_INDEX(x) (x & 0xff)
+#define INDEX_TO_SEQ(x) (x & 0xff)
+#define SEQ_HUGE_FRAME  (0x4000)
+#define SEQ_RX_FRAME    __constant_cpu_to_le16(0x8000)
+#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+
+enum {
+	/* CMD_SIZE_NORMAL = 0, */
+	CMD_SIZE_HUGE = (1 << 0),
+	/* CMD_SYNC = 0, */
+	CMD_ASYNC = (1 << 1),
+	/* CMD_NO_SKB = 0, */
+	CMD_WANT_SKB = (1 << 2),
+};
+
+struct iwl4965_cmd;
+struct iwl4965_priv;
+
+struct iwl4965_cmd_meta {
+	struct iwl4965_cmd_meta *source;
+	union {
+		struct sk_buff *skb;
+		int (*callback)(struct iwl4965_priv *priv,
+				struct iwl4965_cmd *cmd, struct sk_buff *skb);
+	} __attribute__ ((packed)) u;
+
+	/* The CMD_SIZE_HUGE flag bit indicates that the command
+	 * structure is stored at the end of the shared queue memory. */
+	u32 flags;
+
+} __attribute__ ((packed));
+
+/**
+ * struct iwl4965_cmd
+ *
+ * For allocation of the command and tx queues, this establishes the overall
+ * size of the largest command we send to uCode, except for a scan command
+ * (which is relatively huge; space is allocated separately).
+ */
+struct iwl4965_cmd {
+	struct iwl4965_cmd_meta meta;	/* driver data */
+	struct iwl4965_cmd_header hdr;	/* uCode API */
+	union {
+		struct iwl4965_addsta_cmd addsta;
+		struct iwl4965_led_cmd led;
+		u32 flags;
+		u8 val8;
+		u16 val16;
+		u32 val32;
+		struct iwl4965_bt_cmd bt;
+		struct iwl4965_rxon_time_cmd rxon_time;
+		struct iwl4965_powertable_cmd powertable;
+		struct iwl4965_qosparam_cmd qosparam;
+		struct iwl4965_tx_cmd tx;
+		struct iwl4965_tx_beacon_cmd tx_beacon;
+		struct iwl4965_rxon_assoc_cmd rxon_assoc;
+		u8 *indirect;
+		u8 payload[360];
+	} __attribute__ ((packed)) cmd;
+} __attribute__ ((packed));
+
+struct iwl4965_host_cmd {
+	u8 id;
+	u16 len;
+	struct iwl4965_cmd_meta meta;
+	const void *data;
+};
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl4965_cmd) - \
+			      sizeof(struct iwl4965_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/**
+ * struct iwl4965_rx_queue - Rx queue
+ * @processed: Internal index to last handled Rx packet
+ * @read: Shared index to newest available Rx buffer
+ * @write: Shared index to oldest written Rx packet
+ * @free_count: Number of pre-allocated buffers in rx_free
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
+ * @need_update: flag to indicate we need to update read/write index
+ *
+ * NOTE:  rx_free and rx_used are used as a FIFO for iwl4965_rx_mem_buffers
+ */
+struct iwl4965_rx_queue {
+	__le32 *bd;
+	dma_addr_t dma_addr;
+	struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+	struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+	u32 processed;
+	u32 read;
+	u32 write;
+	u32 free_count;
+	struct list_head rx_free;
+	struct list_head rx_used;
+	int need_update;
+	spinlock_t lock;
+};
+
+#define IWL_SUPPORTED_RATES_IE_LEN         8
+
+#define SCAN_INTERVAL 100
+
+#define MAX_A_CHANNELS  252
+#define MIN_A_CHANNELS  7
+
+#define MAX_B_CHANNELS  14
+#define MIN_B_CHANNELS  1
+
+#define STATUS_HCMD_ACTIVE	0	/* host command in progress */
+#define STATUS_INT_ENABLED	1
+#define STATUS_RF_KILL_HW	2
+#define STATUS_RF_KILL_SW	3
+#define STATUS_INIT		4
+#define STATUS_ALIVE		5
+#define STATUS_READY		6
+#define STATUS_TEMPERATURE	7
+#define STATUS_GEO_CONFIGURED	8
+#define STATUS_EXIT_PENDING	9
+#define STATUS_IN_SUSPEND	10
+#define STATUS_STATISTICS	11
+#define STATUS_SCANNING		12
+#define STATUS_SCAN_ABORTING	13
+#define STATUS_SCAN_HW		14
+#define STATUS_POWER_PMI	15
+#define STATUS_FW_ERROR		16
+#define STATUS_CONF_PENDING	17
+
+#define MAX_TID_COUNT        9
+
+#define IWL_INVALID_RATE     0xFF
+#define IWL_INVALID_VALUE    -1
+
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+/**
+ * struct iwl4965_ht_agg -- aggregation status while waiting for block-ack
+ * @txq_id: Tx queue used for Tx attempt
+ * @frame_count: # frames attempted by Tx command
+ * @wait_for_ba: Expect block-ack before next Tx reply
+ * @start_idx: Index of 1st Transmit Frame Descriptor (TFD) in Tx window
+ * @bitmap0: Low order bitmap, one bit for each frame pending ACK in Tx window
+ * @bitmap1: High order, one bit for each frame pending ACK in Tx window
+ * @rate_n_flags: Rate at which Tx was attempted
+ *
+ * If REPLY_TX indicates that aggregation was attempted, driver must wait
+ * for block ack (REPLY_COMPRESSED_BA).  This struct stores tx reply info
+ * until block ack arrives.
+ */
+struct iwl4965_ht_agg {
+	u16 txq_id;
+	u16 frame_count;
+	u16 wait_for_ba;
+	u16 start_idx;
+	u32 bitmap0;
+	u32 bitmap1;
+	u32 rate_n_flags;
+};
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+
+struct iwl4965_tid_data {
+	u16 seq_number;
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+	struct iwl4965_ht_agg agg;
+#endif	/* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+};
+
+struct iwl4965_hw_key {
+	enum ieee80211_key_alg alg;
+	int keylen;
+	u8 key[32];
+};
+
+union iwl4965_ht_rate_supp {
+	u16 rates;
+	struct {
+		u8 siso_rate;
+		u8 mimo_rate;
+	};
+};
+
+#ifdef CONFIG_IWL4965_HT
+#define CFG_HT_RX_AMPDU_FACTOR_DEF  (0x3)
+#define CFG_HT_MPDU_DENSITY_2USEC   (0x5)
+#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
+
+struct iwl_ht_info {
+	/* self configuration data */
+	u8 is_ht;
+	u8 supported_chan_width;
+	u16 tx_mimo_ps_mode;
+	u8 is_green_field;
+	u8 sgf;			/* HT_SHORT_GI_* short guard interval */
+	u8 max_amsdu_size;
+	u8 ampdu_factor;
+	u8 mpdu_density;
+	u8 supp_mcs_set[16];
+	/* BSS related data */
+	u8 control_channel;
+	u8 extension_chan_offset;
+	u8 tx_chan_width;
+	u8 ht_protection;
+	u8 non_GF_STA_present;
+};
+#endif				/*CONFIG_IWL4965_HT */
+
+#ifdef CONFIG_IWL4965_QOS
+
+union iwl4965_qos_capabity {
+	struct {
+		u8 edca_count:4;	/* bit 0-3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 queue_request:1;	/* bit 5 */
+		u8 txop_request:1;	/* bit 6 */
+		u8 reserved:1;		/* bit 7 */
+	} q_AP;
+	struct {
+		u8 acvo_APSD:1;		/* bit 0 */
+		u8 acvi_APSD:1;		/* bit 1 */
+		u8 ac_bk_APSD:1;	/* bit 2 */
+		u8 ac_be_APSD:1;	/* bit 3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 max_len:2;		/* bit 5-6 */
+		u8 more_data_ack:1;	/* bit 7 */
+	} q_STA;
+	u8 val;
+};
+
+/* QoS structures */
+struct iwl4965_qos_info {
+	int qos_enable;
+	int qos_active;
+	union iwl4965_qos_capabity qos_cap;
+	struct iwl4965_qosparam_cmd def_qos_parm;
+};
+#endif /*CONFIG_IWL4965_QOS */
+
+#define STA_PS_STATUS_WAKE             0
+#define STA_PS_STATUS_SLEEP            1
+
+struct iwl4965_station_entry {
+	struct iwl4965_addsta_cmd sta;
+	struct iwl4965_tid_data tid[MAX_TID_COUNT];
+	u8 used;
+	u8 ps_status;
+	struct iwl4965_hw_key keyinfo;
+};
+
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_desc {
+	void *v_addr;		/* access by driver */
+	dma_addr_t p_addr;	/* access by card's busmaster DMA */
+	u32 len;		/* bytes */
+};
+
+/* uCode file layout */
+struct iwl4965_ucode {
+	__le32 ver;		/* major/minor/subminor */
+	__le32 inst_size;	/* bytes of runtime instructions */
+	__le32 data_size;	/* bytes of runtime data */
+	__le32 init_size;	/* bytes of initialization instructions */
+	__le32 init_data_size;	/* bytes of initialization data */
+	__le32 boot_size;	/* bytes of bootstrap instructions */
+	u8 data[0];		/* data in same order as "size" elements */
+};
+
+#define IWL_IBSS_MAC_HASH_SIZE 32
+
+struct iwl4965_ibss_seq {
+	u8 mac[ETH_ALEN];
+	u16 seq_num;
+	u16 frag_num;
+	unsigned long packet_time;
+	struct list_head list;
+};
+
+/**
+ * struct iwl4965_driver_hw_info
+ * @max_txq_num: Max # Tx queues supported
+ * @ac_queue_count: # Tx queues for EDCA Access Categories (AC)
+ * @tx_cmd_len: Size of Tx command (but not including frame itself)
+ * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2)
+ * @rx_buffer_size:
+ * @max_rxq_log: Log-base-2 of max_rxq_size
+ * @max_stations:
+ * @bcast_sta_id:
+ * @shared_virt: Pointer to driver/uCode shared Tx Byte Counts and Rx status
+ * @shared_phys: Physical Pointer to Tx Byte Counts and Rx status
+ */
+struct iwl4965_driver_hw_info {
+	u16 max_txq_num;
+	u16 ac_queue_count;
+	u16 tx_cmd_len;
+	u16 max_rxq_size;
+	u32 rx_buf_size;
+	u32 max_pkt_size;
+	u16 max_rxq_log;
+	u8  max_stations;
+	u8  bcast_sta_id;
+	void *shared_virt;
+	dma_addr_t shared_phys;
+};
+
+#define HT_SHORT_GI_20MHZ_ONLY          (1 << 0)
+#define HT_SHORT_GI_40MHZ_ONLY          (1 << 1)
+
+
+#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\
+		       x->u.rx_frame.stats.payload + \
+		       x->u.rx_frame.stats.phy_count))
+#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\
+		       IWL_RX_HDR(x)->payload + \
+		       le16_to_cpu(IWL_RX_HDR(x)->len)))
+#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
+#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
+
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-base.c which are forward declared here
+ * for use by iwl-*.c
+ *
+ *****************************************************************************/
+struct iwl4965_addsta_cmd;
+extern int iwl4965_send_add_station(struct iwl4965_priv *priv,
+				struct iwl4965_addsta_cmd *sta, u8 flags);
+extern u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr,
+			  int is_ap, u8 flags, void *ht_data);
+extern int iwl4965_is_network_packet(struct iwl4965_priv *priv,
+				 struct ieee80211_hdr *header);
+extern int iwl4965_power_init_handle(struct iwl4965_priv *priv);
+extern int iwl4965_eeprom_init(struct iwl4965_priv *priv);
+#ifdef CONFIG_IWL4965_DEBUG
+extern void iwl4965_report_frame(struct iwl4965_priv *priv,
+			     struct iwl4965_rx_packet *pkt,
+			     struct ieee80211_hdr *header, int group100);
+#else
+static inline void iwl4965_report_frame(struct iwl4965_priv *priv,
+				    struct iwl4965_rx_packet *pkt,
+				    struct ieee80211_hdr *header,
+				    int group100) {}
+#endif
+extern void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv,
+					   struct iwl4965_rx_mem_buffer *rxb,
+					   void *data, short len,
+					   struct ieee80211_rx_status *stats,
+					   u16 phy_flags);
+extern int iwl4965_is_duplicate_packet(struct iwl4965_priv *priv,
+				       struct ieee80211_hdr *header);
+extern int iwl4965_rx_queue_alloc(struct iwl4965_priv *priv);
+extern void iwl4965_rx_queue_reset(struct iwl4965_priv *priv,
+			       struct iwl4965_rx_queue *rxq);
+extern int iwl4965_calc_db_from_ratio(int sig_ratio);
+extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm);
+extern int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
+			     struct iwl4965_tx_queue *txq, int count, u32 id);
+extern void iwl4965_rx_replenish(void *data);
+extern void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq);
+extern int iwl4965_send_cmd_pdu(struct iwl4965_priv *priv, u8 id, u16 len,
+			    const void *data);
+extern int __must_check iwl4965_send_cmd(struct iwl4965_priv *priv,
+		struct iwl4965_host_cmd *cmd);
+extern unsigned int iwl4965_fill_beacon_frame(struct iwl4965_priv *priv,
+					struct ieee80211_hdr *hdr,
+					const u8 *dest, int left);
+extern int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv,
+					 struct iwl4965_rx_queue *q);
+extern int iwl4965_send_statistics_request(struct iwl4965_priv *priv);
+extern void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb,
+				   u32 decrypt_res,
+				   struct ieee80211_rx_status *stats);
+extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
+
+extern const u8 iwl4965_broadcast_addr[ETH_ALEN];
+
+/*
+ * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
+ * call this... todo... fix that.
+*/
+extern u8 iwl4965_sync_station(struct iwl4965_priv *priv, int sta_id,
+			   u16 tx_rate, u8 flags);
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-[34]*.c which are forward declared here
+ * for use by iwl-base.c
+ *
+ * NOTE:  The implementation of these functions are hardware specific
+ * which is why they are in the hardware specific files (vs. iwl-base.c)
+ *
+ * Naming convention --
+ * iwl4965_         <-- Its part of iwlwifi (should be changed to iwl4965_)
+ * iwl4965_hw_      <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
+ * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
+ * iwl4965_bg_      <-- Called from work queue context
+ * iwl4965_mac_     <-- mac80211 callback
+ *
+ ****************************************************************************/
+extern void iwl4965_hw_rx_handler_setup(struct iwl4965_priv *priv);
+extern void iwl4965_hw_setup_deferred_work(struct iwl4965_priv *priv);
+extern void iwl4965_hw_cancel_deferred_work(struct iwl4965_priv *priv);
+extern int iwl4965_hw_rxq_stop(struct iwl4965_priv *priv);
+extern int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv);
+extern int iwl4965_hw_nic_init(struct iwl4965_priv *priv);
+extern int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv);
+extern void iwl4965_hw_txq_ctx_free(struct iwl4965_priv *priv);
+extern void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv);
+extern int iwl4965_hw_nic_reset(struct iwl4965_priv *priv);
+extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl4965_priv *priv, void *tfd,
+					dma_addr_t addr, u16 len);
+extern int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq);
+extern int iwl4965_hw_get_temperature(struct iwl4965_priv *priv);
+extern int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv,
+				struct iwl4965_tx_queue *txq);
+extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv,
+				 struct iwl4965_frame *frame, u8 rate);
+extern int iwl4965_hw_get_rx_read(struct iwl4965_priv *priv);
+extern void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv,
+				     struct iwl4965_cmd *cmd,
+				     struct ieee80211_tx_control *ctrl,
+				     struct ieee80211_hdr *hdr,
+				     int sta_id, int tx_id);
+extern int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv);
+extern int iwl4965_hw_reg_set_txpower(struct iwl4965_priv *priv, s8 power);
+extern void iwl4965_hw_rx_statistics(struct iwl4965_priv *priv,
+				 struct iwl4965_rx_mem_buffer *rxb);
+extern void iwl4965_disable_events(struct iwl4965_priv *priv);
+extern int iwl4965_get_temperature(const struct iwl4965_priv *priv);
+
+/**
+ * iwl4965_hw_find_station - Find station id for a given BSSID
+ * @bssid: MAC address of station ID to find
+ *
+ * NOTE:  This should not be hardware specific but the code has
+ * not yet been merged into a single common layer for managing the
+ * station tables.
+ */
+extern u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *bssid);
+
+extern int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel);
+extern int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index);
+
+struct iwl4965_priv;
 
 /*
  * Forward declare iwl-4965.c functions for iwl-base.c
  */
-extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv);
-extern void iwl_eeprom_release_semaphore(struct iwl_priv *priv);
+extern int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv);
+extern void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv);
 
-extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
-					  struct iwl_tx_queue *txq,
+extern int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv,
+					  struct iwl4965_tx_queue *txq,
 					  u16 byte_cnt);
-extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr,
+extern void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr,
 				int is_ap);
-extern void iwl4965_set_rxon_ht(struct iwl_priv *priv,
-				struct sta_ht_info *ht_info);
-
-extern void iwl4965_set_rxon_chain(struct iwl_priv *priv);
-extern int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
-			  u8 sta_id, dma_addr_t txcmd_phys,
-			  struct ieee80211_hdr *hdr, u8 hdr_len,
-			  struct ieee80211_tx_control *ctrl, void *sta_in);
-extern int iwl4965_init_hw_rates(struct iwl_priv *priv,
-				 struct ieee80211_rate *rates);
-extern int iwl4965_alive_notify(struct iwl_priv *priv);
-extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode);
-extern void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index);
-
-extern void iwl4965_chain_noise_reset(struct iwl_priv *priv);
-extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags,
+extern void iwl4965_set_rxon_chain(struct iwl4965_priv *priv);
+extern int iwl4965_alive_notify(struct iwl4965_priv *priv);
+extern void iwl4965_update_rate_scaling(struct iwl4965_priv *priv, u8 mode);
+extern void iwl4965_chain_noise_reset(struct iwl4965_priv *priv);
+extern void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags,
 				     u8 force);
-extern int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode,
+extern int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode,
 				u16 channel,
-				const struct iwl_eeprom_channel *eeprom_ch,
+				const struct iwl4965_eeprom_channel *eeprom_ch,
 				u8 fat_extension_channel);
-extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
+extern void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv);
 
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
-extern int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da,
+#ifdef CONFIG_IWL4965_HT
+extern void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info,
+					int mode);
+extern void iwl4965_set_rxon_ht(struct iwl4965_priv *priv,
+				struct iwl_ht_info *ht_info);
+extern void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index,
+				struct ieee80211_ht_info *sta_ht_inf);
+extern int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
+				    enum ieee80211_ampdu_mlme_action action,
+				    const u8 *addr, u16 tid, u16 ssn);
+#ifdef CONFIG_IWL4965_HT_AGG
+extern int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da,
 				   u16 tid, u16 *start_seq_num);
-extern int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da,
-				   u16 tid, u16 start_seq_num);
-extern int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+extern int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da,
 				  u16 tid, int generator);
-extern int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da,
-				  u16 tid, int generator);
-extern void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid);
-#endif /* CONFIG_IWLWIFI_HT_AGG */
-#endif /*CONFIG_IWLWIFI_HT */
+extern void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid);
+extern void iwl4965_tl_get_stats(struct iwl4965_priv *priv,
+				struct ieee80211_hdr *hdr);
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /*CONFIG_IWL4965_HT */
 /* Structures, enum, and defines specific to the 4965 */
 
 #define IWL4965_KW_SIZE 0x1000	/*4k */
 
-struct iwl_kw {
+struct iwl4965_kw {
 	dma_addr_t dma_addr;
 	void *v_addr;
 	size_t size;
@@ -120,21 +833,9 @@ struct iwl_kw {
 #define NRG_NUM_PREV_STAT_L     20
 #define NUM_RX_CHAINS           (3)
 
-#define TX_POWER_IWL_ILLEGAL_VDET    -100000
 #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
-#define TX_POWER_IWL_CLOSED_LOOP_MIN_POWER 18
-#define TX_POWER_IWL_CLOSED_LOOP_MAX_POWER 34
-#define TX_POWER_IWL_VDET_SLOPE_BELOW_NOMINAL 17
-#define TX_POWER_IWL_VDET_SLOPE_ABOVE_NOMINAL 20
-#define TX_POWER_IWL_NOMINAL_POWER            26
-#define TX_POWER_IWL_CLOSED_LOOP_ITERATION_LIMIT 1
-#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V       7
-#define TX_POWER_IWL_DEGREES_PER_VDET_CODE       11
-#define IWL_TX_POWER_MAX_NUM_PA_MEASUREMENTS 1
-#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9)
-#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5)
-
-struct iwl_traffic_load {
+
+struct iwl4965_traffic_load {
 	unsigned long time_stamp;
 	u32 packet_count[TID_QUEUE_MAX_SIZE];
 	u8 queue_count;
@@ -142,8 +843,13 @@ struct iwl_traffic_load {
 	u32 total;
 };
 
-#ifdef CONFIG_IWLWIFI_HT_AGG
-struct iwl_agg_control {
+#ifdef CONFIG_IWL4965_HT_AGG
+/**
+ * struct iwl4965_agg_control
+ * @requested_ba: bit map of tids requesting aggregation/block-ack
+ * @granted_ba: bit map of tids granted aggregation/block-ack
+ */
+struct iwl4965_agg_control {
 	unsigned long next_retry;
 	u32 wait_for_agg_status;
 	u32 tid_retry;
@@ -152,13 +858,13 @@ struct iwl_agg_control {
 	u8 auto_agg;
 	u32 tid_traffic_load_threshold;
 	u32 ba_timeout;
-	struct iwl_traffic_load traffic_load[TID_MAX_LOAD_COUNT];
+	struct iwl4965_traffic_load traffic_load[TID_MAX_LOAD_COUNT];
 };
-#endif				/*CONFIG_IWLWIFI_HT_AGG */
+#endif				/*CONFIG_IWL4965_HT_AGG */
 
-struct iwl_lq_mngr {
-#ifdef CONFIG_IWLWIFI_HT_AGG
-	struct iwl_agg_control agg_ctrl;
+struct iwl4965_lq_mngr {
+#ifdef CONFIG_IWL4965_HT_AGG
+	struct iwl4965_agg_control agg_ctrl;
 #endif
 	spinlock_t lock;
 	s32 max_window_size;
@@ -179,22 +885,6 @@ struct iwl_lq_mngr {
 #define CAL_NUM_OF_BEACONS		20
 #define MAXIMUM_ALLOWED_PATHLOSS	15
 
-/* Param table within SENSITIVITY_CMD */
-#define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)
-#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
-#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
-#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
-#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
-#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
-#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
-#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
-#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
-#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX          (9)
-#define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
-
-#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE	__constant_cpu_to_le16(0)
-#define SENSITIVITY_CMD_CONTROL_WORK_TABLE	__constant_cpu_to_le16(1)
-
 #define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
 
 #define MAX_FA_OFDM  50
@@ -222,8 +912,6 @@ struct iwl_lq_mngr {
 #define AUTO_CORR_STEP_CCK     3
 #define AUTO_CORR_MAX_TH_CCK   160
 
-#define NRG_ALG                0
-#define AUTO_CORR_ALG          1
 #define NRG_DIFF               2
 #define NRG_STEP_CCK           2
 #define NRG_MARGIN             8
@@ -239,24 +927,24 @@ struct iwl_lq_mngr {
 #define IN_BAND_FILTER			0xFF
 #define MIN_AVERAGE_NOISE_MAX_VALUE	0xFFFFFFFF
 
-enum iwl_false_alarm_state {
+enum iwl4965_false_alarm_state {
 	IWL_FA_TOO_MANY = 0,
 	IWL_FA_TOO_FEW = 1,
 	IWL_FA_GOOD_RANGE = 2,
 };
 
-enum iwl_chain_noise_state {
+enum iwl4965_chain_noise_state {
 	IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
 	IWL_CHAIN_NOISE_ACCUMULATE = 1,
 	IWL_CHAIN_NOISE_CALIBRATED = 2,
 };
 
-enum iwl_sensitivity_state {
+enum iwl4965_sensitivity_state {
 	IWL_SENS_CALIB_ALLOWED = 0,
 	IWL_SENS_CALIB_NEED_REINIT = 1,
 };
 
-enum iwl_calib_enabled_state {
+enum iwl4965_calib_enabled_state {
 	IWL_CALIB_DISABLED = 0,  /* must be 0 */
 	IWL_CALIB_ENABLED = 1,
 };
@@ -271,7 +959,7 @@ struct statistics_general_data {
 };
 
 /* Sensitivity calib data */
-struct iwl_sensitivity_data {
+struct iwl4965_sensitivity_data {
 	u32 auto_corr_ofdm;
 	u32 auto_corr_ofdm_mrc;
 	u32 auto_corr_ofdm_x1;
@@ -300,7 +988,7 @@ struct iwl_sensitivity_data {
 };
 
 /* Chain noise (differential Rx gain) calib data */
-struct iwl_chain_noise_data {
+struct iwl4965_chain_noise_data {
 	u8 state;
 	u16 beacon_count;
 	u32 chain_noise_a;
@@ -314,28 +1002,323 @@ struct iwl_chain_noise_data {
 	u8 radio_write;
 };
 
-/* IWL4965 */
-#define RATE_MCS_CODE_MSK 0x7
-#define RATE_MCS_MIMO_POS 3
-#define RATE_MCS_MIMO_MSK 0x8
-#define RATE_MCS_HT_DUP_POS 5
-#define RATE_MCS_HT_DUP_MSK 0x20
-#define RATE_MCS_FLAGS_POS 8
-#define RATE_MCS_HT_POS 8
-#define RATE_MCS_HT_MSK 0x100
-#define RATE_MCS_CCK_POS 9
-#define RATE_MCS_CCK_MSK 0x200
-#define RATE_MCS_GF_POS 10
-#define RATE_MCS_GF_MSK 0x400
-
-#define RATE_MCS_FAT_POS 11
-#define RATE_MCS_FAT_MSK 0x800
-#define RATE_MCS_DUP_POS 12
-#define RATE_MCS_DUP_MSK 0x1000
-#define RATE_MCS_SGI_POS 13
-#define RATE_MCS_SGI_MSK 0x2000
-
-#define	EEPROM_SEM_TIMEOUT 10
-#define EEPROM_SEM_RETRY_LIMIT 1000
-
-#endif				/* __iwl_4965_h__ */
+#define	EEPROM_SEM_TIMEOUT 10		/* milliseconds */
+#define EEPROM_SEM_RETRY_LIMIT 1000	/* number of attempts (not time) */
+
+
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+
+enum {
+	MEASUREMENT_READY = (1 << 0),
+	MEASUREMENT_ACTIVE = (1 << 1),
+};
+
+#endif
+
+struct iwl4965_priv {
+
+	/* ieee device used by generic ieee processing code */
+	struct ieee80211_hw *hw;
+	struct ieee80211_channel *ieee_channels;
+	struct ieee80211_rate *ieee_rates;
+
+	/* temporary frame storage list */
+	struct list_head free_frames;
+	int frames_count;
+
+	u8 phymode;
+	int alloc_rxb_skb;
+	bool add_radiotap;
+
+	void (*rx_handlers[REPLY_MAX])(struct iwl4965_priv *priv,
+				       struct iwl4965_rx_mem_buffer *rxb);
+
+	const struct ieee80211_hw_mode *modes;
+
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+	/* spectrum measurement report caching */
+	struct iwl4965_spectrum_notification measure_report;
+	u8 measurement_status;
+#endif
+	/* ucode beacon time */
+	u32 ucode_beacon_time;
+
+	/* we allocate array of iwl4965_channel_info for NIC's valid channels.
+	 *    Access via channel # using indirect index array */
+	struct iwl4965_channel_info *channel_info;	/* channel info array */
+	u8 channel_count;	/* # of channels */
+
+	/* each calibration channel group in the EEPROM has a derived
+	 * clip setting for each rate. */
+	const struct iwl4965_clip_group clip_groups[5];
+
+	/* thermal calibration */
+	s32 temperature;	/* degrees Kelvin */
+	s32 last_temperature;
+
+	/* Scan related variables */
+	unsigned long last_scan_jiffies;
+	unsigned long next_scan_jiffies;
+	unsigned long scan_start;
+	unsigned long scan_pass_start;
+	unsigned long scan_start_tsf;
+	int scan_bands;
+	int one_direct_scan;
+	u8 direct_ssid_len;
+	u8 direct_ssid[IW_ESSID_MAX_SIZE];
+	struct iwl4965_scan_cmd *scan;
+	u8 only_active_channel;
+
+	/* spinlock */
+	spinlock_t lock;	/* protect general shared data */
+	spinlock_t hcmd_lock;	/* protect hcmd */
+	struct mutex mutex;
+
+	/* basic pci-network driver stuff */
+	struct pci_dev *pci_dev;
+
+	/* pci hardware address support */
+	void __iomem *hw_base;
+
+	/* uCode images, save to reload in case of failure */
+	struct fw_desc ucode_code;	/* runtime inst */
+	struct fw_desc ucode_data;	/* runtime data original */
+	struct fw_desc ucode_data_backup;	/* runtime data save/restore */
+	struct fw_desc ucode_init;	/* initialization inst */
+	struct fw_desc ucode_init_data;	/* initialization data */
+	struct fw_desc ucode_boot;	/* bootstrap inst */
+
+
+	struct iwl4965_rxon_time_cmd rxon_timing;
+
+	/* We declare this const so it can only be
+	 * changed via explicit cast within the
+	 * routines that actually update the physical
+	 * hardware */
+	const struct iwl4965_rxon_cmd active_rxon;
+	struct iwl4965_rxon_cmd staging_rxon;
+
+	int error_recovering;
+	struct iwl4965_rxon_cmd recovery_rxon;
+
+	/* 1st responses from initialize and runtime uCode images.
+	 * 4965's initialize alive response contains some calibration data. */
+	struct iwl4965_init_alive_resp card_alive_init;
+	struct iwl4965_alive_resp card_alive;
+
+#ifdef LED
+	/* LED related variables */
+	struct iwl4965_activity_blink activity;
+	unsigned long led_packets;
+	int led_state;
+#endif
+
+	u16 active_rate;
+	u16 active_rate_basic;
+
+	u8 call_post_assoc_from_beacon;
+	u8 assoc_station_added;
+	u8 use_ant_b_for_management_frame;	/* Tx antenna selection */
+	u8 valid_antenna;	/* Bit mask of antennas actually connected */
+#ifdef CONFIG_IWL4965_SENSITIVITY
+	struct iwl4965_sensitivity_data sensitivity_data;
+	struct iwl4965_chain_noise_data chain_noise_data;
+	u8 start_calib;
+	__le16 sensitivity_tbl[HD_TABLE_SIZE];
+#endif /*CONFIG_IWL4965_SENSITIVITY*/
+
+#ifdef CONFIG_IWL4965_HT
+	struct iwl_ht_info current_ht_config;
+#endif
+	u8 last_phy_res[100];
+
+	/* Rate scaling data */
+	struct iwl4965_lq_mngr lq_mngr;
+
+	/* Rate scaling data */
+	s8 data_retry_limit;
+	u8 retry_rate;
+
+	wait_queue_head_t wait_command_queue;
+
+	int activity_timer_active;
+
+	/* Rx and Tx DMA processing queues */
+	struct iwl4965_rx_queue rxq;
+	struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES];
+	unsigned long txq_ctx_active_msk;
+	struct iwl4965_kw kw;	/* keep warm address */
+	u32 scd_base_addr;	/* scheduler sram base address */
+
+	unsigned long status;
+	u32 config;
+
+	int last_rx_rssi;	/* From Rx packet statisitics */
+	int last_rx_noise;	/* From beacon statistics */
+
+	struct iwl4965_power_mgr power_data;
+
+	struct iwl4965_notif_statistics statistics;
+	unsigned long last_statistics_time;
+
+	/* context information */
+	u8 essid[IW_ESSID_MAX_SIZE];
+	u8 essid_len;
+	u16 rates_mask;
+
+	u32 power_mode;
+	u32 antenna;
+	u8 bssid[ETH_ALEN];
+	u16 rts_threshold;
+	u8 mac_addr[ETH_ALEN];
+
+	/*station table variables */
+	spinlock_t sta_lock;
+	int num_stations;
+	struct iwl4965_station_entry stations[IWL_STATION_COUNT];
+
+	/* Indication if ieee80211_ops->open has been called */
+	int is_open;
+
+	u8 mac80211_registered;
+	int is_abg;
+
+	u32 notif_missed_beacons;
+
+	/* Rx'd packet timing information */
+	u32 last_beacon_time;
+	u64 last_tsf;
+
+	/* Duplicate packet detection */
+	u16 last_seq_num;
+	u16 last_frag_num;
+	unsigned long last_packet_time;
+
+	/* Hash table for finding stations in IBSS network */
+	struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
+
+	/* eeprom */
+	struct iwl4965_eeprom eeprom;
+
+	int iw_mode;
+
+	struct sk_buff *ibss_beacon;
+
+	/* Last Rx'd beacon timestamp */
+	u32 timestamp0;
+	u32 timestamp1;
+	u16 beacon_int;
+	struct iwl4965_driver_hw_info hw_setting;
+	struct ieee80211_vif *vif;
+
+	/* Current association information needed to configure the
+	 * hardware */
+	u16 assoc_id;
+	u16 assoc_capability;
+	u8 ps_mode;
+
+#ifdef CONFIG_IWL4965_QOS
+	struct iwl4965_qos_info qos_data;
+#endif /*CONFIG_IWL4965_QOS */
+
+	struct workqueue_struct *workqueue;
+
+	struct work_struct up;
+	struct work_struct restart;
+	struct work_struct calibrated_work;
+	struct work_struct scan_completed;
+	struct work_struct rx_replenish;
+	struct work_struct rf_kill;
+	struct work_struct abort_scan;
+	struct work_struct update_link_led;
+	struct work_struct auth_work;
+	struct work_struct report_work;
+	struct work_struct request_scan;
+	struct work_struct beacon_update;
+
+	struct tasklet_struct irq_tasklet;
+
+	struct delayed_work init_alive_start;
+	struct delayed_work alive_start;
+	struct delayed_work activity_timer;
+	struct delayed_work thermal_periodic;
+	struct delayed_work gather_stats;
+	struct delayed_work scan_check;
+	struct delayed_work post_associate;
+
+#define IWL_DEFAULT_TX_POWER 0x0F
+	s8 user_txpower_limit;
+	s8 max_channel_txpower_limit;
+
+#ifdef CONFIG_PM
+	u32 pm_state[16];
+#endif
+
+#ifdef CONFIG_IWL4965_DEBUG
+	/* debugging info */
+	u32 framecnt_to_us;
+	atomic_t restrict_refcnt;
+#endif
+
+	struct work_struct txpower_work;
+#ifdef CONFIG_IWL4965_SENSITIVITY
+	struct work_struct sensitivity_work;
+#endif
+	struct work_struct statistics_work;
+	struct timer_list statistics_periodic;
+
+#ifdef CONFIG_IWL4965_HT_AGG
+	struct work_struct agg_work;
+#endif
+};				/*iwl4965_priv */
+
+static inline int iwl4965_is_associated(struct iwl4965_priv *priv)
+{
+	return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+static inline int is_channel_valid(const struct iwl4965_channel_info *ch_info)
+{
+	if (ch_info == NULL)
+		return 0;
+	return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
+}
+
+static inline int is_channel_narrow(const struct iwl4965_channel_info *ch_info)
+{
+	return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
+}
+
+static inline int is_channel_radar(const struct iwl4965_channel_info *ch_info)
+{
+	return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
+}
+
+static inline u8 is_channel_a_band(const struct iwl4965_channel_info *ch_info)
+{
+	return ch_info->phymode == MODE_IEEE80211A;
+}
+
+static inline u8 is_channel_bg_band(const struct iwl4965_channel_info *ch_info)
+{
+	return ((ch_info->phymode == MODE_IEEE80211B) ||
+		(ch_info->phymode == MODE_IEEE80211G));
+}
+
+static inline int is_channel_passive(const struct iwl4965_channel_info *ch)
+{
+	return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
+}
+
+static inline int is_channel_ibss(const struct iwl4965_channel_info *ch)
+{
+	return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
+}
+
+extern const struct iwl4965_channel_info *iwl4965_get_channel_info(
+	const struct iwl4965_priv *priv, int phymode, u16 channel);
+
+/* Requires full declaration of iwl4965_priv before including */
+#include "iwl-4965-io.h"
+
+#endif				/* __iwl4965_4965_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-channel.h b/drivers/net/wireless/iwlwifi/iwl-channel.h
deleted file mode 100644
index 023c3f240cea..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-channel.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-#ifndef __iwl_channel_h__
-#define __iwl_channel_h__
-
-#define IWL_NUM_SCAN_RATES         (2)
-
-struct iwl_channel_tgd_info {
-	u8 type;
-	s8 max_power;
-};
-
-struct iwl_channel_tgh_info {
-	s64 last_radar_time;
-};
-
-/* current Tx power values to use, one for each rate for each channel.
- * requested power is limited by:
- * -- regulatory EEPROM limits for this channel
- * -- hardware capabilities (clip-powers)
- * -- spectrum management
- * -- user preference (e.g. iwconfig)
- * when requested power is set, base power index must also be set. */
-struct iwl_channel_power_info {
-	struct iwl_tx_power tpc;	/* actual radio and DSP gain settings */
-	s8 power_table_index;	/* actual (compenst'd) index into gain table */
-	s8 base_power_index;	/* gain index for power at factory temp. */
-	s8 requested_power;	/* power (dBm) requested for this chnl/rate */
-};
-
-/* current scan Tx power values to use, one for each scan rate for each
- * channel. */
-struct iwl_scan_power_info {
-	struct iwl_tx_power tpc;	/* actual radio and DSP gain settings */
-	s8 power_table_index;	/* actual (compenst'd) index into gain table */
-	s8 requested_power;	/* scan pwr (dBm) requested for chnl/rate */
-};
-
-/* Channel unlock period is 15 seconds. If no beacon or probe response
- * has been received within 15 seconds on a locked channel then the channel
- * remains locked. */
-#define TX_UNLOCK_PERIOD 15
-
-/* CSA lock period is 15 seconds.  If a CSA has been received on a channel in
- * the last 15 seconds, the channel is locked */
-#define CSA_LOCK_PERIOD 15
-/*
- * One for each channel, holds all channel setup data
- * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
- *     with one another!
- */
-#define IWL4965_MAX_RATE (33)
-
-struct iwl_channel_info {
-	struct iwl_channel_tgd_info tgd;
-	struct iwl_channel_tgh_info tgh;
-	struct iwl_eeprom_channel eeprom;	/* EEPROM regulatory limit */
-	struct iwl_eeprom_channel fat_eeprom;	/* EEPROM regulatory limit for
-						 * FAT channel */
-
-	u8 channel;	  /* channel number */
-	u8 flags;	  /* flags copied from EEPROM */
-	s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
-	s8 curr_txpow;	  /* (dBm) regulatory/spectrum/user (not h/w) */
-	s8 min_power;	  /* always 0 */
-	s8 scan_power;	  /* (dBm) regul. eeprom, direct scans, any rate */
-
-	u8 group_index;	  /* 0-4, maps channel to group1/2/3/4/5 */
-	u8 band_index;	  /* 0-4, maps channel to band1/2/3/4/5 */
-	u8 phymode;	  /* MODE_IEEE80211{A,B,G} */
-
-	/* Radio/DSP gain settings for each "normal" data Tx rate.
-	 * These include, in addition to RF and DSP gain, a few fields for
-	 *   remembering/modifying gain settings (indexes). */
-	struct iwl_channel_power_info power_info[IWL4965_MAX_RATE];
-
-#if IWL == 4965
-	/* FAT channel info */
-	s8 fat_max_power_avg;	/* (dBm) regul. eeprom, normal Tx, any rate */
-	s8 fat_curr_txpow;	/* (dBm) regulatory/spectrum/user (not h/w) */
-	s8 fat_min_power;	/* always 0 */
-	s8 fat_scan_power;	/* (dBm) eeprom, direct scans, any rate */
-	u8 fat_flags;		/* flags copied from EEPROM */
-	u8 fat_extension_channel;
-#endif
-
-	/* Radio/DSP gain settings for each scan rate, for directed scans. */
-	struct iwl_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
-};
-
-struct iwl_clip_group {
-	/* maximum power level to prevent clipping for each rate, derived by
-	 *   us from this band's saturation power in EEPROM */
-	const s8 clip_powers[IWL_MAX_RATES];
-};
-
-static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
-{
-	if (ch_info == NULL)
-		return 0;
-	return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
-}
-
-static inline int is_channel_narrow(const struct iwl_channel_info *ch_info)
-{
-	return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
-}
-
-static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
-{
-	return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
-}
-
-static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info)
-{
-	return ch_info->phymode == MODE_IEEE80211A;
-}
-
-static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info)
-{
-	return ((ch_info->phymode == MODE_IEEE80211B) ||
-		(ch_info->phymode == MODE_IEEE80211G));
-}
-
-static inline int is_channel_passive(const struct iwl_channel_info *ch)
-{
-	return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
-}
-
-static inline int is_channel_ibss(const struct iwl_channel_info *ch)
-{
-	return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
-}
-
-extern const struct iwl_channel_info *iwl_get_channel_info(
-	const struct iwl_priv *priv, int phymode, u16 channel);
-
-#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
deleted file mode 100644
index e473c97e3f4f..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ /dev/null
@@ -1,336 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU Geeral Public License as
- * published by the Free Software Foundation.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-
-#ifndef __iwl_eeprom_h__
-#define __iwl_eeprom_h__
-
-/*
- * This file defines EEPROM related constants, enums, and inline functions.
- *
- */
-
-#define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
-#define IWL_EEPROM_ACCESS_DELAY		10   /* uSec */
-/* EEPROM field values */
-#define ANTENNA_SWITCH_NORMAL     0
-#define ANTENNA_SWITCH_INVERSE    1
-
-enum {
-	EEPROM_CHANNEL_VALID = (1 << 0),	/* usable for this SKU/geo */
-	EEPROM_CHANNEL_IBSS = (1 << 1),	/* usable as an IBSS channel */
-	/* Bit 2 Reserved */
-	EEPROM_CHANNEL_ACTIVE = (1 << 3),	/* active scanning allowed */
-	EEPROM_CHANNEL_RADAR = (1 << 4),	/* radar detection required */
-	EEPROM_CHANNEL_WIDE = (1 << 5),
-	EEPROM_CHANNEL_NARROW = (1 << 6),
-	EEPROM_CHANNEL_DFS = (1 << 7),	/* dynamic freq selection candidate */
-};
-
-/* EEPROM field lengths */
-#define EEPROM_BOARD_PBA_NUMBER_LENGTH                  11
-
-/* EEPROM field lengths */
-#define EEPROM_BOARD_PBA_NUMBER_LENGTH                  11
-#define EEPROM_REGULATORY_SKU_ID_LENGTH                 4
-#define EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH         14
-#define EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH         13
-#define EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH         12
-#define EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH         11
-#define EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH         6
-
-#if IWL == 3945
-#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \
-	EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \
-	EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \
-	EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \
-	EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \
-	EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH)
-#elif IWL == 4965
-#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH 7
-#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH 11
-#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \
-	EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \
-	EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \
-	EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \
-	EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \
-	EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH + \
-	EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH + \
-	EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH)
-#endif
-
-#define EEPROM_REGULATORY_NUMBER_OF_BANDS               5
-
-/* SKU Capabilities */
-#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE                (1 << 0)
-#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE                (1 << 1)
-#define EEPROM_SKU_CAP_OP_MODE_MRC                      (1 << 7)
-
-/* *regulatory* channel data from eeprom, one for each channel */
-struct iwl_eeprom_channel {
-	u8 flags;		/* flags copied from EEPROM */
-	s8 max_power_avg;	/* max power (dBm) on this chnl, limit 31 */
-} __attribute__ ((packed));
-
-/*
- * Mapping of a Tx power level, at factory calibration temperature,
- *   to a radio/DSP gain table index.
- * One for each of 5 "sample" power levels in each band.
- * v_det is measured at the factory, using the 3945's built-in power amplifier
- *   (PA) output voltage detector.  This same detector is used during Tx of
- *   long packets in normal operation to provide feedback as to proper output
- *   level.
- * Data copied from EEPROM.
- */
-struct iwl_eeprom_txpower_sample {
-	u8 gain_index;		/* index into power (gain) setup table ... */
-	s8 power;		/* ... for this pwr level for this chnl group */
-	u16 v_det;		/* PA output voltage */
-} __attribute__ ((packed));
-
-/*
- * Mappings of Tx power levels -> nominal radio/DSP gain table indexes.
- * One for each channel group (a.k.a. "band") (1 for BG, 4 for A).
- * Tx power setup code interpolates between the 5 "sample" power levels
- *    to determine the nominal setup for a requested power level.
- * Data copied from EEPROM.
- * DO NOT ALTER THIS STRUCTURE!!!
- */
-struct iwl_eeprom_txpower_group {
-	struct iwl_eeprom_txpower_sample samples[5];	/* 5 power levels */
-	s32 a, b, c, d, e;	/* coefficients for voltage->power
-				 * formula (signed) */
-	s32 Fa, Fb, Fc, Fd, Fe;	/* these modify coeffs based on
-					 * frequency (signed) */
-	s8 saturation_power;	/* highest power possible by h/w in this
-				 * band */
-	u8 group_channel;	/* "representative" channel # in this band */
-	s16 temperature;	/* h/w temperature at factory calib this band
-				 * (signed) */
-} __attribute__ ((packed));
-
-/*
- * Temperature-based Tx-power compensation data, not band-specific.
- * These coefficients are use to modify a/b/c/d/e coeffs based on
- *   difference between current temperature and factory calib temperature.
- * Data copied from EEPROM.
- */
-struct iwl_eeprom_temperature_corr {
-	u32 Ta;
-	u32 Tb;
-	u32 Tc;
-	u32 Td;
-	u32 Te;
-} __attribute__ ((packed));
-
-#if IWL == 4965
-#define EEPROM_TX_POWER_TX_CHAINS      (2)
-#define EEPROM_TX_POWER_BANDS          (8)
-#define EEPROM_TX_POWER_MEASUREMENTS   (3)
-#define EEPROM_TX_POWER_VERSION        (2)
-#define EEPROM_TX_POWER_VERSION_NEW    (5)
-
-struct iwl_eeprom_calib_measure {
-	u8 temperature;
-	u8 gain_idx;
-	u8 actual_pow;
-	s8 pa_det;
-} __attribute__ ((packed));
-
-struct iwl_eeprom_calib_ch_info {
-	u8 ch_num;
-	struct iwl_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS]
-		[EEPROM_TX_POWER_MEASUREMENTS];
-} __attribute__ ((packed));
-
-struct iwl_eeprom_calib_subband_info {
-	u8 ch_from;
-	u8 ch_to;
-	struct iwl_eeprom_calib_ch_info ch1;
-	struct iwl_eeprom_calib_ch_info ch2;
-} __attribute__ ((packed));
-
-struct iwl_eeprom_calib_info {
-	u8 saturation_power24;
-	u8 saturation_power52;
-	s16 voltage;		/* signed */
-	struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS];
-} __attribute__ ((packed));
-
-#endif
-
-struct iwl_eeprom {
-	u8 reserved0[16];
-#define EEPROM_DEVICE_ID                    (2*0x08)	/* 2 bytes */
-	u16 device_id;	/* abs.ofs: 16 */
-	u8 reserved1[2];
-#define EEPROM_PMC                          (2*0x0A)	/* 2 bytes */
-	u16 pmc;		/* abs.ofs: 20 */
-	u8 reserved2[20];
-#define EEPROM_MAC_ADDRESS                  (2*0x15)	/* 6  bytes */
-	u8 mac_address[6];	/* abs.ofs: 42 */
-	u8 reserved3[58];
-#define EEPROM_BOARD_REVISION               (2*0x35)	/* 2  bytes */
-	u16 board_revision;	/* abs.ofs: 106 */
-	u8 reserved4[11];
-#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1)	/* 9  bytes */
-	u8 board_pba_number[9];	/* abs.ofs: 119 */
-	u8 reserved5[8];
-#define EEPROM_VERSION                      (2*0x44)	/* 2  bytes */
-	u16 version;		/* abs.ofs: 136 */
-#define EEPROM_SKU_CAP                      (2*0x45)	/* 1  bytes */
-	u8 sku_cap;		/* abs.ofs: 138 */
-#define EEPROM_LEDS_MODE                    (2*0x45+1)	/* 1  bytes */
-	u8 leds_mode;		/* abs.ofs: 139 */
-#define EEPROM_OEM_MODE                     (2*0x46)	/* 2  bytes */
-	u16 oem_mode;
-#define EEPROM_WOWLAN_MODE                  (2*0x47)	/* 2  bytes */
-	u16 wowlan_mode;	/* abs.ofs: 142 */
-#define EEPROM_LEDS_TIME_INTERVAL           (2*0x48)	/* 2  bytes */
-	u16 leds_time_interval;	/* abs.ofs: 144 */
-#define EEPROM_LEDS_OFF_TIME                (2*0x49)	/* 1  bytes */
-	u8 leds_off_time;	/* abs.ofs: 146 */
-#define EEPROM_LEDS_ON_TIME                 (2*0x49+1)	/* 1  bytes */
-	u8 leds_on_time;	/* abs.ofs: 147 */
-#define EEPROM_ALMGOR_M_VERSION             (2*0x4A)	/* 1  bytes */
-	u8 almgor_m_version;	/* abs.ofs: 148 */
-#define EEPROM_ANTENNA_SWITCH_TYPE          (2*0x4A+1)	/* 1  bytes */
-	u8 antenna_switch_type;	/* abs.ofs: 149 */
-#if IWL == 3945
-	u8 reserved6[42];
-#else
-	u8 reserved6[8];
-#define EEPROM_4965_BOARD_REVISION          (2*0x4F)	/* 2 bytes */
-	u16 board_revision_4965;	/* abs.ofs: 158 */
-	u8 reserved7[13];
-#define EEPROM_4965_BOARD_PBA               (2*0x56+1)	/* 9 bytes */
-	u8 board_pba_number_4965[9];	/* abs.ofs: 173 */
-	u8 reserved8[10];
-#endif
-#define EEPROM_REGULATORY_SKU_ID            (2*0x60)	/* 4  bytes */
-	u8 sku_id[4];		/* abs.ofs: 192 */
-#define EEPROM_REGULATORY_BAND_1            (2*0x62)	/* 2  bytes */
-	u16 band_1_count;	/* abs.ofs: 196 */
-#define EEPROM_REGULATORY_BAND_1_CHANNELS   (2*0x63)	/* 28 bytes */
-	struct iwl_eeprom_channel band_1_channels[14];	/* abs.ofs: 196 */
-#define EEPROM_REGULATORY_BAND_2            (2*0x71)	/* 2  bytes */
-	u16 band_2_count;	/* abs.ofs: 226 */
-#define EEPROM_REGULATORY_BAND_2_CHANNELS   (2*0x72)	/* 26 bytes */
-	struct iwl_eeprom_channel band_2_channels[13];	/* abs.ofs: 228 */
-#define EEPROM_REGULATORY_BAND_3            (2*0x7F)	/* 2  bytes */
-	u16 band_3_count;	/* abs.ofs: 254 */
-#define EEPROM_REGULATORY_BAND_3_CHANNELS   (2*0x80)	/* 24 bytes */
-	struct iwl_eeprom_channel band_3_channels[12];	/* abs.ofs: 256 */
-#define EEPROM_REGULATORY_BAND_4            (2*0x8C)	/* 2  bytes */
-	u16 band_4_count;	/* abs.ofs: 280 */
-#define EEPROM_REGULATORY_BAND_4_CHANNELS   (2*0x8D)	/* 22 bytes */
-	struct iwl_eeprom_channel band_4_channels[11];	/* abs.ofs: 282 */
-#define EEPROM_REGULATORY_BAND_5            (2*0x98)	/* 2  bytes */
-	u16 band_5_count;	/* abs.ofs: 304 */
-#define EEPROM_REGULATORY_BAND_5_CHANNELS   (2*0x99)	/* 12 bytes */
-	struct iwl_eeprom_channel band_5_channels[6];	/* abs.ofs: 306 */
-
-/* From here on out the EEPROM diverges between the 4965 and the 3945 */
-#if IWL == 3945
-
-	u8 reserved9[194];
-
-#define EEPROM_TXPOWER_CALIB_GROUP0 0x200
-#define EEPROM_TXPOWER_CALIB_GROUP1 0x240
-#define EEPROM_TXPOWER_CALIB_GROUP2 0x280
-#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0
-#define EEPROM_TXPOWER_CALIB_GROUP4 0x300
-#define IWL_NUM_TX_CALIB_GROUPS 5
-	struct iwl_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS];
-/* abs.ofs: 512 */
-#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340
-	struct iwl_eeprom_temperature_corr corrections;	/* abs.ofs: 832 */
-	u8 reserved16[172];	/* fill out to full 1024 byte block */
-
-/* 4965AGN adds fat channel support */
-#elif IWL == 4965
-
-	u8 reserved10[2];
-#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0)	/* 14 bytes */
-	struct iwl_eeprom_channel band_24_channels[7];	/* abs.ofs: 320 */
-	u8 reserved11[2];
-#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8)	/* 22 bytes */
-	struct iwl_eeprom_channel band_52_channels[11];	/* abs.ofs: 336 */
-	u8 reserved12[6];
-#define EEPROM_CALIB_VERSION_OFFSET            (2*0xB6)	/* 2 bytes */
-	u16 calib_version;	/* abs.ofs: 364 */
-	u8 reserved13[2];
-#define EEPROM_SATURATION_POWER_OFFSET         (2*0xB8)	/* 2 bytes */
-	u16 satruation_power;	/* abs.ofs: 368 */
-	u8 reserved14[94];
-#define EEPROM_IWL_CALIB_TXPOWER_OFFSET        (2*0xE8)	/* 48  bytes */
-	struct iwl_eeprom_calib_info calib_info;	/* abs.ofs: 464 */
-
-	u8 reserved16[140];	/* fill out to full 1024 byte block */
-
-#endif
-
-} __attribute__ ((packed));
-
-#define IWL_EEPROM_IMAGE_SIZE 1024
-
-#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index e2a8d95ad9cd..cd2eb1848310 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -252,4 +252,27 @@ static inline unsigned long elapsed_jiffies(unsigned long start,
 	return end + (MAX_JIFFY_OFFSET - start);
 }
 
+static inline u8 iwl_get_dma_hi_address(dma_addr_t addr)
+{
+	return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0;
+}
+
+/* TODO: Move fw_desc functions to iwl-pci.ko */
+static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
+				    struct fw_desc *desc)
+{
+	if (desc->v_addr)
+		pci_free_consistent(pci_dev, desc->len,
+				    desc->v_addr, desc->p_addr);
+	desc->v_addr = NULL;
+	desc->len = 0;
+}
+
+static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev,
+				    struct fw_desc *desc)
+{
+	desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr);
+	return (desc->v_addr != NULL) ? 0 : -ENOMEM;
+}
+
 #endif				/* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hw.h b/drivers/net/wireless/iwlwifi/iwl-hw.h
deleted file mode 100644
index 1aa6fcd39a5e..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-hw.h
+++ /dev/null
@@ -1,537 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU Geeral Public License as
- * published by the Free Software Foundation.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *  * Neither the name Intel Corporation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-#ifndef	__iwlwifi_hw_h__
-#define __iwlwifi_hw_h__
-
-/*
- * This file defines hardware constants common to 3945 and 4965.
- *
- * Device-specific constants are defined in iwl-3945-hw.h and iwl-4965-hw.h,
- * although this file contains a few definitions for which the .c
- * implementation is the same for 3945 and 4965, except for the value of
- * a constant.
- *
- * uCode API constants are defined in iwl-commands.h.
- *
- * NOTE:  DO NOT PUT OS IMPLEMENTATION-SPECIFIC DECLARATIONS HERE
- *
- * The iwl-*hw.h (and files they include) files should remain OS/driver
- * implementation independent, declaring only the hardware interface.
- */
-
-/* uCode queue management definitions */
-#define IWL_CMD_QUEUE_NUM       4
-#define IWL_CMD_FIFO_NUM        4
-#define IWL_BACK_QUEUE_FIRST_ID 7
-
-/* Tx rates */
-#define IWL_CCK_RATES 4
-#define IWL_OFDM_RATES 8
-
-#if IWL == 3945
-#define IWL_HT_RATES 0
-#elif IWL == 4965
-#define IWL_HT_RATES 16
-#endif
-
-#define IWL_MAX_RATES  (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
-
-/* Time constants */
-#define SHORT_SLOT_TIME 9
-#define LONG_SLOT_TIME 20
-
-/* RSSI to dBm */
-#if IWL == 3945
-#define IWL_RSSI_OFFSET	95
-#elif IWL == 4965
-#define IWL_RSSI_OFFSET	44
-#endif
-
-#include "iwl-eeprom.h"
-#include "iwl-commands.h"
-
-#define PCI_LINK_CTRL      0x0F0
-#define PCI_POWER_SOURCE   0x0C8
-#define PCI_REG_WUM8       0x0E8
-#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
-
-/*=== CSR (control and status registers) ===*/
-#define CSR_BASE    (0x000)
-
-#define CSR_SW_VER              (CSR_BASE+0x000)
-#define CSR_HW_IF_CONFIG_REG    (CSR_BASE+0x000) /* hardware interface config */
-#define CSR_INT_COALESCING      (CSR_BASE+0x004) /* accum ints, 32-usec units */
-#define CSR_INT                 (CSR_BASE+0x008) /* host interrupt status/ack */
-#define CSR_INT_MASK            (CSR_BASE+0x00c) /* host interrupt enable */
-#define CSR_FH_INT_STATUS       (CSR_BASE+0x010) /* busmaster int status/ack*/
-#define CSR_GPIO_IN             (CSR_BASE+0x018) /* read external chip pins */
-#define CSR_RESET               (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
-#define CSR_GP_CNTRL            (CSR_BASE+0x024)
-#define CSR_HW_REV              (CSR_BASE+0x028)
-#define CSR_EEPROM_REG          (CSR_BASE+0x02c)
-#define CSR_EEPROM_GP           (CSR_BASE+0x030)
-#define CSR_GP_UCODE		(CSR_BASE+0x044)
-#define CSR_UCODE_DRV_GP1       (CSR_BASE+0x054)
-#define CSR_UCODE_DRV_GP1_SET   (CSR_BASE+0x058)
-#define CSR_UCODE_DRV_GP1_CLR   (CSR_BASE+0x05c)
-#define CSR_UCODE_DRV_GP2       (CSR_BASE+0x060)
-#define CSR_LED_REG		(CSR_BASE+0x094)
-#define CSR_DRAM_INT_TBL_CTL	(CSR_BASE+0x0A0)
-#define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
-#define CSR_ANA_PLL_CFG         (CSR_BASE+0x20c)
-#define CSR_HW_REV_WA_REG	(CSR_BASE+0x22C)
-
-/* HW I/F configuration */
-#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB         (0x00000100)
-#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM         (0x00000200)
-#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC            (0x00000400)
-#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE         (0x00000800)
-#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A    (0x00000000)
-#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B    (0x00001000)
-#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM     (0x00200000)
-
-/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
- * acknowledged (reset) by host writing "1" to flagged bits. */
-#define CSR_INT_BIT_FH_RX        (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */
-#define CSR_INT_BIT_HW_ERR       (1<<29) /* DMA hardware error FH_INT[31] */
-#define CSR_INT_BIT_DNLD         (1<<28) /* uCode Download */
-#define CSR_INT_BIT_FH_TX        (1<<27) /* Tx DMA FH_INT[1:0] */
-#define CSR_INT_BIT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */
-#define CSR_INT_BIT_SW_ERR       (1<<25) /* uCode error */
-#define CSR_INT_BIT_RF_KILL      (1<<7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
-#define CSR_INT_BIT_CT_KILL      (1<<6)  /* Critical temp (chip too hot) rfkill */
-#define CSR_INT_BIT_SW_RX        (1<<3)  /* Rx, command responses, 3945 */
-#define CSR_INT_BIT_WAKEUP       (1<<1)  /* NIC controller waking up (pwr mgmt) */
-#define CSR_INT_BIT_ALIVE        (1<<0)  /* uCode interrupts once it initializes */
-
-#define CSR_INI_SET_MASK	(CSR_INT_BIT_FH_RX   | \
-				 CSR_INT_BIT_HW_ERR  | \
-				 CSR_INT_BIT_FH_TX   | \
-				 CSR_INT_BIT_SW_ERR  | \
-				 CSR_INT_BIT_RF_KILL | \
-				 CSR_INT_BIT_SW_RX   | \
-				 CSR_INT_BIT_WAKEUP  | \
-				 CSR_INT_BIT_ALIVE)
-
-/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
-#define CSR_FH_INT_BIT_ERR       (1<<31) /* Error */
-#define CSR_FH_INT_BIT_HI_PRIOR  (1<<30) /* High priority Rx, bypass coalescing */
-#define CSR_FH_INT_BIT_RX_CHNL2  (1<<18) /* Rx channel 2 (3945 only) */
-#define CSR_FH_INT_BIT_RX_CHNL1  (1<<17) /* Rx channel 1 */
-#define CSR_FH_INT_BIT_RX_CHNL0  (1<<16) /* Rx channel 0 */
-#define CSR_FH_INT_BIT_TX_CHNL6  (1<<6)  /* Tx channel 6 (3945 only) */
-#define CSR_FH_INT_BIT_TX_CHNL1  (1<<1)  /* Tx channel 1 */
-#define CSR_FH_INT_BIT_TX_CHNL0  (1<<0)  /* Tx channel 0 */
-
-#define CSR_FH_INT_RX_MASK	(CSR_FH_INT_BIT_HI_PRIOR | \
-				 CSR_FH_INT_BIT_RX_CHNL2 | \
-				 CSR_FH_INT_BIT_RX_CHNL1 | \
-				 CSR_FH_INT_BIT_RX_CHNL0)
-
-#define CSR_FH_INT_TX_MASK	(CSR_FH_INT_BIT_TX_CHNL6 | \
-				 CSR_FH_INT_BIT_TX_CHNL1 | \
-				 CSR_FH_INT_BIT_TX_CHNL0 )
-
-
-/* RESET */
-#define CSR_RESET_REG_FLAG_NEVO_RESET                (0x00000001)
-#define CSR_RESET_REG_FLAG_FORCE_NMI                 (0x00000002)
-#define CSR_RESET_REG_FLAG_SW_RESET                  (0x00000080)
-#define CSR_RESET_REG_FLAG_MASTER_DISABLED           (0x00000100)
-#define CSR_RESET_REG_FLAG_STOP_MASTER               (0x00000200)
-
-/* GP (general purpose) CONTROL */
-#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY        (0x00000001)
-#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE              (0x00000004)
-#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ         (0x00000008)
-#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP         (0x00000010)
-
-#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN           (0x00000001)
-
-#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE         (0x07000000)
-#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE         (0x04000000)
-#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW          (0x08000000)
-
-
-/* EEPROM REG */
-#define CSR_EEPROM_REG_READ_VALID_MSK	(0x00000001)
-#define CSR_EEPROM_REG_BIT_CMD		(0x00000002)
-
-/* EEPROM GP */
-#define CSR_EEPROM_GP_VALID_MSK		(0x00000006)
-#define CSR_EEPROM_GP_BAD_SIGNATURE	(0x00000000)
-#define CSR_EEPROM_GP_IF_OWNER_MSK	(0x00000180)
-
-/* UCODE DRV GP */
-#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP             (0x00000001)
-#define CSR_UCODE_SW_BIT_RFKILL                     (0x00000002)
-#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED           (0x00000004)
-#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT      (0x00000008)
-
-/* GPIO */
-#define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
-#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC                (0x00000000)
-#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC		CSR_GPIO_IN_BIT_AUX_POWER
-
-/* GI Chicken Bits */
-#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
-#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER  (0x20000000)
-
-/* CSR_ANA_PLL_CFG */
-#define CSR_ANA_PLL_CFG_SH		(0x00880300)
-
-#define CSR_LED_REG_TRUN_ON		(0x00000078)
-#define CSR_LED_REG_TRUN_OFF		(0x00000038)
-#define CSR_LED_BSM_CTRL_MSK		(0xFFFFFFDF)
-
-/* DRAM_INT_TBL_CTRL */
-#define CSR_DRAM_INT_TBL_CTRL_EN	(1<<31)
-#define CSR_DRAM_INT_TBL_CTRL_WRAP_CHK	(1<<27)
-
-/*=== HBUS (Host-side Bus) ===*/
-#define HBUS_BASE	(0x400)
-
-#define HBUS_TARG_MEM_RADDR     (HBUS_BASE+0x00c)
-#define HBUS_TARG_MEM_WADDR     (HBUS_BASE+0x010)
-#define HBUS_TARG_MEM_WDAT      (HBUS_BASE+0x018)
-#define HBUS_TARG_MEM_RDAT      (HBUS_BASE+0x01c)
-#define HBUS_TARG_PRPH_WADDR    (HBUS_BASE+0x044)
-#define HBUS_TARG_PRPH_RADDR    (HBUS_BASE+0x048)
-#define HBUS_TARG_PRPH_WDAT     (HBUS_BASE+0x04c)
-#define HBUS_TARG_PRPH_RDAT     (HBUS_BASE+0x050)
-#define HBUS_TARG_WRPTR         (HBUS_BASE+0x060)
-
-#define HBUS_TARG_MBX_C         (HBUS_BASE+0x030)
-
-
-/* SCD (Scheduler) */
-#define SCD_BASE                        (CSR_BASE + 0x2E00)
-
-#define SCD_MODE_REG                    (SCD_BASE + 0x000)
-#define SCD_ARASTAT_REG                 (SCD_BASE + 0x004)
-#define SCD_TXFACT_REG                  (SCD_BASE + 0x010)
-#define SCD_TXF4MF_REG                  (SCD_BASE + 0x014)
-#define SCD_TXF5MF_REG                  (SCD_BASE + 0x020)
-#define SCD_SBYP_MODE_1_REG             (SCD_BASE + 0x02C)
-#define SCD_SBYP_MODE_2_REG             (SCD_BASE + 0x030)
-
-/*=== FH (data Flow Handler) ===*/
-#define FH_BASE     (0x800)
-
-#define FH_CBCC_TABLE           (FH_BASE+0x140)
-#define FH_TFDB_TABLE           (FH_BASE+0x180)
-#define FH_RCSR_TABLE           (FH_BASE+0x400)
-#define FH_RSSR_TABLE           (FH_BASE+0x4c0)
-#define FH_TCSR_TABLE           (FH_BASE+0x500)
-#define FH_TSSR_TABLE           (FH_BASE+0x680)
-
-/* TFDB (Transmit Frame Buffer Descriptor) */
-#define FH_TFDB(_channel, buf) \
-	(FH_TFDB_TABLE+((_channel)*2+(buf))*0x28)
-#define ALM_FH_TFDB_CHNL_BUF_CTRL_REG(_channel) \
-	(FH_TFDB_TABLE + 0x50 * _channel)
-/* CBCC _channel is [0,2] */
-#define FH_CBCC(_channel)           (FH_CBCC_TABLE+(_channel)*0x8)
-#define FH_CBCC_CTRL(_channel)      (FH_CBCC(_channel)+0x00)
-#define FH_CBCC_BASE(_channel)      (FH_CBCC(_channel)+0x04)
-
-/* RCSR _channel is [0,2] */
-#define FH_RCSR(_channel)           (FH_RCSR_TABLE+(_channel)*0x40)
-#define FH_RCSR_CONFIG(_channel)    (FH_RCSR(_channel)+0x00)
-#define FH_RCSR_RBD_BASE(_channel)  (FH_RCSR(_channel)+0x04)
-#define FH_RCSR_WPTR(_channel)      (FH_RCSR(_channel)+0x20)
-#define FH_RCSR_RPTR_ADDR(_channel) (FH_RCSR(_channel)+0x24)
-
-#if IWL == 3945
-#define FH_RSCSR_CHNL0_WPTR        (FH_RCSR_WPTR(0))
-#elif IWL == 4965
-#define FH_RSCSR_CHNL0_WPTR        (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
-#endif
-
-/* RSSR */
-#define FH_RSSR_CTRL            (FH_RSSR_TABLE+0x000)
-#define FH_RSSR_STATUS          (FH_RSSR_TABLE+0x004)
-/* TCSR */
-#define FH_TCSR(_channel)           (FH_TCSR_TABLE+(_channel)*0x20)
-#define FH_TCSR_CONFIG(_channel)    (FH_TCSR(_channel)+0x00)
-#define FH_TCSR_CREDIT(_channel)    (FH_TCSR(_channel)+0x04)
-#define FH_TCSR_BUFF_STTS(_channel) (FH_TCSR(_channel)+0x08)
-/* TSSR */
-#define FH_TSSR_CBB_BASE        (FH_TSSR_TABLE+0x000)
-#define FH_TSSR_MSG_CONFIG      (FH_TSSR_TABLE+0x008)
-#define FH_TSSR_TX_STATUS       (FH_TSSR_TABLE+0x010)
-/* 18 - reserved */
-
-/* card static random access memory (SRAM) for processor data and instructs */
-#define RTC_INST_LOWER_BOUND			(0x000000)
-#define RTC_DATA_LOWER_BOUND			(0x800000)
-
-
-/* DBM */
-
-#define ALM_FH_SRVC_CHNL                            (6)
-
-#define ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE     (20)
-#define ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH      (4)
-
-#define ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN    (0x08000000)
-
-#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE        (0x80000000)
-
-#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE           (0x20000000)
-
-#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128         (0x01000000)
-
-#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST         (0x00001000)
-
-#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH               (0x00000000)
-
-#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF              (0x00000000)
-#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER           (0x00000001)
-
-#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
-#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
-
-#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
-
-#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT            (0x00000000)
-
-#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
-#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
-
-#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00004000)
-
-#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR           (0x00000001)
-
-#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON      (0xFF000000)
-#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON      (0x00FF0000)
-
-#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B    (0x00000400)
-
-#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON       (0x00000100)
-#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON       (0x00000080)
-
-#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH     (0x00000020)
-#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH           (0x00000005)
-
-#define ALM_TB_MAX_BYTES_COUNT      (0xFFF0)
-
-#define ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) \
-	((1LU << _channel) << 24)
-#define ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel) \
-	((1LU << _channel) << 16)
-
-#define ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_channel) \
-	(ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) | \
-	 ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel))
-#define PCI_CFG_REV_ID_BIT_BASIC_SKU                (0x40)	/* bit 6    */
-#define PCI_CFG_REV_ID_BIT_RTP                      (0x80)	/* bit 7    */
-
-#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED         (0x00000004)
-
-#define TFD_QUEUE_MIN           0
-#define TFD_QUEUE_MAX           6
-#define TFD_QUEUE_SIZE_MAX      (256)
-
-/* spectrum and channel data structures */
-#define IWL_NUM_SCAN_RATES         (2)
-
-#define IWL_SCAN_FLAG_24GHZ  (1<<0)
-#define IWL_SCAN_FLAG_52GHZ  (1<<1)
-#define IWL_SCAN_FLAG_ACTIVE (1<<2)
-#define IWL_SCAN_FLAG_DIRECT (1<<3)
-
-#define IWL_MAX_CMD_SIZE 1024
-
-#define IWL_DEFAULT_TX_RETRY  15
-#define IWL_MAX_TX_RETRY      16
-
-/*********************************************/
-
-#define RFD_SIZE                              4
-#define NUM_TFD_CHUNKS                        4
-
-#define RX_QUEUE_SIZE                         256
-#define RX_QUEUE_MASK                         255
-#define RX_QUEUE_SIZE_LOG                     8
-
-/* QoS  definitions */
-
-#define CW_MIN_OFDM          15
-#define CW_MAX_OFDM          1023
-#define CW_MIN_CCK           31
-#define CW_MAX_CCK           1023
-
-#define QOS_TX0_CW_MIN_OFDM      CW_MIN_OFDM
-#define QOS_TX1_CW_MIN_OFDM      CW_MIN_OFDM
-#define QOS_TX2_CW_MIN_OFDM      ((CW_MIN_OFDM + 1) / 2 - 1)
-#define QOS_TX3_CW_MIN_OFDM      ((CW_MIN_OFDM + 1) / 4 - 1)
-
-#define QOS_TX0_CW_MIN_CCK       CW_MIN_CCK
-#define QOS_TX1_CW_MIN_CCK       CW_MIN_CCK
-#define QOS_TX2_CW_MIN_CCK       ((CW_MIN_CCK + 1) / 2 - 1)
-#define QOS_TX3_CW_MIN_CCK       ((CW_MIN_CCK + 1) / 4 - 1)
-
-#define QOS_TX0_CW_MAX_OFDM      CW_MAX_OFDM
-#define QOS_TX1_CW_MAX_OFDM      CW_MAX_OFDM
-#define QOS_TX2_CW_MAX_OFDM      CW_MIN_OFDM
-#define QOS_TX3_CW_MAX_OFDM      ((CW_MIN_OFDM + 1) / 2 - 1)
-
-#define QOS_TX0_CW_MAX_CCK       CW_MAX_CCK
-#define QOS_TX1_CW_MAX_CCK       CW_MAX_CCK
-#define QOS_TX2_CW_MAX_CCK       CW_MIN_CCK
-#define QOS_TX3_CW_MAX_CCK       ((CW_MIN_CCK + 1) / 2 - 1)
-
-#define QOS_TX0_AIFS            3
-#define QOS_TX1_AIFS            7
-#define QOS_TX2_AIFS            2
-#define QOS_TX3_AIFS            2
-
-#define QOS_TX0_ACM             0
-#define QOS_TX1_ACM             0
-#define QOS_TX2_ACM             0
-#define QOS_TX3_ACM             0
-
-#define QOS_TX0_TXOP_LIMIT_CCK          0
-#define QOS_TX1_TXOP_LIMIT_CCK          0
-#define QOS_TX2_TXOP_LIMIT_CCK          6016
-#define QOS_TX3_TXOP_LIMIT_CCK          3264
-
-#define QOS_TX0_TXOP_LIMIT_OFDM      0
-#define QOS_TX1_TXOP_LIMIT_OFDM      0
-#define QOS_TX2_TXOP_LIMIT_OFDM      3008
-#define QOS_TX3_TXOP_LIMIT_OFDM      1504
-
-#define DEF_TX0_CW_MIN_OFDM      CW_MIN_OFDM
-#define DEF_TX1_CW_MIN_OFDM      CW_MIN_OFDM
-#define DEF_TX2_CW_MIN_OFDM      CW_MIN_OFDM
-#define DEF_TX3_CW_MIN_OFDM      CW_MIN_OFDM
-
-#define DEF_TX0_CW_MIN_CCK       CW_MIN_CCK
-#define DEF_TX1_CW_MIN_CCK       CW_MIN_CCK
-#define DEF_TX2_CW_MIN_CCK       CW_MIN_CCK
-#define DEF_TX3_CW_MIN_CCK       CW_MIN_CCK
-
-#define DEF_TX0_CW_MAX_OFDM      CW_MAX_OFDM
-#define DEF_TX1_CW_MAX_OFDM      CW_MAX_OFDM
-#define DEF_TX2_CW_MAX_OFDM      CW_MAX_OFDM
-#define DEF_TX3_CW_MAX_OFDM      CW_MAX_OFDM
-
-#define DEF_TX0_CW_MAX_CCK       CW_MAX_CCK
-#define DEF_TX1_CW_MAX_CCK       CW_MAX_CCK
-#define DEF_TX2_CW_MAX_CCK       CW_MAX_CCK
-#define DEF_TX3_CW_MAX_CCK       CW_MAX_CCK
-
-#define DEF_TX0_AIFS            (2)
-#define DEF_TX1_AIFS            (2)
-#define DEF_TX2_AIFS            (2)
-#define DEF_TX3_AIFS            (2)
-
-#define DEF_TX0_ACM             0
-#define DEF_TX1_ACM             0
-#define DEF_TX2_ACM             0
-#define DEF_TX3_ACM             0
-
-#define DEF_TX0_TXOP_LIMIT_CCK        0
-#define DEF_TX1_TXOP_LIMIT_CCK        0
-#define DEF_TX2_TXOP_LIMIT_CCK        0
-#define DEF_TX3_TXOP_LIMIT_CCK        0
-
-#define DEF_TX0_TXOP_LIMIT_OFDM       0
-#define DEF_TX1_TXOP_LIMIT_OFDM       0
-#define DEF_TX2_TXOP_LIMIT_OFDM       0
-#define DEF_TX3_TXOP_LIMIT_OFDM       0
-
-#define QOS_QOS_SETS                  3
-#define QOS_PARAM_SET_ACTIVE          0
-#define QOS_PARAM_SET_DEF_CCK         1
-#define QOS_PARAM_SET_DEF_OFDM        2
-
-#define CTRL_QOS_NO_ACK               (0x0020)
-#define DCT_FLAG_EXT_QOS_ENABLED      (0x10)
-
-#define U32_PAD(n)		((4-(n))&0x3)
-
-/*
- * Generic queue structure
- *
- * Contains common data for Rx and Tx queues
- */
-#define TFD_CTL_COUNT_SET(n)       (n<<24)
-#define TFD_CTL_COUNT_GET(ctl)     ((ctl>>24) & 7)
-#define TFD_CTL_PAD_SET(n)         (n<<28)
-#define TFD_CTL_PAD_GET(ctl)       (ctl>>28)
-
-#define TFD_TX_CMD_SLOTS 256
-#define TFD_CMD_SLOTS 32
-
-#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
-			      sizeof(struct iwl_cmd_meta))
-
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
-#endif				/* __iwlwifi_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
deleted file mode 100644
index 8a8b96fcf48d..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ /dev/null
@@ -1,470 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#ifndef __iwl_io_h__
-#define __iwl_io_h__
-
-#include <linux/io.h>
-
-#include "iwl-debug.h"
-
-/*
- * IO, register, and NIC memory access functions
- *
- * NOTE on naming convention and macro usage for these
- *
- * A single _ prefix before a an access function means that no state
- * check or debug information is printed when that function is called.
- *
- * A double __ prefix before an access function means that state is checked
- * (in the case of *restricted calls) and the current line number is printed
- * in addition to any other debug output.
- *
- * The non-prefixed name is the #define that maps the caller into a
- * #define that provides the caller's __LINE__ to the double prefix version.
- *
- * If you wish to call the function without any debug or state checking,
- * you should use the single _ prefix version (as is used by dependent IO
- * routines, for example _iwl_read_restricted calls the non-check version of
- * _iwl_read32.)
- *
- * These declarations are *extremely* useful in quickly isolating code deltas
- * which result in misconfiguring of the hardware I/O.  In combination with
- * git-bisect and the IO debug level you can quickly determine the specific
- * commit which breaks the IO sequence to the hardware.
- *
- */
-
-#define _iwl_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *iwl,
-				 u32 ofs, u32 val)
-{
-	IWL_DEBUG_IO("write_direct32(0x%08X, 0x%08X) - %s %d\n",
-		     (u32) (ofs), (u32) (val), f, l);
-	_iwl_write32(iwl, ofs, val);
-}
-#define iwl_write32(iwl, ofs, val) \
-	__iwl_write32(__FILE__, __LINE__, iwl, ofs, val)
-#else
-#define iwl_write32(iwl, ofs, val) _iwl_write32(iwl, ofs, val)
-#endif
-
-#define _iwl_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *iwl, u32 ofs)
-{
-	IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
-	return _iwl_read32(iwl, ofs);
-}
-#define iwl_read32(iwl, ofs) __iwl_read32(__FILE__, __LINE__, iwl, ofs)
-#else
-#define iwl_read32(p, o) _iwl_read32(p, o)
-#endif
-
-static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
-				u32 bits, u32 mask, int timeout)
-{
-	int i = 0;
-
-	do {
-		if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
-			return i;
-		mdelay(10);
-		i += 10;
-	} while (i < timeout);
-
-	return -ETIMEDOUT;
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline int __iwl_poll_bit(const char *f, u32 l,
-				 struct iwl_priv *priv, u32 addr,
-				 u32 bits, u32 mask, int timeout)
-{
-	int rc = _iwl_poll_bit(priv, addr, bits, mask, timeout);
-	if (unlikely(rc == -ETIMEDOUT))
-		IWL_DEBUG_IO
-		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n",
-		     addr, bits, mask, f, l);
-	else
-		IWL_DEBUG_IO
-		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n",
-		     addr, bits, mask, rc, f, l);
-	return rc;
-}
-#define iwl_poll_bit(iwl, addr, bits, mask, timeout) \
-	__iwl_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
-#else
-#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t)
-#endif
-
-static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
-{
-	_iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_set_bit(const char *f, u32 l,
-				 struct iwl_priv *priv, u32 reg, u32 mask)
-{
-	u32 val = _iwl_read32(priv, reg) | mask;
-	IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
-	_iwl_write32(priv, reg, val);
-}
-#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m)
-#else
-#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m)
-#endif
-
-static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
-{
-	_iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_clear_bit(const char *f, u32 l,
-				   struct iwl_priv *priv, u32 reg, u32 mask)
-{
-	u32 val = _iwl_read32(priv, reg) & ~mask;
-	IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
-	_iwl_write32(priv, reg, val);
-}
-#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m)
-#else
-#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m)
-#endif
-
-static inline int _iwl_grab_restricted_access(struct iwl_priv *priv)
-{
-	int rc;
-	u32 gp_ctl;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (atomic_read(&priv->restrict_refcnt))
-		return 0;
-#endif
-	if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
-	    test_bit(STATUS_RF_KILL_SW, &priv->status)) {
-		IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
-			"wakes up NIC\n");
-
-		/* 10 msec allows time for NIC to complete its data save */
-		gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL);
-		if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
-			IWL_DEBUG_RF_KILL("Wait for complete power-down, "
-				"gpctl = 0x%08x\n", gp_ctl);
-			mdelay(10);
-		} else
-			IWL_DEBUG_RF_KILL("power-down complete, "
-					  "gpctl = 0x%08x\n", gp_ctl);
-	}
-
-	/* this bit wakes up the NIC */
-	_iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-	rc = _iwl_poll_bit(priv, CSR_GP_CNTRL,
-			   CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
-			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
-			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50);
-	if (rc < 0) {
-		IWL_ERROR("MAC is in deep sleep!\n");
-		return -EIO;
-	}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	atomic_inc(&priv->restrict_refcnt);
-#endif
-	return 0;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline int __iwl_grab_restricted_access(const char *f, u32 l,
-					       struct iwl_priv *priv)
-{
-	if (atomic_read(&priv->restrict_refcnt))
-		IWL_DEBUG_INFO("Grabbing access while already held at "
-			       "line %d.\n", l);
-
-	IWL_DEBUG_IO("grabbing restricted access - %s %d\n", f, l);
-
-	return _iwl_grab_restricted_access(priv);
-}
-#define iwl_grab_restricted_access(priv) \
-	__iwl_grab_restricted_access(__FILE__, __LINE__, priv)
-#else
-#define iwl_grab_restricted_access(priv) \
-	_iwl_grab_restricted_access(priv)
-#endif
-
-static inline void _iwl_release_restricted_access(struct iwl_priv *priv)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (atomic_dec_and_test(&priv->restrict_refcnt))
-#endif
-		_iwl_clear_bit(priv, CSR_GP_CNTRL,
-			       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_release_restricted_access(const char *f, u32 l,
-						   struct iwl_priv *priv)
-{
-	if (atomic_read(&priv->restrict_refcnt) <= 0)
-		IWL_ERROR("Release unheld restricted access at line %d.\n", l);
-
-	IWL_DEBUG_IO("releasing restricted access - %s %d\n", f, l);
-	_iwl_release_restricted_access(priv);
-}
-#define iwl_release_restricted_access(priv) \
-	__iwl_release_restricted_access(__FILE__, __LINE__, priv)
-#else
-#define iwl_release_restricted_access(priv) \
-	_iwl_release_restricted_access(priv)
-#endif
-
-static inline u32 _iwl_read_restricted(struct iwl_priv *priv, u32 reg)
-{
-	return _iwl_read32(priv, reg);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline u32 __iwl_read_restricted(const char *f, u32 l,
-					struct iwl_priv *priv, u32 reg)
-{
-	u32 value = _iwl_read_restricted(priv, reg);
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERROR("Unrestricted access from %s %d\n", f, l);
-	IWL_DEBUG_IO("read_restricted(0x%4X) = 0x%08x - %s %d \n", reg, value,
-		     f, l);
-	return value;
-}
-#define iwl_read_restricted(priv, reg) \
-	__iwl_read_restricted(__FILE__, __LINE__, priv, reg)
-#else
-#define iwl_read_restricted _iwl_read_restricted
-#endif
-
-static inline void _iwl_write_restricted(struct iwl_priv *priv,
-					 u32 reg, u32 value)
-{
-	_iwl_write32(priv, reg, value);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static void __iwl_write_restricted(u32 line,
-				   struct iwl_priv *priv, u32 reg, u32 value)
-{
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERROR("Unrestricted access from line %d\n", line);
-	_iwl_write_restricted(priv, reg, value);
-}
-#define iwl_write_restricted(priv, reg, value) \
-	__iwl_write_restricted(__LINE__, priv, reg, value)
-#else
-#define iwl_write_restricted _iwl_write_restricted
-#endif
-
-static inline void iwl_write_buffer_restricted(struct iwl_priv *priv,
-					       u32 reg, u32 len, u32 *values)
-{
-	u32 count = sizeof(u32);
-
-	if ((priv != NULL) && (values != NULL)) {
-		for (; 0 < len; len -= count, reg += count, values++)
-			_iwl_write_restricted(priv, reg, *values);
-	}
-}
-
-static inline int _iwl_poll_restricted_bit(struct iwl_priv *priv,
-					   u32 addr, u32 mask, int timeout)
-{
-	int i = 0;
-
-	do {
-		if ((_iwl_read_restricted(priv, addr) & mask) == mask)
-			return i;
-		mdelay(10);
-		i += 10;
-	} while (i < timeout);
-
-	return -ETIMEDOUT;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline int __iwl_poll_restricted_bit(const char *f, u32 l,
-					    struct iwl_priv *priv,
-					    u32 addr, u32 mask, int timeout)
-{
-	int rc = _iwl_poll_restricted_bit(priv, addr, mask, timeout);
-
-	if (unlikely(rc == -ETIMEDOUT))
-		IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) - "
-			     "timedout - %s %d\n", addr, mask, f, l);
-	else
-		IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) = 0x%08X "
-			     "- %s %d\n", addr, mask, rc, f, l);
-	return rc;
-}
-#define iwl_poll_restricted_bit(iwl, addr, mask, timeout) \
-	__iwl_poll_restricted_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
-#else
-#define iwl_poll_restricted_bit _iwl_poll_restricted_bit
-#endif
-
-static inline u32 _iwl_read_restricted_reg(struct iwl_priv *priv, u32 reg)
-{
-	_iwl_write_restricted(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
-	return _iwl_read_restricted(priv, HBUS_TARG_PRPH_RDAT);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline u32 __iwl_read_restricted_reg(u32 line,
-					    struct iwl_priv *priv, u32 reg)
-{
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERROR("Unrestricted access from line %d\n", line);
-	return _iwl_read_restricted_reg(priv, reg);
-}
-
-#define iwl_read_restricted_reg(priv, reg) \
-	__iwl_read_restricted_reg(__LINE__, priv, reg)
-#else
-#define iwl_read_restricted_reg _iwl_read_restricted_reg
-#endif
-
-static inline void _iwl_write_restricted_reg(struct iwl_priv *priv,
-					     u32 addr, u32 val)
-{
-	_iwl_write_restricted(priv, HBUS_TARG_PRPH_WADDR,
-			      ((addr & 0x0000FFFF) | (3 << 24)));
-	_iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, val);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_write_restricted_reg(u32 line,
-					      struct iwl_priv *priv,
-					      u32 addr, u32 val)
-{
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERROR("Unrestricted access from line %d\n", line);
-	_iwl_write_restricted_reg(priv, addr, val);
-}
-
-#define iwl_write_restricted_reg(priv, addr, val) \
-	__iwl_write_restricted_reg(__LINE__, priv, addr, val);
-#else
-#define iwl_write_restricted_reg _iwl_write_restricted_reg
-#endif
-
-#define _iwl_set_bits_restricted_reg(priv, reg, mask) \
-	_iwl_write_restricted_reg(priv, reg, \
-				  (_iwl_read_restricted_reg(priv, reg) | mask))
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_set_bits_restricted_reg(u32 line, struct iwl_priv
-						 *priv, u32 reg, u32 mask)
-{
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERROR("Unrestricted access from line %d\n", line);
-	_iwl_set_bits_restricted_reg(priv, reg, mask);
-}
-#define iwl_set_bits_restricted_reg(priv, reg, mask) \
-	__iwl_set_bits_restricted_reg(__LINE__, priv, reg, mask)
-#else
-#define iwl_set_bits_restricted_reg _iwl_set_bits_restricted_reg
-#endif
-
-#define _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \
-	_iwl_write_restricted_reg( \
-	    priv, reg, ((_iwl_read_restricted_reg(priv, reg) & mask) | bits))
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_set_bits_mask_restricted_reg(u32 line,
-		struct iwl_priv *priv, u32 reg, u32 bits, u32 mask)
-{
-	if (!atomic_read(&priv->restrict_refcnt))
-		IWL_ERROR("Unrestricted access from line %d\n", line);
-	_iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask);
-}
-
-#define iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \
-	__iwl_set_bits_mask_restricted_reg(__LINE__, priv, reg, bits, mask)
-#else
-#define iwl_set_bits_mask_restricted_reg _iwl_set_bits_mask_restricted_reg
-#endif
-
-static inline void iwl_clear_bits_restricted_reg(struct iwl_priv
-						 *priv, u32 reg, u32 mask)
-{
-	u32 val = _iwl_read_restricted_reg(priv, reg);
-	_iwl_write_restricted_reg(priv, reg, (val & ~mask));
-}
-
-static inline u32 iwl_read_restricted_mem(struct iwl_priv *priv, u32 addr)
-{
-	iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, addr);
-	return iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
-}
-
-static inline void iwl_write_restricted_mem(struct iwl_priv *priv, u32 addr,
-					    u32 val)
-{
-	iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr);
-	iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, val);
-}
-
-static inline void iwl_write_restricted_mems(struct iwl_priv *priv, u32 addr,
-					     u32 len, u32 *values)
-{
-	iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr);
-	for (; 0 < len; len -= sizeof(u32), values++)
-		iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, *values);
-}
-
-static inline void iwl_write_restricted_regs(struct iwl_priv *priv, u32 reg,
-					     u32 len, u8 *values)
-{
-	u32 reg_offset = reg;
-	u32 aligment = reg & 0x3;
-
-	/* write any non-dword-aligned stuff at the beginning */
-	if (len < sizeof(u32)) {
-		if ((aligment + len) <= sizeof(u32)) {
-			u8 size;
-			u32 value = 0;
-			size = len - 1;
-			memcpy(&value, values, len);
-			reg_offset = (reg_offset & 0x0000FFFF);
-
-			_iwl_write_restricted(priv,
-					      HBUS_TARG_PRPH_WADDR,
-					      (reg_offset | (size << 24)));
-			_iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT,
-					      value);
-		}
-
-		return;
-	}
-
-	/* now write all the dword-aligned stuff */
-	for (; reg_offset < (reg + len);
-	     reg_offset += sizeof(u32), values += sizeof(u32))
-		_iwl_write_restricted_reg(priv, reg_offset, *((u32 *) values));
-}
-
-#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-priv.h b/drivers/net/wireless/iwlwifi/iwl-priv.h
deleted file mode 100644
index 6b490d08fea9..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-priv.h
+++ /dev/null
@@ -1,308 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#ifndef __iwl_priv_h__
-#define __iwl_priv_h__
-
-#include <linux/workqueue.h>
-
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-
-enum {
-	MEASUREMENT_READY = (1 << 0),
-	MEASUREMENT_ACTIVE = (1 << 1),
-};
-
-#endif
-
-struct iwl_priv {
-
-	/* ieee device used by generic ieee processing code */
-	struct ieee80211_hw *hw;
-	struct ieee80211_channel *ieee_channels;
-	struct ieee80211_rate *ieee_rates;
-
-	/* temporary frame storage list */
-	struct list_head free_frames;
-	int frames_count;
-
-	u8 phymode;
-	int alloc_rxb_skb;
-
-	void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
-				       struct iwl_rx_mem_buffer *rxb);
-
-	const struct ieee80211_hw_mode *modes;
-
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-	/* spectrum measurement report caching */
-	struct iwl_spectrum_notification measure_report;
-	u8 measurement_status;
-#endif
-	/* ucode beacon time */
-	u32 ucode_beacon_time;
-
-	/* we allocate array of iwl_channel_info for NIC's valid channels.
-	 *    Access via channel # using indirect index array */
-	struct iwl_channel_info *channel_info;	/* channel info array */
-	u8 channel_count;	/* # of channels */
-
-	/* each calibration channel group in the EEPROM has a derived
-	 * clip setting for each rate. */
-	const struct iwl_clip_group clip_groups[5];
-
-	/* thermal calibration */
-	s32 temperature;	/* degrees Kelvin */
-	s32 last_temperature;
-
-	/* Scan related variables */
-	unsigned long last_scan_jiffies;
-	unsigned long scan_start;
-	unsigned long scan_pass_start;
-	unsigned long scan_start_tsf;
-	int scan_bands;
-	int one_direct_scan;
-	u8 direct_ssid_len;
-	u8 direct_ssid[IW_ESSID_MAX_SIZE];
-	struct iwl_scan_cmd *scan;
-	u8 only_active_channel;
-
-	/* spinlock */
-	spinlock_t lock;	/* protect general shared data */
-	spinlock_t hcmd_lock;	/* protect hcmd */
-	struct mutex mutex;
-
-	/* basic pci-network driver stuff */
-	struct pci_dev *pci_dev;
-
-	/* pci hardware address support */
-	void __iomem *hw_base;
-
-	/* uCode images, save to reload in case of failure */
-	struct fw_image_desc ucode_code;	/* runtime inst */
-	struct fw_image_desc ucode_data;	/* runtime data original */
-	struct fw_image_desc ucode_data_backup;	/* runtime data save/restore */
-	struct fw_image_desc ucode_init;	/* initialization inst */
-	struct fw_image_desc ucode_init_data;	/* initialization data */
-	struct fw_image_desc ucode_boot;	/* bootstrap inst */
-
-
-	struct iwl_rxon_time_cmd rxon_timing;
-
-	/* We declare this const so it can only be
-	 * changed via explicit cast within the
-	 * routines that actually update the physical
-	 * hardware */
-	const struct iwl_rxon_cmd active_rxon;
-	struct iwl_rxon_cmd staging_rxon;
-
-	int error_recovering;
-	struct iwl_rxon_cmd recovery_rxon;
-
-	/* 1st responses from initialize and runtime uCode images.
-	 * 4965's initialize alive response contains some calibration data. */
-	struct iwl_init_alive_resp card_alive_init;
-	struct iwl_alive_resp card_alive;
-
-#ifdef LED
-	/* LED related variables */
-	struct iwl_activity_blink activity;
-	unsigned long led_packets;
-	int led_state;
-#endif
-
-	u16 active_rate;
-	u16 active_rate_basic;
-
-	u8 call_post_assoc_from_beacon;
-	u8 assoc_station_added;
-#if IWL == 4965
-	u8 use_ant_b_for_management_frame;	/* Tx antenna selection */
-	/* HT variables */
-	u8 is_dup;
-	u8 is_ht_enabled;
-	u8 channel_width;	/* 0=20MHZ, 1=40MHZ */
-	u8 current_channel_width;
-	u8 valid_antenna;	/* Bit mask of antennas actually connected */
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
-	struct iwl_sensitivity_data sensitivity_data;
-	struct iwl_chain_noise_data chain_noise_data;
-	u8 start_calib;
-	__le16 sensitivity_tbl[HD_TABLE_SIZE];
-#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
-
-#ifdef CONFIG_IWLWIFI_HT
-	struct sta_ht_info current_assoc_ht;
-#endif
-	u8 active_rate_ht[2];
-	u8 last_phy_res[100];
-
-	/* Rate scaling data */
-	struct iwl_lq_mngr lq_mngr;
-#endif
-
-	/* Rate scaling data */
-	s8 data_retry_limit;
-	u8 retry_rate;
-
-	wait_queue_head_t wait_command_queue;
-
-	int activity_timer_active;
-
-	/* Rx and Tx DMA processing queues */
-	struct iwl_rx_queue rxq;
-	struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
-#if IWL == 4965
-	unsigned long txq_ctx_active_msk;
-	struct iwl_kw kw;	/* keep warm address */
-	u32 scd_base_addr;	/* scheduler sram base address */
-#endif
-
-	unsigned long status;
-	u32 config;
-
-	int last_rx_rssi;	/* From Rx packet statisitics */
-	int last_rx_noise;	/* From beacon statistics */
-
-	struct iwl_power_mgr power_data;
-
-	struct iwl_notif_statistics statistics;
-	unsigned long last_statistics_time;
-
-	/* context information */
-	u8 essid[IW_ESSID_MAX_SIZE];
-	u8 essid_len;
-	u16 rates_mask;
-
-	u32 power_mode;
-	u32 antenna;
-	u8 bssid[ETH_ALEN];
-	u16 rts_threshold;
-	u8 mac_addr[ETH_ALEN];
-
-	/*station table variables */
-	spinlock_t sta_lock;
-	int num_stations;
-	struct iwl_station_entry stations[IWL_STATION_COUNT];
-
-	/* Indication if ieee80211_ops->open has been called */
-	int is_open;
-
-	u8 mac80211_registered;
-	int is_abg;
-
-	u32 notif_missed_beacons;
-
-	/* Rx'd packet timing information */
-	u32 last_beacon_time;
-	u64 last_tsf;
-
-	/* Duplicate packet detection */
-	u16 last_seq_num;
-	u16 last_frag_num;
-	unsigned long last_packet_time;
-	struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
-
-	/* eeprom */
-	struct iwl_eeprom eeprom;
-
-	int iw_mode;
-
-	struct sk_buff *ibss_beacon;
-
-	/* Last Rx'd beacon timestamp */
-	u32 timestamp0;
-	u32 timestamp1;
-	u16 beacon_int;
-	struct iwl_driver_hw_info hw_setting;
-	int interface_id;
-
-	/* Current association information needed to configure the
-	 * hardware */
-	u16 assoc_id;
-	u16 assoc_capability;
-	u8 ps_mode;
-
-#ifdef CONFIG_IWLWIFI_QOS
-	struct iwl_qos_info qos_data;
-#endif /*CONFIG_IWLWIFI_QOS */
-
-	struct workqueue_struct *workqueue;
-
-	struct work_struct up;
-	struct work_struct restart;
-	struct work_struct calibrated_work;
-	struct work_struct scan_completed;
-	struct work_struct rx_replenish;
-	struct work_struct rf_kill;
-	struct work_struct abort_scan;
-	struct work_struct update_link_led;
-	struct work_struct auth_work;
-	struct work_struct report_work;
-	struct work_struct request_scan;
-	struct work_struct beacon_update;
-
-	struct tasklet_struct irq_tasklet;
-
-	struct delayed_work init_alive_start;
-	struct delayed_work alive_start;
-	struct delayed_work activity_timer;
-	struct delayed_work thermal_periodic;
-	struct delayed_work gather_stats;
-	struct delayed_work scan_check;
-	struct delayed_work post_associate;
-
-#define IWL_DEFAULT_TX_POWER 0x0F
-	s8 user_txpower_limit;
-	s8 max_channel_txpower_limit;
-	u32 cck_power_index_compensation;
-
-#ifdef CONFIG_PM
-	u32 pm_state[16];
-#endif
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-	/* debugging info */
-	u32 framecnt_to_us;
-	atomic_t restrict_refcnt;
-#endif
-
-#if IWL == 4965
-	struct work_struct txpower_work;
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
-	struct work_struct sensitivity_work;
-#endif
-	struct work_struct statistics_work;
-	struct timer_list statistics_periodic;
-
-#ifdef CONFIG_IWLWIFI_HT_AGG
-	struct work_struct agg_work;
-#endif
-
-#endif /* 4965 */
-};				/*iwl_priv */
-
-#endif /* __iwl_priv_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 0df41148eadc..4ba121634877 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -8,7 +8,7 @@
  * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU Geeral Public License as
+ * it under the terms of version 2 of the GNU General Public License as
  * published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful, but
@@ -63,7 +63,10 @@
 #ifndef	__iwl_prph_h__
 #define __iwl_prph_h__
 
-
+/*
+ * Registers in this file are internal, not PCI bus memory mapped.
+ * Driver accesses these via HBUS_TARG_PRPH_* registers.
+ */
 #define PRPH_BASE	(0x00000)
 #define PRPH_END	(0xFFFFF)
 
@@ -226,4 +229,58 @@
 #define BSM_SRAM_SIZE			(1024) /* bytes */
 
 
+/* 3945 Tx scheduler registers */
+#define ALM_SCD_BASE                        (PRPH_BASE + 0x2E00)
+#define ALM_SCD_MODE_REG                    (ALM_SCD_BASE + 0x000)
+#define ALM_SCD_ARASTAT_REG                 (ALM_SCD_BASE + 0x004)
+#define ALM_SCD_TXFACT_REG                  (ALM_SCD_BASE + 0x010)
+#define ALM_SCD_TXF4MF_REG                  (ALM_SCD_BASE + 0x014)
+#define ALM_SCD_TXF5MF_REG                  (ALM_SCD_BASE + 0x020)
+#define ALM_SCD_SBYP_MODE_1_REG             (ALM_SCD_BASE + 0x02C)
+#define ALM_SCD_SBYP_MODE_2_REG             (ALM_SCD_BASE + 0x030)
+
+/*
+ * 4965 Tx Scheduler registers.
+ * Details are documented in iwl-4965-hw.h
+ */
+#define KDR_SCD_BASE		(PRPH_BASE + 0xa02c00)
+
+#define KDR_SCD_SRAM_BASE_ADDR         (KDR_SCD_BASE + 0x0)
+#define KDR_SCD_EMPTY_BITS             (KDR_SCD_BASE + 0x4)
+#define KDR_SCD_DRAM_BASE_ADDR         (KDR_SCD_BASE + 0x10)
+#define KDR_SCD_AIT                    (KDR_SCD_BASE + 0x18)
+#define KDR_SCD_TXFACT                 (KDR_SCD_BASE + 0x1c)
+#define KDR_SCD_QUEUE_WRPTR(x)         (KDR_SCD_BASE + 0x24 + (x) * 4)
+#define KDR_SCD_QUEUE_RDPTR(x)         (KDR_SCD_BASE + 0x64 + (x) * 4)
+#define KDR_SCD_SETQUEUENUM            (KDR_SCD_BASE + 0xa4)
+#define KDR_SCD_SET_TXSTAT_TXED        (KDR_SCD_BASE + 0xa8)
+#define KDR_SCD_SET_TXSTAT_DONE        (KDR_SCD_BASE + 0xac)
+#define KDR_SCD_SET_TXSTAT_NOT_SCHD    (KDR_SCD_BASE + 0xb0)
+#define KDR_SCD_DECREASE_CREDIT        (KDR_SCD_BASE + 0xb4)
+#define KDR_SCD_DECREASE_SCREDIT       (KDR_SCD_BASE + 0xb8)
+#define KDR_SCD_LOAD_CREDIT            (KDR_SCD_BASE + 0xbc)
+#define KDR_SCD_LOAD_SCREDIT           (KDR_SCD_BASE + 0xc0)
+#define KDR_SCD_BAR                    (KDR_SCD_BASE + 0xc4)
+#define KDR_SCD_BAR_DW0                (KDR_SCD_BASE + 0xc8)
+#define KDR_SCD_BAR_DW1                (KDR_SCD_BASE + 0xcc)
+#define KDR_SCD_QUEUECHAIN_SEL         (KDR_SCD_BASE + 0xd0)
+#define KDR_SCD_QUERY_REQ              (KDR_SCD_BASE + 0xd8)
+#define KDR_SCD_QUERY_RES              (KDR_SCD_BASE + 0xdc)
+#define KDR_SCD_PENDING_FRAMES         (KDR_SCD_BASE + 0xe0)
+#define KDR_SCD_INTERRUPT_MASK         (KDR_SCD_BASE + 0xe4)
+#define KDR_SCD_INTERRUPT_THRESHOLD    (KDR_SCD_BASE + 0xe8)
+#define KDR_SCD_QUERY_MIN_FRAME_SIZE   (KDR_SCD_BASE + 0x100)
+#define KDR_SCD_QUEUE_STATUS_BITS(x)   (KDR_SCD_BASE + 0x104 + (x) * 4)
+
+/* SP SCD */
+#define SHL_SCD_BASE			(PRPH_BASE + 0xa02c00)
+
+#define SHL_SCD_AIT                    (SHL_SCD_BASE + 0x0c)
+#define SHL_SCD_TXFACT                 (SHL_SCD_BASE + 0x10)
+#define SHL_SCD_QUEUE_WRPTR(x)         (SHL_SCD_BASE + 0x18 + (x) * 4)
+#define SHL_SCD_QUEUE_RDPTR(x)         (SHL_SCD_BASE + 0x68 + (x) * 4)
+#define SHL_SCD_QUEUECHAIN_SEL         (SHL_SCD_BASE + 0xe8)
+#define SHL_SCD_AGGR_SEL	       (SHL_SCD_BASE + 0x248)
+#define SHL_SCD_INTERRUPT_MASK         (SHL_SCD_BASE + 0x108)
+
 #endif				/* __iwl_prph_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 1a6b0e0edf6f..748ac1222abb 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -27,16 +27,6 @@
  *
  *****************************************************************************/
 
-/*
- * NOTE:  This file (iwl-base.c) is used to build to multiple hardware targets
- * by defining IWL to either 3945 or 4965.  The Makefile used when building
- * the base targets will create base-3945.o and base-4965.o
- *
- * The eventual goal is to move as many of the #if IWL / #endif blocks out of
- * this file and into the hardware specific implementation files (iwl-XXXX.c)
- * and leave only the common (non #ifdef sprinkled) code in this file
- */
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/version.h>
@@ -56,16 +46,16 @@
 
 #include <asm/div64.h>
 
-#define IWL 3945
-
-#include "iwlwifi.h"
 #include "iwl-3945.h"
 #include "iwl-helpers.h"
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-u32 iwl_debug_level;
+#ifdef CONFIG_IWL3945_DEBUG
+u32 iwl3945_debug_level;
 #endif
 
+static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv,
+				  struct iwl3945_tx_queue *txq);
+
 /******************************************************************************
  *
  * module boiler plate
@@ -73,13 +63,13 @@ u32 iwl_debug_level;
  ******************************************************************************/
 
 /* module parameters */
-int iwl_param_disable_hw_scan;
-int iwl_param_debug;
-int iwl_param_disable;      /* def: enable radio */
-int iwl_param_antenna;      /* def: 0 = both antennas (use diversity) */
-int iwl_param_hwcrypto;     /* def: using software encryption */
-int iwl_param_qos_enable = 1;
-int iwl_param_queues_num = IWL_MAX_NUM_QUEUES;
+static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */
+static int iwl3945_param_debug;    /* def: 0 = minimal debug log messages */
+static int iwl3945_param_disable;  /* def: 0 = enable radio */
+static int iwl3945_param_antenna;  /* def: 0 = both antennas (use diversity) */
+int iwl3945_param_hwcrypto;        /* def: 0 = use software encryption */
+static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */
+int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 8 Tx queues */
 
 /*
  * module name, copyright, version, etc.
@@ -89,19 +79,19 @@ int iwl_param_queues_num = IWL_MAX_NUM_QUEUES;
 #define DRV_DESCRIPTION	\
 "Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux"
 
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL3945_DEBUG
 #define VD "d"
 #else
 #define VD
 #endif
 
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
 #define VS "s"
 #else
 #define VS
 #endif
 
-#define IWLWIFI_VERSION "1.1.17k" VD VS
+#define IWLWIFI_VERSION "1.2.23k" VD VS
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2007 Intel Corporation"
 #define DRV_VERSION     IWLWIFI_VERSION
 
@@ -116,7 +106,7 @@ MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
-__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
+static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
 {
 	u16 fc = le16_to_cpu(hdr->frame_control);
 	int hdr_len = ieee80211_get_hdrlen(fc);
@@ -126,8 +116,8 @@ __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
 	return NULL;
 }
 
-static const struct ieee80211_hw_mode *iwl_get_hw_mode(
-		struct iwl_priv *priv, int mode)
+static const struct ieee80211_hw_mode *iwl3945_get_hw_mode(
+		struct iwl3945_priv *priv, int mode)
 {
 	int i;
 
@@ -138,7 +128,7 @@ static const struct ieee80211_hw_mode *iwl_get_hw_mode(
 	return NULL;
 }
 
-static int iwl_is_empty_essid(const char *essid, int essid_len)
+static int iwl3945_is_empty_essid(const char *essid, int essid_len)
 {
 	/* Single white space is for Linksys APs */
 	if (essid_len == 1 && essid[0] == ' ')
@@ -154,13 +144,13 @@ static int iwl_is_empty_essid(const char *essid, int essid_len)
 	return 1;
 }
 
-static const char *iwl_escape_essid(const char *essid, u8 essid_len)
+static const char *iwl3945_escape_essid(const char *essid, u8 essid_len)
 {
 	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
 	const char *s = essid;
 	char *d = escaped;
 
-	if (iwl_is_empty_essid(essid, essid_len)) {
+	if (iwl3945_is_empty_essid(essid, essid_len)) {
 		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
 		return escaped;
 	}
@@ -178,10 +168,10 @@ static const char *iwl_escape_essid(const char *essid, u8 essid_len)
 	return escaped;
 }
 
-static void iwl_print_hex_dump(int level, void *p, u32 len)
+static void iwl3945_print_hex_dump(int level, void *p, u32 len)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (!(iwl_debug_level & level))
+#ifdef CONFIG_IWL3945_DEBUG
+	if (!(iwl3945_debug_level & level))
 		return;
 
 	print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
@@ -194,24 +184,31 @@ static void iwl_print_hex_dump(int level, void *p, u32 len)
  *
  * Theory of operation
  *
- * A queue is a circular buffers with 'Read' and 'Write' pointers.
- * 2 empty entries always kept in the buffer to protect from overflow.
+ * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
+ * of buffer descriptors, each of which points to one or more data buffers for
+ * the device to read from or fill.  Driver and device exchange status of each
+ * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
+ * entries in each circular buffer, to protect against confusing empty and full
+ * queue states.
+ *
+ * The device reads or writes the data in the queues via the device's several
+ * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
  *
  * For Tx queue, there are low mark and high mark limits. If, after queuing
  * the packet for Tx, free space become < low mark, Tx queue stopped. When
  * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
  * Tx queue resumed.
  *
- * The IWL operates with six queues, one receive queue in the device's
- * sram, one transmit queue for sending commands to the device firmware,
- * and four transmit queues for data.
+ * The 3945 operates with six queues:  One receive queue, one transmit queue
+ * (#4) for sending commands to the device firmware, and four transmit queues
+ * (#0-3) for data tx via EDCA.  An additional 2 HCCA queues are unused.
  ***************************************************/
 
-static int iwl_queue_space(const struct iwl_queue *q)
+static int iwl3945_queue_space(const struct iwl3945_queue *q)
 {
-	int s = q->last_used - q->first_empty;
+	int s = q->read_ptr - q->write_ptr;
 
-	if (q->last_used > q->first_empty)
+	if (q->read_ptr > q->write_ptr)
 		s -= q->n_bd;
 
 	if (s <= 0)
@@ -223,42 +220,55 @@ static int iwl_queue_space(const struct iwl_queue *q)
 	return s;
 }
 
-/* XXX: n_bd must be power-of-two size */
-static inline int iwl_queue_inc_wrap(int index, int n_bd)
+/**
+ * iwl3945_queue_inc_wrap - increment queue index, wrap back to beginning
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl3945_queue_inc_wrap(int index, int n_bd)
 {
 	return ++index & (n_bd - 1);
 }
 
-/* XXX: n_bd must be power-of-two size */
-static inline int iwl_queue_dec_wrap(int index, int n_bd)
+/**
+ * iwl3945_queue_dec_wrap - increment queue index, wrap back to end
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl3945_queue_dec_wrap(int index, int n_bd)
 {
 	return --index & (n_bd - 1);
 }
 
-static inline int x2_queue_used(const struct iwl_queue *q, int i)
+static inline int x2_queue_used(const struct iwl3945_queue *q, int i)
 {
-	return q->first_empty > q->last_used ?
-		(i >= q->last_used && i < q->first_empty) :
-		!(i < q->last_used && i >= q->first_empty);
+	return q->write_ptr > q->read_ptr ?
+		(i >= q->read_ptr && i < q->write_ptr) :
+		!(i < q->read_ptr && i >= q->write_ptr);
 }
 
-static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+static inline u8 get_cmd_index(struct iwl3945_queue *q, u32 index, int is_huge)
 {
+	/* This is for scan command, the big buffer at end of command array */
 	if (is_huge)
-		return q->n_window;
+		return q->n_window;	/* must be power of 2 */
 
+	/* Otherwise, use normal size buffers */
 	return index & (q->n_window - 1);
 }
 
-static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+/**
+ * iwl3945_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
+static int iwl3945_queue_init(struct iwl3945_priv *priv, struct iwl3945_queue *q,
 			  int count, int slots_num, u32 id)
 {
 	q->n_bd = count;
 	q->n_window = slots_num;
 	q->id = id;
 
-	/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
-	 * and iwl_queue_dec_wrap are broken. */
+	/* count must be power-of-two size, otherwise iwl3945_queue_inc_wrap
+	 * and iwl3945_queue_dec_wrap are broken. */
 	BUG_ON(!is_power_of_2(count));
 
 	/* slots_num must be power-of-two size, otherwise
@@ -273,27 +283,34 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
 	if (q->high_mark < 2)
 		q->high_mark = 2;
 
-	q->first_empty = q->last_used = 0;
+	q->write_ptr = q->read_ptr = 0;
 
 	return 0;
 }
 
-static int iwl_tx_queue_alloc(struct iwl_priv *priv,
-			      struct iwl_tx_queue *txq, u32 id)
+/**
+ * iwl3945_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
+ */
+static int iwl3945_tx_queue_alloc(struct iwl3945_priv *priv,
+			      struct iwl3945_tx_queue *txq, u32 id)
 {
 	struct pci_dev *dev = priv->pci_dev;
 
+	/* Driver private data, only for Tx (not command) queues,
+	 * not shared with device. */
 	if (id != IWL_CMD_QUEUE_NUM) {
 		txq->txb = kmalloc(sizeof(txq->txb[0]) *
 				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
 		if (!txq->txb) {
-			IWL_ERROR("kmalloc for auxilary BD "
+			IWL_ERROR("kmalloc for auxiliary BD "
 				  "structures failed\n");
 			goto error;
 		}
 	} else
 		txq->txb = NULL;
 
+	/* Circular buffer of transmit frame descriptors (TFDs),
+	 * shared with device */
 	txq->bd = pci_alloc_consistent(dev,
 			sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
 			&txq->q.dma_addr);
@@ -316,24 +333,33 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
 	return -ENOMEM;
 }
 
-int iwl_tx_queue_init(struct iwl_priv *priv,
-		      struct iwl_tx_queue *txq, int slots_num, u32 txq_id)
+/**
+ * iwl3945_tx_queue_init - Allocate and initialize one tx/cmd queue
+ */
+int iwl3945_tx_queue_init(struct iwl3945_priv *priv,
+		      struct iwl3945_tx_queue *txq, int slots_num, u32 txq_id)
 {
 	struct pci_dev *dev = priv->pci_dev;
 	int len;
 	int rc = 0;
 
-	/* alocate command space + one big command for scan since scan
-	 * command is very huge the system will not have two scan at the
-	 * same time */
-	len = sizeof(struct iwl_cmd) * slots_num;
+	/*
+	 * Alloc buffer array for commands (Tx or other types of commands).
+	 * For the command queue (#4), allocate command space + one big
+	 * command for scan, since scan command is very huge; the system will
+	 * not have two scans at the same time, so only one is needed.
+	 * For data Tx queues (all other queues), no super-size command
+	 * space is needed.
+	 */
+	len = sizeof(struct iwl3945_cmd) * slots_num;
 	if (txq_id == IWL_CMD_QUEUE_NUM)
 		len +=  IWL_MAX_SCAN_SIZE;
 	txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
 	if (!txq->cmd)
 		return -ENOMEM;
 
-	rc = iwl_tx_queue_alloc(priv, txq, txq_id);
+	/* Alloc driver data array and TFD circular buffer */
+	rc = iwl3945_tx_queue_alloc(priv, txq, txq_id);
 	if (rc) {
 		pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
 
@@ -342,26 +368,29 @@ int iwl_tx_queue_init(struct iwl_priv *priv,
 	txq->need_update = 0;
 
 	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
-	 * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+	 * iwl3945_queue_inc_wrap and iwl3945_queue_dec_wrap are broken. */
 	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-	iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
 
-	iwl_hw_tx_queue_init(priv, txq);
+	/* Initialize queue high/low-water, head/tail indexes */
+	iwl3945_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+	/* Tell device where to find queue, enable DMA channel. */
+	iwl3945_hw_tx_queue_init(priv, txq);
 
 	return 0;
 }
 
 /**
- * iwl_tx_queue_free - Deallocate DMA queue.
+ * iwl3945_tx_queue_free - Deallocate DMA queue.
  * @txq: Transmit queue to deallocate.
  *
  * Empty queue by removing and destroying all BD's.
- * Free all buffers.  txq itself is not freed.
- *
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
  */
-void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq)
 {
-	struct iwl_queue *q = &txq->q;
+	struct iwl3945_queue *q = &txq->q;
 	struct pci_dev *dev = priv->pci_dev;
 	int len;
 
@@ -369,44 +398,47 @@ void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 		return;
 
 	/* first, empty all BD's */
-	for (; q->first_empty != q->last_used;
-	     q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd))
-		iwl_hw_txq_free_tfd(priv, txq);
+	for (; q->write_ptr != q->read_ptr;
+	     q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd))
+		iwl3945_hw_txq_free_tfd(priv, txq);
 
-	len = sizeof(struct iwl_cmd) * q->n_window;
+	len = sizeof(struct iwl3945_cmd) * q->n_window;
 	if (q->id == IWL_CMD_QUEUE_NUM)
 		len += IWL_MAX_SCAN_SIZE;
 
+	/* De-alloc array of command/tx buffers */
 	pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
 
-	/* free buffers belonging to queue itself */
+	/* De-alloc circular buffer of TFDs */
 	if (txq->q.n_bd)
-		pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
+		pci_free_consistent(dev, sizeof(struct iwl3945_tfd_frame) *
 				    txq->q.n_bd, txq->bd, txq->q.dma_addr);
 
+	/* De-alloc array of per-TFD driver data */
 	if (txq->txb) {
 		kfree(txq->txb);
 		txq->txb = NULL;
 	}
 
-	/* 0 fill whole structure */
+	/* 0-fill queue descriptor structure */
 	memset(txq, 0, sizeof(*txq));
 }
 
-const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+const u8 iwl3945_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
 /*************** STATION TABLE MANAGEMENT ****
- *
- * NOTE:  This needs to be overhauled to better synchronize between
- * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c
- *
- * mac80211 should also be examined to determine if sta_info is duplicating
+ * mac80211 should be examined to determine if sta_info is duplicating
  * the functionality provided here
  */
 
 /**************************************************************/
-#if 0 /* temparary disable till we add real remove station */
-static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+#if 0 /* temporary disable till we add real remove station */
+/**
+ * iwl3945_remove_station - Remove driver's knowledge of station.
+ *
+ * NOTE:  This does not remove station from device's station table.
+ */
+static u8 iwl3945_remove_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap)
 {
 	int index = IWL_INVALID_STATION;
 	int i;
@@ -442,7 +474,13 @@ out:
 	return 0;
 }
 #endif
-static void iwl_clear_stations_table(struct iwl_priv *priv)
+
+/**
+ * iwl3945_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE:  This does not clear or otherwise alter the device's station table.
+ */
+static void iwl3945_clear_stations_table(struct iwl3945_priv *priv)
 {
 	unsigned long flags;
 
@@ -454,12 +492,14 @@ static void iwl_clear_stations_table(struct iwl_priv *priv)
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
 
-
-u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
+/**
+ * iwl3945_add_station - Add station to station tables in driver and device
+ */
+u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 flags)
 {
 	int i;
 	int index = IWL_INVALID_STATION;
-	struct iwl_station_entry *station;
+	struct iwl3945_station_entry *station;
 	unsigned long flags_spin;
 	DECLARE_MAC_BUF(mac);
 	u8 rate;
@@ -482,7 +522,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
 				index = i;
 		}
 
-	/* These twh conditions has the same outcome but keep them separate
+	/* These two conditions has the same outcome but keep them separate
 	  since they have different meaning */
 	if (unlikely(index == IWL_INVALID_STATION)) {
 		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -500,30 +540,35 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
 	station->used = 1;
 	priv->num_stations++;
 
-	memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+	/* Set up the REPLY_ADD_STA command to send to device */
+	memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd));
 	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
 	station->sta.mode = 0;
 	station->sta.sta.sta_id = index;
 	station->sta.station_flags = 0;
 
-	rate = (priv->phymode == MODE_IEEE80211A) ? IWL_RATE_6M_PLCP :
-				IWL_RATE_1M_PLCP | priv->hw_setting.cck_flag;
+	if (priv->phymode == MODE_IEEE80211A)
+		rate = IWL_RATE_6M_PLCP;
+	else
+		rate =	IWL_RATE_1M_PLCP;
 
 	/* Turn on both antennas for the station... */
 	station->sta.rate_n_flags =
-			iwl_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
+			iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
 	station->current_rate.rate_n_flags =
 			le16_to_cpu(station->sta.rate_n_flags);
 
 	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-	iwl_send_add_station(priv, &station->sta, flags);
+
+	/* Add station to device's station table */
+	iwl3945_send_add_station(priv, &station->sta, flags);
 	return index;
 
 }
 
 /*************** DRIVER STATUS FUNCTIONS   *****/
 
-static inline int iwl_is_ready(struct iwl_priv *priv)
+static inline int iwl3945_is_ready(struct iwl3945_priv *priv)
 {
 	/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
 	 * set but EXIT_PENDING is not */
@@ -532,29 +577,29 @@ static inline int iwl_is_ready(struct iwl_priv *priv)
 	       !test_bit(STATUS_EXIT_PENDING, &priv->status);
 }
 
-static inline int iwl_is_alive(struct iwl_priv *priv)
+static inline int iwl3945_is_alive(struct iwl3945_priv *priv)
 {
 	return test_bit(STATUS_ALIVE, &priv->status);
 }
 
-static inline int iwl_is_init(struct iwl_priv *priv)
+static inline int iwl3945_is_init(struct iwl3945_priv *priv)
 {
 	return test_bit(STATUS_INIT, &priv->status);
 }
 
-static inline int iwl_is_rfkill(struct iwl_priv *priv)
+static inline int iwl3945_is_rfkill(struct iwl3945_priv *priv)
 {
 	return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
 	       test_bit(STATUS_RF_KILL_SW, &priv->status);
 }
 
-static inline int iwl_is_ready_rf(struct iwl_priv *priv)
+static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv)
 {
 
-	if (iwl_is_rfkill(priv))
+	if (iwl3945_is_rfkill(priv))
 		return 0;
 
-	return iwl_is_ready(priv);
+	return iwl3945_is_ready(priv);
 }
 
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
@@ -613,7 +658,7 @@ static const char *get_cmd_string(u8 cmd)
 #define HOST_COMPLETE_TIMEOUT (HZ / 2)
 
 /**
- * iwl_enqueue_hcmd - enqueue a uCode command
+ * iwl3945_enqueue_hcmd - enqueue a uCode command
  * @priv: device private data point
  * @cmd: a point to the ucode command structure
  *
@@ -621,13 +666,13 @@ static const char *get_cmd_string(u8 cmd)
  * failed. On success, it turns the index (> 0) of command in the
  * command queue.
  */
-static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
 {
-	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
-	struct iwl_queue *q = &txq->q;
-	struct iwl_tfd_frame *tfd;
+	struct iwl3945_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+	struct iwl3945_queue *q = &txq->q;
+	struct iwl3945_tfd_frame *tfd;
 	u32 *control_flags;
-	struct iwl_cmd *out_cmd;
+	struct iwl3945_cmd *out_cmd;
 	u32 idx;
 	u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
 	dma_addr_t phys_addr;
@@ -642,19 +687,19 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
 	       !(cmd->meta.flags & CMD_SIZE_HUGE));
 
-	if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+	if (iwl3945_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
 		IWL_ERROR("No space for Tx\n");
 		return -ENOSPC;
 	}
 
 	spin_lock_irqsave(&priv->hcmd_lock, flags);
 
-	tfd = &txq->bd[q->first_empty];
+	tfd = &txq->bd[q->write_ptr];
 	memset(tfd, 0, sizeof(*tfd));
 
 	control_flags = (u32 *) tfd;
 
-	idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE);
+	idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
 	out_cmd = &txq->cmd[idx];
 
 	out_cmd->hdr.cmd = cmd->id;
@@ -666,13 +711,13 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
 	out_cmd->hdr.flags = 0;
 	out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
-			INDEX_TO_SEQ(q->first_empty));
+			INDEX_TO_SEQ(q->write_ptr));
 	if (out_cmd->meta.flags & CMD_SIZE_HUGE)
 		out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
 
 	phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
-			offsetof(struct iwl_cmd, hdr);
-	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+			offsetof(struct iwl3945_cmd, hdr);
+	iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
 
 	pad = U32_PAD(cmd->len);
 	count = TFD_CTL_COUNT_GET(*control_flags);
@@ -682,17 +727,19 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 		     "%d bytes at %d[%d]:%d\n",
 		     get_cmd_string(out_cmd->hdr.cmd),
 		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
-		     fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM);
+		     fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
 
 	txq->need_update = 1;
-	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
-	ret = iwl_tx_queue_update_write_ptr(priv, txq);
+
+	/* Increment and update queue's write index */
+	q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd);
+	ret = iwl3945_tx_queue_update_write_ptr(priv, txq);
 
 	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
 	return ret ? ret : idx;
 }
 
-int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+static int iwl3945_send_cmd_async(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
 {
 	int ret;
 
@@ -707,16 +754,16 @@ int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return -EBUSY;
 
-	ret = iwl_enqueue_hcmd(priv, cmd);
+	ret = iwl3945_enqueue_hcmd(priv, cmd);
 	if (ret < 0) {
-		IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+		IWL_ERROR("Error sending %s: iwl3945_enqueue_hcmd failed: %d\n",
 			  get_cmd_string(cmd->id), ret);
 		return ret;
 	}
 	return 0;
 }
 
-int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+static int iwl3945_send_cmd_sync(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
 {
 	int cmd_idx;
 	int ret;
@@ -738,10 +785,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	if (cmd->meta.flags & CMD_WANT_SKB)
 		cmd->meta.source = &cmd->meta;
 
-	cmd_idx = iwl_enqueue_hcmd(priv, cmd);
+	cmd_idx = iwl3945_enqueue_hcmd(priv, cmd);
 	if (cmd_idx < 0) {
 		ret = cmd_idx;
-		IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+		IWL_ERROR("Error sending %s: iwl3945_enqueue_hcmd failed: %d\n",
 			  get_cmd_string(cmd->id), ret);
 		goto out;
 	}
@@ -785,7 +832,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
 cancel:
 	if (cmd->meta.flags & CMD_WANT_SKB) {
-		struct iwl_cmd *qcmd;
+		struct iwl3945_cmd *qcmd;
 
 		/* Cancel the CMD_WANT_SKB flag for the cmd in the
 		 * TX cmd queue. Otherwise in case the cmd comes
@@ -804,47 +851,43 @@ out:
 	return ret;
 }
 
-int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+int iwl3945_send_cmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd)
 {
-	/* A command can not be asynchronous AND expect an SKB to be set. */
-	BUG_ON((cmd->meta.flags & CMD_ASYNC) &&
-	       (cmd->meta.flags & CMD_WANT_SKB));
-
 	if (cmd->meta.flags & CMD_ASYNC)
-		return iwl_send_cmd_async(priv, cmd);
+		return iwl3945_send_cmd_async(priv, cmd);
 
-	return iwl_send_cmd_sync(priv, cmd);
+	return iwl3945_send_cmd_sync(priv, cmd);
 }
 
-int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
+int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len, const void *data)
 {
-	struct iwl_host_cmd cmd = {
+	struct iwl3945_host_cmd cmd = {
 		.id = id,
 		.len = len,
 		.data = data,
 	};
 
-	return iwl_send_cmd_sync(priv, &cmd);
+	return iwl3945_send_cmd_sync(priv, &cmd);
 }
 
-static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val)
+static int __must_check iwl3945_send_cmd_u32(struct iwl3945_priv *priv, u8 id, u32 val)
 {
-	struct iwl_host_cmd cmd = {
+	struct iwl3945_host_cmd cmd = {
 		.id = id,
 		.len = sizeof(val),
 		.data = &val,
 	};
 
-	return iwl_send_cmd_sync(priv, &cmd);
+	return iwl3945_send_cmd_sync(priv, &cmd);
 }
 
-int iwl_send_statistics_request(struct iwl_priv *priv)
+int iwl3945_send_statistics_request(struct iwl3945_priv *priv)
 {
-	return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
+	return iwl3945_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
 }
 
 /**
- * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * iwl3945_set_rxon_channel - Set the phymode and channel values in staging RXON
  * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
  * @channel: Any channel valid for the requested phymode
 
@@ -853,9 +896,9 @@ int iwl_send_statistics_request(struct iwl_priv *priv)
  * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
  * in the staging RXON flag structure based on the phymode
  */
-static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel)
+static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, u8 phymode, u16 channel)
 {
-	if (!iwl_get_channel_info(priv, phymode, channel)) {
+	if (!iwl3945_get_channel_info(priv, phymode, channel)) {
 		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
 			       channel, phymode);
 		return -EINVAL;
@@ -879,13 +922,13 @@ static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel)
 }
 
 /**
- * iwl_check_rxon_cmd - validate RXON structure is valid
+ * iwl3945_check_rxon_cmd - validate RXON structure is valid
  *
  * NOTE:  This is really only useful during development and can eventually
  * be #ifdef'd out once the driver is stable and folks aren't actively
  * making changes
  */
-static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+static int iwl3945_check_rxon_cmd(struct iwl3945_rxon_cmd *rxon)
 {
 	int error = 0;
 	int counter = 1;
@@ -951,21 +994,21 @@ static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
 			    le16_to_cpu(rxon->channel));
 
 	if (error) {
-		IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n");
+		IWL_ERROR("Not a valid iwl3945_rxon_assoc_cmd field values\n");
 		return -1;
 	}
 	return 0;
 }
 
 /**
- * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
- * @priv: staging_rxon is comapred to active_rxon
+ * iwl3945_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
+ * @priv: staging_rxon is compared to active_rxon
  *
- * If the RXON structure is changing sufficient to require a new
- * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1
- * to indicate a new tune is required.
+ * If the RXON structure is changing enough to require a new tune,
+ * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
+ * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
  */
-static int iwl_full_rxon_required(struct iwl_priv *priv)
+static int iwl3945_full_rxon_required(struct iwl3945_priv *priv)
 {
 
 	/* These items are only settable from the full RXON command */
@@ -1000,19 +1043,19 @@ static int iwl_full_rxon_required(struct iwl_priv *priv)
 	return 0;
 }
 
-static int iwl_send_rxon_assoc(struct iwl_priv *priv)
+static int iwl3945_send_rxon_assoc(struct iwl3945_priv *priv)
 {
 	int rc = 0;
-	struct iwl_rx_packet *res = NULL;
-	struct iwl_rxon_assoc_cmd rxon_assoc;
-	struct iwl_host_cmd cmd = {
+	struct iwl3945_rx_packet *res = NULL;
+	struct iwl3945_rxon_assoc_cmd rxon_assoc;
+	struct iwl3945_host_cmd cmd = {
 		.id = REPLY_RXON_ASSOC,
 		.len = sizeof(rxon_assoc),
 		.meta.flags = CMD_WANT_SKB,
 		.data = &rxon_assoc,
 	};
-	const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-	const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+	const struct iwl3945_rxon_cmd *rxon1 = &priv->staging_rxon;
+	const struct iwl3945_rxon_cmd *rxon2 = &priv->active_rxon;
 
 	if ((rxon1->flags == rxon2->flags) &&
 	    (rxon1->filter_flags == rxon2->filter_flags) &&
@@ -1028,11 +1071,11 @@ static int iwl_send_rxon_assoc(struct iwl_priv *priv)
 	rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
 	rxon_assoc.reserved = 0;
 
-	rc = iwl_send_cmd_sync(priv, &cmd);
+	rc = iwl3945_send_cmd_sync(priv, &cmd);
 	if (rc)
 		return rc;
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
 		rc = -EIO;
@@ -1045,21 +1088,21 @@ static int iwl_send_rxon_assoc(struct iwl_priv *priv)
 }
 
 /**
- * iwl_commit_rxon - commit staging_rxon to hardware
+ * iwl3945_commit_rxon - commit staging_rxon to hardware
  *
- * The RXON command in staging_rxon is commited to the hardware and
+ * The RXON command in staging_rxon is committed to the hardware and
  * the active_rxon structure is updated with the new data.  This
  * function correctly transitions out of the RXON_ASSOC_MSK state if
  * a HW tune is required based on the RXON structure changes.
  */
-static int iwl_commit_rxon(struct iwl_priv *priv)
+static int iwl3945_commit_rxon(struct iwl3945_priv *priv)
 {
 	/* cast away the const for active_rxon in this function */
-	struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+	struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
 	int rc = 0;
 	DECLARE_MAC_BUF(mac);
 
-	if (!iwl_is_alive(priv))
+	if (!iwl3945_is_alive(priv))
 		return -1;
 
 	/* always get timestamp with Rx frame */
@@ -1070,17 +1113,17 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
 	    ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
 	priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv);
 
-	rc = iwl_check_rxon_cmd(&priv->staging_rxon);
+	rc = iwl3945_check_rxon_cmd(&priv->staging_rxon);
 	if (rc) {
 		IWL_ERROR("Invalid RXON configuration.  Not committing.\n");
 		return -EINVAL;
 	}
 
 	/* If we don't need to send a full RXON, we can use
-	 * iwl_rxon_assoc_cmd which is used to reconfigure filter
+	 * iwl3945_rxon_assoc_cmd which is used to reconfigure filter
 	 * and other flags for the current radio configuration. */
-	if (!iwl_full_rxon_required(priv)) {
-		rc = iwl_send_rxon_assoc(priv);
+	if (!iwl3945_full_rxon_required(priv)) {
+		rc = iwl3945_send_rxon_assoc(priv);
 		if (rc) {
 			IWL_ERROR("Error setting RXON_ASSOC "
 				  "configuration (%d).\n", rc);
@@ -1096,13 +1139,13 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
 	 * an RXON_ASSOC and the new config wants the associated mask enabled,
 	 * we must clear the associated from the active configuration
 	 * before we apply the new config */
-	if (iwl_is_associated(priv) &&
+	if (iwl3945_is_associated(priv) &&
 	    (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
 		IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
 		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
-		rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
-				      sizeof(struct iwl_rxon_cmd),
+		rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON,
+				      sizeof(struct iwl3945_rxon_cmd),
 				      &priv->active_rxon);
 
 		/* If the mask clearing failed then we set
@@ -1125,8 +1168,8 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
 		       print_mac(mac, priv->staging_rxon.bssid_addr));
 
 	/* Apply the new configuration */
-	rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
-			      sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+	rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON,
+			      sizeof(struct iwl3945_rxon_cmd), &priv->staging_rxon);
 	if (rc) {
 		IWL_ERROR("Error setting new configuration (%d).\n", rc);
 		return rc;
@@ -1134,18 +1177,18 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
 
 	memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
 
-	iwl_clear_stations_table(priv);
+	iwl3945_clear_stations_table(priv);
 
 	/* If we issue a new RXON command which required a tune then we must
 	 * send a new TXPOWER command or we won't be able to Tx any frames */
-	rc = iwl_hw_reg_send_txpower(priv);
+	rc = iwl3945_hw_reg_send_txpower(priv);
 	if (rc) {
 		IWL_ERROR("Error setting Tx power (%d).\n", rc);
 		return rc;
 	}
 
 	/* Add the broadcast address so we can send broadcast frames */
-	if (iwl_add_station(priv, BROADCAST_ADDR, 0, 0) ==
+	if (iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0) ==
 	    IWL_INVALID_STATION) {
 		IWL_ERROR("Error adding BROADCAST address for transmit.\n");
 		return -EIO;
@@ -1153,9 +1196,9 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
 
 	/* If we have set the ASSOC_MSK and we are in BSS mode then
 	 * add the IWL_AP_ID to the station rate table */
-	if (iwl_is_associated(priv) &&
+	if (iwl3945_is_associated(priv) &&
 	    (priv->iw_mode == IEEE80211_IF_TYPE_STA))
-		if (iwl_add_station(priv, priv->active_rxon.bssid_addr, 1, 0)
+		if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0)
 		    == IWL_INVALID_STATION) {
 			IWL_ERROR("Error adding AP address for transmit.\n");
 			return -EIO;
@@ -1172,9 +1215,9 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
 	return 0;
 }
 
-static int iwl_send_bt_config(struct iwl_priv *priv)
+static int iwl3945_send_bt_config(struct iwl3945_priv *priv)
 {
-	struct iwl_bt_cmd bt_cmd = {
+	struct iwl3945_bt_cmd bt_cmd = {
 		.flags = 3,
 		.lead_time = 0xAA,
 		.max_kill = 1,
@@ -1182,15 +1225,15 @@ static int iwl_send_bt_config(struct iwl_priv *priv)
 		.kill_cts_mask = 0,
 	};
 
-	return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-				sizeof(struct iwl_bt_cmd), &bt_cmd);
+	return iwl3945_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+				sizeof(struct iwl3945_bt_cmd), &bt_cmd);
 }
 
-static int iwl_send_scan_abort(struct iwl_priv *priv)
+static int iwl3945_send_scan_abort(struct iwl3945_priv *priv)
 {
 	int rc = 0;
-	struct iwl_rx_packet *res;
-	struct iwl_host_cmd cmd = {
+	struct iwl3945_rx_packet *res;
+	struct iwl3945_host_cmd cmd = {
 		.id = REPLY_SCAN_ABORT_CMD,
 		.meta.flags = CMD_WANT_SKB,
 	};
@@ -1203,13 +1246,13 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
 		return 0;
 	}
 
-	rc = iwl_send_cmd_sync(priv, &cmd);
+	rc = iwl3945_send_cmd_sync(priv, &cmd);
 	if (rc) {
 		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
 		return rc;
 	}
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
 	if (res->u.status != CAN_ABORT_STATUS) {
 		/* The scan abort will return 1 for success or
 		 * 2 for "failure".  A failure condition can be
@@ -1227,8 +1270,8 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
 	return rc;
 }
 
-static int iwl_card_state_sync_callback(struct iwl_priv *priv,
-					struct iwl_cmd *cmd,
+static int iwl3945_card_state_sync_callback(struct iwl3945_priv *priv,
+					struct iwl3945_cmd *cmd,
 					struct sk_buff *skb)
 {
 	return 1;
@@ -1237,16 +1280,16 @@ static int iwl_card_state_sync_callback(struct iwl_priv *priv,
 /*
  * CARD_STATE_CMD
  *
- * Use: Sets the internal card state to enable, disable, or halt
+ * Use: Sets the device's internal card state to enable, disable, or halt
  *
  * When in the 'enable' state the card operates as normal.
  * When in the 'disable' state, the card enters into a low power mode.
  * When in the 'halt' state, the card is shut down and must be fully
  * restarted to come back on.
  */
-static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
+static int iwl3945_send_card_state(struct iwl3945_priv *priv, u32 flags, u8 meta_flag)
 {
-	struct iwl_host_cmd cmd = {
+	struct iwl3945_host_cmd cmd = {
 		.id = REPLY_CARD_STATE_CMD,
 		.len = sizeof(u32),
 		.data = &flags,
@@ -1254,22 +1297,22 @@ static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
 	};
 
 	if (meta_flag & CMD_ASYNC)
-		cmd.meta.u.callback = iwl_card_state_sync_callback;
+		cmd.meta.u.callback = iwl3945_card_state_sync_callback;
 
-	return iwl_send_cmd(priv, &cmd);
+	return iwl3945_send_cmd(priv, &cmd);
 }
 
-static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
-				     struct iwl_cmd *cmd, struct sk_buff *skb)
+static int iwl3945_add_sta_sync_callback(struct iwl3945_priv *priv,
+				     struct iwl3945_cmd *cmd, struct sk_buff *skb)
 {
-	struct iwl_rx_packet *res = NULL;
+	struct iwl3945_rx_packet *res = NULL;
 
 	if (!skb) {
 		IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
 		return 1;
 	}
 
-	res = (struct iwl_rx_packet *)skb->data;
+	res = (struct iwl3945_rx_packet *)skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
 			  res->hdr.flags);
@@ -1287,29 +1330,29 @@ static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
 	return 1;
 }
 
-int iwl_send_add_station(struct iwl_priv *priv,
-			 struct iwl_addsta_cmd *sta, u8 flags)
+int iwl3945_send_add_station(struct iwl3945_priv *priv,
+			 struct iwl3945_addsta_cmd *sta, u8 flags)
 {
-	struct iwl_rx_packet *res = NULL;
+	struct iwl3945_rx_packet *res = NULL;
 	int rc = 0;
-	struct iwl_host_cmd cmd = {
+	struct iwl3945_host_cmd cmd = {
 		.id = REPLY_ADD_STA,
-		.len = sizeof(struct iwl_addsta_cmd),
+		.len = sizeof(struct iwl3945_addsta_cmd),
 		.meta.flags = flags,
 		.data = sta,
 	};
 
 	if (flags & CMD_ASYNC)
-		cmd.meta.u.callback = iwl_add_sta_sync_callback;
+		cmd.meta.u.callback = iwl3945_add_sta_sync_callback;
 	else
 		cmd.meta.flags |= CMD_WANT_SKB;
 
-	rc = iwl_send_cmd(priv, &cmd);
+	rc = iwl3945_send_cmd(priv, &cmd);
 
 	if (rc || (flags & CMD_ASYNC))
 		return rc;
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
 			  res->hdr.flags);
@@ -1334,7 +1377,7 @@ int iwl_send_add_station(struct iwl_priv *priv,
 	return rc;
 }
 
-static int iwl_update_sta_key_info(struct iwl_priv *priv,
+static int iwl3945_update_sta_key_info(struct iwl3945_priv *priv,
 				   struct ieee80211_key_conf *keyconf,
 				   u8 sta_id)
 {
@@ -1350,7 +1393,6 @@ static int iwl_update_sta_key_info(struct iwl_priv *priv,
 		break;
 	case ALG_TKIP:
 	case ALG_WEP:
-		return -EINVAL;
 	default:
 		return -EINVAL;
 	}
@@ -1369,28 +1411,28 @@ static int iwl_update_sta_key_info(struct iwl_priv *priv,
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
 	IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	iwl3945_send_add_station(priv, &priv->stations[sta_id].sta, 0);
 	return 0;
 }
 
-static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
+static int iwl3945_clear_sta_key_info(struct iwl3945_priv *priv, u8 sta_id)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
-	memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
-	memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo));
+	memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl3945_hw_key));
+	memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl3945_keyinfo));
 	priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
 	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
 	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
 	IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	iwl3945_send_add_station(priv, &priv->stations[sta_id].sta, 0);
 	return 0;
 }
 
-static void iwl_clear_free_frames(struct iwl_priv *priv)
+static void iwl3945_clear_free_frames(struct iwl3945_priv *priv)
 {
 	struct list_head *element;
 
@@ -1400,7 +1442,7 @@ static void iwl_clear_free_frames(struct iwl_priv *priv)
 	while (!list_empty(&priv->free_frames)) {
 		element = priv->free_frames.next;
 		list_del(element);
-		kfree(list_entry(element, struct iwl_frame, list));
+		kfree(list_entry(element, struct iwl3945_frame, list));
 		priv->frames_count--;
 	}
 
@@ -1411,9 +1453,9 @@ static void iwl_clear_free_frames(struct iwl_priv *priv)
 	}
 }
 
-static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
+static struct iwl3945_frame *iwl3945_get_free_frame(struct iwl3945_priv *priv)
 {
-	struct iwl_frame *frame;
+	struct iwl3945_frame *frame;
 	struct list_head *element;
 	if (list_empty(&priv->free_frames)) {
 		frame = kzalloc(sizeof(*frame), GFP_KERNEL);
@@ -1428,21 +1470,21 @@ static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
 
 	element = priv->free_frames.next;
 	list_del(element);
-	return list_entry(element, struct iwl_frame, list);
+	return list_entry(element, struct iwl3945_frame, list);
 }
 
-static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
+static void iwl3945_free_frame(struct iwl3945_priv *priv, struct iwl3945_frame *frame)
 {
 	memset(frame, 0, sizeof(*frame));
 	list_add(&frame->list, &priv->free_frames);
 }
 
-unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv,
 				struct ieee80211_hdr *hdr,
 				const u8 *dest, int left)
 {
 
-	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
+	if (!iwl3945_is_associated(priv) || !priv->ibss_beacon ||
 	    ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
 	     (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
 		return 0;
@@ -1455,37 +1497,27 @@ unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
 	return priv->ibss_beacon->len;
 }
 
-static int iwl_rate_index_from_plcp(int plcp)
-{
-	int i = 0;
-
-	for (i = 0; i < IWL_RATE_COUNT; i++)
-		if (iwl_rates[i].plcp == plcp)
-			return i;
-	return -1;
-}
-
-static u8 iwl_rate_get_lowest_plcp(int rate_mask)
+static u8 iwl3945_rate_get_lowest_plcp(int rate_mask)
 {
 	u8 i;
 
 	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
-	     i = iwl_rates[i].next_ieee) {
+	     i = iwl3945_rates[i].next_ieee) {
 		if (rate_mask & (1 << i))
-			return iwl_rates[i].plcp;
+			return iwl3945_rates[i].plcp;
 	}
 
 	return IWL_RATE_INVALID;
 }
 
-static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv)
 {
-	struct iwl_frame *frame;
+	struct iwl3945_frame *frame;
 	unsigned int frame_size;
 	int rc;
 	u8 rate;
 
-	frame = iwl_get_free_frame(priv);
+	frame = iwl3945_get_free_frame(priv);
 
 	if (!frame) {
 		IWL_ERROR("Could not obtain free frame buffer for beacon "
@@ -1494,22 +1526,22 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
 	}
 
 	if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
-		rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic &
+		rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic &
 						0xFF0);
 		if (rate == IWL_INVALID_RATE)
 			rate = IWL_RATE_6M_PLCP;
 	} else {
-		rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
+		rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
 		if (rate == IWL_INVALID_RATE)
 			rate = IWL_RATE_1M_PLCP;
 	}
 
-	frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
+	frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate);
 
-	rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
+	rc = iwl3945_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
 			      &frame->u.cmd[0]);
 
-	iwl_free_frame(priv, frame);
+	iwl3945_free_frame(priv, frame);
 
 	return rc;
 }
@@ -1520,22 +1552,22 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
  *
  ******************************************************************************/
 
-static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac)
+static void get_eeprom_mac(struct iwl3945_priv *priv, u8 *mac)
 {
 	memcpy(mac, priv->eeprom.mac_address, 6);
 }
 
 /**
- * iwl_eeprom_init - read EEPROM contents
+ * iwl3945_eeprom_init - read EEPROM contents
  *
- * Load the EEPROM from adapter into priv->eeprom
+ * Load the EEPROM contents from adapter into priv->eeprom
  *
  * NOTE:  This routine uses the non-debug IO access functions.
  */
-int iwl_eeprom_init(struct iwl_priv *priv)
+int iwl3945_eeprom_init(struct iwl3945_priv *priv)
 {
-	u16 *e = (u16 *)&priv->eeprom;
-	u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
+	__le16 *e = (__le16 *)&priv->eeprom;
+	u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP);
 	u32 r;
 	int sz = sizeof(priv->eeprom);
 	int rc;
@@ -1553,20 +1585,21 @@ int iwl_eeprom_init(struct iwl_priv *priv)
 		return -ENOENT;
 	}
 
-	rc = iwl_eeprom_aqcuire_semaphore(priv);
+	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
+	rc = iwl3945_eeprom_acquire_semaphore(priv);
 	if (rc < 0) {
-		IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n");
+		IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
 		return -ENOENT;
 	}
 
 	/* eeprom is an array of 16bit values */
 	for (addr = 0; addr < sz; addr += sizeof(u16)) {
-		_iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
-		_iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+		_iwl3945_write32(priv, CSR_EEPROM_REG, addr << 1);
+		_iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
 
 		for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
 					i += IWL_EEPROM_ACCESS_DELAY) {
-			r = _iwl_read_restricted(priv, CSR_EEPROM_REG);
+			r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG);
 			if (r & CSR_EEPROM_REG_READ_VALID_MSK)
 				break;
 			udelay(IWL_EEPROM_ACCESS_DELAY);
@@ -1576,7 +1609,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
 			IWL_ERROR("Time out reading EEPROM[%d]", addr);
 			return -ETIMEDOUT;
 		}
-		e[addr / 2] = le16_to_cpu(r >> 16);
+		e[addr / 2] = cpu_to_le16(r >> 16);
 	}
 
 	return 0;
@@ -1587,22 +1620,17 @@ int iwl_eeprom_init(struct iwl_priv *priv)
  * Misc. internal state and helper functions
  *
  ******************************************************************************/
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL3945_DEBUG
 
 /**
- * iwl_report_frame - dump frame to syslog during debug sessions
+ * iwl3945_report_frame - dump frame to syslog during debug sessions
  *
- * hack this function to show different aspects of received frames,
+ * You may hack this function to show different aspects of received frames,
  * including selective frame dumps.
  * group100 parameter selects whether to show 1 out of 100 good frames.
- *
- * TODO:  ieee80211_hdr stuff is common to 3945 and 4965, so frame type
- *        info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats)
- *        is 3945-specific and gives bad output for 4965.  Need to split the
- *        functionality, keep common stuff here.
  */
-void iwl_report_frame(struct iwl_priv *priv,
-		      struct iwl_rx_packet *pkt,
+void iwl3945_report_frame(struct iwl3945_priv *priv,
+		      struct iwl3945_rx_packet *pkt,
 		      struct ieee80211_hdr *header, int group100)
 {
 	u32 to_us;
@@ -1624,9 +1652,9 @@ void iwl_report_frame(struct iwl_priv *priv,
 	u8 agc;
 	u16 sig_avg;
 	u16 noise_diff;
-	struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
-	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
-	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+	struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
 	u8 *data = IWL_RX_DATA(pkt);
 
 	/* MAC header */
@@ -1702,11 +1730,11 @@ void iwl_report_frame(struct iwl_priv *priv,
 		else
 			title = "Frame";
 
-		rate = iwl_rate_index_from_plcp(rate_sym);
+		rate = iwl3945_rate_index_from_plcp(rate_sym);
 		if (rate == -1)
 			rate = 0;
 		else
-			rate = iwl_rates[rate].ieee / 2;
+			rate = iwl3945_rates[rate].ieee / 2;
 
 		/* print frame summary.
 		 * MAC addresses show just the last byte (for brevity),
@@ -1728,25 +1756,25 @@ void iwl_report_frame(struct iwl_priv *priv,
 		}
 	}
 	if (print_dump)
-		iwl_print_hex_dump(IWL_DL_RX, data, length);
+		iwl3945_print_hex_dump(IWL_DL_RX, data, length);
 }
 #endif
 
-static void iwl_unset_hw_setting(struct iwl_priv *priv)
+static void iwl3945_unset_hw_setting(struct iwl3945_priv *priv)
 {
 	if (priv->hw_setting.shared_virt)
 		pci_free_consistent(priv->pci_dev,
-				    sizeof(struct iwl_shared),
+				    sizeof(struct iwl3945_shared),
 				    priv->hw_setting.shared_virt,
 				    priv->hw_setting.shared_phys);
 }
 
 /**
- * iwl_supported_rate_to_ie - fill in the supported rate in IE field
+ * iwl3945_supported_rate_to_ie - fill in the supported rate in IE field
  *
  * return : set the bit for each supported rate insert in ie
  */
-static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+static u16 iwl3945_supported_rate_to_ie(u8 *ie, u16 supported_rate,
 				    u16 basic_rate, int *left)
 {
 	u16 ret_rates = 0, bit;
@@ -1757,7 +1785,7 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
 	for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
 		if (bit & supported_rate) {
 			ret_rates |= bit;
-			rates[*cnt] = iwl_rates[i].ieee |
+			rates[*cnt] = iwl3945_rates[i].ieee |
 				((bit & basic_rate) ? 0x80 : 0x00);
 			(*cnt)++;
 			(*left)--;
@@ -1771,9 +1799,9 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
 }
 
 /**
- * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ * iwl3945_fill_probe_req - fill in all required fields and IE for probe request
  */
-static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv,
 			      struct ieee80211_mgmt *frame,
 			      int left, int is_direct)
 {
@@ -1789,9 +1817,9 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
 	len += 24;
 
 	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
-	memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN);
+	memcpy(frame->da, iwl3945_broadcast_addr, ETH_ALEN);
 	memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
-	memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN);
+	memcpy(frame->bssid, iwl3945_broadcast_addr, ETH_ALEN);
 	frame->seq_ctrl = 0;
 
 	/* fill in our indirect SSID IE */
@@ -1834,11 +1862,11 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
 	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
 
 	cck_rates = IWL_CCK_RATES_MASK & active_rates;
-	ret_rates = iwl_supported_rate_to_ie(pos, cck_rates,
+	ret_rates = iwl3945_supported_rate_to_ie(pos, cck_rates,
 			priv->active_rate_basic, &left);
 	active_rates &= ~ret_rates;
 
-	ret_rates = iwl_supported_rate_to_ie(pos, active_rates,
+	ret_rates = iwl3945_supported_rate_to_ie(pos, active_rates,
 				 priv->active_rate_basic, &left);
 	active_rates &= ~ret_rates;
 
@@ -1855,7 +1883,7 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
 	/* ... fill it in... */
 	*pos++ = WLAN_EID_EXT_SUPP_RATES;
 	*pos = 0;
-	iwl_supported_rate_to_ie(pos, active_rates,
+	iwl3945_supported_rate_to_ie(pos, active_rates,
 				 priv->active_rate_basic, &left);
 	if (*pos > 0)
 		len += 2 + *pos;
@@ -1867,16 +1895,16 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
 /*
  * QoS  support
 */
-#ifdef CONFIG_IWLWIFI_QOS
-static int iwl_send_qos_params_command(struct iwl_priv *priv,
-				       struct iwl_qosparam_cmd *qos)
+#ifdef CONFIG_IWL3945_QOS
+static int iwl3945_send_qos_params_command(struct iwl3945_priv *priv,
+				       struct iwl3945_qosparam_cmd *qos)
 {
 
-	return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
-				sizeof(struct iwl_qosparam_cmd), qos);
+	return iwl3945_send_cmd_pdu(priv, REPLY_QOS_PARAM,
+				sizeof(struct iwl3945_qosparam_cmd), qos);
 }
 
-static void iwl_reset_qos(struct iwl_priv *priv)
+static void iwl3945_reset_qos(struct iwl3945_priv *priv)
 {
 	u16 cw_min = 15;
 	u16 cw_max = 1023;
@@ -1963,13 +1991,10 @@ static void iwl_reset_qos(struct iwl_priv *priv)
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force)
 {
 	unsigned long flags;
 
-	if (priv == NULL)
-		return;
-
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
@@ -1990,16 +2015,16 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	if (force || iwl_is_associated(priv)) {
+	if (force || iwl3945_is_associated(priv)) {
 		IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
 			      priv->qos_data.qos_active);
 
-		iwl_send_qos_params_command(priv,
+		iwl3945_send_qos_params_command(priv,
 				&(priv->qos_data.def_qos_parm));
 	}
 }
 
-#endif /* CONFIG_IWLWIFI_QOS */
+#endif /* CONFIG_IWL3945_QOS */
 /*
  * Power management (not Tx power!) functions
  */
@@ -2017,7 +2042,7 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
 
 /* default power management (not Tx power) table values */
 /* for tim  0-10 */
-static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = {
 	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
 	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
 	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
@@ -2027,7 +2052,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
 };
 
 /* for tim > 10 */
-static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+static struct iwl3945_power_vec_entry range_1[IWL_POWER_AC] = {
 	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
 	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
 		 SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
@@ -2040,11 +2065,11 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
 		 SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
 };
 
-int iwl_power_init_handle(struct iwl_priv *priv)
+int iwl3945_power_init_handle(struct iwl3945_priv *priv)
 {
 	int rc = 0, i;
-	struct iwl_power_mgr *pow_data;
-	int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
+	struct iwl3945_power_mgr *pow_data;
+	int size = sizeof(struct iwl3945_power_vec_entry) * IWL_POWER_AC;
 	u16 pci_pm;
 
 	IWL_DEBUG_POWER("Initialize power \n");
@@ -2063,7 +2088,7 @@ int iwl_power_init_handle(struct iwl_priv *priv)
 	if (rc != 0)
 		return 0;
 	else {
-		struct iwl_powertable_cmd *cmd;
+		struct iwl3945_powertable_cmd *cmd;
 
 		IWL_DEBUG_POWER("adjust power command flags\n");
 
@@ -2079,15 +2104,15 @@ int iwl_power_init_handle(struct iwl_priv *priv)
 	return rc;
 }
 
-static int iwl_update_power_cmd(struct iwl_priv *priv,
-				struct iwl_powertable_cmd *cmd, u32 mode)
+static int iwl3945_update_power_cmd(struct iwl3945_priv *priv,
+				struct iwl3945_powertable_cmd *cmd, u32 mode)
 {
 	int rc = 0, i;
 	u8 skip;
 	u32 max_sleep = 0;
-	struct iwl_power_vec_entry *range;
+	struct iwl3945_power_vec_entry *range;
 	u8 period = 0;
-	struct iwl_power_mgr *pow_data;
+	struct iwl3945_power_mgr *pow_data;
 
 	if (mode > IWL_POWER_INDEX_5) {
 		IWL_DEBUG_POWER("Error invalid power mode \n");
@@ -2100,7 +2125,7 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
 	else
 		range = &pow_data->pwr_range_1[1];
 
-	memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
+	memcpy(cmd, &range[mode].cmd, sizeof(struct iwl3945_powertable_cmd));
 
 #ifdef IWL_MAC80211_DISABLE
 	if (priv->assoc_network != NULL) {
@@ -2143,14 +2168,14 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
 	return rc;
 }
 
-static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+static int iwl3945_send_power_mode(struct iwl3945_priv *priv, u32 mode)
 {
-	u32 final_mode = mode;
+	u32 uninitialized_var(final_mode);
 	int rc;
-	struct iwl_powertable_cmd cmd;
+	struct iwl3945_powertable_cmd cmd;
 
 	/* If on battery, set to 3,
-	 * if plugged into AC power, set to CAM ("continuosly aware mode"),
+	 * if plugged into AC power, set to CAM ("continuously aware mode"),
 	 * else user level */
 	switch (mode) {
 	case IWL_POWER_BATTERY:
@@ -2164,9 +2189,9 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
 		break;
 	}
 
-	iwl_update_power_cmd(priv, &cmd, final_mode);
+	iwl3945_update_power_cmd(priv, &cmd, final_mode);
 
-	rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
+	rc = iwl3945_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
 
 	if (final_mode == IWL_POWER_MODE_CAM)
 		clear_bit(STATUS_POWER_PMI, &priv->status);
@@ -2176,7 +2201,7 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
 	return rc;
 }
 
-int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
 {
 	/* Filter incoming packets to determine if they are targeted toward
 	 * this network, discarding packets coming from ourselves */
@@ -2206,7 +2231,7 @@ int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
 
 #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
 
-const char *iwl_get_tx_fail_reason(u32 status)
+static const char *iwl3945_get_tx_fail_reason(u32 status)
 {
 	switch (status & TX_STATUS_MSK) {
 	case TX_STATUS_SUCCESS:
@@ -2233,11 +2258,11 @@ const char *iwl_get_tx_fail_reason(u32 status)
 }
 
 /**
- * iwl_scan_cancel - Cancel any currently executing HW scan
+ * iwl3945_scan_cancel - Cancel any currently executing HW scan
  *
  * NOTE: priv->mutex is not required before calling this function
  */
-static int iwl_scan_cancel(struct iwl_priv *priv)
+static int iwl3945_scan_cancel(struct iwl3945_priv *priv)
 {
 	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
 		clear_bit(STATUS_SCANNING, &priv->status);
@@ -2260,17 +2285,17 @@ static int iwl_scan_cancel(struct iwl_priv *priv)
 }
 
 /**
- * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
+ * iwl3945_scan_cancel_timeout - Cancel any currently executing HW scan
  * @ms: amount of time to wait (in milliseconds) for scan to abort
  *
  * NOTE: priv->mutex must be held before calling this function
  */
-static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+static int iwl3945_scan_cancel_timeout(struct iwl3945_priv *priv, unsigned long ms)
 {
 	unsigned long now = jiffies;
 	int ret;
 
-	ret = iwl_scan_cancel(priv);
+	ret = iwl3945_scan_cancel(priv);
 	if (ret && ms) {
 		mutex_unlock(&priv->mutex);
 		while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
@@ -2284,7 +2309,7 @@ static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
 	return ret;
 }
 
-static void iwl_sequence_reset(struct iwl_priv *priv)
+static void iwl3945_sequence_reset(struct iwl3945_priv *priv)
 {
 	/* Reset ieee stats */
 
@@ -2295,13 +2320,13 @@ static void iwl_sequence_reset(struct iwl_priv *priv)
 	priv->last_frag_num = -1;
 	priv->last_packet_time = 0;
 
-	iwl_scan_cancel(priv);
+	iwl3945_scan_cancel(priv);
 }
 
 #define MAX_UCODE_BEACON_INTERVAL	1024
 #define INTEL_CONN_LISTEN_INTERVAL	__constant_cpu_to_le16(0xA)
 
-static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
+static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val)
 {
 	u16 new_val = 0;
 	u16 beacon_factor = 0;
@@ -2314,7 +2339,7 @@ static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
 	return cpu_to_le16(new_val);
 }
 
-static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv)
 {
 	u64 interval_tm_unit;
 	u64 tsf, result;
@@ -2344,14 +2369,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
 			priv->rxon_timing.beacon_interval =
 				cpu_to_le16(beacon_int);
 			priv->rxon_timing.beacon_interval =
-			    iwl_adjust_beacon_interval(
+			    iwl3945_adjust_beacon_interval(
 				le16_to_cpu(priv->rxon_timing.beacon_interval));
 		}
 
 		priv->rxon_timing.atim_window = 0;
 	} else {
 		priv->rxon_timing.beacon_interval =
-			iwl_adjust_beacon_interval(conf->beacon_int);
+			iwl3945_adjust_beacon_interval(conf->beacon_int);
 		/* TODO: we need to get atim_window from upper stack
 		 * for now we set to 0 */
 		priv->rxon_timing.atim_window = 0;
@@ -2370,14 +2395,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
 		le16_to_cpu(priv->rxon_timing.atim_window));
 }
 
-static int iwl_scan_initiate(struct iwl_priv *priv)
+static int iwl3945_scan_initiate(struct iwl3945_priv *priv)
 {
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
 		IWL_ERROR("APs don't scan.\n");
 		return 0;
 	}
 
-	if (!iwl_is_ready_rf(priv)) {
+	if (!iwl3945_is_ready_rf(priv)) {
 		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
 		return -EIO;
 	}
@@ -2404,9 +2429,9 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
 	return 0;
 }
 
-static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+static int iwl3945_set_rxon_hwcrypto(struct iwl3945_priv *priv, int hw_decrypt)
 {
-	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+	struct iwl3945_rxon_cmd *rxon = &priv->staging_rxon;
 
 	if (hw_decrypt)
 		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
@@ -2416,7 +2441,7 @@ static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
 	return 0;
 }
 
-static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode)
 {
 	if (phymode == MODE_IEEE80211A) {
 		priv->staging_rxon.flags &=
@@ -2424,7 +2449,7 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
 		      | RXON_FLG_CCK_MSK);
 		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
 	} else {
-		/* Copied from iwl_bg_post_associate() */
+		/* Copied from iwl3945_bg_post_associate() */
 		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
 			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
 		else
@@ -2440,11 +2465,11 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
 }
 
 /*
- * initilize rxon structure with default values fromm eeprom
+ * initialize rxon structure with default values from eeprom
  */
-static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv)
 {
-	const struct iwl_channel_info *ch_info;
+	const struct iwl3945_channel_info *ch_info;
 
 	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
@@ -2481,7 +2506,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
 		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
 #endif
 
-	ch_info = iwl_get_channel_info(priv, priv->phymode,
+	ch_info = iwl3945_get_channel_info(priv, priv->phymode,
 				       le16_to_cpu(priv->staging_rxon.channel));
 
 	if (!ch_info)
@@ -2501,7 +2526,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
 	else
 		priv->phymode = MODE_IEEE80211G;
 
-	iwl_set_flags_for_phymode(priv, priv->phymode);
+	iwl3945_set_flags_for_phymode(priv, priv->phymode);
 
 	priv->staging_rxon.ofdm_basic_rates =
 	    (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
@@ -2509,15 +2534,12 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
 	    (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
 }
 
-static int iwl_set_mode(struct iwl_priv *priv, int mode)
+static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode)
 {
-	if (!iwl_is_ready_rf(priv))
-		return -EAGAIN;
-
 	if (mode == IEEE80211_IF_TYPE_IBSS) {
-		const struct iwl_channel_info *ch_info;
+		const struct iwl3945_channel_info *ch_info;
 
-		ch_info = iwl_get_channel_info(priv,
+		ch_info = iwl3945_get_channel_info(priv,
 			priv->phymode,
 			le16_to_cpu(priv->staging_rxon.channel));
 
@@ -2528,32 +2550,36 @@ static int iwl_set_mode(struct iwl_priv *priv, int mode)
 		}
 	}
 
+	priv->iw_mode = mode;
+
+	iwl3945_connection_init_rx_config(priv);
+	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+	iwl3945_clear_stations_table(priv);
+
+	/* dont commit rxon if rf-kill is on*/
+	if (!iwl3945_is_ready_rf(priv))
+		return -EAGAIN;
+
 	cancel_delayed_work(&priv->scan_check);
-	if (iwl_scan_cancel_timeout(priv, 100)) {
+	if (iwl3945_scan_cancel_timeout(priv, 100)) {
 		IWL_WARNING("Aborted scan still in progress after 100ms\n");
 		IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
 		return -EAGAIN;
 	}
 
-	priv->iw_mode = mode;
-
-	iwl_connection_init_rx_config(priv);
-	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
-
-	iwl_clear_stations_table(priv);
-
-	iwl_commit_rxon(priv);
+	iwl3945_commit_rxon(priv);
 
 	return 0;
 }
 
-static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
+static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv,
 				      struct ieee80211_tx_control *ctl,
-				      struct iwl_cmd *cmd,
+				      struct iwl3945_cmd *cmd,
 				      struct sk_buff *skb_frag,
 				      int last_frag)
 {
-	struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+	struct iwl3945_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
 
 	switch (keyinfo->alg) {
 	case ALG_CCMP:
@@ -2596,8 +2622,8 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
 /*
  * handle build REPLY_TX command notification.
  */
-static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
-				  struct iwl_cmd *cmd,
+static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
+				  struct iwl3945_cmd *cmd,
 				  struct ieee80211_tx_control *ctrl,
 				  struct ieee80211_hdr *hdr,
 				  int is_unicast, u8 std_id)
@@ -2645,11 +2671,9 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
 	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
 		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
 		    (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
-			cmd->cmd.tx.timeout.pm_frame_timeout =
-				cpu_to_le16(3);
+			cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3);
 		else
-			cmd->cmd.tx.timeout.pm_frame_timeout =
-				cpu_to_le16(2);
+			cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2);
 	} else
 		cmd->cmd.tx.timeout.pm_frame_timeout = 0;
 
@@ -2658,41 +2682,44 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
 	cmd->cmd.tx.next_frame_len = 0;
 }
 
-static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+/**
+ * iwl3945_get_sta_id - Find station's index within station table
+ */
+static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr)
 {
 	int sta_id;
 	u16 fc = le16_to_cpu(hdr->frame_control);
 
-	/* If this frame is broadcast or not data then use the broadcast
-	 * station id */
+	/* If this frame is broadcast or management, use broadcast station id */
 	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
 	    is_multicast_ether_addr(hdr->addr1))
 		return priv->hw_setting.bcast_sta_id;
 
 	switch (priv->iw_mode) {
 
-	/* If this frame is part of a BSS network (we're a station), then
-	 * we use the AP's station id */
+	/* If we are a client station in a BSS network, use the special
+	 * AP station entry (that's the only station we communicate with) */
 	case IEEE80211_IF_TYPE_STA:
 		return IWL_AP_ID;
 
 	/* If we are an AP, then find the station, or use BCAST */
 	case IEEE80211_IF_TYPE_AP:
-		sta_id = iwl_hw_find_station(priv, hdr->addr1);
+		sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
 		return priv->hw_setting.bcast_sta_id;
 
-	/* If this frame is part of a IBSS network, then we use the
-	 * target specific station id */
+	/* If this frame is going out to an IBSS network, find the station,
+	 * or create a new station table entry */
 	case IEEE80211_IF_TYPE_IBSS: {
 		DECLARE_MAC_BUF(mac);
 
-		sta_id = iwl_hw_find_station(priv, hdr->addr1);
+		/* Create new station table entry */
+		sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
 
-		sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
+		sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
 
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
@@ -2700,11 +2727,11 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
 		IWL_DEBUG_DROP("Station %s not in station map. "
 			       "Defaulting to broadcast...\n",
 			       print_mac(mac, hdr->addr1));
-		iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+		iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
 		return priv->hw_setting.bcast_sta_id;
 	}
 	default:
-		IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode);
+		IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
 		return priv->hw_setting.bcast_sta_id;
 	}
 }
@@ -2712,18 +2739,18 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
 /*
  * start REPLY_TX command process
  */
-static int iwl_tx_skb(struct iwl_priv *priv,
+static int iwl3945_tx_skb(struct iwl3945_priv *priv,
 		      struct sk_buff *skb, struct ieee80211_tx_control *ctl)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_tfd_frame *tfd;
+	struct iwl3945_tfd_frame *tfd;
 	u32 *control_flags;
 	int txq_id = ctl->queue;
-	struct iwl_tx_queue *txq = NULL;
-	struct iwl_queue *q = NULL;
+	struct iwl3945_tx_queue *txq = NULL;
+	struct iwl3945_queue *q = NULL;
 	dma_addr_t phys_addr;
 	dma_addr_t txcmd_phys;
-	struct iwl_cmd *out_cmd = NULL;
+	struct iwl3945_cmd *out_cmd = NULL;
 	u16 len, idx, len_org;
 	u8 id, hdr_len, unicast;
 	u8 sta_id;
@@ -2735,13 +2762,13 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 	int rc;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if (iwl_is_rfkill(priv)) {
+	if (iwl3945_is_rfkill(priv)) {
 		IWL_DEBUG_DROP("Dropping - RF KILL\n");
 		goto drop_unlock;
 	}
 
-	if (!priv->interface_id) {
-		IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+	if (!priv->vif) {
+		IWL_DEBUG_DROP("Dropping - !priv->vif\n");
 		goto drop_unlock;
 	}
 
@@ -2755,7 +2782,7 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 
 	fc = le16_to_cpu(hdr->frame_control);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL3945_DEBUG
 	if (ieee80211_is_auth(fc))
 		IWL_DEBUG_TX("Sending AUTH frame\n");
 	else if (ieee80211_is_assoc_request(fc))
@@ -2764,16 +2791,19 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 		IWL_DEBUG_TX("Sending REASSOC frame\n");
 #endif
 
-	if (!iwl_is_associated(priv) &&
+	/* drop all data frame if we are not associated */
+	if (!iwl3945_is_associated(priv) && !priv->assoc_id &&
 	    ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
-		IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
+		IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n");
 		goto drop_unlock;
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	hdr_len = ieee80211_get_hdrlen(fc);
-	sta_id = iwl_get_sta_id(priv, hdr);
+
+	/* Find (or create) index into station table for destination station */
+	sta_id = iwl3945_get_sta_id(priv, hdr);
 	if (sta_id == IWL_INVALID_STATION) {
 		DECLARE_MAC_BUF(mac);
 
@@ -2794,32 +2824,54 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 				__constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
 		seq_number += 0x10;
 	}
+
+	/* Descriptor for chosen Tx queue */
 	txq = &priv->txq[txq_id];
 	q = &txq->q;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	tfd = &txq->bd[q->first_empty];
+	/* Set up first empty TFD within this queue's circular TFD buffer */
+	tfd = &txq->bd[q->write_ptr];
 	memset(tfd, 0, sizeof(*tfd));
 	control_flags = (u32 *) tfd;
-	idx = get_cmd_index(q, q->first_empty, 0);
+	idx = get_cmd_index(q, q->write_ptr, 0);
 
-	memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info));
-	txq->txb[q->first_empty].skb[0] = skb;
-	memcpy(&(txq->txb[q->first_empty].status.control),
+	/* Set up driver data for this TFD */
+	memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info));
+	txq->txb[q->write_ptr].skb[0] = skb;
+	memcpy(&(txq->txb[q->write_ptr].status.control),
 	       ctl, sizeof(struct ieee80211_tx_control));
+
+	/* Init first empty entry in queue's array of Tx/cmd buffers */
 	out_cmd = &txq->cmd[idx];
 	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
 	memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+
+	/*
+	 * Set up the Tx-command (not MAC!) header.
+	 * Store the chosen Tx queue and TFD index within the sequence field;
+	 * after Tx, uCode's Tx response will return this value so driver can
+	 * locate the frame within the tx queue and do post-tx processing.
+	 */
 	out_cmd->hdr.cmd = REPLY_TX;
 	out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
-				INDEX_TO_SEQ(q->first_empty)));
-	/* copy frags header */
+				INDEX_TO_SEQ(q->write_ptr)));
+
+	/* Copy MAC header from skb into command buffer */
 	memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
 
-	/* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */
+	/*
+	 * Use the first empty entry in this queue's command buffer array
+	 * to contain the Tx command and MAC header concatenated together
+	 * (payload data will be in another buffer).
+	 * Size of this varies, due to varying MAC header length.
+	 * If end is not dword aligned, we'll have 2 extra bytes at the end
+	 * of the MAC header (device reads on dword boundaries).
+	 * We'll tell device about this padding later.
+	 */
 	len = priv->hw_setting.tx_cmd_len +
-		sizeof(struct iwl_cmd_header) + hdr_len;
+		sizeof(struct iwl3945_cmd_header) + hdr_len;
 
 	len_org = len;
 	len = (len + 3) & ~3;
@@ -2829,37 +2881,45 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 	else
 		len_org = 0;
 
-	txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
-		     offsetof(struct iwl_cmd, hdr);
+	/* Physical address of this Tx command's header (not MAC header!),
+	 * within command buffer array. */
+	txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl3945_cmd) * idx +
+		     offsetof(struct iwl3945_cmd, hdr);
 
-	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+	/* Add buffer containing Tx command and MAC(!) header to TFD's
+	 * first entry */
+	iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
 
 	if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
-		iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+		iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
 
-	/* 802.11 null functions have no payload... */
+	/* Set up TFD's 2nd entry to point directly to remainder of skb,
+	 * if any (802.11 null frames have no payload). */
 	len = skb->len - hdr_len;
 	if (len) {
 		phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
 					   len, PCI_DMA_TODEVICE);
-		iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+		iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
 	}
 
-	/* If there is no payload, then only one TFD is used */
 	if (!len)
+		/* If there is no payload, then we use only one Tx buffer */
 		*control_flags = TFD_CTL_COUNT_SET(1);
 	else
+		/* Else use 2 buffers.
+		 * Tell 3945 about any padding after MAC header */
 		*control_flags = TFD_CTL_COUNT_SET(2) |
 			TFD_CTL_PAD_SET(U32_PAD(len));
 
+	/* Total # bytes to be transmitted */
 	len = (u16)skb->len;
 	out_cmd->cmd.tx.len = cpu_to_le16(len);
 
 	/* TODO need this for burst mode later on */
-	iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+	iwl3945_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
 
 	/* set is_hcca to 0; it probably will never be implemented */
-	iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+	iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
 
 	out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
 	out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
@@ -2875,25 +2935,26 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 		txq->need_update = 0;
 	}
 
-	iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+	iwl3945_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
 			   sizeof(out_cmd->cmd.tx));
 
-	iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
+	iwl3945_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
 			   ieee80211_get_hdrlen(fc));
 
-	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
-	rc = iwl_tx_queue_update_write_ptr(priv, txq);
+	/* Tell device the write index *just past* this latest filled TFD */
+	q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd);
+	rc = iwl3945_tx_queue_update_write_ptr(priv, txq);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	if (rc)
 		return rc;
 
-	if ((iwl_queue_space(q) < q->high_mark)
+	if ((iwl3945_queue_space(q) < q->high_mark)
 	    && priv->mac80211_registered) {
 		if (wait_write_ptr) {
 			spin_lock_irqsave(&priv->lock, flags);
 			txq->need_update = 1;
-			iwl_tx_queue_update_write_ptr(priv, txq);
+			iwl3945_tx_queue_update_write_ptr(priv, txq);
 			spin_unlock_irqrestore(&priv->lock, flags);
 		}
 
@@ -2908,13 +2969,13 @@ drop:
 	return -1;
 }
 
-static void iwl_set_rate(struct iwl_priv *priv)
+static void iwl3945_set_rate(struct iwl3945_priv *priv)
 {
 	const struct ieee80211_hw_mode *hw = NULL;
 	struct ieee80211_rate *rate;
 	int i;
 
-	hw = iwl_get_hw_mode(priv, priv->phymode);
+	hw = iwl3945_get_hw_mode(priv, priv->phymode);
 	if (!hw) {
 		IWL_ERROR("Failed to set rate: unable to get hw mode\n");
 		return;
@@ -2932,7 +2993,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
 		if ((rate->val < IWL_RATE_COUNT) &&
 		    (rate->flags & IEEE80211_RATE_SUPPORTED)) {
 			IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
-				       rate->val, iwl_rates[rate->val].plcp,
+				       rate->val, iwl3945_rates[rate->val].plcp,
 				       (rate->flags & IEEE80211_RATE_BASIC) ?
 				       "*" : "");
 			priv->active_rate |= (1 << rate->val);
@@ -2940,7 +3001,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
 				priv->active_rate_basic |= (1 << rate->val);
 		} else
 			IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
-				       rate->val, iwl_rates[rate->val].plcp);
+				       rate->val, iwl3945_rates[rate->val].plcp);
 	}
 
 	IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
@@ -2969,7 +3030,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
 		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
 }
 
-static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+static void iwl3945_radio_kill_sw(struct iwl3945_priv *priv, int disable_radio)
 {
 	unsigned long flags;
 
@@ -2980,21 +3041,21 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
 			  disable_radio ? "OFF" : "ON");
 
 	if (disable_radio) {
-		iwl_scan_cancel(priv);
+		iwl3945_scan_cancel(priv);
 		/* FIXME: This is a workaround for AP */
 		if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
 			spin_lock_irqsave(&priv->lock, flags);
-			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+			iwl3945_write32(priv, CSR_UCODE_DRV_GP1_SET,
 				    CSR_UCODE_SW_BIT_RFKILL);
 			spin_unlock_irqrestore(&priv->lock, flags);
-			iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+			iwl3945_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
 			set_bit(STATUS_RF_KILL_SW, &priv->status);
 		}
 		return;
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
 	clear_bit(STATUS_RF_KILL_SW, &priv->status);
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -3003,9 +3064,9 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
 	msleep(10);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_read32(priv, CSR_UCODE_DRV_GP1);
-	if (!iwl_grab_restricted_access(priv))
-		iwl_release_restricted_access(priv);
+	iwl3945_read32(priv, CSR_UCODE_DRV_GP1);
+	if (!iwl3945_grab_nic_access(priv))
+		iwl3945_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
@@ -3018,7 +3079,7 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
 	return;
 }
 
-void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb,
 			    u32 decrypt_res, struct ieee80211_rx_status *stats)
 {
 	u16 fc =
@@ -3050,97 +3111,9 @@ void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
 	}
 }
 
-void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb,
-				    void *data, short len,
-				    struct ieee80211_rx_status *stats,
-				    u16 phy_flags)
-{
-	struct iwl_rt_rx_hdr *iwl_rt;
-
-	/* First cache any information we need before we overwrite
-	 * the information provided in the skb from the hardware */
-	s8 signal = stats->ssi;
-	s8 noise = 0;
-	int rate = stats->rate;
-	u64 tsf = stats->mactime;
-	__le16 phy_flags_hw = cpu_to_le16(phy_flags);
-
-	/* We received data from the HW, so stop the watchdog */
-	if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) {
-		IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
-		return;
-	}
-
-	/* copy the frame data to write after where the radiotap header goes */
-	iwl_rt = (void *)rxb->skb->data;
-	memmove(iwl_rt->payload, data, len);
-
-	iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
-	iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */
-
-	/* total header + data */
-	iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt));
-
-	/* Set the size of the skb to the size of the frame */
-	skb_put(rxb->skb, sizeof(*iwl_rt) + len);
-
-	/* Big bitfield of all the fields we provide in radiotap */
-	iwl_rt->rt_hdr.it_present =
-	    cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
-			(1 << IEEE80211_RADIOTAP_FLAGS) |
-			(1 << IEEE80211_RADIOTAP_RATE) |
-			(1 << IEEE80211_RADIOTAP_CHANNEL) |
-			(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
-			(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
-			(1 << IEEE80211_RADIOTAP_ANTENNA));
-
-	/* Zero the flags, we'll add to them as we go */
-	iwl_rt->rt_flags = 0;
-
-	iwl_rt->rt_tsf = cpu_to_le64(tsf);
-
-	/* Convert to dBm */
-	iwl_rt->rt_dbmsignal = signal;
-	iwl_rt->rt_dbmnoise = noise;
-
-	/* Convert the channel frequency and set the flags */
-	iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq);
-	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
-		iwl_rt->rt_chbitmask =
-		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
-	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
-		iwl_rt->rt_chbitmask =
-		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
-	else	/* 802.11g */
-		iwl_rt->rt_chbitmask =
-		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
-
-	rate = iwl_rate_index_from_plcp(rate);
-	if (rate == -1)
-		iwl_rt->rt_rate = 0;
-	else
-		iwl_rt->rt_rate = iwl_rates[rate].ieee;
-
-	/* antenna number */
-	iwl_rt->rt_antenna =
-		le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
-
-	/* set the preamble flag if we have it */
-	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-		iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
-	IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
-	stats->flag |= RX_FLAG_RADIOTAP;
-	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
-	rxb->skb = NULL;
-}
-
-
 #define IWL_PACKET_RETRY_TIME HZ
 
-int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
 {
 	u16 sc = le16_to_cpu(header->seq_ctrl);
 	u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
@@ -3151,29 +3124,26 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
 	switch (priv->iw_mode) {
 	case IEEE80211_IF_TYPE_IBSS:{
 		struct list_head *p;
-		struct iwl_ibss_seq *entry = NULL;
+		struct iwl3945_ibss_seq *entry = NULL;
 		u8 *mac = header->addr2;
 		int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
 
 		__list_for_each(p, &priv->ibss_mac_hash[index]) {
-			entry =
-				list_entry(p, struct iwl_ibss_seq, list);
+			entry = list_entry(p, struct iwl3945_ibss_seq, list);
 			if (!compare_ether_addr(entry->mac, mac))
 				break;
 		}
 		if (p == &priv->ibss_mac_hash[index]) {
 			entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 			if (!entry) {
-				IWL_ERROR
-					("Cannot malloc new mac entry\n");
+				IWL_ERROR("Cannot malloc new mac entry\n");
 				return 0;
 			}
 			memcpy(entry->mac, mac, ETH_ALEN);
 			entry->seq_num = seq;
 			entry->frag_num = frag;
 			entry->packet_time = jiffies;
-			list_add(&entry->list,
-				 &priv->ibss_mac_hash[index]);
+			list_add(&entry->list, &priv->ibss_mac_hash[index]);
 			return 0;
 		}
 		last_seq = &entry->seq_num;
@@ -3207,7 +3177,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
 	return 1;
 }
 
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
 
 #include "iwl-spectrum.h"
 
@@ -3222,7 +3192,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
  * the lower 3 bytes is the time in usec within one beacon interval
  */
 
-static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+static u32 iwl3945_usecs_to_beacons(u32 usec, u32 beacon_interval)
 {
 	u32 quot;
 	u32 rem;
@@ -3241,7 +3211,7 @@ static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
  * the same as HW timer counter counting down
  */
 
-static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+static __le32 iwl3945_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
 {
 	u32 base_low = base & BEACON_TIME_MASK_LOW;
 	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
@@ -3260,13 +3230,13 @@ static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
 	return cpu_to_le32(res);
 }
 
-static int iwl_get_measurement(struct iwl_priv *priv,
+static int iwl3945_get_measurement(struct iwl3945_priv *priv,
 			       struct ieee80211_measurement_params *params,
 			       u8 type)
 {
-	struct iwl_spectrum_cmd spectrum;
-	struct iwl_rx_packet *res;
-	struct iwl_host_cmd cmd = {
+	struct iwl3945_spectrum_cmd spectrum;
+	struct iwl3945_rx_packet *res;
+	struct iwl3945_host_cmd cmd = {
 		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
 		.data = (void *)&spectrum,
 		.meta.flags = CMD_WANT_SKB,
@@ -3276,9 +3246,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
 	int spectrum_resp_status;
 	int duration = le16_to_cpu(params->duration);
 
-	if (iwl_is_associated(priv))
+	if (iwl3945_is_associated(priv))
 		add_time =
-		    iwl_usecs_to_beacons(
+		    iwl3945_usecs_to_beacons(
 			le64_to_cpu(params->start_time) - priv->last_tsf,
 			le16_to_cpu(priv->rxon_timing.beacon_interval));
 
@@ -3291,9 +3261,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
 	cmd.len = sizeof(spectrum);
 	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
 
-	if (iwl_is_associated(priv))
+	if (iwl3945_is_associated(priv))
 		spectrum.start_time =
-		    iwl_add_beacon_time(priv->last_beacon_time,
+		    iwl3945_add_beacon_time(priv->last_beacon_time,
 				add_time,
 				le16_to_cpu(priv->rxon_timing.beacon_interval));
 	else
@@ -3306,11 +3276,11 @@ static int iwl_get_measurement(struct iwl_priv *priv,
 		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
 		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
 
-	rc = iwl_send_cmd_sync(priv, &cmd);
+	rc = iwl3945_send_cmd_sync(priv, &cmd);
 	if (rc)
 		return rc;
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
 		rc = -EIO;
@@ -3320,9 +3290,8 @@ static int iwl_get_measurement(struct iwl_priv *priv,
 	switch (spectrum_resp_status) {
 	case 0:		/* Command will be handled */
 		if (res->u.spectrum.id != 0xff) {
-			IWL_DEBUG_INFO
-			    ("Replaced existing measurement: %d\n",
-			     res->u.spectrum.id);
+			IWL_DEBUG_INFO("Replaced existing measurement: %d\n",
+						res->u.spectrum.id);
 			priv->measurement_status &= ~MEASUREMENT_READY;
 		}
 		priv->measurement_status |= MEASUREMENT_ACTIVE;
@@ -3340,8 +3309,8 @@ static int iwl_get_measurement(struct iwl_priv *priv,
 }
 #endif
 
-static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
-				 struct iwl_tx_info *tx_sta)
+static void iwl3945_txstatus_to_ieee(struct iwl3945_priv *priv,
+				 struct iwl3945_tx_info *tx_sta)
 {
 
 	tx_sta->status.ack_signal = 0;
@@ -3360,41 +3329,41 @@ static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
 }
 
 /**
- * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
+ * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
  *
- * When FW advances 'R' index, all entries between old and
- * new 'R' index need to be reclaimed. As result, some free space
- * forms. If there is enough free space (> low mark), wake Tx queue.
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms. If there is
+ * enough free space (> low mark), wake the stack that feeds us.
  */
-int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+static int iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, int txq_id, int index)
 {
-	struct iwl_tx_queue *txq = &priv->txq[txq_id];
-	struct iwl_queue *q = &txq->q;
+	struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
+	struct iwl3945_queue *q = &txq->q;
 	int nfreed = 0;
 
 	if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
 		IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
 			  "is out of range [0-%d] %d %d.\n", txq_id,
-			  index, q->n_bd, q->first_empty, q->last_used);
+			  index, q->n_bd, q->write_ptr, q->read_ptr);
 		return 0;
 	}
 
-	for (index = iwl_queue_inc_wrap(index, q->n_bd);
-		q->last_used != index;
-		q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) {
+	for (index = iwl3945_queue_inc_wrap(index, q->n_bd);
+		q->read_ptr != index;
+		q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 		if (txq_id != IWL_CMD_QUEUE_NUM) {
-			iwl_txstatus_to_ieee(priv,
-					&(txq->txb[txq->q.last_used]));
-			iwl_hw_txq_free_tfd(priv, txq);
+			iwl3945_txstatus_to_ieee(priv,
+					&(txq->txb[txq->q.read_ptr]));
+			iwl3945_hw_txq_free_tfd(priv, txq);
 		} else if (nfreed > 1) {
 			IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
-					q->first_empty, q->last_used);
+					q->write_ptr, q->read_ptr);
 			queue_work(priv->workqueue, &priv->restart);
 		}
 		nfreed++;
 	}
 
-	if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+	if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) &&
 			(txq_id != IWL_CMD_QUEUE_NUM) &&
 			priv->mac80211_registered)
 		ieee80211_wake_queue(priv->hw, txq_id);
@@ -3403,7 +3372,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
 	return nfreed;
 }
 
-static int iwl_is_tx_success(u32 status)
+static int iwl3945_is_tx_success(u32 status)
 {
 	return (status & 0xFF) == 0x1;
 }
@@ -3413,27 +3382,30 @@ static int iwl_is_tx_success(u32 status)
  * Generic RX handler implementations
  *
  ******************************************************************************/
-static void iwl_rx_reply_tx(struct iwl_priv *priv,
-			    struct iwl_rx_mem_buffer *rxb)
+/**
+ * iwl3945_rx_reply_tx - Handle Tx response
+ */
+static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv,
+			    struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
 	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
 	int txq_id = SEQ_TO_QUEUE(sequence);
 	int index = SEQ_TO_INDEX(sequence);
-	struct iwl_tx_queue *txq = &priv->txq[txq_id];
+	struct iwl3945_tx_queue *txq = &priv->txq[txq_id];
 	struct ieee80211_tx_status *tx_status;
-	struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+	struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
 	u32  status = le32_to_cpu(tx_resp->status);
 
 	if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
 		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
 			  "is out of range [0-%d] %d %d\n", txq_id,
-			  index, txq->q.n_bd, txq->q.first_empty,
-			  txq->q.last_used);
+			  index, txq->q.n_bd, txq->q.write_ptr,
+			  txq->q.read_ptr);
 		return;
 	}
 
-	tx_status = &(txq->txb[txq->q.last_used].status);
+	tx_status = &(txq->txb[txq->q.read_ptr].status);
 
 	tx_status->retry_count = tx_resp->failure_frame;
 	tx_status->queue_number = status;
@@ -3441,28 +3413,28 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
 	tx_status->queue_length |= tx_resp->failure_rts;
 
 	tx_status->flags =
-	    iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
+	    iwl3945_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
 
-	tx_status->control.tx_rate = iwl_rate_index_from_plcp(tx_resp->rate);
+	tx_status->control.tx_rate = iwl3945_rate_index_from_plcp(tx_resp->rate);
 
 	IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
-			txq_id, iwl_get_tx_fail_reason(status), status,
+			txq_id, iwl3945_get_tx_fail_reason(status), status,
 			tx_resp->rate, tx_resp->failure_frame);
 
 	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
 	if (index != -1)
-		iwl_tx_queue_reclaim(priv, txq_id, index);
+		iwl3945_tx_queue_reclaim(priv, txq_id, index);
 
 	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
 		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
 }
 
 
-static void iwl_rx_reply_alive(struct iwl_priv *priv,
-			       struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_reply_alive(struct iwl3945_priv *priv,
+			       struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_alive_resp *palive;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_alive_resp *palive;
 	struct delayed_work *pwork;
 
 	palive = &pkt->u.alive_frame;
@@ -3476,14 +3448,14 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
 		IWL_DEBUG_INFO("Initialization Alive received.\n");
 		memcpy(&priv->card_alive_init,
 		       &pkt->u.alive_frame,
-		       sizeof(struct iwl_init_alive_resp));
+		       sizeof(struct iwl3945_init_alive_resp));
 		pwork = &priv->init_alive_start;
 	} else {
 		IWL_DEBUG_INFO("Runtime Alive received.\n");
 		memcpy(&priv->card_alive, &pkt->u.alive_frame,
-		       sizeof(struct iwl_alive_resp));
+		       sizeof(struct iwl3945_alive_resp));
 		pwork = &priv->alive_start;
-		iwl_disable_events(priv);
+		iwl3945_disable_events(priv);
 	}
 
 	/* We delay the ALIVE response by 5ms to
@@ -3495,19 +3467,19 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
 		IWL_WARNING("uCode did not respond OK.\n");
 }
 
-static void iwl_rx_reply_add_sta(struct iwl_priv *priv,
-				 struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_reply_add_sta(struct iwl3945_priv *priv,
+				 struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
 
 	IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
 	return;
 }
 
-static void iwl_rx_reply_error(struct iwl_priv *priv,
-			       struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_reply_error(struct iwl3945_priv *priv,
+			       struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
 
 	IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
 		"seq 0x%04X ser 0x%08X\n",
@@ -3520,23 +3492,23 @@ static void iwl_rx_reply_error(struct iwl_priv *priv,
 
 #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
 
-static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_csa(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
-	struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rxon_cmd *rxon = (void *)&priv->active_rxon;
+	struct iwl3945_csa_notification *csa = &(pkt->u.csa_notif);
 	IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
 		      le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
 	rxon->channel = csa->channel;
 	priv->staging_rxon.channel = csa->channel;
 }
 
-static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
-					  struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_spectrum_measure_notif(struct iwl3945_priv *priv,
+					  struct iwl3945_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_spectrum_notification *report = &(pkt->u.spectrum_notif);
 
 	if (!report->state) {
 		IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
@@ -3549,35 +3521,35 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
 #endif
 }
 
-static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
-				  struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_pm_sleep_notif(struct iwl3945_priv *priv,
+				  struct iwl3945_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+#ifdef CONFIG_IWL3945_DEBUG
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_sleep_notification *sleep = &(pkt->u.sleep_notif);
 	IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
 		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
 #endif
 }
 
-static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-					     struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_pm_debug_statistics_notif(struct iwl3945_priv *priv,
+					     struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
 	IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
 			"notification for %s:\n",
 			le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
-	iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+	iwl3945_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
 }
 
-static void iwl_bg_beacon_update(struct work_struct *work)
+static void iwl3945_bg_beacon_update(struct work_struct *work)
 {
-	struct iwl_priv *priv =
-		container_of(work, struct iwl_priv, beacon_update);
+	struct iwl3945_priv *priv =
+		container_of(work, struct iwl3945_priv, beacon_update);
 	struct sk_buff *beacon;
 
 	/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-	beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+	beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL);
 
 	if (!beacon) {
 		IWL_ERROR("update beacon failed\n");
@@ -3592,15 +3564,15 @@ static void iwl_bg_beacon_update(struct work_struct *work)
 	priv->ibss_beacon = beacon;
 	mutex_unlock(&priv->mutex);
 
-	iwl_send_beacon_cmd(priv);
+	iwl3945_send_beacon_cmd(priv);
 }
 
-static void iwl_rx_beacon_notif(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_beacon_notif(struct iwl3945_priv *priv,
+				struct iwl3945_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status);
+#ifdef CONFIG_IWL3945_DEBUG
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status);
 	u8 rate = beacon->beacon_notify_hdr.rate;
 
 	IWL_DEBUG_RX("beacon status %x retries %d iss %d "
@@ -3618,25 +3590,25 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
 }
 
 /* Service response to REPLY_SCAN_CMD (0x80) */
-static void iwl_rx_reply_scan(struct iwl_priv *priv,
-			      struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_reply_scan(struct iwl3945_priv *priv,
+			      struct iwl3945_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scanreq_notification *notif =
-	    (struct iwl_scanreq_notification *)pkt->u.raw;
+#ifdef CONFIG_IWL3945_DEBUG
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_scanreq_notification *notif =
+	    (struct iwl3945_scanreq_notification *)pkt->u.raw;
 
 	IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
 #endif
 }
 
 /* Service SCAN_START_NOTIFICATION (0x82) */
-static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_scan_start_notif(struct iwl3945_priv *priv,
+				    struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scanstart_notification *notif =
-	    (struct iwl_scanstart_notification *)pkt->u.raw;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_scanstart_notification *notif =
+	    (struct iwl3945_scanstart_notification *)pkt->u.raw;
 	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
 	IWL_DEBUG_SCAN("Scan start: "
 		       "%d [802.11%s] "
@@ -3648,12 +3620,12 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
 }
 
 /* Service SCAN_RESULTS_NOTIFICATION (0x83) */
-static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
-				      struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_scan_results_notif(struct iwl3945_priv *priv,
+				      struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scanresults_notification *notif =
-	    (struct iwl_scanresults_notification *)pkt->u.raw;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_scanresults_notification *notif =
+	    (struct iwl3945_scanresults_notification *)pkt->u.raw;
 
 	IWL_DEBUG_SCAN("Scan ch.res: "
 		       "%d [802.11%s] "
@@ -3669,14 +3641,15 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
 					(priv->last_scan_jiffies, jiffies)));
 
 	priv->last_scan_jiffies = jiffies;
+	priv->next_scan_jiffies = 0;
 }
 
 /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
-static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
-				       struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_scan_complete_notif(struct iwl3945_priv *priv,
+				       struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
 
 	IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
 		       scan_notif->scanned_channels,
@@ -3711,6 +3684,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
 	}
 
 	priv->last_scan_jiffies = jiffies;
+	priv->next_scan_jiffies = 0;
 	IWL_DEBUG_INFO("Setting scan to off\n");
 
 	clear_bit(STATUS_SCANNING, &priv->status);
@@ -3729,10 +3703,10 @@ reschedule:
 
 /* Handle notification from uCode that card's power state is changing
  * due to software, hardware, or critical temperature RFKILL */
-static void iwl_rx_card_state_notif(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_rx_card_state_notif(struct iwl3945_priv *priv,
+				    struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data;
 	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
 	unsigned long status = priv->status;
 
@@ -3740,7 +3714,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
 			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
 			  (flags & SW_CARD_DISABLED) ? "Kill" : "On");
 
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_SET,
 		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 
 	if (flags & HW_CARD_DISABLED)
@@ -3754,7 +3728,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
 	else
 		clear_bit(STATUS_RF_KILL_SW, &priv->status);
 
-	iwl_scan_cancel(priv);
+	iwl3945_scan_cancel(priv);
 
 	if ((test_bit(STATUS_RF_KILL_HW, &status) !=
 	     test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
@@ -3766,7 +3740,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
 }
 
 /**
- * iwl_setup_rx_handlers - Initialize Rx handler callbacks
+ * iwl3945_setup_rx_handlers - Initialize Rx handler callbacks
  *
  * Setup the RX handlers for each of the reply types sent from the uCode
  * to the host.
@@ -3774,61 +3748,58 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
  * This function chains into the hardware specific files for them to setup
  * any hardware specific handlers as well.
  */
-static void iwl_setup_rx_handlers(struct iwl_priv *priv)
+static void iwl3945_setup_rx_handlers(struct iwl3945_priv *priv)
 {
-	priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
-	priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta;
-	priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
-	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+	priv->rx_handlers[REPLY_ALIVE] = iwl3945_rx_reply_alive;
+	priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta;
+	priv->rx_handlers[REPLY_ERROR] = iwl3945_rx_reply_error;
+	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl3945_rx_csa;
 	priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
-	    iwl_rx_spectrum_measure_notif;
-	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
+	    iwl3945_rx_spectrum_measure_notif;
+	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl3945_rx_pm_sleep_notif;
 	priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
-	    iwl_rx_pm_debug_statistics_notif;
-	priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
-
-	/* NOTE:  iwl_rx_statistics is different based on whether
-	 * the build is for the 3945 or the 4965.  See the
-	 * corresponding implementation in iwl-XXXX.c
-	 *
-	 * The same handler is used for both the REPLY to a
-	 * discrete statistics request from the host as well as
-	 * for the periodic statistics notification from the uCode
+	    iwl3945_rx_pm_debug_statistics_notif;
+	priv->rx_handlers[BEACON_NOTIFICATION] = iwl3945_rx_beacon_notif;
+
+	/*
+	 * The same handler is used for both the REPLY to a discrete
+	 * statistics request from the host as well as for the periodic
+	 * statistics notifications (after received beacons) from the uCode.
 	 */
-	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics;
-	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics;
+	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics;
+	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics;
 
-	priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
-	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
+	priv->rx_handlers[REPLY_SCAN_CMD] = iwl3945_rx_reply_scan;
+	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl3945_rx_scan_start_notif;
 	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
-	    iwl_rx_scan_results_notif;
+	    iwl3945_rx_scan_results_notif;
 	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
-	    iwl_rx_scan_complete_notif;
-	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
-	priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx;
+	    iwl3945_rx_scan_complete_notif;
+	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif;
+	priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx;
 
-	/* Setup hardware specific Rx handlers */
-	iwl_hw_rx_handler_setup(priv);
+	/* Set up hardware specific Rx handlers */
+	iwl3945_hw_rx_handler_setup(priv);
 }
 
 /**
- * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
  * @rxb: Rx buffer to reclaim
  *
  * If an Rx buffer has an async callback associated with it the callback
  * will be executed.  The attached skb (if present) will only be freed
  * if the callback returns 1
  */
-static void iwl_tx_cmd_complete(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
+static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv,
+				struct iwl3945_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+	struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
 	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
 	int txq_id = SEQ_TO_QUEUE(sequence);
 	int index = SEQ_TO_INDEX(sequence);
 	int huge = sequence & SEQ_HUGE_FRAME;
 	int cmd_index;
-	struct iwl_cmd *cmd;
+	struct iwl3945_cmd *cmd;
 
 	/* If a Tx command is being handled and it isn't in the actual
 	 * command queue then there a command routing bug has been introduced
@@ -3849,7 +3820,7 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
 		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
 		rxb->skb = NULL;
 
-	iwl_tx_queue_reclaim(priv, txq_id, index);
+	iwl3945_tx_queue_reclaim(priv, txq_id, index);
 
 	if (!(cmd->meta.flags & CMD_ASYNC)) {
 		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
@@ -3879,10 +3850,10 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
  * The queue is empty (no good data) if WRITE = READ - 1, and is full if
  * WRITE = READ.
  *
- * During initialization the host sets up the READ queue position to the first
+ * During initialization, the host sets up the READ queue position to the first
  * INDEX position, and WRITE to the last (READ - 1 wrapped)
  *
- * When the firmware places a packet in a buffer it will advance the READ index
+ * When the firmware places a packet in a buffer, it will advance the READ index
  * and fire the RX interrupt.  The driver can then query the READ index and
  * process as many packets as possible, moving the WRITE index forward as it
  * resets the Rx queue buffers with new memory.
@@ -3890,8 +3861,8 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
  * The management in the driver is as follows:
  * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
  *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- *   to replensish the iwl->rxq->rx_free.
- * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   to replenish the iwl->rxq->rx_free.
+ * + In iwl3945_rx_replenish (scheduled) if 'processed' != 'read' then the
  *   iwl->rxq is replenished and the READ INDEX is updated (updating the
  *   'processed' and 'read' driver indexes as well)
  * + A received packet is processed and handed to the kernel network stack,
@@ -3904,28 +3875,28 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
  *
  * Driver sequence:
  *
- * iwl_rx_queue_alloc()       Allocates rx_free
- * iwl_rx_replenish()         Replenishes rx_free list from rx_used, and calls
- *                            iwl_rx_queue_restock
- * iwl_rx_queue_restock()     Moves available buffers from rx_free into Rx
+ * iwl3945_rx_queue_alloc()   Allocates rx_free
+ * iwl3945_rx_replenish()     Replenishes rx_free list from rx_used, and calls
+ *                            iwl3945_rx_queue_restock
+ * iwl3945_rx_queue_restock() Moves available buffers from rx_free into Rx
  *                            queue, updates firmware pointers, and updates
  *                            the WRITE index.  If insufficient rx_free buffers
- *                            are available, schedules iwl_rx_replenish
+ *                            are available, schedules iwl3945_rx_replenish
  *
  * -- enable interrupts --
- * ISR - iwl_rx()             Detach iwl_rx_mem_buffers from pool up to the
+ * ISR - iwl3945_rx()         Detach iwl3945_rx_mem_buffers from pool up to the
  *                            READ INDEX, detaching the SKB from the pool.
  *                            Moves the packet buffer from queue to rx_used.
- *                            Calls iwl_rx_queue_restock to refill any empty
+ *                            Calls iwl3945_rx_queue_restock to refill any empty
  *                            slots.
  * ...
  *
  */
 
 /**
- * iwl_rx_queue_space - Return number of free slots available in queue.
+ * iwl3945_rx_queue_space - Return number of free slots available in queue.
  */
-static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+static int iwl3945_rx_queue_space(const struct iwl3945_rx_queue *q)
 {
 	int s = q->read - q->write;
 	if (s <= 0)
@@ -3938,15 +3909,9 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
 }
 
 /**
- * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
- *
- * NOTE: This function has 3945 and 4965 specific code sections
- * but is declared in base due to the majority of the
- * implementation being the same (only a numeric constant is
- * different)
- *
+ * iwl3945_rx_queue_update_write_ptr - Update the write pointer for the RX queue
  */
-int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_rx_queue *q)
 {
 	u32 reg = 0;
 	int rc = 0;
@@ -3957,24 +3922,29 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
 	if (q->need_update == 0)
 		goto exit_unlock;
 
+	/* If power-saving is in use, make sure device is awake */
 	if (test_bit(STATUS_POWER_PMI, &priv->status)) {
-		reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+		reg = iwl3945_read32(priv, CSR_UCODE_DRV_GP1);
 
 		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-			iwl_set_bit(priv, CSR_GP_CNTRL,
+			iwl3945_set_bit(priv, CSR_GP_CNTRL,
 				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 			goto exit_unlock;
 		}
 
-		rc = iwl_grab_restricted_access(priv);
+		rc = iwl3945_grab_nic_access(priv);
 		if (rc)
 			goto exit_unlock;
 
-		iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR,
+		/* Device expects a multiple of 8 */
+		iwl3945_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
 				     q->write & ~0x7);
-		iwl_release_restricted_access(priv);
+		iwl3945_release_nic_access(priv);
+
+	/* Else device is assumed to be awake */
 	} else
-		iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+		/* Device expects a multiple of 8 */
+		iwl3945_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
 
 
 	q->need_update = 0;
@@ -3985,42 +3955,43 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
 }
 
 /**
- * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer.
- *
- * NOTE: This function has 3945 and 4965 specific code paths in it.
+ * iwl3945_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
  */
-static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl3945_priv *priv,
 					  dma_addr_t dma_addr)
 {
 	return cpu_to_le32((u32)dma_addr);
 }
 
 /**
- * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+ * iwl3945_rx_queue_restock - refill RX queue from pre-allocated pool
  *
- * If there are slots in the RX queue that  need to be restocked,
+ * If there are slots in the RX queue that need to be restocked,
  * and we have free pre-allocated buffers, fill the ranks as much
- * as we can pulling from rx_free.
+ * as we can, pulling from rx_free.
  *
  * This moves the 'write' index forward to catch up with 'processed', and
  * also updates the memory address in the firmware to reference the new
  * target buffer.
  */
-int iwl_rx_queue_restock(struct iwl_priv *priv)
+static int iwl3945_rx_queue_restock(struct iwl3945_priv *priv)
 {
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl3945_rx_queue *rxq = &priv->rxq;
 	struct list_head *element;
-	struct iwl_rx_mem_buffer *rxb;
+	struct iwl3945_rx_mem_buffer *rxb;
 	unsigned long flags;
 	int write, rc;
 
 	spin_lock_irqsave(&rxq->lock, flags);
 	write = rxq->write & ~0x7;
-	while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+	while ((iwl3945_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+		/* Get next free Rx buffer, remove from free list */
 		element = rxq->rx_free.next;
-		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		rxb = list_entry(element, struct iwl3945_rx_mem_buffer, list);
 		list_del(element);
-		rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+
+		/* Point to Rx buffer via next RBD in circular buffer */
+		rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->dma_addr);
 		rxq->queue[rxq->write] = rxb;
 		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
 		rxq->free_count--;
@@ -4032,13 +4003,14 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
 		queue_work(priv->workqueue, &priv->rx_replenish);
 
 
-	/* If we've added more space for the firmware to place data, tell it */
+	/* If we've added more space for the firmware to place data, tell it.
+	 * Increment device's write pointer in multiples of 8. */
 	if ((write != (rxq->write & ~0x7))
 	    || (abs(rxq->write - rxq->read) > 7)) {
 		spin_lock_irqsave(&rxq->lock, flags);
 		rxq->need_update = 1;
 		spin_unlock_irqrestore(&rxq->lock, flags);
-		rc = iwl_rx_queue_update_write_ptr(priv, rxq);
+		rc = iwl3945_rx_queue_update_write_ptr(priv, rxq);
 		if (rc)
 			return rc;
 	}
@@ -4047,24 +4019,25 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
 }
 
 /**
- * iwl_rx_replensih - Move all used packet from rx_used to rx_free
+ * iwl3945_rx_replenish - Move all used packet from rx_used to rx_free
  *
  * When moving to rx_free an SKB is allocated for the slot.
  *
- * Also restock the Rx queue via iwl_rx_queue_restock.
- * This is called as a scheduled work item (except for during intialization)
+ * Also restock the Rx queue via iwl3945_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
  */
-void iwl_rx_replenish(void *data)
+static void iwl3945_rx_allocate(struct iwl3945_priv *priv)
 {
-	struct iwl_priv *priv = data;
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl3945_rx_queue *rxq = &priv->rxq;
 	struct list_head *element;
-	struct iwl_rx_mem_buffer *rxb;
+	struct iwl3945_rx_mem_buffer *rxb;
 	unsigned long flags;
 	spin_lock_irqsave(&rxq->lock, flags);
 	while (!list_empty(&rxq->rx_used)) {
 		element = rxq->rx_used.next;
-		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		rxb = list_entry(element, struct iwl3945_rx_mem_buffer, list);
+
+		/* Alloc a new receive buffer */
 		rxb->skb =
 		    alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
 		if (!rxb->skb) {
@@ -4076,8 +4049,19 @@ void iwl_rx_replenish(void *data)
 			 * more buffers it will schedule replenish */
 			break;
 		}
+
+		/* If radiotap head is required, reserve some headroom here.
+		 * The physical head count is a variable rx_stats->phy_count.
+		 * We reserve 4 bytes here. Plus these extra bytes, the
+		 * headroom of the physical head should be enough for the
+		 * radiotap head that iwl3945 supported. See iwl3945_rt.
+		 */
+		skb_reserve(rxb->skb, 4);
+
 		priv->alloc_rxb_skb++;
 		list_del(element);
+
+		/* Get physical address of RB/SKB */
 		rxb->dma_addr =
 		    pci_map_single(priv->pci_dev, rxb->skb->data,
 				   IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
@@ -4085,18 +4069,38 @@ void iwl_rx_replenish(void *data)
 		rxq->free_count++;
 	}
 	spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/*
+ * this should be called while priv->lock is locked
+ */
+static void __iwl3945_rx_replenish(void *data)
+{
+	struct iwl3945_priv *priv = data;
+
+	iwl3945_rx_allocate(priv);
+	iwl3945_rx_queue_restock(priv);
+}
+
+
+void iwl3945_rx_replenish(void *data)
+{
+	struct iwl3945_priv *priv = data;
+	unsigned long flags;
+
+	iwl3945_rx_allocate(priv);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_rx_queue_restock(priv);
+	iwl3945_rx_queue_restock(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 /* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * If an SKB has been detached, the POOL needs to have its SKB set to NULL
  * This free routine walks the list of POOL entries and if SKB is set to
  * non NULL it is unmapped and freed
  */
-void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+static void iwl3945_rx_queue_free(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq)
 {
 	int i;
 	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
@@ -4113,21 +4117,25 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
 	rxq->bd = NULL;
 }
 
-int iwl_rx_queue_alloc(struct iwl_priv *priv)
+int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv)
 {
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl3945_rx_queue *rxq = &priv->rxq;
 	struct pci_dev *dev = priv->pci_dev;
 	int i;
 
 	spin_lock_init(&rxq->lock);
 	INIT_LIST_HEAD(&rxq->rx_free);
 	INIT_LIST_HEAD(&rxq->rx_used);
+
+	/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
 	rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
 	if (!rxq->bd)
 		return -ENOMEM;
+
 	/* Fill the rx_used queue with _all_ of the Rx buffers */
 	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
 		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+
 	/* Set us so that we have processed and used all buffers, but have
 	 * not restocked the Rx queue with fresh buffers */
 	rxq->read = rxq->write = 0;
@@ -4136,7 +4144,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
 	return 0;
 }
 
-void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+void iwl3945_rx_queue_reset(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq)
 {
 	unsigned long flags;
 	int i;
@@ -4183,7 +4191,7 @@ static u8 ratio2dB[100] = {
 /* Calculates a relative dB value from a ratio of linear
  *   (i.e. not dB) signal levels.
  * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
-int iwl_calc_db_from_ratio(int sig_ratio)
+int iwl3945_calc_db_from_ratio(int sig_ratio)
 {
 	/* Anything above 1000:1 just report as 60 dB */
 	if (sig_ratio > 1000)
@@ -4209,7 +4217,7 @@ int iwl_calc_db_from_ratio(int sig_ratio)
 /* Calculate an indication of rx signal quality (a percentage, not dBm!).
  * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
  *   about formulas used below. */
-int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
+int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm)
 {
 	int sig_qual;
 	int degradation = PERFECT_RSSI - rssi_dbm;
@@ -4244,24 +4252,30 @@ int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
 }
 
 /**
- * iwl_rx_handle - Main entry function for receiving responses from the uCode
+ * iwl3945_rx_handle - Main entry function for receiving responses from uCode
  *
  * Uses the priv->rx_handlers callback function array to invoke
  * the appropriate handlers, including command responses,
  * frame-received notifications, and other notifications.
  */
-static void iwl_rx_handle(struct iwl_priv *priv)
+static void iwl3945_rx_handle(struct iwl3945_priv *priv)
 {
-	struct iwl_rx_mem_buffer *rxb;
-	struct iwl_rx_packet *pkt;
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl3945_rx_mem_buffer *rxb;
+	struct iwl3945_rx_packet *pkt;
+	struct iwl3945_rx_queue *rxq = &priv->rxq;
 	u32 r, i;
 	int reclaim;
 	unsigned long flags;
+	u8 fill_rx = 0;
+	u32 count = 0;
 
-	r = iwl_hw_get_rx_read(priv);
+	/* uCode's read index (stored in shared DRAM) indicates the last Rx
+	 * buffer that the driver may process (last buffer filled by ucode). */
+	r = iwl3945_hw_get_rx_read(priv);
 	i = rxq->read;
 
+	if (iwl3945_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+		fill_rx = 1;
 	/* Rx interrupt, but nothing sent from uCode */
 	if (i == r)
 		IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
@@ -4269,7 +4283,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 	while (i != r) {
 		rxb = rxq->queue[i];
 
-		/* If an RXB doesn't have a queue slot associated with it
+		/* If an RXB doesn't have a Rx queue slot associated with it,
 		 * then a bug has been introduced in the queue refilling
 		 * routines -- catch it here */
 		BUG_ON(rxb == NULL);
@@ -4279,7 +4293,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
 					    IWL_RX_BUF_SIZE,
 					    PCI_DMA_FROMDEVICE);
-		pkt = (struct iwl_rx_packet *)rxb->skb->data;
+		pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
 
 		/* Reclaim a command buffer only if this packet is a response
 		 *   to a (driver-originated) command.
@@ -4293,7 +4307,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 
 		/* Based on type of command response or notification,
 		 *   handle those that need handling via function in
-		 *   rx_handlers table.  See iwl_setup_rx_handlers() */
+		 *   rx_handlers table.  See iwl3945_setup_rx_handlers() */
 		if (priv->rx_handlers[pkt->hdr.cmd]) {
 			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
 				"r = %d, i = %d, %s, 0x%02x\n", r, i,
@@ -4308,11 +4322,11 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 		}
 
 		if (reclaim) {
-			/* Invoke any callbacks, transfer the skb to caller,
-			 * and fire off the (possibly) blocking iwl_send_cmd()
+			/* Invoke any callbacks, transfer the skb to caller, and
+			 * fire off the (possibly) blocking iwl3945_send_cmd()
 			 * as we reclaim the driver command queue */
 			if (rxb && rxb->skb)
-				iwl_tx_cmd_complete(priv, rxb);
+				iwl3945_tx_cmd_complete(priv, rxb);
 			else
 				IWL_WARNING("Claim null rxb?\n");
 		}
@@ -4332,15 +4346,28 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 		list_add_tail(&rxb->list, &priv->rxq.rx_used);
 		spin_unlock_irqrestore(&rxq->lock, flags);
 		i = (i + 1) & RX_QUEUE_MASK;
+		/* If there are a lot of unused frames,
+		 * restock the Rx queue so ucode won't assert. */
+		if (fill_rx) {
+			count++;
+			if (count >= 8) {
+				priv->rxq.read = i;
+				__iwl3945_rx_replenish(priv);
+				count = 0;
+			}
+		}
 	}
 
 	/* Backtrack one entry */
 	priv->rxq.read = i;
-	iwl_rx_queue_restock(priv);
+	iwl3945_rx_queue_restock(priv);
 }
 
-int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
-				  struct iwl_tx_queue *txq)
+/**
+ * iwl3945_tx_queue_update_write_ptr - Send new write index to hardware
+ */
+static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv,
+				  struct iwl3945_tx_queue *txq)
 {
 	u32 reg = 0;
 	int rc = 0;
@@ -4354,41 +4381,41 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
 		/* wake up nic if it's powered down ...
 		 * uCode will wake up, and interrupt us again, so next
 		 * time we'll skip this part. */
-		reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+		reg = iwl3945_read32(priv, CSR_UCODE_DRV_GP1);
 
 		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
 			IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
-			iwl_set_bit(priv, CSR_GP_CNTRL,
+			iwl3945_set_bit(priv, CSR_GP_CNTRL,
 				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 			return rc;
 		}
 
 		/* restore this queue's parameters in nic hardware. */
-		rc = iwl_grab_restricted_access(priv);
+		rc = iwl3945_grab_nic_access(priv);
 		if (rc)
 			return rc;
-		iwl_write_restricted(priv, HBUS_TARG_WRPTR,
-				     txq->q.first_empty | (txq_id << 8));
-		iwl_release_restricted_access(priv);
+		iwl3945_write_direct32(priv, HBUS_TARG_WRPTR,
+				     txq->q.write_ptr | (txq_id << 8));
+		iwl3945_release_nic_access(priv);
 
 	/* else not in power-save mode, uCode will never sleep when we're
 	 * trying to tx (during RFKILL, we're not trying to tx). */
 	} else
-		iwl_write32(priv, HBUS_TARG_WRPTR,
-			    txq->q.first_empty | (txq_id << 8));
+		iwl3945_write32(priv, HBUS_TARG_WRPTR,
+			    txq->q.write_ptr | (txq_id << 8));
 
 	txq->need_update = 0;
 
 	return rc;
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
+#ifdef CONFIG_IWL3945_DEBUG
+static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon)
 {
 	DECLARE_MAC_BUF(mac);
 
 	IWL_DEBUG_RADIO("RX CONFIG:\n");
-	iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+	iwl3945_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
 	IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
 	IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
 	IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
@@ -4405,24 +4432,24 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
 }
 #endif
 
-static void iwl_enable_interrupts(struct iwl_priv *priv)
+static void iwl3945_enable_interrupts(struct iwl3945_priv *priv)
 {
 	IWL_DEBUG_ISR("Enabling interrupts\n");
 	set_bit(STATUS_INT_ENABLED, &priv->status);
-	iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+	iwl3945_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
 }
 
-static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+static inline void iwl3945_disable_interrupts(struct iwl3945_priv *priv)
 {
 	clear_bit(STATUS_INT_ENABLED, &priv->status);
 
 	/* disable interrupts from uCode/NIC to host */
-	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+	iwl3945_write32(priv, CSR_INT_MASK, 0x00000000);
 
 	/* acknowledge/clear/reset any interrupts still pending
 	 * from uCode or flow handler (Rx/Tx DMA) */
-	iwl_write32(priv, CSR_INT, 0xffffffff);
-	iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+	iwl3945_write32(priv, CSR_INT, 0xffffffff);
+	iwl3945_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
 	IWL_DEBUG_ISR("Disabled interrupts\n");
 }
 
@@ -4449,7 +4476,7 @@ static const char *desc_lookup(int i)
 #define ERROR_START_OFFSET  (1 * sizeof(u32))
 #define ERROR_ELEM_SIZE     (7 * sizeof(u32))
 
-static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+static void iwl3945_dump_nic_error_log(struct iwl3945_priv *priv)
 {
 	u32 i;
 	u32 desc, time, count, base, data1;
@@ -4458,18 +4485,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
 
 	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
 
-	if (!iwl_hw_valid_rtc_data_addr(base)) {
+	if (!iwl3945_hw_valid_rtc_data_addr(base)) {
 		IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
 		return;
 	}
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		IWL_WARNING("Can not read from adapter at this time.\n");
 		return;
 	}
 
-	count = iwl_read_restricted_mem(priv, base);
+	count = iwl3945_read_targ_mem(priv, base);
 
 	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
 		IWL_ERROR("Start IWL Error Log Dump:\n");
@@ -4482,19 +4509,19 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
 	for (i = ERROR_START_OFFSET;
 	     i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET;
 	     i += ERROR_ELEM_SIZE) {
-		desc = iwl_read_restricted_mem(priv, base + i);
+		desc = iwl3945_read_targ_mem(priv, base + i);
 		time =
-		    iwl_read_restricted_mem(priv, base + i + 1 * sizeof(u32));
+		    iwl3945_read_targ_mem(priv, base + i + 1 * sizeof(u32));
 		blink1 =
-		    iwl_read_restricted_mem(priv, base + i + 2 * sizeof(u32));
+		    iwl3945_read_targ_mem(priv, base + i + 2 * sizeof(u32));
 		blink2 =
-		    iwl_read_restricted_mem(priv, base + i + 3 * sizeof(u32));
+		    iwl3945_read_targ_mem(priv, base + i + 3 * sizeof(u32));
 		ilink1 =
-		    iwl_read_restricted_mem(priv, base + i + 4 * sizeof(u32));
+		    iwl3945_read_targ_mem(priv, base + i + 4 * sizeof(u32));
 		ilink2 =
-		    iwl_read_restricted_mem(priv, base + i + 5 * sizeof(u32));
+		    iwl3945_read_targ_mem(priv, base + i + 5 * sizeof(u32));
 		data1 =
-		    iwl_read_restricted_mem(priv, base + i + 6 * sizeof(u32));
+		    iwl3945_read_targ_mem(priv, base + i + 6 * sizeof(u32));
 
 		IWL_ERROR
 		    ("%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
@@ -4502,18 +4529,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
 		     ilink1, ilink2, data1);
 	}
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 
 }
 
-#define EVENT_START_OFFSET  (4 * sizeof(u32))
+#define EVENT_START_OFFSET  (6 * sizeof(u32))
 
 /**
- * iwl_print_event_log - Dump error event log to syslog
+ * iwl3945_print_event_log - Dump error event log to syslog
  *
- * NOTE: Must be called with iwl_grab_restricted_access() already obtained!
+ * NOTE: Must be called with iwl3945_grab_nic_access() already obtained!
  */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+static void iwl3945_print_event_log(struct iwl3945_priv *priv, u32 start_idx,
 				u32 num_events, u32 mode)
 {
 	u32 i;
@@ -4537,21 +4564,21 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
 	/* "time" is actually "data" for mode 0 (no timestamp).
 	 * place event id # at far right for easier visual parsing. */
 	for (i = 0; i < num_events; i++) {
-		ev = iwl_read_restricted_mem(priv, ptr);
+		ev = iwl3945_read_targ_mem(priv, ptr);
 		ptr += sizeof(u32);
-		time = iwl_read_restricted_mem(priv, ptr);
+		time = iwl3945_read_targ_mem(priv, ptr);
 		ptr += sizeof(u32);
 		if (mode == 0)
 			IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
 		else {
-			data = iwl_read_restricted_mem(priv, ptr);
+			data = iwl3945_read_targ_mem(priv, ptr);
 			ptr += sizeof(u32);
 			IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
 		}
 	}
 }
 
-static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+static void iwl3945_dump_nic_event_log(struct iwl3945_priv *priv)
 {
 	int rc;
 	u32 base;       /* SRAM byte address of event log header */
@@ -4562,29 +4589,29 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
 	u32 size;       /* # entries that we'll print */
 
 	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-	if (!iwl_hw_valid_rtc_data_addr(base)) {
+	if (!iwl3945_hw_valid_rtc_data_addr(base)) {
 		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
 		return;
 	}
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		IWL_WARNING("Can not read from adapter at this time.\n");
 		return;
 	}
 
 	/* event log header */
-	capacity = iwl_read_restricted_mem(priv, base);
-	mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32)));
-	num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32)));
-	next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32)));
+	capacity = iwl3945_read_targ_mem(priv, base);
+	mode = iwl3945_read_targ_mem(priv, base + (1 * sizeof(u32)));
+	num_wraps = iwl3945_read_targ_mem(priv, base + (2 * sizeof(u32)));
+	next_entry = iwl3945_read_targ_mem(priv, base + (3 * sizeof(u32)));
 
 	size = num_wraps ? capacity : next_entry;
 
 	/* bail out if nothing in log */
 	if (size == 0) {
 		IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
-		iwl_release_restricted_access(priv);
+		iwl3945_release_nic_access(priv);
 		return;
 	}
 
@@ -4594,31 +4621,31 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
 	/* if uCode has wrapped back to top of log, start at the oldest entry,
 	 * i.e the next one that uCode would fill. */
 	if (num_wraps)
-		iwl_print_event_log(priv, next_entry,
+		iwl3945_print_event_log(priv, next_entry,
 				    capacity - next_entry, mode);
 
 	/* (then/else) start at top of log */
-	iwl_print_event_log(priv, 0, next_entry, mode);
+	iwl3945_print_event_log(priv, 0, next_entry, mode);
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 }
 
 /**
- * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ * iwl3945_irq_handle_error - called for HW or SW error interrupt from card
  */
-static void iwl_irq_handle_error(struct iwl_priv *priv)
+static void iwl3945_irq_handle_error(struct iwl3945_priv *priv)
 {
-	/* Set the FW error flag -- cleared on iwl_down */
+	/* Set the FW error flag -- cleared on iwl3945_down */
 	set_bit(STATUS_FW_ERROR, &priv->status);
 
 	/* Cancel currently queued command. */
 	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & IWL_DL_FW_ERRORS) {
-		iwl_dump_nic_error_log(priv);
-		iwl_dump_nic_event_log(priv);
-		iwl_print_rx_config_cmd(&priv->staging_rxon);
+#ifdef CONFIG_IWL3945_DEBUG
+	if (iwl3945_debug_level & IWL_DL_FW_ERRORS) {
+		iwl3945_dump_nic_error_log(priv);
+		iwl3945_dump_nic_event_log(priv);
+		iwl3945_print_rx_config_cmd(&priv->staging_rxon);
 	}
 #endif
 
@@ -4632,7 +4659,7 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
 		IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
 			  "Restarting adapter due to uCode error.\n");
 
-		if (iwl_is_associated(priv)) {
+		if (iwl3945_is_associated(priv)) {
 			memcpy(&priv->recovery_rxon, &priv->active_rxon,
 			       sizeof(priv->recovery_rxon));
 			priv->error_recovering = 1;
@@ -4641,16 +4668,16 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
 	}
 }
 
-static void iwl_error_recovery(struct iwl_priv *priv)
+static void iwl3945_error_recovery(struct iwl3945_priv *priv)
 {
 	unsigned long flags;
 
 	memcpy(&priv->staging_rxon, &priv->recovery_rxon,
 	       sizeof(priv->staging_rxon));
 	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_commit_rxon(priv);
+	iwl3945_commit_rxon(priv);
 
-	iwl_add_station(priv, priv->bssid, 1, 0);
+	iwl3945_add_station(priv, priv->bssid, 1, 0);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
@@ -4658,12 +4685,12 @@ static void iwl_error_recovery(struct iwl_priv *priv)
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static void iwl_irq_tasklet(struct iwl_priv *priv)
+static void iwl3945_irq_tasklet(struct iwl3945_priv *priv)
 {
 	u32 inta, handled = 0;
 	u32 inta_fh;
 	unsigned long flags;
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL3945_DEBUG
 	u32 inta_mask;
 #endif
 
@@ -4672,18 +4699,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	/* Ack/clear/reset pending uCode interrupts.
 	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
 	 *  and will clear only when CSR_FH_INT_STATUS gets cleared. */
-	inta = iwl_read32(priv, CSR_INT);
-	iwl_write32(priv, CSR_INT, inta);
+	inta = iwl3945_read32(priv, CSR_INT);
+	iwl3945_write32(priv, CSR_INT, inta);
 
 	/* Ack/clear/reset pending flow-handler (DMA) interrupts.
 	 * Any new interrupts that happen after this, either while we're
 	 * in this tasklet, or later, will show up in next ISR/tasklet. */
-	inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
-	iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
+	inta_fh = iwl3945_read32(priv, CSR_FH_INT_STATUS);
+	iwl3945_write32(priv, CSR_FH_INT_STATUS, inta_fh);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & IWL_DL_ISR) {
-		inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+#ifdef CONFIG_IWL3945_DEBUG
+	if (iwl3945_debug_level & IWL_DL_ISR) {
+		/* just for debug */
+		inta_mask = iwl3945_read32(priv, CSR_INT_MASK);
 		IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
 			      inta, inta_mask, inta_fh);
 	}
@@ -4703,9 +4731,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 		IWL_ERROR("Microcode HW error detected.  Restarting.\n");
 
 		/* Tell the device to stop sending interrupts */
-		iwl_disable_interrupts(priv);
+		iwl3945_disable_interrupts(priv);
 
-		iwl_irq_handle_error(priv);
+		iwl3945_irq_handle_error(priv);
 
 		handled |= CSR_INT_BIT_HW_ERR;
 
@@ -4714,8 +4742,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 		return;
 	}
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & (IWL_DL_ISR)) {
+#ifdef CONFIG_IWL3945_DEBUG
+	if (iwl3945_debug_level & (IWL_DL_ISR)) {
 		/* NIC fires this, but we don't use it, redundant with WAKEUP */
 		if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
 			IWL_DEBUG_ISR("Microcode started or stopped.\n");
@@ -4731,7 +4759,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	/* HW RF KILL switch toggled (4965 only) */
 	if (inta & CSR_INT_BIT_RF_KILL) {
 		int hw_rf_kill = 0;
-		if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+		if (!(iwl3945_read32(priv, CSR_GP_CNTRL) &
 				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
 			hw_rf_kill = 1;
 
@@ -4761,20 +4789,20 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	if (inta & CSR_INT_BIT_SW_ERR) {
 		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
 			  inta);
-		iwl_irq_handle_error(priv);
+		iwl3945_irq_handle_error(priv);
 		handled |= CSR_INT_BIT_SW_ERR;
 	}
 
 	/* uCode wakes up after power-down sleep */
 	if (inta & CSR_INT_BIT_WAKEUP) {
 		IWL_DEBUG_ISR("Wakeup interrupt\n");
-		iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+		iwl3945_rx_queue_update_write_ptr(priv, &priv->rxq);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[0]);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[1]);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[2]);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[3]);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[4]);
+		iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[5]);
 
 		handled |= CSR_INT_BIT_WAKEUP;
 	}
@@ -4783,19 +4811,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	 * Rx "responses" (frame-received notification), and other
 	 * notifications from uCode come through here*/
 	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
-		iwl_rx_handle(priv);
+		iwl3945_rx_handle(priv);
 		handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
 	}
 
 	if (inta & CSR_INT_BIT_FH_TX) {
 		IWL_DEBUG_ISR("Tx interrupt\n");
 
-		iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6));
-		if (!iwl_grab_restricted_access(priv)) {
-			iwl_write_restricted(priv,
+		iwl3945_write32(priv, CSR_FH_INT_STATUS, (1 << 6));
+		if (!iwl3945_grab_nic_access(priv)) {
+			iwl3945_write_direct32(priv,
 					     FH_TCSR_CREDIT
 					     (ALM_FH_SRVC_CHNL), 0x0);
-			iwl_release_restricted_access(priv);
+			iwl3945_release_nic_access(priv);
 		}
 		handled |= CSR_INT_BIT_FH_TX;
 	}
@@ -4810,13 +4838,13 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	}
 
 	/* Re-enable all interrupts */
-	iwl_enable_interrupts(priv);
+	iwl3945_enable_interrupts(priv);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & (IWL_DL_ISR)) {
-		inta = iwl_read32(priv, CSR_INT);
-		inta_mask = iwl_read32(priv, CSR_INT_MASK);
-		inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+#ifdef CONFIG_IWL3945_DEBUG
+	if (iwl3945_debug_level & (IWL_DL_ISR)) {
+		inta = iwl3945_read32(priv, CSR_INT);
+		inta_mask = iwl3945_read32(priv, CSR_INT_MASK);
+		inta_fh = iwl3945_read32(priv, CSR_FH_INT_STATUS);
 		IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
 			"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
 	}
@@ -4824,9 +4852,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static irqreturn_t iwl_isr(int irq, void *data)
+static irqreturn_t iwl3945_isr(int irq, void *data)
 {
-	struct iwl_priv *priv = data;
+	struct iwl3945_priv *priv = data;
 	u32 inta, inta_mask;
 	u32 inta_fh;
 	if (!priv)
@@ -4838,12 +4866,12 @@ static irqreturn_t iwl_isr(int irq, void *data)
 	 *    back-to-back ISRs and sporadic interrupts from our NIC.
 	 * If we have something to service, the tasklet will re-enable ints.
 	 * If we *don't* have something, we'll re-enable before leaving here. */
-	inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
-	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+	inta_mask = iwl3945_read32(priv, CSR_INT_MASK);  /* just for debug */
+	iwl3945_write32(priv, CSR_INT_MASK, 0x00000000);
 
 	/* Discover which interrupts are active/pending */
-	inta = iwl_read32(priv, CSR_INT);
-	inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+	inta = iwl3945_read32(priv, CSR_INT);
+	inta_fh = iwl3945_read32(priv, CSR_FH_INT_STATUS);
 
 	/* Ignore interrupt if there's nothing in NIC to service.
 	 * This may be due to IRQ shared with another device,
@@ -4862,7 +4890,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
 	IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
 		      inta, inta_mask, inta_fh);
 
-	/* iwl_irq_tasklet() will service interrupts and re-enable them */
+	/* iwl3945_irq_tasklet() will service interrupts and re-enable them */
 	tasklet_schedule(&priv->irq_tasklet);
 unplugged:
 	spin_unlock(&priv->lock);
@@ -4871,18 +4899,18 @@ unplugged:
 
  none:
 	/* re-enable interrupts here since we don't have anything to service. */
-	iwl_enable_interrupts(priv);
+	iwl3945_enable_interrupts(priv);
 	spin_unlock(&priv->lock);
 	return IRQ_NONE;
 }
 
 /************************** EEPROM BANDS ****************************
  *
- * The iwl_eeprom_band definitions below provide the mapping from the
+ * The iwl3945_eeprom_band definitions below provide the mapping from the
  * EEPROM contents to the specific channel number supported for each
  * band.
  *
- * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
+ * For example, iwl3945_priv->eeprom.band_3_channels[4] from the band_3
  * definition below maps to physical channel 42 in the 5.2GHz spectrum.
  * The specific geography and calibration information for that channel
  * is contained in the eeprom map itself.
@@ -4908,58 +4936,58 @@ unplugged:
  *********************************************************************/
 
 /* 2.4 GHz */
-static const u8 iwl_eeprom_band_1[14] = {
+static const u8 iwl3945_eeprom_band_1[14] = {
 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
 };
 
 /* 5.2 GHz bands */
-static const u8 iwl_eeprom_band_2[] = {
+static const u8 iwl3945_eeprom_band_2[] = {	/* 4915-5080MHz */
 	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
 };
 
-static const u8 iwl_eeprom_band_3[] = {	/* 5205-5320MHz */
+static const u8 iwl3945_eeprom_band_3[] = {	/* 5170-5320MHz */
 	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
 };
 
-static const u8 iwl_eeprom_band_4[] = {	/* 5500-5700MHz */
+static const u8 iwl3945_eeprom_band_4[] = {	/* 5500-5700MHz */
 	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
 };
 
-static const u8 iwl_eeprom_band_5[] = {	/* 5725-5825MHz */
+static const u8 iwl3945_eeprom_band_5[] = {	/* 5725-5825MHz */
 	145, 149, 153, 157, 161, 165
 };
 
-static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
+static void iwl3945_init_band_reference(const struct iwl3945_priv *priv, int band,
 				    int *eeprom_ch_count,
-				    const struct iwl_eeprom_channel
+				    const struct iwl3945_eeprom_channel
 				    **eeprom_ch_info,
 				    const u8 **eeprom_ch_index)
 {
 	switch (band) {
 	case 1:		/* 2.4GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
+		*eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_1);
 		*eeprom_ch_info = priv->eeprom.band_1_channels;
-		*eeprom_ch_index = iwl_eeprom_band_1;
+		*eeprom_ch_index = iwl3945_eeprom_band_1;
 		break;
-	case 2:		/* 5.2GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
+	case 2:		/* 4.9GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_2);
 		*eeprom_ch_info = priv->eeprom.band_2_channels;
-		*eeprom_ch_index = iwl_eeprom_band_2;
+		*eeprom_ch_index = iwl3945_eeprom_band_2;
 		break;
 	case 3:		/* 5.2GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
+		*eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_3);
 		*eeprom_ch_info = priv->eeprom.band_3_channels;
-		*eeprom_ch_index = iwl_eeprom_band_3;
+		*eeprom_ch_index = iwl3945_eeprom_band_3;
 		break;
-	case 4:		/* 5.2GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
+	case 4:		/* 5.5GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_4);
 		*eeprom_ch_info = priv->eeprom.band_4_channels;
-		*eeprom_ch_index = iwl_eeprom_band_4;
+		*eeprom_ch_index = iwl3945_eeprom_band_4;
 		break;
-	case 5:		/* 5.2GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
+	case 5:		/* 5.7GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_5);
 		*eeprom_ch_info = priv->eeprom.band_5_channels;
-		*eeprom_ch_index = iwl_eeprom_band_5;
+		*eeprom_ch_index = iwl3945_eeprom_band_5;
 		break;
 	default:
 		BUG();
@@ -4967,7 +4995,12 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
 	}
 }
 
-const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+/**
+ * iwl3945_get_channel_info - Find driver's private channel info
+ *
+ * Based on band and channel number.
+ */
+const struct iwl3945_channel_info *iwl3945_get_channel_info(const struct iwl3945_priv *priv,
 						    int phymode, u16 channel)
 {
 	int i;
@@ -4994,13 +5027,16 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
 #define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
 			    ? # x " " : "")
 
-static int iwl_init_channel_map(struct iwl_priv *priv)
+/**
+ * iwl3945_init_channel_map - Set up driver's info for all possible channels
+ */
+static int iwl3945_init_channel_map(struct iwl3945_priv *priv)
 {
 	int eeprom_ch_count = 0;
 	const u8 *eeprom_ch_index = NULL;
-	const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
+	const struct iwl3945_eeprom_channel *eeprom_ch_info = NULL;
 	int band, ch;
-	struct iwl_channel_info *ch_info;
+	struct iwl3945_channel_info *ch_info;
 
 	if (priv->channel_count) {
 		IWL_DEBUG_INFO("Channel map already initialized.\n");
@@ -5016,15 +5052,15 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
 	IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
 
 	priv->channel_count =
-	    ARRAY_SIZE(iwl_eeprom_band_1) +
-	    ARRAY_SIZE(iwl_eeprom_band_2) +
-	    ARRAY_SIZE(iwl_eeprom_band_3) +
-	    ARRAY_SIZE(iwl_eeprom_band_4) +
-	    ARRAY_SIZE(iwl_eeprom_band_5);
+	    ARRAY_SIZE(iwl3945_eeprom_band_1) +
+	    ARRAY_SIZE(iwl3945_eeprom_band_2) +
+	    ARRAY_SIZE(iwl3945_eeprom_band_3) +
+	    ARRAY_SIZE(iwl3945_eeprom_band_4) +
+	    ARRAY_SIZE(iwl3945_eeprom_band_5);
 
 	IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
 
-	priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
+	priv->channel_info = kzalloc(sizeof(struct iwl3945_channel_info) *
 				     priv->channel_count, GFP_KERNEL);
 	if (!priv->channel_info) {
 		IWL_ERROR("Could not allocate channel_info\n");
@@ -5039,7 +5075,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
 	 * what just in the EEPROM) */
 	for (band = 1; band <= 5; band++) {
 
-		iwl_init_band_reference(priv, band, &eeprom_ch_count,
+		iwl3945_init_band_reference(priv, band, &eeprom_ch_count,
 					&eeprom_ch_info, &eeprom_ch_index);
 
 		/* Loop through each band adding each of the channels */
@@ -5103,6 +5139,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
 		}
 	}
 
+	/* Set up txpower settings in driver for all channels */
 	if (iwl3945_txpower_set_from_eeprom(priv))
 		return -EIO;
 
@@ -5132,7 +5169,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
 #define IWL_PASSIVE_DWELL_BASE      (100)
 #define IWL_CHANNEL_TUNE_TIME       5
 
-static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
+static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, int phymode)
 {
 	if (phymode == MODE_IEEE80211A)
 		return IWL_ACTIVE_DWELL_TIME_52;
@@ -5140,14 +5177,14 @@ static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
 		return IWL_ACTIVE_DWELL_TIME_24;
 }
 
-static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
+static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, int phymode)
 {
-	u16 active = iwl_get_active_dwell_time(priv, phymode);
+	u16 active = iwl3945_get_active_dwell_time(priv, phymode);
 	u16 passive = (phymode != MODE_IEEE80211A) ?
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
 
-	if (iwl_is_associated(priv)) {
+	if (iwl3945_is_associated(priv)) {
 		/* If we're associated, we clamp the maximum passive
 		 * dwell time to be 98% of the beacon interval (minus
 		 * 2 * channel tune time) */
@@ -5163,30 +5200,30 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
 	return passive;
 }
 
-static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode,
 				     u8 is_active, u8 direct_mask,
-				     struct iwl_scan_channel *scan_ch)
+				     struct iwl3945_scan_channel *scan_ch)
 {
 	const struct ieee80211_channel *channels = NULL;
 	const struct ieee80211_hw_mode *hw_mode;
-	const struct iwl_channel_info *ch_info;
+	const struct iwl3945_channel_info *ch_info;
 	u16 passive_dwell = 0;
 	u16 active_dwell = 0;
 	int added, i;
 
-	hw_mode = iwl_get_hw_mode(priv, phymode);
+	hw_mode = iwl3945_get_hw_mode(priv, phymode);
 	if (!hw_mode)
 		return 0;
 
 	channels = hw_mode->channels;
 
-	active_dwell = iwl_get_active_dwell_time(priv, phymode);
-	passive_dwell = iwl_get_passive_dwell_time(priv, phymode);
+	active_dwell = iwl3945_get_active_dwell_time(priv, phymode);
+	passive_dwell = iwl3945_get_passive_dwell_time(priv, phymode);
 
 	for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
 		if (channels[i].chan ==
 		    le16_to_cpu(priv->active_rxon.channel)) {
-			if (iwl_is_associated(priv)) {
+			if (iwl3945_is_associated(priv)) {
 				IWL_DEBUG_SCAN
 				    ("Skipping current channel %d\n",
 				     le16_to_cpu(priv->active_rxon.channel));
@@ -5197,7 +5234,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
 
 		scan_ch->channel = channels[i].chan;
 
-		ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel);
+		ch_info = iwl3945_get_channel_info(priv, phymode, scan_ch->channel);
 		if (!is_channel_valid(ch_info)) {
 			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
 				       scan_ch->channel);
@@ -5219,7 +5256,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
 		scan_ch->active_dwell = cpu_to_le16(active_dwell);
 		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
 
-		/* Set power levels to defaults */
+		/* Set txpower levels to defaults */
 		scan_ch->tpc.dsp_atten = 110;
 		/* scan_pwr_info->tpc.dsp_atten; */
 
@@ -5229,8 +5266,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
 		else {
 			scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
 			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
-			 * power level
-			 scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+			 * power level:
+			 * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3;
 			 */
 		}
 
@@ -5248,7 +5285,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
 	return added;
 }
 
-static void iwl_reset_channel_flag(struct iwl_priv *priv)
+static void iwl3945_reset_channel_flag(struct iwl3945_priv *priv)
 {
 	int i, j;
 	for (i = 0; i < 3; i++) {
@@ -5258,13 +5295,13 @@ static void iwl_reset_channel_flag(struct iwl_priv *priv)
 	}
 }
 
-static void iwl_init_hw_rates(struct iwl_priv *priv,
+static void iwl3945_init_hw_rates(struct iwl3945_priv *priv,
 			      struct ieee80211_rate *rates)
 {
 	int i;
 
 	for (i = 0; i < IWL_RATE_COUNT; i++) {
-		rates[i].rate = iwl_rates[i].ieee * 5;
+		rates[i].rate = iwl3945_rates[i].ieee * 5;
 		rates[i].val = i; /* Rate scaling will work on indexes */
 		rates[i].val2 = i;
 		rates[i].flags = IEEE80211_RATE_SUPPORTED;
@@ -5276,7 +5313,7 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
 			 * If CCK 1M then set rate flag to CCK else CCK_2
 			 * which is CCK | PREAMBLE2
 			 */
-			rates[i].flags |= (iwl_rates[i].plcp == 10) ?
+			rates[i].flags |= (iwl3945_rates[i].plcp == 10) ?
 				IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
 		}
 
@@ -5287,11 +5324,11 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
 }
 
 /**
- * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ * iwl3945_init_geos - Initialize mac80211's geo/channel info based from eeprom
  */
-static int iwl_init_geos(struct iwl_priv *priv)
+static int iwl3945_init_geos(struct iwl3945_priv *priv)
 {
-	struct iwl_channel_info *ch;
+	struct iwl3945_channel_info *ch;
 	struct ieee80211_hw_mode *modes;
 	struct ieee80211_channel *channels;
 	struct ieee80211_channel *geo_ch;
@@ -5337,7 +5374,7 @@ static int iwl_init_geos(struct iwl_priv *priv)
 
 	/* 5.2GHz channels start after the 2.4GHz channels */
 	modes[A].mode = MODE_IEEE80211A;
-	modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+	modes[A].channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)];
 	modes[A].rates = &rates[4];
 	modes[A].num_rates = 8;	/* just OFDM */
 	modes[A].num_channels = 0;
@@ -5357,7 +5394,7 @@ static int iwl_init_geos(struct iwl_priv *priv)
 	priv->ieee_channels = channels;
 	priv->ieee_rates = rates;
 
-	iwl_init_hw_rates(priv, rates);
+	iwl3945_init_hw_rates(priv, rates);
 
 	for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
 		ch = &priv->channel_info[i];
@@ -5440,57 +5477,21 @@ static int iwl_init_geos(struct iwl_priv *priv)
  *
  ******************************************************************************/
 
-static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+static void iwl3945_dealloc_ucode_pci(struct iwl3945_priv *priv)
 {
-	if (priv->ucode_code.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_code.len,
-				    priv->ucode_code.v_addr,
-				    priv->ucode_code.p_addr);
-		priv->ucode_code.v_addr = NULL;
-	}
-	if (priv->ucode_data.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_data.len,
-				    priv->ucode_data.v_addr,
-				    priv->ucode_data.p_addr);
-		priv->ucode_data.v_addr = NULL;
-	}
-	if (priv->ucode_data_backup.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_data_backup.len,
-				    priv->ucode_data_backup.v_addr,
-				    priv->ucode_data_backup.p_addr);
-		priv->ucode_data_backup.v_addr = NULL;
-	}
-	if (priv->ucode_init.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_init.len,
-				    priv->ucode_init.v_addr,
-				    priv->ucode_init.p_addr);
-		priv->ucode_init.v_addr = NULL;
-	}
-	if (priv->ucode_init_data.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_init_data.len,
-				    priv->ucode_init_data.v_addr,
-				    priv->ucode_init_data.p_addr);
-		priv->ucode_init_data.v_addr = NULL;
-	}
-	if (priv->ucode_boot.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_boot.len,
-				    priv->ucode_boot.v_addr,
-				    priv->ucode_boot.p_addr);
-		priv->ucode_boot.v_addr = NULL;
-	}
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
 }
 
 /**
- * iwl_verify_inst_full - verify runtime uCode image in card vs. host,
+ * iwl3945_verify_inst_full - verify runtime uCode image in card vs. host,
  *     looking at all data.
  */
-static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+static int iwl3945_verify_inst_full(struct iwl3945_priv *priv, __le32 * image, u32 len)
 {
 	u32 val;
 	u32 save_len = len;
@@ -5499,18 +5500,18 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
 
 	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc)
 		return rc;
 
-	iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+	iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
 
 	errcnt = 0;
 	for (; len > 0; len -= sizeof(u32), image++) {
 		/* read data comes through single port, auto-incr addr */
 		/* NOTE: Use the debugless read so we don't flood kernel log
 		 * if IWL_DL_IO is set */
-		val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+		val = _iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT);
 		if (val != le32_to_cpu(*image)) {
 			IWL_ERROR("uCode INST section is invalid at "
 				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
@@ -5522,22 +5523,21 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
 		}
 	}
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 
 	if (!errcnt)
-		IWL_DEBUG_INFO
-		    ("ucode image in INSTRUCTION memory is good\n");
+		IWL_DEBUG_INFO("ucode image in INSTRUCTION memory is good\n");
 
 	return rc;
 }
 
 
 /**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ * iwl3945_verify_inst_sparse - verify runtime uCode image in card vs. host,
  *   using sample data 100 bytes apart.  If these sample points are good,
  *   it's a pretty good bet that everything between them is good, too.
  */
-static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+static int iwl3945_verify_inst_sparse(struct iwl3945_priv *priv, __le32 *image, u32 len)
 {
 	u32 val;
 	int rc = 0;
@@ -5546,7 +5546,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
 
 	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc)
 		return rc;
 
@@ -5554,9 +5554,9 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
 		/* read data comes through single port, auto-incr addr */
 		/* NOTE: Use the debugless read so we don't flood kernel log
 		 * if IWL_DL_IO is set */
-		iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR,
+		iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR,
 			i + RTC_INST_LOWER_BOUND);
-		val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+		val = _iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT);
 		if (val != le32_to_cpu(*image)) {
 #if 0 /* Enable this if you want to see details */
 			IWL_ERROR("uCode INST section is invalid at "
@@ -5570,17 +5570,17 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
 		}
 	}
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 
 	return rc;
 }
 
 
 /**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
+ * iwl3945_verify_ucode - determine which instruction image is in SRAM,
  *    and verify its contents
  */
-static int iwl_verify_ucode(struct iwl_priv *priv)
+static int iwl3945_verify_ucode(struct iwl3945_priv *priv)
 {
 	__le32 *image;
 	u32 len;
@@ -5589,7 +5589,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
 	/* Try bootstrap */
 	image = (__le32 *)priv->ucode_boot.v_addr;
 	len = priv->ucode_boot.len;
-	rc = iwl_verify_inst_sparse(priv, image, len);
+	rc = iwl3945_verify_inst_sparse(priv, image, len);
 	if (rc == 0) {
 		IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
 		return 0;
@@ -5598,7 +5598,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
 	/* Try initialize */
 	image = (__le32 *)priv->ucode_init.v_addr;
 	len = priv->ucode_init.len;
-	rc = iwl_verify_inst_sparse(priv, image, len);
+	rc = iwl3945_verify_inst_sparse(priv, image, len);
 	if (rc == 0) {
 		IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
 		return 0;
@@ -5607,7 +5607,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
 	/* Try runtime/protocol */
 	image = (__le32 *)priv->ucode_code.v_addr;
 	len = priv->ucode_code.len;
-	rc = iwl_verify_inst_sparse(priv, image, len);
+	rc = iwl3945_verify_inst_sparse(priv, image, len);
 	if (rc == 0) {
 		IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
 		return 0;
@@ -5615,18 +5615,19 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
 
 	IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
 
-	/* Show first several data entries in instruction SRAM.
-	 * Selection of bootstrap image is arbitrary. */
+	/* Since nothing seems to match, show first several data entries in
+	 * instruction SRAM, so maybe visual inspection will give a clue.
+	 * Selection of bootstrap image (vs. other images) is arbitrary. */
 	image = (__le32 *)priv->ucode_boot.v_addr;
 	len = priv->ucode_boot.len;
-	rc = iwl_verify_inst_full(priv, image, len);
+	rc = iwl3945_verify_inst_full(priv, image, len);
 
 	return rc;
 }
 
 
 /* check contents of special bootstrap uCode SRAM */
-static int iwl_verify_bsm(struct iwl_priv *priv)
+static int iwl3945_verify_bsm(struct iwl3945_priv *priv)
 {
 	__le32 *image = priv->ucode_boot.v_addr;
 	u32 len = priv->ucode_boot.len;
@@ -5636,11 +5637,11 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
 	IWL_DEBUG_INFO("Begin verify bsm\n");
 
 	/* verify BSM SRAM contents */
-	val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG);
+	val = iwl3945_read_prph(priv, BSM_WR_DWCOUNT_REG);
 	for (reg = BSM_SRAM_LOWER_BOUND;
 	     reg < BSM_SRAM_LOWER_BOUND + len;
 	     reg += sizeof(u32), image ++) {
-		val = iwl_read_restricted_reg(priv, reg);
+		val = iwl3945_read_prph(priv, reg);
 		if (val != le32_to_cpu(*image)) {
 			IWL_ERROR("BSM uCode verification failed at "
 				  "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
@@ -5657,7 +5658,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
 }
 
 /**
- * iwl_load_bsm - Load bootstrap instructions
+ * iwl3945_load_bsm - Load bootstrap instructions
  *
  * BSM operation:
  *
@@ -5688,7 +5689,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
  * the runtime uCode instructions and the backup data cache into SRAM,
  * and re-launches the runtime uCode from where it left off.
  */
-static int iwl_load_bsm(struct iwl_priv *priv)
+static int iwl3945_load_bsm(struct iwl3945_priv *priv)
 {
 	__le32 *image = priv->ucode_boot.v_addr;
 	u32 len = priv->ucode_boot.len;
@@ -5708,8 +5709,8 @@ static int iwl_load_bsm(struct iwl_priv *priv)
 		return -EINVAL;
 
 	/* Tell bootstrap uCode where to find the "Initialize" uCode
-	 *   in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965.
-	 * NOTE:  iwl_initialize_alive_start() will replace these values,
+	 *   in host DRAM ... host DRAM physical address bits 31:0 for 3945.
+	 * NOTE:  iwl3945_initialize_alive_start() will replace these values,
 	 *        after the "initialize" uCode has run, to point to
 	 *        runtime/protocol instructions and backup data cache. */
 	pinst = priv->ucode_init.p_addr;
@@ -5717,42 +5718,42 @@ static int iwl_load_bsm(struct iwl_priv *priv)
 	inst_len = priv->ucode_init.len;
 	data_len = priv->ucode_init_data.len;
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc)
 		return rc;
 
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
-	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
-	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
+	iwl3945_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+	iwl3945_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+	iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+	iwl3945_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
 
 	/* Fill BSM memory with bootstrap instructions */
 	for (reg_offset = BSM_SRAM_LOWER_BOUND;
 	     reg_offset < BSM_SRAM_LOWER_BOUND + len;
 	     reg_offset += sizeof(u32), image++)
-		_iwl_write_restricted_reg(priv, reg_offset,
+		_iwl3945_write_prph(priv, reg_offset,
 					  le32_to_cpu(*image));
 
-	rc = iwl_verify_bsm(priv);
+	rc = iwl3945_verify_bsm(priv);
 	if (rc) {
-		iwl_release_restricted_access(priv);
+		iwl3945_release_nic_access(priv);
 		return rc;
 	}
 
 	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
-	iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0);
-	iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG,
+	iwl3945_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
+	iwl3945_write_prph(priv, BSM_WR_MEM_DST_REG,
 				 RTC_INST_LOWER_BOUND);
-	iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+	iwl3945_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
 
 	/* Load bootstrap code into instruction SRAM now,
 	 *   to prepare to load "initialize" uCode */
-	iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+	iwl3945_write_prph(priv, BSM_WR_CTRL_REG,
 		BSM_WR_CTRL_REG_BIT_START);
 
 	/* Wait for load of bootstrap uCode to finish */
 	for (i = 0; i < 100; i++) {
-		done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG);
+		done = iwl3945_read_prph(priv, BSM_WR_CTRL_REG);
 		if (!(done & BSM_WR_CTRL_REG_BIT_START))
 			break;
 		udelay(10);
@@ -5766,29 +5767,29 @@ static int iwl_load_bsm(struct iwl_priv *priv)
 
 	/* Enable future boot loads whenever power management unit triggers it
 	 *   (e.g. when powering back up after power-save shutdown) */
-	iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+	iwl3945_write_prph(priv, BSM_WR_CTRL_REG,
 		BSM_WR_CTRL_REG_BIT_START_EN);
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 
 	return 0;
 }
 
-static void iwl_nic_start(struct iwl_priv *priv)
+static void iwl3945_nic_start(struct iwl3945_priv *priv)
 {
 	/* Remove all resets to allow NIC to operate */
-	iwl_write32(priv, CSR_RESET, 0);
+	iwl3945_write32(priv, CSR_RESET, 0);
 }
 
 /**
- * iwl_read_ucode - Read uCode images from disk file.
+ * iwl3945_read_ucode - Read uCode images from disk file.
  *
  * Copy into buffers for card to fetch via bus-mastering
  */
-static int iwl_read_ucode(struct iwl_priv *priv)
+static int iwl3945_read_ucode(struct iwl3945_priv *priv)
 {
-	struct iwl_ucode *ucode;
-	int rc = 0;
+	struct iwl3945_ucode *ucode;
+	int ret = 0;
 	const struct firmware *ucode_raw;
 	/* firmware file name contains uCode/driver compatibility version */
 	const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode";
@@ -5798,9 +5799,10 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 
 	/* Ask kernel firmware_class module to get the boot firmware off disk.
 	 * request_firmware() is synchronous, file is in memory on return. */
-	rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
-	if (rc < 0) {
-		IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc);
+	ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+	if (ret < 0) {
+		IWL_ERROR("%s firmware file req failed: Reason %d\n",
+				name, ret);
 		goto error;
 	}
 
@@ -5810,7 +5812,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 	/* Make sure that we got at least our header! */
 	if (ucode_raw->size < sizeof(*ucode)) {
 		IWL_ERROR("File size way too small!\n");
-		rc = -EINVAL;
+		ret = -EINVAL;
 		goto err_release;
 	}
 
@@ -5825,16 +5827,11 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 	boot_size = le32_to_cpu(ucode->boot_size);
 
 	IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
-	IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
-		       inst_size);
-	IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
-		       data_size);
-	IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n",
-		       init_size);
-	IWL_DEBUG_INFO("f/w package hdr init data size = %u\n",
-		       init_data_size);
-	IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n",
-		       boot_size);
+	IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size);
+	IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", data_size);
+	IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", init_size);
+	IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", init_data_size);
+	IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", boot_size);
 
 	/* Verify size of file vs. image size info in file's header */
 	if (ucode_raw->size < sizeof(*ucode) +
@@ -5843,43 +5840,40 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 
 		IWL_DEBUG_INFO("uCode file size %d too small\n",
 			       (int)ucode_raw->size);
-		rc = -EINVAL;
+		ret = -EINVAL;
 		goto err_release;
 	}
 
 	/* Verify that uCode images will fit in card's SRAM */
 	if (inst_size > IWL_MAX_INST_SIZE) {
-		IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n",
-			       (int)inst_size);
-		rc = -EINVAL;
+		IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n",
+			       inst_size);
+		ret = -EINVAL;
 		goto err_release;
 	}
 
 	if (data_size > IWL_MAX_DATA_SIZE) {
-		IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n",
-			       (int)data_size);
-		rc = -EINVAL;
+		IWL_DEBUG_INFO("uCode data len %d too large to fit in\n",
+			       data_size);
+		ret = -EINVAL;
 		goto err_release;
 	}
 	if (init_size > IWL_MAX_INST_SIZE) {
-		IWL_DEBUG_INFO
-		    ("uCode init instr len %d too large to fit in card\n",
-		     (int)init_size);
-		rc = -EINVAL;
+		IWL_DEBUG_INFO("uCode init instr len %d too large to fit in\n",
+				init_size);
+		ret = -EINVAL;
 		goto err_release;
 	}
 	if (init_data_size > IWL_MAX_DATA_SIZE) {
-		IWL_DEBUG_INFO
-		    ("uCode init data len %d too large to fit in card\n",
-		     (int)init_data_size);
-		rc = -EINVAL;
+		IWL_DEBUG_INFO("uCode init data len %d too large to fit in\n",
+				init_data_size);
+		ret = -EINVAL;
 		goto err_release;
 	}
 	if (boot_size > IWL_MAX_BSM_SIZE) {
-		IWL_DEBUG_INFO
-		    ("uCode boot instr len %d too large to fit in bsm\n",
-		     (int)boot_size);
-		rc = -EINVAL;
+		IWL_DEBUG_INFO("uCode boot instr len %d too large to fit in\n",
+				boot_size);
+		ret = -EINVAL;
 		goto err_release;
 	}
 
@@ -5889,66 +5883,54 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 	 * 1) unmodified from disk
 	 * 2) backup cache for save/restore during power-downs */
 	priv->ucode_code.len = inst_size;
-	priv->ucode_code.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_code.len,
-				 &(priv->ucode_code.p_addr));
+	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
 
 	priv->ucode_data.len = data_size;
-	priv->ucode_data.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_data.len,
-				 &(priv->ucode_data.p_addr));
+	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
 
 	priv->ucode_data_backup.len = data_size;
-	priv->ucode_data_backup.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_data_backup.len,
-				 &(priv->ucode_data_backup.p_addr));
+	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
 
+	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
+	    !priv->ucode_data_backup.v_addr)
+		goto err_pci_alloc;
 
 	/* Initialization instructions and data */
-	priv->ucode_init.len = init_size;
-	priv->ucode_init.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_init.len,
-				 &(priv->ucode_init.p_addr));
-
-	priv->ucode_init_data.len = init_data_size;
-	priv->ucode_init_data.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_init_data.len,
-				 &(priv->ucode_init_data.p_addr));
+	if (init_size && init_data_size) {
+		priv->ucode_init.len = init_size;
+		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
+
+		priv->ucode_init_data.len = init_data_size;
+		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+
+		if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
+			goto err_pci_alloc;
+	}
 
 	/* Bootstrap (instructions only, no data) */
-	priv->ucode_boot.len = boot_size;
-	priv->ucode_boot.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_boot.len,
-				 &(priv->ucode_boot.p_addr));
+	if (boot_size) {
+		priv->ucode_boot.len = boot_size;
+		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
 
-	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
-	    !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr ||
-	    !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr)
-		goto err_pci_alloc;
+		if (!priv->ucode_boot.v_addr)
+			goto err_pci_alloc;
+	}
 
 	/* Copy images into buffers for card's bus-master reads ... */
 
 	/* Runtime instructions (first block of data in file) */
 	src = &ucode->data[0];
 	len = priv->ucode_code.len;
-	IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n",
-		       (int)len);
+	IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %Zd\n", len);
 	memcpy(priv->ucode_code.v_addr, src, len);
 	IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
 		priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
 
 	/* Runtime data (2nd block)
-	 * NOTE:  Copy into backup buffer will be done in iwl_up()  */
+	 * NOTE:  Copy into backup buffer will be done in iwl3945_up()  */
 	src = &ucode->data[inst_size];
 	len = priv->ucode_data.len;
-	IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n",
-		       (int)len);
+	IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len);
 	memcpy(priv->ucode_data.v_addr, src, len);
 	memcpy(priv->ucode_data_backup.v_addr, src, len);
 
@@ -5956,8 +5938,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 	if (init_size) {
 		src = &ucode->data[inst_size + data_size];
 		len = priv->ucode_init.len;
-		IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n",
-			       (int)len);
+		IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n",
+			       len);
 		memcpy(priv->ucode_init.v_addr, src, len);
 	}
 
@@ -5983,19 +5965,19 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 
  err_pci_alloc:
 	IWL_ERROR("failed to allocate pci memory\n");
-	rc = -ENOMEM;
-	iwl_dealloc_ucode_pci(priv);
+	ret = -ENOMEM;
+	iwl3945_dealloc_ucode_pci(priv);
 
  err_release:
 	release_firmware(ucode_raw);
 
  error:
-	return rc;
+	return ret;
 }
 
 
 /**
- * iwl_set_ucode_ptrs - Set uCode address location
+ * iwl3945_set_ucode_ptrs - Set uCode address location
  *
  * Tell initialization uCode where to find runtime uCode.
  *
@@ -6003,7 +5985,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  * We need to replace them to load runtime uCode inst and data,
  * and to save runtime data when powering down.
  */
-static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+static int iwl3945_set_ucode_ptrs(struct iwl3945_priv *priv)
 {
 	dma_addr_t pinst;
 	dma_addr_t pdata;
@@ -6015,24 +5997,24 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
 	pdata = priv->ucode_data_backup.p_addr;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
 	/* Tell bootstrap uCode where to find image to load */
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
-	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
-	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+	iwl3945_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+	iwl3945_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+	iwl3945_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
 				 priv->ucode_data.len);
 
 	/* Inst bytecount must be last to set up, bit 31 signals uCode
 	 *   that all new ptr/size info is in place */
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+	iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
 				 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
 
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -6042,17 +6024,13 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
 }
 
 /**
- * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved
+ * iwl3945_init_alive_start - Called after REPLY_ALIVE notification received
  *
  * Called after REPLY_ALIVE notification received from "initialize" uCode.
  *
- * The 4965 "initialize" ALIVE reply contains calibration data for:
- *   Voltage, temperature, and MIMO tx gain correction, now stored in priv
- *   (3945 does not contain this data).
- *
  * Tell "initialize" uCode to go ahead and load the runtime uCode.
-*/
-static void iwl_init_alive_start(struct iwl_priv *priv)
+ */
+static void iwl3945_init_alive_start(struct iwl3945_priv *priv)
 {
 	/* Check alive response for "valid" sign from uCode */
 	if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
@@ -6065,7 +6043,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
 	/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
 	 * This is a paranoid check, because we would not have gotten the
 	 * "initialize" alive if code weren't properly loaded.  */
-	if (iwl_verify_ucode(priv)) {
+	if (iwl3945_verify_ucode(priv)) {
 		/* Runtime instruction load was bad;
 		 * take it all the way back down so we can try again */
 		IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
@@ -6076,7 +6054,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
 	 * load and launch runtime uCode, which will send us another "Alive"
 	 * notification. */
 	IWL_DEBUG_INFO("Initialization Alive received.\n");
-	if (iwl_set_ucode_ptrs(priv)) {
+	if (iwl3945_set_ucode_ptrs(priv)) {
 		/* Runtime instruction load won't happen;
 		 * take it all the way back down so we can try again */
 		IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
@@ -6090,11 +6068,11 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
 
 
 /**
- * iwl_alive_start - called after REPLY_ALIVE notification received
+ * iwl3945_alive_start - called after REPLY_ALIVE notification received
  *                   from protocol/runtime uCode (initialization uCode's
- *                   Alive gets handled by iwl_init_alive_start()).
+ *                   Alive gets handled by iwl3945_init_alive_start()).
  */
-static void iwl_alive_start(struct iwl_priv *priv)
+static void iwl3945_alive_start(struct iwl3945_priv *priv)
 {
 	int rc = 0;
 	int thermal_spin = 0;
@@ -6112,30 +6090,30 @@ static void iwl_alive_start(struct iwl_priv *priv)
 	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
 	 * This is a paranoid check, because we would not have gotten the
 	 * "runtime" alive if code weren't properly loaded.  */
-	if (iwl_verify_ucode(priv)) {
+	if (iwl3945_verify_ucode(priv)) {
 		/* Runtime instruction load was bad;
 		 * take it all the way back down so we can try again */
 		IWL_DEBUG_INFO("Bad runtime uCode load.\n");
 		goto restart;
 	}
 
-	iwl_clear_stations_table(priv);
+	iwl3945_clear_stations_table(priv);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl3945_grab_nic_access(priv);
 	if (rc) {
 		IWL_WARNING("Can not read rfkill status from adapter\n");
 		return;
 	}
 
-	rfkill = iwl_read_restricted_reg(priv, APMG_RFKILL_REG);
+	rfkill = iwl3945_read_prph(priv, APMG_RFKILL_REG);
 	IWL_DEBUG_INFO("RFKILL status: 0x%x\n", rfkill);
-	iwl_release_restricted_access(priv);
+	iwl3945_release_nic_access(priv);
 
 	if (rfkill & 0x1) {
 		clear_bit(STATUS_RF_KILL_HW, &priv->status);
 		/* if rfkill is not on, then wait for thermal
 		 * sensor in adapter to kick in */
-		while (iwl_hw_get_temperature(priv) == 0) {
+		while (iwl3945_hw_get_temperature(priv) == 0) {
 			thermal_spin++;
 			udelay(10);
 		}
@@ -6146,68 +6124,49 @@ static void iwl_alive_start(struct iwl_priv *priv)
 	} else
 		set_bit(STATUS_RF_KILL_HW, &priv->status);
 
-	/* After the ALIVE response, we can process host commands */
+	/* After the ALIVE response, we can send commands to 3945 uCode */
 	set_bit(STATUS_ALIVE, &priv->status);
 
 	/* Clear out the uCode error bit if it is set */
 	clear_bit(STATUS_FW_ERROR, &priv->status);
 
-	rc = iwl_init_channel_map(priv);
+	rc = iwl3945_init_channel_map(priv);
 	if (rc) {
 		IWL_ERROR("initializing regulatory failed: %d\n", rc);
 		return;
 	}
 
-	iwl_init_geos(priv);
+	iwl3945_init_geos(priv);
+	iwl3945_reset_channel_flag(priv);
 
-	if (iwl_is_rfkill(priv))
+	if (iwl3945_is_rfkill(priv))
 		return;
 
-	if (!priv->mac80211_registered) {
-		/* Unlock so any user space entry points can call back into
-		 * the driver without a deadlock... */
-		mutex_unlock(&priv->mutex);
-		iwl_rate_control_register(priv->hw);
-		rc = ieee80211_register_hw(priv->hw);
-		priv->hw->conf.beacon_int = 100;
-		mutex_lock(&priv->mutex);
-
-		if (rc) {
-			iwl_rate_control_unregister(priv->hw);
-			IWL_ERROR("Failed to register network "
-				  "device (error %d)\n", rc);
-			return;
-		}
-
-		priv->mac80211_registered = 1;
-
-		iwl_reset_channel_flag(priv);
-	} else
-		ieee80211_start_queues(priv->hw);
+	ieee80211_start_queues(priv->hw);
 
 	priv->active_rate = priv->rates_mask;
 	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
 
-	iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
+	iwl3945_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
 
-	if (iwl_is_associated(priv)) {
-		struct iwl_rxon_cmd *active_rxon =
-				(struct iwl_rxon_cmd *)(&priv->active_rxon);
+	if (iwl3945_is_associated(priv)) {
+		struct iwl3945_rxon_cmd *active_rxon =
+				(struct iwl3945_rxon_cmd *)(&priv->active_rxon);
 
 		memcpy(&priv->staging_rxon, &priv->active_rxon,
 		       sizeof(priv->staging_rxon));
 		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 	} else {
 		/* Initialize our rx_config data */
-		iwl_connection_init_rx_config(priv);
+		iwl3945_connection_init_rx_config(priv);
 		memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 	}
 
-	/* Configure BT coexistence */
-	iwl_send_bt_config(priv);
+	/* Configure Bluetooth device coexistence support */
+	iwl3945_send_bt_config(priv);
 
 	/* Configure the adapter for unassociated operation */
-	iwl_commit_rxon(priv);
+	iwl3945_commit_rxon(priv);
 
 	/* At this point, the NIC is initialized and operational */
 	priv->notif_missed_beacons = 0;
@@ -6216,9 +6175,10 @@ static void iwl_alive_start(struct iwl_priv *priv)
 	iwl3945_reg_txpower_periodic(priv);
 
 	IWL_DEBUG_INFO("ALIVE processing complete.\n");
+	wake_up_interruptible(&priv->wait_command_queue);
 
 	if (priv->error_recovering)
-		iwl_error_recovery(priv);
+		iwl3945_error_recovery(priv);
 
 	return;
 
@@ -6226,9 +6186,9 @@ static void iwl_alive_start(struct iwl_priv *priv)
 	queue_work(priv->workqueue, &priv->restart);
 }
 
-static void iwl_cancel_deferred_work(struct iwl_priv *priv);
+static void iwl3945_cancel_deferred_work(struct iwl3945_priv *priv);
 
-static void __iwl_down(struct iwl_priv *priv)
+static void __iwl3945_down(struct iwl3945_priv *priv)
 {
 	unsigned long flags;
 	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -6241,7 +6201,7 @@ static void __iwl_down(struct iwl_priv *priv)
 	if (!exit_pending)
 		set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-	iwl_clear_stations_table(priv);
+	iwl3945_clear_stations_table(priv);
 
 	/* Unblock any waiting calls */
 	wake_up_interruptible_all(&priv->wait_command_queue);
@@ -6252,17 +6212,17 @@ static void __iwl_down(struct iwl_priv *priv)
 		clear_bit(STATUS_EXIT_PENDING, &priv->status);
 
 	/* stop and reset the on-board processor */
-	iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+	iwl3945_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 
 	/* tell the device to stop sending interrupts */
-	iwl_disable_interrupts(priv);
+	iwl3945_disable_interrupts(priv);
 
 	if (priv->mac80211_registered)
 		ieee80211_stop_queues(priv->hw);
 
-	/* If we have not previously called iwl_init() then
+	/* If we have not previously called iwl3945_init() then
 	 * clear all bits but the RF Kill and SUSPEND bits and return */
-	if (!iwl_is_init(priv)) {
+	if (!iwl3945_is_init(priv)) {
 		priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
 					STATUS_RF_KILL_HW |
 			       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
@@ -6284,51 +6244,50 @@ static void __iwl_down(struct iwl_priv *priv)
 				STATUS_FW_ERROR;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	iwl_hw_txq_ctx_stop(priv);
-	iwl_hw_rxq_stop(priv);
+	iwl3945_hw_txq_ctx_stop(priv);
+	iwl3945_hw_rxq_stop(priv);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if (!iwl_grab_restricted_access(priv)) {
-		iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+	if (!iwl3945_grab_nic_access(priv)) {
+		iwl3945_write_prph(priv, APMG_CLK_DIS_REG,
 					 APMG_CLK_VAL_DMA_CLK_RQT);
-		iwl_release_restricted_access(priv);
+		iwl3945_release_nic_access(priv);
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	udelay(5);
 
-	iwl_hw_nic_stop_master(priv);
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-	iwl_hw_nic_reset(priv);
+	iwl3945_hw_nic_stop_master(priv);
+	iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+	iwl3945_hw_nic_reset(priv);
 
  exit:
-	memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
+	memset(&priv->card_alive, 0, sizeof(struct iwl3945_alive_resp));
 
 	if (priv->ibss_beacon)
 		dev_kfree_skb(priv->ibss_beacon);
 	priv->ibss_beacon = NULL;
 
 	/* clear out any free frames */
-	iwl_clear_free_frames(priv);
+	iwl3945_clear_free_frames(priv);
 }
 
-static void iwl_down(struct iwl_priv *priv)
+static void iwl3945_down(struct iwl3945_priv *priv)
 {
 	mutex_lock(&priv->mutex);
-	__iwl_down(priv);
+	__iwl3945_down(priv);
 	mutex_unlock(&priv->mutex);
 
-	iwl_cancel_deferred_work(priv);
+	iwl3945_cancel_deferred_work(priv);
 }
 
 #define MAX_HW_RESTARTS 5
 
-static int __iwl_up(struct iwl_priv *priv)
+static int __iwl3945_up(struct iwl3945_priv *priv)
 {
-	DECLARE_MAC_BUF(mac);
 	int rc, i;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
@@ -6339,44 +6298,65 @@ static int __iwl_up(struct iwl_priv *priv)
 	if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
 		IWL_WARNING("Radio disabled by SW RF kill (module "
 			    "parameter)\n");
-		return 0;
+		return -ENODEV;
 	}
 
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+	/* If platform's RF_KILL switch is NOT set to KILL */
+	if (iwl3945_read32(priv, CSR_GP_CNTRL) &
+				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+	else {
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+		if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
+			IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+			return -ENODEV;
+		}
+	}
 
-	rc = iwl_hw_nic_init(priv);
+	if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
+		IWL_ERROR("ucode not available for device bringup\n");
+		return -EIO;
+	}
+
+	iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+	rc = iwl3945_hw_nic_init(priv);
 	if (rc) {
 		IWL_ERROR("Unable to int nic\n");
 		return rc;
 	}
 
 	/* make sure rfkill handshake bits are cleared */
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR,
 		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 
 	/* clear (again), then enable host interrupts */
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-	iwl_enable_interrupts(priv);
+	iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF);
+	iwl3945_enable_interrupts(priv);
 
 	/* really make sure rfkill handshake bits are cleared */
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
 	/* Copy original ucode data image from disk into backup cache.
 	 * This will be used to initialize the on-board processor's
 	 * data SRAM for a clean start when the runtime program first loads. */
 	memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
-			priv->ucode_data.len);
+	       priv->ucode_data.len);
+
+	/* We return success when we resume from suspend and rf_kill is on. */
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status))
+		return 0;
 
 	for (i = 0; i < MAX_HW_RESTARTS; i++) {
 
-		iwl_clear_stations_table(priv);
+		iwl3945_clear_stations_table(priv);
 
 		/* load bootstrap state machine,
 		 * load bootstrap program into processor's memory,
 		 * prepare to load the "initialize" uCode */
-		rc = iwl_load_bsm(priv);
+		rc = iwl3945_load_bsm(priv);
 
 		if (rc) {
 			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
@@ -6384,14 +6364,7 @@ static int __iwl_up(struct iwl_priv *priv)
 		}
 
 		/* start card; "initialize" will load runtime ucode */
-		iwl_nic_start(priv);
-
-		/* MAC Address location in EEPROM same for 3945/4965 */
-		get_eeprom_mac(priv, priv->mac_addr);
-		IWL_DEBUG_INFO("MAC address: %s\n",
-			       print_mac(mac, priv->mac_addr));
-
-		SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+		iwl3945_nic_start(priv);
 
 		IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
 
@@ -6399,7 +6372,7 @@ static int __iwl_up(struct iwl_priv *priv)
 	}
 
 	set_bit(STATUS_EXIT_PENDING, &priv->status);
-	__iwl_down(priv);
+	__iwl3945_down(priv);
 
 	/* tried to restart and config the device for as long as our
 	 * patience could withstand */
@@ -6414,35 +6387,35 @@ static int __iwl_up(struct iwl_priv *priv)
  *
  *****************************************************************************/
 
-static void iwl_bg_init_alive_start(struct work_struct *data)
+static void iwl3945_bg_init_alive_start(struct work_struct *data)
 {
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, init_alive_start.work);
+	struct iwl3945_priv *priv =
+	    container_of(data, struct iwl3945_priv, init_alive_start.work);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
-	iwl_init_alive_start(priv);
+	iwl3945_init_alive_start(priv);
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_alive_start(struct work_struct *data)
+static void iwl3945_bg_alive_start(struct work_struct *data)
 {
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, alive_start.work);
+	struct iwl3945_priv *priv =
+	    container_of(data, struct iwl3945_priv, alive_start.work);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
-	iwl_alive_start(priv);
+	iwl3945_alive_start(priv);
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_rf_kill(struct work_struct *work)
+static void iwl3945_bg_rf_kill(struct work_struct *work)
 {
-	struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
+	struct iwl3945_priv *priv = container_of(work, struct iwl3945_priv, rf_kill);
 
 	wake_up_interruptible(&priv->wait_command_queue);
 
@@ -6451,7 +6424,7 @@ static void iwl_bg_rf_kill(struct work_struct *work)
 
 	mutex_lock(&priv->mutex);
 
-	if (!iwl_is_rfkill(priv)) {
+	if (!iwl3945_is_rfkill(priv)) {
 		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
 			  "HW and/or SW RF Kill no longer active, restarting "
 			  "device\n");
@@ -6472,10 +6445,10 @@ static void iwl_bg_rf_kill(struct work_struct *work)
 
 #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
 
-static void iwl_bg_scan_check(struct work_struct *data)
+static void iwl3945_bg_scan_check(struct work_struct *data)
 {
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, scan_check.work);
+	struct iwl3945_priv *priv =
+	    container_of(data, struct iwl3945_priv, scan_check.work);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
@@ -6488,22 +6461,22 @@ static void iwl_bg_scan_check(struct work_struct *data)
 			  jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
 
 		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
-			iwl_send_scan_abort(priv);
+			iwl3945_send_scan_abort(priv);
 	}
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_request_scan(struct work_struct *data)
+static void iwl3945_bg_request_scan(struct work_struct *data)
 {
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, request_scan);
-	struct iwl_host_cmd cmd = {
+	struct iwl3945_priv *priv =
+	    container_of(data, struct iwl3945_priv, request_scan);
+	struct iwl3945_host_cmd cmd = {
 		.id = REPLY_SCAN_CMD,
-		.len = sizeof(struct iwl_scan_cmd),
+		.len = sizeof(struct iwl3945_scan_cmd),
 		.meta.flags = CMD_SIZE_HUGE,
 	};
 	int rc = 0;
-	struct iwl_scan_cmd *scan;
+	struct iwl3945_scan_cmd *scan;
 	struct ieee80211_conf *conf = NULL;
 	u8 direct_mask;
 	int phymode;
@@ -6512,7 +6485,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 
 	mutex_lock(&priv->mutex);
 
-	if (!iwl_is_ready(priv)) {
+	if (!iwl3945_is_ready(priv)) {
 		IWL_WARNING("request scan called when driver not ready.\n");
 		goto done;
 	}
@@ -6541,7 +6514,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 		goto done;
 	}
 
-	if (iwl_is_rfkill(priv)) {
+	if (iwl3945_is_rfkill(priv)) {
 		IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
 		goto done;
 	}
@@ -6557,7 +6530,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	}
 
 	if (!priv->scan) {
-		priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
+		priv->scan = kmalloc(sizeof(struct iwl3945_scan_cmd) +
 				     IWL_MAX_SCAN_SIZE, GFP_KERNEL);
 		if (!priv->scan) {
 			rc = -ENOMEM;
@@ -6565,12 +6538,12 @@ static void iwl_bg_request_scan(struct work_struct *data)
 		}
 	}
 	scan = priv->scan;
-	memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+	memset(scan, 0, sizeof(struct iwl3945_scan_cmd) + IWL_MAX_SCAN_SIZE);
 
 	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
 	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
 
-	if (iwl_is_associated(priv)) {
+	if (iwl3945_is_associated(priv)) {
 		u16 interval = 0;
 		u32 extra;
 		u32 suspend_time = 100;
@@ -6607,14 +6580,14 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	if (priv->one_direct_scan) {
 		IWL_DEBUG_SCAN
 		    ("Kicking off one direct scan for '%s'\n",
-		     iwl_escape_essid(priv->direct_ssid,
+		     iwl3945_escape_essid(priv->direct_ssid,
 				      priv->direct_ssid_len));
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].len = priv->direct_ssid_len;
 		memcpy(scan->direct_scan[0].ssid,
 		       priv->direct_ssid, priv->direct_ssid_len);
 		direct_mask = 1;
-	} else if (!iwl_is_associated(priv) && priv->essid_len) {
+	} else if (!iwl3945_is_associated(priv) && priv->essid_len) {
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].len = priv->essid_len;
 		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
@@ -6625,7 +6598,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	/* We don't build a direct scan probe request; the uCode will do
 	 * that based on the direct_mask added to each channel entry */
 	scan->tx_cmd.len = cpu_to_le16(
-		iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+		iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
 			IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
 	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
 	scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
@@ -6661,23 +6634,23 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	if (direct_mask)
 		IWL_DEBUG_SCAN
 		    ("Initiating direct scan for %s.\n",
-		     iwl_escape_essid(priv->essid, priv->essid_len));
+		     iwl3945_escape_essid(priv->essid, priv->essid_len));
 	else
 		IWL_DEBUG_SCAN("Initiating indirect scan.\n");
 
 	scan->channel_count =
-		iwl_get_channels_for_scan(
+		iwl3945_get_channels_for_scan(
 			priv, phymode, 1, /* active */
 			direct_mask,
 			(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
 
 	cmd.len += le16_to_cpu(scan->tx_cmd.len) +
-	    scan->channel_count * sizeof(struct iwl_scan_channel);
+	    scan->channel_count * sizeof(struct iwl3945_scan_channel);
 	cmd.data = scan;
 	scan->len = cpu_to_le16(cmd.len);
 
 	set_bit(STATUS_SCAN_HW, &priv->status);
-	rc = iwl_send_cmd_sync(priv, &cmd);
+	rc = iwl3945_send_cmd_sync(priv, &cmd);
 	if (rc)
 		goto done;
 
@@ -6688,50 +6661,52 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	return;
 
  done:
-	/* inform mac80211 sacn aborted */
+	/* inform mac80211 scan aborted */
 	queue_work(priv->workqueue, &priv->scan_completed);
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_up(struct work_struct *data)
+static void iwl3945_bg_up(struct work_struct *data)
 {
-	struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
+	struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv, up);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
-	__iwl_up(priv);
+	__iwl3945_up(priv);
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_restart(struct work_struct *data)
+static void iwl3945_bg_restart(struct work_struct *data)
 {
-	struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
+	struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv, restart);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
-	iwl_down(priv);
+	iwl3945_down(priv);
 	queue_work(priv->workqueue, &priv->up);
 }
 
-static void iwl_bg_rx_replenish(struct work_struct *data)
+static void iwl3945_bg_rx_replenish(struct work_struct *data)
 {
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, rx_replenish);
+	struct iwl3945_priv *priv =
+	    container_of(data, struct iwl3945_priv, rx_replenish);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
-	iwl_rx_replenish(priv);
+	iwl3945_rx_replenish(priv);
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_post_associate(struct work_struct *data)
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+
+static void iwl3945_bg_post_associate(struct work_struct *data)
 {
-	struct iwl_priv *priv = container_of(data, struct iwl_priv,
+	struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv,
 					     post_associate.work);
 
 	int rc = 0;
@@ -6753,20 +6728,20 @@ static void iwl_bg_post_associate(struct work_struct *data)
 
 	mutex_lock(&priv->mutex);
 
-	if (!priv->interface_id || !priv->is_open) {
+	if (!priv->vif || !priv->is_open) {
 		mutex_unlock(&priv->mutex);
 		return;
 	}
-	iwl_scan_cancel_timeout(priv, 200);
+	iwl3945_scan_cancel_timeout(priv, 200);
 
 	conf = ieee80211_get_hw_conf(priv->hw);
 
 	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_commit_rxon(priv);
+	iwl3945_commit_rxon(priv);
 
-	memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-	iwl_setup_rxon_timing(priv);
-	rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+	memset(&priv->rxon_timing, 0, sizeof(struct iwl3945_rxon_time_cmd));
+	iwl3945_setup_rxon_timing(priv);
+	rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON_TIMING,
 			      sizeof(priv->rxon_timing), &priv->rxon_timing);
 	if (rc)
 		IWL_WARNING("REPLY_RXON_TIMING failed - "
@@ -6795,75 +6770,81 @@ static void iwl_bg_post_associate(struct work_struct *data)
 
 	}
 
-	iwl_commit_rxon(priv);
+	iwl3945_commit_rxon(priv);
 
 	switch (priv->iw_mode) {
 	case IEEE80211_IF_TYPE_STA:
-		iwl_rate_scale_init(priv->hw, IWL_AP_ID);
+		iwl3945_rate_scale_init(priv->hw, IWL_AP_ID);
 		break;
 
 	case IEEE80211_IF_TYPE_IBSS:
 
 		/* clear out the station table */
-		iwl_clear_stations_table(priv);
+		iwl3945_clear_stations_table(priv);
 
-		iwl_add_station(priv, BROADCAST_ADDR, 0, 0);
-		iwl_add_station(priv, priv->bssid, 0, 0);
+		iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0);
+		iwl3945_add_station(priv, priv->bssid, 0, 0);
 		iwl3945_sync_sta(priv, IWL_STA_ID,
 				 (priv->phymode == MODE_IEEE80211A)?
 				 IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
 				 CMD_ASYNC);
-		iwl_rate_scale_init(priv->hw, IWL_STA_ID);
-		iwl_send_beacon_cmd(priv);
+		iwl3945_rate_scale_init(priv->hw, IWL_STA_ID);
+		iwl3945_send_beacon_cmd(priv);
 
 		break;
 
 	default:
 		 IWL_ERROR("%s Should not be called in %d mode\n",
-				__FUNCTION__, priv->iw_mode);
+			   __FUNCTION__, priv->iw_mode);
 		break;
 	}
 
-	iwl_sequence_reset(priv);
+	iwl3945_sequence_reset(priv);
 
-#ifdef CONFIG_IWLWIFI_QOS
-	iwl_activate_qos(priv, 0);
-#endif /* CONFIG_IWLWIFI_QOS */
+#ifdef CONFIG_IWL3945_QOS
+	iwl3945_activate_qos(priv, 0);
+#endif /* CONFIG_IWL3945_QOS */
+	/* we have just associated, don't start scan too early */
+	priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_abort_scan(struct work_struct *work)
+static void iwl3945_bg_abort_scan(struct work_struct *work)
 {
-	struct iwl_priv *priv = container_of(work, struct iwl_priv,
-					     abort_scan);
+	struct iwl3945_priv *priv = container_of(work, struct iwl3945_priv, abort_scan);
 
-	if (!iwl_is_ready(priv))
+	if (!iwl3945_is_ready(priv))
 		return;
 
 	mutex_lock(&priv->mutex);
 
 	set_bit(STATUS_SCAN_ABORTING, &priv->status);
-	iwl_send_scan_abort(priv);
+	iwl3945_send_scan_abort(priv);
 
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_scan_completed(struct work_struct *work)
+static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+
+static void iwl3945_bg_scan_completed(struct work_struct *work)
 {
-	struct iwl_priv *priv =
-	    container_of(work, struct iwl_priv, scan_completed);
+	struct iwl3945_priv *priv =
+	    container_of(work, struct iwl3945_priv, scan_completed);
 
 	IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
+	if (test_bit(STATUS_CONF_PENDING, &priv->status))
+		iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
+
 	ieee80211_scan_completed(priv->hw);
 
 	/* Since setting the TXPOWER may have been deferred while
 	 * performing the scan, fire one off */
 	mutex_lock(&priv->mutex);
-	iwl_hw_reg_send_txpower(priv);
+	iwl3945_hw_reg_send_txpower(priv);
 	mutex_unlock(&priv->mutex);
 }
 
@@ -6873,50 +6854,123 @@ static void iwl_bg_scan_completed(struct work_struct *work)
  *
  *****************************************************************************/
 
-static int iwl_mac_start(struct ieee80211_hw *hw)
+#define UCODE_READY_TIMEOUT	(2 * HZ)
+
+static int iwl3945_mac_start(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
+	int ret;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
+	if (pci_enable_device(priv->pci_dev)) {
+		IWL_ERROR("Fail to pci_enable_device\n");
+		return -ENODEV;
+	}
+	pci_restore_state(priv->pci_dev);
+	pci_enable_msi(priv->pci_dev);
+
+	ret = request_irq(priv->pci_dev->irq, iwl3945_isr, IRQF_SHARED,
+			  DRV_NAME, priv);
+	if (ret) {
+		IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq);
+		goto out_disable_msi;
+	}
+
 	/* we should be verifying the device is ready to be opened */
 	mutex_lock(&priv->mutex);
 
-	priv->is_open = 1;
+	memset(&priv->staging_rxon, 0, sizeof(struct iwl3945_rxon_cmd));
+	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+	 * ucode filename and max sizes are card-specific. */
 
-	if (!iwl_is_rfkill(priv))
-		ieee80211_start_queues(priv->hw);
+	if (!priv->ucode_code.len) {
+		ret = iwl3945_read_ucode(priv);
+		if (ret) {
+			IWL_ERROR("Could not read microcode: %d\n", ret);
+			mutex_unlock(&priv->mutex);
+			goto out_release_irq;
+		}
+	}
+
+	ret = __iwl3945_up(priv);
 
 	mutex_unlock(&priv->mutex);
+
+	if (ret)
+		goto out_release_irq;
+
+	IWL_DEBUG_INFO("Start UP work.\n");
+
+	if (test_bit(STATUS_IN_SUSPEND, &priv->status))
+		return 0;
+
+	/* Wait for START_ALIVE from ucode. Otherwise callbacks from
+	 * mac80211 will not be run successfully. */
+	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+			test_bit(STATUS_READY, &priv->status),
+			UCODE_READY_TIMEOUT);
+	if (!ret) {
+		if (!test_bit(STATUS_READY, &priv->status)) {
+			IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n",
+				  jiffies_to_msecs(UCODE_READY_TIMEOUT));
+			ret = -ETIMEDOUT;
+			goto out_release_irq;
+		}
+	}
+
+	priv->is_open = 1;
 	IWL_DEBUG_MAC80211("leave\n");
 	return 0;
+
+out_release_irq:
+	free_irq(priv->pci_dev->irq, priv);
+out_disable_msi:
+	pci_disable_msi(priv->pci_dev);
+	pci_disable_device(priv->pci_dev);
+	priv->is_open = 0;
+	IWL_DEBUG_MAC80211("leave - failed\n");
+	return ret;
 }
 
-static void iwl_mac_stop(struct ieee80211_hw *hw)
+static void iwl3945_mac_stop(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
+	if (!priv->is_open) {
+		IWL_DEBUG_MAC80211("leave - skip\n");
+		return;
+	}
 
-	mutex_lock(&priv->mutex);
-	/* stop mac, cancel any scan request and clear
-	 * RXON_FILTER_ASSOC_MSK BIT
-	 */
 	priv->is_open = 0;
-	iwl_scan_cancel_timeout(priv, 100);
-	cancel_delayed_work(&priv->post_associate);
-	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_commit_rxon(priv);
-	mutex_unlock(&priv->mutex);
+
+	if (iwl3945_is_ready_rf(priv)) {
+		/* stop mac, cancel any scan request and clear
+		 * RXON_FILTER_ASSOC_MSK BIT
+		 */
+		mutex_lock(&priv->mutex);
+		iwl3945_scan_cancel_timeout(priv, 100);
+		cancel_delayed_work(&priv->post_associate);
+		mutex_unlock(&priv->mutex);
+	}
+
+	iwl3945_down(priv);
+
+	flush_workqueue(priv->workqueue);
+	free_irq(priv->pci_dev->irq, priv);
+	pci_disable_msi(priv->pci_dev);
+	pci_save_state(priv->pci_dev);
+	pci_disable_device(priv->pci_dev);
 
 	IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 		      struct ieee80211_tx_control *ctl)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
@@ -6928,29 +6982,29 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
 		     ctl->tx_rate);
 
-	if (iwl_tx_skb(priv, skb, ctl))
+	if (iwl3945_tx_skb(priv, skb, ctl))
 		dev_kfree_skb_any(skb);
 
 	IWL_DEBUG_MAC80211("leave\n");
 	return 0;
 }
 
-static int iwl_mac_add_interface(struct ieee80211_hw *hw,
+static int iwl3945_mac_add_interface(struct ieee80211_hw *hw,
 				 struct ieee80211_if_init_conf *conf)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 	unsigned long flags;
 	DECLARE_MAC_BUF(mac);
 
-	IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+	IWL_DEBUG_MAC80211("enter: type %d\n", conf->type);
 
-	if (priv->interface_id) {
-		IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+	if (priv->vif) {
+		IWL_DEBUG_MAC80211("leave - vif != NULL\n");
 		return -EOPNOTSUPP;
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
-	priv->interface_id = conf->if_id;
+	priv->vif = conf->vif;
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -6961,106 +7015,108 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw,
 		memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
 	}
 
-	iwl_set_mode(priv, conf->type);
+	if (iwl3945_is_ready(priv))
+		iwl3945_set_mode(priv, conf->type);
 
-	IWL_DEBUG_MAC80211("leave\n");
 	mutex_unlock(&priv->mutex);
 
+	IWL_DEBUG_MAC80211("leave\n");
 	return 0;
 }
 
 /**
- * iwl_mac_config - mac80211 config callback
+ * iwl3945_mac_config - mac80211 config callback
  *
  * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
  * be set inappropriately and the driver currently sets the hardware up to
  * use it whenever needed.
  */
-static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 {
-	struct iwl_priv *priv = hw->priv;
-	const struct iwl_channel_info *ch_info;
+	struct iwl3945_priv *priv = hw->priv;
+	const struct iwl3945_channel_info *ch_info;
 	unsigned long flags;
+	int ret = 0;
 
 	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
 
-	if (!iwl_is_ready(priv)) {
+	priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
+	if (!iwl3945_is_ready(priv)) {
 		IWL_DEBUG_MAC80211("leave - not ready\n");
-		mutex_unlock(&priv->mutex);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 
-	/* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
-	 * what is exposed through include/ declrations */
-	if (unlikely(!iwl_param_disable_hw_scan &&
+	if (unlikely(!iwl3945_param_disable_hw_scan &&
 		     test_bit(STATUS_SCANNING, &priv->status))) {
 		IWL_DEBUG_MAC80211("leave - scanning\n");
+		set_bit(STATUS_CONF_PENDING, &priv->status);
 		mutex_unlock(&priv->mutex);
 		return 0;
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel);
+	ch_info = iwl3945_get_channel_info(priv, conf->phymode, conf->channel);
 	if (!is_channel_valid(ch_info)) {
 		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
 			       conf->channel, conf->phymode);
 		IWL_DEBUG_MAC80211("leave - invalid channel\n");
 		spin_unlock_irqrestore(&priv->lock, flags);
-		mutex_unlock(&priv->mutex);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
-	iwl_set_rxon_channel(priv, conf->phymode, conf->channel);
+	iwl3945_set_rxon_channel(priv, conf->phymode, conf->channel);
 
-	iwl_set_flags_for_phymode(priv, conf->phymode);
+	iwl3945_set_flags_for_phymode(priv, conf->phymode);
 
 	/* The list of supported rates and rate mask can be different
 	 * for each phymode; since the phymode may have changed, reset
 	 * the rate mask to what mac80211 lists */
-	iwl_set_rate(priv);
+	iwl3945_set_rate(priv);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 #ifdef IEEE80211_CONF_CHANNEL_SWITCH
 	if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
-		iwl_hw_channel_switch(priv, conf->channel);
-		mutex_unlock(&priv->mutex);
-		return 0;
+		iwl3945_hw_channel_switch(priv, conf->channel);
+		goto out;
 	}
 #endif
 
-	iwl_radio_kill_sw(priv, !conf->radio_enabled);
+	iwl3945_radio_kill_sw(priv, !conf->radio_enabled);
 
 	if (!conf->radio_enabled) {
 		IWL_DEBUG_MAC80211("leave - radio disabled\n");
-		mutex_unlock(&priv->mutex);
-		return 0;
+		goto out;
 	}
 
-	if (iwl_is_rfkill(priv)) {
+	if (iwl3945_is_rfkill(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF kill\n");
-		mutex_unlock(&priv->mutex);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 
-	iwl_set_rate(priv);
+	iwl3945_set_rate(priv);
 
 	if (memcmp(&priv->active_rxon,
 		   &priv->staging_rxon, sizeof(priv->staging_rxon)))
-		iwl_commit_rxon(priv);
+		iwl3945_commit_rxon(priv);
 	else
 		IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
 
 	IWL_DEBUG_MAC80211("leave\n");
 
+out:
+	clear_bit(STATUS_CONF_PENDING, &priv->status);
 	mutex_unlock(&priv->mutex);
-
-	return 0;
+	return ret;
 }
 
-static void iwl_config_ap(struct iwl_priv *priv)
+static void iwl3945_config_ap(struct iwl3945_priv *priv)
 {
 	int rc = 0;
 
@@ -7072,12 +7128,12 @@ static void iwl_config_ap(struct iwl_priv *priv)
 
 		/* RXON - unassoc (to set timing command) */
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl_commit_rxon(priv);
+		iwl3945_commit_rxon(priv);
 
 		/* RXON Timing */
-		memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-		iwl_setup_rxon_timing(priv);
-		rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+		memset(&priv->rxon_timing, 0, sizeof(struct iwl3945_rxon_time_cmd));
+		iwl3945_setup_rxon_timing(priv);
+		rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON_TIMING,
 				sizeof(priv->rxon_timing), &priv->rxon_timing);
 		if (rc)
 			IWL_WARNING("REPLY_RXON_TIMING failed - "
@@ -7107,20 +7163,21 @@ static void iwl_config_ap(struct iwl_priv *priv)
 		}
 		/* restore RXON assoc */
 		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-		iwl_commit_rxon(priv);
-		iwl_add_station(priv, BROADCAST_ADDR, 0, 0);
+		iwl3945_commit_rxon(priv);
+		iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0);
 	}
-	iwl_send_beacon_cmd(priv);
+	iwl3945_send_beacon_cmd(priv);
 
 	/* FIXME - we need to add code here to detect a totally new
 	 * configuration, reset the AP, unassoc, rxon timing, assoc,
 	 * clear sta table, add BCAST sta... */
 }
 
-static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
+					struct ieee80211_vif *vif,
 				    struct ieee80211_if_conf *conf)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 	DECLARE_MAC_BUF(mac);
 	unsigned long flags;
 	int rc;
@@ -7137,9 +7194,11 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
 		return 0;
 	}
 
+	if (!iwl3945_is_alive(priv))
+		return -EAGAIN;
+
 	mutex_lock(&priv->mutex);
 
-	IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
 	if (conf->bssid)
 		IWL_DEBUG_MAC80211("bssid: %s\n",
 				   print_mac(mac, conf->bssid));
@@ -7156,8 +7215,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
 		return 0;
 	}
 
-	if (priv->interface_id != if_id) {
-		IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+	if (priv->vif != vif) {
+		IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
 		mutex_unlock(&priv->mutex);
 		return 0;
 	}
@@ -7175,11 +7234,14 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
 		priv->ibss_beacon = conf->beacon;
 	}
 
+	if (iwl3945_is_rfkill(priv))
+		goto done;
+
 	if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
 	    !is_multicast_ether_addr(conf->bssid)) {
 		/* If there is currently a HW scan going on in the background
 		 * then we need to cancel it else the RXON below will fail. */
-		if (iwl_scan_cancel_timeout(priv, 100)) {
+		if (iwl3945_scan_cancel_timeout(priv, 100)) {
 			IWL_WARNING("Aborted scan still in progress "
 				    "after 100ms\n");
 			IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
@@ -7195,20 +7257,21 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
 		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 
 		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
-			iwl_config_ap(priv);
+			iwl3945_config_ap(priv);
 		else {
-			rc = iwl_commit_rxon(priv);
+			rc = iwl3945_commit_rxon(priv);
 			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
-				iwl_add_station(priv,
+				iwl3945_add_station(priv,
 					priv->active_rxon.bssid_addr, 1, 0);
 		}
 
 	} else {
-		iwl_scan_cancel_timeout(priv, 100);
+		iwl3945_scan_cancel_timeout(priv, 100);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl_commit_rxon(priv);
+		iwl3945_commit_rxon(priv);
 	}
 
+ done:
 	spin_lock_irqsave(&priv->lock, flags);
 	if (!conf->ssid_len)
 		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
@@ -7224,34 +7287,35 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
 	return 0;
 }
 
-static void iwl_configure_filter(struct ieee80211_hw *hw,
+static void iwl3945_configure_filter(struct ieee80211_hw *hw,
 				 unsigned int changed_flags,
 				 unsigned int *total_flags,
 				 int mc_count, struct dev_addr_list *mc_list)
 {
 	/*
 	 * XXX: dummy
-	 * see also iwl_connection_init_rx_config
+	 * see also iwl3945_connection_init_rx_config
 	 */
 	*total_flags = 0;
 }
 
-static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw,
 				     struct ieee80211_if_init_conf *conf)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
 	mutex_lock(&priv->mutex);
 
-	iwl_scan_cancel_timeout(priv, 100);
-	cancel_delayed_work(&priv->post_associate);
-	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_commit_rxon(priv);
-
-	if (priv->interface_id == conf->if_id) {
-		priv->interface_id = 0;
+	if (iwl3945_is_ready_rf(priv)) {
+		iwl3945_scan_cancel_timeout(priv, 100);
+		cancel_delayed_work(&priv->post_associate);
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl3945_commit_rxon(priv);
+	}
+	if (priv->vif == conf->vif) {
+		priv->vif = NULL;
 		memset(priv->bssid, 0, ETH_ALEN);
 		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
 		priv->essid_len = 0;
@@ -7259,22 +7323,20 @@ static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 	mutex_unlock(&priv->mutex);
 
 	IWL_DEBUG_MAC80211("leave\n");
-
 }
 
-#define IWL_DELAY_NEXT_SCAN (HZ*2)
-static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
 {
 	int rc = 0;
 	unsigned long flags;
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
 	mutex_lock(&priv->mutex);
 	spin_lock_irqsave(&priv->lock, flags);
 
-	if (!iwl_is_ready_rf(priv)) {
+	if (!iwl3945_is_ready_rf(priv)) {
 		rc = -EIO;
 		IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
 		goto out_unlock;
@@ -7286,17 +7348,21 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
 		goto out_unlock;
 	}
 
+	/* we don't schedule scan within next_scan_jiffies period */
+	if (priv->next_scan_jiffies &&
+			time_after(priv->next_scan_jiffies, jiffies)) {
+		rc = -EAGAIN;
+		goto out_unlock;
+	}
 	/* if we just finished scan ask for delay */
-	if (priv->last_scan_jiffies &&
-	    time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
-		       jiffies)) {
+	if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies +
+				IWL_DELAY_NEXT_SCAN, jiffies)) {
 		rc = -EAGAIN;
 		goto out_unlock;
 	}
 	if (len) {
-		IWL_DEBUG_SCAN("direct scan for  "
-			       "%s [%d]\n ",
-			       iwl_escape_essid(ssid, len), (int)len);
+		IWL_DEBUG_SCAN("direct scan for %s [%d]\n ",
+			       iwl3945_escape_essid(ssid, len), (int)len);
 
 		priv->one_direct_scan = 1;
 		priv->direct_ssid_len = (u8)
@@ -7305,7 +7371,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
 	} else
 		priv->one_direct_scan = 0;
 
-	rc = iwl_scan_initiate(priv);
+	rc = iwl3945_scan_initiate(priv);
 
 	IWL_DEBUG_MAC80211("leave\n");
 
@@ -7316,17 +7382,17 @@ out_unlock:
 	return rc;
 }
 
-static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 			   const u8 *local_addr, const u8 *addr,
 			   struct ieee80211_key_conf *key)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 	int rc = 0;
 	u8 sta_id;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
-	if (!iwl_param_hwcrypto) {
+	if (!iwl3945_param_hwcrypto) {
 		IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
 		return -EOPNOTSUPP;
 	}
@@ -7335,7 +7401,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		/* only support pairwise keys */
 		return -EOPNOTSUPP;
 
-	sta_id = iwl_hw_find_station(priv, addr);
+	sta_id = iwl3945_hw_find_station(priv, addr);
 	if (sta_id == IWL_INVALID_STATION) {
 		DECLARE_MAC_BUF(mac);
 
@@ -7346,24 +7412,24 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
 	mutex_lock(&priv->mutex);
 
-	iwl_scan_cancel_timeout(priv, 100);
+	iwl3945_scan_cancel_timeout(priv, 100);
 
 	switch (cmd) {
 	case  SET_KEY:
-		rc = iwl_update_sta_key_info(priv, key, sta_id);
+		rc = iwl3945_update_sta_key_info(priv, key, sta_id);
 		if (!rc) {
-			iwl_set_rxon_hwcrypto(priv, 1);
-			iwl_commit_rxon(priv);
+			iwl3945_set_rxon_hwcrypto(priv, 1);
+			iwl3945_commit_rxon(priv);
 			key->hw_key_idx = sta_id;
 			IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
 			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 		}
 		break;
 	case DISABLE_KEY:
-		rc = iwl_clear_sta_key_info(priv, sta_id);
+		rc = iwl3945_clear_sta_key_info(priv, sta_id);
 		if (!rc) {
-			iwl_set_rxon_hwcrypto(priv, 0);
-			iwl_commit_rxon(priv);
+			iwl3945_set_rxon_hwcrypto(priv, 0);
+			iwl3945_commit_rxon(priv);
 			IWL_DEBUG_MAC80211("disable hwcrypto key\n");
 		}
 		break;
@@ -7377,18 +7443,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 	return rc;
 }
 
-static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue,
 			   const struct ieee80211_tx_queue_params *params)
 {
-	struct iwl_priv *priv = hw->priv;
-#ifdef CONFIG_IWLWIFI_QOS
+	struct iwl3945_priv *priv = hw->priv;
+#ifdef CONFIG_IWL3945_QOS
 	unsigned long flags;
 	int q;
-#endif /* CONFIG_IWL_QOS */
+#endif /* CONFIG_IWL3945_QOS */
 
 	IWL_DEBUG_MAC80211("enter\n");
 
-	if (!iwl_is_ready_rf(priv)) {
+	if (!iwl3945_is_ready_rf(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF not ready\n");
 		return -EIO;
 	}
@@ -7398,7 +7464,7 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
 		return 0;
 	}
 
-#ifdef CONFIG_IWLWIFI_QOS
+#ifdef CONFIG_IWL3945_QOS
 	if (!priv->qos_data.qos_enable) {
 		priv->qos_data.qos_active = 0;
 		IWL_DEBUG_MAC80211("leave - qos not enabled\n");
@@ -7421,30 +7487,30 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
 
 	mutex_lock(&priv->mutex);
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
-		iwl_activate_qos(priv, 1);
-	else if (priv->assoc_id && iwl_is_associated(priv))
-		iwl_activate_qos(priv, 0);
+		iwl3945_activate_qos(priv, 1);
+	else if (priv->assoc_id && iwl3945_is_associated(priv))
+		iwl3945_activate_qos(priv, 0);
 
 	mutex_unlock(&priv->mutex);
 
-#endif /*CONFIG_IWLWIFI_QOS */
+#endif /*CONFIG_IWL3945_QOS */
 
 	IWL_DEBUG_MAC80211("leave\n");
 	return 0;
 }
 
-static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw,
 				struct ieee80211_tx_queue_stats *stats)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 	int i, avail;
-	struct iwl_tx_queue *txq;
-	struct iwl_queue *q;
+	struct iwl3945_tx_queue *txq;
+	struct iwl3945_queue *q;
 	unsigned long flags;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
-	if (!iwl_is_ready_rf(priv)) {
+	if (!iwl3945_is_ready_rf(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF not ready\n");
 		return -EIO;
 	}
@@ -7454,7 +7520,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
 	for (i = 0; i < AC_NUM; i++) {
 		txq = &priv->txq[i];
 		q = &txq->q;
-		avail = iwl_queue_space(q);
+		avail = iwl3945_queue_space(q);
 
 		stats->data[i].len = q->n_window - avail;
 		stats->data[i].limit = q->n_window - q->high_mark;
@@ -7468,7 +7534,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
 	return 0;
 }
 
-static int iwl_mac_get_stats(struct ieee80211_hw *hw,
+static int iwl3945_mac_get_stats(struct ieee80211_hw *hw,
 			     struct ieee80211_low_level_stats *stats)
 {
 	IWL_DEBUG_MAC80211("enter\n");
@@ -7477,7 +7543,7 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
 	return 0;
 }
 
-static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
+static u64 iwl3945_mac_get_tsf(struct ieee80211_hw *hw)
 {
 	IWL_DEBUG_MAC80211("enter\n");
 	IWL_DEBUG_MAC80211("leave\n");
@@ -7485,16 +7551,16 @@ static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
 	return 0;
 }
 
-static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 	unsigned long flags;
 
 	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter\n");
 
-#ifdef CONFIG_IWLWIFI_QOS
-	iwl_reset_qos(priv);
+#ifdef CONFIG_IWL3945_QOS
+	iwl3945_reset_qos(priv);
 #endif
 	cancel_delayed_work(&priv->post_associate);
 
@@ -7517,13 +7583,19 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
+	if (!iwl3945_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - not ready\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
 	/* we are restarting association process
 	 * clear RXON_FILTER_ASSOC_MSK bit
 	*/
 	if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
-		iwl_scan_cancel_timeout(priv, 100);
+		iwl3945_scan_cancel_timeout(priv, 100);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl_commit_rxon(priv);
+		iwl3945_commit_rxon(priv);
 	}
 
 	/* Per mac80211.h: This is only used in IBSS mode... */
@@ -7534,15 +7606,9 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 		return;
 	}
 
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_DEBUG_MAC80211("leave - not ready\n");
-		mutex_unlock(&priv->mutex);
-		return;
-	}
-
 	priv->only_active_channel = 0;
 
-	iwl_set_rate(priv);
+	iwl3945_set_rate(priv);
 
 	mutex_unlock(&priv->mutex);
 
@@ -7550,16 +7616,16 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 
 }
 
-static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 				 struct ieee80211_tx_control *control)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl3945_priv *priv = hw->priv;
 	unsigned long flags;
 
 	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter\n");
 
-	if (!iwl_is_ready_rf(priv)) {
+	if (!iwl3945_is_ready_rf(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF not ready\n");
 		mutex_unlock(&priv->mutex);
 		return -EIO;
@@ -7583,8 +7649,8 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 	IWL_DEBUG_MAC80211("leave\n");
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-#ifdef CONFIG_IWLWIFI_QOS
-	iwl_reset_qos(priv);
+#ifdef CONFIG_IWL3945_QOS
+	iwl3945_reset_qos(priv);
 #endif
 
 	queue_work(priv->workqueue, &priv->post_associate.work);
@@ -7600,7 +7666,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
  *
  *****************************************************************************/
 
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL3945_DEBUG
 
 /*
  * The following adds a new attribute to the sysfs representation
@@ -7612,7 +7678,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 
 static ssize_t show_debug_level(struct device_driver *d, char *buf)
 {
-	return sprintf(buf, "0x%08X\n", iwl_debug_level);
+	return sprintf(buf, "0x%08X\n", iwl3945_debug_level);
 }
 static ssize_t store_debug_level(struct device_driver *d,
 				 const char *buf, size_t count)
@@ -7625,7 +7691,7 @@ static ssize_t store_debug_level(struct device_driver *d,
 		printk(KERN_INFO DRV_NAME
 		       ": %s is not in hex or decimal form.\n", buf);
 	else
-		iwl_debug_level = val;
+		iwl3945_debug_level = val;
 
 	return strnlen(buf, count);
 }
@@ -7633,7 +7699,7 @@ static ssize_t store_debug_level(struct device_driver *d,
 static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
 		   show_debug_level, store_debug_level);
 
-#endif /* CONFIG_IWLWIFI_DEBUG */
+#endif /* CONFIG_IWL3945_DEBUG */
 
 static ssize_t show_rf_kill(struct device *d,
 			    struct device_attribute *attr, char *buf)
@@ -7644,7 +7710,7 @@ static ssize_t show_rf_kill(struct device *d,
 	 * 2 - HW based RF kill active
 	 * 3 - Both HW and SW based RF kill active
 	 */
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 	int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
 		  (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
 
@@ -7655,10 +7721,10 @@ static ssize_t store_rf_kill(struct device *d,
 			     struct device_attribute *attr,
 			     const char *buf, size_t count)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 
 	mutex_lock(&priv->mutex);
-	iwl_radio_kill_sw(priv, buf[0] == '1');
+	iwl3945_radio_kill_sw(priv, buf[0] == '1');
 	mutex_unlock(&priv->mutex);
 
 	return count;
@@ -7669,12 +7735,12 @@ static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
 static ssize_t show_temperature(struct device *d,
 				struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 
-	if (!iwl_is_alive(priv))
+	if (!iwl3945_is_alive(priv))
 		return -EAGAIN;
 
-	return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv));
+	return sprintf(buf, "%d\n", iwl3945_hw_get_temperature(priv));
 }
 
 static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
@@ -7683,15 +7749,15 @@ static ssize_t show_rs_window(struct device *d,
 			      struct device_attribute *attr,
 			      char *buf)
 {
-	struct iwl_priv *priv = d->driver_data;
-	return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID);
+	struct iwl3945_priv *priv = d->driver_data;
+	return iwl3945_fill_rs_info(priv->hw, buf, IWL_AP_ID);
 }
 static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
 
 static ssize_t show_tx_power(struct device *d,
 			     struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 	return sprintf(buf, "%d\n", priv->user_txpower_limit);
 }
 
@@ -7699,7 +7765,7 @@ static ssize_t store_tx_power(struct device *d,
 			      struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 	char *p = (char *)buf;
 	u32 val;
 
@@ -7708,7 +7774,7 @@ static ssize_t store_tx_power(struct device *d,
 		printk(KERN_INFO DRV_NAME
 		       ": %s is not in decimal form.\n", buf);
 	else
-		iwl_hw_reg_set_txpower(priv, val);
+		iwl3945_hw_reg_set_txpower(priv, val);
 
 	return count;
 }
@@ -7718,7 +7784,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
 static ssize_t show_flags(struct device *d,
 			  struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 
 	return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
 }
@@ -7727,19 +7793,19 @@ static ssize_t store_flags(struct device *d,
 			   struct device_attribute *attr,
 			   const char *buf, size_t count)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 	u32 flags = simple_strtoul(buf, NULL, 0);
 
 	mutex_lock(&priv->mutex);
 	if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
 		/* Cancel any currently running scans... */
-		if (iwl_scan_cancel_timeout(priv, 100))
+		if (iwl3945_scan_cancel_timeout(priv, 100))
 			IWL_WARNING("Could not cancel scan.\n");
 		else {
 			IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
 				       flags);
 			priv->staging_rxon.flags = cpu_to_le32(flags);
-			iwl_commit_rxon(priv);
+			iwl3945_commit_rxon(priv);
 		}
 	}
 	mutex_unlock(&priv->mutex);
@@ -7752,7 +7818,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
 static ssize_t show_filter_flags(struct device *d,
 				 struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 
 	return sprintf(buf, "0x%04X\n",
 		le32_to_cpu(priv->active_rxon.filter_flags));
@@ -7762,20 +7828,20 @@ static ssize_t store_filter_flags(struct device *d,
 				  struct device_attribute *attr,
 				  const char *buf, size_t count)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 	u32 filter_flags = simple_strtoul(buf, NULL, 0);
 
 	mutex_lock(&priv->mutex);
 	if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
 		/* Cancel any currently running scans... */
-		if (iwl_scan_cancel_timeout(priv, 100))
+		if (iwl3945_scan_cancel_timeout(priv, 100))
 			IWL_WARNING("Could not cancel scan.\n");
 		else {
 			IWL_DEBUG_INFO("Committing rxon.filter_flags = "
 				       "0x%04X\n", filter_flags);
 			priv->staging_rxon.filter_flags =
 				cpu_to_le32(filter_flags);
-			iwl_commit_rxon(priv);
+			iwl3945_commit_rxon(priv);
 		}
 	}
 	mutex_unlock(&priv->mutex);
@@ -7789,20 +7855,20 @@ static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
 static ssize_t show_tune(struct device *d,
 			 struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 
 	return sprintf(buf, "0x%04X\n",
 		       (priv->phymode << 8) |
 			le16_to_cpu(priv->active_rxon.channel));
 }
 
-static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode);
+static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode);
 
 static ssize_t store_tune(struct device *d,
 			  struct device_attribute *attr,
 			  const char *buf, size_t count)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
 	char *p = (char *)buf;
 	u16 tune = simple_strtoul(p, &p, 0);
 	u8 phymode = (tune >> 8) & 0xff;
@@ -7813,9 +7879,9 @@ static ssize_t store_tune(struct device *d,
 	mutex_lock(&priv->mutex);
 	if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
 	    (priv->phymode != phymode)) {
-		const struct iwl_channel_info *ch_info;
+		const struct iwl3945_channel_info *ch_info;
 
-		ch_info = iwl_get_channel_info(priv, phymode, channel);
+		ch_info = iwl3945_get_channel_info(priv, phymode, channel);
 		if (!ch_info) {
 			IWL_WARNING("Requested invalid phymode/channel "
 				    "combination: %d %d\n", phymode, channel);
@@ -7824,18 +7890,18 @@ static ssize_t store_tune(struct device *d,
 		}
 
 		/* Cancel any currently running scans... */
-		if (iwl_scan_cancel_timeout(priv, 100))
+		if (iwl3945_scan_cancel_timeout(priv, 100))
 			IWL_WARNING("Could not cancel scan.\n");
 		else {
 			IWL_DEBUG_INFO("Committing phymode and "
 				       "rxon.channel = %d %d\n",
 				       phymode, channel);
 
-			iwl_set_rxon_channel(priv, phymode, channel);
-			iwl_set_flags_for_phymode(priv, phymode);
+			iwl3945_set_rxon_channel(priv, phymode, channel);
+			iwl3945_set_flags_for_phymode(priv, phymode);
 
-			iwl_set_rate(priv);
-			iwl_commit_rxon(priv);
+			iwl3945_set_rate(priv);
+			iwl3945_commit_rxon(priv);
 		}
 	}
 	mutex_unlock(&priv->mutex);
@@ -7845,13 +7911,13 @@ static ssize_t store_tune(struct device *d,
 
 static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
 
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
 
 static ssize_t show_measurement(struct device *d,
 				struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	struct iwl_spectrum_notification measure_report;
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_spectrum_notification measure_report;
 	u32 size = sizeof(measure_report), len = 0, ofs = 0;
 	u8 *data = (u8 *) & measure_report;
 	unsigned long flags;
@@ -7883,7 +7949,7 @@ static ssize_t store_measurement(struct device *d,
 				 struct device_attribute *attr,
 				 const char *buf, size_t count)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
 	struct ieee80211_measurement_params params = {
 		.channel = le16_to_cpu(priv->active_rxon.channel),
 		.start_time = cpu_to_le64(priv->last_tsf),
@@ -7909,19 +7975,19 @@ static ssize_t store_measurement(struct device *d,
 
 	IWL_DEBUG_INFO("Invoking measurement of type %d on "
 		       "channel %d (for '%s')\n", type, params.channel, buf);
-	iwl_get_measurement(priv, &params, type);
+	iwl3945_get_measurement(priv, &params, type);
 
 	return count;
 }
 
 static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
 		   show_measurement, store_measurement);
-#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */
+#endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */
 
 static ssize_t show_rate(struct device *d,
 			 struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
 	unsigned long flags;
 	int i;
 
@@ -7932,13 +7998,13 @@ static ssize_t show_rate(struct device *d,
 		i = priv->stations[IWL_STA_ID].current_rate.s.rate;
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-	i = iwl_rate_index_from_plcp(i);
+	i = iwl3945_rate_index_from_plcp(i);
 	if (i == -1)
 		return sprintf(buf, "0\n");
 
 	return sprintf(buf, "%d%s\n",
-		       (iwl_rates[i].ieee >> 1),
-		       (iwl_rates[i].ieee & 0x1) ? ".5" : "");
+		       (iwl3945_rates[i].ieee >> 1),
+		       (iwl3945_rates[i].ieee & 0x1) ? ".5" : "");
 }
 
 static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL);
@@ -7947,7 +8013,7 @@ static ssize_t store_retry_rate(struct device *d,
 				struct device_attribute *attr,
 				const char *buf, size_t count)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
 
 	priv->retry_rate = simple_strtoul(buf, NULL, 0);
 	if (priv->retry_rate <= 0)
@@ -7959,7 +8025,7 @@ static ssize_t store_retry_rate(struct device *d,
 static ssize_t show_retry_rate(struct device *d,
 			       struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
 	return sprintf(buf, "%d", priv->retry_rate);
 }
 
@@ -7970,14 +8036,14 @@ static ssize_t store_power_level(struct device *d,
 				 struct device_attribute *attr,
 				 const char *buf, size_t count)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
 	int rc;
 	int mode;
 
 	mode = simple_strtoul(buf, NULL, 0);
 	mutex_lock(&priv->mutex);
 
-	if (!iwl_is_ready(priv)) {
+	if (!iwl3945_is_ready(priv)) {
 		rc = -EAGAIN;
 		goto out;
 	}
@@ -7988,7 +8054,7 @@ static ssize_t store_power_level(struct device *d,
 		mode |= IWL_POWER_ENABLED;
 
 	if (mode != priv->power_mode) {
-		rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode));
+		rc = iwl3945_send_power_mode(priv, IWL_POWER_LEVEL(mode));
 		if (rc) {
 			IWL_DEBUG_MAC80211("failed setting power mode.\n");
 			goto out;
@@ -8024,7 +8090,7 @@ static const s32 period_duration[] = {
 static ssize_t show_power_level(struct device *d,
 				struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
 	int level = IWL_POWER_LEVEL(priv->power_mode);
 	char *p = buf;
 
@@ -8059,18 +8125,18 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
 static ssize_t show_channels(struct device *d,
 			     struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
 	int len = 0, i;
 	struct ieee80211_channel *channels = NULL;
 	const struct ieee80211_hw_mode *hw_mode = NULL;
 	int count = 0;
 
-	if (!iwl_is_ready(priv))
+	if (!iwl3945_is_ready(priv))
 		return -EAGAIN;
 
-	hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G);
+	hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211G);
 	if (!hw_mode)
-		hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B);
+		hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211B);
 	if (hw_mode) {
 		channels = hw_mode->channels;
 		count = hw_mode->num_channels;
@@ -8097,7 +8163,7 @@ static ssize_t show_channels(struct device *d,
 			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
 			       "active/passive" : "passive only");
 
-	hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A);
+	hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211A);
 	if (hw_mode) {
 		channels = hw_mode->channels;
 		count = hw_mode->num_channels;
@@ -8133,17 +8199,17 @@ static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
 static ssize_t show_statistics(struct device *d,
 			       struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	u32 size = sizeof(struct iwl_notif_statistics);
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
+	u32 size = sizeof(struct iwl3945_notif_statistics);
 	u32 len = 0, ofs = 0;
 	u8 *data = (u8 *) & priv->statistics;
 	int rc = 0;
 
-	if (!iwl_is_alive(priv))
+	if (!iwl3945_is_alive(priv))
 		return -EAGAIN;
 
 	mutex_lock(&priv->mutex);
-	rc = iwl_send_statistics_request(priv);
+	rc = iwl3945_send_statistics_request(priv);
 	mutex_unlock(&priv->mutex);
 
 	if (rc) {
@@ -8171,9 +8237,9 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
 static ssize_t show_antenna(struct device *d,
 			    struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
 
-	if (!iwl_is_alive(priv))
+	if (!iwl3945_is_alive(priv))
 		return -EAGAIN;
 
 	return sprintf(buf, "%d\n", priv->antenna);
@@ -8184,7 +8250,7 @@ static ssize_t store_antenna(struct device *d,
 			     const char *buf, size_t count)
 {
 	int ant;
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl3945_priv *priv = dev_get_drvdata(d);
 
 	if (count == 0)
 		return 0;
@@ -8196,7 +8262,7 @@ static ssize_t store_antenna(struct device *d,
 
 	if ((ant >= 0) && (ant <= 2)) {
 		IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
-		priv->antenna = (enum iwl_antenna)ant;
+		priv->antenna = (enum iwl3945_antenna)ant;
 	} else
 		IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
 
@@ -8209,8 +8275,8 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
 static ssize_t show_status(struct device *d,
 			   struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	if (!iwl_is_alive(priv))
+	struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data;
+	if (!iwl3945_is_alive(priv))
 		return -EAGAIN;
 	return sprintf(buf, "0x%08x\n", (int)priv->status);
 }
@@ -8224,7 +8290,7 @@ static ssize_t dump_error_log(struct device *d,
 	char *p = (char *)buf;
 
 	if (p[0] == '1')
-		iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data);
+		iwl3945_dump_nic_error_log((struct iwl3945_priv *)d->driver_data);
 
 	return strnlen(buf, count);
 }
@@ -8238,7 +8304,7 @@ static ssize_t dump_event_log(struct device *d,
 	char *p = (char *)buf;
 
 	if (p[0] == '1')
-		iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data);
+		iwl3945_dump_nic_event_log((struct iwl3945_priv *)d->driver_data);
 
 	return strnlen(buf, count);
 }
@@ -8251,34 +8317,34 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
  *
  *****************************************************************************/
 
-static void iwl_setup_deferred_work(struct iwl_priv *priv)
+static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv)
 {
 	priv->workqueue = create_workqueue(DRV_NAME);
 
 	init_waitqueue_head(&priv->wait_command_queue);
 
-	INIT_WORK(&priv->up, iwl_bg_up);
-	INIT_WORK(&priv->restart, iwl_bg_restart);
-	INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
-	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
-	INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
-	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
-	INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
-	INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
-	INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate);
-	INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
-	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
-	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
-
-	iwl_hw_setup_deferred_work(priv);
+	INIT_WORK(&priv->up, iwl3945_bg_up);
+	INIT_WORK(&priv->restart, iwl3945_bg_restart);
+	INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish);
+	INIT_WORK(&priv->scan_completed, iwl3945_bg_scan_completed);
+	INIT_WORK(&priv->request_scan, iwl3945_bg_request_scan);
+	INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan);
+	INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill);
+	INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
+	INIT_DELAYED_WORK(&priv->post_associate, iwl3945_bg_post_associate);
+	INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
+	INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
+	INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check);
+
+	iwl3945_hw_setup_deferred_work(priv);
 
 	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
-		     iwl_irq_tasklet, (unsigned long)priv);
+		     iwl3945_irq_tasklet, (unsigned long)priv);
 }
 
-static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+static void iwl3945_cancel_deferred_work(struct iwl3945_priv *priv)
 {
-	iwl_hw_cancel_deferred_work(priv);
+	iwl3945_hw_cancel_deferred_work(priv);
 
 	cancel_delayed_work_sync(&priv->init_alive_start);
 	cancel_delayed_work(&priv->scan_check);
@@ -8287,14 +8353,14 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
 	cancel_work_sync(&priv->beacon_update);
 }
 
-static struct attribute *iwl_sysfs_entries[] = {
+static struct attribute *iwl3945_sysfs_entries[] = {
 	&dev_attr_antenna.attr,
 	&dev_attr_channels.attr,
 	&dev_attr_dump_errors.attr,
 	&dev_attr_dump_events.attr,
 	&dev_attr_flags.attr,
 	&dev_attr_filter_flags.attr,
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
 	&dev_attr_measurement.attr,
 #endif
 	&dev_attr_power_level.attr,
@@ -8311,45 +8377,48 @@ static struct attribute *iwl_sysfs_entries[] = {
 	NULL
 };
 
-static struct attribute_group iwl_attribute_group = {
+static struct attribute_group iwl3945_attribute_group = {
 	.name = NULL,		/* put in device directory */
-	.attrs = iwl_sysfs_entries,
+	.attrs = iwl3945_sysfs_entries,
 };
 
-static struct ieee80211_ops iwl_hw_ops = {
-	.tx = iwl_mac_tx,
-	.start = iwl_mac_start,
-	.stop = iwl_mac_stop,
-	.add_interface = iwl_mac_add_interface,
-	.remove_interface = iwl_mac_remove_interface,
-	.config = iwl_mac_config,
-	.config_interface = iwl_mac_config_interface,
-	.configure_filter = iwl_configure_filter,
-	.set_key = iwl_mac_set_key,
-	.get_stats = iwl_mac_get_stats,
-	.get_tx_stats = iwl_mac_get_tx_stats,
-	.conf_tx = iwl_mac_conf_tx,
-	.get_tsf = iwl_mac_get_tsf,
-	.reset_tsf = iwl_mac_reset_tsf,
-	.beacon_update = iwl_mac_beacon_update,
-	.hw_scan = iwl_mac_hw_scan
+static struct ieee80211_ops iwl3945_hw_ops = {
+	.tx = iwl3945_mac_tx,
+	.start = iwl3945_mac_start,
+	.stop = iwl3945_mac_stop,
+	.add_interface = iwl3945_mac_add_interface,
+	.remove_interface = iwl3945_mac_remove_interface,
+	.config = iwl3945_mac_config,
+	.config_interface = iwl3945_mac_config_interface,
+	.configure_filter = iwl3945_configure_filter,
+	.set_key = iwl3945_mac_set_key,
+	.get_stats = iwl3945_mac_get_stats,
+	.get_tx_stats = iwl3945_mac_get_tx_stats,
+	.conf_tx = iwl3945_mac_conf_tx,
+	.get_tsf = iwl3945_mac_get_tsf,
+	.reset_tsf = iwl3945_mac_reset_tsf,
+	.beacon_update = iwl3945_mac_beacon_update,
+	.hw_scan = iwl3945_mac_hw_scan
 };
 
-static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	int err = 0;
 	u32 pci_id;
-	struct iwl_priv *priv;
+	struct iwl3945_priv *priv;
 	struct ieee80211_hw *hw;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
-	if (iwl_param_disable_hw_scan) {
+	/* Disabling hardware scan means that mac80211 will perform scans
+	 * "the hard way", rather than using device's scan. */
+	if (iwl3945_param_disable_hw_scan) {
 		IWL_DEBUG_INFO("Disabling hw_scan\n");
-		iwl_hw_ops.hw_scan = NULL;
+		iwl3945_hw_ops.hw_scan = NULL;
 	}
 
-	if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) ||
-	    (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) {
+	if ((iwl3945_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+	    (iwl3945_param_queues_num < IWL_MIN_NUM_QUEUES)) {
 		IWL_ERROR("invalid queues_num, should be between %d and %d\n",
 			  IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
 		err = -EINVAL;
@@ -8358,7 +8427,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	/* mac80211 allocates memory for this device instance, including
 	 *   space for this driver's private structure */
-	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops);
+	hw = ieee80211_alloc_hw(sizeof(struct iwl3945_priv), &iwl3945_hw_ops);
 	if (hw == NULL) {
 		IWL_ERROR("Can not allocate network device\n");
 		err = -ENOMEM;
@@ -8373,9 +8442,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	priv->hw = hw;
 
 	priv->pci_dev = pdev;
-	priv->antenna = (enum iwl_antenna)iwl_param_antenna;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	iwl_debug_level = iwl_param_debug;
+
+	/* Select antenna (may be helpful if only one antenna is connected) */
+	priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna;
+#ifdef CONFIG_IWL3945_DEBUG
+	iwl3945_debug_level = iwl3945_param_debug;
 	atomic_set(&priv->restrict_refcnt, 0);
 #endif
 	priv->retry_rate = 1;
@@ -8394,6 +8465,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	/* Tell mac80211 our Tx characteristics */
 	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
 
+	/* 4 EDCA QOS priorities */
 	hw->queues = 4;
 
 	spin_lock_init(&priv->lock);
@@ -8414,7 +8486,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	pci_set_master(pdev);
 
-	iwl_clear_stations_table(priv);
+	/* Clear the driver's (not device's) station table */
+	iwl3945_clear_stations_table(priv);
 
 	priv->data_retry_limit = -1;
 	priv->ieee_channels = NULL;
@@ -8433,9 +8506,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	err = pci_request_regions(pdev, DRV_NAME);
 	if (err)
 		goto out_pci_disable_device;
+
 	/* We disable the RETRY_TIMEOUT register (0x41) to keep
 	 * PCI Tx retries from interfering with C3 CPU state */
 	pci_write_config_byte(pdev, 0x41, 0x00);
+
 	priv->hw_base = pci_iomap(pdev, 0, 0);
 	if (!priv->hw_base) {
 		err = -ENODEV;
@@ -8448,7 +8523,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	/* Initialize module parameter values here */
 
-	if (iwl_param_disable) {
+	/* Disable radio (SW RF KILL) via parameter when loading driver */
+	if (iwl3945_param_disable) {
 		set_bit(STATUS_RF_KILL_SW, &priv->status);
 		IWL_DEBUG_INFO("Radio disabled.\n");
 	}
@@ -8483,78 +8559,82 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	       priv->is_abg ? "A" : "");
 
 	/* Device-specific setup */
-	if (iwl_hw_set_hw_setting(priv)) {
+	if (iwl3945_hw_set_hw_setting(priv)) {
 		IWL_ERROR("failed to set hw settings\n");
-		mutex_unlock(&priv->mutex);
 		goto out_iounmap;
 	}
 
-#ifdef CONFIG_IWLWIFI_QOS
-	if (iwl_param_qos_enable)
+#ifdef CONFIG_IWL3945_QOS
+	if (iwl3945_param_qos_enable)
 		priv->qos_data.qos_enable = 1;
 
-	iwl_reset_qos(priv);
+	iwl3945_reset_qos(priv);
 
 	priv->qos_data.qos_active = 0;
 	priv->qos_data.qos_cap.val = 0;
-#endif /* CONFIG_IWLWIFI_QOS */
+#endif /* CONFIG_IWL3945_QOS */
 
-	iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6);
-	iwl_setup_deferred_work(priv);
-	iwl_setup_rx_handlers(priv);
+	iwl3945_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+	iwl3945_setup_deferred_work(priv);
+	iwl3945_setup_rx_handlers(priv);
 
 	priv->rates_mask = IWL_RATES_MASK;
 	/* If power management is turned on, default to AC mode */
 	priv->power_mode = IWL_POWER_AC;
 	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
 
-	pci_enable_msi(pdev);
+	iwl3945_disable_interrupts(priv);
 
-	err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
-	if (err) {
-		IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
-		goto out_disable_msi;
-	}
-
-	mutex_lock(&priv->mutex);
-
-	err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
+	err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group);
 	if (err) {
 		IWL_ERROR("failed to create sysfs device attributes\n");
-		mutex_unlock(&priv->mutex);
 		goto out_release_irq;
 	}
 
-	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
-	 * ucode filename and max sizes are card-specific. */
-	err = iwl_read_ucode(priv);
+	/* nic init */
+	iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+                    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+        iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+        err = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+        if (err < 0) {
+                IWL_DEBUG_INFO("Failed to init the card\n");
+		goto out_remove_sysfs;
+        }
+	/* Read the EEPROM */
+	err = iwl3945_eeprom_init(priv);
 	if (err) {
-		IWL_ERROR("Could not read microcode: %d\n", err);
-		mutex_unlock(&priv->mutex);
-		goto out_pci_alloc;
+		IWL_ERROR("Unable to init EEPROM\n");
+		goto out_remove_sysfs;
 	}
+	/* MAC Address location in EEPROM same for 3945/4965 */
+	get_eeprom_mac(priv, priv->mac_addr);
+	IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
+	SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
-	mutex_unlock(&priv->mutex);
-
-	IWL_DEBUG_INFO("Queing UP work.\n");
+	iwl3945_rate_control_register(priv->hw);
+	err = ieee80211_register_hw(priv->hw);
+	if (err) {
+		IWL_ERROR("Failed to register network device (error %d)\n", err);
+		goto out_remove_sysfs;
+	}
 
-	queue_work(priv->workqueue, &priv->up);
+	priv->hw->conf.beacon_int = 100;
+	priv->mac80211_registered = 1;
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
 
 	return 0;
 
- out_pci_alloc:
-	iwl_dealloc_ucode_pci(priv);
-
-	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+ out_remove_sysfs:
+	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
 
  out_release_irq:
-	free_irq(pdev->irq, priv);
-
- out_disable_msi:
-	pci_disable_msi(pdev);
 	destroy_workqueue(priv->workqueue);
 	priv->workqueue = NULL;
-	iwl_unset_hw_setting(priv);
+	iwl3945_unset_hw_setting(priv);
 
  out_iounmap:
 	pci_iounmap(pdev, priv->hw_base);
@@ -8569,9 +8649,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	return err;
 }
 
-static void iwl_pci_remove(struct pci_dev *pdev)
+static void iwl3945_pci_remove(struct pci_dev *pdev)
 {
-	struct iwl_priv *priv = pci_get_drvdata(pdev);
+	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
 	struct list_head *p, *q;
 	int i;
 
@@ -8582,43 +8662,41 @@ static void iwl_pci_remove(struct pci_dev *pdev)
 
 	set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-	iwl_down(priv);
+	iwl3945_down(priv);
 
 	/* Free MAC hash list for ADHOC */
 	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
 		list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
 			list_del(p);
-			kfree(list_entry(p, struct iwl_ibss_seq, list));
+			kfree(list_entry(p, struct iwl3945_ibss_seq, list));
 		}
 	}
 
-	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+	sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
 
-	iwl_dealloc_ucode_pci(priv);
+	iwl3945_dealloc_ucode_pci(priv);
 
 	if (priv->rxq.bd)
-		iwl_rx_queue_free(priv, &priv->rxq);
-	iwl_hw_txq_ctx_free(priv);
+		iwl3945_rx_queue_free(priv, &priv->rxq);
+	iwl3945_hw_txq_ctx_free(priv);
 
-	iwl_unset_hw_setting(priv);
-	iwl_clear_stations_table(priv);
+	iwl3945_unset_hw_setting(priv);
+	iwl3945_clear_stations_table(priv);
 
 	if (priv->mac80211_registered) {
 		ieee80211_unregister_hw(priv->hw);
-		iwl_rate_control_unregister(priv->hw);
+		iwl3945_rate_control_unregister(priv->hw);
 	}
 
 	/*netif_stop_queue(dev); */
 	flush_workqueue(priv->workqueue);
 
-	/* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
+	/* ieee80211_unregister_hw calls iwl3945_mac_stop, which flushes
 	 * priv->workqueue... so we can't take down the workqueue
 	 * until now... */
 	destroy_workqueue(priv->workqueue);
 	priv->workqueue = NULL;
 
-	free_irq(pdev->irq, priv);
-	pci_disable_msi(pdev);
 	pci_iounmap(pdev, priv->hw_base);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
@@ -8637,93 +8715,31 @@ static void iwl_pci_remove(struct pci_dev *pdev)
 
 #ifdef CONFIG_PM
 
-static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int iwl3945_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-	struct iwl_priv *priv = pci_get_drvdata(pdev);
-
-	set_bit(STATUS_IN_SUSPEND, &priv->status);
-
-	/* Take down the device; powers it off, etc. */
-	iwl_down(priv);
+	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
 
-	if (priv->mac80211_registered)
-		ieee80211_stop_queues(priv->hw);
+	if (priv->is_open) {
+		set_bit(STATUS_IN_SUSPEND, &priv->status);
+		iwl3945_mac_stop(priv->hw);
+		priv->is_open = 1;
+	}
 
-	pci_save_state(pdev);
-	pci_disable_device(pdev);
 	pci_set_power_state(pdev, PCI_D3hot);
 
 	return 0;
 }
 
-static void iwl_resume(struct iwl_priv *priv)
+static int iwl3945_pci_resume(struct pci_dev *pdev)
 {
-	unsigned long flags;
-
-	/* The following it a temporary work around due to the
-	 * suspend / resume not fully initializing the NIC correctly.
-	 * Without all of the following, resume will not attempt to take
-	 * down the NIC (it shouldn't really need to) and will just try
-	 * and bring the NIC back up.  However that fails during the
-	 * ucode verification process.  This then causes iwl_down to be
-	 * called *after* iwl_hw_nic_init() has succeeded -- which
-	 * then lets the next init sequence succeed.  So, we've
-	 * replicated all of that NIC init code here... */
-
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-
-	iwl_hw_nic_init(priv);
-
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
-		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-	/* tell the device to stop sending interrupts */
-	iwl_disable_interrupts(priv);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-	if (!iwl_grab_restricted_access(priv)) {
-		iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
-					 APMG_CLK_VAL_DMA_CLK_RQT);
-		iwl_release_restricted_access(priv);
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	udelay(5);
-
-	iwl_hw_nic_reset(priv);
-
-	/* Bring the device back up */
-	clear_bit(STATUS_IN_SUSPEND, &priv->status);
-	queue_work(priv->workqueue, &priv->up);
-}
-
-static int iwl_pci_resume(struct pci_dev *pdev)
-{
-	struct iwl_priv *priv = pci_get_drvdata(pdev);
-	int err;
-
-	printk(KERN_INFO "Coming out of suspend...\n");
+	struct iwl3945_priv *priv = pci_get_drvdata(pdev);
 
 	pci_set_power_state(pdev, PCI_D0);
-	err = pci_enable_device(pdev);
-	pci_restore_state(pdev);
 
-	/*
-	 * Suspend/Resume resets the PCI configuration space, so we have to
-	 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
-	 * from interfering with C3 CPU state. pci_restore_state won't help
-	 * here since it only restores the first 64 bytes pci config header.
-	 */
-	pci_write_config_byte(pdev, 0x41, 0x00);
-
-	iwl_resume(priv);
+	if (priv->is_open)
+		iwl3945_mac_start(priv->hw);
 
+	clear_bit(STATUS_IN_SUSPEND, &priv->status);
 	return 0;
 }
 
@@ -8735,33 +8751,33 @@ static int iwl_pci_resume(struct pci_dev *pdev)
  *
  *****************************************************************************/
 
-static struct pci_driver iwl_driver = {
+static struct pci_driver iwl3945_driver = {
 	.name = DRV_NAME,
-	.id_table = iwl_hw_card_ids,
-	.probe = iwl_pci_probe,
-	.remove = __devexit_p(iwl_pci_remove),
+	.id_table = iwl3945_hw_card_ids,
+	.probe = iwl3945_pci_probe,
+	.remove = __devexit_p(iwl3945_pci_remove),
 #ifdef CONFIG_PM
-	.suspend = iwl_pci_suspend,
-	.resume = iwl_pci_resume,
+	.suspend = iwl3945_pci_suspend,
+	.resume = iwl3945_pci_resume,
 #endif
 };
 
-static int __init iwl_init(void)
+static int __init iwl3945_init(void)
 {
 
 	int ret;
 	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
 	printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
-	ret = pci_register_driver(&iwl_driver);
+	ret = pci_register_driver(&iwl3945_driver);
 	if (ret) {
 		IWL_ERROR("Unable to initialize PCI module\n");
 		return ret;
 	}
-#ifdef CONFIG_IWLWIFI_DEBUG
-	ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
+#ifdef CONFIG_IWL3945_DEBUG
+	ret = driver_create_file(&iwl3945_driver.driver, &driver_attr_debug_level);
 	if (ret) {
 		IWL_ERROR("Unable to create driver sysfs file\n");
-		pci_unregister_driver(&iwl_driver);
+		pci_unregister_driver(&iwl3945_driver);
 		return ret;
 	}
 #endif
@@ -8769,32 +8785,32 @@ static int __init iwl_init(void)
 	return ret;
 }
 
-static void __exit iwl_exit(void)
+static void __exit iwl3945_exit(void)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
+#ifdef CONFIG_IWL3945_DEBUG
+	driver_remove_file(&iwl3945_driver.driver, &driver_attr_debug_level);
 #endif
-	pci_unregister_driver(&iwl_driver);
+	pci_unregister_driver(&iwl3945_driver);
 }
 
-module_param_named(antenna, iwl_param_antenna, int, 0444);
+module_param_named(antenna, iwl3945_param_antenna, int, 0444);
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(disable, iwl_param_disable, int, 0444);
+module_param_named(disable, iwl3945_param_disable, int, 0444);
 MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
-module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444);
+module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444);
 MODULE_PARM_DESC(hwcrypto,
 		 "using hardware crypto engine (default 0 [software])\n");
-module_param_named(debug, iwl_param_debug, int, 0444);
+module_param_named(debug, iwl3945_param_debug, int, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
-module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444);
+module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444);
 MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
 
-module_param_named(queues_num, iwl_param_queues_num, int, 0444);
+module_param_named(queues_num, iwl3945_param_queues_num, int, 0444);
 MODULE_PARM_DESC(queues_num, "number of hw queues.");
 
 /* QoS */
-module_param_named(qos_enable, iwl_param_qos_enable, int, 0444);
+module_param_named(qos_enable, iwl3945_param_qos_enable, int, 0444);
 MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
 
-module_exit(iwl_exit);
-module_init(iwl_init);
+module_exit(iwl3945_exit);
+module_init(iwl3945_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 6cd57c220631..c86da5cd1df1 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -27,16 +27,6 @@
  *
  *****************************************************************************/
 
-/*
- * NOTE:  This file (iwl-base.c) is used to build to multiple hardware targets
- * by defining IWL to either 3945 or 4965.  The Makefile used when building
- * the base targets will create base-3945.o and base-4965.o
- *
- * The eventual goal is to move as many of the #if IWL / #endif blocks out of
- * this file and into the hardware specific implementation files (iwl-XXXX.c)
- * and leave only the common (non #ifdef sprinkled) code in this file
- */
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/version.h>
@@ -51,21 +41,20 @@
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 
-#include <net/ieee80211_radiotap.h>
 #include <net/mac80211.h>
 
 #include <asm/div64.h>
 
-#define IWL 4965
-
-#include "iwlwifi.h"
 #include "iwl-4965.h"
 #include "iwl-helpers.h"
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-u32 iwl_debug_level;
+#ifdef CONFIG_IWL4965_DEBUG
+u32 iwl4965_debug_level;
 #endif
 
+static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv,
+				  struct iwl4965_tx_queue *txq);
+
 /******************************************************************************
  *
  * module boiler plate
@@ -73,13 +62,14 @@ u32 iwl_debug_level;
  ******************************************************************************/
 
 /* module parameters */
-int iwl_param_disable_hw_scan;
-int iwl_param_debug;
-int iwl_param_disable;      /* def: enable radio */
-int iwl_param_antenna;      /* def: 0 = both antennas (use diversity) */
-int iwl_param_hwcrypto;     /* def: using software encryption */
-int iwl_param_qos_enable = 1;
-int iwl_param_queues_num = IWL_MAX_NUM_QUEUES;
+static int iwl4965_param_disable_hw_scan; /* def: 0 = use 4965's h/w scan */
+static int iwl4965_param_debug;    /* def: 0 = minimal debug log messages */
+static int iwl4965_param_disable;  /* def: enable radio */
+static int iwl4965_param_antenna;  /* def: 0 = both antennas (use diversity) */
+int iwl4965_param_hwcrypto;        /* def: using software encryption */
+static int iwl4965_param_qos_enable = 1; /* def: 1 = use quality of service */
+int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 16 Tx queues */
+int iwl4965_param_amsdu_size_8K;   /* def: enable 8K amsdu size */
 
 /*
  * module name, copyright, version, etc.
@@ -88,19 +78,19 @@ int iwl_param_queues_num = IWL_MAX_NUM_QUEUES;
 
 #define DRV_DESCRIPTION	"Intel(R) Wireless WiFi Link 4965AGN driver for Linux"
 
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL4965_DEBUG
 #define VD "d"
 #else
 #define VD
 #endif
 
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
 #define VS "s"
 #else
 #define VS
 #endif
 
-#define IWLWIFI_VERSION "1.1.17k" VD VS
+#define IWLWIFI_VERSION "1.2.23k" VD VS
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2007 Intel Corporation"
 #define DRV_VERSION     IWLWIFI_VERSION
 
@@ -125,8 +115,8 @@ __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
 	return NULL;
 }
 
-static const struct ieee80211_hw_mode *iwl_get_hw_mode(
-		struct iwl_priv *priv, int mode)
+static const struct ieee80211_hw_mode *iwl4965_get_hw_mode(
+		struct iwl4965_priv *priv, int mode)
 {
 	int i;
 
@@ -137,7 +127,7 @@ static const struct ieee80211_hw_mode *iwl_get_hw_mode(
 	return NULL;
 }
 
-static int iwl_is_empty_essid(const char *essid, int essid_len)
+static int iwl4965_is_empty_essid(const char *essid, int essid_len)
 {
 	/* Single white space is for Linksys APs */
 	if (essid_len == 1 && essid[0] == ' ')
@@ -153,13 +143,13 @@ static int iwl_is_empty_essid(const char *essid, int essid_len)
 	return 1;
 }
 
-static const char *iwl_escape_essid(const char *essid, u8 essid_len)
+static const char *iwl4965_escape_essid(const char *essid, u8 essid_len)
 {
 	static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
 	const char *s = essid;
 	char *d = escaped;
 
-	if (iwl_is_empty_essid(essid, essid_len)) {
+	if (iwl4965_is_empty_essid(essid, essid_len)) {
 		memcpy(escaped, "<hidden>", sizeof("<hidden>"));
 		return escaped;
 	}
@@ -177,10 +167,10 @@ static const char *iwl_escape_essid(const char *essid, u8 essid_len)
 	return escaped;
 }
 
-static void iwl_print_hex_dump(int level, void *p, u32 len)
+static void iwl4965_print_hex_dump(int level, void *p, u32 len)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (!(iwl_debug_level & level))
+#ifdef CONFIG_IWL4965_DEBUG
+	if (!(iwl4965_debug_level & level))
 		return;
 
 	print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
@@ -193,24 +183,33 @@ static void iwl_print_hex_dump(int level, void *p, u32 len)
  *
  * Theory of operation
  *
- * A queue is a circular buffers with 'Read' and 'Write' pointers.
- * 2 empty entries always kept in the buffer to protect from overflow.
+ * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
+ * of buffer descriptors, each of which points to one or more data buffers for
+ * the device to read from or fill.  Driver and device exchange status of each
+ * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
+ * entries in each circular buffer, to protect against confusing empty and full
+ * queue states.
+ *
+ * The device reads or writes the data in the queues via the device's several
+ * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
  *
  * For Tx queue, there are low mark and high mark limits. If, after queuing
  * the packet for Tx, free space become < low mark, Tx queue stopped. When
  * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
  * Tx queue resumed.
  *
- * The IWL operates with six queues, one receive queue in the device's
- * sram, one transmit queue for sending commands to the device firmware,
- * and four transmit queues for data.
+ * The 4965 operates with up to 17 queues:  One receive queue, one transmit
+ * queue (#4) for sending commands to the device firmware, and 15 other
+ * Tx queues that may be mapped to prioritized Tx DMA/FIFO channels.
+ *
+ * See more detailed info in iwl-4965-hw.h.
  ***************************************************/
 
-static int iwl_queue_space(const struct iwl_queue *q)
+static int iwl4965_queue_space(const struct iwl4965_queue *q)
 {
-	int s = q->last_used - q->first_empty;
+	int s = q->read_ptr - q->write_ptr;
 
-	if (q->last_used > q->first_empty)
+	if (q->read_ptr > q->write_ptr)
 		s -= q->n_bd;
 
 	if (s <= 0)
@@ -222,42 +221,55 @@ static int iwl_queue_space(const struct iwl_queue *q)
 	return s;
 }
 
-/* XXX: n_bd must be power-of-two size */
-static inline int iwl_queue_inc_wrap(int index, int n_bd)
+/**
+ * iwl4965_queue_inc_wrap - increment queue index, wrap back to beginning
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl4965_queue_inc_wrap(int index, int n_bd)
 {
 	return ++index & (n_bd - 1);
 }
 
-/* XXX: n_bd must be power-of-two size */
-static inline int iwl_queue_dec_wrap(int index, int n_bd)
+/**
+ * iwl4965_queue_dec_wrap - decrement queue index, wrap back to end
+ * @index -- current index
+ * @n_bd -- total number of entries in queue (must be power of 2)
+ */
+static inline int iwl4965_queue_dec_wrap(int index, int n_bd)
 {
 	return --index & (n_bd - 1);
 }
 
-static inline int x2_queue_used(const struct iwl_queue *q, int i)
+static inline int x2_queue_used(const struct iwl4965_queue *q, int i)
 {
-	return q->first_empty > q->last_used ?
-		(i >= q->last_used && i < q->first_empty) :
-		!(i < q->last_used && i >= q->first_empty);
+	return q->write_ptr > q->read_ptr ?
+		(i >= q->read_ptr && i < q->write_ptr) :
+		!(i < q->read_ptr && i >= q->write_ptr);
 }
 
-static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge)
 {
+	/* This is for scan command, the big buffer at end of command array */
 	if (is_huge)
-		return q->n_window;
+		return q->n_window;	/* must be power of 2 */
 
+	/* Otherwise, use normal size buffers */
 	return index & (q->n_window - 1);
 }
 
-static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+/**
+ * iwl4965_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
+static int iwl4965_queue_init(struct iwl4965_priv *priv, struct iwl4965_queue *q,
 			  int count, int slots_num, u32 id)
 {
 	q->n_bd = count;
 	q->n_window = slots_num;
 	q->id = id;
 
-	/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
-	 * and iwl_queue_dec_wrap are broken. */
+	/* count must be power-of-two size, otherwise iwl4965_queue_inc_wrap
+	 * and iwl4965_queue_dec_wrap are broken. */
 	BUG_ON(!is_power_of_2(count));
 
 	/* slots_num must be power-of-two size, otherwise
@@ -272,27 +284,34 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
 	if (q->high_mark < 2)
 		q->high_mark = 2;
 
-	q->first_empty = q->last_used = 0;
+	q->write_ptr = q->read_ptr = 0;
 
 	return 0;
 }
 
-static int iwl_tx_queue_alloc(struct iwl_priv *priv,
-			      struct iwl_tx_queue *txq, u32 id)
+/**
+ * iwl4965_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue
+ */
+static int iwl4965_tx_queue_alloc(struct iwl4965_priv *priv,
+			      struct iwl4965_tx_queue *txq, u32 id)
 {
 	struct pci_dev *dev = priv->pci_dev;
 
+	/* Driver private data, only for Tx (not command) queues,
+	 * not shared with device. */
 	if (id != IWL_CMD_QUEUE_NUM) {
 		txq->txb = kmalloc(sizeof(txq->txb[0]) *
 				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
 		if (!txq->txb) {
-			IWL_ERROR("kmalloc for auxilary BD "
+			IWL_ERROR("kmalloc for auxiliary BD "
 				  "structures failed\n");
 			goto error;
 		}
 	} else
 		txq->txb = NULL;
 
+	/* Circular buffer of transmit frame descriptors (TFDs),
+	 * shared with device */
 	txq->bd = pci_alloc_consistent(dev,
 			sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
 			&txq->q.dma_addr);
@@ -315,24 +334,33 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
 	return -ENOMEM;
 }
 
-int iwl_tx_queue_init(struct iwl_priv *priv,
-		      struct iwl_tx_queue *txq, int slots_num, u32 txq_id)
+/**
+ * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue
+ */
+int iwl4965_tx_queue_init(struct iwl4965_priv *priv,
+		      struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id)
 {
 	struct pci_dev *dev = priv->pci_dev;
 	int len;
 	int rc = 0;
 
-	/* alocate command space + one big command for scan since scan
-	 * command is very huge the system will not have two scan at the
-	 * same time */
-	len = sizeof(struct iwl_cmd) * slots_num;
+	/*
+	 * Alloc buffer array for commands (Tx or other types of commands).
+	 * For the command queue (#4), allocate command space + one big
+	 * command for scan, since scan command is very huge; the system will
+	 * not have two scans at the same time, so only one is needed.
+	 * For normal Tx queues (all other queues), no super-size command
+	 * space is needed.
+	 */
+	len = sizeof(struct iwl4965_cmd) * slots_num;
 	if (txq_id == IWL_CMD_QUEUE_NUM)
 		len +=  IWL_MAX_SCAN_SIZE;
 	txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
 	if (!txq->cmd)
 		return -ENOMEM;
 
-	rc = iwl_tx_queue_alloc(priv, txq, txq_id);
+	/* Alloc driver data array and TFD circular buffer */
+	rc = iwl4965_tx_queue_alloc(priv, txq, txq_id);
 	if (rc) {
 		pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
 
@@ -341,26 +369,29 @@ int iwl_tx_queue_init(struct iwl_priv *priv,
 	txq->need_update = 0;
 
 	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
-	 * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+	 * iwl4965_queue_inc_wrap and iwl4965_queue_dec_wrap are broken. */
 	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-	iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
 
-	iwl_hw_tx_queue_init(priv, txq);
+	/* Initialize queue's high/low-water marks, and head/tail indexes */
+	iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+	/* Tell device where to find queue */
+	iwl4965_hw_tx_queue_init(priv, txq);
 
 	return 0;
 }
 
 /**
- * iwl_tx_queue_free - Deallocate DMA queue.
+ * iwl4965_tx_queue_free - Deallocate DMA queue.
  * @txq: Transmit queue to deallocate.
  *
  * Empty queue by removing and destroying all BD's.
- * Free all buffers.  txq itself is not freed.
- *
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
  */
-void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq)
 {
-	struct iwl_queue *q = &txq->q;
+	struct iwl4965_queue *q = &txq->q;
 	struct pci_dev *dev = priv->pci_dev;
 	int len;
 
@@ -368,45 +399,48 @@ void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 		return;
 
 	/* first, empty all BD's */
-	for (; q->first_empty != q->last_used;
-	     q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd))
-		iwl_hw_txq_free_tfd(priv, txq);
+	for (; q->write_ptr != q->read_ptr;
+	     q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd))
+		iwl4965_hw_txq_free_tfd(priv, txq);
 
-	len = sizeof(struct iwl_cmd) * q->n_window;
+	len = sizeof(struct iwl4965_cmd) * q->n_window;
 	if (q->id == IWL_CMD_QUEUE_NUM)
 		len += IWL_MAX_SCAN_SIZE;
 
+	/* De-alloc array of command/tx buffers */
 	pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
 
-	/* free buffers belonging to queue itself */
+	/* De-alloc circular buffer of TFDs */
 	if (txq->q.n_bd)
-		pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
+		pci_free_consistent(dev, sizeof(struct iwl4965_tfd_frame) *
 				    txq->q.n_bd, txq->bd, txq->q.dma_addr);
 
+	/* De-alloc array of per-TFD driver data */
 	if (txq->txb) {
 		kfree(txq->txb);
 		txq->txb = NULL;
 	}
 
-	/* 0 fill whole structure */
+	/* 0-fill queue descriptor structure */
 	memset(txq, 0, sizeof(*txq));
 }
 
-const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
 /*************** STATION TABLE MANAGEMENT ****
- *
- * NOTE:  This needs to be overhauled to better synchronize between
- * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c
- *
- * mac80211 should also be examined to determine if sta_info is duplicating
+ * mac80211 should be examined to determine if sta_info is duplicating
  * the functionality provided here
  */
 
 /**************************************************************/
 
-#if 0 /* temparary disable till we add real remove station */
-static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+#if 0 /* temporary disable till we add real remove station */
+/**
+ * iwl4965_remove_station - Remove driver's knowledge of station.
+ *
+ * NOTE:  This does not remove station from device's station table.
+ */
+static u8 iwl4965_remove_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap)
 {
 	int index = IWL_INVALID_STATION;
 	int i;
@@ -443,7 +477,12 @@ out:
 }
 #endif
 
-static void iwl_clear_stations_table(struct iwl_priv *priv)
+/**
+ * iwl4965_clear_stations_table - Clear the driver's station table
+ *
+ * NOTE:  This does not clear or otherwise alter the device's station table.
+ */
+static void iwl4965_clear_stations_table(struct iwl4965_priv *priv)
 {
 	unsigned long flags;
 
@@ -455,11 +494,15 @@ static void iwl_clear_stations_table(struct iwl_priv *priv)
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
 
-u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
+/**
+ * iwl4965_add_station_flags - Add station to tables in driver and device
+ */
+u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr,
+				int is_ap, u8 flags, void *ht_data)
 {
 	int i;
 	int index = IWL_INVALID_STATION;
-	struct iwl_station_entry *station;
+	struct iwl4965_station_entry *station;
 	unsigned long flags_spin;
 	DECLARE_MAC_BUF(mac);
 
@@ -482,8 +525,8 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
 		}
 
 
-	/* These twh conditions has the same outcome but keep them separate
-	  since they have different meaning */
+	/* These two conditions have the same outcome, but keep them separate
+	  since they have different meanings */
 	if (unlikely(index == IWL_INVALID_STATION)) {
 		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 		return index;
@@ -501,28 +544,32 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
 	station->used = 1;
 	priv->num_stations++;
 
-	memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+	/* Set up the REPLY_ADD_STA command to send to device */
+	memset(&station->sta, 0, sizeof(struct iwl4965_addsta_cmd));
 	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
 	station->sta.mode = 0;
 	station->sta.sta.sta_id = index;
 	station->sta.station_flags = 0;
 
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 	/* BCAST station and IBSS stations do not work in HT mode */
 	if (index != priv->hw_setting.bcast_sta_id &&
 	    priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
-		iwl4965_set_ht_add_station(priv, index);
-#endif /*CONFIG_IWLWIFI_HT*/
+		iwl4965_set_ht_add_station(priv, index,
+				 (struct ieee80211_ht_info *) ht_data);
+#endif /*CONFIG_IWL4965_HT*/
 
 	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
-	iwl_send_add_station(priv, &station->sta, flags);
+
+	/* Add station to device's station table */
+	iwl4965_send_add_station(priv, &station->sta, flags);
 	return index;
 
 }
 
 /*************** DRIVER STATUS FUNCTIONS   *****/
 
-static inline int iwl_is_ready(struct iwl_priv *priv)
+static inline int iwl4965_is_ready(struct iwl4965_priv *priv)
 {
 	/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
 	 * set but EXIT_PENDING is not */
@@ -531,29 +578,29 @@ static inline int iwl_is_ready(struct iwl_priv *priv)
 	       !test_bit(STATUS_EXIT_PENDING, &priv->status);
 }
 
-static inline int iwl_is_alive(struct iwl_priv *priv)
+static inline int iwl4965_is_alive(struct iwl4965_priv *priv)
 {
 	return test_bit(STATUS_ALIVE, &priv->status);
 }
 
-static inline int iwl_is_init(struct iwl_priv *priv)
+static inline int iwl4965_is_init(struct iwl4965_priv *priv)
 {
 	return test_bit(STATUS_INIT, &priv->status);
 }
 
-static inline int iwl_is_rfkill(struct iwl_priv *priv)
+static inline int iwl4965_is_rfkill(struct iwl4965_priv *priv)
 {
 	return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
 	       test_bit(STATUS_RF_KILL_SW, &priv->status);
 }
 
-static inline int iwl_is_ready_rf(struct iwl_priv *priv)
+static inline int iwl4965_is_ready_rf(struct iwl4965_priv *priv)
 {
 
-	if (iwl_is_rfkill(priv))
+	if (iwl4965_is_rfkill(priv))
 		return 0;
 
-	return iwl_is_ready(priv);
+	return iwl4965_is_ready(priv);
 }
 
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
@@ -618,7 +665,7 @@ static const char *get_cmd_string(u8 cmd)
 #define HOST_COMPLETE_TIMEOUT (HZ / 2)
 
 /**
- * iwl_enqueue_hcmd - enqueue a uCode command
+ * iwl4965_enqueue_hcmd - enqueue a uCode command
  * @priv: device private data point
  * @cmd: a point to the ucode command structure
  *
@@ -626,13 +673,13 @@ static const char *get_cmd_string(u8 cmd)
  * failed. On success, it turns the index (> 0) of command in the
  * command queue.
  */
-static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd)
 {
-	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
-	struct iwl_queue *q = &txq->q;
-	struct iwl_tfd_frame *tfd;
+	struct iwl4965_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+	struct iwl4965_queue *q = &txq->q;
+	struct iwl4965_tfd_frame *tfd;
 	u32 *control_flags;
-	struct iwl_cmd *out_cmd;
+	struct iwl4965_cmd *out_cmd;
 	u32 idx;
 	u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
 	dma_addr_t phys_addr;
@@ -645,19 +692,19 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
 	       !(cmd->meta.flags & CMD_SIZE_HUGE));
 
-	if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+	if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
 		IWL_ERROR("No space for Tx\n");
 		return -ENOSPC;
 	}
 
 	spin_lock_irqsave(&priv->hcmd_lock, flags);
 
-	tfd = &txq->bd[q->first_empty];
+	tfd = &txq->bd[q->write_ptr];
 	memset(tfd, 0, sizeof(*tfd));
 
 	control_flags = (u32 *) tfd;
 
-	idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE);
+	idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
 	out_cmd = &txq->cmd[idx];
 
 	out_cmd->hdr.cmd = cmd->id;
@@ -669,30 +716,34 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
 	out_cmd->hdr.flags = 0;
 	out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
-			INDEX_TO_SEQ(q->first_empty));
+			INDEX_TO_SEQ(q->write_ptr));
 	if (out_cmd->meta.flags & CMD_SIZE_HUGE)
 		out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
 
 	phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
-			offsetof(struct iwl_cmd, hdr);
-	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+			offsetof(struct iwl4965_cmd, hdr);
+	iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
 
 	IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
 		     "%d bytes at %d[%d]:%d\n",
 		     get_cmd_string(out_cmd->hdr.cmd),
 		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
-		     fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM);
+		     fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM);
 
 	txq->need_update = 1;
+
+	/* Set up entry in queue's byte count circular buffer */
 	ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
-	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
-	iwl_tx_queue_update_write_ptr(priv, txq);
+
+	/* Increment and update queue's write index */
+	q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd);
+	iwl4965_tx_queue_update_write_ptr(priv, txq);
 
 	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
 	return ret ? ret : idx;
 }
 
-int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+static int iwl4965_send_cmd_async(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd)
 {
 	int ret;
 
@@ -707,16 +758,16 @@ int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return -EBUSY;
 
-	ret = iwl_enqueue_hcmd(priv, cmd);
+	ret = iwl4965_enqueue_hcmd(priv, cmd);
 	if (ret < 0) {
-		IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+		IWL_ERROR("Error sending %s: iwl4965_enqueue_hcmd failed: %d\n",
 			  get_cmd_string(cmd->id), ret);
 		return ret;
 	}
 	return 0;
 }
 
-int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+static int iwl4965_send_cmd_sync(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd)
 {
 	int cmd_idx;
 	int ret;
@@ -738,10 +789,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 	if (cmd->meta.flags & CMD_WANT_SKB)
 		cmd->meta.source = &cmd->meta;
 
-	cmd_idx = iwl_enqueue_hcmd(priv, cmd);
+	cmd_idx = iwl4965_enqueue_hcmd(priv, cmd);
 	if (cmd_idx < 0) {
 		ret = cmd_idx;
-		IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+		IWL_ERROR("Error sending %s: iwl4965_enqueue_hcmd failed: %d\n",
 			  get_cmd_string(cmd->id), ret);
 		goto out;
 	}
@@ -785,7 +836,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
 
 cancel:
 	if (cmd->meta.flags & CMD_WANT_SKB) {
-		struct iwl_cmd *qcmd;
+		struct iwl4965_cmd *qcmd;
 
 		/* Cancel the CMD_WANT_SKB flag for the cmd in the
 		 * TX cmd queue. Otherwise in case the cmd comes
@@ -804,64 +855,75 @@ out:
 	return ret;
 }
 
-int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+int iwl4965_send_cmd(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd)
 {
-	/* A command can not be asynchronous AND expect an SKB to be set. */
-	BUG_ON((cmd->meta.flags & CMD_ASYNC) &&
-	       (cmd->meta.flags & CMD_WANT_SKB));
-
 	if (cmd->meta.flags & CMD_ASYNC)
-		return iwl_send_cmd_async(priv, cmd);
+		return iwl4965_send_cmd_async(priv, cmd);
 
-	return iwl_send_cmd_sync(priv, cmd);
+	return iwl4965_send_cmd_sync(priv, cmd);
 }
 
-int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
+int iwl4965_send_cmd_pdu(struct iwl4965_priv *priv, u8 id, u16 len, const void *data)
 {
-	struct iwl_host_cmd cmd = {
+	struct iwl4965_host_cmd cmd = {
 		.id = id,
 		.len = len,
 		.data = data,
 	};
 
-	return iwl_send_cmd_sync(priv, &cmd);
+	return iwl4965_send_cmd_sync(priv, &cmd);
 }
 
-static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val)
+static int __must_check iwl4965_send_cmd_u32(struct iwl4965_priv *priv, u8 id, u32 val)
 {
-	struct iwl_host_cmd cmd = {
+	struct iwl4965_host_cmd cmd = {
 		.id = id,
 		.len = sizeof(val),
 		.data = &val,
 	};
 
-	return iwl_send_cmd_sync(priv, &cmd);
+	return iwl4965_send_cmd_sync(priv, &cmd);
 }
 
-int iwl_send_statistics_request(struct iwl_priv *priv)
+int iwl4965_send_statistics_request(struct iwl4965_priv *priv)
 {
-	return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
+	return iwl4965_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
 }
 
 /**
- * iwl_rxon_add_station - add station into station table.
+ * iwl4965_rxon_add_station - add station into station table.
  *
  * there is only one AP station with id= IWL_AP_ID
- * NOTE: mutex must be held before calling the this fnction
-*/
-static int iwl_rxon_add_station(struct iwl_priv *priv,
+ * NOTE: mutex must be held before calling this fnction
+ */
+static int iwl4965_rxon_add_station(struct iwl4965_priv *priv,
 				const u8 *addr, int is_ap)
 {
 	u8 sta_id;
 
-	sta_id = iwl_add_station(priv, addr, is_ap, 0);
+	/* Add station to device's station table */
+#ifdef CONFIG_IWL4965_HT
+	struct ieee80211_conf *conf = &priv->hw->conf;
+	struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf;
+
+	if ((is_ap) &&
+	    (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+	    (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+		sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
+						   0, cur_ht_config);
+	else
+#endif /* CONFIG_IWL4965_HT */
+		sta_id = iwl4965_add_station_flags(priv, addr, is_ap,
+						   0, NULL);
+
+	/* Set up default rate scaling table in device's station table */
 	iwl4965_add_station(priv, addr, is_ap);
 
 	return sta_id;
 }
 
 /**
- * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * iwl4965_set_rxon_channel - Set the phymode and channel values in staging RXON
  * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
  * @channel: Any channel valid for the requested phymode
 
@@ -870,9 +932,10 @@ static int iwl_rxon_add_station(struct iwl_priv *priv,
  * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
  * in the staging RXON flag structure based on the phymode
  */
-static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel)
+static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, u8 phymode,
+				 u16 channel)
 {
-	if (!iwl_get_channel_info(priv, phymode, channel)) {
+	if (!iwl4965_get_channel_info(priv, phymode, channel)) {
 		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
 			       channel, phymode);
 		return -EINVAL;
@@ -896,13 +959,13 @@ static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel)
 }
 
 /**
- * iwl_check_rxon_cmd - validate RXON structure is valid
+ * iwl4965_check_rxon_cmd - validate RXON structure is valid
  *
  * NOTE:  This is really only useful during development and can eventually
  * be #ifdef'd out once the driver is stable and folks aren't actively
  * making changes
  */
-static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+static int iwl4965_check_rxon_cmd(struct iwl4965_rxon_cmd *rxon)
 {
 	int error = 0;
 	int counter = 1;
@@ -962,21 +1025,21 @@ static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
 			    le16_to_cpu(rxon->channel));
 
 	if (error) {
-		IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n");
+		IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n");
 		return -1;
 	}
 	return 0;
 }
 
 /**
- * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
- * @priv: staging_rxon is comapred to active_rxon
+ * iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
+ * @priv: staging_rxon is compared to active_rxon
  *
- * If the RXON structure is changing sufficient to require a new
- * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1
- * to indicate a new tune is required.
+ * If the RXON structure is changing enough to require a new tune,
+ * or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
+ * a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
  */
-static int iwl_full_rxon_required(struct iwl_priv *priv)
+static int iwl4965_full_rxon_required(struct iwl4965_priv *priv)
 {
 
 	/* These items are only settable from the full RXON command */
@@ -1016,19 +1079,19 @@ static int iwl_full_rxon_required(struct iwl_priv *priv)
 	return 0;
 }
 
-static int iwl_send_rxon_assoc(struct iwl_priv *priv)
+static int iwl4965_send_rxon_assoc(struct iwl4965_priv *priv)
 {
 	int rc = 0;
-	struct iwl_rx_packet *res = NULL;
-	struct iwl_rxon_assoc_cmd rxon_assoc;
-	struct iwl_host_cmd cmd = {
+	struct iwl4965_rx_packet *res = NULL;
+	struct iwl4965_rxon_assoc_cmd rxon_assoc;
+	struct iwl4965_host_cmd cmd = {
 		.id = REPLY_RXON_ASSOC,
 		.len = sizeof(rxon_assoc),
 		.meta.flags = CMD_WANT_SKB,
 		.data = &rxon_assoc,
 	};
-	const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-	const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+	const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon;
+	const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon;
 
 	if ((rxon1->flags == rxon2->flags) &&
 	    (rxon1->filter_flags == rxon2->filter_flags) &&
@@ -1054,11 +1117,11 @@ static int iwl_send_rxon_assoc(struct iwl_priv *priv)
 	    priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
 	rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
 
-	rc = iwl_send_cmd_sync(priv, &cmd);
+	rc = iwl4965_send_cmd_sync(priv, &cmd);
 	if (rc)
 		return rc;
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
 		rc = -EIO;
@@ -1071,37 +1134,37 @@ static int iwl_send_rxon_assoc(struct iwl_priv *priv)
 }
 
 /**
- * iwl_commit_rxon - commit staging_rxon to hardware
+ * iwl4965_commit_rxon - commit staging_rxon to hardware
  *
- * The RXON command in staging_rxon is commited to the hardware and
+ * The RXON command in staging_rxon is committed to the hardware and
  * the active_rxon structure is updated with the new data.  This
  * function correctly transitions out of the RXON_ASSOC_MSK state if
  * a HW tune is required based on the RXON structure changes.
  */
-static int iwl_commit_rxon(struct iwl_priv *priv)
+static int iwl4965_commit_rxon(struct iwl4965_priv *priv)
 {
 	/* cast away the const for active_rxon in this function */
-	struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+	struct iwl4965_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
 	DECLARE_MAC_BUF(mac);
 	int rc = 0;
 
-	if (!iwl_is_alive(priv))
+	if (!iwl4965_is_alive(priv))
 		return -1;
 
 	/* always get timestamp with Rx frame */
 	priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
 
-	rc = iwl_check_rxon_cmd(&priv->staging_rxon);
+	rc = iwl4965_check_rxon_cmd(&priv->staging_rxon);
 	if (rc) {
 		IWL_ERROR("Invalid RXON configuration.  Not committing.\n");
 		return -EINVAL;
 	}
 
 	/* If we don't need to send a full RXON, we can use
-	 * iwl_rxon_assoc_cmd which is used to reconfigure filter
+	 * iwl4965_rxon_assoc_cmd which is used to reconfigure filter
 	 * and other flags for the current radio configuration. */
-	if (!iwl_full_rxon_required(priv)) {
-		rc = iwl_send_rxon_assoc(priv);
+	if (!iwl4965_full_rxon_required(priv)) {
+		rc = iwl4965_send_rxon_assoc(priv);
 		if (rc) {
 			IWL_ERROR("Error setting RXON_ASSOC "
 				  "configuration (%d).\n", rc);
@@ -1116,25 +1179,25 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
 	/* station table will be cleared */
 	priv->assoc_station_added = 0;
 
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
+#ifdef CONFIG_IWL4965_SENSITIVITY
 	priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
 	if (!priv->error_recovering)
 		priv->start_calib = 0;
 
 	iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
-#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+#endif /* CONFIG_IWL4965_SENSITIVITY */
 
 	/* If we are currently associated and the new config requires
 	 * an RXON_ASSOC and the new config wants the associated mask enabled,
 	 * we must clear the associated from the active configuration
 	 * before we apply the new config */
-	if (iwl_is_associated(priv) &&
+	if (iwl4965_is_associated(priv) &&
 	    (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
 		IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
 		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
-		rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
-				      sizeof(struct iwl_rxon_cmd),
+		rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON,
+				      sizeof(struct iwl4965_rxon_cmd),
 				      &priv->active_rxon);
 
 		/* If the mask clearing failed then we set
@@ -1157,35 +1220,35 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
 		       print_mac(mac, priv->staging_rxon.bssid_addr));
 
 	/* Apply the new configuration */
-	rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
-			      sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+	rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON,
+			      sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon);
 	if (rc) {
 		IWL_ERROR("Error setting new configuration (%d).\n", rc);
 		return rc;
 	}
 
-	iwl_clear_stations_table(priv);
+	iwl4965_clear_stations_table(priv);
 
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
+#ifdef CONFIG_IWL4965_SENSITIVITY
 	if (!priv->error_recovering)
 		priv->start_calib = 0;
 
 	priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
 	iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
-#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+#endif /* CONFIG_IWL4965_SENSITIVITY */
 
 	memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
 
 	/* If we issue a new RXON command which required a tune then we must
 	 * send a new TXPOWER command or we won't be able to Tx any frames */
-	rc = iwl_hw_reg_send_txpower(priv);
+	rc = iwl4965_hw_reg_send_txpower(priv);
 	if (rc) {
 		IWL_ERROR("Error setting Tx power (%d).\n", rc);
 		return rc;
 	}
 
 	/* Add the broadcast address so we can send broadcast frames */
-	if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) ==
+	if (iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0) ==
 	    IWL_INVALID_STATION) {
 		IWL_ERROR("Error adding BROADCAST address for transmit.\n");
 		return -EIO;
@@ -1193,9 +1256,9 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
 
 	/* If we have set the ASSOC_MSK and we are in BSS mode then
 	 * add the IWL_AP_ID to the station rate table */
-	if (iwl_is_associated(priv) &&
+	if (iwl4965_is_associated(priv) &&
 	    (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
-		if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
+		if (iwl4965_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
 		    == IWL_INVALID_STATION) {
 			IWL_ERROR("Error adding AP address for transmit.\n");
 			return -EIO;
@@ -1206,9 +1269,9 @@ static int iwl_commit_rxon(struct iwl_priv *priv)
 	return 0;
 }
 
-static int iwl_send_bt_config(struct iwl_priv *priv)
+static int iwl4965_send_bt_config(struct iwl4965_priv *priv)
 {
-	struct iwl_bt_cmd bt_cmd = {
+	struct iwl4965_bt_cmd bt_cmd = {
 		.flags = 3,
 		.lead_time = 0xAA,
 		.max_kill = 1,
@@ -1216,15 +1279,15 @@ static int iwl_send_bt_config(struct iwl_priv *priv)
 		.kill_cts_mask = 0,
 	};
 
-	return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-				sizeof(struct iwl_bt_cmd), &bt_cmd);
+	return iwl4965_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+				sizeof(struct iwl4965_bt_cmd), &bt_cmd);
 }
 
-static int iwl_send_scan_abort(struct iwl_priv *priv)
+static int iwl4965_send_scan_abort(struct iwl4965_priv *priv)
 {
 	int rc = 0;
-	struct iwl_rx_packet *res;
-	struct iwl_host_cmd cmd = {
+	struct iwl4965_rx_packet *res;
+	struct iwl4965_host_cmd cmd = {
 		.id = REPLY_SCAN_ABORT_CMD,
 		.meta.flags = CMD_WANT_SKB,
 	};
@@ -1237,13 +1300,13 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
 		return 0;
 	}
 
-	rc = iwl_send_cmd_sync(priv, &cmd);
+	rc = iwl4965_send_cmd_sync(priv, &cmd);
 	if (rc) {
 		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
 		return rc;
 	}
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
 	if (res->u.status != CAN_ABORT_STATUS) {
 		/* The scan abort will return 1 for success or
 		 * 2 for "failure".  A failure condition can be
@@ -1261,8 +1324,8 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
 	return rc;
 }
 
-static int iwl_card_state_sync_callback(struct iwl_priv *priv,
-					struct iwl_cmd *cmd,
+static int iwl4965_card_state_sync_callback(struct iwl4965_priv *priv,
+					struct iwl4965_cmd *cmd,
 					struct sk_buff *skb)
 {
 	return 1;
@@ -1271,16 +1334,16 @@ static int iwl_card_state_sync_callback(struct iwl_priv *priv,
 /*
  * CARD_STATE_CMD
  *
- * Use: Sets the internal card state to enable, disable, or halt
+ * Use: Sets the device's internal card state to enable, disable, or halt
  *
  * When in the 'enable' state the card operates as normal.
  * When in the 'disable' state, the card enters into a low power mode.
  * When in the 'halt' state, the card is shut down and must be fully
  * restarted to come back on.
  */
-static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
+static int iwl4965_send_card_state(struct iwl4965_priv *priv, u32 flags, u8 meta_flag)
 {
-	struct iwl_host_cmd cmd = {
+	struct iwl4965_host_cmd cmd = {
 		.id = REPLY_CARD_STATE_CMD,
 		.len = sizeof(u32),
 		.data = &flags,
@@ -1288,22 +1351,22 @@ static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
 	};
 
 	if (meta_flag & CMD_ASYNC)
-		cmd.meta.u.callback = iwl_card_state_sync_callback;
+		cmd.meta.u.callback = iwl4965_card_state_sync_callback;
 
-	return iwl_send_cmd(priv, &cmd);
+	return iwl4965_send_cmd(priv, &cmd);
 }
 
-static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
-				     struct iwl_cmd *cmd, struct sk_buff *skb)
+static int iwl4965_add_sta_sync_callback(struct iwl4965_priv *priv,
+				     struct iwl4965_cmd *cmd, struct sk_buff *skb)
 {
-	struct iwl_rx_packet *res = NULL;
+	struct iwl4965_rx_packet *res = NULL;
 
 	if (!skb) {
 		IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
 		return 1;
 	}
 
-	res = (struct iwl_rx_packet *)skb->data;
+	res = (struct iwl4965_rx_packet *)skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
 			  res->hdr.flags);
@@ -1321,29 +1384,29 @@ static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
 	return 1;
 }
 
-int iwl_send_add_station(struct iwl_priv *priv,
-			 struct iwl_addsta_cmd *sta, u8 flags)
+int iwl4965_send_add_station(struct iwl4965_priv *priv,
+			 struct iwl4965_addsta_cmd *sta, u8 flags)
 {
-	struct iwl_rx_packet *res = NULL;
+	struct iwl4965_rx_packet *res = NULL;
 	int rc = 0;
-	struct iwl_host_cmd cmd = {
+	struct iwl4965_host_cmd cmd = {
 		.id = REPLY_ADD_STA,
-		.len = sizeof(struct iwl_addsta_cmd),
+		.len = sizeof(struct iwl4965_addsta_cmd),
 		.meta.flags = flags,
 		.data = sta,
 	};
 
 	if (flags & CMD_ASYNC)
-		cmd.meta.u.callback = iwl_add_sta_sync_callback;
+		cmd.meta.u.callback = iwl4965_add_sta_sync_callback;
 	else
 		cmd.meta.flags |= CMD_WANT_SKB;
 
-	rc = iwl_send_cmd(priv, &cmd);
+	rc = iwl4965_send_cmd(priv, &cmd);
 
 	if (rc || (flags & CMD_ASYNC))
 		return rc;
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
 			  res->hdr.flags);
@@ -1368,7 +1431,7 @@ int iwl_send_add_station(struct iwl_priv *priv,
 	return rc;
 }
 
-static int iwl_update_sta_key_info(struct iwl_priv *priv,
+static int iwl4965_update_sta_key_info(struct iwl4965_priv *priv,
 				   struct ieee80211_key_conf *keyconf,
 				   u8 sta_id)
 {
@@ -1384,7 +1447,6 @@ static int iwl_update_sta_key_info(struct iwl_priv *priv,
 		break;
 	case ALG_TKIP:
 	case ALG_WEP:
-		return -EINVAL;
 	default:
 		return -EINVAL;
 	}
@@ -1403,28 +1465,28 @@ static int iwl_update_sta_key_info(struct iwl_priv *priv,
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
 	IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
 	return 0;
 }
 
-static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
+static int iwl4965_clear_sta_key_info(struct iwl4965_priv *priv, u8 sta_id)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->sta_lock, flags);
-	memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
-	memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo));
+	memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key));
+	memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo));
 	priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
 	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
 	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 	spin_unlock_irqrestore(&priv->sta_lock, flags);
 
 	IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
-	iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
 	return 0;
 }
 
-static void iwl_clear_free_frames(struct iwl_priv *priv)
+static void iwl4965_clear_free_frames(struct iwl4965_priv *priv)
 {
 	struct list_head *element;
 
@@ -1434,7 +1496,7 @@ static void iwl_clear_free_frames(struct iwl_priv *priv)
 	while (!list_empty(&priv->free_frames)) {
 		element = priv->free_frames.next;
 		list_del(element);
-		kfree(list_entry(element, struct iwl_frame, list));
+		kfree(list_entry(element, struct iwl4965_frame, list));
 		priv->frames_count--;
 	}
 
@@ -1445,9 +1507,9 @@ static void iwl_clear_free_frames(struct iwl_priv *priv)
 	}
 }
 
-static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
+static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl4965_priv *priv)
 {
-	struct iwl_frame *frame;
+	struct iwl4965_frame *frame;
 	struct list_head *element;
 	if (list_empty(&priv->free_frames)) {
 		frame = kzalloc(sizeof(*frame), GFP_KERNEL);
@@ -1462,21 +1524,21 @@ static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
 
 	element = priv->free_frames.next;
 	list_del(element);
-	return list_entry(element, struct iwl_frame, list);
+	return list_entry(element, struct iwl4965_frame, list);
 }
 
-static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
+static void iwl4965_free_frame(struct iwl4965_priv *priv, struct iwl4965_frame *frame)
 {
 	memset(frame, 0, sizeof(*frame));
 	list_add(&frame->list, &priv->free_frames);
 }
 
-unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+unsigned int iwl4965_fill_beacon_frame(struct iwl4965_priv *priv,
 				struct ieee80211_hdr *hdr,
 				const u8 *dest, int left)
 {
 
-	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
+	if (!iwl4965_is_associated(priv) || !priv->ibss_beacon ||
 	    ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
 	     (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
 		return 0;
@@ -1489,10 +1551,11 @@ unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
 	return priv->ibss_beacon->len;
 }
 
-int iwl_rate_index_from_plcp(int plcp)
+int iwl4965_rate_index_from_plcp(int plcp)
 {
 	int i = 0;
 
+	/* 4965 HT rate format */
 	if (plcp & RATE_MCS_HT_MSK) {
 		i = (plcp & 0xff);
 
@@ -1506,35 +1569,37 @@ int iwl_rate_index_from_plcp(int plcp)
 		if ((i >= IWL_FIRST_OFDM_RATE) &&
 		    (i <= IWL_LAST_OFDM_RATE))
 			return i;
+
+	/* 4965 legacy rate format, search for match in table */
 	} else {
-		for (i = 0; i < ARRAY_SIZE(iwl_rates); i++)
-			if (iwl_rates[i].plcp == (plcp &0xFF))
+		for (i = 0; i < ARRAY_SIZE(iwl4965_rates); i++)
+			if (iwl4965_rates[i].plcp == (plcp &0xFF))
 				return i;
 	}
 	return -1;
 }
 
-static u8 iwl_rate_get_lowest_plcp(int rate_mask)
+static u8 iwl4965_rate_get_lowest_plcp(int rate_mask)
 {
 	u8 i;
 
 	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
-	     i = iwl_rates[i].next_ieee) {
+	     i = iwl4965_rates[i].next_ieee) {
 		if (rate_mask & (1 << i))
-			return iwl_rates[i].plcp;
+			return iwl4965_rates[i].plcp;
 	}
 
 	return IWL_RATE_INVALID;
 }
 
-static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+static int iwl4965_send_beacon_cmd(struct iwl4965_priv *priv)
 {
-	struct iwl_frame *frame;
+	struct iwl4965_frame *frame;
 	unsigned int frame_size;
 	int rc;
 	u8 rate;
 
-	frame = iwl_get_free_frame(priv);
+	frame = iwl4965_get_free_frame(priv);
 
 	if (!frame) {
 		IWL_ERROR("Could not obtain free frame buffer for beacon "
@@ -1543,22 +1608,22 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
 	}
 
 	if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
-		rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic &
+		rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic &
 						0xFF0);
 		if (rate == IWL_INVALID_RATE)
 			rate = IWL_RATE_6M_PLCP;
 	} else {
-		rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
+		rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
 		if (rate == IWL_INVALID_RATE)
 			rate = IWL_RATE_1M_PLCP;
 	}
 
-	frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
+	frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate);
 
-	rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
+	rc = iwl4965_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
 			      &frame->u.cmd[0]);
 
-	iwl_free_frame(priv, frame);
+	iwl4965_free_frame(priv, frame);
 
 	return rc;
 }
@@ -1569,22 +1634,22 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv)
  *
  ******************************************************************************/
 
-static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac)
+static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac)
 {
 	memcpy(mac, priv->eeprom.mac_address, 6);
 }
 
 /**
- * iwl_eeprom_init - read EEPROM contents
+ * iwl4965_eeprom_init - read EEPROM contents
  *
- * Load the EEPROM from adapter into priv->eeprom
+ * Load the EEPROM contents from adapter into priv->eeprom
  *
  * NOTE:  This routine uses the non-debug IO access functions.
  */
-int iwl_eeprom_init(struct iwl_priv *priv)
+int iwl4965_eeprom_init(struct iwl4965_priv *priv)
 {
-	u16 *e = (u16 *)&priv->eeprom;
-	u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
+	__le16 *e = (__le16 *)&priv->eeprom;
+	u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP);
 	u32 r;
 	int sz = sizeof(priv->eeprom);
 	int rc;
@@ -1602,20 +1667,21 @@ int iwl_eeprom_init(struct iwl_priv *priv)
 		return -ENOENT;
 	}
 
-	rc = iwl_eeprom_aqcuire_semaphore(priv);
+	/* Make sure driver (instead of uCode) is allowed to read EEPROM */
+	rc = iwl4965_eeprom_acquire_semaphore(priv);
 	if (rc < 0) {
-		IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n");
+		IWL_ERROR("Failed to acquire EEPROM semaphore.\n");
 		return -ENOENT;
 	}
 
 	/* eeprom is an array of 16bit values */
 	for (addr = 0; addr < sz; addr += sizeof(u16)) {
-		_iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
-		_iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+		_iwl4965_write32(priv, CSR_EEPROM_REG, addr << 1);
+		_iwl4965_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
 
 		for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
 					i += IWL_EEPROM_ACCESS_DELAY) {
-			r = _iwl_read_restricted(priv, CSR_EEPROM_REG);
+			r = _iwl4965_read_direct32(priv, CSR_EEPROM_REG);
 			if (r & CSR_EEPROM_REG_READ_VALID_MSK)
 				break;
 			udelay(IWL_EEPROM_ACCESS_DELAY);
@@ -1626,12 +1692,12 @@ int iwl_eeprom_init(struct iwl_priv *priv)
 			rc = -ETIMEDOUT;
 			goto done;
 		}
-		e[addr / 2] = le16_to_cpu(r >> 16);
+		e[addr / 2] = cpu_to_le16(r >> 16);
 	}
 	rc = 0;
 
 done:
-	iwl_eeprom_release_semaphore(priv);
+	iwl4965_eeprom_release_semaphore(priv);
 	return rc;
 }
 
@@ -1640,22 +1706,20 @@ done:
  * Misc. internal state and helper functions
  *
  ******************************************************************************/
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL4965_DEBUG
 
 /**
- * iwl_report_frame - dump frame to syslog during debug sessions
+ * iwl4965_report_frame - dump frame to syslog during debug sessions
  *
- * hack this function to show different aspects of received frames,
+ * You may hack this function to show different aspects of received frames,
  * including selective frame dumps.
  * group100 parameter selects whether to show 1 out of 100 good frames.
  *
- * TODO:  ieee80211_hdr stuff is common to 3945 and 4965, so frame type
- *        info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats)
- *        is 3945-specific and gives bad output for 4965.  Need to split the
- *        functionality, keep common stuff here.
+ * TODO:  This was originally written for 3945, need to audit for
+ *        proper operation with 4965.
  */
-void iwl_report_frame(struct iwl_priv *priv,
-		      struct iwl_rx_packet *pkt,
+void iwl4965_report_frame(struct iwl4965_priv *priv,
+		      struct iwl4965_rx_packet *pkt,
 		      struct ieee80211_hdr *header, int group100)
 {
 	u32 to_us;
@@ -1677,9 +1741,9 @@ void iwl_report_frame(struct iwl_priv *priv,
 	u8 agc;
 	u16 sig_avg;
 	u16 noise_diff;
-	struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
-	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
-	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+	struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt);
 	u8 *data = IWL_RX_DATA(pkt);
 
 	/* MAC header */
@@ -1755,11 +1819,11 @@ void iwl_report_frame(struct iwl_priv *priv,
 		else
 			title = "Frame";
 
-		rate = iwl_rate_index_from_plcp(rate_sym);
+		rate = iwl4965_rate_index_from_plcp(rate_sym);
 		if (rate == -1)
 			rate = 0;
 		else
-			rate = iwl_rates[rate].ieee / 2;
+			rate = iwl4965_rates[rate].ieee / 2;
 
 		/* print frame summary.
 		 * MAC addresses show just the last byte (for brevity),
@@ -1781,25 +1845,25 @@ void iwl_report_frame(struct iwl_priv *priv,
 		}
 	}
 	if (print_dump)
-		iwl_print_hex_dump(IWL_DL_RX, data, length);
+		iwl4965_print_hex_dump(IWL_DL_RX, data, length);
 }
 #endif
 
-static void iwl_unset_hw_setting(struct iwl_priv *priv)
+static void iwl4965_unset_hw_setting(struct iwl4965_priv *priv)
 {
 	if (priv->hw_setting.shared_virt)
 		pci_free_consistent(priv->pci_dev,
-				    sizeof(struct iwl_shared),
+				    sizeof(struct iwl4965_shared),
 				    priv->hw_setting.shared_virt,
 				    priv->hw_setting.shared_phys);
 }
 
 /**
- * iwl_supported_rate_to_ie - fill in the supported rate in IE field
+ * iwl4965_supported_rate_to_ie - fill in the supported rate in IE field
  *
  * return : set the bit for each supported rate insert in ie
  */
-static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate,
 				    u16 basic_rate, int *left)
 {
 	u16 ret_rates = 0, bit;
@@ -1810,7 +1874,7 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
 	for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
 		if (bit & supported_rate) {
 			ret_rates |= bit;
-			rates[*cnt] = iwl_rates[i].ieee |
+			rates[*cnt] = iwl4965_rates[i].ieee |
 				((bit & basic_rate) ? 0x80 : 0x00);
 			(*cnt)++;
 			(*left)--;
@@ -1823,22 +1887,25 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
 	return ret_rates;
 }
 
-#ifdef CONFIG_IWLWIFI_HT
-void static iwl_set_ht_capab(struct ieee80211_hw *hw,
-			     struct ieee80211_ht_capability *ht_cap,
-			     u8 use_wide_chan);
+#ifdef CONFIG_IWL4965_HT
+void static iwl4965_set_ht_capab(struct ieee80211_hw *hw,
+			     struct ieee80211_ht_cap *ht_cap,
+			     u8 use_current_config);
 #endif
 
 /**
- * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ * iwl4965_fill_probe_req - fill in all required fields and IE for probe request
  */
-static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+static u16 iwl4965_fill_probe_req(struct iwl4965_priv *priv,
 			      struct ieee80211_mgmt *frame,
 			      int left, int is_direct)
 {
 	int len = 0;
 	u8 *pos = NULL;
-	u16 active_rates, ret_rates, cck_rates;
+	u16 active_rates, ret_rates, cck_rates, active_rate_basic;
+#ifdef CONFIG_IWL4965_HT
+	struct ieee80211_hw_mode *mode;
+#endif /* CONFIG_IWL4965_HT */
 
 	/* Make sure there is enough space for the probe request,
 	 * two mandatory IEs and the data */
@@ -1848,9 +1915,9 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
 	len += 24;
 
 	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
-	memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN);
+	memcpy(frame->da, iwl4965_broadcast_addr, ETH_ALEN);
 	memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
-	memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN);
+	memcpy(frame->bssid, iwl4965_broadcast_addr, ETH_ALEN);
 	frame->seq_ctrl = 0;
 
 	/* fill in our indirect SSID IE */
@@ -1888,17 +1955,19 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
 	*pos++ = WLAN_EID_SUPP_RATES;
 	*pos = 0;
 
-	priv->active_rate = priv->rates_mask;
-	active_rates = priv->active_rate;
-	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+	/* exclude 60M rate */
+	active_rates = priv->rates_mask;
+	active_rates &= ~IWL_RATE_60M_MASK;
+
+	active_rate_basic = active_rates & IWL_BASIC_RATES_MASK;
 
 	cck_rates = IWL_CCK_RATES_MASK & active_rates;
-	ret_rates = iwl_supported_rate_to_ie(pos, cck_rates,
-			priv->active_rate_basic, &left);
+	ret_rates = iwl4965_supported_rate_to_ie(pos, cck_rates,
+			active_rate_basic, &left);
 	active_rates &= ~ret_rates;
 
-	ret_rates = iwl_supported_rate_to_ie(pos, active_rates,
-				 priv->active_rate_basic, &left);
+	ret_rates = iwl4965_supported_rate_to_ie(pos, active_rates,
+				 active_rate_basic, &left);
 	active_rates &= ~ret_rates;
 
 	len += 2 + *pos;
@@ -1914,25 +1983,22 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
 	/* ... fill it in... */
 	*pos++ = WLAN_EID_EXT_SUPP_RATES;
 	*pos = 0;
-	iwl_supported_rate_to_ie(pos, active_rates,
-				 priv->active_rate_basic, &left);
+	iwl4965_supported_rate_to_ie(pos, active_rates,
+				 active_rate_basic, &left);
 	if (*pos > 0)
 		len += 2 + *pos;
 
-#ifdef CONFIG_IWLWIFI_HT
-	if (is_direct && priv->is_ht_enabled) {
-		u8 use_wide_chan = 1;
-
-		if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
-			use_wide_chan = 0;
+#ifdef CONFIG_IWL4965_HT
+	mode = priv->hw->conf.mode;
+	if (mode->ht_info.ht_supported) {
 		pos += (*pos) + 1;
 		*pos++ = WLAN_EID_HT_CAPABILITY;
-		*pos++ = sizeof(struct ieee80211_ht_capability);
-		iwl_set_ht_capab(NULL, (struct ieee80211_ht_capability *)pos,
-				 use_wide_chan);
-		len += 2 + sizeof(struct ieee80211_ht_capability);
+		*pos++ = sizeof(struct ieee80211_ht_cap);
+		iwl4965_set_ht_capab(priv->hw,
+				(struct ieee80211_ht_cap *)pos, 0);
+		len += 2 + sizeof(struct ieee80211_ht_cap);
 	}
-#endif  /*CONFIG_IWLWIFI_HT */
+#endif  /*CONFIG_IWL4965_HT */
 
  fill_end:
 	return (u16)len;
@@ -1941,16 +2007,16 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
 /*
  * QoS  support
 */
-#ifdef CONFIG_IWLWIFI_QOS
-static int iwl_send_qos_params_command(struct iwl_priv *priv,
-				       struct iwl_qosparam_cmd *qos)
+#ifdef CONFIG_IWL4965_QOS
+static int iwl4965_send_qos_params_command(struct iwl4965_priv *priv,
+				       struct iwl4965_qosparam_cmd *qos)
 {
 
-	return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
-				sizeof(struct iwl_qosparam_cmd), qos);
+	return iwl4965_send_cmd_pdu(priv, REPLY_QOS_PARAM,
+				sizeof(struct iwl4965_qosparam_cmd), qos);
 }
 
-static void iwl_reset_qos(struct iwl_priv *priv)
+static void iwl4965_reset_qos(struct iwl4965_priv *priv)
 {
 	u16 cw_min = 15;
 	u16 cw_max = 1023;
@@ -2037,13 +2103,10 @@ static void iwl_reset_qos(struct iwl_priv *priv)
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+static void iwl4965_activate_qos(struct iwl4965_priv *priv, u8 force)
 {
 	unsigned long flags;
 
-	if (priv == NULL)
-		return;
-
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
@@ -2057,23 +2120,28 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
 	    !priv->qos_data.qos_cap.q_AP.txop_request)
 		priv->qos_data.def_qos_parm.qos_flags |=
 			QOS_PARAM_FLG_TXOP_TYPE_MSK;
-
 	if (priv->qos_data.qos_active)
 		priv->qos_data.def_qos_parm.qos_flags |=
 			QOS_PARAM_FLG_UPDATE_EDCA_MSK;
 
+#ifdef CONFIG_IWL4965_HT
+	if (priv->current_ht_config.is_ht)
+		priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+#endif /* CONFIG_IWL4965_HT */
+
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	if (force || iwl_is_associated(priv)) {
-		IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
-			      priv->qos_data.qos_active);
+	if (force || iwl4965_is_associated(priv)) {
+		IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+				priv->qos_data.qos_active,
+				priv->qos_data.def_qos_parm.qos_flags);
 
-		iwl_send_qos_params_command(priv,
+		iwl4965_send_qos_params_command(priv,
 				&(priv->qos_data.def_qos_parm));
 	}
 }
 
-#endif /* CONFIG_IWLWIFI_QOS */
+#endif /* CONFIG_IWL4965_QOS */
 /*
  * Power management (not Tx power!) functions
  */
@@ -2091,7 +2159,7 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
 
 /* default power management (not Tx power) table values */
 /* for tim  0-10 */
-static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+static struct iwl4965_power_vec_entry range_0[IWL_POWER_AC] = {
 	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
 	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
 	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
@@ -2101,7 +2169,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
 };
 
 /* for tim > 10 */
-static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+static struct iwl4965_power_vec_entry range_1[IWL_POWER_AC] = {
 	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
 	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
 		 SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
@@ -2114,11 +2182,11 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
 		 SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
 };
 
-int iwl_power_init_handle(struct iwl_priv *priv)
+int iwl4965_power_init_handle(struct iwl4965_priv *priv)
 {
 	int rc = 0, i;
-	struct iwl_power_mgr *pow_data;
-	int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
+	struct iwl4965_power_mgr *pow_data;
+	int size = sizeof(struct iwl4965_power_vec_entry) * IWL_POWER_AC;
 	u16 pci_pm;
 
 	IWL_DEBUG_POWER("Initialize power \n");
@@ -2137,7 +2205,7 @@ int iwl_power_init_handle(struct iwl_priv *priv)
 	if (rc != 0)
 		return 0;
 	else {
-		struct iwl_powertable_cmd *cmd;
+		struct iwl4965_powertable_cmd *cmd;
 
 		IWL_DEBUG_POWER("adjust power command flags\n");
 
@@ -2153,15 +2221,15 @@ int iwl_power_init_handle(struct iwl_priv *priv)
 	return rc;
 }
 
-static int iwl_update_power_cmd(struct iwl_priv *priv,
-				struct iwl_powertable_cmd *cmd, u32 mode)
+static int iwl4965_update_power_cmd(struct iwl4965_priv *priv,
+				struct iwl4965_powertable_cmd *cmd, u32 mode)
 {
 	int rc = 0, i;
 	u8 skip;
 	u32 max_sleep = 0;
-	struct iwl_power_vec_entry *range;
+	struct iwl4965_power_vec_entry *range;
 	u8 period = 0;
-	struct iwl_power_mgr *pow_data;
+	struct iwl4965_power_mgr *pow_data;
 
 	if (mode > IWL_POWER_INDEX_5) {
 		IWL_DEBUG_POWER("Error invalid power mode \n");
@@ -2174,7 +2242,7 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
 	else
 		range = &pow_data->pwr_range_1[1];
 
-	memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
+	memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd));
 
 #ifdef IWL_MAC80211_DISABLE
 	if (priv->assoc_network != NULL) {
@@ -2217,14 +2285,14 @@ static int iwl_update_power_cmd(struct iwl_priv *priv,
 	return rc;
 }
 
-static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+static int iwl4965_send_power_mode(struct iwl4965_priv *priv, u32 mode)
 {
-	u32 final_mode = mode;
+	u32 uninitialized_var(final_mode);
 	int rc;
-	struct iwl_powertable_cmd cmd;
+	struct iwl4965_powertable_cmd cmd;
 
 	/* If on battery, set to 3,
-	 * if plugged into AC power, set to CAM ("continuosly aware mode"),
+	 * if plugged into AC power, set to CAM ("continuously aware mode"),
 	 * else user level */
 	switch (mode) {
 	case IWL_POWER_BATTERY:
@@ -2240,9 +2308,9 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
 
 	cmd.keep_alive_beacons = 0;
 
-	iwl_update_power_cmd(priv, &cmd, final_mode);
+	iwl4965_update_power_cmd(priv, &cmd, final_mode);
 
-	rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
+	rc = iwl4965_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
 
 	if (final_mode == IWL_POWER_MODE_CAM)
 		clear_bit(STATUS_POWER_PMI, &priv->status);
@@ -2252,7 +2320,7 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
 	return rc;
 }
 
-int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+int iwl4965_is_network_packet(struct iwl4965_priv *priv, struct ieee80211_hdr *header)
 {
 	/* Filter incoming packets to determine if they are targeted toward
 	 * this network, discarding packets coming from ourselves */
@@ -2282,7 +2350,7 @@ int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
 
 #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
 
-const char *iwl_get_tx_fail_reason(u32 status)
+static const char *iwl4965_get_tx_fail_reason(u32 status)
 {
 	switch (status & TX_STATUS_MSK) {
 	case TX_STATUS_SUCCESS:
@@ -2309,11 +2377,11 @@ const char *iwl_get_tx_fail_reason(u32 status)
 }
 
 /**
- * iwl_scan_cancel - Cancel any currently executing HW scan
+ * iwl4965_scan_cancel - Cancel any currently executing HW scan
  *
  * NOTE: priv->mutex is not required before calling this function
  */
-static int iwl_scan_cancel(struct iwl_priv *priv)
+static int iwl4965_scan_cancel(struct iwl4965_priv *priv)
 {
 	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
 		clear_bit(STATUS_SCANNING, &priv->status);
@@ -2336,17 +2404,17 @@ static int iwl_scan_cancel(struct iwl_priv *priv)
 }
 
 /**
- * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
+ * iwl4965_scan_cancel_timeout - Cancel any currently executing HW scan
  * @ms: amount of time to wait (in milliseconds) for scan to abort
  *
  * NOTE: priv->mutex must be held before calling this function
  */
-static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+static int iwl4965_scan_cancel_timeout(struct iwl4965_priv *priv, unsigned long ms)
 {
 	unsigned long now = jiffies;
 	int ret;
 
-	ret = iwl_scan_cancel(priv);
+	ret = iwl4965_scan_cancel(priv);
 	if (ret && ms) {
 		mutex_unlock(&priv->mutex);
 		while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
@@ -2360,7 +2428,7 @@ static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
 	return ret;
 }
 
-static void iwl_sequence_reset(struct iwl_priv *priv)
+static void iwl4965_sequence_reset(struct iwl4965_priv *priv)
 {
 	/* Reset ieee stats */
 
@@ -2371,13 +2439,13 @@ static void iwl_sequence_reset(struct iwl_priv *priv)
 	priv->last_frag_num = -1;
 	priv->last_packet_time = 0;
 
-	iwl_scan_cancel(priv);
+	iwl4965_scan_cancel(priv);
 }
 
 #define MAX_UCODE_BEACON_INTERVAL	4096
 #define INTEL_CONN_LISTEN_INTERVAL	__constant_cpu_to_le16(0xA)
 
-static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
+static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val)
 {
 	u16 new_val = 0;
 	u16 beacon_factor = 0;
@@ -2390,7 +2458,7 @@ static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
 	return cpu_to_le16(new_val);
 }
 
-static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+static void iwl4965_setup_rxon_timing(struct iwl4965_priv *priv)
 {
 	u64 interval_tm_unit;
 	u64 tsf, result;
@@ -2420,14 +2488,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
 			priv->rxon_timing.beacon_interval =
 				cpu_to_le16(beacon_int);
 			priv->rxon_timing.beacon_interval =
-			    iwl_adjust_beacon_interval(
+			    iwl4965_adjust_beacon_interval(
 				le16_to_cpu(priv->rxon_timing.beacon_interval));
 		}
 
 		priv->rxon_timing.atim_window = 0;
 	} else {
 		priv->rxon_timing.beacon_interval =
-			iwl_adjust_beacon_interval(conf->beacon_int);
+			iwl4965_adjust_beacon_interval(conf->beacon_int);
 		/* TODO: we need to get atim_window from upper stack
 		 * for now we set to 0 */
 		priv->rxon_timing.atim_window = 0;
@@ -2446,14 +2514,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv)
 		le16_to_cpu(priv->rxon_timing.atim_window));
 }
 
-static int iwl_scan_initiate(struct iwl_priv *priv)
+static int iwl4965_scan_initiate(struct iwl4965_priv *priv)
 {
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
 		IWL_ERROR("APs don't scan.\n");
 		return 0;
 	}
 
-	if (!iwl_is_ready_rf(priv)) {
+	if (!iwl4965_is_ready_rf(priv)) {
 		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
 		return -EIO;
 	}
@@ -2480,9 +2548,9 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
 	return 0;
 }
 
-static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+static int iwl4965_set_rxon_hwcrypto(struct iwl4965_priv *priv, int hw_decrypt)
 {
-	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+	struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
 
 	if (hw_decrypt)
 		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
@@ -2492,7 +2560,7 @@ static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
 	return 0;
 }
 
-static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode)
 {
 	if (phymode == MODE_IEEE80211A) {
 		priv->staging_rxon.flags &=
@@ -2500,7 +2568,7 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
 		      | RXON_FLG_CCK_MSK);
 		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
 	} else {
-		/* Copied from iwl_bg_post_associate() */
+		/* Copied from iwl4965_bg_post_associate() */
 		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
 			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
 		else
@@ -2516,11 +2584,11 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
 }
 
 /*
- * initilize rxon structure with default values fromm eeprom
+ * initialize rxon structure with default values from eeprom
  */
-static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv)
 {
-	const struct iwl_channel_info *ch_info;
+	const struct iwl4965_channel_info *ch_info;
 
 	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
@@ -2557,7 +2625,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
 		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
 #endif
 
-	ch_info = iwl_get_channel_info(priv, priv->phymode,
+	ch_info = iwl4965_get_channel_info(priv, priv->phymode,
 				       le16_to_cpu(priv->staging_rxon.channel));
 
 	if (!ch_info)
@@ -2577,7 +2645,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
 	else
 		priv->phymode = MODE_IEEE80211G;
 
-	iwl_set_flags_for_phymode(priv, priv->phymode);
+	iwl4965_set_flags_for_phymode(priv, priv->phymode);
 
 	priv->staging_rxon.ofdm_basic_rates =
 	    (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
@@ -2593,15 +2661,12 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv)
 	iwl4965_set_rxon_chain(priv);
 }
 
-static int iwl_set_mode(struct iwl_priv *priv, int mode)
+static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode)
 {
-	if (!iwl_is_ready_rf(priv))
-		return -EAGAIN;
-
 	if (mode == IEEE80211_IF_TYPE_IBSS) {
-		const struct iwl_channel_info *ch_info;
+		const struct iwl4965_channel_info *ch_info;
 
-		ch_info = iwl_get_channel_info(priv,
+		ch_info = iwl4965_get_channel_info(priv,
 			priv->phymode,
 			le16_to_cpu(priv->staging_rxon.channel));
 
@@ -2612,32 +2677,36 @@ static int iwl_set_mode(struct iwl_priv *priv, int mode)
 		}
 	}
 
+	priv->iw_mode = mode;
+
+	iwl4965_connection_init_rx_config(priv);
+	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+	iwl4965_clear_stations_table(priv);
+
+	/* dont commit rxon if rf-kill is on*/
+	if (!iwl4965_is_ready_rf(priv))
+		return -EAGAIN;
+
 	cancel_delayed_work(&priv->scan_check);
-	if (iwl_scan_cancel_timeout(priv, 100)) {
+	if (iwl4965_scan_cancel_timeout(priv, 100)) {
 		IWL_WARNING("Aborted scan still in progress after 100ms\n");
 		IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
 		return -EAGAIN;
 	}
 
-	priv->iw_mode = mode;
-
-	iwl_connection_init_rx_config(priv);
-	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
-
-	iwl_clear_stations_table(priv);
-
-	iwl_commit_rxon(priv);
+	iwl4965_commit_rxon(priv);
 
 	return 0;
 }
 
-static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
+static void iwl4965_build_tx_cmd_hwcrypto(struct iwl4965_priv *priv,
 				      struct ieee80211_tx_control *ctl,
-				      struct iwl_cmd *cmd,
+				      struct iwl4965_cmd *cmd,
 				      struct sk_buff *skb_frag,
 				      int last_frag)
 {
-	struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+	struct iwl4965_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
 
 	switch (keyinfo->alg) {
 	case ALG_CCMP:
@@ -2680,8 +2749,8 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
 /*
  * handle build REPLY_TX command notification.
  */
-static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
-				  struct iwl_cmd *cmd,
+static void iwl4965_build_tx_cmd_basic(struct iwl4965_priv *priv,
+				  struct iwl4965_cmd *cmd,
 				  struct ieee80211_tx_control *ctrl,
 				  struct ieee80211_hdr *hdr,
 				  int is_unicast, u8 std_id)
@@ -2703,6 +2772,10 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
 		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
 	}
 
+	if (ieee80211_is_back_request(fc))
+		tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+
+
 	cmd->cmd.tx.sta_id = std_id;
 	if (ieee80211_get_morefrag(hdr))
 		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
@@ -2729,11 +2802,9 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
 	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
 		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
 		    (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
-			cmd->cmd.tx.timeout.pm_frame_timeout =
-				cpu_to_le16(3);
+			cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3);
 		else
-			cmd->cmd.tx.timeout.pm_frame_timeout =
-				cpu_to_le16(2);
+			cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2);
 	} else
 		cmd->cmd.tx.timeout.pm_frame_timeout = 0;
 
@@ -2742,40 +2813,47 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
 	cmd->cmd.tx.next_frame_len = 0;
 }
 
-static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+/**
+ * iwl4965_get_sta_id - Find station's index within station table
+ *
+ * If new IBSS station, create new entry in station table
+ */
+static int iwl4965_get_sta_id(struct iwl4965_priv *priv,
+				struct ieee80211_hdr *hdr)
 {
 	int sta_id;
 	u16 fc = le16_to_cpu(hdr->frame_control);
 	DECLARE_MAC_BUF(mac);
 
-	/* If this frame is broadcast or not data then use the broadcast
-	 * station id */
+	/* If this frame is broadcast or management, use broadcast station id */
 	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
 	    is_multicast_ether_addr(hdr->addr1))
 		return priv->hw_setting.bcast_sta_id;
 
 	switch (priv->iw_mode) {
 
-	/* If this frame is part of a BSS network (we're a station), then
-	 * we use the AP's station id */
+	/* If we are a client station in a BSS network, use the special
+	 * AP station entry (that's the only station we communicate with) */
 	case IEEE80211_IF_TYPE_STA:
 		return IWL_AP_ID;
 
 	/* If we are an AP, then find the station, or use BCAST */
 	case IEEE80211_IF_TYPE_AP:
-		sta_id = iwl_hw_find_station(priv, hdr->addr1);
+		sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
 		return priv->hw_setting.bcast_sta_id;
 
-	/* If this frame is part of a IBSS network, then we use the
-	 * target specific station id */
+	/* If this frame is going out to an IBSS network, find the station,
+	 * or create a new station table entry */
 	case IEEE80211_IF_TYPE_IBSS:
-		sta_id = iwl_hw_find_station(priv, hdr->addr1);
+		sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
 
-		sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
+		/* Create new station table entry */
+		sta_id = iwl4965_add_station_flags(priv, hdr->addr1,
+						   0, CMD_ASYNC, NULL);
 
 		if (sta_id != IWL_INVALID_STATION)
 			return sta_id;
@@ -2783,11 +2861,11 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
 		IWL_DEBUG_DROP("Station %s not in station map. "
 			       "Defaulting to broadcast...\n",
 			       print_mac(mac, hdr->addr1));
-		iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+		iwl4965_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
 		return priv->hw_setting.bcast_sta_id;
 
 	default:
-		IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode);
+		IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
 		return priv->hw_setting.bcast_sta_id;
 	}
 }
@@ -2795,18 +2873,19 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
 /*
  * start REPLY_TX command process
  */
-static int iwl_tx_skb(struct iwl_priv *priv,
+static int iwl4965_tx_skb(struct iwl4965_priv *priv,
 		      struct sk_buff *skb, struct ieee80211_tx_control *ctl)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct iwl_tfd_frame *tfd;
+	struct iwl4965_tfd_frame *tfd;
 	u32 *control_flags;
 	int txq_id = ctl->queue;
-	struct iwl_tx_queue *txq = NULL;
-	struct iwl_queue *q = NULL;
+	struct iwl4965_tx_queue *txq = NULL;
+	struct iwl4965_queue *q = NULL;
 	dma_addr_t phys_addr;
 	dma_addr_t txcmd_phys;
-	struct iwl_cmd *out_cmd = NULL;
+	dma_addr_t scratch_phys;
+	struct iwl4965_cmd *out_cmd = NULL;
 	u16 len, idx, len_org;
 	u8 id, hdr_len, unicast;
 	u8 sta_id;
@@ -2818,13 +2897,13 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 	int rc;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if (iwl_is_rfkill(priv)) {
+	if (iwl4965_is_rfkill(priv)) {
 		IWL_DEBUG_DROP("Dropping - RF KILL\n");
 		goto drop_unlock;
 	}
 
-	if (!priv->interface_id) {
-		IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+	if (!priv->vif) {
+		IWL_DEBUG_DROP("Dropping - !priv->vif\n");
 		goto drop_unlock;
 	}
 
@@ -2838,7 +2917,7 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 
 	fc = le16_to_cpu(hdr->frame_control);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL4965_DEBUG
 	if (ieee80211_is_auth(fc))
 		IWL_DEBUG_TX("Sending AUTH frame\n");
 	else if (ieee80211_is_assoc_request(fc))
@@ -2847,16 +2926,19 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 		IWL_DEBUG_TX("Sending REASSOC frame\n");
 #endif
 
-	if (!iwl_is_associated(priv) &&
+	/* drop all data frame if we are not associated */
+	if (!iwl4965_is_associated(priv) && !priv->assoc_id &&
 	    ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
-		IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
+		IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n");
 		goto drop_unlock;
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	hdr_len = ieee80211_get_hdrlen(fc);
-	sta_id = iwl_get_sta_id(priv, hdr);
+
+	/* Find (or create) index into station table for destination station */
+	sta_id = iwl4965_get_sta_id(priv, hdr);
 	if (sta_id == IWL_INVALID_STATION) {
 		DECLARE_MAC_BUF(mac);
 
@@ -2876,40 +2958,62 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 			(hdr->seq_ctrl &
 				__constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
 		seq_number += 0x10;
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 		/* aggregation is on for this <sta,tid> */
 		if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG)
 			txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
-#endif /* CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 	}
+
+	/* Descriptor for chosen Tx queue */
 	txq = &priv->txq[txq_id];
 	q = &txq->q;
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	tfd = &txq->bd[q->first_empty];
+	/* Set up first empty TFD within this queue's circular TFD buffer */
+	tfd = &txq->bd[q->write_ptr];
 	memset(tfd, 0, sizeof(*tfd));
 	control_flags = (u32 *) tfd;
-	idx = get_cmd_index(q, q->first_empty, 0);
+	idx = get_cmd_index(q, q->write_ptr, 0);
 
-	memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info));
-	txq->txb[q->first_empty].skb[0] = skb;
-	memcpy(&(txq->txb[q->first_empty].status.control),
+	/* Set up driver data for this TFD */
+	memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl4965_tx_info));
+	txq->txb[q->write_ptr].skb[0] = skb;
+	memcpy(&(txq->txb[q->write_ptr].status.control),
 	       ctl, sizeof(struct ieee80211_tx_control));
+
+	/* Set up first empty entry in queue's array of Tx/cmd buffers */
 	out_cmd = &txq->cmd[idx];
 	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
 	memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+
+	/*
+	 * Set up the Tx-command (not MAC!) header.
+	 * Store the chosen Tx queue and TFD index within the sequence field;
+	 * after Tx, uCode's Tx response will return this value so driver can
+	 * locate the frame within the tx queue and do post-tx processing.
+	 */
 	out_cmd->hdr.cmd = REPLY_TX;
 	out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
-				INDEX_TO_SEQ(q->first_empty)));
-	/* copy frags header */
+				INDEX_TO_SEQ(q->write_ptr)));
+
+	/* Copy MAC header from skb into command buffer */
 	memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
 
-	/* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */
+	/*
+	 * Use the first empty entry in this queue's command buffer array
+	 * to contain the Tx command and MAC header concatenated together
+	 * (payload data will be in another buffer).
+	 * Size of this varies, due to varying MAC header length.
+	 * If end is not dword aligned, we'll have 2 extra bytes at the end
+	 * of the MAC header (device reads on dword boundaries).
+	 * We'll tell device about this padding later.
+	 */
 	len = priv->hw_setting.tx_cmd_len +
-		sizeof(struct iwl_cmd_header) + hdr_len;
+		sizeof(struct iwl4965_cmd_header) + hdr_len;
 
 	len_org = len;
 	len = (len + 3) & ~3;
@@ -2919,36 +3023,53 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 	else
 		len_org = 0;
 
-	txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
-		     offsetof(struct iwl_cmd, hdr);
+	/* Physical address of this Tx command's header (not MAC header!),
+	 * within command buffer array. */
+	txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl4965_cmd) * idx +
+		     offsetof(struct iwl4965_cmd, hdr);
 
-	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+	/* Add buffer containing Tx command and MAC(!) header to TFD's
+	 * first entry */
+	iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
 
 	if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
-		iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+		iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
 
-	/* 802.11 null functions have no payload... */
+	/* Set up TFD's 2nd entry to point directly to remainder of skb,
+	 * if any (802.11 null frames have no payload). */
 	len = skb->len - hdr_len;
 	if (len) {
 		phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
 					   len, PCI_DMA_TODEVICE);
-		iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+		iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
 	}
 
+	/* Tell 4965 about any 2-byte padding after MAC header */
 	if (len_org)
 		out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
 
+	/* Total # bytes to be transmitted */
 	len = (u16)skb->len;
 	out_cmd->cmd.tx.len = cpu_to_le16(len);
 
 	/* TODO need this for burst mode later on */
-	iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+	iwl4965_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
 
 	/* set is_hcca to 0; it probably will never be implemented */
-	iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+	iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+
+	scratch_phys = txcmd_phys + sizeof(struct iwl4965_cmd_header) +
+		offsetof(struct iwl4965_tx_cmd, scratch);
+	out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys);
+	out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys);
+
+#ifdef CONFIG_IWL4965_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+	/* TODO: move this functionality to rate scaling */
+	iwl4965_tl_get_stats(priv, hdr);
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /*CONFIG_IWL4965_HT */
 
-	iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys,
-		       hdr, hdr_len, ctl, NULL);
 
 	if (!ieee80211_get_morefrag(hdr)) {
 		txq->need_update = 1;
@@ -2961,27 +3082,29 @@ static int iwl_tx_skb(struct iwl_priv *priv,
 		txq->need_update = 0;
 	}
 
-	iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+	iwl4965_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
 			   sizeof(out_cmd->cmd.tx));
 
-	iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
+	iwl4965_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
 			   ieee80211_get_hdrlen(fc));
 
+	/* Set up entry for this TFD in Tx byte-count array */
 	iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
 
-	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
-	rc = iwl_tx_queue_update_write_ptr(priv, txq);
+	/* Tell device the write index *just past* this latest filled TFD */
+	q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd);
+	rc = iwl4965_tx_queue_update_write_ptr(priv, txq);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	if (rc)
 		return rc;
 
-	if ((iwl_queue_space(q) < q->high_mark)
+	if ((iwl4965_queue_space(q) < q->high_mark)
 	    && priv->mac80211_registered) {
 		if (wait_write_ptr) {
 			spin_lock_irqsave(&priv->lock, flags);
 			txq->need_update = 1;
-			iwl_tx_queue_update_write_ptr(priv, txq);
+			iwl4965_tx_queue_update_write_ptr(priv, txq);
 			spin_unlock_irqrestore(&priv->lock, flags);
 		}
 
@@ -2996,13 +3119,13 @@ drop:
 	return -1;
 }
 
-static void iwl_set_rate(struct iwl_priv *priv)
+static void iwl4965_set_rate(struct iwl4965_priv *priv)
 {
 	const struct ieee80211_hw_mode *hw = NULL;
 	struct ieee80211_rate *rate;
 	int i;
 
-	hw = iwl_get_hw_mode(priv, priv->phymode);
+	hw = iwl4965_get_hw_mode(priv, priv->phymode);
 	if (!hw) {
 		IWL_ERROR("Failed to set rate: unable to get hw mode\n");
 		return;
@@ -3020,7 +3143,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
 		if ((rate->val < IWL_RATE_COUNT) &&
 		    (rate->flags & IEEE80211_RATE_SUPPORTED)) {
 			IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
-				       rate->val, iwl_rates[rate->val].plcp,
+				       rate->val, iwl4965_rates[rate->val].plcp,
 				       (rate->flags & IEEE80211_RATE_BASIC) ?
 				       "*" : "");
 			priv->active_rate |= (1 << rate->val);
@@ -3028,7 +3151,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
 				priv->active_rate_basic |= (1 << rate->val);
 		} else
 			IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
-				       rate->val, iwl_rates[rate->val].plcp);
+				       rate->val, iwl4965_rates[rate->val].plcp);
 	}
 
 	IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
@@ -3057,7 +3180,7 @@ static void iwl_set_rate(struct iwl_priv *priv)
 		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
 }
 
-static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+static void iwl4965_radio_kill_sw(struct iwl4965_priv *priv, int disable_radio)
 {
 	unsigned long flags;
 
@@ -3068,21 +3191,21 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
 			  disable_radio ? "OFF" : "ON");
 
 	if (disable_radio) {
-		iwl_scan_cancel(priv);
+		iwl4965_scan_cancel(priv);
 		/* FIXME: This is a workaround for AP */
 		if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
 			spin_lock_irqsave(&priv->lock, flags);
-			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+			iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET,
 				    CSR_UCODE_SW_BIT_RFKILL);
 			spin_unlock_irqrestore(&priv->lock, flags);
-			iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+			iwl4965_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
 			set_bit(STATUS_RF_KILL_SW, &priv->status);
 		}
 		return;
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
 	clear_bit(STATUS_RF_KILL_SW, &priv->status);
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -3091,9 +3214,9 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
 	msleep(10);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_read32(priv, CSR_UCODE_DRV_GP1);
-	if (!iwl_grab_restricted_access(priv))
-		iwl_release_restricted_access(priv);
+	iwl4965_read32(priv, CSR_UCODE_DRV_GP1);
+	if (!iwl4965_grab_nic_access(priv))
+		iwl4965_release_nic_access(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
@@ -3106,7 +3229,7 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
 	return;
 }
 
-void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb,
 			    u32 decrypt_res, struct ieee80211_rx_status *stats)
 {
 	u16 fc =
@@ -3138,97 +3261,10 @@ void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
 	}
 }
 
-void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb,
-				    void *data, short len,
-				    struct ieee80211_rx_status *stats,
-				    u16 phy_flags)
-{
-	struct iwl_rt_rx_hdr *iwl_rt;
-
-	/* First cache any information we need before we overwrite
-	 * the information provided in the skb from the hardware */
-	s8 signal = stats->ssi;
-	s8 noise = 0;
-	int rate = stats->rate;
-	u64 tsf = stats->mactime;
-	__le16 phy_flags_hw = cpu_to_le16(phy_flags);
-
-	/* We received data from the HW, so stop the watchdog */
-	if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) {
-		IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
-		return;
-	}
-
-	/* copy the frame data to write after where the radiotap header goes */
-	iwl_rt = (void *)rxb->skb->data;
-	memmove(iwl_rt->payload, data, len);
-
-	iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
-	iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */
-
-	/* total header + data */
-	iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt));
-
-	/* Set the size of the skb to the size of the frame */
-	skb_put(rxb->skb, sizeof(*iwl_rt) + len);
-
-	/* Big bitfield of all the fields we provide in radiotap */
-	iwl_rt->rt_hdr.it_present =
-	    cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
-			(1 << IEEE80211_RADIOTAP_FLAGS) |
-			(1 << IEEE80211_RADIOTAP_RATE) |
-			(1 << IEEE80211_RADIOTAP_CHANNEL) |
-			(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
-			(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
-			(1 << IEEE80211_RADIOTAP_ANTENNA));
-
-	/* Zero the flags, we'll add to them as we go */
-	iwl_rt->rt_flags = 0;
-
-	iwl_rt->rt_tsf = cpu_to_le64(tsf);
-
-	/* Convert to dBm */
-	iwl_rt->rt_dbmsignal = signal;
-	iwl_rt->rt_dbmnoise = noise;
-
-	/* Convert the channel frequency and set the flags */
-	iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq);
-	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
-		iwl_rt->rt_chbitmask =
-		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
-	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
-		iwl_rt->rt_chbitmask =
-		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
-	else	/* 802.11g */
-		iwl_rt->rt_chbitmask =
-		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
-
-	rate = iwl_rate_index_from_plcp(rate);
-	if (rate == -1)
-		iwl_rt->rt_rate = 0;
-	else
-		iwl_rt->rt_rate = iwl_rates[rate].ieee;
-
-	/* antenna number */
-	iwl_rt->rt_antenna =
-		le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
-
-	/* set the preamble flag if we have it */
-	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-		iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
-	IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
-	stats->flag |= RX_FLAG_RADIOTAP;
-	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
-	rxb->skb = NULL;
-}
-
 
 #define IWL_PACKET_RETRY_TIME HZ
 
-int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+int iwl4965_is_duplicate_packet(struct iwl4965_priv *priv, struct ieee80211_hdr *header)
 {
 	u16 sc = le16_to_cpu(header->seq_ctrl);
 	u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
@@ -3239,29 +3275,26 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
 	switch (priv->iw_mode) {
 	case IEEE80211_IF_TYPE_IBSS:{
 		struct list_head *p;
-		struct iwl_ibss_seq *entry = NULL;
+		struct iwl4965_ibss_seq *entry = NULL;
 		u8 *mac = header->addr2;
 		int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
 
 		__list_for_each(p, &priv->ibss_mac_hash[index]) {
-			entry =
-				list_entry(p, struct iwl_ibss_seq, list);
+			entry = list_entry(p, struct iwl4965_ibss_seq, list);
 			if (!compare_ether_addr(entry->mac, mac))
 				break;
 		}
 		if (p == &priv->ibss_mac_hash[index]) {
 			entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
 			if (!entry) {
-				IWL_ERROR
-					("Cannot malloc new mac entry\n");
+				IWL_ERROR("Cannot malloc new mac entry\n");
 				return 0;
 			}
 			memcpy(entry->mac, mac, ETH_ALEN);
 			entry->seq_num = seq;
 			entry->frag_num = frag;
 			entry->packet_time = jiffies;
-			list_add(&entry->list,
-				 &priv->ibss_mac_hash[index]);
+			list_add(&entry->list, &priv->ibss_mac_hash[index]);
 			return 0;
 		}
 		last_seq = &entry->seq_num;
@@ -3295,7 +3328,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
 	return 1;
 }
 
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
 
 #include "iwl-spectrum.h"
 
@@ -3310,7 +3343,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
  * the lower 3 bytes is the time in usec within one beacon interval
  */
 
-static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval)
 {
 	u32 quot;
 	u32 rem;
@@ -3329,7 +3362,7 @@ static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
  * the same as HW timer counter counting down
  */
 
-static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
 {
 	u32 base_low = base & BEACON_TIME_MASK_LOW;
 	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
@@ -3348,13 +3381,13 @@ static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
 	return cpu_to_le32(res);
 }
 
-static int iwl_get_measurement(struct iwl_priv *priv,
+static int iwl4965_get_measurement(struct iwl4965_priv *priv,
 			       struct ieee80211_measurement_params *params,
 			       u8 type)
 {
-	struct iwl_spectrum_cmd spectrum;
-	struct iwl_rx_packet *res;
-	struct iwl_host_cmd cmd = {
+	struct iwl4965_spectrum_cmd spectrum;
+	struct iwl4965_rx_packet *res;
+	struct iwl4965_host_cmd cmd = {
 		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
 		.data = (void *)&spectrum,
 		.meta.flags = CMD_WANT_SKB,
@@ -3364,9 +3397,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
 	int spectrum_resp_status;
 	int duration = le16_to_cpu(params->duration);
 
-	if (iwl_is_associated(priv))
+	if (iwl4965_is_associated(priv))
 		add_time =
-		    iwl_usecs_to_beacons(
+		    iwl4965_usecs_to_beacons(
 			le64_to_cpu(params->start_time) - priv->last_tsf,
 			le16_to_cpu(priv->rxon_timing.beacon_interval));
 
@@ -3379,9 +3412,9 @@ static int iwl_get_measurement(struct iwl_priv *priv,
 	cmd.len = sizeof(spectrum);
 	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
 
-	if (iwl_is_associated(priv))
+	if (iwl4965_is_associated(priv))
 		spectrum.start_time =
-		    iwl_add_beacon_time(priv->last_beacon_time,
+		    iwl4965_add_beacon_time(priv->last_beacon_time,
 				add_time,
 				le16_to_cpu(priv->rxon_timing.beacon_interval));
 	else
@@ -3394,11 +3427,11 @@ static int iwl_get_measurement(struct iwl_priv *priv,
 		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
 		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
 
-	rc = iwl_send_cmd_sync(priv, &cmd);
+	rc = iwl4965_send_cmd_sync(priv, &cmd);
 	if (rc)
 		return rc;
 
-	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
 	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
 		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
 		rc = -EIO;
@@ -3428,8 +3461,8 @@ static int iwl_get_measurement(struct iwl_priv *priv,
 }
 #endif
 
-static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
-				 struct iwl_tx_info *tx_sta)
+static void iwl4965_txstatus_to_ieee(struct iwl4965_priv *priv,
+				 struct iwl4965_tx_info *tx_sta)
 {
 
 	tx_sta->status.ack_signal = 0;
@@ -3448,41 +3481,41 @@ static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
 }
 
 /**
- * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
+ * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
  *
- * When FW advances 'R' index, all entries between old and
- * new 'R' index need to be reclaimed. As result, some free space
- * forms. If there is enough free space (> low mark), wake Tx queue.
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms.  If there is
+ * enough free space (> low mark), wake the stack that feeds us.
  */
-int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index)
 {
-	struct iwl_tx_queue *txq = &priv->txq[txq_id];
-	struct iwl_queue *q = &txq->q;
+	struct iwl4965_tx_queue *txq = &priv->txq[txq_id];
+	struct iwl4965_queue *q = &txq->q;
 	int nfreed = 0;
 
 	if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
 		IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
 			  "is out of range [0-%d] %d %d.\n", txq_id,
-			  index, q->n_bd, q->first_empty, q->last_used);
+			  index, q->n_bd, q->write_ptr, q->read_ptr);
 		return 0;
 	}
 
-	for (index = iwl_queue_inc_wrap(index, q->n_bd);
-		q->last_used != index;
-		q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) {
+	for (index = iwl4965_queue_inc_wrap(index, q->n_bd);
+		q->read_ptr != index;
+		q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 		if (txq_id != IWL_CMD_QUEUE_NUM) {
-			iwl_txstatus_to_ieee(priv,
-					&(txq->txb[txq->q.last_used]));
-			iwl_hw_txq_free_tfd(priv, txq);
+			iwl4965_txstatus_to_ieee(priv,
+					&(txq->txb[txq->q.read_ptr]));
+			iwl4965_hw_txq_free_tfd(priv, txq);
 		} else if (nfreed > 1) {
 			IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
-					q->first_empty, q->last_used);
+					q->write_ptr, q->read_ptr);
 			queue_work(priv->workqueue, &priv->restart);
 		}
 		nfreed++;
 	}
 
-	if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+	if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) &&
 			(txq_id != IWL_CMD_QUEUE_NUM) &&
 			priv->mac80211_registered)
 		ieee80211_wake_queue(priv->hw, txq_id);
@@ -3491,7 +3524,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
 	return nfreed;
 }
 
-static int iwl_is_tx_success(u32 status)
+static int iwl4965_is_tx_success(u32 status)
 {
 	status &= TX_STATUS_MSK;
 	return (status == TX_STATUS_SUCCESS)
@@ -3503,22 +3536,22 @@ static int iwl_is_tx_success(u32 status)
  * Generic RX handler implementations
  *
  ******************************************************************************/
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 
-static inline int iwl_get_ra_sta_id(struct iwl_priv *priv,
+static inline int iwl4965_get_ra_sta_id(struct iwl4965_priv *priv,
 				    struct ieee80211_hdr *hdr)
 {
 	if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
 		return IWL_AP_ID;
 	else {
 		u8 *da = ieee80211_get_DA(hdr);
-		return iwl_hw_find_station(priv, da);
+		return iwl4965_hw_find_station(priv, da);
 	}
 }
 
-static struct ieee80211_hdr *iwl_tx_queue_get_hdr(
-	struct iwl_priv *priv, int txq_id, int idx)
+static struct ieee80211_hdr *iwl4965_tx_queue_get_hdr(
+	struct iwl4965_priv *priv, int txq_id, int idx)
 {
 	if (priv->txq[txq_id].txb[idx].skb[0])
 		return (struct ieee80211_hdr *)priv->txq[txq_id].
@@ -3526,16 +3559,20 @@ static struct ieee80211_hdr *iwl_tx_queue_get_hdr(
 	return NULL;
 }
 
-static inline u32 iwl_get_scd_ssn(struct iwl_tx_resp *tx_resp)
+static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp)
 {
 	__le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
 				tx_resp->frame_count);
 	return le32_to_cpu(*scd_ssn) & MAX_SN;
 
 }
-static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
-				      struct iwl_ht_agg *agg,
-				      struct iwl_tx_resp *tx_resp,
+
+/**
+ * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue
+ */
+static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv,
+				      struct iwl4965_ht_agg *agg,
+				      struct iwl4965_tx_resp *tx_resp,
 				      u16 start_idx)
 {
 	u32 status;
@@ -3547,15 +3584,17 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
 	u16 seq;
 
 	if (agg->wait_for_ba)
-		IWL_DEBUG_TX_REPLY("got tx repsons w/o back\n");
+		IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n");
 
 	agg->frame_count = tx_resp->frame_count;
 	agg->start_idx = start_idx;
 	agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
 	agg->bitmap0 = agg->bitmap1 = 0;
 
+	/* # frames attempted by Tx command */
 	if (agg->frame_count == 1) {
-		struct iwl_tx_queue *txq ;
+		/* Only one frame was attempted; no block-ack will arrive */
+		struct iwl4965_tx_queue *txq ;
 		status = le32_to_cpu(frame_status[0]);
 
 		txq_id = agg->txq_id;
@@ -3564,28 +3603,30 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
 		IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n",
 				   agg->frame_count, agg->start_idx);
 
-		tx_status = &(priv->txq[txq_id].txb[txq->q.last_used].status);
+		tx_status = &(priv->txq[txq_id].txb[txq->q.read_ptr].status);
 		tx_status->retry_count = tx_resp->failure_frame;
 		tx_status->queue_number = status & 0xff;
 		tx_status->queue_length = tx_resp->bt_kill_count;
 		tx_status->queue_length |= tx_resp->failure_rts;
 
-		tx_status->flags = iwl_is_tx_success(status)?
+		tx_status->flags = iwl4965_is_tx_success(status)?
 			IEEE80211_TX_STATUS_ACK : 0;
 		tx_status->control.tx_rate =
-				iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+				iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags);
 		/* FIXME: code repetition end */
 
 		IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
 				    status & 0xff, tx_resp->failure_frame);
 		IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
-				iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags));
+				iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags));
 
 		agg->wait_for_ba = 0;
 	} else {
+		/* Two or more frames were attempted; expect block-ack */
 		u64 bitmap = 0;
 		int start = agg->start_idx;
 
+		/* Construct bit-map of pending frames within Tx window */
 		for (i = 0; i < agg->frame_count; i++) {
 			u16 sc;
 			status = le32_to_cpu(frame_status[i]);
@@ -3600,7 +3641,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
 			IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
 					   agg->frame_count, txq_id, idx);
 
-			hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+			hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, idx);
 
 			sc = le16_to_cpu(hdr->seq_ctrl);
 			if (idx != (SEQ_TO_SN(sc) & 0xff)) {
@@ -3649,19 +3690,22 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
 #endif
 #endif
 
-static void iwl_rx_reply_tx(struct iwl_priv *priv,
-			    struct iwl_rx_mem_buffer *rxb)
+/**
+ * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
+ */
+static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv,
+			    struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
 	int txq_id = SEQ_TO_QUEUE(sequence);
 	int index = SEQ_TO_INDEX(sequence);
-	struct iwl_tx_queue *txq = &priv->txq[txq_id];
+	struct iwl4965_tx_queue *txq = &priv->txq[txq_id];
 	struct ieee80211_tx_status *tx_status;
-	struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+	struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
 	u32  status = le32_to_cpu(tx_resp->status);
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 	int tid, sta_id;
 #endif
 #endif
@@ -3669,18 +3713,18 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
 	if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
 		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
 			  "is out of range [0-%d] %d %d\n", txq_id,
-			  index, txq->q.n_bd, txq->q.first_empty,
-			  txq->q.last_used);
+			  index, txq->q.n_bd, txq->q.write_ptr,
+			  txq->q.read_ptr);
 		return;
 	}
 
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 	if (txq->sched_retry) {
-		const u32 scd_ssn = iwl_get_scd_ssn(tx_resp);
+		const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
 		struct ieee80211_hdr *hdr =
-			iwl_tx_queue_get_hdr(priv, txq_id, index);
-		struct iwl_ht_agg *agg = NULL;
+			iwl4965_tx_queue_get_hdr(priv, txq_id, index);
+		struct iwl4965_ht_agg *agg = NULL;
 		__le16 *qc = ieee80211_get_qos_ctrl(hdr);
 
 		if (qc == NULL) {
@@ -3690,7 +3734,7 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
 
 		tid = le16_to_cpu(*qc) & 0xf;
 
-		sta_id = iwl_get_ra_sta_id(priv, hdr);
+		sta_id = iwl4965_get_ra_sta_id(priv, hdr);
 		if (unlikely(sta_id == IWL_INVALID_STATION)) {
 			IWL_ERROR("Station not known for\n");
 			return;
@@ -3701,20 +3745,20 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
 		iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index);
 
 		if ((tx_resp->frame_count == 1) &&
-		    !iwl_is_tx_success(status)) {
+		    !iwl4965_is_tx_success(status)) {
 			/* TODO: send BAR */
 		}
 
-		if ((txq->q.last_used != (scd_ssn & 0xff))) {
-			index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+		if ((txq->q.read_ptr != (scd_ssn & 0xff))) {
+			index = iwl4965_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
 			IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
 					   "%d index %d\n", scd_ssn , index);
-			iwl_tx_queue_reclaim(priv, txq_id, index);
+			iwl4965_tx_queue_reclaim(priv, txq_id, index);
 		}
 	} else {
-#endif /* CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
-	tx_status = &(txq->txb[txq->q.last_used].status);
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
+	tx_status = &(txq->txb[txq->q.read_ptr].status);
 
 	tx_status->retry_count = tx_resp->failure_frame;
 	tx_status->queue_number = status;
@@ -3722,35 +3766,35 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv,
 	tx_status->queue_length |= tx_resp->failure_rts;
 
 	tx_status->flags =
-	    iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
+	    iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
 
 	tx_status->control.tx_rate =
-		iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+		iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags);
 
 	IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
-		     "retries %d\n", txq_id, iwl_get_tx_fail_reason(status),
+		     "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status),
 		     status, le32_to_cpu(tx_resp->rate_n_flags),
 		     tx_resp->failure_frame);
 
 	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
 	if (index != -1)
-		iwl_tx_queue_reclaim(priv, txq_id, index);
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+		iwl4965_tx_queue_reclaim(priv, txq_id, index);
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
 	}
-#endif /* CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 
 	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
 		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
 }
 
 
-static void iwl_rx_reply_alive(struct iwl_priv *priv,
-			       struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_reply_alive(struct iwl4965_priv *priv,
+			       struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_alive_resp *palive;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_alive_resp *palive;
 	struct delayed_work *pwork;
 
 	palive = &pkt->u.alive_frame;
@@ -3764,12 +3808,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
 		IWL_DEBUG_INFO("Initialization Alive received.\n");
 		memcpy(&priv->card_alive_init,
 		       &pkt->u.alive_frame,
-		       sizeof(struct iwl_init_alive_resp));
+		       sizeof(struct iwl4965_init_alive_resp));
 		pwork = &priv->init_alive_start;
 	} else {
 		IWL_DEBUG_INFO("Runtime Alive received.\n");
 		memcpy(&priv->card_alive, &pkt->u.alive_frame,
-		       sizeof(struct iwl_alive_resp));
+		       sizeof(struct iwl4965_alive_resp));
 		pwork = &priv->alive_start;
 	}
 
@@ -3782,19 +3826,19 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
 		IWL_WARNING("uCode did not respond OK.\n");
 }
 
-static void iwl_rx_reply_add_sta(struct iwl_priv *priv,
-				 struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_reply_add_sta(struct iwl4965_priv *priv,
+				 struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 
 	IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
 	return;
 }
 
-static void iwl_rx_reply_error(struct iwl_priv *priv,
-			       struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_reply_error(struct iwl4965_priv *priv,
+			       struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 
 	IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
 		"seq 0x%04X ser 0x%08X\n",
@@ -3807,23 +3851,23 @@ static void iwl_rx_reply_error(struct iwl_priv *priv,
 
 #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
 
-static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_csa(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
-	struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rxon_cmd *rxon = (void *)&priv->active_rxon;
+	struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif);
 	IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
 		      le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
 	rxon->channel = csa->channel;
 	priv->staging_rxon.channel = csa->channel;
 }
 
-static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
-					  struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_spectrum_measure_notif(struct iwl4965_priv *priv,
+					  struct iwl4965_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif);
 
 	if (!report->state) {
 		IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
@@ -3836,35 +3880,35 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
 #endif
 }
 
-static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
-				  struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_pm_sleep_notif(struct iwl4965_priv *priv,
+				  struct iwl4965_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+#ifdef CONFIG_IWL4965_DEBUG
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif);
 	IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
 		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
 #endif
 }
 
-static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-					     struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_pm_debug_statistics_notif(struct iwl4965_priv *priv,
+					     struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 	IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
 			"notification for %s:\n",
 			le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
-	iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+	iwl4965_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
 }
 
-static void iwl_bg_beacon_update(struct work_struct *work)
+static void iwl4965_bg_beacon_update(struct work_struct *work)
 {
-	struct iwl_priv *priv =
-		container_of(work, struct iwl_priv, beacon_update);
+	struct iwl4965_priv *priv =
+		container_of(work, struct iwl4965_priv, beacon_update);
 	struct sk_buff *beacon;
 
 	/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
-	beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+	beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL);
 
 	if (!beacon) {
 		IWL_ERROR("update beacon failed\n");
@@ -3879,16 +3923,16 @@ static void iwl_bg_beacon_update(struct work_struct *work)
 	priv->ibss_beacon = beacon;
 	mutex_unlock(&priv->mutex);
 
-	iwl_send_beacon_cmd(priv);
+	iwl4965_send_beacon_cmd(priv);
 }
 
-static void iwl_rx_beacon_notif(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_beacon_notif(struct iwl4965_priv *priv,
+				struct iwl4965_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status);
-	u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
+#ifdef CONFIG_IWL4965_DEBUG
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status);
+	u8 rate = iwl4965_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
 
 	IWL_DEBUG_RX("beacon status %x retries %d iss %d "
 		"tsf %d %d rate %d\n",
@@ -3905,25 +3949,25 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
 }
 
 /* Service response to REPLY_SCAN_CMD (0x80) */
-static void iwl_rx_reply_scan(struct iwl_priv *priv,
-			      struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_reply_scan(struct iwl4965_priv *priv,
+			      struct iwl4965_rx_mem_buffer *rxb)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scanreq_notification *notif =
-	    (struct iwl_scanreq_notification *)pkt->u.raw;
+#ifdef CONFIG_IWL4965_DEBUG
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_scanreq_notification *notif =
+	    (struct iwl4965_scanreq_notification *)pkt->u.raw;
 
 	IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
 #endif
 }
 
 /* Service SCAN_START_NOTIFICATION (0x82) */
-static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_scan_start_notif(struct iwl4965_priv *priv,
+				    struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scanstart_notification *notif =
-	    (struct iwl_scanstart_notification *)pkt->u.raw;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_scanstart_notification *notif =
+	    (struct iwl4965_scanstart_notification *)pkt->u.raw;
 	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
 	IWL_DEBUG_SCAN("Scan start: "
 		       "%d [802.11%s] "
@@ -3935,12 +3979,12 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
 }
 
 /* Service SCAN_RESULTS_NOTIFICATION (0x83) */
-static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
-				      struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_scan_results_notif(struct iwl4965_priv *priv,
+				      struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scanresults_notification *notif =
-	    (struct iwl_scanresults_notification *)pkt->u.raw;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_scanresults_notification *notif =
+	    (struct iwl4965_scanresults_notification *)pkt->u.raw;
 
 	IWL_DEBUG_SCAN("Scan ch.res: "
 		       "%d [802.11%s] "
@@ -3956,14 +4000,15 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
 					(priv->last_scan_jiffies, jiffies)));
 
 	priv->last_scan_jiffies = jiffies;
+	priv->next_scan_jiffies = 0;
 }
 
 /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
-static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
-				       struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_scan_complete_notif(struct iwl4965_priv *priv,
+				       struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-	struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
 
 	IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
 		       scan_notif->scanned_channels,
@@ -3998,6 +4043,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
 	}
 
 	priv->last_scan_jiffies = jiffies;
+	priv->next_scan_jiffies = 0;
 	IWL_DEBUG_INFO("Setting scan to off\n");
 
 	clear_bit(STATUS_SCANNING, &priv->status);
@@ -4016,10 +4062,10 @@ reschedule:
 
 /* Handle notification from uCode that card's power state is changing
  * due to software, hardware, or critical temperature RFKILL */
-static void iwl_rx_card_state_notif(struct iwl_priv *priv,
-				    struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_rx_card_state_notif(struct iwl4965_priv *priv,
+				    struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data;
 	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
 	unsigned long status = priv->status;
 
@@ -4030,35 +4076,35 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
 	if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
 		     RF_CARD_DISABLED)) {
 
-		iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+		iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET,
 			    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 
-		if (!iwl_grab_restricted_access(priv)) {
-			iwl_write_restricted(
+		if (!iwl4965_grab_nic_access(priv)) {
+			iwl4965_write_direct32(
 				priv, HBUS_TARG_MBX_C,
 				HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
 
-			iwl_release_restricted_access(priv);
+			iwl4965_release_nic_access(priv);
 		}
 
 		if (!(flags & RXON_CARD_DISABLED)) {
-			iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+			iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR,
 				    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-			if (!iwl_grab_restricted_access(priv)) {
-				iwl_write_restricted(
+			if (!iwl4965_grab_nic_access(priv)) {
+				iwl4965_write_direct32(
 					priv, HBUS_TARG_MBX_C,
 					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
 
-				iwl_release_restricted_access(priv);
+				iwl4965_release_nic_access(priv);
 			}
 		}
 
 		if (flags & RF_CARD_DISABLED) {
-			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+			iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET,
 				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-			iwl_read32(priv, CSR_UCODE_DRV_GP1);
-			if (!iwl_grab_restricted_access(priv))
-				iwl_release_restricted_access(priv);
+			iwl4965_read32(priv, CSR_UCODE_DRV_GP1);
+			if (!iwl4965_grab_nic_access(priv))
+				iwl4965_release_nic_access(priv);
 		}
 	}
 
@@ -4074,7 +4120,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
 		clear_bit(STATUS_RF_KILL_SW, &priv->status);
 
 	if (!(flags & RXON_CARD_DISABLED))
-		iwl_scan_cancel(priv);
+		iwl4965_scan_cancel(priv);
 
 	if ((test_bit(STATUS_RF_KILL_HW, &status) !=
 	     test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
@@ -4086,7 +4132,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
 }
 
 /**
- * iwl_setup_rx_handlers - Initialize Rx handler callbacks
+ * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks
  *
  * Setup the RX handlers for each of the reply types sent from the uCode
  * to the host.
@@ -4094,61 +4140,58 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
  * This function chains into the hardware specific files for them to setup
  * any hardware specific handlers as well.
  */
-static void iwl_setup_rx_handlers(struct iwl_priv *priv)
+static void iwl4965_setup_rx_handlers(struct iwl4965_priv *priv)
 {
-	priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
-	priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta;
-	priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
-	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+	priv->rx_handlers[REPLY_ALIVE] = iwl4965_rx_reply_alive;
+	priv->rx_handlers[REPLY_ADD_STA] = iwl4965_rx_reply_add_sta;
+	priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error;
+	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa;
 	priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
-	    iwl_rx_spectrum_measure_notif;
-	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
+	    iwl4965_rx_spectrum_measure_notif;
+	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif;
 	priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
-	    iwl_rx_pm_debug_statistics_notif;
-	priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
-
-	/* NOTE:  iwl_rx_statistics is different based on whether
-	 * the build is for the 3945 or the 4965.  See the
-	 * corresponding implementation in iwl-XXXX.c
-	 *
-	 * The same handler is used for both the REPLY to a
-	 * discrete statistics request from the host as well as
-	 * for the periodic statistics notification from the uCode
+	    iwl4965_rx_pm_debug_statistics_notif;
+	priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif;
+
+	/*
+	 * The same handler is used for both the REPLY to a discrete
+	 * statistics request from the host as well as for the periodic
+	 * statistics notifications (after received beacons) from the uCode.
 	 */
-	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics;
-	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics;
+	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl4965_hw_rx_statistics;
+	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl4965_hw_rx_statistics;
 
-	priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
-	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
+	priv->rx_handlers[REPLY_SCAN_CMD] = iwl4965_rx_reply_scan;
+	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl4965_rx_scan_start_notif;
 	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
-	    iwl_rx_scan_results_notif;
+	    iwl4965_rx_scan_results_notif;
 	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
-	    iwl_rx_scan_complete_notif;
-	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
-	priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx;
+	    iwl4965_rx_scan_complete_notif;
+	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif;
+	priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
 
-	/* Setup hardware specific Rx handlers */
-	iwl_hw_rx_handler_setup(priv);
+	/* Set up hardware specific Rx handlers */
+	iwl4965_hw_rx_handler_setup(priv);
 }
 
 /**
- * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * iwl4965_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
  * @rxb: Rx buffer to reclaim
  *
  * If an Rx buffer has an async callback associated with it the callback
  * will be executed.  The attached skb (if present) will only be freed
  * if the callback returns 1
  */
-static void iwl_tx_cmd_complete(struct iwl_priv *priv,
-				struct iwl_rx_mem_buffer *rxb)
+static void iwl4965_tx_cmd_complete(struct iwl4965_priv *priv,
+				struct iwl4965_rx_mem_buffer *rxb)
 {
-	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+	struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
 	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
 	int txq_id = SEQ_TO_QUEUE(sequence);
 	int index = SEQ_TO_INDEX(sequence);
 	int huge = sequence & SEQ_HUGE_FRAME;
 	int cmd_index;
-	struct iwl_cmd *cmd;
+	struct iwl4965_cmd *cmd;
 
 	/* If a Tx command is being handled and it isn't in the actual
 	 * command queue then there a command routing bug has been introduced
@@ -4169,7 +4212,7 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
 		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
 		rxb->skb = NULL;
 
-	iwl_tx_queue_reclaim(priv, txq_id, index);
+	iwl4965_tx_queue_reclaim(priv, txq_id, index);
 
 	if (!(cmd->meta.flags & CMD_ASYNC)) {
 		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
@@ -4181,9 +4224,11 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
 /*
  * Rx theory of operation
  *
- * The host allocates 32 DMA target addresses and passes the host address
- * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
- * 0 to 31
+ * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs),
+ * each of which point to Receive Buffers to be filled by 4965.  These get
+ * used not only for Rx frames, but for any command response or notification
+ * from the 4965.  The driver and 4965 manage the Rx buffers by means
+ * of indexes into the circular buffer.
  *
  * Rx Queue Indexes
  * The host/firmware share two index registers for managing the Rx buffers.
@@ -4199,10 +4244,10 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
  * The queue is empty (no good data) if WRITE = READ - 1, and is full if
  * WRITE = READ.
  *
- * During initialization the host sets up the READ queue position to the first
+ * During initialization, the host sets up the READ queue position to the first
  * INDEX position, and WRITE to the last (READ - 1 wrapped)
  *
- * When the firmware places a packet in a buffer it will advance the READ index
+ * When the firmware places a packet in a buffer, it will advance the READ index
  * and fire the RX interrupt.  The driver can then query the READ index and
  * process as many packets as possible, moving the WRITE index forward as it
  * resets the Rx queue buffers with new memory.
@@ -4210,8 +4255,8 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
  * The management in the driver is as follows:
  * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
  *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- *   to replensish the iwl->rxq->rx_free.
- * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   to replenish the iwl->rxq->rx_free.
+ * + In iwl4965_rx_replenish (scheduled) if 'processed' != 'read' then the
  *   iwl->rxq is replenished and the READ INDEX is updated (updating the
  *   'processed' and 'read' driver indexes as well)
  * + A received packet is processed and handed to the kernel network stack,
@@ -4224,28 +4269,28 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv,
  *
  * Driver sequence:
  *
- * iwl_rx_queue_alloc()       Allocates rx_free
- * iwl_rx_replenish()         Replenishes rx_free list from rx_used, and calls
- *                            iwl_rx_queue_restock
- * iwl_rx_queue_restock()     Moves available buffers from rx_free into Rx
+ * iwl4965_rx_queue_alloc()   Allocates rx_free
+ * iwl4965_rx_replenish()     Replenishes rx_free list from rx_used, and calls
+ *                            iwl4965_rx_queue_restock
+ * iwl4965_rx_queue_restock() Moves available buffers from rx_free into Rx
  *                            queue, updates firmware pointers, and updates
  *                            the WRITE index.  If insufficient rx_free buffers
- *                            are available, schedules iwl_rx_replenish
+ *                            are available, schedules iwl4965_rx_replenish
  *
  * -- enable interrupts --
- * ISR - iwl_rx()             Detach iwl_rx_mem_buffers from pool up to the
+ * ISR - iwl4965_rx()         Detach iwl4965_rx_mem_buffers from pool up to the
  *                            READ INDEX, detaching the SKB from the pool.
  *                            Moves the packet buffer from queue to rx_used.
- *                            Calls iwl_rx_queue_restock to refill any empty
+ *                            Calls iwl4965_rx_queue_restock to refill any empty
  *                            slots.
  * ...
  *
  */
 
 /**
- * iwl_rx_queue_space - Return number of free slots available in queue.
+ * iwl4965_rx_queue_space - Return number of free slots available in queue.
  */
-static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+static int iwl4965_rx_queue_space(const struct iwl4965_rx_queue *q)
 {
 	int s = q->read - q->write;
 	if (s <= 0)
@@ -4258,15 +4303,9 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
 }
 
 /**
- * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
- *
- * NOTE: This function has 3945 and 4965 specific code sections
- * but is declared in base due to the majority of the
- * implementation being the same (only a numeric constant is
- * different)
- *
+ * iwl4965_rx_queue_update_write_ptr - Update the write pointer for the RX queue
  */
-int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_rx_queue *q)
 {
 	u32 reg = 0;
 	int rc = 0;
@@ -4277,24 +4316,29 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
 	if (q->need_update == 0)
 		goto exit_unlock;
 
+	/* If power-saving is in use, make sure device is awake */
 	if (test_bit(STATUS_POWER_PMI, &priv->status)) {
-		reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+		reg = iwl4965_read32(priv, CSR_UCODE_DRV_GP1);
 
 		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-			iwl_set_bit(priv, CSR_GP_CNTRL,
+			iwl4965_set_bit(priv, CSR_GP_CNTRL,
 				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 			goto exit_unlock;
 		}
 
-		rc = iwl_grab_restricted_access(priv);
+		rc = iwl4965_grab_nic_access(priv);
 		if (rc)
 			goto exit_unlock;
 
-		iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR,
+		/* Device expects a multiple of 8 */
+		iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
 				     q->write & ~0x7);
-		iwl_release_restricted_access(priv);
+		iwl4965_release_nic_access(priv);
+
+	/* Else device is assumed to be awake */
 	} else
-		iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+		/* Device expects a multiple of 8 */
+		iwl4965_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
 
 
 	q->need_update = 0;
@@ -4305,11 +4349,9 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
 }
 
 /**
- * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer.
- *
- * NOTE: This function has 3945 and 4965 specific code paths in it.
+ * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
  */
-static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl4965_priv *priv,
 					  dma_addr_t dma_addr)
 {
 	return cpu_to_le32((u32)(dma_addr >> 8));
@@ -4317,31 +4359,34 @@ static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
 
 
 /**
- * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+ * iwl4965_rx_queue_restock - refill RX queue from pre-allocated pool
  *
- * If there are slots in the RX queue that  need to be restocked,
+ * If there are slots in the RX queue that need to be restocked,
  * and we have free pre-allocated buffers, fill the ranks as much
- * as we can pulling from rx_free.
+ * as we can, pulling from rx_free.
  *
  * This moves the 'write' index forward to catch up with 'processed', and
  * also updates the memory address in the firmware to reference the new
  * target buffer.
  */
-int iwl_rx_queue_restock(struct iwl_priv *priv)
+static int iwl4965_rx_queue_restock(struct iwl4965_priv *priv)
 {
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl4965_rx_queue *rxq = &priv->rxq;
 	struct list_head *element;
-	struct iwl_rx_mem_buffer *rxb;
+	struct iwl4965_rx_mem_buffer *rxb;
 	unsigned long flags;
 	int write, rc;
 
 	spin_lock_irqsave(&rxq->lock, flags);
 	write = rxq->write & ~0x7;
-	while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+	while ((iwl4965_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+		/* Get next free Rx buffer, remove from free list */
 		element = rxq->rx_free.next;
-		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
 		list_del(element);
-		rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+
+		/* Point to Rx buffer via next RBD in circular buffer */
+		rxq->bd[rxq->write] = iwl4965_dma_addr2rbd_ptr(priv, rxb->dma_addr);
 		rxq->queue[rxq->write] = rxb;
 		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
 		rxq->free_count--;
@@ -4353,13 +4398,14 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
 		queue_work(priv->workqueue, &priv->rx_replenish);
 
 
-	/* If we've added more space for the firmware to place data, tell it */
+	/* If we've added more space for the firmware to place data, tell it.
+	 * Increment device's write pointer in multiples of 8. */
 	if ((write != (rxq->write & ~0x7))
 	    || (abs(rxq->write - rxq->read) > 7)) {
 		spin_lock_irqsave(&rxq->lock, flags);
 		rxq->need_update = 1;
 		spin_unlock_irqrestore(&rxq->lock, flags);
-		rc = iwl_rx_queue_update_write_ptr(priv, rxq);
+		rc = iwl4965_rx_queue_update_write_ptr(priv, rxq);
 		if (rc)
 			return rc;
 	}
@@ -4368,26 +4414,28 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
 }
 
 /**
- * iwl_rx_replensih - Move all used packet from rx_used to rx_free
+ * iwl4965_rx_replenish - Move all used packet from rx_used to rx_free
  *
  * When moving to rx_free an SKB is allocated for the slot.
  *
- * Also restock the Rx queue via iwl_rx_queue_restock.
- * This is called as a scheduled work item (except for during intialization)
+ * Also restock the Rx queue via iwl4965_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
  */
-void iwl_rx_replenish(void *data)
+static void iwl4965_rx_allocate(struct iwl4965_priv *priv)
 {
-	struct iwl_priv *priv = data;
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl4965_rx_queue *rxq = &priv->rxq;
 	struct list_head *element;
-	struct iwl_rx_mem_buffer *rxb;
+	struct iwl4965_rx_mem_buffer *rxb;
 	unsigned long flags;
 	spin_lock_irqsave(&rxq->lock, flags);
 	while (!list_empty(&rxq->rx_used)) {
 		element = rxq->rx_used.next;
-		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list);
+
+		/* Alloc a new receive buffer */
 		rxb->skb =
-		    alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+		    alloc_skb(priv->hw_setting.rx_buf_size,
+				__GFP_NOWARN | GFP_ATOMIC);
 		if (!rxb->skb) {
 			if (net_ratelimit())
 				printk(KERN_CRIT DRV_NAME
@@ -4399,32 +4447,55 @@ void iwl_rx_replenish(void *data)
 		}
 		priv->alloc_rxb_skb++;
 		list_del(element);
+
+		/* Get physical address of RB/SKB */
 		rxb->dma_addr =
 		    pci_map_single(priv->pci_dev, rxb->skb->data,
-				   IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			   priv->hw_setting.rx_buf_size, PCI_DMA_FROMDEVICE);
 		list_add_tail(&rxb->list, &rxq->rx_free);
 		rxq->free_count++;
 	}
 	spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/*
+ * this should be called while priv->lock is locked
+*/
+static void __iwl4965_rx_replenish(void *data)
+{
+	struct iwl4965_priv *priv = data;
+
+	iwl4965_rx_allocate(priv);
+	iwl4965_rx_queue_restock(priv);
+}
+
+
+void iwl4965_rx_replenish(void *data)
+{
+	struct iwl4965_priv *priv = data;
+	unsigned long flags;
+
+	iwl4965_rx_allocate(priv);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_rx_queue_restock(priv);
+	iwl4965_rx_queue_restock(priv);
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 /* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * If an SKB has been detached, the POOL needs to have its SKB set to NULL
  * This free routine walks the list of POOL entries and if SKB is set to
  * non NULL it is unmapped and freed
  */
-void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+static void iwl4965_rx_queue_free(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq)
 {
 	int i;
 	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
 		if (rxq->pool[i].skb != NULL) {
 			pci_unmap_single(priv->pci_dev,
 					 rxq->pool[i].dma_addr,
-					 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+					 priv->hw_setting.rx_buf_size,
+					 PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(rxq->pool[i].skb);
 		}
 	}
@@ -4434,21 +4505,25 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
 	rxq->bd = NULL;
 }
 
-int iwl_rx_queue_alloc(struct iwl_priv *priv)
+int iwl4965_rx_queue_alloc(struct iwl4965_priv *priv)
 {
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl4965_rx_queue *rxq = &priv->rxq;
 	struct pci_dev *dev = priv->pci_dev;
 	int i;
 
 	spin_lock_init(&rxq->lock);
 	INIT_LIST_HEAD(&rxq->rx_free);
 	INIT_LIST_HEAD(&rxq->rx_used);
+
+	/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
 	rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
 	if (!rxq->bd)
 		return -ENOMEM;
+
 	/* Fill the rx_used queue with _all_ of the Rx buffers */
 	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
 		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+
 	/* Set us so that we have processed and used all buffers, but have
 	 * not restocked the Rx queue with fresh buffers */
 	rxq->read = rxq->write = 0;
@@ -4457,7 +4532,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
 	return 0;
 }
 
-void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+void iwl4965_rx_queue_reset(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq)
 {
 	unsigned long flags;
 	int i;
@@ -4471,7 +4546,8 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
 		if (rxq->pool[i].skb != NULL) {
 			pci_unmap_single(priv->pci_dev,
 					 rxq->pool[i].dma_addr,
-					 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+					 priv->hw_setting.rx_buf_size,
+					 PCI_DMA_FROMDEVICE);
 			priv->alloc_rxb_skb--;
 			dev_kfree_skb(rxq->pool[i].skb);
 			rxq->pool[i].skb = NULL;
@@ -4504,7 +4580,7 @@ static u8 ratio2dB[100] = {
 /* Calculates a relative dB value from a ratio of linear
  *   (i.e. not dB) signal levels.
  * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
-int iwl_calc_db_from_ratio(int sig_ratio)
+int iwl4965_calc_db_from_ratio(int sig_ratio)
 {
 	/* 1000:1 or higher just report as 60 dB */
 	if (sig_ratio >= 1000)
@@ -4530,7 +4606,7 @@ int iwl_calc_db_from_ratio(int sig_ratio)
 /* Calculate an indication of rx signal quality (a percentage, not dBm!).
  * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
  *   about formulas used below. */
-int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
+int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm)
 {
 	int sig_qual;
 	int degradation = PERFECT_RSSI - rssi_dbm;
@@ -4565,32 +4641,39 @@ int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
 }
 
 /**
- * iwl_rx_handle - Main entry function for receiving responses from the uCode
+ * iwl4965_rx_handle - Main entry function for receiving responses from uCode
  *
  * Uses the priv->rx_handlers callback function array to invoke
  * the appropriate handlers, including command responses,
  * frame-received notifications, and other notifications.
  */
-static void iwl_rx_handle(struct iwl_priv *priv)
+static void iwl4965_rx_handle(struct iwl4965_priv *priv)
 {
-	struct iwl_rx_mem_buffer *rxb;
-	struct iwl_rx_packet *pkt;
-	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct iwl4965_rx_mem_buffer *rxb;
+	struct iwl4965_rx_packet *pkt;
+	struct iwl4965_rx_queue *rxq = &priv->rxq;
 	u32 r, i;
 	int reclaim;
 	unsigned long flags;
+	u8 fill_rx = 0;
+	u32 count = 0;
 
-	r = iwl_hw_get_rx_read(priv);
+	/* uCode's read index (stored in shared DRAM) indicates the last Rx
+	 * buffer that the driver may process (last buffer filled by ucode). */
+	r = iwl4965_hw_get_rx_read(priv);
 	i = rxq->read;
 
 	/* Rx interrupt, but nothing sent from uCode */
 	if (i == r)
 		IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
 
+	if (iwl4965_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
+		fill_rx = 1;
+
 	while (i != r) {
 		rxb = rxq->queue[i];
 
-		/* If an RXB doesn't have a queue slot associated with it
+		/* If an RXB doesn't have a Rx queue slot associated with it,
 		 * then a bug has been introduced in the queue refilling
 		 * routines -- catch it here */
 		BUG_ON(rxb == NULL);
@@ -4598,9 +4681,9 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 		rxq->queue[i] = NULL;
 
 		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
-					    IWL_RX_BUF_SIZE,
+					    priv->hw_setting.rx_buf_size,
 					    PCI_DMA_FROMDEVICE);
-		pkt = (struct iwl_rx_packet *)rxb->skb->data;
+		pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
 
 		/* Reclaim a command buffer only if this packet is a response
 		 *   to a (driver-originated) command.
@@ -4617,7 +4700,7 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 
 		/* Based on type of command response or notification,
 		 *   handle those that need handling via function in
-		 *   rx_handlers table.  See iwl_setup_rx_handlers() */
+		 *   rx_handlers table.  See iwl4965_setup_rx_handlers() */
 		if (priv->rx_handlers[pkt->hdr.cmd]) {
 			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
 				"r = %d, i = %d, %s, 0x%02x\n", r, i,
@@ -4632,11 +4715,11 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 		}
 
 		if (reclaim) {
-			/* Invoke any callbacks, transfer the skb to caller,
-			 * and fire off the (possibly) blocking iwl_send_cmd()
+			/* Invoke any callbacks, transfer the skb to caller, and
+			 * fire off the (possibly) blocking iwl4965_send_cmd()
 			 * as we reclaim the driver command queue */
 			if (rxb && rxb->skb)
-				iwl_tx_cmd_complete(priv, rxb);
+				iwl4965_tx_cmd_complete(priv, rxb);
 			else
 				IWL_WARNING("Claim null rxb?\n");
 		}
@@ -4651,20 +4734,34 @@ static void iwl_rx_handle(struct iwl_priv *priv)
 		}
 
 		pci_unmap_single(priv->pci_dev, rxb->dma_addr,
-				 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+				 priv->hw_setting.rx_buf_size,
+				 PCI_DMA_FROMDEVICE);
 		spin_lock_irqsave(&rxq->lock, flags);
 		list_add_tail(&rxb->list, &priv->rxq.rx_used);
 		spin_unlock_irqrestore(&rxq->lock, flags);
 		i = (i + 1) & RX_QUEUE_MASK;
+		/* If there are a lot of unused frames,
+		 * restock the Rx queue so ucode wont assert. */
+		if (fill_rx) {
+			count++;
+			if (count >= 8) {
+				priv->rxq.read = i;
+				__iwl4965_rx_replenish(priv);
+				count = 0;
+			}
+		}
 	}
 
 	/* Backtrack one entry */
 	priv->rxq.read = i;
-	iwl_rx_queue_restock(priv);
+	iwl4965_rx_queue_restock(priv);
 }
 
-int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
-				  struct iwl_tx_queue *txq)
+/**
+ * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware
+ */
+static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv,
+				  struct iwl4965_tx_queue *txq)
 {
 	u32 reg = 0;
 	int rc = 0;
@@ -4678,41 +4775,41 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
 		/* wake up nic if it's powered down ...
 		 * uCode will wake up, and interrupt us again, so next
 		 * time we'll skip this part. */
-		reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+		reg = iwl4965_read32(priv, CSR_UCODE_DRV_GP1);
 
 		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
 			IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
-			iwl_set_bit(priv, CSR_GP_CNTRL,
+			iwl4965_set_bit(priv, CSR_GP_CNTRL,
 				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 			return rc;
 		}
 
 		/* restore this queue's parameters in nic hardware. */
-		rc = iwl_grab_restricted_access(priv);
+		rc = iwl4965_grab_nic_access(priv);
 		if (rc)
 			return rc;
-		iwl_write_restricted(priv, HBUS_TARG_WRPTR,
-				     txq->q.first_empty | (txq_id << 8));
-		iwl_release_restricted_access(priv);
+		iwl4965_write_direct32(priv, HBUS_TARG_WRPTR,
+				     txq->q.write_ptr | (txq_id << 8));
+		iwl4965_release_nic_access(priv);
 
 	/* else not in power-save mode, uCode will never sleep when we're
 	 * trying to tx (during RFKILL, we're not trying to tx). */
 	} else
-		iwl_write32(priv, HBUS_TARG_WRPTR,
-			    txq->q.first_empty | (txq_id << 8));
+		iwl4965_write32(priv, HBUS_TARG_WRPTR,
+			    txq->q.write_ptr | (txq_id << 8));
 
 	txq->need_update = 0;
 
 	return rc;
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
+#ifdef CONFIG_IWL4965_DEBUG
+static void iwl4965_print_rx_config_cmd(struct iwl4965_rxon_cmd *rxon)
 {
 	DECLARE_MAC_BUF(mac);
 
 	IWL_DEBUG_RADIO("RX CONFIG:\n");
-	iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+	iwl4965_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
 	IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
 	IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
 	IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
@@ -4729,24 +4826,24 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
 }
 #endif
 
-static void iwl_enable_interrupts(struct iwl_priv *priv)
+static void iwl4965_enable_interrupts(struct iwl4965_priv *priv)
 {
 	IWL_DEBUG_ISR("Enabling interrupts\n");
 	set_bit(STATUS_INT_ENABLED, &priv->status);
-	iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+	iwl4965_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
 }
 
-static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+static inline void iwl4965_disable_interrupts(struct iwl4965_priv *priv)
 {
 	clear_bit(STATUS_INT_ENABLED, &priv->status);
 
 	/* disable interrupts from uCode/NIC to host */
-	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+	iwl4965_write32(priv, CSR_INT_MASK, 0x00000000);
 
 	/* acknowledge/clear/reset any interrupts still pending
 	 * from uCode or flow handler (Rx/Tx DMA) */
-	iwl_write32(priv, CSR_INT, 0xffffffff);
-	iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+	iwl4965_write32(priv, CSR_INT, 0xffffffff);
+	iwl4965_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
 	IWL_DEBUG_ISR("Disabled interrupts\n");
 }
 
@@ -4773,7 +4870,7 @@ static const char *desc_lookup(int i)
 #define ERROR_START_OFFSET  (1 * sizeof(u32))
 #define ERROR_ELEM_SIZE     (7 * sizeof(u32))
 
-static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+static void iwl4965_dump_nic_error_log(struct iwl4965_priv *priv)
 {
 	u32 data2, line;
 	u32 desc, time, count, base, data1;
@@ -4782,18 +4879,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
 
 	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
 
-	if (!iwl_hw_valid_rtc_data_addr(base)) {
+	if (!iwl4965_hw_valid_rtc_data_addr(base)) {
 		IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
 		return;
 	}
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		IWL_WARNING("Can not read from adapter at this time.\n");
 		return;
 	}
 
-	count = iwl_read_restricted_mem(priv, base);
+	count = iwl4965_read_targ_mem(priv, base);
 
 	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
 		IWL_ERROR("Start IWL Error Log Dump:\n");
@@ -4801,15 +4898,15 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
 			  priv->status, priv->config, count);
 	}
 
-	desc = iwl_read_restricted_mem(priv, base + 1 * sizeof(u32));
-	blink1 = iwl_read_restricted_mem(priv, base + 3 * sizeof(u32));
-	blink2 = iwl_read_restricted_mem(priv, base + 4 * sizeof(u32));
-	ilink1 = iwl_read_restricted_mem(priv, base + 5 * sizeof(u32));
-	ilink2 = iwl_read_restricted_mem(priv, base + 6 * sizeof(u32));
-	data1 = iwl_read_restricted_mem(priv, base + 7 * sizeof(u32));
-	data2 = iwl_read_restricted_mem(priv, base + 8 * sizeof(u32));
-	line = iwl_read_restricted_mem(priv, base + 9 * sizeof(u32));
-	time = iwl_read_restricted_mem(priv, base + 11 * sizeof(u32));
+	desc = iwl4965_read_targ_mem(priv, base + 1 * sizeof(u32));
+	blink1 = iwl4965_read_targ_mem(priv, base + 3 * sizeof(u32));
+	blink2 = iwl4965_read_targ_mem(priv, base + 4 * sizeof(u32));
+	ilink1 = iwl4965_read_targ_mem(priv, base + 5 * sizeof(u32));
+	ilink2 = iwl4965_read_targ_mem(priv, base + 6 * sizeof(u32));
+	data1 = iwl4965_read_targ_mem(priv, base + 7 * sizeof(u32));
+	data2 = iwl4965_read_targ_mem(priv, base + 8 * sizeof(u32));
+	line = iwl4965_read_targ_mem(priv, base + 9 * sizeof(u32));
+	time = iwl4965_read_targ_mem(priv, base + 11 * sizeof(u32));
 
 	IWL_ERROR("Desc               Time       "
 		  "data1      data2      line\n");
@@ -4819,17 +4916,17 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv)
 	IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
 		  ilink1, ilink2);
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 }
 
 #define EVENT_START_OFFSET  (4 * sizeof(u32))
 
 /**
- * iwl_print_event_log - Dump error event log to syslog
+ * iwl4965_print_event_log - Dump error event log to syslog
  *
- * NOTE: Must be called with iwl_grab_restricted_access() already obtained!
+ * NOTE: Must be called with iwl4965_grab_nic_access() already obtained!
  */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+static void iwl4965_print_event_log(struct iwl4965_priv *priv, u32 start_idx,
 				u32 num_events, u32 mode)
 {
 	u32 i;
@@ -4853,21 +4950,21 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
 	/* "time" is actually "data" for mode 0 (no timestamp).
 	 * place event id # at far right for easier visual parsing. */
 	for (i = 0; i < num_events; i++) {
-		ev = iwl_read_restricted_mem(priv, ptr);
+		ev = iwl4965_read_targ_mem(priv, ptr);
 		ptr += sizeof(u32);
-		time = iwl_read_restricted_mem(priv, ptr);
+		time = iwl4965_read_targ_mem(priv, ptr);
 		ptr += sizeof(u32);
 		if (mode == 0)
 			IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
 		else {
-			data = iwl_read_restricted_mem(priv, ptr);
+			data = iwl4965_read_targ_mem(priv, ptr);
 			ptr += sizeof(u32);
 			IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
 		}
 	}
 }
 
-static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+static void iwl4965_dump_nic_event_log(struct iwl4965_priv *priv)
 {
 	int rc;
 	u32 base;       /* SRAM byte address of event log header */
@@ -4878,29 +4975,29 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
 	u32 size;       /* # entries that we'll print */
 
 	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-	if (!iwl_hw_valid_rtc_data_addr(base)) {
+	if (!iwl4965_hw_valid_rtc_data_addr(base)) {
 		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
 		return;
 	}
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		IWL_WARNING("Can not read from adapter at this time.\n");
 		return;
 	}
 
 	/* event log header */
-	capacity = iwl_read_restricted_mem(priv, base);
-	mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32)));
-	num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32)));
-	next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32)));
+	capacity = iwl4965_read_targ_mem(priv, base);
+	mode = iwl4965_read_targ_mem(priv, base + (1 * sizeof(u32)));
+	num_wraps = iwl4965_read_targ_mem(priv, base + (2 * sizeof(u32)));
+	next_entry = iwl4965_read_targ_mem(priv, base + (3 * sizeof(u32)));
 
 	size = num_wraps ? capacity : next_entry;
 
 	/* bail out if nothing in log */
 	if (size == 0) {
 		IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
-		iwl_release_restricted_access(priv);
+		iwl4965_release_nic_access(priv);
 		return;
 	}
 
@@ -4910,31 +5007,31 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv)
 	/* if uCode has wrapped back to top of log, start at the oldest entry,
 	 * i.e the next one that uCode would fill. */
 	if (num_wraps)
-		iwl_print_event_log(priv, next_entry,
+		iwl4965_print_event_log(priv, next_entry,
 				    capacity - next_entry, mode);
 
 	/* (then/else) start at top of log */
-	iwl_print_event_log(priv, 0, next_entry, mode);
+	iwl4965_print_event_log(priv, 0, next_entry, mode);
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 }
 
 /**
- * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ * iwl4965_irq_handle_error - called for HW or SW error interrupt from card
  */
-static void iwl_irq_handle_error(struct iwl_priv *priv)
+static void iwl4965_irq_handle_error(struct iwl4965_priv *priv)
 {
-	/* Set the FW error flag -- cleared on iwl_down */
+	/* Set the FW error flag -- cleared on iwl4965_down */
 	set_bit(STATUS_FW_ERROR, &priv->status);
 
 	/* Cancel currently queued command. */
 	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & IWL_DL_FW_ERRORS) {
-		iwl_dump_nic_error_log(priv);
-		iwl_dump_nic_event_log(priv);
-		iwl_print_rx_config_cmd(&priv->staging_rxon);
+#ifdef CONFIG_IWL4965_DEBUG
+	if (iwl4965_debug_level & IWL_DL_FW_ERRORS) {
+		iwl4965_dump_nic_error_log(priv);
+		iwl4965_dump_nic_event_log(priv);
+		iwl4965_print_rx_config_cmd(&priv->staging_rxon);
 	}
 #endif
 
@@ -4948,7 +5045,7 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
 		IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
 			  "Restarting adapter due to uCode error.\n");
 
-		if (iwl_is_associated(priv)) {
+		if (iwl4965_is_associated(priv)) {
 			memcpy(&priv->recovery_rxon, &priv->active_rxon,
 			       sizeof(priv->recovery_rxon));
 			priv->error_recovering = 1;
@@ -4957,16 +5054,16 @@ static void iwl_irq_handle_error(struct iwl_priv *priv)
 	}
 }
 
-static void iwl_error_recovery(struct iwl_priv *priv)
+static void iwl4965_error_recovery(struct iwl4965_priv *priv)
 {
 	unsigned long flags;
 
 	memcpy(&priv->staging_rxon, &priv->recovery_rxon,
 	       sizeof(priv->staging_rxon));
 	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_commit_rxon(priv);
+	iwl4965_commit_rxon(priv);
 
-	iwl_rxon_add_station(priv, priv->bssid, 1);
+	iwl4965_rxon_add_station(priv, priv->bssid, 1);
 
 	spin_lock_irqsave(&priv->lock, flags);
 	priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
@@ -4974,12 +5071,12 @@ static void iwl_error_recovery(struct iwl_priv *priv)
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static void iwl_irq_tasklet(struct iwl_priv *priv)
+static void iwl4965_irq_tasklet(struct iwl4965_priv *priv)
 {
 	u32 inta, handled = 0;
 	u32 inta_fh;
 	unsigned long flags;
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL4965_DEBUG
 	u32 inta_mask;
 #endif
 
@@ -4988,18 +5085,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	/* Ack/clear/reset pending uCode interrupts.
 	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
 	 *  and will clear only when CSR_FH_INT_STATUS gets cleared. */
-	inta = iwl_read32(priv, CSR_INT);
-	iwl_write32(priv, CSR_INT, inta);
+	inta = iwl4965_read32(priv, CSR_INT);
+	iwl4965_write32(priv, CSR_INT, inta);
 
 	/* Ack/clear/reset pending flow-handler (DMA) interrupts.
 	 * Any new interrupts that happen after this, either while we're
 	 * in this tasklet, or later, will show up in next ISR/tasklet. */
-	inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
-	iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
+	inta_fh = iwl4965_read32(priv, CSR_FH_INT_STATUS);
+	iwl4965_write32(priv, CSR_FH_INT_STATUS, inta_fh);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & IWL_DL_ISR) {
-		inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+#ifdef CONFIG_IWL4965_DEBUG
+	if (iwl4965_debug_level & IWL_DL_ISR) {
+		/* just for debug */
+		inta_mask = iwl4965_read32(priv, CSR_INT_MASK);
 		IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
 			      inta, inta_mask, inta_fh);
 	}
@@ -5019,9 +5117,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 		IWL_ERROR("Microcode HW error detected.  Restarting.\n");
 
 		/* Tell the device to stop sending interrupts */
-		iwl_disable_interrupts(priv);
+		iwl4965_disable_interrupts(priv);
 
-		iwl_irq_handle_error(priv);
+		iwl4965_irq_handle_error(priv);
 
 		handled |= CSR_INT_BIT_HW_ERR;
 
@@ -5030,8 +5128,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 		return;
 	}
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & (IWL_DL_ISR)) {
+#ifdef CONFIG_IWL4965_DEBUG
+	if (iwl4965_debug_level & (IWL_DL_ISR)) {
 		/* NIC fires this, but we don't use it, redundant with WAKEUP */
 		if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
 			IWL_DEBUG_ISR("Microcode started or stopped.\n");
@@ -5044,10 +5142,10 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	/* Safely ignore these bits for debug checks below */
 	inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
 
-	/* HW RF KILL switch toggled (4965 only) */
+	/* HW RF KILL switch toggled */
 	if (inta & CSR_INT_BIT_RF_KILL) {
 		int hw_rf_kill = 0;
-		if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+		if (!(iwl4965_read32(priv, CSR_GP_CNTRL) &
 				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
 			hw_rf_kill = 1;
 
@@ -5067,7 +5165,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 		handled |= CSR_INT_BIT_RF_KILL;
 	}
 
-	/* Chip got too hot and stopped itself (4965 only) */
+	/* Chip got too hot and stopped itself */
 	if (inta & CSR_INT_BIT_CT_KILL) {
 		IWL_ERROR("Microcode CT kill error detected.\n");
 		handled |= CSR_INT_BIT_CT_KILL;
@@ -5077,20 +5175,20 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	if (inta & CSR_INT_BIT_SW_ERR) {
 		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
 			  inta);
-		iwl_irq_handle_error(priv);
+		iwl4965_irq_handle_error(priv);
 		handled |= CSR_INT_BIT_SW_ERR;
 	}
 
 	/* uCode wakes up after power-down sleep */
 	if (inta & CSR_INT_BIT_WAKEUP) {
 		IWL_DEBUG_ISR("Wakeup interrupt\n");
-		iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]);
-		iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+		iwl4965_rx_queue_update_write_ptr(priv, &priv->rxq);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[0]);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[1]);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[2]);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[3]);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[4]);
+		iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[5]);
 
 		handled |= CSR_INT_BIT_WAKEUP;
 	}
@@ -5099,7 +5197,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	 * Rx "responses" (frame-received notification), and other
 	 * notifications from uCode come through here*/
 	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
-		iwl_rx_handle(priv);
+		iwl4965_rx_handle(priv);
 		handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
 	}
 
@@ -5118,13 +5216,13 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	}
 
 	/* Re-enable all interrupts */
-	iwl_enable_interrupts(priv);
+	iwl4965_enable_interrupts(priv);
 
-#ifdef CONFIG_IWLWIFI_DEBUG
-	if (iwl_debug_level & (IWL_DL_ISR)) {
-		inta = iwl_read32(priv, CSR_INT);
-		inta_mask = iwl_read32(priv, CSR_INT_MASK);
-		inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+#ifdef CONFIG_IWL4965_DEBUG
+	if (iwl4965_debug_level & (IWL_DL_ISR)) {
+		inta = iwl4965_read32(priv, CSR_INT);
+		inta_mask = iwl4965_read32(priv, CSR_INT_MASK);
+		inta_fh = iwl4965_read32(priv, CSR_FH_INT_STATUS);
 		IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
 			"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
 	}
@@ -5132,9 +5230,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static irqreturn_t iwl_isr(int irq, void *data)
+static irqreturn_t iwl4965_isr(int irq, void *data)
 {
-	struct iwl_priv *priv = data;
+	struct iwl4965_priv *priv = data;
 	u32 inta, inta_mask;
 	u32 inta_fh;
 	if (!priv)
@@ -5146,12 +5244,12 @@ static irqreturn_t iwl_isr(int irq, void *data)
 	 *    back-to-back ISRs and sporadic interrupts from our NIC.
 	 * If we have something to service, the tasklet will re-enable ints.
 	 * If we *don't* have something, we'll re-enable before leaving here. */
-	inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
-	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+	inta_mask = iwl4965_read32(priv, CSR_INT_MASK);  /* just for debug */
+	iwl4965_write32(priv, CSR_INT_MASK, 0x00000000);
 
 	/* Discover which interrupts are active/pending */
-	inta = iwl_read32(priv, CSR_INT);
-	inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+	inta = iwl4965_read32(priv, CSR_INT);
+	inta_fh = iwl4965_read32(priv, CSR_FH_INT_STATUS);
 
 	/* Ignore interrupt if there's nothing in NIC to service.
 	 * This may be due to IRQ shared with another device,
@@ -5171,7 +5269,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
 	IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
 		      inta, inta_mask, inta_fh);
 
-	/* iwl_irq_tasklet() will service interrupts and re-enable them */
+	/* iwl4965_irq_tasklet() will service interrupts and re-enable them */
 	tasklet_schedule(&priv->irq_tasklet);
 
  unplugged:
@@ -5180,18 +5278,18 @@ static irqreturn_t iwl_isr(int irq, void *data)
 
  none:
 	/* re-enable interrupts here since we don't have anything to service. */
-	iwl_enable_interrupts(priv);
+	iwl4965_enable_interrupts(priv);
 	spin_unlock(&priv->lock);
 	return IRQ_NONE;
 }
 
 /************************** EEPROM BANDS ****************************
  *
- * The iwl_eeprom_band definitions below provide the mapping from the
+ * The iwl4965_eeprom_band definitions below provide the mapping from the
  * EEPROM contents to the specific channel number supported for each
  * band.
  *
- * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
+ * For example, iwl4965_priv->eeprom.band_3_channels[4] from the band_3
  * definition below maps to physical channel 42 in the 5.2GHz spectrum.
  * The specific geography and calibration information for that channel
  * is contained in the eeprom map itself.
@@ -5217,76 +5315,77 @@ static irqreturn_t iwl_isr(int irq, void *data)
  *********************************************************************/
 
 /* 2.4 GHz */
-static const u8 iwl_eeprom_band_1[14] = {
+static const u8 iwl4965_eeprom_band_1[14] = {
 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
 };
 
 /* 5.2 GHz bands */
-static const u8 iwl_eeprom_band_2[] = {
+static const u8 iwl4965_eeprom_band_2[] = {	/* 4915-5080MHz */
 	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
 };
 
-static const u8 iwl_eeprom_band_3[] = {	/* 5205-5320MHz */
+static const u8 iwl4965_eeprom_band_3[] = {	/* 5170-5320MHz */
 	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
 };
 
-static const u8 iwl_eeprom_band_4[] = {	/* 5500-5700MHz */
+static const u8 iwl4965_eeprom_band_4[] = {	/* 5500-5700MHz */
 	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
 };
 
-static const u8 iwl_eeprom_band_5[] = {	/* 5725-5825MHz */
+static const u8 iwl4965_eeprom_band_5[] = {	/* 5725-5825MHz */
 	145, 149, 153, 157, 161, 165
 };
 
-static u8 iwl_eeprom_band_6[] = {       /* 2.4 FAT channel */
+static u8 iwl4965_eeprom_band_6[] = {       /* 2.4 FAT channel */
 	1, 2, 3, 4, 5, 6, 7
 };
 
-static u8 iwl_eeprom_band_7[] = {       /* 5.2 FAT channel */
+static u8 iwl4965_eeprom_band_7[] = {       /* 5.2 FAT channel */
 	36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
 };
 
-static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
+static void iwl4965_init_band_reference(const struct iwl4965_priv *priv,
+				    int band,
 				    int *eeprom_ch_count,
-				    const struct iwl_eeprom_channel
+				    const struct iwl4965_eeprom_channel
 				    **eeprom_ch_info,
 				    const u8 **eeprom_ch_index)
 {
 	switch (band) {
 	case 1:		/* 2.4GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_1);
 		*eeprom_ch_info = priv->eeprom.band_1_channels;
-		*eeprom_ch_index = iwl_eeprom_band_1;
+		*eeprom_ch_index = iwl4965_eeprom_band_1;
 		break;
-	case 2:		/* 5.2GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
+	case 2:		/* 4.9GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_2);
 		*eeprom_ch_info = priv->eeprom.band_2_channels;
-		*eeprom_ch_index = iwl_eeprom_band_2;
+		*eeprom_ch_index = iwl4965_eeprom_band_2;
 		break;
 	case 3:		/* 5.2GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_3);
 		*eeprom_ch_info = priv->eeprom.band_3_channels;
-		*eeprom_ch_index = iwl_eeprom_band_3;
+		*eeprom_ch_index = iwl4965_eeprom_band_3;
 		break;
-	case 4:		/* 5.2GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
+	case 4:		/* 5.5GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_4);
 		*eeprom_ch_info = priv->eeprom.band_4_channels;
-		*eeprom_ch_index = iwl_eeprom_band_4;
+		*eeprom_ch_index = iwl4965_eeprom_band_4;
 		break;
-	case 5:		/* 5.2GHz band */
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
+	case 5:		/* 5.7GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_5);
 		*eeprom_ch_info = priv->eeprom.band_5_channels;
-		*eeprom_ch_index = iwl_eeprom_band_5;
+		*eeprom_ch_index = iwl4965_eeprom_band_5;
 		break;
-	case 6:
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
+	case 6:		/* 2.4GHz FAT channels */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_6);
 		*eeprom_ch_info = priv->eeprom.band_24_channels;
-		*eeprom_ch_index = iwl_eeprom_band_6;
+		*eeprom_ch_index = iwl4965_eeprom_band_6;
 		break;
-	case 7:
-		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
+	case 7:		/* 5 GHz FAT channels */
+		*eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_7);
 		*eeprom_ch_info = priv->eeprom.band_52_channels;
-		*eeprom_ch_index = iwl_eeprom_band_7;
+		*eeprom_ch_index = iwl4965_eeprom_band_7;
 		break;
 	default:
 		BUG();
@@ -5294,7 +5393,12 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
 	}
 }
 
-const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+/**
+ * iwl4965_get_channel_info - Find driver's private channel info
+ *
+ * Based on band and channel number.
+ */
+const struct iwl4965_channel_info *iwl4965_get_channel_info(const struct iwl4965_priv *priv,
 						    int phymode, u16 channel)
 {
 	int i;
@@ -5321,13 +5425,16 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
 #define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
 			    ? # x " " : "")
 
-static int iwl_init_channel_map(struct iwl_priv *priv)
+/**
+ * iwl4965_init_channel_map - Set up driver's info for all possible channels
+ */
+static int iwl4965_init_channel_map(struct iwl4965_priv *priv)
 {
 	int eeprom_ch_count = 0;
 	const u8 *eeprom_ch_index = NULL;
-	const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
+	const struct iwl4965_eeprom_channel *eeprom_ch_info = NULL;
 	int band, ch;
-	struct iwl_channel_info *ch_info;
+	struct iwl4965_channel_info *ch_info;
 
 	if (priv->channel_count) {
 		IWL_DEBUG_INFO("Channel map already initialized.\n");
@@ -5343,15 +5450,15 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
 	IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
 
 	priv->channel_count =
-	    ARRAY_SIZE(iwl_eeprom_band_1) +
-	    ARRAY_SIZE(iwl_eeprom_band_2) +
-	    ARRAY_SIZE(iwl_eeprom_band_3) +
-	    ARRAY_SIZE(iwl_eeprom_band_4) +
-	    ARRAY_SIZE(iwl_eeprom_band_5);
+	    ARRAY_SIZE(iwl4965_eeprom_band_1) +
+	    ARRAY_SIZE(iwl4965_eeprom_band_2) +
+	    ARRAY_SIZE(iwl4965_eeprom_band_3) +
+	    ARRAY_SIZE(iwl4965_eeprom_band_4) +
+	    ARRAY_SIZE(iwl4965_eeprom_band_5);
 
 	IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
 
-	priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
+	priv->channel_info = kzalloc(sizeof(struct iwl4965_channel_info) *
 				     priv->channel_count, GFP_KERNEL);
 	if (!priv->channel_info) {
 		IWL_ERROR("Could not allocate channel_info\n");
@@ -5366,7 +5473,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
 	 * what just in the EEPROM) */
 	for (band = 1; band <= 5; band++) {
 
-		iwl_init_band_reference(priv, band, &eeprom_ch_count,
+		iwl4965_init_band_reference(priv, band, &eeprom_ch_count,
 					&eeprom_ch_info, &eeprom_ch_index);
 
 		/* Loop through each band adding each of the channels */
@@ -5430,14 +5537,17 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
 		}
 	}
 
+	/* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */
 	for (band = 6; band <= 7; band++) {
 		int phymode;
 		u8 fat_extension_chan;
 
-		iwl_init_band_reference(priv, band, &eeprom_ch_count,
+		iwl4965_init_band_reference(priv, band, &eeprom_ch_count,
 					&eeprom_ch_info, &eeprom_ch_index);
 
+		/* EEPROM band 6 is 2.4, band 7 is 5 GHz */
 		phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A;
+
 		/* Loop through each band adding each of the channels */
 		for (ch = 0; ch < eeprom_ch_count; ch++) {
 
@@ -5449,11 +5559,13 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
 			else
 				fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
 
+			/* Set up driver's info for lower half */
 			iwl4965_set_fat_chan_info(priv, phymode,
 						  eeprom_ch_index[ch],
 						  &(eeprom_ch_info[ch]),
 						  fat_extension_chan);
 
+			/* Set up driver's info for upper half */
 			iwl4965_set_fat_chan_info(priv, phymode,
 						  (eeprom_ch_index[ch] + 4),
 						  &(eeprom_ch_info[ch]),
@@ -5487,7 +5599,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv)
 #define IWL_PASSIVE_DWELL_BASE      (100)
 #define IWL_CHANNEL_TUNE_TIME       5
 
-static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
+static inline u16 iwl4965_get_active_dwell_time(struct iwl4965_priv *priv, int phymode)
 {
 	if (phymode == MODE_IEEE80211A)
 		return IWL_ACTIVE_DWELL_TIME_52;
@@ -5495,14 +5607,14 @@ static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
 		return IWL_ACTIVE_DWELL_TIME_24;
 }
 
-static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
+static u16 iwl4965_get_passive_dwell_time(struct iwl4965_priv *priv, int phymode)
 {
-	u16 active = iwl_get_active_dwell_time(priv, phymode);
+	u16 active = iwl4965_get_active_dwell_time(priv, phymode);
 	u16 passive = (phymode != MODE_IEEE80211A) ?
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
 	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
 
-	if (iwl_is_associated(priv)) {
+	if (iwl4965_is_associated(priv)) {
 		/* If we're associated, we clamp the maximum passive
 		 * dwell time to be 98% of the beacon interval (minus
 		 * 2 * channel tune time) */
@@ -5518,30 +5630,30 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
 	return passive;
 }
 
-static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode,
 				     u8 is_active, u8 direct_mask,
-				     struct iwl_scan_channel *scan_ch)
+				     struct iwl4965_scan_channel *scan_ch)
 {
 	const struct ieee80211_channel *channels = NULL;
 	const struct ieee80211_hw_mode *hw_mode;
-	const struct iwl_channel_info *ch_info;
+	const struct iwl4965_channel_info *ch_info;
 	u16 passive_dwell = 0;
 	u16 active_dwell = 0;
 	int added, i;
 
-	hw_mode = iwl_get_hw_mode(priv, phymode);
+	hw_mode = iwl4965_get_hw_mode(priv, phymode);
 	if (!hw_mode)
 		return 0;
 
 	channels = hw_mode->channels;
 
-	active_dwell = iwl_get_active_dwell_time(priv, phymode);
-	passive_dwell = iwl_get_passive_dwell_time(priv, phymode);
+	active_dwell = iwl4965_get_active_dwell_time(priv, phymode);
+	passive_dwell = iwl4965_get_passive_dwell_time(priv, phymode);
 
 	for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
 		if (channels[i].chan ==
 		    le16_to_cpu(priv->active_rxon.channel)) {
-			if (iwl_is_associated(priv)) {
+			if (iwl4965_is_associated(priv)) {
 				IWL_DEBUG_SCAN
 				    ("Skipping current channel %d\n",
 				     le16_to_cpu(priv->active_rxon.channel));
@@ -5552,7 +5664,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
 
 		scan_ch->channel = channels[i].chan;
 
-		ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel);
+		ch_info = iwl4965_get_channel_info(priv, phymode,
+					 scan_ch->channel);
 		if (!is_channel_valid(ch_info)) {
 			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
 				       scan_ch->channel);
@@ -5574,7 +5687,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
 		scan_ch->active_dwell = cpu_to_le16(active_dwell);
 		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
 
-		/* Set power levels to defaults */
+		/* Set txpower levels to defaults */
 		scan_ch->tpc.dsp_atten = 110;
 		/* scan_pwr_info->tpc.dsp_atten; */
 
@@ -5584,8 +5697,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
 		else {
 			scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
 			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
-			 * power level
-			 scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+			 * power level:
+			 * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3;
 			 */
 		}
 
@@ -5603,7 +5716,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
 	return added;
 }
 
-static void iwl_reset_channel_flag(struct iwl_priv *priv)
+static void iwl4965_reset_channel_flag(struct iwl4965_priv *priv)
 {
 	int i, j;
 	for (i = 0; i < 3; i++) {
@@ -5613,13 +5726,13 @@ static void iwl_reset_channel_flag(struct iwl_priv *priv)
 	}
 }
 
-static void iwl_init_hw_rates(struct iwl_priv *priv,
+static void iwl4965_init_hw_rates(struct iwl4965_priv *priv,
 			      struct ieee80211_rate *rates)
 {
 	int i;
 
 	for (i = 0; i < IWL_RATE_COUNT; i++) {
-		rates[i].rate = iwl_rates[i].ieee * 5;
+		rates[i].rate = iwl4965_rates[i].ieee * 5;
 		rates[i].val = i; /* Rate scaling will work on indexes */
 		rates[i].val2 = i;
 		rates[i].flags = IEEE80211_RATE_SUPPORTED;
@@ -5631,7 +5744,7 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
 			 * If CCK 1M then set rate flag to CCK else CCK_2
 			 * which is CCK | PREAMBLE2
 			 */
-			rates[i].flags |= (iwl_rates[i].plcp == 10) ?
+			rates[i].flags |= (iwl4965_rates[i].plcp == 10) ?
 				IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
 		}
 
@@ -5639,16 +5752,14 @@ static void iwl_init_hw_rates(struct iwl_priv *priv,
 		if (IWL_BASIC_RATES_MASK & (1 << i))
 			rates[i].flags |= IEEE80211_RATE_BASIC;
 	}
-
-	iwl4965_init_hw_rates(priv, rates);
 }
 
 /**
- * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ * iwl4965_init_geos - Initialize mac80211's geo/channel info based from eeprom
  */
-static int iwl_init_geos(struct iwl_priv *priv)
+static int iwl4965_init_geos(struct iwl4965_priv *priv)
 {
-	struct iwl_channel_info *ch;
+	struct iwl4965_channel_info *ch;
 	struct ieee80211_hw_mode *modes;
 	struct ieee80211_channel *channels;
 	struct ieee80211_channel *geo_ch;
@@ -5658,10 +5769,8 @@ static int iwl_init_geos(struct iwl_priv *priv)
 		A = 0,
 		B = 1,
 		G = 2,
-		A_11N = 3,
-		G_11N = 4,
 	};
-	int mode_count = 5;
+	int mode_count = 3;
 
 	if (priv->modes) {
 		IWL_DEBUG_INFO("Geography modes already initialized.\n");
@@ -5696,11 +5805,14 @@ static int iwl_init_geos(struct iwl_priv *priv)
 
 	/* 5.2GHz channels start after the 2.4GHz channels */
 	modes[A].mode = MODE_IEEE80211A;
-	modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+	modes[A].channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)];
 	modes[A].rates = rates;
 	modes[A].num_rates = 8;	/* just OFDM */
 	modes[A].rates = &rates[4];
 	modes[A].num_channels = 0;
+#ifdef CONFIG_IWL4965_HT
+	iwl4965_init_ht_hw_capab(&modes[A].ht_info, MODE_IEEE80211A);
+#endif
 
 	modes[B].mode = MODE_IEEE80211B;
 	modes[B].channels = channels;
@@ -5713,23 +5825,14 @@ static int iwl_init_geos(struct iwl_priv *priv)
 	modes[G].rates = rates;
 	modes[G].num_rates = 12;	/* OFDM & CCK */
 	modes[G].num_channels = 0;
-
-	modes[G_11N].mode = MODE_IEEE80211G;
-	modes[G_11N].channels = channels;
-	modes[G_11N].num_rates = 13;        /* OFDM & CCK */
-	modes[G_11N].rates = rates;
-	modes[G_11N].num_channels = 0;
-
-	modes[A_11N].mode = MODE_IEEE80211A;
-	modes[A_11N].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
-	modes[A_11N].rates = &rates[4];
-	modes[A_11N].num_rates = 9; /* just OFDM */
-	modes[A_11N].num_channels = 0;
+#ifdef CONFIG_IWL4965_HT
+	iwl4965_init_ht_hw_capab(&modes[G].ht_info, MODE_IEEE80211G);
+#endif
 
 	priv->ieee_channels = channels;
 	priv->ieee_rates = rates;
 
-	iwl_init_hw_rates(priv, rates);
+	iwl4965_init_hw_rates(priv, rates);
 
 	for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
 		ch = &priv->channel_info[i];
@@ -5744,11 +5847,9 @@ static int iwl_init_geos(struct iwl_priv *priv)
 
 		if (is_channel_a_band(ch)) {
 			geo_ch = &modes[A].channels[modes[A].num_channels++];
-			modes[A_11N].num_channels++;
 		} else {
 			geo_ch = &modes[B].channels[modes[B].num_channels++];
 			modes[G].num_channels++;
-			modes[G_11N].num_channels++;
 		}
 
 		geo_ch->freq = ieee80211chan2mhz(ch->channel);
@@ -5814,57 +5915,22 @@ static int iwl_init_geos(struct iwl_priv *priv)
  *
  ******************************************************************************/
 
-static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+static void iwl4965_dealloc_ucode_pci(struct iwl4965_priv *priv)
 {
-	if (priv->ucode_code.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_code.len,
-				    priv->ucode_code.v_addr,
-				    priv->ucode_code.p_addr);
-		priv->ucode_code.v_addr = NULL;
-	}
-	if (priv->ucode_data.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_data.len,
-				    priv->ucode_data.v_addr,
-				    priv->ucode_data.p_addr);
-		priv->ucode_data.v_addr = NULL;
-	}
-	if (priv->ucode_data_backup.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_data_backup.len,
-				    priv->ucode_data_backup.v_addr,
-				    priv->ucode_data_backup.p_addr);
-		priv->ucode_data_backup.v_addr = NULL;
-	}
-	if (priv->ucode_init.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_init.len,
-				    priv->ucode_init.v_addr,
-				    priv->ucode_init.p_addr);
-		priv->ucode_init.v_addr = NULL;
-	}
-	if (priv->ucode_init_data.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_init_data.len,
-				    priv->ucode_init_data.v_addr,
-				    priv->ucode_init_data.p_addr);
-		priv->ucode_init_data.v_addr = NULL;
-	}
-	if (priv->ucode_boot.v_addr != NULL) {
-		pci_free_consistent(priv->pci_dev,
-				    priv->ucode_boot.len,
-				    priv->ucode_boot.v_addr,
-				    priv->ucode_boot.p_addr);
-		priv->ucode_boot.v_addr = NULL;
-	}
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+	iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
 }
 
 /**
- * iwl_verify_inst_full - verify runtime uCode image in card vs. host,
+ * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host,
  *     looking at all data.
  */
-static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 *image,
+				 u32 len)
 {
 	u32 val;
 	u32 save_len = len;
@@ -5873,18 +5939,18 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
 
 	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc)
 		return rc;
 
-	iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+	iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
 
 	errcnt = 0;
 	for (; len > 0; len -= sizeof(u32), image++) {
 		/* read data comes through single port, auto-incr addr */
 		/* NOTE: Use the debugless read so we don't flood kernel log
 		 * if IWL_DL_IO is set */
-		val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+		val = _iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT);
 		if (val != le32_to_cpu(*image)) {
 			IWL_ERROR("uCode INST section is invalid at "
 				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
@@ -5896,7 +5962,7 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
 		}
 	}
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 
 	if (!errcnt)
 		IWL_DEBUG_INFO
@@ -5907,11 +5973,11 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
 
 
 /**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ * iwl4965_verify_inst_sparse - verify runtime uCode image in card vs. host,
  *   using sample data 100 bytes apart.  If these sample points are good,
  *   it's a pretty good bet that everything between them is good, too.
  */
-static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+static int iwl4965_verify_inst_sparse(struct iwl4965_priv *priv, __le32 *image, u32 len)
 {
 	u32 val;
 	int rc = 0;
@@ -5920,7 +5986,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
 
 	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc)
 		return rc;
 
@@ -5928,9 +5994,9 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
 		/* read data comes through single port, auto-incr addr */
 		/* NOTE: Use the debugless read so we don't flood kernel log
 		 * if IWL_DL_IO is set */
-		iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR,
+		iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR,
 			i + RTC_INST_LOWER_BOUND);
-		val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+		val = _iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT);
 		if (val != le32_to_cpu(*image)) {
 #if 0 /* Enable this if you want to see details */
 			IWL_ERROR("uCode INST section is invalid at "
@@ -5944,17 +6010,17 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
 		}
 	}
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 
 	return rc;
 }
 
 
 /**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
+ * iwl4965_verify_ucode - determine which instruction image is in SRAM,
  *    and verify its contents
  */
-static int iwl_verify_ucode(struct iwl_priv *priv)
+static int iwl4965_verify_ucode(struct iwl4965_priv *priv)
 {
 	__le32 *image;
 	u32 len;
@@ -5963,7 +6029,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
 	/* Try bootstrap */
 	image = (__le32 *)priv->ucode_boot.v_addr;
 	len = priv->ucode_boot.len;
-	rc = iwl_verify_inst_sparse(priv, image, len);
+	rc = iwl4965_verify_inst_sparse(priv, image, len);
 	if (rc == 0) {
 		IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
 		return 0;
@@ -5972,7 +6038,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
 	/* Try initialize */
 	image = (__le32 *)priv->ucode_init.v_addr;
 	len = priv->ucode_init.len;
-	rc = iwl_verify_inst_sparse(priv, image, len);
+	rc = iwl4965_verify_inst_sparse(priv, image, len);
 	if (rc == 0) {
 		IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
 		return 0;
@@ -5981,7 +6047,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
 	/* Try runtime/protocol */
 	image = (__le32 *)priv->ucode_code.v_addr;
 	len = priv->ucode_code.len;
-	rc = iwl_verify_inst_sparse(priv, image, len);
+	rc = iwl4965_verify_inst_sparse(priv, image, len);
 	if (rc == 0) {
 		IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
 		return 0;
@@ -5989,18 +6055,19 @@ static int iwl_verify_ucode(struct iwl_priv *priv)
 
 	IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
 
-	/* Show first several data entries in instruction SRAM.
-	 * Selection of bootstrap image is arbitrary. */
+	/* Since nothing seems to match, show first several data entries in
+	 * instruction SRAM, so maybe visual inspection will give a clue.
+	 * Selection of bootstrap image (vs. other images) is arbitrary. */
 	image = (__le32 *)priv->ucode_boot.v_addr;
 	len = priv->ucode_boot.len;
-	rc = iwl_verify_inst_full(priv, image, len);
+	rc = iwl4965_verify_inst_full(priv, image, len);
 
 	return rc;
 }
 
 
 /* check contents of special bootstrap uCode SRAM */
-static int iwl_verify_bsm(struct iwl_priv *priv)
+static int iwl4965_verify_bsm(struct iwl4965_priv *priv)
 {
 	__le32 *image = priv->ucode_boot.v_addr;
 	u32 len = priv->ucode_boot.len;
@@ -6010,11 +6077,11 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
 	IWL_DEBUG_INFO("Begin verify bsm\n");
 
 	/* verify BSM SRAM contents */
-	val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG);
+	val = iwl4965_read_prph(priv, BSM_WR_DWCOUNT_REG);
 	for (reg = BSM_SRAM_LOWER_BOUND;
 	     reg < BSM_SRAM_LOWER_BOUND + len;
 	     reg += sizeof(u32), image ++) {
-		val = iwl_read_restricted_reg(priv, reg);
+		val = iwl4965_read_prph(priv, reg);
 		if (val != le32_to_cpu(*image)) {
 			IWL_ERROR("BSM uCode verification failed at "
 				  "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
@@ -6031,7 +6098,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
 }
 
 /**
- * iwl_load_bsm - Load bootstrap instructions
+ * iwl4965_load_bsm - Load bootstrap instructions
  *
  * BSM operation:
  *
@@ -6062,7 +6129,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv)
  * the runtime uCode instructions and the backup data cache into SRAM,
  * and re-launches the runtime uCode from where it left off.
  */
-static int iwl_load_bsm(struct iwl_priv *priv)
+static int iwl4965_load_bsm(struct iwl4965_priv *priv)
 {
 	__le32 *image = priv->ucode_boot.v_addr;
 	u32 len = priv->ucode_boot.len;
@@ -6082,8 +6149,8 @@ static int iwl_load_bsm(struct iwl_priv *priv)
 		return -EINVAL;
 
 	/* Tell bootstrap uCode where to find the "Initialize" uCode
-	 *   in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965.
-	 * NOTE:  iwl_initialize_alive_start() will replace these values,
+	 *   in host DRAM ... host DRAM physical address bits 35:4 for 4965.
+	 * NOTE:  iwl4965_initialize_alive_start() will replace these values,
 	 *        after the "initialize" uCode has run, to point to
 	 *        runtime/protocol instructions and backup data cache. */
 	pinst = priv->ucode_init.p_addr >> 4;
@@ -6091,42 +6158,42 @@ static int iwl_load_bsm(struct iwl_priv *priv)
 	inst_len = priv->ucode_init.len;
 	data_len = priv->ucode_init_data.len;
 
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc)
 		return rc;
 
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
-	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
-	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
+	iwl4965_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+	iwl4965_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+	iwl4965_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+	iwl4965_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
 
 	/* Fill BSM memory with bootstrap instructions */
 	for (reg_offset = BSM_SRAM_LOWER_BOUND;
 	     reg_offset < BSM_SRAM_LOWER_BOUND + len;
 	     reg_offset += sizeof(u32), image++)
-		_iwl_write_restricted_reg(priv, reg_offset,
+		_iwl4965_write_prph(priv, reg_offset,
 					  le32_to_cpu(*image));
 
-	rc = iwl_verify_bsm(priv);
+	rc = iwl4965_verify_bsm(priv);
 	if (rc) {
-		iwl_release_restricted_access(priv);
+		iwl4965_release_nic_access(priv);
 		return rc;
 	}
 
 	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
-	iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0);
-	iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG,
+	iwl4965_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
+	iwl4965_write_prph(priv, BSM_WR_MEM_DST_REG,
 				 RTC_INST_LOWER_BOUND);
-	iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+	iwl4965_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
 
 	/* Load bootstrap code into instruction SRAM now,
 	 *   to prepare to load "initialize" uCode */
-	iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+	iwl4965_write_prph(priv, BSM_WR_CTRL_REG,
 		BSM_WR_CTRL_REG_BIT_START);
 
 	/* Wait for load of bootstrap uCode to finish */
 	for (i = 0; i < 100; i++) {
-		done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG);
+		done = iwl4965_read_prph(priv, BSM_WR_CTRL_REG);
 		if (!(done & BSM_WR_CTRL_REG_BIT_START))
 			break;
 		udelay(10);
@@ -6140,29 +6207,30 @@ static int iwl_load_bsm(struct iwl_priv *priv)
 
 	/* Enable future boot loads whenever power management unit triggers it
 	 *   (e.g. when powering back up after power-save shutdown) */
-	iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+	iwl4965_write_prph(priv, BSM_WR_CTRL_REG,
 		BSM_WR_CTRL_REG_BIT_START_EN);
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 
 	return 0;
 }
 
-static void iwl_nic_start(struct iwl_priv *priv)
+static void iwl4965_nic_start(struct iwl4965_priv *priv)
 {
 	/* Remove all resets to allow NIC to operate */
-	iwl_write32(priv, CSR_RESET, 0);
+	iwl4965_write32(priv, CSR_RESET, 0);
 }
 
+
 /**
- * iwl_read_ucode - Read uCode images from disk file.
+ * iwl4965_read_ucode - Read uCode images from disk file.
  *
  * Copy into buffers for card to fetch via bus-mastering
  */
-static int iwl_read_ucode(struct iwl_priv *priv)
+static int iwl4965_read_ucode(struct iwl4965_priv *priv)
 {
-	struct iwl_ucode *ucode;
-	int rc = 0;
+	struct iwl4965_ucode *ucode;
+	int ret;
 	const struct firmware *ucode_raw;
 	const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode";
 	u8 *src;
@@ -6171,9 +6239,10 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 
 	/* Ask kernel firmware_class module to get the boot firmware off disk.
 	 * request_firmware() is synchronous, file is in memory on return. */
-	rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
-	if (rc < 0) {
-		IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc);
+	ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+	if (ret < 0) {
+		IWL_ERROR("%s firmware file req failed: Reason %d\n",
+					name, ret);
 		goto error;
 	}
 
@@ -6183,7 +6252,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 	/* Make sure that we got at least our header! */
 	if (ucode_raw->size < sizeof(*ucode)) {
 		IWL_ERROR("File size way too small!\n");
-		rc = -EINVAL;
+		ret = -EINVAL;
 		goto err_release;
 	}
 
@@ -6216,43 +6285,43 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 
 		IWL_DEBUG_INFO("uCode file size %d too small\n",
 			       (int)ucode_raw->size);
-		rc = -EINVAL;
+		ret = -EINVAL;
 		goto err_release;
 	}
 
 	/* Verify that uCode images will fit in card's SRAM */
 	if (inst_size > IWL_MAX_INST_SIZE) {
-		IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n",
-			       (int)inst_size);
-		rc = -EINVAL;
+		IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n",
+			       inst_size);
+		ret = -EINVAL;
 		goto err_release;
 	}
 
 	if (data_size > IWL_MAX_DATA_SIZE) {
-		IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n",
-			       (int)data_size);
-		rc = -EINVAL;
+		IWL_DEBUG_INFO("uCode data len %d too large to fit in\n",
+				data_size);
+		ret = -EINVAL;
 		goto err_release;
 	}
 	if (init_size > IWL_MAX_INST_SIZE) {
 		IWL_DEBUG_INFO
-		    ("uCode init instr len %d too large to fit in card\n",
-		     (int)init_size);
-		rc = -EINVAL;
+		    ("uCode init instr len %d too large to fit in\n",
+		      init_size);
+		ret = -EINVAL;
 		goto err_release;
 	}
 	if (init_data_size > IWL_MAX_DATA_SIZE) {
 		IWL_DEBUG_INFO
-		    ("uCode init data len %d too large to fit in card\n",
-		     (int)init_data_size);
-		rc = -EINVAL;
+		    ("uCode init data len %d too large to fit in\n",
+		      init_data_size);
+		ret = -EINVAL;
 		goto err_release;
 	}
 	if (boot_size > IWL_MAX_BSM_SIZE) {
 		IWL_DEBUG_INFO
-		    ("uCode boot instr len %d too large to fit in bsm\n",
-		     (int)boot_size);
-		rc = -EINVAL;
+		    ("uCode boot instr len %d too large to fit in\n",
+		      boot_size);
+		ret = -EINVAL;
 		goto err_release;
 	}
 
@@ -6262,66 +6331,50 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 	 * 1) unmodified from disk
 	 * 2) backup cache for save/restore during power-downs */
 	priv->ucode_code.len = inst_size;
-	priv->ucode_code.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_code.len,
-				 &(priv->ucode_code.p_addr));
+	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
 
 	priv->ucode_data.len = data_size;
-	priv->ucode_data.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_data.len,
-				 &(priv->ucode_data.p_addr));
+	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
 
 	priv->ucode_data_backup.len = data_size;
-	priv->ucode_data_backup.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_data_backup.len,
-				 &(priv->ucode_data_backup.p_addr));
-
+	iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
 
 	/* Initialization instructions and data */
-	priv->ucode_init.len = init_size;
-	priv->ucode_init.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_init.len,
-				 &(priv->ucode_init.p_addr));
-
-	priv->ucode_init_data.len = init_data_size;
-	priv->ucode_init_data.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_init_data.len,
-				 &(priv->ucode_init_data.p_addr));
+	if (init_size && init_data_size) {
+		priv->ucode_init.len = init_size;
+		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
+
+		priv->ucode_init_data.len = init_data_size;
+		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
+
+		if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
+			goto err_pci_alloc;
+	}
 
 	/* Bootstrap (instructions only, no data) */
-	priv->ucode_boot.len = boot_size;
-	priv->ucode_boot.v_addr =
-	    pci_alloc_consistent(priv->pci_dev,
-				 priv->ucode_boot.len,
-				 &(priv->ucode_boot.p_addr));
+	if (boot_size) {
+		priv->ucode_boot.len = boot_size;
+		iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
 
-	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
-	    !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr ||
-	    !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr)
-		goto err_pci_alloc;
+		if (!priv->ucode_boot.v_addr)
+			goto err_pci_alloc;
+	}
 
 	/* Copy images into buffers for card's bus-master reads ... */
 
 	/* Runtime instructions (first block of data in file) */
 	src = &ucode->data[0];
 	len = priv->ucode_code.len;
-	IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n",
-		       (int)len);
+	IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %Zd\n", len);
 	memcpy(priv->ucode_code.v_addr, src, len);
 	IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
 		priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
 
 	/* Runtime data (2nd block)
-	 * NOTE:  Copy into backup buffer will be done in iwl_up()  */
+	 * NOTE:  Copy into backup buffer will be done in iwl4965_up()  */
 	src = &ucode->data[inst_size];
 	len = priv->ucode_data.len;
-	IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n",
-		       (int)len);
+	IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len);
 	memcpy(priv->ucode_data.v_addr, src, len);
 	memcpy(priv->ucode_data_backup.v_addr, src, len);
 
@@ -6329,8 +6382,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 	if (init_size) {
 		src = &ucode->data[inst_size + data_size];
 		len = priv->ucode_init.len;
-		IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n",
-			       (int)len);
+		IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n",
+				len);
 		memcpy(priv->ucode_init.v_addr, src, len);
 	}
 
@@ -6338,16 +6391,15 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 	if (init_data_size) {
 		src = &ucode->data[inst_size + data_size + init_size];
 		len = priv->ucode_init_data.len;
-		IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
-			       (int)len);
+		IWL_DEBUG_INFO("Copying (but not loading) init data len %Zd\n",
+			       len);
 		memcpy(priv->ucode_init_data.v_addr, src, len);
 	}
 
 	/* Bootstrap instructions (5th block) */
 	src = &ucode->data[inst_size + data_size + init_size + init_data_size];
 	len = priv->ucode_boot.len;
-	IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
-		       (int)len);
+	IWL_DEBUG_INFO("Copying (but not loading) boot instr len %Zd\n", len);
 	memcpy(priv->ucode_boot.v_addr, src, len);
 
 	/* We have our copies now, allow OS release its copies */
@@ -6356,19 +6408,19 @@ static int iwl_read_ucode(struct iwl_priv *priv)
 
  err_pci_alloc:
 	IWL_ERROR("failed to allocate pci memory\n");
-	rc = -ENOMEM;
-	iwl_dealloc_ucode_pci(priv);
+	ret = -ENOMEM;
+	iwl4965_dealloc_ucode_pci(priv);
 
  err_release:
 	release_firmware(ucode_raw);
 
  error:
-	return rc;
+	return ret;
 }
 
 
 /**
- * iwl_set_ucode_ptrs - Set uCode address location
+ * iwl4965_set_ucode_ptrs - Set uCode address location
  *
  * Tell initialization uCode where to find runtime uCode.
  *
@@ -6376,7 +6428,7 @@ static int iwl_read_ucode(struct iwl_priv *priv)
  * We need to replace them to load runtime uCode inst and data,
  * and to save runtime data when powering down.
  */
-static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+static int iwl4965_set_ucode_ptrs(struct iwl4965_priv *priv)
 {
 	dma_addr_t pinst;
 	dma_addr_t pdata;
@@ -6388,24 +6440,24 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
 	pdata = priv->ucode_data_backup.p_addr >> 4;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	rc = iwl_grab_restricted_access(priv);
+	rc = iwl4965_grab_nic_access(priv);
 	if (rc) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return rc;
 	}
 
 	/* Tell bootstrap uCode where to find image to load */
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
-	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
-	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+	iwl4965_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+	iwl4965_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+	iwl4965_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
 				 priv->ucode_data.len);
 
 	/* Inst bytecount must be last to set up, bit 31 signals uCode
 	 *   that all new ptr/size info is in place */
-	iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+	iwl4965_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
 				 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
 
-	iwl_release_restricted_access(priv);
+	iwl4965_release_nic_access(priv);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -6415,7 +6467,7 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
 }
 
 /**
- * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved
+ * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received
  *
  * Called after REPLY_ALIVE notification received from "initialize" uCode.
  *
@@ -6425,7 +6477,7 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
  *
  * Tell "initialize" uCode to go ahead and load the runtime uCode.
 */
-static void iwl_init_alive_start(struct iwl_priv *priv)
+static void iwl4965_init_alive_start(struct iwl4965_priv *priv)
 {
 	/* Check alive response for "valid" sign from uCode */
 	if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
@@ -6438,7 +6490,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
 	/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
 	 * This is a paranoid check, because we would not have gotten the
 	 * "initialize" alive if code weren't properly loaded.  */
-	if (iwl_verify_ucode(priv)) {
+	if (iwl4965_verify_ucode(priv)) {
 		/* Runtime instruction load was bad;
 		 * take it all the way back down so we can try again */
 		IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
@@ -6452,7 +6504,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
 	 * load and launch runtime uCode, which will send us another "Alive"
 	 * notification. */
 	IWL_DEBUG_INFO("Initialization Alive received.\n");
-	if (iwl_set_ucode_ptrs(priv)) {
+	if (iwl4965_set_ucode_ptrs(priv)) {
 		/* Runtime instruction load won't happen;
 		 * take it all the way back down so we can try again */
 		IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
@@ -6466,11 +6518,11 @@ static void iwl_init_alive_start(struct iwl_priv *priv)
 
 
 /**
- * iwl_alive_start - called after REPLY_ALIVE notification received
+ * iwl4965_alive_start - called after REPLY_ALIVE notification received
  *                   from protocol/runtime uCode (initialization uCode's
- *                   Alive gets handled by iwl_init_alive_start()).
+ *                   Alive gets handled by iwl4965_init_alive_start()).
  */
-static void iwl_alive_start(struct iwl_priv *priv)
+static void iwl4965_alive_start(struct iwl4965_priv *priv)
 {
 	int rc = 0;
 
@@ -6486,14 +6538,14 @@ static void iwl_alive_start(struct iwl_priv *priv)
 	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
 	 * This is a paranoid check, because we would not have gotten the
 	 * "runtime" alive if code weren't properly loaded.  */
-	if (iwl_verify_ucode(priv)) {
+	if (iwl4965_verify_ucode(priv)) {
 		/* Runtime instruction load was bad;
 		 * take it all the way back down so we can try again */
 		IWL_DEBUG_INFO("Bad runtime uCode load.\n");
 		goto restart;
 	}
 
-	iwl_clear_stations_table(priv);
+	iwl4965_clear_stations_table(priv);
 
 	rc = iwl4965_alive_notify(priv);
 	if (rc) {
@@ -6502,78 +6554,61 @@ static void iwl_alive_start(struct iwl_priv *priv)
 		goto restart;
 	}
 
-	/* After the ALIVE response, we can process host commands */
+	/* After the ALIVE response, we can send host commands to 4965 uCode */
 	set_bit(STATUS_ALIVE, &priv->status);
 
 	/* Clear out the uCode error bit if it is set */
 	clear_bit(STATUS_FW_ERROR, &priv->status);
 
-	rc = iwl_init_channel_map(priv);
+	rc = iwl4965_init_channel_map(priv);
 	if (rc) {
 		IWL_ERROR("initializing regulatory failed: %d\n", rc);
 		return;
 	}
 
-	iwl_init_geos(priv);
+	iwl4965_init_geos(priv);
+	iwl4965_reset_channel_flag(priv);
 
-	if (iwl_is_rfkill(priv))
+	if (iwl4965_is_rfkill(priv))
 		return;
 
-	if (!priv->mac80211_registered) {
-		/* Unlock so any user space entry points can call back into
-		 * the driver without a deadlock... */
-		mutex_unlock(&priv->mutex);
-		iwl_rate_control_register(priv->hw);
-		rc = ieee80211_register_hw(priv->hw);
-		priv->hw->conf.beacon_int = 100;
-		mutex_lock(&priv->mutex);
-
-		if (rc) {
-			iwl_rate_control_unregister(priv->hw);
-			IWL_ERROR("Failed to register network "
-				  "device (error %d)\n", rc);
-			return;
-		}
-
-		priv->mac80211_registered = 1;
-
-		iwl_reset_channel_flag(priv);
-	} else
-		ieee80211_start_queues(priv->hw);
+	ieee80211_start_queues(priv->hw);
 
 	priv->active_rate = priv->rates_mask;
 	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
 
-	iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
+	iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
 
-	if (iwl_is_associated(priv)) {
-		struct iwl_rxon_cmd *active_rxon =
-				(struct iwl_rxon_cmd *)(&priv->active_rxon);
+	if (iwl4965_is_associated(priv)) {
+		struct iwl4965_rxon_cmd *active_rxon =
+				(struct iwl4965_rxon_cmd *)(&priv->active_rxon);
 
 		memcpy(&priv->staging_rxon, &priv->active_rxon,
 		       sizeof(priv->staging_rxon));
 		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 	} else {
 		/* Initialize our rx_config data */
-		iwl_connection_init_rx_config(priv);
+		iwl4965_connection_init_rx_config(priv);
 		memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 	}
 
-	/* Configure BT coexistence */
-	iwl_send_bt_config(priv);
+	/* Configure Bluetooth device coexistence support */
+	iwl4965_send_bt_config(priv);
 
 	/* Configure the adapter for unassociated operation */
-	iwl_commit_rxon(priv);
+	iwl4965_commit_rxon(priv);
 
 	/* At this point, the NIC is initialized and operational */
 	priv->notif_missed_beacons = 0;
 	set_bit(STATUS_READY, &priv->status);
 
 	iwl4965_rf_kill_ct_config(priv);
+
 	IWL_DEBUG_INFO("ALIVE processing complete.\n");
+	wake_up_interruptible(&priv->wait_command_queue);
 
 	if (priv->error_recovering)
-		iwl_error_recovery(priv);
+		iwl4965_error_recovery(priv);
 
 	return;
 
@@ -6581,9 +6616,9 @@ static void iwl_alive_start(struct iwl_priv *priv)
 	queue_work(priv->workqueue, &priv->restart);
 }
 
-static void iwl_cancel_deferred_work(struct iwl_priv *priv);
+static void iwl4965_cancel_deferred_work(struct iwl4965_priv *priv);
 
-static void __iwl_down(struct iwl_priv *priv)
+static void __iwl4965_down(struct iwl4965_priv *priv)
 {
 	unsigned long flags;
 	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
@@ -6596,7 +6631,7 @@ static void __iwl_down(struct iwl_priv *priv)
 	if (!exit_pending)
 		set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-	iwl_clear_stations_table(priv);
+	iwl4965_clear_stations_table(priv);
 
 	/* Unblock any waiting calls */
 	wake_up_interruptible_all(&priv->wait_command_queue);
@@ -6607,17 +6642,17 @@ static void __iwl_down(struct iwl_priv *priv)
 		clear_bit(STATUS_EXIT_PENDING, &priv->status);
 
 	/* stop and reset the on-board processor */
-	iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+	iwl4965_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 
 	/* tell the device to stop sending interrupts */
-	iwl_disable_interrupts(priv);
+	iwl4965_disable_interrupts(priv);
 
 	if (priv->mac80211_registered)
 		ieee80211_stop_queues(priv->hw);
 
-	/* If we have not previously called iwl_init() then
+	/* If we have not previously called iwl4965_init() then
 	 * clear all bits but the RF Kill and SUSPEND bits and return */
-	if (!iwl_is_init(priv)) {
+	if (!iwl4965_is_init(priv)) {
 		priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
 					STATUS_RF_KILL_HW |
 			       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
@@ -6639,53 +6674,52 @@ static void __iwl_down(struct iwl_priv *priv)
 				STATUS_FW_ERROR;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	iwl4965_clear_bit(priv, CSR_GP_CNTRL,
+			 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	iwl_hw_txq_ctx_stop(priv);
-	iwl_hw_rxq_stop(priv);
+	iwl4965_hw_txq_ctx_stop(priv);
+	iwl4965_hw_rxq_stop(priv);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if (!iwl_grab_restricted_access(priv)) {
-		iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+	if (!iwl4965_grab_nic_access(priv)) {
+		iwl4965_write_prph(priv, APMG_CLK_DIS_REG,
 					 APMG_CLK_VAL_DMA_CLK_RQT);
-		iwl_release_restricted_access(priv);
+		iwl4965_release_nic_access(priv);
 	}
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	udelay(5);
 
-	iwl_hw_nic_stop_master(priv);
-	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-	iwl_hw_nic_reset(priv);
+	iwl4965_hw_nic_stop_master(priv);
+	iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+	iwl4965_hw_nic_reset(priv);
 
  exit:
-	memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
+	memset(&priv->card_alive, 0, sizeof(struct iwl4965_alive_resp));
 
 	if (priv->ibss_beacon)
 		dev_kfree_skb(priv->ibss_beacon);
 	priv->ibss_beacon = NULL;
 
 	/* clear out any free frames */
-	iwl_clear_free_frames(priv);
+	iwl4965_clear_free_frames(priv);
 }
 
-static void iwl_down(struct iwl_priv *priv)
+static void iwl4965_down(struct iwl4965_priv *priv)
 {
 	mutex_lock(&priv->mutex);
-	__iwl_down(priv);
+	__iwl4965_down(priv);
 	mutex_unlock(&priv->mutex);
 
-	iwl_cancel_deferred_work(priv);
+	iwl4965_cancel_deferred_work(priv);
 }
 
 #define MAX_HW_RESTARTS 5
 
-static int __iwl_up(struct iwl_priv *priv)
+static int __iwl4965_up(struct iwl4965_priv *priv)
 {
-	DECLARE_MAC_BUF(mac);
 	int rc, i;
-	u32 hw_rf_kill = 0;
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
 		IWL_WARNING("Exit pending; will not bring the NIC up\n");
@@ -6695,56 +6729,65 @@ static int __iwl_up(struct iwl_priv *priv)
 	if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
 		IWL_WARNING("Radio disabled by SW RF kill (module "
 			    "parameter)\n");
-		return 0;
+		return -ENODEV;
+	}
+
+	/* If platform's RF_KILL switch is NOT set to KILL */
+	if (iwl4965_read32(priv, CSR_GP_CNTRL) &
+				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+	else {
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+		if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
+			IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+			return -ENODEV;
+		}
+	}
+
+	if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
+		IWL_ERROR("ucode not available for device bringup\n");
+		return -EIO;
 	}
 
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+	iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
 
-	rc = iwl_hw_nic_init(priv);
+	rc = iwl4965_hw_nic_init(priv);
 	if (rc) {
 		IWL_ERROR("Unable to int nic\n");
 		return rc;
 	}
 
 	/* make sure rfkill handshake bits are cleared */
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+	iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR,
 		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 
 	/* clear (again), then enable host interrupts */
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-	iwl_enable_interrupts(priv);
+	iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
+	iwl4965_enable_interrupts(priv);
 
 	/* really make sure rfkill handshake bits are cleared */
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
 	/* Copy original ucode data image from disk into backup cache.
 	 * This will be used to initialize the on-board processor's
 	 * data SRAM for a clean start when the runtime program first loads. */
 	memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
-			priv->ucode_data.len);
-
-	/* If platform's RF_KILL switch is set to KILL,
-	 * wait for BIT_INT_RF_KILL interrupt before loading uCode
-	 * and getting things started */
-	if (!(iwl_read32(priv, CSR_GP_CNTRL) &
-				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
-		hw_rf_kill = 1;
+	       priv->ucode_data.len);
 
-	if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) {
-		IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+	/* We return success when we resume from suspend and rf_kill is on. */
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status))
 		return 0;
-	}
 
 	for (i = 0; i < MAX_HW_RESTARTS; i++) {
 
-		iwl_clear_stations_table(priv);
+		iwl4965_clear_stations_table(priv);
 
 		/* load bootstrap state machine,
 		 * load bootstrap program into processor's memory,
 		 * prepare to load the "initialize" uCode */
-		rc = iwl_load_bsm(priv);
+		rc = iwl4965_load_bsm(priv);
 
 		if (rc) {
 			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
@@ -6752,14 +6795,7 @@ static int __iwl_up(struct iwl_priv *priv)
 		}
 
 		/* start card; "initialize" will load runtime ucode */
-		iwl_nic_start(priv);
-
-		/* MAC Address location in EEPROM same for 3945/4965 */
-		get_eeprom_mac(priv, priv->mac_addr);
-		IWL_DEBUG_INFO("MAC address: %s\n",
-			       print_mac(mac, priv->mac_addr));
-
-		SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+		iwl4965_nic_start(priv);
 
 		IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
 
@@ -6767,7 +6803,7 @@ static int __iwl_up(struct iwl_priv *priv)
 	}
 
 	set_bit(STATUS_EXIT_PENDING, &priv->status);
-	__iwl_down(priv);
+	__iwl4965_down(priv);
 
 	/* tried to restart and config the device for as long as our
 	 * patience could withstand */
@@ -6782,35 +6818,35 @@ static int __iwl_up(struct iwl_priv *priv)
  *
  *****************************************************************************/
 
-static void iwl_bg_init_alive_start(struct work_struct *data)
+static void iwl4965_bg_init_alive_start(struct work_struct *data)
 {
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, init_alive_start.work);
+	struct iwl4965_priv *priv =
+	    container_of(data, struct iwl4965_priv, init_alive_start.work);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
-	iwl_init_alive_start(priv);
+	iwl4965_init_alive_start(priv);
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_alive_start(struct work_struct *data)
+static void iwl4965_bg_alive_start(struct work_struct *data)
 {
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, alive_start.work);
+	struct iwl4965_priv *priv =
+	    container_of(data, struct iwl4965_priv, alive_start.work);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
-	iwl_alive_start(priv);
+	iwl4965_alive_start(priv);
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_rf_kill(struct work_struct *work)
+static void iwl4965_bg_rf_kill(struct work_struct *work)
 {
-	struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
+	struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, rf_kill);
 
 	wake_up_interruptible(&priv->wait_command_queue);
 
@@ -6819,7 +6855,7 @@ static void iwl_bg_rf_kill(struct work_struct *work)
 
 	mutex_lock(&priv->mutex);
 
-	if (!iwl_is_rfkill(priv)) {
+	if (!iwl4965_is_rfkill(priv)) {
 		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
 			  "HW and/or SW RF Kill no longer active, restarting "
 			  "device\n");
@@ -6840,10 +6876,10 @@ static void iwl_bg_rf_kill(struct work_struct *work)
 
 #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
 
-static void iwl_bg_scan_check(struct work_struct *data)
+static void iwl4965_bg_scan_check(struct work_struct *data)
 {
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, scan_check.work);
+	struct iwl4965_priv *priv =
+	    container_of(data, struct iwl4965_priv, scan_check.work);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
@@ -6856,22 +6892,22 @@ static void iwl_bg_scan_check(struct work_struct *data)
 			  jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
 
 		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
-			iwl_send_scan_abort(priv);
+			iwl4965_send_scan_abort(priv);
 	}
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_request_scan(struct work_struct *data)
+static void iwl4965_bg_request_scan(struct work_struct *data)
 {
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, request_scan);
-	struct iwl_host_cmd cmd = {
+	struct iwl4965_priv *priv =
+	    container_of(data, struct iwl4965_priv, request_scan);
+	struct iwl4965_host_cmd cmd = {
 		.id = REPLY_SCAN_CMD,
-		.len = sizeof(struct iwl_scan_cmd),
+		.len = sizeof(struct iwl4965_scan_cmd),
 		.meta.flags = CMD_SIZE_HUGE,
 	};
 	int rc = 0;
-	struct iwl_scan_cmd *scan;
+	struct iwl4965_scan_cmd *scan;
 	struct ieee80211_conf *conf = NULL;
 	u8 direct_mask;
 	int phymode;
@@ -6880,7 +6916,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 
 	mutex_lock(&priv->mutex);
 
-	if (!iwl_is_ready(priv)) {
+	if (!iwl4965_is_ready(priv)) {
 		IWL_WARNING("request scan called when driver not ready.\n");
 		goto done;
 	}
@@ -6909,7 +6945,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 		goto done;
 	}
 
-	if (iwl_is_rfkill(priv)) {
+	if (iwl4965_is_rfkill(priv)) {
 		IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
 		goto done;
 	}
@@ -6925,7 +6961,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	}
 
 	if (!priv->scan) {
-		priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
+		priv->scan = kmalloc(sizeof(struct iwl4965_scan_cmd) +
 				     IWL_MAX_SCAN_SIZE, GFP_KERNEL);
 		if (!priv->scan) {
 			rc = -ENOMEM;
@@ -6933,12 +6969,12 @@ static void iwl_bg_request_scan(struct work_struct *data)
 		}
 	}
 	scan = priv->scan;
-	memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+	memset(scan, 0, sizeof(struct iwl4965_scan_cmd) + IWL_MAX_SCAN_SIZE);
 
 	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
 	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
 
-	if (iwl_is_associated(priv)) {
+	if (iwl4965_is_associated(priv)) {
 		u16 interval = 0;
 		u32 extra;
 		u32 suspend_time = 100;
@@ -6968,14 +7004,14 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	if (priv->one_direct_scan) {
 		IWL_DEBUG_SCAN
 		    ("Kicking off one direct scan for '%s'\n",
-		     iwl_escape_essid(priv->direct_ssid,
+		     iwl4965_escape_essid(priv->direct_ssid,
 				      priv->direct_ssid_len));
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].len = priv->direct_ssid_len;
 		memcpy(scan->direct_scan[0].ssid,
 		       priv->direct_ssid, priv->direct_ssid_len);
 		direct_mask = 1;
-	} else if (!iwl_is_associated(priv) && priv->essid_len) {
+	} else if (!iwl4965_is_associated(priv) && priv->essid_len) {
 		scan->direct_scan[0].id = WLAN_EID_SSID;
 		scan->direct_scan[0].len = priv->essid_len;
 		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
@@ -6986,7 +7022,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	/* We don't build a direct scan probe request; the uCode will do
 	 * that based on the direct_mask added to each channel entry */
 	scan->tx_cmd.len = cpu_to_le16(
-		iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+		iwl4965_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
 			IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
 	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
 	scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
@@ -7000,7 +7036,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	case 2:
 		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
 		scan->tx_cmd.rate_n_flags =
-				iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
+				iwl4965_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
 				RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK);
 
 		scan->good_CRC_th = 0;
@@ -7009,7 +7045,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
 
 	case 1:
 		scan->tx_cmd.rate_n_flags =
-				iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
+				iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
 				RATE_MCS_ANT_B_MSK);
 		scan->good_CRC_th = IWL_GOOD_CRC_TH;
 		phymode = MODE_IEEE80211A;
@@ -7036,23 +7072,23 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	if (direct_mask)
 		IWL_DEBUG_SCAN
 		    ("Initiating direct scan for %s.\n",
-		     iwl_escape_essid(priv->essid, priv->essid_len));
+		     iwl4965_escape_essid(priv->essid, priv->essid_len));
 	else
 		IWL_DEBUG_SCAN("Initiating indirect scan.\n");
 
 	scan->channel_count =
-		iwl_get_channels_for_scan(
+		iwl4965_get_channels_for_scan(
 			priv, phymode, 1, /* active */
 			direct_mask,
 			(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
 
 	cmd.len += le16_to_cpu(scan->tx_cmd.len) +
-	    scan->channel_count * sizeof(struct iwl_scan_channel);
+	    scan->channel_count * sizeof(struct iwl4965_scan_channel);
 	cmd.data = scan;
 	scan->len = cpu_to_le16(cmd.len);
 
 	set_bit(STATUS_SCAN_HW, &priv->status);
-	rc = iwl_send_cmd_sync(priv, &cmd);
+	rc = iwl4965_send_cmd_sync(priv, &cmd);
 	if (rc)
 		goto done;
 
@@ -7063,50 +7099,52 @@ static void iwl_bg_request_scan(struct work_struct *data)
 	return;
 
  done:
-	/* inform mac80211 sacn aborted */
+	/* inform mac80211 scan aborted */
 	queue_work(priv->workqueue, &priv->scan_completed);
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_up(struct work_struct *data)
+static void iwl4965_bg_up(struct work_struct *data)
 {
-	struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
+	struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv, up);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
-	__iwl_up(priv);
+	__iwl4965_up(priv);
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_restart(struct work_struct *data)
+static void iwl4965_bg_restart(struct work_struct *data)
 {
-	struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
+	struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv, restart);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
-	iwl_down(priv);
+	iwl4965_down(priv);
 	queue_work(priv->workqueue, &priv->up);
 }
 
-static void iwl_bg_rx_replenish(struct work_struct *data)
+static void iwl4965_bg_rx_replenish(struct work_struct *data)
 {
-	struct iwl_priv *priv =
-	    container_of(data, struct iwl_priv, rx_replenish);
+	struct iwl4965_priv *priv =
+	    container_of(data, struct iwl4965_priv, rx_replenish);
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
 	mutex_lock(&priv->mutex);
-	iwl_rx_replenish(priv);
+	iwl4965_rx_replenish(priv);
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_post_associate(struct work_struct *data)
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+
+static void iwl4965_bg_post_associate(struct work_struct *data)
 {
-	struct iwl_priv *priv = container_of(data, struct iwl_priv,
+	struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv,
 					     post_associate.work);
 
 	int rc = 0;
@@ -7128,20 +7166,20 @@ static void iwl_bg_post_associate(struct work_struct *data)
 
 	mutex_lock(&priv->mutex);
 
-	if (!priv->interface_id || !priv->is_open) {
+	if (!priv->vif || !priv->is_open) {
 		mutex_unlock(&priv->mutex);
 		return;
 	}
-	iwl_scan_cancel_timeout(priv, 200);
+	iwl4965_scan_cancel_timeout(priv, 200);
 
 	conf = ieee80211_get_hw_conf(priv->hw);
 
 	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_commit_rxon(priv);
+	iwl4965_commit_rxon(priv);
 
-	memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-	iwl_setup_rxon_timing(priv);
-	rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+	memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd));
+	iwl4965_setup_rxon_timing(priv);
+	rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON_TIMING,
 			      sizeof(priv->rxon_timing), &priv->rxon_timing);
 	if (rc)
 		IWL_WARNING("REPLY_RXON_TIMING failed - "
@@ -7149,15 +7187,10 @@ static void iwl_bg_post_associate(struct work_struct *data)
 
 	priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
-#ifdef CONFIG_IWLWIFI_HT
-	if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
-		iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht);
-	else {
-		priv->active_rate_ht[0] = 0;
-		priv->active_rate_ht[1] = 0;
-		priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
-	}
-#endif /* CONFIG_IWLWIFI_HT*/
+#ifdef CONFIG_IWL4965_HT
+	if (priv->current_ht_config.is_ht)
+		iwl4965_set_rxon_ht(priv, &priv->current_ht_config);
+#endif /* CONFIG_IWL4965_HT*/
 	iwl4965_set_rxon_chain(priv);
 	priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
 
@@ -7180,22 +7213,22 @@ static void iwl_bg_post_associate(struct work_struct *data)
 
 	}
 
-	iwl_commit_rxon(priv);
+	iwl4965_commit_rxon(priv);
 
 	switch (priv->iw_mode) {
 	case IEEE80211_IF_TYPE_STA:
-		iwl_rate_scale_init(priv->hw, IWL_AP_ID);
+		iwl4965_rate_scale_init(priv->hw, IWL_AP_ID);
 		break;
 
 	case IEEE80211_IF_TYPE_IBSS:
 
 		/* clear out the station table */
-		iwl_clear_stations_table(priv);
+		iwl4965_clear_stations_table(priv);
 
-		iwl_rxon_add_station(priv, BROADCAST_ADDR, 0);
-		iwl_rxon_add_station(priv, priv->bssid, 0);
-		iwl_rate_scale_init(priv->hw, IWL_STA_ID);
-		iwl_send_beacon_cmd(priv);
+		iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0);
+		iwl4965_rxon_add_station(priv, priv->bssid, 0);
+		iwl4965_rate_scale_init(priv->hw, IWL_STA_ID);
+		iwl4965_send_beacon_cmd(priv);
 
 		break;
 
@@ -7205,55 +7238,61 @@ static void iwl_bg_post_associate(struct work_struct *data)
 		break;
 	}
 
-	iwl_sequence_reset(priv);
+	iwl4965_sequence_reset(priv);
 
-#ifdef CONFIG_IWLWIFI_SENSITIVITY
+#ifdef CONFIG_IWL4965_SENSITIVITY
 	/* Enable Rx differential gain and sensitivity calibrations */
 	iwl4965_chain_noise_reset(priv);
 	priv->start_calib = 1;
-#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+#endif /* CONFIG_IWL4965_SENSITIVITY */
 
 	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
 		priv->assoc_station_added = 1;
 
-#ifdef CONFIG_IWLWIFI_QOS
-	iwl_activate_qos(priv, 0);
-#endif /* CONFIG_IWLWIFI_QOS */
+#ifdef CONFIG_IWL4965_QOS
+	iwl4965_activate_qos(priv, 0);
+#endif /* CONFIG_IWL4965_QOS */
+	/* we have just associated, don't start scan too early */
+	priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_abort_scan(struct work_struct *work)
+static void iwl4965_bg_abort_scan(struct work_struct *work)
 {
-	struct iwl_priv *priv = container_of(work, struct iwl_priv,
-					     abort_scan);
+	struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, abort_scan);
 
-	if (!iwl_is_ready(priv))
+	if (!iwl4965_is_ready(priv))
 		return;
 
 	mutex_lock(&priv->mutex);
 
 	set_bit(STATUS_SCAN_ABORTING, &priv->status);
-	iwl_send_scan_abort(priv);
+	iwl4965_send_scan_abort(priv);
 
 	mutex_unlock(&priv->mutex);
 }
 
-static void iwl_bg_scan_completed(struct work_struct *work)
+static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+
+static void iwl4965_bg_scan_completed(struct work_struct *work)
 {
-	struct iwl_priv *priv =
-	    container_of(work, struct iwl_priv, scan_completed);
+	struct iwl4965_priv *priv =
+	    container_of(work, struct iwl4965_priv, scan_completed);
 
 	IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
 
 	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
 		return;
 
+	if (test_bit(STATUS_CONF_PENDING, &priv->status))
+		iwl4965_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw));
+
 	ieee80211_scan_completed(priv->hw);
 
 	/* Since setting the TXPOWER may have been deferred while
 	 * performing the scan, fire one off */
 	mutex_lock(&priv->mutex);
-	iwl_hw_reg_send_txpower(priv);
+	iwl4965_hw_reg_send_txpower(priv);
 	mutex_unlock(&priv->mutex);
 }
 
@@ -7263,50 +7302,123 @@ static void iwl_bg_scan_completed(struct work_struct *work)
  *
  *****************************************************************************/
 
-static int iwl_mac_start(struct ieee80211_hw *hw)
+#define UCODE_READY_TIMEOUT	(2 * HZ)
+
+static int iwl4965_mac_start(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
+	int ret;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
+	if (pci_enable_device(priv->pci_dev)) {
+		IWL_ERROR("Fail to pci_enable_device\n");
+		return -ENODEV;
+	}
+	pci_restore_state(priv->pci_dev);
+	pci_enable_msi(priv->pci_dev);
+
+	ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
+			  DRV_NAME, priv);
+	if (ret) {
+		IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq);
+		goto out_disable_msi;
+	}
+
 	/* we should be verifying the device is ready to be opened */
 	mutex_lock(&priv->mutex);
 
-	priv->is_open = 1;
+	memset(&priv->staging_rxon, 0, sizeof(struct iwl4965_rxon_cmd));
+	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+	 * ucode filename and max sizes are card-specific. */
+
+	if (!priv->ucode_code.len) {
+		ret = iwl4965_read_ucode(priv);
+		if (ret) {
+			IWL_ERROR("Could not read microcode: %d\n", ret);
+			mutex_unlock(&priv->mutex);
+			goto out_release_irq;
+		}
+	}
 
-	if (!iwl_is_rfkill(priv))
-		ieee80211_start_queues(priv->hw);
+	ret = __iwl4965_up(priv);
 
 	mutex_unlock(&priv->mutex);
+
+	if (ret)
+		goto out_release_irq;
+
+	IWL_DEBUG_INFO("Start UP work done.\n");
+
+	if (test_bit(STATUS_IN_SUSPEND, &priv->status))
+		return 0;
+
+	/* Wait for START_ALIVE from ucode. Otherwise callbacks from
+	 * mac80211 will not be run successfully. */
+	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+			test_bit(STATUS_READY, &priv->status),
+			UCODE_READY_TIMEOUT);
+	if (!ret) {
+		if (!test_bit(STATUS_READY, &priv->status)) {
+			IWL_ERROR("Wait for START_ALIVE timeout after %dms.\n",
+				  jiffies_to_msecs(UCODE_READY_TIMEOUT));
+			ret = -ETIMEDOUT;
+			goto out_release_irq;
+		}
+	}
+
+	priv->is_open = 1;
 	IWL_DEBUG_MAC80211("leave\n");
 	return 0;
+
+out_release_irq:
+	free_irq(priv->pci_dev->irq, priv);
+out_disable_msi:
+	pci_disable_msi(priv->pci_dev);
+	pci_disable_device(priv->pci_dev);
+	priv->is_open = 0;
+	IWL_DEBUG_MAC80211("leave - failed\n");
+	return ret;
 }
 
-static void iwl_mac_stop(struct ieee80211_hw *hw)
+static void iwl4965_mac_stop(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
+	if (!priv->is_open) {
+		IWL_DEBUG_MAC80211("leave - skip\n");
+		return;
+	}
 
-	mutex_lock(&priv->mutex);
-	/* stop mac, cancel any scan request and clear
-	 * RXON_FILTER_ASSOC_MSK BIT
-	 */
 	priv->is_open = 0;
-	iwl_scan_cancel_timeout(priv, 100);
-	cancel_delayed_work(&priv->post_associate);
-	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_commit_rxon(priv);
-	mutex_unlock(&priv->mutex);
+
+	if (iwl4965_is_ready_rf(priv)) {
+		/* stop mac, cancel any scan request and clear
+		 * RXON_FILTER_ASSOC_MSK BIT
+		 */
+		mutex_lock(&priv->mutex);
+		iwl4965_scan_cancel_timeout(priv, 100);
+		cancel_delayed_work(&priv->post_associate);
+		mutex_unlock(&priv->mutex);
+	}
+
+	iwl4965_down(priv);
+
+	flush_workqueue(priv->workqueue);
+	free_irq(priv->pci_dev->irq, priv);
+	pci_disable_msi(priv->pci_dev);
+	pci_save_state(priv->pci_dev);
+	pci_disable_device(priv->pci_dev);
 
 	IWL_DEBUG_MAC80211("leave\n");
 }
 
-static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 		      struct ieee80211_tx_control *ctl)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
@@ -7318,29 +7430,29 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
 		     ctl->tx_rate);
 
-	if (iwl_tx_skb(priv, skb, ctl))
+	if (iwl4965_tx_skb(priv, skb, ctl))
 		dev_kfree_skb_any(skb);
 
 	IWL_DEBUG_MAC80211("leave\n");
 	return 0;
 }
 
-static int iwl_mac_add_interface(struct ieee80211_hw *hw,
+static int iwl4965_mac_add_interface(struct ieee80211_hw *hw,
 				 struct ieee80211_if_init_conf *conf)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 	unsigned long flags;
 	DECLARE_MAC_BUF(mac);
 
-	IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+	IWL_DEBUG_MAC80211("enter: type %d\n", conf->type);
 
-	if (priv->interface_id) {
-		IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+	if (priv->vif) {
+		IWL_DEBUG_MAC80211("leave - vif != NULL\n");
 		return 0;
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
-	priv->interface_id = conf->if_id;
+	priv->vif = conf->vif;
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -7350,58 +7462,62 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw,
 		IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr));
 		memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
 	}
-	iwl_set_mode(priv, conf->type);
 
-	IWL_DEBUG_MAC80211("leave\n");
+	if (iwl4965_is_ready(priv))
+		iwl4965_set_mode(priv, conf->type);
+
 	mutex_unlock(&priv->mutex);
 
+	IWL_DEBUG_MAC80211("leave\n");
 	return 0;
 }
 
 /**
- * iwl_mac_config - mac80211 config callback
+ * iwl4965_mac_config - mac80211 config callback
  *
  * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
  * be set inappropriately and the driver currently sets the hardware up to
  * use it whenever needed.
  */
-static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 {
-	struct iwl_priv *priv = hw->priv;
-	const struct iwl_channel_info *ch_info;
+	struct iwl4965_priv *priv = hw->priv;
+	const struct iwl4965_channel_info *ch_info;
 	unsigned long flags;
+	int ret = 0;
 
 	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
 
-	if (!iwl_is_ready(priv)) {
+	priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+
+	if (!iwl4965_is_ready(priv)) {
 		IWL_DEBUG_MAC80211("leave - not ready\n");
-		mutex_unlock(&priv->mutex);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 
-	/* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
-	 * what is exposed through include/ declrations */
-	if (unlikely(!iwl_param_disable_hw_scan &&
+	if (unlikely(!iwl4965_param_disable_hw_scan &&
 		     test_bit(STATUS_SCANNING, &priv->status))) {
 		IWL_DEBUG_MAC80211("leave - scanning\n");
+		set_bit(STATUS_CONF_PENDING, &priv->status);
 		mutex_unlock(&priv->mutex);
 		return 0;
 	}
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel);
+	ch_info = iwl4965_get_channel_info(priv, conf->phymode, conf->channel);
 	if (!is_channel_valid(ch_info)) {
 		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
 			       conf->channel, conf->phymode);
 		IWL_DEBUG_MAC80211("leave - invalid channel\n");
 		spin_unlock_irqrestore(&priv->lock, flags);
-		mutex_unlock(&priv->mutex);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 	/* if we are switching fron ht to 2.4 clear flags
 	 * from any ht related info since 2.4 does not
 	 * support ht */
@@ -7411,57 +7527,56 @@ static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 #endif
 	)
 		priv->staging_rxon.flags = 0;
-#endif /* CONFIG_IWLWIFI_HT */
+#endif /* CONFIG_IWL4965_HT */
 
-	iwl_set_rxon_channel(priv, conf->phymode, conf->channel);
+	iwl4965_set_rxon_channel(priv, conf->phymode, conf->channel);
 
-	iwl_set_flags_for_phymode(priv, conf->phymode);
+	iwl4965_set_flags_for_phymode(priv, conf->phymode);
 
 	/* The list of supported rates and rate mask can be different
 	 * for each phymode; since the phymode may have changed, reset
 	 * the rate mask to what mac80211 lists */
-	iwl_set_rate(priv);
+	iwl4965_set_rate(priv);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 #ifdef IEEE80211_CONF_CHANNEL_SWITCH
 	if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
-		iwl_hw_channel_switch(priv, conf->channel);
-		mutex_unlock(&priv->mutex);
-		return 0;
+		iwl4965_hw_channel_switch(priv, conf->channel);
+		goto out;
 	}
 #endif
 
-	iwl_radio_kill_sw(priv, !conf->radio_enabled);
+	iwl4965_radio_kill_sw(priv, !conf->radio_enabled);
 
 	if (!conf->radio_enabled) {
 		IWL_DEBUG_MAC80211("leave - radio disabled\n");
-		mutex_unlock(&priv->mutex);
-		return 0;
+		goto out;
 	}
 
-	if (iwl_is_rfkill(priv)) {
+	if (iwl4965_is_rfkill(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF kill\n");
-		mutex_unlock(&priv->mutex);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
 
-	iwl_set_rate(priv);
+	iwl4965_set_rate(priv);
 
 	if (memcmp(&priv->active_rxon,
 		   &priv->staging_rxon, sizeof(priv->staging_rxon)))
-		iwl_commit_rxon(priv);
+		iwl4965_commit_rxon(priv);
 	else
 		IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
 
 	IWL_DEBUG_MAC80211("leave\n");
 
+out:
+	clear_bit(STATUS_CONF_PENDING, &priv->status);
 	mutex_unlock(&priv->mutex);
-
-	return 0;
+	return ret;
 }
 
-static void iwl_config_ap(struct iwl_priv *priv)
+static void iwl4965_config_ap(struct iwl4965_priv *priv)
 {
 	int rc = 0;
 
@@ -7473,12 +7588,12 @@ static void iwl_config_ap(struct iwl_priv *priv)
 
 		/* RXON - unassoc (to set timing command) */
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl_commit_rxon(priv);
+		iwl4965_commit_rxon(priv);
 
 		/* RXON Timing */
-		memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-		iwl_setup_rxon_timing(priv);
-		rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+		memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd));
+		iwl4965_setup_rxon_timing(priv);
+		rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON_TIMING,
 				sizeof(priv->rxon_timing), &priv->rxon_timing);
 		if (rc)
 			IWL_WARNING("REPLY_RXON_TIMING failed - "
@@ -7510,23 +7625,24 @@ static void iwl_config_ap(struct iwl_priv *priv)
 		}
 		/* restore RXON assoc */
 		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
-		iwl_commit_rxon(priv);
-#ifdef CONFIG_IWLWIFI_QOS
-		iwl_activate_qos(priv, 1);
+		iwl4965_commit_rxon(priv);
+#ifdef CONFIG_IWL4965_QOS
+		iwl4965_activate_qos(priv, 1);
 #endif
-		iwl_rxon_add_station(priv, BROADCAST_ADDR, 0);
+		iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0);
 	}
-	iwl_send_beacon_cmd(priv);
+	iwl4965_send_beacon_cmd(priv);
 
 	/* FIXME - we need to add code here to detect a totally new
 	 * configuration, reset the AP, unassoc, rxon timing, assoc,
 	 * clear sta table, add BCAST sta... */
 }
 
-static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
+					struct ieee80211_vif *vif,
 				    struct ieee80211_if_conf *conf)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 	DECLARE_MAC_BUF(mac);
 	unsigned long flags;
 	int rc;
@@ -7541,9 +7657,11 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
 		return 0;
 	}
 
+	if (!iwl4965_is_alive(priv))
+		return -EAGAIN;
+
 	mutex_lock(&priv->mutex);
 
-	IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
 	if (conf->bssid)
 		IWL_DEBUG_MAC80211("bssid: %s\n",
 				   print_mac(mac, conf->bssid));
@@ -7560,8 +7678,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
 		return 0;
 	}
 
-	if (priv->interface_id != if_id) {
-		IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+	if (priv->vif != vif) {
+		IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
 		mutex_unlock(&priv->mutex);
 		return 0;
 	}
@@ -7579,11 +7697,14 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
 		priv->ibss_beacon = conf->beacon;
 	}
 
+	if (iwl4965_is_rfkill(priv))
+		goto done;
+
 	if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
 	    !is_multicast_ether_addr(conf->bssid)) {
 		/* If there is currently a HW scan going on in the background
 		 * then we need to cancel it else the RXON below will fail. */
-		if (iwl_scan_cancel_timeout(priv, 100)) {
+		if (iwl4965_scan_cancel_timeout(priv, 100)) {
 			IWL_WARNING("Aborted scan still in progress "
 				    "after 100ms\n");
 			IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
@@ -7599,20 +7720,21 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
 		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
 
 		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
-			iwl_config_ap(priv);
+			iwl4965_config_ap(priv);
 		else {
-			rc = iwl_commit_rxon(priv);
+			rc = iwl4965_commit_rxon(priv);
 			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
-				iwl_rxon_add_station(
+				iwl4965_rxon_add_station(
 					priv, priv->active_rxon.bssid_addr, 1);
 		}
 
 	} else {
-		iwl_scan_cancel_timeout(priv, 100);
+		iwl4965_scan_cancel_timeout(priv, 100);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl_commit_rxon(priv);
+		iwl4965_commit_rxon(priv);
 	}
 
+ done:
 	spin_lock_irqsave(&priv->lock, flags);
 	if (!conf->ssid_len)
 		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
@@ -7628,34 +7750,35 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
 	return 0;
 }
 
-static void iwl_configure_filter(struct ieee80211_hw *hw,
+static void iwl4965_configure_filter(struct ieee80211_hw *hw,
 				 unsigned int changed_flags,
 				 unsigned int *total_flags,
 				 int mc_count, struct dev_addr_list *mc_list)
 {
 	/*
 	 * XXX: dummy
-	 * see also iwl_connection_init_rx_config
+	 * see also iwl4965_connection_init_rx_config
 	 */
 	*total_flags = 0;
 }
 
-static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
 				     struct ieee80211_if_init_conf *conf)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
 	mutex_lock(&priv->mutex);
 
-	iwl_scan_cancel_timeout(priv, 100);
-	cancel_delayed_work(&priv->post_associate);
-	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-	iwl_commit_rxon(priv);
-
-	if (priv->interface_id == conf->if_id) {
-		priv->interface_id = 0;
+	if (iwl4965_is_ready_rf(priv)) {
+		iwl4965_scan_cancel_timeout(priv, 100);
+		cancel_delayed_work(&priv->post_associate);
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl4965_commit_rxon(priv);
+	}
+	if (priv->vif == conf->vif) {
+		priv->vif = NULL;
 		memset(priv->bssid, 0, ETH_ALEN);
 		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
 		priv->essid_len = 0;
@@ -7666,19 +7789,50 @@ static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 
 }
 
-#define IWL_DELAY_NEXT_SCAN (HZ*2)
-static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
+				     struct ieee80211_vif *vif,
+				     struct ieee80211_bss_conf *bss_conf,
+				     u32 changes)
+{
+	struct iwl4965_priv *priv = hw->priv;
+
+	if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+		if (bss_conf->use_short_preamble)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+	}
+
+	if (changes & BSS_CHANGED_ERP_CTS_PROT) {
+		if (bss_conf->use_cts_prot && (priv->phymode != MODE_IEEE80211A))
+			priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
+	}
+
+	if (changes & BSS_CHANGED_ASSOC) {
+		/*
+		 * TODO:
+		 * do stuff instead of sniffing assoc resp
+		 */
+	}
+
+	if (iwl4965_is_associated(priv))
+		iwl4965_send_rxon_assoc(priv);
+}
+
+static int iwl4965_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
 {
 	int rc = 0;
 	unsigned long flags;
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
 	mutex_lock(&priv->mutex);
 	spin_lock_irqsave(&priv->lock, flags);
 
-	if (!iwl_is_ready_rf(priv)) {
+	if (!iwl4965_is_ready_rf(priv)) {
 		rc = -EIO;
 		IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
 		goto out_unlock;
@@ -7690,17 +7844,21 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
 		goto out_unlock;
 	}
 
+	/* we don't schedule scan within next_scan_jiffies period */
+	if (priv->next_scan_jiffies &&
+			time_after(priv->next_scan_jiffies, jiffies)) {
+		rc = -EAGAIN;
+		goto out_unlock;
+	}
 	/* if we just finished scan ask for delay */
-	if (priv->last_scan_jiffies &&
-	    time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
-		       jiffies)) {
+	if (priv->last_scan_jiffies && time_after(priv->last_scan_jiffies +
+				IWL_DELAY_NEXT_SCAN, jiffies)) {
 		rc = -EAGAIN;
 		goto out_unlock;
 	}
 	if (len) {
-		IWL_DEBUG_SCAN("direct scan for  "
-			       "%s [%d]\n ",
-			       iwl_escape_essid(ssid, len), (int)len);
+		IWL_DEBUG_SCAN("direct scan for %s [%d]\n ",
+			       iwl4965_escape_essid(ssid, len), (int)len);
 
 		priv->one_direct_scan = 1;
 		priv->direct_ssid_len = (u8)
@@ -7709,7 +7867,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
 	} else
 		priv->one_direct_scan = 0;
 
-	rc = iwl_scan_initiate(priv);
+	rc = iwl4965_scan_initiate(priv);
 
 	IWL_DEBUG_MAC80211("leave\n");
 
@@ -7720,18 +7878,18 @@ out_unlock:
 	return rc;
 }
 
-static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 			   const u8 *local_addr, const u8 *addr,
 			   struct ieee80211_key_conf *key)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 	DECLARE_MAC_BUF(mac);
 	int rc = 0;
 	u8 sta_id;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
-	if (!iwl_param_hwcrypto) {
+	if (!iwl4965_param_hwcrypto) {
 		IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
 		return -EOPNOTSUPP;
 	}
@@ -7740,7 +7898,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		/* only support pairwise keys */
 		return -EOPNOTSUPP;
 
-	sta_id = iwl_hw_find_station(priv, addr);
+	sta_id = iwl4965_hw_find_station(priv, addr);
 	if (sta_id == IWL_INVALID_STATION) {
 		IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
 				   print_mac(mac, addr));
@@ -7749,24 +7907,24 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
 	mutex_lock(&priv->mutex);
 
-	iwl_scan_cancel_timeout(priv, 100);
+	iwl4965_scan_cancel_timeout(priv, 100);
 
 	switch (cmd) {
 	case  SET_KEY:
-		rc = iwl_update_sta_key_info(priv, key, sta_id);
+		rc = iwl4965_update_sta_key_info(priv, key, sta_id);
 		if (!rc) {
-			iwl_set_rxon_hwcrypto(priv, 1);
-			iwl_commit_rxon(priv);
+			iwl4965_set_rxon_hwcrypto(priv, 1);
+			iwl4965_commit_rxon(priv);
 			key->hw_key_idx = sta_id;
 			IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
 			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
 		}
 		break;
 	case DISABLE_KEY:
-		rc = iwl_clear_sta_key_info(priv, sta_id);
+		rc = iwl4965_clear_sta_key_info(priv, sta_id);
 		if (!rc) {
-			iwl_set_rxon_hwcrypto(priv, 0);
-			iwl_commit_rxon(priv);
+			iwl4965_set_rxon_hwcrypto(priv, 0);
+			iwl4965_commit_rxon(priv);
 			IWL_DEBUG_MAC80211("disable hwcrypto key\n");
 		}
 		break;
@@ -7780,18 +7938,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 	return rc;
 }
 
-static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue,
 			   const struct ieee80211_tx_queue_params *params)
 {
-	struct iwl_priv *priv = hw->priv;
-#ifdef CONFIG_IWLWIFI_QOS
+	struct iwl4965_priv *priv = hw->priv;
+#ifdef CONFIG_IWL4965_QOS
 	unsigned long flags;
 	int q;
-#endif /* CONFIG_IWL_QOS */
+#endif /* CONFIG_IWL4965_QOS */
 
 	IWL_DEBUG_MAC80211("enter\n");
 
-	if (!iwl_is_ready_rf(priv)) {
+	if (!iwl4965_is_ready_rf(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF not ready\n");
 		return -EIO;
 	}
@@ -7801,7 +7959,7 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
 		return 0;
 	}
 
-#ifdef CONFIG_IWLWIFI_QOS
+#ifdef CONFIG_IWL4965_QOS
 	if (!priv->qos_data.qos_enable) {
 		priv->qos_data.qos_active = 0;
 		IWL_DEBUG_MAC80211("leave - qos not enabled\n");
@@ -7824,30 +7982,30 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
 
 	mutex_lock(&priv->mutex);
 	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
-		iwl_activate_qos(priv, 1);
-	else if (priv->assoc_id && iwl_is_associated(priv))
-		iwl_activate_qos(priv, 0);
+		iwl4965_activate_qos(priv, 1);
+	else if (priv->assoc_id && iwl4965_is_associated(priv))
+		iwl4965_activate_qos(priv, 0);
 
 	mutex_unlock(&priv->mutex);
 
-#endif /*CONFIG_IWLWIFI_QOS */
+#endif /*CONFIG_IWL4965_QOS */
 
 	IWL_DEBUG_MAC80211("leave\n");
 	return 0;
 }
 
-static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
 				struct ieee80211_tx_queue_stats *stats)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 	int i, avail;
-	struct iwl_tx_queue *txq;
-	struct iwl_queue *q;
+	struct iwl4965_tx_queue *txq;
+	struct iwl4965_queue *q;
 	unsigned long flags;
 
 	IWL_DEBUG_MAC80211("enter\n");
 
-	if (!iwl_is_ready_rf(priv)) {
+	if (!iwl4965_is_ready_rf(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF not ready\n");
 		return -EIO;
 	}
@@ -7857,7 +8015,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
 	for (i = 0; i < AC_NUM; i++) {
 		txq = &priv->txq[i];
 		q = &txq->q;
-		avail = iwl_queue_space(q);
+		avail = iwl4965_queue_space(q);
 
 		stats->data[i].len = q->n_window - avail;
 		stats->data[i].limit = q->n_window - q->high_mark;
@@ -7871,7 +8029,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
 	return 0;
 }
 
-static int iwl_mac_get_stats(struct ieee80211_hw *hw,
+static int iwl4965_mac_get_stats(struct ieee80211_hw *hw,
 			     struct ieee80211_low_level_stats *stats)
 {
 	IWL_DEBUG_MAC80211("enter\n");
@@ -7880,7 +8038,7 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
 	return 0;
 }
 
-static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
+static u64 iwl4965_mac_get_tsf(struct ieee80211_hw *hw)
 {
 	IWL_DEBUG_MAC80211("enter\n");
 	IWL_DEBUG_MAC80211("leave\n");
@@ -7888,35 +8046,35 @@ static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
 	return 0;
 }
 
-static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 	unsigned long flags;
 
 	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter\n");
 
 	priv->lq_mngr.lq_ready = 0;
-#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWL4965_HT
 	spin_lock_irqsave(&priv->lock, flags);
-	memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info));
+	memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info));
 	spin_unlock_irqrestore(&priv->lock, flags);
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT_AGG
 /*	if (priv->lq_mngr.agg_ctrl.granted_ba)
 		iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/
 
-	memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl_agg_control));
+	memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl4965_agg_control));
 	priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10;
 	priv->lq_mngr.agg_ctrl.ba_timeout = 5000;
 	priv->lq_mngr.agg_ctrl.auto_agg = 1;
 
 	if (priv->lq_mngr.agg_ctrl.auto_agg)
 		priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED;
-#endif /*CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
+#endif /*CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 
-#ifdef CONFIG_IWLWIFI_QOS
-	iwl_reset_qos(priv);
+#ifdef CONFIG_IWL4965_QOS
+	iwl4965_reset_qos(priv);
 #endif
 
 	cancel_delayed_work(&priv->post_associate);
@@ -7941,13 +8099,19 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 
+	if (!iwl4965_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - not ready\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
 	/* we are restarting association process
 	 * clear RXON_FILTER_ASSOC_MSK bit
 	 */
 	if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
-		iwl_scan_cancel_timeout(priv, 100);
+		iwl4965_scan_cancel_timeout(priv, 100);
 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-		iwl_commit_rxon(priv);
+		iwl4965_commit_rxon(priv);
 	}
 
 	/* Per mac80211.h: This is only used in IBSS mode... */
@@ -7958,32 +8122,25 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 		return;
 	}
 
-	if (!iwl_is_ready_rf(priv)) {
-		IWL_DEBUG_MAC80211("leave - not ready\n");
-		mutex_unlock(&priv->mutex);
-		return;
-	}
-
 	priv->only_active_channel = 0;
 
-	iwl_set_rate(priv);
+	iwl4965_set_rate(priv);
 
 	mutex_unlock(&priv->mutex);
 
 	IWL_DEBUG_MAC80211("leave\n");
-
 }
 
-static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 				 struct ieee80211_tx_control *control)
 {
-	struct iwl_priv *priv = hw->priv;
+	struct iwl4965_priv *priv = hw->priv;
 	unsigned long flags;
 
 	mutex_lock(&priv->mutex);
 	IWL_DEBUG_MAC80211("enter\n");
 
-	if (!iwl_is_ready_rf(priv)) {
+	if (!iwl4965_is_ready_rf(priv)) {
 		IWL_DEBUG_MAC80211("leave - RF not ready\n");
 		mutex_unlock(&priv->mutex);
 		return -EIO;
@@ -8007,8 +8164,8 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 	IWL_DEBUG_MAC80211("leave\n");
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-#ifdef CONFIG_IWLWIFI_QOS
-	iwl_reset_qos(priv);
+#ifdef CONFIG_IWL4965_QOS
+	iwl4965_reset_qos(priv);
 #endif
 
 	queue_work(priv->workqueue, &priv->post_associate.work);
@@ -8018,133 +8175,62 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 	return 0;
 }
 
-#ifdef CONFIG_IWLWIFI_HT
-union ht_cap_info {
-	struct {
-		u16 advanced_coding_cap		:1;
-		u16 supported_chan_width_set	:1;
-		u16 mimo_power_save_mode	:2;
-		u16 green_field			:1;
-		u16 short_GI20			:1;
-		u16 short_GI40			:1;
-		u16 tx_stbc			:1;
-		u16 rx_stbc			:1;
-		u16 beam_forming		:1;
-		u16 delayed_ba			:1;
-		u16 maximal_amsdu_size		:1;
-		u16 cck_mode_at_40MHz		:1;
-		u16 psmp_support		:1;
-		u16 stbc_ctrl_frame_support	:1;
-		u16 sig_txop_protection_support	:1;
-	};
-	u16 val;
-} __attribute__ ((packed));
-
-union ht_param_info{
-	struct {
-		u8 max_rx_ampdu_factor	:2;
-		u8 mpdu_density		:3;
-		u8 reserved		:3;
-	};
-	u8 val;
-} __attribute__ ((packed));
-
-union ht_exra_param_info {
-	struct {
-		u8 ext_chan_offset		:2;
-		u8 tx_chan_width		:1;
-		u8 rifs_mode			:1;
-		u8 controlled_access_only	:1;
-		u8 service_interval_granularity	:3;
-	};
-	u8 val;
-} __attribute__ ((packed));
-
-union ht_operation_mode{
-	struct {
-		u16 op_mode	:2;
-		u16 non_GF	:1;
-		u16 reserved	:13;
-	};
-	u16 val;
-} __attribute__ ((packed));
-
+#ifdef CONFIG_IWL4965_HT
 
-static int sta_ht_info_init(struct ieee80211_ht_capability *ht_cap,
-			    struct ieee80211_ht_additional_info *ht_extra,
-			    struct sta_ht_info *ht_info_ap,
-			    struct sta_ht_info *ht_info)
+static void iwl4965_ht_info_fill(struct ieee80211_conf *conf,
+				 struct iwl4965_priv *priv)
 {
-	union ht_cap_info cap;
-	union ht_operation_mode op_mode;
-	union ht_param_info param_info;
-	union ht_exra_param_info extra_param_info;
+	struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
+	struct ieee80211_ht_info *ht_conf = &conf->ht_conf;
+	struct ieee80211_ht_bss_info *ht_bss_conf = &conf->ht_bss_conf;
 
 	IWL_DEBUG_MAC80211("enter: \n");
 
-	if (!ht_info) {
-		IWL_DEBUG_MAC80211("leave: ht_info is NULL\n");
-		return -1;
+	if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) {
+		iwl_conf->is_ht = 0;
+		return;
 	}
 
-	if (ht_cap) {
-		cap.val = (u16) le16_to_cpu(ht_cap->capabilities_info);
-		param_info.val = ht_cap->mac_ht_params_info;
-		ht_info->is_ht = 1;
-		if (cap.short_GI20)
-			ht_info->sgf |= 0x1;
-		if (cap.short_GI40)
-			ht_info->sgf |= 0x2;
-		ht_info->is_green_field = cap.green_field;
-		ht_info->max_amsdu_size = cap.maximal_amsdu_size;
-		ht_info->supported_chan_width = cap.supported_chan_width_set;
-		ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode;
-		memcpy(ht_info->supp_rates, ht_cap->supported_mcs_set, 16);
-
-		ht_info->ampdu_factor = param_info.max_rx_ampdu_factor;
-		ht_info->mpdu_density = param_info.mpdu_density;
-
-		IWL_DEBUG_MAC80211("SISO mask 0x%X MIMO mask 0x%X \n",
-				    ht_cap->supported_mcs_set[0],
-				    ht_cap->supported_mcs_set[1]);
-
-		if (ht_info_ap) {
-			ht_info->control_channel = ht_info_ap->control_channel;
-			ht_info->extension_chan_offset =
-				ht_info_ap->extension_chan_offset;
-			ht_info->tx_chan_width = ht_info_ap->tx_chan_width;
-			ht_info->operating_mode = ht_info_ap->operating_mode;
-		}
-
-		if (ht_extra) {
-			extra_param_info.val = ht_extra->ht_param;
-			ht_info->control_channel = ht_extra->control_chan;
-			ht_info->extension_chan_offset =
-			    extra_param_info.ext_chan_offset;
-			ht_info->tx_chan_width = extra_param_info.tx_chan_width;
-			op_mode.val = (u16)
-			    le16_to_cpu(ht_extra->operation_mode);
-			ht_info->operating_mode = op_mode.op_mode;
-			IWL_DEBUG_MAC80211("control channel %d\n",
-					    ht_extra->control_chan);
-		}
-	} else
-		ht_info->is_ht = 0;
-
+	iwl_conf->is_ht = 1;
+	priv->ps_mode = (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+
+	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
+		iwl_conf->sgf |= 0x1;
+	if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
+		iwl_conf->sgf |= 0x2;
+
+	iwl_conf->is_green_field = !!(ht_conf->cap & IEEE80211_HT_CAP_GRN_FLD);
+	iwl_conf->max_amsdu_size =
+		!!(ht_conf->cap & IEEE80211_HT_CAP_MAX_AMSDU);
+	iwl_conf->supported_chan_width =
+		!!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH);
+	iwl_conf->tx_mimo_ps_mode =
+		(u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
+	memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
+
+	iwl_conf->control_channel = ht_bss_conf->primary_channel;
+	iwl_conf->extension_chan_offset =
+		ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET;
+	iwl_conf->tx_chan_width =
+		!!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH);
+	iwl_conf->ht_protection =
+		ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION;
+	iwl_conf->non_GF_STA_present =
+		!!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT);
+
+	IWL_DEBUG_MAC80211("control channel %d\n",
+		iwl_conf->control_channel);
 	IWL_DEBUG_MAC80211("leave\n");
-	return 0;
 }
 
-static int iwl_mac_conf_ht(struct ieee80211_hw *hw,
-			   struct ieee80211_ht_capability *ht_cap,
-			   struct ieee80211_ht_additional_info *ht_extra)
+static int iwl4965_mac_conf_ht(struct ieee80211_hw *hw,
+			       struct ieee80211_conf *conf)
 {
-	struct iwl_priv *priv = hw->priv;
-	int rs;
+	struct iwl4965_priv *priv = hw->priv;
 
 	IWL_DEBUG_MAC80211("enter: \n");
 
-	rs = sta_ht_info_init(ht_cap, ht_extra, NULL, &priv->current_assoc_ht);
+	iwl4965_ht_info_fill(conf, priv);
 	iwl4965_set_rxon_chain(priv);
 
 	if (priv && priv->assoc_id &&
@@ -8159,58 +8245,33 @@ static int iwl_mac_conf_ht(struct ieee80211_hw *hw,
 		spin_unlock_irqrestore(&priv->lock, flags);
 	}
 
-	IWL_DEBUG_MAC80211("leave: control channel %d\n",
-			ht_extra->control_chan);
-	return rs;
-
+	IWL_DEBUG_MAC80211("leave:\n");
+	return 0;
 }
 
-static void iwl_set_ht_capab(struct ieee80211_hw *hw,
-			     struct ieee80211_ht_capability *ht_cap,
-			     u8 use_wide_chan)
+static void iwl4965_set_ht_capab(struct ieee80211_hw *hw,
+			struct ieee80211_ht_cap *ht_cap,
+			u8 use_current_config)
 {
-	union ht_cap_info cap;
-	union ht_param_info param_info;
-
-	memset(&cap, 0, sizeof(union ht_cap_info));
-	memset(&param_info, 0, sizeof(union ht_param_info));
-
-	cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K;
-	cap.green_field = 1;
-	cap.short_GI20 = 1;
-	cap.short_GI40 = 1;
-	cap.supported_chan_width_set = use_wide_chan;
-	cap.mimo_power_save_mode = 0x3;
-
-	param_info.max_rx_ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
-	param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF;
-	ht_cap->capabilities_info = (__le16) cpu_to_le16(cap.val);
-	ht_cap->mac_ht_params_info = (u8) param_info.val;
+	struct ieee80211_conf *conf = &hw->conf;
+	struct ieee80211_hw_mode *mode = conf->mode;
 
-	ht_cap->supported_mcs_set[0] = 0xff;
-	ht_cap->supported_mcs_set[1] = 0xff;
-	ht_cap->supported_mcs_set[4] =
-	    (cap.supported_chan_width_set) ? 0x1: 0x0;
+	if (use_current_config) {
+		ht_cap->cap_info = cpu_to_le16(conf->ht_conf.cap);
+		memcpy(ht_cap->supp_mcs_set,
+				conf->ht_conf.supp_mcs_set, 16);
+	} else {
+		ht_cap->cap_info = cpu_to_le16(mode->ht_info.cap);
+		memcpy(ht_cap->supp_mcs_set,
+				mode->ht_info.supp_mcs_set, 16);
+	}
+	ht_cap->ampdu_params_info =
+		(mode->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) |
+		((mode->ht_info.ampdu_density << 2) &
+					IEEE80211_HT_CAP_AMPDU_DENSITY);
 }
 
-static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw,
-				 struct ieee80211_ht_capability *ht_cap)
-{
-	u8 use_wide_channel = 1;
-	struct iwl_priv *priv = hw->priv;
-
-	IWL_DEBUG_MAC80211("enter: \n");
-	if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
-		use_wide_channel = 0;
-
-	/* no fat tx allowed on 2.4GHZ */
-	if (priv->phymode != MODE_IEEE80211A)
-		use_wide_channel = 0;
-
-	iwl_set_ht_capab(hw, ht_cap, use_wide_channel);
-	IWL_DEBUG_MAC80211("leave: \n");
-}
-#endif /*CONFIG_IWLWIFI_HT*/
+#endif /*CONFIG_IWL4965_HT*/
 
 /*****************************************************************************
  *
@@ -8218,7 +8279,7 @@ static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw,
  *
  *****************************************************************************/
 
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWL4965_DEBUG
 
 /*
  * The following adds a new attribute to the sysfs representation
@@ -8230,7 +8291,7 @@ static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw,
 
 static ssize_t show_debug_level(struct device_driver *d, char *buf)
 {
-	return sprintf(buf, "0x%08X\n", iwl_debug_level);
+	return sprintf(buf, "0x%08X\n", iwl4965_debug_level);
 }
 static ssize_t store_debug_level(struct device_driver *d,
 				 const char *buf, size_t count)
@@ -8243,7 +8304,7 @@ static ssize_t store_debug_level(struct device_driver *d,
 		printk(KERN_INFO DRV_NAME
 		       ": %s is not in hex or decimal form.\n", buf);
 	else
-		iwl_debug_level = val;
+		iwl4965_debug_level = val;
 
 	return strnlen(buf, count);
 }
@@ -8251,7 +8312,7 @@ static ssize_t store_debug_level(struct device_driver *d,
 static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
 		   show_debug_level, store_debug_level);
 
-#endif /* CONFIG_IWLWIFI_DEBUG */
+#endif /* CONFIG_IWL4965_DEBUG */
 
 static ssize_t show_rf_kill(struct device *d,
 			    struct device_attribute *attr, char *buf)
@@ -8262,7 +8323,7 @@ static ssize_t show_rf_kill(struct device *d,
 	 * 2 - HW based RF kill active
 	 * 3 - Both HW and SW based RF kill active
 	 */
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 	int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
 		  (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
 
@@ -8273,10 +8334,10 @@ static ssize_t store_rf_kill(struct device *d,
 			     struct device_attribute *attr,
 			     const char *buf, size_t count)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 
 	mutex_lock(&priv->mutex);
-	iwl_radio_kill_sw(priv, buf[0] == '1');
+	iwl4965_radio_kill_sw(priv, buf[0] == '1');
 	mutex_unlock(&priv->mutex);
 
 	return count;
@@ -8287,12 +8348,12 @@ static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
 static ssize_t show_temperature(struct device *d,
 				struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 
-	if (!iwl_is_alive(priv))
+	if (!iwl4965_is_alive(priv))
 		return -EAGAIN;
 
-	return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv));
+	return sprintf(buf, "%d\n", iwl4965_hw_get_temperature(priv));
 }
 
 static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
@@ -8301,15 +8362,15 @@ static ssize_t show_rs_window(struct device *d,
 			      struct device_attribute *attr,
 			      char *buf)
 {
-	struct iwl_priv *priv = d->driver_data;
-	return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID);
+	struct iwl4965_priv *priv = d->driver_data;
+	return iwl4965_fill_rs_info(priv->hw, buf, IWL_AP_ID);
 }
 static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
 
 static ssize_t show_tx_power(struct device *d,
 			     struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 	return sprintf(buf, "%d\n", priv->user_txpower_limit);
 }
 
@@ -8317,7 +8378,7 @@ static ssize_t store_tx_power(struct device *d,
 			      struct device_attribute *attr,
 			      const char *buf, size_t count)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 	char *p = (char *)buf;
 	u32 val;
 
@@ -8326,7 +8387,7 @@ static ssize_t store_tx_power(struct device *d,
 		printk(KERN_INFO DRV_NAME
 		       ": %s is not in decimal form.\n", buf);
 	else
-		iwl_hw_reg_set_txpower(priv, val);
+		iwl4965_hw_reg_set_txpower(priv, val);
 
 	return count;
 }
@@ -8336,7 +8397,7 @@ static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
 static ssize_t show_flags(struct device *d,
 			  struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 
 	return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
 }
@@ -8345,19 +8406,19 @@ static ssize_t store_flags(struct device *d,
 			   struct device_attribute *attr,
 			   const char *buf, size_t count)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 	u32 flags = simple_strtoul(buf, NULL, 0);
 
 	mutex_lock(&priv->mutex);
 	if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
 		/* Cancel any currently running scans... */
-		if (iwl_scan_cancel_timeout(priv, 100))
+		if (iwl4965_scan_cancel_timeout(priv, 100))
 			IWL_WARNING("Could not cancel scan.\n");
 		else {
 			IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
 				       flags);
 			priv->staging_rxon.flags = cpu_to_le32(flags);
-			iwl_commit_rxon(priv);
+			iwl4965_commit_rxon(priv);
 		}
 	}
 	mutex_unlock(&priv->mutex);
@@ -8370,7 +8431,7 @@ static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
 static ssize_t show_filter_flags(struct device *d,
 				 struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 
 	return sprintf(buf, "0x%04X\n",
 		le32_to_cpu(priv->active_rxon.filter_flags));
@@ -8380,20 +8441,20 @@ static ssize_t store_filter_flags(struct device *d,
 				  struct device_attribute *attr,
 				  const char *buf, size_t count)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 	u32 filter_flags = simple_strtoul(buf, NULL, 0);
 
 	mutex_lock(&priv->mutex);
 	if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
 		/* Cancel any currently running scans... */
-		if (iwl_scan_cancel_timeout(priv, 100))
+		if (iwl4965_scan_cancel_timeout(priv, 100))
 			IWL_WARNING("Could not cancel scan.\n");
 		else {
 			IWL_DEBUG_INFO("Committing rxon.filter_flags = "
 				       "0x%04X\n", filter_flags);
 			priv->staging_rxon.filter_flags =
 				cpu_to_le32(filter_flags);
-			iwl_commit_rxon(priv);
+			iwl4965_commit_rxon(priv);
 		}
 	}
 	mutex_unlock(&priv->mutex);
@@ -8407,20 +8468,20 @@ static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
 static ssize_t show_tune(struct device *d,
 			 struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 
 	return sprintf(buf, "0x%04X\n",
 		       (priv->phymode << 8) |
 			le16_to_cpu(priv->active_rxon.channel));
 }
 
-static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode);
+static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode);
 
 static ssize_t store_tune(struct device *d,
 			  struct device_attribute *attr,
 			  const char *buf, size_t count)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
 	char *p = (char *)buf;
 	u16 tune = simple_strtoul(p, &p, 0);
 	u8 phymode = (tune >> 8) & 0xff;
@@ -8431,9 +8492,9 @@ static ssize_t store_tune(struct device *d,
 	mutex_lock(&priv->mutex);
 	if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
 	    (priv->phymode != phymode)) {
-		const struct iwl_channel_info *ch_info;
+		const struct iwl4965_channel_info *ch_info;
 
-		ch_info = iwl_get_channel_info(priv, phymode, channel);
+		ch_info = iwl4965_get_channel_info(priv, phymode, channel);
 		if (!ch_info) {
 			IWL_WARNING("Requested invalid phymode/channel "
 				    "combination: %d %d\n", phymode, channel);
@@ -8442,18 +8503,18 @@ static ssize_t store_tune(struct device *d,
 		}
 
 		/* Cancel any currently running scans... */
-		if (iwl_scan_cancel_timeout(priv, 100))
+		if (iwl4965_scan_cancel_timeout(priv, 100))
 			IWL_WARNING("Could not cancel scan.\n");
 		else {
 			IWL_DEBUG_INFO("Committing phymode and "
 				       "rxon.channel = %d %d\n",
 				       phymode, channel);
 
-			iwl_set_rxon_channel(priv, phymode, channel);
-			iwl_set_flags_for_phymode(priv, phymode);
+			iwl4965_set_rxon_channel(priv, phymode, channel);
+			iwl4965_set_flags_for_phymode(priv, phymode);
 
-			iwl_set_rate(priv);
-			iwl_commit_rxon(priv);
+			iwl4965_set_rate(priv);
+			iwl4965_commit_rxon(priv);
 		}
 	}
 	mutex_unlock(&priv->mutex);
@@ -8463,13 +8524,13 @@ static ssize_t store_tune(struct device *d,
 
 static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
 
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
 
 static ssize_t show_measurement(struct device *d,
 				struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	struct iwl_spectrum_notification measure_report;
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+	struct iwl4965_spectrum_notification measure_report;
 	u32 size = sizeof(measure_report), len = 0, ofs = 0;
 	u8 *data = (u8 *) & measure_report;
 	unsigned long flags;
@@ -8501,7 +8562,7 @@ static ssize_t store_measurement(struct device *d,
 				 struct device_attribute *attr,
 				 const char *buf, size_t count)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
 	struct ieee80211_measurement_params params = {
 		.channel = le16_to_cpu(priv->active_rxon.channel),
 		.start_time = cpu_to_le64(priv->last_tsf),
@@ -8527,20 +8588,20 @@ static ssize_t store_measurement(struct device *d,
 
 	IWL_DEBUG_INFO("Invoking measurement of type %d on "
 		       "channel %d (for '%s')\n", type, params.channel, buf);
-	iwl_get_measurement(priv, &params, type);
+	iwl4965_get_measurement(priv, &params, type);
 
 	return count;
 }
 
 static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
 		   show_measurement, store_measurement);
-#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */
+#endif /* CONFIG_IWL4965_SPECTRUM_MEASUREMENT */
 
 static ssize_t store_retry_rate(struct device *d,
 				struct device_attribute *attr,
 				const char *buf, size_t count)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
 
 	priv->retry_rate = simple_strtoul(buf, NULL, 0);
 	if (priv->retry_rate <= 0)
@@ -8552,7 +8613,7 @@ static ssize_t store_retry_rate(struct device *d,
 static ssize_t show_retry_rate(struct device *d,
 			       struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
 	return sprintf(buf, "%d", priv->retry_rate);
 }
 
@@ -8563,14 +8624,14 @@ static ssize_t store_power_level(struct device *d,
 				 struct device_attribute *attr,
 				 const char *buf, size_t count)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
 	int rc;
 	int mode;
 
 	mode = simple_strtoul(buf, NULL, 0);
 	mutex_lock(&priv->mutex);
 
-	if (!iwl_is_ready(priv)) {
+	if (!iwl4965_is_ready(priv)) {
 		rc = -EAGAIN;
 		goto out;
 	}
@@ -8581,7 +8642,7 @@ static ssize_t store_power_level(struct device *d,
 		mode |= IWL_POWER_ENABLED;
 
 	if (mode != priv->power_mode) {
-		rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode));
+		rc = iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(mode));
 		if (rc) {
 			IWL_DEBUG_MAC80211("failed setting power mode.\n");
 			goto out;
@@ -8617,7 +8678,7 @@ static const s32 period_duration[] = {
 static ssize_t show_power_level(struct device *d,
 				struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
 	int level = IWL_POWER_LEVEL(priv->power_mode);
 	char *p = buf;
 
@@ -8652,18 +8713,18 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
 static ssize_t show_channels(struct device *d,
 			     struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
 	int len = 0, i;
 	struct ieee80211_channel *channels = NULL;
 	const struct ieee80211_hw_mode *hw_mode = NULL;
 	int count = 0;
 
-	if (!iwl_is_ready(priv))
+	if (!iwl4965_is_ready(priv))
 		return -EAGAIN;
 
-	hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G);
+	hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211G);
 	if (!hw_mode)
-		hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B);
+		hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211B);
 	if (hw_mode) {
 		channels = hw_mode->channels;
 		count = hw_mode->num_channels;
@@ -8690,7 +8751,7 @@ static ssize_t show_channels(struct device *d,
 			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
 			       "active/passive" : "passive only");
 
-	hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A);
+	hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211A);
 	if (hw_mode) {
 		channels = hw_mode->channels;
 		count = hw_mode->num_channels;
@@ -8726,17 +8787,17 @@ static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
 static ssize_t show_statistics(struct device *d,
 			       struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
-	u32 size = sizeof(struct iwl_notif_statistics);
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
+	u32 size = sizeof(struct iwl4965_notif_statistics);
 	u32 len = 0, ofs = 0;
 	u8 *data = (u8 *) & priv->statistics;
 	int rc = 0;
 
-	if (!iwl_is_alive(priv))
+	if (!iwl4965_is_alive(priv))
 		return -EAGAIN;
 
 	mutex_lock(&priv->mutex);
-	rc = iwl_send_statistics_request(priv);
+	rc = iwl4965_send_statistics_request(priv);
 	mutex_unlock(&priv->mutex);
 
 	if (rc) {
@@ -8764,9 +8825,9 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
 static ssize_t show_antenna(struct device *d,
 			    struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
 
-	if (!iwl_is_alive(priv))
+	if (!iwl4965_is_alive(priv))
 		return -EAGAIN;
 
 	return sprintf(buf, "%d\n", priv->antenna);
@@ -8777,7 +8838,7 @@ static ssize_t store_antenna(struct device *d,
 			     const char *buf, size_t count)
 {
 	int ant;
-	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl4965_priv *priv = dev_get_drvdata(d);
 
 	if (count == 0)
 		return 0;
@@ -8789,7 +8850,7 @@ static ssize_t store_antenna(struct device *d,
 
 	if ((ant >= 0) && (ant <= 2)) {
 		IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
-		priv->antenna = (enum iwl_antenna)ant;
+		priv->antenna = (enum iwl4965_antenna)ant;
 	} else
 		IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
 
@@ -8802,8 +8863,8 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
 static ssize_t show_status(struct device *d,
 			   struct device_attribute *attr, char *buf)
 {
-	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-	if (!iwl_is_alive(priv))
+	struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data;
+	if (!iwl4965_is_alive(priv))
 		return -EAGAIN;
 	return sprintf(buf, "0x%08x\n", (int)priv->status);
 }
@@ -8817,7 +8878,7 @@ static ssize_t dump_error_log(struct device *d,
 	char *p = (char *)buf;
 
 	if (p[0] == '1')
-		iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data);
+		iwl4965_dump_nic_error_log((struct iwl4965_priv *)d->driver_data);
 
 	return strnlen(buf, count);
 }
@@ -8831,7 +8892,7 @@ static ssize_t dump_event_log(struct device *d,
 	char *p = (char *)buf;
 
 	if (p[0] == '1')
-		iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data);
+		iwl4965_dump_nic_event_log((struct iwl4965_priv *)d->driver_data);
 
 	return strnlen(buf, count);
 }
@@ -8844,34 +8905,34 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
  *
  *****************************************************************************/
 
-static void iwl_setup_deferred_work(struct iwl_priv *priv)
+static void iwl4965_setup_deferred_work(struct iwl4965_priv *priv)
 {
 	priv->workqueue = create_workqueue(DRV_NAME);
 
 	init_waitqueue_head(&priv->wait_command_queue);
 
-	INIT_WORK(&priv->up, iwl_bg_up);
-	INIT_WORK(&priv->restart, iwl_bg_restart);
-	INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
-	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
-	INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
-	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
-	INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
-	INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
-	INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate);
-	INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
-	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
-	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
-
-	iwl_hw_setup_deferred_work(priv);
+	INIT_WORK(&priv->up, iwl4965_bg_up);
+	INIT_WORK(&priv->restart, iwl4965_bg_restart);
+	INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish);
+	INIT_WORK(&priv->scan_completed, iwl4965_bg_scan_completed);
+	INIT_WORK(&priv->request_scan, iwl4965_bg_request_scan);
+	INIT_WORK(&priv->abort_scan, iwl4965_bg_abort_scan);
+	INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill);
+	INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update);
+	INIT_DELAYED_WORK(&priv->post_associate, iwl4965_bg_post_associate);
+	INIT_DELAYED_WORK(&priv->init_alive_start, iwl4965_bg_init_alive_start);
+	INIT_DELAYED_WORK(&priv->alive_start, iwl4965_bg_alive_start);
+	INIT_DELAYED_WORK(&priv->scan_check, iwl4965_bg_scan_check);
+
+	iwl4965_hw_setup_deferred_work(priv);
 
 	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
-		     iwl_irq_tasklet, (unsigned long)priv);
+		     iwl4965_irq_tasklet, (unsigned long)priv);
 }
 
-static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+static void iwl4965_cancel_deferred_work(struct iwl4965_priv *priv)
 {
-	iwl_hw_cancel_deferred_work(priv);
+	iwl4965_hw_cancel_deferred_work(priv);
 
 	cancel_delayed_work_sync(&priv->init_alive_start);
 	cancel_delayed_work(&priv->scan_check);
@@ -8880,14 +8941,14 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
 	cancel_work_sync(&priv->beacon_update);
 }
 
-static struct attribute *iwl_sysfs_entries[] = {
+static struct attribute *iwl4965_sysfs_entries[] = {
 	&dev_attr_antenna.attr,
 	&dev_attr_channels.attr,
 	&dev_attr_dump_errors.attr,
 	&dev_attr_dump_events.attr,
 	&dev_attr_flags.attr,
 	&dev_attr_filter_flags.attr,
-#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
 	&dev_attr_measurement.attr,
 #endif
 	&dev_attr_power_level.attr,
@@ -8903,54 +8964,56 @@ static struct attribute *iwl_sysfs_entries[] = {
 	NULL
 };
 
-static struct attribute_group iwl_attribute_group = {
+static struct attribute_group iwl4965_attribute_group = {
 	.name = NULL,		/* put in device directory */
-	.attrs = iwl_sysfs_entries,
+	.attrs = iwl4965_sysfs_entries,
 };
 
-static struct ieee80211_ops iwl_hw_ops = {
-	.tx = iwl_mac_tx,
-	.start = iwl_mac_start,
-	.stop = iwl_mac_stop,
-	.add_interface = iwl_mac_add_interface,
-	.remove_interface = iwl_mac_remove_interface,
-	.config = iwl_mac_config,
-	.config_interface = iwl_mac_config_interface,
-	.configure_filter = iwl_configure_filter,
-	.set_key = iwl_mac_set_key,
-	.get_stats = iwl_mac_get_stats,
-	.get_tx_stats = iwl_mac_get_tx_stats,
-	.conf_tx = iwl_mac_conf_tx,
-	.get_tsf = iwl_mac_get_tsf,
-	.reset_tsf = iwl_mac_reset_tsf,
-	.beacon_update = iwl_mac_beacon_update,
-#ifdef CONFIG_IWLWIFI_HT
-	.conf_ht = iwl_mac_conf_ht,
-	.get_ht_capab = iwl_mac_get_ht_capab,
-#ifdef CONFIG_IWLWIFI_HT_AGG
-	.ht_tx_agg_start = iwl_mac_ht_tx_agg_start,
-	.ht_tx_agg_stop = iwl_mac_ht_tx_agg_stop,
-	.ht_rx_agg_start = iwl_mac_ht_rx_agg_start,
-	.ht_rx_agg_stop = iwl_mac_ht_rx_agg_stop,
-#endif  /* CONFIG_IWLWIFI_HT_AGG */
-#endif  /* CONFIG_IWLWIFI_HT */
-	.hw_scan = iwl_mac_hw_scan
+static struct ieee80211_ops iwl4965_hw_ops = {
+	.tx = iwl4965_mac_tx,
+	.start = iwl4965_mac_start,
+	.stop = iwl4965_mac_stop,
+	.add_interface = iwl4965_mac_add_interface,
+	.remove_interface = iwl4965_mac_remove_interface,
+	.config = iwl4965_mac_config,
+	.config_interface = iwl4965_mac_config_interface,
+	.configure_filter = iwl4965_configure_filter,
+	.set_key = iwl4965_mac_set_key,
+	.get_stats = iwl4965_mac_get_stats,
+	.get_tx_stats = iwl4965_mac_get_tx_stats,
+	.conf_tx = iwl4965_mac_conf_tx,
+	.get_tsf = iwl4965_mac_get_tsf,
+	.reset_tsf = iwl4965_mac_reset_tsf,
+	.beacon_update = iwl4965_mac_beacon_update,
+	.bss_info_changed = iwl4965_bss_info_changed,
+#ifdef CONFIG_IWL4965_HT
+	.conf_ht = iwl4965_mac_conf_ht,
+	.ampdu_action = iwl4965_mac_ampdu_action,
+#ifdef CONFIG_IWL4965_HT_AGG
+	.ht_tx_agg_start = iwl4965_mac_ht_tx_agg_start,
+	.ht_tx_agg_stop = iwl4965_mac_ht_tx_agg_stop,
+#endif  /* CONFIG_IWL4965_HT_AGG */
+#endif  /* CONFIG_IWL4965_HT */
+	.hw_scan = iwl4965_mac_hw_scan
 };
 
-static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	int err = 0;
-	struct iwl_priv *priv;
+	struct iwl4965_priv *priv;
 	struct ieee80211_hw *hw;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
-	if (iwl_param_disable_hw_scan) {
+	/* Disabling hardware scan means that mac80211 will perform scans
+	 * "the hard way", rather than using device's scan. */
+	if (iwl4965_param_disable_hw_scan) {
 		IWL_DEBUG_INFO("Disabling hw_scan\n");
-		iwl_hw_ops.hw_scan = NULL;
+		iwl4965_hw_ops.hw_scan = NULL;
 	}
 
-	if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) ||
-	    (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) {
+	if ((iwl4965_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+	    (iwl4965_param_queues_num < IWL_MIN_NUM_QUEUES)) {
 		IWL_ERROR("invalid queues_num, should be between %d and %d\n",
 			  IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
 		err = -EINVAL;
@@ -8959,7 +9022,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	/* mac80211 allocates memory for this device instance, including
 	 *   space for this driver's private structure */
-	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops);
+	hw = ieee80211_alloc_hw(sizeof(struct iwl4965_priv), &iwl4965_hw_ops);
 	if (hw == NULL) {
 		IWL_ERROR("Can not allocate network device\n");
 		err = -ENOMEM;
@@ -8974,9 +9037,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	priv->hw = hw;
 
 	priv->pci_dev = pdev;
-	priv->antenna = (enum iwl_antenna)iwl_param_antenna;
-#ifdef CONFIG_IWLWIFI_DEBUG
-	iwl_debug_level = iwl_param_debug;
+	priv->antenna = (enum iwl4965_antenna)iwl4965_param_antenna;
+#ifdef CONFIG_IWL4965_DEBUG
+	iwl4965_debug_level = iwl4965_param_debug;
 	atomic_set(&priv->restrict_refcnt, 0);
 #endif
 	priv->retry_rate = 1;
@@ -8995,12 +9058,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	/* Tell mac80211 our Tx characteristics */
 	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
 
+	/* Default value; 4 EDCA QOS priorities */
 	hw->queues = 4;
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
+#ifdef CONFIG_IWL4965_HT
+#ifdef CONFIG_IWL4965_HT_AGG
+	/* Enhanced value; more queues, to support 11n aggregation */
 	hw->queues = 16;
-#endif /* CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
+#endif /* CONFIG_IWL4965_HT_AGG */
+#endif /* CONFIG_IWL4965_HT */
 
 	spin_lock_init(&priv->lock);
 	spin_lock_init(&priv->power_data.lock);
@@ -9021,7 +9086,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	pci_set_master(pdev);
 
-	iwl_clear_stations_table(priv);
+	/* Clear the driver's (not device's) station table */
+	iwl4965_clear_stations_table(priv);
 
 	priv->data_retry_limit = -1;
 	priv->ieee_channels = NULL;
@@ -9040,9 +9106,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	err = pci_request_regions(pdev, DRV_NAME);
 	if (err)
 		goto out_pci_disable_device;
+
 	/* We disable the RETRY_TIMEOUT register (0x41) to keep
 	 * PCI Tx retries from interfering with C3 CPU state */
 	pci_write_config_byte(pdev, 0x41, 0x00);
+
 	priv->hw_base = pci_iomap(pdev, 0, 0);
 	if (!priv->hw_base) {
 		err = -ENODEV;
@@ -9055,7 +9123,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	/* Initialize module parameter values here */
 
-	if (iwl_param_disable) {
+	/* Disable radio (SW RF KILL) via parameter when loading driver */
+	if (iwl4965_param_disable) {
 		set_bit(STATUS_RF_KILL_SW, &priv->status);
 		IWL_DEBUG_INFO("Radio disabled.\n");
 	}
@@ -9064,91 +9133,92 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 	priv->ps_mode = 0;
 	priv->use_ant_b_for_management_frame = 1; /* start with ant B */
-	priv->is_ht_enabled = 1;
-	priv->channel_width = IWL_CHANNEL_WIDTH_40MHZ;
 	priv->valid_antenna = 0x7;	/* assume all 3 connected */
 	priv->ps_mode = IWL_MIMO_PS_NONE;
-	priv->cck_power_index_compensation = iwl_read32(
-		priv, CSR_HW_REV_WA_REG);
 
+	/* Choose which receivers/antennas to use */
 	iwl4965_set_rxon_chain(priv);
 
 	printk(KERN_INFO DRV_NAME
 	       ": Detected Intel Wireless WiFi Link 4965AGN\n");
 
 	/* Device-specific setup */
-	if (iwl_hw_set_hw_setting(priv)) {
+	if (iwl4965_hw_set_hw_setting(priv)) {
 		IWL_ERROR("failed to set hw settings\n");
-		mutex_unlock(&priv->mutex);
 		goto out_iounmap;
 	}
 
-#ifdef CONFIG_IWLWIFI_QOS
-	if (iwl_param_qos_enable)
+#ifdef CONFIG_IWL4965_QOS
+	if (iwl4965_param_qos_enable)
 		priv->qos_data.qos_enable = 1;
 
-	iwl_reset_qos(priv);
+	iwl4965_reset_qos(priv);
 
 	priv->qos_data.qos_active = 0;
 	priv->qos_data.qos_cap.val = 0;
-#endif /* CONFIG_IWLWIFI_QOS */
+#endif /* CONFIG_IWL4965_QOS */
 
-	iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6);
-	iwl_setup_deferred_work(priv);
-	iwl_setup_rx_handlers(priv);
+	iwl4965_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+	iwl4965_setup_deferred_work(priv);
+	iwl4965_setup_rx_handlers(priv);
 
 	priv->rates_mask = IWL_RATES_MASK;
 	/* If power management is turned on, default to AC mode */
 	priv->power_mode = IWL_POWER_AC;
 	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
 
-	pci_enable_msi(pdev);
-
-	err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
-	if (err) {
-		IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
-		goto out_disable_msi;
-	}
-
-	mutex_lock(&priv->mutex);
+	iwl4965_disable_interrupts(priv);
 
-	err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
+	err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
 	if (err) {
 		IWL_ERROR("failed to create sysfs device attributes\n");
-		mutex_unlock(&priv->mutex);
 		goto out_release_irq;
 	}
 
-	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
-	 * ucode filename and max sizes are card-specific. */
-	err = iwl_read_ucode(priv);
+	/* nic init */
+	iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+                    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+        iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+        err = iwl4965_poll_bit(priv, CSR_GP_CNTRL,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+                          CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+        if (err < 0) {
+                IWL_DEBUG_INFO("Failed to init the card\n");
+		goto out_remove_sysfs;
+        }
+	/* Read the EEPROM */
+	err = iwl4965_eeprom_init(priv);
 	if (err) {
-		IWL_ERROR("Could not read microcode: %d\n", err);
-		mutex_unlock(&priv->mutex);
-		goto out_pci_alloc;
+		IWL_ERROR("Unable to init EEPROM\n");
+		goto out_remove_sysfs;
 	}
+	/* MAC Address location in EEPROM same for 3945/4965 */
+	get_eeprom_mac(priv, priv->mac_addr);
+	IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr));
+	SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
 
-	mutex_unlock(&priv->mutex);
-
-	IWL_DEBUG_INFO("Queing UP work.\n");
+	iwl4965_rate_control_register(priv->hw);
+	err = ieee80211_register_hw(priv->hw);
+	if (err) {
+		IWL_ERROR("Failed to register network device (error %d)\n", err);
+		goto out_remove_sysfs;
+	}
 
-	queue_work(priv->workqueue, &priv->up);
+	priv->hw->conf.beacon_int = 100;
+	priv->mac80211_registered = 1;
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
 
 	return 0;
 
- out_pci_alloc:
-	iwl_dealloc_ucode_pci(priv);
-
-	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+ out_remove_sysfs:
+	sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
 
  out_release_irq:
-	free_irq(pdev->irq, priv);
-
- out_disable_msi:
-	pci_disable_msi(pdev);
 	destroy_workqueue(priv->workqueue);
 	priv->workqueue = NULL;
-	iwl_unset_hw_setting(priv);
+	iwl4965_unset_hw_setting(priv);
 
  out_iounmap:
 	pci_iounmap(pdev, priv->hw_base);
@@ -9163,9 +9233,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	return err;
 }
 
-static void iwl_pci_remove(struct pci_dev *pdev)
+static void iwl4965_pci_remove(struct pci_dev *pdev)
 {
-	struct iwl_priv *priv = pci_get_drvdata(pdev);
+	struct iwl4965_priv *priv = pci_get_drvdata(pdev);
 	struct list_head *p, *q;
 	int i;
 
@@ -9176,43 +9246,41 @@ static void iwl_pci_remove(struct pci_dev *pdev)
 
 	set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-	iwl_down(priv);
+	iwl4965_down(priv);
 
 	/* Free MAC hash list for ADHOC */
 	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
 		list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
 			list_del(p);
-			kfree(list_entry(p, struct iwl_ibss_seq, list));
+			kfree(list_entry(p, struct iwl4965_ibss_seq, list));
 		}
 	}
 
-	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+	sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
 
-	iwl_dealloc_ucode_pci(priv);
+	iwl4965_dealloc_ucode_pci(priv);
 
 	if (priv->rxq.bd)
-		iwl_rx_queue_free(priv, &priv->rxq);
-	iwl_hw_txq_ctx_free(priv);
+		iwl4965_rx_queue_free(priv, &priv->rxq);
+	iwl4965_hw_txq_ctx_free(priv);
 
-	iwl_unset_hw_setting(priv);
-	iwl_clear_stations_table(priv);
+	iwl4965_unset_hw_setting(priv);
+	iwl4965_clear_stations_table(priv);
 
 	if (priv->mac80211_registered) {
 		ieee80211_unregister_hw(priv->hw);
-		iwl_rate_control_unregister(priv->hw);
+		iwl4965_rate_control_unregister(priv->hw);
 	}
 
 	/*netif_stop_queue(dev); */
 	flush_workqueue(priv->workqueue);
 
-	/* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
+	/* ieee80211_unregister_hw calls iwl4965_mac_stop, which flushes
 	 * priv->workqueue... so we can't take down the workqueue
 	 * until now... */
 	destroy_workqueue(priv->workqueue);
 	priv->workqueue = NULL;
 
-	free_irq(pdev->irq, priv);
-	pci_disable_msi(pdev);
 	pci_iounmap(pdev, priv->hw_base);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
@@ -9231,93 +9299,31 @@ static void iwl_pci_remove(struct pci_dev *pdev)
 
 #ifdef CONFIG_PM
 
-static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-	struct iwl_priv *priv = pci_get_drvdata(pdev);
+	struct iwl4965_priv *priv = pci_get_drvdata(pdev);
 
-	set_bit(STATUS_IN_SUSPEND, &priv->status);
-
-	/* Take down the device; powers it off, etc. */
-	iwl_down(priv);
-
-	if (priv->mac80211_registered)
-		ieee80211_stop_queues(priv->hw);
+	if (priv->is_open) {
+		set_bit(STATUS_IN_SUSPEND, &priv->status);
+		iwl4965_mac_stop(priv->hw);
+		priv->is_open = 1;
+	}
 
-	pci_save_state(pdev);
-	pci_disable_device(pdev);
 	pci_set_power_state(pdev, PCI_D3hot);
 
 	return 0;
 }
 
-static void iwl_resume(struct iwl_priv *priv)
+static int iwl4965_pci_resume(struct pci_dev *pdev)
 {
-	unsigned long flags;
-
-	/* The following it a temporary work around due to the
-	 * suspend / resume not fully initializing the NIC correctly.
-	 * Without all of the following, resume will not attempt to take
-	 * down the NIC (it shouldn't really need to) and will just try
-	 * and bring the NIC back up.  However that fails during the
-	 * ucode verification process.  This then causes iwl_down to be
-	 * called *after* iwl_hw_nic_init() has succeeded -- which
-	 * then lets the next init sequence succeed.  So, we've
-	 * replicated all of that NIC init code here... */
-
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-
-	iwl_hw_nic_init(priv);
-
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
-		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-	/* tell the device to stop sending interrupts */
-	iwl_disable_interrupts(priv);
-
-	spin_lock_irqsave(&priv->lock, flags);
-	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-	if (!iwl_grab_restricted_access(priv)) {
-		iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
-					 APMG_CLK_VAL_DMA_CLK_RQT);
-		iwl_release_restricted_access(priv);
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-
-	udelay(5);
-
-	iwl_hw_nic_reset(priv);
-
-	/* Bring the device back up */
-	clear_bit(STATUS_IN_SUSPEND, &priv->status);
-	queue_work(priv->workqueue, &priv->up);
-}
-
-static int iwl_pci_resume(struct pci_dev *pdev)
-{
-	struct iwl_priv *priv = pci_get_drvdata(pdev);
-	int err;
-
-	printk(KERN_INFO "Coming out of suspend...\n");
+	struct iwl4965_priv *priv = pci_get_drvdata(pdev);
 
 	pci_set_power_state(pdev, PCI_D0);
-	err = pci_enable_device(pdev);
-	pci_restore_state(pdev);
-
-	/*
-	 * Suspend/Resume resets the PCI configuration space, so we have to
-	 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
-	 * from interfering with C3 CPU state. pci_restore_state won't help
-	 * here since it only restores the first 64 bytes pci config header.
-	 */
-	pci_write_config_byte(pdev, 0x41, 0x00);
 
-	iwl_resume(priv);
+	if (priv->is_open)
+		iwl4965_mac_start(priv->hw);
 
+	clear_bit(STATUS_IN_SUSPEND, &priv->status);
 	return 0;
 }
 
@@ -9329,33 +9335,33 @@ static int iwl_pci_resume(struct pci_dev *pdev)
  *
  *****************************************************************************/
 
-static struct pci_driver iwl_driver = {
+static struct pci_driver iwl4965_driver = {
 	.name = DRV_NAME,
-	.id_table = iwl_hw_card_ids,
-	.probe = iwl_pci_probe,
-	.remove = __devexit_p(iwl_pci_remove),
+	.id_table = iwl4965_hw_card_ids,
+	.probe = iwl4965_pci_probe,
+	.remove = __devexit_p(iwl4965_pci_remove),
 #ifdef CONFIG_PM
-	.suspend = iwl_pci_suspend,
-	.resume = iwl_pci_resume,
+	.suspend = iwl4965_pci_suspend,
+	.resume = iwl4965_pci_resume,
 #endif
 };
 
-static int __init iwl_init(void)
+static int __init iwl4965_init(void)
 {
 
 	int ret;
 	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
 	printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
-	ret = pci_register_driver(&iwl_driver);
+	ret = pci_register_driver(&iwl4965_driver);
 	if (ret) {
 		IWL_ERROR("Unable to initialize PCI module\n");
 		return ret;
 	}
-#ifdef CONFIG_IWLWIFI_DEBUG
-	ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
+#ifdef CONFIG_IWL4965_DEBUG
+	ret = driver_create_file(&iwl4965_driver.driver, &driver_attr_debug_level);
 	if (ret) {
 		IWL_ERROR("Unable to create driver sysfs file\n");
-		pci_unregister_driver(&iwl_driver);
+		pci_unregister_driver(&iwl4965_driver);
 		return ret;
 	}
 #endif
@@ -9363,32 +9369,34 @@ static int __init iwl_init(void)
 	return ret;
 }
 
-static void __exit iwl_exit(void)
+static void __exit iwl4965_exit(void)
 {
-#ifdef CONFIG_IWLWIFI_DEBUG
-	driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
+#ifdef CONFIG_IWL4965_DEBUG
+	driver_remove_file(&iwl4965_driver.driver, &driver_attr_debug_level);
 #endif
-	pci_unregister_driver(&iwl_driver);
+	pci_unregister_driver(&iwl4965_driver);
 }
 
-module_param_named(antenna, iwl_param_antenna, int, 0444);
+module_param_named(antenna, iwl4965_param_antenna, int, 0444);
 MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(disable, iwl_param_disable, int, 0444);
+module_param_named(disable, iwl4965_param_disable, int, 0444);
 MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
-module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444);
+module_param_named(hwcrypto, iwl4965_param_hwcrypto, int, 0444);
 MODULE_PARM_DESC(hwcrypto,
 		 "using hardware crypto engine (default 0 [software])\n");
-module_param_named(debug, iwl_param_debug, int, 0444);
+module_param_named(debug, iwl4965_param_debug, int, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
-module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444);
+module_param_named(disable_hw_scan, iwl4965_param_disable_hw_scan, int, 0444);
 MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
 
-module_param_named(queues_num, iwl_param_queues_num, int, 0444);
+module_param_named(queues_num, iwl4965_param_queues_num, int, 0444);
 MODULE_PARM_DESC(queues_num, "number of hw queues.");
 
 /* QoS */
-module_param_named(qos_enable, iwl_param_qos_enable, int, 0444);
+module_param_named(qos_enable, iwl4965_param_qos_enable, int, 0444);
 MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+module_param_named(amsdu_size_8K, iwl4965_param_amsdu_size_8K, int, 0444);
+MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
 
-module_exit(iwl_exit);
-module_init(iwl_init);
+module_exit(iwl4965_exit);
+module_init(iwl4965_init);
diff --git a/drivers/net/wireless/iwlwifi/iwlwifi.h b/drivers/net/wireless/iwlwifi/iwlwifi.h
deleted file mode 100644
index 432ce887807f..000000000000
--- a/drivers/net/wireless/iwlwifi/iwlwifi.h
+++ /dev/null
@@ -1,708 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ipw3945 project, as well
- * as portions of the ieee80211 subsystem header files.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
- *
- * Contact Information:
- * James P. Ketrenos <ipw2100-admin@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#ifndef __iwlwifi_h__
-#define __iwlwifi_h__
-
-#include <linux/pci.h> /* for struct pci_device_id */
-#include <linux/kernel.h>
-#include <net/ieee80211_radiotap.h>
-
-struct iwl_priv;
-
-/* Hardware specific file defines the PCI IDs table for that hardware module */
-extern struct pci_device_id iwl_hw_card_ids[];
-
-#include "iwl-hw.h"
-#if IWL == 3945
-#define DRV_NAME	"iwl3945"
-#include "iwl-3945-hw.h"
-#elif IWL == 4965
-#define DRV_NAME        "iwl4965"
-#include "iwl-4965-hw.h"
-#endif
-
-#include "iwl-prph.h"
-
-/*
- * Driver implementation data structures, constants, inline
- * functions
- *
- * NOTE:  DO NOT PUT HARDWARE/UCODE SPECIFIC DECLRATIONS HERE
- *
- * Hardware specific declrations go into iwl-*hw.h
- *
- */
-
-#include "iwl-debug.h"
-
-/* Default noise level to report when noise measurement is not available.
- *   This may be because we're:
- *   1)  Not associated (4965, no beacon statistics being sent to driver)
- *   2)  Scanning (noise measurement does not apply to associated channel)
- *   3)  Receiving CCK (3945 delivers noise info only for OFDM frames)
- * Use default noise value of -127 ... this is below the range of measurable
- *   Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
- *   Also, -127 works better than 0 when averaging frames with/without
- *   noise info (e.g. averaging might be done in app); measured dBm values are
- *   always negative ... using a negative value as the default keeps all
- *   averages within an s8's (used in some apps) range of negative values. */
-#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
-
-/* Module parameters accessible from iwl-*.c */
-extern int iwl_param_disable_hw_scan;
-extern int iwl_param_debug;
-extern int iwl_param_mode;
-extern int iwl_param_disable;
-extern int iwl_param_antenna;
-extern int iwl_param_hwcrypto;
-extern int iwl_param_qos_enable;
-extern int iwl_param_queues_num;
-
-enum iwl_antenna {
-	IWL_ANTENNA_DIVERSITY,
-	IWL_ANTENNA_MAIN,
-	IWL_ANTENNA_AUX
-};
-
-/*
- * RTS threshold here is total size [2347] minus 4 FCS bytes
- * Per spec:
- *   a value of 0 means RTS on all data/management packets
- *   a value > max MSDU size means no RTS
- * else RTS for data/management frames where MPDU is larger
- *   than RTS value.
- */
-#define DEFAULT_RTS_THRESHOLD     2347U
-#define MIN_RTS_THRESHOLD         0U
-#define MAX_RTS_THRESHOLD         2347U
-#define MAX_MSDU_SIZE		  2304U
-#define MAX_MPDU_SIZE		  2346U
-#define DEFAULT_BEACON_INTERVAL   100U
-#define	DEFAULT_SHORT_RETRY_LIMIT 7U
-#define	DEFAULT_LONG_RETRY_LIMIT  4U
-
-struct iwl_rx_mem_buffer {
-	dma_addr_t dma_addr;
-	struct sk_buff *skb;
-	struct list_head list;
-};
-
-struct iwl_rt_rx_hdr {
-	struct ieee80211_radiotap_header rt_hdr;
-	__le64 rt_tsf;		/* TSF */
-	u8 rt_flags;		/* radiotap packet flags */
-	u8 rt_rate;		/* rate in 500kb/s */
-	__le16 rt_channelMHz;	/* channel in MHz */
-	__le16 rt_chbitmask;	/* channel bitfield */
-	s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
-	s8 rt_dbmnoise;
-	u8 rt_antenna;		/* antenna number */
-	u8 payload[0];		/* payload... */
-} __attribute__ ((packed));
-
-struct iwl_rt_tx_hdr {
-	struct ieee80211_radiotap_header rt_hdr;
-	u8 rt_rate;		/* rate in 500kb/s */
-	__le16 rt_channel;	/* channel in mHz */
-	__le16 rt_chbitmask;	/* channel bitfield */
-	s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
-	u8 rt_antenna;		/* antenna number */
-	u8 payload[0];		/* payload... */
-} __attribute__ ((packed));
-
-/*
- * Generic queue structure
- *
- * Contains common data for Rx and Tx queues
- */
-struct iwl_queue {
-	int n_bd;              /* number of BDs in this queue */
-	int first_empty;       /* 1-st empty entry (index) host_w*/
-	int last_used;         /* last used entry (index) host_r*/
-	dma_addr_t dma_addr;   /* physical addr for BD's */
-	int n_window;	       /* safe queue window */
-	u32 id;
-	int low_mark;	       /* low watermark, resume queue if free
-				* space more than this */
-	int high_mark;         /* high watermark, stop queue if free
-				* space less than this */
-} __attribute__ ((packed));
-
-#define MAX_NUM_OF_TBS          (20)
-
-struct iwl_tx_info {
-	struct ieee80211_tx_status status;
-	struct sk_buff *skb[MAX_NUM_OF_TBS];
-};
-
-/**
- * struct iwl_tx_queue - Tx Queue for DMA
- * @need_update: need to update read/write index
- * @shed_retry: queue is HT AGG enabled
- *
- * Queue consists of circular buffer of BD's and required locking structures.
- */
-struct iwl_tx_queue {
-	struct iwl_queue q;
-	struct iwl_tfd_frame *bd;
-	struct iwl_cmd *cmd;
-	dma_addr_t dma_addr_cmd;
-	struct iwl_tx_info *txb;
-	int need_update;
-	int sched_retry;
-	int active;
-};
-
-#include "iwl-channel.h"
-
-#if IWL == 3945
-#include "iwl-3945-rs.h"
-#else
-#include "iwl-4965-rs.h"
-#endif
-
-#define IWL_TX_FIFO_AC0	0
-#define IWL_TX_FIFO_AC1	1
-#define IWL_TX_FIFO_AC2	2
-#define IWL_TX_FIFO_AC3	3
-#define IWL_TX_FIFO_HCCA_1	5
-#define IWL_TX_FIFO_HCCA_2	6
-#define IWL_TX_FIFO_NONE	7
-
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL_MIN_NUM_QUEUES	4
-
-/* Power management (not Tx power) structures */
-
-struct iwl_power_vec_entry {
-	struct iwl_powertable_cmd cmd;
-	u8 no_dtim;
-};
-#define IWL_POWER_RANGE_0  (0)
-#define IWL_POWER_RANGE_1  (1)
-
-#define IWL_POWER_MODE_CAM	0x00	/* Continuously Aware Mode, always on */
-#define IWL_POWER_INDEX_3	0x03
-#define IWL_POWER_INDEX_5	0x05
-#define IWL_POWER_AC		0x06
-#define IWL_POWER_BATTERY	0x07
-#define IWL_POWER_LIMIT		0x07
-#define IWL_POWER_MASK		0x0F
-#define IWL_POWER_ENABLED	0x10
-#define IWL_POWER_LEVEL(x)	((x) & IWL_POWER_MASK)
-
-struct iwl_power_mgr {
-	spinlock_t lock;
-	struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC];
-	struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC];
-	u8 active_index;
-	u32 dtim_val;
-};
-
-#define IEEE80211_DATA_LEN              2304
-#define IEEE80211_4ADDR_LEN             30
-#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
-#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
-
-struct iwl_frame {
-	union {
-		struct ieee80211_hdr frame;
-		struct iwl_tx_beacon_cmd beacon;
-		u8 raw[IEEE80211_FRAME_LEN];
-		u8 cmd[360];
-	} u;
-	struct list_head list;
-};
-
-#define SEQ_TO_QUEUE(x)  ((x >> 8) & 0xbf)
-#define QUEUE_TO_SEQ(x)  ((x & 0xbf) << 8)
-#define SEQ_TO_INDEX(x) (x & 0xff)
-#define INDEX_TO_SEQ(x) (x & 0xff)
-#define SEQ_HUGE_FRAME  (0x4000)
-#define SEQ_RX_FRAME    __constant_cpu_to_le16(0x8000)
-#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
-
-enum {
-	/* CMD_SIZE_NORMAL = 0, */
-	CMD_SIZE_HUGE = (1 << 0),
-	/* CMD_SYNC = 0, */
-	CMD_ASYNC = (1 << 1),
-	/* CMD_NO_SKB = 0, */
-	CMD_WANT_SKB = (1 << 2),
-};
-
-struct iwl_cmd;
-struct iwl_priv;
-
-struct iwl_cmd_meta {
-	struct iwl_cmd_meta *source;
-	union {
-		struct sk_buff *skb;
-		int (*callback)(struct iwl_priv *priv,
-				struct iwl_cmd *cmd, struct sk_buff *skb);
-	} __attribute__ ((packed)) u;
-
-	/* The CMD_SIZE_HUGE flag bit indicates that the command
-	 * structure is stored at the end of the shared queue memory. */
-	u32 flags;
-
-} __attribute__ ((packed));
-
-struct iwl_cmd {
-	struct iwl_cmd_meta meta;
-	struct iwl_cmd_header hdr;
-	union {
-		struct iwl_addsta_cmd addsta;
-		struct iwl_led_cmd led;
-		u32 flags;
-		u8 val8;
-		u16 val16;
-		u32 val32;
-		struct iwl_bt_cmd bt;
-		struct iwl_rxon_time_cmd rxon_time;
-		struct iwl_powertable_cmd powertable;
-		struct iwl_qosparam_cmd qosparam;
-		struct iwl_tx_cmd tx;
-		struct iwl_tx_beacon_cmd tx_beacon;
-		struct iwl_rxon_assoc_cmd rxon_assoc;
-		u8 *indirect;
-		u8 payload[360];
-	} __attribute__ ((packed)) cmd;
-} __attribute__ ((packed));
-
-struct iwl_host_cmd {
-	u8 id;
-	u16 len;
-	struct iwl_cmd_meta meta;
-	const void *data;
-};
-
-#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
-			      sizeof(struct iwl_cmd_meta))
-
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 64
-#define RX_LOW_WATERMARK 8
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
-
-/**
- * struct iwl_rx_queue - Rx queue
- * @processed: Internal index to last handled Rx packet
- * @read: Shared index to newest available Rx buffer
- * @write: Shared index to oldest written Rx packet
- * @free_count: Number of pre-allocated buffers in rx_free
- * @rx_free: list of free SKBs for use
- * @rx_used: List of Rx buffers with no SKB
- * @need_update: flag to indicate we need to update read/write index
- *
- * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
- */
-struct iwl_rx_queue {
-	__le32 *bd;
-	dma_addr_t dma_addr;
-	struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
-	struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
-	u32 processed;
-	u32 read;
-	u32 write;
-	u32 free_count;
-	struct list_head rx_free;
-	struct list_head rx_used;
-	int need_update;
-	spinlock_t lock;
-};
-
-#define IWL_SUPPORTED_RATES_IE_LEN         8
-
-#define SCAN_INTERVAL 100
-
-#define MAX_A_CHANNELS  252
-#define MIN_A_CHANNELS  7
-
-#define MAX_B_CHANNELS  14
-#define MIN_B_CHANNELS  1
-
-#define STATUS_HCMD_ACTIVE	0	/* host command in progress */
-#define STATUS_INT_ENABLED	1
-#define STATUS_RF_KILL_HW	2
-#define STATUS_RF_KILL_SW	3
-#define STATUS_INIT		4
-#define STATUS_ALIVE		5
-#define STATUS_READY		6
-#define STATUS_TEMPERATURE	7
-#define STATUS_GEO_CONFIGURED	8
-#define STATUS_EXIT_PENDING	9
-#define STATUS_IN_SUSPEND	10
-#define STATUS_STATISTICS	11
-#define STATUS_SCANNING		12
-#define STATUS_SCAN_ABORTING	13
-#define STATUS_SCAN_HW		14
-#define STATUS_POWER_PMI	15
-#define STATUS_FW_ERROR		16
-
-#define MAX_TID_COUNT        9
-
-#define IWL_INVALID_RATE     0xFF
-#define IWL_INVALID_VALUE    -1
-
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
-struct iwl_ht_agg {
-	u16 txq_id;
-	u16 frame_count;
-	u16 wait_for_ba;
-	u16 start_idx;
-	u32 bitmap0;
-	u32 bitmap1;
-	u32 rate_n_flags;
-};
-#endif /* CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
-#endif
-
-struct iwl_tid_data {
-	u16 seq_number;
-#if IWL == 4965
-#ifdef CONFIG_IWLWIFI_HT
-#ifdef CONFIG_IWLWIFI_HT_AGG
-	struct iwl_ht_agg agg;
-#endif	/* CONFIG_IWLWIFI_HT_AGG */
-#endif /* CONFIG_IWLWIFI_HT */
-#endif
-};
-
-struct iwl_hw_key {
-	enum ieee80211_key_alg alg;
-	int keylen;
-	u8 key[32];
-};
-
-union iwl_ht_rate_supp {
-	u16 rates;
-	struct {
-		u8 siso_rate;
-		u8 mimo_rate;
-	};
-};
-
-#ifdef CONFIG_IWLWIFI_HT
-#define CFG_HT_RX_AMPDU_FACTOR_DEF  (0x3)
-#define HT_IE_MAX_AMSDU_SIZE_4K     (0)
-#define CFG_HT_MPDU_DENSITY_2USEC   (0x5)
-#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
-
-struct sta_ht_info {
-	u8 is_ht;
-	u16 rx_mimo_ps_mode;
-	u16 tx_mimo_ps_mode;
-	u16 control_channel;
-	u8 max_amsdu_size;
-	u8 ampdu_factor;
-	u8 mpdu_density;
-	u8 operating_mode;
-	u8 supported_chan_width;
-	u8 extension_chan_offset;
-	u8 is_green_field;
-	u8 sgf;
-	u8 supp_rates[16];
-	u8 tx_chan_width;
-	u8 chan_width_cap;
-};
-#endif				/*CONFIG_IWLWIFI_HT */
-
-#ifdef CONFIG_IWLWIFI_QOS
-
-union iwl_qos_capabity {
-	struct {
-		u8 edca_count:4;	/* bit 0-3 */
-		u8 q_ack:1;		/* bit 4 */
-		u8 queue_request:1;	/* bit 5 */
-		u8 txop_request:1;	/* bit 6 */
-		u8 reserved:1;		/* bit 7 */
-	} q_AP;
-	struct {
-		u8 acvo_APSD:1;		/* bit 0 */
-		u8 acvi_APSD:1;		/* bit 1 */
-		u8 ac_bk_APSD:1;	/* bit 2 */
-		u8 ac_be_APSD:1;	/* bit 3 */
-		u8 q_ack:1;		/* bit 4 */
-		u8 max_len:2;		/* bit 5-6 */
-		u8 more_data_ack:1;	/* bit 7 */
-	} q_STA;
-	u8 val;
-};
-
-/* QoS sturctures */
-struct iwl_qos_info {
-	int qos_enable;
-	int qos_active;
-	union iwl_qos_capabity qos_cap;
-	struct iwl_qosparam_cmd def_qos_parm;
-};
-#endif /*CONFIG_IWLWIFI_QOS */
-
-#define STA_PS_STATUS_WAKE             0
-#define STA_PS_STATUS_SLEEP            1
-
-struct iwl_station_entry {
-	struct iwl_addsta_cmd sta;
-	struct iwl_tid_data tid[MAX_TID_COUNT];
-#if IWL == 3945
-	union {
-		struct {
-			u8 rate;
-			u8 flags;
-		} s;
-		u16 rate_n_flags;
-	} current_rate;
-#endif
-	u8 used;
-	u8 ps_status;
-	struct iwl_hw_key keyinfo;
-};
-
-/* one for each uCode image (inst/data, boot/init/runtime) */
-struct fw_image_desc {
-	void *v_addr;		/* access by driver */
-	dma_addr_t p_addr;	/* access by card's busmaster DMA */
-	u32 len;		/* bytes */
-};
-
-/* uCode file layout */
-struct iwl_ucode {
-	__le32 ver;		/* major/minor/subminor */
-	__le32 inst_size;	/* bytes of runtime instructions */
-	__le32 data_size;	/* bytes of runtime data */
-	__le32 init_size;	/* bytes of initialization instructions */
-	__le32 init_data_size;	/* bytes of initialization data */
-	__le32 boot_size;	/* bytes of bootstrap instructions */
-	u8 data[0];		/* data in same order as "size" elements */
-};
-
-#define IWL_IBSS_MAC_HASH_SIZE 32
-
-struct iwl_ibss_seq {
-	u8 mac[ETH_ALEN];
-	u16 seq_num;
-	u16 frag_num;
-	unsigned long packet_time;
-	struct list_head list;
-};
-
-struct iwl_driver_hw_info {
-	u16 max_txq_num;
-	u16 ac_queue_count;
-	u32 rx_buffer_size;
-	u16 tx_cmd_len;
-	u16 max_rxq_size;
-	u16 max_rxq_log;
-	u32 cck_flag;
-	u8  max_stations;
-	u8  bcast_sta_id;
-	void *shared_virt;
-	dma_addr_t shared_phys;
-};
-
-
-#define STA_FLG_RTS_MIMO_PROT_MSK	__constant_cpu_to_le32(1 << 17)
-#define STA_FLG_AGG_MPDU_8US_MSK	__constant_cpu_to_le32(1 << 18)
-#define STA_FLG_MAX_AGG_SIZE_POS	(19)
-#define STA_FLG_MAX_AGG_SIZE_MSK	__constant_cpu_to_le32(3 << 19)
-#define STA_FLG_FAT_EN_MSK		__constant_cpu_to_le32(1 << 21)
-#define STA_FLG_MIMO_DIS_MSK		__constant_cpu_to_le32(1 << 22)
-#define STA_FLG_AGG_MPDU_DENSITY_POS	(23)
-#define STA_FLG_AGG_MPDU_DENSITY_MSK	__constant_cpu_to_le32(7 << 23)
-#define HT_SHORT_GI_20MHZ_ONLY          (1 << 0)
-#define HT_SHORT_GI_40MHZ_ONLY          (1 << 1)
-
-
-#include "iwl-priv.h"
-
-/* Requires full declaration of iwl_priv before including */
-#include "iwl-io.h"
-
-#define IWL_RX_HDR(x) ((struct iwl_rx_frame_hdr *)(\
-		       x->u.rx_frame.stats.payload + \
-		       x->u.rx_frame.stats.phy_count))
-#define IWL_RX_END(x) ((struct iwl_rx_frame_end *)(\
-		       IWL_RX_HDR(x)->payload + \
-		       le16_to_cpu(IWL_RX_HDR(x)->len)))
-#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
-#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
-
-
-/******************************************************************************
- *
- * Functions implemented in iwl-base.c which are forward declared here
- * for use by iwl-*.c
- *
- *****************************************************************************/
-struct iwl_addsta_cmd;
-extern int iwl_send_add_station(struct iwl_priv *priv,
-				struct iwl_addsta_cmd *sta, u8 flags);
-extern const char *iwl_get_tx_fail_reason(u32 status);
-extern u8 iwl_add_station(struct iwl_priv *priv, const u8 *bssid,
-			  int is_ap, u8 flags);
-extern int iwl_is_network_packet(struct iwl_priv *priv,
-				 struct ieee80211_hdr *header);
-extern int iwl_power_init_handle(struct iwl_priv *priv);
-extern int iwl_eeprom_init(struct iwl_priv *priv);
-#ifdef CONFIG_IWLWIFI_DEBUG
-extern void iwl_report_frame(struct iwl_priv *priv,
-			     struct iwl_rx_packet *pkt,
-			     struct ieee80211_hdr *header, int group100);
-#else
-static inline void iwl_report_frame(struct iwl_priv *priv,
-				    struct iwl_rx_packet *pkt,
-				    struct ieee80211_hdr *header,
-				    int group100) {}
-#endif
-extern int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
-					 struct iwl_tx_queue *txq);
-extern void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
-					   struct iwl_rx_mem_buffer *rxb,
-					   void *data, short len,
-					   struct ieee80211_rx_status *stats,
-					   u16 phy_flags);
-extern int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr
-			       *header);
-extern void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-extern int iwl_rx_queue_alloc(struct iwl_priv *priv);
-extern void iwl_rx_queue_reset(struct iwl_priv *priv,
-			       struct iwl_rx_queue *rxq);
-extern int iwl_calc_db_from_ratio(int sig_ratio);
-extern int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm);
-extern int iwl_tx_queue_init(struct iwl_priv *priv,
-			     struct iwl_tx_queue *txq, int count, u32 id);
-extern int iwl_rx_queue_restock(struct iwl_priv *priv);
-extern void iwl_rx_replenish(void *data);
-extern void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq);
-extern int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len,
-			    const void *data);
-extern int __must_check iwl_send_cmd_async(struct iwl_priv *priv,
-		struct iwl_host_cmd *cmd);
-extern int __must_check iwl_send_cmd_sync(struct iwl_priv *priv,
-		struct iwl_host_cmd *cmd);
-extern int __must_check iwl_send_cmd(struct iwl_priv *priv,
-		struct iwl_host_cmd *cmd);
-extern unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
-					struct ieee80211_hdr *hdr,
-					const u8 *dest, int left);
-extern int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
-					 struct iwl_rx_queue *q);
-extern int iwl_send_statistics_request(struct iwl_priv *priv);
-extern void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
-				   u32 decrypt_res,
-				   struct ieee80211_rx_status *stats);
-extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
-
-extern const u8 BROADCAST_ADDR[ETH_ALEN];
-
-/*
- * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
- * call this... todo... fix that.
-*/
-extern u8 iwl_sync_station(struct iwl_priv *priv, int sta_id,
-			   u16 tx_rate, u8 flags);
-
-static inline int iwl_is_associated(struct iwl_priv *priv)
-{
-	return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
-}
-
-/******************************************************************************
- *
- * Functions implemented in iwl-[34]*.c which are forward declared here
- * for use by iwl-base.c
- *
- * NOTE:  The implementation of these functions are hardware specific
- * which is why they are in the hardware specific files (vs. iwl-base.c)
- *
- * Naming convention --
- * iwl_         <-- Its part of iwlwifi (should be changed to iwl_)
- * iwl_hw_      <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
- * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
- * iwl_bg_      <-- Called from work queue context
- * iwl_mac_     <-- mac80211 callback
- *
- ****************************************************************************/
-extern void iwl_hw_rx_handler_setup(struct iwl_priv *priv);
-extern void iwl_hw_setup_deferred_work(struct iwl_priv *priv);
-extern void iwl_hw_cancel_deferred_work(struct iwl_priv *priv);
-extern int iwl_hw_rxq_stop(struct iwl_priv *priv);
-extern int iwl_hw_set_hw_setting(struct iwl_priv *priv);
-extern int iwl_hw_nic_init(struct iwl_priv *priv);
-extern void iwl_hw_card_show_info(struct iwl_priv *priv);
-extern int iwl_hw_nic_stop_master(struct iwl_priv *priv);
-extern void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
-extern void iwl_hw_txq_ctx_stop(struct iwl_priv *priv);
-extern int iwl_hw_nic_reset(struct iwl_priv *priv);
-extern int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
-					dma_addr_t addr, u16 len);
-extern int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
-extern int iwl_hw_get_temperature(struct iwl_priv *priv);
-extern int iwl_hw_tx_queue_init(struct iwl_priv *priv,
-				struct iwl_tx_queue *txq);
-extern unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
-				 struct iwl_frame *frame, u8 rate);
-extern int iwl_hw_get_rx_read(struct iwl_priv *priv);
-extern void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
-				     struct iwl_cmd *cmd,
-				     struct ieee80211_tx_control *ctrl,
-				     struct ieee80211_hdr *hdr,
-				     int sta_id, int tx_id);
-extern int iwl_hw_reg_send_txpower(struct iwl_priv *priv);
-extern int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
-extern void iwl_hw_rx_statistics(struct iwl_priv *priv,
-				 struct iwl_rx_mem_buffer *rxb);
-extern void iwl_disable_events(struct iwl_priv *priv);
-extern int iwl4965_get_temperature(const struct iwl_priv *priv);
-
-/**
- * iwl_hw_find_station - Find station id for a given BSSID
- * @bssid: MAC address of station ID to find
- *
- * NOTE:  This should not be hardware specific but the code has
- * not yet been merged into a single common layer for managing the
- * station tables.
- */
-extern u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
-
-extern int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel);
-extern int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
-#endif
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
index 9cf0211de67f..5e10ce0d351c 100644
--- a/drivers/net/wireless/libertas/11d.c
+++ b/drivers/net/wireless/libertas/11d.c
@@ -43,16 +43,14 @@ static struct chan_freq_power channel_freq_power_UN_BG[] = {
 	{14, 2484, TX_PWR_DEFAULT}
 };
 
-static u8 wlan_region_2_code(u8 * region)
+static u8 lbs_region_2_code(u8 *region)
 {
 	u8 i;
-	u8 size = sizeof(region_code_mapping)/
-		  sizeof(struct region_code_mapping);
 
 	for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
 		region[i] = toupper(region[i]);
 
-	for (i = 0; i < size; i++) {
+	for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
 		if (!memcmp(region, region_code_mapping[i].region,
 			    COUNTRY_CODE_LEN))
 			return (region_code_mapping[i].code);
@@ -62,12 +60,11 @@ static u8 wlan_region_2_code(u8 * region)
 	return (region_code_mapping[0].code);
 }
 
-static u8 *wlan_code_2_region(u8 code)
+static u8 *lbs_code_2_region(u8 code)
 {
 	u8 i;
-	u8 size = sizeof(region_code_mapping)
-		  / sizeof(struct region_code_mapping);
-	for (i = 0; i < size; i++) {
+
+	for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) {
 		if (region_code_mapping[i].code == code)
 			return (region_code_mapping[i].region);
 	}
@@ -82,7 +79,7 @@ static u8 *wlan_code_2_region(u8 code)
  *  @param nrchan   number of channels
  *  @return 	      the nrchan-th chan number
 */
-static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
+static u8 lbs_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 *chan)
 /*find the nrchan-th chan after the firstchan*/
 {
 	u8 i;
@@ -90,8 +87,7 @@ static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
 	u8 cfp_no;
 
 	cfp = channel_freq_power_UN_BG;
-	cfp_no = sizeof(channel_freq_power_UN_BG) /
-	    sizeof(struct chan_freq_power);
+	cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG);
 
 	for (i = 0; i < cfp_no; i++) {
 		if ((cfp + i)->channel == firstchan) {
@@ -117,7 +113,7 @@ static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
  *  @param parsed_region_chan   pointer to parsed_region_chan_11d
  *  @return 	                TRUE; FALSE
 */
-static u8 wlan_channel_known_11d(u8 chan,
+static u8 lbs_channel_known_11d(u8 chan,
 			  struct parsed_region_chan_11d * parsed_region_chan)
 {
 	struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
@@ -138,19 +134,15 @@ static u8 wlan_channel_known_11d(u8 chan,
 	return 0;
 }
 
-u32 libertas_chan_2_freq(u8 chan, u8 band)
+u32 lbs_chan_2_freq(u8 chan, u8 band)
 {
 	struct chan_freq_power *cf;
-	u16 cnt;
 	u16 i;
 	u32 freq = 0;
 
 	cf = channel_freq_power_UN_BG;
-	cnt =
-	    sizeof(channel_freq_power_UN_BG) /
-	    sizeof(struct chan_freq_power);
 
-	for (i = 0; i < cnt; i++) {
+	for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) {
 		if (chan == cf[i].channel)
 			freq = cf[i].freq;
 	}
@@ -160,7 +152,7 @@ u32 libertas_chan_2_freq(u8 chan, u8 band)
 
 static int generate_domain_info_11d(struct parsed_region_chan_11d
 				  *parsed_region_chan,
-				  struct wlan_802_11d_domain_reg * domaininfo)
+				  struct lbs_802_11d_domain_reg *domaininfo)
 {
 	u8 nr_subband = 0;
 
@@ -225,7 +217,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d
  *  @param *parsed_region_chan  pointer to parsed_region_chan_11d
  *  @return 	                N/A
 */
-static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan,
+static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan,
 					  struct parsed_region_chan_11d *
 					  parsed_region_chan)
 {
@@ -246,7 +238,7 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_
 	parsed_region_chan->band = region_chan->band;
 	parsed_region_chan->region = region_chan->region;
 	memcpy(parsed_region_chan->countrycode,
-	       wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
+	       lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
 
 	lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
 	       parsed_region_chan->band);
@@ -272,7 +264,7 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_
  *  @param chan                 chan
  *  @return 	                TRUE;FALSE
 */
-static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
+static u8 lbs_region_chan_supported_11d(u8 region, u8 band, u8 chan)
 {
 	struct chan_freq_power *cfp;
 	int cfp_no;
@@ -281,7 +273,7 @@ static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
 
 	lbs_deb_enter(LBS_DEB_11D);
 
-	cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
+	cfp = lbs_get_region_cfp_table(region, band, &cfp_no);
 	if (cfp == NULL)
 		return 0;
 
@@ -346,7 +338,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
 
 	/*Step1: check region_code */
 	parsed_region_chan->region = region =
-	    wlan_region_2_code(countryinfo->countrycode);
+	    lbs_region_2_code(countryinfo->countrycode);
 
 	lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
 	lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
@@ -375,7 +367,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
 		for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
 			/*step4: channel is supported? */
 
-			if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
+			if (!lbs_get_chan_11d(band, firstchan, i, &curchan)) {
 				/* Chan is not found in UN table */
 				lbs_deb_11d("chan is not supported: %d \n", i);
 				break;
@@ -383,7 +375,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
 
 			lastchan = curchan;
 
-			if (wlan_region_chan_supported_11d
+			if (lbs_region_chan_supported_11d
 			    (region, band, curchan)) {
 				/*step5: Check if curchan is supported by mrvl in region */
 				parsed_region_chan->chanpwr[idx].chan = curchan;
@@ -419,14 +411,14 @@ done:
  *  @param parsed_region_chan   pointer to parsed_region_chan_11d
  *  @return 	                PASSIVE if chan is unknown; ACTIVE if chan is known
 */
-u8 libertas_get_scan_type_11d(u8 chan,
+u8 lbs_get_scan_type_11d(u8 chan,
 			  struct parsed_region_chan_11d * parsed_region_chan)
 {
 	u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
 
 	lbs_deb_enter(LBS_DEB_11D);
 
-	if (wlan_channel_known_11d(chan, parsed_region_chan)) {
+	if (lbs_channel_known_11d(chan, parsed_region_chan)) {
 		lbs_deb_11d("found, do active scan\n");
 		scan_type = CMD_SCAN_TYPE_ACTIVE;
 	} else {
@@ -438,29 +430,29 @@ u8 libertas_get_scan_type_11d(u8 chan,
 
 }
 
-void libertas_init_11d(wlan_private * priv)
+void lbs_init_11d(struct lbs_private *priv)
 {
-	priv->adapter->enable11d = 0;
-	memset(&(priv->adapter->parsed_region_chan), 0,
+	priv->enable11d = 0;
+	memset(&(priv->parsed_region_chan), 0,
 	       sizeof(struct parsed_region_chan_11d));
 	return;
 }
 
 /**
  *  @brief This function sets DOMAIN INFO to FW
- *  @param priv       pointer to wlan_private
+ *  @param priv       pointer to struct lbs_private
  *  @return 	      0; -1
 */
-static int set_domain_info_11d(wlan_private * priv)
+static int set_domain_info_11d(struct lbs_private *priv)
 {
 	int ret;
 
-	if (!priv->adapter->enable11d) {
+	if (!priv->enable11d) {
 		lbs_deb_11d("dnld domain Info with 11d disabled\n");
 		return 0;
 	}
 
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
 				    CMD_ACT_SET,
 				    CMD_OPTION_WAITFORRSP, 0, NULL);
 	if (ret)
@@ -471,28 +463,27 @@ static int set_domain_info_11d(wlan_private * priv)
 
 /**
  *  @brief This function setups scan channels
- *  @param priv       pointer to wlan_private
+ *  @param priv       pointer to struct lbs_private
  *  @param band       band
  *  @return 	      0
 */
-int libertas_set_universaltable(wlan_private * priv, u8 band)
+int lbs_set_universaltable(struct lbs_private *priv, u8 band)
 {
-	wlan_adapter *adapter = priv->adapter;
 	u16 size = sizeof(struct chan_freq_power);
 	u16 i = 0;
 
-	memset(adapter->universal_channel, 0,
-	       sizeof(adapter->universal_channel));
+	memset(priv->universal_channel, 0,
+	       sizeof(priv->universal_channel));
 
-	adapter->universal_channel[i].nrcfp =
+	priv->universal_channel[i].nrcfp =
 	    sizeof(channel_freq_power_UN_BG) / size;
 	lbs_deb_11d("BG-band nrcfp %d\n",
-	       adapter->universal_channel[i].nrcfp);
+	       priv->universal_channel[i].nrcfp);
 
-	adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
-	adapter->universal_channel[i].valid = 1;
-	adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
-	adapter->universal_channel[i].band = band;
+	priv->universal_channel[i].CFP = channel_freq_power_UN_BG;
+	priv->universal_channel[i].valid = 1;
+	priv->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+	priv->universal_channel[i].band = band;
 	i++;
 
 	return 0;
@@ -500,21 +491,20 @@ int libertas_set_universaltable(wlan_private * priv, u8 band)
 
 /**
  *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
- *  @param priv       pointer to wlan_private
+ *  @param priv       pointer to struct lbs_private
  *  @param cmd        pointer to cmd buffer
  *  @param cmdno      cmd ID
  *  @param cmdOption  cmd action
  *  @return 	      0
 */
-int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
 				 struct cmd_ds_command *cmd, u16 cmdno,
 				 u16 cmdoption)
 {
 	struct cmd_ds_802_11d_domain_info *pdomaininfo =
 	    &cmd->params.domaininfo;
 	struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
-	wlan_adapter *adapter = priv->adapter;
-	u8 nr_subband = adapter->domainreg.nr_subband;
+	u8 nr_subband = priv->domainreg.nr_subband;
 
 	lbs_deb_enter(LBS_DEB_11D);
 
@@ -526,12 +516,12 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv,
 		cmd->size =
 		    cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
 		lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
-			(int)(cmd->size));
+			le16_to_cpu(cmd->size));
 		goto done;
 	}
 
 	domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
-	memcpy(domain->countrycode, adapter->domainreg.countrycode,
+	memcpy(domain->countrycode, priv->domainreg.countrycode,
 	       sizeof(domain->countrycode));
 
 	domain->header.len =
@@ -539,7 +529,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv,
 			     sizeof(domain->countrycode));
 
 	if (nr_subband) {
-		memcpy(domain->subband, adapter->domainreg.subband,
+		memcpy(domain->subband, priv->domainreg.subband,
 		       nr_subband * sizeof(struct ieeetypes_subbandset));
 
 		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
@@ -560,11 +550,11 @@ done:
 
 /**
  *  @brief This function parses countryinfo from AP and download country info to FW
- *  @param priv    pointer to wlan_private
+ *  @param priv    pointer to struct lbs_private
  *  @param resp    pointer to command response buffer
  *  @return 	   0; -1
  */
-int libertas_ret_802_11d_domain_info(wlan_private * priv,
+int lbs_ret_802_11d_domain_info(struct lbs_private *priv,
 				 struct cmd_ds_command *resp)
 {
 	struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
@@ -606,31 +596,30 @@ int libertas_ret_802_11d_domain_info(wlan_private * priv,
 
 /**
  *  @brief This function parses countryinfo from AP and download country info to FW
- *  @param priv    pointer to wlan_private
+ *  @param priv    pointer to struct lbs_private
  *  @return 	   0; -1
  */
-int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
+int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
                                         struct bss_descriptor * bss)
 {
 	int ret;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_11D);
-	if (priv->adapter->enable11d) {
-		memset(&adapter->parsed_region_chan, 0,
+	if (priv->enable11d) {
+		memset(&priv->parsed_region_chan, 0,
 		       sizeof(struct parsed_region_chan_11d));
 		ret = parse_domain_info_11d(&bss->countryinfo, 0,
-					       &adapter->parsed_region_chan);
+					       &priv->parsed_region_chan);
 
 		if (ret == -1) {
 			lbs_deb_11d("error parsing domain_info from AP\n");
 			goto done;
 		}
 
-		memset(&adapter->domainreg, 0,
-		       sizeof(struct wlan_802_11d_domain_reg));
-		generate_domain_info_11d(&adapter->parsed_region_chan,
-				      &adapter->domainreg);
+		memset(&priv->domainreg, 0,
+		       sizeof(struct lbs_802_11d_domain_reg));
+		generate_domain_info_11d(&priv->parsed_region_chan,
+				      &priv->domainreg);
 
 		ret = set_domain_info_11d(priv);
 
@@ -648,25 +637,23 @@ done:
 
 /**
  *  @brief This function generates 11D info from user specified regioncode and download to FW
- *  @param priv    pointer to wlan_private
+ *  @param priv    pointer to struct lbs_private
  *  @return 	   0; -1
  */
-int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
+int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv)
 {
 	int ret;
-	wlan_adapter *adapter = priv->adapter;
 	struct region_channel *region_chan;
 	u8 j;
 
 	lbs_deb_enter(LBS_DEB_11D);
-	lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band);
+	lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band);
 
-	if (priv->adapter->enable11d) {
+	if (priv->enable11d) {
 		/* update parsed_region_chan_11; dnld domaininf to FW */
 
-		for (j = 0; j < sizeof(adapter->region_channel) /
-		     sizeof(adapter->region_channel[0]); j++) {
-			region_chan = &adapter->region_channel[j];
+		for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) {
+			region_chan = &priv->region_channel[j];
 
 			lbs_deb_11d("%d region_chan->band %d\n", j,
 			       region_chan->band);
@@ -674,29 +661,28 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
 			if (!region_chan || !region_chan->valid
 			    || !region_chan->CFP)
 				continue;
-			if (region_chan->band != adapter->curbssparams.band)
+			if (region_chan->band != priv->curbssparams.band)
 				continue;
 			break;
 		}
 
-		if (j >= sizeof(adapter->region_channel) /
-		    sizeof(adapter->region_channel[0])) {
+		if (j >= ARRAY_SIZE(priv->region_channel)) {
 			lbs_deb_11d("region_chan not found, band %d\n",
-			       adapter->curbssparams.band);
+			       priv->curbssparams.band);
 			ret = -1;
 			goto done;
 		}
 
-		memset(&adapter->parsed_region_chan, 0,
+		memset(&priv->parsed_region_chan, 0,
 		       sizeof(struct parsed_region_chan_11d));
-		wlan_generate_parsed_region_chan_11d(region_chan,
-						     &adapter->
+		lbs_generate_parsed_region_chan_11d(region_chan,
+						     &priv->
 						     parsed_region_chan);
 
-		memset(&adapter->domainreg, 0,
-		       sizeof(struct wlan_802_11d_domain_reg));
-		generate_domain_info_11d(&adapter->parsed_region_chan,
-					 &adapter->domainreg);
+		memset(&priv->domainreg, 0,
+		       sizeof(struct lbs_802_11d_domain_reg));
+		generate_domain_info_11d(&priv->parsed_region_chan,
+					 &priv->domainreg);
 
 		ret = set_domain_info_11d(priv);
 
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
index 3a6d1f8db78f..811eea2cfba3 100644
--- a/drivers/net/wireless/libertas/11d.h
+++ b/drivers/net/wireless/libertas/11d.h
@@ -2,8 +2,8 @@
   * This header file contains data structures and
   * function declarations of 802.11d
   */
-#ifndef _WLAN_11D_
-#define _WLAN_11D_
+#ifndef _LBS_11D_
+#define _LBS_11D_
 
 #include "types.h"
 #include "defs.h"
@@ -52,7 +52,7 @@ struct cmd_ds_802_11d_domain_info {
 } __attribute__ ((packed));
 
 /** domain regulatory information */
-struct wlan_802_11d_domain_reg {
+struct lbs_802_11d_domain_reg {
 	/** country Code*/
 	u8 countrycode[COUNTRY_CODE_LEN];
 	/** No. of subband*/
@@ -78,26 +78,28 @@ struct region_code_mapping {
 	u8 code;
 };
 
-u8 libertas_get_scan_type_11d(u8 chan,
+struct lbs_private;
+
+u8 lbs_get_scan_type_11d(u8 chan,
 			  struct parsed_region_chan_11d *parsed_region_chan);
 
-u32 libertas_chan_2_freq(u8 chan, u8 band);
+u32 lbs_chan_2_freq(u8 chan, u8 band);
 
-void libertas_init_11d(wlan_private * priv);
+void lbs_init_11d(struct lbs_private *priv);
 
-int libertas_set_universaltable(wlan_private * priv, u8 band);
+int lbs_set_universaltable(struct lbs_private *priv, u8 band);
 
-int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
 				 struct cmd_ds_command *cmd, u16 cmdno,
 				 u16 cmdOption);
 
-int libertas_ret_802_11d_domain_info(wlan_private * priv,
+int lbs_ret_802_11d_domain_info(struct lbs_private *priv,
 				 struct cmd_ds_command *resp);
 
 struct bss_descriptor;
-int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
+int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv,
                                         struct bss_descriptor * bss);
 
-int libertas_create_dnld_countryinfo_11d(wlan_private * priv);
+int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv);
 
-#endif				/* _WLAN_11D_ */
+#endif
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
index 0b133ce63805..d860fc375752 100644
--- a/drivers/net/wireless/libertas/README
+++ b/drivers/net/wireless/libertas/README
@@ -195,45 +195,33 @@ setuserscan
 
          where [ARGS]:
 
-      chan=[chan#][band][mode] where band is [a,b,g] and mode is
-                               blank for active or 'p' for passive
       bssid=xx:xx:xx:xx:xx:xx  specify a BSSID filter for the scan
       ssid="[SSID]"            specify a SSID filter for the scan
       keep=[0 or 1]            keep the previous scan results (1), discard (0)
       dur=[scan time]          time to scan for each channel in milliseconds
-      probes=[#]               number of probe requests to send on each chan
       type=[1,2,3]             BSS type: 1 (Infra), 2(Adhoc), 3(Any)
 
-    Any combination of the above arguments can be supplied on the command line.
-      If the chan token is absent, a full channel scan will be completed by
-      the driver.  If the dur or probes tokens are absent, the driver default
-      setting will be used.  The bssid and ssid fields, if blank,
-      will produce an unfiltered scan. The type field will default to 3 (Any)
-      and the keep field will default to 0 (Discard).
+    Any combination of the above arguments can be supplied on the command
+    line. If dur tokens are absent, the driver default setting will be used.
+    The bssid and ssid fields, if blank, will produce an unfiltered scan.
+    The type field will default to 3 (Any) and the keep field will default
+    to 0 (Discard).
 
     Examples:
-    1) Perform an active scan on channels 1, 6, and 11 in the 'g' band:
-            echo "chan=1g,6g,11g" > setuserscan
+    1) Perform a passive scan on all channels for 20 ms per channel:
+            echo "dur=20" > setuserscan
 
-    2) Perform a passive scan on channel 11 for 20 ms:
-            echo "chan=11gp dur=20" > setuserscan
+    2) Perform an active scan for a specific SSID:
+            echo "ssid="TestAP"" > setuserscan
 
-    3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
-       channel 36 in the 'a' band:
-
-            echo "chan=1g,6g,11g,36ap" > setuserscan
-
-    4) Perform an active scan on channel 6 and 36 for a specific SSID:
-            echo "chan=6g,36a ssid="TestAP"" > setuserscan
-
-    5) Scan all available channels (B/G, A bands) for a specific BSSID, keep
+    3) Scan all available channels (B/G, A bands) for a specific BSSID, keep
        the current scan table intact, update existing or append new scan data:
             echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
 
-    6) Scan channel 6, for all infrastructure networks, sending two probe
-       requests.  Keep the previous scan table intact. Update any duplicate
-       BSSID/SSID matches with the new scan data:
-            echo "chan=6g type=1 probes=2 keep=1" > setuserscan
+    4) Scan for all infrastructure networks.
+       Keep the previous scan table intact. Update any duplicate BSSID/SSID
+       matches with the new scan data:
+            echo "type=1 keep=1" > setuserscan
 
     All entries in the scan table (not just the new scan data when keep=1)
     will be displayed upon completion by use of the getscantable ioctl.
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index b61b176e9d07..c622e9b63cd1 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -9,39 +9,16 @@
 #include "decl.h"
 #include "hostcmd.h"
 #include "host.h"
+#include "cmd.h"
 
 
 static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
-static void print_assoc_req(const char * extra, struct assoc_request * assoc_req)
-{
-	DECLARE_MAC_BUF(mac);
-	lbs_deb_assoc(
-	       "#### Association Request: %s\n"
-	       "       flags:      0x%08lX\n"
-	       "       SSID:       '%s'\n"
-	       "       channel:    %d\n"
-	       "       band:       %d\n"
-	       "       mode:       %d\n"
-	       "       BSSID:      %s\n"
-	       "       Encryption:%s%s%s\n"
-	       "       auth:       %d\n",
-	       extra, assoc_req->flags,
-	       escape_essid(assoc_req->ssid, assoc_req->ssid_len),
-	       assoc_req->channel, assoc_req->band, assoc_req->mode,
-	       print_mac(mac, assoc_req->bssid),
-	       assoc_req->secinfo.WPAenabled ? " WPA" : "",
-	       assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
-	       assoc_req->secinfo.wep_enabled ? " WEP" : "",
-	       assoc_req->secinfo.auth_mode);
-}
-
 
-static int assoc_helper_essid(wlan_private *priv,
+static int assoc_helper_essid(struct lbs_private *priv,
                               struct assoc_request * assoc_req)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 	struct bss_descriptor * bss;
 	int channel = -1;
@@ -55,18 +32,17 @@ static int assoc_helper_essid(wlan_private *priv,
 	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
 		channel = assoc_req->channel;
 
-	lbs_deb_assoc("New SSID requested: '%s'\n",
+	lbs_deb_assoc("SSID '%s' requested\n",
 	              escape_essid(assoc_req->ssid, assoc_req->ssid_len));
 	if (assoc_req->mode == IW_MODE_INFRA) {
-		libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
+		lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
 			assoc_req->ssid_len, 0);
 
-		bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid,
+		bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
 				assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
 		if (bss != NULL) {
-			lbs_deb_assoc("SSID found in scan list, associating\n");
 			memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
-			ret = wlan_associate(priv, assoc_req);
+			ret = lbs_associate(priv, assoc_req);
 		} else {
 			lbs_deb_assoc("SSID not found; cannot associate\n");
 		}
@@ -74,23 +50,23 @@ static int assoc_helper_essid(wlan_private *priv,
 		/* Scan for the network, do not save previous results.  Stale
 		 *   scan data will cause us to join a non-existant adhoc network
 		 */
-		libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
+		lbs_send_specific_ssid_scan(priv, assoc_req->ssid,
 			assoc_req->ssid_len, 1);
 
 		/* Search for the requested SSID in the scan table */
-		bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid,
+		bss = lbs_find_ssid_in_list(priv, assoc_req->ssid,
 				assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel);
 		if (bss != NULL) {
 			lbs_deb_assoc("SSID found, will join\n");
 			memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
-			libertas_join_adhoc_network(priv, assoc_req);
+			lbs_join_adhoc_network(priv, assoc_req);
 		} else {
 			/* else send START command */
 			lbs_deb_assoc("SSID not found, creating adhoc network\n");
 			memcpy(&assoc_req->bss.ssid, &assoc_req->ssid,
 				IW_ESSID_MAX_SIZE);
 			assoc_req->bss.ssid_len = assoc_req->ssid_len;
-			libertas_start_adhoc_network(priv, assoc_req);
+			lbs_start_adhoc_network(priv, assoc_req);
 		}
 	}
 
@@ -99,10 +75,9 @@ static int assoc_helper_essid(wlan_private *priv,
 }
 
 
-static int assoc_helper_bssid(wlan_private *priv,
+static int assoc_helper_bssid(struct lbs_private *priv,
                               struct assoc_request * assoc_req)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 	struct bss_descriptor * bss;
 	DECLARE_MAC_BUF(mac);
@@ -111,7 +86,7 @@ static int assoc_helper_bssid(wlan_private *priv,
 		print_mac(mac, assoc_req->bssid));
 
 	/* Search for index position in list for requested MAC */
-	bss = libertas_find_bssid_in_list(adapter, assoc_req->bssid,
+	bss = lbs_find_bssid_in_list(priv, assoc_req->bssid,
 			    assoc_req->mode);
 	if (bss == NULL) {
 		lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
@@ -121,10 +96,10 @@ static int assoc_helper_bssid(wlan_private *priv,
 
 	memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
 	if (assoc_req->mode == IW_MODE_INFRA) {
-		ret = wlan_associate(priv, assoc_req);
-		lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret);
+		ret = lbs_associate(priv, assoc_req);
+		lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret);
 	} else if (assoc_req->mode == IW_MODE_ADHOC) {
-		libertas_join_adhoc_network(priv, assoc_req);
+		lbs_join_adhoc_network(priv, assoc_req);
 	}
 
 out:
@@ -133,11 +108,13 @@ out:
 }
 
 
-static int assoc_helper_associate(wlan_private *priv,
+static int assoc_helper_associate(struct lbs_private *priv,
                                   struct assoc_request * assoc_req)
 {
 	int ret = 0, done = 0;
 
+	lbs_deb_enter(LBS_DEB_ASSOC);
+
 	/* If we're given and 'any' BSSID, try associating based on SSID */
 
 	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
@@ -145,42 +122,36 @@ static int assoc_helper_associate(wlan_private *priv,
 		    && compare_ether_addr(bssid_off, assoc_req->bssid)) {
 			ret = assoc_helper_bssid(priv, assoc_req);
 			done = 1;
-			if (ret) {
-				lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
-			}
 		}
 	}
 
 	if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
 		ret = assoc_helper_essid(priv, assoc_req);
-		if (ret) {
-			lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret);
-		}
 	}
 
+	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return ret;
 }
 
 
-static int assoc_helper_mode(wlan_private *priv,
+static int assoc_helper_mode(struct lbs_private *priv,
                              struct assoc_request * assoc_req)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
-	if (assoc_req->mode == adapter->mode)
+	if (assoc_req->mode == priv->mode)
 		goto done;
 
 	if (assoc_req->mode == IW_MODE_INFRA) {
-		if (adapter->psstate != PS_STATE_FULL_POWER)
-			libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
-		adapter->psmode = WLAN802_11POWERMODECAM;
+		if (priv->psstate != PS_STATE_FULL_POWER)
+			lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
+		priv->psmode = LBS802_11POWERMODECAM;
 	}
 
-	adapter->mode = assoc_req->mode;
-	ret = libertas_prepare_and_send_command(priv,
+	priv->mode = assoc_req->mode;
+	ret = lbs_prepare_and_send_command(priv,
 				    CMD_802_11_SNMP_MIB,
 				    0, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_INFRASTRUCTURE_MODE,
@@ -192,57 +163,76 @@ done:
 }
 
 
-static int update_channel(wlan_private * priv)
+int lbs_update_channel(struct lbs_private *priv)
 {
-	/* the channel in f/w could be out of sync, get the current channel */
-	return libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
-				    CMD_OPT_802_11_RF_CHANNEL_GET,
-				    CMD_OPTION_WAITFORRSP, 0, NULL);
+	int ret;
+
+	/* the channel in f/w could be out of sync; get the current channel */
+	lbs_deb_enter(LBS_DEB_ASSOC);
+
+	ret = lbs_get_channel(priv);
+	if (ret > 0) {
+		priv->curbssparams.channel = ret;
+		ret = 0;
+	}
+	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
+	return ret;
 }
 
-void libertas_sync_channel(struct work_struct *work)
+void lbs_sync_channel(struct work_struct *work)
 {
-	wlan_private *priv = container_of(work, wlan_private, sync_channel);
+	struct lbs_private *priv = container_of(work, struct lbs_private,
+		sync_channel);
 
-	if (update_channel(priv) != 0)
+	lbs_deb_enter(LBS_DEB_ASSOC);
+	if (lbs_update_channel(priv))
 		lbs_pr_info("Channel synchronization failed.");
+	lbs_deb_leave(LBS_DEB_ASSOC);
 }
 
-static int assoc_helper_channel(wlan_private *priv,
+static int assoc_helper_channel(struct lbs_private *priv,
                                 struct assoc_request * assoc_req)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
-	ret = update_channel(priv);
-	if (ret < 0) {
-		lbs_deb_assoc("ASSOC: channel: error getting channel.");
+	ret = lbs_update_channel(priv);
+	if (ret) {
+		lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
+		goto done;
 	}
 
-	if (assoc_req->channel == adapter->curbssparams.channel)
+	if (assoc_req->channel == priv->curbssparams.channel)
 		goto done;
 
+	if (priv->mesh_dev) {
+		/* Change mesh channel first; 21.p21 firmware won't let
+		   you change channel otherwise (even though it'll return
+		   an error to this */
+		lbs_mesh_config(priv, 0, assoc_req->channel);
+	}
+
 	lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
-	       adapter->curbssparams.channel, assoc_req->channel);
+		      priv->curbssparams.channel, assoc_req->channel);
 
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
-				CMD_OPT_802_11_RF_CHANNEL_SET,
-				CMD_OPTION_WAITFORRSP, 0, &assoc_req->channel);
-	if (ret < 0) {
-		lbs_deb_assoc("ASSOC: channel: error setting channel.");
-	}
+	ret = lbs_set_channel(priv, assoc_req->channel);
+	if (ret < 0)
+		lbs_deb_assoc("ASSOC: channel: error setting channel.\n");
 
-	ret = update_channel(priv);
-	if (ret < 0) {
-		lbs_deb_assoc("ASSOC: channel: error getting channel.");
+	/* FIXME: shouldn't need to grab the channel _again_ after setting
+	 * it since the firmware is supposed to return the new channel, but
+	 * whatever... */
+	ret = lbs_update_channel(priv);
+	if (ret) {
+		lbs_deb_assoc("ASSOC: channel: error getting channel.\n");
+		goto done;
 	}
 
-	if (assoc_req->channel != adapter->curbssparams.channel) {
-		lbs_deb_assoc("ASSOC: channel: failed to update channel to %d",
+	if (assoc_req->channel != priv->curbssparams.channel) {
+		lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n",
 		              assoc_req->channel);
-		goto done;
+		goto restore_mesh;
 	}
 
 	if (   assoc_req->secinfo.wep_enabled
@@ -255,83 +245,75 @@ static int assoc_helper_channel(wlan_private *priv,
 	}
 
 	/* Must restart/rejoin adhoc networks after channel change */
-	set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
+ 	set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
 
-done:
+ restore_mesh:
+	if (priv->mesh_dev)
+		lbs_mesh_config(priv, 1, priv->curbssparams.channel);
+
+ done:
 	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return ret;
 }
 
 
-static int assoc_helper_wep_keys(wlan_private *priv,
-                                 struct assoc_request * assoc_req)
+static int assoc_helper_wep_keys(struct lbs_private *priv,
+				 struct assoc_request *assoc_req)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int i;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
 	/* Set or remove WEP keys */
-	if (   assoc_req->wep_keys[0].len
-	    || assoc_req->wep_keys[1].len
-	    || assoc_req->wep_keys[2].len
-	    || assoc_req->wep_keys[3].len) {
-		ret = libertas_prepare_and_send_command(priv,
-					    CMD_802_11_SET_WEP,
-					    CMD_ACT_ADD,
-					    CMD_OPTION_WAITFORRSP,
-					    0, assoc_req);
-	} else {
-		ret = libertas_prepare_and_send_command(priv,
-					    CMD_802_11_SET_WEP,
-					    CMD_ACT_REMOVE,
-					    CMD_OPTION_WAITFORRSP,
-					    0, NULL);
-	}
+	if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len ||
+	    assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len)
+		ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req);
+	else
+		ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req);
 
 	if (ret)
 		goto out;
 
 	/* enable/disable the MAC's WEP packet filter */
 	if (assoc_req->secinfo.wep_enabled)
-		adapter->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
+		priv->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
 	else
-		adapter->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
-	ret = libertas_set_mac_packet_filter(priv);
+		priv->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
+
+	ret = lbs_set_mac_packet_filter(priv);
 	if (ret)
 		goto out;
 
-	mutex_lock(&adapter->lock);
+	mutex_lock(&priv->lock);
 
-	/* Copy WEP keys into adapter wep key fields */
+	/* Copy WEP keys into priv wep key fields */
 	for (i = 0; i < 4; i++) {
-		memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
-			sizeof(struct enc_key));
+		memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i],
+		       sizeof(struct enc_key));
 	}
-	adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
+	priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
 
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 
 out:
 	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return ret;
 }
 
-static int assoc_helper_secinfo(wlan_private *priv,
+static int assoc_helper_secinfo(struct lbs_private *priv,
                                 struct assoc_request * assoc_req)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
-	u32 do_wpa;
-	u32 rsn = 0;
+	uint16_t do_wpa;
+	uint16_t rsn = 0;
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
-	memcpy(&adapter->secinfo, &assoc_req->secinfo,
-		sizeof(struct wlan_802_11_security));
+	memcpy(&priv->secinfo, &assoc_req->secinfo,
+		sizeof(struct lbs_802_11_security));
 
-	ret = libertas_set_mac_packet_filter(priv);
+	ret = lbs_set_mac_packet_filter(priv);
 	if (ret)
 		goto out;
 
@@ -341,28 +323,19 @@ static int assoc_helper_secinfo(wlan_private *priv,
 	 */
 
 	/* Get RSN enabled/disabled */
-	ret = libertas_prepare_and_send_command(priv,
-				    CMD_802_11_ENABLE_RSN,
-				    CMD_ACT_GET,
-				    CMD_OPTION_WAITFORRSP,
-				    0, &rsn);
+	ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn);
 	if (ret) {
-		lbs_deb_assoc("Failed to get RSN status: %d", ret);
+		lbs_deb_assoc("Failed to get RSN status: %d\n", ret);
 		goto out;
 	}
 
 	/* Don't re-enable RSN if it's already enabled */
-	do_wpa = (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled);
+	do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled;
 	if (do_wpa == rsn)
 		goto out;
 
 	/* Set RSN enabled/disabled */
-	rsn = do_wpa;
-	ret = libertas_prepare_and_send_command(priv,
-				    CMD_802_11_ENABLE_RSN,
-				    CMD_ACT_SET,
-				    CMD_OPTION_WAITFORRSP,
-				    0, &rsn);
+	ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa);
 
 out:
 	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -370,7 +343,7 @@ out:
 }
 
 
-static int assoc_helper_wpa_keys(wlan_private *priv,
+static int assoc_helper_wpa_keys(struct lbs_private *priv,
                                  struct assoc_request * assoc_req)
 {
 	int ret = 0;
@@ -385,7 +358,7 @@ static int assoc_helper_wpa_keys(wlan_private *priv,
 
 	if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
 		clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
-		ret = libertas_prepare_and_send_command(priv,
+		ret = lbs_prepare_and_send_command(priv,
 					CMD_802_11_KEY_MATERIAL,
 					CMD_ACT_SET,
 					CMD_OPTION_WAITFORRSP,
@@ -399,7 +372,7 @@ static int assoc_helper_wpa_keys(wlan_private *priv,
 	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
 		clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
 
-		ret = libertas_prepare_and_send_command(priv,
+		ret = lbs_prepare_and_send_command(priv,
 					CMD_802_11_KEY_MATERIAL,
 					CMD_ACT_SET,
 					CMD_OPTION_WAITFORRSP,
@@ -413,20 +386,19 @@ out:
 }
 
 
-static int assoc_helper_wpa_ie(wlan_private *priv,
+static int assoc_helper_wpa_ie(struct lbs_private *priv,
                                struct assoc_request * assoc_req)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
 	if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
-		memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
-		adapter->wpa_ie_len = assoc_req->wpa_ie_len;
+		memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
+		priv->wpa_ie_len = assoc_req->wpa_ie_len;
 	} else {
-		memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
-		adapter->wpa_ie_len = 0;
+		memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN);
+		priv->wpa_ie_len = 0;
 	}
 
 	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
@@ -434,55 +406,68 @@ static int assoc_helper_wpa_ie(wlan_private *priv,
 }
 
 
-static int should_deauth_infrastructure(wlan_adapter *adapter,
+static int should_deauth_infrastructure(struct lbs_private *priv,
                                         struct assoc_request * assoc_req)
 {
-	if (adapter->connect_status != LIBERTAS_CONNECTED)
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_ASSOC);
+
+	if (priv->connect_status != LBS_CONNECTED)
 		return 0;
 
 	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
-		lbs_deb_assoc("Deauthenticating due to new SSID in "
-			" configuration request.\n");
-		return 1;
+		lbs_deb_assoc("Deauthenticating due to new SSID\n");
+		ret = 1;
+		goto out;
 	}
 
 	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
-		if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
-			lbs_deb_assoc("Deauthenticating due to updated security "
-				"info in configuration request.\n");
-			return 1;
+		if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) {
+			lbs_deb_assoc("Deauthenticating due to new security\n");
+			ret = 1;
+			goto out;
 		}
 	}
 
 	if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-		lbs_deb_assoc("Deauthenticating due to new BSSID in "
-			" configuration request.\n");
-		return 1;
+		lbs_deb_assoc("Deauthenticating due to new BSSID\n");
+		ret = 1;
+		goto out;
 	}
 
 	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
-		lbs_deb_assoc("Deauthenticating due to channel switch.\n");
-		return 1;
+		lbs_deb_assoc("Deauthenticating due to channel switch\n");
+		ret = 1;
+		goto out;
 	}
 
 	/* FIXME: deal with 'auto' mode somehow */
 	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
-		if (assoc_req->mode != IW_MODE_INFRA)
-			return 1;
+		if (assoc_req->mode != IW_MODE_INFRA) {
+			lbs_deb_assoc("Deauthenticating due to leaving "
+				"infra mode\n");
+			ret = 1;
+			goto out;
+		}
 	}
 
+out:
+	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return 0;
 }
 
 
-static int should_stop_adhoc(wlan_adapter *adapter,
+static int should_stop_adhoc(struct lbs_private *priv,
                              struct assoc_request * assoc_req)
 {
-	if (adapter->connect_status != LIBERTAS_CONNECTED)
+	lbs_deb_enter(LBS_DEB_ASSOC);
+
+	if (priv->connect_status != LBS_CONNECTED)
 		return 0;
 
-	if (libertas_ssid_cmp(adapter->curbssparams.ssid,
-	                      adapter->curbssparams.ssid_len,
+	if (lbs_ssid_cmp(priv->curbssparams.ssid,
+	                      priv->curbssparams.ssid_len,
 	                      assoc_req->ssid, assoc_req->ssid_len) != 0)
 		return 1;
 
@@ -493,18 +478,19 @@ static int should_stop_adhoc(wlan_adapter *adapter,
 	}
 
 	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
-		if (assoc_req->channel != adapter->curbssparams.channel)
+		if (assoc_req->channel != priv->curbssparams.channel)
 			return 1;
 	}
 
+	lbs_deb_leave(LBS_DEB_ASSOC);
 	return 0;
 }
 
 
-void libertas_association_worker(struct work_struct *work)
+void lbs_association_worker(struct work_struct *work)
 {
-	wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = container_of(work, struct lbs_private,
+		assoc_work.work);
 	struct assoc_request * assoc_req = NULL;
 	int ret = 0;
 	int find_any_ssid = 0;
@@ -512,16 +498,33 @@ void libertas_association_worker(struct work_struct *work)
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
-	mutex_lock(&adapter->lock);
-	assoc_req = adapter->pending_assoc_req;
-	adapter->pending_assoc_req = NULL;
-	adapter->in_progress_assoc_req = assoc_req;
-	mutex_unlock(&adapter->lock);
+	mutex_lock(&priv->lock);
+	assoc_req = priv->pending_assoc_req;
+	priv->pending_assoc_req = NULL;
+	priv->in_progress_assoc_req = assoc_req;
+	mutex_unlock(&priv->lock);
 
 	if (!assoc_req)
 		goto done;
 
-	print_assoc_req(__func__, assoc_req);
+	lbs_deb_assoc(
+		"Association Request:\n"
+		"    flags:     0x%08lx\n"
+		"    SSID:      '%s'\n"
+		"    chann:     %d\n"
+		"    band:      %d\n"
+		"    mode:      %d\n"
+		"    BSSID:     %s\n"
+		"    secinfo:  %s%s%s\n"
+		"    auth_mode: %d\n",
+		assoc_req->flags,
+		escape_essid(assoc_req->ssid, assoc_req->ssid_len),
+		assoc_req->channel, assoc_req->band, assoc_req->mode,
+		print_mac(mac, assoc_req->bssid),
+		assoc_req->secinfo.WPAenabled ? " WPA" : "",
+		assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
+		assoc_req->secinfo.wep_enabled ? " WEP" : "",
+		assoc_req->secinfo.auth_mode);
 
 	/* If 'any' SSID was specified, find an SSID to associate with */
 	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
@@ -538,7 +541,7 @@ void libertas_association_worker(struct work_struct *work)
 	if (find_any_ssid) {
 		u8 new_mode;
 
-		ret = libertas_find_best_network_ssid(priv, assoc_req->ssid,
+		ret = lbs_find_best_network_ssid(priv, assoc_req->ssid,
 				&assoc_req->ssid_len, assoc_req->mode, &new_mode);
 		if (ret) {
 			lbs_deb_assoc("Could not find best network\n");
@@ -557,18 +560,18 @@ void libertas_association_worker(struct work_struct *work)
 	 * Check if the attributes being changing require deauthentication
 	 * from the currently associated infrastructure access point.
 	 */
-	if (adapter->mode == IW_MODE_INFRA) {
-		if (should_deauth_infrastructure(adapter, assoc_req)) {
-			ret = libertas_send_deauthentication(priv);
+	if (priv->mode == IW_MODE_INFRA) {
+		if (should_deauth_infrastructure(priv, assoc_req)) {
+			ret = lbs_send_deauthentication(priv);
 			if (ret) {
 				lbs_deb_assoc("Deauthentication due to new "
 					"configuration request failed: %d\n",
 					ret);
 			}
 		}
-	} else if (adapter->mode == IW_MODE_ADHOC) {
-		if (should_stop_adhoc(adapter, assoc_req)) {
-			ret = libertas_stop_adhoc_network(priv);
+	} else if (priv->mode == IW_MODE_ADHOC) {
+		if (should_stop_adhoc(priv, assoc_req)) {
+			ret = lbs_stop_adhoc_network(priv);
 			if (ret) {
 				lbs_deb_assoc("Teardown of AdHoc network due to "
 					"new configuration request failed: %d\n",
@@ -581,58 +584,40 @@ void libertas_association_worker(struct work_struct *work)
 	/* Send the various configuration bits to the firmware */
 	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
 		ret = assoc_helper_mode(priv, assoc_req);
-		if (ret) {
-			lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n",
-			              __LINE__, ret);
+		if (ret)
 			goto out;
-		}
 	}
 
 	if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) {
 		ret = assoc_helper_channel(priv, assoc_req);
-		if (ret) {
-			lbs_deb_assoc("ASSOC(:%d) channel: ret = %d\n",
-			              __LINE__, ret);
+		if (ret)
 			goto out;
-		}
 	}
 
 	if (   test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
 	    || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
 		ret = assoc_helper_wep_keys(priv, assoc_req);
-		if (ret) {
-			lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n",
-			              __LINE__, ret);
+		if (ret)
 			goto out;
-		}
 	}
 
 	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
 		ret = assoc_helper_secinfo(priv, assoc_req);
-		if (ret) {
-			lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n",
-			              __LINE__, ret);
+		if (ret)
 			goto out;
-		}
 	}
 
 	if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
 		ret = assoc_helper_wpa_ie(priv, assoc_req);
-		if (ret) {
-			lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n",
-			              __LINE__, ret);
+		if (ret)
 			goto out;
-		}
 	}
 
 	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
 	    || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
 		ret = assoc_helper_wpa_keys(priv, assoc_req);
-		if (ret) {
-			lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n",
-			              __LINE__, ret);
+		if (ret)
 			goto out;
-		}
 	}
 
 	/* SSID/BSSID should be the _last_ config option set, because they
@@ -644,28 +629,27 @@ void libertas_association_worker(struct work_struct *work)
 
 		ret = assoc_helper_associate(priv, assoc_req);
 		if (ret) {
-			lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n",
+			lbs_deb_assoc("ASSOC: association unsuccessful: %d\n",
 				ret);
 			success = 0;
 		}
 
-		if (adapter->connect_status != LIBERTAS_CONNECTED) {
-			lbs_deb_assoc("ASSOC: association attempt unsuccessful, "
-				"not connected.\n");
+		if (priv->connect_status != LBS_CONNECTED) {
+			lbs_deb_assoc("ASSOC: association unsuccessful, "
+				"not connected\n");
 			success = 0;
 		}
 
 		if (success) {
-			lbs_deb_assoc("ASSOC: association attempt successful. "
-				"Associated to '%s' (%s)\n",
-				escape_essid(adapter->curbssparams.ssid,
-				             adapter->curbssparams.ssid_len),
-				print_mac(mac, adapter->curbssparams.bssid));
-			libertas_prepare_and_send_command(priv,
+			lbs_deb_assoc("ASSOC: associated to '%s', %s\n",
+				escape_essid(priv->curbssparams.ssid,
+				             priv->curbssparams.ssid_len),
+				print_mac(mac, priv->curbssparams.bssid));
+			lbs_prepare_and_send_command(priv,
 				CMD_802_11_RSSI,
 				0, CMD_OPTION_WAITFORRSP, 0, NULL);
 
-			libertas_prepare_and_send_command(priv,
+			lbs_prepare_and_send_command(priv,
 				CMD_802_11_GET_LOG,
 				0, CMD_OPTION_WAITFORRSP, 0, NULL);
 		} else {
@@ -679,9 +663,9 @@ out:
 			ret);
 	}
 
-	mutex_lock(&adapter->lock);
-	adapter->in_progress_assoc_req = NULL;
-	mutex_unlock(&adapter->lock);
+	mutex_lock(&priv->lock);
+	priv->in_progress_assoc_req = NULL;
+	mutex_unlock(&priv->lock);
 	kfree(assoc_req);
 
 done:
@@ -692,14 +676,15 @@ done:
 /*
  * Caller MUST hold any necessary locks
  */
-struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
+struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
 {
 	struct assoc_request * assoc_req;
 
-	if (!adapter->pending_assoc_req) {
-		adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
+	lbs_deb_enter(LBS_DEB_ASSOC);
+	if (!priv->pending_assoc_req) {
+		priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request),
 		                                     GFP_KERNEL);
-		if (!adapter->pending_assoc_req) {
+		if (!priv->pending_assoc_req) {
 			lbs_pr_info("Not enough memory to allocate association"
 				" request!\n");
 			return NULL;
@@ -709,60 +694,59 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
 	/* Copy current configuration attributes to the association request,
 	 * but don't overwrite any that are already set.
 	 */
-	assoc_req = adapter->pending_assoc_req;
+	assoc_req = priv->pending_assoc_req;
 	if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
-		memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid,
+		memcpy(&assoc_req->ssid, &priv->curbssparams.ssid,
 		       IW_ESSID_MAX_SIZE);
-		assoc_req->ssid_len = adapter->curbssparams.ssid_len;
+		assoc_req->ssid_len = priv->curbssparams.ssid_len;
 	}
 
 	if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
-		assoc_req->channel = adapter->curbssparams.channel;
+		assoc_req->channel = priv->curbssparams.channel;
 
 	if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags))
-		assoc_req->band = adapter->curbssparams.band;
+		assoc_req->band = priv->curbssparams.band;
 
 	if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
-		assoc_req->mode = adapter->mode;
+		assoc_req->mode = priv->mode;
 
 	if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
-		memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
+		memcpy(&assoc_req->bssid, priv->curbssparams.bssid,
 			ETH_ALEN);
 	}
 
 	if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
 		int i;
 		for (i = 0; i < 4; i++) {
-			memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
+			memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i],
 				sizeof(struct enc_key));
 		}
 	}
 
 	if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
-		assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
+		assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx;
 
 	if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
-		memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
+		memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key,
 			sizeof(struct enc_key));
 	}
 
 	if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
-		memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
+		memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key,
 			sizeof(struct enc_key));
 	}
 
 	if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
-		memcpy(&assoc_req->secinfo, &adapter->secinfo,
-			sizeof(struct wlan_802_11_security));
+		memcpy(&assoc_req->secinfo, &priv->secinfo,
+			sizeof(struct lbs_802_11_security));
 	}
 
 	if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
-		memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
+		memcpy(&assoc_req->wpa_ie, &priv->wpa_ie,
 			MAX_WPA_IE_LEN);
-		assoc_req->wpa_ie_len = adapter->wpa_ie_len;
+		assoc_req->wpa_ie_len = priv->wpa_ie_len;
 	}
 
-	print_assoc_req(__func__, assoc_req);
-
+	lbs_deb_leave(LBS_DEB_ASSOC);
 	return assoc_req;
 }
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
index e09b7490abbd..08372bbf3761 100644
--- a/drivers/net/wireless/libertas/assoc.h
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -1,32 +1,12 @@
 /* Copyright (C) 2006, Red Hat, Inc. */
 
-#ifndef _WLAN_ASSOC_H_
-#define _WLAN_ASSOC_H_
+#ifndef _LBS_ASSOC_H_
+#define _LBS_ASSOC_H_
 
 #include "dev.h"
 
-void libertas_association_worker(struct work_struct *work);
+void lbs_association_worker(struct work_struct *work);
+struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
+void lbs_sync_channel(struct work_struct *work);
 
-struct assoc_request * wlan_get_association_request(wlan_adapter *adapter);
-
-void libertas_sync_channel(struct work_struct *work);
-
-#define ASSOC_DELAY (HZ / 2)
-static inline void wlan_postpone_association_work(wlan_private *priv)
-{
-	if (priv->adapter->surpriseremoved)
-		return;
-	cancel_delayed_work(&priv->assoc_work);
-	queue_delayed_work(priv->work_thread, &priv->assoc_work, ASSOC_DELAY);
-}
-
-static inline void wlan_cancel_association_work(wlan_private *priv)
-{
-	cancel_delayed_work(&priv->assoc_work);
-	if (priv->adapter->pending_assoc_req) {
-		kfree(priv->adapter->pending_assoc_req);
-		priv->adapter->pending_assoc_req = NULL;
-	}
-}
-
-#endif /* _WLAN_ASSOC_H */
+#endif /* _LBS_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index be5cfd8402c7..eab020338fde 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -11,47 +11,139 @@
 #include "dev.h"
 #include "join.h"
 #include "wext.h"
+#include "cmd.h"
 
-static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
+static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
+static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
+		    struct cmd_ctrl_node *ptempnode,
+		    void *pdata_buf);
 
-static u16 commands_allowed_in_ps[] = {
-	CMD_802_11_RSSI,
-};
 
 /**
- *  @brief This function checks if the commans is allowed
- *  in PS mode not.
+ *  @brief Checks whether a command is allowed in Power Save mode
  *
  *  @param command the command ID
- *  @return 	   TRUE or FALSE
+ *  @return 	   1 if allowed, 0 if not allowed
  */
-static u8 is_command_allowed_in_ps(__le16 command)
+static u8 is_command_allowed_in_ps(u16 cmd)
 {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(commands_allowed_in_ps); i++) {
-		if (command == cpu_to_le16(commands_allowed_in_ps[i]))
-			return 1;
+	switch (cmd) {
+	case CMD_802_11_RSSI:
+		return 1;
+	default:
+		break;
 	}
-
 	return 0;
 }
 
-static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd)
+/**
+ *  @brief Updates the hardware details like MAC address and regulatory region
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_update_hw_spec(struct lbs_private *priv)
 {
-	struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
+	struct cmd_ds_get_hw_spec cmd;
+	int ret = -1;
+	u32 i;
+	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(CMD_GET_HW_SPEC);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
-	memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
+	ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
+	if (ret)
+		goto out;
+
+	priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
+
+	/* The firmware release is in an interesting format: the patch
+	 * level is in the most significant nibble ... so fix that: */
+	priv->fwrelease = le32_to_cpu(cmd.fwrelease);
+	priv->fwrelease = (priv->fwrelease << 8) |
+		(priv->fwrelease >> 24 & 0xff);
+
+	/* Some firmware capabilities:
+	 * CF card    firmware 5.0.16p0:   cap 0x00000303
+	 * USB dongle firmware 5.110.17p2: cap 0x00000303
+	 */
+	printk("libertas: %s, fw %u.%u.%up%u, cap 0x%08x\n",
+		print_mac(mac, cmd.permanentaddr),
+		priv->fwrelease >> 24 & 0xff,
+		priv->fwrelease >> 16 & 0xff,
+		priv->fwrelease >>  8 & 0xff,
+		priv->fwrelease       & 0xff,
+		priv->fwcapinfo);
+	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
+		    cmd.hwifversion, cmd.version);
+
+	/* Clamp region code to 8-bit since FW spec indicates that it should
+	 * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
+	 * returns non-zero high 8 bits here.
+	 */
+	priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
+
+	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+		/* use the region code to search for the index */
+		if (priv->regioncode == lbs_region_code_to_index[i])
+			break;
+	}
+
+	/* if it's unidentified region code, use the default (USA) */
+	if (i >= MRVDRV_MAX_REGION_CODE) {
+		priv->regioncode = 0x10;
+		lbs_pr_info("unidentified region code; using the default (USA)\n");
+	}
+
+	if (priv->current_addr[0] == 0xff)
+		memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
+
+	memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN);
+	if (priv->mesh_dev)
+		memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
+
+	if (lbs_set_regiontable(priv, priv->regioncode, 0)) {
+		ret = -1;
+		goto out;
+	}
 
+	if (lbs_set_universaltable(priv, 0)) {
+		ret = -1;
+		goto out;
+	}
+
+out:
 	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
+	return ret;
 }
 
-static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
+int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria)
+{
+	struct cmd_ds_host_sleep cmd_config;
+	int ret;
+
+	cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config));
+	cmd_config.criteria = cpu_to_le32(criteria);
+	cmd_config.gpio = priv->wol_gpio;
+	cmd_config.gap = priv->wol_gap;
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
+	if (!ret) {
+		lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
+		priv->wol_criteria = criteria;
+	} else {
+		lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
+
+static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv,
 				   struct cmd_ds_command *cmd,
 				   u16 cmd_action)
 {
@@ -90,161 +182,161 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
-					      struct cmd_ds_command *cmd,
-					      u16 cmd_action, void *pdata_buf)
+int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
+				      uint16_t cmd_action, uint16_t *timeout)
 {
-	u16 *timeout = pdata_buf;
+	struct cmd_ds_802_11_inactivity_timeout cmd;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
-	cmd->size =
-	    cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
-			     + S_DS_GEN);
+	cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 
-	cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action);
+	cmd.action = cpu_to_le16(cmd_action);
 
-	if (cmd_action)
-		cmd->params.inactivity_timeout.timeout = cpu_to_le16(*timeout);
+	if (cmd_action == CMD_ACT_SET)
+		cmd.timeout = cpu_to_le16(*timeout);
 	else
-		cmd->params.inactivity_timeout.timeout = 0;
+		cmd.timeout = 0;
 
-	lbs_deb_leave(LBS_DEB_CMD);
+	ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd);
+
+	if (!ret)
+		*timeout = le16_to_cpu(cmd.timeout);
+
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return 0;
 }
 
-static int wlan_cmd_802_11_sleep_params(wlan_private * priv,
-					struct cmd_ds_command *cmd,
-					u16 cmd_action)
+int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
+				struct sleep_params *sp)
 {
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
+	struct cmd_ds_802_11_sleep_params cmd;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
-				S_DS_GEN);
-	cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
-
 	if (cmd_action == CMD_ACT_GET) {
-		memset(&adapter->sp, 0, sizeof(struct sleep_params));
-		memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
-		sp->action = cpu_to_le16(cmd_action);
-	} else if (cmd_action == CMD_ACT_SET) {
-		sp->action = cpu_to_le16(cmd_action);
-		sp->error = cpu_to_le16(adapter->sp.sp_error);
-		sp->offset = cpu_to_le16(adapter->sp.sp_offset);
-		sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime);
-		sp->calcontrol = (u8) adapter->sp.sp_calcontrol;
-		sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk;
-		sp->reserved = cpu_to_le16(adapter->sp.sp_reserved);
+		memset(&cmd, 0, sizeof(cmd));
+	} else {
+		cmd.error = cpu_to_le16(sp->sp_error);
+		cmd.offset = cpu_to_le16(sp->sp_offset);
+		cmd.stabletime = cpu_to_le16(sp->sp_stabletime);
+		cmd.calcontrol = sp->sp_calcontrol;
+		cmd.externalsleepclk = sp->sp_extsleepclk;
+		cmd.reserved = cpu_to_le16(sp->sp_reserved);
+	}
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(cmd_action);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd);
+
+	if (!ret) {
+		lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, "
+			    "calcontrol 0x%x extsleepclk 0x%x\n",
+			    le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset),
+			    le16_to_cpu(cmd.stabletime), cmd.calcontrol,
+			    cmd.externalsleepclk);
+
+		sp->sp_error = le16_to_cpu(cmd.error);
+		sp->sp_offset = le16_to_cpu(cmd.offset);
+		sp->sp_stabletime = le16_to_cpu(cmd.stabletime);
+		sp->sp_calcontrol = cmd.calcontrol;
+		sp->sp_extsleepclk = cmd.externalsleepclk;
+		sp->sp_reserved = le16_to_cpu(cmd.reserved);
 	}
 
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return 0;
 }
 
-static int wlan_cmd_802_11_set_wep(wlan_private * priv,
-                                   struct cmd_ds_command *cmd,
-                                   u32 cmd_act,
-                                   void * pdata_buf)
+int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
+			   struct assoc_request *assoc)
 {
-	struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
-	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_set_wep cmd;
 	int ret = 0;
-	struct assoc_request * assoc_req = pdata_buf;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
-	cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
-
-	if (cmd_act == CMD_ACT_ADD) {
-		int i;
+	cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP);
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 
-		if (!assoc_req) {
-			lbs_deb_cmd("Invalid association request!");
-			ret = -1;
-			goto done;
-		}
+	cmd.action = cpu_to_le16(cmd_action);
 
-		wep->action = cpu_to_le16(CMD_ACT_ADD);
+	if (cmd_action == CMD_ACT_ADD) {
+		int i;
 
 		/* default tx key index */
-		wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
-						  (u32)CMD_WEP_KEY_INDEX_MASK));
+		cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx &
+					   CMD_WEP_KEY_INDEX_MASK);
 
 		/* Copy key types and material to host command structure */
 		for (i = 0; i < 4; i++) {
-			struct enc_key * pkey = &assoc_req->wep_keys[i];
+			struct enc_key *pkey = &assoc->wep_keys[i];
 
 			switch (pkey->len) {
 			case KEY_LEN_WEP_40:
-				wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
-				memmove(&wep->keymaterial[i], pkey->key,
-				        pkey->len);
+				cmd.keytype[i] = CMD_TYPE_WEP_40_BIT;
+				memmove(cmd.keymaterial[i], pkey->key, pkey->len);
 				lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
 				break;
 			case KEY_LEN_WEP_104:
-				wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
-				memmove(&wep->keymaterial[i], pkey->key,
-				        pkey->len);
+				cmd.keytype[i] = CMD_TYPE_WEP_104_BIT;
+				memmove(cmd.keymaterial[i], pkey->key, pkey->len);
 				lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
 				break;
 			case 0:
 				break;
 			default:
 				lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
-				       i, pkey->len);
+					    i, pkey->len);
 				ret = -1;
 				goto done;
 				break;
 			}
 		}
-	} else if (cmd_act == CMD_ACT_REMOVE) {
+	} else if (cmd_action == CMD_ACT_REMOVE) {
 		/* ACT_REMOVE clears _all_ WEP keys */
-		wep->action = cpu_to_le16(CMD_ACT_REMOVE);
 
 		/* default tx key index */
-		wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx &
-						  (u32)CMD_WEP_KEY_INDEX_MASK));
-		lbs_deb_cmd("SET_WEP: remove key %d\n", adapter->wep_tx_keyidx);
+		cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx &
+					   CMD_WEP_KEY_INDEX_MASK);
+		lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx);
 	}
 
-	ret = 0;
-
+	ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd);
 done:
 	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return ret;
 }
 
-static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
-				      struct cmd_ds_command *cmd,
-				      u16 cmd_action,
-				      void * pdata_buf)
+int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
+			      uint16_t *enable)
 {
-	struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
-	u32 * enable = pdata_buf;
+	struct cmd_ds_802_11_enable_rsn cmd;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
-	cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
-	penableRSN->action = cpu_to_le16(cmd_action);
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(cmd_action);
 
 	if (cmd_action == CMD_ACT_SET) {
 		if (*enable)
-			penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
+			cmd.enable = cpu_to_le16(CMD_ENABLE_RSN);
 		else
-			penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
+			cmd.enable = cpu_to_le16(CMD_DISABLE_RSN);
 		lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
 	}
 
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
-}
+	ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd);
+	if (!ret && cmd_action == CMD_ACT_GET)
+		*enable = le16_to_cpu(cmd.enable);
 
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
+}
 
 static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
                             struct enc_key * pkey)
@@ -272,7 +364,7 @@ static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
 	lbs_deb_leave(LBS_DEB_CMD);
 }
 
-static int wlan_cmd_802_11_key_material(wlan_private * priv,
+static int lbs_cmd_802_11_key_material(struct lbs_private *priv,
 					struct cmd_ds_command *cmd,
 					u16 cmd_action,
 					u32 cmd_oid, void *pdata_buf)
@@ -319,7 +411,7 @@ done:
 	return ret;
 }
 
-static int wlan_cmd_802_11_reset(wlan_private * priv,
+static int lbs_cmd_802_11_reset(struct lbs_private *priv,
 				 struct cmd_ds_command *cmd, int cmd_action)
 {
 	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
@@ -334,7 +426,7 @@ static int wlan_cmd_802_11_reset(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_802_11_get_log(wlan_private * priv,
+static int lbs_cmd_802_11_get_log(struct lbs_private *priv,
 				   struct cmd_ds_command *cmd)
 {
 	lbs_deb_enter(LBS_DEB_CMD);
@@ -346,7 +438,7 @@ static int wlan_cmd_802_11_get_log(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_802_11_get_stat(wlan_private * priv,
+static int lbs_cmd_802_11_get_stat(struct lbs_private *priv,
 				    struct cmd_ds_command *cmd)
 {
 	lbs_deb_enter(LBS_DEB_CMD);
@@ -358,13 +450,12 @@ static int wlan_cmd_802_11_get_stat(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
+static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv,
 				    struct cmd_ds_command *cmd,
 				    int cmd_action,
 				    int cmd_oid, void *pdata_buf)
 {
 	struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
-	wlan_adapter *adapter = priv->adapter;
 	u8 ucTemp;
 
 	lbs_deb_enter(LBS_DEB_CMD);
@@ -380,7 +471,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
 		u8 mode = (u8) (size_t) pdata_buf;
 		pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
 		pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
-		pSNMPMIB->bufsize = sizeof(u8);
+		pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8));
 		if (mode == IW_MODE_ADHOC) {
 			ucTemp = SNMP_MIB_VALUE_ADHOC;
 		} else {
@@ -400,8 +491,8 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
 			pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
 
 			if (cmd_action == CMD_ACT_SET) {
-				pSNMPMIB->querytype = CMD_ACT_SET;
-				pSNMPMIB->bufsize = sizeof(u16);
+				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
+				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
 				ulTemp = *(u32 *)pdata_buf;
 				*((__le16 *)(pSNMPMIB->value)) =
 				    cpu_to_le16((u16) ulTemp);
@@ -433,7 +524,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
 		{
 
 			u32 ulTemp;
-			pSNMPMIB->oid = le16_to_cpu((u16) RTSTHRESH_I);
+			pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I);
 
 			if (cmd_action == CMD_ACT_GET) {
 				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
@@ -456,7 +547,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
 			pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
 			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
 			*((__le16 *)(pSNMPMIB->value)) =
-			    cpu_to_le16((u16) adapter->txretrycount);
+			    cpu_to_le16((u16) priv->txretrycount);
 		}
 
 		break;
@@ -479,47 +570,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_802_11_radio_control(wlan_private * priv,
-					 struct cmd_ds_command *cmd,
-					 int cmd_action)
-{
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ds_802_11_radio_control *pradiocontrol = &cmd->params.radio;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	cmd->size =
-	    cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
-			     S_DS_GEN);
-	cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
-
-	pradiocontrol->action = cpu_to_le16(cmd_action);
-
-	switch (adapter->preamble) {
-	case CMD_TYPE_SHORT_PREAMBLE:
-		pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
-		break;
-
-	case CMD_TYPE_LONG_PREAMBLE:
-		pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
-		break;
-
-	case CMD_TYPE_AUTO_PREAMBLE:
-	default:
-		pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
-		break;
-	}
-
-	if (adapter->radioon)
-		pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
-	else
-		pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
-
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
-}
-
-static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
+static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv,
 				       struct cmd_ds_command *cmd,
 				       u16 cmd_action, void *pdata_buf)
 {
@@ -563,7 +614,7 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_802_11_monitor_mode(wlan_private * priv,
+static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv,
 				      struct cmd_ds_command *cmd,
 				      u16 cmd_action, void *pdata_buf)
 {
@@ -583,13 +634,12 @@ static int wlan_cmd_802_11_monitor_mode(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
+static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv,
 					      struct cmd_ds_command *cmd,
 					      u16 cmd_action)
 {
 	struct cmd_ds_802_11_rate_adapt_rateset
 	*rateadapt = &cmd->params.rateset;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 	cmd->size =
@@ -598,46 +648,100 @@ static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
 	cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
 
 	rateadapt->action = cpu_to_le16(cmd_action);
-	rateadapt->enablehwauto = cpu_to_le16(adapter->enablehwauto);
-	rateadapt->bitmap = cpu_to_le16(adapter->ratebitmap);
+	rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto);
+	rateadapt->bitmap = cpu_to_le16(priv->ratebitmap);
 
 	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
-static int wlan_cmd_802_11_data_rate(wlan_private * priv,
-				     struct cmd_ds_command *cmd,
-				     u16 cmd_action)
+/**
+ *  @brief Get the current data rate
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *
+ *  @return 	   	The data rate on success, error on failure
+ */
+int lbs_get_data_rate(struct lbs_private *priv)
 {
-	struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
-	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_802_11_data_rate cmd;
+	int ret = -1;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
-			     S_DS_GEN);
-	cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE);
-	memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
-	pdatarate->action = cpu_to_le16(cmd_action);
-
-	if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) {
-		pdatarate->rates[0] = libertas_data_rate_to_fw_index(adapter->cur_rate);
-		lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n",
-		       adapter->cur_rate);
-	} else if (cmd_action == CMD_ACT_SET_TX_AUTO) {
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
+	if (ret)
+		goto out;
+
+	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
+
+	ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]);
+	lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret);
+
+out:
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  @brief Set the data rate
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param rate  	The desired data rate, or 0 to clear a locked rate
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_set_data_rate(struct lbs_private *priv, u8 rate)
+{
+	struct cmd_ds_802_11_data_rate cmd;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+	if (rate > 0) {
+		cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE);
+		cmd.rates[0] = lbs_data_rate_to_fw_index(rate);
+		if (cmd.rates[0] == 0) {
+			lbs_deb_cmd("DATA_RATE: invalid requested rate of"
+			            " 0x%02X\n", rate);
+			ret = 0;
+			goto out;
+		}
+		lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]);
+	} else {
+		cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO);
 		lbs_deb_cmd("DATA_RATE: setting auto\n");
 	}
 
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
+	ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd);
+	if (ret)
+		goto out;
+
+	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd));
+
+	/* FIXME: get actual rates FW can do if this command actually returns
+	 * all data rates supported.
+	 */
+	priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]);
+	lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate);
+
+out:
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
 }
 
-static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
+static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv,
 				      struct cmd_ds_command *cmd,
 				      u16 cmd_action)
 {
 	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
@@ -647,39 +751,79 @@ static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
 	lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
 	pMCastAdr->action = cpu_to_le16(cmd_action);
 	pMCastAdr->nr_of_adrs =
-	    cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
-	memcpy(pMCastAdr->maclist, adapter->multicastlist,
-	       adapter->nr_of_multicastmacaddr * ETH_ALEN);
+	    cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
+	memcpy(pMCastAdr->maclist, priv->multicastlist,
+	       priv->nr_of_multicastmacaddr * ETH_ALEN);
 
 	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
-static int wlan_cmd_802_11_rf_channel(wlan_private * priv,
-				      struct cmd_ds_command *cmd,
-				      int option, void *pdata_buf)
+/**
+ *  @brief Get the radio channel
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *
+ *  @return 	   	The channel on success, error on failure
+ */
+int lbs_get_channel(struct lbs_private *priv)
 {
-	struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
+	struct cmd_ds_802_11_rf_channel cmd;
+	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_CMD);
-	cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) +
-				S_DS_GEN);
 
-	if (option == CMD_OPT_802_11_RF_CHANNEL_SET) {
-		rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
-	}
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET);
 
-	rfchan->action = cpu_to_le16(option);
+	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
+	if (ret)
+		goto out;
 
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
+	ret = le16_to_cpu(cmd.channel);
+	lbs_deb_cmd("current radio channel is %d\n", ret);
+
+out:
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  @brief Set the radio channel
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param channel  	The desired channel, or 0 to clear a locked channel
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_set_channel(struct lbs_private *priv, u8 channel)
+{
+	struct cmd_ds_802_11_rf_channel cmd;
+	u8 old_channel = priv->curbssparams.channel;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
+	cmd.channel = cpu_to_le16(channel);
+
+	ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
+	if (ret)
+		goto out;
+
+	priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel);
+	lbs_deb_cmd("channel switch from %d to %d\n", old_channel,
+		priv->curbssparams.channel);
+
+out:
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	return ret;
 }
 
-static int wlan_cmd_802_11_rssi(wlan_private * priv,
+static int lbs_cmd_802_11_rssi(struct lbs_private *priv,
 				struct cmd_ds_command *cmd)
 {
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 	cmd->command = cpu_to_le16(CMD_802_11_RSSI);
@@ -687,28 +831,28 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv,
 	cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
 
 	/* reset Beacon SNR/NF/RSSI values */
-	adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
-	adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0;
-	adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
-	adapter->NF[TYPE_BEACON][TYPE_AVG] = 0;
-	adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
-	adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+	priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
+	priv->SNR[TYPE_BEACON][TYPE_AVG] = 0;
+	priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
+	priv->NF[TYPE_BEACON][TYPE_AVG] = 0;
+	priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
+	priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
 
 	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
-static int wlan_cmd_reg_access(wlan_private * priv,
+static int lbs_cmd_reg_access(struct lbs_private *priv,
 			       struct cmd_ds_command *cmdptr,
 			       u8 cmd_action, void *pdata_buf)
 {
-	struct wlan_offset_value *offval;
+	struct lbs_offset_value *offval;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	offval = (struct wlan_offset_value *)pdata_buf;
+	offval = (struct lbs_offset_value *)pdata_buf;
 
-	switch (cmdptr->command) {
+	switch (le16_to_cpu(cmdptr->command)) {
 	case CMD_MAC_REG_ACCESS:
 		{
 			struct cmd_ds_mac_reg_access *macreg;
@@ -773,11 +917,10 @@ static int wlan_cmd_reg_access(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_802_11_mac_address(wlan_private * priv,
+static int lbs_cmd_802_11_mac_address(struct lbs_private *priv,
 				       struct cmd_ds_command *cmd,
 				       u16 cmd_action)
 {
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 	cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
@@ -789,19 +932,19 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv,
 
 	if (cmd_action == CMD_ACT_SET) {
 		memcpy(cmd->params.macadd.macadd,
-		       adapter->current_addr, ETH_ALEN);
-		lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6);
+		       priv->current_addr, ETH_ALEN);
+		lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6);
 	}
 
 	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
-static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
+static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv,
 					 struct cmd_ds_command *cmd,
 					 int cmd_action, void *pdata_buf)
 {
-	struct wlan_ioctl_regrdwr *ea = pdata_buf;
+	struct lbs_ioctl_regrdwr *ea = pdata_buf;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
@@ -819,7 +962,7 @@ static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_bt_access(wlan_private * priv,
+static int lbs_cmd_bt_access(struct lbs_private *priv,
 			       struct cmd_ds_command *cmd,
 			       u16 cmd_action, void *pdata_buf)
 {
@@ -857,7 +1000,7 @@ static int wlan_cmd_bt_access(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_fwt_access(wlan_private * priv,
+static int lbs_cmd_fwt_access(struct lbs_private *priv,
 			       struct cmd_ds_command *cmd,
 			       u16 cmd_action, void *pdata_buf)
 {
@@ -879,47 +1022,72 @@ static int wlan_cmd_fwt_access(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_cmd_mesh_access(wlan_private * priv,
-				struct cmd_ds_command *cmd,
-				u16 cmd_action, void *pdata_buf)
+int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+		    struct cmd_ds_mesh_access *cmd)
 {
-	struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
+	int ret;
+
 	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
 
-	cmd->command = cpu_to_le16(CMD_MESH_ACCESS);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
-	cmd->result = 0;
+	cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
+	cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
+	cmd->hdr.result = 0;
 
-	if (pdata_buf)
-		memcpy(mesh_access, pdata_buf, sizeof(*mesh_access));
-	else
-		memset(mesh_access, 0, sizeof(*mesh_access));
+	cmd->action = cpu_to_le16(cmd_action);
 
-	mesh_access->action = cpu_to_le16(cmd_action);
+	ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
 
 	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
+	return ret;
 }
+EXPORT_SYMBOL_GPL(lbs_mesh_access);
 
-static int wlan_cmd_set_boot2_ver(wlan_private * priv,
+int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan)
+{
+	struct cmd_ds_mesh_config cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.action = cpu_to_le16(enable);
+	cmd.channel = cpu_to_le16(chan);
+	cmd.type = cpu_to_le16(priv->mesh_tlv);
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+
+	if (enable) {
+		cmd.length = cpu_to_le16(priv->mesh_ssid_len);
+		memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len);
+	}
+	lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n",
+		    enable, priv->mesh_tlv, chan,
+		    escape_essid(priv->mesh_ssid, priv->mesh_ssid_len));
+	return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd);
+}
+
+static int lbs_cmd_bcn_ctrl(struct lbs_private * priv,
 				struct cmd_ds_command *cmd,
-				u16 cmd_action, void *pdata_buf)
+				u16 cmd_action)
 {
-	struct cmd_ds_set_boot2_ver *boot2_ver = &cmd->params.boot2_ver;
-	cmd->command = cpu_to_le16(CMD_SET_BOOT2_VER);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_set_boot2_ver) + S_DS_GEN);
-	boot2_ver->version = priv->boot2_version;
+	struct cmd_ds_802_11_beacon_control
+		*bcn_ctrl = &cmd->params.bcn_ctrl;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control)
+			     + S_DS_GEN);
+	cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL);
+
+	bcn_ctrl->action = cpu_to_le16(cmd_action);
+	bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable);
+	bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period);
+
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
-/*
- * Note: NEVER use libertas_queue_cmd() with addtail==0 other than for
- * the command timer, because it does not account for queued commands.
- */
-void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail)
+static void lbs_queue_cmd(struct lbs_private *priv,
+			  struct cmd_ctrl_node *cmdnode)
 {
 	unsigned long flags;
-	struct cmd_ds_command *cmdptr;
+	int addtail = 1;
 
 	lbs_deb_enter(LBS_DEB_HOST);
 
@@ -927,118 +1095,87 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u
 		lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
 		goto done;
 	}
-
-	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
-	if (!cmdptr) {
-		lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n");
+	if (!cmdnode->cmdbuf->size) {
+		lbs_deb_host("DNLD_CMD: cmd size is zero\n");
 		goto done;
 	}
+	cmdnode->result = 0;
 
 	/* Exit_PS command needs to be queued in the header always. */
-	if (cmdptr->command == CMD_802_11_PS_MODE) {
-		struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
+	if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
+		struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf[1];
+
 		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
-			if (adapter->psstate != PS_STATE_FULL_POWER)
+			if (priv->psstate != PS_STATE_FULL_POWER)
 				addtail = 0;
 		}
 	}
 
-	spin_lock_irqsave(&adapter->driver_lock, flags);
+	spin_lock_irqsave(&priv->driver_lock, flags);
 
-	if (addtail) {
-		list_add_tail((struct list_head *)cmdnode,
-			      &adapter->cmdpendingq);
-		adapter->nr_cmd_pending++;
-	} else
-		list_add((struct list_head *)cmdnode, &adapter->cmdpendingq);
+	if (addtail)
+		list_add_tail(&cmdnode->list, &priv->cmdpendingq);
+	else
+		list_add(&cmdnode->list, &priv->cmdpendingq);
 
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
-	       le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command));
+		     le16_to_cpu(cmdnode->cmdbuf->command));
 
 done:
 	lbs_deb_leave(LBS_DEB_HOST);
 }
 
-/*
- * TODO: Fix the issue when DownloadcommandToStation is being called the
- * second time when the command times out. All the cmdptr->xxx are in little
- * endian and therefore all the comparissions will fail.
- * For now - we are not performing the endian conversion the second time - but
- * for PS and DEEP_SLEEP we need to worry
- */
-static int DownloadcommandToStation(wlan_private * priv,
-				    struct cmd_ctrl_node *cmdnode)
+static void lbs_submit_command(struct lbs_private *priv,
+			       struct cmd_ctrl_node *cmdnode)
 {
 	unsigned long flags;
-	struct cmd_ds_command *cmdptr;
-	wlan_adapter *adapter = priv->adapter;
-	int ret = -1;
-	u16 cmdsize;
-	u16 command;
+	struct cmd_header *cmd;
+	uint16_t cmdsize;
+	uint16_t command;
+	int timeo = 5 * HZ;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_HOST);
 
-	if (!adapter || !cmdnode) {
-		lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n");
-		goto done;
-	}
+	cmd = cmdnode->cmdbuf;
 
-	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	priv->cur_cmd = cmdnode;
+	priv->cur_cmd_retcode = 0;
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
-	spin_lock_irqsave(&adapter->driver_lock, flags);
-	if (!cmdptr || !cmdptr->size) {
-		lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
-		__libertas_cleanup_and_insert_cmd(priv, cmdnode);
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
-		goto done;
-	}
+	cmdsize = le16_to_cpu(cmd->size);
+	command = le16_to_cpu(cmd->command);
 
-	adapter->cur_cmd = cmdnode;
-	adapter->cur_cmd_retcode = 0;
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+	/* These commands take longer */
+	if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
+	    command == CMD_802_11_AUTHENTICATE)
+		timeo = 10 * HZ;
 
-	cmdsize = cmdptr->size;
-	command = cpu_to_le16(cmdptr->command);
+	lbs_deb_host("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n",
+		     command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies);
+	lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
 
-	lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
-		    command, le16_to_cpu(cmdptr->size), jiffies);
-	lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize);
+	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
 
-	cmdnode->cmdwaitqwoken = 0;
-	cmdsize = cpu_to_le16(cmdsize);
-
-	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
-
-	if (ret != 0) {
-		lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
-		spin_lock_irqsave(&adapter->driver_lock, flags);
-		adapter->cur_cmd_retcode = ret;
-		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
-		adapter->nr_cmd_pending--;
-		adapter->cur_cmd = NULL;
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
-		goto done;
-	}
-
-	lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
+	if (ret) {
+		lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
+		/* Let the timer kick in and retry, and potentially reset
+		   the whole thing if the condition persists */
+		timeo = HZ;
+	} else
+		lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n",
+			    command, jiffies);
 
 	/* Setup the timer after transmit command */
-	if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
-	    || command == CMD_802_11_ASSOCIATE)
-		mod_timer(&adapter->command_timer, jiffies + (10*HZ));
-	else
-		mod_timer(&adapter->command_timer, jiffies + (5*HZ));
-
-	ret = 0;
+	mod_timer(&priv->command_timer, jiffies + timeo);
 
-done:
-	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
-	return ret;
+	lbs_deb_leave(LBS_DEB_HOST);
 }
 
-static int wlan_cmd_mac_control(wlan_private * priv,
+static int lbs_cmd_mac_control(struct lbs_private *priv,
 				struct cmd_ds_command *cmd)
 {
 	struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
@@ -1047,7 +1184,7 @@ static int wlan_cmd_mac_control(wlan_private * priv,
 
 	cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
-	mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
+	mac->action = cpu_to_le16(priv->currentpacketfilter);
 
 	lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
 		    le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
@@ -1058,54 +1195,98 @@ static int wlan_cmd_mac_control(wlan_private * priv,
 
 /**
  *  This function inserts command node to cmdfreeq
- *  after cleans it. Requires adapter->driver_lock held.
+ *  after cleans it. Requires priv->driver_lock held.
  */
-void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
+					 struct cmd_ctrl_node *cmdnode)
 {
-	wlan_adapter *adapter = priv->adapter;
+	lbs_deb_enter(LBS_DEB_HOST);
 
-	if (!ptempcmd)
-		return;
+	if (!cmdnode)
+		goto out;
+
+	cmdnode->callback = NULL;
+	cmdnode->callback_arg = 0;
 
-	cleanup_cmdnode(ptempcmd);
-	list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
+	memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
+
+	list_add_tail(&cmdnode->list, &priv->cmdfreeq);
+ out:
+	lbs_deb_leave(LBS_DEB_HOST);
 }
 
-static void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv,
+	struct cmd_ctrl_node *ptempcmd)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
-	__libertas_cleanup_and_insert_cmd(priv, ptempcmd);
-	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	__lbs_cleanup_and_insert_cmd(priv, ptempcmd);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 }
 
-int libertas_set_radio_control(wlan_private * priv)
+void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+			  int result)
+{
+	if (cmd == priv->cur_cmd)
+		priv->cur_cmd_retcode = result;
+
+	cmd->result = result;
+	cmd->cmdwaitqwoken = 1;
+	wake_up_interruptible(&cmd->cmdwait_q);
+
+	if (!cmd->callback)
+		__lbs_cleanup_and_insert_cmd(priv, cmd);
+	priv->cur_cmd = NULL;
+}
+
+int lbs_set_radio_control(struct lbs_private *priv)
 {
 	int ret = 0;
+	struct cmd_ds_802_11_radio_control cmd;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	ret = libertas_prepare_and_send_command(priv,
-				    CMD_802_11_RADIO_CONTROL,
-				    CMD_ACT_SET,
-				    CMD_OPTION_WAITFORRSP, 0, NULL);
+	cmd.hdr.size = cpu_to_le16(sizeof(cmd));
+	cmd.action = cpu_to_le16(CMD_ACT_SET);
+
+	switch (priv->preamble) {
+	case CMD_TYPE_SHORT_PREAMBLE:
+		cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
+		break;
+
+	case CMD_TYPE_LONG_PREAMBLE:
+		cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
+		break;
+
+	case CMD_TYPE_AUTO_PREAMBLE:
+	default:
+		cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
+		break;
+	}
+
+	if (priv->radioon)
+		cmd.control |= cpu_to_le16(TURN_ON_RF);
+	else
+		cmd.control &= cpu_to_le16(~TURN_ON_RF);
+
+	lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon,
+		    priv->preamble);
 
-	lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
-	       priv->adapter->radioon, priv->adapter->preamble);
+	ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
 
 	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return ret;
 }
 
-int libertas_set_mac_packet_filter(wlan_private * priv)
+int lbs_set_mac_packet_filter(struct lbs_private *priv)
 {
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
 	/* Send MAC control command to station */
-	ret = libertas_prepare_and_send_command(priv,
+	ret = lbs_prepare_and_send_command(priv,
 				    CMD_MAC_CONTROL, 0, 0, 0, NULL);
 
 	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
@@ -1115,7 +1296,7 @@ int libertas_set_mac_packet_filter(wlan_private * priv)
 /**
  *  @brief This function prepare the command before send to firmware.
  *
- *  @param priv		A pointer to wlan_private structure
+ *  @param priv		A pointer to struct lbs_private structure
  *  @param cmd_no	command number
  *  @param cmd_action	command action: GET or SET
  *  @param wait_option	wait option: wait response or not
@@ -1123,32 +1304,31 @@ int libertas_set_mac_packet_filter(wlan_private * priv)
  *  @param pdata_buf	A pointer to informaion buffer
  *  @return 		0 or -1
  */
-int libertas_prepare_and_send_command(wlan_private * priv,
+int lbs_prepare_and_send_command(struct lbs_private *priv,
 			  u16 cmd_no,
 			  u16 cmd_action,
 			  u16 wait_option, u32 cmd_oid, void *pdata_buf)
 {
 	int ret = 0;
-	wlan_adapter *adapter = priv->adapter;
 	struct cmd_ctrl_node *cmdnode;
 	struct cmd_ds_command *cmdptr;
 	unsigned long flags;
 
 	lbs_deb_enter(LBS_DEB_HOST);
 
-	if (!adapter) {
-		lbs_deb_host("PREP_CMD: adapter is NULL\n");
+	if (!priv) {
+		lbs_deb_host("PREP_CMD: priv is NULL\n");
 		ret = -1;
 		goto done;
 	}
 
-	if (adapter->surpriseremoved) {
+	if (priv->surpriseremoved) {
 		lbs_deb_host("PREP_CMD: card removed\n");
 		ret = -1;
 		goto done;
 	}
 
-	cmdnode = libertas_get_free_cmd_ctrl_node(priv);
+	cmdnode = lbs_get_cmd_ctrl_node(priv);
 
 	if (cmdnode == NULL) {
 		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
@@ -1159,138 +1339,107 @@ int libertas_prepare_and_send_command(wlan_private * priv,
 		goto done;
 	}
 
-	libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf);
+	lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf);
 
-	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+	cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf;
 
 	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
 
-	if (!cmdptr) {
-		lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
-		libertas_cleanup_and_insert_cmd(priv, cmdnode);
-		ret = -1;
-		goto done;
-	}
-
 	/* Set sequence number, command and INT option */
-	adapter->seqnum++;
-	cmdptr->seqnum = cpu_to_le16(adapter->seqnum);
+	priv->seqnum++;
+	cmdptr->seqnum = cpu_to_le16(priv->seqnum);
 
 	cmdptr->command = cpu_to_le16(cmd_no);
 	cmdptr->result = 0;
 
 	switch (cmd_no) {
-	case CMD_GET_HW_SPEC:
-		ret = wlan_cmd_hw_spec(priv, cmdptr);
-		break;
 	case CMD_802_11_PS_MODE:
-		ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
+		ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
 		break;
 
 	case CMD_802_11_SCAN:
-		ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
+		ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf);
 		break;
 
 	case CMD_MAC_CONTROL:
-		ret = wlan_cmd_mac_control(priv, cmdptr);
+		ret = lbs_cmd_mac_control(priv, cmdptr);
 		break;
 
 	case CMD_802_11_ASSOCIATE:
 	case CMD_802_11_REASSOCIATE:
-		ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
+		ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
 		break;
 
 	case CMD_802_11_DEAUTHENTICATE:
-		ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
-		break;
-
-	case CMD_802_11_SET_WEP:
-		ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
+		ret = lbs_cmd_80211_deauthenticate(priv, cmdptr);
 		break;
 
 	case CMD_802_11_AD_HOC_START:
-		ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
+		ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
 		break;
 	case CMD_CODE_DNLD:
 		break;
 
 	case CMD_802_11_RESET:
-		ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
+		ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action);
 		break;
 
 	case CMD_802_11_GET_LOG:
-		ret = wlan_cmd_802_11_get_log(priv, cmdptr);
+		ret = lbs_cmd_802_11_get_log(priv, cmdptr);
 		break;
 
 	case CMD_802_11_AUTHENTICATE:
-		ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
+		ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
 		break;
 
 	case CMD_802_11_GET_STAT:
-		ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
+		ret = lbs_cmd_802_11_get_stat(priv, cmdptr);
 		break;
 
 	case CMD_802_11_SNMP_MIB:
-		ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
+		ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr,
 					       cmd_action, cmd_oid, pdata_buf);
 		break;
 
 	case CMD_MAC_REG_ACCESS:
 	case CMD_BBP_REG_ACCESS:
 	case CMD_RF_REG_ACCESS:
-		ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
-		break;
-
-	case CMD_802_11_RF_CHANNEL:
-		ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
-						 cmd_action, pdata_buf);
+		ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
 		break;
 
 	case CMD_802_11_RF_TX_POWER:
-		ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
+		ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr,
 						  cmd_action, pdata_buf);
 		break;
 
-	case CMD_802_11_RADIO_CONTROL:
-		ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
-		break;
-
-	case CMD_802_11_DATA_RATE:
-		ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
-		break;
 	case CMD_802_11_RATE_ADAPT_RATESET:
-		ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
+		ret = lbs_cmd_802_11_rate_adapt_rateset(priv,
 							 cmdptr, cmd_action);
 		break;
 
 	case CMD_MAC_MULTICAST_ADR:
-		ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
+		ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
 		break;
 
 	case CMD_802_11_MONITOR_MODE:
-		ret = wlan_cmd_802_11_monitor_mode(priv, cmdptr,
+		ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr,
 				          cmd_action, pdata_buf);
 		break;
 
 	case CMD_802_11_AD_HOC_JOIN:
-		ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
+		ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
 		break;
 
 	case CMD_802_11_RSSI:
-		ret = wlan_cmd_802_11_rssi(priv, cmdptr);
+		ret = lbs_cmd_802_11_rssi(priv, cmdptr);
 		break;
 
 	case CMD_802_11_AD_HOC_STOP:
-		ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
-		break;
-
-	case CMD_802_11_ENABLE_RSN:
-		ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
-				pdata_buf);
+		ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr);
 		break;
 
 	case CMD_802_11_KEY_MATERIAL:
-		ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action,
+		ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action,
 				cmd_oid, pdata_buf);
 		break;
 
@@ -1300,11 +1449,11 @@ int libertas_prepare_and_send_command(wlan_private * priv,
 		break;
 
 	case CMD_802_11_MAC_ADDRESS:
-		ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
+		ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
 		break;
 
 	case CMD_802_11_EEPROM_ACCESS:
-		ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
+		ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr,
 						    cmd_action, pdata_buf);
 		break;
 
@@ -1322,19 +1471,10 @@ int libertas_prepare_and_send_command(wlan_private * priv,
 		goto done;
 
 	case CMD_802_11D_DOMAIN_INFO:
-		ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
+		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr,
 						   cmd_no, cmd_action);
 		break;
 
-	case CMD_802_11_SLEEP_PARAMS:
-		ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
-		break;
-	case CMD_802_11_INACTIVITY_TIMEOUT:
-		ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
-							 cmd_action, pdata_buf);
-		libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
-		break;
-
 	case CMD_802_11_TPC_CFG:
 		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
 		cmdptr->size =
@@ -1361,13 +1501,15 @@ int libertas_prepare_and_send_command(wlan_private * priv,
 
 #define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
 			cmdptr->size =
-			    cpu_to_le16(gpio->header.len + S_DS_GEN +
-					     ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
-			gpio->header.len = cpu_to_le16(gpio->header.len);
+			    cpu_to_le16(le16_to_cpu(gpio->header.len)
+				+ S_DS_GEN
+				+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
+			gpio->header.len = gpio->header.len;
 
 			ret = 0;
 			break;
 		}
+
 	case CMD_802_11_PWR_CFG:
 		cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
 		cmdptr->size =
@@ -1379,19 +1521,11 @@ int libertas_prepare_and_send_command(wlan_private * priv,
 		ret = 0;
 		break;
 	case CMD_BT_ACCESS:
-		ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
+		ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
 		break;
 
 	case CMD_FWT_ACCESS:
-		ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
-		break;
-
-	case CMD_MESH_ACCESS:
-		ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
-		break;
-
-	case CMD_SET_BOOT2_VER:
-		ret = wlan_cmd_set_boot2_ver(priv, cmdptr, cmd_action, pdata_buf);
+		ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
 		break;
 
 	case CMD_GET_TSF:
@@ -1400,6 +1534,9 @@ int libertas_prepare_and_send_command(wlan_private * priv,
 					   S_DS_GEN);
 		ret = 0;
 		break;
+	case CMD_802_11_BEACON_CTRL:
+		ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action);
+		break;
 	default:
 		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
 		ret = -1;
@@ -1409,14 +1546,14 @@ int libertas_prepare_and_send_command(wlan_private * priv,
 	/* return error, since the command preparation failed */
 	if (ret != 0) {
 		lbs_deb_host("PREP_CMD: command preparation failed\n");
-		libertas_cleanup_and_insert_cmd(priv, cmdnode);
+		lbs_cleanup_and_insert_cmd(priv, cmdnode);
 		ret = -1;
 		goto done;
 	}
 
 	cmdnode->cmdwaitqwoken = 0;
 
-	libertas_queue_cmd(adapter, cmdnode, 1);
+	lbs_queue_cmd(priv, cmdnode);
 	wake_up_interruptible(&priv->waitq);
 
 	if (wait_option & CMD_OPTION_WAITFORRSP) {
@@ -1426,67 +1563,60 @@ int libertas_prepare_and_send_command(wlan_private * priv,
 					 cmdnode->cmdwaitqwoken);
 	}
 
-	spin_lock_irqsave(&adapter->driver_lock, flags);
-	if (adapter->cur_cmd_retcode) {
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	if (priv->cur_cmd_retcode) {
 		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
-		       adapter->cur_cmd_retcode);
-		adapter->cur_cmd_retcode = 0;
+		       priv->cur_cmd_retcode);
+		priv->cur_cmd_retcode = 0;
 		ret = -1;
 	}
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 done:
 	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(libertas_prepare_and_send_command);
+EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command);
 
 /**
  *  @brief This function allocates the command buffer and link
  *  it to command free queue.
  *
- *  @param priv		A pointer to wlan_private structure
+ *  @param priv		A pointer to struct lbs_private structure
  *  @return 		0 or -1
  */
-int libertas_allocate_cmd_buffer(wlan_private * priv)
+int lbs_allocate_cmd_buffer(struct lbs_private *priv)
 {
 	int ret = 0;
-	u32 ulbufsize;
+	u32 bufsize;
 	u32 i;
-	struct cmd_ctrl_node *tempcmd_array;
-	u8 *ptempvirtualaddr;
-	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *cmdarray;
 
 	lbs_deb_enter(LBS_DEB_HOST);
 
-	/* Allocate and initialize cmdCtrlNode */
-	ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
-
-	if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) {
+	/* Allocate and initialize the command array */
+	bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
+	if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) {
 		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
 		ret = -1;
 		goto done;
 	}
-	adapter->cmd_array = tempcmd_array;
+	priv->cmd_array = cmdarray;
 
-	/* Allocate and initialize command buffers */
-	ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
-	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
-		if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) {
+	/* Allocate and initialize each command buffer in the command array */
+	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
+		cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
+		if (!cmdarray[i].cmdbuf) {
 			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
 			ret = -1;
 			goto done;
 		}
-
-		/* Update command buffer virtual */
-		tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
 	}
 
-	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
-		init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
-		libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
+	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
+		init_waitqueue_head(&cmdarray[i].cmdwait_q);
+		lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]);
 	}
-
 	ret = 0;
 
 done:
@@ -1497,39 +1627,36 @@ done:
 /**
  *  @brief This function frees the command buffer.
  *
- *  @param priv		A pointer to wlan_private structure
+ *  @param priv		A pointer to struct lbs_private structure
  *  @return 		0 or -1
  */
-int libertas_free_cmd_buffer(wlan_private * priv)
+int lbs_free_cmd_buffer(struct lbs_private *priv)
 {
-	u32 ulbufsize; /* Someone needs to die for this. Slowly and painfully */
+	struct cmd_ctrl_node *cmdarray;
 	unsigned int i;
-	struct cmd_ctrl_node *tempcmd_array;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_HOST);
 
 	/* need to check if cmd array is allocated or not */
-	if (adapter->cmd_array == NULL) {
+	if (priv->cmd_array == NULL) {
 		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
 		goto done;
 	}
 
-	tempcmd_array = adapter->cmd_array;
+	cmdarray = priv->cmd_array;
 
 	/* Release shared memory buffers */
-	ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
-	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
-		if (tempcmd_array[i].bufvirtualaddr) {
-			kfree(tempcmd_array[i].bufvirtualaddr);
-			tempcmd_array[i].bufvirtualaddr = NULL;
+	for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
+		if (cmdarray[i].cmdbuf) {
+			kfree(cmdarray[i].cmdbuf);
+			cmdarray[i].cmdbuf = NULL;
 		}
 	}
 
 	/* Release cmd_ctrl_node */
-	if (adapter->cmd_array) {
-		kfree(adapter->cmd_array);
-		adapter->cmd_array = NULL;
+	if (priv->cmd_array) {
+		kfree(priv->cmd_array);
+		priv->cmd_array = NULL;
 	}
 
 done:
@@ -1541,34 +1668,31 @@ done:
  *  @brief This function gets a free command node if available in
  *  command free queue.
  *
- *  @param priv		A pointer to wlan_private structure
+ *  @param priv		A pointer to struct lbs_private structure
  *  @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
  */
-struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
+static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv)
 {
 	struct cmd_ctrl_node *tempnode;
-	wlan_adapter *adapter = priv->adapter;
 	unsigned long flags;
 
 	lbs_deb_enter(LBS_DEB_HOST);
 
-	if (!adapter)
+	if (!priv)
 		return NULL;
 
-	spin_lock_irqsave(&adapter->driver_lock, flags);
+	spin_lock_irqsave(&priv->driver_lock, flags);
 
-	if (!list_empty(&adapter->cmdfreeq)) {
-		tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
-		list_del((struct list_head *)tempnode);
+	if (!list_empty(&priv->cmdfreeq)) {
+		tempnode = list_first_entry(&priv->cmdfreeq,
+					    struct cmd_ctrl_node, list);
+		list_del(&tempnode->list);
 	} else {
 		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
 		tempnode = NULL;
 	}
 
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
-
-	if (tempnode)
-		cleanup_cmdnode(tempnode);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 	lbs_deb_leave(LBS_DEB_HOST);
 	return tempnode;
@@ -1580,47 +1704,26 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
  *  @param ptempnode	A pointer to cmdCtrlNode structure
  *  @return 		n/a
  */
-static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
-{
-	lbs_deb_enter(LBS_DEB_HOST);
-
-	if (!ptempnode)
-		return;
-	ptempnode->cmdwaitqwoken = 1;
-	wake_up_interruptible(&ptempnode->cmdwait_q);
-	ptempnode->status = 0;
-	ptempnode->cmd_oid = (u32) 0;
-	ptempnode->wait_option = 0;
-	ptempnode->pdata_buf = NULL;
-
-	if (ptempnode->bufvirtualaddr != NULL)
-		memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
-
-	lbs_deb_leave(LBS_DEB_HOST);
-}
 
 /**
  *  @brief This function initializes the command node.
  *
- *  @param priv		A pointer to wlan_private structure
+ *  @param priv		A pointer to struct lbs_private structure
  *  @param ptempnode	A pointer to cmd_ctrl_node structure
- *  @param cmd_oid	cmd oid: treated as sub command
- *  @param wait_option	wait option: wait response or not
  *  @param pdata_buf	A pointer to informaion buffer
  *  @return 		0 or -1
  */
-void libertas_set_cmd_ctrl_node(wlan_private * priv,
-		    struct cmd_ctrl_node *ptempnode,
-		    u32 cmd_oid, u16 wait_option, void *pdata_buf)
+static void lbs_set_cmd_ctrl_node(struct lbs_private *priv,
+				  struct cmd_ctrl_node *ptempnode,
+				  void *pdata_buf)
 {
 	lbs_deb_enter(LBS_DEB_HOST);
 
 	if (!ptempnode)
 		return;
 
-	ptempnode->cmd_oid = cmd_oid;
-	ptempnode->wait_option = wait_option;
-	ptempnode->pdata_buf = pdata_buf;
+	ptempnode->callback = NULL;
+	ptempnode->callback_arg = (unsigned long)pdata_buf;
 
 	lbs_deb_leave(LBS_DEB_HOST);
 }
@@ -1630,60 +1733,58 @@ void libertas_set_cmd_ctrl_node(wlan_private * priv,
  *  pending queue. It will put fimware back to PS mode
  *  if applicable.
  *
- *  @param priv     A pointer to wlan_private structure
+ *  @param priv     A pointer to struct lbs_private structure
  *  @return 	   0 or -1
  */
-int libertas_execute_next_command(wlan_private * priv)
+int lbs_execute_next_command(struct lbs_private *priv)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct cmd_ctrl_node *cmdnode = NULL;
-	struct cmd_ds_command *cmdptr;
+	struct cmd_header *cmd;
 	unsigned long flags;
 	int ret = 0;
 
 	// Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
-	// only caller to us is libertas_thread() and we get even when a
+	// only caller to us is lbs_thread() and we get even when a
 	// data packet is received
 	lbs_deb_enter(LBS_DEB_THREAD);
 
-	spin_lock_irqsave(&adapter->driver_lock, flags);
+	spin_lock_irqsave(&priv->driver_lock, flags);
 
-	if (adapter->cur_cmd) {
+	if (priv->cur_cmd) {
 		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 		ret = -1;
 		goto done;
 	}
 
-	if (!list_empty(&adapter->cmdpendingq)) {
-		cmdnode = (struct cmd_ctrl_node *)
-		    adapter->cmdpendingq.next;
+	if (!list_empty(&priv->cmdpendingq)) {
+		cmdnode = list_first_entry(&priv->cmdpendingq,
+					   struct cmd_ctrl_node, list);
 	}
 
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 	if (cmdnode) {
-		cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+		cmd = cmdnode->cmdbuf;
 
-		if (is_command_allowed_in_ps(cmdptr->command)) {
-			if ((adapter->psstate == PS_STATE_SLEEP) ||
-			    (adapter->psstate == PS_STATE_PRE_SLEEP)) {
+		if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) {
+			if ((priv->psstate == PS_STATE_SLEEP) ||
+			    (priv->psstate == PS_STATE_PRE_SLEEP)) {
 				lbs_deb_host(
 				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
-				       le16_to_cpu(cmdptr->command),
-				       adapter->psstate);
+				       le16_to_cpu(cmd->command),
+				       priv->psstate);
 				ret = -1;
 				goto done;
 			}
 			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
-			       "0x%04x in psstate %d\n",
-				    le16_to_cpu(cmdptr->command),
-				    adapter->psstate);
-		} else if (adapter->psstate != PS_STATE_FULL_POWER) {
+				     "0x%04x in psstate %d\n",
+				     le16_to_cpu(cmd->command), priv->psstate);
+		} else if (priv->psstate != PS_STATE_FULL_POWER) {
 			/*
 			 * 1. Non-PS command:
 			 * Queue it. set needtowakeup to TRUE if current state
-			 * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS.
+			 * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS.
 			 * 2. PS command but not Exit_PS:
 			 * Ignore it.
 			 * 3. PS command Exit_PS:
@@ -1691,18 +1792,17 @@ int libertas_execute_next_command(wlan_private * priv)
 			 * otherwise send this command down to firmware
 			 * immediately.
 			 */
-			if (cmdptr->command !=
-			    cpu_to_le16(CMD_802_11_PS_MODE)) {
+			if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) {
 				/*  Prepare to send Exit PS,
 				 *  this non PS command will be sent later */
-				if ((adapter->psstate == PS_STATE_SLEEP)
-				    || (adapter->psstate == PS_STATE_PRE_SLEEP)
+				if ((priv->psstate == PS_STATE_SLEEP)
+				    || (priv->psstate == PS_STATE_PRE_SLEEP)
 				    ) {
 					/* w/ new scheme, it will not reach here.
 					   since it is blocked in main_thread. */
-					adapter->needtowakeup = 1;
+					priv->needtowakeup = 1;
 				} else
-					libertas_ps_wakeup(priv, 0);
+					lbs_ps_wakeup(priv, 0);
 
 				ret = 0;
 				goto done;
@@ -1711,8 +1811,7 @@ int libertas_execute_next_command(wlan_private * priv)
 				 * PS command. Ignore it if it is not Exit_PS.
 				 * otherwise send it down immediately.
 				 */
-				struct cmd_ds_802_11_ps_mode *psm =
-				    &cmdptr->params.psmode;
+				struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1];
 
 				lbs_deb_host(
 				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
@@ -1721,20 +1820,24 @@ int libertas_execute_next_command(wlan_private * priv)
 				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
 					lbs_deb_host(
 					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
-					list_del((struct list_head *)cmdnode);
-					libertas_cleanup_and_insert_cmd(priv, cmdnode);
+					list_del(&cmdnode->list);
+					spin_lock_irqsave(&priv->driver_lock, flags);
+					lbs_complete_command(priv, cmdnode, 0);
+					spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 					ret = 0;
 					goto done;
 				}
 
-				if ((adapter->psstate == PS_STATE_SLEEP) ||
-				    (adapter->psstate == PS_STATE_PRE_SLEEP)) {
+				if ((priv->psstate == PS_STATE_SLEEP) ||
+				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
 					lbs_deb_host(
 					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
-					list_del((struct list_head *)cmdnode);
-					libertas_cleanup_and_insert_cmd(priv, cmdnode);
-					adapter->needtowakeup = 1;
+					list_del(&cmdnode->list);
+					spin_lock_irqsave(&priv->driver_lock, flags);
+					lbs_complete_command(priv, cmdnode, 0);
+					spin_unlock_irqrestore(&priv->driver_lock, flags);
+					priv->needtowakeup = 1;
 
 					ret = 0;
 					goto done;
@@ -1744,33 +1847,34 @@ int libertas_execute_next_command(wlan_private * priv)
 				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
 			}
 		}
-		list_del((struct list_head *)cmdnode);
+		list_del(&cmdnode->list);
 		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
-			    le16_to_cpu(cmdptr->command));
-		DownloadcommandToStation(priv, cmdnode);
+			    le16_to_cpu(cmd->command));
+		lbs_submit_command(priv, cmdnode);
 	} else {
 		/*
 		 * check if in power save mode, if yes, put the device back
 		 * to PS mode
 		 */
-		if ((adapter->psmode != WLAN802_11POWERMODECAM) &&
-		    (adapter->psstate == PS_STATE_FULL_POWER) &&
-		    (adapter->connect_status == LIBERTAS_CONNECTED)) {
-			if (adapter->secinfo.WPAenabled ||
-			    adapter->secinfo.WPA2enabled) {
+		if ((priv->psmode != LBS802_11POWERMODECAM) &&
+		    (priv->psstate == PS_STATE_FULL_POWER) &&
+		    ((priv->connect_status == LBS_CONNECTED) ||
+		    (priv->mesh_connect_status == LBS_CONNECTED))) {
+			if (priv->secinfo.WPAenabled ||
+			    priv->secinfo.WPA2enabled) {
 				/* check for valid WPA group keys */
-				if (adapter->wpa_mcast_key.len ||
-				    adapter->wpa_unicast_key.len) {
+				if (priv->wpa_mcast_key.len ||
+				    priv->wpa_unicast_key.len) {
 					lbs_deb_host(
 					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
 					       " go back to PS_SLEEP");
-					libertas_ps_sleep(priv, 0);
+					lbs_ps_sleep(priv, 0);
 				}
 			} else {
 				lbs_deb_host(
 				       "EXEC_NEXT_CMD: cmdpendingq empty, "
 				       "go back to PS_SLEEP");
-				libertas_ps_sleep(priv, 0);
+				lbs_ps_sleep(priv, 0);
 			}
 		}
 	}
@@ -1781,7 +1885,7 @@ done:
 	return ret;
 }
 
-void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
+void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)
 {
 	union iwreq_data iwrq;
 	u8 buf[50];
@@ -1805,10 +1909,9 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
 	lbs_deb_leave(LBS_DEB_WEXT);
 }
 
-static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
+static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size)
 {
 	unsigned long flags;
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_HOST);
@@ -1819,26 +1922,25 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
 	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
 
 	ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
-	priv->dnld_sent = DNLD_RES_RECEIVED;
 
-	spin_lock_irqsave(&adapter->driver_lock, flags);
-	if (adapter->intcounter || adapter->currenttxskb)
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	if (priv->intcounter || priv->currenttxskb)
 		lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
-		       adapter->intcounter, adapter->currenttxskb);
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		       priv->intcounter, priv->currenttxskb);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 	if (ret) {
 		lbs_pr_alert(
 		       "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
 	} else {
-		spin_lock_irqsave(&adapter->driver_lock, flags);
-		if (!adapter->intcounter) {
-			adapter->psstate = PS_STATE_SLEEP;
+		spin_lock_irqsave(&priv->driver_lock, flags);
+		if (!priv->intcounter) {
+			priv->psstate = PS_STATE_SLEEP;
 		} else {
 			lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
-			       adapter->intcounter);
+			       priv->intcounter);
 		}
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 		lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
 	}
@@ -1847,7 +1949,7 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
 	return ret;
 }
 
-void libertas_ps_sleep(wlan_private * priv, int wait_option)
+void lbs_ps_sleep(struct lbs_private *priv, int wait_option)
 {
 	lbs_deb_enter(LBS_DEB_HOST);
 
@@ -1856,7 +1958,7 @@ void libertas_ps_sleep(wlan_private * priv, int wait_option)
 	 * Remove this check if it is to be supported in IBSS mode also
 	 */
 
-	libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
+	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
 			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
 
 	lbs_deb_leave(LBS_DEB_HOST);
@@ -1865,19 +1967,19 @@ void libertas_ps_sleep(wlan_private * priv, int wait_option)
 /**
  *  @brief This function sends Exit_PS command to firmware.
  *
- *  @param priv    	A pointer to wlan_private structure
+ *  @param priv    	A pointer to struct lbs_private structure
  *  @param wait_option	wait response or not
  *  @return 	   	n/a
  */
-void libertas_ps_wakeup(wlan_private * priv, int wait_option)
+void lbs_ps_wakeup(struct lbs_private *priv, int wait_option)
 {
 	__le32 Localpsmode;
 
 	lbs_deb_enter(LBS_DEB_HOST);
 
-	Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM);
+	Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
 
-	libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
+	lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
 			      CMD_SUBCMD_EXIT_PS,
 			      wait_option, 0, &Localpsmode);
 
@@ -1888,37 +1990,36 @@ void libertas_ps_wakeup(wlan_private * priv, int wait_option)
  *  @brief This function checks condition and prepares to
  *  send sleep confirm command to firmware if ok.
  *
- *  @param priv    	A pointer to wlan_private structure
+ *  @param priv    	A pointer to struct lbs_private structure
  *  @param psmode  	Power Saving mode
  *  @return 	   	n/a
  */
-void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode)
+void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode)
 {
 	unsigned long flags =0;
-	wlan_adapter *adapter = priv->adapter;
 	u8 allowed = 1;
 
 	lbs_deb_enter(LBS_DEB_HOST);
 
 	if (priv->dnld_sent) {
 		allowed = 0;
-		lbs_deb_host("dnld_sent was set");
+		lbs_deb_host("dnld_sent was set\n");
 	}
 
-	spin_lock_irqsave(&adapter->driver_lock, flags);
-	if (adapter->cur_cmd) {
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	if (priv->cur_cmd) {
 		allowed = 0;
-		lbs_deb_host("cur_cmd was set");
+		lbs_deb_host("cur_cmd was set\n");
 	}
-	if (adapter->intcounter > 0) {
+	if (priv->intcounter > 0) {
 		allowed = 0;
-		lbs_deb_host("intcounter %d", adapter->intcounter);
+		lbs_deb_host("intcounter %d\n", priv->intcounter);
 	}
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 	if (allowed) {
-		lbs_deb_host("sending libertas_ps_confirm_sleep\n");
-		sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
+		lbs_deb_host("sending lbs_ps_confirm_sleep\n");
+		sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep,
 				 sizeof(struct PS_CMD_ConfirmSleep));
 	} else {
 		lbs_deb_host("sleep confirm has been delayed\n");
@@ -1926,3 +2027,123 @@ void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode)
 
 	lbs_deb_leave(LBS_DEB_HOST);
 }
+
+
+/**
+ *  @brief Simple callback that copies response back into command
+ *
+ *  @param priv    	A pointer to struct lbs_private structure
+ *  @param extra  	A pointer to the original command structure for which
+ *                      'resp' is a response
+ *  @param resp         A pointer to the command response
+ *
+ *  @return 	   	0 on success, error on failure
+ */
+int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
+		     struct cmd_header *resp)
+{
+	struct cmd_header *buf = (void *)extra;
+	uint16_t copy_len;
+
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
+	lbs_deb_cmd("Copying back %u bytes; command response was %u bytes, "
+		    "copy back buffer was %u bytes\n", copy_len,
+		    le16_to_cpu(resp->size), le16_to_cpu(buf->size));
+	memcpy(buf, resp, copy_len);
+
+	lbs_deb_leave(LBS_DEB_CMD);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
+
+struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command,
+				      struct cmd_header *in_cmd, int in_cmd_size,
+				      int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+				      unsigned long callback_arg)
+{
+	struct cmd_ctrl_node *cmdnode;
+
+	lbs_deb_enter(LBS_DEB_HOST);
+
+	if (priv->surpriseremoved) {
+		lbs_deb_host("PREP_CMD: card removed\n");
+		cmdnode = ERR_PTR(-ENOENT);
+		goto done;
+	}
+
+	cmdnode = lbs_get_cmd_ctrl_node(priv);
+	if (cmdnode == NULL) {
+		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
+
+		/* Wake up main thread to execute next command */
+		wake_up_interruptible(&priv->waitq);
+		cmdnode = ERR_PTR(-ENOBUFS);
+		goto done;
+	}
+
+	cmdnode->callback = callback;
+	cmdnode->callback_arg = callback_arg;
+
+	/* Copy the incoming command to the buffer */
+	memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
+
+	/* Set sequence number, clean result, move to buffer */
+	priv->seqnum++;
+	cmdnode->cmdbuf->command = cpu_to_le16(command);
+	cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
+	cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
+	cmdnode->cmdbuf->result  = 0;
+
+	lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
+
+	/* here was the big old switch() statement, which is now obsolete,
+	 * because the caller of lbs_cmd() sets up all of *cmd for us. */
+
+	cmdnode->cmdwaitqwoken = 0;
+	lbs_queue_cmd(priv, cmdnode);
+	wake_up_interruptible(&priv->waitq);
+
+ done:
+	lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode);
+	return cmdnode;
+}
+
+int __lbs_cmd(struct lbs_private *priv, uint16_t command,
+	      struct cmd_header *in_cmd, int in_cmd_size,
+	      int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+	      unsigned long callback_arg)
+{
+	struct cmd_ctrl_node *cmdnode;
+	unsigned long flags;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_HOST);
+
+	cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size,
+				  callback, callback_arg);
+	if (IS_ERR(cmdnode)) {
+		ret = PTR_ERR(cmdnode);
+		goto done;
+	}
+
+	might_sleep();
+	wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken);
+
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	ret = cmdnode->result;
+	if (ret)
+		lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
+			    command, ret);
+
+	__lbs_cleanup_and_insert_cmd(priv, cmdnode);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+done:
+	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(__lbs_cmd);
+
+
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
new file mode 100644
index 000000000000..b9ab85cc7913
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2007, Red Hat, Inc. */
+
+#ifndef _LBS_CMD_H_
+#define _LBS_CMD_H_
+
+#include "hostcmd.h"
+#include "dev.h"
+
+/* lbs_cmd() infers the size of the buffer to copy data back into, from
+   the size of the target of the pointer. Since the command to be sent 
+   may often be smaller, that size is set in cmd->size by the caller.*/
+#define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg)	({		\
+	uint16_t __sz = le16_to_cpu((cmd)->hdr.size);		\
+	(cmd)->hdr.size = cpu_to_le16(sizeof(*(cmd)));		\
+	__lbs_cmd(priv, cmdnr, &(cmd)->hdr, __sz, cb, cb_arg);	\
+})
+
+#define lbs_cmd_with_response(priv, cmdnr, cmd)	\
+	lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd))
+
+/* __lbs_cmd() will free the cmdnode and return success/failure.
+   __lbs_cmd_async() requires that the callback free the cmdnode */
+struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command,
+				      struct cmd_header *in_cmd, int in_cmd_size,
+				      int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+				      unsigned long callback_arg);
+int __lbs_cmd(struct lbs_private *priv, uint16_t command,
+	      struct cmd_header *in_cmd, int in_cmd_size,
+	      int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
+	      unsigned long callback_arg);
+
+int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
+		     struct cmd_header *resp);
+
+int lbs_update_hw_spec(struct lbs_private *priv);
+
+int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
+		    struct cmd_ds_mesh_access *cmd);
+
+int lbs_get_data_rate(struct lbs_private *priv);
+int lbs_set_data_rate(struct lbs_private *priv, u8 rate);
+
+int lbs_get_channel(struct lbs_private *priv);
+int lbs_set_channel(struct lbs_private *priv, u8 channel);
+
+int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan);
+
+int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria);
+int lbs_suspend(struct lbs_private *priv);
+int lbs_resume(struct lbs_private *priv);
+
+int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv,
+				      uint16_t cmd_action, uint16_t *timeout);
+int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
+				struct sleep_params *sp);
+int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
+			   struct assoc_request *assoc);
+int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action,
+			      uint16_t *enable);
+
+#endif /* _LBS_CMD_H */
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 8f90892ea22e..159216a91903 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -20,18 +20,17 @@
  *  reports disconnect to upper layer, clean tx/rx packets,
  *  reset link state etc.
  *
- *  @param priv    A pointer to wlan_private structure
+ *  @param priv    A pointer to struct lbs_private structure
  *  @return 	   n/a
  */
-void libertas_mac_event_disconnected(wlan_private * priv)
+void lbs_mac_event_disconnected(struct lbs_private *priv)
 {
-	wlan_adapter *adapter = priv->adapter;
 	union iwreq_data wrqu;
 
-	if (adapter->connect_status != LIBERTAS_CONNECTED)
+	if (priv->connect_status != LBS_CONNECTED)
 		return;
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_ASSOC);
 
 	memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -44,40 +43,36 @@ void libertas_mac_event_disconnected(wlan_private * priv)
 	msleep_interruptible(1000);
 	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
 
-	/* Free Tx and Rx packets */
-	kfree_skb(priv->adapter->currenttxskb);
-	priv->adapter->currenttxskb = NULL;
-
 	/* report disconnect to upper layer */
 	netif_stop_queue(priv->dev);
 	netif_carrier_off(priv->dev);
 
+	/* Free Tx and Rx packets */
+	kfree_skb(priv->currenttxskb);
+	priv->currenttxskb = NULL;
+	priv->tx_pending_len = 0;
+
 	/* reset SNR/NF/RSSI values */
-	memset(adapter->SNR, 0x00, sizeof(adapter->SNR));
-	memset(adapter->NF, 0x00, sizeof(adapter->NF));
-	memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI));
-	memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
-	memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
-	adapter->nextSNRNF = 0;
-	adapter->numSNRNF = 0;
-	lbs_deb_cmd("current SSID '%s', length %u\n",
-	            escape_essid(adapter->curbssparams.ssid,
-	                         adapter->curbssparams.ssid_len),
-	            adapter->curbssparams.ssid_len);
-
-	adapter->connect_status = LIBERTAS_DISCONNECTED;
+	memset(priv->SNR, 0x00, sizeof(priv->SNR));
+	memset(priv->NF, 0x00, sizeof(priv->NF));
+	memset(priv->RSSI, 0x00, sizeof(priv->RSSI));
+	memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
+	memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
+	priv->nextSNRNF = 0;
+	priv->numSNRNF = 0;
+	priv->connect_status = LBS_DISCONNECTED;
 
 	/* Clear out associated SSID and BSSID since connection is
 	 * no longer valid.
 	 */
-	memset(&adapter->curbssparams.bssid, 0, ETH_ALEN);
-	memset(&adapter->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
-	adapter->curbssparams.ssid_len = 0;
+	memset(&priv->curbssparams.bssid, 0, ETH_ALEN);
+	memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE);
+	priv->curbssparams.ssid_len = 0;
 
-	if (adapter->psstate != PS_STATE_FULL_POWER) {
+	if (priv->psstate != PS_STATE_FULL_POWER) {
 		/* make firmware to exit PS mode */
 		lbs_deb_cmd("disconnected, so exit PS mode\n");
-		libertas_ps_wakeup(priv, 0);
+		lbs_ps_wakeup(priv, 0);
 	}
 	lbs_deb_leave(LBS_DEB_CMD);
 }
@@ -85,11 +80,11 @@ void libertas_mac_event_disconnected(wlan_private * priv)
 /**
  *  @brief This function handles MIC failure event.
  *
- *  @param priv    A pointer to wlan_private structure
+ *  @param priv    A pointer to struct lbs_private structure
  *  @para  event   the event id
  *  @return 	   n/a
  */
-static void handle_mic_failureevent(wlan_private * priv, u32 event)
+static void handle_mic_failureevent(struct lbs_private *priv, u32 event)
 {
 	char buf[50];
 
@@ -104,15 +99,14 @@ static void handle_mic_failureevent(wlan_private * priv, u32 event)
 		strcat(buf, "multicast ");
 	}
 
-	libertas_send_iwevcustom_event(priv, buf);
+	lbs_send_iwevcustom_event(priv, buf);
 	lbs_deb_leave(LBS_DEB_CMD);
 }
 
-static int wlan_ret_reg_access(wlan_private * priv,
+static int lbs_ret_reg_access(struct lbs_private *priv,
 			       u16 type, struct cmd_ds_command *resp)
 {
 	int ret = 0;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
@@ -121,8 +115,8 @@ static int wlan_ret_reg_access(wlan_private * priv,
 		{
 			struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
 
-			adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
-			adapter->offsetvalue.value = le32_to_cpu(reg->value);
+			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
+			priv->offsetvalue.value = le32_to_cpu(reg->value);
 			break;
 		}
 
@@ -130,8 +124,8 @@ static int wlan_ret_reg_access(wlan_private * priv,
 		{
 			struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
 
-			adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
-			adapter->offsetvalue.value = reg->value;
+			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
+			priv->offsetvalue.value = reg->value;
 			break;
 		}
 
@@ -139,8 +133,8 @@ static int wlan_ret_reg_access(wlan_private * priv,
 		{
 			struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
 
-			adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
-			adapter->offsetvalue.value = reg->value;
+			priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset);
+			priv->offsetvalue.value = reg->value;
 			break;
 		}
 
@@ -152,112 +146,23 @@ static int wlan_ret_reg_access(wlan_private * priv,
 	return ret;
 }
 
-static int wlan_ret_get_hw_spec(wlan_private * priv,
-				struct cmd_ds_command *resp)
-{
-	u32 i;
-	struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
-	wlan_adapter *adapter = priv->adapter;
-	int ret = 0;
-	DECLARE_MAC_BUF(mac);
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);
-
-	memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4);
-
-	lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
-		    adapter->fwreleasenumber[2], adapter->fwreleasenumber[1],
-		    adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]);
-	lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
-		    print_mac(mac, hwspec->permanentaddr));
-	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
-	       hwspec->hwifversion, hwspec->version);
-
-	/* Clamp region code to 8-bit since FW spec indicates that it should
-	 * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
-	 * returns non-zero high 8 bits here.
-	 */
-	adapter->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF;
-
-	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
-		/* use the region code to search for the index */
-		if (adapter->regioncode == libertas_region_code_to_index[i]) {
-			break;
-		}
-	}
-
-	/* if it's unidentified region code, use the default (USA) */
-	if (i >= MRVDRV_MAX_REGION_CODE) {
-		adapter->regioncode = 0x10;
-		lbs_pr_info("unidentified region code; using the default (USA)\n");
-	}
-
-	if (adapter->current_addr[0] == 0xff)
-		memmove(adapter->current_addr, hwspec->permanentaddr, ETH_ALEN);
-
-	memcpy(priv->dev->dev_addr, adapter->current_addr, ETH_ALEN);
-	if (priv->mesh_dev)
-		memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
-
-	if (libertas_set_regiontable(priv, adapter->regioncode, 0)) {
-		ret = -1;
-		goto done;
-	}
-
-	if (libertas_set_universaltable(priv, 0)) {
-		ret = -1;
-		goto done;
-	}
-
-done:
-	lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
-	return ret;
-}
-
-static int wlan_ret_802_11_sleep_params(wlan_private * priv,
-					struct cmd_ds_command *resp)
-{
-	struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
-	wlan_adapter *adapter = priv->adapter;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
-		    "extsleepclk 0x%x\n", le16_to_cpu(sp->error),
-		    le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
-		    sp->calcontrol, sp->externalsleepclk);
-
-	adapter->sp.sp_error = le16_to_cpu(sp->error);
-	adapter->sp.sp_offset = le16_to_cpu(sp->offset);
-	adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
-	adapter->sp.sp_calcontrol = sp->calcontrol;
-	adapter->sp.sp_extsleepclk = sp->externalsleepclk;
-	adapter->sp.sp_reserved = le16_to_cpu(sp->reserved);
-
-	lbs_deb_enter(LBS_DEB_CMD);
-	return 0;
-}
-
-static int wlan_ret_802_11_stat(wlan_private * priv,
+static int lbs_ret_802_11_stat(struct lbs_private *priv,
 				struct cmd_ds_command *resp)
 {
 	lbs_deb_enter(LBS_DEB_CMD);
-/*	currently adapter->wlan802_11Stat is unused
+/*	currently priv->wlan802_11Stat is unused
 
 	struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
-	wlan_adapter *adapter = priv->adapter;
 
 	// TODO Convert it to Big endian befor copy
-	memcpy(&adapter->wlan802_11Stat,
+	memcpy(&priv->wlan802_11Stat,
 	       p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
 */
 	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
-static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
+static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv,
 				    struct cmd_ds_command *resp)
 {
 	struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
@@ -273,22 +178,22 @@ static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
 	if (querytype == CMD_ACT_GET) {
 		switch (oid) {
 		case FRAGTHRESH_I:
-			priv->adapter->fragthsd =
+			priv->fragthsd =
 				le16_to_cpu(*((__le16 *)(smib->value)));
 			lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
-				    priv->adapter->fragthsd);
+				    priv->fragthsd);
 			break;
 		case RTSTHRESH_I:
-			priv->adapter->rtsthsd =
+			priv->rtsthsd =
 				le16_to_cpu(*((__le16 *)(smib->value)));
 			lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
-				    priv->adapter->rtsthsd);
+				    priv->rtsthsd);
 			break;
 		case SHORT_RETRYLIM_I:
-			priv->adapter->txretrycount =
+			priv->txretrycount =
 				le16_to_cpu(*((__le16 *)(smib->value)));
 			lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
-				    priv->adapter->rtsthsd);
+				    priv->rtsthsd);
 			break;
 		default:
 			break;
@@ -299,12 +204,11 @@ static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_ret_802_11_key_material(wlan_private * priv,
+static int lbs_ret_802_11_key_material(struct lbs_private *priv,
 					struct cmd_ds_command *resp)
 {
 	struct cmd_ds_802_11_key_material *pkeymaterial =
 	    &resp->params.keymaterial;
-	wlan_adapter *adapter = priv->adapter;
 	u16 action = le16_to_cpu(pkeymaterial->action);
 
 	lbs_deb_enter(LBS_DEB_CMD);
@@ -332,9 +236,9 @@ static int wlan_ret_802_11_key_material(wlan_private * priv,
 				break;
 
 			if (key_flags & KEY_INFO_WPA_UNICAST)
-				pkey = &adapter->wpa_unicast_key;
+				pkey = &priv->wpa_unicast_key;
 			else if (key_flags & KEY_INFO_WPA_MCAST)
-				pkey = &adapter->wpa_mcast_key;
+				pkey = &priv->wpa_mcast_key;
 			else
 				break;
 
@@ -355,134 +259,85 @@ static int wlan_ret_802_11_key_material(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_ret_802_11_mac_address(wlan_private * priv,
+static int lbs_ret_802_11_mac_address(struct lbs_private *priv,
 				       struct cmd_ds_command *resp)
 {
 	struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN);
+	memcpy(priv->current_addr, macadd->macadd, ETH_ALEN);
 
 	lbs_deb_enter(LBS_DEB_CMD);
 	return 0;
 }
 
-static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
+static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv,
 				       struct cmd_ds_command *resp)
 {
 	struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
+	priv->txpowerlevel = le16_to_cpu(rtp->currentlevel);
 
-	lbs_deb_cmd("TX power currently %d\n", adapter->txpowerlevel);
+	lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel);
 
 	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
-static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
+static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv,
 					      struct cmd_ds_command *resp)
 {
 	struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
 	if (rates->action == CMD_ACT_GET) {
-		adapter->enablehwauto = le16_to_cpu(rates->enablehwauto);
-		adapter->ratebitmap = le16_to_cpu(rates->bitmap);
+		priv->enablehwauto = le16_to_cpu(rates->enablehwauto);
+		priv->ratebitmap = le16_to_cpu(rates->bitmap);
 	}
 
 	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
-static int wlan_ret_802_11_data_rate(wlan_private * priv,
-				     struct cmd_ds_command *resp)
-{
-	struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
-	wlan_adapter *adapter = priv->adapter;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate,
-		sizeof(struct cmd_ds_802_11_data_rate));
-
-	/* FIXME: get actual rates FW can do if this command actually returns
-	 * all data rates supported.
-	 */
-	adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]);
-	lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate);
-
-	lbs_deb_leave(LBS_DEB_CMD);
-	return 0;
-}
-
-static int wlan_ret_802_11_rf_channel(wlan_private * priv,
-				      struct cmd_ds_command *resp)
-{
-	struct cmd_ds_802_11_rf_channel *rfchannel = &resp->params.rfchannel;
-	wlan_adapter *adapter = priv->adapter;
-	u16 action = le16_to_cpu(rfchannel->action);
-	u16 newchannel = le16_to_cpu(rfchannel->currentchannel);
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	if (action == CMD_OPT_802_11_RF_CHANNEL_GET
-	    && adapter->curbssparams.channel != newchannel) {
-		lbs_deb_cmd("channel switch from %d to %d\n",
-		       adapter->curbssparams.channel, newchannel);
-
-		/* Update the channel again */
-		adapter->curbssparams.channel = newchannel;
-	}
-
-	lbs_deb_enter(LBS_DEB_CMD);
-	return 0;
-}
-
-static int wlan_ret_802_11_rssi(wlan_private * priv,
+static int lbs_ret_802_11_rssi(struct lbs_private *priv,
 				struct cmd_ds_command *resp)
 {
 	struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
 	/* store the non average value */
-	adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
-	adapter->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
+	priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
+	priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
 
-	adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
-	adapter->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
+	priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
+	priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
 
-	adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
-	    CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
-		     adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+	priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
+	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
+		     priv->NF[TYPE_BEACON][TYPE_NOAVG]);
 
-	adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
-	    CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
-		     adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
+	priv->RSSI[TYPE_BEACON][TYPE_AVG] =
+	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
+		     priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
 
 	lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
-	       adapter->RSSI[TYPE_BEACON][TYPE_NOAVG],
-	       adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
+	       priv->RSSI[TYPE_BEACON][TYPE_NOAVG],
+	       priv->RSSI[TYPE_BEACON][TYPE_AVG]);
 
 	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
-static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
+static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv,
 				  struct cmd_ds_command *resp)
 {
-	wlan_adapter *adapter = priv->adapter;
-	struct wlan_ioctl_regrdwr *pbuf;
-	pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
+	struct lbs_ioctl_regrdwr *pbuf;
+	pbuf = (struct lbs_ioctl_regrdwr *) priv->prdeeprom;
 
 	lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
 	       le16_to_cpu(resp->params.rdeeprom.bytecount));
@@ -503,46 +358,45 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
 	return 0;
 }
 
-static int wlan_ret_get_log(wlan_private * priv,
+static int lbs_ret_get_log(struct lbs_private *priv,
 			    struct cmd_ds_command *resp)
 {
 	struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
 	/* Stored little-endian */
-	memcpy(&adapter->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
+	memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
 
 	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
-static int libertas_ret_802_11_enable_rsn(wlan_private * priv,
-                                          struct cmd_ds_command *resp)
+static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv,
+					struct cmd_ds_command *resp)
 {
-	struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn;
-	wlan_adapter *adapter = priv->adapter;
-	u32 * pdata_buf = adapter->cur_cmd->pdata_buf;
+	struct cmd_ds_802_11_beacon_control *bcn_ctrl =
+	    &resp->params.bcn_ctrl;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
-		if (pdata_buf)
-			*pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
+	if (bcn_ctrl->action == CMD_ACT_GET) {
+		priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable);
+		priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period);
 	}
 
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_CMD);
 	return 0;
 }
 
-static inline int handle_cmd_response(u16 respcmd,
-				      struct cmd_ds_command *resp,
-				      wlan_private *priv)
+static inline int handle_cmd_response(struct lbs_private *priv,
+				      unsigned long dummy,
+				      struct cmd_header *cmd_response)
 {
+	struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response;
 	int ret = 0;
 	unsigned long flags;
-	wlan_adapter *adapter = priv->adapter;
+	uint16_t respcmd = le16_to_cpu(resp->command);
 
 	lbs_deb_enter(LBS_DEB_HOST);
 
@@ -550,218 +404,213 @@ static inline int handle_cmd_response(u16 respcmd,
 	case CMD_RET(CMD_MAC_REG_ACCESS):
 	case CMD_RET(CMD_BBP_REG_ACCESS):
 	case CMD_RET(CMD_RF_REG_ACCESS):
-		ret = wlan_ret_reg_access(priv, respcmd, resp);
-		break;
-
-	case CMD_RET(CMD_GET_HW_SPEC):
-		ret = wlan_ret_get_hw_spec(priv, resp);
+		ret = lbs_ret_reg_access(priv, respcmd, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_SCAN):
-		ret = libertas_ret_80211_scan(priv, resp);
+		ret = lbs_ret_80211_scan(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_GET_LOG):
-		ret = wlan_ret_get_log(priv, resp);
+		ret = lbs_ret_get_log(priv, resp);
 		break;
 
 	case CMD_RET_802_11_ASSOCIATE:
 	case CMD_RET(CMD_802_11_ASSOCIATE):
 	case CMD_RET(CMD_802_11_REASSOCIATE):
-		ret = libertas_ret_80211_associate(priv, resp);
+		ret = lbs_ret_80211_associate(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_DISASSOCIATE):
 	case CMD_RET(CMD_802_11_DEAUTHENTICATE):
-		ret = libertas_ret_80211_disassociate(priv, resp);
+		ret = lbs_ret_80211_disassociate(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_AD_HOC_START):
 	case CMD_RET(CMD_802_11_AD_HOC_JOIN):
-		ret = libertas_ret_80211_ad_hoc_start(priv, resp);
+		ret = lbs_ret_80211_ad_hoc_start(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_GET_STAT):
-		ret = wlan_ret_802_11_stat(priv, resp);
+		ret = lbs_ret_802_11_stat(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_SNMP_MIB):
-		ret = wlan_ret_802_11_snmp_mib(priv, resp);
+		ret = lbs_ret_802_11_snmp_mib(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_RF_TX_POWER):
-		ret = wlan_ret_802_11_rf_tx_power(priv, resp);
+		ret = lbs_ret_802_11_rf_tx_power(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_SET_AFC):
 	case CMD_RET(CMD_802_11_GET_AFC):
-		spin_lock_irqsave(&adapter->driver_lock, flags);
-		memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc,
+		spin_lock_irqsave(&priv->driver_lock, flags);
+		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc,
 			sizeof(struct cmd_ds_802_11_afc));
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 		break;
 
 	case CMD_RET(CMD_MAC_MULTICAST_ADR):
 	case CMD_RET(CMD_MAC_CONTROL):
-	case CMD_RET(CMD_802_11_SET_WEP):
 	case CMD_RET(CMD_802_11_RESET):
 	case CMD_RET(CMD_802_11_AUTHENTICATE):
-	case CMD_RET(CMD_802_11_RADIO_CONTROL):
 	case CMD_RET(CMD_802_11_BEACON_STOP):
 		break;
 
-	case CMD_RET(CMD_802_11_ENABLE_RSN):
-		ret = libertas_ret_802_11_enable_rsn(priv, resp);
-		break;
-
-	case CMD_RET(CMD_802_11_DATA_RATE):
-		ret = wlan_ret_802_11_data_rate(priv, resp);
-		break;
 	case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
-		ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
-		break;
-	case CMD_RET(CMD_802_11_RF_CHANNEL):
-		ret = wlan_ret_802_11_rf_channel(priv, resp);
+		ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_RSSI):
-		ret = wlan_ret_802_11_rssi(priv, resp);
+		ret = lbs_ret_802_11_rssi(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_MAC_ADDRESS):
-		ret = wlan_ret_802_11_mac_address(priv, resp);
+		ret = lbs_ret_802_11_mac_address(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_AD_HOC_STOP):
-		ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
+		ret = lbs_ret_80211_ad_hoc_stop(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_KEY_MATERIAL):
-		ret = wlan_ret_802_11_key_material(priv, resp);
+		ret = lbs_ret_802_11_key_material(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_EEPROM_ACCESS):
-		ret = wlan_ret_802_11_eeprom_access(priv, resp);
+		ret = lbs_ret_802_11_eeprom_access(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11D_DOMAIN_INFO):
-		ret = libertas_ret_802_11d_domain_info(priv, resp);
-		break;
-
-	case CMD_RET(CMD_802_11_SLEEP_PARAMS):
-		ret = wlan_ret_802_11_sleep_params(priv, resp);
-		break;
-	case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
-		spin_lock_irqsave(&adapter->driver_lock, flags);
-		*((u16 *) adapter->cur_cmd->pdata_buf) =
-		    le16_to_cpu(resp->params.inactivity_timeout.timeout);
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		ret = lbs_ret_802_11d_domain_info(priv, resp);
 		break;
 
 	case CMD_RET(CMD_802_11_TPC_CFG):
-		spin_lock_irqsave(&adapter->driver_lock, flags);
-		memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg,
+		spin_lock_irqsave(&priv->driver_lock, flags);
+		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
 			sizeof(struct cmd_ds_802_11_tpc_cfg));
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 		break;
 	case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
-		spin_lock_irqsave(&adapter->driver_lock, flags);
-		memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio,
+		spin_lock_irqsave(&priv->driver_lock, flags);
+		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.ledgpio,
 			sizeof(struct cmd_ds_802_11_led_ctrl));
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 		break;
+
 	case CMD_RET(CMD_802_11_PWR_CFG):
-		spin_lock_irqsave(&adapter->driver_lock, flags);
-		memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg,
+		spin_lock_irqsave(&priv->driver_lock, flags);
+		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.pwrcfg,
 			sizeof(struct cmd_ds_802_11_pwr_cfg));
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 		break;
 
 	case CMD_RET(CMD_GET_TSF):
-		spin_lock_irqsave(&adapter->driver_lock, flags);
-		memcpy(priv->adapter->cur_cmd->pdata_buf,
+		spin_lock_irqsave(&priv->driver_lock, flags);
+		memcpy((void *)priv->cur_cmd->callback_arg,
 		       &resp->params.gettsf.tsfvalue, sizeof(u64));
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 		break;
 	case CMD_RET(CMD_BT_ACCESS):
-		spin_lock_irqsave(&adapter->driver_lock, flags);
-		if (adapter->cur_cmd->pdata_buf)
-			memcpy(adapter->cur_cmd->pdata_buf,
+		spin_lock_irqsave(&priv->driver_lock, flags);
+		if (priv->cur_cmd->callback_arg)
+			memcpy((void *)priv->cur_cmd->callback_arg,
 			       &resp->params.bt.addr1, 2 * ETH_ALEN);
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 		break;
 	case CMD_RET(CMD_FWT_ACCESS):
-		spin_lock_irqsave(&adapter->driver_lock, flags);
-		if (adapter->cur_cmd->pdata_buf)
-			memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt,
+		spin_lock_irqsave(&priv->driver_lock, flags);
+		if (priv->cur_cmd->callback_arg)
+			memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt,
 			       sizeof(resp->params.fwt));
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 		break;
-	case CMD_RET(CMD_MESH_ACCESS):
-		if (adapter->cur_cmd->pdata_buf)
-			memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh,
-			       sizeof(resp->params.mesh));
+	case CMD_RET(CMD_802_11_BEACON_CTRL):
+		ret = lbs_ret_802_11_bcn_ctrl(priv, resp);
 		break;
+
 	default:
 		lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
-			    resp->command);
+			     le16_to_cpu(resp->command));
 		break;
 	}
 	lbs_deb_leave(LBS_DEB_HOST);
 	return ret;
 }
 
-int libertas_process_rx_command(wlan_private * priv)
+int lbs_process_rx_command(struct lbs_private *priv)
 {
-	u16 respcmd;
-	struct cmd_ds_command *resp;
-	wlan_adapter *adapter = priv->adapter;
+	uint16_t respcmd, curcmd;
+	struct cmd_header *resp;
 	int ret = 0;
-	ulong flags;
-	u16 result;
+	unsigned long flags;
+	uint16_t result;
 
 	lbs_deb_enter(LBS_DEB_HOST);
 
-	/* Now we got response from FW, cancel the command timer */
-	del_timer(&adapter->command_timer);
-
-	mutex_lock(&adapter->lock);
-	spin_lock_irqsave(&adapter->driver_lock, flags);
+	mutex_lock(&priv->lock);
+	spin_lock_irqsave(&priv->driver_lock, flags);
 
-	if (!adapter->cur_cmd) {
+	if (!priv->cur_cmd) {
 		lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
 		ret = -1;
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 		goto done;
 	}
-	resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
+
+	resp = (void *)priv->upld_buf;
+
+	curcmd = le16_to_cpu(resp->command);
 
 	respcmd = le16_to_cpu(resp->command);
 	result = le16_to_cpu(resp->result);
 
-	lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
-		respcmd, priv->upld_len, jiffies);
-	lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr,
-		    priv->upld_len);
-
-	if (!(respcmd & 0x8000)) {
-		lbs_deb_host("invalid response!\n");
-		adapter->cur_cmd_retcode = -1;
-		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
-		adapter->nr_cmd_pending--;
-		adapter->cur_cmd = NULL;
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+	lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n",
+		     respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies);
+	lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len);
+
+	if (resp->seqnum != resp->seqnum) {
+		lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
+			    le16_to_cpu(resp->seqnum), le16_to_cpu(resp->seqnum));
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+	if (respcmd != CMD_RET(curcmd) &&
+	    respcmd != CMD_802_11_ASSOCIATE && curcmd != CMD_RET_802_11_ASSOCIATE) {
+		lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
+		ret = -1;
+		goto done;
+	}
+
+	if (resp->result == cpu_to_le16(0x0004)) {
+		/* 0x0004 means -EAGAIN. Drop the response, let it time out
+		   and be resubmitted */
+		lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
+			    le16_to_cpu(resp->command));
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 		ret = -1;
 		goto done;
 	}
 
+	/* Now we got response from FW, cancel the command timer */
+	del_timer(&priv->command_timer);
+	priv->cmd_timed_out = 0;
+	if (priv->nr_retries) {
+		lbs_pr_info("Received result %x to command %x after %d retries\n",
+			    result, curcmd, priv->nr_retries);
+		priv->nr_retries = 0;
+	}
+
 	/* Store the response code to cur_cmd_retcode. */
-	adapter->cur_cmd_retcode = result;;
+	priv->cur_cmd_retcode = result;
 
 	if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
-		struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
+		struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
 		u16 action = le16_to_cpu(psmode->action);
 
 		lbs_deb_host(
@@ -774,54 +623,45 @@ int libertas_process_rx_command(wlan_private * priv)
 			/*
 			 * We should not re-try enter-ps command in
 			 * ad-hoc mode. It takes place in
-			 * libertas_execute_next_command().
+			 * lbs_execute_next_command().
 			 */
-			if (adapter->mode == IW_MODE_ADHOC &&
+			if (priv->mode == IW_MODE_ADHOC &&
 			    action == CMD_SUBCMD_ENTER_PS)
-				adapter->psmode = WLAN802_11POWERMODECAM;
+				priv->psmode = LBS802_11POWERMODECAM;
 		} else if (action == CMD_SUBCMD_ENTER_PS) {
-			adapter->needtowakeup = 0;
-			adapter->psstate = PS_STATE_AWAKE;
+			priv->needtowakeup = 0;
+			priv->psstate = PS_STATE_AWAKE;
 
 			lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
-			if (adapter->connect_status != LIBERTAS_CONNECTED) {
+			if (priv->connect_status != LBS_CONNECTED) {
 				/*
 				 * When Deauth Event received before Enter_PS command
 				 * response, We need to wake up the firmware.
 				 */
 				lbs_deb_host(
-				       "disconnected, invoking libertas_ps_wakeup\n");
+				       "disconnected, invoking lbs_ps_wakeup\n");
 
-				spin_unlock_irqrestore(&adapter->driver_lock, flags);
-				mutex_unlock(&adapter->lock);
-				libertas_ps_wakeup(priv, 0);
-				mutex_lock(&adapter->lock);
-				spin_lock_irqsave(&adapter->driver_lock, flags);
+				spin_unlock_irqrestore(&priv->driver_lock, flags);
+				mutex_unlock(&priv->lock);
+				lbs_ps_wakeup(priv, 0);
+				mutex_lock(&priv->lock);
+				spin_lock_irqsave(&priv->driver_lock, flags);
 			}
 		} else if (action == CMD_SUBCMD_EXIT_PS) {
-			adapter->needtowakeup = 0;
-			adapter->psstate = PS_STATE_FULL_POWER;
+			priv->needtowakeup = 0;
+			priv->psstate = PS_STATE_FULL_POWER;
 			lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
 		} else {
 			lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
 		}
 
-		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
-		adapter->nr_cmd_pending--;
-		adapter->cur_cmd = NULL;
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		lbs_complete_command(priv, priv->cur_cmd, result);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 		ret = 0;
 		goto done;
 	}
 
-	if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
-		/* Copy the response back to response buffer */
-		memcpy(adapter->cur_cmd->pdata_buf, resp,
-		       le16_to_cpu(resp->size));
-		adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
-	}
-
 	/* If the command is not successful, cleanup and return failure */
 	if ((result != 0 || !(respcmd & 0x8000))) {
 		lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
@@ -836,106 +676,132 @@ int libertas_process_rx_command(wlan_private * priv)
 			break;
 
 		}
-
-		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
-		adapter->nr_cmd_pending--;
-		adapter->cur_cmd = NULL;
-		spin_unlock_irqrestore(&adapter->driver_lock, flags);
+		lbs_complete_command(priv, priv->cur_cmd, result);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 		ret = -1;
 		goto done;
 	}
 
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
-	ret = handle_cmd_response(respcmd, resp, priv);
+	if (priv->cur_cmd && priv->cur_cmd->callback) {
+		ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
+				resp);
+	} else
+		ret = handle_cmd_response(priv, 0, resp);
 
-	spin_lock_irqsave(&adapter->driver_lock, flags);
-	if (adapter->cur_cmd) {
+	spin_lock_irqsave(&priv->driver_lock, flags);
+
+	if (priv->cur_cmd) {
 		/* Clean up and Put current command back to cmdfreeq */
-		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
-		adapter->nr_cmd_pending--;
-		WARN_ON(adapter->nr_cmd_pending > 128);
-		adapter->cur_cmd = NULL;
+		lbs_complete_command(priv, priv->cur_cmd, result);
 	}
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 done:
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
 	return ret;
 }
 
-int libertas_process_event(wlan_private * priv)
+static int lbs_send_confirmwake(struct lbs_private *priv)
+{
+	struct cmd_header *cmd = &priv->lbs_ps_confirm_wake;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_HOST);
+
+	cmd->command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
+	cmd->size = cpu_to_le16(sizeof(*cmd));
+	cmd->seqnum = cpu_to_le16(++priv->seqnum);
+	cmd->result = 0;
+
+	lbs_deb_host("SEND_WAKEC_CMD: before download\n");
+
+	lbs_deb_hex(LBS_DEB_HOST, "wake confirm command", (void *)cmd, sizeof(*cmd));
+
+	ret = priv->hw_host_to_card(priv, MVMS_CMD, (void *)cmd, sizeof(*cmd));
+	if (ret)
+		lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n");
+
+	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
+	return ret;
+}
+
+int lbs_process_event(struct lbs_private *priv)
 {
 	int ret = 0;
-	wlan_adapter *adapter = priv->adapter;
 	u32 eventcause;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	spin_lock_irq(&adapter->driver_lock);
-	eventcause = adapter->eventcause;
-	spin_unlock_irq(&adapter->driver_lock);
+	spin_lock_irq(&priv->driver_lock);
+	eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT;
+	spin_unlock_irq(&priv->driver_lock);
 
-	lbs_deb_cmd("event cause 0x%x\n", eventcause);
+	lbs_deb_cmd("event cause %d\n", eventcause);
 
-	switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
+	switch (eventcause) {
 	case MACREG_INT_CODE_LINK_SENSED:
 		lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n");
 		break;
 
 	case MACREG_INT_CODE_DEAUTHENTICATED:
 		lbs_deb_cmd("EVENT: deauthenticated\n");
-		libertas_mac_event_disconnected(priv);
+		lbs_mac_event_disconnected(priv);
 		break;
 
 	case MACREG_INT_CODE_DISASSOCIATED:
 		lbs_deb_cmd("EVENT: disassociated\n");
-		libertas_mac_event_disconnected(priv);
+		lbs_mac_event_disconnected(priv);
 		break;
 
-	case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
+	case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
 		lbs_deb_cmd("EVENT: link lost\n");
-		libertas_mac_event_disconnected(priv);
+		lbs_mac_event_disconnected(priv);
 		break;
 
 	case MACREG_INT_CODE_PS_SLEEP:
 		lbs_deb_cmd("EVENT: sleep\n");
 
 		/* handle unexpected PS SLEEP event */
-		if (adapter->psstate == PS_STATE_FULL_POWER) {
+		if (priv->psstate == PS_STATE_FULL_POWER) {
 			lbs_deb_cmd(
 			       "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
 			break;
 		}
-		adapter->psstate = PS_STATE_PRE_SLEEP;
+		priv->psstate = PS_STATE_PRE_SLEEP;
 
-		libertas_ps_confirm_sleep(priv, (u16) adapter->psmode);
+		lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
 
 		break;
 
+	case MACREG_INT_CODE_HOST_AWAKE:
+		lbs_deb_cmd("EVENT: HOST_AWAKE\n");
+		lbs_send_confirmwake(priv);
+		break;
+
 	case MACREG_INT_CODE_PS_AWAKE:
 		lbs_deb_cmd("EVENT: awake\n");
-
 		/* handle unexpected PS AWAKE event */
-		if (adapter->psstate == PS_STATE_FULL_POWER) {
+		if (priv->psstate == PS_STATE_FULL_POWER) {
 			lbs_deb_cmd(
 			       "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
 			break;
 		}
 
-		adapter->psstate = PS_STATE_AWAKE;
+		priv->psstate = PS_STATE_AWAKE;
 
-		if (adapter->needtowakeup) {
+		if (priv->needtowakeup) {
 			/*
 			 * wait for the command processing to finish
 			 * before resuming sending
-			 * adapter->needtowakeup will be set to FALSE
-			 * in libertas_ps_wakeup()
+			 * priv->needtowakeup will be set to FALSE
+			 * in lbs_ps_wakeup()
 			 */
 			lbs_deb_cmd("waking up ...\n");
-			libertas_ps_wakeup(priv, 0);
+			lbs_ps_wakeup(priv, 0);
 		}
 		break;
 
@@ -979,24 +845,24 @@ int libertas_process_event(wlan_private * priv)
 			break;
 		}
 		lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
-		adapter->connect_status = LIBERTAS_CONNECTED;
-		if (priv->mesh_open == 1) {
-			netif_wake_queue(priv->mesh_dev);
+		priv->mesh_connect_status = LBS_CONNECTED;
+		if (priv->mesh_open) {
 			netif_carrier_on(priv->mesh_dev);
+			if (!priv->tx_pending_len)
+				netif_wake_queue(priv->mesh_dev);
 		}
-		adapter->mode = IW_MODE_ADHOC;
+		priv->mode = IW_MODE_ADHOC;
 		schedule_work(&priv->sync_channel);
 		break;
 
 	default:
-		lbs_pr_alert("EVENT: unknown event id 0x%04x\n",
-		       eventcause >> SBI_EVENT_CAUSE_SHIFT);
+		lbs_pr_alert("EVENT: unknown event id %d\n", eventcause);
 		break;
 	}
 
-	spin_lock_irq(&adapter->driver_lock);
-	adapter->eventcause = 0;
-	spin_unlock_irq(&adapter->driver_lock);
+	spin_lock_irq(&priv->driver_lock);
+	priv->eventcause = 0;
+	spin_unlock_irq(&priv->driver_lock);
 
 	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return ret;
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 0bda0b511910..fd67b770dd78 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -10,15 +10,16 @@
 #include "decl.h"
 #include "host.h"
 #include "debugfs.h"
+#include "cmd.h"
 
-static struct dentry *libertas_dir = NULL;
+static struct dentry *lbs_dir;
 static char *szStates[] = {
 	"Connected",
 	"Disconnected"
 };
 
 #ifdef PROC_DEBUG
-static void libertas_debug_init(wlan_private * priv, struct net_device *dev);
+static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev);
 #endif
 
 static int open_file_generic(struct inode *inode, struct file *file)
@@ -35,19 +36,19 @@ static ssize_t write_file_dummy(struct file *file, const char __user *buf,
 
 static const size_t len = PAGE_SIZE;
 
-static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
+static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
+	struct lbs_private *priv = file->private_data;
 	size_t pos = 0;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
 	ssize_t res;
 
 	pos += snprintf(buf+pos, len-pos, "state = %s\n",
-				szStates[priv->adapter->connect_status]);
+				szStates[priv->connect_status]);
 	pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
-				(u32) priv->adapter->regioncode);
+				(u32) priv->regioncode);
 
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 
@@ -56,10 +57,10 @@ static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
 }
 
 
-static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
+static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
+	struct lbs_private *priv = file->private_data;
 	size_t pos = 0;
 	int numscansdone = 0, res;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
@@ -70,8 +71,8 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
 	pos += snprintf(buf+pos, len-pos,
 		"# | ch  | rssi |       bssid       |   cap    | Qual | SSID \n");
 
-	mutex_lock(&priv->adapter->lock);
-	list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
+	mutex_lock(&priv->lock);
+	list_for_each_entry (iter_bss, &priv->network_list, list) {
 		u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
 		u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
 		u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
@@ -90,7 +91,7 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
 
 		numscansdone++;
 	}
-	mutex_unlock(&priv->adapter->lock);
+	mutex_unlock(&priv->lock);
 
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 
@@ -98,83 +99,75 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
 	return res;
 }
 
-static ssize_t libertas_sleepparams_write(struct file *file,
+static ssize_t lbs_sleepparams_write(struct file *file,
 				const char __user *user_buf, size_t count,
 				loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	ssize_t buf_size, res;
+	struct lbs_private *priv = file->private_data;
+	ssize_t buf_size, ret;
+	struct sleep_params sp;
 	int p1, p2, p3, p4, p5, p6;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
 
 	buf_size = min(count, len - 1);
 	if (copy_from_user(buf, user_buf, buf_size)) {
-		res = -EFAULT;
+		ret = -EFAULT;
 		goto out_unlock;
 	}
-	res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
-	if (res != 6) {
-		res = -EFAULT;
+	ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
+	if (ret != 6) {
+		ret = -EINVAL;
 		goto out_unlock;
 	}
-	priv->adapter->sp.sp_error = p1;
-	priv->adapter->sp.sp_offset = p2;
-	priv->adapter->sp.sp_stabletime = p3;
-	priv->adapter->sp.sp_calcontrol = p4;
-	priv->adapter->sp.sp_extsleepclk = p5;
-	priv->adapter->sp.sp_reserved = p6;
-
-        res = libertas_prepare_and_send_command(priv,
-				CMD_802_11_SLEEP_PARAMS,
-				CMD_ACT_SET,
-				CMD_OPTION_WAITFORRSP, 0, NULL);
-
-	if (!res)
-		res = count;
-	else
-		res = -EINVAL;
+	sp.sp_error = p1;
+	sp.sp_offset = p2;
+	sp.sp_stabletime = p3;
+	sp.sp_calcontrol = p4;
+	sp.sp_extsleepclk = p5;
+	sp.sp_reserved = p6;
+
+	ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
+	if (!ret)
+		ret = count;
+	else if (ret > 0)
+		ret = -EINVAL;
 
 out_unlock:
 	free_page(addr);
-	return res;
+	return ret;
 }
 
-static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
+static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	ssize_t res;
+	struct lbs_private *priv = file->private_data;
+	ssize_t ret;
 	size_t pos = 0;
+	struct sleep_params sp;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
 
-        res = libertas_prepare_and_send_command(priv,
-				CMD_802_11_SLEEP_PARAMS,
-				CMD_ACT_GET,
-				CMD_OPTION_WAITFORRSP, 0, NULL);
-	if (res) {
-		res = -EFAULT;
+	ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
+	if (ret)
 		goto out_unlock;
-	}
 
-	pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
-			adapter->sp.sp_offset, adapter->sp.sp_stabletime,
-			adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
-			adapter->sp.sp_reserved);
+	pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
+			sp.sp_offset, sp.sp_stabletime,
+			sp.sp_calcontrol, sp.sp_extsleepclk,
+			sp.sp_reserved);
 
-	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 
 out_unlock:
 	free_page(addr);
-	return res;
+	return ret;
 }
 
-static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
+static ssize_t lbs_extscan(struct file *file, const char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
+	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
 	union iwreq_data wrqu;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
@@ -186,7 +179,7 @@ static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
 		goto out_unlock;
 	}
 
-	libertas_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);
+	lbs_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0);
 
 	memset(&wrqu, 0, sizeof(union iwreq_data));
 	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -196,45 +189,8 @@ out_unlock:
 	return count;
 }
 
-static int libertas_parse_chan(char *buf, size_t count,
-			struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
-{
-	char *start, *end, *hold, *str;
-	int i = 0;
-
-	start = strstr(buf, "chan=");
-	if (!start)
-		return -EINVAL;
-	start += 5;
-	end = strchr(start, ' ');
-	if (!end)
-		end = buf + count;
-	hold = kzalloc((end - start)+1, GFP_KERNEL);
-	if (!hold)
-		return -ENOMEM;
-	strncpy(hold, start, end - start);
-	hold[(end-start)+1] = '\0';
-	while(hold && (str = strsep(&hold, ","))) {
-		int chan;
-		char band, passive = 0;
-		sscanf(str, "%d%c%c", &chan, &band, &passive);
-		scan_cfg->chanlist[i].channumber = chan;
-		scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
-		if (band == 'b' || band == 'g')
-			scan_cfg->chanlist[i].radiotype = 0;
-		else if (band == 'a')
-			scan_cfg->chanlist[i].radiotype = 1;
-
-		scan_cfg->chanlist[i].scantime = dur;
-		i++;
-	}
-
-	kfree(hold);
-	return i;
-}
-
-static void libertas_parse_bssid(char *buf, size_t count,
-                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+static void lbs_parse_bssid(char *buf, size_t count,
+	struct lbs_ioctl_user_scan_cfg *scan_cfg)
 {
 	char *hold;
 	unsigned int mac[ETH_ALEN];
@@ -243,12 +199,13 @@ static void libertas_parse_bssid(char *buf, size_t count,
 	if (!hold)
 		return;
 	hold += 6;
-	sscanf(hold, MAC_FMT, mac, mac+1, mac+2, mac+3, mac+4, mac+5);
+	sscanf(hold, "%02x:%02x:%02x:%02x:%02x:%02x",
+	       mac, mac+1, mac+2, mac+3, mac+4, mac+5);
 	memcpy(scan_cfg->bssid, mac, ETH_ALEN);
 }
 
-static void libertas_parse_ssid(char *buf, size_t count,
-                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+static void lbs_parse_ssid(char *buf, size_t count,
+	struct lbs_ioctl_user_scan_cfg *scan_cfg)
 {
 	char *hold, *end;
 	ssize_t size;
@@ -267,7 +224,7 @@ static void libertas_parse_ssid(char *buf, size_t count,
 	return;
 }
 
-static int libertas_parse_clear(char *buf, size_t count, const char *tag)
+static int lbs_parse_clear(char *buf, size_t count, const char *tag)
 {
 	char *hold;
 	int val;
@@ -284,8 +241,8 @@ static int libertas_parse_clear(char *buf, size_t count, const char *tag)
 	return val;
 }
 
-static int libertas_parse_dur(char *buf, size_t count,
-                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+static int lbs_parse_dur(char *buf, size_t count,
+	struct lbs_ioctl_user_scan_cfg *scan_cfg)
 {
 	char *hold;
 	int val;
@@ -299,25 +256,8 @@ static int libertas_parse_dur(char *buf, size_t count,
 	return val;
 }
 
-static void libertas_parse_probes(char *buf, size_t count,
-                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
-{
-	char *hold;
-	int val;
-
-	hold = strstr(buf, "probes=");
-	if (!hold)
-		return;
-	hold += 7;
-	sscanf(hold, "%d", &val);
-
-	scan_cfg->numprobes = val;
-
-	return;
-}
-
-static void libertas_parse_type(char *buf, size_t count,
-                        struct wlan_ioctl_user_scan_cfg *scan_cfg)
+static void lbs_parse_type(char *buf, size_t count,
+	struct lbs_ioctl_user_scan_cfg *scan_cfg)
 {
 	char *hold;
 	int val;
@@ -337,1036 +277,324 @@ static void libertas_parse_type(char *buf, size_t count,
 	return;
 }
 
-static ssize_t libertas_setuserscan(struct file *file,
+static ssize_t lbs_setuserscan(struct file *file,
 				    const char __user *userbuf,
 				    size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
+	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
-	struct wlan_ioctl_user_scan_cfg *scan_cfg;
+	struct lbs_ioctl_user_scan_cfg *scan_cfg;
 	union iwreq_data wrqu;
 	int dur;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
+	char *buf = (char *)get_zeroed_page(GFP_KERNEL);
 
-	scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
-	if (!scan_cfg)
+	if (!buf)
 		return -ENOMEM;
 
 	buf_size = min(count, len - 1);
 	if (copy_from_user(buf, userbuf, buf_size)) {
 		res = -EFAULT;
-		goto out_unlock;
+		goto out_buf;
+	}
+
+	scan_cfg = kzalloc(sizeof(struct lbs_ioctl_user_scan_cfg), GFP_KERNEL);
+	if (!scan_cfg) {
+		res = -ENOMEM;
+		goto out_buf;
 	}
+	res = count;
+
+	scan_cfg->bsstype = LBS_SCAN_BSS_TYPE_ANY;
 
-	scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;
+	dur = lbs_parse_dur(buf, count, scan_cfg);
+	lbs_parse_bssid(buf, count, scan_cfg);
+	scan_cfg->clear_bssid = lbs_parse_clear(buf, count, "clear_bssid=");
+	lbs_parse_ssid(buf, count, scan_cfg);
+	scan_cfg->clear_ssid = lbs_parse_clear(buf, count, "clear_ssid=");
+	lbs_parse_type(buf, count, scan_cfg);
 
-	dur = libertas_parse_dur(buf, count, scan_cfg);
-	libertas_parse_chan(buf, count, scan_cfg, dur);
-	libertas_parse_bssid(buf, count, scan_cfg);
-	scan_cfg->clear_bssid = libertas_parse_clear(buf, count, "clear_bssid=");
-	libertas_parse_ssid(buf, count, scan_cfg);
-	scan_cfg->clear_ssid = libertas_parse_clear(buf, count, "clear_ssid=");
-	libertas_parse_probes(buf, count, scan_cfg);
-	libertas_parse_type(buf, count, scan_cfg);
+	lbs_scan_networks(priv, scan_cfg, 1);
+	wait_event_interruptible(priv->cmd_pending,
+				 priv->surpriseremoved || !priv->last_scanned_channel);
 
-	wlan_scan_networks(priv, scan_cfg, 1);
-	wait_event_interruptible(priv->adapter->cmd_pending,
-				 !priv->adapter->nr_cmd_pending);
+	if (priv->surpriseremoved)
+		goto out_scan_cfg;
 
 	memset(&wrqu, 0x00, sizeof(union iwreq_data));
 	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
 
-out_unlock:
-	free_page(addr);
+ out_scan_cfg:
 	kfree(scan_cfg);
-	return count;
+ out_buf:
+	free_page((unsigned long)buf);
+	return res;
 }
 
-static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
-			struct cmd_ctrl_node **cmdnode,
-			struct cmd_ds_command **cmd)
-{
-	u16 wait_option = CMD_OPTION_WAITFORRSP;
-
-	if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
-		lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n");
-		return -ENOMEM;
-	}
-	if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
-		lbs_deb_debugfs("failed to allocate response buffer!\n");
-		return -ENOMEM;
-	}
-	libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
-	init_waitqueue_head(&(*cmdnode)->cmdwait_q);
-	(*cmdnode)->pdata_buf = *response_buf;
-	(*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
-	(*cmdnode)->cmdwaitqwoken = 0;
-	*cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
-	(*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT);
-	(*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum);
-	(*cmd)->result = 0;
-	return 0;
-}
 
-static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
-				  size_t count, loff_t *ppos)
+/*
+ * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
+ * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
+ * firmware. Here's an example:
+ *	04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
+ *	00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
+ *	00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ *
+ * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
+ * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
+ * defined in mrvlietypes_thresholds
+ *
+ * This function searches in this TLV data chunk for a given TLV type
+ * and returns a pointer to the first data byte of the TLV, or to NULL
+ * if the TLV hasn't been found.
+ */
+static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	void *response_buf;
-	int res, cmd_len;
+	struct mrvlietypesheader *tlv_h;
+	uint16_t length;
 	ssize_t pos = 0;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0) {
-		free_page(addr);
-		return res;
-	}
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_GET);
-	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
 
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
-
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	event = (void *)(response_buf + S_DS_GEN);
-	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
-		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
-		switch (header->type) {
-		struct mrvlietypes_rssithreshold  *Lowrssi;
-		case __constant_cpu_to_le16(TLV_TYPE_RSSI_LOW):
-			Lowrssi = (void *)(response_buf + cmd_len);
-			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
-					Lowrssi->rssivalue,
-					Lowrssi->rssifreq,
-					(event->events & cpu_to_le16(0x0001))?1:0);
-		default:
-			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
-			break;
-		}
-	}
-
-	kfree(response_buf);
-	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-	free_page(addr);
-	return res;
-}
-
-static u16 libertas_get_events_bitmap(wlan_private *priv)
-{
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	void *response_buf;
-	int res;
-	u16 event_bitmap;
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0)
-		return res;
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_GET);
-	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
-
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		return 0;
-	}
-
-	if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		return 0;
-	}
-
-	event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
-	event_bitmap = le16_to_cpu(event->events);
-	kfree(response_buf);
-	return event_bitmap;
+	while (pos < size) {
+		tlv_h = (struct mrvlietypesheader *) tlv;
+		if (!tlv_h->len)
+			return NULL;
+		if (tlv_h->type == cpu_to_le16(tlv_type))
+			return tlv_h;
+		length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
+		pos += length;
+		tlv += length;
+	}
+	return NULL;
 }
 
-static ssize_t libertas_lowrssi_write(struct file *file,
-				    const char __user *userbuf,
-				    size_t count, loff_t *ppos)
-{
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	ssize_t res, buf_size;
-	int value, freq, subscribed, cmd_len;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	struct mrvlietypes_rssithreshold *rssi_threshold;
-	void *response_buf;
-	u16 event_bitmap;
-	u8 *ptr;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
 
-	buf_size = min(count, len - 1);
-	if (copy_from_user(buf, userbuf, buf_size)) {
-		res = -EFAULT;
-		goto out_unlock;
-	}
-	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
-	if (res != 3) {
-		res = -EFAULT;
-		goto out_unlock;
-	}
-
-	event_bitmap = libertas_get_events_bitmap(priv);
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0)
-		goto out_unlock;
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_SET);
-	pcmdptr->size = cpu_to_le16(S_DS_GEN +
-		sizeof(struct cmd_ds_802_11_subscribe_event) +
-		sizeof(struct mrvlietypes_rssithreshold));
-
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	ptr = (u8*) pcmdptr+cmd_len;
-	rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
-	rssi_threshold->header.type = cpu_to_le16(0x0104);
-	rssi_threshold->header.len = cpu_to_le16(2);
-	rssi_threshold->rssivalue = value;
-	rssi_threshold->rssifreq = freq;
-	event_bitmap |= subscribed ? 0x0001 : 0x0;
-	event->events = cpu_to_le16(event_bitmap);
-
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
-
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
-
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
-
-	res = count;
-out_unlock:
-	free_page(addr);
-	return res;
-}
-
-static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
+static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
+				  struct file *file, char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	void *response_buf;
-	int res, cmd_len;
-	ssize_t pos = 0;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0) {
-		free_page(addr);
-		return res;
-	}
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_GET);
-	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
+	struct cmd_ds_802_11_subscribe_event *subscribed;
+	struct mrvlietypes_thresholds *got;
+	struct lbs_private *priv = file->private_data;
+	ssize_t ret = 0;
+	size_t pos = 0;
+	char *buf;
+	u8 value;
+	u8 freq;
+	int events = 0;
 
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
+	buf = (char *)get_zeroed_page(GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
 
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
+	subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
+	if (!subscribed) {
+		ret = -ENOMEM;
+		goto out_page;
 	}
 
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	event = (void *)(response_buf + S_DS_GEN);
-	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
-		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
-		switch (header->type) {
-		struct mrvlietypes_snrthreshold *LowSnr;
-		case __constant_cpu_to_le16(TLV_TYPE_SNR_LOW):
-			LowSnr = (void *)(response_buf + cmd_len);
-			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
-					LowSnr->snrvalue,
-					LowSnr->snrfreq,
-					(event->events & cpu_to_le16(0x0002))?1:0);
-		default:
-			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
-			break;
-		}
-	}
+	subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
+	subscribed->action = cpu_to_le16(CMD_ACT_GET);
 
-	kfree(response_buf);
+	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
+	if (ret)
+		goto out_cmd;
 
-	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-	free_page(addr);
-	return res;
-}
+	got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
+	if (got) {
+		value = got->value;
+		freq  = got->freq;
+		events = le16_to_cpu(subscribed->events);
 
-static ssize_t libertas_lowsnr_write(struct file *file,
-				    const char __user *userbuf,
-				    size_t count, loff_t *ppos)
-{
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	ssize_t res, buf_size;
-	int value, freq, subscribed, cmd_len;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	struct mrvlietypes_snrthreshold *snr_threshold;
-	void *response_buf;
-	u16 event_bitmap;
-	u8 *ptr;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
-
-	buf_size = min(count, len - 1);
-	if (copy_from_user(buf, userbuf, buf_size)) {
-		res = -EFAULT;
-		goto out_unlock;
-	}
-	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
-	if (res != 3) {
-		res = -EFAULT;
-		goto out_unlock;
-	}
-
-	event_bitmap = libertas_get_events_bitmap(priv);
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0)
-		goto out_unlock;
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_SET);
-	pcmdptr->size = cpu_to_le16(S_DS_GEN +
-		sizeof(struct cmd_ds_802_11_subscribe_event) +
-		sizeof(struct mrvlietypes_snrthreshold));
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	ptr = (u8*) pcmdptr+cmd_len;
-	snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
-	snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
-	snr_threshold->header.len = cpu_to_le16(2);
-	snr_threshold->snrvalue = value;
-	snr_threshold->snrfreq = freq;
-	event_bitmap |= subscribed ? 0x0002 : 0x0;
-	event->events = cpu_to_le16(event_bitmap);
-
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
-
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
+		pos += snprintf(buf, len, "%d %d %d\n", value, freq,
+				!!(events & event_mask));
 	}
 
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
+	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 
-	res = count;
+ out_cmd:
+	kfree(subscribed);
 
-out_unlock:
-	free_page(addr);
-	return res;
+ out_page:
+	free_page((unsigned long)buf);
+	return ret;
 }
 
-static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
-				  size_t count, loff_t *ppos)
-{
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	void *response_buf;
-	int res, cmd_len;
-	ssize_t pos = 0;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0) {
-		free_page(addr);
-		return res;
-	}
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_GET);
-	pcmdptr->size =	cpu_to_le16(sizeof(*event) + S_DS_GEN);
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
-
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
-
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
-
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	event = (void *)(response_buf + S_DS_GEN);
-	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
-		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
-		switch (header->type) {
-		struct mrvlietypes_failurecount *failcount;
-		case __constant_cpu_to_le16(TLV_TYPE_FAILCOUNT):
-			failcount = (void *)(response_buf + cmd_len);
-			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
-					failcount->failvalue,
-					failcount->Failfreq,
-					(event->events & cpu_to_le16(0x0004))?1:0);
-		default:
-			cmd_len += sizeof(struct mrvlietypes_failurecount);
-			break;
-		}
-	}
-
-	kfree(response_buf);
-	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-	free_page(addr);
-	return res;
-}
 
-static ssize_t libertas_failcount_write(struct file *file,
-				    const char __user *userbuf,
-				    size_t count, loff_t *ppos)
+static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
+				   struct file *file,
+				   const char __user *userbuf, size_t count,
+				   loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	ssize_t res, buf_size;
-	int value, freq, subscribed, cmd_len;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	struct mrvlietypes_failurecount *failcount;
-	void *response_buf;
-	u16 event_bitmap;
-	u8 *ptr;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
+	struct cmd_ds_802_11_subscribe_event *events;
+	struct mrvlietypes_thresholds *tlv;
+	struct lbs_private *priv = file->private_data;
+	ssize_t buf_size;
+	int value, freq, new_mask;
+	uint16_t curr_mask;
+	char *buf;
+	int ret;
+
+	buf = (char *)get_zeroed_page(GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
 
 	buf_size = min(count, len - 1);
 	if (copy_from_user(buf, userbuf, buf_size)) {
-		res = -EFAULT;
-		goto out_unlock;
+		ret = -EFAULT;
+		goto out_page;
 	}
-	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
-	if (res != 3) {
-		res = -EFAULT;
-		goto out_unlock;
+	ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
+	if (ret != 3) {
+		ret = -EINVAL;
+		goto out_page;
 	}
-
-	event_bitmap = libertas_get_events_bitmap(priv);
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0)
-		goto out_unlock;
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_SET);
-	pcmdptr->size = cpu_to_le16(S_DS_GEN +
-		sizeof(struct cmd_ds_802_11_subscribe_event) +
-		sizeof(struct mrvlietypes_failurecount));
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	ptr = (u8*) pcmdptr+cmd_len;
-	failcount = (struct mrvlietypes_failurecount *)(ptr);
-	failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
-	failcount->header.len = cpu_to_le16(2);
-	failcount->failvalue = value;
-	failcount->Failfreq = freq;
-	event_bitmap |= subscribed ? 0x0004 : 0x0;
-	event->events = cpu_to_le16(event_bitmap);
-
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = (struct cmd_ds_command *)response_buf;
-
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
+	events = kzalloc(sizeof(*events), GFP_KERNEL);
+	if (!events) {
+		ret = -ENOMEM;
+		goto out_page;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
+	events->hdr.size = cpu_to_le16(sizeof(*events));
+	events->action = cpu_to_le16(CMD_ACT_GET);
 
-	res = count;
-out_unlock:
-	free_page(addr);
-	return res;
-}
-
-static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
-				  size_t count, loff_t *ppos)
-{
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	void *response_buf;
-	int res, cmd_len;
-	ssize_t pos = 0;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0) {
-		free_page(addr);
-		return res;
-	}
+	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
+	if (ret)
+		goto out_events;
 
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_GET);
-	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
+	curr_mask = le16_to_cpu(events->events);
 
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
+	if (new_mask)
+		new_mask = curr_mask | event_mask;
+	else
+		new_mask = curr_mask & ~event_mask;
 
-	pcmdptr = response_buf;
+	/* Now everything is set and we can send stuff down to the firmware */
 
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		free_page(addr);
-		kfree(response_buf);
-		return 0;
-	}
+	tlv = (void *)events->tlv;
 
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		free_page(addr);
-		kfree(response_buf);
-		return 0;
-	}
+	events->action = cpu_to_le16(CMD_ACT_SET);
+	events->events = cpu_to_le16(new_mask);
+	tlv->header.type = cpu_to_le16(tlv_type);
+	tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
+	tlv->value = value;
+	if (tlv_type != TLV_TYPE_BCNMISS)
+		tlv->freq = freq;
 
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	event = (void *)(response_buf + S_DS_GEN);
-	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
-		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
-		switch (header->type) {
-		struct mrvlietypes_beaconsmissed *bcnmiss;
-		case __constant_cpu_to_le16(TLV_TYPE_BCNMISS):
-			bcnmiss = (void *)(response_buf + cmd_len);
-			pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
-					bcnmiss->beaconmissed,
-					(event->events & cpu_to_le16(0x0008))?1:0);
-		default:
-			cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
-			break;
-		}
-	}
+	/* The command header, the event mask, and the one TLV */
+	events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 2 + sizeof(*tlv));
 
-	kfree(response_buf);
+	ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
 
-	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-	free_page(addr);
-	return res;
+	if (!ret)
+		ret = count;
+ out_events:
+	kfree(events);
+ out_page:
+	free_page((unsigned long)buf);
+	return ret;
 }
 
-static ssize_t libertas_bcnmiss_write(struct file *file,
-				    const char __user *userbuf,
-				    size_t count, loff_t *ppos)
+
+static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	ssize_t res, buf_size;
-	int value, freq, subscribed, cmd_len;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	struct mrvlietypes_beaconsmissed *bcnmiss;
-	void *response_buf;
-	u16 event_bitmap;
-	u8 *ptr;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
+	return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
+				  file, userbuf, count, ppos);
+}
 
-	buf_size = min(count, len - 1);
-	if (copy_from_user(buf, userbuf, buf_size)) {
-		res = -EFAULT;
-		goto out_unlock;
-	}
-	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
-	if (res != 3) {
-		res = -EFAULT;
-		goto out_unlock;
-	}
 
-	event_bitmap = libertas_get_events_bitmap(priv);
+static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
+				   file, userbuf, count, ppos);
+}
 
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0)
-		goto out_unlock;
 
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_SET);
-	pcmdptr->size = cpu_to_le16(S_DS_GEN +
-		sizeof(struct cmd_ds_802_11_subscribe_event) +
-		sizeof(struct mrvlietypes_beaconsmissed));
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	ptr = (u8*) pcmdptr+cmd_len;
-	bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
-	bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
-	bcnmiss->header.len = cpu_to_le16(2);
-	bcnmiss->beaconmissed = value;
-	event_bitmap |= subscribed ? 0x0008 : 0x0;
-	event->events = cpu_to_le16(event_bitmap);
-
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
-
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
+static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
+			       size_t count, loff_t *ppos)
+{
+	return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
+				  file, userbuf, count, ppos);
+}
 
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		free_page(addr);
-		kfree(response_buf);
-		return 0;
-	}
 
-	res = count;
-out_unlock:
-	free_page(addr);
-	return res;
+static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
+				   file, userbuf, count, ppos);
 }
 
-static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
+
+static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	void *response_buf;
-	int res, cmd_len;
-	ssize_t pos = 0;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0) {
-		free_page(addr);
-		return res;
-	}
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_GET);
-	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
-
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
-
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
-
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	event = (void *)(response_buf + S_DS_GEN);
-	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
-		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
-		switch (header->type) {
-		struct mrvlietypes_rssithreshold  *Highrssi;
-		case __constant_cpu_to_le16(TLV_TYPE_RSSI_HIGH):
-			Highrssi = (void *)(response_buf + cmd_len);
-			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
-					Highrssi->rssivalue,
-					Highrssi->rssifreq,
-					(event->events & cpu_to_le16(0x0010))?1:0);
-		default:
-			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
-			break;
-		}
-	}
-
-	kfree(response_buf);
-
-	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-	free_page(addr);
-	return res;
+	return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
+				  file, userbuf, count, ppos);
 }
 
-static ssize_t libertas_highrssi_write(struct file *file,
-				    const char __user *userbuf,
-				    size_t count, loff_t *ppos)
-{
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	ssize_t res, buf_size;
-	int value, freq, subscribed, cmd_len;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	struct mrvlietypes_rssithreshold *rssi_threshold;
-	void *response_buf;
-	u16 event_bitmap;
-	u8 *ptr;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
-
-	buf_size = min(count, len - 1);
-	if (copy_from_user(buf, userbuf, buf_size)) {
-		res = -EFAULT;
-		goto out_unlock;
-	}
-	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
-	if (res != 3) {
-		res = -EFAULT;
-		goto out_unlock;
-	}
 
-	event_bitmap = libertas_get_events_bitmap(priv);
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0)
-		goto out_unlock;
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_SET);
-	pcmdptr->size = cpu_to_le16(S_DS_GEN +
-		sizeof(struct cmd_ds_802_11_subscribe_event) +
-		sizeof(struct mrvlietypes_rssithreshold));
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	ptr = (u8*) pcmdptr+cmd_len;
-	rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
-	rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
-	rssi_threshold->header.len = cpu_to_le16(2);
-	rssi_threshold->rssivalue = value;
-	rssi_threshold->rssifreq = freq;
-	event_bitmap |= subscribed ? 0x0010 : 0x0;
-	event->events = cpu_to_le16(event_bitmap);
-
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
-
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		return 0;
-	}
+static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
+				   size_t count, loff_t *ppos)
+{
+	return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
+				   file, userbuf, count, ppos);
+}
 
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		return 0;
-	}
 
-	res = count;
-out_unlock:
-	free_page(addr);
-	return res;
+static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
+				  file, userbuf, count, ppos);
 }
 
-static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
+
+static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	void *response_buf;
-	int res, cmd_len;
-	ssize_t pos = 0;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
-
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0) {
-		free_page(addr);
-		return res;
-	}
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_GET);
-	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
+	return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
+				   file, userbuf, count, ppos);
+}
 
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
 
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
-
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	event = (void *)(response_buf + S_DS_GEN);
-	while (cmd_len < le16_to_cpu(pcmdptr->size)) {
-		struct mrvlietypesheader *header = (void *)(response_buf + cmd_len);
-		switch (header->type) {
-		struct mrvlietypes_snrthreshold *HighSnr;
-		case __constant_cpu_to_le16(TLV_TYPE_SNR_HIGH):
-			HighSnr = (void *)(response_buf + cmd_len);
-			pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
-					HighSnr->snrvalue,
-					HighSnr->snrfreq,
-					(event->events & cpu_to_le16(0x0020))?1:0);
-		default:
-			cmd_len += sizeof(struct mrvlietypes_snrthreshold);
-			break;
-		}
-	}
+static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
+				  file, userbuf, count, ppos);
+}
 
-	kfree(response_buf);
 
-	res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
-	free_page(addr);
-	return res;
+static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
+				   file, userbuf, count, ppos);
 }
 
-static ssize_t libertas_highsnr_write(struct file *file,
-				    const char __user *userbuf,
-				    size_t count, loff_t *ppos)
+static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	ssize_t res, buf_size;
-	int value, freq, subscribed, cmd_len;
-	struct cmd_ctrl_node *pcmdnode;
-	struct cmd_ds_command *pcmdptr;
-	struct cmd_ds_802_11_subscribe_event *event;
-	struct mrvlietypes_snrthreshold *snr_threshold;
-	void *response_buf;
-	u16 event_bitmap;
-	u8 *ptr;
-	unsigned long addr = get_zeroed_page(GFP_KERNEL);
-	char *buf = (char *)addr;
-
-	buf_size = min(count, len - 1);
-	if (copy_from_user(buf, userbuf, buf_size)) {
-		res = -EFAULT;
-		goto out_unlock;
-	}
-	res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
-	if (res != 3) {
-		res = -EFAULT;
-		goto out_unlock;
-	}
+	return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
+				  file, userbuf, count, ppos);
+}
 
-	event_bitmap = libertas_get_events_bitmap(priv);
 
-	res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
-	if (res < 0)
-		goto out_unlock;
-
-	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(CMD_ACT_SET);
-	pcmdptr->size = cpu_to_le16(S_DS_GEN +
-		sizeof(struct cmd_ds_802_11_subscribe_event) +
-		sizeof(struct mrvlietypes_snrthreshold));
-	cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
-	ptr = (u8*) pcmdptr+cmd_len;
-	snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
-	snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
-	snr_threshold->header.len = cpu_to_le16(2);
-	snr_threshold->snrvalue = value;
-	snr_threshold->snrfreq = freq;
-	event_bitmap |= subscribed ? 0x0020 : 0x0;
-	event->events = cpu_to_le16(event_bitmap);
-
-	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->waitq);
-
-	/* Sleep until response is generated by FW */
-	wait_event_interruptible(pcmdnode->cmdwait_q,
-				 pcmdnode->cmdwaitqwoken);
-
-	pcmdptr = response_buf;
-
-	if (pcmdptr->result) {
-		lbs_pr_err("%s: fail, result=%d\n", __func__,
-			   le16_to_cpu(pcmdptr->result));
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
+static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
+				   file, userbuf, count, ppos);
+}
 
-	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
-		lbs_pr_err("command response incorrect!\n");
-		kfree(response_buf);
-		free_page(addr);
-		return 0;
-	}
 
-	res = count;
-out_unlock:
-	free_page(addr);
-	return res;
-}
 
-static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
+static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	struct wlan_offset_value offval;
+	struct lbs_private *priv = file->private_data;
+	struct lbs_offset_value offval;
 	ssize_t pos = 0;
 	int ret;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
@@ -1375,23 +603,23 @@ static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
 	offval.offset = priv->mac_offset;
 	offval.value = 0;
 
-	ret = libertas_prepare_and_send_command(priv,
+	ret = lbs_prepare_and_send_command(priv,
 				CMD_MAC_REG_ACCESS, 0,
 				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
 	pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
-				priv->mac_offset, adapter->offsetvalue.value);
+				priv->mac_offset, priv->offsetvalue.value);
 
 	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	free_page(addr);
 	return ret;
 }
 
-static ssize_t libertas_rdmac_write(struct file *file,
+static ssize_t lbs_rdmac_write(struct file *file,
 				    const char __user *userbuf,
 				    size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
+	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
@@ -1408,15 +636,15 @@ out_unlock:
 	return res;
 }
 
-static ssize_t libertas_wrmac_write(struct file *file,
+static ssize_t lbs_wrmac_write(struct file *file,
 				    const char __user *userbuf,
 				    size_t count, loff_t *ppos)
 {
 
-	wlan_private *priv = file->private_data;
+	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
 	u32 offset, value;
-	struct wlan_offset_value offval;
+	struct lbs_offset_value offval;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
 
@@ -1433,7 +661,7 @@ static ssize_t libertas_wrmac_write(struct file *file,
 
 	offval.offset = offset;
 	offval.value = value;
-	res = libertas_prepare_and_send_command(priv,
+	res = lbs_prepare_and_send_command(priv,
 				CMD_MAC_REG_ACCESS, 1,
 				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
@@ -1444,12 +672,11 @@ out_unlock:
 	return res;
 }
 
-static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
+static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	struct wlan_offset_value offval;
+	struct lbs_private *priv = file->private_data;
+	struct lbs_offset_value offval;
 	ssize_t pos = 0;
 	int ret;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
@@ -1458,12 +685,12 @@ static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
 	offval.offset = priv->bbp_offset;
 	offval.value = 0;
 
-	ret = libertas_prepare_and_send_command(priv,
+	ret = lbs_prepare_and_send_command(priv,
 				CMD_BBP_REG_ACCESS, 0,
 				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
 	pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
-				priv->bbp_offset, adapter->offsetvalue.value);
+				priv->bbp_offset, priv->offsetvalue.value);
 
 	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	free_page(addr);
@@ -1471,11 +698,11 @@ static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
 	return ret;
 }
 
-static ssize_t libertas_rdbbp_write(struct file *file,
+static ssize_t lbs_rdbbp_write(struct file *file,
 				    const char __user *userbuf,
 				    size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
+	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
@@ -1492,15 +719,15 @@ out_unlock:
 	return res;
 }
 
-static ssize_t libertas_wrbbp_write(struct file *file,
+static ssize_t lbs_wrbbp_write(struct file *file,
 				    const char __user *userbuf,
 				    size_t count, loff_t *ppos)
 {
 
-	wlan_private *priv = file->private_data;
+	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
 	u32 offset, value;
-	struct wlan_offset_value offval;
+	struct lbs_offset_value offval;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
 
@@ -1517,7 +744,7 @@ static ssize_t libertas_wrbbp_write(struct file *file,
 
 	offval.offset = offset;
 	offval.value = value;
-	res = libertas_prepare_and_send_command(priv,
+	res = lbs_prepare_and_send_command(priv,
 				CMD_BBP_REG_ACCESS, 1,
 				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
@@ -1528,12 +755,11 @@ out_unlock:
 	return res;
 }
 
-static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
+static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
 				  size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
-	wlan_adapter *adapter = priv->adapter;
-	struct wlan_offset_value offval;
+	struct lbs_private *priv = file->private_data;
+	struct lbs_offset_value offval;
 	ssize_t pos = 0;
 	int ret;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
@@ -1542,12 +768,12 @@ static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
 	offval.offset = priv->rf_offset;
 	offval.value = 0;
 
-	ret = libertas_prepare_and_send_command(priv,
+	ret = lbs_prepare_and_send_command(priv,
 				CMD_RF_REG_ACCESS, 0,
 				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
 	pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
-				priv->rf_offset, adapter->offsetvalue.value);
+				priv->rf_offset, priv->offsetvalue.value);
 
 	ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
 	free_page(addr);
@@ -1555,11 +781,11 @@ static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
 	return ret;
 }
 
-static ssize_t libertas_rdrf_write(struct file *file,
+static ssize_t lbs_rdrf_write(struct file *file,
 				    const char __user *userbuf,
 				    size_t count, loff_t *ppos)
 {
-	wlan_private *priv = file->private_data;
+	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
@@ -1576,15 +802,15 @@ out_unlock:
 	return res;
 }
 
-static ssize_t libertas_wrrf_write(struct file *file,
+static ssize_t lbs_wrrf_write(struct file *file,
 				    const char __user *userbuf,
 				    size_t count, loff_t *ppos)
 {
 
-	wlan_private *priv = file->private_data;
+	struct lbs_private *priv = file->private_data;
 	ssize_t res, buf_size;
 	u32 offset, value;
-	struct wlan_offset_value offval;
+	struct lbs_offset_value offval;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
 
@@ -1601,7 +827,7 @@ static ssize_t libertas_wrrf_write(struct file *file,
 
 	offval.offset = offset;
 	offval.value = value;
-	res = libertas_prepare_and_send_command(priv,
+	res = lbs_prepare_and_send_command(priv,
 				CMD_RF_REG_ACCESS, 1,
 				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
@@ -1619,69 +845,69 @@ out_unlock:
 	.write = (fwrite), \
 }
 
-struct libertas_debugfs_files {
+struct lbs_debugfs_files {
 	char *name;
 	int perm;
 	struct file_operations fops;
 };
 
-static struct libertas_debugfs_files debugfs_files[] = {
-	{ "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
-	{ "getscantable", 0444, FOPS(libertas_getscantable,
+static struct lbs_debugfs_files debugfs_files[] = {
+	{ "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
+	{ "getscantable", 0444, FOPS(lbs_getscantable,
 					write_file_dummy), },
-	{ "sleepparams", 0644, FOPS(libertas_sleepparams_read,
-				libertas_sleepparams_write), },
-	{ "extscan", 0600, FOPS(NULL, libertas_extscan), },
-	{ "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
+	{ "sleepparams", 0644, FOPS(lbs_sleepparams_read,
+				lbs_sleepparams_write), },
+	{ "extscan", 0600, FOPS(NULL, lbs_extscan), },
+	{ "setuserscan", 0600, FOPS(NULL, lbs_setuserscan), },
 };
 
-static struct libertas_debugfs_files debugfs_events_files[] = {
-	{"low_rssi", 0644, FOPS(libertas_lowrssi_read,
-				libertas_lowrssi_write), },
-	{"low_snr", 0644, FOPS(libertas_lowsnr_read,
-				libertas_lowsnr_write), },
-	{"failure_count", 0644, FOPS(libertas_failcount_read,
-				libertas_failcount_write), },
-	{"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
-				libertas_bcnmiss_write), },
-	{"high_rssi", 0644, FOPS(libertas_highrssi_read,
-				libertas_highrssi_write), },
-	{"high_snr", 0644, FOPS(libertas_highsnr_read,
-				libertas_highsnr_write), },
+static struct lbs_debugfs_files debugfs_events_files[] = {
+	{"low_rssi", 0644, FOPS(lbs_lowrssi_read,
+				lbs_lowrssi_write), },
+	{"low_snr", 0644, FOPS(lbs_lowsnr_read,
+				lbs_lowsnr_write), },
+	{"failure_count", 0644, FOPS(lbs_failcount_read,
+				lbs_failcount_write), },
+	{"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
+				lbs_bcnmiss_write), },
+	{"high_rssi", 0644, FOPS(lbs_highrssi_read,
+				lbs_highrssi_write), },
+	{"high_snr", 0644, FOPS(lbs_highsnr_read,
+				lbs_highsnr_write), },
 };
 
-static struct libertas_debugfs_files debugfs_regs_files[] = {
-	{"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
-	{"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
-	{"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
-	{"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
-	{"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
-	{"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
+static struct lbs_debugfs_files debugfs_regs_files[] = {
+	{"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
+	{"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
+	{"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
+	{"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
+	{"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
+	{"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
 };
 
-void libertas_debugfs_init(void)
+void lbs_debugfs_init(void)
 {
-	if (!libertas_dir)
-		libertas_dir = debugfs_create_dir("libertas_wireless", NULL);
+	if (!lbs_dir)
+		lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
 
 	return;
 }
 
-void libertas_debugfs_remove(void)
+void lbs_debugfs_remove(void)
 {
-	if (libertas_dir)
-		 debugfs_remove(libertas_dir);
+	if (lbs_dir)
+		 debugfs_remove(lbs_dir);
 	return;
 }
 
-void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
+void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
 {
 	int i;
-	struct libertas_debugfs_files *files;
-	if (!libertas_dir)
+	struct lbs_debugfs_files *files;
+	if (!lbs_dir)
 		goto exit;
 
-	priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
+	priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
 	if (!priv->debugfs_dir)
 		goto exit;
 
@@ -1721,13 +947,13 @@ void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
 	}
 
 #ifdef PROC_DEBUG
-	libertas_debug_init(priv, dev);
+	lbs_debug_init(priv, dev);
 #endif
 exit:
 	return;
 }
 
-void libertas_debugfs_remove_one(wlan_private *priv)
+void lbs_debugfs_remove_one(struct lbs_private *priv)
 {
 	int i;
 
@@ -1754,8 +980,8 @@ void libertas_debugfs_remove_one(wlan_private *priv)
 
 #ifdef PROC_DEBUG
 
-#define item_size(n)	(FIELD_SIZEOF(wlan_adapter, n))
-#define item_addr(n)	(offsetof(wlan_adapter, n))
+#define item_size(n)	(FIELD_SIZEOF(struct lbs_private, n))
+#define item_addr(n)	(offsetof(struct lbs_private, n))
 
 
 struct debug_data {
@@ -1764,7 +990,7 @@ struct debug_data {
 	size_t addr;
 };
 
-/* To debug any member of wlan_adapter, simply add one line here.
+/* To debug any member of struct lbs_private, simply add one line here.
  */
 static struct debug_data items[] = {
 	{"intcounter", item_size(intcounter), item_addr(intcounter)},
@@ -1785,7 +1011,7 @@ static int num_of_items = ARRAY_SIZE(items);
  *  @param data    data to output
  *  @return 	   number of output data
  */
-static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
+static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
 			size_t count, loff_t *ppos)
 {
 	int val = 0;
@@ -1829,7 +1055,7 @@ static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
  *  @param data    data to write
  *  @return 	   number of data
  */
-static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf,
+static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
 			    size_t cnt, loff_t *ppos)
 {
 	int r, i;
@@ -1881,21 +1107,21 @@ static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf,
 	return (ssize_t)cnt;
 }
 
-static struct file_operations libertas_debug_fops = {
+static struct file_operations lbs_debug_fops = {
 	.owner = THIS_MODULE,
 	.open = open_file_generic,
-	.write = wlan_debugfs_write,
-	.read = wlan_debugfs_read,
+	.write = lbs_debugfs_write,
+	.read = lbs_debugfs_read,
 };
 
 /**
  *  @brief create debug proc file
  *
- *  @param priv	   pointer wlan_private
+ *  @param priv	   pointer struct lbs_private
  *  @param dev     pointer net_device
  *  @return 	   N/A
  */
-static void libertas_debug_init(wlan_private * priv, struct net_device *dev)
+static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev)
 {
 	int i;
 
@@ -1903,11 +1129,10 @@ static void libertas_debug_init(wlan_private * priv, struct net_device *dev)
 		return;
 
 	for (i = 0; i < num_of_items; i++)
-		items[i].addr += (size_t) priv->adapter;
+		items[i].addr += (size_t) priv;
 
 	priv->debugfs_debug = debugfs_create_file("debug", 0644,
 						  priv->debugfs_dir, &items[0],
-						  &libertas_debug_fops);
+						  &lbs_debug_fops);
 }
 #endif
-
diff --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h
index 880a11b95d26..f2b9c7ffe0fd 100644
--- a/drivers/net/wireless/libertas/debugfs.h
+++ b/drivers/net/wireless/libertas/debugfs.h
@@ -1,6 +1,10 @@
-void libertas_debugfs_init(void);
-void libertas_debugfs_remove(void);
+#ifndef _LBS_DEBUGFS_H_
+#define _LBS_DEBUGFS_H_
 
-void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev);
-void libertas_debugfs_remove_one(wlan_private *priv);
+void lbs_debugfs_init(void);
+void lbs_debugfs_remove(void);
 
+void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev);
+void lbs_debugfs_remove_one(struct lbs_private *priv);
+
+#endif
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 87fea9d5b90a..aaacd9bd6bd2 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -3,80 +3,74 @@
   *  functions defined in other source files
   */
 
-#ifndef _WLAN_DECL_H_
-#define _WLAN_DECL_H_
+#ifndef _LBS_DECL_H_
+#define _LBS_DECL_H_
 
 #include <linux/device.h>
 
 #include "defs.h"
 
 /** Function Prototype Declaration */
-struct wlan_private;
+struct lbs_private;
 struct sk_buff;
 struct net_device;
-
-int libertas_set_mac_packet_filter(wlan_private * priv);
-
-void libertas_send_tx_feedback(wlan_private * priv);
-
-int libertas_free_cmd_buffer(wlan_private * priv);
 struct cmd_ctrl_node;
-struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv);
+struct cmd_ds_command;
 
-void libertas_set_cmd_ctrl_node(wlan_private * priv,
-		    struct cmd_ctrl_node *ptempnode,
-		    u32 cmd_oid, u16 wait_option, void *pdata_buf);
+int lbs_set_mac_packet_filter(struct lbs_private *priv);
 
-int libertas_prepare_and_send_command(wlan_private * priv,
-			  u16 cmd_no,
-			  u16 cmd_action,
-			  u16 wait_option, u32 cmd_oid, void *pdata_buf);
+void lbs_send_tx_feedback(struct lbs_private *priv);
 
-void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail);
+int lbs_free_cmd_buffer(struct lbs_private *priv);
 
-int libertas_allocate_cmd_buffer(wlan_private * priv);
-int libertas_execute_next_command(wlan_private * priv);
-int libertas_process_event(wlan_private * priv);
-void libertas_interrupt(struct net_device *);
-int libertas_set_radio_control(wlan_private * priv);
-u32 libertas_fw_index_to_data_rate(u8 index);
-u8 libertas_data_rate_to_fw_index(u32 rate);
-void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
+int lbs_prepare_and_send_command(struct lbs_private *priv,
+	u16 cmd_no,
+	u16 cmd_action,
+	u16 wait_option, u32 cmd_oid, void *pdata_buf);
 
-void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
+int lbs_allocate_cmd_buffer(struct lbs_private *priv);
+int lbs_execute_next_command(struct lbs_private *priv);
+int lbs_process_event(struct lbs_private *priv);
+void lbs_interrupt(struct lbs_private *priv);
+int lbs_set_radio_control(struct lbs_private *priv);
+u32 lbs_fw_index_to_data_rate(u8 index);
+u8 lbs_data_rate_to_fw_index(u32 rate);
+void lbs_get_fwversion(struct lbs_private *priv,
+	char *fwversion,
+	int maxlen);
 
 /** The proc fs interface */
-int libertas_process_rx_command(wlan_private * priv);
-int libertas_process_tx(wlan_private * priv, struct sk_buff *skb);
-void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
-					struct cmd_ctrl_node *ptempcmd);
-
-int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band);
-
-int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *);
+int lbs_process_rx_command(struct lbs_private *priv);
+void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd,
+			  int result);
+int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
+int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);
 
-void libertas_ps_sleep(wlan_private * priv, int wait_option);
-void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode);
-void libertas_ps_wakeup(wlan_private * priv, int wait_option);
+int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *);
 
-void libertas_tx_runqueue(wlan_private *priv);
+void lbs_ps_sleep(struct lbs_private *priv, int wait_option);
+void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode);
+void lbs_ps_wakeup(struct lbs_private *priv, int wait_option);
 
-struct chan_freq_power *libertas_find_cfp_by_band_and_channel(
-				wlan_adapter * adapter, u8 band, u16 channel);
+struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
+	struct lbs_private *priv,
+	u8 band,
+	u16 channel);
 
-void libertas_mac_event_disconnected(wlan_private * priv);
+void lbs_mac_event_disconnected(struct lbs_private *priv);
 
-void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str);
+void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
 
 /* main.c */
-struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band,
-						             int *cfp_no);
-wlan_private *libertas_add_card(void *card, struct device *dmdev);
-int libertas_remove_card(wlan_private *priv);
-int libertas_start_card(wlan_private *priv);
-int libertas_stop_card(wlan_private *priv);
-int libertas_add_mesh(wlan_private *priv, struct device *dev);
-void libertas_remove_mesh(wlan_private *priv);
-int libertas_reset_device(wlan_private *priv);
-
-#endif				/* _WLAN_DECL_H_ */
+struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
+	u8 band,
+	int *cfp_no);
+struct lbs_private *lbs_add_card(void *card, struct device *dmdev);
+int lbs_remove_card(struct lbs_private *priv);
+int lbs_start_card(struct lbs_private *priv);
+int lbs_stop_card(struct lbs_private *priv);
+int lbs_reset_device(struct lbs_private *priv);
+void lbs_host_to_card_done(struct lbs_private *priv);
+
+int lbs_update_channel(struct lbs_private *priv);
+#endif
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 3a0c9beefcf8..3053cc2160bc 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -2,8 +2,8 @@
   * This header file contains global constant/enum definitions,
   * global variable declaration.
   */
-#ifndef _WLAN_DEFS_H_
-#define _WLAN_DEFS_H_
+#ifndef _LBS_DEFS_H_
+#define _LBS_DEFS_H_
 
 #include <linux/spinlock.h>
 
@@ -41,11 +41,11 @@
 #define LBS_DEB_HEX	0x00200000
 #define LBS_DEB_SDIO	0x00400000
 
-extern unsigned int libertas_debug;
+extern unsigned int lbs_debug;
 
 #ifdef DEBUG
 #define LBS_DEB_LL(grp, grpnam, fmt, args...) \
-do { if ((libertas_debug & (grp)) == (grp)) \
+do { if ((lbs_debug & (grp)) == (grp)) \
   printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
          in_interrupt() ? " (INT)" : "", ## args); } while (0)
 #else
@@ -96,8 +96,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 	int i = 0;
 
 	if (len &&
-	    (libertas_debug & LBS_DEB_HEX) &&
-	    (libertas_debug & grp))
+	    (lbs_debug & LBS_DEB_HEX) &&
+	    (lbs_debug & grp))
 	{
 		for (i = 1; i <= len; i++) {
 			if ((i & 0xf) == 1) {
@@ -132,15 +132,22 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 */
 
 #define MRVDRV_MAX_MULTICAST_LIST_SIZE	32
-#define MRVDRV_NUM_OF_CMD_BUFFER        10
-#define MRVDRV_SIZE_OF_CMD_BUFFER       (2 * 1024)
+#define LBS_NUM_CMD_BUFFERS             10
+#define LBS_CMD_BUFFER_SIZE             (2 * 1024)
 #define MRVDRV_MAX_CHANNEL_SIZE		14
 #define MRVDRV_ASSOCIATION_TIME_OUT	255
 #define MRVDRV_SNAP_HEADER_LEN          8
 
-#define	WLAN_UPLD_SIZE			2312
+#define	LBS_UPLD_SIZE			2312
 #define DEV_NAME_LEN			32
 
+/* Wake criteria for HOST_SLEEP_CFG command */
+#define EHS_WAKE_ON_BROADCAST_DATA	0x0001
+#define EHS_WAKE_ON_UNICAST_DATA	0x0002
+#define EHS_WAKE_ON_MAC_EVENT		0x0004
+#define EHS_WAKE_ON_MULTICAST_DATA	0x0008
+#define EHS_REMOVE_WAKEUP		0xFFFFFFFF
+
 /** Misc constants */
 /* This section defines 802.11 specific contants */
 
@@ -257,17 +264,11 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 
 #define	MAX_LEDS			8
 
-#define IS_MESH_FRAME(x) (x->cb[6])
-#define SET_MESH_FRAME(x) (x->cb[6]=1)
-#define UNSET_MESH_FRAME(x) (x->cb[6]=0)
-
 /** Global Variable Declaration */
-typedef struct _wlan_private wlan_private;
-typedef struct _wlan_adapter wlan_adapter;
-extern const char libertas_driver_version[];
-extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
+extern const char lbs_driver_version[];
+extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
 
-extern u8 libertas_bg_rates[MAX_RATES];
+extern u8 lbs_bg_rates[MAX_RATES];
 
 /** ENUM definition*/
 /** SNRNF_TYPE */
@@ -284,13 +285,13 @@ enum SNRNF_DATA {
 	MAX_TYPE_AVG
 };
 
-/** WLAN_802_11_POWER_MODE */
-enum WLAN_802_11_POWER_MODE {
-	WLAN802_11POWERMODECAM,
-	WLAN802_11POWERMODEMAX_PSP,
-	WLAN802_11POWERMODEFAST_PSP,
+/** LBS_802_11_POWER_MODE */
+enum LBS_802_11_POWER_MODE {
+	LBS802_11POWERMODECAM,
+	LBS802_11POWERMODEMAX_PSP,
+	LBS802_11POWERMODEFAST_PSP,
 	/*not a real mode, defined as an upper bound */
-	WLAN802_11POWEMODEMAX
+	LBS802_11POWEMODEMAX
 };
 
 /** PS_STATE */
@@ -308,16 +309,16 @@ enum DNLD_STATE {
 	DNLD_CMD_SENT
 };
 
-/** WLAN_MEDIA_STATE */
-enum WLAN_MEDIA_STATE {
-	LIBERTAS_CONNECTED,
-	LIBERTAS_DISCONNECTED
+/** LBS_MEDIA_STATE */
+enum LBS_MEDIA_STATE {
+	LBS_CONNECTED,
+	LBS_DISCONNECTED
 };
 
-/** WLAN_802_11_PRIVACY_FILTER */
-enum WLAN_802_11_PRIVACY_FILTER {
-	WLAN802_11PRIVFILTERACCEPTALL,
-	WLAN802_11PRIVFILTER8021XWEP
+/** LBS_802_11_PRIVACY_FILTER */
+enum LBS_802_11_PRIVACY_FILTER {
+	LBS802_11PRIVFILTERACCEPTALL,
+	LBS802_11PRIVFILTER8021XWEP
 };
 
 /** mv_ms_type */
@@ -382,4 +383,4 @@ enum SNMP_MIB_VALUE_e {
 #define FWT_DEFAULT_SLEEPMODE 0
 #define FWT_DEFAULT_SNR 0
 
-#endif				/* _WLAN_DEFS_H_ */
+#endif
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 1fb807aa91b9..58d7ef6b5ff5 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -1,21 +1,20 @@
 /**
   * This file contains definitions and data structures specific
   * to Marvell 802.11 NIC. It contains the Device Information
-  * structure wlan_adapter.
+  * structure struct lbs_private..
   */
-#ifndef _WLAN_DEV_H_
-#define _WLAN_DEV_H_
+#ifndef _LBS_DEV_H_
+#define _LBS_DEV_H_
 
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <linux/ethtool.h>
 #include <linux/debugfs.h>
-#include <net/ieee80211.h>
 
 #include "defs.h"
 #include "scan.h"
 
-extern struct ethtool_ops libertas_ethtool_ops;
+extern struct ethtool_ops lbs_ethtool_ops;
 
 #define	MAX_BSSID_PER_CHANNEL		16
 
@@ -53,7 +52,7 @@ struct region_channel {
 	struct chan_freq_power *CFP;
 };
 
-struct wlan_802_11_security {
+struct lbs_802_11_security {
 	u8 WPAenabled;
 	u8 WPA2enabled;
 	u8 wep_enabled;
@@ -78,16 +77,16 @@ struct current_bss_params {
 
 /** sleep_params */
 struct sleep_params {
-	u16 sp_error;
-	u16 sp_offset;
-	u16 sp_stabletime;
-	u8 sp_calcontrol;
-	u8 sp_extsleepclk;
-	u16 sp_reserved;
+	uint16_t sp_error;
+	uint16_t sp_offset;
+	uint16_t sp_stabletime;
+	uint8_t  sp_calcontrol;
+	uint8_t  sp_extsleepclk;
+	uint16_t sp_reserved;
 };
 
 /* Mesh statistics */
-struct wlan_mesh_stats {
+struct lbs_mesh_stats {
 	u32	fwd_bcast_cnt;		/* Fwd: Broadcast counter */
 	u32	fwd_unicast_cnt;	/* Fwd: Unicast counter */
 	u32	fwd_drop_ttl;		/* Fwd: TTL zero */
@@ -99,26 +98,22 @@ struct wlan_mesh_stats {
 };
 
 /** Private structure for the MV device */
-struct _wlan_private {
-	int open;
+struct lbs_private {
 	int mesh_open;
 	int infra_open;
 	int mesh_autostart_enabled;
-	__le16 boot2_version;
 
 	char name[DEV_NAME_LEN];
 
 	void *card;
-	wlan_adapter *adapter;
 	struct net_device *dev;
 
 	struct net_device_stats stats;
 	struct net_device *mesh_dev; /* Virtual device */
 	struct net_device *rtap_net_dev;
-	struct ieee80211_device *ieee;
 
 	struct iw_statistics wstats;
-	struct wlan_mesh_stats mstats;
+	struct lbs_mesh_stats mstats;
 	struct dentry *debugfs_dir;
 	struct dentry *debugfs_debug;
 	struct dentry *debugfs_files[6];
@@ -136,15 +131,13 @@ struct _wlan_private {
 	/** Upload length */
 	u32 upld_len;
 	/* Upload buffer */
-	u8 upld_buf[WLAN_UPLD_SIZE];
+	u8 upld_buf[LBS_UPLD_SIZE];
 	/* Download sent:
 	   bit0 1/0=data_sent/data_tx_done,
 	   bit1 1/0=cmd_sent/cmd_tx_done,
 	   all other bits reserved 0 */
 	u8 dnld_sent;
 
-	struct device *hotplug_device;
-
 	/** thread to service interrupts */
 	struct task_struct *main_thread;
 	wait_queue_head_t waitq;
@@ -155,65 +148,29 @@ struct _wlan_private {
 	struct work_struct sync_channel;
 
 	/** Hardware access */
-	int (*hw_host_to_card) (wlan_private * priv, u8 type, u8 * payload, u16 nb);
-	int (*hw_get_int_status) (wlan_private * priv, u8 *);
-	int (*hw_read_event_cause) (wlan_private *);
-};
+	int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
+	int (*hw_get_int_status) (struct lbs_private *priv, u8 *);
+	int (*hw_read_event_cause) (struct lbs_private *);
 
-/** Association request
- *
- * Encapsulates all the options that describe a specific assocation request
- * or configuration of the wireless card's radio, mode, and security settings.
- */
-struct assoc_request {
-#define ASSOC_FLAG_SSID			1
-#define ASSOC_FLAG_CHANNEL		2
-#define ASSOC_FLAG_BAND			3
-#define ASSOC_FLAG_MODE			4
-#define ASSOC_FLAG_BSSID		5
-#define ASSOC_FLAG_WEP_KEYS		6
-#define ASSOC_FLAG_WEP_TX_KEYIDX	7
-#define ASSOC_FLAG_WPA_MCAST_KEY	8
-#define ASSOC_FLAG_WPA_UCAST_KEY	9
-#define ASSOC_FLAG_SECINFO		10
-#define ASSOC_FLAG_WPA_IE		11
-	unsigned long flags;
+	/* Wake On LAN */
+	uint32_t wol_criteria;
+	uint8_t wol_gpio;
+	uint8_t wol_gap;
 
-	u8 ssid[IW_ESSID_MAX_SIZE + 1];
-	u8 ssid_len;
-	u8 channel;
-	u8 band;
-	u8 mode;
-	u8 bssid[ETH_ALEN];
-
-	/** WEP keys */
-	struct enc_key wep_keys[4];
-	u16 wep_tx_keyidx;
-
-	/** WPA keys */
-	struct enc_key wpa_mcast_key;
-	struct enc_key wpa_unicast_key;
+	/* was struct lbs_adapter from here... */
 
-	struct wlan_802_11_security secinfo;
-
-	/** WPA Information Elements*/
-	u8 wpa_ie[MAX_WPA_IE_LEN];
-	u8 wpa_ie_len;
-
-	/* BSS to associate with for infrastructure of Ad-Hoc join */
-	struct bss_descriptor bss;
-};
-
-/** Wlan adapter data structure*/
-struct _wlan_adapter {
+	/** Wlan adapter data structure*/
 	/** STATUS variables */
-	u8 fwreleasenumber[4];
+	u32 fwrelease;
 	u32 fwcapinfo;
 	/* protected with big lock */
 
 	struct mutex lock;
 
-	u8 tmptxbuf[WLAN_UPLD_SIZE];
+	/* TX packet ready to be sent... */
+	int tx_pending_len;		/* -1 while building packet */
+
+	u8 tx_pending_buf[LBS_UPLD_SIZE];
 	/* protected by hard_start_xmit serialization */
 
 	/** command-related variables */
@@ -231,8 +188,7 @@ struct _wlan_adapter {
 	struct list_head cmdpendingq;
 
 	wait_queue_head_t cmd_pending;
-	u8 nr_cmd_pending;
-	/* command related variables protected by adapter->driver_lock */
+	/* command related variables protected by priv->driver_lock */
 
 	/** Async and Sync Event variables */
 	u32 intcounter;
@@ -244,17 +200,18 @@ struct _wlan_adapter {
 
 	/** Timers */
 	struct timer_list command_timer;
-
-	/* TX queue used in PS mode */
-	spinlock_t txqueue_lock;
-	struct sk_buff *tx_queue_ps[NR_TX_QUEUE];
-	unsigned int tx_queue_idx;
+	int nr_retries;
+	int cmd_timed_out;
 
 	u8 hisregcpy;
 
 	/** current ssid/bssid related parameters*/
 	struct current_bss_params curbssparams;
 
+	uint16_t mesh_tlv;
+	u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1];
+	u8 mesh_ssid_len;
+
 	/* IW_MODE_* */
 	u8 mode;
 
@@ -263,6 +220,8 @@ struct _wlan_adapter {
 	struct list_head network_free_list;
 	struct bss_descriptor *networks;
 
+	u16 beacon_period;
+	u8 beacon_enable;
 	u8 adhoccreate;
 
 	/** capability Info used in Association, start, join */
@@ -286,11 +245,11 @@ struct _wlan_adapter {
 
 	/** Tx-related variables (for single packet tx) */
 	struct sk_buff *currenttxskb;
-	u16 TxLockFlag;
 
 	/** NIC Operation characteristics */
 	u16 currentpacketfilter;
 	u32 connect_status;
+	u32 mesh_connect_status;
 	u16 regioncode;
 	u16 txpowerlevel;
 
@@ -300,15 +259,17 @@ struct _wlan_adapter {
 	u16 psmode;		/* Wlan802_11PowermodeCAM=disable
 				   Wlan802_11PowermodeMAX_PSP=enable */
 	u32 psstate;
+	char ps_supported;
 	u8 needtowakeup;
 
-	struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep;
+	struct PS_CMD_ConfirmSleep lbs_ps_confirm_sleep;
+	struct cmd_header lbs_ps_confirm_wake;
 
 	struct assoc_request * pending_assoc_req;
 	struct assoc_request * in_progress_assoc_req;
 
 	/** Encryption parameter */
-	struct wlan_802_11_security secinfo;
+	struct lbs_802_11_security secinfo;
 
 	/** WEP keys */
 	struct enc_key wep_keys[4];
@@ -338,9 +299,6 @@ struct _wlan_adapter {
 	u8 cur_rate;
 	u8 auto_rate;
 
-	/** sleep_params */
-	struct sleep_params sp;
-
 	/** RF calibration data */
 
 #define	MAX_REGION_CHANNEL_NUM	2
@@ -350,7 +308,7 @@ struct _wlan_adapter {
 	struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
 
 	/** 11D and Domain Regulatory Data */
-	struct wlan_802_11d_domain_reg domainreg;
+	struct lbs_802_11d_domain_reg domainreg;
 	struct parsed_region_chan_11d parsed_region_chan;
 
 	/** FSM variable for 11d support */
@@ -358,14 +316,57 @@ struct _wlan_adapter {
 
 	/**	MISCELLANEOUS */
 	u8 *prdeeprom;
-	struct wlan_offset_value offsetvalue;
+	struct lbs_offset_value offsetvalue;
 
 	struct cmd_ds_802_11_get_log logmsg;
 
 	u32 monitormode;
+	int last_scanned_channel;
 	u8 fw_ready;
+};
+
+/** Association request
+ *
+ * Encapsulates all the options that describe a specific assocation request
+ * or configuration of the wireless card's radio, mode, and security settings.
+ */
+struct assoc_request {
+#define ASSOC_FLAG_SSID			1
+#define ASSOC_FLAG_CHANNEL		2
+#define ASSOC_FLAG_BAND			3
+#define ASSOC_FLAG_MODE			4
+#define ASSOC_FLAG_BSSID		5
+#define ASSOC_FLAG_WEP_KEYS		6
+#define ASSOC_FLAG_WEP_TX_KEYIDX	7
+#define ASSOC_FLAG_WPA_MCAST_KEY	8
+#define ASSOC_FLAG_WPA_UCAST_KEY	9
+#define ASSOC_FLAG_SECINFO		10
+#define ASSOC_FLAG_WPA_IE		11
+	unsigned long flags;
 
-	u8 last_scanned_channel;
+	u8 ssid[IW_ESSID_MAX_SIZE + 1];
+	u8 ssid_len;
+	u8 channel;
+	u8 band;
+	u8 mode;
+	u8 bssid[ETH_ALEN];
+
+	/** WEP keys */
+	struct enc_key wep_keys[4];
+	u16 wep_tx_keyidx;
+
+	/** WPA keys */
+	struct enc_key wpa_mcast_key;
+	struct enc_key wpa_unicast_key;
+
+	struct lbs_802_11_security secinfo;
+
+	/** WPA Information Elements*/
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	u8 wpa_ie_len;
+
+	/* BSS to associate with for infrastructure of Ad-Hoc join */
+	struct bss_descriptor bss;
 };
 
-#endif				/* _WLAN_DEV_H_ */
+#endif
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 3dae15211b6a..21e6f988ea81 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -8,6 +8,8 @@
 #include "dev.h"
 #include "join.h"
 #include "wext.h"
+#include "cmd.h"
+
 static const char * mesh_stat_strings[]= {
 			"drop_duplicate_bcast",
 			"drop_ttl_zero",
@@ -19,35 +21,34 @@ static const char * mesh_stat_strings[]= {
 			"tx_failed_cnt"
 };
 
-static void libertas_ethtool_get_drvinfo(struct net_device *dev,
+static void lbs_ethtool_get_drvinfo(struct net_device *dev,
 					 struct ethtool_drvinfo *info)
 {
-	wlan_private *priv = (wlan_private *) dev->priv;
+	struct lbs_private *priv = (struct lbs_private *) dev->priv;
 	char fwver[32];
 
-	libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1);
+	lbs_get_fwversion(priv, fwver, sizeof(fwver) - 1);
 
 	strcpy(info->driver, "libertas");
-	strcpy(info->version, libertas_driver_version);
+	strcpy(info->version, lbs_driver_version);
 	strcpy(info->fw_version, fwver);
 }
 
 /* All 8388 parts have 16KiB EEPROM size at the time of writing.
  * In case that changes this needs fixing.
  */
-#define LIBERTAS_EEPROM_LEN 16384
+#define LBS_EEPROM_LEN 16384
 
-static int libertas_ethtool_get_eeprom_len(struct net_device *dev)
+static int lbs_ethtool_get_eeprom_len(struct net_device *dev)
 {
-	return LIBERTAS_EEPROM_LEN;
+	return LBS_EEPROM_LEN;
 }
 
-static int libertas_ethtool_get_eeprom(struct net_device *dev,
+static int lbs_ethtool_get_eeprom(struct net_device *dev,
                                   struct ethtool_eeprom *eeprom, u8 * bytes)
 {
-	wlan_private *priv = (wlan_private *) dev->priv;
-	wlan_adapter *adapter = priv->adapter;
-	struct wlan_ioctl_regrdwr regctrl;
+	struct lbs_private *priv = (struct lbs_private *) dev->priv;
+	struct lbs_ioctl_regrdwr regctrl;
 	char *ptr;
 	int ret;
 
@@ -55,47 +56,47 @@ static int libertas_ethtool_get_eeprom(struct net_device *dev,
 	regctrl.offset = eeprom->offset;
 	regctrl.NOB = eeprom->len;
 
-	if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN)
+	if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN)
 		return -EINVAL;
 
 //      mutex_lock(&priv->mutex);
 
-	adapter->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
-	if (!adapter->prdeeprom)
+	priv->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
+	if (!priv->prdeeprom)
 		return -ENOMEM;
-	memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
+	memcpy(priv->prdeeprom, &regctrl, sizeof(regctrl));
 
 	/* +14 is for action, offset, and NOB in
 	 * response */
 	lbs_deb_ethtool("action:%d offset: %x NOB: %02x\n",
 	       regctrl.action, regctrl.offset, regctrl.NOB);
 
-	ret = libertas_prepare_and_send_command(priv,
+	ret = lbs_prepare_and_send_command(priv,
 				    CMD_802_11_EEPROM_ACCESS,
 				    regctrl.action,
 				    CMD_OPTION_WAITFORRSP, 0,
 				    &regctrl);
 
 	if (ret) {
-		if (adapter->prdeeprom)
-			kfree(adapter->prdeeprom);
+		if (priv->prdeeprom)
+			kfree(priv->prdeeprom);
 		goto done;
 	}
 
 	mdelay(10);
 
-	ptr = (char *)adapter->prdeeprom;
+	ptr = (char *)priv->prdeeprom;
 
 	/* skip the command header, but include the "value" u32 variable */
-	ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4;
+	ptr = ptr + sizeof(struct lbs_ioctl_regrdwr) - 4;
 
 	/*
 	 * Return the result back to the user
 	 */
 	memcpy(bytes, ptr, eeprom->len);
 
-	if (adapter->prdeeprom)
-		kfree(adapter->prdeeprom);
+	if (priv->prdeeprom)
+		kfree(priv->prdeeprom);
 //	mutex_unlock(&priv->mutex);
 
 	ret = 0;
@@ -105,17 +106,17 @@ done:
         return ret;
 }
 
-static void libertas_ethtool_get_stats(struct net_device * dev,
+static void lbs_ethtool_get_stats(struct net_device * dev,
 				struct ethtool_stats * stats, u64 * data)
 {
-	wlan_private *priv = dev->priv;
+	struct lbs_private *priv = dev->priv;
 	struct cmd_ds_mesh_access mesh_access;
 	int ret;
 
 	lbs_deb_enter(LBS_DEB_ETHTOOL);
 
 	/* Get Mesh Statistics */
-	ret = libertas_prepare_and_send_command(priv,
+	ret = lbs_prepare_and_send_command(priv,
 			CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS,
 			CMD_OPTION_WAITFORRSP, 0, &mesh_access);
 
@@ -143,7 +144,7 @@ static void libertas_ethtool_get_stats(struct net_device * dev,
 	lbs_deb_enter(LBS_DEB_ETHTOOL);
 }
 
-static int libertas_ethtool_get_sset_count(struct net_device * dev, int sset)
+static int lbs_ethtool_get_sset_count(struct net_device * dev, int sset)
 {
 	switch (sset) {
 	case ETH_SS_STATS:
@@ -153,7 +154,7 @@ static int libertas_ethtool_get_sset_count(struct net_device * dev, int sset)
 	}
 }
 
-static void libertas_ethtool_get_strings (struct net_device * dev,
+static void lbs_ethtool_get_strings(struct net_device *dev,
 					  u32 stringset,
 					  u8 * s)
 {
@@ -173,12 +174,57 @@ static void libertas_ethtool_get_strings (struct net_device * dev,
 	lbs_deb_enter(LBS_DEB_ETHTOOL);
 }
 
-struct ethtool_ops libertas_ethtool_ops = {
-	.get_drvinfo = libertas_ethtool_get_drvinfo,
-	.get_eeprom =  libertas_ethtool_get_eeprom,
-	.get_eeprom_len = libertas_ethtool_get_eeprom_len,
-	.get_sset_count = libertas_ethtool_get_sset_count,
-	.get_ethtool_stats = libertas_ethtool_get_stats,
-	.get_strings = libertas_ethtool_get_strings,
+static void lbs_ethtool_get_wol(struct net_device *dev,
+				struct ethtool_wolinfo *wol)
+{
+	struct lbs_private *priv = dev->priv;
+
+	if (priv->wol_criteria == 0xffffffff) {
+		/* Interface driver didn't configure wake */
+		wol->supported = wol->wolopts = 0;
+		return;
+	}
+
+	wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
+
+	if (priv->wol_criteria & EHS_WAKE_ON_UNICAST_DATA)
+		wol->wolopts |= WAKE_UCAST;
+	if (priv->wol_criteria & EHS_WAKE_ON_MULTICAST_DATA)
+		wol->wolopts |= WAKE_MCAST;
+	if (priv->wol_criteria & EHS_WAKE_ON_BROADCAST_DATA)
+		wol->wolopts |= WAKE_BCAST;
+	if (priv->wol_criteria & EHS_WAKE_ON_MAC_EVENT)
+		wol->wolopts |= WAKE_PHY;
+}
+
+static int lbs_ethtool_set_wol(struct net_device *dev,
+			       struct ethtool_wolinfo *wol)
+{
+	struct lbs_private *priv = dev->priv;
+	uint32_t criteria = 0;
+
+	if (priv->wol_criteria == 0xffffffff && wol->wolopts)
+		return -EOPNOTSUPP;
+
+	if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
+		return -EOPNOTSUPP;
+
+	if (wol->wolopts & WAKE_UCAST) criteria |= EHS_WAKE_ON_UNICAST_DATA;
+	if (wol->wolopts & WAKE_MCAST) criteria |= EHS_WAKE_ON_MULTICAST_DATA;
+	if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA;
+	if (wol->wolopts & WAKE_PHY)   criteria |= EHS_WAKE_ON_MAC_EVENT;
+
+	return lbs_host_sleep_cfg(priv, criteria);
+}
+
+struct ethtool_ops lbs_ethtool_ops = {
+	.get_drvinfo = lbs_ethtool_get_drvinfo,
+	.get_eeprom =  lbs_ethtool_get_eeprom,
+	.get_eeprom_len = lbs_ethtool_get_eeprom_len,
+	.get_sset_count = lbs_ethtool_get_sset_count,
+	.get_ethtool_stats = lbs_ethtool_get_stats,
+	.get_strings = lbs_ethtool_get_strings,
+	.get_wol = lbs_ethtool_get_wol,
+	.set_wol = lbs_ethtool_set_wol,
 };
 
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index b37ddbca969f..1aa04076b1ac 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -2,25 +2,25 @@
   * This file contains definitions of WLAN commands.
   */
 
-#ifndef _HOST_H_
-#define _HOST_H_
+#ifndef _LBS_HOST_H_
+#define _LBS_HOST_H_
 
 /** PUBLIC DEFINITIONS */
-#define DEFAULT_AD_HOC_CHANNEL       6
-#define DEFAULT_AD_HOC_CHANNEL_A    36
+#define DEFAULT_AD_HOC_CHANNEL			6
+#define	DEFAULT_AD_HOC_CHANNEL_A		36
 
 /** IEEE 802.11 oids */
-#define OID_802_11_SSID                       0x00008002
-#define OID_802_11_INFRASTRUCTURE_MODE        0x00008008
-#define OID_802_11_FRAGMENTATION_THRESHOLD    0x00008009
-#define OID_802_11_RTS_THRESHOLD              0x0000800A
-#define OID_802_11_TX_ANTENNA_SELECTED        0x0000800D
-#define OID_802_11_SUPPORTED_RATES            0x0000800E
-#define OID_802_11_STATISTICS                 0x00008012
-#define OID_802_11_TX_RETRYCOUNT              0x0000801D
-#define OID_802_11D_ENABLE                    0x00008020
-
-#define CMD_OPTION_WAITFORRSP             0x0002
+#define OID_802_11_SSID				0x00008002
+#define OID_802_11_INFRASTRUCTURE_MODE		0x00008008
+#define OID_802_11_FRAGMENTATION_THRESHOLD	0x00008009
+#define OID_802_11_RTS_THRESHOLD		0x0000800A
+#define OID_802_11_TX_ANTENNA_SELECTED		0x0000800D
+#define OID_802_11_SUPPORTED_RATES		0x0000800E
+#define OID_802_11_STATISTICS			0x00008012
+#define OID_802_11_TX_RETRYCOUNT		0x0000801D
+#define OID_802_11D_ENABLE			0x00008020
+
+#define CMD_OPTION_WAITFORRSP			0x0002
 
 /** Host command IDs */
 
@@ -30,192 +30,189 @@
 #define CMD_RET(cmd)			(0x8000 | cmd)
 
 /* Return command convention exceptions: */
-#define CMD_RET_802_11_ASSOCIATE      0x8012
+#define CMD_RET_802_11_ASSOCIATE		0x8012
 
 /* Command codes */
-#define CMD_CODE_DNLD                 0x0002
-#define CMD_GET_HW_SPEC               0x0003
-#define CMD_EEPROM_UPDATE             0x0004
-#define CMD_802_11_RESET              0x0005
-#define CMD_802_11_SCAN               0x0006
-#define CMD_802_11_GET_LOG            0x000b
-#define CMD_MAC_MULTICAST_ADR         0x0010
-#define CMD_802_11_AUTHENTICATE       0x0011
-#define CMD_802_11_EEPROM_ACCESS      0x0059
-#define CMD_802_11_ASSOCIATE          0x0050
-#define CMD_802_11_SET_WEP            0x0013
-#define CMD_802_11_GET_STAT           0x0014
-#define CMD_802_3_GET_STAT            0x0015
-#define CMD_802_11_SNMP_MIB           0x0016
-#define CMD_MAC_REG_MAP               0x0017
-#define CMD_BBP_REG_MAP               0x0018
-#define CMD_MAC_REG_ACCESS            0x0019
-#define CMD_BBP_REG_ACCESS            0x001a
-#define CMD_RF_REG_ACCESS             0x001b
-#define CMD_802_11_RADIO_CONTROL      0x001c
-#define CMD_802_11_RF_CHANNEL         0x001d
-#define CMD_802_11_RF_TX_POWER        0x001e
-#define CMD_802_11_RSSI               0x001f
-#define CMD_802_11_RF_ANTENNA         0x0020
-
-#define CMD_802_11_PS_MODE	      0x0021
-
-#define CMD_802_11_DATA_RATE          0x0022
-#define CMD_RF_REG_MAP                0x0023
-#define CMD_802_11_DEAUTHENTICATE     0x0024
-#define CMD_802_11_REASSOCIATE        0x0025
-#define CMD_802_11_DISASSOCIATE       0x0026
-#define CMD_MAC_CONTROL               0x0028
-#define CMD_802_11_AD_HOC_START       0x002b
-#define CMD_802_11_AD_HOC_JOIN        0x002c
-
-#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS  0x002e
-#define CMD_802_11_ENABLE_RSN              0x002f
-#define CMD_802_11_PAIRWISE_TSC       0x0036
-#define CMD_802_11_GROUP_TSC          0x0037
-#define CMD_802_11_KEY_MATERIAL       0x005e
-
-#define CMD_802_11_SET_AFC            0x003c
-#define CMD_802_11_GET_AFC            0x003d
-
-#define CMD_802_11_AD_HOC_STOP        0x0040
-
-#define CMD_802_11_BEACON_STOP        0x0049
-
-#define CMD_802_11_MAC_ADDRESS        0x004D
-#define CMD_802_11_EEPROM_ACCESS      0x0059
-
-#define CMD_802_11_BAND_CONFIG        0x0058
-
-#define CMD_802_11D_DOMAIN_INFO       0x005b
-
-#define CMD_802_11_SLEEP_PARAMS          0x0066
-
-#define CMD_802_11_INACTIVITY_TIMEOUT    0x0067
-
-#define CMD_802_11_TPC_CFG               0x0072
-#define CMD_802_11_PWR_CFG               0x0073
-
-#define CMD_802_11_LED_GPIO_CTRL         0x004e
-
-#define CMD_802_11_SUBSCRIBE_EVENT       0x0075
-
-#define CMD_802_11_RATE_ADAPT_RATESET    0x0076
-
-#define CMD_802_11_TX_RATE_QUERY	0x007f
-
-#define CMD_GET_TSF                      0x0080
-
-#define CMD_BT_ACCESS                 0x0087
-
-#define CMD_FWT_ACCESS                0x0095
-
-#define CMD_802_11_MONITOR_MODE       0x0098
-
-#define CMD_MESH_ACCESS               0x009b
-
-#define CMD_SET_BOOT2_VER                 0x00a5
+#define CMD_CODE_DNLD				0x0002
+#define CMD_GET_HW_SPEC				0x0003
+#define	CMD_EEPROM_UPDATE			0x0004
+#define CMD_802_11_RESET			0x0005
+#define	CMD_802_11_SCAN				0x0006
+#define CMD_802_11_GET_LOG			0x000b
+#define CMD_MAC_MULTICAST_ADR			0x0010
+#define CMD_802_11_AUTHENTICATE			0x0011
+#define CMD_802_11_EEPROM_ACCESS		0x0059
+#define CMD_802_11_ASSOCIATE			0x0050
+#define CMD_802_11_SET_WEP			0x0013
+#define CMD_802_11_GET_STAT			0x0014
+#define CMD_802_3_GET_STAT			0x0015
+#define CMD_802_11_SNMP_MIB			0x0016
+#define CMD_MAC_REG_MAP				0x0017
+#define CMD_BBP_REG_MAP				0x0018
+#define CMD_MAC_REG_ACCESS			0x0019
+#define CMD_BBP_REG_ACCESS			0x001a
+#define CMD_RF_REG_ACCESS			0x001b
+#define CMD_802_11_RADIO_CONTROL		0x001c
+#define CMD_802_11_RF_CHANNEL			0x001d
+#define CMD_802_11_RF_TX_POWER			0x001e
+#define CMD_802_11_RSSI				0x001f
+#define CMD_802_11_RF_ANTENNA			0x0020
+#define CMD_802_11_PS_MODE			0x0021
+#define CMD_802_11_DATA_RATE			0x0022
+#define CMD_RF_REG_MAP				0x0023
+#define CMD_802_11_DEAUTHENTICATE		0x0024
+#define CMD_802_11_REASSOCIATE			0x0025
+#define CMD_802_11_DISASSOCIATE			0x0026
+#define CMD_MAC_CONTROL				0x0028
+#define CMD_802_11_AD_HOC_START			0x002b
+#define CMD_802_11_AD_HOC_JOIN			0x002c
+#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS	0x002e
+#define CMD_802_11_ENABLE_RSN			0x002f
+#define CMD_802_11_PAIRWISE_TSC			0x0036
+#define CMD_802_11_GROUP_TSC			0x0037
+#define CMD_802_11_SET_AFC			0x003c
+#define CMD_802_11_GET_AFC			0x003d
+#define CMD_802_11_AD_HOC_STOP			0x0040
+#define CMD_802_11_HOST_SLEEP_CFG		0x0043
+#define CMD_802_11_WAKEUP_CONFIRM		0x0044
+#define CMD_802_11_HOST_SLEEP_ACTIVATE		0x0045
+#define CMD_802_11_BEACON_STOP			0x0049
+#define CMD_802_11_MAC_ADDRESS			0x004d
+#define CMD_802_11_LED_GPIO_CTRL		0x004e
+#define CMD_802_11_EEPROM_ACCESS		0x0059
+#define CMD_802_11_BAND_CONFIG			0x0058
+#define CMD_802_11D_DOMAIN_INFO			0x005b
+#define CMD_802_11_KEY_MATERIAL			0x005e
+#define CMD_802_11_SLEEP_PARAMS			0x0066
+#define CMD_802_11_INACTIVITY_TIMEOUT		0x0067
+#define CMD_802_11_SLEEP_PERIOD			0x0068
+#define CMD_802_11_TPC_CFG			0x0072
+#define CMD_802_11_PWR_CFG			0x0073
+#define CMD_802_11_FW_WAKE_METHOD		0x0074
+#define CMD_802_11_SUBSCRIBE_EVENT		0x0075
+#define CMD_802_11_RATE_ADAPT_RATESET		0x0076
+#define CMD_802_11_TX_RATE_QUERY		0x007f
+#define	CMD_GET_TSF				0x0080
+#define CMD_BT_ACCESS				0x0087
+#define CMD_FWT_ACCESS				0x0095
+#define CMD_802_11_MONITOR_MODE			0x0098
+#define CMD_MESH_ACCESS				0x009b
+#define CMD_MESH_CONFIG				0x00a3
+#define	CMD_SET_BOOT2_VER			0x00a5
+#define CMD_802_11_BEACON_CTRL			0x00b0
 
 /* For the IEEE Power Save */
-#define CMD_SUBCMD_ENTER_PS               0x0030
-#define CMD_SUBCMD_EXIT_PS                0x0031
-#define CMD_SUBCMD_SLEEP_CONFIRMED        0x0034
-#define CMD_SUBCMD_FULL_POWERDOWN         0x0035
-#define CMD_SUBCMD_FULL_POWERUP           0x0036
-
-#define CMD_ENABLE_RSN                    0x0001
-#define CMD_DISABLE_RSN                   0x0000
+#define CMD_SUBCMD_ENTER_PS		0x0030
+#define CMD_SUBCMD_EXIT_PS		0x0031
+#define CMD_SUBCMD_SLEEP_CONFIRMED	0x0034
+#define CMD_SUBCMD_FULL_POWERDOWN	0x0035
+#define CMD_SUBCMD_FULL_POWERUP		0x0036
 
-#define CMD_ACT_SET                       0x0001
-#define CMD_ACT_GET                       0x0000
+#define CMD_ENABLE_RSN			0x0001
+#define CMD_DISABLE_RSN			0x0000
 
-#define CMD_ACT_GET_AES                   (CMD_ACT_GET + 2)
-#define CMD_ACT_SET_AES                   (CMD_ACT_SET + 2)
-#define CMD_ACT_REMOVE_AES                (CMD_ACT_SET + 3)
+#define CMD_ACT_GET			0x0000
+#define CMD_ACT_SET			0x0001
+#define CMD_ACT_GET_AES			0x0002
+#define CMD_ACT_SET_AES			0x0003
+#define CMD_ACT_REMOVE_AES		0x0004
 
 /* Define action or option for CMD_802_11_SET_WEP */
-#define CMD_ACT_ADD                         0x0002
-#define CMD_ACT_REMOVE                      0x0004
-#define CMD_ACT_USE_DEFAULT                 0x0008
+#define CMD_ACT_ADD			0x0002
+#define CMD_ACT_REMOVE			0x0004
+#define CMD_ACT_USE_DEFAULT		0x0008
 
-#define CMD_TYPE_WEP_40_BIT                 0x01
-#define CMD_TYPE_WEP_104_BIT                0x02
+#define CMD_TYPE_WEP_40_BIT		0x01
+#define CMD_TYPE_WEP_104_BIT		0x02
 
-#define CMD_NUM_OF_WEP_KEYS                 4
+#define CMD_NUM_OF_WEP_KEYS		4
 
-#define CMD_WEP_KEY_INDEX_MASK              0x3fff
+#define CMD_WEP_KEY_INDEX_MASK		0x3fff
 
 /* Define action or option for CMD_802_11_RESET */
-#define CMD_ACT_HALT                        0x0003
+#define CMD_ACT_HALT			0x0003
 
 /* Define action or option for CMD_802_11_SCAN */
-#define CMD_BSS_TYPE_BSS                    0x0001
-#define CMD_BSS_TYPE_IBSS                   0x0002
-#define CMD_BSS_TYPE_ANY                    0x0003
+#define CMD_BSS_TYPE_BSS		0x0001
+#define CMD_BSS_TYPE_IBSS		0x0002
+#define CMD_BSS_TYPE_ANY		0x0003
 
 /* Define action or option for CMD_802_11_SCAN */
-#define CMD_SCAN_TYPE_ACTIVE                0x0000
-#define CMD_SCAN_TYPE_PASSIVE               0x0001
+#define CMD_SCAN_TYPE_ACTIVE		0x0000
+#define CMD_SCAN_TYPE_PASSIVE		0x0001
 
 #define CMD_SCAN_RADIO_TYPE_BG		0
 
-#define CMD_SCAN_PROBE_DELAY_TIME           0
+#define	CMD_SCAN_PROBE_DELAY_TIME	0
 
 /* Define action or option for CMD_MAC_CONTROL */
-#define CMD_ACT_MAC_RX_ON                   0x0001
-#define CMD_ACT_MAC_TX_ON                   0x0002
-#define CMD_ACT_MAC_LOOPBACK_ON             0x0004
-#define CMD_ACT_MAC_WEP_ENABLE              0x0008
-#define CMD_ACT_MAC_INT_ENABLE              0x0010
-#define CMD_ACT_MAC_MULTICAST_ENABLE        0x0020
-#define CMD_ACT_MAC_BROADCAST_ENABLE        0x0040
-#define CMD_ACT_MAC_PROMISCUOUS_ENABLE      0x0080
-#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE    0x0100
-#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE  0x0400
+#define CMD_ACT_MAC_RX_ON			0x0001
+#define CMD_ACT_MAC_TX_ON			0x0002
+#define CMD_ACT_MAC_LOOPBACK_ON			0x0004
+#define CMD_ACT_MAC_WEP_ENABLE			0x0008
+#define CMD_ACT_MAC_INT_ENABLE			0x0010
+#define CMD_ACT_MAC_MULTICAST_ENABLE		0x0020
+#define CMD_ACT_MAC_BROADCAST_ENABLE		0x0040
+#define CMD_ACT_MAC_PROMISCUOUS_ENABLE		0x0080
+#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE	0x0100
+#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE	0x0400
 
 /* Define action or option for CMD_802_11_RADIO_CONTROL */
-#define CMD_TYPE_AUTO_PREAMBLE              0x0001
-#define CMD_TYPE_SHORT_PREAMBLE             0x0002
-#define CMD_TYPE_LONG_PREAMBLE              0x0003
-
-#define TURN_ON_RF                              0x01
-#define RADIO_ON                                0x01
-#define RADIO_OFF                               0x00
-
-#define SET_AUTO_PREAMBLE                       0x05
-#define SET_SHORT_PREAMBLE                      0x03
-#define SET_LONG_PREAMBLE                       0x01
+#define CMD_TYPE_AUTO_PREAMBLE		0x0001
+#define CMD_TYPE_SHORT_PREAMBLE		0x0002
+#define CMD_TYPE_LONG_PREAMBLE		0x0003
+
+/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */
+#define CMD_SUBSCRIBE_RSSI_LOW		0x0001
+#define CMD_SUBSCRIBE_SNR_LOW		0x0002
+#define CMD_SUBSCRIBE_FAILCOUNT		0x0004
+#define CMD_SUBSCRIBE_BCNMISS		0x0008
+#define CMD_SUBSCRIBE_RSSI_HIGH		0x0010
+#define CMD_SUBSCRIBE_SNR_HIGH		0x0020
+
+#define TURN_ON_RF			0x01
+#define RADIO_ON			0x01
+#define RADIO_OFF			0x00
+
+#define SET_AUTO_PREAMBLE		0x05
+#define SET_SHORT_PREAMBLE		0x03
+#define SET_LONG_PREAMBLE		0x01
 
 /* Define action or option for CMD_802_11_RF_CHANNEL */
-#define CMD_OPT_802_11_RF_CHANNEL_GET       0x00
-#define CMD_OPT_802_11_RF_CHANNEL_SET       0x01
+#define CMD_OPT_802_11_RF_CHANNEL_GET	0x00
+#define CMD_OPT_802_11_RF_CHANNEL_SET	0x01
 
 /* Define action or option for CMD_802_11_RF_TX_POWER */
-#define CMD_ACT_TX_POWER_OPT_GET            0x0000
-#define CMD_ACT_TX_POWER_OPT_SET_HIGH       0x8007
-#define CMD_ACT_TX_POWER_OPT_SET_MID        0x8004
-#define CMD_ACT_TX_POWER_OPT_SET_LOW        0x8000
+#define CMD_ACT_TX_POWER_OPT_GET	0x0000
+#define CMD_ACT_TX_POWER_OPT_SET_HIGH	0x8007
+#define CMD_ACT_TX_POWER_OPT_SET_MID	0x8004
+#define CMD_ACT_TX_POWER_OPT_SET_LOW	0x8000
 
-#define CMD_ACT_TX_POWER_INDEX_HIGH         0x0007
-#define CMD_ACT_TX_POWER_INDEX_MID          0x0004
-#define CMD_ACT_TX_POWER_INDEX_LOW          0x0000
+#define CMD_ACT_TX_POWER_INDEX_HIGH	0x0007
+#define CMD_ACT_TX_POWER_INDEX_MID	0x0004
+#define CMD_ACT_TX_POWER_INDEX_LOW	0x0000
 
 /* Define action or option for CMD_802_11_DATA_RATE */
-#define CMD_ACT_SET_TX_AUTO                 0x0000
-#define CMD_ACT_SET_TX_FIX_RATE             0x0001
-#define CMD_ACT_GET_TX_RATE                 0x0002
+#define CMD_ACT_SET_TX_AUTO		0x0000
+#define CMD_ACT_SET_TX_FIX_RATE		0x0001
+#define CMD_ACT_GET_TX_RATE		0x0002
 
-#define CMD_ACT_SET_RX                      0x0001
-#define CMD_ACT_SET_TX                      0x0002
-#define CMD_ACT_SET_BOTH                    0x0003
-#define CMD_ACT_GET_RX                      0x0004
-#define CMD_ACT_GET_TX                      0x0008
-#define CMD_ACT_GET_BOTH                    0x000c
+#define CMD_ACT_SET_RX			0x0001
+#define	CMD_ACT_SET_TX			0x0002
+#define CMD_ACT_SET_BOTH		0x0003
+#define	CMD_ACT_GET_RX			0x0004
+#define CMD_ACT_GET_TX			0x0008
+#define	CMD_ACT_GET_BOTH		0x000c
 
 /* Define action or option for CMD_802_11_PS_MODE */
-#define CMD_TYPE_CAM                        0x0000
-#define CMD_TYPE_MAX_PSP                    0x0001
-#define CMD_TYPE_FAST_PSP                   0x0002
+#define CMD_TYPE_CAM			0x0000
+#define	CMD_TYPE_MAX_PSP		0x0001
+#define CMD_TYPE_FAST_PSP		0x0002
+
+/* Options for CMD_802_11_FW_WAKE_METHOD */
+#define CMD_WAKE_METHOD_UNCHANGED	0x0000
+#define CMD_WAKE_METHOD_COMMAND_INT	0x0001
+#define CMD_WAKE_METHOD_GPIO		0x0002
 
 /* Define action or option for CMD_BT_ACCESS */
 enum cmd_bt_access_opts {
@@ -237,8 +234,8 @@ enum cmd_fwt_access_opts {
 	CMD_ACT_FWT_ACCESS_DEL,
 	CMD_ACT_FWT_ACCESS_LOOKUP,
 	CMD_ACT_FWT_ACCESS_LIST,
-	CMD_ACT_FWT_ACCESS_LIST_route,
-	CMD_ACT_FWT_ACCESS_LIST_neighbor,
+	CMD_ACT_FWT_ACCESS_LIST_ROUTE,
+	CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR,
 	CMD_ACT_FWT_ACCESS_RESET,
 	CMD_ACT_FWT_ACCESS_CLEANUP,
 	CMD_ACT_FWT_ACCESS_TIME,
@@ -264,27 +261,36 @@ enum cmd_mesh_access_opts {
 };
 
 /** Card Event definition */
-#define MACREG_INT_CODE_TX_PPA_FREE             0x00000000
-#define MACREG_INT_CODE_TX_DMA_DONE             0x00000001
-#define MACREG_INT_CODE_LINK_LOSE_W_SCAN        0x00000002
-#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN       0x00000003
-#define MACREG_INT_CODE_LINK_SENSED             0x00000004
-#define MACREG_INT_CODE_CMD_FINISHED            0x00000005
-#define MACREG_INT_CODE_MIB_CHANGED             0x00000006
-#define MACREG_INT_CODE_INIT_DONE               0x00000007
-#define MACREG_INT_CODE_DEAUTHENTICATED         0x00000008
-#define MACREG_INT_CODE_DISASSOCIATED           0x00000009
-#define MACREG_INT_CODE_PS_AWAKE                0x0000000a
-#define MACREG_INT_CODE_PS_SLEEP                0x0000000b
-#define MACREG_INT_CODE_MIC_ERR_MULTICAST       0x0000000d
-#define MACREG_INT_CODE_MIC_ERR_UNICAST         0x0000000e
-#define MACREG_INT_CODE_WM_AWAKE                0x0000000f
-#define MACREG_INT_CODE_ADHOC_BCN_LOST          0x00000011
-#define MACREG_INT_CODE_RSSI_LOW		0x00000019
-#define MACREG_INT_CODE_SNR_LOW			0x0000001a
-#define MACREG_INT_CODE_MAX_FAIL		0x0000001b
-#define MACREG_INT_CODE_RSSI_HIGH		0x0000001c
-#define MACREG_INT_CODE_SNR_HIGH		0x0000001d
-#define MACREG_INT_CODE_MESH_AUTO_STARTED	0x00000023
-
-#endif				/* _HOST_H_ */
+#define MACREG_INT_CODE_TX_PPA_FREE		0
+#define MACREG_INT_CODE_TX_DMA_DONE		1
+#define MACREG_INT_CODE_LINK_LOST_W_SCAN	2
+#define MACREG_INT_CODE_LINK_LOST_NO_SCAN	3
+#define MACREG_INT_CODE_LINK_SENSED		4
+#define MACREG_INT_CODE_CMD_FINISHED		5
+#define MACREG_INT_CODE_MIB_CHANGED		6
+#define MACREG_INT_CODE_INIT_DONE		7
+#define MACREG_INT_CODE_DEAUTHENTICATED		8
+#define MACREG_INT_CODE_DISASSOCIATED		9
+#define MACREG_INT_CODE_PS_AWAKE		10
+#define MACREG_INT_CODE_PS_SLEEP		11
+#define MACREG_INT_CODE_MIC_ERR_MULTICAST	13
+#define MACREG_INT_CODE_MIC_ERR_UNICAST		14
+#define MACREG_INT_CODE_WM_AWAKE		15
+#define MACREG_INT_CODE_DEEP_SLEEP_AWAKE	16
+#define MACREG_INT_CODE_ADHOC_BCN_LOST		17
+#define MACREG_INT_CODE_HOST_AWAKE		18
+#define MACREG_INT_CODE_STOP_TX			19
+#define MACREG_INT_CODE_START_TX		20
+#define MACREG_INT_CODE_CHANNEL_SWITCH		21
+#define MACREG_INT_CODE_MEASUREMENT_RDY		22
+#define MACREG_INT_CODE_WMM_CHANGE		23
+#define MACREG_INT_CODE_BG_SCAN_REPORT		24
+#define MACREG_INT_CODE_RSSI_LOW		25
+#define MACREG_INT_CODE_SNR_LOW			26
+#define MACREG_INT_CODE_MAX_FAIL		27
+#define MACREG_INT_CODE_RSSI_HIGH		28
+#define MACREG_INT_CODE_SNR_HIGH		29
+#define MACREG_INT_CODE_MESH_AUTO_STARTED	35
+#define MACREG_INT_CODE_FIRMWARE_READY		48
+
+#endif
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index e1045dc02cce..d35b015b6657 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -2,8 +2,8 @@
  * This file contains the function prototypes, data structure
  * and defines for all the host/station commands
  */
-#ifndef __HOSTCMD__H
-#define __HOSTCMD__H
+#ifndef _LBS_HOSTCMD_H
+#define _LBS_HOSTCMD_H
 
 #include <linux/wireless.h>
 #include "11d.h"
@@ -65,19 +65,21 @@ struct rxpd {
 	u8 reserved[3];
 };
 
+struct cmd_header {
+	__le16 command;
+	__le16 size;
+	__le16 seqnum;
+	__le16 result;
+} __attribute__ ((packed));
+
 struct cmd_ctrl_node {
-	/* CMD link list */
 	struct list_head list;
-	u32 status;
-	/* CMD ID */
-	u32 cmd_oid;
-	/*CMD wait option: wait for finish or no wait */
-	u16 wait_option;
-	/* command parameter */
-	void *pdata_buf;
-	/*command data */
-	u8 *bufvirtualaddr;
-	u16 cmdflags;
+	int result;
+	/* command response */
+	int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *);
+	unsigned long callback_arg;
+	/* command data */
+	struct cmd_header *cmdbuf;
 	/* wait queue */
 	u16 cmdwaitqwoken;
 	wait_queue_head_t cmdwait_q;
@@ -86,13 +88,13 @@ struct cmd_ctrl_node {
 /* Generic structure to hold all key types. */
 struct enc_key {
 	u16 len;
-	u16 flags;  /* KEY_INFO_* from wlan_defs.h */
-	u16 type; /* KEY_TYPE_* from wlan_defs.h */
+	u16 flags;  /* KEY_INFO_* from defs.h */
+	u16 type; /* KEY_TYPE_* from defs.h */
 	u8 key[32];
 };
 
-/* wlan_offset_value */
-struct wlan_offset_value {
+/* lbs_offset_value */
+struct lbs_offset_value {
 	u32 offset;
 	u32 value;
 };
@@ -104,14 +106,19 @@ struct cmd_ds_gen {
 	__le16 size;
 	__le16 seqnum;
 	__le16 result;
+	void *cmdresp[0];
 };
 
 #define S_DS_GEN sizeof(struct cmd_ds_gen)
+
+
 /*
  * Define data structure for CMD_GET_HW_SPEC
  * This structure defines the response for the GET_HW_SPEC command
  */
 struct cmd_ds_get_hw_spec {
+	struct cmd_header hdr;
+
 	/* HW Interface version number */
 	__le16 hwifversion;
 	/* HW version number */
@@ -129,8 +136,8 @@ struct cmd_ds_get_hw_spec {
 	/* Number of antenna used */
 	__le16 nr_antenna;
 
-	/* FW release number, example 1,2,3,4 = 3.2.1p4 */
-	u8 fwreleasenumber[4];
+	/* FW release number, example 0x01030304 = 2.3.4p1 */
+	__le32 fwrelease;
 
 	/* Base Address of TxPD queue */
 	__le32 wcb_base;
@@ -149,8 +156,17 @@ struct cmd_ds_802_11_reset {
 };
 
 struct cmd_ds_802_11_subscribe_event {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le16 events;
+
+	/* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a
+	 * number of TLVs. From the v5.1 manual, those TLVs would add up to
+	 * 40 bytes. However, future firmware might add additional TLVs, so I
+	 * bump this up a bit.
+	 */
+	uint8_t tlv[128];
 };
 
 /*
@@ -242,6 +258,8 @@ struct cmd_ds_802_11_ad_hoc_result {
 };
 
 struct cmd_ds_802_11_set_wep {
+	struct cmd_header hdr;
+
 	/* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
 	__le16 action;
 
@@ -249,8 +267,8 @@ struct cmd_ds_802_11_set_wep {
 	__le16 keyindex;
 
 	/* 40, 128bit or TXWEP */
-	u8 keytype[4];
-	u8 keymaterial[4][16];
+	uint8_t keytype[4];
+	uint8_t keymaterial[4][16];
 };
 
 struct cmd_ds_802_3_get_stat {
@@ -328,11 +346,21 @@ struct cmd_ds_rf_reg_access {
 };
 
 struct cmd_ds_802_11_radio_control {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le16 control;
 };
 
+struct cmd_ds_802_11_beacon_control {
+	__le16 action;
+	__le16 beacon_enable;
+	__le16 beacon_period;
+};
+
 struct cmd_ds_802_11_sleep_params {
+	struct cmd_header hdr;
+
 	/* ACT_GET/ACT_SET */
 	__le16 action;
 
@@ -346,16 +374,18 @@ struct cmd_ds_802_11_sleep_params {
 	__le16 stabletime;
 
 	/* control periodic calibration */
-	u8 calcontrol;
+	uint8_t calcontrol;
 
 	/* control the use of external sleep clock */
-	u8 externalsleepclk;
+	uint8_t externalsleepclk;
 
 	/* reserved field, should be set to zero */
 	__le16 reserved;
 };
 
 struct cmd_ds_802_11_inactivity_timeout {
+	struct cmd_header hdr;
+
 	/* ACT_GET/ACT_SET */
 	__le16 action;
 
@@ -364,11 +394,13 @@ struct cmd_ds_802_11_inactivity_timeout {
 };
 
 struct cmd_ds_802_11_rf_channel {
+	struct cmd_header hdr;
+
 	__le16 action;
-	__le16 currentchannel;
-	__le16 rftype;
-	__le16 reserved;
-	u8 channellist[32];
+	__le16 channel;
+	__le16 rftype;      /* unused */
+	__le16 reserved;    /* unused */
+	u8 channellist[32]; /* unused */
 };
 
 struct cmd_ds_802_11_rssi {
@@ -406,13 +438,29 @@ struct cmd_ds_802_11_rf_antenna {
 };
 
 struct cmd_ds_802_11_monitor_mode {
-	u16 action;
-	u16 mode;
+	__le16 action;
+	__le16 mode;
 };
 
 struct cmd_ds_set_boot2_ver {
-	u16 action;
-	u16 version;
+	struct cmd_header hdr;
+
+	__le16 action;
+	__le16 version;
+};
+
+struct cmd_ds_802_11_fw_wake_method {
+	struct cmd_header hdr;
+
+	__le16 action;
+	__le16 method;
+};
+
+struct cmd_ds_802_11_sleep_period {
+	struct cmd_header hdr;
+
+	__le16 action;
+	__le16 period;
 };
 
 struct cmd_ds_802_11_ps_mode {
@@ -437,6 +485,8 @@ struct PS_CMD_ConfirmSleep {
 };
 
 struct cmd_ds_802_11_data_rate {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le16 reserved;
 	u8 rates[MAX_RATES];
@@ -488,6 +538,8 @@ struct cmd_ds_802_11_ad_hoc_join {
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_enable_rsn {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le16 enable;
 } __attribute__ ((packed));
@@ -512,6 +564,13 @@ struct MrvlIEtype_keyParamSet {
 	u8 key[32];
 };
 
+struct cmd_ds_host_sleep {
+	struct cmd_header hdr;
+	__le32 criteria;
+	uint8_t gpio;
+	uint8_t gap;
+} __attribute__ ((packed));
+
 struct cmd_ds_802_11_key_material {
 	__le16 action;
 	struct MrvlIEtype_keyParamSet keyParamSet[2];
@@ -598,7 +657,21 @@ struct cmd_ds_fwt_access {
 	u8 prec[ETH_ALEN];
 } __attribute__ ((packed));
 
+
+struct cmd_ds_mesh_config {
+	struct cmd_header hdr;
+
+        __le16 action;
+        __le16 channel;
+        __le16 type;
+        __le16 length;
+        u8 data[128];   /* last position reserved */
+} __attribute__ ((packed));
+
+
 struct cmd_ds_mesh_access {
+	struct cmd_header hdr;
+
 	__le16 action;
 	__le32 data[32];	/* last position reserved */
 } __attribute__ ((packed));
@@ -615,14 +688,12 @@ struct cmd_ds_command {
 
 	/* command Body */
 	union {
-		struct cmd_ds_get_hw_spec hwspec;
 		struct cmd_ds_802_11_ps_mode psmode;
 		struct cmd_ds_802_11_scan scan;
 		struct cmd_ds_802_11_scan_rsp scanresp;
 		struct cmd_ds_mac_control macctrl;
 		struct cmd_ds_802_11_associate associate;
 		struct cmd_ds_802_11_deauthenticate deauth;
-		struct cmd_ds_802_11_set_wep wep;
 		struct cmd_ds_802_11_ad_hoc_start ads;
 		struct cmd_ds_802_11_reset reset;
 		struct cmd_ds_802_11_ad_hoc_result result;
@@ -634,17 +705,13 @@ struct cmd_ds_command {
 		struct cmd_ds_802_11_rf_tx_power txp;
 		struct cmd_ds_802_11_rf_antenna rant;
 		struct cmd_ds_802_11_monitor_mode monitor;
-		struct cmd_ds_802_11_data_rate drate;
 		struct cmd_ds_802_11_rate_adapt_rateset rateset;
 		struct cmd_ds_mac_multicast_adr madr;
 		struct cmd_ds_802_11_ad_hoc_join adj;
-		struct cmd_ds_802_11_radio_control radio;
-		struct cmd_ds_802_11_rf_channel rfchannel;
 		struct cmd_ds_802_11_rssi rssi;
 		struct cmd_ds_802_11_rssi_rsp rssirsp;
 		struct cmd_ds_802_11_disassociate dassociate;
 		struct cmd_ds_802_11_mac_address macadd;
-		struct cmd_ds_802_11_enable_rsn enbrsn;
 		struct cmd_ds_802_11_key_material keymaterial;
 		struct cmd_ds_mac_reg_access macreg;
 		struct cmd_ds_bbp_reg_access bbpreg;
@@ -654,8 +721,6 @@ struct cmd_ds_command {
 		struct cmd_ds_802_11d_domain_info domaininfo;
 		struct cmd_ds_802_11d_domain_info domaininforesp;
 
-		struct cmd_ds_802_11_sleep_params sleep_params;
-		struct cmd_ds_802_11_inactivity_timeout inactivity_timeout;
 		struct cmd_ds_802_11_tpc_cfg tpccfg;
 		struct cmd_ds_802_11_pwr_cfg pwrcfg;
 		struct cmd_ds_802_11_afc afc;
@@ -664,10 +729,8 @@ struct cmd_ds_command {
 		struct cmd_tx_rate_query txrate;
 		struct cmd_ds_bt_access bt;
 		struct cmd_ds_fwt_access fwt;
-		struct cmd_ds_mesh_access mesh;
-		struct cmd_ds_set_boot2_ver boot2_ver;
 		struct cmd_ds_get_tsf gettsf;
-		struct cmd_ds_802_11_subscribe_event subscribe_event;
+		struct cmd_ds_802_11_beacon_control bcn_ctrl;
 	} params;
 } __attribute__ ((packed));
 
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index ba4fc2b3bf0a..4b5ab9a6b97b 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -57,7 +57,7 @@ MODULE_LICENSE("GPL");
 
 struct if_cs_card {
 	struct pcmcia_device *p_dev;
-	wlan_private *priv;
+	struct lbs_private *priv;
 	void __iomem *iobase;
 };
 
@@ -243,7 +243,7 @@ static inline void if_cs_disable_ints(struct if_cs_card *card)
 
 static irqreturn_t if_cs_interrupt(int irq, void *data)
 {
-	struct if_cs_card *card = (struct if_cs_card *)data;
+	struct if_cs_card *card = data;
 	u16 int_cause;
 
 	lbs_deb_enter(LBS_DEB_CS);
@@ -253,25 +253,20 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
 		/* Not for us */
 		return IRQ_NONE;
 
-	} else if(int_cause == 0xffff) {
+	} else if (int_cause == 0xffff) {
 		/* Read in junk, the card has probably been removed */
-		card->priv->adapter->surpriseremoved = 1;
+		card->priv->surpriseremoved = 1;
 
 	} else {
-		if(int_cause & IF_CS_H_IC_TX_OVER) {
-			card->priv->dnld_sent = DNLD_RES_RECEIVED;
-			if (!card->priv->adapter->cur_cmd)
-				wake_up_interruptible(&card->priv->waitq);
-
-			if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED)
-				netif_wake_queue(card->priv->dev);
-		}
+		if (int_cause & IF_CS_H_IC_TX_OVER)
+			lbs_host_to_card_done(card->priv);
 
 		/* clear interrupt */
 		if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK);
 	}
-
-	libertas_interrupt(card->priv->dev);
+	spin_lock(&card->priv->driver_lock);
+	lbs_interrupt(card->priv);
+	spin_unlock(&card->priv->driver_lock);
 
 	return IRQ_HANDLED;
 }
@@ -286,7 +281,7 @@ static irqreturn_t if_cs_interrupt(int irq, void *data)
 /*
  * Called from if_cs_host_to_card to send a command to the hardware
  */
-static int if_cs_send_cmd(wlan_private *priv, u8 *buf, u16 nb)
+static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
 {
 	struct if_cs_card *card = (struct if_cs_card *)priv->card;
 	int ret = -1;
@@ -331,7 +326,7 @@ done:
 /*
  * Called from if_cs_host_to_card to send a data to the hardware
  */
-static void if_cs_send_data(wlan_private *priv, u8 *buf, u16 nb)
+static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
 {
 	struct if_cs_card *card = (struct if_cs_card *)priv->card;
 
@@ -354,7 +349,7 @@ static void if_cs_send_data(wlan_private *priv, u8 *buf, u16 nb)
 /*
  * Get the command result out of the card.
  */
-static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len)
+static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
 {
 	int ret = -1;
 	u16 val;
@@ -369,7 +364,7 @@ static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len)
 	}
 
 	*len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN);
-	if ((*len == 0) || (*len > MRVDRV_SIZE_OF_CMD_BUFFER)) {
+	if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
 		lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
 		goto out;
 	}
@@ -379,6 +374,9 @@ static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len)
 	if (*len & 1)
 		data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD);
 
+	/* This is a workaround for a firmware that reports too much
+	 * bytes */
+	*len -= 8;
 	ret = 0;
 out:
 	lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
@@ -386,7 +384,7 @@ out:
 }
 
 
-static struct sk_buff *if_cs_receive_data(wlan_private *priv)
+static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
 {
 	struct sk_buff *skb = NULL;
 	u16 len;
@@ -616,7 +614,10 @@ done:
 /********************************************************************/
 
 /* Send commands or data packets to the card */
-static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb)
+static int if_cs_host_to_card(struct lbs_private *priv,
+	u8 type,
+	u8 *buf,
+	u16 nb)
 {
 	int ret = -1;
 
@@ -641,18 +642,16 @@ static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb)
 }
 
 
-static int if_cs_get_int_status(wlan_private *priv, u8 *ireg)
+static int if_cs_get_int_status(struct lbs_private *priv, u8 *ireg)
 {
 	struct if_cs_card *card = (struct if_cs_card *)priv->card;
-	//wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 	u16 int_cause;
-	u8 *cmdbuf;
 	*ireg = 0;
 
 	lbs_deb_enter(LBS_DEB_CS);
 
-	if (priv->adapter->surpriseremoved)
+	if (priv->surpriseremoved)
 		goto out;
 
 	int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;
@@ -668,7 +667,7 @@ sbi_get_int_status_exit:
 	/* is there a data packet for us? */
 	if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {
 		struct sk_buff *skb = if_cs_receive_data(priv);
-		libertas_process_rxed_packet(priv, skb);
+		lbs_process_rxed_packet(priv, skb);
 		*ireg &= ~IF_CS_C_S_RX_UPLD_RDY;
 	}
 
@@ -678,31 +677,24 @@ sbi_get_int_status_exit:
 
 	/* Card has a command result for us */
 	if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
-		spin_lock(&priv->adapter->driver_lock);
-		if (!priv->adapter->cur_cmd) {
-			cmdbuf = priv->upld_buf;
-			priv->adapter->hisregcpy &= ~IF_CS_C_S_RX_UPLD_RDY;
-		} else {
-			cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
-		}
-
-		ret = if_cs_receive_cmdres(priv, cmdbuf, &priv->upld_len);
-		spin_unlock(&priv->adapter->driver_lock);
+		spin_lock(&priv->driver_lock);
+		ret = if_cs_receive_cmdres(priv, priv->upld_buf, &priv->upld_len);
+		spin_unlock(&priv->driver_lock);
 		if (ret < 0)
 			lbs_pr_err("could not receive cmd from card\n");
 	}
 
 out:
-	lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->adapter->hisregcpy);
+	lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->hisregcpy);
 	return ret;
 }
 
 
-static int if_cs_read_event_cause(wlan_private *priv)
+static int if_cs_read_event_cause(struct lbs_private *priv)
 {
 	lbs_deb_enter(LBS_DEB_CS);
 
-	priv->adapter->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
+	priv->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
 	if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
 
 	return 0;
@@ -746,7 +738,7 @@ static void if_cs_release(struct pcmcia_device *p_dev)
 static int if_cs_probe(struct pcmcia_device *p_dev)
 {
 	int ret = -ENOMEM;
-	wlan_private *priv;
+	struct lbs_private *priv;
 	struct if_cs_card *card;
 	/* CIS parsing */
 	tuple_t tuple;
@@ -856,7 +848,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
 		goto out2;
 
 	/* Make this card known to the libertas driver */
-	priv = libertas_add_card(card, &p_dev->dev);
+	priv = lbs_add_card(card, &p_dev->dev);
 	if (!priv) {
 		ret = -ENOMEM;
 		goto out2;
@@ -869,7 +861,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
 	priv->hw_get_int_status   = if_cs_get_int_status;
 	priv->hw_read_event_cause = if_cs_read_event_cause;
 
-	priv->adapter->fw_ready = 1;
+	priv->fw_ready = 1;
 
 	/* Now actually get the IRQ */
 	ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt,
@@ -885,7 +877,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
 	if_cs_enable_ints(card);
 
 	/* And finally bring the card up */
-	if (libertas_start_card(priv) != 0) {
+	if (lbs_start_card(priv) != 0) {
 		lbs_pr_err("could not activate card\n");
 		goto out3;
 	}
@@ -894,7 +886,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
 	goto out;
 
 out3:
-	libertas_remove_card(priv);
+	lbs_remove_card(priv);
 out2:
 	ioport_unmap(card->iobase);
 out1:
@@ -917,8 +909,8 @@ static void if_cs_detach(struct pcmcia_device *p_dev)
 
 	lbs_deb_enter(LBS_DEB_CS);
 
-	libertas_stop_card(card->priv);
-	libertas_remove_card(card->priv);
+	lbs_stop_card(card->priv);
+	lbs_remove_card(card->priv);
 	if_cs_disable_ints(card);
 	if_cs_release(p_dev);
 	kfree(card);
@@ -939,7 +931,7 @@ static struct pcmcia_device_id if_cs_ids[] = {
 MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
 
 
-static struct pcmcia_driver libertas_driver = {
+static struct pcmcia_driver lbs_driver = {
 	.owner		= THIS_MODULE,
 	.drv		= {
 		.name	= DRV_NAME,
@@ -955,7 +947,7 @@ static int __init if_cs_init(void)
 	int ret;
 
 	lbs_deb_enter(LBS_DEB_CS);
-	ret = pcmcia_register_driver(&libertas_driver);
+	ret = pcmcia_register_driver(&lbs_driver);
 	lbs_deb_leave(LBS_DEB_CS);
 	return ret;
 }
@@ -964,7 +956,7 @@ static int __init if_cs_init(void)
 static void __exit if_cs_exit(void)
 {
 	lbs_deb_enter(LBS_DEB_CS);
-	pcmcia_unregister_driver(&libertas_driver);
+	pcmcia_unregister_driver(&lbs_driver);
 	lbs_deb_leave(LBS_DEB_CS);
 }
 
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 4f1efb108c28..eed73204bcc9 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -19,7 +19,7 @@
  * current block size.
  *
  * As SDIO is still new to the kernel, it is unfortunately common with
- * bugs in the host controllers related to that. One such bug is that 
+ * bugs in the host controllers related to that. One such bug is that
  * controllers cannot do transfers that aren't a multiple of 4 bytes.
  * If you don't have time to fix the host controller driver, you can
  * work around the problem by modifying if_sdio_host_to_card() and
@@ -40,11 +40,11 @@
 #include "dev.h"
 #include "if_sdio.h"
 
-static char *libertas_helper_name = NULL;
-module_param_named(helper_name, libertas_helper_name, charp, 0644);
+static char *lbs_helper_name = NULL;
+module_param_named(helper_name, lbs_helper_name, charp, 0644);
 
-static char *libertas_fw_name = NULL;
-module_param_named(fw_name, libertas_fw_name, charp, 0644);
+static char *lbs_fw_name = NULL;
+module_param_named(fw_name, lbs_fw_name, charp, 0644);
 
 static const struct sdio_device_id if_sdio_ids[] = {
 	{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
@@ -82,7 +82,7 @@ struct if_sdio_packet {
 
 struct if_sdio_card {
 	struct sdio_func	*func;
-	wlan_private		*priv;
+	struct lbs_private	*priv;
 
 	int			model;
 	unsigned long		ioport;
@@ -134,32 +134,26 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card,
 
 	lbs_deb_enter(LBS_DEB_SDIO);
 
-	spin_lock_irqsave(&card->priv->adapter->driver_lock, flags);
+	spin_lock_irqsave(&card->priv->driver_lock, flags);
 
-	if (!card->priv->adapter->cur_cmd) {
-		lbs_deb_sdio("discarding spurious response\n");
-		ret = 0;
-		goto out;
-	}
-
-	if (size > MRVDRV_SIZE_OF_CMD_BUFFER) {
+	if (size > LBS_CMD_BUFFER_SIZE) {
 		lbs_deb_sdio("response packet too large (%d bytes)\n",
 			(int)size);
 		ret = -E2BIG;
 		goto out;
 	}
 
-	memcpy(card->priv->adapter->cur_cmd->bufvirtualaddr, buffer, size);
+	memcpy(card->priv->upld_buf, buffer, size);
 	card->priv->upld_len = size;
 
 	card->int_cause |= MRVDRV_CMD_UPLD_RDY;
 
-	libertas_interrupt(card->priv->dev);
+	lbs_interrupt(card->priv);
 
 	ret = 0;
 
 out:
-	spin_unlock_irqrestore(&card->priv->adapter->driver_lock, flags);
+	spin_unlock_irqrestore(&card->priv->driver_lock, flags);
 
 	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
 
@@ -194,7 +188,7 @@ static int if_sdio_handle_data(struct if_sdio_card *card,
 
 	memcpy(data, buffer, size);
 
-	libertas_process_rxed_packet(card->priv, skb);
+	lbs_process_rxed_packet(card->priv, skb);
 
 	ret = 0;
 
@@ -231,14 +225,14 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
 		event <<= SBI_EVENT_CAUSE_SHIFT;
 	}
 
-	spin_lock_irqsave(&card->priv->adapter->driver_lock, flags);
+	spin_lock_irqsave(&card->priv->driver_lock, flags);
 
 	card->event = event;
 	card->int_cause |= MRVDRV_CARDEVENT;
 
-	libertas_interrupt(card->priv->dev);
+	lbs_interrupt(card->priv);
 
-	spin_unlock_irqrestore(&card->priv->adapter->driver_lock, flags);
+	spin_unlock_irqrestore(&card->priv->driver_lock, flags);
 
 	ret = 0;
 
@@ -454,7 +448,7 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
 
 		chunk_size = min(size, (size_t)60);
 
-		*((u32*)chunk_buffer) = cpu_to_le32(chunk_size);
+		*((__le32*)chunk_buffer) = cpu_to_le32(chunk_size);
 		memcpy(chunk_buffer + 4, firmware, chunk_size);
 /*
 		lbs_deb_sdio("sending %d bytes chunk\n", chunk_size);
@@ -694,7 +688,8 @@ out:
 /* Libertas callbacks                                              */
 /*******************************************************************/
 
-static int if_sdio_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb)
+static int if_sdio_host_to_card(struct lbs_private *priv,
+		u8 type, u8 *buf, u16 nb)
 {
 	int ret;
 	struct if_sdio_card *card;
@@ -775,7 +770,7 @@ out:
 	return ret;
 }
 
-static int if_sdio_get_int_status(wlan_private *priv, u8 *ireg)
+static int if_sdio_get_int_status(struct lbs_private *priv, u8 *ireg)
 {
 	struct if_sdio_card *card;
 
@@ -791,7 +786,7 @@ static int if_sdio_get_int_status(wlan_private *priv, u8 *ireg)
 	return 0;
 }
 
-static int if_sdio_read_event_cause(wlan_private *priv)
+static int if_sdio_read_event_cause(struct lbs_private *priv)
 {
 	struct if_sdio_card *card;
 
@@ -799,7 +794,7 @@ static int if_sdio_read_event_cause(wlan_private *priv)
 
 	card = priv->card;
 
-	priv->adapter->eventcause = card->event;
+	priv->eventcause = card->event;
 
 	lbs_deb_leave(LBS_DEB_SDIO);
 
@@ -834,12 +829,9 @@ static void if_sdio_interrupt(struct sdio_func *func)
 	 * Ignore the define name, this really means the card has
 	 * successfully received the command.
 	 */
-	if (cause & IF_SDIO_H_INT_DNLD) {
-		if ((card->priv->dnld_sent == DNLD_DATA_SENT) &&
-			(card->priv->adapter->connect_status == LIBERTAS_CONNECTED))
-			netif_wake_queue(card->priv->dev);
-		card->priv->dnld_sent = DNLD_RES_RECEIVED;
-	}
+	if (cause & IF_SDIO_H_INT_DNLD)
+		lbs_host_to_card_done(card->priv);
+
 
 	if (cause & IF_SDIO_H_INT_UPLD) {
 		ret = if_sdio_card_to_host(card);
@@ -857,7 +849,7 @@ static int if_sdio_probe(struct sdio_func *func,
 		const struct sdio_device_id *id)
 {
 	struct if_sdio_card *card;
-	wlan_private *priv;
+	struct lbs_private *priv;
 	int ret, i;
 	unsigned int model;
 	struct if_sdio_packet *packet;
@@ -905,15 +897,15 @@ static int if_sdio_probe(struct sdio_func *func,
 	card->helper = if_sdio_models[i].helper;
 	card->firmware = if_sdio_models[i].firmware;
 
-	if (libertas_helper_name) {
+	if (lbs_helper_name) {
 		lbs_deb_sdio("overriding helper firmware: %s\n",
-			libertas_helper_name);
-		card->helper = libertas_helper_name;
+			lbs_helper_name);
+		card->helper = lbs_helper_name;
 	}
 
-	if (libertas_fw_name) {
-		lbs_deb_sdio("overriding firmware: %s\n", libertas_fw_name);
-		card->firmware = libertas_fw_name;
+	if (lbs_fw_name) {
+		lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
+		card->firmware = lbs_fw_name;
 	}
 
 	sdio_claim_host(func);
@@ -951,7 +943,7 @@ static int if_sdio_probe(struct sdio_func *func,
 	if (ret)
 		goto reclaim;
 
-	priv = libertas_add_card(card, &func->dev);
+	priv = lbs_add_card(card, &func->dev);
 	if (!priv) {
 		ret = -ENOMEM;
 		goto reclaim;
@@ -964,7 +956,7 @@ static int if_sdio_probe(struct sdio_func *func,
 	priv->hw_get_int_status = if_sdio_get_int_status;
 	priv->hw_read_event_cause = if_sdio_read_event_cause;
 
-	priv->adapter->fw_ready = 1;
+	priv->fw_ready = 1;
 
 	/*
 	 * Enable interrupts now that everything is set up
@@ -975,7 +967,7 @@ static int if_sdio_probe(struct sdio_func *func,
 	if (ret)
 		goto reclaim;
 
-	ret = libertas_start_card(priv);
+	ret = lbs_start_card(priv);
 	if (ret)
 		goto err_activate_card;
 
@@ -987,7 +979,7 @@ out:
 err_activate_card:
 	flush_scheduled_work();
 	free_netdev(priv->dev);
-	kfree(priv->adapter);
+	kfree(priv);
 reclaim:
 	sdio_claim_host(func);
 release_int:
@@ -1017,11 +1009,11 @@ static void if_sdio_remove(struct sdio_func *func)
 
 	card = sdio_get_drvdata(func);
 
-	card->priv->adapter->surpriseremoved = 1;
+	card->priv->surpriseremoved = 1;
 
 	lbs_deb_sdio("call remove card\n");
-	libertas_stop_card(card->priv);
-	libertas_remove_card(card->priv);
+	lbs_stop_card(card->priv);
+	lbs_remove_card(card->priv);
 
 	flush_scheduled_work();
 
@@ -1052,7 +1044,7 @@ static struct sdio_driver if_sdio_driver = {
 /* Module functions                                                */
 /*******************************************************************/
 
-static int if_sdio_init_module(void)
+static int __init if_sdio_init_module(void)
 {
 	int ret = 0;
 
@@ -1068,7 +1060,7 @@ static int if_sdio_init_module(void)
 	return ret;
 }
 
-static void if_sdio_exit_module(void)
+static void __exit if_sdio_exit_module(void)
 {
 	lbs_deb_enter(LBS_DEB_SDIO);
 
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
index dfcaea7b168f..533bdfbf5d2a 100644
--- a/drivers/net/wireless/libertas/if_sdio.h
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -9,8 +9,8 @@
  * your option) any later version.
  */
 
-#ifndef LIBERTAS_IF_SDIO_H
-#define LIBERTAS_IF_SDIO_H
+#ifndef _LBS_IF_SDIO_H
+#define _LBS_IF_SDIO_H
 
 #define IF_SDIO_IOPORT		0x00
 
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index cb59f46ed126..75aed9d07367 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -5,7 +5,6 @@
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/netdevice.h>
-#include <linux/list.h>
 #include <linux/usb.h>
 
 #define DRV_NAME "usb8xxx"
@@ -14,24 +13,16 @@
 #include "decl.h"
 #include "defs.h"
 #include "dev.h"
+#include "cmd.h"
 #include "if_usb.h"
 
-#define MESSAGE_HEADER_LEN	4
-
-static const char usbdriver_name[] = "usb8xxx";
-static u8 *default_fw_name = "usb8388.bin";
+#define INSANEDEBUG	0
+#define lbs_deb_usb2(...) do { if (INSANEDEBUG) lbs_deb_usbd(__VA_ARGS__); } while (0)
 
-static char *libertas_fw_name = NULL;
-module_param_named(fw_name, libertas_fw_name, charp, 0644);
+#define MESSAGE_HEADER_LEN	4
 
-/*
- * We need to send a RESET command to all USB devices before
- * we tear down the USB connection. Otherwise we would not
- * be able to re-init device the device if the module gets
- * loaded again. This is a list of all initialized USB devices,
- * for the reset code see if_usb_reset_device()
-*/
-static LIST_HEAD(usb_devices);
+static char *lbs_fw_name = "usb8388.bin";
+module_param_named(fw_name, lbs_fw_name, charp, 0644);
 
 static struct usb_device_id if_usb_table[] = {
 	/* Enter the device signature inside */
@@ -44,14 +35,16 @@ MODULE_DEVICE_TABLE(usb, if_usb_table);
 
 static void if_usb_receive(struct urb *urb);
 static void if_usb_receive_fwload(struct urb *urb);
-static int if_usb_prog_firmware(struct usb_card_rec *cardp);
-static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
-static int if_usb_get_int_status(wlan_private * priv, u8 *);
-static int if_usb_read_event_cause(wlan_private *);
-static int usb_tx_block(struct usb_card_rec *cardp, u8 *payload, u16 nb);
-static void if_usb_free(struct usb_card_rec *cardp);
-static int if_usb_submit_rx_urb(struct usb_card_rec *cardp);
-static int if_usb_reset_device(struct usb_card_rec *cardp);
+static int if_usb_prog_firmware(struct if_usb_card *cardp);
+static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
+			       uint8_t *payload, uint16_t nb);
+static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *);
+static int if_usb_read_event_cause(struct lbs_private *);
+static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
+			uint16_t nb);
+static void if_usb_free(struct if_usb_card *cardp);
+static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
+static int if_usb_reset_device(struct if_usb_card *cardp);
 
 /**
  *  @brief  call back function to handle the status of the URB
@@ -60,37 +53,22 @@ static int if_usb_reset_device(struct usb_card_rec *cardp);
  */
 static void if_usb_write_bulk_callback(struct urb *urb)
 {
-	struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context;
+	struct if_usb_card *cardp = (struct if_usb_card *) urb->context;
 
 	/* handle the transmission complete validations */
 
 	if (urb->status == 0) {
-		wlan_private *priv = cardp->priv;
+		struct lbs_private *priv = cardp->priv;
 
-		/*
-		lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n");
-		lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n",
-		       urb->actual_length);
-		*/
+		lbs_deb_usb2(&urb->dev->dev, "URB status is successful\n");
+		lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
+			     urb->actual_length);
 
 		/* Used for both firmware TX and regular TX.  priv isn't
 		 * valid at firmware load time.
 		 */
-		if (priv) {
-			wlan_adapter *adapter = priv->adapter;
-			struct net_device *dev = priv->dev;
-
-			priv->dnld_sent = DNLD_RES_RECEIVED;
-
-			/* Wake main thread if commands are pending */
-			if (!adapter->cur_cmd)
-				wake_up_interruptible(&priv->waitq);
-
-			if ((adapter->connect_status == LIBERTAS_CONNECTED)) {
-				netif_wake_queue(dev);
-				netif_wake_queue(priv->mesh_dev);
-			}
-		}
+		if (priv)
+			lbs_host_to_card_done(priv);
 	} else {
 		/* print the failure status number for debug */
 		lbs_pr_info("URB in failure status: %d\n", urb->status);
@@ -101,10 +79,10 @@ static void if_usb_write_bulk_callback(struct urb *urb)
 
 /**
  *  @brief  free tx/rx urb, skb and rx buffer
- *  @param cardp	pointer usb_card_rec
+ *  @param cardp	pointer if_usb_card
  *  @return 	   	N/A
  */
-static void if_usb_free(struct usb_card_rec *cardp)
+static void if_usb_free(struct if_usb_card *cardp)
 {
 	lbs_deb_enter(LBS_DEB_USB);
 
@@ -118,12 +96,58 @@ static void if_usb_free(struct usb_card_rec *cardp)
 	usb_free_urb(cardp->rx_urb);
 	cardp->rx_urb = NULL;
 
-	kfree(cardp->bulk_out_buffer);
-	cardp->bulk_out_buffer = NULL;
+	kfree(cardp->ep_out_buf);
+	cardp->ep_out_buf = NULL;
 
 	lbs_deb_leave(LBS_DEB_USB);
 }
 
+static void if_usb_setup_firmware(struct lbs_private *priv)
+{
+	struct if_usb_card *cardp = priv->card;
+	struct cmd_ds_set_boot2_ver b2_cmd;
+	struct cmd_ds_802_11_fw_wake_method wake_method;
+
+	b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
+	b2_cmd.action = 0;
+	b2_cmd.version = cardp->boot2_version;
+
+	if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
+		lbs_deb_usb("Setting boot2 version failed\n");
+
+	priv->wol_gpio = 2; /* Wake via GPIO2... */
+	priv->wol_gap = 20; /* ... after 20ms    */
+	lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA);
+
+	wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
+	wake_method.action = cpu_to_le16(CMD_ACT_GET);
+	if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
+		lbs_pr_info("Firmware does not seem to support PS mode\n");
+	} else {
+		if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
+			lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
+			priv->ps_supported = 1;
+		} else {
+			/* The versions which boot up this way don't seem to
+			   work even if we set it to the command interrupt */
+			lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
+		}
+	}
+}
+
+static void if_usb_fw_timeo(unsigned long priv)
+{
+	struct if_usb_card *cardp = (void *)priv;
+
+	if (cardp->fwdnldover) {
+		lbs_deb_usb("Download complete, no event. Assuming success\n");
+	} else {
+		lbs_pr_err("Download timed out\n");
+		cardp->surprise_removed = 1;
+	}
+	wake_up(&cardp->fw_wq);
+}
+
 /**
  *  @brief sets the configuration values
  *  @param ifnum	interface number
@@ -136,23 +160,26 @@ static int if_usb_probe(struct usb_interface *intf,
 	struct usb_device *udev;
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
-	wlan_private *priv;
-	struct usb_card_rec *cardp;
+	struct lbs_private *priv;
+	struct if_usb_card *cardp;
 	int i;
 
 	udev = interface_to_usbdev(intf);
 
-	cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
+	cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
 	if (!cardp) {
 		lbs_pr_err("Out of memory allocating private data.\n");
 		goto error;
 	}
 
+	setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
+	init_waitqueue_head(&cardp->fw_wq);
+
 	cardp->udev = udev;
 	iface_desc = intf->cur_altsetting;
 
 	lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
-	       " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+		     " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
 		     le16_to_cpu(udev->descriptor.bcdUSB),
 		     udev->descriptor.bDeviceClass,
 		     udev->descriptor.bDeviceSubClass,
@@ -160,92 +187,62 @@ static int if_usb_probe(struct usb_interface *intf,
 
 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
 		endpoint = &iface_desc->endpoint[i].desc;
-		if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-		    && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-			USB_ENDPOINT_XFER_BULK)) {
-			/* we found a bulk in endpoint */
-			lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n",
-				     le16_to_cpu(endpoint->wMaxPacketSize));
-			if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
-				lbs_deb_usbd(&udev->dev,
-				       "Rx URB allocation failed\n");
-				goto dealloc;
-			}
-			cardp->rx_urb_recall = 0;
-
-			cardp->bulk_in_size =
-				le16_to_cpu(endpoint->wMaxPacketSize);
-			cardp->bulk_in_endpointAddr =
-			    (endpoint->
-			     bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
-			lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n",
-			       endpoint->bEndpointAddress);
-		}
+		if (usb_endpoint_is_bulk_in(endpoint)) {
+			cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
+			cardp->ep_in = usb_endpoint_num(endpoint);
 
-		if (((endpoint->
-		      bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
-		     USB_DIR_OUT)
-		    && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-			USB_ENDPOINT_XFER_BULK)) {
-			/* We found bulk out endpoint */
-			if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
-				lbs_deb_usbd(&udev->dev,
-				       "Tx URB allocation failed\n");
-				goto dealloc;
-			}
+			lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
+			lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
 
-			cardp->bulk_out_size =
-				le16_to_cpu(endpoint->wMaxPacketSize);
-			lbs_deb_usbd(&udev->dev,
-				     "Bulk out size is %d\n",
-				     le16_to_cpu(endpoint->wMaxPacketSize));
-			cardp->bulk_out_endpointAddr =
-			    endpoint->bEndpointAddress;
-			lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n",
-				    endpoint->bEndpointAddress);
-			cardp->bulk_out_buffer =
-			    kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
-				    GFP_KERNEL);
-
-			if (!cardp->bulk_out_buffer) {
-				lbs_deb_usbd(&udev->dev,
-				       "Could not allocate buffer\n");
-				goto dealloc;
-			}
+		} else if (usb_endpoint_is_bulk_out(endpoint)) {
+			cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
+			cardp->ep_out = usb_endpoint_num(endpoint);
+
+			lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
+			lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
 		}
 	}
+	if (!cardp->ep_out_size || !cardp->ep_in_size) {
+		lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
+		goto dealloc;
+	}
+	if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
+		lbs_deb_usbd(&udev->dev, "Rx URB allocation failed\n");
+		goto dealloc;
+	}
+	if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
+		lbs_deb_usbd(&udev->dev, "Tx URB allocation failed\n");
+		goto dealloc;
+	}
+	cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, GFP_KERNEL);
+	if (!cardp->ep_out_buf) {
+		lbs_deb_usbd(&udev->dev, "Could not allocate buffer\n");
+		goto dealloc;
+	}
 
 	/* Upload firmware */
-	cardp->rinfo.cardp = cardp;
 	if (if_usb_prog_firmware(cardp)) {
-		lbs_deb_usbd(&udev->dev, "FW upload failed");
+		lbs_deb_usbd(&udev->dev, "FW upload failed\n");
 		goto err_prog_firmware;
 	}
 
-	if (!(priv = libertas_add_card(cardp, &udev->dev)))
+	if (!(priv = lbs_add_card(cardp, &udev->dev)))
 		goto err_prog_firmware;
 
 	cardp->priv = priv;
-
-	if (libertas_add_mesh(priv, &udev->dev))
-		goto err_add_mesh;
-
-	cardp->eth_dev = priv->dev;
+	cardp->priv->fw_ready = 1;
 
 	priv->hw_host_to_card = if_usb_host_to_card;
 	priv->hw_get_int_status = if_usb_get_int_status;
 	priv->hw_read_event_cause = if_usb_read_event_cause;
-	priv->boot2_version = udev->descriptor.bcdDevice;
+	cardp->boot2_version = udev->descriptor.bcdDevice;
 
-	/* Delay 200 ms to waiting for the FW ready */
 	if_usb_submit_rx_urb(cardp);
-	msleep_interruptible(200);
-	priv->adapter->fw_ready = 1;
 
-	if (libertas_start_card(priv))
+	if (lbs_start_card(priv))
 		goto err_start_card;
 
-	list_add_tail(&cardp->list, &usb_devices);
+	if_usb_setup_firmware(priv);
 
 	usb_get_dev(udev);
 	usb_set_intfdata(intf, cardp);
@@ -253,9 +250,7 @@ static int if_usb_probe(struct usb_interface *intf,
 	return 0;
 
 err_start_card:
-	libertas_remove_mesh(priv);
-err_add_mesh:
-	libertas_remove_card(priv);
+	lbs_remove_card(priv);
 err_prog_firmware:
 	if_usb_reset_device(cardp);
 dealloc:
@@ -272,23 +267,17 @@ error:
  */
 static void if_usb_disconnect(struct usb_interface *intf)
 {
-	struct usb_card_rec *cardp = usb_get_intfdata(intf);
-	wlan_private *priv = (wlan_private *) cardp->priv;
+	struct if_usb_card *cardp = usb_get_intfdata(intf);
+	struct lbs_private *priv = (struct lbs_private *) cardp->priv;
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
-	/* Update Surprise removed to TRUE */
 	cardp->surprise_removed = 1;
 
-	list_del(&cardp->list);
-
 	if (priv) {
-		wlan_adapter *adapter = priv->adapter;
-
-		adapter->surpriseremoved = 1;
-		libertas_stop_card(priv);
-		libertas_remove_mesh(priv);
-		libertas_remove_card(priv);
+		priv->surpriseremoved = 1;
+		lbs_stop_card(priv);
+		lbs_remove_card(priv);
 	}
 
 	/* Unlink and free urb */
@@ -302,102 +291,82 @@ static void if_usb_disconnect(struct usb_interface *intf)
 
 /**
  *  @brief  This function download FW
- *  @param priv		pointer to wlan_private
+ *  @param priv		pointer to struct lbs_private
  *  @return 	   	0
  */
-static int if_prog_firmware(struct usb_card_rec *cardp)
+static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
 {
-	struct FWData *fwdata;
-	struct fwheader *fwheader;
-	u8 *firmware = cardp->fw->data;
-
-	fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
-
-	if (!fwdata)
-		return -1;
-
-	fwheader = &fwdata->fwheader;
+	struct fwdata *fwdata = cardp->ep_out_buf;
+	uint8_t *firmware = cardp->fw->data;
 
+	/* If we got a CRC failure on the last block, back
+	   up and retry it */
 	if (!cardp->CRC_OK) {
 		cardp->totalbytes = cardp->fwlastblksent;
-		cardp->fwseqnum = cardp->lastseqnum - 1;
+		cardp->fwseqnum--;
 	}
 
-	/*
-	lbs_deb_usbd(&cardp->udev->dev, "totalbytes = %d\n",
-		    cardp->totalbytes);
-	*/
+	lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
+		     cardp->totalbytes);
 
-	memcpy(fwheader, &firmware[cardp->totalbytes],
+	/* struct fwdata (which we sent to the card) has an
+	   extra __le32 field in between the header and the data,
+	   which is not in the struct fwheader in the actual
+	   firmware binary. Insert the seqnum in the middle... */
+	memcpy(&fwdata->hdr, &firmware[cardp->totalbytes],
 	       sizeof(struct fwheader));
 
 	cardp->fwlastblksent = cardp->totalbytes;
 	cardp->totalbytes += sizeof(struct fwheader);
 
-	/* lbs_deb_usbd(&cardp->udev->dev,"Copy Data\n"); */
 	memcpy(fwdata->data, &firmware[cardp->totalbytes],
-	       le32_to_cpu(fwdata->fwheader.datalength));
+	       le32_to_cpu(fwdata->hdr.datalength));
 
-	/*
-	lbs_deb_usbd(&cardp->udev->dev,
-		    "Data length = %d\n", le32_to_cpu(fwdata->fwheader.datalength));
-	*/
+	lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
+		     le32_to_cpu(fwdata->hdr.datalength));
 
-	cardp->fwseqnum = cardp->fwseqnum + 1;
+	fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
+	cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
 
-	fwdata->seqnum = cpu_to_le32(cardp->fwseqnum);
-	cardp->lastseqnum = cardp->fwseqnum;
-	cardp->totalbytes += le32_to_cpu(fwdata->fwheader.datalength);
+	usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
+		     le32_to_cpu(fwdata->hdr.datalength));
+
+	if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
+		lbs_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
+		lbs_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
+			     cardp->fwseqnum, cardp->totalbytes);
+	} else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
+		lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
+		lbs_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
 
-	if (fwheader->dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
-		/*
-		lbs_deb_usbd(&cardp->udev->dev, "There are data to follow\n");
-		lbs_deb_usbd(&cardp->udev->dev,
-			    "seqnum = %d totalbytes = %d\n", cardp->fwseqnum,
-			    cardp->totalbytes);
-		*/
-		memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
-		usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
-
-	} else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
-		/*
-		lbs_deb_usbd(&cardp->udev->dev,
-			    "Host has finished FW downloading\n");
-		lbs_deb_usbd(&cardp->udev->dev,
-			    "Donwloading FW JUMP BLOCK\n");
-		*/
-		memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
-		usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
 		cardp->fwfinalblk = 1;
 	}
 
-	/*
-	lbs_deb_usbd(&cardp->udev->dev,
-		    "The firmware download is done size is %d\n",
-		    cardp->totalbytes);
-	*/
-
-	kfree(fwdata);
+	lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
+		     cardp->totalbytes);
 
 	return 0;
 }
 
-static int if_usb_reset_device(struct usb_card_rec *cardp)
+static int if_usb_reset_device(struct if_usb_card *cardp)
 {
+	struct cmd_ds_command *cmd = cardp->ep_out_buf + 4;
 	int ret;
-	wlan_private * priv = cardp->priv;
 
 	lbs_deb_enter(LBS_DEB_USB);
 
-	/* Try a USB port reset first, if that fails send the reset
-	 * command to the firmware.
-	 */
+	*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
+
+	cmd->command = cpu_to_le16(CMD_802_11_RESET);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
+	cmd->result = cpu_to_le16(0);
+	cmd->seqnum = cpu_to_le16(0x5a5a);
+	cmd->params.reset.action = cpu_to_le16(CMD_ACT_HALT);
+	usb_tx_block(cardp, cardp->ep_out_buf, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset));
+
+	msleep(100);
 	ret = usb_reset_device(cardp->udev);
-	if (!ret && priv) {
-		msleep(10);
-		ret = libertas_reset_device(priv);
-		msleep(10);
-	}
+	msleep(100);
 
 	lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
 
@@ -406,12 +375,12 @@ static int if_usb_reset_device(struct usb_card_rec *cardp)
 
 /**
  *  @brief This function transfer the data to the device.
- *  @param priv 	pointer to wlan_private
+ *  @param priv 	pointer to struct lbs_private
  *  @param payload	pointer to payload data
  *  @param nb		data length
  *  @return 	   	0 or -1
  */
-static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb)
+static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
 {
 	int ret = -1;
 
@@ -423,17 +392,16 @@ static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb)
 
 	usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
 			  usb_sndbulkpipe(cardp->udev,
-					  cardp->bulk_out_endpointAddr),
+					  cardp->ep_out),
 			  payload, nb, if_usb_write_bulk_callback, cardp);
 
 	cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
 
 	if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
-		/*  transfer failed */
-		lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed\n");
+		lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
 		ret = -1;
 	} else {
-		/* lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb success\n"); */
+		lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
 		ret = 0;
 	}
 
@@ -441,11 +409,10 @@ tx_ret:
 	return ret;
 }
 
-static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp,
+static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
 				  void (*callbackfn)(struct urb *urb))
 {
 	struct sk_buff *skb;
-	struct read_cb_info *rinfo = &cardp->rinfo;
 	int ret = -1;
 
 	if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
@@ -453,25 +420,25 @@ static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp,
 		goto rx_ret;
 	}
 
-	rinfo->skb = skb;
+	cardp->rx_skb = skb;
 
 	/* Fill the receive configuration URB and initialise the Rx call back */
 	usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
-			  usb_rcvbulkpipe(cardp->udev,
-					  cardp->bulk_in_endpointAddr),
+			  usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
 			  (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET),
 			  MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
-			  rinfo);
+			  cardp);
 
 	cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
 
-	/* lbs_deb_usbd(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); */
+	lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
 	if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
-		/* handle failure conditions */
-		lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed\n");
+		lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
+		kfree_skb(skb);
+		cardp->rx_skb = NULL;
 		ret = -1;
 	} else {
-		/* lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB success\n"); */
+		lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n");
 		ret = 0;
 	}
 
@@ -479,58 +446,78 @@ rx_ret:
 	return ret;
 }
 
-static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp)
+static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
 {
 	return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
 }
 
-static int if_usb_submit_rx_urb(struct usb_card_rec *cardp)
+static int if_usb_submit_rx_urb(struct if_usb_card *cardp)
 {
 	return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
 }
 
 static void if_usb_receive_fwload(struct urb *urb)
 {
-	struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
-	struct sk_buff *skb = rinfo->skb;
-	struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp;
+	struct if_usb_card *cardp = urb->context;
+	struct sk_buff *skb = cardp->rx_skb;
 	struct fwsyncheader *syncfwheader;
-	struct bootcmdrespStr bootcmdresp;
+	struct bootcmdresp bootcmdresp;
 
 	if (urb->status) {
 		lbs_deb_usbd(&cardp->udev->dev,
-			    "URB status is failed during fw load\n");
+			     "URB status is failed during fw load\n");
 		kfree_skb(skb);
 		return;
 	}
 
-	if (cardp->bootcmdresp == 0) {
+	if (cardp->fwdnldover) {
+		__le32 *tmp = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
+
+		if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
+		    tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
+			lbs_pr_info("Firmware ready event received\n");
+			wake_up(&cardp->fw_wq);
+		} else {
+			lbs_deb_usb("Waiting for confirmation; got %x %x\n",
+				    le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1]));
+			if_usb_submit_rx_urb_fwload(cardp);
+		}
+		kfree_skb(skb);
+		return;
+	}
+	if (cardp->bootcmdresp <= 0) {
 		memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
 			sizeof(bootcmdresp));
+
 		if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
 			kfree_skb(skb);
 			if_usb_submit_rx_urb_fwload(cardp);
 			cardp->bootcmdresp = 1;
 			lbs_deb_usbd(&cardp->udev->dev,
-				    "Received valid boot command response\n");
+				     "Received valid boot command response\n");
 			return;
 		}
-		if (bootcmdresp.u32magicnumber != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
-			lbs_pr_info(
-				"boot cmd response wrong magic number (0x%x)\n",
-				le32_to_cpu(bootcmdresp.u32magicnumber));
-		} else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) {
-			lbs_pr_info(
-				"boot cmd response cmd_tag error (%d)\n",
-				bootcmdresp.u8cmd_tag);
-		} else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) {
-			lbs_pr_info(
-				"boot cmd response result error (%d)\n",
-				bootcmdresp.u8result);
+		if (bootcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
+			if (bootcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
+			    bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
+			    bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
+				if (!cardp->bootcmdresp)
+					lbs_pr_info("Firmware already seems alive; resetting\n");
+				cardp->bootcmdresp = -1;
+			} else {
+				lbs_pr_info("boot cmd response wrong magic number (0x%x)\n",
+					    le32_to_cpu(bootcmdresp.magic));
+			}
+		} else if (bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) {
+			lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
+				    bootcmdresp.cmd);
+		} else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
+			lbs_pr_info("boot cmd response result error (%d)\n",
+				    bootcmdresp.result);
 		} else {
 			cardp->bootcmdresp = 1;
 			lbs_deb_usbd(&cardp->udev->dev,
-				    "Received valid boot command response\n");
+				     "Received valid boot command response\n");
 		}
 		kfree_skb(skb);
 		if_usb_submit_rx_urb_fwload(cardp);
@@ -545,50 +532,47 @@ static void if_usb_receive_fwload(struct urb *urb)
 	}
 
 	memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
-			sizeof(struct fwsyncheader));
+	       sizeof(struct fwsyncheader));
 
 	if (!syncfwheader->cmd) {
-		/*
-		lbs_deb_usbd(&cardp->udev->dev,
-			    "FW received Blk with correct CRC\n");
-		lbs_deb_usbd(&cardp->udev->dev,
-			    "FW received Blk seqnum = %d\n",
-		       syncfwheader->seqnum);
-		*/
+		lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
+		lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
+			     le32_to_cpu(syncfwheader->seqnum));
 		cardp->CRC_OK = 1;
 	} else {
-		lbs_deb_usbd(&cardp->udev->dev,
-			    "FW received Blk with CRC error\n");
+		lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
 		cardp->CRC_OK = 0;
 	}
 
 	kfree_skb(skb);
 
+	/* reschedule timer for 200ms hence */
+	mod_timer(&cardp->fw_timeout, jiffies + (HZ/5));
+
 	if (cardp->fwfinalblk) {
 		cardp->fwdnldover = 1;
 		goto exit;
 	}
 
-	if_prog_firmware(cardp);
+	if_usb_send_fw_pkt(cardp);
 
+ exit:
 	if_usb_submit_rx_urb_fwload(cardp);
-exit:
+
 	kfree(syncfwheader);
 
 	return;
-
 }
 
 #define MRVDRV_MIN_PKT_LEN	30
 
 static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
-				       struct usb_card_rec *cardp,
-				       wlan_private *priv)
+				       struct if_usb_card *cardp,
+				       struct lbs_private *priv)
 {
-	if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +
-	    MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) {
-		lbs_deb_usbd(&cardp->udev->dev,
-			    "Packet length is Invalid\n");
+	if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
+	    || recvlength < MRVDRV_MIN_PKT_LEN) {
+		lbs_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n");
 		kfree_skb(skb);
 		return;
 	}
@@ -596,19 +580,19 @@ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
 	skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
 	skb_put(skb, recvlength);
 	skb_pull(skb, MESSAGE_HEADER_LEN);
-	libertas_process_rxed_packet(priv, skb);
+
+	lbs_process_rxed_packet(priv, skb);
 	priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
 }
 
-static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
+static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
 				      struct sk_buff *skb,
-				      struct usb_card_rec *cardp,
-				      wlan_private *priv)
+				      struct if_usb_card *cardp,
+				      struct lbs_private *priv)
 {
-	u8 *cmdbuf;
-	if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) {
+	if (recvlength > LBS_CMD_BUFFER_SIZE) {
 		lbs_deb_usbd(&cardp->udev->dev,
-			    "The receive buffer is too large\n");
+			     "The receive buffer is too large\n");
 		kfree_skb(skb);
 		return;
 	}
@@ -616,28 +600,17 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
 	if (!in_interrupt())
 		BUG();
 
-	spin_lock(&priv->adapter->driver_lock);
-	/* take care of cur_cmd = NULL case by reading the
-	 * data to clear the interrupt */
-	if (!priv->adapter->cur_cmd) {
-		cmdbuf = priv->upld_buf;
-		priv->adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
-	} else
-		cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
-
+	spin_lock(&priv->driver_lock);
 	cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;
 	priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
-	memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
-	       priv->upld_len);
+	memcpy(priv->upld_buf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len);
 
 	kfree_skb(skb);
-	libertas_interrupt(priv->dev);
-	spin_unlock(&priv->adapter->driver_lock);
+	lbs_interrupt(priv);
+	spin_unlock(&priv->driver_lock);
 
 	lbs_deb_usbd(&cardp->udev->dev,
 		    "Wake up main thread to handle cmd response\n");
-
-	return;
 }
 
 /**
@@ -649,35 +622,33 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
  */
 static void if_usb_receive(struct urb *urb)
 {
-	struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
-	struct sk_buff *skb = rinfo->skb;
-	struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp;
-	wlan_private * priv = cardp->priv;
-
+	struct if_usb_card *cardp = urb->context;
+	struct sk_buff *skb = cardp->rx_skb;
+	struct lbs_private *priv = cardp->priv;
 	int recvlength = urb->actual_length;
-	u8 *recvbuff = NULL;
-	u32 recvtype = 0;
+	uint8_t *recvbuff = NULL;
+	uint32_t recvtype = 0;
+	__le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
 
 	lbs_deb_enter(LBS_DEB_USB);
 
 	if (recvlength) {
-		__le32 tmp;
-
 		if (urb->status) {
-			lbs_deb_usbd(&cardp->udev->dev,
-				    "URB status is failed\n");
+			lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
+				     urb->status);
 			kfree_skb(skb);
 			goto setup_for_next;
 		}
 
 		recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
-		memcpy(&tmp, recvbuff, sizeof(u32));
-		recvtype = le32_to_cpu(tmp);
+		recvtype = le32_to_cpu(pkt[0]);
 		lbs_deb_usbd(&cardp->udev->dev,
 			    "Recv length = 0x%x, Recv type = 0x%X\n",
 			    recvlength, recvtype);
-	} else if (urb->status)
+	} else if (urb->status) {
+		kfree_skb(skb);
 		goto rx_exit;
+	}
 
 	switch (recvtype) {
 	case CMD_TYPE_DATA:
@@ -690,24 +661,28 @@ static void if_usb_receive(struct urb *urb)
 
 	case CMD_TYPE_INDICATION:
 		/* Event cause handling */
-		spin_lock(&priv->adapter->driver_lock);
-		cardp->usb_event_cause = le32_to_cpu(*(__le32 *) (recvbuff + MESSAGE_HEADER_LEN));
+		spin_lock(&priv->driver_lock);
+
+		cardp->usb_event_cause = le32_to_cpu(pkt[1]);
+
 		lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n",
-			    cardp->usb_event_cause);
+			     cardp->usb_event_cause);
+
+		/* Icky undocumented magic special case */
 		if (cardp->usb_event_cause & 0xffff0000) {
-			libertas_send_tx_feedback(priv);
-			spin_unlock(&priv->adapter->driver_lock);
+			lbs_send_tx_feedback(priv);
+			spin_unlock(&priv->driver_lock);
 			break;
 		}
 		cardp->usb_event_cause <<= 3;
 		cardp->usb_int_cause |= MRVDRV_CARDEVENT;
 		kfree_skb(skb);
-		libertas_interrupt(priv->dev);
-		spin_unlock(&priv->adapter->driver_lock);
+		lbs_interrupt(priv);
+		spin_unlock(&priv->driver_lock);
 		goto rx_exit;
 	default:
 		lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
-		             recvtype);
+			     recvtype);
 		kfree_skb(skb);
 		break;
 	}
@@ -720,58 +695,54 @@ rx_exit:
 
 /**
  *  @brief This function downloads data to FW
- *  @param priv		pointer to wlan_private structure
+ *  @param priv		pointer to struct lbs_private structure
  *  @param type		type of data
  *  @param buf		pointer to data buffer
  *  @param len		number of bytes
  *  @return 	   	0 or -1
  */
-static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
+static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
+			       uint8_t *payload, uint16_t nb)
 {
-	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+	struct if_usb_card *cardp = priv->card;
 
 	lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);
 	lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);
 
 	if (type == MVMS_CMD) {
-		__le32 tmp = cpu_to_le32(CMD_TYPE_REQUEST);
+		*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
 		priv->dnld_sent = DNLD_CMD_SENT;
-		memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
-		       MESSAGE_HEADER_LEN);
-
 	} else {
-		__le32 tmp = cpu_to_le32(CMD_TYPE_DATA);
+		*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA);
 		priv->dnld_sent = DNLD_DATA_SENT;
-		memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
-		       MESSAGE_HEADER_LEN);
 	}
 
-	memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
+	memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb);
 
-	return usb_tx_block(cardp, cardp->bulk_out_buffer,
-	                    nb + MESSAGE_HEADER_LEN);
+	return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
 }
 
-/* called with adapter->driver_lock held */
-static int if_usb_get_int_status(wlan_private * priv, u8 * ireg)
+/* called with priv->driver_lock held */
+static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *ireg)
 {
-	struct usb_card_rec *cardp = priv->card;
+	struct if_usb_card *cardp = priv->card;
 
 	*ireg = cardp->usb_int_cause;
 	cardp->usb_int_cause = 0;
 
-	lbs_deb_usbd(&cardp->udev->dev,"Int cause is 0x%X\n", *ireg);
+	lbs_deb_usbd(&cardp->udev->dev, "Int cause is 0x%X\n", *ireg);
 
 	return 0;
 }
 
-static int if_usb_read_event_cause(wlan_private * priv)
+static int if_usb_read_event_cause(struct lbs_private *priv)
 {
-	struct usb_card_rec *cardp = priv->card;
+	struct if_usb_card *cardp = priv->card;
 
-	priv->adapter->eventcause = cardp->usb_event_cause;
+	priv->eventcause = cardp->usb_event_cause;
 	/* Re-submit rx urb here to avoid event lost issue */
 	if_usb_submit_rx_urb(cardp);
+
 	return 0;
 }
 
@@ -781,20 +752,17 @@ static int if_usb_read_event_cause(wlan_private * priv)
  *                  2:Boot from FW in EEPROM
  *  @return 	   	0
  */
-static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue)
+static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
 {
-	struct bootcmdstr sbootcmd;
-	int i;
+	struct bootcmd *bootcmd = cardp->ep_out_buf;
 
 	/* Prepare command */
-	sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
-	sbootcmd.u8cmd_tag = ivalue;
-	for (i=0; i<11; i++)
-		sbootcmd.au8dumy[i]=0x00;
-	memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
+	bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
+	bootcmd->cmd = ivalue;
+	memset(bootcmd->pad, 0, sizeof(bootcmd->pad));
 
 	/* Issue command */
-	usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
+	usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd));
 
 	return 0;
 }
@@ -807,10 +775,10 @@ static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue)
  *         len               image length
  *  @return     0 or -1
  */
-static int check_fwfile_format(u8 *data, u32 totlen)
+static int check_fwfile_format(uint8_t *data, uint32_t totlen)
 {
-	u32 bincmd, exit;
-	u32 blksize, offset, len;
+	uint32_t bincmd, exit;
+	uint32_t blksize, offset, len;
 	int ret;
 
 	ret = 1;
@@ -848,7 +816,7 @@ static int check_fwfile_format(u8 *data, u32 totlen)
 }
 
 
-static int if_usb_prog_firmware(struct usb_card_rec *cardp)
+static int if_usb_prog_firmware(struct if_usb_card *cardp)
 {
 	int i = 0;
 	static int reset_count = 10;
@@ -856,10 +824,10 @@ static int if_usb_prog_firmware(struct usb_card_rec *cardp)
 
 	lbs_deb_enter(LBS_DEB_USB);
 
-	if ((ret = request_firmware(&cardp->fw, libertas_fw_name,
+	if ((ret = request_firmware(&cardp->fw, lbs_fw_name,
 				    &cardp->udev->dev)) < 0) {
 		lbs_pr_err("request_firmware() failed with %#x\n", ret);
-		lbs_pr_err("firmware %s not found\n", libertas_fw_name);
+		lbs_pr_err("firmware %s not found\n", lbs_fw_name);
 		goto done;
 	}
 
@@ -886,7 +854,7 @@ restart:
 		} while (cardp->bootcmdresp == 0 && j < 10);
 	} while (cardp->bootcmdresp == 0 && i < 5);
 
-	if (cardp->bootcmdresp == 0) {
+	if (cardp->bootcmdresp <= 0) {
 		if (--reset_count >= 0) {
 			if_usb_reset_device(cardp);
 			goto restart;
@@ -904,15 +872,14 @@ restart:
 	cardp->totalbytes = 0;
 	cardp->fwfinalblk = 0;
 
-	if_prog_firmware(cardp);
+	/* Send the first firmware packet... */
+	if_usb_send_fw_pkt(cardp);
 
-	do {
-		lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n");
-		i++;
-		msleep_interruptible(100);
-		if (cardp->surprise_removed || i >= 20)
-			break;
-	} while (!cardp->fwdnldover);
+	/* ... and wait for the process to complete */
+	wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover);
+
+	del_timer_sync(&cardp->fw_timeout);
+	usb_kill_urb(cardp->rx_urb);
 
 	if (!cardp->fwdnldover) {
 		lbs_pr_info("failed to load fw, resetting device!\n");
@@ -926,11 +893,11 @@ restart:
 		goto release_fw;
 	}
 
-release_fw:
+ release_fw:
 	release_firmware(cardp->fw);
 	cardp->fw = NULL;
 
-done:
+ done:
 	lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
 	return ret;
 }
@@ -939,66 +906,38 @@ done:
 #ifdef CONFIG_PM
 static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
 {
-	struct usb_card_rec *cardp = usb_get_intfdata(intf);
-	wlan_private *priv = cardp->priv;
+	struct if_usb_card *cardp = usb_get_intfdata(intf);
+	struct lbs_private *priv = cardp->priv;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_USB);
 
-	if (priv->adapter->psstate != PS_STATE_FULL_POWER)
+	if (priv->psstate != PS_STATE_FULL_POWER)
 		return -1;
 
-	if (priv->mesh_dev && !priv->mesh_autostart_enabled) {
-		/* Mesh autostart must be activated while sleeping
-		 * On resume it will go back to the current state
-		 */
-		struct cmd_ds_mesh_access mesh_access;
-		memset(&mesh_access, 0, sizeof(mesh_access));
-		mesh_access.data[0] = cpu_to_le32(1);
-		libertas_prepare_and_send_command(priv,
-				CMD_MESH_ACCESS,
-				CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
-				CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
-	}
-
-	netif_device_detach(cardp->eth_dev);
-	netif_device_detach(priv->mesh_dev);
+	ret = lbs_suspend(priv);
+	if (ret)
+		goto out;
 
 	/* Unlink tx & rx urb */
 	usb_kill_urb(cardp->tx_urb);
 	usb_kill_urb(cardp->rx_urb);
 
-	cardp->rx_urb_recall = 1;
-
+ out:
 	lbs_deb_leave(LBS_DEB_USB);
-	return 0;
+	return ret;
 }
 
 static int if_usb_resume(struct usb_interface *intf)
 {
-	struct usb_card_rec *cardp = usb_get_intfdata(intf);
-	wlan_private *priv = cardp->priv;
+	struct if_usb_card *cardp = usb_get_intfdata(intf);
+	struct lbs_private *priv = cardp->priv;
 
 	lbs_deb_enter(LBS_DEB_USB);
 
-	cardp->rx_urb_recall = 0;
-
-	if_usb_submit_rx_urb(cardp->priv);
+	if_usb_submit_rx_urb(cardp);
 
-	netif_device_attach(cardp->eth_dev);
-	netif_device_attach(priv->mesh_dev);
-
-	if (priv->mesh_dev && !priv->mesh_autostart_enabled) {
-		/* Mesh autostart was activated while sleeping
-		 * Disable it if appropriate
-		 */
-		struct cmd_ds_mesh_access mesh_access;
-		memset(&mesh_access, 0, sizeof(mesh_access));
-		mesh_access.data[0] = cpu_to_le32(0);
-		libertas_prepare_and_send_command(priv,
-				CMD_MESH_ACCESS,
-				CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
-				CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
-	}
+	lbs_resume(priv);
 
 	lbs_deb_leave(LBS_DEB_USB);
 	return 0;
@@ -1009,46 +948,30 @@ static int if_usb_resume(struct usb_interface *intf)
 #endif
 
 static struct usb_driver if_usb_driver = {
-	/* driver name */
-	.name = usbdriver_name,
-	/* probe function name */
+	.name = DRV_NAME,
 	.probe = if_usb_probe,
-	/* disconnect function  name */
 	.disconnect = if_usb_disconnect,
-	/* device signature table */
 	.id_table = if_usb_table,
 	.suspend = if_usb_suspend,
 	.resume = if_usb_resume,
 };
 
-static int if_usb_init_module(void)
+static int __init if_usb_init_module(void)
 {
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
-	if (libertas_fw_name == NULL) {
-		libertas_fw_name = default_fw_name;
-	}
-
 	ret = usb_register(&if_usb_driver);
 
 	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
 	return ret;
 }
 
-static void if_usb_exit_module(void)
+static void __exit if_usb_exit_module(void)
 {
-	struct usb_card_rec *cardp, *cardp_temp;
-
 	lbs_deb_enter(LBS_DEB_MAIN);
 
-	list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) {
-		libertas_prepare_and_send_command(cardp->priv, CMD_802_11_RESET,
-		                                  CMD_ACT_HALT, 0, 0, NULL);
-	}
-
-	/* API unregisters the driver from USB subsystem */
 	usb_deregister(&if_usb_driver);
 
 	lbs_deb_leave(LBS_DEB_MAIN);
@@ -1058,5 +981,5 @@ module_init(if_usb_init_module);
 module_exit(if_usb_exit_module);
 
 MODULE_DESCRIPTION("8388 USB WLAN Driver");
-MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
index e07a10ed28b5..e4829a391eb9 100644
--- a/drivers/net/wireless/libertas/if_usb.h
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -1,79 +1,76 @@
-#ifndef _LIBERTAS_IF_USB_H
-#define _LIBERTAS_IF_USB_H
+#ifndef _LBS_IF_USB_H
+#define _LBS_IF_USB_H
 
-#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+
+struct lbs_private;
 
 /**
   * This file contains definition for USB interface.
   */
-#define CMD_TYPE_REQUEST                0xF00DFACE
-#define CMD_TYPE_DATA                   0xBEADC0DE
-#define CMD_TYPE_INDICATION             0xBEEFFACE
+#define CMD_TYPE_REQUEST		0xF00DFACE
+#define CMD_TYPE_DATA			0xBEADC0DE
+#define CMD_TYPE_INDICATION		0xBEEFFACE
 
-#define IPFIELD_ALIGN_OFFSET	2
+#define IPFIELD_ALIGN_OFFSET		2
 
-#define BOOT_CMD_FW_BY_USB     0x01
-#define BOOT_CMD_FW_IN_EEPROM  0x02
-#define BOOT_CMD_UPDATE_BOOT2  0x03
-#define BOOT_CMD_UPDATE_FW     0x04
-#define BOOT_CMD_MAGIC_NUMBER  0x4C56524D   /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */
+#define BOOT_CMD_FW_BY_USB		0x01
+#define BOOT_CMD_FW_IN_EEPROM		0x02
+#define BOOT_CMD_UPDATE_BOOT2		0x03
+#define BOOT_CMD_UPDATE_FW		0x04
+#define BOOT_CMD_MAGIC_NUMBER		0x4C56524D   /* LVRM */
 
-struct bootcmdstr
+struct bootcmd
 {
-	__le32 u32magicnumber;
-	u8  u8cmd_tag;
-	u8  au8dumy[11];
+	__le32	magic;
+	uint8_t	cmd;
+	uint8_t	pad[11];
 };
 
-#define BOOT_CMD_RESP_OK     0x0001
-#define BOOT_CMD_RESP_FAIL   0x0000
+#define BOOT_CMD_RESP_OK		0x0001
+#define BOOT_CMD_RESP_FAIL		0x0000
 
-struct bootcmdrespStr
+struct bootcmdresp
 {
-	__le32 u32magicnumber;
-	u8  u8cmd_tag;
-	u8  u8result;
-	u8  au8dumy[2];
-};
-
-/* read callback private data */
-struct read_cb_info {
-        struct usb_card_rec *cardp;
-        struct sk_buff *skb;
+	__le32	magic;
+	uint8_t	cmd;
+	uint8_t	result;
+	uint8_t	pad[2];
 };
 
 /** USB card description structure*/
-struct usb_card_rec {
-	struct list_head list;
-	struct net_device *eth_dev;
+struct if_usb_card {
 	struct usb_device *udev;
 	struct urb *rx_urb, *tx_urb;
-	void *priv;
-	struct read_cb_info rinfo;
+	struct lbs_private *priv;
 
-	int bulk_in_size;
-	u8 bulk_in_endpointAddr;
+	struct sk_buff *rx_skb;
+	uint32_t usb_event_cause;
+	uint8_t usb_int_cause;
 
-	u8 *bulk_out_buffer;
-	int bulk_out_size;
-	u8 bulk_out_endpointAddr;
+	uint8_t ep_in;
+	uint8_t ep_out;
 
-	const struct firmware *fw;
-	u8 CRC_OK;
-	u32 fwseqnum;
-	u32 lastseqnum;
-	u32 totalbytes;
-	u32 fwlastblksent;
-	u8 fwdnldover;
-	u8 fwfinalblk;
-	u8 surprise_removed;
+	int8_t bootcmdresp;
 
-	u32 usb_event_cause;
-	u8 usb_int_cause;
+	int ep_in_size;
 
-	u8 rx_urb_recall;
+	void *ep_out_buf;
+	int ep_out_size;
 
-	u8 bootcmdresp;
+	const struct firmware *fw;
+	struct timer_list fw_timeout;
+	wait_queue_head_t fw_wq;
+	uint32_t fwseqnum;
+	uint32_t totalbytes;
+	uint32_t fwlastblksent;
+	uint8_t CRC_OK;
+	uint8_t fwdnldover;
+	uint8_t fwfinalblk;
+	uint8_t surprise_removed;
+
+	__le16 boot2_version;
 };
 
 /** fwheader */
@@ -86,10 +83,10 @@ struct fwheader {
 
 #define FW_MAX_DATA_BLK_SIZE	600
 /** FWData */
-struct FWData {
-	struct fwheader fwheader;
+struct fwdata {
+	struct fwheader hdr;
 	__le32 seqnum;
-	u8 data[FW_MAX_DATA_BLK_SIZE];
+	uint8_t data[0];
 };
 
 /** fwsyncheader */
@@ -101,7 +98,5 @@ struct fwsyncheader {
 #define FW_HAS_DATA_TO_RECV		0x00000001
 #define FW_HAS_LAST_BLOCK		0x00000004
 
-#define FW_DATA_XMIT_SIZE \
-	sizeof(struct fwheader) + le32_to_cpu(fwdata->fwheader.datalength) + sizeof(u32)
 
 #endif
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
index dc24a05c9447..2d4508048b68 100644
--- a/drivers/net/wireless/libertas/join.c
+++ b/drivers/net/wireless/libertas/join.c
@@ -30,16 +30,18 @@
  * NOTE: Setting the MSB of the basic rates need to be taken
  *   care, either before or after calling this function
  *
- *  @param adapter     A pointer to wlan_adapter structure
+ *  @param priv     A pointer to struct lbs_private structure
  *  @param rate1       the buffer which keeps input and output
  *  @param rate1_size  the size of rate1 buffer; new size of buffer on return
  *
  *  @return            0 or -1
  */
-static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size)
+static int get_common_rates(struct lbs_private *priv,
+	u8 *rates,
+	u16 *rates_size)
 {
-	u8 *card_rates = libertas_bg_rates;
-	size_t num_card_rates = sizeof(libertas_bg_rates);
+	u8 *card_rates = lbs_bg_rates;
+	size_t num_card_rates = sizeof(lbs_bg_rates);
 	int ret = 0, i, j;
 	u8 tmp[30];
 	size_t tmp_size = 0;
@@ -55,15 +57,15 @@ static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size)
 	lbs_deb_hex(LBS_DEB_JOIN, "AP rates    ", rates, *rates_size);
 	lbs_deb_hex(LBS_DEB_JOIN, "card rates  ", card_rates, num_card_rates);
 	lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
-	lbs_deb_join("Tx datarate is currently 0x%X\n", adapter->cur_rate);
+	lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
 
-	if (!adapter->auto_rate) {
+	if (!priv->auto_rate) {
 		for (i = 0; i < tmp_size; i++) {
-			if (tmp[i] == adapter->cur_rate)
+			if (tmp[i] == priv->cur_rate)
 				goto done;
 		}
 		lbs_pr_alert("Previously set fixed data rate %#x isn't "
-		       "compatible with the network.\n", adapter->cur_rate);
+		       "compatible with the network.\n", priv->cur_rate);
 		ret = -1;
 		goto done;
 	}
@@ -85,7 +87,7 @@ done:
  *  @param rates     buffer of data rates
  *  @param len       size of buffer
  */
-static void libertas_set_basic_rate_flags(u8 * rates, size_t len)
+static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
 {
 	int i;
 
@@ -104,7 +106,7 @@ static void libertas_set_basic_rate_flags(u8 * rates, size_t len)
  *  @param rates     buffer of data rates
  *  @param len       size of buffer
  */
-void libertas_unset_basic_rate_flags(u8 * rates, size_t len)
+void lbs_unset_basic_rate_flags(u8 *rates, size_t len)
 {
 	int i;
 
@@ -116,19 +118,18 @@ void libertas_unset_basic_rate_flags(u8 * rates, size_t len)
 /**
  *  @brief Associate to a specific BSS discovered in a scan
  *
- *  @param priv      A pointer to wlan_private structure
+ *  @param priv      A pointer to struct lbs_private structure
  *  @param pbssdesc  Pointer to the BSS descriptor to associate with.
  *
  *  @return          0-success, otherwise fail
  */
-int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req)
+int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret;
 
-	lbs_deb_enter(LBS_DEB_JOIN);
+	lbs_deb_enter(LBS_DEB_ASSOC);
 
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
 				    0, CMD_OPTION_WAITFORRSP,
 				    0, assoc_req->bss.bssid);
 
@@ -136,50 +137,50 @@ int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req)
 		goto done;
 
 	/* set preamble to firmware */
-	if (   (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+	if (   (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
 	    && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
-		adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
+		priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
 	else
-		adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
+		priv->preamble = CMD_TYPE_LONG_PREAMBLE;
 
-	libertas_set_radio_control(priv);
+	lbs_set_radio_control(priv);
 
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
 				    0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
 
 done:
-	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return ret;
 }
 
 /**
  *  @brief Start an Adhoc Network
  *
- *  @param priv         A pointer to wlan_private structure
+ *  @param priv         A pointer to struct lbs_private structure
  *  @param adhocssid    The ssid of the Adhoc Network
  *  @return             0--success, -1--fail
  */
-int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req)
+int lbs_start_adhoc_network(struct lbs_private *priv,
+	struct assoc_request *assoc_req)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 
-	adapter->adhoccreate = 1;
+	priv->adhoccreate = 1;
 
-	if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
+	if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
 		lbs_deb_join("AdhocStart: Short preamble\n");
-		adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
+		priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
 	} else {
 		lbs_deb_join("AdhocStart: Long preamble\n");
-		adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
+		priv->preamble = CMD_TYPE_LONG_PREAMBLE;
 	}
 
-	libertas_set_radio_control(priv);
+	lbs_set_radio_control(priv);
 
 	lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
 	lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
 
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
 				    0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
 
 	return ret;
@@ -188,34 +189,34 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass
 /**
  *  @brief Join an adhoc network found in a previous scan
  *
- *  @param priv         A pointer to wlan_private structure
+ *  @param priv         A pointer to struct lbs_private structure
  *  @param pbssdesc     Pointer to a BSS descriptor found in a previous scan
  *                      to attempt to join
  *
  *  @return             0--success, -1--fail
  */
-int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req)
+int lbs_join_adhoc_network(struct lbs_private *priv,
+	struct assoc_request *assoc_req)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct bss_descriptor * bss = &assoc_req->bss;
 	int ret = 0;
 
 	lbs_deb_join("%s: Current SSID '%s', ssid length %u\n",
 	             __func__,
-	             escape_essid(adapter->curbssparams.ssid,
-	                          adapter->curbssparams.ssid_len),
-	             adapter->curbssparams.ssid_len);
+	             escape_essid(priv->curbssparams.ssid,
+	                          priv->curbssparams.ssid_len),
+	             priv->curbssparams.ssid_len);
 	lbs_deb_join("%s: requested ssid '%s', ssid length %u\n",
 	             __func__, escape_essid(bss->ssid, bss->ssid_len),
 	             bss->ssid_len);
 
 	/* check if the requested SSID is already joined */
-	if (   adapter->curbssparams.ssid_len
-	    && !libertas_ssid_cmp(adapter->curbssparams.ssid,
-	                          adapter->curbssparams.ssid_len,
+	if (   priv->curbssparams.ssid_len
+	    && !lbs_ssid_cmp(priv->curbssparams.ssid,
+	                          priv->curbssparams.ssid_len,
 	                          bss->ssid, bss->ssid_len)
-	    && (adapter->mode == IW_MODE_ADHOC)
-	    && (adapter->connect_status == LIBERTAS_CONNECTED)) {
+	    && (priv->mode == IW_MODE_ADHOC)
+	    && (priv->connect_status == LBS_CONNECTED)) {
 		union iwreq_data wrqu;
 
 		lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
@@ -225,7 +226,7 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso
 		 * request really was successful, even if just a null-op.
 		 */
 		memset(&wrqu, 0, sizeof(wrqu));
-		memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid,
+		memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid,
 		       ETH_ALEN);
 		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 		wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
@@ -235,22 +236,22 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso
 	/* Use shortpreamble only when both creator and card supports
 	   short preamble */
 	if (   !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
-	    || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
+	    || !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
 		lbs_deb_join("AdhocJoin: Long preamble\n");
-		adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
+		priv->preamble = CMD_TYPE_LONG_PREAMBLE;
 	} else {
 		lbs_deb_join("AdhocJoin: Short preamble\n");
-		adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
+		priv->preamble = CMD_TYPE_SHORT_PREAMBLE;
 	}
 
-	libertas_set_radio_control(priv);
+	lbs_set_radio_control(priv);
 
 	lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel);
 	lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band);
 
-	adapter->adhoccreate = 0;
+	priv->adhoccreate = 0;
 
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
 				    0, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_SSID, assoc_req);
 
@@ -258,38 +259,37 @@ out:
 	return ret;
 }
 
-int libertas_stop_adhoc_network(wlan_private * priv)
+int lbs_stop_adhoc_network(struct lbs_private *priv)
 {
-	return libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
+	return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
 				     0, CMD_OPTION_WAITFORRSP, 0, NULL);
 }
 
 /**
  *  @brief Send Deauthentication Request
  *
- *  @param priv      A pointer to wlan_private structure
+ *  @param priv      A pointer to struct lbs_private structure
  *  @return          0--success, -1--fail
  */
-int libertas_send_deauthentication(wlan_private * priv)
+int lbs_send_deauthentication(struct lbs_private *priv)
 {
-	return libertas_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
+	return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
 				     0, CMD_OPTION_WAITFORRSP, 0, NULL);
 }
 
 /**
  *  @brief This function prepares command of authenticate.
  *
- *  @param priv      A pointer to wlan_private structure
+ *  @param priv      A pointer to struct lbs_private structure
  *  @param cmd       A pointer to cmd_ds_command structure
  *  @param pdata_buf Void cast of pointer to a BSSID to authenticate with
  *
  *  @return         0 or -1
  */
-int libertas_cmd_80211_authenticate(wlan_private * priv,
+int lbs_cmd_80211_authenticate(struct lbs_private *priv,
 				 struct cmd_ds_command *cmd,
 				 void *pdata_buf)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
 	int ret = -1;
 	u8 *bssid = pdata_buf;
@@ -302,7 +302,7 @@ int libertas_cmd_80211_authenticate(wlan_private * priv,
 	                        + S_DS_GEN);
 
 	/* translate auth mode to 802.11 defined wire value */
-	switch (adapter->secinfo.auth_mode) {
+	switch (priv->secinfo.auth_mode) {
 	case IW_AUTH_ALG_OPEN_SYSTEM:
 		pauthenticate->authtype = 0x00;
 		break;
@@ -314,13 +314,13 @@ int libertas_cmd_80211_authenticate(wlan_private * priv,
 		break;
 	default:
 		lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
-		             adapter->secinfo.auth_mode);
+		             priv->secinfo.auth_mode);
 		goto out;
 	}
 
 	memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
 
-	lbs_deb_join("AUTH_CMD: BSSID is : %s auth=0x%X\n",
+	lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
 	             print_mac(mac, bssid), pauthenticate->authtype);
 	ret = 0;
 
@@ -329,10 +329,9 @@ out:
 	return ret;
 }
 
-int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
 				   struct cmd_ds_command *cmd)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
 
 	lbs_deb_enter(LBS_DEB_JOIN);
@@ -342,7 +341,7 @@ int libertas_cmd_80211_deauthenticate(wlan_private * priv,
 			     S_DS_GEN);
 
 	/* set AP MAC address */
-	memmove(dauth->macaddr, adapter->curbssparams.bssid, ETH_ALEN);
+	memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN);
 
 	/* Reason code 3 = Station is leaving */
 #define REASON_CODE_STA_LEAVING 3
@@ -352,10 +351,9 @@ int libertas_cmd_80211_deauthenticate(wlan_private * priv,
 	return 0;
 }
 
-int libertas_cmd_80211_associate(wlan_private * priv,
+int lbs_cmd_80211_associate(struct lbs_private *priv,
 			      struct cmd_ds_command *cmd, void *pdata_buf)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
 	int ret = 0;
 	struct assoc_request * assoc_req = pdata_buf;
@@ -368,11 +366,11 @@ int libertas_cmd_80211_associate(wlan_private * priv,
 	struct mrvlietypes_ratesparamset *rates;
 	struct mrvlietypes_rsnparamset *rsn;
 
-	lbs_deb_enter(LBS_DEB_JOIN);
+	lbs_deb_enter(LBS_DEB_ASSOC);
 
 	pos = (u8 *) passo;
 
-	if (!adapter) {
+	if (!priv) {
 		ret = -1;
 		goto done;
 	}
@@ -416,22 +414,22 @@ int libertas_cmd_80211_associate(wlan_private * priv,
 	rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
 	memcpy(&rates->rates, &bss->rates, MAX_RATES);
 	tmplen = MAX_RATES;
-	if (get_common_rates(adapter, rates->rates, &tmplen)) {
+	if (get_common_rates(priv, rates->rates, &tmplen)) {
 		ret = -1;
 		goto done;
 	}
 	pos += sizeof(rates->header) + tmplen;
 	rates->header.len = cpu_to_le16(tmplen);
-	lbs_deb_join("ASSOC_CMD: num rates = %u\n", tmplen);
+	lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
 
 	/* Copy the infra. association rates into Current BSS state structure */
-	memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
-	memcpy(&adapter->curbssparams.rates, &rates->rates, tmplen);
+	memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
+	memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
 
 	/* Set MSB on basic rates as the firmware requires, but _after_
 	 * copying to current bss rates.
 	 */
-	libertas_set_basic_rate_flags(rates->rates, tmplen);
+	lbs_set_basic_rate_flags(rates->rates, tmplen);
 
 	if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
 		rsn = (struct mrvlietypes_rsnparamset *) pos;
@@ -446,9 +444,9 @@ int libertas_cmd_80211_associate(wlan_private * priv,
 	}
 
 	/* update curbssparams */
-	adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
+	priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
 
-	if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
+	if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
 		ret = -1;
 		goto done;
 	}
@@ -460,18 +458,16 @@ int libertas_cmd_80211_associate(wlan_private * priv,
 	if (bss->mode == IW_MODE_INFRA)
 		tmpcap |= WLAN_CAPABILITY_ESS;
 	passo->capability = cpu_to_le16(tmpcap);
-	lbs_deb_join("ASSOC_CMD: capability=%4X CAPINFO_MASK=%4X\n",
-		     tmpcap, CAPINFO_MASK);
+	lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
 
 done:
-	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return ret;
 }
 
-int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
 				 struct cmd_ds_command *cmd, void *pdata_buf)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
 	int ret = 0;
 	int cmdappendsize = 0;
@@ -481,7 +477,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
-	if (!adapter) {
+	if (!priv) {
 		ret = -1;
 		goto done;
 	}
@@ -491,7 +487,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
 	/*
 	 * Fill in the parameters for 2 data structures:
 	 *   1. cmd_ds_802_11_ad_hoc_start command
-	 *   2. adapter->scantable[i]
+	 *   2. priv->scantable[i]
 	 *
 	 * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
 	 *   probe delay, and cap info.
@@ -509,8 +505,10 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
 
 	/* set the BSS type */
 	adhs->bsstype = CMD_BSS_TYPE_IBSS;
-	adapter->mode = IW_MODE_ADHOC;
-	adhs->beaconperiod = cpu_to_le16(MRVDRV_BEACON_INTERVAL);
+	priv->mode = IW_MODE_ADHOC;
+	if (priv->beacon_period == 0)
+		priv->beacon_period = MRVDRV_BEACON_INTERVAL;
+	adhs->beaconperiod = cpu_to_le16(priv->beacon_period);
 
 	/* set Physical param set */
 #define DS_PARA_IE_ID   3
@@ -548,24 +546,24 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
 	adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
 
 	memset(adhs->rates, 0, sizeof(adhs->rates));
-	ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates));
-	memcpy(adhs->rates, libertas_bg_rates, ratesize);
+	ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates));
+	memcpy(adhs->rates, lbs_bg_rates, ratesize);
 
 	/* Copy the ad-hoc creating rates into Current BSS state structure */
-	memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
-	memcpy(&adapter->curbssparams.rates, &adhs->rates, ratesize);
+	memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
+	memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize);
 
 	/* Set MSB on basic rates as the firmware requires, but _after_
 	 * copying to current bss rates.
 	 */
-	libertas_set_basic_rate_flags(adhs->rates, ratesize);
+	lbs_set_basic_rate_flags(adhs->rates, ratesize);
 
 	lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
 	       adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
 
 	lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
 
-	if (libertas_create_dnld_countryinfo_11d(priv)) {
+	if (lbs_create_dnld_countryinfo_11d(priv)) {
 		lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
 		ret = -1;
 		goto done;
@@ -580,7 +578,7 @@ done:
 	return ret;
 }
 
-int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv,
 				struct cmd_ds_command *cmd)
 {
 	cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
@@ -589,10 +587,9 @@ int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
 	return 0;
 }
 
-int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
 				struct cmd_ds_command *cmd, void *pdata_buf)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
 	struct assoc_request * assoc_req = pdata_buf;
 	struct bss_descriptor *bss = &assoc_req->bss;
@@ -633,26 +630,26 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
 	/* probedelay */
 	join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
 
-	adapter->curbssparams.channel = bss->channel;
+	priv->curbssparams.channel = bss->channel;
 
 	/* Copy Data rates from the rates recorded in scan response */
 	memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
 	ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
 	memcpy(join_cmd->bss.rates, bss->rates, ratesize);
-	if (get_common_rates(adapter, join_cmd->bss.rates, &ratesize)) {
+	if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) {
 		lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
 		ret = -1;
 		goto done;
 	}
 
 	/* Copy the ad-hoc creating rates into Current BSS state structure */
-	memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
-	memcpy(&adapter->curbssparams.rates, join_cmd->bss.rates, ratesize);
+	memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
+	memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize);
 
 	/* Set MSB on basic rates as the firmware requires, but _after_
 	 * copying to current bss rates.
 	 */
-	libertas_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
+	lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
 
 	join_cmd->bss.ssparamset.ibssparamset.atimwindow =
 	    cpu_to_le16(bss->atimwindow);
@@ -663,12 +660,12 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
 		join_cmd->bss.capability = cpu_to_le16(tmp);
 	}
 
-	if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
+	if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
 		/* wake up first */
 		__le32 Localpsmode;
 
-		Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM);
-		ret = libertas_prepare_and_send_command(priv,
+		Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM);
+		ret = lbs_prepare_and_send_command(priv,
 					    CMD_802_11_PS_MODE,
 					    CMD_ACT_SET,
 					    0, 0, &Localpsmode);
@@ -679,7 +676,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
 		}
 	}
 
-	if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
+	if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
 		ret = -1;
 		goto done;
 	}
@@ -692,24 +689,23 @@ done:
 	return ret;
 }
 
-int libertas_ret_80211_associate(wlan_private * priv,
+int lbs_ret_80211_associate(struct lbs_private *priv,
 			      struct cmd_ds_command *resp)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 	union iwreq_data wrqu;
 	struct ieeetypes_assocrsp *passocrsp;
 	struct bss_descriptor * bss;
 	u16 status_code;
 
-	lbs_deb_enter(LBS_DEB_JOIN);
+	lbs_deb_enter(LBS_DEB_ASSOC);
 
-	if (!adapter->in_progress_assoc_req) {
-		lbs_deb_join("ASSOC_RESP: no in-progress association request\n");
+	if (!priv->in_progress_assoc_req) {
+		lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
 		ret = -1;
 		goto done;
 	}
-	bss = &adapter->in_progress_assoc_req->bss;
+	bss = &priv->in_progress_assoc_req->bss;
 
 	passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
 
@@ -734,96 +730,83 @@ int libertas_ret_80211_associate(wlan_private * priv,
 	status_code = le16_to_cpu(passocrsp->statuscode);
 	switch (status_code) {
 	case 0x00:
-		lbs_deb_join("ASSOC_RESP: Association succeeded\n");
 		break;
 	case 0x01:
-		lbs_deb_join("ASSOC_RESP: Association failed; invalid "
-		             "parameters (status code %d)\n", status_code);
+		lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
 		break;
 	case 0x02:
-		lbs_deb_join("ASSOC_RESP: Association failed; internal timer "
-		             "expired while waiting for the AP (status code %d)"
-		             "\n", status_code);
+		lbs_deb_assoc("ASSOC_RESP: internal timer "
+			"expired while waiting for the AP\n");
 		break;
 	case 0x03:
-		lbs_deb_join("ASSOC_RESP: Association failed; association "
-		             "was refused by the AP (status code %d)\n",
-		             status_code);
+		lbs_deb_assoc("ASSOC_RESP: association "
+			"refused by AP\n");
 		break;
 	case 0x04:
-		lbs_deb_join("ASSOC_RESP: Association failed; authentication "
-		             "was refused by the AP (status code %d)\n",
-		             status_code);
+		lbs_deb_assoc("ASSOC_RESP: authentication "
+			"refused by AP\n");
 		break;
 	default:
-		lbs_deb_join("ASSOC_RESP: Association failed; reason unknown "
-		             "(status code %d)\n", status_code);
+		lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
+			" unknown\n", status_code);
 		break;
 	}
 
 	if (status_code) {
-		libertas_mac_event_disconnected(priv);
+		lbs_mac_event_disconnected(priv);
 		ret = -1;
 		goto done;
 	}
 
-	lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_RESP", (void *)&resp->params,
+	lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params,
 		le16_to_cpu(resp->size) - S_DS_GEN);
 
 	/* Send a Media Connected event, according to the Spec */
-	adapter->connect_status = LIBERTAS_CONNECTED;
-
-	lbs_deb_join("ASSOC_RESP: assocated to '%s'\n",
-	             escape_essid(bss->ssid, bss->ssid_len));
+	priv->connect_status = LBS_CONNECTED;
 
 	/* Update current SSID and BSSID */
-	memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
-	adapter->curbssparams.ssid_len = bss->ssid_len;
-	memcpy(adapter->curbssparams.bssid, bss->bssid, ETH_ALEN);
+	memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+	priv->curbssparams.ssid_len = bss->ssid_len;
+	memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
 
-	lbs_deb_join("ASSOC_RESP: currentpacketfilter is %x\n",
-	       adapter->currentpacketfilter);
+	lbs_deb_assoc("ASSOC_RESP: currentpacketfilter is 0x%x\n",
+		priv->currentpacketfilter);
 
-	adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
-	adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
+	priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
+	priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
 
-	memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
-	memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
-	adapter->nextSNRNF = 0;
-	adapter->numSNRNF = 0;
+	memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
+	memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
+	priv->nextSNRNF = 0;
+	priv->numSNRNF = 0;
 
 	netif_carrier_on(priv->dev);
-	netif_wake_queue(priv->dev);
-
-	if (priv->mesh_dev) {
-		netif_carrier_on(priv->mesh_dev);
-		netif_wake_queue(priv->mesh_dev);
-	}
+	if (!priv->tx_pending_len)
+		netif_wake_queue(priv->dev);
 
-	memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+	memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
 
 done:
-	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return ret;
 }
 
-int libertas_ret_80211_disassociate(wlan_private * priv,
+int lbs_ret_80211_disassociate(struct lbs_private *priv,
 				 struct cmd_ds_command *resp)
 {
 	lbs_deb_enter(LBS_DEB_JOIN);
 
-	libertas_mac_event_disconnected(priv);
+	lbs_mac_event_disconnected(priv);
 
 	lbs_deb_leave(LBS_DEB_JOIN);
 	return 0;
 }
 
-int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
 				 struct cmd_ds_command *resp)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 	u16 command = le16_to_cpu(resp->command);
 	u16 result = le16_to_cpu(resp->result);
@@ -840,20 +823,20 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
 	lbs_deb_join("ADHOC_RESP: command = %x\n", command);
 	lbs_deb_join("ADHOC_RESP: result = %x\n", result);
 
-	if (!adapter->in_progress_assoc_req) {
+	if (!priv->in_progress_assoc_req) {
 		lbs_deb_join("ADHOC_RESP: no in-progress association request\n");
 		ret = -1;
 		goto done;
 	}
-	bss = &adapter->in_progress_assoc_req->bss;
+	bss = &priv->in_progress_assoc_req->bss;
 
 	/*
 	 * Join result code 0 --> SUCCESS
 	 */
 	if (result) {
 		lbs_deb_join("ADHOC_RESP: failed\n");
-		if (adapter->connect_status == LIBERTAS_CONNECTED) {
-			libertas_mac_event_disconnected(priv);
+		if (priv->connect_status == LBS_CONNECTED) {
+			lbs_mac_event_disconnected(priv);
 		}
 		ret = -1;
 		goto done;
@@ -867,7 +850,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
 	             escape_essid(bss->ssid, bss->ssid_len));
 
 	/* Send a Media Connected event, according to the Spec */
-	adapter->connect_status = LIBERTAS_CONNECTED;
+	priv->connect_status = LBS_CONNECTED;
 
 	if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
 		/* Update the created network descriptor with the new BSSID */
@@ -875,27 +858,23 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
 	}
 
 	/* Set the BSSID from the joined/started descriptor */
-	memcpy(&adapter->curbssparams.bssid, bss->bssid, ETH_ALEN);
+	memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
 
 	/* Set the new SSID to current SSID */
-	memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
-	adapter->curbssparams.ssid_len = bss->ssid_len;
+	memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
+	priv->curbssparams.ssid_len = bss->ssid_len;
 
 	netif_carrier_on(priv->dev);
-	netif_wake_queue(priv->dev);
-
-	if (priv->mesh_dev) {
-		netif_carrier_on(priv->mesh_dev);
-		netif_wake_queue(priv->mesh_dev);
-	}
+	if (!priv->tx_pending_len)
+		netif_wake_queue(priv->dev);
 
 	memset(&wrqu, 0, sizeof(wrqu));
-	memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+	memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
 
 	lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
-	lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel);
+	lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel);
 	lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
 		     print_mac(mac, padhocresult->bssid));
 
@@ -904,12 +883,12 @@ done:
 	return ret;
 }
 
-int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv,
 				struct cmd_ds_command *resp)
 {
 	lbs_deb_enter(LBS_DEB_JOIN);
 
-	libertas_mac_event_disconnected(priv);
+	lbs_mac_event_disconnected(priv);
 
 	lbs_deb_leave(LBS_DEB_JOIN);
 	return 0;
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
index 894a072b9f8d..c617d071f781 100644
--- a/drivers/net/wireless/libertas/join.h
+++ b/drivers/net/wireless/libertas/join.h
@@ -2,52 +2,52 @@
   * Interface for the wlan infrastructure and adhoc join routines
   *
   * Driver interface functions and type declarations for the join module
-  *   implemented in wlan_join.c.  Process all start/join requests for
+  *   implemented in join.c.  Process all start/join requests for
   *   both adhoc and infrastructure networks
   */
-#ifndef _WLAN_JOIN_H
-#define _WLAN_JOIN_H
+#ifndef _LBS_JOIN_H
+#define _LBS_JOIN_H
 
 #include "defs.h"
 #include "dev.h"
 
 struct cmd_ds_command;
-int libertas_cmd_80211_authenticate(wlan_private * priv,
+int lbs_cmd_80211_authenticate(struct lbs_private *priv,
 					struct cmd_ds_command *cmd,
 					void *pdata_buf);
-int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv,
 				       struct cmd_ds_command *cmd,
 				       void *pdata_buf);
-int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv,
 				       struct cmd_ds_command *cmd);
-int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv,
 					struct cmd_ds_command *cmd,
 					void *pdata_buf);
-int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
 					  struct cmd_ds_command *cmd);
-int libertas_cmd_80211_associate(wlan_private * priv,
+int lbs_cmd_80211_associate(struct lbs_private *priv,
 				     struct cmd_ds_command *cmd,
 				     void *pdata_buf);
 
-int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
 					struct cmd_ds_command *resp);
-int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv,
 				       struct cmd_ds_command *resp);
-int libertas_ret_80211_disassociate(wlan_private * priv,
+int lbs_ret_80211_disassociate(struct lbs_private *priv,
 					struct cmd_ds_command *resp);
-int libertas_ret_80211_associate(wlan_private * priv,
+int lbs_ret_80211_associate(struct lbs_private *priv,
 				     struct cmd_ds_command *resp);
 
-int libertas_start_adhoc_network(wlan_private * priv,
+int lbs_start_adhoc_network(struct lbs_private *priv,
 			     struct assoc_request * assoc_req);
-int libertas_join_adhoc_network(wlan_private * priv,
+int lbs_join_adhoc_network(struct lbs_private *priv,
 				struct assoc_request * assoc_req);
-int libertas_stop_adhoc_network(wlan_private * priv);
+int lbs_stop_adhoc_network(struct lbs_private *priv);
 
-int libertas_send_deauthentication(wlan_private * priv);
+int lbs_send_deauthentication(struct lbs_private *priv);
 
-int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req);
+int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req);
 
-void libertas_unset_basic_rate_flags(u8 * rates, size_t len);
+void lbs_unset_basic_rate_flags(u8 *rates, size_t len);
 
 #endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 1823b48a8ba7..84fb49ca0fae 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -6,7 +6,6 @@
 
 #include <linux/moduleparam.h>
 #include <linux/delay.h>
-#include <linux/freezer.h>
 #include <linux/etherdevice.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
@@ -22,9 +21,10 @@
 #include "debugfs.h"
 #include "assoc.h"
 #include "join.h"
+#include "cmd.h"
 
 #define DRIVER_RELEASE_VERSION "323.p0"
-const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
+const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
 #ifdef  DEBUG
     "-dbg"
 #endif
@@ -32,80 +32,80 @@ const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
 
 
 /* Module parameters */
-unsigned int libertas_debug = 0;
-module_param(libertas_debug, int, 0644);
-EXPORT_SYMBOL_GPL(libertas_debug);
+unsigned int lbs_debug;
+EXPORT_SYMBOL_GPL(lbs_debug);
+module_param_named(libertas_debug, lbs_debug, int, 0644);
 
 
-#define WLAN_TX_PWR_DEFAULT		20	/*100mW */
-#define WLAN_TX_PWR_US_DEFAULT		20	/*100mW */
-#define WLAN_TX_PWR_JP_DEFAULT		16	/*50mW */
-#define WLAN_TX_PWR_FR_DEFAULT		20	/*100mW */
-#define WLAN_TX_PWR_EMEA_DEFAULT	20	/*100mW */
+#define LBS_TX_PWR_DEFAULT		20	/*100mW */
+#define LBS_TX_PWR_US_DEFAULT		20	/*100mW */
+#define LBS_TX_PWR_JP_DEFAULT		16	/*50mW */
+#define LBS_TX_PWR_FR_DEFAULT		20	/*100mW */
+#define LBS_TX_PWR_EMEA_DEFAULT	20	/*100mW */
 
 /* Format { channel, frequency (MHz), maxtxpower } */
 /* band: 'B/G', region: USA FCC/Canada IC */
 static struct chan_freq_power channel_freq_power_US_BG[] = {
-	{1, 2412, WLAN_TX_PWR_US_DEFAULT},
-	{2, 2417, WLAN_TX_PWR_US_DEFAULT},
-	{3, 2422, WLAN_TX_PWR_US_DEFAULT},
-	{4, 2427, WLAN_TX_PWR_US_DEFAULT},
-	{5, 2432, WLAN_TX_PWR_US_DEFAULT},
-	{6, 2437, WLAN_TX_PWR_US_DEFAULT},
-	{7, 2442, WLAN_TX_PWR_US_DEFAULT},
-	{8, 2447, WLAN_TX_PWR_US_DEFAULT},
-	{9, 2452, WLAN_TX_PWR_US_DEFAULT},
-	{10, 2457, WLAN_TX_PWR_US_DEFAULT},
-	{11, 2462, WLAN_TX_PWR_US_DEFAULT}
+	{1, 2412, LBS_TX_PWR_US_DEFAULT},
+	{2, 2417, LBS_TX_PWR_US_DEFAULT},
+	{3, 2422, LBS_TX_PWR_US_DEFAULT},
+	{4, 2427, LBS_TX_PWR_US_DEFAULT},
+	{5, 2432, LBS_TX_PWR_US_DEFAULT},
+	{6, 2437, LBS_TX_PWR_US_DEFAULT},
+	{7, 2442, LBS_TX_PWR_US_DEFAULT},
+	{8, 2447, LBS_TX_PWR_US_DEFAULT},
+	{9, 2452, LBS_TX_PWR_US_DEFAULT},
+	{10, 2457, LBS_TX_PWR_US_DEFAULT},
+	{11, 2462, LBS_TX_PWR_US_DEFAULT}
 };
 
 /* band: 'B/G', region: Europe ETSI */
 static struct chan_freq_power channel_freq_power_EU_BG[] = {
-	{1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
-	{2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
-	{3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
-	{4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
-	{5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
-	{6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
-	{7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
-	{8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
-	{9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
-	{10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
-	{11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
-	{12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
-	{13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
+	{1, 2412, LBS_TX_PWR_EMEA_DEFAULT},
+	{2, 2417, LBS_TX_PWR_EMEA_DEFAULT},
+	{3, 2422, LBS_TX_PWR_EMEA_DEFAULT},
+	{4, 2427, LBS_TX_PWR_EMEA_DEFAULT},
+	{5, 2432, LBS_TX_PWR_EMEA_DEFAULT},
+	{6, 2437, LBS_TX_PWR_EMEA_DEFAULT},
+	{7, 2442, LBS_TX_PWR_EMEA_DEFAULT},
+	{8, 2447, LBS_TX_PWR_EMEA_DEFAULT},
+	{9, 2452, LBS_TX_PWR_EMEA_DEFAULT},
+	{10, 2457, LBS_TX_PWR_EMEA_DEFAULT},
+	{11, 2462, LBS_TX_PWR_EMEA_DEFAULT},
+	{12, 2467, LBS_TX_PWR_EMEA_DEFAULT},
+	{13, 2472, LBS_TX_PWR_EMEA_DEFAULT}
 };
 
 /* band: 'B/G', region: Spain */
 static struct chan_freq_power channel_freq_power_SPN_BG[] = {
-	{10, 2457, WLAN_TX_PWR_DEFAULT},
-	{11, 2462, WLAN_TX_PWR_DEFAULT}
+	{10, 2457, LBS_TX_PWR_DEFAULT},
+	{11, 2462, LBS_TX_PWR_DEFAULT}
 };
 
 /* band: 'B/G', region: France */
 static struct chan_freq_power channel_freq_power_FR_BG[] = {
-	{10, 2457, WLAN_TX_PWR_FR_DEFAULT},
-	{11, 2462, WLAN_TX_PWR_FR_DEFAULT},
-	{12, 2467, WLAN_TX_PWR_FR_DEFAULT},
-	{13, 2472, WLAN_TX_PWR_FR_DEFAULT}
+	{10, 2457, LBS_TX_PWR_FR_DEFAULT},
+	{11, 2462, LBS_TX_PWR_FR_DEFAULT},
+	{12, 2467, LBS_TX_PWR_FR_DEFAULT},
+	{13, 2472, LBS_TX_PWR_FR_DEFAULT}
 };
 
 /* band: 'B/G', region: Japan */
 static struct chan_freq_power channel_freq_power_JPN_BG[] = {
-	{1, 2412, WLAN_TX_PWR_JP_DEFAULT},
-	{2, 2417, WLAN_TX_PWR_JP_DEFAULT},
-	{3, 2422, WLAN_TX_PWR_JP_DEFAULT},
-	{4, 2427, WLAN_TX_PWR_JP_DEFAULT},
-	{5, 2432, WLAN_TX_PWR_JP_DEFAULT},
-	{6, 2437, WLAN_TX_PWR_JP_DEFAULT},
-	{7, 2442, WLAN_TX_PWR_JP_DEFAULT},
-	{8, 2447, WLAN_TX_PWR_JP_DEFAULT},
-	{9, 2452, WLAN_TX_PWR_JP_DEFAULT},
-	{10, 2457, WLAN_TX_PWR_JP_DEFAULT},
-	{11, 2462, WLAN_TX_PWR_JP_DEFAULT},
-	{12, 2467, WLAN_TX_PWR_JP_DEFAULT},
-	{13, 2472, WLAN_TX_PWR_JP_DEFAULT},
-	{14, 2484, WLAN_TX_PWR_JP_DEFAULT}
+	{1, 2412, LBS_TX_PWR_JP_DEFAULT},
+	{2, 2417, LBS_TX_PWR_JP_DEFAULT},
+	{3, 2422, LBS_TX_PWR_JP_DEFAULT},
+	{4, 2427, LBS_TX_PWR_JP_DEFAULT},
+	{5, 2432, LBS_TX_PWR_JP_DEFAULT},
+	{6, 2437, LBS_TX_PWR_JP_DEFAULT},
+	{7, 2442, LBS_TX_PWR_JP_DEFAULT},
+	{8, 2447, LBS_TX_PWR_JP_DEFAULT},
+	{9, 2452, LBS_TX_PWR_JP_DEFAULT},
+	{10, 2457, LBS_TX_PWR_JP_DEFAULT},
+	{11, 2462, LBS_TX_PWR_JP_DEFAULT},
+	{12, 2467, LBS_TX_PWR_JP_DEFAULT},
+	{13, 2472, LBS_TX_PWR_JP_DEFAULT},
+	{14, 2484, LBS_TX_PWR_JP_DEFAULT}
 };
 
 /**
@@ -153,13 +153,13 @@ static struct region_cfp_table region_cfp_table[] = {
 /**
  * the table to keep region code
  */
-u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
     { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
 
 /**
  * 802.11b/g supported bitrates (in 500Kb/s units)
  */
-u8 libertas_bg_rates[MAX_RATES] =
+u8 lbs_bg_rates[MAX_RATES] =
     { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
 0x00, 0x00 };
 
@@ -179,7 +179,7 @@ static u8 fw_data_rates[MAX_RATES] =
  *  @param idx                The index of data rate
  *  @return 	   		data rate or 0
  */
-u32 libertas_fw_index_to_data_rate(u8 idx)
+u32 lbs_fw_index_to_data_rate(u8 idx)
 {
 	if (idx >= sizeof(fw_data_rates))
 		idx = 0;
@@ -192,7 +192,7 @@ u32 libertas_fw_index_to_data_rate(u8 idx)
  *  @param rate                 data rate
  *  @return 	   		index or 0
  */
-u8 libertas_data_rate_to_fw_index(u32 rate)
+u8 lbs_data_rate_to_fw_index(u32 rate)
 {
 	u8 i;
 
@@ -213,16 +213,18 @@ u8 libertas_data_rate_to_fw_index(u32 rate)
 /**
  * @brief Get function for sysfs attribute anycast_mask
  */
-static ssize_t libertas_anycast_get(struct device * dev,
+static ssize_t lbs_anycast_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
 {
+	struct lbs_private *priv = to_net_dev(dev)->priv;
 	struct cmd_ds_mesh_access mesh_access;
+	int ret;
 
 	memset(&mesh_access, 0, sizeof(mesh_access));
-	libertas_prepare_and_send_command(to_net_dev(dev)->priv,
-			CMD_MESH_ACCESS,
-			CMD_ACT_MESH_GET_ANYCAST,
-			CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+
+	ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
+	if (ret)
+		return ret;
 
 	return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
 }
@@ -230,244 +232,191 @@ static ssize_t libertas_anycast_get(struct device * dev,
 /**
  * @brief Set function for sysfs attribute anycast_mask
  */
-static ssize_t libertas_anycast_set(struct device * dev,
+static ssize_t lbs_anycast_set(struct device *dev,
 		struct device_attribute *attr, const char * buf, size_t count)
 {
+	struct lbs_private *priv = to_net_dev(dev)->priv;
 	struct cmd_ds_mesh_access mesh_access;
 	uint32_t datum;
+	int ret;
 
 	memset(&mesh_access, 0, sizeof(mesh_access));
 	sscanf(buf, "%x", &datum);
 	mesh_access.data[0] = cpu_to_le32(datum);
 
-	libertas_prepare_and_send_command((to_net_dev(dev))->priv,
-			CMD_MESH_ACCESS,
-			CMD_ACT_MESH_SET_ANYCAST,
-			CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+	ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
+	if (ret)
+		return ret;
+
 	return strlen(buf);
 }
 
-int libertas_add_rtap(wlan_private *priv);
-void libertas_remove_rtap(wlan_private *priv);
+static int lbs_add_rtap(struct lbs_private *priv);
+static void lbs_remove_rtap(struct lbs_private *priv);
+static int lbs_add_mesh(struct lbs_private *priv);
+static void lbs_remove_mesh(struct lbs_private *priv);
+
 
 /**
  * Get function for sysfs attribute rtap
  */
-static ssize_t libertas_rtap_get(struct device * dev,
+static ssize_t lbs_rtap_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
 {
-	wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv;
-	wlan_adapter *adapter = priv->adapter;
-	return snprintf(buf, 5, "0x%X\n", adapter->monitormode);
+	struct lbs_private *priv = to_net_dev(dev)->priv;
+	return snprintf(buf, 5, "0x%X\n", priv->monitormode);
 }
 
 /**
  *  Set function for sysfs attribute rtap
  */
-static ssize_t libertas_rtap_set(struct device * dev,
+static ssize_t lbs_rtap_set(struct device *dev,
 		struct device_attribute *attr, const char * buf, size_t count)
 {
 	int monitor_mode;
-	wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = to_net_dev(dev)->priv;
 
 	sscanf(buf, "%x", &monitor_mode);
-	if (monitor_mode != WLAN_MONITOR_OFF) {
-		if(adapter->monitormode == monitor_mode)
+	if (monitor_mode != LBS_MONITOR_OFF) {
+		if(priv->monitormode == monitor_mode)
 			return strlen(buf);
-		if (adapter->monitormode == WLAN_MONITOR_OFF) {
-			if (adapter->mode == IW_MODE_INFRA)
-				libertas_send_deauthentication(priv);
-			else if (adapter->mode == IW_MODE_ADHOC)
-				libertas_stop_adhoc_network(priv);
-			libertas_add_rtap(priv);
+		if (priv->monitormode == LBS_MONITOR_OFF) {
+			if (priv->infra_open || priv->mesh_open)
+				return -EBUSY;
+			if (priv->mode == IW_MODE_INFRA)
+				lbs_send_deauthentication(priv);
+			else if (priv->mode == IW_MODE_ADHOC)
+				lbs_stop_adhoc_network(priv);
+			lbs_add_rtap(priv);
 		}
-		adapter->monitormode = monitor_mode;
+		priv->monitormode = monitor_mode;
 	}
 
 	else {
-		if(adapter->monitormode == WLAN_MONITOR_OFF)
+		if (priv->monitormode == LBS_MONITOR_OFF)
 			return strlen(buf);
-		adapter->monitormode = WLAN_MONITOR_OFF;
-		libertas_remove_rtap(priv);
-		netif_wake_queue(priv->dev);
-		netif_wake_queue(priv->mesh_dev);
+		priv->monitormode = LBS_MONITOR_OFF;
+		lbs_remove_rtap(priv);
+
+		if (priv->currenttxskb) {
+			dev_kfree_skb_any(priv->currenttxskb);
+			priv->currenttxskb = NULL;
+		}
+
+		/* Wake queues, command thread, etc. */
+		lbs_host_to_card_done(priv);
 	}
 
-	libertas_prepare_and_send_command(priv,
+	lbs_prepare_and_send_command(priv,
 			CMD_802_11_MONITOR_MODE, CMD_ACT_SET,
-			CMD_OPTION_WAITFORRSP, 0, &adapter->monitormode);
+			CMD_OPTION_WAITFORRSP, 0, &priv->monitormode);
 	return strlen(buf);
 }
 
 /**
- * libertas_rtap attribute to be exported per mshX interface
- * through sysfs (/sys/class/net/mshX/libertas-rtap)
+ * lbs_rtap attribute to be exported per ethX interface
+ * through sysfs (/sys/class/net/ethX/lbs_rtap)
  */
-static DEVICE_ATTR(libertas_rtap, 0644, libertas_rtap_get,
-		libertas_rtap_set );
+static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
 
 /**
- * anycast_mask attribute to be exported per mshX interface
- * through sysfs (/sys/class/net/mshX/anycast_mask)
+ * Get function for sysfs attribute mesh
  */
-static DEVICE_ATTR(anycast_mask, 0644, libertas_anycast_get, libertas_anycast_set);
-
-static ssize_t libertas_autostart_enabled_get(struct device * dev,
+static ssize_t lbs_mesh_get(struct device *dev,
 		struct device_attribute *attr, char * buf)
 {
-	struct cmd_ds_mesh_access mesh_access;
-
-	memset(&mesh_access, 0, sizeof(mesh_access));
-	libertas_prepare_and_send_command(to_net_dev(dev)->priv,
-			CMD_MESH_ACCESS,
-			CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
-			CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
-
-	return sprintf(buf, "%d\n", le32_to_cpu(mesh_access.data[0]));
+	struct lbs_private *priv = to_net_dev(dev)->priv;
+	return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
 }
 
-static ssize_t libertas_autostart_enabled_set(struct device * dev,
+/**
+ *  Set function for sysfs attribute mesh
+ */
+static ssize_t lbs_mesh_set(struct device *dev,
 		struct device_attribute *attr, const char * buf, size_t count)
 {
-	struct cmd_ds_mesh_access mesh_access;
-	uint32_t datum;
-	wlan_private * priv = (to_net_dev(dev))->priv;
+	struct lbs_private *priv = to_net_dev(dev)->priv;
+	int enable;
 	int ret;
 
-	memset(&mesh_access, 0, sizeof(mesh_access));
-	sscanf(buf, "%d", &datum);
-	mesh_access.data[0] = cpu_to_le32(datum);
+	sscanf(buf, "%x", &enable);
+	enable = !!enable;
+	if (enable == !!priv->mesh_dev)
+		return count;
+
+	ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel);
+	if (ret)
+		return ret;
 
-	ret = libertas_prepare_and_send_command(priv,
-			CMD_MESH_ACCESS,
-			CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
-			CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
-	if (ret == 0)
-		priv->mesh_autostart_enabled = datum ? 1 : 0;
+	if (enable)
+		lbs_add_mesh(priv);
+	else
+		lbs_remove_mesh(priv);
 
-	return strlen(buf);
+	return count;
 }
 
-static DEVICE_ATTR(autostart_enabled, 0644,
-		libertas_autostart_enabled_get, libertas_autostart_enabled_set);
+/**
+ * lbs_mesh attribute to be exported per ethX interface
+ * through sysfs (/sys/class/net/ethX/lbs_mesh)
+ */
+static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
 
-static struct attribute *libertas_mesh_sysfs_entries[] = {
+/**
+ * anycast_mask attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/anycast_mask)
+ */
+static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
+
+static struct attribute *lbs_mesh_sysfs_entries[] = {
 	&dev_attr_anycast_mask.attr,
-	&dev_attr_autostart_enabled.attr,
 	NULL,
 };
 
-static struct attribute_group libertas_mesh_attr_group = {
-	.attrs = libertas_mesh_sysfs_entries,
+static struct attribute_group lbs_mesh_attr_group = {
+	.attrs = lbs_mesh_sysfs_entries,
 };
 
 /**
- *  @brief Check if the device can be open and wait if necessary.
- *
- *  @param dev     A pointer to net_device structure
- *  @return 	   0
- *
- * For USB adapter, on some systems the device open handler will be
- * called before FW ready. Use the following flag check and wait
- * function to work around the issue.
- *
- */
-static int pre_open_check(struct net_device *dev)
-{
-	wlan_private *priv = (wlan_private *) dev->priv;
-	wlan_adapter *adapter = priv->adapter;
-	int i = 0;
-
-	while (!adapter->fw_ready && i < 20) {
-		i++;
-		msleep_interruptible(100);
-	}
-	if (!adapter->fw_ready) {
-		lbs_pr_err("firmware not ready\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-/**
- *  @brief This function opens the device
+ *  @brief This function opens the ethX or mshX interface
  *
  *  @param dev     A pointer to net_device structure
- *  @return 	   0
+ *  @return 	   0 or -EBUSY if monitor mode active
  */
-static int libertas_dev_open(struct net_device *dev)
+static int lbs_dev_open(struct net_device *dev)
 {
-	wlan_private *priv = (wlan_private *) dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = (struct lbs_private *) dev->priv ;
+	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_NET);
 
-	priv->open = 1;
+	spin_lock_irq(&priv->driver_lock);
 
-	if (adapter->connect_status == LIBERTAS_CONNECTED) {
-		netif_carrier_on(priv->dev);
-		if (priv->mesh_dev)
-			netif_carrier_on(priv->mesh_dev);
-	} else {
-		netif_carrier_off(priv->dev);
-		if (priv->mesh_dev)
-			netif_carrier_off(priv->mesh_dev);
+	if (priv->monitormode != LBS_MONITOR_OFF) {
+		ret = -EBUSY;
+		goto out;
 	}
 
-	lbs_deb_leave(LBS_DEB_NET);
-	return 0;
-}
-/**
- *  @brief This function opens the mshX interface
- *
- *  @param dev     A pointer to net_device structure
- *  @return 	   0
- */
-static int libertas_mesh_open(struct net_device *dev)
-{
-	wlan_private *priv = (wlan_private *) dev->priv ;
-
-	if (pre_open_check(dev) == -1)
-		return -1;
-	priv->mesh_open = 1 ;
-	netif_wake_queue(priv->mesh_dev);
-	if (priv->infra_open == 0)
-		return libertas_dev_open(priv->dev) ;
-	return 0;
-}
-
-/**
- *  @brief This function opens the ethX interface
- *
- *  @param dev     A pointer to net_device structure
- *  @return 	   0
- */
-static int libertas_open(struct net_device *dev)
-{
-	wlan_private *priv = (wlan_private *) dev->priv ;
-
-	if(pre_open_check(dev) == -1)
-		return -1;
-	priv->infra_open = 1 ;
-	netif_wake_queue(priv->dev);
-	if (priv->open == 0)
-		return libertas_dev_open(priv->dev) ;
-	return 0;
-}
-
-static int libertas_dev_close(struct net_device *dev)
-{
-	wlan_private *priv = dev->priv;
+	if (dev == priv->mesh_dev) {
+		priv->mesh_open = 1;
+		priv->mesh_connect_status = LBS_CONNECTED;
+		netif_carrier_on(dev);
+	} else {
+		priv->infra_open = 1;
 
-	lbs_deb_enter(LBS_DEB_NET);
+		if (priv->connect_status == LBS_CONNECTED)
+			netif_carrier_on(dev);
+		else
+			netif_carrier_off(dev);
+	}
 
-	netif_carrier_off(priv->dev);
-	priv->open = 0;
+	if (!priv->tx_pending_len)
+		netif_wake_queue(dev);
+ out:
 
-	lbs_deb_leave(LBS_DEB_NET);
-	return 0;
+	spin_unlock_irq(&priv->driver_lock);
+	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+	return ret;
 }
 
 /**
@@ -476,16 +425,23 @@ static int libertas_dev_close(struct net_device *dev)
  *  @param dev     A pointer to net_device structure
  *  @return 	   0
  */
-static int libertas_mesh_close(struct net_device *dev)
+static int lbs_mesh_stop(struct net_device *dev)
 {
-	wlan_private *priv = (wlan_private *) (dev->priv);
+	struct lbs_private *priv = (struct lbs_private *) (dev->priv);
+
+	lbs_deb_enter(LBS_DEB_MESH);
+	spin_lock_irq(&priv->driver_lock);
 
 	priv->mesh_open = 0;
-	netif_stop_queue(priv->mesh_dev);
-	if (priv->infra_open == 0)
-		return libertas_dev_close(dev);
-	else
-		return 0;
+	priv->mesh_connect_status = LBS_DISCONNECTED;
+
+	netif_stop_queue(dev);
+	netif_carrier_off(dev);
+
+	spin_unlock_irq(&priv->driver_lock);
+
+	lbs_deb_leave(LBS_DEB_MESH);
+	return 0;
 }
 
 /**
@@ -494,134 +450,86 @@ static int libertas_mesh_close(struct net_device *dev)
  *  @param dev     A pointer to net_device structure
  *  @return 	   0
  */
-static int libertas_close(struct net_device *dev)
-{
-	wlan_private *priv = (wlan_private *) dev->priv;
-
-	netif_stop_queue(dev);
-	priv->infra_open = 0;
-	if (priv->mesh_open == 0)
-		return libertas_dev_close(dev);
-	else
-		return 0;
-}
-
-
-static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int lbs_eth_stop(struct net_device *dev)
 {
-	int ret = 0;
-	wlan_private *priv = dev->priv;
+	struct lbs_private *priv = (struct lbs_private *) dev->priv;
 
 	lbs_deb_enter(LBS_DEB_NET);
 
-	if (priv->dnld_sent || priv->adapter->TxLockFlag) {
-		priv->stats.tx_dropped++;
-		goto done;
-	}
-
-	netif_stop_queue(priv->dev);
-	if (priv->mesh_dev)
-		netif_stop_queue(priv->mesh_dev);
+	spin_lock_irq(&priv->driver_lock);
+	priv->infra_open = 0;
+	netif_stop_queue(dev);
+	spin_unlock_irq(&priv->driver_lock);
 
-	if (libertas_process_tx(priv, skb) == 0)
-		dev->trans_start = jiffies;
-done:
-	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
-	return ret;
+	lbs_deb_leave(LBS_DEB_NET);
+	return 0;
 }
 
-/**
- * @brief Mark mesh packets and handover them to libertas_hard_start_xmit
- *
- */
-static int libertas_mesh_pre_start_xmit(struct sk_buff *skb,
-		struct net_device *dev)
+static void lbs_tx_timeout(struct net_device *dev)
 {
-	wlan_private *priv = dev->priv;
-	int ret;
-
-	lbs_deb_enter(LBS_DEB_MESH);
-	if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
-		netif_stop_queue(dev);
-		return -EOPNOTSUPP;
-	}
-
-	SET_MESH_FRAME(skb);
+	struct lbs_private *priv = (struct lbs_private *) dev->priv;
 
-	ret = libertas_hard_start_xmit(skb, priv->dev);
-	lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
-	return ret;
-}
+	lbs_deb_enter(LBS_DEB_TX);
 
-/**
- * @brief Mark non-mesh packets and handover them to libertas_hard_start_xmit
- *
- */
-static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	wlan_private *priv = dev->priv;
-	int ret;
+	lbs_pr_err("tx watch dog timeout\n");
 
-	lbs_deb_enter(LBS_DEB_NET);
+	dev->trans_start = jiffies;
 
-	if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
-		netif_stop_queue(dev);
-		return -EOPNOTSUPP;
+	if (priv->currenttxskb) {
+		priv->eventcause = 0x01000000;
+		lbs_send_tx_feedback(priv);
 	}
+	/* XX: Shouldn't we also call into the hw-specific driver
+	   to kick it somehow? */
+	lbs_host_to_card_done(priv);
 
-	UNSET_MESH_FRAME(skb);
+	/* More often than not, this actually happens because the
+	   firmware has crapped itself -- rather than just a very
+	   busy medium. So send a harmless command, and if/when
+	   _that_ times out, we'll kick it in the head. */
+	lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+				     0, 0, NULL);
 
-	ret = libertas_hard_start_xmit(skb, dev);
-	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
-	return ret;
+	lbs_deb_leave(LBS_DEB_TX);
 }
 
-static void libertas_tx_timeout(struct net_device *dev)
+void lbs_host_to_card_done(struct lbs_private *priv)
 {
-	wlan_private *priv = (wlan_private *) dev->priv;
+	unsigned long flags;
 
-	lbs_deb_enter(LBS_DEB_TX);
+	lbs_deb_enter(LBS_DEB_THREAD);
 
-	lbs_pr_err("tx watch dog timeout\n");
+	spin_lock_irqsave(&priv->driver_lock, flags);
 
 	priv->dnld_sent = DNLD_RES_RECEIVED;
-	dev->trans_start = jiffies;
 
-	if (priv->adapter->currenttxskb) {
-		if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
-			/* If we are here, we have not received feedback from
-			   the previous packet.  Assume TX_FAIL and move on. */
-			priv->adapter->eventcause = 0x01000000;
-			libertas_send_tx_feedback(priv);
-		} else
-			wake_up_interruptible(&priv->waitq);
-	} else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
-		netif_wake_queue(priv->dev);
-		if (priv->mesh_dev)
-			netif_wake_queue(priv->mesh_dev);
-	}
+	/* Wake main thread if commands are pending */
+	if (!priv->cur_cmd || priv->tx_pending_len > 0)
+		wake_up_interruptible(&priv->waitq);
 
-	lbs_deb_leave(LBS_DEB_TX);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+	lbs_deb_leave(LBS_DEB_THREAD);
 }
+EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
 
 /**
  *  @brief This function returns the network statistics
  *
- *  @param dev     A pointer to wlan_private structure
+ *  @param dev     A pointer to struct lbs_private structure
  *  @return 	   A pointer to net_device_stats structure
  */
-static struct net_device_stats *libertas_get_stats(struct net_device *dev)
+static struct net_device_stats *lbs_get_stats(struct net_device *dev)
 {
-	wlan_private *priv = (wlan_private *) dev->priv;
+	struct lbs_private *priv = (struct lbs_private *) dev->priv;
 
+	lbs_deb_enter(LBS_DEB_NET);
 	return &priv->stats;
 }
 
-static int libertas_set_mac_address(struct net_device *dev, void *addr)
+static int lbs_set_mac_address(struct net_device *dev, void *addr)
 {
 	int ret = 0;
-	wlan_private *priv = (wlan_private *) dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = (struct lbs_private *) dev->priv;
 	struct sockaddr *phwaddr = addr;
 
 	lbs_deb_enter(LBS_DEB_NET);
@@ -629,15 +537,15 @@ static int libertas_set_mac_address(struct net_device *dev, void *addr)
 	/* In case it was called from the mesh device */
 	dev = priv->dev ;
 
-	memset(adapter->current_addr, 0, ETH_ALEN);
+	memset(priv->current_addr, 0, ETH_ALEN);
 
 	/* dev->dev_addr is 8 bytes */
 	lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN);
 
 	lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN);
-	memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
+	memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN);
 
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS,
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS,
 				    CMD_ACT_SET,
 				    CMD_OPTION_WAITFORRSP, 0, NULL);
 
@@ -647,89 +555,86 @@ static int libertas_set_mac_address(struct net_device *dev, void *addr)
 		goto done;
 	}
 
-	lbs_deb_hex(LBS_DEB_NET, "adapter->macaddr", adapter->current_addr, ETH_ALEN);
-	memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
+	lbs_deb_hex(LBS_DEB_NET, "priv->macaddr", priv->current_addr, ETH_ALEN);
+	memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN);
 	if (priv->mesh_dev)
-		memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+		memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN);
 
 done:
 	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
 	return ret;
 }
 
-static int libertas_copy_multicast_address(wlan_adapter * adapter,
+static int lbs_copy_multicast_address(struct lbs_private *priv,
 				     struct net_device *dev)
 {
 	int i = 0;
 	struct dev_mc_list *mcptr = dev->mc_list;
 
 	for (i = 0; i < dev->mc_count; i++) {
-		memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
+		memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
 		mcptr = mcptr->next;
 	}
-
 	return i;
-
 }
 
-static void libertas_set_multicast_list(struct net_device *dev)
+static void lbs_set_multicast_list(struct net_device *dev)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	int oldpacketfilter;
 	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_NET);
 
-	oldpacketfilter = adapter->currentpacketfilter;
+	oldpacketfilter = priv->currentpacketfilter;
 
 	if (dev->flags & IFF_PROMISC) {
 		lbs_deb_net("enable promiscuous mode\n");
-		adapter->currentpacketfilter |=
+		priv->currentpacketfilter |=
 		    CMD_ACT_MAC_PROMISCUOUS_ENABLE;
-		adapter->currentpacketfilter &=
+		priv->currentpacketfilter &=
 		    ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
 		      CMD_ACT_MAC_MULTICAST_ENABLE);
 	} else {
 		/* Multicast */
-		adapter->currentpacketfilter &=
+		priv->currentpacketfilter &=
 		    ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
 
 		if (dev->flags & IFF_ALLMULTI || dev->mc_count >
 		    MRVDRV_MAX_MULTICAST_LIST_SIZE) {
 			lbs_deb_net( "enabling all multicast\n");
-			adapter->currentpacketfilter |=
+			priv->currentpacketfilter |=
 			    CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
-			adapter->currentpacketfilter &=
+			priv->currentpacketfilter &=
 			    ~CMD_ACT_MAC_MULTICAST_ENABLE;
 		} else {
-			adapter->currentpacketfilter &=
+			priv->currentpacketfilter &=
 			    ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
 
 			if (!dev->mc_count) {
 				lbs_deb_net("no multicast addresses, "
 				       "disabling multicast\n");
-				adapter->currentpacketfilter &=
+				priv->currentpacketfilter &=
 				    ~CMD_ACT_MAC_MULTICAST_ENABLE;
 			} else {
 				int i;
 
-				adapter->currentpacketfilter |=
+				priv->currentpacketfilter |=
 				    CMD_ACT_MAC_MULTICAST_ENABLE;
 
-				adapter->nr_of_multicastmacaddr =
-				    libertas_copy_multicast_address(adapter, dev);
+				priv->nr_of_multicastmacaddr =
+				    lbs_copy_multicast_address(priv, dev);
 
 				lbs_deb_net("multicast addresses: %d\n",
 				       dev->mc_count);
 
 				for (i = 0; i < dev->mc_count; i++) {
-					lbs_deb_net("Multicast address %d:%s\n",
+					lbs_deb_net("Multicast address %d: %s\n",
 					       i, print_mac(mac,
-					       adapter->multicastlist[i]));
+					       priv->multicastlist[i]));
 				}
 				/* send multicast addresses to firmware */
-				libertas_prepare_and_send_command(priv,
+				lbs_prepare_and_send_command(priv,
 						      CMD_MAC_MULTICAST_ADR,
 						      CMD_ACT_SET, 0, 0,
 						      NULL);
@@ -737,26 +642,25 @@ static void libertas_set_multicast_list(struct net_device *dev)
 		}
 	}
 
-	if (adapter->currentpacketfilter != oldpacketfilter) {
-		libertas_set_mac_packet_filter(priv);
+	if (priv->currentpacketfilter != oldpacketfilter) {
+		lbs_set_mac_packet_filter(priv);
 	}
 
 	lbs_deb_leave(LBS_DEB_NET);
 }
 
 /**
- *  @brief This function handles the major jobs in the WLAN driver.
+ *  @brief This function handles the major jobs in the LBS driver.
  *  It handles all events generated by firmware, RX data received
  *  from firmware and TX data sent from kernel.
  *
- *  @param data    A pointer to wlan_thread structure
+ *  @param data    A pointer to lbs_thread structure
  *  @return 	   0
  */
-static int libertas_thread(void *data)
+static int lbs_thread(void *data)
 {
 	struct net_device *dev = data;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	wait_queue_t wait;
 	u8 ireg = 0;
 
@@ -764,215 +668,291 @@ static int libertas_thread(void *data)
 
 	init_waitqueue_entry(&wait, current);
 
-	set_freezable();
 	for (;;) {
-		lbs_deb_thread( "main-thread 111: intcounter=%d "
-		       "currenttxskb=%p dnld_sent=%d\n",
-		       adapter->intcounter,
-		       adapter->currenttxskb, priv->dnld_sent);
+		int shouldsleep;
+
+		lbs_deb_thread( "main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
+				priv->intcounter, priv->currenttxskb, priv->dnld_sent);
 
 		add_wait_queue(&priv->waitq, &wait);
 		set_current_state(TASK_INTERRUPTIBLE);
-		spin_lock_irq(&adapter->driver_lock);
-		if ((adapter->psstate == PS_STATE_SLEEP) ||
-		    (!adapter->intcounter
-		     && (priv->dnld_sent || adapter->cur_cmd ||
-			 list_empty(&adapter->cmdpendingq)))) {
-			lbs_deb_thread(
-			       "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
-			       adapter->connect_status, adapter->intcounter,
-			       adapter->psmode, adapter->psstate);
-			spin_unlock_irq(&adapter->driver_lock);
+		spin_lock_irq(&priv->driver_lock);
+
+		if (kthread_should_stop())
+			shouldsleep = 0;	/* Bye */
+		else if (priv->surpriseremoved)
+			shouldsleep = 1;	/* We need to wait until we're _told_ to die */
+		else if (priv->psstate == PS_STATE_SLEEP)
+			shouldsleep = 1;	/* Sleep mode. Nothing we can do till it wakes */
+		else if (priv->intcounter)
+			shouldsleep = 0;	/* Interrupt pending. Deal with it now */
+		else if (priv->cmd_timed_out)
+			shouldsleep = 0;	/* Command timed out. Recover */
+		else if (!priv->fw_ready)
+			shouldsleep = 1;	/* Firmware not ready. We're waiting for it */
+		else if (priv->dnld_sent)
+			shouldsleep = 1;	/* Something is en route to the device already */
+		else if (priv->tx_pending_len > 0)
+			shouldsleep = 0;	/* We've a packet to send */
+		else if (priv->cur_cmd)
+			shouldsleep = 1;	/* Can't send a command; one already running */
+		else if (!list_empty(&priv->cmdpendingq))
+			shouldsleep = 0;	/* We have a command to send */
+		else
+			shouldsleep = 1;	/* No command */
+
+		if (shouldsleep) {
+			lbs_deb_thread("main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
+				       priv->connect_status, priv->intcounter,
+				       priv->psmode, priv->psstate);
+			spin_unlock_irq(&priv->driver_lock);
 			schedule();
 		} else
-			spin_unlock_irq(&adapter->driver_lock);
+			spin_unlock_irq(&priv->driver_lock);
 
-		lbs_deb_thread(
-		       "main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
-		       "dnld_sent=%d\n", adapter->intcounter,
-		       adapter->currenttxskb, priv->dnld_sent);
+		lbs_deb_thread("main-thread 222 (waking up): intcounter=%d currenttxskb=%p dnld_sent=%d\n",
+			       priv->intcounter, priv->currenttxskb, priv->dnld_sent);
 
 		set_current_state(TASK_RUNNING);
 		remove_wait_queue(&priv->waitq, &wait);
-		try_to_freeze();
-
-		lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p "
-		       "dnld_sent=%d\n",
-		       adapter->intcounter,
-		       adapter->currenttxskb, priv->dnld_sent);
-
-		if (kthread_should_stop()
-		    || adapter->surpriseremoved) {
-			lbs_deb_thread(
-			       "main-thread: break from main thread: surpriseremoved=0x%x\n",
-			       adapter->surpriseremoved);
+
+		lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
+			       priv->intcounter, priv->currenttxskb, priv->dnld_sent);
+
+		if (kthread_should_stop()) {
+			lbs_deb_thread("main-thread: break from main thread\n");
 			break;
 		}
 
+		if (priv->surpriseremoved) {
+			lbs_deb_thread("adapter removed; waiting to die...\n");
+			continue;
+		}
+
+		spin_lock_irq(&priv->driver_lock);
 
-		spin_lock_irq(&adapter->driver_lock);
-		if (adapter->intcounter) {
+		if (priv->intcounter) {
 			u8 int_status;
-			adapter->intcounter = 0;
+
+			priv->intcounter = 0;
 			int_status = priv->hw_get_int_status(priv, &ireg);
 
 			if (int_status) {
-				lbs_deb_thread(
-				       "main-thread: reading HOST_INT_STATUS_REG failed\n");
-				spin_unlock_irq(&adapter->driver_lock);
+				lbs_deb_thread("main-thread: reading HOST_INT_STATUS_REG failed\n");
+				spin_unlock_irq(&priv->driver_lock);
 				continue;
 			}
-			adapter->hisregcpy |= ireg;
+			priv->hisregcpy |= ireg;
 		}
 
-		lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p "
-		       "dnld_sent=%d\n",
-		       adapter->intcounter,
-		       adapter->currenttxskb, priv->dnld_sent);
+		lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p dnld_sent=%d\n",
+			       priv->intcounter, priv->currenttxskb, priv->dnld_sent);
 
 		/* command response? */
-		if (adapter->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
+		if (priv->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
 			lbs_deb_thread("main-thread: cmd response ready\n");
 
-			adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
-			spin_unlock_irq(&adapter->driver_lock);
-			libertas_process_rx_command(priv);
-			spin_lock_irq(&adapter->driver_lock);
+			priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
+			spin_unlock_irq(&priv->driver_lock);
+			lbs_process_rx_command(priv);
+			spin_lock_irq(&priv->driver_lock);
 		}
 
+		if (priv->cmd_timed_out && priv->cur_cmd) {
+			struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
+
+			if (++priv->nr_retries > 10) {
+				lbs_pr_info("Excessive timeouts submitting command %x\n",
+					    le16_to_cpu(cmdnode->cmdbuf->command));
+				lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
+				priv->nr_retries = 0;
+			} else {
+				priv->cur_cmd = NULL;
+				lbs_pr_info("requeueing command %x due to timeout (#%d)\n",
+					    le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries);
+
+				/* Stick it back at the _top_ of the pending queue
+				   for immediate resubmission */
+				list_add(&cmdnode->list, &priv->cmdpendingq);
+			}
+		}
+		priv->cmd_timed_out = 0;
+
 		/* Any Card Event */
-		if (adapter->hisregcpy & MRVDRV_CARDEVENT) {
+		if (priv->hisregcpy & MRVDRV_CARDEVENT) {
 			lbs_deb_thread("main-thread: Card Event Activity\n");
 
-			adapter->hisregcpy &= ~MRVDRV_CARDEVENT;
+			priv->hisregcpy &= ~MRVDRV_CARDEVENT;
 
 			if (priv->hw_read_event_cause(priv)) {
-				lbs_pr_alert(
-				       "main-thread: hw_read_event_cause failed\n");
-				spin_unlock_irq(&adapter->driver_lock);
+				lbs_pr_alert("main-thread: hw_read_event_cause failed\n");
+				spin_unlock_irq(&priv->driver_lock);
 				continue;
 			}
-			spin_unlock_irq(&adapter->driver_lock);
-			libertas_process_event(priv);
+			spin_unlock_irq(&priv->driver_lock);
+			lbs_process_event(priv);
 		} else
-			spin_unlock_irq(&adapter->driver_lock);
+			spin_unlock_irq(&priv->driver_lock);
+
+		if (!priv->fw_ready)
+			continue;
 
 		/* Check if we need to confirm Sleep Request received previously */
-		if (adapter->psstate == PS_STATE_PRE_SLEEP) {
-			if (!priv->dnld_sent && !adapter->cur_cmd) {
-				if (adapter->connect_status ==
-				    LIBERTAS_CONNECTED) {
-					lbs_deb_thread(
-					       "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
-					       "dnld_sent=%d cur_cmd=%p, confirm now\n",
-					       adapter->intcounter,
-					       adapter->currenttxskb,
-					       priv->dnld_sent,
-					       adapter->cur_cmd);
-
-					libertas_ps_confirm_sleep(priv,
-						       (u16) adapter->psmode);
-				} else {
-					/* workaround for firmware sending
-					 * deauth/linkloss event immediately
-					 * after sleep request, remove this
-					 * after firmware fixes it
-					 */
-					adapter->psstate = PS_STATE_AWAKE;
-					lbs_pr_alert(
-					       "main-thread: ignore PS_SleepConfirm in non-connected state\n");
-				}
+		if (priv->psstate == PS_STATE_PRE_SLEEP &&
+		    !priv->dnld_sent && !priv->cur_cmd) {
+			if (priv->connect_status == LBS_CONNECTED) {
+				lbs_deb_thread("main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p dnld_sent=%d cur_cmd=%p, confirm now\n",
+					       priv->intcounter, priv->currenttxskb, priv->dnld_sent, priv->cur_cmd);
+
+				lbs_ps_confirm_sleep(priv, (u16) priv->psmode);
+			} else {
+				/* workaround for firmware sending
+				 * deauth/linkloss event immediately
+				 * after sleep request; remove this
+				 * after firmware fixes it
+				 */
+				priv->psstate = PS_STATE_AWAKE;
+				lbs_pr_alert("main-thread: ignore PS_SleepConfirm in non-connected state\n");
 			}
 		}
 
 		/* The PS state is changed during processing of Sleep Request
 		 * event above
 		 */
-		if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
-		    (priv->adapter->psstate == PS_STATE_PRE_SLEEP))
+		if ((priv->psstate == PS_STATE_SLEEP) ||
+		    (priv->psstate == PS_STATE_PRE_SLEEP))
 			continue;
 
 		/* Execute the next command */
-		if (!priv->dnld_sent && !priv->adapter->cur_cmd)
-			libertas_execute_next_command(priv);
+		if (!priv->dnld_sent && !priv->cur_cmd)
+			lbs_execute_next_command(priv);
 
 		/* Wake-up command waiters which can't sleep in
-		 * libertas_prepare_and_send_command
+		 * lbs_prepare_and_send_command
 		 */
-		if (!adapter->nr_cmd_pending)
-			wake_up_all(&adapter->cmd_pending);
-
-		libertas_tx_runqueue(priv);
+		if (!list_empty(&priv->cmdpendingq))
+			wake_up_all(&priv->cmd_pending);
+
+		spin_lock_irq(&priv->driver_lock);
+		if (!priv->dnld_sent && priv->tx_pending_len > 0) {
+			int ret = priv->hw_host_to_card(priv, MVMS_DAT,
+							priv->tx_pending_buf,
+							priv->tx_pending_len);
+			if (ret) {
+				lbs_deb_tx("host_to_card failed %d\n", ret);
+				priv->dnld_sent = DNLD_RES_RECEIVED;
+			}
+			priv->tx_pending_len = 0;
+			if (!priv->currenttxskb) {
+				/* We can wake the queues immediately if we aren't
+				   waiting for TX feedback */
+				if (priv->connect_status == LBS_CONNECTED)
+					netif_wake_queue(priv->dev);
+				if (priv->mesh_dev &&
+				    priv->mesh_connect_status == LBS_CONNECTED)
+					netif_wake_queue(priv->mesh_dev);
+			}
+		}
+		spin_unlock_irq(&priv->driver_lock);
 	}
 
-	del_timer(&adapter->command_timer);
-	adapter->nr_cmd_pending = 0;
-	wake_up_all(&adapter->cmd_pending);
+	del_timer(&priv->command_timer);
+	wake_up_all(&priv->cmd_pending);
 
 	lbs_deb_leave(LBS_DEB_THREAD);
 	return 0;
 }
 
+static int lbs_suspend_callback(struct lbs_private *priv, unsigned long dummy,
+				struct cmd_header *cmd)
+{
+	lbs_deb_enter(LBS_DEB_FW);
+
+	netif_device_detach(priv->dev);
+	if (priv->mesh_dev)
+		netif_device_detach(priv->mesh_dev);
+
+	priv->fw_ready = 0;
+	lbs_deb_leave(LBS_DEB_FW);
+	return 0;
+}
+
+int lbs_suspend(struct lbs_private *priv)
+{
+	struct cmd_header cmd;
+	int ret;
+
+	lbs_deb_enter(LBS_DEB_FW);
+
+	if (priv->wol_criteria == 0xffffffff) {
+		lbs_pr_info("Suspend attempt without configuring wake params!\n");
+		return -EINVAL;
+	}
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
+			sizeof(cmd), lbs_suspend_callback, 0);
+	if (ret)
+		lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
+
+	lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(lbs_suspend);
+
+int lbs_resume(struct lbs_private *priv)
+{
+	lbs_deb_enter(LBS_DEB_FW);
+
+	priv->fw_ready = 1;
+
+	/* Firmware doesn't seem to give us RX packets any more
+	   until we send it some command. Might as well update */
+	lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+				     0, 0, NULL);
+
+	netif_device_attach(priv->dev);
+	if (priv->mesh_dev)
+		netif_device_attach(priv->mesh_dev);
+
+	lbs_deb_leave(LBS_DEB_FW);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(lbs_resume);
+
 /**
  *  @brief This function downloads firmware image, gets
  *  HW spec from firmware and set basic parameters to
  *  firmware.
  *
- *  @param priv    A pointer to wlan_private structure
+ *  @param priv    A pointer to struct lbs_private structure
  *  @return 	   0 or -1
  */
-static int wlan_setup_firmware(wlan_private * priv)
+static int lbs_setup_firmware(struct lbs_private *priv)
 {
 	int ret = -1;
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ds_mesh_access mesh_access;
 
 	lbs_deb_enter(LBS_DEB_FW);
 
 	/*
 	 * Read MAC address from HW
 	 */
-	memset(adapter->current_addr, 0xff, ETH_ALEN);
-
-	ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC,
-				    0, CMD_OPTION_WAITFORRSP, 0, NULL);
-
+	memset(priv->current_addr, 0xff, ETH_ALEN);
+	ret = lbs_update_hw_spec(priv);
 	if (ret) {
 		ret = -1;
 		goto done;
 	}
 
-	libertas_set_mac_packet_filter(priv);
-
-	/* Get the supported Data rates */
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
-				    CMD_ACT_GET_TX_RATE,
-				    CMD_OPTION_WAITFORRSP, 0, NULL);
+	lbs_set_mac_packet_filter(priv);
 
-	if (ret) {
+	ret = lbs_get_data_rate(priv);
+	if (ret < 0) {
 		ret = -1;
 		goto done;
 	}
 
-	/* Disable mesh autostart */
-	if (priv->mesh_dev) {
-		memset(&mesh_access, 0, sizeof(mesh_access));
-		mesh_access.data[0] = cpu_to_le32(0);
-		ret = libertas_prepare_and_send_command(priv,
-				CMD_MESH_ACCESS,
-				CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
-				CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
-		if (ret) {
-			ret = -1;
-			goto done;
-		}
-		priv->mesh_autostart_enabled = 0;
-	}
-
-       /* Set the boot2 version in firmware */
-       ret = libertas_prepare_and_send_command(priv, CMD_SET_BOOT2_VER,
-                                   0, CMD_OPTION_WAITFORRSP, 0, NULL);
-
 	ret = 0;
 done:
 	lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
@@ -985,164 +965,130 @@ done:
  */
 static void command_timer_fn(unsigned long data)
 {
-	wlan_private *priv = (wlan_private *)data;
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *ptempnode;
-	struct cmd_ds_command *cmd;
+	struct lbs_private *priv = (struct lbs_private *)data;
 	unsigned long flags;
 
-	ptempnode = adapter->cur_cmd;
-	if (ptempnode == NULL) {
-		lbs_deb_fw("ptempnode empty\n");
-		return;
-	}
+	lbs_deb_enter(LBS_DEB_CMD);
+	spin_lock_irqsave(&priv->driver_lock, flags);
 
-	cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
-	if (!cmd) {
-		lbs_deb_fw("cmd is NULL\n");
-		return;
+	if (!priv->cur_cmd) {
+		lbs_pr_info("Command timer expired; no pending command\n");
+		goto out;
 	}
 
-	lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command);
-
-	if (!adapter->fw_ready)
-		return;
-
-	spin_lock_irqsave(&adapter->driver_lock, flags);
-	adapter->cur_cmd = NULL;
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
-
-	lbs_deb_fw("re-sending same command because of timeout\n");
-	libertas_queue_cmd(adapter, ptempnode, 0);
+	lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command));
 
+	priv->cmd_timed_out = 1;
 	wake_up_interruptible(&priv->waitq);
-
-	return;
+out:
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+	lbs_deb_leave(LBS_DEB_CMD);
 }
 
-static int libertas_init_adapter(wlan_private * priv)
+static int lbs_init_adapter(struct lbs_private *priv)
 {
-	wlan_adapter *adapter = priv->adapter;
 	size_t bufsize;
 	int i, ret = 0;
 
+	lbs_deb_enter(LBS_DEB_MAIN);
+
 	/* Allocate buffer to store the BSSID list */
 	bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
-	adapter->networks = kzalloc(bufsize, GFP_KERNEL);
-	if (!adapter->networks) {
+	priv->networks = kzalloc(bufsize, GFP_KERNEL);
+	if (!priv->networks) {
 		lbs_pr_err("Out of memory allocating beacons\n");
 		ret = -1;
 		goto out;
 	}
 
 	/* Initialize scan result lists */
-	INIT_LIST_HEAD(&adapter->network_free_list);
-	INIT_LIST_HEAD(&adapter->network_list);
+	INIT_LIST_HEAD(&priv->network_free_list);
+	INIT_LIST_HEAD(&priv->network_list);
 	for (i = 0; i < MAX_NETWORK_COUNT; i++) {
-		list_add_tail(&adapter->networks[i].list,
-			      &adapter->network_free_list);
+		list_add_tail(&priv->networks[i].list,
+			      &priv->network_free_list);
 	}
 
-	adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
-	adapter->libertas_ps_confirm_sleep.command =
+	priv->lbs_ps_confirm_sleep.seqnum = cpu_to_le16(++priv->seqnum);
+	priv->lbs_ps_confirm_sleep.command =
 	    cpu_to_le16(CMD_802_11_PS_MODE);
-	adapter->libertas_ps_confirm_sleep.size =
+	priv->lbs_ps_confirm_sleep.size =
 	    cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
-	adapter->libertas_ps_confirm_sleep.action =
+	priv->lbs_ps_confirm_sleep.action =
 	    cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
 
-	memset(adapter->current_addr, 0xff, ETH_ALEN);
-
-	adapter->connect_status = LIBERTAS_DISCONNECTED;
-	adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-	adapter->mode = IW_MODE_INFRA;
-	adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
-	adapter->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
-	adapter->radioon = RADIO_ON;
-	adapter->auto_rate = 1;
-	adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
-	adapter->psmode = WLAN802_11POWERMODECAM;
-	adapter->psstate = PS_STATE_FULL_POWER;
+	memset(priv->current_addr, 0xff, ETH_ALEN);
 
-	mutex_init(&adapter->lock);
+	priv->connect_status = LBS_DISCONNECTED;
+	priv->mesh_connect_status = LBS_DISCONNECTED;
+	priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
+	priv->mode = IW_MODE_INFRA;
+	priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
+	priv->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
+	priv->radioon = RADIO_ON;
+	priv->auto_rate = 1;
+	priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
+	priv->psmode = LBS802_11POWERMODECAM;
+	priv->psstate = PS_STATE_FULL_POWER;
 
-	memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
-	adapter->tx_queue_idx = 0;
-	spin_lock_init(&adapter->txqueue_lock);
+	mutex_init(&priv->lock);
 
-	setup_timer(&adapter->command_timer, command_timer_fn,
-	            (unsigned long)priv);
+	setup_timer(&priv->command_timer, command_timer_fn,
+		(unsigned long)priv);
 
-	INIT_LIST_HEAD(&adapter->cmdfreeq);
-	INIT_LIST_HEAD(&adapter->cmdpendingq);
+	INIT_LIST_HEAD(&priv->cmdfreeq);
+	INIT_LIST_HEAD(&priv->cmdpendingq);
 
-	spin_lock_init(&adapter->driver_lock);
-	init_waitqueue_head(&adapter->cmd_pending);
-	adapter->nr_cmd_pending = 0;
+	spin_lock_init(&priv->driver_lock);
+	init_waitqueue_head(&priv->cmd_pending);
 
 	/* Allocate the command buffers */
-	if (libertas_allocate_cmd_buffer(priv)) {
+	if (lbs_allocate_cmd_buffer(priv)) {
 		lbs_pr_err("Out of memory allocating command buffers\n");
 		ret = -1;
 	}
 
 out:
+	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+
 	return ret;
 }
 
-static void libertas_free_adapter(wlan_private * priv)
+static void lbs_free_adapter(struct lbs_private *priv)
 {
-	wlan_adapter *adapter = priv->adapter;
-
-	if (!adapter) {
-		lbs_deb_fw("why double free adapter?\n");
-		return;
-	}
-
-	lbs_deb_fw("free command buffer\n");
-	libertas_free_cmd_buffer(priv);
-
-	lbs_deb_fw("free command_timer\n");
-	del_timer(&adapter->command_timer);
+	lbs_deb_enter(LBS_DEB_MAIN);
 
-	lbs_deb_fw("free scan results table\n");
-	kfree(adapter->networks);
-	adapter->networks = NULL;
+	lbs_free_cmd_buffer(priv);
+	del_timer(&priv->command_timer);
+	kfree(priv->networks);
+	priv->networks = NULL;
 
-	/* Free the adapter object itself */
-	lbs_deb_fw("free adapter\n");
-	kfree(adapter);
-	priv->adapter = NULL;
+	lbs_deb_leave(LBS_DEB_MAIN);
 }
 
 /**
  * @brief This function adds the card. it will probe the
- * card, allocate the wlan_priv and initialize the device.
+ * card, allocate the lbs_priv and initialize the device.
  *
  *  @param card    A pointer to card
- *  @return 	   A pointer to wlan_private structure
+ *  @return 	   A pointer to struct lbs_private structure
  */
-wlan_private *libertas_add_card(void *card, struct device *dmdev)
+struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
 {
 	struct net_device *dev = NULL;
-	wlan_private *priv = NULL;
+	struct lbs_private *priv = NULL;
 
-	lbs_deb_enter(LBS_DEB_NET);
+	lbs_deb_enter(LBS_DEB_MAIN);
 
 	/* Allocate an Ethernet device and register it */
-	if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
+	dev = alloc_etherdev(sizeof(struct lbs_private));
+	if (!dev) {
 		lbs_pr_err("init ethX device failed\n");
 		goto done;
 	}
 	priv = dev->priv;
 
-	/* allocate buffer for wlan_adapter */
-	if (!(priv->adapter = kzalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
-		lbs_pr_err("allocate buffer for wlan_adapter failed\n");
-		goto err_kzalloc;
-	}
-
-	if (libertas_init_adapter(priv)) {
+	if (lbs_init_adapter(priv)) {
 		lbs_pr_err("failed to initialize adapter structure.\n");
 		goto err_init_adapter;
 	}
@@ -1151,81 +1097,78 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
 	priv->card = card;
 	priv->mesh_open = 0;
 	priv->infra_open = 0;
-	priv->hotplug_device = dmdev;
 
 	/* Setup the OS Interface to our functions */
-	dev->open = libertas_open;
-	dev->hard_start_xmit = libertas_pre_start_xmit;
-	dev->stop = libertas_close;
-	dev->set_mac_address = libertas_set_mac_address;
-	dev->tx_timeout = libertas_tx_timeout;
-	dev->get_stats = libertas_get_stats;
+	dev->open = lbs_dev_open;
+	dev->hard_start_xmit = lbs_hard_start_xmit;
+	dev->stop = lbs_eth_stop;
+	dev->set_mac_address = lbs_set_mac_address;
+	dev->tx_timeout = lbs_tx_timeout;
+	dev->get_stats = lbs_get_stats;
 	dev->watchdog_timeo = 5 * HZ;
-	dev->ethtool_ops = &libertas_ethtool_ops;
+	dev->ethtool_ops = &lbs_ethtool_ops;
 #ifdef	WIRELESS_EXT
-	dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
+	dev->wireless_handlers = (struct iw_handler_def *)&lbs_handler_def;
 #endif
 	dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
-	dev->set_multicast_list = libertas_set_multicast_list;
+	dev->set_multicast_list = lbs_set_multicast_list;
 
 	SET_NETDEV_DEV(dev, dmdev);
 
 	priv->rtap_net_dev = NULL;
-	if (device_create_file(dmdev, &dev_attr_libertas_rtap))
-		goto err_init_adapter;
 
 	lbs_deb_thread("Starting main thread...\n");
 	init_waitqueue_head(&priv->waitq);
-	priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main");
+	priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
 	if (IS_ERR(priv->main_thread)) {
 		lbs_deb_thread("Error creating main thread.\n");
-		goto err_kthread_run;
+		goto err_init_adapter;
 	}
 
-	priv->work_thread = create_singlethread_workqueue("libertas_worker");
-	INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
-	INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker);
-	INIT_WORK(&priv->sync_channel, libertas_sync_channel);
+	priv->work_thread = create_singlethread_workqueue("lbs_worker");
+	INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker);
+	INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
+	INIT_WORK(&priv->sync_channel, lbs_sync_channel);
 
-	goto done;
+	sprintf(priv->mesh_ssid, "mesh");
+	priv->mesh_ssid_len = 4;
 
-err_kthread_run:
-	device_remove_file(dmdev, &dev_attr_libertas_rtap);
+	priv->wol_criteria = 0xffffffff;
+	priv->wol_gpio = 0xff;
 
-err_init_adapter:
-	libertas_free_adapter(priv);
+	goto done;
 
-err_kzalloc:
+err_init_adapter:
+	lbs_free_adapter(priv);
 	free_netdev(dev);
 	priv = NULL;
 
 done:
-	lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv);
+	lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv);
 	return priv;
 }
-EXPORT_SYMBOL_GPL(libertas_add_card);
+EXPORT_SYMBOL_GPL(lbs_add_card);
 
 
-int libertas_remove_card(wlan_private *priv)
+int lbs_remove_card(struct lbs_private *priv)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct net_device *dev = priv->dev;
 	union iwreq_data wrqu;
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
-	libertas_remove_rtap(priv);
+	lbs_remove_mesh(priv);
+	lbs_remove_rtap(priv);
 
 	dev = priv->dev;
-	device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap);
 
 	cancel_delayed_work(&priv->scan_work);
 	cancel_delayed_work(&priv->assoc_work);
 	destroy_workqueue(priv->work_thread);
 
-	if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
-		adapter->psmode = WLAN802_11POWERMODECAM;
-		libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
+	if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
+		priv->psmode = LBS802_11POWERMODECAM;
+		lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
 	}
 
 	memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
@@ -1233,10 +1176,10 @@ int libertas_remove_card(wlan_private *priv)
 	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
 
 	/* Stop the thread servicing the interrupts */
-	adapter->surpriseremoved = 1;
+	priv->surpriseremoved = 1;
 	kthread_stop(priv->main_thread);
 
-	libertas_free_adapter(priv);
+	lbs_free_adapter(priv);
 
 	priv->dev = NULL;
 	free_netdev(dev);
@@ -1244,10 +1187,10 @@ int libertas_remove_card(wlan_private *priv)
 	lbs_deb_leave(LBS_DEB_MAIN);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(libertas_remove_card);
+EXPORT_SYMBOL_GPL(lbs_remove_card);
 
 
-int libertas_start_card(wlan_private *priv)
+int lbs_start_card(struct lbs_private *priv)
 {
 	struct net_device *dev = priv->dev;
 	int ret = -1;
@@ -1255,19 +1198,52 @@ int libertas_start_card(wlan_private *priv)
 	lbs_deb_enter(LBS_DEB_MAIN);
 
 	/* poke the firmware */
-	ret = wlan_setup_firmware(priv);
+	ret = lbs_setup_firmware(priv);
 	if (ret)
 		goto done;
 
 	/* init 802.11d */
-	libertas_init_11d(priv);
+	lbs_init_11d(priv);
 
 	if (register_netdev(dev)) {
 		lbs_pr_err("cannot register ethX device\n");
 		goto done;
 	}
+	if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
+		lbs_pr_err("cannot register lbs_rtap attribute\n");
+
+	lbs_update_channel(priv);
+
+	/* 5.0.16p0 is known to NOT support any mesh */
+	if (priv->fwrelease > 0x05001000) {
+		/* Enable mesh, if supported, and work out which TLV it uses.
+		   0x100 + 291 is an unofficial value used in 5.110.20.pXX
+		   0x100 + 37 is the official value used in 5.110.21.pXX
+		   but we check them in that order because 20.pXX doesn't
+		   give an error -- it just silently fails. */
+
+		/* 5.110.20.pXX firmware will fail the command if the channel
+		   doesn't match the existing channel. But only if the TLV
+		   is correct. If the channel is wrong, _BOTH_ versions will
+		   give an error to 0x100+291, and allow 0x100+37 to succeed.
+		   It's just that 5.110.20.pXX will not have done anything
+		   useful */
+
+		priv->mesh_tlv = 0x100 + 291;
+		if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) {
+			priv->mesh_tlv = 0x100 + 37;
+			if (lbs_mesh_config(priv, 1, priv->curbssparams.channel))
+				priv->mesh_tlv = 0;
+		}
+		if (priv->mesh_tlv) {
+			lbs_add_mesh(priv);
 
-	libertas_debugfs_init_one(priv, dev);
+			if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
+				lbs_pr_err("cannot register lbs_mesh attribute\n");
+		}
+	}
+
+	lbs_debugfs_init_one(priv, dev);
 
 	lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
 
@@ -1277,10 +1253,10 @@ done:
 	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(libertas_start_card);
+EXPORT_SYMBOL_GPL(lbs_start_card);
 
 
-int libertas_stop_card(wlan_private *priv)
+int lbs_stop_card(struct lbs_private *priv)
 {
 	struct net_device *dev = priv->dev;
 	int ret = -1;
@@ -1292,31 +1268,35 @@ int libertas_stop_card(wlan_private *priv)
 	netif_stop_queue(priv->dev);
 	netif_carrier_off(priv->dev);
 
-	libertas_debugfs_remove_one(priv);
+	lbs_debugfs_remove_one(priv);
+	device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
+	if (priv->mesh_tlv)
+		device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
 
 	/* Flush pending command nodes */
-	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
-	list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
+		cmdnode->result = -ENOENT;
 		cmdnode->cmdwaitqwoken = 1;
 		wake_up_interruptible(&cmdnode->cmdwait_q);
 	}
-	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
 
 	unregister_netdev(dev);
 
 	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(libertas_stop_card);
+EXPORT_SYMBOL_GPL(lbs_stop_card);
 
 
 /**
  * @brief This function adds mshX interface
  *
- *  @param priv    A pointer to the wlan_private structure
+ *  @param priv    A pointer to the struct lbs_private structure
  *  @return 	   0 if successful, -X otherwise
  */
-int libertas_add_mesh(wlan_private *priv, struct device *dev)
+static int lbs_add_mesh(struct lbs_private *priv)
 {
 	struct net_device *mesh_dev = NULL;
 	int ret = 0;
@@ -1332,16 +1312,16 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev)
 	mesh_dev->priv = priv;
 	priv->mesh_dev = mesh_dev;
 
-	mesh_dev->open = libertas_mesh_open;
-	mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit;
-	mesh_dev->stop = libertas_mesh_close;
-	mesh_dev->get_stats = libertas_get_stats;
-	mesh_dev->set_mac_address = libertas_set_mac_address;
-	mesh_dev->ethtool_ops = &libertas_ethtool_ops;
+	mesh_dev->open = lbs_dev_open;
+	mesh_dev->hard_start_xmit = lbs_hard_start_xmit;
+	mesh_dev->stop = lbs_mesh_stop;
+	mesh_dev->get_stats = lbs_get_stats;
+	mesh_dev->set_mac_address = lbs_set_mac_address;
+	mesh_dev->ethtool_ops = &lbs_ethtool_ops;
 	memcpy(mesh_dev->dev_addr, priv->dev->dev_addr,
 			sizeof(priv->dev->dev_addr));
 
-	SET_NETDEV_DEV(priv->mesh_dev, dev);
+	SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
 
 #ifdef	WIRELESS_EXT
 	mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def;
@@ -1353,7 +1333,7 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev)
 		goto err_free;
 	}
 
-	ret = sysfs_create_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
+	ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
 	if (ret)
 		goto err_unregister;
 
@@ -1371,33 +1351,28 @@ done:
 	lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(libertas_add_mesh);
+EXPORT_SYMBOL_GPL(lbs_add_mesh);
 
 
-void libertas_remove_mesh(wlan_private *priv)
+static void lbs_remove_mesh(struct lbs_private *priv)
 {
 	struct net_device *mesh_dev;
 
-	lbs_deb_enter(LBS_DEB_MAIN);
-
-	if (!priv)
-		goto out;
 
 	mesh_dev = priv->mesh_dev;
+	if (!mesh_dev)
+		return;
 
+	lbs_deb_enter(LBS_DEB_MESH);
 	netif_stop_queue(mesh_dev);
 	netif_carrier_off(priv->mesh_dev);
-
-	sysfs_remove_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
+	sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
 	unregister_netdev(mesh_dev);
-
-	priv->mesh_dev = NULL ;
+	priv->mesh_dev = NULL;
 	free_netdev(mesh_dev);
-
-out:
-	lbs_deb_leave(LBS_DEB_MAIN);
+	lbs_deb_leave(LBS_DEB_MESH);
 }
-EXPORT_SYMBOL_GPL(libertas_remove_mesh);
+EXPORT_SYMBOL_GPL(lbs_remove_mesh);
 
 /**
  *  @brief This function finds the CFP in
@@ -1408,7 +1383,7 @@ EXPORT_SYMBOL_GPL(libertas_remove_mesh);
  *  @param cfp_no  A pointer to CFP number
  *  @return 	   A pointer to CFP
  */
-struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
+struct chan_freq_power *lbs_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
 {
 	int i, end;
 
@@ -1430,9 +1405,8 @@ struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *c
 	return NULL;
 }
 
-int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band)
+int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 	int i = 0;
 
@@ -1441,24 +1415,22 @@ int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band)
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
-	memset(adapter->region_channel, 0, sizeof(adapter->region_channel));
+	memset(priv->region_channel, 0, sizeof(priv->region_channel));
 
-	{
-		cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
-		if (cfp != NULL) {
-			adapter->region_channel[i].nrcfp = cfp_no;
-			adapter->region_channel[i].CFP = cfp;
-		} else {
-			lbs_deb_main("wrong region code %#x in band B/G\n",
-			       region);
-			ret = -1;
-			goto out;
-		}
-		adapter->region_channel[i].valid = 1;
-		adapter->region_channel[i].region = region;
-		adapter->region_channel[i].band = band;
-		i++;
+	cfp = lbs_get_region_cfp_table(region, band, &cfp_no);
+	if (cfp != NULL) {
+		priv->region_channel[i].nrcfp = cfp_no;
+		priv->region_channel[i].CFP = cfp;
+	} else {
+		lbs_deb_main("wrong region code %#x in band B/G\n",
+		       region);
+		ret = -1;
+		goto out;
 	}
+	priv->region_channel[i].valid = 1;
+	priv->region_channel[i].region = region;
+	priv->region_channel[i].band = band;
+	i++;
 out:
 	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
 	return ret;
@@ -1472,58 +1444,46 @@ out:
  *  @param dev     A pointer to net_device structure
  *  @return 	   n/a
  */
-void libertas_interrupt(struct net_device *dev)
+void lbs_interrupt(struct lbs_private *priv)
 {
-	wlan_private *priv = dev->priv;
-
 	lbs_deb_enter(LBS_DEB_THREAD);
 
-	lbs_deb_thread("libertas_interrupt: intcounter=%d\n",
-	       priv->adapter->intcounter);
-
-	priv->adapter->intcounter++;
-
-	if (priv->adapter->psstate == PS_STATE_SLEEP) {
-		priv->adapter->psstate = PS_STATE_AWAKE;
-		netif_wake_queue(dev);
-		if (priv->mesh_dev)
-			netif_wake_queue(priv->mesh_dev);
-	}
-
+	lbs_deb_thread("lbs_interrupt: intcounter=%d\n", priv->intcounter);
+	priv->intcounter++;
+	if (priv->psstate == PS_STATE_SLEEP)
+		priv->psstate = PS_STATE_AWAKE;
 	wake_up_interruptible(&priv->waitq);
 
 	lbs_deb_leave(LBS_DEB_THREAD);
 }
-EXPORT_SYMBOL_GPL(libertas_interrupt);
+EXPORT_SYMBOL_GPL(lbs_interrupt);
 
-int libertas_reset_device(wlan_private *priv)
+int lbs_reset_device(struct lbs_private *priv)
 {
 	int ret;
 
 	lbs_deb_enter(LBS_DEB_MAIN);
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET,
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_RESET,
 				    CMD_ACT_HALT, 0, 0, NULL);
 	msleep_interruptible(10);
 
 	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(libertas_reset_device);
+EXPORT_SYMBOL_GPL(lbs_reset_device);
 
-static int libertas_init_module(void)
+static int __init lbs_init_module(void)
 {
 	lbs_deb_enter(LBS_DEB_MAIN);
-	libertas_debugfs_init();
+	lbs_debugfs_init();
 	lbs_deb_leave(LBS_DEB_MAIN);
 	return 0;
 }
 
-static void libertas_exit_module(void)
+static void __exit lbs_exit_module(void)
 {
 	lbs_deb_enter(LBS_DEB_MAIN);
-
-	libertas_debugfs_remove();
-
+	lbs_debugfs_remove();
 	lbs_deb_leave(LBS_DEB_MAIN);
 }
 
@@ -1531,79 +1491,89 @@ static void libertas_exit_module(void)
  * rtap interface support fuctions
  */
 
-static int libertas_rtap_open(struct net_device *dev)
+static int lbs_rtap_open(struct net_device *dev)
 {
-        netif_carrier_off(dev);
-        netif_stop_queue(dev);
-        return 0;
+	/* Yes, _stop_ the queue. Because we don't support injection */
+	lbs_deb_enter(LBS_DEB_MAIN);
+	netif_carrier_off(dev);
+	netif_stop_queue(dev);
+	lbs_deb_leave(LBS_DEB_LEAVE);
+	return 0;
 }
 
-static int libertas_rtap_stop(struct net_device *dev)
+static int lbs_rtap_stop(struct net_device *dev)
 {
-        return 0;
+	lbs_deb_enter(LBS_DEB_MAIN);
+	lbs_deb_leave(LBS_DEB_MAIN);
+	return 0;
 }
 
-static int libertas_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-        netif_stop_queue(dev);
-        return -EOPNOTSUPP;
+	netif_stop_queue(dev);
+	return NETDEV_TX_BUSY;
 }
 
-static struct net_device_stats *libertas_rtap_get_stats(struct net_device *dev)
+static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev)
 {
-	wlan_private *priv = dev->priv;
-	return &priv->ieee->stats;
+	struct lbs_private *priv = dev->priv;
+	lbs_deb_enter(LBS_DEB_NET);
+	return &priv->stats;
 }
 
 
-void libertas_remove_rtap(wlan_private *priv)
+static void lbs_remove_rtap(struct lbs_private *priv)
 {
+	lbs_deb_enter(LBS_DEB_MAIN);
 	if (priv->rtap_net_dev == NULL)
 		return;
 	unregister_netdev(priv->rtap_net_dev);
-	free_ieee80211(priv->rtap_net_dev);
+	free_netdev(priv->rtap_net_dev);
 	priv->rtap_net_dev = NULL;
+	lbs_deb_leave(LBS_DEB_MAIN);
 }
 
-int libertas_add_rtap(wlan_private *priv)
+static int lbs_add_rtap(struct lbs_private *priv)
 {
-	int rc = 0;
-
-	if (priv->rtap_net_dev)
-		return -EPERM;
-
-	priv->rtap_net_dev = alloc_ieee80211(0);
-	if (priv->rtap_net_dev == NULL)
-		return -ENOMEM;
-
-
-	priv->ieee = netdev_priv(priv->rtap_net_dev);
+	int ret = 0;
+	struct net_device *rtap_dev;
 
-	strcpy(priv->rtap_net_dev->name, "rtap%d");
+	lbs_deb_enter(LBS_DEB_MAIN);
+	if (priv->rtap_net_dev) {
+		ret = -EPERM;
+		goto out;
+	}
 
-	priv->rtap_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-	priv->rtap_net_dev->open = libertas_rtap_open;
-	priv->rtap_net_dev->stop = libertas_rtap_stop;
-	priv->rtap_net_dev->get_stats = libertas_rtap_get_stats;
-	priv->rtap_net_dev->hard_start_xmit = libertas_rtap_hard_start_xmit;
-	priv->rtap_net_dev->set_multicast_list = libertas_set_multicast_list;
-	priv->rtap_net_dev->priv = priv;
+	rtap_dev = alloc_netdev(0, "rtap%d", ether_setup);
+	if (rtap_dev == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
-	priv->ieee->iw_mode = IW_MODE_MONITOR;
+	memcpy(rtap_dev->dev_addr, priv->current_addr, ETH_ALEN);
+	rtap_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+	rtap_dev->open = lbs_rtap_open;
+	rtap_dev->stop = lbs_rtap_stop;
+	rtap_dev->get_stats = lbs_rtap_get_stats;
+	rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
+	rtap_dev->set_multicast_list = lbs_set_multicast_list;
+	rtap_dev->priv = priv;
 
-	rc = register_netdev(priv->rtap_net_dev);
-	if (rc) {
-		free_ieee80211(priv->rtap_net_dev);
-		priv->rtap_net_dev = NULL;
-		return rc;
+	ret = register_netdev(rtap_dev);
+	if (ret) {
+		free_netdev(rtap_dev);
+		goto out;
 	}
+	priv->rtap_net_dev = rtap_dev;
 
-	return 0;
+out:
+	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+	return ret;
 }
 
 
-module_init(libertas_init_module);
-module_exit(libertas_exit_module);
+module_init(lbs_init_module);
+module_exit(lbs_exit_module);
 
 MODULE_DESCRIPTION("Libertas WLAN Driver Library");
 MODULE_AUTHOR("Marvell International Ltd.");
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 0420e5b9ff9b..149557a478ac 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -35,134 +35,114 @@ struct rx80211packethdr {
 	void *eth80211_hdr;
 } __attribute__ ((packed));
 
-static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb);
+static int process_rxed_802_11_packet(struct lbs_private *priv,
+	struct sk_buff *skb);
 
 /**
  *  @brief This function computes the avgSNR .
  *
- *  @param priv    A pointer to wlan_private structure
+ *  @param priv    A pointer to struct lbs_private structure
  *  @return 	   avgSNR
  */
-static u8 wlan_getavgsnr(wlan_private * priv)
+static u8 lbs_getavgsnr(struct lbs_private *priv)
 {
 	u8 i;
 	u16 temp = 0;
-	wlan_adapter *adapter = priv->adapter;
-	if (adapter->numSNRNF == 0)
+	if (priv->numSNRNF == 0)
 		return 0;
-	for (i = 0; i < adapter->numSNRNF; i++)
-		temp += adapter->rawSNR[i];
-	return (u8) (temp / adapter->numSNRNF);
+	for (i = 0; i < priv->numSNRNF; i++)
+		temp += priv->rawSNR[i];
+	return (u8) (temp / priv->numSNRNF);
 
 }
 
 /**
  *  @brief This function computes the AvgNF
  *
- *  @param priv    A pointer to wlan_private structure
+ *  @param priv    A pointer to struct lbs_private structure
  *  @return 	   AvgNF
  */
-static u8 wlan_getavgnf(wlan_private * priv)
+static u8 lbs_getavgnf(struct lbs_private *priv)
 {
 	u8 i;
 	u16 temp = 0;
-	wlan_adapter *adapter = priv->adapter;
-	if (adapter->numSNRNF == 0)
+	if (priv->numSNRNF == 0)
 		return 0;
-	for (i = 0; i < adapter->numSNRNF; i++)
-		temp += adapter->rawNF[i];
-	return (u8) (temp / adapter->numSNRNF);
+	for (i = 0; i < priv->numSNRNF; i++)
+		temp += priv->rawNF[i];
+	return (u8) (temp / priv->numSNRNF);
 
 }
 
 /**
  *  @brief This function save the raw SNR/NF to our internel buffer
  *
- *  @param priv    A pointer to wlan_private structure
+ *  @param priv    A pointer to struct lbs_private structure
  *  @param prxpd   A pointer to rxpd structure of received packet
  *  @return 	   n/a
  */
-static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
+static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
 {
-	wlan_adapter *adapter = priv->adapter;
-	if (adapter->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
-		adapter->numSNRNF++;
-	adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
-	adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
-	adapter->nextSNRNF++;
-	if (adapter->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
-		adapter->nextSNRNF = 0;
+	if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
+		priv->numSNRNF++;
+	priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr;
+	priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf;
+	priv->nextSNRNF++;
+	if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
+		priv->nextSNRNF = 0;
 	return;
 }
 
 /**
  *  @brief This function computes the RSSI in received packet.
  *
- *  @param priv    A pointer to wlan_private structure
+ *  @param priv    A pointer to struct lbs_private structure
  *  @param prxpd   A pointer to rxpd structure of received packet
  *  @return 	   n/a
  */
-static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd)
+static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
 {
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_RX);
 
 	lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf);
 	lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n",
-	       adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
-	       adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+	       priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+	       priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
 
-	adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
-	adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
-	wlan_save_rawSNRNF(priv, p_rx_pd);
+	priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
+	priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
+	lbs_save_rawSNRNF(priv, p_rx_pd);
 
-	adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
-	adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
+	priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE;
+	priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE;
 	lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
-	       adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
-	       adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+	       priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+	       priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
 
-	adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
-	    CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
-		     adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+	priv->RSSI[TYPE_RXPD][TYPE_NOAVG] =
+	    CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG],
+		     priv->NF[TYPE_RXPD][TYPE_NOAVG]);
 
-	adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
-	    CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
-		     adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+	priv->RSSI[TYPE_RXPD][TYPE_AVG] =
+	    CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+		     priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
 
 	lbs_deb_leave(LBS_DEB_RX);
 }
 
-void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
-{
-	lbs_deb_rx("skb->data %p\n", skb->data);
-
-	if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
-		skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
-	} else {
-		if (priv->mesh_dev && IS_MESH_FRAME(skb))
-			skb->protocol = eth_type_trans(skb, priv->mesh_dev);
-		else
-			skb->protocol = eth_type_trans(skb, priv->dev);
-	}
-	skb->ip_summed = CHECKSUM_UNNECESSARY;
-	netif_rx(skb);
-}
-
 /**
  *  @brief This function processes received packet and forwards it
  *  to kernel/upper layer
  *
- *  @param priv    A pointer to wlan_private
+ *  @param priv    A pointer to struct lbs_private
  *  @param skb     A pointer to skb which includes the received packet
  *  @return 	   0 or -1
  */
-int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
+int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
-
+	struct net_device *dev = priv->dev;
 	struct rxpackethdr *p_rx_pkt;
 	struct rxpd *p_rx_pd;
 
@@ -173,15 +153,15 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
 
 	lbs_deb_enter(LBS_DEB_RX);
 
-	if (priv->adapter->monitormode != WLAN_MONITOR_OFF)
+	skb->ip_summed = CHECKSUM_NONE;
+
+	if (priv->monitormode != LBS_MONITOR_OFF)
 		return process_rxed_802_11_packet(priv, skb);
 
 	p_rx_pkt = (struct rxpackethdr *) skb->data;
 	p_rx_pd = &p_rx_pkt->rx_pd;
-	if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
-		SET_MESH_FRAME(skb);
-	else
-		UNSET_MESH_FRAME(skb);
+	if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME))
+		dev = priv->mesh_dev;
 
 	lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
 		 min_t(unsigned int, skb->len, 100));
@@ -257,23 +237,27 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
 	/* Take the data rate from the rxpd structure
 	 * only if the rate is auto
 	 */
-	if (adapter->auto_rate)
-		adapter->cur_rate = libertas_fw_index_to_data_rate(p_rx_pd->rx_rate);
+	if (priv->auto_rate)
+		priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);
 
-	wlan_compute_rssi(priv, p_rx_pd);
+	lbs_compute_rssi(priv, p_rx_pd);
 
 	lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
 	priv->stats.rx_bytes += skb->len;
 	priv->stats.rx_packets++;
 
-	libertas_upload_rx_packet(priv, skb);
+	skb->protocol = eth_type_trans(skb, dev);
+	if (in_interrupt())
+		netif_rx(skb);
+	else
+		netif_rx_ni(skb);
 
 	ret = 0;
 done:
 	lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(libertas_process_rxed_packet);
+EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
 
 /**
  *  @brief This function converts Tx/Rx rates from the Marvell WLAN format
@@ -319,13 +303,13 @@ static u8 convert_mv_rate_to_radiotap(u8 rate)
  *  @brief This function processes a received 802.11 packet and forwards it
  *  to kernel/upper layer
  *
- *  @param priv    A pointer to wlan_private
+ *  @param priv    A pointer to struct lbs_private
  *  @param skb     A pointer to skb which includes the received packet
  *  @return 	   0 or -1
  */
-static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
+static int process_rxed_802_11_packet(struct lbs_private *priv,
+	struct sk_buff *skb)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 
 	struct rx80211packethdr *p_rx_pkt;
@@ -341,9 +325,10 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
 	// lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
 
 	if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
-		lbs_deb_rx("rx err: frame received wit bad length\n");
+		lbs_deb_rx("rx err: frame received with bad length\n");
 		priv->stats.rx_length_errors++;
-		ret = 0;
+		ret = -EINVAL;
+		kfree(skb);
 		goto done;
 	}
 
@@ -359,65 +344,56 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
 	       skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
 
 	/* create the exported radio header */
-	if(priv->adapter->monitormode == WLAN_MONITOR_OFF) {
-		/* no radio header */
-		/* chop the rxpd */
-		skb_pull(skb, sizeof(struct rxpd));
-	}
 
-	else {
-		/* radiotap header */
-		radiotap_hdr.hdr.it_version = 0;
-		/* XXX must check this value for pad */
-		radiotap_hdr.hdr.it_pad = 0;
-		radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
-		radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
-		/* unknown values */
-		radiotap_hdr.flags = 0;
-		radiotap_hdr.chan_freq = 0;
-		radiotap_hdr.chan_flags = 0;
-		radiotap_hdr.antenna = 0;
-		/* known values */
-		radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
-		/* XXX must check no carryout */
-		radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
-		radiotap_hdr.rx_flags = 0;
-		if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK)))
-			radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
-		//memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
-
-		/* chop the rxpd */
-		skb_pull(skb, sizeof(struct rxpd));
-
-		/* add space for the new radio header */
-		if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
-		    pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0,
-				     GFP_ATOMIC)) {
-			lbs_pr_alert("%s: couldn't pskb_expand_head\n",
-			       __func__);
-		}
-
-		pradiotap_hdr =
-		    (struct rx_radiotap_hdr *)skb_push(skb,
-						     sizeof(struct
-							    rx_radiotap_hdr));
-		memcpy(pradiotap_hdr, &radiotap_hdr,
-		       sizeof(struct rx_radiotap_hdr));
+	/* radiotap header */
+	radiotap_hdr.hdr.it_version = 0;
+	/* XXX must check this value for pad */
+	radiotap_hdr.hdr.it_pad = 0;
+	radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
+	radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
+	/* unknown values */
+	radiotap_hdr.flags = 0;
+	radiotap_hdr.chan_freq = 0;
+	radiotap_hdr.chan_flags = 0;
+	radiotap_hdr.antenna = 0;
+	/* known values */
+	radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
+	/* XXX must check no carryout */
+	radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
+	radiotap_hdr.rx_flags = 0;
+	if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK)))
+		radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
+	//memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
+
+	/* chop the rxpd */
+	skb_pull(skb, sizeof(struct rxpd));
+
+	/* add space for the new radio header */
+	if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
+	    pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) {
+		lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__);
+		ret = -ENOMEM;
+		kfree_skb(skb);
+		goto done;
 	}
 
+	pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));
+	memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));
+
 	/* Take the data rate from the rxpd structure
 	 * only if the rate is auto
 	 */
-	if (adapter->auto_rate)
-		adapter->cur_rate = libertas_fw_index_to_data_rate(prxpd->rx_rate);
+	if (priv->auto_rate)
+		priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);
 
-	wlan_compute_rssi(priv, prxpd);
+	lbs_compute_rssi(priv, prxpd);
 
 	lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
 	priv->stats.rx_bytes += skb->len;
 	priv->stats.rx_packets++;
 
-	libertas_upload_rx_packet(priv, skb);
+	skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
+	netif_rx(skb);
 
 	ret = 0;
 
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index ad1e67d984ce..9a61188b62e9 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -39,9 +39,8 @@
 //! Memory needed to store a max number/size SSID TLV for a firmware scan
 #define SSID_TLV_MAX_SIZE  (1 * sizeof(struct mrvlietypes_ssidparamset))
 
-//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
-#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config)  \
-                            + sizeof(struct mrvlietypes_numprobes)   \
+//! Maximum memory needed for a lbs_scan_cmd_config with all TLVs at max
+#define MAX_SCAN_CFG_ALLOC (sizeof(struct lbs_scan_cmd_config)  \
                             + CHAN_TLV_MAX_SIZE                 \
                             + SSID_TLV_MAX_SIZE)
 
@@ -80,7 +79,23 @@ static inline void clear_bss_descriptor (struct bss_descriptor * bss)
 	memset(bss, 0, offsetof(struct bss_descriptor, list));
 }
 
-static inline int match_bss_no_security(struct wlan_802_11_security * secinfo,
+/**
+ *  @brief Compare two SSIDs
+ *
+ *  @param ssid1    A pointer to ssid to compare
+ *  @param ssid2    A pointer to ssid to compare
+ *
+ *  @return         0: ssid is same, otherwise is different
+ */
+int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
+{
+	if (ssid1_len != ssid2_len)
+		return -1;
+
+	return memcmp(ssid1, ssid2, ssid1_len);
+}
+
+static inline int match_bss_no_security(struct lbs_802_11_security *secinfo,
 			struct bss_descriptor * match_bss)
 {
 	if (   !secinfo->wep_enabled
@@ -94,7 +109,7 @@ static inline int match_bss_no_security(struct wlan_802_11_security * secinfo,
 	return 0;
 }
 
-static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo,
+static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo,
 			struct bss_descriptor * match_bss)
 {
 	if ( secinfo->wep_enabled
@@ -106,7 +121,7 @@ static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo,
 	return 0;
 }
 
-static inline int match_bss_wpa(struct wlan_802_11_security * secinfo,
+static inline int match_bss_wpa(struct lbs_802_11_security *secinfo,
 			struct bss_descriptor * match_bss)
 {
 	if (  !secinfo->wep_enabled
@@ -121,7 +136,7 @@ static inline int match_bss_wpa(struct wlan_802_11_security * secinfo,
 	return 0;
 }
 
-static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo,
+static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo,
 			struct bss_descriptor * match_bss)
 {
 	if (  !secinfo->wep_enabled
@@ -136,7 +151,7 @@ static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo,
 	return 0;
 }
 
-static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo,
+static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo,
 			struct bss_descriptor * match_bss)
 {
 	if (  !secinfo->wep_enabled
@@ -150,6 +165,18 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo,
 	return 0;
 }
 
+static inline int is_same_network(struct bss_descriptor *src,
+				  struct bss_descriptor *dst)
+{
+	/* A network is only a duplicate if the channel, BSSID, and ESSID
+	 * all match.  We treat all <hidden> with the same BSSID and channel
+	 * as one network */
+	return ((src->ssid_len == dst->ssid_len) &&
+		(src->channel == dst->channel) &&
+		!compare_ether_addr(src->bssid, dst->bssid) &&
+		!memcmp(src->ssid, dst->ssid, src->ssid_len));
+}
+
 /**
  *  @brief Check if a scanned network compatible with the driver settings
  *
@@ -163,13 +190,13 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo,
  *    0       0        0       0     !=NONE     1      0    0   yes Dynamic WEP
  *
  *
- *  @param adapter A pointer to wlan_adapter
+ *  @param priv A pointer to struct lbs_private
  *  @param index   Index in scantable to check against current driver settings
  *  @param mode    Network mode: Infrastructure or IBSS
  *
  *  @return        Index in scantable, or error code if negative
  */
-static int is_network_compatible(wlan_adapter * adapter,
+static int is_network_compatible(struct lbs_private *priv,
 		struct bss_descriptor * bss, u8 mode)
 {
 	int matched = 0;
@@ -179,34 +206,34 @@ static int is_network_compatible(wlan_adapter * adapter,
 	if (bss->mode != mode)
 		goto done;
 
-	if ((matched = match_bss_no_security(&adapter->secinfo, bss))) {
+	if ((matched = match_bss_no_security(&priv->secinfo, bss))) {
 		goto done;
-	} else if ((matched = match_bss_static_wep(&adapter->secinfo, bss))) {
+	} else if ((matched = match_bss_static_wep(&priv->secinfo, bss))) {
 		goto done;
-	} else if ((matched = match_bss_wpa(&adapter->secinfo, bss))) {
+	} else if ((matched = match_bss_wpa(&priv->secinfo, bss))) {
 		lbs_deb_scan(
-		       "is_network_compatible() WPA: wpa_ie=%#x "
-		       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
-		       "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0],
-		       adapter->secinfo.wep_enabled ? "e" : "d",
-		       adapter->secinfo.WPAenabled ? "e" : "d",
-		       adapter->secinfo.WPA2enabled ? "e" : "d",
+		       "is_network_compatible() WPA: wpa_ie 0x%x "
+		       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
+		       "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
+		       priv->secinfo.wep_enabled ? "e" : "d",
+		       priv->secinfo.WPAenabled ? "e" : "d",
+		       priv->secinfo.WPA2enabled ? "e" : "d",
 		       (bss->capability & WLAN_CAPABILITY_PRIVACY));
 		goto done;
-	} else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) {
+	} else if ((matched = match_bss_wpa2(&priv->secinfo, bss))) {
 		lbs_deb_scan(
-		       "is_network_compatible() WPA2: wpa_ie=%#x "
-		       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
-		       "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0],
-		       adapter->secinfo.wep_enabled ? "e" : "d",
-		       adapter->secinfo.WPAenabled ? "e" : "d",
-		       adapter->secinfo.WPA2enabled ? "e" : "d",
+		       "is_network_compatible() WPA2: wpa_ie 0x%x "
+		       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s "
+		       "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0],
+		       priv->secinfo.wep_enabled ? "e" : "d",
+		       priv->secinfo.WPAenabled ? "e" : "d",
+		       priv->secinfo.WPA2enabled ? "e" : "d",
 		       (bss->capability & WLAN_CAPABILITY_PRIVACY));
 		goto done;
-	} else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) {
+	} else if ((matched = match_bss_dynamic_wep(&priv->secinfo, bss))) {
 		lbs_deb_scan(
 		       "is_network_compatible() dynamic WEP: "
-		       "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n",
+		       "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n",
 		       bss->wpa_ie[0], bss->rsn_ie[0],
 		       (bss->capability & WLAN_CAPABILITY_PRIVACY));
 		goto done;
@@ -214,12 +241,12 @@ static int is_network_compatible(wlan_adapter * adapter,
 
 	/* bss security settings don't match those configured on card */
 	lbs_deb_scan(
-	       "is_network_compatible() FAILED: wpa_ie=%#x "
-	       "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s privacy=%#x\n",
+	       "is_network_compatible() FAILED: wpa_ie 0x%x "
+	       "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n",
 	       bss->wpa_ie[0], bss->rsn_ie[0],
-	       adapter->secinfo.wep_enabled ? "e" : "d",
-	       adapter->secinfo.WPAenabled ? "e" : "d",
-	       adapter->secinfo.WPA2enabled ? "e" : "d",
+	       priv->secinfo.wep_enabled ? "e" : "d",
+	       priv->secinfo.WPAenabled ? "e" : "d",
+	       priv->secinfo.WPA2enabled ? "e" : "d",
 	       (bss->capability & WLAN_CAPABILITY_PRIVACY));
 
 done:
@@ -227,22 +254,6 @@ done:
 	return matched;
 }
 
-/**
- *  @brief Compare two SSIDs
- *
- *  @param ssid1    A pointer to ssid to compare
- *  @param ssid2    A pointer to ssid to compare
- *
- *  @return         0--ssid is same, otherwise is different
- */
-int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
-{
-	if (ssid1_len != ssid2_len)
-		return -1;
-
-	return memcmp(ssid1, ssid2, ssid1_len);
-}
-
 
 
 
@@ -252,17 +263,27 @@ int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
 /*                                                                   */
 /*********************************************************************/
 
+void lbs_scan_worker(struct work_struct *work)
+{
+	struct lbs_private *priv =
+		container_of(work, struct lbs_private, scan_work.work);
+
+	lbs_deb_enter(LBS_DEB_SCAN);
+	lbs_scan_networks(priv, NULL, 0);
+	lbs_deb_leave(LBS_DEB_SCAN);
+}
+
 
 /**
  *  @brief Create a channel list for the driver to scan based on region info
  *
- *  Only used from wlan_scan_setup_scan_config()
+ *  Only used from lbs_scan_setup_scan_config()
  *
  *  Use the driver region/band information to construct a comprehensive list
  *    of channels to scan.  This routine is used for any scan that is not
  *    provided a specific channel list to scan.
  *
- *  @param priv          A pointer to wlan_private structure
+ *  @param priv          A pointer to struct lbs_private structure
  *  @param scanchanlist  Output parameter: resulting channel list to scan
  *  @param filteredscan  Flag indicating whether or not a BSSID or SSID filter
  *                       is being sent in the command to firmware.  Used to
@@ -272,12 +293,11 @@ int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
  *
  *  @return              void
  */
-static void wlan_scan_create_channel_list(wlan_private * priv,
+static int lbs_scan_create_channel_list(struct lbs_private *priv,
 					  struct chanscanparamset * scanchanlist,
 					  u8 filteredscan)
 {
 
-	wlan_adapter *adapter = priv->adapter;
 	struct region_channel *scanregion;
 	struct chan_freq_power *cfp;
 	int rgnidx;
@@ -285,8 +305,6 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
 	int nextchan;
 	u8 scantype;
 
-	lbs_deb_enter_args(LBS_DEB_SCAN, "filteredscan %d", filteredscan);
-
 	chanidx = 0;
 
 	/* Set the default scan type to the user specified type, will later
@@ -295,21 +313,22 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
 	 */
 	scantype = CMD_SCAN_TYPE_ACTIVE;
 
-	for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
-		if (priv->adapter->enable11d &&
-		    adapter->connect_status != LIBERTAS_CONNECTED) {
+	for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {
+		if (priv->enable11d &&
+		    (priv->connect_status != LBS_CONNECTED) &&
+		    (priv->mesh_connect_status != LBS_CONNECTED)) {
 			/* Scan all the supported chan for the first scan */
-			if (!adapter->universal_channel[rgnidx].valid)
+			if (!priv->universal_channel[rgnidx].valid)
 				continue;
-			scanregion = &adapter->universal_channel[rgnidx];
+			scanregion = &priv->universal_channel[rgnidx];
 
 			/* clear the parsed_region_chan for the first scan */
-			memset(&adapter->parsed_region_chan, 0x00,
-			       sizeof(adapter->parsed_region_chan));
+			memset(&priv->parsed_region_chan, 0x00,
+			       sizeof(priv->parsed_region_chan));
 		} else {
-			if (!adapter->region_channel[rgnidx].valid)
+			if (!priv->region_channel[rgnidx].valid)
 				continue;
-			scanregion = &adapter->region_channel[rgnidx];
+			scanregion = &priv->region_channel[rgnidx];
 		}
 
 		for (nextchan = 0;
@@ -317,10 +336,10 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
 
 			cfp = scanregion->CFP + nextchan;
 
-			if (priv->adapter->enable11d) {
+			if (priv->enable11d) {
 				scantype =
-				    libertas_get_scan_type_11d(cfp->channel,
-							   &adapter->
+				    lbs_get_scan_type_11d(cfp->channel,
+							   &priv->
 							   parsed_region_chan);
 			}
 
@@ -353,453 +372,151 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
 			}
 		}
 	}
+	return chanidx;
 }
 
 
-/* Delayed partial scan worker */
-void libertas_scan_worker(struct work_struct *work)
+/*
+ * Add SSID TLV of the form:
+ *
+ * TLV-ID SSID     00 00
+ * length          06 00
+ * ssid            4d 4e 54 45 53 54
+ */
+static int lbs_scan_add_ssid_tlv(u8 *tlv,
+	const struct lbs_ioctl_user_scan_cfg *user_cfg)
 {
-	wlan_private *priv = container_of(work, wlan_private, scan_work.work);
-
-	wlan_scan_networks(priv, NULL, 0);
+	struct mrvlietypes_ssidparamset *ssid_tlv =
+		(struct mrvlietypes_ssidparamset *)tlv;
+	ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+	ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len);
+	memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len);
+	return sizeof(ssid_tlv->header) + user_cfg->ssid_len;
 }
 
 
-/**
- *  @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
- *
- *  Application layer or other functions can invoke wlan_scan_networks
- *    with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
- *    This structure is used as the basis of one or many wlan_scan_cmd_config
- *    commands that are sent to the command processing module and sent to
- *    firmware.
- *
- *  Create a wlan_scan_cmd_config based on the following user supplied
- *    parameters (if present):
- *             - SSID filter
- *             - BSSID filter
- *             - Number of Probes to be sent
- *             - channel list
- *
- *  If the SSID or BSSID filter is not present, disable/clear the filter.
- *  If the number of probes is not set, use the adapter default setting
- *  Qualify the channel
+/*
+ * Add CHANLIST TLV of the form
  *
- *  @param priv             A pointer to wlan_private structure
- *  @param puserscanin      NULL or pointer to scan configuration parameters
- *  @param ppchantlvout     Output parameter: Pointer to the start of the
- *                          channel TLV portion of the output scan config
- *  @param pscanchanlist    Output parameter: Pointer to the resulting channel
- *                          list to scan
- *  @param pmaxchanperscan  Output parameter: Number of channels to scan for
- *                          each issuance of the firmware scan command
- *  @param pfilteredscan    Output parameter: Flag indicating whether or not
- *                          a BSSID or SSID filter is being sent in the
- *                          command to firmware.  Used to increase the number
- *                          of channels sent in a scan command and to
- *                          disable the firmware channel scan filter.
- *  @param pscancurrentonly Output parameter: Flag indicating whether or not
- *                          we are only scanning our current active channel
+ * TLV-ID CHANLIST 01 01
+ * length          5b 00
+ * channel 1       00 01 00 00 00 64 00
+ *   radio type    00
+ *   channel          01
+ *   scan type           00
+ *   min scan time          00 00
+ *   max scan time                64 00
+ * channel 2       00 02 00 00 00 64 00
+ * channel 3       00 03 00 00 00 64 00
+ * channel 4       00 04 00 00 00 64 00
+ * channel 5       00 05 00 00 00 64 00
+ * channel 6       00 06 00 00 00 64 00
+ * channel 7       00 07 00 00 00 64 00
+ * channel 8       00 08 00 00 00 64 00
+ * channel 9       00 09 00 00 00 64 00
+ * channel 10      00 0a 00 00 00 64 00
+ * channel 11      00 0b 00 00 00 64 00
+ * channel 12      00 0c 00 00 00 64 00
+ * channel 13      00 0d 00 00 00 64 00
  *
- *  @return                 resulting scan configuration
  */
-static struct wlan_scan_cmd_config *
-wlan_scan_setup_scan_config(wlan_private * priv,
-			    const struct wlan_ioctl_user_scan_cfg * puserscanin,
-			    struct mrvlietypes_chanlistparamset ** ppchantlvout,
-			    struct chanscanparamset * pscanchanlist,
-			    int *pmaxchanperscan,
-			    u8 * pfilteredscan,
-			    u8 * pscancurrentonly)
+static int lbs_scan_add_chanlist_tlv(u8 *tlv,
+	struct chanscanparamset *chan_list,
+	int chan_count)
 {
-	struct mrvlietypes_numprobes *pnumprobestlv;
-	struct mrvlietypes_ssidparamset *pssidtlv;
-	struct wlan_scan_cmd_config * pscancfgout = NULL;
-	u8 *ptlvpos;
-	u16 numprobes;
-	int chanidx;
-	int scantype;
-	int scandur;
-	int channel;
-	int radiotype;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
-	if (pscancfgout == NULL)
-		goto out;
-
-	/* The tlvbufferlen is calculated for each scan command.  The TLVs added
-	 *   in this routine will be preserved since the routine that sends
-	 *   the command will append channelTLVs at *ppchantlvout.  The difference
-	 *   between the *ppchantlvout and the tlvbuffer start will be used
-	 *   to calculate the size of anything we add in this routine.
-	 */
-	pscancfgout->tlvbufferlen = 0;
-
-	/* Running tlv pointer.  Assigned to ppchantlvout at end of function
-	 *  so later routines know where channels can be added to the command buf
-	 */
-	ptlvpos = pscancfgout->tlvbuffer;
-
-	/*
-	 * Set the initial scan paramters for progressive scanning.  If a specific
-	 *   BSSID or SSID is used, the number of channels in the scan command
-	 *   will be increased to the absolute maximum
-	 */
-	*pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
-
-	/* Initialize the scan as un-filtered by firmware, set to TRUE below if
-	 *   a SSID or BSSID filter is sent in the command
-	 */
-	*pfilteredscan = 0;
-
-	/* Initialize the scan as not being only on the current channel.  If
-	 *   the channel list is customized, only contains one channel, and
-	 *   is the active channel, this is set true and data flow is not halted.
-	 */
-	*pscancurrentonly = 0;
-
-	if (puserscanin) {
-		/* Set the bss type scan filter, use adapter setting if unset */
-		pscancfgout->bsstype =
-		    puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY;
-
-		/* Set the number of probes to send, use adapter setting if unset */
-		numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0;
-
-		/*
-		 * Set the BSSID filter to the incoming configuration,
-		 *   if non-zero.  If not set, it will remain disabled (all zeros).
-		 */
-		memcpy(pscancfgout->bssid, puserscanin->bssid,
-		       sizeof(pscancfgout->bssid));
-
-		if (puserscanin->ssid_len) {
-			pssidtlv =
-			    (struct mrvlietypes_ssidparamset *) pscancfgout->
-			    tlvbuffer;
-			pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
-			pssidtlv->header.len = cpu_to_le16(puserscanin->ssid_len);
-			memcpy(pssidtlv->ssid, puserscanin->ssid,
-			       puserscanin->ssid_len);
-			ptlvpos += sizeof(pssidtlv->header) + puserscanin->ssid_len;
-		}
-
-		/*
-		 *  The default number of channels sent in the command is low to
-		 *    ensure the response buffer from the firmware does not truncate
-		 *    scan results.  That is not an issue with an SSID or BSSID
-		 *    filter applied to the scan results in the firmware.
-		 */
-		if (   puserscanin->ssid_len
-		    || (compare_ether_addr(pscancfgout->bssid, &zeromac[0]) != 0)) {
-			*pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
-			*pfilteredscan = 1;
-		}
-	} else {
-		pscancfgout->bsstype = CMD_BSS_TYPE_ANY;
-		numprobes = 0;
-	}
-
-	/* If the input config or adapter has the number of Probes set, add tlv */
-	if (numprobes) {
-		pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos;
-		pnumprobestlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
-		pnumprobestlv->header.len = cpu_to_le16(2);
-		pnumprobestlv->numprobes = cpu_to_le16(numprobes);
-
-		ptlvpos += sizeof(*pnumprobestlv);
-	}
-
-	/*
-	 * Set the output for the channel TLV to the address in the tlv buffer
-	 *   past any TLVs that were added in this fuction (SSID, numprobes).
-	 *   channel TLVs will be added past this for each scan command, preserving
-	 *   the TLVs that were previously added.
-	 */
-	*ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
-
-	if (!puserscanin || !puserscanin->chanlist[0].channumber) {
-		/* Create a default channel scan list */
-		lbs_deb_scan("creating full region channel list\n");
-		wlan_scan_create_channel_list(priv, pscanchanlist,
-					      *pfilteredscan);
-		goto out;
-	}
-
-	for (chanidx = 0;
-	     chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
-	     && puserscanin->chanlist[chanidx].channumber; chanidx++) {
-
-		channel = puserscanin->chanlist[chanidx].channumber;
-		(pscanchanlist + chanidx)->channumber = channel;
-
-		radiotype = puserscanin->chanlist[chanidx].radiotype;
-		(pscanchanlist + chanidx)->radiotype = radiotype;
-
-		scantype = puserscanin->chanlist[chanidx].scantype;
-
-		if (scantype == CMD_SCAN_TYPE_PASSIVE) {
-			(pscanchanlist +
-			 chanidx)->chanscanmode.passivescan = 1;
-		} else {
-			(pscanchanlist +
-			 chanidx)->chanscanmode.passivescan = 0;
-		}
-
-		if (puserscanin->chanlist[chanidx].scantime) {
-			scandur = puserscanin->chanlist[chanidx].scantime;
-		} else {
-			if (scantype == CMD_SCAN_TYPE_PASSIVE) {
-				scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
-			} else {
-				scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
-			}
-		}
-
-		(pscanchanlist + chanidx)->minscantime =
-		    cpu_to_le16(scandur);
-		(pscanchanlist + chanidx)->maxscantime =
-		    cpu_to_le16(scandur);
-	}
-
-	/* Check if we are only scanning the current channel */
-	if ((chanidx == 1) &&
-	    (puserscanin->chanlist[0].channumber ==
-			       priv->adapter->curbssparams.channel)) {
-		*pscancurrentonly = 1;
-		lbs_deb_scan("scanning current channel only");
-	}
-
-out:
-	return pscancfgout;
+	size_t size = sizeof(struct chanscanparamset) * chan_count;
+	struct mrvlietypes_chanlistparamset *chan_tlv =
+		(struct mrvlietypes_chanlistparamset *) tlv;
+
+	chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+	memcpy(chan_tlv->chanscanparam, chan_list, size);
+	chan_tlv->header.len = cpu_to_le16(size);
+	return sizeof(chan_tlv->header) + size;
 }
 
-/**
- *  @brief Construct and send multiple scan config commands to the firmware
- *
- *  Only used from wlan_scan_networks()
- *
- *  Previous routines have created a wlan_scan_cmd_config with any requested
- *   TLVs.  This function splits the channel TLV into maxchanperscan lists
- *   and sends the portion of the channel TLV along with the other TLVs
- *   to the wlan_cmd routines for execution in the firmware.
+
+/*
+ * Add RATES TLV of the form
  *
- *  @param priv            A pointer to wlan_private structure
- *  @param maxchanperscan  Maximum number channels to be included in each
- *                         scan command sent to firmware
- *  @param filteredscan    Flag indicating whether or not a BSSID or SSID
- *                         filter is being used for the firmware command
- *                         scan command sent to firmware
- *  @param pscancfgout     Scan configuration used for this scan.
- *  @param pchantlvout     Pointer in the pscancfgout where the channel TLV
- *                         should start.  This is past any other TLVs that
- *                         must be sent down in each firmware command.
- *  @param pscanchanlist   List of channels to scan in maxchanperscan segments
+ * TLV-ID RATES    01 00
+ * length          0e 00
+ * rates           82 84 8b 96 0c 12 18 24 30 48 60 6c
  *
- *  @return                0 or error return otherwise
+ * The rates are in lbs_bg_rates[], but for the 802.11b
+ * rates the high bit isn't set.
  */
-static int wlan_scan_channel_list(wlan_private * priv,
-				  int maxchanperscan,
-				  u8 filteredscan,
-				  struct wlan_scan_cmd_config * pscancfgout,
-				  struct mrvlietypes_chanlistparamset * pchantlvout,
-				  struct chanscanparamset * pscanchanlist,
-				  const struct wlan_ioctl_user_scan_cfg * puserscanin,
-				  int full_scan)
+static int lbs_scan_add_rates_tlv(u8 *tlv)
 {
-	struct chanscanparamset *ptmpchan;
-	struct chanscanparamset *pstartchan;
-	u8 scanband;
-	int doneearly;
-	int tlvidx;
-	int ret = 0;
-	int scanned = 0;
-	union iwreq_data wrqu;
-
-	lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, "
-		"full_scan %d", maxchanperscan, filteredscan, full_scan);
-
-	if (!pscancfgout || !pchantlvout || !pscanchanlist) {
-		lbs_deb_scan("pscancfgout, pchantlvout or "
-			"pscanchanlist is NULL\n");
-		ret = -1;
-		goto out;
-	}
-
-	pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
-
-	/* Set the temp channel struct pointer to the start of the desired list */
-	ptmpchan = pscanchanlist;
-
-	if (priv->adapter->last_scanned_channel && !puserscanin)
-		ptmpchan += priv->adapter->last_scanned_channel;
-
-	/* Loop through the desired channel list, sending a new firmware scan
-	 *   commands for each maxchanperscan channels (or for 1,6,11 individually
-	 *   if configured accordingly)
-	 */
-	while (ptmpchan->channumber) {
-
-		tlvidx = 0;
-		pchantlvout->header.len = 0;
-		scanband = ptmpchan->radiotype;
-		pstartchan = ptmpchan;
-		doneearly = 0;
-
-		/* Construct the channel TLV for the scan command.  Continue to
-		 *  insert channel TLVs until:
-		 *    - the tlvidx hits the maximum configured per scan command
-		 *    - the next channel to insert is 0 (end of desired channel list)
-		 *    - doneearly is set (controlling individual scanning of 1,6,11)
-		 */
-		while (tlvidx < maxchanperscan && ptmpchan->channumber
-		       && !doneearly && scanned < 2) {
-
-			lbs_deb_scan("channel %d, radio %d, passive %d, "
-				"dischanflt %d, maxscantime %d\n",
-				ptmpchan->channumber,
-				ptmpchan->radiotype,
-			             ptmpchan->chanscanmode.passivescan,
-			             ptmpchan->chanscanmode.disablechanfilt,
-			             ptmpchan->maxscantime);
-
-			/* Copy the current channel TLV to the command being prepared */
-			memcpy(pchantlvout->chanscanparam + tlvidx,
-			       ptmpchan, sizeof(pchantlvout->chanscanparam));
-
-			/* Increment the TLV header length by the size appended */
-			/* Ew, it would be _so_ nice if we could just declare the
-			   variable little-endian and let GCC handle it for us */
-			pchantlvout->header.len =
-				cpu_to_le16(le16_to_cpu(pchantlvout->header.len) +
-					    sizeof(pchantlvout->chanscanparam));
-
-			/*
-			 *  The tlv buffer length is set to the number of bytes of the
-			 *    between the channel tlv pointer and the start of the
-			 *    tlv buffer.  This compensates for any TLVs that were appended
-			 *    before the channel list.
-			 */
-			pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
-						     - pscancfgout->tlvbuffer);
-
-			/*  Add the size of the channel tlv header and the data length */
-			pscancfgout->tlvbufferlen +=
-			    (sizeof(pchantlvout->header)
-			     + le16_to_cpu(pchantlvout->header.len));
-
-			/* Increment the index to the channel tlv we are constructing */
-			tlvidx++;
-
-			doneearly = 0;
-
-			/* Stop the loop if the *current* channel is in the 1,6,11 set
-			 *   and we are not filtering on a BSSID or SSID.
-			 */
-			if (!filteredscan && (ptmpchan->channumber == 1
-					      || ptmpchan->channumber == 6
-					      || ptmpchan->channumber == 11)) {
-				doneearly = 1;
-			}
-
-			/* Increment the tmp pointer to the next channel to be scanned */
-			ptmpchan++;
-			scanned++;
-
-			/* Stop the loop if the *next* channel is in the 1,6,11 set.
-			 *  This will cause it to be the only channel scanned on the next
-			 *  interation
-			 */
-			if (!filteredscan && (ptmpchan->channumber == 1
-					      || ptmpchan->channumber == 6
-					      || ptmpchan->channumber == 11)) {
-				doneearly = 1;
-			}
-		}
-
-		/* Send the scan command to the firmware with the specified cfg */
-		ret = libertas_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
-					    0, 0, pscancfgout);
-		if (scanned >= 2 && !full_scan) {
-			ret = 0;
-			goto done;
-		}
-		scanned = 0;
-	}
-
-done:
-	priv->adapter->last_scanned_channel = ptmpchan->channumber;
-
-	if (priv->adapter->last_scanned_channel) {
-		/* Schedule the next part of the partial scan */
-		if (!full_scan && !priv->adapter->surpriseremoved) {
-			cancel_delayed_work(&priv->scan_work);
-			queue_delayed_work(priv->work_thread, &priv->scan_work,
-			                   msecs_to_jiffies(300));
-		}
-	} else {
-		/* All done, tell userspace the scan table has been updated */
-		memset(&wrqu, 0, sizeof(union iwreq_data));
-		wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+	int i;
+	struct mrvlietypes_ratesparamset *rate_tlv =
+		(struct mrvlietypes_ratesparamset *) tlv;
+
+	rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
+	tlv += sizeof(rate_tlv->header);
+	for (i = 0; i < MAX_RATES; i++) {
+		*tlv = lbs_bg_rates[i];
+		if (*tlv == 0)
+			break;
+		/* This code makes sure that the 802.11b rates (1 MBit/s, 2
+		   MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set.
+		   Note that the values are MBit/s * 2, to mark them as
+		   basic rates so that the firmware likes it better */
+		if (*tlv == 0x02 || *tlv == 0x04 ||
+		    *tlv == 0x0b || *tlv == 0x16)
+			*tlv |= 0x80;
+		tlv++;
 	}
-
-out:
-	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
-	return ret;
+	rate_tlv->header.len = cpu_to_le16(i);
+	return sizeof(rate_tlv->header) + i;
 }
 
+
 /*
- * Only used from wlan_scan_networks()
-*/
-static void clear_selected_scan_list_entries(wlan_adapter *adapter,
-	const struct wlan_ioctl_user_scan_cfg *scan_cfg)
+ * Generate the CMD_802_11_SCAN command with the proper tlv
+ * for a bunch of channels.
+ */
+static int lbs_do_scan(struct lbs_private *priv,
+	u8 bsstype,
+	struct chanscanparamset *chan_list,
+	int chan_count,
+	const struct lbs_ioctl_user_scan_cfg *user_cfg)
 {
-	struct bss_descriptor *bss;
-	struct bss_descriptor *safe;
-	u32 clear_ssid_flag = 0, clear_bssid_flag = 0;
+	int ret = -ENOMEM;
+	struct lbs_scan_cmd_config *scan_cmd;
+	u8 *tlv;    /* pointer into our current, growing TLV storage area */
 
-	lbs_deb_enter(LBS_DEB_SCAN);
+	lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, "
+		"chan_count %d",
+		bsstype, chan_list[0].channumber, chan_count);
 
-	if (!scan_cfg)
+	/* create the fixed part for scan command */
+	scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
+	if (scan_cmd == NULL)
 		goto out;
-
-	if (scan_cfg->clear_ssid && scan_cfg->ssid_len)
-		clear_ssid_flag = 1;
-
-	if (scan_cfg->clear_bssid
-	    && (compare_ether_addr(scan_cfg->bssid, &zeromac[0]) != 0)
-	    && (compare_ether_addr(scan_cfg->bssid, &bcastmac[0]) != 0)) {
-		clear_bssid_flag = 1;
-	}
-
-	if (!clear_ssid_flag && !clear_bssid_flag)
-		goto out;
-
-	mutex_lock(&adapter->lock);
-	list_for_each_entry_safe (bss, safe, &adapter->network_list, list) {
-		u32 clear = 0;
-
-		/* Check for an SSID match */
-		if (   clear_ssid_flag
-		    && (bss->ssid_len == scan_cfg->ssid_len)
-		    && !memcmp(bss->ssid, scan_cfg->ssid, bss->ssid_len))
-			clear = 1;
-
-		/* Check for a BSSID match */
-		if (   clear_bssid_flag
-		    && !compare_ether_addr(bss->bssid, scan_cfg->bssid))
-			clear = 1;
-
-		if (clear) {
-			list_move_tail (&bss->list, &adapter->network_free_list);
-			clear_bss_descriptor(bss);
-		}
-	}
-	mutex_unlock(&adapter->lock);
+	tlv = scan_cmd->tlvbuffer;
+	if (user_cfg)
+		memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN);
+	scan_cmd->bsstype = bsstype;
+
+	/* add TLVs */
+	if (user_cfg && user_cfg->ssid_len)
+		tlv += lbs_scan_add_ssid_tlv(tlv, user_cfg);
+	if (chan_list && chan_count)
+		tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);
+	tlv += lbs_scan_add_rates_tlv(tlv);
+
+	/* This is the final data we are about to send */
+	scan_cmd->tlvbufferlen = tlv - scan_cmd->tlvbuffer;
+	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, 1+6);
+	lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,
+		scan_cmd->tlvbufferlen);
+
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
+		CMD_OPTION_WAITFORRSP, 0, scan_cmd);
 out:
-	lbs_deb_leave(LBS_DEB_SCAN);
+	kfree(scan_cmd);
+	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
+	return ret;
 }
 
 
@@ -812,32 +529,32 @@ out:
  *    order to send the appropriate scan commands to firmware to populate or
  *    update the internal driver scan table
  *
- *  @param priv          A pointer to wlan_private structure
+ *  @param priv          A pointer to struct lbs_private structure
  *  @param puserscanin   Pointer to the input configuration for the requested
  *                       scan.
- *  @param full_scan     ???
  *
  *  @return              0 or < 0 if error
  */
-int wlan_scan_networks(wlan_private * priv,
-                       const struct wlan_ioctl_user_scan_cfg * puserscanin,
+int lbs_scan_networks(struct lbs_private *priv,
+	const struct lbs_ioctl_user_scan_cfg *user_cfg,
                        int full_scan)
 {
-	wlan_adapter * adapter = priv->adapter;
-	struct mrvlietypes_chanlistparamset *pchantlvout;
-	struct chanscanparamset * scan_chan_list = NULL;
-	struct wlan_scan_cmd_config * scan_cfg = NULL;
-	u8 filteredscan;
-	u8 scancurrentchanonly;
-	int maxchanperscan;
-	int ret;
+	int ret = -ENOMEM;
+	struct chanscanparamset *chan_list;
+	struct chanscanparamset *curr_chans;
+	int chan_count;
+	u8 bsstype = CMD_BSS_TYPE_ANY;
+	int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;
+	int filteredscan = 0;
+	union iwreq_data wrqu;
 #ifdef CONFIG_LIBERTAS_DEBUG
-	struct bss_descriptor * iter_bss;
+	struct bss_descriptor *iter;
 	int i = 0;
 	DECLARE_MAC_BUF(mac);
 #endif
 
-	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
+	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d",
+		full_scan);
 
 	/* Cancel any partial outstanding partial scans if this scan
 	 * is a full scan.
@@ -845,90 +562,138 @@ int wlan_scan_networks(wlan_private * priv,
 	if (full_scan && delayed_work_pending(&priv->scan_work))
 		cancel_delayed_work(&priv->scan_work);
 
-	scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
-				WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
-	if (scan_chan_list == NULL) {
-		ret = -ENOMEM;
+	/* Determine same scan parameters */
+	if (user_cfg) {
+		if (user_cfg->bsstype)
+			bsstype = user_cfg->bsstype;
+		if (compare_ether_addr(user_cfg->bssid, &zeromac[0]) != 0) {
+			numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN;
+			filteredscan = 1;
+		}
+	}
+	lbs_deb_scan("numchannels %d, bsstype %d, "
+		"filteredscan %d\n",
+		numchannels, bsstype, filteredscan);
+
+	/* Create list of channels to scan */
+	chan_list = kzalloc(sizeof(struct chanscanparamset) *
+				LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
+	if (!chan_list) {
+		lbs_pr_alert("SCAN: chan_list empty\n");
 		goto out;
 	}
 
-	scan_cfg = wlan_scan_setup_scan_config(priv,
-					       puserscanin,
-					       &pchantlvout,
-					       scan_chan_list,
-					       &maxchanperscan,
-					       &filteredscan,
-					       &scancurrentchanonly);
-	if (scan_cfg == NULL) {
-		ret = -ENOMEM;
-		goto out;
+	/* We want to scan all channels */
+	chan_count = lbs_scan_create_channel_list(priv, chan_list,
+		filteredscan);
+
+	netif_stop_queue(priv->dev);
+	netif_carrier_off(priv->dev);
+	if (priv->mesh_dev) {
+		netif_stop_queue(priv->mesh_dev);
+		netif_carrier_off(priv->mesh_dev);
+	}
+
+	/* Prepare to continue an interrupted scan */
+	lbs_deb_scan("chan_count %d, last_scanned_channel %d\n",
+		     chan_count, priv->last_scanned_channel);
+	curr_chans = chan_list;
+	/* advance channel list by already-scanned-channels */
+	if (priv->last_scanned_channel > 0) {
+		curr_chans += priv->last_scanned_channel;
+		chan_count -= priv->last_scanned_channel;
 	}
 
-	clear_selected_scan_list_entries(adapter, puserscanin);
+	/* Send scan command(s)
+	 * numchannels contains the number of channels we should maximally scan
+	 * chan_count is the total number of channels to scan
+	 */
 
-	/* Keep the data path active if we are only scanning our current channel */
-	if (!scancurrentchanonly) {
-		netif_stop_queue(priv->dev);
-		netif_carrier_off(priv->dev);
-		if (priv->mesh_dev) {
-			netif_stop_queue(priv->mesh_dev);
-			netif_carrier_off(priv->mesh_dev);
+	while (chan_count) {
+		int to_scan = min(numchannels, chan_count);
+		lbs_deb_scan("scanning %d of %d channels\n",
+			to_scan, chan_count);
+		ret = lbs_do_scan(priv, bsstype, curr_chans,
+			to_scan, user_cfg);
+		if (ret) {
+			lbs_pr_err("SCAN_CMD failed\n");
+			goto out2;
+		}
+		curr_chans += to_scan;
+		chan_count -= to_scan;
+
+		/* somehow schedule the next part of the scan */
+		if (chan_count &&
+		    !full_scan &&
+		    !priv->surpriseremoved) {
+			/* -1 marks just that we're currently scanning */
+			if (priv->last_scanned_channel < 0)
+				priv->last_scanned_channel = to_scan;
+			else
+				priv->last_scanned_channel += to_scan;
+			cancel_delayed_work(&priv->scan_work);
+			queue_delayed_work(priv->work_thread, &priv->scan_work,
+				msecs_to_jiffies(300));
+			/* skip over GIWSCAN event */
+			goto out;
 		}
-	}
 
-	ret = wlan_scan_channel_list(priv,
-				     maxchanperscan,
-				     filteredscan,
-				     scan_cfg,
-				     pchantlvout,
-				     scan_chan_list,
-				     puserscanin,
-				     full_scan);
+	}
+	memset(&wrqu, 0, sizeof(union iwreq_data));
+	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
 
 #ifdef CONFIG_LIBERTAS_DEBUG
 	/* Dump the scan table */
-	mutex_lock(&adapter->lock);
-	lbs_deb_scan("The scan table contains:\n");
-	list_for_each_entry (iter_bss, &adapter->network_list, list) {
-		lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n",
-		       i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi,
-		       escape_essid(iter_bss->ssid, iter_bss->ssid_len));
-	}
-	mutex_unlock(&adapter->lock);
+	mutex_lock(&priv->lock);
+	lbs_deb_scan("scan table:\n");
+	list_for_each_entry(iter, &priv->network_list, list)
+		lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n",
+		       i++, print_mac(mac, iter->bssid), (s32) iter->rssi,
+		       escape_essid(iter->ssid, iter->ssid_len));
+	mutex_unlock(&priv->lock);
 #endif
 
-	if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
+out2:
+	priv->last_scanned_channel = 0;
+
+out:
+	if (priv->connect_status == LBS_CONNECTED) {
 		netif_carrier_on(priv->dev);
-		netif_wake_queue(priv->dev);
-		if (priv->mesh_dev) {
-			netif_carrier_on(priv->mesh_dev);
+		if (!priv->tx_pending_len)
+			netif_wake_queue(priv->dev);
+	}
+	if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) {
+		netif_carrier_on(priv->mesh_dev);
+		if (!priv->tx_pending_len)
 			netif_wake_queue(priv->mesh_dev);
-		}
 	}
-
-out:
-	if (scan_cfg)
-		kfree(scan_cfg);
-
-	if (scan_chan_list)
-		kfree(scan_chan_list);
+	kfree(chan_list);
 
 	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
 	return ret;
 }
 
+
+
+
+/*********************************************************************/
+/*                                                                   */
+/*  Result interpretation                                            */
+/*                                                                   */
+/*********************************************************************/
+
 /**
  *  @brief Interpret a BSS scan response returned from the firmware
  *
  *  Parse the various fixed fields and IEs passed back for a a BSS probe
- *   response or beacon from the scan command.  Record information as needed
- *   in the scan table struct bss_descriptor for that entry.
+ *  response or beacon from the scan command.  Record information as needed
+ *  in the scan table struct bss_descriptor for that entry.
  *
  *  @param bss  Output parameter: Pointer to the BSS Entry
  *
  *  @return             0 or -1
  */
-static int libertas_process_bss(struct bss_descriptor * bss,
+static int lbs_process_bss(struct bss_descriptor *bss,
 				u8 ** pbeaconinfo, int *bytesleft)
 {
 	struct ieeetypes_fhparamset *pFH;
@@ -946,7 +711,7 @@ static int libertas_process_bss(struct bss_descriptor * bss,
 
 	if (*bytesleft >= sizeof(beaconsize)) {
 		/* Extract & convert beacon size from the command buffer */
-		beaconsize = le16_to_cpu(get_unaligned((u16 *)*pbeaconinfo));
+		beaconsize = le16_to_cpu(get_unaligned((__le16 *)*pbeaconinfo));
 		*bytesleft -= sizeof(beaconsize);
 		*pbeaconinfo += sizeof(beaconsize);
 	}
@@ -967,7 +732,7 @@ static int libertas_process_bss(struct bss_descriptor * bss,
 	*bytesleft -= beaconsize;
 
 	memcpy(bss->bssid, pos, ETH_ALEN);
-	lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid));
+	lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid));
 	pos += ETH_ALEN;
 
 	if ((end - pos) < 12) {
@@ -983,7 +748,7 @@ static int libertas_process_bss(struct bss_descriptor * bss,
 
 	/* RSSI is 1 byte long */
 	bss->rssi = *pos;
-	lbs_deb_scan("process_bss: RSSI=%02X\n", *pos);
+	lbs_deb_scan("process_bss: RSSI %d\n", *pos);
 	pos++;
 
 	/* time stamp is 8 bytes long */
@@ -995,18 +760,18 @@ static int libertas_process_bss(struct bss_descriptor * bss,
 
 	/* capability information is 2 bytes long */
 	bss->capability = le16_to_cpup((void *) pos);
-	lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability);
+	lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
 	pos += 2;
 
 	if (bss->capability & WLAN_CAPABILITY_PRIVACY)
-		lbs_deb_scan("process_bss: AP WEP enabled\n");
+		lbs_deb_scan("process_bss: WEP enabled\n");
 	if (bss->capability & WLAN_CAPABILITY_IBSS)
 		bss->mode = IW_MODE_ADHOC;
 	else
 		bss->mode = IW_MODE_INFRA;
 
 	/* rest of the current buffer are IE's */
-	lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos);
+	lbs_deb_scan("process_bss: IE len %zd\n", end - pos);
 	lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
 
 	/* process variable IE */
@@ -1024,7 +789,7 @@ static int libertas_process_bss(struct bss_descriptor * bss,
 		case MFIE_TYPE_SSID:
 			bss->ssid_len = elem->len;
 			memcpy(bss->ssid, elem->data, elem->len);
-			lbs_deb_scan("ssid '%s', ssid length %u\n",
+			lbs_deb_scan("got SSID IE: '%s', len %u\n",
 			             escape_essid(bss->ssid, bss->ssid_len),
 			             bss->ssid_len);
 			break;
@@ -1033,16 +798,14 @@ static int libertas_process_bss(struct bss_descriptor * bss,
 			n_basic_rates = min_t(u8, MAX_RATES, elem->len);
 			memcpy(bss->rates, elem->data, n_basic_rates);
 			got_basic_rates = 1;
+			lbs_deb_scan("got RATES IE\n");
 			break;
 
 		case MFIE_TYPE_FH_SET:
 			pFH = (struct ieeetypes_fhparamset *) pos;
 			memmove(&bss->phyparamset.fhparamset, pFH,
 				sizeof(struct ieeetypes_fhparamset));
-#if 0 /* I think we can store these LE */
-			bss->phyparamset.fhparamset.dwelltime
-			    = le16_to_cpu(bss->phyparamset.fhparamset.dwelltime);
-#endif
+			lbs_deb_scan("got FH IE\n");
 			break;
 
 		case MFIE_TYPE_DS_SET:
@@ -1050,31 +813,31 @@ static int libertas_process_bss(struct bss_descriptor * bss,
 			bss->channel = pDS->currentchan;
 			memcpy(&bss->phyparamset.dsparamset, pDS,
 			       sizeof(struct ieeetypes_dsparamset));
+			lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
 			break;
 
 		case MFIE_TYPE_CF_SET:
 			pCF = (struct ieeetypes_cfparamset *) pos;
 			memcpy(&bss->ssparamset.cfparamset, pCF,
 			       sizeof(struct ieeetypes_cfparamset));
+			lbs_deb_scan("got CF IE\n");
 			break;
 
 		case MFIE_TYPE_IBSS_SET:
 			pibss = (struct ieeetypes_ibssparamset *) pos;
-			bss->atimwindow = le32_to_cpu(pibss->atimwindow);
+			bss->atimwindow = le16_to_cpu(pibss->atimwindow);
 			memmove(&bss->ssparamset.ibssparamset, pibss,
 				sizeof(struct ieeetypes_ibssparamset));
-#if 0
-			bss->ssparamset.ibssparamset.atimwindow
-			    = le16_to_cpu(bss->ssparamset.ibssparamset.atimwindow);
-#endif
+			lbs_deb_scan("got IBSS IE\n");
 			break;
 
 		case MFIE_TYPE_COUNTRY:
 			pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
+			lbs_deb_scan("got COUNTRY IE\n");
 			if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
 			    || pcountryinfo->len > 254) {
 				lbs_deb_scan("process_bss: 11D- Err "
-				       "CountryInfo len =%d min=%zd max=254\n",
+				       "CountryInfo len %d, min %zd, max 254\n",
 				       pcountryinfo->len,
 				       sizeof(pcountryinfo->countrycode));
 				ret = -1;
@@ -1093,8 +856,11 @@ static int libertas_process_bss(struct bss_descriptor * bss,
 			 * already found. Data rate IE should come before
 			 * extended supported rate IE
 			 */
-			if (!got_basic_rates)
+			lbs_deb_scan("got RATESEX IE\n");
+			if (!got_basic_rates) {
+				lbs_deb_scan("... but ignoring it\n");
 				break;
+			}
 
 			n_ex_rates = elem->len;
 			if (n_basic_rates + n_ex_rates > MAX_RATES)
@@ -1113,24 +879,36 @@ static int libertas_process_bss(struct bss_descriptor * bss,
 				bss->wpa_ie_len = min(elem->len + 2,
 				                      MAX_WPA_IE_LEN);
 				memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
-				lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie,
+				lbs_deb_scan("got WPA IE\n");
+				lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,
 				            elem->len);
 			} else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
 			    elem->data[0] == 0x00 &&
 			    elem->data[1] == 0x50 &&
 			    elem->data[2] == 0x43 &&
 			    elem->data[3] == 0x04) {
+				lbs_deb_scan("got mesh IE\n");
 				bss->mesh = 1;
+			} else {
+				lbs_deb_scan("got generiec IE: "
+					"%02x:%02x:%02x:%02x, len %d\n",
+					elem->data[0], elem->data[1],
+					elem->data[2], elem->data[3],
+					elem->len);
 			}
 			break;
 
 		case MFIE_TYPE_RSN:
+			lbs_deb_scan("got RSN IE\n");
 			bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
 			memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
-			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len);
+			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",
+				bss->rsn_ie, elem->len);
 			break;
 
 		default:
+			lbs_deb_scan("got IE 0x%04x, len %d\n",
+				elem->id, elem->len);
 			break;
 		}
 
@@ -1139,7 +917,7 @@ static int libertas_process_bss(struct bss_descriptor * bss,
 
 	/* Timestamp */
 	bss->last_scanned = jiffies;
-	libertas_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
+	lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
 
 	ret = 0;
 
@@ -1153,13 +931,13 @@ done:
  *
  *  Used in association code
  *
- *  @param adapter  A pointer to wlan_adapter
+ *  @param priv  A pointer to struct lbs_private
  *  @param bssid    BSSID to find in the scan list
  *  @param mode     Network mode: Infrastructure or IBSS
  *
  *  @return         index in BSSID list, or error return code (< 0)
  */
-struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter,
+struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
 		u8 * bssid, u8 mode)
 {
 	struct bss_descriptor * iter_bss;
@@ -1177,14 +955,14 @@ struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter,
 	 *   continue past a matched bssid that is not compatible in case there
 	 *   is an AP with multiple SSIDs assigned to the same BSSID
 	 */
-	mutex_lock(&adapter->lock);
-	list_for_each_entry (iter_bss, &adapter->network_list, list) {
+	mutex_lock(&priv->lock);
+	list_for_each_entry (iter_bss, &priv->network_list, list) {
 		if (compare_ether_addr(iter_bss->bssid, bssid))
 			continue; /* bssid doesn't match */
 		switch (mode) {
 		case IW_MODE_INFRA:
 		case IW_MODE_ADHOC:
-			if (!is_network_compatible(adapter, iter_bss, mode))
+			if (!is_network_compatible(priv, iter_bss, mode))
 				break;
 			found_bss = iter_bss;
 			break;
@@ -1193,7 +971,7 @@ struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter,
 			break;
 		}
 	}
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 
 out:
 	lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
@@ -1205,14 +983,14 @@ out:
  *
  *  Used in association code
  *
- *  @param adapter  A pointer to wlan_adapter
+ *  @param priv  A pointer to struct lbs_private
  *  @param ssid     SSID to find in the list
  *  @param bssid    BSSID to qualify the SSID selection (if provided)
  *  @param mode     Network mode: Infrastructure or IBSS
  *
  *  @return         index in BSSID list
  */
-struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
+struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
 		   u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode,
 		   int channel)
 {
@@ -1223,14 +1001,14 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
 
 	lbs_deb_enter(LBS_DEB_SCAN);
 
-	mutex_lock(&adapter->lock);
+	mutex_lock(&priv->lock);
 
-	list_for_each_entry (iter_bss, &adapter->network_list, list) {
+	list_for_each_entry (iter_bss, &priv->network_list, list) {
 		if (   !tmp_oldest
 		    || (iter_bss->last_scanned < tmp_oldest->last_scanned))
 			tmp_oldest = iter_bss;
 
-		if (libertas_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
+		if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len,
 		                      ssid, ssid_len) != 0)
 			continue; /* ssid doesn't match */
 		if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0)
@@ -1241,7 +1019,7 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
 		switch (mode) {
 		case IW_MODE_INFRA:
 		case IW_MODE_ADHOC:
-			if (!is_network_compatible(adapter, iter_bss, mode))
+			if (!is_network_compatible(priv, iter_bss, mode))
 				break;
 
 			if (bssid) {
@@ -1266,7 +1044,7 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
 	}
 
 out:
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 	lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
 	return found_bss;
 }
@@ -1277,12 +1055,13 @@ out:
  *  Search the scan table for the best SSID that also matches the current
  *   adapter network preference (infrastructure or adhoc)
  *
- *  @param adapter  A pointer to wlan_adapter
+ *  @param priv  A pointer to struct lbs_private
  *
  *  @return         index in BSSID list
  */
-static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
-		u8 mode)
+static struct bss_descriptor *lbs_find_best_ssid_in_list(
+	struct lbs_private *priv,
+	u8 mode)
 {
 	u8 bestrssi = 0;
 	struct bss_descriptor * iter_bss;
@@ -1290,13 +1069,13 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad
 
 	lbs_deb_enter(LBS_DEB_SCAN);
 
-	mutex_lock(&adapter->lock);
+	mutex_lock(&priv->lock);
 
-	list_for_each_entry (iter_bss, &adapter->network_list, list) {
+	list_for_each_entry (iter_bss, &priv->network_list, list) {
 		switch (mode) {
 		case IW_MODE_INFRA:
 		case IW_MODE_ADHOC:
-			if (!is_network_compatible(adapter, iter_bss, mode))
+			if (!is_network_compatible(priv, iter_bss, mode))
 				break;
 			if (SCAN_RSSI(iter_bss->rssi) <= bestrssi)
 				break;
@@ -1313,7 +1092,7 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad
 		}
 	}
 
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 	lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
 	return best_bss;
 }
@@ -1323,27 +1102,24 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad
  *
  *  Used from association worker.
  *
- *  @param priv         A pointer to wlan_private structure
+ *  @param priv         A pointer to struct lbs_private structure
  *  @param pSSID        A pointer to AP's ssid
  *
  *  @return             0--success, otherwise--fail
  */
-int libertas_find_best_network_ssid(wlan_private * priv,
+int lbs_find_best_network_ssid(struct lbs_private *priv,
 		u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = -1;
 	struct bss_descriptor * found;
 
 	lbs_deb_enter(LBS_DEB_SCAN);
 
-	wlan_scan_networks(priv, NULL, 1);
-	if (adapter->surpriseremoved)
+	lbs_scan_networks(priv, NULL, 1);
+	if (priv->surpriseremoved)
 		goto out;
 
-	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
-
-	found = libertas_find_best_ssid_in_list(adapter, preferred_mode);
+	found = lbs_find_best_ssid_in_list(priv, preferred_mode);
 	if (found && (found->ssid_len > 0)) {
 		memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE);
 		*out_ssid_len = found->ssid_len;
@@ -1356,57 +1132,24 @@ out:
 	return ret;
 }
 
-/**
- *  @brief Scan Network
- *
- *  @param dev          A pointer to net_device structure
- *  @param info         A pointer to iw_request_info structure
- *  @param vwrq         A pointer to iw_param structure
- *  @param extra        A pointer to extra data buf
- *
- *  @return             0 --success, otherwise fail
- */
-int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
-		  struct iw_param *vwrq, char *extra)
-{
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
-
-	lbs_deb_enter(LBS_DEB_SCAN);
-
-	if (!delayed_work_pending(&priv->scan_work)) {
-		queue_delayed_work(priv->work_thread, &priv->scan_work,
-		                   msecs_to_jiffies(50));
-	}
-
-	if (adapter->surpriseremoved)
-		return -1;
-
-	lbs_deb_leave(LBS_DEB_SCAN);
-	return 0;
-}
-
 
 /**
  *  @brief Send a scan command for all available channels filtered on a spec
  *
  *  Used in association code and from debugfs
  *
- *  @param priv             A pointer to wlan_private structure
+ *  @param priv             A pointer to struct lbs_private structure
  *  @param ssid             A pointer to the SSID to scan for
  *  @param ssid_len         Length of the SSID
  *  @param clear_ssid       Should existing scan results with this SSID
  *                          be cleared?
- *  @param prequestedssid   A pointer to AP's ssid
- *  @param keeppreviousscan Flag used to save/clear scan table before scan
  *
  *  @return                0-success, otherwise fail
  */
-int libertas_send_specific_ssid_scan(wlan_private * priv,
+int lbs_send_specific_ssid_scan(struct lbs_private *priv,
 			u8 *ssid, u8 ssid_len, u8 clear_ssid)
 {
-	wlan_adapter *adapter = priv->adapter;
-	struct wlan_ioctl_user_scan_cfg scancfg;
+	struct lbs_ioctl_user_scan_cfg scancfg;
 	int ret = 0;
 
 	lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d",
@@ -1420,12 +1163,11 @@ int libertas_send_specific_ssid_scan(wlan_private * priv,
 	scancfg.ssid_len = ssid_len;
 	scancfg.clear_ssid = clear_ssid;
 
-	wlan_scan_networks(priv, &scancfg, 1);
-	if (adapter->surpriseremoved) {
+	lbs_scan_networks(priv, &scancfg, 1);
+	if (priv->surpriseremoved) {
 		ret = -1;
 		goto out;
 	}
-	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
 
 out:
 	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
@@ -1441,13 +1183,13 @@ out:
 /*                                                                   */
 /*********************************************************************/
 
+
 #define MAX_CUSTOM_LEN 64
 
-static inline char *libertas_translate_scan(wlan_private *priv,
+static inline char *lbs_translate_scan(struct lbs_private *priv,
 					char *start, char *stop,
 					struct bss_descriptor *bss)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct chan_freq_power *cfp;
 	char *current_val;	/* For rates */
 	struct iw_event iwe;	/* Temporary buffer */
@@ -1459,14 +1201,14 @@ static inline char *libertas_translate_scan(wlan_private *priv,
 
 	lbs_deb_enter(LBS_DEB_SCAN);
 
-	cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel);
+	cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel);
 	if (!cfp) {
 		lbs_deb_scan("Invalid channel number %d\n", bss->channel);
 		start = NULL;
 		goto out;
 	}
 
-	/* First entry *MUST* be the AP BSSID */
+	/* First entry *MUST* be the BSSID */
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);
@@ -1502,25 +1244,25 @@ static inline char *libertas_translate_scan(wlan_private *priv,
 	if (iwe.u.qual.qual > 100)
 		iwe.u.qual.qual = 100;
 
-	if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+	if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
 		iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
 	} else {
 		iwe.u.qual.noise =
-		    CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+		    CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
 	}
 
 	/* Locally created ad-hoc BSSs won't have beacons if this is the
 	 * only station in the adhoc network; so get signal strength
 	 * from receive statistics.
 	 */
-	if ((adapter->mode == IW_MODE_ADHOC)
-	    && adapter->adhoccreate
-	    && !libertas_ssid_cmp(adapter->curbssparams.ssid,
-	                          adapter->curbssparams.ssid_len,
+	if ((priv->mode == IW_MODE_ADHOC)
+	    && priv->adhoccreate
+	    && !lbs_ssid_cmp(priv->curbssparams.ssid,
+	                          priv->curbssparams.ssid_len,
 	                          bss->ssid, bss->ssid_len)) {
 		int snr, nf;
-		snr = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
-		nf = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+		snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+		nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
 		iwe.u.qual.level = CAL_RSSI(snr, nf);
 	}
 	start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
@@ -1549,10 +1291,10 @@ static inline char *libertas_translate_scan(wlan_private *priv,
 					 stop, &iwe, IW_EV_PARAM_LEN);
 	}
 	if ((bss->mode == IW_MODE_ADHOC)
-	    && !libertas_ssid_cmp(adapter->curbssparams.ssid,
-	                          adapter->curbssparams.ssid_len,
+	    && !lbs_ssid_cmp(priv->curbssparams.ssid,
+	                          priv->curbssparams.ssid_len,
 	                          bss->ssid, bss->ssid_len)
-	    && adapter->adhoccreate) {
+	    && priv->adhoccreate) {
 		iwe.u.bitrate.value = 22 * 500000;
 		current_val = iwe_stream_add_value(start, current_val,
 					 stop, &iwe, IW_EV_PARAM_LEN);
@@ -1596,6 +1338,54 @@ out:
 	return start;
 }
 
+
+/**
+ *  @brief Handle Scan Network ioctl
+ *
+ *  @param dev          A pointer to net_device structure
+ *  @param info         A pointer to iw_request_info structure
+ *  @param vwrq         A pointer to iw_param structure
+ *  @param extra        A pointer to extra data buf
+ *
+ *  @return             0 --success, otherwise fail
+ */
+int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
+		  struct iw_param *wrqu, char *extra)
+{
+	struct lbs_private *priv = dev->priv;
+
+	lbs_deb_enter(LBS_DEB_SCAN);
+
+	if (!netif_running(dev))
+		return -ENETDOWN;
+
+	/* mac80211 does this:
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	if (sdata->type != IEEE80211_IF_TYPE_xxx)
+		return -EOPNOTSUPP;
+
+	if (wrqu->data.length == sizeof(struct iw_scan_req) &&
+	    wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+		req = (struct iw_scan_req *)extra;
+			ssid = req->essid;
+		ssid_len = req->essid_len;
+	}
+	*/
+
+	if (!delayed_work_pending(&priv->scan_work))
+		queue_delayed_work(priv->work_thread, &priv->scan_work,
+			msecs_to_jiffies(50));
+	/* set marker that currently a scan is taking place */
+	priv->last_scanned_channel = -1;
+
+	if (priv->surpriseremoved)
+		return -EIO;
+
+	lbs_deb_leave(LBS_DEB_SCAN);
+	return 0;
+}
+
+
 /**
  *  @brief  Handle Retrieve scan table ioctl
  *
@@ -1606,12 +1396,11 @@ out:
  *
  *  @return             0 --success, otherwise fail
  */
-int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
 		  struct iw_point *dwrq, char *extra)
 {
 #define SCAN_ITEM_SIZE 128
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	int err = 0;
 	char *ev = extra;
 	char *stop = ev + dwrq->length;
@@ -1620,14 +1409,18 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
 
 	lbs_deb_enter(LBS_DEB_SCAN);
 
+	/* iwlist should wait until the current scan is finished */
+	if (priv->last_scanned_channel)
+		return -EAGAIN;
+
 	/* Update RSSI if current BSS is a locally created ad-hoc BSS */
-	if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) {
-		libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+	if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {
+		lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
 					CMD_OPTION_WAITFORRSP, 0, NULL);
 	}
 
-	mutex_lock(&adapter->lock);
-	list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) {
+	mutex_lock(&priv->lock);
+	list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
 		char * next_ev;
 		unsigned long stale_time;
 
@@ -1644,18 +1437,18 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
 		stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
 		if (time_after(jiffies, stale_time)) {
 			list_move_tail (&iter_bss->list,
-			                &adapter->network_free_list);
+			                &priv->network_free_list);
 			clear_bss_descriptor(iter_bss);
 			continue;
 		}
 
 		/* Translate to WE format this entry */
-		next_ev = libertas_translate_scan(priv, ev, stop, iter_bss);
+		next_ev = lbs_translate_scan(priv, ev, stop, iter_bss);
 		if (next_ev == NULL)
 			continue;
 		ev = next_ev;
 	}
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 
 	dwrq->length = (ev - extra);
 	dwrq->flags = 0;
@@ -1677,24 +1470,25 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
 /**
  *  @brief Prepare a scan command to be sent to the firmware
  *
- *  Called from libertas_prepare_and_send_command() in cmd.c
+ *  Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...)
+ *  from cmd.c
  *
  *  Sends a fixed lenght data part (specifying the BSS type and BSSID filters)
  *  as well as a variable number/length of TLVs to the firmware.
  *
- *  @param priv       A pointer to wlan_private structure
+ *  @param priv       A pointer to struct lbs_private structure
  *  @param cmd        A pointer to cmd_ds_command structure to be sent to
  *                    firmware with the cmd_DS_801_11_SCAN structure
- *  @param pdata_buf  Void pointer cast of a wlan_scan_cmd_config struct used
+ *  @param pdata_buf  Void pointer cast of a lbs_scan_cmd_config struct used
  *                    to set the fields/TLVs for the command sent to firmware
  *
  *  @return           0 or -1
  */
-int libertas_cmd_80211_scan(wlan_private * priv,
-			 struct cmd_ds_command *cmd, void *pdata_buf)
+int lbs_cmd_80211_scan(struct lbs_private *priv,
+	struct cmd_ds_command *cmd, void *pdata_buf)
 {
 	struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
-	struct wlan_scan_cmd_config *pscancfg = pdata_buf;
+	struct lbs_scan_cmd_config *pscancfg = pdata_buf;
 
 	lbs_deb_enter(LBS_DEB_SCAN);
 
@@ -1703,32 +1497,14 @@ int libertas_cmd_80211_scan(wlan_private * priv,
 	memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN);
 	memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
 
-	cmd->command = cpu_to_le16(CMD_802_11_SCAN);
-
 	/* size is equal to the sizeof(fixed portions) + the TLV len + header */
 	cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN
 				+ pscancfg->tlvbufferlen + S_DS_GEN);
 
-	lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n",
-		     le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
-		     le16_to_cpu(cmd->seqnum));
-
 	lbs_deb_leave(LBS_DEB_SCAN);
 	return 0;
 }
 
-static inline int is_same_network(struct bss_descriptor *src,
-				  struct bss_descriptor *dst)
-{
-	/* A network is only a duplicate if the channel, BSSID, and ESSID
-	 * all match.  We treat all <hidden> with the same BSSID and channel
-	 * as one network */
-	return ((src->ssid_len == dst->ssid_len) &&
-		(src->channel == dst->channel) &&
-		!compare_ether_addr(src->bssid, dst->bssid) &&
-		!memcmp(src->ssid, dst->ssid, src->ssid_len));
-}
-
 /**
  *  @brief This function handles the command response of scan
  *
@@ -1750,14 +1526,13 @@ static inline int is_same_network(struct bss_descriptor *src,
  *     |            bufsize and sizeof the fixed fields above)     |
  *     .-----------------------------------------------------------.
  *
- *  @param priv    A pointer to wlan_private structure
+ *  @param priv    A pointer to struct lbs_private structure
  *  @param resp    A pointer to cmd_ds_command
  *
  *  @return        0 or -1
  */
-int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
+int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct cmd_ds_802_11_scan_rsp *pscan;
 	struct bss_descriptor * iter_bss;
 	struct bss_descriptor * safe;
@@ -1771,11 +1546,11 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
 	lbs_deb_enter(LBS_DEB_SCAN);
 
 	/* Prune old entries from scan table */
-	list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) {
+	list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {
 		unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
 		if (time_before(jiffies, stale_time))
 			continue;
-		list_move_tail (&iter_bss->list, &adapter->network_free_list);
+		list_move_tail (&iter_bss->list, &priv->network_free_list);
 		clear_bss_descriptor(iter_bss);
 	}
 
@@ -1789,12 +1564,11 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
 		goto done;
 	}
 
-	bytesleft = le16_to_cpu(get_unaligned((u16*)&pscan->bssdescriptsize));
+	bytesleft = le16_to_cpu(pscan->bssdescriptsize);
 	lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
 
-	scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size));
-	lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n",
-	       pscan->nr_sets);
+	scanrespsize = le16_to_cpu(resp->size);
+	lbs_deb_scan("SCAN_RESP: scan results %d\n", pscan->nr_sets);
 
 	pbssinfo = pscan->bssdesc_and_tlvbuffer;
 
@@ -1821,14 +1595,14 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
 
 		/* Process the data fields and IEs returned for this BSS */
 		memset(&new, 0, sizeof (struct bss_descriptor));
-		if (libertas_process_bss(&new, &pbssinfo, &bytesleft) != 0) {
+		if (lbs_process_bss(&new, &pbssinfo, &bytesleft) != 0) {
 			/* error parsing the scan response, skipped */
 			lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n");
 			continue;
 		}
 
 		/* Try to find this bss in the scan table */
-		list_for_each_entry (iter_bss, &adapter->network_list, list) {
+		list_for_each_entry (iter_bss, &priv->network_list, list) {
 			if (is_same_network(iter_bss, &new)) {
 				found = iter_bss;
 				break;
@@ -1842,21 +1616,21 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
 		if (found) {
 			/* found, clear it */
 			clear_bss_descriptor(found);
-		} else if (!list_empty(&adapter->network_free_list)) {
+		} else if (!list_empty(&priv->network_free_list)) {
 			/* Pull one from the free list */
-			found = list_entry(adapter->network_free_list.next,
+			found = list_entry(priv->network_free_list.next,
 					   struct bss_descriptor, list);
-			list_move_tail(&found->list, &adapter->network_list);
+			list_move_tail(&found->list, &priv->network_list);
 		} else if (oldest) {
 			/* If there are no more slots, expire the oldest */
 			found = oldest;
 			clear_bss_descriptor(found);
-			list_move_tail(&found->list, &adapter->network_list);
+			list_move_tail(&found->list, &priv->network_list);
 		} else {
 			continue;
 		}
 
-		lbs_deb_scan("SCAN_RESP: BSSID = %s\n",
+		lbs_deb_scan("SCAN_RESP: BSSID %s\n",
 			     print_mac(mac, new.bssid));
 
 		/* Copy the locally created newbssentry to the scan table */
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index c29c031bef8c..319f70dde350 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -2,10 +2,10 @@
   * Interface for the wlan network scan routines
   *
   * Driver interface functions and type declarations for the scan module
-  *   implemented in wlan_scan.c.
+  * implemented in scan.c.
   */
-#ifndef _WLAN_SCAN_H
-#define _WLAN_SCAN_H
+#ifndef _LBS_SCAN_H
+#define _LBS_SCAN_H
 
 #include <net/ieee80211.h>
 #include "hostcmd.h"
@@ -13,38 +13,38 @@
 /**
  *  @brief Maximum number of channels that can be sent in a setuserscan ioctl
  *
- *  @sa wlan_ioctl_user_scan_cfg
+ *  @sa lbs_ioctl_user_scan_cfg
  */
-#define WLAN_IOCTL_USER_SCAN_CHAN_MAX  50
+#define LBS_IOCTL_USER_SCAN_CHAN_MAX  50
 
-//! Infrastructure BSS scan type in wlan_scan_cmd_config
-#define WLAN_SCAN_BSS_TYPE_BSS         1
+//! Infrastructure BSS scan type in lbs_scan_cmd_config
+#define LBS_SCAN_BSS_TYPE_BSS         1
 
-//! Adhoc BSS scan type in wlan_scan_cmd_config
-#define WLAN_SCAN_BSS_TYPE_IBSS        2
+//! Adhoc BSS scan type in lbs_scan_cmd_config
+#define LBS_SCAN_BSS_TYPE_IBSS        2
 
-//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter
-#define WLAN_SCAN_BSS_TYPE_ANY         3
+//! Adhoc or Infrastructure BSS scan type in lbs_scan_cmd_config, no filter
+#define LBS_SCAN_BSS_TYPE_ANY         3
 
 /**
  * @brief Structure used internally in the wlan driver to configure a scan.
  *
  * Sent to the command processing module to configure the firmware
- *   scan command prepared by libertas_cmd_80211_scan.
+ *   scan command prepared by lbs_cmd_80211_scan.
  *
- * @sa wlan_scan_networks
+ * @sa lbs_scan_networks
  *
  */
-struct wlan_scan_cmd_config {
+struct lbs_scan_cmd_config {
     /**
      *  @brief BSS type to be sent in the firmware command
      *
      *  Field can be used to restrict the types of networks returned in the
      *    scan.  valid settings are:
      *
-     *   - WLAN_SCAN_BSS_TYPE_BSS  (infrastructure)
-     *   - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
-     *   - WLAN_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
+     *   - LBS_SCAN_BSS_TYPE_BSS  (infrastructure)
+     *   - LBS_SCAN_BSS_TYPE_IBSS (adhoc)
+     *   - LBS_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
      */
 	u8 bsstype;
 
@@ -68,12 +68,12 @@ struct wlan_scan_cmd_config {
 };
 
 /**
- *  @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *  @brief IOCTL channel sub-structure sent in lbs_ioctl_user_scan_cfg
  *
  *  Multiple instances of this structure are included in the IOCTL command
  *   to configure a instance of a scan on the specific channel.
  */
-struct wlan_ioctl_user_scan_chan {
+struct lbs_ioctl_user_scan_chan {
 	u8 channumber;		//!< channel Number to scan
 	u8 radiotype;		//!< Radio type: 'B/G' band = 0, 'A' band = 1
 	u8 scantype;		//!< Scan type: Active = 0, Passive = 1
@@ -83,31 +83,26 @@ struct wlan_ioctl_user_scan_chan {
 /**
  *  @brief IOCTL input structure to configure an immediate scan cmd to firmware
  *
- *  Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl.  Specifies
+ *  Used in the setuserscan (LBS_SET_USER_SCAN) private ioctl.  Specifies
  *   a number of parameters to be used in general for the scan as well
- *   as a channel list (wlan_ioctl_user_scan_chan) for each scan period
+ *   as a channel list (lbs_ioctl_user_scan_chan) for each scan period
  *   desired.
  *
- *  @sa libertas_set_user_scan_ioctl
+ *  @sa lbs_set_user_scan_ioctl
  */
-struct wlan_ioctl_user_scan_cfg {
+struct lbs_ioctl_user_scan_cfg {
     /**
      *  @brief BSS type to be sent in the firmware command
      *
      *  Field can be used to restrict the types of networks returned in the
      *    scan.  valid settings are:
      *
-     *   - WLAN_SCAN_BSS_TYPE_BSS  (infrastructure)
-     *   - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
-     *   - WLAN_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
+     *   - LBS_SCAN_BSS_TYPE_BSS  (infrastructure)
+     *   - LBS_SCAN_BSS_TYPE_IBSS (adhoc)
+     *   - LBS_SCAN_BSS_TYPE_ANY  (unrestricted, adhoc and infrastructure)
      */
 	u8 bsstype;
 
-    /**
-     *  @brief Configure the number of probe requests for active chan scans
-     */
-	u8 numprobes;
-
 	/**
 	 *  @brief BSSID filter sent in the firmware command to limit the results
 	 */
@@ -124,11 +119,6 @@ struct wlan_ioctl_user_scan_cfg {
 
 	/* Clear existing scan results matching this SSID */
 	u8 clear_ssid;
-
-    /**
-     *  @brief Variable number (fixed maximum) of channels to scan up
-     */
-	struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
 };
 
 /**
@@ -174,30 +164,30 @@ struct bss_descriptor {
 	struct list_head list;
 };
 
-int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
+int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
 
-struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
-			u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode,
-			int channel);
+struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv,
+		u8 *ssid, u8 ssid_len, u8 *bssid, u8 mode,
+		int channel);
 
-struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
-			u8 * bssid, u8 mode);
+struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv,
+	u8 *bssid, u8 mode);
 
-int libertas_find_best_network_ssid(wlan_private * priv, u8 *out_ssid,
+int lbs_find_best_network_ssid(struct lbs_private *priv, u8 *out_ssid,
 			u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode);
 
-int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid,
+int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,
 				u8 ssid_len, u8 clear_ssid);
 
-int libertas_cmd_80211_scan(wlan_private * priv,
+int lbs_cmd_80211_scan(struct lbs_private *priv,
 				struct cmd_ds_command *cmd,
 				void *pdata_buf);
 
-int libertas_ret_80211_scan(wlan_private * priv,
+int lbs_ret_80211_scan(struct lbs_private *priv,
 				struct cmd_ds_command *resp);
 
-int wlan_scan_networks(wlan_private * priv,
-                const struct wlan_ioctl_user_scan_cfg * puserscanin,
+int lbs_scan_networks(struct lbs_private *priv,
+	const struct lbs_ioctl_user_scan_cfg *puserscanin,
                 int full_scan);
 
 struct ifreq;
@@ -205,11 +195,11 @@ struct ifreq;
 struct iw_point;
 struct iw_param;
 struct iw_request_info;
-int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_point *dwrq, char *extra);
-int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_param *vwrq, char *extra);
 
-void libertas_scan_worker(struct work_struct *work);
+void lbs_scan_worker(struct work_struct *work);
 
-#endif				/* _WLAN_SCAN_H */
+#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index fbec06c10dd7..00d95f75bd89 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -2,6 +2,7 @@
   * This file contains the handling of TX in wlan driver.
   */
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 
 #include "hostcmd.h"
 #include "radiotap.h"
@@ -49,188 +50,122 @@ static u32 convert_radiotap_rate_to_mv(u8 rate)
 }
 
 /**
- *  @brief This function processes a single packet and sends
- *  to IF layer
+ *  @brief This function checks the conditions and sends packet to IF
+ *  layer if everything is ok.
  *
- *  @param priv    A pointer to wlan_private structure
+ *  @param priv    A pointer to struct lbs_private structure
  *  @param skb     A pointer to skb which includes TX packet
  *  @return 	   0 or -1
  */
-static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
+int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	int ret = 0;
-	struct txpd localtxpd;
-	struct txpd *plocaltxpd = &localtxpd;
-	u8 *p802x_hdr;
-	struct tx_radiotap_hdr *pradiotap_hdr;
-	u32 new_rate;
-	u8 *ptr = priv->adapter->tmptxbuf;
+	unsigned long flags;
+	struct lbs_private *priv = dev->priv;
+	struct txpd *txpd;
+	char *p802x_hdr;
+	uint16_t pkt_len;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_TX);
 
-	if (priv->adapter->surpriseremoved)
-		return -1;
+	ret = NETDEV_TX_OK;
+
+	/* We need to protect against the queues being restarted before
+	   we get round to stopping them */
+	spin_lock_irqsave(&priv->driver_lock, flags);
+
+	if (priv->surpriseremoved)
+		goto free;
 
 	if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
 		lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
 		       skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
-		ret = -1;
-		goto done;
+		/* We'll never manage to send this one; drop it and return 'OK' */
+
+		priv->stats.tx_dropped++;
+		priv->stats.tx_errors++;
+		goto free;
 	}
 
-	memset(plocaltxpd, 0, sizeof(struct txpd));
 
-	plocaltxpd->tx_packet_length = cpu_to_le16(skb->len);
+	netif_stop_queue(priv->dev);
+	if (priv->mesh_dev)
+		netif_stop_queue(priv->mesh_dev);
 
-	/* offset of actual data */
-	plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
+	if (priv->tx_pending_len) {
+		/* This can happen if packets come in on the mesh and eth
+		   device simultaneously -- there's no mutual exclusion on
+		   hard_start_xmit() calls between devices. */
+		lbs_deb_tx("Packet on %s while busy\n", dev->name);
+		ret = NETDEV_TX_BUSY;
+		goto unlock;
+	}
+
+	priv->tx_pending_len = -1;
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+	lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+
+	txpd = (void *)priv->tx_pending_buf;
+	memset(txpd, 0, sizeof(struct txpd));
 
 	p802x_hdr = skb->data;
-	if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+	pkt_len = skb->len;
 
-		/* locate radiotap header */
-		pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
+	if (dev == priv->rtap_net_dev) {
+		struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;
 
 		/* set txpd fields from the radiotap header */
-		new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
-		if (new_rate != 0) {
-			/* use new tx_control[4:0] */
-			plocaltxpd->tx_control = cpu_to_le32(new_rate);
-		}
+		txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate));
 
 		/* skip the radiotap header */
-		p802x_hdr += sizeof(struct tx_radiotap_hdr);
-		plocaltxpd->tx_packet_length =
-			cpu_to_le16(le16_to_cpu(plocaltxpd->tx_packet_length)
-				    - sizeof(struct tx_radiotap_hdr));
+		p802x_hdr += sizeof(*rtap_hdr);
+		pkt_len -= sizeof(*rtap_hdr);
 
+		/* copy destination address from 802.11 header */
+		memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
+	} else {
+		/* copy destination address from 802.3 header */
+		memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
 	}
-	/* copy destination address from 802.3 or 802.11 header */
-	if (priv->adapter->monitormode != WLAN_MONITOR_OFF)
-		memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
-	else
-		memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
 
-	lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
+	txpd->tx_packet_length = cpu_to_le16(pkt_len);
+	txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
 
-	if (IS_MESH_FRAME(skb)) {
-		plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
-	}
+	if (dev == priv->mesh_dev)
+		txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
 
-	memcpy(ptr, plocaltxpd, sizeof(struct txpd));
+	lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd));
 
-	ptr += sizeof(struct txpd);
+	lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
 
-	lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
-	memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
-	ret = priv->hw_host_to_card(priv, MVMS_DAT,
-				    priv->adapter->tmptxbuf,
-				    le16_to_cpu(plocaltxpd->tx_packet_length) +
-				    sizeof(struct txpd));
+	memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length));
 
-	if (ret) {
-		lbs_deb_tx("tx err: hw_host_to_card returned 0x%X\n", ret);
-		goto done;
-	}
+	spin_lock_irqsave(&priv->driver_lock, flags);
+	priv->tx_pending_len = pkt_len + sizeof(struct txpd);
 
-	lbs_deb_tx("SendSinglePacket succeeds\n");
+	lbs_deb_tx("%s lined up packet\n", __func__);
 
-done:
-	if (!ret) {
-		priv->stats.tx_packets++;
-		priv->stats.tx_bytes += skb->len;
-	} else {
-		priv->stats.tx_dropped++;
-		priv->stats.tx_errors++;
-	}
+	priv->stats.tx_packets++;
+	priv->stats.tx_bytes += skb->len;
 
-	if (!ret && priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+	dev->trans_start = jiffies;
+
+	if (priv->monitormode != LBS_MONITOR_OFF) {
 		/* Keep the skb to echo it back once Tx feedback is
 		   received from FW */
 		skb_orphan(skb);
-		/* stop processing outgoing pkts */
-		netif_stop_queue(priv->dev);
-		if (priv->mesh_dev)
-			netif_stop_queue(priv->mesh_dev);
-		/* freeze any packets already in our queues */
-		priv->adapter->TxLockFlag = 1;
-	} else {
-		dev_kfree_skb_any(skb);
-		priv->adapter->currenttxskb = NULL;
-	}
 
-	lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
-	return ret;
-}
-
-
-void libertas_tx_runqueue(wlan_private *priv)
-{
-	wlan_adapter *adapter = priv->adapter;
-	int i;
-
-	spin_lock(&adapter->txqueue_lock);
-	for (i = 0; i < adapter->tx_queue_idx; i++) {
-		struct sk_buff *skb = adapter->tx_queue_ps[i];
-		spin_unlock(&adapter->txqueue_lock);
-		SendSinglePacket(priv, skb);
-		spin_lock(&adapter->txqueue_lock);
-	}
-	adapter->tx_queue_idx = 0;
-	spin_unlock(&adapter->txqueue_lock);
-}
-
-static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb)
-{
-	wlan_adapter *adapter = priv->adapter;
-
-	spin_lock(&adapter->txqueue_lock);
-
-	WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE);
-	adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb;
-	if (adapter->tx_queue_idx == NR_TX_QUEUE) {
-		netif_stop_queue(priv->dev);
-		if (priv->mesh_dev)
-			netif_stop_queue(priv->mesh_dev);
+		/* Keep the skb around for when we get feedback */
+		priv->currenttxskb = skb;
 	} else {
-		netif_start_queue(priv->dev);
-		if (priv->mesh_dev)
-			netif_start_queue(priv->mesh_dev);
-	}
-
-	spin_unlock(&adapter->txqueue_lock);
-}
-
-/**
- *  @brief This function checks the conditions and sends packet to IF
- *  layer if everything is ok.
- *
- *  @param priv    A pointer to wlan_private structure
- *  @return 	   n/a
- */
-int libertas_process_tx(wlan_private * priv, struct sk_buff *skb)
-{
-	int ret = -1;
-
-	lbs_deb_enter(LBS_DEB_TX);
-	lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
-
-	if (priv->dnld_sent) {
-		lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
-		       priv->dnld_sent);
-		goto done;
-	}
-
-	if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
-	    (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) {
-		wlan_tx_queue(priv, skb);
-		return ret;
+ free:
+		dev_kfree_skb_any(skb);
 	}
+ unlock:
+	spin_unlock_irqrestore(&priv->driver_lock, flags);
+	wake_up(&priv->waitq);
 
-	priv->adapter->currenttxskb = skb;
-
-	ret = SendSinglePacket(priv, skb);
-done:
 	lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret);
 	return ret;
 }
@@ -239,24 +174,23 @@ done:
  *  @brief This function sends to the host the last transmitted packet,
  *  filling the radiotap headers with transmission information.
  *
- *  @param priv     A pointer to wlan_private structure
+ *  @param priv     A pointer to struct lbs_private structure
  *  @param status   A 32 bit value containing transmission status.
  *
  *  @returns void
  */
-void libertas_send_tx_feedback(wlan_private * priv)
+void lbs_send_tx_feedback(struct lbs_private *priv)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct tx_radiotap_hdr *radiotap_hdr;
-	u32 status = adapter->eventcause;
+	u32 status = priv->eventcause;
 	int txfail;
 	int try_count;
 
-	if (adapter->monitormode == WLAN_MONITOR_OFF ||
-	    adapter->currenttxskb == NULL)
+	if (priv->monitormode == LBS_MONITOR_OFF ||
+	    priv->currenttxskb == NULL)
 		return;
 
-	radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
+	radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;
 
 	txfail = (status >> 24);
 
@@ -269,14 +203,19 @@ void libertas_send_tx_feedback(wlan_private * priv)
 #endif
 	try_count = (status >> 16) & 0xff;
 	radiotap_hdr->data_retries = (try_count) ?
-	    (1 + adapter->txretrycount - try_count) : 0;
-	libertas_upload_rx_packet(priv, adapter->currenttxskb);
-	adapter->currenttxskb = NULL;
-	priv->adapter->TxLockFlag = 0;
-	if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
+	    (1 + priv->txretrycount - try_count) : 0;
+
+
+	priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,
+						      priv->rtap_net_dev);
+	netif_rx(priv->currenttxskb);
+
+	priv->currenttxskb = NULL;
+
+	if (priv->connect_status == LBS_CONNECTED)
 		netif_wake_queue(priv->dev);
-		if (priv->mesh_dev)
-			netif_wake_queue(priv->mesh_dev);
-	}
+
+	if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED))
+		netif_wake_queue(priv->mesh_dev);
 }
-EXPORT_SYMBOL_GPL(libertas_send_tx_feedback);
+EXPORT_SYMBOL_GPL(lbs_send_tx_feedback);
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index a43a5f63c879..f0d57958b34b 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -1,8 +1,8 @@
 /**
   * This header file contains definition for global types
   */
-#ifndef _WLAN_TYPES_
-#define _WLAN_TYPES_
+#ifndef _LBS_TYPES_H_
+#define _LBS_TYPES_H_
 
 #include <linux/if_ether.h>
 #include <asm/byteorder.h>
@@ -201,22 +201,11 @@ struct mrvlietypes_powercapability {
 	s8 maxpower;
 } __attribute__ ((packed));
 
-struct mrvlietypes_rssithreshold {
+/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
+struct mrvlietypes_thresholds {
 	struct mrvlietypesheader header;
-	u8 rssivalue;
-	u8 rssifreq;
-} __attribute__ ((packed));
-
-struct mrvlietypes_snrthreshold {
-	struct mrvlietypesheader header;
-	u8 snrvalue;
-	u8 snrfreq;
-} __attribute__ ((packed));
-
-struct mrvlietypes_failurecount {
-	struct mrvlietypesheader header;
-	u8 failvalue;
-	u8 Failfreq;
+	u8 value;
+	u8 freq;
 } __attribute__ ((packed));
 
 struct mrvlietypes_beaconsmissed {
@@ -250,4 +239,4 @@ struct mrvlietypes_ledgpio {
 	struct led_pin ledpin[1];
 } __attribute__ ((packed));
 
-#endif				/* _WLAN_TYPES_ */
+#endif
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 395b7882d4d6..e8bfc26b10a4 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -19,30 +19,47 @@
 #include "join.h"
 #include "wext.h"
 #include "assoc.h"
+#include "cmd.h"
+
+
+static inline void lbs_postpone_association_work(struct lbs_private *priv)
+{
+	if (priv->surpriseremoved)
+		return;
+	cancel_delayed_work(&priv->assoc_work);
+	queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
+}
+
+static inline void lbs_cancel_association_work(struct lbs_private *priv)
+{
+	cancel_delayed_work(&priv->assoc_work);
+	kfree(priv->pending_assoc_req);
+	priv->pending_assoc_req = NULL;
+}
 
 
 /**
  *  @brief Find the channel frequency power info with specific channel
  *
- *  @param adapter 	A pointer to wlan_adapter structure
+ *  @param priv 	A pointer to struct lbs_private structure
  *  @param band		it can be BAND_A, BAND_G or BAND_B
  *  @param channel      the channel for looking
  *  @return 	   	A pointer to struct chan_freq_power structure or NULL if not find.
  */
-struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
-						 u8 band, u16 channel)
+struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
+	struct lbs_private *priv,
+	u8 band,
+	u16 channel)
 {
 	struct chan_freq_power *cfp = NULL;
 	struct region_channel *rc;
-	int count = sizeof(adapter->region_channel) /
-	    sizeof(adapter->region_channel[0]);
 	int i, j;
 
-	for (j = 0; !cfp && (j < count); j++) {
-		rc = &adapter->region_channel[j];
+	for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
+		rc = &priv->region_channel[j];
 
-		if (adapter->enable11d)
-			rc = &adapter->universal_channel[j];
+		if (priv->enable11d)
+			rc = &priv->universal_channel[j];
 		if (!rc->valid || !rc->CFP)
 			continue;
 		if (rc->band != band)
@@ -56,7 +73,7 @@ struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * ada
 	}
 
 	if (!cfp && channel)
-		lbs_deb_wext("libertas_find_cfp_by_band_and_channel: can't find "
+		lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find "
 		       "cfp by band %d / channel %d\n", band, channel);
 
 	return cfp;
@@ -65,25 +82,25 @@ struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * ada
 /**
  *  @brief Find the channel frequency power info with specific frequency
  *
- *  @param adapter 	A pointer to wlan_adapter structure
+ *  @param priv 	A pointer to struct lbs_private structure
  *  @param band		it can be BAND_A, BAND_G or BAND_B
  *  @param freq	        the frequency for looking
  *  @return 	   	A pointer to struct chan_freq_power structure or NULL if not find.
  */
-static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
-						     u8 band, u32 freq)
+static struct chan_freq_power *find_cfp_by_band_and_freq(
+	struct lbs_private *priv,
+	u8 band,
+	u32 freq)
 {
 	struct chan_freq_power *cfp = NULL;
 	struct region_channel *rc;
-	int count = sizeof(adapter->region_channel) /
-	    sizeof(adapter->region_channel[0]);
 	int i, j;
 
-	for (j = 0; !cfp && (j < count); j++) {
-		rc = &adapter->region_channel[j];
+	for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
+		rc = &priv->region_channel[j];
 
-		if (adapter->enable11d)
-			rc = &adapter->universal_channel[j];
+		if (priv->enable11d)
+			rc = &priv->universal_channel[j];
 		if (!rc->valid || !rc->CFP)
 			continue;
 		if (rc->band != band)
@@ -107,22 +124,21 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
 /**
  *  @brief Set Radio On/OFF
  *
- *  @param priv                 A pointer to wlan_private structure
+ *  @param priv                 A pointer to struct lbs_private structure
  *  @option 			Radio Option
  *  @return 	   		0 --success, otherwise fail
  */
-static int wlan_radio_ioctl(wlan_private * priv, u8 option)
+static int lbs_radio_ioctl(struct lbs_private *priv, u8 option)
 {
 	int ret = 0;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (adapter->radioon != option) {
+	if (priv->radioon != option) {
 		lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
-		adapter->radioon = option;
+		priv->radioon = option;
 
-		ret = libertas_prepare_and_send_command(priv,
+		ret = lbs_prepare_and_send_command(priv,
 					    CMD_802_11_RADIO_CONTROL,
 					    CMD_ACT_SET,
 					    CMD_OPTION_WAITFORRSP, 0, NULL);
@@ -135,22 +151,23 @@ static int wlan_radio_ioctl(wlan_private * priv, u8 option)
 /**
  *  @brief Copy active data rates based on adapter mode and status
  *
- *  @param adapter              A pointer to wlan_adapter structure
+ *  @param priv              A pointer to struct lbs_private structure
  *  @param rate		        The buf to return the active rates
  */
-static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates)
+static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
 {
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (adapter->connect_status != LIBERTAS_CONNECTED)
-		memcpy(rates, libertas_bg_rates, MAX_RATES);
+	if ((priv->connect_status != LBS_CONNECTED) &&
+		(priv->mesh_connect_status != LBS_CONNECTED))
+		memcpy(rates, lbs_bg_rates, MAX_RATES);
 	else
-		memcpy(rates, adapter->curbssparams.rates, MAX_RATES);
+		memcpy(rates, priv->curbssparams.rates, MAX_RATES);
 
 	lbs_deb_leave(LBS_DEB_WEXT);
 }
 
-static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_name(struct net_device *dev, struct iw_request_info *info,
 			 char *cwrq, char *extra)
 {
 
@@ -163,22 +180,21 @@ static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
 	return 0;
 }
 
-static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_freq *fwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	struct chan_freq_power *cfp;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
-					   adapter->curbssparams.channel);
+	cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
+					   priv->curbssparams.channel);
 
 	if (!cfp) {
-		if (adapter->curbssparams.channel)
+		if (priv->curbssparams.channel)
 			lbs_deb_wext("invalid channel %d\n",
-			       adapter->curbssparams.channel);
+			       priv->curbssparams.channel);
 		return -EINVAL;
 	}
 
@@ -190,16 +206,15 @@ static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
 	return 0;
 }
 
-static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
 			struct sockaddr *awrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (adapter->connect_status == LIBERTAS_CONNECTED) {
-		memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+	if (priv->connect_status == LBS_CONNECTED) {
+		memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN);
 	} else {
 		memset(awrq->sa_data, 0, ETH_ALEN);
 	}
@@ -209,11 +224,10 @@ static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
 	return 0;
 }
 
-static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
+static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_point *dwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -225,25 +239,24 @@ static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
 		return -E2BIG;
 	}
 
-	mutex_lock(&adapter->lock);
-	memset(adapter->nodename, 0, sizeof(adapter->nodename));
-	memcpy(adapter->nodename, extra, dwrq->length);
-	mutex_unlock(&adapter->lock);
+	mutex_lock(&priv->lock);
+	memset(priv->nodename, 0, sizeof(priv->nodename));
+	memcpy(priv->nodename, extra, dwrq->length);
+	mutex_unlock(&priv->lock);
 
 	lbs_deb_leave(LBS_DEB_WEXT);
 	return 0;
 }
 
-static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_point *dwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	dwrq->length = strlen(adapter->nodename);
-	memcpy(extra, adapter->nodename, dwrq->length);
+	dwrq->length = strlen(priv->nodename);
+	memcpy(extra, priv->nodename, dwrq->length);
 	extra[dwrq->length] = '\0';
 
 	dwrq->flags = 1;	/* active */
@@ -255,14 +268,13 @@ static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
 static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_point *dwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	/* Use nickname to indicate that mesh is on */
 
-	if (adapter->connect_status == LIBERTAS_CONNECTED) {
+	if (priv->mesh_connect_status == LBS_CONNECTED) {
 		strncpy(extra, "Mesh", 12);
 		extra[12] = '\0';
 		dwrq->length = strlen(extra);
@@ -277,25 +289,24 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
 	return 0;
 }
 
-static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
+static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
 			struct iw_param *vwrq, char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	u32 rthr = vwrq->value;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	if (vwrq->disabled) {
-		adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
+		priv->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
 	} else {
 		if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
 			return -EINVAL;
-		adapter->rtsthsd = rthr;
+		priv->rtsthsd = rthr;
 	}
 
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
 				    CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_RTS_THRESHOLD, &rthr);
 
@@ -303,23 +314,22 @@ static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
 	return ret;
 }
 
-static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
 			struct iw_param *vwrq, char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	adapter->rtsthsd = 0;
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+	priv->rtsthsd = 0;
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
 				    CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_RTS_THRESHOLD, NULL);
 	if (ret)
 		goto out;
 
-	vwrq->value = adapter->rtsthsd;
+	vwrq->value = priv->rtsthsd;
 	vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
 			  || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
 	vwrq->fixed = 1;
@@ -329,26 +339,25 @@ out:
 	return ret;
 }
 
-static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
+static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_param *vwrq, char *extra)
 {
 	int ret = 0;
 	u32 fthr = vwrq->value;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	if (vwrq->disabled) {
-		adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
+		priv->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
 	} else {
 		if (fthr < MRVDRV_FRAG_MIN_VALUE
 		    || fthr > MRVDRV_FRAG_MAX_VALUE)
 			return -EINVAL;
-		adapter->fragthsd = fthr;
+		priv->fragthsd = fthr;
 	}
 
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+	ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
 				    CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
 
@@ -356,24 +365,23 @@ static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
 	return ret;
 }
 
-static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_param *vwrq, char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	adapter->fragthsd = 0;
-	ret = libertas_prepare_and_send_command(priv,
+	priv->fragthsd = 0;
+	ret = lbs_prepare_and_send_command(priv,
 				    CMD_802_11_SNMP_MIB,
 				    CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
 	if (ret)
 		goto out;
 
-	vwrq->value = adapter->fragthsd;
+	vwrq->value = priv->fragthsd;
 	vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
 			  || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
 	vwrq->fixed = 1;
@@ -383,15 +391,14 @@ out:
 	return ret;
 }
 
-static int wlan_get_mode(struct net_device *dev,
+static int lbs_get_mode(struct net_device *dev,
 			 struct iw_request_info *info, u32 * uwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	*uwrq = adapter->mode;
+	*uwrq = priv->mode;
 
 	lbs_deb_leave(LBS_DEB_WEXT);
 	return 0;
@@ -409,17 +416,16 @@ static int mesh_wlan_get_mode(struct net_device *dev,
 	return 0;
 }
 
-static int wlan_get_txpow(struct net_device *dev,
+static int lbs_get_txpow(struct net_device *dev,
 			  struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	ret = libertas_prepare_and_send_command(priv,
+	ret = lbs_prepare_and_send_command(priv,
 				    CMD_802_11_RF_TX_POWER,
 				    CMD_ACT_TX_POWER_OPT_GET,
 				    CMD_OPTION_WAITFORRSP, 0, NULL);
@@ -427,10 +433,10 @@ static int wlan_get_txpow(struct net_device *dev,
 	if (ret)
 		goto out;
 
-	lbs_deb_wext("tx power level %d dbm\n", adapter->txpowerlevel);
-	vwrq->value = adapter->txpowerlevel;
+	lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel);
+	vwrq->value = priv->txpowerlevel;
 	vwrq->fixed = 1;
-	if (adapter->radioon) {
+	if (priv->radioon) {
 		vwrq->disabled = 0;
 		vwrq->flags = IW_TXPOW_DBM;
 	} else {
@@ -442,12 +448,11 @@ out:
 	return ret;
 }
 
-static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
+static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -460,9 +465,9 @@ static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
 			return -EINVAL;
 
 		/* Adding 1 to convert retry count to try count */
-		adapter->txretrycount = vwrq->value + 1;
+		priv->txretrycount = vwrq->value + 1;
 
-		ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+		ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
 					    CMD_ACT_SET,
 					    CMD_OPTION_WAITFORRSP,
 					    OID_802_11_TX_RETRYCOUNT, NULL);
@@ -478,17 +483,16 @@ out:
 	return ret;
 }
 
-static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	adapter->txretrycount = 0;
-	ret = libertas_prepare_and_send_command(priv,
+	priv->txretrycount = 0;
+	ret = lbs_prepare_and_send_command(priv,
 				    CMD_802_11_SNMP_MIB,
 				    CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_TX_RETRYCOUNT, NULL);
@@ -499,7 +503,7 @@ static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
 	if (!vwrq->flags) {
 		vwrq->flags = IW_RETRY_LIMIT;
 		/* Subtract 1 to convert try count to retry count */
-		vwrq->value = adapter->txretrycount - 1;
+		vwrq->value = priv->txretrycount - 1;
 	}
 
 out:
@@ -546,12 +550,11 @@ static inline void sort_channels(struct iw_freq *freq, int num)
  *  @param extra		A pointer to extra data buf
  *  @return 	   		0 --success, otherwise fail
  */
-static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
 			  struct iw_point *dwrq, char *extra)
 {
 	int i, j;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	struct iw_range *range = (struct iw_range *)extra;
 	struct chan_freq_power *cfp;
 	u8 rates[MAX_RATES + 1];
@@ -567,7 +570,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
 	range->max_nwid = 0;
 
 	memset(rates, 0, sizeof(rates));
-	copy_active_data_rates(adapter, rates);
+	copy_active_data_rates(priv, rates);
 	range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
 	for (i = 0; i < range->num_bitrates; i++)
 		range->bitrate[i] = rates[i] * 500000;
@@ -576,13 +579,14 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
 	       range->num_bitrates);
 
 	range->num_frequency = 0;
-	if (priv->adapter->enable11d &&
-	    adapter->connect_status == LIBERTAS_CONNECTED) {
+	if (priv->enable11d &&
+	    (priv->connect_status == LBS_CONNECTED ||
+	    priv->mesh_connect_status == LBS_CONNECTED)) {
 		u8 chan_no;
 		u8 band;
 
 		struct parsed_region_chan_11d *parsed_region_chan =
-		    &adapter->parsed_region_chan;
+		    &priv->parsed_region_chan;
 
 		if (parsed_region_chan == NULL) {
 			lbs_deb_wext("11d: parsed_region_chan is NULL\n");
@@ -598,7 +602,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
 			lbs_deb_wext("chan_no %d\n", chan_no);
 			range->freq[range->num_frequency].i = (long)chan_no;
 			range->freq[range->num_frequency].m =
-			    (long)libertas_chan_2_freq(chan_no, band) * 100000;
+			    (long)lbs_chan_2_freq(chan_no, band) * 100000;
 			range->freq[range->num_frequency].e = 1;
 			range->num_frequency++;
 		}
@@ -606,13 +610,12 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
 	}
 	if (!flag) {
 		for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
-		     && (j < sizeof(adapter->region_channel)
-			 / sizeof(adapter->region_channel[0])); j++) {
-			cfp = adapter->region_channel[j].CFP;
+		     && (j < ARRAY_SIZE(priv->region_channel)); j++) {
+			cfp = priv->region_channel[j].CFP;
 			for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
-			     && adapter->region_channel[j].valid
+			     && priv->region_channel[j].valid
 			     && cfp
-			     && (i < adapter->region_channel[j].nrcfp); i++) {
+			     && (i < priv->region_channel[j].nrcfp); i++) {
 				range->freq[range->num_frequency].i =
 				    (long)cfp->channel;
 				range->freq[range->num_frequency].m =
@@ -712,7 +715,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
 				IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
 	range->event_capa[1] = IW_EVENT_CAPA_K_1;
 
-	if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
+	if (priv->fwcapinfo & FW_CAPINFO_WPA) {
 		range->enc_capa =   IW_ENC_CAPA_WPA
 		                  | IW_ENC_CAPA_WPA2
 		                  | IW_ENC_CAPA_CIPHER_TKIP
@@ -724,22 +727,28 @@ out:
 	return 0;
 }
 
-static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
+static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
+	if (!priv->ps_supported) {
+		if (vwrq->disabled)
+			return 0;
+		else
+			return -EINVAL;
+	}
+
 	/* PS is currently supported only in Infrastructure mode
 	 * Remove this check if it is to be supported in IBSS mode also
 	 */
 
 	if (vwrq->disabled) {
-		adapter->psmode = WLAN802_11POWERMODECAM;
-		if (adapter->psstate != PS_STATE_FULL_POWER) {
-			libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
+		priv->psmode = LBS802_11POWERMODECAM;
+		if (priv->psstate != PS_STATE_FULL_POWER) {
+			lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
 		}
 
 		return 0;
@@ -754,33 +763,32 @@ static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
 		return -EINVAL;
 	}
 
-	if (adapter->psmode != WLAN802_11POWERMODECAM) {
+	if (priv->psmode != LBS802_11POWERMODECAM) {
 		return 0;
 	}
 
-	adapter->psmode = WLAN802_11POWERMODEMAX_PSP;
+	priv->psmode = LBS802_11POWERMODEMAX_PSP;
 
-	if (adapter->connect_status == LIBERTAS_CONNECTED) {
-		libertas_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
+	if (priv->connect_status == LBS_CONNECTED) {
+		lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
 	}
 
 	lbs_deb_leave(LBS_DEB_WEXT);
 	return 0;
 }
 
-static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,
 			  struct iw_param *vwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	int mode;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	mode = adapter->psmode;
+	mode = priv->psmode;
 
-	if ((vwrq->disabled = (mode == WLAN802_11POWERMODECAM))
-	    || adapter->connect_status == LIBERTAS_DISCONNECTED)
+	if ((vwrq->disabled = (mode == LBS802_11POWERMODECAM))
+	    || priv->connect_status == LBS_DISCONNECTED)
 	{
 		goto out;
 	}
@@ -792,7 +800,7 @@ out:
 	return 0;
 }
 
-static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
+static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
 {
 	enum {
 		POOR = 30,
@@ -802,8 +810,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
 		EXCELLENT = 95,
 		PERFECT = 100
 	};
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	u32 rssi_qual;
 	u32 tx_qual;
 	u32 quality = 0;
@@ -813,22 +820,23 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	priv->wstats.status = adapter->mode;
+	priv->wstats.status = priv->mode;
 
 	/* If we're not associated, all quality values are meaningless */
-	if (adapter->connect_status != LIBERTAS_CONNECTED)
+	if ((priv->connect_status != LBS_CONNECTED) &&
+	    (priv->mesh_connect_status != LBS_CONNECTED))
 		goto out;
 
 	/* Quality by RSSI */
 	priv->wstats.qual.level =
-	    CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
-	     adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+	    CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
+	     priv->NF[TYPE_BEACON][TYPE_NOAVG]);
 
-	if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+	if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
 		priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
 	} else {
 		priv->wstats.qual.noise =
-		    CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+		    CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
 	}
 
 	lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
@@ -852,7 +860,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
 	/* Quality by TX errors */
 	priv->wstats.discard.retries = priv->stats.tx_errors;
 
-	tx_retries = le32_to_cpu(adapter->logmsg.retry);
+	tx_retries = le32_to_cpu(priv->logmsg.retry);
 
 	if (tx_retries > 75)
 		tx_qual = (90 - tx_retries) * POOR / 15;
@@ -868,10 +876,10 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
 		    (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
 	quality = min(quality, tx_qual);
 
-	priv->wstats.discard.code = le32_to_cpu(adapter->logmsg.wepundecryptable);
-	priv->wstats.discard.fragment = le32_to_cpu(adapter->logmsg.rxfrag);
+	priv->wstats.discard.code = le32_to_cpu(priv->logmsg.wepundecryptable);
+	priv->wstats.discard.fragment = le32_to_cpu(priv->logmsg.rxfrag);
 	priv->wstats.discard.retries = tx_retries;
-	priv->wstats.discard.misc = le32_to_cpu(adapter->logmsg.ackfailure);
+	priv->wstats.discard.misc = le32_to_cpu(priv->logmsg.ackfailure);
 
 	/* Calculate quality */
 	priv->wstats.qual.qual = min_t(u8, quality, 100);
@@ -879,9 +887,9 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
 	stats_valid = 1;
 
 	/* update stats asynchronously for future calls */
-	libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+	lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
 					0, 0, NULL);
-	libertas_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0,
+	lbs_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0,
 					0, 0, NULL);
 out:
 	if (!stats_valid) {
@@ -901,19 +909,18 @@ out:
 
 }
 
-static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
+static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
 		  struct iw_freq *fwrq, char *extra)
 {
 	int ret = -EINVAL;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	struct chan_freq_power *cfp;
 	struct assoc_request * assoc_req;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	mutex_lock(&adapter->lock);
-	assoc_req = wlan_get_association_request(adapter);
+	mutex_lock(&priv->lock);
+	assoc_req = lbs_get_association_request(priv);
 	if (!assoc_req) {
 		ret = -ENOMEM;
 		goto out;
@@ -923,7 +930,7 @@ static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
 	if (fwrq->e == 1) {
 		long f = fwrq->m / 100000;
 
-		cfp = find_cfp_by_band_and_freq(adapter, 0, f);
+		cfp = find_cfp_by_band_and_freq(priv, 0, f);
 		if (!cfp) {
 			lbs_deb_wext("invalid freq %ld\n", f);
 			goto out;
@@ -938,7 +945,7 @@ static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
 		goto out;
 	}
 
-	cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, fwrq->m);
+	cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
 	if (!cfp) {
 		goto out;
 	}
@@ -949,23 +956,71 @@ static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
 out:
 	if (ret == 0) {
 		set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		lbs_postpone_association_work(priv);
 	} else {
-		wlan_cancel_association_work(priv);
+		lbs_cancel_association_work(priv);
+	}
+	mutex_unlock(&priv->lock);
+
+	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+	return ret;
+}
+
+static int lbs_mesh_set_freq(struct net_device *dev,
+			     struct iw_request_info *info,
+			     struct iw_freq *fwrq, char *extra)
+{
+	struct lbs_private *priv = dev->priv;
+	struct chan_freq_power *cfp;
+	int ret = -EINVAL;
+
+	lbs_deb_enter(LBS_DEB_WEXT);
+
+	/* If setting by frequency, convert to a channel */
+	if (fwrq->e == 1) {
+		long f = fwrq->m / 100000;
+
+		cfp = find_cfp_by_band_and_freq(priv, 0, f);
+		if (!cfp) {
+			lbs_deb_wext("invalid freq %ld\n", f);
+			goto out;
+		}
+
+		fwrq->e = 0;
+		fwrq->m = (int) cfp->channel;
+	}
+
+	/* Setting by channel number */
+	if (fwrq->m > 1000 || fwrq->e > 0) {
+		goto out;
+	}
+
+	cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
+	if (!cfp) {
+		goto out;
+	}
+
+	if (fwrq->m != priv->curbssparams.channel) {
+		lbs_deb_wext("mesh channel change forces eth disconnect\n");
+		if (priv->mode == IW_MODE_INFRA)
+			lbs_send_deauthentication(priv);
+		else if (priv->mode == IW_MODE_ADHOC)
+			lbs_stop_adhoc_network(priv);
 	}
-	mutex_unlock(&adapter->lock);
+	lbs_mesh_config(priv, 1, fwrq->m);
+	lbs_update_channel(priv);
+	ret = 0;
 
+out:
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
 }
 
-static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
+static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
 		  struct iw_param *vwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
-	u32 new_rate;
-	u16 action;
+	struct lbs_private *priv = dev->priv;
+	u8 new_rate = 0;
 	int ret = -EINVAL;
 	u8 rates[MAX_RATES + 1];
 
@@ -974,15 +1029,14 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
 
 	/* Auto rate? */
 	if (vwrq->value == -1) {
-		action = CMD_ACT_SET_TX_AUTO;
-		adapter->auto_rate = 1;
-		adapter->cur_rate = 0;
+		priv->auto_rate = 1;
+		priv->cur_rate = 0;
 	} else {
 		if (vwrq->value % 100000)
 			goto out;
 
 		memset(rates, 0, sizeof(rates));
-		copy_active_data_rates(adapter, rates);
+		copy_active_data_rates(priv, rates);
 		new_rate = vwrq->value / 500000;
 		if (!memchr(rates, new_rate, sizeof(rates))) {
 			lbs_pr_alert("fixed data rate 0x%X out of range\n",
@@ -990,31 +1044,28 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
 			goto out;
 		}
 
-		adapter->cur_rate = new_rate;
-		action = CMD_ACT_SET_TX_FIX_RATE;
-		adapter->auto_rate = 0;
+		priv->cur_rate = new_rate;
+		priv->auto_rate = 0;
 	}
 
-	ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
-				    action, CMD_OPTION_WAITFORRSP, 0, NULL);
+	ret = lbs_set_data_rate(priv, new_rate);
 
 out:
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
 }
 
-static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
 		  struct iw_param *vwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (adapter->connect_status == LIBERTAS_CONNECTED) {
-		vwrq->value = adapter->cur_rate * 500000;
+	if (priv->connect_status == LBS_CONNECTED) {
+		vwrq->value = priv->cur_rate * 500000;
 
-		if (adapter->auto_rate)
+		if (priv->auto_rate)
 			vwrq->fixed = 0;
 		else
 			vwrq->fixed = 1;
@@ -1028,12 +1079,11 @@ static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
 	return 0;
 }
 
-static int wlan_set_mode(struct net_device *dev,
+static int lbs_set_mode(struct net_device *dev,
 		  struct iw_request_info *info, u32 * uwrq, char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	struct assoc_request * assoc_req;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
@@ -1046,18 +1096,18 @@ static int wlan_set_mode(struct net_device *dev,
 		goto out;
 	}
 
-	mutex_lock(&adapter->lock);
-	assoc_req = wlan_get_association_request(adapter);
+	mutex_lock(&priv->lock);
+	assoc_req = lbs_get_association_request(priv);
 	if (!assoc_req) {
 		ret = -ENOMEM;
-		wlan_cancel_association_work(priv);
+		lbs_cancel_association_work(priv);
 	} else {
 		assoc_req->mode = *uwrq;
 		set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		lbs_postpone_association_work(priv);
 		lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
 	}
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 
 out:
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -1074,23 +1124,22 @@ out:
  *  @param extra		A pointer to extra data buf
  *  @return 	   		0 --success, otherwise fail
  */
-static int wlan_get_encode(struct net_device *dev,
+static int lbs_get_encode(struct net_device *dev,
 			   struct iw_request_info *info,
 			   struct iw_point *dwrq, u8 * extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
-	       dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
+	       dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx);
 
 	dwrq->flags = 0;
 
 	/* Authentication method */
-	switch (adapter->secinfo.auth_mode) {
+	switch (priv->secinfo.auth_mode) {
 	case IW_AUTH_ALG_OPEN_SYSTEM:
 		dwrq->flags = IW_ENCODE_OPEN;
 		break;
@@ -1104,41 +1153,32 @@ static int wlan_get_encode(struct net_device *dev,
 		break;
 	}
 
-	if (   adapter->secinfo.wep_enabled
-	    || adapter->secinfo.WPAenabled
-	    || adapter->secinfo.WPA2enabled) {
-		dwrq->flags &= ~IW_ENCODE_DISABLED;
-	} else {
-		dwrq->flags |= IW_ENCODE_DISABLED;
-	}
-
 	memset(extra, 0, 16);
 
-	mutex_lock(&adapter->lock);
+	mutex_lock(&priv->lock);
 
 	/* Default to returning current transmit key */
 	if (index < 0)
-		index = adapter->wep_tx_keyidx;
+		index = priv->wep_tx_keyidx;
 
-	if ((adapter->wep_keys[index].len) && adapter->secinfo.wep_enabled) {
-		memcpy(extra, adapter->wep_keys[index].key,
-		       adapter->wep_keys[index].len);
-		dwrq->length = adapter->wep_keys[index].len;
+	if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) {
+		memcpy(extra, priv->wep_keys[index].key,
+		       priv->wep_keys[index].len);
+		dwrq->length = priv->wep_keys[index].len;
 
 		dwrq->flags |= (index + 1);
 		/* Return WEP enabled */
 		dwrq->flags &= ~IW_ENCODE_DISABLED;
-	} else if ((adapter->secinfo.WPAenabled)
-		   || (adapter->secinfo.WPA2enabled)) {
+	} else if ((priv->secinfo.WPAenabled)
+		   || (priv->secinfo.WPA2enabled)) {
 		/* return WPA enabled */
 		dwrq->flags &= ~IW_ENCODE_DISABLED;
+		dwrq->flags |= IW_ENCODE_NOKEY;
 	} else {
 		dwrq->flags |= IW_ENCODE_DISABLED;
 	}
 
-	mutex_unlock(&adapter->lock);
-
-	dwrq->flags |= IW_ENCODE_NOKEY;
+	mutex_unlock(&priv->lock);
 
 	lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
 	       extra[0], extra[1], extra[2],
@@ -1160,7 +1200,7 @@ static int wlan_get_encode(struct net_device *dev,
  *  @param set_tx_key		Force set TX key (1 = yes, 0 = no)
  *  @return 	   		0 --success, otherwise fail
  */
-static int wlan_set_wep_key(struct assoc_request *assoc_req,
+static int lbs_set_wep_key(struct assoc_request *assoc_req,
 			    const char *key_material,
 			    u16 key_length,
 			    u16 index,
@@ -1278,20 +1318,19 @@ static void disable_wpa(struct assoc_request *assoc_req)
  *  @param extra		A pointer to extra data buf
  *  @return 	   		0 --success, otherwise fail
  */
-static int wlan_set_encode(struct net_device *dev,
+static int lbs_set_encode(struct net_device *dev,
 		    struct iw_request_info *info,
 		    struct iw_point *dwrq, char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	struct assoc_request * assoc_req;
 	u16 is_default = 0, index = 0, set_tx_key = 0;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	mutex_lock(&adapter->lock);
-	assoc_req = wlan_get_association_request(adapter);
+	mutex_lock(&priv->lock);
+	assoc_req = lbs_get_association_request(priv);
 	if (!assoc_req) {
 		ret = -ENOMEM;
 		goto out;
@@ -1317,7 +1356,7 @@ static int wlan_set_encode(struct net_device *dev,
 	if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
 		set_tx_key = 1;
 
-	ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
+	ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
 	if (ret)
 		goto out;
 
@@ -1335,11 +1374,11 @@ static int wlan_set_encode(struct net_device *dev,
 out:
 	if (ret == 0) {
 		set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		lbs_postpone_association_work(priv);
 	} else {
-		wlan_cancel_association_work(priv);
+		lbs_cancel_association_work(priv);
 	}
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
@@ -1354,14 +1393,13 @@ out:
  *  @param extra		A pointer to extra data buf
  *  @return 	   		0 on success, otherwise failure
  */
-static int wlan_get_encodeext(struct net_device *dev,
+static int lbs_get_encodeext(struct net_device *dev,
 			      struct iw_request_info *info,
 			      struct iw_point *dwrq,
 			      char *extra)
 {
 	int ret = -EINVAL;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 	int index, max_key_len;
 
@@ -1377,46 +1415,46 @@ static int wlan_get_encodeext(struct net_device *dev,
 			goto out;
 		index--;
 	} else {
-		index = adapter->wep_tx_keyidx;
+		index = priv->wep_tx_keyidx;
 	}
 
-	if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
+	if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
 	    ext->alg != IW_ENCODE_ALG_WEP) {
-		if (index != 0 || adapter->mode != IW_MODE_INFRA)
+		if (index != 0 || priv->mode != IW_MODE_INFRA)
 			goto out;
 	}
 
 	dwrq->flags = index + 1;
 	memset(ext, 0, sizeof(*ext));
 
-	if (   !adapter->secinfo.wep_enabled
-	    && !adapter->secinfo.WPAenabled
-	    && !adapter->secinfo.WPA2enabled) {
+	if (   !priv->secinfo.wep_enabled
+	    && !priv->secinfo.WPAenabled
+	    && !priv->secinfo.WPA2enabled) {
 		ext->alg = IW_ENCODE_ALG_NONE;
 		ext->key_len = 0;
 		dwrq->flags |= IW_ENCODE_DISABLED;
 	} else {
 		u8 *key = NULL;
 
-		if (   adapter->secinfo.wep_enabled
-		    && !adapter->secinfo.WPAenabled
-		    && !adapter->secinfo.WPA2enabled) {
+		if (   priv->secinfo.wep_enabled
+		    && !priv->secinfo.WPAenabled
+		    && !priv->secinfo.WPA2enabled) {
 			/* WEP */
 			ext->alg = IW_ENCODE_ALG_WEP;
-			ext->key_len = adapter->wep_keys[index].len;
-			key = &adapter->wep_keys[index].key[0];
-		} else if (   !adapter->secinfo.wep_enabled
-		           && (adapter->secinfo.WPAenabled ||
-		               adapter->secinfo.WPA2enabled)) {
+			ext->key_len = priv->wep_keys[index].len;
+			key = &priv->wep_keys[index].key[0];
+		} else if (   !priv->secinfo.wep_enabled
+		           && (priv->secinfo.WPAenabled ||
+		               priv->secinfo.WPA2enabled)) {
 			/* WPA */
 			struct enc_key * pkey = NULL;
 
-			if (   adapter->wpa_mcast_key.len
-			    && (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
-				pkey = &adapter->wpa_mcast_key;
-			else if (   adapter->wpa_unicast_key.len
-			         && (adapter->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
-				pkey = &adapter->wpa_unicast_key;
+			if (   priv->wpa_mcast_key.len
+			    && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
+				pkey = &priv->wpa_mcast_key;
+			else if (   priv->wpa_unicast_key.len
+			         && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
+				pkey = &priv->wpa_unicast_key;
 
 			if (pkey) {
 				if (pkey->type == KEY_TYPE_ID_AES) {
@@ -1461,22 +1499,21 @@ out:
  *  @param extra		A pointer to extra data buf
  *  @return 	   		0 --success, otherwise fail
  */
-static int wlan_set_encodeext(struct net_device *dev,
+static int lbs_set_encodeext(struct net_device *dev,
 			      struct iw_request_info *info,
 			      struct iw_point *dwrq,
 			      char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
 	int alg = ext->alg;
 	struct assoc_request * assoc_req;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	mutex_lock(&adapter->lock);
-	assoc_req = wlan_get_association_request(adapter);
+	mutex_lock(&priv->lock);
+	assoc_req = lbs_get_association_request(priv);
 	if (!assoc_req) {
 		ret = -ENOMEM;
 		goto out;
@@ -1503,7 +1540,7 @@ static int wlan_set_encodeext(struct net_device *dev,
 			set_tx_key = 1;
 
 		/* Copy key to driver */
-		ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
+		ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index,
 					set_tx_key);
 		if (ret)
 			goto out;
@@ -1576,31 +1613,30 @@ static int wlan_set_encodeext(struct net_device *dev,
 
 out:
 	if (ret == 0) {
-		wlan_postpone_association_work(priv);
+		lbs_postpone_association_work(priv);
 	} else {
-		wlan_cancel_association_work(priv);
+		lbs_cancel_association_work(priv);
 	}
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
 }
 
 
-static int wlan_set_genie(struct net_device *dev,
+static int lbs_set_genie(struct net_device *dev,
 			  struct iw_request_info *info,
 			  struct iw_point *dwrq,
 			  char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	int ret = 0;
 	struct assoc_request * assoc_req;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	mutex_lock(&adapter->lock);
-	assoc_req = wlan_get_association_request(adapter);
+	mutex_lock(&priv->lock);
+	assoc_req = lbs_get_association_request(priv);
 	if (!assoc_req) {
 		ret = -ENOMEM;
 		goto out;
@@ -1616,46 +1652,45 @@ static int wlan_set_genie(struct net_device *dev,
 		memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
 		assoc_req->wpa_ie_len = dwrq->length;
 	} else {
-		memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
+		memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie));
 		assoc_req->wpa_ie_len = 0;
 	}
 
 out:
 	if (ret == 0) {
 		set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		lbs_postpone_association_work(priv);
 	} else {
-		wlan_cancel_association_work(priv);
+		lbs_cancel_association_work(priv);
 	}
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
 }
 
-static int wlan_get_genie(struct net_device *dev,
+static int lbs_get_genie(struct net_device *dev,
 			  struct iw_request_info *info,
 			  struct iw_point *dwrq,
 			  char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (adapter->wpa_ie_len == 0) {
+	if (priv->wpa_ie_len == 0) {
 		dwrq->length = 0;
 		goto out;
 	}
 
-	if (dwrq->length < adapter->wpa_ie_len) {
+	if (dwrq->length < priv->wpa_ie_len) {
 		ret = -E2BIG;
 		goto out;
 	}
 
-	dwrq->length = adapter->wpa_ie_len;
-	memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
+	dwrq->length = priv->wpa_ie_len;
+	memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len);
 
 out:
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -1663,21 +1698,20 @@ out:
 }
 
 
-static int wlan_set_auth(struct net_device *dev,
+static int lbs_set_auth(struct net_device *dev,
 			 struct iw_request_info *info,
 			 struct iw_param *dwrq,
 			 char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	struct assoc_request * assoc_req;
 	int ret = 0;
 	int updated = 0;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	mutex_lock(&adapter->lock);
-	assoc_req = wlan_get_association_request(adapter);
+	mutex_lock(&priv->lock);
+	assoc_req = lbs_get_association_request(priv);
 	if (!assoc_req) {
 		ret = -ENOMEM;
 		goto out;
@@ -1752,44 +1786,43 @@ out:
 	if (ret == 0) {
 		if (updated)
 			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		lbs_postpone_association_work(priv);
 	} else if (ret != -EOPNOTSUPP) {
-		wlan_cancel_association_work(priv);
+		lbs_cancel_association_work(priv);
 	}
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
 }
 
-static int wlan_get_auth(struct net_device *dev,
+static int lbs_get_auth(struct net_device *dev,
 			 struct iw_request_info *info,
 			 struct iw_param *dwrq,
 			 char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	switch (dwrq->flags & IW_AUTH_INDEX) {
 	case IW_AUTH_WPA_VERSION:
 		dwrq->value = 0;
-		if (adapter->secinfo.WPAenabled)
+		if (priv->secinfo.WPAenabled)
 			dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
-		if (adapter->secinfo.WPA2enabled)
+		if (priv->secinfo.WPA2enabled)
 			dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
 		if (!dwrq->value)
 			dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
 		break;
 
 	case IW_AUTH_80211_AUTH_ALG:
-		dwrq->value = adapter->secinfo.auth_mode;
+		dwrq->value = priv->secinfo.auth_mode;
 		break;
 
 	case IW_AUTH_WPA_ENABLED:
-		if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
+		if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled)
 			dwrq->value = 1;
 		break;
 
@@ -1802,25 +1835,24 @@ static int wlan_get_auth(struct net_device *dev,
 }
 
 
-static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
+static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
 		   struct iw_param *vwrq, char *extra)
 {
 	int ret = 0;
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	u16 dbm;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	if (vwrq->disabled) {
-		wlan_radio_ioctl(priv, RADIO_OFF);
+		lbs_radio_ioctl(priv, RADIO_OFF);
 		return 0;
 	}
 
-	adapter->preamble = CMD_TYPE_AUTO_PREAMBLE;
+	priv->preamble = CMD_TYPE_AUTO_PREAMBLE;
 
-	wlan_radio_ioctl(priv, RADIO_ON);
+	lbs_radio_ioctl(priv, RADIO_ON);
 
 	/* Userspace check in iwrange if it should use dBm or mW,
 	 * therefore this should never happen... Jean II */
@@ -1836,7 +1868,7 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
 
 	lbs_deb_wext("txpower set %d dbm\n", dbm);
 
-	ret = libertas_prepare_and_send_command(priv,
+	ret = lbs_prepare_and_send_command(priv,
 				    CMD_802_11_RF_TX_POWER,
 				    CMD_ACT_TX_POWER_OPT_SET_LOW,
 				    CMD_OPTION_WAITFORRSP, 0, (void *)&dbm);
@@ -1845,11 +1877,10 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
 	return ret;
 }
 
-static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
+static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
 		   struct iw_point *dwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -1861,19 +1892,19 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
 	/*
 	 * Get the current SSID
 	 */
-	if (adapter->connect_status == LIBERTAS_CONNECTED) {
-		memcpy(extra, adapter->curbssparams.ssid,
-		       adapter->curbssparams.ssid_len);
-		extra[adapter->curbssparams.ssid_len] = '\0';
+	if (priv->connect_status == LBS_CONNECTED) {
+		memcpy(extra, priv->curbssparams.ssid,
+		       priv->curbssparams.ssid_len);
+		extra[priv->curbssparams.ssid_len] = '\0';
 	} else {
 		memset(extra, 0, 32);
-		extra[adapter->curbssparams.ssid_len] = '\0';
+		extra[priv->curbssparams.ssid_len] = '\0';
 	}
 	/*
 	 * If none, we may want to get the one that was set
 	 */
 
-	dwrq->length = adapter->curbssparams.ssid_len;
+	dwrq->length = priv->curbssparams.ssid_len;
 
 	dwrq->flags = 1;	/* active */
 
@@ -1881,11 +1912,10 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
 	return 0;
 }
 
-static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
+static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
 		   struct iw_point *dwrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	int ret = 0;
 	u8 ssid[IW_ESSID_MAX_SIZE];
 	u8 ssid_len = 0;
@@ -1918,10 +1948,10 @@ static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
 	}
 
 out:
-	mutex_lock(&adapter->lock);
+	mutex_lock(&priv->lock);
 	if (ret == 0) {
 		/* Get or create the current association request */
-		assoc_req = wlan_get_association_request(adapter);
+		assoc_req = lbs_get_association_request(priv);
 		if (!assoc_req) {
 			ret = -ENOMEM;
 		} else {
@@ -1929,17 +1959,65 @@ out:
 			memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
 			assoc_req->ssid_len = ssid_len;
 			set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
-			wlan_postpone_association_work(priv);
+			lbs_postpone_association_work(priv);
 		}
 	}
 
 	/* Cancel the association request if there was an error */
 	if (ret != 0) {
-		wlan_cancel_association_work(priv);
+		lbs_cancel_association_work(priv);
+	}
+
+	mutex_unlock(&priv->lock);
+
+	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
+	return ret;
+}
+
+static int lbs_mesh_get_essid(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_point *dwrq, char *extra)
+{
+	struct lbs_private *priv = dev->priv;
+
+	lbs_deb_enter(LBS_DEB_WEXT);
+
+	memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len);
+
+	dwrq->length = priv->mesh_ssid_len;
+
+	dwrq->flags = 1;	/* active */
+
+	lbs_deb_leave(LBS_DEB_WEXT);
+	return 0;
+}
+
+static int lbs_mesh_set_essid(struct net_device *dev,
+			      struct iw_request_info *info,
+			      struct iw_point *dwrq, char *extra)
+{
+	struct lbs_private *priv = dev->priv;
+	int ret = 0;
+
+	lbs_deb_enter(LBS_DEB_WEXT);
+
+	/* Check the size of the string */
+	if (dwrq->length > IW_ESSID_MAX_SIZE) {
+		ret = -E2BIG;
+		goto out;
 	}
 
-	mutex_unlock(&adapter->lock);
+	if (!dwrq->flags || !dwrq->length) {
+		ret = -EINVAL;
+		goto out;
+	} else {
+		/* Specific SSID requested */
+		memcpy(priv->mesh_ssid, extra, dwrq->length);
+		priv->mesh_ssid_len = dwrq->length;
+	}
 
+	lbs_mesh_config(priv, 1, priv->curbssparams.channel);
+ out:
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
 }
@@ -1953,11 +2031,10 @@ out:
  *  @param extra        A pointer to extra data buf
  *  @return             0 --success, otherwise fail
  */
-static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
+static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
 		 struct sockaddr *awrq, char *extra)
 {
-	wlan_private *priv = dev->priv;
-	wlan_adapter *adapter = priv->adapter;
+	struct lbs_private *priv = dev->priv;
 	struct assoc_request * assoc_req;
 	int ret = 0;
 	DECLARE_MAC_BUF(mac);
@@ -1969,44 +2046,38 @@ static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
 
 	lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data));
 
-	mutex_lock(&adapter->lock);
+	mutex_lock(&priv->lock);
 
 	/* Get or create the current association request */
-	assoc_req = wlan_get_association_request(adapter);
+	assoc_req = lbs_get_association_request(priv);
 	if (!assoc_req) {
-		wlan_cancel_association_work(priv);
+		lbs_cancel_association_work(priv);
 		ret = -ENOMEM;
 	} else {
 		/* Copy the BSSID to the association request */
 		memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
 		set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		lbs_postpone_association_work(priv);
 	}
 
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 
 	return ret;
 }
 
-void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
+void lbs_get_fwversion(struct lbs_private *priv, char *fwversion, int maxlen)
 {
 	char fwver[32];
 
-	mutex_lock(&adapter->lock);
+	mutex_lock(&priv->lock);
 
-	if (adapter->fwreleasenumber[3] == 0)
-		sprintf(fwver, "%u.%u.%u",
-			adapter->fwreleasenumber[2],
-			adapter->fwreleasenumber[1],
-			adapter->fwreleasenumber[0]);
-	else
-		sprintf(fwver, "%u.%u.%u.p%u",
-			adapter->fwreleasenumber[2],
-			adapter->fwreleasenumber[1],
-			adapter->fwreleasenumber[0],
-			adapter->fwreleasenumber[3]);
+	sprintf(fwver, "%u.%u.%u.p%u",
+		priv->fwrelease >> 24 & 0xff,
+		priv->fwrelease >> 16 & 0xff,
+		priv->fwrelease >>  8 & 0xff,
+		priv->fwrelease       & 0xff);
 
-	mutex_unlock(&adapter->lock);
+	mutex_unlock(&priv->lock);
 	snprintf(fwversion, maxlen, fwver);
 }
 
@@ -2014,19 +2085,19 @@ void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
 /*
  * iwconfig settable callbacks
  */
-static const iw_handler wlan_handler[] = {
+static const iw_handler lbs_handler[] = {
 	(iw_handler) NULL,	/* SIOCSIWCOMMIT */
-	(iw_handler) wlan_get_name,	/* SIOCGIWNAME */
+	(iw_handler) lbs_get_name,	/* SIOCGIWNAME */
 	(iw_handler) NULL,	/* SIOCSIWNWID */
 	(iw_handler) NULL,	/* SIOCGIWNWID */
-	(iw_handler) wlan_set_freq,	/* SIOCSIWFREQ */
-	(iw_handler) wlan_get_freq,	/* SIOCGIWFREQ */
-	(iw_handler) wlan_set_mode,	/* SIOCSIWMODE */
-	(iw_handler) wlan_get_mode,	/* SIOCGIWMODE */
+	(iw_handler) lbs_set_freq,	/* SIOCSIWFREQ */
+	(iw_handler) lbs_get_freq,	/* SIOCGIWFREQ */
+	(iw_handler) lbs_set_mode,	/* SIOCSIWMODE */
+	(iw_handler) lbs_get_mode,	/* SIOCGIWMODE */
 	(iw_handler) NULL,	/* SIOCSIWSENS */
 	(iw_handler) NULL,	/* SIOCGIWSENS */
 	(iw_handler) NULL,	/* SIOCSIWRANGE */
-	(iw_handler) wlan_get_range,	/* SIOCGIWRANGE */
+	(iw_handler) lbs_get_range,	/* SIOCGIWRANGE */
 	(iw_handler) NULL,	/* SIOCSIWPRIV */
 	(iw_handler) NULL,	/* SIOCGIWPRIV */
 	(iw_handler) NULL,	/* SIOCSIWSTATS */
@@ -2035,56 +2106,56 @@ static const iw_handler wlan_handler[] = {
 	iw_handler_get_spy,	/* SIOCGIWSPY */
 	iw_handler_set_thrspy,	/* SIOCSIWTHRSPY */
 	iw_handler_get_thrspy,	/* SIOCGIWTHRSPY */
-	(iw_handler) wlan_set_wap,	/* SIOCSIWAP */
-	(iw_handler) wlan_get_wap,	/* SIOCGIWAP */
+	(iw_handler) lbs_set_wap,	/* SIOCSIWAP */
+	(iw_handler) lbs_get_wap,	/* SIOCGIWAP */
 	(iw_handler) NULL,	/* SIOCSIWMLME */
 	(iw_handler) NULL,	/* SIOCGIWAPLIST - deprecated */
-	(iw_handler) libertas_set_scan,	/* SIOCSIWSCAN */
-	(iw_handler) libertas_get_scan,	/* SIOCGIWSCAN */
-	(iw_handler) wlan_set_essid,	/* SIOCSIWESSID */
-	(iw_handler) wlan_get_essid,	/* SIOCGIWESSID */
-	(iw_handler) wlan_set_nick,	/* SIOCSIWNICKN */
-	(iw_handler) wlan_get_nick,	/* SIOCGIWNICKN */
+	(iw_handler) lbs_set_scan,	/* SIOCSIWSCAN */
+	(iw_handler) lbs_get_scan,	/* SIOCGIWSCAN */
+	(iw_handler) lbs_set_essid,	/* SIOCSIWESSID */
+	(iw_handler) lbs_get_essid,	/* SIOCGIWESSID */
+	(iw_handler) lbs_set_nick,	/* SIOCSIWNICKN */
+	(iw_handler) lbs_get_nick,	/* SIOCGIWNICKN */
 	(iw_handler) NULL,	/* -- hole -- */
 	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) wlan_set_rate,	/* SIOCSIWRATE */
-	(iw_handler) wlan_get_rate,	/* SIOCGIWRATE */
-	(iw_handler) wlan_set_rts,	/* SIOCSIWRTS */
-	(iw_handler) wlan_get_rts,	/* SIOCGIWRTS */
-	(iw_handler) wlan_set_frag,	/* SIOCSIWFRAG */
-	(iw_handler) wlan_get_frag,	/* SIOCGIWFRAG */
-	(iw_handler) wlan_set_txpow,	/* SIOCSIWTXPOW */
-	(iw_handler) wlan_get_txpow,	/* SIOCGIWTXPOW */
-	(iw_handler) wlan_set_retry,	/* SIOCSIWRETRY */
-	(iw_handler) wlan_get_retry,	/* SIOCGIWRETRY */
-	(iw_handler) wlan_set_encode,	/* SIOCSIWENCODE */
-	(iw_handler) wlan_get_encode,	/* SIOCGIWENCODE */
-	(iw_handler) wlan_set_power,	/* SIOCSIWPOWER */
-	(iw_handler) wlan_get_power,	/* SIOCGIWPOWER */
+	(iw_handler) lbs_set_rate,	/* SIOCSIWRATE */
+	(iw_handler) lbs_get_rate,	/* SIOCGIWRATE */
+	(iw_handler) lbs_set_rts,	/* SIOCSIWRTS */
+	(iw_handler) lbs_get_rts,	/* SIOCGIWRTS */
+	(iw_handler) lbs_set_frag,	/* SIOCSIWFRAG */
+	(iw_handler) lbs_get_frag,	/* SIOCGIWFRAG */
+	(iw_handler) lbs_set_txpow,	/* SIOCSIWTXPOW */
+	(iw_handler) lbs_get_txpow,	/* SIOCGIWTXPOW */
+	(iw_handler) lbs_set_retry,	/* SIOCSIWRETRY */
+	(iw_handler) lbs_get_retry,	/* SIOCGIWRETRY */
+	(iw_handler) lbs_set_encode,	/* SIOCSIWENCODE */
+	(iw_handler) lbs_get_encode,	/* SIOCGIWENCODE */
+	(iw_handler) lbs_set_power,	/* SIOCSIWPOWER */
+	(iw_handler) lbs_get_power,	/* SIOCGIWPOWER */
 	(iw_handler) NULL,	/* -- hole -- */
 	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) wlan_set_genie,	/* SIOCSIWGENIE */
-	(iw_handler) wlan_get_genie,	/* SIOCGIWGENIE */
-	(iw_handler) wlan_set_auth,	/* SIOCSIWAUTH */
-	(iw_handler) wlan_get_auth,	/* SIOCGIWAUTH */
-	(iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
-	(iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
+	(iw_handler) lbs_set_genie,	/* SIOCSIWGENIE */
+	(iw_handler) lbs_get_genie,	/* SIOCGIWGENIE */
+	(iw_handler) lbs_set_auth,	/* SIOCSIWAUTH */
+	(iw_handler) lbs_get_auth,	/* SIOCGIWAUTH */
+	(iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
+	(iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
 	(iw_handler) NULL,		/* SIOCSIWPMKSA */
 };
 
 static const iw_handler mesh_wlan_handler[] = {
 	(iw_handler) NULL,	/* SIOCSIWCOMMIT */
-	(iw_handler) wlan_get_name,	/* SIOCGIWNAME */
+	(iw_handler) lbs_get_name,	/* SIOCGIWNAME */
 	(iw_handler) NULL,	/* SIOCSIWNWID */
 	(iw_handler) NULL,	/* SIOCGIWNWID */
-	(iw_handler) wlan_set_freq,	/* SIOCSIWFREQ */
-	(iw_handler) wlan_get_freq,	/* SIOCGIWFREQ */
+	(iw_handler) lbs_mesh_set_freq,	/* SIOCSIWFREQ */
+	(iw_handler) lbs_get_freq,	/* SIOCGIWFREQ */
 	(iw_handler) NULL,		/* SIOCSIWMODE */
 	(iw_handler) mesh_wlan_get_mode,	/* SIOCGIWMODE */
 	(iw_handler) NULL,	/* SIOCSIWSENS */
 	(iw_handler) NULL,	/* SIOCGIWSENS */
 	(iw_handler) NULL,	/* SIOCSIWRANGE */
-	(iw_handler) wlan_get_range,	/* SIOCGIWRANGE */
+	(iw_handler) lbs_get_range,	/* SIOCGIWRANGE */
 	(iw_handler) NULL,	/* SIOCSIWPRIV */
 	(iw_handler) NULL,	/* SIOCGIWPRIV */
 	(iw_handler) NULL,	/* SIOCSIWSTATS */
@@ -2097,46 +2168,46 @@ static const iw_handler mesh_wlan_handler[] = {
 	(iw_handler) NULL,	/* SIOCGIWAP */
 	(iw_handler) NULL,	/* SIOCSIWMLME */
 	(iw_handler) NULL,	/* SIOCGIWAPLIST - deprecated */
-	(iw_handler) libertas_set_scan,	/* SIOCSIWSCAN */
-	(iw_handler) libertas_get_scan,	/* SIOCGIWSCAN */
-	(iw_handler) NULL,		/* SIOCSIWESSID */
-	(iw_handler) NULL,		/* SIOCGIWESSID */
+	(iw_handler) lbs_set_scan,	/* SIOCSIWSCAN */
+	(iw_handler) lbs_get_scan,	/* SIOCGIWSCAN */
+	(iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */
+	(iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */
 	(iw_handler) NULL,		/* SIOCSIWNICKN */
 	(iw_handler) mesh_get_nick,	/* SIOCGIWNICKN */
 	(iw_handler) NULL,	/* -- hole -- */
 	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) wlan_set_rate,	/* SIOCSIWRATE */
-	(iw_handler) wlan_get_rate,	/* SIOCGIWRATE */
-	(iw_handler) wlan_set_rts,	/* SIOCSIWRTS */
-	(iw_handler) wlan_get_rts,	/* SIOCGIWRTS */
-	(iw_handler) wlan_set_frag,	/* SIOCSIWFRAG */
-	(iw_handler) wlan_get_frag,	/* SIOCGIWFRAG */
-	(iw_handler) wlan_set_txpow,	/* SIOCSIWTXPOW */
-	(iw_handler) wlan_get_txpow,	/* SIOCGIWTXPOW */
-	(iw_handler) wlan_set_retry,	/* SIOCSIWRETRY */
-	(iw_handler) wlan_get_retry,	/* SIOCGIWRETRY */
-	(iw_handler) wlan_set_encode,	/* SIOCSIWENCODE */
-	(iw_handler) wlan_get_encode,	/* SIOCGIWENCODE */
-	(iw_handler) wlan_set_power,	/* SIOCSIWPOWER */
-	(iw_handler) wlan_get_power,	/* SIOCGIWPOWER */
+	(iw_handler) lbs_set_rate,	/* SIOCSIWRATE */
+	(iw_handler) lbs_get_rate,	/* SIOCGIWRATE */
+	(iw_handler) lbs_set_rts,	/* SIOCSIWRTS */
+	(iw_handler) lbs_get_rts,	/* SIOCGIWRTS */
+	(iw_handler) lbs_set_frag,	/* SIOCSIWFRAG */
+	(iw_handler) lbs_get_frag,	/* SIOCGIWFRAG */
+	(iw_handler) lbs_set_txpow,	/* SIOCSIWTXPOW */
+	(iw_handler) lbs_get_txpow,	/* SIOCGIWTXPOW */
+	(iw_handler) lbs_set_retry,	/* SIOCSIWRETRY */
+	(iw_handler) lbs_get_retry,	/* SIOCGIWRETRY */
+	(iw_handler) lbs_set_encode,	/* SIOCSIWENCODE */
+	(iw_handler) lbs_get_encode,	/* SIOCGIWENCODE */
+	(iw_handler) lbs_set_power,	/* SIOCSIWPOWER */
+	(iw_handler) lbs_get_power,	/* SIOCGIWPOWER */
 	(iw_handler) NULL,	/* -- hole -- */
 	(iw_handler) NULL,	/* -- hole -- */
-	(iw_handler) wlan_set_genie,	/* SIOCSIWGENIE */
-	(iw_handler) wlan_get_genie,	/* SIOCGIWGENIE */
-	(iw_handler) wlan_set_auth,	/* SIOCSIWAUTH */
-	(iw_handler) wlan_get_auth,	/* SIOCGIWAUTH */
-	(iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
-	(iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
+	(iw_handler) lbs_set_genie,	/* SIOCSIWGENIE */
+	(iw_handler) lbs_get_genie,	/* SIOCGIWGENIE */
+	(iw_handler) lbs_set_auth,	/* SIOCSIWAUTH */
+	(iw_handler) lbs_get_auth,	/* SIOCGIWAUTH */
+	(iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
+	(iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
 	(iw_handler) NULL,		/* SIOCSIWPMKSA */
 };
-struct iw_handler_def libertas_handler_def = {
-	.num_standard	= ARRAY_SIZE(wlan_handler),
-	.standard	= (iw_handler *) wlan_handler,
-	.get_wireless_stats = wlan_get_wireless_stats,
+struct iw_handler_def lbs_handler_def = {
+	.num_standard	= ARRAY_SIZE(lbs_handler),
+	.standard	= (iw_handler *) lbs_handler,
+	.get_wireless_stats = lbs_get_wireless_stats,
 };
 
 struct iw_handler_def mesh_handler_def = {
 	.num_standard	= ARRAY_SIZE(mesh_wlan_handler),
 	.standard	= (iw_handler *) mesh_wlan_handler,
-	.get_wireless_stats = wlan_get_wireless_stats,
+	.get_wireless_stats = lbs_get_wireless_stats,
 };
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
index 6aa444c7de8d..a563d9a231b6 100644
--- a/drivers/net/wireless/libertas/wext.h
+++ b/drivers/net/wireless/libertas/wext.h
@@ -1,11 +1,11 @@
 /**
   * This file contains definition for IOCTL call.
   */
-#ifndef	_WLAN_WEXT_H_
-#define	_WLAN_WEXT_H_
+#ifndef	_LBS_WEXT_H_
+#define	_LBS_WEXT_H_
 
-/** wlan_ioctl_regrdwr */
-struct wlan_ioctl_regrdwr {
+/** lbs_ioctl_regrdwr */
+struct lbs_ioctl_regrdwr {
 	/** Which register to access */
 	u16 whichreg;
 	/** Read or Write */
@@ -15,9 +15,9 @@ struct wlan_ioctl_regrdwr {
 	u32 value;
 };
 
-#define WLAN_MONITOR_OFF			0
+#define LBS_MONITOR_OFF			0
 
-extern struct iw_handler_def libertas_handler_def;
+extern struct iw_handler_def lbs_handler_def;
 extern struct iw_handler_def mesh_handler_def;
 
-#endif				/* _WLAN_WEXT_H_ */
+#endif
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index ca6c2da7bc5d..6d13a0d15a0c 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -270,6 +270,37 @@ static inline void set_port_type(struct orinoco_private *priv)
 	}
 }
 
+#define ORINOCO_MAX_BSS_COUNT	64
+static int orinoco_bss_data_allocate(struct orinoco_private *priv)
+{
+	if (priv->bss_data)
+		return 0;
+
+	priv->bss_data =
+	    kzalloc(ORINOCO_MAX_BSS_COUNT * sizeof(bss_element), GFP_KERNEL);
+	if (!priv->bss_data) {
+		printk(KERN_WARNING "Out of memory allocating beacons");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static void orinoco_bss_data_free(struct orinoco_private *priv)
+{
+	kfree(priv->bss_data);
+	priv->bss_data = NULL;
+}
+
+static void orinoco_bss_data_init(struct orinoco_private *priv)
+{
+	int i;
+
+	INIT_LIST_HEAD(&priv->bss_free_list);
+	INIT_LIST_HEAD(&priv->bss_list);
+	for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
+		list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list);
+}
+
 /********************************************************************/
 /* Device methods                                                   */
 /********************************************************************/
@@ -1083,6 +1114,124 @@ static void orinoco_send_wevents(struct work_struct *work)
 	orinoco_unlock(priv, &flags);
 }
 
+
+static inline void orinoco_clear_scan_results(struct orinoco_private *priv,
+					      unsigned long scan_age)
+{
+	bss_element *bss;
+	bss_element *tmp_bss;
+
+	/* Blow away current list of scan results */
+	list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
+		if (!scan_age ||
+		    time_after(jiffies, bss->last_scanned + scan_age)) {
+			list_move_tail(&bss->list, &priv->bss_free_list);
+			/* Don't blow away ->list, just BSS data */
+			memset(bss, 0, sizeof(bss->bss));
+			bss->last_scanned = 0;
+		}
+	}
+}
+
+static int orinoco_process_scan_results(struct net_device *dev,
+					unsigned char *buf,
+					int len)
+{
+	struct orinoco_private *priv = netdev_priv(dev);
+	int			offset;		/* In the scan data */
+	union hermes_scan_info *atom;
+	int			atom_len;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_AGERE:
+		atom_len = sizeof(struct agere_scan_apinfo);
+		offset = 0;
+		break;
+	case FIRMWARE_TYPE_SYMBOL:
+		/* Lack of documentation necessitates this hack.
+		 * Different firmwares have 68 or 76 byte long atoms.
+		 * We try modulo first.  If the length divides by both,
+		 * we check what would be the channel in the second
+		 * frame for a 68-byte atom.  76-byte atoms have 0 there.
+		 * Valid channel cannot be 0.  */
+		if (len % 76)
+			atom_len = 68;
+		else if (len % 68)
+			atom_len = 76;
+		else if (len >= 1292 && buf[68] == 0)
+			atom_len = 76;
+		else
+			atom_len = 68;
+		offset = 0;
+		break;
+	case FIRMWARE_TYPE_INTERSIL:
+		offset = 4;
+		if (priv->has_hostscan) {
+			atom_len = le16_to_cpup((__le16 *)buf);
+			/* Sanity check for atom_len */
+			if (atom_len < sizeof(struct prism2_scan_apinfo)) {
+				printk(KERN_ERR "%s: Invalid atom_len in scan "
+				       "data: %d\n", dev->name, atom_len);
+				return -EIO;
+			}
+		} else
+			atom_len = offsetof(struct prism2_scan_apinfo, atim);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	/* Check that we got an whole number of atoms */
+	if ((len - offset) % atom_len) {
+		printk(KERN_ERR "%s: Unexpected scan data length %d, "
+		       "atom_len %d, offset %d\n", dev->name, len,
+		       atom_len, offset);
+		return -EIO;
+	}
+
+	orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
+
+	/* Read the entries one by one */
+	for (; offset + atom_len <= len; offset += atom_len) {
+		int found = 0;
+		bss_element *bss = NULL;
+
+		/* Get next atom */
+		atom = (union hermes_scan_info *) (buf + offset);
+
+		/* Try to update an existing bss first */
+		list_for_each_entry(bss, &priv->bss_list, list) {
+			if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
+				continue;
+			if (le16_to_cpu(bss->bss.a.essid_len) !=
+			      le16_to_cpu(atom->a.essid_len))
+				continue;
+			if (memcmp(bss->bss.a.essid, atom->a.essid,
+			      le16_to_cpu(atom->a.essid_len)))
+				continue;
+			found = 1;
+			break;
+		}
+
+		/* Grab a bss off the free list */
+		if (!found && !list_empty(&priv->bss_free_list)) {
+			bss = list_entry(priv->bss_free_list.next,
+					 bss_element, list);
+			list_del(priv->bss_free_list.next);
+
+			list_add_tail(&bss->list, &priv->bss_list);
+		}
+
+		if (bss) {
+			/* Always update the BSS to get latest beacon info */
+			memcpy(&bss->bss, atom, sizeof(bss->bss));
+			bss->last_scanned = jiffies;
+		}
+	}
+
+	return 0;
+}
+
 static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
@@ -1208,6 +1357,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 		union iwreq_data	wrqu;
 		unsigned char *buf;
 
+		/* Scan is no longer in progress */
+		priv->scan_inprogress = 0;
+
 		/* Sanity check */
 		if (len > 4096) {
 			printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
@@ -1215,15 +1367,6 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 			break;
 		}
 
-		/* We are a strict producer. If the previous scan results
-		 * have not been consumed, we just have to drop this
-		 * frame. We can't remove the previous results ourselves,
-		 * that would be *very* racy... Jean II */
-		if (priv->scan_result != NULL) {
-			printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
-			break;
-		}
-
 		/* Allocate buffer for results */
 		buf = kmalloc(len, GFP_ATOMIC);
 		if (buf == NULL)
@@ -1248,18 +1391,17 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 		}
 #endif	/* ORINOCO_DEBUG */
 
-		/* Allow the clients to access the results */
-		priv->scan_len = len;
-		priv->scan_result = buf;
-
-		/* Send an empty event to user space.
-		 * We don't send the received data on the event because
-		 * it would require us to do complex transcoding, and
-		 * we want to minimise the work done in the irq handler
-		 * Use a request to extract the data - Jean II */
-		wrqu.data.length = 0;
-		wrqu.data.flags = 0;
-		wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+		if (orinoco_process_scan_results(dev, buf, len) == 0) {
+			/* Send an empty event to user space.
+			 * We don't send the received data on the event because
+			 * it would require us to do complex transcoding, and
+			 * we want to minimise the work done in the irq handler
+			 * Use a request to extract the data - Jean II */
+			wrqu.data.length = 0;
+			wrqu.data.flags = 0;
+			wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+		}
+		kfree(buf);
 	}
 	break;
 	case HERMES_INQ_SEC_STAT_AGERE:
@@ -1896,8 +2038,7 @@ static void orinoco_reset(struct work_struct *work)
 	orinoco_unlock(priv, &flags);
 
  	/* Scanning support: Cleanup of driver struct */
-	kfree(priv->scan_result);
-	priv->scan_result = NULL;
+	orinoco_clear_scan_results(priv, 0);
 	priv->scan_inprogress = 0;
 
 	if (priv->hard_reset) {
@@ -2412,6 +2553,10 @@ struct net_device *alloc_orinocodev(int sizeof_card,
 	else
 		priv->card = NULL;
 
+	if (orinoco_bss_data_allocate(priv))
+		goto err_out_free;
+	orinoco_bss_data_init(priv);
+
 	/* Setup / override net_device fields */
 	dev->init = orinoco_init;
 	dev->hard_start_xmit = orinoco_xmit;
@@ -2447,13 +2592,16 @@ struct net_device *alloc_orinocodev(int sizeof_card,
 
 	return dev;
 
+err_out_free:
+	free_netdev(dev);
+	return NULL;
 }
 
 void free_orinocodev(struct net_device *dev)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
 
-	kfree(priv->scan_result);
+	orinoco_bss_data_free(priv);
 	free_netdev(dev);
 }
 
@@ -3841,23 +3989,10 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
 	 * we access scan variables in priv is critical.
 	 *	o scan_inprogress : not touched by irq handler
 	 *	o scan_mode : not touched by irq handler
-	 *	o scan_result : irq is strict producer, non-irq is strict
-	 *		consumer.
 	 *	o scan_len : synchronised with scan_result
 	 * Before modifying anything on those variables, please think hard !
 	 * Jean II */
 
-	/* If there is still some left-over scan results, get rid of it */
-	if (priv->scan_result != NULL) {
-		/* What's likely is that a client did crash or was killed
-		 * between triggering the scan request and reading the
-		 * results, so we need to reset everything.
-		 * Some clients that are too slow may suffer from that...
-		 * Jean II */
-		kfree(priv->scan_result);
-		priv->scan_result = NULL;
-	}
-
 	/* Save flags */
 	priv->scan_mode = srq->flags;
 
@@ -3905,169 +4040,125 @@ static int orinoco_ioctl_setscan(struct net_device *dev,
 	return err;
 }
 
+#define MAX_CUSTOM_LEN 64
+
 /* Translate scan data returned from the card to a card independant
  * format that the Wireless Tools will understand - Jean II
  * Return message length or -errno for fatal errors */
-static inline int orinoco_translate_scan(struct net_device *dev,
-					 char *buffer,
-					 char *scan,
-					 int scan_len)
+static inline char *orinoco_translate_scan(struct net_device *dev,
+					   char *current_ev,
+					   char *end_buf,
+					   union hermes_scan_info *bss,
+					   unsigned int last_scanned)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
-	int			offset;		/* In the scan data */
-	union hermes_scan_info *atom;
-	int			atom_len;
 	u16			capabilities;
 	u16			channel;
 	struct iw_event		iwe;		/* Temporary buffer */
-	char *			current_ev = buffer;
-	char *			end_buf = buffer + IW_SCAN_MAX_DATA;
-
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_AGERE:
-		atom_len = sizeof(struct agere_scan_apinfo);
- 		offset = 0;
-		break;
-	case FIRMWARE_TYPE_SYMBOL:
-		/* Lack of documentation necessitates this hack.
-		 * Different firmwares have 68 or 76 byte long atoms.
-		 * We try modulo first.  If the length divides by both,
-		 * we check what would be the channel in the second
-		 * frame for a 68-byte atom.  76-byte atoms have 0 there.
-		 * Valid channel cannot be 0.  */
-		if (scan_len % 76)
-			atom_len = 68;
-		else if (scan_len % 68)
-			atom_len = 76;
-		else if (scan_len >= 1292 && scan[68] == 0)
-			atom_len = 76;
+	char                   *p;
+	char custom[MAX_CUSTOM_LEN];
+
+	/* First entry *MUST* be the AP MAC address */
+	iwe.cmd = SIOCGIWAP;
+	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+	memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+	/* Other entries will be displayed in the order we give them */
+
+	/* Add the ESSID */
+	iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
+	if (iwe.u.data.length > 32)
+		iwe.u.data.length = 32;
+	iwe.cmd = SIOCGIWESSID;
+	iwe.u.data.flags = 1;
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
+
+	/* Add mode */
+	iwe.cmd = SIOCGIWMODE;
+	capabilities = le16_to_cpu(bss->a.capabilities);
+	if (capabilities & 0x3) {
+		if (capabilities & 0x1)
+			iwe.u.mode = IW_MODE_MASTER;
 		else
-			atom_len = 68;
-		offset = 0;
-		break;
-	case FIRMWARE_TYPE_INTERSIL:
-		offset = 4;
-		if (priv->has_hostscan) {
-			atom_len = le16_to_cpup((__le16 *)scan);
-			/* Sanity check for atom_len */
-			if (atom_len < sizeof(struct prism2_scan_apinfo)) {
-				printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n",
-				dev->name, atom_len);
-				return -EIO;
-			}
-		} else
-			atom_len = offsetof(struct prism2_scan_apinfo, atim);
-		break;
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	/* Check that we got an whole number of atoms */
-	if ((scan_len - offset) % atom_len) {
-		printk(KERN_ERR "%s: Unexpected scan data length %d, "
-		       "atom_len %d, offset %d\n", dev->name, scan_len,
-		       atom_len, offset);
-		return -EIO;
-	}
-
-	/* Read the entries one by one */
-	for (; offset + atom_len <= scan_len; offset += atom_len) {
-		/* Get next atom */
-		atom = (union hermes_scan_info *) (scan + offset);
-
-		/* First entry *MUST* be the AP MAC address */
-		iwe.cmd = SIOCGIWAP;
-		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
-		memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN);
-		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
-
-		/* Other entries will be displayed in the order we give them */
-
-		/* Add the ESSID */
-		iwe.u.data.length = le16_to_cpu(atom->a.essid_len);
-		if (iwe.u.data.length > 32)
-			iwe.u.data.length = 32;
-		iwe.cmd = SIOCGIWESSID;
-		iwe.u.data.flags = 1;
-		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
-
-		/* Add mode */
-		iwe.cmd = SIOCGIWMODE;
-		capabilities = le16_to_cpu(atom->a.capabilities);
-		if (capabilities & 0x3) {
-			if (capabilities & 0x1)
-				iwe.u.mode = IW_MODE_MASTER;
-			else
-				iwe.u.mode = IW_MODE_ADHOC;
-			current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
-		}
-
-		channel = atom->s.channel;
-		if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) {
-			/* Add frequency */
-			iwe.cmd = SIOCGIWFREQ;
-			iwe.u.freq.m = channel_frequency[channel-1] * 100000;
-			iwe.u.freq.e = 1;
-			current_ev = iwe_stream_add_event(current_ev, end_buf,
-							  &iwe, IW_EV_FREQ_LEN);
-		}
+			iwe.u.mode = IW_MODE_ADHOC;
+		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+	}
+
+	channel = bss->s.channel;
+	if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
+		/* Add frequency */
+		iwe.cmd = SIOCGIWFREQ;
+		iwe.u.freq.m = channel_frequency[channel-1] * 100000;
+		iwe.u.freq.e = 1;
+		current_ev = iwe_stream_add_event(current_ev, end_buf,
+						  &iwe, IW_EV_FREQ_LEN);
+	}
+
+	/* Add quality statistics */
+	iwe.cmd = IWEVQUAL;
+	iwe.u.qual.updated = 0x10;	/* no link quality */
+	iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
+	iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
+	/* Wireless tools prior to 27.pre22 will show link quality
+	 * anyway, so we provide a reasonable value. */
+	if (iwe.u.qual.level > iwe.u.qual.noise)
+		iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+	else
+		iwe.u.qual.qual = 0;
+	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
 
-		/* Add quality statistics */
-		iwe.cmd = IWEVQUAL;
-		iwe.u.qual.updated = 0x10;	/* no link quality */
-		iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95;
-		iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95;
-		/* Wireless tools prior to 27.pre22 will show link quality
-		 * anyway, so we provide a reasonable value. */
-		if (iwe.u.qual.level > iwe.u.qual.noise)
-			iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
-		else
-			iwe.u.qual.qual = 0;
-		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+	/* Add encryption capability */
+	iwe.cmd = SIOCGIWENCODE;
+	if (capabilities & 0x10)
+		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+	else
+		iwe.u.data.flags = IW_ENCODE_DISABLED;
+	iwe.u.data.length = 0;
+	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid);
+
+	/* Add EXTRA: Age to display seconds since last beacon/probe response
+	 * for given network. */
+	iwe.cmd = IWEVCUSTOM;
+	p = custom;
+	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+		      " Last beacon: %dms ago",
+		      jiffies_to_msecs(jiffies - last_scanned));
+	iwe.u.data.length = p - custom;
+	if (iwe.u.data.length)
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom);
+
+	/* Bit rate is not available in Lucent/Agere firmwares */
+	if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
+		char *current_val = current_ev + IW_EV_LCP_LEN;
+		int i;
+		int step;
 
-		/* Add encryption capability */
-		iwe.cmd = SIOCGIWENCODE;
-		if (capabilities & 0x10)
-			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+		if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+			step = 2;
 		else
-			iwe.u.data.flags = IW_ENCODE_DISABLED;
-		iwe.u.data.length = 0;
-		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
-
-		/* Bit rate is not available in Lucent/Agere firmwares */
-		if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
-			char *	current_val = current_ev + IW_EV_LCP_LEN;
-			int	i;
-			int	step;
-
-			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
-				step = 2;
-			else
-				step = 1;
-
-			iwe.cmd = SIOCGIWRATE;
-			/* Those two flags are ignored... */
-			iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-			/* Max 10 values */
-			for (i = 0; i < 10; i += step) {
-				/* NULL terminated */
-				if (atom->p.rates[i] == 0x0)
-					break;
-				/* Bit rate given in 500 kb/s units (+ 0x80) */
-				iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000);
-				current_val = iwe_stream_add_value(current_ev, current_val,
-								   end_buf, &iwe,
-								   IW_EV_PARAM_LEN);
-			}
-			/* Check if we added any event */
-			if ((current_val - current_ev) > IW_EV_LCP_LEN)
-				current_ev = current_val;
+			step = 1;
+
+		iwe.cmd = SIOCGIWRATE;
+		/* Those two flags are ignored... */
+		iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+		/* Max 10 values */
+		for (i = 0; i < 10; i += step) {
+			/* NULL terminated */
+			if (bss->p.rates[i] == 0x0)
+				break;
+			/* Bit rate given in 500 kb/s units (+ 0x80) */
+			iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000);
+			current_val = iwe_stream_add_value(current_ev, current_val,
+							   end_buf, &iwe,
+							   IW_EV_PARAM_LEN);
 		}
-
-		/* The other data in the scan result are not really
-		 * interesting, so for now drop it - Jean II */
+		/* Check if we added any event */
+		if ((current_val - current_ev) > IW_EV_LCP_LEN)
+			current_ev = current_val;
 	}
-	return current_ev - buffer;
+
+	return current_ev;
 }
 
 /* Return results of a scan */
@@ -4077,68 +4168,45 @@ static int orinoco_ioctl_getscan(struct net_device *dev,
 				 char *extra)
 {
 	struct orinoco_private *priv = netdev_priv(dev);
+	bss_element *bss;
 	int err = 0;
 	unsigned long flags;
+	char *current_ev = extra;
 
 	if (orinoco_lock(priv, &flags) != 0)
 		return -EBUSY;
 
-	/* If no results yet, ask to try again later */
-	if (priv->scan_result == NULL) {
-		if (priv->scan_inprogress)
-			/* Important note : we don't want to block the caller
-			 * until results are ready for various reasons.
-			 * First, managing wait queues is complex and racy.
-			 * Second, we grab some rtnetlink lock before comming
-			 * here (in dev_ioctl()).
-			 * Third, we generate an Wireless Event, so the
-			 * caller can wait itself on that - Jean II */
-			err = -EAGAIN;
-		else
-			/* Client error, no scan results...
-			 * The caller need to restart the scan. */
-			err = -ENODATA;
-	} else {
-		/* We have some results to push back to user space */
-
-		/* Translate to WE format */
-		int ret = orinoco_translate_scan(dev, extra,
-						 priv->scan_result,
-						 priv->scan_len);
-
-		if (ret < 0) {
-			err = ret;
-			kfree(priv->scan_result);
-			priv->scan_result = NULL;
-		} else {
-			srq->length = ret;
+	if (priv->scan_inprogress) {
+		/* Important note : we don't want to block the caller
+		 * until results are ready for various reasons.
+		 * First, managing wait queues is complex and racy.
+		 * Second, we grab some rtnetlink lock before comming
+		 * here (in dev_ioctl()).
+		 * Third, we generate an Wireless Event, so the
+		 * caller can wait itself on that - Jean II */
+		err = -EAGAIN;
+		goto out;
+	}
 
-			/* Return flags */
-			srq->flags = (__u16) priv->scan_mode;
+	list_for_each_entry(bss, &priv->bss_list, list) {
+		/* Translate to WE format this entry */
+		current_ev = orinoco_translate_scan(dev, current_ev,
+						    extra + srq->length,
+						    &bss->bss,
+						    bss->last_scanned);
 
-			/* In any case, Scan results will be cleaned up in the
-			 * reset function and when exiting the driver.
-			 * The person triggering the scanning may never come to
-			 * pick the results, so we need to do it in those places.
-			 * Jean II */
-
-#ifdef SCAN_SINGLE_READ
-			/* If you enable this option, only one client (the first
-			 * one) will be able to read the result (and only one
-			 * time). If there is multiple concurent clients that
-			 * want to read scan results, this behavior is not
-			 * advisable - Jean II */
-			kfree(priv->scan_result);
-			priv->scan_result = NULL;
-#endif /* SCAN_SINGLE_READ */
-			/* Here, if too much time has elapsed since last scan,
-			 * we may want to clean up scan results... - Jean II */
+		/* Check if there is space for one more entry */
+		if ((extra + srq->length - current_ev) <= IW_EV_ADDR_LEN) {
+			/* Ask user space to try again with a bigger buffer */
+			err = -E2BIG;
+			goto out;
 		}
-
-		/* Scan is no longer in progress */
-		priv->scan_inprogress = 0;
 	}
-	  
+
+	srq->length = (current_ev - extra);
+	srq->flags = (__u16) priv->scan_mode;
+
+out:
 	orinoco_unlock(priv, &flags);
 	return err;
 }
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index 4720fb20d66d..c6b1858abde8 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -36,6 +36,12 @@ typedef enum {
 	FIRMWARE_TYPE_SYMBOL
 } fwtype_t;
 
+typedef struct {
+	union hermes_scan_info bss;
+	unsigned long last_scanned;
+	struct list_head list;
+} bss_element;
+
 struct orinoco_private {
 	void *card;	/* Pointer to card dependent structure */
 	int (*hard_reset)(struct orinoco_private *);
@@ -105,10 +111,12 @@ struct orinoco_private {
 	int promiscuous, mc_count;
 
 	/* Scanning support */
+	struct list_head bss_list;
+	struct list_head bss_free_list;
+	bss_element *bss_data;
+
 	int	scan_inprogress;	/* Scan pending... */
 	u32	scan_mode;		/* Type of scan done */
-	char *	scan_result;		/* Result of previous scan */
-	int	scan_len;		/* Lenght of result */
 };
 
 #ifdef ORINOCO_DEBUG
diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c
index 1437db0cf4b2..5cda49aff3a8 100644
--- a/drivers/net/wireless/p54common.c
+++ b/drivers/net/wireless/p54common.c
@@ -54,7 +54,7 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
 		u32 code = le32_to_cpu(bootrec->code);
 		switch (code) {
 		case BR_CODE_COMPONENT_ID:
-			switch (be32_to_cpu(*bootrec->data)) {
+			switch (be32_to_cpu(*(__be32 *)bootrec->data)) {
 			case FW_FMAC:
 				printk(KERN_INFO "p54: FreeMAC firmware\n");
 				break;
@@ -78,14 +78,14 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
 				fw_version = (unsigned char*)bootrec->data;
 			break;
 		case BR_CODE_DESCR:
-			priv->rx_start = le32_to_cpu(bootrec->data[1]);
+			priv->rx_start = le32_to_cpu(((__le32 *)bootrec->data)[1]);
 			/* FIXME add sanity checking */
-			priv->rx_end = le32_to_cpu(bootrec->data[2]) - 0x3500;
+			priv->rx_end = le32_to_cpu(((__le32 *)bootrec->data)[2]) - 0x3500;
 			break;
 		case BR_CODE_EXPOSED_IF:
 			exp_if = (struct bootrec_exp_if *) bootrec->data;
 			for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
-				if (exp_if[i].if_id == 0x1a)
+				if (exp_if[i].if_id == cpu_to_le16(0x1a))
 					priv->fw_var = le16_to_cpu(exp_if[i].variant);
 			break;
 		case BR_CODE_DEPENDENT_IF:
@@ -314,6 +314,7 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
 	rx_status.phymode = MODE_IEEE80211G;
 	rx_status.antenna = hdr->antenna;
 	rx_status.mactime = le64_to_cpu(hdr->timestamp);
+	rx_status.flag |= RX_FLAG_TSFT;
 
 	skb_pull(skb, sizeof(*hdr));
 	skb_trim(skb, le16_to_cpu(hdr->len));
@@ -374,7 +375,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
 			if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
 				pad = entry_data->align[0];
 
-			if (!status.control.flags & IEEE80211_TXCTL_NO_ACK) {
+			if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
 				if (!(payload->status & 0x01))
 					status.flags |= IEEE80211_TX_STATUS_ACK;
 				else
@@ -853,7 +854,8 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
 	return ret;
 }
 
-static int p54_config_interface(struct ieee80211_hw *dev, int if_id,
+static int p54_config_interface(struct ieee80211_hw *dev,
+				struct ieee80211_vif *vif,
 				struct ieee80211_if_conf *conf)
 {
 	struct p54_common *priv = dev->priv;
diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c
index 410b54387f23..fa527723fbe0 100644
--- a/drivers/net/wireless/p54pci.c
+++ b/drivers/net/wireless/p54pci.c
@@ -48,10 +48,10 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
 	const struct firmware *fw_entry = NULL;
 	__le32 reg;
 	int err;
-	u32 *data;
+	__le32 *data;
 	u32 remains, left, device_addr;
 
-	P54P_WRITE(int_enable, 0);
+	P54P_WRITE(int_enable, cpu_to_le32(0));
 	P54P_READ(int_enable);
 	udelay(10);
 
@@ -82,7 +82,7 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
 
 	p54_parse_firmware(dev, fw_entry);
 
-	data = (u32 *) fw_entry->data;
+	data = (__le32 *) fw_entry->data;
 	remains = fw_entry->size;
 	device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
 	while (remains) {
@@ -141,6 +141,7 @@ static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id)
 static int p54p_read_eeprom(struct ieee80211_hw *dev)
 {
 	struct p54p_priv *priv = dev->priv;
+	struct p54p_ring_control *ring_control = priv->ring_control;
 	int err;
 	struct p54_control_hdr *hdr;
 	void *eeprom;
@@ -164,8 +165,8 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev)
 		goto out;
 	}
 
-	memset(priv->ring_control, 0, sizeof(*priv->ring_control));
-	P54P_WRITE(ring_control_base, priv->ring_control_dma);
+	memset(ring_control, 0, sizeof(*ring_control));
+	P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
 	P54P_READ(ring_control_base);
 	udelay(10);
 
@@ -194,14 +195,14 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev)
 	tx_mapping = pci_map_single(priv->pdev, (void *)hdr,
 				    EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
 
-	priv->ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping);
-	priv->ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010);
-	priv->ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping);
-	priv->ring_control->tx_data[0].device_addr = hdr->req_id;
-	priv->ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN);
+	ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping);
+	ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010);
+	ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping);
+	ring_control->tx_data[0].device_addr = hdr->req_id;
+	ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN);
 
-	priv->ring_control->host_idx[2] = cpu_to_le32(1);
-	priv->ring_control->host_idx[1] = cpu_to_le32(1);
+	ring_control->host_idx[2] = cpu_to_le32(1);
+	ring_control->host_idx[1] = cpu_to_le32(1);
 
 	wmb();
 	mdelay(100);
@@ -215,8 +216,8 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev)
 	pci_unmap_single(priv->pdev, rx_mapping,
 			 0x2010, PCI_DMA_FROMDEVICE);
 
-	alen = le16_to_cpu(priv->ring_control->rx_mgmt[0].len);
-	if (le32_to_cpu(priv->ring_control->device_idx[2]) != 1 ||
+	alen = le16_to_cpu(ring_control->rx_mgmt[0].len);
+	if (le32_to_cpu(ring_control->device_idx[2]) != 1 ||
 	    alen < 0x10) {
 		printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n",
 		       pci_name(priv->pdev));
@@ -228,7 +229,7 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev)
 
  out:
 	kfree(eeprom);
-	P54P_WRITE(int_enable, 0);
+	P54P_WRITE(int_enable, cpu_to_le32(0));
 	P54P_READ(int_enable);
 	udelay(10);
 	free_irq(priv->pdev->irq, priv);
@@ -239,16 +240,17 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev)
 static void p54p_refill_rx_ring(struct ieee80211_hw *dev)
 {
 	struct p54p_priv *priv = dev->priv;
+	struct p54p_ring_control *ring_control = priv->ring_control;
 	u32 limit, host_idx, idx;
 
-	host_idx = le32_to_cpu(priv->ring_control->host_idx[0]);
+	host_idx = le32_to_cpu(ring_control->host_idx[0]);
 	limit = host_idx;
-	limit -= le32_to_cpu(priv->ring_control->device_idx[0]);
-	limit = ARRAY_SIZE(priv->ring_control->rx_data) - limit;
+	limit -= le32_to_cpu(ring_control->device_idx[0]);
+	limit = ARRAY_SIZE(ring_control->rx_data) - limit;
 
-	idx = host_idx % ARRAY_SIZE(priv->ring_control->rx_data);
+	idx = host_idx % ARRAY_SIZE(ring_control->rx_data);
 	while (limit-- > 1) {
-		struct p54p_desc *desc = &priv->ring_control->rx_data[idx];
+		struct p54p_desc *desc = &ring_control->rx_data[idx];
 
 		if (!desc->host_addr) {
 			struct sk_buff *skb;
@@ -270,22 +272,23 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev)
 
 		idx++;
 		host_idx++;
-		idx %= ARRAY_SIZE(priv->ring_control->rx_data);
+		idx %= ARRAY_SIZE(ring_control->rx_data);
 	}
 
 	wmb();
-	priv->ring_control->host_idx[0] = cpu_to_le32(host_idx);
+	ring_control->host_idx[0] = cpu_to_le32(host_idx);
 }
 
 static irqreturn_t p54p_interrupt(int irq, void *dev_id)
 {
 	struct ieee80211_hw *dev = dev_id;
 	struct p54p_priv *priv = dev->priv;
+	struct p54p_ring_control *ring_control = priv->ring_control;
 	__le32 reg;
 
 	spin_lock(&priv->lock);
 	reg = P54P_READ(int_ident);
-	if (unlikely(reg == 0xFFFFFFFF)) {
+	if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) {
 		spin_unlock(&priv->lock);
 		return IRQ_HANDLED;
 	}
@@ -298,12 +301,12 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id)
 		struct p54p_desc *desc;
 		u32 idx, i;
 		i = priv->tx_idx;
-		i %= ARRAY_SIZE(priv->ring_control->tx_data);
-		priv->tx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[1]);
-		idx %= ARRAY_SIZE(priv->ring_control->tx_data);
+		i %= ARRAY_SIZE(ring_control->tx_data);
+		priv->tx_idx = idx = le32_to_cpu(ring_control->device_idx[1]);
+		idx %= ARRAY_SIZE(ring_control->tx_data);
 
 		while (i != idx) {
-			desc = &priv->ring_control->tx_data[i];
+			desc = &ring_control->tx_data[i];
 			if (priv->tx_buf[i]) {
 				kfree(priv->tx_buf[i]);
 				priv->tx_buf[i] = NULL;
@@ -318,17 +321,17 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id)
 			desc->flags = 0;
 
 			i++;
-			i %= ARRAY_SIZE(priv->ring_control->tx_data);
+			i %= ARRAY_SIZE(ring_control->tx_data);
 		}
 
 		i = priv->rx_idx;
-		i %= ARRAY_SIZE(priv->ring_control->rx_data);
-		priv->rx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[0]);
-		idx %= ARRAY_SIZE(priv->ring_control->rx_data);
+		i %= ARRAY_SIZE(ring_control->rx_data);
+		priv->rx_idx = idx = le32_to_cpu(ring_control->device_idx[0]);
+		idx %= ARRAY_SIZE(ring_control->rx_data);
 		while (i != idx) {
 			u16 len;
 			struct sk_buff *skb;
-			desc = &priv->ring_control->rx_data[i];
+			desc = &ring_control->rx_data[i];
 			len = le16_to_cpu(desc->len);
 			skb = priv->rx_buf[i];
 
@@ -347,7 +350,7 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id)
 			}
 
 			i++;
-			i %= ARRAY_SIZE(priv->ring_control->rx_data);
+			i %= ARRAY_SIZE(ring_control->rx_data);
 		}
 
 		p54p_refill_rx_ring(dev);
@@ -366,6 +369,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
 		    size_t len, int free_on_tx)
 {
 	struct p54p_priv *priv = dev->priv;
+	struct p54p_ring_control *ring_control = priv->ring_control;
 	unsigned long flags;
 	struct p54p_desc *desc;
 	dma_addr_t mapping;
@@ -373,19 +377,19 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	device_idx = le32_to_cpu(priv->ring_control->device_idx[1]);
-	idx = le32_to_cpu(priv->ring_control->host_idx[1]);
-	i = idx % ARRAY_SIZE(priv->ring_control->tx_data);
+	device_idx = le32_to_cpu(ring_control->device_idx[1]);
+	idx = le32_to_cpu(ring_control->host_idx[1]);
+	i = idx % ARRAY_SIZE(ring_control->tx_data);
 
 	mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE);
-	desc = &priv->ring_control->tx_data[i];
+	desc = &ring_control->tx_data[i];
 	desc->host_addr = cpu_to_le32(mapping);
 	desc->device_addr = data->req_id;
 	desc->len = cpu_to_le16(len);
 	desc->flags = 0;
 
 	wmb();
-	priv->ring_control->host_idx[1] = cpu_to_le32(idx + 1);
+	ring_control->host_idx[1] = cpu_to_le32(idx + 1);
 
 	if (free_on_tx)
 		priv->tx_buf[i] = data;
@@ -397,7 +401,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
 
 	/* FIXME: unlikely to happen because the device usually runs out of
 	   memory before we fill the ring up, but we can make it impossible */
-	if (idx - device_idx > ARRAY_SIZE(priv->ring_control->tx_data) - 2)
+	if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2)
 		printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy));
 }
 
@@ -421,7 +425,7 @@ static int p54p_open(struct ieee80211_hw *dev)
 
 	p54p_upload_firmware(dev);
 
-	P54P_WRITE(ring_control_base, priv->ring_control_dma);
+	P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
 	P54P_READ(ring_control_base);
 	wmb();
 	udelay(10);
@@ -457,10 +461,11 @@ static int p54p_open(struct ieee80211_hw *dev)
 static void p54p_stop(struct ieee80211_hw *dev)
 {
 	struct p54p_priv *priv = dev->priv;
+	struct p54p_ring_control *ring_control = priv->ring_control;
 	unsigned int i;
 	struct p54p_desc *desc;
 
-	P54P_WRITE(int_enable, 0);
+	P54P_WRITE(int_enable, cpu_to_le32(0));
 	P54P_READ(int_enable);
 	udelay(10);
 
@@ -469,7 +474,7 @@ static void p54p_stop(struct ieee80211_hw *dev)
 	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
 
 	for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) {
-		desc = &priv->ring_control->rx_data[i];
+		desc = &ring_control->rx_data[i];
 		if (desc->host_addr)
 			pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
 					 MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
@@ -478,7 +483,7 @@ static void p54p_stop(struct ieee80211_hw *dev)
 	}
 
 	for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) {
-		desc = &priv->ring_control->tx_data[i];
+		desc = &ring_control->tx_data[i];
 		if (desc->host_addr)
 			pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
 					 le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
@@ -487,7 +492,7 @@ static void p54p_stop(struct ieee80211_hw *dev)
 		priv->tx_buf[i] = NULL;
 	}
 
-	memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+	memset(ring_control, 0, sizeof(ring_control));
 }
 
 static int __devinit p54p_probe(struct pci_dev *pdev,
diff --git a/drivers/net/wireless/p54pci.h b/drivers/net/wireless/p54pci.h
index 52feb597dc4a..5bedd7af385d 100644
--- a/drivers/net/wireless/p54pci.h
+++ b/drivers/net/wireless/p54pci.h
@@ -85,8 +85,8 @@ struct p54p_ring_control {
 	struct p54p_desc tx_mgmt[4];
 } __attribute__ ((packed));
 
-#define P54P_READ(r) __raw_readl(&priv->map->r)
-#define P54P_WRITE(r, val) __raw_writel((__force u32)(val), &priv->map->r)
+#define P54P_READ(r) (__force __le32)__raw_readl(&priv->map->r)
+#define P54P_WRITE(r, val) __raw_writel((__force u32)(__le32)(val), &priv->map->r)
 
 struct p54p_priv {
 	struct p54_common common;
diff --git a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h
index 3fadcb6f5297..19c33d313734 100644
--- a/drivers/net/wireless/prism54/isl_38xx.h
+++ b/drivers/net/wireless/prism54/isl_38xx.h
@@ -138,14 +138,14 @@ isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset)
 #define MAX_FRAGMENT_SIZE_RX	                1600
 
 typedef struct {
-	u32 address;		/* physical address on host */
-	u16 size;		/* packet size */
-	u16 flags;		/* set of bit-wise flags */
+	__le32 address;		/* physical address on host */
+	__le16 size;		/* packet size */
+	__le16 flags;		/* set of bit-wise flags */
 } isl38xx_fragment;
 
 struct isl38xx_cb {
-	u32 driver_curr_frag[ISL38XX_CB_QCOUNT];
-	u32 device_curr_frag[ISL38XX_CB_QCOUNT];
+	__le32 driver_curr_frag[ISL38XX_CB_QCOUNT];
+	__le32 device_curr_frag[ISL38XX_CB_QCOUNT];
 	isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE];
 	isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE];
 	isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE];
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 6d80ca421cf0..1b595a6525f4 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -165,8 +165,7 @@ prism54_update_stats(struct work_struct *work)
 	struct obj_bss bss, *bss2;
 	union oid_res_t r;
 
-	if (down_interruptible(&priv->stats_sem))
-		return;
+	down(&priv->stats_sem);
 
 /* Noise floor.
  * I'm not sure if the unit is dBm.
@@ -1118,7 +1117,7 @@ prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
 			    mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
 					    &index);
 		} else {
-			if (!dwrq->flags & IW_ENCODE_MODE) {
+			if (!(dwrq->flags & IW_ENCODE_MODE)) {
 				/* we cannot do anything. Complain. */
 				return -EINVAL;
 			}
@@ -1793,8 +1792,7 @@ prism54_clear_mac(struct islpci_acl *acl)
 	struct list_head *ptr, *next;
 	struct mac_entry *entry;
 
-	if (down_interruptible(&acl->sem))
-		return;
+	down(&acl->sem);
 
 	if (acl->size == 0) {
 		up(&acl->sem);
@@ -2116,8 +2114,7 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
 	if (wpa_ie_len > MAX_WPA_IE_LEN)
 		wpa_ie_len = MAX_WPA_IE_LEN;
 
-	if (down_interruptible(&priv->wpa_sem))
-		return;
+	down(&priv->wpa_sem);
 
 	/* try to use existing entry */
 	list_for_each(ptr, &priv->bss_wpa_list) {
@@ -2178,8 +2175,7 @@ prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
 	struct islpci_bss_wpa_ie *bss = NULL;
 	size_t len = 0;
 
-	if (down_interruptible(&priv->wpa_sem))
-		return 0;
+	down(&priv->wpa_sem);
 
 	list_for_each(ptr, &priv->bss_wpa_list) {
 		bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
@@ -2610,7 +2606,7 @@ prism2_ioctl_set_encryption(struct net_device *dev,
 			    mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
 					    &index);
 		} else {
-			if (!param->u.crypt.flags & IW_ENCODE_MODE) {
+			if (!(param->u.crypt.flags & IW_ENCODE_MODE)) {
 				/* we cannot do anything. Complain. */
 				return -EINVAL;
 			}
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 219dd651dc41..dbb538ccb4ec 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -861,7 +861,7 @@ islpci_setup(struct pci_dev *pdev)
 	init_waitqueue_head(&priv->reset_done);
 
 	/* init the queue read locks, process wait counter */
-	sema_init(&priv->mgmt_sem, 1);
+	mutex_init(&priv->mgmt_lock);
 	priv->mgmt_received = NULL;
 	init_waitqueue_head(&priv->mgmt_wqueue);
 	sema_init(&priv->stats_sem, 1);
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index 736666da6c24..4e0182ce835b 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -26,6 +26,7 @@
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
 #include <linux/list.h>
+#include <linux/mutex.h>
 
 #include "isl_38xx.h"
 #include "isl_oid.h"
@@ -164,7 +165,7 @@ typedef struct {
 	wait_queue_head_t reset_done;
 
 	/* used by islpci_mgt_transaction */
-	struct semaphore mgmt_sem; /* serialize access to mailbox and wqueue */
+	struct mutex mgmt_lock; /* serialize access to mailbox and wqueue */
 	struct islpci_mgmtframe *mgmt_received;	  /* mbox for incoming frame */
 	wait_queue_head_t mgmt_wqueue;            /* waitqueue for mbox */
 
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index f49eb068c7d0..762e85bef55d 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -471,7 +471,7 @@ islpci_eth_receive(islpci_private *priv)
 		wmb();
 
 		/* increment the driver read pointer */
-		add_le32p((u32 *) &control_block->
+		add_le32p(&control_block->
 			  driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1);
 	}
 
diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h
index 5bf820defbd0..61454d32d74d 100644
--- a/drivers/net/wireless/prism54/islpci_eth.h
+++ b/drivers/net/wireless/prism54/islpci_eth.h
@@ -23,15 +23,15 @@
 #include "islpci_dev.h"
 
 struct rfmon_header {
-	u16 unk0;		/* = 0x0000 */
-	u16 length;		/* = 0x1400 */
-	u32 clock;		/* 1MHz clock */
+	__le16 unk0;		/* = 0x0000 */
+	__le16 length;		/* = 0x1400 */
+	__le32 clock;		/* 1MHz clock */
 	u8 flags;
 	u8 unk1;
 	u8 rate;
 	u8 unk2;
-	u16 freq;
-	u16 unk3;
+	__le16 freq;
+	__le16 unk3;
 	u8 rssi;
 	u8 padding[3];
 } __attribute__ ((packed));
@@ -47,20 +47,20 @@ struct rx_annex_header {
 #define P80211CAPTURE_VERSION 0x80211001
 
 struct avs_80211_1_header {
-	uint32_t version;
-	uint32_t length;
-	uint64_t mactime;
-	uint64_t hosttime;
-	uint32_t phytype;
-	uint32_t channel;
-	uint32_t datarate;
-	uint32_t antenna;
-	uint32_t priority;
-	uint32_t ssi_type;
-	int32_t ssi_signal;
-	int32_t ssi_noise;
-	uint32_t preamble;
-	uint32_t encoding;
+	__be32 version;
+	__be32 length;
+	__be64 mactime;
+	__be64 hosttime;
+	__be32 phytype;
+	__be32 channel;
+	__be32 datarate;
+	__be32 antenna;
+	__be32 priority;
+	__be32 ssi_type;
+	__be32 ssi_signal;
+	__be32 ssi_noise;
+	__be32 preamble;
+	__be32 encoding;
 };
 
 void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *);
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
index 2246f7930b4e..f7c677e2094d 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.c
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -460,7 +460,7 @@ islpci_mgt_transaction(struct net_device *ndev,
 
 	*recvframe = NULL;
 
-	if (down_interruptible(&priv->mgmt_sem))
+	if (mutex_lock_interruptible(&priv->mgmt_lock))
 		return -ERESTARTSYS;
 
 	prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE);
@@ -504,7 +504,7 @@ islpci_mgt_transaction(struct net_device *ndev,
 	/* TODO: we should reset the device here */
  out:
 	finish_wait(&priv->mgmt_wqueue, &wait);
-	up(&priv->mgmt_sem);
+	mutex_unlock(&priv->mgmt_lock);
 	return err;
 }
 
diff --git a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h
index fc53b587b722..f91a88fc1e35 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.h
+++ b/drivers/net/wireless/prism54/islpci_mgt.h
@@ -86,7 +86,7 @@ extern int pc_debug;
 #define PIMFOR_FLAG_LITTLE_ENDIAN               0x02
 
 static inline void
-add_le32p(u32 * le_number, u32 add)
+add_le32p(__le32 * le_number, u32 add)
 {
 	*le_number = cpu_to_le32(le32_to_cpup(le_number) + add);
 }
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index f87fe10059ae..f3858ee36f32 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -44,6 +44,7 @@
 #include <linux/ioport.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
+#include <linux/ieee80211.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
@@ -997,13 +998,13 @@ static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev,
 static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigned char *data,
                     int len)
 {
-    unsigned short int proto = ((struct ethhdr *)data)->h_proto;
+    __be16 proto = ((struct ethhdr *)data)->h_proto;
     if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */
         DEBUG(3,"ray_cs translate_frame DIX II\n");
         /* Copy LLC header to card buffer */
         memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc));
         memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2);
-        if ((proto == 0xf380) || (proto == 0x3781)) {
+        if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) {
             /* This is the selective translation table, only 2 entries */
             writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]);
         }
@@ -1014,7 +1015,7 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigne
     }
     else { /* already  802 type, and proto is length */
         DEBUG(3,"ray_cs translate_frame 802\n");
-        if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */
+        if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */
         DEBUG(3,"ray_cs translate_frame evil IPX\n");
             memcpy_toio(&ptx->var, data + ETH_HLEN,  len - ETH_HLEN);
             return 0 - ETH_HLEN;
@@ -1780,19 +1781,19 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev)
     }
     if (readb(&p->mrx_overflow_for_host))
     {
-        local->stats.rx_over_errors += ntohs(readb(&p->mrx_overflow));
+        local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow));
         writeb(0,&p->mrx_overflow);
         writeb(0,&p->mrx_overflow_for_host);
     }
     if (readb(&p->mrx_checksum_error_for_host))
     {
-        local->stats.rx_crc_errors += ntohs(readb(&p->mrx_checksum_error));
+        local->stats.rx_crc_errors += swab16(readw(&p->mrx_checksum_error));
         writeb(0,&p->mrx_checksum_error);
         writeb(0,&p->mrx_checksum_error_for_host);
     }
     if (readb(&p->rx_hec_error_for_host))
     {
-        local->stats.rx_frame_errors += ntohs(readb(&p->rx_hec_error));
+        local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error));
         writeb(0,&p->rx_hec_error);
         writeb(0,&p->rx_hec_error_for_host);
     }
@@ -2316,32 +2317,17 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i
 static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
 {
     snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH);
-    struct mac_header *pmac = (struct mac_header *)skb->data;
-    unsigned short type = *(unsigned short *)psnap->ethertype;
-    unsigned int xsap = *(unsigned int *)psnap & 0x00ffffff;
-    unsigned int org = (*(unsigned int *)psnap->org) & 0x00ffffff;
+    struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data;
+    __be16 type = *(__be16 *)psnap->ethertype;
     int delta;
     struct ethhdr *peth;
     UCHAR srcaddr[ADDRLEN];
     UCHAR destaddr[ADDRLEN];
+    static UCHAR org_bridge[3] = {0, 0, 0xf8};
+    static UCHAR org_1042[3] = {0, 0, 0};
 
-    if (pmac->frame_ctl_2 & FC2_FROM_DS) {
-	if (pmac->frame_ctl_2 & FC2_TO_DS) { /* AP to AP */
-	    memcpy(destaddr, pmac->addr_3, ADDRLEN);
-	    memcpy(srcaddr, ((unsigned char *)pmac->addr_3) + ADDRLEN, ADDRLEN);
-	} else { /* AP to terminal */
-	    memcpy(destaddr, pmac->addr_1, ADDRLEN);
-	    memcpy(srcaddr, pmac->addr_3, ADDRLEN); 
-	}
-    } else { /* Terminal to AP */
-	if (pmac->frame_ctl_2 & FC2_TO_DS) {
-	    memcpy(destaddr, pmac->addr_3, ADDRLEN);
-	    memcpy(srcaddr, pmac->addr_2, ADDRLEN); 
-	} else { /* Adhoc */
-	    memcpy(destaddr, pmac->addr_1, ADDRLEN);
-	    memcpy(srcaddr, pmac->addr_2, ADDRLEN); 
-	}
-    }
+    memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN);
+    memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN);
 
 #ifdef PCMCIA_DEBUG
     if (pc_debug > 3) {
@@ -2349,33 +2335,34 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
     printk(KERN_DEBUG "skb->data before untranslate");
     for (i=0;i<64;i++) 
         printk("%02x ",skb->data[i]);
-    printk("\n" KERN_DEBUG "type = %08x, xsap = %08x, org = %08x\n",
-           type,xsap,org);
+    printk("\n" KERN_DEBUG "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n",
+           ntohs(type),
+	   psnap->dsap, psnap->ssap, psnap->ctrl,
+	   psnap->org[0], psnap->org[1], psnap->org[2]);
     printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data);
     }
 #endif
 
-    if ( xsap != SNAP_ID) {
+    if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) {
         /* not a snap type so leave it alone */
-        DEBUG(3,"ray_cs untranslate NOT SNAP %x\n", *(unsigned int *)psnap & 0x00ffffff);
+        DEBUG(3,"ray_cs untranslate NOT SNAP %02x %02x %02x\n",
+		psnap->dsap, psnap->ssap, psnap->ctrl);
 
         delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
         peth = (struct ethhdr *)(skb->data + delta);
         peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
     }
     else { /* Its a SNAP */
-        if (org == BRIDGE_ENCAP) { /* EtherII and nuke the LLC  */
+        if (memcmp(psnap->org, org_bridge, 3) == 0) { /* EtherII and nuke the LLC  */
         DEBUG(3,"ray_cs untranslate Bridge encap\n");
             delta = RX_MAC_HEADER_LENGTH 
                 + sizeof(struct snaphdr_t) - ETH_HLEN;
             peth = (struct ethhdr *)(skb->data + delta);
             peth->h_proto = type;
-        }
-        else {
-            if (org == RFC1042_ENCAP) {
-                switch (type) {
-                case RAY_IPX_TYPE:
-                case APPLEARP_TYPE:
+	} else if (memcmp(psnap->org, org_1042, 3) == 0) {
+                switch (ntohs(type)) {
+                case ETH_P_IPX:
+                case ETH_P_AARP:
                     DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n");
                     delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
                     peth = (struct ethhdr *)(skb->data + delta);
@@ -2389,14 +2376,12 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
                     peth->h_proto = type;
                     break;
                 }
-            }
-            else {
+	} else {
                 printk("ray_cs untranslate very confused by packet\n");
                 delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
                 peth = (struct ethhdr *)(skb->data + delta);
                 peth->h_proto = type;
-            }
-        }
+	}
     }
 /* TBD reserve  skb_reserve(skb, delta); */
     skb_pull(skb, delta);
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 31c1dd271627..d6cba138c7ab 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -24,11 +24,6 @@
 	Supported chipsets: RT2460.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2400pci"
-
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
@@ -54,7 +49,7 @@
  * the access attempt is considered to have failed,
  * and we will print an error.
  */
-static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
 	unsigned int i;
@@ -69,7 +64,7 @@ static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
 	return reg;
 }
 
-static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, const u8 value)
 {
 	u32 reg;
@@ -95,7 +90,7 @@ static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
 	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
 }
 
-static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, u8 *value)
 {
 	u32 reg;
@@ -132,7 +127,7 @@ static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
 	*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
 }
 
-static void rt2400pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, const u32 value)
 {
 	u32 reg;
@@ -195,13 +190,13 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 #define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
 
-static void rt2400pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, u32 *data)
 {
 	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
 }
 
-static void rt2400pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, u32 data)
 {
 	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
@@ -285,7 +280,7 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
 	 */
 	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
 	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
-	rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+	rt2x00_set_field32(&reg, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON));
 	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
 	rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync);
 	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
@@ -397,7 +392,7 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower)
 }
 
 static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-				     int antenna_tx, int antenna_rx)
+				     struct antenna_setup *ant)
 {
 	u8 r1;
 	u8 r4;
@@ -408,14 +403,20 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
 	/*
 	 * Configure the TX antenna.
 	 */
-	switch (antenna_tx) {
-	case ANTENNA_SW_DIVERSITY:
+	switch (ant->tx) {
 	case ANTENNA_HW_DIVERSITY:
 		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
 		break;
 	case ANTENNA_A:
 		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
 		break;
+	case ANTENNA_SW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
 	case ANTENNA_B:
 		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
 		break;
@@ -424,14 +425,20 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
 	/*
 	 * Configure the RX antenna.
 	 */
-	switch (antenna_rx) {
-	case ANTENNA_SW_DIVERSITY:
+	switch (ant->rx) {
 	case ANTENNA_HW_DIVERSITY:
 		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
 		break;
 	case ANTENNA_A:
 		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
 		break;
+	case ANTENNA_SW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
 	case ANTENNA_B:
 		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
 		break;
@@ -485,9 +492,7 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,
 		rt2400pci_config_txpower(rt2x00dev,
 					 libconf->conf->power_level);
 	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt2400pci_config_antenna(rt2x00dev,
-					 libconf->conf->antenna_sel_tx,
-					 libconf->conf->antenna_sel_rx);
+		rt2400pci_config_antenna(rt2x00dev, &libconf->ant);
 	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
 		rt2400pci_config_duration(rt2x00dev, libconf);
 }
@@ -514,18 +519,10 @@ static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev)
 
 	rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
 	rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
-
-	if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
-		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
-		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
-	} else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
-		rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
-		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
-	} else {
-		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
-		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
-	}
-
+	rt2x00_set_field32(&reg, LEDCSR_LINK,
+			   (rt2x00dev->led_mode != LED_MODE_ASUS));
+	rt2x00_set_field32(&reg, LEDCSR_ACTIVITY,
+			   (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
 	rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
 }
 
@@ -542,7 +539,8 @@ static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev)
 /*
  * Link tuning
  */
-static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev)
+static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev,
+				 struct link_qual *qual)
 {
 	u32 reg;
 	u8 bbp;
@@ -551,13 +549,13 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev)
 	 * Update FCS error count from register.
 	 */
 	rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
-	rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
+	qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
 
 	/*
 	 * Update False CCA count from register.
 	 */
 	rt2400pci_bbp_read(rt2x00dev, 39, &bbp);
-	rt2x00dev->link.false_cca = bbp;
+	qual->false_cca = bbp;
 }
 
 static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
@@ -582,10 +580,10 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
 	 */
 	rt2400pci_bbp_read(rt2x00dev, 13, &reg);
 
-	if (rt2x00dev->link.false_cca > 512 && reg < 0x20) {
+	if (rt2x00dev->link.qual.false_cca > 512 && reg < 0x20) {
 		rt2400pci_bbp_write(rt2x00dev, 13, ++reg);
 		rt2x00dev->link.vgc_level = reg;
-	} else if (rt2x00dev->link.false_cca < 100 && reg > 0x08) {
+	} else if (rt2x00dev->link.qual.false_cca < 100 && reg > 0x08) {
 		rt2400pci_bbp_write(rt2x00dev, 13, --reg);
 		rt2x00dev->link.vgc_level = reg;
 	}
@@ -594,65 +592,43 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
 /*
  * Initialization functions.
  */
-static void rt2400pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
+				   struct data_entry *entry)
 {
-	struct data_ring *ring = rt2x00dev->rx;
-	struct data_desc *rxd;
-	unsigned int i;
+	__le32 *rxd = entry->priv;
 	u32 word;
 
-	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
-
-	for (i = 0; i < ring->stats.limit; i++) {
-		rxd = ring->entry[i].priv;
-
-		rt2x00_desc_read(rxd, 2, &word);
-		rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
-				   ring->data_size);
-		rt2x00_desc_write(rxd, 2, word);
-
-		rt2x00_desc_read(rxd, 1, &word);
-		rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS,
-				   ring->entry[i].data_dma);
-		rt2x00_desc_write(rxd, 1, word);
+	rt2x00_desc_read(rxd, 2, &word);
+	rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->ring->data_size);
+	rt2x00_desc_write(rxd, 2, word);
 
-		rt2x00_desc_read(rxd, 0, &word);
-		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-		rt2x00_desc_write(rxd, 0, word);
-	}
+	rt2x00_desc_read(rxd, 1, &word);
+	rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry->data_dma);
+	rt2x00_desc_write(rxd, 1, word);
 
-	rt2x00_ring_index_clear(rt2x00dev->rx);
+	rt2x00_desc_read(rxd, 0, &word);
+	rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+	rt2x00_desc_write(rxd, 0, word);
 }
 
-static void rt2400pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev,
+				   struct data_entry *entry)
 {
-	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
-	struct data_desc *txd;
-	unsigned int i;
+	__le32 *txd = entry->priv;
 	u32 word;
 
-	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
-
-	for (i = 0; i < ring->stats.limit; i++) {
-		txd = ring->entry[i].priv;
-
-		rt2x00_desc_read(txd, 1, &word);
-		rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS,
-				   ring->entry[i].data_dma);
-		rt2x00_desc_write(txd, 1, word);
-
-		rt2x00_desc_read(txd, 2, &word);
-		rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH,
-				   ring->data_size);
-		rt2x00_desc_write(txd, 2, word);
+	rt2x00_desc_read(txd, 1, &word);
+	rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry->data_dma);
+	rt2x00_desc_write(txd, 1, word);
 
-		rt2x00_desc_read(txd, 0, &word);
-		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-		rt2x00_desc_write(txd, 0, word);
-	}
+	rt2x00_desc_read(txd, 2, &word);
+	rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, entry->ring->data_size);
+	rt2x00_desc_write(txd, 2, word);
 
-	rt2x00_ring_index_clear(ring);
+	rt2x00_desc_read(txd, 0, &word);
+	rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+	rt2x00_desc_write(txd, 0, word);
 }
 
 static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev)
@@ -660,15 +636,6 @@ static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev)
 	u32 reg;
 
 	/*
-	 * Initialize rings.
-	 */
-	rt2400pci_init_rxring(rt2x00dev);
-	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
-	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
-	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
-	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
-
-	/*
 	 * Initialize registers.
 	 */
 	rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
@@ -1014,53 +981,37 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
  * TX descriptor initialization
  */
 static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-				    struct data_desc *txd,
+				    struct sk_buff *skb,
 				    struct txdata_entry_desc *desc,
-				    struct ieee80211_hdr *ieee80211hdr,
-				    unsigned int length,
 				    struct ieee80211_tx_control *control)
 {
+	struct skb_desc *skbdesc = get_skb_desc(skb);
+	__le32 *txd = skbdesc->desc;
 	u32 word;
-	u32 signal = 0;
-	u32 service = 0;
-	u32 length_high = 0;
-	u32 length_low = 0;
-
-	/*
-	 * The PLCP values should be treated as if they
-	 * were BBP values.
-	 */
-	rt2x00_set_field32(&signal, BBPCSR_VALUE, desc->signal);
-	rt2x00_set_field32(&signal, BBPCSR_REGNUM, 5);
-	rt2x00_set_field32(&signal, BBPCSR_BUSY, 1);
-
-	rt2x00_set_field32(&service, BBPCSR_VALUE, desc->service);
-	rt2x00_set_field32(&service, BBPCSR_REGNUM, 6);
-	rt2x00_set_field32(&service, BBPCSR_BUSY, 1);
-
-	rt2x00_set_field32(&length_high, BBPCSR_VALUE, desc->length_high);
-	rt2x00_set_field32(&length_high, BBPCSR_REGNUM, 7);
-	rt2x00_set_field32(&length_high, BBPCSR_BUSY, 1);
-
-	rt2x00_set_field32(&length_low, BBPCSR_VALUE, desc->length_low);
-	rt2x00_set_field32(&length_low, BBPCSR_REGNUM, 8);
-	rt2x00_set_field32(&length_low, BBPCSR_BUSY, 1);
 
 	/*
 	 * Start writing the descriptor words.
 	 */
 	rt2x00_desc_read(txd, 2, &word);
-	rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, length);
+	rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len);
 	rt2x00_desc_write(txd, 2, word);
 
 	rt2x00_desc_read(txd, 3, &word);
-	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, signal);
-	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, service);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_REGNUM, 5);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_BUSY, 1);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_REGNUM, 6);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_BUSY, 1);
 	rt2x00_desc_write(txd, 3, word);
 
 	rt2x00_desc_read(txd, 4, &word);
-	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, length_low);
-	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, length_high);
+	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, desc->length_low);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_REGNUM, 8);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_BUSY, 1);
+	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, desc->length_high);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_REGNUM, 7);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1);
 	rt2x00_desc_write(txd, 4, word);
 
 	rt2x00_desc_read(txd, 0, &word);
@@ -1069,7 +1020,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
 			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_ACK,
-			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
+			   test_bit(ENTRY_TXD_ACK, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
 			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_RTS,
@@ -1099,12 +1050,12 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 	}
 
 	rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
-	if (queue == IEEE80211_TX_QUEUE_DATA0)
-		rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
-	else if (queue == IEEE80211_TX_QUEUE_DATA1)
-		rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
-	else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
-		rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+	rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO,
+			   (queue == IEEE80211_TX_QUEUE_DATA0));
+	rt2x00_set_field32(&reg, TXCSR0_KICK_TX,
+			   (queue == IEEE80211_TX_QUEUE_DATA1));
+	rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM,
+			   (queue == IEEE80211_TX_QUEUE_AFTER_BEACON));
 	rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
 }
 
@@ -1114,7 +1065,7 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 static void rt2400pci_fill_rxdone(struct data_entry *entry,
 				  struct rxdata_entry_desc *desc)
 {
-	struct data_desc *rxd = entry->priv;
+	__le32 *rxd = entry->priv;
 	u32 word0;
 	u32 word2;
 
@@ -1135,6 +1086,7 @@ static void rt2400pci_fill_rxdone(struct data_entry *entry,
 	    entry->ring->rt2x00dev->rssi_offset;
 	desc->ofdm = 0;
 	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+	desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
 }
 
 /*
@@ -1144,7 +1096,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
 {
 	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
 	struct data_entry *entry;
-	struct data_desc *txd;
+	__le32 *txd;
 	u32 word;
 	int tx_status;
 	int retry;
@@ -1164,26 +1116,8 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
 		tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
 		retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
 
-		rt2x00lib_txdone(entry, tx_status, retry);
-
-		/*
-		 * Make this entry available for reuse.
-		 */
-		entry->flags = 0;
-		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-		rt2x00_desc_write(txd, 0, word);
-		rt2x00_ring_index_done_inc(ring);
+		rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry);
 	}
-
-	/*
-	 * If the data ring was full before the txdone handler
-	 * we must make sure the packet queue in the mac80211 stack
-	 * is reenabled when the txdone handler has finished.
-	 */
-	entry = ring->entry;
-	if (!rt2x00_ring_full(ring))
-		ieee80211_wake_queue(rt2x00dev->hw,
-				     entry->tx_status.control.queue);
 }
 
 static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
@@ -1315,12 +1249,23 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Identify default antenna configuration.
 	 */
-	rt2x00dev->hw->conf.antenna_sel_tx =
+	rt2x00dev->default_ant.tx =
 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
-	rt2x00dev->hw->conf.antenna_sel_rx =
+	rt2x00dev->default_ant.rx =
 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
 
 	/*
+	 * When the eeprom indicates SW_DIVERSITY use HW_DIVERSITY instead.
+	 * I am not 100% sure about this, but the legacy drivers do not
+	 * indicate antenna swapping in software is required when
+	 * diversity is enabled.
+	 */
+	if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
+		rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY;
+	if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
+		rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY;
+
+	/*
 	 * Store led mode, for correct led behaviour.
 	 */
 	rt2x00dev->led_mode =
@@ -1447,7 +1392,6 @@ static void rt2400pci_configure_filter(struct ieee80211_hw *hw,
 				       struct dev_addr_list *mc_list)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct interface *intf = &rt2x00dev->interface;
 	u32 reg;
 
 	/*
@@ -1466,21 +1410,18 @@ static void rt2400pci_configure_filter(struct ieee80211_hw *hw,
 	 * Apply some rules to the filters:
 	 * - Some filters imply different filters to be set.
 	 * - Some things we can't filter out at all.
-	 * - Some filters are set based on interface type.
 	 */
 	*total_flags |= FIF_ALLMULTI;
 	if (*total_flags & FIF_OTHER_BSS ||
 	    *total_flags & FIF_PROMISC_IN_BSS)
 		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
-	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
-		*total_flags |= FIF_PROMISC_IN_BSS;
 
 	/*
 	 * Check if there is any work left for us.
 	 */
-	if (intf->filter == *total_flags)
+	if (rt2x00dev->packet_filter == *total_flags)
 		return;
-	intf->filter = *total_flags;
+	rt2x00dev->packet_filter = *total_flags;
 
 	/*
 	 * Start configuration steps.
@@ -1583,7 +1524,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
 	.configure_filter	= rt2400pci_configure_filter,
 	.get_stats		= rt2x00mac_get_stats,
 	.set_retry_limit	= rt2400pci_set_retry_limit,
-	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
+	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2400pci_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt2400pci_get_tsf,
@@ -1597,6 +1538,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
 	.probe_hw		= rt2400pci_probe_hw,
 	.initialize		= rt2x00pci_initialize,
 	.uninitialize		= rt2x00pci_uninitialize,
+	.init_rxentry		= rt2400pci_init_rxentry,
+	.init_txentry		= rt2400pci_init_txentry,
 	.set_device_state	= rt2400pci_set_device_state,
 	.rfkill_poll		= rt2400pci_rfkill_poll,
 	.link_stats		= rt2400pci_link_stats,
@@ -1614,7 +1557,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
 };
 
 static const struct rt2x00_ops rt2400pci_ops = {
-	.name		= DRV_NAME,
+	.name		= KBUILD_MODNAME,
 	.rxd_size	= RXD_DESC_SIZE,
 	.txd_size	= TXD_DESC_SIZE,
 	.eeprom_size	= EEPROM_SIZE,
@@ -1642,7 +1585,7 @@ MODULE_DEVICE_TABLE(pci, rt2400pci_device_table);
 MODULE_LICENSE("GPL");
 
 static struct pci_driver rt2400pci_driver = {
-	.name		= DRV_NAME,
+	.name		= KBUILD_MODNAME,
 	.id_table	= rt2400pci_device_table,
 	.probe		= rt2x00pci_probe,
 	.remove		= __devexit_p(rt2x00pci_remove),
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index ae22501f085d..369aac6d0336 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -803,8 +803,8 @@
 /*
  * DMA descriptor defines.
  */
-#define TXD_DESC_SIZE			( 8 * sizeof(struct data_desc) )
-#define RXD_DESC_SIZE			( 8 * sizeof(struct data_desc) )
+#define TXD_DESC_SIZE			( 8 * sizeof(__le32) )
+#define RXD_DESC_SIZE			( 8 * sizeof(__le32) )
 
 /*
  * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
@@ -839,11 +839,21 @@
 
 /*
  * Word3 & 4: PLCP information
- */
-#define TXD_W3_PLCP_SIGNAL		FIELD32(0x0000ffff)
-#define TXD_W3_PLCP_SERVICE		FIELD32(0xffff0000)
-#define TXD_W4_PLCP_LENGTH_LOW		FIELD32(0x0000ffff)
-#define TXD_W4_PLCP_LENGTH_HIGH		FIELD32(0xffff0000)
+ * The PLCP values should be treated as if they were BBP values.
+ */
+#define TXD_W3_PLCP_SIGNAL		FIELD32(0x000000ff)
+#define TXD_W3_PLCP_SIGNAL_REGNUM	FIELD32(0x00007f00)
+#define TXD_W3_PLCP_SIGNAL_BUSY		FIELD32(0x00008000)
+#define TXD_W3_PLCP_SERVICE		FIELD32(0x00ff0000)
+#define TXD_W3_PLCP_SERVICE_REGNUM	FIELD32(0x7f000000)
+#define TXD_W3_PLCP_SERVICE_BUSY	FIELD32(0x80000000)
+
+#define TXD_W4_PLCP_LENGTH_LOW		FIELD32(0x000000ff)
+#define TXD_W3_PLCP_LENGTH_LOW_REGNUM	FIELD32(0x00007f00)
+#define TXD_W3_PLCP_LENGTH_LOW_BUSY	FIELD32(0x00008000)
+#define TXD_W4_PLCP_LENGTH_HIGH		FIELD32(0x00ff0000)
+#define TXD_W3_PLCP_LENGTH_HIGH_REGNUM	FIELD32(0x7f000000)
+#define TXD_W3_PLCP_LENGTH_HIGH_BUSY	FIELD32(0x80000000)
 
 /*
  * Word5
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 702321c30164..e874fdcae204 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -24,11 +24,6 @@
 	Supported chipsets: RT2560.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2500pci"
-
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
@@ -54,7 +49,7 @@
  * the access attempt is considered to have failed,
  * and we will print an error.
  */
-static u32 rt2500pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+static u32 rt2500pci_bbp_check(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
 	unsigned int i;
@@ -69,7 +64,7 @@ static u32 rt2500pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
 	return reg;
 }
 
-static void rt2500pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, const u8 value)
 {
 	u32 reg;
@@ -95,7 +90,7 @@ static void rt2500pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
 	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
 }
 
-static void rt2500pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, u8 *value)
 {
 	u32 reg;
@@ -132,7 +127,7 @@ static void rt2500pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
 	*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
 }
 
-static void rt2500pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, const u32 value)
 {
 	u32 reg;
@@ -195,13 +190,13 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 #define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
 
-static void rt2500pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt2500pci_read_csr(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, u32 *data)
 {
 	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
 }
 
-static void rt2500pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt2500pci_write_csr(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, u32 data)
 {
 	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
@@ -289,7 +284,7 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
 	 */
 	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
 	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
-	rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+	rt2x00_set_field32(&reg, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON));
 	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
 	rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync);
 	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
@@ -424,7 +419,7 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev,
 }
 
 static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-				     const int antenna_tx, const int antenna_rx)
+				     struct antenna_setup *ant)
 {
 	u32 reg;
 	u8 r14;
@@ -437,18 +432,20 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev,
 	/*
 	 * Configure the TX antenna.
 	 */
-	switch (antenna_tx) {
-	case ANTENNA_SW_DIVERSITY:
-	case ANTENNA_HW_DIVERSITY:
-		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
-		rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
-		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
-		break;
+	switch (ant->tx) {
 	case ANTENNA_A:
 		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
 		rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
 		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
 		break;
+	case ANTENNA_HW_DIVERSITY:
+	case ANTENNA_SW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
 	case ANTENNA_B:
 		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
 		rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
@@ -459,14 +456,18 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev,
 	/*
 	 * Configure the RX antenna.
 	 */
-	switch (antenna_rx) {
-	case ANTENNA_SW_DIVERSITY:
-	case ANTENNA_HW_DIVERSITY:
-		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
-		break;
+	switch (ant->rx) {
 	case ANTENNA_A:
 		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
 		break;
+	case ANTENNA_HW_DIVERSITY:
+	case ANTENNA_SW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
 	case ANTENNA_B:
 		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
 		break;
@@ -541,9 +542,7 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,
 		rt2500pci_config_txpower(rt2x00dev,
 					 libconf->conf->power_level);
 	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt2500pci_config_antenna(rt2x00dev,
-					 libconf->conf->antenna_sel_tx,
-					 libconf->conf->antenna_sel_rx);
+		rt2500pci_config_antenna(rt2x00dev, &libconf->ant);
 	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
 		rt2500pci_config_duration(rt2x00dev, libconf);
 }
@@ -559,18 +558,10 @@ static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev)
 
 	rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
 	rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
-
-	if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
-		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
-		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
-	} else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
-		rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
-		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
-	} else {
-		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
-		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
-	}
-
+	rt2x00_set_field32(&reg, LEDCSR_LINK,
+			   (rt2x00dev->led_mode != LED_MODE_ASUS));
+	rt2x00_set_field32(&reg, LEDCSR_ACTIVITY,
+			   (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
 	rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
 }
 
@@ -587,7 +578,8 @@ static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev)
 /*
  * Link tuning
  */
-static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev)
+static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev,
+				 struct link_qual *qual)
 {
 	u32 reg;
 
@@ -595,13 +587,13 @@ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev)
 	 * Update FCS error count from register.
 	 */
 	rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
-	rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
+	qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
 
 	/*
 	 * Update False CCA count from register.
 	 */
 	rt2x00pci_register_read(rt2x00dev, CNT3, &reg);
-	rt2x00dev->link.false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA);
+	qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA);
 }
 
 static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
@@ -679,10 +671,10 @@ dynamic_cca_tune:
 	 * R17 is inside the dynamic tuning range,
 	 * start tuning the link based on the false cca counter.
 	 */
-	if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) {
+	if (rt2x00dev->link.qual.false_cca > 512 && r17 < 0x40) {
 		rt2500pci_bbp_write(rt2x00dev, 17, ++r17);
 		rt2x00dev->link.vgc_level = r17;
-	} else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) {
+	} else if (rt2x00dev->link.qual.false_cca < 100 && r17 > 0x32) {
 		rt2500pci_bbp_write(rt2x00dev, 17, --r17);
 		rt2x00dev->link.vgc_level = r17;
 	}
@@ -691,55 +683,35 @@ dynamic_cca_tune:
 /*
  * Initialization functions.
  */
-static void rt2500pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
+				   struct data_entry *entry)
 {
-	struct data_ring *ring = rt2x00dev->rx;
-	struct data_desc *rxd;
-	unsigned int i;
+	__le32 *rxd = entry->priv;
 	u32 word;
 
-	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
-
-	for (i = 0; i < ring->stats.limit; i++) {
-		rxd = ring->entry[i].priv;
-
-		rt2x00_desc_read(rxd, 1, &word);
-		rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS,
-				   ring->entry[i].data_dma);
-		rt2x00_desc_write(rxd, 1, word);
-
-		rt2x00_desc_read(rxd, 0, &word);
-		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-		rt2x00_desc_write(rxd, 0, word);
-	}
+	rt2x00_desc_read(rxd, 1, &word);
+	rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry->data_dma);
+	rt2x00_desc_write(rxd, 1, word);
 
-	rt2x00_ring_index_clear(rt2x00dev->rx);
+	rt2x00_desc_read(rxd, 0, &word);
+	rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+	rt2x00_desc_write(rxd, 0, word);
 }
 
-static void rt2500pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev,
+				   struct data_entry *entry)
 {
-	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
-	struct data_desc *txd;
-	unsigned int i;
+	__le32 *txd = entry->priv;
 	u32 word;
 
-	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
-
-	for (i = 0; i < ring->stats.limit; i++) {
-		txd = ring->entry[i].priv;
-
-		rt2x00_desc_read(txd, 1, &word);
-		rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS,
-				   ring->entry[i].data_dma);
-		rt2x00_desc_write(txd, 1, word);
-
-		rt2x00_desc_read(txd, 0, &word);
-		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-		rt2x00_desc_write(txd, 0, word);
-	}
+	rt2x00_desc_read(txd, 1, &word);
+	rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry->data_dma);
+	rt2x00_desc_write(txd, 1, word);
 
-	rt2x00_ring_index_clear(ring);
+	rt2x00_desc_read(txd, 0, &word);
+	rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+	rt2x00_desc_write(txd, 0, word);
 }
 
 static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev)
@@ -747,15 +719,6 @@ static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev)
 	u32 reg;
 
 	/*
-	 * Initialize rings.
-	 */
-	rt2500pci_init_rxring(rt2x00dev);
-	rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
-	rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
-	rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
-	rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
-
-	/*
 	 * Initialize registers.
 	 */
 	rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
@@ -1170,12 +1133,12 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
  * TX descriptor initialization
  */
 static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-				    struct data_desc *txd,
+				    struct sk_buff *skb,
 				    struct txdata_entry_desc *desc,
-				    struct ieee80211_hdr *ieee80211hdr,
-				    unsigned int length,
 				    struct ieee80211_tx_control *control)
 {
+	struct skb_desc *skbdesc = get_skb_desc(skb);
+	__le32 *txd = skbdesc->desc;
 	u32 word;
 
 	/*
@@ -1206,7 +1169,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
 			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_ACK,
-			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
+			   test_bit(ENTRY_TXD_ACK, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
 			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_OFDM,
@@ -1216,7 +1179,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
 			   !!(control->flags &
 			      IEEE80211_TXCTL_LONG_RETRY_LIMIT));
-	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
 	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
 	rt2x00_desc_write(txd, 0, word);
 }
@@ -1239,12 +1202,12 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 	}
 
 	rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
-	if (queue == IEEE80211_TX_QUEUE_DATA0)
-		rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
-	else if (queue == IEEE80211_TX_QUEUE_DATA1)
-		rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
-	else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
-		rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+	rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO,
+			   (queue == IEEE80211_TX_QUEUE_DATA0));
+	rt2x00_set_field32(&reg, TXCSR0_KICK_TX,
+			   (queue == IEEE80211_TX_QUEUE_DATA1));
+	rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM,
+			   (queue == IEEE80211_TX_QUEUE_AFTER_BEACON));
 	rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
 }
 
@@ -1254,7 +1217,7 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 static void rt2500pci_fill_rxdone(struct data_entry *entry,
 				  struct rxdata_entry_desc *desc)
 {
-	struct data_desc *rxd = entry->priv;
+	__le32 *rxd = entry->priv;
 	u32 word0;
 	u32 word2;
 
@@ -1272,6 +1235,7 @@ static void rt2500pci_fill_rxdone(struct data_entry *entry,
 	    entry->ring->rt2x00dev->rssi_offset;
 	desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
 	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+	desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
 }
 
 /*
@@ -1281,7 +1245,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
 {
 	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
 	struct data_entry *entry;
-	struct data_desc *txd;
+	__le32 *txd;
 	u32 word;
 	int tx_status;
 	int retry;
@@ -1301,26 +1265,8 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
 		tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
 		retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
 
-		rt2x00lib_txdone(entry, tx_status, retry);
-
-		/*
-		 * Make this entry available for reuse.
-		 */
-		entry->flags = 0;
-		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-		rt2x00_desc_write(txd, 0, word);
-		rt2x00_ring_index_done_inc(ring);
+		rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry);
 	}
-
-	/*
-	 * If the data ring was full before the txdone handler
-	 * we must make sure the packet queue in the mac80211 stack
-	 * is reenabled when the txdone handler has finished.
-	 */
-	entry = ring->entry;
-	if (!rt2x00_ring_full(ring))
-		ieee80211_wake_queue(rt2x00dev->hw,
-				     entry->tx_status.control.queue);
 }
 
 static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
@@ -1420,9 +1366,12 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
 	if (word == 0xffff) {
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
-		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0);
-		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0);
-		rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT,
+				   ANTENNA_SW_DIVERSITY);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT,
+				   ANTENNA_SW_DIVERSITY);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE,
+				   LED_MODE_DEFAULT);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
@@ -1481,9 +1430,9 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Identify default antenna configuration.
 	 */
-	rt2x00dev->hw->conf.antenna_sel_tx =
+	rt2x00dev->default_ant.tx =
 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
-	rt2x00dev->hw->conf.antenna_sel_rx =
+	rt2x00dev->default_ant.rx =
 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
 
 	/*
@@ -1774,7 +1723,6 @@ static void rt2500pci_configure_filter(struct ieee80211_hw *hw,
 				       struct dev_addr_list *mc_list)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct interface *intf = &rt2x00dev->interface;
 	u32 reg;
 
 	/*
@@ -1793,22 +1741,19 @@ static void rt2500pci_configure_filter(struct ieee80211_hw *hw,
 	 * Apply some rules to the filters:
 	 * - Some filters imply different filters to be set.
 	 * - Some things we can't filter out at all.
-	 * - Some filters are set based on interface type.
 	 */
 	if (mc_count)
 		*total_flags |= FIF_ALLMULTI;
 	if (*total_flags & FIF_OTHER_BSS ||
 	    *total_flags & FIF_PROMISC_IN_BSS)
 		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
-	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
-		*total_flags |= FIF_PROMISC_IN_BSS;
 
 	/*
 	 * Check if there is any work left for us.
 	 */
-	if (intf->filter == *total_flags)
+	if (rt2x00dev->packet_filter == *total_flags)
 		return;
-	intf->filter = *total_flags;
+	rt2x00dev->packet_filter = *total_flags;
 
 	/*
 	 * Start configuration steps.
@@ -1890,7 +1835,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
 	.configure_filter	= rt2500pci_configure_filter,
 	.get_stats		= rt2x00mac_get_stats,
 	.set_retry_limit	= rt2500pci_set_retry_limit,
-	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
+	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt2500pci_get_tsf,
@@ -1904,6 +1849,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
 	.probe_hw		= rt2500pci_probe_hw,
 	.initialize		= rt2x00pci_initialize,
 	.uninitialize		= rt2x00pci_uninitialize,
+	.init_rxentry		= rt2500pci_init_rxentry,
+	.init_txentry		= rt2500pci_init_txentry,
 	.set_device_state	= rt2500pci_set_device_state,
 	.rfkill_poll		= rt2500pci_rfkill_poll,
 	.link_stats		= rt2500pci_link_stats,
@@ -1921,7 +1868,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
 };
 
 static const struct rt2x00_ops rt2500pci_ops = {
-	.name		= DRV_NAME,
+	.name		= KBUILD_MODNAME,
 	.rxd_size	= RXD_DESC_SIZE,
 	.txd_size	= TXD_DESC_SIZE,
 	.eeprom_size	= EEPROM_SIZE,
@@ -1949,7 +1896,7 @@ MODULE_DEVICE_TABLE(pci, rt2500pci_device_table);
 MODULE_LICENSE("GPL");
 
 static struct pci_driver rt2500pci_driver = {
-	.name		= DRV_NAME,
+	.name		= KBUILD_MODNAME,
 	.id_table	= rt2500pci_device_table,
 	.probe		= rt2x00pci_probe,
 	.remove		= __devexit_p(rt2x00pci_remove),
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index d92aa56b2f4b..92ba0902d107 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -1082,8 +1082,8 @@
 /*
  * DMA descriptor defines.
  */
-#define TXD_DESC_SIZE			( 11 * sizeof(struct data_desc) )
-#define RXD_DESC_SIZE			( 11 * sizeof(struct data_desc) )
+#define TXD_DESC_SIZE			( 11 * sizeof(__le32) )
+#define RXD_DESC_SIZE			( 11 * sizeof(__le32) )
 
 /*
  * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 18b1f9145389..86ded4066f5b 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -24,11 +24,6 @@
 	Supported chipsets: RT2570.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2500usb"
-
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
@@ -52,8 +47,10 @@
  * between each attampt. When the busy bit is still set at that time,
  * the access attempt is considered to have failed,
  * and we will print an error.
+ * If the usb_cache_mutex is already held then the _lock variants must
+ * be used instead.
  */
-static inline void rt2500usb_register_read(const struct rt2x00_dev *rt2x00dev,
+static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
 					   const unsigned int offset,
 					   u16 *value)
 {
@@ -64,8 +61,18 @@ static inline void rt2500usb_register_read(const struct rt2x00_dev *rt2x00dev,
 	*value = le16_to_cpu(reg);
 }
 
-static inline void rt2500usb_register_multiread(const struct rt2x00_dev
-						*rt2x00dev,
+static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
+						const unsigned int offset,
+						u16 *value)
+{
+	__le16 reg;
+	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
+				       USB_VENDOR_REQUEST_IN, offset,
+				       &reg, sizeof(u16), REGISTER_TIMEOUT);
+	*value = le16_to_cpu(reg);
+}
+
+static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev,
 						const unsigned int offset,
 						void *value, const u16 length)
 {
@@ -75,7 +82,7 @@ static inline void rt2500usb_register_multiread(const struct rt2x00_dev
 				      value, length, timeout);
 }
 
-static inline void rt2500usb_register_write(const struct rt2x00_dev *rt2x00dev,
+static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
 					    const unsigned int offset,
 					    u16 value)
 {
@@ -85,8 +92,17 @@ static inline void rt2500usb_register_write(const struct rt2x00_dev *rt2x00dev,
 				      &reg, sizeof(u16), REGISTER_TIMEOUT);
 }
 
-static inline void rt2500usb_register_multiwrite(const struct rt2x00_dev
-						 *rt2x00dev,
+static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
+						 const unsigned int offset,
+						 u16 value)
+{
+	__le16 reg = cpu_to_le16(value);
+	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
+				       USB_VENDOR_REQUEST_OUT, offset,
+				       &reg, sizeof(u16), REGISTER_TIMEOUT);
+}
+
+static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
 						 const unsigned int offset,
 						 void *value, const u16 length)
 {
@@ -96,13 +112,13 @@ static inline void rt2500usb_register_multiwrite(const struct rt2x00_dev
 				      value, length, timeout);
 }
 
-static u16 rt2500usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
+static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev)
 {
 	u16 reg;
 	unsigned int i;
 
 	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2500usb_register_read(rt2x00dev, PHY_CSR8, &reg);
+		rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, &reg);
 		if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
 			break;
 		udelay(REGISTER_BUSY_DELAY);
@@ -111,17 +127,20 @@ static u16 rt2500usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
 	return reg;
 }
 
-static void rt2500usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
+static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, const u8 value)
 {
 	u16 reg;
 
+	mutex_lock(&rt2x00dev->usb_cache_mutex);
+
 	/*
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt2500usb_bbp_check(rt2x00dev);
 	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
 		ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
+		mutex_unlock(&rt2x00dev->usb_cache_mutex);
 		return;
 	}
 
@@ -133,14 +152,18 @@ static void rt2500usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
 	rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
 
-	rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
+
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
-static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
+static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, u8 *value)
 {
 	u16 reg;
 
+	mutex_lock(&rt2x00dev->usb_cache_mutex);
+
 	/*
 	 * Wait until the BBP becomes ready.
 	 */
@@ -157,7 +180,7 @@ static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
 	rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
 
-	rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg);
 
 	/*
 	 * Wait until the BBP becomes ready.
@@ -166,14 +189,17 @@ static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
 	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
 		ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
 		*value = 0xff;
+		mutex_unlock(&rt2x00dev->usb_cache_mutex);
 		return;
 	}
 
-	rt2500usb_register_read(rt2x00dev, PHY_CSR7, &reg);
+	rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, &reg);
 	*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
+
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
-static void rt2500usb_rf_write(const struct rt2x00_dev *rt2x00dev,
+static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, const u32 value)
 {
 	u16 reg;
@@ -182,20 +208,23 @@ static void rt2500usb_rf_write(const struct rt2x00_dev *rt2x00dev,
 	if (!word)
 		return;
 
+	mutex_lock(&rt2x00dev->usb_cache_mutex);
+
 	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt2500usb_register_read(rt2x00dev, PHY_CSR10, &reg);
+		rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, &reg);
 		if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
 			goto rf_write;
 		udelay(REGISTER_BUSY_DELAY);
 	}
 
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
 	ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
 	return;
 
 rf_write:
 	reg = 0;
 	rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
-	rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg);
+	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg);
 
 	reg = 0;
 	rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
@@ -203,20 +232,22 @@ rf_write:
 	rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
 	rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
 
-	rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg);
+	rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg);
 	rt2x00_rf_write(rt2x00dev, word, value);
+
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 #define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u16)) )
 
-static void rt2500usb_read_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt2500usb_read_csr(struct rt2x00_dev *rt2x00dev,
 			       const unsigned int word, u32 *data)
 {
 	rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data);
 }
 
-static void rt2500usb_write_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt2500usb_write_csr(struct rt2x00_dev *rt2x00dev,
 				const unsigned int word, u32 data)
 {
 	rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
@@ -296,7 +327,8 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
 
 	rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
 	rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
-	rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
+	rt2x00_set_field16(&reg, TXRX_CSR19_TBCN,
+			   (tsf_sync == TSF_SYNC_BEACON));
 	rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
 	rt2x00_set_field16(&reg, TXRX_CSR19_TSF_SYNC, tsf_sync);
 	rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
@@ -385,7 +417,7 @@ static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
 }
 
 static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
-				     const int antenna_tx, const int antenna_rx)
+				     struct antenna_setup *ant)
 {
 	u8 r2;
 	u8 r14;
@@ -400,8 +432,7 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
 	/*
 	 * Configure the TX antenna.
 	 */
-	switch (antenna_tx) {
-	case ANTENNA_SW_DIVERSITY:
+	switch (ant->tx) {
 	case ANTENNA_HW_DIVERSITY:
 		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 1);
 		rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 1);
@@ -412,6 +443,13 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
 		rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0);
 		rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0);
 		break;
+	case ANTENNA_SW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
 	case ANTENNA_B:
 		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
 		rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2);
@@ -422,14 +460,20 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
 	/*
 	 * Configure the RX antenna.
 	 */
-	switch (antenna_rx) {
-	case ANTENNA_SW_DIVERSITY:
+	switch (ant->rx) {
 	case ANTENNA_HW_DIVERSITY:
 		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 1);
 		break;
 	case ANTENNA_A:
 		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
 		break;
+	case ANTENNA_SW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
 	case ANTENNA_B:
 		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
 		break;
@@ -487,9 +531,7 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev,
 		rt2500usb_config_txpower(rt2x00dev,
 					 libconf->conf->power_level);
 	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt2500usb_config_antenna(rt2x00dev,
-					 libconf->conf->antenna_sel_tx,
-					 libconf->conf->antenna_sel_rx);
+		rt2500usb_config_antenna(rt2x00dev, &libconf->ant);
 	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
 		rt2500usb_config_duration(rt2x00dev, libconf);
 }
@@ -507,18 +549,10 @@ static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev)
 	rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg);
 
 	rt2500usb_register_read(rt2x00dev, MAC_CSR20, &reg);
-
-	if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
-		rt2x00_set_field16(&reg, MAC_CSR20_LINK, 1);
-		rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 0);
-	} else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
-		rt2x00_set_field16(&reg, MAC_CSR20_LINK, 0);
-		rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 1);
-	} else {
-		rt2x00_set_field16(&reg, MAC_CSR20_LINK, 1);
-		rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 1);
-	}
-
+	rt2x00_set_field16(&reg, MAC_CSR20_LINK,
+			   (rt2x00dev->led_mode != LED_MODE_ASUS));
+	rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY,
+			   (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
 	rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
 }
 
@@ -535,7 +569,8 @@ static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev)
 /*
  * Link tuning
  */
-static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev)
+static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev,
+				 struct link_qual *qual)
 {
 	u16 reg;
 
@@ -543,14 +578,13 @@ static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev)
 	 * Update FCS error count from register.
 	 */
 	rt2500usb_register_read(rt2x00dev, STA_CSR0, &reg);
-	rt2x00dev->link.rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR);
+	qual->rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR);
 
 	/*
 	 * Update False CCA count from register.
 	 */
 	rt2500usb_register_read(rt2x00dev, STA_CSR3, &reg);
-	rt2x00dev->link.false_cca =
-	    rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR);
+	qual->false_cca = rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR);
 }
 
 static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
@@ -673,10 +707,10 @@ static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev)
 	if (r17 > up_bound) {
 		rt2500usb_bbp_write(rt2x00dev, 17, up_bound);
 		rt2x00dev->link.vgc_level = up_bound;
-	} else if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+	} else if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) {
 		rt2500usb_bbp_write(rt2x00dev, 17, ++r17);
 		rt2x00dev->link.vgc_level = r17;
-	} else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+	} else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) {
 		rt2500usb_bbp_write(rt2x00dev, 17, --r17);
 		rt2x00dev->link.vgc_level = r17;
 	}
@@ -755,9 +789,11 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
 
 	if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
 		rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
-		reg &= ~0x0002;
+		rt2x00_set_field16(&reg, PHY_CSR2_LNA, 0);
 	} else {
-		reg = 0x3002;
+		reg = 0;
+		rt2x00_set_field16(&reg, PHY_CSR2_LNA, 1);
+		rt2x00_set_field16(&reg, PHY_CSR2_LNA_MODE, 3);
 	}
 	rt2500usb_register_write(rt2x00dev, PHY_CSR2, reg);
 
@@ -884,8 +920,6 @@ static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 		return -EIO;
 	}
 
-	rt2x00usb_enable_radio(rt2x00dev);
-
 	/*
 	 * Enable LED
 	 */
@@ -988,12 +1022,12 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
  * TX descriptor initialization
  */
 static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-				    struct data_desc *txd,
+				    struct sk_buff *skb,
 				    struct txdata_entry_desc *desc,
-				    struct ieee80211_hdr *ieee80211hdr,
-				    unsigned int length,
 				    struct ieee80211_tx_control *control)
 {
+	struct skb_desc *skbdesc = get_skb_desc(skb);
+	__le32 *txd = skbdesc->desc;
 	u32 word;
 
 	/*
@@ -1018,7 +1052,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
 			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_ACK,
-			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
+			   test_bit(ENTRY_TXD_ACK, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
 			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_OFDM,
@@ -1026,7 +1060,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
 			   !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT));
 	rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
-	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
 	rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
 	rt2x00_desc_write(txd, 0, word);
 }
@@ -1079,10 +1113,10 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 static void rt2500usb_fill_rxdone(struct data_entry *entry,
 				  struct rxdata_entry_desc *desc)
 {
+	struct skb_desc *skbdesc = get_skb_desc(entry->skb);
 	struct urb *urb = entry->priv;
-	struct data_desc *rxd = (struct data_desc *)(entry->skb->data +
-						     (urb->actual_length -
-						      entry->ring->desc_size));
+	__le32 *rxd = (__le32 *)(entry->skb->data +
+				 (urb->actual_length - entry->ring->desc_size));
 	u32 word0;
 	u32 word1;
 
@@ -1103,8 +1137,15 @@ static void rt2500usb_fill_rxdone(struct data_entry *entry,
 	    entry->ring->rt2x00dev->rssi_offset;
 	desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
 	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+	desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
 
-	return;
+	/*
+	 * Set descriptor and data pointer.
+	 */
+	skbdesc->desc = entry->skb->data + desc->size;
+	skbdesc->desc_len = entry->ring->desc_size;
+	skbdesc->data = entry->skb->data;
+	skbdesc->data_len = desc->size;
 }
 
 /*
@@ -1163,9 +1204,12 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
 	if (word == 0xffff) {
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
-		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0);
-		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0);
-		rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT,
+				   ANTENNA_SW_DIVERSITY);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT,
+				   ANTENNA_SW_DIVERSITY);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE,
+				   LED_MODE_DEFAULT);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
@@ -1275,12 +1319,23 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Identify default antenna configuration.
 	 */
-	rt2x00dev->hw->conf.antenna_sel_tx =
+	rt2x00dev->default_ant.tx =
 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
-	rt2x00dev->hw->conf.antenna_sel_rx =
+	rt2x00dev->default_ant.rx =
 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
 
 	/*
+	 * When the eeprom indicates SW_DIVERSITY use HW_DIVERSITY instead.
+	 * I am not 100% sure about this, but the legacy drivers do not
+	 * indicate antenna swapping in software is required when
+	 * diversity is enabled.
+	 */
+	if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
+		rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY;
+	if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
+		rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY;
+
+	/*
 	 * Store led mode, for correct led behaviour.
 	 */
 	rt2x00dev->led_mode =
@@ -1562,7 +1617,6 @@ static void rt2500usb_configure_filter(struct ieee80211_hw *hw,
 				       struct dev_addr_list *mc_list)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct interface *intf = &rt2x00dev->interface;
 	u16 reg;
 
 	/*
@@ -1581,22 +1635,19 @@ static void rt2500usb_configure_filter(struct ieee80211_hw *hw,
 	 * Apply some rules to the filters:
 	 * - Some filters imply different filters to be set.
 	 * - Some things we can't filter out at all.
-	 * - Some filters are set based on interface type.
 	 */
 	if (mc_count)
 		*total_flags |= FIF_ALLMULTI;
 	if (*total_flags & FIF_OTHER_BSS ||
 	    *total_flags & FIF_PROMISC_IN_BSS)
 		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
-	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
-		*total_flags |= FIF_PROMISC_IN_BSS;
 
 	/*
 	 * Check if there is any work left for us.
 	 */
-	if (intf->filter == *total_flags)
+	if (rt2x00dev->packet_filter == *total_flags)
 		return;
-	intf->filter = *total_flags;
+	rt2x00dev->packet_filter = *total_flags;
 
 	/*
 	 * When in atomic context, reschedule and let rt2x00lib
@@ -1638,8 +1689,8 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	struct usb_device *usb_dev =
 	    interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
-	struct data_ring *ring =
-	    rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+	struct skb_desc *desc;
+	struct data_ring *ring;
 	struct data_entry *beacon;
 	struct data_entry *guardian;
 	int pipe = usb_sndbulkpipe(usb_dev, 1);
@@ -1651,6 +1702,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
 	 * initialization.
 	 */
 	control->queue = IEEE80211_TX_QUEUE_BEACON;
+	ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
 
 	/*
 	 * Obtain 2 entries, one for the guardian byte,
@@ -1661,23 +1713,34 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
 	beacon = rt2x00_get_data_entry(ring);
 
 	/*
-	 * First we create the beacon.
+	 * Add the descriptor in front of the skb.
 	 */
 	skb_push(skb, ring->desc_size);
 	memset(skb->data, 0, ring->desc_size);
 
-	rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
-				(struct ieee80211_hdr *)(skb->data +
-							 ring->desc_size),
-				skb->len - ring->desc_size, control);
+	/*
+	 * Fill in skb descriptor
+	 */
+	desc = get_skb_desc(skb);
+	desc->desc_len = ring->desc_size;
+	desc->data_len = skb->len - ring->desc_size;
+	desc->desc = skb->data;
+	desc->data = skb->data + ring->desc_size;
+	desc->ring = ring;
+	desc->entry = beacon;
+
+	rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
 
+	/*
+	 * USB devices cannot blindly pass the skb->len as the
+	 * length of the data to usb_fill_bulk_urb. Pass the skb
+	 * to the driver to determine what the length should be.
+	 */
 	length = rt2500usb_get_tx_data_len(rt2x00dev, skb);
 
 	usb_fill_bulk_urb(beacon->priv, usb_dev, pipe,
 			  skb->data, length, rt2500usb_beacondone, beacon);
 
-	beacon->skb = skb;
-
 	/*
 	 * Second we need to create the guardian byte.
 	 * We only need a single byte, so lets recycle
@@ -1710,7 +1773,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
 	.config_interface	= rt2x00mac_config_interface,
 	.configure_filter	= rt2500usb_configure_filter,
 	.get_stats		= rt2x00mac_get_stats,
-	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
+	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.beacon_update		= rt2500usb_beacon_update,
@@ -1720,6 +1783,8 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
 	.probe_hw		= rt2500usb_probe_hw,
 	.initialize		= rt2x00usb_initialize,
 	.uninitialize		= rt2x00usb_uninitialize,
+	.init_rxentry		= rt2x00usb_init_rxentry,
+	.init_txentry		= rt2x00usb_init_txentry,
 	.set_device_state	= rt2500usb_set_device_state,
 	.link_stats		= rt2500usb_link_stats,
 	.reset_tuner		= rt2500usb_reset_tuner,
@@ -1737,7 +1802,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
 };
 
 static const struct rt2x00_ops rt2500usb_ops = {
-	.name		= DRV_NAME,
+	.name		= KBUILD_MODNAME,
 	.rxd_size	= RXD_DESC_SIZE,
 	.txd_size	= TXD_DESC_SIZE,
 	.eeprom_size	= EEPROM_SIZE,
@@ -1809,7 +1874,7 @@ MODULE_DEVICE_TABLE(usb, rt2500usb_device_table);
 MODULE_LICENSE("GPL");
 
 static struct usb_driver rt2500usb_driver = {
-	.name		= DRV_NAME,
+	.name		= KBUILD_MODNAME,
 	.id_table	= rt2500usb_device_table,
 	.probe		= rt2x00usb_probe,
 	.disconnect	= rt2x00usb_disconnect,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index b18d56e73cf1..9e0433722e3d 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -430,10 +430,21 @@
 
 /*
  * MAC configuration registers.
+ */
+
+/*
  * PHY_CSR2: TX MAC configuration.
- * PHY_CSR3: RX MAC configuration.
+ * NOTE: Both register fields are complete dummy,
+ * documentation and legacy drivers are unclear un
+ * what this register means or what fields exists.
  */
 #define PHY_CSR2			0x04c4
+#define PHY_CSR2_LNA			FIELD16(0x0002)
+#define PHY_CSR2_LNA_MODE		FIELD16(0x3000)
+
+/*
+ * PHY_CSR3: RX MAC configuration.
+ */
 #define PHY_CSR3			0x04c6
 
 /*
@@ -692,8 +703,8 @@
 /*
  * DMA descriptor defines.
  */
-#define TXD_DESC_SIZE			( 5 * sizeof(struct data_desc) )
-#define RXD_DESC_SIZE			( 4 * sizeof(struct data_desc) )
+#define TXD_DESC_SIZE			( 5 * sizeof(__le32) )
+#define RXD_DESC_SIZE			( 4 * sizeof(__le32) )
 
 /*
  * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index c8f16f161c28..05927b908f80 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -31,6 +31,8 @@
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <linux/firmware.h>
+#include <linux/mutex.h>
+#include <linux/etherdevice.h>
 
 #include <net/mac80211.h>
 
@@ -40,9 +42,8 @@
 
 /*
  * Module information.
- * DRV_NAME should be set within the individual module source files.
  */
-#define DRV_VERSION	"2.0.10"
+#define DRV_VERSION	"2.0.14"
 #define DRV_PROJECT	"http://rt2x00.serialmonkey.com"
 
 /*
@@ -55,7 +56,7 @@
 
 #define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...)	\
 	printk(__kernlvl "%s -> %s: %s - " __msg,		\
-	       DRV_NAME, __FUNCTION__, __lvl, ##__args)
+	       KBUILD_MODNAME, __FUNCTION__, __lvl, ##__args)
 
 #ifdef CONFIG_RT2X00_DEBUG
 #define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...)	\
@@ -133,20 +134,26 @@
  */
 static inline int is_rts_frame(u16 fc)
 {
-	return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-		  ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS));
+	return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+		((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS));
 }
 
 static inline int is_cts_frame(u16 fc)
 {
-	return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
-		  ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS));
+	return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+		((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS));
 }
 
 static inline int is_probe_resp(u16 fc)
 {
-	return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
-		  ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP));
+	return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+		((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP));
+}
+
+static inline int is_beacon(u16 fc)
+{
+	return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+		((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON));
 }
 
 /*
@@ -180,18 +187,17 @@ struct rf_channel {
 };
 
 /*
- * To optimize the quality of the link we need to store
- * the quality of received frames and periodically
- * optimize the link.
+ * Antenna setup values.
  */
-struct link {
-	/*
-	 * Link tuner counter
-	 * The number of times the link has been tuned
-	 * since the radio has been switched on.
-	 */
-	u32 count;
+struct antenna_setup {
+	enum antenna rx;
+	enum antenna tx;
+};
 
+/*
+ * Quality statistics about the currently active link.
+ */
+struct link_qual {
 	/*
 	 * Statistics required for Link tuning.
 	 * For the average RSSI value we use the "Walking average" approach.
@@ -211,7 +217,6 @@ struct link {
 	 * the new values correctly allowing a effective link tuning.
 	 */
 	int avg_rssi;
-	int vgc_level;
 	int false_cca;
 
 	/*
@@ -240,6 +245,72 @@ struct link {
 #define WEIGHT_RSSI	20
 #define WEIGHT_RX	40
 #define WEIGHT_TX	40
+};
+
+/*
+ * Antenna settings about the currently active link.
+ */
+struct link_ant {
+	/*
+	 * Antenna flags
+	 */
+	unsigned int flags;
+#define ANTENNA_RX_DIVERSITY	0x00000001
+#define ANTENNA_TX_DIVERSITY	0x00000002
+#define ANTENNA_MODE_SAMPLE	0x00000004
+
+	/*
+	 * Currently active TX/RX antenna setup.
+	 * When software diversity is used, this will indicate
+	 * which antenna is actually used at this time.
+	 */
+	struct antenna_setup active;
+
+	/*
+	 * RSSI information for the different antenna's.
+	 * These statistics are used to determine when
+	 * to switch antenna when using software diversity.
+	 *
+	 *        rssi[0] -> Antenna A RSSI
+	 *        rssi[1] -> Antenna B RSSI
+	 */
+	int rssi_history[2];
+
+	/*
+	 * Current RSSI average of the currently active antenna.
+	 * Similar to the avg_rssi in the link_qual structure
+	 * this value is updated by using the walking average.
+	 */
+	int rssi_ant;
+};
+
+/*
+ * To optimize the quality of the link we need to store
+ * the quality of received frames and periodically
+ * optimize the link.
+ */
+struct link {
+	/*
+	 * Link tuner counter
+	 * The number of times the link has been tuned
+	 * since the radio has been switched on.
+	 */
+	u32 count;
+
+	/*
+	 * Quality measurement values.
+	 */
+	struct link_qual qual;
+
+	/*
+	 * TX/RX antenna setup.
+	 */
+	struct link_ant ant;
+
+	/*
+	 * Active VGC level
+	 */
+	int vgc_level;
 
 	/*
 	 * Work structure for scheduling periodic link tuning.
@@ -248,36 +319,47 @@ struct link {
 };
 
 /*
- * Clear all counters inside the link structure.
- * This can be easiest achieved by memsetting everything
- * except for the work structure at the end.
+ * Small helper macro to work with moving/walking averages.
  */
-static inline void rt2x00_clear_link(struct link *link)
-{
-	memset(link, 0x00, sizeof(*link) - sizeof(link->work));
-	link->rx_percentage = 50;
-	link->tx_percentage = 50;
-}
+#define MOVING_AVERAGE(__avg, __val, __samples) \
+	( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) )
 
 /*
- * Update the rssi using the walking average approach.
+ * When we lack RSSI information return something less then -80 to
+ * tell the driver to tune the device to maximum sensitivity.
  */
-static inline void rt2x00_update_link_rssi(struct link *link, int rssi)
-{
-	if (!link->avg_rssi)
-		link->avg_rssi = rssi;
-	else
-		link->avg_rssi = ((link->avg_rssi * 7) + rssi) / 8;
-}
+#define DEFAULT_RSSI	( -128 )
 
 /*
- * When the avg_rssi is unset or no frames  have been received),
- * we need to return the default value which needs to be less
- * than -80 so the device will select the maximum sensitivity.
+ * Link quality access functions.
  */
 static inline int rt2x00_get_link_rssi(struct link *link)
 {
-	return (link->avg_rssi && link->rx_success) ? link->avg_rssi : -128;
+	if (link->qual.avg_rssi && link->qual.rx_success)
+		return link->qual.avg_rssi;
+	return DEFAULT_RSSI;
+}
+
+static inline int rt2x00_get_link_ant_rssi(struct link *link)
+{
+	if (link->ant.rssi_ant && link->qual.rx_success)
+		return link->ant.rssi_ant;
+	return DEFAULT_RSSI;
+}
+
+static inline int rt2x00_get_link_ant_rssi_history(struct link *link,
+						   enum antenna ant)
+{
+	if (link->ant.rssi_history[ant - ANTENNA_A])
+		return link->ant.rssi_history[ant - ANTENNA_A];
+	return DEFAULT_RSSI;
+}
+
+static inline int rt2x00_update_ant_rssi(struct link *link, int rssi)
+{
+	int old_rssi = link->ant.rssi_history[link->ant.active.rx - ANTENNA_A];
+	link->ant.rssi_history[link->ant.active.rx - ANTENNA_A] = rssi;
+	return old_rssi;
 }
 
 /*
@@ -290,14 +372,12 @@ struct interface {
 	 * to us by the 80211 stack, and is used to request
 	 * new beacons.
 	 */
-	int id;
+	struct ieee80211_vif *id;
 
 	/*
 	 * Current working type (IEEE80211_IF_TYPE_*).
-	 * When set to INVALID_INTERFACE, no interface is configured.
 	 */
 	int type;
-#define INVALID_INTERFACE	IEEE80211_IF_TYPE_INVALID
 
 	/*
 	 * MAC of the device.
@@ -308,11 +388,6 @@ struct interface {
 	 * BBSID of the AP to associate with.
 	 */
 	u8 bssid[ETH_ALEN];
-
-	/*
-	 * Store the packet filter mode for the current interface.
-	 */
-	unsigned int filter;
 };
 
 static inline int is_interface_present(struct interface *intf)
@@ -362,6 +437,8 @@ struct rt2x00lib_conf {
 	struct ieee80211_conf *conf;
 	struct rf_channel rf;
 
+	struct antenna_setup ant;
+
 	int phymode;
 
 	int basic_rates;
@@ -397,12 +474,21 @@ struct rt2x00lib_ops {
 	void (*uninitialize) (struct rt2x00_dev *rt2x00dev);
 
 	/*
+	 * Ring initialization handlers
+	 */
+	void (*init_rxentry) (struct rt2x00_dev *rt2x00dev,
+			      struct data_entry *entry);
+	void (*init_txentry) (struct rt2x00_dev *rt2x00dev,
+			      struct data_entry *entry);
+
+	/*
 	 * Radio control handlers.
 	 */
 	int (*set_device_state) (struct rt2x00_dev *rt2x00dev,
 				 enum dev_state state);
 	int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev);
-	void (*link_stats) (struct rt2x00_dev *rt2x00dev);
+	void (*link_stats) (struct rt2x00_dev *rt2x00dev,
+			    struct link_qual *qual);
 	void (*reset_tuner) (struct rt2x00_dev *rt2x00dev);
 	void (*link_tuner) (struct rt2x00_dev *rt2x00dev);
 
@@ -410,10 +496,8 @@ struct rt2x00lib_ops {
 	 * TX control handlers
 	 */
 	void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
-			       struct data_desc *txd,
+			       struct sk_buff *skb,
 			       struct txdata_entry_desc *desc,
-			       struct ieee80211_hdr *ieee80211hdr,
-			       unsigned int length,
 			       struct ieee80211_tx_control *control);
 	int (*write_tx_data) (struct rt2x00_dev *rt2x00dev,
 			      struct data_ring *ring, struct sk_buff *skb,
@@ -545,7 +629,7 @@ struct rt2x00_dev {
 	 * required for deregistration of debugfs.
 	 */
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
-	const struct rt2x00debug_intf *debugfs_intf;
+	struct rt2x00debug_intf *debugfs_intf;
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
 	/*
@@ -566,6 +650,13 @@ struct rt2x00_dev {
 	struct hw_mode_spec spec;
 
 	/*
+	 * This is the default TX/RX antenna setup as indicated
+	 * by the device's EEPROM. When mac80211 sets its
+	 * antenna value to 0 we should be using these values.
+	 */
+	struct antenna_setup default_ant;
+
+	/*
 	 * Register pointers
 	 * csr_addr: Base register address. (PCI)
 	 * csr_cache: CSR cache for usb_control_msg. (USB)
@@ -574,6 +665,25 @@ struct rt2x00_dev {
 	void *csr_cache;
 
 	/*
+	 * Mutex to protect register accesses on USB devices.
+	 * There are 2 reasons this is needed, one is to ensure
+	 * use of the csr_cache (for USB devices) by one thread
+	 * isn't corrupted by another thread trying to access it.
+	 * The other is that access to BBP and RF registers
+	 * require multiple BUS transactions and if another thread
+	 * attempted to access one of those registers at the same
+	 * time one of the writes could silently fail.
+	 */
+	struct mutex usb_cache_mutex;
+
+	/*
+	 * Current packet filter configuration for the device.
+	 * This contains all currently active FIF_* flags send
+	 * to us by mac80211 during configure_filter().
+	 */
+	unsigned int packet_filter;
+
+	/*
 	 * Interface configuration.
 	 */
 	struct interface interface;
@@ -697,13 +807,13 @@ struct rt2x00_dev {
  * Generic RF access.
  * The RF is being accessed by word index.
  */
-static inline void rt2x00_rf_read(const struct rt2x00_dev *rt2x00dev,
+static inline void rt2x00_rf_read(struct rt2x00_dev *rt2x00dev,
 				  const unsigned int word, u32 *data)
 {
 	*data = rt2x00dev->rf[word];
 }
 
-static inline void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev,
+static inline void rt2x00_rf_write(struct rt2x00_dev *rt2x00dev,
 				   const unsigned int word, u32 data)
 {
 	rt2x00dev->rf[word] = data;
@@ -713,19 +823,19 @@ static inline void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev,
  *  Generic EEPROM access.
  * The EEPROM is being accessed by word index.
  */
-static inline void *rt2x00_eeprom_addr(const struct rt2x00_dev *rt2x00dev,
+static inline void *rt2x00_eeprom_addr(struct rt2x00_dev *rt2x00dev,
 				       const unsigned int word)
 {
 	return (void *)&rt2x00dev->eeprom[word];
 }
 
-static inline void rt2x00_eeprom_read(const struct rt2x00_dev *rt2x00dev,
+static inline void rt2x00_eeprom_read(struct rt2x00_dev *rt2x00dev,
 				      const unsigned int word, u16 *data)
 {
 	*data = le16_to_cpu(rt2x00dev->eeprom[word]);
 }
 
-static inline void rt2x00_eeprom_write(const struct rt2x00_dev *rt2x00dev,
+static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev,
 				       const unsigned int word, u16 data)
 {
 	rt2x00dev->eeprom[word] = cpu_to_le16(data);
@@ -804,9 +914,7 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
  * TX descriptor initializer
  */
 void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-			     struct data_desc *txd,
-			     struct ieee80211_hdr *ieee80211hdr,
-			     unsigned int length,
+			     struct sk_buff *skb,
 			     struct ieee80211_tx_control *control);
 
 /*
@@ -821,14 +929,17 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
 				struct ieee80211_if_init_conf *conf);
 int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
-int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
+int rt2x00mac_config_interface(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
 			       struct ieee80211_if_conf *conf);
 int rt2x00mac_get_stats(struct ieee80211_hw *hw,
 			struct ieee80211_low_level_stats *stats);
 int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
 			   struct ieee80211_tx_queue_stats *stats);
-void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
-			      int cts_protection, int preamble);
+void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
+				struct ieee80211_vif *vif,
+				struct ieee80211_bss_conf *bss_conf,
+				u32 changes);
 int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
 		      const struct ieee80211_tx_queue_params *params);
 
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 12914cf7156c..72cfe00c1ed7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -23,11 +23,6 @@
 	Abstract: rt2x00 generic configuration routines.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2x00lib"
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 
@@ -94,12 +89,44 @@ void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type)
 	rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync);
 }
 
+void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
+			      enum antenna rx, enum antenna tx)
+{
+	struct rt2x00lib_conf libconf;
+
+	libconf.ant.rx = rx;
+	libconf.ant.tx = tx;
+
+	/*
+	 * Antenna setup changes require the RX to be disabled,
+	 * else the changes will be ignored by the device.
+	 */
+	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+
+	/*
+	 * Write new antenna setup to device and reset the link tuner.
+	 * The latter is required since we need to recalibrate the
+	 * noise-sensitivity ratio for the new setup.
+	 */
+	rt2x00dev->ops->lib->config(rt2x00dev, CONFIG_UPDATE_ANTENNA, &libconf);
+	rt2x00lib_reset_link_tuner(rt2x00dev);
+
+	rt2x00dev->link.ant.active.rx = libconf.ant.rx;
+	rt2x00dev->link.ant.active.tx = libconf.ant.tx;
+
+	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+}
+
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 		      struct ieee80211_conf *conf, const int force_config)
 {
 	struct rt2x00lib_conf libconf;
 	struct ieee80211_hw_mode *mode;
 	struct ieee80211_rate *rate;
+	struct antenna_setup *default_ant = &rt2x00dev->default_ant;
+	struct antenna_setup *active_ant = &rt2x00dev->link.ant.active;
 	int flags = 0;
 	int short_slot_time;
 
@@ -122,7 +149,39 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 		flags |= CONFIG_UPDATE_CHANNEL;
 	if (rt2x00dev->tx_power != conf->power_level)
 		flags |= CONFIG_UPDATE_TXPOWER;
-	if (rt2x00dev->rx_status.antenna == conf->antenna_sel_rx)
+
+	/*
+	 * Determining changes in the antenna setups request several checks:
+	 * antenna_sel_{r,t}x = 0
+	 *    -> Does active_{r,t}x match default_{r,t}x
+	 *    -> Is default_{r,t}x SW_DIVERSITY
+	 * antenna_sel_{r,t}x = 1/2
+	 *    -> Does active_{r,t}x match antenna_sel_{r,t}x
+	 * The reason for not updating the antenna while SW diversity
+	 * should be used is simple: Software diversity means that
+	 * we should switch between the antenna's based on the
+	 * quality. This means that the current antenna is good enough
+	 * to work with untill the link tuner decides that an antenna
+	 * switch should be performed.
+	 */
+	if (!conf->antenna_sel_rx &&
+	    default_ant->rx != ANTENNA_SW_DIVERSITY &&
+	    default_ant->rx != active_ant->rx)
+		flags |= CONFIG_UPDATE_ANTENNA;
+	else if (conf->antenna_sel_rx &&
+		 conf->antenna_sel_rx != active_ant->rx)
+		flags |= CONFIG_UPDATE_ANTENNA;
+	else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
+		flags |= CONFIG_UPDATE_ANTENNA;
+
+	if (!conf->antenna_sel_tx &&
+	    default_ant->tx != ANTENNA_SW_DIVERSITY &&
+	    default_ant->tx != active_ant->tx)
+		flags |= CONFIG_UPDATE_ANTENNA;
+	else if (conf->antenna_sel_tx &&
+		 conf->antenna_sel_tx != active_ant->tx)
+		flags |= CONFIG_UPDATE_ANTENNA;
+	else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
 		flags |= CONFIG_UPDATE_ANTENNA;
 
 	/*
@@ -171,6 +230,22 @@ config:
 		       sizeof(libconf.rf));
 	}
 
+	if (flags & CONFIG_UPDATE_ANTENNA) {
+		if (conf->antenna_sel_rx)
+			libconf.ant.rx = conf->antenna_sel_rx;
+		else if (default_ant->rx != ANTENNA_SW_DIVERSITY)
+			libconf.ant.rx = default_ant->rx;
+		else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
+			libconf.ant.rx = ANTENNA_B;
+
+		if (conf->antenna_sel_tx)
+			libconf.ant.tx = conf->antenna_sel_tx;
+		else if (default_ant->tx != ANTENNA_SW_DIVERSITY)
+			libconf.ant.tx = default_ant->tx;
+		else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
+			libconf.ant.tx = ANTENNA_B;
+	}
+
 	if (flags & CONFIG_UPDATE_SLOT_TIME) {
 		short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME;
 
@@ -196,10 +271,17 @@ config:
 	if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA))
 		rt2x00lib_reset_link_tuner(rt2x00dev);
 
-	rt2x00dev->curr_hwmode = libconf.phymode;
-	rt2x00dev->rx_status.phymode = conf->phymode;
+	if (flags & CONFIG_UPDATE_PHYMODE) {
+		rt2x00dev->curr_hwmode = libconf.phymode;
+		rt2x00dev->rx_status.phymode = conf->phymode;
+	}
+
 	rt2x00dev->rx_status.freq = conf->freq;
 	rt2x00dev->rx_status.channel = conf->channel;
 	rt2x00dev->tx_power = conf->power_level;
-	rt2x00dev->rx_status.antenna = conf->antenna_sel_rx;
+
+	if (flags & CONFIG_UPDATE_ANTENNA) {
+		rt2x00dev->link.ant.active.rx = libconf.ant.rx;
+		rt2x00dev->link.ant.active.tx = libconf.ant.tx;
+	}
 }
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 9275d6f9517e..b44a9f4b9b7f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -23,18 +23,15 @@
 	Abstract: rt2x00 debugfs specific routines.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2x00lib"
-
 #include <linux/debugfs.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/poll.h>
 #include <linux/uaccess.h>
 
 #include "rt2x00.h"
 #include "rt2x00lib.h"
+#include "rt2x00dump.h"
 
 #define PRINT_LINE_LEN_MAX 32
 
@@ -55,18 +52,22 @@ struct rt2x00debug_intf {
 	/*
 	 * Debugfs entries for:
 	 * - driver folder
-	 * - driver file
-	 * - chipset file
-	 * - device flags file
-	 * - register offset/value files
-	 * - eeprom offset/value files
-	 * - bbp offset/value files
-	 * - rf offset/value files
+	 *   - driver file
+	 *   - chipset file
+	 *   - device flags file
+	 *   - register folder
+	 *     - csr offset/value files
+	 *     - eeprom offset/value files
+	 *     - bbp offset/value files
+	 *     - rf offset/value files
+	 *   - frame dump folder
+	 *     - frame dump file
 	 */
 	struct dentry *driver_folder;
 	struct dentry *driver_entry;
 	struct dentry *chipset_entry;
 	struct dentry *dev_flags;
+	struct dentry *register_folder;
 	struct dentry *csr_off_entry;
 	struct dentry *csr_val_entry;
 	struct dentry *eeprom_off_entry;
@@ -75,6 +76,24 @@ struct rt2x00debug_intf {
 	struct dentry *bbp_val_entry;
 	struct dentry *rf_off_entry;
 	struct dentry *rf_val_entry;
+	struct dentry *frame_folder;
+	struct dentry *frame_dump_entry;
+
+	/*
+	 * The frame dump file only allows a single reader,
+	 * so we need to store the current state here.
+	 */
+	unsigned long frame_dump_flags;
+#define FRAME_DUMP_FILE_OPEN	1
+
+	/*
+	 * We queue each frame before dumping it to the user,
+	 * per read command we will pass a single skb structure
+	 * so we should be prepared to queue multiple sk buffers
+	 * before sending it to userspace.
+	 */
+	struct sk_buff_head frame_dump_skbqueue;
+	wait_queue_head_t frame_dump_waitqueue;
 
 	/*
 	 * Driver and chipset files will use a data buffer
@@ -93,6 +112,59 @@ struct rt2x00debug_intf {
 	unsigned int offset_rf;
 };
 
+void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+			    struct sk_buff *skb)
+{
+	struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
+	struct skb_desc *desc = get_skb_desc(skb);
+	struct sk_buff *skbcopy;
+	struct rt2x00dump_hdr *dump_hdr;
+	struct timeval timestamp;
+
+	do_gettimeofday(&timestamp);
+
+	if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
+		return;
+
+	if (skb_queue_len(&intf->frame_dump_skbqueue) > 20) {
+		DEBUG(rt2x00dev, "txrx dump queue length exceeded.\n");
+		return;
+	}
+
+	skbcopy = alloc_skb(sizeof(*dump_hdr) + desc->desc_len + desc->data_len,
+			    GFP_ATOMIC);
+	if (!skbcopy) {
+		DEBUG(rt2x00dev, "Failed to copy skb for dump.\n");
+		return;
+	}
+
+	dump_hdr = (struct rt2x00dump_hdr *)skb_put(skbcopy, sizeof(*dump_hdr));
+	dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION);
+	dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr));
+	dump_hdr->desc_length = cpu_to_le32(desc->desc_len);
+	dump_hdr->data_length = cpu_to_le32(desc->data_len);
+	dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
+	dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
+	dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev);
+	dump_hdr->type = cpu_to_le16(desc->frame_type);
+	dump_hdr->ring_index = desc->ring->queue_idx;
+	dump_hdr->entry_index = desc->entry->entry_idx;
+	dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
+	dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec);
+
+	memcpy(skb_put(skbcopy, desc->desc_len), desc->desc, desc->desc_len);
+	memcpy(skb_put(skbcopy, desc->data_len), desc->data, desc->data_len);
+
+	skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy);
+	wake_up_interruptible(&intf->frame_dump_waitqueue);
+
+	/*
+	 * Verify that the file has not been closed while we were working.
+	 */
+	if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
+		skb_queue_purge(&intf->frame_dump_skbqueue);
+}
+
 static int rt2x00debug_file_open(struct inode *inode, struct file *file)
 {
 	struct rt2x00debug_intf *intf = inode->i_private;
@@ -114,13 +186,96 @@ static int rt2x00debug_file_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
+static int rt2x00debug_open_ring_dump(struct inode *inode, struct file *file)
+{
+	struct rt2x00debug_intf *intf = inode->i_private;
+	int retval;
+
+	retval = rt2x00debug_file_open(inode, file);
+	if (retval)
+		return retval;
+
+	if (test_and_set_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)) {
+		rt2x00debug_file_release(inode, file);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int rt2x00debug_release_ring_dump(struct inode *inode, struct file *file)
+{
+	struct rt2x00debug_intf *intf = inode->i_private;
+
+	skb_queue_purge(&intf->frame_dump_skbqueue);
+
+	clear_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags);
+
+	return rt2x00debug_file_release(inode, file);
+}
+
+static ssize_t rt2x00debug_read_ring_dump(struct file *file,
+					  char __user *buf,
+					  size_t length,
+					  loff_t *offset)
+{
+	struct rt2x00debug_intf *intf = file->private_data;
+	struct sk_buff *skb;
+	size_t status;
+	int retval;
+
+	if (file->f_flags & O_NONBLOCK)
+		return -EAGAIN;
+
+	retval =
+	    wait_event_interruptible(intf->frame_dump_waitqueue,
+				     (skb =
+				     skb_dequeue(&intf->frame_dump_skbqueue)));
+	if (retval)
+		return retval;
+
+	status = min((size_t)skb->len, length);
+	if (copy_to_user(buf, skb->data, status)) {
+		status = -EFAULT;
+		goto exit;
+	}
+
+	*offset += status;
+
+exit:
+	kfree_skb(skb);
+
+	return status;
+}
+
+static unsigned int rt2x00debug_poll_ring_dump(struct file *file,
+					       poll_table *wait)
+{
+	struct rt2x00debug_intf *intf = file->private_data;
+
+	poll_wait(file, &intf->frame_dump_waitqueue, wait);
+
+	if (!skb_queue_empty(&intf->frame_dump_skbqueue))
+		return POLLOUT | POLLWRNORM;
+
+	return 0;
+}
+
+static const struct file_operations rt2x00debug_fop_ring_dump = {
+	.owner		= THIS_MODULE,
+	.read		= rt2x00debug_read_ring_dump,
+	.poll		= rt2x00debug_poll_ring_dump,
+	.open		= rt2x00debug_open_ring_dump,
+	.release	= rt2x00debug_release_ring_dump,
+};
+
 #define RT2X00DEBUGFS_OPS_READ(__name, __format, __type)	\
 static ssize_t rt2x00debug_read_##__name(struct file *file,	\
 					 char __user *buf,	\
 					 size_t length,		\
 					 loff_t *offset)	\
 {								\
-	struct rt2x00debug_intf *intf =	file->private_data;	\
+	struct rt2x00debug_intf *intf = file->private_data;	\
 	const struct rt2x00debug *debug = intf->debug;		\
 	char line[16];						\
 	size_t size;						\
@@ -150,7 +305,7 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,	\
 					  size_t length,	\
 					  loff_t *offset)	\
 {								\
-	struct rt2x00debug_intf *intf =	file->private_data;	\
+	struct rt2x00debug_intf *intf = file->private_data;	\
 	const struct rt2x00debug *debug = intf->debug;		\
 	char line[16];						\
 	size_t size;						\
@@ -254,11 +409,15 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
 	const struct rt2x00debug *debug = intf->debug;
 	char *data;
 
-	data = kzalloc(4 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
+	data = kzalloc(8 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
 	if (!data)
 		return NULL;
 
 	blob->data = data;
+	data += sprintf(data, "rt chip: %04x\n", intf->rt2x00dev->chip.rt);
+	data += sprintf(data, "rf chip: %04x\n", intf->rt2x00dev->chip.rf);
+	data += sprintf(data, "revision:%08x\n", intf->rt2x00dev->chip.rev);
+	data += sprintf(data, "\n");
 	data += sprintf(data, "csr length: %d\n", debug->csr.word_count);
 	data += sprintf(data, "eeprom length: %d\n", debug->eeprom.word_count);
 	data += sprintf(data, "bbp length: %d\n", debug->bbp.word_count);
@@ -306,12 +465,17 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 	if (IS_ERR(intf->dev_flags))
 		goto exit;
 
-#define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name)		\
+	intf->register_folder =
+	    debugfs_create_dir("register", intf->driver_folder);
+	if (IS_ERR(intf->register_folder))
+		goto exit;
+
+#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name)	\
 ({								\
 	(__intf)->__name##_off_entry =				\
 	    debugfs_create_u32(__stringify(__name) "_offset",	\
 			       S_IRUGO | S_IWUSR,		\
-			       (__intf)->driver_folder,		\
+			       (__intf)->register_folder,	\
 			       &(__intf)->offset_##__name);	\
 	if (IS_ERR((__intf)->__name##_off_entry))		\
 		goto exit;					\
@@ -319,18 +483,32 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 	(__intf)->__name##_val_entry =				\
 	    debugfs_create_file(__stringify(__name) "_value",	\
 				S_IRUGO | S_IWUSR,		\
-				(__intf)->driver_folder,	\
+				(__intf)->register_folder,	\
 				(__intf), &rt2x00debug_fop_##__name);\
 	if (IS_ERR((__intf)->__name##_val_entry))		\
 		goto exit;					\
 })
 
-	RT2X00DEBUGFS_CREATE_ENTRY(intf, csr);
-	RT2X00DEBUGFS_CREATE_ENTRY(intf, eeprom);
-	RT2X00DEBUGFS_CREATE_ENTRY(intf, bbp);
-	RT2X00DEBUGFS_CREATE_ENTRY(intf, rf);
+	RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, csr);
+	RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, eeprom);
+	RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, bbp);
+	RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rf);
 
-#undef RT2X00DEBUGFS_CREATE_ENTRY
+#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY
+
+	intf->frame_folder =
+	    debugfs_create_dir("frame", intf->driver_folder);
+	if (IS_ERR(intf->frame_folder))
+		goto exit;
+
+	intf->frame_dump_entry =
+	    debugfs_create_file("dump", S_IRUGO, intf->frame_folder,
+				intf, &rt2x00debug_fop_ring_dump);
+	if (IS_ERR(intf->frame_dump_entry))
+		goto exit;
+
+	skb_queue_head_init(&intf->frame_dump_skbqueue);
+	init_waitqueue_head(&intf->frame_dump_waitqueue);
 
 	return;
 
@@ -343,11 +521,15 @@ exit:
 
 void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
 {
-	const struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
+	struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
 
 	if (unlikely(!intf))
 		return;
 
+	skb_queue_purge(&intf->frame_dump_skbqueue);
+
+	debugfs_remove(intf->frame_dump_entry);
+	debugfs_remove(intf->frame_folder);
 	debugfs_remove(intf->rf_val_entry);
 	debugfs_remove(intf->rf_off_entry);
 	debugfs_remove(intf->bbp_val_entry);
@@ -356,6 +538,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
 	debugfs_remove(intf->eeprom_off_entry);
 	debugfs_remove(intf->csr_val_entry);
 	debugfs_remove(intf->csr_off_entry);
+	debugfs_remove(intf->register_folder);
 	debugfs_remove(intf->dev_flags);
 	debugfs_remove(intf->chipset_entry);
 	debugfs_remove(intf->driver_entry);
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h
index 860e8fa3a0da..d37efbd09c41 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.h
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.h
@@ -30,9 +30,9 @@ struct rt2x00_dev;
 
 #define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type)		\
 struct reg##__name {						\
-	void (*read)(const struct rt2x00_dev *rt2x00dev,	\
+	void (*read)(struct rt2x00_dev *rt2x00dev,		\
 		     const unsigned int word, __type *data);	\
-	void (*write)(const struct rt2x00_dev *rt2x00dev,	\
+	void (*write)(struct rt2x00_dev *rt2x00dev,		\
 		      const unsigned int word, __type data);	\
 								\
 	unsigned int word_size;					\
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index ff399f8083e9..c4be2ac4d7a4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -23,16 +23,12 @@
 	Abstract: rt2x00 generic device routines.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2x00lib"
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 
 #include "rt2x00.h"
 #include "rt2x00lib.h"
+#include "rt2x00dump.h"
 
 /*
  * Ring handler.
@@ -67,7 +63,21 @@ EXPORT_SYMBOL_GPL(rt2x00lib_get_ring);
  */
 static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
 {
-	rt2x00_clear_link(&rt2x00dev->link);
+	rt2x00dev->link.count = 0;
+	rt2x00dev->link.vgc_level = 0;
+
+	memset(&rt2x00dev->link.qual, 0, sizeof(rt2x00dev->link.qual));
+
+	/*
+	 * The RX and TX percentage should start at 50%
+	 * this will assure we will get at least get some
+	 * decent value when the link tuner starts.
+	 * The value will be dropped and overwritten with
+	 * the correct (measured )value anyway during the
+	 * first run of the link tuner.
+	 */
+	rt2x00dev->link.qual.rx_percentage = 50;
+	rt2x00dev->link.qual.tx_percentage = 50;
 
 	/*
 	 * Reset the link tuner.
@@ -93,6 +103,46 @@ void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
 }
 
 /*
+ * Ring initialization
+ */
+static void rt2x00lib_init_rxrings(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring = rt2x00dev->rx;
+	unsigned int i;
+
+	if (!rt2x00dev->ops->lib->init_rxentry)
+		return;
+
+	if (ring->data_addr)
+		memset(ring->data_addr, 0, rt2x00_get_ring_size(ring));
+
+	for (i = 0; i < ring->stats.limit; i++)
+		rt2x00dev->ops->lib->init_rxentry(rt2x00dev, &ring->entry[i]);
+
+	rt2x00_ring_index_clear(ring);
+}
+
+static void rt2x00lib_init_txrings(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring;
+	unsigned int i;
+
+	if (!rt2x00dev->ops->lib->init_txentry)
+		return;
+
+	txringall_for_each(rt2x00dev, ring) {
+		if (ring->data_addr)
+			memset(ring->data_addr, 0, rt2x00_get_ring_size(ring));
+
+		for (i = 0; i < ring->stats.limit; i++)
+			rt2x00dev->ops->lib->init_txentry(rt2x00dev,
+							  &ring->entry[i]);
+
+		rt2x00_ring_index_clear(ring);
+	}
+}
+
+/*
  * Radio control handlers.
  */
 int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -108,6 +158,12 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
 		return 0;
 
 	/*
+	 * Initialize all data rings.
+	 */
+	rt2x00lib_init_rxrings(rt2x00dev);
+	rt2x00lib_init_txrings(rt2x00dev);
+
+	/*
 	 * Enable radio.
 	 */
 	status = rt2x00dev->ops->lib->set_device_state(rt2x00dev,
@@ -179,26 +235,153 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
 		rt2x00lib_start_link_tuner(rt2x00dev);
 }
 
-static void rt2x00lib_precalculate_link_signal(struct link *link)
+static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev)
 {
-	if (link->rx_failed || link->rx_success)
-		link->rx_percentage =
-		    (link->rx_success * 100) /
-		    (link->rx_failed + link->rx_success);
+	enum antenna rx = rt2x00dev->link.ant.active.rx;
+	enum antenna tx = rt2x00dev->link.ant.active.tx;
+	int sample_a =
+	    rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A);
+	int sample_b =
+	    rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B);
+
+	/*
+	 * We are done sampling. Now we should evaluate the results.
+	 */
+	rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE;
+
+	/*
+	 * During the last period we have sampled the RSSI
+	 * from both antenna's. It now is time to determine
+	 * which antenna demonstrated the best performance.
+	 * When we are already on the antenna with the best
+	 * performance, then there really is nothing for us
+	 * left to do.
+	 */
+	if (sample_a == sample_b)
+		return;
+
+	if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) {
+		if (sample_a > sample_b && rx == ANTENNA_B)
+			rx = ANTENNA_A;
+		else if (rx == ANTENNA_A)
+			rx = ANTENNA_B;
+	}
+
+	if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) {
+		if (sample_a > sample_b && tx == ANTENNA_B)
+			tx = ANTENNA_A;
+		else if (tx == ANTENNA_A)
+			tx = ANTENNA_B;
+	}
+
+	rt2x00lib_config_antenna(rt2x00dev, rx, tx);
+}
+
+static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev)
+{
+	enum antenna rx = rt2x00dev->link.ant.active.rx;
+	enum antenna tx = rt2x00dev->link.ant.active.tx;
+	int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link);
+	int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr);
+
+	/*
+	 * Legacy driver indicates that we should swap antenna's
+	 * when the difference in RSSI is greater that 5. This
+	 * also should be done when the RSSI was actually better
+	 * then the previous sample.
+	 * When the difference exceeds the threshold we should
+	 * sample the rssi from the other antenna to make a valid
+	 * comparison between the 2 antennas.
+	 */
+	if ((rssi_curr - rssi_old) > -5 || (rssi_curr - rssi_old) < 5)
+		return;
+
+	rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE;
+
+	if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY)
+		rx = (rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
+
+	if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)
+		tx = (tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A;
+
+	rt2x00lib_config_antenna(rt2x00dev, rx, tx);
+}
+
+static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev)
+{
+	/*
+	 * Determine if software diversity is enabled for
+	 * either the TX or RX antenna (or both).
+	 * Always perform this check since within the link
+	 * tuner interval the configuration might have changed.
+	 */
+	rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY;
+	rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY;
+
+	if (rt2x00dev->hw->conf.antenna_sel_rx == 0 &&
+	    rt2x00dev->default_ant.rx != ANTENNA_SW_DIVERSITY)
+		rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY;
+	if (rt2x00dev->hw->conf.antenna_sel_tx == 0 &&
+	    rt2x00dev->default_ant.tx != ANTENNA_SW_DIVERSITY)
+		rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY;
+
+	if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) &&
+	    !(rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)) {
+		rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE;
+		return;
+	}
+
+	/*
+	 * If we have only sampled the data over the last period
+	 * we should now harvest the data. Otherwise just evaluate
+	 * the data. The latter should only be performed once
+	 * every 2 seconds.
+	 */
+	if (rt2x00dev->link.ant.flags & ANTENNA_MODE_SAMPLE)
+		rt2x00lib_evaluate_antenna_sample(rt2x00dev);
+	else if (rt2x00dev->link.count & 1)
+		rt2x00lib_evaluate_antenna_eval(rt2x00dev);
+}
+
+static void rt2x00lib_update_link_stats(struct link *link, int rssi)
+{
+	int avg_rssi = rssi;
+
+	/*
+	 * Update global RSSI
+	 */
+	if (link->qual.avg_rssi)
+		avg_rssi = MOVING_AVERAGE(link->qual.avg_rssi, rssi, 8);
+	link->qual.avg_rssi = avg_rssi;
+
+	/*
+	 * Update antenna RSSI
+	 */
+	if (link->ant.rssi_ant)
+		rssi = MOVING_AVERAGE(link->ant.rssi_ant, rssi, 8);
+	link->ant.rssi_ant = rssi;
+}
+
+static void rt2x00lib_precalculate_link_signal(struct link_qual *qual)
+{
+	if (qual->rx_failed || qual->rx_success)
+		qual->rx_percentage =
+		    (qual->rx_success * 100) /
+		    (qual->rx_failed + qual->rx_success);
 	else
-		link->rx_percentage = 50;
+		qual->rx_percentage = 50;
 
-	if (link->tx_failed || link->tx_success)
-		link->tx_percentage =
-		    (link->tx_success * 100) /
-		    (link->tx_failed + link->tx_success);
+	if (qual->tx_failed || qual->tx_success)
+		qual->tx_percentage =
+		    (qual->tx_success * 100) /
+		    (qual->tx_failed + qual->tx_success);
 	else
-		link->tx_percentage = 50;
+		qual->tx_percentage = 50;
 
-	link->rx_success = 0;
-	link->rx_failed = 0;
-	link->tx_success = 0;
-	link->tx_failed = 0;
+	qual->rx_success = 0;
+	qual->rx_failed = 0;
+	qual->tx_success = 0;
+	qual->tx_failed = 0;
 }
 
 static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev,
@@ -225,8 +408,8 @@ static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev,
 	 * defines to calculate the current link signal.
 	 */
 	signal = ((WEIGHT_RSSI * rssi_percentage) +
-		  (WEIGHT_TX * rt2x00dev->link.tx_percentage) +
-		  (WEIGHT_RX * rt2x00dev->link.rx_percentage)) / 100;
+		  (WEIGHT_TX * rt2x00dev->link.qual.tx_percentage) +
+		  (WEIGHT_RX * rt2x00dev->link.qual.rx_percentage)) / 100;
 
 	return (signal > 100) ? 100 : signal;
 }
@@ -246,10 +429,9 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
 	/*
 	 * Update statistics.
 	 */
-	rt2x00dev->ops->lib->link_stats(rt2x00dev);
-
+	rt2x00dev->ops->lib->link_stats(rt2x00dev, &rt2x00dev->link.qual);
 	rt2x00dev->low_level_stats.dot11FCSErrorCount +=
-	    rt2x00dev->link.rx_failed;
+	    rt2x00dev->link.qual.rx_failed;
 
 	/*
 	 * Only perform the link tuning when Link tuning
@@ -259,10 +441,15 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
 		rt2x00dev->ops->lib->link_tuner(rt2x00dev);
 
 	/*
+	 * Evaluate antenna setup.
+	 */
+	rt2x00lib_evaluate_antenna(rt2x00dev);
+
+	/*
 	 * Precalculate a portion of the link signal which is
 	 * in based on the tx/rx success/failure counters.
 	 */
-	rt2x00lib_precalculate_link_signal(&rt2x00dev->link);
+	rt2x00lib_precalculate_link_signal(&rt2x00dev->link.qual);
 
 	/*
 	 * Increase tuner counter, and reschedule the next link tuner run.
@@ -276,7 +463,7 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
 {
 	struct rt2x00_dev *rt2x00dev =
 	    container_of(work, struct rt2x00_dev, filter_work);
-	unsigned int filter = rt2x00dev->interface.filter;
+	unsigned int filter = rt2x00dev->packet_filter;
 
 	/*
 	 * Since we had stored the filter inside interface.filter,
@@ -284,7 +471,7 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
 	 * assume nothing has changed (*total_flags will be compared
 	 * to interface.filter to determine if any action is required).
 	 */
-	rt2x00dev->interface.filter = 0;
+	rt2x00dev->packet_filter = 0;
 
 	rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw,
 					     filter, &filter, 0, NULL);
@@ -294,10 +481,17 @@ static void rt2x00lib_configuration_scheduled(struct work_struct *work)
 {
 	struct rt2x00_dev *rt2x00dev =
 	    container_of(work, struct rt2x00_dev, config_work);
-	int preamble = !test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+	struct ieee80211_bss_conf bss_conf;
 
-	rt2x00mac_erp_ie_changed(rt2x00dev->hw,
-				 IEEE80211_ERP_CHANGE_PREAMBLE, 0, preamble);
+	bss_conf.use_short_preamble =
+		test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+
+	/*
+	 * FIXME: shouldn't invoke it this way because all other contents
+	 *	  of bss_conf is invalid.
+	 */
+	rt2x00mac_bss_info_changed(rt2x00dev->hw, rt2x00dev->interface.id,
+				   &bss_conf, BSS_CHANGED_ERP_PREAMBLE);
 }
 
 /*
@@ -350,8 +544,8 @@ void rt2x00lib_txdone(struct data_entry *entry,
 	tx_status->ack_signal = 0;
 	tx_status->excessive_retries = (status == TX_FAIL_RETRY);
 	tx_status->retry_count = retry;
-	rt2x00dev->link.tx_success += success;
-	rt2x00dev->link.tx_failed += retry + fail;
+	rt2x00dev->link.qual.tx_success += success;
+	rt2x00dev->link.qual.tx_failed += retry + fail;
 
 	if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) {
 		if (success)
@@ -371,9 +565,11 @@ void rt2x00lib_txdone(struct data_entry *entry,
 	}
 
 	/*
-	 * Send the tx_status to mac80211,
-	 * that method also cleans up the skb structure.
+	 * Send the tx_status to mac80211 & debugfs.
+	 * mac80211 will clean up the skb structure.
 	 */
+	get_skb_desc(entry->skb)->frame_type = DUMP_FRAME_TXDONE;
+	rt2x00debug_dump_frame(rt2x00dev, entry->skb);
 	ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status);
 	entry->skb = NULL;
 }
@@ -386,8 +582,10 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
 	struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
 	struct ieee80211_hw_mode *mode;
 	struct ieee80211_rate *rate;
+	struct ieee80211_hdr *hdr;
 	unsigned int i;
 	int val = 0;
+	u16 fc;
 
 	/*
 	 * Update RX statistics.
@@ -412,17 +610,28 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
 		}
 	}
 
-	rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi);
-	rt2x00dev->link.rx_success++;
+	/*
+	 * Only update link status if this is a beacon frame carrying our bssid.
+	 */
+	hdr = (struct ieee80211_hdr*)skb->data;
+	fc = le16_to_cpu(hdr->frame_control);
+	if (is_beacon(fc) && desc->my_bss)
+		rt2x00lib_update_link_stats(&rt2x00dev->link, desc->rssi);
+
+	rt2x00dev->link.qual.rx_success++;
+
 	rx_status->rate = val;
 	rx_status->signal =
 	    rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi);
 	rx_status->ssi = desc->rssi;
 	rx_status->flag = desc->flags;
+	rx_status->antenna = rt2x00dev->link.ant.active.rx;
 
 	/*
-	 * Send frame to mac80211
+	 * Send frame to mac80211 & debugfs
 	 */
+	get_skb_desc(skb)->frame_type = DUMP_FRAME_RXDONE;
+	rt2x00debug_dump_frame(rt2x00dev, skb);
 	ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
@@ -431,36 +640,25 @@ EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
  * TX descriptor initializer
  */
 void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-			     struct data_desc *txd,
-			     struct ieee80211_hdr *ieee80211hdr,
-			     unsigned int length,
+			     struct sk_buff *skb,
 			     struct ieee80211_tx_control *control)
 {
 	struct txdata_entry_desc desc;
-	struct data_ring *ring;
+	struct skb_desc *skbdesc = get_skb_desc(skb);
+	struct ieee80211_hdr *ieee80211hdr = skbdesc->data;
 	int tx_rate;
 	int bitrate;
+	int length;
 	int duration;
 	int residual;
 	u16 frame_control;
 	u16 seq_ctrl;
 
-	/*
-	 * Make sure the descriptor is properly cleared.
-	 */
-	memset(&desc, 0x00, sizeof(desc));
+	memset(&desc, 0, sizeof(desc));
 
-	/*
-	 * Get ring pointer, if we fail to obtain the
-	 * correct ring, then use the first TX ring.
-	 */
-	ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
-	if (!ring)
-		ring = rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
-
-	desc.cw_min = ring->tx_params.cw_min;
-	desc.cw_max = ring->tx_params.cw_max;
-	desc.aifs = ring->tx_params.aifs;
+	desc.cw_min = skbdesc->ring->tx_params.cw_min;
+	desc.cw_max = skbdesc->ring->tx_params.cw_max;
+	desc.aifs = skbdesc->ring->tx_params.aifs;
 
 	/*
 	 * Identify queue
@@ -482,12 +680,21 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	tx_rate = control->tx_rate;
 
 	/*
+	 * Check whether this frame is to be acked
+	 */
+	if (!(control->flags & IEEE80211_TXCTL_NO_ACK))
+		__set_bit(ENTRY_TXD_ACK, &desc.flags);
+
+	/*
 	 * Check if this is a RTS/CTS frame
 	 */
 	if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
 		__set_bit(ENTRY_TXD_BURST, &desc.flags);
-		if (is_rts_frame(frame_control))
+		if (is_rts_frame(frame_control)) {
 			__set_bit(ENTRY_TXD_RTS_FRAME, &desc.flags);
+			__set_bit(ENTRY_TXD_ACK, &desc.flags);
+		} else
+			__clear_bit(ENTRY_TXD_ACK, &desc.flags);
 		if (control->rts_cts_rate)
 			tx_rate = control->rts_cts_rate;
 	}
@@ -532,17 +739,18 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP);
 	desc.service = 0x04;
 
+	length = skbdesc->data_len + FCS_LEN;
 	if (test_bit(ENTRY_TXD_OFDM_RATE, &desc.flags)) {
-		desc.length_high = ((length + FCS_LEN) >> 6) & 0x3f;
-		desc.length_low = ((length + FCS_LEN) & 0x3f);
+		desc.length_high = (length >> 6) & 0x3f;
+		desc.length_low = length & 0x3f;
 	} else {
 		bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE);
 
 		/*
 		 * Convert length to microseconds.
 		 */
-		residual = get_duration_res(length + FCS_LEN, bitrate);
-		duration = get_duration(length + FCS_LEN, bitrate);
+		residual = get_duration_res(length, bitrate);
+		duration = get_duration(length, bitrate);
 
 		if (residual != 0) {
 			duration++;
@@ -565,8 +773,22 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 			desc.signal |= 0x08;
 	}
 
-	rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, txd, &desc,
-					   ieee80211hdr, length, control);
+	rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &desc, control);
+
+	/*
+	 * Update ring entry.
+	 */
+	skbdesc->entry->skb = skb;
+	memcpy(&skbdesc->entry->tx_status.control, control, sizeof(*control));
+
+	/*
+	 * The frame has been completely initialized and ready
+	 * for sending to the device. The caller will push the
+	 * frame to the device, but we are going to push the
+	 * frame to debugfs here.
+	 */
+	skbdesc->frame_type = DUMP_FRAME_TX;
+	rt2x00debug_dump_frame(rt2x00dev, skb);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc);
 
@@ -809,6 +1031,7 @@ static int rt2x00lib_alloc_entries(struct data_ring *ring,
 		entry[i].flags = 0;
 		entry[i].ring = ring;
 		entry[i].skb = NULL;
+		entry[i].entry_idx = i;
 	}
 
 	ring->entry = entry;
@@ -866,7 +1089,7 @@ static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev)
 	}
 }
 
-void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
+static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
 {
 	if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
 		return;
@@ -887,7 +1110,7 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
 	rt2x00lib_free_ring_entries(rt2x00dev);
 }
 
-int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
+static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
 {
 	int status;
 
@@ -930,12 +1153,65 @@ exit:
 	return status;
 }
 
+int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
+{
+	int retval;
+
+	if (test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+		return 0;
+
+	/*
+	 * If this is the first interface which is added,
+	 * we should load the firmware now.
+	 */
+	if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
+		retval = rt2x00lib_load_firmware(rt2x00dev);
+		if (retval)
+			return retval;
+	}
+
+	/*
+	 * Initialize the device.
+	 */
+	retval = rt2x00lib_initialize(rt2x00dev);
+	if (retval)
+		return retval;
+
+	/*
+	 * Enable radio.
+	 */
+	retval = rt2x00lib_enable_radio(rt2x00dev);
+	if (retval) {
+		rt2x00lib_uninitialize(rt2x00dev);
+		return retval;
+	}
+
+	__set_bit(DEVICE_STARTED, &rt2x00dev->flags);
+
+	return 0;
+}
+
+void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)
+{
+	if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+		return;
+
+	/*
+	 * Perhaps we can add something smarter here,
+	 * but for now just disabling the radio should do.
+	 */
+	rt2x00lib_disable_radio(rt2x00dev);
+
+	__clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
+}
+
 /*
  * driver allocation handlers.
  */
 static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_ring *ring;
+	unsigned int index;
 
 	/*
 	 * We need the following rings:
@@ -963,11 +1239,18 @@ static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev)
 
 	/*
 	 * Initialize ring parameters.
-	 * cw_min: 2^5 = 32.
-	 * cw_max: 2^10 = 1024.
+	 * RX: queue_idx = 0
+	 * TX: queue_idx = IEEE80211_TX_QUEUE_DATA0 + index
+	 * TX: cw_min: 2^5 = 32.
+	 * TX: cw_max: 2^10 = 1024.
 	 */
-	ring_for_each(rt2x00dev, ring) {
+	rt2x00dev->rx->rt2x00dev = rt2x00dev;
+	rt2x00dev->rx->queue_idx = 0;
+
+	index = IEEE80211_TX_QUEUE_DATA0;
+	txring_for_each(rt2x00dev, ring) {
 		ring->rt2x00dev = rt2x00dev;
+		ring->queue_idx = index++;
 		ring->tx_params.aifs = 2;
 		ring->tx_params.cw_min = 5;
 		ring->tx_params.cw_max = 10;
@@ -1008,7 +1291,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Reset current working type.
 	 */
-	rt2x00dev->interface.type = INVALID_INTERFACE;
+	rt2x00dev->interface.type = IEEE80211_IF_TYPE_INVALID;
 
 	/*
 	 * Allocate ring array.
@@ -1112,7 +1395,7 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
 	 * Disable radio and unitialize all items
 	 * that must be recreated on resume.
 	 */
-	rt2x00mac_stop(rt2x00dev->hw);
+	rt2x00lib_stop(rt2x00dev);
 	rt2x00lib_uninitialize(rt2x00dev);
 	rt2x00debug_deregister(rt2x00dev);
 
@@ -1134,7 +1417,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
 	int retval;
 
 	NOTICE(rt2x00dev, "Waking up.\n");
-	__set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
 
 	/*
 	 * Open the debugfs entry.
@@ -1150,7 +1432,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Reinitialize device and all active interfaces.
 	 */
-	retval = rt2x00mac_start(rt2x00dev->hw);
+	retval = rt2x00lib_start(rt2x00dev);
 	if (retval)
 		goto exit;
 
@@ -1166,6 +1448,11 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
 	rt2x00lib_config_type(rt2x00dev, intf->type);
 
 	/*
+	 * We are ready again to receive requests from mac80211.
+	 */
+	__set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+	/*
 	 * It is possible that during that mac80211 has attempted
 	 * to send frames while we were suspending or resuming.
 	 * In that case we have disabled the TX queue and should
diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h
new file mode 100644
index 000000000000..99f3f367adce
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00dump.h
@@ -0,0 +1,121 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	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.
+ */
+
+/*
+	Module: rt2x00dump
+	Abstract: Data structures for the rt2x00debug & userspace.
+ */
+
+#ifndef RT2X00DUMP_H
+#define RT2X00DUMP_H
+
+/**
+ * DOC: Introduction
+ *
+ * This header is intended to be exported to userspace,
+ * to make the structures and enumerations available to userspace
+ * applications. This means that all data types should be exportable.
+ *
+ * When rt2x00 is compiled with debugfs support enabled,
+ * it is possible to capture all data coming in and out of the device
+ * by reading the frame dump file. This file can have only a single reader.
+ * The following frames will be reported:
+ *   - All incoming frames (rx)
+ *   - All outgoing frames (tx, including beacon and atim)
+ *   - All completed frames (txdone including atim)
+ *
+ * The data is send to the file using the following format:
+ *
+ *   [rt2x00dump header][hardware descriptor][ieee802.11 frame]
+ *
+ * rt2x00dump header: The description of the dumped frame, as well as
+ *	additional information usefull for debugging. See &rt2x00dump_hdr.
+ * hardware descriptor: Descriptor that was used to receive or transmit
+ *	the frame.
+ * ieee802.11 frame: The actual frame that was received or transmitted.
+ */
+
+/**
+ * enum rt2x00_dump_type - Frame type
+ *
+ * These values are used for the @type member of &rt2x00dump_hdr.
+ * @DUMP_FRAME_RXDONE: This frame has been received by the hardware.
+ * @DUMP_FRAME_TX: This frame is queued for transmission to the hardware.
+ * @DUMP_FRAME_TXDONE: This frame indicates the device has handled
+ *	the tx event which has either succeeded or failed. A frame
+ *	with this type should also have been reported with as a
+ *	%DUMP_FRAME_TX frame.
+ */
+enum rt2x00_dump_type {
+	DUMP_FRAME_RXDONE = 1,
+	DUMP_FRAME_TX = 2,
+	DUMP_FRAME_TXDONE = 3,
+};
+
+/**
+ * struct rt2x00dump_hdr - Dump frame header
+ *
+ * Each frame dumped to the debugfs file starts with this header
+ * attached. This header contains the description of the actual
+ * frame which was dumped.
+ *
+ * New fields inside the structure must be appended to the end of
+ * the structure. This way userspace tools compiled for earlier
+ * header versions can still correctly handle the frame dump
+ * (although they will not handle all data passed to them in the dump).
+ *
+ * @version: Header version should always be set to %DUMP_HEADER_VERSION.
+ *	This field must be checked by userspace to determine if it can
+ *	handle this frame.
+ * @header_length: The length of the &rt2x00dump_hdr structure. This is
+ *	used for compatibility reasons so userspace can easily determine
+ *	the location of the next field in the dump.
+ * @desc_length: The length of the device descriptor.
+ * @data_length: The length of the frame data (including the ieee802.11 header.
+ * @chip_rt: RT chipset
+ * @chip_rf: RF chipset
+ * @chip_rev: Chipset revision
+ * @type: The frame type (&rt2x00_dump_type)
+ * @ring_index: The index number of the data ring.
+ * @entry_index: The index number of the entry inside the data ring.
+ * @timestamp_sec: Timestamp - seconds
+ * @timestamp_usec: Timestamp - microseconds
+ */
+struct rt2x00dump_hdr {
+	__le32 version;
+#define DUMP_HEADER_VERSION	2
+
+	__le32 header_length;
+	__le32 desc_length;
+	__le32 data_length;
+
+	__le16 chip_rt;
+	__le16 chip_rf;
+	__le32 chip_rev;
+
+	__le16 type;
+	__u8 ring_index;
+	__u8 entry_index;
+
+	__le32 timestamp_sec;
+	__le32 timestamp_usec;
+};
+
+#endif /* RT2X00DUMP_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
index 236025f8b90f..0a475e4e2442 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -23,11 +23,6 @@
 	Abstract: rt2x00 firmware loading routines.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2x00lib"
-
 #include <linux/crc-itu-t.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 06d9bc0015c0..1adbd28e0973 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -44,8 +44,8 @@ void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev);
 /*
  * Initialization handlers.
  */
-int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev);
-void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev);
+int rt2x00lib_start(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev);
 
 /*
  * Configuration handlers.
@@ -53,6 +53,8 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev);
 void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac);
 void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid);
 void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type);
+void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
+			      enum antenna rx, enum antenna tx);
 void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
 		      struct ieee80211_conf *conf, const int force_config);
 
@@ -78,6 +80,7 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
 void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
+void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
 #else
 static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 {
@@ -86,6 +89,11 @@ static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
 {
 }
+
+static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+					  struct sk_buff *skb)
+{
+}
 #endif /* CONFIG_RT2X00_LIB_DEBUGFS */
 
 /*
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 85ea8a8e658e..e3f15e518c76 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -23,11 +23,6 @@
 	Abstract: rt2x00 generic mac80211 routines.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2x00lib"
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 
@@ -89,7 +84,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 	 */
 	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) {
 		ieee80211_stop_queues(hw);
-		return 0;
+		return NETDEV_TX_OK;
 	}
 
 	/*
@@ -115,15 +110,24 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 	if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
 	    (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
 			       IEEE80211_TXCTL_USE_CTS_PROTECT))) {
-		if (rt2x00_ring_free(ring) <= 1)
+		if (rt2x00_ring_free(ring) <= 1) {
+			ieee80211_stop_queue(rt2x00dev->hw, control->queue);
 			return NETDEV_TX_BUSY;
+		}
 
-		if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control))
+		if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) {
+			ieee80211_stop_queue(rt2x00dev->hw, control->queue);
 			return NETDEV_TX_BUSY;
+		}
 	}
 
-	if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control))
+	if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
+		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
 		return NETDEV_TX_BUSY;
+	}
+
+	if (rt2x00_ring_full(ring))
+		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
 
 	if (rt2x00dev->ops->lib->kick_tx_queue)
 		rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
@@ -135,41 +139,11 @@ EXPORT_SYMBOL_GPL(rt2x00mac_tx);
 int rt2x00mac_start(struct ieee80211_hw *hw)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	int status;
 
-	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
-	    test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
 		return 0;
 
-	/*
-	 * If this is the first interface which is added,
-	 * we should load the firmware now.
-	 */
-	if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
-		status = rt2x00lib_load_firmware(rt2x00dev);
-		if (status)
-			return status;
-	}
-
-	/*
-	 * Initialize the device.
-	 */
-	status = rt2x00lib_initialize(rt2x00dev);
-	if (status)
-		return status;
-
-	/*
-	 * Enable radio.
-	 */
-	status = rt2x00lib_enable_radio(rt2x00dev);
-	if (status) {
-		rt2x00lib_uninitialize(rt2x00dev);
-		return status;
-	}
-
-	__set_bit(DEVICE_STARTED, &rt2x00dev->flags);
-
-	return 0;
+	return rt2x00lib_start(rt2x00dev);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_start);
 
@@ -180,13 +154,7 @@ void rt2x00mac_stop(struct ieee80211_hw *hw)
 	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
 		return;
 
-	/*
-	 * Perhaps we can add something smarter here,
-	 * but for now just disabling the radio should do.
-	 */
-	rt2x00lib_disable_radio(rt2x00dev);
-
-	__clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
+	rt2x00lib_stop(rt2x00dev);
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_stop);
 
@@ -213,7 +181,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 	    is_interface_present(intf))
 		return -ENOBUFS;
 
-	intf->id = conf->if_id;
+	intf->id = conf->vif;
 	intf->type = conf->type;
 	if (conf->type == IEEE80211_IF_TYPE_AP)
 		memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
@@ -247,7 +215,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
 		return;
 
 	intf->id = 0;
-	intf->type = INVALID_INTERFACE;
+	intf->type = IEEE80211_IF_TYPE_INVALID;
 	memset(&intf->bssid, 0x00, ETH_ALEN);
 	memset(&intf->mac, 0x00, ETH_ALEN);
 
@@ -297,7 +265,8 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_config);
 
-int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
+int rt2x00mac_config_interface(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
 			       struct ieee80211_if_conf *conf)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -373,23 +342,27 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats);
 
-void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
-			      int cts_protection, int preamble)
+void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
+				struct ieee80211_vif *vif,
+				struct ieee80211_bss_conf *bss_conf,
+				u32 changes)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 	int short_preamble;
 	int ack_timeout;
 	int ack_consume_time;
 	int difs;
+	int preamble;
 
 	/*
 	 * We only support changing preamble mode.
 	 */
-	if (!(changes & IEEE80211_ERP_CHANGE_PREAMBLE))
+	if (!(changes & BSS_CHANGED_ERP_PREAMBLE))
 		return;
 
-	short_preamble = !preamble;
-	preamble = !!(preamble) ? PREAMBLE : SHORT_PREAMBLE;
+	short_preamble = bss_conf->use_short_preamble;
+	preamble = bss_conf->use_short_preamble ?
+				SHORT_PREAMBLE : PREAMBLE;
 
 	difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ?
 		SHORT_DIFS : DIFS;
@@ -405,7 +378,7 @@ void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
 	rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble,
 					     ack_timeout, ack_consume_time);
 }
-EXPORT_SYMBOL_GPL(rt2x00mac_erp_ie_changed);
+EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed);
 
 int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
 		      const struct ieee80211_tx_queue_params *params)
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 04663eb31950..804a9980055d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -23,11 +23,6 @@
 	Abstract: rt2x00 generic pci device routines.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2x00pci"
-
 #include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -43,9 +38,9 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 			    struct ieee80211_tx_control *control)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct data_ring *ring =
-	    rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
-	struct data_entry *entry = rt2x00_get_data_entry(ring);
+	struct skb_desc *desc;
+	struct data_ring *ring;
+	struct data_entry *entry;
 
 	/*
 	 * Just in case mac80211 doesn't set this correctly,
@@ -53,14 +48,22 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 	 * initialization.
 	 */
 	control->queue = IEEE80211_TX_QUEUE_BEACON;
+	ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
+	entry = rt2x00_get_data_entry(ring);
 
 	/*
-	 * Update the beacon entry.
+	 * Fill in skb descriptor
 	 */
+	desc = get_skb_desc(skb);
+	desc->desc_len = ring->desc_size;
+	desc->data_len = skb->len;
+	desc->desc = entry->priv;
+	desc->data = skb->data;
+	desc->ring = ring;
+	desc->entry = entry;
+
 	memcpy(entry->data_addr, skb->data, skb->len);
-	rt2x00lib_write_tx_desc(rt2x00dev, entry->priv,
-				(struct ieee80211_hdr *)skb->data,
-				skb->len, control);
+	rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
 
 	/*
 	 * Enable beacon generation.
@@ -78,15 +81,13 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
 			    struct data_ring *ring, struct sk_buff *skb,
 			    struct ieee80211_tx_control *control)
 {
-	struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
 	struct data_entry *entry = rt2x00_get_data_entry(ring);
-	struct data_desc *txd = entry->priv;
+	__le32 *txd = entry->priv;
+	struct skb_desc *desc;
 	u32 word;
 
-	if (rt2x00_ring_full(ring)) {
-		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+	if (rt2x00_ring_full(ring))
 		return -EINVAL;
-	}
 
 	rt2x00_desc_read(txd, 0, &word);
 
@@ -96,37 +97,42 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
 		      "Arrived at non-free entry in the non-full queue %d.\n"
 		      "Please file bug report to %s.\n",
 		      control->queue, DRV_PROJECT);
-		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
 		return -EINVAL;
 	}
 
-	entry->skb = skb;
-	memcpy(&entry->tx_status.control, control, sizeof(*control));
+	/*
+	 * Fill in skb descriptor
+	 */
+	desc = get_skb_desc(skb);
+	desc->desc_len = ring->desc_size;
+	desc->data_len = skb->len;
+	desc->desc = entry->priv;
+	desc->data = skb->data;
+	desc->ring = ring;
+	desc->entry = entry;
+
 	memcpy(entry->data_addr, skb->data, skb->len);
-	rt2x00lib_write_tx_desc(rt2x00dev, txd, ieee80211hdr,
-				skb->len, control);
+	rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
 
 	rt2x00_ring_index_inc(ring);
 
-	if (rt2x00_ring_full(ring))
-		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
 
 /*
- * RX data handlers.
+ * TX/RX data handlers.
  */
 void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_ring *ring = rt2x00dev->rx;
 	struct data_entry *entry;
-	struct data_desc *rxd;
 	struct sk_buff *skb;
 	struct ieee80211_hdr *hdr;
+	struct skb_desc *skbdesc;
 	struct rxdata_entry_desc desc;
 	int header_size;
+	__le32 *rxd;
 	int align;
 	u32 word;
 
@@ -138,7 +144,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 		if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
 			break;
 
-		memset(&desc, 0x00, sizeof(desc));
+		memset(&desc, 0, sizeof(desc));
 		rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
 
 		hdr = (struct ieee80211_hdr *)entry->data_addr;
@@ -163,6 +169,17 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 		memcpy(skb_put(skb, desc.size), entry->data_addr, desc.size);
 
 		/*
+		 * Fill in skb descriptor
+		 */
+		skbdesc = get_skb_desc(skb);
+		skbdesc->desc_len = entry->ring->desc_size;
+		skbdesc->data_len = skb->len;
+		skbdesc->desc = entry->priv;
+		skbdesc->data = skb->data;
+		skbdesc->ring = ring;
+		skbdesc->entry = entry;
+
+		/*
 		 * Send the frame to rt2x00lib for further processing.
 		 */
 		rt2x00lib_rxdone(entry, skb, &desc);
@@ -177,6 +194,37 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
 
+void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct data_entry *entry,
+		      const int tx_status, const int retry)
+{
+	u32 word;
+
+	rt2x00lib_txdone(entry, tx_status, retry);
+
+	/*
+	 * Make this entry available for reuse.
+	 */
+	entry->flags = 0;
+
+	rt2x00_desc_read(entry->priv, 0, &word);
+	rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0);
+	rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0);
+	rt2x00_desc_write(entry->priv, 0, word);
+
+	rt2x00_ring_index_done_inc(entry->ring);
+
+	/*
+	 * If the data ring was full before the txdone handler
+	 * we must make sure the packet queue in the mac80211 stack
+	 * is reenabled when the txdone handler has finished.
+	 */
+	if (!rt2x00_ring_full(entry->ring))
+		ieee80211_wake_queue(rt2x00dev->hw,
+				     entry->tx_status.control.queue);
+
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
+
 /*
  * Device initialization handlers.
  */
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 82adeac061d0..2d1eb8144da4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -57,7 +57,7 @@
 /*
  * Register access.
  */
-static inline void rt2x00pci_register_read(const struct rt2x00_dev *rt2x00dev,
+static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
 					   const unsigned long offset,
 					   u32 *value)
 {
@@ -65,14 +65,14 @@ static inline void rt2x00pci_register_read(const struct rt2x00_dev *rt2x00dev,
 }
 
 static inline void
-rt2x00pci_register_multiread(const struct rt2x00_dev *rt2x00dev,
+rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
 			     const unsigned long offset,
 			     void *value, const u16 length)
 {
 	memcpy_fromio(value, rt2x00dev->csr_addr + offset, length);
 }
 
-static inline void rt2x00pci_register_write(const struct rt2x00_dev *rt2x00dev,
+static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
 					    const unsigned long offset,
 					    u32 value)
 {
@@ -80,7 +80,7 @@ static inline void rt2x00pci_register_write(const struct rt2x00_dev *rt2x00dev,
 }
 
 static inline void
-rt2x00pci_register_multiwrite(const struct rt2x00_dev *rt2x00dev,
+rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
 			      const unsigned long offset,
 			      void *value, const u16 length)
 {
@@ -101,9 +101,11 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
 			    struct ieee80211_tx_control *control);
 
 /*
- * RX data handlers.
+ * RX/TX data handlers.
  */
 void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
+void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct data_entry *entry,
+		      const int tx_status, const int retry);
 
 /*
  * Device initialization handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
index a0f8b8e0a24b..34a96d44e306 100644
--- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c
+++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
@@ -23,11 +23,6 @@
 	Abstract: rt2x00 rfkill routines.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2x00lib"
-
 #include <linux/input-polldev.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -68,8 +63,10 @@ static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
 	struct rt2x00_dev *rt2x00dev = poll_dev->private;
 	int state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
 
-	if (rt2x00dev->rfkill->state != state)
+	if (rt2x00dev->rfkill->state != state) {
 		input_report_key(poll_dev->input, KEY_WLAN, 1);
+		input_report_key(poll_dev->input, KEY_WLAN, 0);
+	}
 }
 
 int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
@@ -92,6 +89,13 @@ int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
 		return retval;
 	}
 
+	/*
+	 * Force initial poll which will detect the initial device state,
+	 * and correctly sends the signal to the rfkill layer about this
+	 * state.
+	 */
+	rt2x00rfkill_poll(rt2x00dev->poll_dev);
+
 	return 0;
 }
 
@@ -114,26 +118,41 @@ int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
 	rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
 	if (!rt2x00dev->rfkill) {
 		ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n");
-		return -ENOMEM;
+		goto exit;
 	}
 
 	rt2x00dev->rfkill->name = rt2x00dev->ops->name;
 	rt2x00dev->rfkill->data = rt2x00dev;
-	rt2x00dev->rfkill->state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+	rt2x00dev->rfkill->state = -1;
 	rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio;
 
 	rt2x00dev->poll_dev = input_allocate_polled_device();
 	if (!rt2x00dev->poll_dev) {
 		ERROR(rt2x00dev, "Failed to allocate polled device.\n");
-		rfkill_free(rt2x00dev->rfkill);
-		return -ENOMEM;
+		goto exit_free_rfkill;
 	}
 
 	rt2x00dev->poll_dev->private = rt2x00dev;
 	rt2x00dev->poll_dev->poll = rt2x00rfkill_poll;
 	rt2x00dev->poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
 
+	rt2x00dev->poll_dev->input->name = rt2x00dev->ops->name;
+	rt2x00dev->poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy);
+	rt2x00dev->poll_dev->input->id.bustype = BUS_HOST;
+	rt2x00dev->poll_dev->input->id.vendor = 0x1814;
+	rt2x00dev->poll_dev->input->id.product = rt2x00dev->chip.rt;
+	rt2x00dev->poll_dev->input->id.version = rt2x00dev->chip.rev;
+	rt2x00dev->poll_dev->input->dev.parent = device;
+	rt2x00dev->poll_dev->input->evbit[0] = BIT(EV_KEY);
+	set_bit(KEY_WLAN, rt2x00dev->poll_dev->input->keybit);
+
 	return 0;
+
+exit_free_rfkill:
+	rfkill_free(rt2x00dev->rfkill);
+
+exit:
+	return -ENOMEM;
 }
 
 void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h
index 1a864d32cfbd..1caa6d688c40 100644
--- a/drivers/net/wireless/rt2x00/rt2x00ring.h
+++ b/drivers/net/wireless/rt2x00/rt2x00ring.h
@@ -27,19 +27,27 @@
 #define RT2X00RING_H
 
 /*
- * data_desc
- * Each data entry also contains a descriptor which is used by the
- * device to determine what should be done with the packet and
- * what the current status is.
- * This structure is greatly simplified, but the descriptors
- * are basically a list of little endian 32 bit values.
- * Make the array by default 1 word big, this will allow us
- * to use sizeof() correctly.
+ * skb_desc
+ * Descriptor information for the skb buffer
  */
-struct data_desc {
-	__le32 word[1];
+struct skb_desc {
+	unsigned int frame_type;
+
+	unsigned int desc_len;
+	unsigned int data_len;
+
+	void *desc;
+	void *data;
+
+	struct data_ring *ring;
+	struct data_entry *entry;
 };
 
+static inline struct skb_desc* get_skb_desc(struct sk_buff *skb)
+{
+	return (struct skb_desc*)&skb->cb[0];
+}
+
 /*
  * rxdata_entry_desc
  * Summary of information that has been read from the
@@ -51,6 +59,7 @@ struct rxdata_entry_desc {
 	int ofdm;
 	int size;
 	int flags;
+	int my_bss;
 };
 
 /*
@@ -66,6 +75,7 @@ struct txdata_entry_desc {
 #define ENTRY_TXD_MORE_FRAG	4
 #define ENTRY_TXD_REQ_TIMESTAMP	5
 #define ENTRY_TXD_BURST		6
+#define ENTRY_TXD_ACK		7
 
 /*
  * Queue ID. ID's 0-4 are data TX rings
@@ -134,6 +144,11 @@ struct data_entry {
 	 */
 	void *data_addr;
 	dma_addr_t data_dma;
+
+	/*
+	 * Entry identification number (index).
+	 */
+	unsigned int entry_idx;
 };
 
 /*
@@ -172,6 +187,13 @@ struct data_ring {
 	void *data_addr;
 
 	/*
+	 * Queue identification number:
+	 * RX: 0
+	 * TX: IEEE80211_TX_*
+	 */
+	unsigned int queue_idx;
+
+	/*
 	 * Index variables.
 	 */
 	u16 index;
@@ -253,16 +275,16 @@ static inline int rt2x00_ring_free(struct data_ring *ring)
 /*
  * TX/RX Descriptor access functions.
  */
-static inline void rt2x00_desc_read(struct data_desc *desc,
+static inline void rt2x00_desc_read(__le32 *desc,
 				    const u8 word, u32 *value)
 {
-	*value = le32_to_cpu(desc->word[word]);
+	*value = le32_to_cpu(desc[word]);
 }
 
-static inline void rt2x00_desc_write(struct data_desc *desc,
+static inline void rt2x00_desc_write(__le32 *desc,
 				     const u8 word, const u32 value)
 {
-	desc->word[word] = cpu_to_le32(value);
+	desc[word] = cpu_to_le32(value);
 }
 
 #endif /* RT2X00RING_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 568d73847dca..84e9bdb73910 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -23,14 +23,10 @@
 	Abstract: rt2x00 generic usb device routines.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt2x00usb"
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/bug.h>
 
 #include "rt2x00.h"
 #include "rt2x00usb.h"
@@ -38,7 +34,7 @@
 /*
  * Interfacing with the HW.
  */
-int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
+int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
 			     const u8 request, const u8 requesttype,
 			     const u16 offset, const u16 value,
 			     void *buffer, const u16 buffer_length,
@@ -52,6 +48,7 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
 	    (requesttype == USB_VENDOR_REQUEST_IN) ?
 	    usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
 
+
 	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
 		status = usb_control_msg(usb_dev, pipe, request, requesttype,
 					 value, offset, buffer, buffer_length,
@@ -76,13 +73,15 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request);
 
-int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev,
-				  const u8 request, const u8 requesttype,
-				  const u16 offset, void *buffer,
-				  const u16 buffer_length, const int timeout)
+int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
+				   const u8 request, const u8 requesttype,
+				   const u16 offset, void *buffer,
+				   const u16 buffer_length, const int timeout)
 {
 	int status;
 
+	BUG_ON(!mutex_is_locked(&rt2x00dev->usb_cache_mutex));
+
 	/*
 	 * Check for Cache availability.
 	 */
@@ -103,6 +102,25 @@ int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev,
 
 	return status;
 }
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_req_buff_lock);
+
+int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
+				  const u8 request, const u8 requesttype,
+				  const u16 offset, void *buffer,
+				  const u16 buffer_length, const int timeout)
+{
+	int status;
+
+	mutex_lock(&rt2x00dev->usb_cache_mutex);
+
+	status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
+						requesttype, offset, buffer,
+						buffer_length, timeout);
+
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+	return status;
+}
 EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
 
 /*
@@ -113,7 +131,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
 	struct data_entry *entry = (struct data_entry *)urb->context;
 	struct data_ring *ring = entry->ring;
 	struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
-	struct data_desc *txd = (struct data_desc *)entry->skb->data;
+	__le32 *txd = (__le32 *)entry->skb->data;
 	u32 word;
 	int tx_status;
 
@@ -158,20 +176,17 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
 	struct usb_device *usb_dev =
 	    interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
 	struct data_entry *entry = rt2x00_get_data_entry(ring);
-	int pipe = usb_sndbulkpipe(usb_dev, 1);
+	struct skb_desc *desc;
 	u32 length;
 
-	if (rt2x00_ring_full(ring)) {
-		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+	if (rt2x00_ring_full(ring))
 		return -EINVAL;
-	}
 
 	if (test_bit(ENTRY_OWNER_NIC, &entry->flags)) {
 		ERROR(rt2x00dev,
 		      "Arrived at non-free entry in the non-full queue %d.\n"
 		      "Please file bug report to %s.\n",
 		      control->queue, DRV_PROJECT);
-		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
 		return -EINVAL;
 	}
 
@@ -181,12 +196,18 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
 	skb_push(skb, ring->desc_size);
 	memset(skb->data, 0, ring->desc_size);
 
-	rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
-				(struct ieee80211_hdr *)(skb->data +
-							 ring->desc_size),
-				skb->len - ring->desc_size, control);
-	memcpy(&entry->tx_status.control, control, sizeof(*control));
-	entry->skb = skb;
+	/*
+	 * Fill in skb descriptor
+	 */
+	desc = get_skb_desc(skb);
+	desc->desc_len = ring->desc_size;
+	desc->data_len = skb->len - ring->desc_size;
+	desc->desc = skb->data;
+	desc->data = skb->data + ring->desc_size;
+	desc->ring = ring;
+	desc->entry = entry;
+
+	rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
 
 	/*
 	 * USB devices cannot blindly pass the skb->len as the
@@ -199,15 +220,12 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
 	 * Initialize URB and send the frame to the device.
 	 */
 	__set_bit(ENTRY_OWNER_NIC, &entry->flags);
-	usb_fill_bulk_urb(entry->priv, usb_dev, pipe,
+	usb_fill_bulk_urb(entry->priv, usb_dev, usb_sndbulkpipe(usb_dev, 1),
 			  skb->data, length, rt2x00usb_interrupt_txdone, entry);
 	usb_submit_urb(entry->priv, GFP_ATOMIC);
 
 	rt2x00_ring_index_inc(ring);
 
-	if (rt2x00_ring_full(ring))
-		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
@@ -222,6 +240,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
 	struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
 	struct sk_buff *skb;
 	struct ieee80211_hdr *hdr;
+	struct skb_desc *skbdesc;
 	struct rxdata_entry_desc desc;
 	int header_size;
 	int frame_size;
@@ -238,7 +257,14 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
 	if (urb->actual_length < entry->ring->desc_size || urb->status)
 		goto skip_entry;
 
-	memset(&desc, 0x00, sizeof(desc));
+	/*
+	 * Fill in skb descriptor
+	 */
+	skbdesc = get_skb_desc(entry->skb);
+	skbdesc->ring = ring;
+	skbdesc->entry = entry;
+
+	memset(&desc, 0, sizeof(desc));
 	rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
 
 	/*
@@ -264,9 +290,6 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
 	/*
 	 * The data behind the ieee80211 header must be
 	 * aligned on a 4 byte boundary.
-	 * After that trim the entire buffer down to only
-	 * contain the valid frame data excluding the device
-	 * descriptor.
 	 */
 	hdr = (struct ieee80211_hdr *)entry->skb->data;
 	header_size =
@@ -276,6 +299,16 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
 		skb_push(entry->skb, 2);
 		memmove(entry->skb->data, entry->skb->data + 2, skb->len - 2);
 	}
+
+	/*
+	 * Trim the entire buffer down to only contain the valid frame data
+	 * excluding the device descriptor. The position of the descriptor
+	 * varies. This means that we should check where the descriptor is
+	 * and decide if we need to pull the data pointer to exclude the
+	 * device descriptor.
+	 */
+	if (skbdesc->data > skbdesc->desc)
+		skb_pull(entry->skb, skbdesc->desc_len);
 	skb_trim(entry->skb, desc.size);
 
 	/*
@@ -303,43 +336,6 @@ skip_entry:
 /*
  * Radio handlers
  */
-void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev)
-{
-	struct usb_device *usb_dev =
-	    interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
-	struct data_ring *ring;
-	struct data_entry *entry;
-	unsigned int i;
-
-	/*
-	 * Initialize the TX rings
-	 */
-	txringall_for_each(rt2x00dev, ring) {
-		for (i = 0; i < ring->stats.limit; i++)
-			ring->entry[i].flags = 0;
-
-		rt2x00_ring_index_clear(ring);
-	}
-
-	/*
-	 * Initialize and start the RX ring.
-	 */
-	rt2x00_ring_index_clear(rt2x00dev->rx);
-
-	for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
-		entry = &rt2x00dev->rx->entry[i];
-
-		usb_fill_bulk_urb(entry->priv, usb_dev,
-				  usb_rcvbulkpipe(usb_dev, 1),
-				  entry->skb->data, entry->skb->len,
-				  rt2x00usb_interrupt_rxdone, entry);
-
-		__set_bit(ENTRY_OWNER_NIC, &entry->flags);
-		usb_submit_urb(entry->priv, GFP_ATOMIC);
-	}
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_enable_radio);
-
 void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
 {
 	struct data_ring *ring;
@@ -361,6 +357,29 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
 /*
  * Device initialization handlers.
  */
+void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
+			    struct data_entry *entry)
+{
+	struct usb_device *usb_dev =
+	     interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+
+	usb_fill_bulk_urb(entry->priv, usb_dev,
+			  usb_rcvbulkpipe(usb_dev, 1),
+			  entry->skb->data, entry->skb->len,
+			  rt2x00usb_interrupt_rxdone, entry);
+
+	__set_bit(ENTRY_OWNER_NIC, &entry->flags);
+	usb_submit_urb(entry->priv, GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry);
+
+void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev,
+			    struct data_entry *entry)
+{
+	entry->flags = 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry);
+
 static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
 			       struct data_ring *ring)
 {
@@ -400,7 +419,7 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
 	struct sk_buff *skb;
 	unsigned int entry_size;
 	unsigned int i;
-	int status;
+	int uninitialized_var(status);
 
 	/*
 	 * Allocate DMA
@@ -507,6 +526,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
 	rt2x00dev->dev = usb_intf;
 	rt2x00dev->ops = ops;
 	rt2x00dev->hw = hw;
+	mutex_init(&rt2x00dev->usb_cache_mutex);
 
 	rt2x00dev->usb_maxpacket =
 	    usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 2681abe4d49e..e40df4050cd0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -91,7 +91,7 @@
  * a buffer allocated by kmalloc. Failure to do so can lead
  * to unexpected behavior depending on the architecture.
  */
-int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
+int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
 			     const u8 request, const u8 requesttype,
 			     const u16 offset, const u16 value,
 			     void *buffer, const u16 buffer_length,
@@ -107,18 +107,25 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
  * kmalloc. Hence the reason for using a previously allocated cache
  * which has been allocated properly.
  */
-int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev,
+int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
 				  const u8 request, const u8 requesttype,
 				  const u16 offset, void *buffer,
 				  const u16 buffer_length, const int timeout);
 
 /*
+ * A version of rt2x00usb_vendor_request_buff which must be called
+ * if the usb_cache_mutex is already held. */
+int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
+				   const u8 request, const u8 requesttype,
+				   const u16 offset, void *buffer,
+				   const u16 buffer_length, const int timeout);
+
+/*
  * Simple wrapper around rt2x00usb_vendor_request to write a single
  * command to the device. Since we don't use the buffer argument we
  * don't have to worry about kmalloc here.
  */
-static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev
-					      *rt2x00dev,
+static inline int rt2x00usb_vendor_request_sw(struct rt2x00_dev *rt2x00dev,
 					      const u8 request,
 					      const u16 offset,
 					      const u16 value,
@@ -134,8 +141,8 @@ static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev
  * from the device. Note that the eeprom argument _must_ be allocated using
  * kmalloc for correct handling inside the kernel USB layer.
  */
-static inline int rt2x00usb_eeprom_read(const struct rt2x00_dev *rt2x00dev,
-					 __le16 *eeprom, const u16 lenght)
+static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
+					__le16 *eeprom, const u16 lenght)
 {
 	int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16));
 
@@ -147,7 +154,6 @@ static inline int rt2x00usb_eeprom_read(const struct rt2x00_dev *rt2x00dev,
 /*
  * Radio handlers
  */
-void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev);
 void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
 
 /*
@@ -160,6 +166,10 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
 /*
  * Device initialization handlers.
  */
+void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev,
+			    struct data_entry *entry);
+void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev,
+			    struct data_entry *entry);
 int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev);
 void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
 
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index ecae968ce091..ab52f221cd71 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -24,11 +24,6 @@
 	Supported chipsets: RT2561, RT2561s, RT2661.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt61pci"
-
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
@@ -52,7 +47,7 @@
  * the access attempt is considered to have failed,
  * and we will print an error.
  */
-static u32 rt61pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+static u32 rt61pci_bbp_check(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
 	unsigned int i;
@@ -67,7 +62,7 @@ static u32 rt61pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
 	return reg;
 }
 
-static void rt61pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
 			      const unsigned int word, const u8 value)
 {
 	u32 reg;
@@ -93,7 +88,7 @@ static void rt61pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
 	rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
 }
 
-static void rt61pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
 			     const unsigned int word, u8 *value)
 {
 	u32 reg;
@@ -130,7 +125,7 @@ static void rt61pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
 	*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
 }
 
-static void rt61pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
 			     const unsigned int word, const u32 value)
 {
 	u32 reg;
@@ -160,7 +155,7 @@ rf_write:
 	rt2x00_rf_write(rt2x00dev, word, value);
 }
 
-static void rt61pci_mcu_request(const struct rt2x00_dev *rt2x00dev,
+static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,
 				const u8 command, const u8 token,
 				const u8 arg0, const u8 arg1)
 {
@@ -220,13 +215,13 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 #define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
 
-static void rt61pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt61pci_read_csr(struct rt2x00_dev *rt2x00dev,
 			     const unsigned int word, u32 *data)
 {
 	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
 }
 
-static void rt61pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt61pci_write_csr(struct rt2x00_dev *rt2x00dev,
 			      const unsigned int word, u32 data)
 {
 	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
@@ -322,7 +317,8 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
 	 */
 	rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
-	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE,
+			  (tsf_sync == TSF_SYNC_BEACON));
 	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync);
 	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
@@ -411,8 +407,7 @@ static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
 }
 
 static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
-				      const int antenna_tx,
-				      const int antenna_rx)
+				      struct antenna_setup *ant)
 {
 	u8 r3;
 	u8 r4;
@@ -423,32 +418,39 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
 	rt61pci_bbp_read(rt2x00dev, 77, &r77);
 
 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
-			  !rt2x00_rf(&rt2x00dev->chip, RF5225));
+			  rt2x00_rf(&rt2x00dev->chip, RF5325));
 
-	switch (antenna_rx) {
-	case ANTENNA_SW_DIVERSITY:
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (ant->rx) {
 	case ANTENNA_HW_DIVERSITY:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
 		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
-				  !!(rt2x00dev->curr_hwmode != HWMODE_A));
+				  (rt2x00dev->curr_hwmode != HWMODE_A));
 		break;
 	case ANTENNA_A:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
 		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
-
 		if (rt2x00dev->curr_hwmode == HWMODE_A)
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
 		else
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
 		break;
+	case ANTENNA_SW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
 	case ANTENNA_B:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
 		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
-
 		if (rt2x00dev->curr_hwmode == HWMODE_A)
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
 		else
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
 		break;
 	}
 
@@ -458,8 +460,7 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
 }
 
 static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
-				      const int antenna_tx,
-				      const int antenna_rx)
+				      struct antenna_setup *ant)
 {
 	u8 r3;
 	u8 r4;
@@ -470,22 +471,31 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
 	rt61pci_bbp_read(rt2x00dev, 77, &r77);
 
 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
-			  !rt2x00_rf(&rt2x00dev->chip, RF2527));
+			  rt2x00_rf(&rt2x00dev->chip, RF2529));
 	rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
 			  !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
 
-	switch (antenna_rx) {
-	case ANTENNA_SW_DIVERSITY:
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (ant->rx) {
 	case ANTENNA_HW_DIVERSITY:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
 		break;
 	case ANTENNA_A:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
-		rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
+		rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
 		break;
+	case ANTENNA_SW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
 	case ANTENNA_B:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
-		rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
+		rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
 		break;
 	}
 
@@ -501,23 +511,18 @@ static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev,
 
 	rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
 
-	if (p1 != 0xff) {
-		rt2x00_set_field32(&reg, MAC_CSR13_BIT4, !!p1);
-		rt2x00_set_field32(&reg, MAC_CSR13_BIT12, 0);
-		rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
-	}
-	if (p2 != 0xff) {
-		rt2x00_set_field32(&reg, MAC_CSR13_BIT3, !p2);
-		rt2x00_set_field32(&reg, MAC_CSR13_BIT11, 0);
-		rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
-	}
+	rt2x00_set_field32(&reg, MAC_CSR13_BIT4, p1);
+	rt2x00_set_field32(&reg, MAC_CSR13_BIT12, 0);
+
+	rt2x00_set_field32(&reg, MAC_CSR13_BIT3, !p2);
+	rt2x00_set_field32(&reg, MAC_CSR13_BIT11, 0);
+
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
 }
 
 static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev,
-					const int antenna_tx,
-					const int antenna_rx)
+					struct antenna_setup *ant)
 {
-	u16 eeprom;
 	u8 r3;
 	u8 r4;
 	u8 r77;
@@ -525,70 +530,36 @@ static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev,
 	rt61pci_bbp_read(rt2x00dev, 3, &r3);
 	rt61pci_bbp_read(rt2x00dev, 4, &r4);
 	rt61pci_bbp_read(rt2x00dev, 77, &r77);
-	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
 
-	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
-
-	if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
-	    rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
-		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 1);
-		rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
-	} else if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) {
-		if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED) >= 2) {
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
-			rt61pci_bbp_write(rt2x00dev, 77, r77);
-		}
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
-		rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
-	} else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
-		   rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
-		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
-
-		switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) {
-		case 0:
-			rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
-			break;
-		case 1:
-			rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0);
-			break;
-		case 2:
-			rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
-			break;
-		case 3:
-			rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
-			break;
-		}
-	} else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
-		   !rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
-		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+	/* FIXME: Antenna selection for the rf 2529 is very confusing in the
+	 * legacy driver. The code below should be ok for non-diversity setups.
+	 */
 
-		switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) {
-		case 0:
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
-			rt61pci_bbp_write(rt2x00dev, 77, r77);
-			rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
-			break;
-		case 1:
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
-			rt61pci_bbp_write(rt2x00dev, 77, r77);
-			rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0);
-			break;
-		case 2:
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
-			rt61pci_bbp_write(rt2x00dev, 77, r77);
-			rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
-			break;
-		case 3:
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
-			rt61pci_bbp_write(rt2x00dev, 77, r77);
-			rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
-			break;
-		}
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (ant->rx) {
+	case ANTENNA_A:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
+		rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
+		rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
+		break;
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
+	case ANTENNA_B:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
+		rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
+		rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
+		break;
 	}
 
+	rt61pci_bbp_write(rt2x00dev, 77, r77);
 	rt61pci_bbp_write(rt2x00dev, 3, r3);
 	rt61pci_bbp_write(rt2x00dev, 4, r4);
 }
@@ -625,46 +596,44 @@ static const struct antenna_sel antenna_sel_bg[] = {
 };
 
 static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
-				   const int antenna_tx, const int antenna_rx)
+				   struct antenna_setup *ant)
 {
 	const struct antenna_sel *sel;
 	unsigned int lna;
 	unsigned int i;
 	u32 reg;
 
-	rt2x00pci_register_read(rt2x00dev, PHY_CSR0, &reg);
-
 	if (rt2x00dev->curr_hwmode == HWMODE_A) {
 		sel = antenna_sel_a;
 		lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
-
-		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 0);
-		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 1);
 	} else {
 		sel = antenna_sel_bg;
 		lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
-
-		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 1);
-		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 0);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
 		rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
 
+	rt2x00pci_register_read(rt2x00dev, PHY_CSR0, &reg);
+
+	rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG,
+			   (rt2x00dev->curr_hwmode == HWMODE_B ||
+			    rt2x00dev->curr_hwmode == HWMODE_G));
+	rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A,
+			   (rt2x00dev->curr_hwmode == HWMODE_A));
+
 	rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
 
 	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
 	    rt2x00_rf(&rt2x00dev->chip, RF5325))
-		rt61pci_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx);
+		rt61pci_config_antenna_5x(rt2x00dev, ant);
 	else if (rt2x00_rf(&rt2x00dev->chip, RF2527))
-		rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx);
+		rt61pci_config_antenna_2x(rt2x00dev, ant);
 	else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) {
 		if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
-			rt61pci_config_antenna_2x(rt2x00dev, antenna_tx,
-						  antenna_rx);
+			rt61pci_config_antenna_2x(rt2x00dev, ant);
 		else
-			rt61pci_config_antenna_2529(rt2x00dev, antenna_tx,
-						    antenna_rx);
+			rt61pci_config_antenna_2529(rt2x00dev, ant);
 	}
 }
 
@@ -709,8 +678,7 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev,
 	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
 		rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level);
 	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt61pci_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx,
-				       libconf->conf->antenna_sel_rx);
+		rt61pci_config_antenna(rt2x00dev, &libconf->ant);
 	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
 		rt61pci_config_duration(rt2x00dev, libconf);
 }
@@ -721,7 +689,6 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev,
 static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
-	u16 led_reg;
 	u8 arg0;
 	u8 arg1;
 
@@ -730,15 +697,14 @@ static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev)
 	rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, 30);
 	rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg);
 
-	led_reg = rt2x00dev->led_reg;
-	rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 1);
-	if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)
-		rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 1);
-	else
-		rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 1);
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1);
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS,
+			   (rt2x00dev->rx_status.phymode == MODE_IEEE80211A));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS,
+			   (rt2x00dev->rx_status.phymode != MODE_IEEE80211A));
 
-	arg0 = led_reg & 0xff;
-	arg1 = (led_reg >> 8) & 0xff;
+	arg0 = rt2x00dev->led_reg & 0xff;
+	arg1 = (rt2x00dev->led_reg >> 8) & 0xff;
 
 	rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
 }
@@ -792,7 +758,8 @@ static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
 /*
  * Link tuning
  */
-static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev)
+static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev,
+			       struct link_qual *qual)
 {
 	u32 reg;
 
@@ -800,14 +767,13 @@ static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev)
 	 * Update FCS error count from register.
 	 */
 	rt2x00pci_register_read(rt2x00dev, STA_CSR0, &reg);
-	rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
+	qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
 
 	/*
 	 * Update False CCA count from register.
 	 */
 	rt2x00pci_register_read(rt2x00dev, STA_CSR1, &reg);
-	rt2x00dev->link.false_cca =
-	    rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+	qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
 }
 
 static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
@@ -904,11 +870,11 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
 	 * r17 does not yet exceed upper limit, continue and base
 	 * the r17 tuning on the false CCA count.
 	 */
-	if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+	if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) {
 		if (++r17 > up_bound)
 			r17 = up_bound;
 		rt61pci_bbp_write(rt2x00dev, 17, r17);
-	} else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+	} else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) {
 		if (--r17 < low_bound)
 			r17 = low_bound;
 		rt61pci_bbp_write(rt2x00dev, 17, r17);
@@ -1023,64 +989,46 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
 	return 0;
 }
 
-static void rt61pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev,
+				 struct data_entry *entry)
 {
-	struct data_ring *ring = rt2x00dev->rx;
-	struct data_desc *rxd;
-	unsigned int i;
+	__le32 *rxd = entry->priv;
 	u32 word;
 
-	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
-
-	for (i = 0; i < ring->stats.limit; i++) {
-		rxd = ring->entry[i].priv;
-
-		rt2x00_desc_read(rxd, 5, &word);
-		rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
-				   ring->entry[i].data_dma);
-		rt2x00_desc_write(rxd, 5, word);
+	rt2x00_desc_read(rxd, 5, &word);
+	rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
+			   entry->data_dma);
+	rt2x00_desc_write(rxd, 5, word);
 
-		rt2x00_desc_read(rxd, 0, &word);
-		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
-		rt2x00_desc_write(rxd, 0, word);
-	}
-
-	rt2x00_ring_index_clear(rt2x00dev->rx);
+	rt2x00_desc_read(rxd, 0, &word);
+	rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+	rt2x00_desc_write(rxd, 0, word);
 }
 
-static void rt61pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev,
+				 struct data_entry *entry)
 {
-	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
-	struct data_desc *txd;
-	unsigned int i;
+	__le32 *txd = entry->priv;
 	u32 word;
 
-	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
-
-	for (i = 0; i < ring->stats.limit; i++) {
-		txd = ring->entry[i].priv;
-
-		rt2x00_desc_read(txd, 1, &word);
-		rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
-		rt2x00_desc_write(txd, 1, word);
-
-		rt2x00_desc_read(txd, 5, &word);
-		rt2x00_set_field32(&word, TXD_W5_PID_TYPE, queue);
-		rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, i);
-		rt2x00_desc_write(txd, 5, word);
+	rt2x00_desc_read(txd, 1, &word);
+	rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
+	rt2x00_desc_write(txd, 1, word);
 
-		rt2x00_desc_read(txd, 6, &word);
-		rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
-				   ring->entry[i].data_dma);
-		rt2x00_desc_write(txd, 6, word);
+	rt2x00_desc_read(txd, 5, &word);
+	rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->ring->queue_idx);
+	rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx);
+	rt2x00_desc_write(txd, 5, word);
 
-		rt2x00_desc_read(txd, 0, &word);
-		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
-		rt2x00_desc_write(txd, 0, word);
-	}
+	rt2x00_desc_read(txd, 6, &word);
+	rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
+			   entry->data_dma);
+	rt2x00_desc_write(txd, 6, word);
 
-	rt2x00_ring_index_clear(ring);
+	rt2x00_desc_read(txd, 0, &word);
+	rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+	rt2x00_desc_write(txd, 0, word);
 }
 
 static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev)
@@ -1088,16 +1036,6 @@ static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev)
 	u32 reg;
 
 	/*
-	 * Initialize rings.
-	 */
-	rt61pci_init_rxring(rt2x00dev);
-	rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
-	rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
-	rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA2);
-	rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA3);
-	rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA4);
-
-	/*
 	 * Initialize registers.
 	 */
 	rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, &reg);
@@ -1565,12 +1503,12 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
  * TX descriptor initialization
  */
 static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-				  struct data_desc *txd,
-				  struct txdata_entry_desc *desc,
-				  struct ieee80211_hdr *ieee80211hdr,
-				  unsigned int length,
-				  struct ieee80211_tx_control *control)
+				    struct sk_buff *skb,
+				    struct txdata_entry_desc *desc,
+				    struct ieee80211_tx_control *control)
 {
+	struct skb_desc *skbdesc = get_skb_desc(skb);
+	__le32 *txd = skbdesc->desc;
 	u32 word;
 
 	/*
@@ -1599,7 +1537,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_desc_write(txd, 5, word);
 
 	rt2x00_desc_read(txd, 11, &word);
-	rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, length);
+	rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len);
 	rt2x00_desc_write(txd, 11, word);
 
 	rt2x00_desc_read(txd, 0, &word);
@@ -1608,7 +1546,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
 			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_ACK,
-			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
+			   test_bit(ENTRY_TXD_ACK, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
 			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_OFDM,
@@ -1618,7 +1556,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 			   !!(control->flags &
 			      IEEE80211_TXCTL_LONG_RETRY_LIMIT));
 	rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
-	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
 	rt2x00_set_field32(&word, TXD_W0_BURST,
 			   test_bit(ENTRY_TXD_BURST, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
@@ -1649,16 +1587,16 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 	}
 
 	rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
-	if (queue == IEEE80211_TX_QUEUE_DATA0)
-		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
-	else if (queue == IEEE80211_TX_QUEUE_DATA1)
-		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
-	else if (queue == IEEE80211_TX_QUEUE_DATA2)
-		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
-	else if (queue == IEEE80211_TX_QUEUE_DATA3)
-		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
-	else if (queue == IEEE80211_TX_QUEUE_DATA4)
-		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_MGMT, 1);
+	rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0,
+			   (queue == IEEE80211_TX_QUEUE_DATA0));
+	rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1,
+			   (queue == IEEE80211_TX_QUEUE_DATA1));
+	rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2,
+			   (queue == IEEE80211_TX_QUEUE_DATA2));
+	rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3,
+			   (queue == IEEE80211_TX_QUEUE_DATA3));
+	rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_MGMT,
+			   (queue == IEEE80211_TX_QUEUE_DATA4));
 	rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
 }
 
@@ -1709,7 +1647,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
 static void rt61pci_fill_rxdone(struct data_entry *entry,
 			        struct rxdata_entry_desc *desc)
 {
-	struct data_desc *rxd = entry->priv;
+	__le32 *rxd = entry->priv;
 	u32 word0;
 	u32 word1;
 
@@ -1727,8 +1665,7 @@ static void rt61pci_fill_rxdone(struct data_entry *entry,
 	desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
 	desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
 	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
-
-	return;
+	desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
 }
 
 /*
@@ -1739,7 +1676,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
 	struct data_ring *ring;
 	struct data_entry *entry;
 	struct data_entry *entry_done;
-	struct data_desc *txd;
+	__le32 *txd;
 	u32 word;
 	u32 reg;
 	u32 old_reg;
@@ -1809,24 +1746,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
 		tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
 		retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
 
-		rt2x00lib_txdone(entry, tx_status, retry);
-
-		/*
-		 * Make this entry available for reuse.
-		 */
-		entry->flags = 0;
-		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
-		rt2x00_desc_write(txd, 0, word);
-		rt2x00_ring_index_done_inc(entry->ring);
-
-		/*
-		 * If the data ring was full before the txdone handler
-		 * we must make sure the packet queue in the mac80211 stack
-		 * is reenabled when the txdone handler has finished.
-		 */
-		if (!rt2x00_ring_full(ring))
-			ieee80211_wake_queue(rt2x00dev->hw,
-					     entry->tx_status.control.queue);
+		rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry);
 	}
 }
 
@@ -1920,8 +1840,10 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
 	if (word == 0xffff) {
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
-		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2);
-		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT,
+				   ANTENNA_B);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT,
+				   ANTENNA_B);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
@@ -2025,11 +1947,17 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	}
 
 	/*
+	 * Determine number of antenna's.
+	 */
+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
+		__set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
+
+	/*
 	 * Identify default antenna configuration.
 	 */
-	rt2x00dev->hw->conf.antenna_sel_tx =
+	rt2x00dev->default_ant.tx =
 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
-	rt2x00dev->hw->conf.antenna_sel_rx =
+	rt2x00dev->default_ant.rx =
 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
 
 	/*
@@ -2039,12 +1967,6 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
 		__set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
 
 	/*
-	 * Determine number of antenna's.
-	 */
-	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
-		__set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
-
-	/*
 	 * Detect if this device has an hardware controlled radio.
 	 */
 #ifdef CONFIG_RT61PCI_RFKILL
@@ -2072,6 +1994,38 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
 		__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
 
 	/*
+	 * When working with a RF2529 chip without double antenna
+	 * the antenna settings should be gathered from the NIC
+	 * eeprom word.
+	 */
+	if (rt2x00_rf(&rt2x00dev->chip, RF2529) &&
+	    !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) {
+		switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) {
+		case 0:
+			rt2x00dev->default_ant.tx = ANTENNA_B;
+			rt2x00dev->default_ant.rx = ANTENNA_A;
+			break;
+		case 1:
+			rt2x00dev->default_ant.tx = ANTENNA_B;
+			rt2x00dev->default_ant.rx = ANTENNA_B;
+			break;
+		case 2:
+			rt2x00dev->default_ant.tx = ANTENNA_A;
+			rt2x00dev->default_ant.rx = ANTENNA_A;
+			break;
+		case 3:
+			rt2x00dev->default_ant.tx = ANTENNA_A;
+			rt2x00dev->default_ant.rx = ANTENNA_B;
+			break;
+		}
+
+		if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY))
+			rt2x00dev->default_ant.tx = ANTENNA_SW_DIVERSITY;
+		if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY))
+			rt2x00dev->default_ant.rx = ANTENNA_SW_DIVERSITY;
+	}
+
+	/*
 	 * Store led settings, for correct led behaviour.
 	 * If the eeprom value is invalid,
 	 * switch to default led mode.
@@ -2325,7 +2279,6 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw,
 				     struct dev_addr_list *mc_list)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct interface *intf = &rt2x00dev->interface;
 	u32 reg;
 
 	/*
@@ -2344,22 +2297,19 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw,
 	 * Apply some rules to the filters:
 	 * - Some filters imply different filters to be set.
 	 * - Some things we can't filter out at all.
-	 * - Some filters are set based on interface type.
 	 */
 	if (mc_count)
 		*total_flags |= FIF_ALLMULTI;
 	if (*total_flags & FIF_OTHER_BSS ||
 	    *total_flags & FIF_PROMISC_IN_BSS)
 		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
-	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
-		*total_flags |= FIF_PROMISC_IN_BSS;
 
 	/*
 	 * Check if there is any work left for us.
 	 */
-	if (intf->filter == *total_flags)
+	if (rt2x00dev->packet_filter == *total_flags)
 		return;
-	intf->filter = *total_flags;
+	rt2x00dev->packet_filter = *total_flags;
 
 	/*
 	 * Start configuration steps.
@@ -2426,6 +2376,9 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 			  struct ieee80211_tx_control *control)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct skb_desc *desc;
+	struct data_ring *ring;
+	struct data_entry *entry;
 
 	/*
 	 * Just in case the ieee80211 doesn't set this,
@@ -2433,6 +2386,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 	 * initialization.
 	 */
 	control->queue = IEEE80211_TX_QUEUE_BEACON;
+	ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
+	entry = rt2x00_get_data_entry(ring);
 
 	/*
 	 * We need to append the descriptor in front of the
@@ -2446,15 +2401,23 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 	}
 
 	/*
-	 * First we create the beacon.
+	 * Add the descriptor in front of the skb.
+	 */
+	skb_push(skb, ring->desc_size);
+	memset(skb->data, 0, ring->desc_size);
+
+	/*
+	 * Fill in skb descriptor
 	 */
-	skb_push(skb, TXD_DESC_SIZE);
-	memset(skb->data, 0, TXD_DESC_SIZE);
+	desc = get_skb_desc(skb);
+	desc->desc_len = ring->desc_size;
+	desc->data_len = skb->len - ring->desc_size;
+	desc->desc = skb->data;
+	desc->data = skb->data + ring->desc_size;
+	desc->ring = ring;
+	desc->entry = entry;
 
-	rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
-				(struct ieee80211_hdr *)(skb->data +
-							 TXD_DESC_SIZE),
-				skb->len - TXD_DESC_SIZE, control);
+	rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
 
 	/*
 	 * Write entire beacon with descriptor to register,
@@ -2478,7 +2441,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
 	.configure_filter	= rt61pci_configure_filter,
 	.get_stats		= rt2x00mac_get_stats,
 	.set_retry_limit	= rt61pci_set_retry_limit,
-	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
+	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt61pci_get_tsf,
@@ -2493,6 +2456,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
 	.load_firmware		= rt61pci_load_firmware,
 	.initialize		= rt2x00pci_initialize,
 	.uninitialize		= rt2x00pci_uninitialize,
+	.init_rxentry		= rt61pci_init_rxentry,
+	.init_txentry		= rt61pci_init_txentry,
 	.set_device_state	= rt61pci_set_device_state,
 	.rfkill_poll		= rt61pci_rfkill_poll,
 	.link_stats		= rt61pci_link_stats,
@@ -2510,7 +2475,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
 };
 
 static const struct rt2x00_ops rt61pci_ops = {
-	.name		= DRV_NAME,
+	.name		= KBUILD_MODNAME,
 	.rxd_size	= RXD_DESC_SIZE,
 	.txd_size	= TXD_DESC_SIZE,
 	.eeprom_size	= EEPROM_SIZE,
@@ -2547,7 +2512,7 @@ MODULE_FIRMWARE(FIRMWARE_RT2661);
 MODULE_LICENSE("GPL");
 
 static struct pci_driver rt61pci_driver = {
-	.name		= DRV_NAME,
+	.name		= KBUILD_MODNAME,
 	.id_table	= rt61pci_device_table,
 	.probe		= rt2x00pci_probe,
 	.remove		= __devexit_p(rt2x00pci_remove),
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 6721d7dd32bc..4c6524eedad0 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -1077,13 +1077,19 @@ struct hw_pairwise_ta_entry {
  * R4: RX antenna control
  * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529)
  */
-#define BBP_R4_RX_ANTENNA		FIELD8(0x03)
+
+/*
+ * ANTENNA_CONTROL semantics (guessed):
+ * 0x1: Software controlled antenna switching (fixed or SW diversity)
+ * 0x2: Hardware diversity.
+ */
+#define BBP_R4_RX_ANTENNA_CONTROL	FIELD8(0x03)
 #define BBP_R4_RX_FRAME_END		FIELD8(0x20)
 
 /*
  * R77
  */
-#define BBP_R77_PAIR			FIELD8(0x03)
+#define BBP_R77_RX_ANTENNA		FIELD8(0x03)
 
 /*
  * RF registers
@@ -1240,8 +1246,8 @@ struct hw_pairwise_ta_entry {
 /*
  * DMA descriptor defines.
  */
-#define TXD_DESC_SIZE			( 16 * sizeof(struct data_desc) )
-#define RXD_DESC_SIZE			( 16 * sizeof(struct data_desc) )
+#define TXD_DESC_SIZE			( 16 * sizeof(__le32) )
+#define RXD_DESC_SIZE			( 16 * sizeof(__le32) )
 
 /*
  * TX descriptor format for TX, PRIO and Beacon Ring.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index c0671c2e6e73..4d576ab3e7f9 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -24,11 +24,6 @@
 	Supported chipsets: rt2571W & rt2671.
  */
 
-/*
- * Set enviroment defines for rt2x00.h
- */
-#define DRV_NAME "rt73usb"
-
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
@@ -52,8 +47,9 @@
  * between each attampt. When the busy bit is still set at that time,
  * the access attempt is considered to have failed,
  * and we will print an error.
+ * The _lock versions must be used if you already hold the usb_cache_mutex
  */
-static inline void rt73usb_register_read(const struct rt2x00_dev *rt2x00dev,
+static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev,
 					 const unsigned int offset, u32 *value)
 {
 	__le32 reg;
@@ -63,8 +59,17 @@ static inline void rt73usb_register_read(const struct rt2x00_dev *rt2x00dev,
 	*value = le32_to_cpu(reg);
 }
 
-static inline void rt73usb_register_multiread(const struct rt2x00_dev
-					      *rt2x00dev,
+static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev,
+					      const unsigned int offset, u32 *value)
+{
+	__le32 reg;
+	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ,
+				       USB_VENDOR_REQUEST_IN, offset,
+				       &reg, sizeof(u32), REGISTER_TIMEOUT);
+	*value = le32_to_cpu(reg);
+}
+
+static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev,
 					      const unsigned int offset,
 					      void *value, const u32 length)
 {
@@ -74,7 +79,7 @@ static inline void rt73usb_register_multiread(const struct rt2x00_dev
 				      value, length, timeout);
 }
 
-static inline void rt73usb_register_write(const struct rt2x00_dev *rt2x00dev,
+static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev,
 					  const unsigned int offset, u32 value)
 {
 	__le32 reg = cpu_to_le32(value);
@@ -83,8 +88,16 @@ static inline void rt73usb_register_write(const struct rt2x00_dev *rt2x00dev,
 				      &reg, sizeof(u32), REGISTER_TIMEOUT);
 }
 
-static inline void rt73usb_register_multiwrite(const struct rt2x00_dev
-					       *rt2x00dev,
+static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
+					       const unsigned int offset, u32 value)
+{
+	__le32 reg = cpu_to_le32(value);
+	rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE,
+				       USB_VENDOR_REQUEST_OUT, offset,
+				      &reg, sizeof(u32), REGISTER_TIMEOUT);
+}
+
+static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
 					       const unsigned int offset,
 					       void *value, const u32 length)
 {
@@ -94,13 +107,13 @@ static inline void rt73usb_register_multiwrite(const struct rt2x00_dev
 				      value, length, timeout);
 }
 
-static u32 rt73usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
+static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev)
 {
 	u32 reg;
 	unsigned int i;
 
 	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt73usb_register_read(rt2x00dev, PHY_CSR3, &reg);
+		rt73usb_register_read_lock(rt2x00dev, PHY_CSR3, &reg);
 		if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
 			break;
 		udelay(REGISTER_BUSY_DELAY);
@@ -109,17 +122,20 @@ static u32 rt73usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
 	return reg;
 }
 
-static void rt73usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
+static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev,
 			      const unsigned int word, const u8 value)
 {
 	u32 reg;
 
+	mutex_lock(&rt2x00dev->usb_cache_mutex);
+
 	/*
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt73usb_bbp_check(rt2x00dev);
 	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
 		ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
+		mutex_unlock(&rt2x00dev->usb_cache_mutex);
 		return;
 	}
 
@@ -132,20 +148,24 @@ static void rt73usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
 	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
 
-	rt73usb_register_write(rt2x00dev, PHY_CSR3, reg);
+	rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
-static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
+static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev,
 			     const unsigned int word, u8 *value)
 {
 	u32 reg;
 
+	mutex_lock(&rt2x00dev->usb_cache_mutex);
+
 	/*
 	 * Wait until the BBP becomes ready.
 	 */
 	reg = rt73usb_bbp_check(rt2x00dev);
 	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
 		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+		mutex_unlock(&rt2x00dev->usb_cache_mutex);
 		return;
 	}
 
@@ -157,7 +177,7 @@ static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
 	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
 
-	rt73usb_register_write(rt2x00dev, PHY_CSR3, reg);
+	rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg);
 
 	/*
 	 * Wait until the BBP becomes ready.
@@ -170,9 +190,10 @@ static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
 	}
 
 	*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
-static void rt73usb_rf_write(const struct rt2x00_dev *rt2x00dev,
+static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
 			     const unsigned int word, const u32 value)
 {
 	u32 reg;
@@ -181,13 +202,16 @@ static void rt73usb_rf_write(const struct rt2x00_dev *rt2x00dev,
 	if (!word)
 		return;
 
+	mutex_lock(&rt2x00dev->usb_cache_mutex);
+
 	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-		rt73usb_register_read(rt2x00dev, PHY_CSR4, &reg);
+		rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, &reg);
 		if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
 			goto rf_write;
 		udelay(REGISTER_BUSY_DELAY);
 	}
 
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
 	ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
 	return;
 
@@ -200,25 +224,26 @@ rf_write:
 	 * all others contain 20 bits.
 	 */
 	rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
-			   20 + !!(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
-				   rt2x00_rf(&rt2x00dev->chip, RF2527)));
+			   20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+				 rt2x00_rf(&rt2x00dev->chip, RF2527)));
 	rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
 	rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
 
-	rt73usb_register_write(rt2x00dev, PHY_CSR4, reg);
+	rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg);
 	rt2x00_rf_write(rt2x00dev, word, value);
+	mutex_unlock(&rt2x00dev->usb_cache_mutex);
 }
 
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 #define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
 
-static void rt73usb_read_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt73usb_read_csr(struct rt2x00_dev *rt2x00dev,
 			     const unsigned int word, u32 *data)
 {
 	rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data);
 }
 
-static void rt73usb_write_csr(const struct rt2x00_dev *rt2x00dev,
+static void rt73usb_write_csr(struct rt2x00_dev *rt2x00dev,
 			      const unsigned int word, u32 data)
 {
 	rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
@@ -302,7 +327,8 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
 	 */
 	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
-	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE,
+			   (tsf_sync == TSF_SYNC_BEACON));
 	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
 	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync);
 	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
@@ -396,12 +422,12 @@ static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
 }
 
 static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
-				      const int antenna_tx,
-				      const int antenna_rx)
+				      struct antenna_setup *ant)
 {
 	u8 r3;
 	u8 r4;
 	u8 r77;
+	u8 temp;
 
 	rt73usb_bbp_read(rt2x00dev, 3, &r3);
 	rt73usb_bbp_read(rt2x00dev, 4, &r4);
@@ -409,30 +435,38 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
 
 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
 
-	switch (antenna_rx) {
-	case ANTENNA_SW_DIVERSITY:
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (ant->rx) {
 	case ANTENNA_HW_DIVERSITY:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
-		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
-				  !!(rt2x00dev->curr_hwmode != HWMODE_A));
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
+		temp = !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)
+		       && (rt2x00dev->curr_hwmode != HWMODE_A);
+		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp);
 		break;
 	case ANTENNA_A:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
 		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
-
 		if (rt2x00dev->curr_hwmode == HWMODE_A)
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
 		else
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
 		break;
+	case ANTENNA_SW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
 	case ANTENNA_B:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
 		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
-
 		if (rt2x00dev->curr_hwmode == HWMODE_A)
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
 		else
-			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+			rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
 		break;
 	}
 
@@ -442,8 +476,7 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
 }
 
 static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
-				      const int antenna_tx,
-				      const int antenna_rx)
+				      struct antenna_setup *ant)
 {
 	u8 r3;
 	u8 r4;
@@ -457,18 +490,27 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
 			  !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
 
-	switch (antenna_rx) {
-	case ANTENNA_SW_DIVERSITY:
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (ant->rx) {
 	case ANTENNA_HW_DIVERSITY:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
 		break;
 	case ANTENNA_A:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
-		rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+		rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
 		break;
+	case ANTENNA_SW_DIVERSITY:
+		/*
+		 * NOTE: We should never come here because rt2x00lib is
+		 * supposed to catch this and send us the correct antenna
+		 * explicitely. However we are nog going to bug about this.
+		 * Instead, just default to antenna B.
+		 */
 	case ANTENNA_B:
-		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
-		rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+		rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0);
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1);
 		break;
 	}
 
@@ -509,40 +551,40 @@ static const struct antenna_sel antenna_sel_bg[] = {
 };
 
 static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
-				   const int antenna_tx, const int antenna_rx)
+				   struct antenna_setup *ant)
 {
 	const struct antenna_sel *sel;
 	unsigned int lna;
 	unsigned int i;
 	u32 reg;
 
-	rt73usb_register_read(rt2x00dev, PHY_CSR0, &reg);
-
 	if (rt2x00dev->curr_hwmode == HWMODE_A) {
 		sel = antenna_sel_a;
 		lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
-
-		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 0);
-		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 1);
 	} else {
 		sel = antenna_sel_bg;
 		lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
-
-		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 1);
-		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 0);
 	}
 
 	for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
 		rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
 
+	rt73usb_register_read(rt2x00dev, PHY_CSR0, &reg);
+
+	rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG,
+			   (rt2x00dev->curr_hwmode == HWMODE_B ||
+			    rt2x00dev->curr_hwmode == HWMODE_G));
+	rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A,
+			   (rt2x00dev->curr_hwmode == HWMODE_A));
+
 	rt73usb_register_write(rt2x00dev, PHY_CSR0, reg);
 
 	if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
 	    rt2x00_rf(&rt2x00dev->chip, RF5225))
-		rt73usb_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx);
+		rt73usb_config_antenna_5x(rt2x00dev, ant);
 	else if (rt2x00_rf(&rt2x00dev->chip, RF2528) ||
 		 rt2x00_rf(&rt2x00dev->chip, RF2527))
-		rt73usb_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx);
+		rt73usb_config_antenna_2x(rt2x00dev, ant);
 }
 
 static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
@@ -586,8 +628,7 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
 	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
 		rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level);
 	if (flags & CONFIG_UPDATE_ANTENNA)
-		rt73usb_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx,
-				       libconf->conf->antenna_sel_rx);
+		rt73usb_config_antenna(rt2x00dev, &libconf->ant);
 	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
 		rt73usb_config_duration(rt2x00dev, libconf);
 }
@@ -605,12 +646,10 @@ static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev)
 	rt73usb_register_write(rt2x00dev, MAC_CSR14, reg);
 
 	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1);
-	if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)
-		rt2x00_set_field16(&rt2x00dev->led_reg,
-				   MCU_LEDCS_LINK_A_STATUS, 1);
-	else
-		rt2x00_set_field16(&rt2x00dev->led_reg,
-				   MCU_LEDCS_LINK_BG_STATUS, 1);
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS,
+			   (rt2x00dev->rx_status.phymode == MODE_IEEE80211A));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS,
+			   (rt2x00dev->rx_status.phymode != MODE_IEEE80211A));
 
 	rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000,
 				    rt2x00dev->led_reg, REGISTER_TIMEOUT);
@@ -659,7 +698,8 @@ static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
 /*
  * Link tuning
  */
-static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev)
+static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev,
+			       struct link_qual *qual)
 {
 	u32 reg;
 
@@ -667,15 +707,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev)
 	 * Update FCS error count from register.
 	 */
 	rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
-	rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
+	qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
 
 	/*
 	 * Update False CCA count from register.
 	 */
 	rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
-	reg = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
-	rt2x00dev->link.false_cca =
-	    rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+	qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
 }
 
 static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
@@ -781,12 +819,12 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
 	 * r17 does not yet exceed upper limit, continue and base
 	 * the r17 tuning on the false CCA count.
 	 */
-	if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+	if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) {
 		r17 += 4;
 		if (r17 > up_bound)
 			r17 = up_bound;
 		rt73usb_bbp_write(rt2x00dev, 17, r17);
-	} else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+	} else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) {
 		r17 -= 4;
 		if (r17 < low_bound)
 			r17 = low_bound;
@@ -1098,8 +1136,6 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
 		return -EIO;
 	}
 
-	rt2x00usb_enable_radio(rt2x00dev);
-
 	/*
 	 * Enable LED
 	 */
@@ -1193,12 +1229,12 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
  * TX descriptor initialization
  */
 static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
-				  struct data_desc *txd,
-				  struct txdata_entry_desc *desc,
-				  struct ieee80211_hdr *ieee80211hdr,
-				  unsigned int length,
-				  struct ieee80211_tx_control *control)
+				    struct sk_buff *skb,
+				    struct txdata_entry_desc *desc,
+				    struct ieee80211_tx_control *control)
 {
+	struct skb_desc *skbdesc = get_skb_desc(skb);
+	__le32 *txd = skbdesc->desc;
 	u32 word;
 
 	/*
@@ -1233,7 +1269,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
 			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_ACK,
-			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
+			   test_bit(ENTRY_TXD_ACK, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
 			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_OFDM,
@@ -1243,7 +1279,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 			   !!(control->flags &
 			      IEEE80211_TXCTL_LONG_RETRY_LIMIT));
 	rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
-	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len);
 	rt2x00_set_field32(&word, TXD_W0_BURST2,
 			   test_bit(ENTRY_TXD_BURST, &desc->flags));
 	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
@@ -1340,7 +1376,8 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
 static void rt73usb_fill_rxdone(struct data_entry *entry,
 			        struct rxdata_entry_desc *desc)
 {
-	struct data_desc *rxd = (struct data_desc *)entry->skb->data;
+	struct skb_desc *skbdesc = get_skb_desc(entry->skb);
+	__le32 *rxd = (__le32 *)entry->skb->data;
 	u32 word0;
 	u32 word1;
 
@@ -1358,13 +1395,15 @@ static void rt73usb_fill_rxdone(struct data_entry *entry,
 	desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1);
 	desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
 	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+	desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS);
 
 	/*
-	 * Pull the skb to clear the descriptor area.
+	 * Set descriptor and data pointer.
 	 */
-	skb_pull(entry->skb, entry->ring->desc_size);
-
-	return;
+	skbdesc->desc = entry->skb->data;
+	skbdesc->desc_len = entry->ring->desc_size;
+	skbdesc->data = entry->skb->data + entry->ring->desc_size;
+	skbdesc->data_len = desc->size;
 }
 
 /*
@@ -1392,8 +1431,10 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
 	if (word == 0xffff) {
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
-		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2);
-		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT,
+				   ANTENNA_B);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT,
+				   ANTENNA_B);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
 		rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
@@ -1502,9 +1543,9 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
 	/*
 	 * Identify default antenna configuration.
 	 */
-	rt2x00dev->hw->conf.antenna_sel_tx =
+	rt2x00dev->default_ant.tx =
 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
-	rt2x00dev->hw->conf.antenna_sel_rx =
+	rt2x00dev->default_ant.rx =
 	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
 
 	/*
@@ -1806,7 +1847,6 @@ static void rt73usb_configure_filter(struct ieee80211_hw *hw,
 				     struct dev_addr_list *mc_list)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
-	struct interface *intf = &rt2x00dev->interface;
 	u32 reg;
 
 	/*
@@ -1825,22 +1865,19 @@ static void rt73usb_configure_filter(struct ieee80211_hw *hw,
 	 * Apply some rules to the filters:
 	 * - Some filters imply different filters to be set.
 	 * - Some things we can't filter out at all.
-	 * - Some filters are set based on interface type.
 	 */
 	if (mc_count)
 		*total_flags |= FIF_ALLMULTI;
 	if (*total_flags & FIF_OTHER_BSS ||
 	    *total_flags & FIF_PROMISC_IN_BSS)
 		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
-	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
-		*total_flags |= FIF_PROMISC_IN_BSS;
 
 	/*
 	 * Check if there is any work left for us.
 	 */
-	if (intf->filter == *total_flags)
+	if (rt2x00dev->packet_filter == *total_flags)
 		return;
-	intf->filter = *total_flags;
+	rt2x00dev->packet_filter = *total_flags;
 
 	/*
 	 * When in atomic context, reschedule and let rt2x00lib
@@ -1926,6 +1963,9 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 			  struct ieee80211_tx_control *control)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct skb_desc *desc;
+	struct data_ring *ring;
+	struct data_entry *entry;
 	int timeout;
 
 	/*
@@ -1934,17 +1974,27 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
 	 * initialization.
 	 */
 	control->queue = IEEE80211_TX_QUEUE_BEACON;
+	ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
+	entry = rt2x00_get_data_entry(ring);
+
+	/*
+	 * Add the descriptor in front of the skb.
+	 */
+	skb_push(skb, ring->desc_size);
+	memset(skb->data, 0, ring->desc_size);
 
 	/*
-	 * First we create the beacon.
+	 * Fill in skb descriptor
 	 */
-	skb_push(skb, TXD_DESC_SIZE);
-	memset(skb->data, 0, TXD_DESC_SIZE);
+	desc = get_skb_desc(skb);
+	desc->desc_len = ring->desc_size;
+	desc->data_len = skb->len - ring->desc_size;
+	desc->desc = skb->data;
+	desc->data = skb->data + ring->desc_size;
+	desc->ring = ring;
+	desc->entry = entry;
 
-	rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
-				(struct ieee80211_hdr *)(skb->data +
-							 TXD_DESC_SIZE),
-				skb->len - TXD_DESC_SIZE, control);
+	rt2x00lib_write_tx_desc(rt2x00dev, skb, control);
 
 	/*
 	 * Write entire beacon with descriptor to register,
@@ -1971,7 +2021,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
 	.configure_filter	= rt73usb_configure_filter,
 	.get_stats		= rt2x00mac_get_stats,
 	.set_retry_limit	= rt73usb_set_retry_limit,
-	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
+	.bss_info_changed	= rt2x00mac_bss_info_changed,
 	.conf_tx		= rt2x00mac_conf_tx,
 	.get_tx_stats		= rt2x00mac_get_tx_stats,
 	.get_tsf		= rt73usb_get_tsf,
@@ -1985,6 +2035,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
 	.load_firmware		= rt73usb_load_firmware,
 	.initialize		= rt2x00usb_initialize,
 	.uninitialize		= rt2x00usb_uninitialize,
+	.init_rxentry		= rt2x00usb_init_rxentry,
+	.init_txentry		= rt2x00usb_init_txentry,
 	.set_device_state	= rt73usb_set_device_state,
 	.link_stats		= rt73usb_link_stats,
 	.reset_tuner		= rt73usb_reset_tuner,
@@ -2002,7 +2054,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
 };
 
 static const struct rt2x00_ops rt73usb_ops = {
-	.name		= DRV_NAME,
+	.name		= KBUILD_MODNAME,
 	.rxd_size	= RXD_DESC_SIZE,
 	.txd_size	= TXD_DESC_SIZE,
 	.eeprom_size	= EEPROM_SIZE,
@@ -2089,7 +2141,7 @@ MODULE_FIRMWARE(FIRMWARE_RT2571);
 MODULE_LICENSE("GPL");
 
 static struct usb_driver rt73usb_driver = {
-	.name		= DRV_NAME,
+	.name		= KBUILD_MODNAME,
 	.id_table	= rt73usb_device_table,
 	.probe		= rt2x00usb_probe,
 	.disconnect	= rt2x00usb_disconnect,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index f0951519f74b..d49dcaacecee 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -713,13 +713,19 @@ struct hw_pairwise_ta_entry {
  * R4: RX antenna control
  * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529)
  */
-#define BBP_R4_RX_ANTENNA		FIELD8(0x03)
+
+/*
+ * ANTENNA_CONTROL semantics (guessed):
+ * 0x1: Software controlled antenna switching (fixed or SW diversity)
+ * 0x2: Hardware diversity.
+ */
+#define BBP_R4_RX_ANTENNA_CONTROL	FIELD8(0x03)
 #define BBP_R4_RX_FRAME_END		FIELD8(0x20)
 
 /*
  * R77
  */
-#define BBP_R77_PAIR			FIELD8(0x03)
+#define BBP_R77_RX_ANTENNA		FIELD8(0x03)
 
 /*
  * RF registers
@@ -860,8 +866,8 @@ struct hw_pairwise_ta_entry {
 /*
  * DMA descriptor defines.
  */
-#define TXD_DESC_SIZE			( 6 * sizeof(struct data_desc) )
-#define RXD_DESC_SIZE			( 6 * sizeof(struct data_desc) )
+#define TXD_DESC_SIZE			( 6 * sizeof(__le32) )
+#define RXD_DESC_SIZE			( 6 * sizeof(__le32) )
 
 /*
  * TX descriptor format for TX, PRIO and Beacon Ring.
diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl8180.h
new file mode 100644
index 000000000000..2cbfe3c8081f
--- /dev/null
+++ b/drivers/net/wireless/rtl8180.h
@@ -0,0 +1,151 @@
+#ifndef RTL8180_H
+#define RTL8180_H
+
+#include "rtl818x.h"
+
+#define MAX_RX_SIZE IEEE80211_MAX_RTS_THRESHOLD
+
+#define RF_PARAM_ANALOGPHY	(1 << 0)
+#define RF_PARAM_ANTBDEFAULT	(1 << 1)
+#define RF_PARAM_CARRIERSENSE1	(1 << 2)
+#define RF_PARAM_CARRIERSENSE2	(1 << 3)
+
+#define BB_ANTATTEN_CHAN14	0x0C
+#define BB_ANTENNA_B 		0x40
+
+#define BB_HOST_BANG 		(1 << 30)
+#define BB_HOST_BANG_EN 	(1 << 2)
+#define BB_HOST_BANG_CLK 	(1 << 1)
+#define BB_HOST_BANG_DATA	1
+
+#define ANAPARAM_TXDACOFF_SHIFT	27
+#define ANAPARAM_PWR0_SHIFT	28
+#define ANAPARAM_PWR0_MASK 	(0x07 << ANAPARAM_PWR0_SHIFT)
+#define ANAPARAM_PWR1_SHIFT	20
+#define ANAPARAM_PWR1_MASK	(0x7F << ANAPARAM_PWR1_SHIFT)
+
+enum rtl8180_tx_desc_flags {
+	RTL8180_TX_DESC_FLAG_NO_ENC	= (1 << 15),
+	RTL8180_TX_DESC_FLAG_TX_OK	= (1 << 15),
+	RTL8180_TX_DESC_FLAG_SPLCP	= (1 << 16),
+	RTL8180_TX_DESC_FLAG_RX_UNDER	= (1 << 16),
+	RTL8180_TX_DESC_FLAG_MOREFRAG	= (1 << 17),
+	RTL8180_TX_DESC_FLAG_CTS	= (1 << 18),
+	RTL8180_TX_DESC_FLAG_RTS	= (1 << 23),
+	RTL8180_TX_DESC_FLAG_LS		= (1 << 28),
+	RTL8180_TX_DESC_FLAG_FS		= (1 << 29),
+	RTL8180_TX_DESC_FLAG_DMA	= (1 << 30),
+	RTL8180_TX_DESC_FLAG_OWN	= (1 << 31)
+};
+
+struct rtl8180_tx_desc {
+	__le32 flags;
+	__le16 rts_duration;
+	__le16 plcp_len;
+	__le32 tx_buf;
+	__le32 frame_len;
+	__le32 next_tx_desc;
+	u8 cw;
+	u8 retry_limit;
+	u8 agc;
+	u8 flags2;
+	u32 reserved[2];
+} __attribute__ ((packed));
+
+enum rtl8180_rx_desc_flags {
+	RTL8180_RX_DESC_FLAG_ICV_ERR	= (1 << 12),
+	RTL8180_RX_DESC_FLAG_CRC32_ERR	= (1 << 13),
+	RTL8180_RX_DESC_FLAG_PM		= (1 << 14),
+	RTL8180_RX_DESC_FLAG_RX_ERR	= (1 << 15),
+	RTL8180_RX_DESC_FLAG_BCAST	= (1 << 16),
+	RTL8180_RX_DESC_FLAG_PAM	= (1 << 17),
+	RTL8180_RX_DESC_FLAG_MCAST	= (1 << 18),
+	RTL8180_RX_DESC_FLAG_SPLCP	= (1 << 25),
+	RTL8180_RX_DESC_FLAG_FOF	= (1 << 26),
+	RTL8180_RX_DESC_FLAG_DMA_FAIL	= (1 << 27),
+	RTL8180_RX_DESC_FLAG_LS		= (1 << 28),
+	RTL8180_RX_DESC_FLAG_FS		= (1 << 29),
+	RTL8180_RX_DESC_FLAG_EOR	= (1 << 30),
+	RTL8180_RX_DESC_FLAG_OWN	= (1 << 31)
+};
+
+struct rtl8180_rx_desc {
+	__le32 flags;
+	__le32 flags2;
+	union {
+		__le32 rx_buf;
+		__le64 tsft;
+	};
+} __attribute__ ((packed));
+
+struct rtl8180_tx_ring {
+	struct rtl8180_tx_desc *desc;
+	dma_addr_t dma;
+	unsigned int idx;
+	unsigned int entries;
+	struct sk_buff_head queue;
+};
+
+struct rtl8180_priv {
+	/* common between rtl818x drivers */
+	struct rtl818x_csr __iomem *map;
+	const struct rtl818x_rf_ops *rf;
+	struct ieee80211_vif *vif;
+	int mode;
+
+	/* rtl8180 driver specific */
+	spinlock_t lock;
+	struct rtl8180_rx_desc *rx_ring;
+	dma_addr_t rx_ring_dma;
+	unsigned int rx_idx;
+	struct sk_buff *rx_buf[32];
+	struct rtl8180_tx_ring tx_ring[4];
+	struct ieee80211_channel channels[14];
+	struct ieee80211_rate rates[12];
+	struct ieee80211_hw_mode modes[2];
+	struct pci_dev *pdev;
+	u32 rx_conf;
+
+	int r8185;
+	u32 anaparam;
+	u16 rfparam;
+	u8 csthreshold;
+};
+
+void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
+void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam);
+
+static inline u8 rtl818x_ioread8(struct rtl8180_priv *priv, u8 __iomem *addr)
+{
+	return ioread8(addr);
+}
+
+static inline u16 rtl818x_ioread16(struct rtl8180_priv *priv, __le16 __iomem *addr)
+{
+	return ioread16(addr);
+}
+
+static inline u32 rtl818x_ioread32(struct rtl8180_priv *priv, __le32 __iomem *addr)
+{
+	return ioread32(addr);
+}
+
+static inline void rtl818x_iowrite8(struct rtl8180_priv *priv,
+				    u8 __iomem *addr, u8 val)
+{
+	iowrite8(val, addr);
+}
+
+static inline void rtl818x_iowrite16(struct rtl8180_priv *priv,
+				     __le16 __iomem *addr, u16 val)
+{
+	iowrite16(val, addr);
+}
+
+static inline void rtl818x_iowrite32(struct rtl8180_priv *priv,
+				     __le32 __iomem *addr, u32 val)
+{
+	iowrite32(val, addr);
+}
+
+#endif /* RTL8180_H */
diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c
new file mode 100644
index 000000000000..07f37b0ccf91
--- /dev/null
+++ b/drivers/net/wireless/rtl8180_dev.c
@@ -0,0 +1,1051 @@
+
+/*
+ * Linux device driver for RTL8180 / RTL8185
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8180 driver, which is:
+ * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * Thanks to Realtek for their support!
+ *
+ * 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/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/eeprom_93cx6.h>
+#include <net/mac80211.h>
+
+#include "rtl8180.h"
+#include "rtl8180_rtl8225.h"
+#include "rtl8180_sa2400.h"
+#include "rtl8180_max2820.h"
+#include "rtl8180_grf5101.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
+MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver");
+MODULE_LICENSE("GPL");
+
+static struct pci_device_id rtl8180_table[] __devinitdata = {
+	/* rtl8185 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x701f) },
+
+	/* rtl8180 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8180) },
+	{ PCI_DEVICE(0x1799, 0x6001) },
+	{ PCI_DEVICE(0x1799, 0x6020) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x3300) },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, rtl8180_table);
+
+void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	int i = 10;
+	u32 buf;
+
+	buf = (data << 8) | addr;
+
+	rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf | 0x80);
+	while (i--) {
+		rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf);
+		if (rtl818x_ioread8(priv, &priv->map->PHY[2]) == (data & 0xFF))
+			return;
+	}
+}
+
+static void rtl8180_handle_rx(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	unsigned int count = 32;
+
+	while (count--) {
+		struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
+		struct sk_buff *skb = priv->rx_buf[priv->rx_idx];
+		u32 flags = le32_to_cpu(entry->flags);
+
+		if (flags & RTL8180_RX_DESC_FLAG_OWN)
+			return;
+
+		if (unlikely(flags & (RTL8180_RX_DESC_FLAG_DMA_FAIL |
+				      RTL8180_RX_DESC_FLAG_FOF |
+				      RTL8180_RX_DESC_FLAG_RX_ERR)))
+			goto done;
+		else {
+			u32 flags2 = le32_to_cpu(entry->flags2);
+			struct ieee80211_rx_status rx_status = {0};
+			struct sk_buff *new_skb = dev_alloc_skb(MAX_RX_SIZE);
+
+			if (unlikely(!new_skb))
+				goto done;
+
+			pci_unmap_single(priv->pdev,
+					 *((dma_addr_t *)skb->cb),
+					 MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+			skb_put(skb, flags & 0xFFF);
+
+			rx_status.antenna = (flags2 >> 15) & 1;
+			/* TODO: improve signal/rssi reporting */
+			rx_status.signal = flags2 & 0xFF;
+			rx_status.ssi = (flags2 >> 8) & 0x7F;
+			rx_status.rate = (flags >> 20) & 0xF;
+			rx_status.freq = dev->conf.freq;
+			rx_status.channel = dev->conf.channel;
+			rx_status.phymode = dev->conf.phymode;
+			rx_status.mactime = le64_to_cpu(entry->tsft);
+			rx_status.flag |= RX_FLAG_TSFT;
+			if (flags & RTL8180_RX_DESC_FLAG_CRC32_ERR)
+				rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
+
+			ieee80211_rx_irqsafe(dev, skb, &rx_status);
+
+			skb = new_skb;
+			priv->rx_buf[priv->rx_idx] = skb;
+			*((dma_addr_t *) skb->cb) =
+				pci_map_single(priv->pdev, skb_tail_pointer(skb),
+					       MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+		}
+
+	done:
+		entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb));
+		entry->flags = cpu_to_le32(RTL8180_RX_DESC_FLAG_OWN |
+					   MAX_RX_SIZE);
+		if (priv->rx_idx == 31)
+			entry->flags |= cpu_to_le32(RTL8180_RX_DESC_FLAG_EOR);
+		priv->rx_idx = (priv->rx_idx + 1) % 32;
+	}
+}
+
+static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	struct rtl8180_tx_ring *ring = &priv->tx_ring[prio];
+
+	while (skb_queue_len(&ring->queue)) {
+		struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
+		struct sk_buff *skb;
+		struct ieee80211_tx_status status = { {0} };
+		struct ieee80211_tx_control *control;
+		u32 flags = le32_to_cpu(entry->flags);
+
+		if (flags & RTL8180_TX_DESC_FLAG_OWN)
+			return;
+
+		ring->idx = (ring->idx + 1) % ring->entries;
+		skb = __skb_dequeue(&ring->queue);
+		pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
+				 skb->len, PCI_DMA_TODEVICE);
+
+		control = *((struct ieee80211_tx_control **)skb->cb);
+		if (control)
+			memcpy(&status.control, control, sizeof(*control));
+		kfree(control);
+
+		if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
+			if (flags & RTL8180_TX_DESC_FLAG_TX_OK)
+				status.flags = IEEE80211_TX_STATUS_ACK;
+			else
+				status.excessive_retries = 1;
+		}
+		status.retry_count = flags & 0xFF;
+
+		ieee80211_tx_status_irqsafe(dev, skb, &status);
+		if (ring->entries - skb_queue_len(&ring->queue) == 2)
+			ieee80211_wake_queue(dev, prio);
+	}
+}
+
+static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
+{
+	struct ieee80211_hw *dev = dev_id;
+	struct rtl8180_priv *priv = dev->priv;
+	u16 reg;
+
+	spin_lock(&priv->lock);
+	reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS);
+	if (unlikely(reg == 0xFFFF)) {
+		spin_unlock(&priv->lock);
+		return IRQ_HANDLED;
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg);
+
+	if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR))
+		rtl8180_handle_tx(dev, 3);
+
+	if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR))
+		rtl8180_handle_tx(dev, 2);
+
+	if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR))
+		rtl8180_handle_tx(dev, 1);
+
+	if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR))
+		rtl8180_handle_tx(dev, 0);
+
+	if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR))
+		rtl8180_handle_rx(dev);
+
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+		      struct ieee80211_tx_control *control)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	struct rtl8180_tx_ring *ring;
+	struct rtl8180_tx_desc *entry;
+	unsigned long flags;
+	unsigned int idx, prio;
+	dma_addr_t mapping;
+	u32 tx_flags;
+	u16 plcp_len = 0;
+	__le16 rts_duration = 0;
+
+	prio = control->queue;
+	ring = &priv->tx_ring[prio];
+
+	mapping = pci_map_single(priv->pdev, skb->data,
+				 skb->len, PCI_DMA_TODEVICE);
+
+	tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS |
+		   RTL8180_TX_DESC_FLAG_LS | (control->tx_rate << 24) |
+		   (control->rts_cts_rate << 19) | skb->len;
+
+	if (priv->r8185)
+		tx_flags |= RTL8180_TX_DESC_FLAG_DMA |
+			    RTL8180_TX_DESC_FLAG_NO_ENC;
+
+	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+		tx_flags |= RTL8180_TX_DESC_FLAG_RTS;
+	else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+		tx_flags |= RTL8180_TX_DESC_FLAG_CTS;
+
+	*((struct ieee80211_tx_control **) skb->cb) =
+		kmemdup(control, sizeof(*control), GFP_ATOMIC);
+
+	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+		rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len,
+						      control);
+
+	if (!priv->r8185) {
+		unsigned int remainder;
+
+		plcp_len = DIV_ROUND_UP(16 * (skb->len + 4),
+					(control->rate->rate * 2) / 10);
+		remainder = (16 * (skb->len + 4)) %
+			    ((control->rate->rate * 2) / 10);
+		if (remainder > 0 && remainder <= 6)
+			plcp_len |= 1 << 15;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
+	entry = &ring->desc[idx];
+
+	entry->rts_duration = rts_duration;
+	entry->plcp_len = cpu_to_le16(plcp_len);
+	entry->tx_buf = cpu_to_le32(mapping);
+	entry->frame_len = cpu_to_le32(skb->len);
+	entry->flags2 = control->alt_retry_rate != -1 ?
+			control->alt_retry_rate << 4 : 0;
+	entry->retry_limit = control->retry_limit;
+	entry->flags = cpu_to_le32(tx_flags);
+	__skb_queue_tail(&ring->queue, skb);
+	if (ring->entries - skb_queue_len(&ring->queue) < 2)
+		ieee80211_stop_queue(dev, control->queue);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
+
+	return 0;
+}
+
+void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam)
+{
+	u8 reg;
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+		 reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3,
+		 reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+}
+
+static int rtl8180_init_hw(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u16 reg;
+
+	rtl818x_iowrite8(priv, &priv->map->CMD, 0);
+	rtl818x_ioread8(priv, &priv->map->CMD);
+	msleep(10);
+
+	/* reset */
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+	rtl818x_ioread8(priv, &priv->map->CMD);
+
+	reg = rtl818x_ioread8(priv, &priv->map->CMD);
+	reg &= (1 << 1);
+	reg |= RTL818X_CMD_RESET;
+	rtl818x_iowrite8(priv, &priv->map->CMD, RTL818X_CMD_RESET);
+	rtl818x_ioread8(priv, &priv->map->CMD);
+	msleep(200);
+
+	/* check success of reset */
+	if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) {
+		printk(KERN_ERR "%s: reset timeout!\n", wiphy_name(dev->wiphy));
+		return -ETIMEDOUT;
+	}
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD);
+	rtl818x_ioread8(priv, &priv->map->CMD);
+	msleep(200);
+
+	if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) {
+		/* For cardbus */
+		reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+		reg |= 1 << 1;
+		rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
+		reg = rtl818x_ioread16(priv, &priv->map->FEMR);
+		reg |= (1 << 15) | (1 << 14) | (1 << 4);
+		rtl818x_iowrite16(priv, &priv->map->FEMR, reg);
+	}
+
+	rtl818x_iowrite8(priv, &priv->map->MSR, 0);
+
+	if (!priv->r8185)
+		rtl8180_set_anaparam(priv, priv->anaparam);
+
+	rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma);
+	rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma);
+	rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma);
+	rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma);
+	rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma);
+
+	/* TODO: necessary? specs indicate not */
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG2);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3));
+	if (priv->r8185) {
+		reg = rtl818x_ioread8(priv, &priv->map->CONFIG2);
+		rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4));
+	}
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	/* TODO: set CONFIG5 for calibrating AGC on rtl8180 + philips radio? */
+
+	/* TODO: turn off hw wep on rtl8180 */
+
+	rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
+
+	if (priv->r8185) {
+		rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
+		rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
+		rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0);
+
+		rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+
+		/* TODO: set ClkRun enable? necessary? */
+		reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE);
+		rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6));
+		rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+		reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+		rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2));
+		rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+	} else {
+		rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1);
+		rtl818x_iowrite8(priv, &priv->map->SECURITY, 0);
+
+		rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6);
+		rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C);
+	}
+
+	priv->rf->init(dev);
+	if (priv->r8185)
+		rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+	return 0;
+}
+
+static int rtl8180_init_rx_ring(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	struct rtl8180_rx_desc *entry;
+	int i;
+
+	priv->rx_ring = pci_alloc_consistent(priv->pdev,
+					     sizeof(*priv->rx_ring) * 32,
+					     &priv->rx_ring_dma);
+
+	if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) {
+		printk(KERN_ERR "%s: Cannot allocate RX ring\n",
+		       wiphy_name(dev->wiphy));
+		return -ENOMEM;
+	}
+
+	memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * 32);
+	priv->rx_idx = 0;
+
+	for (i = 0; i < 32; i++) {
+		struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE);
+		dma_addr_t *mapping;
+		entry = &priv->rx_ring[i];
+		if (!skb)
+			return 0;
+
+		priv->rx_buf[i] = skb;
+		mapping = (dma_addr_t *)skb->cb;
+		*mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb),
+					  MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+		entry->rx_buf = cpu_to_le32(*mapping);
+		entry->flags = cpu_to_le32(RTL8180_RX_DESC_FLAG_OWN |
+					   MAX_RX_SIZE);
+	}
+	entry->flags |= cpu_to_le32(RTL8180_RX_DESC_FLAG_EOR);
+	return 0;
+}
+
+static void rtl8180_free_rx_ring(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		struct sk_buff *skb = priv->rx_buf[i];
+		if (!skb)
+			continue;
+
+		pci_unmap_single(priv->pdev,
+				 *((dma_addr_t *)skb->cb),
+				 MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+		kfree_skb(skb);
+	}
+
+	pci_free_consistent(priv->pdev, sizeof(*priv->rx_ring) * 32,
+			    priv->rx_ring, priv->rx_ring_dma);
+	priv->rx_ring = NULL;
+}
+
+static int rtl8180_init_tx_ring(struct ieee80211_hw *dev,
+				unsigned int prio, unsigned int entries)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	struct rtl8180_tx_desc *ring;
+	dma_addr_t dma;
+	int i;
+
+	ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma);
+	if (!ring || (unsigned long)ring & 0xFF) {
+		printk(KERN_ERR "%s: Cannot allocate TX ring (prio = %d)\n",
+		       wiphy_name(dev->wiphy), prio);
+		return -ENOMEM;
+	}
+
+	memset(ring, 0, sizeof(*ring)*entries);
+	priv->tx_ring[prio].desc = ring;
+	priv->tx_ring[prio].dma = dma;
+	priv->tx_ring[prio].idx = 0;
+	priv->tx_ring[prio].entries = entries;
+	skb_queue_head_init(&priv->tx_ring[prio].queue);
+
+	for (i = 0; i < entries; i++)
+		ring[i].next_tx_desc =
+			cpu_to_le32((u32)dma + ((i + 1) % entries) * sizeof(*ring));
+
+	return 0;
+}
+
+static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	struct rtl8180_tx_ring *ring = &priv->tx_ring[prio];
+
+	while (skb_queue_len(&ring->queue)) {
+		struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
+		struct sk_buff *skb = __skb_dequeue(&ring->queue);
+
+		pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
+				 skb->len, PCI_DMA_TODEVICE);
+		kfree(*((struct ieee80211_tx_control **) skb->cb));
+		kfree_skb(skb);
+		ring->idx = (ring->idx + 1) % ring->entries;
+	}
+
+	pci_free_consistent(priv->pdev, sizeof(*ring->desc)*ring->entries,
+			    ring->desc, ring->dma);
+	ring->desc = NULL;
+}
+
+static int rtl8180_start(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	int ret, i;
+	u32 reg;
+
+	ret = rtl8180_init_rx_ring(dev);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < 4; i++)
+		if ((ret = rtl8180_init_tx_ring(dev, i, 16)))
+			goto err_free_rings;
+
+	ret = rtl8180_init_hw(dev);
+	if (ret)
+		goto err_free_rings;
+
+	rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma);
+	rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma);
+	rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma);
+	rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma);
+	rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma);
+
+	ret = request_irq(priv->pdev->irq, &rtl8180_interrupt,
+			  IRQF_SHARED, KBUILD_MODNAME, dev);
+	if (ret) {
+		printk(KERN_ERR "%s: failed to register IRQ handler\n",
+		       wiphy_name(dev->wiphy));
+		goto err_free_rings;
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
+
+	rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
+	rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0);
+
+	reg = RTL818X_RX_CONF_ONLYERLPKT |
+	      RTL818X_RX_CONF_RX_AUTORESETPHY |
+	      RTL818X_RX_CONF_MGMT |
+	      RTL818X_RX_CONF_DATA |
+	      (7 << 8 /* MAX RX DMA */) |
+	      RTL818X_RX_CONF_BROADCAST |
+	      RTL818X_RX_CONF_NICMAC;
+
+	if (priv->r8185)
+		reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2;
+	else {
+		reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1)
+			? RTL818X_RX_CONF_CSDM1 : 0;
+		reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2)
+			? RTL818X_RX_CONF_CSDM2 : 0;
+	}
+
+	priv->rx_conf = reg;
+	rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
+
+	if (priv->r8185) {
+		reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
+		reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT;
+		reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
+		rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
+
+		reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
+		reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
+		reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
+		reg |=  RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
+		rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
+
+		/* disable early TX */
+		rtl818x_iowrite8(priv, (u8 __iomem *)priv->map + 0xec, 0x3f);
+	}
+
+	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
+	reg |= (6 << 21 /* MAX TX DMA */) |
+	       RTL818X_TX_CONF_NO_ICV;
+
+	if (priv->r8185)
+		reg &= ~RTL818X_TX_CONF_PROBE_DTS;
+	else
+		reg &= ~RTL818X_TX_CONF_HW_SEQNUM;
+
+	/* different meaning, same value on both rtl8185 and rtl8180 */
+	reg &= ~RTL818X_TX_CONF_SAT_HWPLCP;
+
+	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
+
+	reg = rtl818x_ioread8(priv, &priv->map->CMD);
+	reg |= RTL818X_CMD_RX_ENABLE;
+	reg |= RTL818X_CMD_TX_ENABLE;
+	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	return 0;
+
+ err_free_rings:
+	rtl8180_free_rx_ring(dev);
+	for (i = 0; i < 4; i++)
+		if (priv->tx_ring[i].desc)
+			rtl8180_free_tx_ring(dev, i);
+
+	return ret;
+}
+
+static void rtl8180_stop(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u8 reg;
+	int i;
+
+	priv->mode = IEEE80211_IF_TYPE_INVALID;
+
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+
+	reg = rtl818x_ioread8(priv, &priv->map->CMD);
+	reg &= ~RTL818X_CMD_TX_ENABLE;
+	reg &= ~RTL818X_CMD_RX_ENABLE;
+	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+	priv->rf->stop(dev);
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG4);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	free_irq(priv->pdev->irq, dev);
+
+	rtl8180_free_rx_ring(dev);
+	for (i = 0; i < 4; i++)
+		rtl8180_free_tx_ring(dev, i);
+}
+
+static int rtl8180_add_interface(struct ieee80211_hw *dev,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct rtl8180_priv *priv = dev->priv;
+
+	if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+		return -EOPNOTSUPP;
+
+	switch (conf->type) {
+	case IEEE80211_IF_TYPE_STA:
+		priv->mode = conf->type;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	priv->vif = conf->vif;
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
+			  cpu_to_le32(*(u32 *)conf->mac_addr));
+	rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4],
+			  cpu_to_le16(*(u16 *)(conf->mac_addr + 4)));
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	return 0;
+}
+
+static void rtl8180_remove_interface(struct ieee80211_hw *dev,
+				     struct ieee80211_if_init_conf *conf)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	priv->vif = NULL;
+}
+
+static int rtl8180_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+	struct rtl8180_priv *priv = dev->priv;
+
+	priv->rf->set_chan(dev, conf);
+
+	return 0;
+}
+
+static int rtl8180_config_interface(struct ieee80211_hw *dev,
+				    struct ieee80211_vif *vif,
+				    struct ieee80211_if_conf *conf)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	int i;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
+
+	if (is_valid_ether_addr(conf->bssid))
+		rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA);
+	else
+		rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK);
+
+	return 0;
+}
+
+static void rtl8180_configure_filter(struct ieee80211_hw *dev,
+				     unsigned int changed_flags,
+				     unsigned int *total_flags,
+				     int mc_count, struct dev_addr_list *mclist)
+{
+	struct rtl8180_priv *priv = dev->priv;
+
+	if (changed_flags & FIF_FCSFAIL)
+		priv->rx_conf ^= RTL818X_RX_CONF_FCS;
+	if (changed_flags & FIF_CONTROL)
+		priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
+	if (changed_flags & FIF_OTHER_BSS)
+		priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
+	if (*total_flags & FIF_ALLMULTI || mc_count > 0)
+		priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
+	else
+		priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
+
+	*total_flags = 0;
+
+	if (priv->rx_conf & RTL818X_RX_CONF_FCS)
+		*total_flags |= FIF_FCSFAIL;
+	if (priv->rx_conf & RTL818X_RX_CONF_CTRL)
+		*total_flags |= FIF_CONTROL;
+	if (priv->rx_conf & RTL818X_RX_CONF_MONITOR)
+		*total_flags |= FIF_OTHER_BSS;
+	if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST)
+		*total_flags |= FIF_ALLMULTI;
+
+	rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf);
+}
+
+static const struct ieee80211_ops rtl8180_ops = {
+	.tx			= rtl8180_tx,
+	.start			= rtl8180_start,
+	.stop			= rtl8180_stop,
+	.add_interface		= rtl8180_add_interface,
+	.remove_interface	= rtl8180_remove_interface,
+	.config			= rtl8180_config,
+	.config_interface	= rtl8180_config_interface,
+	.configure_filter	= rtl8180_configure_filter,
+};
+
+static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+	struct ieee80211_hw *dev = eeprom->data;
+	struct rtl8180_priv *priv = dev->priv;
+	u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+
+	eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
+	eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ;
+	eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK;
+	eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS;
+}
+
+static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+	struct ieee80211_hw *dev = eeprom->data;
+	struct rtl8180_priv *priv = dev->priv;
+	u8 reg = 2 << 6;
+
+	if (eeprom->reg_data_in)
+		reg |= RTL818X_EEPROM_CMD_WRITE;
+	if (eeprom->reg_data_out)
+		reg |= RTL818X_EEPROM_CMD_READ;
+	if (eeprom->reg_data_clock)
+		reg |= RTL818X_EEPROM_CMD_CK;
+	if (eeprom->reg_chip_select)
+		reg |= RTL818X_EEPROM_CMD_CS;
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(10);
+}
+
+static int __devinit rtl8180_probe(struct pci_dev *pdev,
+				   const struct pci_device_id *id)
+{
+	struct ieee80211_hw *dev;
+	struct rtl8180_priv *priv;
+	unsigned long mem_addr, mem_len;
+	unsigned int io_addr, io_len;
+	int err, i;
+	struct eeprom_93cx6 eeprom;
+	const char *chip_name, *rf_name = NULL;
+	u32 reg;
+	u16 eeprom_val;
+	DECLARE_MAC_BUF(mac);
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s (rtl8180): Cannot enable new PCI device\n",
+		       pci_name(pdev));
+		return err;
+	}
+
+	err = pci_request_regions(pdev, KBUILD_MODNAME);
+	if (err) {
+		printk(KERN_ERR "%s (rtl8180): Cannot obtain PCI resources\n",
+		       pci_name(pdev));
+		return err;
+	}
+
+	io_addr = pci_resource_start(pdev, 0);
+	io_len = pci_resource_len(pdev, 0);
+	mem_addr = pci_resource_start(pdev, 1);
+	mem_len = pci_resource_len(pdev, 1);
+
+	if (mem_len < sizeof(struct rtl818x_csr) ||
+	    io_len < sizeof(struct rtl818x_csr)) {
+		printk(KERN_ERR "%s (rtl8180): Too short PCI resources\n",
+		       pci_name(pdev));
+		err = -ENOMEM;
+		goto err_free_reg;
+	}
+
+	if ((err = pci_set_dma_mask(pdev, 0xFFFFFF00ULL)) ||
+	    (err = pci_set_consistent_dma_mask(pdev, 0xFFFFFF00ULL))) {
+		printk(KERN_ERR "%s (rtl8180): No suitable DMA available\n",
+		       pci_name(pdev));
+		goto err_free_reg;
+	}
+
+	pci_set_master(pdev);
+
+	dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8180_ops);
+	if (!dev) {
+		printk(KERN_ERR "%s (rtl8180): ieee80211 alloc failed\n",
+		       pci_name(pdev));
+		err = -ENOMEM;
+		goto err_free_reg;
+	}
+
+	priv = dev->priv;
+	priv->pdev = pdev;
+
+	SET_IEEE80211_DEV(dev, &pdev->dev);
+	pci_set_drvdata(pdev, dev);
+
+	priv->map = pci_iomap(pdev, 1, mem_len);
+	if (!priv->map)
+		priv->map = pci_iomap(pdev, 0, io_len);
+
+	if (!priv->map) {
+		printk(KERN_ERR "%s (rtl8180): Cannot map device memory\n",
+		       pci_name(pdev));
+		goto err_free_dev;
+	}
+
+	memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels));
+	memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates));
+	priv->modes[0].mode = MODE_IEEE80211G;
+	priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates);
+	priv->modes[0].rates = priv->rates;
+	priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels);
+	priv->modes[0].channels = priv->channels;
+	priv->modes[1].mode = MODE_IEEE80211B;
+	priv->modes[1].num_rates = 4;
+	priv->modes[1].rates = priv->rates;
+	priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
+	priv->modes[1].channels = priv->channels;
+	priv->mode = IEEE80211_IF_TYPE_INVALID;
+	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+		     IEEE80211_HW_RX_INCLUDES_FCS;
+	dev->queues = 1;
+	dev->max_rssi = 65;
+
+	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
+	reg &= RTL818X_TX_CONF_HWVER_MASK;
+	switch (reg) {
+	case RTL818X_TX_CONF_R8180_ABCD:
+		chip_name = "RTL8180";
+		break;
+	case RTL818X_TX_CONF_R8180_F:
+		chip_name = "RTL8180vF";
+		break;
+	case RTL818X_TX_CONF_R8185_ABC:
+		chip_name = "RTL8185";
+		break;
+	case RTL818X_TX_CONF_R8185_D:
+		chip_name = "RTL8185vD";
+		break;
+	default:
+		printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n",
+		       pci_name(pdev), reg >> 25);
+		goto err_iounmap;
+	}
+
+	priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC;
+	if (priv->r8185) {
+		if ((err = ieee80211_register_hwmode(dev, &priv->modes[0])))
+			goto err_iounmap;
+
+		pci_try_set_mwi(pdev);
+	}
+
+	if ((err = ieee80211_register_hwmode(dev, &priv->modes[1])))
+		goto err_iounmap;
+
+	eeprom.data = dev;
+	eeprom.register_read = rtl8180_eeprom_register_read;
+	eeprom.register_write = rtl8180_eeprom_register_write;
+	if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6))
+		eeprom.width = PCI_EEPROM_WIDTH_93C66;
+	else
+		eeprom.width = PCI_EEPROM_WIDTH_93C46;
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_PROGRAM);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(10);
+
+	eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val);
+	eeprom_val &= 0xFF;
+	switch (eeprom_val) {
+	case 1:	rf_name = "Intersil";
+		break;
+	case 2:	rf_name = "RFMD";
+		break;
+	case 3:	priv->rf = &sa2400_rf_ops;
+		break;
+	case 4:	priv->rf = &max2820_rf_ops;
+		break;
+	case 5:	priv->rf = &grf5101_rf_ops;
+		break;
+	case 9:	priv->rf = rtl8180_detect_rf(dev);
+		break;
+	case 10:
+		rf_name = "RTL8255";
+		break;
+	default:
+		printk(KERN_ERR "%s (rtl8180): Unknown RF! (0x%x)\n",
+		       pci_name(pdev), eeprom_val);
+		goto err_iounmap;
+	}
+
+	if (!priv->rf) {
+		printk(KERN_ERR "%s (rtl8180): %s RF frontend not supported!\n",
+		       pci_name(pdev), rf_name);
+		goto err_iounmap;
+	}
+
+	eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val);
+	priv->csthreshold = eeprom_val >> 8;
+	if (!priv->r8185) {
+		__le32 anaparam;
+		eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2);
+		priv->anaparam = le32_to_cpu(anaparam);
+		eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam);
+	}
+
+	eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)dev->wiphy->perm_addr, 3);
+	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+		printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using"
+		       " randomly generated MAC addr\n", pci_name(pdev));
+		random_ether_addr(dev->wiphy->perm_addr);
+	}
+
+	/* CCK TX power */
+	for (i = 0; i < 14; i += 2) {
+		u16 txpwr;
+		eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr);
+		priv->channels[i].val = txpwr & 0xFF;
+		priv->channels[i + 1].val = txpwr >> 8;
+	}
+
+	/* OFDM TX power */
+	if (priv->r8185) {
+		for (i = 0; i < 14; i += 2) {
+			u16 txpwr;
+			eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr);
+			priv->channels[i].val |= (txpwr & 0xFF) << 8;
+			priv->channels[i + 1].val |= txpwr & 0xFF00;
+		}
+	}
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	spin_lock_init(&priv->lock);
+
+	err = ieee80211_register_hw(dev);
+	if (err) {
+		printk(KERN_ERR "%s (rtl8180): Cannot register device\n",
+		       pci_name(pdev));
+		goto err_iounmap;
+	}
+
+	printk(KERN_INFO "%s: hwaddr %s, %s + %s\n",
+	       wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
+	       chip_name, priv->rf->name);
+
+	return 0;
+
+ err_iounmap:
+	iounmap(priv->map);
+
+ err_free_dev:
+	pci_set_drvdata(pdev, NULL);
+	ieee80211_free_hw(dev);
+
+ err_free_reg:
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	return err;
+}
+
+static void __devexit rtl8180_remove(struct pci_dev *pdev)
+{
+	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+	struct rtl8180_priv *priv;
+
+	if (!dev)
+		return;
+
+	ieee80211_unregister_hw(dev);
+
+	priv = dev->priv;
+
+	pci_iounmap(pdev, priv->map);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	ieee80211_free_hw(dev);
+}
+
+#ifdef CONFIG_PM
+static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	return 0;
+}
+
+static int rtl8180_resume(struct pci_dev *pdev)
+{
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+static struct pci_driver rtl8180_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= rtl8180_table,
+	.probe		= rtl8180_probe,
+	.remove		= __devexit_p(rtl8180_remove),
+#ifdef CONFIG_PM
+	.suspend	= rtl8180_suspend,
+	.resume		= rtl8180_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init rtl8180_init(void)
+{
+	return pci_register_driver(&rtl8180_driver);
+}
+
+static void __exit rtl8180_exit(void)
+{
+	pci_unregister_driver(&rtl8180_driver);
+}
+
+module_init(rtl8180_init);
+module_exit(rtl8180_exit);
diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl8180_grf5101.c
new file mode 100644
index 000000000000..8293e19c4c59
--- /dev/null
+++ b/drivers/net/wireless/rtl8180_grf5101.c
@@ -0,0 +1,179 @@
+
+/*
+ * Radio tuning for GCT GRF5101 on RTL8180
+ *
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Code from the BSD driver and the rtl8181 project have been
+ * very useful to understand certain things
+ *
+ * I want to thanks the Authors of such projects and the Ndiswrapper
+ * project Authors.
+ *
+ * A special Big Thanks also is for all people who donated me cards,
+ * making possible the creation of the original rtl8180 driver
+ * from which this code is derived!
+ *
+ * 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/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <net/mac80211.h>
+
+#include "rtl8180.h"
+#include "rtl8180_grf5101.h"
+
+static const int grf5101_encode[] = {
+	0x0, 0x8, 0x4, 0xC,
+	0x2, 0xA, 0x6, 0xE,
+	0x1, 0x9, 0x5, 0xD,
+	0x3, 0xB, 0x7, 0xF
+};
+
+static void write_grf5101(struct ieee80211_hw *dev, u8 addr, u32 data)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u32 phy_config;
+
+	phy_config =  grf5101_encode[(data >> 8) & 0xF];
+	phy_config |= grf5101_encode[(data >> 4) & 0xF] << 4;
+	phy_config |= grf5101_encode[data & 0xF] << 8;
+	phy_config |= grf5101_encode[(addr >> 1) & 0xF] << 12;
+	phy_config |= (addr & 1) << 16;
+	phy_config |= grf5101_encode[(data & 0xf000) >> 12] << 24;
+
+	/* MAC will bang bits to the chip */
+	phy_config |= 0x90000000;
+
+	rtl818x_iowrite32(priv,
+		(__le32 __iomem *) &priv->map->RFPinsOutput, phy_config);
+
+	msleep(3);
+}
+
+static void grf5101_write_phy_antenna(struct ieee80211_hw *dev, short chan)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u8 ant = GRF5101_ANTENNA;
+
+	if (priv->rfparam & RF_PARAM_ANTBDEFAULT)
+		ant |= BB_ANTENNA_B;
+
+	if (chan == 14)
+		ant |= BB_ANTATTEN_CHAN14;
+
+	rtl8180_write_phy(dev, 0x10, ant);
+}
+
+static void grf5101_rf_set_channel(struct ieee80211_hw *dev,
+				   struct ieee80211_conf *conf)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u32 txpw = priv->channels[conf->channel - 1].val & 0xFF;
+	u32 chan = conf->channel - 1;
+
+	/* set TX power */
+	write_grf5101(dev, 0x15, 0x0);
+	write_grf5101(dev, 0x06, txpw);
+	write_grf5101(dev, 0x15, 0x10);
+	write_grf5101(dev, 0x15, 0x0);
+
+	/* set frequency */
+	write_grf5101(dev, 0x07, 0x0);
+	write_grf5101(dev, 0x0B, chan);
+	write_grf5101(dev, 0x07, 0x1000);
+
+	grf5101_write_phy_antenna(dev, chan);
+}
+
+static void grf5101_rf_stop(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u32 anaparam;
+
+	anaparam = priv->anaparam;
+	anaparam &= 0x000fffff;
+	anaparam |= 0x3f900000;
+	rtl8180_set_anaparam(priv, anaparam);
+
+	write_grf5101(dev, 0x07, 0x0);
+	write_grf5101(dev, 0x1f, 0x45);
+	write_grf5101(dev, 0x1f, 0x5);
+	write_grf5101(dev, 0x00, 0x8e4);
+}
+
+static void grf5101_rf_init(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+
+	rtl8180_set_anaparam(priv, priv->anaparam);
+
+	write_grf5101(dev, 0x1f, 0x0);
+	write_grf5101(dev, 0x1f, 0x0);
+	write_grf5101(dev, 0x1f, 0x40);
+	write_grf5101(dev, 0x1f, 0x60);
+	write_grf5101(dev, 0x1f, 0x61);
+	write_grf5101(dev, 0x1f, 0x61);
+	write_grf5101(dev, 0x00, 0xae4);
+	write_grf5101(dev, 0x1f, 0x1);
+	write_grf5101(dev, 0x1f, 0x41);
+	write_grf5101(dev, 0x1f, 0x61);
+
+	write_grf5101(dev, 0x01, 0x1a23);
+	write_grf5101(dev, 0x02, 0x4971);
+	write_grf5101(dev, 0x03, 0x41de);
+	write_grf5101(dev, 0x04, 0x2d80);
+	write_grf5101(dev, 0x05, 0x68ff);	/* 0x61ff original value */
+	write_grf5101(dev, 0x06, 0x0);
+	write_grf5101(dev, 0x07, 0x0);
+	write_grf5101(dev, 0x08, 0x7533);
+	write_grf5101(dev, 0x09, 0xc401);
+	write_grf5101(dev, 0x0a, 0x0);
+	write_grf5101(dev, 0x0c, 0x1c7);
+	write_grf5101(dev, 0x0d, 0x29d3);
+	write_grf5101(dev, 0x0e, 0x2e8);
+	write_grf5101(dev, 0x10, 0x192);
+	write_grf5101(dev, 0x11, 0x248);
+	write_grf5101(dev, 0x12, 0x0);
+	write_grf5101(dev, 0x13, 0x20c4);
+	write_grf5101(dev, 0x14, 0xf4fc);
+	write_grf5101(dev, 0x15, 0x0);
+	write_grf5101(dev, 0x16, 0x1500);
+
+	write_grf5101(dev, 0x07, 0x1000);
+
+	/* baseband configuration */
+	rtl8180_write_phy(dev, 0, 0xa8);
+	rtl8180_write_phy(dev, 3, 0x0);
+	rtl8180_write_phy(dev, 4, 0xc0);
+	rtl8180_write_phy(dev, 5, 0x90);
+	rtl8180_write_phy(dev, 6, 0x1e);
+	rtl8180_write_phy(dev, 7, 0x64);
+
+	grf5101_write_phy_antenna(dev, 1);
+
+	rtl8180_write_phy(dev, 0x11, 0x88);
+
+	if (rtl818x_ioread8(priv, &priv->map->CONFIG2) &
+	    RTL818X_CONFIG2_ANTENNA_DIV)
+		rtl8180_write_phy(dev, 0x12, 0xc0); /* enable ant diversity */
+	else
+		rtl8180_write_phy(dev, 0x12, 0x40); /* disable ant diversity */
+
+	rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold);
+
+	rtl8180_write_phy(dev, 0x19, 0x0);
+	rtl8180_write_phy(dev, 0x1a, 0xa0);
+	rtl8180_write_phy(dev, 0x1b, 0x44);
+}
+
+const struct rtl818x_rf_ops grf5101_rf_ops = {
+	.name		= "GCT",
+	.init		= grf5101_rf_init,
+	.stop		= grf5101_rf_stop,
+	.set_chan	= grf5101_rf_set_channel
+};
diff --git a/drivers/net/wireless/rtl8180_grf5101.h b/drivers/net/wireless/rtl8180_grf5101.h
new file mode 100644
index 000000000000..76647111bcff
--- /dev/null
+++ b/drivers/net/wireless/rtl8180_grf5101.h
@@ -0,0 +1,28 @@
+#ifndef RTL8180_GRF5101_H
+#define RTL8180_GRF5101_H
+
+/*
+ * Radio tuning for GCT GRF5101 on RTL8180
+ *
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Code from the BSD driver and the rtl8181 project have been
+ * very useful to understand certain things
+ *
+ * I want to thanks the Authors of such projects and the Ndiswrapper
+ * project Authors.
+ *
+ * A special Big Thanks also is for all people who donated me cards,
+ * making possible the creation of the original rtl8180 driver
+ * from which this code is derived!
+ *
+ * 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.
+ */
+
+#define GRF5101_ANTENNA 0xA3
+
+extern const struct rtl818x_rf_ops grf5101_rf_ops;
+
+#endif /* RTL8180_GRF5101_H */
diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl8180_max2820.c
new file mode 100644
index 000000000000..98fe9fd64968
--- /dev/null
+++ b/drivers/net/wireless/rtl8180_max2820.c
@@ -0,0 +1,150 @@
+/*
+ * Radio tuning for Maxim max2820 on RTL8180
+ *
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Code from the BSD driver and the rtl8181 project have been
+ * very useful to understand certain things
+ *
+ * I want to thanks the Authors of such projects and the Ndiswrapper
+ * project Authors.
+ *
+ * A special Big Thanks also is for all people who donated me cards,
+ * making possible the creation of the original rtl8180 driver
+ * from which this code is derived!
+ *
+ * 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/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <net/mac80211.h>
+
+#include "rtl8180.h"
+#include "rtl8180_max2820.h"
+
+static const u32 max2820_chan[] = {
+	12, /* CH 1 */
+	17,
+	22,
+	27,
+	32,
+	37,
+	42,
+	47,
+	52,
+	57,
+	62,
+	67,
+	72,
+	84, /* CH 14 */
+};
+
+static void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u32 phy_config;
+
+	phy_config = 0x90 + (data & 0xf);
+	phy_config <<= 16;
+	phy_config += addr;
+	phy_config <<= 8;
+	phy_config += (data >> 4) & 0xff;
+
+	rtl818x_iowrite32(priv,
+		(__le32 __iomem *) &priv->map->RFPinsOutput, phy_config);
+
+	msleep(1);
+}
+
+static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u8 ant;
+
+	ant = MAXIM_ANTENNA;
+	if (priv->rfparam & RF_PARAM_ANTBDEFAULT)
+		ant |= BB_ANTENNA_B;
+	if (chan == 14)
+		ant |= BB_ANTATTEN_CHAN14;
+
+	rtl8180_write_phy(dev, 0x10, ant);
+}
+
+static void max2820_rf_set_channel(struct ieee80211_hw *dev,
+				   struct ieee80211_conf *conf)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	unsigned int chan_idx = conf ? conf->channel - 1 : 0;
+	u32 txpw = priv->channels[chan_idx].val & 0xFF;
+	u32 chan = max2820_chan[chan_idx];
+
+	/* While philips SA2400 drive the PA bias from
+	 * sa2400, for MAXIM we do this directly from BB */
+	rtl8180_write_phy(dev, 3, txpw);
+
+	max2820_write_phy_antenna(dev, chan);
+	write_max2820(dev, 3, chan);
+}
+
+static void max2820_rf_stop(struct ieee80211_hw *dev)
+{
+	rtl8180_write_phy(dev, 3, 0x8);
+	write_max2820(dev, 1, 0);
+}
+
+
+static void max2820_rf_init(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+
+	/* MAXIM from netbsd driver */
+	write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */
+	write_max2820(dev, 1, 0x01e); /* enable register */
+	write_max2820(dev, 2, 0x001); /* synt register */
+
+	max2820_rf_set_channel(dev, NULL);
+
+	write_max2820(dev, 4, 0x313); /* rx register */
+
+	/* PA is driven directly by the BB, we keep the MAXIM bias
+	 * at the highest value in case that setting it to lower
+	 * values may introduce some further attenuation somewhere..
+	 */
+	write_max2820(dev, 5, 0x00f);
+
+	/* baseband configuration */
+	rtl8180_write_phy(dev, 0, 0x88); /* sys1       */
+	rtl8180_write_phy(dev, 3, 0x08); /* txagc      */
+	rtl8180_write_phy(dev, 4, 0xf8); /* lnadet     */
+	rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit  */
+	rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */
+	rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet   */
+
+	max2820_write_phy_antenna(dev, 1);
+
+	rtl8180_write_phy(dev, 0x11, 0x88); /* trl */
+
+	if (rtl818x_ioread8(priv, &priv->map->CONFIG2) &
+	    RTL818X_CONFIG2_ANTENNA_DIV)
+		rtl8180_write_phy(dev, 0x12, 0xc7);
+	else
+		rtl8180_write_phy(dev, 0x12, 0x47);
+
+	rtl8180_write_phy(dev, 0x13, 0x9b);
+
+	rtl8180_write_phy(dev, 0x19, 0x0);  /* CHESTLIM */
+	rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM  */
+
+	max2820_rf_set_channel(dev, NULL);
+}
+
+const struct rtl818x_rf_ops max2820_rf_ops = {
+	.name		= "Maxim",
+	.init		= max2820_rf_init,
+	.stop		= max2820_rf_stop,
+	.set_chan	= max2820_rf_set_channel
+};
diff --git a/drivers/net/wireless/rtl8180_max2820.h b/drivers/net/wireless/rtl8180_max2820.h
new file mode 100644
index 000000000000..61cf6d1e7d57
--- /dev/null
+++ b/drivers/net/wireless/rtl8180_max2820.h
@@ -0,0 +1,28 @@
+#ifndef RTL8180_MAX2820_H
+#define RTL8180_MAX2820_H
+
+/*
+ * Radio tuning for Maxim max2820 on RTL8180
+ *
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Code from the BSD driver and the rtl8181 project have been
+ * very useful to understand certain things
+ *
+ * I want to thanks the Authors of such projects and the Ndiswrapper
+ * project Authors.
+ *
+ * A special Big Thanks also is for all people who donated me cards,
+ * making possible the creation of the original rtl8180 driver
+ * from which this code is derived!
+ *
+ * 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.
+ */
+
+#define MAXIM_ANTENNA 0xb3
+
+extern const struct rtl818x_rf_ops max2820_rf_ops;
+
+#endif /* RTL8180_MAX2820_H */
diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl8180_rtl8225.c
new file mode 100644
index 000000000000..ef3832bee85c
--- /dev/null
+++ b/drivers/net/wireless/rtl8180_rtl8225.c
@@ -0,0 +1,779 @@
+
+/*
+ * Radio tuning for RTL8225 on RTL8180
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8180 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * Thanks to Realtek for their support!
+ *
+ * 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/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <net/mac80211.h>
+
+#include "rtl8180.h"
+#include "rtl8180_rtl8225.h"
+
+static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u16 reg80, reg84, reg82;
+	u32 bangdata;
+	int i;
+
+	bangdata = (data << 4) | (addr & 0xf);
+
+	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;
+	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);
+
+	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7 | 0x400);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(10);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(2);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(10);
+
+	for (i = 15; i >= 0; i--) {
+		u16 reg = reg80 | !!(bangdata & (1 << i));
+
+		if (i & 1)
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
+
+		if (!(i & 1))
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(10);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x400);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+}
+
+static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u16 reg80, reg82, reg84, out;
+	int i;
+
+	reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
+	reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+	reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect) | 0x400;
+
+	reg80 &= ~0xF;
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(4);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(5);
+
+	for (i = 4; i >= 0; i--) {
+		u16 reg = reg80 | ((addr >> i) & 1);
+
+		if (!(i & 1)) {
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+			rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+			udelay(1);
+		}
+
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg | (1 << 1));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg | (1 << 1));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+
+		if (i & 1) {
+			rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+			rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+			udelay(1);
+		}
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x000E);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x040E);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3) | (1 << 1));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(2);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(2);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(2);
+
+	out = 0;
+	for (i = 11; i >= 0; i--) {
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(1);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3) | (1 << 1));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3) | (1 << 1));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3) | (1 << 1));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+
+		if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
+			out |= 1 << i;
+
+		rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+				  reg80 | (1 << 3));
+		rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+		udelay(2);
+	}
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+			  reg80 | (1 << 3) | (1 << 2));
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	udelay(2);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
+
+	return out;
+}
+
+static const u16 rtl8225bcd_rxgain[] = {
+	0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
+	0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
+	0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
+	0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
+	0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
+	0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
+	0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
+	0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
+	0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
+	0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
+	0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
+	0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
+};
+
+static const u8 rtl8225_agc[] = {
+	0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+	0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
+	0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
+	0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
+	0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
+	0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
+	0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
+	0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
+	0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
+	0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
+	0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
+	0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
+	0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+};
+
+static const u8 rtl8225_gain[] = {
+	0x23, 0x88, 0x7c, 0xa5, /* -82dbm */
+	0x23, 0x88, 0x7c, 0xb5, /* -82dbm */
+	0x23, 0x88, 0x7c, 0xc5, /* -82dbm */
+	0x33, 0x80, 0x79, 0xc5, /* -78dbm */
+	0x43, 0x78, 0x76, 0xc5, /* -74dbm */
+	0x53, 0x60, 0x73, 0xc5, /* -70dbm */
+	0x63, 0x58, 0x70, 0xc5, /* -66dbm */
+};
+
+static const u8 rtl8225_threshold[] = {
+	0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
+};
+
+static const u8 rtl8225_tx_gain_cck_ofdm[] = {
+	0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
+};
+
+static const u8 rtl8225_tx_power_cck[] = {
+	0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
+	0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
+	0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
+	0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
+	0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
+	0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
+};
+
+static const u8 rtl8225_tx_power_cck_ch14[] = {
+	0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
+	0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
+	0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
+	0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
+	0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
+	0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225_tx_power_ofdm[] = {
+	0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
+};
+
+static const u32 rtl8225_chan[] = {
+	0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
+	0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
+};
+
+static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u8 cck_power, ofdm_power;
+	const u8 *tmp;
+	u32 reg;
+	int i;
+
+	cck_power = priv->channels[channel - 1].val & 0xFF;
+	ofdm_power = priv->channels[channel - 1].val >> 8;
+
+	cck_power = min(cck_power, (u8)35);
+	ofdm_power = min(ofdm_power, (u8)35);
+
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
+			 rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
+
+	if (channel == 14)
+		tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
+	else
+		tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
+
+	for (i = 0; i < 8; i++)
+		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
+
+	msleep(1); /* FIXME: optional? */
+
+	/* anaparam2 on */
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
+			 rtl8225_tx_gain_cck_ofdm[ofdm_power/6] >> 1);
+
+	tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
+
+	rtl8225_write_phy_ofdm(dev, 5, *tmp);
+	rtl8225_write_phy_ofdm(dev, 7, *tmp);
+
+	msleep(1);
+}
+
+static void rtl8225_rf_init(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	int i;
+
+	rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON);
+
+	/* host_pci_init */
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
+	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	msleep(200);	/* FIXME: ehh?? */
+	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6));
+
+	rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008);
+
+	/* TODO: check if we need really to change BRSR to do RF config */
+	rtl818x_ioread16(priv, &priv->map->BRSR);
+	rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
+	rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl8225_write(dev, 0x0, 0x067);
+	rtl8225_write(dev, 0x1, 0xFE0);
+	rtl8225_write(dev, 0x2, 0x44D);
+	rtl8225_write(dev, 0x3, 0x441);
+	rtl8225_write(dev, 0x4, 0x8BE);
+	rtl8225_write(dev, 0x5, 0xBF0);		/* TODO: minipci */
+	rtl8225_write(dev, 0x6, 0xAE6);
+	rtl8225_write(dev, 0x7, rtl8225_chan[0]);
+	rtl8225_write(dev, 0x8, 0x01F);
+	rtl8225_write(dev, 0x9, 0x334);
+	rtl8225_write(dev, 0xA, 0xFD4);
+	rtl8225_write(dev, 0xB, 0x391);
+	rtl8225_write(dev, 0xC, 0x050);
+	rtl8225_write(dev, 0xD, 0x6DB);
+	rtl8225_write(dev, 0xE, 0x029);
+	rtl8225_write(dev, 0xF, 0x914); msleep(1);
+
+	rtl8225_write(dev, 0x2, 0xC4D); msleep(100);
+
+	rtl8225_write(dev, 0x0, 0x127);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
+		rtl8225_write(dev, 0x1, i + 1);
+		rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
+	}
+
+	rtl8225_write(dev, 0x0, 0x027);
+	rtl8225_write(dev, 0x0, 0x22F);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
+		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
+		msleep(1);
+		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
+		msleep(1);
+	}
+
+	msleep(1);
+
+	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x06, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x08, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x11, 0x03); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+
+	rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
+	rtl8225_write_phy_cck(dev, 0x19, 0x00);
+	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
+	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
+	rtl8225_write_phy_cck(dev, 0x40, 0x86);
+	rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+
+	rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); msleep(1);
+
+	rtl8225_rf_set_tx_power(dev, 1);
+
+	/* RX antenna default to A */
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);	/* B: 0xDB */
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);	/* B: 0x10 */
+
+	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
+	msleep(1);
+	rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+
+	rtl8225_write(dev, 0x0c, 0x50);
+	/* set OFDM initial gain */
+	rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[4 * 4]);
+	rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[4 * 4 + 1]);
+	rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[4 * 4 + 2]);
+	rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[4 * 4 + 3]);
+	/* set CCK threshold */
+	rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[0]);
+}
+
+static const u8 rtl8225z2_tx_power_cck_ch14[] = {
+	0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225z2_tx_power_cck_B[] = {
+	0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04
+};
+
+static const u8 rtl8225z2_tx_power_cck_A[] = {
+	0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04
+};
+
+static const u8 rtl8225z2_tx_power_cck[] = {
+	0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
+};
+
+static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u8 cck_power, ofdm_power;
+	const u8 *tmp;
+	int i;
+
+	cck_power = priv->channels[channel - 1].val & 0xFF;
+	ofdm_power = priv->channels[channel - 1].val >> 8;
+
+	if (channel == 14)
+		tmp = rtl8225z2_tx_power_cck_ch14;
+	else if (cck_power == 12)
+		tmp = rtl8225z2_tx_power_cck_B;
+	else if (cck_power == 13)
+		tmp = rtl8225z2_tx_power_cck_A;
+	else
+		tmp = rtl8225z2_tx_power_cck;
+
+	for (i = 0; i < 8; i++)
+		rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
+
+	cck_power = min(cck_power, (u8)35);
+	if (cck_power == 13 || cck_power == 14)
+		cck_power = 12;
+	if (cck_power >= 15)
+		cck_power -= 2;
+
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, cck_power);
+	rtl818x_ioread8(priv, &priv->map->TX_GAIN_CCK);
+	msleep(1);
+
+	ofdm_power = min(ofdm_power, (u8)35);
+	rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, ofdm_power);
+
+	rtl8225_write_phy_ofdm(dev, 2, 0x62);
+	rtl8225_write_phy_ofdm(dev, 5, 0x00);
+	rtl8225_write_phy_ofdm(dev, 6, 0x40);
+	rtl8225_write_phy_ofdm(dev, 7, 0x00);
+	rtl8225_write_phy_ofdm(dev, 8, 0x40);
+
+	msleep(1);
+}
+
+static const u16 rtl8225z2_rxgain[] = {
+	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009,
+	0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141,
+	0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183,
+	0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244,
+	0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288,
+	0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345,
+	0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389,
+	0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393,
+	0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d,
+	0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9,
+	0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
+	0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
+};
+
+static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	int i;
+
+	rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON);
+
+	/* host_pci_init */
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
+	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	msleep(200);	/* FIXME: ehh?? */
+	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6));
+
+	rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00088008);
+
+	/* TODO: check if we need really to change BRSR to do RF config */
+	rtl818x_ioread16(priv, &priv->map->BRSR);
+	rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
+	rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+
+	rtl8225_write(dev, 0x0, 0x0B7); msleep(1);
+	rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
+	rtl8225_write(dev, 0x2, 0x44D); msleep(1);
+	rtl8225_write(dev, 0x3, 0x441); msleep(1);
+	rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
+	rtl8225_write(dev, 0x5, 0xC72); msleep(1);
+	rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
+	rtl8225_write(dev, 0x7, 0x82A); msleep(1);
+	rtl8225_write(dev, 0x8, 0x03F); msleep(1);
+	rtl8225_write(dev, 0x9, 0x335); msleep(1);
+	rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
+	rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
+	rtl8225_write(dev, 0xc, 0x850); msleep(1);
+	rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
+	rtl8225_write(dev, 0xe, 0x02B); msleep(1);
+	rtl8225_write(dev, 0xf, 0x114); msleep(100);
+
+	if (!(rtl8225_read(dev, 6) & (1 << 7))) {
+		rtl8225_write(dev, 0x02, 0x0C4D);
+		msleep(200);
+		rtl8225_write(dev, 0x02, 0x044D);
+		msleep(100);
+		/* TODO: readd calibration failure message when the calibration
+		   check works */
+	}
+
+	rtl8225_write(dev, 0x0, 0x1B7);
+	rtl8225_write(dev, 0x3, 0x002);
+	rtl8225_write(dev, 0x5, 0x004);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
+		rtl8225_write(dev, 0x1, i + 1);
+		rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
+	}
+
+	rtl8225_write(dev, 0x0, 0x0B7); msleep(100);
+	rtl8225_write(dev, 0x2, 0xC4D);
+
+	msleep(200);
+	rtl8225_write(dev, 0x2, 0x44D);
+	msleep(100);
+
+	rtl8225_write(dev, 0x00, 0x2BF);
+	rtl8225_write(dev, 0xFF, 0xFFFF);
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+
+	for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
+		rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
+		msleep(1);
+		rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
+		msleep(1);
+	}
+
+	msleep(1);
+
+	rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
+	rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1b, 0x11); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1e, 0xb3); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); /* FIXME: not needed? */
+	rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
+	rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+
+	rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x13, 0xd0);
+	rtl8225_write_phy_cck(dev, 0x19, 0x00);
+	rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
+	rtl8225_write_phy_cck(dev, 0x1b, 0x08);
+	rtl8225_write_phy_cck(dev, 0x40, 0x86);
+	rtl8225_write_phy_cck(dev, 0x41, 0x8a); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
+	rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+
+	rtl818x_iowrite8(priv, (u8 __iomem *)((void __iomem *)priv->map + 0x5B), 0x0D); msleep(1);
+
+	rtl8225z2_rf_set_tx_power(dev, 1);
+
+	/* RX antenna default to A */
+	rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);	/* B: 0xDB */
+	rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);	/* B: 0x10 */
+
+	rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03);	/* B: 0x00 */
+	msleep(1);
+	rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+}
+
+static void rtl8225_rf_stop(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u8 reg;
+
+	rtl8225_write(dev, 0x4, 0x1f); msleep(1);
+
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
+	rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
+	rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+}
+
+static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
+				   struct ieee80211_conf *conf)
+{
+	struct rtl8180_priv *priv = dev->priv;
+
+	if (priv->rf->init == rtl8225_rf_init)
+		rtl8225_rf_set_tx_power(dev, conf->channel);
+	else
+		rtl8225z2_rf_set_tx_power(dev, conf->channel);
+
+	rtl8225_write(dev, 0x7, rtl8225_chan[conf->channel - 1]);
+	msleep(10);
+
+	if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
+		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
+		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
+		rtl818x_iowrite8(priv, &priv->map->EIFS, 81);
+		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
+	} else {
+		rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
+		rtl818x_iowrite8(priv, &priv->map->SIFS, 0x44);
+		rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
+		rtl818x_iowrite8(priv, &priv->map->EIFS, 81);
+		rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
+	}
+}
+
+static const struct rtl818x_rf_ops rtl8225_ops = {
+	.name		= "rtl8225",
+	.init		= rtl8225_rf_init,
+	.stop		= rtl8225_rf_stop,
+	.set_chan	= rtl8225_rf_set_channel
+};
+
+static const struct rtl818x_rf_ops rtl8225z2_ops = {
+	.name		= "rtl8225z2",
+	.init		= rtl8225z2_rf_init,
+	.stop		= rtl8225_rf_stop,
+	.set_chan	= rtl8225_rf_set_channel
+};
+
+const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u16 reg8, reg9;
+
+	rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488);
+	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF);
+	rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+	msleep(100);
+
+	rtl8225_write(dev, 0, 0x1B7);
+
+	reg8 = rtl8225_read(dev, 8);
+	reg9 = rtl8225_read(dev, 9);
+
+	rtl8225_write(dev, 0, 0x0B7);
+
+	if (reg8 != 0x588 || reg9 != 0x700)
+		return &rtl8225_ops;
+
+	return &rtl8225z2_ops;
+}
diff --git a/drivers/net/wireless/rtl8180_rtl8225.h b/drivers/net/wireless/rtl8180_rtl8225.h
new file mode 100644
index 000000000000..310013a2d726
--- /dev/null
+++ b/drivers/net/wireless/rtl8180_rtl8225.h
@@ -0,0 +1,23 @@
+#ifndef RTL8180_RTL8225_H
+#define RTL8180_RTL8225_H
+
+#define RTL8225_ANAPARAM_ON	0xa0000b59
+#define RTL8225_ANAPARAM2_ON	0x860dec11
+#define RTL8225_ANAPARAM_OFF	0xa00beb59
+#define RTL8225_ANAPARAM2_OFF	0x840dec11
+
+const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *);
+
+static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev,
+					  u8 addr, u8 data)
+{
+	rtl8180_write_phy(dev, addr, data);
+}
+
+static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev,
+					 u8 addr, u8 data)
+{
+	rtl8180_write_phy(dev, addr, data | 0x10000);
+}
+
+#endif /* RTL8180_RTL8225_H */
diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl8180_sa2400.c
new file mode 100644
index 000000000000..e08ace7b1cb7
--- /dev/null
+++ b/drivers/net/wireless/rtl8180_sa2400.c
@@ -0,0 +1,201 @@
+
+/*
+ * Radio tuning for Philips SA2400 on RTL8180
+ *
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Code from the BSD driver and the rtl8181 project have been
+ * very useful to understand certain things
+ *
+ * I want to thanks the Authors of such projects and the Ndiswrapper
+ * project Authors.
+ *
+ * A special Big Thanks also is for all people who donated me cards,
+ * making possible the creation of the original rtl8180 driver
+ * from which this code is derived!
+ *
+ * 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/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <net/mac80211.h>
+
+#include "rtl8180.h"
+#include "rtl8180_sa2400.h"
+
+static const u32 sa2400_chan[] = {
+	0x00096c, /* ch1 */
+	0x080970,
+	0x100974,
+	0x180978,
+	0x000980,
+	0x080984,
+	0x100988,
+	0x18098c,
+	0x000994,
+	0x080998,
+	0x10099c,
+	0x1809a0,
+	0x0009a8,
+	0x0009b4, /* ch 14 */
+};
+
+static void write_sa2400(struct ieee80211_hw *dev, u8 addr, u32 data)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u32 phy_config;
+
+	/* MAC will bang bits to the sa2400. sw 3-wire is NOT used */
+	phy_config = 0xb0000000;
+
+	phy_config |= ((u32)(addr & 0xf)) << 24;
+	phy_config |= data & 0xffffff;
+
+	rtl818x_iowrite32(priv,
+		(__le32 __iomem *) &priv->map->RFPinsOutput, phy_config);
+
+	msleep(3);
+}
+
+static void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u8 ant = SA2400_ANTENNA;
+
+	if (priv->rfparam & RF_PARAM_ANTBDEFAULT)
+		ant |= BB_ANTENNA_B;
+
+	if (chan == 14)
+		ant |= BB_ANTATTEN_CHAN14;
+
+	rtl8180_write_phy(dev, 0x10, ant);
+
+}
+
+static void sa2400_rf_set_channel(struct ieee80211_hw *dev,
+				  struct ieee80211_conf *conf)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u32 txpw = priv->channels[conf->channel - 1].val & 0xFF;
+	u32 chan = sa2400_chan[conf->channel - 1];
+
+	write_sa2400(dev, 7, txpw);
+
+	sa2400_write_phy_antenna(dev, chan);
+
+	write_sa2400(dev, 0, chan);
+	write_sa2400(dev, 1, 0xbb50);
+	write_sa2400(dev, 2, 0x80);
+	write_sa2400(dev, 3, 0);
+}
+
+static void sa2400_rf_stop(struct ieee80211_hw *dev)
+{
+	write_sa2400(dev, 4, 0);
+}
+
+static void sa2400_rf_init(struct ieee80211_hw *dev)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	u32 anaparam, txconf;
+	u8 firdac;
+	int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY;
+
+	anaparam = priv->anaparam;
+	anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT);
+	anaparam &= ~ANAPARAM_PWR1_MASK;
+	anaparam &= ~ANAPARAM_PWR0_MASK;
+
+	if (analogphy) {
+		anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT;
+		firdac = 0;
+	} else {
+		anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT);
+		anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT);
+		firdac = 1 << SA2400_REG4_FIRDAC_SHIFT;
+	}
+
+	rtl8180_set_anaparam(priv, anaparam);
+
+	write_sa2400(dev, 0, sa2400_chan[0]);
+	write_sa2400(dev, 1, 0xbb50);
+	write_sa2400(dev, 2, 0x80);
+	write_sa2400(dev, 3, 0);
+	write_sa2400(dev, 4, 0x19340 | firdac);
+	write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15);
+	write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */
+
+	if (!analogphy)
+		write_sa2400(dev, 4, 0x1938c); /*???*/
+
+	write_sa2400(dev, 4, 0x19340 | firdac);
+
+	write_sa2400(dev, 0, sa2400_chan[0]);
+	write_sa2400(dev, 1, 0xbb50);
+	write_sa2400(dev, 2, 0x80);
+	write_sa2400(dev, 3, 0);
+	write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */
+
+	/* new from rtl8180 embedded driver (rtl8181 project) */
+	write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */
+	write_sa2400(dev, 8, 0); /* VCO */
+
+	if (analogphy) {
+		rtl8180_set_anaparam(priv, anaparam |
+				     (1 << ANAPARAM_TXDACOFF_SHIFT));
+
+		txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF);
+		rtl818x_iowrite32(priv, &priv->map->TX_CONF,
+			txconf | RTL818X_TX_CONF_LOOPBACK_CONT);
+
+		write_sa2400(dev, 4, 0x19341); /* calibrates DC */
+
+		/* a 5us sleep is required here,
+		 * we rely on the 3ms delay introduced in write_sa2400 */
+		write_sa2400(dev, 4, 0x19345);
+
+		/* a 20us sleep is required here,
+		 * we rely on the 3ms delay introduced in write_sa2400 */
+
+		rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf);
+
+		rtl8180_set_anaparam(priv, anaparam);
+	}
+	/* end new code */
+
+	write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */
+
+	/* baseband configuration */
+	rtl8180_write_phy(dev, 0, 0x98);
+	rtl8180_write_phy(dev, 3, 0x38);
+	rtl8180_write_phy(dev, 4, 0xe0);
+	rtl8180_write_phy(dev, 5, 0x90);
+	rtl8180_write_phy(dev, 6, 0x1a);
+	rtl8180_write_phy(dev, 7, 0x64);
+
+	sa2400_write_phy_antenna(dev, 1);
+
+	rtl8180_write_phy(dev, 0x11, 0x80);
+
+	if (rtl818x_ioread8(priv, &priv->map->CONFIG2) &
+	    RTL818X_CONFIG2_ANTENNA_DIV)
+		rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */
+	else
+		rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */
+
+	rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold);
+
+	rtl8180_write_phy(dev, 0x19, 0x0);
+	rtl8180_write_phy(dev, 0x1a, 0xa0);
+}
+
+const struct rtl818x_rf_ops sa2400_rf_ops = {
+	.name		= "Philips",
+	.init		= sa2400_rf_init,
+	.stop		= sa2400_rf_stop,
+	.set_chan	= sa2400_rf_set_channel
+};
diff --git a/drivers/net/wireless/rtl8180_sa2400.h b/drivers/net/wireless/rtl8180_sa2400.h
new file mode 100644
index 000000000000..a4aaa0d413f1
--- /dev/null
+++ b/drivers/net/wireless/rtl8180_sa2400.h
@@ -0,0 +1,36 @@
+#ifndef RTL8180_SA2400_H
+#define RTL8180_SA2400_H
+
+/*
+ * Radio tuning for Philips SA2400 on RTL8180
+ *
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Code from the BSD driver and the rtl8181 project have been
+ * very useful to understand certain things
+ *
+ * I want to thanks the Authors of such projects and the Ndiswrapper
+ * project Authors.
+ *
+ * A special Big Thanks also is for all people who donated me cards,
+ * making possible the creation of the original rtl8180 driver
+ * from which this code is derived!
+ *
+ * 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.
+ */
+
+#define SA2400_ANTENNA 0x91
+#define SA2400_DIG_ANAPARAM_PWR1_ON 0x8
+#define SA2400_ANA_ANAPARAM_PWR1_ON 0x28
+#define SA2400_ANAPARAM_PWR0_ON 0x3
+
+/* RX sensitivity in dbm */
+#define SA2400_MAX_SENS 85
+
+#define SA2400_REG4_FIRDAC_SHIFT 7
+
+extern const struct rtl818x_rf_ops sa2400_rf_ops;
+
+#endif /* RTL8180_SA2400_H */
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
index 6ad322ef0da1..8680a0b6433c 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl8187.h
@@ -64,9 +64,9 @@ struct rtl8187_tx_hdr {
 struct rtl8187_priv {
 	/* common between rtl818x drivers */
 	struct rtl818x_csr *map;
-	void (*rf_init)(struct ieee80211_hw *);
+	const struct rtl818x_rf_ops *rf;
+	struct ieee80211_vif *vif;
 	int mode;
-	int if_id;
 
 	/* rtl8187 specific */
 	struct ieee80211_channel channels[14];
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index bd1ab3b3afc0..0d71716d750d 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -150,7 +150,8 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
 		flags |= RTL8187_TX_FLAG_MORE_FRAG;
 	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
 		flags |= RTL8187_TX_FLAG_RTS;
-		rts_dur = ieee80211_rts_duration(dev, priv->if_id, skb->len, control);
+		rts_dur = ieee80211_rts_duration(dev, priv->vif,
+						 skb->len, control);
 	}
 	if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
 		flags |= RTL8187_TX_FLAG_CTS;
@@ -227,6 +228,7 @@ static void rtl8187_rx_cb(struct urb *urb)
 	rx_status.channel = dev->conf.channel;
 	rx_status.phymode = dev->conf.phymode;
 	rx_status.mactime = le64_to_cpu(hdr->mac_time);
+	rx_status.flag |= RX_FLAG_TSFT;
 	if (flags & (1 << 13))
 		rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 	ieee80211_rx_irqsafe(dev, skb, &rx_status);
@@ -392,37 +394,19 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
 	rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7);
 	msleep(100);
 
-	priv->rf_init(dev);
+	priv->rf->init(dev);
 
 	rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
-	reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & 0xfffe;
-	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 0x1);
+	reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1;
+	rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1);
 	rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10);
 	rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80);
 	rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60);
-	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
+	rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
 
 	return 0;
 }
 
-static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel)
-{
-	u32 reg;
-	struct rtl8187_priv *priv = dev->priv;
-
-	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
-	/* Enable TX loopback on MAC level to avoid TX during channel
-	 * changes, as this has be seen to causes problems and the
-	 * card will stop work until next reset
-	 */
-	rtl818x_iowrite32(priv, &priv->map->TX_CONF,
-			  reg | RTL818X_TX_CONF_LOOPBACK_MAC);
-	msleep(10);
-	rtl8225_rf_set_channel(dev, channel);
-	msleep(10);
-	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
-}
-
 static int rtl8187_start(struct ieee80211_hw *dev)
 {
 	struct rtl8187_priv *priv = dev->priv;
@@ -491,7 +475,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
 	reg &= ~RTL818X_CMD_RX_ENABLE;
 	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
 
-	rtl8225_rf_stop(dev);
+	priv->rf->stop(dev);
 
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG4);
@@ -542,7 +526,19 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev,
 static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
 {
 	struct rtl8187_priv *priv = dev->priv;
-	rtl8187_set_channel(dev, conf->channel);
+	u32 reg;
+
+	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
+	/* Enable TX loopback on MAC level to avoid TX during channel
+	 * changes, as this has be seen to causes problems and the
+	 * card will stop work until next reset
+	 */
+	rtl818x_iowrite32(priv, &priv->map->TX_CONF,
+			  reg | RTL818X_TX_CONF_LOOPBACK_MAC);
+	msleep(10);
+	priv->rf->set_chan(dev, conf);
+	msleep(10);
+	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
 
 	rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
 
@@ -565,14 +561,13 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
 	return 0;
 }
 
-static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id,
+static int rtl8187_config_interface(struct ieee80211_hw *dev,
+				    struct ieee80211_vif *vif,
 				    struct ieee80211_if_conf *conf)
 {
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
 
-	priv->if_id = if_id;
-
 	for (i = 0; i < ETH_ALEN; i++)
 		rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
 
@@ -752,23 +747,16 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
 	eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE,
 			  &priv->txpwr_base);
 
-	reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & ~1;
-	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 1);
+	reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1;
+	rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1);
 	/* 0 means asic B-cut, we should use SW 3 wire
 	 * bit-by-bit banging for radio. 1 means we can use
 	 * USB specific request to write radio registers */
 	priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3;
-	rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
+	rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
-	rtl8225_write(dev, 0, 0x1B7);
-
-	if (rtl8225_read(dev, 8) != 0x588 || rtl8225_read(dev, 9) != 0x700)
-		priv->rf_init = rtl8225_rf_init;
-	else
-		priv->rf_init = rtl8225z2_rf_init;
-
-	rtl8225_write(dev, 0, 0x0B7);
+	priv->rf = rtl8187_detect_rf(dev);
 
 	err = ieee80211_register_hw(dev);
 	if (err) {
@@ -778,8 +766,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
 
 	printk(KERN_INFO "%s: hwaddr %s, rtl8187 V%d + %s\n",
 	       wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
-	       priv->asic_rev, priv->rf_init == rtl8225_rf_init ?
-	       "rtl8225" : "rtl8225z2");
+	       priv->asic_rev, priv->rf->name);
 
 	return 0;
 
diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c
index efc41207780e..b713de17ba0a 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl8187_rtl8225.c
@@ -101,7 +101,7 @@ static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
 	msleep(2);
 }
 
-void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
+static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
 {
 	struct rtl8187_priv *priv = dev->priv;
 
@@ -111,7 +111,7 @@ void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
 		rtl8225_write_bitbang(dev, addr, data);
 }
 
-u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
+static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
 {
 	struct rtl8187_priv *priv = dev->priv;
 	u16 reg80, reg82, reg84, out;
@@ -325,7 +325,7 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
 	msleep(1);
 }
 
-void rtl8225_rf_init(struct ieee80211_hw *dev)
+static void rtl8225_rf_init(struct ieee80211_hw *dev)
 {
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
@@ -567,7 +567,7 @@ static const u8 rtl8225z2_gain_bg[] = {
 	0x63, 0x15, 0xc5  /* -66dBm */
 };
 
-void rtl8225z2_rf_init(struct ieee80211_hw *dev)
+static void rtl8225z2_rf_init(struct ieee80211_hw *dev)
 {
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
@@ -715,7 +715,7 @@ void rtl8225z2_rf_init(struct ieee80211_hw *dev)
 	rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
 }
 
-void rtl8225_rf_stop(struct ieee80211_hw *dev)
+static void rtl8225_rf_stop(struct ieee80211_hw *dev)
 {
 	u8 reg;
 	struct rtl8187_priv *priv = dev->priv;
@@ -731,15 +731,47 @@ void rtl8225_rf_stop(struct ieee80211_hw *dev)
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 }
 
-void rtl8225_rf_set_channel(struct ieee80211_hw *dev, int channel)
+static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
+				   struct ieee80211_conf *conf)
 {
 	struct rtl8187_priv *priv = dev->priv;
 
-	if (priv->rf_init == rtl8225_rf_init)
-		rtl8225_rf_set_tx_power(dev, channel);
+	if (priv->rf->init == rtl8225_rf_init)
+		rtl8225_rf_set_tx_power(dev, conf->channel);
 	else
-		rtl8225z2_rf_set_tx_power(dev, channel);
+		rtl8225z2_rf_set_tx_power(dev, conf->channel);
 
-	rtl8225_write(dev, 0x7, rtl8225_chan[channel - 1]);
+	rtl8225_write(dev, 0x7, rtl8225_chan[conf->channel - 1]);
 	msleep(10);
 }
+
+static const struct rtl818x_rf_ops rtl8225_ops = {
+	.name		= "rtl8225",
+	.init		= rtl8225_rf_init,
+	.stop		= rtl8225_rf_stop,
+	.set_chan	= rtl8225_rf_set_channel
+};
+
+static const struct rtl818x_rf_ops rtl8225z2_ops = {
+	.name		= "rtl8225z2",
+	.init		= rtl8225z2_rf_init,
+	.stop		= rtl8225_rf_stop,
+	.set_chan	= rtl8225_rf_set_channel
+};
+
+const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev)
+{
+	u16 reg8, reg9;
+
+	rtl8225_write(dev, 0, 0x1B7);
+
+	reg8 = rtl8225_read(dev, 8);
+	reg9 = rtl8225_read(dev, 9);
+
+	rtl8225_write(dev, 0, 0x0B7);
+
+	if (reg8 != 0x588 || reg9 != 0x700)
+		return &rtl8225_ops;
+
+	return &rtl8225z2_ops;
+}
diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl8187_rtl8225.h
index 798ba4a97376..d39ed0295b6e 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.h
+++ b/drivers/net/wireless/rtl8187_rtl8225.h
@@ -20,14 +20,7 @@
 #define RTL8225_ANAPARAM_OFF	0xa00beb59
 #define RTL8225_ANAPARAM2_OFF	0x840dec11
 
-void rtl8225_write(struct ieee80211_hw *, u8 addr, u16 data);
-u16  rtl8225_read(struct ieee80211_hw *, u8 addr);
-
-void rtl8225_rf_init(struct ieee80211_hw *);
-void rtl8225z2_rf_init(struct ieee80211_hw *);
-void rtl8225_rf_stop(struct ieee80211_hw *);
-void rtl8225_rf_set_channel(struct ieee80211_hw *, int);
-
+const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *);
 
 static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev,
 					  u8 addr, u32 data)
diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h
index 880d4becae31..1e7d6f8278d7 100644
--- a/drivers/net/wireless/rtl818x.h
+++ b/drivers/net/wireless/rtl818x.h
@@ -58,13 +58,17 @@ struct rtl818x_csr {
 #define RTL818X_INT_TX_FO		(1 << 15)
 	__le32	TX_CONF;
 #define RTL818X_TX_CONF_LOOPBACK_MAC	(1 << 17)
+#define RTL818X_TX_CONF_LOOPBACK_CONT	(3 << 17)
 #define RTL818X_TX_CONF_NO_ICV		(1 << 19)
 #define RTL818X_TX_CONF_DISCW		(1 << 20)
+#define RTL818X_TX_CONF_SAT_HWPLCP	(1 << 24)
 #define RTL818X_TX_CONF_R8180_ABCD	(2 << 25)
 #define RTL818X_TX_CONF_R8180_F		(3 << 25)
 #define RTL818X_TX_CONF_R8185_ABC	(4 << 25)
 #define RTL818X_TX_CONF_R8185_D		(5 << 25)
 #define RTL818X_TX_CONF_HWVER_MASK	(7 << 25)
+#define RTL818X_TX_CONF_PROBE_DTS	(1 << 29)
+#define RTL818X_TX_CONF_HW_SEQNUM	(1 << 30)
 #define RTL818X_TX_CONF_CW_MIN		(1 << 31)
 	__le32	RX_CONF;
 #define RTL818X_RX_CONF_MONITOR		(1 <<  0)
@@ -75,8 +79,12 @@ struct rtl818x_csr {
 #define RTL818X_RX_CONF_DATA		(1 << 18)
 #define RTL818X_RX_CONF_CTRL		(1 << 19)
 #define RTL818X_RX_CONF_MGMT		(1 << 20)
+#define RTL818X_RX_CONF_ADDR3		(1 << 21)
+#define RTL818X_RX_CONF_PM		(1 << 22)
 #define RTL818X_RX_CONF_BSSID		(1 << 23)
 #define RTL818X_RX_CONF_RX_AUTORESETPHY	(1 << 28)
+#define RTL818X_RX_CONF_CSDM1		(1 << 29)
+#define RTL818X_RX_CONF_CSDM2		(1 << 30)
 #define RTL818X_RX_CONF_ONLYERLPKT	(1 << 31)
 	__le32	INT_TIMEOUT;
 	__le32	TBDA;
@@ -92,6 +100,7 @@ struct rtl818x_csr {
 	u8	CONFIG0;
 	u8	CONFIG1;
 	u8	CONFIG2;
+#define RTL818X_CONFIG2_ANTENNA_DIV	(1 << 6)
 	__le32	ANAPARAM;
 	u8	MSR;
 #define RTL818X_MSR_NO_LINK		(0 << 2)
@@ -104,14 +113,17 @@ struct rtl818x_csr {
 #define RTL818X_CONFIG4_VCOOFF		(1 << 7)
 	u8	TESTR;
 	u8	reserved_9[2];
-	__le16	PGSELECT;
+	u8	PGSELECT;
+	u8	SECURITY;
 	__le32	ANAPARAM2;
 	u8	reserved_10[12];
 	__le16	BEACON_INTERVAL;
 	__le16	ATIM_WND;
 	__le16	BEACON_INTERVAL_TIME;
 	__le16	ATIMTR_INTERVAL;
-	u8	reserved_11[4];
+	u8	PHY_DELAY;
+	u8	CARRIER_SENSE_COUNTER;
+	u8	reserved_11[2];
 	u8	PHY[4];
 	__le16	RFPinsOutput;
 	__le16	RFPinsEnable;
@@ -149,11 +161,20 @@ struct rtl818x_csr {
 	u8	RETRY_CTR;
 	u8	reserved_18[5];
 	__le32	RDSAR;
-	u8	reserved_19[18];
-	u16	TALLY_CNT;
+	u8	reserved_19[12];
+	__le16	FEMR;
+	u8	reserved_20[4];
+	__le16	TALLY_CNT;
 	u8	TALLY_SEL;
 } __attribute__((packed));
 
+struct rtl818x_rf_ops {
+	char *name;
+	void (*init)(struct ieee80211_hw *);
+	void (*stop)(struct ieee80211_hw *);
+	void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *);
+};
+
 static const struct ieee80211_rate rtl818x_rates[] = {
 	{ .rate = 10,
 	  .val = 0,
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index a1f8a1687842..03384a43186b 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -49,27 +49,6 @@ static int __init wv_psa_to_irq(u8 irqval)
 	return -1;
 }
 
-#ifdef STRUCT_CHECK
-/*------------------------------------------------------------------*/
-/*
- * Sanity routine to verify the sizes of the various WaveLAN interface
- * structures.
- */
-static char *wv_struct_check(void)
-{
-#define	SC(t,s,n)	if (sizeof(t) != s) return(n);
-
-	SC(psa_t, PSA_SIZE, "psa_t");
-	SC(mmw_t, MMW_SIZE, "mmw_t");
-	SC(mmr_t, MMR_SIZE, "mmr_t");
-	SC(ha_t, HA_SIZE, "ha_t");
-
-#undef	SC
-
-	return ((char *) NULL);
-}				/* wv_struct_check */
-#endif				/* STRUCT_CHECK */
-
 /********************* HOST ADAPTER SUBROUTINES *********************/
 /*
  * Useful subroutines to manage the WaveLAN ISA interface
@@ -3740,7 +3719,7 @@ static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac)
 	 * non-NCR/AT&T/Lucent ISA card.  See wavelan.p.h for detail on
 	 * how to configure your card.
 	 */
-	for (i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
+	for (i = 0; i < ARRAY_SIZE(MAC_ADDRESSES); i++)
 		if ((mac[0] == MAC_ADDRESSES[i][0]) &&
 		    (mac[1] == MAC_ADDRESSES[i][1]) &&
 		    (mac[2] == MAC_ADDRESSES[i][2]))
@@ -4215,14 +4194,11 @@ struct net_device * __init wavelan_probe(int unit)
 	int i;
 	int r = 0;
 
-#ifdef	STRUCT_CHECK
-	if (wv_struct_check() != (char *) NULL) {
-		printk(KERN_WARNING
-		       "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n",
-		       dev->name, wv_struct_check());
-		return -ENODEV;
-	}
-#endif				/* STRUCT_CHECK */
+	/* compile-time check the sizes of structures */
+	BUILD_BUG_ON(sizeof(psa_t) != PSA_SIZE);
+	BUILD_BUG_ON(sizeof(mmw_t) != MMW_SIZE);
+	BUILD_BUG_ON(sizeof(mmr_t) != MMR_SIZE);
+	BUILD_BUG_ON(sizeof(ha_t) != HA_SIZE);
 
 	dev = alloc_etherdev(sizeof(net_local));
 	if (!dev)
diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
index fe242812d858..b33ac47dd8df 100644
--- a/drivers/net/wireless/wavelan.p.h
+++ b/drivers/net/wireless/wavelan.p.h
@@ -400,7 +400,6 @@
  */
 #undef SET_PSA_CRC		/* Calculate and set the CRC on PSA (slower) */
 #define USE_PSA_CONFIG		/* Use info from the PSA. */
-#undef STRUCT_CHECK		/* Verify padding of structures. */
 #undef EEPROM_IS_PROTECTED	/* doesn't seem to be necessary */
 #define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical). */
 #undef SET_MAC_ADDRESS		/* Experimental */
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 577c647824fe..c2037b2a05bf 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -71,27 +71,6 @@ static void wv_nwid_filter(unsigned char mode, net_local *lp);
  * (wavelan modem or i82593)
  */
 
-#ifdef STRUCT_CHECK
-/*------------------------------------------------------------------*/
-/*
- * Sanity routine to verify the sizes of the various WaveLAN interface
- * structures.
- */
-static char *
-wv_structuct_check(void)
-{
-#define	SC(t,s,n)	if (sizeof(t) != s) return(n);
-
-  SC(psa_t, PSA_SIZE, "psa_t");
-  SC(mmw_t, MMW_SIZE, "mmw_t");
-  SC(mmr_t, MMR_SIZE, "mmr_t");
-
-#undef	SC
-
-  return((char *) NULL);
-} /* wv_structuct_check */
-#endif	/* STRUCT_CHECK */
-
 /******************* MODEM MANAGEMENT SUBROUTINES *******************/
 /*
  * Useful subroutines to manage the modem of the wavelan
@@ -3223,14 +3202,14 @@ wv_mmc_init(struct net_device *	dev)
    * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on
    * how to configure your card...
    */
-  for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
-    if((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) &&
-       (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) &&
-       (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2]))
+  for (i = 0; i < ARRAY_SIZE(MAC_ADDRESSES); i++)
+    if ((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) &&
+        (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) &&
+        (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2]))
       break;
 
   /* If we have not found it... */
-  if(i == (sizeof(MAC_ADDRESSES) / sizeof(char) / 3))
+  if (i == ARRAY_SIZE(MAC_ADDRESSES))
     {
 #ifdef DEBUG_CONFIG_ERRORS
       printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n",
@@ -3794,14 +3773,10 @@ wv_hw_config(struct net_device *	dev)
   printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
 #endif
 
-#ifdef STRUCT_CHECK
-  if(wv_structuct_check() != (char *) NULL)
-    {
-      printk(KERN_WARNING "%s: wv_hw_config: structure/compiler botch: \"%s\"\n",
-	     dev->name, wv_structuct_check());
-      return FALSE;
-    }
-#endif	/* STRUCT_CHECK == 1 */
+  /* compile-time check the sizes of structures */
+  BUILD_BUG_ON(sizeof(psa_t) != PSA_SIZE);
+  BUILD_BUG_ON(sizeof(mmw_t) != MMW_SIZE);
+  BUILD_BUG_ON(sizeof(mmr_t) != MMR_SIZE);
 
   /* Reset the pcmcia interface */
   if(wv_pcmcia_reset(dev) == FALSE)
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index 4b9de0093a7b..33dd97094227 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -459,7 +459,6 @@
 #undef WAVELAN_ROAMING_EXT	/* Enable roaming wireless extensions */
 #undef SET_PSA_CRC		/* Set the CRC in PSA (slower) */
 #define USE_PSA_CONFIG		/* Use info from the PSA */
-#undef STRUCT_CHECK		/* Verify padding of structures */
 #undef EEPROM_IS_PROTECTED	/* Doesn't seem to be necessary */
 #define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical) */
 #undef SET_MAC_ADDRESS		/* Experimental */
@@ -548,7 +547,7 @@ typedef struct wavepoint_beacon
 			spec_id2,	/* Unused */
 			pdu_type,	/* Unused */
 			seq;		/* WavePoint beacon sequence number */
-  unsigned short	domain_id,	/* WavePoint Domain ID */
+  __be16		domain_id,	/* WavePoint Domain ID */
 			nwid;		/* WavePoint NWID */
 } wavepoint_beacon;
 
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig
index d1ab24a95630..74b31eafe72d 100644
--- a/drivers/net/wireless/zd1211rw/Kconfig
+++ b/drivers/net/wireless/zd1211rw/Kconfig
@@ -1,14 +1,13 @@
 config ZD1211RW
 	tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
-	depends on USB && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL
-	select WIRELESS_EXT
+	depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL
 	select FW_LOADER
 	---help---
 	  This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
 	  chip, present in many USB-wireless adapters.
 
-	  Device firmware is required alongside this driver. You can download the
-	  firmware distribution from http://zd1211.ath.cx/get-firmware
+	  Device firmware is required alongside this driver. You can download
+	  the firmware distribution from http://zd1211.ath.cx/get-firmware
 
 config ZD1211RW_DEBUG
 	bool "ZyDAS ZD1211 debugging"
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
index 7a2f2a98edab..cc36126cee88 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -1,7 +1,6 @@
 obj-$(CONFIG_ZD1211RW) += zd1211rw.o
 
-zd1211rw-objs := zd_chip.o zd_ieee80211.o \
-		zd_mac.o zd_netdev.o \
+zd1211rw-objs := zd_chip.o zd_ieee80211.o zd_mac.o \
 		zd_rf_al2230.o zd_rf_rf2959.o \
 		zd_rf_al7230b.o zd_rf_uw2453.o \
 		zd_rf.o zd_usb.o
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index f831b68f1b9c..99e5b03b3f51 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -1,4 +1,7 @@
-/* zd_chip.c
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
@@ -30,12 +33,12 @@
 #include "zd_rf.h"
 
 void zd_chip_init(struct zd_chip *chip,
-	         struct net_device *netdev,
+	         struct ieee80211_hw *hw,
 		 struct usb_interface *intf)
 {
 	memset(chip, 0, sizeof(*chip));
 	mutex_init(&chip->mutex);
-	zd_usb_init(&chip->usb, netdev, intf);
+	zd_usb_init(&chip->usb, hw, intf);
 	zd_rf_init(&chip->rf);
 }
 
@@ -50,7 +53,7 @@ void zd_chip_clear(struct zd_chip *chip)
 
 static int scnprint_mac_oui(struct zd_chip *chip, char *buffer, size_t size)
 {
-	u8 *addr = zd_usb_to_netdev(&chip->usb)->dev_addr;
+	u8 *addr = zd_mac_get_perm_addr(zd_chip_to_mac(chip));
 	return scnprintf(buffer, size, "%02x-%02x-%02x",
 		         addr[0], addr[1], addr[2]);
 }
@@ -378,15 +381,18 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
 	};
 	DECLARE_MAC_BUF(mac);
 
-	reqs[0].value = (mac_addr[3] << 24)
-		      | (mac_addr[2] << 16)
-		      | (mac_addr[1] <<  8)
-		      |  mac_addr[0];
-	reqs[1].value = (mac_addr[5] <<  8)
-		      |  mac_addr[4];
-
-	dev_dbg_f(zd_chip_dev(chip),
-		"mac addr %s\n", print_mac(mac, mac_addr));
+	if (mac_addr) {
+		reqs[0].value = (mac_addr[3] << 24)
+			      | (mac_addr[2] << 16)
+			      | (mac_addr[1] <<  8)
+			      |  mac_addr[0];
+		reqs[1].value = (mac_addr[5] <<  8)
+			      |  mac_addr[4];
+		dev_dbg_f(zd_chip_dev(chip),
+			"mac addr %s\n", print_mac(mac, mac_addr));
+	} else {
+		dev_dbg_f(zd_chip_dev(chip), "set NULL mac\n");
+	}
 
 	mutex_lock(&chip->mutex);
 	r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
@@ -980,7 +986,7 @@ static int print_fw_version(struct zd_chip *chip)
 	return 0;
 }
 
-static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std)
+static int set_mandatory_rates(struct zd_chip *chip, int mode)
 {
 	u32 rates;
 	ZD_ASSERT(mutex_is_locked(&chip->mutex));
@@ -988,11 +994,11 @@ static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std)
 	 * that the device is supporting. Until further notice we should try
 	 * to support 802.11g also for full speed USB.
 	 */
-	switch (std) {
-	case IEEE80211B:
+	switch (mode) {
+	case MODE_IEEE80211B:
 		rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M;
 		break;
-	case IEEE80211G:
+	case MODE_IEEE80211G:
 		rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M|
 			CR_RATE_6M|CR_RATE_12M|CR_RATE_24M;
 		break;
@@ -1003,24 +1009,17 @@ static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std)
 }
 
 int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
-	u8 rts_rate, int preamble)
+				    int preamble)
 {
-	int rts_mod = ZD_RX_CCK;
 	u32 value = 0;
 
-	/* Modulation bit */
-	if (ZD_MODULATION_TYPE(rts_rate) == ZD_OFDM)
-		rts_mod = ZD_RX_OFDM;
-
-	dev_dbg_f(zd_chip_dev(chip), "rts_rate=%x preamble=%x\n",
-		rts_rate, preamble);
-
-	value |= ZD_PURE_RATE(rts_rate) << RTSCTS_SH_RTS_RATE;
-	value |= rts_mod << RTSCTS_SH_RTS_MOD_TYPE;
+	dev_dbg_f(zd_chip_dev(chip), "preamble=%x\n", preamble);
 	value |= preamble << RTSCTS_SH_RTS_PMB_TYPE;
 	value |= preamble << RTSCTS_SH_CTS_PMB_TYPE;
 
-	/* We always send 11M self-CTS messages, like the vendor driver. */
+	/* We always send 11M RTS/self-CTS messages, like the vendor driver. */
+	value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_RTS_RATE;
+	value |= ZD_RX_CCK << RTSCTS_SH_RTS_MOD_TYPE;
 	value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE;
 	value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE;
 
@@ -1109,7 +1108,7 @@ int zd_chip_init_hw(struct zd_chip *chip)
 	 * It might be discussed, whether we should suppport pure b mode for
 	 * full speed USB.
 	 */
-	r = set_mandatory_rates(chip, IEEE80211G);
+	r = set_mandatory_rates(chip, MODE_IEEE80211G);
 	if (r)
 		goto out;
 	/* Disabling interrupts is certainly a smart thing here.
@@ -1320,12 +1319,17 @@ out:
 	return r;
 }
 
-int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates)
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
 {
-	ZD_ASSERT((cr_rates & ~(CR_RATES_80211B | CR_RATES_80211G)) == 0);
-	dev_dbg_f(zd_chip_dev(chip), "%x\n", cr_rates);
+	int r;
+
+	if (cr_rates & ~(CR_RATES_80211B|CR_RATES_80211G))
+		return -EINVAL;
 
-	return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
+	mutex_lock(&chip->mutex);
+	r = zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
+	mutex_unlock(&chip->mutex);
+	return r;
 }
 
 static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size)
@@ -1468,56 +1472,44 @@ u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
 {
 	return (status->frame_status&ZD_RX_OFDM) ?
 		ofdm_qual_percent(status->signal_quality_ofdm,
-					  zd_rate_from_ofdm_plcp_header(rx_frame),
+				  zd_rate_from_ofdm_plcp_header(rx_frame),
 			          size) :
 		cck_qual_percent(status->signal_quality_cck);
 }
 
-u8 zd_rx_strength_percent(u8 rssi)
-{
-	int r = (rssi*100) / 41;
-	if (r > 100)
-		r = 100;
-	return (u8) r;
-}
-
-u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
+/**
+ * zd_rx_rate - report zd-rate
+ * @rx_frame - received frame
+ * @rx_status - rx_status as given by the device
+ *
+ * This function converts the rate as encoded in the received packet to the
+ * zd-rate, we are using on other places in the driver.
+ */
+u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
 {
-	static const u16 ofdm_rates[] = {
-		[ZD_OFDM_PLCP_RATE_6M]  = 60,
-		[ZD_OFDM_PLCP_RATE_9M]  = 90,
-		[ZD_OFDM_PLCP_RATE_12M] = 120,
-		[ZD_OFDM_PLCP_RATE_18M] = 180,
-		[ZD_OFDM_PLCP_RATE_24M] = 240,
-		[ZD_OFDM_PLCP_RATE_36M] = 360,
-		[ZD_OFDM_PLCP_RATE_48M] = 480,
-		[ZD_OFDM_PLCP_RATE_54M] = 540,
-	};
-	u16 rate;
+	u8 zd_rate;
 	if (status->frame_status & ZD_RX_OFDM) {
-		/* Deals with PLCP OFDM rate (not zd_rates) */
-		u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame);
-		rate = ofdm_rates[ofdm_rate & 0xf];
+		zd_rate = zd_rate_from_ofdm_plcp_header(rx_frame);
 	} else {
 		switch (zd_cck_plcp_header_signal(rx_frame)) {
 		case ZD_CCK_PLCP_SIGNAL_1M:
-			rate = 10;
+			zd_rate = ZD_CCK_RATE_1M;
 			break;
 		case ZD_CCK_PLCP_SIGNAL_2M:
-			rate = 20;
+			zd_rate = ZD_CCK_RATE_2M;
 			break;
 		case ZD_CCK_PLCP_SIGNAL_5M5:
-			rate = 55;
+			zd_rate = ZD_CCK_RATE_5_5M;
 			break;
 		case ZD_CCK_PLCP_SIGNAL_11M:
-			rate = 110;
+			zd_rate = ZD_CCK_RATE_11M;
 			break;
 		default:
-			rate = 0;
+			zd_rate = 0;
 		}
 	}
 
-	return rate;
+	return zd_rate;
 }
 
 int zd_chip_switch_radio_on(struct zd_chip *chip)
@@ -1557,20 +1549,22 @@ void zd_chip_disable_int(struct zd_chip *chip)
 	mutex_unlock(&chip->mutex);
 }
 
-int zd_chip_enable_rx(struct zd_chip *chip)
+int zd_chip_enable_rxtx(struct zd_chip *chip)
 {
 	int r;
 
 	mutex_lock(&chip->mutex);
+	zd_usb_enable_tx(&chip->usb);
 	r = zd_usb_enable_rx(&chip->usb);
 	mutex_unlock(&chip->mutex);
 	return r;
 }
 
-void zd_chip_disable_rx(struct zd_chip *chip)
+void zd_chip_disable_rxtx(struct zd_chip *chip)
 {
 	mutex_lock(&chip->mutex);
 	zd_usb_disable_rx(&chip->usb);
+	zd_usb_disable_tx(&chip->usb);
 	mutex_unlock(&chip->mutex);
 }
 
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 8009b70213e2..009c03777a35 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -1,4 +1,7 @@
-/* zd_chip.h
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
@@ -433,9 +436,10 @@ enum {
 #define CR_GROUP_HASH_P2		CTL_REG(0x0628)
 
 #define CR_RX_TIMEOUT			CTL_REG(0x062C)
+
 /* Basic rates supported by the BSS. When producing ACK or CTS messages, the
  * device will use a rate in this table that is less than or equal to the rate
- * of the incoming frame which prompted the response */
+ * of the incoming frame which prompted the response. */
 #define CR_BASIC_RATE_TBL		CTL_REG(0x0630)
 #define CR_RATE_1M	(1 <<  0)	/* 802.11b */
 #define CR_RATE_2M	(1 <<  1)	/* 802.11b */
@@ -509,14 +513,37 @@ enum {
 #define CR_UNDERRUN_CNT			CTL_REG(0x0688)
 
 #define CR_RX_FILTER			CTL_REG(0x068c)
+#define RX_FILTER_ASSOC_REQUEST		(1 <<  0)
 #define RX_FILTER_ASSOC_RESPONSE	(1 <<  1)
+#define RX_FILTER_REASSOC_REQUEST	(1 <<  2)
 #define RX_FILTER_REASSOC_RESPONSE	(1 <<  3)
+#define RX_FILTER_PROBE_REQUEST		(1 <<  4)
 #define RX_FILTER_PROBE_RESPONSE	(1 <<  5)
+/* bits 6 and 7 reserved */
 #define RX_FILTER_BEACON		(1 <<  8)
+#define RX_FILTER_ATIM			(1 <<  9)
 #define RX_FILTER_DISASSOC		(1 << 10)
 #define RX_FILTER_AUTH			(1 << 11)
-#define AP_RX_FILTER			0x0400feff
-#define STA_RX_FILTER			0x0000ffff
+#define RX_FILTER_DEAUTH		(1 << 12)
+#define RX_FILTER_PSPOLL		(1 << 26)
+#define RX_FILTER_RTS			(1 << 27)
+#define RX_FILTER_CTS			(1 << 28)
+#define RX_FILTER_ACK			(1 << 29)
+#define RX_FILTER_CFEND			(1 << 30)
+#define RX_FILTER_CFACK			(1 << 31)
+
+/* Enable bits for all frames you are interested in. */
+#define STA_RX_FILTER	(RX_FILTER_ASSOC_REQUEST | RX_FILTER_ASSOC_RESPONSE | \
+	RX_FILTER_REASSOC_REQUEST | RX_FILTER_REASSOC_RESPONSE | \
+	RX_FILTER_PROBE_REQUEST | RX_FILTER_PROBE_RESPONSE | \
+	(0x3 << 6) /* vendor driver sets these reserved bits */ | \
+	RX_FILTER_BEACON | RX_FILTER_ATIM | RX_FILTER_DISASSOC | \
+	RX_FILTER_AUTH | RX_FILTER_DEAUTH | \
+	(0x7 << 13) /* vendor driver sets these reserved bits */ | \
+	RX_FILTER_PSPOLL | RX_FILTER_ACK) /* 0x2400ffff */
+
+#define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \
+	RX_FILTER_CFEND | RX_FILTER_CFACK)
 
 /* Monitor mode sets filter to 0xfffff */
 
@@ -730,7 +757,7 @@ static inline struct zd_chip *zd_rf_to_chip(struct zd_rf *rf)
 #define zd_chip_dev(chip) (&(chip)->usb.intf->dev)
 
 void zd_chip_init(struct zd_chip *chip,
-	         struct net_device *netdev,
+	         struct ieee80211_hw *hw,
 	         struct usb_interface *intf);
 void zd_chip_clear(struct zd_chip *chip);
 int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr);
@@ -835,14 +862,12 @@ int zd_chip_switch_radio_on(struct zd_chip *chip);
 int zd_chip_switch_radio_off(struct zd_chip *chip);
 int zd_chip_enable_int(struct zd_chip *chip);
 void zd_chip_disable_int(struct zd_chip *chip);
-int zd_chip_enable_rx(struct zd_chip *chip);
-void zd_chip_disable_rx(struct zd_chip *chip);
+int zd_chip_enable_rxtx(struct zd_chip *chip);
+void zd_chip_disable_rxtx(struct zd_chip *chip);
 int zd_chip_enable_hwint(struct zd_chip *chip);
 int zd_chip_disable_hwint(struct zd_chip *chip);
 int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel);
-
-int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
-	u8 rts_rate, int preamble);
+int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, int preamble);
 
 static inline int zd_get_encryption_type(struct zd_chip *chip, u32 *type)
 {
@@ -859,17 +884,7 @@ static inline int zd_chip_get_basic_rates(struct zd_chip *chip, u16 *cr_rates)
 	return zd_ioread16(chip, CR_BASIC_RATE_TBL, cr_rates);
 }
 
-int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates);
-
-static inline int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
-{
-	int r;
-
-	mutex_lock(&chip->mutex);
-	r = zd_chip_set_basic_rates_locked(chip, cr_rates);
-	mutex_unlock(&chip->mutex);
-	return r;
-}
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates);
 
 int zd_chip_lock_phy_regs(struct zd_chip *chip);
 int zd_chip_unlock_phy_regs(struct zd_chip *chip);
@@ -893,9 +908,8 @@ struct rx_status;
 
 u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
 	               const struct rx_status *status);
-u8 zd_rx_strength_percent(u8 rssi);
 
-u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
+u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
 
 struct zd_mc_hash {
 	u32 low;
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index 505b4d7dd0e2..5200db405610 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -1,4 +1,7 @@
-/* zd_def.h
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
index 189160efd2ae..7c277ec43f79 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
@@ -1,4 +1,7 @@
-/* zd_ieee80211.c
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
@@ -16,178 +19,85 @@
  */
 
 /*
- * A lot of this code is generic and should be moved into the upper layers
- * at some point.
+ * In the long term, we'll probably find a better way of handling regulatory
+ * requirements outside of the driver.
  */
 
-#include <linux/errno.h>
-#include <linux/wireless.h>
 #include <linux/kernel.h>
-#include <net/ieee80211.h>
+#include <net/mac80211.h>
 
-#include "zd_def.h"
 #include "zd_ieee80211.h"
 #include "zd_mac.h"
 
+struct channel_range {
+	u8 regdomain;
+	u8 start;
+	u8 end; /* exclusive (channel must be less than end) */
+};
+
 static const struct channel_range channel_ranges[] = {
-	[0]			 = { 0,  0},
-	[ZD_REGDOMAIN_FCC]	 = { 1, 12},
-	[ZD_REGDOMAIN_IC]	 = { 1, 12},
-	[ZD_REGDOMAIN_ETSI]	 = { 1, 14},
-	[ZD_REGDOMAIN_JAPAN]	 = { 1, 14},
-	[ZD_REGDOMAIN_SPAIN]	 = { 1, 14},
-	[ZD_REGDOMAIN_FRANCE]	 = { 1, 14},
+	{ ZD_REGDOMAIN_FCC,		1, 12 },
+	{ ZD_REGDOMAIN_IC,		1, 12 },
+	{ ZD_REGDOMAIN_ETSI,		1, 14 },
+	{ ZD_REGDOMAIN_JAPAN,		1, 14 },
+	{ ZD_REGDOMAIN_SPAIN,		1, 14 },
+	{ ZD_REGDOMAIN_FRANCE,		1, 14 },
 
 	/* Japan originally only had channel 14 available (see CHNL_ID 0x40 in
 	 * 802.11). However, in 2001 the range was extended to include channels
 	 * 1-13. The ZyDAS devices still use the old region code but are
 	 * designed to allow the extra channel access in Japan. */
-	[ZD_REGDOMAIN_JAPAN_ADD] = { 1, 15},
+	{ ZD_REGDOMAIN_JAPAN_ADD,	1, 15 },
 };
 
-const struct channel_range *zd_channel_range(u8 regdomain)
-{
-	if (regdomain >= ARRAY_SIZE(channel_ranges))
-		regdomain = 0;
-	return &channel_ranges[regdomain];
-}
-
-int zd_regdomain_supports_channel(u8 regdomain, u8 channel)
-{
-	const struct channel_range *range = zd_channel_range(regdomain);
-	return range->start <= channel && channel < range->end;
-}
-
-int zd_regdomain_supported(u8 regdomain)
-{
-	const struct channel_range *range = zd_channel_range(regdomain);
-	return range->start != 0;
-}
-
-/* Stores channel frequencies in MHz. */
-static const u16 channel_frequencies[] = {
-	2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
-	2452, 2457, 2462, 2467, 2472, 2484,
-};
-
-#define NUM_CHANNELS ARRAY_SIZE(channel_frequencies)
-
-static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz)
-{
-	u32 factor;
-
-	freq->e = 0;
-	if (mhz >= 1000000000U) {
-		pr_debug("zd1211 mhz %u to large\n", mhz);
-		freq->m = 0;
-		return -EINVAL;
-	}
-
-	factor = 1000;
-	while (mhz >= factor) {
-
-		freq->e += 1;
-		factor *= 10;
-	}
-
-	factor /= 1000U;
-	freq->m = mhz * (1000000U/factor) + hz/factor;
-
-	return 0;
-}
-
-int zd_channel_to_freq(struct iw_freq *freq, u8 channel)
+static const struct channel_range *zd_channel_range(u8 regdomain)
 {
-	if (channel > NUM_CHANNELS) {
-		freq->m = 0;
-		freq->e = 0;
-		return -EINVAL;
-	}
-	if (!channel) {
-		freq->m = 0;
-		freq->e = 0;
-		return -EINVAL;
+	int i;
+	for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) {
+		const struct channel_range *range = &channel_ranges[i];
+		if (range->regdomain == regdomain)
+			return range;
 	}
-	return compute_freq(freq, channel_frequencies[channel-1], 0);
+	return NULL;
 }
 
-static int freq_to_mhz(const struct iw_freq *freq)
-{
-	u32 factor;
-	int e;
-
-	/* Such high frequencies are not supported. */
-	if (freq->e > 6)
-		return -EINVAL;
-
-	factor = 1;
-	for (e = freq->e; e > 0; --e) {
-		factor *= 10;
-	}
-	factor = 1000000U / factor;
-
-	if (freq->m % factor) {
-		return -EINVAL;
-	}
-
-	return freq->m / factor;
-}
+#define CHAN_TO_IDX(chan) ((chan) - 1)
 
-int zd_find_channel(u8 *channel, const struct iw_freq *freq)
+static void unmask_bg_channels(struct ieee80211_hw *hw,
+	const struct channel_range *range,
+	struct ieee80211_hw_mode *mode)
 {
-	int i, r;
-	u32 mhz;
-
-	if (freq->m < 1000) {
-		if (freq->m  > NUM_CHANNELS || freq->m == 0)
-			return -EINVAL;
-		*channel = freq->m;
-		return 1;
-	}
-
-	r = freq_to_mhz(freq);
-	if (r < 0)
-		return r;
-	mhz = r;
+	u8 channel;
 
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		if (mhz == channel_frequencies[i]) {
-			*channel = i+1;
-			return 1;
-		}
+	for (channel = range->start; channel < range->end; channel++) {
+		struct ieee80211_channel *chan =
+			&mode->channels[CHAN_TO_IDX(channel)];
+		chan->flag |= IEEE80211_CHAN_W_SCAN |
+			IEEE80211_CHAN_W_ACTIVE_SCAN |
+			IEEE80211_CHAN_W_IBSS;
 	}
-
-	return -EINVAL;
 }
 
-int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain)
+void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain)
 {
-	struct ieee80211_geo geo;
+	struct zd_mac *mac = zd_hw_mac(hw);
 	const struct channel_range *range;
-	int i;
-	u8 channel;
 
-	dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)),
-		"regdomain %#04x\n", regdomain);
+	dev_dbg(zd_mac_dev(mac), "regdomain %#02x\n", regdomain);
 
 	range = zd_channel_range(regdomain);
-	if (range->start == 0) {
-		dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)),
-			"zd1211 regdomain %#04x not supported\n",
-			regdomain);
-		return -EINVAL;
+	if (!range) {
+		/* The vendor driver overrides the regulatory domain and
+		 * allowed channel registers and unconditionally restricts
+		 * available channels to 1-11 everywhere. Match their
+		 * questionable behaviour only for regdomains which we don't
+		 * recognise. */
+		dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: "
+			"%#02x. Defaulting to FCC.\n", regdomain);
+		range = zd_channel_range(ZD_REGDOMAIN_FCC);
 	}
 
-	memset(&geo, 0, sizeof(geo));
-
-	for (i = 0, channel = range->start; channel < range->end; channel++) {
-		struct ieee80211_channel *chan = &geo.bg[i++];
-		chan->freq = channel_frequencies[channel - 1];
-		chan->channel = channel;
-	}
-
-	geo.bg_channels = i;
-	memcpy(geo.name, "XX ", 4);
-	ieee80211_set_geo(ieee, &geo);
-	return 0;
+	unmask_bg_channels(hw, range, &mac->modes[0]);
+	unmask_bg_channels(hw, range, &mac->modes[1]);
 }
+
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index fbf6491dce7e..26b79f197587 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -1,7 +1,27 @@
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
 #ifndef _ZD_IEEE80211_H
 #define _ZD_IEEE80211_H
 
-#include <net/ieee80211.h>
+#include <net/mac80211.h>
 
 /* Additional definitions from the standards.
  */
@@ -19,22 +39,7 @@ enum {
 	MAX_CHANNEL24 = 14,
 };
 
-struct channel_range {
-	u8 start;
-	u8 end; /* exclusive (channel must be less than end) */
-};
-
-struct iw_freq;
-
-int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain);
-
-const struct channel_range *zd_channel_range(u8 regdomain);
-int zd_regdomain_supports_channel(u8 regdomain, u8 channel);
-int zd_regdomain_supported(u8 regdomain);
-
-/* for 2.4 GHz band */
-int zd_channel_to_freq(struct iw_freq *freq, u8 channel);
-int zd_find_channel(u8 *channel, const struct iw_freq *freq);
+void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain);
 
 #define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
 
@@ -54,8 +59,8 @@ static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
  *
  * See the struct zd_ctrlset definition in zd_mac.h.
  */
-#define ZD_OFDM_PLCP_RATE_6M		0xb
-#define ZD_OFDM_PLCP_RATE_9M		0xf
+#define ZD_OFDM_PLCP_RATE_6M	0xb
+#define ZD_OFDM_PLCP_RATE_9M	0xf
 #define ZD_OFDM_PLCP_RATE_12M	0xa
 #define ZD_OFDM_PLCP_RATE_18M	0xe
 #define ZD_OFDM_PLCP_RATE_24M	0x9
@@ -87,10 +92,4 @@ static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
 #define ZD_CCK_PLCP_SIGNAL_5M5	0x37
 #define ZD_CCK_PLCP_SIGNAL_11M	0x6e
 
-enum ieee80211_std {
-	IEEE80211B = 0x01,
-	IEEE80211A = 0x02,
-	IEEE80211G = 0x04,
-};
-
 #endif /* _ZD_IEEE80211_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 5298a8bf1129..49127e4b42c2 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -1,4 +1,9 @@
-/* zd_mac.c
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright (C) 2006-2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,7 +22,6 @@
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/wireless.h>
 #include <linux/usb.h>
 #include <linux/jiffies.h>
 #include <net/ieee80211_radiotap.h>
@@ -26,81 +30,105 @@
 #include "zd_chip.h"
 #include "zd_mac.h"
 #include "zd_ieee80211.h"
-#include "zd_netdev.h"
 #include "zd_rf.h"
 
-static void ieee_init(struct ieee80211_device *ieee);
-static void softmac_init(struct ieee80211softmac_device *sm);
-static void set_rts_cts_work(struct work_struct *work);
-static void set_basic_rates_work(struct work_struct *work);
+/* This table contains the hardware specific values for the modulation rates. */
+static const struct ieee80211_rate zd_rates[] = {
+	{ .rate = 10,
+	  .val = ZD_CCK_RATE_1M,
+	  .flags = IEEE80211_RATE_CCK },
+	{ .rate = 20,
+	  .val = ZD_CCK_RATE_2M,
+	  .val2 = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT,
+	  .flags = IEEE80211_RATE_CCK_2 },
+	{ .rate = 55,
+	  .val = ZD_CCK_RATE_5_5M,
+	  .val2 = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT,
+	  .flags = IEEE80211_RATE_CCK_2 },
+	{ .rate = 110,
+	  .val = ZD_CCK_RATE_11M,
+	  .val2 = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT,
+	  .flags = IEEE80211_RATE_CCK_2 },
+	{ .rate = 60,
+	  .val = ZD_OFDM_RATE_6M,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 90,
+	  .val = ZD_OFDM_RATE_9M,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 120,
+	  .val = ZD_OFDM_RATE_12M,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 180,
+	  .val = ZD_OFDM_RATE_18M,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 240,
+	  .val = ZD_OFDM_RATE_24M,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 360,
+	  .val = ZD_OFDM_RATE_36M,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 480,
+	  .val = ZD_OFDM_RATE_48M,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 540,
+	  .val = ZD_OFDM_RATE_54M,
+	  .flags = IEEE80211_RATE_OFDM },
+};
+
+static const struct ieee80211_channel zd_channels[] = {
+	{ .chan = 1,
+	  .freq = 2412},
+	{ .chan = 2,
+	  .freq = 2417},
+	{ .chan = 3,
+	  .freq = 2422},
+	{ .chan = 4,
+	  .freq = 2427},
+	{ .chan = 5,
+	  .freq = 2432},
+	{ .chan = 6,
+	  .freq = 2437},
+	{ .chan = 7,
+	  .freq = 2442},
+	{ .chan = 8,
+	  .freq = 2447},
+	{ .chan = 9,
+	  .freq = 2452},
+	{ .chan = 10,
+	  .freq = 2457},
+	{ .chan = 11,
+	  .freq = 2462},
+	{ .chan = 12,
+	  .freq = 2467},
+	{ .chan = 13,
+	  .freq = 2472},
+	{ .chan = 14,
+	  .freq = 2484}
+};
 
 static void housekeeping_init(struct zd_mac *mac);
 static void housekeeping_enable(struct zd_mac *mac);
 static void housekeeping_disable(struct zd_mac *mac);
 
-static void set_multicast_hash_handler(struct work_struct *work);
-
-static void do_rx(unsigned long mac_ptr);
-
-int zd_mac_init(struct zd_mac *mac,
-	        struct net_device *netdev,
-	        struct usb_interface *intf)
-{
-	struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
-
-	memset(mac, 0, sizeof(*mac));
-	spin_lock_init(&mac->lock);
-	mac->netdev = netdev;
-	INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
-	INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work);
-
-	skb_queue_head_init(&mac->rx_queue);
-	tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac);
-	tasklet_disable(&mac->rx_tasklet);
-
-	ieee_init(ieee);
-	softmac_init(ieee80211_priv(netdev));
-	zd_chip_init(&mac->chip, netdev, intf);
-	housekeeping_init(mac);
-	INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler);
-	return 0;
-}
-
-static int reset_channel(struct zd_mac *mac)
-{
-	int r;
-	unsigned long flags;
-	const struct channel_range *range;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	range = zd_channel_range(mac->regdomain);
-	if (!range->start) {
-		r = -EINVAL;
-		goto out;
-	}
-	mac->requested_channel = range->start;
-	r = 0;
-out:
-	spin_unlock_irqrestore(&mac->lock, flags);
-	return r;
-}
-
-int zd_mac_preinit_hw(struct zd_mac *mac)
+int zd_mac_preinit_hw(struct ieee80211_hw *hw)
 {
 	int r;
 	u8 addr[ETH_ALEN];
+	struct zd_mac *mac = zd_hw_mac(hw);
 
 	r = zd_chip_read_mac_addr_fw(&mac->chip, addr);
 	if (r)
 		return r;
 
-	memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);
+	SET_IEEE80211_PERM_ADDR(hw, addr);
+
 	return 0;
 }
 
-int zd_mac_init_hw(struct zd_mac *mac)
+int zd_mac_init_hw(struct ieee80211_hw *hw)
 {
 	int r;
+	struct zd_mac *mac = zd_hw_mac(hw);
 	struct zd_chip *chip = &mac->chip;
 	u8 default_regdomain;
 
@@ -116,22 +144,9 @@ int zd_mac_init_hw(struct zd_mac *mac)
 	r = zd_read_regdomain(chip, &default_regdomain);
 	if (r)
 		goto disable_int;
-	if (!zd_regdomain_supported(default_regdomain)) {
-		/* The vendor driver overrides the regulatory domain and
-		 * allowed channel registers and unconditionally restricts
-		 * available channels to 1-11 everywhere. Match their
-		 * questionable behaviour only for regdomains which we don't
-		 * recognise. */
-		dev_warn(zd_mac_dev(mac),  "Unrecognised regulatory domain: "
-			"%#04x. Defaulting to FCC.\n", default_regdomain);
-		default_regdomain = ZD_REGDOMAIN_FCC;
-	}
 	spin_lock_irq(&mac->lock);
 	mac->regdomain = mac->default_regdomain = default_regdomain;
 	spin_unlock_irq(&mac->lock);
-	r = reset_channel(mac);
-	if (r)
-		goto disable_int;
 
 	/* We must inform the device that we are doing encryption/decryption in
 	 * software at the moment. */
@@ -139,9 +154,7 @@ int zd_mac_init_hw(struct zd_mac *mac)
 	if (r)
 		goto disable_int;
 
-	r = zd_geo_init(zd_mac_to_ieee80211(mac), mac->regdomain);
-	if (r)
-		goto disable_int;
+	zd_geo_init(hw, mac->regdomain);
 
 	r = 0;
 disable_int:
@@ -153,8 +166,6 @@ out:
 void zd_mac_clear(struct zd_mac *mac)
 {
 	flush_workqueue(zd_workqueue);
-	skb_queue_purge(&mac->rx_queue);
-	tasklet_kill(&mac->rx_tasklet);
 	zd_chip_clear(&mac->chip);
 	ZD_ASSERT(!spin_is_locked(&mac->lock));
 	ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
@@ -162,34 +173,27 @@ void zd_mac_clear(struct zd_mac *mac)
 
 static int set_rx_filter(struct zd_mac *mac)
 {
-	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
-	return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
-}
+	unsigned long flags;
+	u32 filter = STA_RX_FILTER;
 
-static int set_sniffer(struct zd_mac *mac)
-{
-	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	return zd_iowrite32(&mac->chip, CR_SNIFFER_ON,
-		ieee->iw_mode == IW_MODE_MONITOR ? 1 : 0);
-	return 0;
+	spin_lock_irqsave(&mac->lock, flags);
+	if (mac->pass_ctrl)
+		filter |= RX_FILTER_CTRL;
+	spin_unlock_irqrestore(&mac->lock, flags);
+
+	return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
 }
 
 static int set_mc_hash(struct zd_mac *mac)
 {
 	struct zd_mc_hash hash;
-	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-
 	zd_mc_clear(&hash);
-	if (ieee->iw_mode == IW_MODE_MONITOR)
-		zd_mc_add_all(&hash);
-
 	return zd_chip_set_multicast_hash(&mac->chip, &hash);
 }
 
-int zd_mac_open(struct net_device *netdev)
+static int zd_op_start(struct ieee80211_hw *hw)
 {
-	struct zd_mac *mac = zd_netdev_mac(netdev);
+	struct zd_mac *mac = zd_hw_mac(hw);
 	struct zd_chip *chip = &mac->chip;
 	struct zd_usb *usb = &chip->usb;
 	int r;
@@ -200,46 +204,33 @@ int zd_mac_open(struct net_device *netdev)
 			goto out;
 	}
 
-	tasklet_enable(&mac->rx_tasklet);
-
 	r = zd_chip_enable_int(chip);
 	if (r < 0)
 		goto out;
 
-	r = zd_write_mac_addr(chip, netdev->dev_addr);
-	if (r)
-		goto disable_int;
-
 	r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
 	if (r < 0)
 		goto disable_int;
 	r = set_rx_filter(mac);
 	if (r)
 		goto disable_int;
-	r = set_sniffer(mac);
-	if (r)
-		goto disable_int;
 	r = set_mc_hash(mac);
 	if (r)
 		goto disable_int;
 	r = zd_chip_switch_radio_on(chip);
 	if (r < 0)
 		goto disable_int;
-	r = zd_chip_set_channel(chip, mac->requested_channel);
-	if (r < 0)
-		goto disable_radio;
-	r = zd_chip_enable_rx(chip);
+	r = zd_chip_enable_rxtx(chip);
 	if (r < 0)
 		goto disable_radio;
 	r = zd_chip_enable_hwint(chip);
 	if (r < 0)
-		goto disable_rx;
+		goto disable_rxtx;
 
 	housekeeping_enable(mac);
-	ieee80211softmac_start(netdev);
 	return 0;
-disable_rx:
-	zd_chip_disable_rx(chip);
+disable_rxtx:
+	zd_chip_disable_rxtx(chip);
 disable_radio:
 	zd_chip_switch_radio_off(chip);
 disable_int:
@@ -248,494 +239,190 @@ out:
 	return r;
 }
 
-int zd_mac_stop(struct net_device *netdev)
+/**
+ * clear_tx_skb_control_block - clears the control block of tx skbuffs
+ * @skb: a &struct sk_buff pointer
+ *
+ * This clears the control block of skbuff buffers, which were transmitted to
+ * the device. Notify that the function is not thread-safe, so prevent
+ * multiple calls.
+ */
+static void clear_tx_skb_control_block(struct sk_buff *skb)
 {
-	struct zd_mac *mac = zd_netdev_mac(netdev);
-	struct zd_chip *chip = &mac->chip;
+	struct zd_tx_skb_control_block *cb =
+		(struct zd_tx_skb_control_block *)skb->cb;
 
-	netif_stop_queue(netdev);
+	kfree(cb->control);
+	cb->control = NULL;
+}
 
-	/*
-	 * The order here deliberately is a little different from the open()
+/**
+ * kfree_tx_skb - frees a tx skbuff
+ * @skb: a &struct sk_buff pointer
+ *
+ * Frees the tx skbuff. Frees also the allocated control structure in the
+ * control block if necessary.
+ */
+static void kfree_tx_skb(struct sk_buff *skb)
+{
+	clear_tx_skb_control_block(skb);
+	dev_kfree_skb_any(skb);
+}
+
+static void zd_op_stop(struct ieee80211_hw *hw)
+{
+	struct zd_mac *mac = zd_hw_mac(hw);
+	struct zd_chip *chip = &mac->chip;
+	struct sk_buff *skb;
+	struct sk_buff_head *ack_wait_queue = &mac->ack_wait_queue;
+
+	/* The order here deliberately is a little different from the open()
 	 * method, since we need to make sure there is no opportunity for RX
-	 * frames to be processed by softmac after we have stopped it.
+	 * frames to be processed by mac80211 after we have stopped it.
 	 */
 
-	zd_chip_disable_rx(chip);
-	skb_queue_purge(&mac->rx_queue);
-	tasklet_disable(&mac->rx_tasklet);
+	zd_chip_disable_rxtx(chip);
 	housekeeping_disable(mac);
-	ieee80211softmac_stop(netdev);
-
-	/* Ensure no work items are running or queued from this point */
-	cancel_delayed_work(&mac->set_rts_cts_work);
-	cancel_delayed_work(&mac->set_basic_rates_work);
 	flush_workqueue(zd_workqueue);
-	mac->updating_rts_rate = 0;
-	mac->updating_basic_rates = 0;
 
 	zd_chip_disable_hwint(chip);
 	zd_chip_switch_radio_off(chip);
 	zd_chip_disable_int(chip);
 
-	return 0;
-}
-
-int zd_mac_set_mac_address(struct net_device *netdev, void *p)
-{
-	int r;
-	unsigned long flags;
-	struct sockaddr *addr = p;
-	struct zd_mac *mac = zd_netdev_mac(netdev);
-	struct zd_chip *chip = &mac->chip;
-	DECLARE_MAC_BUF(mac2);
-
-	if (!is_valid_ether_addr(addr->sa_data))
-		return -EADDRNOTAVAIL;
-
-	dev_dbg_f(zd_mac_dev(mac),
-		  "Setting MAC to %s\n", print_mac(mac2, addr->sa_data));
-
-	if (netdev->flags & IFF_UP) {
-		r = zd_write_mac_addr(chip, addr->sa_data);
-		if (r)
-			return r;
-	}
-
-	spin_lock_irqsave(&mac->lock, flags);
-	memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN);
-	spin_unlock_irqrestore(&mac->lock, flags);
-
-	return 0;
-}
-
-static void set_multicast_hash_handler(struct work_struct *work)
-{
-	struct zd_mac *mac = container_of(work, struct zd_mac,
-					  set_multicast_hash_work);
-	struct zd_mc_hash hash;
-
-	spin_lock_irq(&mac->lock);
-	hash = mac->multicast_hash;
-	spin_unlock_irq(&mac->lock);
 
-	zd_chip_set_multicast_hash(&mac->chip, &hash);
+	while ((skb = skb_dequeue(ack_wait_queue)))
+		kfree_tx_skb(skb);
 }
 
-void zd_mac_set_multicast_list(struct net_device *dev)
-{
-	struct zd_mac *mac = zd_netdev_mac(dev);
-	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	struct zd_mc_hash hash;
-	struct dev_mc_list *mc;
-	unsigned long flags;
-	DECLARE_MAC_BUF(mac2);
-
-	if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) ||
-			ieee->iw_mode == IW_MODE_MONITOR) {
-		zd_mc_add_all(&hash);
-	} else {
-		zd_mc_clear(&hash);
-		for (mc = dev->mc_list; mc; mc = mc->next) {
-			dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n",
-				  print_mac(mac2, mc->dmi_addr));
-			zd_mc_add_addr(&hash, mc->dmi_addr);
-		}
-	}
-
-	spin_lock_irqsave(&mac->lock, flags);
-	mac->multicast_hash = hash;
-	spin_unlock_irqrestore(&mac->lock, flags);
-	queue_work(zd_workqueue, &mac->set_multicast_hash_work);
-}
-
-int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain)
-{
-	int r;
-	u8 channel;
-
-	ZD_ASSERT(!irqs_disabled());
-	spin_lock_irq(&mac->lock);
-	if (regdomain == 0) {
-		regdomain = mac->default_regdomain;
-	}
-	if (!zd_regdomain_supported(regdomain)) {
-		spin_unlock_irq(&mac->lock);
-		return -EINVAL;
-	}
-	mac->regdomain = regdomain;
-	channel = mac->requested_channel;
-	spin_unlock_irq(&mac->lock);
-
-	r = zd_geo_init(zd_mac_to_ieee80211(mac), regdomain);
-	if (r)
-		return r;
-	if (!zd_regdomain_supports_channel(regdomain, channel)) {
-		r = reset_channel(mac);
-		if (r)
-			return r;
-	}
+/**
+ * init_tx_skb_control_block - initializes skb control block
+ * @skb: a &sk_buff pointer
+ * @dev: pointer to the mac80221 device
+ * @control: mac80211 tx control applying for the frame in @skb
+ *
+ * Initializes the control block of the skbuff to be transmitted.
+ */
+static int init_tx_skb_control_block(struct sk_buff *skb,
+				     struct ieee80211_hw *hw,
+	                             struct ieee80211_tx_control *control)
+{
+	struct zd_tx_skb_control_block *cb =
+		(struct zd_tx_skb_control_block *)skb->cb;
+
+	ZD_ASSERT(sizeof(*cb) <= sizeof(skb->cb));
+	memset(cb, 0, sizeof(*cb));
+	cb->hw= hw;
+	cb->control = kmalloc(sizeof(*control), GFP_ATOMIC);
+	if (cb->control == NULL)
+		return -ENOMEM;
+	memcpy(cb->control, control, sizeof(*control));
 
 	return 0;
 }
 
-u8 zd_mac_get_regdomain(struct zd_mac *mac)
-{
-	unsigned long flags;
-	u8 regdomain;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	regdomain = mac->regdomain;
-	spin_unlock_irqrestore(&mac->lock, flags);
-	return regdomain;
-}
-
-/* Fallback to lowest rate, if rate is unknown. */
-static u8 rate_to_zd_rate(u8 rate)
-{
-	switch (rate) {
-	case IEEE80211_CCK_RATE_2MB:
-		return ZD_CCK_RATE_2M;
-	case IEEE80211_CCK_RATE_5MB:
-		return ZD_CCK_RATE_5_5M;
-	case IEEE80211_CCK_RATE_11MB:
-		return ZD_CCK_RATE_11M;
-	case IEEE80211_OFDM_RATE_6MB:
-		return ZD_OFDM_RATE_6M;
-	case IEEE80211_OFDM_RATE_9MB:
-		return ZD_OFDM_RATE_9M;
-	case IEEE80211_OFDM_RATE_12MB:
-		return ZD_OFDM_RATE_12M;
-	case IEEE80211_OFDM_RATE_18MB:
-		return ZD_OFDM_RATE_18M;
-	case IEEE80211_OFDM_RATE_24MB:
-		return ZD_OFDM_RATE_24M;
-	case IEEE80211_OFDM_RATE_36MB:
-		return ZD_OFDM_RATE_36M;
-	case IEEE80211_OFDM_RATE_48MB:
-		return ZD_OFDM_RATE_48M;
-	case IEEE80211_OFDM_RATE_54MB:
-		return ZD_OFDM_RATE_54M;
-	}
-	return ZD_CCK_RATE_1M;
-}
-
-static u16 rate_to_cr_rate(u8 rate)
-{
-	switch (rate) {
-	case IEEE80211_CCK_RATE_2MB:
-		return CR_RATE_1M;
-	case IEEE80211_CCK_RATE_5MB:
-		return CR_RATE_5_5M;
-	case IEEE80211_CCK_RATE_11MB:
-		return CR_RATE_11M;
-	case IEEE80211_OFDM_RATE_6MB:
-		return CR_RATE_6M;
-	case IEEE80211_OFDM_RATE_9MB:
-		return CR_RATE_9M;
-	case IEEE80211_OFDM_RATE_12MB:
-		return CR_RATE_12M;
-	case IEEE80211_OFDM_RATE_18MB:
-		return CR_RATE_18M;
-	case IEEE80211_OFDM_RATE_24MB:
-		return CR_RATE_24M;
-	case IEEE80211_OFDM_RATE_36MB:
-		return CR_RATE_36M;
-	case IEEE80211_OFDM_RATE_48MB:
-		return CR_RATE_48M;
-	case IEEE80211_OFDM_RATE_54MB:
-		return CR_RATE_54M;
-	}
-	return CR_RATE_1M;
-}
-
-static void try_enable_tx(struct zd_mac *mac)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	if (mac->updating_rts_rate == 0 && mac->updating_basic_rates == 0)
-		netif_wake_queue(mac->netdev);
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-static void set_rts_cts_work(struct work_struct *work)
+/**
+ * tx_status - reports tx status of a packet if required
+ * @hw - a &struct ieee80211_hw pointer
+ * @skb - a sk-buffer
+ * @status - the tx status of the packet without control information
+ * @success - True for successfull transmission of the frame
+ *
+ * This information calls ieee80211_tx_status_irqsafe() if required by the
+ * control information. It copies the control information into the status
+ * information.
+ *
+ * If no status information has been requested, the skb is freed.
+ */
+static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
+	              struct ieee80211_tx_status *status,
+		      bool success)
 {
-	struct zd_mac *mac =
-		container_of(work, struct zd_mac, set_rts_cts_work.work);
-	unsigned long flags;
-	u8 rts_rate;
-	unsigned int short_preamble;
-
-	mutex_lock(&mac->chip.mutex);
-
-	spin_lock_irqsave(&mac->lock, flags);
-	mac->updating_rts_rate = 0;
-	rts_rate = mac->rts_rate;
-	short_preamble = mac->short_preamble;
-	spin_unlock_irqrestore(&mac->lock, flags);
-
-	zd_chip_set_rts_cts_rate_locked(&mac->chip, rts_rate, short_preamble);
-	mutex_unlock(&mac->chip.mutex);
+	struct zd_tx_skb_control_block *cb = (struct zd_tx_skb_control_block *)
+		skb->cb;
 
-	try_enable_tx(mac);
+	ZD_ASSERT(cb->control != NULL);
+	memcpy(&status->control, cb->control, sizeof(status->control));
+	if (!success)
+		status->excessive_retries = 1;
+	clear_tx_skb_control_block(skb);
+	ieee80211_tx_status_irqsafe(hw, skb, status);
 }
 
-static void set_basic_rates_work(struct work_struct *work)
+/**
+ * zd_mac_tx_failed - callback for failed frames
+ * @dev: the mac80211 wireless device
+ *
+ * This function is called if a frame couldn't be succesfully be
+ * transferred. The first frame from the tx queue, will be selected and
+ * reported as error to the upper layers.
+ */
+void zd_mac_tx_failed(struct ieee80211_hw *hw)
 {
-	struct zd_mac *mac =
-		container_of(work, struct zd_mac, set_basic_rates_work.work);
-	unsigned long flags;
-	u16 basic_rates;
-
-	mutex_lock(&mac->chip.mutex);
-
-	spin_lock_irqsave(&mac->lock, flags);
-	mac->updating_basic_rates = 0;
-	basic_rates = mac->basic_rates;
-	spin_unlock_irqrestore(&mac->lock, flags);
-
-	zd_chip_set_basic_rates_locked(&mac->chip, basic_rates);
-	mutex_unlock(&mac->chip.mutex);
+	struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue;
+	struct sk_buff *skb;
+	struct ieee80211_tx_status status = {{0}};
 
-	try_enable_tx(mac);
+	skb = skb_dequeue(q);
+	if (skb == NULL)
+		return;
+	tx_status(hw, skb, &status, 0);
 }
 
-static void bssinfo_change(struct net_device *netdev, u32 changes)
-{
-	struct zd_mac *mac = zd_netdev_mac(netdev);
-	struct ieee80211softmac_device *softmac = ieee80211_priv(netdev);
-	struct ieee80211softmac_bss_info *bssinfo = &softmac->bssinfo;
-	int need_set_rts_cts = 0;
-	int need_set_rates = 0;
-	u16 basic_rates;
-	unsigned long flags;
-
-	dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes);
-
-	if (changes & IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE) {
-		spin_lock_irqsave(&mac->lock, flags);
-		mac->short_preamble = bssinfo->short_preamble;
-		spin_unlock_irqrestore(&mac->lock, flags);
-		need_set_rts_cts = 1;
-	}
-
-	if (changes & IEEE80211SOFTMAC_BSSINFOCHG_RATES) {
-		/* Set RTS rate to highest available basic rate */
-		u8 hi_rate = ieee80211softmac_highest_supported_rate(softmac,
-			&bssinfo->supported_rates, 1);
-		hi_rate = rate_to_zd_rate(hi_rate);
-
-		spin_lock_irqsave(&mac->lock, flags);
-		if (hi_rate != mac->rts_rate) {
-			mac->rts_rate = hi_rate;
-			need_set_rts_cts = 1;
-		}
-		spin_unlock_irqrestore(&mac->lock, flags);
-
-		/* Set basic rates */
-		need_set_rates = 1;
-		if (bssinfo->supported_rates.count == 0) {
-			/* Allow the device to be flexible */
-			basic_rates = CR_RATES_80211B | CR_RATES_80211G;
+/**
+ * zd_mac_tx_to_dev - callback for USB layer
+ * @skb: a &sk_buff pointer
+ * @error: error value, 0 if transmission successful
+ *
+ * Informs the MAC layer that the frame has successfully transferred to the
+ * device. If an ACK is required and the transfer to the device has been
+ * successful, the packets are put on the @ack_wait_queue with
+ * the control set removed.
+ */
+void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
+{
+	struct zd_tx_skb_control_block *cb =
+		(struct zd_tx_skb_control_block *)skb->cb;
+	struct ieee80211_hw *hw = cb->hw;
+
+	if (likely(cb->control)) {
+		skb_pull(skb, sizeof(struct zd_ctrlset));
+		if (unlikely(error ||
+		    (cb->control->flags & IEEE80211_TXCTL_NO_ACK)))
+		{
+			struct ieee80211_tx_status status = {{0}};
+			tx_status(hw, skb, &status, !error);
 		} else {
-			int i = 0;
-			basic_rates = 0;
-
-			for (i = 0; i < bssinfo->supported_rates.count; i++) {
-				u16 rate = bssinfo->supported_rates.rates[i];
-				if ((rate & IEEE80211_BASIC_RATE_MASK) == 0)
-					continue;
+			struct sk_buff_head *q =
+				&zd_hw_mac(hw)->ack_wait_queue;
 
-				rate &= ~IEEE80211_BASIC_RATE_MASK;
-				basic_rates |= rate_to_cr_rate(rate);
-			}
+			skb_queue_tail(q, skb);
+			while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS)
+				zd_mac_tx_failed(hw);
 		}
-		spin_lock_irqsave(&mac->lock, flags);
-		mac->basic_rates = basic_rates;
-		spin_unlock_irqrestore(&mac->lock, flags);
-	}
-
-	/* Schedule any changes we made above */
-
-	spin_lock_irqsave(&mac->lock, flags);
-	if (need_set_rts_cts && !mac->updating_rts_rate) {
-		mac->updating_rts_rate = 1;
-		netif_stop_queue(mac->netdev);
-		queue_delayed_work(zd_workqueue, &mac->set_rts_cts_work, 0);
-	}
-	if (need_set_rates && !mac->updating_basic_rates) {
-		mac->updating_basic_rates = 1;
-		netif_stop_queue(mac->netdev);
-		queue_delayed_work(zd_workqueue, &mac->set_basic_rates_work,
-				   0);
-	}
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-static void set_channel(struct net_device *netdev, u8 channel)
-{
-	struct zd_mac *mac = zd_netdev_mac(netdev);
-
-	dev_dbg_f(zd_mac_dev(mac), "channel %d\n", channel);
-
-	zd_chip_set_channel(&mac->chip, channel);
-}
-
-int zd_mac_request_channel(struct zd_mac *mac, u8 channel)
-{
-	unsigned long lock_flags;
-	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-
-	if (ieee->iw_mode == IW_MODE_INFRA)
-		return -EPERM;
-
-	spin_lock_irqsave(&mac->lock, lock_flags);
-	if (!zd_regdomain_supports_channel(mac->regdomain, channel)) {
-		spin_unlock_irqrestore(&mac->lock, lock_flags);
-		return -EINVAL;
-	}
-	mac->requested_channel = channel;
-	spin_unlock_irqrestore(&mac->lock, lock_flags);
-	if (netif_running(mac->netdev))
-		return zd_chip_set_channel(&mac->chip, channel);
-	else
-		return 0;
-}
-
-u8 zd_mac_get_channel(struct zd_mac *mac)
-{
-	u8 channel = zd_chip_get_channel(&mac->chip);
-
-	dev_dbg_f(zd_mac_dev(mac), "channel %u\n", channel);
-	return channel;
-}
-
-int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
-{
-	struct ieee80211_device *ieee;
-
-	switch (mode) {
-	case IW_MODE_AUTO:
-	case IW_MODE_ADHOC:
-	case IW_MODE_INFRA:
-		mac->netdev->type = ARPHRD_ETHER;
-		break;
-	case IW_MODE_MONITOR:
-		mac->netdev->type = ARPHRD_IEEE80211_RADIOTAP;
-		break;
-	default:
-		dev_dbg_f(zd_mac_dev(mac), "wrong mode %u\n", mode);
-		return -EINVAL;
-	}
-
-	ieee = zd_mac_to_ieee80211(mac);
-	ZD_ASSERT(!irqs_disabled());
-	spin_lock_irq(&ieee->lock);
-	ieee->iw_mode = mode;
-	spin_unlock_irq(&ieee->lock);
-
-	if (netif_running(mac->netdev)) {
-		int r = set_rx_filter(mac);
-		if (r)
-			return r;
-		return set_sniffer(mac);
-	}
-
-	return 0;
-}
-
-int zd_mac_get_mode(struct zd_mac *mac, u32 *mode)
-{
-	unsigned long flags;
-	struct ieee80211_device *ieee;
-
-	ieee = zd_mac_to_ieee80211(mac);
-	spin_lock_irqsave(&ieee->lock, flags);
-	*mode = ieee->iw_mode;
-	spin_unlock_irqrestore(&ieee->lock, flags);
-	return 0;
-}
-
-int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range)
-{
-	int i;
-	const struct channel_range *channel_range;
-	u8 regdomain;
-
-	memset(range, 0, sizeof(*range));
-
-	/* FIXME: Not so important and depends on the mode. For 802.11g
-	 * usually this value is used. It seems to be that Bit/s number is
-	 * given here.
-	 */
-	range->throughput = 27 * 1000 * 1000;
-
-	range->max_qual.qual = 100;
-	range->max_qual.level = 100;
-
-	/* FIXME: Needs still to be tuned. */
-	range->avg_qual.qual = 71;
-	range->avg_qual.level = 80;
-
-	/* FIXME: depends on standard? */
-	range->min_rts = 256;
-	range->max_rts = 2346;
-
-	range->min_frag = MIN_FRAG_THRESHOLD;
-	range->max_frag = MAX_FRAG_THRESHOLD;
-
-	range->max_encoding_tokens = WEP_KEYS;
-	range->num_encoding_sizes = 2;
-	range->encoding_size[0] = 5;
-	range->encoding_size[1] = WEP_KEY_LEN;
-
-	range->we_version_compiled = WIRELESS_EXT;
-	range->we_version_source = 20;
-
-	range->enc_capa = IW_ENC_CAPA_WPA |  IW_ENC_CAPA_WPA2 |
-			  IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
-	ZD_ASSERT(!irqs_disabled());
-	spin_lock_irq(&mac->lock);
-	regdomain = mac->regdomain;
-	spin_unlock_irq(&mac->lock);
-	channel_range = zd_channel_range(regdomain);
-
-	range->num_channels = channel_range->end - channel_range->start;
-	range->old_num_channels = range->num_channels;
-	range->num_frequency = range->num_channels;
-	range->old_num_frequency = range->num_frequency;
-
-	for (i = 0; i < range->num_frequency; i++) {
-		struct iw_freq *freq = &range->freq[i];
-		freq->i = channel_range->start + i;
-		zd_channel_to_freq(freq, freq->i);
+	} else {
+		kfree_tx_skb(skb);
 	}
-
-	return 0;
 }
 
 static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
 {
 	/* ZD_PURE_RATE() must be used to remove the modulation type flag of
-	 * the zd-rate values. */
+	 * the zd-rate values.
+	 */
 	static const u8 rate_divisor[] = {
-		[ZD_PURE_RATE(ZD_CCK_RATE_1M)]		=  1,
-		[ZD_PURE_RATE(ZD_CCK_RATE_2M)]		=  2,
-
-		/* bits must be doubled */
-		[ZD_PURE_RATE(ZD_CCK_RATE_5_5M)]	= 11,
-
-		[ZD_PURE_RATE(ZD_CCK_RATE_11M)]		= 11,
-		[ZD_PURE_RATE(ZD_OFDM_RATE_6M)]		=  6,
-		[ZD_PURE_RATE(ZD_OFDM_RATE_9M)]		=  9,
-		[ZD_PURE_RATE(ZD_OFDM_RATE_12M)]	= 12,
-		[ZD_PURE_RATE(ZD_OFDM_RATE_18M)]	= 18,
-		[ZD_PURE_RATE(ZD_OFDM_RATE_24M)]	= 24,
-		[ZD_PURE_RATE(ZD_OFDM_RATE_36M)]	= 36,
-		[ZD_PURE_RATE(ZD_OFDM_RATE_48M)]	= 48,
-		[ZD_PURE_RATE(ZD_OFDM_RATE_54M)]	= 54,
+		[ZD_PURE_RATE(ZD_CCK_RATE_1M)]   =  1,
+		[ZD_PURE_RATE(ZD_CCK_RATE_2M)]	 =  2,
+		/* Bits must be doubled. */
+		[ZD_PURE_RATE(ZD_CCK_RATE_5_5M)] = 11,
+		[ZD_PURE_RATE(ZD_CCK_RATE_11M)]	 = 11,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_6M)]  =  6,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_9M)]  =  9,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_12M)] = 12,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_18M)] = 18,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_24M)] = 24,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_36M)] = 36,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_48M)] = 48,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_54M)] = 54,
 	};
 
 	u32 bits = (u32)tx_length * 8;
@@ -764,34 +451,10 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
 	return bits/divisor;
 }
 
-static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs,
-	                      struct ieee80211_hdr_4addr *hdr)
-{
-	struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
-	u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl));
-	u8 rate;
-	int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0;
-	int is_multicast = is_multicast_ether_addr(hdr->addr1);
-	int short_preamble = ieee80211softmac_short_preamble_ok(softmac,
-		is_multicast, is_mgt);
-
-	rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt);
-	cs->modulation = rate_to_zd_rate(rate);
-
-	/* Set short preamble bit when appropriate */
-	if (short_preamble && ZD_MODULATION_TYPE(cs->modulation) == ZD_CCK
-	    && cs->modulation != ZD_CCK_RATE_1M)
-		cs->modulation |= ZD_CCK_PREA_SHORT;
-}
-
 static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
-	                   struct ieee80211_hdr_4addr *header)
+	                   struct ieee80211_hdr *header, u32 flags)
 {
-	struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
-	unsigned int tx_length = le16_to_cpu(cs->tx_length);
-	u16 fctl = le16_to_cpu(header->frame_ctl);
-	u16 ftype = WLAN_FC_GET_TYPE(fctl);
-	u16 stype = WLAN_FC_GET_STYPE(fctl);
+	u16 fctl = le16_to_cpu(header->frame_control);
 
 	/*
 	 * CONTROL TODO:
@@ -802,7 +465,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
 	cs->control = 0;
 
 	/* First fragment */
-	if (WLAN_GET_SEQ_FRAG(le16_to_cpu(header->seq_ctl)) == 0)
+	if (flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
 		cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
 
 	/* Multicast */
@@ -810,54 +473,37 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
 		cs->control |= ZD_CS_MULTICAST;
 
 	/* PS-POLL */
-	if (ftype == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL)
+	if ((fctl & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) ==
+	    (IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL))
 		cs->control |= ZD_CS_PS_POLL_FRAME;
 
-	/* Unicast data frames over the threshold should have RTS */
-	if (!is_multicast_ether_addr(header->addr1) &&
-	    	ftype != IEEE80211_FTYPE_MGMT &&
-		    tx_length > zd_netdev_ieee80211(mac->netdev)->rts)
+	if (flags & IEEE80211_TXCTL_USE_RTS_CTS)
 		cs->control |= ZD_CS_RTS;
 
-	/* Use CTS-to-self protection if required */
-	if (ZD_MODULATION_TYPE(cs->modulation) == ZD_OFDM &&
-			ieee80211softmac_protection_needed(softmac)) {
-		/* FIXME: avoid sending RTS *and* self-CTS, is that correct? */
-		cs->control &= ~ZD_CS_RTS;
+	if (flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
 		cs->control |= ZD_CS_SELF_CTS;
-	}
 
 	/* FIXME: Management frame? */
 }
 
 static int fill_ctrlset(struct zd_mac *mac,
-	                struct ieee80211_txb *txb,
-			int frag_num)
+			struct sk_buff *skb,
+			struct ieee80211_tx_control *control)
 {
 	int r;
-	struct sk_buff *skb = txb->fragments[frag_num];
-	struct ieee80211_hdr_4addr *hdr =
-		(struct ieee80211_hdr_4addr *) skb->data;
-	unsigned int frag_len = skb->len + IEEE80211_FCS_LEN;
-	unsigned int next_frag_len;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	unsigned int frag_len = skb->len + FCS_LEN;
 	unsigned int packet_length;
 	struct zd_ctrlset *cs = (struct zd_ctrlset *)
 		skb_push(skb, sizeof(struct zd_ctrlset));
 
-	if (frag_num+1  < txb->nr_frags) {
-		next_frag_len = txb->fragments[frag_num+1]->len +
-			        IEEE80211_FCS_LEN;
-	} else {
-		next_frag_len = 0;
-	}
 	ZD_ASSERT(frag_len <= 0xffff);
-	ZD_ASSERT(next_frag_len <= 0xffff);
 
-	cs_set_modulation(mac, cs, hdr);
+	cs->modulation = control->tx_rate;
 
 	cs->tx_length = cpu_to_le16(frag_len);
 
-	cs_set_control(mac, cs, hdr);
+	cs_set_control(mac, cs, hdr, control->flags);
 
 	packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
 	ZD_ASSERT(packet_length <= 0xffff);
@@ -886,419 +532,417 @@ static int fill_ctrlset(struct zd_mac *mac,
 	if (r < 0)
 		return r;
 	cs->current_length = cpu_to_le16(r);
-
-	if (next_frag_len == 0) {
-		cs->next_frame_length = 0;
-	} else {
-		r = zd_calc_tx_length_us(NULL, ZD_RATE(cs->modulation),
-			                 next_frag_len);
-		if (r < 0)
-			return r;
-		cs->next_frame_length = cpu_to_le16(r);
-	}
+	cs->next_frame_length = 0;
 
 	return 0;
 }
 
-static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
+/**
+ * zd_op_tx - transmits a network frame to the device
+ *
+ * @dev: mac80211 hardware device
+ * @skb: socket buffer
+ * @control: the control structure
+ *
+ * This function transmit an IEEE 802.11 network frame to the device. The
+ * control block of the skbuff will be initialized. If necessary the incoming
+ * mac80211 queues will be stopped.
+ */
+static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		     struct ieee80211_tx_control *control)
 {
-	int i, r;
-	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+	struct zd_mac *mac = zd_hw_mac(hw);
+	int r;
 
-	for (i = 0; i < txb->nr_frags; i++) {
-		struct sk_buff *skb = txb->fragments[i];
+	r = fill_ctrlset(mac, skb, control);
+	if (r)
+		return r;
 
-		r = fill_ctrlset(mac, txb, i);
-		if (r) {
-			ieee->stats.tx_dropped++;
-			return r;
-		}
-		r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
-		if (r) {
-			ieee->stats.tx_dropped++;
-			return r;
-		}
+	r = init_tx_skb_control_block(skb, hw, control);
+	if (r)
+		return r;
+	r = zd_usb_tx(&mac->chip.usb, skb);
+	if (r) {
+		clear_tx_skb_control_block(skb);
+		return r;
 	}
-
-	/* FIXME: shouldn't this be handled by the upper layers? */
-	mac->netdev->trans_start = jiffies;
-
-	ieee80211_txb_free(txb);
 	return 0;
 }
 
-struct zd_rt_hdr {
-	struct ieee80211_radiotap_header rt_hdr;
-	u8  rt_flags;
-	u8  rt_rate;
-	u16 rt_channel;
-	u16 rt_chbitmask;
-} __attribute__((packed));
-
-static void fill_rt_header(void *buffer, struct zd_mac *mac,
-	                   const struct ieee80211_rx_stats *stats,
-			   const struct rx_status *status)
-{
-	struct zd_rt_hdr *hdr = buffer;
-
-	hdr->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
-	hdr->rt_hdr.it_pad = 0;
-	hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr));
-	hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
-		                 (1 << IEEE80211_RADIOTAP_CHANNEL) |
-				 (1 << IEEE80211_RADIOTAP_RATE));
-
-	hdr->rt_flags = 0;
-	if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256))
-		hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP;
-
-	hdr->rt_rate = stats->rate / 5;
-
-	/* FIXME: 802.11a */
-	hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz(
-		                             _zd_chip_get_channel(&mac->chip)));
-	hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ |
-		((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) ==
-		ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK));
-}
-
-/* Returns 1 if the data packet is for us and 0 otherwise. */
-static int is_data_packet_for_us(struct ieee80211_device *ieee,
-	                         struct ieee80211_hdr_4addr *hdr)
-{
-	struct net_device *netdev = ieee->dev;
-	u16 fc = le16_to_cpu(hdr->frame_ctl);
-
-	ZD_ASSERT(WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA);
-
-	switch (ieee->iw_mode) {
-	case IW_MODE_ADHOC:
-		if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
-		    compare_ether_addr(hdr->addr3, ieee->bssid) != 0)
-			return 0;
-		break;
-	case IW_MODE_AUTO:
-	case IW_MODE_INFRA:
-		if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
-		    IEEE80211_FCTL_FROMDS ||
-		    compare_ether_addr(hdr->addr2, ieee->bssid) != 0)
-			return 0;
-		break;
-	default:
-		ZD_ASSERT(ieee->iw_mode != IW_MODE_MONITOR);
-		return 0;
-	}
-
-	return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 ||
-	       (is_multicast_ether_addr(hdr->addr1) &&
-		compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) ||
-	       (netdev->flags & IFF_PROMISC);
-}
-
-/* Filters received packets. The function returns 1 if the packet should be
- * forwarded to ieee80211_rx(). If the packet should be ignored the function
- * returns 0. If an invalid packet is found the function returns -EINVAL.
+/**
+ * filter_ack - filters incoming packets for acknowledgements
+ * @dev: the mac80211 device
+ * @rx_hdr: received header
+ * @stats: the status for the received packet
  *
- * The function calls ieee80211_rx_mgt() directly.
+ * This functions looks for ACK packets and tries to match them with the
+ * frames in the tx queue. If a match is found the frame will be dequeued and
+ * the upper layers is informed about the successful transmission. If
+ * mac80211 queues have been stopped and the number of frames still to be
+ * transmitted is low the queues will be opened again.
  *
- * It has been based on ieee80211_rx_any.
+ * Returns 1 if the frame was an ACK, 0 if it was ignored.
  */
-static int filter_rx(struct ieee80211_device *ieee,
-	             const u8 *buffer, unsigned int length,
-		     struct ieee80211_rx_stats *stats)
+static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr,
+		      struct ieee80211_rx_status *stats)
 {
-	struct ieee80211_hdr_4addr *hdr;
-	u16 fc;
-
-	if (ieee->iw_mode == IW_MODE_MONITOR)
-		return 1;
-
-	hdr = (struct ieee80211_hdr_4addr *)buffer;
-	fc = le16_to_cpu(hdr->frame_ctl);
-	if ((fc & IEEE80211_FCTL_VERS) != 0)
-		return -EINVAL;
+	u16 fc = le16_to_cpu(rx_hdr->frame_control);
+	struct sk_buff *skb;
+	struct sk_buff_head *q;
+	unsigned long flags;
 
-	switch (WLAN_FC_GET_TYPE(fc)) {
-	case IEEE80211_FTYPE_MGMT:
-		if (length < sizeof(struct ieee80211_hdr_3addr))
-			return -EINVAL;
-		ieee80211_rx_mgt(ieee, hdr, stats);
-		return 0;
-	case IEEE80211_FTYPE_CTL:
+	if ((fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) !=
+	    (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK))
 		return 0;
-	case IEEE80211_FTYPE_DATA:
-		/* Ignore invalid short buffers */
-		if (length < sizeof(struct ieee80211_hdr_3addr))
-			return -EINVAL;
-		return is_data_packet_for_us(ieee, hdr);
-	}
 
-	return -EINVAL;
+	q = &zd_hw_mac(hw)->ack_wait_queue;
+	spin_lock_irqsave(&q->lock, flags);
+	for (skb = q->next; skb != (struct sk_buff *)q; skb = skb->next) {
+		struct ieee80211_hdr *tx_hdr;
+
+		tx_hdr = (struct ieee80211_hdr *)skb->data;
+		if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1)))
+		{
+			struct ieee80211_tx_status status = {{0}};
+			status.flags = IEEE80211_TX_STATUS_ACK;
+			status.ack_signal = stats->ssi;
+			__skb_unlink(skb, q);
+			tx_status(hw, skb, &status, 1);
+			goto out;
+		}
+	}
+out:
+	spin_unlock_irqrestore(&q->lock, flags);
+	return 1;
 }
 
-static void update_qual_rssi(struct zd_mac *mac,
-			     const u8 *buffer, unsigned int length,
-			     u8 qual_percent, u8 rssi_percent)
+int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
 {
-	unsigned long flags;
-	struct ieee80211_hdr_3addr *hdr;
-	int i;
+	struct zd_mac *mac = zd_hw_mac(hw);
+	struct ieee80211_rx_status stats;
+	const struct rx_status *status;
+	struct sk_buff *skb;
+	int bad_frame = 0;
+	u16 fc;
+	bool is_qos, is_4addr, need_padding;
 
-	hdr = (struct ieee80211_hdr_3addr *)buffer;
-	if (length < offsetof(struct ieee80211_hdr_3addr, addr3))
-		return;
-	if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0)
-		return;
+	if (length < ZD_PLCP_HEADER_SIZE + 10 /* IEEE80211_1ADDR_LEN */ +
+	             FCS_LEN + sizeof(struct rx_status))
+		return -EINVAL;
 
-	spin_lock_irqsave(&mac->lock, flags);
-	i = mac->stats_count % ZD_MAC_STATS_BUFFER_SIZE;
-	mac->qual_buffer[i] = qual_percent;
-	mac->rssi_buffer[i] = rssi_percent;
-	mac->stats_count++;
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
+	memset(&stats, 0, sizeof(stats));
 
-static int fill_rx_stats(struct ieee80211_rx_stats *stats,
-	                 const struct rx_status **pstatus,
-		         struct zd_mac *mac,
-			 const u8 *buffer, unsigned int length)
-{
-	const struct rx_status *status;
+	/* Note about pass_failed_fcs and pass_ctrl access below:
+	 * mac locking intentionally omitted here, as this is the only unlocked
+	 * reader and the only writer is configure_filter. Plus, if there were
+	 * any races accessing these variables, it wouldn't really matter.
+	 * If mac80211 ever provides a way for us to access filter flags
+	 * from outside configure_filter, we could improve on this. Also, this
+	 * situation may change once we implement some kind of DMA-into-skb
+	 * RX path. */
 
-	*pstatus = status = (struct rx_status *)
+	/* Caller has to ensure that length >= sizeof(struct rx_status). */
+	status = (struct rx_status *)
 		(buffer + (length - sizeof(struct rx_status)));
 	if (status->frame_status & ZD_RX_ERROR) {
-		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-		ieee->stats.rx_errors++;
-		if (status->frame_status & ZD_RX_TIMEOUT_ERROR)
-			ieee->stats.rx_missed_errors++;
-		else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR)
-			ieee->stats.rx_fifo_errors++;
-		else if (status->frame_status & ZD_RX_DECRYPTION_ERROR)
-			ieee->ieee_stats.rx_discards_undecryptable++;
-		else if (status->frame_status & ZD_RX_CRC32_ERROR) {
-			ieee->stats.rx_crc_errors++;
-			ieee->ieee_stats.rx_fcs_errors++;
+		if (mac->pass_failed_fcs &&
+				(status->frame_status & ZD_RX_CRC32_ERROR)) {
+			stats.flag |= RX_FLAG_FAILED_FCS_CRC;
+			bad_frame = 1;
+		} else {
+			return -EINVAL;
 		}
-		else if (status->frame_status & ZD_RX_CRC16_ERROR)
-			ieee->stats.rx_crc_errors++;
-		return -EINVAL;
 	}
 
-	memset(stats, 0, sizeof(struct ieee80211_rx_stats));
-	stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
-		               + sizeof(struct rx_status));
-	/* FIXME: 802.11a */
-	stats->freq = IEEE80211_24GHZ_BAND;
-	stats->received_channel = _zd_chip_get_channel(&mac->chip);
-	stats->rssi = zd_rx_strength_percent(status->signal_strength);
-	stats->signal = zd_rx_qual_percent(buffer,
+	stats.channel = _zd_chip_get_channel(&mac->chip);
+	stats.freq = zd_channels[stats.channel - 1].freq;
+	stats.phymode = MODE_IEEE80211G;
+	stats.ssi = status->signal_strength;
+	stats.signal = zd_rx_qual_percent(buffer,
 		                          length - sizeof(struct rx_status),
 		                          status);
-	stats->mask = IEEE80211_STATMASK_RSSI | IEEE80211_STATMASK_SIGNAL;
-	stats->rate = zd_rx_rate(buffer, status);
-	if (stats->rate)
-		stats->mask |= IEEE80211_STATMASK_RATE;
+	stats.rate = zd_rx_rate(buffer, status);
+
+	length -= ZD_PLCP_HEADER_SIZE + sizeof(struct rx_status);
+	buffer += ZD_PLCP_HEADER_SIZE;
+
+	/* Except for bad frames, filter each frame to see if it is an ACK, in
+	 * which case our internal TX tracking is updated. Normally we then
+	 * bail here as there's no need to pass ACKs on up to the stack, but
+	 * there is also the case where the stack has requested us to pass
+	 * control frames on up (pass_ctrl) which we must consider. */
+	if (!bad_frame &&
+			filter_ack(hw, (struct ieee80211_hdr *)buffer, &stats)
+			&& !mac->pass_ctrl)
+		return 0;
 
-	return 0;
-}
+	fc = le16_to_cpu(*((__le16 *) buffer));
 
-static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
-{
-	int r;
-	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-	struct ieee80211_rx_stats stats;
-	const struct rx_status *status;
+	is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+		 ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA);
+	is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+		   (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
+	need_padding = is_qos ^ is_4addr;
 
-	if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
-	               IEEE80211_FCS_LEN + sizeof(struct rx_status))
-	{
-		ieee->stats.rx_errors++;
-		ieee->stats.rx_length_errors++;
-		goto free_skb;
+	skb = dev_alloc_skb(length + (need_padding ? 2 : 0));
+	if (skb == NULL)
+		return -ENOMEM;
+	if (need_padding) {
+		/* Make sure the the payload data is 4 byte aligned. */
+		skb_reserve(skb, 2);
 	}
 
-	r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
-	if (r) {
-		/* Only packets with rx errors are included here.
-		 * The error stats have already been set in fill_rx_stats.
-		 */
-		goto free_skb;
-	}
+	memcpy(skb_put(skb, length), buffer, length);
 
-	__skb_pull(skb, ZD_PLCP_HEADER_SIZE);
-	__skb_trim(skb, skb->len -
-		        (IEEE80211_FCS_LEN + sizeof(struct rx_status)));
+	ieee80211_rx_irqsafe(hw, skb, &stats);
+	return 0;
+}
 
-	ZD_ASSERT(IS_ALIGNED((unsigned long)skb->data, 4));
+static int zd_op_add_interface(struct ieee80211_hw *hw,
+				struct ieee80211_if_init_conf *conf)
+{
+	struct zd_mac *mac = zd_hw_mac(hw);
 
-	update_qual_rssi(mac, skb->data, skb->len, stats.signal,
-		         status->signal_strength);
+	/* using IEEE80211_IF_TYPE_INVALID to indicate no mode selected */
+	if (mac->type != IEEE80211_IF_TYPE_INVALID)
+		return -EOPNOTSUPP;
 
-	r = filter_rx(ieee, skb->data, skb->len, &stats);
-	if (r <= 0) {
-		if (r < 0) {
-			ieee->stats.rx_errors++;
-			dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
-		}
-		goto free_skb;
+	switch (conf->type) {
+	case IEEE80211_IF_TYPE_MNTR:
+	case IEEE80211_IF_TYPE_STA:
+		mac->type = conf->type;
+		break;
+	default:
+		return -EOPNOTSUPP;
 	}
 
-	if (ieee->iw_mode == IW_MODE_MONITOR)
-		fill_rt_header(skb_push(skb, sizeof(struct zd_rt_hdr)), mac,
-			       &stats, status);
-
-	r = ieee80211_rx(ieee, skb, &stats);
-	if (r)
-		return;
-free_skb:
-	/* We are always in a soft irq. */
-	dev_kfree_skb(skb);
+	return zd_write_mac_addr(&mac->chip, conf->mac_addr);
 }
 
-static void do_rx(unsigned long mac_ptr)
+static void zd_op_remove_interface(struct ieee80211_hw *hw,
+				    struct ieee80211_if_init_conf *conf)
 {
-	struct zd_mac *mac = (struct zd_mac *)mac_ptr;
-	struct sk_buff *skb;
+	struct zd_mac *mac = zd_hw_mac(hw);
+	mac->type = IEEE80211_IF_TYPE_INVALID;
+	zd_write_mac_addr(&mac->chip, NULL);
+}
 
-	while ((skb = skb_dequeue(&mac->rx_queue)) != NULL)
-		zd_mac_rx(mac, skb);
+static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+	struct zd_mac *mac = zd_hw_mac(hw);
+	return zd_chip_set_channel(&mac->chip, conf->channel);
 }
 
-int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+static int zd_op_config_interface(struct ieee80211_hw *hw,
+				  struct ieee80211_vif *vif,
+				   struct ieee80211_if_conf *conf)
 {
-	struct sk_buff *skb;
-	unsigned int reserved =
-		ALIGN(max_t(unsigned int,
-		            sizeof(struct zd_rt_hdr), ZD_PLCP_HEADER_SIZE), 4) -
-		ZD_PLCP_HEADER_SIZE;
-
-	skb = dev_alloc_skb(reserved + length);
-	if (!skb) {
-		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-		dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
-		ieee->stats.rx_dropped++;
-		return -ENOMEM;
-	}
-	skb_reserve(skb, reserved);
-	memcpy(__skb_put(skb, length), buffer, length);
-	skb_queue_tail(&mac->rx_queue, skb);
-	tasklet_schedule(&mac->rx_tasklet);
+	struct zd_mac *mac = zd_hw_mac(hw);
+
+	spin_lock_irq(&mac->lock);
+	mac->associated = is_valid_ether_addr(conf->bssid);
+	spin_unlock_irq(&mac->lock);
+
+	/* TODO: do hardware bssid filtering */
 	return 0;
 }
 
-static int netdev_tx(struct ieee80211_txb *txb, struct net_device *netdev,
-		     int pri)
+static void set_multicast_hash_handler(struct work_struct *work)
 {
-	return zd_mac_tx(zd_netdev_mac(netdev), txb, pri);
+	struct zd_mac *mac =
+		container_of(work, struct zd_mac, set_multicast_hash_work);
+	struct zd_mc_hash hash;
+
+	spin_lock_irq(&mac->lock);
+	hash = mac->multicast_hash;
+	spin_unlock_irq(&mac->lock);
+
+	zd_chip_set_multicast_hash(&mac->chip, &hash);
 }
 
-static void set_security(struct net_device *netdev,
-			 struct ieee80211_security *sec)
+static void set_rx_filter_handler(struct work_struct *work)
 {
-	struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
-	struct ieee80211_security *secinfo = &ieee->sec;
-	int keyidx;
-
-	dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
-
-	for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
-		if (sec->flags & (1<<keyidx)) {
-			secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
-			secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
-			memcpy(secinfo->keys[keyidx], sec->keys[keyidx],
-			       SCM_KEY_LEN);
-		}
+	struct zd_mac *mac =
+		container_of(work, struct zd_mac, set_rx_filter_work);
+	int r;
 
-	if (sec->flags & SEC_ACTIVE_KEY) {
-		secinfo->active_key = sec->active_key;
-		dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
-			"   .active_key = %d\n", sec->active_key);
-	}
-	if (sec->flags & SEC_UNICAST_GROUP) {
-		secinfo->unicast_uses_group = sec->unicast_uses_group;
-		dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
-			"   .unicast_uses_group = %d\n",
-			sec->unicast_uses_group);
-	}
-	if (sec->flags & SEC_LEVEL) {
-		secinfo->level = sec->level;
-		dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
-			"   .level = %d\n", sec->level);
-	}
-	if (sec->flags & SEC_ENABLED) {
-		secinfo->enabled = sec->enabled;
-		dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
-			"   .enabled = %d\n", sec->enabled);
-	}
-	if (sec->flags & SEC_ENCRYPT) {
-		secinfo->encrypt = sec->encrypt;
-		dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
-			"   .encrypt = %d\n", sec->encrypt);
-	}
-	if (sec->flags & SEC_AUTH_MODE) {
-		secinfo->auth_mode = sec->auth_mode;
-		dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
-			"   .auth_mode = %d\n", sec->auth_mode);
+	dev_dbg_f(zd_mac_dev(mac), "\n");
+	r = set_rx_filter(mac);
+	if (r)
+		dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r);
+}
+
+#define SUPPORTED_FIF_FLAGS \
+	(FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \
+	FIF_OTHER_BSS)
+static void zd_op_configure_filter(struct ieee80211_hw *hw,
+			unsigned int changed_flags,
+			unsigned int *new_flags,
+			int mc_count, struct dev_mc_list *mclist)
+{
+	struct zd_mc_hash hash;
+	struct zd_mac *mac = zd_hw_mac(hw);
+	unsigned long flags;
+	int i;
+
+	/* Only deal with supported flags */
+	changed_flags &= SUPPORTED_FIF_FLAGS;
+	*new_flags &= SUPPORTED_FIF_FLAGS;
+
+	/* changed_flags is always populated but this driver
+	 * doesn't support all FIF flags so its possible we don't
+	 * need to do anything */
+	if (!changed_flags)
+		return;
+
+	if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) {
+		zd_mc_add_all(&hash);
+	} else {
+		DECLARE_MAC_BUF(macbuf);
+
+		zd_mc_clear(&hash);
+		for (i = 0; i < mc_count; i++) {
+			if (!mclist)
+				break;
+			dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n",
+				  print_mac(macbuf, mclist->dmi_addr));
+			zd_mc_add_addr(&hash, mclist->dmi_addr);
+			mclist = mclist->next;
+		}
 	}
+
+	spin_lock_irqsave(&mac->lock, flags);
+	mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL);
+	mac->pass_ctrl = !!(*new_flags & FIF_CONTROL);
+	mac->multicast_hash = hash;
+	spin_unlock_irqrestore(&mac->lock, flags);
+	queue_work(zd_workqueue, &mac->set_multicast_hash_work);
+
+	if (changed_flags & FIF_CONTROL)
+		queue_work(zd_workqueue, &mac->set_rx_filter_work);
+
+	/* no handling required for FIF_OTHER_BSS as we don't currently
+	 * do BSSID filtering */
+	/* FIXME: in future it would be nice to enable the probe response
+	 * filter (so that the driver doesn't see them) until
+	 * FIF_BCN_PRBRESP_PROMISC is set. however due to atomicity here, we'd
+	 * have to schedule work to enable prbresp reception, which might
+	 * happen too late. For now we'll just listen and forward them all the
+	 * time. */
 }
 
-static void ieee_init(struct ieee80211_device *ieee)
+static void set_rts_cts_work(struct work_struct *work)
 {
-	ieee->mode = IEEE_B | IEEE_G;
-	ieee->freq_band = IEEE80211_24GHZ_BAND;
-	ieee->modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION;
-	ieee->tx_headroom = sizeof(struct zd_ctrlset);
-	ieee->set_security = set_security;
-	ieee->hard_start_xmit = netdev_tx;
-
-	/* Software encryption/decryption for now */
-	ieee->host_build_iv = 0;
-	ieee->host_encrypt = 1;
-	ieee->host_decrypt = 1;
-
-	/* FIXME: default to managed mode, until ieee80211 and zd1211rw can
-	 * correctly support AUTO */
-	ieee->iw_mode = IW_MODE_INFRA;
+	struct zd_mac *mac =
+		container_of(work, struct zd_mac, set_rts_cts_work);
+	unsigned long flags;
+	unsigned int short_preamble;
+
+	mutex_lock(&mac->chip.mutex);
+
+	spin_lock_irqsave(&mac->lock, flags);
+	mac->updating_rts_rate = 0;
+	short_preamble = mac->short_preamble;
+	spin_unlock_irqrestore(&mac->lock, flags);
+
+	zd_chip_set_rts_cts_rate_locked(&mac->chip, short_preamble);
+	mutex_unlock(&mac->chip.mutex);
 }
 
-static void softmac_init(struct ieee80211softmac_device *sm)
+static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif,
+				   struct ieee80211_bss_conf *bss_conf,
+				   u32 changes)
 {
-	sm->set_channel = set_channel;
-	sm->bssinfo_change = bssinfo_change;
+	struct zd_mac *mac = zd_hw_mac(hw);
+	unsigned long flags;
+
+	dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes);
+
+	if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+		spin_lock_irqsave(&mac->lock, flags);
+		mac->short_preamble = bss_conf->use_short_preamble;
+		if (!mac->updating_rts_rate) {
+			mac->updating_rts_rate = 1;
+			/* FIXME: should disable TX here, until work has
+			 * completed and RTS_CTS reg is updated */
+			queue_work(zd_workqueue, &mac->set_rts_cts_work);
+		}
+		spin_unlock_irqrestore(&mac->lock, flags);
+	}
 }
 
-struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev)
+static const struct ieee80211_ops zd_ops = {
+	.tx			= zd_op_tx,
+	.start			= zd_op_start,
+	.stop			= zd_op_stop,
+	.add_interface		= zd_op_add_interface,
+	.remove_interface	= zd_op_remove_interface,
+	.config			= zd_op_config,
+	.config_interface	= zd_op_config_interface,
+	.configure_filter	= zd_op_configure_filter,
+	.bss_info_changed	= zd_op_bss_info_changed,
+};
+
+struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
 {
-	struct zd_mac *mac = zd_netdev_mac(ndev);
-	struct iw_statistics *iw_stats = &mac->iw_stats;
-	unsigned int i, count, qual_total, rssi_total;
+	struct zd_mac *mac;
+	struct ieee80211_hw *hw;
+	int i;
 
-	memset(iw_stats, 0, sizeof(struct iw_statistics));
-	/* We are not setting the status, because ieee->state is not updated
-	 * at all and this driver doesn't track authentication state.
-	 */
-	spin_lock_irq(&mac->lock);
-	count = mac->stats_count < ZD_MAC_STATS_BUFFER_SIZE ?
-		mac->stats_count : ZD_MAC_STATS_BUFFER_SIZE;
-	qual_total = rssi_total = 0;
-	for (i = 0; i < count; i++) {
-		qual_total += mac->qual_buffer[i];
-		rssi_total += mac->rssi_buffer[i];
+	hw = ieee80211_alloc_hw(sizeof(struct zd_mac), &zd_ops);
+	if (!hw) {
+		dev_dbg_f(&intf->dev, "out of memory\n");
+		return NULL;
 	}
-	spin_unlock_irq(&mac->lock);
-	iw_stats->qual.updated = IW_QUAL_NOISE_INVALID;
-	if (count > 0) {
-		iw_stats->qual.qual = qual_total / count;
-		iw_stats->qual.level = rssi_total / count;
-		iw_stats->qual.updated |=
-			IW_QUAL_QUAL_UPDATED|IW_QUAL_LEVEL_UPDATED;
-	} else {
-		iw_stats->qual.updated |=
-			IW_QUAL_QUAL_INVALID|IW_QUAL_LEVEL_INVALID;
+
+	mac = zd_hw_mac(hw);
+
+	memset(mac, 0, sizeof(*mac));
+	spin_lock_init(&mac->lock);
+	mac->hw = hw;
+
+	mac->type = IEEE80211_IF_TYPE_INVALID;
+
+	memcpy(mac->channels, zd_channels, sizeof(zd_channels));
+	memcpy(mac->rates, zd_rates, sizeof(zd_rates));
+	mac->modes[0].mode = MODE_IEEE80211G;
+	mac->modes[0].num_rates = ARRAY_SIZE(zd_rates);
+	mac->modes[0].rates = mac->rates;
+	mac->modes[0].num_channels = ARRAY_SIZE(zd_channels);
+	mac->modes[0].channels = mac->channels;
+	mac->modes[1].mode = MODE_IEEE80211B;
+	mac->modes[1].num_rates = 4;
+	mac->modes[1].rates = mac->rates;
+	mac->modes[1].num_channels = ARRAY_SIZE(zd_channels);
+	mac->modes[1].channels = mac->channels;
+
+	hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+		     IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED;
+	hw->max_rssi = 100;
+	hw->max_signal = 100;
+
+	hw->queues = 1;
+	hw->extra_tx_headroom = sizeof(struct zd_ctrlset);
+
+	skb_queue_head_init(&mac->ack_wait_queue);
+
+	for (i = 0; i < 2; i++) {
+		if (ieee80211_register_hwmode(hw, &mac->modes[i])) {
+			dev_dbg_f(&intf->dev, "cannot register hwmode\n");
+			ieee80211_free_hw(hw);
+			return NULL;
+		}
 	}
-	/* TODO: update counter */
-	return iw_stats;
+
+	zd_chip_init(&mac->chip, hw, intf);
+	housekeeping_init(mac);
+	INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler);
+	INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
+	INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler);
+
+	SET_IEEE80211_DEV(hw, &intf->dev);
+	return hw;
 }
 
 #define LINK_LED_WORK_DELAY HZ
@@ -1308,18 +952,17 @@ static void link_led_handler(struct work_struct *work)
 	struct zd_mac *mac =
 		container_of(work, struct zd_mac, housekeeping.link_led_work.work);
 	struct zd_chip *chip = &mac->chip;
-	struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev);
 	int is_associated;
 	int r;
 
 	spin_lock_irq(&mac->lock);
-	is_associated = sm->associnfo.associated != 0;
+	is_associated = mac->associated;
 	spin_unlock_irq(&mac->lock);
 
 	r = zd_chip_control_leds(chip,
 		                 is_associated ? LED_ASSOCIATED : LED_SCANNING);
 	if (r)
-		dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r);
+		dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r);
 
 	queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
 		           LINK_LED_WORK_DELAY);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 1b15bde3ff60..2dde108df767 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -1,4 +1,7 @@
-/* zd_mac.h
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
@@ -18,14 +21,11 @@
 #ifndef _ZD_MAC_H
 #define _ZD_MAC_H
 
-#include <linux/wireless.h>
 #include <linux/kernel.h>
-#include <linux/workqueue.h>
-#include <net/ieee80211.h>
-#include <net/ieee80211softmac.h>
+#include <net/mac80211.h>
 
 #include "zd_chip.h"
-#include "zd_netdev.h"
+#include "zd_ieee80211.h"
 
 struct zd_ctrlset {
 	u8     modulation;
@@ -57,7 +57,7 @@ struct zd_ctrlset {
 /* The two possible modulation types. Notify that 802.11b doesn't use the CCK
  * codeing for the 1 and 2 MBit/s rate. We stay with the term here to remain
  * consistent with uses the term at other places.
-  */
+ */
 #define ZD_CCK                  0x00
 #define ZD_OFDM                 0x10
 
@@ -141,58 +141,68 @@ struct rx_status {
 #define ZD_RX_CRC16_ERROR		0x40
 #define ZD_RX_ERROR			0x80
 
+enum mac_flags {
+	MAC_FIXED_CHANNEL = 0x01,
+};
+
 struct housekeeping {
 	struct delayed_work link_led_work;
 };
 
+/**
+ * struct zd_tx_skb_control_block - control block for tx skbuffs
+ * @control: &struct ieee80211_tx_control pointer
+ * @context: context pointer
+ *
+ * This structure is used to fill the cb field in an &sk_buff to transmit.
+ * The control field is NULL, if there is no requirement from the mac80211
+ * stack to report about the packet ACK. This is the case if the flag
+ * IEEE80211_TXCTL_NO_ACK is not set in &struct ieee80211_tx_control.
+ */
+struct zd_tx_skb_control_block {
+	struct ieee80211_tx_control *control;
+	struct ieee80211_hw *hw;
+	void *context;
+};
+
 #define ZD_MAC_STATS_BUFFER_SIZE 16
 
+#define ZD_MAC_MAX_ACK_WAITERS 10
+
 struct zd_mac {
 	struct zd_chip chip;
 	spinlock_t lock;
-	struct net_device *netdev;
-
-	/* Unlocked reading possible */
-	struct iw_statistics iw_stats;
-
+	struct ieee80211_hw *hw;
 	struct housekeeping housekeeping;
 	struct work_struct set_multicast_hash_work;
+	struct work_struct set_rts_cts_work;
+	struct work_struct set_rx_filter_work;
 	struct zd_mc_hash multicast_hash;
-	struct delayed_work set_rts_cts_work;
-	struct delayed_work set_basic_rates_work;
-
-	struct tasklet_struct rx_tasklet;
-	struct sk_buff_head rx_queue;
-
-	unsigned int stats_count;
-	u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
-	u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE];
 	u8 regdomain;
 	u8 default_regdomain;
-	u8 requested_channel;
-
-	/* A bitpattern of cr_rates */
-	u16 basic_rates;
-
-	/* A zd_rate */
-	u8 rts_rate;
+	int type;
+	int associated;
+	struct sk_buff_head ack_wait_queue;
+	struct ieee80211_channel channels[14];
+	struct ieee80211_rate rates[12];
+	struct ieee80211_hw_mode modes[2];
 
 	/* Short preamble (used for RTS/CTS) */
 	unsigned int short_preamble:1;
 
 	/* flags to indicate update in progress */
 	unsigned int updating_rts_rate:1;
-	unsigned int updating_basic_rates:1;
-};
 
-static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac)
-{
-	return zd_netdev_ieee80211(mac->netdev);
-}
+	/* whether to pass frames with CRC errors to stack */
+	unsigned int pass_failed_fcs:1;
 
-static inline struct zd_mac *zd_netdev_mac(struct net_device *netdev)
+	/* whether to pass control frames to stack */
+	unsigned int pass_ctrl:1;
+};
+
+static inline struct zd_mac *zd_hw_mac(struct ieee80211_hw *hw)
 {
-	return ieee80211softmac_priv(netdev);
+	return hw->priv;
 }
 
 static inline struct zd_mac *zd_chip_to_mac(struct zd_chip *chip)
@@ -205,35 +215,22 @@ static inline struct zd_mac *zd_usb_to_mac(struct zd_usb *usb)
 	return zd_chip_to_mac(zd_usb_to_chip(usb));
 }
 
+static inline u8 *zd_mac_get_perm_addr(struct zd_mac *mac)
+{
+	return mac->hw->wiphy->perm_addr;
+}
+
 #define zd_mac_dev(mac) (zd_chip_dev(&(mac)->chip))
 
-int zd_mac_init(struct zd_mac *mac,
-                struct net_device *netdev,
-		struct usb_interface *intf);
+struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf);
 void zd_mac_clear(struct zd_mac *mac);
 
-int zd_mac_preinit_hw(struct zd_mac *mac);
-int zd_mac_init_hw(struct zd_mac *mac);
-
-int zd_mac_open(struct net_device *netdev);
-int zd_mac_stop(struct net_device *netdev);
-int zd_mac_set_mac_address(struct net_device *dev, void *p);
-void zd_mac_set_multicast_list(struct net_device *netdev);
-
-int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length);
-
-int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain);
-u8 zd_mac_get_regdomain(struct zd_mac *zd_mac);
-
-int zd_mac_request_channel(struct zd_mac *mac, u8 channel);
-u8 zd_mac_get_channel(struct zd_mac *mac);
-
-int zd_mac_set_mode(struct zd_mac *mac, u32 mode);
-int zd_mac_get_mode(struct zd_mac *mac, u32 *mode);
-
-int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range);
+int zd_mac_preinit_hw(struct ieee80211_hw *hw);
+int zd_mac_init_hw(struct ieee80211_hw *hw);
 
-struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev);
+int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length);
+void zd_mac_tx_failed(struct ieee80211_hw *hw);
+void zd_mac_tx_to_dev(struct sk_buff *skb, int error);
 
 #ifdef DEBUG
 void zd_dump_rx_status(const struct rx_status *status);
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
deleted file mode 100644
index 047cab3d87df..000000000000
--- a/drivers/net/wireless/zd1211rw/zd_netdev.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/* zd_netdev.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
- */
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <net/ieee80211.h>
-#include <net/ieee80211softmac.h>
-#include <net/ieee80211softmac_wx.h>
-#include <net/iw_handler.h>
-
-#include "zd_def.h"
-#include "zd_netdev.h"
-#include "zd_mac.h"
-#include "zd_ieee80211.h"
-
-/* Region 0 means reset regdomain to default. */
-static int zd_set_regdomain(struct net_device *netdev,
-	                    struct iw_request_info *info,
-			    union iwreq_data *req, char *extra)
-{
-	const u8 *regdomain = (u8 *)req;
-	return zd_mac_set_regdomain(zd_netdev_mac(netdev), *regdomain);
-}
-
-static int zd_get_regdomain(struct net_device *netdev,
-	                    struct iw_request_info *info,
-			    union iwreq_data *req, char *extra)
-{
-	u8 *regdomain = (u8 *)req;
-	if (!regdomain)
-		return -EINVAL;
-	*regdomain = zd_mac_get_regdomain(zd_netdev_mac(netdev));
-	return 0;
-}
-
-static const struct iw_priv_args zd_priv_args[] = {
-	{
-		.cmd = ZD_PRIV_SET_REGDOMAIN,
-		.set_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-		.name = "set_regdomain",
-	},
-	{
-		.cmd = ZD_PRIV_GET_REGDOMAIN,
-		.get_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
-		.name = "get_regdomain",
-	},
-};
-
-#define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV]
-
-static const iw_handler zd_priv_handler[] = {
-	PRIV_OFFSET(ZD_PRIV_SET_REGDOMAIN) = zd_set_regdomain,
-	PRIV_OFFSET(ZD_PRIV_GET_REGDOMAIN) = zd_get_regdomain,
-};
-
-static int iw_get_name(struct net_device *netdev,
-	               struct iw_request_info *info,
-		       union iwreq_data *req, char *extra)
-{
-	/* FIXME: check whether 802.11a will also supported */
-	strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
-	return 0;
-}
-
-static int iw_get_nick(struct net_device *netdev,
-	               struct iw_request_info *info,
-		       union iwreq_data *req, char *extra)
-{
-	strcpy(extra, "zd1211");
-	req->data.length = strlen(extra);
-	req->data.flags = 1;
-	return 0;
-}
-
-static int iw_set_freq(struct net_device *netdev,
-	               struct iw_request_info *info,
-		       union iwreq_data *req, char *extra)
-{
-	int r;
-	struct zd_mac *mac = zd_netdev_mac(netdev);
-	struct iw_freq *freq = &req->freq;
-	u8 channel;
-
-	r = zd_find_channel(&channel, freq);
-	if (r < 0)
-		return r;
-	r = zd_mac_request_channel(mac, channel);
-	return r;
-}
-
-static int iw_get_freq(struct net_device *netdev,
-	           struct iw_request_info *info,
-		   union iwreq_data *req, char *extra)
-{
-	struct zd_mac *mac = zd_netdev_mac(netdev);
-	struct iw_freq *freq = &req->freq;
-
-	return zd_channel_to_freq(freq, zd_mac_get_channel(mac));
-}
-
-static int iw_set_mode(struct net_device *netdev,
-	               struct iw_request_info *info,
-		       union iwreq_data *req, char *extra)
-{
-	return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode);
-}
-
-static int iw_get_mode(struct net_device *netdev,
-	               struct iw_request_info *info,
-		       union iwreq_data *req, char *extra)
-{
-	return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode);
-}
-
-static int iw_get_range(struct net_device *netdev,
-	               struct iw_request_info *info,
-		       union iwreq_data *req, char *extra)
-{
-	struct iw_range *range = (struct iw_range *)extra;
-
-	dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
-	req->data.length = sizeof(*range);
-	return zd_mac_get_range(zd_netdev_mac(netdev), range);
-}
-
-static int iw_set_encode(struct net_device *netdev,
-			 struct iw_request_info *info,
-			 union iwreq_data *data,
-			 char *extra)
-{
-	return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info,
-		data, extra);
-}
-
-static int iw_get_encode(struct net_device *netdev,
-			 struct iw_request_info *info,
-			 union iwreq_data *data,
-			 char *extra)
-{
-	return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info,
-		data, extra);
-}
-
-static int iw_set_encodeext(struct net_device *netdev,
-			 struct iw_request_info *info,
-			 union iwreq_data *data,
-			 char *extra)
-{
-	return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info,
-		data, extra);
-}
-
-static int iw_get_encodeext(struct net_device *netdev,
-			 struct iw_request_info *info,
-			 union iwreq_data *data,
-			 char *extra)
-{
-	return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info,
-		data, extra);
-}
-
-#define WX(x) [(x)-SIOCIWFIRST]
-
-static const iw_handler zd_standard_iw_handlers[] = {
-	WX(SIOCGIWNAME)		= iw_get_name,
-	WX(SIOCGIWNICKN)	= iw_get_nick,
-	WX(SIOCSIWFREQ)		= iw_set_freq,
-	WX(SIOCGIWFREQ)		= iw_get_freq,
-	WX(SIOCSIWMODE)		= iw_set_mode,
-	WX(SIOCGIWMODE)		= iw_get_mode,
-	WX(SIOCGIWRANGE)	= iw_get_range,
-	WX(SIOCSIWENCODE)	= iw_set_encode,
-	WX(SIOCGIWENCODE)	= iw_get_encode,
-	WX(SIOCSIWENCODEEXT)	= iw_set_encodeext,
-	WX(SIOCGIWENCODEEXT)	= iw_get_encodeext,
-	WX(SIOCSIWAUTH)		= ieee80211_wx_set_auth,
-	WX(SIOCGIWAUTH)		= ieee80211_wx_get_auth,
-	WX(SIOCSIWSCAN)		= ieee80211softmac_wx_trigger_scan,
-	WX(SIOCGIWSCAN)		= ieee80211softmac_wx_get_scan_results,
-	WX(SIOCSIWESSID)	= ieee80211softmac_wx_set_essid,
-	WX(SIOCGIWESSID)	= ieee80211softmac_wx_get_essid,
-	WX(SIOCSIWAP)		= ieee80211softmac_wx_set_wap,
-	WX(SIOCGIWAP)		= ieee80211softmac_wx_get_wap,
-	WX(SIOCSIWRATE)		= ieee80211softmac_wx_set_rate,
-	WX(SIOCGIWRATE)		= ieee80211softmac_wx_get_rate,
-	WX(SIOCSIWGENIE)	= ieee80211softmac_wx_set_genie,
-	WX(SIOCGIWGENIE)	= ieee80211softmac_wx_get_genie,
-	WX(SIOCSIWMLME)		= ieee80211softmac_wx_set_mlme,
-};
-
-static const struct iw_handler_def iw_handler_def = {
-	.standard		= zd_standard_iw_handlers,
-	.num_standard		= ARRAY_SIZE(zd_standard_iw_handlers),
-	.private		= zd_priv_handler,
-	.num_private		= ARRAY_SIZE(zd_priv_handler),
-	.private_args		= zd_priv_args,
-	.num_private_args	= ARRAY_SIZE(zd_priv_args),
-	.get_wireless_stats	= zd_mac_get_wireless_stats,
-};
-
-struct net_device *zd_netdev_alloc(struct usb_interface *intf)
-{
-	int r;
-	struct net_device *netdev;
-	struct zd_mac *mac;
-
-	netdev = alloc_ieee80211softmac(sizeof(struct zd_mac));
-	if (!netdev) {
-		dev_dbg_f(&intf->dev, "out of memory\n");
-		return NULL;
-	}
-
-	mac = zd_netdev_mac(netdev);
-	r = zd_mac_init(mac, netdev, intf);
-	if (r) {
-		usb_set_intfdata(intf, NULL);
-		free_ieee80211(netdev);
-		return NULL;
-	}
-
-	SET_NETDEV_DEV(netdev, &intf->dev);
-
-	dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
-	dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features);
-
-	netdev->open = zd_mac_open;
-	netdev->stop = zd_mac_stop;
-	/* netdev->get_stats = */
-	netdev->set_multicast_list = zd_mac_set_multicast_list;
-	netdev->set_mac_address = zd_mac_set_mac_address;
-	netdev->wireless_handlers = &iw_handler_def;
-	/* netdev->ethtool_ops = */
-
-	return netdev;
-}
-
-void zd_netdev_free(struct net_device *netdev)
-{
-	if (!netdev)
-		return;
-
-	zd_mac_clear(zd_netdev_mac(netdev));
-	free_ieee80211(netdev);
-}
-
-void zd_netdev_disconnect(struct net_device *netdev)
-{
-	unregister_netdev(netdev);
-}
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.h b/drivers/net/wireless/zd1211rw/zd_netdev.h
deleted file mode 100644
index 374a957073c1..000000000000
--- a/drivers/net/wireless/zd1211rw/zd_netdev.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* zd_netdev.h: Header for net device related functions.
- *
- * 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 _ZD_NETDEV_H
-#define _ZD_NETDEV_H
-
-#include <linux/usb.h>
-#include <linux/netdevice.h>
-#include <net/ieee80211.h>
-
-#define ZD_PRIV_SET_REGDOMAIN (SIOCIWFIRSTPRIV)
-#define ZD_PRIV_GET_REGDOMAIN (SIOCIWFIRSTPRIV+1)
-
-static inline struct ieee80211_device *zd_netdev_ieee80211(
-	struct net_device *ndev)
-{
-	return netdev_priv(ndev);
-}
-
-static inline struct net_device *zd_ieee80211_to_netdev(
-	struct ieee80211_device *ieee)
-{
-	return ieee->dev;
-}
-
-struct net_device *zd_netdev_alloc(struct usb_interface *intf);
-void zd_netdev_free(struct net_device *netdev);
-
-void zd_netdev_disconnect(struct net_device *netdev);
-
-#endif /* _ZD_NETDEV_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index abe5d38f7f4d..ec4129312813 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -1,4 +1,7 @@
-/* zd_rf.c
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index 30502f26b71c..79dc1035592d 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -1,4 +1,7 @@
-/* zd_rf.h
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 006774de3202..74a8f7a55591 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -1,4 +1,7 @@
-/* zd_rf_al2230.c: Functions for the AL2230 RF controller
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
index 73d0bb26f810..65095d661e6b 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -1,4 +1,7 @@
-/* zd_rf_al7230b.c: Functions for the AL7230B RF controller
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
index cc70d40684ea..0597d862fbd2 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -1,4 +1,7 @@
-/* zd_rf_rfmd.c: Functions for the RFMD RF controller
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
index 857dcf3eae61..439799b84876 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
@@ -1,4 +1,7 @@
-/* zd_rf_uw2453.c: Functions for the UW2453 RF controller
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
@@ -403,7 +406,7 @@ static int uw2453_init_hw(struct zd_rf *rf)
 		if (r)
 			return r;
 
-		if (!intr_status & 0xf) {
+		if (!(intr_status & 0xf)) {
 			dev_dbg_f(zd_chip_dev(chip),
 				"PLL locked on configuration %d\n", i);
 			found_config = i;
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index c755b6923812..7942b15acfe7 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -1,4 +1,8 @@
-/* zd_usb.c
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright (C) 2006-2007 Michael Wu <flamingice@sourmilk.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,18 +21,16 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/skbuff.h>
 #include <linux/usb.h>
 #include <linux/workqueue.h>
-#include <net/ieee80211.h>
+#include <net/mac80211.h>
 #include <asm/unaligned.h>
 
 #include "zd_def.h"
-#include "zd_netdev.h"
 #include "zd_mac.h"
 #include "zd_usb.h"
 
@@ -55,6 +57,7 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -353,18 +356,6 @@ out:
 	spin_unlock(&intr->lock);
 }
 
-static inline void handle_retry_failed_int(struct urb *urb)
-{
-	struct zd_usb *usb = urb->context;
-	struct zd_mac *mac = zd_usb_to_mac(usb);
-	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-
-	ieee->stats.tx_errors++;
-	ieee->ieee_stats.tx_retry_limit_exceeded++;
-	dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
-}
-
-
 static void int_urb_complete(struct urb *urb)
 {
 	int r;
@@ -400,7 +391,7 @@ static void int_urb_complete(struct urb *urb)
 		handle_regs_int(urb);
 		break;
 	case USB_INT_ID_RETRY_FAILED:
-		handle_retry_failed_int(urb);
+		zd_mac_tx_failed(zd_usb_to_hw(urb->context));
 		break;
 	default:
 		dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,
@@ -530,14 +521,10 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
 			     unsigned int length)
 {
 	int i;
-	struct zd_mac *mac = zd_usb_to_mac(usb);
 	const struct rx_length_info *length_info;
 
 	if (length < sizeof(struct rx_length_info)) {
 		/* It's not a complete packet anyhow. */
-		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
-		ieee->stats.rx_errors++;
-		ieee->stats.rx_length_errors++;
 		return;
 	}
 	length_info = (struct rx_length_info *)
@@ -561,13 +548,13 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
 			n = l+k;
 			if (n > length)
 				return;
-			zd_mac_rx_irq(mac, buffer+l, k);
+			zd_mac_rx(zd_usb_to_hw(usb), buffer+l, k);
 			if (i >= 2)
 				return;
 			l = (n+3) & ~3;
 		}
 	} else {
-		zd_mac_rx_irq(mac, buffer, length);
+		zd_mac_rx(zd_usb_to_hw(usb), buffer, length);
 	}
 }
 
@@ -629,7 +616,7 @@ resubmit:
 	usb_submit_urb(urb, GFP_ATOMIC);
 }
 
-static struct urb *alloc_urb(struct zd_usb *usb)
+static struct urb *alloc_rx_urb(struct zd_usb *usb)
 {
 	struct usb_device *udev = zd_usb_to_usbdev(usb);
 	struct urb *urb;
@@ -653,7 +640,7 @@ static struct urb *alloc_urb(struct zd_usb *usb)
 	return urb;
 }
 
-static void free_urb(struct urb *urb)
+static void free_rx_urb(struct urb *urb)
 {
 	if (!urb)
 		return;
@@ -671,11 +658,11 @@ int zd_usb_enable_rx(struct zd_usb *usb)
 	dev_dbg_f(zd_usb_dev(usb), "\n");
 
 	r = -ENOMEM;
-	urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
+	urbs = kcalloc(RX_URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
 	if (!urbs)
 		goto error;
-	for (i = 0; i < URBS_COUNT; i++) {
-		urbs[i] = alloc_urb(usb);
+	for (i = 0; i < RX_URBS_COUNT; i++) {
+		urbs[i] = alloc_rx_urb(usb);
 		if (!urbs[i])
 			goto error;
 	}
@@ -688,10 +675,10 @@ int zd_usb_enable_rx(struct zd_usb *usb)
 		goto error;
 	}
 	rx->urbs = urbs;
-	rx->urbs_count = URBS_COUNT;
+	rx->urbs_count = RX_URBS_COUNT;
 	spin_unlock_irq(&rx->lock);
 
-	for (i = 0; i < URBS_COUNT; i++) {
+	for (i = 0; i < RX_URBS_COUNT; i++) {
 		r = usb_submit_urb(urbs[i], GFP_KERNEL);
 		if (r)
 			goto error_submit;
@@ -699,7 +686,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
 
 	return 0;
 error_submit:
-	for (i = 0; i < URBS_COUNT; i++) {
+	for (i = 0; i < RX_URBS_COUNT; i++) {
 		usb_kill_urb(urbs[i]);
 	}
 	spin_lock_irq(&rx->lock);
@@ -708,8 +695,8 @@ error_submit:
 	spin_unlock_irq(&rx->lock);
 error:
 	if (urbs) {
-		for (i = 0; i < URBS_COUNT; i++)
-			free_urb(urbs[i]);
+		for (i = 0; i < RX_URBS_COUNT; i++)
+			free_rx_urb(urbs[i]);
 	}
 	return r;
 }
@@ -731,7 +718,7 @@ void zd_usb_disable_rx(struct zd_usb *usb)
 
 	for (i = 0; i < count; i++) {
 		usb_kill_urb(urbs[i]);
-		free_urb(urbs[i]);
+		free_rx_urb(urbs[i]);
 	}
 	kfree(urbs);
 
@@ -741,9 +728,142 @@ void zd_usb_disable_rx(struct zd_usb *usb)
 	spin_unlock_irqrestore(&rx->lock, flags);
 }
 
+/**
+ * zd_usb_disable_tx - disable transmission
+ * @usb: the zd1211rw-private USB structure
+ *
+ * Frees all URBs in the free list and marks the transmission as disabled.
+ */
+void zd_usb_disable_tx(struct zd_usb *usb)
+{
+	struct zd_usb_tx *tx = &usb->tx;
+	unsigned long flags;
+	struct list_head *pos, *n;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	list_for_each_safe(pos, n, &tx->free_urb_list) {
+		list_del(pos);
+		usb_free_urb(list_entry(pos, struct urb, urb_list));
+	}
+	tx->enabled = 0;
+	tx->submitted_urbs = 0;
+	/* The stopped state is ignored, relying on ieee80211_wake_queues()
+	 * in a potentionally following zd_usb_enable_tx().
+	 */
+	spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+/**
+ * zd_usb_enable_tx - enables transmission
+ * @usb: a &struct zd_usb pointer
+ *
+ * This function enables transmission and prepares the &zd_usb_tx data
+ * structure.
+ */
+void zd_usb_enable_tx(struct zd_usb *usb)
+{
+	unsigned long flags;
+	struct zd_usb_tx *tx = &usb->tx;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	tx->enabled = 1;
+	tx->submitted_urbs = 0;
+	ieee80211_wake_queues(zd_usb_to_hw(usb));
+	tx->stopped = 0;
+	spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+/**
+ * alloc_tx_urb - provides an tx URB
+ * @usb: a &struct zd_usb pointer
+ *
+ * Allocates a new URB. If possible takes the urb from the free list in
+ * usb->tx.
+ */
+static struct urb *alloc_tx_urb(struct zd_usb *usb)
+{
+	struct zd_usb_tx *tx = &usb->tx;
+	unsigned long flags;
+	struct list_head *entry;
+	struct urb *urb;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	if (list_empty(&tx->free_urb_list)) {
+		urb = usb_alloc_urb(0, GFP_ATOMIC);
+		goto out;
+	}
+	entry = tx->free_urb_list.next;
+	list_del(entry);
+	urb = list_entry(entry, struct urb, urb_list);
+out:
+	spin_unlock_irqrestore(&tx->lock, flags);
+	return urb;
+}
+
+/**
+ * free_tx_urb - frees a used tx URB
+ * @usb: a &struct zd_usb pointer
+ * @urb: URB to be freed
+ *
+ * Frees the the transmission URB, which means to put it on the free URB
+ * list.
+ */
+static void free_tx_urb(struct zd_usb *usb, struct urb *urb)
+{
+	struct zd_usb_tx *tx = &usb->tx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	if (!tx->enabled) {
+		usb_free_urb(urb);
+		goto out;
+	}
+	list_add(&urb->urb_list, &tx->free_urb_list);
+out:
+	spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static void tx_dec_submitted_urbs(struct zd_usb *usb)
+{
+	struct zd_usb_tx *tx = &usb->tx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	--tx->submitted_urbs;
+	if (tx->stopped && tx->submitted_urbs <= ZD_USB_TX_LOW) {
+		ieee80211_wake_queues(zd_usb_to_hw(usb));
+		tx->stopped = 0;
+	}
+	spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static void tx_inc_submitted_urbs(struct zd_usb *usb)
+{
+	struct zd_usb_tx *tx = &usb->tx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tx->lock, flags);
+	++tx->submitted_urbs;
+	if (!tx->stopped && tx->submitted_urbs > ZD_USB_TX_HIGH) {
+		ieee80211_stop_queues(zd_usb_to_hw(usb));
+		tx->stopped = 1;
+	}
+	spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+/**
+ * tx_urb_complete - completes the execution of an URB
+ * @urb: a URB
+ *
+ * This function is called if the URB has been transferred to a device or an
+ * error has happened.
+ */
 static void tx_urb_complete(struct urb *urb)
 {
 	int r;
+	struct sk_buff *skb;
+	struct zd_tx_skb_control_block *cb;
+	struct zd_usb *usb;
 
 	switch (urb->status) {
 	case 0:
@@ -761,9 +881,12 @@ static void tx_urb_complete(struct urb *urb)
 		goto resubmit;
 	}
 free_urb:
-	usb_buffer_free(urb->dev, urb->transfer_buffer_length,
-		        urb->transfer_buffer, urb->transfer_dma);
-	usb_free_urb(urb);
+	skb = (struct sk_buff *)urb->context;
+	zd_mac_tx_to_dev(skb, urb->status);
+	cb = (struct zd_tx_skb_control_block *)skb->cb;
+	usb = &zd_hw_mac(cb->hw)->chip.usb;
+	free_tx_urb(usb, urb);
+	tx_dec_submitted_urbs(usb);
 	return;
 resubmit:
 	r = usb_submit_urb(urb, GFP_ATOMIC);
@@ -773,43 +896,40 @@ resubmit:
 	}
 }
 
-/* Puts the frame on the USB endpoint. It doesn't wait for
- * completion. The frame must contain the control set.
+/**
+ * zd_usb_tx: initiates transfer of a frame of the device
+ *
+ * @usb: the zd1211rw-private USB structure
+ * @skb: a &struct sk_buff pointer
+ *
+ * This function tranmits a frame to the device. It doesn't wait for
+ * completion. The frame must contain the control set and have all the
+ * control set information available.
+ *
+ * The function returns 0 if the transfer has been successfully initiated.
  */
-int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length)
+int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb)
 {
 	int r;
 	struct usb_device *udev = zd_usb_to_usbdev(usb);
 	struct urb *urb;
-	void *buffer;
 
-	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	urb = alloc_tx_urb(usb);
 	if (!urb) {
 		r = -ENOMEM;
 		goto out;
 	}
 
-	buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC,
-		                  &urb->transfer_dma);
-	if (!buffer) {
-		r = -ENOMEM;
-		goto error_free_urb;
-	}
-	memcpy(buffer, frame, length);
-
 	usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
-		          buffer, length, tx_urb_complete, NULL);
-	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+		          skb->data, skb->len, tx_urb_complete, skb);
 
 	r = usb_submit_urb(urb, GFP_ATOMIC);
 	if (r)
 		goto error;
+	tx_inc_submitted_urbs(usb);
 	return 0;
 error:
-	usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer,
-		        urb->transfer_dma);
-error_free_urb:
-	usb_free_urb(urb);
+	free_tx_urb(usb, urb);
 out:
 	return r;
 }
@@ -838,16 +958,20 @@ static inline void init_usb_rx(struct zd_usb *usb)
 
 static inline void init_usb_tx(struct zd_usb *usb)
 {
-	/* FIXME: at this point we will allocate a fixed number of urb's for
-	 * use in a cyclic scheme */
+	struct zd_usb_tx *tx = &usb->tx;
+	spin_lock_init(&tx->lock);
+	tx->enabled = 0;
+	tx->stopped = 0;
+	INIT_LIST_HEAD(&tx->free_urb_list);
+	tx->submitted_urbs = 0;
 }
 
-void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
+void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw,
 	         struct usb_interface *intf)
 {
 	memset(usb, 0, sizeof(*usb));
 	usb->intf = usb_get_intf(intf);
-	usb_set_intfdata(usb->intf, netdev);
+	usb_set_intfdata(usb->intf, hw);
 	init_usb_interrupt(usb);
 	init_usb_tx(usb);
 	init_usb_rx(usb);
@@ -973,7 +1097,7 @@ int zd_usb_init_hw(struct zd_usb *usb)
 		return r;
 	}
 
-	r = zd_mac_init_hw(mac);
+	r = zd_mac_init_hw(mac->hw);
 	if (r) {
 		dev_dbg_f(zd_usb_dev(usb),
 		         "couldn't initialize mac. Error number %d\n", r);
@@ -987,9 +1111,9 @@ int zd_usb_init_hw(struct zd_usb *usb)
 static int probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	int r;
-	struct zd_usb *usb;
 	struct usb_device *udev = interface_to_usbdev(intf);
-	struct net_device *netdev = NULL;
+	struct zd_usb *usb;
+	struct ieee80211_hw *hw = NULL;
 
 	print_id(udev);
 
@@ -1007,57 +1131,65 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
 		goto error;
 	}
 
-	usb_reset_device(interface_to_usbdev(intf));
+	r = usb_reset_device(udev);
+	if (r) {
+		dev_err(&intf->dev,
+			"couldn't reset usb device. Error number %d\n", r);
+		goto error;
+	}
 
-	netdev = zd_netdev_alloc(intf);
-	if (netdev == NULL) {
+	hw = zd_mac_alloc_hw(intf);
+	if (hw == NULL) {
 		r = -ENOMEM;
 		goto error;
 	}
 
-	usb = &zd_netdev_mac(netdev)->chip.usb;
+	usb = &zd_hw_mac(hw)->chip.usb;
 	usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0;
 
-	r = zd_mac_preinit_hw(zd_netdev_mac(netdev));
+	r = zd_mac_preinit_hw(hw);
 	if (r) {
 		dev_dbg_f(&intf->dev,
 		         "couldn't initialize mac. Error number %d\n", r);
 		goto error;
 	}
 
-	r = register_netdev(netdev);
+	r = ieee80211_register_hw(hw);
 	if (r) {
 		dev_dbg_f(&intf->dev,
-			 "couldn't register netdev. Error number %d\n", r);
+			 "couldn't register device. Error number %d\n", r);
 		goto error;
 	}
 
 	dev_dbg_f(&intf->dev, "successful\n");
-	dev_info(&intf->dev,"%s\n", netdev->name);
+	dev_info(&intf->dev, "%s\n", wiphy_name(hw->wiphy));
 	return 0;
 error:
 	usb_reset_device(interface_to_usbdev(intf));
-	zd_netdev_free(netdev);
+	if (hw) {
+		zd_mac_clear(zd_hw_mac(hw));
+		ieee80211_free_hw(hw);
+	}
 	return r;
 }
 
 static void disconnect(struct usb_interface *intf)
 {
-	struct net_device *netdev = zd_intf_to_netdev(intf);
+	struct ieee80211_hw *hw = zd_intf_to_hw(intf);
 	struct zd_mac *mac;
 	struct zd_usb *usb;
 
 	/* Either something really bad happened, or we're just dealing with
 	 * a DEVICE_INSTALLER. */
-	if (netdev == NULL)
+	if (hw == NULL)
 		return;
 
-	mac = zd_netdev_mac(netdev);
+	mac = zd_hw_mac(hw);
 	usb = &mac->chip.usb;
 
 	dev_dbg_f(zd_usb_dev(usb), "\n");
 
-	zd_netdev_disconnect(netdev);
+	ieee80211_unregister_hw(hw);
 
 	/* Just in case something has gone wrong! */
 	zd_usb_disable_rx(usb);
@@ -1070,12 +1202,13 @@ static void disconnect(struct usb_interface *intf)
 	 */
 	usb_reset_device(interface_to_usbdev(intf));
 
-	zd_netdev_free(netdev);
+	zd_mac_clear(mac);
+	ieee80211_free_hw(hw);
 	dev_dbg(&intf->dev, "disconnected\n");
 }
 
 static struct usb_driver driver = {
-	.name		= "zd1211rw",
+	.name		= KBUILD_MODNAME,
 	.id_table	= usb_ids,
 	.probe		= probe,
 	.disconnect	= disconnect,
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 961a7a12ad68..049f8b91f020 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -1,4 +1,7 @@
-/* zd_usb.h: Header for USB interface implemented by ZD1211 chip
+/* ZD1211 USB-WLAN driver for Linux
+ *
+ * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de>
+ * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.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
@@ -26,6 +29,9 @@
 
 #include "zd_def.h"
 
+#define ZD_USB_TX_HIGH  5
+#define ZD_USB_TX_LOW   2
+
 enum devicetype {
 	DEVICE_ZD1211  = 0,
 	DEVICE_ZD1211B = 1,
@@ -165,7 +171,7 @@ static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr)
 	return (struct usb_int_regs *)intr->read_regs.buffer;
 }
 
-#define URBS_COUNT 5
+#define RX_URBS_COUNT 5
 
 struct zd_usb_rx {
 	spinlock_t lock;
@@ -176,8 +182,21 @@ struct zd_usb_rx {
 	int urbs_count;
 };
 
+/**
+ * struct zd_usb_tx - structure used for transmitting frames
+ * @lock: lock for transmission
+ * @free_urb_list: list of free URBs, contains all the URBs, which can be used
+ * @submitted_urbs: atomic integer that counts the URBs having sent to the
+ *	device, which haven't been completed
+ * @enabled: enabled flag, indicates whether tx is enabled
+ * @stopped: indicates whether higher level tx queues are stopped
+ */
 struct zd_usb_tx {
 	spinlock_t lock;
+	struct list_head free_urb_list;
+	int submitted_urbs;
+	int enabled;
+	int stopped;
 };
 
 /* Contains the usb parts. The structure doesn't require a lock because intf
@@ -198,17 +217,17 @@ static inline struct usb_device *zd_usb_to_usbdev(struct zd_usb *usb)
 	return interface_to_usbdev(usb->intf);
 }
 
-static inline struct net_device *zd_intf_to_netdev(struct usb_interface *intf)
+static inline struct ieee80211_hw *zd_intf_to_hw(struct usb_interface *intf)
 {
 	return usb_get_intfdata(intf);
 }
 
-static inline struct net_device *zd_usb_to_netdev(struct zd_usb *usb)
+static inline struct ieee80211_hw *zd_usb_to_hw(struct zd_usb *usb)
 {
-	return zd_intf_to_netdev(usb->intf);
+	return zd_intf_to_hw(usb->intf);
 }
 
-void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
+void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw,
 	         struct usb_interface *intf);
 int zd_usb_init_hw(struct zd_usb *usb);
 void zd_usb_clear(struct zd_usb *usb);
@@ -221,7 +240,10 @@ void zd_usb_disable_int(struct zd_usb *usb);
 int zd_usb_enable_rx(struct zd_usb *usb);
 void zd_usb_disable_rx(struct zd_usb *usb);
 
-int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length);
+void zd_usb_enable_tx(struct zd_usb *usb);
+void zd_usb_disable_tx(struct zd_usb *usb);
+
+int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb);
 
 int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
 	         const zd_addr_t *addresses, unsigned int count);
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index bca37bf0f545..7483d45bc5bc 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1073,7 +1073,7 @@ static void xennet_release_rx_bufs(struct netfront_info *np)
 		if (!xen_feature(XENFEAT_auto_translated_physmap)) {
 			/* Do all the remapping work and M2P updates. */
 			MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu,
-					 0, DOMID_SELF);
+					 NULL, DOMID_SELF);
 			mcl++;
 			HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
 		}
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index a6d6b2488ffc..703b85edb004 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -364,7 +364,7 @@ static __inline__ int led_get_net_activity(void)
 	    struct in_device *in_dev = __in_dev_get_rcu(dev);
 	    if (!in_dev || !in_dev->ifa_list)
 		continue;
-	    if (LOOPBACK(in_dev->ifa_list->ifa_local))
+	    if (ipv4_is_loopback(in_dev->ifa_list->ifa_local))
 		continue;
 	    stats = dev->get_stats(dev);
 	    rx_total += stats->rx_packets;
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index ebb09e98d215..de34aa9d3136 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -120,7 +120,7 @@ struct pdcspath_entry pdcspath_entry_##_name = { \
 };
 
 #define PDCS_ATTR(_name, _mode, _show, _store) \
-struct subsys_attribute pdcs_attr_##_name = { \
+struct kobj_attribute pdcs_attr_##_name = { \
 	.attr = {.name = __stringify(_name), .mode = _mode}, \
 	.show = _show, \
 	.store = _store, \
@@ -523,15 +523,15 @@ static struct pdcspath_entry *pdcspath_entries[] = {
 
 /**
  * pdcs_size_read - Stable Storage size output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
-static ssize_t
-pdcs_size_read(struct kset *kset, char *buf)
+static ssize_t pdcs_size_read(struct kobject *kobj,
+			      struct kobj_attribute *attr,
+			      char *buf)
 {
 	char *out = buf;
 
-	if (!kset || !buf)
+	if (!buf)
 		return -EINVAL;
 
 	/* show the size of the stable storage */
@@ -542,17 +542,17 @@ pdcs_size_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_auto_read - Stable Storage autoboot/search flag output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
  */
-static ssize_t
-pdcs_auto_read(struct kset *kset, char *buf, int knob)
+static ssize_t pdcs_auto_read(struct kobject *kobj,
+			      struct kobj_attribute *attr,
+			      char *buf, int knob)
 {
 	char *out = buf;
 	struct pdcspath_entry *pathentry;
 
-	if (!kset || !buf)
+	if (!buf)
 		return -EINVAL;
 
 	/* Current flags are stored in primary boot path entry */
@@ -568,40 +568,37 @@ pdcs_auto_read(struct kset *kset, char *buf, int knob)
 
 /**
  * pdcs_autoboot_read - Stable Storage autoboot flag output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
-static inline ssize_t
-pdcs_autoboot_read(struct kset *kset, char *buf)
+static ssize_t pdcs_autoboot_read(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
 {
-	return pdcs_auto_read(kset, buf, PF_AUTOBOOT);
+	return pdcs_auto_read(kobj, attr, buf, PF_AUTOBOOT);
 }
 
 /**
  * pdcs_autosearch_read - Stable Storage autoboot flag output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
-static inline ssize_t
-pdcs_autosearch_read(struct kset *kset, char *buf)
+static ssize_t pdcs_autosearch_read(struct kobject *kobj,
+				    struct kobj_attribute *attr, char *buf)
 {
-	return pdcs_auto_read(kset, buf, PF_AUTOSEARCH);
+	return pdcs_auto_read(kobj, attr, buf, PF_AUTOSEARCH);
 }
 
 /**
  * pdcs_timer_read - Stable Storage timer count output (in seconds).
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * The value of the timer field correponds to a number of seconds in powers of 2.
  */
-static ssize_t
-pdcs_timer_read(struct kset *kset, char *buf)
+static ssize_t pdcs_timer_read(struct kobject *kobj,
+			       struct kobj_attribute *attr, char *buf)
 {
 	char *out = buf;
 	struct pdcspath_entry *pathentry;
 
-	if (!kset || !buf)
+	if (!buf)
 		return -EINVAL;
 
 	/* Current flags are stored in primary boot path entry */
@@ -618,15 +615,14 @@ pdcs_timer_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_osid_read - Stable Storage OS ID register output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  */
-static ssize_t
-pdcs_osid_read(struct kset *kset, char *buf)
+static ssize_t pdcs_osid_read(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
 {
 	char *out = buf;
 
-	if (!kset || !buf)
+	if (!buf)
 		return -EINVAL;
 
 	out += sprintf(out, "%s dependent data (0x%.4x)\n",
@@ -637,18 +633,17 @@ pdcs_osid_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * This can hold 16 bytes of OS-Dependent data.
  */
-static ssize_t
-pdcs_osdep1_read(struct kset *kset, char *buf)
+static ssize_t pdcs_osdep1_read(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf)
 {
 	char *out = buf;
 	u32 result[4];
 
-	if (!kset || !buf)
+	if (!buf)
 		return -EINVAL;
 
 	if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
@@ -664,18 +659,17 @@ pdcs_osdep1_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_diagnostic_read - Stable Storage Diagnostic register output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * I have NFC how to interpret the content of that register ;-).
  */
-static ssize_t
-pdcs_diagnostic_read(struct kset *kset, char *buf)
+static ssize_t pdcs_diagnostic_read(struct kobject *kobj,
+				    struct kobj_attribute *attr, char *buf)
 {
 	char *out = buf;
 	u32 result;
 
-	if (!kset || !buf)
+	if (!buf)
 		return -EINVAL;
 
 	/* get diagnostic */
@@ -689,18 +683,17 @@ pdcs_diagnostic_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_fastsize_read - Stable Storage FastSize register output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * This register holds the amount of system RAM to be tested during boot sequence.
  */
-static ssize_t
-pdcs_fastsize_read(struct kset *kset, char *buf)
+static ssize_t pdcs_fastsize_read(struct kobject *kobj,
+				  struct kobj_attribute *attr, char *buf)
 {
 	char *out = buf;
 	u32 result;
 
-	if (!kset || !buf)
+	if (!buf)
 		return -EINVAL;
 
 	/* get fast-size */
@@ -718,13 +711,12 @@ pdcs_fastsize_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The output buffer to write to.
  *
  * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
  */
-static ssize_t
-pdcs_osdep2_read(struct kset *kset, char *buf)
+static ssize_t pdcs_osdep2_read(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf)
 {
 	char *out = buf;
 	unsigned long size;
@@ -736,7 +728,7 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
 
 	size = pdcs_size - 224;
 
-	if (!kset || !buf)
+	if (!buf)
 		return -EINVAL;
 
 	for (i=0; i<size; i+=4) {
@@ -751,7 +743,6 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
 
 /**
  * pdcs_auto_write - This function handles autoboot/search flag modifying.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
@@ -760,8 +751,9 @@ pdcs_osdep2_read(struct kset *kset, char *buf)
  * We expect a precise syntax:
  *	\"n\" (n == 0 or 1) to toggle AutoBoot Off or On
  */
-static ssize_t
-pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob)
+static ssize_t pdcs_auto_write(struct kobject *kobj,
+			       struct kobj_attribute *attr, const char *buf,
+			       size_t count, int knob)
 {
 	struct pdcspath_entry *pathentry;
 	unsigned char flags;
@@ -771,7 +763,7 @@ pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob)
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	if (!kset || !buf || !count)
+	if (!buf || !count)
 		return -EINVAL;
 
 	/* We'll use a local copy of buf */
@@ -826,7 +818,6 @@ parse_error:
 
 /**
  * pdcs_autoboot_write - This function handles autoboot flag modifying.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -834,15 +825,15 @@ parse_error:
  * We expect a precise syntax:
  *	\"n\" (n == 0 or 1) to toggle AutoSearch Off or On
  */
-static inline ssize_t
-pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count)
+static ssize_t pdcs_autoboot_write(struct kobject *kobj,
+				   struct kobj_attribute *attr,
+				   const char *buf, size_t count)
 {
-	return pdcs_auto_write(kset, buf, count, PF_AUTOBOOT);
+	return pdcs_auto_write(kset, attr, buf, count, PF_AUTOBOOT);
 }
 
 /**
  * pdcs_autosearch_write - This function handles autosearch flag modifying.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -850,15 +841,15 @@ pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count)
  * We expect a precise syntax:
  *	\"n\" (n == 0 or 1) to toggle AutoSearch Off or On
  */
-static inline ssize_t
-pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count)
+static ssize_t pdcs_autosearch_write(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t count)
 {
-	return pdcs_auto_write(kset, buf, count, PF_AUTOSEARCH);
+	return pdcs_auto_write(kset, attr, buf, count, PF_AUTOSEARCH);
 }
 
 /**
  * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -866,15 +857,16 @@ pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count)
  * write approach. It's up to userspace to deal with it when constructing
  * its input buffer.
  */
-static ssize_t
-pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
+static ssize_t pdcs_osdep1_write(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *buf, size_t count)
 {
 	u8 in[16];
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	if (!kset || !buf || !count)
+	if (!buf || !count)
 		return -EINVAL;
 
 	if (unlikely(pdcs_osid != OS_ID_LINUX))
@@ -895,7 +887,6 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
 
 /**
  * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
- * @kset: An allocated and populated struct kset. We don't use it tho.
  * @buf: The input buffer to read from.
  * @count: The number of bytes to be read.
  *
@@ -903,8 +894,9 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
  * byte-by-byte write approach. It's up to userspace to deal with it when
  * constructing its input buffer.
  */
-static ssize_t
-pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count)
+static ssize_t pdcs_osdep2_write(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *buf, size_t count)
 {
 	unsigned long size;
 	unsigned short i;
@@ -913,7 +905,7 @@ pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count)
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	if (!kset || !buf || !count)
+	if (!buf || !count)
 		return -EINVAL;
 
 	if (unlikely(pdcs_size <= 224))
@@ -951,21 +943,25 @@ static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
 static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
 static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
 
-static struct subsys_attribute *pdcs_subsys_attrs[] = {
-	&pdcs_attr_size,
-	&pdcs_attr_autoboot,
-	&pdcs_attr_autosearch,
-	&pdcs_attr_timer,
-	&pdcs_attr_osid,
-	&pdcs_attr_osdep1,
-	&pdcs_attr_diagnostic,
-	&pdcs_attr_fastsize,
-	&pdcs_attr_osdep2,
+static struct attribute *pdcs_subsys_attrs[] = {
+	&pdcs_attr_size.attr,
+	&pdcs_attr_autoboot.attr,
+	&pdcs_attr_autosearch.attr,
+	&pdcs_attr_timer.attr,
+	&pdcs_attr_osid.attr,
+	&pdcs_attr_osdep1.attr,
+	&pdcs_attr_diagnostic.attr,
+	&pdcs_attr_fastsize.attr,
+	&pdcs_attr_osdep2.attr,
 	NULL,
 };
 
-static decl_subsys(paths, &ktype_pdcspath, NULL);
-static decl_subsys(stable, NULL, NULL);
+static struct attribute_group pdcs_attr_group = {
+	.attrs = pdcs_subsys_attrs,
+};
+
+static struct kobject *stable_kobj;
+static struct kset *paths_kset;
 
 /**
  * pdcs_register_pathentries - Prepares path entries kobjects for sysfs usage.
@@ -995,12 +991,12 @@ pdcs_register_pathentries(void)
 		if (err < 0)
 			continue;
 
-		if ((err = kobject_set_name(&entry->kobj, "%s", entry->name)))
-			return err;
-		kobj_set_kset_s(entry, paths_subsys);
-		if ((err = kobject_register(&entry->kobj)))
+		entry->kobj.kset = paths_kset;
+		err = kobject_init_and_add(&entry->kobj, &ktype_pdcspath, NULL,
+					   "%s", entry->name);
+		if (err)
 			return err;
-		
+
 		/* kobject is now registered */
 		write_lock(&entry->rw_lock);
 		entry->ready = 2;
@@ -1012,6 +1008,7 @@ pdcs_register_pathentries(void)
 		}
 
 		write_unlock(&entry->rw_lock);
+		kobject_uevent(&entry->kobj, KOBJ_ADD);
 	}
 	
 	return 0;
@@ -1029,7 +1026,7 @@ pdcs_unregister_pathentries(void)
 	for (i = 0; (entry = pdcspath_entries[i]); i++) {
 		read_lock(&entry->rw_lock);
 		if (entry->ready >= 2)
-			kobject_unregister(&entry->kobj);
+			kobject_put(&entry->kobj);
 		read_unlock(&entry->rw_lock);
 	}
 }
@@ -1041,8 +1038,7 @@ pdcs_unregister_pathentries(void)
 static int __init
 pdc_stable_init(void)
 {
-	struct subsys_attribute *attr;
-	int i, rc = 0, error = 0;
+	int rc = 0, error = 0;
 	u32 result;
 
 	/* find the size of the stable storage */
@@ -1062,21 +1058,24 @@ pdc_stable_init(void)
 	/* the actual result is 16 bits away */
 	pdcs_osid = (u16)(result >> 16);
 
-	/* For now we'll register the stable subsys within this driver */
-	if ((rc = firmware_register(&stable_subsys)))
+	/* For now we'll register the directory at /sys/firmware/stable */
+	stable_kobj = kobject_create_and_add("stable", firmware_kobj);
+	if (!stable_kobj) {
+		rc = -ENOMEM;
 		goto fail_firmreg;
+	}
 
 	/* Don't forget the root entries */
-	for (i = 0; (attr = pdcs_subsys_attrs[i]) && !error; i++)
-		if (attr->show)
-			error = subsys_create_file(&stable_subsys, attr);
-	
-	/* register the paths subsys as a subsystem of stable subsys */
-	kobj_set_kset_s(&paths_subsys, stable_subsys);
-	if ((rc = subsystem_register(&paths_subsys)))
-		goto fail_subsysreg;
+	error = sysfs_create_group(stable_kobj, pdcs_attr_group);
 
-	/* now we create all "files" for the paths subsys */
+	/* register the paths kset as a child of the stable kset */
+	paths_kset = kset_create_and_add("paths", NULL, stable_kobj);
+	if (!paths_kset) {
+		rc = -ENOMEM;
+		goto fail_ksetreg;
+	}
+
+	/* now we create all "files" for the paths kset */
 	if ((rc = pdcs_register_pathentries()))
 		goto fail_pdcsreg;
 
@@ -1084,10 +1083,10 @@ pdc_stable_init(void)
 	
 fail_pdcsreg:
 	pdcs_unregister_pathentries();
-	subsystem_unregister(&paths_subsys);
+	kset_unregister(paths_kset);
 	
-fail_subsysreg:
-	firmware_unregister(&stable_subsys);
+fail_ksetreg:
+	kobject_put(stable_kobj);
 	
 fail_firmreg:
 	printk(KERN_INFO PDCS_PREFIX " bailing out\n");
@@ -1098,9 +1097,8 @@ static void __exit
 pdc_stable_exit(void)
 {
 	pdcs_unregister_pathentries();
-	subsystem_unregister(&paths_subsys);
-
-	firmware_unregister(&stable_subsys);
+	kset_unregister(paths_kset);
+	kobject_put(stable_kobj);
 }
 
 
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 47d26b65e99a..750ebd7a4c10 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -429,7 +429,7 @@ static int __init ibm_acpiphp_init(void)
 	int retval = 0;
 	acpi_status status;
 	struct acpi_device *device;
-	struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
+	struct kobject *sysdir = &pci_hotplug_slots_kset->kobj;
 
 	dbg("%s\n", __FUNCTION__);
 
@@ -476,7 +476,7 @@ init_return:
 static void __exit ibm_acpiphp_exit(void)
 {
 	acpi_status status;
-	struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
+	struct kobject *sysdir = &pci_hotplug_slots_kset->kobj;
 
 	dbg("%s\n", __FUNCTION__);
 
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 01c351c176ac..47bb0e1ff3fa 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -61,7 +61,7 @@ static int debug;
 
 static LIST_HEAD(pci_hotplug_slot_list);
 
-struct kset pci_hotplug_slots_subsys;
+struct kset *pci_hotplug_slots_kset;
 
 static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
 		struct attribute *attr, char *buf)
@@ -96,8 +96,6 @@ static struct kobj_type hotplug_slot_ktype = {
 	.release = &hotplug_slot_release,
 };
 
-decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
-
 /* these strings match up with the values in pci_bus_speed */
 static char *pci_bus_speed_strings[] = {
 	"33 MHz PCI",		/* 0x00 */
@@ -632,18 +630,19 @@ int pci_hp_register (struct hotplug_slot *slot)
 		return -EINVAL;
 	}
 
-	kobject_set_name(&slot->kobj, "%s", slot->name);
-	kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
-
 	/* this can fail if we have already registered a slot with the same name */
-	if (kobject_register(&slot->kobj)) {
-		err("Unable to register kobject");
+	slot->kobj.kset = pci_hotplug_slots_kset;
+	result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL,
+				      "%s", slot->name);
+	if (result) {
+		err("Unable to register kobject '%s'", slot->name);
 		return -EINVAL;
 	}
-		
+
 	list_add (&slot->slot_list, &pci_hotplug_slot_list);
 
 	result = fs_add_slot (slot);
+	kobject_uevent(&slot->kobj, KOBJ_ADD);
 	dbg ("Added slot %s to the list\n", slot->name);
 	return result;
 }
@@ -672,7 +671,7 @@ int pci_hp_deregister (struct hotplug_slot *slot)
 
 	fs_remove_slot (slot);
 	dbg ("Removed slot %s from the list\n", slot->name);
-	kobject_unregister(&slot->kobj);
+	kobject_put(&slot->kobj);
 	return 0;
 }
 
@@ -700,11 +699,15 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
 static int __init pci_hotplug_init (void)
 {
 	int result;
+	struct kset *pci_bus_kset;
 
-	kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
-	result = subsystem_register(&pci_hotplug_slots_subsys);
-	if (result) {
-		err("Register subsys with error %d\n", result);
+	pci_bus_kset = bus_get_kset(&pci_bus_type);
+
+	pci_hotplug_slots_kset = kset_create_and_add("slots", NULL,
+						     &pci_bus_kset->kobj);
+	if (!pci_hotplug_slots_kset) {
+		result = -ENOMEM;
+		err("Register subsys error\n");
 		goto exit;
 	}
 	result = cpci_hotplug_init(debug);
@@ -715,9 +718,9 @@ static int __init pci_hotplug_init (void)
 
 	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
 	goto exit;
-	
+
 err_subsys:
-	subsystem_unregister(&pci_hotplug_slots_subsys);
+	kset_unregister(pci_hotplug_slots_kset);
 exit:
 	return result;
 }
@@ -725,7 +728,7 @@ exit:
 static void __exit pci_hotplug_exit (void)
 {
 	cpci_hotplug_exit();
-	subsystem_unregister(&pci_hotplug_slots_subsys);
+	kset_unregister(pci_hotplug_slots_kset);
 }
 
 module_init(pci_hotplug_init);
@@ -737,7 +740,7 @@ MODULE_LICENSE("GPL");
 module_param(debug, bool, 0644);
 MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
 
-EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
+EXPORT_SYMBOL_GPL(pci_hotplug_slots_kset);
 EXPORT_SYMBOL_GPL(pci_hp_register);
 EXPORT_SYMBOL_GPL(pci_hp_deregister);
 EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
index a080fedf0332..e32148a8fa12 100644
--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -23,44 +23,13 @@
 
 #define MAX_DRC_NAME_LEN 64
 
-/* Store return code of dlpar operation in attribute struct */
-struct dlpar_io_attr {
-	int rc;
-	struct attribute attr;
-	ssize_t (*store)(struct dlpar_io_attr *dlpar_attr, const char *buf,
-		size_t nbytes);
-};
 
-/* Common show callback for all attrs, display the return code
- * of the dlpar op */
-static ssize_t
-dlpar_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
-{
-	struct dlpar_io_attr *dlpar_attr = container_of(attr,
-						struct dlpar_io_attr, attr);
-	return sprintf(buf, "%d\n", dlpar_attr->rc);
-}
-
-static ssize_t
-dlpar_attr_store(struct kobject * kobj, struct attribute * attr,
-		 const char *buf, size_t nbytes)
-{
-	struct dlpar_io_attr *dlpar_attr = container_of(attr,
-						struct dlpar_io_attr, attr);
-	return dlpar_attr->store ?
-		dlpar_attr->store(dlpar_attr, buf, nbytes) : -EIO;
-}
-
-static struct sysfs_ops dlpar_attr_sysfs_ops = {
-	.show = dlpar_attr_show,
-	.store = dlpar_attr_store,
-};
-
-static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr,
-				const char *buf, size_t nbytes)
+static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr,
+			      const char *buf, size_t nbytes)
 {
 	char drc_name[MAX_DRC_NAME_LEN];
 	char *end;
+	int rc;
 
 	if (nbytes >= MAX_DRC_NAME_LEN)
 		return 0;
@@ -72,15 +41,25 @@ static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr,
 		end = &drc_name[nbytes];
 	*end = '\0';
 
-	dlpar_attr->rc = dlpar_add_slot(drc_name);
+	rc = dlpar_add_slot(drc_name);
+	if (rc)
+		return rc;
 
 	return nbytes;
 }
 
-static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr,
-		 		const char *buf, size_t nbytes)
+static ssize_t add_slot_show(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0\n");
+}
+
+static ssize_t remove_slot_store(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *buf, size_t nbytes)
 {
 	char drc_name[MAX_DRC_NAME_LEN];
+	int rc;
 	char *end;
 
 	if (nbytes >= MAX_DRC_NAME_LEN)
@@ -93,22 +72,24 @@ static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr,
 		end = &drc_name[nbytes];
 	*end = '\0';
 
-	dlpar_attr->rc = dlpar_remove_slot(drc_name);
+	rc = dlpar_remove_slot(drc_name);
+	if (rc)
+		return rc;
 
 	return nbytes;
 }
 
-static struct dlpar_io_attr add_slot_attr = {
-	.rc = 0,
-	.attr = { .name = ADD_SLOT_ATTR_NAME, .mode = 0644, },
-	.store = add_slot_store,
-};
+static ssize_t remove_slot_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0\n");
+}
 
-static struct dlpar_io_attr remove_slot_attr = {
-	.rc = 0,
-	.attr = { .name = REMOVE_SLOT_ATTR_NAME, .mode = 0644},
-	.store = remove_slot_store,
-};
+static struct kobj_attribute add_slot_attr =
+	__ATTR(ADD_SLOT_ATTR_NAME, 0644, add_slot_show, add_slot_store);
+
+static struct kobj_attribute remove_slot_attr =
+	__ATTR(REMOVE_SLOT_ATTR_NAME, 0644, remove_slot_show, remove_slot_store);
 
 static struct attribute *default_attrs[] = {
 	&add_slot_attr.attr,
@@ -116,37 +97,29 @@ static struct attribute *default_attrs[] = {
 	NULL,
 };
 
-static void dlpar_io_release(struct kobject *kobj)
-{
-	/* noop */
-	return;
-}
-
-struct kobj_type ktype_dlpar_io = {
-	.release = dlpar_io_release,
-	.sysfs_ops = &dlpar_attr_sysfs_ops,
-	.default_attrs = default_attrs,
+static struct attribute_group dlpar_attr_group = {
+	.attrs = default_attrs,
 };
 
-struct kset dlpar_io_kset = {
-	.kobj = {.ktype = &ktype_dlpar_io,
-		 .parent = &pci_hotplug_slots_subsys.kobj},
-	.ktype = &ktype_dlpar_io,
-};
+static struct kobject *dlpar_kobj;
 
 int dlpar_sysfs_init(void)
 {
-	kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME);
-	if (kset_register(&dlpar_io_kset)) {
-		printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
-				kobject_name(&dlpar_io_kset.kobj));
+	int error;
+
+	dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME,
+					    &pci_hotplug_slots_kset->kobj);
+	if (!dlpar_kobj)
 		return -EINVAL;
-	}
 
-	return 0;
+	error = sysfs_create_group(dlpar_kobj, &dlpar_attr_group);
+	if (error)
+		kobject_put(dlpar_kobj);
+	return error;
 }
 
 void dlpar_sysfs_exit(void)
 {
-	kset_unregister(&dlpar_io_kset);
+	sysfs_remove_group(dlpar_kobj, &dlpar_attr_group);
+	kobject_put(dlpar_kobj);
 }
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 6d1a21611818..c4fa35d1dd77 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -1,6 +1,11 @@
 /*
  * drivers/pci/pci-driver.c
  *
+ * (C) Copyright 2002-2004, 2007 Greg Kroah-Hartman <greg@kroah.com>
+ * (C) Copyright 2007 Novell Inc.
+ *
+ * Released under the GPL v2 only.
+ *
  */
 
 #include <linux/pci.h>
@@ -96,17 +101,21 @@ pci_create_newid_file(struct pci_driver *drv)
 {
 	int error = 0;
 	if (drv->probe != NULL)
-		error = sysfs_create_file(&drv->driver.kobj,
-					  &driver_attr_new_id.attr);
+		error = driver_create_file(&drv->driver, &driver_attr_new_id);
 	return error;
 }
 
+static void pci_remove_newid_file(struct pci_driver *drv)
+{
+	driver_remove_file(&drv->driver, &driver_attr_new_id);
+}
 #else /* !CONFIG_HOTPLUG */
 static inline void pci_free_dynids(struct pci_driver *drv) {}
 static inline int pci_create_newid_file(struct pci_driver *drv)
 {
 	return 0;
 }
+static inline void pci_remove_newid_file(struct pci_driver *drv) {}
 #endif
 
 /**
@@ -352,50 +361,6 @@ static void pci_device_shutdown(struct device *dev)
 		drv->shutdown(pci_dev);
 }
 
-#define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj)
-#define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr)
-
-static ssize_t
-pci_driver_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
-{
-	struct device_driver *driver = kobj_to_pci_driver(kobj);
-	struct driver_attribute *dattr = attr_to_driver_attribute(attr);
-	ssize_t ret;
-
-	if (!get_driver(driver))
-		return -ENODEV;
-
-	ret = dattr->show ? dattr->show(driver, buf) : -EIO;
-
-	put_driver(driver);
-	return ret;
-}
-
-static ssize_t
-pci_driver_attr_store(struct kobject * kobj, struct attribute *attr,
-		      const char *buf, size_t count)
-{
-	struct device_driver *driver = kobj_to_pci_driver(kobj);
-	struct driver_attribute *dattr = attr_to_driver_attribute(attr);
-	ssize_t ret;
-
-	if (!get_driver(driver))
-		return -ENODEV;
-
-	ret = dattr->store ? dattr->store(driver, buf, count) : -EIO;
-
-	put_driver(driver);
-	return ret;
-}
-
-static struct sysfs_ops pci_driver_sysfs_ops = {
-	.show = pci_driver_attr_show,
-	.store = pci_driver_attr_store,
-};
-static struct kobj_type pci_driver_kobj_type = {
-	.sysfs_ops = &pci_driver_sysfs_ops,
-};
-
 /**
  * __pci_register_driver - register a new pci driver
  * @drv: the driver structure to register
@@ -417,7 +382,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
 	drv->driver.bus = &pci_bus_type;
 	drv->driver.owner = owner;
 	drv->driver.mod_name = mod_name;
-	drv->driver.kobj.ktype = &pci_driver_kobj_type;
 
 	spin_lock_init(&drv->dynids.lock);
 	INIT_LIST_HEAD(&drv->dynids.list);
@@ -447,6 +411,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
 void
 pci_unregister_driver(struct pci_driver *drv)
 {
+	pci_remove_newid_file(drv);
 	driver_unregister(&drv->driver);
 	pci_free_dynids(drv);
 }
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c5ca3134513a..5fd585293e79 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1210,16 +1210,19 @@ static void __init pci_sort_breadthfirst_klist(void)
 	struct klist_node *n;
 	struct device *dev;
 	struct pci_dev *pdev;
+	struct klist *device_klist;
 
-	spin_lock(&pci_bus_type.klist_devices.k_lock);
-	list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) {
+	device_klist = bus_get_device_klist(&pci_bus_type);
+
+	spin_lock(&device_klist->k_lock);
+	list_for_each_safe(pos, tmp, &device_klist->k_list) {
 		n = container_of(pos, struct klist_node, n_node);
 		dev = container_of(n, struct device, knode_bus);
 		pdev = to_pci_dev(dev);
 		pci_insertion_sort_klist(pdev, &sorted_devices);
 	}
-	list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list);
-	spin_unlock(&pci_bus_type.klist_devices.k_lock);
+	list_splice(&sorted_devices, &device_klist->k_list);
+	spin_unlock(&device_klist->k_lock);
 }
 
 static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list)
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 5cf89a91da1e..15c18f5246d6 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -312,8 +312,7 @@ pcmcia_create_newid_file(struct pcmcia_driver *drv)
 {
 	int error = 0;
 	if (drv->probe != NULL)
-		error = sysfs_create_file(&drv->drv.kobj,
-					  &driver_attr_new_id.attr);
+		error = driver_create_file(&drv->drv, &driver_attr_new_id);
 	return error;
 }
 
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 874923fcb2f9..e439044d88f2 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -29,6 +29,7 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-regs.h>
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/ss.h>
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
index 5dba68fe33f5..a8364d815222 100644
--- a/drivers/pnp/pnpbios/bioscalls.c
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -61,7 +61,7 @@ set_base(gdt[(selname) >> 3], (u32)(address)); \
 set_limit(gdt[(selname) >> 3], size); \
 } while(0)
 
-static struct desc_struct bad_bios_desc = { 0, 0x00409200 };
+static struct desc_struct bad_bios_desc;
 
 /*
  * At some point we want to use this stack frame pointer to unwind
@@ -477,6 +477,9 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header)
 	pnp_bios_callpoint.offset = header->fields.pm16offset;
 	pnp_bios_callpoint.segment = PNP_CS16;
 
+	bad_bios_desc.a = 0;
+	bad_bios_desc.b = 0x00409200;
+
 	set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
 	_set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
 	for (i = 0; i < NR_CPUS; i++) {
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
index bbf3ee10da04..7e29b90a4f63 100644
--- a/drivers/power/apm_power.c
+++ b/drivers/power/apm_power.c
@@ -13,6 +13,7 @@
 #include <linux/power_supply.h>
 #include <linux/apm-emulation.h>
 
+static DEFINE_MUTEX(apm_mutex);
 #define PSY_PROP(psy, prop, val) psy->get_property(psy, \
 			 POWER_SUPPLY_PROP_##prop, val)
 
@@ -23,67 +24,86 @@
 
 static struct power_supply *main_battery;
 
-static void find_main_battery(void)
-{
-	struct device *dev;
-	struct power_supply *bat = NULL;
-	struct power_supply *max_charge_bat = NULL;
-	struct power_supply *max_energy_bat = NULL;
+struct find_bat_param {
+	struct power_supply *main;
+	struct power_supply *bat;
+	struct power_supply *max_charge_bat;
+	struct power_supply *max_energy_bat;
 	union power_supply_propval full;
-	int max_charge = 0;
-	int max_energy = 0;
+	int max_charge;
+	int max_energy;
+};
 
-	main_battery = NULL;
+static int __find_main_battery(struct device *dev, void *data)
+{
+	struct find_bat_param *bp = (struct find_bat_param *)data;
 
-	list_for_each_entry(dev, &power_supply_class->devices, node) {
-		bat = dev_get_drvdata(dev);
+	bp->bat = dev_get_drvdata(dev);
 
-		if (bat->use_for_apm) {
-			/* nice, we explicitly asked to report this battery. */
-			main_battery = bat;
-			return;
-		}
+	if (bp->bat->use_for_apm) {
+		/* nice, we explicitly asked to report this battery. */
+		bp->main = bp->bat;
+		return 1;
+	}
 
-		if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) ||
-				!PSY_PROP(bat, CHARGE_FULL, &full)) {
-			if (full.intval > max_charge) {
-				max_charge_bat = bat;
-				max_charge = full.intval;
-			}
-		} else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) ||
-				!PSY_PROP(bat, ENERGY_FULL, &full)) {
-			if (full.intval > max_energy) {
-				max_energy_bat = bat;
-				max_energy = full.intval;
-			}
+	if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) ||
+			!PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) {
+		if (bp->full.intval > bp->max_charge) {
+			bp->max_charge_bat = bp->bat;
+			bp->max_charge = bp->full.intval;
+		}
+	} else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) ||
+			!PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) {
+		if (bp->full.intval > bp->max_energy) {
+			bp->max_energy_bat = bp->bat;
+			bp->max_energy = bp->full.intval;
 		}
 	}
+	return 0;
+}
+
+static void find_main_battery(void)
+{
+	struct find_bat_param bp;
+	int error;
+
+	memset(&bp, 0, sizeof(struct find_bat_param));
+	main_battery = NULL;
+	bp.main = main_battery;
+
+	error = class_for_each_device(power_supply_class, &bp,
+				      __find_main_battery);
+	if (error) {
+		main_battery = bp.main;
+		return;
+	}
 
-	if ((max_energy_bat && max_charge_bat) &&
-			(max_energy_bat != max_charge_bat)) {
+	if ((bp.max_energy_bat && bp.max_charge_bat) &&
+			(bp.max_energy_bat != bp.max_charge_bat)) {
 		/* try guess battery with more capacity */
-		if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) {
-			if (max_energy > max_charge * full.intval)
-				main_battery = max_energy_bat;
+		if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN,
+			      &bp.full)) {
+			if (bp.max_energy > bp.max_charge * bp.full.intval)
+				main_battery = bp.max_energy_bat;
 			else
-				main_battery = max_charge_bat;
-		} else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN,
-								  &full)) {
-			if (max_charge > max_energy / full.intval)
-				main_battery = max_charge_bat;
+				main_battery = bp.max_charge_bat;
+		} else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN,
+								  &bp.full)) {
+			if (bp.max_charge > bp.max_energy / bp.full.intval)
+				main_battery = bp.max_charge_bat;
 			else
-				main_battery = max_energy_bat;
+				main_battery = bp.max_energy_bat;
 		} else {
 			/* give up, choice any */
-			main_battery = max_energy_bat;
+			main_battery = bp.max_energy_bat;
 		}
-	} else if (max_charge_bat) {
-		main_battery = max_charge_bat;
-	} else if (max_energy_bat) {
-		main_battery = max_energy_bat;
+	} else if (bp.max_charge_bat) {
+		main_battery = bp.max_charge_bat;
+	} else if (bp.max_energy_bat) {
+		main_battery = bp.max_energy_bat;
 	} else {
 		/* give up, try the last if any */
-		main_battery = bat;
+		main_battery = bp.bat;
 	}
 }
 
@@ -207,10 +227,10 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
 	union power_supply_propval status;
 	union power_supply_propval capacity, time_to_full, time_to_empty;
 
-	down(&power_supply_class->sem);
+	mutex_lock(&apm_mutex);
 	find_main_battery();
 	if (!main_battery) {
-		up(&power_supply_class->sem);
+		mutex_unlock(&apm_mutex);
 		return;
 	}
 
@@ -278,7 +298,7 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
 		}
 	}
 
-	up(&power_supply_class->sem);
+	mutex_unlock(&apm_mutex);
 }
 
 static int __init apm_battery_init(void)
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index a63b75cf75e2..03d6a38464ef 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -20,28 +20,29 @@
 
 struct class *power_supply_class;
 
+static int __power_supply_changed_work(struct device *dev, void *data)
+{
+	struct power_supply *psy = (struct power_supply *)data;
+	struct power_supply *pst = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < psy->num_supplicants; i++)
+		if (!strcmp(psy->supplied_to[i], pst->name)) {
+			if (pst->external_power_changed)
+				pst->external_power_changed(pst);
+		}
+	return 0;
+}
+
 static void power_supply_changed_work(struct work_struct *work)
 {
 	struct power_supply *psy = container_of(work, struct power_supply,
 						changed_work);
-	int i;
 
 	dev_dbg(psy->dev, "%s\n", __FUNCTION__);
 
-	for (i = 0; i < psy->num_supplicants; i++) {
-		struct device *dev;
-
-		down(&power_supply_class->sem);
-		list_for_each_entry(dev, &power_supply_class->devices, node) {
-			struct power_supply *pst = dev_get_drvdata(dev);
-
-			if (!strcmp(psy->supplied_to[i], pst->name)) {
-				if (pst->external_power_changed)
-					pst->external_power_changed(pst);
-			}
-		}
-		up(&power_supply_class->sem);
-	}
+	class_for_each_device(power_supply_class, psy,
+			      __power_supply_changed_work);
 
 	power_supply_update_leds(psy);
 
@@ -55,32 +56,35 @@ void power_supply_changed(struct power_supply *psy)
 	schedule_work(&psy->changed_work);
 }
 
-int power_supply_am_i_supplied(struct power_supply *psy)
+static int __power_supply_am_i_supplied(struct device *dev, void *data)
 {
 	union power_supply_propval ret = {0,};
-	struct device *dev;
-
-	down(&power_supply_class->sem);
-	list_for_each_entry(dev, &power_supply_class->devices, node) {
-		struct power_supply *epsy = dev_get_drvdata(dev);
-		int i;
-
-		for (i = 0; i < epsy->num_supplicants; i++) {
-			if (!strcmp(epsy->supplied_to[i], psy->name)) {
-				if (epsy->get_property(epsy,
-					  POWER_SUPPLY_PROP_ONLINE, &ret))
-					continue;
-				if (ret.intval)
-					goto out;
-			}
+	struct power_supply *psy = (struct power_supply *)data;
+	struct power_supply *epsy = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < epsy->num_supplicants; i++) {
+		if (!strcmp(epsy->supplied_to[i], psy->name)) {
+			if (epsy->get_property(epsy,
+				  POWER_SUPPLY_PROP_ONLINE, &ret))
+				continue;
+			if (ret.intval)
+				return ret.intval;
 		}
 	}
-out:
-	up(&power_supply_class->sem);
+	return 0;
+}
+
+int power_supply_am_i_supplied(struct power_supply *psy)
+{
+	int error;
+
+	error = class_for_each_device(power_supply_class, psy,
+				      __power_supply_am_i_supplied);
 
-	dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval);
+	dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error);
 
-	return ret.intval;
+	return error;
 }
 
 int power_supply_register(struct device *parent, struct power_supply *psy)
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h
index b242cee656e7..80e3f03b5041 100644
--- a/drivers/rapidio/rio.h
+++ b/drivers/rapidio/rio.h
@@ -31,8 +31,8 @@ extern struct rio_route_ops __end_rio_route_ops[];
 
 /* Helpers internal to the RIO core code */
 #define DECLARE_RIO_ROUTE_SECTION(section, vid, did, add_hook, get_hook)  \
-        static struct rio_route_ops __rio_route_ops __attribute_used__   \
-	        __attribute__((__section__(#section))) = { vid, did, add_hook, get_hook };
+	static struct rio_route_ops __rio_route_ops __used   \
+	__section(section)= { vid, did, add_hook, get_hook };
 
 /**
  * DECLARE_RIO_ROUTE_OPS - Registers switch routing operations
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 1e6715ec51ef..45e4b9648176 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -404,7 +404,7 @@ config RTC_DRV_SA1100
 
 config RTC_DRV_SH
 	tristate "SuperH On-Chip RTC"
-	depends on RTC_CLASS && (CPU_SH3 || CPU_SH4)
+	depends on RTC_CLASS && SUPERH
 	help
 	  Say Y here to enable support for the on-chip RTC found in
 	  most SuperH processors.
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index f1e00ff54ce8..7e3ad4f3b343 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -251,20 +251,23 @@ void rtc_update_irq(struct rtc_device *rtc,
 }
 EXPORT_SYMBOL_GPL(rtc_update_irq);
 
+static int __rtc_match(struct device *dev, void *data)
+{
+	char *name = (char *)data;
+
+	if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0)
+		return 1;
+	return 0;
+}
+
 struct rtc_device *rtc_class_open(char *name)
 {
 	struct device *dev;
 	struct rtc_device *rtc = NULL;
 
-	down(&rtc_class->sem);
-	list_for_each_entry(dev, &rtc_class->devices, node) {
-		if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) {
-			dev = get_device(dev);
-			if (dev)
-				rtc = to_rtc_device(dev);
-			break;
-		}
-	}
+	dev = class_find_device(rtc_class, name, __rtc_match);
+	if (dev)
+		rtc = to_rtc_device(dev);
 
 	if (rtc) {
 		if (!try_module_get(rtc->owner)) {
@@ -272,7 +275,6 @@ struct rtc_device *rtc_class_open(char *name)
 			rtc = NULL;
 		}
 	}
-	up(&rtc_class->sem);
 
 	return rtc;
 }
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index dfef1637bfb8..e0900ca678ec 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -16,7 +16,7 @@
 #define DRV_VERSION "0.3"
 
 /* Addresses to scan: none. This chip cannot be detected. */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD;
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index 1c743641b73b..725b0c73c333 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -61,7 +61,7 @@
 /* i2c configuration */
 #define ISL1208_I2C_ADDR 0xde
 
-static unsigned short normal_i2c[] = {
+static const unsigned short normal_i2c[] = {
 	ISL1208_I2C_ADDR>>1, I2C_CLIENT_END
 };
 I2C_CLIENT_INSMOD; /* defines addr_data */
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index a1cd448639c9..7683412970c4 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -54,7 +54,7 @@
 
 #define MAX6900_I2C_ADDR		0xa0
 
-static unsigned short normal_i2c[] = {
+static const unsigned short normal_i2c[] = {
 	MAX6900_I2C_ADDR >> 1,
 	I2C_CLIENT_END
 };
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 0242d803ebe5..b3317fcc16c3 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -25,7 +25,7 @@
  * located at 0x51 will pass the validation routine due to
  * the way the registers are implemented.
  */
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 /* Module parameters */
 I2C_CLIENT_INSMOD;
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 556d0e7da35b..c973ba94c422 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -40,7 +40,7 @@ struct pcf8583 {
 #define CTRL_ALARM	0x02
 #define CTRL_TIMER	0x01
 
-static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END };
 
 /* Module parameters */
 I2C_CLIENT_INSMOD;
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 6f1e9a9804bc..2eb38520f0c8 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -337,6 +337,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
 	if (IS_ERR(rtc))
 		return PTR_ERR(rtc);
 
+	device_init_wakeup(&pdev->dev, 1);
+
 	platform_set_drvdata(pdev, rtc);
 
 	return 0;
@@ -352,9 +354,38 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	if (pdev->dev.power.power_state.event != state.event) {
+		if (state.event == PM_EVENT_SUSPEND &&
+		    device_may_wakeup(&pdev->dev))
+			enable_irq_wake(IRQ_RTCAlrm);
+
+		pdev->dev.power.power_state = state;
+	}
+	return 0;
+}
+
+static int sa1100_rtc_resume(struct platform_device *pdev)
+{
+	if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
+		if (device_may_wakeup(&pdev->dev))
+			disable_irq_wake(IRQ_RTCAlrm);
+		pdev->dev.power.power_state = PMSG_ON;
+	}
+	return 0;
+}
+#else
+#define sa1100_rtc_suspend	NULL
+#define sa1100_rtc_resume	NULL
+#endif
+
 static struct platform_driver sa1100_rtc_driver = {
 	.probe		= sa1100_rtc_probe,
 	.remove		= sa1100_rtc_remove,
+	.suspend	= sa1100_rtc_suspend,
+	.resume		= sa1100_rtc_resume,
 	.driver		= {
 		.name		= "sa1100-rtc",
 	},
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 8e8c8b8e81ee..c1d6a1880ccf 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -26,17 +26,7 @@
 #include <asm/rtc.h>
 
 #define DRV_NAME	"sh-rtc"
-#define DRV_VERSION	"0.1.3"
-
-#ifdef CONFIG_CPU_SH3
-#define rtc_reg_size		sizeof(u16)
-#define RTC_BIT_INVERTED	0	/* No bug on SH7708, SH7709A */
-#define RTC_DEF_CAPABILITIES	0UL
-#elif defined(CONFIG_CPU_SH4)
-#define rtc_reg_size		sizeof(u32)
-#define RTC_BIT_INVERTED	0x40	/* bug on SH7750, SH7750S */
-#define RTC_DEF_CAPABILITIES	RTC_CAP_4_DIGIT_YEAR
-#endif
+#define DRV_VERSION	"0.1.6"
 
 #define RTC_REG(r)	((r) * rtc_reg_size)
 
@@ -58,6 +48,18 @@
 #define RCR1		RTC_REG(14)	/* Control */
 #define RCR2		RTC_REG(15)	/* Control */
 
+/*
+ * Note on RYRAR and RCR3: Up until this point most of the register
+ * definitions are consistent across all of the available parts. However,
+ * the placement of the optional RYRAR and RCR3 (the RYRAR control
+ * register used to control RYRCNT/RYRAR compare) varies considerably
+ * across various parts, occasionally being mapped in to a completely
+ * unrelated address space. For proper RYRAR support a separate resource
+ * would have to be handed off, but as this is purely optional in
+ * practice, we simply opt not to support it, thereby keeping the code
+ * quite a bit more simplified.
+ */
+
 /* ALARM Bits - or with BCD encoded value */
 #define AR_ENB		0x80	/* Enable for alarm cmp   */
 
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index b3fae357ca49..b90fb1866ce9 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -32,7 +32,7 @@
  * unknown chips, the user must explicitly set the probe parameter.
  */
 
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 /* Insmod parameters */
 I2C_CLIENT_INSMOD;
diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile
index be9f22d52fd8..0a89e080b389 100644
--- a/drivers/s390/block/Makefile
+++ b/drivers/s390/block/Makefile
@@ -2,8 +2,8 @@
 # S/390 block devices
 #
 
-dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
-dasd_fba_mod-objs  := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
+dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_alias.o
+dasd_fba_mod-objs  := dasd_fba.o
 dasd_diag_mod-objs := dasd_diag.o
 dasd_mod-objs      := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
 			dasd_genhd.o dasd_erp.o
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index e6bfce690ca3..d640427c74c8 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -48,13 +48,15 @@ MODULE_LICENSE("GPL");
 /*
  * SECTION: prototypes for static functions of dasd.c
  */
-static int  dasd_alloc_queue(struct dasd_device * device);
-static void dasd_setup_queue(struct dasd_device * device);
-static void dasd_free_queue(struct dasd_device * device);
-static void dasd_flush_request_queue(struct dasd_device *);
-static int dasd_flush_ccw_queue(struct dasd_device *, int);
-static void dasd_tasklet(struct dasd_device *);
+static int  dasd_alloc_queue(struct dasd_block *);
+static void dasd_setup_queue(struct dasd_block *);
+static void dasd_free_queue(struct dasd_block *);
+static void dasd_flush_request_queue(struct dasd_block *);
+static int dasd_flush_block_queue(struct dasd_block *);
+static void dasd_device_tasklet(struct dasd_device *);
+static void dasd_block_tasklet(struct dasd_block *);
 static void do_kick_device(struct work_struct *);
+static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
 
 /*
  * SECTION: Operations on the device structure.
@@ -65,26 +67,23 @@ static wait_queue_head_t dasd_flush_wq;
 /*
  * Allocate memory for a new device structure.
  */
-struct dasd_device *
-dasd_alloc_device(void)
+struct dasd_device *dasd_alloc_device(void)
 {
 	struct dasd_device *device;
 
-	device = kzalloc(sizeof (struct dasd_device), GFP_ATOMIC);
-	if (device == NULL)
+	device = kzalloc(sizeof(struct dasd_device), GFP_ATOMIC);
+	if (!device)
 		return ERR_PTR(-ENOMEM);
-	/* open_count = 0 means device online but not in use */
-	atomic_set(&device->open_count, -1);
 
 	/* Get two pages for normal block device operations. */
 	device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
-	if (device->ccw_mem == NULL) {
+	if (!device->ccw_mem) {
 		kfree(device);
 		return ERR_PTR(-ENOMEM);
 	}
 	/* Get one page for error recovery. */
 	device->erp_mem = (void *) get_zeroed_page(GFP_ATOMIC | GFP_DMA);
-	if (device->erp_mem == NULL) {
+	if (!device->erp_mem) {
 		free_pages((unsigned long) device->ccw_mem, 1);
 		kfree(device);
 		return ERR_PTR(-ENOMEM);
@@ -93,10 +92,9 @@ dasd_alloc_device(void)
 	dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
 	dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
 	spin_lock_init(&device->mem_lock);
-	spin_lock_init(&device->request_queue_lock);
-	atomic_set (&device->tasklet_scheduled, 0);
+	atomic_set(&device->tasklet_scheduled, 0);
 	tasklet_init(&device->tasklet,
-		     (void (*)(unsigned long)) dasd_tasklet,
+		     (void (*)(unsigned long)) dasd_device_tasklet,
 		     (unsigned long) device);
 	INIT_LIST_HEAD(&device->ccw_queue);
 	init_timer(&device->timer);
@@ -110,8 +108,7 @@ dasd_alloc_device(void)
 /*
  * Free memory of a device structure.
  */
-void
-dasd_free_device(struct dasd_device *device)
+void dasd_free_device(struct dasd_device *device)
 {
 	kfree(device->private);
 	free_page((unsigned long) device->erp_mem);
@@ -120,10 +117,42 @@ dasd_free_device(struct dasd_device *device)
 }
 
 /*
+ * Allocate memory for a new device structure.
+ */
+struct dasd_block *dasd_alloc_block(void)
+{
+	struct dasd_block *block;
+
+	block = kzalloc(sizeof(*block), GFP_ATOMIC);
+	if (!block)
+		return ERR_PTR(-ENOMEM);
+	/* open_count = 0 means device online but not in use */
+	atomic_set(&block->open_count, -1);
+
+	spin_lock_init(&block->request_queue_lock);
+	atomic_set(&block->tasklet_scheduled, 0);
+	tasklet_init(&block->tasklet,
+		     (void (*)(unsigned long)) dasd_block_tasklet,
+		     (unsigned long) block);
+	INIT_LIST_HEAD(&block->ccw_queue);
+	spin_lock_init(&block->queue_lock);
+	init_timer(&block->timer);
+
+	return block;
+}
+
+/*
+ * Free memory of a device structure.
+ */
+void dasd_free_block(struct dasd_block *block)
+{
+	kfree(block);
+}
+
+/*
  * Make a new device known to the system.
  */
-static int
-dasd_state_new_to_known(struct dasd_device *device)
+static int dasd_state_new_to_known(struct dasd_device *device)
 {
 	int rc;
 
@@ -133,12 +162,13 @@ dasd_state_new_to_known(struct dasd_device *device)
 	 */
 	dasd_get_device(device);
 
-	rc = dasd_alloc_queue(device);
-	if (rc) {
-		dasd_put_device(device);
-		return rc;
+	if (device->block) {
+		rc = dasd_alloc_queue(device->block);
+		if (rc) {
+			dasd_put_device(device);
+			return rc;
+		}
 	}
-
 	device->state = DASD_STATE_KNOWN;
 	return 0;
 }
@@ -146,21 +176,24 @@ dasd_state_new_to_known(struct dasd_device *device)
 /*
  * Let the system forget about a device.
  */
-static int
-dasd_state_known_to_new(struct dasd_device * device)
+static int dasd_state_known_to_new(struct dasd_device *device)
 {
 	/* Disable extended error reporting for this device. */
 	dasd_eer_disable(device);
 	/* Forget the discipline information. */
-	if (device->discipline)
+	if (device->discipline) {
+		if (device->discipline->uncheck_device)
+			device->discipline->uncheck_device(device);
 		module_put(device->discipline->owner);
+	}
 	device->discipline = NULL;
 	if (device->base_discipline)
 		module_put(device->base_discipline->owner);
 	device->base_discipline = NULL;
 	device->state = DASD_STATE_NEW;
 
-	dasd_free_queue(device);
+	if (device->block)
+		dasd_free_queue(device->block);
 
 	/* Give up reference we took in dasd_state_new_to_known. */
 	dasd_put_device(device);
@@ -170,19 +203,19 @@ dasd_state_known_to_new(struct dasd_device * device)
 /*
  * Request the irq line for the device.
  */
-static int
-dasd_state_known_to_basic(struct dasd_device * device)
+static int dasd_state_known_to_basic(struct dasd_device *device)
 {
 	int rc;
 
 	/* Allocate and register gendisk structure. */
-	rc = dasd_gendisk_alloc(device);
-	if (rc)
-		return rc;
-
+	if (device->block) {
+		rc = dasd_gendisk_alloc(device->block);
+		if (rc)
+			return rc;
+	}
 	/* register 'device' debug area, used for all DBF_DEV_XXX calls */
-	device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2,
-					    8 * sizeof (long));
+	device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 1,
+					    8 * sizeof(long));
 	debug_register_view(device->debug_area, &debug_sprintf_view);
 	debug_set_level(device->debug_area, DBF_WARNING);
 	DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
@@ -194,16 +227,17 @@ dasd_state_known_to_basic(struct dasd_device * device)
 /*
  * Release the irq line for the device. Terminate any running i/o.
  */
-static int
-dasd_state_basic_to_known(struct dasd_device * device)
+static int dasd_state_basic_to_known(struct dasd_device *device)
 {
 	int rc;
-
-	dasd_gendisk_free(device);
-	rc = dasd_flush_ccw_queue(device, 1);
+	if (device->block) {
+		dasd_gendisk_free(device->block);
+		dasd_block_clear_timer(device->block);
+	}
+	rc = dasd_flush_device_queue(device);
 	if (rc)
 		return rc;
-	dasd_clear_timer(device);
+	dasd_device_clear_timer(device);
 
 	DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
 	if (device->debug_area != NULL) {
@@ -228,26 +262,32 @@ dasd_state_basic_to_known(struct dasd_device * device)
  * In case the analysis returns an error, the device setup is stopped
  * (a fake disk was already added to allow formatting).
  */
-static int
-dasd_state_basic_to_ready(struct dasd_device * device)
+static int dasd_state_basic_to_ready(struct dasd_device *device)
 {
 	int rc;
+	struct dasd_block *block;
 
 	rc = 0;
-	if (device->discipline->do_analysis != NULL)
-		rc = device->discipline->do_analysis(device);
-	if (rc) {
-		if (rc != -EAGAIN)
-			device->state = DASD_STATE_UNFMT;
-		return rc;
-	}
+	block = device->block;
 	/* make disk known with correct capacity */
-	dasd_setup_queue(device);
-	set_capacity(device->gdp, device->blocks << device->s2b_shift);
-	device->state = DASD_STATE_READY;
-	rc = dasd_scan_partitions(device);
-	if (rc)
-		device->state = DASD_STATE_BASIC;
+	if (block) {
+		if (block->base->discipline->do_analysis != NULL)
+			rc = block->base->discipline->do_analysis(block);
+		if (rc) {
+			if (rc != -EAGAIN)
+				device->state = DASD_STATE_UNFMT;
+			return rc;
+		}
+		dasd_setup_queue(block);
+		set_capacity(block->gdp,
+			     block->blocks << block->s2b_shift);
+		device->state = DASD_STATE_READY;
+		rc = dasd_scan_partitions(block);
+		if (rc)
+			device->state = DASD_STATE_BASIC;
+	} else {
+		device->state = DASD_STATE_READY;
+	}
 	return rc;
 }
 
@@ -256,28 +296,31 @@ dasd_state_basic_to_ready(struct dasd_device * device)
  * Forget format information. Check if the target level is basic
  * and if it is create fake disk for formatting.
  */
-static int
-dasd_state_ready_to_basic(struct dasd_device * device)
+static int dasd_state_ready_to_basic(struct dasd_device *device)
 {
 	int rc;
 
-	rc = dasd_flush_ccw_queue(device, 0);
-	if (rc)
-		return rc;
-	dasd_destroy_partitions(device);
-	dasd_flush_request_queue(device);
-	device->blocks = 0;
-	device->bp_block = 0;
-	device->s2b_shift = 0;
 	device->state = DASD_STATE_BASIC;
+	if (device->block) {
+		struct dasd_block *block = device->block;
+		rc = dasd_flush_block_queue(block);
+		if (rc) {
+			device->state = DASD_STATE_READY;
+			return rc;
+		}
+		dasd_destroy_partitions(block);
+		dasd_flush_request_queue(block);
+		block->blocks = 0;
+		block->bp_block = 0;
+		block->s2b_shift = 0;
+	}
 	return 0;
 }
 
 /*
  * Back to basic.
  */
-static int
-dasd_state_unfmt_to_basic(struct dasd_device * device)
+static int dasd_state_unfmt_to_basic(struct dasd_device *device)
 {
 	device->state = DASD_STATE_BASIC;
 	return 0;
@@ -291,17 +334,31 @@ dasd_state_unfmt_to_basic(struct dasd_device * device)
 static int
 dasd_state_ready_to_online(struct dasd_device * device)
 {
+	int rc;
+
+	if (device->discipline->ready_to_online) {
+		rc = device->discipline->ready_to_online(device);
+		if (rc)
+			return rc;
+	}
 	device->state = DASD_STATE_ONLINE;
-	dasd_schedule_bh(device);
+	if (device->block)
+		dasd_schedule_block_bh(device->block);
 	return 0;
 }
 
 /*
  * Stop the requeueing of requests again.
  */
-static int
-dasd_state_online_to_ready(struct dasd_device * device)
+static int dasd_state_online_to_ready(struct dasd_device *device)
 {
+	int rc;
+
+	if (device->discipline->online_to_ready) {
+		rc = device->discipline->online_to_ready(device);
+		if (rc)
+			return rc;
+	}
 	device->state = DASD_STATE_READY;
 	return 0;
 }
@@ -309,8 +366,7 @@ dasd_state_online_to_ready(struct dasd_device * device)
 /*
  * Device startup state changes.
  */
-static int
-dasd_increase_state(struct dasd_device *device)
+static int dasd_increase_state(struct dasd_device *device)
 {
 	int rc;
 
@@ -345,8 +401,7 @@ dasd_increase_state(struct dasd_device *device)
 /*
  * Device shutdown state changes.
  */
-static int
-dasd_decrease_state(struct dasd_device *device)
+static int dasd_decrease_state(struct dasd_device *device)
 {
 	int rc;
 
@@ -381,8 +436,7 @@ dasd_decrease_state(struct dasd_device *device)
 /*
  * This is the main startup/shutdown routine.
  */
-static void
-dasd_change_state(struct dasd_device *device)
+static void dasd_change_state(struct dasd_device *device)
 {
         int rc;
 
@@ -409,17 +463,15 @@ dasd_change_state(struct dasd_device *device)
  * dasd_kick_device will schedule a call do do_kick_device to the kernel
  * event daemon.
  */
-static void
-do_kick_device(struct work_struct *work)
+static void do_kick_device(struct work_struct *work)
 {
 	struct dasd_device *device = container_of(work, struct dasd_device, kick_work);
 	dasd_change_state(device);
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 	dasd_put_device(device);
 }
 
-void
-dasd_kick_device(struct dasd_device *device)
+void dasd_kick_device(struct dasd_device *device)
 {
 	dasd_get_device(device);
 	/* queue call to dasd_kick_device to the kernel event daemon. */
@@ -429,8 +481,7 @@ dasd_kick_device(struct dasd_device *device)
 /*
  * Set the target state for a device and starts the state change.
  */
-void
-dasd_set_target_state(struct dasd_device *device, int target)
+void dasd_set_target_state(struct dasd_device *device, int target)
 {
 	/* If we are in probeonly mode stop at DASD_STATE_READY. */
 	if (dasd_probeonly && target > DASD_STATE_READY)
@@ -447,14 +498,12 @@ dasd_set_target_state(struct dasd_device *device, int target)
 /*
  * Enable devices with device numbers in [from..to].
  */
-static inline int
-_wait_for_device(struct dasd_device *device)
+static inline int _wait_for_device(struct dasd_device *device)
 {
 	return (device->state == device->target);
 }
 
-void
-dasd_enable_device(struct dasd_device *device)
+void dasd_enable_device(struct dasd_device *device)
 {
 	dasd_set_target_state(device, DASD_STATE_ONLINE);
 	if (device->state <= DASD_STATE_KNOWN)
@@ -475,20 +524,20 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF;
 /*
  * Increments counter in global and local profiling structures.
  */
-#define dasd_profile_counter(value, counter, device) \
+#define dasd_profile_counter(value, counter, block) \
 { \
 	int index; \
 	for (index = 0; index < 31 && value >> (2+index); index++); \
 	dasd_global_profile.counter[index]++; \
-	device->profile.counter[index]++; \
+	block->profile.counter[index]++; \
 }
 
 /*
  * Add profiling information for cqr before execution.
  */
-static void
-dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
-		   struct request *req)
+static void dasd_profile_start(struct dasd_block *block,
+			       struct dasd_ccw_req *cqr,
+			       struct request *req)
 {
 	struct list_head *l;
 	unsigned int counter;
@@ -498,19 +547,19 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
 
 	/* count the length of the chanq for statistics */
 	counter = 0;
-	list_for_each(l, &device->ccw_queue)
+	list_for_each(l, &block->ccw_queue)
 		if (++counter >= 31)
 			break;
 	dasd_global_profile.dasd_io_nr_req[counter]++;
-	device->profile.dasd_io_nr_req[counter]++;
+	block->profile.dasd_io_nr_req[counter]++;
 }
 
 /*
  * Add profiling information for cqr after execution.
  */
-static void
-dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
-		 struct request *req)
+static void dasd_profile_end(struct dasd_block *block,
+			     struct dasd_ccw_req *cqr,
+			     struct request *req)
 {
 	long strtime, irqtime, endtime, tottime;	/* in microseconds */
 	long tottimeps, sectors;
@@ -532,27 +581,27 @@ dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
 
 	if (!dasd_global_profile.dasd_io_reqs)
 		memset(&dasd_global_profile, 0,
-		       sizeof (struct dasd_profile_info_t));
+		       sizeof(struct dasd_profile_info_t));
 	dasd_global_profile.dasd_io_reqs++;
 	dasd_global_profile.dasd_io_sects += sectors;
 
-	if (!device->profile.dasd_io_reqs)
-		memset(&device->profile, 0,
-		       sizeof (struct dasd_profile_info_t));
-	device->profile.dasd_io_reqs++;
-	device->profile.dasd_io_sects += sectors;
+	if (!block->profile.dasd_io_reqs)
+		memset(&block->profile, 0,
+		       sizeof(struct dasd_profile_info_t));
+	block->profile.dasd_io_reqs++;
+	block->profile.dasd_io_sects += sectors;
 
-	dasd_profile_counter(sectors, dasd_io_secs, device);
-	dasd_profile_counter(tottime, dasd_io_times, device);
-	dasd_profile_counter(tottimeps, dasd_io_timps, device);
-	dasd_profile_counter(strtime, dasd_io_time1, device);
-	dasd_profile_counter(irqtime, dasd_io_time2, device);
-	dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, device);
-	dasd_profile_counter(endtime, dasd_io_time3, device);
+	dasd_profile_counter(sectors, dasd_io_secs, block);
+	dasd_profile_counter(tottime, dasd_io_times, block);
+	dasd_profile_counter(tottimeps, dasd_io_timps, block);
+	dasd_profile_counter(strtime, dasd_io_time1, block);
+	dasd_profile_counter(irqtime, dasd_io_time2, block);
+	dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, block);
+	dasd_profile_counter(endtime, dasd_io_time3, block);
 }
 #else
-#define dasd_profile_start(device, cqr, req) do {} while (0)
-#define dasd_profile_end(device, cqr, req) do {} while (0)
+#define dasd_profile_start(block, cqr, req) do {} while (0)
+#define dasd_profile_end(block, cqr, req) do {} while (0)
 #endif				/* CONFIG_DASD_PROFILE */
 
 /*
@@ -562,9 +611,9 @@ dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
  * memory and 2) dasd_smalloc_request uses the static ccw memory
  * that gets allocated for each device.
  */
-struct dasd_ccw_req *
-dasd_kmalloc_request(char *magic, int cplength, int datasize,
-		   struct dasd_device * device)
+struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength,
+					  int datasize,
+					  struct dasd_device *device)
 {
 	struct dasd_ccw_req *cqr;
 
@@ -600,9 +649,9 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize,
 	return cqr;
 }
 
-struct dasd_ccw_req *
-dasd_smalloc_request(char *magic, int cplength, int datasize,
-		   struct dasd_device * device)
+struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength,
+					  int datasize,
+					  struct dasd_device *device)
 {
 	unsigned long flags;
 	struct dasd_ccw_req *cqr;
@@ -649,8 +698,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize,
  * idal lists that might have been created by dasd_set_cda and the
  * struct dasd_ccw_req itself.
  */
-void
-dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+void dasd_kfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 {
 #ifdef CONFIG_64BIT
 	struct ccw1 *ccw;
@@ -667,8 +715,7 @@ dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
 	dasd_put_device(device);
 }
 
-void
-dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 {
 	unsigned long flags;
 
@@ -681,14 +728,13 @@ dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
 /*
  * Check discipline magic in cqr.
  */
-static inline int
-dasd_check_cqr(struct dasd_ccw_req *cqr)
+static inline int dasd_check_cqr(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 
 	if (cqr == NULL)
 		return -EINVAL;
-	device = cqr->device;
+	device = cqr->startdev;
 	if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) {
 		DEV_MESSAGE(KERN_WARNING, device,
 			    " dasd_ccw_req 0x%08x magic doesn't match"
@@ -706,8 +752,7 @@ dasd_check_cqr(struct dasd_ccw_req *cqr)
  * ccw_device_clear can fail if the i/o subsystem
  * is in a bad mood.
  */
-int
-dasd_term_IO(struct dasd_ccw_req * cqr)
+int dasd_term_IO(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 	int retries, rc;
@@ -717,13 +762,13 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
 	if (rc)
 		return rc;
 	retries = 0;
-	device = (struct dasd_device *) cqr->device;
+	device = (struct dasd_device *) cqr->startdev;
 	while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
 		rc = ccw_device_clear(device->cdev, (long) cqr);
 		switch (rc) {
 		case 0:	/* termination successful */
 			cqr->retries--;
-			cqr->status = DASD_CQR_CLEAR;
+			cqr->status = DASD_CQR_CLEAR_PENDING;
 			cqr->stopclk = get_clock();
 			cqr->starttime = 0;
 			DBF_DEV_EVENT(DBF_DEBUG, device,
@@ -753,7 +798,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
 		}
 		retries++;
 	}
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 	return rc;
 }
 
@@ -761,8 +806,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
  * Start the i/o. This start_IO can fail if the channel is really busy.
  * In that case set up a timer to start the request later.
  */
-int
-dasd_start_IO(struct dasd_ccw_req * cqr)
+int dasd_start_IO(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 	int rc;
@@ -771,12 +815,12 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
 	rc = dasd_check_cqr(cqr);
 	if (rc)
 		return rc;
-	device = (struct dasd_device *) cqr->device;
+	device = (struct dasd_device *) cqr->startdev;
 	if (cqr->retries < 0) {
 		DEV_MESSAGE(KERN_DEBUG, device,
 			    "start_IO: request %p (%02x/%i) - no retry left.",
 			    cqr, cqr->status, cqr->retries);
-		cqr->status = DASD_CQR_FAILED;
+		cqr->status = DASD_CQR_ERROR;
 		return -EIO;
 	}
 	cqr->startclk = get_clock();
@@ -833,8 +877,7 @@ dasd_start_IO(struct dasd_ccw_req * cqr)
  * The head of the ccw queue will have status DASD_CQR_IN_IO for 1),
  * DASD_CQR_QUEUED for 2) and 3).
  */
-static void
-dasd_timeout_device(unsigned long ptr)
+static void dasd_device_timeout(unsigned long ptr)
 {
 	unsigned long flags;
 	struct dasd_device *device;
@@ -844,14 +887,13 @@ dasd_timeout_device(unsigned long ptr)
 	/* re-activate request queue */
         device->stopped &= ~DASD_STOPPED_PENDING;
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 }
 
 /*
  * Setup timeout for a device in jiffies.
  */
-void
-dasd_set_timer(struct dasd_device *device, int expires)
+void dasd_device_set_timer(struct dasd_device *device, int expires)
 {
 	if (expires == 0) {
 		if (timer_pending(&device->timer))
@@ -862,7 +904,7 @@ dasd_set_timer(struct dasd_device *device, int expires)
 		if (mod_timer(&device->timer, jiffies + expires))
 			return;
 	}
-	device->timer.function = dasd_timeout_device;
+	device->timer.function = dasd_device_timeout;
 	device->timer.data = (unsigned long) device;
 	device->timer.expires = jiffies + expires;
 	add_timer(&device->timer);
@@ -871,15 +913,14 @@ dasd_set_timer(struct dasd_device *device, int expires)
 /*
  * Clear timeout for a device.
  */
-void
-dasd_clear_timer(struct dasd_device *device)
+void dasd_device_clear_timer(struct dasd_device *device)
 {
 	if (timer_pending(&device->timer))
 		del_timer(&device->timer);
 }
 
-static void
-dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
+static void dasd_handle_killed_request(struct ccw_device *cdev,
+				       unsigned long intparm)
 {
 	struct dasd_ccw_req *cqr;
 	struct dasd_device *device;
@@ -893,7 +934,7 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
 		return;
 	}
 
-	device = (struct dasd_device *) cqr->device;
+	device = (struct dasd_device *) cqr->startdev;
 	if (device == NULL ||
 	    device != dasd_device_from_cdev_locked(cdev) ||
 	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
@@ -905,46 +946,32 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
 	/* Schedule request to be retried. */
 	cqr->status = DASD_CQR_QUEUED;
 
-	dasd_clear_timer(device);
-	dasd_schedule_bh(device);
+	dasd_device_clear_timer(device);
+	dasd_schedule_device_bh(device);
 	dasd_put_device(device);
 }
 
-static void
-dasd_handle_state_change_pending(struct dasd_device *device)
+void dasd_generic_handle_state_change(struct dasd_device *device)
 {
-	struct dasd_ccw_req *cqr;
-	struct list_head *l, *n;
-
 	/* First of all start sense subsystem status request. */
 	dasd_eer_snss(device);
 
 	device->stopped &= ~DASD_STOPPED_PENDING;
-
-        /* restart all 'running' IO on queue */
-	list_for_each_safe(l, n, &device->ccw_queue) {
-		cqr = list_entry(l, struct dasd_ccw_req, list);
-                if (cqr->status == DASD_CQR_IN_IO) {
-                        cqr->status = DASD_CQR_QUEUED;
-		}
-        }
-	dasd_clear_timer(device);
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
+	if (device->block)
+		dasd_schedule_block_bh(device->block);
 }
 
 /*
  * Interrupt handler for "normal" ssch-io based dasd devices.
  */
-void
-dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
-		 struct irb *irb)
+void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
+		      struct irb *irb)
 {
 	struct dasd_ccw_req *cqr, *next;
 	struct dasd_device *device;
 	unsigned long long now;
 	int expires;
-	dasd_era_t era;
-	char mask;
 
 	if (IS_ERR(irb)) {
 		switch (PTR_ERR(irb)) {
@@ -969,29 +996,25 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
 		  cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat),
 		  (unsigned int) intparm);
 
-	/* first of all check for state change pending interrupt */
-	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
-	if ((irb->scsw.dstat & mask) == mask) {
+	/* check for unsolicited interrupts */
+	cqr = (struct dasd_ccw_req *) intparm;
+	if (!cqr || ((irb->scsw.cc == 1) &&
+		     (irb->scsw.fctl & SCSW_FCTL_START_FUNC) &&
+		     (irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) ) {
+		if (cqr && cqr->status == DASD_CQR_IN_IO)
+			cqr->status = DASD_CQR_QUEUED;
 		device = dasd_device_from_cdev_locked(cdev);
 		if (!IS_ERR(device)) {
-			dasd_handle_state_change_pending(device);
+			dasd_device_clear_timer(device);
+			device->discipline->handle_unsolicited_interrupt(device,
+									 irb);
 			dasd_put_device(device);
 		}
 		return;
 	}
 
-	cqr = (struct dasd_ccw_req *) intparm;
-
-	/* check for unsolicited interrupts */
-	if (cqr == NULL) {
-		MESSAGE(KERN_DEBUG,
-			"unsolicited interrupt received: bus_id %s",
-			cdev->dev.bus_id);
-		return;
-	}
-
-	device = (struct dasd_device *) cqr->device;
-	if (device == NULL ||
+	device = (struct dasd_device *) cqr->startdev;
+	if (!device ||
 	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
 		MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
 			cdev->dev.bus_id);
@@ -999,12 +1022,12 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
 	}
 
 	/* Check for clear pending */
-	if (cqr->status == DASD_CQR_CLEAR &&
+	if (cqr->status == DASD_CQR_CLEAR_PENDING &&
 	    irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
-		cqr->status = DASD_CQR_QUEUED;
-		dasd_clear_timer(device);
+		cqr->status = DASD_CQR_CLEARED;
+		dasd_device_clear_timer(device);
 		wake_up(&dasd_flush_wq);
-		dasd_schedule_bh(device);
+		dasd_schedule_device_bh(device);
 		return;
 	}
 
@@ -1017,277 +1040,170 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
 	}
 	DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p",
 		      ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
-
- 	/* Find out the appropriate era_action. */
-	if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
-		era = dasd_era_fatal;
-	else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
-		 irb->scsw.cstat == 0 &&
-		 !irb->esw.esw0.erw.cons)
-		era = dasd_era_none;
-	else if (irb->esw.esw0.erw.cons)
-		era = device->discipline->examine_error(cqr, irb);
-	else
-		era = dasd_era_recover;
-
-	DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);
+	next = NULL;
 	expires = 0;
-	if (era == dasd_era_none) {
-		cqr->status = DASD_CQR_DONE;
+	if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
+	    irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) {
+		/* request was completed successfully */
+		cqr->status = DASD_CQR_SUCCESS;
 		cqr->stopclk = now;
 		/* Start first request on queue if possible -> fast_io. */
-		if (cqr->list.next != &device->ccw_queue) {
-			next = list_entry(cqr->list.next,
-					  struct dasd_ccw_req, list);
-			if ((next->status == DASD_CQR_QUEUED) &&
-			    (!device->stopped)) {
-				if (device->discipline->start_IO(next) == 0)
-					expires = next->expires;
-				else
-					DEV_MESSAGE(KERN_DEBUG, device, "%s",
-						    "Interrupt fastpath "
-						    "failed!");
-			}
+		if (cqr->devlist.next != &device->ccw_queue) {
+			next = list_entry(cqr->devlist.next,
+					  struct dasd_ccw_req, devlist);
 		}
-	} else {		/* error */
-		memcpy(&cqr->irb, irb, sizeof (struct irb));
+	} else {  /* error */
+		memcpy(&cqr->irb, irb, sizeof(struct irb));
 		if (device->features & DASD_FEATURE_ERPLOG) {
-			/* dump sense data */
 			dasd_log_sense(cqr, irb);
 		}
-		switch (era) {
-		case dasd_era_fatal:
-			cqr->status = DASD_CQR_FAILED;
-			cqr->stopclk = now;
-			break;
-		case dasd_era_recover:
+		/* If we have no sense data, or we just don't want complex ERP
+		 * for this request, but if we have retries left, then just
+		 * reset this request and retry it in the fastpath
+		 */
+		if (!(cqr->irb.esw.esw0.erw.cons &&
+		      test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) &&
+		    cqr->retries > 0) {
+			DEV_MESSAGE(KERN_DEBUG, device,
+				    "default ERP in fastpath (%i retries left)",
+				    cqr->retries);
+			cqr->lpm    = LPM_ANYPATH;
+			cqr->status = DASD_CQR_QUEUED;
+			next = cqr;
+		} else
 			cqr->status = DASD_CQR_ERROR;
-			break;
-		default:
-			BUG();
-		}
+	}
+	if (next && (next->status == DASD_CQR_QUEUED) &&
+	    (!device->stopped)) {
+		if (device->discipline->start_IO(next) == 0)
+			expires = next->expires;
+		else
+			DEV_MESSAGE(KERN_DEBUG, device, "%s",
+				    "Interrupt fastpath "
+				    "failed!");
 	}
 	if (expires != 0)
-		dasd_set_timer(device, expires);
+		dasd_device_set_timer(device, expires);
 	else
-		dasd_clear_timer(device);
-	dasd_schedule_bh(device);
+		dasd_device_clear_timer(device);
+	dasd_schedule_device_bh(device);
 }
 
 /*
- * posts the buffer_cache about a finalized request
+ * If we have an error on a dasd_block layer request then we cancel
+ * and return all further requests from the same dasd_block as well.
  */
-static inline void
-dasd_end_request(struct request *req, int uptodate)
+static void __dasd_device_recovery(struct dasd_device *device,
+				   struct dasd_ccw_req *ref_cqr)
 {
-	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
-		BUG();
-	add_disk_randomness(req->rq_disk);
-	end_that_request_last(req, uptodate);
-}
+	struct list_head *l, *n;
+	struct dasd_ccw_req *cqr;
 
-/*
- * Process finished error recovery ccw.
- */
-static inline void
-__dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
-{
-	dasd_erp_fn_t erp_fn;
+	/*
+	 * only requeue request that came from the dasd_block layer
+	 */
+	if (!ref_cqr->block)
+		return;
 
-	if (cqr->status == DASD_CQR_DONE)
-		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
-	else
-		DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
-	erp_fn = device->discipline->erp_postaction(cqr);
-	erp_fn(cqr);
-}
+	list_for_each_safe(l, n, &device->ccw_queue) {
+		cqr = list_entry(l, struct dasd_ccw_req, devlist);
+		if (cqr->status == DASD_CQR_QUEUED &&
+		    ref_cqr->block == cqr->block) {
+			cqr->status = DASD_CQR_CLEARED;
+		}
+	}
+};
 
 /*
- * Process ccw request queue.
+ * Remove those ccw requests from the queue that need to be returned
+ * to the upper layer.
  */
-static void
-__dasd_process_ccw_queue(struct dasd_device * device,
-			 struct list_head *final_queue)
+static void __dasd_device_process_ccw_queue(struct dasd_device *device,
+					    struct list_head *final_queue)
 {
 	struct list_head *l, *n;
 	struct dasd_ccw_req *cqr;
-	dasd_erp_fn_t erp_fn;
 
-restart:
 	/* Process request with final status. */
 	list_for_each_safe(l, n, &device->ccw_queue) {
-		cqr = list_entry(l, struct dasd_ccw_req, list);
+		cqr = list_entry(l, struct dasd_ccw_req, devlist);
+
 		/* Stop list processing at the first non-final request. */
-		if (cqr->status != DASD_CQR_DONE &&
-		    cqr->status != DASD_CQR_FAILED &&
-		    cqr->status != DASD_CQR_ERROR)
+		if (cqr->status == DASD_CQR_QUEUED ||
+		    cqr->status == DASD_CQR_IN_IO ||
+		    cqr->status == DASD_CQR_CLEAR_PENDING)
 			break;
-		/*  Process requests with DASD_CQR_ERROR */
 		if (cqr->status == DASD_CQR_ERROR) {
-			if (cqr->irb.scsw.fctl & SCSW_FCTL_HALT_FUNC) {
-				cqr->status = DASD_CQR_FAILED;
-				cqr->stopclk = get_clock();
-			} else {
-				if (cqr->irb.esw.esw0.erw.cons &&
-				    test_bit(DASD_CQR_FLAGS_USE_ERP,
-					     &cqr->flags)) {
-					erp_fn = device->discipline->
-						erp_action(cqr);
-					erp_fn(cqr);
-				} else
-					dasd_default_erp_action(cqr);
-			}
-			goto restart;
-		}
-
-		/* First of all call extended error reporting. */
-		if (dasd_eer_enabled(device) &&
-		    cqr->status == DASD_CQR_FAILED) {
-			dasd_eer_write(device, cqr, DASD_EER_FATALERROR);
-
-			/* restart request  */
-			cqr->status = DASD_CQR_QUEUED;
-			cqr->retries = 255;
-			device->stopped |= DASD_STOPPED_QUIESCE;
-			goto restart;
+			__dasd_device_recovery(device, cqr);
 		}
-
-		/* Process finished ERP request. */
-		if (cqr->refers) {
-			__dasd_process_erp(device, cqr);
-			goto restart;
-		}
-
 		/* Rechain finished requests to final queue */
-		cqr->endclk = get_clock();
-		list_move_tail(&cqr->list, final_queue);
+		list_move_tail(&cqr->devlist, final_queue);
 	}
 }
 
-static void
-dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
-{
-	struct request *req;
-	struct dasd_device *device;
-	int status;
-
-	req = (struct request *) data;
-	device = cqr->device;
-	dasd_profile_end(device, cqr, req);
-	status = cqr->device->discipline->free_cp(cqr,req);
-	spin_lock_irq(&device->request_queue_lock);
-	dasd_end_request(req, status);
-	spin_unlock_irq(&device->request_queue_lock);
-}
-
-
 /*
- * Fetch requests from the block device queue.
+ * the cqrs from the final queue are returned to the upper layer
+ * by setting a dasd_block state and calling the callback function
  */
-static void
-__dasd_process_blk_queue(struct dasd_device * device)
+static void __dasd_device_process_final_queue(struct dasd_device *device,
+					      struct list_head *final_queue)
 {
-	struct request_queue *queue;
-	struct request *req;
+	struct list_head *l, *n;
 	struct dasd_ccw_req *cqr;
-	int nr_queued;
-
-	queue = device->request_queue;
-	/* No queue ? Then there is nothing to do. */
-	if (queue == NULL)
-		return;
-
-	/*
-	 * We requeue request from the block device queue to the ccw
-	 * queue only in two states. In state DASD_STATE_READY the
-	 * partition detection is done and we need to requeue requests
-	 * for that. State DASD_STATE_ONLINE is normal block device
-	 * operation.
-	 */
-	if (device->state != DASD_STATE_READY &&
-	    device->state != DASD_STATE_ONLINE)
-		return;
-	nr_queued = 0;
-	/* Now we try to fetch requests from the request queue */
-	list_for_each_entry(cqr, &device->ccw_queue, list)
-		if (cqr->status == DASD_CQR_QUEUED)
-			nr_queued++;
-	while (!blk_queue_plugged(queue) &&
-	       elv_next_request(queue) &&
-		nr_queued < DASD_CHANQ_MAX_SIZE) {
-		req = elv_next_request(queue);
 
-		if (device->features & DASD_FEATURE_READONLY &&
-		    rq_data_dir(req) == WRITE) {
-			DBF_DEV_EVENT(DBF_ERR, device,
-				      "Rejecting write request %p",
-				      req);
-			blkdev_dequeue_request(req);
-			dasd_end_request(req, 0);
-			continue;
-		}
-		if (device->stopped & DASD_STOPPED_DC_EIO) {
-			blkdev_dequeue_request(req);
-			dasd_end_request(req, 0);
-			continue;
-		}
-		cqr = device->discipline->build_cp(device, req);
-		if (IS_ERR(cqr)) {
-			if (PTR_ERR(cqr) == -ENOMEM)
-				break;	/* terminate request queue loop */
-			if (PTR_ERR(cqr) == -EAGAIN) {
-				/*
-				 * The current request cannot be build right
-				 * now, we have to try later. If this request
-				 * is the head-of-queue we stop the device
-				 * for 1/2 second.
-				 */
-				if (!list_empty(&device->ccw_queue))
-					break;
-				device->stopped |= DASD_STOPPED_PENDING;
-				dasd_set_timer(device, HZ/2);
-				break;
-			}
-			DBF_DEV_EVENT(DBF_ERR, device,
-				      "CCW creation failed (rc=%ld) "
-				      "on request %p",
-				      PTR_ERR(cqr), req);
-			blkdev_dequeue_request(req);
-			dasd_end_request(req, 0);
-			continue;
+	list_for_each_safe(l, n, final_queue) {
+		cqr = list_entry(l, struct dasd_ccw_req, devlist);
+		list_del_init(&cqr->devlist);
+		if (cqr->block)
+			spin_lock_bh(&cqr->block->queue_lock);
+		switch (cqr->status) {
+		case DASD_CQR_SUCCESS:
+			cqr->status = DASD_CQR_DONE;
+			break;
+		case DASD_CQR_ERROR:
+			cqr->status = DASD_CQR_NEED_ERP;
+			break;
+		case DASD_CQR_CLEARED:
+			cqr->status = DASD_CQR_TERMINATED;
+			break;
+		default:
+			DEV_MESSAGE(KERN_ERR, device,
+				    "wrong cqr status in __dasd_process_final_queue "
+				    "for cqr %p, status %x",
+				    cqr, cqr->status);
+			BUG();
 		}
-		cqr->callback = dasd_end_request_cb;
-		cqr->callback_data = (void *) req;
-		cqr->status = DASD_CQR_QUEUED;
-		blkdev_dequeue_request(req);
-		list_add_tail(&cqr->list, &device->ccw_queue);
-		dasd_profile_start(device, cqr, req);
-		nr_queued++;
+		if (cqr->block)
+			spin_unlock_bh(&cqr->block->queue_lock);
+		if (cqr->callback != NULL)
+			(cqr->callback)(cqr, cqr->callback_data);
 	}
 }
 
+
+
 /*
  * Take a look at the first request on the ccw queue and check
  * if it reached its expire time. If so, terminate the IO.
  */
-static void
-__dasd_check_expire(struct dasd_device * device)
+static void __dasd_device_check_expire(struct dasd_device *device)
 {
 	struct dasd_ccw_req *cqr;
 
 	if (list_empty(&device->ccw_queue))
 		return;
-	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
+	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
 	if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) &&
 	    (time_after_eq(jiffies, cqr->expires + cqr->starttime))) {
 		if (device->discipline->term_IO(cqr) != 0) {
 			/* Hmpf, try again in 5 sec */
-			dasd_set_timer(device, 5*HZ);
 			DEV_MESSAGE(KERN_ERR, device,
 				    "internal error - timeout (%is) expired "
 				    "for cqr %p, termination failed, "
 				    "retrying in 5s",
 				    (cqr->expires/HZ), cqr);
+			cqr->expires += 5*HZ;
+			dasd_device_set_timer(device, 5*HZ);
 		} else {
 			DEV_MESSAGE(KERN_ERR, device,
 				    "internal error - timeout (%is) expired "
@@ -1301,77 +1217,53 @@ __dasd_check_expire(struct dasd_device * device)
  * Take a look at the first request on the ccw queue and check
  * if it needs to be started.
  */
-static void
-__dasd_start_head(struct dasd_device * device)
+static void __dasd_device_start_head(struct dasd_device *device)
 {
 	struct dasd_ccw_req *cqr;
 	int rc;
 
 	if (list_empty(&device->ccw_queue))
 		return;
-	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
+	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
 	if (cqr->status != DASD_CQR_QUEUED)
 		return;
-	/* Non-temporary stop condition will trigger fail fast */
-	if (device->stopped & ~DASD_STOPPED_PENDING &&
-	    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
-	    (!dasd_eer_enabled(device))) {
-		cqr->status = DASD_CQR_FAILED;
-		dasd_schedule_bh(device);
+	/* when device is stopped, return request to previous layer */
+	if (device->stopped) {
+		cqr->status = DASD_CQR_CLEARED;
+		dasd_schedule_device_bh(device);
 		return;
 	}
-	/* Don't try to start requests if device is stopped */
-	if (device->stopped)
-		return;
 
 	rc = device->discipline->start_IO(cqr);
 	if (rc == 0)
-		dasd_set_timer(device, cqr->expires);
+		dasd_device_set_timer(device, cqr->expires);
 	else if (rc == -EACCES) {
-		dasd_schedule_bh(device);
+		dasd_schedule_device_bh(device);
 	} else
 		/* Hmpf, try again in 1/2 sec */
-		dasd_set_timer(device, 50);
-}
-
-static inline int
-_wait_for_clear(struct dasd_ccw_req *cqr)
-{
-	return (cqr->status == DASD_CQR_QUEUED);
+		dasd_device_set_timer(device, 50);
 }
 
 /*
- * Remove all requests from the ccw queue (all = '1') or only block device
- * requests in case all = '0'.
- * Take care of the erp-chain (chained via cqr->refers) and remove either
- * the whole erp-chain or none of the erp-requests.
- * If a request is currently running, term_IO is called and the request
- * is re-queued. Prior to removing the terminated request we need to wait
- * for the clear-interrupt.
- * In case termination is not possible we stop processing and just finishing
- * the already moved requests.
+ * Go through all request on the dasd_device request queue,
+ * terminate them on the cdev if necessary, and return them to the
+ * submitting layer via callback.
+ * Note:
+ * Make sure that all 'submitting layers' still exist when
+ * this function is called!. In other words, when 'device' is a base
+ * device then all block layer requests must have been removed before
+ * via dasd_flush_block_queue.
  */
-static int
-dasd_flush_ccw_queue(struct dasd_device * device, int all)
+int dasd_flush_device_queue(struct dasd_device *device)
 {
-	struct dasd_ccw_req *cqr, *orig, *n;
-	int rc, i;
-
+	struct dasd_ccw_req *cqr, *n;
+	int rc;
 	struct list_head flush_queue;
 
 	INIT_LIST_HEAD(&flush_queue);
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	rc = 0;
-restart:
-	list_for_each_entry_safe(cqr, n, &device->ccw_queue, list) {
-		/* get original request of erp request-chain */
-		for (orig = cqr; orig->refers != NULL; orig = orig->refers);
-
-		/* Flush all request or only block device requests? */
-		if (all == 0 && cqr->callback != dasd_end_request_cb &&
-		    orig->callback != dasd_end_request_cb) {
-			continue;
-		}
+	list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) {
 		/* Check status and move request to flush_queue */
 		switch (cqr->status) {
 		case DASD_CQR_IN_IO:
@@ -1387,90 +1279,60 @@ restart:
 			}
 			break;
 		case DASD_CQR_QUEUED:
-		case DASD_CQR_ERROR:
-			/* set request to FAILED */
 			cqr->stopclk = get_clock();
-			cqr->status = DASD_CQR_FAILED;
+			cqr->status = DASD_CQR_CLEARED;
 			break;
-		default: /* do not touch the others */
+		default: /* no need to modify the others */
 			break;
 		}
-		/* Rechain request (including erp chain) */
-		for (i = 0; cqr != NULL; cqr = cqr->refers, i++) {
-			cqr->endclk = get_clock();
-			list_move_tail(&cqr->list, &flush_queue);
-		}
-		if (i > 1)
-			/* moved more than one request - need to restart */
-			goto restart;
+		list_move_tail(&cqr->devlist, &flush_queue);
 	}
-
 finished:
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
-	/* Now call the callback function of flushed requests */
-restart_cb:
-	list_for_each_entry_safe(cqr, n, &flush_queue, list) {
-		if (cqr->status == DASD_CQR_CLEAR) {
-			/* wait for clear interrupt! */
-			wait_event(dasd_flush_wq, _wait_for_clear(cqr));
-			cqr->status = DASD_CQR_FAILED;
-		}
-		/* Process finished ERP request. */
-		if (cqr->refers) {
-			__dasd_process_erp(device, cqr);
-			/* restart list_for_xx loop since dasd_process_erp
-			 * might remove multiple elements */
-			goto restart_cb;
-		}
-		/* call the callback function */
-		cqr->endclk = get_clock();
-		if (cqr->callback != NULL)
-			(cqr->callback)(cqr, cqr->callback_data);
-	}
+	/*
+	 * After this point all requests must be in state CLEAR_PENDING,
+	 * CLEARED, SUCCESS or ERROR. Now wait for CLEAR_PENDING to become
+	 * one of the others.
+	 */
+	list_for_each_entry_safe(cqr, n, &flush_queue, devlist)
+		wait_event(dasd_flush_wq,
+			   (cqr->status != DASD_CQR_CLEAR_PENDING));
+	/*
+	 * Now set each request back to TERMINATED, DONE or NEED_ERP
+	 * and call the callback function of flushed requests
+	 */
+	__dasd_device_process_final_queue(device, &flush_queue);
 	return rc;
 }
 
 /*
  * Acquire the device lock and process queues for the device.
  */
-static void
-dasd_tasklet(struct dasd_device * device)
+static void dasd_device_tasklet(struct dasd_device *device)
 {
 	struct list_head final_queue;
-	struct list_head *l, *n;
-	struct dasd_ccw_req *cqr;
 
 	atomic_set (&device->tasklet_scheduled, 0);
 	INIT_LIST_HEAD(&final_queue);
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	/* Check expire time of first request on the ccw queue. */
-	__dasd_check_expire(device);
-	/* Finish off requests on ccw queue */
-	__dasd_process_ccw_queue(device, &final_queue);
+	__dasd_device_check_expire(device);
+	/* find final requests on ccw queue */
+	__dasd_device_process_ccw_queue(device, &final_queue);
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 	/* Now call the callback function of requests with final status */
-	list_for_each_safe(l, n, &final_queue) {
-		cqr = list_entry(l, struct dasd_ccw_req, list);
-		list_del_init(&cqr->list);
-		if (cqr->callback != NULL)
-			(cqr->callback)(cqr, cqr->callback_data);
-	}
-	spin_lock_irq(&device->request_queue_lock);
-	spin_lock(get_ccwdev_lock(device->cdev));
-	/* Get new request from the block device request queue */
-	__dasd_process_blk_queue(device);
+	__dasd_device_process_final_queue(device, &final_queue);
+	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	/* Now check if the head of the ccw queue needs to be started. */
-	__dasd_start_head(device);
-	spin_unlock(get_ccwdev_lock(device->cdev));
-	spin_unlock_irq(&device->request_queue_lock);
+	__dasd_device_start_head(device);
+	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 	dasd_put_device(device);
 }
 
 /*
  * Schedules a call to dasd_tasklet over the device tasklet.
  */
-void
-dasd_schedule_bh(struct dasd_device * device)
+void dasd_schedule_device_bh(struct dasd_device *device)
 {
 	/* Protect against rescheduling. */
 	if (atomic_cmpxchg (&device->tasklet_scheduled, 0, 1) != 0)
@@ -1480,160 +1342,109 @@ dasd_schedule_bh(struct dasd_device * device)
 }
 
 /*
- * Queue a request to the head of the ccw_queue. Start the I/O if
- * possible.
+ * Queue a request to the head of the device ccw_queue.
+ * Start the I/O if possible.
  */
-void
-dasd_add_request_head(struct dasd_ccw_req *req)
+void dasd_add_request_head(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 	unsigned long flags;
 
-	device = req->device;
+	device = cqr->startdev;
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	req->status = DASD_CQR_QUEUED;
-	req->device = device;
-	list_add(&req->list, &device->ccw_queue);
+	cqr->status = DASD_CQR_QUEUED;
+	list_add(&cqr->devlist, &device->ccw_queue);
 	/* let the bh start the request to keep them in order */
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 }
 
 /*
- * Queue a request to the tail of the ccw_queue. Start the I/O if
- * possible.
+ * Queue a request to the tail of the device ccw_queue.
+ * Start the I/O if possible.
  */
-void
-dasd_add_request_tail(struct dasd_ccw_req *req)
+void dasd_add_request_tail(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 	unsigned long flags;
 
-	device = req->device;
+	device = cqr->startdev;
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	req->status = DASD_CQR_QUEUED;
-	req->device = device;
-	list_add_tail(&req->list, &device->ccw_queue);
+	cqr->status = DASD_CQR_QUEUED;
+	list_add_tail(&cqr->devlist, &device->ccw_queue);
 	/* let the bh start the request to keep them in order */
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 }
 
 /*
- * Wakeup callback.
+ * Wakeup helper for the 'sleep_on' functions.
  */
-static void
-dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
+static void dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
 {
 	wake_up((wait_queue_head_t *) data);
 }
 
-static inline int
-_wait_for_wakeup(struct dasd_ccw_req *cqr)
+static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 	int rc;
 
-	device = cqr->device;
+	device = cqr->startdev;
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	rc = ((cqr->status == DASD_CQR_DONE ||
-	       cqr->status == DASD_CQR_FAILED) &&
-	      list_empty(&cqr->list));
+	       cqr->status == DASD_CQR_NEED_ERP ||
+	       cqr->status == DASD_CQR_TERMINATED) &&
+	      list_empty(&cqr->devlist));
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 	return rc;
 }
 
 /*
- * Attempts to start a special ccw queue and waits for its completion.
+ * Queue a request to the tail of the device ccw_queue and wait for
+ * it's completion.
  */
-int
-dasd_sleep_on(struct dasd_ccw_req * cqr)
+int dasd_sleep_on(struct dasd_ccw_req *cqr)
 {
 	wait_queue_head_t wait_q;
 	struct dasd_device *device;
 	int rc;
 
-	device = cqr->device;
-	spin_lock_irq(get_ccwdev_lock(device->cdev));
+	device = cqr->startdev;
 
 	init_waitqueue_head (&wait_q);
 	cqr->callback = dasd_wakeup_cb;
 	cqr->callback_data = (void *) &wait_q;
-	cqr->status = DASD_CQR_QUEUED;
-	list_add_tail(&cqr->list, &device->ccw_queue);
-
-	/* let the bh start the request to keep them in order */
-	dasd_schedule_bh(device);
-
-	spin_unlock_irq(get_ccwdev_lock(device->cdev));
-
+	dasd_add_request_tail(cqr);
 	wait_event(wait_q, _wait_for_wakeup(cqr));
 
 	/* Request status is either done or failed. */
-	rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
 	return rc;
 }
 
 /*
- * Attempts to start a special ccw queue and wait interruptible
- * for its completion.
+ * Queue a request to the tail of the device ccw_queue and wait
+ * interruptible for it's completion.
  */
-int
-dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
+int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr)
 {
 	wait_queue_head_t wait_q;
 	struct dasd_device *device;
-	int rc, finished;
-
-	device = cqr->device;
-	spin_lock_irq(get_ccwdev_lock(device->cdev));
+	int rc;
 
+	device = cqr->startdev;
 	init_waitqueue_head (&wait_q);
 	cqr->callback = dasd_wakeup_cb;
 	cqr->callback_data = (void *) &wait_q;
-	cqr->status = DASD_CQR_QUEUED;
-	list_add_tail(&cqr->list, &device->ccw_queue);
-
-	/* let the bh start the request to keep them in order */
-	dasd_schedule_bh(device);
-	spin_unlock_irq(get_ccwdev_lock(device->cdev));
-
-	finished = 0;
-	while (!finished) {
-		rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
-		if (rc != -ERESTARTSYS) {
-			/* Request is final (done or failed) */
-			rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
-			break;
-		}
-		spin_lock_irq(get_ccwdev_lock(device->cdev));
-		switch (cqr->status) {
-		case DASD_CQR_IN_IO:
-                        /* terminate runnig cqr */
-			if (device->discipline->term_IO) {
-				cqr->retries = -1;
-				device->discipline->term_IO(cqr);
-				/* wait (non-interruptible) for final status
-				 * because signal ist still pending */
-				spin_unlock_irq(get_ccwdev_lock(device->cdev));
-				wait_event(wait_q, _wait_for_wakeup(cqr));
-				spin_lock_irq(get_ccwdev_lock(device->cdev));
-				rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
-				finished = 1;
-			}
-			break;
-		case DASD_CQR_QUEUED:
-			/* request  */
-			list_del_init(&cqr->list);
-			rc = -EIO;
-			finished = 1;
-			break;
-		default:
-			/* cqr with 'non-interruptable' status - just wait */
-			break;
-		}
-		spin_unlock_irq(get_ccwdev_lock(device->cdev));
+	dasd_add_request_tail(cqr);
+	rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
+	if (rc == -ERESTARTSYS) {
+		dasd_cancel_req(cqr);
+		/* wait (non-interruptible) for final status */
+		wait_event(wait_q, _wait_for_wakeup(cqr));
 	}
+	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
 	return rc;
 }
 
@@ -1643,25 +1454,23 @@ dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
  * and be put back to status queued, before the special request is added
  * to the head of the queue. Then the special request is waited on normally.
  */
-static inline int
-_dasd_term_running_cqr(struct dasd_device *device)
+static inline int _dasd_term_running_cqr(struct dasd_device *device)
 {
 	struct dasd_ccw_req *cqr;
 
 	if (list_empty(&device->ccw_queue))
 		return 0;
-	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
+	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist);
 	return device->discipline->term_IO(cqr);
 }
 
-int
-dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
+int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
 {
 	wait_queue_head_t wait_q;
 	struct dasd_device *device;
 	int rc;
 
-	device = cqr->device;
+	device = cqr->startdev;
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	rc = _dasd_term_running_cqr(device);
 	if (rc) {
@@ -1673,17 +1482,17 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
 	cqr->callback = dasd_wakeup_cb;
 	cqr->callback_data = (void *) &wait_q;
 	cqr->status = DASD_CQR_QUEUED;
-	list_add(&cqr->list, &device->ccw_queue);
+	list_add(&cqr->devlist, &device->ccw_queue);
 
 	/* let the bh start the request to keep them in order */
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
 	wait_event(wait_q, _wait_for_wakeup(cqr));
 
 	/* Request status is either done or failed. */
-	rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+	rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
 	return rc;
 }
 
@@ -1692,11 +1501,14 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
  * This is useful to timeout requests. The request will be
  * terminated if it is currently in i/o.
  * Returns 1 if the request has been terminated.
+ *	   0 if there was no need to terminate the request (not started yet)
+ *	   negative error code if termination failed
+ * Cancellation of a request is an asynchronous operation! The calling
+ * function has to wait until the request is properly returned via callback.
  */
-int
-dasd_cancel_req(struct dasd_ccw_req *cqr)
+int dasd_cancel_req(struct dasd_ccw_req *cqr)
 {
-	struct dasd_device *device = cqr->device;
+	struct dasd_device *device = cqr->startdev;
 	unsigned long flags;
 	int rc;
 
@@ -1704,74 +1516,454 @@ dasd_cancel_req(struct dasd_ccw_req *cqr)
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 	switch (cqr->status) {
 	case DASD_CQR_QUEUED:
-		/* request was not started - just set to failed */
-		cqr->status = DASD_CQR_FAILED;
+		/* request was not started - just set to cleared */
+		cqr->status = DASD_CQR_CLEARED;
 		break;
 	case DASD_CQR_IN_IO:
 		/* request in IO - terminate IO and release again */
-		if (device->discipline->term_IO(cqr) != 0)
-			/* what to do if unable to terminate ??????
-			   e.g. not _IN_IO */
-			cqr->status = DASD_CQR_FAILED;
-		cqr->stopclk = get_clock();
-		rc = 1;
+		rc = device->discipline->term_IO(cqr);
+		if (rc) {
+			DEV_MESSAGE(KERN_ERR, device,
+				    "dasd_cancel_req is unable "
+				    " to terminate request %p, rc = %d",
+				    cqr, rc);
+		} else {
+			cqr->stopclk = get_clock();
+			rc = 1;
+		}
 		break;
-	case DASD_CQR_DONE:
-	case DASD_CQR_FAILED:
-		/* already finished - do nothing */
+	default: /* already finished or clear pending - do nothing */
 		break;
-	default:
-		DEV_MESSAGE(KERN_ALERT, device,
-			    "invalid status %02x in request",
-			    cqr->status);
+	}
+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	dasd_schedule_device_bh(device);
+	return rc;
+}
+
+
+/*
+ * SECTION: Operations of the dasd_block layer.
+ */
+
+/*
+ * Timeout function for dasd_block. This is used when the block layer
+ * is waiting for something that may not come reliably, (e.g. a state
+ * change interrupt)
+ */
+static void dasd_block_timeout(unsigned long ptr)
+{
+	unsigned long flags;
+	struct dasd_block *block;
+
+	block = (struct dasd_block *) ptr;
+	spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags);
+	/* re-activate request queue */
+	block->base->stopped &= ~DASD_STOPPED_PENDING;
+	spin_unlock_irqrestore(get_ccwdev_lock(block->base->cdev), flags);
+	dasd_schedule_block_bh(block);
+}
+
+/*
+ * Setup timeout for a dasd_block in jiffies.
+ */
+void dasd_block_set_timer(struct dasd_block *block, int expires)
+{
+	if (expires == 0) {
+		if (timer_pending(&block->timer))
+			del_timer(&block->timer);
+		return;
+	}
+	if (timer_pending(&block->timer)) {
+		if (mod_timer(&block->timer, jiffies + expires))
+			return;
+	}
+	block->timer.function = dasd_block_timeout;
+	block->timer.data = (unsigned long) block;
+	block->timer.expires = jiffies + expires;
+	add_timer(&block->timer);
+}
+
+/*
+ * Clear timeout for a dasd_block.
+ */
+void dasd_block_clear_timer(struct dasd_block *block)
+{
+	if (timer_pending(&block->timer))
+		del_timer(&block->timer);
+}
+
+/*
+ * posts the buffer_cache about a finalized request
+ */
+static inline void dasd_end_request(struct request *req, int error)
+{
+	if (__blk_end_request(req, error, blk_rq_bytes(req)))
 		BUG();
+}
+
+/*
+ * Process finished error recovery ccw.
+ */
+static inline void __dasd_block_process_erp(struct dasd_block *block,
+					    struct dasd_ccw_req *cqr)
+{
+	dasd_erp_fn_t erp_fn;
+	struct dasd_device *device = block->base;
+
+	if (cqr->status == DASD_CQR_DONE)
+		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
+	else
+		DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
+	erp_fn = device->discipline->erp_postaction(cqr);
+	erp_fn(cqr);
+}
 
+/*
+ * Fetch requests from the block device queue.
+ */
+static void __dasd_process_request_queue(struct dasd_block *block)
+{
+	struct request_queue *queue;
+	struct request *req;
+	struct dasd_ccw_req *cqr;
+	struct dasd_device *basedev;
+	unsigned long flags;
+	queue = block->request_queue;
+	basedev = block->base;
+	/* No queue ? Then there is nothing to do. */
+	if (queue == NULL)
+		return;
+
+	/*
+	 * We requeue request from the block device queue to the ccw
+	 * queue only in two states. In state DASD_STATE_READY the
+	 * partition detection is done and we need to requeue requests
+	 * for that. State DASD_STATE_ONLINE is normal block device
+	 * operation.
+	 */
+	if (basedev->state < DASD_STATE_READY)
+		return;
+	/* Now we try to fetch requests from the request queue */
+	while (!blk_queue_plugged(queue) &&
+	       elv_next_request(queue)) {
+
+		req = elv_next_request(queue);
+
+		if (basedev->features & DASD_FEATURE_READONLY &&
+		    rq_data_dir(req) == WRITE) {
+			DBF_DEV_EVENT(DBF_ERR, basedev,
+				      "Rejecting write request %p",
+				      req);
+			blkdev_dequeue_request(req);
+			dasd_end_request(req, -EIO);
+			continue;
+		}
+		cqr = basedev->discipline->build_cp(basedev, block, req);
+		if (IS_ERR(cqr)) {
+			if (PTR_ERR(cqr) == -EBUSY)
+				break;	/* normal end condition */
+			if (PTR_ERR(cqr) == -ENOMEM)
+				break;	/* terminate request queue loop */
+			if (PTR_ERR(cqr) == -EAGAIN) {
+				/*
+				 * The current request cannot be build right
+				 * now, we have to try later. If this request
+				 * is the head-of-queue we stop the device
+				 * for 1/2 second.
+				 */
+				if (!list_empty(&block->ccw_queue))
+					break;
+				spin_lock_irqsave(get_ccwdev_lock(basedev->cdev), flags);
+				basedev->stopped |= DASD_STOPPED_PENDING;
+				spin_unlock_irqrestore(get_ccwdev_lock(basedev->cdev), flags);
+				dasd_block_set_timer(block, HZ/2);
+				break;
+			}
+			DBF_DEV_EVENT(DBF_ERR, basedev,
+				      "CCW creation failed (rc=%ld) "
+				      "on request %p",
+				      PTR_ERR(cqr), req);
+			blkdev_dequeue_request(req);
+			dasd_end_request(req, -EIO);
+			continue;
+		}
+		/*
+		 *  Note: callback is set to dasd_return_cqr_cb in
+		 * __dasd_block_start_head to cover erp requests as well
+		 */
+		cqr->callback_data = (void *) req;
+		cqr->status = DASD_CQR_FILLED;
+		blkdev_dequeue_request(req);
+		list_add_tail(&cqr->blocklist, &block->ccw_queue);
+		dasd_profile_start(block, cqr, req);
+	}
+}
+
+static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
+{
+	struct request *req;
+	int status;
+	int error = 0;
+
+	req = (struct request *) cqr->callback_data;
+	dasd_profile_end(cqr->block, cqr, req);
+	status = cqr->memdev->discipline->free_cp(cqr, req);
+	if (status <= 0)
+		error = status ? status : -EIO;
+	dasd_end_request(req, error);
+}
+
+/*
+ * Process ccw request queue.
+ */
+static void __dasd_process_block_ccw_queue(struct dasd_block *block,
+					   struct list_head *final_queue)
+{
+	struct list_head *l, *n;
+	struct dasd_ccw_req *cqr;
+	dasd_erp_fn_t erp_fn;
+	unsigned long flags;
+	struct dasd_device *base = block->base;
+
+restart:
+	/* Process request with final status. */
+	list_for_each_safe(l, n, &block->ccw_queue) {
+		cqr = list_entry(l, struct dasd_ccw_req, blocklist);
+		if (cqr->status != DASD_CQR_DONE &&
+		    cqr->status != DASD_CQR_FAILED &&
+		    cqr->status != DASD_CQR_NEED_ERP &&
+		    cqr->status != DASD_CQR_TERMINATED)
+			continue;
+
+		if (cqr->status == DASD_CQR_TERMINATED) {
+			base->discipline->handle_terminated_request(cqr);
+			goto restart;
+		}
+
+		/*  Process requests that may be recovered */
+		if (cqr->status == DASD_CQR_NEED_ERP) {
+			if (cqr->irb.esw.esw0.erw.cons &&
+			    test_bit(DASD_CQR_FLAGS_USE_ERP,
+				     &cqr->flags)) {
+				erp_fn = base->discipline->erp_action(cqr);
+				erp_fn(cqr);
+			}
+			goto restart;
+		}
+
+		/* First of all call extended error reporting. */
+		if (dasd_eer_enabled(base) &&
+		    cqr->status == DASD_CQR_FAILED) {
+			dasd_eer_write(base, cqr, DASD_EER_FATALERROR);
+
+			/* restart request  */
+			cqr->status = DASD_CQR_FILLED;
+			cqr->retries = 255;
+			spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+			base->stopped |= DASD_STOPPED_QUIESCE;
+			spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
+					       flags);
+			goto restart;
+		}
+
+		/* Process finished ERP request. */
+		if (cqr->refers) {
+			__dasd_block_process_erp(block, cqr);
+			goto restart;
+		}
+
+		/* Rechain finished requests to final queue */
+		cqr->endclk = get_clock();
+		list_move_tail(&cqr->blocklist, final_queue);
+	}
+}
+
+static void dasd_return_cqr_cb(struct dasd_ccw_req *cqr, void *data)
+{
+	dasd_schedule_block_bh(cqr->block);
+}
+
+static void __dasd_block_start_head(struct dasd_block *block)
+{
+	struct dasd_ccw_req *cqr;
+
+	if (list_empty(&block->ccw_queue))
+		return;
+	/* We allways begin with the first requests on the queue, as some
+	 * of previously started requests have to be enqueued on a
+	 * dasd_device again for error recovery.
+	 */
+	list_for_each_entry(cqr, &block->ccw_queue, blocklist) {
+		if (cqr->status != DASD_CQR_FILLED)
+			continue;
+		/* Non-temporary stop condition will trigger fail fast */
+		if (block->base->stopped & ~DASD_STOPPED_PENDING &&
+		    test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+		    (!dasd_eer_enabled(block->base))) {
+			cqr->status = DASD_CQR_FAILED;
+			dasd_schedule_block_bh(block);
+			continue;
+		}
+		/* Don't try to start requests if device is stopped */
+		if (block->base->stopped)
+			return;
+
+		/* just a fail safe check, should not happen */
+		if (!cqr->startdev)
+			cqr->startdev = block->base;
+
+		/* make sure that the requests we submit find their way back */
+		cqr->callback = dasd_return_cqr_cb;
+
+		dasd_add_request_tail(cqr);
+	}
+}
+
+/*
+ * Central dasd_block layer routine. Takes requests from the generic
+ * block layer request queue, creates ccw requests, enqueues them on
+ * a dasd_device and processes ccw requests that have been returned.
+ */
+static void dasd_block_tasklet(struct dasd_block *block)
+{
+	struct list_head final_queue;
+	struct list_head *l, *n;
+	struct dasd_ccw_req *cqr;
+
+	atomic_set(&block->tasklet_scheduled, 0);
+	INIT_LIST_HEAD(&final_queue);
+	spin_lock(&block->queue_lock);
+	/* Finish off requests on ccw queue */
+	__dasd_process_block_ccw_queue(block, &final_queue);
+	spin_unlock(&block->queue_lock);
+	/* Now call the callback function of requests with final status */
+	spin_lock_irq(&block->request_queue_lock);
+	list_for_each_safe(l, n, &final_queue) {
+		cqr = list_entry(l, struct dasd_ccw_req, blocklist);
+		list_del_init(&cqr->blocklist);
+		__dasd_cleanup_cqr(cqr);
+	}
+	spin_lock(&block->queue_lock);
+	/* Get new request from the block device request queue */
+	__dasd_process_request_queue(block);
+	/* Now check if the head of the ccw queue needs to be started. */
+	__dasd_block_start_head(block);
+	spin_unlock(&block->queue_lock);
+	spin_unlock_irq(&block->request_queue_lock);
+	dasd_put_device(block->base);
+}
+
+static void _dasd_wake_block_flush_cb(struct dasd_ccw_req *cqr, void *data)
+{
+	wake_up(&dasd_flush_wq);
+}
+
+/*
+ * Go through all request on the dasd_block request queue, cancel them
+ * on the respective dasd_device, and return them to the generic
+ * block layer.
+ */
+static int dasd_flush_block_queue(struct dasd_block *block)
+{
+	struct dasd_ccw_req *cqr, *n;
+	int rc, i;
+	struct list_head flush_queue;
+
+	INIT_LIST_HEAD(&flush_queue);
+	spin_lock_bh(&block->queue_lock);
+	rc = 0;
+restart:
+	list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) {
+		/* if this request currently owned by a dasd_device cancel it */
+		if (cqr->status >= DASD_CQR_QUEUED)
+			rc = dasd_cancel_req(cqr);
+		if (rc < 0)
+			break;
+		/* Rechain request (including erp chain) so it won't be
+		 * touched by the dasd_block_tasklet anymore.
+		 * Replace the callback so we notice when the request
+		 * is returned from the dasd_device layer.
+		 */
+		cqr->callback = _dasd_wake_block_flush_cb;
+		for (i = 0; cqr != NULL; cqr = cqr->refers, i++)
+			list_move_tail(&cqr->blocklist, &flush_queue);
+		if (i > 1)
+			/* moved more than one request - need to restart */
+			goto restart;
+	}
+	spin_unlock_bh(&block->queue_lock);
+	/* Now call the callback function of flushed requests */
+restart_cb:
+	list_for_each_entry_safe(cqr, n, &flush_queue, blocklist) {
+		wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED));
+		/* Process finished ERP request. */
+		if (cqr->refers) {
+			__dasd_block_process_erp(block, cqr);
+			/* restart list_for_xx loop since dasd_process_erp
+			 * might remove multiple elements */
+			goto restart_cb;
+		}
+		/* call the callback function */
+		cqr->endclk = get_clock();
+		list_del_init(&cqr->blocklist);
+		__dasd_cleanup_cqr(cqr);
 	}
-	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
-	dasd_schedule_bh(device);
 	return rc;
 }
 
 /*
- * SECTION: Block device operations (request queue, partitions, open, release).
+ * Schedules a call to dasd_tasklet over the device tasklet.
+ */
+void dasd_schedule_block_bh(struct dasd_block *block)
+{
+	/* Protect against rescheduling. */
+	if (atomic_cmpxchg(&block->tasklet_scheduled, 0, 1) != 0)
+		return;
+	/* life cycle of block is bound to it's base device */
+	dasd_get_device(block->base);
+	tasklet_hi_schedule(&block->tasklet);
+}
+
+
+/*
+ * SECTION: external block device operations
+ * (request queue handling, open, release, etc.)
  */
 
 /*
  * Dasd request queue function. Called from ll_rw_blk.c
  */
-static void
-do_dasd_request(struct request_queue * queue)
+static void do_dasd_request(struct request_queue *queue)
 {
-	struct dasd_device *device;
+	struct dasd_block *block;
 
-	device = (struct dasd_device *) queue->queuedata;
-	spin_lock(get_ccwdev_lock(device->cdev));
+	block = queue->queuedata;
+	spin_lock(&block->queue_lock);
 	/* Get new request from the block device request queue */
-	__dasd_process_blk_queue(device);
+	__dasd_process_request_queue(block);
 	/* Now check if the head of the ccw queue needs to be started. */
-	__dasd_start_head(device);
-	spin_unlock(get_ccwdev_lock(device->cdev));
+	__dasd_block_start_head(block);
+	spin_unlock(&block->queue_lock);
 }
 
 /*
  * Allocate and initialize request queue and default I/O scheduler.
  */
-static int
-dasd_alloc_queue(struct dasd_device * device)
+static int dasd_alloc_queue(struct dasd_block *block)
 {
 	int rc;
 
-	device->request_queue = blk_init_queue(do_dasd_request,
-					       &device->request_queue_lock);
-	if (device->request_queue == NULL)
+	block->request_queue = blk_init_queue(do_dasd_request,
+					       &block->request_queue_lock);
+	if (block->request_queue == NULL)
 		return -ENOMEM;
 
-	device->request_queue->queuedata = device;
+	block->request_queue->queuedata = block;
 
-	elevator_exit(device->request_queue->elevator);
-	rc = elevator_init(device->request_queue, "deadline");
+	elevator_exit(block->request_queue->elevator);
+	rc = elevator_init(block->request_queue, "deadline");
 	if (rc) {
-		blk_cleanup_queue(device->request_queue);
+		blk_cleanup_queue(block->request_queue);
 		return rc;
 	}
 	return 0;
@@ -1780,79 +1972,76 @@ dasd_alloc_queue(struct dasd_device * device)
 /*
  * Allocate and initialize request queue.
  */
-static void
-dasd_setup_queue(struct dasd_device * device)
+static void dasd_setup_queue(struct dasd_block *block)
 {
 	int max;
 
-	blk_queue_hardsect_size(device->request_queue, device->bp_block);
-	max = device->discipline->max_blocks << device->s2b_shift;
-	blk_queue_max_sectors(device->request_queue, max);
-	blk_queue_max_phys_segments(device->request_queue, -1L);
-	blk_queue_max_hw_segments(device->request_queue, -1L);
-	blk_queue_max_segment_size(device->request_queue, -1L);
-	blk_queue_segment_boundary(device->request_queue, -1L);
-	blk_queue_ordered(device->request_queue, QUEUE_ORDERED_TAG, NULL);
+	blk_queue_hardsect_size(block->request_queue, block->bp_block);
+	max = block->base->discipline->max_blocks << block->s2b_shift;
+	blk_queue_max_sectors(block->request_queue, max);
+	blk_queue_max_phys_segments(block->request_queue, -1L);
+	blk_queue_max_hw_segments(block->request_queue, -1L);
+	blk_queue_max_segment_size(block->request_queue, -1L);
+	blk_queue_segment_boundary(block->request_queue, -1L);
+	blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL);
 }
 
 /*
  * Deactivate and free request queue.
  */
-static void
-dasd_free_queue(struct dasd_device * device)
+static void dasd_free_queue(struct dasd_block *block)
 {
-	if (device->request_queue) {
-		blk_cleanup_queue(device->request_queue);
-		device->request_queue = NULL;
+	if (block->request_queue) {
+		blk_cleanup_queue(block->request_queue);
+		block->request_queue = NULL;
 	}
 }
 
 /*
  * Flush request on the request queue.
  */
-static void
-dasd_flush_request_queue(struct dasd_device * device)
+static void dasd_flush_request_queue(struct dasd_block *block)
 {
 	struct request *req;
 
-	if (!device->request_queue)
+	if (!block->request_queue)
 		return;
 
-	spin_lock_irq(&device->request_queue_lock);
-	while ((req = elv_next_request(device->request_queue))) {
+	spin_lock_irq(&block->request_queue_lock);
+	while ((req = elv_next_request(block->request_queue))) {
 		blkdev_dequeue_request(req);
-		dasd_end_request(req, 0);
+		dasd_end_request(req, -EIO);
 	}
-	spin_unlock_irq(&device->request_queue_lock);
+	spin_unlock_irq(&block->request_queue_lock);
 }
 
-static int
-dasd_open(struct inode *inp, struct file *filp)
+static int dasd_open(struct inode *inp, struct file *filp)
 {
 	struct gendisk *disk = inp->i_bdev->bd_disk;
-	struct dasd_device *device = disk->private_data;
+	struct dasd_block *block = disk->private_data;
+	struct dasd_device *base = block->base;
 	int rc;
 
-        atomic_inc(&device->open_count);
-	if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
+	atomic_inc(&block->open_count);
+	if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) {
 		rc = -ENODEV;
 		goto unlock;
 	}
 
-	if (!try_module_get(device->discipline->owner)) {
+	if (!try_module_get(base->discipline->owner)) {
 		rc = -EINVAL;
 		goto unlock;
 	}
 
 	if (dasd_probeonly) {
-		DEV_MESSAGE(KERN_INFO, device, "%s",
+		DEV_MESSAGE(KERN_INFO, base, "%s",
 			    "No access to device due to probeonly mode");
 		rc = -EPERM;
 		goto out;
 	}
 
-	if (device->state <= DASD_STATE_BASIC) {
-		DBF_DEV_EVENT(DBF_ERR, device, " %s",
+	if (base->state <= DASD_STATE_BASIC) {
+		DBF_DEV_EVENT(DBF_ERR, base, " %s",
 			      " Cannot open unrecognized device");
 		rc = -ENODEV;
 		goto out;
@@ -1861,41 +2050,41 @@ dasd_open(struct inode *inp, struct file *filp)
 	return 0;
 
 out:
-	module_put(device->discipline->owner);
+	module_put(base->discipline->owner);
 unlock:
-	atomic_dec(&device->open_count);
+	atomic_dec(&block->open_count);
 	return rc;
 }
 
-static int
-dasd_release(struct inode *inp, struct file *filp)
+static int dasd_release(struct inode *inp, struct file *filp)
 {
 	struct gendisk *disk = inp->i_bdev->bd_disk;
-	struct dasd_device *device = disk->private_data;
+	struct dasd_block *block = disk->private_data;
 
-	atomic_dec(&device->open_count);
-	module_put(device->discipline->owner);
+	atomic_dec(&block->open_count);
+	module_put(block->base->discipline->owner);
 	return 0;
 }
 
 /*
  * Return disk geometry.
  */
-static int
-dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-	struct dasd_device *device;
+	struct dasd_block *block;
+	struct dasd_device *base;
 
-	device = bdev->bd_disk->private_data;
-	if (!device)
+	block = bdev->bd_disk->private_data;
+	base = block->base;
+	if (!block)
 		return -ENODEV;
 
-	if (!device->discipline ||
-	    !device->discipline->fill_geometry)
+	if (!base->discipline ||
+	    !base->discipline->fill_geometry)
 		return -EINVAL;
 
-	device->discipline->fill_geometry(device, geo);
-	geo->start = get_start_sect(bdev) >> device->s2b_shift;
+	base->discipline->fill_geometry(block, geo);
+	geo->start = get_start_sect(bdev) >> block->s2b_shift;
 	return 0;
 }
 
@@ -1909,6 +2098,9 @@ dasd_device_operations = {
 	.getgeo		= dasd_getgeo,
 };
 
+/*******************************************************************************
+ * end of block device operations
+ */
 
 static void
 dasd_exit(void)
@@ -1937,9 +2129,8 @@ dasd_exit(void)
  * Initial attempt at a probe function. this can be simplified once
  * the other detection code is gone.
  */
-int
-dasd_generic_probe (struct ccw_device *cdev,
-		    struct dasd_discipline *discipline)
+int dasd_generic_probe(struct ccw_device *cdev,
+		       struct dasd_discipline *discipline)
 {
 	int ret;
 
@@ -1969,19 +2160,20 @@ dasd_generic_probe (struct ccw_device *cdev,
 		ret = ccw_device_set_online(cdev);
 	if (ret)
 		printk(KERN_WARNING
-		       "dasd_generic_probe: could not initially online "
-		       "ccw-device %s\n", cdev->dev.bus_id);
-	return ret;
+		       "dasd_generic_probe: could not initially "
+		       "online ccw-device %s; return code: %d\n",
+		       cdev->dev.bus_id, ret);
+	return 0;
 }
 
 /*
  * This will one day be called from a global not_oper handler.
  * It is also used by driver_unregister during module unload.
  */
-void
-dasd_generic_remove (struct ccw_device *cdev)
+void dasd_generic_remove(struct ccw_device *cdev)
 {
 	struct dasd_device *device;
+	struct dasd_block *block;
 
 	cdev->handler = NULL;
 
@@ -2001,7 +2193,15 @@ dasd_generic_remove (struct ccw_device *cdev)
 	 */
 	dasd_set_target_state(device, DASD_STATE_NEW);
 	/* dasd_delete_device destroys the device reference. */
+	block = device->block;
+	device->block = NULL;
 	dasd_delete_device(device);
+	/*
+	 * life cycle of block is bound to device, so delete it after
+	 * device was safely removed
+	 */
+	if (block)
+		dasd_free_block(block);
 }
 
 /*
@@ -2009,10 +2209,8 @@ dasd_generic_remove (struct ccw_device *cdev)
  * the device is detected for the first time and is supposed to be used
  * or the user has started activation through sysfs.
  */
-int
-dasd_generic_set_online (struct ccw_device *cdev,
-			 struct dasd_discipline *base_discipline)
-
+int dasd_generic_set_online(struct ccw_device *cdev,
+			    struct dasd_discipline *base_discipline)
 {
 	struct dasd_discipline *discipline;
 	struct dasd_device *device;
@@ -2048,6 +2246,7 @@ dasd_generic_set_online (struct ccw_device *cdev,
 	device->base_discipline = base_discipline;
 	device->discipline = discipline;
 
+	/* check_device will allocate block device if necessary */
 	rc = discipline->check_device(device);
 	if (rc) {
 		printk (KERN_WARNING
@@ -2067,6 +2266,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
 			cdev->dev.bus_id);
 		rc = -ENODEV;
 		dasd_set_target_state(device, DASD_STATE_NEW);
+		if (device->block)
+			dasd_free_block(device->block);
 		dasd_delete_device(device);
 	} else
 		pr_debug("dasd_generic device %s found\n",
@@ -2081,10 +2282,10 @@ dasd_generic_set_online (struct ccw_device *cdev,
 	return rc;
 }
 
-int
-dasd_generic_set_offline (struct ccw_device *cdev)
+int dasd_generic_set_offline(struct ccw_device *cdev)
 {
 	struct dasd_device *device;
+	struct dasd_block *block;
 	int max_count, open_count;
 
 	device = dasd_device_from_cdev(cdev);
@@ -2101,30 +2302,39 @@ dasd_generic_set_offline (struct ccw_device *cdev)
 	 * the blkdev_get in dasd_scan_partitions. We are only interested
 	 * in the other openers.
 	 */
-	max_count = device->bdev ? 0 : -1;
-	open_count = (int) atomic_read(&device->open_count);
-	if (open_count > max_count) {
-		if (open_count > 0)
-			printk (KERN_WARNING "Can't offline dasd device with "
-				"open count = %i.\n",
-				open_count);
-		else
-			printk (KERN_WARNING "%s",
-				"Can't offline dasd device due to internal "
-				"use\n");
-		clear_bit(DASD_FLAG_OFFLINE, &device->flags);
-		dasd_put_device(device);
-		return -EBUSY;
+	if (device->block) {
+		struct dasd_block *block = device->block;
+		max_count = block->bdev ? 0 : -1;
+		open_count = (int) atomic_read(&block->open_count);
+		if (open_count > max_count) {
+			if (open_count > 0)
+				printk(KERN_WARNING "Can't offline dasd "
+				       "device with open count = %i.\n",
+				       open_count);
+			else
+				printk(KERN_WARNING "%s",
+				       "Can't offline dasd device due "
+				       "to internal use\n");
+			clear_bit(DASD_FLAG_OFFLINE, &device->flags);
+			dasd_put_device(device);
+			return -EBUSY;
+		}
 	}
 	dasd_set_target_state(device, DASD_STATE_NEW);
 	/* dasd_delete_device destroys the device reference. */
+	block = device->block;
+	device->block = NULL;
 	dasd_delete_device(device);
-
+	/*
+	 * life cycle of block is bound to device, so delete it after
+	 * device was safely removed
+	 */
+	if (block)
+		dasd_free_block(block);
 	return 0;
 }
 
-int
-dasd_generic_notify(struct ccw_device *cdev, int event)
+int dasd_generic_notify(struct ccw_device *cdev, int event)
 {
 	struct dasd_device *device;
 	struct dasd_ccw_req *cqr;
@@ -2145,27 +2355,22 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
 		if (device->state < DASD_STATE_BASIC)
 			break;
 		/* Device is active. We want to keep it. */
-		if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) {
-			list_for_each_entry(cqr, &device->ccw_queue, list)
-				if (cqr->status == DASD_CQR_IN_IO)
-					cqr->status = DASD_CQR_FAILED;
-			device->stopped |= DASD_STOPPED_DC_EIO;
-		} else {
-			list_for_each_entry(cqr, &device->ccw_queue, list)
-				if (cqr->status == DASD_CQR_IN_IO) {
-					cqr->status = DASD_CQR_QUEUED;
-					cqr->retries++;
-				}
-			device->stopped |= DASD_STOPPED_DC_WAIT;
-			dasd_set_timer(device, 0);
-		}
-		dasd_schedule_bh(device);
+		list_for_each_entry(cqr, &device->ccw_queue, devlist)
+			if (cqr->status == DASD_CQR_IN_IO) {
+				cqr->status = DASD_CQR_QUEUED;
+				cqr->retries++;
+			}
+		device->stopped |= DASD_STOPPED_DC_WAIT;
+		dasd_device_clear_timer(device);
+		dasd_schedule_device_bh(device);
 		ret = 1;
 		break;
 	case CIO_OPER:
 		/* FIXME: add a sanity check. */
-		device->stopped &= ~(DASD_STOPPED_DC_WAIT|DASD_STOPPED_DC_EIO);
-		dasd_schedule_bh(device);
+		device->stopped &= ~DASD_STOPPED_DC_WAIT;
+		dasd_schedule_device_bh(device);
+		if (device->block)
+			dasd_schedule_block_bh(device->block);
 		ret = 1;
 		break;
 	}
@@ -2195,7 +2400,8 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
 	ccw->cda = (__u32)(addr_t)rdc_buffer;
 	ccw->count = rdc_buffer_size;
 
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	cqr->expires = 10*HZ;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	cqr->retries = 2;
@@ -2217,13 +2423,12 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
 		return PTR_ERR(cqr);
 
 	ret = dasd_sleep_on(cqr);
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars);
 
-static int __init
-dasd_init(void)
+static int __init dasd_init(void)
 {
 	int rc;
 
@@ -2231,7 +2436,7 @@ dasd_init(void)
 	init_waitqueue_head(&dasd_flush_wq);
 
 	/* register 'common' DASD debug area, used for all DBF_XXX calls */
-	dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long));
+	dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long));
 	if (dasd_debug_area == NULL) {
 		rc = -ENOMEM;
 		goto failed;
@@ -2277,15 +2482,18 @@ EXPORT_SYMBOL(dasd_diag_discipline_pointer);
 EXPORT_SYMBOL(dasd_add_request_head);
 EXPORT_SYMBOL(dasd_add_request_tail);
 EXPORT_SYMBOL(dasd_cancel_req);
-EXPORT_SYMBOL(dasd_clear_timer);
+EXPORT_SYMBOL(dasd_device_clear_timer);
+EXPORT_SYMBOL(dasd_block_clear_timer);
 EXPORT_SYMBOL(dasd_enable_device);
 EXPORT_SYMBOL(dasd_int_handler);
 EXPORT_SYMBOL(dasd_kfree_request);
 EXPORT_SYMBOL(dasd_kick_device);
 EXPORT_SYMBOL(dasd_kmalloc_request);
-EXPORT_SYMBOL(dasd_schedule_bh);
+EXPORT_SYMBOL(dasd_schedule_device_bh);
+EXPORT_SYMBOL(dasd_schedule_block_bh);
 EXPORT_SYMBOL(dasd_set_target_state);
-EXPORT_SYMBOL(dasd_set_timer);
+EXPORT_SYMBOL(dasd_device_set_timer);
+EXPORT_SYMBOL(dasd_block_set_timer);
 EXPORT_SYMBOL(dasd_sfree_request);
 EXPORT_SYMBOL(dasd_sleep_on);
 EXPORT_SYMBOL(dasd_sleep_on_immediatly);
@@ -2299,4 +2507,7 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove);
 EXPORT_SYMBOL_GPL(dasd_generic_notify);
 EXPORT_SYMBOL_GPL(dasd_generic_set_online);
 EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
-
+EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change);
+EXPORT_SYMBOL_GPL(dasd_flush_device_queue);
+EXPORT_SYMBOL_GPL(dasd_alloc_block);
+EXPORT_SYMBOL_GPL(dasd_free_block);
diff --git a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c
deleted file mode 100644
index 1ddab8991d92..000000000000
--- a/drivers/s390/block/dasd_3370_erp.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * File...........: linux/drivers/s390/block/dasd_3370_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- *
- */
-
-#define PRINTK_HEADER "dasd_erp(3370)"
-
-#include "dasd_int.h"
-
-
-/*
- * DASD_3370_ERP_EXAMINE
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recover error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
- *   'Chapter 7. 3370 Sense Data'.
- *
- * RETURN VALUES
- *   dasd_era_none	no error
- *   dasd_era_fatal	for all fatal (unrecoverable errors)
- *   dasd_era_recover	for all others.
- */
-dasd_era_t
-dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-	char *sense = irb->ecw;
-
-	/* check for successful execution first */
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-	if (sense[0] & 0x80) {	/* CMD reject */
-		return dasd_era_fatal;
-	}
-	if (sense[0] & 0x40) {	/* Drive offline */
-		return dasd_era_recover;
-	}
-	if (sense[0] & 0x20) {	/* Bus out parity */
-		return dasd_era_recover;
-	}
-	if (sense[0] & 0x10) {	/* equipment check */
-		if (sense[1] & 0x80) {
-			return dasd_era_fatal;
-		}
-		return dasd_era_recover;
-	}
-	if (sense[0] & 0x08) {	/* data check */
-		if (sense[1] & 0x80) {
-			return dasd_era_fatal;
-		}
-		return dasd_era_recover;
-	}
-	if (sense[0] & 0x04) {	/* overrun */
-		if (sense[1] & 0x80) {
-			return dasd_era_fatal;
-		}
-		return dasd_era_recover;
-	}
-	if (sense[1] & 0x40) {	/* invalid blocksize */
-		return dasd_era_fatal;
-	}
-	if (sense[1] & 0x04) {	/* file protected */
-		return dasd_era_recover;
-	}
-	if (sense[1] & 0x01) {	/* operation incomplete */
-		return dasd_era_recover;
-	}
-	if (sense[2] & 0x80) {	/* check data erroor */
-		return dasd_era_recover;
-	}
-	if (sense[2] & 0x10) {	/* Env. data present */
-		return dasd_era_recover;
-	}
-	/* examine the 24 byte sense data */
-	return dasd_era_recover;
-
-}				/* END dasd_3370_erp_examine */
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 5b7385e430ea..c361ab69ec00 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -26,158 +26,6 @@ struct DCTL_data {
 
 /*
  *****************************************************************************
- * SECTION ERP EXAMINATION
- *****************************************************************************
- */
-
-/*
- * DASD_3990_ERP_EXAMINE_24
- *
- * DESCRIPTION
- *   Checks only for fatal (unrecoverable) error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   Each bit configuration leading to an action code 2 (Exit with
- *   programming error or unusual condition indication)
- *   are handled as fatal errors.
- *
- *   All other configurations are handled as recoverable errors.
- *
- * RETURN VALUES
- *   dasd_era_fatal	for all fatal (unrecoverable errors)
- *   dasd_era_recover	for all others.
- */
-static dasd_era_t
-dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense)
-{
-
-	struct dasd_device *device = cqr->device;
-
-	/* check for 'Command Reject' */
-	if ((sense[0] & SNS0_CMD_REJECT) &&
-	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))) {
-
-		DEV_MESSAGE(KERN_ERR, device, "%s",
-			    "EXAMINE 24: Command Reject detected - "
-			    "fatal error");
-
-		return dasd_era_fatal;
-	}
-
-	/* check for 'Invalid Track Format' */
-	if ((sense[1] & SNS1_INV_TRACK_FORMAT) &&
-	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))) {
-
-		DEV_MESSAGE(KERN_ERR, device, "%s",
-			    "EXAMINE 24: Invalid Track Format detected "
-			    "- fatal error");
-
-		return dasd_era_fatal;
-	}
-
-	/* check for 'No Record Found' */
-	if (sense[1] & SNS1_NO_REC_FOUND) {
-
-                /* FIXME: fatal error ?!? */
-		DEV_MESSAGE(KERN_ERR, device,
-			    "EXAMINE 24: No Record Found detected %s",
-                            device->state <= DASD_STATE_BASIC ?
-			    " " : "- fatal error");
-
-		return dasd_era_fatal;
-	}
-
-	/* return recoverable for all others */
-	return dasd_era_recover;
-}				/* END dasd_3990_erp_examine_24 */
-
-/*
- * DASD_3990_ERP_EXAMINE_32
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recoverable error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- * RETURN VALUES
- *   dasd_era_none	no error
- *   dasd_era_fatal	for all fatal (unrecoverable errors)
- *   dasd_era_recover	for recoverable others.
- */
-static dasd_era_t
-dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
-{
-
-	struct dasd_device *device = cqr->device;
-
-	switch (sense[25]) {
-	case 0x00:
-		return dasd_era_none;
-
-	case 0x01:
-		DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 32: fatal error");
-
-		return dasd_era_fatal;
-
-	default:
-
-		return dasd_era_recover;
-	}
-
-}				/* end dasd_3990_erp_examine_32 */
-
-/*
- * DASD_3990_ERP_EXAMINE
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recover error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   The logic is based on the 'IBM 3990 Storage Control  Reference' manual
- *   'Chapter 7. Error Recovery Procedures'.
- *
- * RETURN VALUES
- *   dasd_era_none	no error
- *   dasd_era_fatal	for all fatal (unrecoverable errors)
- *   dasd_era_recover	for all others.
- */
-dasd_era_t
-dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-
-	char *sense = irb->ecw;
-	dasd_era_t era = dasd_era_recover;
-	struct dasd_device *device = cqr->device;
-
-	/* check for successful execution first */
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	/* distinguish between 24 and 32 byte sense data */
-	if (sense[27] & DASD_SENSE_BIT_0) {
-
-		era = dasd_3990_erp_examine_24(cqr, sense);
-
-	} else {
-
-		era = dasd_3990_erp_examine_32(cqr, sense);
-
-	}
-
-	/* log the erp chain if fatal error occurred */
-	if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
-		dasd_log_sense(cqr, irb);
-	}
-
-	return era;
-
-}				/* END dasd_3990_erp_examine */
-
-/*
- *****************************************************************************
  * SECTION ERP HANDLING
  *****************************************************************************
  */
@@ -206,7 +54,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
 {
 	struct dasd_ccw_req *cqr = erp->refers;
 
-	dasd_free_erp_request(erp, erp->device);
+	dasd_free_erp_request(erp, erp->memdev);
 	cqr->status = final_status;
 	return cqr;
 
@@ -224,15 +72,17 @@ static void
 dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
+	unsigned long flags;
 
 	DEV_MESSAGE(KERN_INFO, device,
 		    "blocking request queue for %is", expires/HZ);
 
+	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 	device->stopped |= DASD_STOPPED_PENDING;
-	erp->status = DASD_CQR_QUEUED;
-
-	dasd_set_timer(device, expires);
+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	erp->status = DASD_CQR_FILLED;
+	dasd_block_set_timer(device->block, expires);
 }
 
 /*
@@ -251,7 +101,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	/* first time set initial retry counter and erp_function */
 	/* and retry once without blocking queue		 */
@@ -292,11 +142,14 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
 static void
 dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
 {
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 	__u8 opm;
+	unsigned long flags;
 
 	/* try alternate valid path */
+	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 	opm = ccw_device_get_path_mask(device->cdev);
+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 	//FIXME: start with get_opm ?
 	if (erp->lpm == 0)
 		erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum);
@@ -309,9 +162,8 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
 			    "try alternate lpm=%x (lpum=%x / opm=%x)",
 			    erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm);
 
-		/* reset status to queued to handle the request again... */
-		if (erp->status > DASD_CQR_QUEUED)
-			erp->status = DASD_CQR_QUEUED;
+		/* reset status to submit the request again... */
+		erp->status = DASD_CQR_FILLED;
 		erp->retries = 1;
 	} else {
 		DEV_MESSAGE(KERN_ERR, device,
@@ -320,8 +172,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
 			    erp->irb.esw.esw0.sublog.lpum, opm);
 
 		/* post request with permanent error */
-		if (erp->status > DASD_CQR_QUEUED)
-			erp->status = DASD_CQR_FAILED;
+		erp->status = DASD_CQR_FAILED;
 	}
 }				/* end dasd_3990_erp_alternate_path */
 
@@ -344,14 +195,14 @@ static struct dasd_ccw_req *
 dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 	struct DCTL_data *DCTL_data;
 	struct ccw1 *ccw;
 	struct dasd_ccw_req *dctl_cqr;
 
 	dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1,
-					  sizeof (struct DCTL_data),
-					  erp->device);
+					  sizeof(struct DCTL_data),
+					  device);
 	if (IS_ERR(dctl_cqr)) {
 		DEV_MESSAGE(KERN_ERR, device, "%s",
 			    "Unable to allocate DCTL-CQR");
@@ -365,13 +216,14 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
 	DCTL_data->modifier = modifier;
 
 	ccw = dctl_cqr->cpaddr;
-	memset(ccw, 0, sizeof (struct ccw1));
+	memset(ccw, 0, sizeof(struct ccw1));
 	ccw->cmd_code = CCW_CMD_DCTL;
 	ccw->count = 4;
 	ccw->cda = (__u32)(addr_t) DCTL_data;
 	dctl_cqr->function = dasd_3990_erp_DCTL;
 	dctl_cqr->refers = erp;
-	dctl_cqr->device = erp->device;
+	dctl_cqr->startdev = device;
+	dctl_cqr->memdev = device;
 	dctl_cqr->magic = erp->magic;
 	dctl_cqr->expires = 5 * 60 * HZ;
 	dctl_cqr->retries = 2;
@@ -435,7 +287,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	/* first time set initial retry counter and erp_function    */
 	/* and retry once without waiting for state change pending  */
@@ -472,7 +324,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
 				     "redriving request immediately, "
 				     "%d retries left",
 				     erp->retries);
-			erp->status = DASD_CQR_QUEUED;
+			erp->status = DASD_CQR_FILLED;
 		}
 	}
 
@@ -530,7 +382,7 @@ static void
 dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 	char msg_format = (sense[7] & 0xF0);
 	char msg_no = (sense[7] & 0x0F);
 
@@ -1157,7 +1009,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_com_rej;
 
@@ -1198,7 +1050,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_bus_out(struct dasd_ccw_req * erp)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	/* first time set initial retry counter and erp_function */
 	/* and retry once without blocking queue		 */
@@ -1237,7 +1089,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_equip_check;
 
@@ -1279,7 +1131,6 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
 
 		erp = dasd_3990_erp_action_5(erp);
 	}
-
 	return erp;
 
 }				/* end dasd_3990_erp_equip_check */
@@ -1299,7 +1150,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_data_check;
 
@@ -1358,7 +1209,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_overrun(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_overrun;
 
@@ -1387,7 +1238,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_inv_format;
 
@@ -1403,8 +1254,7 @@ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
 
 	} else {
 		DEV_MESSAGE(KERN_ERR, device, "%s",
-			    "Invalid Track Format - Fatal error should have "
-			    "been handled within the interrupt handler");
+			    "Invalid Track Format - Fatal error");
 
 		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
 	}
@@ -1428,7 +1278,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_EOC(struct dasd_ccw_req * default_erp, char *sense)
 {
 
-	struct dasd_device *device = default_erp->device;
+	struct dasd_device *device = default_erp->startdev;
 
 	DEV_MESSAGE(KERN_ERR, device, "%s",
 		    "End-of-Cylinder - must never happen");
@@ -1453,7 +1303,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_env_data;
 
@@ -1463,11 +1313,9 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
 
 	/* don't retry on disabled interface */
 	if (sense[7] != 0x0F) {
-
 		erp = dasd_3990_erp_action_4(erp, sense);
 	} else {
-
-		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_IN_IO);
+		erp->status = DASD_CQR_FILLED;
 	}
 
 	return erp;
@@ -1490,11 +1338,10 @@ static struct dasd_ccw_req *
 dasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense)
 {
 
-	struct dasd_device *device = default_erp->device;
+	struct dasd_device *device = default_erp->startdev;
 
 	DEV_MESSAGE(KERN_ERR, device, "%s",
-		    "No Record Found - Fatal error should "
-		    "have been handled within the interrupt handler");
+		    "No Record Found - Fatal error ");
 
 	return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
 
@@ -1517,7 +1364,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	DEV_MESSAGE(KERN_ERR, device, "%s", "File Protected");
 
@@ -1526,6 +1373,43 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
 }				/* end dasd_3990_erp_file_prot */
 
 /*
+ * DASD_3990_ERP_INSPECT_ALIAS
+ *
+ * DESCRIPTION
+ *   Checks if the original request was started on an alias device.
+ *   If yes, it modifies the original and the erp request so that
+ *   the erp request can be started on a base device.
+ *
+ * PARAMETER
+ *   erp		pointer to the currently created default ERP
+ *
+ * RETURN VALUES
+ *   erp		pointer to the modified ERP, or NULL
+ */
+
+static struct dasd_ccw_req *dasd_3990_erp_inspect_alias(
+						struct dasd_ccw_req *erp)
+{
+	struct dasd_ccw_req *cqr = erp->refers;
+
+	if (cqr->block &&
+	    (cqr->block->base != cqr->startdev)) {
+		if (cqr->startdev->features & DASD_FEATURE_ERPLOG) {
+			DEV_MESSAGE(KERN_ERR, cqr->startdev,
+				    "ERP on alias device for request %p,"
+				    " recover on base device %s", cqr,
+				    cqr->block->base->cdev->dev.bus_id);
+		}
+		dasd_eckd_reset_ccw_to_base_io(cqr);
+		erp->startdev = cqr->block->base;
+		erp->function = dasd_3990_erp_inspect_alias;
+		return erp;
+	} else
+		return NULL;
+}
+
+
+/*
  * DASD_3990_ERP_INSPECT_24
  *
  * DESCRIPTION
@@ -1623,7 +1507,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->retries = 256;
 	erp->function = dasd_3990_erp_action_10_32;
@@ -1657,13 +1541,14 @@ static struct dasd_ccw_req *
 dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 {
 
-	struct dasd_device *device = default_erp->device;
+	struct dasd_device *device = default_erp->startdev;
 	__u32 cpa = 0;
 	struct dasd_ccw_req *cqr;
 	struct dasd_ccw_req *erp;
 	struct DE_eckd_data *DE_data;
+	struct PFX_eckd_data *PFX_data;
 	char *LO_data;		/* LO_eckd_data_t */
-	struct ccw1 *ccw;
+	struct ccw1 *ccw, *oldccw;
 
 	DEV_MESSAGE(KERN_DEBUG, device, "%s",
 		    "Write not finished because of unexpected condition");
@@ -1702,8 +1587,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 	/* Build new ERP request including DE/LO */
 	erp = dasd_alloc_erp_request((char *) &cqr->magic,
 				     2 + 1,/* DE/LO + TIC */
-				     sizeof (struct DE_eckd_data) +
-				     sizeof (struct LO_eckd_data), device);
+				     sizeof(struct DE_eckd_data) +
+				     sizeof(struct LO_eckd_data), device);
 
 	if (IS_ERR(erp)) {
 		DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP");
@@ -1712,10 +1597,16 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 
 	/* use original DE */
 	DE_data = erp->data;
-	memcpy(DE_data, cqr->data, sizeof (struct DE_eckd_data));
+	oldccw = cqr->cpaddr;
+	if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) {
+		PFX_data = cqr->data;
+		memcpy(DE_data, &PFX_data->define_extend,
+		       sizeof(struct DE_eckd_data));
+	} else
+		memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data));
 
 	/* create LO */
-	LO_data = erp->data + sizeof (struct DE_eckd_data);
+	LO_data = erp->data + sizeof(struct DE_eckd_data);
 
 	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
 
@@ -1748,7 +1639,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 
 	/* create DE ccw */
 	ccw = erp->cpaddr;
-	memset(ccw, 0, sizeof (struct ccw1));
+	memset(ccw, 0, sizeof(struct ccw1));
 	ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 16;
@@ -1756,7 +1647,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 
 	/* create LO ccw */
 	ccw++;
-	memset(ccw, 0, sizeof (struct ccw1));
+	memset(ccw, 0, sizeof(struct ccw1));
 	ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 16;
@@ -1770,7 +1661,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
 	/* fill erp related fields */
 	erp->function = dasd_3990_erp_action_1B_32;
 	erp->refers = default_erp->refers;
-	erp->device = device;
+	erp->startdev = device;
+	erp->memdev = device;
 	erp->magic = default_erp->magic;
 	erp->expires = 0;
 	erp->retries = 256;
@@ -1803,7 +1695,7 @@ static struct dasd_ccw_req *
 dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 {
 
-	struct dasd_device *device = previous_erp->device;
+	struct dasd_device *device = previous_erp->startdev;
 	__u32 cpa = 0;
 	struct dasd_ccw_req *cqr;
 	struct dasd_ccw_req *erp;
@@ -1827,7 +1719,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 		DEV_MESSAGE(KERN_DEBUG, device, "%s",
 			    "Imprecise ending is set - just retry");
 
-		previous_erp->status = DASD_CQR_QUEUED;
+		previous_erp->status = DASD_CQR_FILLED;
 
 		return previous_erp;
 	}
@@ -1850,7 +1742,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 	erp = previous_erp;
 
 	/* update the LO with the new returned sense data  */
-	LO_data = erp->data + sizeof (struct DE_eckd_data);
+	LO_data = erp->data + sizeof(struct DE_eckd_data);
 
 	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
 
@@ -1889,7 +1781,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
 	ccw++;			/* addr of TIC ccw */
 	ccw->cda = cpa;
 
-	erp->status = DASD_CQR_QUEUED;
+	erp->status = DASD_CQR_FILLED;
 
 	return erp;
 
@@ -1968,9 +1860,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
 			 * try further actions. */
 
 			erp->lpm = 0;
-
-			erp->status = DASD_CQR_ERROR;
-
+			erp->status = DASD_CQR_NEED_ERP;
 		}
 	}
 
@@ -2047,7 +1937,7 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)
 	if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) {
 
 		/* set to suspended duplex state then restart */
-		struct dasd_device *device = erp->device;
+		struct dasd_device *device = erp->startdev;
 
 		DEV_MESSAGE(KERN_ERR, device, "%s",
 			    "Set device to suspended duplex state should be "
@@ -2081,28 +1971,26 @@ dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense)
 {
 
 	if ((erp->function == dasd_3990_erp_compound_retry) &&
-	    (erp->status == DASD_CQR_ERROR)) {
+	    (erp->status == DASD_CQR_NEED_ERP)) {
 
 		dasd_3990_erp_compound_path(erp, sense);
 	}
 
 	if ((erp->function == dasd_3990_erp_compound_path) &&
-	    (erp->status == DASD_CQR_ERROR)) {
+	    (erp->status == DASD_CQR_NEED_ERP)) {
 
 		erp = dasd_3990_erp_compound_code(erp, sense);
 	}
 
 	if ((erp->function == dasd_3990_erp_compound_code) &&
-	    (erp->status == DASD_CQR_ERROR)) {
+	    (erp->status == DASD_CQR_NEED_ERP)) {
 
 		dasd_3990_erp_compound_config(erp, sense);
 	}
 
 	/* if no compound action ERP specified, the request failed */
-	if (erp->status == DASD_CQR_ERROR) {
-
+	if (erp->status == DASD_CQR_NEED_ERP)
 		erp->status = DASD_CQR_FAILED;
-	}
 
 	return erp;
 
@@ -2127,7 +2015,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 
 	erp->function = dasd_3990_erp_inspect_32;
 
@@ -2149,8 +2037,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
 
 		case 0x01:	/* fatal error */
 			DEV_MESSAGE(KERN_ERR, device, "%s",
-				    "Fatal error should have been "
-				    "handled within the interrupt handler");
+				    "Retry not recommended - Fatal error");
 
 			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
 			break;
@@ -2253,6 +2140,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
 	/* already set up new ERP !			      */
 	char *sense = erp->refers->irb.ecw;
 
+	/* if this problem occured on an alias retry on base */
+	erp_new = dasd_3990_erp_inspect_alias(erp);
+	if (erp_new)
+		return erp_new;
+
 	/* distinguish between 24 and 32 byte sense data */
 	if (sense[27] & DASD_SENSE_BIT_0) {
 
@@ -2287,13 +2179,13 @@ static struct dasd_ccw_req *
 dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
 {
 
-	struct dasd_device *device = cqr->device;
+	struct dasd_device *device = cqr->startdev;
 	struct ccw1 *ccw;
 
 	/* allocate additional request block */
 	struct dasd_ccw_req *erp;
 
-	erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, cqr->device);
+	erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, device);
 	if (IS_ERR(erp)) {
                 if (cqr->retries <= 0) {
 		        DEV_MESSAGE(KERN_ERR, device, "%s",
@@ -2305,7 +2197,7 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
                                      "Unable to allocate ERP request "
 				     "(%i retries left)",
                                      cqr->retries);
-			dasd_set_timer(device, (HZ << 3));
+			dasd_block_set_timer(device->block, (HZ << 3));
                 }
 		return cqr;
 	}
@@ -2319,7 +2211,9 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
 	ccw->cda      = (long)(cqr->cpaddr);
 	erp->function = dasd_3990_erp_add_erp;
 	erp->refers   = cqr;
-	erp->device   = cqr->device;
+	erp->startdev = device;
+	erp->memdev   = device;
+	erp->block    = cqr->block;
 	erp->magic    = cqr->magic;
 	erp->expires  = 0;
 	erp->retries  = 256;
@@ -2466,7 +2360,7 @@ static struct dasd_ccw_req *
 dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
 {
 
-	struct dasd_device *device = erp->device;
+	struct dasd_device *device = erp->startdev;
 	char *sense = erp->irb.ecw;
 
 	/* check for 24 byte sense ERP */
@@ -2557,7 +2451,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
 			       struct dasd_ccw_req *erp)
 {
 
-	struct dasd_device *device = erp_head->device;
+	struct dasd_device *device = erp_head->startdev;
 	struct dasd_ccw_req *erp_done = erp_head;	/* finished req */
 	struct dasd_ccw_req *erp_free = NULL;	/* req to be freed */
 
@@ -2569,13 +2463,13 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
 			      "original request was lost\n");
 
 		/* remove the request from the device queue */
-		list_del(&erp_done->list);
+		list_del(&erp_done->blocklist);
 
 		erp_free = erp_done;
 		erp_done = erp_done->refers;
 
 		/* free the finished erp request */
-		dasd_free_erp_request(erp_free, erp_free->device);
+		dasd_free_erp_request(erp_free, erp_free->memdev);
 
 	}			/* end while */
 
@@ -2603,7 +2497,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
 				    erp->retries, erp);
 
 			/* handle the request again... */
-			erp->status = DASD_CQR_QUEUED;
+			erp->status = DASD_CQR_FILLED;
 		}
 
 	} else {
@@ -2620,7 +2514,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
  * DASD_3990_ERP_ACTION
  *
  * DESCRIPTION
- *   controll routine for 3990 erp actions.
+ *   control routine for 3990 erp actions.
  *   Has to be called with the queue lock (namely the s390_irq_lock) acquired.
  *
  * PARAMETER
@@ -2636,9 +2530,8 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
 struct dasd_ccw_req *
 dasd_3990_erp_action(struct dasd_ccw_req * cqr)
 {
-
 	struct dasd_ccw_req *erp = NULL;
-	struct dasd_device *device = cqr->device;
+	struct dasd_device *device = cqr->startdev;
 	struct dasd_ccw_req *temp_erp = NULL;
 
 	if (device->features & DASD_FEATURE_ERPLOG) {
@@ -2704,10 +2597,11 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
 		}
 	}
 
-	/* enqueue added ERP request */
-	if (erp->status == DASD_CQR_FILLED) {
-		erp->status = DASD_CQR_QUEUED;
-		list_add(&erp->list, &device->ccw_queue);
+	/* enqueue ERP request if it's a new one */
+	if (list_empty(&erp->blocklist)) {
+		cqr->status = DASD_CQR_IN_ERP;
+		/* add erp request before the cqr */
+		list_add_tail(&erp->blocklist, &cqr->blocklist);
 	}
 
 	return erp;
diff --git a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c
deleted file mode 100644
index 6e082688475a..000000000000
--- a/drivers/s390/block/dasd_9336_erp.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * File...........: linux/drivers/s390/block/dasd_9336_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- *
- */
-
-#define PRINTK_HEADER "dasd_erp(9336)"
-
-#include "dasd_int.h"
-
-
-/*
- * DASD_9336_ERP_EXAMINE
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recover error.
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
- *   'Chapter 7. 9336 Sense Data'.
- *
- * RETURN VALUES
- *   dasd_era_none	no error
- *   dasd_era_fatal	for all fatal (unrecoverable errors)
- *   dasd_era_recover	for all others.
- */
-dasd_era_t
-dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-	/* check for successful execution first */
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	/* examine the 24 byte sense data */
-	return dasd_era_recover;
-
-}				/* END dasd_9336_erp_examine */
diff --git a/drivers/s390/block/dasd_9343_erp.c b/drivers/s390/block/dasd_9343_erp.c
deleted file mode 100644
index ddecb9808ed4..000000000000
--- a/drivers/s390/block/dasd_9343_erp.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * File...........: linux/drivers/s390/block/dasd_9345_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- *
- */
-
-#define PRINTK_HEADER "dasd_erp(9343)"
-
-#include "dasd_int.h"
-
-dasd_era_t
-dasd_9343_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	return dasd_era_recover;
-}
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
new file mode 100644
index 000000000000..3a40bee9d358
--- /dev/null
+++ b/drivers/s390/block/dasd_alias.c
@@ -0,0 +1,903 @@
+/*
+ * PAV alias management for the DASD ECKD discipline
+ *
+ * Copyright IBM Corporation, 2007
+ * Author(s): Stefan Weinhuber <wein@de.ibm.com>
+ */
+
+#include <linux/list.h>
+#include <asm/ebcdic.h>
+#include "dasd_int.h"
+#include "dasd_eckd.h"
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif				/* PRINTK_HEADER */
+#define PRINTK_HEADER "dasd(eckd):"
+
+
+/*
+ * General concept of alias management:
+ * - PAV and DASD alias management is specific to the eckd discipline.
+ * - A device is connected to an lcu as long as the device exists.
+ *   dasd_alias_make_device_known_to_lcu will be called wenn the
+ *   device is checked by the eckd discipline and
+ *   dasd_alias_disconnect_device_from_lcu will be called
+ *   before the device is deleted.
+ * - The dasd_alias_add_device / dasd_alias_remove_device
+ *   functions mark the point when a device is 'ready for service'.
+ * - A summary unit check is a rare occasion, but it is mandatory to
+ *   support it. It requires some complex recovery actions before the
+ *   devices can be used again (see dasd_alias_handle_summary_unit_check).
+ * - dasd_alias_get_start_dev will find an alias device that can be used
+ *   instead of the base device and does some (very simple) load balancing.
+ *   This is the function that gets called for each I/O, so when improving
+ *   something, this function should get faster or better, the rest has just
+ *   to be correct.
+ */
+
+
+static void summary_unit_check_handling_work(struct work_struct *);
+static void lcu_update_work(struct work_struct *);
+static int _schedule_lcu_update(struct alias_lcu *, struct dasd_device *);
+
+static struct alias_root aliastree = {
+	.serverlist = LIST_HEAD_INIT(aliastree.serverlist),
+	.lock = __SPIN_LOCK_UNLOCKED(aliastree.lock),
+};
+
+static struct alias_server *_find_server(struct dasd_uid *uid)
+{
+	struct alias_server *pos;
+	list_for_each_entry(pos, &aliastree.serverlist, server) {
+		if (!strncmp(pos->uid.vendor, uid->vendor,
+			     sizeof(uid->vendor))
+		    && !strncmp(pos->uid.serial, uid->serial,
+				sizeof(uid->serial)))
+			return pos;
+	};
+	return NULL;
+}
+
+static struct alias_lcu *_find_lcu(struct alias_server *server,
+				   struct dasd_uid *uid)
+{
+	struct alias_lcu *pos;
+	list_for_each_entry(pos, &server->lculist, lcu) {
+		if (pos->uid.ssid == uid->ssid)
+			return pos;
+	};
+	return NULL;
+}
+
+static struct alias_pav_group *_find_group(struct alias_lcu *lcu,
+					   struct dasd_uid *uid)
+{
+	struct alias_pav_group *pos;
+	__u8 search_unit_addr;
+
+	/* for hyper pav there is only one group */
+	if (lcu->pav == HYPER_PAV) {
+		if (list_empty(&lcu->grouplist))
+			return NULL;
+		else
+			return list_first_entry(&lcu->grouplist,
+						struct alias_pav_group, group);
+	}
+
+	/* for base pav we have to find the group that matches the base */
+	if (uid->type == UA_BASE_DEVICE)
+		search_unit_addr = uid->real_unit_addr;
+	else
+		search_unit_addr = uid->base_unit_addr;
+	list_for_each_entry(pos, &lcu->grouplist, group) {
+		if (pos->uid.base_unit_addr == search_unit_addr)
+			return pos;
+	};
+	return NULL;
+}
+
+static struct alias_server *_allocate_server(struct dasd_uid *uid)
+{
+	struct alias_server *server;
+
+	server = kzalloc(sizeof(*server), GFP_KERNEL);
+	if (!server)
+		return ERR_PTR(-ENOMEM);
+	memcpy(server->uid.vendor, uid->vendor, sizeof(uid->vendor));
+	memcpy(server->uid.serial, uid->serial, sizeof(uid->serial));
+	INIT_LIST_HEAD(&server->server);
+	INIT_LIST_HEAD(&server->lculist);
+	return server;
+}
+
+static void _free_server(struct alias_server *server)
+{
+	kfree(server);
+}
+
+static struct alias_lcu *_allocate_lcu(struct dasd_uid *uid)
+{
+	struct alias_lcu *lcu;
+
+	lcu = kzalloc(sizeof(*lcu), GFP_KERNEL);
+	if (!lcu)
+		return ERR_PTR(-ENOMEM);
+	lcu->uac = kzalloc(sizeof(*(lcu->uac)), GFP_KERNEL | GFP_DMA);
+	if (!lcu->uac)
+		goto out_err1;
+	lcu->rsu_cqr = kzalloc(sizeof(*lcu->rsu_cqr), GFP_KERNEL | GFP_DMA);
+	if (!lcu->rsu_cqr)
+		goto out_err2;
+	lcu->rsu_cqr->cpaddr = kzalloc(sizeof(struct ccw1),
+				       GFP_KERNEL | GFP_DMA);
+	if (!lcu->rsu_cqr->cpaddr)
+		goto out_err3;
+	lcu->rsu_cqr->data = kzalloc(16, GFP_KERNEL | GFP_DMA);
+	if (!lcu->rsu_cqr->data)
+		goto out_err4;
+
+	memcpy(lcu->uid.vendor, uid->vendor, sizeof(uid->vendor));
+	memcpy(lcu->uid.serial, uid->serial, sizeof(uid->serial));
+	lcu->uid.ssid = uid->ssid;
+	lcu->pav = NO_PAV;
+	lcu->flags = NEED_UAC_UPDATE | UPDATE_PENDING;
+	INIT_LIST_HEAD(&lcu->lcu);
+	INIT_LIST_HEAD(&lcu->inactive_devices);
+	INIT_LIST_HEAD(&lcu->active_devices);
+	INIT_LIST_HEAD(&lcu->grouplist);
+	INIT_WORK(&lcu->suc_data.worker, summary_unit_check_handling_work);
+	INIT_DELAYED_WORK(&lcu->ruac_data.dwork, lcu_update_work);
+	spin_lock_init(&lcu->lock);
+	return lcu;
+
+out_err4:
+	kfree(lcu->rsu_cqr->cpaddr);
+out_err3:
+	kfree(lcu->rsu_cqr);
+out_err2:
+	kfree(lcu->uac);
+out_err1:
+	kfree(lcu);
+	return ERR_PTR(-ENOMEM);
+}
+
+static void _free_lcu(struct alias_lcu *lcu)
+{
+	kfree(lcu->rsu_cqr->data);
+	kfree(lcu->rsu_cqr->cpaddr);
+	kfree(lcu->rsu_cqr);
+	kfree(lcu->uac);
+	kfree(lcu);
+}
+
+/*
+ * This is the function that will allocate all the server and lcu data,
+ * so this function must be called first for a new device.
+ * If the return value is 1, the lcu was already known before, if it
+ * is 0, this is a new lcu.
+ * Negative return code indicates that something went wrong (e.g. -ENOMEM)
+ */
+int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
+{
+	struct dasd_eckd_private *private;
+	unsigned long flags;
+	struct alias_server *server, *newserver;
+	struct alias_lcu *lcu, *newlcu;
+	int is_lcu_known;
+	struct dasd_uid *uid;
+
+	private = (struct dasd_eckd_private *) device->private;
+	uid = &private->uid;
+	spin_lock_irqsave(&aliastree.lock, flags);
+	is_lcu_known = 1;
+	server = _find_server(uid);
+	if (!server) {
+		spin_unlock_irqrestore(&aliastree.lock, flags);
+		newserver = _allocate_server(uid);
+		if (IS_ERR(newserver))
+			return PTR_ERR(newserver);
+		spin_lock_irqsave(&aliastree.lock, flags);
+		server = _find_server(uid);
+		if (!server) {
+			list_add(&newserver->server, &aliastree.serverlist);
+			server = newserver;
+			is_lcu_known = 0;
+		} else {
+			/* someone was faster */
+			_free_server(newserver);
+		}
+	}
+
+	lcu = _find_lcu(server, uid);
+	if (!lcu) {
+		spin_unlock_irqrestore(&aliastree.lock, flags);
+		newlcu = _allocate_lcu(uid);
+		if (IS_ERR(newlcu))
+			return PTR_ERR(lcu);
+		spin_lock_irqsave(&aliastree.lock, flags);
+		lcu = _find_lcu(server, uid);
+		if (!lcu) {
+			list_add(&newlcu->lcu, &server->lculist);
+			lcu = newlcu;
+			is_lcu_known = 0;
+		} else {
+			/* someone was faster */
+			_free_lcu(newlcu);
+		}
+		is_lcu_known = 0;
+	}
+	spin_lock(&lcu->lock);
+	list_add(&device->alias_list, &lcu->inactive_devices);
+	private->lcu = lcu;
+	spin_unlock(&lcu->lock);
+	spin_unlock_irqrestore(&aliastree.lock, flags);
+
+	return is_lcu_known;
+}
+
+/*
+ * This function removes a device from the scope of alias management.
+ * The complicated part is to make sure that it is not in use by
+ * any of the workers. If necessary cancel the work.
+ */
+void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
+{
+	struct dasd_eckd_private *private;
+	unsigned long flags;
+	struct alias_lcu *lcu;
+	struct alias_server *server;
+	int was_pending;
+
+	private = (struct dasd_eckd_private *) device->private;
+	lcu = private->lcu;
+	spin_lock_irqsave(&lcu->lock, flags);
+	list_del_init(&device->alias_list);
+	/* make sure that the workers don't use this device */
+	if (device == lcu->suc_data.device) {
+		spin_unlock_irqrestore(&lcu->lock, flags);
+		cancel_work_sync(&lcu->suc_data.worker);
+		spin_lock_irqsave(&lcu->lock, flags);
+		if (device == lcu->suc_data.device)
+			lcu->suc_data.device = NULL;
+	}
+	was_pending = 0;
+	if (device == lcu->ruac_data.device) {
+		spin_unlock_irqrestore(&lcu->lock, flags);
+		was_pending = 1;
+		cancel_delayed_work_sync(&lcu->ruac_data.dwork);
+		spin_lock_irqsave(&lcu->lock, flags);
+		if (device == lcu->ruac_data.device)
+			lcu->ruac_data.device = NULL;
+	}
+	private->lcu = NULL;
+	spin_unlock_irqrestore(&lcu->lock, flags);
+
+	spin_lock_irqsave(&aliastree.lock, flags);
+	spin_lock(&lcu->lock);
+	if (list_empty(&lcu->grouplist) &&
+	    list_empty(&lcu->active_devices) &&
+	    list_empty(&lcu->inactive_devices)) {
+		list_del(&lcu->lcu);
+		spin_unlock(&lcu->lock);
+		_free_lcu(lcu);
+		lcu = NULL;
+	} else {
+		if (was_pending)
+			_schedule_lcu_update(lcu, NULL);
+		spin_unlock(&lcu->lock);
+	}
+	server = _find_server(&private->uid);
+	if (server && list_empty(&server->lculist)) {
+		list_del(&server->server);
+		_free_server(server);
+	}
+	spin_unlock_irqrestore(&aliastree.lock, flags);
+}
+
+/*
+ * This function assumes that the unit address configuration stored
+ * in the lcu is up to date and will update the device uid before
+ * adding it to a pav group.
+ */
+static int _add_device_to_lcu(struct alias_lcu *lcu,
+			      struct dasd_device *device)
+{
+
+	struct dasd_eckd_private *private;
+	struct alias_pav_group *group;
+	struct dasd_uid *uid;
+
+	private = (struct dasd_eckd_private *) device->private;
+	uid = &private->uid;
+	uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type;
+	uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua;
+	dasd_set_uid(device->cdev, &private->uid);
+
+	/* if we have no PAV anyway, we don't need to bother with PAV groups */
+	if (lcu->pav == NO_PAV) {
+		list_move(&device->alias_list, &lcu->active_devices);
+		return 0;
+	}
+
+	group = _find_group(lcu, uid);
+	if (!group) {
+		group = kzalloc(sizeof(*group), GFP_ATOMIC);
+		if (!group)
+			return -ENOMEM;
+		memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor));
+		memcpy(group->uid.serial, uid->serial, sizeof(uid->serial));
+		group->uid.ssid = uid->ssid;
+		if (uid->type == UA_BASE_DEVICE)
+			group->uid.base_unit_addr = uid->real_unit_addr;
+		else
+			group->uid.base_unit_addr = uid->base_unit_addr;
+		INIT_LIST_HEAD(&group->group);
+		INIT_LIST_HEAD(&group->baselist);
+		INIT_LIST_HEAD(&group->aliaslist);
+		list_add(&group->group, &lcu->grouplist);
+	}
+	if (uid->type == UA_BASE_DEVICE)
+		list_move(&device->alias_list, &group->baselist);
+	else
+		list_move(&device->alias_list, &group->aliaslist);
+	private->pavgroup = group;
+	return 0;
+};
+
+static void _remove_device_from_lcu(struct alias_lcu *lcu,
+				    struct dasd_device *device)
+{
+	struct dasd_eckd_private *private;
+	struct alias_pav_group *group;
+
+	private = (struct dasd_eckd_private *) device->private;
+	list_move(&device->alias_list, &lcu->inactive_devices);
+	group = private->pavgroup;
+	if (!group)
+		return;
+	private->pavgroup = NULL;
+	if (list_empty(&group->baselist) && list_empty(&group->aliaslist)) {
+		list_del(&group->group);
+		kfree(group);
+		return;
+	}
+	if (group->next == device)
+		group->next = NULL;
+};
+
+static int read_unit_address_configuration(struct dasd_device *device,
+					   struct alias_lcu *lcu)
+{
+	struct dasd_psf_prssd_data *prssdp;
+	struct dasd_ccw_req *cqr;
+	struct ccw1 *ccw;
+	int rc;
+	unsigned long flags;
+
+	cqr = dasd_kmalloc_request("ECKD",
+				   1 /* PSF */	+ 1 /* RSSD */ ,
+				   (sizeof(struct dasd_psf_prssd_data)),
+				   device);
+	if (IS_ERR(cqr))
+		return PTR_ERR(cqr);
+	cqr->startdev = device;
+	cqr->memdev = device;
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+	cqr->retries = 10;
+	cqr->expires = 20 * HZ;
+
+	/* Prepare for Read Subsystem Data */
+	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
+	prssdp->order = PSF_ORDER_PRSSD;
+	prssdp->suborder = 0x0e;	/* Read unit address configuration */
+	/* all other bytes of prssdp must be zero */
+
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
+	ccw->count = sizeof(struct dasd_psf_prssd_data);
+	ccw->flags |= CCW_FLAG_CC;
+	ccw->cda = (__u32)(addr_t) prssdp;
+
+	/* Read Subsystem Data - feature codes */
+	memset(lcu->uac, 0, sizeof(*(lcu->uac)));
+
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+	ccw->count = sizeof(*(lcu->uac));
+	ccw->cda = (__u32)(addr_t) lcu->uac;
+
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+
+	/* need to unset flag here to detect race with summary unit check */
+	spin_lock_irqsave(&lcu->lock, flags);
+	lcu->flags &= ~NEED_UAC_UPDATE;
+	spin_unlock_irqrestore(&lcu->lock, flags);
+
+	do {
+		rc = dasd_sleep_on(cqr);
+	} while (rc && (cqr->retries > 0));
+	if (rc) {
+		spin_lock_irqsave(&lcu->lock, flags);
+		lcu->flags |= NEED_UAC_UPDATE;
+		spin_unlock_irqrestore(&lcu->lock, flags);
+	}
+	dasd_kfree_request(cqr, cqr->memdev);
+	return rc;
+}
+
+static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
+{
+	unsigned long flags;
+	struct alias_pav_group *pavgroup, *tempgroup;
+	struct dasd_device *device, *tempdev;
+	int i, rc;
+	struct dasd_eckd_private *private;
+
+	spin_lock_irqsave(&lcu->lock, flags);
+	list_for_each_entry_safe(pavgroup, tempgroup, &lcu->grouplist, group) {
+		list_for_each_entry_safe(device, tempdev, &pavgroup->baselist,
+					 alias_list) {
+			list_move(&device->alias_list, &lcu->active_devices);
+			private = (struct dasd_eckd_private *) device->private;
+			private->pavgroup = NULL;
+		}
+		list_for_each_entry_safe(device, tempdev, &pavgroup->aliaslist,
+					 alias_list) {
+			list_move(&device->alias_list, &lcu->active_devices);
+			private = (struct dasd_eckd_private *) device->private;
+			private->pavgroup = NULL;
+		}
+		list_del(&pavgroup->group);
+		kfree(pavgroup);
+	}
+	spin_unlock_irqrestore(&lcu->lock, flags);
+
+	rc = read_unit_address_configuration(refdev, lcu);
+	if (rc)
+		return rc;
+
+	spin_lock_irqsave(&lcu->lock, flags);
+	lcu->pav = NO_PAV;
+	for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) {
+		switch (lcu->uac->unit[i].ua_type) {
+		case UA_BASE_PAV_ALIAS:
+			lcu->pav = BASE_PAV;
+			break;
+		case UA_HYPER_PAV_ALIAS:
+			lcu->pav = HYPER_PAV;
+			break;
+		}
+		if (lcu->pav != NO_PAV)
+			break;
+	}
+
+	list_for_each_entry_safe(device, tempdev, &lcu->active_devices,
+				 alias_list) {
+		_add_device_to_lcu(lcu, device);
+	}
+	spin_unlock_irqrestore(&lcu->lock, flags);
+	return 0;
+}
+
+static void lcu_update_work(struct work_struct *work)
+{
+	struct alias_lcu *lcu;
+	struct read_uac_work_data *ruac_data;
+	struct dasd_device *device;
+	unsigned long flags;
+	int rc;
+
+	ruac_data = container_of(work, struct read_uac_work_data, dwork.work);
+	lcu = container_of(ruac_data, struct alias_lcu, ruac_data);
+	device = ruac_data->device;
+	rc = _lcu_update(device, lcu);
+	/*
+	 * Need to check flags again, as there could have been another
+	 * prepare_update or a new device a new device while we were still
+	 * processing the data
+	 */
+	spin_lock_irqsave(&lcu->lock, flags);
+	if (rc || (lcu->flags & NEED_UAC_UPDATE)) {
+		DEV_MESSAGE(KERN_WARNING, device, "could not update"
+			    " alias data in lcu (rc = %d), retry later", rc);
+		schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ);
+	} else {
+		lcu->ruac_data.device = NULL;
+		lcu->flags &= ~UPDATE_PENDING;
+	}
+	spin_unlock_irqrestore(&lcu->lock, flags);
+}
+
+static int _schedule_lcu_update(struct alias_lcu *lcu,
+				struct dasd_device *device)
+{
+	struct dasd_device *usedev = NULL;
+	struct alias_pav_group *group;
+
+	lcu->flags |= NEED_UAC_UPDATE;
+	if (lcu->ruac_data.device) {
+		/* already scheduled or running */
+		return 0;
+	}
+	if (device && !list_empty(&device->alias_list))
+		usedev = device;
+
+	if (!usedev && !list_empty(&lcu->grouplist)) {
+		group = list_first_entry(&lcu->grouplist,
+					 struct alias_pav_group, group);
+		if (!list_empty(&group->baselist))
+			usedev = list_first_entry(&group->baselist,
+						  struct dasd_device,
+						  alias_list);
+		else if (!list_empty(&group->aliaslist))
+			usedev = list_first_entry(&group->aliaslist,
+						  struct dasd_device,
+						  alias_list);
+	}
+	if (!usedev && !list_empty(&lcu->active_devices)) {
+		usedev = list_first_entry(&lcu->active_devices,
+					  struct dasd_device, alias_list);
+	}
+	/*
+	 * if we haven't found a proper device yet, give up for now, the next
+	 * device that will be set active will trigger an lcu update
+	 */
+	if (!usedev)
+		return -EINVAL;
+	lcu->ruac_data.device = usedev;
+	schedule_delayed_work(&lcu->ruac_data.dwork, 0);
+	return 0;
+}
+
+int dasd_alias_add_device(struct dasd_device *device)
+{
+	struct dasd_eckd_private *private;
+	struct alias_lcu *lcu;
+	unsigned long flags;
+	int rc;
+
+	private = (struct dasd_eckd_private *) device->private;
+	lcu = private->lcu;
+	rc = 0;
+	spin_lock_irqsave(&lcu->lock, flags);
+	if (!(lcu->flags & UPDATE_PENDING)) {
+		rc = _add_device_to_lcu(lcu, device);
+		if (rc)
+			lcu->flags |= UPDATE_PENDING;
+	}
+	if (lcu->flags & UPDATE_PENDING) {
+		list_move(&device->alias_list, &lcu->active_devices);
+		_schedule_lcu_update(lcu, device);
+	}
+	spin_unlock_irqrestore(&lcu->lock, flags);
+	return rc;
+}
+
+int dasd_alias_remove_device(struct dasd_device *device)
+{
+	struct dasd_eckd_private *private;
+	struct alias_lcu *lcu;
+	unsigned long flags;
+
+	private = (struct dasd_eckd_private *) device->private;
+	lcu = private->lcu;
+	spin_lock_irqsave(&lcu->lock, flags);
+	_remove_device_from_lcu(lcu, device);
+	spin_unlock_irqrestore(&lcu->lock, flags);
+	return 0;
+}
+
+struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device)
+{
+
+	struct dasd_device *alias_device;
+	struct alias_pav_group *group;
+	struct alias_lcu *lcu;
+	struct dasd_eckd_private *private, *alias_priv;
+	unsigned long flags;
+
+	private = (struct dasd_eckd_private *) base_device->private;
+	group = private->pavgroup;
+	lcu = private->lcu;
+	if (!group || !lcu)
+		return NULL;
+	if (lcu->pav == NO_PAV ||
+	    lcu->flags & (NEED_UAC_UPDATE | UPDATE_PENDING))
+		return NULL;
+
+	spin_lock_irqsave(&lcu->lock, flags);
+	alias_device = group->next;
+	if (!alias_device) {
+		if (list_empty(&group->aliaslist)) {
+			spin_unlock_irqrestore(&lcu->lock, flags);
+			return NULL;
+		} else {
+			alias_device = list_first_entry(&group->aliaslist,
+							struct dasd_device,
+							alias_list);
+		}
+	}
+	if (list_is_last(&alias_device->alias_list, &group->aliaslist))
+		group->next = list_first_entry(&group->aliaslist,
+					       struct dasd_device, alias_list);
+	else
+		group->next = list_first_entry(&alias_device->alias_list,
+					       struct dasd_device, alias_list);
+	spin_unlock_irqrestore(&lcu->lock, flags);
+	alias_priv = (struct dasd_eckd_private *) alias_device->private;
+	if ((alias_priv->count < private->count) && !alias_device->stopped)
+		return alias_device;
+	else
+		return NULL;
+}
+
+/*
+ * Summary unit check handling depends on the way alias devices
+ * are handled so it is done here rather then in dasd_eckd.c
+ */
+static int reset_summary_unit_check(struct alias_lcu *lcu,
+				    struct dasd_device *device,
+				    char reason)
+{
+	struct dasd_ccw_req *cqr;
+	int rc = 0;
+
+	cqr = lcu->rsu_cqr;
+	strncpy((char *) &cqr->magic, "ECKD", 4);
+	ASCEBC((char *) &cqr->magic, 4);
+	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RSCK;
+	cqr->cpaddr->flags = 0 ;
+	cqr->cpaddr->count = 16;
+	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
+	((char *)cqr->data)[0] = reason;
+
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+	cqr->retries = 255;	/* set retry counter to enable basic ERP */
+	cqr->startdev = device;
+	cqr->memdev = device;
+	cqr->block = NULL;
+	cqr->expires = 5 * HZ;
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+
+	rc = dasd_sleep_on_immediatly(cqr);
+	return rc;
+}
+
+static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu)
+{
+	struct alias_pav_group *pavgroup;
+	struct dasd_device *device;
+	struct dasd_eckd_private *private;
+
+	/* active and inactive list can contain alias as well as base devices */
+	list_for_each_entry(device, &lcu->active_devices, alias_list) {
+		private = (struct dasd_eckd_private *) device->private;
+		if (private->uid.type != UA_BASE_DEVICE)
+			continue;
+		dasd_schedule_block_bh(device->block);
+		dasd_schedule_device_bh(device);
+	}
+	list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
+		private = (struct dasd_eckd_private *) device->private;
+		if (private->uid.type != UA_BASE_DEVICE)
+			continue;
+		dasd_schedule_block_bh(device->block);
+		dasd_schedule_device_bh(device);
+	}
+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+		list_for_each_entry(device, &pavgroup->baselist, alias_list) {
+			dasd_schedule_block_bh(device->block);
+			dasd_schedule_device_bh(device);
+		}
+	}
+}
+
+static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu)
+{
+	struct alias_pav_group *pavgroup;
+	struct dasd_device *device, *temp;
+	struct dasd_eckd_private *private;
+	int rc;
+	unsigned long flags;
+	LIST_HEAD(active);
+
+	/*
+	 * Problem here ist that dasd_flush_device_queue may wait
+	 * for termination of a request to complete. We can't keep
+	 * the lcu lock during that time, so we must assume that
+	 * the lists may have changed.
+	 * Idea: first gather all active alias devices in a separate list,
+	 * then flush the first element of this list unlocked, and afterwards
+	 * check if it is still on the list before moving it to the
+	 * active_devices list.
+	 */
+
+	spin_lock_irqsave(&lcu->lock, flags);
+	list_for_each_entry_safe(device, temp, &lcu->active_devices,
+				 alias_list) {
+		private = (struct dasd_eckd_private *) device->private;
+		if (private->uid.type == UA_BASE_DEVICE)
+			continue;
+		list_move(&device->alias_list, &active);
+	}
+
+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+		list_splice_init(&pavgroup->aliaslist, &active);
+	}
+	while (!list_empty(&active)) {
+		device = list_first_entry(&active, struct dasd_device,
+					  alias_list);
+		spin_unlock_irqrestore(&lcu->lock, flags);
+		rc = dasd_flush_device_queue(device);
+		spin_lock_irqsave(&lcu->lock, flags);
+		/*
+		 * only move device around if it wasn't moved away while we
+		 * were waiting for the flush
+		 */
+		if (device == list_first_entry(&active,
+					       struct dasd_device, alias_list))
+			list_move(&device->alias_list, &lcu->active_devices);
+	}
+	spin_unlock_irqrestore(&lcu->lock, flags);
+}
+
+/*
+ * This function is called in interrupt context, so the
+ * cdev lock for device is already locked!
+ */
+static void _stop_all_devices_on_lcu(struct alias_lcu *lcu,
+				     struct dasd_device *device)
+{
+	struct alias_pav_group *pavgroup;
+	struct dasd_device *pos;
+
+	list_for_each_entry(pos, &lcu->active_devices, alias_list) {
+		if (pos != device)
+			spin_lock(get_ccwdev_lock(pos->cdev));
+		pos->stopped |= DASD_STOPPED_SU;
+		if (pos != device)
+			spin_unlock(get_ccwdev_lock(pos->cdev));
+	}
+	list_for_each_entry(pos, &lcu->inactive_devices, alias_list) {
+		if (pos != device)
+			spin_lock(get_ccwdev_lock(pos->cdev));
+		pos->stopped |= DASD_STOPPED_SU;
+		if (pos != device)
+			spin_unlock(get_ccwdev_lock(pos->cdev));
+	}
+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+		list_for_each_entry(pos, &pavgroup->baselist, alias_list) {
+			if (pos != device)
+				spin_lock(get_ccwdev_lock(pos->cdev));
+			pos->stopped |= DASD_STOPPED_SU;
+			if (pos != device)
+				spin_unlock(get_ccwdev_lock(pos->cdev));
+		}
+		list_for_each_entry(pos, &pavgroup->aliaslist, alias_list) {
+			if (pos != device)
+				spin_lock(get_ccwdev_lock(pos->cdev));
+			pos->stopped |= DASD_STOPPED_SU;
+			if (pos != device)
+				spin_unlock(get_ccwdev_lock(pos->cdev));
+		}
+	}
+}
+
+static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu)
+{
+	struct alias_pav_group *pavgroup;
+	struct dasd_device *device;
+	unsigned long flags;
+
+	list_for_each_entry(device, &lcu->active_devices, alias_list) {
+		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+		device->stopped &= ~DASD_STOPPED_SU;
+		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	}
+
+	list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
+		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+		device->stopped &= ~DASD_STOPPED_SU;
+		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	}
+
+	list_for_each_entry(pavgroup, &lcu->grouplist, group) {
+		list_for_each_entry(device, &pavgroup->baselist, alias_list) {
+			spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+			device->stopped &= ~DASD_STOPPED_SU;
+			spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+					       flags);
+		}
+		list_for_each_entry(device, &pavgroup->aliaslist, alias_list) {
+			spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+			device->stopped &= ~DASD_STOPPED_SU;
+			spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+					       flags);
+		}
+	}
+}
+
+static void summary_unit_check_handling_work(struct work_struct *work)
+{
+	struct alias_lcu *lcu;
+	struct summary_unit_check_work_data *suc_data;
+	unsigned long flags;
+	struct dasd_device *device;
+
+	suc_data = container_of(work, struct summary_unit_check_work_data,
+				worker);
+	lcu = container_of(suc_data, struct alias_lcu, suc_data);
+	device = suc_data->device;
+
+	/* 1. flush alias devices */
+	flush_all_alias_devices_on_lcu(lcu);
+
+	/* 2. reset summary unit check */
+	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+	device->stopped &= ~(DASD_STOPPED_SU | DASD_STOPPED_PENDING);
+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	reset_summary_unit_check(lcu, device, suc_data->reason);
+
+	spin_lock_irqsave(&lcu->lock, flags);
+	_unstop_all_devices_on_lcu(lcu);
+	_restart_all_base_devices_on_lcu(lcu);
+	/* 3. read new alias configuration */
+	_schedule_lcu_update(lcu, device);
+	lcu->suc_data.device = NULL;
+	spin_unlock_irqrestore(&lcu->lock, flags);
+}
+
+/*
+ * note: this will be called from int handler context (cdev locked)
+ */
+void dasd_alias_handle_summary_unit_check(struct dasd_device *device,
+					  struct irb *irb)
+{
+	struct alias_lcu *lcu;
+	char reason;
+	struct dasd_eckd_private *private;
+
+	private = (struct dasd_eckd_private *) device->private;
+
+	reason = irb->ecw[8];
+	DEV_MESSAGE(KERN_WARNING, device, "%s %x",
+		    "eckd handle summary unit check: reason", reason);
+
+	lcu = private->lcu;
+	if (!lcu) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "device not ready to handle summary"
+			    " unit check (no lcu structure)");
+		return;
+	}
+	spin_lock(&lcu->lock);
+	_stop_all_devices_on_lcu(lcu, device);
+	/* prepare for lcu_update */
+	private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING;
+	/* If this device is about to be removed just return and wait for
+	 * the next interrupt on a different device
+	 */
+	if (list_empty(&device->alias_list)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "device is in offline processing,"
+			    " don't do summary unit check handling");
+		spin_unlock(&lcu->lock);
+		return;
+	}
+	if (lcu->suc_data.device) {
+		/* already scheduled or running */
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "previous instance of summary unit check worker"
+			    " still pending");
+		spin_unlock(&lcu->lock);
+		return ;
+	}
+	lcu->suc_data.reason = reason;
+	lcu->suc_data.device = device;
+	spin_unlock(&lcu->lock);
+	schedule_work(&lcu->suc_data.worker);
+};
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 0c67258fb9ec..f4fb40257348 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -49,22 +49,6 @@ struct dasd_devmap {
 };
 
 /*
- * dasd_server_ssid_map contains a globally unique storage server subsystem ID.
- * dasd_server_ssid_list contains the list of all subsystem IDs accessed by
- * the DASD device driver.
- */
-struct dasd_server_ssid_map {
-	struct list_head list;
-	struct system_id {
-		char vendor[4];
-		char serial[15];
-		__u16 ssid;
-	} sid;
-};
-
-static struct list_head dasd_server_ssid_list;
-
-/*
  * Parameter parsing functions for dasd= parameter. The syntax is:
  *   <devno>		: (0x)?[0-9a-fA-F]+
  *   <busid>		: [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
@@ -721,8 +705,9 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr,
 		devmap->features &= ~DASD_FEATURE_READONLY;
 	if (devmap->device)
 		devmap->device->features = devmap->features;
-	if (devmap->device && devmap->device->gdp)
-		set_disk_ro(devmap->device->gdp, val);
+	if (devmap->device && devmap->device->block
+	    && devmap->device->block->gdp)
+		set_disk_ro(devmap->device->block->gdp, val);
 	spin_unlock(&dasd_devmap_lock);
 	return count;
 }
@@ -893,12 +878,16 @@ dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
 
 	devmap = dasd_find_busid(dev->bus_id);
 	spin_lock(&dasd_devmap_lock);
-	if (!IS_ERR(devmap))
-		alias = devmap->uid.alias;
+	if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
+		spin_unlock(&dasd_devmap_lock);
+		return sprintf(buf, "0\n");
+	}
+	if (devmap->uid.type == UA_BASE_PAV_ALIAS ||
+	    devmap->uid.type == UA_HYPER_PAV_ALIAS)
+		alias = 1;
 	else
 		alias = 0;
 	spin_unlock(&dasd_devmap_lock);
-
 	return sprintf(buf, alias ? "1\n" : "0\n");
 }
 
@@ -930,19 +919,36 @@ static ssize_t
 dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct dasd_devmap *devmap;
-	char uid[UID_STRLEN];
+	char uid_string[UID_STRLEN];
+	char ua_string[3];
+	struct dasd_uid *uid;
 
 	devmap = dasd_find_busid(dev->bus_id);
 	spin_lock(&dasd_devmap_lock);
-	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
-		snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
-			 devmap->uid.vendor, devmap->uid.serial,
-			 devmap->uid.ssid, devmap->uid.unit_addr);
-	else
-		uid[0] = 0;
+	if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
+		spin_unlock(&dasd_devmap_lock);
+		return sprintf(buf, "\n");
+	}
+	uid = &devmap->uid;
+	switch (uid->type) {
+	case UA_BASE_DEVICE:
+		sprintf(ua_string, "%02x", uid->real_unit_addr);
+		break;
+	case UA_BASE_PAV_ALIAS:
+		sprintf(ua_string, "%02x", uid->base_unit_addr);
+		break;
+	case UA_HYPER_PAV_ALIAS:
+		sprintf(ua_string, "xx");
+		break;
+	default:
+		/* should not happen, treat like base device */
+		sprintf(ua_string, "%02x", uid->real_unit_addr);
+		break;
+	}
+	snprintf(uid_string, sizeof(uid_string), "%s.%s.%04x.%s",
+		 uid->vendor, uid->serial, uid->ssid, ua_string);
 	spin_unlock(&dasd_devmap_lock);
-
-	return snprintf(buf, PAGE_SIZE, "%s\n", uid);
+	return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
 }
 
 static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
@@ -1040,39 +1046,16 @@ int
 dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
 {
 	struct dasd_devmap *devmap;
-	struct dasd_server_ssid_map *srv, *tmp;
 
 	devmap = dasd_find_busid(cdev->dev.bus_id);
 	if (IS_ERR(devmap))
 		return PTR_ERR(devmap);
 
-	/* generate entry for server_ssid_map */
-	srv = (struct dasd_server_ssid_map *)
-		kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL);
-	if (!srv)
-		return -ENOMEM;
-	strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1);
-	strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1);
-	srv->sid.ssid = uid->ssid;
-
-	/* server is already contained ? */
 	spin_lock(&dasd_devmap_lock);
 	devmap->uid = *uid;
-	list_for_each_entry(tmp, &dasd_server_ssid_list, list) {
-		if (!memcmp(&srv->sid, &tmp->sid,
-			    sizeof(struct system_id))) {
-			kfree(srv);
-			srv = NULL;
-			break;
-		}
-	}
-
-	/* add servermap to serverlist */
-	if (srv)
-		list_add(&srv->list, &dasd_server_ssid_list);
 	spin_unlock(&dasd_devmap_lock);
 
-	return (srv ? 1 : 0);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(dasd_set_uid);
 
@@ -1138,9 +1121,6 @@ dasd_devmap_init(void)
 	dasd_max_devindex = 0;
 	for (i = 0; i < 256; i++)
 		INIT_LIST_HEAD(&dasd_hashlists[i]);
-
-	/* Initialize servermap structure. */
-	INIT_LIST_HEAD(&dasd_server_ssid_list);
 	return 0;
 }
 
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 571320ab9e1a..d91df38ee4f7 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -142,7 +142,7 @@ dasd_diag_erp(struct dasd_device *device)
 	int rc;
 
 	mdsk_term_io(device);
-	rc = mdsk_init_io(device, device->bp_block, 0, NULL);
+	rc = mdsk_init_io(device, device->block->bp_block, 0, NULL);
 	if (rc)
 		DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, "
 			    "rc=%d", rc);
@@ -158,11 +158,11 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
 	struct dasd_diag_req *dreq;
 	int rc;
 
-	device = cqr->device;
+	device = cqr->startdev;
 	if (cqr->retries < 0) {
 		DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p "
 			    "- no retry left)", cqr);
-		cqr->status = DASD_CQR_FAILED;
+		cqr->status = DASD_CQR_ERROR;
 		return -EIO;
 	}
 	private = (struct dasd_diag_private *) device->private;
@@ -184,7 +184,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr)
 	switch (rc) {
 	case 0: /* Synchronous I/O finished successfully */
 		cqr->stopclk = get_clock();
-		cqr->status = DASD_CQR_DONE;
+		cqr->status = DASD_CQR_SUCCESS;
 		/* Indicate to calling function that only a dasd_schedule_bh()
 		   and no timer is needed */
                 rc = -EACCES;
@@ -209,12 +209,12 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
 {
 	struct dasd_device *device;
 
-	device = cqr->device;
+	device = cqr->startdev;
 	mdsk_term_io(device);
-	mdsk_init_io(device, device->bp_block, 0, NULL);
-	cqr->status = DASD_CQR_CLEAR;
+	mdsk_init_io(device, device->block->bp_block, 0, NULL);
+	cqr->status = DASD_CQR_CLEAR_PENDING;
 	cqr->stopclk = get_clock();
-	dasd_schedule_bh(device);
+	dasd_schedule_device_bh(device);
 	return 0;
 }
 
@@ -247,7 +247,7 @@ dasd_ext_handler(__u16 code)
 		return;
 	}
 	cqr = (struct dasd_ccw_req *) ip;
-	device = (struct dasd_device *) cqr->device;
+	device = (struct dasd_device *) cqr->startdev;
 	if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
 		DEV_MESSAGE(KERN_WARNING, device,
 			    " magic number of dasd_ccw_req 0x%08X doesn't"
@@ -260,10 +260,10 @@ dasd_ext_handler(__u16 code)
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 
 	/* Check for a pending clear operation */
-	if (cqr->status == DASD_CQR_CLEAR) {
-		cqr->status = DASD_CQR_QUEUED;
-		dasd_clear_timer(device);
-		dasd_schedule_bh(device);
+	if (cqr->status == DASD_CQR_CLEAR_PENDING) {
+		cqr->status = DASD_CQR_CLEARED;
+		dasd_device_clear_timer(device);
+		dasd_schedule_device_bh(device);
 		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 		return;
 	}
@@ -272,11 +272,11 @@ dasd_ext_handler(__u16 code)
 
 	expires = 0;
 	if (status == 0) {
-		cqr->status = DASD_CQR_DONE;
+		cqr->status = DASD_CQR_SUCCESS;
 		/* Start first request on queue if possible -> fast_io. */
 		if (!list_empty(&device->ccw_queue)) {
 			next = list_entry(device->ccw_queue.next,
-					  struct dasd_ccw_req, list);
+					  struct dasd_ccw_req, devlist);
 			if (next->status == DASD_CQR_QUEUED) {
 				rc = dasd_start_diag(next);
 				if (rc == 0)
@@ -296,10 +296,10 @@ dasd_ext_handler(__u16 code)
 	}
 
 	if (expires != 0)
-		dasd_set_timer(device, expires);
+		dasd_device_set_timer(device, expires);
 	else
-		dasd_clear_timer(device);
-	dasd_schedule_bh(device);
+		dasd_device_clear_timer(device);
+	dasd_schedule_device_bh(device);
 
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 }
@@ -309,6 +309,7 @@ dasd_ext_handler(__u16 code)
 static int
 dasd_diag_check_device(struct dasd_device *device)
 {
+	struct dasd_block *block;
 	struct dasd_diag_private *private;
 	struct dasd_diag_characteristics *rdc_data;
 	struct dasd_diag_bio bio;
@@ -328,6 +329,16 @@ dasd_diag_check_device(struct dasd_device *device)
 		ccw_device_get_id(device->cdev, &private->dev_id);
 		device->private = (void *) private;
 	}
+	block = dasd_alloc_block();
+	if (IS_ERR(block)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "could not allocate dasd block structure");
+		kfree(device->private);
+		return PTR_ERR(block);
+	}
+	device->block = block;
+	block->base = device;
+
 	/* Read Device Characteristics */
 	rdc_data = (void *) &(private->rdc_data);
 	rdc_data->dev_nr = private->dev_id.devno;
@@ -409,14 +420,14 @@ dasd_diag_check_device(struct dasd_device *device)
 		  sizeof(DASD_DIAG_CMS1)) == 0) {
 		/* get formatted blocksize from label block */
 		bsize = (unsigned int) label->block_size;
-		device->blocks = (unsigned long) label->block_count;
+		block->blocks = (unsigned long) label->block_count;
 	} else
-		device->blocks = end_block;
-	device->bp_block = bsize;
-	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
+		block->blocks = end_block;
+	block->bp_block = bsize;
+	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
 	for (sb = 512; sb < bsize; sb = sb << 1)
-		device->s2b_shift++;
-	rc = mdsk_init_io(device, device->bp_block, 0, NULL);
+		block->s2b_shift++;
+	rc = mdsk_init_io(device, block->bp_block, 0, NULL);
 	if (rc) {
 		DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization "
 			"failed (rc=%d)", rc);
@@ -424,9 +435,9 @@ dasd_diag_check_device(struct dasd_device *device)
 	} else {
 		DEV_MESSAGE(KERN_INFO, device,
 			    "(%ld B/blk): %ldkB",
-			    (unsigned long) device->bp_block,
-			    (unsigned long) (device->blocks <<
-				device->s2b_shift) >> 1);
+			    (unsigned long) block->bp_block,
+			    (unsigned long) (block->blocks <<
+				block->s2b_shift) >> 1);
 	}
 out:
 	free_page((long) label);
@@ -436,22 +447,16 @@ out:
 /* Fill in virtual disk geometry for device. Return zero on success, non-zero
  * otherwise. */
 static int
-dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
+dasd_diag_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
 {
-	if (dasd_check_blocksize(device->bp_block) != 0)
+	if (dasd_check_blocksize(block->bp_block) != 0)
 		return -EINVAL;
-	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
+	geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
 	geo->heads = 16;
-	geo->sectors = 128 >> device->s2b_shift;
+	geo->sectors = 128 >> block->s2b_shift;
 	return 0;
 }
 
-static dasd_era_t
-dasd_diag_examine_error(struct dasd_ccw_req * cqr, struct irb * stat)
-{
-	return dasd_era_fatal;
-}
-
 static dasd_erp_fn_t
 dasd_diag_erp_action(struct dasd_ccw_req * cqr)
 {
@@ -466,8 +471,9 @@ dasd_diag_erp_postaction(struct dasd_ccw_req * cqr)
 
 /* Create DASD request from block device request. Return pointer to new
  * request on success, ERR_PTR otherwise. */
-static struct dasd_ccw_req *
-dasd_diag_build_cp(struct dasd_device * device, struct request *req)
+static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
+					       struct dasd_block *block,
+					       struct request *req)
 {
 	struct dasd_ccw_req *cqr;
 	struct dasd_diag_req *dreq;
@@ -486,17 +492,17 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
 		rw_cmd = MDSK_WRITE_REQ;
 	else
 		return ERR_PTR(-EINVAL);
-	blksize = device->bp_block;
+	blksize = block->bp_block;
 	/* Calculate record id of first and last block. */
-	first_rec = req->sector >> device->s2b_shift;
-	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+	first_rec = req->sector >> block->s2b_shift;
+	last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
 	/* Check struct bio and count the number of blocks for the request. */
 	count = 0;
 	rq_for_each_segment(bv, req, iter) {
 		if (bv->bv_len & (blksize - 1))
 			/* Fba can only do full blocks. */
 			return ERR_PTR(-EINVAL);
-		count += bv->bv_len >> (device->s2b_shift + 9);
+		count += bv->bv_len >> (block->s2b_shift + 9);
 	}
 	/* Paranoia. */
 	if (count != last_rec - first_rec + 1)
@@ -505,7 +511,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
 	datasize = sizeof(struct dasd_diag_req) +
 		count*sizeof(struct dasd_diag_bio);
 	cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0,
-				   datasize, device);
+				   datasize, memdev);
 	if (IS_ERR(cqr))
 		return cqr;
 
@@ -529,7 +535,9 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
 	cqr->buildclk = get_clock();
 	if (req->cmd_flags & REQ_FAILFAST)
 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->device = device;
+	cqr->startdev = memdev;
+	cqr->memdev = memdev;
+	cqr->block = block;
 	cqr->expires = DIAG_TIMEOUT;
 	cqr->status = DASD_CQR_FILLED;
 	return cqr;
@@ -543,10 +551,15 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req)
 	int status;
 
 	status = cqr->status == DASD_CQR_DONE;
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return status;
 }
 
+static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr)
+{
+	cqr->status = DASD_CQR_FILLED;
+};
+
 /* Fill in IOCTL data for device. */
 static int
 dasd_diag_fill_info(struct dasd_device * device,
@@ -583,7 +596,7 @@ static struct dasd_discipline dasd_diag_discipline = {
 	.fill_geometry = dasd_diag_fill_geometry,
 	.start_IO = dasd_start_diag,
 	.term_IO = dasd_diag_term_IO,
-	.examine_error = dasd_diag_examine_error,
+	.handle_terminated_request = dasd_diag_handle_terminated_request,
 	.erp_action = dasd_diag_erp_action,
 	.erp_postaction = dasd_diag_erp_postaction,
 	.build_cp = dasd_diag_build_cp,
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 44adf8496bda..61f16937c1e0 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -52,16 +52,6 @@ MODULE_LICENSE("GPL");
 
 static struct dasd_discipline dasd_eckd_discipline;
 
-struct dasd_eckd_private {
-	struct dasd_eckd_characteristics rdc_data;
-	struct dasd_eckd_confdata conf_data;
-	struct dasd_eckd_path path_data;
-	struct eckd_count count_area[5];
-	int init_cqr_status;
-	int uses_cdl;
-	struct attrib_data_t attrib;	/* e.g. cache operations */
-};
-
 /* The ccw bus type uses this table to find devices that it sends to
  * dasd_eckd_probe */
 static struct ccw_device_id dasd_eckd_ids[] = {
@@ -188,7 +178,7 @@ check_XRC (struct ccw1         *de_ccw,
 	if (rc == -ENOSYS || rc == -EACCES)
 		rc = 0;
 
-	de_ccw->count = sizeof (struct DE_eckd_data);
+	de_ccw->count = sizeof(struct DE_eckd_data);
 	de_ccw->flags |= CCW_FLAG_SLI;
 	return rc;
 }
@@ -208,7 +198,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
 	ccw->count = 16;
 	ccw->cda = (__u32) __pa(data);
 
-	memset(data, 0, sizeof (struct DE_eckd_data));
+	memset(data, 0, sizeof(struct DE_eckd_data));
 	switch (cmd) {
 	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
 	case DASD_ECKD_CCW_READ_RECORD_ZERO:
@@ -280,6 +270,132 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
 	return rc;
 }
 
+static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,
+			       struct dasd_device  *device)
+{
+	struct dasd_eckd_private *private;
+	int rc;
+
+	private = (struct dasd_eckd_private *) device->private;
+	if (!private->rdc_data.facilities.XRC_supported)
+		return 0;
+
+	/* switch on System Time Stamp - needed for XRC Support */
+	pfxdata->define_extend.ga_extended |= 0x08; /* 'Time Stamp Valid'   */
+	pfxdata->define_extend.ga_extended |= 0x02; /* 'Extended Parameter' */
+	pfxdata->validity.time_stamp = 1;	    /* 'Time Stamp Valid'   */
+
+	rc = get_sync_clock(&pfxdata->define_extend.ep_sys_time);
+	/* Ignore return code if sync clock is switched off. */
+	if (rc == -ENOSYS || rc == -EACCES)
+		rc = 0;
+	return rc;
+}
+
+static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk,
+		  int totrk, int cmd, struct dasd_device *basedev,
+		  struct dasd_device *startdev)
+{
+	struct dasd_eckd_private *basepriv, *startpriv;
+	struct DE_eckd_data *data;
+	struct ch_t geo, beg, end;
+	int rc = 0;
+
+	basepriv = (struct dasd_eckd_private *) basedev->private;
+	startpriv = (struct dasd_eckd_private *) startdev->private;
+	data = &pfxdata->define_extend;
+
+	ccw->cmd_code = DASD_ECKD_CCW_PFX;
+	ccw->flags = 0;
+	ccw->count = sizeof(*pfxdata);
+	ccw->cda = (__u32) __pa(pfxdata);
+
+	memset(pfxdata, 0, sizeof(*pfxdata));
+	/* prefix data */
+	pfxdata->format = 0;
+	pfxdata->base_address = basepriv->conf_data.ned1.unit_addr;
+	pfxdata->base_lss = basepriv->conf_data.ned1.ID;
+	pfxdata->validity.define_extend = 1;
+
+	/* private uid is kept up to date, conf_data may be outdated */
+	if (startpriv->uid.type != UA_BASE_DEVICE) {
+		pfxdata->validity.verify_base = 1;
+		if (startpriv->uid.type == UA_HYPER_PAV_ALIAS)
+			pfxdata->validity.hyper_pav = 1;
+	}
+
+	/* define extend data (mostly)*/
+	switch (cmd) {
+	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
+	case DASD_ECKD_CCW_READ_RECORD_ZERO:
+	case DASD_ECKD_CCW_READ:
+	case DASD_ECKD_CCW_READ_MT:
+	case DASD_ECKD_CCW_READ_CKD:
+	case DASD_ECKD_CCW_READ_CKD_MT:
+	case DASD_ECKD_CCW_READ_KD:
+	case DASD_ECKD_CCW_READ_KD_MT:
+	case DASD_ECKD_CCW_READ_COUNT:
+		data->mask.perm = 0x1;
+		data->attributes.operation = basepriv->attrib.operation;
+		break;
+	case DASD_ECKD_CCW_WRITE:
+	case DASD_ECKD_CCW_WRITE_MT:
+	case DASD_ECKD_CCW_WRITE_KD:
+	case DASD_ECKD_CCW_WRITE_KD_MT:
+		data->mask.perm = 0x02;
+		data->attributes.operation = basepriv->attrib.operation;
+		rc = check_XRC_on_prefix(pfxdata, basedev);
+		break;
+	case DASD_ECKD_CCW_WRITE_CKD:
+	case DASD_ECKD_CCW_WRITE_CKD_MT:
+		data->attributes.operation = DASD_BYPASS_CACHE;
+		rc = check_XRC_on_prefix(pfxdata, basedev);
+		break;
+	case DASD_ECKD_CCW_ERASE:
+	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
+	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
+		data->mask.perm = 0x3;
+		data->mask.auth = 0x1;
+		data->attributes.operation = DASD_BYPASS_CACHE;
+		rc = check_XRC_on_prefix(pfxdata, basedev);
+		break;
+	default:
+		DEV_MESSAGE(KERN_ERR, basedev, "unknown opcode 0x%x", cmd);
+		break;
+	}
+
+	data->attributes.mode = 0x3;	/* ECKD */
+
+	if ((basepriv->rdc_data.cu_type == 0x2105 ||
+	     basepriv->rdc_data.cu_type == 0x2107 ||
+	     basepriv->rdc_data.cu_type == 0x1750)
+	    && !(basepriv->uses_cdl && trk < 2))
+		data->ga_extended |= 0x40; /* Regular Data Format Mode */
+
+	geo.cyl = basepriv->rdc_data.no_cyl;
+	geo.head = basepriv->rdc_data.trk_per_cyl;
+	beg.cyl = trk / geo.head;
+	beg.head = trk % geo.head;
+	end.cyl = totrk / geo.head;
+	end.head = totrk % geo.head;
+
+	/* check for sequential prestage - enhance cylinder range */
+	if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
+	    data->attributes.operation == DASD_SEQ_ACCESS) {
+
+		if (end.cyl + basepriv->attrib.nr_cyl < geo.cyl)
+			end.cyl += basepriv->attrib.nr_cyl;
+		else
+			end.cyl = (geo.cyl - 1);
+	}
+
+	data->beg_ext.cyl = beg.cyl;
+	data->beg_ext.head = beg.head;
+	data->end_ext.cyl = end.cyl;
+	data->end_ext.head = end.head;
+	return rc;
+}
+
 static void
 locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
 	      int rec_on_trk, int no_rec, int cmd,
@@ -300,7 +416,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
 	ccw->count = 16;
 	ccw->cda = (__u32) __pa(data);
 
-	memset(data, 0, sizeof (struct LO_eckd_data));
+	memset(data, 0, sizeof(struct LO_eckd_data));
 	sector = 0;
 	if (rec_on_trk) {
 		switch (private->rdc_data.dev_type) {
@@ -441,12 +557,15 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
 	       sizeof(uid->serial) - 1);
 	EBCASC(uid->serial, sizeof(uid->serial) - 1);
 	uid->ssid = confdata->neq.subsystemID;
-	if (confdata->ned2.sneq.flags == 0x40) {
-		uid->alias = 1;
-		uid->unit_addr = confdata->ned2.sneq.base_unit_addr;
-	} else
-		uid->unit_addr = confdata->ned1.unit_addr;
-
+	uid->real_unit_addr = confdata->ned1.unit_addr;
+	if (confdata->ned2.sneq.flags == 0x40 &&
+	    confdata->ned2.sneq.format == 0x0001) {
+		uid->type = confdata->ned2.sneq.sua_flags;
+		if (uid->type == UA_BASE_PAV_ALIAS)
+			uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr;
+	} else {
+		uid->type = UA_BASE_DEVICE;
+	}
 	return 0;
 }
 
@@ -470,7 +589,9 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
 	ccw->cda = (__u32)(addr_t)rcd_buffer;
 	ccw->count = ciw->count;
 
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
+	cqr->block = NULL;
 	cqr->expires = 10*HZ;
 	cqr->lpm = lpm;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
@@ -511,7 +632,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
 	/*
 	 * on success we update the user input parms
 	 */
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	if (ret)
 		goto out_error;
 
@@ -557,19 +678,19 @@ dasd_eckd_read_conf(struct dasd_device *device)
 					"data retrieved");
 				continue;	/* no error */
 			}
-			if (conf_len != sizeof (struct dasd_eckd_confdata)) {
+			if (conf_len != sizeof(struct dasd_eckd_confdata)) {
 				MESSAGE(KERN_WARNING,
 					"sizes of configuration data mismatch"
 					"%d (read) vs %ld (expected)",
 					conf_len,
-					sizeof (struct dasd_eckd_confdata));
+					sizeof(struct dasd_eckd_confdata));
 				kfree(conf_data);
 				continue;	/* no error */
 			}
 			/* save first valid configuration data */
 			if (!conf_data_saved){
 				memcpy(&private->conf_data, conf_data,
-				       sizeof (struct dasd_eckd_confdata));
+				       sizeof(struct dasd_eckd_confdata));
 				conf_data_saved++;
 			}
 			switch (((char *)conf_data)[242] & 0x07){
@@ -586,39 +707,104 @@ dasd_eckd_read_conf(struct dasd_device *device)
 	return 0;
 }
 
+static int dasd_eckd_read_features(struct dasd_device *device)
+{
+	struct dasd_psf_prssd_data *prssdp;
+	struct dasd_rssd_features *features;
+	struct dasd_ccw_req *cqr;
+	struct ccw1 *ccw;
+	int rc;
+	struct dasd_eckd_private *private;
+
+	private = (struct dasd_eckd_private *) device->private;
+	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+				   1 /* PSF */	+ 1 /* RSSD */ ,
+				   (sizeof(struct dasd_psf_prssd_data) +
+				    sizeof(struct dasd_rssd_features)),
+				   device);
+	if (IS_ERR(cqr)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "Could not allocate initialization request");
+		return PTR_ERR(cqr);
+	}
+	cqr->startdev = device;
+	cqr->memdev = device;
+	cqr->block = NULL;
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+	cqr->retries = 5;
+	cqr->expires = 10 * HZ;
+
+	/* Prepare for Read Subsystem Data */
+	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
+	prssdp->order = PSF_ORDER_PRSSD;
+	prssdp->suborder = 0x41;	/* Read Feature Codes */
+	/* all other bytes of prssdp must be zero */
+
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
+	ccw->count = sizeof(struct dasd_psf_prssd_data);
+	ccw->flags |= CCW_FLAG_CC;
+	ccw->cda = (__u32)(addr_t) prssdp;
+
+	/* Read Subsystem Data - feature codes */
+	features = (struct dasd_rssd_features *) (prssdp + 1);
+	memset(features, 0, sizeof(struct dasd_rssd_features));
+
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+	ccw->count = sizeof(struct dasd_rssd_features);
+	ccw->cda = (__u32)(addr_t) features;
+
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+	rc = dasd_sleep_on(cqr);
+	if (rc == 0) {
+		prssdp = (struct dasd_psf_prssd_data *) cqr->data;
+		features = (struct dasd_rssd_features *) (prssdp + 1);
+		memcpy(&private->features, features,
+		       sizeof(struct dasd_rssd_features));
+	}
+	dasd_sfree_request(cqr, cqr->memdev);
+	return rc;
+}
+
+
 /*
  * Build CP for Perform Subsystem Function - SSC.
  */
-static struct dasd_ccw_req *
-dasd_eckd_build_psf_ssc(struct dasd_device *device)
+static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device)
 {
-       struct dasd_ccw_req *cqr;
-       struct dasd_psf_ssc_data *psf_ssc_data;
-       struct ccw1 *ccw;
+	struct dasd_ccw_req *cqr;
+	struct dasd_psf_ssc_data *psf_ssc_data;
+	struct ccw1 *ccw;
 
-       cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
+	cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
 				  sizeof(struct dasd_psf_ssc_data),
 				  device);
 
-       if (IS_ERR(cqr)) {
-	       DEV_MESSAGE(KERN_WARNING, device, "%s",
+	if (IS_ERR(cqr)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
 			   "Could not allocate PSF-SSC request");
-	       return cqr;
-       }
-       psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
-       psf_ssc_data->order = PSF_ORDER_SSC;
-       psf_ssc_data->suborder = 0x08;
-
-       ccw = cqr->cpaddr;
-       ccw->cmd_code = DASD_ECKD_CCW_PSF;
-       ccw->cda = (__u32)(addr_t)psf_ssc_data;
-       ccw->count = 66;
-
-       cqr->device = device;
-       cqr->expires = 10*HZ;
-       cqr->buildclk = get_clock();
-       cqr->status = DASD_CQR_FILLED;
-       return cqr;
+		return cqr;
+	}
+	psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
+	psf_ssc_data->order = PSF_ORDER_SSC;
+	psf_ssc_data->suborder = 0x88;
+	psf_ssc_data->reserved[0] = 0x88;
+
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
+	ccw->cda = (__u32)(addr_t)psf_ssc_data;
+	ccw->count = 66;
+
+	cqr->startdev = device;
+	cqr->memdev = device;
+	cqr->block = NULL;
+	cqr->expires = 10*HZ;
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+	return cqr;
 }
 
 /*
@@ -629,28 +815,28 @@ dasd_eckd_build_psf_ssc(struct dasd_device *device)
 static int
 dasd_eckd_psf_ssc(struct dasd_device *device)
 {
-       struct dasd_ccw_req *cqr;
-       int rc;
-
-       cqr = dasd_eckd_build_psf_ssc(device);
-       if (IS_ERR(cqr))
-	       return PTR_ERR(cqr);
-
-       rc = dasd_sleep_on(cqr);
-       if (!rc)
-	       /* trigger CIO to reprobe devices */
-	       css_schedule_reprobe();
-       dasd_sfree_request(cqr, cqr->device);
-       return rc;
+	struct dasd_ccw_req *cqr;
+	int rc;
+
+	cqr = dasd_eckd_build_psf_ssc(device);
+	if (IS_ERR(cqr))
+		return PTR_ERR(cqr);
+
+	rc = dasd_sleep_on(cqr);
+	if (!rc)
+		/* trigger CIO to reprobe devices */
+		css_schedule_reprobe();
+	dasd_sfree_request(cqr, cqr->memdev);
+	return rc;
 }
 
 /*
  * Valide storage server of current device.
  */
-static int
-dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
+static int dasd_eckd_validate_server(struct dasd_device *device)
 {
 	int rc;
+	struct dasd_eckd_private *private;
 
 	/* Currently PAV is the only reason to 'validate' server on LPAR */
 	if (dasd_nopav || MACHINE_IS_VM)
@@ -659,9 +845,11 @@ dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
 	rc = dasd_eckd_psf_ssc(device);
 	/* may be requested feature is not available on server,
 	 * therefore just report error and go ahead */
+	private = (struct dasd_eckd_private *) device->private;
 	DEV_MESSAGE(KERN_INFO, device,
 		    "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d",
-		    uid->vendor, uid->serial, uid->ssid, rc);
+		    private->uid.vendor, private->uid.serial,
+		    private->uid.ssid, rc);
 	/* RE-Read Configuration Data */
 	return dasd_eckd_read_conf(device);
 }
@@ -674,9 +862,9 @@ static int
 dasd_eckd_check_characteristics(struct dasd_device *device)
 {
 	struct dasd_eckd_private *private;
-	struct dasd_uid uid;
+	struct dasd_block *block;
 	void *rdc_data;
-	int rc;
+	int is_known, rc;
 
 	private = (struct dasd_eckd_private *) device->private;
 	if (private == NULL) {
@@ -699,27 +887,54 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
 	/* Read Configuration Data */
 	rc = dasd_eckd_read_conf(device);
 	if (rc)
-		return rc;
+		goto out_err1;
 
 	/* Generate device unique id and register in devmap */
-	rc = dasd_eckd_generate_uid(device, &uid);
+	rc = dasd_eckd_generate_uid(device, &private->uid);
 	if (rc)
-		return rc;
-	rc = dasd_set_uid(device->cdev, &uid);
-	if (rc == 1)	/* new server found */
-		rc = dasd_eckd_validate_server(device, &uid);
+		goto out_err1;
+	dasd_set_uid(device->cdev, &private->uid);
+
+	if (private->uid.type == UA_BASE_DEVICE) {
+		block = dasd_alloc_block();
+		if (IS_ERR(block)) {
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "could not allocate dasd block structure");
+			rc = PTR_ERR(block);
+			goto out_err1;
+		}
+		device->block = block;
+		block->base = device;
+	}
+
+	/* register lcu with alias handling, enable PAV if this is a new lcu */
+	is_known = dasd_alias_make_device_known_to_lcu(device);
+	if (is_known < 0) {
+		rc = is_known;
+		goto out_err2;
+	}
+	if (!is_known) {
+		/* new lcu found */
+		rc = dasd_eckd_validate_server(device); /* will switch pav on */
+		if (rc)
+			goto out_err3;
+	}
+
+	/* Read Feature Codes */
+	rc = dasd_eckd_read_features(device);
 	if (rc)
-		return rc;
+		goto out_err3;
 
 	/* Read Device Characteristics */
 	rdc_data = (void *) &(private->rdc_data);
 	memset(rdc_data, 0, sizeof(rdc_data));
 	rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64);
-	if (rc)
+	if (rc) {
 		DEV_MESSAGE(KERN_WARNING, device,
 			    "Read device characteristics returned "
 			    "rc=%d", rc);
-
+		goto out_err3;
+	}
 	DEV_MESSAGE(KERN_INFO, device,
 		    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
 		    private->rdc_data.dev_type,
@@ -729,9 +944,24 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
 		    private->rdc_data.no_cyl,
 		    private->rdc_data.trk_per_cyl,
 		    private->rdc_data.sec_per_trk);
+	return 0;
+
+out_err3:
+	dasd_alias_disconnect_device_from_lcu(device);
+out_err2:
+	dasd_free_block(device->block);
+	device->block = NULL;
+out_err1:
+	kfree(device->private);
+	device->private = NULL;
 	return rc;
 }
 
+static void dasd_eckd_uncheck_device(struct dasd_device *device)
+{
+	dasd_alias_disconnect_device_from_lcu(device);
+}
+
 static struct dasd_ccw_req *
 dasd_eckd_analysis_ccw(struct dasd_device *device)
 {
@@ -755,7 +985,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
 	/* Define extent for the first 3 tracks. */
 	define_extent(ccw++, cqr->data, 0, 2,
 		      DASD_ECKD_CCW_READ_COUNT, device);
-	LO_data = cqr->data + sizeof (struct DE_eckd_data);
+	LO_data = cqr->data + sizeof(struct DE_eckd_data);
 	/* Locate record for the first 4 records on track 0. */
 	ccw[-1].flags |= CCW_FLAG_CC;
 	locate_record(ccw++, LO_data++, 0, 0, 4,
@@ -783,7 +1013,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
 	ccw->count = 8;
 	ccw->cda = (__u32)(addr_t) count_data;
 
-	cqr->device = device;
+	cqr->block = NULL;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	cqr->retries = 0;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
@@ -803,7 +1035,7 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data)
 	struct dasd_eckd_private *private;
 	struct dasd_device *device;
 
-	device = init_cqr->device;
+	device = init_cqr->startdev;
 	private = (struct dasd_eckd_private *) device->private;
 	private->init_cqr_status = init_cqr->status;
 	dasd_sfree_request(init_cqr, device);
@@ -811,13 +1043,13 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data)
 }
 
 static int
-dasd_eckd_start_analysis(struct dasd_device *device)
+dasd_eckd_start_analysis(struct dasd_block *block)
 {
 	struct dasd_eckd_private *private;
 	struct dasd_ccw_req *init_cqr;
 
-	private = (struct dasd_eckd_private *) device->private;
-	init_cqr = dasd_eckd_analysis_ccw(device);
+	private = (struct dasd_eckd_private *) block->base->private;
+	init_cqr = dasd_eckd_analysis_ccw(block->base);
 	if (IS_ERR(init_cqr))
 		return PTR_ERR(init_cqr);
 	init_cqr->callback = dasd_eckd_analysis_callback;
@@ -828,13 +1060,15 @@ dasd_eckd_start_analysis(struct dasd_device *device)
 }
 
 static int
-dasd_eckd_end_analysis(struct dasd_device *device)
+dasd_eckd_end_analysis(struct dasd_block *block)
 {
+	struct dasd_device *device;
 	struct dasd_eckd_private *private;
 	struct eckd_count *count_area;
 	unsigned int sb, blk_per_trk;
 	int status, i;
 
+	device = block->base;
 	private = (struct dasd_eckd_private *) device->private;
 	status = private->init_cqr_status;
 	private->init_cqr_status = -1;
@@ -846,7 +1080,7 @@ dasd_eckd_end_analysis(struct dasd_device *device)
 
 	private->uses_cdl = 1;
 	/* Calculate number of blocks/records per track. */
-	blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
+	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
 	/* Check Track 0 for Compatible Disk Layout */
 	count_area = NULL;
 	for (i = 0; i < 3; i++) {
@@ -876,56 +1110,65 @@ dasd_eckd_end_analysis(struct dasd_device *device)
 	if (count_area != NULL && count_area->kl == 0) {
 		/* we found notthing violating our disk layout */
 		if (dasd_check_blocksize(count_area->dl) == 0)
-			device->bp_block = count_area->dl;
+			block->bp_block = count_area->dl;
 	}
-	if (device->bp_block == 0) {
+	if (block->bp_block == 0) {
 		DEV_MESSAGE(KERN_WARNING, device, "%s",
 			    "Volume has incompatible disk layout");
 		return -EMEDIUMTYPE;
 	}
-	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
-	for (sb = 512; sb < device->bp_block; sb = sb << 1)
-		device->s2b_shift++;
+	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
+	for (sb = 512; sb < block->bp_block; sb = sb << 1)
+		block->s2b_shift++;
 
-	blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
-	device->blocks = (private->rdc_data.no_cyl *
+	blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block);
+	block->blocks = (private->rdc_data.no_cyl *
 			  private->rdc_data.trk_per_cyl *
 			  blk_per_trk);
 
 	DEV_MESSAGE(KERN_INFO, device,
 		    "(%dkB blks): %dkB at %dkB/trk %s",
-		    (device->bp_block >> 10),
+		    (block->bp_block >> 10),
 		    ((private->rdc_data.no_cyl *
 		      private->rdc_data.trk_per_cyl *
-		      blk_per_trk * (device->bp_block >> 9)) >> 1),
-		    ((blk_per_trk * device->bp_block) >> 10),
+		      blk_per_trk * (block->bp_block >> 9)) >> 1),
+		    ((blk_per_trk * block->bp_block) >> 10),
 		    private->uses_cdl ?
 		    "compatible disk layout" : "linux disk layout");
 
 	return 0;
 }
 
-static int
-dasd_eckd_do_analysis(struct dasd_device *device)
+static int dasd_eckd_do_analysis(struct dasd_block *block)
 {
 	struct dasd_eckd_private *private;
 
-	private = (struct dasd_eckd_private *) device->private;
+	private = (struct dasd_eckd_private *) block->base->private;
 	if (private->init_cqr_status < 0)
-		return dasd_eckd_start_analysis(device);
+		return dasd_eckd_start_analysis(block);
 	else
-		return dasd_eckd_end_analysis(device);
+		return dasd_eckd_end_analysis(block);
 }
 
+static int dasd_eckd_ready_to_online(struct dasd_device *device)
+{
+	return dasd_alias_add_device(device);
+};
+
+static int dasd_eckd_online_to_ready(struct dasd_device *device)
+{
+	return dasd_alias_remove_device(device);
+};
+
 static int
-dasd_eckd_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
+dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
 {
 	struct dasd_eckd_private *private;
 
-	private = (struct dasd_eckd_private *) device->private;
-	if (dasd_check_blocksize(device->bp_block) == 0) {
+	private = (struct dasd_eckd_private *) block->base->private;
+	if (dasd_check_blocksize(block->bp_block) == 0) {
 		geo->sectors = recs_per_track(&private->rdc_data,
-					      0, device->bp_block);
+					      0, block->bp_block);
 	}
 	geo->cylinders = private->rdc_data.no_cyl;
 	geo->heads = private->rdc_data.trk_per_cyl;
@@ -1037,7 +1280,7 @@ dasd_eckd_format_device(struct dasd_device * device,
 		locate_record(ccw++, (struct LO_eckd_data *) data,
 			      fdata->start_unit, 0, rpt + 1,
 			      DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
-			      device->bp_block);
+			      device->block->bp_block);
 		data += sizeof(struct LO_eckd_data);
 		break;
 	case 0x04: /* Invalidate track. */
@@ -1110,43 +1353,28 @@ dasd_eckd_format_device(struct dasd_device * device,
 			ccw++;
 		}
 	}
-	fcp->device = device;
-	fcp->retries = 2;	/* set retry counter to enable ERP */
+	fcp->startdev = device;
+	fcp->memdev = device;
+	clear_bit(DASD_CQR_FLAGS_USE_ERP, &fcp->flags);
+	fcp->retries = 5;	/* set retry counter to enable default ERP */
 	fcp->buildclk = get_clock();
 	fcp->status = DASD_CQR_FILLED;
 	return fcp;
 }
 
-static dasd_era_t
-dasd_eckd_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
+static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
 {
-	struct dasd_device *device = (struct dasd_device *) cqr->device;
-	struct ccw_device *cdev = device->cdev;
-
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	switch (cdev->id.cu_type) {
-	case 0x3990:
-	case 0x2105:
-	case 0x2107:
-	case 0x1750:
-		return dasd_3990_erp_examine(cqr, irb);
-	case 0x9343:
-		return dasd_9343_erp_examine(cqr, irb);
-	case 0x3880:
-	default:
-		DEV_MESSAGE(KERN_WARNING, device, "%s",
-			    "default (unknown CU type) - RECOVERABLE return");
-		return dasd_era_recover;
+	cqr->status = DASD_CQR_FILLED;
+	if (cqr->block && (cqr->startdev != cqr->block->base)) {
+		dasd_eckd_reset_ccw_to_base_io(cqr);
+		cqr->startdev = cqr->block->base;
 	}
-}
+};
 
 static dasd_erp_fn_t
 dasd_eckd_erp_action(struct dasd_ccw_req * cqr)
 {
-	struct dasd_device *device = (struct dasd_device *) cqr->device;
+	struct dasd_device *device = (struct dasd_device *) cqr->startdev;
 	struct ccw_device *cdev = device->cdev;
 
 	switch (cdev->id.cu_type) {
@@ -1168,8 +1396,37 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr)
 	return dasd_default_erp_postaction;
 }
 
-static struct dasd_ccw_req *
-dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
+
+static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
+						   struct irb *irb)
+{
+	char mask;
+
+	/* first of all check for state change pending interrupt */
+	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
+	if ((irb->scsw.dstat & mask) == mask) {
+		dasd_generic_handle_state_change(device);
+		return;
+	}
+
+	/* summary unit check */
+	if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && irb->ecw[7] == 0x0D) {
+		dasd_alias_handle_summary_unit_check(device, irb);
+		return;
+	}
+
+	/* just report other unsolicited interrupts */
+	DEV_MESSAGE(KERN_DEBUG, device, "%s",
+		    "unsolicited interrupt received");
+	device->discipline->dump_sense(device, NULL, irb);
+	dasd_schedule_device_bh(device);
+
+	return;
+};
+
+static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
+					       struct dasd_block *block,
+					       struct request *req)
 {
 	struct dasd_eckd_private *private;
 	unsigned long *idaws;
@@ -1185,8 +1442,11 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
 	sector_t first_trk, last_trk;
 	unsigned int first_offs, last_offs;
 	unsigned char cmd, rcmd;
+	int use_prefix;
+	struct dasd_device *basedev;
 
-	private = (struct dasd_eckd_private *) device->private;
+	basedev = block->base;
+	private = (struct dasd_eckd_private *) basedev->private;
 	if (rq_data_dir(req) == READ)
 		cmd = DASD_ECKD_CCW_READ_MT;
 	else if (rq_data_dir(req) == WRITE)
@@ -1194,13 +1454,13 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
 	else
 		return ERR_PTR(-EINVAL);
 	/* Calculate number of blocks/records per track. */
-	blksize = device->bp_block;
+	blksize = block->bp_block;
 	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
 	/* Calculate record id of first and last block. */
-	first_rec = first_trk = req->sector >> device->s2b_shift;
+	first_rec = first_trk = req->sector >> block->s2b_shift;
 	first_offs = sector_div(first_trk, blk_per_trk);
 	last_rec = last_trk =
-		(req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+		(req->sector + req->nr_sectors - 1) >> block->s2b_shift;
 	last_offs = sector_div(last_trk, blk_per_trk);
 	/* Check struct bio and count the number of blocks for the request. */
 	count = 0;
@@ -1209,20 +1469,33 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
 		if (bv->bv_len & (blksize - 1))
 			/* Eckd can only do full blocks. */
 			return ERR_PTR(-EINVAL);
-		count += bv->bv_len >> (device->s2b_shift + 9);
+		count += bv->bv_len >> (block->s2b_shift + 9);
 #if defined(CONFIG_64BIT)
 		if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
-			cidaw += bv->bv_len >> (device->s2b_shift + 9);
+			cidaw += bv->bv_len >> (block->s2b_shift + 9);
 #endif
 	}
 	/* Paranoia. */
 	if (count != last_rec - first_rec + 1)
 		return ERR_PTR(-EINVAL);
-	/* 1x define extent + 1x locate record + number of blocks */
-	cplength = 2 + count;
-	/* 1x define extent + 1x locate record + cidaws*sizeof(long) */
-	datasize = sizeof(struct DE_eckd_data) + sizeof(struct LO_eckd_data) +
-		cidaw * sizeof(unsigned long);
+
+	/* use the prefix command if available */
+	use_prefix = private->features.feature[8] & 0x01;
+	if (use_prefix) {
+		/* 1x prefix + number of blocks */
+		cplength = 2 + count;
+		/* 1x prefix + cidaws*sizeof(long) */
+		datasize = sizeof(struct PFX_eckd_data) +
+			sizeof(struct LO_eckd_data) +
+			cidaw * sizeof(unsigned long);
+	} else {
+		/* 1x define extent + 1x locate record + number of blocks */
+		cplength = 2 + count;
+		/* 1x define extent + 1x locate record + cidaws*sizeof(long) */
+		datasize = sizeof(struct DE_eckd_data) +
+			sizeof(struct LO_eckd_data) +
+			cidaw * sizeof(unsigned long);
+	}
 	/* Find out the number of additional locate record ccws for cdl. */
 	if (private->uses_cdl && first_rec < 2*blk_per_trk) {
 		if (last_rec >= 2*blk_per_trk)
@@ -1232,26 +1505,42 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
 	}
 	/* Allocate the ccw request. */
 	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
-				   cplength, datasize, device);
+				   cplength, datasize, startdev);
 	if (IS_ERR(cqr))
 		return cqr;
 	ccw = cqr->cpaddr;
-	/* First ccw is define extent. */
-	if (define_extent(ccw++, cqr->data, first_trk,
-			  last_trk, cmd, device) == -EAGAIN) {
-		/* Clock not in sync and XRC is enabled. Try again later. */
-		dasd_sfree_request(cqr, device);
-		return ERR_PTR(-EAGAIN);
+	/* First ccw is define extent or prefix. */
+	if (use_prefix) {
+		if (prefix(ccw++, cqr->data, first_trk,
+			   last_trk, cmd, basedev, startdev) == -EAGAIN) {
+			/* Clock not in sync and XRC is enabled.
+			 * Try again later.
+			 */
+			dasd_sfree_request(cqr, startdev);
+			return ERR_PTR(-EAGAIN);
+		}
+		idaws = (unsigned long *) (cqr->data +
+					   sizeof(struct PFX_eckd_data));
+	} else {
+		if (define_extent(ccw++, cqr->data, first_trk,
+				  last_trk, cmd, startdev) == -EAGAIN) {
+			/* Clock not in sync and XRC is enabled.
+			 * Try again later.
+			 */
+			dasd_sfree_request(cqr, startdev);
+			return ERR_PTR(-EAGAIN);
+		}
+		idaws = (unsigned long *) (cqr->data +
+					   sizeof(struct DE_eckd_data));
 	}
 	/* Build locate_record+read/write/ccws. */
-	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
 	LO_data = (struct LO_eckd_data *) (idaws + cidaw);
 	recid = first_rec;
 	if (private->uses_cdl == 0 || recid > 2*blk_per_trk) {
 		/* Only standard blocks so there is just one locate record. */
 		ccw[-1].flags |= CCW_FLAG_CC;
 		locate_record(ccw++, LO_data++, first_trk, first_offs + 1,
-			      last_rec - recid + 1, cmd, device, blksize);
+			      last_rec - recid + 1, cmd, basedev, blksize);
 	}
 	rq_for_each_segment(bv, req, iter) {
 		dst = page_address(bv->bv_page) + bv->bv_offset;
@@ -1281,7 +1570,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
 				ccw[-1].flags |= CCW_FLAG_CC;
 				locate_record(ccw++, LO_data++,
 					      trkid, recoffs + 1,
-					      1, rcmd, device, count);
+					      1, rcmd, basedev, count);
 			}
 			/* Locate record for standard blocks ? */
 			if (private->uses_cdl && recid == 2*blk_per_trk) {
@@ -1289,7 +1578,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
 				locate_record(ccw++, LO_data++,
 					      trkid, recoffs + 1,
 					      last_rec - recid + 1,
-					      cmd, device, count);
+					      cmd, basedev, count);
 			}
 			/* Read/write ccw. */
 			ccw[-1].flags |= CCW_FLAG_CC;
@@ -1310,7 +1599,9 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
 	}
 	if (req->cmd_flags & REQ_FAILFAST)
 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->device = device;
+	cqr->startdev = startdev;
+	cqr->memdev = startdev;
+	cqr->block = block;
 	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
 	cqr->lpm = private->path_data.ppm;
 	cqr->retries = 256;
@@ -1333,10 +1624,10 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
 
 	if (!dasd_page_cache)
 		goto out;
-	private = (struct dasd_eckd_private *) cqr->device->private;
-	blksize = cqr->device->bp_block;
+	private = (struct dasd_eckd_private *) cqr->block->base->private;
+	blksize = cqr->block->bp_block;
 	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
-	recid = req->sector >> cqr->device->s2b_shift;
+	recid = req->sector >> cqr->block->s2b_shift;
 	ccw = cqr->cpaddr;
 	/* Skip over define extent & locate record. */
 	ccw++;
@@ -1367,10 +1658,71 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
 	}
 out:
 	status = cqr->status == DASD_CQR_DONE;
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return status;
 }
 
+/*
+ * Modify ccw chain in cqr so it can be started on a base device.
+ *
+ * Note that this is not enough to restart the cqr!
+ * Either reset cqr->startdev as well (summary unit check handling)
+ * or restart via separate cqr (as in ERP handling).
+ */
+void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *cqr)
+{
+	struct ccw1 *ccw;
+	struct PFX_eckd_data *pfxdata;
+
+	ccw = cqr->cpaddr;
+	pfxdata = cqr->data;
+
+	if (ccw->cmd_code == DASD_ECKD_CCW_PFX) {
+		pfxdata->validity.verify_base = 0;
+		pfxdata->validity.hyper_pav = 0;
+	}
+}
+
+#define DASD_ECKD_CHANQ_MAX_SIZE 4
+
+static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
+						     struct dasd_block *block,
+						     struct request *req)
+{
+	struct dasd_eckd_private *private;
+	struct dasd_device *startdev;
+	unsigned long flags;
+	struct dasd_ccw_req *cqr;
+
+	startdev = dasd_alias_get_start_dev(base);
+	if (!startdev)
+		startdev = base;
+	private = (struct dasd_eckd_private *) startdev->private;
+	if (private->count >= DASD_ECKD_CHANQ_MAX_SIZE)
+		return ERR_PTR(-EBUSY);
+
+	spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags);
+	private->count++;
+	cqr = dasd_eckd_build_cp(startdev, block, req);
+	if (IS_ERR(cqr))
+		private->count--;
+	spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags);
+	return cqr;
+}
+
+static int dasd_eckd_free_alias_cp(struct dasd_ccw_req *cqr,
+				   struct request *req)
+{
+	struct dasd_eckd_private *private;
+	unsigned long flags;
+
+	spin_lock_irqsave(get_ccwdev_lock(cqr->memdev->cdev), flags);
+	private = (struct dasd_eckd_private *) cqr->memdev->private;
+	private->count--;
+	spin_unlock_irqrestore(get_ccwdev_lock(cqr->memdev->cdev), flags);
+	return dasd_eckd_free_cp(cqr, req);
+}
+
 static int
 dasd_eckd_fill_info(struct dasd_device * device,
 		    struct dasd_information2_t * info)
@@ -1384,9 +1736,9 @@ dasd_eckd_fill_info(struct dasd_device * device,
 	info->characteristics_size = sizeof(struct dasd_eckd_characteristics);
 	memcpy(info->characteristics, &private->rdc_data,
 	       sizeof(struct dasd_eckd_characteristics));
-	info->confdata_size = sizeof (struct dasd_eckd_confdata);
+	info->confdata_size = sizeof(struct dasd_eckd_confdata);
 	memcpy(info->configuration_data, &private->conf_data,
-	       sizeof (struct dasd_eckd_confdata));
+	       sizeof(struct dasd_eckd_confdata));
 	return 0;
 }
 
@@ -1419,7 +1771,8 @@ dasd_eckd_release(struct dasd_device *device)
         cqr->cpaddr->flags |= CCW_FLAG_SLI;
         cqr->cpaddr->count = 32;
 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
@@ -1429,7 +1782,7 @@ dasd_eckd_release(struct dasd_device *device)
 
 	rc = dasd_sleep_on_immediatly(cqr);
 
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return rc;
 }
 
@@ -1459,7 +1812,8 @@ dasd_eckd_reserve(struct dasd_device *device)
         cqr->cpaddr->flags |= CCW_FLAG_SLI;
         cqr->cpaddr->count = 32;
 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
@@ -1469,7 +1823,7 @@ dasd_eckd_reserve(struct dasd_device *device)
 
 	rc = dasd_sleep_on_immediatly(cqr);
 
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return rc;
 }
 
@@ -1498,7 +1852,8 @@ dasd_eckd_steal_lock(struct dasd_device *device)
         cqr->cpaddr->flags |= CCW_FLAG_SLI;
         cqr->cpaddr->count = 32;
 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 	set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
 	cqr->retries = 2;	/* set retry counter to enable basic ERP */
@@ -1508,7 +1863,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
 
 	rc = dasd_sleep_on_immediatly(cqr);
 
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return rc;
 }
 
@@ -1526,52 +1881,52 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp)
 
 	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
 				   1 /* PSF */  + 1 /* RSSD */ ,
-				   (sizeof (struct dasd_psf_prssd_data) +
-				    sizeof (struct dasd_rssd_perf_stats_t)),
+				   (sizeof(struct dasd_psf_prssd_data) +
+				    sizeof(struct dasd_rssd_perf_stats_t)),
 				   device);
 	if (IS_ERR(cqr)) {
 		DEV_MESSAGE(KERN_WARNING, device, "%s",
 			    "Could not allocate initialization request");
 		return PTR_ERR(cqr);
 	}
-	cqr->device = device;
+	cqr->startdev = device;
+	cqr->memdev = device;
 	cqr->retries = 0;
 	cqr->expires = 10 * HZ;
 
 	/* Prepare for Read Subsystem Data */
 	prssdp = (struct dasd_psf_prssd_data *) cqr->data;
-	memset(prssdp, 0, sizeof (struct dasd_psf_prssd_data));
+	memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data));
 	prssdp->order = PSF_ORDER_PRSSD;
-	prssdp->suborder = 0x01;	/* Perfomance Statistics */
+	prssdp->suborder = 0x01;	/* Performance Statistics */
 	prssdp->varies[1] = 0x01;	/* Perf Statistics for the Subsystem */
 
 	ccw = cqr->cpaddr;
 	ccw->cmd_code = DASD_ECKD_CCW_PSF;
-	ccw->count = sizeof (struct dasd_psf_prssd_data);
+	ccw->count = sizeof(struct dasd_psf_prssd_data);
 	ccw->flags |= CCW_FLAG_CC;
 	ccw->cda = (__u32)(addr_t) prssdp;
 
 	/* Read Subsystem Data - Performance Statistics */
 	stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
-	memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t));
+	memset(stats, 0, sizeof(struct dasd_rssd_perf_stats_t));
 
 	ccw++;
 	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
-	ccw->count = sizeof (struct dasd_rssd_perf_stats_t);
+	ccw->count = sizeof(struct dasd_rssd_perf_stats_t);
 	ccw->cda = (__u32)(addr_t) stats;
 
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 	rc = dasd_sleep_on(cqr);
 	if (rc == 0) {
-		/* Prepare for Read Subsystem Data */
 		prssdp = (struct dasd_psf_prssd_data *) cqr->data;
 		stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
 		if (copy_to_user(argp, stats,
 				 sizeof(struct dasd_rssd_perf_stats_t)))
 			rc = -EFAULT;
 	}
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return rc;
 }
 
@@ -1594,7 +1949,7 @@ dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp)
 
 	rc = 0;
 	if (copy_to_user(argp, (long *) &attrib,
-			 sizeof (struct attrib_data_t)))
+			 sizeof(struct attrib_data_t)))
 		rc = -EFAULT;
 
 	return rc;
@@ -1627,8 +1982,10 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp)
 }
 
 static int
-dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
+dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp)
 {
+	struct dasd_device *device = block->base;
+
 	switch (cmd) {
 	case BIODASDGATTR:
 		return dasd_eckd_get_attrib(device, argp);
@@ -1685,9 +2042,8 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
  * Print sense data and related channel program.
  * Parts are printed because printk buffer is only 1024 bytes.
  */
-static void
-dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
-		     struct irb *irb)
+static void dasd_eckd_dump_sense(struct dasd_device *device,
+				 struct dasd_ccw_req *req, struct irb *irb)
 {
 	char *page;
 	struct ccw1 *first, *last, *fail, *from, *to;
@@ -1743,37 +2099,40 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
 	}
 	printk("%s", page);
 
-	/* dump the Channel Program (max 140 Bytes per line) */
-	/* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
-	first = req->cpaddr;
-	for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
-	to = min(first + 6, last);
-	len = sprintf(page,  KERN_ERR PRINTK_HEADER
-		      " Related CP in req: %p\n", req);
-	dasd_eckd_dump_ccw_range(first, to, page + len);
-	printk("%s", page);
+	if (req) {
+		/* req == NULL for unsolicited interrupts */
+		/* dump the Channel Program (max 140 Bytes per line) */
+		/* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
+		first = req->cpaddr;
+		for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
+		to = min(first + 6, last);
+		len = sprintf(page,  KERN_ERR PRINTK_HEADER
+			      " Related CP in req: %p\n", req);
+		dasd_eckd_dump_ccw_range(first, to, page + len);
+		printk("%s", page);
 
-	/* print failing CCW area (maximum 4) */
-	/* scsw->cda is either valid or zero  */
-	len = 0;
-	from = ++to;
-	fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
-	if (from <  fail - 2) {
-		from = fail - 2;     /* there is a gap - print header */
-		len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
-	}
-	to = min(fail + 1, last);
-	len += dasd_eckd_dump_ccw_range(from, to, page + len);
-
-	/* print last CCWs (maximum 2) */
-	from = max(from, ++to);
-	if (from < last - 1) {
-		from = last - 1;     /* there is a gap - print header */
-		len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
+		/* print failing CCW area (maximum 4) */
+		/* scsw->cda is either valid or zero  */
+		len = 0;
+		from = ++to;
+		fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
+		if (from <  fail - 2) {
+			from = fail - 2;     /* there is a gap - print header */
+			len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
+		}
+		to = min(fail + 1, last);
+		len += dasd_eckd_dump_ccw_range(from, to, page + len);
+
+		/* print last CCWs (maximum 2) */
+		from = max(from, ++to);
+		if (from < last - 1) {
+			from = last - 1;     /* there is a gap - print header */
+			len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
+		}
+		len += dasd_eckd_dump_ccw_range(from, last, page + len);
+		if (len > 0)
+			printk("%s", page);
 	}
-	len += dasd_eckd_dump_ccw_range(from, last, page + len);
-	if (len > 0)
-		printk("%s", page);
 	free_page((unsigned long) page);
 }
 
@@ -1796,16 +2155,20 @@ static struct dasd_discipline dasd_eckd_discipline = {
 	.ebcname = "ECKD",
 	.max_blocks = 240,
 	.check_device = dasd_eckd_check_characteristics,
+	.uncheck_device = dasd_eckd_uncheck_device,
 	.do_analysis = dasd_eckd_do_analysis,
+	.ready_to_online = dasd_eckd_ready_to_online,
+	.online_to_ready = dasd_eckd_online_to_ready,
 	.fill_geometry = dasd_eckd_fill_geometry,
 	.start_IO = dasd_start_IO,
 	.term_IO = dasd_term_IO,
+	.handle_terminated_request = dasd_eckd_handle_terminated_request,
 	.format_device = dasd_eckd_format_device,
-	.examine_error = dasd_eckd_examine_error,
 	.erp_action = dasd_eckd_erp_action,
 	.erp_postaction = dasd_eckd_erp_postaction,
-	.build_cp = dasd_eckd_build_cp,
-	.free_cp = dasd_eckd_free_cp,
+	.handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt,
+	.build_cp = dasd_eckd_build_alias_cp,
+	.free_cp = dasd_eckd_free_alias_cp,
 	.dump_sense = dasd_eckd_dump_sense,
 	.fill_info = dasd_eckd_fill_info,
 	.ioctl = dasd_eckd_ioctl,
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 712ff1650134..fc2509c939bc 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -39,6 +39,8 @@
 #define DASD_ECKD_CCW_READ_CKD_MT	 0x9e
 #define DASD_ECKD_CCW_WRITE_CKD_MT	 0x9d
 #define DASD_ECKD_CCW_RESERVE		 0xB4
+#define DASD_ECKD_CCW_PFX		 0xE7
+#define DASD_ECKD_CCW_RSCK		 0xF9
 
 /*
  * Perform Subsystem Function / Sub-Orders
@@ -137,6 +139,25 @@ struct LO_eckd_data {
 	__u16 length;
 } __attribute__ ((packed));
 
+/* Prefix data for format 0x00 and 0x01 */
+struct PFX_eckd_data {
+	unsigned char format;
+	struct {
+		unsigned char define_extend:1;
+		unsigned char time_stamp:1;
+		unsigned char verify_base:1;
+		unsigned char hyper_pav:1;
+		unsigned char reserved:4;
+	} __attribute__ ((packed)) validity;
+	__u8 base_address;
+	__u8 aux;
+	__u8 base_lss;
+	__u8 reserved[7];
+	struct DE_eckd_data define_extend;
+	struct LO_eckd_data locate_record;
+	__u8 LO_extended_data[4];
+} __attribute__ ((packed));
+
 struct dasd_eckd_characteristics {
 	__u16 cu_type;
 	struct {
@@ -254,7 +275,9 @@ struct dasd_eckd_confdata {
 		} __attribute__ ((packed)) ned;
 		struct {
 			unsigned char flags;            /* byte  0    */
-			unsigned char res2[7];          /* byte  1- 7 */
+			unsigned char res1;		/* byte  1    */
+			__u16 format;			/* byte  2-3  */
+			unsigned char res2[4];		/* byte  4-7  */
 			unsigned char sua_flags;	/* byte  8    */
 			__u8 base_unit_addr;            /* byte  9    */
 			unsigned char res3[22];	        /* byte 10-31 */
@@ -343,6 +366,11 @@ struct dasd_eckd_path {
 	__u8 npm;
 };
 
+struct dasd_rssd_features {
+	char feature[256];
+} __attribute__((packed));
+
+
 /*
  * Perform Subsystem Function - Prepare for Read Subsystem Data
  */
@@ -365,4 +393,99 @@ struct dasd_psf_ssc_data {
 	unsigned char reserved[59];
 } __attribute__((packed));
 
+
+/*
+ * some structures and definitions for alias handling
+ */
+struct dasd_unit_address_configuration {
+	struct {
+		char ua_type;
+		char base_ua;
+	} unit[256];
+} __attribute__((packed));
+
+
+#define MAX_DEVICES_PER_LCU 256
+
+/* flags on the LCU  */
+#define NEED_UAC_UPDATE  0x01
+#define UPDATE_PENDING	0x02
+
+enum pavtype {NO_PAV, BASE_PAV, HYPER_PAV};
+
+
+struct alias_root {
+	struct list_head serverlist;
+	spinlock_t lock;
+};
+
+struct alias_server {
+	struct list_head server;
+	struct dasd_uid uid;
+	struct list_head lculist;
+};
+
+struct summary_unit_check_work_data {
+	char reason;
+	struct dasd_device *device;
+	struct work_struct worker;
+};
+
+struct read_uac_work_data {
+	struct dasd_device *device;
+	struct delayed_work dwork;
+};
+
+struct alias_lcu {
+	struct list_head lcu;
+	struct dasd_uid uid;
+	enum pavtype pav;
+	char flags;
+	spinlock_t lock;
+	struct list_head grouplist;
+	struct list_head active_devices;
+	struct list_head inactive_devices;
+	struct dasd_unit_address_configuration *uac;
+	struct summary_unit_check_work_data suc_data;
+	struct read_uac_work_data ruac_data;
+	struct dasd_ccw_req *rsu_cqr;
+};
+
+struct alias_pav_group {
+	struct list_head group;
+	struct dasd_uid uid;
+	struct alias_lcu *lcu;
+	struct list_head baselist;
+	struct list_head aliaslist;
+	struct dasd_device *next;
+};
+
+
+struct dasd_eckd_private {
+	struct dasd_eckd_characteristics rdc_data;
+	struct dasd_eckd_confdata conf_data;
+	struct dasd_eckd_path path_data;
+	struct eckd_count count_area[5];
+	int init_cqr_status;
+	int uses_cdl;
+	struct attrib_data_t attrib;	/* e.g. cache operations */
+	struct dasd_rssd_features features;
+
+	/* alias managemnet */
+	struct dasd_uid uid;
+	struct alias_pav_group *pavgroup;
+	struct alias_lcu *lcu;
+	int count;
+};
+
+
+
+int dasd_alias_make_device_known_to_lcu(struct dasd_device *);
+void dasd_alias_disconnect_device_from_lcu(struct dasd_device *);
+int dasd_alias_add_device(struct dasd_device *);
+int dasd_alias_remove_device(struct dasd_device *);
+struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *);
+void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
+void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
+
 #endif				/* DASD_ECKD_H */
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index 0c081a664ee8..6e53ab606e97 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -336,7 +336,7 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device,
 	unsigned long flags;
 	struct eerbuffer *eerb;
 
-	snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+	snss_rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;
 	if (snss_rc)
 		data_size = 0;
 	else
@@ -404,10 +404,11 @@ void dasd_eer_snss(struct dasd_device *device)
 		set_bit(DASD_FLAG_EER_SNSS, &device->flags);
 		return;
 	}
+	/* cdev is already locked, can't use dasd_add_request_head */
 	clear_bit(DASD_FLAG_EER_SNSS, &device->flags);
 	cqr->status = DASD_CQR_QUEUED;
-	list_add(&cqr->list, &device->ccw_queue);
-	dasd_schedule_bh(device);
+	list_add(&cqr->devlist, &device->ccw_queue);
+	dasd_schedule_device_bh(device);
 }
 
 /*
@@ -415,7 +416,7 @@ void dasd_eer_snss(struct dasd_device *device)
  */
 static void dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data)
 {
-        struct dasd_device *device = cqr->device;
+	struct dasd_device *device = cqr->startdev;
 	unsigned long flags;
 
 	dasd_eer_write(device, cqr, DASD_EER_STATECHANGE);
@@ -458,7 +459,7 @@ int dasd_eer_enable(struct dasd_device *device)
 	if (!cqr)
 		return -ENOMEM;
 
-	cqr->device = device;
+	cqr->startdev = device;
 	cqr->retries = 255;
 	cqr->expires = 10 * HZ;
 	clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index caa5d91420f8..8f10000851a3 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -46,6 +46,8 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
 	if (cqr == NULL)
 		return ERR_PTR(-ENOMEM);
 	memset(cqr, 0, sizeof(struct dasd_ccw_req));
+	INIT_LIST_HEAD(&cqr->devlist);
+	INIT_LIST_HEAD(&cqr->blocklist);
 	data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L);
 	cqr->cpaddr = NULL;
 	if (cplength > 0) {
@@ -66,7 +68,7 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize,
 }
 
 void
-dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
+dasd_free_erp_request(struct dasd_ccw_req *cqr, struct dasd_device * device)
 {
 	unsigned long flags;
 
@@ -81,11 +83,11 @@ dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device)
  * dasd_default_erp_action just retries the current cqr
  */
 struct dasd_ccw_req *
-dasd_default_erp_action(struct dasd_ccw_req * cqr)
+dasd_default_erp_action(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device;
 
-	device = cqr->device;
+	device = cqr->startdev;
 
         /* just retry - there is nothing to save ... I got no sense data.... */
         if (cqr->retries > 0) {
@@ -93,12 +95,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
                              "default ERP called (%i retries left)",
                              cqr->retries);
 		cqr->lpm    = LPM_ANYPATH;
-		cqr->status = DASD_CQR_QUEUED;
+		cqr->status = DASD_CQR_FILLED;
         } else {
                 DEV_MESSAGE (KERN_WARNING, device, "%s",
 			     "default ERP called (NO retry left)");
 		cqr->status = DASD_CQR_FAILED;
-		cqr->stopclk = get_clock ();
+		cqr->stopclk = get_clock();
         }
         return cqr;
 }				/* end dasd_default_erp_action */
@@ -117,15 +119,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
  * RETURN VALUES
  *   cqr		pointer to the original CQR
  */
-struct dasd_ccw_req *
-dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
+struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
 {
-	struct dasd_device *device;
 	int success;
 
 	BUG_ON(cqr->refers == NULL || cqr->function == NULL);
 
-	device = cqr->device;
 	success = cqr->status == DASD_CQR_DONE;
 
 	/* free all ERPs - but NOT the original cqr */
@@ -133,10 +132,10 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
 		struct dasd_ccw_req *refers;
 
 		refers = cqr->refers;
-		/* remove the request from the device queue */
-		list_del(&cqr->list);
+		/* remove the request from the block queue */
+		list_del(&cqr->blocklist);
 		/* free the finished erp request */
-		dasd_free_erp_request(cqr, device);
+		dasd_free_erp_request(cqr, cqr->memdev);
 		cqr = refers;
 	}
 
@@ -157,7 +156,7 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
 {
 	struct dasd_device *device;
 
-	device = cqr->device;
+	device = cqr->startdev;
 	/* dump sense data */
 	if (device->discipline && device->discipline->dump_sense)
 		device->discipline->dump_sense(device, cqr, irb);
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 1d95822e0b8e..d13ea05089a7 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -117,6 +117,7 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
 static int
 dasd_fba_check_characteristics(struct dasd_device *device)
 {
+	struct dasd_block *block;
 	struct dasd_fba_private *private;
 	struct ccw_device *cdev = device->cdev;
 	void *rdc_data;
@@ -133,6 +134,16 @@ dasd_fba_check_characteristics(struct dasd_device *device)
 		}
 		device->private = (void *) private;
 	}
+	block = dasd_alloc_block();
+	if (IS_ERR(block)) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "could not allocate dasd block structure");
+		kfree(device->private);
+		return PTR_ERR(block);
+	}
+	device->block = block;
+	block->base = device;
+
 	/* Read Device Characteristics */
 	rdc_data = (void *) &(private->rdc_data);
 	rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
@@ -155,60 +166,37 @@ dasd_fba_check_characteristics(struct dasd_device *device)
 	return 0;
 }
 
-static int
-dasd_fba_do_analysis(struct dasd_device *device)
+static int dasd_fba_do_analysis(struct dasd_block *block)
 {
 	struct dasd_fba_private *private;
 	int sb, rc;
 
-	private = (struct dasd_fba_private *) device->private;
+	private = (struct dasd_fba_private *) block->base->private;
 	rc = dasd_check_blocksize(private->rdc_data.blk_size);
 	if (rc) {
-		DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d",
+		DEV_MESSAGE(KERN_INFO, block->base, "unknown blocksize %d",
 			    private->rdc_data.blk_size);
 		return rc;
 	}
-	device->blocks = private->rdc_data.blk_bdsa;
-	device->bp_block = private->rdc_data.blk_size;
-	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
+	block->blocks = private->rdc_data.blk_bdsa;
+	block->bp_block = private->rdc_data.blk_size;
+	block->s2b_shift = 0;	/* bits to shift 512 to get a block */
 	for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1)
-		device->s2b_shift++;
+		block->s2b_shift++;
 	return 0;
 }
 
-static int
-dasd_fba_fill_geometry(struct dasd_device *device, struct hd_geometry *geo)
+static int dasd_fba_fill_geometry(struct dasd_block *block,
+				  struct hd_geometry *geo)
 {
-	if (dasd_check_blocksize(device->bp_block) != 0)
+	if (dasd_check_blocksize(block->bp_block) != 0)
 		return -EINVAL;
-	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
+	geo->cylinders = (block->blocks << block->s2b_shift) >> 10;
 	geo->heads = 16;
-	geo->sectors = 128 >> device->s2b_shift;
+	geo->sectors = 128 >> block->s2b_shift;
 	return 0;
 }
 
-static dasd_era_t
-dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
-{
-	struct dasd_device *device;
-	struct ccw_device *cdev;
-
-	device = (struct dasd_device *) cqr->device;
-	if (irb->scsw.cstat == 0x00 &&
-	    irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	cdev = device->cdev;
-	switch (cdev->id.dev_type) {
-	case 0x3370:
-		return dasd_3370_erp_examine(cqr, irb);
-	case 0x9336:
-		return dasd_9336_erp_examine(cqr, irb);
-	default:
-		return dasd_era_recover;
-	}
-}
-
 static dasd_erp_fn_t
 dasd_fba_erp_action(struct dasd_ccw_req * cqr)
 {
@@ -221,13 +209,34 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr)
 	if (cqr->function == dasd_default_erp_action)
 		return dasd_default_erp_postaction;
 
-	DEV_MESSAGE(KERN_WARNING, cqr->device, "unknown ERP action %p",
+	DEV_MESSAGE(KERN_WARNING, cqr->startdev, "unknown ERP action %p",
 		    cqr->function);
 	return NULL;
 }
 
-static struct dasd_ccw_req *
-dasd_fba_build_cp(struct dasd_device * device, struct request *req)
+static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device,
+						   struct irb *irb)
+{
+	char mask;
+
+	/* first of all check for state change pending interrupt */
+	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
+	if ((irb->scsw.dstat & mask) == mask) {
+		dasd_generic_handle_state_change(device);
+		return;
+	}
+
+	/* check for unsolicited interrupts */
+	DEV_MESSAGE(KERN_DEBUG, device, "%s",
+		    "unsolicited interrupt received");
+	device->discipline->dump_sense(device, NULL, irb);
+	dasd_schedule_device_bh(device);
+	return;
+};
+
+static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
+					      struct dasd_block *block,
+					      struct request *req)
 {
 	struct dasd_fba_private *private;
 	unsigned long *idaws;
@@ -242,17 +251,17 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
 	unsigned int blksize, off;
 	unsigned char cmd;
 
-	private = (struct dasd_fba_private *) device->private;
+	private = (struct dasd_fba_private *) block->base->private;
 	if (rq_data_dir(req) == READ) {
 		cmd = DASD_FBA_CCW_READ;
 	} else if (rq_data_dir(req) == WRITE) {
 		cmd = DASD_FBA_CCW_WRITE;
 	} else
 		return ERR_PTR(-EINVAL);
-	blksize = device->bp_block;
+	blksize = block->bp_block;
 	/* Calculate record id of first and last block. */
-	first_rec = req->sector >> device->s2b_shift;
-	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+	first_rec = req->sector >> block->s2b_shift;
+	last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift;
 	/* Check struct bio and count the number of blocks for the request. */
 	count = 0;
 	cidaw = 0;
@@ -260,7 +269,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
 		if (bv->bv_len & (blksize - 1))
 			/* Fba can only do full blocks. */
 			return ERR_PTR(-EINVAL);
-		count += bv->bv_len >> (device->s2b_shift + 9);
+		count += bv->bv_len >> (block->s2b_shift + 9);
 #if defined(CONFIG_64BIT)
 		if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
 			cidaw += bv->bv_len / blksize;
@@ -284,13 +293,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
 	}
 	/* Allocate the ccw request. */
 	cqr = dasd_smalloc_request(dasd_fba_discipline.name,
-				   cplength, datasize, device);
+				   cplength, datasize, memdev);
 	if (IS_ERR(cqr))
 		return cqr;
 	ccw = cqr->cpaddr;
 	/* First ccw is define extent. */
 	define_extent(ccw++, cqr->data, rq_data_dir(req),
-		      device->bp_block, req->sector, req->nr_sectors);
+		      block->bp_block, req->sector, req->nr_sectors);
 	/* Build locate_record + read/write ccws. */
 	idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data));
 	LO_data = (struct LO_fba_data *) (idaws + cidaw);
@@ -326,7 +335,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
 					ccw[-1].flags |= CCW_FLAG_CC;
 			}
 			ccw->cmd_code = cmd;
-			ccw->count = device->bp_block;
+			ccw->count = block->bp_block;
 			if (idal_is_needed(dst, blksize)) {
 				ccw->cda = (__u32)(addr_t) idaws;
 				ccw->flags = CCW_FLAG_IDA;
@@ -342,7 +351,9 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
 	}
 	if (req->cmd_flags & REQ_FAILFAST)
 		set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-	cqr->device = device;
+	cqr->startdev = memdev;
+	cqr->memdev = memdev;
+	cqr->block = block;
 	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
 	cqr->retries = 32;
 	cqr->buildclk = get_clock();
@@ -363,8 +374,8 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
 
 	if (!dasd_page_cache)
 		goto out;
-	private = (struct dasd_fba_private *) cqr->device->private;
-	blksize = cqr->device->bp_block;
+	private = (struct dasd_fba_private *) cqr->block->base->private;
+	blksize = cqr->block->bp_block;
 	ccw = cqr->cpaddr;
 	/* Skip over define extent & locate record. */
 	ccw++;
@@ -394,10 +405,15 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
 	}
 out:
 	status = cqr->status == DASD_CQR_DONE;
-	dasd_sfree_request(cqr, cqr->device);
+	dasd_sfree_request(cqr, cqr->memdev);
 	return status;
 }
 
+static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr)
+{
+	cqr->status = DASD_CQR_FILLED;
+};
+
 static int
 dasd_fba_fill_info(struct dasd_device * device,
 		   struct dasd_information2_t * info)
@@ -546,9 +562,10 @@ static struct dasd_discipline dasd_fba_discipline = {
 	.fill_geometry = dasd_fba_fill_geometry,
 	.start_IO = dasd_start_IO,
 	.term_IO = dasd_term_IO,
-	.examine_error = dasd_fba_examine_error,
+	.handle_terminated_request = dasd_fba_handle_terminated_request,
 	.erp_action = dasd_fba_erp_action,
 	.erp_postaction = dasd_fba_erp_postaction,
+	.handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt,
 	.build_cp = dasd_fba_build_cp,
 	.free_cp = dasd_fba_free_cp,
 	.dump_sense = dasd_fba_dump_sense,
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index 47ba4462708d..aee6565aaf98 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -25,14 +25,15 @@
 /*
  * Allocate and register gendisk structure for device.
  */
-int
-dasd_gendisk_alloc(struct dasd_device *device)
+int dasd_gendisk_alloc(struct dasd_block *block)
 {
 	struct gendisk *gdp;
+	struct dasd_device *base;
 	int len;
 
 	/* Make sure the minor for this device exists. */
-	if (device->devindex >= DASD_PER_MAJOR)
+	base = block->base;
+	if (base->devindex >= DASD_PER_MAJOR)
 		return -EBUSY;
 
 	gdp = alloc_disk(1 << DASD_PARTN_BITS);
@@ -41,9 +42,9 @@ dasd_gendisk_alloc(struct dasd_device *device)
 
 	/* Initialize gendisk structure. */
 	gdp->major = DASD_MAJOR;
-	gdp->first_minor = device->devindex << DASD_PARTN_BITS;
+	gdp->first_minor = base->devindex << DASD_PARTN_BITS;
 	gdp->fops = &dasd_device_operations;
-	gdp->driverfs_dev = &device->cdev->dev;
+	gdp->driverfs_dev = &base->cdev->dev;
 
 	/*
 	 * Set device name.
@@ -53,53 +54,51 @@ dasd_gendisk_alloc(struct dasd_device *device)
 	 *   dasdaaaa - dasdzzzz : 456976 devices, added up = 475252
 	 */
 	len = sprintf(gdp->disk_name, "dasd");
-	if (device->devindex > 25) {
-	        if (device->devindex > 701) {
-		        if (device->devindex > 18277)
+	if (base->devindex > 25) {
+		if (base->devindex > 701) {
+			if (base->devindex > 18277)
 			        len += sprintf(gdp->disk_name + len, "%c",
-					       'a'+(((device->devindex-18278)
+					       'a'+(((base->devindex-18278)
 						     /17576)%26));
 			len += sprintf(gdp->disk_name + len, "%c",
-				       'a'+(((device->devindex-702)/676)%26));
+				       'a'+(((base->devindex-702)/676)%26));
 		}
 		len += sprintf(gdp->disk_name + len, "%c",
-			       'a'+(((device->devindex-26)/26)%26));
+			       'a'+(((base->devindex-26)/26)%26));
 	}
-	len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
+	len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26));
 
-	if (device->features & DASD_FEATURE_READONLY)
+	if (block->base->features & DASD_FEATURE_READONLY)
 		set_disk_ro(gdp, 1);
-	gdp->private_data = device;
-	gdp->queue = device->request_queue;
-	device->gdp = gdp;
-	set_capacity(device->gdp, 0);
-	add_disk(device->gdp);
+	gdp->private_data = block;
+	gdp->queue = block->request_queue;
+	block->gdp = gdp;
+	set_capacity(block->gdp, 0);
+	add_disk(block->gdp);
 	return 0;
 }
 
 /*
  * Unregister and free gendisk structure for device.
  */
-void
-dasd_gendisk_free(struct dasd_device *device)
+void dasd_gendisk_free(struct dasd_block *block)
 {
-	if (device->gdp) {
-		del_gendisk(device->gdp);
-		device->gdp->queue = NULL;
-		put_disk(device->gdp);
-		device->gdp = NULL;
+	if (block->gdp) {
+		del_gendisk(block->gdp);
+		block->gdp->queue = NULL;
+		put_disk(block->gdp);
+		block->gdp = NULL;
 	}
 }
 
 /*
  * Trigger a partition detection.
  */
-int
-dasd_scan_partitions(struct dasd_device * device)
+int dasd_scan_partitions(struct dasd_block *block)
 {
 	struct block_device *bdev;
 
-	bdev = bdget_disk(device->gdp, 0);
+	bdev = bdget_disk(block->gdp, 0);
 	if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0)
 		return -ENODEV;
 	/*
@@ -117,7 +116,7 @@ dasd_scan_partitions(struct dasd_device * device)
 	 * is why the assignment to device->bdev is done AFTER
 	 * the BLKRRPART ioctl.
 	 */
-	device->bdev = bdev;
+	block->bdev = bdev;
 	return 0;
 }
 
@@ -125,8 +124,7 @@ dasd_scan_partitions(struct dasd_device * device)
  * Remove all inodes in the system for a device, delete the
  * partitions and make device unusable by setting its size to zero.
  */
-void
-dasd_destroy_partitions(struct dasd_device * device)
+void dasd_destroy_partitions(struct dasd_block *block)
 {
 	/* The two structs have 168/176 byte on 31/64 bit. */
 	struct blkpg_partition bpart;
@@ -137,8 +135,8 @@ dasd_destroy_partitions(struct dasd_device * device)
 	 * Get the bdev pointer from the device structure and clear
 	 * device->bdev to lower the offline open_count limit again.
 	 */
-	bdev = device->bdev;
-	device->bdev = NULL;
+	bdev = block->bdev;
+	block->bdev = NULL;
 
 	/*
 	 * See fs/partition/check.c:delete_partition
@@ -149,17 +147,16 @@ dasd_destroy_partitions(struct dasd_device * device)
 	memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
 	barg.data = (void __force __user *) &bpart;
 	barg.op = BLKPG_DEL_PARTITION;
-	for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
+	for (bpart.pno = block->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
 		ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
 
-	invalidate_partition(device->gdp, 0);
+	invalidate_partition(block->gdp, 0);
 	/* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
 	blkdev_put(bdev);
-	set_capacity(device->gdp, 0);
+	set_capacity(block->gdp, 0);
 }
 
-int
-dasd_gendisk_init(void)
+int dasd_gendisk_init(void)
 {
 	int rc;
 
@@ -174,8 +171,7 @@ dasd_gendisk_init(void)
 	return 0;
 }
 
-void
-dasd_gendisk_exit(void)
+void dasd_gendisk_exit(void)
 {
 	unregister_blkdev(DASD_MAJOR, "dasd");
 }
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index d427daeef511..44b2984dfbee 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -64,13 +64,7 @@
  * SECTION: Type definitions
  */
 struct dasd_device;
-
-typedef enum {
-	dasd_era_fatal = -1,	/* no chance to recover		     */
-	dasd_era_none = 0,	/* don't recover, everything alright */
-	dasd_era_msg = 1,	/* don't recover, just report...     */
-	dasd_era_recover = 2	/* recovery action recommended	     */
-} dasd_era_t;
+struct dasd_block;
 
 /* BIT DEFINITIONS FOR SENSE DATA */
 #define DASD_SENSE_BIT_0 0x80
@@ -151,19 +145,22 @@ do { \
 
 struct dasd_ccw_req {
 	unsigned int magic;		/* Eye catcher */
-        struct list_head list;		/* list_head for request queueing. */
+	struct list_head devlist;	/* for dasd_device request queue */
+	struct list_head blocklist;	/* for dasd_block request queue */
 
 	/* Where to execute what... */
-	struct dasd_device *device;	/* device the request is for */
+	struct dasd_block *block;	/* the originating block device */
+	struct dasd_device *memdev;	/* the device used to allocate this */
+	struct dasd_device *startdev;	/* device the request is started on */
 	struct ccw1 *cpaddr;		/* address of channel program */
-	char status;	        	/* status of this request */
+	char status;			/* status of this request */
 	short retries;			/* A retry counter */
 	unsigned long flags;        	/* flags of this request */
 
 	/* ... and how */
 	unsigned long starttime;	/* jiffies time of request start */
 	int expires;			/* expiration period in jiffies */
-	char lpm;               	/* logical path mask */
+	char lpm;			/* logical path mask */
 	void *data;			/* pointer to data area */
 
 	/* these are important for recovering erroneous requests          */
@@ -178,20 +175,27 @@ struct dasd_ccw_req {
 	unsigned long long endclk;	/* TOD-clock of request termination */
 
         /* Callback that is called after reaching final status. */
-        void (*callback)(struct dasd_ccw_req *, void *data);
-        void *callback_data;
+	void (*callback)(struct dasd_ccw_req *, void *data);
+	void *callback_data;
 };
 
 /*
  * dasd_ccw_req -> status can be:
  */
-#define DASD_CQR_FILLED   0x00	/* request is ready to be processed */
-#define DASD_CQR_QUEUED   0x01	/* request is queued to be processed */
-#define DASD_CQR_IN_IO    0x02	/* request is currently in IO */
-#define DASD_CQR_DONE     0x03	/* request is completed successfully */
-#define DASD_CQR_ERROR    0x04	/* request is completed with error */
-#define DASD_CQR_FAILED   0x05	/* request is finally failed */
-#define DASD_CQR_CLEAR    0x06	/* request is clear pending */
+#define DASD_CQR_FILLED 	0x00	/* request is ready to be processed */
+#define DASD_CQR_DONE		0x01	/* request is completed successfully */
+#define DASD_CQR_NEED_ERP	0x02	/* request needs recovery action */
+#define DASD_CQR_IN_ERP 	0x03	/* request is in recovery */
+#define DASD_CQR_FAILED 	0x04	/* request is finally failed */
+#define DASD_CQR_TERMINATED	0x05	/* request was stopped by driver */
+
+#define DASD_CQR_QUEUED 	0x80	/* request is queued to be processed */
+#define DASD_CQR_IN_IO		0x81	/* request is currently in IO */
+#define DASD_CQR_ERROR		0x82	/* request is completed with error */
+#define DASD_CQR_CLEAR_PENDING	0x83	/* request is clear pending */
+#define DASD_CQR_CLEARED	0x84	/* request was cleared */
+#define DASD_CQR_SUCCESS	0x85	/* request was successfull */
+
 
 /* per dasd_ccw_req flags */
 #define DASD_CQR_FLAGS_USE_ERP   0	/* use ERP for this request */
@@ -214,52 +218,71 @@ struct dasd_discipline {
 
 	struct list_head list;	/* used for list of disciplines */
 
-        /*
-         * Device recognition functions. check_device is used to verify
-         * the sense data and the information returned by read device
-         * characteristics. It returns 0 if the discipline can be used
-         * for the device in question.
-         * do_analysis is used in the step from device state "basic" to
-         * state "accept". It returns 0 if the device can be made ready,
-         * it returns -EMEDIUMTYPE if the device can't be made ready or
-         * -EAGAIN if do_analysis started a ccw that needs to complete
-         * before the analysis may be repeated.
-         */
-        int (*check_device)(struct dasd_device *);
-	int (*do_analysis) (struct dasd_device *);
-
-        /*
-         * Device operation functions. build_cp creates a ccw chain for
-         * a block device request, start_io starts the request and
-         * term_IO cancels it (e.g. in case of a timeout). format_device
-         * returns a ccw chain to be used to format the device.
-         */
+	/*
+	 * Device recognition functions. check_device is used to verify
+	 * the sense data and the information returned by read device
+	 * characteristics. It returns 0 if the discipline can be used
+	 * for the device in question. uncheck_device is called during
+	 * device shutdown to deregister a device from its discipline.
+	 */
+	int (*check_device) (struct dasd_device *);
+	void (*uncheck_device) (struct dasd_device *);
+
+	/*
+	 * do_analysis is used in the step from device state "basic" to
+	 * state "accept". It returns 0 if the device can be made ready,
+	 * it returns -EMEDIUMTYPE if the device can't be made ready or
+	 * -EAGAIN if do_analysis started a ccw that needs to complete
+	 * before the analysis may be repeated.
+	 */
+	int (*do_analysis) (struct dasd_block *);
+
+	/*
+	 * Last things to do when a device is set online, and first things
+	 * when it is set offline.
+	 */
+	int (*ready_to_online) (struct dasd_device *);
+	int (*online_to_ready) (struct dasd_device *);
+
+	/*
+	 * Device operation functions. build_cp creates a ccw chain for
+	 * a block device request, start_io starts the request and
+	 * term_IO cancels it (e.g. in case of a timeout). format_device
+	 * returns a ccw chain to be used to format the device.
+	 * handle_terminated_request allows to examine a cqr and prepare
+	 * it for retry.
+	 */
 	struct dasd_ccw_req *(*build_cp) (struct dasd_device *,
+					  struct dasd_block *,
 					  struct request *);
 	int (*start_IO) (struct dasd_ccw_req *);
 	int (*term_IO) (struct dasd_ccw_req *);
+	void (*handle_terminated_request) (struct dasd_ccw_req *);
 	struct dasd_ccw_req *(*format_device) (struct dasd_device *,
 					       struct format_data_t *);
 	int (*free_cp) (struct dasd_ccw_req *, struct request *);
-        /*
-         * Error recovery functions. examine_error() returns a value that
-         * indicates what to do for an error condition. If examine_error()
+
+	/*
+	 * Error recovery functions. examine_error() returns a value that
+	 * indicates what to do for an error condition. If examine_error()
 	 * returns 'dasd_era_recover' erp_action() is called to create a
-         * special error recovery ccw. erp_postaction() is called after
-         * an error recovery ccw has finished its execution. dump_sense
-         * is called for every error condition to print the sense data
-         * to the console.
-         */
-	dasd_era_t(*examine_error) (struct dasd_ccw_req *, struct irb *);
+	 * special error recovery ccw. erp_postaction() is called after
+	 * an error recovery ccw has finished its execution. dump_sense
+	 * is called for every error condition to print the sense data
+	 * to the console.
+	 */
 	dasd_erp_fn_t(*erp_action) (struct dasd_ccw_req *);
 	dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *);
 	void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *,
 			    struct irb *);
 
+	void (*handle_unsolicited_interrupt) (struct dasd_device *,
+					      struct irb *);
+
         /* i/o control functions. */
-	int (*fill_geometry) (struct dasd_device *, struct hd_geometry *);
+	int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
 	int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
-	int (*ioctl) (struct dasd_device *, unsigned int, void __user *);
+	int (*ioctl) (struct dasd_block *, unsigned int, void __user *);
 };
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -267,12 +290,18 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer;
 /*
  * Unique identifier for dasd device.
  */
+#define UA_NOT_CONFIGURED  0x00
+#define UA_BASE_DEVICE	   0x01
+#define UA_BASE_PAV_ALIAS  0x02
+#define UA_HYPER_PAV_ALIAS 0x03
+
 struct dasd_uid {
-	__u8 alias;
+	__u8 type;
 	char vendor[4];
 	char serial[15];
 	__u16 ssid;
-	__u8 unit_addr;
+	__u8 real_unit_addr;
+	__u8 base_unit_addr;
 };
 
 /*
@@ -293,14 +322,9 @@ struct dasd_uid {
 
 struct dasd_device {
 	/* Block device stuff. */
-	struct gendisk *gdp;
-	struct request_queue *request_queue;
-	spinlock_t request_queue_lock;
-	struct block_device *bdev;
+	struct dasd_block *block;
+
         unsigned int devindex;
-	unsigned long blocks;	   /* size of volume in blocks */
-	unsigned int bp_block;	   /* bytes per block */
-	unsigned int s2b_shift;	   /* log2 (bp_block/512) */
 	unsigned long flags;	   /* per device flags */
 	unsigned short features;   /* copy of devmap-features (read-only!) */
 
@@ -316,9 +340,8 @@ struct dasd_device {
 	int state, target;
 	int stopped;		/* device (ccw_device_start) was stopped */
 
-	/* Open and reference count. */
+	/* reference count. */
         atomic_t ref_count;
-	atomic_t open_count;
 
 	/* ccw queue and memory for static ccw/erp buffers. */
 	struct list_head ccw_queue;
@@ -337,20 +360,45 @@ struct dasd_device {
 
 	struct ccw_device *cdev;
 
+	/* hook for alias management */
+	struct list_head alias_list;
+};
+
+struct dasd_block {
+	/* Block device stuff. */
+	struct gendisk *gdp;
+	struct request_queue *request_queue;
+	spinlock_t request_queue_lock;
+	struct block_device *bdev;
+	atomic_t open_count;
+
+	unsigned long blocks;	   /* size of volume in blocks */
+	unsigned int bp_block;	   /* bytes per block */
+	unsigned int s2b_shift;	   /* log2 (bp_block/512) */
+
+	struct dasd_device *base;
+	struct list_head ccw_queue;
+	spinlock_t queue_lock;
+
+	atomic_t tasklet_scheduled;
+	struct tasklet_struct tasklet;
+	struct timer_list timer;
+
 #ifdef CONFIG_DASD_PROFILE
 	struct dasd_profile_info_t profile;
 #endif
 };
 
+
+
 /* reasons why device (ccw_device_start) was stopped */
 #define DASD_STOPPED_NOT_ACC 1         /* not accessible */
 #define DASD_STOPPED_QUIESCE 2         /* Quiesced */
 #define DASD_STOPPED_PENDING 4         /* long busy */
 #define DASD_STOPPED_DC_WAIT 8         /* disconnected, wait */
-#define DASD_STOPPED_DC_EIO  16        /* disconnected, return -EIO */
+#define DASD_STOPPED_SU      16        /* summary unit check handling */
 
 /* per device flags */
-#define DASD_FLAG_DSC_ERROR	2	/* return -EIO when disconnected */
 #define DASD_FLAG_OFFLINE	3	/* device is in offline processing */
 #define DASD_FLAG_EER_SNSS	4	/* A SNSS is required */
 #define DASD_FLAG_EER_IN_USE	5	/* A SNSS request is running */
@@ -489,6 +537,9 @@ dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, struct dasd_device *device)
 struct dasd_device *dasd_alloc_device(void);
 void dasd_free_device(struct dasd_device *);
 
+struct dasd_block *dasd_alloc_block(void);
+void dasd_free_block(struct dasd_block *);
+
 void dasd_enable_device(struct dasd_device *);
 void dasd_set_target_state(struct dasd_device *, int);
 void dasd_kick_device(struct dasd_device *);
@@ -497,18 +548,23 @@ void dasd_add_request_head(struct dasd_ccw_req *);
 void dasd_add_request_tail(struct dasd_ccw_req *);
 int  dasd_start_IO(struct dasd_ccw_req *);
 int  dasd_term_IO(struct dasd_ccw_req *);
-void dasd_schedule_bh(struct dasd_device *);
+void dasd_schedule_device_bh(struct dasd_device *);
+void dasd_schedule_block_bh(struct dasd_block *);
 int  dasd_sleep_on(struct dasd_ccw_req *);
 int  dasd_sleep_on_immediatly(struct dasd_ccw_req *);
 int  dasd_sleep_on_interruptible(struct dasd_ccw_req *);
-void dasd_set_timer(struct dasd_device *, int);
-void dasd_clear_timer(struct dasd_device *);
+void dasd_device_set_timer(struct dasd_device *, int);
+void dasd_device_clear_timer(struct dasd_device *);
+void dasd_block_set_timer(struct dasd_block *, int);
+void dasd_block_clear_timer(struct dasd_block *);
 int  dasd_cancel_req(struct dasd_ccw_req *);
+int dasd_flush_device_queue(struct dasd_device *);
 int dasd_generic_probe (struct ccw_device *, struct dasd_discipline *);
 void dasd_generic_remove (struct ccw_device *cdev);
 int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
 int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
+void dasd_generic_handle_state_change(struct dasd_device *);
 
 int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
 
@@ -542,10 +598,10 @@ int dasd_busid_known(char *);
 /* externals in dasd_gendisk.c */
 int  dasd_gendisk_init(void);
 void dasd_gendisk_exit(void);
-int dasd_gendisk_alloc(struct dasd_device *);
-void dasd_gendisk_free(struct dasd_device *);
-int dasd_scan_partitions(struct dasd_device *);
-void dasd_destroy_partitions(struct dasd_device *);
+int dasd_gendisk_alloc(struct dasd_block *);
+void dasd_gendisk_free(struct dasd_block *);
+int dasd_scan_partitions(struct dasd_block *);
+void dasd_destroy_partitions(struct dasd_block *);
 
 /* externals in dasd_ioctl.c */
 int  dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
@@ -563,20 +619,9 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
 void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
 void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
 
-/* externals in dasd_3370_erp.c */
-dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
-
 /* externals in dasd_3990_erp.c */
-dasd_era_t dasd_3990_erp_examine(struct dasd_ccw_req *, struct irb *);
 struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *);
 
-/* externals in dasd_9336_erp.c */
-dasd_era_t dasd_9336_erp_examine(struct dasd_ccw_req *, struct irb *);
-
-/* externals in dasd_9336_erp.c */
-dasd_era_t dasd_9343_erp_examine(struct dasd_ccw_req *, struct irb *);
-struct dasd_ccw_req *dasd_9343_erp_action(struct dasd_ccw_req *);
-
 /* externals in dasd_eer.c */
 #ifdef CONFIG_DASD_EER
 int dasd_eer_init(void);
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 672eb0a3dd0b..91a64630cb0f 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -38,15 +38,15 @@ dasd_ioctl_api_version(void __user *argp)
 static int
 dasd_ioctl_enable(struct block_device *bdev)
 {
-	struct dasd_device *device = bdev->bd_disk->private_data;
+	struct dasd_block *block = bdev->bd_disk->private_data;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
-	dasd_enable_device(device);
+	dasd_enable_device(block->base);
 	/* Formatting the dasd device can change the capacity. */
 	mutex_lock(&bdev->bd_mutex);
-	i_size_write(bdev->bd_inode, (loff_t)get_capacity(device->gdp) << 9);
+	i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9);
 	mutex_unlock(&bdev->bd_mutex);
 	return 0;
 }
@@ -58,7 +58,7 @@ dasd_ioctl_enable(struct block_device *bdev)
 static int
 dasd_ioctl_disable(struct block_device *bdev)
 {
-	struct dasd_device *device = bdev->bd_disk->private_data;
+	struct dasd_block *block = bdev->bd_disk->private_data;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -71,7 +71,7 @@ dasd_ioctl_disable(struct block_device *bdev)
 	 * using the BIODASDFMT ioctl. Therefore the correct state for the
 	 * device is DASD_STATE_BASIC that allows to do basic i/o.
 	 */
-	dasd_set_target_state(device, DASD_STATE_BASIC);
+	dasd_set_target_state(block->base, DASD_STATE_BASIC);
 	/*
 	 * Set i_size to zero, since read, write, etc. check against this
 	 * value.
@@ -85,19 +85,19 @@ dasd_ioctl_disable(struct block_device *bdev)
 /*
  * Quiesce device.
  */
-static int
-dasd_ioctl_quiesce(struct dasd_device *device)
+static int dasd_ioctl_quiesce(struct dasd_block *block)
 {
 	unsigned long flags;
+	struct dasd_device *base;
 
+	base = block->base;
 	if (!capable (CAP_SYS_ADMIN))
 		return -EACCES;
 
-	DEV_MESSAGE (KERN_DEBUG, device, "%s",
-		     "Quiesce IO on device");
-	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	device->stopped |= DASD_STOPPED_QUIESCE;
-	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device");
+	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+	base->stopped |= DASD_STOPPED_QUIESCE;
+	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
 	return 0;
 }
 
@@ -105,22 +105,21 @@ dasd_ioctl_quiesce(struct dasd_device *device)
 /*
  * Quiesce device.
  */
-static int
-dasd_ioctl_resume(struct dasd_device *device)
+static int dasd_ioctl_resume(struct dasd_block *block)
 {
 	unsigned long flags;
+	struct dasd_device *base;
 
+	base = block->base;
 	if (!capable (CAP_SYS_ADMIN))
 		return -EACCES;
 
-	DEV_MESSAGE (KERN_DEBUG, device, "%s",
-		     "resume IO on device");
-
-	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	device->stopped &= ~DASD_STOPPED_QUIESCE;
-	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	DEV_MESSAGE(KERN_DEBUG, base, "%s", "resume IO on device");
+	spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+	base->stopped &= ~DASD_STOPPED_QUIESCE;
+	spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
 
-	dasd_schedule_bh (device);
+	dasd_schedule_block_bh(block);
 	return 0;
 }
 
@@ -130,22 +129,23 @@ dasd_ioctl_resume(struct dasd_device *device)
  * commands to format a single unit of the device. In terms of the ECKD
  * devices this means CCWs are generated to format a single track.
  */
-static int
-dasd_format(struct dasd_device * device, struct format_data_t * fdata)
+static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
 {
 	struct dasd_ccw_req *cqr;
+	struct dasd_device *base;
 	int rc;
 
-	if (device->discipline->format_device == NULL)
+	base = block->base;
+	if (base->discipline->format_device == NULL)
 		return -EPERM;
 
-	if (device->state != DASD_STATE_BASIC) {
-		DEV_MESSAGE(KERN_WARNING, device, "%s",
+	if (base->state != DASD_STATE_BASIC) {
+		DEV_MESSAGE(KERN_WARNING, base, "%s",
 			    "dasd_format: device is not disabled! ");
 		return -EBUSY;
 	}
 
-	DBF_DEV_EVENT(DBF_NOTICE, device,
+	DBF_DEV_EVENT(DBF_NOTICE, base,
 		      "formatting units %d to %d (%d B blocks) flags %d",
 		      fdata->start_unit,
 		      fdata->stop_unit, fdata->blksize, fdata->intensity);
@@ -156,20 +156,20 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
 	 * enabling the device later.
 	 */
 	if (fdata->start_unit == 0) {
-		struct block_device *bdev = bdget_disk(device->gdp, 0);
+		struct block_device *bdev = bdget_disk(block->gdp, 0);
 		bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize);
 		bdput(bdev);
 	}
 
 	while (fdata->start_unit <= fdata->stop_unit) {
-		cqr = device->discipline->format_device(device, fdata);
+		cqr = base->discipline->format_device(base, fdata);
 		if (IS_ERR(cqr))
 			return PTR_ERR(cqr);
 		rc = dasd_sleep_on_interruptible(cqr);
-		dasd_sfree_request(cqr, cqr->device);
+		dasd_sfree_request(cqr, cqr->memdev);
 		if (rc) {
 			if (rc != -ERESTARTSYS)
-				DEV_MESSAGE(KERN_ERR, device,
+				DEV_MESSAGE(KERN_ERR, base,
 					    " Formatting of unit %d failed "
 					    "with rc = %d",
 					    fdata->start_unit, rc);
@@ -186,7 +186,7 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata)
 static int
 dasd_ioctl_format(struct block_device *bdev, void __user *argp)
 {
-	struct dasd_device *device = bdev->bd_disk->private_data;
+	struct dasd_block *block = bdev->bd_disk->private_data;
 	struct format_data_t fdata;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -194,51 +194,47 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp)
 	if (!argp)
 		return -EINVAL;
 
-	if (device->features & DASD_FEATURE_READONLY)
+	if (block->base->features & DASD_FEATURE_READONLY)
 		return -EROFS;
 	if (copy_from_user(&fdata, argp, sizeof(struct format_data_t)))
 		return -EFAULT;
 	if (bdev != bdev->bd_contains) {
-		DEV_MESSAGE(KERN_WARNING, device, "%s",
+		DEV_MESSAGE(KERN_WARNING, block->base, "%s",
 			    "Cannot low-level format a partition");
 		return -EINVAL;
 	}
-	return dasd_format(device, &fdata);
+	return dasd_format(block, &fdata);
 }
 
 #ifdef CONFIG_DASD_PROFILE
 /*
  * Reset device profile information
  */
-static int
-dasd_ioctl_reset_profile(struct dasd_device *device)
+static int dasd_ioctl_reset_profile(struct dasd_block *block)
 {
-	memset(&device->profile, 0, sizeof (struct dasd_profile_info_t));
+	memset(&block->profile, 0, sizeof(struct dasd_profile_info_t));
 	return 0;
 }
 
 /*
  * Return device profile information
  */
-static int
-dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
+static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
 {
 	if (dasd_profile_level == DASD_PROFILE_OFF)
 		return -EIO;
-	if (copy_to_user(argp, &device->profile,
-			 sizeof (struct dasd_profile_info_t)))
+	if (copy_to_user(argp, &block->profile,
+			 sizeof(struct dasd_profile_info_t)))
 		return -EFAULT;
 	return 0;
 }
 #else
-static int
-dasd_ioctl_reset_profile(struct dasd_device *device)
+static int dasd_ioctl_reset_profile(struct dasd_block *block)
 {
 	return -ENOSYS;
 }
 
-static int
-dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
+static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
 {
 	return -ENOSYS;
 }
@@ -247,87 +243,88 @@ dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp)
 /*
  * Return dasd information. Used for BIODASDINFO and BIODASDINFO2.
  */
-static int
-dasd_ioctl_information(struct dasd_device *device,
-		unsigned int cmd, void __user *argp)
+static int dasd_ioctl_information(struct dasd_block *block,
+				  unsigned int cmd, void __user *argp)
 {
 	struct dasd_information2_t *dasd_info;
 	unsigned long flags;
 	int rc;
+	struct dasd_device *base;
 	struct ccw_device *cdev;
 	struct ccw_dev_id dev_id;
 
-	if (!device->discipline->fill_info)
+	base = block->base;
+	if (!base->discipline->fill_info)
 		return -EINVAL;
 
 	dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL);
 	if (dasd_info == NULL)
 		return -ENOMEM;
 
-	rc = device->discipline->fill_info(device, dasd_info);
+	rc = base->discipline->fill_info(base, dasd_info);
 	if (rc) {
 		kfree(dasd_info);
 		return rc;
 	}
 
-	cdev = device->cdev;
+	cdev = base->cdev;
 	ccw_device_get_id(cdev, &dev_id);
 
 	dasd_info->devno = dev_id.devno;
-	dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev);
+	dasd_info->schid = _ccw_device_get_subchannel_number(base->cdev);
 	dasd_info->cu_type = cdev->id.cu_type;
 	dasd_info->cu_model = cdev->id.cu_model;
 	dasd_info->dev_type = cdev->id.dev_type;
 	dasd_info->dev_model = cdev->id.dev_model;
-	dasd_info->status = device->state;
+	dasd_info->status = base->state;
 	/*
 	 * The open_count is increased for every opener, that includes
 	 * the blkdev_get in dasd_scan_partitions.
 	 * This must be hidden from user-space.
 	 */
-	dasd_info->open_count = atomic_read(&device->open_count);
-	if (!device->bdev)
+	dasd_info->open_count = atomic_read(&block->open_count);
+	if (!block->bdev)
 		dasd_info->open_count++;
 
 	/*
 	 * check if device is really formatted
 	 * LDL / CDL was returned by 'fill_info'
 	 */
-	if ((device->state < DASD_STATE_READY) ||
-	    (dasd_check_blocksize(device->bp_block)))
+	if ((base->state < DASD_STATE_READY) ||
+	    (dasd_check_blocksize(block->bp_block)))
 		dasd_info->format = DASD_FORMAT_NONE;
 
 	dasd_info->features |=
-		((device->features & DASD_FEATURE_READONLY) != 0);
+		((base->features & DASD_FEATURE_READONLY) != 0);
 
-	if (device->discipline)
-		memcpy(dasd_info->type, device->discipline->name, 4);
+	if (base->discipline)
+		memcpy(dasd_info->type, base->discipline->name, 4);
 	else
 		memcpy(dasd_info->type, "none", 4);
 
-	if (device->request_queue->request_fn) {
+	if (block->request_queue->request_fn) {
 		struct list_head *l;
 #ifdef DASD_EXTENDED_PROFILING
 		{
 			struct list_head *l;
-			spin_lock_irqsave(&device->lock, flags);
-			list_for_each(l, &device->request_queue->queue_head)
+			spin_lock_irqsave(&block->lock, flags);
+			list_for_each(l, &block->request_queue->queue_head)
 				dasd_info->req_queue_len++;
-			spin_unlock_irqrestore(&device->lock, flags);
+			spin_unlock_irqrestore(&block->lock, flags);
 		}
 #endif				/* DASD_EXTENDED_PROFILING */
-		spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-		list_for_each(l, &device->ccw_queue)
+		spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
+		list_for_each(l, &base->ccw_queue)
 			dasd_info->chanq_len++;
-		spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+		spin_unlock_irqrestore(get_ccwdev_lock(base->cdev),
 				       flags);
 	}
 
 	rc = 0;
 	if (copy_to_user(argp, dasd_info,
 			 ((cmd == (unsigned int) BIODASDINFO2) ?
-			  sizeof (struct dasd_information2_t) :
-			  sizeof (struct dasd_information_t))))
+			  sizeof(struct dasd_information2_t) :
+			  sizeof(struct dasd_information_t))))
 		rc = -EFAULT;
 	kfree(dasd_info);
 	return rc;
@@ -339,7 +336,7 @@ dasd_ioctl_information(struct dasd_device *device,
 static int
 dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
 {
-	struct dasd_device *device =  bdev->bd_disk->private_data;
+	struct dasd_block *block =  bdev->bd_disk->private_data;
 	int intval;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -351,11 +348,10 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
 		return -EFAULT;
 
 	set_disk_ro(bdev->bd_disk, intval);
-	return dasd_set_feature(device->cdev, DASD_FEATURE_READONLY, intval);
+	return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval);
 }
 
-static int
-dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
+static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd,
 		unsigned long arg)
 {
 	struct cmbdata __user *argp = (void __user *) arg;
@@ -363,7 +359,7 @@ dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd,
 	struct cmbdata data;
 	int ret;
 
-	ret = cmf_readall(device->cdev, &data);
+	ret = cmf_readall(block->base->cdev, &data);
 	if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp))))
 		return -EFAULT;
 	return ret;
@@ -374,10 +370,10 @@ dasd_ioctl(struct inode *inode, struct file *file,
 	   unsigned int cmd, unsigned long arg)
 {
 	struct block_device *bdev = inode->i_bdev;
-	struct dasd_device *device = bdev->bd_disk->private_data;
+	struct dasd_block *block = bdev->bd_disk->private_data;
 	void __user *argp = (void __user *)arg;
 
-	if (!device)
+	if (!block)
                 return -ENODEV;
 
 	if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) {
@@ -391,33 +387,33 @@ dasd_ioctl(struct inode *inode, struct file *file,
 	case BIODASDENABLE:
 		return dasd_ioctl_enable(bdev);
 	case BIODASDQUIESCE:
-		return dasd_ioctl_quiesce(device);
+		return dasd_ioctl_quiesce(block);
 	case BIODASDRESUME:
-		return dasd_ioctl_resume(device);
+		return dasd_ioctl_resume(block);
 	case BIODASDFMT:
 		return dasd_ioctl_format(bdev, argp);
 	case BIODASDINFO:
-		return dasd_ioctl_information(device, cmd, argp);
+		return dasd_ioctl_information(block, cmd, argp);
 	case BIODASDINFO2:
-		return dasd_ioctl_information(device, cmd, argp);
+		return dasd_ioctl_information(block, cmd, argp);
 	case BIODASDPRRD:
-		return dasd_ioctl_read_profile(device, argp);
+		return dasd_ioctl_read_profile(block, argp);
 	case BIODASDPRRST:
-		return dasd_ioctl_reset_profile(device);
+		return dasd_ioctl_reset_profile(block);
 	case BLKROSET:
 		return dasd_ioctl_set_ro(bdev, argp);
 	case DASDAPIVER:
 		return dasd_ioctl_api_version(argp);
 	case BIODASDCMFENABLE:
-		return enable_cmf(device->cdev);
+		return enable_cmf(block->base->cdev);
 	case BIODASDCMFDISABLE:
-		return disable_cmf(device->cdev);
+		return disable_cmf(block->base->cdev);
 	case BIODASDREADALLCMB:
-		return dasd_ioctl_readall_cmb(device, cmd, arg);
+		return dasd_ioctl_readall_cmb(block, cmd, arg);
 	default:
 		/* if the discipline has an ioctl method try it. */
-		if (device->discipline->ioctl) {
-			int rval = device->discipline->ioctl(device, cmd, argp);
+		if (block->base->discipline->ioctl) {
+			int rval = block->base->discipline->ioctl(block, cmd, argp);
 			if (rval != -ENOIOCTLCMD)
 				return rval;
 		}
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index ac7e8ef504cb..28a86f070048 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -54,11 +54,16 @@ static int
 dasd_devices_show(struct seq_file *m, void *v)
 {
 	struct dasd_device *device;
+	struct dasd_block *block;
 	char *substr;
 
 	device = dasd_device_from_devindex((unsigned long) v - 1);
 	if (IS_ERR(device))
 		return 0;
+	if (device->block)
+		block = device->block;
+	else
+		return 0;
 	/* Print device number. */
 	seq_printf(m, "%s", device->cdev->dev.bus_id);
 	/* Print discipline string. */
@@ -67,14 +72,14 @@ dasd_devices_show(struct seq_file *m, void *v)
 	else
 		seq_printf(m, "(none)");
 	/* Print kdev. */
-	if (device->gdp)
+	if (block->gdp)
 		seq_printf(m, " at (%3d:%6d)",
-			   device->gdp->major, device->gdp->first_minor);
+			   block->gdp->major, block->gdp->first_minor);
 	else
 		seq_printf(m, "  at (???:??????)");
 	/* Print device name. */
-	if (device->gdp)
-		seq_printf(m, " is %-8s", device->gdp->disk_name);
+	if (block->gdp)
+		seq_printf(m, " is %-8s", block->gdp->disk_name);
 	else
 		seq_printf(m, " is ????????");
 	/* Print devices features. */
@@ -100,14 +105,14 @@ dasd_devices_show(struct seq_file *m, void *v)
 	case DASD_STATE_READY:
 	case DASD_STATE_ONLINE:
 		seq_printf(m, "active ");
-		if (dasd_check_blocksize(device->bp_block))
+		if (dasd_check_blocksize(block->bp_block))
 			seq_printf(m, "n/f	 ");
 		else
 			seq_printf(m,
 				   "at blocksize: %d, %ld blocks, %ld MB",
-				   device->bp_block, device->blocks,
-				   ((device->bp_block >> 9) *
-				    device->blocks) >> 11);
+				   block->bp_block, block->blocks,
+				   ((block->bp_block >> 9) *
+				    block->blocks) >> 11);
 		break;
 	default:
 		seq_printf(m, "no stat");
@@ -137,7 +142,7 @@ static void dasd_devices_stop(struct seq_file *m, void *v)
 {
 }
 
-static struct seq_operations dasd_devices_seq_ops = {
+static const struct seq_operations dasd_devices_seq_ops = {
 	.start		= dasd_devices_start,
 	.next		= dasd_devices_next,
 	.stop		= dasd_devices_stop,
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 15a5789b7734..7779bfce1c31 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -82,7 +82,7 @@ struct dcssblk_dev_info {
 	struct request_queue *dcssblk_queue;
 };
 
-static struct list_head dcssblk_devices = LIST_HEAD_INIT(dcssblk_devices);
+static LIST_HEAD(dcssblk_devices);
 static struct rw_semaphore dcssblk_devices_sem;
 
 /*
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 130de19916f2..7e73e39a1741 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -3,7 +3,7 @@
 #
 
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
-	 sclp_info.o sclp_config.o sclp_chp.o
+	 sclp_cmd.o sclp_config.o sclp_cpi_sys.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index 20442fbf9346..a86c0534cd49 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -295,7 +295,7 @@ module_init(mon_init);
 module_exit(mon_exit);
 
 module_param_named(max_bufs, mon_max_bufs, int, 0644);
-MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers"
+MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
 		 "that can be active at one time");
 
 MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>");
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 8d1c64a24dec..0d98f1ff2edd 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -66,7 +66,7 @@ struct raw3270 {
 static DEFINE_MUTEX(raw3270_mutex);
 
 /* List of 3270 devices. */
-static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices);
+static LIST_HEAD(raw3270_devices);
 
 /*
  * Flag to indicate if the driver has been registered. Some operations
@@ -1210,7 +1210,7 @@ struct raw3270_notifier {
 	void (*notifier)(int, int);
 };
 
-static struct list_head raw3270_notifier = LIST_HEAD_INIT(raw3270_notifier);
+static LIST_HEAD(raw3270_notifier);
 
 int raw3270_register_notifier(void (*notifier)(int, int))
 {
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index c7318a125852..aa8186d18aee 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -56,8 +56,6 @@ typedef unsigned int sclp_cmdw_t;
 #define SCLP_CMDW_READ_EVENT_DATA	0x00770005
 #define SCLP_CMDW_WRITE_EVENT_DATA	0x00760005
 #define SCLP_CMDW_WRITE_EVENT_MASK	0x00780005
-#define SCLP_CMDW_READ_SCP_INFO		0x00020001
-#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
 
 #define GDS_ID_MDSMU		0x1310
 #define GDS_ID_MDSROUTEINFO	0x1311
@@ -83,6 +81,8 @@ extern u64 sclp_facilities;
 
 #define SCLP_HAS_CHP_INFO	(sclp_facilities & 0x8000000000000000ULL)
 #define SCLP_HAS_CHP_RECONFIG	(sclp_facilities & 0x2000000000000000ULL)
+#define SCLP_HAS_CPU_INFO	(sclp_facilities & 0x0800000000000000ULL)
+#define SCLP_HAS_CPU_RECONFIG	(sclp_facilities & 0x0400000000000000ULL)
 
 struct gds_subvector {
 	u8	length;
diff --git a/drivers/s390/char/sclp_chp.c b/drivers/s390/char/sclp_chp.c
deleted file mode 100644
index c68f5e7e63a0..000000000000
--- a/drivers/s390/char/sclp_chp.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- *  drivers/s390/char/sclp_chp.c
- *
- *    Copyright IBM Corp. 2007
- *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
- */
-
-#include <linux/types.h>
-#include <linux/gfp.h>
-#include <linux/errno.h>
-#include <linux/completion.h>
-#include <asm/sclp.h>
-#include <asm/chpid.h>
-
-#include "sclp.h"
-
-#define TAG	"sclp_chp: "
-
-#define SCLP_CMDW_CONFIGURE_CHANNEL_PATH	0x000f0001
-#define SCLP_CMDW_DECONFIGURE_CHANNEL_PATH	0x000e0001
-#define SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION	0x00030001
-
-static inline sclp_cmdw_t get_configure_cmdw(struct chp_id chpid)
-{
-	return SCLP_CMDW_CONFIGURE_CHANNEL_PATH | chpid.id << 8;
-}
-
-static inline sclp_cmdw_t get_deconfigure_cmdw(struct chp_id chpid)
-{
-	return SCLP_CMDW_DECONFIGURE_CHANNEL_PATH | chpid.id << 8;
-}
-
-static void chp_callback(struct sclp_req *req, void *data)
-{
-	struct completion *completion = data;
-
-	complete(completion);
-}
-
-struct chp_cfg_sccb {
-	struct sccb_header header;
-	u8 ccm;
-	u8 reserved[6];
-	u8 cssid;
-} __attribute__((packed));
-
-struct chp_cfg_data {
-	struct chp_cfg_sccb sccb;
-	struct sclp_req req;
-	struct completion completion;
-} __attribute__((packed));
-
-static int do_configure(sclp_cmdw_t cmd)
-{
-	struct chp_cfg_data *data;
-	int rc;
-
-	if (!SCLP_HAS_CHP_RECONFIG)
-		return -EOPNOTSUPP;
-	/* Prepare sccb. */
-	data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-	if (!data)
-		return -ENOMEM;
-	data->sccb.header.length = sizeof(struct chp_cfg_sccb);
-	data->req.command = cmd;
-	data->req.sccb = &(data->sccb);
-	data->req.status = SCLP_REQ_FILLED;
-	data->req.callback = chp_callback;
-	data->req.callback_data = &(data->completion);
-	init_completion(&data->completion);
-
-	/* Perform sclp request. */
-	rc = sclp_add_request(&(data->req));
-	if (rc)
-		goto out;
-	wait_for_completion(&data->completion);
-
-	/* Check response .*/
-	if (data->req.status != SCLP_REQ_DONE) {
-		printk(KERN_WARNING TAG "configure channel-path request failed "
-		       "(status=0x%02x)\n", data->req.status);
-		rc = -EIO;
-		goto out;
-	}
-	switch (data->sccb.header.response_code) {
-	case 0x0020:
-	case 0x0120:
-	case 0x0440:
-	case 0x0450:
-		break;
-	default:
-		printk(KERN_WARNING TAG "configure channel-path failed "
-		       "(cmd=0x%08x, response=0x%04x)\n", cmd,
-		       data->sccb.header.response_code);
-		rc = -EIO;
-		break;
-	}
-out:
-	free_page((unsigned long) data);
-
-	return rc;
-}
-
-/**
- * sclp_chp_configure - perform configure channel-path sclp command
- * @chpid: channel-path ID
- *
- * Perform configure channel-path command sclp command for specified chpid.
- * Return 0 after command successfully finished, non-zero otherwise.
- */
-int sclp_chp_configure(struct chp_id chpid)
-{
-	return do_configure(get_configure_cmdw(chpid));
-}
-
-/**
- * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
- * @chpid: channel-path ID
- *
- * Perform deconfigure channel-path command sclp command for specified chpid
- * and wait for completion. On success return 0. Return non-zero otherwise.
- */
-int sclp_chp_deconfigure(struct chp_id chpid)
-{
-	return do_configure(get_deconfigure_cmdw(chpid));
-}
-
-struct chp_info_sccb {
-	struct sccb_header header;
-	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
-	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
-	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
-	u8 ccm;
-	u8 reserved[6];
-	u8 cssid;
-} __attribute__((packed));
-
-struct chp_info_data {
-	struct chp_info_sccb sccb;
-	struct sclp_req req;
-	struct completion completion;
-} __attribute__((packed));
-
-/**
- * sclp_chp_read_info - perform read channel-path information sclp command
- * @info: resulting channel-path information data
- *
- * Perform read channel-path information sclp command and wait for completion.
- * On success, store channel-path information in @info and return 0. Return
- * non-zero otherwise.
- */
-int sclp_chp_read_info(struct sclp_chp_info *info)
-{
-	struct chp_info_data *data;
-	int rc;
-
-	if (!SCLP_HAS_CHP_INFO)
-		return -EOPNOTSUPP;
-	/* Prepare sccb. */
-	data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-	if (!data)
-		return -ENOMEM;
-	data->sccb.header.length = sizeof(struct chp_info_sccb);
-	data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION;
-	data->req.sccb = &(data->sccb);
-	data->req.status = SCLP_REQ_FILLED;
-	data->req.callback = chp_callback;
-	data->req.callback_data = &(data->completion);
-	init_completion(&data->completion);
-
-	/* Perform sclp request. */
-	rc = sclp_add_request(&(data->req));
-	if (rc)
-		goto out;
-	wait_for_completion(&data->completion);
-
-	/* Check response .*/
-	if (data->req.status != SCLP_REQ_DONE) {
-		printk(KERN_WARNING TAG "read channel-path info request failed "
-		       "(status=0x%02x)\n", data->req.status);
-		rc = -EIO;
-		goto out;
-	}
-	if (data->sccb.header.response_code != 0x0010) {
-		printk(KERN_WARNING TAG "read channel-path info failed "
-		       "(response=0x%04x)\n", data->sccb.header.response_code);
-		rc = -EIO;
-		goto out;
-	}
-	memcpy(info->recognized, data->sccb.recognized,
-	       SCLP_CHP_INFO_MASK_SIZE);
-	memcpy(info->standby, data->sccb.standby,
-	       SCLP_CHP_INFO_MASK_SIZE);
-	memcpy(info->configured, data->sccb.configured,
-	       SCLP_CHP_INFO_MASK_SIZE);
-out:
-	free_page((unsigned long) data);
-
-	return rc;
-}
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
new file mode 100644
index 000000000000..b5c23396f8fe
--- /dev/null
+++ b/drivers/s390/char/sclp_cmd.c
@@ -0,0 +1,398 @@
+/*
+ *  drivers/s390/char/sclp_cmd.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *		 Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ */
+
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/chpid.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+
+#define TAG	"sclp_cmd: "
+
+#define SCLP_CMDW_READ_SCP_INFO		0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001
+
+struct read_info_sccb {
+	struct	sccb_header header;	/* 0-7 */
+	u16	rnmax;			/* 8-9 */
+	u8	rnsize;			/* 10 */
+	u8	_reserved0[24 - 11];	/* 11-15 */
+	u8	loadparm[8];		/* 24-31 */
+	u8	_reserved1[48 - 32];	/* 32-47 */
+	u64	facilities;		/* 48-55 */
+	u8	_reserved2[84 - 56];	/* 56-83 */
+	u8	fac84;			/* 84 */
+	u8	_reserved3[91 - 85];	/* 85-90 */
+	u8	flags;			/* 91 */
+	u8	_reserved4[100 - 92];	/* 92-99 */
+	u32	rnsize2;		/* 100-103 */
+	u64	rnmax2;			/* 104-111 */
+	u8	_reserved5[4096 - 112];	/* 112-4095 */
+} __attribute__((packed, aligned(PAGE_SIZE)));
+
+static struct read_info_sccb __initdata early_read_info_sccb;
+static int __initdata early_read_info_sccb_valid;
+
+u64 sclp_facilities;
+static u8 sclp_fac84;
+
+static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
+{
+	int rc;
+
+	__ctl_set_bit(0, 9);
+	rc = sclp_service_call(cmd, sccb);
+	if (rc)
+		goto out;
+	__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
+			PSW_MASK_WAIT | PSW_DEFAULT_KEY);
+	local_irq_disable();
+out:
+	/* Contents of the sccb might have changed. */
+	barrier();
+	__ctl_clear_bit(0, 9);
+	return rc;
+}
+
+void __init sclp_read_info_early(void)
+{
+	int rc;
+	int i;
+	struct read_info_sccb *sccb;
+	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
+				  SCLP_CMDW_READ_SCP_INFO};
+
+	sccb = &early_read_info_sccb;
+	for (i = 0; i < ARRAY_SIZE(commands); i++) {
+		do {
+			memset(sccb, 0, sizeof(*sccb));
+			sccb->header.length = sizeof(*sccb);
+			sccb->header.control_mask[2] = 0x80;
+			rc = sclp_cmd_sync_early(commands[i], sccb);
+		} while (rc == -EBUSY);
+
+		if (rc)
+			break;
+		if (sccb->header.response_code == 0x10) {
+			early_read_info_sccb_valid = 1;
+			break;
+		}
+		if (sccb->header.response_code != 0x1f0)
+			break;
+	}
+}
+
+void __init sclp_facilities_detect(void)
+{
+	if (!early_read_info_sccb_valid)
+		return;
+	sclp_facilities = early_read_info_sccb.facilities;
+	sclp_fac84 = early_read_info_sccb.fac84;
+}
+
+unsigned long long __init sclp_memory_detect(void)
+{
+	unsigned long long memsize;
+	struct read_info_sccb *sccb;
+
+	if (!early_read_info_sccb_valid)
+		return 0;
+	sccb = &early_read_info_sccb;
+	if (sccb->rnsize)
+		memsize = sccb->rnsize << 20;
+	else
+		memsize = sccb->rnsize2 << 20;
+	if (sccb->rnmax)
+		memsize *= sccb->rnmax;
+	else
+		memsize *= sccb->rnmax2;
+	return memsize;
+}
+
+/*
+ * This function will be called after sclp_memory_detect(), which gets called
+ * early from early.c code. Therefore the sccb should have valid contents.
+ */
+void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
+{
+	struct read_info_sccb *sccb;
+
+	if (!early_read_info_sccb_valid)
+		return;
+	sccb = &early_read_info_sccb;
+	info->is_valid = 1;
+	if (sccb->flags & 0x2)
+		info->has_dump = 1;
+	memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
+}
+
+static void sclp_sync_callback(struct sclp_req *req, void *data)
+{
+	struct completion *completion = data;
+
+	complete(completion);
+}
+
+static int do_sync_request(sclp_cmdw_t cmd, void *sccb)
+{
+	struct completion completion;
+	struct sclp_req *request;
+	int rc;
+
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (!request)
+		return -ENOMEM;
+	request->command = cmd;
+	request->sccb = sccb;
+	request->status = SCLP_REQ_FILLED;
+	request->callback = sclp_sync_callback;
+	request->callback_data = &completion;
+	init_completion(&completion);
+
+	/* Perform sclp request. */
+	rc = sclp_add_request(request);
+	if (rc)
+		goto out;
+	wait_for_completion(&completion);
+
+	/* Check response. */
+	if (request->status != SCLP_REQ_DONE) {
+		printk(KERN_WARNING TAG "sync request failed "
+		       "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status);
+		rc = -EIO;
+	}
+out:
+	kfree(request);
+	return rc;
+}
+
+/*
+ * CPU configuration related functions.
+ */
+
+#define SCLP_CMDW_READ_CPU_INFO		0x00010001
+#define SCLP_CMDW_CONFIGURE_CPU		0x00110001
+#define SCLP_CMDW_DECONFIGURE_CPU	0x00100001
+
+struct read_cpu_info_sccb {
+	struct	sccb_header header;
+	u16	nr_configured;
+	u16	offset_configured;
+	u16	nr_standby;
+	u16	offset_standby;
+	u8	reserved[4096 - 16];
+} __attribute__((packed, aligned(PAGE_SIZE)));
+
+static void sclp_fill_cpu_info(struct sclp_cpu_info *info,
+			       struct read_cpu_info_sccb *sccb)
+{
+	char *page = (char *) sccb;
+
+	memset(info, 0, sizeof(*info));
+	info->configured = sccb->nr_configured;
+	info->standby = sccb->nr_standby;
+	info->combined = sccb->nr_configured + sccb->nr_standby;
+	info->has_cpu_type = sclp_fac84 & 0x1;
+	memcpy(&info->cpu, page + sccb->offset_configured,
+	       info->combined * sizeof(struct sclp_cpu_entry));
+}
+
+int sclp_get_cpu_info(struct sclp_cpu_info *info)
+{
+	int rc;
+	struct read_cpu_info_sccb *sccb;
+
+	if (!SCLP_HAS_CPU_INFO)
+		return -EOPNOTSUPP;
+	sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!sccb)
+		return -ENOMEM;
+	sccb->header.length = sizeof(*sccb);
+	rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb);
+	if (rc)
+		goto out;
+	if (sccb->header.response_code != 0x0010) {
+		printk(KERN_WARNING TAG "readcpuinfo failed "
+		       "(response=0x%04x)\n", sccb->header.response_code);
+		rc = -EIO;
+		goto out;
+	}
+	sclp_fill_cpu_info(info, sccb);
+out:
+	free_page((unsigned long) sccb);
+	return rc;
+}
+
+struct cpu_configure_sccb {
+	struct sccb_header header;
+} __attribute__((packed, aligned(8)));
+
+static int do_cpu_configure(sclp_cmdw_t cmd)
+{
+	struct cpu_configure_sccb *sccb;
+	int rc;
+
+	if (!SCLP_HAS_CPU_RECONFIG)
+		return -EOPNOTSUPP;
+	/*
+	 * This is not going to cross a page boundary since we force
+	 * kmalloc to have a minimum alignment of 8 bytes on s390.
+	 */
+	sccb = kzalloc(sizeof(*sccb), GFP_KERNEL | GFP_DMA);
+	if (!sccb)
+		return -ENOMEM;
+	sccb->header.length = sizeof(*sccb);
+	rc = do_sync_request(cmd, sccb);
+	if (rc)
+		goto out;
+	switch (sccb->header.response_code) {
+	case 0x0020:
+	case 0x0120:
+		break;
+	default:
+		printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, "
+		       "response=0x%04x)\n", cmd, sccb->header.response_code);
+		rc = -EIO;
+		break;
+	}
+out:
+	kfree(sccb);
+	return rc;
+}
+
+int sclp_cpu_configure(u8 cpu)
+{
+	return do_cpu_configure(SCLP_CMDW_CONFIGURE_CPU | cpu << 8);
+}
+
+int sclp_cpu_deconfigure(u8 cpu)
+{
+	return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8);
+}
+
+/*
+ * Channel path configuration related functions.
+ */
+
+#define SCLP_CMDW_CONFIGURE_CHPATH		0x000f0001
+#define SCLP_CMDW_DECONFIGURE_CHPATH		0x000e0001
+#define SCLP_CMDW_READ_CHPATH_INFORMATION	0x00030001
+
+struct chp_cfg_sccb {
+	struct sccb_header header;
+	u8 ccm;
+	u8 reserved[6];
+	u8 cssid;
+} __attribute__((packed));
+
+static int do_chp_configure(sclp_cmdw_t cmd)
+{
+	struct chp_cfg_sccb *sccb;
+	int rc;
+
+	if (!SCLP_HAS_CHP_RECONFIG)
+		return -EOPNOTSUPP;
+	/* Prepare sccb. */
+	sccb = (struct chp_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!sccb)
+		return -ENOMEM;
+	sccb->header.length = sizeof(*sccb);
+	rc = do_sync_request(cmd, sccb);
+	if (rc)
+		goto out;
+	switch (sccb->header.response_code) {
+	case 0x0020:
+	case 0x0120:
+	case 0x0440:
+	case 0x0450:
+		break;
+	default:
+		printk(KERN_WARNING TAG "configure channel-path failed "
+		       "(cmd=0x%08x, response=0x%04x)\n", cmd,
+		       sccb->header.response_code);
+		rc = -EIO;
+		break;
+	}
+out:
+	free_page((unsigned long) sccb);
+	return rc;
+}
+
+/**
+ * sclp_chp_configure - perform configure channel-path sclp command
+ * @chpid: channel-path ID
+ *
+ * Perform configure channel-path command sclp command for specified chpid.
+ * Return 0 after command successfully finished, non-zero otherwise.
+ */
+int sclp_chp_configure(struct chp_id chpid)
+{
+	return do_chp_configure(SCLP_CMDW_CONFIGURE_CHPATH | chpid.id << 8);
+}
+
+/**
+ * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
+ * @chpid: channel-path ID
+ *
+ * Perform deconfigure channel-path command sclp command for specified chpid
+ * and wait for completion. On success return 0. Return non-zero otherwise.
+ */
+int sclp_chp_deconfigure(struct chp_id chpid)
+{
+	return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8);
+}
+
+struct chp_info_sccb {
+	struct sccb_header header;
+	u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
+	u8 standby[SCLP_CHP_INFO_MASK_SIZE];
+	u8 configured[SCLP_CHP_INFO_MASK_SIZE];
+	u8 ccm;
+	u8 reserved[6];
+	u8 cssid;
+} __attribute__((packed));
+
+/**
+ * sclp_chp_read_info - perform read channel-path information sclp command
+ * @info: resulting channel-path information data
+ *
+ * Perform read channel-path information sclp command and wait for completion.
+ * On success, store channel-path information in @info and return 0. Return
+ * non-zero otherwise.
+ */
+int sclp_chp_read_info(struct sclp_chp_info *info)
+{
+	struct chp_info_sccb *sccb;
+	int rc;
+
+	if (!SCLP_HAS_CHP_INFO)
+		return -EOPNOTSUPP;
+	/* Prepare sccb. */
+	sccb = (struct chp_info_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!sccb)
+		return -ENOMEM;
+	sccb->header.length = sizeof(*sccb);
+	rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb);
+	if (rc)
+		goto out;
+	if (sccb->header.response_code != 0x0010) {
+		printk(KERN_WARNING TAG "read channel-path info failed "
+		       "(response=0x%04x)\n", sccb->header.response_code);
+		rc = -EIO;
+		goto out;
+	}
+	memcpy(info->recognized, sccb->recognized, SCLP_CHP_INFO_MASK_SIZE);
+	memcpy(info->standby, sccb->standby, SCLP_CHP_INFO_MASK_SIZE);
+	memcpy(info->configured, sccb->configured, SCLP_CHP_INFO_MASK_SIZE);
+out:
+	free_page((unsigned long) sccb);
+	return rc;
+}
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index 5322e5e54a98..9dc77f14fa52 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -29,12 +29,12 @@ static void sclp_cpu_capability_notify(struct work_struct *work)
 	struct sys_device *sysdev;
 
 	printk(KERN_WARNING TAG "cpu capability changed.\n");
-	lock_cpu_hotplug();
+	get_online_cpus();
 	for_each_online_cpu(cpu) {
 		sysdev = get_cpu_sysdev(cpu);
 		kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
 	}
-	unlock_cpu_hotplug();
+	put_online_cpus();
 }
 
 static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
index 82a13d9fdfe4..5716487b8c9d 100644
--- a/drivers/s390/char/sclp_cpi.c
+++ b/drivers/s390/char/sclp_cpi.c
@@ -1,255 +1,41 @@
 /*
- * Author: Martin Peschke <mpeschke@de.ibm.com>
- * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
+ *  drivers/s390/char/sclp_cpi.c
+ *    SCLP control programm identification
  *
- * SCLP Control-Program Identification.
+ *    Copyright IBM Corp. 2001, 2007
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *		 Michael Ernst <mernst@de.ibm.com>
  */
 
-#include <linux/version.h>
 #include <linux/kmod.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <asm/ebcdic.h>
-#include <asm/semaphore.h>
-
-#include "sclp.h"
-#include "sclp_rw.h"
-
-#define CPI_LENGTH_SYSTEM_TYPE	8
-#define CPI_LENGTH_SYSTEM_NAME	8
-#define CPI_LENGTH_SYSPLEX_NAME	8
-
-struct cpi_evbuf {
-	struct evbuf_header header;
-	u8	id_format;
-	u8	reserved0;
-	u8	system_type[CPI_LENGTH_SYSTEM_TYPE];
-	u64	reserved1;
-	u8	system_name[CPI_LENGTH_SYSTEM_NAME];
-	u64	reserved2;
-	u64	system_level;
-	u64	reserved3;
-	u8	sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
-	u8	reserved4[16];
-} __attribute__((packed));
-
-struct cpi_sccb {
-	struct sccb_header header;
-	struct cpi_evbuf cpi_evbuf;
-} __attribute__((packed));
-
-/* Event type structure for write message and write priority message */
-static struct sclp_register sclp_cpi_event =
-{
-	.send_mask = EVTYP_CTLPROGIDENT_MASK
-};
+#include <linux/version.h>
+#include "sclp_cpi_sys.h"
 
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Identify this operating system instance "
+		   "to the System z hardware");
+MODULE_AUTHOR("Martin Peschke <mpeschke@de.ibm.com>, "
+	      "Michael Ernst <mernst@de.ibm.com>");
 
-MODULE_AUTHOR(
-	"Martin Peschke, IBM Deutschland Entwicklung GmbH "
-	"<mpeschke@de.ibm.com>");
-
-MODULE_DESCRIPTION(
-	"identify this operating system instance to the S/390 "
-	"or zSeries hardware");
+static char *system_name = "";
+static char *sysplex_name = "";
 
-static char *system_name = NULL;
 module_param(system_name, charp, 0);
 MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters");
-
-static char *sysplex_name = NULL;
-#ifdef ALLOW_SYSPLEX_NAME
 module_param(sysplex_name, charp, 0);
 MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters");
-#endif
-
-/* use default value for this field (as well as for system level) */
-static char *system_type = "LINUX";
 
-static int
-cpi_check_parms(void)
+static int __init cpi_module_init(void)
 {
-	/* reject if no system type specified */
-	if (!system_type) {
-		printk("cpi: bug: no system type specified\n");
-		return -EINVAL;
-	}
-
-	/* reject if system type larger than 8 characters */
-	if (strlen(system_type) > CPI_LENGTH_SYSTEM_NAME) {
-		printk("cpi: bug: system type has length of %li characters - "
-		       "only %i characters supported\n",
-		       strlen(system_type), CPI_LENGTH_SYSTEM_TYPE);
-		return -EINVAL;
-	}
-
-	/* reject if no system name specified */
-	if (!system_name) {
-		printk("cpi: no system name specified\n");
-		return -EINVAL;
-	}
-
-	/* reject if system name larger than 8 characters */
-	if (strlen(system_name) > CPI_LENGTH_SYSTEM_NAME) {
-		printk("cpi: system name has length of %li characters - "
-		       "only %i characters supported\n",
-		       strlen(system_name), CPI_LENGTH_SYSTEM_NAME);
-		return -EINVAL;
-	}
-
-	/* reject if specified sysplex name larger than 8 characters */
-	if (sysplex_name && strlen(sysplex_name) > CPI_LENGTH_SYSPLEX_NAME) {
-		printk("cpi: sysplex name has length of %li characters"
-		       " - only %i characters supported\n",
-		       strlen(sysplex_name), CPI_LENGTH_SYSPLEX_NAME);
-		return -EINVAL;
-	}
-	return 0;
+	return sclp_cpi_set_data(system_name, sysplex_name, "LINUX",
+				 LINUX_VERSION_CODE);
 }
 
-static void
-cpi_callback(struct sclp_req *req, void *data)
-{
-	struct semaphore *sem;
-
-	sem = (struct semaphore *) data;
-	up(sem);
-}
-
-static struct sclp_req *
-cpi_prepare_req(void)
-{
-	struct sclp_req *req;
-	struct cpi_sccb *sccb;
-	struct cpi_evbuf *evb;
-
-	req = kmalloc(sizeof(struct sclp_req), GFP_KERNEL);
-	if (req == NULL)
-		return ERR_PTR(-ENOMEM);
-	sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA);
-	if (sccb == NULL) {
-		kfree(req);
-		return ERR_PTR(-ENOMEM);
-	}
-	memset(sccb, 0, sizeof(struct cpi_sccb));
-
-	/* setup SCCB for Control-Program Identification */
-	sccb->header.length = sizeof(struct cpi_sccb);
-	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
-	sccb->cpi_evbuf.header.type = 0x0B;
-	evb = &sccb->cpi_evbuf;
-
-	/* set system type */
-	memset(evb->system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
-	memcpy(evb->system_type, system_type, strlen(system_type));
-	sclp_ascebc_str(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
-	EBC_TOUPPER(evb->system_type, CPI_LENGTH_SYSTEM_TYPE);
-
-	/* set system name */
-	memset(evb->system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
-	memcpy(evb->system_name, system_name, strlen(system_name));
-	sclp_ascebc_str(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
-	EBC_TOUPPER(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
-
-	/* set system level */
-	evb->system_level = LINUX_VERSION_CODE;
-
-	/* set sysplex name */
-	if (sysplex_name) {
-		memset(evb->sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
-		memcpy(evb->sysplex_name, sysplex_name, strlen(sysplex_name));
-		sclp_ascebc_str(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
-		EBC_TOUPPER(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
-	}
-
-	/* prepare request data structure presented to SCLP driver */
-	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
-	req->sccb = sccb;
-	req->status = SCLP_REQ_FILLED;
-	req->callback = cpi_callback;
-	return req;
-}
-
-static void
-cpi_free_req(struct sclp_req *req)
-{
-	free_page((unsigned long) req->sccb);
-	kfree(req);
-}
-
-static int __init
-cpi_module_init(void)
-{
-	struct semaphore sem;
-	struct sclp_req *req;
-	int rc;
-
-	rc = cpi_check_parms();
-	if (rc)
-		return rc;
-
-	rc = sclp_register(&sclp_cpi_event);
-	if (rc) {
-		/* could not register sclp event. Die. */
-		printk(KERN_WARNING "cpi: could not register to hardware "
-		       "console.\n");
-		return -EINVAL;
-	}
-	if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
-		printk(KERN_WARNING "cpi: no control program identification "
-		       "support\n");
-		sclp_unregister(&sclp_cpi_event);
-		return -EOPNOTSUPP;
-	}
-
-	req = cpi_prepare_req();
-	if (IS_ERR(req)) {
-		printk(KERN_WARNING "cpi: couldn't allocate request\n");
-		sclp_unregister(&sclp_cpi_event);
-		return PTR_ERR(req);
-	}
-
-	/* Prepare semaphore */
-	sema_init(&sem, 0);
-	req->callback_data = &sem;
-	/* Add request to sclp queue */
-	rc = sclp_add_request(req);
-	if (rc) {
-		printk(KERN_WARNING "cpi: could not start request\n");
-		cpi_free_req(req);
-		sclp_unregister(&sclp_cpi_event);
-		return rc;
-	}
-	/* make "insmod" sleep until callback arrives */
-	down(&sem);
-
-	rc = ((struct cpi_sccb *) req->sccb)->header.response_code;
-	if (rc != 0x0020) {
-		printk(KERN_WARNING "cpi: failed with response code 0x%x\n",
-		       rc);
-		rc = -ECOMM;
-	} else
-		rc = 0;
-
-	cpi_free_req(req);
-	sclp_unregister(&sclp_cpi_event);
-
-	return rc;
-}
-
-
 static void __exit cpi_module_exit(void)
 {
 }
 
-
-/* declare driver module init/cleanup functions */
 module_init(cpi_module_init);
 module_exit(cpi_module_exit);
-
diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c
new file mode 100644
index 000000000000..41617032afdc
--- /dev/null
+++ b/drivers/s390/char/sclp_cpi_sys.c
@@ -0,0 +1,400 @@
+/*
+ *  drivers/s390/char/sclp_cpi_sys.c
+ *    SCLP control program identification sysfs interface
+ *
+ *    Copyright IBM Corp. 2001, 2007
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *		 Michael Ernst <mernst@de.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <asm/ebcdic.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+#include "sclp_rw.h"
+#include "sclp_cpi_sys.h"
+
+#define CPI_LENGTH_NAME 8
+#define CPI_LENGTH_LEVEL 16
+
+struct cpi_evbuf {
+	struct evbuf_header header;
+	u8	id_format;
+	u8	reserved0;
+	u8	system_type[CPI_LENGTH_NAME];
+	u64	reserved1;
+	u8	system_name[CPI_LENGTH_NAME];
+	u64	reserved2;
+	u64	system_level;
+	u64	reserved3;
+	u8	sysplex_name[CPI_LENGTH_NAME];
+	u8	reserved4[16];
+} __attribute__((packed));
+
+struct cpi_sccb {
+	struct sccb_header header;
+	struct cpi_evbuf cpi_evbuf;
+} __attribute__((packed));
+
+static struct sclp_register sclp_cpi_event = {
+	.send_mask = EVTYP_CTLPROGIDENT_MASK,
+};
+
+static char system_name[CPI_LENGTH_NAME + 1];
+static char sysplex_name[CPI_LENGTH_NAME + 1];
+static char system_type[CPI_LENGTH_NAME + 1];
+static u64 system_level;
+
+static void set_data(char *field, char *data)
+{
+	memset(field, ' ', CPI_LENGTH_NAME);
+	memcpy(field, data, strlen(data));
+	sclp_ascebc_str(field, CPI_LENGTH_NAME);
+}
+
+static void cpi_callback(struct sclp_req *req, void *data)
+{
+	struct completion *completion = data;
+
+	complete(completion);
+}
+
+static struct sclp_req *cpi_prepare_req(void)
+{
+	struct sclp_req *req;
+	struct cpi_sccb *sccb;
+	struct cpi_evbuf *evb;
+
+	req = kzalloc(sizeof(struct sclp_req), GFP_KERNEL);
+	if (!req)
+		return ERR_PTR(-ENOMEM);
+	sccb = (struct cpi_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+	if (!sccb) {
+		kfree(req);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	/* setup SCCB for Control-Program Identification */
+	sccb->header.length = sizeof(struct cpi_sccb);
+	sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf);
+	sccb->cpi_evbuf.header.type = 0x0b;
+	evb = &sccb->cpi_evbuf;
+
+	/* set system type */
+	set_data(evb->system_type, system_type);
+
+	/* set system name */
+	set_data(evb->system_name, system_name);
+
+	/* set sytem level */
+	evb->system_level = system_level;
+
+	/* set sysplex name */
+	set_data(evb->sysplex_name, sysplex_name);
+
+	/* prepare request data structure presented to SCLP driver */
+	req->command = SCLP_CMDW_WRITE_EVENT_DATA;
+	req->sccb = sccb;
+	req->status = SCLP_REQ_FILLED;
+	req->callback = cpi_callback;
+	return req;
+}
+
+static void cpi_free_req(struct sclp_req *req)
+{
+	free_page((unsigned long) req->sccb);
+	kfree(req);
+}
+
+static int cpi_req(void)
+{
+	struct completion completion;
+	struct sclp_req *req;
+	int rc;
+	int response;
+
+	rc = sclp_register(&sclp_cpi_event);
+	if (rc) {
+		printk(KERN_WARNING "cpi: could not register "
+			"to hardware console.\n");
+		goto out;
+	}
+	if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) {
+		printk(KERN_WARNING "cpi: no control program "
+			"identification support\n");
+		rc = -EOPNOTSUPP;
+		goto out_unregister;
+	}
+
+	req = cpi_prepare_req();
+	if (IS_ERR(req)) {
+		printk(KERN_WARNING "cpi: could not allocate request\n");
+		rc = PTR_ERR(req);
+		goto out_unregister;
+	}
+
+	init_completion(&completion);
+	req->callback_data = &completion;
+
+	/* Add request to sclp queue */
+	rc = sclp_add_request(req);
+	if (rc) {
+		printk(KERN_WARNING "cpi: could not start request\n");
+		goto out_free_req;
+	}
+
+	wait_for_completion(&completion);
+
+	if (req->status != SCLP_REQ_DONE) {
+		printk(KERN_WARNING "cpi: request failed (status=0x%02x)\n",
+			req->status);
+		rc = -EIO;
+		goto out_free_req;
+	}
+
+	response = ((struct cpi_sccb *) req->sccb)->header.response_code;
+	if (response != 0x0020) {
+		printk(KERN_WARNING "cpi: failed with "
+			"response code 0x%x\n", response);
+		rc = -EIO;
+	}
+
+out_free_req:
+	cpi_free_req(req);
+
+out_unregister:
+	sclp_unregister(&sclp_cpi_event);
+
+out:
+	return rc;
+}
+
+static int check_string(const char *attr, const char *str)
+{
+	size_t len;
+	size_t i;
+
+	len = strlen(str);
+
+	if ((len > 0) && (str[len - 1] == '\n'))
+		len--;
+
+	if (len > CPI_LENGTH_NAME)
+		return -EINVAL;
+
+	for (i = 0; i < len ; i++) {
+		if (isalpha(str[i]) || isdigit(str[i]) ||
+		    strchr("$@# ", str[i]))
+			continue;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void set_string(char *attr, const char *value)
+{
+	size_t len;
+	size_t i;
+
+	len = strlen(value);
+
+	if ((len > 0) && (value[len - 1] == '\n'))
+		len--;
+
+	for (i = 0; i < CPI_LENGTH_NAME; i++) {
+		if (i < len)
+			attr[i] = toupper(value[i]);
+		else
+			attr[i] = ' ';
+	}
+}
+
+static ssize_t system_name_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%s\n", system_name);
+}
+
+static ssize_t system_name_store(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *buf,
+	size_t len)
+{
+	int rc;
+
+	rc = check_string("system_name", buf);
+	if (rc)
+		return rc;
+
+	set_string(system_name, buf);
+
+	return len;
+}
+
+static struct kobj_attribute system_name_attr =
+	__ATTR(system_name, 0644, system_name_show, system_name_store);
+
+static ssize_t sysplex_name_show(struct kobject *kobj,
+				 struct kobj_attribute *attr, char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%s\n", sysplex_name);
+}
+
+static ssize_t sysplex_name_store(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  const char *buf,
+	size_t len)
+{
+	int rc;
+
+	rc = check_string("sysplex_name", buf);
+	if (rc)
+		return rc;
+
+	set_string(sysplex_name, buf);
+
+	return len;
+}
+
+static struct kobj_attribute sysplex_name_attr =
+	__ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store);
+
+static ssize_t system_type_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *page)
+{
+	return snprintf(page, PAGE_SIZE, "%s\n", system_type);
+}
+
+static ssize_t system_type_store(struct kobject *kobj,
+				 struct kobj_attribute *attr,
+				 const char *buf,
+	size_t len)
+{
+	int rc;
+
+	rc = check_string("system_type", buf);
+	if (rc)
+		return rc;
+
+	set_string(system_type, buf);
+
+	return len;
+}
+
+static struct kobj_attribute system_type_attr =
+	__ATTR(system_type, 0644, system_type_show, system_type_store);
+
+static ssize_t system_level_show(struct kobject *kobj,
+				 struct kobj_attribute *attr, char *page)
+{
+	unsigned long long level = system_level;
+
+	return snprintf(page, PAGE_SIZE, "%#018llx\n", level);
+}
+
+static ssize_t system_level_store(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  const char *buf,
+	size_t len)
+{
+	unsigned long long level;
+	char *endp;
+
+	level = simple_strtoull(buf, &endp, 16);
+
+	if (endp == buf)
+		return -EINVAL;
+	if (*endp == '\n')
+		endp++;
+	if (*endp)
+		return -EINVAL;
+
+	system_level = level;
+
+	return len;
+}
+
+static struct kobj_attribute system_level_attr =
+	__ATTR(system_level, 0644, system_level_show, system_level_store);
+
+static ssize_t set_store(struct kobject *kobj,
+			 struct kobj_attribute *attr,
+			 const char *buf, size_t len)
+{
+	int rc;
+
+	rc = cpi_req();
+	if (rc)
+		return rc;
+
+	return len;
+}
+
+static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store);
+
+static struct attribute *cpi_attrs[] = {
+	&system_name_attr.attr,
+	&sysplex_name_attr.attr,
+	&system_type_attr.attr,
+	&system_level_attr.attr,
+	&set_attr.attr,
+	NULL,
+};
+
+static struct attribute_group cpi_attr_group = {
+	.attrs = cpi_attrs,
+};
+
+static struct kset *cpi_kset;
+
+int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type,
+		      const u64 level)
+{
+	int rc;
+
+	rc = check_string("system_name", system);
+	if (rc)
+		return rc;
+	rc = check_string("sysplex_name", sysplex);
+	if (rc)
+		return rc;
+	rc = check_string("system_type", type);
+	if (rc)
+		return rc;
+
+	set_string(system_name, system);
+	set_string(sysplex_name, sysplex);
+	set_string(system_type, type);
+	system_level = level;
+
+	return cpi_req();
+}
+EXPORT_SYMBOL(sclp_cpi_set_data);
+
+static int __init cpi_init(void)
+{
+	int rc;
+
+	cpi_kset = kset_create_and_add("cpi", NULL, firmware_kobj);
+	if (!cpi_kset)
+		return -ENOMEM;
+
+	rc = sysfs_create_group(&cpi_kset->kobj, &cpi_attr_group);
+	if (rc)
+		kset_unregister(cpi_kset);
+
+	return rc;
+}
+
+__initcall(cpi_init);
diff --git a/drivers/s390/char/sclp_cpi_sys.h b/drivers/s390/char/sclp_cpi_sys.h
new file mode 100644
index 000000000000..deef3e6ff496
--- /dev/null
+++ b/drivers/s390/char/sclp_cpi_sys.h
@@ -0,0 +1,15 @@
+/*
+ *  drivers/s390/char/sclp_cpi_sys.h
+ *    SCLP control program identification sysfs interface
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Michael Ernst <mernst@de.ibm.com>
+ */
+
+#ifndef __SCLP_CPI_SYS_H__
+#define __SCLP_CPI_SYS_H__
+
+int sclp_cpi_set_data(const char *system, const char *sysplex,
+		      const char *type, u64 level);
+
+#endif	 /* __SCLP_CPI_SYS_H__ */
diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c
deleted file mode 100644
index a1136e052750..000000000000
--- a/drivers/s390/char/sclp_info.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- *  drivers/s390/char/sclp_info.c
- *
- *    Copyright IBM Corp. 2007
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
- */
-
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <asm/sclp.h>
-#include "sclp.h"
-
-struct sclp_readinfo_sccb {
-	struct	sccb_header header;	/* 0-7 */
-	u16	rnmax;			/* 8-9 */
-	u8	rnsize;			/* 10 */
-	u8	_reserved0[24 - 11];	/* 11-23 */
-	u8	loadparm[8];		/* 24-31 */
-	u8	_reserved1[48 - 32];	/* 32-47 */
-	u64	facilities;		/* 48-55 */
-	u8	_reserved2[91 - 56];	/* 56-90 */
-	u8	flags;			/* 91 */
-	u8	_reserved3[100 - 92];	/* 92-99 */
-	u32	rnsize2;		/* 100-103 */
-	u64	rnmax2;			/* 104-111 */
-	u8	_reserved4[4096 - 112];	/* 112-4095 */
-} __attribute__((packed, aligned(4096)));
-
-static struct sclp_readinfo_sccb __initdata early_readinfo_sccb;
-static int __initdata early_readinfo_sccb_valid;
-
-u64 sclp_facilities;
-
-void __init sclp_readinfo_early(void)
-{
-	int ret;
-	int i;
-	struct sclp_readinfo_sccb *sccb;
-	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
-				  SCLP_CMDW_READ_SCP_INFO};
-
-	/* Enable service signal subclass mask. */
-	__ctl_set_bit(0, 9);
-	sccb = &early_readinfo_sccb;
-	for (i = 0; i < ARRAY_SIZE(commands); i++) {
-		do {
-			memset(sccb, 0, sizeof(*sccb));
-			sccb->header.length = sizeof(*sccb);
-			sccb->header.control_mask[2] = 0x80;
-			ret = sclp_service_call(commands[i], sccb);
-		} while (ret == -EBUSY);
-
-		if (ret)
-			break;
-		__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
-				PSW_MASK_WAIT | PSW_DEFAULT_KEY);
-		local_irq_disable();
-		/*
-		 * Contents of the sccb might have changed
-		 * therefore a barrier is needed.
-		 */
-		barrier();
-		if (sccb->header.response_code == 0x10) {
-			early_readinfo_sccb_valid = 1;
-			break;
-		}
-		if (sccb->header.response_code != 0x1f0)
-			break;
-	}
-	/* Disable service signal subclass mask again. */
-	__ctl_clear_bit(0, 9);
-}
-
-void __init sclp_facilities_detect(void)
-{
-	if (!early_readinfo_sccb_valid)
-		return;
-	sclp_facilities = early_readinfo_sccb.facilities;
-}
-
-unsigned long long __init sclp_memory_detect(void)
-{
-	unsigned long long memsize;
-	struct sclp_readinfo_sccb *sccb;
-
-	if (!early_readinfo_sccb_valid)
-		return 0;
-	sccb = &early_readinfo_sccb;
-	if (sccb->rnsize)
-		memsize = sccb->rnsize << 20;
-	else
-		memsize = sccb->rnsize2 << 20;
-	if (sccb->rnmax)
-		memsize *= sccb->rnmax;
-	else
-		memsize *= sccb->rnmax2;
-	return memsize;
-}
-
-/*
- * This function will be called after sclp_memory_detect(), which gets called
- * early from early.c code. Therefore the sccb should have valid contents.
- */
-void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
-{
-	struct sclp_readinfo_sccb *sccb;
-
-	if (!early_readinfo_sccb_valid)
-		return;
-	sccb = &early_readinfo_sccb;
-	info->is_valid = 1;
-	if (sccb->flags & 0x2)
-		info->has_dump = 1;
-	memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
-}
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index d6b06ab81188..ad7195d3de0c 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -76,7 +76,7 @@ sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
 }
 
 /*
- * Return a pointer to the orignal page that has been used to create
+ * Return a pointer to the original page that has been used to create
  * the buffer.
  */
 void *
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index da25f8e24152..8246ef3ab095 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -1495,7 +1495,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
 			   device->cdev->dev.bus_id);
 		return tape_3590_erp_basic(device, request, irb, -EPERM);
 	case 0x8013:
-		PRINT_WARN("(%s): Another host has priviliged access to the "
+		PRINT_WARN("(%s): Another host has privileged access to the "
 			   "tape device\n", device->cdev->dev.bus_id);
 		PRINT_WARN("(%s): To solve the problem unload the current "
 			   "cartridge!\n", device->cdev->dev.bus_id);
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index eeb92e2ed0cc..ddc4a114e7f4 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -74,11 +74,10 @@ tapeblock_trigger_requeue(struct tape_device *device)
  * Post finished request.
  */
 static void
-tapeblock_end_request(struct request *req, int uptodate)
+tapeblock_end_request(struct request *req, int error)
 {
-	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
+	if (__blk_end_request(req, error, blk_rq_bytes(req)))
 		BUG();
-	end_that_request_last(req, uptodate);
 }
 
 static void
@@ -91,7 +90,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data)
 
 	device = ccw_req->device;
 	req = (struct request *) data;
-	tapeblock_end_request(req, ccw_req->rc == 0);
+	tapeblock_end_request(req, (ccw_req->rc == 0) ? 0 : -EIO);
 	if (ccw_req->rc == 0)
 		/* Update position. */
 		device->blk_data.block_position =
@@ -119,7 +118,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req)
 	ccw_req = device->discipline->bread(device, req);
 	if (IS_ERR(ccw_req)) {
 		DBF_EVENT(1, "TBLOCK: bread failed\n");
-		tapeblock_end_request(req, 0);
+		tapeblock_end_request(req, -EIO);
 		return PTR_ERR(ccw_req);
 	}
 	ccw_req->callback = __tapeblock_end_request;
@@ -132,7 +131,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req)
 		 * Start/enqueueing failed. No retries in
 		 * this case.
 		 */
-		tapeblock_end_request(req, 0);
+		tapeblock_end_request(req, -EIO);
 		device->discipline->free_bread(ccw_req);
 	}
 
@@ -177,7 +176,7 @@ tapeblock_requeue(struct work_struct *work) {
 		if (rq_data_dir(req) == WRITE) {
 			DBF_EVENT(1, "TBLOCK: Rejecting write request\n");
 			blkdev_dequeue_request(req);
-			tapeblock_end_request(req, 0);
+			tapeblock_end_request(req, -EIO);
 			continue;
 		}
 		spin_unlock_irq(&device->blk_data.request_queue_lock);
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index 2fae6338ee1c..7ad8cf157641 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -37,7 +37,7 @@ static void tape_long_busy_timeout(unsigned long data);
  * we can assign the devices to minor numbers of the same major
  * The list is protected by the rwlock
  */
-static struct list_head tape_device_list = LIST_HEAD_INIT(tape_device_list);
+static LIST_HEAD(tape_device_list);
 static DEFINE_RWLOCK(tape_device_lock);
 
 /*
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index cea49f001f89..c9b96d51b28f 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -97,7 +97,7 @@ static void tape_proc_stop(struct seq_file *m, void *v)
 {
 }
 
-static struct seq_operations tape_proc_seq = {
+static const struct seq_operations tape_proc_seq = {
 	.start		= tape_proc_start,
 	.next		= tape_proc_next,
 	.stop		= tape_proc_stop,
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index e0c4c508e121..d364e0bfae12 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -683,7 +683,7 @@ static int vmlogrdr_register_driver(void)
 	/* Register with iucv driver */
 	ret = iucv_register(&vmlogrdr_iucv_handler, 1);
 	if (ret) {
-		printk (KERN_ERR "vmlogrdr: failed to register with"
+		printk (KERN_ERR "vmlogrdr: failed to register with "
 			"iucv driver\n");
 		goto out;
 	}
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index d70a6e65bf14..7689b500a104 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -759,7 +759,7 @@ static loff_t ur_llseek(struct file *file, loff_t offset, int whence)
 	return newpos;
 }
 
-static struct file_operations ur_fops = {
+static const struct file_operations ur_fops = {
 	.owner	 = THIS_MODULE,
 	.open	 = ur_open,
 	.release = ur_release,
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 7073daf77981..f523501e6e6c 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -470,7 +470,7 @@ static loff_t zcore_lseek(struct file *file, loff_t offset, int orig)
 	return rc;
 }
 
-static struct file_operations zcore_fops = {
+static const struct file_operations zcore_fops = {
 	.owner		= THIS_MODULE,
 	.llseek		= zcore_lseek,
 	.read		= zcore_read,
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index 5287631fbfc8..b7a07a866291 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/airq.c
- *   S/390 common I/O routines -- support for adapter interruptions
+ *    Support for adapter interruptions
  *
- *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
- *			      IBM Corporation
- *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *		 Cornelia Huck (cornelia.huck@de.ibm.com)
- *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    Copyright IBM Corp. 1999,2007
+ *    Author(s): Ingo Adlung <adlung@de.ibm.com>
+ *		 Cornelia Huck <cornelia.huck@de.ibm.com>
+ *		 Arnd Bergmann <arndb@de.ibm.com>
+ *		 Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
 
 #include <linux/init.h>
@@ -14,72 +14,131 @@
 #include <linux/slab.h>
 #include <linux/rcupdate.h>
 
+#include <asm/airq.h>
+
+#include "cio.h"
 #include "cio_debug.h"
-#include "airq.h"
 
-static adapter_int_handler_t adapter_handler;
+#define NR_AIRQS		32
+#define NR_AIRQS_PER_WORD	sizeof(unsigned long)
+#define NR_AIRQ_WORDS		(NR_AIRQS / NR_AIRQS_PER_WORD)
 
-/*
- * register for adapter interrupts
- *
- * With HiperSockets the zSeries architecture provides for
- *  means of adapter interrups, pseudo I/O interrupts that are
- *  not tied to an I/O subchannel, but to an adapter. However,
- *  it doesn't disclose the info how to enable/disable them, but
- *  to recognize them only. Perhaps we should consider them
- *  being shared interrupts, and thus build a linked list
- *  of adapter handlers ... to be evaluated ...
- */
-int
-s390_register_adapter_interrupt (adapter_int_handler_t handler)
-{
-	int ret;
-	char dbf_txt[15];
+union indicator_t {
+	unsigned long word[NR_AIRQ_WORDS];
+	unsigned char byte[NR_AIRQS];
+} __attribute__((packed));
 
-	CIO_TRACE_EVENT (4, "rgaint");
+struct airq_t {
+	adapter_int_handler_t handler;
+	void *drv_data;
+};
 
-	if (handler == NULL)
-		ret = -EINVAL;
-	else
-		ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0);
-	if (!ret)
-		synchronize_sched();  /* Allow interrupts to complete. */
+static union indicator_t indicators;
+static struct airq_t *airqs[NR_AIRQS];
 
-	sprintf (dbf_txt, "ret:%d", ret);
-	CIO_TRACE_EVENT (4, dbf_txt);
+static int register_airq(struct airq_t *airq)
+{
+	int i;
 
-	return ret;
+	for (i = 0; i < NR_AIRQS; i++)
+		if (!cmpxchg(&airqs[i], NULL, airq))
+			return i;
+	return -ENOMEM;
 }
 
-int
-s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
+/**
+ * s390_register_adapter_interrupt() - register adapter interrupt handler
+ * @handler: adapter handler to be registered
+ * @drv_data: driver data passed with each call to the handler
+ *
+ * Returns:
+ *  Pointer to the indicator to be used on success
+ *  ERR_PTR() if registration failed
+ */
+void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
+				      void *drv_data)
 {
+	struct airq_t *airq;
+	char dbf_txt[16];
 	int ret;
-	char dbf_txt[15];
 
-	CIO_TRACE_EVENT (4, "urgaint");
-
-	if (handler == NULL)
-		ret = -EINVAL;
-	else {
-		adapter_handler = NULL;
-		synchronize_sched();  /* Allow interrupts to complete. */
-		ret = 0;
+	airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
+	if (!airq) {
+		ret = -ENOMEM;
+		goto out;
 	}
-	sprintf (dbf_txt, "ret:%d", ret);
-	CIO_TRACE_EVENT (4, dbf_txt);
-
-	return ret;
+	airq->handler = handler;
+	airq->drv_data = drv_data;
+	ret = register_airq(airq);
+	if (ret < 0)
+		kfree(airq);
+out:
+	snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
+	CIO_TRACE_EVENT(4, dbf_txt);
+	if (ret < 0)
+		return ERR_PTR(ret);
+	else
+		return &indicators.byte[ret];
 }
+EXPORT_SYMBOL(s390_register_adapter_interrupt);
 
-void
-do_adapter_IO (void)
+/**
+ * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
+ * @ind: indicator for which the handler is to be unregistered
+ */
+void s390_unregister_adapter_interrupt(void *ind)
 {
-	CIO_TRACE_EVENT (6, "doaio");
+	struct airq_t *airq;
+	char dbf_txt[16];
+	int i;
 
-	if (adapter_handler)
-		(*adapter_handler) ();
+	i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]);
+	snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
+	CIO_TRACE_EVENT(4, dbf_txt);
+	indicators.byte[i] = 0;
+	airq = xchg(&airqs[i], NULL);
+	/*
+	 * Allow interrupts to complete. This will ensure that the airq handle
+	 * is no longer referenced by any interrupt handler.
+	 */
+	synchronize_sched();
+	kfree(airq);
 }
+EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
+
+#define INDICATOR_MASK	(0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
 
-EXPORT_SYMBOL (s390_register_adapter_interrupt);
-EXPORT_SYMBOL (s390_unregister_adapter_interrupt);
+void do_adapter_IO(void)
+{
+	int w;
+	int i;
+	unsigned long word;
+	struct airq_t *airq;
+
+	/*
+	 * Access indicator array in word-sized chunks to minimize storage
+	 * fetch operations.
+	 */
+	for (w = 0; w < NR_AIRQ_WORDS; w++) {
+		word = indicators.word[w];
+		i = w * NR_AIRQS_PER_WORD;
+		/*
+		 * Check bytes within word for active indicators.
+		 */
+		while (word) {
+			if (word & INDICATOR_MASK) {
+				airq = airqs[i];
+				if (likely(airq))
+					airq->handler(&indicators.byte[i],
+						      airq->drv_data);
+				else
+					/*
+					 * Reset ill-behaved indicator.
+					 */
+					indicators.byte[i] = 0;
+			}
+			word <<= 8;
+			i++;
+		}
+	}
+}
diff --git a/drivers/s390/cio/airq.h b/drivers/s390/cio/airq.h
deleted file mode 100644
index 7d6be3fdcd66..000000000000
--- a/drivers/s390/cio/airq.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef S390_AINTERRUPT_H
-#define S390_AINTERRUPT_H
-
-typedef	int (*adapter_int_handler_t)(void);
-
-extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
-extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
-extern void do_adapter_IO (void);
-
-#endif
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index bd5f16f80bf8..e8597ec92247 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -348,7 +348,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
 	return user_len;
 }
 
-static struct seq_operations cio_ignore_proc_seq_ops = {
+static const struct seq_operations cio_ignore_proc_seq_ops = {
 	.start = cio_ignore_proc_seq_start,
 	.stop  = cio_ignore_proc_seq_stop,
 	.next  = cio_ignore_proc_seq_next,
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 5baa517c3b66..3964056a9a47 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -35,8 +35,8 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv)
 	struct ccwgroup_device *gdev;
 	struct ccwgroup_driver *gdrv;
 
-	gdev = container_of(dev, struct ccwgroup_device, dev);
-	gdrv = container_of(drv, struct ccwgroup_driver, driver);
+	gdev = to_ccwgroupdev(dev);
+	gdrv = to_ccwgroupdrv(drv);
 
 	if (gdev->creator_id == gdrv->driver_id)
 		return 1;
@@ -75,8 +75,10 @@ static void ccwgroup_ungroup_callback(struct device *dev)
 	struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
 
 	mutex_lock(&gdev->reg_mutex);
-	__ccwgroup_remove_symlinks(gdev);
-	device_unregister(dev);
+	if (device_is_registered(&gdev->dev)) {
+		__ccwgroup_remove_symlinks(gdev);
+		device_unregister(dev);
+	}
 	mutex_unlock(&gdev->reg_mutex);
 }
 
@@ -111,7 +113,7 @@ ccwgroup_release (struct device *dev)
 	gdev = to_ccwgroupdev(dev);
 
 	for (i = 0; i < gdev->count; i++) {
-		gdev->cdev[i]->dev.driver_data = NULL;
+		dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
 		put_device(&gdev->cdev[i]->dev);
 	}
 	kfree(gdev);
@@ -196,11 +198,11 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
 			goto error;
 		}
 		/* Don't allow a device to belong to more than one group. */
-		if (gdev->cdev[i]->dev.driver_data) {
+		if (dev_get_drvdata(&gdev->cdev[i]->dev)) {
 			rc = -EINVAL;
 			goto error;
 		}
-		gdev->cdev[i]->dev.driver_data = gdev;
+		dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
 	}
 
 	gdev->creator_id = creator_id;
@@ -234,8 +236,8 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
 error:
 	for (i = 0; i < argc; i++)
 		if (gdev->cdev[i]) {
-			if (gdev->cdev[i]->dev.driver_data == gdev)
-				gdev->cdev[i]->dev.driver_data = NULL;
+			if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
+				dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
 			put_device(&gdev->cdev[i]->dev);
 		}
 	mutex_unlock(&gdev->reg_mutex);
@@ -408,6 +410,7 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
 	/* register our new driver with the core */
 	cdriver->driver.bus = &ccwgroup_bus_type;
 	cdriver->driver.name = cdriver->name;
+	cdriver->driver.owner = cdriver->owner;
 
 	return driver_register(&cdriver->driver);
 }
@@ -463,8 +466,8 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
 {
 	struct ccwgroup_device *gdev;
 
-	if (cdev->dev.driver_data) {
-		gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
+	gdev = dev_get_drvdata(&cdev->dev);
+	if (gdev) {
 		if (get_device(&gdev->dev)) {
 			mutex_lock(&gdev->reg_mutex);
 			if (device_is_registered(&gdev->dev))
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 597c0c76a2ad..e7ba16a74ef7 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -89,7 +89,8 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
 	/* Copy data */
 	ret = 0;
 	memset(ssd, 0, sizeof(struct chsc_ssd_info));
-	if ((ssd_area->st != 0) && (ssd_area->st != 2))
+	if ((ssd_area->st != SUBCHANNEL_TYPE_IO) &&
+	    (ssd_area->st != SUBCHANNEL_TYPE_MSG))
 		goto out_free;
 	ssd->path_mask = ssd_area->path_mask;
 	ssd->fla_valid_mask = ssd_area->fla_valid_mask;
@@ -132,20 +133,16 @@ static void terminate_internal_io(struct subchannel *sch)
 	device_set_intretry(sch);
 	/* Call handler. */
 	if (sch->driver && sch->driver->termination)
-		sch->driver->termination(&sch->dev);
+		sch->driver->termination(sch);
 }
 
-static int
-s390_subchannel_remove_chpid(struct device *dev, void *data)
+static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data)
 {
 	int j;
 	int mask;
-	struct subchannel *sch;
-	struct chp_id *chpid;
+	struct chp_id *chpid = data;
 	struct schib schib;
 
-	sch = to_subchannel(dev);
-	chpid = data;
 	for (j = 0; j < 8; j++) {
 		mask = 0x80 >> j;
 		if ((sch->schib.pmcw.pim & mask) &&
@@ -158,7 +155,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
 	spin_lock_irq(sch->lock);
 
 	stsch(sch->schid, &schib);
-	if (!schib.pmcw.dnv)
+	if (!css_sch_is_valid(&schib))
 		goto out_unreg;
 	memcpy(&sch->schib, &schib, sizeof(struct schib));
 	/* Check for single path devices. */
@@ -172,12 +169,12 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
 			terminate_internal_io(sch);
 			/* Re-start path verification. */
 			if (sch->driver && sch->driver->verify)
-				sch->driver->verify(&sch->dev);
+				sch->driver->verify(sch);
 		}
 	} else {
 		/* trigger path verification. */
 		if (sch->driver && sch->driver->verify)
-			sch->driver->verify(&sch->dev);
+			sch->driver->verify(sch);
 		else if (sch->lpm == mask)
 			goto out_unreg;
 	}
@@ -201,12 +198,10 @@ void chsc_chp_offline(struct chp_id chpid)
 
 	if (chp_get_status(chpid) <= 0)
 		return;
-	bus_for_each_dev(&css_bus_type, NULL, &chpid,
-			 s390_subchannel_remove_chpid);
+	for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid);
 }
 
-static int
-s390_process_res_acc_new_sch(struct subchannel_id schid)
+static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data)
 {
 	struct schib schib;
 	/*
@@ -252,18 +247,10 @@ static int get_res_chpid_mask(struct chsc_ssd_info *ssd,
 	return 0;
 }
 
-static int
-__s390_process_res_acc(struct subchannel_id schid, void *data)
+static int __s390_process_res_acc(struct subchannel *sch, void *data)
 {
 	int chp_mask, old_lpm;
-	struct res_acc_data *res_data;
-	struct subchannel *sch;
-
-	res_data = data;
-	sch = get_subchannel_by_schid(schid);
-	if (!sch)
-		/* Check if a subchannel is newly available. */
-		return s390_process_res_acc_new_sch(schid);
+	struct res_acc_data *res_data = data;
 
 	spin_lock_irq(sch->lock);
 	chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data);
@@ -279,10 +266,10 @@ __s390_process_res_acc(struct subchannel_id schid, void *data)
 	if (!old_lpm && sch->lpm)
 		device_trigger_reprobe(sch);
 	else if (sch->driver && sch->driver->verify)
-		sch->driver->verify(&sch->dev);
+		sch->driver->verify(sch);
 out:
 	spin_unlock_irq(sch->lock);
-	put_device(&sch->dev);
+
 	return 0;
 }
 
@@ -305,7 +292,8 @@ static void s390_process_res_acc (struct res_acc_data *res_data)
 	 * The more information we have (info), the less scanning
 	 * will we have to do.
 	 */
-	for_each_subchannel(__s390_process_res_acc, res_data);
+	for_each_subchannel_staged(__s390_process_res_acc,
+				   s390_process_res_acc_new_sch, res_data);
 }
 
 static int
@@ -499,8 +487,7 @@ void chsc_process_crw(void)
 	} while (sei_area->flags & 0x80);
 }
 
-static int
-__chp_add_new_sch(struct subchannel_id schid)
+static int __chp_add_new_sch(struct subchannel_id schid, void *data)
 {
 	struct schib schib;
 
@@ -514,45 +501,37 @@ __chp_add_new_sch(struct subchannel_id schid)
 }
 
 
-static int
-__chp_add(struct subchannel_id schid, void *data)
+static int __chp_add(struct subchannel *sch, void *data)
 {
 	int i, mask;
-	struct chp_id *chpid;
-	struct subchannel *sch;
-
-	chpid = data;
-	sch = get_subchannel_by_schid(schid);
-	if (!sch)
-		/* Check if the subchannel is now available. */
-		return __chp_add_new_sch(schid);
+	struct chp_id *chpid = data;
+
 	spin_lock_irq(sch->lock);
 	for (i=0; i<8; i++) {
 		mask = 0x80 >> i;
 		if ((sch->schib.pmcw.pim & mask) &&
-		    (sch->schib.pmcw.chpid[i] == chpid->id)) {
-			if (stsch(sch->schid, &sch->schib) != 0) {
-				/* Endgame. */
-				spin_unlock_irq(sch->lock);
-				return -ENXIO;
-			}
+		    (sch->schib.pmcw.chpid[i] == chpid->id))
 			break;
-		}
 	}
 	if (i==8) {
 		spin_unlock_irq(sch->lock);
 		return 0;
 	}
+	if (stsch(sch->schid, &sch->schib)) {
+		spin_unlock_irq(sch->lock);
+		css_schedule_eval(sch->schid);
+		return 0;
+	}
 	sch->lpm = ((sch->schib.pmcw.pim &
 		     sch->schib.pmcw.pam &
 		     sch->schib.pmcw.pom)
 		    | mask) & sch->opm;
 
 	if (sch->driver && sch->driver->verify)
-		sch->driver->verify(&sch->dev);
+		sch->driver->verify(sch);
 
 	spin_unlock_irq(sch->lock);
-	put_device(&sch->dev);
+
 	return 0;
 }
 
@@ -564,7 +543,8 @@ void chsc_chp_online(struct chp_id chpid)
 	CIO_TRACE_EVENT(2, dbf_txt);
 
 	if (chp_get_status(chpid) != 0)
-		for_each_subchannel(__chp_add, &chpid);
+		for_each_subchannel_staged(__chp_add, __chp_add_new_sch,
+					   &chpid);
 }
 
 static void __s390_subchannel_vary_chpid(struct subchannel *sch,
@@ -589,7 +569,7 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
 			if (!old_lpm)
 				device_trigger_reprobe(sch);
 			else if (sch->driver && sch->driver->verify)
-				sch->driver->verify(&sch->dev);
+				sch->driver->verify(sch);
 			break;
 		}
 		sch->opm &= ~mask;
@@ -603,37 +583,29 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
 				terminate_internal_io(sch);
 				/* Re-start path verification. */
 				if (sch->driver && sch->driver->verify)
-					sch->driver->verify(&sch->dev);
+					sch->driver->verify(sch);
 			}
 		} else if (!sch->lpm) {
 			if (device_trigger_verify(sch) != 0)
 				css_schedule_eval(sch->schid);
 		} else if (sch->driver && sch->driver->verify)
-			sch->driver->verify(&sch->dev);
+			sch->driver->verify(sch);
 		break;
 	}
 	spin_unlock_irqrestore(sch->lock, flags);
 }
 
-static int s390_subchannel_vary_chpid_off(struct device *dev, void *data)
+static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data)
 {
-	struct subchannel *sch;
-	struct chp_id *chpid;
-
-	sch = to_subchannel(dev);
-	chpid = data;
+	struct chp_id *chpid = data;
 
 	__s390_subchannel_vary_chpid(sch, *chpid, 0);
 	return 0;
 }
 
-static int s390_subchannel_vary_chpid_on(struct device *dev, void *data)
+static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data)
 {
-	struct subchannel *sch;
-	struct chp_id *chpid;
-
-	sch = to_subchannel(dev);
-	chpid = data;
+	struct chp_id *chpid = data;
 
 	__s390_subchannel_vary_chpid(sch, *chpid, 1);
 	return 0;
@@ -643,13 +615,7 @@ static int
 __s390_vary_chpid_on(struct subchannel_id schid, void *data)
 {
 	struct schib schib;
-	struct subchannel *sch;
 
-	sch = get_subchannel_by_schid(schid);
-	if (sch) {
-		put_device(&sch->dev);
-		return 0;
-	}
 	if (stsch_err(schid, &schib))
 		/* We're through */
 		return -ENXIO;
@@ -669,12 +635,13 @@ int chsc_chp_vary(struct chp_id chpid, int on)
 	 * Redo PathVerification on the devices the chpid connects to
 	 */
 
-	bus_for_each_dev(&css_bus_type, NULL, &chpid, on ?
-			 s390_subchannel_vary_chpid_on :
-			 s390_subchannel_vary_chpid_off);
 	if (on)
-		/* Scan for new devices on varied on path. */
-		for_each_subchannel(__s390_vary_chpid_on, NULL);
+		for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
+					   __s390_vary_chpid_on, &chpid);
+	else
+		for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
+					   NULL, &chpid);
+
 	return 0;
 }
 
@@ -1075,7 +1042,7 @@ chsc_determine_css_characteristics(void)
 
 	scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 	if (!scsc_area) {
-		CIO_MSG_EVENT(0, "Was not able to determine available"
+		CIO_MSG_EVENT(0, "Was not able to determine available "
 			      "CHSCs due to no memory.\n");
 		return -ENOMEM;
 	}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 46905345159e..60590a12d529 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -23,11 +23,12 @@
 #include <asm/reset.h>
 #include <asm/ipl.h>
 #include <asm/chpid.h>
-#include "airq.h"
+#include <asm/airq.h>
 #include "cio.h"
 #include "css.h"
 #include "chsc.h"
 #include "ioasm.h"
+#include "io_sch.h"
 #include "blacklist.h"
 #include "cio_debug.h"
 #include "chp.h"
@@ -56,39 +57,37 @@ __setup ("cio_msg=", cio_setup);
 
 /*
  * Function: cio_debug_init
- * Initializes three debug logs (under /proc/s390dbf) for common I/O:
- * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
+ * Initializes three debug logs for common I/O:
+ * - cio_msg logs generic cio messages
  * - cio_trace logs the calling of different functions
- * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
- * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
+ * - cio_crw logs machine check related cio messages
  */
-static int __init
-cio_debug_init (void)
+static int __init cio_debug_init(void)
 {
-	cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long));
+	cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long));
 	if (!cio_debug_msg_id)
 		goto out_unregister;
-	debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
-	debug_set_level (cio_debug_msg_id, 2);
-	cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 16);
+	debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
+	debug_set_level(cio_debug_msg_id, 2);
+	cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16);
 	if (!cio_debug_trace_id)
 		goto out_unregister;
-	debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
-	debug_set_level (cio_debug_trace_id, 2);
-	cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long));
+	debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
+	debug_set_level(cio_debug_trace_id, 2);
+	cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long));
 	if (!cio_debug_crw_id)
 		goto out_unregister;
-	debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
-	debug_set_level (cio_debug_crw_id, 2);
+	debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
+	debug_set_level(cio_debug_crw_id, 4);
 	return 0;
 
 out_unregister:
 	if (cio_debug_msg_id)
-		debug_unregister (cio_debug_msg_id);
+		debug_unregister(cio_debug_msg_id);
 	if (cio_debug_trace_id)
-		debug_unregister (cio_debug_trace_id);
+		debug_unregister(cio_debug_trace_id);
 	if (cio_debug_crw_id)
-		debug_unregister (cio_debug_crw_id);
+		debug_unregister(cio_debug_crw_id);
 	printk(KERN_WARNING"cio: could not initialize debugging\n");
 	return -1;
 }
@@ -147,7 +146,7 @@ cio_tpi(void)
 	spin_lock(sch->lock);
 	memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw));
 	if (sch->driver && sch->driver->irq)
-		sch->driver->irq(&sch->dev);
+		sch->driver->irq(sch);
 	spin_unlock(sch->lock);
 	irq_exit ();
 	_local_bh_enable();
@@ -184,33 +183,35 @@ cio_start_key (struct subchannel *sch,	/* subchannel structure */
 {
 	char dbf_txt[15];
 	int ccode;
+	struct orb *orb;
 
-	CIO_TRACE_EVENT (4, "stIO");
-	CIO_TRACE_EVENT (4, sch->dev.bus_id);
+	CIO_TRACE_EVENT(4, "stIO");
+	CIO_TRACE_EVENT(4, sch->dev.bus_id);
 
+	orb = &to_io_private(sch)->orb;
 	/* sch is always under 2G. */
-	sch->orb.intparm = (__u32)(unsigned long)sch;
-	sch->orb.fmt = 1;
+	orb->intparm = (u32)(addr_t)sch;
+	orb->fmt = 1;
 
-	sch->orb.pfch = sch->options.prefetch == 0;
-	sch->orb.spnd = sch->options.suspend;
-	sch->orb.ssic = sch->options.suspend && sch->options.inter;
-	sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
+	orb->pfch = sch->options.prefetch == 0;
+	orb->spnd = sch->options.suspend;
+	orb->ssic = sch->options.suspend && sch->options.inter;
+	orb->lpm = (lpm != 0) ? lpm : sch->lpm;
 #ifdef CONFIG_64BIT
 	/*
 	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
 	 */
-	sch->orb.c64 = 1;
-	sch->orb.i2k = 0;
+	orb->c64 = 1;
+	orb->i2k = 0;
 #endif
-	sch->orb.key = key >> 4;
+	orb->key = key >> 4;
 	/* issue "Start Subchannel" */
-	sch->orb.cpa = (__u32) __pa (cpa);
-	ccode = ssch (sch->schid, &sch->orb);
+	orb->cpa = (__u32) __pa(cpa);
+	ccode = ssch(sch->schid, orb);
 
 	/* process condition code */
-	sprintf (dbf_txt, "ccode:%d", ccode);
-	CIO_TRACE_EVENT (4, dbf_txt);
+	sprintf(dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT(4, dbf_txt);
 
 	switch (ccode) {
 	case 0:
@@ -405,8 +406,8 @@ cio_modify (struct subchannel *sch)
 /*
  * Enable subchannel.
  */
-int
-cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
+int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
+			  u32 intparm)
 {
 	char dbf_txt[15];
 	int ccode;
@@ -425,7 +426,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
 	for (retry = 5, ret = 0; retry > 0; retry--) {
 		sch->schib.pmcw.ena = 1;
 		sch->schib.pmcw.isc = isc;
-		sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+		sch->schib.pmcw.intparm = intparm;
 		ret = cio_modify(sch);
 		if (ret == -ENODEV)
 			break;
@@ -567,7 +568,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
 	 */
 	if (sch->st != 0) {
 		CIO_DEBUG(KERN_INFO, 0,
-			  "cio: Subchannel 0.%x.%04x reports "
+			  "Subchannel 0.%x.%04x reports "
 			  "non-I/O subchannel type %04X\n",
 			  sch->schid.ssid, sch->schid.sch_no, sch->st);
 		/* We stop here for non-io subchannels. */
@@ -576,11 +577,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
 	}
 
 	/* Initialization for io subchannels. */
-	if (!sch->schib.pmcw.dnv) {
-		/* io subchannel but device number is invalid. */
+	if (!css_sch_is_valid(&sch->schib)) {
 		err = -ENODEV;
 		goto out;
 	}
+
 	/* Devno is valid. */
 	if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) {
 		/*
@@ -600,7 +601,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
 	sch->lpm = sch->schib.pmcw.pam & sch->opm;
 
 	CIO_DEBUG(KERN_INFO, 0,
-		  "cio: Detected device %04x on subchannel 0.%x.%04X"
+		  "Detected device %04x on subchannel 0.%x.%04X"
 		  " - PIM = %02X, PAM = %02X, POM = %02X\n",
 		  sch->schib.pmcw.dev, sch->schid.ssid,
 		  sch->schid.sch_no, sch->schib.pmcw.pim,
@@ -680,7 +681,7 @@ do_IRQ (struct pt_regs *regs)
 				sizeof (irb->scsw));
 			/* Call interrupt handler if there is one. */
 			if (sch->driver && sch->driver->irq)
-				sch->driver->irq(&sch->dev);
+				sch->driver->irq(sch);
 		}
 		if (sch)
 			spin_unlock(sch->lock);
@@ -698,8 +699,14 @@ do_IRQ (struct pt_regs *regs)
 
 #ifdef CONFIG_CCW_CONSOLE
 static struct subchannel console_subchannel;
+static struct io_subchannel_private console_priv;
 static int console_subchannel_in_use;
 
+void *cio_get_console_priv(void)
+{
+	return &console_priv;
+}
+
 /*
  * busy wait for the next interrupt on the console
  */
@@ -738,9 +745,9 @@ cio_test_for_console(struct subchannel_id schid, void *data)
 {
 	if (stsch_err(schid, &console_subchannel.schib) != 0)
 		return -ENXIO;
-	if (console_subchannel.schib.pmcw.dnv &&
-	    console_subchannel.schib.pmcw.dev ==
-	    console_devno) {
+	if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
+	    console_subchannel.schib.pmcw.dnv &&
+	    (console_subchannel.schib.pmcw.dev == console_devno)) {
 		console_irq = schid.sch_no;
 		return 1; /* found */
 	}
@@ -758,6 +765,7 @@ cio_get_console_sch_no(void)
 		/* VM provided us with the irq number of the console. */
 		schid.sch_no = console_irq;
 		if (stsch(schid, &console_subchannel.schib) != 0 ||
+		    (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
 		    !console_subchannel.schib.pmcw.dnv)
 			return -1;
 		console_devno = console_subchannel.schib.pmcw.dev;
@@ -804,7 +812,7 @@ cio_probe_console(void)
 	ctl_set_bit(6, 24);
 	console_subchannel.schib.pmcw.isc = 7;
 	console_subchannel.schib.pmcw.intparm =
-		(__u32)(unsigned long)&console_subchannel;
+		(u32)(addr_t)&console_subchannel;
 	ret = cio_modify(&console_subchannel);
 	if (ret) {
 		console_subchannel_in_use = 0;
@@ -1022,7 +1030,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data)
 
 	if (stsch_reset(schid, &schib))
 		return -ENXIO;
-	if (schib.pmcw.dnv &&
+	if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
 	    (schib.pmcw.dev == match_id->devid.devno) &&
 	    (schid.ssid == match_id->devid.ssid)) {
 		match_id->schid = schid;
@@ -1068,6 +1076,8 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
 		return -ENODEV;
 	if (stsch(schid, &schib))
 		return -ENODEV;
+	if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
+		return -ENODEV;
 	if (!schib.pmcw.dnv)
 		return -ENODEV;
 	iplinfo->devno = schib.pmcw.dev;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 7446c39951a7..52afa4c784de 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -11,32 +11,32 @@
  * path management control word
  */
 struct pmcw {
-	__u32 intparm;		/* interruption parameter */
-	__u32 qf   : 1;		/* qdio facility */
-	__u32 res0 : 1;		/* reserved zeros */
-	__u32 isc  : 3;		/* interruption sublass */
-	__u32 res5 : 3;		/* reserved zeros */
-	__u32 ena  : 1;		/* enabled */
-	__u32 lm   : 2;		/* limit mode */
-	__u32 mme  : 2;		/* measurement-mode enable */
-	__u32 mp   : 1;		/* multipath mode */
-	__u32 tf   : 1;		/* timing facility */
-	__u32 dnv  : 1;		/* device number valid */
-	__u32 dev  : 16;	/* device number */
-	__u8  lpm;		/* logical path mask */
-	__u8  pnom;		/* path not operational mask */
-	__u8  lpum;		/* last path used mask */
-	__u8  pim;		/* path installed mask */
-	__u16 mbi;		/* measurement-block index */
-	__u8  pom;		/* path operational mask */
-	__u8  pam;		/* path available mask */
-	__u8  chpid[8];		/* CHPID 0-7 (if available) */
-	__u32 unused1 : 8;	/* reserved zeros */
-	__u32 st      : 3;	/* subchannel type */
-	__u32 unused2 : 18;	/* reserved zeros */
-	__u32 mbfc    : 1;      /* measurement block format control */
-	__u32 xmwme   : 1;      /* extended measurement word mode enable */
-	__u32 csense  : 1;	/* concurrent sense; can be enabled ...*/
+	u32 intparm;		/* interruption parameter */
+	u32 qf	 : 1;		/* qdio facility */
+	u32 res0 : 1;		/* reserved zeros */
+	u32 isc  : 3;		/* interruption sublass */
+	u32 res5 : 3;		/* reserved zeros */
+	u32 ena  : 1;		/* enabled */
+	u32 lm	 : 2;		/* limit mode */
+	u32 mme  : 2;		/* measurement-mode enable */
+	u32 mp	 : 1;		/* multipath mode */
+	u32 tf	 : 1;		/* timing facility */
+	u32 dnv  : 1;		/* device number valid */
+	u32 dev  : 16;		/* device number */
+	u8  lpm;		/* logical path mask */
+	u8  pnom;		/* path not operational mask */
+	u8  lpum;		/* last path used mask */
+	u8  pim;		/* path installed mask */
+	u16 mbi;		/* measurement-block index */
+	u8  pom;		/* path operational mask */
+	u8  pam;		/* path available mask */
+	u8  chpid[8];		/* CHPID 0-7 (if available) */
+	u32 unused1 : 8;	/* reserved zeros */
+	u32 st	    : 3;	/* subchannel type */
+	u32 unused2 : 18;	/* reserved zeros */
+	u32 mbfc    : 1;	/* measurement block format control */
+	u32 xmwme   : 1;	/* extended measurement word mode enable */
+	u32 csense  : 1;	/* concurrent sense; can be enabled ...*/
 				/*  ... per MSCH, however, if facility */
 				/*  ... is not installed, this results */
 				/*  ... in an operand exception.       */
@@ -52,31 +52,6 @@ struct schib {
 	__u8 mda[4];		 /* model dependent area */
 } __attribute__ ((packed,aligned(4)));
 
-/*
- * operation request block
- */
-struct orb {
-	__u32 intparm;		/* interruption parameter */
-	__u32 key  : 4; 	/* flags, like key, suspend control, etc. */
-	__u32 spnd : 1; 	/* suspend control */
-	__u32 res1 : 1; 	/* reserved */
-	__u32 mod  : 1; 	/* modification control */
-	__u32 sync : 1; 	/* synchronize control */
-	__u32 fmt  : 1; 	/* format control */
-	__u32 pfch : 1; 	/* prefetch control */
-	__u32 isic : 1; 	/* initial-status-interruption control */
-	__u32 alcc : 1; 	/* address-limit-checking control */
-	__u32 ssic : 1; 	/* suppress-suspended-interr. control */
-	__u32 res2 : 1; 	/* reserved */
-	__u32 c64  : 1; 	/* IDAW/QDIO 64 bit control  */
-	__u32 i2k  : 1; 	/* IDAW 2/4kB block size control */
-	__u32 lpm  : 8; 	/* logical path mask */
-	__u32 ils  : 1; 	/* incorrect length */
-	__u32 zero : 6; 	/* reserved zeros */
-	__u32 orbx : 1; 	/* ORB extension control */
-	__u32 cpa;		/* channel program address */
-}  __attribute__ ((packed,aligned(4)));
-
 /* subchannel data structure used by I/O subroutines */
 struct subchannel {
 	struct subchannel_id schid;
@@ -85,7 +60,7 @@ struct subchannel {
 	enum {
 		SUBCHANNEL_TYPE_IO = 0,
 		SUBCHANNEL_TYPE_CHSC = 1,
-		SUBCHANNEL_TYPE_MESSAGE = 2,
+		SUBCHANNEL_TYPE_MSG = 2,
 		SUBCHANNEL_TYPE_ADM = 3,
 	} st;			/* subchannel type */
 
@@ -99,11 +74,10 @@ struct subchannel {
 	__u8 lpm;		/* logical path mask */
 	__u8 opm;               /* operational path mask */
 	struct schib schib;	/* subchannel information block */
-	struct orb orb;		/* operation request block */
-	struct ccw1 sense_ccw;	/* static ccw for sense command */
 	struct chsc_ssd_info ssd_info;	/* subchannel description */
 	struct device dev;	/* entry in device tree */
 	struct css_driver *driver;
+	void *private; /* private per subchannel type data */
 } __attribute__ ((aligned(8)));
 
 #define IO_INTERRUPT_TYPE	   0 /* I/O interrupt type */
@@ -111,7 +85,7 @@ struct subchannel {
 #define to_subchannel(n) container_of(n, struct subchannel, dev)
 
 extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
-extern int cio_enable_subchannel (struct subchannel *, unsigned int);
+extern int cio_enable_subchannel(struct subchannel *, unsigned int, u32);
 extern int cio_disable_subchannel (struct subchannel *);
 extern int cio_cancel (struct subchannel *);
 extern int cio_clear (struct subchannel *);
@@ -125,6 +99,7 @@ extern int cio_get_options (struct subchannel *);
 extern int cio_modify (struct subchannel *);
 
 int cio_create_sch_lock(struct subchannel *);
+void do_adapter_IO(void);
 
 /* Use with care. */
 #ifdef CONFIG_CCW_CONSOLE
@@ -133,10 +108,12 @@ extern void cio_release_console(void);
 extern int cio_is_console(struct subchannel_id);
 extern struct subchannel *cio_get_console_subchannel(void);
 extern spinlock_t * cio_get_console_lock(void);
+extern void *cio_get_console_priv(void);
 #else
 #define cio_is_console(schid) 0
 #define cio_get_console_subchannel() NULL
-#define cio_get_console_lock() NULL;
+#define cio_get_console_lock() NULL
+#define cio_get_console_priv() NULL
 #endif
 
 extern int cio_show_msg;
diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
index c9bf8989930f..d7429ef6c666 100644
--- a/drivers/s390/cio/cio_debug.h
+++ b/drivers/s390/cio/cio_debug.h
@@ -8,20 +8,19 @@ extern debug_info_t *cio_debug_msg_id;
 extern debug_info_t *cio_debug_trace_id;
 extern debug_info_t *cio_debug_crw_id;
 
-#define CIO_TRACE_EVENT(imp, txt) do { \
+#define CIO_TRACE_EVENT(imp, txt) do {				\
 		debug_text_event(cio_debug_trace_id, imp, txt); \
 	} while (0)
 
-#define CIO_MSG_EVENT(imp, args...) do { \
-		debug_sprintf_event(cio_debug_msg_id, imp , ##args); \
+#define CIO_MSG_EVENT(imp, args...) do {				\
+		debug_sprintf_event(cio_debug_msg_id, imp , ##args);	\
 	} while (0)
 
-#define CIO_CRW_EVENT(imp, args...) do { \
-		debug_sprintf_event(cio_debug_crw_id, imp , ##args); \
+#define CIO_CRW_EVENT(imp, args...) do {				\
+		debug_sprintf_event(cio_debug_crw_id, imp , ##args);	\
 	} while (0)
 
-static inline void
-CIO_HEX_EVENT(int level, void *data, int length)
+static inline void CIO_HEX_EVENT(int level, void *data, int length)
 {
 	if (unlikely(!cio_debug_trace_id))
 		return;
@@ -32,9 +31,10 @@ CIO_HEX_EVENT(int level, void *data, int length)
 	}
 }
 
-#define CIO_DEBUG(printk_level,event_level,msg...) ({ \
-	if (cio_show_msg) printk(printk_level msg); \
-	CIO_MSG_EVENT (event_level, msg); \
-})
+#define CIO_DEBUG(printk_level, event_level, msg...) do {	\
+		if (cio_show_msg)				\
+			printk(printk_level "cio: " msg);	\
+		CIO_MSG_EVENT(event_level, msg);		\
+	} while (0)
 
 #endif
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index c3df2cd009a4..3b45bbe6cce0 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -51,6 +51,62 @@ for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
 	return ret;
 }
 
+struct cb_data {
+	void *data;
+	struct idset *set;
+	int (*fn_known_sch)(struct subchannel *, void *);
+	int (*fn_unknown_sch)(struct subchannel_id, void *);
+};
+
+static int call_fn_known_sch(struct device *dev, void *data)
+{
+	struct subchannel *sch = to_subchannel(dev);
+	struct cb_data *cb = data;
+	int rc = 0;
+
+	idset_sch_del(cb->set, sch->schid);
+	if (cb->fn_known_sch)
+		rc = cb->fn_known_sch(sch, cb->data);
+	return rc;
+}
+
+static int call_fn_unknown_sch(struct subchannel_id schid, void *data)
+{
+	struct cb_data *cb = data;
+	int rc = 0;
+
+	if (idset_sch_contains(cb->set, schid))
+		rc = cb->fn_unknown_sch(schid, cb->data);
+	return rc;
+}
+
+int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
+			       int (*fn_unknown)(struct subchannel_id,
+			       void *), void *data)
+{
+	struct cb_data cb;
+	int rc;
+
+	cb.set = idset_sch_new();
+	if (!cb.set)
+		return -ENOMEM;
+	idset_fill(cb.set);
+	cb.data = data;
+	cb.fn_known_sch = fn_known;
+	cb.fn_unknown_sch = fn_unknown;
+	/* Process registered subchannels. */
+	rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch);
+	if (rc)
+		goto out;
+	/* Process unregistered subchannels. */
+	if (fn_unknown)
+		rc = for_each_subchannel(call_fn_unknown_sch, &cb);
+out:
+	idset_free(cb.set);
+
+	return rc;
+}
+
 static struct subchannel *
 css_alloc_subchannel(struct subchannel_id schid)
 {
@@ -77,7 +133,7 @@ css_alloc_subchannel(struct subchannel_id schid)
 	 * This is fine even on 64bit since the subchannel is always located
 	 * under 2G.
 	 */
-	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+	sch->schib.pmcw.intparm = (u32)(addr_t)sch;
 	ret = cio_modify(sch);
 	if (ret) {
 		kfree(sch->lock);
@@ -237,11 +293,25 @@ get_subchannel_by_schid(struct subchannel_id schid)
 	return dev ? to_subchannel(dev) : NULL;
 }
 
+/**
+ * css_sch_is_valid() - check if a subchannel is valid
+ * @schib: subchannel information block for the subchannel
+ */
+int css_sch_is_valid(struct schib *schib)
+{
+	if ((schib->pmcw.st == SUBCHANNEL_TYPE_IO) && !schib->pmcw.dnv)
+		return 0;
+	return 1;
+}
+EXPORT_SYMBOL_GPL(css_sch_is_valid);
+
 static int css_get_subchannel_status(struct subchannel *sch)
 {
 	struct schib schib;
 
-	if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
+	if (stsch(sch->schid, &schib))
+		return CIO_GONE;
+	if (!css_sch_is_valid(&schib))
 		return CIO_GONE;
 	if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
 		return CIO_REVALIDATE;
@@ -293,7 +363,7 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
 		action = UNREGISTER;
 		if (sch->driver && sch->driver->notify) {
 			spin_unlock_irqrestore(sch->lock, flags);
-			ret = sch->driver->notify(&sch->dev, event);
+			ret = sch->driver->notify(sch, event);
 			spin_lock_irqsave(sch->lock, flags);
 			if (ret)
 				action = NONE;
@@ -349,7 +419,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
 		/* Will be done on the slow path. */
 		return -EAGAIN;
 	}
-	if (stsch_err(schid, &schib) || !schib.pmcw.dnv) {
+	if (stsch_err(schid, &schib) || !css_sch_is_valid(&schib)) {
 		/* Unusable - ignore. */
 		return 0;
 	}
@@ -388,20 +458,56 @@ static int __init slow_subchannel_init(void)
 	return 0;
 }
 
-static void css_slow_path_func(struct work_struct *unused)
+static int slow_eval_known_fn(struct subchannel *sch, void *data)
 {
-	struct subchannel_id schid;
+	int eval;
+	int rc;
 
-	CIO_TRACE_EVENT(4, "slowpath");
 	spin_lock_irq(&slow_subchannel_lock);
-	init_subchannel_id(&schid);
-	while (idset_sch_get_first(slow_subchannel_set, &schid)) {
-		idset_sch_del(slow_subchannel_set, schid);
-		spin_unlock_irq(&slow_subchannel_lock);
-		css_evaluate_subchannel(schid, 1);
-		spin_lock_irq(&slow_subchannel_lock);
+	eval = idset_sch_contains(slow_subchannel_set, sch->schid);
+	idset_sch_del(slow_subchannel_set, sch->schid);
+	spin_unlock_irq(&slow_subchannel_lock);
+	if (eval) {
+		rc = css_evaluate_known_subchannel(sch, 1);
+		if (rc == -EAGAIN)
+			css_schedule_eval(sch->schid);
 	}
+	return 0;
+}
+
+static int slow_eval_unknown_fn(struct subchannel_id schid, void *data)
+{
+	int eval;
+	int rc = 0;
+
+	spin_lock_irq(&slow_subchannel_lock);
+	eval = idset_sch_contains(slow_subchannel_set, schid);
+	idset_sch_del(slow_subchannel_set, schid);
 	spin_unlock_irq(&slow_subchannel_lock);
+	if (eval) {
+		rc = css_evaluate_new_subchannel(schid, 1);
+		switch (rc) {
+		case -EAGAIN:
+			css_schedule_eval(schid);
+			rc = 0;
+			break;
+		case -ENXIO:
+		case -ENOMEM:
+		case -EIO:
+			/* These should abort looping */
+			break;
+		default:
+			rc = 0;
+		}
+	}
+	return rc;
+}
+
+static void css_slow_path_func(struct work_struct *unused)
+{
+	CIO_TRACE_EVENT(4, "slowpath");
+	for_each_subchannel_staged(slow_eval_known_fn, slow_eval_unknown_fn,
+				   NULL);
 }
 
 static DECLARE_WORK(slow_path_work, css_slow_path_func);
@@ -430,7 +536,6 @@ void css_schedule_eval_all(void)
 /* Reprobe subchannel if unregistered. */
 static int reprobe_subchannel(struct subchannel_id schid, void *data)
 {
-	struct subchannel *sch;
 	int ret;
 
 	CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n",
@@ -438,13 +543,6 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data)
 	if (need_reprobe)
 		return -EAGAIN;
 
-	sch = get_subchannel_by_schid(schid);
-	if (sch) {
-		/* Already known. */
-		put_device(&sch->dev);
-		return 0;
-	}
-
 	ret = css_probe_device(schid);
 	switch (ret) {
 	case 0:
@@ -472,7 +570,7 @@ static void reprobe_all(struct work_struct *unused)
 	/* Make sure initial subchannel scan is done. */
 	wait_event(ccw_device_init_wq,
 		   atomic_read(&ccw_device_init_count) == 0);
-	ret = for_each_subchannel(reprobe_subchannel, NULL);
+	ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);
 
 	CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
 		      need_reprobe);
@@ -787,8 +885,8 @@ int sch_is_pseudo_sch(struct subchannel *sch)
 static int
 css_bus_match (struct device *dev, struct device_driver *drv)
 {
-	struct subchannel *sch = container_of (dev, struct subchannel, dev);
-	struct css_driver *driver = container_of (drv, struct css_driver, drv);
+	struct subchannel *sch = to_subchannel(dev);
+	struct css_driver *driver = to_cssdriver(drv);
 
 	if (sch->st == driver->subchannel_type)
 		return 1;
@@ -796,32 +894,36 @@ css_bus_match (struct device *dev, struct device_driver *drv)
 	return 0;
 }
 
-static int
-css_probe (struct device *dev)
+static int css_probe(struct device *dev)
 {
 	struct subchannel *sch;
+	int ret;
 
 	sch = to_subchannel(dev);
-	sch->driver = container_of (dev->driver, struct css_driver, drv);
-	return (sch->driver->probe ? sch->driver->probe(sch) : 0);
+	sch->driver = to_cssdriver(dev->driver);
+	ret = sch->driver->probe ? sch->driver->probe(sch) : 0;
+	if (ret)
+		sch->driver = NULL;
+	return ret;
 }
 
-static int
-css_remove (struct device *dev)
+static int css_remove(struct device *dev)
 {
 	struct subchannel *sch;
+	int ret;
 
 	sch = to_subchannel(dev);
-	return (sch->driver->remove ? sch->driver->remove(sch) : 0);
+	ret = sch->driver->remove ? sch->driver->remove(sch) : 0;
+	sch->driver = NULL;
+	return ret;
 }
 
-static void
-css_shutdown (struct device *dev)
+static void css_shutdown(struct device *dev)
 {
 	struct subchannel *sch;
 
 	sch = to_subchannel(dev);
-	if (sch->driver->shutdown)
+	if (sch->driver && sch->driver->shutdown)
 		sch->driver->shutdown(sch);
 }
 
@@ -833,6 +935,34 @@ struct bus_type css_bus_type = {
 	.shutdown = css_shutdown,
 };
 
+/**
+ * css_driver_register - register a css driver
+ * @cdrv: css driver to register
+ *
+ * This is mainly a wrapper around driver_register that sets name
+ * and bus_type in the embedded struct device_driver correctly.
+ */
+int css_driver_register(struct css_driver *cdrv)
+{
+	cdrv->drv.name = cdrv->name;
+	cdrv->drv.bus = &css_bus_type;
+	cdrv->drv.owner = cdrv->owner;
+	return driver_register(&cdrv->drv);
+}
+EXPORT_SYMBOL_GPL(css_driver_register);
+
+/**
+ * css_driver_unregister - unregister a css driver
+ * @cdrv: css driver to unregister
+ *
+ * This is a wrapper around driver_unregister.
+ */
+void css_driver_unregister(struct css_driver *cdrv)
+{
+	driver_unregister(&cdrv->drv);
+}
+EXPORT_SYMBOL_GPL(css_driver_unregister);
+
 subsys_initcall(init_channel_subsystem);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 81215ef32435..b70554523552 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -58,64 +58,6 @@ struct pgid {
 	__u32 tod_high;		/* high word TOD clock */
 } __attribute__ ((packed));
 
-#define MAX_CIWS 8
-
-/*
- * sense-id response buffer layout
- */
-struct senseid {
-	/* common part */
-	__u8  reserved;     	/* always 0x'FF' */
-	__u16 cu_type;	     	/* control unit type */
-	__u8  cu_model;     	/* control unit model */
-	__u16 dev_type;     	/* device type */
-	__u8  dev_model;    	/* device model */
-	__u8  unused;	     	/* padding byte */
-	/* extended part */
-	struct ciw ciw[MAX_CIWS];	/* variable # of CIWs */
-}  __attribute__ ((packed,aligned(4)));
-
-struct ccw_device_private {
-	struct ccw_device *cdev;
-	struct subchannel *sch;
-	int state;		/* device state */
-	atomic_t onoff;
-	unsigned long registered;
-	struct ccw_dev_id dev_id;	/* device id */
-	struct subchannel_id schid;	/* subchannel number */
-	__u8 imask;		/* lpm mask for SNID/SID/SPGID */
-	int iretry;		/* retry counter SNID/SID/SPGID */
-	struct {
-		unsigned int fast:1;	/* post with "channel end" */
-		unsigned int repall:1;	/* report every interrupt status */
-		unsigned int pgroup:1;  /* do path grouping */
-		unsigned int force:1;   /* allow forced online */
-	} __attribute__ ((packed)) options;
-	struct {
-		unsigned int pgid_single:1; /* use single path for Set PGID */
-		unsigned int esid:1;        /* Ext. SenseID supported by HW */
-		unsigned int dosense:1;	    /* delayed SENSE required */
-		unsigned int doverify:1;    /* delayed path verification */
-		unsigned int donotify:1;    /* call notify function */
-		unsigned int recog_done:1;  /* dev. recog. complete */
-		unsigned int fake_irb:1;    /* deliver faked irb */
-		unsigned int intretry:1;    /* retry internal operation */
-	} __attribute__((packed)) flags;
-	unsigned long intparm;	/* user interruption parameter */
-	struct qdio_irq *qdio_data;
-	struct irb irb;		/* device status */
-	struct senseid senseid;	/* SenseID info */
-	struct pgid pgid[8];	/* path group IDs per chpid*/
-	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
-	struct work_struct kick_work;
-	wait_queue_head_t wait_q;
-	struct timer_list timer;
-	void *cmb;			/* measurement information */
-	struct list_head cmb_list;	/* list of measured devices */
-	u64 cmb_start_time;		/* clock value of cmb reset */
-	void *cmb_wait;			/* deferred cmb enable/disable */
-};
-
 /*
  * A css driver handles all subchannels of one type.
  * Currently, we only care about I/O subchannels (type 0), these
@@ -123,25 +65,35 @@ struct ccw_device_private {
  */
 struct subchannel;
 struct css_driver {
+	struct module *owner;
 	unsigned int subchannel_type;
 	struct device_driver drv;
-	void (*irq)(struct device *);
-	int (*notify)(struct device *, int);
-	void (*verify)(struct device *);
-	void (*termination)(struct device *);
+	void (*irq)(struct subchannel *);
+	int (*notify)(struct subchannel *, int);
+	void (*verify)(struct subchannel *);
+	void (*termination)(struct subchannel *);
 	int (*probe)(struct subchannel *);
 	int (*remove)(struct subchannel *);
 	void (*shutdown)(struct subchannel *);
+	const char *name;
 };
 
+#define to_cssdriver(n) container_of(n, struct css_driver, drv)
+
 /*
  * all css_drivers have the css_bus_type
  */
 extern struct bus_type css_bus_type;
 
+extern int css_driver_register(struct css_driver *);
+extern void css_driver_unregister(struct css_driver *);
+
 extern void css_sch_device_unregister(struct subchannel *);
 extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
 extern int css_init_done;
+int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
+			       int (*fn_unknown)(struct subchannel_id,
+			       void *), void *data);
 extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
 extern void css_process_crw(int, int);
 extern void css_reiterate_subchannels(void);
@@ -188,6 +140,8 @@ void css_schedule_eval(struct subchannel_id schid);
 void css_schedule_eval_all(void);
 
 int sch_is_pseudo_sch(struct subchannel *);
+struct schib;
+int css_sch_is_valid(struct schib *);
 
 extern struct workqueue_struct *slow_path_wq;
 
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 74f6b539974a..d35dc3f25d06 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -17,6 +17,7 @@
 #include <linux/list.h>
 #include <linux/device.h>
 #include <linux/workqueue.h>
+#include <linux/timer.h>
 
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
@@ -28,6 +29,12 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
+
+static struct timer_list recovery_timer;
+static spinlock_t recovery_lock;
+static int recovery_phase;
+static const unsigned long recovery_delay[] = { 3, 30, 300 };
 
 /******************* bus type handling ***********************/
 
@@ -115,19 +122,18 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 struct bus_type ccw_bus_type;
 
-static int io_subchannel_probe (struct subchannel *);
-static int io_subchannel_remove (struct subchannel *);
-static int io_subchannel_notify(struct device *, int);
-static void io_subchannel_verify(struct device *);
-static void io_subchannel_ioterm(struct device *);
+static void io_subchannel_irq(struct subchannel *);
+static int io_subchannel_probe(struct subchannel *);
+static int io_subchannel_remove(struct subchannel *);
+static int io_subchannel_notify(struct subchannel *, int);
+static void io_subchannel_verify(struct subchannel *);
+static void io_subchannel_ioterm(struct subchannel *);
 static void io_subchannel_shutdown(struct subchannel *);
 
 static struct css_driver io_subchannel_driver = {
+	.owner = THIS_MODULE,
 	.subchannel_type = SUBCHANNEL_TYPE_IO,
-	.drv = {
-		.name = "io_subchannel",
-		.bus  = &css_bus_type,
-	},
+	.name = "io_subchannel",
 	.irq = io_subchannel_irq,
 	.notify = io_subchannel_notify,
 	.verify = io_subchannel_verify,
@@ -142,6 +148,8 @@ struct workqueue_struct *ccw_device_notify_work;
 wait_queue_head_t ccw_device_init_wq;
 atomic_t ccw_device_init_count;
 
+static void recovery_func(unsigned long data);
+
 static int __init
 init_ccw_bus_type (void)
 {
@@ -149,6 +157,7 @@ init_ccw_bus_type (void)
 
 	init_waitqueue_head(&ccw_device_init_wq);
 	atomic_set(&ccw_device_init_count, 0);
+	setup_timer(&recovery_timer, recovery_func, 0);
 
 	ccw_device_work = create_singlethread_workqueue("cio");
 	if (!ccw_device_work)
@@ -166,7 +175,8 @@ init_ccw_bus_type (void)
 	if ((ret = bus_register (&ccw_bus_type)))
 		goto out_err;
 
-	if ((ret = driver_register(&io_subchannel_driver.drv)))
+	ret = css_driver_register(&io_subchannel_driver);
+	if (ret)
 		goto out_err;
 
 	wait_event(ccw_device_init_wq,
@@ -186,7 +196,7 @@ out_err:
 static void __exit
 cleanup_ccw_bus_type (void)
 {
-	driver_unregister(&io_subchannel_driver.drv);
+	css_driver_unregister(&io_subchannel_driver);
 	bus_unregister(&ccw_bus_type);
 	destroy_workqueue(ccw_device_notify_work);
 	destroy_workqueue(ccw_device_work);
@@ -773,7 +783,7 @@ static void sch_attach_device(struct subchannel *sch,
 {
 	css_update_ssd_info(sch);
 	spin_lock_irq(sch->lock);
-	sch->dev.driver_data = cdev;
+	sch_set_cdev(sch, cdev);
 	cdev->private->schid = sch->schid;
 	cdev->ccwlock = sch->lock;
 	device_trigger_reprobe(sch);
@@ -795,7 +805,7 @@ static void sch_attach_disconnected_device(struct subchannel *sch,
 		put_device(&other_sch->dev);
 		return;
 	}
-	other_sch->dev.driver_data = NULL;
+	sch_set_cdev(other_sch, NULL);
 	/* No need to keep a subchannel without ccw device around. */
 	css_sch_device_unregister(other_sch);
 	put_device(&other_sch->dev);
@@ -831,12 +841,12 @@ static void sch_create_and_recog_new_device(struct subchannel *sch)
 		return;
 	}
 	spin_lock_irq(sch->lock);
-	sch->dev.driver_data = cdev;
+	sch_set_cdev(sch, cdev);
 	spin_unlock_irq(sch->lock);
 	/* Start recognition for the new ccw device. */
 	if (io_subchannel_recog(cdev, sch)) {
 		spin_lock_irq(sch->lock);
-		sch->dev.driver_data = NULL;
+		sch_set_cdev(sch, NULL);
 		spin_unlock_irq(sch->lock);
 		if (cdev->dev.release)
 			cdev->dev.release(&cdev->dev);
@@ -940,7 +950,7 @@ io_subchannel_register(struct work_struct *work)
 			      cdev->private->dev_id.devno, ret);
 		put_device(&cdev->dev);
 		spin_lock_irqsave(sch->lock, flags);
-		sch->dev.driver_data = NULL;
+		sch_set_cdev(sch, NULL);
 		spin_unlock_irqrestore(sch->lock, flags);
 		kfree (cdev->private);
 		kfree (cdev);
@@ -1022,7 +1032,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
 	int rc;
 	struct ccw_device_private *priv;
 
-	sch->dev.driver_data = cdev;
+	sch_set_cdev(sch, cdev);
 	sch->driver = &io_subchannel_driver;
 	cdev->ccwlock = sch->lock;
 
@@ -1082,7 +1092,7 @@ static void ccw_device_move_to_sch(struct work_struct *work)
 	}
 	if (former_parent) {
 		spin_lock_irq(former_parent->lock);
-		former_parent->dev.driver_data = NULL;
+		sch_set_cdev(former_parent, NULL);
 		spin_unlock_irq(former_parent->lock);
 		css_sch_device_unregister(former_parent);
 		/* Reset intparm to zeroes. */
@@ -1096,6 +1106,18 @@ out:
 	put_device(&cdev->dev);
 }
 
+static void io_subchannel_irq(struct subchannel *sch)
+{
+	struct ccw_device *cdev;
+
+	cdev = sch_get_cdev(sch);
+
+	CIO_TRACE_EVENT(3, "IRQ");
+	CIO_TRACE_EVENT(3, sch->dev.bus_id);
+	if (cdev)
+		dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
+}
+
 static int
 io_subchannel_probe (struct subchannel *sch)
 {
@@ -1104,13 +1126,13 @@ io_subchannel_probe (struct subchannel *sch)
 	unsigned long flags;
 	struct ccw_dev_id dev_id;
 
-	if (sch->dev.driver_data) {
+	cdev = sch_get_cdev(sch);
+	if (cdev) {
 		/*
 		 * This subchannel already has an associated ccw_device.
 		 * Register it and exit. This happens for all early
 		 * device, e.g. the console.
 		 */
-		cdev = sch->dev.driver_data;
 		cdev->dev.groups = ccwdev_attr_groups;
 		device_initialize(&cdev->dev);
 		ccw_device_register(cdev);
@@ -1132,6 +1154,11 @@ io_subchannel_probe (struct subchannel *sch)
 	 */
 	dev_id.devno = sch->schib.pmcw.dev;
 	dev_id.ssid = sch->schid.ssid;
+	/* Allocate I/O subchannel private data. */
+	sch->private = kzalloc(sizeof(struct io_subchannel_private),
+			       GFP_KERNEL | GFP_DMA);
+	if (!sch->private)
+		return -ENOMEM;
 	cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
 	if (!cdev)
 		cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
@@ -1149,16 +1176,18 @@ io_subchannel_probe (struct subchannel *sch)
 		return 0;
 	}
 	cdev = io_subchannel_create_ccwdev(sch);
-	if (IS_ERR(cdev))
+	if (IS_ERR(cdev)) {
+		kfree(sch->private);
 		return PTR_ERR(cdev);
-
+	}
 	rc = io_subchannel_recog(cdev, sch);
 	if (rc) {
 		spin_lock_irqsave(sch->lock, flags);
-		sch->dev.driver_data = NULL;
+		sch_set_cdev(sch, NULL);
 		spin_unlock_irqrestore(sch->lock, flags);
 		if (cdev->dev.release)
 			cdev->dev.release(&cdev->dev);
+		kfree(sch->private);
 	}
 
 	return rc;
@@ -1170,25 +1199,25 @@ io_subchannel_remove (struct subchannel *sch)
 	struct ccw_device *cdev;
 	unsigned long flags;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return 0;
-	cdev = sch->dev.driver_data;
 	/* Set ccw device to not operational and drop reference. */
 	spin_lock_irqsave(cdev->ccwlock, flags);
-	sch->dev.driver_data = NULL;
+	sch_set_cdev(sch, NULL);
 	cdev->private->state = DEV_STATE_NOT_OPER;
 	spin_unlock_irqrestore(cdev->ccwlock, flags);
 	ccw_device_unregister(cdev);
 	put_device(&cdev->dev);
+	kfree(sch->private);
 	return 0;
 }
 
-static int
-io_subchannel_notify(struct device *dev, int event)
+static int io_subchannel_notify(struct subchannel *sch, int event)
 {
 	struct ccw_device *cdev;
 
-	cdev = dev->driver_data;
+	cdev = sch_get_cdev(sch);
 	if (!cdev)
 		return 0;
 	if (!cdev->drv)
@@ -1198,22 +1227,20 @@ io_subchannel_notify(struct device *dev, int event)
 	return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0;
 }
 
-static void
-io_subchannel_verify(struct device *dev)
+static void io_subchannel_verify(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	cdev = dev->driver_data;
+	cdev = sch_get_cdev(sch);
 	if (cdev)
 		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
 }
 
-static void
-io_subchannel_ioterm(struct device *dev)
+static void io_subchannel_ioterm(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	cdev = dev->driver_data;
+	cdev = sch_get_cdev(sch);
 	if (!cdev)
 		return;
 	/* Internal I/O will be retried by the interrupt handler. */
@@ -1231,7 +1258,7 @@ io_subchannel_shutdown(struct subchannel *sch)
 	struct ccw_device *cdev;
 	int ret;
 
-	cdev = sch->dev.driver_data;
+	cdev = sch_get_cdev(sch);
 
 	if (cio_is_console(sch->schid))
 		return;
@@ -1271,6 +1298,9 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
 {
 	int rc;
 
+	/* Attach subchannel private data. */
+	sch->private = cio_get_console_priv();
+	memset(sch->private, 0, sizeof(struct io_subchannel_private));
 	/* Initialize the ccw_device structure. */
 	cdev->dev.parent= &sch->dev;
 	rc = io_subchannel_recog(cdev, sch);
@@ -1456,6 +1486,7 @@ int ccw_driver_register(struct ccw_driver *cdriver)
 
 	drv->bus = &ccw_bus_type;
 	drv->name = cdriver->name;
+	drv->owner = cdriver->owner;
 
 	return driver_register(drv);
 }
@@ -1481,6 +1512,60 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev)
 	return sch->schid;
 }
 
+static int recovery_check(struct device *dev, void *data)
+{
+	struct ccw_device *cdev = to_ccwdev(dev);
+	int *redo = data;
+
+	spin_lock_irq(cdev->ccwlock);
+	switch (cdev->private->state) {
+	case DEV_STATE_DISCONNECTED:
+		CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n",
+			      cdev->private->dev_id.ssid,
+			      cdev->private->dev_id.devno);
+		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+		*redo = 1;
+		break;
+	case DEV_STATE_DISCONNECTED_SENSE_ID:
+		*redo = 1;
+		break;
+	}
+	spin_unlock_irq(cdev->ccwlock);
+
+	return 0;
+}
+
+static void recovery_func(unsigned long data)
+{
+	int redo = 0;
+
+	bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check);
+	if (redo) {
+		spin_lock_irq(&recovery_lock);
+		if (!timer_pending(&recovery_timer)) {
+			if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1)
+				recovery_phase++;
+			mod_timer(&recovery_timer, jiffies +
+				  recovery_delay[recovery_phase] * HZ);
+		}
+		spin_unlock_irq(&recovery_lock);
+	} else
+		CIO_MSG_EVENT(2, "recovery: end\n");
+}
+
+void ccw_device_schedule_recovery(void)
+{
+	unsigned long flags;
+
+	CIO_MSG_EVENT(2, "recovery: schedule\n");
+	spin_lock_irqsave(&recovery_lock, flags);
+	if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
+		recovery_phase = 0;
+		mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ);
+	}
+	spin_unlock_irqrestore(&recovery_lock, flags);
+}
+
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(ccw_device_set_online);
 EXPORT_SYMBOL(ccw_device_set_offline);
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 0d4089600439..d40a2ffaa000 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -5,6 +5,8 @@
 #include <asm/atomic.h>
 #include <linux/wait.h>
 
+#include "io_sch.h"
+
 /*
  * states of the device statemachine
  */
@@ -74,7 +76,6 @@ extern struct workqueue_struct *ccw_device_notify_work;
 extern wait_queue_head_t ccw_device_init_wq;
 extern atomic_t ccw_device_init_count;
 
-void io_subchannel_irq (struct device *pdev);
 void io_subchannel_recog_done(struct ccw_device *cdev);
 
 int ccw_device_cancel_halt_clear(struct ccw_device *);
@@ -87,6 +88,8 @@ int ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
 
+void ccw_device_schedule_recovery(void);
+
 /* Function prototypes for device status and basic sense stuff. */
 void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);
 void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index bfad421cda66..4b92c84fb438 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -25,14 +25,16 @@
 #include "ioasm.h"
 #include "chp.h"
 
+static int timeout_log_enabled;
+
 int
 device_is_online(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return 0;
-	cdev = sch->dev.driver_data;
 	return (cdev->private->state == DEV_STATE_ONLINE);
 }
 
@@ -41,9 +43,9 @@ device_is_disconnected(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return 0;
-	cdev = sch->dev.driver_data;
 	return (cdev->private->state == DEV_STATE_DISCONNECTED ||
 		cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID);
 }
@@ -53,19 +55,21 @@ device_set_disconnected(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return;
-	cdev = sch->dev.driver_data;
 	ccw_device_set_timeout(cdev, 0);
 	cdev->private->flags.fake_irb = 0;
 	cdev->private->state = DEV_STATE_DISCONNECTED;
+	if (cdev->online)
+		ccw_device_schedule_recovery();
 }
 
 void device_set_intretry(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	cdev = sch->dev.driver_data;
+	cdev = sch_get_cdev(sch);
 	if (!cdev)
 		return;
 	cdev->private->flags.intretry = 1;
@@ -75,13 +79,62 @@ int device_trigger_verify(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	cdev = sch->dev.driver_data;
+	cdev = sch_get_cdev(sch);
 	if (!cdev || !cdev->online)
 		return -EINVAL;
 	dev_fsm_event(cdev, DEV_EVENT_VERIFY);
 	return 0;
 }
 
+static int __init ccw_timeout_log_setup(char *unused)
+{
+	timeout_log_enabled = 1;
+	return 1;
+}
+
+__setup("ccw_timeout_log", ccw_timeout_log_setup);
+
+static void ccw_timeout_log(struct ccw_device *cdev)
+{
+	struct schib schib;
+	struct subchannel *sch;
+	struct io_subchannel_private *private;
+	int cc;
+
+	sch = to_subchannel(cdev->dev.parent);
+	private = to_io_private(sch);
+	cc = stsch(sch->schid, &schib);
+
+	printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
+	       "device information:\n", get_clock());
+	printk(KERN_WARNING "cio: orb:\n");
+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+		       &private->orb, sizeof(private->orb), 0);
+	printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id);
+	printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id);
+	printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, "
+	       "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm);
+
+	if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw ||
+	    (void *)(addr_t)private->orb.cpa == cdev->private->iccws)
+		printk(KERN_WARNING "cio: last channel program (intern):\n");
+	else
+		printk(KERN_WARNING "cio: last channel program:\n");
+
+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+		       (void *)(addr_t)private->orb.cpa,
+		       sizeof(struct ccw1), 0);
+	printk(KERN_WARNING "cio: ccw device state: %d\n",
+	       cdev->private->state);
+	printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc);
+	printk(KERN_WARNING "cio: schib:\n");
+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+		       &schib, sizeof(schib), 0);
+	printk(KERN_WARNING "cio: ccw device flags:\n");
+	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
+		       &cdev->private->flags, sizeof(cdev->private->flags), 0);
+}
+
 /*
  * Timeout function. It just triggers a DEV_EVENT_TIMEOUT.
  */
@@ -92,6 +145,8 @@ ccw_device_timeout(unsigned long data)
 
 	cdev = (struct ccw_device *) data;
 	spin_lock_irq(cdev->ccwlock);
+	if (timeout_log_enabled)
+		ccw_timeout_log(cdev);
 	dev_fsm_event(cdev, DEV_EVENT_TIMEOUT);
 	spin_unlock_irq(cdev->ccwlock);
 }
@@ -122,9 +177,9 @@ device_kill_pending_timer(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return;
-	cdev = sch->dev.driver_data;
 	ccw_device_set_timeout(cdev, 0);
 }
 
@@ -268,7 +323,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
 	switch (state) {
 	case DEV_STATE_NOT_OPER:
 		CIO_DEBUG(KERN_WARNING, 2,
-			  "cio: SenseID : unknown device %04x on subchannel "
+			  "SenseID : unknown device %04x on subchannel "
 			  "0.%x.%04x\n", cdev->private->dev_id.devno,
 			  sch->schid.ssid, sch->schid.sch_no);
 		break;
@@ -294,7 +349,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
 		}
 		/* Issue device info message. */
 		CIO_DEBUG(KERN_INFO, 2,
-			  "cio: SenseID : device 0.%x.%04x reports: "
+			  "SenseID : device 0.%x.%04x reports: "
 			  "CU  Type/Mod = %04X/%02X, Dev Type/Mod = "
 			  "%04X/%02X\n",
 			  cdev->private->dev_id.ssid,
@@ -304,7 +359,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
 		break;
 	case DEV_STATE_BOXED:
 		CIO_DEBUG(KERN_WARNING, 2,
-			  "cio: SenseID : boxed device %04x on subchannel "
+			  "SenseID : boxed device %04x on subchannel "
 			  "0.%x.%04x\n", cdev->private->dev_id.devno,
 			  sch->schid.ssid, sch->schid.sch_no);
 		break;
@@ -349,7 +404,7 @@ ccw_device_oper_notify(struct work_struct *work)
 	sch = to_subchannel(cdev->dev.parent);
 	if (sch->driver && sch->driver->notify) {
 		spin_unlock_irqrestore(cdev->ccwlock, flags);
-		ret = sch->driver->notify(&sch->dev, CIO_OPER);
+		ret = sch->driver->notify(sch, CIO_OPER);
 		spin_lock_irqsave(cdev->ccwlock, flags);
 	} else
 		ret = 0;
@@ -389,7 +444,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
 
 	if (state == DEV_STATE_BOXED)
 		CIO_DEBUG(KERN_WARNING, 2,
-			  "cio: Boxed device %04x on subchannel %04x\n",
+			  "Boxed device %04x on subchannel %04x\n",
 			  cdev->private->dev_id.devno, sch->schid.sch_no);
 
 	if (cdev->private->flags.donotify) {
@@ -500,7 +555,8 @@ ccw_device_recognition(struct ccw_device *cdev)
 	    (cdev->private->state != DEV_STATE_BOXED))
 		return -EINVAL;
 	sch = to_subchannel(cdev->dev.parent);
-	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
+	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
+				    (u32)(addr_t)sch);
 	if (ret != 0)
 		/* Couldn't enable the subchannel for i/o. Sick device. */
 		return ret;
@@ -587,9 +643,10 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
 	default:
 		/* Reset oper notify indication after verify error. */
 		cdev->private->flags.donotify = 0;
-		if (cdev->online)
+		if (cdev->online) {
+			ccw_device_set_timeout(cdev, 0);
 			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
-		else
+		} else
 			ccw_device_done(cdev, DEV_STATE_NOT_OPER);
 		break;
 	}
@@ -610,7 +667,8 @@ ccw_device_online(struct ccw_device *cdev)
 	sch = to_subchannel(cdev->dev.parent);
 	if (css_init_done && !get_device(&cdev->dev))
 		return -ENODEV;
-	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc);
+	ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
+				    (u32)(addr_t)sch);
 	if (ret != 0) {
 		/* Couldn't enable the subchannel for i/o. Sick device. */
 		if (ret == -ENODEV)
@@ -937,7 +995,7 @@ void device_kill_io(struct subchannel *sch)
 	int ret;
 	struct ccw_device *cdev;
 
-	cdev = sch->dev.driver_data;
+	cdev = sch_get_cdev(sch);
 	ret = ccw_device_cancel_halt_clear(cdev);
 	if (ret == -EBUSY) {
 		ccw_device_set_timeout(cdev, 3*HZ);
@@ -990,7 +1048,8 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
 	struct subchannel *sch;
 
 	sch = to_subchannel(cdev->dev.parent);
-	if (cio_enable_subchannel(sch, sch->schib.pmcw.isc) != 0)
+	if (cio_enable_subchannel(sch, sch->schib.pmcw.isc,
+				  (u32)(addr_t)sch) != 0)
 		/* Couldn't enable the subchannel for i/o. Sick device. */
 		return;
 
@@ -1006,9 +1065,9 @@ device_trigger_reprobe(struct subchannel *sch)
 {
 	struct ccw_device *cdev;
 
-	if (!sch->dev.driver_data)
+	cdev = sch_get_cdev(sch);
+	if (!cdev)
 		return;
-	cdev = sch->dev.driver_data;
 	if (cdev->private->state != DEV_STATE_DISCONNECTED)
 		return;
 
@@ -1028,7 +1087,7 @@ device_trigger_reprobe(struct subchannel *sch)
 	sch->schib.pmcw.ena = 0;
 	if ((sch->lpm & (sch->lpm - 1)) != 0)
 		sch->schib.pmcw.mp = 1;
-	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+	sch->schib.pmcw.intparm = (u32)(addr_t)sch;
 	/* We should also udate ssd info, but this has to wait. */
 	/* Check if this is another device which appeared on the same sch. */
 	if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
@@ -1223,21 +1282,4 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
 	},
 };
 
-/*
- * io_subchannel_irq is called for "real" interrupts or for status
- * pending conditions on msch.
- */
-void
-io_subchannel_irq (struct device *pdev)
-{
-	struct ccw_device *cdev;
-
-	cdev = to_subchannel(pdev)->dev.driver_data;
-
-	CIO_TRACE_EVENT (3, "IRQ");
-	CIO_TRACE_EVENT (3, pdev->bus_id);
-	if (cdev)
-		dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
-}
-
 EXPORT_SYMBOL_GPL(ccw_device_set_timeout);
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 156f3f9786b5..918b8b89cf9a 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -24,6 +24,7 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
 
 /*
  * Input :
@@ -219,11 +220,13 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
 		return -EAGAIN;
 	}
 	if (irb->scsw.cc == 3) {
-		if ((sch->orb.lpm &
-		     sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
+		u8 lpm;
+
+		lpm = to_io_private(sch)->orb.lpm;
+		if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
 			CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x "
 				      "on subchannel 0.%x.%04x is "
-				      "'not operational'\n", sch->orb.lpm,
+				      "'not operational'\n", lpm,
 				      cdev->private->dev_id.devno,
 				      sch->schid.ssid, sch->schid.sch_no);
 		return -EACCES;
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 7fd2dadc3297..49b58eb0fab8 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -501,7 +501,7 @@ ccw_device_stlck(struct ccw_device *cdev)
 		return -ENOMEM;
 	}
 	spin_lock_irqsave(sch->lock, flags);
-	ret = cio_enable_subchannel(sch, 3);
+	ret = cio_enable_subchannel(sch, 3, (u32)(addr_t)sch);
 	if (ret)
 		goto out_unlock;
 	/*
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index cb1879a96818..c52449a1f9fc 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -22,6 +22,7 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
 
 /*
  * Helper function called from interrupt context to decide whether an
@@ -155,10 +156,13 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
 		return -EAGAIN;
 	}
 	if (irb->scsw.cc == 3) {
+		u8 lpm;
+
+		lpm = to_io_private(sch)->orb.lpm;
 		CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x,"
 			      " lpm %02X, became 'not operational'\n",
 			      cdev->private->dev_id.devno, sch->schid.ssid,
-			      sch->schid.sch_no, sch->orb.lpm);
+			      sch->schid.sch_no, lpm);
 		return -EACCES;
 	}
 	i = 8 - ffs(cdev->private->imask);
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index aa96e6752592..ebe0848cfe33 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -20,6 +20,7 @@
 #include "css.h"
 #include "device.h"
 #include "ioasm.h"
+#include "io_sch.h"
 
 /*
  * Check for any kind of channel or interface control check but don't
@@ -310,6 +311,7 @@ int
 ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
 {
 	struct subchannel *sch;
+	struct ccw1 *sense_ccw;
 
 	sch = to_subchannel(cdev->dev.parent);
 
@@ -326,15 +328,16 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
 	/*
 	 * We have ending status but no sense information. Do a basic sense.
 	 */
-	sch->sense_ccw.cmd_code = CCW_CMD_BASIC_SENSE;
-	sch->sense_ccw.cda = (__u32) __pa(cdev->private->irb.ecw);
-	sch->sense_ccw.count = SENSE_MAX_COUNT;
-	sch->sense_ccw.flags = CCW_FLAG_SLI;
+	sense_ccw = &to_io_private(sch)->sense_ccw;
+	sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
+	sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw);
+	sense_ccw->count = SENSE_MAX_COUNT;
+	sense_ccw->flags = CCW_FLAG_SLI;
 
 	/* Reset internal retry indication. */
 	cdev->private->flags.intretry = 0;
 
-	return cio_start (sch, &sch->sense_ccw, 0xff);
+	return cio_start(sch, sense_ccw, 0xff);
 }
 
 /*
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
new file mode 100644
index 000000000000..8c613160bfce
--- /dev/null
+++ b/drivers/s390/cio/io_sch.h
@@ -0,0 +1,163 @@
+#ifndef S390_IO_SCH_H
+#define S390_IO_SCH_H
+
+#include "schid.h"
+
+/*
+ * operation request block
+ */
+struct orb {
+	u32 intparm;	/* interruption parameter */
+	u32 key  : 4;	/* flags, like key, suspend control, etc. */
+	u32 spnd : 1;	/* suspend control */
+	u32 res1 : 1;	/* reserved */
+	u32 mod  : 1;	/* modification control */
+	u32 sync : 1;	/* synchronize control */
+	u32 fmt  : 1;	/* format control */
+	u32 pfch : 1;	/* prefetch control */
+	u32 isic : 1;	/* initial-status-interruption control */
+	u32 alcc : 1;	/* address-limit-checking control */
+	u32 ssic : 1;	/* suppress-suspended-interr. control */
+	u32 res2 : 1;	/* reserved */
+	u32 c64  : 1;	/* IDAW/QDIO 64 bit control  */
+	u32 i2k  : 1;	/* IDAW 2/4kB block size control */
+	u32 lpm  : 8;	/* logical path mask */
+	u32 ils  : 1;	/* incorrect length */
+	u32 zero : 6;	/* reserved zeros */
+	u32 orbx : 1;	/* ORB extension control */
+	u32 cpa;	/* channel program address */
+}  __attribute__ ((packed, aligned(4)));
+
+struct io_subchannel_private {
+	struct orb orb;		/* operation request block */
+	struct ccw1 sense_ccw;	/* static ccw for sense command */
+} __attribute__ ((aligned(8)));
+
+#define to_io_private(n) ((struct io_subchannel_private *)n->private)
+#define sch_get_cdev(n) (dev_get_drvdata(&n->dev))
+#define sch_set_cdev(n, c) (dev_set_drvdata(&n->dev, c))
+
+#define MAX_CIWS 8
+
+/*
+ * sense-id response buffer layout
+ */
+struct senseid {
+	/* common part */
+	u8  reserved;	/* always 0x'FF' */
+	u16 cu_type;	/* control unit type */
+	u8  cu_model;	/* control unit model */
+	u16 dev_type;	/* device type */
+	u8  dev_model;	/* device model */
+	u8  unused;	/* padding byte */
+	/* extended part */
+	struct ciw ciw[MAX_CIWS];	/* variable # of CIWs */
+}  __attribute__ ((packed, aligned(4)));
+
+struct ccw_device_private {
+	struct ccw_device *cdev;
+	struct subchannel *sch;
+	int state;		/* device state */
+	atomic_t onoff;
+	unsigned long registered;
+	struct ccw_dev_id dev_id;	/* device id */
+	struct subchannel_id schid;	/* subchannel number */
+	u8 imask;		/* lpm mask for SNID/SID/SPGID */
+	int iretry;		/* retry counter SNID/SID/SPGID */
+	struct {
+		unsigned int fast:1;	/* post with "channel end" */
+		unsigned int repall:1;	/* report every interrupt status */
+		unsigned int pgroup:1;	/* do path grouping */
+		unsigned int force:1;	/* allow forced online */
+	} __attribute__ ((packed)) options;
+	struct {
+		unsigned int pgid_single:1; /* use single path for Set PGID */
+		unsigned int esid:1;	    /* Ext. SenseID supported by HW */
+		unsigned int dosense:1;	    /* delayed SENSE required */
+		unsigned int doverify:1;    /* delayed path verification */
+		unsigned int donotify:1;    /* call notify function */
+		unsigned int recog_done:1;  /* dev. recog. complete */
+		unsigned int fake_irb:1;    /* deliver faked irb */
+		unsigned int intretry:1;    /* retry internal operation */
+	} __attribute__((packed)) flags;
+	unsigned long intparm;	/* user interruption parameter */
+	struct qdio_irq *qdio_data;
+	struct irb irb;		/* device status */
+	struct senseid senseid;	/* SenseID info */
+	struct pgid pgid[8];	/* path group IDs per chpid*/
+	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
+	struct work_struct kick_work;
+	wait_queue_head_t wait_q;
+	struct timer_list timer;
+	void *cmb;			/* measurement information */
+	struct list_head cmb_list;	/* list of measured devices */
+	u64 cmb_start_time;		/* clock value of cmb reset */
+	void *cmb_wait;			/* deferred cmb enable/disable */
+};
+
+static inline int ssch(struct subchannel_id schid, volatile struct orb *addr)
+{
+	register struct subchannel_id reg1 asm("1") = schid;
+	int ccode;
+
+	asm volatile(
+		"	ssch	0(%2)\n"
+		"	ipm	%0\n"
+		"	srl	%0,28"
+		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
+	return ccode;
+}
+
+static inline int rsch(struct subchannel_id schid)
+{
+	register struct subchannel_id reg1 asm("1") = schid;
+	int ccode;
+
+	asm volatile(
+		"	rsch\n"
+		"	ipm	%0\n"
+		"	srl	%0,28"
+		: "=d" (ccode) : "d" (reg1) : "cc");
+	return ccode;
+}
+
+static inline int csch(struct subchannel_id schid)
+{
+	register struct subchannel_id reg1 asm("1") = schid;
+	int ccode;
+
+	asm volatile(
+		"	csch\n"
+		"	ipm	%0\n"
+		"	srl	%0,28"
+		: "=d" (ccode) : "d" (reg1) : "cc");
+	return ccode;
+}
+
+static inline int hsch(struct subchannel_id schid)
+{
+	register struct subchannel_id reg1 asm("1") = schid;
+	int ccode;
+
+	asm volatile(
+		"	hsch\n"
+		"	ipm	%0\n"
+		"	srl	%0,28"
+		: "=d" (ccode) : "d" (reg1) : "cc");
+	return ccode;
+}
+
+static inline int xsch(struct subchannel_id schid)
+{
+	register struct subchannel_id reg1 asm("1") = schid;
+	int ccode;
+
+	asm volatile(
+		"	.insn	rre,0xb2760000,%1,0\n"
+		"	ipm	%0\n"
+		"	srl	%0,28"
+		: "=d" (ccode) : "d" (reg1) : "cc");
+	return ccode;
+}
+
+#endif
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index 7153dd959082..652ea3625f9d 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -109,72 +109,6 @@ static inline int tpi( volatile struct tpi_info *addr)
 	return ccode;
 }
 
-static inline int ssch(struct subchannel_id schid,
-			   volatile struct orb *addr)
-{
-	register struct subchannel_id reg1 asm ("1") = schid;
-	int ccode;
-
-	asm volatile(
-		"	ssch	0(%2)\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
-	return ccode;
-}
-
-static inline int rsch(struct subchannel_id schid)
-{
-	register struct subchannel_id reg1 asm ("1") = schid;
-	int ccode;
-
-	asm volatile(
-		"	rsch\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
-	return ccode;
-}
-
-static inline int csch(struct subchannel_id schid)
-{
-	register struct subchannel_id reg1 asm ("1") = schid;
-	int ccode;
-
-	asm volatile(
-		"	csch\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
-	return ccode;
-}
-
-static inline int hsch(struct subchannel_id schid)
-{
-	register struct subchannel_id reg1 asm ("1") = schid;
-	int ccode;
-
-	asm volatile(
-		"	hsch\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
-	return ccode;
-}
-
-static inline int xsch(struct subchannel_id schid)
-{
-	register struct subchannel_id reg1 asm ("1") = schid;
-	int ccode;
-
-	asm volatile(
-		"	.insn	rre,0xb2760000,%1,0\n"
-		"	ipm	%0\n"
-		"	srl	%0,28"
-		: "=d" (ccode) : "d" (reg1) : "cc");
-	return ccode;
-}
-
 static inline int chsc(void *chsc_area)
 {
 	typedef struct { char _[4096]; } addr_type;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 40a3208c7cf3..e2a781b6b21d 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -48,11 +48,11 @@
 #include <asm/debug.h>
 #include <asm/s390_rdev.h>
 #include <asm/qdio.h>
+#include <asm/airq.h>
 
 #include "cio.h"
 #include "css.h"
 #include "device.h"
-#include "airq.h"
 #include "qdio.h"
 #include "ioasm.h"
 #include "chsc.h"
@@ -96,7 +96,7 @@ static debug_info_t *qdio_dbf_slsb_in;
 static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change
 						 during a while loop */
 static DEFINE_SPINLOCK(ttiq_list_lock);
-static int register_thinint_result;
+static void *tiqdio_ind;
 static void tiqdio_tl(unsigned long);
 static DECLARE_TASKLET(tiqdio_tasklet,tiqdio_tl,0);
 
@@ -399,7 +399,7 @@ qdio_get_indicator(void)
 {
 	int i;
 
-	for (i=1;i<INDICATORS_PER_CACHELINE;i++)
+	for (i = 0; i < INDICATORS_PER_CACHELINE; i++)
 		if (!indicator_used[i]) {
 			indicator_used[i]=1;
 			return indicators+i;
@@ -1408,8 +1408,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
 	if (q->hydra_gives_outbound_pcis) {
 		if (!q->siga_sync_done_on_thinints) {
 			SYNC_MEMORY_ALL;
-		} else if ((!q->siga_sync_done_on_outb_tis)&&
-			 (q->hydra_gives_outbound_pcis)) {
+		} else if (!q->siga_sync_done_on_outb_tis) {
 			SYNC_MEMORY_ALL_OUTB;
 		}
 	} else {
@@ -1911,8 +1910,7 @@ qdio_fill_thresholds(struct qdio_irq *irq_ptr,
 	}
 }
 
-static int
-tiqdio_thinint_handler(void)
+static void tiqdio_thinint_handler(void *ind, void *drv_data)
 {
 	QDIO_DBF_TEXT4(0,trace,"thin_int");
 
@@ -1925,7 +1923,6 @@ tiqdio_thinint_handler(void)
 		tiqdio_clear_global_summary();
 
 	tiqdio_inbound_checks();
-	return 0;
 }
 
 static void
@@ -2445,7 +2442,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero)
 		real_addr_dev_st_chg_ind=0;
 	} else {
 		real_addr_local_summary_bit=
-			virt_to_phys((volatile void *)indicators);
+			virt_to_phys((volatile void *)tiqdio_ind);
 		real_addr_dev_st_chg_ind=
 			virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind);
 	}
@@ -3740,23 +3737,25 @@ static void
 tiqdio_register_thinints(void)
 {
 	char dbf_text[20];
-	register_thinint_result=
-		s390_register_adapter_interrupt(&tiqdio_thinint_handler);
-	if (register_thinint_result) {
-		sprintf(dbf_text,"regthn%x",(register_thinint_result&0xff));
+
+	tiqdio_ind =
+		s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL);
+	if (IS_ERR(tiqdio_ind)) {
+		sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind));
 		QDIO_DBF_TEXT0(0,setup,dbf_text);
 		QDIO_PRINT_ERR("failed to register adapter handler " \
-			       "(rc=%i).\nAdapter interrupts might " \
+			       "(rc=%li).\nAdapter interrupts might " \
 			       "not work. Continuing.\n",
-			       register_thinint_result);
+			       PTR_ERR(tiqdio_ind));
+		tiqdio_ind = NULL;
 	}
 }
 
 static void
 tiqdio_unregister_thinints(void)
 {
-	if (!register_thinint_result)
-		s390_unregister_adapter_interrupt(&tiqdio_thinint_handler);
+	if (tiqdio_ind)
+		s390_unregister_adapter_interrupt(tiqdio_ind);
 }
 
 static int
@@ -3768,8 +3767,8 @@ qdio_get_qdio_memory(void)
 	for (i=1;i<INDICATORS_PER_CACHELINE;i++)
 		indicator_used[i]=0;
 	indicators = kzalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
-				   GFP_KERNEL);
-       	if (!indicators)
+			     GFP_KERNEL);
+	if (!indicators)
 		return -ENOMEM;
 	return 0;
 }
@@ -3780,7 +3779,6 @@ qdio_release_qdio_memory(void)
 	kfree(indicators);
 }
 
-
 static void
 qdio_unregister_dbf_views(void)
 {
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 6d7aad18f6f0..37870e4e938e 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -57,7 +57,7 @@
 					    of the queue to 0 */
 
 #define QDIO_ESTABLISH_TIMEOUT (1*HZ)
-#define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10)
+#define QDIO_ACTIVATE_TIMEOUT (5*HZ)
 #define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ)
 #define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ)
 #define QDIO_FORCE_CHECK_TIMEOUT (10*HZ)
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 3561982749e3..c3076217871e 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -2416,7 +2416,7 @@ init_ccw_bk(struct net_device *dev)
 		    privptr->p_buff_pages_perwrite);
 #endif
                    if (p_buff==NULL) {
-                        printk(KERN_INFO "%s:%s __get_free_pages"
+			printk(KERN_INFO "%s:%s __get_free_pages "
 			 	"for writes buf failed : get is for %d pages\n",
 				dev->name,
 				__FUNCTION__,
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 0fd663b23d76..7bfe8d707a34 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1115,7 +1115,7 @@ list_modified:
 			rc = lcs_send_setipm(card, ipm);
 			spin_lock_irqsave(&card->ipm_lock, flags);
 			if (rc) {
-				PRINT_INFO("Adding multicast address failed."
+				PRINT_INFO("Adding multicast address failed. "
 					   "Table possibly full!\n");
 				/* store ipm in failed list -> will be added
 				 * to ipm_list again, so a retry will be done
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index c7ea9381db9f..f3d893cfe61d 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -198,8 +198,7 @@ struct iucv_connection {
 /**
  * Linked list of all connection structs.
  */
-static struct list_head iucv_connection_list =
-	LIST_HEAD_INIT(iucv_connection_list);
+static LIST_HEAD(iucv_connection_list);
 static DEFINE_RWLOCK(iucv_connection_rwlock);
 
 /**
@@ -2089,6 +2088,11 @@ static struct attribute_group netiucv_drv_attr_group = {
 	.attrs = netiucv_drv_attrs,
 };
 
+static struct attribute_group *netiucv_drv_attr_groups[] = {
+	&netiucv_drv_attr_group,
+	NULL,
+};
+
 static void netiucv_banner(void)
 {
 	PRINT_INFO("NETIUCV driver initialized\n");
@@ -2113,7 +2117,6 @@ static void __exit netiucv_exit(void)
 		netiucv_unregister_device(dev);
 	}
 
-	sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
 	driver_unregister(&netiucv_driver);
 	iucv_unregister(&netiucv_handler, 1);
 	iucv_unregister_dbf_views();
@@ -2133,6 +2136,7 @@ static int __init netiucv_init(void)
 	if (rc)
 		goto out_dbf;
 	IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
+	netiucv_driver.groups = netiucv_drv_attr_groups;
 	rc = driver_register(&netiucv_driver);
 	if (rc) {
 		PRINT_ERR("NETIUCV: failed to register driver.\n");
@@ -2140,18 +2144,9 @@ static int __init netiucv_init(void)
 		goto out_iucv;
 	}
 
-	rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group);
-	if (rc) {
-		PRINT_ERR("NETIUCV: failed to add driver attributes.\n");
-		IUCV_DBF_TEXT_(setup, 2,
-			       "ret %d - netiucv_drv_attr_group\n", rc);
-		goto out_driver;
-	}
 	netiucv_banner();
 	return rc;
 
-out_driver:
-	driver_unregister(&netiucv_driver);
 out_iucv:
 	iucv_unregister(&netiucv_handler, 1);
 out_dbf:
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index ff999ff0b627..62606ce26e55 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -3890,7 +3890,7 @@ qeth_verify_vlan_dev(struct net_device *dev, struct qeth_card *card)
 			break;
 		}
 	}
-	if (rc && !(VLAN_DEV_INFO(dev)->real_dev->priv == (void *)card))
+	if (rc && !(vlan_dev_info(dev)->real_dev->priv == (void *)card))
 		return 0;
 
 #endif
@@ -3930,7 +3930,7 @@ qeth_get_card_from_dev(struct net_device *dev)
 		card = (struct qeth_card *)dev->priv;
 	else if (rc == QETH_VLAN_CARD)
 		card = (struct qeth_card *)
-			VLAN_DEV_INFO(dev)->real_dev->priv;
+			vlan_dev_info(dev)->real_dev->priv;
 
 	QETH_DBF_TEXT_(trace, 4, "%d", rc);
 	return card ;
@@ -8340,7 +8340,7 @@ qeth_arp_constructor(struct neighbour *neigh)
 	neigh->parms = neigh_parms_clone(parms);
 	rcu_read_unlock();
 
-	neigh->type = inet_addr_type(*(__be32 *) neigh->primary_key);
+	neigh->type = inet_addr_type(&init_net, *(__be32 *) neigh->primary_key);
 	neigh->nud_state = NUD_NOARP;
 	neigh->ops = arp_direct_ops;
 	neigh->output = neigh->ops->queue_xmit;
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
index f1ff165a5e05..46ecd03a597e 100644
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -146,7 +146,7 @@ qeth_procfile_seq_show(struct seq_file *s, void *it)
 	return 0;
 }
 
-static struct seq_operations qeth_procfile_seq_ops = {
+static const struct seq_operations qeth_procfile_seq_ops = {
 	.start = qeth_procfile_seq_start,
 	.stop  = qeth_procfile_seq_stop,
 	.next  = qeth_procfile_seq_next,
@@ -264,7 +264,7 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
 	return 0;
 }
 
-static struct seq_operations qeth_perf_procfile_seq_ops = {
+static const struct seq_operations qeth_perf_procfile_seq_ops = {
 	.start = qeth_procfile_seq_start,
 	.stop  = qeth_procfile_seq_stop,
 	.next  = qeth_procfile_seq_next,
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 47bb47b48581..8735a415a116 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -42,7 +42,7 @@ MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
 static struct iucv_path *smsg_path;
 
 static DEFINE_SPINLOCK(smsg_list_lock);
-static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list);
+static LIST_HEAD(smsg_list);
 
 static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
 static void smsg_message_pending(struct iucv_path *, struct iucv_message *);
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 00118499018b..874b55ed00a3 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -844,8 +844,6 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
 	unit->sysfs_device.release = zfcp_sysfs_unit_release;
 	dev_set_drvdata(&unit->sysfs_device, unit);
 
-	init_waitqueue_head(&unit->scsi_scan_wq);
-
 	/* mark unit unusable as long as sysfs registration is not complete */
 	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
 
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index e01cbf152a81..edc5015e920d 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -52,6 +52,9 @@ static struct ccw_driver zfcp_ccw_driver = {
 	.set_offline = zfcp_ccw_set_offline,
 	.notify      = zfcp_ccw_notify,
 	.shutdown    = zfcp_ccw_shutdown,
+	.driver = {
+		.groups = zfcp_driver_attr_groups,
+	},
 };
 
 MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
@@ -120,6 +123,9 @@ zfcp_ccw_remove(struct ccw_device *ccw_device)
 
 	list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) {
 		list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) {
+			if (atomic_test_mask(ZFCP_STATUS_UNIT_REGISTERED,
+				&unit->status))
+				scsi_remove_device(unit->device);
 			zfcp_unit_dequeue(unit);
 		}
 		zfcp_port_dequeue(port);
@@ -251,16 +257,7 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
 int __init
 zfcp_ccw_register(void)
 {
-	int retval;
-
-	retval = ccw_driver_register(&zfcp_ccw_driver);
-	if (retval)
-		goto out;
-	retval = zfcp_sysfs_driver_create_files(&zfcp_ccw_driver.driver);
-	if (retval)
-		ccw_driver_unregister(&zfcp_ccw_driver);
- out:
-	return retval;
+	return ccw_driver_register(&zfcp_ccw_driver);
 }
 
 /**
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index ffa3bf756943..701046c9bb33 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -161,12 +161,6 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
 		   (fsf_req->fsf_command == FSF_QTCB_OPEN_LUN)) {
 		strncpy(rec->tag2, "open", ZFCP_DBF_TAG_SIZE);
 		level = 4;
-	} else if ((prot_status_qual->doubleword[0] != 0) ||
-		   (prot_status_qual->doubleword[1] != 0) ||
-		   (fsf_status_qual->doubleword[0] != 0) ||
-		   (fsf_status_qual->doubleword[1] != 0)) {
-		strncpy(rec->tag2, "qual", ZFCP_DBF_TAG_SIZE);
-		level = 3;
 	} else {
 		strncpy(rec->tag2, "norm", ZFCP_DBF_TAG_SIZE);
 		level = 6;
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index e268f79bdbd2..9e9f6c1e4e5d 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -118,7 +118,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
 
 #define ZFCP_SBAL_TIMEOUT               (5*HZ)
 
-#define ZFCP_TYPE2_RECOVERY_TIME        (8*HZ)
+#define ZFCP_TYPE2_RECOVERY_TIME        8	/* seconds */
 
 /* queue polling (values in microseconds) */
 #define ZFCP_MAX_INPUT_THRESHOLD 	5000	/* FIXME: tune */
@@ -139,7 +139,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
 #define ZFCP_STATUS_READS_RECOM		        FSF_STATUS_READS_RECOM
 
 /* Do 1st retry in 1 second, then double the timeout for each following retry */
-#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP	100
+#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP	1
 #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES	7
 
 /* timeout value for "default timer" for fsf requests */
@@ -983,10 +983,6 @@ struct zfcp_unit {
         struct scsi_device     *device;        /* scsi device struct pointer */
 	struct zfcp_erp_action erp_action;     /* pending error recovery */
         atomic_t               erp_counter;
-	wait_queue_head_t      scsi_scan_wq;   /* can be used to wait until
-						  all scsi_scan_target
-						  requests have been
-						  completed. */
 };
 
 /* FSF request */
@@ -1127,6 +1123,20 @@ zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id)
 	return NULL;
 }
 
+static inline struct zfcp_fsf_req *
+zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req)
+{
+	struct zfcp_fsf_req *request;
+	unsigned int idx;
+
+	for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) {
+		list_for_each_entry(request, &adapter->req_list[idx], list)
+			if (request == req)
+				return request;
+	}
+	return NULL;
+}
+
 /*
  *  functions needed for reference/usage counting
  */
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 07fa824d179f..2dc8110ebf74 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -131,7 +131,7 @@ static void zfcp_close_qdio(struct zfcp_adapter *adapter)
 	debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
 	while (qdio_shutdown(adapter->ccw_device,
 			     QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
-		msleep(1000);
+		ssleep(1);
 	debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
 
 	/* cleanup used outbound sbals */
@@ -456,7 +456,7 @@ zfcp_test_link(struct zfcp_port *port)
 
 	zfcp_port_get(port);
 	retval = zfcp_erp_adisc(port);
-	if (retval != 0) {
+	if (retval != 0 && retval != -EBUSY) {
 		zfcp_port_put(port);
 		ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx "
 				"on adapter %s\n ", port->wwpn,
@@ -846,7 +846,8 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
 	if (erp_action->fsf_req) {
 		/* take lock to ensure that request is not deleted meanwhile */
 		spin_lock(&adapter->req_list_lock);
-		if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) {
+		if (zfcp_reqlist_find_safe(adapter, erp_action->fsf_req) &&
+		    erp_action->fsf_req->erp_action == erp_action) {
 			/* fsf_req still exists */
 			debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
 			debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
@@ -1285,7 +1286,7 @@ zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
 	 * note: no lock in subsequent strategy routines
 	 * (this allows these routine to call schedule, e.g.
 	 * kmalloc with such flags or qdio_initialize & friends)
-	 * Note: in case of timeout, the seperate strategies will fail
+	 * Note: in case of timeout, the separate strategies will fail
 	 * anyhow. No need for a special action. Even worse, a nameserver
 	 * failure would not wake up waiting ports without the call.
 	 */
@@ -1609,7 +1610,6 @@ static void zfcp_erp_scsi_scan(struct work_struct *work)
 	scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
 			 unit->scsi_lun, 0);
 	atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
-	wake_up(&unit->scsi_scan_wq);
 	zfcp_unit_put(unit);
 	kfree(p);
 }
@@ -1900,7 +1900,7 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action)
 		ZFCP_LOG_INFO("Waiting to allow the adapter %s "
 			      "to recover itself\n",
 			      zfcp_get_busid_by_adapter(adapter));
-		msleep(jiffies_to_msecs(ZFCP_TYPE2_RECOVERY_TIME));
+		ssleep(ZFCP_TYPE2_RECOVERY_TIME);
 	}
 
 	return retval;
@@ -2080,7 +2080,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
 	debug_text_event(adapter->erp_dbf, 3, "qdio_down1a");
 	while (qdio_shutdown(adapter->ccw_device,
 			     QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
-		msleep(1000);
+		ssleep(1);
 	debug_text_event(adapter->erp_dbf, 3, "qdio_down1b");
 
  failed_qdio_establish:
@@ -2165,7 +2165,7 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
 		ZFCP_LOG_DEBUG("host connection still initialising... "
 			       "waiting and retrying...\n");
 		/* sleep a little bit before retry */
-		msleep(jiffies_to_msecs(sleep));
+		ssleep(sleep);
 		sleep *= 2;
 	}
 
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 8534cf09546c..06b1079b7f3d 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -27,8 +27,7 @@
 extern struct zfcp_data zfcp_data;
 
 /******************************** SYSFS  *************************************/
-extern int  zfcp_sysfs_driver_create_files(struct device_driver *);
-extern void zfcp_sysfs_driver_remove_files(struct device_driver *);
+extern struct attribute_group *zfcp_driver_attr_groups[];
 extern int  zfcp_sysfs_adapter_create_files(struct device *);
 extern void zfcp_sysfs_adapter_remove_files(struct device *);
 extern int  zfcp_sysfs_port_create_files(struct device *, u32);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index ff866ebd44ac..0dff05840ee2 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -502,7 +502,7 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
 		fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR;
 		break;
 	case FSF_SQ_NO_RECOM:
-		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a"
+		ZFCP_LOG_NORMAL("bug: No recommendation could be given for a "
 				"problem on the adapter %s "
 				"Stopping all operations on this adapter. ",
 				zfcp_get_busid_by_adapter(fsf_req->adapter));
@@ -813,7 +813,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
 	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 
 	if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
-		ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
+		ZFCP_LOG_NORMAL("bug: Reopen port indication received for "
 				"nonexisting port with d_id 0x%06x on "
 				"adapter %s. Ignored.\n",
 				status_buffer->d_id & ZFCP_DID_MASK,
@@ -1116,6 +1116,10 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
 		goto out;
 	}
 
+	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
+			&unit->status)))
+		goto unit_blocked;
+
 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
         sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
         sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -1131,22 +1135,13 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
 
 	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
 	retval = zfcp_fsf_req_send(fsf_req);
-	if (retval) {
-		ZFCP_LOG_INFO("error: Failed to send abort command request "
-			      "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
-			      zfcp_get_busid_by_adapter(adapter),
-			      unit->port->wwpn, unit->fcp_lun);
+	if (!retval)
+		goto out;
+
+ unit_blocked:
 		zfcp_fsf_req_free(fsf_req);
 		fsf_req = NULL;
-		goto out;
-	}
 
-	ZFCP_LOG_DEBUG("Abort FCP Command request initiated "
-		       "(adapter%s, port d_id=0x%06x, "
-		       "unit x%016Lx, old_req_id=0x%lx)\n",
-		       zfcp_get_busid_by_adapter(adapter),
-		       unit->port->d_id,
-		       unit->fcp_lun, old_req_id);
  out:
 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
 	return fsf_req;
@@ -1164,8 +1159,8 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
 {
 	int retval = -EINVAL;
 	struct zfcp_unit *unit;
-	unsigned char status_qual =
-	    new_fsf_req->qtcb->header.fsf_status_qual.word[0];
+	union fsf_status_qual *fsf_stat_qual =
+		&new_fsf_req->qtcb->header.fsf_status_qual;
 
 	if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
 		/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
@@ -1178,7 +1173,7 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
 	switch (new_fsf_req->qtcb->header.fsf_status) {
 
 	case FSF_PORT_HANDLE_NOT_VALID:
-		if (status_qual >> 4 != status_qual % 0xf) {
+		if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
 			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
 					 "fsf_s_phand_nv0");
 			/*
@@ -1207,8 +1202,7 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
 		break;
 
 	case FSF_LUN_HANDLE_NOT_VALID:
-		if (status_qual >> 4 != status_qual % 0xf) {
-			/* 2 */
+		if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) {
 			debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
 					 "fsf_s_lhand_nv0");
 			/*
@@ -1674,6 +1668,12 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
                 goto failed_req;
 	}
 
+	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
+			&els->port->status))) {
+		ret = -EBUSY;
+		goto port_blocked;
+	}
+
 	sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
         if (zfcp_use_one_sbal(els->req, els->req_count,
                               els->resp, els->resp_count)){
@@ -1755,6 +1755,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
 		       "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
 	goto out;
 
+ port_blocked:
  failed_send:
 	zfcp_fsf_req_free(fsf_req);
 
@@ -2280,7 +2281,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
 				     &lock_flags, &fsf_req);
 	if (retval) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
-			      "exchange port data request for"
+			      "exchange port data request for "
 			      "the adapter %s.\n",
 			      zfcp_get_busid_by_adapter(adapter));
 		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
@@ -2339,7 +2340,7 @@ zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
 				0, NULL, &lock_flags, &fsf_req);
 	if (retval) {
 		ZFCP_LOG_INFO("error: Out of resources. Could not create an "
-			      "exchange port data request for"
+			      "exchange port data request for "
 			      "the adapter %s.\n",
 			      zfcp_get_busid_by_adapter(adapter));
 		write_unlock_irqrestore(&adapter->request_queue.queue_lock,
@@ -3592,6 +3593,12 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
 		goto failed_req_create;
 	}
 
+	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
+			&unit->status))) {
+		retval = -EBUSY;
+		goto unit_blocked;
+	}
+
 	zfcp_unit_get(unit);
 	fsf_req->unit = unit;
 
@@ -3732,6 +3739,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
  send_failed:
  no_fit:
  failed_scsi_cmnd:
+ unit_blocked:
 	zfcp_unit_put(unit);
 	zfcp_fsf_req_free(fsf_req);
 	fsf_req = NULL;
@@ -3766,6 +3774,10 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
 		goto out;
 	}
 
+	if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED,
+			&unit->status)))
+		goto unit_blocked;
+
 	/*
 	 * Used to decide on proper handler in the return path,
 	 * could be either zfcp_fsf_send_fcp_command_task_handler or
@@ -3799,25 +3811,13 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
 
 	zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
 	retval = zfcp_fsf_req_send(fsf_req);
-	if (retval) {
-		ZFCP_LOG_INFO("error: Could not send an FCP-command (task "
-			      "management) on adapter %s, port 0x%016Lx for "
-			      "unit LUN 0x%016Lx\n",
-			      zfcp_get_busid_by_adapter(adapter),
-			      unit->port->wwpn,
-			      unit->fcp_lun);
-		zfcp_fsf_req_free(fsf_req);
-		fsf_req = NULL;
+	if (!retval)
 		goto out;
-	}
 
-	ZFCP_LOG_TRACE("Send FCP Command (task management function) initiated "
-		       "(adapter %s, port 0x%016Lx, unit 0x%016Lx, "
-		       "tm_flags=0x%x)\n",
-		       zfcp_get_busid_by_adapter(adapter),
-		       unit->port->wwpn,
-		       unit->fcp_lun,
-		       tm_flags);
+ unit_blocked:
+	zfcp_fsf_req_free(fsf_req);
+	fsf_req = NULL;
+
  out:
 	write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
 	return fsf_req;
@@ -4224,10 +4224,10 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
 
 		ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n",
 			       fcp_rsp_iu->fcp_sns_len);
-		memcpy(&scpnt->sense_buffer,
+		memcpy(scpnt->sense_buffer,
 		       zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len);
 		ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
-			      (void *) &scpnt->sense_buffer, sns_len);
+			      (void *)scpnt->sense_buffer, sns_len);
 	}
 
 	/* check for overrun */
@@ -4725,7 +4725,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
 	/* allocate new FSF request */
 	fsf_req = zfcp_fsf_req_alloc(pool, req_flags);
 	if (unlikely(NULL == fsf_req)) {
-		ZFCP_LOG_DEBUG("error: Could not put an FSF request into"
+		ZFCP_LOG_DEBUG("error: Could not put an FSF request into "
 			       "the outbound (send) queue.\n");
 		ret = -ENOMEM;
 		goto failed_fsf_req;
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 51d92b196ee7..22fdc17e0d0e 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -529,7 +529,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
 
 
 /**
- * zfcp_qdio_sbale_fill - set address and lenght in current SBALE
+ * zfcp_qdio_sbale_fill - set address and length in current SBALE
  *	on request_queue
  */
 static void
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index abae2027f7e5..b9daf5c05862 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -51,7 +51,6 @@ struct zfcp_data zfcp_data = {
 		.queuecommand		= zfcp_scsi_queuecommand,
 		.eh_abort_handler	= zfcp_scsi_eh_abort_handler,
 		.eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
-		.eh_bus_reset_handler	= zfcp_scsi_eh_host_reset_handler,
 		.eh_host_reset_handler	= zfcp_scsi_eh_host_reset_handler,
 		.can_queue		= 4096,
 		.this_id		= -1,
@@ -181,9 +180,6 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
 
 	if (unit) {
 		zfcp_erp_wait(unit->port->adapter);
-		wait_event(unit->scsi_scan_wq,
-			   atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
-					    &unit->status) == 0);
 		atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
 		sdpnt->hostdata = NULL;
 		unit->device = NULL;
@@ -262,8 +258,9 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
 		goto out;
 	}
 
-	if (unlikely(
-	     !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) {
+	tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer,
+					     ZFCP_REQ_AUTO_CLEANUP);
+	if (unlikely(tmp == -EBUSY)) {
 		ZFCP_LOG_DEBUG("adapter %s not ready or unit 0x%016Lx "
 			       "on port 0x%016Lx in recovery\n",
 			       zfcp_get_busid_by_unit(unit),
@@ -272,9 +269,6 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
 		goto out;
 	}
 
-	tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer,
-					     ZFCP_REQ_AUTO_CLEANUP);
-
 	if (unlikely(tmp < 0)) {
 		ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n");
 		retval = SCSI_MLQUEUE_HOST_BUSY;
@@ -459,7 +453,9 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
 		retval = SUCCESS;
 		goto out;
 	}
-	ZFCP_LOG_NORMAL("resetting unit 0x%016Lx\n", unit->fcp_lun);
+	ZFCP_LOG_NORMAL("resetting unit 0x%016Lx on port 0x%016Lx, adapter %s\n",
+			unit->fcp_lun, unit->port->wwpn,
+			zfcp_get_busid_by_adapter(unit->port->adapter));
 
 	/*
 	 * If we do not know whether the unit supports 'logical unit reset'
@@ -542,7 +538,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
 }
 
 /**
- * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
+ * zfcp_scsi_eh_host_reset_handler - handler for host reset
  */
 static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 {
@@ -552,8 +548,10 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 	unit = (struct zfcp_unit*) scpnt->device->hostdata;
 	adapter = unit->port->adapter;
 
-	ZFCP_LOG_NORMAL("host/bus reset because of problems with "
-			"unit 0x%016Lx\n", unit->fcp_lun);
+	ZFCP_LOG_NORMAL("host reset because of problems with "
+		"unit 0x%016Lx on port 0x%016Lx, adapter %s\n",
+		unit->fcp_lun, unit->port->wwpn,
+		zfcp_get_busid_by_adapter(unit->port->adapter));
 
 	zfcp_erp_adapter_reopen(adapter, 0);
 	zfcp_erp_wait(adapter);
diff --git a/drivers/s390/scsi/zfcp_sysfs_driver.c b/drivers/s390/scsi/zfcp_sysfs_driver.c
index 005e62f8593b..651edd58906a 100644
--- a/drivers/s390/scsi/zfcp_sysfs_driver.c
+++ b/drivers/s390/scsi/zfcp_sysfs_driver.c
@@ -98,28 +98,9 @@ static struct attribute_group zfcp_driver_attr_group = {
 	.attrs = zfcp_driver_attrs,
 };
 
-/**
- * zfcp_sysfs_create_driver_files - create sysfs driver files
- * @dev: pointer to belonging device
- *
- * Create all sysfs attributes of the zfcp device driver
- */
-int
-zfcp_sysfs_driver_create_files(struct device_driver *drv)
-{
-	return sysfs_create_group(&drv->kobj, &zfcp_driver_attr_group);
-}
-
-/**
- * zfcp_sysfs_remove_driver_files - remove sysfs driver files
- * @dev: pointer to belonging device
- *
- * Remove all sysfs attributes of the zfcp device driver
- */
-void
-zfcp_sysfs_driver_remove_files(struct device_driver *drv)
-{
-	sysfs_remove_group(&drv->kobj, &zfcp_driver_attr_group);
-}
+struct attribute_group *zfcp_driver_attr_groups[] = {
+	&zfcp_driver_attr_group,
+	NULL,
+};
 
 #undef ZFCP_LOG_AREA
diff --git a/drivers/scsi/.gitignore b/drivers/scsi/.gitignore
index b385af314356..c89ae9a04399 100644
--- a/drivers/scsi/.gitignore
+++ b/drivers/scsi/.gitignore
@@ -1,3 +1 @@
 53c700_d.h
-53c7xx_d.h
-53c7xx_u.h
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index afb262b4be15..b4912d1cee2a 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1990,7 +1990,6 @@ static struct scsi_host_template driver_template = {
 	.max_sectors		= TW_MAX_SECTORS,
 	.cmd_per_lun		= TW_MAX_CMDS_PER_LUN,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 	.shost_attrs		= twa_host_attrs,
 	.emulated		= 1
 };
@@ -2010,6 +2009,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
 	}
 
 	pci_set_master(pdev);
+	pci_try_set_mwi(pdev);
 
 	if (pci_set_dma_mask(pdev, DMA_64BIT_MASK)
 	    || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 59716ebeb10c..d09532162217 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -2261,7 +2261,6 @@ static struct scsi_host_template driver_template = {
 	.max_sectors		= TW_MAX_SECTORS,
 	.cmd_per_lun		= TW_MAX_CMDS_PER_LUN,	
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 	.shost_attrs		= tw_host_attrs,
 	.emulated		= 1
 };
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index 71ff3fbfce12..f4c4fe90240a 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -608,7 +608,8 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
 			scsi_print_sense("53c700", SCp);
 
 #endif
-			dma_unmap_single(hostdata->dev, slot->dma_handle, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
+			dma_unmap_single(hostdata->dev, slot->dma_handle,
+					 SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
 			/* restore the old result if the request sense was
 			 * successful */
 			if (result == 0)
@@ -1010,7 +1011,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
 				cmnd[1] = (SCp->device->lun & 0x7) << 5;
 				cmnd[2] = 0;
 				cmnd[3] = 0;
-				cmnd[4] = sizeof(SCp->sense_buffer);
+				cmnd[4] = SCSI_SENSE_BUFFERSIZE;
 				cmnd[5] = 0;
 				/* Here's a quiet hack: the
 				 * REQUEST_SENSE command is six bytes,
@@ -1024,14 +1025,14 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
 				SCp->cmd_len = 6; /* command length for
 						   * REQUEST_SENSE */
 				slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE);
-				slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
-				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
+				slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | SCSI_SENSE_BUFFERSIZE);
 				slot->SG[0].pAddr = bS_to_host(slot->dma_handle);
 				slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
 				slot->SG[1].pAddr = 0;
 				slot->resume_offset = hostdata->pScript;
 				dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG[0])*2, DMA_TO_DEVICE);
-				dma_cache_sync(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
+				dma_cache_sync(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
 
 				/* queue the command for reissue */
 				slot->state = NCR_700_SLOT_QUEUED;
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 49e1ffa4b2ff..4d3ebb1af490 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -2947,7 +2947,7 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
 		}
 	}
 	memcpy(CCB->CDB, CDB, CDB_Length);
-	CCB->SenseDataLength = sizeof(Command->sense_buffer);
+	CCB->SenseDataLength = SCSI_SENSE_BUFFERSIZE;
 	CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, Command->sense_buffer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE);
 	CCB->Command = Command;
 	Command->scsi_done = CompletionRoutine;
@@ -3575,7 +3575,6 @@ static struct scsi_host_template Bus_Logic_template = {
 	.unchecked_isa_dma = 1,
 	.max_sectors = 128,
 	.use_clustering = ENABLE_CLUSTERING,
-	.use_sg_chaining = ENABLE_SG_CHAINING,
 };
 
 /*
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 184c7ae78519..14fc7f39e83e 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -341,11 +341,11 @@ config ISCSI_TCP
 	 The userspace component needed to initialize the driver, documentation,
 	 and sample configuration files can be found here:
 
-	 http://linux-iscsi.sf.net
+	 http://open-iscsi.org
 
 config SGIWD93_SCSI
 	tristate "SGI WD93C93 SCSI Driver"
-	depends on SGI_IP22 && SCSI
+	depends on SGI_HAS_WD93 && SCSI
   	help
 	  If you have a Western Digital WD93 SCSI controller on
 	  an SGI MIPS system, say Y.  Otherwise, say N.
@@ -573,10 +573,10 @@ config SCSI_ARCMSR_AER
 source "drivers/scsi/megaraid/Kconfig.megaraid"
 
 config SCSI_HPTIOP
-	tristate "HighPoint RocketRAID 3xxx Controller support"
+	tristate "HighPoint RocketRAID 3xxx/4xxx Controller support"
 	depends on SCSI && PCI
 	help
-	  This option enables support for HighPoint RocketRAID 3xxx
+	  This option enables support for HighPoint RocketRAID 3xxx/4xxx
 	  controllers.
 
 	  To compile this driver as a module, choose M here; the module
@@ -1288,17 +1288,6 @@ config SCSI_PAS16
 	  To compile this driver as a module, choose M here: the
 	  module will be called pas16.
 
-config SCSI_PSI240I
-	tristate "PSI240i support"
-	depends on ISA && SCSI
-	help
-	  This is support for the PSI240i EIDE interface card which acts as a
-	  SCSI host adapter.  Please read the SCSI-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called psi240i.
-
 config SCSI_QLOGIC_FAS
 	tristate "Qlogic FAS SCSI support"
 	depends on ISA && SCSI
@@ -1359,21 +1348,6 @@ config SCSI_LPFC
           This lpfc driver supports the Emulex LightPulse
           Family of Fibre Channel PCI host adapters.
 
-config SCSI_SEAGATE
-	tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
-	depends on X86 && ISA && SCSI
-	select CHECK_SIGNATURE
-	---help---
-	  These are 8-bit SCSI controllers; the ST-01 is also supported by
-	  this driver.  It is explained in section 3.9 of the SCSI-HOWTO,
-	  available from <http://www.tldp.org/docs.html#howto>.  If it
-	  doesn't work out of the box, you may have to change some macros at
-	  compiletime, which are described in <file:drivers/scsi/seagate.c>.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called seagate.
-
-# definitely looks not 64bit safe:
 config SCSI_SIM710
 	tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
 	depends on (EISA || MCA) && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 2e6129f13d38..93e1428d03fc 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -16,9 +16,8 @@
 
 CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF
 CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
-CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
 
-subdir-$(CONFIG_PCMCIA)		+= pcmcia
+obj-$(CONFIG_PCMCIA)		+= pcmcia/
 
 obj-$(CONFIG_SCSI)		+= scsi_mod.o
 obj-$(CONFIG_SCSI_TGT)		+= scsi_tgt.o
@@ -59,7 +58,6 @@ obj-$(CONFIG_MVME16x_SCSI)	+= 53c700.o	mvme16x_scsi.o
 obj-$(CONFIG_BVME6000_SCSI)	+= 53c700.o	bvme6000_scsi.o
 obj-$(CONFIG_SCSI_SIM710)	+= 53c700.o	sim710.o
 obj-$(CONFIG_SCSI_ADVANSYS)	+= advansys.o
-obj-$(CONFIG_SCSI_PSI240I)	+= psi240i.o
 obj-$(CONFIG_SCSI_BUSLOGIC)	+= BusLogic.o
 obj-$(CONFIG_SCSI_DPT_I2O)	+= dpt_i2o.o
 obj-$(CONFIG_SCSI_U14_34F)	+= u14-34f.o
@@ -90,7 +88,6 @@ obj-$(CONFIG_SCSI_QLA_FC)	+= qla2xxx/
 obj-$(CONFIG_SCSI_QLA_ISCSI)	+= qla4xxx/
 obj-$(CONFIG_SCSI_LPFC)		+= lpfc/
 obj-$(CONFIG_SCSI_PAS16)	+= pas16.o
-obj-$(CONFIG_SCSI_SEAGATE)	+= seagate.o
 obj-$(CONFIG_SCSI_T128)		+= t128.o
 obj-$(CONFIG_SCSI_DMX3191D)	+= dmx3191d.o
 obj-$(CONFIG_SCSI_DTC3280)	+= dtc.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 2597209183d0..eeddbd19eba5 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -295,16 +295,16 @@ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
 	 * various queues are valid.
 	 */
 
-	if (cmd->use_sg) {
-		cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+	if (scsi_bufflen(cmd)) {
+		cmd->SCp.buffer = scsi_sglist(cmd);
+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
 	} else {
 		cmd->SCp.buffer = NULL;
 		cmd->SCp.buffers_residual = 0;
-		cmd->SCp.ptr = (char *) cmd->request_buffer;
-		cmd->SCp.this_residual = cmd->request_bufflen;
+		cmd->SCp.ptr = NULL;
+		cmd->SCp.this_residual = 0;
 	}
 }
 
@@ -932,7 +932,7 @@ static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags)
  *	@instance: adapter to remove
  */
 
-static void __devexit NCR5380_exit(struct Scsi_Host *instance)
+static void NCR5380_exit(struct Scsi_Host *instance)
 {
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 
@@ -975,14 +975,14 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 		case WRITE_6:
 		case WRITE_10:
 			hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
-			hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+			hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
 			hostdata->pendingw++;
 			break;
 		case READ:
 		case READ_6:
 		case READ_10:
 			hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
-			hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+			hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
 			hostdata->pendingr++;
 			break;
 	}
@@ -1157,16 +1157,17 @@ static void NCR5380_main(struct work_struct *work)
  *	Locks: takes the needed instance locks
  */
 
-static irqreturn_t NCR5380_intr(int irq, void *dev_id) 
+static irqreturn_t NCR5380_intr(int dummy, void *dev_id)
 {
 	NCR5380_local_declare();
-	struct Scsi_Host *instance = (struct Scsi_Host *)dev_id;
+	struct Scsi_Host *instance = dev_id;
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 	int done;
 	unsigned char basr;
 	unsigned long flags;
 
-	dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq));
+	dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n",
+		instance->irq));
 
 	do {
 		done = 1;
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index 137d065db3da..6961f78742ae 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -1065,7 +1065,6 @@ static struct scsi_host_template driver_template =
      .cmd_per_lun       	= 1			/* commands per lun */, 
      .unchecked_isa_dma 	= 1			/* unchecked_isa_dma */,
      .use_clustering    	= ENABLE_CLUSTERING,
-     .use_sg_chaining           = ENABLE_SG_CHAINING,
 };
 
 #include "scsi_module.c"
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index d3a6d15fb77a..f608d4a1d6da 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -1071,7 +1071,6 @@ static struct scsi_host_template inia100_template = {
 	.sg_tablesize		= SG_ALL,
 	.cmd_per_lun 		= 1,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 };
 
 static int __devinit inia100_probe_one(struct pci_dev *pdev,
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index b7c5385e2efe..23f27c9c9895 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -73,18 +73,9 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 	}
 
 	if (!dir_in) {
-	    /* copy to bounce buffer for a write */
-	    if (cmd->use_sg)
-#if 0
-		panic ("scsi%ddma: incomplete s/g support",
-		       instance->host_no);
-#else
+		/* copy to bounce buffer for a write */
 		memcpy (HDATA(instance)->dma_bounce_buffer,
 			cmd->SCp.ptr, cmd->SCp.this_residual);
-#endif
-	    else
-		memcpy (HDATA(instance)->dma_bounce_buffer,
-			cmd->request_buffer, cmd->request_bufflen);
 	}
     }
 
@@ -144,30 +135,13 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 
     /* copy from a bounce buffer, if necessary */
     if (status && HDATA(instance)->dma_bounce_buffer) {
-	if (SCpnt && SCpnt->use_sg) {
-#if 0
-	    panic ("scsi%d: incomplete s/g support",
-		   instance->host_no);
-#else
-	    if( HDATA(instance)->dma_dir )
+	if( HDATA(instance)->dma_dir )
 		memcpy (SCpnt->SCp.ptr, 
 			HDATA(instance)->dma_bounce_buffer,
 			SCpnt->SCp.this_residual);
-	    kfree (HDATA(instance)->dma_bounce_buffer);
-	    HDATA(instance)->dma_bounce_buffer = NULL;
-	    HDATA(instance)->dma_bounce_len = 0;
-	    
-#endif
-	} else {
-	    if (HDATA(instance)->dma_dir && SCpnt)
-		memcpy (SCpnt->request_buffer,
-			HDATA(instance)->dma_bounce_buffer,
-			SCpnt->request_bufflen);
-
-	    kfree (HDATA(instance)->dma_bounce_buffer);
-	    HDATA(instance)->dma_bounce_buffer = NULL;
-	    HDATA(instance)->dma_bounce_len = 0;
-	}
+	kfree (HDATA(instance)->dma_bounce_buffer);
+	HDATA(instance)->dma_bounce_buffer = NULL;
+	HDATA(instance)->dma_bounce_len = 0;
     }
 }
 
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index 796f1c4d772e..d7255c8bf281 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -70,12 +70,8 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 
 	if (!dir_in) {
 	    /* copy to bounce buffer for a write */
-	    if (cmd->use_sg) {
-		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
-			cmd->SCp.ptr, cmd->SCp.this_residual);
-	    } else
-		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
-			cmd->request_buffer, cmd->request_bufflen);
+	    memcpy (HDATA(a3000_host)->dma_bounce_buffer,
+		cmd->SCp.ptr, cmd->SCp.this_residual);
 	}
 
 	addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
@@ -146,7 +142,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 
     /* copy from a bounce buffer, if necessary */
     if (status && HDATA(instance)->dma_bounce_buffer) {
-	if (SCpnt && SCpnt->use_sg) {
+	if (SCpnt) {
 	    if (HDATA(instance)->dma_dir && SCpnt)
 		memcpy (SCpnt->SCp.ptr,
 			HDATA(instance)->dma_bounce_buffer,
@@ -155,11 +151,6 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 	    HDATA(instance)->dma_bounce_buffer = NULL;
 	    HDATA(instance)->dma_bounce_len = 0;
 	} else {
-	    if (HDATA(instance)->dma_dir && SCpnt)
-		memcpy (SCpnt->request_buffer,
-			HDATA(instance)->dma_bounce_buffer,
-			SCpnt->request_bufflen);
-
 	    kfree (HDATA(instance)->dma_bounce_buffer);
 	    HDATA(instance)->dma_bounce_buffer = NULL;
 	    HDATA(instance)->dma_bounce_len = 0;
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index a77ab8d693d4..d7235f42cf5f 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -31,9 +31,9 @@
 #include <linux/slab.h>
 #include <linux/completion.h>
 #include <linux/blkdev.h>
-#include <linux/dma-mapping.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
+#include <linux/highmem.h> /* For flush_kernel_dcache_page */
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -56,54 +56,54 @@
 /*
  *	Sense codes
  */
- 
-#define SENCODE_NO_SENSE                        0x00
-#define SENCODE_END_OF_DATA                     0x00
-#define SENCODE_BECOMING_READY                  0x04
-#define SENCODE_INIT_CMD_REQUIRED               0x04
-#define SENCODE_PARAM_LIST_LENGTH_ERROR         0x1A
-#define SENCODE_INVALID_COMMAND                 0x20
-#define SENCODE_LBA_OUT_OF_RANGE                0x21
-#define SENCODE_INVALID_CDB_FIELD               0x24
-#define SENCODE_LUN_NOT_SUPPORTED               0x25
-#define SENCODE_INVALID_PARAM_FIELD             0x26
-#define SENCODE_PARAM_NOT_SUPPORTED             0x26
-#define SENCODE_PARAM_VALUE_INVALID             0x26
-#define SENCODE_RESET_OCCURRED                  0x29
-#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET     0x3E
-#define SENCODE_INQUIRY_DATA_CHANGED            0x3F
-#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED     0x39
-#define SENCODE_DIAGNOSTIC_FAILURE              0x40
-#define SENCODE_INTERNAL_TARGET_FAILURE         0x44
-#define SENCODE_INVALID_MESSAGE_ERROR           0x49
-#define SENCODE_LUN_FAILED_SELF_CONFIG          0x4c
-#define SENCODE_OVERLAPPED_COMMAND              0x4E
+
+#define SENCODE_NO_SENSE			0x00
+#define SENCODE_END_OF_DATA			0x00
+#define SENCODE_BECOMING_READY			0x04
+#define SENCODE_INIT_CMD_REQUIRED		0x04
+#define SENCODE_PARAM_LIST_LENGTH_ERROR		0x1A
+#define SENCODE_INVALID_COMMAND			0x20
+#define SENCODE_LBA_OUT_OF_RANGE		0x21
+#define SENCODE_INVALID_CDB_FIELD		0x24
+#define SENCODE_LUN_NOT_SUPPORTED		0x25
+#define SENCODE_INVALID_PARAM_FIELD		0x26
+#define SENCODE_PARAM_NOT_SUPPORTED		0x26
+#define SENCODE_PARAM_VALUE_INVALID		0x26
+#define SENCODE_RESET_OCCURRED			0x29
+#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x3E
+#define SENCODE_INQUIRY_DATA_CHANGED		0x3F
+#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x39
+#define SENCODE_DIAGNOSTIC_FAILURE		0x40
+#define SENCODE_INTERNAL_TARGET_FAILURE		0x44
+#define SENCODE_INVALID_MESSAGE_ERROR		0x49
+#define SENCODE_LUN_FAILED_SELF_CONFIG		0x4c
+#define SENCODE_OVERLAPPED_COMMAND		0x4E
 
 /*
  *	Additional sense codes
  */
- 
-#define ASENCODE_NO_SENSE                       0x00
-#define ASENCODE_END_OF_DATA                    0x05
-#define ASENCODE_BECOMING_READY                 0x01
-#define ASENCODE_INIT_CMD_REQUIRED              0x02
-#define ASENCODE_PARAM_LIST_LENGTH_ERROR        0x00
-#define ASENCODE_INVALID_COMMAND                0x00
-#define ASENCODE_LBA_OUT_OF_RANGE               0x00
-#define ASENCODE_INVALID_CDB_FIELD              0x00
-#define ASENCODE_LUN_NOT_SUPPORTED              0x00
-#define ASENCODE_INVALID_PARAM_FIELD            0x00
-#define ASENCODE_PARAM_NOT_SUPPORTED            0x01
-#define ASENCODE_PARAM_VALUE_INVALID            0x02
-#define ASENCODE_RESET_OCCURRED                 0x00
-#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET    0x00
-#define ASENCODE_INQUIRY_DATA_CHANGED           0x03
-#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED    0x00
-#define ASENCODE_DIAGNOSTIC_FAILURE             0x80
-#define ASENCODE_INTERNAL_TARGET_FAILURE        0x00
-#define ASENCODE_INVALID_MESSAGE_ERROR          0x00
-#define ASENCODE_LUN_FAILED_SELF_CONFIG         0x00
-#define ASENCODE_OVERLAPPED_COMMAND             0x00
+
+#define ASENCODE_NO_SENSE			0x00
+#define ASENCODE_END_OF_DATA			0x05
+#define ASENCODE_BECOMING_READY			0x01
+#define ASENCODE_INIT_CMD_REQUIRED		0x02
+#define ASENCODE_PARAM_LIST_LENGTH_ERROR	0x00
+#define ASENCODE_INVALID_COMMAND		0x00
+#define ASENCODE_LBA_OUT_OF_RANGE		0x00
+#define ASENCODE_INVALID_CDB_FIELD		0x00
+#define ASENCODE_LUN_NOT_SUPPORTED		0x00
+#define ASENCODE_INVALID_PARAM_FIELD		0x00
+#define ASENCODE_PARAM_NOT_SUPPORTED		0x01
+#define ASENCODE_PARAM_VALUE_INVALID		0x02
+#define ASENCODE_RESET_OCCURRED			0x00
+#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET	0x00
+#define ASENCODE_INQUIRY_DATA_CHANGED		0x03
+#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED	0x00
+#define ASENCODE_DIAGNOSTIC_FAILURE		0x80
+#define ASENCODE_INTERNAL_TARGET_FAILURE	0x00
+#define ASENCODE_INVALID_MESSAGE_ERROR		0x00
+#define ASENCODE_LUN_FAILED_SELF_CONFIG		0x00
+#define ASENCODE_OVERLAPPED_COMMAND		0x00
 
 #define BYTE0(x) (unsigned char)(x)
 #define BYTE1(x) (unsigned char)((x) >> 8)
@@ -115,8 +115,8 @@
  *----------------------------------------------------------------------------*/
 /* SCSI inquiry data */
 struct inquiry_data {
-	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type  */
-	u8 inqd_dtq;	/* RMB | Device Type Qualifier  */
+	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type */
+	u8 inqd_dtq;	/* RMB | Device Type Qualifier */
 	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
 	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
 	u8 inqd_len;	/* Additional length (n-4) */
@@ -130,7 +130,7 @@ struct inquiry_data {
 /*
  *              M O D U L E   G L O B A L S
  */
- 
+
 static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
 static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
 static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);
@@ -141,9 +141,10 @@ static char *aac_get_status_string(u32 status);
 
 /*
  *	Non dasd selection is handled entirely in aachba now
- */	
- 
+ */
+
 static int nondasd = -1;
+static int aac_cache = 0;
 static int dacmode = -1;
 
 int aac_commit = -1;
@@ -152,6 +153,8 @@ int aif_timeout = 120;
 
 module_param(nondasd, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
+module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n\tbit 0 - Disable FUA in WRITE SCSI commands\n\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n\tbit 2 - Disable only if Battery not protecting Cache");
 module_param(dacmode, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on");
 module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR);
@@ -179,7 +182,7 @@ MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health che
 
 int aac_check_reset = 1;
 module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter.");
+MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter. a value of -1 forces the reset to adapters programmed to ignore it.");
 
 int expose_physicals = -1;
 module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
@@ -193,12 +196,12 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
 		struct fib *fibptr) {
 	struct scsi_device *device;
 
-	if (unlikely(!scsicmd || !scsicmd->scsi_done )) {
+	if (unlikely(!scsicmd || !scsicmd->scsi_done)) {
 		dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
-                aac_fib_complete(fibptr);
-                aac_fib_free(fibptr);
-                return 0;
-        }
+		aac_fib_complete(fibptr);
+		aac_fib_free(fibptr);
+		return 0;
+	}
 	scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
 	device = scsicmd->device;
 	if (unlikely(!device || !scsi_device_online(device))) {
@@ -240,7 +243,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
 			    FsaNormal,
 			    1, 1,
 			    NULL, NULL);
-	if (status < 0 ) {
+	if (status < 0) {
 		printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
 	} else {
 		struct aac_get_config_status_resp *reply
@@ -264,10 +267,10 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
 			struct aac_commit_config * dinfo;
 			aac_fib_init(fibptr);
 			dinfo = (struct aac_commit_config *) fib_data(fibptr);
-	
+
 			dinfo->command = cpu_to_le32(VM_ContainerConfig);
 			dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
-	
+
 			status = aac_fib_send(ContainerCommand,
 				    fibptr,
 				    sizeof (struct aac_commit_config),
@@ -293,7 +296,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag)
 int aac_get_containers(struct aac_dev *dev)
 {
 	struct fsa_dev_info *fsa_dev_ptr;
-	u32 index; 
+	u32 index;
 	int status = 0;
 	struct fib * fibptr;
 	struct aac_get_container_count *dinfo;
@@ -363,6 +366,7 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne
 	if (buf && transfer_len > 0)
 		memcpy(buf + offset, data, transfer_len);
 
+	flush_kernel_dcache_page(kmap_atomic_to_page(buf - sg->offset));
 	kunmap_atomic(buf - sg->offset, KM_IRQ0);
 
 }
@@ -395,7 +399,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
 			do {
 				*dp++ = (*sp) ? *sp++ : ' ';
 			} while (--count > 0);
-			aac_internal_transfer(scsicmd, d, 
+			aac_internal_transfer(scsicmd, d,
 			  offsetof(struct inquiry_data, inqd_pid), sizeof(d));
 		}
 	}
@@ -431,13 +435,13 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
 	dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
 
 	status = aac_fib_send(ContainerCommand,
-		  cmd_fibcontext, 
+		  cmd_fibcontext,
 		  sizeof (struct aac_get_name),
-		  FsaNormal, 
-		  0, 1, 
-		  (fib_callback) get_container_name_callback, 
+		  FsaNormal,
+		  0, 1,
+		  (fib_callback)get_container_name_callback,
 		  (void *) scsicmd);
-	
+
 	/*
 	 *	Check that the command queued to the controller
 	 */
@@ -445,7 +449,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 		return 0;
 	}
-		
+
 	printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status);
 	aac_fib_complete(cmd_fibcontext);
 	aac_fib_free(cmd_fibcontext);
@@ -652,42 +656,47 @@ struct scsi_inq {
  *	@a:	string to copy from
  *	@b:	string to copy to
  *
- * 	Copy a String from one location to another
+ *	Copy a String from one location to another
  *	without copying \0
  */
 
 static void inqstrcpy(char *a, char *b)
 {
 
-	while(*a != (char)0) 
+	while (*a != (char)0)
 		*b++ = *a++;
 }
 
 static char *container_types[] = {
-        "None",
-        "Volume",
-        "Mirror",
-        "Stripe",
-        "RAID5",
-        "SSRW",
-        "SSRO",
-        "Morph",
-        "Legacy",
-        "RAID4",
-        "RAID10",             
-        "RAID00",             
-        "V-MIRRORS",          
-        "PSEUDO R4",          
+	"None",
+	"Volume",
+	"Mirror",
+	"Stripe",
+	"RAID5",
+	"SSRW",
+	"SSRO",
+	"Morph",
+	"Legacy",
+	"RAID4",
+	"RAID10",
+	"RAID00",
+	"V-MIRRORS",
+	"PSEUDO R4",
 	"RAID50",
 	"RAID5D",
 	"RAID5D0",
 	"RAID1E",
 	"RAID6",
 	"RAID60",
-        "Unknown"
+	"Unknown"
 };
 
-
+char * get_container_type(unsigned tindex)
+{
+	if (tindex >= ARRAY_SIZE(container_types))
+		tindex = ARRAY_SIZE(container_types) - 1;
+	return container_types[tindex];
+}
 
 /* Function: setinqstr
  *
@@ -707,16 +716,21 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
 
 	if (dev->supplement_adapter_info.AdapterTypeText[0]) {
 		char * cp = dev->supplement_adapter_info.AdapterTypeText;
-		int c = sizeof(str->vid);
-		while (*cp && *cp != ' ' && --c)
-			++cp;
-		c = *cp;
-		*cp = '\0';
-		inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
-		  str->vid); 
-		*cp = c;
-		while (*cp && *cp != ' ')
-			++cp;
+		int c;
+		if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C'))
+			inqstrcpy("SMC", str->vid);
+		else {
+			c = sizeof(str->vid);
+			while (*cp && *cp != ' ' && --c)
+				++cp;
+			c = *cp;
+			*cp = '\0';
+			inqstrcpy (dev->supplement_adapter_info.AdapterTypeText,
+				   str->vid);
+			*cp = c;
+			while (*cp && *cp != ' ')
+				++cp;
+		}
 		while (*cp == ' ')
 			++cp;
 		/* last six chars reserved for vol type */
@@ -898,9 +912,8 @@ static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba)
 			    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
 			    0, 0);
 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(cmd->sense_buffer))
-		    ? sizeof(cmd->sense_buffer)
-		    : sizeof(dev->fsa_dev[cid].sense_data));
+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+			     SCSI_SENSE_BUFFERSIZE));
 		cmd->scsi_done(cmd);
 		return 1;
 	}
@@ -981,7 +994,7 @@ static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32
 	aac_fib_init(fib);
 	readcmd = (struct aac_read *) fib_data(fib);
 	readcmd->command = cpu_to_le32(VM_CtBlockRead);
-	readcmd->cid = cpu_to_le16(scmd_id(cmd));
+	readcmd->cid = cpu_to_le32(scmd_id(cmd));
 	readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
 	readcmd->count = cpu_to_le32(count * 512);
 
@@ -1013,7 +1026,8 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
 	writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
 	writecmd->count = cpu_to_le32(count<<9);
 	writecmd->cid = cpu_to_le16(scmd_id(cmd));
-	writecmd->flags = fua ?
+	writecmd->flags = (fua && ((aac_cache & 5) != 1) &&
+	  (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ?
 		cpu_to_le16(IO_TYPE_WRITE|IO_SUREWRITE) :
 		cpu_to_le16(IO_TYPE_WRITE);
 	writecmd->bpTotal = 0;
@@ -1072,7 +1086,7 @@ static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
 	aac_fib_init(fib);
 	writecmd = (struct aac_write *) fib_data(fib);
 	writecmd->command = cpu_to_le32(VM_CtBlockWrite);
-	writecmd->cid = cpu_to_le16(scmd_id(cmd));
+	writecmd->cid = cpu_to_le32(scmd_id(cmd));
 	writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
 	writecmd->count = cpu_to_le32(count * 512);
 	writecmd->sg.count = cpu_to_le32(1);
@@ -1190,6 +1204,15 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
 				  (fib_callback) aac_srb_callback, (void *) cmd);
 }
 
+static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd)
+{
+	if ((sizeof(dma_addr_t) > 4) &&
+	 (num_physpages > (0xFFFFFFFFULL >> PAGE_SHIFT)) &&
+	 (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64))
+		return FAILED;
+	return aac_scsi_32(fib, cmd);
+}
+
 int aac_get_adapter_info(struct aac_dev* dev)
 {
 	struct fib* fibptr;
@@ -1207,11 +1230,11 @@ int aac_get_adapter_info(struct aac_dev* dev)
 	memset(info,0,sizeof(*info));
 
 	rcode = aac_fib_send(RequestAdapterInfo,
-			 fibptr, 
+			 fibptr,
 			 sizeof(*info),
-			 FsaNormal, 
+			 FsaNormal,
 			 -1, 1, /* First `interrupt' command uses special wait */
-			 NULL, 
+			 NULL,
 			 NULL);
 
 	if (rcode < 0) {
@@ -1222,29 +1245,29 @@ int aac_get_adapter_info(struct aac_dev* dev)
 	memcpy(&dev->adapter_info, info, sizeof(*info));
 
 	if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) {
-		struct aac_supplement_adapter_info * info;
+		struct aac_supplement_adapter_info * sinfo;
 
 		aac_fib_init(fibptr);
 
-		info = (struct aac_supplement_adapter_info *) fib_data(fibptr);
+		sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr);
 
-		memset(info,0,sizeof(*info));
+		memset(sinfo,0,sizeof(*sinfo));
 
 		rcode = aac_fib_send(RequestSupplementAdapterInfo,
 				 fibptr,
-				 sizeof(*info),
+				 sizeof(*sinfo),
 				 FsaNormal,
 				 1, 1,
 				 NULL,
 				 NULL);
 
 		if (rcode >= 0)
-			memcpy(&dev->supplement_adapter_info, info, sizeof(*info));
+			memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo));
 	}
 
 
-	/* 
-	 * GetBusInfo 
+	/*
+	 * GetBusInfo
 	 */
 
 	aac_fib_init(fibptr);
@@ -1267,6 +1290,8 @@ int aac_get_adapter_info(struct aac_dev* dev)
 			 1, 1,
 			 NULL, NULL);
 
+	/* reasoned default */
+	dev->maximum_num_physicals = 16;
 	if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) {
 		dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus);
 		dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
@@ -1276,7 +1301,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
 		char buffer[16];
 		tmp = le32_to_cpu(dev->adapter_info.kernelrev);
 		printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
-			dev->name, 
+			dev->name,
 			dev->id,
 			tmp>>24,
 			(tmp>>16)&0xff,
@@ -1305,19 +1330,21 @@ int aac_get_adapter_info(struct aac_dev* dev)
 			  (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
 			  dev->supplement_adapter_info.VpdInfo.Tsid);
 		}
-		if (!aac_check_reset ||
+		if (!aac_check_reset || ((aac_check_reset != 1) &&
 		  (dev->supplement_adapter_info.SupportedOptions2 &
-		  le32_to_cpu(AAC_OPTION_IGNORE_RESET))) {
+		  AAC_OPTION_IGNORE_RESET))) {
 			printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
 			  dev->name, dev->id);
 		}
 	}
 
+	dev->cache_protected = 0;
+	dev->jbod = ((dev->supplement_adapter_info.FeatureBits &
+		AAC_FEATURE_JBOD) != 0);
 	dev->nondasd_support = 0;
 	dev->raid_scsi_mode = 0;
-	if(dev->adapter_info.options & AAC_OPT_NONDASD){
+	if(dev->adapter_info.options & AAC_OPT_NONDASD)
 		dev->nondasd_support = 1;
-	}
 
 	/*
 	 * If the firmware supports ROMB RAID/SCSI mode and we are currently
@@ -1338,11 +1365,10 @@ int aac_get_adapter_info(struct aac_dev* dev)
 	if (dev->raid_scsi_mode != 0)
 		printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
 				dev->name, dev->id);
-		
-	if(nondasd != -1) {  
+
+	if (nondasd != -1)
 		dev->nondasd_support = (nondasd!=0);
-	}
-	if(dev->nondasd_support != 0){
+	if(dev->nondasd_support != 0) {
 		printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
 	}
 
@@ -1371,12 +1397,14 @@ int aac_get_adapter_info(struct aac_dev* dev)
 			rcode = -ENOMEM;
 		}
 	}
-	/* 
+	/*
 	 * Deal with configuring for the individualized limits of each packet
 	 * interface.
 	 */
 	dev->a_ops.adapter_scsi = (dev->dac_support)
-				? aac_scsi_64
+	  ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32)
+				? aac_scsi_32_64
+				: aac_scsi_64)
 				: aac_scsi_32;
 	if (dev->raw_io_interface) {
 		dev->a_ops.adapter_bounds = (dev->raw_io_64)
@@ -1393,8 +1421,8 @@ int aac_get_adapter_info(struct aac_dev* dev)
 		if (dev->dac_support) {
 			dev->a_ops.adapter_read = aac_read_block64;
 			dev->a_ops.adapter_write = aac_write_block64;
-			/* 
-			 * 38 scatter gather elements 
+			/*
+			 * 38 scatter gather elements
 			 */
 			dev->scsi_host_ptr->sg_tablesize =
 				(dev->max_fib_size -
@@ -1498,9 +1526,8 @@ static void io_callback(void *context, struct fib * fibptr)
 				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
 				    0, 0);
 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
-		    ? sizeof(scsicmd->sense_buffer)
-		    : sizeof(dev->fsa_dev[cid].sense_data));
+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+			     SCSI_SENSE_BUFFERSIZE));
 	}
 	aac_fib_complete(fibptr);
 	aac_fib_free(fibptr);
@@ -1524,7 +1551,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
 	case READ_6:
 		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
 
-		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 
+		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
 			(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
 		count = scsicmd->cmnd[4];
 
@@ -1534,32 +1561,32 @@ static int aac_read(struct scsi_cmnd * scsicmd)
 	case READ_16:
 		dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
 
-		lba = 	((u64)scsicmd->cmnd[2] << 56) |
-		 	((u64)scsicmd->cmnd[3] << 48) |
+		lba =	((u64)scsicmd->cmnd[2] << 56) |
+			((u64)scsicmd->cmnd[3] << 48) |
 			((u64)scsicmd->cmnd[4] << 40) |
 			((u64)scsicmd->cmnd[5] << 32) |
-			((u64)scsicmd->cmnd[6] << 24) | 
+			((u64)scsicmd->cmnd[6] << 24) |
 			(scsicmd->cmnd[7] << 16) |
 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
-		count = (scsicmd->cmnd[10] << 24) | 
+		count = (scsicmd->cmnd[10] << 24) |
 			(scsicmd->cmnd[11] << 16) |
 			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
 		break;
 	case READ_12:
 		dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
 
-		lba = ((u64)scsicmd->cmnd[2] << 24) | 
+		lba = ((u64)scsicmd->cmnd[2] << 24) |
 			(scsicmd->cmnd[3] << 16) |
-		    	(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
-		count = (scsicmd->cmnd[6] << 24) | 
+			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		count = (scsicmd->cmnd[6] << 24) |
 			(scsicmd->cmnd[7] << 16) |
-		      	(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
 		break;
 	default:
 		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
 
-		lba = ((u64)scsicmd->cmnd[2] << 24) | 
-			(scsicmd->cmnd[3] << 16) | 
+		lba = ((u64)scsicmd->cmnd[2] << 24) |
+			(scsicmd->cmnd[3] << 16) |
 			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 		break;
@@ -1584,7 +1611,7 @@ static int aac_read(struct scsi_cmnd * scsicmd)
 		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
 		return 0;
 	}
-		
+
 	printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status);
 	/*
 	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
@@ -1619,11 +1646,11 @@ static int aac_write(struct scsi_cmnd * scsicmd)
 	} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
 		dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
 
-		lba = 	((u64)scsicmd->cmnd[2] << 56) |
+		lba =	((u64)scsicmd->cmnd[2] << 56) |
 			((u64)scsicmd->cmnd[3] << 48) |
 			((u64)scsicmd->cmnd[4] << 40) |
 			((u64)scsicmd->cmnd[5] << 32) |
-			((u64)scsicmd->cmnd[6] << 24) | 
+			((u64)scsicmd->cmnd[6] << 24) |
 			(scsicmd->cmnd[7] << 16) |
 			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
 		count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
@@ -1712,8 +1739,8 @@ static void synchronize_callback(void *context, struct fib *fibptr)
 				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
 				    0, 0);
 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-		  min(sizeof(dev->fsa_dev[cid].sense_data),
-			  sizeof(cmd->sense_buffer)));
+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+			     SCSI_SENSE_BUFFERSIZE));
 	}
 
 	aac_fib_complete(fibptr);
@@ -1798,7 +1825,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
 	if (active)
 		return SCSI_MLQUEUE_DEVICE_BUSY;
 
-	aac = (struct aac_dev *)scsicmd->device->host->hostdata;
+	aac = (struct aac_dev *)sdev->host->hostdata;
 	if (aac->in_reset)
 		return SCSI_MLQUEUE_HOST_BUSY;
 
@@ -1850,14 +1877,14 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
  *	Emulate a SCSI command and queue the required request for the
  *	aacraid firmware.
  */
- 
+
 int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 {
 	u32 cid;
 	struct Scsi_Host *host = scsicmd->device->host;
 	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
 	struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
-	
+
 	if (fsa_dev_ptr == NULL)
 		return -1;
 	/*
@@ -1898,7 +1925,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 				}
 			}
 		} else {  /* check for physical non-dasd devices */
-			if ((dev->nondasd_support == 1) || expose_physicals) {
+			if (dev->nondasd_support || expose_physicals ||
+					dev->jbod) {
 				if (dev->in_reset)
 					return -1;
 				return aac_send_srb_fib(scsicmd);
@@ -1913,7 +1941,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 	 * else Command for the controller itself
 	 */
 	else if ((scsicmd->cmnd[0] != INQUIRY) &&	/* only INQUIRY & TUR cmnd supported for controller */
-		(scsicmd->cmnd[0] != TEST_UNIT_READY)) 
+		(scsicmd->cmnd[0] != TEST_UNIT_READY))
 	{
 		dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
@@ -1922,9 +1950,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 			    SENCODE_INVALID_COMMAND,
 			    ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
 		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
-		    ? sizeof(scsicmd->sense_buffer)
-		    : sizeof(dev->fsa_dev[cid].sense_data));
+		       min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+			     SCSI_SENSE_BUFFERSIZE));
 		scsicmd->scsi_done(scsicmd);
 		return 0;
 	}
@@ -1939,7 +1966,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
 		memset(&inq_data, 0, sizeof (struct inquiry_data));
 
-		if (scsicmd->cmnd[1] & 0x1 ) {
+		if (scsicmd->cmnd[1] & 0x1) {
 			char *arr = (char *)&inq_data;
 
 			/* EVPD bit set */
@@ -1974,10 +2001,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 				  ASENCODE_NO_SENSE, 0, 7, 2, 0);
 				memcpy(scsicmd->sense_buffer,
 				  &dev->fsa_dev[cid].sense_data,
-				  (sizeof(dev->fsa_dev[cid].sense_data) >
-				    sizeof(scsicmd->sense_buffer))
-				       ? sizeof(scsicmd->sense_buffer)
-				       : sizeof(dev->fsa_dev[cid].sense_data));
+				  min_t(size_t,
+					sizeof(dev->fsa_dev[cid].sense_data),
+					SCSI_SENSE_BUFFERSIZE));
 			}
 			scsicmd->scsi_done(scsicmd);
 			return 0;
@@ -2092,7 +2118,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 		mode_buf[2] = 0;	/* Device-specific param,
 					   bit 8: 0/1 = write enabled/protected
 					   bit 4: 0/1 = FUA enabled */
-		if (dev->raw_io_interface)
+		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
 			mode_buf[2] = 0x10;
 		mode_buf[3] = 0;	/* Block descriptor length */
 		if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
@@ -2100,7 +2126,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 			mode_buf[0] = 6;
 			mode_buf[4] = 8;
 			mode_buf[5] = 1;
-			mode_buf[6] = 0x04; /* WCE */
+			mode_buf[6] = ((aac_cache & 6) == 2)
+				? 0 : 0x04; /* WCE */
 			mode_buf_length = 7;
 			if (mode_buf_length > scsicmd->cmnd[4])
 				mode_buf_length = scsicmd->cmnd[4];
@@ -2123,7 +2150,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 		mode_buf[3] = 0;	/* Device-specific param,
 					   bit 8: 0/1 = write enabled/protected
 					   bit 4: 0/1 = FUA enabled */
-		if (dev->raw_io_interface)
+		if (dev->raw_io_interface && ((aac_cache & 5) != 1))
 			mode_buf[3] = 0x10;
 		mode_buf[4] = 0;	/* reserved */
 		mode_buf[5] = 0;	/* reserved */
@@ -2134,7 +2161,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 			mode_buf[1] = 9;
 			mode_buf[8] = 8;
 			mode_buf[9] = 1;
-			mode_buf[10] = 0x04; /* WCE */
+			mode_buf[10] = ((aac_cache & 6) == 2)
+				? 0 : 0x04; /* WCE */
 			mode_buf_length = 11;
 			if (mode_buf_length > scsicmd->cmnd[8])
 				mode_buf_length = scsicmd->cmnd[8];
@@ -2179,7 +2207,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 		return 0;
 	}
 
-	switch (scsicmd->cmnd[0]) 
+	switch (scsicmd->cmnd[0])
 	{
 		case READ_6:
 		case READ_10:
@@ -2192,11 +2220,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 			 *	corresponds to a container. Needed to convert
 			 *	containers to /dev/sd device names
 			 */
-			 
+
 			if (scsicmd->request->rq_disk)
 				strlcpy(fsa_dev_ptr[cid].devname,
 				scsicmd->request->rq_disk->disk_name,
-			  	min(sizeof(fsa_dev_ptr[cid].devname),
+				min(sizeof(fsa_dev_ptr[cid].devname),
 				sizeof(scsicmd->request->rq_disk->disk_name) + 1));
 
 			return aac_read(scsicmd);
@@ -2210,9 +2238,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 			return aac_write(scsicmd);
 
 		case SYNCHRONIZE_CACHE:
+			if (((aac_cache & 6) == 6) && dev->cache_protected) {
+				scsicmd->result = DID_OK << 16 |
+					COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+				scsicmd->scsi_done(scsicmd);
+				return 0;
+			}
 			/* Issue FIB to tell Firmware to flush it's cache */
-			return aac_synchronize(scsicmd);
-			
+			if ((aac_cache & 6) != 2)
+				return aac_synchronize(scsicmd);
+			/* FALLTHRU */
 		default:
 			/*
 			 *	Unhandled commands
@@ -2223,9 +2258,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
 				ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
 				ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
 			memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-			  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
-			    ? sizeof(scsicmd->sense_buffer)
-			    : sizeof(dev->fsa_dev[cid].sense_data));
+				min_t(size_t,
+				      sizeof(dev->fsa_dev[cid].sense_data),
+				      SCSI_SENSE_BUFFERSIZE));
 			scsicmd->scsi_done(scsicmd);
 			return 0;
 	}
@@ -2243,7 +2278,7 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
 		return -EFAULT;
 	if (qd.cnum == -1)
 		qd.cnum = qd.id;
-	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) 
+	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1))
 	{
 		if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
 			return -EINVAL;
@@ -2370,7 +2405,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 
 	scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
 	/*
-	 *	Calculate resid for sg 
+	 *	Calculate resid for sg
 	 */
 
 	scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
@@ -2385,10 +2420,8 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 	if (le32_to_cpu(srbreply->status) != ST_OK){
 		int len;
 		printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
-		len = (le32_to_cpu(srbreply->sense_data_size) > 
-				sizeof(scsicmd->sense_buffer)) ?
-				sizeof(scsicmd->sense_buffer) : 
-				le32_to_cpu(srbreply->sense_data_size);
+		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+			    SCSI_SENSE_BUFFERSIZE);
 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
 	}
@@ -2412,7 +2445,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 		case  WRITE_12:
 		case  READ_16:
 		case  WRITE_16:
-			if(le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow ) {
+			if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) {
 				printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
 			} else {
 				printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
@@ -2481,26 +2514,23 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
 		printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
 			le32_to_cpu(srbreply->srb_status) & 0x3F,
 			aac_get_status_string(
-				le32_to_cpu(srbreply->srb_status) & 0x3F), 
-			scsicmd->cmnd[0], 
+				le32_to_cpu(srbreply->srb_status) & 0x3F),
+			scsicmd->cmnd[0],
 			le32_to_cpu(srbreply->scsi_status));
 #endif
 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
 		break;
 	}
-	if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){  // Check Condition
+	if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {
 		int len;
 		scsicmd->result |= SAM_STAT_CHECK_CONDITION;
-		len = (le32_to_cpu(srbreply->sense_data_size) > 
-				sizeof(scsicmd->sense_buffer)) ?
-				sizeof(scsicmd->sense_buffer) :
-				le32_to_cpu(srbreply->sense_data_size);
+		len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+			    SCSI_SENSE_BUFFERSIZE);
 #ifdef AAC_DETAILED_STATUS_INFO
 		printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
 					le32_to_cpu(srbreply->status), len);
 #endif
 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
-		
 	}
 	/*
 	 * OR in the scsi status (already shifted up a bit)
@@ -2517,7 +2547,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
  * aac_send_scb_fib
  * @scsicmd: the scsi command block
  *
- * This routine will form a FIB and fill in the aac_srb from the 
+ * This routine will form a FIB and fill in the aac_srb from the
  * scsicmd passed in.
  */
 
@@ -2731,7 +2761,7 @@ static struct aac_srb_status_info srb_status_info[] = {
 	{ SRB_STATUS_ERROR_RECOVERY,	"Error Recovery"},
 	{ SRB_STATUS_NOT_STARTED,	"Not Started"},
 	{ SRB_STATUS_NOT_IN_USE,	"Not In Use"},
-    	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
+	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
 	{ SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"},
 	{ 0xff,				"Unknown Error"}
 };
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 9abba8b90f70..3195d29f2177 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -1,4 +1,4 @@
-#if (!defined(dprintk))
+#ifndef dprintk
 # define dprintk(x)
 #endif
 /* eg: if (nblank(dprintk(x))) */
@@ -12,7 +12,7 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2449
+# define AAC_DRIVER_BUILD 2455
 # define AAC_DRIVER_BRANCH "-ms"
 #endif
 #define MAXIMUM_NUM_CONTAINERS	32
@@ -50,9 +50,9 @@ struct diskparm
 /*
  *	Firmware constants
  */
- 
+
 #define		CT_NONE			0
-#define 	CT_OK        		218
+#define		CT_OK			218
 #define		FT_FILESYS	8	/* ADAPTEC's "FSA"(tm) filesystem */
 #define		FT_DRIVE	9	/* physical disk - addressable in scsi by bus/id/lun */
 
@@ -107,12 +107,12 @@ struct user_sgentryraw {
 
 struct sgmap {
 	__le32		count;
-	struct sgentry	sg[1]; 
+	struct sgentry	sg[1];
 };
 
 struct user_sgmap {
 	u32		count;
-	struct user_sgentry	sg[1]; 
+	struct user_sgentry	sg[1];
 };
 
 struct sgmap64 {
@@ -137,18 +137,18 @@ struct user_sgmapraw {
 
 struct creation_info
 {
-	u8 		buildnum;		/* e.g., 588 */
-	u8 		usec;			/* e.g., 588 */
-	u8	 	via;			/* e.g., 1 = FSU,
-						 * 	 2 = API
+	u8		buildnum;		/* e.g., 588 */
+	u8		usec;			/* e.g., 588 */
+	u8		via;			/* e.g., 1 = FSU,
+						 *	 2 = API
 						 */
-	u8	 	year;		 	/* e.g., 1997 = 97 */
+	u8		year;			/* e.g., 1997 = 97 */
 	__le32		date;			/*
-						 * unsigned 	Month		:4;	// 1 - 12
-						 * unsigned 	Day		:6;	// 1 - 32
-						 * unsigned 	Hour		:6;	// 0 - 23
-						 * unsigned 	Minute		:6;	// 0 - 60
-						 * unsigned 	Second		:6;	// 0 - 60
+						 * unsigned	Month		:4;	// 1 - 12
+						 * unsigned	Day		:6;	// 1 - 32
+						 * unsigned	Hour		:6;	// 0 - 23
+						 * unsigned	Minute		:6;	// 0 - 60
+						 * unsigned	Second		:6;	// 0 - 60
 						 */
 	__le32		serial[2];			/* e.g., 0x1DEADB0BFAFAF001 */
 };
@@ -184,7 +184,7 @@ struct creation_info
 /*
  *	Set the queues on a 16 byte alignment
  */
- 
+
 #define QUEUE_ALIGNMENT		16
 
 /*
@@ -203,9 +203,9 @@ struct aac_entry {
  *	The adapter assumes the ProducerIndex and ConsumerIndex are grouped
  *	adjacently and in that order.
  */
- 
+
 struct aac_qhdr {
-	__le64 header_addr;/* Address to hand the adapter to access 
+	__le64 header_addr;/* Address to hand the adapter to access
 			      to this queue head */
 	__le32 *producer; /* The producer index for this queue (host address) */
 	__le32 *consumer; /* The consumer index for this queue (host address) */
@@ -215,7 +215,7 @@ struct aac_qhdr {
  *	Define all the events which the adapter would like to notify
  *	the host of.
  */
- 
+
 #define		HostNormCmdQue		1	/* Change in host normal priority command queue */
 #define		HostHighCmdQue		2	/* Change in host high priority command queue */
 #define		HostNormRespQue		3	/* Change in host normal priority response queue */
@@ -286,17 +286,17 @@ struct aac_fibhdr {
 	u8 StructType;		/* Type FIB */
 	u8 Flags;		/* Flags for FIB */
 	__le16 Size;		/* Size of this FIB in bytes */
-	__le16 SenderSize;	/* Size of the FIB in the sender 
+	__le16 SenderSize;	/* Size of the FIB in the sender
 				   (for response sizing) */
 	__le32 SenderFibAddress;  /* Host defined data in the FIB */
-	__le32 ReceiverFibAddress;/* Logical address of this FIB for 
+	__le32 ReceiverFibAddress;/* Logical address of this FIB for
 				     the adapter */
 	u32 SenderData;		/* Place holder for the sender to store data */
 	union {
 		struct {
-		    __le32 _ReceiverTimeStart; 	/* Timestamp for 
+		    __le32 _ReceiverTimeStart;	/* Timestamp for
 						   receipt of fib */
-		    __le32 _ReceiverTimeDone;	/* Timestamp for 
+		    __le32 _ReceiverTimeDone;	/* Timestamp for
 						   completion of fib */
 		} _s;
 	} _u;
@@ -311,7 +311,7 @@ struct hw_fib {
  *	FIB commands
  */
 
-#define 	TestCommandResponse		1
+#define		TestCommandResponse		1
 #define		TestAdapterCommand		2
 /*
  *	Lowlevel and comm commands
@@ -350,10 +350,6 @@ struct hw_fib {
 #define		ContainerCommand64		501
 #define		ContainerRawIo			502
 /*
- *	Cluster Commands
- */
-#define		ClusterCommand	 		550
-/*
  *	Scsi Port commands (scsi passthrough)
  */
 #define		ScsiPortCommand			600
@@ -375,19 +371,19 @@ struct hw_fib {
  */
 
 enum fib_xfer_state {
-	HostOwned 			= (1<<0),
-	AdapterOwned 			= (1<<1),
-	FibInitialized 			= (1<<2),
-	FibEmpty 			= (1<<3),
-	AllocatedFromPool 		= (1<<4),
-	SentFromHost 			= (1<<5),
-	SentFromAdapter 		= (1<<6),
-	ResponseExpected 		= (1<<7),
-	NoResponseExpected 		= (1<<8),
-	AdapterProcessed 		= (1<<9),
-	HostProcessed 			= (1<<10),
-	HighPriority 			= (1<<11),
-	NormalPriority 			= (1<<12),
+	HostOwned			= (1<<0),
+	AdapterOwned			= (1<<1),
+	FibInitialized			= (1<<2),
+	FibEmpty			= (1<<3),
+	AllocatedFromPool		= (1<<4),
+	SentFromHost			= (1<<5),
+	SentFromAdapter			= (1<<6),
+	ResponseExpected		= (1<<7),
+	NoResponseExpected		= (1<<8),
+	AdapterProcessed		= (1<<9),
+	HostProcessed			= (1<<10),
+	HighPriority			= (1<<11),
+	NormalPriority			= (1<<12),
 	Async				= (1<<13),
 	AsyncIo				= (1<<13),	// rpbfix: remove with new regime
 	PageFileIo			= (1<<14),	// rpbfix: remove with new regime
@@ -420,7 +416,7 @@ struct aac_init
 	__le32	AdapterFibAlign;
 	__le32	printfbuf;
 	__le32	printfbufsiz;
-	__le32	HostPhysMemPages;   /* number of 4k pages of host 
+	__le32	HostPhysMemPages;   /* number of 4k pages of host
 				       physical memory */
 	__le32	HostElapsedSeconds; /* number of seconds since 1970. */
 	/*
@@ -481,7 +477,7 @@ struct adapter_ops
 
 struct aac_driver_ident
 {
-	int 	(*init)(struct aac_dev *dev);
+	int	(*init)(struct aac_dev *dev);
 	char *	name;
 	char *	vname;
 	char *	model;
@@ -489,7 +485,7 @@ struct aac_driver_ident
 	int	quirks;
 };
 /*
- * Some adapter firmware needs communication memory 
+ * Some adapter firmware needs communication memory
  * below 2gig. This tells the init function to set the
  * dma mask such that fib memory will be allocated where the
  * adapter firmware can get to it.
@@ -521,33 +517,39 @@ struct aac_driver_ident
 #define AAC_QUIRK_17SG	0x0010
 
 /*
+ *	Some adapter firmware does not support 64 bit scsi passthrough
+ * commands.
+ */
+#define AAC_QUIRK_SCSI_32	0x0020
+
+/*
  *	The adapter interface specs all queues to be located in the same
  *	physically contigous block. The host structure that defines the
  *	commuication queues will assume they are each a separate physically
  *	contigous memory region that will support them all being one big
- *	contigous block. 
+ *	contigous block.
  *	There is a command and response queue for each level and direction of
  *	commuication. These regions are accessed by both the host and adapter.
  */
- 
+
 struct aac_queue {
-	u64		 	logical;	/*address we give the adapter */
+	u64			logical;	/*address we give the adapter */
 	struct aac_entry	*base;		/*system virtual address */
-	struct aac_qhdr 	headers;       	/*producer,consumer q headers*/
-	u32	 		entries;	/*Number of queue entries */
+	struct aac_qhdr		headers;	/*producer,consumer q headers*/
+	u32			entries;	/*Number of queue entries */
 	wait_queue_head_t	qfull;		/*Event to wait on if q full */
 	wait_queue_head_t	cmdready;	/*Cmd ready from the adapter */
-                  /* This is only valid for adapter to host command queues. */ 
-	spinlock_t	 	*lock;		/* Spinlock for this queue must take this lock before accessing the lock */
+		/* This is only valid for adapter to host command queues. */
+	spinlock_t		*lock;		/* Spinlock for this queue must take this lock before accessing the lock */
 	spinlock_t		lockdata;	/* Actual lock (used only on one side of the lock) */
-	struct list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
-                                		/* only valid for command queues which receive entries from the adapter. */
+	struct list_head	cmdq;		/* A queue of FIBs which need to be prcessed by the FS thread. This is */
+						/* only valid for command queues which receive entries from the adapter. */
 	u32			numpending;	/* Number of entries on outstanding queue. */
 	struct aac_dev *	dev;		/* Back pointer to adapter structure */
 };
 
 /*
- *	Message queues. The order here is important, see also the 
+ *	Message queues. The order here is important, see also the
  *	queue type ordering
  */
 
@@ -559,12 +561,12 @@ struct aac_queue_block
 /*
  *	SaP1 Message Unit Registers
  */
- 
+
 struct sa_drawbridge_CSR {
-				/*	Offset 	|  Name */
+				/*	Offset	|  Name */
 	__le32	reserved[10];	/*	00h-27h |  Reserved */
 	u8	LUT_Offset;	/*	28h	|  Lookup Table Offset */
-	u8	reserved1[3];	/* 	29h-2bh	|  Reserved */
+	u8	reserved1[3];	/*	29h-2bh	|  Reserved */
 	__le32	LUT_Data;	/*	2ch	|  Looup Table Data */
 	__le32	reserved2[26];	/*	30h-97h	|  Reserved */
 	__le16	PRICLEARIRQ;	/*	98h	|  Primary Clear Irq */
@@ -583,8 +585,8 @@ struct sa_drawbridge_CSR {
 	__le32	MAILBOX5;	/*	bch	|  Scratchpad 5 */
 	__le32	MAILBOX6;	/*	c0h	|  Scratchpad 6 */
 	__le32	MAILBOX7;	/*	c4h	|  Scratchpad 7 */
-	__le32	ROM_Setup_Data;	/*	c8h 	|  Rom Setup and Data */
-	__le32	ROM_Control_Addr;/*	cch 	|  Rom Control and Address */
+	__le32	ROM_Setup_Data;	/*	c8h	|  Rom Setup and Data */
+	__le32	ROM_Control_Addr;/*	cch	|  Rom Control and Address */
 	__le32	reserved3[12];	/*	d0h-ffh	|  reserved */
 	__le32	LUT[64];	/*    100h-1ffh	|  Lookup Table Entries */
 };
@@ -597,7 +599,7 @@ struct sa_drawbridge_CSR {
 #define Mailbox5	SaDbCSR.MAILBOX5
 #define Mailbox6	SaDbCSR.MAILBOX6
 #define Mailbox7	SaDbCSR.MAILBOX7
-	
+
 #define DoorbellReg_p SaDbCSR.PRISETIRQ
 #define DoorbellReg_s SaDbCSR.SECSETIRQ
 #define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ
@@ -611,19 +613,19 @@ struct sa_drawbridge_CSR {
 #define DOORBELL_5	0x0020
 #define DOORBELL_6	0x0040
 
-	
+
 #define PrintfReady	DOORBELL_5
 #define PrintfDone	DOORBELL_5
-	
+
 struct sa_registers {
 	struct sa_drawbridge_CSR	SaDbCSR;			/* 98h - c4h */
 };
-	
+
 
 #define Sa_MINIPORT_REVISION			1
 
 #define sa_readw(AEP, CSR)		readl(&((AEP)->regs.sa->CSR))
-#define sa_readl(AEP,  CSR)		readl(&((AEP)->regs.sa->CSR))
+#define sa_readl(AEP, CSR)		readl(&((AEP)->regs.sa->CSR))
 #define sa_writew(AEP, CSR, value)	writew(value, &((AEP)->regs.sa->CSR))
 #define sa_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.sa->CSR))
 
@@ -640,21 +642,21 @@ struct rx_mu_registers {
 	__le32	IMRx[2];    /*	1310h  | 10h | Inbound Message Registers */
 	__le32	OMRx[2];    /*	1318h  | 18h | Outbound Message Registers */
 	__le32	IDR;	    /*	1320h  | 20h | Inbound Doorbell Register */
-	__le32	IISR;	    /*	1324h  | 24h | Inbound Interrupt 
+	__le32	IISR;	    /*	1324h  | 24h | Inbound Interrupt
 						Status Register */
-	__le32	IIMR;	    /*	1328h  | 28h | Inbound Interrupt 
-					 	Mask Register */
+	__le32	IIMR;	    /*	1328h  | 28h | Inbound Interrupt
+						Mask Register */
 	__le32	ODR;	    /*	132Ch  | 2Ch | Outbound Doorbell Register */
-	__le32	OISR;	    /*	1330h  | 30h | Outbound Interrupt 
+	__le32	OISR;	    /*	1330h  | 30h | Outbound Interrupt
 						Status Register */
-	__le32	OIMR;	    /*	1334h  | 34h | Outbound Interrupt 
+	__le32	OIMR;	    /*	1334h  | 34h | Outbound Interrupt
 						Mask Register */
 	__le32	reserved2;  /*	1338h  | 38h | Reserved */
 	__le32	reserved3;  /*	133Ch  | 3Ch | Reserved */
 	__le32	InboundQueue;/*	1340h  | 40h | Inbound Queue Port relative to firmware */
 	__le32	OutboundQueue;/*1344h  | 44h | Outbound Queue Port relative to firmware */
-			    /* * Must access through ATU Inbound 
-			     	 Translation Window */
+			    /* * Must access through ATU Inbound
+				 Translation Window */
 };
 
 struct rx_inbound {
@@ -710,12 +712,12 @@ struct rkt_registers {
 typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
 
 struct aac_fib_context {
-	s16	 		type;		// used for verification of structure	
-	s16	 		size;
+	s16			type;		// used for verification of structure
+	s16			size;
 	u32			unique;		// unique value representing this context
 	ulong			jiffies;	// used for cleanup - dmb changed to ulong
 	struct list_head	next;		// used to link context's into a linked list
-	struct semaphore 	wait_sem;	// this is used to wait for the next fib to arrive.
+	struct semaphore	wait_sem;	// this is used to wait for the next fib to arrive.
 	int			wait;		// Set to true when thread is in WaitForSingleObject
 	unsigned long		count;		// total number of FIBs on FibList
 	struct list_head	fib_list;	// this holds fibs and their attachd hw_fibs
@@ -734,9 +736,9 @@ struct sense_data {
 	u8 EOM:1;		/* End Of Medium - reserved for random access devices */
 	u8 filemark:1;		/* Filemark - reserved for random access devices */
 
-	u8 information[4];	/* for direct-access devices, contains the unsigned 
-				 * logical block address or residue associated with 
-				 * the sense key 
+	u8 information[4];	/* for direct-access devices, contains the unsigned
+				 * logical block address or residue associated with
+				 * the sense key
 				 */
 	u8 add_sense_len;	/* number of additional sense bytes to follow this field */
 	u8 cmnd_info[4];	/* not used */
@@ -746,7 +748,7 @@ struct sense_data {
 	u8 bit_ptr:3;		/* indicates which byte of the CDB or parameter data
 				 * was in error
 				 */
-	u8 BPV:1;		/* bit pointer valid (BPV): 1- indicates that 
+	u8 BPV:1;		/* bit pointer valid (BPV): 1- indicates that
 				 * the bit_ptr field has valid value
 				 */
 	u8 reserved2:2;
@@ -780,24 +782,24 @@ struct fib {
 	/*
 	 *	The Adapter that this I/O is destined for.
 	 */
-	struct aac_dev 		*dev;
+	struct aac_dev		*dev;
 	/*
 	 *	This is the event the sendfib routine will wait on if the
 	 *	caller did not pass one and this is synch io.
 	 */
-	struct semaphore 	event_wait;
+	struct semaphore	event_wait;
 	spinlock_t		event_lock;
 
 	u32			done;	/* gets set to 1 when fib is complete */
-	fib_callback 		callback;
-	void 			*callback_data;
+	fib_callback		callback;
+	void			*callback_data;
 	u32			flags; // u32 dmb was ulong
 	/*
 	 *	And for the internal issue/reply queues (we may be able
 	 *	to merge these two)
 	 */
 	struct list_head	fiblink;
-	void 			*data;
+	void			*data;
 	struct hw_fib		*hw_fib_va;		/* Actual shared object */
 	dma_addr_t		hw_fib_pa;		/* physical address of hw_fib*/
 };
@@ -807,7 +809,7 @@ struct fib {
  *
  *	This is returned by the RequestAdapterInfo block
  */
- 
+
 struct aac_adapter_info
 {
 	__le32	platform;
@@ -826,7 +828,7 @@ struct aac_adapter_info
 	__le32	biosrev;
 	__le32	biosbuild;
 	__le32	cluster;
-	__le32	clusterchannelmask; 
+	__le32	clusterchannelmask;
 	__le32	serial[2];
 	__le32	battery;
 	__le32	options;
@@ -863,9 +865,10 @@ struct aac_supplement_adapter_info
 	__le32	SupportedOptions2;
 	__le32	ReservedGrowth[1];
 };
-#define AAC_FEATURE_FALCON	0x00000010
-#define AAC_OPTION_MU_RESET	0x00000001
-#define AAC_OPTION_IGNORE_RESET	0x00000002
+#define AAC_FEATURE_FALCON	cpu_to_le32(0x00000010)
+#define AAC_FEATURE_JBOD	cpu_to_le32(0x08000000)
+#define AAC_OPTION_MU_RESET	cpu_to_le32(0x00000001)
+#define AAC_OPTION_IGNORE_RESET	cpu_to_le32(0x00000002)
 #define AAC_SIS_VERSION_V3	3
 #define AAC_SIS_SLOT_UNKNOWN	0xFF
 
@@ -916,13 +919,13 @@ struct aac_bus_info_response {
 #define AAC_OPT_HOST_TIME_FIB		cpu_to_le32(1<<4)
 #define AAC_OPT_RAID50			cpu_to_le32(1<<5)
 #define AAC_OPT_4GB_WINDOW		cpu_to_le32(1<<6)
-#define AAC_OPT_SCSI_UPGRADEABLE 	cpu_to_le32(1<<7)
+#define AAC_OPT_SCSI_UPGRADEABLE	cpu_to_le32(1<<7)
 #define AAC_OPT_SOFT_ERR_REPORT		cpu_to_le32(1<<8)
-#define AAC_OPT_SUPPORTED_RECONDITION 	cpu_to_le32(1<<9)
+#define AAC_OPT_SUPPORTED_RECONDITION	cpu_to_le32(1<<9)
 #define AAC_OPT_SGMAP_HOST64		cpu_to_le32(1<<10)
 #define AAC_OPT_ALARM			cpu_to_le32(1<<11)
 #define AAC_OPT_NONDASD			cpu_to_le32(1<<12)
-#define AAC_OPT_SCSI_MANAGED    	cpu_to_le32(1<<13)
+#define AAC_OPT_SCSI_MANAGED		cpu_to_le32(1<<13)
 #define AAC_OPT_RAID_SCSI_MODE		cpu_to_le32(1<<14)
 #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO	cpu_to_le32(1<<16)
 #define AAC_OPT_NEW_COMM		cpu_to_le32(1<<17)
@@ -942,7 +945,7 @@ struct aac_dev
 
 	/*
 	 *	Map for 128 fib objects (64k)
-	 */	
+	 */
 	dma_addr_t		hw_fib_pa;
 	struct hw_fib		*hw_fib_va;
 	struct hw_fib		*aif_base_va;
@@ -953,24 +956,24 @@ struct aac_dev
 
 	struct fib		*free_fib;
 	spinlock_t		fib_lock;
-	
+
 	struct aac_queue_block *queues;
 	/*
 	 *	The user API will use an IOCTL to register itself to receive
 	 *	FIBs from the adapter.  The following list is used to keep
 	 *	track of all the threads that have requested these FIBs.  The
-	 *	mutex is used to synchronize access to all data associated 
+	 *	mutex is used to synchronize access to all data associated
 	 *	with the adapter fibs.
 	 */
 	struct list_head	fib_list;
 
 	struct adapter_ops	a_ops;
 	unsigned long		fsrev;		/* Main driver's revision number */
-	
+
 	unsigned		base_size;	/* Size of mapped in region */
 	struct aac_init		*init;		/* Holds initialization info to communicate with adapter */
-	dma_addr_t		init_pa; 	/* Holds physical address of the init struct */
-	
+	dma_addr_t		init_pa;	/* Holds physical address of the init struct */
+
 	struct pci_dev		*pdev;		/* Our PCI interface */
 	void *			printfbuf;	/* pointer to buffer used for printf's from the adapter */
 	void *			comm_addr;	/* Base address of Comm area */
@@ -984,11 +987,11 @@ struct aac_dev
 	struct fsa_dev_info	*fsa_dev;
 	struct task_struct	*thread;
 	int			cardtype;
-	
+
 	/*
 	 *	The following is the device specific extension.
 	 */
-#if (!defined(AAC_MIN_FOOTPRINT_SIZE))
+#ifndef AAC_MIN_FOOTPRINT_SIZE
 #	define AAC_MIN_FOOTPRINT_SIZE 8192
 #endif
 	union
@@ -1009,7 +1012,9 @@ struct aac_dev
 	/* These are in adapter info but they are in the io flow so
 	 * lets break them out so we don't have to do an AND to check them
 	 */
-	u8			nondasd_support; 
+	u8			nondasd_support;
+	u8			jbod;
+	u8			cache_protected;
 	u8			dac_support;
 	u8			raid_scsi_mode;
 	u8			comm_interface;
@@ -1066,18 +1071,19 @@ struct aac_dev
 	(dev)->a_ops.adapter_comm(dev, comm)
 
 #define FIB_CONTEXT_FLAG_TIMED_OUT		(0x00000001)
+#define FIB_CONTEXT_FLAG			(0x00000002)
 
 /*
  *	Define the command values
  */
- 
+
 #define		Null			0
-#define 	GetAttributes		1
-#define 	SetAttributes		2
-#define 	Lookup			3
-#define 	ReadLink		4
-#define 	Read			5
-#define 	Write			6
+#define		GetAttributes		1
+#define		SetAttributes		2
+#define		Lookup			3
+#define		ReadLink		4
+#define		Read			5
+#define		Write			6
 #define		Create			7
 #define		MakeDirectory		8
 #define		SymbolicLink		9
@@ -1173,19 +1179,19 @@ struct aac_dev
 
 struct aac_read
 {
-	__le32	 	command;
-	__le32 		cid;
-	__le32 		block;
-	__le32 		count;
+	__le32		command;
+	__le32		cid;
+	__le32		block;
+	__le32		count;
 	struct sgmap	sg;	// Must be last in struct because it is variable
 };
 
 struct aac_read64
 {
-	__le32	 	command;
-	__le16 		cid;
-	__le16 		sector_count;
-	__le32 		block;
+	__le32		command;
+	__le16		cid;
+	__le16		sector_count;
+	__le32		block;
 	__le16		pad;
 	__le16		flags;
 	struct sgmap64	sg;	// Must be last in struct because it is variable
@@ -1193,26 +1199,26 @@ struct aac_read64
 
 struct aac_read_reply
 {
-	__le32	 	status;
-	__le32 		count;
+	__le32		status;
+	__le32		count;
 };
 
 struct aac_write
 {
 	__le32		command;
-	__le32 		cid;
-	__le32 		block;
-	__le32 		count;
-	__le32	 	stable;	// Not used
+	__le32		cid;
+	__le32		block;
+	__le32		count;
+	__le32		stable;	// Not used
 	struct sgmap	sg;	// Must be last in struct because it is variable
 };
 
 struct aac_write64
 {
-	__le32	 	command;
-	__le16 		cid;
-	__le16 		sector_count;
-	__le32 		block;
+	__le32		command;
+	__le16		cid;
+	__le16		sector_count;
+	__le32		block;
 	__le16		pad;
 	__le16		flags;
 #define	IO_TYPE_WRITE 0x00000000
@@ -1223,7 +1229,7 @@ struct aac_write64
 struct aac_write_reply
 {
 	__le32		status;
-	__le32 		count;
+	__le32		count;
 	__le32		committed;
 };
 
@@ -1326,10 +1332,10 @@ struct aac_srb_reply
 #define		SRB_NoDataXfer		 0x0000
 #define		SRB_DisableDisconnect	 0x0004
 #define		SRB_DisableSynchTransfer 0x0008
-#define 	SRB_BypassFrozenQueue	 0x0010
+#define		SRB_BypassFrozenQueue	 0x0010
 #define		SRB_DisableAutosense	 0x0020
 #define		SRB_DataIn		 0x0040
-#define 	SRB_DataOut		 0x0080
+#define		SRB_DataOut		 0x0080
 
 /*
  * SRB Functions - set in aac_srb->function
@@ -1352,7 +1358,7 @@ struct aac_srb_reply
 #define	SRBF_RemoveDevice	0x0016
 #define	SRBF_DomainValidation	0x0017
 
-/* 
+/*
  * SRB SCSI Status - set in aac_srb->scsi_status
  */
 #define SRB_STATUS_PENDING                  0x00
@@ -1511,17 +1517,17 @@ struct aac_get_container_count_resp {
  */
 
 struct aac_mntent {
-	__le32    		oid;
+	__le32			oid;
 	u8			name[16];	/* if applicable */
 	struct creation_info	create_info;	/* if applicable */
 	__le32			capacity;
-	__le32			vol;    	/* substrate structure */
-	__le32			obj;	        /* FT_FILESYS, etc. */
-	__le32			state;		/* unready for mounting, 
+	__le32			vol;		/* substrate structure */
+	__le32			obj;		/* FT_FILESYS, etc. */
+	__le32			state;		/* unready for mounting,
 						   readonly, etc. */
-	union aac_contentinfo	fileinfo;	/* Info specific to content 
+	union aac_contentinfo	fileinfo;	/* Info specific to content
 						   manager (eg, filesystem) */
-	__le32			altoid;		/* != oid <==> snapshot or 
+	__le32			altoid;		/* != oid <==> snapshot or
 						   broken mirror exists */
 	__le32			capacityhigh;
 };
@@ -1538,7 +1544,7 @@ struct aac_query_mount {
 
 struct aac_mount {
 	__le32		status;
-	__le32	   	type;           /* should be same as that requested */
+	__le32		type;           /* should be same as that requested */
 	__le32		count;
 	struct aac_mntent mnt[1];
 };
@@ -1608,7 +1614,7 @@ struct aac_delete_disk {
 	u32	disknum;
 	u32	cnum;
 };
- 
+
 struct fib_ioctl
 {
 	u32	fibctx;
@@ -1622,10 +1628,10 @@ struct revision
 	__le32 version;
 	__le32 build;
 };
-	
+
 
 /*
- * 	Ugly - non Linux like ioctl coding for back compat.
+ *	Ugly - non Linux like ioctl coding for back compat.
  */
 
 #define CTL_CODE(function, method) (                 \
@@ -1633,7 +1639,7 @@ struct revision
 )
 
 /*
- *	Define the method codes for how buffers are passed for I/O and FS 
+ *	Define the method codes for how buffers are passed for I/O and FS
  *	controls
  */
 
@@ -1644,15 +1650,15 @@ struct revision
  *	Filesystem ioctls
  */
 
-#define FSACTL_SENDFIB                  	CTL_CODE(2050, METHOD_BUFFERED)
-#define FSACTL_SEND_RAW_SRB               	CTL_CODE(2067, METHOD_BUFFERED)
+#define FSACTL_SENDFIB				CTL_CODE(2050, METHOD_BUFFERED)
+#define FSACTL_SEND_RAW_SRB			CTL_CODE(2067, METHOD_BUFFERED)
 #define FSACTL_DELETE_DISK			0x163
 #define FSACTL_QUERY_DISK			0x173
 #define FSACTL_OPEN_GET_ADAPTER_FIB		CTL_CODE(2100, METHOD_BUFFERED)
 #define FSACTL_GET_NEXT_ADAPTER_FIB		CTL_CODE(2101, METHOD_BUFFERED)
 #define FSACTL_CLOSE_GET_ADAPTER_FIB		CTL_CODE(2102, METHOD_BUFFERED)
 #define FSACTL_MINIPORT_REV_CHECK               CTL_CODE(2107, METHOD_BUFFERED)
-#define FSACTL_GET_PCI_INFO               	CTL_CODE(2119, METHOD_BUFFERED)
+#define FSACTL_GET_PCI_INFO			CTL_CODE(2119, METHOD_BUFFERED)
 #define FSACTL_FORCE_DELETE_DISK		CTL_CODE(2120, METHOD_NEITHER)
 #define FSACTL_GET_CONTAINERS			2131
 #define FSACTL_SEND_LARGE_FIB			CTL_CODE(2138, METHOD_BUFFERED)
@@ -1661,7 +1667,7 @@ struct revision
 struct aac_common
 {
 	/*
-	 *	If this value is set to 1 then interrupt moderation will occur 
+	 *	If this value is set to 1 then interrupt moderation will occur
 	 *	in the base commuication support.
 	 */
 	u32 irq_mod;
@@ -1690,11 +1696,11 @@ extern struct aac_common aac_config;
  *	The following macro is used when sending and receiving FIBs. It is
  *	only used for debugging.
  */
- 
+
 #ifdef DBG
 #define	FIB_COUNTER_INCREMENT(counter)		(counter)++
 #else
-#define	FIB_COUNTER_INCREMENT(counter)		
+#define	FIB_COUNTER_INCREMENT(counter)
 #endif
 
 /*
@@ -1726,17 +1732,17 @@ extern struct aac_common aac_config;
  *
  *	The adapter reports is present state through the phase.  Only
  *	a single phase should be ever be set.  Each phase can have multiple
- *	phase status bits to provide more detailed information about the 
- *	state of the board.  Care should be taken to ensure that any phase 
+ *	phase status bits to provide more detailed information about the
+ *	state of the board.  Care should be taken to ensure that any phase
  *	status bits that are set when changing the phase are also valid
  *	for the new phase or be cleared out.  Adapter software (monitor,
- *	iflash, kernel) is responsible for properly maintining the phase 
+ *	iflash, kernel) is responsible for properly maintining the phase
  *	status mailbox when it is running.
- *											
- *	MONKER_API Phases							
  *
- *	Phases are bit oriented.  It is NOT valid  to have multiple bits set						
- */					
+ *	MONKER_API Phases
+ *
+ *	Phases are bit oriented.  It is NOT valid  to have multiple bits set
+ */
 
 #define	SELF_TEST_FAILED		0x00000004
 #define	MONITOR_PANIC			0x00000020
@@ -1759,16 +1765,22 @@ extern struct aac_common aac_config;
  *	For FIB communication, we need all of the following things
  *	to send back to the user.
  */
- 
-#define 	AifCmdEventNotify	1	/* Notify of event */
+
+#define		AifCmdEventNotify	1	/* Notify of event */
 #define			AifEnConfigChange	3	/* Adapter configuration change */
 #define			AifEnContainerChange	4	/* Container configuration change */
 #define			AifEnDeviceFailure	5	/* SCSI device failed */
+#define			AifEnEnclosureManagement 13	/* EM_DRIVE_* */
+#define				EM_DRIVE_INSERTION	31
+#define				EM_DRIVE_REMOVAL	32
+#define			AifEnBatteryEvent	14	/* Change in Battery State */
 #define			AifEnAddContainer	15	/* A new array was created */
 #define			AifEnDeleteContainer	16	/* A container was deleted */
 #define			AifEnExpEvent		23	/* Firmware Event Log */
 #define			AifExeFirmwarePanic	3	/* Firmware Event Panic */
 #define			AifHighPriority		3	/* Highest Priority Event */
+#define			AifEnAddJBOD		30	/* JBOD created */
+#define			AifEnDeleteJBOD		31	/* JBOD deleted */
 
 #define		AifCmdJobProgress	2	/* Progress report */
 #define			AifJobCtrZero	101	/* Array Zero progress */
@@ -1780,11 +1792,11 @@ extern struct aac_common aac_config;
 #define			AifDenVolumeExtendComplete 201 /* A volume extend completed */
 #define		AifReqJobList		100	/* Gets back complete job list */
 #define		AifReqJobsForCtr	101	/* Gets back jobs for specific container */
-#define		AifReqJobsForScsi	102	/* Gets back jobs for specific SCSI device */ 
-#define		AifReqJobReport		103	/* Gets back a specific job report or list of them */ 
+#define		AifReqJobsForScsi	102	/* Gets back jobs for specific SCSI device */
+#define		AifReqJobReport		103	/* Gets back a specific job report or list of them */
 #define		AifReqTerminateJob	104	/* Terminates job */
 #define		AifReqSuspendJob	105	/* Suspends a job */
-#define		AifReqResumeJob		106	/* Resumes a job */ 
+#define		AifReqResumeJob		106	/* Resumes a job */
 #define		AifReqSendAPIReport	107	/* API generic report requests */
 #define		AifReqAPIJobStart	108	/* Start a job from the API */
 #define		AifReqAPIJobUpdate	109	/* Update a job report from the API */
@@ -1803,8 +1815,8 @@ struct aac_aifcmd {
 };
 
 /**
- * 	Convert capacity to cylinders
- *  	accounting for the fact capacity could be a 64 bit value
+ *	Convert capacity to cylinders
+ *	accounting for the fact capacity could be a 64 bit value
  *
  */
 static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
@@ -1861,6 +1873,7 @@ int aac_probe_container(struct aac_dev *dev, int cid);
 int _aac_rx_init(struct aac_dev *dev);
 int aac_rx_select_comm(struct aac_dev *dev, int comm);
 int aac_rx_deliver_producer(struct fib * fib);
+char * get_container_type(unsigned type);
 extern int numacb;
 extern int acbsize;
 extern char aac_driver_version[];
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index 1e6d7a9c75bf..f8afa358b6b6 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -48,13 +48,13 @@
  *	ioctl_send_fib	-	send a FIB from userspace
  *	@dev:	adapter is being processed
  *	@arg:	arguments to the ioctl call
- *	
+ *
  *	This routine sends a fib to the adapter on behalf of a user level
  *	program.
  */
 # define AAC_DEBUG_PREAMBLE	KERN_INFO
 # define AAC_DEBUG_POSTAMBLE
- 
+
 static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
 {
 	struct hw_fib * kfib;
@@ -71,7 +71,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
 	if(fibptr == NULL) {
 		return -ENOMEM;
 	}
-		
+
 	kfib = fibptr->hw_fib_va;
 	/*
 	 *	First copy in the header so that we can check the size field.
@@ -109,7 +109,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
 	if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) {
 		aac_adapter_interrupt(dev);
 		/*
-		 * Since we didn't really send a fib, zero out the state to allow 
+		 * Since we didn't really send a fib, zero out the state to allow
 		 * cleanup code not to assert.
 		 */
 		kfib->header.XferState = 0;
@@ -169,7 +169,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
 
 		fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
 		fibctx->size = sizeof(struct aac_fib_context);
- 		/*
+		/*
 		 *	Yes yes, I know this could be an index, but we have a
 		 * better guarantee of uniqueness for the locked loop below.
 		 * Without the aid of a persistent history, this also helps
@@ -189,7 +189,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
 		INIT_LIST_HEAD(&fibctx->fib_list);
 		fibctx->jiffies = jiffies/HZ;
 		/*
-		 *	Now add this context onto the adapter's 
+		 *	Now add this context onto the adapter's
 		 *	AdapterFibContext list.
 		 */
 		spin_lock_irqsave(&dev->fib_lock, flags);
@@ -207,12 +207,12 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
 		}
 		list_add_tail(&fibctx->next, &dev->fib_list);
 		spin_unlock_irqrestore(&dev->fib_lock, flags);
-		if (copy_to_user(arg,  &fibctx->unique, 
+		if (copy_to_user(arg, &fibctx->unique,
 						sizeof(fibctx->unique))) {
 			status = -EFAULT;
 		} else {
 			status = 0;
-		}	
+		}
 	}
 	return status;
 }
@@ -221,8 +221,8 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
  *	next_getadapter_fib	-	get the next fib
  *	@dev: adapter to use
  *	@arg: ioctl argument
- *	
- * 	This routine will get the next Fib, if available, from the AdapterFibContext
+ *
+ *	This routine will get the next Fib, if available, from the AdapterFibContext
  *	passed in from the user.
  */
 
@@ -234,7 +234,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
 	int status;
 	struct list_head * entry;
 	unsigned long flags;
-	
+
 	if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
 		return -EFAULT;
 	/*
@@ -275,13 +275,12 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
 	 */
 return_fib:
 	if (!list_empty(&fibctx->fib_list)) {
-		struct list_head * entry;
 		/*
 		 *	Pull the next fib from the fibs
 		 */
 		entry = fibctx->fib_list.next;
 		list_del(entry);
-		
+
 		fib = list_entry(entry, struct fib, fiblink);
 		fibctx->count--;
 		spin_unlock_irqrestore(&dev->fib_lock, flags);
@@ -289,7 +288,7 @@ return_fib:
 			kfree(fib->hw_fib_va);
 			kfree(fib);
 			return -EFAULT;
-		}	
+		}
 		/*
 		 *	Free the space occupied by this copy of the fib.
 		 */
@@ -318,7 +317,7 @@ return_fib:
 			}
 		} else {
 			status = -EAGAIN;
-		}	
+		}
 	}
 	fibctx->jiffies = jiffies/HZ;
 	return status;
@@ -368,7 +367,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
  *
  *	This routine will close down the fibctx passed in from the user.
  */
- 
+
 static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
 {
 	struct aac_fib_context *fibctx;
@@ -415,7 +414,7 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
  *	@arg: ioctl arguments
  *
  *	This routine returns the driver version.
- *      Under Linux, there have been no version incompatibilities, so this is 
+ *      Under Linux, there have been no version incompatibilities, so this is
  *      simple!
  */
 
@@ -426,12 +425,12 @@ static int check_revision(struct aac_dev *dev, void __user *arg)
 	u32 version;
 
 	response.compat = 1;
-	version = (simple_strtol(driver_version, 
+	version = (simple_strtol(driver_version,
 				&driver_version, 10) << 24) | 0x00000400;
 	version += simple_strtol(driver_version + 1, &driver_version, 10) << 16;
 	version += simple_strtol(driver_version + 1, NULL, 10);
 	response.version = cpu_to_le32(version);
-#	if (defined(AAC_DRIVER_BUILD))
+#	ifdef AAC_DRIVER_BUILD
 		response.build = cpu_to_le32(AAC_DRIVER_BUILD);
 #	else
 		response.build = cpu_to_le32(9999);
@@ -475,7 +474,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 		return -EBUSY;
 	}
 	if (!capable(CAP_SYS_ADMIN)){
-		dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); 
+		dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n"));
 		return -EPERM;
 	}
 	/*
@@ -490,7 +489,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 
 	memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */
 	if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
-		dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); 
+		dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n"));
 		rcode = -EFAULT;
 		goto cleanup;
 	}
@@ -507,7 +506,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 		goto cleanup;
 	}
 	if(copy_from_user(user_srbcmd, user_srb,fibsize)){
-		dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n")); 
+		dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n"));
 		rcode = -EFAULT;
 		goto cleanup;
 	}
@@ -526,7 +525,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 	srbcmd->retry_limit = 0; // Obsolete parameter
 	srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size);
 	memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb));
-	
+
 	switch (flags & (SRB_DataIn | SRB_DataOut)) {
 	case SRB_DataOut:
 		data_dir = DMA_TO_DEVICE;
@@ -582,7 +581,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 				void* p;
 				/* Does this really need to be GFP_DMA? */
 				p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA);
-				if(p == 0) {
+				if(!p) {
 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
 					  upsg->sg[i].count,i,upsg->count));
 					rcode = -ENOMEM;
@@ -594,7 +593,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 				sg_list[i] = p; // save so we can clean up later
 				sg_indx = i;
 
-				if( flags & SRB_DataOut ){
+				if (flags & SRB_DataOut) {
 					if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
 						rcode = -EFAULT;
@@ -626,7 +625,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 				void* p;
 				/* Does this really need to be GFP_DMA? */
 				p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
-				if(p == 0) {
+				if(!p) {
 					kfree (usg);
 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
 					  usg->sg[i].count,i,usg->count));
@@ -637,7 +636,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 				sg_list[i] = p; // save so we can clean up later
 				sg_indx = i;
 
-				if( flags & SRB_DataOut ){
+				if (flags & SRB_DataOut) {
 					if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
 						kfree (usg);
 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
@@ -668,7 +667,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 				void* p;
 				/* Does this really need to be GFP_DMA? */
 				p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
-				if(p == 0) {
+				if(!p) {
 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
 					  usg->sg[i].count,i,usg->count));
 					rcode = -ENOMEM;
@@ -680,7 +679,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 				sg_list[i] = p; // save so we can clean up later
 				sg_indx = i;
 
-				if( flags & SRB_DataOut ){
+				if (flags & SRB_DataOut) {
 					if(copy_from_user(p,sg_user[i],usg->sg[i].count)){
 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
 						rcode = -EFAULT;
@@ -698,7 +697,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 				dma_addr_t addr;
 				void* p;
 				p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
-				if(p == 0) {
+				if (!p) {
 					dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
 					  upsg->sg[i].count, i, upsg->count));
 					rcode = -ENOMEM;
@@ -708,7 +707,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 				sg_list[i] = p; // save so we can clean up later
 				sg_indx = i;
 
-				if( flags & SRB_DataOut ){
+				if (flags & SRB_DataOut) {
 					if(copy_from_user(p, sg_user[i],
 							upsg->sg[i].count)) {
 						dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
@@ -734,19 +733,19 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 	}
 
 	if (status != 0){
-		dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); 
+		dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"));
 		rcode = -ENXIO;
 		goto cleanup;
 	}
 
-	if( flags & SRB_DataIn ) {
+	if (flags & SRB_DataIn) {
 		for(i = 0 ; i <= sg_indx; i++){
 			byte_count = le32_to_cpu(
 			  (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)
 			      ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count
 			      : srbcmd->sg.sg[i].count);
 			if(copy_to_user(sg_user[i], sg_list[i], byte_count)){
-				dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); 
+				dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n"));
 				rcode = -EFAULT;
 				goto cleanup;
 
@@ -756,7 +755,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
 
 	reply = (struct aac_srb_reply *) fib_data(srbfib);
 	if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
-		dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n")); 
+		dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n"));
 		rcode = -EFAULT;
 		goto cleanup;
 	}
@@ -775,34 +774,34 @@ cleanup:
 }
 
 struct aac_pci_info {
-        u32 bus;
-        u32 slot;
+	u32 bus;
+	u32 slot;
 };
 
 
 static int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
 {
-        struct aac_pci_info pci_info;
+	struct aac_pci_info pci_info;
 
 	pci_info.bus = dev->pdev->bus->number;
 	pci_info.slot = PCI_SLOT(dev->pdev->devfn);
 
        if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
-               dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
-               return -EFAULT;
+	       dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n"));
+	       return -EFAULT;
 	}
-        return 0;
+	return 0;
 }
- 
+
 
 int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
 {
 	int status;
-	
+
 	/*
 	 *	HBA gets first crack
 	 */
-	 
+
 	status = aac_dev_ioctl(dev, cmd, arg);
 	if(status != -ENOTTY)
 		return status;
@@ -832,7 +831,7 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
 		break;
 	default:
 		status = -ENOTTY;
-	  	break;	
+		break;
 	}
 	return status;
 }
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 8736813a0296..89cc8b7b42a2 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -301,10 +301,10 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
 	if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
 		0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) &&
 	 		(status[0] == 0x00000001)) {
-		if (status[1] & AAC_OPT_NEW_COMM_64)
+		if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
 			dev->raw_io_64 = 1;
 		if (dev->a_ops.adapter_comm &&
-		    (status[1] & AAC_OPT_NEW_COMM))
+		    (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)))
 			dev->comm_interface = AAC_COMM_MESSAGE;
 		if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
 		    (status[2] > dev->base_size)) {
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index abce48ccc85b..81b36923e0ef 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -56,7 +56,7 @@
  *	Allocate and map the shared PCI space for the FIB blocks used to
  *	talk to the Adaptec firmware.
  */
- 
+
 static int fib_map_alloc(struct aac_dev *dev)
 {
 	dprintk((KERN_INFO
@@ -109,14 +109,16 @@ int aac_fib_setup(struct aac_dev * dev)
 	}
 	if (i<0)
 		return -ENOMEM;
-		
+
 	hw_fib = dev->hw_fib_va;
 	hw_fib_pa = dev->hw_fib_pa;
 	memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
 	/*
 	 *	Initialise the fibs
 	 */
-	for (i = 0, fibptr = &dev->fibs[i]; i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++) 
+	for (i = 0, fibptr = &dev->fibs[i];
+		i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
+		i++, fibptr++)
 	{
 		fibptr->dev = dev;
 		fibptr->hw_fib_va = hw_fib;
@@ -148,13 +150,13 @@ int aac_fib_setup(struct aac_dev * dev)
  *	Allocate a fib from the adapter fib pool. If the pool is empty we
  *	return NULL.
  */
- 
+
 struct fib *aac_fib_alloc(struct aac_dev *dev)
 {
 	struct fib * fibptr;
 	unsigned long flags;
 	spin_lock_irqsave(&dev->fib_lock, flags);
-	fibptr = dev->free_fib;	
+	fibptr = dev->free_fib;
 	if(!fibptr){
 		spin_unlock_irqrestore(&dev->fib_lock, flags);
 		return fibptr;
@@ -171,6 +173,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
 	 *	each I/O
 	 */
 	fibptr->hw_fib_va->header.XferState = 0;
+	fibptr->flags = 0;
 	fibptr->callback = NULL;
 	fibptr->callback_data = NULL;
 
@@ -183,7 +186,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
  *
  *	Frees up a fib and places it on the appropriate queue
  */
- 
+
 void aac_fib_free(struct fib *fibptr)
 {
 	unsigned long flags;
@@ -204,10 +207,10 @@ void aac_fib_free(struct fib *fibptr)
 /**
  *	aac_fib_init	-	initialise a fib
  *	@fibptr: The fib to initialize
- *	
+ *
  *	Set up the generic fib fields ready for use
  */
- 
+
 void aac_fib_init(struct fib *fibptr)
 {
 	struct hw_fib *hw_fib = fibptr->hw_fib_va;
@@ -227,12 +230,12 @@ void aac_fib_init(struct fib *fibptr)
  *	Will deallocate and return to the free pool the FIB pointed to by the
  *	caller.
  */
- 
+
 static void fib_dealloc(struct fib * fibptr)
 {
 	struct hw_fib *hw_fib = fibptr->hw_fib_va;
 	BUG_ON(hw_fib->header.StructType != FIB_MAGIC);
-	hw_fib->header.XferState = 0;        
+	hw_fib->header.XferState = 0;
 }
 
 /*
@@ -241,7 +244,7 @@ static void fib_dealloc(struct fib * fibptr)
  *	these routines and are the only routines which have a knowledge of the
  *	 how these queues are implemented.
  */
- 
+
 /**
  *	aac_get_entry		-	get a queue entry
  *	@dev: Adapter
@@ -254,7 +257,7 @@ static void fib_dealloc(struct fib * fibptr)
  *	is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is
  *	returned.
  */
- 
+
 static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify)
 {
 	struct aac_queue * q;
@@ -279,26 +282,27 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr
 				idx = ADAP_NORM_RESP_ENTRIES;
 		}
 		if (idx != le32_to_cpu(*(q->headers.consumer)))
-			*nonotify = 1; 
+			*nonotify = 1;
 	}
 
 	if (qid == AdapNormCmdQueue) {
-	        if (*index >= ADAP_NORM_CMD_ENTRIES) 
+		if (*index >= ADAP_NORM_CMD_ENTRIES)
 			*index = 0; /* Wrap to front of the Producer Queue. */
 	} else {
-		if (*index >= ADAP_NORM_RESP_ENTRIES) 
+		if (*index >= ADAP_NORM_RESP_ENTRIES)
 			*index = 0; /* Wrap to front of the Producer Queue. */
 	}
 
-        if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
+	/* Queue is full */
+	if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) {
 		printk(KERN_WARNING "Queue %d full, %u outstanding.\n",
 				qid, q->numpending);
 		return 0;
 	} else {
-	        *entry = q->base + *index;
+		*entry = q->base + *index;
 		return 1;
 	}
-}   
+}
 
 /**
  *	aac_queue_get		-	get the next free QE
@@ -320,31 +324,29 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
 {
 	struct aac_entry * entry = NULL;
 	int map = 0;
-	    
+
 	if (qid == AdapNormCmdQueue) {
 		/*  if no entries wait for some if caller wants to */
-        	while (!aac_get_entry(dev, qid, &entry, index, nonotify)) 
-        	{
+		while (!aac_get_entry(dev, qid, &entry, index, nonotify)) {
 			printk(KERN_ERR "GetEntries failed\n");
 		}
-	        /*
-	         *	Setup queue entry with a command, status and fib mapped
-	         */
-	        entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
-	        map = 1;
+		/*
+		 *	Setup queue entry with a command, status and fib mapped
+		 */
+		entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
+		map = 1;
 	} else {
-	        while(!aac_get_entry(dev, qid, &entry, index, nonotify)) 
-	        {
+		while (!aac_get_entry(dev, qid, &entry, index, nonotify)) {
 			/* if no entries wait for some if caller wants to */
 		}
-        	/*
-        	 *	Setup queue entry with command, status and fib mapped
-        	 */
-        	entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
-        	entry->addr = hw_fib->header.SenderFibAddress;
-     			/* Restore adapters pointer to the FIB */
+		/*
+		 *	Setup queue entry with command, status and fib mapped
+		 */
+		entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
+		entry->addr = hw_fib->header.SenderFibAddress;
+			/* Restore adapters pointer to the FIB */
 		hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress;	/* Let the adapter now where to find its data */
-        	map = 0;
+		map = 0;
 	}
 	/*
 	 *	If MapFib is true than we need to map the Fib and put pointers
@@ -356,8 +358,8 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
 }
 
 /*
- *	Define the highest level of host to adapter communication routines. 
- *	These routines will support host to adapter FS commuication. These 
+ *	Define the highest level of host to adapter communication routines.
+ *	These routines will support host to adapter FS commuication. These
  *	routines have no knowledge of the commuication method used. This level
  *	sends and receives FIBs. This level has no knowledge of how these FIBs
  *	get passed back and forth.
@@ -379,7 +381,7 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
  *	an event to wait on must be supplied. This event will be set when a
  *	response FIB is received from the adapter.
  */
- 
+
 int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
 		int priority, int wait, int reply, fib_callback callback,
 		void *callback_data)
@@ -392,16 +394,17 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
 	if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
 		return -EBUSY;
 	/*
-	 *	There are 5 cases with the wait and reponse requested flags. 
+	 *	There are 5 cases with the wait and reponse requested flags.
 	 *	The only invalid cases are if the caller requests to wait and
 	 *	does not request a response and if the caller does not want a
 	 *	response and the Fib is not allocated from pool. If a response
 	 *	is not requesed the Fib will just be deallocaed by the DPC
 	 *	routine when the response comes back from the adapter. No
-	 *	further processing will be done besides deleting the Fib. We 
+	 *	further processing will be done besides deleting the Fib. We
 	 *	will have a debug mode where the adapter can notify the host
 	 *	it had a problem and the host can log that fact.
 	 */
+	fibptr->flags = 0;
 	if (wait && !reply) {
 		return -EINVAL;
 	} else if (!wait && reply) {
@@ -413,7 +416,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
 	} else if (wait && reply) {
 		hw_fib->header.XferState |= cpu_to_le32(ResponseExpected);
 		FIB_COUNTER_INCREMENT(aac_config.NormalSent);
-	} 
+	}
 	/*
 	 *	Map the fib into 32bits by using the fib number
 	 */
@@ -436,7 +439,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
 	hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size);
 	if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) {
 		return -EMSGSIZE;
-	}                
+	}
 	/*
 	 *	Get a queue entry connect the FIB to it and send an notify
 	 *	the adapter a command is ready.
@@ -450,10 +453,10 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
 	if (!wait) {
 		fibptr->callback = callback;
 		fibptr->callback_data = callback_data;
+		fibptr->flags = FIB_CONTEXT_FLAG;
 	}
 
 	fibptr->done = 0;
-	fibptr->flags = 0;
 
 	FIB_COUNTER_INCREMENT(aac_config.FibsSent);
 
@@ -473,9 +476,9 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
 	aac_adapter_deliver(fibptr);
 
 	/*
-	 *	If the caller wanted us to wait for response wait now. 
+	 *	If the caller wanted us to wait for response wait now.
 	 */
-    
+
 	if (wait) {
 		spin_unlock_irqrestore(&fibptr->event_lock, flags);
 		/* Only set for first known interruptable command */
@@ -522,7 +525,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
 		}
 		spin_unlock_irqrestore(&fibptr->event_lock, flags);
 		BUG_ON(fibptr->done == 0);
-			
+
 		if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
 			return -ETIMEDOUT;
 		return 0;
@@ -537,15 +540,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
 		return 0;
 }
 
-/** 
+/**
  *	aac_consumer_get	-	get the top of the queue
  *	@dev: Adapter
  *	@q: Queue
  *	@entry: Return entry
  *
  *	Will return a pointer to the entry on the top of the queue requested that
- * 	we are a consumer of, and return the address of the queue entry. It does
- *	not change the state of the queue. 
+ *	we are a consumer of, and return the address of the queue entry. It does
+ *	not change the state of the queue.
  */
 
 int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry)
@@ -560,10 +563,10 @@ int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entr
 		 *	the end of the queue, else we just use the entry
 		 *	pointed to by the header index
 		 */
-		if (le32_to_cpu(*q->headers.consumer) >= q->entries) 
-			index = 0;		
+		if (le32_to_cpu(*q->headers.consumer) >= q->entries)
+			index = 0;
 		else
-		        index = le32_to_cpu(*q->headers.consumer);
+			index = le32_to_cpu(*q->headers.consumer);
 		*entry = q->base + index;
 		status = 1;
 	}
@@ -587,12 +590,12 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
 
 	if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer))
 		wasfull = 1;
-        
+
 	if (le32_to_cpu(*q->headers.consumer) >= q->entries)
 		*q->headers.consumer = cpu_to_le32(1);
 	else
 		*q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1);
-        
+
 	if (wasfull) {
 		switch (qid) {
 
@@ -608,7 +611,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
 		}
 		aac_adapter_notify(dev, notify);
 	}
-}        
+}
 
 /**
  *	aac_fib_adapter_complete	-	complete adapter issued fib
@@ -630,32 +633,32 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
 	if (hw_fib->header.XferState == 0) {
 		if (dev->comm_interface == AAC_COMM_MESSAGE)
 			kfree (hw_fib);
-        	return 0;
+		return 0;
 	}
 	/*
 	 *	If we plan to do anything check the structure type first.
-	 */ 
-	if ( hw_fib->header.StructType != FIB_MAGIC ) {
+	 */
+	if (hw_fib->header.StructType != FIB_MAGIC) {
 		if (dev->comm_interface == AAC_COMM_MESSAGE)
 			kfree (hw_fib);
-        	return -EINVAL;
+		return -EINVAL;
 	}
 	/*
 	 *	This block handles the case where the adapter had sent us a
 	 *	command and we have finished processing the command. We
-	 *	call completeFib when we are done processing the command 
-	 *	and want to send a response back to the adapter. This will 
+	 *	call completeFib when we are done processing the command
+	 *	and want to send a response back to the adapter. This will
 	 *	send the completed cdb to the adapter.
 	 */
 	if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
 		if (dev->comm_interface == AAC_COMM_MESSAGE) {
 			kfree (hw_fib);
 		} else {
-	       		u32 index;
-		        hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
+			u32 index;
+			hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
 			if (size) {
 				size += sizeof(struct aac_fibhdr);
-				if (size > le16_to_cpu(hw_fib->header.SenderSize)) 
+				if (size > le16_to_cpu(hw_fib->header.SenderSize))
 					return -EMSGSIZE;
 				hw_fib->header.Size = cpu_to_le16(size);
 			}
@@ -667,12 +670,11 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
 			if (!(nointr & (int)aac_config.irq_mod))
 				aac_adapter_notify(dev, AdapNormRespQueue);
 		}
+	} else {
+		printk(KERN_WARNING "aac_fib_adapter_complete: "
+			"Unknown xferstate detected.\n");
+		BUG();
 	}
-	else 
-	{
-        	printk(KERN_WARNING "aac_fib_adapter_complete: Unknown xferstate detected.\n");
-        	BUG();
-	}   
 	return 0;
 }
 
@@ -682,7 +684,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
  *
  *	Will do all necessary work to complete a FIB.
  */
- 
+
 int aac_fib_complete(struct fib *fibptr)
 {
 	struct hw_fib * hw_fib = fibptr->hw_fib_va;
@@ -692,15 +694,15 @@ int aac_fib_complete(struct fib *fibptr)
 	 */
 
 	if (hw_fib->header.XferState == 0)
-        	return 0;
+		return 0;
 	/*
 	 *	If we plan to do anything check the structure type first.
-	 */ 
+	 */
 
 	if (hw_fib->header.StructType != FIB_MAGIC)
-	        return -EINVAL;
+		return -EINVAL;
 	/*
-	 *	This block completes a cdb which orginated on the host and we 
+	 *	This block completes a cdb which orginated on the host and we
 	 *	just need to deallocate the cdb or reinit it. At this point the
 	 *	command is complete that we had sent to the adapter and this
 	 *	cdb could be reused.
@@ -721,7 +723,7 @@ int aac_fib_complete(struct fib *fibptr)
 		fib_dealloc(fibptr);
 	} else {
 		BUG();
-	}   
+	}
 	return 0;
 }
 
@@ -741,7 +743,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
 	{
 		int length = val & 0xffff;
 		int level = (val >> 16) & 0xffff;
-		
+
 		/*
 		 *	The size of the printfbuf is set in port.c
 		 *	There is no variable or define for it
@@ -755,7 +757,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
 		else
 			printk(KERN_INFO "%s:%s", dev->name, cp);
 	}
-	memset(cp, 0,  256);
+	memset(cp, 0, 256);
 }
 
 
@@ -773,20 +775,20 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 {
 	struct hw_fib * hw_fib = fibptr->hw_fib_va;
 	struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
-	u32 container;
+	u32 channel, id, lun, container;
 	struct scsi_device *device;
 	enum {
 		NOTHING,
 		DELETE,
 		ADD,
 		CHANGE
-	} device_config_needed;
+	} device_config_needed = NOTHING;
 
 	/* Sniff for container changes */
 
 	if (!dev || !dev->fsa_dev)
 		return;
-	container = (u32)-1;
+	container = channel = id = lun = (u32)-1;
 
 	/*
 	 *	We have set this up to try and minimize the number of
@@ -796,13 +798,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 	 */
 	switch (le32_to_cpu(aifcmd->command)) {
 	case AifCmdDriverNotify:
-		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
+		switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) {
 		/*
 		 *	Morph or Expand complete
 		 */
 		case AifDenMorphComplete:
 		case AifDenVolumeExtendComplete:
-			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
 			if (container >= dev->maximum_num_containers)
 				break;
 
@@ -814,9 +816,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 			 */
 
 			if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) {
-				device = scsi_device_lookup(dev->scsi_host_ptr, 
-					CONTAINER_TO_CHANNEL(container), 
-					CONTAINER_TO_ID(container), 
+				device = scsi_device_lookup(dev->scsi_host_ptr,
+					CONTAINER_TO_CHANNEL(container),
+					CONTAINER_TO_ID(container),
 					CONTAINER_TO_LUN(container));
 				if (device) {
 					dev->fsa_dev[container].config_needed = CHANGE;
@@ -835,25 +837,29 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 			if (container >= dev->maximum_num_containers)
 				break;
 			if ((dev->fsa_dev[container].config_waiting_on ==
-			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
+			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
 				dev->fsa_dev[container].config_waiting_on = 0;
 		} else for (container = 0;
 		    container < dev->maximum_num_containers; ++container) {
 			if ((dev->fsa_dev[container].config_waiting_on ==
-			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
+			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
 				dev->fsa_dev[container].config_waiting_on = 0;
 		}
 		break;
 
 	case AifCmdEventNotify:
-		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
+		switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) {
+		case AifEnBatteryEvent:
+			dev->cache_protected =
+				(((__le32 *)aifcmd->data)[1] == cpu_to_le32(3));
+			break;
 		/*
 		 *	Add an Array.
 		 */
 		case AifEnAddContainer:
-			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
 			if (container >= dev->maximum_num_containers)
 				break;
 			dev->fsa_dev[container].config_needed = ADD;
@@ -866,7 +872,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 		 *	Delete an Array.
 		 */
 		case AifEnDeleteContainer:
-			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
 			if (container >= dev->maximum_num_containers)
 				break;
 			dev->fsa_dev[container].config_needed = DELETE;
@@ -880,7 +886,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 		 * waiting on something else, setup to wait on a Config Change.
 		 */
 		case AifEnContainerChange:
-			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
 			if (container >= dev->maximum_num_containers)
 				break;
 			if (dev->fsa_dev[container].config_waiting_on &&
@@ -895,6 +901,60 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 		case AifEnConfigChange:
 			break;
 
+		case AifEnAddJBOD:
+		case AifEnDeleteJBOD:
+			container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
+			if ((container >> 28))
+				break;
+			channel = (container >> 24) & 0xF;
+			if (channel >= dev->maximum_num_channels)
+				break;
+			id = container & 0xFFFF;
+			if (id >= dev->maximum_num_physicals)
+				break;
+			lun = (container >> 16) & 0xFF;
+			channel = aac_phys_to_logical(channel);
+			device_config_needed =
+			  (((__le32 *)aifcmd->data)[0] ==
+			    cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE;
+			break;
+
+		case AifEnEnclosureManagement:
+			/*
+			 * If in JBOD mode, automatic exposure of new
+			 * physical target to be suppressed until configured.
+			 */
+			if (dev->jbod)
+				break;
+			switch (le32_to_cpu(((__le32 *)aifcmd->data)[3])) {
+			case EM_DRIVE_INSERTION:
+			case EM_DRIVE_REMOVAL:
+				container = le32_to_cpu(
+					((__le32 *)aifcmd->data)[2]);
+				if ((container >> 28))
+					break;
+				channel = (container >> 24) & 0xF;
+				if (channel >= dev->maximum_num_channels)
+					break;
+				id = container & 0xFFFF;
+				lun = (container >> 16) & 0xFF;
+				if (id >= dev->maximum_num_physicals) {
+					/* legacy dev_t ? */
+					if ((0x2000 <= id) || lun || channel ||
+					  ((channel = (id >> 7) & 0x3F) >=
+					  dev->maximum_num_channels))
+						break;
+					lun = (id >> 4) & 7;
+					id &= 0xF;
+				}
+				channel = aac_phys_to_logical(channel);
+				device_config_needed =
+				  (((__le32 *)aifcmd->data)[3]
+				    == cpu_to_le32(EM_DRIVE_INSERTION)) ?
+				  ADD : DELETE;
+				break;
+			}
+			break;
 		}
 
 		/*
@@ -905,13 +965,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 			if (container >= dev->maximum_num_containers)
 				break;
 			if ((dev->fsa_dev[container].config_waiting_on ==
-			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
+			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
 				dev->fsa_dev[container].config_waiting_on = 0;
 		} else for (container = 0;
 		    container < dev->maximum_num_containers; ++container) {
 			if ((dev->fsa_dev[container].config_waiting_on ==
-			    le32_to_cpu(*(u32 *)aifcmd->data)) &&
+			    le32_to_cpu(*(__le32 *)aifcmd->data)) &&
 			 time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT))
 				dev->fsa_dev[container].config_waiting_on = 0;
 		}
@@ -926,9 +986,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 		 * wait for a container change.
 		 */
 
-		if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
-		 && ((((u32 *)aifcmd->data)[6] == ((u32 *)aifcmd->data)[5])
-		  || (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess)))) {
+		if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) &&
+		    (((__le32 *)aifcmd->data)[6] == ((__le32 *)aifcmd->data)[5] ||
+		     ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess))) {
 			for (container = 0;
 			    container < dev->maximum_num_containers;
 			    ++container) {
@@ -943,9 +1003,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 					jiffies;
 			}
 		}
-		if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
-		 && (((u32 *)aifcmd->data)[6] == 0)
-		 && (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning))) {
+		if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) &&
+		    ((__le32 *)aifcmd->data)[6] == 0 &&
+		    ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning)) {
 			for (container = 0;
 			    container < dev->maximum_num_containers;
 			    ++container) {
@@ -963,7 +1023,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 		break;
 	}
 
-	device_config_needed = NOTHING;
+	if (device_config_needed == NOTHING)
 	for (container = 0; container < dev->maximum_num_containers;
 	    ++container) {
 		if ((dev->fsa_dev[container].config_waiting_on == 0) &&
@@ -972,6 +1032,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 			device_config_needed =
 				dev->fsa_dev[container].config_needed;
 			dev->fsa_dev[container].config_needed = NOTHING;
+			channel = CONTAINER_TO_CHANNEL(container);
+			id = CONTAINER_TO_ID(container);
+			lun = CONTAINER_TO_LUN(container);
 			break;
 		}
 	}
@@ -995,34 +1058,56 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 	/*
 	 * force reload of disk info via aac_probe_container
 	 */
-	if ((device_config_needed == CHANGE)
-	 && (dev->fsa_dev[container].valid == 1))
-		dev->fsa_dev[container].valid = 2;
-	if ((device_config_needed == CHANGE) ||
-			(device_config_needed == ADD))
+	if ((channel == CONTAINER_CHANNEL) &&
+	  (device_config_needed != NOTHING)) {
+		if (dev->fsa_dev[container].valid == 1)
+			dev->fsa_dev[container].valid = 2;
 		aac_probe_container(dev, container);
-	device = scsi_device_lookup(dev->scsi_host_ptr, 
-		CONTAINER_TO_CHANNEL(container), 
-		CONTAINER_TO_ID(container), 
-		CONTAINER_TO_LUN(container));
+	}
+	device = scsi_device_lookup(dev->scsi_host_ptr, channel, id, lun);
 	if (device) {
 		switch (device_config_needed) {
 		case DELETE:
+			if (scsi_device_online(device)) {
+				scsi_device_set_state(device, SDEV_OFFLINE);
+				sdev_printk(KERN_INFO, device,
+					"Device offlined - %s\n",
+					(channel == CONTAINER_CHANNEL) ?
+						"array deleted" :
+						"enclosure services event");
+			}
+			break;
+		case ADD:
+			if (!scsi_device_online(device)) {
+				sdev_printk(KERN_INFO, device,
+					"Device online - %s\n",
+					(channel == CONTAINER_CHANNEL) ?
+						"array created" :
+						"enclosure services event");
+				scsi_device_set_state(device, SDEV_RUNNING);
+			}
+			/* FALLTHRU */
 		case CHANGE:
+			if ((channel == CONTAINER_CHANNEL)
+			 && (!dev->fsa_dev[container].valid)) {
+				if (!scsi_device_online(device))
+					break;
+				scsi_device_set_state(device, SDEV_OFFLINE);
+				sdev_printk(KERN_INFO, device,
+					"Device offlined - %s\n",
+					"array failed");
+				break;
+			}
 			scsi_rescan_device(&device->sdev_gendev);
 
 		default:
 			break;
 		}
 		scsi_device_put(device);
+		device_config_needed = NOTHING;
 	}
-	if (device_config_needed == ADD) {
-		scsi_add_device(dev->scsi_host_ptr,
-		  CONTAINER_TO_CHANNEL(container),
-		  CONTAINER_TO_ID(container),
-		  CONTAINER_TO_LUN(container));
-	}
-
+	if (device_config_needed == ADD)
+		scsi_add_device(dev->scsi_host_ptr, channel, id, lun);
 }
 
 static int _aac_reset_adapter(struct aac_dev *aac, int forced)
@@ -1099,7 +1184,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
 	free_irq(aac->pdev->irq, aac);
 	kfree(aac->fsa_dev);
 	aac->fsa_dev = NULL;
-	if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
+	quirks = aac_get_driver_ident(index)->quirks;
+	if (quirks & AAC_QUIRK_31BIT) {
 		if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) ||
 		  ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK))))
 			goto out;
@@ -1110,7 +1196,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
 	}
 	if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
 		goto out;
-	if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
+	if (quirks & AAC_QUIRK_31BIT)
 		if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
 			goto out;
 	if (jafo) {
@@ -1121,15 +1207,14 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
 		}
 	}
 	(void)aac_get_adapter_info(aac);
-	quirks = aac_get_driver_ident(index)->quirks;
 	if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) {
- 		host->sg_tablesize = 34;
- 		host->max_sectors = (host->sg_tablesize * 8) + 112;
- 	}
- 	if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
- 		host->sg_tablesize = 17;
- 		host->max_sectors = (host->sg_tablesize * 8) + 112;
- 	}
+		host->sg_tablesize = 34;
+		host->max_sectors = (host->sg_tablesize * 8) + 112;
+	}
+	if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
+		host->sg_tablesize = 17;
+		host->max_sectors = (host->sg_tablesize * 8) + 112;
+	}
 	aac_get_config_status(aac, 1);
 	aac_get_containers(aac);
 	/*
@@ -1217,12 +1302,13 @@ int aac_reset_adapter(struct aac_dev * aac, int forced)
 	}
 
 	/* Quiesce build, flush cache, write through mode */
-	aac_send_shutdown(aac);
+	if (forced < 2)
+		aac_send_shutdown(aac);
 	spin_lock_irqsave(host->host_lock, flagv);
-	retval = _aac_reset_adapter(aac, forced);
+	retval = _aac_reset_adapter(aac, forced ? forced : ((aac_check_reset != 0) && (aac_check_reset != 1)));
 	spin_unlock_irqrestore(host->host_lock, flagv);
 
-	if (retval == -ENODEV) {
+	if ((forced < 2) && (retval == -ENODEV)) {
 		/* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */
 		struct fib * fibctx = aac_fib_alloc(aac);
 		if (fibctx) {
@@ -1338,11 +1424,11 @@ int aac_check_health(struct aac_dev * aac)
 			fib->data = hw_fib->data;
 			aif = (struct aac_aifcmd *)hw_fib->data;
 			aif->command = cpu_to_le32(AifCmdEventNotify);
-		 	aif->seqnum = cpu_to_le32(0xFFFFFFFF);
-			aif->data[0] = AifEnExpEvent;
-			aif->data[1] = AifExeFirmwarePanic;
-			aif->data[2] = AifHighPriority;
-			aif->data[3] = BlinkLED;
+			aif->seqnum = cpu_to_le32(0xFFFFFFFF);
+			((__le32 *)aif->data)[0] = cpu_to_le32(AifEnExpEvent);
+			((__le32 *)aif->data)[1] = cpu_to_le32(AifExeFirmwarePanic);
+			((__le32 *)aif->data)[2] = cpu_to_le32(AifHighPriority);
+			((__le32 *)aif->data)[3] = cpu_to_le32(BlinkLED);
 
 			/*
 			 * Put the FIB onto the
@@ -1372,14 +1458,14 @@ int aac_check_health(struct aac_dev * aac)
 
 	printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
 
-	if (!aac_check_reset ||
+	if (!aac_check_reset || ((aac_check_reset != 1) &&
 		(aac->supplement_adapter_info.SupportedOptions2 &
-			le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
+			AAC_OPTION_IGNORE_RESET)))
 		goto out;
 	host = aac->scsi_host_ptr;
 	if (aac->thread->pid != current->pid)
 		spin_lock_irqsave(host->host_lock, flagv);
-	BlinkLED = _aac_reset_adapter(aac, 0);
+	BlinkLED = _aac_reset_adapter(aac, aac_check_reset != 1);
 	if (aac->thread->pid != current->pid)
 		spin_unlock_irqrestore(host->host_lock, flagv);
 	return BlinkLED;
@@ -1399,7 +1485,7 @@ out:
  *	until the queue is empty. When the queue is empty it will wait for
  *	more FIBs.
  */
- 
+
 int aac_command_thread(void *data)
 {
 	struct aac_dev *dev = data;
@@ -1425,30 +1511,29 @@ int aac_command_thread(void *data)
 	add_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	dprintk ((KERN_INFO "aac_command_thread start\n"));
-	while(1) 
-	{
+	while (1) {
 		spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags);
 		while(!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) {
 			struct list_head *entry;
 			struct aac_aifcmd * aifcmd;
 
 			set_current_state(TASK_RUNNING);
-	
+
 			entry = dev->queues->queue[HostNormCmdQueue].cmdq.next;
 			list_del(entry);
-		
+
 			spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
 			fib = list_entry(entry, struct fib, fiblink);
 			/*
-			 *	We will process the FIB here or pass it to a 
-			 *	worker thread that is TBD. We Really can't 
+			 *	We will process the FIB here or pass it to a
+			 *	worker thread that is TBD. We Really can't
 			 *	do anything at this point since we don't have
 			 *	anything defined for this thread to do.
 			 */
 			hw_fib = fib->hw_fib_va;
 			memset(fib, 0, sizeof(struct fib));
 			fib->type = FSAFS_NTC_FIB_CONTEXT;
-			fib->size = sizeof( struct fib );
+			fib->size = sizeof(struct fib);
 			fib->hw_fib_va = hw_fib;
 			fib->data = hw_fib->data;
 			fib->dev = dev;
@@ -1462,20 +1547,19 @@ int aac_command_thread(void *data)
 				*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
 				aac_fib_adapter_complete(fib, (u16)sizeof(u32));
 			} else {
-				struct list_head *entry;
 				/* The u32 here is important and intended. We are using
 				   32bit wrapping time to fit the adapter field */
-				   
+
 				u32 time_now, time_last;
 				unsigned long flagv;
 				unsigned num;
 				struct hw_fib ** hw_fib_pool, ** hw_fib_p;
 				struct fib ** fib_pool, ** fib_p;
-			
+
 				/* Sniff events */
-				if ((aifcmd->command == 
+				if ((aifcmd->command ==
 				     cpu_to_le32(AifCmdEventNotify)) ||
-				    (aifcmd->command == 
+				    (aifcmd->command ==
 				     cpu_to_le32(AifCmdJobProgress))) {
 					aac_handle_aif(dev, fib);
 				}
@@ -1527,7 +1611,7 @@ int aac_command_thread(void *data)
 				spin_lock_irqsave(&dev->fib_lock, flagv);
 				entry = dev->fib_list.next;
 				/*
-				 * For each Context that is on the 
+				 * For each Context that is on the
 				 * fibctxList, make a copy of the
 				 * fib, and then set the event to wake up the
 				 * thread that is waiting for it.
@@ -1552,7 +1636,7 @@ int aac_command_thread(void *data)
 						 */
 						time_last = fibctx->jiffies;
 						/*
-						 * Has it been > 2 minutes 
+						 * Has it been > 2 minutes
 						 * since the last read off
 						 * the queue?
 						 */
@@ -1583,7 +1667,7 @@ int aac_command_thread(void *data)
 						 */
 						list_add_tail(&newfib->fiblink, &fibctx->fib_list);
 						fibctx->count++;
-						/* 
+						/*
 						 * Set the event to wake up the
 						 * thread that is waiting.
 						 */
@@ -1655,11 +1739,11 @@ int aac_command_thread(void *data)
 				struct fib *fibptr;
 
 				if ((fibptr = aac_fib_alloc(dev))) {
-					u32 * info;
+					__le32 *info;
 
 					aac_fib_init(fibptr);
 
-					info = (u32 *) fib_data(fibptr);
+					info = (__le32 *) fib_data(fibptr);
 					if (now.tv_usec > 500000)
 						++now.tv_sec;
 
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index e6032ffc66a6..d1163ded132b 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -120,6 +120,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
 			 *	NOTE:  we cannot touch the fib after this
 			 *	    call, because it may have been deallocated.
 			 */
+			fib->flags = 0;
 			fib->callback(fib->callback_data, fib);
 		} else {
 			unsigned long flagv;
@@ -229,11 +230,9 @@ unsigned int aac_command_normal(struct aac_queue *q)
  *	all QE there are and wake up all the waiters before exiting.
  */
 
-unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
+unsigned int aac_intr_normal(struct aac_dev * dev, u32 index)
 {
-	u32 index = le32_to_cpu(Index);
-
-	dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, Index));
+	dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index));
 	if ((index & 0x00000002L)) {
 		struct hw_fib * hw_fib;
 		struct fib * fib;
@@ -301,7 +300,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
 
 		if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
 		{
-			u32 *pstatus = (u32 *)hwfib->data;
+			__le32 *pstatus = (__le32 *)hwfib->data;
 			if (*pstatus & cpu_to_le32(0xffff0000))
 				*pstatus = cpu_to_le32(ST_OK);
 		}
@@ -315,6 +314,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
 			 *	NOTE:  we cannot touch the fib after this
 			 *	    call, because it may have been deallocated.
 			 */
+			fib->flags = 0;
 			fib->callback(fib->callback_data, fib);
 		} else {
 			unsigned long flagv;
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 9dd331bc29b0..0e8267c1e915 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -159,27 +159,27 @@ static struct pci_device_id aac_pci_tbl[] = {
 MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
 
 /*
- * dmb - For now we add the number of channels to this structure.  
+ * dmb - For now we add the number of channels to this structure.
  * In the future we should add a fib that reports the number of channels
  * for the card.  At that time we can remove the channels from here
  */
 static struct aac_driver_ident aac_drivers[] = {
-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 2/Si (Iguana/PERC2Si) */
-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Opal/PERC3Di) */
-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Si (SlimFast/PERC3Si */
-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Viper/PERC3DiV) */
-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Lexus/PERC3DiL) */
-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Dagger/PERC3DiD) */
-	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Boxster/PERC3DiB) */
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* catapult */
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* tomcat */
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */
-	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan-2m) */
-	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S220 (Legend Crusader) */
-	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S230 (Legend Vulcan) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 2/Si (Iguana/PERC2Si) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Opal/PERC3Di) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Si (SlimFast/PERC3Si */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Viper/PERC3DiV) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Lexus/PERC3DiL) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Dagger/PERC3DiD) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Boxster/PERC3DiB) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* catapult */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* tomcat */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2120S (Crusader) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan-2m) */
+	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S220 (Legend Crusader) */
+	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S230 (Legend Vulcan) */
 
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3230S   ", 2 }, /* Adaptec 3230S (Harrier) */
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3240S   ", 2 }, /* Adaptec 3240S (Tornado) */
@@ -224,8 +224,8 @@ static struct aac_driver_ident aac_drivers[] = {
 	{ aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */
 	{ aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */
 
-	{ aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */
-	{ aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */
+	{ aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Dell Catchall */
+	{ aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */
 	{ aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Catch All */
 	{ aac_rkt_init, "aacraid", "ADAPTEC ", "RAID            ", 2 }, /* Adaptec Rocket Catch All */
 	{ aac_nark_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec NEMER/ARK Catch All */
@@ -239,7 +239,7 @@ static struct aac_driver_ident aac_drivers[] = {
  *	Queues a command for execution by the associated Host Adapter.
  *
  *	TODO: unify with aac_scsi_cmd().
- */ 
+ */
 
 static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
@@ -258,7 +258,7 @@ static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd
 	}
 	cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
 	return (aac_scsi_cmd(cmd) ? FAILED : 0);
-} 
+}
 
 /**
  *	aac_info		-	Returns the host adapter name
@@ -292,21 +292,21 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype)
  *	@capacity: the sector capacity of the disk
  *	@geom: geometry block to fill in
  *
- *	Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.  
- *	The default disk geometry is 64 heads, 32 sectors, and the appropriate 
- *	number of cylinders so as not to exceed drive capacity.  In order for 
+ *	Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.
+ *	The default disk geometry is 64 heads, 32 sectors, and the appropriate
+ *	number of cylinders so as not to exceed drive capacity.  In order for
  *	disks equal to or larger than 1 GB to be addressable by the BIOS
- *	without exceeding the BIOS limitation of 1024 cylinders, Extended 
- *	Translation should be enabled.   With Extended Translation enabled, 
- *	drives between 1 GB inclusive and 2 GB exclusive are given a disk 
- *	geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive 
- *	are given a disk geometry of 255 heads and 63 sectors.  However, if 
- *	the BIOS detects that the Extended Translation setting does not match 
- *	the geometry in the partition table, then the translation inferred 
- *	from the partition table will be used by the BIOS, and a warning may 
+ *	without exceeding the BIOS limitation of 1024 cylinders, Extended
+ *	Translation should be enabled.   With Extended Translation enabled,
+ *	drives between 1 GB inclusive and 2 GB exclusive are given a disk
+ *	geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive
+ *	are given a disk geometry of 255 heads and 63 sectors.  However, if
+ *	the BIOS detects that the Extended Translation setting does not match
+ *	the geometry in the partition table, then the translation inferred
+ *	from the partition table will be used by the BIOS, and a warning may
  *	be displayed.
  */
- 
+
 static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
 			sector_t capacity, int *geom)
 {
@@ -333,10 +333,10 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
 
 	param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors);
 
-	/* 
+	/*
 	 *	Read the first 1024 bytes from the disk device, if the boot
 	 *	sector partition table is valid, search for a partition table
-	 *	entry whose end_head matches one of the standard geometry 
+	 *	entry whose end_head matches one of the standard geometry
 	 *	translations ( 64/32, 128/32, 255/63 ).
 	 */
 	buf = scsi_bios_ptable(bdev);
@@ -401,30 +401,44 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
 
 static int aac_slave_configure(struct scsi_device *sdev)
 {
+	struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
 	if ((sdev->type == TYPE_DISK) &&
-			(sdev_channel(sdev) != CONTAINER_CHANNEL)) {
+			(sdev_channel(sdev) != CONTAINER_CHANNEL) &&
+			(!aac->jbod || sdev->inq_periph_qual) &&
+			(!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))) {
 		if (expose_physicals == 0)
 			return -ENXIO;
-		if (expose_physicals < 0) {
-			struct aac_dev *aac =
-				(struct aac_dev *)sdev->host->hostdata;
-			if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
-				sdev->no_uld_attach = 1;
-		}
+		if (expose_physicals < 0)
+			sdev->no_uld_attach = 1;
 	}
 	if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
-			(sdev_channel(sdev) == CONTAINER_CHANNEL)) {
+			(!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) &&
+			!sdev->no_uld_attach) {
 		struct scsi_device * dev;
 		struct Scsi_Host *host = sdev->host;
 		unsigned num_lsu = 0;
 		unsigned num_one = 0;
 		unsigned depth;
+		unsigned cid;
 
+		/*
+		 * Firmware has an individual device recovery time typically
+		 * of 35 seconds, give us a margin.
+		 */
+		if (sdev->timeout < (45 * HZ))
+			sdev->timeout = 45 * HZ;
+		for (cid = 0; cid < aac->maximum_num_containers; ++cid)
+			if (aac->fsa_dev[cid].valid)
+				++num_lsu;
 		__shost_for_each_device(dev, host) {
 			if (dev->tagged_supported && (dev->type == TYPE_DISK) &&
-				(sdev_channel(dev) == CONTAINER_CHANNEL))
-				++num_lsu;
-			else
+					(!aac->raid_scsi_mode ||
+						(sdev_channel(sdev) != 2)) &&
+					!dev->no_uld_attach) {
+				if ((sdev_channel(dev) != CONTAINER_CHANNEL)
+				 || !aac->fsa_dev[sdev_id(dev)].valid)
+					++num_lsu;
+			} else
 				++num_one;
 		}
 		if (num_lsu == 0)
@@ -481,9 +495,35 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
 	return sdev->queue_depth;
 }
 
+static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct scsi_device * sdev = to_scsi_device(dev);
+	if (sdev_channel(sdev) != CONTAINER_CHANNEL)
+		return snprintf(buf, PAGE_SIZE, sdev->no_uld_attach
+		  ? "Hidden\n" : "JBOD");
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+	  get_container_type(((struct aac_dev *)(sdev->host->hostdata))
+	    ->fsa_dev[sdev_id(sdev)].type));
+}
+
+static struct device_attribute aac_raid_level_attr = {
+	.attr = {
+		.name = "level",
+		.mode = S_IRUGO,
+	},
+	.show = aac_show_raid_level
+};
+
+static struct device_attribute *aac_dev_attrs[] = {
+	&aac_raid_level_attr,
+	NULL,
+};
+
 static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
 {
 	struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
 	return aac_do_ioctl(dev, cmd, arg);
 }
 
@@ -506,17 +546,33 @@ static int aac_eh_abort(struct scsi_cmnd* cmd)
 			break;
 	case INQUIRY:
 	case READ_CAPACITY:
-	case TEST_UNIT_READY:
 		/* Mark associated FIB to not complete, eh handler does this */
 		for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
 			struct fib * fib = &aac->fibs[count];
 			if (fib->hw_fib_va->header.XferState &&
+			  (fib->flags & FIB_CONTEXT_FLAG) &&
 			  (fib->callback_data == cmd)) {
 				fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
 				cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
 				ret = SUCCESS;
 			}
 		}
+		break;
+	case TEST_UNIT_READY:
+		/* Mark associated FIB to not complete, eh handler does this */
+		for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+			struct scsi_cmnd * command;
+			struct fib * fib = &aac->fibs[count];
+			if ((fib->hw_fib_va->header.XferState & cpu_to_le32(Async | NoResponseExpected)) &&
+			  (fib->flags & FIB_CONTEXT_FLAG) &&
+			  ((command = fib->callback_data)) &&
+			  (command->device == cmd->device)) {
+				fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+				command->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+				if (command == cmd)
+					ret = SUCCESS;
+			}
+		}
 	}
 	return ret;
 }
@@ -539,12 +595,13 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
 	for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
 		struct fib * fib = &aac->fibs[count];
 		if (fib->hw_fib_va->header.XferState &&
+		  (fib->flags & FIB_CONTEXT_FLAG) &&
 		  (fib->callback_data == cmd)) {
 			fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
 			cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
 		}
 	}
-	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", 
+	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
 					AAC_DRIVERNAME);
 
 	if ((count = aac_check_health(aac)))
@@ -584,8 +641,11 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
 	 * support a register, instead of a commanded, reset.
 	 */
 	if ((aac->supplement_adapter_info.SupportedOptions2 &
-	  le32_to_cpu(AAC_OPTION_MU_RESET|AAC_OPTION_IGNORE_RESET)) ==
-	  le32_to_cpu(AAC_OPTION_MU_RESET))
+	   AAC_OPTION_MU_RESET) &&
+	  aac_check_reset &&
+	  ((aac_check_reset != 1) ||
+	   (aac->supplement_adapter_info.SupportedOptions2 &
+	    AAC_OPTION_IGNORE_RESET)))
 		aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */
 	return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
 }
@@ -632,8 +692,8 @@ static int aac_cfg_open(struct inode *inode, struct file *file)
  *	Bugs: Needs locking against parallel ioctls lower down
  *	Bugs: Needs to handle hot plugging
  */
- 
-static int aac_cfg_ioctl(struct inode *inode,  struct file *file,
+
+static int aac_cfg_ioctl(struct inode *inode, struct file *file,
 		unsigned int cmd, unsigned long arg)
 {
 	if (!capable(CAP_SYS_RAWIO))
@@ -646,7 +706,7 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
 {
 	long ret;
 	lock_kernel();
-	switch (cmd) { 
+	switch (cmd) {
 	case FSACTL_MINIPORT_REV_CHECK:
 	case FSACTL_SENDFIB:
 	case FSACTL_OPEN_GET_ADAPTER_FIB:
@@ -656,14 +716,14 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
 	case FSACTL_QUERY_DISK:
 	case FSACTL_DELETE_DISK:
 	case FSACTL_FORCE_DELETE_DISK:
-	case FSACTL_GET_CONTAINERS: 
+	case FSACTL_GET_CONTAINERS:
 	case FSACTL_SEND_LARGE_FIB:
 		ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
 		break;
 
 	case FSACTL_GET_NEXT_ADAPTER_FIB: {
 		struct fib_ioctl __user *f;
-		
+
 		f = compat_alloc_user_space(sizeof(*f));
 		ret = 0;
 		if (clear_user(f, sizeof(*f)))
@@ -676,9 +736,9 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long
 	}
 
 	default:
-		ret = -ENOIOCTLCMD; 
+		ret = -ENOIOCTLCMD;
 		break;
-	} 
+	}
 	unlock_kernel();
 	return ret;
 }
@@ -735,6 +795,25 @@ static ssize_t aac_show_vendor(struct class_device *class_dev,
 	return len;
 }
 
+static ssize_t aac_show_flags(struct class_device *class_dev, char *buf)
+{
+	int len = 0;
+	struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+
+	if (nblank(dprintk(x)))
+		len = snprintf(buf, PAGE_SIZE, "dprintk\n");
+#ifdef AAC_DETAILED_STATUS_INFO
+	len += snprintf(buf + len, PAGE_SIZE - len,
+			"AAC_DETAILED_STATUS_INFO\n");
+#endif
+	if (dev->raw_io_interface && dev->raw_io_64)
+		len += snprintf(buf + len, PAGE_SIZE - len,
+				"SAI_READ_CAPACITY_16\n");
+	if (dev->jbod)
+		len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n");
+	return len;
+}
+
 static ssize_t aac_show_kernel_version(struct class_device *class_dev,
 		char *buf)
 {
@@ -742,7 +821,7 @@ static ssize_t aac_show_kernel_version(struct class_device *class_dev,
 	int len, tmp;
 
 	tmp = le32_to_cpu(dev->adapter_info.kernelrev);
-	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
+	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
 	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
 	  le32_to_cpu(dev->adapter_info.kernelbuild));
 	return len;
@@ -755,7 +834,7 @@ static ssize_t aac_show_monitor_version(struct class_device *class_dev,
 	int len, tmp;
 
 	tmp = le32_to_cpu(dev->adapter_info.monitorrev);
-	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
+	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
 	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
 	  le32_to_cpu(dev->adapter_info.monitorbuild));
 	return len;
@@ -768,7 +847,7 @@ static ssize_t aac_show_bios_version(struct class_device *class_dev,
 	int len, tmp;
 
 	tmp = le32_to_cpu(dev->adapter_info.biosrev);
-	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", 
+	len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n",
 	  tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff,
 	  le32_to_cpu(dev->adapter_info.biosbuild));
 	return len;
@@ -844,6 +923,13 @@ static struct class_device_attribute aac_vendor = {
 	},
 	.show = aac_show_vendor,
 };
+static struct class_device_attribute aac_flags = {
+	.attr = {
+		.name = "flags",
+		.mode = S_IRUGO,
+	},
+	.show = aac_show_flags,
+};
 static struct class_device_attribute aac_kernel_version = {
 	.attr = {
 		.name = "hba_kernel_version",
@@ -898,6 +984,7 @@ static struct class_device_attribute aac_reset = {
 static struct class_device_attribute *aac_attrs[] = {
 	&aac_model,
 	&aac_vendor,
+	&aac_flags,
 	&aac_kernel_version,
 	&aac_monitor_version,
 	&aac_bios_version,
@@ -928,23 +1015,23 @@ static struct scsi_host_template aac_driver_template = {
 	.compat_ioctl			= aac_compat_ioctl,
 #endif
 	.queuecommand   		= aac_queuecommand,
-	.bios_param     		= aac_biosparm,	
+	.bios_param     		= aac_biosparm,
 	.shost_attrs			= aac_attrs,
 	.slave_configure		= aac_slave_configure,
 	.change_queue_depth		= aac_change_queue_depth,
+	.sdev_attrs			= aac_dev_attrs,
 	.eh_abort_handler		= aac_eh_abort,
 	.eh_host_reset_handler		= aac_eh_reset,
-	.can_queue      		= AAC_NUM_IO_FIB,	
+	.can_queue      		= AAC_NUM_IO_FIB,
 	.this_id        		= MAXIMUM_NUM_CONTAINERS,
 	.sg_tablesize   		= 16,
 	.max_sectors    		= 128,
 #if (AAC_NUM_IO_FIB > 256)
 	.cmd_per_lun			= 256,
-#else		
-	.cmd_per_lun    		= AAC_NUM_IO_FIB, 
-#endif	
+#else
+	.cmd_per_lun    		= AAC_NUM_IO_FIB,
+#endif
 	.use_clustering			= ENABLE_CLUSTERING,
-	.use_sg_chaining		= ENABLE_SG_CHAINING,
 	.emulated                       = 1,
 };
 
@@ -979,18 +1066,18 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
 		goto out;
 	error = -ENODEV;
 
-	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || 
+	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
 			pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
 		goto out_disable_pdev;
 	/*
 	 * If the quirk31 bit is set, the adapter needs adapter
 	 * to driver communication memory to be allocated below 2gig
 	 */
-	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) 
+	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
 		if (pci_set_dma_mask(pdev, DMA_31BIT_MASK) ||
 				pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK))
 			goto out_disable_pdev;
-	
+
 	pci_set_master(pdev);
 
 	shost = scsi_host_alloc(&aac_driver_template, sizeof(struct aac_dev));
@@ -1003,7 +1090,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
 	shost->max_cmd_len = 16;
 
 	aac = (struct aac_dev *)shost->hostdata;
-	aac->scsi_host_ptr = shost;	
+	aac->scsi_host_ptr = shost;
 	aac->pdev = pdev;
 	aac->name = aac_driver_template.name;
 	aac->id = shost->unique_id;
@@ -1040,7 +1127,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
 	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
 		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK))
 			goto out_deinit;
- 
+
 	aac->maximum_num_channels = aac_drivers[index].channels;
 	error = aac_get_adapter_info(aac);
 	if (error < 0)
@@ -1049,7 +1136,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
 	/*
  	 * Lets override negotiations and drop the maximum SG limit to 34
  	 */
- 	if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) && 
+	if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) &&
 			(aac->scsi_host_ptr->sg_tablesize > 34)) {
  		aac->scsi_host_ptr->sg_tablesize = 34;
  		aac->scsi_host_ptr->max_sectors
@@ -1066,17 +1153,17 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
 	/*
 	 * Firware printf works only with older firmware.
 	 */
-	if (aac_drivers[index].quirks & AAC_QUIRK_34SG) 
+	if (aac_drivers[index].quirks & AAC_QUIRK_34SG)
 		aac->printf_enabled = 1;
 	else
 		aac->printf_enabled = 0;
- 
+
  	/*
 	 * max channel will be the physical channels plus 1 virtual channel
 	 * all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
 	 * physical channels are address by their actual physical number+1
 	 */
-	if ((aac->nondasd_support == 1) || expose_physicals)
+	if (aac->nondasd_support || expose_physicals || aac->jbod)
 		shost->max_channel = aac->maximum_num_channels;
 	else
 		shost->max_channel = 0;
@@ -1148,10 +1235,10 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
 	kfree(aac->queues);
 
 	aac_adapter_ioremap(aac, 0);
-	
+
 	kfree(aac->fibs);
 	kfree(aac->fsa_dev);
-	
+
 	list_del(&aac->entry);
 	scsi_host_put(shost);
 	pci_disable_device(pdev);
@@ -1172,7 +1259,7 @@ static struct pci_driver aac_pci_driver = {
 static int __init aac_init(void)
 {
 	int error;
-	
+
 	printk(KERN_INFO "Adaptec %s driver %s\n",
 	  AAC_DRIVERNAME, aac_driver_version);
 
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index 73eef3dc5dc6..a08bbf1fd76c 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -465,7 +465,7 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
 	u32 var;
 
 	if (!(dev->supplement_adapter_info.SupportedOptions2 &
-	  le32_to_cpu(AAC_OPTION_MU_RESET)) || (bled >= 0) || (bled == -2)) {
+	  AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) {
 		if (bled)
 			printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
 				dev->name, dev->id, bled);
@@ -549,7 +549,9 @@ int _aac_rx_init(struct aac_dev *dev)
 	dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
 	if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) &&
 	  !aac_rx_restart_adapter(dev, 0))
-		++restart;
+		/* Make sure the Hardware FIFO is empty */
+		while ((++restart < 512) &&
+		  (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL));
 	/*
 	 *	Check to see if the board panic'd while booting.
 	 */
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 38a1ee2eacd8..374ed025dc5a 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -8233,7 +8233,7 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
 			if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
 				ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
 				ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-						  sizeof(scp->sense_buffer));
+						  SCSI_SENSE_BUFFERSIZE);
 				/*
 				 * Note: The 'status_byte()' macro used by
 				 * target drivers defined in scsi.h shifts the
@@ -9136,7 +9136,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
 	BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var);
 
 	dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
-			sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+			 SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
 	/*
 	 * 'qdonep' contains the command's ending status.
 	 */
@@ -9166,7 +9166,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
 			if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
 				ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
 				ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-						  sizeof(scp->sense_buffer));
+						  SCSI_SENSE_BUFFERSIZE);
 				/*
 				 * Note: The 'status_byte()' macro used by
 				 * target drivers defined in scsi.h shifts the
@@ -9881,9 +9881,9 @@ static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp)
 {
 	struct asc_board *board = shost_priv(scp->device->host);
 	scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer,
-				sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+					     SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
 	dma_cache_sync(board->dev, scp->sense_buffer,
-				sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+		       SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
 	return cpu_to_le32(scp->SCp.dma_handle);
 }
 
@@ -9914,7 +9914,7 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
 	asc_scsi_q->q2.target_ix =
 	    ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
 	asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp);
-	asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer);
+	asc_scsi_q->q1.sense_len = SCSI_SENSE_BUFFERSIZE;
 
 	/*
 	 * If there are any outstanding requests for the current target,
@@ -10173,7 +10173,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
 	scsiqp->target_lun = scp->device->lun;
 
 	scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
-	scsiqp->sense_len = sizeof(scp->sense_buffer);
+	scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE;
 
 	/* Build ADV_SCSI_REQ_Q */
 
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index ea8c69947644..6ccdc96cc480 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -260,6 +260,7 @@
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport_spi.h>
+#include <scsi/scsi_eh.h>
 #include "aha152x.h"
 
 static LIST_HEAD(aha152x_host_list);
@@ -558,9 +559,7 @@ struct aha152x_hostdata {
 struct aha152x_scdata {
 	Scsi_Cmnd *next;	/* next sc in queue */
 	struct completion *done;/* semaphore to block on */
-	unsigned char aha_orig_cmd_len;
-	unsigned char aha_orig_cmnd[MAX_COMMAND_SIZE];
-	int aha_orig_resid;
+	struct scsi_eh_save ses;
 };
 
 /* access macros for hostdata */
@@ -1017,16 +1016,10 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
 	   SCp.buffers_residual : left buffers in list
 	   SCp.phase            : current state of the command */
 
-	if ((phase & (check_condition|resetting)) || !scsi_sglist(SCpnt)) {
-		if (phase & check_condition) {
-			SCpnt->SCp.ptr           = SCpnt->sense_buffer;
-			SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
-			scsi_set_resid(SCpnt, sizeof(SCpnt->sense_buffer));
-		} else {
-			SCpnt->SCp.ptr           = NULL;
-			SCpnt->SCp.this_residual = 0;
-			scsi_set_resid(SCpnt, 0);
-		}
+	if ((phase & resetting) || !scsi_sglist(SCpnt)) {
+		SCpnt->SCp.ptr           = NULL;
+		SCpnt->SCp.this_residual = 0;
+		scsi_set_resid(SCpnt, 0);
 		SCpnt->SCp.buffer           = NULL;
 		SCpnt->SCp.buffers_residual = 0;
 	} else {
@@ -1561,10 +1554,7 @@ static void busfree_run(struct Scsi_Host *shpnt)
 			}
 #endif
 
-			/* restore old command */
-			memcpy(cmd->cmnd, sc->aha_orig_cmnd, sizeof(cmd->cmnd));
-			cmd->cmd_len = sc->aha_orig_cmd_len;
-			scsi_set_resid(cmd, sc->aha_orig_resid);
+			scsi_eh_restore_cmnd(cmd, &sc->ses);
 
 			cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
 
@@ -1587,22 +1577,10 @@ static void busfree_run(struct Scsi_Host *shpnt)
 				DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
 #endif
 
-				/* save old command */
 				sc = SCDATA(ptr);
 				/* It was allocated in aha152x_internal_queue? */
 				BUG_ON(!sc);
-				memcpy(sc->aha_orig_cmnd, ptr->cmnd,
-				                            sizeof(ptr->cmnd));
-				sc->aha_orig_cmd_len = ptr->cmd_len;
-				sc->aha_orig_resid = scsi_get_resid(ptr);
-
-				ptr->cmnd[0]         = REQUEST_SENSE;
-				ptr->cmnd[1]         = 0;
-				ptr->cmnd[2]         = 0;
-				ptr->cmnd[3]         = 0;
-				ptr->cmnd[4]         = sizeof(ptr->sense_buffer);
-				ptr->cmnd[5]         = 0;
-				ptr->cmd_len         = 6;
+				scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0);
 
 				DO_UNLOCK(flags);
 				aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index bbcc2c52d79f..190568ebea3c 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -51,15 +51,6 @@
 #define SCSI_BUF_PA(address)	isa_virt_to_bus(address)
 #define SCSI_SG_PA(sgent)	(isa_page_to_bus(sg_page((sgent))) + (sgent)->offset)
 
-static void BAD_DMA(void *address, unsigned int length)
-{
-	printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n",
-	       address,
-	       SCSI_BUF_PA(address),
-	       length);
-	panic("Buffer at physical address > 16Mb used for aha1542");
-}
-
 static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
 		       struct scatterlist *sgp,
 		       int nseg,
@@ -545,7 +536,7 @@ static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id)
 		   we will still have it in the cdb when we come back */
 		if (ccb[mbo].tarstat == 2)
 			memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
-			       sizeof(SCtmp->sense_buffer));
+			       SCSI_SENSE_BUFFERSIZE);
 
 
 		/* is there mail :-) */
@@ -597,8 +588,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 	unchar target = SCpnt->device->id;
 	unchar lun = SCpnt->device->lun;
 	unsigned long flags;
-	void *buff = SCpnt->request_buffer;
-	int bufflen = SCpnt->request_bufflen;
+	int bufflen = scsi_bufflen(SCpnt);
 	int mbo;
 	struct mailbox *mb;
 	struct ccb *ccb;
@@ -619,7 +609,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 #if 0
 		/* scsi_request_sense() provides a buffer of size 256,
 		   so there is no reason to expect equality */
-		if (bufflen != sizeof(SCpnt->sense_buffer))
+		if (bufflen != SCSI_SENSE_BUFFERSIZE)
 			printk(KERN_CRIT "aha1542: Wrong buffer length supplied "
 			       "for request sense (%d)\n", bufflen);
 #endif
@@ -689,42 +679,29 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 
 	memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
 
-	if (SCpnt->use_sg) {
+	if (bufflen) {
 		struct scatterlist *sg;
 		struct chain *cptr;
 #ifdef DEBUG
 		unsigned char *ptr;
 #endif
-		int i;
+		int i, sg_count = scsi_sg_count(SCpnt);
 		ccb[mbo].op = 2;	/* SCSI Initiator Command  w/scatter-gather */
-		SCpnt->host_scribble = kmalloc(512, GFP_KERNEL | GFP_DMA);
+		SCpnt->host_scribble = kmalloc(sizeof(*cptr)*sg_count,
+		                                         GFP_KERNEL | GFP_DMA);
 		cptr = (struct chain *) SCpnt->host_scribble;
 		if (cptr == NULL) {
 			/* free the claimed mailbox slot */
 			HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL;
 			return SCSI_MLQUEUE_HOST_BUSY;
 		}
-		scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
-			if (sg->length == 0 || SCpnt->use_sg > 16 ||
-			    (((int) sg->offset) & 1) || (sg->length & 1)) {
-				unsigned char *ptr;
-				printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
-				scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
-					printk(KERN_CRIT "%d: %p %d\n", i,
-					       sg_virt(sg), sg->length);
-				};
-				printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
-				ptr = (unsigned char *) &cptr[i];
-				for (i = 0; i < 18; i++)
-					printk("%02x ", ptr[i]);
-				panic("Foooooooood fight!");
-			};
+		scsi_for_each_sg(SCpnt, sg, sg_count, i) {
 			any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg));
 			if (SCSI_SG_PA(sg) + sg->length - 1 > ISA_DMA_THRESHOLD)
-				BAD_SG_DMA(SCpnt, sg, SCpnt->use_sg, i);
+				BAD_SG_DMA(SCpnt, scsi_sglist(SCpnt), sg_count, i);
 			any2scsi(cptr[i].datalen, sg->length);
 		};
-		any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
+		any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain));
 		any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr));
 #ifdef DEBUG
 		printk("cptr %x: ", cptr);
@@ -735,10 +712,8 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 	} else {
 		ccb[mbo].op = 0;	/* SCSI Initiator Command */
 		SCpnt->host_scribble = NULL;
-		any2scsi(ccb[mbo].datalen, bufflen);
-		if (buff && SCSI_BUF_PA(buff + bufflen - 1) > ISA_DMA_THRESHOLD)
-			BAD_DMA(buff, bufflen);
-		any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(buff));
+		any2scsi(ccb[mbo].datalen, 0);
+		any2scsi(ccb[mbo].dataptr, 0);
 	};
 	ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7);	/*SCSI Target Id */
 	ccb[mbo].rsalen = 16;
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index f6722fd46008..7c45d88a205b 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -286,7 +286,7 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
 			   cdb when we come back */
 			if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
 				memcpy(SCtmp->sense_buffer, ecbptr->sense, 
-				       sizeof(SCtmp->sense_buffer));
+				       SCSI_SENSE_BUFFERSIZE);
 				errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
 			} else
 				errstatus = 0;
@@ -563,7 +563,6 @@ static struct scsi_host_template aha1740_template = {
 	.sg_tablesize     = AHA1740_SCATTER,
 	.cmd_per_lun      = AHA1740_CMDLUN,
 	.use_clustering   = ENABLE_CLUSTERING,
-	.use_sg_chaining  = ENABLE_SG_CHAINING,
 	.eh_abort_handler = aha1740_eh_abort_handler,
 };
 
diff --git a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile
index 9a6ce19a4030..e4f70c563bc2 100644
--- a/drivers/scsi/aic7xxx/Makefile
+++ b/drivers/scsi/aic7xxx/Makefile
@@ -33,11 +33,10 @@ aic79xx-y					+= aic79xx_osm.o	\
 						   aic79xx_proc.o	\
 						   aic79xx_osm_pci.o
 
-EXTRA_CFLAGS += -Idrivers/scsi
+ccflags-y += -Idrivers/scsi
 ifdef WARNINGS_BECOME_ERRORS
-EXTRA_CFLAGS += -Werror
+ccflags-y += -Werror
 endif
-#EXTRA_CFLAGS += -g
 
 # Files generated that shall be removed upon make clean
 clean-files := aic7xxx_seq.h aic7xxx_reg.h aic7xxx_reg_print.c
@@ -46,53 +45,45 @@ clean-files += aic79xx_seq.h aic79xx_reg.h aic79xx_reg_print.c
 # Dependencies for generated files need to be listed explicitly
 
 $(obj)/aic7xxx_core.o: $(obj)/aic7xxx_seq.h
+$(obj)/aic7xxx_core.o: $(obj)/aic7xxx_reg.h
 $(obj)/aic79xx_core.o: $(obj)/aic79xx_seq.h
-$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped
-$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped
+$(obj)/aic79xx_core.o: $(obj)/aic79xx_reg.h
 
-$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_reg.h
-$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_reg.h
+$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_seq.h
+$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_seq.h
 
-aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE)	:= $(obj)/aic7xxx_seq.h \
-						   $(obj)/aic7xxx_reg.h
+aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE)	:= $(obj)/aic7xxx_reg.h
 aic7xxx-gen-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT)	+= $(obj)/aic7xxx_reg_print.c
 
 aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) := \
 	-p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h
 
 ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y)
-# Create a dependency chain in generated files
-# to avoid concurrent invocations of the single
-# rule that builds them all.
-aic7xxx_seq.h: aic7xxx_reg.h
-ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y)
-aic7xxx_reg.h: aic7xxx_reg_print.c
-endif
-$(aic7xxx-gen-y): $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm
+$(obj)/aic7xxx_seq.h: $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm
 	$(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \
 			      $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \
 			      $(src)/aic7xxx.seq
+
+$(aic7xxx-gen-y): $(obj)/aic7xxx_seq.h
+else
+$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped
 endif
 
-aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE)	:= $(obj)/aic79xx_seq.h \
-						   $(obj)/aic79xx_reg.h
+aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE)	:= $(obj)/aic79xx_reg.h
 aic79xx-gen-$(CONFIG_AIC79XX_REG_PRETTY_PRINT)	+= $(obj)/aic79xx_reg_print.c
 
 aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) := \
 	-p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h
 
 ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y)
-# Create a dependency chain in generated files
-# to avoid concurrent invocations of the single
-# rule that builds them all.
-aic79xx_seq.h: aic79xx_reg.h
-ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y)
-aic79xx_reg.h: aic79xx_reg_print.c
-endif
-$(aic79xx-gen-y): $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm
+$(obj)/aic79xx_seq.h: $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm
 	$(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \
 			      $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \
 			      $(src)/aic79xx.seq
+
+$(aic79xx-gen-y): $(obj)/aic79xx_seq.h
+else
+$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped
 endif
 
 $(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl]
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index ce638aa6005a..2f00467b6b8c 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -1340,8 +1340,10 @@ struct	ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
 int			  ahd_pci_config(struct ahd_softc *,
 					 struct ahd_pci_identity *);
 int	ahd_pci_test_register_access(struct ahd_softc *);
+#ifdef CONFIG_PM
 void	ahd_pci_suspend(struct ahd_softc *);
 void	ahd_pci_resume(struct ahd_softc *);
+#endif
 
 /************************** SCB and SCB queue management **********************/
 void		ahd_qinfifo_requeue_tail(struct ahd_softc *ahd,
@@ -1352,8 +1354,10 @@ struct ahd_softc	*ahd_alloc(void *platform_arg, char *name);
 int			 ahd_softc_init(struct ahd_softc *);
 void			 ahd_controller_info(struct ahd_softc *ahd, char *buf);
 int			 ahd_init(struct ahd_softc *ahd);
+#ifdef CONFIG_PM
 int			 ahd_suspend(struct ahd_softc *ahd);
 void			 ahd_resume(struct ahd_softc *ahd);
+#endif
 int			 ahd_default_config(struct ahd_softc *ahd);
 int			 ahd_parse_vpddata(struct ahd_softc *ahd,
 					   struct vpd_config *vpd);
@@ -1361,7 +1365,6 @@ int			 ahd_parse_cfgdata(struct ahd_softc *ahd,
 					   struct seeprom_config *sc);
 void			 ahd_intr_enable(struct ahd_softc *ahd, int enable);
 void			 ahd_pause_and_flushwork(struct ahd_softc *ahd);
-int			 ahd_suspend(struct ahd_softc *ahd); 
 void			 ahd_set_unit(struct ahd_softc *, int);
 void			 ahd_set_name(struct ahd_softc *, char *);
 struct scb		*ahd_get_scb(struct ahd_softc *ahd, u_int col_idx);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index a7dd8cdda472..ade0fb8fbdb2 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -7175,6 +7175,7 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
 	ahd->flags &= ~AHD_ALL_INTERRUPTS;
 }
 
+#ifdef CONFIG_PM
 int
 ahd_suspend(struct ahd_softc *ahd)
 {
@@ -7197,6 +7198,7 @@ ahd_resume(struct ahd_softc *ahd)
 	ahd_intr_enable(ahd, TRUE); 
 	ahd_restart(ahd);
 }
+#endif
 
 /************************** Busy Target Table *********************************/
 /*
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 2d020405480c..014654792901 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -766,7 +766,6 @@ struct scsi_host_template aic79xx_driver_template = {
 	.max_sectors		= 8192,
 	.cmd_per_lun		= 2,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 	.slave_alloc		= ahd_linux_slave_alloc,
 	.slave_configure	= ahd_linux_slave_configure,
 	.target_alloc		= ahd_linux_target_alloc,
@@ -1784,7 +1783,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
 			if (scb->flags & SCB_SENSE) {
 				sense_size = min(sizeof(struct scsi_sense_data)
 					       - ahd_get_sense_residual(scb),
-						 (u_long)sizeof(cmd->sense_buffer));
+						 (u_long)SCSI_SENSE_BUFFERSIZE);
 				sense_offset = 0;
 			} else {
 				/*
@@ -1795,11 +1794,11 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
 				    scb->sense_data;
 				sense_size = min_t(size_t,
 						scsi_4btoul(siu->sense_length),
-						sizeof(cmd->sense_buffer));
+						SCSI_SENSE_BUFFERSIZE);
 				sense_offset = SIU_SENSE_OFFSET(siu);
 			}
 
-			memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+			memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 			memcpy(cmd->sense_buffer,
 			       ahd_get_sense_buf(ahd, scb)
 			       + sense_offset, sense_size);
@@ -1922,7 +1921,7 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd)
 				struct scsi_sense_data *sense;
 				
 				sense = (struct scsi_sense_data *)
-					&cmd->sense_buffer;
+					cmd->sense_buffer;
 				if (sense->extra_len >= 5 &&
 				    (sense->add_sense_code == 0x47
 				     || sense->add_sense_code == 0x48))
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index 66f0259edb69..4150c8a8fdc2 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -43,17 +43,6 @@
 #include "aic79xx_inline.h"
 #include "aic79xx_pci.h"
 
-static int	ahd_linux_pci_dev_probe(struct pci_dev *pdev,
-					const struct pci_device_id *ent);
-static int	ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd,
-						 u_long *base, u_long *base2);
-static int	ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
-						 u_long *bus_addr,
-						 uint8_t __iomem **maddr);
-static int	ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg);
-static int	ahd_linux_pci_dev_resume(struct pci_dev *pdev);
-static void	ahd_linux_pci_dev_remove(struct pci_dev *pdev);
-
 /* Define the macro locally since it's different for different class of chips.
  */
 #define ID(x)            \
@@ -85,17 +74,7 @@ static struct pci_device_id ahd_linux_pci_id_table[] = {
 
 MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
 
-static struct pci_driver aic79xx_pci_driver = {
-	.name		= "aic79xx",
-	.probe		= ahd_linux_pci_dev_probe,
 #ifdef CONFIG_PM
-	.suspend	= ahd_linux_pci_dev_suspend,
-	.resume		= ahd_linux_pci_dev_resume,
-#endif
-	.remove		= ahd_linux_pci_dev_remove,
-	.id_table	= ahd_linux_pci_id_table
-};
-
 static int
 ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
@@ -139,6 +118,7 @@ ahd_linux_pci_dev_resume(struct pci_dev *pdev)
 
 	return rc;
 }
+#endif
 
 static void
 ahd_linux_pci_dev_remove(struct pci_dev *pdev)
@@ -245,6 +225,17 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	return (0);
 }
 
+static struct pci_driver aic79xx_pci_driver = {
+	.name		= "aic79xx",
+	.probe		= ahd_linux_pci_dev_probe,
+#ifdef CONFIG_PM
+	.suspend	= ahd_linux_pci_dev_suspend,
+	.resume		= ahd_linux_pci_dev_resume,
+#endif
+	.remove		= ahd_linux_pci_dev_remove,
+	.id_table	= ahd_linux_pci_id_table
+};
+
 int
 ahd_linux_pci_init(void)
 {
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 7a203a90601a..df853676e66a 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -389,6 +389,7 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
 	return error;
 }
 
+#ifdef CONFIG_PM
 void
 ahd_pci_suspend(struct ahd_softc *ahd)
 {
@@ -415,6 +416,7 @@ ahd_pci_resume(struct ahd_softc *ahd)
 	ahd_pci_write_config(ahd->dev_softc, CSIZE_LATTIME,
 			     ahd->suspend_state.pci_state.csize_lattime, /*bytes*/1);
 }
+#endif
 
 /*
  * Perform some simple tests that should catch situations where
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index 3d4e42d90452..c0344e617651 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -1143,7 +1143,9 @@ struct ahc_pci_identity	*ahc_find_pci_device(ahc_dev_softc_t);
 int			 ahc_pci_config(struct ahc_softc *,
 					struct ahc_pci_identity *);
 int			 ahc_pci_test_register_access(struct ahc_softc *);
+#ifdef CONFIG_PM
 void			 ahc_pci_resume(struct ahc_softc *ahc);
+#endif
 
 /*************************** EISA/VL Front End ********************************/
 struct aic7770_identity *aic7770_find_device(uint32_t);
@@ -1170,8 +1172,10 @@ int			 ahc_chip_init(struct ahc_softc *ahc);
 int			 ahc_init(struct ahc_softc *ahc);
 void			 ahc_intr_enable(struct ahc_softc *ahc, int enable);
 void			 ahc_pause_and_flushwork(struct ahc_softc *ahc);
+#ifdef CONFIG_PM
 int			 ahc_suspend(struct ahc_softc *ahc); 
 int			 ahc_resume(struct ahc_softc *ahc);
+#endif
 void			 ahc_set_unit(struct ahc_softc *, int);
 void			 ahc_set_name(struct ahc_softc *, char *);
 void			 ahc_alloc_scbs(struct ahc_softc *ahc);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index f350b5e89e76..6d2ae641273c 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -5078,6 +5078,7 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc)
 	ahc->flags &= ~AHC_ALL_INTERRUPTS;
 }
 
+#ifdef CONFIG_PM
 int
 ahc_suspend(struct ahc_softc *ahc)
 {
@@ -5113,7 +5114,7 @@ ahc_resume(struct ahc_softc *ahc)
 	ahc_restart(ahc);
 	return (0);
 }
-
+#endif
 /************************** Busy Target Table *********************************/
 /*
  * Return the untagged transaction id for a given target/channel lun.
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 390b0fc991c5..99a3b33a3233 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -747,7 +747,6 @@ struct scsi_host_template aic7xxx_driver_template = {
 	.max_sectors		= 8192,
 	.cmd_per_lun		= 2,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 	.slave_alloc		= ahc_linux_slave_alloc,
 	.slave_configure	= ahc_linux_slave_configure,
 	.target_alloc		= ahc_linux_target_alloc,
@@ -1658,9 +1657,12 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb)
 		untagged_q = &(ahc->untagged_queues[target_offset]);
 		TAILQ_REMOVE(untagged_q, scb, links.tqe);
 		BUG_ON(!TAILQ_EMPTY(untagged_q));
-	}
-
-	if ((scb->flags & SCB_ACTIVE) == 0) {
+	} else if ((scb->flags & SCB_ACTIVE) == 0) {
+		/*
+		 * Transactions aborted from the untagged queue may
+		 * not have been dispatched to the controller, so
+		 * only check the SCB_ACTIVE flag for tagged transactions.
+		 */
 		printf("SCB %d done'd twice\n", scb->hscb->tag);
 		ahc_dump_card_state(ahc);
 		panic("Stopping for safety");
@@ -1801,12 +1803,12 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
 
 			sense_size = min(sizeof(struct scsi_sense_data)
 				       - ahc_get_sense_residual(scb),
-					 (u_long)sizeof(cmd->sense_buffer));
+					 (u_long)SCSI_SENSE_BUFFERSIZE);
 			memcpy(cmd->sense_buffer,
 			       ahc_get_sense_buf(ahc, scb), sense_size);
-			if (sense_size < sizeof(cmd->sense_buffer))
+			if (sense_size < SCSI_SENSE_BUFFERSIZE)
 				memset(&cmd->sense_buffer[sense_size], 0,
-				       sizeof(cmd->sense_buffer) - sense_size);
+				       SCSI_SENSE_BUFFERSIZE - sense_size);
 			cmd->result |= (DRIVER_SENSE << 24);
 #ifdef AHC_DEBUG
 			if (ahc_debug & AHC_SHOW_SENSE) {
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index 4488946cff2e..dd6e21d6f1dd 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -42,17 +42,6 @@
 #include "aic7xxx_osm.h"
 #include "aic7xxx_pci.h"
 
-static int	ahc_linux_pci_dev_probe(struct pci_dev *pdev,
-					const struct pci_device_id *ent);
-static int	ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
-						u_long *base);
-static int	ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
-						 u_long *bus_addr,
-						 uint8_t __iomem **maddr);
-static int	ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg);
-static int	ahc_linux_pci_dev_resume(struct pci_dev *pdev);
-static void	ahc_linux_pci_dev_remove(struct pci_dev *pdev);
-
 /* Define the macro locally since it's different for different class of chips.
 */
 #define ID(x)	ID_C(x, PCI_CLASS_STORAGE_SCSI)
@@ -132,17 +121,7 @@ static struct pci_device_id ahc_linux_pci_id_table[] = {
 
 MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
 
-static struct pci_driver aic7xxx_pci_driver = {
-	.name		= "aic7xxx",
-	.probe		= ahc_linux_pci_dev_probe,
 #ifdef CONFIG_PM
-	.suspend	= ahc_linux_pci_dev_suspend,
-	.resume		= ahc_linux_pci_dev_resume,
-#endif
-	.remove		= ahc_linux_pci_dev_remove,
-	.id_table	= ahc_linux_pci_id_table
-};
-
 static int
 ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
@@ -182,6 +161,7 @@ ahc_linux_pci_dev_resume(struct pci_dev *pdev)
 
 	return (ahc_resume(ahc));
 }
+#endif
 
 static void
 ahc_linux_pci_dev_remove(struct pci_dev *pdev)
@@ -289,6 +269,17 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	return (0);
 }
 
+static struct pci_driver aic7xxx_pci_driver = {
+	.name		= "aic7xxx",
+	.probe		= ahc_linux_pci_dev_probe,
+#ifdef CONFIG_PM
+	.suspend	= ahc_linux_pci_dev_suspend,
+	.resume		= ahc_linux_pci_dev_resume,
+#endif
+	.remove		= ahc_linux_pci_dev_remove,
+	.id_table	= ahc_linux_pci_id_table
+};
+
 int
 ahc_linux_pci_init(void)
 {
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index ae35937b8055..56848f41e4f9 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -2020,6 +2020,7 @@ ahc_pci_chip_init(struct ahc_softc *ahc)
 	return (ahc_chip_init(ahc));
 }
 
+#ifdef CONFIG_PM
 void
 ahc_pci_resume(struct ahc_softc *ahc)
 {
@@ -2051,6 +2052,7 @@ ahc_pci_resume(struct ahc_softc *ahc)
 		ahc_release_seeprom(&sd);
 	}
 }
+#endif
 
 static int
 ahc_aic785X_setup(struct ahc_softc *ahc)
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 8f8db5f0aef7..3bfd9296bbfa 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -2696,7 +2696,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
   {
     pci_unmap_single(p->pdev,
                      le32_to_cpu(scb->sg_list[0].address),
-                     sizeof(cmd->sense_buffer),
+                     SCSI_SENSE_BUFFERSIZE,
                      PCI_DMA_FROMDEVICE);
   }
   if (scb->flags & SCB_RECOVERY_SCB)
@@ -4267,13 +4267,13 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                        sizeof(generic_sense));
 
                 scb->sense_cmd[1] = (cmd->device->lun << 5);
-                scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+                scb->sense_cmd[4] = SCSI_SENSE_BUFFERSIZE;
 
                 scb->sg_list[0].length = 
-                  cpu_to_le32(sizeof(cmd->sense_buffer));
+                  cpu_to_le32(SCSI_SENSE_BUFFERSIZE);
 		scb->sg_list[0].address =
                         cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer,
-                                                   sizeof(cmd->sense_buffer),
+                                                   SCSI_SENSE_BUFFERSIZE,
                                                    PCI_DMA_FROMDEVICE));
 
                 /*
@@ -4296,7 +4296,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                 hscb->residual_data_count[2] = 0;
 
                 scb->sg_count = hscb->SG_segment_count = 1;
-                scb->sg_length = sizeof(cmd->sense_buffer);
+                scb->sg_length = SCSI_SENSE_BUFFERSIZE;
                 scb->tag_action = 0;
                 scb->flags |= SCB_SENSE;
                 /*
@@ -10293,7 +10293,6 @@ static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
   aic7xxx_position(cmd) = scb->hscb->tag;
   cmd->scsi_done = fn;
   cmd->result = DID_OK;
-  memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
   aic7xxx_error(cmd) = DID_OK;
   aic7xxx_status(cmd) = 0;
   cmd->host_scribble = NULL;
@@ -11142,7 +11141,6 @@ static struct scsi_host_template driver_template = {
 	.max_sectors		= 2048,
 	.cmd_per_lun		= 3,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 };
 
 #include "scsi_module.c"
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
index 3dce618bf414..72042cae7768 100644
--- a/drivers/scsi/aic94xx/aic94xx_dev.c
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -165,7 +165,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
 	if (dev->port->oob_mode != SATA_OOB_MODE) {
 		flags |= OPEN_REQUIRED;
 		if ((dev->dev_type == SATA_DEV) ||
-		    (dev->tproto & SAS_PROTO_STP)) {
+		    (dev->tproto & SAS_PROTOCOL_STP)) {
 			struct smp_resp *rps_resp = &dev->sata_dev.rps_resp;
 			if (rps_resp->frame_type == SMP_RESPONSE &&
 			    rps_resp->function == SMP_REPORT_PHY_SATA &&
@@ -193,7 +193,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
 	asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags);
 
 	flags = 0;
-	if (dev->tproto & SAS_PROTO_STP)
+	if (dev->tproto & SAS_PROTOCOL_STP)
 		flags |= STP_CL_POL_NO_TX;
 	asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags);
 
@@ -201,7 +201,7 @@ static int asd_init_target_ddb(struct domain_device *dev)
 	asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF);
 	asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
 
-	if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) {
+	if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
 		i = asd_init_sata(dev);
 		if (i < 0) {
 			asd_free_ddb(asd_ha, ddb);
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c
index 6bd8e3059d27..3d8c4ff1f2ef 100644
--- a/drivers/scsi/aic94xx/aic94xx_dump.c
+++ b/drivers/scsi/aic94xx/aic94xx_dump.c
@@ -903,11 +903,11 @@ void asd_dump_frame_rcvd(struct asd_phy *phy,
 	int i;
 
 	switch ((dl->status_block[1] & 0x70) >> 3) {
-	case SAS_PROTO_STP:
+	case SAS_PROTOCOL_STP:
 		ASD_DPRINTK("STP proto device-to-host FIS:\n");
 		break;
 	default:
-	case SAS_PROTO_SSP:
+	case SAS_PROTOCOL_SSP:
 		ASD_DPRINTK("SAS proto IDENTIFY:\n");
 		break;
 	}
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
index 0cd7eed9196c..098b5f39cd31 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.c
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
@@ -91,7 +91,7 @@ static int asd_init_phy(struct asd_phy *phy)
 
 	sas_phy->enabled = 1;
 	sas_phy->class = SAS;
-	sas_phy->iproto = SAS_PROTO_ALL;
+	sas_phy->iproto = SAS_PROTOCOL_ALL;
 	sas_phy->tproto = 0;
 	sas_phy->type = PHY_TYPE_PHYSICAL;
 	sas_phy->role = PHY_ROLE_INITIATOR;
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
index 491e5d8a98bc..150f6706d23f 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.h
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
@@ -72,6 +72,7 @@ struct flash_struct {
 	u8     manuf;
 	u8     dev_id;
 	u8     sec_prot;
+	u8     method;
 
 	u32    dir_offs;
 };
@@ -216,6 +217,8 @@ struct asd_ha_struct {
 	struct dma_pool  *scb_pool;
 
 	struct asd_seq_data  seq; /* sequencer related */
+	u32    bios_status;
+	const struct firmware *bios_image;
 };
 
 /* ---------- Common macros ---------- */
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index b70d6e7f96e9..5d761eb67442 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -29,6 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
+#include <linux/firmware.h>
 
 #include <scsi/scsi_host.h>
 
@@ -36,6 +37,7 @@
 #include "aic94xx_reg.h"
 #include "aic94xx_hwi.h"
 #include "aic94xx_seq.h"
+#include "aic94xx_sds.h"
 
 /* The format is "version.release.patchlevel" */
 #define ASD_DRIVER_VERSION "1.0.3"
@@ -134,7 +136,7 @@ Err:
 	return err;
 }
 
-static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
+static void asd_unmap_memio(struct asd_ha_struct *asd_ha)
 {
 	struct asd_ha_addrspace *io_handle;
 
@@ -171,7 +173,7 @@ static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
 	return err;
 }
 
-static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
+static void asd_unmap_ioport(struct asd_ha_struct *asd_ha)
 {
 	pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
 }
@@ -208,7 +210,7 @@ Err:
 	return err;
 }
 
-static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
+static void asd_unmap_ha(struct asd_ha_struct *asd_ha)
 {
 	if (asd_ha->iospace)
 		asd_unmap_ioport(asd_ha);
@@ -313,6 +315,181 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev,
 }
 static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
 
+#define FLASH_CMD_NONE      0x00
+#define FLASH_CMD_UPDATE    0x01
+#define FLASH_CMD_VERIFY    0x02
+
+struct flash_command {
+     u8      command[8];
+     int     code;
+};
+
+static struct flash_command flash_command_table[] =
+{
+     {"verify",      FLASH_CMD_VERIFY},
+     {"update",      FLASH_CMD_UPDATE},
+     {"",            FLASH_CMD_NONE}      /* Last entry should be NULL. */
+};
+
+struct error_bios {
+     char    *reason;
+     int     err_code;
+};
+
+static struct error_bios flash_error_table[] =
+{
+     {"Failed to open bios image file",      FAIL_OPEN_BIOS_FILE},
+     {"PCI ID mismatch",                     FAIL_CHECK_PCI_ID},
+     {"Checksum mismatch",                   FAIL_CHECK_SUM},
+     {"Unknown Error",                       FAIL_UNKNOWN},
+     {"Failed to verify.",                   FAIL_VERIFY},
+     {"Failed to reset flash chip.",         FAIL_RESET_FLASH},
+     {"Failed to find flash chip type.",     FAIL_FIND_FLASH_ID},
+     {"Failed to erash flash chip.",         FAIL_ERASE_FLASH},
+     {"Failed to program flash chip.",       FAIL_WRITE_FLASH},
+     {"Flash in progress",                   FLASH_IN_PROGRESS},
+     {"Image file size Error",               FAIL_FILE_SIZE},
+     {"Input parameter error",               FAIL_PARAMETERS},
+     {"Out of memory",                       FAIL_OUT_MEMORY},
+     {"OK", 0}	/* Last entry err_code = 0. */
+};
+
+static ssize_t asd_store_update_bios(struct device *dev,
+	struct device_attribute *attr,
+	const char *buf, size_t count)
+{
+	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+	char *cmd_ptr, *filename_ptr;
+	struct bios_file_header header, *hdr_ptr;
+	int res, i;
+	u32 csum = 0;
+	int flash_command = FLASH_CMD_NONE;
+	int err = 0;
+
+	cmd_ptr = kzalloc(count*2, GFP_KERNEL);
+
+	if (!cmd_ptr) {
+		err = FAIL_OUT_MEMORY;
+		goto out;
+	}
+
+	filename_ptr = cmd_ptr + count;
+	res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
+	if (res != 2) {
+		err = FAIL_PARAMETERS;
+		goto out1;
+	}
+
+	for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
+		if (!memcmp(flash_command_table[i].command,
+				 cmd_ptr, strlen(cmd_ptr))) {
+			flash_command = flash_command_table[i].code;
+			break;
+		}
+	}
+	if (flash_command == FLASH_CMD_NONE) {
+		err = FAIL_PARAMETERS;
+		goto out1;
+	}
+
+	if (asd_ha->bios_status == FLASH_IN_PROGRESS) {
+		err = FLASH_IN_PROGRESS;
+		goto out1;
+	}
+	err = request_firmware(&asd_ha->bios_image,
+				   filename_ptr,
+				   &asd_ha->pcidev->dev);
+	if (err) {
+		asd_printk("Failed to load bios image file %s, error %d\n",
+			   filename_ptr, err);
+		err = FAIL_OPEN_BIOS_FILE;
+		goto out1;
+	}
+
+	hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data;
+
+	if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor ||
+		hdr_ptr->contrl_id.device != asd_ha->pcidev->device) &&
+		(hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor ||
+		hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) {
+
+		ASD_DPRINTK("The PCI vendor or device id does not match\n");
+		ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x"
+		" pci vendor=%x pci dev=%x\n",
+		hdr_ptr->contrl_id.vendor,
+		hdr_ptr->contrl_id.device,
+		hdr_ptr->contrl_id.sub_vendor,
+		hdr_ptr->contrl_id.sub_device,
+		asd_ha->pcidev->vendor,
+		asd_ha->pcidev->device);
+		err = FAIL_CHECK_PCI_ID;
+		goto out2;
+	}
+
+	if (hdr_ptr->filelen != asd_ha->bios_image->size) {
+		err = FAIL_FILE_SIZE;
+		goto out2;
+	}
+
+	/* calculate checksum */
+	for (i = 0; i < hdr_ptr->filelen; i++)
+		csum += asd_ha->bios_image->data[i];
+
+	if ((csum & 0x0000ffff) != hdr_ptr->checksum) {
+		ASD_DPRINTK("BIOS file checksum mismatch\n");
+		err = FAIL_CHECK_SUM;
+		goto out2;
+	}
+	if (flash_command == FLASH_CMD_UPDATE) {
+		asd_ha->bios_status = FLASH_IN_PROGRESS;
+		err = asd_write_flash_seg(asd_ha,
+			&asd_ha->bios_image->data[sizeof(*hdr_ptr)],
+			0, hdr_ptr->filelen-sizeof(*hdr_ptr));
+		if (!err)
+			err = asd_verify_flash_seg(asd_ha,
+				&asd_ha->bios_image->data[sizeof(*hdr_ptr)],
+				0, hdr_ptr->filelen-sizeof(*hdr_ptr));
+	} else {
+		asd_ha->bios_status = FLASH_IN_PROGRESS;
+		err = asd_verify_flash_seg(asd_ha,
+			&asd_ha->bios_image->data[sizeof(header)],
+			0, hdr_ptr->filelen-sizeof(header));
+	}
+
+out2:
+	release_firmware(asd_ha->bios_image);
+out1:
+	kfree(cmd_ptr);
+out:
+	asd_ha->bios_status = err;
+
+	if (!err)
+		return count;
+	else
+		return -err;
+}
+
+static ssize_t asd_show_update_bios(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	int i;
+	struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+
+	for (i = 0; flash_error_table[i].err_code != 0; i++) {
+		if (flash_error_table[i].err_code == asd_ha->bios_status)
+			break;
+	}
+	if (asd_ha->bios_status != FLASH_IN_PROGRESS)
+		asd_ha->bios_status = FLASH_OK;
+
+	return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
+			flash_error_table[i].err_code,
+			flash_error_table[i].reason);
+}
+
+static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUGO,
+	asd_show_update_bios, asd_store_update_bios);
+
 static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
 {
 	int err;
@@ -328,9 +505,14 @@ static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
 	err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
 	if (err)
 		goto err_biosb;
+	err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
+	if (err)
+		goto err_update_bios;
 
 	return 0;
 
+err_update_bios:
+	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
 err_biosb:
 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
 err_rev:
@@ -343,6 +525,7 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
 	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+	device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios);
 }
 
 /* The first entry, 0, is used for dynamic ids, the rest for devices
@@ -589,6 +772,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
 	asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
 	asd_ha->sas_ha.lldd_ha = asd_ha;
 
+	asd_ha->bios_status = FLASH_OK;
 	asd_ha->name = asd_dev->name;
 	asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
 
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index db6ab1a3b81e..0febad4dd75f 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -788,12 +788,12 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
 
 		/* initiator port settings are in the hi nibble */
 		if (phy->sas_phy.role == PHY_ROLE_INITIATOR)
-			control_phy->port_type = SAS_PROTO_ALL << 4;
+			control_phy->port_type = SAS_PROTOCOL_ALL << 4;
 		else if (phy->sas_phy.role == PHY_ROLE_TARGET)
-			control_phy->port_type = SAS_PROTO_ALL;
+			control_phy->port_type = SAS_PROTOCOL_ALL;
 		else
 			control_phy->port_type =
-				(SAS_PROTO_ALL << 4) | SAS_PROTO_ALL;
+				(SAS_PROTOCOL_ALL << 4) | SAS_PROTOCOL_ALL;
 
 		/* link reset retries, this should be nominal */
 		control_phy->link_reset_retries = 10;
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
index 06509bff71f7..2a4c933eb89c 100644
--- a/drivers/scsi/aic94xx/aic94xx_sds.c
+++ b/drivers/scsi/aic94xx/aic94xx_sds.c
@@ -30,6 +30,7 @@
 
 #include "aic94xx.h"
 #include "aic94xx_reg.h"
+#include "aic94xx_sds.h"
 
 /* ---------- OCM stuff ---------- */
 
@@ -1083,3 +1084,391 @@ out:
 	kfree(flash_dir);
 	return err;
 }
+
+/**
+ * asd_verify_flash_seg - verify data with flash memory
+ * @asd_ha: pointer to the host adapter structure
+ * @src: pointer to the source data to be verified
+ * @dest_offset: offset from flash memory
+ * @bytes_to_verify: total bytes to verify
+ */
+int asd_verify_flash_seg(struct asd_ha_struct *asd_ha,
+		void *src, u32 dest_offset, u32 bytes_to_verify)
+{
+	u8 *src_buf;
+	u8 flash_char;
+	int err;
+	u32 nv_offset, reg, i;
+
+	reg = asd_ha->hw_prof.flash.bar;
+	src_buf = NULL;
+
+	err = FLASH_OK;
+	nv_offset = dest_offset;
+	src_buf = (u8 *)src;
+	for (i = 0; i < bytes_to_verify; i++) {
+		flash_char = asd_read_reg_byte(asd_ha, reg + nv_offset + i);
+		if (flash_char != src_buf[i]) {
+			err = FAIL_VERIFY;
+			break;
+		}
+	}
+	return err;
+}
+
+/**
+ * asd_write_flash_seg - write data into flash memory
+ * @asd_ha: pointer to the host adapter structure
+ * @src: pointer to the source data to be written
+ * @dest_offset: offset from flash memory
+ * @bytes_to_write: total bytes to write
+ */
+int asd_write_flash_seg(struct asd_ha_struct *asd_ha,
+		void *src, u32 dest_offset, u32 bytes_to_write)
+{
+	u8 *src_buf;
+	u32 nv_offset, reg, i;
+	int err;
+
+	reg = asd_ha->hw_prof.flash.bar;
+	src_buf = NULL;
+
+	err = asd_check_flash_type(asd_ha);
+	if (err) {
+		ASD_DPRINTK("couldn't find the type of flash. err=%d\n", err);
+		return err;
+	}
+
+	nv_offset = dest_offset;
+	err = asd_erase_nv_sector(asd_ha, nv_offset, bytes_to_write);
+	if (err) {
+		ASD_DPRINTK("Erase failed at offset:0x%x\n",
+			nv_offset);
+		return err;
+	}
+
+	err = asd_reset_flash(asd_ha);
+	if (err) {
+		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+		return err;
+	}
+
+	src_buf = (u8 *)src;
+	for (i = 0; i < bytes_to_write; i++) {
+		/* Setup program command sequence */
+		switch (asd_ha->hw_prof.flash.method) {
+		case FLASH_METHOD_A:
+		{
+			asd_write_reg_byte(asd_ha,
+					(reg + 0xAAA), 0xAA);
+			asd_write_reg_byte(asd_ha,
+					(reg + 0x555), 0x55);
+			asd_write_reg_byte(asd_ha,
+					(reg + 0xAAA), 0xA0);
+			asd_write_reg_byte(asd_ha,
+					(reg + nv_offset + i),
+					(*(src_buf + i)));
+			break;
+		}
+		case FLASH_METHOD_B:
+		{
+			asd_write_reg_byte(asd_ha,
+					(reg + 0x555), 0xAA);
+			asd_write_reg_byte(asd_ha,
+					(reg + 0x2AA), 0x55);
+			asd_write_reg_byte(asd_ha,
+					(reg + 0x555), 0xA0);
+			asd_write_reg_byte(asd_ha,
+					(reg + nv_offset + i),
+					(*(src_buf + i)));
+			break;
+		}
+		default:
+			break;
+		}
+		if (asd_chk_write_status(asd_ha,
+				(nv_offset + i), 0) != 0) {
+			ASD_DPRINTK("aicx: Write failed at offset:0x%x\n",
+				reg + nv_offset + i);
+			return FAIL_WRITE_FLASH;
+		}
+	}
+
+	err = asd_reset_flash(asd_ha);
+	if (err) {
+		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+		return err;
+	}
+	return 0;
+}
+
+int asd_chk_write_status(struct asd_ha_struct *asd_ha,
+	 u32 sector_addr, u8 erase_flag)
+{
+	u32 reg;
+	u32 loop_cnt;
+	u8  nv_data1, nv_data2;
+	u8  toggle_bit1;
+
+	/*
+	 * Read from DQ2 requires sector address
+	 * while it's dont care for DQ6
+	 */
+	reg = asd_ha->hw_prof.flash.bar;
+
+	for (loop_cnt = 0; loop_cnt < 50000; loop_cnt++) {
+		nv_data1 = asd_read_reg_byte(asd_ha, reg);
+		nv_data2 = asd_read_reg_byte(asd_ha, reg);
+
+		toggle_bit1 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
+				 ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
+
+		if (toggle_bit1 == 0) {
+			return 0;
+		} else {
+			if (nv_data2 & FLASH_STATUS_BIT_MASK_DQ5) {
+				nv_data1 = asd_read_reg_byte(asd_ha,
+								reg);
+				nv_data2 = asd_read_reg_byte(asd_ha,
+								reg);
+				toggle_bit1 =
+				((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6)
+				^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6));
+
+				if (toggle_bit1 == 0)
+					return 0;
+			}
+		}
+
+		/*
+		 * ERASE is a sector-by-sector operation and requires
+		 * more time to finish while WRITE is byte-byte-byte
+		 * operation and takes lesser time to finish.
+		 *
+		 * For some strange reason a reduced ERASE delay gives different
+		 * behaviour across different spirit boards. Hence we set
+		 * a optimum balance of 50mus for ERASE which works well
+		 * across all boards.
+		 */
+		if (erase_flag) {
+			udelay(FLASH_STATUS_ERASE_DELAY_COUNT);
+		} else {
+			udelay(FLASH_STATUS_WRITE_DELAY_COUNT);
+		}
+	}
+	return -1;
+}
+
+/**
+ * asd_hwi_erase_nv_sector - Erase the flash memory sectors.
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_addr: pointer to offset from flash memory
+ * @size: total bytes to erase.
+ */
+int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr, u32 size)
+{
+	u32 reg;
+	u32 sector_addr;
+
+	reg = asd_ha->hw_prof.flash.bar;
+
+	/* sector staring address */
+	sector_addr = flash_addr & FLASH_SECTOR_SIZE_MASK;
+
+	/*
+	 * Erasing an flash sector needs to be done in six consecutive
+	 * write cyles.
+	 */
+	while (sector_addr < flash_addr+size) {
+		switch (asd_ha->hw_prof.flash.method) {
+		case FLASH_METHOD_A:
+			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
+			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
+			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0x80);
+			asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA);
+			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55);
+			asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
+			break;
+		case FLASH_METHOD_B:
+			asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
+			asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
+			asd_write_reg_byte(asd_ha, (reg + 0x555), 0x80);
+			asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
+			asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
+			asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30);
+			break;
+		default:
+			break;
+		}
+
+		if (asd_chk_write_status(asd_ha, sector_addr, 1) != 0)
+			return FAIL_ERASE_FLASH;
+
+		sector_addr += FLASH_SECTOR_SIZE;
+	}
+
+	return 0;
+}
+
+int asd_check_flash_type(struct asd_ha_struct *asd_ha)
+{
+	u8 manuf_id;
+	u8 dev_id;
+	u8 sec_prot;
+	u32 inc;
+	u32 reg;
+	int err;
+
+	/* get Flash memory base address */
+	reg = asd_ha->hw_prof.flash.bar;
+
+	/* Determine flash info */
+	err = asd_reset_flash(asd_ha);
+	if (err) {
+		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+		return err;
+	}
+
+	asd_ha->hw_prof.flash.method = FLASH_METHOD_UNKNOWN;
+	asd_ha->hw_prof.flash.manuf = FLASH_MANUF_ID_UNKNOWN;
+	asd_ha->hw_prof.flash.dev_id = FLASH_DEV_ID_UNKNOWN;
+
+	/* Get flash info. This would most likely be AMD Am29LV family flash.
+	 * First try the sequence for word mode.  It is the same as for
+	 * 008B (byte mode only), 160B (word mode) and 800D (word mode).
+	 */
+	inc = asd_ha->hw_prof.flash.wide ? 2 : 1;
+	asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA);
+	asd_write_reg_byte(asd_ha, reg + 0x555, 0x55);
+	asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90);
+	manuf_id = asd_read_reg_byte(asd_ha, reg);
+	dev_id = asd_read_reg_byte(asd_ha, reg + inc);
+	sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
+	/* Get out of autoselect mode. */
+	err = asd_reset_flash(asd_ha);
+	if (err) {
+		ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+		return err;
+	}
+	ASD_DPRINTK("Flash MethodA manuf_id(0x%x) dev_id(0x%x) "
+		"sec_prot(0x%x)\n", manuf_id, dev_id, sec_prot);
+	err = asd_reset_flash(asd_ha);
+	if (err != 0)
+		return err;
+
+	switch (manuf_id) {
+	case FLASH_MANUF_ID_AMD:
+		switch (sec_prot) {
+		case FLASH_DEV_ID_AM29LV800DT:
+		case FLASH_DEV_ID_AM29LV640MT:
+		case FLASH_DEV_ID_AM29F800B:
+			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+			break;
+		default:
+			break;
+		}
+		break;
+	case FLASH_MANUF_ID_ST:
+		switch (sec_prot) {
+		case FLASH_DEV_ID_STM29W800DT:
+		case FLASH_DEV_ID_STM29LV640:
+			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+			break;
+		default:
+			break;
+		}
+		break;
+	case FLASH_MANUF_ID_FUJITSU:
+		switch (sec_prot) {
+		case FLASH_DEV_ID_MBM29LV800TE:
+		case FLASH_DEV_ID_MBM29DL800TA:
+			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+			break;
+		}
+		break;
+	case FLASH_MANUF_ID_MACRONIX:
+		switch (sec_prot) {
+		case FLASH_DEV_ID_MX29LV800BT:
+			asd_ha->hw_prof.flash.method = FLASH_METHOD_A;
+			break;
+		}
+		break;
+	}
+
+	if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) {
+		err = asd_reset_flash(asd_ha);
+		if (err) {
+			ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+			return err;
+		}
+
+		/* Issue Unlock sequence for AM29LV008BT */
+		asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA);
+		asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55);
+		asd_write_reg_byte(asd_ha, (reg + 0x555), 0x90);
+		manuf_id = asd_read_reg_byte(asd_ha, reg);
+		dev_id = asd_read_reg_byte(asd_ha, reg + inc);
+		sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc);
+
+		ASD_DPRINTK("Flash MethodB manuf_id(0x%x) dev_id(0x%x) sec_prot"
+			"(0x%x)\n", manuf_id, dev_id, sec_prot);
+
+		err = asd_reset_flash(asd_ha);
+		if (err != 0) {
+			ASD_DPRINTK("couldn't reset flash. err=%d\n", err);
+			return err;
+		}
+
+		switch (manuf_id) {
+		case FLASH_MANUF_ID_AMD:
+			switch (dev_id) {
+			case FLASH_DEV_ID_AM29LV008BT:
+				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+				break;
+			default:
+				break;
+			}
+			break;
+		case FLASH_MANUF_ID_ST:
+			switch (dev_id) {
+			case FLASH_DEV_ID_STM29008:
+				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+				break;
+			default:
+				break;
+			}
+			break;
+		case FLASH_MANUF_ID_FUJITSU:
+			switch (dev_id) {
+			case FLASH_DEV_ID_MBM29LV008TA:
+				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+				break;
+			}
+			break;
+		case FLASH_MANUF_ID_INTEL:
+			switch (dev_id) {
+			case FLASH_DEV_ID_I28LV00TAT:
+				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+				break;
+			}
+			break;
+		case FLASH_MANUF_ID_MACRONIX:
+			switch (dev_id) {
+			case FLASH_DEV_ID_I28LV00TAT:
+				asd_ha->hw_prof.flash.method = FLASH_METHOD_B;
+				break;
+			}
+			break;
+		default:
+			return FAIL_FIND_FLASH_ID;
+		}
+	}
+
+	if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN)
+	      return FAIL_FIND_FLASH_ID;
+
+	asd_ha->hw_prof.flash.manuf = manuf_id;
+	asd_ha->hw_prof.flash.dev_id = dev_id;
+	asd_ha->hw_prof.flash.sec_prot = sec_prot;
+	return 0;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.h b/drivers/scsi/aic94xx/aic94xx_sds.h
new file mode 100644
index 000000000000..bb9795a04dc3
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_sds.h
@@ -0,0 +1,121 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Gilbert Wu <gilbert_wu@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+#ifndef _AIC94XX_SDS_H_
+#define _AIC94XX_SDS_H_
+
+enum {
+	FLASH_METHOD_UNKNOWN,
+	FLASH_METHOD_A,
+	FLASH_METHOD_B
+};
+
+#define FLASH_MANUF_ID_AMD              0x01
+#define FLASH_MANUF_ID_ST               0x20
+#define FLASH_MANUF_ID_FUJITSU          0x04
+#define FLASH_MANUF_ID_MACRONIX         0xC2
+#define FLASH_MANUF_ID_INTEL            0x89
+#define FLASH_MANUF_ID_UNKNOWN          0xFF
+
+#define FLASH_DEV_ID_AM29LV008BT        0x3E
+#define FLASH_DEV_ID_AM29LV800DT        0xDA
+#define FLASH_DEV_ID_STM29W800DT        0xD7
+#define FLASH_DEV_ID_STM29LV640         0xDE
+#define FLASH_DEV_ID_STM29008           0xEA
+#define FLASH_DEV_ID_MBM29LV800TE       0xDA
+#define FLASH_DEV_ID_MBM29DL800TA       0x4A
+#define FLASH_DEV_ID_MBM29LV008TA       0x3E
+#define FLASH_DEV_ID_AM29LV640MT        0x7E
+#define FLASH_DEV_ID_AM29F800B          0xD6
+#define FLASH_DEV_ID_MX29LV800BT        0xDA
+#define FLASH_DEV_ID_MX29LV008CT        0xDA
+#define FLASH_DEV_ID_I28LV00TAT         0x3E
+#define FLASH_DEV_ID_UNKNOWN            0xFF
+
+/* status bit mask values */
+#define FLASH_STATUS_BIT_MASK_DQ6       0x40
+#define FLASH_STATUS_BIT_MASK_DQ5       0x20
+#define FLASH_STATUS_BIT_MASK_DQ2       0x04
+
+/* minimum value in micro seconds needed for checking status */
+#define FLASH_STATUS_ERASE_DELAY_COUNT  50
+#define FLASH_STATUS_WRITE_DELAY_COUNT  25
+
+#define FLASH_SECTOR_SIZE               0x010000
+#define FLASH_SECTOR_SIZE_MASK          0xffff0000
+
+#define FLASH_OK                        0x000000
+#define FAIL_OPEN_BIOS_FILE             0x000100
+#define FAIL_CHECK_PCI_ID               0x000200
+#define FAIL_CHECK_SUM                  0x000300
+#define FAIL_UNKNOWN                    0x000400
+#define FAIL_VERIFY                     0x000500
+#define FAIL_RESET_FLASH                0x000600
+#define FAIL_FIND_FLASH_ID              0x000700
+#define FAIL_ERASE_FLASH                0x000800
+#define FAIL_WRITE_FLASH                0x000900
+#define FAIL_FILE_SIZE                  0x000a00
+#define FAIL_PARAMETERS                 0x000b00
+#define FAIL_OUT_MEMORY                 0x000c00
+#define FLASH_IN_PROGRESS               0x001000
+
+struct controller_id {
+	u32 vendor;     /* PCI Vendor ID */
+	u32 device;     /* PCI Device ID */
+	u32 sub_vendor; /* PCI Subvendor ID */
+	u32 sub_device; /* PCI Subdevice ID */
+};
+
+struct image_info {
+	u32 ImageId;       /* Identifies the image */
+	u32 ImageOffset;   /* Offset the beginning of the file */
+	u32 ImageLength;   /* length of the image */
+	u32 ImageChecksum; /* Image checksum */
+	u32 ImageVersion;  /* Version of the image, could be build number */
+};
+
+struct bios_file_header {
+	u8 signature[32]; /* Signature/Cookie to identify the file */
+	u32 checksum;	  /*Entire file checksum with this field zero */
+	u32 antidote;	  /* Entire file checksum with this field 0xFFFFFFFF */
+	struct controller_id contrl_id; /*PCI id to identify the controller */
+	u32 filelen;      /*Length of the entire file*/
+	u32 chunk_num;	  /*The chunk/part number for multiple Image files */
+	u32 total_chunks; /*Total number of chunks/parts in the image file */
+	u32 num_images;   /* Number of images in the file */
+	u32 build_num;    /* Build number of this image */
+	struct image_info image_header;
+};
+
+int asd_verify_flash_seg(struct asd_ha_struct *asd_ha,
+		void *src, u32 dest_offset, u32 bytes_to_verify);
+int asd_write_flash_seg(struct asd_ha_struct *asd_ha,
+		void *src, u32 dest_offset, u32 bytes_to_write);
+int asd_chk_write_status(struct asd_ha_struct *asd_ha,
+		u32 sector_addr, u8 erase_flag);
+int asd_check_flash_type(struct asd_ha_struct *asd_ha);
+int asd_erase_nv_sector(struct asd_ha_struct *asd_ha,
+		u32 flash_addr, u32 size);
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index ee0a98bffcd4..965d4bb999d9 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -187,29 +187,13 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
 	ts->buf_valid_size = 0;
 	edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
 	r = edb->vaddr;
-	if (task->task_proto == SAS_PROTO_SSP) {
+	if (task->task_proto == SAS_PROTOCOL_SSP) {
 		struct ssp_response_iu *iu =
 			r + 16 + sizeof(struct ssp_frame_hdr);
 
 		ts->residual = le32_to_cpu(*(__le32 *)r);
-		ts->resp = SAS_TASK_COMPLETE;
-		if (iu->datapres == 0)
-			ts->stat = iu->status;
-		else if (iu->datapres == 1)
-			ts->stat = iu->resp_data[3];
-		else if (iu->datapres == 2) {
-			ts->stat = SAM_CHECK_COND;
-			ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE,
-					 be32_to_cpu(iu->sense_data_len));
-			memcpy(ts->buf, iu->sense_data, ts->buf_valid_size);
-			if (iu->status != SAM_CHECK_COND) {
-				ASD_DPRINTK("device %llx sent sense data, but "
-					    "stat(0x%x) is not CHECK_CONDITION"
-					    "\n",
-					    SAS_ADDR(task->dev->sas_addr),
-					    iu->status);
-			}
-		}
+
+		sas_ssp_task_response(&asd_ha->pcidev->dev, task, iu);
 	}  else {
 		struct ata_task_resp *resp = (void *) &ts->buf[0];
 
@@ -341,14 +325,14 @@ Again:
 	}
 
 	switch (task->task_proto) {
-	case SATA_PROTO:
-	case SAS_PROTO_STP:
+	case SAS_PROTOCOL_SATA:
+	case SAS_PROTOCOL_STP:
 		asd_unbuild_ata_ascb(ascb);
 		break;
-	case SAS_PROTO_SMP:
+	case SAS_PROTOCOL_SMP:
 		asd_unbuild_smp_ascb(ascb);
 		break;
-	case SAS_PROTO_SSP:
+	case SAS_PROTOCOL_SSP:
 		asd_unbuild_ssp_ascb(ascb);
 	default:
 		break;
@@ -586,17 +570,17 @@ int asd_execute_task(struct sas_task *task, const int num,
 	list_for_each_entry(a, &alist, list) {
 		t = a->uldd_task;
 		a->uldd_timer = 1;
-		if (t->task_proto & SAS_PROTO_STP)
-			t->task_proto = SAS_PROTO_STP;
+		if (t->task_proto & SAS_PROTOCOL_STP)
+			t->task_proto = SAS_PROTOCOL_STP;
 		switch (t->task_proto) {
-		case SATA_PROTO:
-		case SAS_PROTO_STP:
+		case SAS_PROTOCOL_SATA:
+		case SAS_PROTOCOL_STP:
 			res = asd_build_ata_ascb(a, t, gfp_flags);
 			break;
-		case SAS_PROTO_SMP:
+		case SAS_PROTOCOL_SMP:
 			res = asd_build_smp_ascb(a, t, gfp_flags);
 			break;
-		case SAS_PROTO_SSP:
+		case SAS_PROTOCOL_SSP:
 			res = asd_build_ssp_ascb(a, t, gfp_flags);
 			break;
 		default:
@@ -633,14 +617,14 @@ out_err_unmap:
 			t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
 			spin_unlock_irqrestore(&t->task_state_lock, flags);
 			switch (t->task_proto) {
-			case SATA_PROTO:
-			case SAS_PROTO_STP:
+			case SAS_PROTOCOL_SATA:
+			case SAS_PROTOCOL_STP:
 				asd_unbuild_ata_ascb(a);
 				break;
-			case SAS_PROTO_SMP:
+			case SAS_PROTOCOL_SMP:
 				asd_unbuild_smp_ascb(a);
 				break;
-			case SAS_PROTO_SSP:
+			case SAS_PROTOCOL_SSP:
 				asd_unbuild_ssp_ascb(a);
 			default:
 				break;
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index c0d0b7d7a8ce..87b2f6e6adfe 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -372,21 +372,21 @@ int asd_abort_task(struct sas_task *task)
 	scb->header.opcode = ABORT_TASK;
 
 	switch (task->task_proto) {
-	case SATA_PROTO:
-	case SAS_PROTO_STP:
+	case SAS_PROTOCOL_SATA:
+	case SAS_PROTOCOL_STP:
 		scb->abort_task.proto_conn_rate = (1 << 5); /* STP */
 		break;
-	case SAS_PROTO_SSP:
+	case SAS_PROTOCOL_SSP:
 		scb->abort_task.proto_conn_rate  = (1 << 4); /* SSP */
 		scb->abort_task.proto_conn_rate |= task->dev->linkrate;
 		break;
-	case SAS_PROTO_SMP:
+	case SAS_PROTOCOL_SMP:
 		break;
 	default:
 		break;
 	}
 
-	if (task->task_proto == SAS_PROTO_SSP) {
+	if (task->task_proto == SAS_PROTOCOL_SSP) {
 		scb->abort_task.ssp_frame.frame_type = SSP_TASK;
 		memcpy(scb->abort_task.ssp_frame.hashed_dest_addr,
 		       task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
@@ -512,7 +512,7 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
 	int res = 1;
 	struct scb *scb;
 
-	if (!(dev->tproto & SAS_PROTO_SSP))
+	if (!(dev->tproto & SAS_PROTOCOL_SSP))
 		return TMF_RESP_FUNC_ESUPP;
 
 	ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index d466a2dac1db..f4a202e8df26 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -122,7 +122,6 @@ static struct scsi_host_template arcmsr_scsi_host_template = {
 	.max_sectors    	= ARCMSR_MAX_XFER_SECTORS,
 	.cmd_per_lun		= ARCMSR_MAX_CMD_PERLUN,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 	.shost_attrs		= arcmsr_host_attrs,
 };
 #ifdef CONFIG_SCSI_ARCMSR_AER
@@ -634,9 +633,9 @@ static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
 	pcmd->result = DID_OK << 16;
 	if (sensebuffer) {
 		int sense_data_length =
-			sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer)
-			? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer);
-		memset(sensebuffer, 0, sizeof(pcmd->sense_buffer));
+			sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE
+			? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE;
+		memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE);
 		memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
 		sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
 		sensebuffer->Valid = 1;
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index a9680b5e8ac6..93b61f148653 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -511,9 +511,9 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd)
 	 * various queues are valid.
 	 */
 
-	if (cmd->use_sg) {
-		cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer;
-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+	if (scsi_bufflen(cmd)) {
+		cmd->SCp.buffer = scsi_sglist(cmd);
+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
 		/* ++roman: Try to merge some scatter-buffers if they are at
@@ -523,8 +523,8 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd)
 	} else {
 		cmd->SCp.buffer = NULL;
 		cmd->SCp.buffers_residual = 0;
-		cmd->SCp.ptr = (char *)cmd->request_buffer;
-		cmd->SCp.this_residual = cmd->request_bufflen;
+		cmd->SCp.ptr = NULL;
+		cmd->SCp.this_residual = 0;
 	}
 }
 
@@ -936,21 +936,21 @@ static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 	}
 # endif
 # ifdef NCR5380_STAT_LIMIT
-	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+	if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
 # endif
 		switch (cmd->cmnd[0]) {
 		case WRITE:
 		case WRITE_6:
 		case WRITE_10:
 			hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
-			hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+			hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
 			hostdata->pendingw++;
 			break;
 		case READ:
 		case READ_6:
 		case READ_10:
 			hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
-			hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+			hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
 			hostdata->pendingr++;
 			break;
 		}
@@ -1352,21 +1352,21 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id)
 static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd)
 {
 # ifdef NCR5380_STAT_LIMIT
-	if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+	if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
 # endif
 		switch (cmd->cmnd[0]) {
 		case WRITE:
 		case WRITE_6:
 		case WRITE_10:
 			hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
-			/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
+			/*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/
 			hostdata->pendingw--;
 			break;
 		case READ:
 		case READ_6:
 		case READ_10:
 			hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
-			/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
+			/*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/
 			hostdata->pendingr--;
 			break;
 		}
@@ -1868,7 +1868,7 @@ static int do_abort(struct Scsi_Host *host)
 	 * the target sees, so we just handshake.
 	 */
 
-	while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ)
+	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
 		;
 
 	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index fec58cc47f1c..db6de5e6afb3 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -471,18 +471,8 @@ go_42:
 			/*
 			 *	Complete the command
 			 */
-			if (workreq->use_sg) {
-				pci_unmap_sg(dev->pdev,
-					(struct scatterlist *)workreq->request_buffer,
-					workreq->use_sg,
-					workreq->sc_data_direction);
-			} else if (workreq->request_bufflen &&
-					workreq->sc_data_direction != DMA_NONE) {
-				pci_unmap_single(dev->pdev,
-					workreq->SCp.dma_handle,
-					workreq->request_bufflen,
-					workreq->sc_data_direction);
-			}			
+			scsi_dma_unmap(workreq);
+
 			spin_lock_irqsave(dev->host->host_lock, flags);
 			(*workreq->scsi_done) (workreq);
 #ifdef ED_DBGP
@@ -624,7 +614,7 @@ static int atp870u_queuecommand(struct scsi_cmnd * req_p,
 
 	c = scmd_channel(req_p);
 	req_p->sense_buffer[0]=0;
-	req_p->resid = 0;
+	scsi_set_resid(req_p, 0);
 	if (scmd_channel(req_p) > 1) {
 		req_p->result = 0x00040000;
 		done(req_p);
@@ -722,7 +712,6 @@ static void send_s870(struct atp_unit *dev,unsigned char c)
 	unsigned short int tmpcip, w;
 	unsigned long l, bttl = 0;
 	unsigned int workport;
-	struct scatterlist *sgpnt;
 	unsigned long  sg_count;
 
 	if (dev->in_snd[c] != 0) {
@@ -793,6 +782,8 @@ oktosend:
 	}
 	printk("\n");
 #endif	
+	l = scsi_bufflen(workreq);
+
 	if (dev->dev_id == ATP885_DEVID) {
 		j = inb(dev->baseport + 0x29) & 0xfe;
 		outb(j, dev->baseport + 0x29);
@@ -800,12 +791,11 @@ oktosend:
 	}
 	
 	if (workreq->cmnd[0] == READ_CAPACITY) {
-		if (workreq->request_bufflen > 8) {
-			workreq->request_bufflen = 0x08;
-		}
+		if (l > 8)
+			l = 8;
 	}
 	if (workreq->cmnd[0] == 0x00) {
-		workreq->request_bufflen = 0;
+		l = 0;
 	}
 
 	tmport = workport + 0x1b;
@@ -852,40 +842,8 @@ oktosend:
 #ifdef ED_DBGP	
 	printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
 #endif
-	/*
-	 *	Figure out the transfer size
-	 */
-	if (workreq->use_sg) {
-#ifdef ED_DBGP
-		printk("Using SGL\n");
-#endif		
-		l = 0;
-		
-		sgpnt = (struct scatterlist *) workreq->request_buffer;
-		sg_count = pci_map_sg(dev->pdev, sgpnt, workreq->use_sg,
-	   			workreq->sc_data_direction);		
-		
-		for (i = 0; i < workreq->use_sg; i++) {
-			if (sgpnt[i].length == 0 || workreq->use_sg > ATP870U_SCATTER) {
-				panic("Foooooooood fight!");
-			}
-			l += sgpnt[i].length;
-		}
-#ifdef ED_DBGP		
-		printk( "send_s870: workreq->use_sg %d, sg_count %d l %8ld\n", workreq->use_sg, sg_count, l);
-#endif
-	} else if(workreq->request_bufflen && workreq->sc_data_direction != PCI_DMA_NONE) {
-#ifdef ED_DBGP
-		printk("Not using SGL\n");
-#endif					
-		workreq->SCp.dma_handle = pci_map_single(dev->pdev, workreq->request_buffer,
-				workreq->request_bufflen,
-				workreq->sc_data_direction);		
-		l = workreq->request_bufflen;
-#ifdef ED_DBGP		
-		printk( "send_s870: workreq->use_sg %d, l %8ld\n", workreq->use_sg, l);
-#endif
-	} else l = 0;
+
+	sg_count = scsi_dma_map(workreq);
 	/*
 	 *	Write transfer size
 	 */
@@ -938,16 +896,16 @@ oktosend:
 	 *	a linear chain.
 	 */
 
-	if (workreq->use_sg) {
-		sgpnt = (struct scatterlist *) workreq->request_buffer;
+	if (l) {
+		struct scatterlist *sgpnt;
 		i = 0;
-		for (j = 0; j < workreq->use_sg; j++) {
-			bttl = sg_dma_address(&sgpnt[j]);
-			l=sg_dma_len(&sgpnt[j]);
+		scsi_for_each_sg(workreq, sgpnt, sg_count, j) {
+			bttl = sg_dma_address(sgpnt);
+			l=sg_dma_len(sgpnt);
 #ifdef ED_DBGP		
-		printk("1. bttl %x, l %x\n",bttl, l);
+			printk("1. bttl %x, l %x\n",bttl, l);
 #endif			
-		while (l > 0x10000) {
+			while (l > 0x10000) {
 				(((u16 *) (prd))[i + 3]) = 0x0000;
 				(((u16 *) (prd))[i + 2]) = 0x0000;
 				(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
@@ -965,32 +923,6 @@ oktosend:
 		printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
 		printk("2. bttl %x, l %x\n",bttl, l);
 #endif			
-	} else {
-		/*
-		 *	For a linear request write a chain of blocks
-		 */        
-		bttl = workreq->SCp.dma_handle;
-		l = workreq->request_bufflen;
-		i = 0;
-#ifdef ED_DBGP		
-		printk("3. bttl %x, l %x\n",bttl, l);
-#endif			
-		while (l > 0x10000) {
-				(((u16 *) (prd))[i + 3]) = 0x0000;
-				(((u16 *) (prd))[i + 2]) = 0x0000;
-				(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
-				l -= 0x10000;
-				bttl += 0x10000;
-				i += 0x04;
-			}
-			(((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000);
-			(((u16 *) (prd))[i + 2]) = cpu_to_le16(l);
-			(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);		
-#ifdef ED_DBGP		
-		printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
-		printk("4. bttl %x, l %x\n",bttl, l);
-#endif			
-		
 	}
 	tmpcip += 4;
 #ifdef ED_DBGP		
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 2311019304c0..7aad15436d24 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -21,6 +21,7 @@
 #include <linux/compat.h>
 #include <linux/chio.h>			/* here are all the ioctls */
 #include <linux/mutex.h>
+#include <linux/idr.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -33,6 +34,7 @@
 
 #define CH_DT_MAX       16
 #define CH_TYPES        8
+#define CH_MAX_DEVS     128
 
 MODULE_DESCRIPTION("device driver for scsi media changer devices");
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>");
@@ -88,17 +90,6 @@ static const char * vendor_labels[CH_TYPES-4] = {
 
 #define MAX_RETRIES   1
 
-static int  ch_probe(struct device *);
-static int  ch_remove(struct device *);
-static int  ch_open(struct inode * inode, struct file * filp);
-static int  ch_release(struct inode * inode, struct file * filp);
-static int  ch_ioctl(struct inode * inode, struct file * filp,
-		     unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-static long ch_ioctl_compat(struct file * filp,
-			    unsigned int cmd, unsigned long arg);
-#endif
-
 static struct class * ch_sysfs_class;
 
 typedef struct {
@@ -114,30 +105,8 @@ typedef struct {
 	struct mutex	    lock;
 } scsi_changer;
 
-static LIST_HEAD(ch_devlist);
-static DEFINE_SPINLOCK(ch_devlist_lock);
-static int ch_devcount;
-
-static struct scsi_driver ch_template =
-{
-	.owner     	= THIS_MODULE,
-	.gendrv     	= {
-		.name	= "ch",
-		.probe  = ch_probe,
-		.remove = ch_remove,
-	},
-};
-
-static const struct file_operations changer_fops =
-{
-	.owner        = THIS_MODULE,
-	.open         = ch_open,
-	.release      = ch_release,
-	.ioctl        = ch_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl = ch_ioctl_compat,
-#endif
-};
+static DEFINE_IDR(ch_index_idr);
+static DEFINE_SPINLOCK(ch_index_lock);
 
 static const struct {
 	unsigned char  sense;
@@ -207,7 +176,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
 {
 	int errno, retries = 0, timeout, result;
 	struct scsi_sense_hdr sshdr;
-	
+
 	timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
 		? timeout_init : timeout_move;
 
@@ -245,7 +214,7 @@ static int
 ch_elem_to_typecode(scsi_changer *ch, u_int elem)
 {
 	int i;
-	
+
 	for (i = 0; i < CH_TYPES; i++) {
 		if (elem >= ch->firsts[i]  &&
 		    elem <  ch->firsts[i] +
@@ -261,15 +230,15 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
 	u_char  cmd[12];
 	u_char  *buffer;
 	int     result;
-	
+
 	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
 	if(!buffer)
 		return -ENOMEM;
-	
+
  retry:
 	memset(cmd,0,sizeof(cmd));
 	cmd[0] = READ_ELEMENT_STATUS;
-	cmd[1] = (ch->device->lun << 5) | 
+	cmd[1] = (ch->device->lun << 5) |
 		(ch->voltags ? 0x10 : 0) |
 		ch_elem_to_typecode(ch,elem);
 	cmd[2] = (elem >> 8) & 0xff;
@@ -296,7 +265,7 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
 	return result;
 }
 
-static int 
+static int
 ch_init_elem(scsi_changer *ch)
 {
 	int err;
@@ -322,7 +291,7 @@ ch_readconfig(scsi_changer *ch)
 	buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
 	if (!buffer)
 		return -ENOMEM;
-	
+
 	memset(cmd,0,sizeof(cmd));
 	cmd[0] = MODE_SENSE;
 	cmd[1] = ch->device->lun << 5;
@@ -365,7 +334,7 @@ ch_readconfig(scsi_changer *ch)
 	} else {
 		vprintk("reading element address assigment page failed!\n");
 	}
-	
+
 	/* vendor specific element types */
 	for (i = 0; i < 4; i++) {
 		if (0 == vendor_counts[i])
@@ -443,7 +412,7 @@ static int
 ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
 {
 	u_char  cmd[10];
-	
+
 	dprintk("position: 0x%x\n",elem);
 	if (0 == trans)
 		trans = ch->firsts[CHET_MT];
@@ -462,7 +431,7 @@ static int
 ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
 {
 	u_char  cmd[12];
-	
+
 	dprintk("move: 0x%x => 0x%x\n",src,dest);
 	if (0 == trans)
 		trans = ch->firsts[CHET_MT];
@@ -484,7 +453,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
 	    u_int dest1, u_int dest2, int rotate1, int rotate2)
 {
 	u_char  cmd[12];
-	
+
 	dprintk("exchange: 0x%x => 0x%x => 0x%x\n",
 		src,dest1,dest2);
 	if (0 == trans)
@@ -501,7 +470,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
 	cmd[8]  = (dest2 >> 8) & 0xff;
 	cmd[9]  =  dest2       & 0xff;
 	cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
-	
+
 	return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
 }
 
@@ -539,14 +508,14 @@ ch_set_voltag(scsi_changer *ch, u_int elem,
 		elem, tag);
 	memset(cmd,0,sizeof(cmd));
 	cmd[0]  = SEND_VOLUME_TAG;
-	cmd[1] = (ch->device->lun << 5) | 
+	cmd[1] = (ch->device->lun << 5) |
 		ch_elem_to_typecode(ch,elem);
 	cmd[2] = (elem >> 8) & 0xff;
 	cmd[3] = elem        & 0xff;
 	cmd[5] = clear
 		? (alternate ? 0x0d : 0x0c)
 		: (alternate ? 0x0b : 0x0a);
-	
+
 	cmd[9] = 255;
 
 	memcpy(buffer,tag,32);
@@ -562,7 +531,7 @@ static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
 	int retval = 0;
 	u_char data[16];
 	unsigned int i;
-	
+
 	mutex_lock(&ch->lock);
 	for (i = 0; i < ch->counts[type]; i++) {
 		if (0 != ch_read_element_status
@@ -599,20 +568,17 @@ ch_release(struct inode *inode, struct file *file)
 static int
 ch_open(struct inode *inode, struct file *file)
 {
-	scsi_changer *tmp, *ch;
+	scsi_changer *ch;
 	int minor = iminor(inode);
 
-	spin_lock(&ch_devlist_lock);
-	ch = NULL;
-	list_for_each_entry(tmp,&ch_devlist,list) {
-		if (tmp->minor == minor)
-			ch = tmp;
-	}
+	spin_lock(&ch_index_lock);
+	ch = idr_find(&ch_index_idr, minor);
+
 	if (NULL == ch || scsi_device_get(ch->device)) {
-		spin_unlock(&ch_devlist_lock);
+		spin_unlock(&ch_index_lock);
 		return -ENXIO;
 	}
-	spin_unlock(&ch_devlist_lock);
+	spin_unlock(&ch_index_lock);
 
 	file->private_data = ch;
 	return 0;
@@ -626,24 +592,24 @@ ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit)
 	return 0;
 }
 
-static int ch_ioctl(struct inode * inode, struct file * file,
+static long ch_ioctl(struct file *file,
 		    unsigned int cmd, unsigned long arg)
 {
 	scsi_changer *ch = file->private_data;
 	int retval;
 	void __user *argp = (void __user *)arg;
-	
+
 	switch (cmd) {
 	case CHIOGPARAMS:
 	{
 		struct changer_params params;
-		
+
 		params.cp_curpicker = 0;
 		params.cp_npickers  = ch->counts[CHET_MT];
 		params.cp_nslots    = ch->counts[CHET_ST];
 		params.cp_nportals  = ch->counts[CHET_IE];
 		params.cp_ndrives   = ch->counts[CHET_DT];
-		
+
 		if (copy_to_user(argp, &params, sizeof(params)))
 			return -EFAULT;
 		return 0;
@@ -673,11 +639,11 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 			return -EFAULT;
 		return 0;
 	}
-	
+
 	case CHIOPOSITION:
 	{
 		struct changer_position pos;
-		
+
 		if (copy_from_user(&pos, argp, sizeof (pos)))
 			return -EFAULT;
 
@@ -692,7 +658,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 		mutex_unlock(&ch->lock);
 		return retval;
 	}
-	
+
 	case CHIOMOVE:
 	{
 		struct changer_move mv;
@@ -705,7 +671,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 			dprintk("CHIOMOVE: invalid parameter\n");
 			return -EBADSLT;
 		}
-		
+
 		mutex_lock(&ch->lock);
 		retval = ch_move(ch,0,
 				 ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
@@ -718,7 +684,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 	case CHIOEXCHANGE:
 	{
 		struct changer_exchange mv;
-		
+
 		if (copy_from_user(&mv, argp, sizeof (mv)))
 			return -EFAULT;
 
@@ -728,7 +694,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 			dprintk("CHIOEXCHANGE: invalid parameter\n");
 			return -EBADSLT;
 		}
-		
+
 		mutex_lock(&ch->lock);
 		retval = ch_exchange
 			(ch,0,
@@ -743,7 +709,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 	case CHIOGSTATUS:
 	{
 		struct changer_element_status ces;
-		
+
 		if (copy_from_user(&ces, argp, sizeof (ces)))
 			return -EFAULT;
 		if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
@@ -759,19 +725,19 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 		u_char  *buffer;
 		unsigned int elem;
 		int     result,i;
-		
+
 		if (copy_from_user(&cge, argp, sizeof (cge)))
 			return -EFAULT;
 
 		if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
 			return -EINVAL;
 		elem = ch->firsts[cge.cge_type] + cge.cge_unit;
-		
+
 		buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
 		if (!buffer)
 			return -ENOMEM;
 		mutex_lock(&ch->lock);
-		
+
 	voltag_retry:
 		memset(cmd,0,sizeof(cmd));
 		cmd[0] = READ_ELEMENT_STATUS;
@@ -782,7 +748,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 		cmd[3] = elem        & 0xff;
 		cmd[5] = 1;
 		cmd[9] = 255;
-		
+
 		if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) {
 			cge.cge_status = buffer[18];
 			cge.cge_flags = 0;
@@ -822,7 +788,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 		}
 		kfree(buffer);
 		mutex_unlock(&ch->lock);
-		
+
 		if (copy_to_user(argp, &cge, sizeof (cge)))
 			return -EFAULT;
 		return result;
@@ -835,7 +801,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 		mutex_unlock(&ch->lock);
 		return retval;
 	}
-		
+
 	case CHIOSVOLTAG:
 	{
 		struct changer_set_voltag csv;
@@ -876,7 +842,7 @@ static long ch_ioctl_compat(struct file * file,
 			    unsigned int cmd, unsigned long arg)
 {
 	scsi_changer *ch = file->private_data;
-	
+
 	switch (cmd) {
 	case CHIOGPARAMS:
 	case CHIOGVPARAMS:
@@ -887,13 +853,12 @@ static long ch_ioctl_compat(struct file * file,
 	case CHIOINITELEM:
 	case CHIOSVOLTAG:
 		/* compatible */
-		return ch_ioctl(NULL /* inode, unused */,
-				file, cmd, arg);
+		return ch_ioctl(file, cmd, arg);
 	case CHIOGSTATUS32:
 	{
 		struct changer_element_status32 ces32;
 		unsigned char __user *data;
-		
+
 		if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32)))
 			return -EFAULT;
 		if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
@@ -915,63 +880,100 @@ static long ch_ioctl_compat(struct file * file,
 static int ch_probe(struct device *dev)
 {
 	struct scsi_device *sd = to_scsi_device(dev);
+	struct class_device *class_dev;
+	int minor, ret = -ENOMEM;
 	scsi_changer *ch;
-	
+
 	if (sd->type != TYPE_MEDIUM_CHANGER)
 		return -ENODEV;
-    
+
 	ch = kzalloc(sizeof(*ch), GFP_KERNEL);
 	if (NULL == ch)
 		return -ENOMEM;
 
-	ch->minor = ch_devcount;
+	if (!idr_pre_get(&ch_index_idr, GFP_KERNEL))
+		goto free_ch;
+
+	spin_lock(&ch_index_lock);
+	ret = idr_get_new(&ch_index_idr, ch, &minor);
+	spin_unlock(&ch_index_lock);
+
+	if (ret)
+		goto free_ch;
+
+	if (minor > CH_MAX_DEVS) {
+		ret = -ENODEV;
+		goto remove_idr;
+	}
+
+	ch->minor = minor;
 	sprintf(ch->name,"ch%d",ch->minor);
+
+	class_dev = class_device_create(ch_sysfs_class, NULL,
+					MKDEV(SCSI_CHANGER_MAJOR, ch->minor),
+					dev, "s%s", ch->name);
+	if (IS_ERR(class_dev)) {
+		printk(KERN_WARNING "ch%d: class_device_create failed\n",
+		       ch->minor);
+		ret = PTR_ERR(class_dev);
+		goto remove_idr;
+	}
+
 	mutex_init(&ch->lock);
 	ch->device = sd;
 	ch_readconfig(ch);
 	if (init)
 		ch_init_elem(ch);
 
-	class_device_create(ch_sysfs_class, NULL,
-			    MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
-			    dev, "s%s", ch->name);
-
+	dev_set_drvdata(dev, ch);
 	sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
-	
-	spin_lock(&ch_devlist_lock);
-	list_add_tail(&ch->list,&ch_devlist);
-	ch_devcount++;
-	spin_unlock(&ch_devlist_lock);
+
 	return 0;
+remove_idr:
+	idr_remove(&ch_index_idr, minor);
+free_ch:
+	kfree(ch);
+	return ret;
 }
 
 static int ch_remove(struct device *dev)
 {
-	struct scsi_device *sd = to_scsi_device(dev);
-	scsi_changer *tmp, *ch;
+	scsi_changer *ch = dev_get_drvdata(dev);
 
-	spin_lock(&ch_devlist_lock);
-	ch = NULL;
-	list_for_each_entry(tmp,&ch_devlist,list) {
-		if (tmp->device == sd)
-			ch = tmp;
-	}
-	BUG_ON(NULL == ch);
-	list_del(&ch->list);
-	spin_unlock(&ch_devlist_lock);
+	spin_lock(&ch_index_lock);
+	idr_remove(&ch_index_idr, ch->minor);
+	spin_unlock(&ch_index_lock);
 
 	class_device_destroy(ch_sysfs_class,
 			     MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
 	kfree(ch->dt);
 	kfree(ch);
-	ch_devcount--;
 	return 0;
 }
 
+static struct scsi_driver ch_template = {
+	.owner     	= THIS_MODULE,
+	.gendrv     	= {
+		.name	= "ch",
+		.probe  = ch_probe,
+		.remove = ch_remove,
+	},
+};
+
+static const struct file_operations changer_fops = {
+	.owner		= THIS_MODULE,
+	.open		= ch_open,
+	.release	= ch_release,
+	.unlocked_ioctl	= ch_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= ch_ioctl_compat,
+#endif
+};
+
 static int __init init_ch_module(void)
 {
 	int rc;
-	
+
 	printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n");
         ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer");
         if (IS_ERR(ch_sysfs_class)) {
@@ -996,11 +998,12 @@ static int __init init_ch_module(void)
 	return rc;
 }
 
-static void __exit exit_ch_module(void) 
+static void __exit exit_ch_module(void)
 {
 	scsi_unregister_driver(&ch_template.gendrv);
 	unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
 	class_destroy(ch_sysfs_class);
+	idr_destroy(&ch_index_idr);
 }
 
 module_init(init_ch_module);
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 024553f9c247..403a7f2d8f9b 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -362,7 +362,6 @@ void scsi_print_command(struct scsi_cmnd *cmd)
 EXPORT_SYMBOL(scsi_print_command);
 
 /**
- *
  *	scsi_print_status - print scsi status description
  *	@scsi_status: scsi status value
  *
@@ -1369,7 +1368,7 @@ EXPORT_SYMBOL(scsi_print_sense);
 static const char * const hostbyte_table[]={
 "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET",
 "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
-"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"};
+"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE"};
 #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table)
 
 static const char * const driverbyte_table[]={
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index a9def6e1d30e..22ef3716e786 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -1629,8 +1629,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
-		DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
-			      sizeof(srb->cmd->sense_buffer));
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
 	} else {
 		ptr = (u8 *)srb->cmd->cmnd;
@@ -1915,8 +1914,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
-		DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
-			      sizeof(srb->cmd->sense_buffer));
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE);
 		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
 	}
 	srb->state |= SRB_COMMAND;
@@ -3685,7 +3683,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
 	srb->target_status = 0;
 
 	/* KG: Can this prevent crap sense data ? */
-	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 
 	/* Save some data */
 	srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address =
@@ -3694,15 +3692,15 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
 	    srb->segment_x[0].length;
 	srb->xferred = srb->total_xfer_length;
 	/* srb->segment_x : a one entry of S/G list table */
-	srb->total_xfer_length = sizeof(cmd->sense_buffer);
-	srb->segment_x[0].length = sizeof(cmd->sense_buffer);
+	srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE;
+	srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE;
 	/* Map sense buffer */
 	srb->segment_x[0].address =
 	    pci_map_single(acb->dev, cmd->sense_buffer,
-			   sizeof(cmd->sense_buffer), PCI_DMA_FROMDEVICE);
+			   SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE);
 	dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n",
 	       cmd->sense_buffer, srb->segment_x[0].address,
-	       sizeof(cmd->sense_buffer));
+	       SCSI_SENSE_BUFFERSIZE);
 	srb->sg_count = 1;
 	srb->sg_index = 0;
 
@@ -4765,7 +4763,6 @@ static struct scsi_host_template dc395x_driver_template = {
 	.eh_bus_reset_handler   = dc395x_eh_bus_reset,
 	.unchecked_isa_dma      = 0,
 	.use_clustering         = DISABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 };
 
 
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index b31d1c95c9fb..c9dd8392aab2 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -2296,9 +2296,8 @@ static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd)
 
 		// copy over the request sense data if it was a check
 		// condition status
-		if(dev_status == 0x02 /*CHECK_CONDITION*/) {
-			u32 len = sizeof(cmd->sense_buffer);
-			len = (len > 40) ?  40 : len;
+		if (dev_status == SAM_STAT_CHECK_CONDITION) {
+			u32 len = min(SCSI_SENSE_BUFFERSIZE, 40);
 			// Copy over the sense data
 			memcpy_fromio(cmd->sense_buffer, (reply+28) , len);
 			if(cmd->sense_buffer[0] == 0x70 /* class 7 */ && 
@@ -3341,7 +3340,6 @@ static struct scsi_host_template driver_template = {
 	.this_id		= 7,
 	.cmd_per_lun		= 1,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 };
 #include "scsi_module.c"
 MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 7ead5210de96..8be3d76656fa 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -524,7 +524,6 @@ static struct scsi_host_template driver_template = {
 	.this_id = 7,
 	.unchecked_isa_dma = 1,
 	.use_clustering = ENABLE_CLUSTERING,
-	.use_sg_chaining = ENABLE_SG_CHAINING,
 };
 
 #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
@@ -1623,9 +1622,9 @@ static void map_dma(unsigned int i, struct hostdata *ha)
 	if (SCpnt->sense_buffer)
 		cpp->sense_addr =
 		    H2DEV(pci_map_single(ha->pdev, SCpnt->sense_buffer,
-			   sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+			   SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE));
 
-	cpp->sense_len = sizeof SCpnt->sense_buffer;
+	cpp->sense_len = SCSI_SENSE_BUFFERSIZE;
 
 	count = scsi_dma_map(SCpnt);
 	BUG_ON(count < 0);
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 982c5092be11..b5a60926e556 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -369,7 +369,6 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
 	cp = &hd->ccb[y];
 
 	memset(cp, 0, sizeof(struct eata_ccb));
-	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
 
 	cp->status = USED;	/* claim free slot */
 
@@ -385,7 +384,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
 		cp->DataIn = 0;	/* Input mode  */
 
 	cp->Interpret = (cmd->device->id == hd->hostid);
-	cp->cp_datalen = cpu_to_be32(cmd->request_bufflen);
+	cp->cp_datalen = cpu_to_be32(scsi_bufflen(cmd));
 	cp->Auto_Req_Sen = 0;
 	cp->cp_reqDMA = 0;
 	cp->reqlen = 0;
@@ -402,14 +401,14 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
 	cp->cmd = cmd;
 	cmd->host_scribble = (char *) &hd->ccb[y];
 
-	if (cmd->use_sg == 0) {
+	if (!scsi_bufflen(cmd)) {
 		cmd->SCp.buffers_residual = 1;
-		cmd->SCp.ptr = cmd->request_buffer;
-		cmd->SCp.this_residual = cmd->request_bufflen;
+		cmd->SCp.ptr = NULL;
+		cmd->SCp.this_residual = 0;
 		cmd->SCp.buffer = NULL;
 	} else {
-		cmd->SCp.buffer = cmd->request_buffer;
-		cmd->SCp.buffers_residual = cmd->use_sg;
+		cmd->SCp.buffer = scsi_sglist(cmd);
+		cmd->SCp.buffers_residual = scsi_sg_count(cmd);
 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
 	}
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index 8335b608e571..85bd54c77b50 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -1017,24 +1017,6 @@ static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
 		printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in);
 #endif
 
-#if ERRORS_ONLY
-		if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
-			if ((unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f) {
-				unsigned char key;
-				unsigned char code;
-				unsigned char qualifier;
-
-				key = (unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f;
-				code = (unsigned char) (*((char *) current_SC->request_buffer + 12));
-				qualifier = (unsigned char) (*((char *) current_SC->request_buffer + 13));
-
-				if (key != UNIT_ATTENTION && !(key == NOT_READY && code == 0x04 && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
-				    && !(key == ILLEGAL_REQUEST && (code == 0x25 || code == 0x24 || !code)))
-
-					printk("fd_mcs: REQUEST SENSE " "Key = %x, Code = %x, Qualifier = %x\n", key, code, qualifier);
-			}
-		}
-#endif
 #if EVERY_ACCESS
 		printk("BEFORE MY_DONE. . .");
 #endif
@@ -1097,7 +1079,9 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 		panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n");
 	}
 #if EVERY_ACCESS
-	printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->target, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
+	printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+		SCpnt->target, *(unsigned char *) SCpnt->cmnd,
+		scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
 #endif
 
 	fd_mcs_make_bus_idle(shpnt);
@@ -1107,14 +1091,14 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 
 	/* Initialize static data */
 
-	if (current_SC->use_sg) {
-		current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer;
+	if (scsi_bufflen(current_SC)) {
+		current_SC->SCp.buffer = scsi_sglist(current_SC);
 		current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
 		current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
-		current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
+		current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
 	} else {
-		current_SC->SCp.ptr = (char *) current_SC->request_buffer;
-		current_SC->SCp.this_residual = current_SC->request_bufflen;
+		current_SC->SCp.ptr = NULL;
+		current_SC->SCp.this_residual = 0;
 		current_SC->SCp.buffer = NULL;
 		current_SC->SCp.buffers_residual = 0;
 	}
@@ -1166,7 +1150,9 @@ static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
 		break;
 	}
 
-	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
+	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+		SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd,
+		scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
 	printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout);
 #if DEBUG_RACE
 	printk("in_interrupt_flag = %d\n", in_interrupt_flag);
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index b253b8c718d3..c82523908c2e 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -141,7 +141,7 @@
 static void gdth_delay(int milliseconds);
 static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
 static irqreturn_t gdth_interrupt(int irq, void *dev_id);
-static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
                                     int gdth_from_wait, int* pIndex);
 static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
                                                                Scsi_Cmnd *scp);
@@ -165,7 +165,6 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
 static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive);
 
 static void gdth_enable_int(gdth_ha_str *ha);
-static unchar gdth_get_status(gdth_ha_str *ha, int irq);
 static int gdth_test_busy(gdth_ha_str *ha);
 static int gdth_get_cmd_index(gdth_ha_str *ha);
 static void gdth_release_event(gdth_ha_str *ha);
@@ -1334,14 +1333,12 @@ static void __init gdth_enable_int(gdth_ha_str *ha)
 }
 
 /* return IStatus if interrupt was from this card else 0 */
-static unchar gdth_get_status(gdth_ha_str *ha, int irq)
+static unchar gdth_get_status(gdth_ha_str *ha)
 {
     unchar IStatus = 0;
 
-    TRACE(("gdth_get_status() irq %d ctr_count %d\n", irq, gdth_ctr_count));
+    TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count));
 
-        if (ha->irq != (unchar)irq)             /* check IRQ */
-            return false;
         if (ha->type == GDT_EISA)
             IStatus = inb((ushort)ha->bmic + EDOORREG);
         else if (ha->type == GDT_ISA)
@@ -1523,7 +1520,7 @@ static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time)
         return 1;                               /* no wait required */
 
     do {
-        __gdth_interrupt(ha, (int)ha->irq, true, &wait_index);
+	__gdth_interrupt(ha, true, &wait_index);
         if (wait_index == index) {
             answer_found = TRUE;
             break;
@@ -3036,7 +3033,7 @@ static void gdth_clear_events(void)
 
 /* SCSI interface functions */
 
-static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha,
                                     int gdth_from_wait, int* pIndex)
 {
     gdt6m_dpram_str __iomem *dp6m_ptr = NULL;
@@ -3054,7 +3051,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
     int act_int_coal = 0;       
 #endif
 
-    TRACE(("gdth_interrupt() IRQ %d\n",irq));
+    TRACE(("gdth_interrupt() IRQ %d\n", ha->irq));
 
     /* if polling and not from gdth_wait() -> return */
     if (gdth_polling) {
@@ -3067,7 +3064,8 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
         spin_lock_irqsave(&ha->smp_lock, flags);
 
     /* search controller */
-    if (0 == (IStatus = gdth_get_status(ha, irq))) {
+    IStatus = gdth_get_status(ha);
+    if (IStatus == 0) {
         /* spurious interrupt */
         if (!gdth_polling)
             spin_unlock_irqrestore(&ha->smp_lock, flags);
@@ -3294,9 +3292,9 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
 
 static irqreturn_t gdth_interrupt(int irq, void *dev_id)
 {
-	gdth_ha_str *ha = (gdth_ha_str *)dev_id;
+	gdth_ha_str *ha = dev_id;
 
-	return __gdth_interrupt(ha, irq, false, NULL);
+	return __gdth_interrupt(ha, false, NULL);
 }
 
 static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 24271a871b8c..880c78bff0e1 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -54,8 +54,7 @@ static struct class shost_class = {
 };
 
 /**
- *	scsi_host_set_state - Take the given host through the host
- *		state model.
+ *	scsi_host_set_state - Take the given host through the host state model.
  *	@shost:	scsi host to change the state of.
  *	@state:	state to change to.
  *
@@ -343,7 +342,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
 	shost->use_clustering = sht->use_clustering;
 	shost->ordered_tag = sht->ordered_tag;
 	shost->active_mode = sht->supported_mode;
-	shost->use_sg_chaining = sht->use_sg_chaining;
 
 	if (sht->supported_mode == MODE_UNKNOWN)
 		/* means we didn't set it ... default to INITIATOR */
@@ -429,9 +427,17 @@ void scsi_unregister(struct Scsi_Host *shost)
 }
 EXPORT_SYMBOL(scsi_unregister);
 
+static int __scsi_host_match(struct class_device *cdev, void *data)
+{
+	struct Scsi_Host *p;
+	unsigned short *hostnum = (unsigned short *)data;
+
+	p = class_to_shost(cdev);
+	return p->host_no == *hostnum;
+}
+
 /**
  * scsi_host_lookup - get a reference to a Scsi_Host by host no
- *
  * @hostnum:	host number to locate
  *
  * Return value:
@@ -439,19 +445,12 @@ EXPORT_SYMBOL(scsi_unregister);
  **/
 struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
 {
-	struct class *class = &shost_class;
 	struct class_device *cdev;
-	struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
+	struct Scsi_Host *shost = ERR_PTR(-ENXIO);
 
-	down(&class->sem);
-	list_for_each_entry(cdev, &class->children, node) {
-		p = class_to_shost(cdev);
-		if (p->host_no == hostnum) {
-			shost = scsi_host_get(p);
-			break;
-		}
-	}
-	up(&class->sem);
+	cdev = class_find_child(&shost_class, &hostnum, __scsi_host_match);
+	if (cdev)
+		shost = scsi_host_get(class_to_shost(cdev));
 
 	return shost;
 }
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 0844331abb87..ff149ad6bc4e 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -1,5 +1,5 @@
 /*
- * HighPoint RR3xxx controller driver for Linux
+ * HighPoint RR3xxx/4xxx controller driver for Linux
  * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -38,80 +38,84 @@
 #include "hptiop.h"
 
 MODULE_AUTHOR("HighPoint Technologies, Inc.");
-MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx SATA Controller Driver");
+MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
 
 static char driver_name[] = "hptiop";
-static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver";
-static const char driver_ver[] = "v1.2 (070830)";
-
-static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag);
-static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag);
+static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
+static const char driver_ver[] = "v1.3 (071203)";
+
+static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
+static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
+				struct hpt_iop_request_scsi_command *req);
+static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 tag);
+static void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag);
 static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg);
 
-static inline void hptiop_pci_posting_flush(struct hpt_iopmu __iomem *iop)
-{
-	readl(&iop->outbound_intstatus);
-}
-
-static int iop_wait_ready(struct hpt_iopmu __iomem *iop, u32 millisec)
+static int iop_wait_ready_itl(struct hptiop_hba *hba, u32 millisec)
 {
 	u32 req = 0;
 	int i;
 
 	for (i = 0; i < millisec; i++) {
-		req = readl(&iop->inbound_queue);
+		req = readl(&hba->u.itl.iop->inbound_queue);
 		if (req != IOPMU_QUEUE_EMPTY)
 			break;
 		msleep(1);
 	}
 
 	if (req != IOPMU_QUEUE_EMPTY) {
-		writel(req, &iop->outbound_queue);
-		hptiop_pci_posting_flush(iop);
+		writel(req, &hba->u.itl.iop->outbound_queue);
+		readl(&hba->u.itl.iop->outbound_intstatus);
 		return 0;
 	}
 
 	return -1;
 }
 
-static void hptiop_request_callback(struct hptiop_hba *hba, u32 tag)
+static int iop_wait_ready_mv(struct hptiop_hba *hba, u32 millisec)
+{
+	return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec);
+}
+
+static void hptiop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
 {
 	if (tag & IOPMU_QUEUE_ADDR_HOST_BIT)
-		return hptiop_host_request_callback(hba,
+		hptiop_host_request_callback_itl(hba,
 				tag & ~IOPMU_QUEUE_ADDR_HOST_BIT);
 	else
-		return hptiop_iop_request_callback(hba, tag);
+		hptiop_iop_request_callback_itl(hba, tag);
 }
 
-static inline void hptiop_drain_outbound_queue(struct hptiop_hba *hba)
+static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba)
 {
 	u32 req;
 
-	while ((req = readl(&hba->iop->outbound_queue)) != IOPMU_QUEUE_EMPTY) {
+	while ((req = readl(&hba->u.itl.iop->outbound_queue)) !=
+						IOPMU_QUEUE_EMPTY) {
 
 		if (req & IOPMU_QUEUE_MASK_HOST_BITS)
-			hptiop_request_callback(hba, req);
+			hptiop_request_callback_itl(hba, req);
 		else {
 			struct hpt_iop_request_header __iomem * p;
 
 			p = (struct hpt_iop_request_header __iomem *)
-				((char __iomem *)hba->iop + req);
+				((char __iomem *)hba->u.itl.iop + req);
 
 			if (readl(&p->flags) & IOP_REQUEST_FLAG_SYNC_REQUEST) {
 				if (readl(&p->context))
-					hptiop_request_callback(hba, req);
+					hptiop_request_callback_itl(hba, req);
 				else
 					writel(1, &p->context);
 			}
 			else
-				hptiop_request_callback(hba, req);
+				hptiop_request_callback_itl(hba, req);
 		}
 	}
 }
 
-static int __iop_intr(struct hptiop_hba *hba)
+static int iop_intr_itl(struct hptiop_hba *hba)
 {
-	struct hpt_iopmu __iomem *iop = hba->iop;
+	struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop;
 	u32 status;
 	int ret = 0;
 
@@ -119,6 +123,7 @@ static int __iop_intr(struct hptiop_hba *hba)
 
 	if (status & IOPMU_OUTBOUND_INT_MSG0) {
 		u32 msg = readl(&iop->outbound_msgaddr0);
+
 		dprintk("received outbound msg %x\n", msg);
 		writel(IOPMU_OUTBOUND_INT_MSG0, &iop->outbound_intstatus);
 		hptiop_message_callback(hba, msg);
@@ -126,31 +131,115 @@ static int __iop_intr(struct hptiop_hba *hba)
 	}
 
 	if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) {
-		hptiop_drain_outbound_queue(hba);
+		hptiop_drain_outbound_queue_itl(hba);
+		ret = 1;
+	}
+
+	return ret;
+}
+
+static u64 mv_outbound_read(struct hpt_iopmu_mv __iomem *mu)
+{
+	u32 outbound_tail = readl(&mu->outbound_tail);
+	u32 outbound_head = readl(&mu->outbound_head);
+
+	if (outbound_tail != outbound_head) {
+		u64 p;
+
+		memcpy_fromio(&p, &mu->outbound_q[mu->outbound_tail], 8);
+		outbound_tail++;
+
+		if (outbound_tail == MVIOP_QUEUE_LEN)
+			outbound_tail = 0;
+		writel(outbound_tail, &mu->outbound_tail);
+		return p;
+	} else
+		return 0;
+}
+
+static void mv_inbound_write(u64 p, struct hptiop_hba *hba)
+{
+	u32 inbound_head = readl(&hba->u.mv.mu->inbound_head);
+	u32 head = inbound_head + 1;
+
+	if (head == MVIOP_QUEUE_LEN)
+		head = 0;
+
+	memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8);
+	writel(head, &hba->u.mv.mu->inbound_head);
+	writel(MVIOP_MU_INBOUND_INT_POSTQUEUE,
+			&hba->u.mv.regs->inbound_doorbell);
+}
+
+static void hptiop_request_callback_mv(struct hptiop_hba *hba, u64 tag)
+{
+	u32 req_type = (tag >> 5) & 0x7;
+	struct hpt_iop_request_scsi_command *req;
+
+	dprintk("hptiop_request_callback_mv: tag=%llx\n", tag);
+
+	BUG_ON((tag & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) == 0);
+
+	switch (req_type) {
+	case IOP_REQUEST_TYPE_GET_CONFIG:
+	case IOP_REQUEST_TYPE_SET_CONFIG:
+		hba->msg_done = 1;
+		break;
+
+	case IOP_REQUEST_TYPE_SCSI_COMMAND:
+		req = hba->reqs[tag >> 8].req_virt;
+		if (likely(tag & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT))
+			req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
+
+		hptiop_finish_scsi_req(hba, tag>>8, req);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static int iop_intr_mv(struct hptiop_hba *hba)
+{
+	u32 status;
+	int ret = 0;
+
+	status = readl(&hba->u.mv.regs->outbound_doorbell);
+	writel(~status, &hba->u.mv.regs->outbound_doorbell);
+
+	if (status & MVIOP_MU_OUTBOUND_INT_MSG) {
+		u32 msg;
+		msg = readl(&hba->u.mv.mu->outbound_msg);
+		dprintk("received outbound msg %x\n", msg);
+		hptiop_message_callback(hba, msg);
+		ret = 1;
+	}
+
+	if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) {
+		u64 tag;
+
+		while ((tag = mv_outbound_read(hba->u.mv.mu)))
+			hptiop_request_callback_mv(hba, tag);
 		ret = 1;
 	}
 
 	return ret;
 }
 
-static int iop_send_sync_request(struct hptiop_hba *hba,
+static int iop_send_sync_request_itl(struct hptiop_hba *hba,
 					void __iomem *_req, u32 millisec)
 {
 	struct hpt_iop_request_header __iomem *req = _req;
 	u32 i;
 
-	writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST,
-			&req->flags);
-
+	writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST, &req->flags);
 	writel(0, &req->context);
-
-	writel((unsigned long)req - (unsigned long)hba->iop,
-			&hba->iop->inbound_queue);
-
-	hptiop_pci_posting_flush(hba->iop);
+	writel((unsigned long)req - (unsigned long)hba->u.itl.iop,
+			&hba->u.itl.iop->inbound_queue);
+	readl(&hba->u.itl.iop->outbound_intstatus);
 
 	for (i = 0; i < millisec; i++) {
-		__iop_intr(hba);
+		iop_intr_itl(hba);
 		if (readl(&req->context))
 			return 0;
 		msleep(1);
@@ -159,19 +248,49 @@ static int iop_send_sync_request(struct hptiop_hba *hba,
 	return -1;
 }
 
-static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
+static int iop_send_sync_request_mv(struct hptiop_hba *hba,
+					u32 size_bits, u32 millisec)
 {
+	struct hpt_iop_request_header *reqhdr = hba->u.mv.internal_req;
 	u32 i;
 
 	hba->msg_done = 0;
+	reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST);
+	mv_inbound_write(hba->u.mv.internal_req_phy |
+			MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bits, hba);
+
+	for (i = 0; i < millisec; i++) {
+		iop_intr_mv(hba);
+		if (hba->msg_done)
+			return 0;
+		msleep(1);
+	}
+	return -1;
+}
+
+static void hptiop_post_msg_itl(struct hptiop_hba *hba, u32 msg)
+{
+	writel(msg, &hba->u.itl.iop->inbound_msgaddr0);
+	readl(&hba->u.itl.iop->outbound_intstatus);
+}
+
+static void hptiop_post_msg_mv(struct hptiop_hba *hba, u32 msg)
+{
+	writel(msg, &hba->u.mv.mu->inbound_msg);
+	writel(MVIOP_MU_INBOUND_INT_MSG, &hba->u.mv.regs->inbound_doorbell);
+	readl(&hba->u.mv.regs->inbound_doorbell);
+}
 
-	writel(msg, &hba->iop->inbound_msgaddr0);
+static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
+{
+	u32 i;
 
-	hptiop_pci_posting_flush(hba->iop);
+	hba->msg_done = 0;
+	hba->ops->post_msg(hba, msg);
 
 	for (i = 0; i < millisec; i++) {
 		spin_lock_irq(hba->host->host_lock);
-		__iop_intr(hba);
+		hba->ops->iop_intr(hba);
 		spin_unlock_irq(hba->host->host_lock);
 		if (hba->msg_done)
 			break;
@@ -181,46 +300,67 @@ static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec)
 	return hba->msg_done? 0 : -1;
 }
 
-static int iop_get_config(struct hptiop_hba *hba,
+static int iop_get_config_itl(struct hptiop_hba *hba,
 				struct hpt_iop_request_get_config *config)
 {
 	u32 req32;
 	struct hpt_iop_request_get_config __iomem *req;
 
-	req32 = readl(&hba->iop->inbound_queue);
+	req32 = readl(&hba->u.itl.iop->inbound_queue);
 	if (req32 == IOPMU_QUEUE_EMPTY)
 		return -1;
 
 	req = (struct hpt_iop_request_get_config __iomem *)
-			((unsigned long)hba->iop + req32);
+			((unsigned long)hba->u.itl.iop + req32);
 
 	writel(0, &req->header.flags);
 	writel(IOP_REQUEST_TYPE_GET_CONFIG, &req->header.type);
 	writel(sizeof(struct hpt_iop_request_get_config), &req->header.size);
 	writel(IOP_RESULT_PENDING, &req->header.result);
 
-	if (iop_send_sync_request(hba, req, 20000)) {
+	if (iop_send_sync_request_itl(hba, req, 20000)) {
 		dprintk("Get config send cmd failed\n");
 		return -1;
 	}
 
 	memcpy_fromio(config, req, sizeof(*config));
-	writel(req32, &hba->iop->outbound_queue);
+	writel(req32, &hba->u.itl.iop->outbound_queue);
+	return 0;
+}
+
+static int iop_get_config_mv(struct hptiop_hba *hba,
+				struct hpt_iop_request_get_config *config)
+{
+	struct hpt_iop_request_get_config *req = hba->u.mv.internal_req;
+
+	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
+	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG);
+	req->header.size =
+		cpu_to_le32(sizeof(struct hpt_iop_request_get_config));
+	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
+	req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_GET_CONFIG<<5);
+
+	if (iop_send_sync_request_mv(hba, 0, 20000)) {
+		dprintk("Get config send cmd failed\n");
+		return -1;
+	}
+
+	memcpy(config, req, sizeof(struct hpt_iop_request_get_config));
 	return 0;
 }
 
-static int iop_set_config(struct hptiop_hba *hba,
+static int iop_set_config_itl(struct hptiop_hba *hba,
 				struct hpt_iop_request_set_config *config)
 {
 	u32 req32;
 	struct hpt_iop_request_set_config __iomem *req;
 
-	req32 = readl(&hba->iop->inbound_queue);
+	req32 = readl(&hba->u.itl.iop->inbound_queue);
 	if (req32 == IOPMU_QUEUE_EMPTY)
 		return -1;
 
 	req = (struct hpt_iop_request_set_config __iomem *)
-			((unsigned long)hba->iop + req32);
+			((unsigned long)hba->u.itl.iop + req32);
 
 	memcpy_toio((u8 __iomem *)req + sizeof(struct hpt_iop_request_header),
 		(u8 *)config + sizeof(struct hpt_iop_request_header),
@@ -232,22 +372,52 @@ static int iop_set_config(struct hptiop_hba *hba,
 	writel(sizeof(struct hpt_iop_request_set_config), &req->header.size);
 	writel(IOP_RESULT_PENDING, &req->header.result);
 
-	if (iop_send_sync_request(hba, req, 20000)) {
+	if (iop_send_sync_request_itl(hba, req, 20000)) {
 		dprintk("Set config send cmd failed\n");
 		return -1;
 	}
 
-	writel(req32, &hba->iop->outbound_queue);
+	writel(req32, &hba->u.itl.iop->outbound_queue);
 	return 0;
 }
 
-static int hptiop_initialize_iop(struct hptiop_hba *hba)
+static int iop_set_config_mv(struct hptiop_hba *hba,
+				struct hpt_iop_request_set_config *config)
 {
-	struct hpt_iopmu __iomem *iop = hba->iop;
+	struct hpt_iop_request_set_config *req = hba->u.mv.internal_req;
 
-	/* enable interrupts */
+	memcpy(req, config, sizeof(struct hpt_iop_request_set_config));
+	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
+	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG);
+	req->header.size =
+		cpu_to_le32(sizeof(struct hpt_iop_request_set_config));
+	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
+	req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_SET_CONFIG<<5);
+
+	if (iop_send_sync_request_mv(hba, 0, 20000)) {
+		dprintk("Set config send cmd failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void hptiop_enable_intr_itl(struct hptiop_hba *hba)
+{
 	writel(~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0),
-			&iop->outbound_intmask);
+		&hba->u.itl.iop->outbound_intmask);
+}
+
+static void hptiop_enable_intr_mv(struct hptiop_hba *hba)
+{
+	writel(MVIOP_MU_OUTBOUND_INT_POSTQUEUE | MVIOP_MU_OUTBOUND_INT_MSG,
+		&hba->u.mv.regs->outbound_intmask);
+}
+
+static int hptiop_initialize_iop(struct hptiop_hba *hba)
+{
+	/* enable interrupts */
+	hba->ops->enable_intr(hba);
 
 	hba->initialized = 1;
 
@@ -261,37 +431,74 @@ static int hptiop_initialize_iop(struct hptiop_hba *hba)
 	return 0;
 }
 
-static int hptiop_map_pci_bar(struct hptiop_hba *hba)
+static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
 {
 	u32 mem_base_phy, length;
 	void __iomem *mem_base_virt;
+
 	struct pci_dev *pcidev = hba->pcidev;
 
-	if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
+
+	if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) {
 		printk(KERN_ERR "scsi%d: pci resource invalid\n",
 				hba->host->host_no);
-		return -1;
+		return 0;
 	}
 
-	mem_base_phy = pci_resource_start(pcidev, 0);
-	length = pci_resource_len(pcidev, 0);
+	mem_base_phy = pci_resource_start(pcidev, index);
+	length = pci_resource_len(pcidev, index);
 	mem_base_virt = ioremap(mem_base_phy, length);
 
 	if (!mem_base_virt) {
 		printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n",
 				hba->host->host_no);
+		return 0;
+	}
+	return mem_base_virt;
+}
+
+static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba)
+{
+	hba->u.itl.iop = hptiop_map_pci_bar(hba, 0);
+	if (hba->u.itl.iop)
+		return 0;
+	else
+		return -1;
+}
+
+static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)
+{
+	iounmap(hba->u.itl.iop);
+}
+
+static int hptiop_map_pci_bar_mv(struct hptiop_hba *hba)
+{
+	hba->u.mv.regs = hptiop_map_pci_bar(hba, 0);
+	if (hba->u.mv.regs == 0)
+		return -1;
+
+	hba->u.mv.mu = hptiop_map_pci_bar(hba, 2);
+	if (hba->u.mv.mu == 0) {
+		iounmap(hba->u.mv.regs);
 		return -1;
 	}
 
-	hba->iop = mem_base_virt;
-	dprintk("hptiop_map_pci_bar: iop=%p\n", hba->iop);
 	return 0;
 }
 
+static void hptiop_unmap_pci_bar_mv(struct hptiop_hba *hba)
+{
+	iounmap(hba->u.mv.regs);
+	iounmap(hba->u.mv.mu);
+}
+
 static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
 {
 	dprintk("iop message 0x%x\n", msg);
 
+	if (msg == IOPMU_INBOUND_MSG0_NOP)
+		hba->msg_done = 1;
+
 	if (!hba->initialized)
 		return;
 
@@ -303,7 +510,7 @@ static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg)
 		hba->msg_done = 1;
 }
 
-static inline struct hptiop_request *get_req(struct hptiop_hba *hba)
+static struct hptiop_request *get_req(struct hptiop_hba *hba)
 {
 	struct hptiop_request *ret;
 
@@ -316,30 +523,19 @@ static inline struct hptiop_request *get_req(struct hptiop_hba *hba)
 	return ret;
 }
 
-static inline void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
+static void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
 {
 	dprintk("free_req(%d, %p)\n", req->index, req);
 	req->next = hba->req_list;
 	hba->req_list = req;
 }
 
-static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
+static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
+				struct hpt_iop_request_scsi_command *req)
 {
-	struct hpt_iop_request_scsi_command *req;
 	struct scsi_cmnd *scp;
-	u32 tag;
-
-	if (hba->iopintf_v2) {
-		tag = _tag & ~ IOPMU_QUEUE_REQUEST_RESULT_BIT;
-		req = hba->reqs[tag].req_virt;
-		if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
-			req->header.result = IOP_RESULT_SUCCESS;
-	} else {
-		tag = _tag;
-		req = hba->reqs[tag].req_virt;
-	}
 
-	dprintk("hptiop_host_request_callback: req=%p, type=%d, "
+	dprintk("hptiop_finish_scsi_req: req=%p, type=%d, "
 			"result=%d, context=0x%x tag=%d\n",
 			req, req->header.type, req->header.result,
 			req->header.context, tag);
@@ -354,6 +550,8 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
 
 	switch (le32_to_cpu(req->header.result)) {
 	case IOP_RESULT_SUCCESS:
+		scsi_set_resid(scp,
+			scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
 		scp->result = (DID_OK<<16);
 		break;
 	case IOP_RESULT_BAD_TARGET:
@@ -371,12 +569,12 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
 	case IOP_RESULT_INVALID_REQUEST:
 		scp->result = (DID_ABORT<<16);
 		break;
-	case IOP_RESULT_MODE_SENSE_CHECK_CONDITION:
+	case IOP_RESULT_CHECK_CONDITION:
+		scsi_set_resid(scp,
+			scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length));
 		scp->result = SAM_STAT_CHECK_CONDITION;
-		memset(&scp->sense_buffer,
-				0, sizeof(scp->sense_buffer));
-		memcpy(&scp->sense_buffer, &req->sg_list,
-				min(sizeof(scp->sense_buffer),
+		memcpy(scp->sense_buffer, &req->sg_list,
+				min_t(size_t, SCSI_SENSE_BUFFERSIZE,
 					le32_to_cpu(req->dataxfer_length)));
 		break;
 
@@ -391,15 +589,33 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
 	free_req(hba, &hba->reqs[tag]);
 }
 
-void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag)
+static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 _tag)
+{
+	struct hpt_iop_request_scsi_command *req;
+	u32 tag;
+
+	if (hba->iopintf_v2) {
+		tag = _tag & ~IOPMU_QUEUE_REQUEST_RESULT_BIT;
+		req = hba->reqs[tag].req_virt;
+		if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
+			req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS);
+	} else {
+		tag = _tag;
+		req = hba->reqs[tag].req_virt;
+	}
+
+	hptiop_finish_scsi_req(hba, tag, req);
+}
+
+void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag)
 {
 	struct hpt_iop_request_header __iomem *req;
 	struct hpt_iop_request_ioctl_command __iomem *p;
 	struct hpt_ioctl_k *arg;
 
 	req = (struct hpt_iop_request_header __iomem *)
-			((unsigned long)hba->iop + tag);
-	dprintk("hptiop_iop_request_callback: req=%p, type=%d, "
+			((unsigned long)hba->u.itl.iop + tag);
+	dprintk("hptiop_iop_request_callback_itl: req=%p, type=%d, "
 			"result=%d, context=0x%x tag=%d\n",
 			req, readl(&req->type), readl(&req->result),
 			readl(&req->context), tag);
@@ -427,7 +643,7 @@ void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag)
 		arg->result = HPT_IOCTL_RESULT_FAILED;
 
 	arg->done(arg);
-	writel(tag, &hba->iop->outbound_queue);
+	writel(tag, &hba->u.itl.iop->outbound_queue);
 }
 
 static irqreturn_t hptiop_intr(int irq, void *dev_id)
@@ -437,7 +653,7 @@ static irqreturn_t hptiop_intr(int irq, void *dev_id)
 	unsigned long flags;
 
 	spin_lock_irqsave(hba->host->host_lock, flags);
-	handled = __iop_intr(hba);
+	handled = hba->ops->iop_intr(hba);
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
 
 	return handled;
@@ -469,6 +685,57 @@ static int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg)
 	return HPT_SCP(scp)->sgcnt;
 }
 
+static void hptiop_post_req_itl(struct hptiop_hba *hba,
+					struct hptiop_request *_req)
+{
+	struct hpt_iop_request_header *reqhdr = _req->req_virt;
+
+	reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
+							(u32)_req->index);
+	reqhdr->context_hi32 = 0;
+
+	if (hba->iopintf_v2) {
+		u32 size, size_bits;
+
+		size = le32_to_cpu(reqhdr->size);
+		if (size < 256)
+			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
+		else if (size < 512)
+			size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
+		else
+			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
+						IOPMU_QUEUE_ADDR_HOST_BIT;
+		writel(_req->req_shifted_phy | size_bits,
+			&hba->u.itl.iop->inbound_queue);
+	} else
+		writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
+					&hba->u.itl.iop->inbound_queue);
+}
+
+static void hptiop_post_req_mv(struct hptiop_hba *hba,
+					struct hptiop_request *_req)
+{
+	struct hpt_iop_request_header *reqhdr = _req->req_virt;
+	u32 size, size_bit;
+
+	reqhdr->context = cpu_to_le32(_req->index<<8 |
+					IOP_REQUEST_TYPE_SCSI_COMMAND<<5);
+	reqhdr->context_hi32 = 0;
+	size = le32_to_cpu(reqhdr->size);
+
+	if (size <= 256)
+		size_bit = 0;
+	else if (size <= 256*2)
+		size_bit = 1;
+	else if (size <= 256*3)
+		size_bit = 2;
+	else
+		size_bit = 3;
+
+	mv_inbound_write((_req->req_shifted_phy << 5) |
+		MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba);
+}
+
 static int hptiop_queuecommand(struct scsi_cmnd *scp,
 				void (*done)(struct scsi_cmnd *))
 {
@@ -518,9 +785,6 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
 	req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
 	req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND);
 	req->header.result = cpu_to_le32(IOP_RESULT_PENDING);
-	req->header.context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
-							(u32)_req->index);
-	req->header.context_hi32 = 0;
 	req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp));
 	req->channel = scp->device->channel;
 	req->target = scp->device->id;
@@ -531,21 +795,7 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
 				 + sg_count * sizeof(struct hpt_iopsg));
 
 	memcpy(req->cdb, scp->cmnd, sizeof(req->cdb));
-
-	if (hba->iopintf_v2) {
-		u32 size_bits;
-		if (req->header.size < 256)
-			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
-		else if (req->header.size < 512)
-			size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
-		else
-			size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
-						IOPMU_QUEUE_ADDR_HOST_BIT;
-		writel(_req->req_shifted_phy | size_bits, &hba->iop->inbound_queue);
-	} else
-		writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
-					&hba->iop->inbound_queue);
-
+	hba->ops->post_req(hba, _req);
 	return 0;
 
 cmd_done:
@@ -563,9 +813,7 @@ static int hptiop_reset_hba(struct hptiop_hba *hba)
 {
 	if (atomic_xchg(&hba->resetting, 1) == 0) {
 		atomic_inc(&hba->reset_count);
-		writel(IOPMU_INBOUND_MSG0_RESET,
-				&hba->iop->inbound_msgaddr0);
-		hptiop_pci_posting_flush(hba->iop);
+		hba->ops->post_msg(hba, IOPMU_INBOUND_MSG0_RESET);
 	}
 
 	wait_event_timeout(hba->reset_wq,
@@ -601,8 +849,10 @@ static int hptiop_reset(struct scsi_cmnd *scp)
 static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
 						int queue_depth)
 {
-	if(queue_depth > 256)
-		queue_depth = 256;
+	struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata;
+
+	if (queue_depth > hba->max_requests)
+		queue_depth = hba->max_requests;
 	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
 	return queue_depth;
 }
@@ -656,13 +906,32 @@ static struct scsi_host_template driver_template = {
 	.unchecked_isa_dma          = 0,
 	.emulated                   = 0,
 	.use_clustering             = ENABLE_CLUSTERING,
-	.use_sg_chaining            = ENABLE_SG_CHAINING,
 	.proc_name                  = driver_name,
 	.shost_attrs                = hptiop_attrs,
 	.this_id                    = -1,
 	.change_queue_depth         = hptiop_adjust_disk_queue_depth,
 };
 
+static int hptiop_internal_memalloc_mv(struct hptiop_hba *hba)
+{
+	hba->u.mv.internal_req = dma_alloc_coherent(&hba->pcidev->dev,
+			0x800, &hba->u.mv.internal_req_phy, GFP_KERNEL);
+	if (hba->u.mv.internal_req)
+		return 0;
+	else
+		return -1;
+}
+
+static int hptiop_internal_memfree_mv(struct hptiop_hba *hba)
+{
+	if (hba->u.mv.internal_req) {
+		dma_free_coherent(&hba->pcidev->dev, 0x800,
+			hba->u.mv.internal_req, hba->u.mv.internal_req_phy);
+		return 0;
+	} else
+		return -1;
+}
+
 static int __devinit hptiop_probe(struct pci_dev *pcidev,
 					const struct pci_device_id *id)
 {
@@ -708,6 +977,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
 
 	hba = (struct hptiop_hba *)host->hostdata;
 
+	hba->ops = (struct hptiop_adapter_ops *)id->driver_data;
 	hba->pcidev = pcidev;
 	hba->host = host;
 	hba->initialized = 0;
@@ -725,16 +995,24 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
 	host->n_io_port = 0;
 	host->irq = pcidev->irq;
 
-	if (hptiop_map_pci_bar(hba))
+	if (hba->ops->map_pci_bar(hba))
 		goto free_scsi_host;
 
-	if (iop_wait_ready(hba->iop, 20000)) {
+	if (hba->ops->iop_wait_ready(hba, 20000)) {
 		printk(KERN_ERR "scsi%d: firmware not ready\n",
 				hba->host->host_no);
 		goto unmap_pci_bar;
 	}
 
-	if (iop_get_config(hba, &iop_config)) {
+	if (hba->ops->internal_memalloc) {
+		if (hba->ops->internal_memalloc(hba)) {
+			printk(KERN_ERR "scsi%d: internal_memalloc failed\n",
+				hba->host->host_no);
+			goto unmap_pci_bar;
+		}
+	}
+
+	if (hba->ops->get_config(hba, &iop_config)) {
 		printk(KERN_ERR "scsi%d: get config failed\n",
 				hba->host->host_no);
 		goto unmap_pci_bar;
@@ -770,7 +1048,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
 	set_config.vbus_id = cpu_to_le16(host->host_no);
 	set_config.max_host_request_size = cpu_to_le16(req_size);
 
-	if (iop_set_config(hba, &set_config)) {
+	if (hba->ops->set_config(hba, &set_config)) {
 		printk(KERN_ERR "scsi%d: set config failed\n",
 				hba->host->host_no);
 		goto unmap_pci_bar;
@@ -839,21 +1117,24 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
 
 free_request_mem:
 	dma_free_coherent(&hba->pcidev->dev,
-			hba->req_size*hba->max_requests + 0x20,
+			hba->req_size * hba->max_requests + 0x20,
 			hba->dma_coherent, hba->dma_coherent_handle);
 
 free_request_irq:
 	free_irq(hba->pcidev->irq, hba);
 
 unmap_pci_bar:
-	iounmap(hba->iop);
+	if (hba->ops->internal_memfree)
+		hba->ops->internal_memfree(hba);
 
-free_pci_regions:
-	pci_release_regions(pcidev) ;
+	hba->ops->unmap_pci_bar(hba);
 
 free_scsi_host:
 	scsi_host_put(host);
 
+free_pci_regions:
+	pci_release_regions(pcidev);
+
 disable_pci_device:
 	pci_disable_device(pcidev);
 
@@ -865,8 +1146,6 @@ static void hptiop_shutdown(struct pci_dev *pcidev)
 {
 	struct Scsi_Host *host = pci_get_drvdata(pcidev);
 	struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
-	struct hpt_iopmu __iomem *iop = hba->iop;
-	u32    int_mask;
 
 	dprintk("hptiop_shutdown(%p)\n", hba);
 
@@ -876,11 +1155,24 @@ static void hptiop_shutdown(struct pci_dev *pcidev)
 					hba->host->host_no);
 
 	/* disable all outbound interrupts */
-	int_mask = readl(&iop->outbound_intmask);
+	hba->ops->disable_intr(hba);
+}
+
+static void hptiop_disable_intr_itl(struct hptiop_hba *hba)
+{
+	u32 int_mask;
+
+	int_mask = readl(&hba->u.itl.iop->outbound_intmask);
 	writel(int_mask |
 		IOPMU_OUTBOUND_INT_MSG0 | IOPMU_OUTBOUND_INT_POSTQUEUE,
-		&iop->outbound_intmask);
-	hptiop_pci_posting_flush(iop);
+		&hba->u.itl.iop->outbound_intmask);
+	readl(&hba->u.itl.iop->outbound_intmask);
+}
+
+static void hptiop_disable_intr_mv(struct hptiop_hba *hba)
+{
+	writel(0, &hba->u.mv.regs->outbound_intmask);
+	readl(&hba->u.mv.regs->outbound_intmask);
 }
 
 static void hptiop_remove(struct pci_dev *pcidev)
@@ -901,7 +1193,10 @@ static void hptiop_remove(struct pci_dev *pcidev)
 			hba->dma_coherent,
 			hba->dma_coherent_handle);
 
-	iounmap(hba->iop);
+	if (hba->ops->internal_memfree)
+		hba->ops->internal_memfree(hba);
+
+	hba->ops->unmap_pci_bar(hba);
 
 	pci_release_regions(hba->pcidev);
 	pci_set_drvdata(hba->pcidev, NULL);
@@ -910,11 +1205,50 @@ static void hptiop_remove(struct pci_dev *pcidev)
 	scsi_host_put(host);
 }
 
+static struct hptiop_adapter_ops hptiop_itl_ops = {
+	.iop_wait_ready    = iop_wait_ready_itl,
+	.internal_memalloc = 0,
+	.internal_memfree  = 0,
+	.map_pci_bar       = hptiop_map_pci_bar_itl,
+	.unmap_pci_bar     = hptiop_unmap_pci_bar_itl,
+	.enable_intr       = hptiop_enable_intr_itl,
+	.disable_intr      = hptiop_disable_intr_itl,
+	.get_config        = iop_get_config_itl,
+	.set_config        = iop_set_config_itl,
+	.iop_intr          = iop_intr_itl,
+	.post_msg          = hptiop_post_msg_itl,
+	.post_req          = hptiop_post_req_itl,
+};
+
+static struct hptiop_adapter_ops hptiop_mv_ops = {
+	.iop_wait_ready    = iop_wait_ready_mv,
+	.internal_memalloc = hptiop_internal_memalloc_mv,
+	.internal_memfree  = hptiop_internal_memfree_mv,
+	.map_pci_bar       = hptiop_map_pci_bar_mv,
+	.unmap_pci_bar     = hptiop_unmap_pci_bar_mv,
+	.enable_intr       = hptiop_enable_intr_mv,
+	.disable_intr      = hptiop_disable_intr_mv,
+	.get_config        = iop_get_config_mv,
+	.set_config        = iop_set_config_mv,
+	.iop_intr          = iop_intr_mv,
+	.post_msg          = hptiop_post_msg_mv,
+	.post_req          = hptiop_post_req_mv,
+};
+
 static struct pci_device_id hptiop_id_table[] = {
-	{ PCI_VDEVICE(TTI, 0x3220) },
-	{ PCI_VDEVICE(TTI, 0x3320) },
-	{ PCI_VDEVICE(TTI, 0x3520) },
-	{ PCI_VDEVICE(TTI, 0x4320) },
+	{ PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops },
+	{ PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops },
+	{ PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
+	{ PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
+	{ PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops },
+	{ PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops },
+	{ PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops },
+	{ PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops },
+	{ PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
+	{ PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
+	{ PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops },
+	{ PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops },
+	{ PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
 	{},
 };
 
diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h
index 2a5e46e001cb..a0289f219752 100644
--- a/drivers/scsi/hptiop.h
+++ b/drivers/scsi/hptiop.h
@@ -1,5 +1,5 @@
 /*
- * HighPoint RR3xxx controller driver for Linux
+ * HighPoint RR3xxx/4xxx controller driver for Linux
  * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,7 @@
 #ifndef _HPTIOP_H_
 #define _HPTIOP_H_
 
-struct hpt_iopmu
-{
+struct hpt_iopmu_itl {
 	__le32 resrved0[4];
 	__le32 inbound_msgaddr0;
 	__le32 inbound_msgaddr1;
@@ -54,6 +53,40 @@ struct hpt_iopmu
 #define IOPMU_INBOUND_INT_ERROR      8
 #define IOPMU_INBOUND_INT_POSTQUEUE  0x10
 
+#define MVIOP_QUEUE_LEN  512
+
+struct hpt_iopmu_mv {
+	__le32 inbound_head;
+	__le32 inbound_tail;
+	__le32 outbound_head;
+	__le32 outbound_tail;
+	__le32 inbound_msg;
+	__le32 outbound_msg;
+	__le32 reserve[10];
+	__le64 inbound_q[MVIOP_QUEUE_LEN];
+	__le64 outbound_q[MVIOP_QUEUE_LEN];
+};
+
+struct hpt_iopmv_regs {
+	__le32 reserved[0x20400 / 4];
+	__le32 inbound_doorbell;
+	__le32 inbound_intmask;
+	__le32 outbound_doorbell;
+	__le32 outbound_intmask;
+};
+
+#define MVIOP_MU_QUEUE_ADDR_HOST_MASK   (~(0x1full))
+#define MVIOP_MU_QUEUE_ADDR_HOST_BIT    4
+
+#define MVIOP_MU_QUEUE_ADDR_IOP_HIGH32  0xffffffff
+#define MVIOP_MU_QUEUE_REQUEST_RESULT_BIT   1
+#define MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT 2
+
+#define MVIOP_MU_INBOUND_INT_MSG        1
+#define MVIOP_MU_INBOUND_INT_POSTQUEUE  2
+#define MVIOP_MU_OUTBOUND_INT_MSG       1
+#define MVIOP_MU_OUTBOUND_INT_POSTQUEUE 2
+
 enum hpt_iopmu_message {
 	/* host-to-iop messages */
 	IOPMU_INBOUND_MSG0_NOP = 0,
@@ -72,8 +105,7 @@ enum hpt_iopmu_message {
 	IOPMU_OUTBOUND_MSG0_REVALIDATE_DEVICE_MAX = 0x3ff,
 };
 
-struct hpt_iop_request_header
-{
+struct hpt_iop_request_header {
 	__le32 size;
 	__le32 type;
 	__le32 flags;
@@ -104,11 +136,10 @@ enum hpt_iop_result_type {
 	IOP_RESULT_RESET,
 	IOP_RESULT_INVALID_REQUEST,
 	IOP_RESULT_BAD_TARGET,
-	IOP_RESULT_MODE_SENSE_CHECK_CONDITION,
+	IOP_RESULT_CHECK_CONDITION,
 };
 
-struct hpt_iop_request_get_config
-{
+struct hpt_iop_request_get_config {
 	struct hpt_iop_request_header header;
 	__le32 interface_version;
 	__le32 firmware_version;
@@ -121,8 +152,7 @@ struct hpt_iop_request_get_config
 	__le32 sdram_size;
 };
 
-struct hpt_iop_request_set_config
-{
+struct hpt_iop_request_set_config {
 	struct hpt_iop_request_header header;
 	__le32 iop_id;
 	__le16 vbus_id;
@@ -130,15 +160,13 @@ struct hpt_iop_request_set_config
 	__le32 reserve[6];
 };
 
-struct hpt_iopsg
-{
+struct hpt_iopsg {
 	__le32 size;
 	__le32 eot; /* non-zero: end of table */
 	__le64 pci_address;
 };
 
-struct hpt_iop_request_block_command
-{
+struct hpt_iop_request_block_command {
 	struct hpt_iop_request_header header;
 	u8     channel;
 	u8     target;
@@ -156,8 +184,7 @@ struct hpt_iop_request_block_command
 #define IOP_BLOCK_COMMAND_FLUSH    4
 #define IOP_BLOCK_COMMAND_SHUTDOWN 5
 
-struct hpt_iop_request_scsi_command
-{
+struct hpt_iop_request_scsi_command {
 	struct hpt_iop_request_header header;
 	u8     channel;
 	u8     target;
@@ -168,8 +195,7 @@ struct hpt_iop_request_scsi_command
 	struct hpt_iopsg sg_list[1];
 };
 
-struct hpt_iop_request_ioctl_command
-{
+struct hpt_iop_request_ioctl_command {
 	struct hpt_iop_request_header header;
 	__le32 ioctl_code;
 	__le32 inbuf_size;
@@ -182,11 +208,11 @@ struct hpt_iop_request_ioctl_command
 #define HPTIOP_MAX_REQUESTS  256u
 
 struct hptiop_request {
-	struct hptiop_request * next;
-	void *                  req_virt;
-	u32                     req_shifted_phy;
-	struct scsi_cmnd *      scp;
-	int                     index;
+	struct hptiop_request *next;
+	void                  *req_virt;
+	u32                   req_shifted_phy;
+	struct scsi_cmnd      *scp;
+	int                   index;
 };
 
 struct hpt_scsi_pointer {
@@ -198,9 +224,21 @@ struct hpt_scsi_pointer {
 #define HPT_SCP(scp) ((struct hpt_scsi_pointer *)&(scp)->SCp)
 
 struct hptiop_hba {
-	struct hpt_iopmu __iomem * iop;
-	struct Scsi_Host * host;
-	struct pci_dev * pcidev;
+	struct hptiop_adapter_ops *ops;
+	union {
+		struct {
+			struct hpt_iopmu_itl __iomem *iop;
+		} itl;
+		struct {
+			struct hpt_iopmv_regs *regs;
+			struct hpt_iopmu_mv __iomem *mu;
+			void *internal_req;
+			dma_addr_t internal_req_phy;
+		} mv;
+	} u;
+
+	struct Scsi_Host *host;
+	struct pci_dev *pcidev;
 
 	/* IOP config info */
 	u32     interface_version;
@@ -213,15 +251,15 @@ struct hptiop_hba {
 
 	u32     req_size; /* host-allocated request buffer size */
 
-	int     iopintf_v2: 1;
-	int     initialized: 1;
-	int     msg_done: 1;
+	u32     iopintf_v2: 1;
+	u32     initialized: 1;
+	u32     msg_done: 1;
 
 	struct hptiop_request * req_list;
 	struct hptiop_request reqs[HPTIOP_MAX_REQUESTS];
 
 	/* used to free allocated dma area */
-	void *      dma_coherent;
+	void        *dma_coherent;
 	dma_addr_t  dma_coherent_handle;
 
 	atomic_t    reset_count;
@@ -231,19 +269,35 @@ struct hptiop_hba {
 	wait_queue_head_t ioctl_wq;
 };
 
-struct hpt_ioctl_k
-{
+struct hpt_ioctl_k {
 	struct hptiop_hba * hba;
 	u32    ioctl_code;
 	u32    inbuf_size;
 	u32    outbuf_size;
-	void * inbuf;
-	void * outbuf;
-	u32  * bytes_returned;
+	void   *inbuf;
+	void   *outbuf;
+	u32    *bytes_returned;
 	void (*done)(struct hpt_ioctl_k *);
 	int    result; /* HPT_IOCTL_RESULT_ */
 };
 
+struct hptiop_adapter_ops {
+	int  (*iop_wait_ready)(struct hptiop_hba *hba, u32 millisec);
+	int  (*internal_memalloc)(struct hptiop_hba *hba);
+	int  (*internal_memfree)(struct hptiop_hba *hba);
+	int  (*map_pci_bar)(struct hptiop_hba *hba);
+	void (*unmap_pci_bar)(struct hptiop_hba *hba);
+	void (*enable_intr)(struct hptiop_hba *hba);
+	void (*disable_intr)(struct hptiop_hba *hba);
+	int  (*get_config)(struct hptiop_hba *hba,
+				struct hpt_iop_request_get_config *config);
+	int  (*set_config)(struct hptiop_hba *hba,
+				struct hpt_iop_request_set_config *config);
+	int  (*iop_intr)(struct hptiop_hba *hba);
+	void (*post_msg)(struct hptiop_hba *hba, u32 msg);
+	void (*post_req)(struct hptiop_hba *hba, struct hptiop_request *_req);
+};
+
 #define HPT_IOCTL_RESULT_OK         0
 #define HPT_IOCTL_RESULT_FAILED     (-1)
 
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index db004a450732..4d15a62914e9 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -1501,7 +1501,6 @@ static struct scsi_host_template ibmmca_driver_template = {
           .sg_tablesize   = 16,
           .cmd_per_lun    = 1,
           .use_clustering = ENABLE_CLUSTERING,
-          .use_sg_chaining = ENABLE_SG_CHAINING,
 };
 
 static int ibmmca_probe(struct device *dev)
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 5f2396c03958..78d46a900bb5 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -629,6 +629,16 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
 		list_del(&evt_struct->list);
 		del_timer(&evt_struct->timer);
 
+		/* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY.
+		 * Firmware will send a CRQ with a transport event (0xFF) to
+		 * tell this client what has happened to the transport.  This
+		 * will be handled in ibmvscsi_handle_crq()
+		 */
+		if (rc == H_CLOSED) {
+			dev_warn(hostdata->dev, "send warning. "
+			         "Receive queue closed, will retry.\n");
+			goto send_busy;
+		}
 		dev_err(hostdata->dev, "send error %d\n", rc);
 		atomic_inc(&hostdata->request_limit);
 		goto send_error;
@@ -976,58 +986,74 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
 	int rsp_rc;
 	unsigned long flags;
 	u16 lun = lun_from_dev(cmd->device);
+	unsigned long wait_switch = 0;
 
 	/* First, find this command in our sent list so we can figure
 	 * out the correct tag
 	 */
 	spin_lock_irqsave(hostdata->host->host_lock, flags);
-	found_evt = NULL;
-	list_for_each_entry(tmp_evt, &hostdata->sent, list) {
-		if (tmp_evt->cmnd == cmd) {
-			found_evt = tmp_evt;
-			break;
+	wait_switch = jiffies + (init_timeout * HZ);
+	do {
+		found_evt = NULL;
+		list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+			if (tmp_evt->cmnd == cmd) {
+				found_evt = tmp_evt;
+				break;
+			}
 		}
-	}
 
-	if (!found_evt) {
-		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-		return SUCCESS;
-	}
+		if (!found_evt) {
+			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+			return SUCCESS;
+		}
 
-	evt = get_event_struct(&hostdata->pool);
-	if (evt == NULL) {
-		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-		sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n");
-		return FAILED;
-	}
+		evt = get_event_struct(&hostdata->pool);
+		if (evt == NULL) {
+			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+			sdev_printk(KERN_ERR, cmd->device,
+				"failed to allocate abort event\n");
+			return FAILED;
+		}
 	
-	init_event_struct(evt,
-			  sync_completion,
-			  VIOSRP_SRP_FORMAT,
-			  init_timeout);
+		init_event_struct(evt,
+				  sync_completion,
+				  VIOSRP_SRP_FORMAT,
+				  init_timeout);
 
-	tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
 	
-	/* Set up an abort SRP command */
-	memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
-	tsk_mgmt->opcode = SRP_TSK_MGMT;
-	tsk_mgmt->lun = ((u64) lun) << 48;
-	tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
-	tsk_mgmt->task_tag = (u64) found_evt;
-
-	sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n",
-		    tsk_mgmt->lun, tsk_mgmt->task_tag);
-
-	evt->sync_srp = &srp_rsp;
-	init_completion(&evt->comp);
-	rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+		/* Set up an abort SRP command */
+		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+		tsk_mgmt->opcode = SRP_TSK_MGMT;
+		tsk_mgmt->lun = ((u64) lun) << 48;
+		tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
+		tsk_mgmt->task_tag = (u64) found_evt;
+
+		evt->sync_srp = &srp_rsp;
+
+		init_completion(&evt->comp);
+		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+
+		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
+			break;
+
+		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+		msleep(10);
+		spin_lock_irqsave(hostdata->host->host_lock, flags);
+	} while (time_before(jiffies, wait_switch));
+
 	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
 	if (rsp_rc != 0) {
 		sdev_printk(KERN_ERR, cmd->device,
 			    "failed to send abort() event. rc=%d\n", rsp_rc);
 		return FAILED;
 	}
 
+	sdev_printk(KERN_INFO, cmd->device,
+                    "aborting command. lun 0x%lx, tag 0x%lx\n",
+		    (((u64) lun) << 48), (u64) found_evt);
+
 	wait_for_completion(&evt->comp);
 
 	/* make sure we got a good response */
@@ -1099,41 +1125,56 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
 	int rsp_rc;
 	unsigned long flags;
 	u16 lun = lun_from_dev(cmd->device);
+	unsigned long wait_switch = 0;
 
 	spin_lock_irqsave(hostdata->host->host_lock, flags);
-	evt = get_event_struct(&hostdata->pool);
-	if (evt == NULL) {
-		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
-		sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n");
-		return FAILED;
-	}
+	wait_switch = jiffies + (init_timeout * HZ);
+	do {
+		evt = get_event_struct(&hostdata->pool);
+		if (evt == NULL) {
+			spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+			sdev_printk(KERN_ERR, cmd->device,
+				"failed to allocate reset event\n");
+			return FAILED;
+		}
 	
-	init_event_struct(evt,
-			  sync_completion,
-			  VIOSRP_SRP_FORMAT,
-			  init_timeout);
+		init_event_struct(evt,
+				  sync_completion,
+				  VIOSRP_SRP_FORMAT,
+				  init_timeout);
 
-	tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+		tsk_mgmt = &evt->iu.srp.tsk_mgmt;
 
-	/* Set up a lun reset SRP command */
-	memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
-	tsk_mgmt->opcode = SRP_TSK_MGMT;
-	tsk_mgmt->lun = ((u64) lun) << 48;
-	tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
+		/* Set up a lun reset SRP command */
+		memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+		tsk_mgmt->opcode = SRP_TSK_MGMT;
+		tsk_mgmt->lun = ((u64) lun) << 48;
+		tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
 
-	sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
-		    tsk_mgmt->lun);
+		evt->sync_srp = &srp_rsp;
+
+		init_completion(&evt->comp);
+		rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
+
+		if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY)
+			break;
+
+		spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+		msleep(10);
+		spin_lock_irqsave(hostdata->host->host_lock, flags);
+	} while (time_before(jiffies, wait_switch));
 
-	evt->sync_srp = &srp_rsp;
-	init_completion(&evt->comp);
-	rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
 	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
 	if (rsp_rc != 0) {
 		sdev_printk(KERN_ERR, cmd->device,
 			    "failed to send reset event. rc=%d\n", rsp_rc);
 		return FAILED;
 	}
 
+	sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
+		    (((u64) lun) << 48));
+
 	wait_for_completion(&evt->comp);
 
 	/* make sure we got a good response */
@@ -1386,8 +1427,10 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
 	unsigned long lock_flags = 0;
 
 	spin_lock_irqsave(shost->host_lock, lock_flags);
-	if (sdev->type == TYPE_DISK)
+	if (sdev->type == TYPE_DISK) {
 		sdev->allow_restart = 1;
+		sdev->timeout = 60 * HZ;
+	}
 	scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
 	spin_unlock_irqrestore(shost->host_lock, lock_flags);
 	return 0;
@@ -1557,7 +1600,6 @@ static struct scsi_host_template driver_template = {
 	.this_id = -1,
 	.sg_tablesize = SG_ALL,
 	.use_clustering = ENABLE_CLUSTERING,
-	.use_sg_chaining = ENABLE_SG_CHAINING,
 	.shost_attrs = ibmvscsi_attrs,
 };
 
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index 82bcab688b44..d63f11e95abf 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -292,7 +292,7 @@ static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
 	dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
 		cmd->usg_sg);
 
-	if (sc->use_sg)
+	if (scsi_sg_count(sc))
 		err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
 
 	spin_lock_irqsave(&target->lock, flags);
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 9706de9d98d5..db8bc20539e1 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -395,14 +395,12 @@ static int idescsi_expiry(ide_drive_t *drive)
 static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-	idescsi_pc_t *pc=scsi->pc;
+	ide_hwif_t *hwif = drive->hwif;
+	idescsi_pc_t *pc = scsi->pc;
 	struct request *rq = pc->rq;
-	atapi_bcount_t bcount;
-	atapi_status_t status;
-	atapi_ireason_t ireason;
-	atapi_feature_t feature;
-
 	unsigned int temp;
+	u16 bcount;
+	u8 stat, ireason;
 
 #if IDESCSI_DEBUG_LOG
 	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
@@ -425,30 +423,29 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 		(void) HWIF(drive)->ide_dma_end(drive);
 	}
 
-	feature.all = 0;
 	/* Clear the interrupt */
-	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+	stat = drive->hwif->INB(IDE_STATUS_REG);
 
-	if (!status.b.drq) {
+	if ((stat & DRQ_STAT) == 0) {
 		/* No more interrupts */
 		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
 			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
 		local_irq_enable_in_hardirq();
-		if (status.b.check)
+		if (stat & ERR_STAT)
 			rq->errors++;
 		idescsi_end_request (drive, 1, 0);
 		return ide_stopped;
 	}
-	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);
-	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);
-	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
+	bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) |
+		  hwif->INB(IDE_BCOUNTL_REG);
+	ireason = hwif->INB(IDE_IREASON_REG);
 
-	if (ireason.b.cod) {
+	if (ireason & CD) {
 		printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
 		return ide_do_reset (drive);
 	}
-	if (ireason.b.io) {
-		temp = pc->actually_transferred + bcount.all;
+	if (ireason & IO) {
+		temp = pc->actually_transferred + bcount;
 		if (temp > pc->request_transfer) {
 			if (temp > pc->buffer_size) {
 				printk(KERN_ERR "ide-scsi: The scsi wants to "
@@ -461,11 +458,13 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 						idescsi_input_buffers(drive, pc, temp);
 					else
 						drive->hwif->atapi_input_bytes(drive, pc->current_position, temp);
-					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all);
+					printk(KERN_ERR "ide-scsi: transferred"
+							" %d of %d bytes\n",
+							temp, bcount);
 				}
 				pc->actually_transferred += temp;
 				pc->current_position += temp;
-				idescsi_discard_data(drive, bcount.all - temp);
+				idescsi_discard_data(drive, bcount - temp);
 				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
 				return ide_started;
 			}
@@ -474,22 +473,24 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
 #endif /* IDESCSI_DEBUG_LOG */
 		}
 	}
-	if (ireason.b.io) {
+	if (ireason & IO) {
 		clear_bit(PC_WRITING, &pc->flags);
 		if (pc->sg)
-			idescsi_input_buffers(drive, pc, bcount.all);
+			idescsi_input_buffers(drive, pc, bcount);
 		else
-			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
+			hwif->atapi_input_bytes(drive, pc->current_position,
+						bcount);
 	} else {
 		set_bit(PC_WRITING, &pc->flags);
 		if (pc->sg)
-			idescsi_output_buffers (drive, pc, bcount.all);
+			idescsi_output_buffers(drive, pc, bcount);
 		else
-			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
+			hwif->atapi_output_bytes(drive, pc->current_position,
+						 bcount);
 	}
 	/* Update the current position */
-	pc->actually_transferred += bcount.all;
-	pc->current_position += bcount.all;
+	pc->actually_transferred += bcount;
+	pc->current_position += bcount;
 
 	/* And set the interrupt handler again */
 	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
@@ -501,16 +502,16 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
 	ide_hwif_t *hwif = drive->hwif;
 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
 	idescsi_pc_t *pc = scsi->pc;
-	atapi_ireason_t ireason;
 	ide_startstop_t startstop;
+	u8 ireason;
 
 	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
 		printk(KERN_ERR "ide-scsi: Strange, packet command "
 			"initiated yet DRQ isn't asserted\n");
 		return startstop;
 	}
-	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
-	if (!ireason.b.cod || ireason.b.io) {
+	ireason = hwif->INB(IDE_IREASON_REG);
+	if ((ireason & CD) == 0 || (ireason & IO)) {
 		printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "
 				"issuing a packet command\n");
 		return ide_do_reset (drive);
@@ -573,30 +574,26 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
 {
 	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
 	ide_hwif_t *hwif = drive->hwif;
-	atapi_feature_t feature;
-	atapi_bcount_t bcount;
+	u16 bcount;
+	u8 dma = 0;
 
 	scsi->pc=pc;							/* Set the current packet command */
 	pc->actually_transferred=0;					/* We haven't transferred any data yet */
 	pc->current_position=pc->buffer;
-	bcount.all = min(pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
+	/* Request to transfer the entire buffer at once */
+	bcount = min(pc->request_transfer, 63 * 1024);
 
-	feature.all = 0;
 	if (drive->using_dma && !idescsi_map_sg(drive, pc)) {
 		hwif->sg_mapped = 1;
-		feature.b.dma = !hwif->dma_setup(drive);
+		dma = !hwif->dma_setup(drive);
 		hwif->sg_mapped = 0;
 	}
 
 	SELECT_DRIVE(drive);
-	if (IDE_CONTROL_REG)
-		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
 
-	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
-	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
-	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+	ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK, bcount, dma);
 
-	if (feature.b.dma)
+	if (dma)
 		set_bit(PC_DMA_OK, &pc->flags);
 
 	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
@@ -922,8 +919,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
 	}
 
 	/* kill current request */
-	blkdev_dequeue_request(req);
-	end_that_request_last(req, 0);
+	if (__blk_end_request(req, -EIO, 0))
+		BUG();
 	if (blk_sense_request(req))
 		kfree(scsi->pc->buffer);
 	kfree(scsi->pc);
@@ -932,8 +929,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
 
 	/* now nuke the drive queue */
 	while ((req = elv_next_request(drive->queue))) {
-		blkdev_dequeue_request(req);
-		end_that_request_last(req, 0);
+		if (__blk_end_request(req, -EIO, 0))
+			BUG();
 	}
 
 	HWGROUP(drive)->rq = NULL;
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index a3d0c6b14958..f97d172844be 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -837,19 +837,16 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
 
 		/* Phase 4 - Setup scatter/gather buffers */
 	case 4:
-		if (cmd->use_sg) {
-			/* if many buffers are available, start filling the first */
-			cmd->SCp.buffer =
-			    (struct scatterlist *) cmd->request_buffer;
+		if (scsi_bufflen(cmd)) {
+			cmd->SCp.buffer = scsi_sglist(cmd);
 			cmd->SCp.this_residual = cmd->SCp.buffer->length;
 			cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
 		} else {
-			/* else fill the only available buffer */
 			cmd->SCp.buffer = NULL;
-			cmd->SCp.this_residual = cmd->request_bufflen;
-			cmd->SCp.ptr = cmd->request_buffer;
+			cmd->SCp.this_residual = 0;
+			cmd->SCp.ptr = NULL;
 		}
-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
 		cmd->SCp.phase++;
 		if (cmd->SCp.this_residual & 0x01)
 			cmd->SCp.this_residual++;
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index c8b452f2878c..8053b1e86ccb 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -369,16 +369,16 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
  *  - SCp.phase records this command's SRCID_ER bit setting
  */
 
-	if (cmd->use_sg) {
-		cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+	if (scsi_bufflen(cmd)) {
+		cmd->SCp.buffer = scsi_sglist(cmd);
+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
 	} else {
 		cmd->SCp.buffer = NULL;
 		cmd->SCp.buffers_residual = 0;
-		cmd->SCp.ptr = (char *) cmd->request_buffer;
-		cmd->SCp.this_residual = cmd->request_bufflen;
+		cmd->SCp.ptr = NULL;
+		cmd->SCp.this_residual = 0;
 	}
 	cmd->SCp.have_data_in = 0;
 
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 01bf0189367d..0cc8868ea35d 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -823,7 +823,7 @@ static void initio_append_busy_scb(struct initio_host * host, struct scsi_ctrl_b
 {
 
 #if DEBUG_QUEUE
-	printk("append busy SCB %o; ", scbp);
+	printk("append busy SCB %p; ", scbp);
 #endif
 	if (scbp->tagmsg)
 		host->act_tags[scbp->target]++;
@@ -2609,6 +2609,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c
 		cblk->bufptr = cpu_to_le32((u32)dma_addr);
 		cmnd->SCp.dma_handle = dma_addr;
 
+		cblk->sglen = nseg;
 
 		cblk->flags |= SCF_SG;	/* Turn on SG list flag       */
 		total_len = 0;
@@ -2832,7 +2833,6 @@ static struct scsi_host_template initio_template = {
 	.sg_tablesize		= SG_ALL,
 	.cmd_per_lun		= 1,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 };
 
 static int initio_probe_one(struct pci_dev *pdev,
@@ -2869,6 +2869,7 @@ static int initio_probe_one(struct pci_dev *pdev,
 	host = (struct initio_host *)shost->hostdata;
 	memset(host, 0, sizeof(struct initio_host));
 	host->addr = pci_resource_start(pdev, 0);
+	host->bios_addr = bios_seg;
 
 	if (!request_region(host->addr, 256, "i91u")) {
 		printk(KERN_WARNING "initio: I/O port range 0x%x is busy.\n", host->addr);
@@ -2895,6 +2896,8 @@ static int initio_probe_one(struct pci_dev *pdev,
 
 	host->pci_dev = pdev;
 
+	host->semaph = 1;
+	spin_lock_init(&host->semaph_lock);
 	host->num_scbs = num_scb;
 	host->scb = scb;
 	host->next_pending = scb;
@@ -2911,7 +2914,7 @@ static int initio_probe_one(struct pci_dev *pdev,
 	host->last_avail = prev;
 	spin_lock_init(&host->avail_lock);
 
-	initio_init(host, phys_to_virt(bios_seg << 4));
+	initio_init(host, phys_to_virt(((u32)bios_seg << 4)));
 
 	host->jsstatus0 = 0;
 
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 0841df01bc19..73270ff892d9 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -84,7 +84,7 @@
 /*
  *   Global Data
  */
-static struct list_head ipr_ioa_head = LIST_HEAD_INIT(ipr_ioa_head);
+static LIST_HEAD(ipr_ioa_head);
 static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL;
 static unsigned int ipr_max_speed = 1;
 static int ipr_testmode = 0;
@@ -5142,6 +5142,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
 	struct ipr_ioadl_desc *last_ioadl = NULL;
 	int len = qc->nbytes + qc->pad_len;
 	struct scatterlist *sg;
+	unsigned int si;
 
 	if (len == 0)
 		return;
@@ -5159,7 +5160,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
 			cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
 	}
 
-	ata_for_each_sg(sg, qc) {
+	for_each_sg(qc->sg, sg, qc->n_elem, si) {
 		ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg));
 		ioadl->address = cpu_to_be32(sg_dma_address(sg));
 
@@ -5222,12 +5223,12 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
 		regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
 		break;
 
-	case ATA_PROT_ATAPI:
-	case ATA_PROT_ATAPI_NODATA:
+	case ATAPI_PROT_PIO:
+	case ATAPI_PROT_NODATA:
 		regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
 		break;
 
-	case ATA_PROT_ATAPI_DMA:
+	case ATAPI_PROT_DMA:
 		regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
 		regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
 		break;
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 5c5a9b2628fc..7505cca8e68e 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -389,17 +389,17 @@ static struct  pci_device_id  ips_pci_table[] = {
 MODULE_DEVICE_TABLE( pci, ips_pci_table );
 
 static char ips_hot_plug_name[] = "ips";
-   
+
 static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
 static void __devexit ips_remove_device(struct pci_dev *pci_dev);
-   
+
 static struct pci_driver ips_pci_driver = {
 	.name		= ips_hot_plug_name,
 	.id_table	= ips_pci_table,
 	.probe		= ips_insert_device,
 	.remove		= __devexit_p(ips_remove_device),
 };
-           
+
 
 /*
  * Necessary forward function protoypes
@@ -587,7 +587,7 @@ static void
 ips_setup_funclist(ips_ha_t * ha)
 {
 
-	/*                                
+	/*
 	 * Setup Functions
 	 */
 	if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
@@ -702,12 +702,8 @@ ips_release(struct Scsi_Host *sh)
 	/* free extra memory */
 	ips_free(ha);
 
-	/* Free I/O Region */
-	if (ha->io_addr)
-		release_region(ha->io_addr, ha->io_len);
-
 	/* free IRQ */
-	free_irq(ha->irq, ha);
+	free_irq(ha->pcidev->irq, ha);
 
 	scsi_host_put(sh);
 
@@ -1637,7 +1633,7 @@ ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
 				return (IPS_FAILURE);
 			}
 
-			if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
+			if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD &&
 			    pt->CoppCP.cmd.flashfw.op_code ==
 			    IPS_CMD_RW_BIOSFW) {
 				ret = ips_flash_copperhead(ha, pt, scb);
@@ -2021,7 +2017,7 @@ ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
 	pt->ExtendedStatus = scb->extended_status;
 	pt->AdapterType = ha->ad_type;
 
-	if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
+	if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD &&
 	    (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD ||
 	     scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
 		ips_free_flash_copperhead(ha);
@@ -2075,13 +2071,13 @@ ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len)
 			  ha->mem_ptr);
 	}
 
-	copy_info(&info, "\tIRQ number                        : %d\n", ha->irq);
+	copy_info(&info, "\tIRQ number                        : %d\n", ha->pcidev->irq);
 
     /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */
     /* That keeps everything happy for "text" operations on the proc file.                    */
 
 	if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) {
-        if (ha->nvram->bios_low[3] == 0) { 
+	if (ha->nvram->bios_low[3] == 0) {
             copy_info(&info,
 			          "\tBIOS Version                      : %c%c%c%c%c%c%c\n",
 			          ha->nvram->bios_high[0], ha->nvram->bios_high[1],
@@ -2232,31 +2228,31 @@ ips_identify_controller(ips_ha_t * ha)
 {
 	METHOD_TRACE("ips_identify_controller", 1);
 
-	switch (ha->device_id) {
+	switch (ha->pcidev->device) {
 	case IPS_DEVICEID_COPPERHEAD:
-		if (ha->revision_id <= IPS_REVID_SERVERAID) {
+		if (ha->pcidev->revision <= IPS_REVID_SERVERAID) {
 			ha->ad_type = IPS_ADTYPE_SERVERAID;
-		} else if (ha->revision_id == IPS_REVID_SERVERAID2) {
+		} else if (ha->pcidev->revision == IPS_REVID_SERVERAID2) {
 			ha->ad_type = IPS_ADTYPE_SERVERAID2;
-		} else if (ha->revision_id == IPS_REVID_NAVAJO) {
+		} else if (ha->pcidev->revision == IPS_REVID_NAVAJO) {
 			ha->ad_type = IPS_ADTYPE_NAVAJO;
-		} else if ((ha->revision_id == IPS_REVID_SERVERAID2)
+		} else if ((ha->pcidev->revision == IPS_REVID_SERVERAID2)
 			   && (ha->slot_num == 0)) {
 			ha->ad_type = IPS_ADTYPE_KIOWA;
-		} else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
-			   (ha->revision_id <= IPS_REVID_CLARINETP3)) {
+		} else if ((ha->pcidev->revision >= IPS_REVID_CLARINETP1) &&
+			   (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) {
 			if (ha->enq->ucMaxPhysicalDevices == 15)
 				ha->ad_type = IPS_ADTYPE_SERVERAID3L;
 			else
 				ha->ad_type = IPS_ADTYPE_SERVERAID3;
-		} else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
-			   (ha->revision_id <= IPS_REVID_TROMBONE64)) {
+		} else if ((ha->pcidev->revision >= IPS_REVID_TROMBONE32) &&
+			   (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) {
 			ha->ad_type = IPS_ADTYPE_SERVERAID4H;
 		}
 		break;
 
 	case IPS_DEVICEID_MORPHEUS:
-		switch (ha->subdevice_id) {
+		switch (ha->pcidev->subsystem_device) {
 		case IPS_SUBDEVICEID_4L:
 			ha->ad_type = IPS_ADTYPE_SERVERAID4L;
 			break;
@@ -2285,7 +2281,7 @@ ips_identify_controller(ips_ha_t * ha)
 		break;
 
 	case IPS_DEVICEID_MARCO:
-		switch (ha->subdevice_id) {
+		switch (ha->pcidev->subsystem_device) {
 		case IPS_SUBDEVICEID_6M:
 			ha->ad_type = IPS_ADTYPE_SERVERAID6M;
 			break;
@@ -2332,20 +2328,20 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
 
 	strncpy(ha->bios_version, "       ?", 8);
 
-	if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
+	if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) {
 		if (IPS_USE_MEMIO(ha)) {
 			/* Memory Mapped I/O */
 
 			/* test 1st byte */
 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
 				return;
 
 			writel(1, ha->mem_ptr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
@@ -2353,20 +2349,20 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
 
 			/* Get Major version */
 			writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			major = readb(ha->mem_ptr + IPS_REG_FLDP);
 
 			/* Get Minor version */
 			writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 			minor = readb(ha->mem_ptr + IPS_REG_FLDP);
 
 			/* Get SubMinor version */
 			writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 			subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
 
@@ -2375,14 +2371,14 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
 
 			/* test 1st byte */
 			outl(0, ha->io_addr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
 				return;
 
 			outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
@@ -2390,21 +2386,21 @@ ips_get_bios_version(ips_ha_t * ha, int intr)
 
 			/* Get Major version */
 			outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			major = inb(ha->io_addr + IPS_REG_FLDP);
 
 			/* Get Minor version */
 			outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			minor = inb(ha->io_addr + IPS_REG_FLDP);
 
 			/* Get SubMinor version */
 			outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			subminor = inb(ha->io_addr + IPS_REG_FLDP);
@@ -2740,8 +2736,6 @@ ips_next(ips_ha_t * ha, int intr)
 		SC->result = DID_OK;
 		SC->host_scribble = NULL;
 
-		memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer));
-
 		scb->target_id = SC->device->id;
 		scb->lun = SC->device->lun;
 		scb->bus = SC->device->channel;
@@ -2780,10 +2774,11 @@ ips_next(ips_ha_t * ha, int intr)
 		scb->dcdb.cmd_attribute =
 		    ips_command_direction[scb->scsi_cmd->cmnd[0]];
 
-        /* Allow a WRITE BUFFER Command to Have no Data */
-        /* This is Used by Tape Flash Utilites          */
-        if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && (scb->data_len == 0)) 
-            scb->dcdb.cmd_attribute = 0;                  
+		/* Allow a WRITE BUFFER Command to Have no Data */
+		/* This is Used by Tape Flash Utilites          */
+		if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) &&
+				(scb->data_len == 0))
+			scb->dcdb.cmd_attribute = 0;
 
 		if (!(scb->dcdb.cmd_attribute & 0x3))
 			scb->dcdb.transfer_length = 0;
@@ -3404,7 +3399,7 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
 
 				/* Restrict access to physical DASD */
 				if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
-				    ips_scmd_buf_read(scb->scsi_cmd, 
+				    ips_scmd_buf_read(scb->scsi_cmd,
                                       &inquiryData, sizeof (inquiryData));
  				    if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) {
 				        errcode = DID_TIME_OUT;
@@ -3438,13 +3433,11 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
 					    (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
 					memcpy(scb->scsi_cmd->sense_buffer,
 					       tapeDCDB->sense_info,
-					       sizeof (scb->scsi_cmd->
-						       sense_buffer));
+					       SCSI_SENSE_BUFFERSIZE);
 				} else {
 					memcpy(scb->scsi_cmd->sense_buffer,
 					       scb->dcdb.sense_info,
-					       sizeof (scb->scsi_cmd->
-						       sense_buffer));
+					       SCSI_SENSE_BUFFERSIZE);
 				}
 				device_error = 2;	/* check condition */
 			}
@@ -3824,7 +3817,6 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
 			/* attempted, a Check Condition occurred, and Sense   */
 			/* Data indicating an Invalid CDB OpCode is returned. */
 			sp = (char *) scb->scsi_cmd->sense_buffer;
-			memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer));
 
 			sp[0] = 0x70;	/* Error Code               */
 			sp[2] = ILLEGAL_REQUEST;	/* Sense Key 5 Illegal Req. */
@@ -4090,10 +4082,10 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
 			scb->scsi_cmd->result = errcode << 16;
 		} else {	/* bus == 0 */
 			/* restrict access to physical drives */
-			if (scb->scsi_cmd->cmnd[0] == INQUIRY) { 
-			    ips_scmd_buf_read(scb->scsi_cmd, 
+			if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
+			    ips_scmd_buf_read(scb->scsi_cmd,
                                   &inquiryData, sizeof (inquiryData));
-			    if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) 
+			    if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK)
 			        scb->scsi_cmd->result = DID_TIME_OUT << 16;
 			}
 		}		/* else */
@@ -4393,8 +4385,6 @@ ips_free(ips_ha_t * ha)
 			ha->mem_ptr = NULL;
 		}
 
-		if (ha->mem_addr)
-			release_mem_region(ha->mem_addr, ha->mem_len);
 		ha->mem_addr = 0;
 
 	}
@@ -4661,8 +4651,8 @@ ips_isinit_morpheus(ips_ha_t * ha)
 	uint32_t bits;
 
 	METHOD_TRACE("ips_is_init_morpheus", 1);
-   
-	if (ips_isintr_morpheus(ha)) 
+
+	if (ips_isintr_morpheus(ha))
 	    ips_flush_and_reset(ha);
 
 	post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
@@ -4686,7 +4676,7 @@ ips_isinit_morpheus(ips_ha_t * ha)
 /*   state ( was trying to INIT and an interrupt was already pending ) ...  */
 /*                                                                          */
 /****************************************************************************/
-static void 
+static void
 ips_flush_and_reset(ips_ha_t *ha)
 {
 	ips_scb_t *scb;
@@ -4718,9 +4708,9 @@ ips_flush_and_reset(ips_ha_t *ha)
 	    if (ret == IPS_SUCCESS) {
 	        time = 60 * IPS_ONE_SEC;	              /* Max Wait time is 60 seconds */
 	        done = 0;
-	            
+
 	        while ((time > 0) && (!done)) {
-	           done = ips_poll_for_flush_complete(ha); 	   
+		   done = ips_poll_for_flush_complete(ha);
 	           /* This may look evil, but it's only done during extremely rare start-up conditions ! */
 	           udelay(1000);
 	           time--;
@@ -4749,17 +4739,17 @@ static int
 ips_poll_for_flush_complete(ips_ha_t * ha)
 {
 	IPS_STATUS cstatus;
-    
+
 	while (TRUE) {
 	    cstatus.value = (*ha->func.statupd) (ha);
 
 	    if (cstatus.value == 0xffffffff)      /* If No Interrupt to process */
 			break;
-            
+
 	    /* Success is when we see the Flush Command ID */
-	    if (cstatus.fields.command_id == IPS_MAX_CMDS ) 
+	    if (cstatus.fields.command_id == IPS_MAX_CMDS)
 	        return 1;
-	 }	
+	 }
 
 	return 0;
 }
@@ -4903,7 +4893,7 @@ ips_init_copperhead(ips_ha_t * ha)
 	/* Enable busmastering */
 	outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
 
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		/* fix for anaconda64 */
 		outl(0, ha->io_addr + IPS_REG_NDAE);
 
@@ -4997,7 +4987,7 @@ ips_init_copperhead_memio(ips_ha_t * ha)
 	/* Enable busmastering */
 	writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
 
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		/* fix for anaconda64 */
 		writel(0, ha->mem_ptr + IPS_REG_NDAE);
 
@@ -5142,7 +5132,7 @@ ips_reset_copperhead(ips_ha_t * ha)
 	METHOD_TRACE("ips_reset_copperhead", 1);
 
 	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
-		  ips_name, ha->host_num, ha->io_addr, ha->irq);
+		  ips_name, ha->host_num, ha->io_addr, ha->pcidev->irq);
 
 	reset_counter = 0;
 
@@ -5187,7 +5177,7 @@ ips_reset_copperhead_memio(ips_ha_t * ha)
 	METHOD_TRACE("ips_reset_copperhead_memio", 1);
 
 	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
-		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
+		  ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq);
 
 	reset_counter = 0;
 
@@ -5233,7 +5223,7 @@ ips_reset_morpheus(ips_ha_t * ha)
 	METHOD_TRACE("ips_reset_morpheus", 1);
 
 	DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
-		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
+		  ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq);
 
 	reset_counter = 0;
 
@@ -5920,7 +5910,7 @@ ips_read_config(ips_ha_t * ha, int intr)
 
 		return (0);
 	}
-	
+
 	memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf));
 	return (1);
 }
@@ -5959,7 +5949,7 @@ ips_readwrite_page5(ips_ha_t * ha, int write, int intr)
 	scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr;
 	if (write)
 		memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));
-	
+
 	/* issue the command */
 	if (((ret =
 	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
@@ -6196,32 +6186,32 @@ ips_erase_bios(ips_ha_t * ha)
 
 	/* Clear the status register */
 	outl(0, ha->io_addr + IPS_REG_FLAP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	outb(0x50, ha->io_addr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	/* Erase Setup */
 	outb(0x20, ha->io_addr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	/* Erase Confirm */
 	outb(0xD0, ha->io_addr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	/* Erase Status */
 	outb(0x70, ha->io_addr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	timeout = 80000;	/* 80 seconds */
 
 	while (timeout > 0) {
-		if (ha->revision_id == IPS_REVID_TROMBONE64) {
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
 			outl(0, ha->io_addr + IPS_REG_FLAP);
 			udelay(25);	/* 25 us */
 		}
@@ -6241,13 +6231,13 @@ ips_erase_bios(ips_ha_t * ha)
 
 		/* try to suspend the erase */
 		outb(0xB0, ha->io_addr + IPS_REG_FLDP);
-		if (ha->revision_id == IPS_REVID_TROMBONE64)
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 			udelay(25);	/* 25 us */
 
 		/* wait for 10 seconds */
 		timeout = 10000;
 		while (timeout > 0) {
-			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
 				outl(0, ha->io_addr + IPS_REG_FLAP);
 				udelay(25);	/* 25 us */
 			}
@@ -6277,12 +6267,12 @@ ips_erase_bios(ips_ha_t * ha)
 	/* Otherwise, we were successful */
 	/* clear status */
 	outb(0x50, ha->io_addr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	/* enable reads */
 	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	return (0);
@@ -6308,32 +6298,32 @@ ips_erase_bios_memio(ips_ha_t * ha)
 
 	/* Clear the status register */
 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	/* Erase Setup */
 	writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	/* Erase Confirm */
 	writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	/* Erase Status */
 	writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	timeout = 80000;	/* 80 seconds */
 
 	while (timeout > 0) {
-		if (ha->revision_id == IPS_REVID_TROMBONE64) {
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
 			udelay(25);	/* 25 us */
 		}
@@ -6353,13 +6343,13 @@ ips_erase_bios_memio(ips_ha_t * ha)
 
 		/* try to suspend the erase */
 		writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
-		if (ha->revision_id == IPS_REVID_TROMBONE64)
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 			udelay(25);	/* 25 us */
 
 		/* wait for 10 seconds */
 		timeout = 10000;
 		while (timeout > 0) {
-			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
 				writel(0, ha->mem_ptr + IPS_REG_FLAP);
 				udelay(25);	/* 25 us */
 			}
@@ -6389,12 +6379,12 @@ ips_erase_bios_memio(ips_ha_t * ha)
 	/* Otherwise, we were successful */
 	/* clear status */
 	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	/* enable reads */
 	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	return (0);
@@ -6423,21 +6413,21 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 	for (i = 0; i < buffersize; i++) {
 		/* write a byte */
 		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
-		if (ha->revision_id == IPS_REVID_TROMBONE64)
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 			udelay(25);	/* 25 us */
 
 		outb(0x40, ha->io_addr + IPS_REG_FLDP);
-		if (ha->revision_id == IPS_REVID_TROMBONE64)
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 			udelay(25);	/* 25 us */
 
 		outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
-		if (ha->revision_id == IPS_REVID_TROMBONE64)
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 			udelay(25);	/* 25 us */
 
 		/* wait up to one second */
 		timeout = 1000;
 		while (timeout > 0) {
-			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
 				outl(0, ha->io_addr + IPS_REG_FLAP);
 				udelay(25);	/* 25 us */
 			}
@@ -6454,11 +6444,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 		if (timeout == 0) {
 			/* timeout error */
 			outl(0, ha->io_addr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			return (1);
@@ -6468,11 +6458,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 		if (status & 0x18) {
 			/* programming error */
 			outl(0, ha->io_addr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			return (1);
@@ -6481,11 +6471,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 
 	/* Enable reading */
 	outl(0, ha->io_addr + IPS_REG_FLAP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	return (0);
@@ -6514,21 +6504,21 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 	for (i = 0; i < buffersize; i++) {
 		/* write a byte */
 		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
-		if (ha->revision_id == IPS_REVID_TROMBONE64)
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 			udelay(25);	/* 25 us */
 
 		writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
-		if (ha->revision_id == IPS_REVID_TROMBONE64)
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 			udelay(25);	/* 25 us */
 
 		writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
-		if (ha->revision_id == IPS_REVID_TROMBONE64)
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 			udelay(25);	/* 25 us */
 
 		/* wait up to one second */
 		timeout = 1000;
 		while (timeout > 0) {
-			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64) {
 				writel(0, ha->mem_ptr + IPS_REG_FLAP);
 				udelay(25);	/* 25 us */
 			}
@@ -6545,11 +6535,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 		if (timeout == 0) {
 			/* timeout error */
 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			return (1);
@@ -6559,11 +6549,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 		if (status & 0x18) {
 			/* programming error */
 			writel(0, ha->mem_ptr + IPS_REG_FLAP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-			if (ha->revision_id == IPS_REVID_TROMBONE64)
+			if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 				udelay(25);	/* 25 us */
 
 			return (1);
@@ -6572,11 +6562,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 
 	/* Enable reading */
 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	return (0);
@@ -6601,14 +6591,14 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 
 	/* test 1st byte */
 	outl(0, ha->io_addr + IPS_REG_FLAP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
 		return (1);
 
 	outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 	if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
 		return (1);
@@ -6617,7 +6607,7 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 	for (i = 2; i < buffersize; i++) {
 
 		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
-		if (ha->revision_id == IPS_REVID_TROMBONE64)
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 			udelay(25);	/* 25 us */
 
 		checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
@@ -6650,14 +6640,14 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 
 	/* test 1st byte */
 	writel(0, ha->mem_ptr + IPS_REG_FLAP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 
 	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
 		return (1);
 
 	writel(1, ha->mem_ptr + IPS_REG_FLAP);
-	if (ha->revision_id == IPS_REVID_TROMBONE64)
+	if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 		udelay(25);	/* 25 us */
 	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
 		return (1);
@@ -6666,7 +6656,7 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
 	for (i = 2; i < buffersize; i++) {
 
 		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
-		if (ha->revision_id == IPS_REVID_TROMBONE64)
+		if (ha->pcidev->revision == IPS_REVID_TROMBONE64)
 			udelay(25);	/* 25 us */
 
 		checksum =
@@ -6837,24 +6827,18 @@ ips_register_scsi(int index)
 	}
 	ha = IPS_HA(sh);
 	memcpy(ha, oldha, sizeof (ips_ha_t));
-	free_irq(oldha->irq, oldha);
+	free_irq(oldha->pcidev->irq, oldha);
 	/* Install the interrupt handler with the new ha */
-	if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
+	if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
 			   "Unable to install interrupt handler\n");
-		scsi_host_put(sh);
-		return -1;
+		goto err_out_sh;
 	}
 
 	kfree(oldha);
-	ips_sh[index] = sh;
-	ips_ha[index] = ha;
 
 	/* Store away needed values for later use */
-	sh->io_port = ha->io_addr;
-	sh->n_io_port = ha->io_addr ? 255 : 0;
 	sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr;
-	sh->irq = ha->irq;
 	sh->sg_tablesize = sh->hostt->sg_tablesize;
 	sh->can_queue = sh->hostt->can_queue;
 	sh->cmd_per_lun = sh->hostt->cmd_per_lun;
@@ -6867,10 +6851,21 @@ ips_register_scsi(int index)
 	sh->max_channel = ha->nbus - 1;
 	sh->can_queue = ha->max_cmds - 1;
 
-	scsi_add_host(sh, NULL);
+	if (scsi_add_host(sh, &ha->pcidev->dev))
+		goto err_out;
+
+	ips_sh[index] = sh;
+	ips_ha[index] = ha;
+
 	scsi_scan_host(sh);
 
 	return 0;
+
+err_out:
+	free_irq(ha->pcidev->irq, ha);
+err_out_sh:
+	scsi_host_put(sh);
+	return -1;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -6882,20 +6877,14 @@ ips_register_scsi(int index)
 static void __devexit
 ips_remove_device(struct pci_dev *pci_dev)
 {
-	int i;
-	struct Scsi_Host *sh;
-	ips_ha_t *ha;
+	struct Scsi_Host *sh = pci_get_drvdata(pci_dev);
 
-	for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
-		ha = ips_ha[i];
-		if (ha) {
-			if ((pci_dev->bus->number == ha->pcidev->bus->number) &&
-			    (pci_dev->devfn == ha->pcidev->devfn)) {
-				sh = ips_sh[i];
-				ips_release(sh);
-			}
-		}
-	}
+	pci_set_drvdata(pci_dev, NULL);
+
+	ips_release(sh);
+
+	pci_release_regions(pci_dev);
+	pci_disable_device(pci_dev);
 }
 
 /****************************************************************************/
@@ -6949,12 +6938,17 @@ module_exit(ips_module_exit);
 static int __devinit
 ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
 {
-	int uninitialized_var(index);
+	int index = -1;
 	int rc;
 
 	METHOD_TRACE("ips_insert_device", 1);
-	if (pci_enable_device(pci_dev))
-		return -1;
+	rc = pci_enable_device(pci_dev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pci_dev, "ips");
+	if (rc)
+		goto err_out;
 
 	rc = ips_init_phase1(pci_dev, &index);
 	if (rc == SUCCESS)
@@ -6970,6 +6964,19 @@ ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
 		ips_num_controllers++;
 
 	ips_next_controller = ips_num_controllers;
+
+	if (rc < 0) {
+		rc = -ENODEV;
+		goto err_out_regions;
+	}
+
+	pci_set_drvdata(pci_dev, ips_sh[index]);
+	return 0;
+
+err_out_regions:
+	pci_release_regions(pci_dev);
+err_out:
+	pci_disable_device(pci_dev);
 	return rc;
 }
 
@@ -6992,8 +6999,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
 	uint32_t mem_len;
 	uint8_t bus;
 	uint8_t func;
-	uint8_t irq;
-	uint16_t subdevice_id;
 	int j;
 	int index;
 	dma_addr_t dma_address;
@@ -7004,7 +7009,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
 	METHOD_TRACE("ips_init_phase1", 1);
 	index = IPS_MAX_ADAPTERS;
 	for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
-		if (ips_ha[j] == 0) {
+		if (ips_ha[j] == NULL) {
 			index = j;
 			break;
 		}
@@ -7014,7 +7019,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
 		return -1;
 
 	/* stuff that we get in dev */
-	irq = pci_dev->irq;
 	bus = pci_dev->bus->number;
 	func = pci_dev->devfn;
 
@@ -7042,34 +7046,17 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
 		uint32_t base;
 		uint32_t offs;
 
-		if (!request_mem_region(mem_addr, mem_len, "ips")) {
-			IPS_PRINTK(KERN_WARNING, pci_dev,
-				   "Couldn't allocate IO Memory space %x len %d.\n",
-				   mem_addr, mem_len);
-			return -1;
-		}
-
 		base = mem_addr & PAGE_MASK;
 		offs = mem_addr - base;
 		ioremap_ptr = ioremap(base, PAGE_SIZE);
+		if (!ioremap_ptr)
+			return -1;
 		mem_ptr = ioremap_ptr + offs;
 	} else {
 		ioremap_ptr = NULL;
 		mem_ptr = NULL;
 	}
 
-	/* setup I/O mapped area (if applicable) */
-	if (io_addr) {
-		if (!request_region(io_addr, io_len, "ips")) {
-			IPS_PRINTK(KERN_WARNING, pci_dev,
-				   "Couldn't allocate IO space %x len %d.\n",
-				   io_addr, io_len);
-			return -1;
-		}
-	}
-
-	subdevice_id = pci_dev->subsystem_device;
-
 	/* found a controller */
 	ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL);
 	if (ha == NULL) {
@@ -7078,13 +7065,11 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
 		return -1;
 	}
 
-
 	ips_sh[index] = NULL;
 	ips_ha[index] = ha;
 	ha->active = 1;
 
 	/* Store info in HA structure */
-	ha->irq = irq;
 	ha->io_addr = io_addr;
 	ha->io_len = io_len;
 	ha->mem_addr = mem_addr;
@@ -7092,10 +7077,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
 	ha->mem_ptr = mem_ptr;
 	ha->ioremap_ptr = ioremap_ptr;
 	ha->host_num = (uint32_t) index;
-	ha->revision_id = pci_dev->revision;
 	ha->slot_num = PCI_SLOT(pci_dev->devfn);
-	ha->device_id = pci_dev->device;
-	ha->subdevice_id = subdevice_id;
 	ha->pcidev = pci_dev;
 
 	/*
@@ -7240,7 +7222,7 @@ ips_init_phase2(int index)
 	}
 
 	/* Install the interrupt handler */
-	if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
+	if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
 			   "Unable to install interrupt handler\n");
 		return ips_abort_init(ha, index);
@@ -7253,14 +7235,14 @@ ips_init_phase2(int index)
 	if (!ips_allocatescbs(ha)) {
 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
 			   "Unable to allocate a CCB\n");
-		free_irq(ha->irq, ha);
+		free_irq(ha->pcidev->irq, ha);
 		return ips_abort_init(ha, index);
 	}
 
 	if (!ips_hainit(ha)) {
 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
 			   "Unable to initialize controller\n");
-		free_irq(ha->irq, ha);
+		free_irq(ha->pcidev->irq, ha);
 		return ips_abort_init(ha, index);
 	}
 	/* Free the temporary SCB */
@@ -7270,7 +7252,7 @@ ips_init_phase2(int index)
 	if (!ips_allocatescbs(ha)) {
 		IPS_PRINTK(KERN_WARNING, ha->pcidev,
 			   "Unable to allocate CCBs\n");
-		free_irq(ha->irq, ha);
+		free_irq(ha->pcidev->irq, ha);
 		return ips_abort_init(ha, index);
 	}
 
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index 3bcbd9ff056b..e0657b6f009c 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -60,14 +60,14 @@
     */
    #define IPS_HA(x)                   ((ips_ha_t *) x->hostdata)
    #define IPS_COMMAND_ID(ha, scb)     (int) (scb - ha->scbs)
-   #define IPS_IS_TROMBONE(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
-                                         (ha->revision_id >= IPS_REVID_TROMBONE32) && \
-                                         (ha->revision_id <= IPS_REVID_TROMBONE64)) ? 1 : 0)
-   #define IPS_IS_CLARINET(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
-                                         (ha->revision_id >= IPS_REVID_CLARINETP1) && \
-                                         (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0)
-   #define IPS_IS_MORPHEUS(ha)         (ha->device_id == IPS_DEVICEID_MORPHEUS)
-   #define IPS_IS_MARCO(ha)            (ha->device_id == IPS_DEVICEID_MARCO)
+   #define IPS_IS_TROMBONE(ha)         (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \
+                                         (ha->pcidev->revision >= IPS_REVID_TROMBONE32) && \
+                                         (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) ? 1 : 0)
+   #define IPS_IS_CLARINET(ha)         (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \
+                                         (ha->pcidev->revision >= IPS_REVID_CLARINETP1) && \
+                                         (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) ? 1 : 0)
+   #define IPS_IS_MORPHEUS(ha)         (ha->pcidev->device == IPS_DEVICEID_MORPHEUS)
+   #define IPS_IS_MARCO(ha)            (ha->pcidev->device == IPS_DEVICEID_MARCO)
    #define IPS_USE_I2O_DELIVER(ha)     ((IPS_IS_MORPHEUS(ha) || \
                                          (IPS_IS_TROMBONE(ha) && \
                                           (ips_force_i2o))) ? 1 : 0)
@@ -92,7 +92,7 @@
    #ifndef min
       #define min(x,y) ((x) < (y) ? x : y)
    #endif
-   
+
    #ifndef __iomem       /* For clean compiles in earlier kernels without __iomem annotations */
       #define __iomem
    #endif
@@ -171,7 +171,7 @@
    #define IPS_CMD_DOWNLOAD             0x20
    #define IPS_CMD_RW_BIOSFW            0x22
    #define IPS_CMD_GET_VERSION_INFO     0xC6
-   #define IPS_CMD_RESET_CHANNEL        0x1A  
+   #define IPS_CMD_RESET_CHANNEL        0x1A
 
    /*
     * Adapter Equates
@@ -458,7 +458,7 @@ typedef struct {
    uint32_t reserved3;
    uint32_t buffer_addr;
    uint32_t reserved4;
-} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD; 
+} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD;
 
 typedef struct {
    uint8_t  op_code;
@@ -552,7 +552,7 @@ typedef struct {
    uint32_t cccr;
 } IPS_NVRAM_CMD, *PIPS_NVRAM_CMD;
 
-typedef struct 
+typedef struct
 {
     uint8_t  op_code;
     uint8_t  command_id;
@@ -650,7 +650,7 @@ typedef struct {
    uint8_t   device_address;
    uint8_t   cmd_attribute;
    uint8_t   cdb_length;
-   uint8_t   reserved_for_LUN; 	 
+   uint8_t   reserved_for_LUN;
    uint32_t  transfer_length;
    uint32_t  buffer_pointer;
    uint16_t  sg_count;
@@ -790,7 +790,7 @@ typedef struct {
                                              /* SubSystem Parameter[4]      */
 #define  IPS_GET_VERSION_SUPPORT 0x00018000  /* Mask for Versioning Support */
 
-typedef struct 
+typedef struct
 {
    uint32_t  revision;
    uint8_t   bootBlkVersion[32];
@@ -1034,7 +1034,6 @@ typedef struct ips_ha {
    uint8_t            ha_id[IPS_MAX_CHANNELS+1];
    uint32_t           dcdb_active[IPS_MAX_CHANNELS];
    uint32_t           io_addr;            /* Base I/O address           */
-   uint8_t            irq;                /* IRQ for adapter            */
    uint8_t            ntargets;           /* Number of targets          */
    uint8_t            nbus;               /* Number of buses            */
    uint8_t            nlun;               /* Number of Luns             */
@@ -1066,10 +1065,7 @@ typedef struct ips_ha {
    int                ioctl_reset;        /* IOCTL Requested Reset Flag */
    uint16_t           reset_count;        /* number of resets           */
    time_t             last_ffdc;          /* last time we sent ffdc info*/
-   uint8_t            revision_id;        /* Revision level             */
-   uint16_t           device_id;          /* PCI device ID              */
    uint8_t            slot_num;           /* PCI Slot Number            */
-   uint16_t           subdevice_id;       /* Subsystem device ID        */
    int                ioctl_len;          /* size of ioctl buffer       */
    dma_addr_t         ioctl_busaddr;      /* dma address of ioctl buffer*/
    uint8_t            bios_version[8];    /* BIOS Revision              */
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 57ce2251abc8..b6f99dfbb038 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -48,7 +48,7 @@ MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus@yahoo.com>, "
 	      "Alex Aizman <itn780@yahoo.com>");
 MODULE_DESCRIPTION("iSCSI/TCP data-path");
 MODULE_LICENSE("GPL");
-/* #define DEBUG_TCP */
+#undef DEBUG_TCP
 #define DEBUG_ASSERT
 
 #ifdef DEBUG_TCP
@@ -67,115 +67,429 @@ MODULE_LICENSE("GPL");
 static unsigned int iscsi_max_lun = 512;
 module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
 
+static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
+				   struct iscsi_segment *segment);
+
+/*
+ * Scatterlist handling: inside the iscsi_segment, we
+ * remember an index into the scatterlist, and set data/size
+ * to the current scatterlist entry. For highmem pages, we
+ * kmap as needed.
+ *
+ * Note that the page is unmapped when we return from
+ * TCP's data_ready handler, so we may end up mapping and
+ * unmapping the same page repeatedly. The whole reason
+ * for this is that we shouldn't keep the page mapped
+ * outside the softirq.
+ */
+
+/**
+ * iscsi_tcp_segment_init_sg - init indicated scatterlist entry
+ * @segment: the buffer object
+ * @sg: scatterlist
+ * @offset: byte offset into that sg entry
+ *
+ * This function sets up the segment so that subsequent
+ * data is copied to the indicated sg entry, at the given
+ * offset.
+ */
 static inline void
-iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
+iscsi_tcp_segment_init_sg(struct iscsi_segment *segment,
+			  struct scatterlist *sg, unsigned int offset)
 {
-	sg_init_one(&ibuf->sg, vbuf, size);
-	ibuf->sent = 0;
-	ibuf->use_sendmsg = 1;
+	segment->sg = sg;
+	segment->sg_offset = offset;
+	segment->size = min(sg->length - offset,
+			    segment->total_size - segment->total_copied);
+	segment->data = NULL;
 }
 
+/**
+ * iscsi_tcp_segment_map - map the current S/G page
+ * @segment: iscsi_segment
+ * @recv: 1 if called from recv path
+ *
+ * We only need to possibly kmap data if scatter lists are being used,
+ * because the iscsi passthrough and internal IO paths will never use high
+ * mem pages.
+ */
 static inline void
-iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
+iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv)
 {
-	sg_init_table(&ibuf->sg, 1);
-	sg_set_page(&ibuf->sg, sg_page(sg), sg->length, sg->offset);
+	struct scatterlist *sg;
+
+	if (segment->data != NULL || !segment->sg)
+		return;
+
+	sg = segment->sg;
+	BUG_ON(segment->sg_mapped);
+	BUG_ON(sg->length == 0);
+
 	/*
-	 * Fastpath: sg element fits into single page
+	 * If the page count is greater than one it is ok to send
+	 * to the network layer's zero copy send path. If not we
+	 * have to go the slow sendmsg path. We always map for the
+	 * recv path.
 	 */
-	if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg_page(sg)))
-		ibuf->use_sendmsg = 0;
-	else
-		ibuf->use_sendmsg = 1;
-	ibuf->sent = 0;
+	if (page_count(sg_page(sg)) >= 1 && !recv)
+		return;
+
+	debug_tcp("iscsi_tcp_segment_map %s %p\n", recv ? "recv" : "xmit",
+		  segment);
+	segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0);
+	segment->data = segment->sg_mapped + sg->offset + segment->sg_offset;
 }
 
-static inline int
-iscsi_buf_left(struct iscsi_buf *ibuf)
+static inline void
+iscsi_tcp_segment_unmap(struct iscsi_segment *segment)
 {
-	int rc;
+	debug_tcp("iscsi_tcp_segment_unmap %p\n", segment);
 
-	rc = ibuf->sg.length - ibuf->sent;
-	BUG_ON(rc < 0);
-	return rc;
+	if (segment->sg_mapped) {
+		debug_tcp("iscsi_tcp_segment_unmap valid\n");
+		kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0);
+		segment->sg_mapped = NULL;
+		segment->data = NULL;
+	}
 }
 
+/*
+ * Splice the digest buffer into the buffer
+ */
 static inline void
-iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
-		 u8* crc)
+iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest)
 {
-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-
-	crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
-	buf->sg.length += sizeof(u32);
+	segment->data = digest;
+	segment->digest_len = ISCSI_DIGEST_SIZE;
+	segment->total_size += ISCSI_DIGEST_SIZE;
+	segment->size = ISCSI_DIGEST_SIZE;
+	segment->copied = 0;
+	segment->sg = NULL;
+	segment->hash = NULL;
 }
 
+/**
+ * iscsi_tcp_segment_done - check whether the segment is complete
+ * @segment: iscsi segment to check
+ * @recv: set to one of this is called from the recv path
+ * @copied: number of bytes copied
+ *
+ * Check if we're done receiving this segment. If the receive
+ * buffer is full but we expect more data, move on to the
+ * next entry in the scatterlist.
+ *
+ * If the amount of data we received isn't a multiple of 4,
+ * we will transparently receive the pad bytes, too.
+ *
+ * This function must be re-entrant.
+ */
 static inline int
-iscsi_hdr_extract(struct iscsi_tcp_conn *tcp_conn)
+iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv, unsigned copied)
 {
-	struct sk_buff *skb = tcp_conn->in.skb;
-
-	tcp_conn->in.zero_copy_hdr = 0;
+	static unsigned char padbuf[ISCSI_PAD_LEN];
+	struct scatterlist sg;
+	unsigned int pad;
 
-	if (tcp_conn->in.copy >= tcp_conn->hdr_size &&
-	    tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER) {
+	debug_tcp("copied %u %u size %u %s\n", segment->copied, copied,
+		  segment->size, recv ? "recv" : "xmit");
+	if (segment->hash && copied) {
 		/*
-		 * Zero-copy PDU Header: using connection context
-		 * to store header pointer.
+		 * If a segment is kmapd we must unmap it before sending
+		 * to the crypto layer since that will try to kmap it again.
 		 */
-		if (skb_shinfo(skb)->frag_list == NULL &&
-		    !skb_shinfo(skb)->nr_frags) {
-			tcp_conn->in.hdr = (struct iscsi_hdr *)
-				((char*)skb->data + tcp_conn->in.offset);
-			tcp_conn->in.zero_copy_hdr = 1;
+		iscsi_tcp_segment_unmap(segment);
+
+		if (!segment->data) {
+			sg_init_table(&sg, 1);
+			sg_set_page(&sg, sg_page(segment->sg), copied,
+				    segment->copied + segment->sg_offset +
+							segment->sg->offset);
+		} else
+			sg_init_one(&sg, segment->data + segment->copied,
+				    copied);
+		crypto_hash_update(segment->hash, &sg, copied);
+	}
+
+	segment->copied += copied;
+	if (segment->copied < segment->size) {
+		iscsi_tcp_segment_map(segment, recv);
+		return 0;
+	}
+
+	segment->total_copied += segment->copied;
+	segment->copied = 0;
+	segment->size = 0;
+
+	/* Unmap the current scatterlist page, if there is one. */
+	iscsi_tcp_segment_unmap(segment);
+
+	/* Do we have more scatterlist entries? */
+	debug_tcp("total copied %u total size %u\n", segment->total_copied,
+		   segment->total_size);
+	if (segment->total_copied < segment->total_size) {
+		/* Proceed to the next entry in the scatterlist. */
+		iscsi_tcp_segment_init_sg(segment, sg_next(segment->sg),
+					  0);
+		iscsi_tcp_segment_map(segment, recv);
+		BUG_ON(segment->size == 0);
+		return 0;
+	}
+
+	/* Do we need to handle padding? */
+	pad = iscsi_padding(segment->total_copied);
+	if (pad != 0) {
+		debug_tcp("consume %d pad bytes\n", pad);
+		segment->total_size += pad;
+		segment->size = pad;
+		segment->data = padbuf;
+		return 0;
+	}
+
+	/*
+	 * Set us up for transferring the data digest. hdr digest
+	 * is completely handled in hdr done function.
+	 */
+	if (segment->hash) {
+		crypto_hash_final(segment->hash, segment->digest);
+		iscsi_tcp_segment_splice_digest(segment,
+				 recv ? segment->recv_digest : segment->digest);
+		return 0;
+	}
+
+	return 1;
+}
+
+/**
+ * iscsi_tcp_xmit_segment - transmit segment
+ * @tcp_conn: the iSCSI TCP connection
+ * @segment: the buffer to transmnit
+ *
+ * This function transmits as much of the buffer as
+ * the network layer will accept, and returns the number of
+ * bytes transmitted.
+ *
+ * If CRC hashing is enabled, the function will compute the
+ * hash as it goes. When the entire segment has been transmitted,
+ * it will retrieve the hash value and send it as well.
+ */
+static int
+iscsi_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
+		       struct iscsi_segment *segment)
+{
+	struct socket *sk = tcp_conn->sock;
+	unsigned int copied = 0;
+	int r = 0;
+
+	while (!iscsi_tcp_segment_done(segment, 0, r)) {
+		struct scatterlist *sg;
+		unsigned int offset, copy;
+		int flags = 0;
+
+		r = 0;
+		offset = segment->copied;
+		copy = segment->size - offset;
+
+		if (segment->total_copied + segment->size < segment->total_size)
+			flags |= MSG_MORE;
+
+		/* Use sendpage if we can; else fall back to sendmsg */
+		if (!segment->data) {
+			sg = segment->sg;
+			offset += segment->sg_offset + sg->offset;
+			r = tcp_conn->sendpage(sk, sg_page(sg), offset, copy,
+					       flags);
 		} else {
-			/* ignoring return code since we checked
-			 * in.copy before */
-			skb_copy_bits(skb, tcp_conn->in.offset,
-				&tcp_conn->hdr, tcp_conn->hdr_size);
-			tcp_conn->in.hdr = &tcp_conn->hdr;
+			struct msghdr msg = { .msg_flags = flags };
+			struct kvec iov = {
+				.iov_base = segment->data + offset,
+				.iov_len = copy
+			};
+
+			r = kernel_sendmsg(sk, &msg, &iov, 1, copy);
 		}
-		tcp_conn->in.offset += tcp_conn->hdr_size;
-		tcp_conn->in.copy -= tcp_conn->hdr_size;
-	} else {
-		int hdr_remains;
-		int copylen;
 
-		/*
-		 * PDU header scattered across SKB's,
-		 * copying it... This'll happen quite rarely.
-		 */
+		if (r < 0) {
+			iscsi_tcp_segment_unmap(segment);
+			if (copied || r == -EAGAIN)
+				break;
+			return r;
+		}
+		copied += r;
+	}
+	return copied;
+}
+
+/**
+ * iscsi_tcp_segment_recv - copy data to segment
+ * @tcp_conn: the iSCSI TCP connection
+ * @segment: the buffer to copy to
+ * @ptr: data pointer
+ * @len: amount of data available
+ *
+ * This function copies up to @len bytes to the
+ * given buffer, and returns the number of bytes
+ * consumed, which can actually be less than @len.
+ *
+ * If hash digest is enabled, the function will update the
+ * hash while copying.
+ * Combining these two operations doesn't buy us a lot (yet),
+ * but in the future we could implement combined copy+crc,
+ * just way we do for network layer checksums.
+ */
+static int
+iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn,
+		       struct iscsi_segment *segment, const void *ptr,
+		       unsigned int len)
+{
+	unsigned int copy = 0, copied = 0;
+
+	while (!iscsi_tcp_segment_done(segment, 1, copy)) {
+		if (copied == len) {
+			debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n",
+				  len);
+			break;
+		}
+
+		copy = min(len - copied, segment->size - segment->copied);
+		debug_tcp("iscsi_tcp_segment_recv copying %d\n", copy);
+		memcpy(segment->data + segment->copied, ptr + copied, copy);
+		copied += copy;
+	}
+	return copied;
+}
 
-		if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER)
-			tcp_conn->in.hdr_offset = 0;
+static inline void
+iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr, size_t hdrlen,
+		      unsigned char digest[ISCSI_DIGEST_SIZE])
+{
+	struct scatterlist sg;
 
-		hdr_remains = tcp_conn->hdr_size - tcp_conn->in.hdr_offset;
-		BUG_ON(hdr_remains <= 0);
+	sg_init_one(&sg, hdr, hdrlen);
+	crypto_hash_digest(hash, &sg, hdrlen, digest);
+}
 
-		copylen = min(tcp_conn->in.copy, hdr_remains);
-		skb_copy_bits(skb, tcp_conn->in.offset,
-			(char*)&tcp_conn->hdr + tcp_conn->in.hdr_offset,
-			copylen);
+static inline int
+iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn,
+		      struct iscsi_segment *segment)
+{
+	if (!segment->digest_len)
+		return 1;
 
-		debug_tcp("PDU gather offset %d bytes %d in.offset %d "
-		       "in.copy %d\n", tcp_conn->in.hdr_offset, copylen,
-		       tcp_conn->in.offset, tcp_conn->in.copy);
+	if (memcmp(segment->recv_digest, segment->digest,
+		   segment->digest_len)) {
+		debug_scsi("digest mismatch\n");
+		return 0;
+	}
 
-		tcp_conn->in.offset += copylen;
-		tcp_conn->in.copy -= copylen;
-		if (copylen < hdr_remains)  {
-			tcp_conn->in_progress = IN_PROGRESS_HEADER_GATHER;
-			tcp_conn->in.hdr_offset += copylen;
-		        return -EAGAIN;
+	return 1;
+}
+
+/*
+ * Helper function to set up segment buffer
+ */
+static inline void
+__iscsi_segment_init(struct iscsi_segment *segment, size_t size,
+		     iscsi_segment_done_fn_t *done, struct hash_desc *hash)
+{
+	memset(segment, 0, sizeof(*segment));
+	segment->total_size = size;
+	segment->done = done;
+
+	if (hash) {
+		segment->hash = hash;
+		crypto_hash_init(hash);
+	}
+}
+
+static inline void
+iscsi_segment_init_linear(struct iscsi_segment *segment, void *data,
+			  size_t size, iscsi_segment_done_fn_t *done,
+			  struct hash_desc *hash)
+{
+	__iscsi_segment_init(segment, size, done, hash);
+	segment->data = data;
+	segment->size = size;
+}
+
+static inline int
+iscsi_segment_seek_sg(struct iscsi_segment *segment,
+		      struct scatterlist *sg_list, unsigned int sg_count,
+		      unsigned int offset, size_t size,
+		      iscsi_segment_done_fn_t *done, struct hash_desc *hash)
+{
+	struct scatterlist *sg;
+	unsigned int i;
+
+	debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n",
+		  offset, size);
+	__iscsi_segment_init(segment, size, done, hash);
+	for_each_sg(sg_list, sg, sg_count, i) {
+		debug_scsi("sg %d, len %u offset %u\n", i, sg->length,
+			   sg->offset);
+		if (offset < sg->length) {
+			iscsi_tcp_segment_init_sg(segment, sg, offset);
+			return 0;
 		}
-		tcp_conn->in.hdr = &tcp_conn->hdr;
-		tcp_conn->discontiguous_hdr_cnt++;
-	        tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+		offset -= sg->length;
 	}
 
+	return ISCSI_ERR_DATA_OFFSET;
+}
+
+/**
+ * iscsi_tcp_hdr_recv_prep - prep segment for hdr reception
+ * @tcp_conn: iscsi connection to prep for
+ *
+ * This function always passes NULL for the hash argument, because when this
+ * function is called we do not yet know the final size of the header and want
+ * to delay the digest processing until we know that.
+ */
+static void
+iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn)
+{
+	debug_tcp("iscsi_tcp_hdr_recv_prep(%p%s)\n", tcp_conn,
+		  tcp_conn->iscsi_conn->hdrdgst_en ? ", digest enabled" : "");
+	iscsi_segment_init_linear(&tcp_conn->in.segment,
+				tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr),
+				iscsi_tcp_hdr_recv_done, NULL);
+}
+
+/*
+ * Handle incoming reply to any other type of command
+ */
+static int
+iscsi_tcp_data_recv_done(struct iscsi_tcp_conn *tcp_conn,
+			 struct iscsi_segment *segment)
+{
+	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
+	int rc = 0;
+
+	if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
+		return ISCSI_ERR_DATA_DGST;
+
+	rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr,
+			conn->data, tcp_conn->in.datalen);
+	if (rc)
+		return rc;
+
+	iscsi_tcp_hdr_recv_prep(tcp_conn);
 	return 0;
 }
 
+static void
+iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
+{
+	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
+	struct hash_desc *rx_hash = NULL;
+
+	if (conn->datadgst_en)
+		rx_hash = &tcp_conn->rx_hash;
+
+	iscsi_segment_init_linear(&tcp_conn->in.segment,
+				conn->data, tcp_conn->in.datalen,
+				iscsi_tcp_data_recv_done, rx_hash);
+}
+
 /*
  * must be called with session lock
  */
@@ -184,7 +498,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 	struct iscsi_r2t_info *r2t;
-	struct scsi_cmnd *sc;
 
 	/* flush ctask's r2t queues */
 	while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
@@ -193,12 +506,12 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 		debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n");
 	}
 
-	sc = ctask->sc;
-	if (unlikely(!sc))
-		return;
-
-	tcp_ctask->xmstate = XMSTATE_VALUE_IDLE;
-	tcp_ctask->r2t = NULL;
+	r2t = tcp_ctask->r2t;
+	if (r2t != NULL) {
+		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+			    sizeof(void*));
+		tcp_ctask->r2t = NULL;
+	}
 }
 
 /**
@@ -217,11 +530,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 	int datasn = be32_to_cpu(rhdr->datasn);
 
 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
-	/*
-	 * setup Data-In byte counter (gets decremented..)
-	 */
-	ctask->data_count = tcp_conn->in.datalen;
-
 	if (tcp_conn->in.datalen == 0)
 		return 0;
 
@@ -242,22 +550,20 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 	}
 
 	if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
+		sc->result = (DID_OK << 16) | rhdr->cmd_status;
 		conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
-		if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
+		if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW |
+		                   ISCSI_FLAG_DATA_OVERFLOW)) {
 			int res_count = be32_to_cpu(rhdr->residual_count);
 
 			if (res_count > 0 &&
-			    res_count <= scsi_bufflen(sc)) {
+			    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+			     res_count <= scsi_bufflen(sc)))
 				scsi_set_resid(sc, res_count);
-				sc->result = (DID_OK << 16) | rhdr->cmd_status;
-			} else
+			else
 				sc->result = (DID_BAD_TARGET << 16) |
 					rhdr->cmd_status;
-		} else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) {
-			scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
-			sc->result = (DID_OK << 16) | rhdr->cmd_status;
-		} else
-			sc->result = (DID_OK << 16) | rhdr->cmd_status;
+		}
 	}
 
 	conn->datain_pdus_cnt++;
@@ -281,9 +587,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
 			struct iscsi_r2t_info *r2t)
 {
 	struct iscsi_data *hdr;
-	struct scsi_cmnd *sc = ctask->sc;
-	int i, sg_count = 0;
-	struct scatterlist *sg;
 
 	hdr = &r2t->dtask.hdr;
 	memset(hdr, 0, sizeof(struct iscsi_data));
@@ -307,34 +610,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
 	conn->dataout_pdus_cnt++;
 
 	r2t->sent = 0;
-
-	iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
-			   sizeof(struct iscsi_hdr));
-
-	sg = scsi_sglist(sc);
-	r2t->sg = NULL;
-	for (i = 0; i < scsi_sg_count(sc); i++, sg += 1) {
-		/* FIXME: prefetch ? */
-		if (sg_count + sg->length > r2t->data_offset) {
-			int page_offset;
-
-			/* sg page found! */
-
-			/* offset within this page */
-			page_offset = r2t->data_offset - sg_count;
-
-			/* fill in this buffer */
-			iscsi_buf_init_sg(&r2t->sendbuf, sg);
-			r2t->sendbuf.sg.offset += page_offset;
-			r2t->sendbuf.sg.length -= page_offset;
-
-			/* xmit logic will continue with next one */
-			r2t->sg = sg + 1;
-			break;
-		}
-		sg_count += sg->length;
-	}
-	BUG_ON(r2t->sg == NULL);
 }
 
 /**
@@ -366,14 +641,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 	}
 
 	/* fill-in new R2T associated with the task */
-	spin_lock(&session->lock);
 	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
 
-	if (!ctask->sc || ctask->mtask ||
-	     session->state != ISCSI_STATE_LOGGED_IN) {
+	if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) {
 		printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in "
 		       "recovery...\n", ctask->itt);
-		spin_unlock(&session->lock);
 		return 0;
 	}
 
@@ -384,7 +656,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 	r2t->data_length = be32_to_cpu(rhdr->data_length);
 	if (r2t->data_length == 0) {
 		printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n");
-		spin_unlock(&session->lock);
+		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+			    sizeof(void*));
 		return ISCSI_ERR_DATALEN;
 	}
 
@@ -395,10 +668,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 
 	r2t->data_offset = be32_to_cpu(rhdr->data_offset);
 	if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
-		spin_unlock(&session->lock);
 		printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
 		       "offset %u and total length %d\n", r2t->data_length,
 		       r2t->data_offset, scsi_bufflen(ctask->sc));
+		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+			    sizeof(void*));
 		return ISCSI_ERR_DATALEN;
 	}
 
@@ -409,26 +683,55 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 
 	tcp_ctask->exp_datasn = r2tsn + 1;
 	__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
-	set_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
-	list_move_tail(&ctask->running, &conn->xmitqueue);
-
-	scsi_queue_work(session->host, &conn->xmitwork);
 	conn->r2t_pdus_cnt++;
-	spin_unlock(&session->lock);
 
+	iscsi_requeue_ctask(ctask);
 	return 0;
 }
 
+/*
+ * Handle incoming reply to DataIn command
+ */
 static int
-iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
+iscsi_tcp_process_data_in(struct iscsi_tcp_conn *tcp_conn,
+			  struct iscsi_segment *segment)
+{
+	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
+	struct iscsi_hdr *hdr = tcp_conn->in.hdr;
+	int rc;
+
+	if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
+		return ISCSI_ERR_DATA_DGST;
+
+	/* check for non-exceptional status */
+	if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+		rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
+		if (rc)
+			return rc;
+	}
+
+	iscsi_tcp_hdr_recv_prep(tcp_conn);
+	return 0;
+}
+
+/**
+ * iscsi_tcp_hdr_dissect - process PDU header
+ * @conn: iSCSI connection
+ * @hdr: PDU header
+ *
+ * This function analyzes the header of the PDU received,
+ * and performs several sanity checks. If the PDU is accompanied
+ * by data, the receive buffer is set up to copy the incoming data
+ * to the correct location.
+ */
+static int
+iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 {
 	int rc = 0, opcode, ahslen;
-	struct iscsi_hdr *hdr;
 	struct iscsi_session *session = conn->session;
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-	uint32_t cdgst, rdgst = 0, itt;
-
-	hdr = tcp_conn->in.hdr;
+	struct iscsi_cmd_task *ctask;
+	uint32_t itt;
 
 	/* verify PDU length */
 	tcp_conn->in.datalen = ntoh24(hdr->dlength);
@@ -437,78 +740,73 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
 		       tcp_conn->in.datalen, conn->max_recv_dlength);
 		return ISCSI_ERR_DATALEN;
 	}
-	tcp_conn->data_copied = 0;
 
-	/* read AHS */
+	/* Additional header segments. So far, we don't
+	 * process additional headers.
+	 */
 	ahslen = hdr->hlength << 2;
-	tcp_conn->in.offset += ahslen;
-	tcp_conn->in.copy -= ahslen;
-	if (tcp_conn->in.copy < 0) {
-		printk(KERN_ERR "iscsi_tcp: can't handle AHS with length "
-		       "%d bytes\n", ahslen);
-		return ISCSI_ERR_AHSLEN;
-	}
-
-	/* calculate read padding */
-	tcp_conn->in.padding = tcp_conn->in.datalen & (ISCSI_PAD_LEN-1);
-	if (tcp_conn->in.padding) {
-		tcp_conn->in.padding = ISCSI_PAD_LEN - tcp_conn->in.padding;
-		debug_scsi("read padding %d bytes\n", tcp_conn->in.padding);
-	}
-
-	if (conn->hdrdgst_en) {
-		struct scatterlist sg;
-
-		sg_init_one(&sg, (u8 *)hdr,
-			    sizeof(struct iscsi_hdr) + ahslen);
-		crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length,
-				   (u8 *)&cdgst);
-		rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
-				     ahslen);
-		if (cdgst != rdgst) {
-			printk(KERN_ERR "iscsi_tcp: hdrdgst error "
-			       "recv 0x%x calc 0x%x\n", rdgst, cdgst);
-			return ISCSI_ERR_HDR_DGST;
-		}
-	}
 
 	opcode = hdr->opcode & ISCSI_OPCODE_MASK;
 	/* verify itt (itt encoding: age+cid+itt) */
 	rc = iscsi_verify_itt(conn, hdr, &itt);
-	if (rc == ISCSI_ERR_NO_SCSI_CMD) {
-		tcp_conn->in.datalen = 0; /* force drop */
-		return 0;
-	} else if (rc)
+	if (rc)
 		return rc;
 
-	debug_tcp("opcode 0x%x offset %d copy %d ahslen %d datalen %d\n",
-		  opcode, tcp_conn->in.offset, tcp_conn->in.copy,
-		  ahslen, tcp_conn->in.datalen);
+	debug_tcp("opcode 0x%x ahslen %d datalen %d\n",
+		  opcode, ahslen, tcp_conn->in.datalen);
 
 	switch(opcode) {
 	case ISCSI_OP_SCSI_DATA_IN:
-		tcp_conn->in.ctask = session->cmds[itt];
-		rc = iscsi_data_rsp(conn, tcp_conn->in.ctask);
+		ctask = session->cmds[itt];
+		spin_lock(&conn->session->lock);
+		rc = iscsi_data_rsp(conn, ctask);
+		spin_unlock(&conn->session->lock);
 		if (rc)
 			return rc;
+		if (tcp_conn->in.datalen) {
+			struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+			struct hash_desc *rx_hash = NULL;
+
+			/*
+			 * Setup copy of Data-In into the Scsi_Cmnd
+			 * Scatterlist case:
+			 * We set up the iscsi_segment to point to the next
+			 * scatterlist entry to copy to. As we go along,
+			 * we move on to the next scatterlist entry and
+			 * update the digest per-entry.
+			 */
+			if (conn->datadgst_en)
+				rx_hash = &tcp_conn->rx_hash;
+
+			debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, "
+				  "datalen=%d)\n", tcp_conn,
+				  tcp_ctask->data_offset,
+				  tcp_conn->in.datalen);
+			return iscsi_segment_seek_sg(&tcp_conn->in.segment,
+						     scsi_sglist(ctask->sc),
+						     scsi_sg_count(ctask->sc),
+						     tcp_ctask->data_offset,
+						     tcp_conn->in.datalen,
+						     iscsi_tcp_process_data_in,
+						     rx_hash);
+		}
 		/* fall through */
 	case ISCSI_OP_SCSI_CMD_RSP:
-		tcp_conn->in.ctask = session->cmds[itt];
-		if (tcp_conn->in.datalen)
-			goto copy_hdr;
-
-		spin_lock(&session->lock);
-		rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
-		spin_unlock(&session->lock);
+		if (tcp_conn->in.datalen) {
+			iscsi_tcp_data_recv_prep(tcp_conn);
+			return 0;
+		}
+		rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
 		break;
 	case ISCSI_OP_R2T:
-		tcp_conn->in.ctask = session->cmds[itt];
+		ctask = session->cmds[itt];
 		if (ahslen)
 			rc = ISCSI_ERR_AHSLEN;
-		else if (tcp_conn->in.ctask->sc->sc_data_direction ==
-								DMA_TO_DEVICE)
-			rc = iscsi_r2t_rsp(conn, tcp_conn->in.ctask);
-		else
+		else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) {
+			spin_lock(&session->lock);
+			rc = iscsi_r2t_rsp(conn, ctask);
+			spin_unlock(&session->lock);
+		} else
 			rc = ISCSI_ERR_PROTO;
 		break;
 	case ISCSI_OP_LOGIN_RSP:
@@ -520,8 +818,7 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
 		 * than 8K, but there are no targets that currently do this.
 		 * For now we fail until we find a vendor that needs it
 		 */
-		if (ISCSI_DEF_MAX_RECV_SEG_LEN <
-		    tcp_conn->in.datalen) {
+		if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) {
 			printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
 			      "but conn buffer is only %u (opcode %0x)\n",
 			      tcp_conn->in.datalen,
@@ -530,8 +827,13 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
 			break;
 		}
 
-		if (tcp_conn->in.datalen)
-			goto copy_hdr;
+		/* If there's data coming in with the response,
+		 * receive it to the connection's buffer.
+		 */
+		if (tcp_conn->in.datalen) {
+			iscsi_tcp_data_recv_prep(tcp_conn);
+			return 0;
+		}
 	/* fall through */
 	case ISCSI_OP_LOGOUT_RSP:
 	case ISCSI_OP_NOOP_IN:
@@ -543,461 +845,161 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
 		break;
 	}
 
-	return rc;
-
-copy_hdr:
-	/*
-	 * if we did zero copy for the header but we will need multiple
-	 * skbs to complete the command then we have to copy the header
-	 * for later use
-	 */
-	if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <=
-	   (tcp_conn->in.datalen + tcp_conn->in.padding +
-	    (conn->datadgst_en ? 4 : 0))) {
-		debug_tcp("Copying header for later use. in.copy %d in.datalen"
-			  " %d\n", tcp_conn->in.copy, tcp_conn->in.datalen);
-		memcpy(&tcp_conn->hdr, tcp_conn->in.hdr,
-		       sizeof(struct iscsi_hdr));
-		tcp_conn->in.hdr = &tcp_conn->hdr;
-		tcp_conn->in.zero_copy_hdr = 0;
-	}
-	return 0;
-}
-
-/**
- * iscsi_ctask_copy - copy skb bits to the destanation cmd task
- * @conn: iscsi tcp connection
- * @ctask: scsi command task
- * @buf: buffer to copy to
- * @buf_size: size of buffer
- * @offset: offset within the buffer
- *
- * Notes:
- *	The function calls skb_copy_bits() and updates per-connection and
- *	per-cmd byte counters.
- *
- *	Read counters (in bytes):
- *
- *	conn->in.offset		offset within in progress SKB
- *	conn->in.copy		left to copy from in progress SKB
- *				including padding
- *	conn->in.copied		copied already from in progress SKB
- *	conn->data_copied	copied already from in progress buffer
- *	ctask->sent		total bytes sent up to the MidLayer
- *	ctask->data_count	left to copy from in progress Data-In
- *	buf_left		left to copy from in progress buffer
- **/
-static inline int
-iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask,
-		void *buf, int buf_size, int offset)
-{
-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-	int buf_left = buf_size - (tcp_conn->data_copied + offset);
-	unsigned size = min(tcp_conn->in.copy, buf_left);
-	int rc;
-
-	size = min(size, ctask->data_count);
-
-	debug_tcp("ctask_copy %d bytes at offset %d copied %d\n",
-	       size, tcp_conn->in.offset, tcp_conn->in.copied);
-
-	BUG_ON(size <= 0);
-	BUG_ON(tcp_ctask->sent + size > scsi_bufflen(ctask->sc));
-
-	rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
-			   (char*)buf + (offset + tcp_conn->data_copied), size);
-	/* must fit into skb->len */
-	BUG_ON(rc);
-
-	tcp_conn->in.offset += size;
-	tcp_conn->in.copy -= size;
-	tcp_conn->in.copied += size;
-	tcp_conn->data_copied += size;
-	tcp_ctask->sent += size;
-	ctask->data_count -= size;
-
-	BUG_ON(tcp_conn->in.copy < 0);
-	BUG_ON(ctask->data_count < 0);
-
-	if (buf_size != (tcp_conn->data_copied + offset)) {
-		if (!ctask->data_count) {
-			BUG_ON(buf_size - tcp_conn->data_copied < 0);
-			/* done with this PDU */
-			return buf_size - tcp_conn->data_copied;
-		}
-		return -EAGAIN;
+	if (rc == 0) {
+		/* Anything that comes with data should have
+		 * been handled above. */
+		if (tcp_conn->in.datalen)
+			return ISCSI_ERR_PROTO;
+		iscsi_tcp_hdr_recv_prep(tcp_conn);
 	}
 
-	/* done with this buffer or with both - PDU and buffer */
-	tcp_conn->data_copied = 0;
-	return 0;
+	return rc;
 }
 
 /**
- * iscsi_tcp_copy - copy skb bits to the destanation buffer
- * @conn: iscsi tcp connection
+ * iscsi_tcp_hdr_recv_done - process PDU header
  *
- * Notes:
- *	The function calls skb_copy_bits() and updates per-connection
- *	byte counters.
- **/
-static inline int
-iscsi_tcp_copy(struct iscsi_conn *conn, int buf_size)
-{
-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-	int buf_left = buf_size - tcp_conn->data_copied;
-	int size = min(tcp_conn->in.copy, buf_left);
-	int rc;
-
-	debug_tcp("tcp_copy %d bytes at offset %d copied %d\n",
-	       size, tcp_conn->in.offset, tcp_conn->data_copied);
-	BUG_ON(size <= 0);
-
-	rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
-			   (char*)conn->data + tcp_conn->data_copied, size);
-	BUG_ON(rc);
-
-	tcp_conn->in.offset += size;
-	tcp_conn->in.copy -= size;
-	tcp_conn->in.copied += size;
-	tcp_conn->data_copied += size;
-
-	if (buf_size != tcp_conn->data_copied)
-		return -EAGAIN;
-
-	return 0;
-}
-
-static inline void
-partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg,
-			 int offset, int length)
-{
-	struct scatterlist temp;
-
-	sg_init_table(&temp, 1);
-	sg_set_page(&temp, sg_page(sg), length, offset);
-	crypto_hash_update(desc, &temp, length);
-}
-
-static void
-iscsi_recv_digest_update(struct iscsi_tcp_conn *tcp_conn, char* buf, int len)
-{
-	struct scatterlist tmp;
-
-	sg_init_one(&tmp, buf, len);
-	crypto_hash_update(&tcp_conn->rx_hash, &tmp, len);
-}
-
-static int iscsi_scsi_data_in(struct iscsi_conn *conn)
+ * This is the callback invoked when the PDU header has
+ * been received. If the header is followed by additional
+ * header segments, we go back for more data.
+ */
+static int
+iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
+			struct iscsi_segment *segment)
 {
-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-	struct iscsi_cmd_task *ctask = tcp_conn->in.ctask;
-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-	struct scsi_cmnd *sc = ctask->sc;
-	struct scatterlist *sg;
-	int i, offset, rc = 0;
-
-	BUG_ON((void*)ctask != sc->SCp.ptr);
-
-	offset = tcp_ctask->data_offset;
-	sg = scsi_sglist(sc);
-
-	if (tcp_ctask->data_offset)
-		for (i = 0; i < tcp_ctask->sg_count; i++)
-			offset -= sg[i].length;
-	/* we've passed through partial sg*/
-	if (offset < 0)
-		offset = 0;
-
-	for (i = tcp_ctask->sg_count; i < scsi_sg_count(sc); i++) {
-		char *dest;
-
-		dest = kmap_atomic(sg_page(&sg[i]), KM_SOFTIRQ0);
-		rc = iscsi_ctask_copy(tcp_conn, ctask, dest + sg[i].offset,
-				      sg[i].length, offset);
-		kunmap_atomic(dest, KM_SOFTIRQ0);
-		if (rc == -EAGAIN)
-			/* continue with the next SKB/PDU */
-			return rc;
-		if (!rc) {
-			if (conn->datadgst_en) {
-				if (!offset)
-					crypto_hash_update(
-							&tcp_conn->rx_hash,
-							&sg[i], sg[i].length);
-				else
-					partial_sg_digest_update(
-							&tcp_conn->rx_hash,
-							&sg[i],
-							sg[i].offset + offset,
-							sg[i].length - offset);
-			}
-			offset = 0;
-			tcp_ctask->sg_count++;
-		}
-
-		if (!ctask->data_count) {
-			if (rc && conn->datadgst_en)
-				/*
-				 * data-in is complete, but buffer not...
-				 */
-				partial_sg_digest_update(&tcp_conn->rx_hash,
-							 &sg[i],
-							 sg[i].offset,
-							 sg[i].length-rc);
-			rc = 0;
-			break;
-		}
-
-		if (!tcp_conn->in.copy)
-			return -EAGAIN;
-	}
-	BUG_ON(ctask->data_count);
+	struct iscsi_conn *conn = tcp_conn->iscsi_conn;
+	struct iscsi_hdr *hdr;
 
-	/* check for non-exceptional status */
-	if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) {
-		debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n",
-			   (long)sc, sc->result, ctask->itt,
-			   tcp_conn->in.hdr->flags);
-		spin_lock(&conn->session->lock);
-		__iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
-		spin_unlock(&conn->session->lock);
+	/* Check if there are additional header segments
+	 * *prior* to computing the digest, because we
+	 * may need to go back to the caller for more.
+	 */
+	hdr = (struct iscsi_hdr *) tcp_conn->in.hdr_buf;
+	if (segment->copied == sizeof(struct iscsi_hdr) && hdr->hlength) {
+		/* Bump the header length - the caller will
+		 * just loop around and get the AHS for us, and
+		 * call again. */
+		unsigned int ahslen = hdr->hlength << 2;
+
+		/* Make sure we don't overflow */
+		if (sizeof(*hdr) + ahslen > sizeof(tcp_conn->in.hdr_buf))
+			return ISCSI_ERR_AHSLEN;
+
+		segment->total_size += ahslen;
+		segment->size += ahslen;
+		return 0;
 	}
 
-	return rc;
-}
-
-static int
-iscsi_data_recv(struct iscsi_conn *conn)
-{
-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-	int rc = 0, opcode;
-
-	opcode = tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK;
-	switch (opcode) {
-	case ISCSI_OP_SCSI_DATA_IN:
-		rc = iscsi_scsi_data_in(conn);
-		break;
-	case ISCSI_OP_SCSI_CMD_RSP:
-	case ISCSI_OP_TEXT_RSP:
-	case ISCSI_OP_LOGIN_RSP:
-	case ISCSI_OP_ASYNC_EVENT:
-	case ISCSI_OP_REJECT:
-		/*
-		 * Collect data segment to the connection's data
-		 * placeholder
-		 */
-		if (iscsi_tcp_copy(conn, tcp_conn->in.datalen)) {
-			rc = -EAGAIN;
-			goto exit;
+	/* We're done processing the header. See if we're doing
+	 * header digests; if so, set up the recv_digest buffer
+	 * and go back for more. */
+	if (conn->hdrdgst_en) {
+		if (segment->digest_len == 0) {
+			iscsi_tcp_segment_splice_digest(segment,
+							segment->recv_digest);
+			return 0;
 		}
+		iscsi_tcp_dgst_header(&tcp_conn->rx_hash, hdr,
+				      segment->total_copied - ISCSI_DIGEST_SIZE,
+				      segment->digest);
 
-		rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, conn->data,
-					tcp_conn->in.datalen);
-		if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP)
-			iscsi_recv_digest_update(tcp_conn, conn->data,
-			  			tcp_conn->in.datalen);
-		break;
-	default:
-		BUG_ON(1);
+		if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
+			return ISCSI_ERR_HDR_DGST;
 	}
-exit:
-	return rc;
+
+	tcp_conn->in.hdr = hdr;
+	return iscsi_tcp_hdr_dissect(conn, hdr);
 }
 
 /**
- * iscsi_tcp_data_recv - TCP receive in sendfile fashion
+ * iscsi_tcp_recv - TCP receive in sendfile fashion
  * @rd_desc: read descriptor
  * @skb: socket buffer
  * @offset: offset in skb
  * @len: skb->len - offset
  **/
 static int
-iscsi_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
-		unsigned int offset, size_t len)
+iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
+	       unsigned int offset, size_t len)
 {
-	int rc;
 	struct iscsi_conn *conn = rd_desc->arg.data;
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-	int processed;
-	char pad[ISCSI_PAD_LEN];
-	struct scatterlist sg;
-
-	/*
-	 * Save current SKB and its offset in the corresponding
-	 * connection context.
-	 */
-	tcp_conn->in.copy = skb->len - offset;
-	tcp_conn->in.offset = offset;
-	tcp_conn->in.skb = skb;
-	tcp_conn->in.len = tcp_conn->in.copy;
-	BUG_ON(tcp_conn->in.copy <= 0);
-	debug_tcp("in %d bytes\n", tcp_conn->in.copy);
+	struct iscsi_segment *segment = &tcp_conn->in.segment;
+	struct skb_seq_state seq;
+	unsigned int consumed = 0;
+	int rc = 0;
 
-more:
-	tcp_conn->in.copied = 0;
-	rc = 0;
+	debug_tcp("in %d bytes\n", skb->len - offset);
 
 	if (unlikely(conn->suspend_rx)) {
 		debug_tcp("conn %d Rx suspended!\n", conn->id);
 		return 0;
 	}
 
-	if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER ||
-	    tcp_conn->in_progress == IN_PROGRESS_HEADER_GATHER) {
-		rc = iscsi_hdr_extract(tcp_conn);
-		if (rc) {
-		       if (rc == -EAGAIN)
-				goto nomore;
-		       else {
-				iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-				return 0;
-		       }
-		}
+	skb_prepare_seq_read(skb, offset, skb->len, &seq);
+	while (1) {
+		unsigned int avail;
+		const u8 *ptr;
 
-		/*
-		 * Verify and process incoming PDU header.
-		 */
-		rc = iscsi_tcp_hdr_recv(conn);
-		if (!rc && tcp_conn->in.datalen) {
-			if (conn->datadgst_en)
-				crypto_hash_init(&tcp_conn->rx_hash);
-			tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
-		} else if (rc) {
-			iscsi_conn_failure(conn, rc);
-			return 0;
+		avail = skb_seq_read(consumed, &ptr, &seq);
+		if (avail == 0) {
+			debug_tcp("no more data avail. Consumed %d\n",
+				  consumed);
+			break;
 		}
-	}
-
-	if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV &&
-	    tcp_conn->in.copy) {
-		uint32_t recv_digest;
-
-		debug_tcp("extra data_recv offset %d copy %d\n",
-			  tcp_conn->in.offset, tcp_conn->in.copy);
-
-		if (!tcp_conn->data_copied) {
-			if (tcp_conn->in.padding) {
-				debug_tcp("padding -> %d\n",
-					  tcp_conn->in.padding);
-				memset(pad, 0, tcp_conn->in.padding);
-				sg_init_one(&sg, pad, tcp_conn->in.padding);
-				crypto_hash_update(&tcp_conn->rx_hash,
-						   &sg, sg.length);
+		BUG_ON(segment->copied >= segment->size);
+
+		debug_tcp("skb %p ptr=%p avail=%u\n", skb, ptr, avail);
+		rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail);
+		BUG_ON(rc == 0);
+		consumed += rc;
+
+		if (segment->total_copied >= segment->total_size) {
+			debug_tcp("segment done\n");
+			rc = segment->done(tcp_conn, segment);
+			if (rc != 0) {
+				skb_abort_seq_read(&seq);
+				goto error;
 			}
-			crypto_hash_final(&tcp_conn->rx_hash,
-					  (u8 *) &tcp_conn->in.datadgst);
-			debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
-		}
 
-		rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
-		if (rc) {
-			if (rc == -EAGAIN)
-				goto again;
-			iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-			return 0;
-		}
-
-		memcpy(&recv_digest, conn->data, sizeof(uint32_t));
-		if (recv_digest != tcp_conn->in.datadgst) {
-			debug_tcp("iscsi_tcp: data digest error!"
-				  "0x%x != 0x%x\n", recv_digest,
-				  tcp_conn->in.datadgst);
-			iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST);
-			return 0;
-		} else {
-			debug_tcp("iscsi_tcp: data digest match!"
-				  "0x%x == 0x%x\n", recv_digest,
-				  tcp_conn->in.datadgst);
-			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+			/* The done() functions sets up the
+			 * next segment. */
 		}
 	}
+	skb_abort_seq_read(&seq);
+	conn->rxdata_octets += consumed;
+	return consumed;
 
-	if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV &&
-	    tcp_conn->in.copy) {
-		debug_tcp("data_recv offset %d copy %d\n",
-		       tcp_conn->in.offset, tcp_conn->in.copy);
-
-		rc = iscsi_data_recv(conn);
-		if (rc) {
-			if (rc == -EAGAIN)
-				goto again;
-			iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-			return 0;
-		}
-
-		if (tcp_conn->in.padding)
-			tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
-		else if (conn->datadgst_en)
-			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
-		else
-			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-		tcp_conn->data_copied = 0;
-	}
-
-	if (tcp_conn->in_progress == IN_PROGRESS_PAD_RECV &&
-	    tcp_conn->in.copy) {
-		int copylen = min(tcp_conn->in.padding - tcp_conn->data_copied,
-				  tcp_conn->in.copy);
-
-		tcp_conn->in.copy -= copylen;
-		tcp_conn->in.offset += copylen;
-		tcp_conn->data_copied += copylen;
-
-		if (tcp_conn->data_copied != tcp_conn->in.padding)
-			tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
-		else if (conn->datadgst_en)
-			tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
-		else
-			tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-		tcp_conn->data_copied = 0;
-	}
-
-	debug_tcp("f, processed %d from out of %d padding %d\n",
-	       tcp_conn->in.offset - offset, (int)len, tcp_conn->in.padding);
-	BUG_ON(tcp_conn->in.offset - offset > len);
-
-	if (tcp_conn->in.offset - offset != len) {
-		debug_tcp("continue to process %d bytes\n",
-		       (int)len - (tcp_conn->in.offset - offset));
-		goto more;
-	}
-
-nomore:
-	processed = tcp_conn->in.offset - offset;
-	BUG_ON(processed == 0);
-	return processed;
-
-again:
-	processed = tcp_conn->in.offset - offset;
-	debug_tcp("c, processed %d from out of %d rd_desc_cnt %d\n",
-	          processed, (int)len, (int)rd_desc->count);
-	BUG_ON(processed == 0);
-	BUG_ON(processed > len);
-
-	conn->rxdata_octets += processed;
-	return processed;
+error:
+	debug_tcp("Error receiving PDU, errno=%d\n", rc);
+	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+	return 0;
 }
 
 static void
 iscsi_tcp_data_ready(struct sock *sk, int flag)
 {
 	struct iscsi_conn *conn = sk->sk_user_data;
+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 	read_descriptor_t rd_desc;
 
 	read_lock(&sk->sk_callback_lock);
 
 	/*
-	 * Use rd_desc to pass 'conn' to iscsi_tcp_data_recv.
+	 * Use rd_desc to pass 'conn' to iscsi_tcp_recv.
 	 * We set count to 1 because we want the network layer to
-	 * hand us all the skbs that are available. iscsi_tcp_data_recv
+	 * hand us all the skbs that are available. iscsi_tcp_recv
 	 * handled pdus that cross buffers or pdus that still need data.
 	 */
 	rd_desc.arg.data = conn;
 	rd_desc.count = 1;
-	tcp_read_sock(sk, &rd_desc, iscsi_tcp_data_recv);
+	tcp_read_sock(sk, &rd_desc, iscsi_tcp_recv);
 
 	read_unlock(&sk->sk_callback_lock);
+
+	/* If we had to (atomically) map a highmem page,
+	 * unmap it now. */
+	iscsi_tcp_segment_unmap(&tcp_conn->in.segment);
 }
 
 static void
@@ -1077,121 +1079,173 @@ iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn)
 }
 
 /**
- * iscsi_send - generic send routine
- * @sk: kernel's socket
- * @buf: buffer to write from
- * @size: actual size to write
- * @flags: socket's flags
- */
-static inline int
-iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
+ * iscsi_xmit - TCP transmit
+ **/
+static int
+iscsi_xmit(struct iscsi_conn *conn)
 {
 	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-	struct socket *sk = tcp_conn->sock;
-	int offset = buf->sg.offset + buf->sent, res;
+	struct iscsi_segment *segment = &tcp_conn->out.segment;
+	unsigned int consumed = 0;
+	int rc = 0;
 
-	/*
-	 * if we got use_sg=0 or are sending something we kmallocd
-	 * then we did not have to do kmap (kmap returns page_address)
-	 *
-	 * if we got use_sg > 0, but had to drop down, we do not
-	 * set clustering so this should only happen for that
-	 * slab case.
-	 */
-	if (buf->use_sendmsg)
-		res = sock_no_sendpage(sk, sg_page(&buf->sg), offset, size, flags);
-	else
-		res = tcp_conn->sendpage(sk, sg_page(&buf->sg), offset, size, flags);
-
-	if (res >= 0) {
-		conn->txdata_octets += res;
-		buf->sent += res;
-		return res;
+	while (1) {
+		rc = iscsi_tcp_xmit_segment(tcp_conn, segment);
+		if (rc < 0)
+			goto error;
+		if (rc == 0)
+			break;
+
+		consumed += rc;
+
+		if (segment->total_copied >= segment->total_size) {
+			if (segment->done != NULL) {
+				rc = segment->done(tcp_conn, segment);
+				if (rc < 0)
+					goto error;
+			}
+		}
 	}
 
-	tcp_conn->sendpage_failures_cnt++;
-	if (res == -EAGAIN)
-		res = -ENOBUFS;
-	else
-		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-	return res;
+	debug_tcp("xmit %d bytes\n", consumed);
+
+	conn->txdata_octets += consumed;
+	return consumed;
+
+error:
+	/* Transmit error. We could initiate error recovery
+	 * here. */
+	debug_tcp("Error sending PDU, errno=%d\n", rc);
+	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+	return rc;
 }
 
 /**
- * iscsi_sendhdr - send PDU Header via tcp_sendpage()
- * @conn: iscsi connection
- * @buf: buffer to write from
- * @datalen: lenght of data to be sent after the header
- *
- * Notes:
- *	(Tx, Fast Path)
- **/
+ * iscsi_tcp_xmit_qlen - return the number of bytes queued for xmit
+ */
 static inline int
-iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen)
+iscsi_tcp_xmit_qlen(struct iscsi_conn *conn)
 {
-	int flags = 0; /* MSG_DONTWAIT; */
-	int res, size;
-
-	size = buf->sg.length - buf->sent;
-	BUG_ON(buf->sent + size > buf->sg.length);
-	if (buf->sent + size != buf->sg.length || datalen)
-		flags |= MSG_MORE;
-
-	res = iscsi_send(conn, buf, size, flags);
-	debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res);
-	if (res >= 0) {
-		if (size != res)
-			return -EAGAIN;
-		return 0;
-	}
+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+	struct iscsi_segment *segment = &tcp_conn->out.segment;
 
-	return res;
+	return segment->total_copied - segment->total_size;
 }
 
-/**
- * iscsi_sendpage - send one page of iSCSI Data-Out.
- * @conn: iscsi connection
- * @buf: buffer to write from
- * @count: remaining data
- * @sent: number of bytes sent
- *
- * Notes:
- *	(Tx, Fast Path)
- **/
 static inline int
-iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
-	       int *count, int *sent)
+iscsi_tcp_flush(struct iscsi_conn *conn)
 {
-	int flags = 0; /* MSG_DONTWAIT; */
-	int res, size;
-
-	size = buf->sg.length - buf->sent;
-	BUG_ON(buf->sent + size > buf->sg.length);
-	if (size > *count)
-		size = *count;
-	if (buf->sent + size != buf->sg.length || *count != size)
-		flags |= MSG_MORE;
-
-	res = iscsi_send(conn, buf, size, flags);
-	debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n",
-		  size, buf->sent, *count, *sent, res);
-	if (res >= 0) {
-		*count -= res;
-		*sent += res;
-		if (size != res)
+	int rc;
+
+	while (iscsi_tcp_xmit_qlen(conn)) {
+		rc = iscsi_xmit(conn);
+		if (rc == 0)
 			return -EAGAIN;
-		return 0;
+		if (rc < 0)
+			return rc;
 	}
 
-	return res;
+	return 0;
 }
 
-static inline void
-iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
-		      struct iscsi_tcp_cmd_task *tcp_ctask)
+/*
+ * This is called when we're done sending the header.
+ * Simply copy the data_segment to the send segment, and return.
+ */
+static int
+iscsi_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn,
+			struct iscsi_segment *segment)
+{
+	tcp_conn->out.segment = tcp_conn->out.data_segment;
+	debug_tcp("Header done. Next segment size %u total_size %u\n",
+		  tcp_conn->out.segment.size, tcp_conn->out.segment.total_size);
+	return 0;
+}
+
+static void
+iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen)
 {
-	crypto_hash_init(&tcp_conn->tx_hash);
-	tcp_ctask->digest_count = 4;
+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+
+	debug_tcp("%s(%p%s)\n", __FUNCTION__, tcp_conn,
+			conn->hdrdgst_en? ", digest enabled" : "");
+
+	/* Clear the data segment - needs to be filled in by the
+	 * caller using iscsi_tcp_send_data_prep() */
+	memset(&tcp_conn->out.data_segment, 0, sizeof(struct iscsi_segment));
+
+	/* If header digest is enabled, compute the CRC and
+	 * place the digest into the same buffer. We make
+	 * sure that both iscsi_tcp_ctask and mtask have
+	 * sufficient room.
+	 */
+	if (conn->hdrdgst_en) {
+		iscsi_tcp_dgst_header(&tcp_conn->tx_hash, hdr, hdrlen,
+				      hdr + hdrlen);
+		hdrlen += ISCSI_DIGEST_SIZE;
+	}
+
+	/* Remember header pointer for later, when we need
+	 * to decide whether there's a payload to go along
+	 * with the header. */
+	tcp_conn->out.hdr = hdr;
+
+	iscsi_segment_init_linear(&tcp_conn->out.segment, hdr, hdrlen,
+				iscsi_tcp_send_hdr_done, NULL);
+}
+
+/*
+ * Prepare the send buffer for the payload data.
+ * Padding and checksumming will all be taken care
+ * of by the iscsi_segment routines.
+ */
+static int
+iscsi_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg,
+			 unsigned int count, unsigned int offset,
+			 unsigned int len)
+{
+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+	struct hash_desc *tx_hash = NULL;
+	unsigned int hdr_spec_len;
+
+	debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __FUNCTION__,
+			tcp_conn, offset, len,
+			conn->datadgst_en? ", digest enabled" : "");
+
+	/* Make sure the datalen matches what the caller
+	   said he would send. */
+	hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength);
+	WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
+
+	if (conn->datadgst_en)
+		tx_hash = &tcp_conn->tx_hash;
+
+	return iscsi_segment_seek_sg(&tcp_conn->out.data_segment,
+				   sg, count, offset, len,
+				   NULL, tx_hash);
+}
+
+static void
+iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data,
+				   size_t len)
+{
+	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+	struct hash_desc *tx_hash = NULL;
+	unsigned int hdr_spec_len;
+
+	debug_tcp("%s(%p, datalen=%d%s)\n", __FUNCTION__, tcp_conn, len,
+		  conn->datadgst_en? ", digest enabled" : "");
+
+	/* Make sure the datalen matches what the caller
+	   said he would send. */
+	hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength);
+	WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len));
+
+	if (conn->datadgst_en)
+		tx_hash = &tcp_conn->tx_hash;
+
+	iscsi_segment_init_linear(&tcp_conn->out.data_segment,
+				data, len, NULL, tx_hash);
 }
 
 /**
@@ -1207,12 +1261,17 @@ iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
  *
  *	Called under connection lock.
  **/
-static void
+static int
 iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
-			struct iscsi_r2t_info *r2t, int left)
+			struct iscsi_r2t_info *r2t)
 {
 	struct iscsi_data *hdr;
-	int new_offset;
+	int new_offset, left;
+
+	BUG_ON(r2t->data_length - r2t->sent < 0);
+	left = r2t->data_length - r2t->sent;
+	if (left == 0)
+		return 0;
 
 	hdr = &r2t->dtask.hdr;
 	memset(hdr, 0, sizeof(struct iscsi_data));
@@ -1233,43 +1292,46 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
 		r2t->data_count = left;
 		hdr->flags = ISCSI_FLAG_CMD_FINAL;
 	}
-	conn->dataout_pdus_cnt++;
-
-	iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
-			   sizeof(struct iscsi_hdr));
-
-	if (iscsi_buf_left(&r2t->sendbuf))
-		return;
-
-	iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
-	r2t->sg += 1;
-}
 
-static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
-			      unsigned long len)
-{
-	tcp_ctask->pad_count = len & (ISCSI_PAD_LEN - 1);
-	if (!tcp_ctask->pad_count)
-		return;
-
-	tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count;
-	debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count);
-	set_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
+	conn->dataout_pdus_cnt++;
+	return 1;
 }
 
 /**
- * iscsi_tcp_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
+ * iscsi_tcp_ctask - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
  * @conn: iscsi connection
  * @ctask: scsi command task
  * @sc: scsi command
  **/
-static void
-iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
+static int
+iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask)
 {
 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+	struct iscsi_conn *conn = ctask->conn;
+	struct scsi_cmnd *sc = ctask->sc;
+	int err;
 
 	BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));
-	tcp_ctask->xmstate = 1 << XMSTATE_BIT_CMD_HDR_INIT;
+	tcp_ctask->sent = 0;
+	tcp_ctask->exp_datasn = 0;
+
+	/* Prepare PDU, optionally w/ immediate data */
+	debug_scsi("ctask deq [cid %d itt 0x%x imm %d unsol %d]\n",
+		    conn->id, ctask->itt, ctask->imm_count,
+		    ctask->unsol_count);
+	iscsi_tcp_send_hdr_prep(conn, ctask->hdr, ctask->hdr_len);
+
+	if (!ctask->imm_count)
+		return 0;
+
+	/* If we have immediate data, attach a payload */
+	err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), scsi_sg_count(sc),
+				       0, ctask->imm_count);
+	if (err)
+		return err;
+	tcp_ctask->sent += ctask->imm_count;
+	ctask->imm_count = 0;
+	return 0;
 }
 
 /**
@@ -1281,484 +1343,130 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
  *	The function can return -EAGAIN in which case caller must
  *	call it again later, or recover. '0' return code means successful
  *	xmit.
- *
- *	Management xmit state machine consists of these states:
- *		XMSTATE_BIT_IMM_HDR_INIT - calculate digest of PDU Header
- *		XMSTATE_BIT_IMM_HDR      - PDU Header xmit in progress
- *		XMSTATE_BIT_IMM_DATA     - PDU Data xmit in progress
- *		XMSTATE_VALUE_IDLE       - management PDU is done
  **/
 static int
 iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
 {
-	struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
 	int rc;
 
-	debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n",
-		conn->id, tcp_mtask->xmstate, mtask->itt);
-
-	if (test_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate)) {
-		iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
-				   sizeof(struct iscsi_hdr));
-
-		if (mtask->data_count) {
-			set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
-			iscsi_buf_init_iov(&tcp_mtask->sendbuf,
-					   (char*)mtask->data,
-					   mtask->data_count);
-		}
-
-		if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
-		    conn->stop_stage != STOP_CONN_RECOVER &&
-		    conn->hdrdgst_en)
-			iscsi_hdr_digest(conn, &tcp_mtask->headbuf,
-					(u8*)tcp_mtask->hdrext);
-
-		tcp_mtask->sent = 0;
-		clear_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate);
-		set_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
-	}
-
-	if (test_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate)) {
-		rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf,
-				   mtask->data_count);
-		if (rc)
-			return rc;
-		clear_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate);
-	}
-
-	if (test_and_clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate)) {
-		BUG_ON(!mtask->data_count);
-		/* FIXME: implement.
-		 * Virtual buffer could be spreaded across multiple pages...
-		 */
-		do {
-			int rc;
-
-			rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf,
-					&mtask->data_count, &tcp_mtask->sent);
-			if (rc) {
-				set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate);
-				return rc;
-			}
-		} while (mtask->data_count);
-	}
+	/* Flush any pending data first. */
+	rc = iscsi_tcp_flush(conn);
+	if (rc < 0)
+		return rc;
 
-	BUG_ON(tcp_mtask->xmstate != XMSTATE_VALUE_IDLE);
 	if (mtask->hdr->itt == RESERVED_ITT) {
 		struct iscsi_session *session = conn->session;
 
 		spin_lock_bh(&session->lock);
-		list_del(&conn->mtask->running);
-		__kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask,
-			    sizeof(void*));
+		iscsi_free_mgmt_task(conn, mtask);
 		spin_unlock_bh(&session->lock);
 	}
+
 	return 0;
 }
 
+/*
+ * iscsi_tcp_ctask_xmit - xmit normal PDU task
+ * @conn: iscsi connection
+ * @ctask: iscsi command task
+ *
+ * We're expected to return 0 when everything was transmitted succesfully,
+ * -EAGAIN if there's still data in the queue, or != 0 for any other kind
+ * of error.
+ */
 static int
-iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
-	struct scsi_cmnd *sc = ctask->sc;
 	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+	struct scsi_cmnd *sc = ctask->sc;
 	int rc = 0;
 
-	if (test_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate)) {
-		tcp_ctask->sent = 0;
-		tcp_ctask->sg_count = 0;
-		tcp_ctask->exp_datasn = 0;
-
-		if (sc->sc_data_direction == DMA_TO_DEVICE) {
-			struct scatterlist *sg = scsi_sglist(sc);
-
-			iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
-			tcp_ctask->sg = sg + 1;
-			tcp_ctask->bad_sg = sg + scsi_sg_count(sc);
-
-			debug_scsi("cmd [itt 0x%x total %d imm_data %d "
-				   "unsol count %d, unsol offset %d]\n",
-				   ctask->itt, scsi_bufflen(sc),
-				   ctask->imm_count, ctask->unsol_count,
-				   ctask->unsol_offset);
-		}
-
-		iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
-				  sizeof(struct iscsi_hdr));
-
-		if (conn->hdrdgst_en)
-			iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
-					 (u8*)tcp_ctask->hdrext);
-		clear_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate);
-		set_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
-	}
-
-	if (test_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate)) {
-		rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
-		if (rc)
-			return rc;
-		clear_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate);
-
-		if (sc->sc_data_direction != DMA_TO_DEVICE)
-			return 0;
-
-		if (ctask->imm_count) {
-			set_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
-			iscsi_set_padding(tcp_ctask, ctask->imm_count);
-
-			if (ctask->conn->datadgst_en) {
-				iscsi_data_digest_init(ctask->conn->dd_data,
-						       tcp_ctask);
-				tcp_ctask->immdigest = 0;
-			}
-		}
-
-		if (ctask->unsol_count) {
-			set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
-			set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
-		}
-	}
-	return rc;
-}
-
-static int
-iscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-	int sent = 0, rc;
-
-	if (test_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate)) {
-		iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
-				   tcp_ctask->pad_count);
-		if (conn->datadgst_en)
-			crypto_hash_update(&tcp_conn->tx_hash,
-					   &tcp_ctask->sendbuf.sg,
-					   tcp_ctask->sendbuf.sg.length);
-	} else if (!test_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate))
-		return 0;
-
-	clear_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate);
-	clear_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
-	debug_scsi("sending %d pad bytes for itt 0x%x\n",
-		   tcp_ctask->pad_count, ctask->itt);
-	rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
-			   &sent);
-	if (rc) {
-		debug_scsi("padding send failed %d\n", rc);
-		set_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate);
-	}
-	return rc;
-}
-
-static int
-iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
-			struct iscsi_buf *buf, uint32_t *digest)
-{
-	struct iscsi_tcp_cmd_task *tcp_ctask;
-	struct iscsi_tcp_conn *tcp_conn;
-	int rc, sent = 0;
-
-	if (!conn->datadgst_en)
-		return 0;
-
-	tcp_ctask = ctask->dd_data;
-	tcp_conn = conn->dd_data;
-
-	if (!test_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate)) {
-		crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
-		iscsi_buf_init_iov(buf, (char*)digest, 4);
-	}
-	clear_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
-
-	rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
-	if (!rc)
-		debug_scsi("sent digest 0x%x for itt 0x%x\n", *digest,
-			  ctask->itt);
-	else {
-		debug_scsi("sending digest 0x%x failed for itt 0x%x!\n",
-			  *digest, ctask->itt);
-		set_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate);
-	}
-	return rc;
-}
-
-static int
-iscsi_send_data(struct iscsi_cmd_task *ctask, struct iscsi_buf *sendbuf,
-		struct scatterlist **sg, int *sent, int *count,
-		struct iscsi_buf *digestbuf, uint32_t *digest)
-{
-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-	struct iscsi_conn *conn = ctask->conn;
-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-	int rc, buf_sent, offset;
-
-	while (*count) {
-		buf_sent = 0;
-		offset = sendbuf->sent;
-
-		rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);
-		*sent = *sent + buf_sent;
-		if (buf_sent && conn->datadgst_en)
-			partial_sg_digest_update(&tcp_conn->tx_hash,
-				&sendbuf->sg, sendbuf->sg.offset + offset,
-				buf_sent);
-		if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {
-			iscsi_buf_init_sg(sendbuf, *sg);
-			*sg = *sg + 1;
-		}
-
-		if (rc)
-			return rc;
-	}
-
-	rc = iscsi_send_padding(conn, ctask);
-	if (rc)
+flush:
+	/* Flush any pending data first. */
+	rc = iscsi_tcp_flush(conn);
+	if (rc < 0)
 		return rc;
 
-	return iscsi_send_digest(conn, ctask, digestbuf, digest);
-}
-
-static int
-iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-	struct iscsi_data_task *dtask;
-	int rc;
-
-	set_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
-	if (test_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate)) {
-		dtask = &tcp_ctask->unsol_dtask;
-
-		iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);
-		iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
-				   sizeof(struct iscsi_hdr));
-		if (conn->hdrdgst_en)
-			iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
-					(u8*)dtask->hdrext);
-
-		clear_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
-		iscsi_set_padding(tcp_ctask, ctask->data_count);
-	}
-
-	rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);
-	if (rc) {
-		clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
-		set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate);
-		return rc;
-	}
+	/* Are we done already? */
+	if (sc->sc_data_direction != DMA_TO_DEVICE)
+		return 0;
 
-	if (conn->datadgst_en) {
-		dtask = &tcp_ctask->unsol_dtask;
-		iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
-		dtask->digest = 0;
-	}
+	if (ctask->unsol_count != 0) {
+		struct iscsi_data *hdr = &tcp_ctask->unsol_dtask.hdr;
 
-	debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n",
-		   ctask->itt, ctask->unsol_count, tcp_ctask->sent);
-	return 0;
-}
+		/* Prepare a header for the unsolicited PDU.
+		 * The amount of data we want to send will be
+		 * in ctask->data_count.
+		 * FIXME: return the data count instead.
+		 */
+		iscsi_prep_unsolicit_data_pdu(ctask, hdr);
 
-static int
-iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-	int rc;
+		debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n",
+				ctask->itt, tcp_ctask->sent, ctask->data_count);
 
-	if (test_and_clear_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate)) {
-		BUG_ON(!ctask->unsol_count);
-send_hdr:
-		rc = iscsi_send_unsol_hdr(conn, ctask);
+		iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr));
+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
+					      scsi_sg_count(sc),
+					      tcp_ctask->sent,
+					      ctask->data_count);
 		if (rc)
-			return rc;
-	}
-
-	if (test_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate)) {
-		struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;
-		int start = tcp_ctask->sent;
+			goto fail;
+		tcp_ctask->sent += ctask->data_count;
+		ctask->unsol_count -= ctask->data_count;
+		goto flush;
+	} else {
+		struct iscsi_session *session = conn->session;
+		struct iscsi_r2t_info *r2t;
 
-		rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
-				     &tcp_ctask->sent, &ctask->data_count,
-				     &dtask->digestbuf, &dtask->digest);
-		ctask->unsol_count -= tcp_ctask->sent - start;
-		if (rc)
-			return rc;
-		clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate);
-		/*
-		 * Done with the Data-Out. Next, check if we need
-		 * to send another unsolicited Data-Out.
+		/* All unsolicited PDUs sent. Check for solicited PDUs.
 		 */
-		if (ctask->unsol_count) {
-			debug_scsi("sending more uns\n");
-			set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate);
-			goto send_hdr;
+		spin_lock_bh(&session->lock);
+		r2t = tcp_ctask->r2t;
+		if (r2t != NULL) {
+			/* Continue with this R2T? */
+			if (!iscsi_solicit_data_cont(conn, ctask, r2t)) {
+				debug_scsi("  done with r2t %p\n", r2t);
+
+				__kfifo_put(tcp_ctask->r2tpool.queue,
+					    (void*)&r2t, sizeof(void*));
+				tcp_ctask->r2t = r2t = NULL;
+			}
 		}
-	}
-	return 0;
-}
-
-static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
-			      struct iscsi_cmd_task *ctask)
-{
-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-	struct iscsi_session *session = conn->session;
-	struct iscsi_r2t_info *r2t;
-	struct iscsi_data_task *dtask;
-	int left, rc;
 
-	if (test_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate)) {
-		if (!tcp_ctask->r2t) {
-			spin_lock_bh(&session->lock);
+		if (r2t == NULL) {
 			__kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
 				    sizeof(void*));
-			spin_unlock_bh(&session->lock);
+			r2t = tcp_ctask->r2t;
 		}
-send_hdr:
-		r2t = tcp_ctask->r2t;
-		dtask = &r2t->dtask;
-
-		if (conn->hdrdgst_en)
-			iscsi_hdr_digest(conn, &r2t->headbuf,
-					(u8*)dtask->hdrext);
-		clear_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate);
-		set_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
-	}
-
-	if (test_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate)) {
-		r2t = tcp_ctask->r2t;
-		dtask = &r2t->dtask;
-
-		rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
-		if (rc)
-			return rc;
-		clear_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate);
-		set_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
+		spin_unlock_bh(&session->lock);
 
-		if (conn->datadgst_en) {
-			iscsi_data_digest_init(conn->dd_data, tcp_ctask);
-			dtask->digest = 0;
+		/* Waiting for more R2Ts to arrive. */
+		if (r2t == NULL) {
+			debug_tcp("no R2Ts yet\n");
+			return 0;
 		}
 
-		iscsi_set_padding(tcp_ctask, r2t->data_count);
-		debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
-			r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
-			r2t->sent);
-	}
+		debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n",
+			r2t, r2t->solicit_datasn - 1, ctask->itt,
+			r2t->data_offset + r2t->sent, r2t->data_count);
 
-	if (test_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate)) {
-		r2t = tcp_ctask->r2t;
-		dtask = &r2t->dtask;
+		iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr,
+					sizeof(struct iscsi_hdr));
 
-		rc = iscsi_send_data(ctask, &r2t->sendbuf, &r2t->sg,
-				     &r2t->sent, &r2t->data_count,
-				     &dtask->digestbuf, &dtask->digest);
+		rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc),
+					      scsi_sg_count(sc),
+					      r2t->data_offset + r2t->sent,
+					      r2t->data_count);
 		if (rc)
-			return rc;
-		clear_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate);
-
-		/*
-		 * Done with this Data-Out. Next, check if we have
-		 * to send another Data-Out for this R2T.
-		 */
-		BUG_ON(r2t->data_length - r2t->sent < 0);
-		left = r2t->data_length - r2t->sent;
-		if (left) {
-			iscsi_solicit_data_cont(conn, ctask, r2t, left);
-			goto send_hdr;
-		}
-
-		/*
-		 * Done with this R2T. Check if there are more
-		 * outstanding R2Ts ready to be processed.
-		 */
-		spin_lock_bh(&session->lock);
-		tcp_ctask->r2t = NULL;
-		__kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
-			    sizeof(void*));
-		if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t,
-				sizeof(void*))) {
-			tcp_ctask->r2t = r2t;
-			spin_unlock_bh(&session->lock);
-			goto send_hdr;
-		}
-		spin_unlock_bh(&session->lock);
+			goto fail;
+		tcp_ctask->sent += r2t->data_count;
+		r2t->sent += r2t->data_count;
+		goto flush;
 	}
 	return 0;
-}
-
-/**
- * iscsi_tcp_ctask_xmit - xmit normal PDU task
- * @conn: iscsi connection
- * @ctask: iscsi command task
- *
- * Notes:
- *	The function can return -EAGAIN in which case caller must
- *	call it again later, or recover. '0' return code means successful
- *	xmit.
- *	The function is devided to logical helpers (above) for the different
- *	xmit stages.
- *
- *iscsi_send_cmd_hdr()
- *	XMSTATE_BIT_CMD_HDR_INIT - prepare Header and Data buffers Calculate
- *	                           Header Digest
- *	XMSTATE_BIT_CMD_HDR_XMIT - Transmit header in progress
- *
- *iscsi_send_padding
- *	XMSTATE_BIT_W_PAD        - Prepare and send pading
- *	XMSTATE_BIT_W_RESEND_PAD - retry send pading
- *
- *iscsi_send_digest
- *	XMSTATE_BIT_W_RESEND_DATA_DIGEST - Finalize and send Data Digest
- *	XMSTATE_BIT_W_RESEND_DATA_DIGEST - retry sending digest
- *
- *iscsi_send_unsol_hdr
- *	XMSTATE_BIT_UNS_INIT     - prepare un-solicit data header and digest
- *	XMSTATE_BIT_UNS_HDR      - send un-solicit header
- *
- *iscsi_send_unsol_pdu
- *	XMSTATE_BIT_UNS_DATA     - send un-solicit data in progress
- *
- *iscsi_send_sol_pdu
- *	XMSTATE_BIT_SOL_HDR_INIT - solicit data header and digest initialize
- *	XMSTATE_BIT_SOL_HDR      - send solicit header
- *	XMSTATE_BIT_SOL_DATA     - send solicit data
- *
- *iscsi_tcp_ctask_xmit
- *	XMSTATE_BIT_IMM_DATA     - xmit managment data (??)
- **/
-static int
-iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
-	struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-	int rc = 0;
-
-	debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n",
-		conn->id, tcp_ctask->xmstate, ctask->itt);
-
-	rc = iscsi_send_cmd_hdr(conn, ctask);
-	if (rc)
-		return rc;
-	if (ctask->sc->sc_data_direction != DMA_TO_DEVICE)
-		return 0;
-
-	if (test_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate)) {
-		rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
-				     &tcp_ctask->sent, &ctask->imm_count,
-				     &tcp_ctask->immbuf, &tcp_ctask->immdigest);
-		if (rc)
-			return rc;
-		clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate);
-	}
-
-	rc = iscsi_send_unsol_pdu(conn, ctask);
-	if (rc)
-		return rc;
-
-	rc = iscsi_send_sol_pdu(conn, ctask);
-	if (rc)
-		return rc;
-
-	return rc;
+fail:
+	iscsi_conn_failure(conn, rc);
+	return -EIO;
 }
 
 static struct iscsi_cls_conn *
@@ -1784,9 +1492,6 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
 
 	conn->dd_data = tcp_conn;
 	tcp_conn->iscsi_conn = conn;
-	tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-	/* initial operational parameters */
-	tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
 
 	tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
 						  CRYPTO_ALG_ASYNC);
@@ -1863,11 +1568,9 @@ static void
 iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
 {
 	struct iscsi_conn *conn = cls_conn->dd_data;
-	struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
 
 	iscsi_conn_stop(cls_conn, flag);
 	iscsi_tcp_release_conn(conn);
-	tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
 }
 
 static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
@@ -1967,7 +1670,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
 	/*
 	 * set receive state machine into initial state
 	 */
-	tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+	iscsi_tcp_hdr_recv_prep(tcp_conn);
 	return 0;
 
 free_socket:
@@ -1977,10 +1680,17 @@ free_socket:
 
 /* called with host lock */
 static void
-iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
+iscsi_tcp_mtask_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
 {
-	struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
-	tcp_mtask->xmstate = 1 << XMSTATE_BIT_IMM_HDR_INIT;
+	debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt);
+
+	/* Prepare PDU, optionally w/ immediate data */
+	iscsi_tcp_send_hdr_prep(conn, mtask->hdr, sizeof(*mtask->hdr));
+
+	/* If we have immediate data, attach a payload */
+	if (mtask->data_count)
+		iscsi_tcp_send_linear_data_prepare(conn, mtask->data,
+						   mtask->data_count);
 }
 
 static int
@@ -2003,8 +1713,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session)
 		 */
 
 		/* R2T pool */
-		if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4,
-				    (void***)&tcp_ctask->r2ts,
+		if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, NULL,
 				    sizeof(struct iscsi_r2t_info))) {
 			goto r2t_alloc_fail;
 		}
@@ -2013,8 +1722,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session)
 		tcp_ctask->r2tqueue = kfifo_alloc(
 		      session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
 		if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) {
-			iscsi_pool_free(&tcp_ctask->r2tpool,
-					(void**)tcp_ctask->r2ts);
+			iscsi_pool_free(&tcp_ctask->r2tpool);
 			goto r2t_alloc_fail;
 		}
 	}
@@ -2027,8 +1735,7 @@ r2t_alloc_fail:
 		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 
 		kfifo_free(tcp_ctask->r2tqueue);
-		iscsi_pool_free(&tcp_ctask->r2tpool,
-				(void**)tcp_ctask->r2ts);
+		iscsi_pool_free(&tcp_ctask->r2tpool);
 	}
 	return -ENOMEM;
 }
@@ -2043,8 +1750,7 @@ iscsi_r2tpool_free(struct iscsi_session *session)
 		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 
 		kfifo_free(tcp_ctask->r2tqueue);
-		iscsi_pool_free(&tcp_ctask->r2tpool,
-				(void**)tcp_ctask->r2ts);
+		iscsi_pool_free(&tcp_ctask->r2tpool);
 	}
 }
 
@@ -2060,9 +1766,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
 	switch(param) {
 	case ISCSI_PARAM_HDRDGST_EN:
 		iscsi_set_param(cls_conn, param, buf, buflen);
-		tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
-		if (conn->hdrdgst_en)
-			tcp_conn->hdr_size += sizeof(__u32);
 		break;
 	case ISCSI_PARAM_DATADGST_EN:
 		iscsi_set_param(cls_conn, param, buf, buflen);
@@ -2071,12 +1774,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
 		break;
 	case ISCSI_PARAM_MAX_R2T:
 		sscanf(buf, "%d", &value);
-		if (session->max_r2t == roundup_pow_of_two(value))
+		if (value <= 0 || !is_power_of_2(value))
+			return -EINVAL;
+		if (session->max_r2t == value)
 			break;
 		iscsi_r2tpool_free(session);
 		iscsi_set_param(cls_conn, param, buf, buflen);
-		if (session->max_r2t & (session->max_r2t - 1))
-			session->max_r2t = roundup_pow_of_two(session->max_r2t);
 		if (iscsi_r2tpool_alloc(session))
 			return -ENOMEM;
 		break;
@@ -2183,14 +1886,15 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit,
 		struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
 		struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
 
-		ctask->hdr = &tcp_ctask->hdr;
+		ctask->hdr = &tcp_ctask->hdr.cmd_hdr;
+		ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE;
 	}
 
 	for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) {
 		struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i];
 		struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
 
-		mtask->hdr = &tcp_mtask->hdr;
+		mtask->hdr = (struct iscsi_hdr *) &tcp_mtask->hdr;
 	}
 
 	if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session)))
@@ -2222,10 +1926,11 @@ static struct scsi_host_template iscsi_sht = {
 	.queuecommand           = iscsi_queuecommand,
 	.change_queue_depth	= iscsi_change_queue_depth,
 	.can_queue		= ISCSI_DEF_XMIT_CMDS_MAX - 1,
-	.sg_tablesize		= ISCSI_SG_TABLESIZE,
+	.sg_tablesize		= 4096,
 	.max_sectors		= 0xFFFF,
 	.cmd_per_lun		= ISCSI_DEF_CMD_PER_LUN,
 	.eh_abort_handler       = iscsi_eh_abort,
+	.eh_device_reset_handler= iscsi_eh_device_reset,
 	.eh_host_reset_handler	= iscsi_eh_host_reset,
 	.use_clustering         = DISABLE_CLUSTERING,
 	.slave_configure        = iscsi_tcp_slave_configure,
@@ -2257,14 +1962,17 @@ static struct iscsi_transport iscsi_tcp_transport = {
 				  ISCSI_PERSISTENT_ADDRESS |
 				  ISCSI_TARGET_NAME | ISCSI_TPGT |
 				  ISCSI_USERNAME | ISCSI_PASSWORD |
-				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
+				  ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
+				  ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
+				  ISCSI_LU_RESET_TMO |
+				  ISCSI_PING_TMO | ISCSI_RECV_TMO,
 	.host_param_mask	= ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
 				  ISCSI_HOST_INITIATOR_NAME |
 				  ISCSI_HOST_NETDEV_NAME,
 	.host_template		= &iscsi_sht,
 	.conndata_size		= sizeof(struct iscsi_conn),
 	.max_conn		= 1,
-	.max_cmd_len		= ISCSI_TCP_MAX_CMD_LEN,
+	.max_cmd_len		= 16,
 	/* session management */
 	.create_session		= iscsi_tcp_session_create,
 	.destroy_session	= iscsi_tcp_session_destroy,
@@ -2283,8 +1991,8 @@ static struct iscsi_transport iscsi_tcp_transport = {
 	/* IO */
 	.send_pdu		= iscsi_conn_send_pdu,
 	.get_stats		= iscsi_conn_get_stats,
-	.init_cmd_task		= iscsi_tcp_cmd_init,
-	.init_mgmt_task		= iscsi_tcp_mgmt_init,
+	.init_cmd_task		= iscsi_tcp_ctask_init,
+	.init_mgmt_task		= iscsi_tcp_mtask_init,
 	.xmit_cmd_task		= iscsi_tcp_ctask_xmit,
 	.xmit_mgmt_task		= iscsi_tcp_mtask_xmit,
 	.cleanup_cmd_task	= iscsi_tcp_cleanup_ctask,
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 68c36cc8997e..ed0b991d1e72 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -24,71 +24,61 @@
 
 #include <scsi/libiscsi.h>
 
-/* Socket's Receive state machine */
-#define IN_PROGRESS_WAIT_HEADER		0x0
-#define IN_PROGRESS_HEADER_GATHER	0x1
-#define IN_PROGRESS_DATA_RECV		0x2
-#define IN_PROGRESS_DDIGEST_RECV	0x3
-#define IN_PROGRESS_PAD_RECV		0x4
-
-/* xmit state machine */
-#define XMSTATE_VALUE_IDLE			0
-#define XMSTATE_BIT_CMD_HDR_INIT		0
-#define XMSTATE_BIT_CMD_HDR_XMIT		1
-#define XMSTATE_BIT_IMM_HDR			2
-#define XMSTATE_BIT_IMM_DATA			3
-#define XMSTATE_BIT_UNS_INIT			4
-#define XMSTATE_BIT_UNS_HDR			5
-#define XMSTATE_BIT_UNS_DATA			6
-#define XMSTATE_BIT_SOL_HDR			7
-#define XMSTATE_BIT_SOL_DATA			8
-#define XMSTATE_BIT_W_PAD			9
-#define XMSTATE_BIT_W_RESEND_PAD		10
-#define XMSTATE_BIT_W_RESEND_DATA_DIGEST	11
-#define XMSTATE_BIT_IMM_HDR_INIT		12
-#define XMSTATE_BIT_SOL_HDR_INIT		13
-
-#define ISCSI_PAD_LEN			4
-#define ISCSI_SG_TABLESIZE		SG_ALL
-#define ISCSI_TCP_MAX_CMD_LEN		16
-
 struct crypto_hash;
 struct socket;
+struct iscsi_tcp_conn;
+struct iscsi_segment;
+
+typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *,
+				    struct iscsi_segment *);
+
+struct iscsi_segment {
+	unsigned char		*data;
+	unsigned int		size;
+	unsigned int		copied;
+	unsigned int		total_size;
+	unsigned int		total_copied;
+
+	struct hash_desc	*hash;
+	unsigned char		recv_digest[ISCSI_DIGEST_SIZE];
+	unsigned char		digest[ISCSI_DIGEST_SIZE];
+	unsigned int		digest_len;
+
+	struct scatterlist	*sg;
+	void			*sg_mapped;
+	unsigned int		sg_offset;
+
+	iscsi_segment_done_fn_t	*done;
+};
 
 /* Socket connection recieve helper */
 struct iscsi_tcp_recv {
 	struct iscsi_hdr	*hdr;
-	struct sk_buff		*skb;
-	int			offset;
-	int			len;
-	int			hdr_offset;
-	int			copy;
-	int			copied;
-	int			padding;
-	struct iscsi_cmd_task	*ctask;		/* current cmd in progress */
+	struct iscsi_segment	segment;
+
+	/* Allocate buffer for BHS + AHS */
+	uint32_t		hdr_buf[64];
 
 	/* copied and flipped values */
 	int			datalen;
-	int			datadgst;
-	char			zero_copy_hdr;
+};
+
+/* Socket connection send helper */
+struct iscsi_tcp_send {
+	struct iscsi_hdr	*hdr;
+	struct iscsi_segment	segment;
+	struct iscsi_segment	data_segment;
 };
 
 struct iscsi_tcp_conn {
 	struct iscsi_conn	*iscsi_conn;
 	struct socket		*sock;
-	struct iscsi_hdr	hdr;		/* header placeholder */
-	char			hdrext[4*sizeof(__u16) +
-				    sizeof(__u32)];
-	int			data_copied;
 	int			stop_stage;	/* conn_stop() flag: *
 						 * stop to recover,  *
 						 * stop to terminate */
-	/* iSCSI connection-wide sequencing */
-	int			hdr_size;	/* PDU header size */
-
 	/* control data */
 	struct iscsi_tcp_recv	in;		/* TCP receive context */
-	int			in_progress;	/* connection state machine */
+	struct iscsi_tcp_send	out;		/* TCP send context */
 
 	/* old values for socket callbacks */
 	void			(*old_data_ready)(struct sock *, int);
@@ -103,29 +93,19 @@ struct iscsi_tcp_conn {
 	uint32_t		sendpage_failures_cnt;
 	uint32_t		discontiguous_hdr_cnt;
 
-	ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
-};
+	int			error;
 
-struct iscsi_buf {
-	struct scatterlist	sg;
-	unsigned int		sent;
-	char			use_sendmsg;
+	ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
 };
 
 struct iscsi_data_task {
 	struct iscsi_data	hdr;			/* PDU */
-	char			hdrext[sizeof(__u32)];	/* Header-Digest */
-	struct iscsi_buf	digestbuf;		/* digest buffer */
-	uint32_t		digest;			/* data digest */
+	char			hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */
 };
 
 struct iscsi_tcp_mgmt_task {
 	struct iscsi_hdr	hdr;
-	char			hdrext[sizeof(__u32)]; /* Header-Digest */
-	unsigned long		xmstate;	/* mgmt xmit progress */
-	struct iscsi_buf	headbuf;	/* header buffer */
-	struct iscsi_buf	sendbuf;	/* in progress buffer */
-	int			sent;
+	char			hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */
 };
 
 struct iscsi_r2t_info {
@@ -133,38 +113,26 @@ struct iscsi_r2t_info {
 	__be32			exp_statsn;	/* copied from R2T */
 	uint32_t		data_length;	/* copied from R2T */
 	uint32_t		data_offset;	/* copied from R2T */
-	struct iscsi_buf	headbuf;	/* Data-Out Header Buffer */
-	struct iscsi_buf	sendbuf;	/* Data-Out in progress buffer*/
 	int			sent;		/* R2T sequence progress */
 	int			data_count;	/* DATA-Out payload progress */
-	struct scatterlist	*sg;		/* per-R2T SG list */
 	int			solicit_datasn;
-	struct iscsi_data_task   dtask;        /* which data task */
+	struct iscsi_data_task	dtask;		/* Data-Out header buf */
 };
 
 struct iscsi_tcp_cmd_task {
-	struct iscsi_cmd	hdr;
-	char			hdrext[4*sizeof(__u16)+	/* AHS */
-				    sizeof(__u32)];	/* HeaderDigest */
-	char			pad[ISCSI_PAD_LEN];
-	int			pad_count;		/* padded bytes */
-	struct iscsi_buf	headbuf;		/* header buf (xmit) */
-	struct iscsi_buf	sendbuf;		/* in progress buffer*/
-	unsigned long		xmstate;		/* xmit xtate machine */
+	struct iscsi_hdr_buff {
+		struct iscsi_cmd	cmd_hdr;
+		char			hdrextbuf[ISCSI_MAX_AHS_SIZE +
+		                                  ISCSI_DIGEST_SIZE];
+	} hdr;
+
 	int			sent;
-	struct scatterlist	*sg;			/* per-cmd SG list  */
-	struct scatterlist	*bad_sg;		/* assert statement */
-	int			sg_count;		/* SG's to process  */
-	uint32_t		exp_datasn;		/* expected target's R2TSN/DataSN */
+	uint32_t		exp_datasn;	/* expected target's R2TSN/DataSN */
 	int			data_offset;
-	struct iscsi_r2t_info	*r2t;			/* in progress R2T    */
-	struct iscsi_queue	r2tpool;
+	struct iscsi_r2t_info	*r2t;		/* in progress R2T    */
+	struct iscsi_pool	r2tpool;
 	struct kfifo		*r2tqueue;
-	struct iscsi_r2t_info	**r2ts;
-	int			digest_count;
-	uint32_t		immdigest;		/* for imm data */
-	struct iscsi_buf	immbuf;			/* for imm data digest */
-	struct iscsi_data_task	unsol_dtask;	/* unsol data task */
+	struct iscsi_data_task	unsol_dtask;	/* Data-Out header buf */
 };
 
 #endif /* ISCSI_H */
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 8b57af5baaec..553168ae44f1 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -24,6 +24,7 @@
 #include <linux/types.h>
 #include <linux/kfifo.h>
 #include <linux/delay.h>
+#include <linux/log2.h>
 #include <asm/unaligned.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
@@ -86,7 +87,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
 		 * xmit thread
 		 */
 		if (!list_empty(&session->leadconn->xmitqueue) ||
-		    __kfifo_len(session->leadconn->mgmtqueue))
+		    !list_empty(&session->leadconn->mgmtqueue))
 			scsi_queue_work(session->host,
 					&session->leadconn->xmitwork);
 	}
@@ -122,6 +123,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
 }
 EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
 
+static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len)
+{
+	unsigned exp_len = ctask->hdr_len + len;
+
+	if (exp_len > ctask->hdr_max) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */
+	ctask->hdr_len = exp_len;
+	return 0;
+}
+
 /**
  * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu
  * @ctask: iscsi cmd task
@@ -129,27 +144,32 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu);
  * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set
  * fields like dlength or final based on how much data it sends
  */
-static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
+static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
 {
 	struct iscsi_conn *conn = ctask->conn;
 	struct iscsi_session *session = conn->session;
 	struct iscsi_cmd *hdr = ctask->hdr;
 	struct scsi_cmnd *sc = ctask->sc;
+	unsigned hdrlength;
+	int rc;
 
-        hdr->opcode = ISCSI_OP_SCSI_CMD;
-        hdr->flags = ISCSI_ATTR_SIMPLE;
-        int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
-        hdr->itt = build_itt(ctask->itt, conn->id, session->age);
-        hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
-        hdr->cmdsn = cpu_to_be32(session->cmdsn);
-        session->cmdsn++;
-        hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
-        memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
+	ctask->hdr_len = 0;
+	rc = iscsi_add_hdr(ctask, sizeof(*hdr));
+	if (rc)
+		return rc;
+	hdr->opcode = ISCSI_OP_SCSI_CMD;
+	hdr->flags = ISCSI_ATTR_SIMPLE;
+	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+	hdr->itt = build_itt(ctask->itt, conn->id, session->age);
+	hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
+	hdr->cmdsn = cpu_to_be32(session->cmdsn);
+	session->cmdsn++;
+	hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
+	memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
 	if (sc->cmd_len < MAX_COMMAND_SIZE)
 		memset(&hdr->cdb[sc->cmd_len], 0,
 			MAX_COMMAND_SIZE - sc->cmd_len);
 
-	ctask->data_count = 0;
 	ctask->imm_count = 0;
 	if (sc->sc_data_direction == DMA_TO_DEVICE) {
 		hdr->flags |= ISCSI_FLAG_CMD_WRITE;
@@ -178,9 +198,9 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
 			else
 				ctask->imm_count = min(scsi_bufflen(sc),
 							conn->max_xmit_dlength);
-			hton24(ctask->hdr->dlength, ctask->imm_count);
+			hton24(hdr->dlength, ctask->imm_count);
 		} else
-			zero_data(ctask->hdr->dlength);
+			zero_data(hdr->dlength);
 
 		if (!session->initial_r2t_en) {
 			ctask->unsol_count = min((session->first_burst),
@@ -190,7 +210,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
 
 		if (!ctask->unsol_count)
 			/* No unsolicit Data-Out's */
-			ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+			hdr->flags |= ISCSI_FLAG_CMD_FINAL;
 	} else {
 		hdr->flags |= ISCSI_FLAG_CMD_FINAL;
 		zero_data(hdr->dlength);
@@ -199,13 +219,25 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
 			hdr->flags |= ISCSI_FLAG_CMD_READ;
 	}
 
-	conn->scsicmd_pdus_cnt++;
+	/* calculate size of additional header segments (AHSs) */
+	hdrlength = ctask->hdr_len - sizeof(*hdr);
+
+	WARN_ON(hdrlength & (ISCSI_PAD_LEN-1));
+	hdrlength /= ISCSI_PAD_LEN;
+
+	WARN_ON(hdrlength >= 256);
+	hdr->hlength = hdrlength & 0xFF;
+
+	if (conn->session->tt->init_cmd_task(conn->ctask))
+		return EIO;
 
-        debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
+	conn->scsicmd_pdus_cnt++;
+	debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
 		"cmdsn %d win %d]\n",
-                sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+		sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
 		conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
-                session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+		session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
+	return 0;
 }
 
 /**
@@ -218,13 +250,16 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
  */
 static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
 {
-	struct iscsi_session *session = ctask->conn->session;
+	struct iscsi_conn *conn = ctask->conn;
+	struct iscsi_session *session = conn->session;
 	struct scsi_cmnd *sc = ctask->sc;
 
 	ctask->state = ISCSI_TASK_COMPLETED;
 	ctask->sc = NULL;
 	/* SCSI eh reuses commands to verify us */
 	sc->SCp.ptr = NULL;
+	if (conn->ctask == ctask)
+		conn->ctask = NULL;
 	list_del_init(&ctask->running);
 	__kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
 	sc->scsi_done(sc);
@@ -241,6 +276,112 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
 		iscsi_complete_command(ctask);
 }
 
+/*
+ * session lock must be held
+ */
+static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+			 int err)
+{
+	struct scsi_cmnd *sc;
+
+	sc = ctask->sc;
+	if (!sc)
+		return;
+
+	if (ctask->state == ISCSI_TASK_PENDING)
+		/*
+		 * cmd never made it to the xmit thread, so we should not count
+		 * the cmd in the sequencing
+		 */
+		conn->session->queued_cmdsn--;
+	else
+		conn->session->tt->cleanup_cmd_task(conn, ctask);
+
+	sc->result = err;
+	scsi_set_resid(sc, scsi_bufflen(sc));
+	if (conn->ctask == ctask)
+		conn->ctask = NULL;
+	/* release ref from queuecommand */
+	__iscsi_put_ctask(ctask);
+}
+
+/**
+ * iscsi_free_mgmt_task - return mgmt task back to pool
+ * @conn: iscsi connection
+ * @mtask: mtask
+ *
+ * Must be called with session lock.
+ */
+void iscsi_free_mgmt_task(struct iscsi_conn *conn,
+			  struct iscsi_mgmt_task *mtask)
+{
+	list_del_init(&mtask->running);
+	if (conn->login_mtask == mtask)
+		return;
+
+	if (conn->ping_mtask == mtask)
+		conn->ping_mtask = NULL;
+	__kfifo_put(conn->session->mgmtpool.queue,
+		    (void*)&mtask, sizeof(void*));
+}
+EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task);
+
+static struct iscsi_mgmt_task *
+__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+		      char *data, uint32_t data_size)
+{
+	struct iscsi_session *session = conn->session;
+	struct iscsi_mgmt_task *mtask;
+
+	if (session->state == ISCSI_STATE_TERMINATE)
+		return NULL;
+
+	if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
+	    hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
+		/*
+		 * Login and Text are sent serially, in
+		 * request-followed-by-response sequence.
+		 * Same mtask can be used. Same ITT must be used.
+		 * Note that login_mtask is preallocated at conn_create().
+		 */
+		mtask = conn->login_mtask;
+	else {
+		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
+		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
+
+		if (!__kfifo_get(session->mgmtpool.queue,
+				 (void*)&mtask, sizeof(void*)))
+			return NULL;
+	}
+
+	if (data_size) {
+		memcpy(mtask->data, data, data_size);
+		mtask->data_count = data_size;
+	} else
+		mtask->data_count = 0;
+
+	memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
+	INIT_LIST_HEAD(&mtask->running);
+	list_add_tail(&mtask->running, &conn->mgmtqueue);
+	return mtask;
+}
+
+int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
+			char *data, uint32_t data_size)
+{
+	struct iscsi_conn *conn = cls_conn->dd_data;
+	struct iscsi_session *session = conn->session;
+	int err = 0;
+
+	spin_lock_bh(&session->lock);
+	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
+		err = -EPERM;
+	spin_unlock_bh(&session->lock);
+	scsi_queue_work(session->host, &conn->xmitwork);
+	return err;
+}
+EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
+
 /**
  * iscsi_cmd_rsp - SCSI Command Response processing
  * @conn: iscsi connection
@@ -291,17 +432,19 @@ invalid_datalen:
 			   min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
 	}
 
-	if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
+	if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
+	                   ISCSI_FLAG_CMD_OVERFLOW)) {
 		int res_count = be32_to_cpu(rhdr->residual_count);
 
-		if (res_count > 0 && res_count <= scsi_bufflen(sc))
+		if (res_count > 0 &&
+		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
+		     res_count <= scsi_bufflen(sc)))
 			scsi_set_resid(sc, res_count);
 		else
 			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-	} else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW)
+	} else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
+	                          ISCSI_FLAG_CMD_BIDI_OVERFLOW))
 		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-	else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW)
-		scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
 
 out:
 	debug_scsi("done [sc %lx res %d itt 0x%x]\n",
@@ -318,18 +461,51 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
 	conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
 	conn->tmfrsp_pdus_cnt++;
 
-	if (conn->tmabort_state != TMABORT_INITIAL)
+	if (conn->tmf_state != TMF_QUEUED)
 		return;
 
 	if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
-		conn->tmabort_state = TMABORT_SUCCESS;
+		conn->tmf_state = TMF_SUCCESS;
 	else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
-		conn->tmabort_state = TMABORT_NOT_FOUND;
+		conn->tmf_state = TMF_NOT_FOUND;
 	else
-		conn->tmabort_state = TMABORT_FAILED;
+		conn->tmf_state = TMF_FAILED;
 	wake_up(&conn->ehwait);
 }
 
+static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
+{
+        struct iscsi_nopout hdr;
+	struct iscsi_mgmt_task *mtask;
+
+	if (!rhdr && conn->ping_mtask)
+		return;
+
+	memset(&hdr, 0, sizeof(struct iscsi_nopout));
+	hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
+	hdr.flags = ISCSI_FLAG_CMD_FINAL;
+
+	if (rhdr) {
+		memcpy(hdr.lun, rhdr->lun, 8);
+		hdr.ttt = rhdr->ttt;
+		hdr.itt = RESERVED_ITT;
+	} else
+		hdr.ttt = RESERVED_ITT;
+
+	mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
+	if (!mtask) {
+		printk(KERN_ERR "Could not send nopout\n");
+		return;
+	}
+
+	/* only track our nops */
+	if (!rhdr) {
+		conn->ping_mtask = mtask;
+		conn->last_ping = jiffies;
+	}
+	scsi_queue_work(conn->session->host, &conn->xmitwork);
+}
+
 static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 			       char *data, int datalen)
 {
@@ -374,6 +550,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 	struct iscsi_mgmt_task *mtask;
 	uint32_t itt;
 
+	conn->last_recv = jiffies;
 	if (hdr->itt != RESERVED_ITT)
 		itt = get_itt(hdr->itt);
 	else
@@ -429,10 +606,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 			 */
 			if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
 				rc = ISCSI_ERR_CONN_FAILED;
-			list_del(&mtask->running);
-			if (conn->login_mtask != mtask)
-				__kfifo_put(session->mgmtpool.queue,
-					    (void*)&mtask, sizeof(void*));
+			iscsi_free_mgmt_task(conn, mtask);
 			break;
 		case ISCSI_OP_SCSI_TMFUNC_RSP:
 			if (datalen) {
@@ -441,20 +615,26 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 			}
 
 			iscsi_tmf_rsp(conn, hdr);
+			iscsi_free_mgmt_task(conn, mtask);
 			break;
 		case ISCSI_OP_NOOP_IN:
-			if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
+			if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) ||
+			    datalen) {
 				rc = ISCSI_ERR_PROTO;
 				break;
 			}
 			conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
 
-			if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
-				rc = ISCSI_ERR_CONN_FAILED;
-			list_del(&mtask->running);
-			if (conn->login_mtask != mtask)
-				__kfifo_put(session->mgmtpool.queue,
-					    (void*)&mtask, sizeof(void*));
+			if (conn->ping_mtask != mtask) {
+				/*
+				 * If this is not in response to one of our
+				 * nops then it must be from userspace.
+				 */
+				if (iscsi_recv_pdu(conn->cls_conn, hdr, data,
+						   datalen))
+					rc = ISCSI_ERR_CONN_FAILED;
+			}
+			iscsi_free_mgmt_task(conn, mtask);
 			break;
 		default:
 			rc = ISCSI_ERR_BAD_OPCODE;
@@ -473,8 +653,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 			if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
 				break;
 
-			if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
-				rc = ISCSI_ERR_CONN_FAILED;
+			iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr);
 			break;
 		case ISCSI_OP_REJECT:
 			rc = iscsi_handle_reject(conn, hdr, data, datalen);
@@ -609,20 +788,19 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn,
 		session->tt->init_mgmt_task(conn, mtask);
 
 	debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
-		   hdr->opcode, hdr->itt, mtask->data_count);
+		   hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt,
+		   mtask->data_count);
 }
 
 static int iscsi_xmit_mtask(struct iscsi_conn *conn)
 {
 	struct iscsi_hdr *hdr = conn->mtask->hdr;
-	int rc, was_logout = 0;
+	int rc;
 
+	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT)
+		conn->session->state = ISCSI_STATE_LOGGING_OUT;
 	spin_unlock_bh(&conn->session->lock);
-	if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
-		conn->session->state = ISCSI_STATE_IN_RECOVERY;
-		iscsi_block_session(session_to_cls(conn->session));
-		was_logout = 1;
-	}
+
 	rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
 	spin_lock_bh(&conn->session->lock);
 	if (rc)
@@ -630,11 +808,6 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn)
 
 	/* done with this in-progress mtask */
 	conn->mtask = NULL;
-
-	if (was_logout) {
-		set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-		return -ENODATA;
-	}
 	return 0;
 }
 
@@ -658,21 +831,13 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
 static int iscsi_xmit_ctask(struct iscsi_conn *conn)
 {
 	struct iscsi_cmd_task *ctask = conn->ctask;
-	int rc = 0;
-
-	/*
-	 * serialize with TMF AbortTask
-	 */
-	if (ctask->state == ISCSI_TASK_ABORTING)
-		goto done;
+	int rc;
 
 	__iscsi_get_ctask(ctask);
 	spin_unlock_bh(&conn->session->lock);
 	rc = conn->session->tt->xmit_cmd_task(conn, ctask);
 	spin_lock_bh(&conn->session->lock);
 	__iscsi_put_ctask(ctask);
-
-done:
 	if (!rc)
 		/* done with this ctask */
 		conn->ctask = NULL;
@@ -680,6 +845,22 @@ done:
 }
 
 /**
+ * iscsi_requeue_ctask - requeue ctask to run from session workqueue
+ * @ctask: ctask to requeue
+ *
+ * LLDs that need to run a ctask from the session workqueue should call
+ * this. The session lock must be held.
+ */
+void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask)
+{
+	struct iscsi_conn *conn = ctask->conn;
+
+	list_move_tail(&ctask->running, &conn->requeue);
+	scsi_queue_work(conn->session->host, &conn->xmitwork);
+}
+EXPORT_SYMBOL_GPL(iscsi_requeue_ctask);
+
+/**
  * iscsi_data_xmit - xmit any command into the scheduled connection
  * @conn: iscsi connection
  *
@@ -717,36 +898,40 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
 	 * overflow us with nop-ins
 	 */
 check_mgmt:
-	while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
-			   sizeof(void*))) {
+	while (!list_empty(&conn->mgmtqueue)) {
+		conn->mtask = list_entry(conn->mgmtqueue.next,
+					 struct iscsi_mgmt_task, running);
+		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
+			iscsi_free_mgmt_task(conn, conn->mtask);
+			conn->mtask = NULL;
+			continue;
+		}
+
 		iscsi_prep_mtask(conn, conn->mtask);
-		list_add_tail(&conn->mtask->running, &conn->mgmt_run_list);
+		list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list);
 		rc = iscsi_xmit_mtask(conn);
 		if (rc)
 			goto again;
 	}
 
-	/* process command queue */
+	/* process pending command queue */
 	while (!list_empty(&conn->xmitqueue)) {
-		/*
-		 * iscsi tcp may readd the task to the xmitqueue to send
-		 * write data
-		 */
+		if (conn->tmf_state == TMF_QUEUED)
+			break;
+
 		conn->ctask = list_entry(conn->xmitqueue.next,
 					 struct iscsi_cmd_task, running);
-		switch (conn->ctask->state) {
-		case ISCSI_TASK_ABORTING:
-			break;
-		case ISCSI_TASK_PENDING:
-			iscsi_prep_scsi_cmd_pdu(conn->ctask);
-			conn->session->tt->init_cmd_task(conn->ctask);
-			/* fall through */
-		default:
-			conn->ctask->state = ISCSI_TASK_RUNNING;
-			break;
+		if (conn->session->state == ISCSI_STATE_LOGGING_OUT) {
+			fail_command(conn, conn->ctask, DID_IMM_RETRY << 16);
+			continue;
+		}
+		if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) {
+			fail_command(conn, conn->ctask, DID_ABORT << 16);
+			continue;
 		}
-		list_move_tail(conn->xmitqueue.next, &conn->run_list);
 
+		conn->ctask->state = ISCSI_TASK_RUNNING;
+		list_move_tail(conn->xmitqueue.next, &conn->run_list);
 		rc = iscsi_xmit_ctask(conn);
 		if (rc)
 			goto again;
@@ -755,7 +940,28 @@ check_mgmt:
 		 * we need to check the mgmt queue for nops that need to
 		 * be sent to aviod starvation
 		 */
-		if (__kfifo_len(conn->mgmtqueue))
+		if (!list_empty(&conn->mgmtqueue))
+			goto check_mgmt;
+	}
+
+	while (!list_empty(&conn->requeue)) {
+		if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL)
+			break;
+
+		/*
+		 * we always do fastlogout - conn stop code will clean up.
+		 */
+		if (conn->session->state == ISCSI_STATE_LOGGING_OUT)
+			break;
+
+		conn->ctask = list_entry(conn->requeue.next,
+					 struct iscsi_cmd_task, running);
+		conn->ctask->state = ISCSI_TASK_RUNNING;
+		list_move_tail(conn->requeue.next, &conn->run_list);
+		rc = iscsi_xmit_ctask(conn);
+		if (rc)
+			goto again;
+		if (!list_empty(&conn->mgmtqueue))
 			goto check_mgmt;
 	}
 	spin_unlock_bh(&conn->session->lock);
@@ -790,6 +996,7 @@ enum {
 	FAILURE_SESSION_TERMINATE,
 	FAILURE_SESSION_IN_RECOVERY,
 	FAILURE_SESSION_RECOVERY_TIMEOUT,
+	FAILURE_SESSION_LOGGING_OUT,
 };
 
 int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
@@ -805,8 +1012,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 	sc->SCp.ptr = NULL;
 
 	host = sc->device->host;
-	session = iscsi_hostdata(host->hostdata);
+	spin_unlock(host->host_lock);
 
+	session = iscsi_hostdata(host->hostdata);
 	spin_lock(&session->lock);
 
 	/*
@@ -822,17 +1030,22 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 		 * be entering our queuecommand while a block is starting
 		 * up because the block code is not locked)
 		 */
-		if (session->state == ISCSI_STATE_IN_RECOVERY) {
+		switch (session->state) {
+		case ISCSI_STATE_IN_RECOVERY:
 			reason = FAILURE_SESSION_IN_RECOVERY;
 			goto reject;
-		}
-
-		if (session->state == ISCSI_STATE_RECOVERY_FAILED)
+		case ISCSI_STATE_LOGGING_OUT:
+			reason = FAILURE_SESSION_LOGGING_OUT;
+			goto reject;
+		case ISCSI_STATE_RECOVERY_FAILED:
 			reason = FAILURE_SESSION_RECOVERY_TIMEOUT;
-		else if (session->state == ISCSI_STATE_TERMINATE)
+			break;
+		case ISCSI_STATE_TERMINATE:
 			reason = FAILURE_SESSION_TERMINATE;
-		else
+			break;
+		default:
 			reason = FAILURE_SESSION_FREED;
+		}
 		goto fault;
 	}
 
@@ -859,7 +1072,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 
 	atomic_set(&ctask->refcount, 1);
 	ctask->state = ISCSI_TASK_PENDING;
-	ctask->mtask = NULL;
 	ctask->conn = conn;
 	ctask->sc = sc;
 	INIT_LIST_HEAD(&ctask->running);
@@ -868,11 +1080,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 	spin_unlock(&session->lock);
 
 	scsi_queue_work(host, &conn->xmitwork);
+	spin_lock(host->host_lock);
 	return 0;
 
 reject:
 	spin_unlock(&session->lock);
 	debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason);
+	spin_lock(host->host_lock);
 	return SCSI_MLQUEUE_HOST_BUSY;
 
 fault:
@@ -882,6 +1096,7 @@ fault:
 	sc->result = (DID_NO_CONNECT << 16);
 	scsi_set_resid(sc, scsi_bufflen(sc));
 	sc->scsi_done(sc);
+	spin_lock(host->host_lock);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(iscsi_queuecommand);
@@ -895,72 +1110,15 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
 }
 EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
 
-static struct iscsi_mgmt_task *
-__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
-		      char *data, uint32_t data_size)
-{
-	struct iscsi_session *session = conn->session;
-	struct iscsi_mgmt_task *mtask;
-
-	if (session->state == ISCSI_STATE_TERMINATE)
-		return NULL;
-
-	if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
-	    hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
-		/*
-		 * Login and Text are sent serially, in
-		 * request-followed-by-response sequence.
-		 * Same mtask can be used. Same ITT must be used.
-		 * Note that login_mtask is preallocated at conn_create().
-		 */
-		mtask = conn->login_mtask;
-	else {
-		BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
-		BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
-
-		if (!__kfifo_get(session->mgmtpool.queue,
-				 (void*)&mtask, sizeof(void*)))
-			return NULL;
-	}
-
-	if (data_size) {
-		memcpy(mtask->data, data, data_size);
-		mtask->data_count = data_size;
-	} else
-		mtask->data_count = 0;
-
-	INIT_LIST_HEAD(&mtask->running);
-	memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
-	__kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
-	return mtask;
-}
-
-int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
-			char *data, uint32_t data_size)
-{
-	struct iscsi_conn *conn = cls_conn->dd_data;
-	struct iscsi_session *session = conn->session;
-	int err = 0;
-
-	spin_lock_bh(&session->lock);
-	if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
-		err = -EPERM;
-	spin_unlock_bh(&session->lock);
-	scsi_queue_work(session->host, &conn->xmitwork);
-	return err;
-}
-EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
-
 void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
 {
 	struct iscsi_session *session = class_to_transport_session(cls_session);
-	struct iscsi_conn *conn = session->leadconn;
 
 	spin_lock_bh(&session->lock);
 	if (session->state != ISCSI_STATE_LOGGED_IN) {
 		session->state = ISCSI_STATE_RECOVERY_FAILED;
-		if (conn)
-			wake_up(&conn->ehwait);
+		if (session->leadconn)
+			wake_up(&session->leadconn->ehwait);
 	}
 	spin_unlock_bh(&session->lock);
 }
@@ -971,30 +1129,25 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc)
 	struct Scsi_Host *host = sc->device->host;
 	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
 	struct iscsi_conn *conn = session->leadconn;
-	int fail_session = 0;
 
+	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
 	if (session->state == ISCSI_STATE_TERMINATE) {
 failed:
 		debug_scsi("failing host reset: session terminated "
 			   "[CID %d age %d]\n", conn->id, session->age);
 		spin_unlock_bh(&session->lock);
+		mutex_unlock(&session->eh_mutex);
 		return FAILED;
 	}
 
-	if (sc->SCp.phase == session->age) {
-		debug_scsi("failing connection CID %d due to SCSI host reset\n",
-			   conn->id);
-		fail_session = 1;
-	}
 	spin_unlock_bh(&session->lock);
-
+	mutex_unlock(&session->eh_mutex);
 	/*
 	 * we drop the lock here but the leadconn cannot be destoyed while
 	 * we are in the scsi eh
 	 */
-	if (fail_session)
-		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+	iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
 
 	debug_scsi("iscsi_eh_host_reset wait for relogin\n");
 	wait_event_interruptible(conn->ehwait,
@@ -1004,73 +1157,56 @@ failed:
 	if (signal_pending(current))
 		flush_signals(current);
 
+	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
 	if (session->state == ISCSI_STATE_LOGGED_IN)
 		printk(KERN_INFO "iscsi: host reset succeeded\n");
 	else
 		goto failed;
 	spin_unlock_bh(&session->lock);
-
+	mutex_unlock(&session->eh_mutex);
 	return SUCCESS;
 }
 EXPORT_SYMBOL_GPL(iscsi_eh_host_reset);
 
-static void iscsi_tmabort_timedout(unsigned long data)
+static void iscsi_tmf_timedout(unsigned long data)
 {
-	struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)data;
-	struct iscsi_conn *conn = ctask->conn;
+	struct iscsi_conn *conn = (struct iscsi_conn *)data;
 	struct iscsi_session *session = conn->session;
 
 	spin_lock(&session->lock);
-	if (conn->tmabort_state == TMABORT_INITIAL) {
-		conn->tmabort_state = TMABORT_TIMEDOUT;
-		debug_scsi("tmabort timedout [sc %p itt 0x%x]\n",
-			ctask->sc, ctask->itt);
+	if (conn->tmf_state == TMF_QUEUED) {
+		conn->tmf_state = TMF_TIMEDOUT;
+		debug_scsi("tmf timedout\n");
 		/* unblock eh_abort() */
 		wake_up(&conn->ehwait);
 	}
 	spin_unlock(&session->lock);
 }
 
-static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
-				 struct iscsi_cmd_task *ctask)
+static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
+				   struct iscsi_tm *hdr, int age,
+				   int timeout)
 {
-	struct iscsi_conn *conn = ctask->conn;
 	struct iscsi_session *session = conn->session;
-	struct iscsi_tm *hdr = &conn->tmhdr;
-
-	/*
-	 * ctask timed out but session is OK requests must be serialized.
-	 */
-	memset(hdr, 0, sizeof(struct iscsi_tm));
-	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
-	hdr->flags = ISCSI_TM_FUNC_ABORT_TASK;
-	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
-	memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
-	hdr->rtt = ctask->hdr->itt;
-	hdr->refcmdsn = ctask->hdr->cmdsn;
+	struct iscsi_mgmt_task *mtask;
 
-	ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
-					    NULL, 0);
-	if (!ctask->mtask) {
+	mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
+				      NULL, 0);
+	if (!mtask) {
 		spin_unlock_bh(&session->lock);
 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-		spin_lock_bh(&session->lock)
-		debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt);
+		spin_lock_bh(&session->lock);
+		debug_scsi("tmf exec failure\n");
 		return -EPERM;
 	}
-	ctask->state = ISCSI_TASK_ABORTING;
+	conn->tmfcmd_pdus_cnt++;
+	conn->tmf_timer.expires = timeout * HZ + jiffies;
+	conn->tmf_timer.function = iscsi_tmf_timedout;
+	conn->tmf_timer.data = (unsigned long)conn;
+	add_timer(&conn->tmf_timer);
+	debug_scsi("tmf set timeout\n");
 
-	debug_scsi("abort sent [itt 0x%x]\n", ctask->itt);
-
-	if (conn->tmabort_state == TMABORT_INITIAL) {
-		conn->tmfcmd_pdus_cnt++;
-		conn->tmabort_timer.expires = 20*HZ + jiffies;
-		conn->tmabort_timer.function = iscsi_tmabort_timedout;
-		conn->tmabort_timer.data = (unsigned long)ctask;
-		add_timer(&conn->tmabort_timer);
-		debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
-	}
 	spin_unlock_bh(&session->lock);
 	mutex_unlock(&session->eh_mutex);
 	scsi_queue_work(session->host, &conn->xmitwork);
@@ -1078,113 +1214,197 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
 	/*
 	 * block eh thread until:
 	 *
-	 * 1) abort response
-	 * 2) abort timeout
+	 * 1) tmf response
+	 * 2) tmf timeout
 	 * 3) session is terminated or restarted or userspace has
 	 * given up on recovery
 	 */
-	wait_event_interruptible(conn->ehwait,
-				 sc->SCp.phase != session->age ||
+	wait_event_interruptible(conn->ehwait, age != session->age ||
 				 session->state != ISCSI_STATE_LOGGED_IN ||
-				 conn->tmabort_state != TMABORT_INITIAL);
+				 conn->tmf_state != TMF_QUEUED);
 	if (signal_pending(current))
 		flush_signals(current);
-	del_timer_sync(&conn->tmabort_timer);
+	del_timer_sync(&conn->tmf_timer);
+
 	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
+	/* if the session drops it will clean up the mtask */
+	if (age != session->age ||
+	    session->state != ISCSI_STATE_LOGGED_IN)
+		return -ENOTCONN;
 	return 0;
 }
 
 /*
- * session lock must be held
+ * Fail commands. session lock held and recv side suspended and xmit
+ * thread flushed
  */
-static struct iscsi_mgmt_task *
-iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt)
+static void fail_all_commands(struct iscsi_conn *conn, unsigned lun)
 {
-	int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*);
-	struct iscsi_mgmt_task *task;
+	struct iscsi_cmd_task *ctask, *tmp;
 
-	debug_scsi("searching %d tasks\n", nr_tasks);
+	if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1))
+		conn->ctask = NULL;
 
-	for (i = 0; i < nr_tasks; i++) {
-		__kfifo_get(fifo, (void*)&task, sizeof(void*));
-		debug_scsi("check task %u\n", task->itt);
+	/* flush pending */
+	list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
+		if (lun == ctask->sc->device->lun || lun == -1) {
+			debug_scsi("failing pending sc %p itt 0x%x\n",
+				   ctask->sc, ctask->itt);
+			fail_command(conn, ctask, DID_BUS_BUSY << 16);
+		}
+	}
 
-		if (task->itt == itt) {
-			debug_scsi("matched task\n");
-			return task;
+	list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) {
+		if (lun == ctask->sc->device->lun || lun == -1) {
+			debug_scsi("failing requeued sc %p itt 0x%x\n",
+				   ctask->sc, ctask->itt);
+			fail_command(conn, ctask, DID_BUS_BUSY << 16);
 		}
+	}
 
-		__kfifo_put(fifo, (void*)&task, sizeof(void*));
+	/* fail all other running */
+	list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
+		if (lun == ctask->sc->device->lun || lun == -1) {
+			debug_scsi("failing in progress sc %p itt 0x%x\n",
+				   ctask->sc, ctask->itt);
+			fail_command(conn, ctask, DID_BUS_BUSY << 16);
+		}
 	}
-	return NULL;
 }
 
-static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
+static void iscsi_suspend_tx(struct iscsi_conn *conn)
 {
-	struct iscsi_conn *conn = ctask->conn;
-	struct iscsi_session *session = conn->session;
-
-	if (!ctask->mtask)
-		return -EINVAL;
+	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+	scsi_flush_work(conn->session->host);
+}
 
-	if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt))
-		list_del(&ctask->mtask->running);
-	__kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask,
-		    sizeof(void*));
-	ctask->mtask = NULL;
-	return 0;
+static void iscsi_start_tx(struct iscsi_conn *conn)
+{
+	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+	scsi_queue_work(conn->session->host, &conn->xmitwork);
 }
 
-/*
- * session lock must be held
- */
-static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
-			 int err)
+static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd)
 {
-	struct scsi_cmnd *sc;
+	struct iscsi_cls_session *cls_session;
+	struct iscsi_session *session;
+	struct iscsi_conn *conn;
+	enum scsi_eh_timer_return rc = EH_NOT_HANDLED;
 
-	sc = ctask->sc;
-	if (!sc)
-		return;
+	cls_session = starget_to_session(scsi_target(scmd->device));
+	session = class_to_transport_session(cls_session);
 
-	if (ctask->state == ISCSI_TASK_PENDING)
+	debug_scsi("scsi cmd %p timedout\n", scmd);
+
+	spin_lock(&session->lock);
+	if (session->state != ISCSI_STATE_LOGGED_IN) {
 		/*
-		 * cmd never made it to the xmit thread, so we should not count
-		 * the cmd in the sequencing
+		 * We are probably in the middle of iscsi recovery so let
+		 * that complete and handle the error.
 		 */
-		conn->session->queued_cmdsn--;
-	else
-		conn->session->tt->cleanup_cmd_task(conn, ctask);
-	iscsi_ctask_mtask_cleanup(ctask);
+		rc = EH_RESET_TIMER;
+		goto done;
+	}
 
-	sc->result = err;
-	scsi_set_resid(sc, scsi_bufflen(sc));
-	if (conn->ctask == ctask)
-		conn->ctask = NULL;
-	/* release ref from queuecommand */
-	__iscsi_put_ctask(ctask);
+	conn = session->leadconn;
+	if (!conn) {
+		/* In the middle of shuting down */
+		rc = EH_RESET_TIMER;
+		goto done;
+	}
+
+	if (!conn->recv_timeout && !conn->ping_timeout)
+		goto done;
+	/*
+	 * if the ping timedout then we are in the middle of cleaning up
+	 * and can let the iscsi eh handle it
+	 */
+	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) +
+			    (conn->ping_timeout * HZ), jiffies))
+		rc = EH_RESET_TIMER;
+	/*
+	 * if we are about to check the transport then give the command
+	 * more time
+	 */
+	if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ),
+			   jiffies))
+		rc = EH_RESET_TIMER;
+	/* if in the middle of checking the transport then give us more time */
+	if (conn->ping_mtask)
+		rc = EH_RESET_TIMER;
+done:
+	spin_unlock(&session->lock);
+	debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh");
+	return rc;
 }
 
-static void iscsi_suspend_tx(struct iscsi_conn *conn)
+static void iscsi_check_transport_timeouts(unsigned long data)
 {
-	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-	scsi_flush_work(conn->session->host);
+	struct iscsi_conn *conn = (struct iscsi_conn *)data;
+	struct iscsi_session *session = conn->session;
+	unsigned long timeout, next_timeout = 0, last_recv;
+
+	spin_lock(&session->lock);
+	if (session->state != ISCSI_STATE_LOGGED_IN)
+		goto done;
+
+	timeout = conn->recv_timeout;
+	if (!timeout)
+		goto done;
+
+	timeout *= HZ;
+	last_recv = conn->last_recv;
+	if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ),
+			   jiffies)) {
+		printk(KERN_ERR "ping timeout of %d secs expired, "
+		       "last rx %lu, last ping %lu, now %lu\n",
+		       conn->ping_timeout, last_recv,
+		       conn->last_ping, jiffies);
+		spin_unlock(&session->lock);
+		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+		return;
+	}
+
+	if (time_before_eq(last_recv + timeout, jiffies)) {
+		if (time_before_eq(conn->last_ping, last_recv)) {
+			/* send a ping to try to provoke some traffic */
+			debug_scsi("Sending nopout as ping on conn %p\n", conn);
+			iscsi_send_nopout(conn, NULL);
+		}
+		next_timeout = last_recv + timeout + (conn->ping_timeout * HZ);
+	} else {
+		next_timeout = last_recv + timeout;
+	}
+
+	if (next_timeout) {
+		debug_scsi("Setting next tmo %lu\n", next_timeout);
+		mod_timer(&conn->transport_timer, next_timeout);
+	}
+done:
+	spin_unlock(&session->lock);
 }
 
-static void iscsi_start_tx(struct iscsi_conn *conn)
+static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask,
+				      struct iscsi_tm *hdr)
 {
-	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
-	scsi_queue_work(conn->session->host, &conn->xmitwork);
+	memset(hdr, 0, sizeof(*hdr));
+	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
+	hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK;
+	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+	memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun));
+	hdr->rtt = ctask->hdr->itt;
+	hdr->refcmdsn = ctask->hdr->cmdsn;
 }
 
 int iscsi_eh_abort(struct scsi_cmnd *sc)
 {
 	struct Scsi_Host *host = sc->device->host;
 	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
-	struct iscsi_cmd_task *ctask;
 	struct iscsi_conn *conn;
-	int rc;
+	struct iscsi_cmd_task *ctask;
+	struct iscsi_tm *hdr;
+	int rc, age;
 
 	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
@@ -1199,19 +1419,23 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 		return SUCCESS;
 	}
 
-	ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
-	conn = ctask->conn;
-
-	conn->eh_abort_cnt++;
-	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
-
 	/*
 	 * If we are not logged in or we have started a new session
 	 * then let the host reset code handle this
 	 */
-	if (session->state != ISCSI_STATE_LOGGED_IN ||
-	    sc->SCp.phase != session->age)
-		goto failed;
+	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN ||
+	    sc->SCp.phase != session->age) {
+		spin_unlock_bh(&session->lock);
+		mutex_unlock(&session->eh_mutex);
+		return FAILED;
+	}
+
+	conn = session->leadconn;
+	conn->eh_abort_cnt++;
+	age = session->age;
+
+	ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
+	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
 
 	/* ctask completed before time out */
 	if (!ctask->sc) {
@@ -1219,27 +1443,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 		goto success;
 	}
 
-	/* what should we do here ? */
-	if (conn->ctask == ctask) {
-		printk(KERN_INFO "iscsi: sc %p itt 0x%x partially sent. "
-		       "Failing abort\n", sc, ctask->itt);
-		goto failed;
-	}
-
 	if (ctask->state == ISCSI_TASK_PENDING) {
 		fail_command(conn, ctask, DID_ABORT << 16);
 		goto success;
 	}
 
-	conn->tmabort_state = TMABORT_INITIAL;
-	rc = iscsi_exec_abort_task(sc, ctask);
-	if (rc || sc->SCp.phase != session->age ||
-	    session->state != ISCSI_STATE_LOGGED_IN)
+	/* only have one tmf outstanding at a time */
+	if (conn->tmf_state != TMF_INITIAL)
+		goto failed;
+	conn->tmf_state = TMF_QUEUED;
+
+	hdr = &conn->tmhdr;
+	iscsi_prep_abort_task_pdu(ctask, hdr);
+
+	if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) {
+		rc = FAILED;
 		goto failed;
-	iscsi_ctask_mtask_cleanup(ctask);
+	}
 
-	switch (conn->tmabort_state) {
-	case TMABORT_SUCCESS:
+	switch (conn->tmf_state) {
+	case TMF_SUCCESS:
 		spin_unlock_bh(&session->lock);
 		iscsi_suspend_tx(conn);
 		/*
@@ -1248,22 +1471,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
 		write_lock_bh(conn->recv_lock);
 		spin_lock(&session->lock);
 		fail_command(conn, ctask, DID_ABORT << 16);
+		conn->tmf_state = TMF_INITIAL;
 		spin_unlock(&session->lock);
 		write_unlock_bh(conn->recv_lock);
 		iscsi_start_tx(conn);
 		goto success_unlocked;
-	case TMABORT_NOT_FOUND:
-		if (!ctask->sc) {
+	case TMF_TIMEDOUT:
+		spin_unlock_bh(&session->lock);
+		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+		goto failed_unlocked;
+	case TMF_NOT_FOUND:
+		if (!sc->SCp.ptr) {
+			conn->tmf_state = TMF_INITIAL;
 			/* ctask completed before tmf abort response */
 			debug_scsi("sc completed while abort in progress\n");
 			goto success;
 		}
 		/* fall through */
 	default:
-		/* timedout or failed */
-		spin_unlock_bh(&session->lock);
-		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
-		goto failed_unlocked;
+		conn->tmf_state = TMF_INITIAL;
+		goto failed;
 	}
 
 success:
@@ -1276,65 +1503,152 @@ success_unlocked:
 failed:
 	spin_unlock_bh(&session->lock);
 failed_unlocked:
-	debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
+	debug_scsi("abort failed [sc %p itt 0x%x]\n", sc,
+		    ctask ? ctask->itt : 0);
 	mutex_unlock(&session->eh_mutex);
 	return FAILED;
 }
 EXPORT_SYMBOL_GPL(iscsi_eh_abort);
 
+static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
+{
+	memset(hdr, 0, sizeof(*hdr));
+	hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE;
+	hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK;
+	hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+	int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
+	hdr->rtt = RESERVED_ITT;
+}
+
+int iscsi_eh_device_reset(struct scsi_cmnd *sc)
+{
+	struct Scsi_Host *host = sc->device->host;
+	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
+	struct iscsi_conn *conn;
+	struct iscsi_tm *hdr;
+	int rc = FAILED;
+
+	debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun);
+
+	mutex_lock(&session->eh_mutex);
+	spin_lock_bh(&session->lock);
+	/*
+	 * Just check if we are not logged in. We cannot check for
+	 * the phase because the reset could come from a ioctl.
+	 */
+	if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN)
+		goto unlock;
+	conn = session->leadconn;
+
+	/* only have one tmf outstanding at a time */
+	if (conn->tmf_state != TMF_INITIAL)
+		goto unlock;
+	conn->tmf_state = TMF_QUEUED;
+
+	hdr = &conn->tmhdr;
+	iscsi_prep_lun_reset_pdu(sc, hdr);
+
+	if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
+				    session->lu_reset_timeout)) {
+		rc = FAILED;
+		goto unlock;
+	}
+
+	switch (conn->tmf_state) {
+	case TMF_SUCCESS:
+		break;
+	case TMF_TIMEDOUT:
+		spin_unlock_bh(&session->lock);
+		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+		goto done;
+	default:
+		conn->tmf_state = TMF_INITIAL;
+		goto unlock;
+	}
+
+	rc = SUCCESS;
+	spin_unlock_bh(&session->lock);
+
+	iscsi_suspend_tx(conn);
+	/* need to grab the recv lock then session lock */
+	write_lock_bh(conn->recv_lock);
+	spin_lock(&session->lock);
+	fail_all_commands(conn, sc->device->lun);
+	conn->tmf_state = TMF_INITIAL;
+	spin_unlock(&session->lock);
+	write_unlock_bh(conn->recv_lock);
+
+	iscsi_start_tx(conn);
+	goto done;
+
+unlock:
+	spin_unlock_bh(&session->lock);
+done:
+	debug_scsi("iscsi_eh_device_reset %s\n",
+		  rc == SUCCESS ? "SUCCESS" : "FAILED");
+	mutex_unlock(&session->eh_mutex);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(iscsi_eh_device_reset);
+
+/*
+ * Pre-allocate a pool of @max items of @item_size. By default, the pool
+ * should be accessed via kfifo_{get,put} on q->queue.
+ * Optionally, the caller can obtain the array of object pointers
+ * by passing in a non-NULL @items pointer
+ */
 int
-iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size)
+iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
 {
-	int i;
+	int i, num_arrays = 1;
 
-	*items = kmalloc(max * sizeof(void*), GFP_KERNEL);
-	if (*items == NULL)
-		return -ENOMEM;
+	memset(q, 0, sizeof(*q));
 
 	q->max = max;
-	q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL);
-	if (q->pool == NULL) {
-		kfree(*items);
-		return -ENOMEM;
-	}
+
+	/* If the user passed an items pointer, he wants a copy of
+	 * the array. */
+	if (items)
+		num_arrays++;
+	q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL);
+	if (q->pool == NULL)
+		goto enomem;
 
 	q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
 			      GFP_KERNEL, NULL);
-	if (q->queue == ERR_PTR(-ENOMEM)) {
-		kfree(q->pool);
-		kfree(*items);
-		return -ENOMEM;
-	}
+	if (q->queue == ERR_PTR(-ENOMEM))
+		goto enomem;
 
 	for (i = 0; i < max; i++) {
-		q->pool[i] = kmalloc(item_size, GFP_KERNEL);
+		q->pool[i] = kzalloc(item_size, GFP_KERNEL);
 		if (q->pool[i] == NULL) {
-			int j;
-
-			for (j = 0; j < i; j++)
-				kfree(q->pool[j]);
-
-			kfifo_free(q->queue);
-			kfree(q->pool);
-			kfree(*items);
-			return -ENOMEM;
+			q->max = i;
+			goto enomem;
 		}
-		memset(q->pool[i], 0, item_size);
-		(*items)[i] = q->pool[i];
 		__kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
 	}
+
+	if (items) {
+		*items = q->pool + max;
+		memcpy(*items, q->pool, max * sizeof(void *));
+	}
+
 	return 0;
+
+enomem:
+	iscsi_pool_free(q);
+	return -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(iscsi_pool_init);
 
-void iscsi_pool_free(struct iscsi_queue *q, void **items)
+void iscsi_pool_free(struct iscsi_pool *q)
 {
 	int i;
 
 	for (i = 0; i < q->max; i++)
-		kfree(items[i]);
-	kfree(q->pool);
-	kfree(items);
+		kfree(q->pool[i]);
+	if (q->pool)
+		kfree(q->pool);
 }
 EXPORT_SYMBOL_GPL(iscsi_pool_free);
 
@@ -1387,7 +1701,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
 		qdepth = ISCSI_DEF_CMD_PER_LUN;
 	}
 
-	if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) ||
+	if (!is_power_of_2(cmds_max) ||
 	    cmds_max >= ISCSI_MGMT_ITT_OFFSET) {
 		if (cmds_max != 0)
 			printk(KERN_ERR "iscsi: invalid can_queue of %d. "
@@ -1411,12 +1725,16 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
 	shost->max_cmd_len = iscsit->max_cmd_len;
 	shost->transportt = scsit;
 	shost->transportt->create_work_queue = 1;
+	shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
 	*hostno = shost->host_no;
 
 	session = iscsi_hostdata(shost->hostdata);
 	memset(session, 0, sizeof(struct iscsi_session));
 	session->host = shost;
 	session->state = ISCSI_STATE_FREE;
+	session->fast_abort = 1;
+	session->lu_reset_timeout = 15;
+	session->abort_timeout = 10;
 	session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
 	session->cmds_max = cmds_max;
 	session->queued_cmdsn = session->cmdsn = initial_cmdsn;
@@ -1479,9 +1797,9 @@ module_put:
 cls_session_fail:
 	scsi_remove_host(shost);
 add_host_fail:
-	iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
+	iscsi_pool_free(&session->mgmtpool);
 mgmtpool_alloc_fail:
-	iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+	iscsi_pool_free(&session->cmdpool);
 cmdpool_alloc_fail:
 	scsi_host_put(shost);
 	return NULL;
@@ -1501,11 +1819,11 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
 	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 	struct module *owner = cls_session->transport->owner;
 
-	iscsi_unblock_session(cls_session);
+	iscsi_remove_session(cls_session);
 	scsi_remove_host(shost);
 
-	iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
-	iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+	iscsi_pool_free(&session->mgmtpool);
+	iscsi_pool_free(&session->cmdpool);
 
 	kfree(session->password);
 	kfree(session->password_in);
@@ -1516,7 +1834,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
 	kfree(session->hwaddress);
 	kfree(session->initiatorname);
 
-	iscsi_destroy_session(cls_session);
+	iscsi_free_session(cls_session);
 	scsi_host_put(shost);
 	module_put(owner);
 }
@@ -1546,17 +1864,17 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
 	conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
 	conn->id = conn_idx;
 	conn->exp_statsn = 0;
-	conn->tmabort_state = TMABORT_INITIAL;
+	conn->tmf_state = TMF_INITIAL;
+
+	init_timer(&conn->transport_timer);
+	conn->transport_timer.data = (unsigned long)conn;
+	conn->transport_timer.function = iscsi_check_transport_timeouts;
+
 	INIT_LIST_HEAD(&conn->run_list);
 	INIT_LIST_HEAD(&conn->mgmt_run_list);
+	INIT_LIST_HEAD(&conn->mgmtqueue);
 	INIT_LIST_HEAD(&conn->xmitqueue);
-
-	/* initialize general immediate & non-immediate PDU commands queue */
-	conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
-			                GFP_KERNEL, NULL);
-	if (conn->mgmtqueue == ERR_PTR(-ENOMEM))
-		goto mgmtqueue_alloc_fail;
-
+	INIT_LIST_HEAD(&conn->requeue);
 	INIT_WORK(&conn->xmitwork, iscsi_xmitworker);
 
 	/* allocate login_mtask used for the login/text sequences */
@@ -1574,7 +1892,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
 		goto login_mtask_data_alloc_fail;
 	conn->login_mtask->data = conn->data = data;
 
-	init_timer(&conn->tmabort_timer);
+	init_timer(&conn->tmf_timer);
 	init_waitqueue_head(&conn->ehwait);
 
 	return cls_conn;
@@ -1583,8 +1901,6 @@ login_mtask_data_alloc_fail:
 	__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
 		    sizeof(void*));
 login_mtask_alloc_fail:
-	kfifo_free(conn->mgmtqueue);
-mgmtqueue_alloc_fail:
 	iscsi_destroy_conn(cls_conn);
 	return NULL;
 }
@@ -1603,8 +1919,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
 	struct iscsi_session *session = conn->session;
 	unsigned long flags;
 
+	del_timer_sync(&conn->transport_timer);
+
 	spin_lock_bh(&session->lock);
-	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
 	conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
 	if (session->leadconn == conn) {
 		/*
@@ -1637,7 +1954,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
 	}
 
 	/* flush queued up work because we free the connection below */
-	scsi_flush_work(session->host);
+	iscsi_suspend_tx(conn);
 
 	spin_lock_bh(&session->lock);
 	kfree(conn->data);
@@ -1648,8 +1965,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
 		session->leadconn = NULL;
 	spin_unlock_bh(&session->lock);
 
-	kfifo_free(conn->mgmtqueue);
-
 	iscsi_destroy_conn(cls_conn);
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_teardown);
@@ -1672,11 +1987,29 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
 		return -EINVAL;
 	}
 
+	if (conn->ping_timeout && !conn->recv_timeout) {
+		printk(KERN_ERR "iscsi: invalid recv timeout of zero "
+		      "Using 5 seconds\n.");
+		conn->recv_timeout = 5;
+	}
+
+	if (conn->recv_timeout && !conn->ping_timeout) {
+		printk(KERN_ERR "iscsi: invalid ping timeout of zero "
+		      "Using 5 seconds.\n");
+		conn->ping_timeout = 5;
+	}
+
 	spin_lock_bh(&session->lock);
 	conn->c_stage = ISCSI_CONN_STARTED;
 	session->state = ISCSI_STATE_LOGGED_IN;
 	session->queued_cmdsn = session->cmdsn;
 
+	conn->last_recv = jiffies;
+	conn->last_ping = jiffies;
+	if (conn->recv_timeout && conn->ping_timeout)
+		mod_timer(&conn->transport_timer,
+			  jiffies + (conn->recv_timeout * HZ));
+
 	switch(conn->stop_stage) {
 	case STOP_CONN_RECOVER:
 		/*
@@ -1684,7 +2017,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
 		 * commands after successful recovery
 		 */
 		conn->stop_stage = 0;
-		conn->tmabort_state = TMABORT_INITIAL;
+		conn->tmf_state = TMF_INITIAL;
 		session->age++;
 		spin_unlock_bh(&session->lock);
 
@@ -1709,55 +2042,27 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
 	struct iscsi_mgmt_task *mtask, *tmp;
 
 	/* handle pending */
-	while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
-		if (mtask == conn->login_mtask)
-			continue;
+	list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) {
 		debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
-		__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
-			    sizeof(void*));
+		iscsi_free_mgmt_task(conn, mtask);
 	}
 
 	/* handle running */
 	list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) {
 		debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt);
-		list_del(&mtask->running);
-
-		if (mtask == conn->login_mtask)
-			continue;
-		__kfifo_put(session->mgmtpool.queue, (void*)&mtask,
-			   sizeof(void*));
+		iscsi_free_mgmt_task(conn, mtask);
 	}
 
 	conn->mtask = NULL;
 }
 
-/* Fail commands. Mutex and session lock held and recv side suspended */
-static void fail_all_commands(struct iscsi_conn *conn)
-{
-	struct iscsi_cmd_task *ctask, *tmp;
-
-	/* flush pending */
-	list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
-		debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc,
-			   ctask->itt);
-		fail_command(conn, ctask, DID_BUS_BUSY << 16);
-	}
-
-	/* fail all other running */
-	list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) {
-		debug_scsi("failing in progress sc %p itt 0x%x\n",
-			   ctask->sc, ctask->itt);
-		fail_command(conn, ctask, DID_BUS_BUSY << 16);
-	}
-
-	conn->ctask = NULL;
-}
-
 static void iscsi_start_session_recovery(struct iscsi_session *session,
 					 struct iscsi_conn *conn, int flag)
 {
 	int old_stop_stage;
 
+	del_timer_sync(&conn->transport_timer);
+
 	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
 	if (conn->stop_stage == STOP_CONN_TERM) {
@@ -1818,7 +2123,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
 	 * flush queues.
 	 */
 	spin_lock_bh(&session->lock);
-	fail_all_commands(conn);
+	fail_all_commands(conn, -1);
 	flush_control_queues(session, conn);
 	spin_unlock_bh(&session->lock);
 	mutex_unlock(&session->eh_mutex);
@@ -1869,6 +2174,21 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
 	uint32_t value;
 
 	switch(param) {
+	case ISCSI_PARAM_FAST_ABORT:
+		sscanf(buf, "%d", &session->fast_abort);
+		break;
+	case ISCSI_PARAM_ABORT_TMO:
+		sscanf(buf, "%d", &session->abort_timeout);
+		break;
+	case ISCSI_PARAM_LU_RESET_TMO:
+		sscanf(buf, "%d", &session->lu_reset_timeout);
+		break;
+	case ISCSI_PARAM_PING_TMO:
+		sscanf(buf, "%d", &conn->ping_timeout);
+		break;
+	case ISCSI_PARAM_RECV_TMO:
+		sscanf(buf, "%d", &conn->recv_timeout);
+		break;
 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
 		sscanf(buf, "%d", &conn->max_recv_dlength);
 		break;
@@ -1983,6 +2303,15 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
 	int len;
 
 	switch(param) {
+	case ISCSI_PARAM_FAST_ABORT:
+		len = sprintf(buf, "%d\n", session->fast_abort);
+		break;
+	case ISCSI_PARAM_ABORT_TMO:
+		len = sprintf(buf, "%d\n", session->abort_timeout);
+		break;
+	case ISCSI_PARAM_LU_RESET_TMO:
+		len = sprintf(buf, "%d\n", session->lu_reset_timeout);
+		break;
 	case ISCSI_PARAM_INITIAL_R2T_EN:
 		len = sprintf(buf, "%d\n", session->initial_r2t_en);
 		break;
@@ -2040,6 +2369,12 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
 	int len;
 
 	switch(param) {
+	case ISCSI_PARAM_PING_TMO:
+		len = sprintf(buf, "%u\n", conn->ping_timeout);
+		break;
+	case ISCSI_PARAM_RECV_TMO:
+		len = sprintf(buf, "%u\n", conn->recv_timeout);
+		break;
 	case ISCSI_PARAM_MAX_RECV_DLENGTH:
 		len = sprintf(buf, "%u\n", conn->max_recv_dlength);
 		break;
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
index c01a40d321d4..18f33cd54411 100644
--- a/drivers/scsi/libsas/Kconfig
+++ b/drivers/scsi/libsas/Kconfig
@@ -38,6 +38,15 @@ config SCSI_SAS_ATA
 		Builds in ATA support into libsas.  Will necessitate
 		the loading of libata along with libsas.
 
+config SCSI_SAS_HOST_SMP
+	bool "Support for SMP interpretation for SAS hosts"
+	default y
+	depends on SCSI_SAS_LIBSAS
+	help
+		Allows sas hosts to receive SMP frames.  Selecting this
+		option builds an SMP interpreter into libsas.  Say
+		N here if you want to save the few kb this consumes.
+
 config SCSI_SAS_LIBSAS_DEBUG
 	bool "Compile the SAS Domain Transport Attributes in debug mode"
 	default y
diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
index fd387b91856e..1ad1323c60fa 100644
--- a/drivers/scsi/libsas/Makefile
+++ b/drivers/scsi/libsas/Makefile
@@ -33,5 +33,7 @@ libsas-y +=  sas_init.o     \
 		sas_dump.o     \
 		sas_discover.o \
 		sas_expander.o \
-		sas_scsi_host.o
+		sas_scsi_host.o \
+		sas_task.o
 libsas-$(CONFIG_SCSI_SAS_ATA) +=	sas_ata.o
+libsas-$(CONFIG_SCSI_SAS_HOST_SMP) +=	sas_host_smp.o
\ No newline at end of file
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 0829b55c64d2..0996f866f14c 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -158,8 +158,8 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
 	struct Scsi_Host *host = sas_ha->core.shost;
 	struct sas_internal *i = to_sas_internal(host->transportt);
 	struct scatterlist *sg;
-	unsigned int num = 0;
 	unsigned int xfer = 0;
+	unsigned int si;
 
 	task = sas_alloc_task(GFP_ATOMIC);
 	if (!task)
@@ -176,22 +176,20 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
 
 	ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis);
 	task->uldd_task = qc;
-	if (is_atapi_taskfile(&qc->tf)) {
+	if (ata_is_atapi(qc->tf.protocol)) {
 		memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len);
 		task->total_xfer_len = qc->nbytes + qc->pad_len;
 		task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
 	} else {
-		ata_for_each_sg(sg, qc) {
-			num++;
+		for_each_sg(qc->sg, sg, qc->n_elem, si)
 			xfer += sg->length;
-		}
 
 		task->total_xfer_len = xfer;
-		task->num_scatter = num;
+		task->num_scatter = si;
 	}
 
 	task->data_dir = qc->dma_dir;
-	task->scatter = qc->__sg;
+	task->scatter = qc->sg;
 	task->ata_task.retry_count = 1;
 	task->task_state_flags = SAS_TASK_STATE_PENDING;
 	qc->lldd_task = task;
@@ -200,7 +198,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
 	case ATA_PROT_NCQ:
 		task->ata_task.use_ncq = 1;
 		/* fall through */
-	case ATA_PROT_ATAPI_DMA:
+	case ATAPI_PROT_DMA:
 	case ATA_PROT_DMA:
 		task->ata_task.dma_xfer = 1;
 		break;
@@ -500,7 +498,7 @@ static int sas_execute_task(struct sas_task *task, void *buffer, int size,
 			goto ex_err;
 		}
 		wait_for_completion(&task->completion);
-		res = -ETASK;
+		res = -ECOMM;
 		if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
 			int res2;
 			SAS_DPRINTK("task aborted, flags:0x%x\n",
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 5f3a0d7b18de..31b9af224243 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -98,7 +98,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
 			dev->dev_type = SATA_PM;
 		else
 			dev->dev_type = SATA_DEV;
-		dev->tproto = SATA_PROTO;
+		dev->tproto = SAS_PROTOCOL_SATA;
 	} else {
 		struct sas_identify_frame *id =
 			(struct sas_identify_frame *) dev->frame_rcvd;
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 8727436b222d..aefd865a5788 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -96,7 +96,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
 		}
 
 		wait_for_completion(&task->completion);
-		res = -ETASK;
+		res = -ECOMM;
 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
 			SAS_DPRINTK("smp task timed out or aborted\n");
 			i->dft->lldd_abort_task(task);
@@ -109,6 +109,16 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
 		    task->task_status.stat == SAM_GOOD) {
 			res = 0;
 			break;
+		} if (task->task_status.resp == SAS_TASK_COMPLETE &&
+		      task->task_status.stat == SAS_DATA_UNDERRUN) {
+			/* no error, but return the number of bytes of
+			 * underrun */
+			res = task->task_status.residual;
+			break;
+		} if (task->task_status.resp == SAS_TASK_COMPLETE &&
+		      task->task_status.stat == SAS_DATA_OVERRUN) {
+			res = -EMSGSIZE;
+			break;
 		} else {
 			SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
 				    "status 0x%x\n", __FUNCTION__,
@@ -656,9 +666,9 @@ static struct domain_device *sas_ex_discover_end_dev(
 	sas_ex_get_linkrate(parent, child, phy);
 
 #ifdef CONFIG_SCSI_SAS_ATA
-	if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
+	if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
 		child->dev_type = SATA_DEV;
-		if (phy->attached_tproto & SAS_PROTO_STP)
+		if (phy->attached_tproto & SAS_PROTOCOL_STP)
 			child->tproto = phy->attached_tproto;
 		if (phy->attached_sata_dev)
 			child->tproto |= SATA_DEV;
@@ -695,7 +705,7 @@ static struct domain_device *sas_ex_discover_end_dev(
 		}
 	} else
 #endif
-	  if (phy->attached_tproto & SAS_PROTO_SSP) {
+	  if (phy->attached_tproto & SAS_PROTOCOL_SSP) {
 		child->dev_type = SAS_END_DEV;
 		rphy = sas_end_device_alloc(phy->port);
 		/* FIXME: error handling */
@@ -1896,11 +1906,9 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 	}
 
 	/* no rphy means no smp target support (ie aic94xx host) */
-	if (!rphy) {
-		printk("%s: can we send a smp request to a host?\n",
-		       __FUNCTION__);
-		return -EINVAL;
-	}
+	if (!rphy)
+		return sas_smp_host_handler(shost, req, rsp);
+
 	type = rphy->identify.device_type;
 
 	if (type != SAS_EDGE_EXPANDER_DEVICE &&
@@ -1926,6 +1934,15 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
 	ret = smp_execute_task(dev, bio_data(req->bio), req->data_len,
 			       bio_data(rsp->bio), rsp->data_len);
+	if (ret > 0) {
+		/* positive number is the untransferred residual */
+		rsp->data_len = ret;
+		req->data_len = 0;
+		ret = 0;
+	} else if (ret == 0) {
+		rsp->data_len = 0;
+		req->data_len = 0;
+	}
 
 	return ret;
 }
diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c
new file mode 100644
index 000000000000..16f93123271e
--- /dev/null
+++ b/drivers/scsi/libsas/sas_host_smp.c
@@ -0,0 +1,274 @@
+/*
+ * Serial Attached SCSI (SAS) Expander discovery and configuration
+ *
+ * Copyright (C) 2007 James E.J. Bottomley
+ *		<James.Bottomley@HansenPartnership.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 only.
+ */
+#include <linux/scatterlist.h>
+#include <linux/blkdev.h>
+
+#include "sas_internal.h"
+
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+static void sas_host_smp_discover(struct sas_ha_struct *sas_ha, u8 *resp_data,
+				  u8 phy_id)
+{
+	struct sas_phy *phy;
+	struct sas_rphy *rphy;
+
+	if (phy_id >= sas_ha->num_phys) {
+		resp_data[2] = SMP_RESP_NO_PHY;
+		return;
+	}
+	resp_data[2] = SMP_RESP_FUNC_ACC;
+
+	phy = sas_ha->sas_phy[phy_id]->phy;
+	resp_data[9] = phy_id;
+	resp_data[13] = phy->negotiated_linkrate;
+	memcpy(resp_data + 16, sas_ha->sas_addr, SAS_ADDR_SIZE);
+	memcpy(resp_data + 24, sas_ha->sas_phy[phy_id]->attached_sas_addr,
+	       SAS_ADDR_SIZE);
+	resp_data[40] = (phy->minimum_linkrate << 4) |
+		phy->minimum_linkrate_hw;
+	resp_data[41] = (phy->maximum_linkrate << 4) |
+		phy->maximum_linkrate_hw;
+
+	if (!sas_ha->sas_phy[phy_id]->port ||
+	    !sas_ha->sas_phy[phy_id]->port->port_dev)
+		return;
+
+	rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
+	resp_data[12] = rphy->identify.device_type << 4;
+	resp_data[14] = rphy->identify.initiator_port_protocols;
+	resp_data[15] = rphy->identify.target_port_protocols;
+}
+
+static void sas_report_phy_sata(struct sas_ha_struct *sas_ha, u8 *resp_data,
+				u8 phy_id)
+{
+	struct sas_rphy *rphy;
+	struct dev_to_host_fis *fis;
+	int i;
+
+	if (phy_id >= sas_ha->num_phys) {
+		resp_data[2] = SMP_RESP_NO_PHY;
+		return;
+	}
+
+	resp_data[2] = SMP_RESP_PHY_NO_SATA;
+
+	if (!sas_ha->sas_phy[phy_id]->port)
+		return;
+
+	rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
+	fis = (struct dev_to_host_fis *)
+		sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd;
+	if (rphy->identify.target_port_protocols != SAS_PROTOCOL_SATA)
+		return;
+
+	resp_data[2] = SMP_RESP_FUNC_ACC;
+	resp_data[9] = phy_id;
+	memcpy(resp_data + 16, sas_ha->sas_phy[phy_id]->attached_sas_addr,
+	       SAS_ADDR_SIZE);
+
+	/* check to see if we have a valid d2h fis */
+	if (fis->fis_type != 0x34)
+		return;
+
+	/* the d2h fis is required by the standard to be in LE format */
+	for (i = 0; i < 20; i += 4) {
+		u8 *dst = resp_data + 24 + i, *src =
+			&sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd[i];
+		dst[0] = src[3];
+		dst[1] = src[2];
+		dst[2] = src[1];
+		dst[3] = src[0];
+	}
+}
+
+static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id,
+			    u8 phy_op, enum sas_linkrate min,
+			    enum sas_linkrate max, u8 *resp_data)
+{
+	struct sas_internal *i =
+		to_sas_internal(sas_ha->core.shost->transportt);
+	struct sas_phy_linkrates rates;
+
+	if (phy_id >= sas_ha->num_phys) {
+		resp_data[2] = SMP_RESP_NO_PHY;
+		return;
+	}
+	switch (phy_op) {
+	case PHY_FUNC_NOP:
+	case PHY_FUNC_LINK_RESET:
+	case PHY_FUNC_HARD_RESET:
+	case PHY_FUNC_DISABLE:
+	case PHY_FUNC_CLEAR_ERROR_LOG:
+	case PHY_FUNC_CLEAR_AFFIL:
+	case PHY_FUNC_TX_SATA_PS_SIGNAL:
+		break;
+
+	default:
+		resp_data[2] = SMP_RESP_PHY_UNK_OP;
+		return;
+	}
+
+	rates.minimum_linkrate = min;
+	rates.maximum_linkrate = max;
+
+	if (i->dft->lldd_control_phy(sas_ha->sas_phy[phy_id], phy_op, &rates))
+		resp_data[2] = SMP_RESP_FUNC_FAILED;
+	else
+		resp_data[2] = SMP_RESP_FUNC_ACC;
+}
+
+int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
+			 struct request *rsp)
+{
+	u8 *req_data = NULL, *resp_data = NULL, *buf;
+	struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+	int error = -EINVAL, resp_data_len = rsp->data_len;
+
+	/* eight is the minimum size for request and response frames */
+	if (req->data_len < 8 || rsp->data_len < 8)
+		goto out;
+
+	if (bio_offset(req->bio) + req->data_len > PAGE_SIZE ||
+	    bio_offset(rsp->bio) + rsp->data_len > PAGE_SIZE) {
+		shost_printk(KERN_ERR, shost,
+			"SMP request/response frame crosses page boundary");
+		goto out;
+	}
+
+	req_data = kzalloc(req->data_len, GFP_KERNEL);
+
+	/* make sure frame can always be built ... we copy
+	 * back only the requested length */
+	resp_data = kzalloc(max(rsp->data_len, 128U), GFP_KERNEL);
+
+	if (!req_data || !resp_data) {
+		error = -ENOMEM;
+		goto out;
+	}
+
+	local_irq_disable();
+	buf = kmap_atomic(bio_page(req->bio), KM_USER0) + bio_offset(req->bio);
+	memcpy(req_data, buf, req->data_len);
+	kunmap_atomic(buf - bio_offset(req->bio), KM_USER0);
+	local_irq_enable();
+
+	if (req_data[0] != SMP_REQUEST)
+		goto out;
+
+	/* always succeeds ... even if we can't process the request
+	 * the result is in the response frame */
+	error = 0;
+
+	/* set up default don't know response */
+	resp_data[0] = SMP_RESPONSE;
+	resp_data[1] = req_data[1];
+	resp_data[2] = SMP_RESP_FUNC_UNK;
+
+	switch (req_data[1]) {
+	case SMP_REPORT_GENERAL:
+		req->data_len -= 8;
+		resp_data_len -= 32;
+		resp_data[2] = SMP_RESP_FUNC_ACC;
+		resp_data[9] = sas_ha->num_phys;
+		break;
+
+	case SMP_REPORT_MANUF_INFO:
+		req->data_len -= 8;
+		resp_data_len -= 64;
+		resp_data[2] = SMP_RESP_FUNC_ACC;
+		memcpy(resp_data + 12, shost->hostt->name,
+		       SAS_EXPANDER_VENDOR_ID_LEN);
+		memcpy(resp_data + 20, "libsas virt phy",
+		       SAS_EXPANDER_PRODUCT_ID_LEN);
+		break;
+
+	case SMP_READ_GPIO_REG:
+		/* FIXME: need GPIO support in the transport class */
+		break;
+
+	case SMP_DISCOVER:
+		req->data_len =- 16;
+		if (req->data_len < 0) {
+			req->data_len = 0;
+			error = -EINVAL;
+			goto out;
+		}
+		resp_data_len -= 56;
+		sas_host_smp_discover(sas_ha, resp_data, req_data[9]);
+		break;
+
+	case SMP_REPORT_PHY_ERR_LOG:
+		/* FIXME: could implement this with additional
+		 * libsas callbacks providing the HW supports it */
+		break;
+
+	case SMP_REPORT_PHY_SATA:
+		req->data_len =- 16;
+		if (req->data_len < 0) {
+			req->data_len = 0;
+			error = -EINVAL;
+			goto out;
+		}
+		resp_data_len -= 60;
+		sas_report_phy_sata(sas_ha, resp_data, req_data[9]);
+		break;
+
+	case SMP_REPORT_ROUTE_INFO:
+		/* Can't implement; hosts have no routes */
+		break;
+
+	case SMP_WRITE_GPIO_REG:
+		/* FIXME: need GPIO support in the transport class */
+		break;
+
+	case SMP_CONF_ROUTE_INFO:
+		/* Can't implement; hosts have no routes */
+		break;
+
+	case SMP_PHY_CONTROL:
+		req->data_len =- 44;
+		if (req->data_len < 0) {
+			req->data_len = 0;
+			error = -EINVAL;
+			goto out;
+		}
+		resp_data_len -= 8;
+		sas_phy_control(sas_ha, req_data[9], req_data[10],
+				req_data[32] >> 4, req_data[33] >> 4,
+				resp_data);
+		break;
+
+	case SMP_PHY_TEST_FUNCTION:
+		/* FIXME: should this be implemented? */
+		break;
+
+	default:
+		/* probably a 2.0 function */
+		break;
+	}
+
+	local_irq_disable();
+	buf = kmap_atomic(bio_page(rsp->bio), KM_USER0) + bio_offset(rsp->bio);
+	memcpy(buf, resp_data, rsp->data_len);
+	flush_kernel_dcache_page(bio_page(rsp->bio));
+	kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0);
+	local_irq_enable();
+	rsp->data_len = resp_data_len;
+
+ out:
+	kfree(req_data);
+	kfree(resp_data);
+	return error;
+}
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 2b8213b1832d..b4f9368f116a 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -45,7 +45,7 @@
 void sas_scsi_recover_host(struct Scsi_Host *shost);
 
 int sas_show_class(enum sas_class class, char *buf);
-int sas_show_proto(enum sas_proto proto, char *buf);
+int sas_show_proto(enum sas_protocol proto, char *buf);
 int sas_show_linkrate(enum sas_linkrate linkrate, char *buf);
 int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
 
@@ -80,6 +80,20 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
 
 void sas_hae_reset(struct work_struct *work);
 
+#ifdef CONFIG_SCSI_SAS_HOST_SMP
+extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
+				struct request *rsp);
+#else
+static inline int sas_smp_host_handler(struct Scsi_Host *shost,
+				       struct request *req,
+				       struct request *rsp)
+{
+	shost_printk(KERN_ERR, shost,
+		"Cannot send SMP to a sas host (not enabled in CONFIG)\n");
+	return -EINVAL;
+}
+#endif
+
 static inline void sas_queue_event(int event, spinlock_t *lock,
 				   unsigned long *pending,
 				   struct work_struct *work,
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 7663841eb4cf..f869fba86807 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -108,7 +108,7 @@ static void sas_scsi_task_done(struct sas_task *task)
 			break;
 		case SAM_CHECK_COND:
 			memcpy(sc->sense_buffer, ts->buf,
-			       max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
+			       min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
 			stat = SAM_CHECK_COND;
 			break;
 		default:
@@ -148,7 +148,6 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
 	if (!task)
 		return NULL;
 
-	*(u32 *)cmd->sense_buffer = 0;
 	task->uldd_task = cmd;
 	ASSIGN_SAS_TASK(cmd, task);
 
@@ -200,6 +199,10 @@ int sas_queue_up(struct sas_task *task)
  */
 int sas_queuecommand(struct scsi_cmnd *cmd,
 		     void (*scsi_done)(struct scsi_cmnd *))
+	__releases(host->host_lock)
+	__acquires(dev->sata_dev.ap->lock)
+	__releases(dev->sata_dev.ap->lock)
+	__acquires(host->host_lock)
 {
 	int res = 0;
 	struct domain_device *dev = cmd_to_domain_dev(cmd);
@@ -410,7 +413,7 @@ static int sas_recover_I_T(struct domain_device *dev)
 }
 
 /* Find the sas_phy that's attached to this device */
-struct sas_phy *find_local_sas_phy(struct domain_device *dev)
+static struct sas_phy *find_local_sas_phy(struct domain_device *dev)
 {
 	struct domain_device *pdev = dev->parent;
 	struct ex_phy *exphy = NULL;
@@ -464,7 +467,7 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
 	res = sas_phy_reset(phy, 1);
 	if (res)
 		SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
-			    phy->dev.kobj.k_name,
+			    kobject_name(&phy->dev.kobj),
 			    res);
 	if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE)
 		return SUCCESS;
diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c
new file mode 100644
index 000000000000..594524d5bfa1
--- /dev/null
+++ b/drivers/scsi/libsas/sas_task.c
@@ -0,0 +1,36 @@
+#include <linux/kernel.h>
+#include <scsi/sas.h>
+#include <scsi/libsas.h>
+
+/* fill task_status_struct based on SSP response frame */
+void sas_ssp_task_response(struct device *dev, struct sas_task *task,
+			   struct ssp_response_iu *iu)
+{
+	struct task_status_struct *tstat = &task->task_status;
+
+	tstat->resp = SAS_TASK_COMPLETE;
+
+	if (iu->datapres == 0)
+		tstat->stat = iu->status;
+	else if (iu->datapres == 1)
+		tstat->stat = iu->resp_data[3];
+	else if (iu->datapres == 2) {
+		tstat->stat = SAM_CHECK_COND;
+		tstat->buf_valid_size =
+			min_t(int, SAS_STATUS_BUF_SIZE,
+			      be32_to_cpu(iu->sense_data_len));
+		memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size);
+
+		if (iu->status != SAM_CHECK_COND)
+			dev_printk(KERN_WARNING, dev,
+				   "dev %llx sent sense data, but "
+				   "stat(%x) is not CHECK CONDITION\n",
+				   SAS_ADDR(task->dev->sas_addr),
+				   iu->status);
+	}
+	else
+		/* when datapres contains corrupt/unknown value... */
+		tstat->stat = SAM_CHECK_COND;
+}
+EXPORT_SYMBOL_GPL(sas_ssp_task_response);
+
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
index 2ad0a27dbaab..6d6a76e65a6c 100644
--- a/drivers/scsi/libsrp.c
+++ b/drivers/scsi/libsrp.c
@@ -192,18 +192,18 @@ static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md,
 
 	if (dma_map) {
 		iue = (struct iu_entry *) sc->SCp.ptr;
-		sg = sc->request_buffer;
+		sg = scsi_sglist(sc);
 
-		dprintk("%p %u %u %d\n", iue, sc->request_bufflen,
-			md->len, sc->use_sg);
+		dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc),
+			md->len, scsi_sg_count(sc));
 
-		nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg,
+		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
 				 DMA_BIDIRECTIONAL);
 		if (!nsg) {
-			printk("fail to map %p %d\n", iue, sc->use_sg);
+			printk("fail to map %p %d\n", iue, scsi_sg_count(sc));
 			return 0;
 		}
-		len = min(sc->request_bufflen, md->len);
+		len = min(scsi_bufflen(sc), md->len);
 	} else
 		len = md->len;
 
@@ -229,10 +229,10 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
 
 	if (dma_map || ext_desc) {
 		iue = (struct iu_entry *) sc->SCp.ptr;
-		sg = sc->request_buffer;
+		sg = scsi_sglist(sc);
 
 		dprintk("%p %u %u %d %d\n",
-			iue, sc->request_bufflen, id->len,
+			iue, scsi_bufflen(sc), id->len,
 			cmd->data_in_desc_cnt, cmd->data_out_desc_cnt);
 	}
 
@@ -268,13 +268,14 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
 
 rdma:
 	if (dma_map) {
-		nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL);
+		nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc),
+				 DMA_BIDIRECTIONAL);
 		if (!nsg) {
-			eprintk("fail to map %p %d\n", iue, sc->use_sg);
+			eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc));
 			err = -EIO;
 			goto free_mem;
 		}
-		len = min(sc->request_bufflen, id->len);
+		len = min(scsi_bufflen(sc), id->len);
 	} else
 		len = id->len;
 
@@ -425,8 +426,8 @@ int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
 
 	sc->SCp.ptr = info;
 	memcpy(sc->cmnd, cmd->cdb, MAX_COMMAND_SIZE);
-	sc->request_bufflen = len;
-	sc->request_buffer = (void *) (unsigned long) addr;
+	sc->sdb.length = len;
+	sc->sdb.table.sgl = (void *) (unsigned long) addr;
 	sc->tag = tag;
 	err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun,
 				     cmd->tag);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index ba3ecab9baf3..f26b9538affe 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -29,7 +29,8 @@ struct lpfc_sli2_slim;
 #define LPFC_MAX_NS_RETRY	3	/* Number of retry attempts to contact
 					   the NameServer  before giving up. */
 #define LPFC_CMD_PER_LUN	3	/* max outstanding cmds per lun */
-#define LPFC_SG_SEG_CNT		64	/* sg element count per scsi cmnd */
+#define LPFC_DEFAULT_SG_SEG_CNT	64	/* sg element count per scsi cmnd */
+#define LPFC_MAX_SG_SEG_CNT	256	/* sg element count per scsi cmnd */
 #define LPFC_IOCB_LIST_CNT	2250	/* list of IOCBs for fast-path usage. */
 #define LPFC_Q_RAMP_UP_INTERVAL 120     /* lun q_depth ramp up interval */
 
@@ -68,6 +69,7 @@ struct lpfc_dmabuf {
 	struct list_head list;
 	void *virt;		/* virtual address ptr */
 	dma_addr_t phys;	/* mapped address */
+	uint32_t   buffer_tag;	/* used for tagged queue ring */
 };
 
 struct lpfc_dma_pool {
@@ -272,10 +274,16 @@ struct lpfc_vport {
 #define FC_ABORT_DISCOVERY      0x8000	 /* we want to abort discovery */
 #define FC_NDISC_ACTIVE         0x10000	 /* NPort discovery active */
 #define FC_BYPASSED_MODE        0x20000	 /* NPort is in bypassed mode */
-#define FC_RFF_NOT_SUPPORTED    0x40000	 /* RFF_ID was rejected by switch */
 #define FC_VPORT_NEEDS_REG_VPI	0x80000  /* Needs to have its vpi registered */
 #define FC_RSCN_DEFERRED	0x100000 /* A deferred RSCN being processed */
 
+	uint32_t ct_flags;
+#define FC_CT_RFF_ID		0x1	 /* RFF_ID accepted by switch */
+#define FC_CT_RNN_ID		0x2	 /* RNN_ID accepted by switch */
+#define FC_CT_RSNN_NN		0x4	 /* RSNN_NN accepted by switch */
+#define FC_CT_RSPN_ID		0x8	 /* RSPN_ID accepted by switch */
+#define FC_CT_RFT_ID		0x10	 /* RFT_ID accepted by switch */
+
 	struct list_head fc_nodes;
 
 	/* Keep counters for the number of entries in each list. */
@@ -344,6 +352,7 @@ struct lpfc_vport {
 	uint32_t cfg_discovery_threads;
 	uint32_t cfg_log_verbose;
 	uint32_t cfg_max_luns;
+	uint32_t cfg_enable_da_id;
 
 	uint32_t dev_loss_tmo_changed;
 
@@ -360,6 +369,7 @@ struct lpfc_vport {
 
 struct hbq_s {
 	uint16_t entry_count;	  /* Current number of HBQ slots */
+	uint16_t buffer_count;	  /* Current number of buffers posted */
 	uint32_t next_hbqPutIdx;  /* Index to next HBQ slot to use */
 	uint32_t hbqPutIdx;	  /* HBQ slot to use */
 	uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */
@@ -377,6 +387,11 @@ struct hbq_s {
 #define LPFC_ELS_HBQ	0
 #define LPFC_EXTRA_HBQ	1
 
+enum hba_temp_state {
+	HBA_NORMAL_TEMP,
+	HBA_OVER_TEMP
+};
+
 struct lpfc_hba {
 	struct lpfc_sli sli;
 	uint32_t sli_rev;		/* SLI2 or SLI3 */
@@ -457,7 +472,8 @@ struct lpfc_hba {
 	uint64_t cfg_soft_wwnn;
 	uint64_t cfg_soft_wwpn;
 	uint32_t cfg_hba_queue_depth;
-
+	uint32_t cfg_enable_hba_reset;
+	uint32_t cfg_enable_hba_heartbeat;
 
 	lpfc_vpd_t vpd;		/* vital product data */
 
@@ -544,8 +560,7 @@ struct lpfc_hba {
 	struct list_head port_list;
 	struct lpfc_vport *pport;	/* physical lpfc_vport pointer */
 	uint16_t max_vpi;		/* Maximum virtual nports */
-#define LPFC_MAX_VPI 100		/* Max number of VPI supported */
-#define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */
+#define LPFC_MAX_VPI 0xFFFF		/* Max number of VPI supported */
 	unsigned long *vpi_bmask;	/* vpi allocation table */
 
 	/* Data structure used by fabric iocb scheduler */
@@ -563,16 +578,30 @@ struct lpfc_hba {
 	struct dentry *hba_debugfs_root;
 	atomic_t debugfs_vport_count;
 	struct dentry *debug_hbqinfo;
-	struct dentry *debug_dumpslim;
+	struct dentry *debug_dumpHostSlim;
+	struct dentry *debug_dumpHBASlim;
 	struct dentry *debug_slow_ring_trc;
 	struct lpfc_debugfs_trc *slow_ring_trc;
 	atomic_t slow_ring_trc_cnt;
 #endif
 
+	/* Used for deferred freeing of ELS data buffers */
+	struct list_head elsbuf;
+	int elsbuf_cnt;
+	int elsbuf_prev_cnt;
+
+	uint8_t temp_sensor_support;
 	/* Fields used for heart beat. */
 	unsigned long last_completion_time;
 	struct timer_list hb_tmofunc;
 	uint8_t hb_outstanding;
+	/*
+	 * Following bit will be set for all buffer tags which are not
+	 * associated with any HBQ.
+	 */
+#define QUE_BUFTAG_BIT  (1<<31)
+	uint32_t buffer_tag_count;
+	enum hba_temp_state over_temp_state;
 };
 
 static inline struct Scsi_Host *
@@ -598,5 +627,15 @@ lpfc_is_link_up(struct lpfc_hba *phba)
 		phba->link_state == LPFC_HBA_READY;
 }
 
-#define FC_REG_DUMP_EVENT	0x10	/* Register for Dump events */
+#define FC_REG_DUMP_EVENT		0x10	/* Register for Dump events */
+#define FC_REG_TEMPERATURE_EVENT	0x20    /* Register for temperature
+						   event */
 
+struct temp_event {
+	uint32_t event_type;
+	uint32_t event_code;
+	uint32_t data;
+};
+#define LPFC_CRIT_TEMP		0x1
+#define LPFC_THRESHOLD_TEMP	0x2
+#define LPFC_NORMAL_TEMP	0x3
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 80a11218b9bb..4bae4a2ed2f1 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -45,6 +45,10 @@
 #define LPFC_MIN_DEVLOSS_TMO 1
 #define LPFC_MAX_DEVLOSS_TMO 255
 
+#define LPFC_MAX_LINK_SPEED 8
+#define LPFC_LINK_SPEED_BITMAP 0x00000117
+#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8"
+
 static void
 lpfc_jedec_to_ascii(int incr, char hdw[])
 {
@@ -86,6 +90,15 @@ lpfc_serialnum_show(struct class_device *cdev, char *buf)
 }
 
 static ssize_t
+lpfc_temp_sensor_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+	struct lpfc_hba   *phba = vport->phba;
+	return snprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support);
+}
+
+static ssize_t
 lpfc_modeldesc_show(struct class_device *cdev, char *buf)
 {
 	struct Scsi_Host  *shost = class_to_shost(cdev);
@@ -178,12 +191,9 @@ lpfc_state_show(struct class_device *cdev, char *buf)
 	case LPFC_LINK_UP:
 	case LPFC_CLEAR_LA:
 	case LPFC_HBA_READY:
-		len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n");
+		len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - ");
 
 		switch (vport->port_state) {
-			len += snprintf(buf + len, PAGE_SIZE-len,
-					"initializing\n");
-			break;
 		case LPFC_LOCAL_CFG_LINK:
 			len += snprintf(buf + len, PAGE_SIZE-len,
 					"Configuring Link\n");
@@ -252,8 +262,7 @@ lpfc_issue_lip(struct Scsi_Host *shost)
 	int mbxstatus = MBXERR_ERROR;
 
 	if ((vport->fc_flag & FC_OFFLINE_MODE) ||
-	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) ||
-	    (vport->port_state != LPFC_VPORT_READY))
+	    (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
 		return -EPERM;
 
 	pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
@@ -305,12 +314,14 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
 
 	psli = &phba->sli;
 
+	/* Wait a little for things to settle down, but not
+	 * long enough for dev loss timeout to expire.
+	 */
 	for (i = 0; i < psli->num_rings; i++) {
 		pring = &psli->ring[i];
-		/* The linkdown event takes 30 seconds to timeout. */
 		while (pring->txcmplq_cnt) {
 			msleep(10);
-			if (cnt++ > 3000) {
+			if (cnt++ > 500) {  /* 5 secs */
 				lpfc_printf_log(phba,
 					KERN_WARNING, LOG_INIT,
 					"0466 Outstanding IO when "
@@ -336,6 +347,9 @@ lpfc_selective_reset(struct lpfc_hba *phba)
 	struct completion online_compl;
 	int status = 0;
 
+	if (!phba->cfg_enable_hba_reset)
+		return -EIO;
+
 	status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 
 	if (status != 0)
@@ -409,6 +423,8 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
 	struct completion online_compl;
 	int status=0;
 
+	if (!phba->cfg_enable_hba_reset)
+		return -EACCES;
 	init_completion(&online_compl);
 
 	if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
@@ -908,6 +924,8 @@ static CLASS_DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL);
 static CLASS_DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL);
 static CLASS_DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL);
 static CLASS_DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL);
+static CLASS_DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show,
+			 NULL);
 
 
 static char *lpfc_soft_wwn_key = "C99G71SL8032A";
@@ -971,6 +989,14 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
 	unsigned int i, j, cnt=count;
 	u8 wwpn[8];
 
+	if (!phba->cfg_enable_hba_reset)
+		return -EACCES;
+	spin_lock_irq(&phba->hbalock);
+	if (phba->over_temp_state == HBA_OVER_TEMP) {
+		spin_unlock_irq(&phba->hbalock);
+		return -EACCES;
+	}
+	spin_unlock_irq(&phba->hbalock);
 	/* count may include a LF at end of string */
 	if (buf[cnt-1] == '\n')
 		cnt--;
@@ -1102,7 +1128,13 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
 		 " 2 - select SLI-2 even on SLI-3 capable HBAs,"
 		 " 3 - select SLI-3");
 
-LPFC_ATTR_R(enable_npiv, 0, 0, 1, "Enable NPIV functionality");
+int lpfc_enable_npiv = 0;
+module_param(lpfc_enable_npiv, int, 0);
+MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality");
+lpfc_param_show(enable_npiv);
+lpfc_param_init(enable_npiv, 0, 0, 1);
+static CLASS_DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO,
+			 lpfc_enable_npiv_show, NULL);
 
 /*
 # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -1248,6 +1280,13 @@ LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff,
 		       "Verbose logging bit-mask");
 
 /*
+# lpfc_enable_da_id: This turns on the DA_ID CT command that deregisters
+# objects that have been registered with the nameserver after login.
+*/
+LPFC_VPORT_ATTR_R(enable_da_id, 0, 0, 1,
+		  "Deregister nameserver objects before LOGO");
+
+/*
 # lun_queue_depth:  This parameter is used to limit the number of outstanding
 # commands per FCP LUN. Value range is [1,128]. Default value is 30.
 */
@@ -1369,7 +1408,33 @@ LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1,
 # Set loop mode if you want to run as an NL_Port. Value range is [0,0x6].
 # Default value is 0.
 */
-LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
+static int
+lpfc_topology_set(struct lpfc_hba *phba, int val)
+{
+	int err;
+	uint32_t prev_val;
+	if (val >= 0 && val <= 6) {
+		prev_val = phba->cfg_topology;
+		phba->cfg_topology = val;
+		err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
+		if (err)
+			phba->cfg_topology = prev_val;
+		return err;
+	}
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+		"%d:0467 lpfc_topology attribute cannot be set to %d, "
+		"allowed range is [0, 6]\n",
+		phba->brd_no, val);
+	return -EINVAL;
+}
+static int lpfc_topology = 0;
+module_param(lpfc_topology, int, 0);
+MODULE_PARM_DESC(lpfc_topology, "Select Fibre Channel topology");
+lpfc_param_show(topology)
+lpfc_param_init(topology, 0, 0, 6)
+lpfc_param_store(topology)
+static CLASS_DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR,
+		lpfc_topology_show, lpfc_topology_store);
 
 /*
 # lpfc_link_speed: Link speed selection for initializing the Fibre Channel
@@ -1381,7 +1446,59 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
 #       8  = 8 Gigabaud
 # Value range is [0,8]. Default value is 0.
 */
-LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed");
+static int
+lpfc_link_speed_set(struct lpfc_hba *phba, int val)
+{
+	int err;
+	uint32_t prev_val;
+
+	if (((val == LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) ||
+		((val == LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) ||
+		((val == LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) ||
+		((val == LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) ||
+		((val == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)))
+		return -EINVAL;
+
+	if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED)
+		&& (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
+		prev_val = phba->cfg_link_speed;
+		phba->cfg_link_speed = val;
+		err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport));
+		if (err)
+			phba->cfg_link_speed = prev_val;
+		return err;
+	}
+
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+		"%d:0469 lpfc_link_speed attribute cannot be set to %d, "
+		"allowed range is [0, 8]\n",
+		phba->brd_no, val);
+	return -EINVAL;
+}
+
+static int lpfc_link_speed = 0;
+module_param(lpfc_link_speed, int, 0);
+MODULE_PARM_DESC(lpfc_link_speed, "Select link speed");
+lpfc_param_show(link_speed)
+static int
+lpfc_link_speed_init(struct lpfc_hba *phba, int val)
+{
+	if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED)
+		&& (LPFC_LINK_SPEED_BITMAP & (1 << val))) {
+		phba->cfg_link_speed = val;
+		return 0;
+	}
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"0454 lpfc_link_speed attribute cannot "
+			"be set to %d, allowed values are "
+			"["LPFC_LINK_SPEED_STRING"]\n", val);
+	phba->cfg_link_speed = 0;
+	return -EINVAL;
+}
+
+lpfc_param_store(link_speed)
+static CLASS_DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR,
+		lpfc_link_speed_show, lpfc_link_speed_store);
 
 /*
 # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
@@ -1479,7 +1596,30 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
 */
 LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible");
 
+/*
+# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
+#       0  = HBA resets disabled
+#       1  = HBA resets enabled (default)
+# Value range is [0,1]. Default value is 1.
+*/
+LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver.");
+
+/*
+# lpfc_enable_hba_heartbeat: Enable HBA heartbeat timer..
+#       0  = HBA Heartbeat disabled
+#       1  = HBA Heartbeat enabled (default)
+# Value range is [0,1]. Default value is 1.
+*/
+LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat.");
 
+/*
+ * lpfc_sg_seg_cnt: Initial Maximum DMA Segment Count
+ * This value can be set to values between 64 and 256. The default value is
+ * 64, but may be increased to allow for larger Max I/O sizes. The scsi layer
+ * will be allowed to request I/Os of sizes up to (MAX_SEG_COUNT * SEG_SIZE).
+ */
+LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT,
+	    LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count");
 
 struct class_device_attribute *lpfc_hba_attrs[] = {
 	&class_device_attr_info,
@@ -1494,6 +1634,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
 	&class_device_attr_state,
 	&class_device_attr_num_discovered_ports,
 	&class_device_attr_lpfc_drvr_version,
+	&class_device_attr_lpfc_temp_sensor,
 	&class_device_attr_lpfc_log_verbose,
 	&class_device_attr_lpfc_lun_queue_depth,
 	&class_device_attr_lpfc_hba_queue_depth,
@@ -1530,6 +1671,9 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
 	&class_device_attr_lpfc_soft_wwnn,
 	&class_device_attr_lpfc_soft_wwpn,
 	&class_device_attr_lpfc_soft_wwn_enable,
+	&class_device_attr_lpfc_enable_hba_reset,
+	&class_device_attr_lpfc_enable_hba_heartbeat,
+	&class_device_attr_lpfc_sg_seg_cnt,
 	NULL,
 };
 
@@ -1552,6 +1696,7 @@ struct class_device_attribute *lpfc_vport_attrs[] = {
 	&class_device_attr_lpfc_max_luns,
 	&class_device_attr_nport_evt_cnt,
 	&class_device_attr_npiv_info,
+	&class_device_attr_lpfc_enable_da_id,
 	NULL,
 };
 
@@ -1727,13 +1872,18 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
 
 	spin_lock_irq(&phba->hbalock);
 
+	if (phba->over_temp_state == HBA_OVER_TEMP) {
+		sysfs_mbox_idle(phba);
+		spin_unlock_irq(&phba->hbalock);
+		return  -EACCES;
+	}
+
 	if (off == 0 &&
 	    phba->sysfs_mbox.state  == SMBOX_WRITING &&
 	    phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) {
 
 		switch (phba->sysfs_mbox.mbox->mb.mbxCommand) {
 			/* Offline only */
-		case MBX_WRITE_NV:
 		case MBX_INIT_LINK:
 		case MBX_DOWN_LINK:
 		case MBX_CONFIG_LINK:
@@ -1744,9 +1894,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
 		case MBX_DUMP_CONTEXT:
 		case MBX_RUN_DIAGS:
 		case MBX_RESTART:
-		case MBX_FLASH_WR_ULA:
 		case MBX_SET_MASK:
-		case MBX_SET_SLIM:
 		case MBX_SET_DEBUG:
 			if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
 				printk(KERN_WARNING "mbox_read:Command 0x%x "
@@ -1756,6 +1904,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
 				spin_unlock_irq(&phba->hbalock);
 				return -EPERM;
 			}
+		case MBX_WRITE_NV:
+		case MBX_WRITE_VPARMS:
 		case MBX_LOAD_SM:
 		case MBX_READ_NV:
 		case MBX_READ_CONFIG:
@@ -1772,6 +1922,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
 		case MBX_LOAD_EXP_ROM:
 		case MBX_BEACON:
 		case MBX_DEL_LD_ENTRY:
+		case MBX_SET_VARIABLE:
+		case MBX_WRITE_WWN:
 			break;
 		case MBX_READ_SPARM64:
 		case MBX_READ_LA:
@@ -1793,6 +1945,17 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
 			return -EPERM;
 		}
 
+		/* If HBA encountered an error attention, allow only DUMP
+		 * mailbox command until the HBA is restarted.
+		 */
+		if ((phba->pport->stopped) &&
+			(phba->sysfs_mbox.mbox->mb.mbxCommand
+				!= MBX_DUMP_MEMORY)) {
+			sysfs_mbox_idle(phba);
+			spin_unlock_irq(&phba->hbalock);
+			return -EPERM;
+		}
+
 		phba->sysfs_mbox.mbox->vport = vport;
 
 		if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
@@ -1993,7 +2156,8 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
 				fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 			break;
 		}
-	}
+	} else
+		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
 
 	spin_unlock_irq(shost->host_lock);
 }
@@ -2013,7 +2177,7 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost)
 		node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn);
 	else
 		/* fabric is local port if there is no F/FL_Port */
-		node_name = wwn_to_u64(vport->fc_nodename.u.wwn);
+		node_name = 0;
 
 	spin_unlock_irq(shost->host_lock);
 
@@ -2337,8 +2501,6 @@ struct fc_function_template lpfc_transport_functions = {
 	.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
 	.terminate_rport_io = lpfc_terminate_rport_io,
 
-	.vport_create = lpfc_vport_create,
-	.vport_delete = lpfc_vport_delete,
 	.dd_fcvport_size = sizeof(struct lpfc_vport *),
 };
 
@@ -2414,21 +2576,23 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
 	lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
 	lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
 	lpfc_use_msi_init(phba, lpfc_use_msi);
+	lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
+	lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);
 	phba->cfg_poll = lpfc_poll;
 	phba->cfg_soft_wwnn = 0L;
 	phba->cfg_soft_wwpn = 0L;
-	/*
-	 * The total number of segments is the configuration value plus 2
-	 * since the IOCB need a command and response bde.
-	 */
-	phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2;
+	lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
+	/* Also reinitialize the host templates with new values. */
+	lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt;
+	lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt;
 	/*
 	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
-	 * used to create the sg_dma_buf_pool must be dynamically calculated
+	 * used to create the sg_dma_buf_pool must be dynamically calculated.
+	 * 2 segments are added since the IOCB needs a command and response bde.
 	 */
 	phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
 			sizeof(struct fcp_rsp) +
-			(phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
+			((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64));
 	lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
 	return;
 }
@@ -2448,5 +2612,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
 	lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
 	lpfc_max_luns_init(vport, lpfc_max_luns);
 	lpfc_scan_down_init(vport, lpfc_scan_down);
+	lpfc_enable_da_id_init(vport, lpfc_enable_da_id);
 	return;
 }
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index a599e1510710..50fcb7c930bc 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -23,6 +23,8 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
 struct fc_rport;
 void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
 void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
+
 void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
 int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
 		 struct lpfc_dmabuf *mp);
@@ -43,9 +45,9 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
 struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
 void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
 int lpfc_linkdown(struct lpfc_hba *);
+void lpfc_port_link_failure(struct lpfc_vport *);
 void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 
-void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -66,15 +68,15 @@ int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
 void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t);
 struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
 int  lpfc_nlp_put(struct lpfc_nodelist *);
+int  lpfc_nlp_not_used(struct lpfc_nodelist *ndlp);
 struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t);
 void lpfc_disc_list_loopmap(struct lpfc_vport *);
 void lpfc_disc_start(struct lpfc_vport *);
-void lpfc_disc_flush_list(struct lpfc_vport *);
 void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
+void lpfc_cleanup(struct lpfc_vport *);
 void lpfc_disc_timeout(unsigned long);
 
 struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
-struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
 
 void lpfc_worker_wake_up(struct lpfc_hba *);
 int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
@@ -82,17 +84,17 @@ int lpfc_do_work(void *);
 int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *,
 			    uint32_t);
 
-void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *,
-			struct lpfc_nodelist *);
 void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
 int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
 		     struct serv_parm *, uint32_t);
 int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_more_plogi(struct lpfc_vport *);
+void lpfc_more_adisc(struct lpfc_vport *);
+void lpfc_end_rscn(struct lpfc_vport *);
 int lpfc_els_chk_latt(struct lpfc_vport *);
 int lpfc_els_abort_flogi(struct lpfc_hba *);
 int lpfc_initial_flogi(struct lpfc_vport *);
 int lpfc_initial_fdisc(struct lpfc_vport *);
-int lpfc_issue_els_fdisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
 int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t);
 int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
 int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
@@ -112,7 +114,6 @@ int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
 void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *);
 void lpfc_els_retry_delay(unsigned long);
 void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
-void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *);
 void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
 			  struct lpfc_iocbq *);
 int lpfc_els_handle_rscn(struct lpfc_vport *);
@@ -124,7 +125,6 @@ int lpfc_els_disc_adisc(struct lpfc_vport *);
 int lpfc_els_disc_plogi(struct lpfc_vport *);
 void lpfc_els_timeout(unsigned long);
 void lpfc_els_timeout_handler(struct lpfc_vport *);
-void lpfc_hb_timeout(unsigned long);
 void lpfc_hb_timeout_handler(struct lpfc_hba *);
 
 void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
@@ -142,7 +142,6 @@ void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
 int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
 void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
 int lpfc_online(struct lpfc_hba *);
-void lpfc_block_mgmt_io(struct lpfc_hba *);
 void lpfc_unblock_mgmt_io(struct lpfc_hba *);
 void lpfc_offline_prep(struct lpfc_hba *);
 void lpfc_offline(struct lpfc_hba *);
@@ -165,7 +164,6 @@ int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
 
 void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
 	uint32_t , LPFC_MBOXQ_t *);
-struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t);
 struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *);
 void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *);
 
@@ -178,7 +176,6 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba);
 void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba);
 struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
 void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
-void __lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
 uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
 
 void lpfc_reset_barrier(struct lpfc_hba * phba);
@@ -204,11 +201,14 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
 struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
 					     struct lpfc_sli_ring *,
 					     dma_addr_t);
+
+uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *);
+struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *,
+			struct lpfc_sli_ring *, uint32_t );
+
 int lpfc_sli_hbq_count(void);
-int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
 int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
 void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *);
-struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t);
 int lpfc_sli_hbq_size(void);
 int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
 			       struct lpfc_iocbq *);
@@ -219,9 +219,6 @@ int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t,
 void lpfc_mbox_timeout(unsigned long);
 void lpfc_mbox_timeout_handler(struct lpfc_hba *);
 
-struct lpfc_nodelist *__lpfc_find_node(struct lpfc_vport *, node_filter,
-				       void *);
-struct lpfc_nodelist *lpfc_find_node(struct lpfc_vport *, node_filter, void *);
 struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t);
 struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *,
 					 struct lpfc_name *);
@@ -260,6 +257,7 @@ extern struct scsi_host_template lpfc_vport_template;
 extern struct fc_function_template lpfc_transport_functions;
 extern struct fc_function_template lpfc_vport_transport_functions;
 extern int lpfc_sli_mode;
+extern int lpfc_enable_npiv;
 
 int  lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
 void lpfc_terminate_rport_io(struct fc_rport *);
@@ -281,11 +279,8 @@ extern void lpfc_debugfs_slow_ring_trc(struct lpfc_hba *, char *, uint32_t,
 extern struct lpfc_hbq_init *lpfc_hbq_defs[];
 
 /* Interface exported by fabric iocb scheduler */
-int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
-void lpfc_fabric_abort_vport(struct lpfc_vport *);
 void lpfc_fabric_abort_nport(struct lpfc_nodelist *);
 void lpfc_fabric_abort_hba(struct lpfc_hba *);
-void lpfc_fabric_abort_flogi(struct lpfc_hba *);
 void lpfc_fabric_block_timeout(unsigned long);
 void lpfc_unblock_fabric_iocbs(struct lpfc_hba *);
 void lpfc_adjust_queue_depth(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index c701e4d611a9..92441ce610ed 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -19,7 +19,7 @@
  *******************************************************************/
 
 /*
- * Fibre Channel SCSI LAN Device Driver CT support
+ * Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS
  */
 
 #include <linux/blkdev.h>
@@ -57,45 +57,27 @@
 
 static char *lpfc_release_version = LPFC_DRIVER_VERSION;
 
-/*
- * lpfc_ct_unsol_event
- */
 static void
-lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
-		     struct lpfc_dmabuf *mp, uint32_t size)
+lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+			  struct lpfc_dmabuf *mp, uint32_t size)
 {
 	if (!mp) {
-		printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, "
-		       "piocbq = %p, status = x%x, mp = %p, size = %d\n",
-		       __FUNCTION__, __LINE__,
-		       piocbq, piocbq->iocb.ulpStatus, mp, size);
+		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+				"0146 Ignoring unsolicted CT No HBQ "
+				"status = x%x\n",
+				piocbq->iocb.ulpStatus);
 	}
-
-	printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, "
-	       "buffer = %p, size = %d, status = x%x\n",
-	       __FUNCTION__, __LINE__,
-	       piocbq, mp, size,
-	       piocbq->iocb.ulpStatus);
-
+	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+			"0145 Ignoring unsolicted CT HBQ Size:%d "
+			"status = x%x\n",
+			size, piocbq->iocb.ulpStatus);
 }
 
 static void
-lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
-			  struct lpfc_dmabuf *mp, uint32_t size)
+lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+		     struct lpfc_dmabuf *mp, uint32_t size)
 {
-	if (!mp) {
-		printk(KERN_ERR "%s (%d): Unsolited CT, no "
-		       "HBQ buffer, piocbq = %p, status = x%x\n",
-		       __FUNCTION__, __LINE__,
-		       piocbq, piocbq->iocb.ulpStatus);
-	} else {
-		lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
-		printk(KERN_ERR "%s (%d): Ignoring unsolicted CT "
-		       "piocbq = %p, buffer = %p, size = %d, "
-		       "status = x%x\n",
-		       __FUNCTION__, __LINE__,
-		       piocbq, mp, size, piocbq->iocb.ulpStatus);
-	}
+	lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size);
 }
 
 void
@@ -109,11 +91,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	struct lpfc_iocbq *iocbq;
 	dma_addr_t paddr;
 	uint32_t size;
-	struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
-	struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
-
-	piocbq->context2 = NULL;
-	piocbq->context3 = NULL;
+	struct list_head head;
+	struct lpfc_dmabuf *bdeBuf;
 
 	if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
 		lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
@@ -122,7 +101,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		/* Not enough posted buffers; Try posting more buffers */
 		phba->fc_stat.NoRcvBuf++;
 		if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
-			lpfc_post_buffer(phba, pring, 0, 1);
+			lpfc_post_buffer(phba, pring, 2, 1);
 		return;
 	}
 
@@ -133,38 +112,34 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		return;
 
 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
-		list_for_each_entry(iocbq, &piocbq->list, list) {
+		INIT_LIST_HEAD(&head);
+		list_add_tail(&head, &piocbq->list);
+		list_for_each_entry(iocbq, &head, list) {
 			icmd = &iocbq->iocb;
-			if (icmd->ulpBdeCount == 0) {
-				printk(KERN_ERR "%s (%d): Unsolited CT, no "
-				       "BDE, iocbq = %p, status = x%x\n",
-				       __FUNCTION__, __LINE__,
-				       iocbq, iocbq->iocb.ulpStatus);
+			if (icmd->ulpBdeCount == 0)
 				continue;
-			}
-
+			bdeBuf = iocbq->context2;
+			iocbq->context2 = NULL;
 			size  = icmd->un.cont64[0].tus.f.bdeSize;
-			lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size);
-			lpfc_in_buf_free(phba, bdeBuf1);
+			lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
+			lpfc_in_buf_free(phba, bdeBuf);
 			if (icmd->ulpBdeCount == 2) {
-				lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2,
-							  size);
-				lpfc_in_buf_free(phba, bdeBuf2);
+				bdeBuf = iocbq->context3;
+				iocbq->context3 = NULL;
+				size  = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize;
+				lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf,
+						     size);
+				lpfc_in_buf_free(phba, bdeBuf);
 			}
 		}
+		list_del(&head);
 	} else {
 		struct lpfc_iocbq  *next;
 
 		list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
 			icmd = &iocbq->iocb;
-			if (icmd->ulpBdeCount == 0) {
-				printk(KERN_ERR "%s (%d): Unsolited CT, no "
-				       "BDE, iocbq = %p, status = x%x\n",
-				       __FUNCTION__, __LINE__,
-				       iocbq, iocbq->iocb.ulpStatus);
-				continue;
-			}
-
+			if (icmd->ulpBdeCount == 0)
+				lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0);
 			for (i = 0; i < icmd->ulpBdeCount; i++) {
 				paddr = getPaddr(icmd->un.cont64[i].addrHigh,
 						 icmd->un.cont64[i].addrLow);
@@ -176,6 +151,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 			}
 			list_del(&iocbq->list);
 			lpfc_sli_release_iocbq(phba, iocbq);
+			lpfc_post_buffer(phba, pring, i, 1);
 		}
 	}
 }
@@ -203,7 +179,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
 	struct lpfc_dmabuf *mp;
 	int cnt, i = 0;
 
-	/* We get chucks of FCELSSIZE */
+	/* We get chunks of FCELSSIZE */
 	cnt = size > FCELSSIZE ? FCELSSIZE: size;
 
 	while (size) {
@@ -426,6 +402,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
 
 	lpfc_set_disctmo(vport);
 	vport->num_disc_nodes = 0;
+	vport->fc_ns_retry = 0;
 
 
 	list_add_tail(&head, &mp->list);
@@ -458,7 +435,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
 			    ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
 			     vport->cfg_peer_port_login)) {
 				if ((vport->port_type != LPFC_NPIV_PORT) ||
-				    (vport->fc_flag & FC_RFF_NOT_SUPPORTED) ||
+				    (!(vport->ct_flags & FC_CT_RFF_ID)) ||
 				    (!vport->cfg_restrict_login)) {
 					ndlp = lpfc_setup_disc_node(vport, Did);
 					if (ndlp) {
@@ -506,7 +483,17 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
 						Did, vport->fc_flag,
 						vport->fc_rscn_id_cnt);
 
-						if (lpfc_ns_cmd(vport,
+						/* This NPortID was previously
+						 * a FCP target, * Don't even
+						 * bother to send GFF_ID.
+						 */
+						ndlp = lpfc_findnode_did(vport,
+							Did);
+						if (ndlp && (ndlp->nlp_type &
+							NLP_FCP_TARGET))
+							lpfc_setup_disc_node
+								(vport, Did);
+						else if (lpfc_ns_cmd(vport,
 							SLI_CTNS_GFF_ID,
 							0, Did) == 0)
 							vport->num_disc_nodes++;
@@ -554,7 +541,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	struct lpfc_dmabuf *outp;
 	struct lpfc_sli_ct_request *CTrsp;
 	struct lpfc_nodelist *ndlp;
-	int rc;
+	int rc, retry;
 
 	/* First save ndlp, before we overwrite it */
 	ndlp = cmdiocb->context_un.ndlp;
@@ -574,7 +561,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	if (vport->load_flag & FC_UNLOADING)
 		goto out;
 
-
 	if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
 		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
 				 "0216 Link event during NS query\n");
@@ -585,14 +571,35 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	if (irsp->ulpStatus) {
 		/* Check for retry */
 		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
-			if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
-				(irsp->un.ulpWord[4] != IOERR_NO_RESOURCES))
+			retry = 1;
+			if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+				switch (irsp->un.ulpWord[4]) {
+				case IOERR_NO_RESOURCES:
+					/* We don't increment the retry
+					 * count for this case.
+					 */
+					break;
+				case IOERR_LINK_DOWN:
+				case IOERR_SLI_ABORTED:
+				case IOERR_SLI_DOWN:
+					retry = 0;
+					break;
+				default:
+					vport->fc_ns_retry++;
+				}
+			}
+			else
 				vport->fc_ns_retry++;
-			/* CT command is being retried */
-			rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
+
+			if (retry) {
+				/* CT command is being retried */
+				rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
 					 vport->fc_ns_retry, 0);
-			if (rc == 0)
-				goto out;
+				if (rc == 0) {
+					/* success */
+					goto out;
+				}
+			}
 		}
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
@@ -698,7 +705,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
 	struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
 	struct lpfc_sli_ct_request *CTrsp;
-	int did;
+	int did, rc, retry;
 	uint8_t fbits;
 	struct lpfc_nodelist *ndlp;
 
@@ -729,6 +736,39 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 		}
 	}
 	else {
+		/* Check for retry */
+		if (cmdiocb->retry < LPFC_MAX_NS_RETRY) {
+			retry = 1;
+			if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+				switch (irsp->un.ulpWord[4]) {
+				case IOERR_NO_RESOURCES:
+					/* We don't increment the retry
+					 * count for this case.
+					 */
+					break;
+				case IOERR_LINK_DOWN:
+				case IOERR_SLI_ABORTED:
+				case IOERR_SLI_DOWN:
+					retry = 0;
+					break;
+				default:
+					cmdiocb->retry++;
+				}
+			}
+			else
+				cmdiocb->retry++;
+
+			if (retry) {
+				/* CT command is being retried */
+				rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID,
+					 cmdiocb->retry, did);
+				if (rc == 0) {
+					/* success */
+					lpfc_ct_free_iocb(phba, cmdiocb);
+					return;
+				}
+			}
+		}
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
 				 "0267 NameServer GFF Rsp "
 				 "x%x Error (%d %d) Data: x%x x%x\n",
@@ -778,8 +818,8 @@ out:
 
 
 static void
-lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
-			struct lpfc_iocbq *rspiocb)
+lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+	     struct lpfc_iocbq *rspiocb)
 {
 	struct lpfc_vport *vport = cmdiocb->vport;
 	struct lpfc_dmabuf *inp;
@@ -809,7 +849,7 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
 	/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
 	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
-			 "0209 RFT request completes, latt %d, "
+			 "0209 CT Request completes, latt %d, "
 			 "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
 			 latt, irsp->ulpStatus,
 			 CTrsp->CommandResponse.bits.CmdRsp,
@@ -848,10 +888,44 @@ out:
 }
 
 static void
+lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+			struct lpfc_iocbq *rspiocb)
+{
+	IOCB_t *irsp = &rspiocb->iocb;
+	struct lpfc_vport *vport = cmdiocb->vport;
+
+	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+		struct lpfc_dmabuf *outp;
+		struct lpfc_sli_ct_request *CTrsp;
+
+		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+		if (CTrsp->CommandResponse.bits.CmdRsp ==
+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+			vport->ct_flags |= FC_CT_RFT_ID;
+	}
+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+	return;
+}
+
+static void
 lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			struct lpfc_iocbq *rspiocb)
 {
-	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+	IOCB_t *irsp = &rspiocb->iocb;
+	struct lpfc_vport *vport = cmdiocb->vport;
+
+	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+		struct lpfc_dmabuf *outp;
+		struct lpfc_sli_ct_request *CTrsp;
+
+		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+		if (CTrsp->CommandResponse.bits.CmdRsp ==
+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+			vport->ct_flags |= FC_CT_RNN_ID;
+	}
+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
 	return;
 }
 
@@ -859,7 +933,20 @@ static void
 lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			 struct lpfc_iocbq *rspiocb)
 {
-	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+	IOCB_t *irsp = &rspiocb->iocb;
+	struct lpfc_vport *vport = cmdiocb->vport;
+
+	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+		struct lpfc_dmabuf *outp;
+		struct lpfc_sli_ct_request *CTrsp;
+
+		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+		if (CTrsp->CommandResponse.bits.CmdRsp ==
+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+			vport->ct_flags |= FC_CT_RSPN_ID;
+	}
+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
 	return;
 }
 
@@ -867,7 +954,32 @@ static void
 lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			 struct lpfc_iocbq *rspiocb)
 {
-	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+	IOCB_t *irsp = &rspiocb->iocb;
+	struct lpfc_vport *vport = cmdiocb->vport;
+
+	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+		struct lpfc_dmabuf *outp;
+		struct lpfc_sli_ct_request *CTrsp;
+
+		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+		if (CTrsp->CommandResponse.bits.CmdRsp ==
+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+			vport->ct_flags |= FC_CT_RSNN_NN;
+	}
+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
+	return;
+}
+
+static void
+lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+	struct lpfc_vport *vport = cmdiocb->vport;
+
+	/* even if it fails we will act as though it succeeded. */
+	vport->ct_flags = 0;
+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
 	return;
 }
 
@@ -878,10 +990,17 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	IOCB_t *irsp = &rspiocb->iocb;
 	struct lpfc_vport *vport = cmdiocb->vport;
 
-	if (irsp->ulpStatus != IOSTAT_SUCCESS)
-	    vport->fc_flag |= FC_RFF_NOT_SUPPORTED;
+	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+		struct lpfc_dmabuf *outp;
+		struct lpfc_sli_ct_request *CTrsp;
 
-	lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
+		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+		if (CTrsp->CommandResponse.bits.CmdRsp ==
+		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
+			vport->ct_flags |= FC_CT_RFF_ID;
+	}
+	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
 	return;
 }
 
@@ -1001,6 +1120,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
 		bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
 	else if (cmdcode == SLI_CTNS_RSNN_NN)
 		bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
+	else if (cmdcode == SLI_CTNS_DA_ID)
+		bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ;
 	else if (cmdcode == SLI_CTNS_RFF_ID)
 		bpl->tus.f.bdeSize = RFF_REQUEST_SZ;
 	else
@@ -1029,31 +1150,34 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
 	case SLI_CTNS_GFF_ID:
 		CtReq->CommandResponse.bits.CmdRsp =
 			be16_to_cpu(SLI_CTNS_GFF_ID);
-		CtReq->un.gff.PortId = be32_to_cpu(context);
+		CtReq->un.gff.PortId = cpu_to_be32(context);
 		cmpl = lpfc_cmpl_ct_cmd_gff_id;
 		break;
 
 	case SLI_CTNS_RFT_ID:
+		vport->ct_flags &= ~FC_CT_RFT_ID;
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RFT_ID);
-		CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID);
+		CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID);
 		CtReq->un.rft.fcpReg = 1;
 		cmpl = lpfc_cmpl_ct_cmd_rft_id;
 		break;
 
 	case SLI_CTNS_RNN_ID:
+		vport->ct_flags &= ~FC_CT_RNN_ID;
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RNN_ID);
-		CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID);
+		CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
 		memcpy(CtReq->un.rnn.wwnn,  &vport->fc_nodename,
 		       sizeof (struct lpfc_name));
 		cmpl = lpfc_cmpl_ct_cmd_rnn_id;
 		break;
 
 	case SLI_CTNS_RSPN_ID:
+		vport->ct_flags &= ~FC_CT_RSPN_ID;
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RSPN_ID);
-		CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID);
+		CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID);
 		size = sizeof(CtReq->un.rspn.symbname);
 		CtReq->un.rspn.len =
 			lpfc_vport_symbolic_port_name(vport,
@@ -1061,6 +1185,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
 		cmpl = lpfc_cmpl_ct_cmd_rspn_id;
 		break;
 	case SLI_CTNS_RSNN_NN:
+		vport->ct_flags &= ~FC_CT_RSNN_NN;
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RSNN_NN);
 		memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
@@ -1071,11 +1196,18 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
 			CtReq->un.rsnn.symbname, size);
 		cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
 		break;
+	case SLI_CTNS_DA_ID:
+		/* Implement DA_ID Nameserver request */
+		CtReq->CommandResponse.bits.CmdRsp =
+			be16_to_cpu(SLI_CTNS_DA_ID);
+		CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID);
+		cmpl = lpfc_cmpl_ct_cmd_da_id;
+		break;
 	case SLI_CTNS_RFF_ID:
-		vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED;
+		vport->ct_flags &= ~FC_CT_RFF_ID;
 		CtReq->CommandResponse.bits.CmdRsp =
 		    be16_to_cpu(SLI_CTNS_RFF_ID);
-		CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);;
+		CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);;
 		CtReq->un.rff.fbits = FC4_FEATURE_INIT;
 		CtReq->un.rff.type_code = FC_FCP_DATA;
 		cmpl = lpfc_cmpl_ct_cmd_rff_id;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index d6a98bc970ff..783d1eea13ef 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -43,6 +43,7 @@
 #include "lpfc_crtn.h"
 #include "lpfc_vport.h"
 #include "lpfc_version.h"
+#include "lpfc_compat.h"
 #include "lpfc_debugfs.h"
 
 #ifdef CONFIG_LPFC_DEBUG_FS
@@ -75,18 +76,18 @@ module_param(lpfc_debugfs_enable, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
 
 /* This MUST be a power of 2 */
-static int lpfc_debugfs_max_disc_trc = 0;
+static int lpfc_debugfs_max_disc_trc;
 module_param(lpfc_debugfs_max_disc_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
 	"Set debugfs discovery trace depth");
 
 /* This MUST be a power of 2 */
-static int lpfc_debugfs_max_slow_ring_trc = 0;
+static int lpfc_debugfs_max_slow_ring_trc;
 module_param(lpfc_debugfs_max_slow_ring_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
 	"Set debugfs slow ring trace depth");
 
-static int lpfc_debugfs_mask_disc_trc = 0;
+int lpfc_debugfs_mask_disc_trc;
 module_param(lpfc_debugfs_mask_disc_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
 	"Set debugfs discovery trace mask");
@@ -100,8 +101,11 @@ MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
 #define LPFC_NODELIST_SIZE 8192
 #define LPFC_NODELIST_ENTRY_SIZE 120
 
-/* dumpslim output buffer size */
-#define LPFC_DUMPSLIM_SIZE 4096
+/* dumpHBASlim output buffer size */
+#define LPFC_DUMPHBASLIM_SIZE 4096
+
+/* dumpHostSlim output buffer size */
+#define LPFC_DUMPHOSTSLIM_SIZE 4096
 
 /* hbqinfo output buffer size */
 #define LPFC_HBQINFO_SIZE 8192
@@ -243,16 +247,17 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
 	raw_index = phba->hbq_get[i];
 	getidx = le32_to_cpu(raw_index);
 	len +=  snprintf(buf+len, size-len,
-		"entrys:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
-		hbqs->entry_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx,
-		hbqs->local_hbqGetIdx, getidx);
+		"entrys:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
+		hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx,
+		hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx);
 
 	hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt;
 	for (j=0; j<hbqs->entry_count; j++) {
 		len +=  snprintf(buf+len, size-len,
 			"%03d: %08x %04x %05x ", j,
-			hbqe->bde.addrLow, hbqe->bde.tus.w, hbqe->buffer_tag);
-
+			le32_to_cpu(hbqe->bde.addrLow),
+			le32_to_cpu(hbqe->bde.tus.w),
+			le32_to_cpu(hbqe->buffer_tag));
 		i = 0;
 		found = 0;
 
@@ -276,7 +281,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
 		list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) {
 			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
 			phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff);
-			if (phys == hbqe->bde.addrLow) {
+			if (phys == le32_to_cpu(hbqe->bde.addrLow)) {
 				len +=  snprintf(buf+len, size-len,
 					"Buf%d: %p %06x\n", i,
 					hbq_buf->dbuf.virt, hbq_buf->tag);
@@ -297,18 +302,58 @@ skipit:
 	return len;
 }
 
+static int lpfc_debugfs_last_hba_slim_off;
+
+static int
+lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size)
+{
+	int len = 0;
+	int i, off;
+	uint32_t *ptr;
+	char buffer[1024];
+
+	off = 0;
+	spin_lock_irq(&phba->hbalock);
+
+	len +=  snprintf(buf+len, size-len, "HBA SLIM\n");
+	lpfc_memcpy_from_slim(buffer,
+		((uint8_t *)phba->MBslimaddr) + lpfc_debugfs_last_hba_slim_off,
+		1024);
+
+	ptr = (uint32_t *)&buffer[0];
+	off = lpfc_debugfs_last_hba_slim_off;
+
+	/* Set it up for the next time */
+	lpfc_debugfs_last_hba_slim_off += 1024;
+	if (lpfc_debugfs_last_hba_slim_off >= 4096)
+		lpfc_debugfs_last_hba_slim_off = 0;
+
+	i = 1024;
+	while (i > 0) {
+		len +=  snprintf(buf+len, size-len,
+		"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+		off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
+		*(ptr+5), *(ptr+6), *(ptr+7));
+		ptr += 8;
+		i -= (8 * sizeof(uint32_t));
+		off += (8 * sizeof(uint32_t));
+	}
+
+	spin_unlock_irq(&phba->hbalock);
+	return len;
+}
+
 static int
-lpfc_debugfs_dumpslim_data(struct lpfc_hba *phba, char *buf, int size)
+lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size)
 {
 	int len = 0;
-	int cnt, i, off;
+	int i, off;
 	uint32_t word0, word1, word2, word3;
 	uint32_t *ptr;
 	struct lpfc_pgp *pgpp;
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
 
-	cnt = LPFC_DUMPSLIM_SIZE;
 	off = 0;
 	spin_lock_irq(&phba->hbalock);
 
@@ -620,7 +665,34 @@ out:
 }
 
 static int
-lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
+lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file)
+{
+	struct lpfc_hba *phba = inode->i_private;
+	struct lpfc_debug *debug;
+	int rc = -ENOMEM;
+
+	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+	if (!debug)
+		goto out;
+
+	/* Round to page boundry */
+	debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL);
+	if (!debug->buffer) {
+		kfree(debug);
+		goto out;
+	}
+
+	debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer,
+		LPFC_DUMPHBASLIM_SIZE);
+	file->private_data = debug;
+
+	rc = 0;
+out:
+	return rc;
+}
+
+static int
+lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file)
 {
 	struct lpfc_hba *phba = inode->i_private;
 	struct lpfc_debug *debug;
@@ -631,14 +703,14 @@ lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
 		goto out;
 
 	/* Round to page boundry */
-	debug->buffer = kmalloc(LPFC_DUMPSLIM_SIZE, GFP_KERNEL);
+	debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL);
 	if (!debug->buffer) {
 		kfree(debug);
 		goto out;
 	}
 
-	debug->len = lpfc_debugfs_dumpslim_data(phba, debug->buffer,
-		LPFC_DUMPSLIM_SIZE);
+	debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer,
+		LPFC_DUMPHOSTSLIM_SIZE);
 	file->private_data = debug;
 
 	rc = 0;
@@ -741,10 +813,19 @@ static struct file_operations lpfc_debugfs_op_hbqinfo = {
 	.release =      lpfc_debugfs_release,
 };
 
-#undef lpfc_debugfs_op_dumpslim
-static struct file_operations lpfc_debugfs_op_dumpslim = {
+#undef lpfc_debugfs_op_dumpHBASlim
+static struct file_operations lpfc_debugfs_op_dumpHBASlim = {
+	.owner =        THIS_MODULE,
+	.open =         lpfc_debugfs_dumpHBASlim_open,
+	.llseek =       lpfc_debugfs_lseek,
+	.read =         lpfc_debugfs_read,
+	.release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpHostSlim
+static struct file_operations lpfc_debugfs_op_dumpHostSlim = {
 	.owner =        THIS_MODULE,
-	.open =         lpfc_debugfs_dumpslim_open,
+	.open =         lpfc_debugfs_dumpHostSlim_open,
 	.llseek =       lpfc_debugfs_lseek,
 	.read =         lpfc_debugfs_read,
 	.release =      lpfc_debugfs_release,
@@ -812,15 +893,27 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
 			goto debug_failed;
 		}
 
-		/* Setup dumpslim */
-		snprintf(name, sizeof(name), "dumpslim");
-		phba->debug_dumpslim =
+		/* Setup dumpHBASlim */
+		snprintf(name, sizeof(name), "dumpHBASlim");
+		phba->debug_dumpHBASlim =
+			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+				 phba->hba_debugfs_root,
+				 phba, &lpfc_debugfs_op_dumpHBASlim);
+		if (!phba->debug_dumpHBASlim) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				"0409 Cannot create debugfs dumpHBASlim\n");
+			goto debug_failed;
+		}
+
+		/* Setup dumpHostSlim */
+		snprintf(name, sizeof(name), "dumpHostSlim");
+		phba->debug_dumpHostSlim =
 			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
 				 phba->hba_debugfs_root,
-				 phba, &lpfc_debugfs_op_dumpslim);
-		if (!phba->debug_dumpslim) {
+				 phba, &lpfc_debugfs_op_dumpHostSlim);
+		if (!phba->debug_dumpHostSlim) {
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
-				"0409 Cannot create debugfs dumpslim\n");
+				"0409 Cannot create debugfs dumpHostSlim\n");
 			goto debug_failed;
 		}
 
@@ -970,9 +1063,13 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
 			debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
 			phba->debug_hbqinfo = NULL;
 		}
-		if (phba->debug_dumpslim) {
-			debugfs_remove(phba->debug_dumpslim); /* dumpslim */
-			phba->debug_dumpslim = NULL;
+		if (phba->debug_dumpHBASlim) {
+			debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */
+			phba->debug_dumpHBASlim = NULL;
+		}
+		if (phba->debug_dumpHostSlim) {
+			debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */
+			phba->debug_dumpHostSlim = NULL;
 		}
 		if (phba->slow_ring_trc) {
 			kfree(phba->slow_ring_trc);
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index aacac9ac5381..cfe81c50529a 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -36,7 +36,6 @@ enum lpfc_work_type {
 	LPFC_EVT_WARM_START,
 	LPFC_EVT_KILL,
 	LPFC_EVT_ELS_RETRY,
-	LPFC_EVT_DEV_LOSS_DELAY,
 	LPFC_EVT_DEV_LOSS,
 };
 
@@ -92,6 +91,7 @@ struct lpfc_nodelist {
 #define NLP_LOGO_SND       0x100	/* sent LOGO request for this entry */
 #define NLP_RNID_SND       0x400	/* sent RNID request for this entry */
 #define NLP_ELS_SND_MASK   0x7e0	/* sent ELS request for this entry */
+#define NLP_DEFER_RM       0x10000	/* Remove this ndlp if no longer used */
 #define NLP_DELAY_TMO      0x20000	/* delay timeout is running for node */
 #define NLP_NPR_2B_DISC    0x40000	/* node is included in num_disc_nodes */
 #define NLP_RCV_PLOGI      0x80000	/* Rcv'ed PLOGI from remote system */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 8085900635d4..c6b739dc6bc3 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -18,7 +18,7 @@
  * more details, a copy of which can be found in the file COPYING  *
  * included with this package.                                     *
  *******************************************************************/
-
+/* See Fibre Channel protocol T11 FC-LS for details */
 #include <linux/blkdev.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
@@ -42,6 +42,14 @@ static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
 			  struct lpfc_iocbq *);
 static void lpfc_cmpl_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *,
 			struct lpfc_iocbq *);
+static void lpfc_fabric_abort_vport(struct lpfc_vport *vport);
+static int lpfc_issue_els_fdisc(struct lpfc_vport *vport,
+				struct lpfc_nodelist *ndlp, uint8_t retry);
+static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba,
+				  struct lpfc_iocbq *iocb);
+static void lpfc_register_new_vport(struct lpfc_hba *phba,
+				    struct lpfc_vport *vport,
+				    struct lpfc_nodelist *ndlp);
 
 static int lpfc_max_els_tries = 3;
 
@@ -109,14 +117,11 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
 
 	/* fill in BDEs for command */
 	/* Allocate buffer for command payload */
-	if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
-	    ((pcmd->virt = lpfc_mbuf_alloc(phba,
-					   MEM_PRI, &(pcmd->phys))) == 0)) {
-		kfree(pcmd);
-
-		lpfc_sli_release_iocbq(phba, elsiocb);
-		return NULL;
-	}
+	pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+	if (pcmd)
+		pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys);
+	if (!pcmd || !pcmd->virt)
+		goto els_iocb_free_pcmb_exit;
 
 	INIT_LIST_HEAD(&pcmd->list);
 
@@ -126,13 +131,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
 		if (prsp)
 			prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
 						     &prsp->phys);
-		if (prsp == 0 || prsp->virt == 0) {
-			kfree(prsp);
-			lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
-			kfree(pcmd);
-			lpfc_sli_release_iocbq(phba, elsiocb);
-			return NULL;
-		}
+		if (!prsp || !prsp->virt)
+			goto els_iocb_free_prsp_exit;
 		INIT_LIST_HEAD(&prsp->list);
 	} else {
 		prsp = NULL;
@@ -143,15 +143,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
 	if (pbuflist)
 		pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
 						 &pbuflist->phys);
-	if (pbuflist == 0 || pbuflist->virt == 0) {
-		lpfc_sli_release_iocbq(phba, elsiocb);
-		lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
-		lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
-		kfree(pcmd);
-		kfree(prsp);
-		kfree(pbuflist);
-		return NULL;
-	}
+	if (!pbuflist || !pbuflist->virt)
+		goto els_iocb_free_pbuf_exit;
 
 	INIT_LIST_HEAD(&pbuflist->list);
 
@@ -196,7 +189,10 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
 		bpl->tus.w = le32_to_cpu(bpl->tus.w);
 	}
 
+	/* prevent preparing iocb with NULL ndlp reference */
 	elsiocb->context1 = lpfc_nlp_get(ndlp);
+	if (!elsiocb->context1)
+		goto els_iocb_free_pbuf_exit;
 	elsiocb->context2 = pcmd;
 	elsiocb->context3 = pbuflist;
 	elsiocb->retry = retry;
@@ -222,8 +218,20 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
 				 cmdSize);
 	}
 	return elsiocb;
-}
 
+els_iocb_free_pbuf_exit:
+	lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
+	kfree(pbuflist);
+
+els_iocb_free_prsp_exit:
+	lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
+	kfree(prsp);
+
+els_iocb_free_pcmb_exit:
+	kfree(pcmd);
+	lpfc_sli_release_iocbq(phba, elsiocb);
+	return NULL;
+}
 
 static int
 lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
@@ -234,40 +242,53 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
 	struct lpfc_nodelist *ndlp;
 	struct serv_parm *sp;
 	int rc;
+	int err = 0;
 
 	sp = &phba->fc_fabparam;
 	ndlp = lpfc_findnode_did(vport, Fabric_DID);
-	if (!ndlp)
+	if (!ndlp) {
+		err = 1;
 		goto fail;
+	}
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-	if (!mbox)
+	if (!mbox) {
+		err = 2;
 		goto fail;
+	}
 
 	vport->port_state = LPFC_FABRIC_CFG_LINK;
 	lpfc_config_link(phba, mbox);
 	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 	mbox->vport = vport;
 
-	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
-	if (rc == MBX_NOT_FINISHED)
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+	if (rc == MBX_NOT_FINISHED) {
+		err = 3;
 		goto fail_free_mbox;
+	}
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-	if (!mbox)
+	if (!mbox) {
+		err = 4;
 		goto fail;
+	}
 	rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
 			    0);
-	if (rc)
+	if (rc) {
+		err = 5;
 		goto fail_free_mbox;
+	}
 
 	mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
 	mbox->vport = vport;
 	mbox->context2 = lpfc_nlp_get(ndlp);
 
-	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
-	if (rc == MBX_NOT_FINISHED)
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+	if (rc == MBX_NOT_FINISHED) {
+		err = 6;
 		goto fail_issue_reg_login;
+	}
 
 	return 0;
 
@@ -282,7 +303,7 @@ fail_free_mbox:
 fail:
 	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-		"0249 Cannot issue Register Fabric login\n");
+		"0249 Cannot issue Register Fabric login: Err %d\n", err);
 	return -ENXIO;
 }
 
@@ -370,11 +391,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		}
 		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
 			lpfc_mbx_unreg_vpi(vport);
+			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+			spin_unlock_irq(shost->host_lock);
 		}
 	}
 
-	ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
 
 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
@@ -429,8 +451,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 		mbox->vport = vport;
-		rc = lpfc_sli_issue_mbox(phba, mbox,
-					 MBX_NOWAIT | MBX_STOP_IOCB);
+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
 		if (rc == MBX_NOT_FINISHED) {
 			mempool_free(mbox, phba->mbox_mem_pool);
 			goto fail;
@@ -463,6 +484,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		lpfc_nlp_put(ndlp);
 	}
 
+	/* If we are pt2pt with another NPort, force NPIV off! */
+	phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
+
 	spin_lock_irq(shost->host_lock);
 	vport->fc_flag |= FC_PT2PT;
 	spin_unlock_irq(shost->host_lock);
@@ -488,6 +512,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
 	/* Check to see if link went down during discovery */
 	if (lpfc_els_chk_latt(vport)) {
+		/* One additional decrement on node reference count to
+		 * trigger the release of the node
+		 */
 		lpfc_nlp_put(ndlp);
 		goto out;
 	}
@@ -562,8 +589,13 @@ flogifail:
 
 		/* Start discovery */
 		lpfc_disc_start(vport);
+	} else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
+			((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
+			(irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) &&
+			(phba->link_state != LPFC_CLEAR_LA)) {
+		/* If FLOGI failed enable link interrupt. */
+		lpfc_issue_clear_la(phba, vport);
 	}
-
 out:
 	lpfc_els_free_iocb(phba, cmdiocb);
 }
@@ -685,6 +717,9 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
 	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_nodelist *ndlp;
 
+	vport->port_state = LPFC_FLOGI;
+	lpfc_set_disctmo(vport);
+
 	/* First look for the Fabric ndlp */
 	ndlp = lpfc_findnode_did(vport, Fabric_DID);
 	if (!ndlp) {
@@ -696,7 +731,11 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
 	} else {
 		lpfc_dequeue_node(vport, ndlp);
 	}
+
 	if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
+		/* This decrement of reference count to node shall kick off
+		 * the release of the node.
+		 */
 		lpfc_nlp_put(ndlp);
 	}
 	return 1;
@@ -720,11 +759,16 @@ lpfc_initial_fdisc(struct lpfc_vport *vport)
 		lpfc_dequeue_node(vport, ndlp);
 	}
 	if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
+		/* decrement node reference count to trigger the release of
+		 * the node.
+		 */
 		lpfc_nlp_put(ndlp);
+		return 0;
 	}
 	return 1;
 }
-static void
+
+void
 lpfc_more_plogi(struct lpfc_vport *vport)
 {
 	int sentplogi;
@@ -752,6 +796,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
 {
 	struct lpfc_vport    *vport = ndlp->vport;
 	struct lpfc_nodelist *new_ndlp;
+	struct lpfc_rport_data *rdata;
+	struct fc_rport *rport;
 	struct serv_parm *sp;
 	uint8_t  name[sizeof(struct lpfc_name)];
 	uint32_t rc;
@@ -788,11 +834,34 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
 	lpfc_unreg_rpi(vport, new_ndlp);
 	new_ndlp->nlp_DID = ndlp->nlp_DID;
 	new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
+
+	if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
+		new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+
 	lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
 
 	/* Move this back to NPR state */
-	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
+	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
+		/* The new_ndlp is replacing ndlp totally, so we need
+		 * to put ndlp on UNUSED list and try to free it.
+		 */
+
+		/* Fix up the rport accordingly */
+		rport =  ndlp->rport;
+		if (rport) {
+			rdata = rport->dd_data;
+			if (rdata->pnode == ndlp) {
+				lpfc_nlp_put(ndlp);
+				ndlp->rport = NULL;
+				rdata->pnode = lpfc_nlp_get(new_ndlp);
+				new_ndlp->rport = rport;
+			}
+			new_ndlp->nlp_type = ndlp->nlp_type;
+		}
+
 		lpfc_drop_node(vport, ndlp);
+	}
 	else {
 		lpfc_unreg_rpi(vport, ndlp);
 		ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
@@ -801,6 +870,27 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
 	return new_ndlp;
 }
 
+void
+lpfc_end_rscn(struct lpfc_vport *vport)
+{
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+	if (vport->fc_flag & FC_RSCN_MODE) {
+		/*
+		 * Check to see if more RSCNs came in while we were
+		 * processing this one.
+		 */
+		if (vport->fc_rscn_id_cnt ||
+		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
+			lpfc_els_handle_rscn(vport);
+		else {
+			spin_lock_irq(shost->host_lock);
+			vport->fc_flag &= ~FC_RSCN_MODE;
+			spin_unlock_irq(shost->host_lock);
+		}
+	}
+}
+
 static void
 lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 		    struct lpfc_iocbq *rspiocb)
@@ -871,13 +961,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			goto out;
 		}
 		/* PLOGI failed */
-		if (ndlp->nlp_DID == NameServer_DID) {
-			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
-					 "0250 Nameserver login error: "
-					 "0x%x / 0x%x\n",
-					 irsp->ulpStatus, irsp->un.ulpWord[4]);
-		}
 		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
 		if (lpfc_error_lost_link(irsp)) {
 			rc = NLP_STE_FREED_NODE;
@@ -905,20 +988,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			spin_unlock_irq(shost->host_lock);
 
 			lpfc_can_disctmo(vport);
-			if (vport->fc_flag & FC_RSCN_MODE) {
-				/*
-				 * Check to see if more RSCNs came in while
-				 * we were processing this one.
-				 */
-				if ((vport->fc_rscn_id_cnt == 0) &&
-				    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
-					spin_lock_irq(shost->host_lock);
-					vport->fc_flag &= ~FC_RSCN_MODE;
-					spin_unlock_irq(shost->host_lock);
-				} else {
-					lpfc_els_handle_rscn(vport);
-				}
-			}
+			lpfc_end_rscn(vport);
 		}
 	}
 
@@ -933,6 +1003,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
 	struct lpfc_hba  *phba = vport->phba;
 	struct serv_parm *sp;
 	IOCB_t *icmd;
+	struct lpfc_nodelist *ndlp;
 	struct lpfc_iocbq *elsiocb;
 	struct lpfc_sli_ring *pring;
 	struct lpfc_sli *psli;
@@ -943,8 +1014,11 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
 	psli = &phba->sli;
 	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
 
+	ndlp = lpfc_findnode_did(vport, did);
+	/* If ndlp if not NULL, we will bump the reference count on it */
+
 	cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
-	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
+	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
 				     ELS_CMD_PLOGI);
 	if (!elsiocb)
 		return 1;
@@ -1109,7 +1183,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	return 0;
 }
 
-static void
+void
 lpfc_more_adisc(struct lpfc_vport *vport)
 {
 	int sentadisc;
@@ -1134,8 +1208,6 @@ lpfc_more_adisc(struct lpfc_vport *vport)
 static void
 lpfc_rscn_disc(struct lpfc_vport *vport)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
 	lpfc_can_disctmo(vport);
 
 	/* RSCN discovery */
@@ -1144,19 +1216,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport)
 		if (lpfc_els_disc_plogi(vport))
 			return;
 
-	if (vport->fc_flag & FC_RSCN_MODE) {
-		/* Check to see if more RSCNs came in while we were
-		 * processing this one.
-		 */
-		if ((vport->fc_rscn_id_cnt == 0) &&
-		    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
-			spin_lock_irq(shost->host_lock);
-			vport->fc_flag &= ~FC_RSCN_MODE;
-			spin_unlock_irq(shost->host_lock);
-		} else {
-			lpfc_els_handle_rscn(vport);
-		}
-	}
+	lpfc_end_rscn(vport);
 }
 
 static void
@@ -1413,6 +1473,13 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	psli = &phba->sli;
 	pring = &psli->ring[LPFC_ELS_RING];
 
+	spin_lock_irq(shost->host_lock);
+	if (ndlp->nlp_flag & NLP_LOGO_SND) {
+		spin_unlock_irq(shost->host_lock);
+		return 0;
+	}
+	spin_unlock_irq(shost->host_lock);
+
 	cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
 				     ndlp->nlp_DID, ELS_CMD_LOGO);
@@ -1499,6 +1566,9 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
 				     ndlp->nlp_DID, ELS_CMD_SCR);
 
 	if (!elsiocb) {
+		/* This will trigger the release of the node just
+		 * allocated
+		 */
 		lpfc_nlp_put(ndlp);
 		return 1;
 	}
@@ -1520,10 +1590,17 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
 	phba->fc_stat.elsXmitSCR++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+		/* The additional lpfc_nlp_put will cause the following
+		 * lpfc_els_free_iocb routine to trigger the rlease of
+		 * the node.
+		 */
 		lpfc_nlp_put(ndlp);
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
 	}
+	/* This will cause the callback-function lpfc_cmpl_els_cmd to
+	 * trigger the release of node.
+	 */
 	lpfc_nlp_put(ndlp);
 	return 0;
 }
@@ -1555,6 +1632,9 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
 	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
 				     ndlp->nlp_DID, ELS_CMD_RNID);
 	if (!elsiocb) {
+		/* This will trigger the release of the node just
+		 * allocated
+		 */
 		lpfc_nlp_put(ndlp);
 		return 1;
 	}
@@ -1591,35 +1671,21 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
 	phba->fc_stat.elsXmitFARPR++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+		/* The additional lpfc_nlp_put will cause the following
+		 * lpfc_els_free_iocb routine to trigger the release of
+		 * the node.
+		 */
 		lpfc_nlp_put(ndlp);
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
 	}
+	/* This will cause the callback-function lpfc_cmpl_els_cmd to
+	 * trigger the release of the node.
+	 */
 	lpfc_nlp_put(ndlp);
 	return 0;
 }
 
-static void
-lpfc_end_rscn(struct lpfc_vport *vport)
-{
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
-	if (vport->fc_flag & FC_RSCN_MODE) {
-		/*
-		 * Check to see if more RSCNs came in while we were
-		 * processing this one.
-		 */
-		if (vport->fc_rscn_id_cnt ||
-		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
-			lpfc_els_handle_rscn(vport);
-		else {
-			spin_lock_irq(shost->host_lock);
-			vport->fc_flag &= ~FC_RSCN_MODE;
-			spin_unlock_irq(shost->host_lock);
-		}
-	}
-}
-
 void
 lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
 {
@@ -1675,7 +1741,10 @@ lpfc_els_retry_delay(unsigned long ptr)
 		return;
 	}
 
-	evtp->evt_arg1  = ndlp;
+	/* We need to hold the node by incrementing the reference
+	 * count until the queued work is done
+	 */
+	evtp->evt_arg1  = lpfc_nlp_get(ndlp);
 	evtp->evt       = LPFC_EVT_ELS_RETRY;
 	list_add_tail(&evtp->evt_listp, &phba->work_list);
 	if (phba->work_wait)
@@ -1759,6 +1828,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	uint32_t *elscmd;
 	struct ls_rjt stat;
 	int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
+	int logerr = 0;
 	uint32_t cmd = 0;
 	uint32_t did;
 
@@ -1815,6 +1885,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			break;
 
 		case IOERR_NO_RESOURCES:
+			logerr = 1; /* HBA out of resources */
 			retry = 1;
 			if (cmdiocb->retry > 100)
 				delay = 100;
@@ -1843,6 +1914,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 
 	case IOSTAT_NPORT_BSY:
 	case IOSTAT_FABRIC_BSY:
+		logerr = 1; /* Fabric / Remote NPort out of resources */
 		retry = 1;
 		break;
 
@@ -1923,6 +1995,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	if (did == FDMI_DID)
 		retry = 1;
 
+	if ((cmd == ELS_CMD_FLOGI) &&
+	    (phba->fc_topology != TOPOLOGY_LOOP)) {
+		/* FLOGI retry policy */
+		retry = 1;
+		maxretry = 48;
+		if (cmdiocb->retry >= 32)
+			delay = 1000;
+	}
+
 	if ((++cmdiocb->retry) >= maxretry) {
 		phba->fc_stat.elsRetryExceeded++;
 		retry = 0;
@@ -2006,11 +2087,46 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 		}
 	}
 	/* No retry ELS command <elsCmd> to remote NPORT <did> */
-	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+	if (logerr) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+			 "0137 No retry ELS command x%x to remote "
+			 "NPORT x%x: Out of Resources: Error:x%x/%x\n",
+			 cmd, did, irsp->ulpStatus,
+			 irsp->un.ulpWord[4]);
+	}
+	else {
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
 			 "0108 No retry ELS command x%x to remote "
 			 "NPORT x%x Retried:%d Error:x%x/%x\n",
 			 cmd, did, cmdiocb->retry, irsp->ulpStatus,
 			 irsp->un.ulpWord[4]);
+	}
+	return 0;
+}
+
+static int
+lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1)
+{
+	struct lpfc_dmabuf *buf_ptr;
+
+	/* Free the response before processing the command.  */
+	if (!list_empty(&buf_ptr1->list)) {
+		list_remove_head(&buf_ptr1->list, buf_ptr,
+				 struct lpfc_dmabuf,
+				 list);
+		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+		kfree(buf_ptr);
+	}
+	lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
+	kfree(buf_ptr1);
+	return 0;
+}
+
+static int
+lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr)
+{
+	lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+	kfree(buf_ptr);
 	return 0;
 }
 
@@ -2018,30 +2134,63 @@ int
 lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
 {
 	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
+	struct lpfc_nodelist *ndlp;
 
-	if (elsiocb->context1) {
-		lpfc_nlp_put(elsiocb->context1);
+	ndlp = (struct lpfc_nodelist *)elsiocb->context1;
+	if (ndlp) {
+		if (ndlp->nlp_flag & NLP_DEFER_RM) {
+			lpfc_nlp_put(ndlp);
+
+			/* If the ndlp is not being used by another discovery
+			 * thread, free it.
+			 */
+			if (!lpfc_nlp_not_used(ndlp)) {
+				/* If ndlp is being used by another discovery
+				 * thread, just clear NLP_DEFER_RM
+				 */
+				ndlp->nlp_flag &= ~NLP_DEFER_RM;
+			}
+		}
+		else
+			lpfc_nlp_put(ndlp);
 		elsiocb->context1 = NULL;
 	}
 	/* context2  = cmd,  context2->next = rsp, context3 = bpl */
 	if (elsiocb->context2) {
-		buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
-		/* Free the response before processing the command.  */
-		if (!list_empty(&buf_ptr1->list)) {
-			list_remove_head(&buf_ptr1->list, buf_ptr,
-					 struct lpfc_dmabuf,
-					 list);
-			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-			kfree(buf_ptr);
+		if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) {
+			/* Firmware could still be in progress of DMAing
+			 * payload, so don't free data buffer till after
+			 * a hbeat.
+			 */
+			elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE;
+			buf_ptr = elsiocb->context2;
+			elsiocb->context2 = NULL;
+			if (buf_ptr) {
+				buf_ptr1 = NULL;
+				spin_lock_irq(&phba->hbalock);
+				if (!list_empty(&buf_ptr->list)) {
+					list_remove_head(&buf_ptr->list,
+						buf_ptr1, struct lpfc_dmabuf,
+						list);
+					INIT_LIST_HEAD(&buf_ptr1->list);
+					list_add_tail(&buf_ptr1->list,
+						&phba->elsbuf);
+					phba->elsbuf_cnt++;
+				}
+				INIT_LIST_HEAD(&buf_ptr->list);
+				list_add_tail(&buf_ptr->list, &phba->elsbuf);
+				phba->elsbuf_cnt++;
+				spin_unlock_irq(&phba->hbalock);
+			}
+		} else {
+			buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
+			lpfc_els_free_data(phba, buf_ptr1);
 		}
-		lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
-		kfree(buf_ptr1);
 	}
 
 	if (elsiocb->context3) {
 		buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
-		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
-		kfree(buf_ptr);
+		lpfc_els_free_bpl(phba, buf_ptr);
 	}
 	lpfc_sli_release_iocbq(phba, elsiocb);
 	return 0;
@@ -2065,15 +2214,20 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			 "Data: x%x x%x x%x\n",
 			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
 			 ndlp->nlp_rpi);
-	switch (ndlp->nlp_state) {
-	case NLP_STE_UNUSED_NODE:	/* node is just allocated */
-		lpfc_drop_node(vport, ndlp);
-		break;
-	case NLP_STE_NPR_NODE:		/* NPort Recovery mode */
-		lpfc_unreg_rpi(vport, ndlp);
-		break;
-	default:
-		break;
+
+	if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
+		/* NPort Recovery mode or node is just allocated */
+		if (!lpfc_nlp_not_used(ndlp)) {
+			/* If the ndlp is being used by another discovery
+			 * thread, just unregister the RPI.
+			 */
+			lpfc_unreg_rpi(vport, ndlp);
+		} else {
+			/* Indicate the node has already released, should
+			 * not reference to it from within lpfc_els_free_iocb.
+			 */
+			cmdiocb->context1 = NULL;
+		}
 	}
 	lpfc_els_free_iocb(phba, cmdiocb);
 	return;
@@ -2089,7 +2243,14 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
 	mempool_free(pmb, phba->mbox_mem_pool);
-	lpfc_nlp_put(ndlp);
+	if (ndlp) {
+		lpfc_nlp_put(ndlp);
+		/* This is the end of the default RPI cleanup logic for this
+		 * ndlp. If no other discovery threads are using this ndlp.
+		 * we should free all resources associated with it.
+		 */
+		lpfc_nlp_not_used(ndlp);
+	}
 	return;
 }
 
@@ -2100,15 +2261,29 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
 	struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
 	struct Scsi_Host  *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
-	IOCB_t *irsp;
+	IOCB_t  *irsp;
+	uint8_t *pcmd;
 	LPFC_MBOXQ_t *mbox = NULL;
 	struct lpfc_dmabuf *mp = NULL;
+	uint32_t ls_rjt = 0;
 
 	irsp = &rspiocb->iocb;
 
 	if (cmdiocb->context_un.mbox)
 		mbox = cmdiocb->context_un.mbox;
 
+	/* First determine if this is a LS_RJT cmpl. Note, this callback
+	 * function can have cmdiocb->contest1 (ndlp) field set to NULL.
+	 */
+	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
+	if (ndlp && (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) {
+		/* A LS_RJT associated with Default RPI cleanup has its own
+		 * seperate code path.
+		 */
+		if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
+			ls_rjt = 1;
+	}
+
 	/* Check to see if link went down during discovery */
 	if (!ndlp || lpfc_els_chk_latt(vport)) {
 		if (mbox) {
@@ -2119,6 +2294,15 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			}
 			mempool_free(mbox, phba->mbox_mem_pool);
 		}
+		if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
+			if (lpfc_nlp_not_used(ndlp)) {
+				ndlp = NULL;
+				/* Indicate the node has already released,
+				 * should not reference to it from within
+				 * the routine lpfc_els_free_iocb.
+				 */
+				cmdiocb->context1 = NULL;
+			}
 		goto out;
 	}
 
@@ -2150,20 +2334,39 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 				lpfc_nlp_set_state(vport, ndlp,
 					   NLP_STE_REG_LOGIN_ISSUE);
 			}
-			if (lpfc_sli_issue_mbox(phba, mbox,
-						(MBX_NOWAIT | MBX_STOP_IOCB))
+			if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
 			    != MBX_NOT_FINISHED) {
 				goto out;
 			}
-			lpfc_nlp_put(ndlp);
-			/* NOTE: we should have messages for unsuccessful
-			   reglogin */
+
+			/* ELS rsp: Cannot issue reg_login for <NPortid> */
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				"0138 ELS rsp: Cannot issue reg_login for x%x "
+				"Data: x%x x%x x%x\n",
+				ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+				ndlp->nlp_rpi);
+
+			if (lpfc_nlp_not_used(ndlp)) {
+				ndlp = NULL;
+				/* Indicate node has already been released,
+				 * should not reference to it from within
+				 * the routine lpfc_els_free_iocb.
+				 */
+				cmdiocb->context1 = NULL;
+			}
 		} else {
 			/* Do not drop node for lpfc_els_abort'ed ELS cmds */
 			if (!lpfc_error_lost_link(irsp) &&
 			    ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
-				lpfc_drop_node(vport, ndlp);
-				ndlp = NULL;
+				if (lpfc_nlp_not_used(ndlp)) {
+					ndlp = NULL;
+					/* Indicate node has already been
+					 * released, should not reference
+					 * to it from within the routine
+					 * lpfc_els_free_iocb.
+					 */
+					cmdiocb->context1 = NULL;
+				}
 			}
 		}
 		mp = (struct lpfc_dmabuf *) mbox->context1;
@@ -2178,7 +2381,21 @@ out:
 		spin_lock_irq(shost->host_lock);
 		ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
 		spin_unlock_irq(shost->host_lock);
+
+		/* If the node is not being used by another discovery thread,
+		 * and we are sending a reject, we are done with it.
+		 * Release driver reference count here and free associated
+		 * resources.
+		 */
+		if (ls_rjt)
+			if (lpfc_nlp_not_used(ndlp))
+				/* Indicate node has already been released,
+				 * should not reference to it from within
+				 * the routine lpfc_els_free_iocb.
+				 */
+				cmdiocb->context1 = NULL;
 	}
+
 	lpfc_els_free_iocb(phba, cmdiocb);
 	return;
 }
@@ -2349,14 +2566,6 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
 
-	/* If the node is in the UNUSED state, and we are sending
-	 * a reject, we are done with it.  Release driver reference
-	 * count here.  The outstanding els will release its reference on
-	 * completion and the node can be freed then.
-	 */
-	if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
-		lpfc_nlp_put(ndlp);
-
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
@@ -2642,7 +2851,10 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport)
 			}
 		}
 	}
-	if (sentplogi == 0) {
+	if (sentplogi) {
+		lpfc_set_disctmo(vport);
+	}
+	else {
 		spin_lock_irq(shost->host_lock);
 		vport->fc_flag &= ~FC_NLP_MORE;
 		spin_unlock_irq(shost->host_lock);
@@ -2830,10 +3042,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 			"RCV RSCN defer:  did:x%x/ste:x%x flg:x%x",
 			ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
 
+		spin_lock_irq(shost->host_lock);
 		vport->fc_flag |= FC_RSCN_DEFERRED;
 		if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
 		    !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
-			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_RSCN_MODE;
 			spin_unlock_irq(shost->host_lock);
 			if (rscn_cnt) {
@@ -2862,7 +3074,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 					 vport->fc_rscn_id_cnt, vport->fc_flag,
 					 vport->port_state);
 		} else {
-			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_RSCN_DISCOVERY;
 			spin_unlock_irq(shost->host_lock);
 			/* ReDiscovery RSCN */
@@ -2877,7 +3088,9 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 
 		/* send RECOVERY event for ALL nodes that match RSCN payload */
 		lpfc_rscn_recovery_check(vport);
+		spin_lock_irq(shost->host_lock);
 		vport->fc_flag &= ~FC_RSCN_DEFERRED;
+		spin_unlock_irq(shost->host_lock);
 		return 0;
 	}
 
@@ -2929,6 +3142,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport)
 
 	/* To process RSCN, first compare RSCN data with NameServer */
 	vport->fc_ns_retry = 0;
+	vport->num_disc_nodes = 0;
+
 	ndlp = lpfc_findnode_did(vport, NameServer_DID);
 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
 		/* Good ndlp, issue CT Request to NameServer */
@@ -3022,8 +3237,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 			mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
 			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 			mbox->vport = vport;
-			rc = lpfc_sli_issue_mbox
-				(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
 			lpfc_set_loopback_flag(phba);
 			if (rc == MBX_NOT_FINISHED) {
 				mempool_free(mbox, phba->mbox_mem_pool);
@@ -3140,7 +3354,10 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
 				     lpfc_max_els_tries, ndlp,
 				     ndlp->nlp_DID, ELS_CMD_ACC);
+
+	/* Decrement the ndlp reference count from previous mbox command */
 	lpfc_nlp_put(ndlp);
+
 	if (!elsiocb)
 		return;
 
@@ -3160,13 +3377,13 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 		status |= 0x4;
 
 	rps_rsp->rsvd1 = 0;
-	rps_rsp->portStatus = be16_to_cpu(status);
-	rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
-	rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
-	rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
-	rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
-	rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
-	rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
+	rps_rsp->portStatus = cpu_to_be16(status);
+	rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
+	rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
+	rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
+	rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
+	rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
+	rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
 	/* Xmit ELS RPS ACC response tag <ulpIoTag> */
 	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
 			 "0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
@@ -3223,11 +3440,13 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 			mbox->context2 = lpfc_nlp_get(ndlp);
 			mbox->vport = vport;
 			mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
-			if (lpfc_sli_issue_mbox (phba, mbox,
-			    (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED)
+			if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
+				!= MBX_NOT_FINISHED)
 				/* Mbox completion will send ELS Response */
 				return 0;
-
+			/* Decrement reference count used for the failed mbox
+			 * command.
+			 */
 			lpfc_nlp_put(ndlp);
 			mempool_free(mbox, phba->mbox_mem_pool);
 		}
@@ -3461,6 +3680,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 					 * other NLP_FABRIC logins
 					 */
 					lpfc_drop_node(vport, ndlp);
+
 				} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
 					/* Fail outstanding I/O now since this
 					 * device is marked for PLOGI
@@ -3469,8 +3689,6 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 				}
 			}
 
-			vport->port_state = LPFC_FLOGI;
-			lpfc_set_disctmo(vport);
 			lpfc_initial_flogi(vport);
 			return 0;
 		}
@@ -3711,6 +3929,7 @@ static void
 lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		      struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
 {
+	struct Scsi_Host  *shost;
 	struct lpfc_nodelist *ndlp;
 	struct ls_rjt stat;
 	uint32_t *payload;
@@ -3750,11 +3969,19 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 			goto dropit;
 
 		lpfc_nlp_init(vport, ndlp, did);
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 		newnode = 1;
 		if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
 			ndlp->nlp_type |= NLP_FABRIC;
 		}
-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+	}
+	else {
+		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
+			/* This is simular to the new node path */
+			lpfc_nlp_get(ndlp);
+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+			newnode = 1;
+		}
 	}
 
 	phba->fc_stat.elsRcvFrame++;
@@ -3783,6 +4010,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 			rjt_err = LSRJT_UNABLE_TPC;
 			break;
 		}
+
+		shost = lpfc_shost_from_vport(vport);
+		spin_lock_irq(shost->host_lock);
+		ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
+		spin_unlock_irq(shost->host_lock);
+
 		lpfc_disc_state_machine(vport, ndlp, elsiocb,
 					NLP_EVT_RCV_PLOGI);
 
@@ -3795,7 +4028,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		phba->fc_stat.elsRcvFLOGI++;
 		lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
 		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+			lpfc_nlp_put(ndlp);
 		break;
 	case ELS_CMD_LOGO:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3825,7 +4058,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		phba->fc_stat.elsRcvRSCN++;
 		lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
 		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+			lpfc_nlp_put(ndlp);
 		break;
 	case ELS_CMD_ADISC:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3897,7 +4130,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		phba->fc_stat.elsRcvLIRR++;
 		lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
 		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+			lpfc_nlp_put(ndlp);
 		break;
 	case ELS_CMD_RPS:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3907,7 +4140,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		phba->fc_stat.elsRcvRPS++;
 		lpfc_els_rcv_rps(vport, elsiocb, ndlp);
 		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+			lpfc_nlp_put(ndlp);
 		break;
 	case ELS_CMD_RPL:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3917,7 +4150,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		phba->fc_stat.elsRcvRPL++;
 		lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
 		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+			lpfc_nlp_put(ndlp);
 		break;
 	case ELS_CMD_RNID:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3927,7 +4160,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		phba->fc_stat.elsRcvRNID++;
 		lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
 		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+			lpfc_nlp_put(ndlp);
 		break;
 	default:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3942,7 +4175,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 				 "0115 Unknown ELS command x%x "
 				 "received from NPORT x%x\n", cmd, did);
 		if (newnode)
-			lpfc_drop_node(vport, ndlp);
+			lpfc_nlp_put(ndlp);
 		break;
 	}
 
@@ -3958,10 +4191,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	return;
 
 dropit:
-	lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+	if (vport && !(vport->load_flag & FC_UNLOADING))
+		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
 			"(%d):0111 Dropping received ELS cmd "
 			"Data: x%x x%x x%x\n",
-			vport ? vport->vpi : 0xffff, icmd->ulpStatus,
+			vport->vpi, icmd->ulpStatus,
 			icmd->un.ulpWord[4], icmd->ulpTimeout);
 	phba->fc_stat.elsRcvDrop++;
 }
@@ -4114,8 +4348,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
 	MAILBOX_t *mb = &pmb->mb;
 
+	spin_lock_irq(shost->host_lock);
 	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
-	lpfc_nlp_put(ndlp);
+	spin_unlock_irq(shost->host_lock);
 
 	if (mb->mbxStatus) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
@@ -4135,7 +4370,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 		default:
 			/* Try to recover from this error */
 			lpfc_mbx_unreg_vpi(vport);
+			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+			spin_unlock_irq(shost->host_lock);
 			lpfc_initial_fdisc(vport);
 			break;
 		}
@@ -4146,14 +4383,21 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 		else
 			lpfc_do_scr_ns_plogi(phba, vport);
 	}
+
+	/* Now, we decrement the ndlp reference count held for this
+	 * callback function
+	 */
+	lpfc_nlp_put(ndlp);
+
 	mempool_free(pmb, phba->mbox_mem_pool);
 	return;
 }
 
-void
+static void
 lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
 			struct lpfc_nodelist *ndlp)
 {
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	LPFC_MBOXQ_t *mbox;
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -4162,25 +4406,31 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
 		mbox->vport = vport;
 		mbox->context2 = lpfc_nlp_get(ndlp);
 		mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
-		if (lpfc_sli_issue_mbox(phba, mbox,
-					MBX_NOWAIT | MBX_STOP_IOCB)
+		if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
 		    == MBX_NOT_FINISHED) {
+			/* mailbox command not success, decrement ndlp
+			 * reference count for this command
+			 */
+			lpfc_nlp_put(ndlp);
 			mempool_free(mbox, phba->mbox_mem_pool);
-			vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
 
-			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
 				"0253 Register VPI: Can't send mbox\n");
+			goto mbox_err_exit;
 		}
 	} else {
-		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
 				 "0254 Register VPI: no memory\n");
-
-		vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
-		lpfc_nlp_put(ndlp);
+		goto mbox_err_exit;
 	}
+	return;
+
+mbox_err_exit:
+	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+	spin_lock_irq(shost->host_lock);
+	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+	spin_unlock_irq(shost->host_lock);
+	return;
 }
 
 static void
@@ -4251,7 +4501,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 				lpfc_unreg_rpi(vport, np);
 			}
 			lpfc_mbx_unreg_vpi(vport);
+			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+			spin_unlock_irq(shost->host_lock);
 		}
 
 		if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
@@ -4259,14 +4511,15 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 		else
 			lpfc_do_scr_ns_plogi(phba, vport);
 
-		lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */
+		/* Unconditionaly kick off releasing fabric node for vports */
+		lpfc_nlp_put(ndlp);
 	}
 
 out:
 	lpfc_els_free_iocb(phba, cmdiocb);
 }
 
-int
+static int
 lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		     uint8_t retry)
 {
@@ -4539,7 +4792,7 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 	}
 }
 
-int
+static int
 lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
 {
 	unsigned long iflags;
@@ -4583,7 +4836,7 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
 }
 
 
-void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
+static void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
 {
 	LIST_HEAD(completions);
 	struct lpfc_hba  *phba = vport->phba;
@@ -4663,6 +4916,7 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
 }
 
 
+#if 0
 void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
 {
 	LIST_HEAD(completions);
@@ -4693,5 +4947,6 @@ void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
 		(piocb->iocb_cmpl) (phba, piocb, piocb);
 	}
 }
+#endif  /*  0  */
 
 
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index c81c2b3228d6..dc042bd97baa 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -57,6 +57,7 @@ static uint8_t lpfcAlpaArray[] = {
 };
 
 static void lpfc_disc_timeout_handler(struct lpfc_vport *);
+static void lpfc_disc_flush_list(struct lpfc_vport *vport);
 
 void
 lpfc_terminate_rport_io(struct fc_rport *rport)
@@ -107,20 +108,14 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
 	struct lpfc_nodelist * ndlp;
 	struct lpfc_vport *vport;
 	struct lpfc_hba   *phba;
-	struct completion devloss_compl;
 	struct lpfc_work_evt *evtp;
+	int  put_node;
+	int  put_rport;
 
 	rdata = rport->dd_data;
 	ndlp = rdata->pnode;
-
-	if (!ndlp) {
-		if (rport->scsi_target_id != -1) {
-			printk(KERN_ERR "Cannot find remote node"
-				" for rport in dev_loss_tmo_callbk x%x\n",
-				rport->port_id);
-		}
+	if (!ndlp)
 		return;
-	}
 
 	vport = ndlp->vport;
 	phba  = vport->phba;
@@ -129,15 +124,35 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
 		"rport devlosscb: sid:x%x did:x%x flg:x%x",
 		ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
 
-	init_completion(&devloss_compl);
+	/* Don't defer this if we are in the process of deleting the vport
+	 * or unloading the driver. The unload will cleanup the node
+	 * appropriately we just need to cleanup the ndlp rport info here.
+	 */
+	if (vport->load_flag & FC_UNLOADING) {
+		put_node = rdata->pnode != NULL;
+		put_rport = ndlp->rport != NULL;
+		rdata->pnode = NULL;
+		ndlp->rport = NULL;
+		if (put_node)
+			lpfc_nlp_put(ndlp);
+		if (put_rport)
+			put_device(&rport->dev);
+		return;
+	}
+
+	if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+		return;
+
 	evtp = &ndlp->dev_loss_evt;
 
 	if (!list_empty(&evtp->evt_listp))
 		return;
 
 	spin_lock_irq(&phba->hbalock);
-	evtp->evt_arg1  = ndlp;
-	evtp->evt_arg2  = &devloss_compl;
+	/* We need to hold the node by incrementing the reference
+	 * count until this queued work is done
+	 */
+	evtp->evt_arg1  = lpfc_nlp_get(ndlp);
 	evtp->evt       = LPFC_EVT_DEV_LOSS;
 	list_add_tail(&evtp->evt_listp, &phba->work_list);
 	if (phba->work_wait)
@@ -145,8 +160,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
 
 	spin_unlock_irq(&phba->hbalock);
 
-	wait_for_completion(&devloss_compl);
-
 	return;
 }
 
@@ -154,7 +167,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
  * This function is called from the worker thread when dev_loss_tmo
  * expire.
  */
-void
+static void
 lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
 {
 	struct lpfc_rport_data *rdata;
@@ -162,6 +175,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
 	struct lpfc_vport *vport;
 	struct lpfc_hba   *phba;
 	uint8_t *name;
+	int  put_node;
+	int  put_rport;
 	int warn_on = 0;
 
 	rport = ndlp->rport;
@@ -178,14 +193,32 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
 		"rport devlosstmo:did:x%x type:x%x id:x%x",
 		ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
 
-	if (!(vport->load_flag & FC_UNLOADING) &&
-	    ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+	/* Don't defer this if we are in the process of deleting the vport
+	 * or unloading the driver. The unload will cleanup the node
+	 * appropriately we just need to cleanup the ndlp rport info here.
+	 */
+	if (vport->load_flag & FC_UNLOADING) {
+		if (ndlp->nlp_sid != NLP_NO_SID) {
+			/* flush the target */
+			lpfc_sli_abort_iocb(vport,
+					&phba->sli.ring[phba->sli.fcp_ring],
+					ndlp->nlp_sid, 0, LPFC_CTX_TGT);
+		}
+		put_node = rdata->pnode != NULL;
+		put_rport = ndlp->rport != NULL;
+		rdata->pnode = NULL;
+		ndlp->rport = NULL;
+		if (put_node)
+			lpfc_nlp_put(ndlp);
+		if (put_rport)
+			put_device(&rport->dev);
 		return;
+	}
 
-	if (ndlp->nlp_type & NLP_FABRIC) {
-		int  put_node;
-		int  put_rport;
+	if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+		return;
 
+	if (ndlp->nlp_type & NLP_FABRIC) {
 		/* We will clean up these Nodes in linkup */
 		put_node = rdata->pnode != NULL;
 		put_rport = ndlp->rport != NULL;
@@ -227,23 +260,20 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
 				 ndlp->nlp_state, ndlp->nlp_rpi);
 	}
 
+	put_node = rdata->pnode != NULL;
+	put_rport = ndlp->rport != NULL;
+	rdata->pnode = NULL;
+	ndlp->rport = NULL;
+	if (put_node)
+		lpfc_nlp_put(ndlp);
+	if (put_rport)
+		put_device(&rport->dev);
+
 	if (!(vport->load_flag & FC_UNLOADING) &&
 	    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
 	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
-	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
+	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) {
 		lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
-	else {
-		int  put_node;
-		int  put_rport;
-
-		put_node = rdata->pnode != NULL;
-		put_rport = ndlp->rport != NULL;
-		rdata->pnode = NULL;
-		ndlp->rport = NULL;
-		if (put_node)
-			lpfc_nlp_put(ndlp);
-		if (put_rport)
-			put_device(&rport->dev);
 	}
 }
 
@@ -260,7 +290,6 @@ lpfc_work_list_done(struct lpfc_hba *phba)
 {
 	struct lpfc_work_evt  *evtp = NULL;
 	struct lpfc_nodelist  *ndlp;
-	struct lpfc_vport     *vport;
 	int free_evt;
 
 	spin_lock_irq(&phba->hbalock);
@@ -270,35 +299,22 @@ lpfc_work_list_done(struct lpfc_hba *phba)
 		spin_unlock_irq(&phba->hbalock);
 		free_evt = 1;
 		switch (evtp->evt) {
-		case LPFC_EVT_DEV_LOSS_DELAY:
-			free_evt = 0; /* evt is part of ndlp */
-			ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
-			vport = ndlp->vport;
-			if (!vport)
-				break;
-
-			lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
-				"rport devlossdly:did:x%x flg:x%x",
-				ndlp->nlp_DID, ndlp->nlp_flag, 0);
-
-			if (!(vport->load_flag & FC_UNLOADING) &&
-			    !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
-			    !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
-				lpfc_disc_state_machine(vport, ndlp, NULL,
-					NLP_EVT_DEVICE_RM);
-			}
-			break;
 		case LPFC_EVT_ELS_RETRY:
 			ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
 			lpfc_els_retry_delay_handler(ndlp);
 			free_evt = 0; /* evt is part of ndlp */
+			/* decrement the node reference count held
+			 * for this queued work
+			 */
+			lpfc_nlp_put(ndlp);
 			break;
 		case LPFC_EVT_DEV_LOSS:
 			ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
-			lpfc_nlp_get(ndlp);
 			lpfc_dev_loss_tmo_handler(ndlp);
 			free_evt = 0;
-			complete((struct completion *)(evtp->evt_arg2));
+			/* decrement the node reference count held for
+			 * this queued work
+			 */
 			lpfc_nlp_put(ndlp);
 			break;
 		case LPFC_EVT_ONLINE:
@@ -373,7 +389,7 @@ lpfc_work_done(struct lpfc_hba *phba)
 		lpfc_handle_latt(phba);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS; i++) {
+		for(i = 0; i <= phba->max_vpi; i++) {
 			/*
 			 * We could have no vports in array if unloading, so if
 			 * this happens then just use the pport
@@ -405,14 +421,14 @@ lpfc_work_done(struct lpfc_hba *phba)
 			vport->work_port_events &= ~work_port_events;
 			spin_unlock_irq(&vport->work_port_lock);
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 
 	pring = &phba->sli.ring[LPFC_ELS_RING];
 	status = (ha_copy & (HA_RXMASK  << (4*LPFC_ELS_RING)));
 	status >>= (4*LPFC_ELS_RING);
 	if ((status & HA_RXMASK)
 		|| (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
-		if (pring->flag & LPFC_STOP_IOCB_MASK) {
+		if (pring->flag & LPFC_STOP_IOCB_EVENT) {
 			pring->flag |= LPFC_DEFERRED_RING_EVENT;
 		} else {
 			lpfc_sli_handle_slow_ring_event(phba, pring,
@@ -544,6 +560,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
 void
 lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
 {
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
 	struct lpfc_nodelist *ndlp, *next_ndlp;
 	int  rc;
@@ -552,7 +569,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
 		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
 			continue;
 
-		if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN)
+		if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) ||
+			((vport->port_type == LPFC_NPIV_PORT) &&
+			(ndlp->nlp_DID == NameServer_DID)))
 			lpfc_unreg_rpi(vport, ndlp);
 
 		/* Leave Fabric nodes alone on link down */
@@ -565,14 +584,30 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
 	}
 	if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) {
 		lpfc_mbx_unreg_vpi(vport);
+		spin_lock_irq(shost->host_lock);
 		vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+		spin_unlock_irq(shost->host_lock);
 	}
 }
 
+void
+lpfc_port_link_failure(struct lpfc_vport *vport)
+{
+	/* Cleanup any outstanding RSCN activity */
+	lpfc_els_flush_rscn(vport);
+
+	/* Cleanup any outstanding ELS commands */
+	lpfc_els_flush_cmd(vport);
+
+	lpfc_cleanup_rpis(vport, 0);
+
+	/* Turn off discovery timer if its running */
+	lpfc_can_disctmo(vport);
+}
+
 static void
 lpfc_linkdown_port(struct lpfc_vport *vport)
 {
-	struct lpfc_nodelist *ndlp, *next_ndlp;
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
 
 	fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
@@ -581,21 +616,8 @@ lpfc_linkdown_port(struct lpfc_vport *vport)
 		"Link Down:       state:x%x rtry:x%x flg:x%x",
 		vport->port_state, vport->fc_ns_retry, vport->fc_flag);
 
-	/* Cleanup any outstanding RSCN activity */
-	lpfc_els_flush_rscn(vport);
-
-	/* Cleanup any outstanding ELS commands */
-	lpfc_els_flush_cmd(vport);
+	lpfc_port_link_failure(vport);
 
-	lpfc_cleanup_rpis(vport, 0);
-
-	/* free any ndlp's on unused list */
-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
-		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
-			lpfc_drop_node(vport, ndlp);
-
-	/* Turn off discovery timer if its running */
-	lpfc_can_disctmo(vport);
 }
 
 int
@@ -618,18 +640,18 @@ lpfc_linkdown(struct lpfc_hba *phba)
 	spin_unlock_irq(&phba->hbalock);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			/* Issue a LINK DOWN event to all nodes */
 			lpfc_linkdown_port(vports[i]);
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	/* Clean up any firmware default rpi's */
 	mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (mb) {
 		lpfc_unreg_did(phba, 0xffff, 0xffffffff, mb);
 		mb->vport = vport;
 		mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
+		if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
 		    == MBX_NOT_FINISHED) {
 			mempool_free(mb, phba->mbox_mem_pool);
 		}
@@ -643,8 +665,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
 			lpfc_config_link(phba, mb);
 			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 			mb->vport = vport;
-			if (lpfc_sli_issue_mbox(phba, mb,
-						(MBX_NOWAIT | MBX_STOP_IOCB))
+			if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
 			    == MBX_NOT_FINISHED) {
 				mempool_free(mb, phba->mbox_mem_pool);
 			}
@@ -686,7 +707,6 @@ static void
 lpfc_linkup_port(struct lpfc_vport *vport)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-	struct lpfc_nodelist *ndlp, *next_ndlp;
 	struct lpfc_hba  *phba = vport->phba;
 
 	if ((vport->load_flag & FC_UNLOADING) != 0)
@@ -713,11 +733,6 @@ lpfc_linkup_port(struct lpfc_vport *vport)
 	if (vport->fc_flag & FC_LBIT)
 		lpfc_linkup_cleanup_nodes(vport);
 
-				/* free any ndlp's in unused state */
-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
-				 nlp_listp)
-		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
-			lpfc_drop_node(vport, ndlp);
 }
 
 static int
@@ -734,9 +749,9 @@ lpfc_linkup(struct lpfc_hba *phba)
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
 			lpfc_linkup_port(vports[i]);
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
 		lpfc_issue_clear_la(phba, phba->pport);
 
@@ -749,7 +764,7 @@ lpfc_linkup(struct lpfc_hba *phba)
  * as the completion routine when the command is
  * handed off to the SLI layer.
  */
-void
+static void
 lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
 	struct lpfc_vport *vport = pmb->vport;
@@ -852,8 +867,6 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	 * LPFC_FLOGI while waiting for FLOGI cmpl
 	 */
 	if (vport->port_state != LPFC_FLOGI) {
-		vport->port_state = LPFC_FLOGI;
-		lpfc_set_disctmo(vport);
 		lpfc_initial_flogi(vport);
 	}
 	return;
@@ -1022,8 +1035,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
 		lpfc_read_sparam(phba, sparam_mbox, 0);
 		sparam_mbox->vport = vport;
 		sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
-		rc = lpfc_sli_issue_mbox(phba, sparam_mbox,
-				    (MBX_NOWAIT | MBX_STOP_IOCB));
+		rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT);
 		if (rc == MBX_NOT_FINISHED) {
 			mp = (struct lpfc_dmabuf *) sparam_mbox->context1;
 			lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -1040,8 +1052,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
 		lpfc_config_link(phba, cfglink_mbox);
 		cfglink_mbox->vport = vport;
 		cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
-		rc = lpfc_sli_issue_mbox(phba, cfglink_mbox,
-				    (MBX_NOWAIT | MBX_STOP_IOCB));
+		rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT);
 		if (rc != MBX_NOT_FINISHED)
 			return;
 		mempool_free(cfglink_mbox, phba->mbox_mem_pool);
@@ -1174,6 +1185,9 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
 	mempool_free(pmb, phba->mbox_mem_pool);
+	/* decrement the node reference count held for this callback
+	 * function.
+	 */
 	lpfc_nlp_put(ndlp);
 
 	return;
@@ -1219,7 +1233,7 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
 	lpfc_unreg_vpi(phba, vport->vpi, mbox);
 	mbox->vport = vport;
 	mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi;
-	rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
 	if (rc == MBX_NOT_FINISHED) {
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
 				 "1800 Could not issue unreg_vpi\n");
@@ -1319,7 +1333,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 		vports = lpfc_create_vport_work_array(phba);
 		if (vports != NULL)
 			for(i = 0;
-			    i < LPFC_MAX_VPORTS && vports[i] != NULL;
+			    i <= phba->max_vpi && vports[i] != NULL;
 			    i++) {
 				if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
 					continue;
@@ -1335,7 +1349,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 							"Fabric support\n");
 				}
 			}
-		lpfc_destroy_vport_work_array(vports);
+		lpfc_destroy_vport_work_array(phba, vports);
 		lpfc_do_scr_ns_plogi(phba, vport);
 	}
 
@@ -1361,11 +1375,16 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 
 	if (mb->mbxStatus) {
 out:
+		/* decrement the node reference count held for this
+		 * callback function.
+		 */
 		lpfc_nlp_put(ndlp);
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
 		mempool_free(pmb, phba->mbox_mem_pool);
-		lpfc_drop_node(vport, ndlp);
+
+		/* If no other thread is using the ndlp, free it */
+		lpfc_nlp_not_used(ndlp);
 
 		if (phba->fc_topology == TOPOLOGY_LOOP) {
 			/*
@@ -1410,6 +1429,9 @@ out:
 		goto out;
 	}
 
+	/* decrement the node reference count held for this
+	 * callback function.
+	 */
 	lpfc_nlp_put(ndlp);
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
@@ -1656,8 +1678,18 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 void
 lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
+	/*
+	 * Use of lpfc_drop_node and UNUSED list: lpfc_drop_node should
+	 * be used if we wish to issue the "last" lpfc_nlp_put() to remove
+	 * the ndlp from the vport. The ndlp marked as UNUSED on the list
+	 * until ALL other outstanding threads have completed. We check
+	 * that the ndlp not already in the UNUSED state before we proceed.
+	 */
+	if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+		return;
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
 	lpfc_nlp_put(ndlp);
+	return;
 }
 
 /*
@@ -1868,8 +1900,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 			lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
 			mbox->vport = vport;
 			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-			rc = lpfc_sli_issue_mbox(phba, mbox,
-						 (MBX_NOWAIT | MBX_STOP_IOCB));
+			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
 			if (rc == MBX_NOT_FINISHED)
 				mempool_free(mbox, phba->mbox_mem_pool);
 		}
@@ -1892,8 +1923,8 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport)
 		lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox);
 		mbox->vport = vport;
 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		rc = lpfc_sli_issue_mbox(phba, mbox,
-					 (MBX_NOWAIT | MBX_STOP_IOCB));
+		mbox->context1 = NULL;
+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
 		if (rc == MBX_NOT_FINISHED) {
 			mempool_free(mbox, phba->mbox_mem_pool);
 		}
@@ -1912,8 +1943,8 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport)
 		lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox);
 		mbox->vport = vport;
 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		rc = lpfc_sli_issue_mbox(phba, mbox,
-					 (MBX_NOWAIT | MBX_STOP_IOCB));
+		mbox->context1 = NULL;
+		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
 		if (rc == MBX_NOT_FINISHED) {
 			lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
 					 "1815 Could not issue "
@@ -1981,11 +2012,6 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 	if (!list_empty(&ndlp->dev_loss_evt.evt_listp))
 		list_del_init(&ndlp->dev_loss_evt.evt_listp);
 
-	if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) {
-		list_del_init(&ndlp->dev_loss_evt.evt_listp);
-		complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2));
-	}
-
 	lpfc_unreg_rpi(vport, ndlp);
 
 	return 0;
@@ -1999,12 +2025,39 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 static void
 lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
+	struct lpfc_hba  *phba = vport->phba;
 	struct lpfc_rport_data *rdata;
+	LPFC_MBOXQ_t *mbox;
+	int rc;
 
 	if (ndlp->nlp_flag & NLP_DELAY_TMO) {
 		lpfc_cancel_retry_delay_tmo(vport, ndlp);
 	}
 
+	if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) {
+		/* For this case we need to cleanup the default rpi
+		 * allocated by the firmware.
+		 */
+		if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))
+			!= NULL) {
+			rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID,
+			    (uint8_t *) &vport->fc_sparam, mbox, 0);
+			if (rc) {
+				mempool_free(mbox, phba->mbox_mem_pool);
+			}
+			else {
+				mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
+				mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+				mbox->vport = vport;
+				mbox->context2 = NULL;
+				rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+				if (rc == MBX_NOT_FINISHED) {
+					mempool_free(mbox, phba->mbox_mem_pool);
+				}
+			}
+		}
+	}
+
 	lpfc_cleanup_node(vport, ndlp);
 
 	/*
@@ -2132,6 +2185,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
 	}
 	if (vport->fc_flag & FC_RSCN_MODE) {
 		if (lpfc_rscn_payload_check(vport, did)) {
+			/* If we've already recieved a PLOGI from this NPort
+			 * we don't need to try to discover it again.
+			 */
+			if (ndlp->nlp_flag & NLP_RCV_PLOGI)
+				return NULL;
+
 			spin_lock_irq(shost->host_lock);
 			ndlp->nlp_flag |= NLP_NPR_2B_DISC;
 			spin_unlock_irq(shost->host_lock);
@@ -2144,8 +2203,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
 		} else
 			ndlp = NULL;
 	} else {
+		/* If we've already recieved a PLOGI from this NPort,
+		 * or we are already in the process of discovery on it,
+		 * we don't need to try to discover it again.
+		 */
 		if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
-		    ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
+		    ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
+		    ndlp->nlp_flag & NLP_RCV_PLOGI)
 			return NULL;
 		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 		spin_lock_irq(shost->host_lock);
@@ -2220,8 +2284,7 @@ lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport)
 		lpfc_clear_la(phba, mbox);
 		mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
 		mbox->vport = vport;
-		rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT |
-						      MBX_STOP_IOCB));
+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
 		if (rc == MBX_NOT_FINISHED) {
 			mempool_free(mbox, phba->mbox_mem_pool);
 			lpfc_disc_flush_list(vport);
@@ -2244,8 +2307,7 @@ lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport)
 		lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox);
 		regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi;
 		regvpimbox->vport = vport;
-		if (lpfc_sli_issue_mbox(phba, regvpimbox,
-					(MBX_NOWAIT | MBX_STOP_IOCB))
+		if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT)
 					== MBX_NOT_FINISHED) {
 			mempool_free(regvpimbox, phba->mbox_mem_pool);
 		}
@@ -2414,7 +2476,7 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 	}
 }
 
-void
+static void
 lpfc_disc_flush_list(struct lpfc_vport *vport)
 {
 	struct lpfc_nodelist *ndlp, *next_ndlp;
@@ -2426,7 +2488,6 @@ lpfc_disc_flush_list(struct lpfc_vport *vport)
 			if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
 			    ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
 				lpfc_free_tx(phba, ndlp);
-				lpfc_nlp_put(ndlp);
 			}
 		}
 	}
@@ -2516,6 +2577,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 			if (ndlp->nlp_type & NLP_FABRIC) {
 				/* Clean up the ndlp on Fabric connections */
 				lpfc_drop_node(vport, ndlp);
+
 			} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
 				/* Fail outstanding IO now since device
 				 * is marked for PLOGI.
@@ -2524,9 +2586,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 			}
 		}
 		if (vport->port_state != LPFC_FLOGI) {
-			vport->port_state = LPFC_FLOGI;
-			lpfc_set_disctmo(vport);
 			lpfc_initial_flogi(vport);
+			return;
 		}
 		break;
 
@@ -2536,7 +2597,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 		/* Initial FLOGI timeout */
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
 				 "0222 Initial %s timeout\n",
-				 vport->vpi ? "FLOGI" : "FDISC");
+				 vport->vpi ? "FDISC" : "FLOGI");
 
 		/* Assume no Fabric and go on with discovery.
 		 * Check for outstanding ELS FLOGI to abort.
@@ -2558,10 +2619,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 		/* Next look for NameServer ndlp */
 		ndlp = lpfc_findnode_did(vport, NameServer_DID);
 		if (ndlp)
-			lpfc_nlp_put(ndlp);
-		/* Start discovery */
-		lpfc_disc_start(vport);
-		break;
+			lpfc_els_abort(phba, ndlp);
+
+		/* ReStart discovery */
+		goto restart_disc;
 
 	case LPFC_NS_QRY:
 	/* Check for wait for NameServer Rsp timeout */
@@ -2580,6 +2641,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 		}
 		vport->fc_ns_retry = 0;
 
+restart_disc:
 		/*
 		 * Discovery is over.
 		 * set port_state to PORT_READY if SLI2.
@@ -2608,8 +2670,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 		initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
 		initlinkmbox->vport = vport;
 		initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-		rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
-					 (MBX_NOWAIT | MBX_STOP_IOCB));
+		rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT);
 		lpfc_set_loopback_flag(phba);
 		if (rc == MBX_NOT_FINISHED)
 			mempool_free(initlinkmbox, phba->mbox_mem_pool);
@@ -2664,12 +2725,14 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport)
 		clrlaerr = 1;
 		break;
 
+	case LPFC_LINK_UP:
+		lpfc_issue_clear_la(phba, vport);
+		/* Drop thru */
 	case LPFC_LINK_UNKNOWN:
 	case LPFC_WARM_START:
 	case LPFC_INIT_START:
 	case LPFC_INIT_MBX_CMDS:
 	case LPFC_LINK_DOWN:
-	case LPFC_LINK_UP:
 	case LPFC_HBA_ERROR:
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
 				 "0230 Unexpected timeout, hba link "
@@ -2723,7 +2786,9 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 	else
 		mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
 
-				/* Mailbox took a reference to the node */
+	/* decrement the node reference count held for this callback
+	 * function.
+	 */
 	lpfc_nlp_put(ndlp);
 	lpfc_mbuf_free(phba, mp->virt, mp->phys);
 	kfree(mp);
@@ -2747,19 +2812,19 @@ lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param)
 		      sizeof(ndlp->nlp_portname)) == 0;
 }
 
-struct lpfc_nodelist *
+static struct lpfc_nodelist *
 __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
 {
 	struct lpfc_nodelist *ndlp;
 
 	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
-		if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
-		    filter(ndlp, param))
+		if (filter(ndlp, param))
 			return ndlp;
 	}
 	return NULL;
 }
 
+#if 0
 /*
  * Search node lists for a remote port matching filter criteria
  * Caller needs to hold host_lock before calling this routine.
@@ -2775,6 +2840,7 @@ lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
 	spin_unlock_irq(shost->host_lock);
 	return ndlp;
 }
+#endif  /*  0  */
 
 /*
  * This routine looks up the ndlp lists for the given RPI. If rpi found it
@@ -2786,6 +2852,7 @@ __lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
 	return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi);
 }
 
+#if 0
 struct lpfc_nodelist *
 lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
 {
@@ -2797,6 +2864,7 @@ lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
 	spin_unlock_irq(shost->host_lock);
 	return ndlp;
 }
+#endif  /*  0  */
 
 /*
  * This routine looks up the ndlp lists for the given WWPN. If WWPN found it
@@ -2837,6 +2905,9 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	return;
 }
 
+/* This routine releases all resources associated with a specifc NPort's ndlp
+ * and mempool_free's the nodelist.
+ */
 static void
 lpfc_nlp_release(struct kref *kref)
 {
@@ -2851,16 +2922,57 @@ lpfc_nlp_release(struct kref *kref)
 	mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool);
 }
 
+/* This routine bumps the reference count for a ndlp structure to ensure
+ * that one discovery thread won't free a ndlp while another discovery thread
+ * is using it.
+ */
 struct lpfc_nodelist *
 lpfc_nlp_get(struct lpfc_nodelist *ndlp)
 {
-	if (ndlp)
+	if (ndlp) {
+		lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
+			"node get:        did:x%x flg:x%x refcnt:x%x",
+			ndlp->nlp_DID, ndlp->nlp_flag,
+			atomic_read(&ndlp->kref.refcount));
 		kref_get(&ndlp->kref);
+	}
 	return ndlp;
 }
 
+
+/* This routine decrements the reference count for a ndlp structure. If the
+ * count goes to 0, this indicates the the associated nodelist should be freed.
+ */
 int
 lpfc_nlp_put(struct lpfc_nodelist *ndlp)
 {
+	if (ndlp) {
+		lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
+		"node put:        did:x%x flg:x%x refcnt:x%x",
+			ndlp->nlp_DID, ndlp->nlp_flag,
+			atomic_read(&ndlp->kref.refcount));
+	}
 	return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
 }
+
+/* This routine free's the specified nodelist if it is not in use
+ * by any other discovery thread. This routine returns 1 if the ndlp
+ * is not being used by anyone and has been freed. A return value of
+ * 0 indicates it is being used by another discovery thread and the
+ * refcount is left unchanged.
+ */
+int
+lpfc_nlp_not_used(struct lpfc_nodelist *ndlp)
+{
+	lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
+		"node not used:   did:x%x flg:x%x refcnt:x%x",
+		ndlp->nlp_DID, ndlp->nlp_flag,
+		atomic_read(&ndlp->kref.refcount));
+
+	if (atomic_read(&ndlp->kref.refcount) == 1) {
+		lpfc_nlp_put(ndlp);
+		return 1;
+	}
+	return 0;
+}
+
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 451accd5564b..041f83e7634a 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -139,6 +139,9 @@ struct lpfc_sli_ct_request {
 			uint8_t len;
 			uint8_t symbname[255];
 		} rsnn;
+		struct da_id { /* For DA_ID requests */
+			uint32_t port_id;
+		} da_id;
 		struct rspn {	/* For RSPN_ID requests */
 			uint32_t PortId;
 			uint8_t len;
@@ -150,11 +153,7 @@ struct lpfc_sli_ct_request {
 		struct gff_acc {
 			uint8_t fbits[128];
 		} gff_acc;
-#ifdef __BIG_ENDIAN_BITFIELD
 #define FCP_TYPE_FEATURE_OFFSET 7
-#else	/*  __LITTLE_ENDIAN_BITFIELD */
-#define FCP_TYPE_FEATURE_OFFSET 4
-#endif
 		struct rff {
 			uint32_t PortId;
 			uint8_t reserved[2];
@@ -177,6 +176,8 @@ struct lpfc_sli_ct_request {
 			   sizeof(struct rnn))
 #define  RSNN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \
 			   sizeof(struct rsnn))
+#define DA_ID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+			  sizeof(struct da_id))
 #define  RSPN_REQUEST_SZ  (offsetof(struct lpfc_sli_ct_request, un) + \
 			   sizeof(struct rspn))
 
@@ -1228,7 +1229,8 @@ typedef struct {		/* FireFly BIU registers */
 #define HS_FFER3       0x20000000	/* Bit 29 */
 #define HS_FFER2       0x40000000	/* Bit 30 */
 #define HS_FFER1       0x80000000	/* Bit 31 */
-#define HS_FFERM       0xFF000000	/* Mask for error bits 31:24 */
+#define HS_CRIT_TEMP   0x00000100	/* Bit 8  */
+#define HS_FFERM       0xFF000100	/* Mask for error bits 31:24 and 8 */
 
 /* Host Control Register */
 
@@ -1277,12 +1279,14 @@ typedef struct {		/* FireFly BIU registers */
 #define MBX_DEL_LD_ENTRY    0x1D
 #define MBX_RUN_PROGRAM     0x1E
 #define MBX_SET_MASK        0x20
-#define MBX_SET_SLIM        0x21
+#define MBX_SET_VARIABLE    0x21
 #define MBX_UNREG_D_ID      0x23
 #define MBX_KILL_BOARD      0x24
 #define MBX_CONFIG_FARP     0x25
 #define MBX_BEACON          0x2A
 #define MBX_HEARTBEAT       0x31
+#define MBX_WRITE_VPARMS    0x32
+#define MBX_ASYNCEVT_ENABLE 0x33
 
 #define MBX_CONFIG_HBQ	    0x7C
 #define MBX_LOAD_AREA       0x81
@@ -1297,7 +1301,7 @@ typedef struct {		/* FireFly BIU registers */
 #define MBX_REG_VNPID	    0x96
 #define MBX_UNREG_VNPID	    0x97
 
-#define MBX_FLASH_WR_ULA    0x98
+#define MBX_WRITE_WWN       0x98
 #define MBX_SET_DEBUG       0x99
 #define MBX_LOAD_EXP_ROM    0x9C
 
@@ -1344,6 +1348,7 @@ typedef struct {		/* FireFly BIU registers */
 
 /*  SLI_2 IOCB Command Set */
 
+#define CMD_ASYNC_STATUS        0x7C
 #define CMD_RCV_SEQUENCE64_CX   0x81
 #define CMD_XMIT_SEQUENCE64_CR  0x82
 #define CMD_XMIT_SEQUENCE64_CX  0x83
@@ -1368,6 +1373,7 @@ typedef struct {		/* FireFly BIU registers */
 #define CMD_FCP_TRECEIVE64_CX   0xA1
 #define CMD_FCP_TRSP64_CX       0xA3
 
+#define CMD_QUE_XRI64_CX	0xB3
 #define CMD_IOCB_RCV_SEQ64_CX	0xB5
 #define CMD_IOCB_RCV_ELS64_CX	0xB7
 #define CMD_IOCB_RCV_CONT64_CX	0xBB
@@ -1406,6 +1412,8 @@ typedef struct {		/* FireFly BIU registers */
 #define MBX_BUSY                   0xffffff /* Attempted cmd to busy Mailbox */
 #define MBX_TIMEOUT                0xfffffe /* time-out expired waiting for */
 
+#define TEMPERATURE_OFFSET 0xB0	/* Slim offset for critical temperature event */
+
 /*
  *    Begin Structure Definitions for Mailbox Commands
  */
@@ -2606,6 +2614,18 @@ typedef struct {
 	uint32_t IPAddress;
 } CONFIG_FARP_VAR;
 
+/* Structure for MB Command MBX_ASYNCEVT_ENABLE (0x33) */
+
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rsvd:30;
+	uint32_t ring:2;	/* Ring for ASYNC_EVENT iocb Bits 0-1*/
+#else /*  __LITTLE_ENDIAN */
+	uint32_t ring:2;	/* Ring for ASYNC_EVENT iocb Bits 0-1*/
+	uint32_t rsvd:30;
+#endif
+} ASYNCEVT_ENABLE_VAR;
+
 /* Union of all Mailbox Command types */
 #define MAILBOX_CMD_WSIZE	32
 #define MAILBOX_CMD_SIZE	(MAILBOX_CMD_WSIZE * sizeof(uint32_t))
@@ -2645,6 +2665,7 @@ typedef union {
 	CONFIG_PORT_VAR varCfgPort;	/* cmd = 0x88 (CONFIG_PORT)  */
 	REG_VPI_VAR varRegVpi;		/* cmd = 0x96 (REG_VPI) */
 	UNREG_VPI_VAR varUnregVpi;	/* cmd = 0x97 (UNREG_VPI) */
+	ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */
 } MAILVARIANTS;
 
 /*
@@ -2973,6 +2994,34 @@ typedef struct {
 #endif
 } RCV_ELS_REQ64;
 
+/* IOCB Command template for RCV_SEQ64 */
+struct rcv_seq64 {
+	struct ulp_bde64 elsReq;
+	uint32_t hbq_1;
+	uint32_t parmRo;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint32_t rctl:8;
+	uint32_t type:8;
+	uint32_t dfctl:8;
+	uint32_t ls:1;
+	uint32_t fs:1;
+	uint32_t rsvd2:3;
+	uint32_t si:1;
+	uint32_t bc:1;
+	uint32_t rsvd3:1;
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
+	uint32_t rsvd3:1;
+	uint32_t bc:1;
+	uint32_t si:1;
+	uint32_t rsvd2:3;
+	uint32_t fs:1;
+	uint32_t ls:1;
+	uint32_t dfctl:8;
+	uint32_t type:8;
+	uint32_t rctl:8;
+#endif
+};
+
 /* IOCB Command template for all 64 bit FCP Initiator commands */
 typedef struct {
 	ULP_BDL bdl;
@@ -2987,6 +3036,21 @@ typedef struct {
 	uint32_t fcpt_Length;	/* transfer ready for IWRITE */
 } FCPT_FIELDS64;
 
+/* IOCB Command template for Async Status iocb commands */
+typedef struct {
+	uint32_t rsvd[4];
+	uint32_t param;
+#ifdef __BIG_ENDIAN_BITFIELD
+	uint16_t evt_code;		/* High order bits word 5 */
+	uint16_t sub_ctxt_tag;		/* Low  order bits word 5 */
+#else   /*  __LITTLE_ENDIAN_BITFIELD */
+	uint16_t sub_ctxt_tag;		/* High order bits word 5 */
+	uint16_t evt_code;		/* Low  order bits word 5 */
+#endif
+} ASYNCSTAT_FIELDS;
+#define ASYNC_TEMP_WARN		0x100
+#define ASYNC_TEMP_SAFE		0x101
+
 /* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7)
    or CMD_IOCB_RCV_SEQ64_CX (0xB5) */
 
@@ -3004,7 +3068,26 @@ struct rcv_sli3 {
 	struct ulp_bde64 bde2;
 };
 
+/* Structure used for a single HBQ entry */
+struct lpfc_hbq_entry {
+	struct ulp_bde64 bde;
+	uint32_t buffer_tag;
+};
 
+/* IOCB Command template for QUE_XRI64_CX (0xB3) command */
+typedef struct {
+	struct lpfc_hbq_entry   buff;
+	uint32_t                rsvd;
+	uint32_t		rsvd1;
+} QUE_XRI64_CX_FIELDS;
+
+struct que_xri64cx_ext_fields {
+	uint32_t	iotag64_low;
+	uint32_t	iotag64_high;
+	uint32_t	ebde_count;
+	uint32_t	rsvd;
+	struct lpfc_hbq_entry	buff[5];
+};
 
 typedef struct _IOCB {	/* IOCB structure */
 	union {
@@ -3028,6 +3111,9 @@ typedef struct _IOCB {	/* IOCB structure */
 		XMT_SEQ_FIELDS64 xseq64;	/* XMIT / BCAST cmd */
 		FCPI_FIELDS64 fcpi64;	/* FCP 64 bit Initiator template */
 		FCPT_FIELDS64 fcpt64;	/* FCP 64 bit target template */
+		ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */
+		QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */
+		struct rcv_seq64 rcvseq64;	/* RCV_SEQ64 and RCV_CONT64 */
 
 		uint32_t ulpWord[IOCB_WORD_SZ - 2];	/* generic 6 'words' */
 	} un;
@@ -3085,6 +3171,10 @@ typedef struct _IOCB {	/* IOCB structure */
 
 	union {
 		struct rcv_sli3 rcvsli3; /* words 8 - 15 */
+
+		/* words 8-31 used for que_xri_cx iocb */
+		struct que_xri64cx_ext_fields que_xri64cx_ext_words;
+
 		uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */
 	} unsli3;
 
@@ -3124,12 +3214,6 @@ typedef struct _IOCB {	/* IOCB structure */
 
 } IOCB_t;
 
-/* Structure used for a single HBQ entry */
-struct lpfc_hbq_entry {
-	struct ulp_bde64 bde;
-	uint32_t buffer_tag;
-};
-
 
 #define SLI1_SLIM_SIZE   (4 * 1024)
 
@@ -3172,6 +3256,8 @@ lpfc_is_LC_HBA(unsigned short device)
 	    (device == PCI_DEVICE_ID_BSMB) ||
 	    (device == PCI_DEVICE_ID_ZMID) ||
 	    (device == PCI_DEVICE_ID_ZSMB) ||
+	    (device == PCI_DEVICE_ID_SAT_MID) ||
+	    (device == PCI_DEVICE_ID_SAT_SMB) ||
 	    (device == PCI_DEVICE_ID_RFLY))
 		return 1;
 	else
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index ecebdfa00470..3205f7488d1c 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -212,6 +212,18 @@ out_free_mbox:
 	return 0;
 }
 
+/* Completion handler for config async event mailbox command. */
+static void
+lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
+{
+	if (pmboxq->mb.mbxStatus == MBX_SUCCESS)
+		phba->temp_sensor_support = 1;
+	else
+		phba->temp_sensor_support = 0;
+	mempool_free(pmboxq, phba->mbox_mem_pool);
+	return;
+}
+
 /************************************************************************/
 /*                                                                      */
 /*    lpfc_config_port_post                                             */
@@ -234,6 +246,15 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 	int i, j;
 	int rc;
 
+	spin_lock_irq(&phba->hbalock);
+	/*
+	 * If the Config port completed correctly the HBA is not
+	 * over heated any more.
+	 */
+	if (phba->over_temp_state == HBA_OVER_TEMP)
+		phba->over_temp_state = HBA_NORMAL_TEMP;
+	spin_unlock_irq(&phba->hbalock);
+
 	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!pmb) {
 		phba->link_state = LPFC_HBA_ERROR;
@@ -343,7 +364,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 
 	phba->link_state = LPFC_LINK_DOWN;
 
-	/* Only process IOCBs on ring 0 till hba_state is READY */
+	/* Only process IOCBs on ELS ring till hba_state is READY */
 	if (psli->ring[psli->extra_ring].cmdringaddr)
 		psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT;
 	if (psli->ring[psli->fcp_ring].cmdringaddr)
@@ -409,7 +430,21 @@ lpfc_config_port_post(struct lpfc_hba *phba)
 		return -EIO;
 	}
 	/* MBOX buffer will be freed in mbox compl */
+	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	lpfc_config_async(phba, pmb, LPFC_ELS_RING);
+	pmb->mbox_cmpl = lpfc_config_async_cmpl;
+	pmb->vport = phba->pport;
+	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
 
+	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_INIT,
+				"0456 Adapter failed to issue "
+				"ASYNCEVT_ENABLE mbox status x%x \n.",
+				rc);
+		mempool_free(pmb, phba->mbox_mem_pool);
+	}
 	return (0);
 }
 
@@ -449,6 +484,9 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
 	struct lpfc_dmabuf *mp, *next_mp;
+	struct lpfc_iocbq *iocb;
+	IOCB_t *cmd = NULL;
+	LIST_HEAD(completions);
 	int i;
 
 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
@@ -464,16 +502,42 @@ lpfc_hba_down_post(struct lpfc_hba *phba)
 		}
 	}
 
+	spin_lock_irq(&phba->hbalock);
 	for (i = 0; i < psli->num_rings; i++) {
 		pring = &psli->ring[i];
+
+		/* At this point in time the HBA is either reset or DOA. Either
+		 * way, nothing should be on txcmplq as it will NEVER complete.
+		 */
+		list_splice_init(&pring->txcmplq, &completions);
+		pring->txcmplq_cnt = 0;
+		spin_unlock_irq(&phba->hbalock);
+
+		while (!list_empty(&completions)) {
+			iocb = list_get_first(&completions, struct lpfc_iocbq,
+				list);
+			cmd = &iocb->iocb;
+			list_del_init(&iocb->list);
+
+			if (!iocb->iocb_cmpl)
+				lpfc_sli_release_iocbq(phba, iocb);
+			else {
+				cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+				cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+				(iocb->iocb_cmpl) (phba, iocb, iocb);
+			}
+		}
+
 		lpfc_sli_abort_iocb_ring(phba, pring);
+		spin_lock_irq(&phba->hbalock);
 	}
+	spin_unlock_irq(&phba->hbalock);
 
 	return 0;
 }
 
 /* HBA heart beat timeout handler */
-void
+static void
 lpfc_hb_timeout(unsigned long ptr)
 {
 	struct lpfc_hba *phba;
@@ -512,8 +576,10 @@ void
 lpfc_hb_timeout_handler(struct lpfc_hba *phba)
 {
 	LPFC_MBOXQ_t *pmboxq;
+	struct lpfc_dmabuf *buf_ptr;
 	int retval;
 	struct lpfc_sli *psli = &phba->sli;
+	LIST_HEAD(completions);
 
 	if ((phba->link_state == LPFC_HBA_ERROR) ||
 		(phba->pport->load_flag & FC_UNLOADING) ||
@@ -540,49 +606,88 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba)
 	}
 	spin_unlock_irq(&phba->pport->work_port_lock);
 
-	/* If there is no heart beat outstanding, issue a heartbeat command */
-	if (!phba->hb_outstanding) {
-		pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
-		if (!pmboxq) {
-			mod_timer(&phba->hb_tmofunc,
-				jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
-			return;
+	if (phba->elsbuf_cnt &&
+		(phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) {
+		spin_lock_irq(&phba->hbalock);
+		list_splice_init(&phba->elsbuf, &completions);
+		phba->elsbuf_cnt = 0;
+		phba->elsbuf_prev_cnt = 0;
+		spin_unlock_irq(&phba->hbalock);
+
+		while (!list_empty(&completions)) {
+			list_remove_head(&completions, buf_ptr,
+				struct lpfc_dmabuf, list);
+			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+			kfree(buf_ptr);
 		}
+	}
+	phba->elsbuf_prev_cnt = phba->elsbuf_cnt;
 
-		lpfc_heart_beat(phba, pmboxq);
-		pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
-		pmboxq->vport = phba->pport;
-		retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+	/* If there is no heart beat outstanding, issue a heartbeat command */
+	if (phba->cfg_enable_hba_heartbeat) {
+		if (!phba->hb_outstanding) {
+			pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
+			if (!pmboxq) {
+				mod_timer(&phba->hb_tmofunc,
+					  jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+				return;
+			}
 
-		if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
-			mempool_free(pmboxq, phba->mbox_mem_pool);
+			lpfc_heart_beat(phba, pmboxq);
+			pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
+			pmboxq->vport = phba->pport;
+			retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+
+			if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
+				mempool_free(pmboxq, phba->mbox_mem_pool);
+				mod_timer(&phba->hb_tmofunc,
+					  jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+				return;
+			}
 			mod_timer(&phba->hb_tmofunc,
-				jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+				  jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
+			phba->hb_outstanding = 1;
 			return;
+		} else {
+			/*
+			* If heart beat timeout called with hb_outstanding set
+			* we need to take the HBA offline.
+			*/
+			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+					"0459 Adapter heartbeat failure, "
+					"taking this port offline.\n");
+
+			spin_lock_irq(&phba->hbalock);
+			psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+			spin_unlock_irq(&phba->hbalock);
+
+			lpfc_offline_prep(phba);
+			lpfc_offline(phba);
+			lpfc_unblock_mgmt_io(phba);
+			phba->link_state = LPFC_HBA_ERROR;
+			lpfc_hba_down_post(phba);
 		}
-		mod_timer(&phba->hb_tmofunc,
-			jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
-		phba->hb_outstanding = 1;
-		return;
-	} else {
-		/*
-		 * If heart beat timeout called with hb_outstanding set we
-		 * need to take the HBA offline.
-		 */
-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"0459 Adapter heartbeat failure, taking "
-				"this port offline.\n");
+	}
+}
 
-		spin_lock_irq(&phba->hbalock);
-		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
-		spin_unlock_irq(&phba->hbalock);
+static void
+lpfc_offline_eratt(struct lpfc_hba *phba)
+{
+	struct lpfc_sli   *psli = &phba->sli;
 
-		lpfc_offline_prep(phba);
-		lpfc_offline(phba);
-		lpfc_unblock_mgmt_io(phba);
-		phba->link_state = LPFC_HBA_ERROR;
-		lpfc_hba_down_post(phba);
-	}
+	spin_lock_irq(&phba->hbalock);
+	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+	spin_unlock_irq(&phba->hbalock);
+	lpfc_offline_prep(phba);
+
+	lpfc_offline(phba);
+	lpfc_reset_barrier(phba);
+	lpfc_sli_brdreset(phba);
+	lpfc_hba_down_post(phba);
+	lpfc_sli_brdready(phba, HS_MBRDY);
+	lpfc_unblock_mgmt_io(phba);
+	phba->link_state = LPFC_HBA_ERROR;
+	return;
 }
 
 /************************************************************************/
@@ -601,6 +706,8 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 	struct lpfc_sli_ring  *pring;
 	struct lpfc_vport **vports;
 	uint32_t event_data;
+	unsigned long temperature;
+	struct temp_event temp_event_data;
 	struct Scsi_Host  *shost;
 	int i;
 
@@ -608,6 +715,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 	 * since we cannot communicate with the pci card anyway. */
 	if (pci_channel_offline(phba->pcidev))
 		return;
+	/* If resets are disabled then leave the HBA alone and return */
+	if (!phba->cfg_enable_hba_reset)
+		return;
 
 	if (phba->work_hs & HS_FFER6 ||
 	    phba->work_hs & HS_FFER5) {
@@ -620,14 +730,14 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 		vports = lpfc_create_vport_work_array(phba);
 		if (vports != NULL)
 			for(i = 0;
-			    i < LPFC_MAX_VPORTS && vports[i] != NULL;
+			    i <= phba->max_vpi && vports[i] != NULL;
 			    i++){
 				shost = lpfc_shost_from_vport(vports[i]);
 				spin_lock_irq(shost->host_lock);
 				vports[i]->fc_flag |= FC_ESTABLISH_LINK;
 				spin_unlock_irq(shost->host_lock);
 			}
-		lpfc_destroy_vport_work_array(vports);
+		lpfc_destroy_vport_work_array(phba, vports);
 		spin_lock_irq(&phba->hbalock);
 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
 		spin_unlock_irq(&phba->hbalock);
@@ -655,6 +765,31 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 			return;
 		}
 		lpfc_unblock_mgmt_io(phba);
+	} else if (phba->work_hs & HS_CRIT_TEMP) {
+		temperature = readl(phba->MBslimaddr + TEMPERATURE_OFFSET);
+		temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
+		temp_event_data.event_code = LPFC_CRIT_TEMP;
+		temp_event_data.data = (uint32_t)temperature;
+
+		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+				"0459 Adapter maximum temperature exceeded "
+				"(%ld), taking this port offline "
+				"Data: x%x x%x x%x\n",
+				temperature, phba->work_hs,
+				phba->work_status[0], phba->work_status[1]);
+
+		shost = lpfc_shost_from_vport(phba->pport);
+		fc_host_post_vendor_event(shost, fc_get_event_number(),
+					  sizeof(temp_event_data),
+					  (char *) &temp_event_data,
+					  SCSI_NL_VID_TYPE_PCI
+					  | PCI_VENDOR_ID_EMULEX);
+
+		spin_lock_irq(&phba->hbalock);
+		phba->over_temp_state = HBA_OVER_TEMP;
+		spin_unlock_irq(&phba->hbalock);
+		lpfc_offline_eratt(phba);
+
 	} else {
 		/* The if clause above forces this code path when the status
 		 * failure is a value other than FFER6.  Do not call the offline
@@ -672,14 +807,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba)
 				sizeof(event_data), (char *) &event_data,
 				SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
 
-		spin_lock_irq(&phba->hbalock);
-		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
-		spin_unlock_irq(&phba->hbalock);
-		lpfc_offline_prep(phba);
-		lpfc_offline(phba);
-		lpfc_unblock_mgmt_io(phba);
-		phba->link_state = LPFC_HBA_ERROR;
-		lpfc_hba_down_post(phba);
+		lpfc_offline_eratt(phba);
 	}
 }
 
@@ -699,21 +827,25 @@ lpfc_handle_latt(struct lpfc_hba *phba)
 	LPFC_MBOXQ_t *pmb;
 	volatile uint32_t control;
 	struct lpfc_dmabuf *mp;
-	int rc = -ENOMEM;
+	int rc = 0;
 
 	pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-	if (!pmb)
+	if (!pmb) {
+		rc = 1;
 		goto lpfc_handle_latt_err_exit;
+	}
 
 	mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
-	if (!mp)
+	if (!mp) {
+		rc = 2;
 		goto lpfc_handle_latt_free_pmb;
+	}
 
 	mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
-	if (!mp->virt)
+	if (!mp->virt) {
+		rc = 3;
 		goto lpfc_handle_latt_free_mp;
-
-	rc = -EIO;
+	}
 
 	/* Cleanup any outstanding ELS commands */
 	lpfc_els_flush_all_cmd(phba);
@@ -722,9 +854,11 @@ lpfc_handle_latt(struct lpfc_hba *phba)
 	lpfc_read_la(phba, pmb, mp);
 	pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
 	pmb->vport = vport;
-	rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
-	if (rc == MBX_NOT_FINISHED)
+	rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT);
+	if (rc == MBX_NOT_FINISHED) {
+		rc = 4;
 		goto lpfc_handle_latt_free_mbuf;
+	}
 
 	/* Clear Link Attention in HA REG */
 	spin_lock_irq(&phba->hbalock);
@@ -756,10 +890,8 @@ lpfc_handle_latt_err_exit:
 	lpfc_linkdown(phba);
 	phba->link_state = LPFC_HBA_ERROR;
 
-	/* The other case is an error from issue_mbox */
-	if (rc == -ENOMEM)
-		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
-			        "0300 READ_LA: no buffers\n");
+	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+		     "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc);
 
 	return;
 }
@@ -1088,9 +1220,8 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
 		/* Allocate buffer to post */
 		mp1 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
 		if (mp1)
-		    mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
-						&mp1->phys);
-		if (mp1 == 0 || mp1->virt == 0) {
+		    mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp1->phys);
+		if (!mp1 || !mp1->virt) {
 			kfree(mp1);
 			lpfc_sli_release_iocbq(phba, iocb);
 			pring->missbufcnt = cnt;
@@ -1104,7 +1235,7 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
 			if (mp2)
 				mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
 							    &mp2->phys);
-			if (mp2 == 0 || mp2->virt == 0) {
+			if (!mp2 || !mp2->virt) {
 				kfree(mp2);
 				lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
 				kfree(mp1);
@@ -1280,15 +1411,39 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
 	kfree(HashWorking);
 }
 
-static void
+void
 lpfc_cleanup(struct lpfc_vport *vport)
 {
+	struct lpfc_hba   *phba = vport->phba;
 	struct lpfc_nodelist *ndlp, *next_ndlp;
+	int i = 0;
 
-	/* clean up phba - lpfc specific */
-	lpfc_can_disctmo(vport);
-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
-		lpfc_nlp_put(ndlp);
+	if (phba->link_state > LPFC_LINK_DOWN)
+		lpfc_port_link_failure(vport);
+
+	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+		if (ndlp->nlp_type & NLP_FABRIC)
+			lpfc_disc_state_machine(vport, ndlp, NULL,
+					NLP_EVT_DEVICE_RECOVERY);
+		lpfc_disc_state_machine(vport, ndlp, NULL,
+					     NLP_EVT_DEVICE_RM);
+	}
+
+	/* At this point, ALL ndlp's should be gone
+	 * because of the previous NLP_EVT_DEVICE_RM.
+	 * Lets wait for this to happen, if needed.
+	 */
+	while (!list_empty(&vport->fc_nodes)) {
+
+		if (i++ > 3000) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				"0233 Nodelist not empty\n");
+			break;
+		}
+
+		/* Wait for any activity on ndlps to settle */
+		msleep(10);
+	}
 	return;
 }
 
@@ -1307,14 +1462,14 @@ lpfc_establish_link_tmo(unsigned long ptr)
 			phba->pport->fc_flag, phba->pport->port_state);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			struct Scsi_Host *shost;
 			shost = lpfc_shost_from_vport(vports[i]);
 			spin_lock_irqsave(shost->host_lock, iflag);
 			vports[i]->fc_flag &= ~FC_ESTABLISH_LINK;
 			spin_unlock_irqrestore(shost->host_lock, iflag);
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 }
 
 void
@@ -1339,6 +1494,16 @@ lpfc_stop_phba_timers(struct lpfc_hba *phba)
 	return;
 }
 
+static void
+lpfc_block_mgmt_io(struct lpfc_hba * phba)
+{
+	unsigned long iflag;
+
+	spin_lock_irqsave(&phba->hbalock, iflag);
+	phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
+	spin_unlock_irqrestore(&phba->hbalock, iflag);
+}
+
 int
 lpfc_online(struct lpfc_hba *phba)
 {
@@ -1369,7 +1534,7 @@ lpfc_online(struct lpfc_hba *phba)
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			struct Scsi_Host *shost;
 			shost = lpfc_shost_from_vport(vports[i]);
 			spin_lock_irq(shost->host_lock);
@@ -1378,23 +1543,13 @@ lpfc_online(struct lpfc_hba *phba)
 				vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
 			spin_unlock_irq(shost->host_lock);
 		}
-		lpfc_destroy_vport_work_array(vports);
+		lpfc_destroy_vport_work_array(phba, vports);
 
 	lpfc_unblock_mgmt_io(phba);
 	return 0;
 }
 
 void
-lpfc_block_mgmt_io(struct lpfc_hba * phba)
-{
-	unsigned long iflag;
-
-	spin_lock_irqsave(&phba->hbalock, iflag);
-	phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
-	spin_unlock_irqrestore(&phba->hbalock, iflag);
-}
-
-void
 lpfc_unblock_mgmt_io(struct lpfc_hba * phba)
 {
 	unsigned long iflag;
@@ -1409,6 +1564,8 @@ lpfc_offline_prep(struct lpfc_hba * phba)
 {
 	struct lpfc_vport *vport = phba->pport;
 	struct lpfc_nodelist  *ndlp, *next_ndlp;
+	struct lpfc_vport **vports;
+	int i;
 
 	if (vport->fc_flag & FC_OFFLINE_MODE)
 		return;
@@ -1417,10 +1574,34 @@ lpfc_offline_prep(struct lpfc_hba * phba)
 
 	lpfc_linkdown(phba);
 
-	/* Issue an unreg_login to all nodes */
-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
-		if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
-			lpfc_unreg_rpi(vport, ndlp);
+	/* Issue an unreg_login to all nodes on all vports */
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
+			struct Scsi_Host *shost;
+
+			if (vports[i]->load_flag & FC_UNLOADING)
+				continue;
+			shost =	lpfc_shost_from_vport(vports[i]);
+			list_for_each_entry_safe(ndlp, next_ndlp,
+						 &vports[i]->fc_nodes,
+						 nlp_listp) {
+				if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+					continue;
+				if (ndlp->nlp_type & NLP_FABRIC) {
+					lpfc_disc_state_machine(vports[i], ndlp,
+						NULL, NLP_EVT_DEVICE_RECOVERY);
+					lpfc_disc_state_machine(vports[i], ndlp,
+						NULL, NLP_EVT_DEVICE_RM);
+				}
+				spin_lock_irq(shost->host_lock);
+				ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+				spin_unlock_irq(shost->host_lock);
+				lpfc_unreg_rpi(vports[i], ndlp);
+			}
+		}
+	}
+	lpfc_destroy_vport_work_array(phba, vports);
 
 	lpfc_sli_flush_mbox_queue(phba);
 }
@@ -1439,9 +1620,9 @@ lpfc_offline(struct lpfc_hba *phba)
 	lpfc_stop_phba_timers(phba);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++)
 			lpfc_stop_vport_timers(vports[i]);
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
 			"0460 Bring Adapter offline\n");
 	/* Bring down the SLI Layer and cleanup.  The HBA is offline
@@ -1452,15 +1633,14 @@ lpfc_offline(struct lpfc_hba *phba)
 	spin_unlock_irq(&phba->hbalock);
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			shost = lpfc_shost_from_vport(vports[i]);
-			lpfc_cleanup(vports[i]);
 			spin_lock_irq(shost->host_lock);
 			vports[i]->work_port_events = 0;
 			vports[i]->fc_flag |= FC_OFFLINE_MODE;
 			spin_unlock_irq(shost->host_lock);
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 }
 
 /******************************************************************************
@@ -1674,6 +1854,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost)
 	fc_host_supported_speeds(shost) = 0;
 	if (phba->lmt & LMT_10Gb)
 		fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
+	if (phba->lmt & LMT_8Gb)
+		fc_host_supported_speeds(shost) |= FC_PORTSPEED_8GBIT;
 	if (phba->lmt & LMT_4Gb)
 		fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT;
 	if (phba->lmt & LMT_2Gb)
@@ -1707,13 +1889,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	struct Scsi_Host  *shost = NULL;
 	void *ptr;
 	unsigned long bar0map_len, bar2map_len;
-	int error = -ENODEV;
+	int error = -ENODEV, retval;
 	int  i, hbq_count;
 	uint16_t iotag;
+	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 
-	if (pci_enable_device(pdev))
+	if (pci_enable_device_bars(pdev, bars))
 		goto out;
-	if (pci_request_regions(pdev, LPFC_DRIVER_NAME))
+	if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME))
 		goto out_disable_device;
 
 	phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL);
@@ -1823,9 +2006,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	lpfc_sli_setup(phba);
 	lpfc_sli_queue_setup(phba);
 
-	error = lpfc_mem_alloc(phba);
-	if (error)
+	retval = lpfc_mem_alloc(phba);
+	if (retval) {
+		error = retval;
 		goto out_free_hbqslimp;
+	}
 
 	/* Initialize and populate the iocb list per host.  */
 	INIT_LIST_HEAD(&phba->lpfc_iocb_list);
@@ -1880,6 +2065,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	/* Initialize list of fabric iocbs */
 	INIT_LIST_HEAD(&phba->fabric_iocb_list);
 
+	/* Initialize list to save ELS buffers */
+	INIT_LIST_HEAD(&phba->elsbuf);
+
 	vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
 	if (!vport)
 		goto out_kthread_stop;
@@ -1891,8 +2079,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	pci_set_drvdata(pdev, shost);
 
 	if (phba->cfg_use_msi) {
-		error = pci_enable_msi(phba->pcidev);
-		if (!error)
+		retval = pci_enable_msi(phba->pcidev);
+		if (!retval)
 			phba->using_msi = 1;
 		else
 			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
@@ -1900,11 +2088,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 					"with IRQ\n");
 	}
 
-	error =	request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
+	retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
 			    LPFC_DRIVER_NAME, phba);
-	if (error) {
+	if (retval) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 			"0451 Enable interrupt handler failed\n");
+		error = retval;
 		goto out_disable_msi;
 	}
 
@@ -1914,11 +2103,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 	phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
 	phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
 
-	if (lpfc_alloc_sysfs_attr(vport))
+	if (lpfc_alloc_sysfs_attr(vport)) {
+		error = -ENOMEM;
 		goto out_free_irq;
+	}
 
-	if (lpfc_sli_hba_setup(phba))
+	if (lpfc_sli_hba_setup(phba)) {
+		error = -ENODEV;
 		goto out_remove_device;
+	}
 
 	/*
 	 * hba setup may have changed the hba_queue_depth so we need to adjust
@@ -1975,7 +2168,7 @@ out_idr_remove:
 out_free_phba:
 	kfree(phba);
 out_release_regions:
-	pci_release_regions(pdev);
+	pci_release_selected_regions(pdev, bars);
 out_disable_device:
 	pci_disable_device(pdev);
 out:
@@ -1991,6 +2184,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 	struct Scsi_Host  *shost = pci_get_drvdata(pdev);
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
+	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
+
 	spin_lock_irq(&phba->hbalock);
 	vport->load_flag |= FC_UNLOADING;
 	spin_unlock_irq(&phba->hbalock);
@@ -1998,8 +2193,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 	kfree(vport->vname);
 	lpfc_free_sysfs_attr(vport);
 
+	kthread_stop(phba->worker_thread);
+
 	fc_remove_host(shost);
 	scsi_remove_host(shost);
+	lpfc_cleanup(vport);
+
 	/*
 	 * Bring down the SLI Layer. This step disable all interrupts,
 	 * clears the rings, discards all mailbox commands, and resets
@@ -2014,9 +2213,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 	spin_unlock_irq(&phba->hbalock);
 
 	lpfc_debugfs_terminate(vport);
-	lpfc_cleanup(vport);
-
-	kthread_stop(phba->worker_thread);
 
 	/* Release the irq reservation */
 	free_irq(phba->pcidev->irq, phba);
@@ -2048,7 +2244,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
 
 	kfree(phba);
 
-	pci_release_regions(pdev);
+	pci_release_selected_regions(pdev, bars);
 	pci_disable_device(pdev);
 }
 
@@ -2239,12 +2435,22 @@ lpfc_init(void)
 	printk(LPFC_MODULE_DESC "\n");
 	printk(LPFC_COPYRIGHT "\n");
 
+	if (lpfc_enable_npiv) {
+		lpfc_transport_functions.vport_create = lpfc_vport_create;
+		lpfc_transport_functions.vport_delete = lpfc_vport_delete;
+	}
 	lpfc_transport_template =
 				fc_attach_transport(&lpfc_transport_functions);
-	lpfc_vport_transport_template =
-			fc_attach_transport(&lpfc_vport_transport_functions);
-	if (!lpfc_transport_template || !lpfc_vport_transport_template)
+	if (lpfc_transport_template == NULL)
 		return -ENOMEM;
+	if (lpfc_enable_npiv) {
+		lpfc_vport_transport_template =
+			fc_attach_transport(&lpfc_vport_transport_functions);
+		if (lpfc_vport_transport_template == NULL) {
+			fc_release_transport(lpfc_transport_template);
+			return -ENOMEM;
+		}
+	}
 	error = pci_register_driver(&lpfc_driver);
 	if (error) {
 		fc_release_transport(lpfc_transport_template);
@@ -2259,7 +2465,8 @@ lpfc_exit(void)
 {
 	pci_unregister_driver(&lpfc_driver);
 	fc_release_transport(lpfc_transport_template);
-	fc_release_transport(lpfc_vport_transport_template);
+	if (lpfc_enable_npiv)
+		fc_release_transport(lpfc_vport_transport_template);
 }
 
 module_init(lpfc_init);
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
index 626e4d878725..c5841d7565f7 100644
--- a/drivers/scsi/lpfc/lpfc_logmsg.h
+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
@@ -26,6 +26,7 @@
 #define LOG_IP                        0x20	/* IP traffic history */
 #define LOG_FCP                       0x40	/* FCP traffic history */
 #define LOG_NODE                      0x80	/* Node table events */
+#define LOG_TEMP                      0x100	/* Temperature sensor events */
 #define LOG_MISC                      0x400	/* Miscellaneous events */
 #define LOG_SLI                       0x800	/* SLI events */
 #define LOG_FCP_ERROR                 0x1000	/* log errors, not underruns */
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index a592733664e9..dfc63f6ccd7b 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -82,6 +82,24 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
 }
 
 /**********************************************/
+/*  lpfc_config_async  Issue a                */
+/*  MBX_ASYNC_EVT_ENABLE mailbox command      */
+/**********************************************/
+void
+lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
+		uint32_t ring)
+{
+	MAILBOX_t *mb;
+
+	mb = &pmb->mb;
+	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+	mb->mbxCommand = MBX_ASYNCEVT_ENABLE;
+	mb->un.varCfgAsyncEvent.ring = ring;
+	mb->mbxOwner = OWN_HOST;
+	return;
+}
+
+/**********************************************/
 /*  lpfc_heart_beat  Issue a HEART_BEAT       */
 /*                mailbox command             */
 /**********************************************/
@@ -270,8 +288,10 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
 
 	/* Get a buffer to hold the HBAs Service Parameters */
 
-	if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
-	    ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
+	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+	if (mp)
+		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+	if (!mp || !mp->virt) {
 		kfree(mp);
 		mb->mbxCommand = MBX_READ_SPARM64;
 		/* READ_SPARAM: no buffers */
@@ -369,8 +389,10 @@ lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
 	mb->mbxOwner = OWN_HOST;
 
 	/* Get a buffer to hold NPorts Service Parameters */
-	if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == NULL) ||
-	    ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) {
+	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+	if (mp)
+		mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+	if (!mp || !mp->virt) {
 		kfree(mp);
 		mb->mbxCommand = MBX_REG_LOGIN64;
 		/* REG_LOGIN: no buffers */
@@ -874,7 +896,7 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
 	case MBX_DOWN_LOAD:	/* 0x1C */
 	case MBX_DEL_LD_ENTRY:	/* 0x1D */
 	case MBX_LOAD_AREA:	/* 0x81 */
-	case MBX_FLASH_WR_ULA:  /* 0x98 */
+	case MBX_WRITE_WWN:     /* 0x98 */
 	case MBX_LOAD_EXP_ROM:	/* 0x9C */
 		return LPFC_MBOX_TMO_FLASH_CMD;
 	}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 43c3b8a0d76a..6dc5ab8d6716 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -98,6 +98,7 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
 
  fail_free_hbq_pool:
 	lpfc_sli_hbqbuf_free_all(phba);
+	pci_pool_destroy(phba->lpfc_hbq_pool);
  fail_free_nlp_mem_pool:
 	mempool_destroy(phba->nlp_mem_pool);
 	phba->nlp_mem_pool = NULL;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 880af0cd463d..4a0e3406e37a 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -287,6 +287,24 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
 	lp = (uint32_t *) pcmd->virt;
 	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+	if (wwn_to_u64(sp->portName.u.wwn) == 0) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0140 PLOGI Reject: invalid nname\n");
+		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+		stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME;
+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+			NULL);
+		return 0;
+	}
+	if (wwn_to_u64(sp->nodeName.u.wwn) == 0) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0141 PLOGI Reject: invalid pname\n");
+		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+		stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME;
+		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+			NULL);
+		return 0;
+	}
 	if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) {
 		/* Reject this request because invalid parameters */
 		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
@@ -343,8 +361,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		lpfc_config_link(phba, mbox);
 		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
 		mbox->vport = vport;
-		rc = lpfc_sli_issue_mbox
-			(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
 		if (rc == MBX_NOT_FINISHED) {
 			mempool_free(mbox, phba->mbox_mem_pool);
 			goto out;
@@ -407,6 +424,61 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			ndlp, mbox);
 		return 1;
 	}
+
+	/* If the remote NPort logs into us, before we can initiate
+	 * discovery to them, cleanup the NPort from discovery accordingly.
+	 */
+	if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
+		spin_lock_irq(shost->host_lock);
+		ndlp->nlp_flag &= ~NLP_DELAY_TMO;
+		spin_unlock_irq(shost->host_lock);
+		del_timer_sync(&ndlp->nlp_delayfunc);
+		ndlp->nlp_last_elscmd = 0;
+
+		if (!list_empty(&ndlp->els_retry_evt.evt_listp))
+			list_del_init(&ndlp->els_retry_evt.evt_listp);
+
+		if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+			spin_lock_irq(shost->host_lock);
+			ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
+			spin_unlock_irq(shost->host_lock);
+
+			if ((ndlp->nlp_flag & NLP_ADISC_SND) &&
+				(vport->num_disc_nodes)) {
+				/* Check to see if there are more
+				 * ADISCs to be sent
+				 */
+				lpfc_more_adisc(vport);
+
+				if ((vport->num_disc_nodes == 0) &&
+					(vport->fc_npr_cnt))
+					lpfc_els_disc_plogi(vport);
+
+				if (vport->num_disc_nodes == 0) {
+					spin_lock_irq(shost->host_lock);
+					vport->fc_flag &= ~FC_NDISC_ACTIVE;
+					spin_unlock_irq(shost->host_lock);
+					lpfc_can_disctmo(vport);
+					lpfc_end_rscn(vport);
+				}
+			}
+			else if (vport->num_disc_nodes) {
+				/* Check to see if there are more
+				 * PLOGIs to be sent
+				 */
+				lpfc_more_plogi(vport);
+
+				if (vport->num_disc_nodes == 0) {
+					spin_lock_irq(shost->host_lock);
+					vport->fc_flag &= ~FC_NDISC_ACTIVE;
+					spin_unlock_irq(shost->host_lock);
+					lpfc_can_disctmo(vport);
+					lpfc_end_rscn(vport);
+				}
+			}
+		}
+	}
+
 	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
 	return 1;
 
@@ -501,12 +573,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		spin_unlock_irq(shost->host_lock);
 
 		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
-		ndlp->nlp_prev_state = ndlp->nlp_state;
-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
-	} else {
-		ndlp->nlp_prev_state = ndlp->nlp_state;
-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
 	}
+	ndlp->nlp_prev_state = ndlp->nlp_state;
+	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag &= ~NLP_NPR_ADISC;
@@ -594,6 +663,25 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	return ndlp->nlp_state;
 }
 
+static uint32_t
+lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+		  void *arg, uint32_t evt)
+{
+	/* This transition is only legal if we previously
+	 * rcv'ed a PLOGI. Since we don't want 2 discovery threads
+	 * working on the same NPortID, do nothing for this thread
+	 * to stop it.
+	 */
+	if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+			 "0253 Illegal State Transition: node x%x "
+			 "event x%x, state x%x Data: x%x x%x\n",
+			 ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
+			 ndlp->nlp_flag);
+	}
+	return ndlp->nlp_state;
+}
+
 /* Start of Discovery State Machine routines */
 
 static uint32_t
@@ -605,11 +693,8 @@ lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	cmdiocb = (struct lpfc_iocbq *) arg;
 
 	if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
-		ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
 		return ndlp->nlp_state;
 	}
-	lpfc_drop_node(vport, ndlp);
 	return NLP_STE_FREED_NODE;
 }
 
@@ -618,7 +703,6 @@ lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			 void *arg, uint32_t evt)
 {
 	lpfc_issue_els_logo(vport, ndlp, 0);
-	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
 	return ndlp->nlp_state;
 }
 
@@ -633,7 +717,6 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	ndlp->nlp_flag |= NLP_LOGO_ACC;
 	spin_unlock_irq(shost->host_lock);
 	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
-	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
 
 	return ndlp->nlp_state;
 }
@@ -642,7 +725,6 @@ static uint32_t
 lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			   void *arg, uint32_t evt)
 {
-	lpfc_drop_node(vport, ndlp);
 	return NLP_STE_FREED_NODE;
 }
 
@@ -650,7 +732,6 @@ static uint32_t
 lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			   void *arg, uint32_t evt)
 {
-	lpfc_drop_node(vport, ndlp);
 	return NLP_STE_FREED_NODE;
 }
 
@@ -752,6 +833,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
 			    uint32_t evt)
 {
 	struct lpfc_hba    *phba = vport->phba;
+	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_iocbq  *cmdiocb, *rspiocb;
 	struct lpfc_dmabuf *pcmd, *prsp, *mp;
 	uint32_t *lp;
@@ -778,6 +860,12 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
 
 	lp = (uint32_t *) prsp->virt;
 	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+	if (wwn_to_u64(sp->portName.u.wwn) == 0 ||
+	    wwn_to_u64(sp->nodeName.u.wwn) == 0) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0142 PLOGI RSP: Invalid WWN.\n");
+		goto out;
+	}
 	if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
 		goto out;
 	/* PLOGI chkparm OK */
@@ -828,13 +916,15 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
 		}
 		mbox->context2 = lpfc_nlp_get(ndlp);
 		mbox->vport = vport;
-		if (lpfc_sli_issue_mbox(phba, mbox,
-					(MBX_NOWAIT | MBX_STOP_IOCB))
+		if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
 		    != MBX_NOT_FINISHED) {
 			lpfc_nlp_set_state(vport, ndlp,
 					   NLP_STE_REG_LOGIN_ISSUE);
 			return ndlp->nlp_state;
 		}
+		/* decrement node reference count to the failed mbox
+		 * command
+		 */
 		lpfc_nlp_put(ndlp);
 		mp = (struct lpfc_dmabuf *) mbox->context1;
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -864,13 +954,27 @@ out:
 				 "0261 Cannot Register NameServer login\n");
 	}
 
-	/* Free this node since the driver cannot login or has the wrong
-	   sparm */
-	lpfc_drop_node(vport, ndlp);
+	spin_lock_irq(shost->host_lock);
+	ndlp->nlp_flag |= NLP_DEFER_RM;
+	spin_unlock_irq(shost->host_lock);
 	return NLP_STE_FREED_NODE;
 }
 
 static uint32_t
+lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+			   void *arg, uint32_t evt)
+{
+	return ndlp->nlp_state;
+}
+
+static uint32_t
+lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
+	struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
+{
+	return ndlp->nlp_state;
+}
+
+static uint32_t
 lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			   void *arg, uint32_t evt)
 {
@@ -1137,7 +1241,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
 		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
 			mp = (struct lpfc_dmabuf *) (mb->context1);
 			if (mp) {
-				lpfc_mbuf_free(phba, mp->virt, mp->phys);
+				__lpfc_mbuf_free(phba, mp->virt, mp->phys);
 				kfree(mp);
 			}
 			lpfc_nlp_put(ndlp);
@@ -1197,8 +1301,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
 		 * retry discovery.
 		 */
 		if (mb->mbxStatus == MBXERR_RPI_FULL) {
-			ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
-			lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+			ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
+			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 			return ndlp->nlp_state;
 		}
 
@@ -1378,7 +1482,7 @@ out:
 		lpfc_issue_els_logo(vport, ndlp, 0);
 
 		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
-		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
 		return ndlp->nlp_state;
 	}
 
@@ -1753,7 +1857,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
 	irsp = &rspiocb->iocb;
 	if (irsp->ulpStatus) {
-		lpfc_drop_node(vport, ndlp);
+		ndlp->nlp_flag |= NLP_DEFER_RM;
 		return NLP_STE_FREED_NODE;
 	}
 	return ndlp->nlp_state;
@@ -1942,9 +2046,9 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
 	lpfc_rcv_els_plogi_issue,	/* RCV_PRLO        */
 	lpfc_cmpl_plogi_plogi_issue,	/* CMPL_PLOGI      */
 	lpfc_disc_illegal,		/* CMPL_PRLI       */
-	lpfc_disc_illegal,		/* CMPL_LOGO       */
+	lpfc_cmpl_logo_plogi_issue,	/* CMPL_LOGO       */
 	lpfc_disc_illegal,		/* CMPL_ADISC      */
-	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
+	lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN  */
 	lpfc_device_rm_plogi_issue,	/* DEVICE_RM       */
 	lpfc_device_recov_plogi_issue,	/* DEVICE_RECOVERY */
 
@@ -1968,7 +2072,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
 	lpfc_rcv_padisc_reglogin_issue,	/* RCV_ADISC       */
 	lpfc_rcv_padisc_reglogin_issue,	/* RCV_PDISC       */
 	lpfc_rcv_prlo_reglogin_issue,	/* RCV_PRLO        */
-	lpfc_disc_illegal,		/* CMPL_PLOGI      */
+	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
 	lpfc_disc_illegal,		/* CMPL_PRLI       */
 	lpfc_disc_illegal,		/* CMPL_LOGO       */
 	lpfc_disc_illegal,		/* CMPL_ADISC      */
@@ -1982,7 +2086,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
 	lpfc_rcv_padisc_prli_issue,	/* RCV_ADISC       */
 	lpfc_rcv_padisc_prli_issue,	/* RCV_PDISC       */
 	lpfc_rcv_prlo_prli_issue,	/* RCV_PRLO        */
-	lpfc_disc_illegal,		/* CMPL_PLOGI      */
+	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
 	lpfc_cmpl_prli_prli_issue,	/* CMPL_PRLI       */
 	lpfc_disc_illegal,		/* CMPL_LOGO       */
 	lpfc_disc_illegal,		/* CMPL_ADISC      */
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 4e46045dea6d..fc5c3a42b05a 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -130,7 +130,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			shost = lpfc_shost_from_vport(vports[i]);
 			shost_for_each_device(sdev, shost) {
 				new_queue_depth =
@@ -151,7 +151,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
 							new_queue_depth);
 			}
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	atomic_set(&phba->num_rsrc_err, 0);
 	atomic_set(&phba->num_cmd_success, 0);
 }
@@ -166,7 +166,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
 
 	vports = lpfc_create_vport_work_array(phba);
 	if (vports != NULL)
-		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+		for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) {
 			shost = lpfc_shost_from_vport(vports[i]);
 			shost_for_each_device(sdev, shost) {
 				if (sdev->ordered_tags)
@@ -179,7 +179,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
 							sdev->queue_depth+1);
 			}
 		}
-	lpfc_destroy_vport_work_array(vports);
+	lpfc_destroy_vport_work_array(phba, vports);
 	atomic_set(&phba->num_rsrc_err, 0);
 	atomic_set(&phba->num_cmd_success, 0);
 }
@@ -380,7 +380,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
 		(num_bde * sizeof (struct ulp_bde64));
 	iocb_cmd->ulpBdeCount = 1;
 	iocb_cmd->ulpLe = 1;
-	fcp_cmnd->fcpDl = be32_to_cpu(scsi_bufflen(scsi_cmnd));
+	fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
 	return 0;
 }
 
@@ -542,6 +542,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 	int result;
 	struct scsi_device *sdev, *tmp_sdev;
 	int depth = 0;
+	unsigned long flags;
 
 	lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
 	lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
@@ -608,6 +609,15 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 	cmd->scsi_done(cmd);
 
 	if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
+		/*
+		 * If there is a thread waiting for command completion
+		 * wake up the thread.
+		 */
+		spin_lock_irqsave(sdev->host->host_lock, flags);
+		lpfc_cmd->pCmd = NULL;
+		if (lpfc_cmd->waitq)
+			wake_up(lpfc_cmd->waitq);
+		spin_unlock_irqrestore(sdev->host->host_lock, flags);
 		lpfc_release_scsi_buf(phba, lpfc_cmd);
 		return;
 	}
@@ -669,6 +679,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
 		}
 	}
 
+	/*
+	 * If there is a thread waiting for command completion
+	 * wake up the thread.
+	 */
+	spin_lock_irqsave(sdev->host->host_lock, flags);
+	lpfc_cmd->pCmd = NULL;
+	if (lpfc_cmd->waitq)
+		wake_up(lpfc_cmd->waitq);
+	spin_unlock_irqrestore(sdev->host->host_lock, flags);
+
 	lpfc_release_scsi_buf(phba, lpfc_cmd);
 }
 
@@ -743,6 +763,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 	piocbq->iocb.ulpContext = pnode->nlp_rpi;
 	if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE)
 		piocbq->iocb.ulpFCP2Rcvy = 1;
+	else
+		piocbq->iocb.ulpFCP2Rcvy = 0;
 
 	piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f);
 	piocbq->context1  = lpfc_cmd;
@@ -1018,8 +1040,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 	struct lpfc_iocbq *abtsiocb;
 	struct lpfc_scsi_buf *lpfc_cmd;
 	IOCB_t *cmd, *icmd;
-	unsigned int loop_count = 0;
 	int ret = SUCCESS;
+	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
 
 	lpfc_block_error_handler(cmnd);
 	lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
@@ -1074,17 +1096,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
 	if (phba->cfg_poll & DISABLE_FCP_RING_INT)
 		lpfc_sli_poll_fcp_ring (phba);
 
+	lpfc_cmd->waitq = &waitq;
 	/* Wait for abort to complete */
-	while (lpfc_cmd->pCmd == cmnd)
-	{
-		if (phba->cfg_poll & DISABLE_FCP_RING_INT)
-			lpfc_sli_poll_fcp_ring (phba);
+	wait_event_timeout(waitq,
+			  (lpfc_cmd->pCmd != cmnd),
+			   (2*vport->cfg_devloss_tmo*HZ));
 
-		schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ);
-		if (++loop_count
-		    > (2 * vport->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
-			break;
-	}
+	spin_lock_irq(shost->host_lock);
+	lpfc_cmd->waitq = NULL;
+	spin_unlock_irq(shost->host_lock);
 
 	if (lpfc_cmd->pCmd == cmnd) {
 		ret = FAILED;
@@ -1438,8 +1458,7 @@ struct scsi_host_template lpfc_template = {
 	.slave_destroy		= lpfc_slave_destroy,
 	.scan_finished		= lpfc_scan_finished,
 	.this_id		= -1,
-	.sg_tablesize		= LPFC_SG_SEG_CNT,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
+	.sg_tablesize		= LPFC_DEFAULT_SG_SEG_CNT,
 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.shost_attrs		= lpfc_hba_attrs,
@@ -1459,10 +1478,9 @@ struct scsi_host_template lpfc_vport_template = {
 	.slave_destroy		= lpfc_slave_destroy,
 	.scan_finished		= lpfc_scan_finished,
 	.this_id		= -1,
-	.sg_tablesize		= LPFC_SG_SEG_CNT,
+	.sg_tablesize		= LPFC_DEFAULT_SG_SEG_CNT,
 	.cmd_per_lun		= LPFC_CMD_PER_LUN,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 	.shost_attrs		= lpfc_vport_attrs,
 	.max_sectors		= 0xFFFF,
 };
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index 31787bb6d53e..daba92374985 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -138,6 +138,7 @@ struct lpfc_scsi_buf {
 	 * Iotag is in here
 	 */
 	struct lpfc_iocbq cur_iocbq;
+	wait_queue_head_t *waitq;
 };
 
 #define LPFC_SCSI_DMA_EXT_SIZE 264
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index ce348c5c706c..fdd01e384e36 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -106,7 +106,7 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba)
 	return iocbq;
 }
 
-void
+static void
 __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
 {
 	size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
@@ -199,6 +199,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
 	case CMD_RCV_ELS_REQ_CX:
 	case CMD_RCV_SEQUENCE64_CX:
 	case CMD_RCV_ELS_REQ64_CX:
+	case CMD_ASYNC_STATUS:
 	case CMD_IOCB_RCV_SEQ64_CX:
 	case CMD_IOCB_RCV_ELS64_CX:
 	case CMD_IOCB_RCV_CONT64_CX:
@@ -473,8 +474,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 	if (pring->txq_cnt &&
 	    lpfc_is_link_up(phba) &&
 	    (pring->ringno != phba->sli.fcp_ring ||
-	     phba->sli.sli_flag & LPFC_PROCESS_LA) &&
-	    !(pring->flag & LPFC_STOP_IOCB_MBX)) {
+	     phba->sli.sli_flag & LPFC_PROCESS_LA)) {
 
 		while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
 		       (nextiocb = lpfc_sli_ringtx_get(phba, pring)))
@@ -489,32 +489,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
 	return;
 }
 
-/* lpfc_sli_turn_on_ring is only called by lpfc_sli_handle_mb_event below */
-static void
-lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno)
-{
-	struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
-		&phba->slim2p->mbx.us.s3_pgp.port[ringno] :
-		&phba->slim2p->mbx.us.s2.port[ringno];
-	unsigned long iflags;
-
-	/* If the ring is active, flag it */
-	spin_lock_irqsave(&phba->hbalock, iflags);
-	if (phba->sli.ring[ringno].cmdringaddr) {
-		if (phba->sli.ring[ringno].flag & LPFC_STOP_IOCB_MBX) {
-			phba->sli.ring[ringno].flag &= ~LPFC_STOP_IOCB_MBX;
-			/*
-			 * Force update of the local copy of cmdGetInx
-			 */
-			phba->sli.ring[ringno].local_getidx
-				= le32_to_cpu(pgp->cmdGetInx);
-			lpfc_sli_resume_iocb(phba, &phba->sli.ring[ringno]);
-		}
-	}
-	spin_unlock_irqrestore(&phba->hbalock, iflags);
-}
-
-struct lpfc_hbq_entry *
+static struct lpfc_hbq_entry *
 lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
 {
 	struct hbq_s *hbqp = &phba->hbqs[hbqno];
@@ -565,6 +540,7 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
 			list_del(&hbq_buf->dbuf.list);
 			(phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf);
 		}
+		phba->hbqs[i].buffer_count = 0;
 	}
 }
 
@@ -633,8 +609,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
 		return 0;
 	}
 
-	start = lpfc_hbq_defs[hbqno]->buffer_count;
-	end = count + lpfc_hbq_defs[hbqno]->buffer_count;
+	start = phba->hbqs[hbqno].buffer_count;
+	end = count + start;
 	if (end > lpfc_hbq_defs[hbqno]->entry_count) {
 		end = lpfc_hbq_defs[hbqno]->entry_count;
 	}
@@ -646,7 +622,7 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
 			return 1;
 		hbq_buffer->tag = (i | (hbqno << 16));
 		if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
-			lpfc_hbq_defs[hbqno]->buffer_count++;
+			phba->hbqs[hbqno].buffer_count++;
 		else
 			(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
 	}
@@ -660,14 +636,14 @@ lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno)
 					 lpfc_hbq_defs[qno]->add_count));
 }
 
-int
+static int
 lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno)
 {
 	return(lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
 					 lpfc_hbq_defs[qno]->init_count));
 }
 
-struct hbq_dmabuf *
+static struct hbq_dmabuf *
 lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
 {
 	struct lpfc_dmabuf *d_buf;
@@ -686,7 +662,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
 	}
 	lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
 			"1803 Bad hbq tag. Data: x%x x%x\n",
-			tag, lpfc_hbq_defs[tag >> 16]->buffer_count);
+			tag, phba->hbqs[tag >> 16].buffer_count);
 	return NULL;
 }
 
@@ -712,6 +688,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
 	case MBX_LOAD_SM:
 	case MBX_READ_NV:
 	case MBX_WRITE_NV:
+	case MBX_WRITE_VPARMS:
 	case MBX_RUN_BIU_DIAG:
 	case MBX_INIT_LINK:
 	case MBX_DOWN_LINK:
@@ -739,7 +716,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
 	case MBX_DEL_LD_ENTRY:
 	case MBX_RUN_PROGRAM:
 	case MBX_SET_MASK:
-	case MBX_SET_SLIM:
+	case MBX_SET_VARIABLE:
 	case MBX_UNREG_D_ID:
 	case MBX_KILL_BOARD:
 	case MBX_CONFIG_FARP:
@@ -751,9 +728,10 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
 	case MBX_READ_RPI64:
 	case MBX_REG_LOGIN64:
 	case MBX_READ_LA64:
-	case MBX_FLASH_WR_ULA:
+	case MBX_WRITE_WWN:
 	case MBX_SET_DEBUG:
 	case MBX_LOAD_EXP_ROM:
+	case MBX_ASYNCEVT_ENABLE:
 	case MBX_REG_VPI:
 	case MBX_UNREG_VPI:
 	case MBX_HEARTBEAT:
@@ -953,6 +931,17 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
 	return &new_hbq_entry->dbuf;
 }
 
+static struct lpfc_dmabuf *
+lpfc_sli_get_buff(struct lpfc_hba *phba,
+			struct lpfc_sli_ring *pring,
+			uint32_t tag)
+{
+	if (tag & QUE_BUFTAG_BIT)
+		return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
+	else
+		return lpfc_sli_replace_hbqbuff(phba, tag);
+}
+
 static int
 lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 			    struct lpfc_iocbq *saveq)
@@ -961,19 +950,112 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	WORD5            * w5p;
 	uint32_t           Rctl, Type;
 	uint32_t           match, i;
+	struct lpfc_iocbq *iocbq;
 
 	match = 0;
 	irsp = &(saveq->iocb);
-	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX)
-	    || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)
-	    || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)
-	    || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) {
+
+	if (irsp->ulpStatus == IOSTAT_NEED_BUFFER)
+		return 1;
+	if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
+		if (pring->lpfc_sli_rcv_async_status)
+			pring->lpfc_sli_rcv_async_status(phba, pring, saveq);
+		else
+			lpfc_printf_log(phba,
+					KERN_WARNING,
+					LOG_SLI,
+					"0316 Ring %d handler: unexpected "
+					"ASYNC_STATUS iocb received evt_code "
+					"0x%x\n",
+					pring->ringno,
+					irsp->un.asyncstat.evt_code);
+		return 1;
+	}
+
+	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+		if (irsp->ulpBdeCount != 0) {
+			saveq->context2 = lpfc_sli_get_buff(phba, pring,
+						irsp->un.ulpWord[3]);
+			if (!saveq->context2)
+				lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_SLI,
+					"0341 Ring %d Cannot find buffer for "
+					"an unsolicited iocb. tag 0x%x\n",
+					pring->ringno,
+					irsp->un.ulpWord[3]);
+		}
+		if (irsp->ulpBdeCount == 2) {
+			saveq->context3 = lpfc_sli_get_buff(phba, pring,
+						irsp->unsli3.sli3Words[7]);
+			if (!saveq->context3)
+				lpfc_printf_log(phba,
+					KERN_ERR,
+					LOG_SLI,
+					"0342 Ring %d Cannot find buffer for an"
+					" unsolicited iocb. tag 0x%x\n",
+					pring->ringno,
+					irsp->unsli3.sli3Words[7]);
+		}
+		list_for_each_entry(iocbq, &saveq->list, list) {
+			irsp = &(iocbq->iocb);
+			if (irsp->ulpBdeCount != 0) {
+				iocbq->context2 = lpfc_sli_get_buff(phba, pring,
+							irsp->un.ulpWord[3]);
+				if (!iocbq->context2)
+					lpfc_printf_log(phba,
+						KERN_ERR,
+						LOG_SLI,
+						"0343 Ring %d Cannot find "
+						"buffer for an unsolicited iocb"
+						". tag 0x%x\n", pring->ringno,
+						irsp->un.ulpWord[3]);
+			}
+			if (irsp->ulpBdeCount == 2) {
+				iocbq->context3 = lpfc_sli_get_buff(phba, pring,
+						irsp->unsli3.sli3Words[7]);
+				if (!iocbq->context3)
+					lpfc_printf_log(phba,
+						KERN_ERR,
+						LOG_SLI,
+						"0344 Ring %d Cannot find "
+						"buffer for an unsolicited "
+						"iocb. tag 0x%x\n",
+						pring->ringno,
+						irsp->unsli3.sli3Words[7]);
+			}
+		}
+	}
+	if (irsp->ulpBdeCount != 0 &&
+	    (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX ||
+	     irsp->ulpStatus == IOSTAT_INTERMED_RSP)) {
+		int found = 0;
+
+		/* search continue save q for same XRI */
+		list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) {
+			if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) {
+				list_add_tail(&saveq->list, &iocbq->list);
+				found = 1;
+				break;
+			}
+		}
+		if (!found)
+			list_add_tail(&saveq->clist,
+				      &pring->iocb_continue_saveq);
+		if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) {
+			list_del_init(&iocbq->clist);
+			saveq = iocbq;
+			irsp = &(saveq->iocb);
+		} else
+			return 0;
+	}
+	if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) ||
+	    (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) ||
+	    (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) {
 		Rctl = FC_ELS_REQ;
 		Type = FC_ELS_DATA;
 	} else {
-		w5p =
-		    (WORD5 *) & (saveq->iocb.un.
-				 ulpWord[5]);
+		w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]);
 		Rctl = w5p->hcsw.Rctl;
 		Type = w5p->hcsw.Type;
 
@@ -988,15 +1070,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		}
 	}
 
-	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
-		if (irsp->ulpBdeCount != 0)
-			saveq->context2 = lpfc_sli_replace_hbqbuff(phba,
-						irsp->un.ulpWord[3]);
-		if (irsp->ulpBdeCount == 2)
-			saveq->context3 = lpfc_sli_replace_hbqbuff(phba,
-						irsp->unsli3.sli3Words[7]);
-	}
-
 	/* unSolicited Responses */
 	if (pring->prt[0].profile) {
 		if (pring->prt[0].lpfc_sli_rcv_unsol_event)
@@ -1006,12 +1079,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	} else {
 		/* We must search, based on rctl / type
 		   for the right routine */
-		for (i = 0; i < pring->num_mask;
-		     i++) {
-			if ((pring->prt[i].rctl ==
-			     Rctl)
-			    && (pring->prt[i].
-				type == Type)) {
+		for (i = 0; i < pring->num_mask; i++) {
+			if ((pring->prt[i].rctl == Rctl)
+			    && (pring->prt[i].type == Type)) {
 				if (pring->prt[i].lpfc_sli_rcv_unsol_event)
 					(pring->prt[i].lpfc_sli_rcv_unsol_event)
 							(phba, pring, saveq);
@@ -1084,6 +1154,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 						IOSTAT_LOCAL_REJECT;
 					saveq->iocb.un.ulpWord[4] =
 						IOERR_SLI_ABORTED;
+
+					/* Firmware could still be in progress
+					 * of DMAing payload, so don't free data
+					 * buffer till after a hbeat.
+					 */
+					saveq->iocb_flag |= LPFC_DELAY_MEM_FREE;
 				}
 			}
 			(cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -1572,12 +1648,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 
 		writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
 
-		if (list_empty(&(pring->iocb_continueq))) {
-			list_add(&rspiocbp->list, &(pring->iocb_continueq));
-		} else {
-			list_add_tail(&rspiocbp->list,
-				      &(pring->iocb_continueq));
-		}
+		list_add_tail(&rspiocbp->list, &(pring->iocb_continueq));
 
 		pring->iocb_continueq_cnt++;
 		if (irsp->ulpLe) {
@@ -1642,17 +1713,17 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
 			iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
 			type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
 			if (type == LPFC_SOL_IOCB) {
-				spin_unlock_irqrestore(&phba->hbalock,
-						       iflag);
+				spin_unlock_irqrestore(&phba->hbalock, iflag);
 				rc = lpfc_sli_process_sol_iocb(phba, pring,
 							       saveq);
 				spin_lock_irqsave(&phba->hbalock, iflag);
 			} else if (type == LPFC_UNSOL_IOCB) {
-				spin_unlock_irqrestore(&phba->hbalock,
-						       iflag);
+				spin_unlock_irqrestore(&phba->hbalock, iflag);
 				rc = lpfc_sli_process_unsol_iocb(phba, pring,
 								 saveq);
 				spin_lock_irqsave(&phba->hbalock, iflag);
+				if (!rc)
+					free_saveq = 0;
 			} else if (type == LPFC_ABORT_IOCB) {
 				if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
 				    ((cmdiocbp =
@@ -1921,8 +1992,8 @@ lpfc_sli_brdkill(struct lpfc_hba *phba)
 			"0329 Kill HBA Data: x%x x%x\n",
 			phba->pport->port_state, psli->sli_flag);
 
-	if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
-						  GFP_KERNEL)) == 0)
+	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+	if (!pmb)
 		return 1;
 
 	/* Disable the error attention */
@@ -2113,7 +2184,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
 			   <status> */
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 					"0436 Adapter failed to init, "
-					"timeout, status reg x%x\n", status);
+					"timeout, status reg x%x, "
+					"FW Data: A8 x%x AC x%x\n", status,
+					readl(phba->MBslimaddr + 0xa8),
+					readl(phba->MBslimaddr + 0xac));
 			phba->link_state = LPFC_HBA_ERROR;
 			return -ETIMEDOUT;
 		}
@@ -2125,7 +2199,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
 			   <status> */
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 					"0437 Adapter failed to init, "
-					"chipset, status reg x%x\n", status);
+					"chipset, status reg x%x, "
+					"FW Data: A8 x%x AC x%x\n", status,
+					readl(phba->MBslimaddr + 0xa8),
+					readl(phba->MBslimaddr + 0xac));
 			phba->link_state = LPFC_HBA_ERROR;
 			return -EIO;
 		}
@@ -2153,7 +2230,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
 		/* Adapter failed to init, chipset, status reg <status> */
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
 				"0438 Adapter failed to init, chipset, "
-				"status reg x%x\n", status);
+				"status reg x%x, "
+				"FW Data: A8 x%x AC x%x\n", status,
+				readl(phba->MBslimaddr + 0xa8),
+				readl(phba->MBslimaddr + 0xac));
 		phba->link_state = LPFC_HBA_ERROR;
 		return -EIO;
 	}
@@ -2485,11 +2565,16 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
 	lpfc_sli_abort_iocb_ring(phba, pring);
 
 	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
-			"0316 Resetting board due to mailbox timeout\n");
+			"0345 Resetting board due to mailbox timeout\n");
 	/*
 	 * lpfc_offline calls lpfc_sli_hba_down which will clean up
 	 * on oustanding mailbox commands.
 	 */
+	/* If resets are disabled then set error state and return. */
+	if (!phba->cfg_enable_hba_reset) {
+		phba->link_state = LPFC_HBA_ERROR;
+		return;
+	}
 	lpfc_offline_prep(phba);
 	lpfc_offline(phba);
 	lpfc_sli_brdrestart(phba);
@@ -2507,6 +2592,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 	uint32_t status, evtctr;
 	uint32_t ha_copy;
 	int i;
+	unsigned long timeout;
 	unsigned long drvr_flag = 0;
 	volatile uint32_t word0, ldata;
 	void __iomem *to_slim;
@@ -2519,7 +2605,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 					"1806 Mbox x%x failed. No vport\n",
 					pmbox->mb.mbxCommand);
 			dump_stack();
-			return MBXERR_ERROR;
+			return MBX_NOT_FINISHED;
 		}
 	}
 
@@ -2571,21 +2657,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 			return MBX_NOT_FINISHED;
 		}
 
-		/* Handle STOP IOCB processing flag. This is only meaningful
-		 * if we are not polling for mbox completion.
-		 */
-		if (flag & MBX_STOP_IOCB) {
-			flag &= ~MBX_STOP_IOCB;
-			/* Now flag each ring */
-			for (i = 0; i < psli->num_rings; i++) {
-				/* If the ring is active, flag it */
-				if (psli->ring[i].cmdringaddr) {
-					psli->ring[i].flag |=
-					    LPFC_STOP_IOCB_MBX;
-				}
-			}
-		}
-
 		/* Another mailbox command is still being processed, queue this
 		 * command to be processed later.
 		 */
@@ -2620,23 +2691,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 		return MBX_BUSY;
 	}
 
-	/* Handle STOP IOCB processing flag. This is only meaningful
-	 * if we are not polling for mbox completion.
-	 */
-	if (flag & MBX_STOP_IOCB) {
-		flag &= ~MBX_STOP_IOCB;
-		if (flag == MBX_NOWAIT) {
-			/* Now flag each ring */
-			for (i = 0; i < psli->num_rings; i++) {
-				/* If the ring is active, flag it */
-				if (psli->ring[i].cmdringaddr) {
-					psli->ring[i].flag |=
-					    LPFC_STOP_IOCB_MBX;
-				}
-			}
-		}
-	}
-
 	psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE;
 
 	/* If we are not polling, we MUST be in SLI2 mode */
@@ -2714,18 +2768,24 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 	}
 
 	wmb();
-	/* interrupt board to doit right away */
-	writel(CA_MBATT, phba->CAregaddr);
-	readl(phba->CAregaddr); /* flush */
 
 	switch (flag) {
 	case MBX_NOWAIT:
-		/* Don't wait for it to finish, just return */
+		/* Set up reference to mailbox command */
 		psli->mbox_active = pmbox;
+		/* Interrupt board to do it */
+		writel(CA_MBATT, phba->CAregaddr);
+		readl(phba->CAregaddr); /* flush */
+		/* Don't wait for it to finish, just return */
 		break;
 
 	case MBX_POLL:
+		/* Set up null reference to mailbox command */
 		psli->mbox_active = NULL;
+		/* Interrupt board to do it */
+		writel(CA_MBATT, phba->CAregaddr);
+		readl(phba->CAregaddr); /* flush */
+
 		if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
 			/* First read mbox status word */
 			word0 = *((volatile uint32_t *)&phba->slim2p->mbx);
@@ -2737,15 +2797,15 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 
 		/* Read the HBA Host Attention Register */
 		ha_copy = readl(phba->HAregaddr);
-
-		i = lpfc_mbox_tmo_val(phba, mb->mbxCommand);
-		i *= 1000; /* Convert to ms */
-
+		timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba,
+							     mb->mbxCommand) *
+					   1000) + jiffies;
+		i = 0;
 		/* Wait for command to complete */
 		while (((word0 & OWN_CHIP) == OWN_CHIP) ||
 		       (!(ha_copy & HA_MBATT) &&
 			(phba->link_state > LPFC_WARM_START))) {
-			if (i-- <= 0) {
+			if (time_after(jiffies, timeout)) {
 				psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
 				spin_unlock_irqrestore(&phba->hbalock,
 						       drvr_flag);
@@ -2758,12 +2818,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
 			    && (evtctr != psli->slistat.mbox_event))
 				break;
 
-			spin_unlock_irqrestore(&phba->hbalock,
-					       drvr_flag);
-
-			msleep(1);
-
-			spin_lock_irqsave(&phba->hbalock, drvr_flag);
+			if (i++ > 10) {
+				spin_unlock_irqrestore(&phba->hbalock,
+						       drvr_flag);
+				msleep(1);
+				spin_lock_irqsave(&phba->hbalock, drvr_flag);
+			}
 
 			if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
 				/* First copy command data */
@@ -2848,7 +2908,7 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 /*
  * Lockless version of lpfc_sli_issue_iocb.
  */
-int
+static int
 __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		    struct lpfc_iocbq *piocb, uint32_t flag)
 {
@@ -2879,9 +2939,9 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
 	/*
 	 * Check to see if we are blocking IOCB processing because of a
-	 * outstanding mbox command.
+	 * outstanding event.
 	 */
-	if (unlikely(pring->flag & LPFC_STOP_IOCB_MBX))
+	if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT))
 		goto iocb_busy;
 
 	if (unlikely(phba->link_state == LPFC_LINK_DOWN)) {
@@ -2993,6 +3053,61 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
 	return 0;
 }
 
+static void
+lpfc_sli_async_event_handler(struct lpfc_hba * phba,
+	struct lpfc_sli_ring * pring, struct lpfc_iocbq * iocbq)
+{
+	IOCB_t *icmd;
+	uint16_t evt_code;
+	uint16_t temp;
+	struct temp_event temp_event_data;
+	struct Scsi_Host *shost;
+
+	icmd = &iocbq->iocb;
+	evt_code = icmd->un.asyncstat.evt_code;
+	temp = icmd->ulpContext;
+
+	if ((evt_code != ASYNC_TEMP_WARN) &&
+		(evt_code != ASYNC_TEMP_SAFE)) {
+		lpfc_printf_log(phba,
+			KERN_ERR,
+			LOG_SLI,
+			"0346 Ring %d handler: unexpected ASYNC_STATUS"
+			" evt_code 0x%x\n",
+			pring->ringno,
+			icmd->un.asyncstat.evt_code);
+		return;
+	}
+	temp_event_data.data = (uint32_t)temp;
+	temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
+	if (evt_code == ASYNC_TEMP_WARN) {
+		temp_event_data.event_code = LPFC_THRESHOLD_TEMP;
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_TEMP,
+				"0347 Adapter is very hot, please take "
+				"corrective action. temperature : %d Celsius\n",
+				temp);
+	}
+	if (evt_code == ASYNC_TEMP_SAFE) {
+		temp_event_data.event_code = LPFC_NORMAL_TEMP;
+		lpfc_printf_log(phba,
+				KERN_ERR,
+				LOG_TEMP,
+				"0340 Adapter temperature is OK now. "
+				"temperature : %d Celsius\n",
+				temp);
+	}
+
+	/* Send temperature change event to applications */
+	shost = lpfc_shost_from_vport(phba->pport);
+	fc_host_post_vendor_event(shost, fc_get_event_number(),
+		sizeof(temp_event_data), (char *) &temp_event_data,
+		SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
+
+}
+
+
 int
 lpfc_sli_setup(struct lpfc_hba *phba)
 {
@@ -3059,6 +3174,8 @@ lpfc_sli_setup(struct lpfc_hba *phba)
 			pring->fast_iotag = 0;
 			pring->iotag_ctr = 0;
 			pring->iotag_max = 4096;
+			pring->lpfc_sli_rcv_async_status =
+				lpfc_sli_async_event_handler;
 			pring->num_mask = 4;
 			pring->prt[0].profile = 0;	/* Mask 0 */
 			pring->prt[0].rctl = FC_ELS_REQ;
@@ -3123,6 +3240,7 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba)
 		INIT_LIST_HEAD(&pring->txq);
 		INIT_LIST_HEAD(&pring->txcmplq);
 		INIT_LIST_HEAD(&pring->iocb_continueq);
+		INIT_LIST_HEAD(&pring->iocb_continue_saveq);
 		INIT_LIST_HEAD(&pring->postbufq);
 	}
 	spin_unlock_irq(&phba->hbalock);
@@ -3193,6 +3311,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
 	LIST_HEAD(completions);
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring *pring;
+	struct lpfc_dmabuf *buf_ptr;
 	LPFC_MBOXQ_t *pmb;
 	struct lpfc_iocbq *iocb;
 	IOCB_t *cmd = NULL;
@@ -3232,6 +3351,19 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
 		}
 	}
 
+	spin_lock_irqsave(&phba->hbalock, flags);
+	list_splice_init(&phba->elsbuf, &completions);
+	phba->elsbuf_cnt = 0;
+	phba->elsbuf_prev_cnt = 0;
+	spin_unlock_irqrestore(&phba->hbalock, flags);
+
+	while (!list_empty(&completions)) {
+		list_remove_head(&completions, buf_ptr,
+			struct lpfc_dmabuf, list);
+		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+		kfree(buf_ptr);
+	}
+
 	/* Return any active mbox cmds */
 	del_timer_sync(&psli->mbox_tmo);
 	spin_lock_irqsave(&phba->hbalock, flags);
@@ -3294,6 +3426,47 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 	return 0;
 }
 
+uint32_t
+lpfc_sli_get_buffer_tag(struct lpfc_hba *phba)
+{
+	spin_lock_irq(&phba->hbalock);
+	phba->buffer_tag_count++;
+	/*
+	 * Always set the QUE_BUFTAG_BIT to distiguish between
+	 * a tag assigned by HBQ.
+	 */
+	phba->buffer_tag_count |= QUE_BUFTAG_BIT;
+	spin_unlock_irq(&phba->hbalock);
+	return phba->buffer_tag_count;
+}
+
+struct lpfc_dmabuf *
+lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+			uint32_t tag)
+{
+	struct lpfc_dmabuf *mp, *next_mp;
+	struct list_head *slp = &pring->postbufq;
+
+	/* Search postbufq, from the begining, looking for a match on tag */
+	spin_lock_irq(&phba->hbalock);
+	list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
+		if (mp->buffer_tag == tag) {
+			list_del_init(&mp->list);
+			pring->postbufq_cnt--;
+			spin_unlock_irq(&phba->hbalock);
+			return mp;
+		}
+	}
+
+	spin_unlock_irq(&phba->hbalock);
+	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+			"0410 Cannot find virtual addr for buffer tag on "
+			"ring %d Data x%lx x%p x%p x%x\n",
+			pring->ringno, (unsigned long) tag,
+			slp->next, slp->prev, pring->postbufq_cnt);
+
+	return NULL;
+}
 
 struct lpfc_dmabuf *
 lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
@@ -3361,6 +3534,12 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			pring->txcmplq_cnt--;
 			spin_unlock_irq(&phba->hbalock);
 
+			/* Firmware could still be in progress of DMAing
+			 * payload, so don't free data buffer till after
+			 * a hbeat.
+			 */
+			abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE;
+
 			abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
 			abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
 			abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED;
@@ -3699,7 +3878,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
 	unsigned long flag;
 
 	/* The caller must leave context1 empty. */
-	if (pmboxq->context1 != 0)
+	if (pmboxq->context1)
 		return MBX_NOT_FINISHED;
 
 	/* setup wake call as IOCB callback */
@@ -3771,7 +3950,6 @@ lpfc_intr_handler(int irq, void *dev_id)
 	uint32_t ha_copy;
 	uint32_t work_ha_copy;
 	unsigned long status;
-	int i;
 	uint32_t control;
 
 	MAILBOX_t *mbox, *pmbox;
@@ -3888,7 +4066,6 @@ lpfc_intr_handler(int irq, void *dev_id)
 		}
 
 		if (work_ha_copy & HA_ERATT) {
-			phba->link_state = LPFC_HBA_ERROR;
 			/*
 			 * There was a link/board error.  Read the
 			 * status register to retrieve the error event
@@ -3920,7 +4097,7 @@ lpfc_intr_handler(int irq, void *dev_id)
 				 * Stray Mailbox Interrupt, mbxCommand <cmd>
 				 * mbxStatus <status>
 				 */
-				lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX |
+				lpfc_printf_log(phba, KERN_ERR, LOG_MBOX |
 						LOG_SLI,
 						"(%d):0304 Stray Mailbox "
 						"Interrupt mbxCommand x%x "
@@ -3928,51 +4105,60 @@ lpfc_intr_handler(int irq, void *dev_id)
 						(vport ? vport->vpi : 0),
 						pmbox->mbxCommand,
 						pmbox->mbxStatus);
-			}
-			phba->last_completion_time = jiffies;
-			del_timer_sync(&phba->sli.mbox_tmo);
-
-			phba->sli.mbox_active = NULL;
-			if (pmb->mbox_cmpl) {
-				lpfc_sli_pcimem_bcopy(mbox, pmbox,
-						      MAILBOX_CMD_SIZE);
-			}
-			if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
-				pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
+				/* clear mailbox attention bit */
+				work_ha_copy &= ~HA_MBATT;
+			} else {
+				phba->last_completion_time = jiffies;
+				del_timer(&phba->sli.mbox_tmo);
 
-				lpfc_debugfs_disc_trc(vport,
-					LPFC_DISC_TRC_MBOX_VPORT,
-					"MBOX dflt rpi: : status:x%x rpi:x%x",
-					(uint32_t)pmbox->mbxStatus,
-					pmbox->un.varWords[0], 0);
-
-				if ( !pmbox->mbxStatus) {
-					mp = (struct lpfc_dmabuf *)
-						(pmb->context1);
-					ndlp = (struct lpfc_nodelist *)
-						pmb->context2;
-
-					/* Reg_LOGIN of dflt RPI was successful.
-					 * new lets get rid of the RPI using the
-					 * same mbox buffer.
-					 */
-					lpfc_unreg_login(phba, vport->vpi,
-						pmbox->un.varWords[0], pmb);
-					pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
-					pmb->context1 = mp;
-					pmb->context2 = ndlp;
-					pmb->vport = vport;
-					spin_lock(&phba->hbalock);
-					phba->sli.sli_flag &=
-						~LPFC_SLI_MBOX_ACTIVE;
-					spin_unlock(&phba->hbalock);
-					goto send_current_mbox;
+				phba->sli.mbox_active = NULL;
+				if (pmb->mbox_cmpl) {
+					lpfc_sli_pcimem_bcopy(mbox, pmbox,
+							MAILBOX_CMD_SIZE);
+				}
+				if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
+					pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
+
+					lpfc_debugfs_disc_trc(vport,
+						LPFC_DISC_TRC_MBOX_VPORT,
+						"MBOX dflt rpi: : "
+						"status:x%x rpi:x%x",
+						(uint32_t)pmbox->mbxStatus,
+						pmbox->un.varWords[0], 0);
+
+					if (!pmbox->mbxStatus) {
+						mp = (struct lpfc_dmabuf *)
+							(pmb->context1);
+						ndlp = (struct lpfc_nodelist *)
+							pmb->context2;
+
+						/* Reg_LOGIN of dflt RPI was
+						 * successful. new lets get
+						 * rid of the RPI using the
+						 * same mbox buffer.
+						 */
+						lpfc_unreg_login(phba,
+							vport->vpi,
+							pmbox->un.varWords[0],
+							pmb);
+						pmb->mbox_cmpl =
+							lpfc_mbx_cmpl_dflt_rpi;
+						pmb->context1 = mp;
+						pmb->context2 = ndlp;
+						pmb->vport = vport;
+						spin_lock(&phba->hbalock);
+						phba->sli.sli_flag &=
+							~LPFC_SLI_MBOX_ACTIVE;
+						spin_unlock(&phba->hbalock);
+						goto send_current_mbox;
+					}
 				}
+				spin_lock(&phba->pport->work_port_lock);
+				phba->pport->work_port_events &=
+					~WORKER_MBOX_TMO;
+				spin_unlock(&phba->pport->work_port_lock);
+				lpfc_mbox_cmpl_put(phba, pmb);
 			}
-			spin_lock(&phba->pport->work_port_lock);
-			phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
-			spin_unlock(&phba->pport->work_port_lock);
-			lpfc_mbox_cmpl_put(phba, pmb);
 		}
 		if ((work_ha_copy & HA_MBATT) &&
 		    (phba->sli.mbox_active == NULL)) {
@@ -3990,10 +4176,6 @@ send_current_mbox:
 					lpfc_mbox_cmpl_put(phba, pmb);
 					goto send_next_mbox;
 				}
-			} else {
-				/* Turn on IOCB processing */
-				for (i = 0; i < phba->sli.num_rings; i++)
-					lpfc_sli_turn_on_ring(phba, i);
 			}
 
 		}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 51b2b6b949be..7249fd252cbb 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -33,6 +33,7 @@ typedef enum _lpfc_ctx_cmd {
 struct lpfc_iocbq {
 	/* lpfc_iocbqs are used in double linked lists */
 	struct list_head list;
+	struct list_head clist;
 	uint16_t iotag;         /* pre-assigned IO tag */
 	uint16_t rsvd1;
 
@@ -44,6 +45,7 @@ struct lpfc_iocbq {
 #define LPFC_IO_FCP		4	/* FCP command -- iocbq in scsi_buf */
 #define LPFC_DRIVER_ABORTED	8	/* driver aborted this request */
 #define LPFC_IO_FABRIC		0x10	/* Iocb send using fabric scheduler */
+#define LPFC_DELAY_MEM_FREE	0x20    /* Defer free'ing of FC data */
 
 	uint8_t abort_count;
 	uint8_t rsvd2;
@@ -92,8 +94,6 @@ typedef struct lpfcMboxq {
 #define MBX_POLL        1	/* poll mailbox till command done, then
 				   return */
 #define MBX_NOWAIT      2	/* issue command then return immediately */
-#define MBX_STOP_IOCB   4	/* Stop iocb processing till mbox cmds
-				   complete */
 
 #define LPFC_MAX_RING_MASK  4	/* max num of rctl/type masks allowed per
 				   ring */
@@ -129,9 +129,7 @@ struct lpfc_sli_ring {
 	uint16_t flag;		/* ring flags */
 #define LPFC_DEFERRED_RING_EVENT 0x001	/* Deferred processing a ring event */
 #define LPFC_CALL_RING_AVAILABLE 0x002	/* indicates cmd was full */
-#define LPFC_STOP_IOCB_MBX       0x010	/* Stop processing IOCB cmds mbox */
 #define LPFC_STOP_IOCB_EVENT     0x020	/* Stop processing IOCB cmds event */
-#define LPFC_STOP_IOCB_MASK      0x030	/* Stop processing IOCB cmds mask */
 	uint16_t abtsiotag;	/* tracks next iotag to use for ABTS */
 
 	uint32_t local_getidx;   /* last available cmd index (from cmdGetInx) */
@@ -163,9 +161,12 @@ struct lpfc_sli_ring {
 	struct list_head iocb_continueq;
 	uint16_t iocb_continueq_cnt;	/* current length of queue */
 	uint16_t iocb_continueq_max;	/* max length */
+	struct list_head iocb_continue_saveq;
 
 	struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK];
 	uint32_t num_mask;	/* number of mask entries in prt array */
+	void (*lpfc_sli_rcv_async_status) (struct lpfc_hba *,
+		struct lpfc_sli_ring *, struct lpfc_iocbq *);
 
 	struct lpfc_sli_ring_stat stats;	/* SLI statistical info */
 
@@ -199,9 +200,6 @@ struct lpfc_hbq_init {
 	uint32_t add_count;	/* number to allocate when starved */
 } ;
 
-#define LPFC_MAX_HBQ 16
-
-
 /* Structure used to hold SLI statistical counters and info */
 struct lpfc_sli_stat {
 	uint64_t mbox_stat_err;  /* Mbox cmds completed status error */
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 0081f49286bc..4b633d39a82a 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2007 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2008 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  *                                                                 *
@@ -18,10 +18,10 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.2.2"
+#define LPFC_DRIVER_VERSION "8.2.4"
 
 #define LPFC_DRIVER_NAME "lpfc"
 
 #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
 		LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex.  All rights reserved."
+#define LPFC_COPYRIGHT "Copyright(c) 2004-2008 Emulex.  All rights reserved."
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index dcb415e717c3..9fad7663c117 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -125,15 +125,26 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
 	pmb->vport = vport;
 	rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
 	if (rc != MBX_SUCCESS) {
-		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
-				 "1818 VPort failed init, mbxCmd x%x "
-				 "READ_SPARM mbxStatus x%x, rc = x%x\n",
-				 mb->mbxCommand, mb->mbxStatus, rc);
-		lpfc_mbuf_free(phba, mp->virt, mp->phys);
-		kfree(mp);
-		if (rc != MBX_TIMEOUT)
-			mempool_free(pmb, phba->mbox_mem_pool);
-		return -EIO;
+		if (signal_pending(current)) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
+					 "1830 Signal aborted mbxCmd x%x\n",
+					 mb->mbxCommand);
+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
+			kfree(mp);
+			if (rc != MBX_TIMEOUT)
+				mempool_free(pmb, phba->mbox_mem_pool);
+			return -EINTR;
+		} else {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
+					 "1818 VPort failed init, mbxCmd x%x "
+					 "READ_SPARM mbxStatus x%x, rc = x%x\n",
+					 mb->mbxCommand, mb->mbxStatus, rc);
+			lpfc_mbuf_free(phba, mp->virt, mp->phys);
+			kfree(mp);
+			if (rc != MBX_TIMEOUT)
+				mempool_free(pmb, phba->mbox_mem_pool);
+			return -EIO;
+		}
 	}
 
 	memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
@@ -204,6 +215,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
 	int instance;
 	int vpi;
 	int rc = VPORT_ERROR;
+	int status;
 
 	if ((phba->sli_rev < 3) ||
 		!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
@@ -248,13 +260,19 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
 	vport->vpi = vpi;
 	lpfc_debugfs_initialize(vport);
 
-	if (lpfc_vport_sparm(phba, vport)) {
-		lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
-				 "1813 Create VPORT failed. "
-				 "Cannot get sparam\n");
+	if ((status = lpfc_vport_sparm(phba, vport))) {
+		if (status == -EINTR) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+					 "1831 Create VPORT Interrupted.\n");
+			rc = VPORT_ERROR;
+		} else {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+					 "1813 Create VPORT failed. "
+					 "Cannot get sparam\n");
+			rc = VPORT_NORESOURCES;
+		}
 		lpfc_free_vpi(phba, vpi);
 		destroy_port(vport);
-		rc = VPORT_NORESOURCES;
 		goto error_out;
 	}
 
@@ -427,7 +445,6 @@ int
 lpfc_vport_delete(struct fc_vport *fc_vport)
 {
 	struct lpfc_nodelist *ndlp = NULL;
-	struct lpfc_nodelist *next_ndlp;
 	struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost;
 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
 	struct lpfc_hba   *phba = vport->phba;
@@ -482,8 +499,18 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
 
 	ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
 	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
-		phba->link_state >= LPFC_LINK_UP) {
-
+	    phba->link_state >= LPFC_LINK_UP) {
+		if (vport->cfg_enable_da_id) {
+			timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
+			if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0))
+				while (vport->ct_flags && timeout)
+					timeout = schedule_timeout(timeout);
+			else
+				lpfc_printf_log(vport->phba, KERN_WARNING,
+						LOG_VPORT,
+						"1829 CT command failed to "
+						"delete objects on fabric. \n");
+		}
 		/* First look for the Fabric ndlp */
 		ndlp = lpfc_findnode_did(vport, Fabric_DID);
 		if (!ndlp) {
@@ -503,23 +530,20 @@ lpfc_vport_delete(struct fc_vport *fc_vport)
 	}
 
 skip_logo:
+	lpfc_cleanup(vport);
 	lpfc_sli_host_down(vport);
 
-	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
-		lpfc_disc_state_machine(vport, ndlp, NULL,
-					     NLP_EVT_DEVICE_RECOVERY);
-		lpfc_disc_state_machine(vport, ndlp, NULL,
-					     NLP_EVT_DEVICE_RM);
-	}
-
 	lpfc_stop_vport_timers(vport);
 	lpfc_unreg_all_rpis(vport);
-	lpfc_unreg_default_rpis(vport);
-	/*
-	 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
-	 * scsi_host_put() to release the vport.
-	 */
-	lpfc_mbx_unreg_vpi(vport);
+
+	if (!(phba->pport->load_flag & FC_UNLOADING)) {
+		lpfc_unreg_default_rpis(vport);
+		/*
+		 * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi)
+		 * does the scsi_host_put() to release the vport.
+		 */
+		lpfc_mbx_unreg_vpi(vport);
+	}
 
 	lpfc_free_vpi(phba, vport->vpi);
 	vport->work_port_events = 0;
@@ -532,16 +556,13 @@ skip_logo:
 	return VPORT_OK;
 }
 
-EXPORT_SYMBOL(lpfc_vport_create);
-EXPORT_SYMBOL(lpfc_vport_delete);
-
 struct lpfc_vport **
 lpfc_create_vport_work_array(struct lpfc_hba *phba)
 {
 	struct lpfc_vport *port_iterator;
 	struct lpfc_vport **vports;
 	int index = 0;
-	vports = kzalloc(LPFC_MAX_VPORTS * sizeof(struct lpfc_vport *),
+	vports = kzalloc((phba->max_vpi + 1) * sizeof(struct lpfc_vport *),
 			 GFP_KERNEL);
 	if (vports == NULL)
 		return NULL;
@@ -560,12 +581,12 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba)
 }
 
 void
-lpfc_destroy_vport_work_array(struct lpfc_vport **vports)
+lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports)
 {
 	int i;
 	if (vports == NULL)
 		return;
-	for (i=0; vports[i] != NULL && i < LPFC_MAX_VPORTS; i++)
+	for (i=0; vports[i] != NULL && i <= phba->max_vpi; i++)
 		scsi_host_put(lpfc_shost_from_vport(vports[i]));
 	kfree(vports);
 }
diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h
index 91da17751a37..96c445333b69 100644
--- a/drivers/scsi/lpfc/lpfc_vport.h
+++ b/drivers/scsi/lpfc/lpfc_vport.h
@@ -89,7 +89,7 @@ int lpfc_vport_delete(struct fc_vport *);
 int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
 int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
 struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *);
-void lpfc_destroy_vport_work_array(struct lpfc_vport **);
+void lpfc_destroy_vport_work_array(struct lpfc_hba *, struct lpfc_vport **);
 
 /*
  *  queuecommand  VPORT-specific return codes. Specified in  the host byte code.
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index a035001f4438..b12ad7c7c673 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -402,7 +402,6 @@ static struct scsi_host_template mac53c94_template = {
 	.sg_tablesize	= SG_ALL,
 	.cmd_per_lun	= 1,
 	.use_clustering	= DISABLE_CLUSTERING,
-	.use_sg_chaining = ENABLE_SG_CHAINING,
 };
 
 static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *match)
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 66c652035730..4d59ae8491a4 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -4490,7 +4490,6 @@ static struct scsi_host_template megaraid_template = {
 	.sg_tablesize			= MAX_SGLIST,
 	.cmd_per_lun			= DEF_CMD_PER_LUN,
 	.use_clustering			= ENABLE_CLUSTERING,
-	.use_sg_chaining		= ENABLE_SG_CHAINING,
 	.eh_abort_handler		= megaraid_abort,
 	.eh_device_reset_handler	= megaraid_reset,
 	.eh_bus_reset_handler		= megaraid_reset,
@@ -4889,7 +4888,7 @@ __megaraid_shutdown(adapter_t *adapter)
 		mdelay(1000);
 }
 
-static void
+static void __devexit
 megaraid_remove_one(struct pci_dev *pdev)
 {
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index c8923108183a..6db77c00e3ee 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -300,7 +300,7 @@ static struct pci_device_id pci_id_table_g[] =  {
 MODULE_DEVICE_TABLE(pci, pci_id_table_g);
 
 
-static struct pci_driver megaraid_pci_driver_g = {
+static struct pci_driver megaraid_pci_driver = {
 	.name		= "megaraid",
 	.id_table	= pci_id_table_g,
 	.probe		= megaraid_probe_one,
@@ -361,7 +361,6 @@ static struct scsi_host_template megaraid_template_g = {
 	.eh_host_reset_handler		= megaraid_reset_handler,
 	.change_queue_depth		= megaraid_change_queue_depth,
 	.use_clustering			= ENABLE_CLUSTERING,
-	.use_sg_chaining		= ENABLE_SG_CHAINING,
 	.sdev_attrs			= megaraid_sdev_attrs,
 	.shost_attrs			= megaraid_shost_attrs,
 };
@@ -394,7 +393,7 @@ megaraid_init(void)
 
 
 	// register as a PCI hot-plug driver module
-	rval = pci_register_driver(&megaraid_pci_driver_g);
+	rval = pci_register_driver(&megaraid_pci_driver);
 	if (rval < 0) {
 		con_log(CL_ANN, (KERN_WARNING
 			"megaraid: could not register hotplug support.\n"));
@@ -415,7 +414,7 @@ megaraid_exit(void)
 	con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n"));
 
 	// unregister as PCI hotplug driver
-	pci_unregister_driver(&megaraid_pci_driver_g);
+	pci_unregister_driver(&megaraid_pci_driver);
 
 	return;
 }
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index e3c5c5282203..672c759ac24d 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -2,7 +2,7 @@
  *
  *		Linux MegaRAID driver for SAS based RAID controllers
  *
- * Copyright (c) 2003-2005  LSI Logic Corporation.
+ * Copyright (c) 2003-2005  LSI Corporation.
  *
  *	   This program is free software; you can redistribute it and/or
  *	   modify it under the terms of the GNU General Public License
@@ -10,7 +10,7 @@
  *	   2 of the License, or (at your option) any later version.
  *
  * FILE		: megaraid_sas.c
- * Version	: v00.00.03.10-rc5
+ * Version	: v00.00.03.16-rc1
  *
  * Authors:
  *	(email-id : megaraidlinux@lsi.com)
@@ -31,6 +31,7 @@
 #include <linux/moduleparam.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/uio.h>
@@ -46,10 +47,18 @@
 #include <scsi/scsi_host.h>
 #include "megaraid_sas.h"
 
+/*
+ * poll_mode_io:1- schedule complete completion from q cmd
+ */
+static unsigned int poll_mode_io;
+module_param_named(poll_mode_io, poll_mode_io, int, 0);
+MODULE_PARM_DESC(poll_mode_io,
+	"Complete cmds from IO path, (default=0)");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux@lsi.com");
-MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
+MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
 
 /*
  * PCI ID table for all supported controllers
@@ -76,6 +85,10 @@ static DEFINE_MUTEX(megasas_async_queue_mutex);
 
 static u32 megasas_dbg_lvl;
 
+static void
+megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+		     u8 alt_status);
+
 /**
  * megasas_get_cmd -	Get a command from the free pool
  * @instance:		Adapter soft state
@@ -855,6 +868,12 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
 	atomic_inc(&instance->fw_outstanding);
 
 	instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
+	/*
+	 * Check if we have pend cmds to be completed
+	 */
+	if (poll_mode_io && atomic_read(&instance->fw_outstanding))
+		tasklet_schedule(&instance->isr_tasklet);
+
 
 	return 0;
 
@@ -886,6 +905,64 @@ static int megasas_slave_configure(struct scsi_device *sdev)
 }
 
 /**
+ * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
+ * @instance_addr:			Address of adapter soft state
+ *
+ * Tasklet to complete cmds
+ */
+static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+{
+	u32 producer;
+	u32 consumer;
+	u32 context;
+	struct megasas_cmd *cmd;
+	struct megasas_instance *instance =
+				(struct megasas_instance *)instance_addr;
+	unsigned long flags;
+
+	/* If we have already declared adapter dead, donot complete cmds */
+	if (instance->hw_crit_error)
+		return;
+
+	spin_lock_irqsave(&instance->completion_lock, flags);
+
+	producer = *instance->producer;
+	consumer = *instance->consumer;
+
+	while (consumer != producer) {
+		context = instance->reply_queue[consumer];
+
+		cmd = instance->cmd_list[context];
+
+		megasas_complete_cmd(instance, cmd, DID_OK);
+
+		consumer++;
+		if (consumer == (instance->max_fw_cmds + 1)) {
+			consumer = 0;
+		}
+	}
+
+	*instance->consumer = producer;
+
+	spin_unlock_irqrestore(&instance->completion_lock, flags);
+
+	/*
+	 * Check if we can restore can_queue
+	 */
+	if (instance->flag & MEGASAS_FW_BUSY
+		&& time_after(jiffies, instance->last_time + 5 * HZ)
+		&& atomic_read(&instance->fw_outstanding) < 17) {
+
+		spin_lock_irqsave(instance->host->host_lock, flags);
+		instance->flag &= ~MEGASAS_FW_BUSY;
+		instance->host->can_queue =
+				instance->max_fw_cmds - MEGASAS_INT_CMDS;
+
+		spin_unlock_irqrestore(instance->host->host_lock, flags);
+	}
+}
+
+/**
  * megasas_wait_for_outstanding -	Wait for all outstanding cmds
  * @instance:				Adapter soft state
  *
@@ -908,6 +985,11 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
 			printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
 			       "commands to complete\n",i,outstanding);
+			/*
+			 * Call cmd completion routine. Cmd to be
+			 * be completed directly without depending on isr.
+			 */
+			megasas_complete_cmd_dpc((unsigned long)instance);
 		}
 
 		msleep(1000);
@@ -1100,7 +1182,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
 static struct scsi_host_template megasas_template = {
 
 	.module = THIS_MODULE,
-	.name = "LSI Logic SAS based MegaRAID driver",
+	.name = "LSI SAS based MegaRAID driver",
 	.proc_name = "megaraid_sas",
 	.slave_configure = megasas_slave_configure,
 	.queuecommand = megasas_queue_command,
@@ -1110,7 +1192,6 @@ static struct scsi_host_template megasas_template = {
 	.eh_timed_out = megasas_reset_timer,
 	.bios_param = megasas_bios_param,
 	.use_clustering = ENABLE_CLUSTERING,
-	.use_sg_chaining = ENABLE_SG_CHAINING,
 };
 
 /**
@@ -1749,57 +1830,119 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
 }
 
 /**
- * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
- * @instance_addr:			Address of adapter soft state
+ * megasas_issue_init_mfi -	Initializes the FW
+ * @instance:		Adapter soft state
  *
- * Tasklet to complete cmds
+ * Issues the INIT MFI cmd
  */
-static void megasas_complete_cmd_dpc(unsigned long instance_addr)
+static int
+megasas_issue_init_mfi(struct megasas_instance *instance)
 {
-	u32 producer;
-	u32 consumer;
 	u32 context;
+
 	struct megasas_cmd *cmd;
-	struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
-	unsigned long flags;
 
-	/* If we have already declared adapter dead, donot complete cmds */
-	if (instance->hw_crit_error)
-		return;
+	struct megasas_init_frame *init_frame;
+	struct megasas_init_queue_info *initq_info;
+	dma_addr_t init_frame_h;
+	dma_addr_t initq_info_h;
 
-	producer = *instance->producer;
-	consumer = *instance->consumer;
+	/*
+	 * Prepare a init frame. Note the init frame points to queue info
+	 * structure. Each frame has SGL allocated after first 64 bytes. For
+	 * this frame - since we don't need any SGL - we use SGL's space as
+	 * queue info structure
+	 *
+	 * We will not get a NULL command below. We just created the pool.
+	 */
+	cmd = megasas_get_cmd(instance);
 
-	while (consumer != producer) {
-		context = instance->reply_queue[consumer];
+	init_frame = (struct megasas_init_frame *)cmd->frame;
+	initq_info = (struct megasas_init_queue_info *)
+		((unsigned long)init_frame + 64);
 
-		cmd = instance->cmd_list[context];
+	init_frame_h = cmd->frame_phys_addr;
+	initq_info_h = init_frame_h + 64;
 
-		megasas_complete_cmd(instance, cmd, DID_OK);
+	context = init_frame->context;
+	memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
+	memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
+	init_frame->context = context;
 
-		consumer++;
-		if (consumer == (instance->max_fw_cmds + 1)) {
-			consumer = 0;
-		}
-	}
+	initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
+	initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
 
-	*instance->consumer = producer;
+	initq_info->producer_index_phys_addr_lo = instance->producer_h;
+	initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
+
+	init_frame->cmd = MFI_CMD_INIT;
+	init_frame->cmd_status = 0xFF;
+	init_frame->queue_info_new_phys_addr_lo = initq_info_h;
+
+	init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
 
 	/*
-	 * Check if we can restore can_queue
+	 * disable the intr before firing the init frame to FW
 	 */
-	if (instance->flag & MEGASAS_FW_BUSY
-		&& time_after(jiffies, instance->last_time + 5 * HZ)
-		&& atomic_read(&instance->fw_outstanding) < 17) {
+	instance->instancet->disable_intr(instance->reg_set);
 
-		spin_lock_irqsave(instance->host->host_lock, flags);
-		instance->flag &= ~MEGASAS_FW_BUSY;
-		instance->host->can_queue =
-				instance->max_fw_cmds - MEGASAS_INT_CMDS;
+	/*
+	 * Issue the init frame in polled mode
+	 */
 
-		spin_unlock_irqrestore(instance->host->host_lock, flags);
+	if (megasas_issue_polled(instance, cmd)) {
+		printk(KERN_ERR "megasas: Failed to init firmware\n");
+		megasas_return_cmd(instance, cmd);
+		goto fail_fw_init;
 	}
 
+	megasas_return_cmd(instance, cmd);
+
+	return 0;
+
+fail_fw_init:
+	return -EINVAL;
+}
+
+/**
+ * megasas_start_timer - Initializes a timer object
+ * @instance:		Adapter soft state
+ * @timer:		timer object to be initialized
+ * @fn:			timer function
+ * @interval:		time interval between timer function call
+ */
+static inline void
+megasas_start_timer(struct megasas_instance *instance,
+			struct timer_list *timer,
+			void *fn, unsigned long interval)
+{
+	init_timer(timer);
+	timer->expires = jiffies + interval;
+	timer->data = (unsigned long)instance;
+	timer->function = fn;
+	add_timer(timer);
+}
+
+/**
+ * megasas_io_completion_timer - Timer fn
+ * @instance_addr:	Address of adapter soft state
+ *
+ * Schedules tasklet for cmd completion
+ * if poll_mode_io is set
+ */
+static void
+megasas_io_completion_timer(unsigned long instance_addr)
+{
+	struct megasas_instance *instance =
+			(struct megasas_instance *)instance_addr;
+
+	if (atomic_read(&instance->fw_outstanding))
+		tasklet_schedule(&instance->isr_tasklet);
+
+	/* Restart timer */
+	if (poll_mode_io)
+		mod_timer(&instance->io_completion_timer,
+			jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL);
 }
 
 /**
@@ -1814,22 +1957,15 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 	u32 reply_q_sz;
 	u32 max_sectors_1;
 	u32 max_sectors_2;
+	u32 tmp_sectors;
 	struct megasas_register_set __iomem *reg_set;
-
-	struct megasas_cmd *cmd;
 	struct megasas_ctrl_info *ctrl_info;
-
-	struct megasas_init_frame *init_frame;
-	struct megasas_init_queue_info *initq_info;
-	dma_addr_t init_frame_h;
-	dma_addr_t initq_info_h;
-
 	/*
 	 * Map the message registers
 	 */
 	instance->base_addr = pci_resource_start(instance->pdev, 0);
 
-	if (pci_request_regions(instance->pdev, "megasas: LSI Logic")) {
+	if (pci_request_regions(instance->pdev, "megasas: LSI")) {
 		printk(KERN_DEBUG "megasas: IO memory region busy!\n");
 		return -EBUSY;
 	}
@@ -1900,52 +2036,8 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 		goto fail_reply_queue;
 	}
 
-	/*
-	 * Prepare a init frame. Note the init frame points to queue info
-	 * structure. Each frame has SGL allocated after first 64 bytes. For
-	 * this frame - since we don't need any SGL - we use SGL's space as
-	 * queue info structure
-	 *
-	 * We will not get a NULL command below. We just created the pool.
-	 */
-	cmd = megasas_get_cmd(instance);
-
-	init_frame = (struct megasas_init_frame *)cmd->frame;
-	initq_info = (struct megasas_init_queue_info *)
-	    ((unsigned long)init_frame + 64);
-
-	init_frame_h = cmd->frame_phys_addr;
-	initq_info_h = init_frame_h + 64;
-
-	memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
-	memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
-
-	initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
-	initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
-
-	initq_info->producer_index_phys_addr_lo = instance->producer_h;
-	initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
-
-	init_frame->cmd = MFI_CMD_INIT;
-	init_frame->cmd_status = 0xFF;
-	init_frame->queue_info_new_phys_addr_lo = initq_info_h;
-
-	init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
-
-	/*
-	 * disable the intr before firing the init frame to FW
-	 */
-	instance->instancet->disable_intr(instance->reg_set);
-
-	/*
-	 * Issue the init frame in polled mode
-	 */
-	if (megasas_issue_polled(instance, cmd)) {
-		printk(KERN_DEBUG "megasas: Failed to init firmware\n");
+	if (megasas_issue_init_mfi(instance))
 		goto fail_fw_init;
-	}
-
-	megasas_return_cmd(instance, cmd);
 
 	ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
 
@@ -1958,17 +2050,20 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 	 * Note that older firmwares ( < FW ver 30) didn't report information
 	 * to calculate max_sectors_1. So the number ended up as zero always.
 	 */
+	tmp_sectors = 0;
 	if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) {
 
 		max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
 		    ctrl_info->max_strips_per_io;
 		max_sectors_2 = ctrl_info->max_request_size;
 
-		instance->max_sectors_per_req = (max_sectors_1 < max_sectors_2)
-		    ? max_sectors_1 : max_sectors_2;
-	} else
-		instance->max_sectors_per_req = instance->max_num_sge *
-		    PAGE_SIZE / 512;
+		tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
+	}
+
+	instance->max_sectors_per_req = instance->max_num_sge *
+						PAGE_SIZE / 512;
+	if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
+		instance->max_sectors_per_req = tmp_sectors;
 
 	kfree(ctrl_info);
 
@@ -1976,12 +2071,17 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 	* Setup tasklet for cmd completion
 	*/
 
-        tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
-                        (unsigned long)instance);
+	tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+		(unsigned long)instance);
+
+	/* Initialize the cmd completion timer */
+	if (poll_mode_io)
+		megasas_start_timer(instance, &instance->io_completion_timer,
+				megasas_io_completion_timer,
+				MEGASAS_COMPLETION_TIMER_INTERVAL);
 	return 0;
 
       fail_fw_init:
-	megasas_return_cmd(instance, cmd);
 
 	pci_free_consistent(instance->pdev, reply_q_sz,
 			    instance->reply_queue, instance->reply_queue_h);
@@ -2263,6 +2363,28 @@ static int megasas_io_attach(struct megasas_instance *instance)
 	return 0;
 }
 
+static int
+megasas_set_dma_mask(struct pci_dev *pdev)
+{
+	/*
+	 * All our contollers are capable of performing 64-bit DMA
+	 */
+	if (IS_DMA64) {
+		if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
+
+			if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
+				goto fail_set_dma_mask;
+		}
+	} else {
+		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
+			goto fail_set_dma_mask;
+	}
+	return 0;
+
+fail_set_dma_mask:
+	return 1;
+}
+
 /**
  * megasas_probe_one -	PCI hotplug entry point
  * @pdev:		PCI device structure
@@ -2296,19 +2418,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	pci_set_master(pdev);
 
-	/*
-	 * All our contollers are capable of performing 64-bit DMA
-	 */
-	if (IS_DMA64) {
-		if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
-
-			if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
-				goto fail_set_dma_mask;
-		}
-	} else {
-		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
-			goto fail_set_dma_mask;
-	}
+	if (megasas_set_dma_mask(pdev))
+		goto fail_set_dma_mask;
 
 	host = scsi_host_alloc(&megasas_template,
 			       sizeof(struct megasas_instance));
@@ -2357,8 +2468,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	init_waitqueue_head(&instance->abort_cmd_wait_q);
 
 	spin_lock_init(&instance->cmd_pool_lock);
+	spin_lock_init(&instance->completion_lock);
 
-	sema_init(&instance->aen_mutex, 1);
+	mutex_init(&instance->aen_mutex);
 	sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
 
 	/*
@@ -2490,8 +2602,10 @@ static void megasas_flush_cache(struct megasas_instance *instance)
 /**
  * megasas_shutdown_controller -	Instructs FW to shutdown the controller
  * @instance:				Adapter soft state
+ * @opcode:				Shutdown/Hibernate
  */
-static void megasas_shutdown_controller(struct megasas_instance *instance)
+static void megasas_shutdown_controller(struct megasas_instance *instance,
+					u32 opcode)
 {
 	struct megasas_cmd *cmd;
 	struct megasas_dcmd_frame *dcmd;
@@ -2514,7 +2628,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance)
 	dcmd->flags = MFI_FRAME_DIR_NONE;
 	dcmd->timeout = 0;
 	dcmd->data_xfer_len = 0;
-	dcmd->opcode = MR_DCMD_CTRL_SHUTDOWN;
+	dcmd->opcode = opcode;
 
 	megasas_issue_blocked_cmd(instance, cmd);
 
@@ -2524,6 +2638,139 @@ static void megasas_shutdown_controller(struct megasas_instance *instance)
 }
 
 /**
+ * megasas_suspend -	driver suspend entry point
+ * @pdev:		PCI device structure
+ * @state:		PCI power state to suspend routine
+ */
+static int __devinit
+megasas_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct Scsi_Host *host;
+	struct megasas_instance *instance;
+
+	instance = pci_get_drvdata(pdev);
+	host = instance->host;
+
+	if (poll_mode_io)
+		del_timer_sync(&instance->io_completion_timer);
+
+	megasas_flush_cache(instance);
+	megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
+	tasklet_kill(&instance->isr_tasklet);
+
+	pci_set_drvdata(instance->pdev, instance);
+	instance->instancet->disable_intr(instance->reg_set);
+	free_irq(instance->pdev->irq, instance);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+/**
+ * megasas_resume-      driver resume entry point
+ * @pdev:               PCI device structure
+ */
+static int __devinit
+megasas_resume(struct pci_dev *pdev)
+{
+	int rval;
+	struct Scsi_Host *host;
+	struct megasas_instance *instance;
+
+	instance = pci_get_drvdata(pdev);
+	host = instance->host;
+	pci_set_power_state(pdev, PCI_D0);
+	pci_enable_wake(pdev, PCI_D0, 0);
+	pci_restore_state(pdev);
+
+	/*
+	 * PCI prepping: enable device set bus mastering and dma mask
+	 */
+	rval = pci_enable_device(pdev);
+
+	if (rval) {
+		printk(KERN_ERR "megasas: Enable device failed\n");
+		return rval;
+	}
+
+	pci_set_master(pdev);
+
+	if (megasas_set_dma_mask(pdev))
+		goto fail_set_dma_mask;
+
+	/*
+	 * Initialize MFI Firmware
+	 */
+
+	*instance->producer = 0;
+	*instance->consumer = 0;
+
+	atomic_set(&instance->fw_outstanding, 0);
+
+	/*
+	 * We expect the FW state to be READY
+	 */
+	if (megasas_transition_to_ready(instance))
+		goto fail_ready_state;
+
+	if (megasas_issue_init_mfi(instance))
+		goto fail_init_mfi;
+
+	tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+			(unsigned long)instance);
+
+	/*
+	 * Register IRQ
+	 */
+	if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
+		"megasas", instance)) {
+		printk(KERN_ERR "megasas: Failed to register IRQ\n");
+		goto fail_irq;
+	}
+
+	instance->instancet->enable_intr(instance->reg_set);
+
+	/*
+	 * Initiate AEN (Asynchronous Event Notification)
+	 */
+	if (megasas_start_aen(instance))
+		printk(KERN_ERR "megasas: Start AEN failed\n");
+
+	/* Initialize the cmd completion timer */
+	if (poll_mode_io)
+		megasas_start_timer(instance, &instance->io_completion_timer,
+				megasas_io_completion_timer,
+				MEGASAS_COMPLETION_TIMER_INTERVAL);
+	return 0;
+
+fail_irq:
+fail_init_mfi:
+	if (instance->evt_detail)
+		pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+				instance->evt_detail,
+				instance->evt_detail_h);
+
+	if (instance->producer)
+		pci_free_consistent(pdev, sizeof(u32), instance->producer,
+				instance->producer_h);
+	if (instance->consumer)
+		pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+				instance->consumer_h);
+	scsi_host_put(host);
+
+fail_set_dma_mask:
+fail_ready_state:
+
+	pci_disable_device(pdev);
+
+	return -ENODEV;
+}
+
+/**
  * megasas_detach_one -	PCI hot"un"plug entry point
  * @pdev:		PCI device structure
  */
@@ -2536,9 +2783,12 @@ static void megasas_detach_one(struct pci_dev *pdev)
 	instance = pci_get_drvdata(pdev);
 	host = instance->host;
 
+	if (poll_mode_io)
+		del_timer_sync(&instance->io_completion_timer);
+
 	scsi_remove_host(instance->host);
 	megasas_flush_cache(instance);
-	megasas_shutdown_controller(instance);
+	megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
 	tasklet_kill(&instance->isr_tasklet);
 
 	/*
@@ -2660,6 +2910,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
 	void *sense = NULL;
 	dma_addr_t sense_handle;
 	u32 *sense_ptr;
+	unsigned long *sense_buff;
 
 	memset(kbuff_arr, 0, sizeof(kbuff_arr));
 
@@ -2764,14 +3015,16 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
 	 */
 	if (ioc->sense_len) {
 		/*
-		 * sense_ptr points to the location that has the user
+		 * sense_buff points to the location that has the user
 		 * sense buffer address
 		 */
-		sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw +
-				     ioc->sense_off);
+		sense_buff = (unsigned long *) ((unsigned long)ioc->frame.raw +
+								ioc->sense_off);
 
-		if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
-				 sense, ioc->sense_len)) {
+		if (copy_to_user((void __user *)(unsigned long)(*sense_buff),
+				sense, ioc->sense_len)) {
+			printk(KERN_ERR "megasas: Failed to copy out to user "
+					"sense data\n");
 			error = -EFAULT;
 			goto out;
 		}
@@ -2874,10 +3127,10 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
 	if (!instance)
 		return -ENODEV;
 
-	down(&instance->aen_mutex);
+	mutex_lock(&instance->aen_mutex);
 	error = megasas_register_aen(instance, aen.seq_num,
 				     aen.class_locale_word);
-	up(&instance->aen_mutex);
+	mutex_unlock(&instance->aen_mutex);
 	return error;
 }
 
@@ -2977,6 +3230,8 @@ static struct pci_driver megasas_pci_driver = {
 	.id_table = megasas_pci_table,
 	.probe = megasas_probe_one,
 	.remove = __devexit_p(megasas_detach_one),
+	.suspend = megasas_suspend,
+	.resume = megasas_resume,
 	.shutdown = megasas_shutdown,
 };
 
@@ -3004,7 +3259,7 @@ static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
 static ssize_t
 megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
 {
-	return sprintf(buf,"%u",megasas_dbg_lvl);
+	return sprintf(buf, "%u\n", megasas_dbg_lvl);
 }
 
 static ssize_t
@@ -3019,7 +3274,65 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun
 }
 
 static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
-		   megasas_sysfs_set_dbg_lvl);
+		megasas_sysfs_set_dbg_lvl);
+
+static ssize_t
+megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf)
+{
+	return sprintf(buf, "%u\n", poll_mode_io);
+}
+
+static ssize_t
+megasas_sysfs_set_poll_mode_io(struct device_driver *dd,
+				const char *buf, size_t count)
+{
+	int retval = count;
+	int tmp = poll_mode_io;
+	int i;
+	struct megasas_instance *instance;
+
+	if (sscanf(buf, "%u", &poll_mode_io) < 1) {
+		printk(KERN_ERR "megasas: could not set poll_mode_io\n");
+		retval = -EINVAL;
+	}
+
+	/*
+	 * Check if poll_mode_io is already set or is same as previous value
+	 */
+	if ((tmp && poll_mode_io) || (tmp == poll_mode_io))
+		goto out;
+
+	if (poll_mode_io) {
+		/*
+		 * Start timers for all adapters
+		 */
+		for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+			instance = megasas_mgmt_info.instance[i];
+			if (instance) {
+				megasas_start_timer(instance,
+					&instance->io_completion_timer,
+					megasas_io_completion_timer,
+					MEGASAS_COMPLETION_TIMER_INTERVAL);
+			}
+		}
+	} else {
+		/*
+		 * Delete timers for all adapters
+		 */
+		for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+			instance = megasas_mgmt_info.instance[i];
+			if (instance)
+				del_timer_sync(&instance->io_completion_timer);
+		}
+	}
+
+out:
+	return retval;
+}
+
+static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO,
+		megasas_sysfs_show_poll_mode_io,
+		megasas_sysfs_set_poll_mode_io);
 
 /**
  * megasas_init - Driver load entry point
@@ -3070,8 +3383,16 @@ static int __init megasas_init(void)
 				  &driver_attr_dbg_lvl);
 	if (rval)
 		goto err_dcf_dbg_lvl;
+	rval = driver_create_file(&megasas_pci_driver.driver,
+				  &driver_attr_poll_mode_io);
+	if (rval)
+		goto err_dcf_poll_mode_io;
 
 	return rval;
+
+err_dcf_poll_mode_io:
+	driver_remove_file(&megasas_pci_driver.driver,
+			   &driver_attr_dbg_lvl);
 err_dcf_dbg_lvl:
 	driver_remove_file(&megasas_pci_driver.driver,
 			   &driver_attr_release_date);
@@ -3090,6 +3411,8 @@ err_pcidrv:
 static void __exit megasas_exit(void)
 {
 	driver_remove_file(&megasas_pci_driver.driver,
+			   &driver_attr_poll_mode_io);
+	driver_remove_file(&megasas_pci_driver.driver,
 			   &driver_attr_dbg_lvl);
 	driver_remove_file(&megasas_pci_driver.driver,
 			   &driver_attr_release_date);
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 4dffc918a414..6466bdf548c2 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -2,7 +2,7 @@
  *
  *		Linux MegaRAID driver for SAS based RAID controllers
  *
- * Copyright (c) 2003-2005  LSI Logic Corporation.
+ * Copyright (c) 2003-2005  LSI Corporation.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -18,9 +18,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION				"00.00.03.10-rc5"
-#define MEGASAS_RELDATE				"May 17, 2007"
-#define MEGASAS_EXT_VERSION			"Thu May 17 10:09:32 PDT 2007"
+#define MEGASAS_VERSION				"00.00.03.16-rc1"
+#define MEGASAS_RELDATE				"Nov. 07, 2007"
+#define MEGASAS_EXT_VERSION			"Thu. Nov. 07 10:09:32 PDT 2007"
 
 /*
  * Device IDs
@@ -117,6 +117,7 @@
 #define MR_FLUSH_DISK_CACHE			0x02
 
 #define MR_DCMD_CTRL_SHUTDOWN			0x01050000
+#define MR_DCMD_HIBERNATE_SHUTDOWN		0x01060000
 #define MR_ENABLE_DRIVE_SPINDOWN		0x01
 
 #define MR_DCMD_CTRL_EVENT_GET_INFO		0x01040100
@@ -570,7 +571,8 @@ struct megasas_ctrl_info {
 #define IS_DMA64				(sizeof(dma_addr_t) == 8)
 
 #define MFI_OB_INTR_STATUS_MASK			0x00000002
-#define MFI_POLL_TIMEOUT_SECS			10
+#define MFI_POLL_TIMEOUT_SECS			60
+#define MEGASAS_COMPLETION_TIMER_INTERVAL      (HZ/10)
 
 #define MFI_REPLY_1078_MESSAGE_INTERRUPT	0x80000000
 
@@ -1083,13 +1085,15 @@ struct megasas_instance {
 	struct megasas_cmd **cmd_list;
 	struct list_head cmd_pool;
 	spinlock_t cmd_pool_lock;
+	/* used to synch producer, consumer ptrs in dpc */
+	spinlock_t completion_lock;
 	struct dma_pool *frame_dma_pool;
 	struct dma_pool *sense_dma_pool;
 
 	struct megasas_evt_detail *evt_detail;
 	dma_addr_t evt_detail_h;
 	struct megasas_cmd *aen_cmd;
-	struct semaphore aen_mutex;
+	struct mutex aen_mutex;
 	struct semaphore ioctl_sem;
 
 	struct Scsi_Host *host;
@@ -1108,6 +1112,8 @@ struct megasas_instance {
 
 	u8 flag;
 	unsigned long last_time;
+
+	struct timer_list io_completion_timer;
 };
 
 #define MEGASAS_IS_LOGICAL(scp)						\
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 7470ff39ab22..651d09b08f2a 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1843,7 +1843,6 @@ static struct scsi_host_template mesh_template = {
 	.sg_tablesize			= SG_ALL,
 	.cmd_per_lun			= 2,
 	.use_clustering			= DISABLE_CLUSTERING,
-	.use_sg_chaining		= ENABLE_SG_CHAINING,
 };
 
 static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 016c462bc771..c5ebf018b378 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -4963,10 +4963,11 @@ void ncr_complete (struct ncb *np, struct ccb *cp)
 		**	Copy back sense data to caller's buffer.
 		*/
 		memcpy(cmd->sense_buffer, cp->sense_buf,
-		       min(sizeof(cmd->sense_buffer), sizeof(cp->sense_buf)));
+		       min_t(size_t, SCSI_SENSE_BUFFERSIZE,
+			     sizeof(cp->sense_buf)));
 
 		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
-			u_char * p = (u_char*) & cmd->sense_buffer;
+			u_char *p = cmd->sense_buffer;
 			int i;
 			PRINT_ADDR(cmd, "sense data:");
 			for (i=0; i<14; i++) printk (" %x", *p++);
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 28161dc95e0d..7fed35372150 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -281,7 +281,6 @@ static struct scsi_host_template nsp32_template = {
 	.cmd_per_lun			= 1,
 	.this_id			= NSP32_HOST_SCSIID,
 	.use_clustering			= DISABLE_CLUSTERING,
-	.use_sg_chaining		= ENABLE_SG_CHAINING,
 	.eh_abort_handler       	= nsp32_eh_abort,
 	.eh_bus_reset_handler		= nsp32_eh_bus_reset,
 	.eh_host_reset_handler		= nsp32_eh_host_reset,
diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
index fa481b515ead..53857c6b6d4d 100644
--- a/drivers/scsi/pcmcia/Kconfig
+++ b/drivers/scsi/pcmcia/Kconfig
@@ -6,7 +6,8 @@ menuconfig SCSI_LOWLEVEL_PCMCIA
 	bool "PCMCIA SCSI adapter support"
 	depends on SCSI!=n && PCMCIA!=n
 
-if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA
+# drivers have problems when build in, so require modules
+if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA && m
 
 config PCMCIA_AHA152X
 	tristate "Adaptec AHA152X PCMCIA support"
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index a45d89b14147..5082ca3c6876 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -135,6 +135,11 @@ static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
 
 #define NSP_DEBUG_BUF_LEN		150
 
+static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc)
+{
+	scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc);
+}
+
 static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
 {
 	va_list args;
@@ -192,8 +197,10 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
 #endif
 	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
 
-	nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d",
-		   SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
+	nsp_dbg(NSP_DEBUG_QUEUECOMMAND,
+		"SCpnt=0x%p target=%d lun=%d sglist=0x%p bufflen=%d sg_count=%d",
+		SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt),
+		scsi_bufflen(SCpnt), scsi_sg_count(SCpnt));
 	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
 
 	SCpnt->scsi_done	= done;
@@ -225,7 +232,7 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
 	SCpnt->SCp.have_data_in = IO_UNKNOWN;
 	SCpnt->SCp.sent_command = 0;
 	SCpnt->SCp.phase	= PH_UNDETERMINED;
-	SCpnt->resid	        = SCpnt->request_bufflen;
+	scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
 
 	/* setup scratch area
 	   SCp.ptr		: buffer pointer
@@ -233,14 +240,14 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt,
 	   SCp.buffer		: next buffer
 	   SCp.buffers_residual : left buffers in list
 	   SCp.phase		: current state of the command */
-	if (SCpnt->use_sg) {
-		SCpnt->SCp.buffer	    = (struct scatterlist *) SCpnt->request_buffer;
+	if (scsi_bufflen(SCpnt)) {
+		SCpnt->SCp.buffer	    = scsi_sglist(SCpnt);
 		SCpnt->SCp.ptr		    = BUFFER_ADDR;
 		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
-		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+		SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
 	} else {
-		SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;
-		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+		SCpnt->SCp.ptr		    = NULL;
+		SCpnt->SCp.this_residual    = 0;
 		SCpnt->SCp.buffer	    = NULL;
 		SCpnt->SCp.buffers_residual = 0;
 	}
@@ -721,7 +728,9 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
 	ocount = data->FifoCount;
 
 	nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d",
-		SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
+		SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr,
+		SCpnt->SCp.this_residual, SCpnt->SCp.buffer,
+		SCpnt->SCp.buffers_residual);
 
 	time_out = 1000;
 
@@ -771,7 +780,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
 			return;
 		}
 
-		SCpnt->resid	       	 -= res;
+		nsp_inc_resid(SCpnt, -res);
 		SCpnt->SCp.ptr		 += res;
 		SCpnt->SCp.this_residual -= res;
 		ocount			 += res;
@@ -795,10 +804,12 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt)
 
 	if (time_out == 0) {
 		nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
-			SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
+			scsi_get_resid(SCpnt), SCpnt->SCp.this_residual,
+			SCpnt->SCp.buffers_residual);
 	}
 	nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
-	nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
+	nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId,
+	                                                scsi_get_resid(SCpnt));
 }
 
 /*
@@ -816,7 +827,9 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
 	ocount	 = data->FifoCount;
 
 	nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
-		data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
+		data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual,
+		SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual,
+		scsi_get_resid(SCpnt));
 
 	time_out = 1000;
 
@@ -830,7 +843,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
 
 			nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
 			/* Put back pointer */
-			SCpnt->resid	       	 += res;
+			nsp_inc_resid(SCpnt, res);
 			SCpnt->SCp.ptr		 -= res;
 			SCpnt->SCp.this_residual += res;
 			ocount			 -= res;
@@ -866,7 +879,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
 			break;
 		}
 
-		SCpnt->resid	       	 -= res;
+		nsp_inc_resid(SCpnt, -res);
 		SCpnt->SCp.ptr		 += res;
 		SCpnt->SCp.this_residual -= res;
 		ocount			 += res;
@@ -886,10 +899,12 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt)
 	data->FifoCount = ocount;
 
 	if (time_out == 0) {
-		nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid);
+		nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x",
+		                                        scsi_get_resid(SCpnt));
 	}
 	nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
-	nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
+	nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId,
+	                                                scsi_get_resid(SCpnt));
 }
 #undef RFIFO_CRIT
 #undef WFIFO_CRIT
@@ -911,9 +926,8 @@ static int nsp_nexus(struct scsi_cmnd *SCpnt)
 	nsp_index_write(base, SYNCREG,	sync->SyncRegister);
 	nsp_index_write(base, ACKWIDTH, sync->AckWidth);
 
-	if (SCpnt->use_sg    == 0        ||
-	    SCpnt->resid % 4 != 0        ||
-	    SCpnt->resid     <= PAGE_SIZE ) {
+	if (scsi_get_resid(SCpnt) % 4 != 0 ||
+	    scsi_get_resid(SCpnt) <= PAGE_SIZE ) {
 		data->TransferMode = MODE_IO8;
 	} else if (nsp_burst_mode == BURST_MEM32) {
 		data->TransferMode = MODE_MEM32;
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 969b9387a0c3..3454a5714749 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -692,7 +692,6 @@ static struct scsi_host_template sym53c500_driver_template = {
      .sg_tablesize		= 32,
      .cmd_per_lun		= 1,
      .use_clustering		= ENABLE_CLUSTERING,
-     .use_sg_chaining		= ENABLE_SG_CHAINING,
      .shost_attrs		= SYM53C500_shost_attrs
 };
 
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 67ee51a3d7e1..f655ae320b48 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -750,18 +750,16 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
 		cmd->SCp.phase++;
 
 	case 4:		/* Phase 4 - Setup scatter/gather buffers */
-		if (cmd->use_sg) {
-			/* if many buffers are available, start filling the first */
-			cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+		if (scsi_bufflen(cmd)) {
+			cmd->SCp.buffer = scsi_sglist(cmd);
 			cmd->SCp.this_residual = cmd->SCp.buffer->length;
 			cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
 		} else {
-			/* else fill the only available buffer */
 			cmd->SCp.buffer = NULL;
-			cmd->SCp.this_residual = cmd->request_bufflen;
-			cmd->SCp.ptr = cmd->request_buffer;
+			cmd->SCp.this_residual = 0;
+			cmd->SCp.ptr = NULL;
 		}
-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
 		cmd->SCp.phase++;
 
 	case 5:		/* Phase 5 - Data transfer stage */
diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
deleted file mode 100644
index 899e89d6fe67..000000000000
--- a/drivers/scsi/psi240i.c
+++ /dev/null
@@ -1,689 +0,0 @@
-/*+M*************************************************************************
- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
- *
- * Copyright (c) 1997 Perceptive Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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.
- *
- *
- *	File Name:		psi240i.c
- *
- *	Description:	SCSI driver for the PSI240I EIDE interface card.
- *
- *-M*************************************************************************/
-
-#include <linux/module.h>
-
-#include <linux/blkdev.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/stat.h>
-
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-
-#include "psi240i.h"
-#include "psi_chip.h"
-
-//#define DEBUG 1
-
-#ifdef DEBUG
-#define DEB(x) x
-#else
-#define DEB(x)
-#endif
-
-#define MAXBOARDS 6	/* Increase this and the sizes of the arrays below, if you need more. */
-
-#define	PORT_DATA				0
-#define	PORT_ERROR				1
-#define	PORT_SECTOR_COUNT		2
-#define	PORT_LBA_0				3
-#define	PORT_LBA_8				4
-#define	PORT_LBA_16				5
-#define	PORT_LBA_24				6
-#define	PORT_STAT_CMD			7
-#define	PORT_SEL_FAIL			8
-#define	PORT_IRQ_STATUS			9
-#define	PORT_ADDRESS			10
-#define	PORT_FAIL				11
-#define	PORT_ALT_STAT		   	12
-
-typedef struct
-	{
-	UCHAR		   	device;				// device code
-	UCHAR			byte6;				// device select register image
-	UCHAR			spigot;				// spigot number
-	UCHAR			expectingIRQ;		// flag for expecting and interrupt
-	USHORT			sectors;			// number of sectors per track
-	USHORT			heads;				// number of heads
-	USHORT			cylinders;			// number of cylinders for this device
-	USHORT			spareword;			// placeholder
-	ULONG			blocks;				// number of blocks on device
-	}	OUR_DEVICE, *POUR_DEVICE;
-
-typedef struct
-	{
-	USHORT		 ports[13];
-	OUR_DEVICE	 device[8];
-	struct scsi_cmnd *pSCmnd;
-	IDE_STRUCT	 ide;
-	ULONG		 startSector;
-	USHORT		 sectorCount;
-	struct scsi_cmnd *SCpnt;
-	VOID		*buffer;
-	USHORT		 expectingIRQ;
-	}	ADAPTER240I, *PADAPTER240I;
-
-#define HOSTDATA(host) ((PADAPTER240I)&host->hostdata)
-
-static struct	Scsi_Host *PsiHost[6] = {NULL,};  /* One for each IRQ level (10-15) */
-static			IDENTIFY_DATA	identifyData;
-static			SETUP			ChipSetup;
-
-static	USHORT	portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5};
-
-/****************************************************************
- *	Name:	WriteData	:LOCAL
- *
- *	Description:	Write data to device.
- *
- *	Parameters:		padapter - Pointer adapter data structure.
- *
- *	Returns:		TRUE if drive does not assert DRQ in time.
- *
- ****************************************************************/
-static int WriteData (PADAPTER240I padapter)
-	{
-	ULONG	timer;
-	USHORT *pports = padapter->ports;
-
-	timer = jiffies + TIMEOUT_DRQ;								// calculate the timeout value
-	do  {
-		if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
-			{
-			outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256);
-			return 0;
-			}
-		}	while ( time_after(timer, jiffies) );									// test for timeout
-
-	padapter->ide.ide.ides.cmd = 0;									// null out the command byte
-	return 1;
-	}
-/****************************************************************
- *	Name:	IdeCmd	:LOCAL
- *
- *	Description:	Process a queued command from the SCSI manager.
- *
- *	Parameters:		padapter - Pointer adapter data structure.
- *
- *	Returns:		Zero if no error or status register contents on error.
- *
- ****************************************************************/
-static UCHAR IdeCmd (PADAPTER240I padapter)
-	{
-	ULONG	timer;
-	USHORT *pports = padapter->ports;
-	UCHAR	status;
-
-	outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]);	// select the spigot
-	outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]);			// select the drive
-	timer = jiffies + TIMEOUT_READY;							// calculate the timeout value
-	do  {
-		status = inb_p (padapter->ports[PORT_STAT_CMD]);
-		if ( status & IDE_STATUS_DRDY )
-			{
-			outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
-			outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
-			outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
-			outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
-			padapter->expectingIRQ = 1;
-			outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
-
-			if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
-				return (WriteData (padapter));
-
-			return 0;
-			}
-		}	while ( time_after(timer, jiffies) );									// test for timeout
-
-	padapter->ide.ide.ides.cmd = 0;									// null out the command byte
-	return status;
-	}
-/****************************************************************
- *	Name:	SetupTransfer	:LOCAL
- *
- *	Description:	Setup a data transfer command.
- *
- *	Parameters:		padapter - Pointer adapter data structure.
- *					drive	 - Drive/head register upper nibble only.
- *
- *	Returns:		TRUE if no data to transfer.
- *
- ****************************************************************/
-static int SetupTransfer (PADAPTER240I padapter, UCHAR drive)
-	{
-	if ( padapter->sectorCount )
-		{
-		*(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
-		padapter->ide.ide.ide[6] |= drive;
-		padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
-		padapter->sectorCount -= padapter->ide.ide.ides.sectors;	// bump the start and count for next xfer
-		padapter->startSector += padapter->ide.ide.ides.sectors;
-		return 0;
-		}
-	else
-		{
-		padapter->ide.ide.ides.cmd = 0;								// null out the command byte
-		padapter->SCpnt = NULL;
-		return 1;
-		}
-	}
-/****************************************************************
- *	Name:	DecodeError	:LOCAL
- *
- *	Description:	Decode and process device errors.
- *
- *	Parameters:		pshost - Pointer to host data block.
- *					status - Status register code.
- *
- *	Returns:		The driver status code.
- *
- ****************************************************************/
-static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
-	{
-	PADAPTER240I	padapter = HOSTDATA(pshost);
-	UCHAR			error;
-
-	padapter->expectingIRQ = 0;
-	padapter->SCpnt = NULL;
-	if ( status & IDE_STATUS_WRITE_FAULT )
-		{
-		return DID_PARITY << 16;
-		}
-	if ( status & IDE_STATUS_BUSY )
-		return DID_BUS_BUSY << 16;
-
-	error = inb_p (padapter->ports[PORT_ERROR]);
-	DEB(printk ("\npsi240i error register: %x", error));
-	switch ( error )
-		{
-		case IDE_ERROR_AMNF:
-		case IDE_ERROR_TKONF:
-		case IDE_ERROR_ABRT:
-		case IDE_ERROR_IDFN:
-		case IDE_ERROR_UNC:
-		case IDE_ERROR_BBK:
-		default:
-			return DID_ERROR << 16;
-		}
-	return DID_ERROR << 16;
-	}
-/****************************************************************
- *	Name:	Irq_Handler	:LOCAL
- *
- *	Description:	Interrupt handler.
- *
- *	Parameters:		irq		- Hardware IRQ number.
- *					dev_id	-
- *
- *	Returns:		TRUE if drive is not ready in time.
- *
- ****************************************************************/
-static void Irq_Handler (int irq, void *dev_id)
-	{
-	struct Scsi_Host *shost;	// Pointer to host data block
-	PADAPTER240I padapter;		// Pointer to adapter control structure
-	USHORT *pports;			// I/O port array
-	struct scsi_cmnd *SCpnt;
-	UCHAR status;
-	int z;
-
-	DEB(printk ("\npsi240i received interrupt\n"));
-
-	shost = PsiHost[irq - 10];
-	if ( !shost )
-		panic ("Splunge!");
-
-	padapter = HOSTDATA(shost);
-	pports = padapter->ports;
-	SCpnt = padapter->SCpnt;
-
-	if ( !padapter->expectingIRQ )
-		{
-		DEB(printk ("\npsi240i Unsolicited interrupt\n"));
-		return;
-		}
-	padapter->expectingIRQ = 0;
-
-	status = inb_p (padapter->ports[PORT_STAT_CMD]);			// read the device status
-	if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
-		goto irqerror;
-
-	DEB(printk ("\npsi240i processing interrupt"));
-	switch ( padapter->ide.ide.ides.cmd )							// decide how to handle the interrupt
-		{
-		case IDE_CMD_READ_MULTIPLE:
-			if ( status & IDE_STATUS_DRQ )
-				{
-				insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256);
-				padapter->buffer += padapter->ide.ide.ides.sectors * 512;
-				if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
-					{
-					SCpnt->result = DID_OK << 16;
-					padapter->SCpnt = NULL;
-					SCpnt->scsi_done (SCpnt);
-					return;
-					}
-				if ( !(status = IdeCmd (padapter)) )
-					return;
-				}
-			break;
-
-		case IDE_CMD_WRITE_MULTIPLE:
-			padapter->buffer += padapter->ide.ide.ides.sectors * 512;
-			if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
-				{
-				SCpnt->result = DID_OK << 16;
-				padapter->SCpnt = NULL;
-				SCpnt->scsi_done (SCpnt);
-				return;
-				}
-			if ( !(status = IdeCmd (padapter)) )
-				return;
-			break;
-
-		case IDE_COMMAND_IDENTIFY:
-			{
-			PINQUIRYDATA	pinquiryData  = SCpnt->request_buffer;
-
-			if ( status & IDE_STATUS_DRQ )
-				{
-				insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
-
-				memset (pinquiryData, 0, SCpnt->request_bufflen);		// Zero INQUIRY data structure.
-				pinquiryData->DeviceType = 0;
-				pinquiryData->Versions = 2;
-				pinquiryData->AdditionalLength = 35 - 4;
-
-				// Fill in vendor identification fields.
-				for ( z = 0;  z < 8;  z += 2 )
-					{
-					pinquiryData->VendorId[z]	  = ((UCHAR *)identifyData.ModelNumber)[z + 1];
-					pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
-					}
-
-				// Initialize unused portion of product id.
-				for ( z = 0;  z < 4;  z++ )
-					pinquiryData->ProductId[12 + z] = ' ';
-
-				// Move firmware revision from IDENTIFY data to
-				// product revision in INQUIRY data.
-				for ( z = 0;  z < 4;  z += 2 )
-					{
-					pinquiryData->ProductRevisionLevel[z]	 = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
-					pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
-					}
-
-				SCpnt->result = DID_OK << 16;
-				padapter->SCpnt = NULL;
-				SCpnt->scsi_done (SCpnt);
-				return;
-				}
-			break;
-			}
-
-		default:
-			SCpnt->result = DID_OK << 16;
-			padapter->SCpnt = NULL;
-			SCpnt->scsi_done (SCpnt);
-			return;
-		}
-
-irqerror:;
-	DEB(printk ("\npsi240i error  Device Status: %X\n", status));
-	SCpnt->result = DecodeError (shost, status);
-	SCpnt->scsi_done (SCpnt);
-	}
-
-static irqreturn_t do_Irq_Handler (int irq, void *dev_id)
-{
-	unsigned long flags;
-	struct Scsi_Host *dev = dev_id;
-	
-	spin_lock_irqsave(dev->host_lock, flags);
-	Irq_Handler(irq, dev_id);
-	spin_unlock_irqrestore(dev->host_lock, flags);
-	return IRQ_HANDLED;
-}
-
-/****************************************************************
- *	Name:	Psi240i_QueueCommand
- *
- *	Description:	Process a queued command from the SCSI manager.
- *
- *	Parameters:		SCpnt - Pointer to SCSI command structure.
- *					done  - Pointer to done function to call.
- *
- *	Returns:		Status code.
- *
- ****************************************************************/
-static int Psi240i_QueueCommand(struct scsi_cmnd *SCpnt,
-				void (*done)(struct scsi_cmnd *))
-	{
-	UCHAR *cdb = (UCHAR *)SCpnt->cmnd;
-	// Pointer to SCSI CDB
-	PADAPTER240I padapter = HOSTDATA (SCpnt->device->host);
-	// Pointer to adapter control structure
-	POUR_DEVICE pdev = &padapter->device [SCpnt->device->id];
-	// Pointer to device information
-	UCHAR rc;
-	// command return code
-
-	SCpnt->scsi_done = done;
-	padapter->ide.ide.ides.spigot = pdev->spigot;
-	padapter->buffer = SCpnt->request_buffer;
-	if (done)
-		{
-		if ( !pdev->device )
-			{
-			SCpnt->result = DID_BAD_TARGET << 16;
-			done (SCpnt);
-			return 0;
-			}
-		}
-	else
-		{
-		printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);
-		return 0;
-		}
-
-	switch ( *cdb )
-		{
-		case SCSIOP_INQUIRY:   					// inquiry CDB
-			{
-			padapter->ide.ide.ide[6] = pdev->byte6;
-			padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
-			break;
-			}
-
-		case SCSIOP_TEST_UNIT_READY:			// test unit ready CDB
-			SCpnt->result = DID_OK << 16;
-			done (SCpnt);
-			return 0;
-
-		case SCSIOP_READ_CAPACITY:			  	// read capctiy CDB
-			{
-			PREAD_CAPACITY_DATA	pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
-
-			pdata->blksiz = 0x20000;
-			XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
-			SCpnt->result = DID_OK << 16;
-			done (SCpnt);
-			return 0;
-			}
-
-		case SCSIOP_VERIFY:						// verify CDB
-			*(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
-			padapter->ide.ide.ide[6] |= pdev->byte6;
-			padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
-			padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
-			break;
-
-		case SCSIOP_READ:						// read10 CDB
-			padapter->startSector = XSCSI2LONG (&cdb[2]);
-			padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
-			SetupTransfer (padapter, pdev->byte6);
-			padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
-			break;
-
-		case SCSIOP_READ6:						// read6  CDB
-			padapter->startSector = SCSI2LONG (&cdb[1]);
-			padapter->sectorCount = cdb[4];
-			SetupTransfer (padapter, pdev->byte6);
-			padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
-			break;
-
-		case SCSIOP_WRITE:						// write10 CDB
-			padapter->startSector = XSCSI2LONG (&cdb[2]);
-			padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
-			SetupTransfer (padapter, pdev->byte6);
-			padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
-			break;
-		case SCSIOP_WRITE6:						// write6  CDB
-			padapter->startSector = SCSI2LONG (&cdb[1]);
-			padapter->sectorCount = cdb[4];
-			SetupTransfer (padapter, pdev->byte6);
-			padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
-			break;
-
-		default:
-			DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
-			SCpnt->result = DID_ERROR << 16;
-			done (SCpnt);
-			return 0;
-		}
-
-	padapter->SCpnt = SCpnt;  									// Save this command data
-
-	rc = IdeCmd (padapter);
-	if ( rc )
-		{
-		padapter->expectingIRQ = 0;
-		DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
-		SCpnt->result = DID_ERROR << 16;
-		done (SCpnt);
-		return 0;
-		}
-	DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));
-	return 0;
-	}
-
-/***************************************************************************
- *	Name:			ReadChipMemory
- *
- *	Description:	Read information from controller memory.
- *
- *	Parameters:		psetup	- Pointer to memory image of setup information.
- *					base	- base address of memory.
- *					length	- lenght of data space in bytes.
- *					port	- I/O address of data port.
- *
- *	Returns:		Nothing.
- *
- **************************************************************************/
-static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
-	{
-	USHORT	z, zz;
-	UCHAR	*pd = (UCHAR *)pdata;
-	outb_p (SEL_NONE, port + REG_SEL_FAIL);				// setup data port
-	zz = 0;
-	while ( zz < length )
-		{
-		outw_p (base, port + REG_ADDRESS);				// setup address
-
-		for ( z = 0;  z < 8;  z++ )
-			{
-			if ( (zz + z) < length )
-			*pd++ = inb_p (port + z);	// read data byte
-			}
-		zz += 8;
-		base += 8;
-		}
-	}
-/****************************************************************
- *	Name:	Psi240i_Detect
- *
- *	Description:	Detect and initialize our boards.
- *
- *	Parameters:		tpnt - Pointer to SCSI host template structure.
- *
- *	Returns:		Number of adapters found.
- *
- ****************************************************************/
-static int Psi240i_Detect (struct scsi_host_template *tpnt)
-	{
-	int					board;
-	int					count = 0;
-	int					unit;
-	int					z;
-	USHORT				port, port_range = 16;
-	CHIP_CONFIG_N		chipConfig;
-	CHIP_DEVICE_N		chipDevice[8];
-	struct Scsi_Host   *pshost;
-
-	for ( board = 0;  board < MAXBOARDS;  board++ )					// scan for I/O ports
-		{
-		pshost = NULL;
-		port = portAddr[board];								// get base address to test
-		if ( !request_region (port, port_range, "psi240i") )
-			continue;
-		if ( inb_p (port + REG_FAIL) != CHIP_ID )			// do the first test for likley hood that it is us
-			goto host_init_failure;
-		outb_p (SEL_NONE, port + REG_SEL_FAIL);				// setup EEPROM/RAM access
-		outw (0, port + REG_ADDRESS);						// setup EEPROM address zero
-		if ( inb_p (port) != 0x55 )							// test 1st byte
-			goto host_init_failure;									//   nope
-		if ( inb_p (port + 1) != 0xAA )						// test 2nd byte
-			goto host_init_failure;								//   nope
-
-		// at this point our board is found and can be accessed.  Now we need to initialize
-		// our informatation and register with the kernel.
-
-
-		ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port);
-		ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port);
-		ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port);
-
-		if ( !chipConfig.numDrives )						// if no devices on this board
-			goto host_init_failure;
-
-		pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
-		if(pshost == NULL)
-			goto host_init_failure;	
-
-		PsiHost[chipConfig.irq - 10] = pshost;
-		pshost->unique_id = port;
-		pshost->io_port = port;
-		pshost->n_io_port = 16;  /* Number of bytes of I/O space used */
-		pshost->irq = chipConfig.irq;
-
-		for ( z = 0;  z < 11;  z++ )						// build regester address array
-			HOSTDATA(pshost)->ports[z] = port + z;
-		HOSTDATA(pshost)->ports[11] = port + REG_FAIL;
-		HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT;
-		DEB (printk ("\nPorts ="));
-		DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]););
-
-		for ( z = 0;  z < chipConfig.numDrives;  ++z )
-			{
-			unit = chipDevice[z].channel & 0x0F;
-			HOSTDATA(pshost)->device[unit].device	 = ChipSetup.setupDevice[unit].device;
-			HOSTDATA(pshost)->device[unit].byte6	 = (UCHAR)(((unit & 1) << 4) | 0xE0);
-			HOSTDATA(pshost)->device[unit].spigot	 = (UCHAR)(1 << (unit >> 1));
-			HOSTDATA(pshost)->device[unit].sectors	 = ChipSetup.setupDevice[unit].sectors;
-			HOSTDATA(pshost)->device[unit].heads	 = ChipSetup.setupDevice[unit].heads;
-			HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders;
-			HOSTDATA(pshost)->device[unit].blocks	 = ChipSetup.setupDevice[unit].blocks;
-			DEB (printk ("\nHOSTDATA->device    = %X", HOSTDATA(pshost)->device[unit].device));
-			DEB (printk ("\n          byte6     = %X", HOSTDATA(pshost)->device[unit].byte6));
-			DEB (printk ("\n          spigot    = %X", HOSTDATA(pshost)->device[unit].spigot));
-			DEB (printk ("\n          sectors   = %X", HOSTDATA(pshost)->device[unit].sectors));
-			DEB (printk ("\n          heads     = %X", HOSTDATA(pshost)->device[unit].heads));
-			DEB (printk ("\n          cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders));
-			DEB (printk ("\n          blocks    = %lX", HOSTDATA(pshost)->device[unit].blocks));
-			}
-
-		if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 ) 
-			{
-			printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x  IRQ = %d\n", port, chipConfig.irq);
-		        printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
-		        count++;
-		        continue;
-			}
-
-		printk ("Unable to allocate IRQ for PSI-240I controller.\n");
-           
-host_init_failure:
-		
-		release_region (port, port_range);
-		if (pshost)
-			scsi_unregister (pshost);
-
-		}
-	return count;
-	}
-
-static int Psi240i_Release(struct Scsi_Host *shost)
-{
-	if (shost->irq)
-		free_irq(shost->irq, NULL);
-	if (shost->io_port && shost->n_io_port)
-		release_region(shost->io_port, shost->n_io_port);
-	scsi_unregister(shost);
-	return 0;
-}
-
-/****************************************************************
- *	Name:	Psi240i_BiosParam
- *
- *	Description:	Process the biosparam request from the SCSI manager to
- *					return C/H/S data.
- *
- *	Parameters:		disk - Pointer to SCSI disk structure.
- *					dev	 - Major/minor number from kernel.
- *					geom - Pointer to integer array to place geometry data.
- *
- *	Returns:		zero.
- *
- ****************************************************************/
-static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
-		sector_t capacity, int geom[])
-	{
-	POUR_DEVICE	pdev;
-
-	pdev = &(HOSTDATA(sdev->host)->device[sdev_id(sdev)]);
-
-	geom[0] = pdev->heads;
-	geom[1] = pdev->sectors;
-	geom[2] = pdev->cylinders;
-	return 0;
-	}
-
-MODULE_LICENSE("GPL");
-
-static struct scsi_host_template driver_template = {
-	.proc_name		= "psi240i", 
-	.name			= "PSI-240I EIDE Disk Controller",
-	.detect			= Psi240i_Detect,
-	.release		= Psi240i_Release,
-	.queuecommand		= Psi240i_QueueCommand,
-	.bios_param	  	= Psi240i_BiosParam,
-	.can_queue	  	= 1,
-	.this_id	  	= -1,
-	.sg_tablesize	  	= SG_NONE,
-	.cmd_per_lun	  	= 1, 
-	.use_clustering		= DISABLE_CLUSTERING,
-};
-#include "scsi_module.c"
diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
deleted file mode 100644
index 21ebb9214004..000000000000
--- a/drivers/scsi/psi240i.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/*+M*************************************************************************
- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
- *
- * Copyright (c) 1997 Perceptive Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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.
- *
- *
- *	File Name:		psi240i.h
- *
- *	Description:	Header file for the SCSI driver for the PSI240I
- *					EIDE interface card.
- *
- *-M*************************************************************************/
-#ifndef _PSI240I_H
-#define _PSI240I_H
-
-#include <linux/types.h>
-
-#ifndef	PSI_EIDE_SCSIOP
-#define	PSI_EIDE_SCSIOP	1
-
-/************************************************/
-/*		Some defines that we like 				*/
-/************************************************/
-#define	CHAR		char
-#define	UCHAR		unsigned char
-#define	SHORT		short
-#define	USHORT		unsigned short
-#define	BOOL		unsigned short
-#define	LONG		long
-#define	ULONG		unsigned long
-#define	VOID		void
-
-/************************************************/
-/*		Timeout konstants		 				*/
-/************************************************/
-#define	TIMEOUT_READY				10		// 100 mSec
-#define	TIMEOUT_DRQ					40		// 400 mSec
-
-/************************************************/
-/*		Misc. macros			 				*/
-/************************************************/
-#define ANY2SCSI(up, p)					\
-((UCHAR *)up)[0] = (((ULONG)(p)) >> 8);	\
-((UCHAR *)up)[1] = ((ULONG)(p));
-
-#define SCSI2LONG(up)					\
-( (((long)*(((UCHAR *)up))) << 16)		\
-+ (((long)(((UCHAR *)up)[1])) << 8)		\
-+ ((long)(((UCHAR *)up)[2])) )
-
-#define XANY2SCSI(up, p)				\
-((UCHAR *)up)[0] = ((long)(p)) >> 24;	\
-((UCHAR *)up)[1] = ((long)(p)) >> 16;	\
-((UCHAR *)up)[2] = ((long)(p)) >> 8;	\
-((UCHAR *)up)[3] = ((long)(p));
-
-#define XSCSI2LONG(up)					\
-( (((long)(((UCHAR *)up)[0])) << 24)	\
-+ (((long)(((UCHAR *)up)[1])) << 16)	\
-+ (((long)(((UCHAR *)up)[2])) <<  8)	\
-+ ((long)(((UCHAR *)up)[3])) )
-
-/************************************************/
-/*		SCSI CDB operation codes 				*/
-/************************************************/
-#define SCSIOP_TEST_UNIT_READY		0x00
-#define SCSIOP_REZERO_UNIT			0x01
-#define SCSIOP_REWIND				0x01
-#define SCSIOP_REQUEST_BLOCK_ADDR	0x02
-#define SCSIOP_REQUEST_SENSE		0x03
-#define SCSIOP_FORMAT_UNIT			0x04
-#define SCSIOP_READ_BLOCK_LIMITS	0x05
-#define SCSIOP_REASSIGN_BLOCKS		0x07
-#define SCSIOP_READ6				0x08
-#define SCSIOP_RECEIVE				0x08
-#define SCSIOP_WRITE6				0x0A
-#define SCSIOP_PRINT				0x0A
-#define SCSIOP_SEND					0x0A
-#define SCSIOP_SEEK6				0x0B
-#define SCSIOP_TRACK_SELECT			0x0B
-#define SCSIOP_SLEW_PRINT			0x0B
-#define SCSIOP_SEEK_BLOCK			0x0C
-#define SCSIOP_PARTITION			0x0D
-#define SCSIOP_READ_REVERSE			0x0F
-#define SCSIOP_WRITE_FILEMARKS		0x10
-#define SCSIOP_FLUSH_BUFFER			0x10
-#define SCSIOP_SPACE				0x11
-#define SCSIOP_INQUIRY				0x12
-#define SCSIOP_VERIFY6				0x13
-#define SCSIOP_RECOVER_BUF_DATA		0x14
-#define SCSIOP_MODE_SELECT			0x15
-#define SCSIOP_RESERVE_UNIT			0x16
-#define SCSIOP_RELEASE_UNIT			0x17
-#define SCSIOP_COPY					0x18
-#define SCSIOP_ERASE				0x19
-#define SCSIOP_MODE_SENSE			0x1A
-#define SCSIOP_START_STOP_UNIT		0x1B
-#define SCSIOP_STOP_PRINT			0x1B
-#define SCSIOP_LOAD_UNLOAD			0x1B
-#define SCSIOP_RECEIVE_DIAGNOSTIC	0x1C
-#define SCSIOP_SEND_DIAGNOSTIC		0x1D
-#define SCSIOP_MEDIUM_REMOVAL		0x1E
-#define SCSIOP_READ_CAPACITY		0x25
-#define SCSIOP_READ					0x28
-#define SCSIOP_WRITE				0x2A
-#define SCSIOP_SEEK					0x2B
-#define SCSIOP_LOCATE				0x2B
-#define SCSIOP_WRITE_VERIFY			0x2E
-#define SCSIOP_VERIFY				0x2F
-#define SCSIOP_SEARCH_DATA_HIGH		0x30
-#define SCSIOP_SEARCH_DATA_EQUAL	0x31
-#define SCSIOP_SEARCH_DATA_LOW		0x32
-#define SCSIOP_SET_LIMITS			0x33
-#define SCSIOP_READ_POSITION		0x34
-#define SCSIOP_SYNCHRONIZE_CACHE	0x35
-#define SCSIOP_COMPARE				0x39
-#define SCSIOP_COPY_COMPARE			0x3A
-#define SCSIOP_WRITE_DATA_BUFF		0x3B
-#define SCSIOP_READ_DATA_BUFF		0x3C
-#define SCSIOP_CHANGE_DEFINITION	0x40
-#define SCSIOP_READ_SUB_CHANNEL		0x42
-#define SCSIOP_READ_TOC				0x43
-#define SCSIOP_READ_HEADER			0x44
-#define SCSIOP_PLAY_AUDIO			0x45
-#define SCSIOP_PLAY_AUDIO_MSF		0x47
-#define SCSIOP_PLAY_TRACK_INDEX		0x48
-#define SCSIOP_PLAY_TRACK_RELATIVE	0x49
-#define SCSIOP_PAUSE_RESUME			0x4B
-#define SCSIOP_LOG_SELECT			0x4C
-#define SCSIOP_LOG_SENSE			0x4D
-#define SCSIOP_MODE_SELECT10		0x55
-#define SCSIOP_MODE_SENSE10			0x5A
-#define SCSIOP_LOAD_UNLOAD_SLOT		0xA6
-#define SCSIOP_MECHANISM_STATUS		0xBD
-#define SCSIOP_READ_CD				0xBE
-
-// IDE command definitions
-#define IDE_COMMAND_ATAPI_RESET		0x08
-#define IDE_COMMAND_READ			0x20
-#define IDE_COMMAND_WRITE			0x30
-#define IDE_COMMAND_RECALIBRATE		0x10
-#define IDE_COMMAND_SEEK			0x70
-#define IDE_COMMAND_SET_PARAMETERS	0x91
-#define IDE_COMMAND_VERIFY			0x40
-#define IDE_COMMAND_ATAPI_PACKET	0xA0
-#define IDE_COMMAND_ATAPI_IDENTIFY	0xA1
-#define	IDE_CMD_READ_MULTIPLE		0xC4
-#define	IDE_CMD_WRITE_MULTIPLE		0xC5
-#define	IDE_CMD_SET_MULTIPLE		0xC6
-#define IDE_COMMAND_WRITE_DMA		0xCA
-#define IDE_COMMAND_READ_DMA		0xC8
-#define IDE_COMMAND_IDENTIFY		0xEC
-
-// IDE status definitions
-#define IDE_STATUS_ERROR			0x01
-#define IDE_STATUS_INDEX			0x02
-#define IDE_STATUS_CORRECTED_ERROR	0x04
-#define IDE_STATUS_DRQ				0x08
-#define IDE_STATUS_DSC				0x10
-#define	IDE_STATUS_WRITE_FAULT		0x20
-#define IDE_STATUS_DRDY				0x40
-#define IDE_STATUS_BUSY				0x80
-
-// IDE error definitions
-#define	IDE_ERROR_AMNF				0x01
-#define	IDE_ERROR_TKONF				0x02
-#define	IDE_ERROR_ABRT				0x04
-#define	IDE_ERROR_MCR				0x08
-#define	IDE_ERROR_IDFN				0x10
-#define	IDE_ERROR_MC				0x20
-#define	IDE_ERROR_UNC				0x40
-#define	IDE_ERROR_BBK				0x80
-
-//	IDE interface structure
-typedef struct _IDE_STRUCT
-	{
-	union
-		{
-		UCHAR	ide[9];
-		struct
-			{
-			USHORT	data;
-			UCHAR	sectors;
-			UCHAR	lba[4];
-			UCHAR	cmd;
-			UCHAR	spigot;
-			}	ides;
-		} ide;
-	}	IDE_STRUCT;
-
-// SCSI read capacity structure
-typedef	struct _READ_CAPACITY_DATA
-	{
-	ULONG blks;				/* total blocks (converted to little endian) */
-	ULONG blksiz;			/* size of each (converted to little endian) */
-	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
-
-// SCSI inquiry data
-#ifndef HOSTS_C
-
-typedef struct _INQUIRYDATA
-	{
-	UCHAR DeviceType			:5;
-	UCHAR DeviceTypeQualifier	:3;
-	UCHAR DeviceTypeModifier	:7;
-	UCHAR RemovableMedia		:1;
-    UCHAR Versions;
-    UCHAR ResponseDataFormat;
-    UCHAR AdditionalLength;
-    UCHAR Reserved[2];
-	UCHAR SoftReset				:1;
-	UCHAR CommandQueue			:1;
-	UCHAR Reserved2				:1;
-	UCHAR LinkedCommands		:1;
-	UCHAR Synchronous			:1;
-	UCHAR Wide16Bit				:1;
-	UCHAR Wide32Bit				:1;
-	UCHAR RelativeAddressing	:1;
-    UCHAR VendorId[8];
-    UCHAR ProductId[16];
-    UCHAR ProductRevisionLevel[4];
-    UCHAR VendorSpecific[20];
-    UCHAR Reserved3[40];
-	}	INQUIRYDATA, *PINQUIRYDATA;
-#endif
-
-// IDE IDENTIFY data
-typedef struct _IDENTIFY_DATA
-	{
-    USHORT GeneralConfiguration;            // 00
-    USHORT NumberOfCylinders;               // 02
-    USHORT Reserved1;                       // 04
-    USHORT NumberOfHeads;                   // 06
-    USHORT UnformattedBytesPerTrack;        // 08
-    USHORT UnformattedBytesPerSector;       // 0A
-    USHORT SectorsPerTrack;                 // 0C
-    USHORT VendorUnique1[3];                // 0E
-    USHORT SerialNumber[10];                // 14
-    USHORT BufferType;                      // 28
-    USHORT BufferSectorSize;                // 2A
-    USHORT NumberOfEccBytes;                // 2C
-    USHORT FirmwareRevision[4];             // 2E
-    USHORT ModelNumber[20];                 // 36
-    UCHAR  MaximumBlockTransfer;            // 5E
-    UCHAR  VendorUnique2;                   // 5F
-    USHORT DoubleWordIo;                    // 60
-    USHORT Capabilities;                    // 62
-    USHORT Reserved2;                       // 64
-    UCHAR  VendorUnique3;                   // 66
-    UCHAR  PioCycleTimingMode;              // 67
-    UCHAR  VendorUnique4;                   // 68
-    UCHAR  DmaCycleTimingMode;              // 69
-    USHORT TranslationFieldsValid:1;        // 6A
-    USHORT Reserved3:15;
-    USHORT NumberOfCurrentCylinders;        // 6C
-    USHORT NumberOfCurrentHeads;            // 6E
-    USHORT CurrentSectorsPerTrack;          // 70
-    ULONG  CurrentSectorCapacity;           // 72
-    USHORT Reserved4[197];                  // 76
-	}	IDENTIFY_DATA, *PIDENTIFY_DATA;
-
-// Identify data without the Reserved4.
-typedef struct _IDENTIFY_DATA2 {
-    USHORT GeneralConfiguration;            // 00
-    USHORT NumberOfCylinders;               // 02
-    USHORT Reserved1;                       // 04
-    USHORT NumberOfHeads;                   // 06
-    USHORT UnformattedBytesPerTrack;        // 08
-    USHORT UnformattedBytesPerSector;       // 0A
-    USHORT SectorsPerTrack;                 // 0C
-    USHORT VendorUnique1[3];                // 0E
-    USHORT SerialNumber[10];                // 14
-    USHORT BufferType;                      // 28
-    USHORT BufferSectorSize;                // 2A
-    USHORT NumberOfEccBytes;                // 2C
-    USHORT FirmwareRevision[4];             // 2E
-    USHORT ModelNumber[20];                 // 36
-    UCHAR  MaximumBlockTransfer;            // 5E
-    UCHAR  VendorUnique2;                   // 5F
-    USHORT DoubleWordIo;                    // 60
-    USHORT Capabilities;                    // 62
-    USHORT Reserved2;                       // 64
-    UCHAR  VendorUnique3;                   // 66
-    UCHAR  PioCycleTimingMode;              // 67
-    UCHAR  VendorUnique4;                   // 68
-    UCHAR  DmaCycleTimingMode;              // 69
-	USHORT TranslationFieldsValid:1;     	// 6A
-    USHORT Reserved3:15;
-    USHORT NumberOfCurrentCylinders;        // 6C
-    USHORT NumberOfCurrentHeads;            // 6E
-    USHORT CurrentSectorsPerTrack;          // 70
-    ULONG  CurrentSectorCapacity;           // 72
-	}	IDENTIFY_DATA2, *PIDENTIFY_DATA2;
-
-#endif	// PSI_EIDE_SCSIOP
-
-// function prototypes
-int Psi240i_Command(struct scsi_cmnd *SCpnt);
-int Psi240i_Abort(struct scsi_cmnd *SCpnt);
-int Psi240i_Reset(struct scsi_cmnd *SCpnt, unsigned int flags);
-#endif
diff --git a/drivers/scsi/psi_chip.h b/drivers/scsi/psi_chip.h
deleted file mode 100644
index 224cf8f64c97..000000000000
--- a/drivers/scsi/psi_chip.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*+M*************************************************************************
- * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
- *
- * Copyright (c) 1997 Perceptive Solutions, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; 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.
- *
- *
- *	File Name:	psi_chip.h
- *
- *	Description:	This file contains the interface defines and
- *					error codes.
- *
- *-M*************************************************************************/
-#ifndef PSI_CHIP
-#define PSI_CHIP
-
-/************************************************/
-/*		Misc konstants							*/
-/************************************************/
-#define	CHIP_MAXDRIVES			8
-
-/************************************************/
-/*		Chip I/O addresses						*/
-/************************************************/
-#define	CHIP_ADRS_0				0x0130
-#define	CHIP_ADRS_1				0x0150
-#define	CHIP_ADRS_2				0x0190
-#define	CHIP_ADRS_3				0x0210
-#define	CHIP_ADRS_4				0x0230
-#define	CHIP_ADRS_5				0x0250
-
-/************************************************/
-/*		EEPROM locations		*/
-/************************************************/
-#define	CHIP_EEPROM_BIOS		0x0000		// BIOS base address
-#define	CHIP_EEPROM_DATA		0x2000	   	// SETUP data base address
-#define	CHIP_EEPROM_FACTORY		0x2400	   	// FACTORY data base address
-#define	CHIP_EEPROM_SETUP		0x3000	   	// SETUP PROGRAM base address
-
-#define	CHIP_EEPROM_SIZE		32768U	   	// size of the entire EEPROM
-#define	CHIP_EEPROM_BIOS_SIZE	8192	   	// size of the BIOS in bytes
-#define	CHIP_EEPROM_DATA_SIZE	4096	   	// size of factory, setup, log data block in bytes
-#define	CHIP_EEPROM_SETUP_SIZE	20480U	   	// size of the setup program in bytes
-
-/************************************************/
-/*		Chip Interrupts							*/
-/************************************************/
-#define	CHIP_IRQ_10				0x72
-#define	CHIP_IRQ_11				0x73
-#define	CHIP_IRQ_12				0x74
-
-/************************************************/
-/*		Chip Setup addresses		*/
-/************************************************/
-#define	CHIP_SETUP_BASE			0x0000C000L
-
-/************************************************/
-/*		Chip Register address offsets	*/
-/************************************************/
-#define	REG_DATA				0x00
-#define	REG_ERROR				0x01
-#define	REG_SECTOR_COUNT		0x02
-#define	REG_LBA_0				0x03
-#define	REG_LBA_8				0x04
-#define	REG_LBA_16				0x05
-#define	REG_LBA_24				0x06
-#define	REG_STAT_CMD			0x07
-#define	REG_SEL_FAIL			0x08
-#define	REG_IRQ_STATUS			0x09
-#define	REG_ADDRESS				0x0A
-#define	REG_FAIL				0x0C
-#define	REG_ALT_STAT		   	0x0E
-#define	REG_DRIVE_ADRS			0x0F
-
-/************************************************/
-/*		Chip RAM locations		*/
-/************************************************/
-#define	CHIP_DEVICE				0x8000
-#define	CHIP_DEVICE_0			0x8000
-#define CHIP_DEVICE_1			0x8008
-#define	CHIP_DEVICE_2			0x8010
-#define	CHIP_DEVICE_3			0x8018
-#define	CHIP_DEVICE_4			0x8020
-#define	CHIP_DEVICE_5			0x8028
-#define	CHIP_DEVICE_6			0x8030
-#define	CHIP_DEVICE_7			0x8038
-typedef struct
-	{
-	UCHAR	channel;		// channel of this device (0-8).
-	UCHAR	spt;			// Sectors Per Track.
-	ULONG	spc;			// Sectors Per Cylinder.
-	}	CHIP_DEVICE_N;
-
-#define	CHIP_CONFIG				0x8100		// address of boards configuration.
-typedef struct
-	{
-	UCHAR		irq;			// interrupt request channel number
-	UCHAR		numDrives;		// Number of accessible drives
-	UCHAR		fastFormat;	 	// Boolean for fast format enable
-	}	CHIP_CONFIG_N;
-
-#define	CHIP_MAP				0x8108 		// eight byte device type map.
-
-
-#define	CHIP_RAID				0x8120 		// array of RAID signature structures and LBA
-#define	CHIP_RAID_1				0x8120
-#define CHIP_RAID_2				0x8130
-#define	CHIP_RAID_3				0x8140
-#define	CHIP_RAID_4				0x8150
-
-/************************************************/
-/*		Chip Register Masks		*/
-/************************************************/
-#define	CHIP_ID					0x7B
-#define	SEL_RAM					0x8000
-#define	MASK_FAIL				0x80
-
-/************************************************/
-/*		Chip cable select bits		*/
-/************************************************/
-#define	SECTORSXFER				8
-
-/************************************************/
-/*		Chip cable select bits		*/
-/************************************************/
-#define	SEL_NONE				0x00
-#define	SEL_1					0x01
-#define	SEL_2					0x02
-#define	SEL_3					0x04
-#define	SEL_4					0x08
-
-/************************************************/
-/*		Programmable Interrupt Controller*/
-/************************************************/
-#define	PIC1					0x20		// first 8259 base port address
-#define	PIC2					0xA0		// second 8259 base port address
-#define	INT_OCW1				1			// Operation Control Word 1: IRQ mask
-#define	EOI						0x20		// non-specific end-of-interrupt
-
-/************************************************/
-/*		Device/Geometry controls				*/
-/************************************************/
-#define GEOMETRY_NONE		 	0x0			// No device
-#define GEOMETRY_AUTO			0x1			// Geometry set automatically
-#define GEOMETRY_USER		 	0x2			// User supplied geometry
-
-#define	DEVICE_NONE				0x0			// No device present
-#define	DEVICE_INACTIVE			0x1			// device present but not registered active
-#define	DEVICE_ATAPI			0x2			// ATAPI device (CD_ROM, Tape, Etc...)
-#define	DEVICE_DASD_NONLBA		0x3			// Non LBA incompatible device
-#define	DEVICE_DASD_LBA			0x4			// LBA compatible device
-
-/************************************************/
-/*		Setup Structure Definitions	*/
-/************************************************/
-typedef struct							// device setup parameters
-	{
-	UCHAR			geometryControl;	// geometry control flags
-	UCHAR		   	device;				// device code
-	USHORT			sectors;			// number of sectors per track
-	USHORT			heads;				// number of heads
-	USHORT			cylinders;			// number of cylinders for this device
-	ULONG			blocks;				// number of blocks on device
-	USHORT			spare1;
-	USHORT			spare2;
-	} SETUP_DEVICE, *PSETUP_DEVICE;
-
-typedef struct		// master setup structure
-	{
-	USHORT 			startupDelay;
-	USHORT 			promptBIOS;
-	USHORT 			fastFormat;
-	USHORT			spare2;
-	USHORT			spare3;
-	USHORT			spare4;
-	USHORT			spare5;
-	USHORT			spare6;
-	SETUP_DEVICE	setupDevice[8];
-	}	SETUP, *PSETUP;
-
-#endif
-
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 288640756099..68c0d09ffe78 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -528,7 +528,7 @@ __setup("qla1280=", qla1280_setup);
 #define	CMD_CDBLEN(Cmnd)	Cmnd->cmd_len
 #define	CMD_CDBP(Cmnd)		Cmnd->cmnd
 #define	CMD_SNSP(Cmnd)		Cmnd->sense_buffer
-#define	CMD_SNSLEN(Cmnd)	sizeof(Cmnd->sense_buffer)
+#define	CMD_SNSLEN(Cmnd)	SCSI_SENSE_BUFFERSIZE
 #define	CMD_RESULT(Cmnd)	Cmnd->result
 #define	CMD_HANDLE(Cmnd)	Cmnd->host_scribble
 #define CMD_REQUEST(Cmnd)	Cmnd->request->cmd
@@ -3715,7 +3715,7 @@ qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt,
 			} else
 				sense_sz = 0;
 			memset(cmd->sense_buffer + sense_sz, 0,
-			       sizeof(cmd->sense_buffer) - sense_sz);
+			       SCSI_SENSE_BUFFERSIZE - sense_sz);
 
 			dprintk(2, "qla1280_status_entry: Check "
 				"condition Sense data, b %i, t %i, "
@@ -4204,7 +4204,6 @@ static struct scsi_host_template qla1280_driver_template = {
 	.sg_tablesize		= SG_ALL,
 	.cmd_per_lun		= 1,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 };
 
 
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index 71ddb5db4944..c51fd1f86639 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,4 +1,4 @@
 qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
-		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o
+		qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o
 
 obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index fb388b8c07cf..adf97320574b 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -9,7 +9,7 @@
 #include <linux/kthread.h>
 #include <linux/vmalloc.h>
 
-int qla24xx_vport_disable(struct fc_vport *, bool);
+static int qla24xx_vport_disable(struct fc_vport *, bool);
 
 /* SYSFS attributes --------------------------------------------------------- */
 
@@ -958,7 +958,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
 {
 	scsi_qla_host_t *ha = shost_priv(shost);
 
-	set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags);
+	qla2x00_loop_reset(ha);
 	return 0;
 }
 
@@ -967,35 +967,51 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
 {
 	scsi_qla_host_t *ha = shost_priv(shost);
 	int rval;
-	uint16_t mb_stat[1];
-	link_stat_t stat_buf;
+	struct link_statistics *stats;
+	dma_addr_t stats_dma;
 	struct fc_host_statistics *pfc_host_stat;
 
-	rval = QLA_FUNCTION_FAILED;
 	pfc_host_stat = &ha->fc_host_stat;
 	memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
 
+	stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
+	if (stats == NULL) {
+		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
+		    __func__, ha->host_no));
+		goto done;
+	}
+	memset(stats, 0, DMA_POOL_SIZE);
+
+	rval = QLA_FUNCTION_FAILED;
 	if (IS_FWI2_CAPABLE(ha)) {
-		rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf,
-		    sizeof(stat_buf) / 4, mb_stat);
+		rval = qla24xx_get_isp_stats(ha, stats, stats_dma);
 	} else if (atomic_read(&ha->loop_state) == LOOP_READY &&
 		    !test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) &&
 		    !test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) &&
 		    !ha->dpc_active) {
 		/* Must be in a 'READY' state for statistics retrieval. */
-		rval = qla2x00_get_link_status(ha, ha->loop_id, &stat_buf,
-		    mb_stat);
+		rval = qla2x00_get_link_status(ha, ha->loop_id, stats,
+		    stats_dma);
 	}
 
 	if (rval != QLA_SUCCESS)
-		goto done;
+		goto done_free;
+
+	pfc_host_stat->link_failure_count = stats->link_fail_cnt;
+	pfc_host_stat->loss_of_sync_count = stats->loss_sync_cnt;
+	pfc_host_stat->loss_of_signal_count = stats->loss_sig_cnt;
+	pfc_host_stat->prim_seq_protocol_err_count = stats->prim_seq_err_cnt;
+	pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
+	pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
+	if (IS_FWI2_CAPABLE(ha)) {
+		pfc_host_stat->tx_frames = stats->tx_frames;
+		pfc_host_stat->rx_frames = stats->rx_frames;
+		pfc_host_stat->dumped_frames = stats->dumped_frames;
+		pfc_host_stat->nos_count = stats->nos_rcvd;
+	}
 
-	pfc_host_stat->link_failure_count = stat_buf.link_fail_cnt;
-	pfc_host_stat->loss_of_sync_count = stat_buf.loss_sync_cnt;
-	pfc_host_stat->loss_of_signal_count = stat_buf.loss_sig_cnt;
-	pfc_host_stat->prim_seq_protocol_err_count = stat_buf.prim_seq_err_cnt;
-	pfc_host_stat->invalid_tx_word_count = stat_buf.inval_xmit_word_cnt;
-	pfc_host_stat->invalid_crc_count = stat_buf.inval_crc_cnt;
+done_free:
+        dma_pool_free(ha->s_dma_pool, stats, stats_dma);
 done:
 	return pfc_host_stat;
 }
@@ -1113,7 +1129,7 @@ vport_create_failed_2:
 	return FC_VPORT_FAILED;
 }
 
-int
+static int
 qla24xx_vport_delete(struct fc_vport *fc_vport)
 {
 	scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
@@ -1124,7 +1140,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
 
 	down(&ha->vport_sem);
 	ha->cur_vport_count--;
-	clear_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
+	clear_bit(vha->vp_idx, ha->vp_idx_map);
 	up(&ha->vport_sem);
 
 	kfree(vha->node_name);
@@ -1146,7 +1162,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
 	return 0;
 }
 
-int
+static int
 qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
 {
 	scsi_qla_host_t *vha = fc_vport->dd_data;
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index eaa04dabcdf6..d88e98c476b0 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -1051,6 +1051,7 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
 	struct qla25xx_fw_dump *fw;
 	uint32_t	ext_mem_cnt;
 	void		*nxt;
+	struct qla2xxx_fce_chain *fcec;
 
 	risc_address = ext_mem_cnt = 0;
 	flags = 0;
@@ -1321,10 +1322,31 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
 	if (rval != QLA_SUCCESS)
 		goto qla25xx_fw_dump_failed_0;
 
+	/* Fibre Channel Trace Buffer. */
 	nxt = qla2xxx_copy_queues(ha, nxt);
 	if (ha->eft)
 		memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
 
+	/* Fibre Channel Event Buffer. */
+	if (!ha->fce)
+		goto qla25xx_fw_dump_failed_0;
+
+	ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
+
+	fcec = nxt + ntohl(ha->fw_dump->eft_size);
+	fcec->type = __constant_htonl(DUMP_CHAIN_FCE | DUMP_CHAIN_LAST);
+	fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) +
+	    fce_calc_size(ha->fce_bufs));
+	fcec->size = htonl(fce_calc_size(ha->fce_bufs));
+	fcec->addr_l = htonl(LSD(ha->fce_dma));
+	fcec->addr_h = htonl(MSD(ha->fce_dma));
+
+	iter_reg = fcec->eregs;
+	for (cnt = 0; cnt < 8; cnt++)
+		*iter_reg++ = htonl(ha->fce_mb[cnt]);
+
+	memcpy(iter_reg, ha->fce, ntohl(fcec->size));
+
 qla25xx_fw_dump_failed_0:
 	if (rval != QLA_SUCCESS) {
 		qla_printk(KERN_WARNING, ha,
@@ -1428,21 +1450,6 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd)
 	printk("  sp flags=0x%x\n", sp->flags);
 }
 
-void
-qla2x00_dump_pkt(void *pkt)
-{
-	uint32_t i;
-	uint8_t *data = (uint8_t *) pkt;
-
-	for (i = 0; i < 64; i++) {
-		if (!(i % 4))
-			printk("\n%02x: ", i);
-
-		printk("%02x ", data[i]);
-	}
-	printk("\n");
-}
-
 #if defined(QL_DEBUG_ROUTINES)
 /*
  * qla2x00_formatted_dump_buffer
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index a50ecf0b7c84..524598afc81c 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -256,6 +256,25 @@ struct qla25xx_fw_dump {
 #define EFT_BYTES_PER_BUFFER	0x4000
 #define EFT_SIZE		((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
 
+#define FCE_NUM_BUFFERS		64
+#define FCE_BYTES_PER_BUFFER	0x400
+#define FCE_SIZE		((FCE_BYTES_PER_BUFFER) * (FCE_NUM_BUFFERS))
+#define fce_calc_size(b)	((FCE_BYTES_PER_BUFFER) * (b))
+
+struct qla2xxx_fce_chain {
+	uint32_t type;
+	uint32_t chain_size;
+
+	uint32_t size;
+	uint32_t addr_l;
+	uint32_t addr_h;
+	uint32_t eregs[8];
+};
+
+#define DUMP_CHAIN_VARIANT	0x80000000
+#define DUMP_CHAIN_FCE		0x7FFFFAF0
+#define DUMP_CHAIN_LAST		0x80000000
+
 struct qla2xxx_fw_dump {
 	uint8_t signature[4];
 	uint32_t version;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 04e8cbca4c0d..6f129da37589 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -623,9 +623,6 @@ typedef struct {
 #define MBC_GET_LINK_PRIV_STATS		0x6d	/* Get link & private data. */
 #define MBC_SET_VENDOR_ID		0x76	/* Set Vendor ID. */
 
-#define TC_ENABLE			4
-#define TC_DISABLE			5
-
 /* Firmware return data sizes */
 #define FCAL_MAP_SIZE	128
 
@@ -862,14 +859,20 @@ typedef struct {
 #define GLSO_SEND_RPS	BIT_0
 #define GLSO_USE_DID	BIT_3
 
-typedef struct {
-	uint32_t	link_fail_cnt;
-	uint32_t	loss_sync_cnt;
-	uint32_t	loss_sig_cnt;
-	uint32_t	prim_seq_err_cnt;
-	uint32_t	inval_xmit_word_cnt;
-	uint32_t	inval_crc_cnt;
-} link_stat_t;
+struct link_statistics {
+	uint32_t link_fail_cnt;
+	uint32_t loss_sync_cnt;
+	uint32_t loss_sig_cnt;
+	uint32_t prim_seq_err_cnt;
+	uint32_t inval_xmit_word_cnt;
+	uint32_t inval_crc_cnt;
+	uint32_t unused1[0x1b];
+	uint32_t tx_frames;
+	uint32_t rx_frames;
+	uint32_t dumped_frames;
+	uint32_t unused2[2];
+	uint32_t nos_rcvd;
+};
 
 /*
  * NVRAM Command values.
@@ -2116,14 +2119,6 @@ struct qla_msix_entry {
 
 #define	WATCH_INTERVAL		1       /* number of seconds */
 
-/* NPIV */
-#define MAX_MULTI_ID_LOOP                     126
-#define MAX_MULTI_ID_FABRIC                    64
-#define MAX_NUM_VPORT_LOOP                      (MAX_MULTI_ID_LOOP - 1)
-#define MAX_NUM_VPORT_FABRIC                    (MAX_MULTI_ID_FABRIC - 1)
-#define MAX_NUM_VHBA_LOOP                       (MAX_MULTI_ID_LOOP - 1)
-#define MAX_NUM_VHBA_FABRIC                     (MAX_MULTI_ID_FABRIC - 1)
-
 /*
  * Linux Host Adapter structure
  */
@@ -2161,6 +2156,7 @@ typedef struct scsi_qla_host {
 		uint32_t	gpsc_supported		:1;
 		uint32_t        vsan_enabled            :1;
 		uint32_t	npiv_supported		:1;
+		uint32_t	fce_enabled		:1;
 	} flags;
 
 	atomic_t	loop_state;
@@ -2273,8 +2269,7 @@ typedef struct scsi_qla_host {
 
 	int		bars;
 	device_reg_t __iomem *iobase;		/* Base I/O address */
-	unsigned long	pio_address;
-	unsigned long	pio_length;
+	resource_size_t pio_address;
 #define MIN_IOBASE_LEN		0x100
 
 	/* ISP ring lock, rings, and indexes */
@@ -2416,9 +2411,9 @@ typedef struct scsi_qla_host {
 #define MBX_INTR_WAIT	2
 #define MBX_UPDATE_FLASH_ACTIVE	3
 
-	struct semaphore mbx_cmd_sem;	/* Serialialize mbx access */
 	struct semaphore vport_sem;	/* Virtual port synchronization */
-	struct semaphore mbx_intr_sem;  /* Used for completion notification */
+	struct completion mbx_cmd_comp;	/* Serialize mbx access */
+	struct completion mbx_intr_comp;  /* Used for completion notification */
 
 	uint32_t	mbx_flags;
 #define  MBX_IN_PROGRESS	BIT_0
@@ -2455,6 +2450,15 @@ typedef struct scsi_qla_host {
 	dma_addr_t	eft_dma;
 	void		*eft;
 
+	struct dentry *dfs_dir;
+	struct dentry *dfs_fce;
+	dma_addr_t	fce_dma;
+	void		*fce;
+	uint32_t	fce_bufs;
+	uint16_t	fce_mb[8];
+	uint64_t	fce_wr, fce_rd;
+	struct mutex	fce_mutex;
+
 	uint8_t		host_str[16];
 	uint32_t	pci_attr;
 	uint16_t	chip_revision;
@@ -2507,7 +2511,7 @@ typedef struct scsi_qla_host {
 
 	struct list_head	vp_list;	/* list of VP */
 	struct fc_vport	*fc_vport;	/* holds fc_vport * for each vport */
-	uint8_t		vp_idx_map[16];
+	unsigned long	vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) / sizeof(unsigned long)];
 	uint16_t        num_vhosts;	/* number of vports created */
 	uint16_t        num_vsans;	/* number of vsan created */
 	uint16_t        vp_idx;		/* vport ID */
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
new file mode 100644
index 000000000000..1479c60441c8
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -0,0 +1,175 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2005 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#include "qla_def.h"
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static struct dentry *qla2x00_dfs_root;
+static atomic_t qla2x00_dfs_root_count;
+
+static int
+qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
+{
+	scsi_qla_host_t *ha = s->private;
+	uint32_t cnt;
+	uint32_t *fce;
+	uint64_t fce_start;
+
+	mutex_lock(&ha->fce_mutex);
+
+	seq_printf(s, "FCE Trace Buffer\n");
+	seq_printf(s, "In Pointer = %llx\n\n", ha->fce_wr);
+	seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma);
+	seq_printf(s, "FCE Enable Registers\n");
+	seq_printf(s, "%08x %08x %08x %08x %08x %08x\n",
+	    ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4],
+	    ha->fce_mb[5], ha->fce_mb[6]);
+
+	fce = (uint32_t *) ha->fce;
+	fce_start = (unsigned long long) ha->fce_dma;
+	for (cnt = 0; cnt < fce_calc_size(ha->fce_bufs) / 4; cnt++) {
+		if (cnt % 8 == 0)
+			seq_printf(s, "\n%llx: ",
+			    (unsigned long long)((cnt * 4) + fce_start));
+		else
+			seq_printf(s, " ");
+		seq_printf(s, "%08x", *fce++);
+	}
+
+	seq_printf(s, "\nEnd\n");
+
+	mutex_unlock(&ha->fce_mutex);
+
+	return 0;
+}
+
+static int
+qla2x00_dfs_fce_open(struct inode *inode, struct file *file)
+{
+	scsi_qla_host_t *ha = inode->i_private;
+	int rval;
+
+	if (!ha->flags.fce_enabled)
+		goto out;
+
+	mutex_lock(&ha->fce_mutex);
+
+	/* Pause tracing to flush FCE buffers. */
+	rval = qla2x00_disable_fce_trace(ha, &ha->fce_wr, &ha->fce_rd);
+	if (rval)
+		qla_printk(KERN_WARNING, ha,
+		    "DebugFS: Unable to disable FCE (%d).\n", rval);
+
+	ha->flags.fce_enabled = 0;
+
+	mutex_unlock(&ha->fce_mutex);
+out:
+	return single_open(file, qla2x00_dfs_fce_show, ha);
+}
+
+static int
+qla2x00_dfs_fce_release(struct inode *inode, struct file *file)
+{
+	scsi_qla_host_t *ha = inode->i_private;
+	int rval;
+
+	if (ha->flags.fce_enabled)
+		goto out;
+
+	mutex_lock(&ha->fce_mutex);
+
+	/* Re-enable FCE tracing. */
+	ha->flags.fce_enabled = 1;
+	memset(ha->fce, 0, fce_calc_size(ha->fce_bufs));
+	rval = qla2x00_enable_fce_trace(ha, ha->fce_dma, ha->fce_bufs,
+	    ha->fce_mb, &ha->fce_bufs);
+	if (rval) {
+		qla_printk(KERN_WARNING, ha,
+		    "DebugFS: Unable to reinitialize FCE (%d).\n", rval);
+		ha->flags.fce_enabled = 0;
+	}
+
+	mutex_unlock(&ha->fce_mutex);
+out:
+	return single_release(inode, file);
+}
+
+static const struct file_operations dfs_fce_ops = {
+	.open		= qla2x00_dfs_fce_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= qla2x00_dfs_fce_release,
+};
+
+int
+qla2x00_dfs_setup(scsi_qla_host_t *ha)
+{
+	if (!IS_QLA25XX(ha))
+		goto out;
+	if (!ha->fce)
+		goto out;
+
+	if (qla2x00_dfs_root)
+		goto create_dir;
+
+	atomic_set(&qla2x00_dfs_root_count, 0);
+	qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL);
+	if (!qla2x00_dfs_root) {
+		qla_printk(KERN_NOTICE, ha,
+		    "DebugFS: Unable to create root directory.\n");
+		goto out;
+	}
+
+create_dir:
+	if (ha->dfs_dir)
+		goto create_nodes;
+
+	mutex_init(&ha->fce_mutex);
+	ha->dfs_dir = debugfs_create_dir(ha->host_str, qla2x00_dfs_root);
+	if (!ha->dfs_dir) {
+		qla_printk(KERN_NOTICE, ha,
+		    "DebugFS: Unable to create ha directory.\n");
+		goto out;
+	}
+
+	atomic_inc(&qla2x00_dfs_root_count);
+
+create_nodes:
+	ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, ha,
+	    &dfs_fce_ops);
+	if (!ha->dfs_fce) {
+		qla_printk(KERN_NOTICE, ha,
+		    "DebugFS: Unable to fce node.\n");
+		goto out;
+	}
+out:
+	return 0;
+}
+
+int
+qla2x00_dfs_remove(scsi_qla_host_t *ha)
+{
+	if (ha->dfs_fce) {
+		debugfs_remove(ha->dfs_fce);
+		ha->dfs_fce = NULL;
+	}
+
+	if (ha->dfs_dir) {
+		debugfs_remove(ha->dfs_dir);
+		ha->dfs_dir = NULL;
+		atomic_dec(&qla2x00_dfs_root_count);
+	}
+
+	if (atomic_read(&qla2x00_dfs_root_count) == 0 &&
+	    qla2x00_dfs_root) {
+		debugfs_remove(qla2x00_dfs_root);
+		qla2x00_dfs_root = NULL;
+	}
+
+	return 0;
+}
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 25364b1aaf12..9337e138ed63 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -952,9 +952,31 @@ struct device_reg_24xx {
 	uint32_t iobase_sdata;
 };
 
+/* Trace Control *************************************************************/
+
+#define TC_AEN_DISABLE		0
+
+#define TC_EFT_ENABLE		4
+#define TC_EFT_DISABLE		5
+
+#define TC_FCE_ENABLE		8
+#define TC_FCE_OPTIONS		0
+#define TC_FCE_DEFAULT_RX_SIZE	2112
+#define TC_FCE_DEFAULT_TX_SIZE	2112
+#define TC_FCE_DISABLE		9
+#define TC_FCE_DISABLE_TRACE	BIT_0
+
 /* MID Support ***************************************************************/
 
-#define MAX_MID_VPS	125
+#define MIN_MULTI_ID_FABRIC	64	/* Must be power-of-2. */
+#define MAX_MULTI_ID_FABRIC	256	/* ... */
+
+#define for_each_mapped_vp_idx(_ha, _idx)		\
+	for (_idx = find_next_bit((_ha)->vp_idx_map,	\
+		(_ha)->max_npiv_vports + 1, 1);		\
+	    _idx <= (_ha)->max_npiv_vports;		\
+	    _idx = find_next_bit((_ha)->vp_idx_map,	\
+		(_ha)->max_npiv_vports + 1, _idx + 1))	\
 
 struct mid_conf_entry_24xx {
 	uint16_t reserved_1;
@@ -982,7 +1004,7 @@ struct mid_init_cb_24xx {
 	uint16_t count;
 	uint16_t options;
 
-	struct mid_conf_entry_24xx entries[MAX_MID_VPS];
+	struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC];
 };
 
 
@@ -1002,10 +1024,6 @@ struct mid_db_entry_24xx {
 	uint8_t reserved_1;
 };
 
-struct mid_db_24xx {
-	struct mid_db_entry_24xx entries[MAX_MID_VPS];
-};
-
  /*
  * Virtual Fabric ID type definition.
  */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 09cb2a908059..ba35fc26ce6b 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -65,33 +65,25 @@ extern int ql2xextended_error_logging;
 extern int ql2xqfullrampup;
 extern int num_hosts;
 
+extern int qla2x00_loop_reset(scsi_qla_host_t *);
+
 /*
  * Global Functions in qla_mid.c source file.
  */
-extern struct scsi_host_template qla2x00_driver_template;
 extern struct scsi_host_template qla24xx_driver_template;
 extern struct scsi_transport_template *qla2xxx_transport_vport_template;
-extern uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
 extern void qla2x00_timer(scsi_qla_host_t *);
 extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long);
-extern void qla2x00_stop_timer(scsi_qla_host_t *);
-extern uint32_t qla24xx_allocate_vp_id(scsi_qla_host_t *);
 extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *);
 extern int qla24xx_disable_vp (scsi_qla_host_t *);
 extern int qla24xx_enable_vp (scsi_qla_host_t *);
-extern void qla2x00_mem_free(scsi_qla_host_t *);
 extern int qla24xx_control_vp(scsi_qla_host_t *, int );
 extern int qla24xx_modify_vp_config(scsi_qla_host_t *);
 extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t);
 extern void qla2x00_vp_stop_timer(scsi_qla_host_t *);
 extern int qla24xx_configure_vhba (scsi_qla_host_t *);
-extern int qla24xx_get_vp_entry(scsi_qla_host_t *, uint16_t, int);
-extern int qla24xx_get_vp_database(scsi_qla_host_t *, uint16_t);
-extern int qla2x00_do_dpc_vp(scsi_qla_host_t *);
 extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
     struct vp_rpt_id_entry_24xx *);
-extern scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *,
-    uint8_t *);
 extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
 extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
 extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *);
@@ -103,8 +95,6 @@ extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
 extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int);
 extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int);
 
-extern int qla2x00_down_timeout(struct semaphore *, unsigned long);
-
 extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
 
 extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);
@@ -113,7 +103,6 @@ extern void qla2xxx_wake_dpc(scsi_qla_host_t *);
 extern void qla2x00_alert_all_vps(scsi_qla_host_t *, uint16_t *);
 extern void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
 extern void qla2x00_vp_abort_isp(scsi_qla_host_t *);
-extern int qla24xx_vport_delete(struct fc_vport *);
 
 /*
  * Global Function Prototypes in qla_iocb.c source file.
@@ -222,21 +211,16 @@ extern int
 qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
 
 extern int
-qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, link_stat_t *,
-    uint16_t *);
+qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, struct link_statistics *,
+    dma_addr_t);
 
 extern int
-qla24xx_get_isp_stats(scsi_qla_host_t *, uint32_t *, uint32_t, uint16_t *);
+qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *,
+    dma_addr_t);
 
 extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *);
 extern int qla24xx_abort_target(fc_port_t *);
 
-extern int qla2x00_system_error(scsi_qla_host_t *);
-
-extern int
-qla2x00_get_serdes_params(scsi_qla_host_t *, uint16_t *, uint16_t *,
-    uint16_t *);
-
 extern int
 qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
 
@@ -244,13 +228,19 @@ extern int
 qla2x00_stop_firmware(scsi_qla_host_t *);
 
 extern int
-qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t);
+qla2x00_enable_eft_trace(scsi_qla_host_t *, dma_addr_t, uint16_t);
+extern int
+qla2x00_disable_eft_trace(scsi_qla_host_t *);
 
 extern int
-qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
+qla2x00_enable_fce_trace(scsi_qla_host_t *, dma_addr_t, uint16_t , uint16_t *,
+    uint32_t *);
 
 extern int
-qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *);
+qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *);
+
+extern int
+qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
 
 extern int
 qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
@@ -270,11 +260,7 @@ extern void qla2x00_free_irqs(scsi_qla_host_t *);
 /*
  * Global Function Prototypes in qla_sup.c source file.
  */
-extern void qla2x00_lock_nvram_access(scsi_qla_host_t *);
-extern void qla2x00_unlock_nvram_access(scsi_qla_host_t *);
 extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
-extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t);
-extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t);
 extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
     uint32_t, uint32_t);
 extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
@@ -321,7 +307,6 @@ extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
 extern void qla2x00_dump_regs(scsi_qla_host_t *);
 extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
 extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
-extern void qla2x00_dump_pkt(void *);
 
 /*
  * Global Function Prototypes in qla_gs.c source file.
@@ -356,4 +341,10 @@ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
 extern void qla2x00_init_host_attr(scsi_qla_host_t *);
 extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
 extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
+
+/*
+ * Global Function Prototypes in qla_dfs.c source file.
+ */
+extern int qla2x00_dfs_setup(scsi_qla_host_t *);
+extern int qla2x00_dfs_remove(scsi_qla_host_t *);
 #endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 191dafd89be0..d0633ca894be 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -732,9 +732,9 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 {
 	int rval;
 	uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
-	    eft_size;
-	dma_addr_t eft_dma;
-	void *eft;
+	    eft_size, fce_size;
+	dma_addr_t tc_dma;
+	void *tc;
 
 	if (ha->fw_dump) {
 		qla_printk(KERN_WARNING, ha,
@@ -743,7 +743,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 	}
 
 	ha->fw_dumped = 0;
-	fixed_size = mem_size = eft_size = 0;
+	fixed_size = mem_size = eft_size = fce_size = 0;
 	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
 		fixed_size = sizeof(struct qla2100_fw_dump);
 	} else if (IS_QLA23XX(ha)) {
@@ -758,21 +758,21 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 		    sizeof(uint32_t);
 
 		/* Allocate memory for Extended Trace Buffer. */
-		eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma,
+		tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
 		    GFP_KERNEL);
-		if (!eft) {
+		if (!tc) {
 			qla_printk(KERN_WARNING, ha, "Unable to allocate "
 			    "(%d KB) for EFT.\n", EFT_SIZE / 1024);
 			goto cont_alloc;
 		}
 
-		rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma,
-		    EFT_NUM_BUFFERS);
+		memset(tc, 0, EFT_SIZE);
+		rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS);
 		if (rval) {
 			qla_printk(KERN_WARNING, ha, "Unable to initialize "
 			    "EFT (%d).\n", rval);
-			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft,
-			    eft_dma);
+			dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
+			    tc_dma);
 			goto cont_alloc;
 		}
 
@@ -780,9 +780,40 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
 		    EFT_SIZE / 1024);
 
 		eft_size = EFT_SIZE;
-		memset(eft, 0, eft_size);
-		ha->eft_dma = eft_dma;
-		ha->eft = eft;
+		ha->eft_dma = tc_dma;
+		ha->eft = tc;
+
+		/* Allocate memory for Fibre Channel Event Buffer. */
+		if (!IS_QLA25XX(ha))
+			goto cont_alloc;
+
+		tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
+		    GFP_KERNEL);
+		if (!tc) {
+			qla_printk(KERN_WARNING, ha, "Unable to allocate "
+			    "(%d KB) for FCE.\n", FCE_SIZE / 1024);
+			goto cont_alloc;
+		}
+
+		memset(tc, 0, FCE_SIZE);
+		rval = qla2x00_enable_fce_trace(ha, tc_dma, FCE_NUM_BUFFERS,
+		    ha->fce_mb, &ha->fce_bufs);
+		if (rval) {
+			qla_printk(KERN_WARNING, ha, "Unable to initialize "
+			    "FCE (%d).\n", rval);
+			dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
+			    tc_dma);
+			ha->flags.fce_enabled = 0;
+			goto cont_alloc;
+		}
+
+		qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
+		    FCE_SIZE / 1024);
+
+		fce_size = sizeof(struct qla2xxx_fce_chain) + EFT_SIZE;
+		ha->flags.fce_enabled = 1;
+		ha->fce_dma = tc_dma;
+		ha->fce = tc;
 	}
 cont_alloc:
 	req_q_size = ha->request_q_length * sizeof(request_t);
@@ -790,7 +821,7 @@ cont_alloc:
 
 	dump_size = offsetof(struct qla2xxx_fw_dump, isp);
 	dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
-	    eft_size;
+	    eft_size + fce_size;
 
 	ha->fw_dump = vmalloc(dump_size);
 	if (!ha->fw_dump) {
@@ -922,9 +953,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
 					ha->flags.npiv_supported = 1;
 					if ((!ha->max_npiv_vports) ||
 					    ((ha->max_npiv_vports + 1) %
-					    MAX_MULTI_ID_FABRIC))
+					    MIN_MULTI_ID_FABRIC))
 						ha->max_npiv_vports =
-						    MAX_NUM_VPORT_FABRIC;
+						    MIN_MULTI_ID_FABRIC - 1;
 				}
 
 				if (ql2xallocfwdump)
@@ -1162,7 +1193,10 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
 
 	DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
 
-	mid_init_cb->count = ha->max_npiv_vports;
+	if (ha->flags.npiv_supported)
+		mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports);
+
+	mid_init_cb->options = __constant_cpu_to_le16(BIT_1);
 
 	rval = qla2x00_init_firmware(ha, ha->init_cb_size);
 	if (rval) {
@@ -2566,14 +2600,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
 
 		/* Bypass virtual ports of the same host. */
 		if (pha->num_vhosts) {
-			vp_index = find_next_bit(
-			    (unsigned long *)pha->vp_idx_map,
-			    MAX_MULTI_ID_FABRIC + 1, 1);
-
-			for (;vp_index <= MAX_MULTI_ID_FABRIC;
-			    vp_index = find_next_bit(
-			    (unsigned long *)pha->vp_idx_map,
-			    MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) {
+			for_each_mapped_vp_idx(pha, vp_index) {
 				empty_vp_index = 1;
 				found_vp = 0;
 				list_for_each_entry(vha, &pha->vp_list,
@@ -2592,7 +2619,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
 				    new_fcport->d_id.b24 == vha->d_id.b24)
 					break;
 			}
-			if (vp_index <= MAX_MULTI_ID_FABRIC)
+
+			if (vp_index <= pha->max_npiv_vports)
 				continue;
 		}
 
@@ -3245,7 +3273,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 			clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
 
 			if (ha->eft) {
-				rval = qla2x00_trace_control(ha, TC_ENABLE,
+				rval = qla2x00_enable_eft_trace(ha,
 				    ha->eft_dma, EFT_NUM_BUFFERS);
 				if (rval) {
 					qla_printk(KERN_WARNING, ha,
@@ -3253,6 +3281,21 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
 					    "(%d).\n", rval);
 				}
 			}
+
+			if (ha->fce) {
+				ha->flags.fce_enabled = 1;
+				memset(ha->fce, 0,
+				    fce_calc_size(ha->fce_bufs));
+				rval = qla2x00_enable_fce_trace(ha,
+				    ha->fce_dma, ha->fce_bufs, ha->fce_mb,
+				    &ha->fce_bufs);
+				if (rval) {
+					qla_printk(KERN_WARNING, ha,
+					    "Unable to reinitialize FCE "
+					    "(%d).\n", rval);
+					ha->flags.fce_enabled = 0;
+				}
+			}
 		} else {	/* failed the ISP abort */
 			ha->flags.online = 1;
 			if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 1104bd2eed40..642a0c3f09c6 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -104,7 +104,7 @@ qla2100_intr_handler(int irq, void *dev_id)
 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-		up(&ha->mbx_intr_sem);
+		complete(&ha->mbx_intr_comp);
 	}
 
 	return (IRQ_HANDLED);
@@ -216,7 +216,7 @@ qla2300_intr_handler(int irq, void *dev_id)
 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-		up(&ha->mbx_intr_sem);
+		complete(&ha->mbx_intr_comp);
 	}
 
 	return (IRQ_HANDLED);
@@ -347,10 +347,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
 		break;
 
 	case MBA_SYSTEM_ERR:		/* System Error */
-		mb[1] = RD_MAILBOX_REG(ha, reg, 1);
-		mb[2] = RD_MAILBOX_REG(ha, reg, 2);
-		mb[3] = RD_MAILBOX_REG(ha, reg, 3);
-
 		qla_printk(KERN_INFO, ha,
 		    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
 		    mb[1], mb[2], mb[3]);
@@ -579,12 +575,15 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
 		/* Check if the Vport has issued a SCR */
 		if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags))
 			break;
+		/* Only handle SCNs for our Vport index. */
+		if (ha->flags.npiv_supported && ha->vp_idx != mb[3])
+			break;
 
 		DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
 		    ha->host_no));
 		DEBUG(printk(KERN_INFO
-		    "scsi(%ld): RSCN database changed -- %04x %04x.\n",
-		    ha->host_no, mb[1], mb[2]));
+		    "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
+		    ha->host_no, mb[1], mb[2], mb[3]));
 
 		rscn_entry = (mb[1] << 16) | mb[2];
 		host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) |
@@ -823,6 +822,35 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha)
 	WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), ha->rsp_ring_index);
 }
 
+static inline void
+qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
+{
+	struct scsi_cmnd *cp = sp->cmd;
+
+	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
+		sense_len = SCSI_SENSE_BUFFERSIZE;
+
+	CMD_ACTUAL_SNSLEN(cp) = sense_len;
+	sp->request_sense_length = sense_len;
+	sp->request_sense_ptr = cp->sense_buffer;
+	if (sp->request_sense_length > 32)
+		sense_len = 32;
+
+	memcpy(cp->sense_buffer, sense_data, sense_len);
+
+	sp->request_sense_ptr += sense_len;
+	sp->request_sense_length -= sense_len;
+	if (sp->request_sense_length != 0)
+		sp->ha->status_srb = sp;
+
+	DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
+	    "cmd=%p pid=%ld\n", __func__, sp->ha->host_no, cp->device->channel,
+	    cp->device->id, cp->device->lun, cp, cp->serial_number));
+	if (sense_len)
+		DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
+		    CMD_ACTUAL_SNSLEN(cp)));
+}
+
 /**
  * qla2x00_status_entry() - Process a Status IOCB entry.
  * @ha: SCSI driver HA context
@@ -977,36 +1005,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
 		if (lscsi_status != SS_CHECK_CONDITION)
 			break;
 
-		/* Copy Sense Data into sense buffer. */
-		memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
-
+		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 		if (!(scsi_status & SS_SENSE_LEN_VALID))
 			break;
 
-		if (sense_len >= sizeof(cp->sense_buffer))
-			sense_len = sizeof(cp->sense_buffer);
-
-		CMD_ACTUAL_SNSLEN(cp) = sense_len;
-		sp->request_sense_length = sense_len;
-		sp->request_sense_ptr = cp->sense_buffer;
-
-		if (sp->request_sense_length > 32)
-			sense_len = 32;
-
-		memcpy(cp->sense_buffer, sense_data, sense_len);
-
-		sp->request_sense_ptr += sense_len;
-		sp->request_sense_length -= sense_len;
-		if (sp->request_sense_length != 0)
-			ha->status_srb = sp;
-
-		DEBUG5(printk("%s(): Check condition Sense data, "
-		    "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n", __func__,
-		    ha->host_no, cp->device->channel, cp->device->id,
-		    cp->device->lun, cp, cp->serial_number));
-		if (sense_len)
-			DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
-			    CMD_ACTUAL_SNSLEN(cp)));
+		qla2x00_handle_sense(sp, sense_data, sense_len);
 		break;
 
 	case CS_DATA_UNDERRUN:
@@ -1061,34 +1064,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
 			if (lscsi_status != SS_CHECK_CONDITION)
 				break;
 
-			/* Copy Sense Data into sense buffer */
-			memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
-
+			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 			if (!(scsi_status & SS_SENSE_LEN_VALID))
 				break;
 
-			if (sense_len >= sizeof(cp->sense_buffer))
-				sense_len = sizeof(cp->sense_buffer);
-
-			CMD_ACTUAL_SNSLEN(cp) = sense_len;
-			sp->request_sense_length = sense_len;
-			sp->request_sense_ptr = cp->sense_buffer;
-
-			if (sp->request_sense_length > 32)
-				sense_len = 32;
-
-			memcpy(cp->sense_buffer, sense_data, sense_len);
-
-			sp->request_sense_ptr += sense_len;
-			sp->request_sense_length -= sense_len;
-			if (sp->request_sense_length != 0)
-				ha->status_srb = sp;
-
-			DEBUG5(printk("%s(): Check condition Sense data, "
-			    "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n",
-			    __func__, ha->host_no, cp->device->channel,
-			    cp->device->id, cp->device->lun, cp,
-			    cp->serial_number));
+			qla2x00_handle_sense(sp, sense_data, sense_len);
 
 			/*
 			 * In case of a Underrun condition, set both the lscsi
@@ -1108,10 +1088,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
 
 				cp->result = DID_ERROR << 16 | lscsi_status;
 			}
-
-			if (sense_len)
-				DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
-				    CMD_ACTUAL_SNSLEN(cp)));
 		} else {
 			/*
 			 * If RISC reports underrun and target does not report
@@ -1621,7 +1597,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-		up(&ha->mbx_intr_sem);
+		complete(&ha->mbx_intr_comp);
 	}
 
 	return IRQ_HANDLED;
@@ -1758,7 +1734,7 @@ qla24xx_msix_default(int irq, void *dev_id)
 	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
 	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
 		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-		up(&ha->mbx_intr_sem);
+		complete(&ha->mbx_intr_comp);
 	}
 
 	return IRQ_HANDLED;
@@ -1853,6 +1829,18 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
 		goto skip_msix;
 	}
 
+	if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
+	    (ha->pdev->subsystem_device == 0x7040 ||
+		ha->pdev->subsystem_device == 0x7041 ||
+		ha->pdev->subsystem_device == 0x1705)) {
+		DEBUG2(qla_printk(KERN_WARNING, ha,
+		    "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X, 0x%X).\n",
+		    ha->pdev->subsystem_vendor,
+		    ha->pdev->subsystem_device));
+
+		goto skip_msi;
+	}
+
 	ret = qla24xx_enable_msix(ha);
 	if (!ret) {
 		DEBUG2(qla_printk(KERN_INFO, ha,
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index ccd662a6f5dc..0c10c0b0fb73 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -8,19 +8,6 @@
 
 #include <linux/delay.h>
 
-static void
-qla2x00_mbx_sem_timeout(unsigned long data)
-{
-	struct semaphore	*sem_ptr = (struct semaphore *)data;
-
-	DEBUG11(printk("qla2x00_sem_timeout: entered.\n"));
-
-	if (sem_ptr != NULL) {
-		up(sem_ptr);
-	}
-
-	DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n"));
-}
 
 /*
  * qla2x00_mailbox_command
@@ -47,7 +34,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 	int		rval;
 	unsigned long    flags = 0;
 	device_reg_t __iomem *reg;
-	struct timer_list	tmp_intr_timer;
 	uint8_t		abort_active;
 	uint8_t		io_lock_on;
 	uint16_t	command;
@@ -72,7 +58,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 	 * non ISP abort time.
 	 */
 	if (!abort_active) {
-		if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) {
+		if (!wait_for_completion_timeout(&ha->mbx_cmd_comp,
+		    mcp->tov * HZ)) {
 			/* Timeout occurred. Return error. */
 			DEBUG2_3_11(printk("%s(%ld): cmd access timeout. "
 			    "Exiting.\n", __func__, ha->host_no));
@@ -135,22 +122,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 	/* Wait for mbx cmd completion until timeout */
 
 	if (!abort_active && io_lock_on) {
-		/* sleep on completion semaphore */
-		DEBUG11(printk("%s(%ld): INTERRUPT MODE. Initializing timer.\n",
-		    __func__, ha->host_no));
-
-		init_timer(&tmp_intr_timer);
-		tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem;
-		tmp_intr_timer.expires = jiffies + mcp->tov * HZ;
-		tmp_intr_timer.function =
-		    (void (*)(unsigned long))qla2x00_mbx_sem_timeout;
-
-		DEBUG11(printk("%s(%ld): Adding timer.\n", __func__,
-		    ha->host_no));
-		add_timer(&tmp_intr_timer);
-
-		DEBUG11(printk("%s(%ld): going to unlock & sleep. "
-		    "time=0x%lx.\n", __func__, ha->host_no, jiffies));
 
 		set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
 
@@ -160,17 +131,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 			WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-		/* Wait for either the timer to expire
-		 * or the mbox completion interrupt
-		 */
-		down(&ha->mbx_intr_sem);
+		wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ);
 
-		DEBUG11(printk("%s(%ld): waking up. time=0x%lx\n", __func__,
-		    ha->host_no, jiffies));
 		clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
 
-		/* delete the timer */
-		del_timer(&tmp_intr_timer);
 	} else {
 		DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
 		    ha->host_no, command));
@@ -299,7 +263,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
 
 	/* Allow next mbx cmd to come in. */
 	if (!abort_active)
-		up(&ha->mbx_cmd_sem);
+		complete(&ha->mbx_cmd_comp);
 
 	if (rval) {
 		DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, "
@@ -905,7 +869,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
 
 	mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
 	mcp->mb[9] = ha->vp_idx;
-	mcp->out_mb = MBX_0;
+	mcp->out_mb = MBX_9|MBX_0;
 	mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->tov = 30;
 	mcp->flags = 0;
@@ -1016,7 +980,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
 	DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
 	    ha->host_no));
 
-	if (ha->flags.npiv_supported)
+	if (ha->fw_attributes & BIT_2)
 		mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;
 	else
 		mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
@@ -2042,29 +2006,20 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map)
  */
 int
 qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
-    link_stat_t *ret_buf, uint16_t *status)
+    struct link_statistics *stats, dma_addr_t stats_dma)
 {
 	int rval;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
-	link_stat_t *stat_buf;
-	dma_addr_t stat_buf_dma;
+	uint32_t *siter, *diter, dwords;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-	stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma);
-	if (stat_buf == NULL) {
-		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
-		    __func__, ha->host_no));
-		return BIT_0;
-	}
-	memset(stat_buf, 0, sizeof(link_stat_t));
-
 	mcp->mb[0] = MBC_GET_LINK_STATUS;
-	mcp->mb[2] = MSW(stat_buf_dma);
-	mcp->mb[3] = LSW(stat_buf_dma);
-	mcp->mb[6] = MSW(MSD(stat_buf_dma));
-	mcp->mb[7] = LSW(MSD(stat_buf_dma));
+	mcp->mb[2] = MSW(stats_dma);
+	mcp->mb[3] = LSW(stats_dma);
+	mcp->mb[6] = MSW(MSD(stats_dma));
+	mcp->mb[7] = LSW(MSD(stats_dma));
 	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
 	mcp->in_mb = MBX_0;
 	if (IS_FWI2_CAPABLE(ha)) {
@@ -2089,78 +2044,43 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
 		if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
 			DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
 			    __func__, ha->host_no, mcp->mb[0]));
-			status[0] = mcp->mb[0];
-			rval = BIT_1;
+			rval = QLA_FUNCTION_FAILED;
 		} else {
-			/* copy over data -- firmware data is LE. */
-			ret_buf->link_fail_cnt =
-			    le32_to_cpu(stat_buf->link_fail_cnt);
-			ret_buf->loss_sync_cnt =
-			    le32_to_cpu(stat_buf->loss_sync_cnt);
-			ret_buf->loss_sig_cnt =
-			    le32_to_cpu(stat_buf->loss_sig_cnt);
-			ret_buf->prim_seq_err_cnt =
-			    le32_to_cpu(stat_buf->prim_seq_err_cnt);
-			ret_buf->inval_xmit_word_cnt =
-			    le32_to_cpu(stat_buf->inval_xmit_word_cnt);
-			ret_buf->inval_crc_cnt =
-			    le32_to_cpu(stat_buf->inval_crc_cnt);
-
-			DEBUG11(printk("%s(%ld): stat dump: fail_cnt=%d "
-			    "loss_sync=%d loss_sig=%d seq_err=%d "
-			    "inval_xmt_word=%d inval_crc=%d.\n", __func__,
-			    ha->host_no, stat_buf->link_fail_cnt,
-			    stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt,
-			    stat_buf->prim_seq_err_cnt,
-			    stat_buf->inval_xmit_word_cnt,
-			    stat_buf->inval_crc_cnt));
+			/* Copy over data -- firmware data is LE. */
+			dwords = offsetof(struct link_statistics, unused1) / 4;
+			siter = diter = &stats->link_fail_cnt;
+			while (dwords--)
+				*diter++ = le32_to_cpu(*siter++);
 		}
 	} else {
 		/* Failed. */
 		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
 		    ha->host_no, rval));
-		rval = BIT_1;
 	}
 
-	dma_pool_free(ha->s_dma_pool, stat_buf, stat_buf_dma);
-
 	return rval;
 }
 
 int
-qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
-    uint16_t *status)
+qla24xx_get_isp_stats(scsi_qla_host_t *ha, struct link_statistics *stats,
+    dma_addr_t stats_dma)
 {
 	int rval;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
-	uint32_t *sbuf, *siter;
-	dma_addr_t sbuf_dma;
+	uint32_t *siter, *diter, dwords;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-	if (dwords > (DMA_POOL_SIZE / 4)) {
-		DEBUG2_3_11(printk("%s(%ld): Unabled to retrieve %d DWORDs "
-		    "(max %d).\n", __func__, ha->host_no, dwords,
-		    DMA_POOL_SIZE / 4));
-		return BIT_0;
-	}
-	sbuf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &sbuf_dma);
-	if (sbuf == NULL) {
-		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
-		    __func__, ha->host_no));
-		return BIT_0;
-	}
-	memset(sbuf, 0, DMA_POOL_SIZE);
-
 	mcp->mb[0] = MBC_GET_LINK_PRIV_STATS;
-	mcp->mb[2] = MSW(sbuf_dma);
-	mcp->mb[3] = LSW(sbuf_dma);
-	mcp->mb[6] = MSW(MSD(sbuf_dma));
-	mcp->mb[7] = LSW(MSD(sbuf_dma));
-	mcp->mb[8] = dwords;
+	mcp->mb[2] = MSW(stats_dma);
+	mcp->mb[3] = LSW(stats_dma);
+	mcp->mb[6] = MSW(MSD(stats_dma));
+	mcp->mb[7] = LSW(MSD(stats_dma));
+	mcp->mb[8] = sizeof(struct link_statistics) / 4;
+	mcp->mb[9] = ha->vp_idx;
 	mcp->mb[10] = 0;
-	mcp->out_mb = MBX_10|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
 	mcp->in_mb = MBX_2|MBX_1|MBX_0;
 	mcp->tov = 30;
 	mcp->flags = IOCTL_CMD;
@@ -2170,23 +2090,20 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
 		if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
 			DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
 			    __func__, ha->host_no, mcp->mb[0]));
-			status[0] = mcp->mb[0];
-			rval = BIT_1;
+			rval = QLA_FUNCTION_FAILED;
 		} else {
 			/* Copy over data -- firmware data is LE. */
-			siter = sbuf;
+			dwords = sizeof(struct link_statistics) / 4;
+			siter = diter = &stats->link_fail_cnt;
 			while (dwords--)
-				*dwbuf++ = le32_to_cpu(*siter++);
+				*diter++ = le32_to_cpu(*siter++);
 		}
 	} else {
 		/* Failed. */
 		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
 		    ha->host_no, rval));
-		rval = BIT_1;
 	}
 
-	dma_pool_free(ha->s_dma_pool, sbuf, sbuf_dma);
-
 	return rval;
 }
 
@@ -2331,6 +2248,8 @@ atarget_done:
 	return rval;
 }
 
+#if 0
+
 int
 qla2x00_system_error(scsi_qla_host_t *ha)
 {
@@ -2360,47 +2279,7 @@ qla2x00_system_error(scsi_qla_host_t *ha)
 	return rval;
 }
 
-/**
- * qla2x00_get_serdes_params() -
- * @ha: HA context
- *
- * Returns
- */
-int
-qla2x00_get_serdes_params(scsi_qla_host_t *ha, uint16_t *sw_em_1g,
-    uint16_t *sw_em_2g, uint16_t *sw_em_4g)
-{
-	int rval;
-	mbx_cmd_t mc;
-	mbx_cmd_t *mcp = &mc;
-
-	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
-
-	mcp->mb[0] = MBC_SERDES_PARAMS;
-	mcp->mb[1] = 0;
-	mcp->out_mb = MBX_1|MBX_0;
-	mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_0;
-	mcp->tov = 30;
-	mcp->flags = 0;
-	rval = qla2x00_mailbox_command(ha, mcp);
-
-	if (rval != QLA_SUCCESS) {
-		/*EMPTY*/
-		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-		    ha->host_no, rval, mcp->mb[0]));
-	} else {
-		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
-
-		if (sw_em_1g)
-			*sw_em_1g = mcp->mb[2];
-		if (sw_em_2g)
-			*sw_em_2g = mcp->mb[3];
-		if (sw_em_4g)
-			*sw_em_4g = mcp->mb[4];
-	}
-
-	return rval;
-}
+#endif  /*  0  */
 
 /**
  * qla2x00_set_serdes_params() -
@@ -2471,7 +2350,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha)
 }
 
 int
-qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
+qla2x00_enable_eft_trace(scsi_qla_host_t *ha, dma_addr_t eft_dma,
     uint16_t buffers)
 {
 	int rval;
@@ -2484,22 +2363,18 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
 	mcp->mb[0] = MBC_TRACE_CONTROL;
-	mcp->mb[1] = ctrl;
-	mcp->out_mb = MBX_1|MBX_0;
+	mcp->mb[1] = TC_EFT_ENABLE;
+	mcp->mb[2] = LSW(eft_dma);
+	mcp->mb[3] = MSW(eft_dma);
+	mcp->mb[4] = LSW(MSD(eft_dma));
+	mcp->mb[5] = MSW(MSD(eft_dma));
+	mcp->mb[6] = buffers;
+	mcp->mb[7] = TC_AEN_DISABLE;
+	mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->in_mb = MBX_1|MBX_0;
-	if (ctrl == TC_ENABLE) {
-		mcp->mb[2] = LSW(eft_dma);
-		mcp->mb[3] = MSW(eft_dma);
-		mcp->mb[4] = LSW(MSD(eft_dma));
-		mcp->mb[5] = MSW(MSD(eft_dma));
-		mcp->mb[6] = buffers;
-		mcp->mb[7] = 0;
-		mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2;
-	}
 	mcp->tov = 30;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
-
 	if (rval != QLA_SUCCESS) {
 		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
 		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
@@ -2511,8 +2386,7 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
 }
 
 int
-qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
-    uint16_t off, uint16_t count)
+qla2x00_disable_eft_trace(scsi_qla_host_t *ha)
 {
 	int rval;
 	mbx_cmd_t mc;
@@ -2523,24 +2397,16 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-	mcp->mb[0] = MBC_READ_SFP;
-	mcp->mb[1] = addr;
-	mcp->mb[2] = MSW(sfp_dma);
-	mcp->mb[3] = LSW(sfp_dma);
-	mcp->mb[6] = MSW(MSD(sfp_dma));
-	mcp->mb[7] = LSW(MSD(sfp_dma));
-	mcp->mb[8] = count;
-	mcp->mb[9] = off;
-	mcp->mb[10] = 0;
-	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
-	mcp->in_mb = MBX_0;
+	mcp->mb[0] = MBC_TRACE_CONTROL;
+	mcp->mb[1] = TC_EFT_DISABLE;
+	mcp->out_mb = MBX_1|MBX_0;
+	mcp->in_mb = MBX_1|MBX_0;
 	mcp->tov = 30;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
-
 	if (rval != QLA_SUCCESS) {
-		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
-		    ha->host_no, rval, mcp->mb[0]));
+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
+		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
 	} else {
 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
 	}
@@ -2549,176 +2415,168 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
 }
 
 int
-qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
-    uint16_t *port_speed, uint16_t *mb)
+qla2x00_enable_fce_trace(scsi_qla_host_t *ha, dma_addr_t fce_dma,
+    uint16_t buffers, uint16_t *mb, uint32_t *dwords)
 {
 	int rval;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_IIDMA_CAPABLE(ha))
+	if (!IS_QLA25XX(ha))
 		return QLA_FUNCTION_FAILED;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-	mcp->mb[0] = MBC_PORT_PARAMS;
-	mcp->mb[1] = loop_id;
-	mcp->mb[2] = mcp->mb[3] = mcp->mb[4] = mcp->mb[5] = 0;
-	mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
-	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
+	mcp->mb[0] = MBC_TRACE_CONTROL;
+	mcp->mb[1] = TC_FCE_ENABLE;
+	mcp->mb[2] = LSW(fce_dma);
+	mcp->mb[3] = MSW(fce_dma);
+	mcp->mb[4] = LSW(MSD(fce_dma));
+	mcp->mb[5] = MSW(MSD(fce_dma));
+	mcp->mb[6] = buffers;
+	mcp->mb[7] = TC_AEN_DISABLE;
+	mcp->mb[8] = 0;
+	mcp->mb[9] = TC_FCE_DEFAULT_RX_SIZE;
+	mcp->mb[10] = TC_FCE_DEFAULT_TX_SIZE;
+	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|
+	    MBX_1|MBX_0;
+	mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->tov = 30;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
-
-	/* Return mailbox statuses. */
-	if (mb != NULL) {
-		mb[0] = mcp->mb[0];
-		mb[1] = mcp->mb[1];
-		mb[3] = mcp->mb[3];
-		mb[4] = mcp->mb[4];
-		mb[5] = mcp->mb[5];
-	}
-
 	if (rval != QLA_SUCCESS) {
-		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-		    ha->host_no, rval));
+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
+		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
 	} else {
 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
-		if (port_speed)
-			*port_speed = mcp->mb[3];
+
+		if (mb)
+			memcpy(mb, mcp->mb, 8 * sizeof(*mb));
+		if (dwords)
+			*dwords = mcp->mb[6];
 	}
 
 	return rval;
 }
 
 int
-qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
-    uint16_t port_speed, uint16_t *mb)
+qla2x00_disable_fce_trace(scsi_qla_host_t *ha, uint64_t *wr, uint64_t *rd)
 {
 	int rval;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_IIDMA_CAPABLE(ha))
+	if (!IS_FWI2_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-	mcp->mb[0] = MBC_PORT_PARAMS;
-	mcp->mb[1] = loop_id;
-	mcp->mb[2] = BIT_0;
-	mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
-	mcp->mb[4] = mcp->mb[5] = 0;
-	mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
-	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
+	mcp->mb[0] = MBC_TRACE_CONTROL;
+	mcp->mb[1] = TC_FCE_DISABLE;
+	mcp->mb[2] = TC_FCE_DISABLE_TRACE;
+	mcp->out_mb = MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|
+	    MBX_1|MBX_0;
 	mcp->tov = 30;
 	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
-
-	/* Return mailbox statuses. */
-	if (mb != NULL) {
-		mb[0] = mcp->mb[0];
-		mb[1] = mcp->mb[1];
-		mb[3] = mcp->mb[3];
-		mb[4] = mcp->mb[4];
-		mb[5] = mcp->mb[5];
-	}
-
 	if (rval != QLA_SUCCESS) {
-		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
-		    ha->host_no, rval));
+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
+		    __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
 	} else {
 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+
+		if (wr)
+			*wr = (uint64_t) mcp->mb[5] << 48 |
+			    (uint64_t) mcp->mb[4] << 32 |
+			    (uint64_t) mcp->mb[3] << 16 |
+			    (uint64_t) mcp->mb[2];
+		if (rd)
+			*rd = (uint64_t) mcp->mb[9] << 48 |
+			    (uint64_t) mcp->mb[8] << 32 |
+			    (uint64_t) mcp->mb[7] << 16 |
+			    (uint64_t) mcp->mb[6];
 	}
 
 	return rval;
 }
 
-/*
- * qla24xx_get_vp_database
- *	Get the VP's database for all configured ports.
- *
- * Input:
- *	ha = adapter block pointer.
- *	size = size of initialization control block.
- *
- * Returns:
- *	qla2x00 local function return status code.
- *
- * Context:
- *	Kernel context.
- */
 int
-qla24xx_get_vp_database(scsi_qla_host_t *ha, uint16_t size)
+qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
+    uint16_t off, uint16_t count)
 {
 	int rval;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	DEBUG11(printk("scsi(%ld):%s - entered.\n",
-	    ha->host_no, __func__));
+	if (!IS_FWI2_CAPABLE(ha))
+		return QLA_FUNCTION_FAILED;
 
-	mcp->mb[0] = MBC_MID_GET_VP_DATABASE;
-	mcp->mb[2] = MSW(ha->init_cb_dma);
-	mcp->mb[3] = LSW(ha->init_cb_dma);
-	mcp->mb[4] = 0;
-	mcp->mb[5] = 0;
-	mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
-	mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
-	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
-	mcp->in_mb = MBX_1|MBX_0;
-	mcp->buf_size = size;
-	mcp->flags = MBX_DMA_OUT;
-	mcp->tov = MBX_TOV_SECONDS;
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	mcp->mb[0] = MBC_READ_SFP;
+	mcp->mb[1] = addr;
+	mcp->mb[2] = MSW(sfp_dma);
+	mcp->mb[3] = LSW(sfp_dma);
+	mcp->mb[6] = MSW(MSD(sfp_dma));
+	mcp->mb[7] = LSW(MSD(sfp_dma));
+	mcp->mb[8] = count;
+	mcp->mb[9] = off;
+	mcp->mb[10] = 0;
+	mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
 
 	if (rval != QLA_SUCCESS) {
-		/*EMPTY*/
-		DEBUG2_3_11(printk("%s(%ld): failed=%x "
-		    "mb0=%x.\n",
-		    __func__, ha->host_no, rval, mcp->mb[0]));
+		DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
+		    ha->host_no, rval, mcp->mb[0]));
 	} else {
-		/*EMPTY*/
-		DEBUG11(printk("%s(%ld): done.\n",
-		    __func__, ha->host_no));
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
 	}
 
 	return rval;
 }
 
 int
-qla24xx_get_vp_entry(scsi_qla_host_t *ha, uint16_t size, int vp_id)
+qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
+    uint16_t port_speed, uint16_t *mb)
 {
 	int rval;
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
+	if (!IS_IIDMA_CAPABLE(ha))
+		return QLA_FUNCTION_FAILED;
+
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-	mcp->mb[0] = MBC_MID_GET_VP_ENTRY;
-	mcp->mb[2] = MSW(ha->init_cb_dma);
-	mcp->mb[3] = LSW(ha->init_cb_dma);
-	mcp->mb[4] = 0;
-	mcp->mb[5] = 0;
-	mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
-	mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
-	mcp->mb[9] = vp_id;
-	mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
-	mcp->in_mb = MBX_0;
-	mcp->buf_size = size;
-	mcp->flags = MBX_DMA_OUT;
+	mcp->mb[0] = MBC_PORT_PARAMS;
+	mcp->mb[1] = loop_id;
+	mcp->mb[2] = BIT_0;
+	mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
+	mcp->mb[4] = mcp->mb[5] = 0;
+	mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
 	mcp->tov = 30;
+	mcp->flags = 0;
 	rval = qla2x00_mailbox_command(ha, mcp);
 
+	/* Return mailbox statuses. */
+	if (mb != NULL) {
+		mb[0] = mcp->mb[0];
+		mb[1] = mcp->mb[1];
+		mb[3] = mcp->mb[3];
+		mb[4] = mcp->mb[4];
+		mb[5] = mcp->mb[5];
+	}
+
 	if (rval != QLA_SUCCESS) {
-		/*EMPTY*/
-		DEBUG2_3_11(printk("qla24xx_get_vp_entry(%ld): failed=%x "
-		    "mb0=%x.\n",
-		    ha->host_no, rval, mcp->mb[0]));
+		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+		    ha->host_no, rval));
 	} else {
-		/*EMPTY*/
-		DEBUG11(printk("qla24xx_get_vp_entry(%ld): done.\n",
-		    ha->host_no));
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
 	}
 
 	return rval;
@@ -2873,7 +2731,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
 	DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__,
 	    ha->host_no, vp_index));
 
-	if (vp_index == 0 || vp_index >= MAX_MULTI_ID_LOOP)
+	if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
 		return QLA_PARAMETER_ERROR;
 
 	vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma);
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 821ee74aadc6..cf784cdafb01 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -39,7 +39,7 @@ qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
 	}
 }
 
-uint32_t
+static uint32_t
 qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
 {
 	uint32_t vp_id;
@@ -47,16 +47,15 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
 
 	/* Find an empty slot and assign an vp_id */
 	down(&ha->vport_sem);
-	vp_id = find_first_zero_bit((unsigned long *)ha->vp_idx_map,
-				MAX_MULTI_ID_FABRIC);
-	if (vp_id > MAX_MULTI_ID_FABRIC) {
-		DEBUG15(printk ("vp_id %d is bigger than MAX_MULTI_ID_FABRID\n",
-		    vp_id));
+	vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1);
+	if (vp_id > ha->max_npiv_vports) {
+		DEBUG15(printk ("vp_id %d is bigger than max-supported %d.\n",
+		    vp_id, ha->max_npiv_vports));
 		up(&ha->vport_sem);
 		return vp_id;
 	}
 
-	set_bit(vp_id, (unsigned long *)ha->vp_idx_map);
+	set_bit(vp_id, ha->vp_idx_map);
 	ha->num_vhosts++;
 	vha->vp_idx = vp_id;
 	list_add_tail(&vha->vp_list, &ha->vp_list);
@@ -73,12 +72,12 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
 	down(&ha->vport_sem);
 	vp_id = vha->vp_idx;
 	ha->num_vhosts--;
-	clear_bit(vp_id, (unsigned long *)ha->vp_idx_map);
+	clear_bit(vp_id, ha->vp_idx_map);
 	list_del(&vha->vp_list);
 	up(&ha->vport_sem);
 }
 
-scsi_qla_host_t *
+static scsi_qla_host_t *
 qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
 {
 	scsi_qla_host_t *vha;
@@ -216,11 +215,7 @@ qla2x00_alert_all_vps(scsi_qla_host_t *ha, uint16_t *mb)
 	if (ha->parent)
 		return;
 
-	i = find_next_bit((unsigned long *)ha->vp_idx_map,
-	    MAX_MULTI_ID_FABRIC + 1, 1);
-	for (;i <= MAX_MULTI_ID_FABRIC;
-	    i = find_next_bit((unsigned long *)ha->vp_idx_map,
-	    MAX_MULTI_ID_FABRIC + 1, i + 1)) {
+	for_each_mapped_vp_idx(ha, i) {
 		vp_idx_matched = 0;
 
 		list_for_each_entry(vha, &ha->vp_list, vp_list) {
@@ -270,7 +265,7 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
 	qla24xx_enable_vp(vha);
 }
 
-int
+static int
 qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
 {
 	if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
@@ -311,11 +306,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
 
 	clear_bit(VP_DPC_NEEDED, &ha->dpc_flags);
 
-	i = find_next_bit((unsigned long *)ha->vp_idx_map,
-	    MAX_MULTI_ID_FABRIC + 1, 1);
-	for (;i <= MAX_MULTI_ID_FABRIC;
-	    i = find_next_bit((unsigned long *)ha->vp_idx_map,
-	    MAX_MULTI_ID_FABRIC + 1, i + 1)) {
+	for_each_mapped_vp_idx(ha, i) {
 		vp_idx_matched = 0;
 
 		list_for_each_entry(vha, &ha->vp_list, vp_list) {
@@ -350,15 +341,17 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
 
 	/* Check up unique WWPN */
 	u64_to_wwn(fc_vport->port_name, port_name);
+	if (!memcmp(port_name, ha->port_name, WWN_SIZE))
+		return VPCERR_BAD_WWN;
 	vha = qla24xx_find_vhost_by_name(ha, port_name);
 	if (vha)
 		return VPCERR_BAD_WWN;
 
 	/* Check up max-npiv-supports */
 	if (ha->num_vhosts > ha->max_npiv_vports) {
-		DEBUG15(printk("scsi(%ld): num_vhosts %d is bigger than "
-		    "max_npv_vports %d.\n", ha->host_no,
-		    (uint16_t) ha->num_vhosts, (int) ha->max_npiv_vports));
+		DEBUG15(printk("scsi(%ld): num_vhosts %ud is bigger than "
+		    "max_npv_vports %ud.\n", ha->host_no,
+		    ha->num_vhosts, ha->max_npiv_vports));
 		return VPCERR_UNSUPPORTED;
 	}
 	return 0;
@@ -412,8 +405,9 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 	}
 	vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
 
-	init_MUTEX(&vha->mbx_cmd_sem);
-	init_MUTEX_LOCKED(&vha->mbx_intr_sem);
+	init_completion(&vha->mbx_cmd_comp);
+	complete(&vha->mbx_cmd_comp);
+	init_completion(&vha->mbx_intr_comp);
 
 	INIT_LIST_HEAD(&vha->list);
 	INIT_LIST_HEAD(&vha->fcports);
@@ -450,7 +444,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 	num_hosts++;
 
 	down(&ha->vport_sem);
-	set_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
+	set_bit(vha->vp_idx, ha->vp_idx_map);
 	ha->cur_vport_count++;
 	up(&ha->vport_sem);
 
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 8ecc0470b8f3..3954ed2d7b51 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -105,13 +105,12 @@ static int qla2xxx_eh_abort(struct scsi_cmnd *);
 static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
 static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
 static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
-static int qla2x00_loop_reset(scsi_qla_host_t *ha);
 static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
 
 static int qla2x00_change_queue_depth(struct scsi_device *, int);
 static int qla2x00_change_queue_type(struct scsi_device *, int);
 
-struct scsi_host_template qla2x00_driver_template = {
+static struct scsi_host_template qla2x00_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= QLA2XXX_DRIVER_NAME,
 	.queuecommand		= qla2x00_queuecommand,
@@ -132,7 +131,6 @@ struct scsi_host_template qla2x00_driver_template = {
 	.this_id		= -1,
 	.cmd_per_lun		= 3,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 	.sg_tablesize		= SG_ALL,
 
 	/*
@@ -164,7 +162,6 @@ struct scsi_host_template qla24xx_driver_template = {
 	.this_id		= -1,
 	.cmd_per_lun		= 3,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 	.sg_tablesize		= SG_ALL,
 
 	.max_sectors		= 0xFFFF,
@@ -179,13 +176,6 @@ struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
  * Timer routines
  */
 
-void qla2x00_timer(scsi_qla_host_t *);
-
-__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
-    void *, unsigned long);
-static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
-__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
-
 __inline__ void
 qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
 {
@@ -203,7 +193,7 @@ qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
 	mod_timer(&ha->timer, jiffies + interval * HZ);
 }
 
-__inline__ void
+static __inline__ void
 qla2x00_stop_timer(scsi_qla_host_t *ha)
 {
 	del_timer_sync(&ha->timer);
@@ -214,12 +204,11 @@ static int qla2x00_do_dpc(void *data);
 
 static void qla2x00_rst_aen(scsi_qla_host_t *);
 
-uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
-void qla2x00_mem_free(scsi_qla_host_t *ha);
+static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+static void qla2x00_mem_free(scsi_qla_host_t *ha);
 static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
 static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
 static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
-void qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *);
 
 /* -------------------------------------------------------------------------- */
 
@@ -1060,7 +1049,7 @@ eh_host_reset_lock:
 * Returns:
 *      0 = success
 */
-static int
+int
 qla2x00_loop_reset(scsi_qla_host_t *ha)
 {
 	int ret;
@@ -1479,8 +1468,7 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha)
 static int
 qla2x00_iospace_config(scsi_qla_host_t *ha)
 {
-	unsigned long	pio, pio_len, pio_flags;
-	unsigned long	mmio, mmio_len, mmio_flags;
+	resource_size_t pio;
 
 	if (pci_request_selected_regions(ha->pdev, ha->bars,
 	    QLA2XXX_DRIVER_NAME)) {
@@ -1495,10 +1483,8 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
 
 	/* We only need PIO for Flash operations on ISP2312 v2 chips. */
 	pio = pci_resource_start(ha->pdev, 0);
-	pio_len = pci_resource_len(ha->pdev, 0);
-	pio_flags = pci_resource_flags(ha->pdev, 0);
-	if (pio_flags & IORESOURCE_IO) {
-		if (pio_len < MIN_IOBASE_LEN) {
+	if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) {
+		if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) {
 			qla_printk(KERN_WARNING, ha,
 			    "Invalid PCI I/O region size (%s)...\n",
 				pci_name(ha->pdev));
@@ -1511,28 +1497,23 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
 		pio = 0;
 	}
 	ha->pio_address = pio;
-	ha->pio_length = pio_len;
 
 skip_pio:
 	/* Use MMIO operations for all accesses. */
-	mmio = pci_resource_start(ha->pdev, 1);
-	mmio_len = pci_resource_len(ha->pdev, 1);
-	mmio_flags = pci_resource_flags(ha->pdev, 1);
-
-	if (!(mmio_flags & IORESOURCE_MEM)) {
+	if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) {
 		qla_printk(KERN_ERR, ha,
-		    "region #0 not an MMIO resource (%s), aborting\n",
+		    "region #1 not an MMIO resource (%s), aborting\n",
 		    pci_name(ha->pdev));
 		goto iospace_error_exit;
 	}
-	if (mmio_len < MIN_IOBASE_LEN) {
+	if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) {
 		qla_printk(KERN_ERR, ha,
 		    "Invalid PCI mem region size (%s), aborting\n",
 			pci_name(ha->pdev));
 		goto iospace_error_exit;
 	}
 
-	ha->iobase = ioremap(mmio, MIN_IOBASE_LEN);
+	ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN);
 	if (!ha->iobase) {
 		qla_printk(KERN_ERR, ha,
 		    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
@@ -1701,9 +1682,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	/* load the F/W, read paramaters, and init the H/W */
 	ha->instance = num_hosts;
 
-	init_MUTEX(&ha->mbx_cmd_sem);
 	init_MUTEX(&ha->vport_sem);
-	init_MUTEX_LOCKED(&ha->mbx_intr_sem);
+	init_completion(&ha->mbx_cmd_comp);
+	complete(&ha->mbx_cmd_comp);
+	init_completion(&ha->mbx_intr_comp);
 
 	INIT_LIST_HEAD(&ha->list);
 	INIT_LIST_HEAD(&ha->fcports);
@@ -1807,6 +1789,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	qla2x00_init_host_attr(ha);
 
+	qla2x00_dfs_setup(ha);
+
 	qla_printk(KERN_INFO, ha, "\n"
 	    " QLogic Fibre Channel HBA Driver: %s\n"
 	    "  QLogic %s - %s\n"
@@ -1838,6 +1822,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
 
 	ha = pci_get_drvdata(pdev);
 
+	qla2x00_dfs_remove(ha);
+
 	qla2x00_free_sysfs_attr(ha);
 
 	fc_remove_host(ha->host);
@@ -1871,8 +1857,11 @@ qla2x00_free_device(scsi_qla_host_t *ha)
 		kthread_stop(t);
 	}
 
+	if (ha->flags.fce_enabled)
+		qla2x00_disable_fce_trace(ha, NULL, NULL);
+
 	if (ha->eft)
-		qla2x00_trace_control(ha, TC_DISABLE, 0, 0);
+		qla2x00_disable_eft_trace(ha);
 
 	ha->flags.online = 0;
 
@@ -2016,7 +2005,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
 *      0  = success.
 *      1  = failure.
 */
-uint8_t
+static uint8_t
 qla2x00_mem_alloc(scsi_qla_host_t *ha)
 {
 	char	name[16];
@@ -2213,7 +2202,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
 * Input:
 *      ha = adapter block pointer.
 */
-void
+static void
 qla2x00_mem_free(scsi_qla_host_t *ha)
 {
 	struct list_head	*fcpl, *fcptemp;
@@ -2228,6 +2217,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
 	/* free sp pool */
 	qla2x00_free_sp_pool(ha);
 
+	if (ha->fce)
+		dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
+		    ha->fce_dma);
+
 	if (ha->fw_dump) {
 		if (ha->eft)
 			dma_free_coherent(&ha->pdev->dev,
@@ -2748,23 +2741,6 @@ qla2x00_timer(scsi_qla_host_t *ha)
 	qla2x00_restart_timer(ha, WATCH_INTERVAL);
 }
 
-/* XXX(hch): crude hack to emulate a down_timeout() */
-int
-qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
-{
-	const unsigned int step = 100; /* msecs */
-	unsigned int iterations = jiffies_to_msecs(timeout)/100;
-
-	do {
-		if (!down_trylock(sema))
-			return 0;
-		if (msleep_interruptible(step))
-			break;
-	} while (--iterations > 0);
-
-	return -ETIMEDOUT;
-}
-
 /* Firmware interface routines. */
 
 #define FW_BLOBS	6
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index ad2fa01bd233..b68fb73613ed 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -22,7 +22,7 @@ static void qla2x00_nv_write(scsi_qla_host_t *, uint16_t);
  * qla2x00_lock_nvram_access() -
  * @ha: HA context
  */
-void
+static void
 qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
 {
 	uint16_t data;
@@ -55,7 +55,7 @@ qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
  * qla2x00_unlock_nvram_access() -
  * @ha: HA context
  */
-void
+static void
 qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
 {
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
@@ -74,7 +74,7 @@ qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
  *
  * Returns the word read from nvram @addr.
  */
-uint16_t
+static uint16_t
 qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
 {
 	uint16_t	data;
@@ -93,7 +93,7 @@ qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
  * @addr: Address in NVRAM to write
  * @data: word to program
  */
-void
+static void
 qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data)
 {
 	int count;
@@ -550,7 +550,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
 	int ret;
 	uint32_t liter, miter;
 	uint32_t sec_mask, rest_addr, conf_addr;
-	uint32_t fdata, findex ;
+	uint32_t fdata, findex, cnt;
 	uint8_t	man_id, flash_id;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 	dma_addr_t optrom_dma;
@@ -690,8 +690,14 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
 			    0xff0000) | ((fdata >> 16) & 0xff));
 	}
 
-	/* Enable flash write-protection. */
+	/* Enable flash write-protection and wait for completion. */
 	qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
+	for (cnt = 300; cnt &&
+	    qla24xx_read_flash_dword(ha,
+		    flash_conf_to_access_addr(0x005)) & BIT_0;
+	    cnt--) {
+		udelay(10);
+	}
 
 	/* Disable flash write. */
 	WRT_REG_DWORD(&reg->ctrl_status,
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index ae6f7a2fb19f..2c2f6b4697c7 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.02.00-k5"
+#define QLA2XXX_VERSION      "8.02.00-k7"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	2
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index d692c713416a..cbe0a17ced5f 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -5,6 +5,7 @@
  * See LICENSE.qla4xxx for copyright and licensing details.
  */
 
+#include <scsi/iscsi_if.h>
 #include "ql4_def.h"
 #include "ql4_glbl.h"
 #include "ql4_dbg.h"
@@ -1305,7 +1306,8 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
 		atomic_set(&ddb_entry->relogin_timer, 0);
 		clear_bit(DF_RELOGIN, &ddb_entry->flags);
 		clear_bit(DF_NO_RELOGIN, &ddb_entry->flags);
-		iscsi_if_create_session_done(ddb_entry->conn);
+		iscsi_session_event(ddb_entry->sess,
+				    ISCSI_KEVENT_CREATE_SESSION);
 		/*
 		 * Change the lun state to READY in case the lun TIMEOUT before
 		 * the device came back.
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 4a154beb0d39..0f029d0d7315 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -123,15 +123,14 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
 			break;
 
 		/* Copy Sense Data into sense buffer. */
-		memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+		memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 
 		sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
 		if (sensebytecnt == 0)
 			break;
 
 		memcpy(cmd->sense_buffer, sts_entry->senseData,
-		       min(sensebytecnt,
-			   (uint16_t) sizeof(cmd->sense_buffer)));
+		       min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
 
 		DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
 			      "ASC/ASCQ = %02x/%02x\n", ha->host_no,
@@ -208,8 +207,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
 				break;
 
 			/* Copy Sense Data into sense buffer. */
-			memset(cmd->sense_buffer, 0,
-			       sizeof(cmd->sense_buffer));
+			memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 
 			sensebytecnt =
 				le16_to_cpu(sts_entry->senseDataByteCnt);
@@ -217,8 +215,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
 				break;
 
 			memcpy(cmd->sense_buffer, sts_entry->senseData,
-			       min(sensebytecnt,
-				   (uint16_t) sizeof(cmd->sense_buffer)));
+			       min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE));
 
 			DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
 				      "ASC/ASCQ = %02x/%02x\n", ha->host_no,
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 89460d27c689..2e2b9fedffcc 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -94,7 +94,6 @@ static struct scsi_host_template qla4xxx_driver_template = {
 	.this_id		= -1,
 	.cmd_per_lun		= 3,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 	.sg_tablesize		= SG_ALL,
 
 	.max_sectors		= 0xFFFF,
@@ -173,18 +172,6 @@ static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag)
 		printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
 }
 
-static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
-{
-	int i;
-	char *cp = buf;
-
-	for (i = 0; i < len; i++)
-		cp += sprintf(cp, "%02x%c", addr[i],
-			      i == (len - 1) ? '\n' : ':');
-	return cp - buf;
-}
-
-
 static int qla4xxx_host_get_param(struct Scsi_Host *shost,
 				  enum iscsi_host_param param, char *buf)
 {
@@ -193,7 +180,7 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost,
 
 	switch (param) {
 	case ISCSI_HOST_PARAM_HWADDRESS:
-		len = format_addr(buf, ha->my_mac, MAC_ADDR_LEN);
+		len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN);
 		break;
 	case ISCSI_HOST_PARAM_IPADDRESS:
 		len = sprintf(buf, "%d.%d.%d.%d\n", ha->ip_address[0],
@@ -298,8 +285,7 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry)
 		return;
 
 	if (ddb_entry->conn) {
-		iscsi_if_destroy_session_done(ddb_entry->conn);
-		iscsi_destroy_conn(ddb_entry->conn);
+		atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
 		iscsi_remove_session(ddb_entry->sess);
 	}
 	iscsi_free_session(ddb_entry->sess);
@@ -309,6 +295,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
 {
 	int err;
 
+	ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
 	err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index);
 	if (err) {
 		DEBUG2(printk(KERN_ERR "Could not add session.\n"));
@@ -321,9 +308,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
 		DEBUG2(printk(KERN_ERR "Could not add connection.\n"));
 		return -ENOMEM;
 	}
-
-	ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
-	iscsi_if_create_session_done(ddb_entry->conn);
 	return 0;
 }
 
diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
index 1769f965eedf..1e874f1fb5c6 100644
--- a/drivers/scsi/qlogicfas.c
+++ b/drivers/scsi/qlogicfas.c
@@ -197,7 +197,6 @@ static struct scsi_host_template qlogicfas_driver_template = {
 	.sg_tablesize		= SG_ALL,
 	.cmd_per_lun		= 1,
 	.use_clustering		= DISABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 };
 
 static __init int qlogicfas_init(void)
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 7a2e7986b038..65455ab1f3b9 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -871,11 +871,12 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
 	struct scatterlist *sg, *s;
 	int i, n;
 
-	if (Cmnd->use_sg) {
+	if (scsi_bufflen(Cmnd)) {
 		int sg_count;
 
-		sg = (struct scatterlist *) Cmnd->request_buffer;
-		sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction);
+		sg = scsi_sglist(Cmnd);
+		sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd),
+		                                      Cmnd->sc_data_direction);
 
 		ds = cmd->dataseg;
 		cmd->segment_cnt = sg_count;
@@ -914,16 +915,6 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
 			}
 			sg_count -= n;
 		}
-	} else if (Cmnd->request_bufflen) {
-		Cmnd->SCp.ptr = (char *)(unsigned long)
-			sbus_map_single(qpti->sdev,
-					Cmnd->request_buffer,
-					Cmnd->request_bufflen,
-					Cmnd->sc_data_direction);
-
-		cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr);
-		cmd->dataseg[0].d_count = Cmnd->request_bufflen;
-		cmd->segment_cnt = 1;
 	} else {
 		cmd->dataseg[0].d_base = 0;
 		cmd->dataseg[0].d_count = 0;
@@ -1151,7 +1142,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
 
 		if (sts->state_flags & SF_GOT_SENSE)
 			memcpy(Cmnd->sense_buffer, sts->req_sense_data,
-			       sizeof(Cmnd->sense_buffer));
+			       SCSI_SENSE_BUFFERSIZE);
 
 		if (sts->hdr.entry_type == ENTRY_STATUS)
 			Cmnd->result =
@@ -1159,17 +1150,11 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
 		else
 			Cmnd->result = DID_ERROR << 16;
 
-		if (Cmnd->use_sg) {
+		if (scsi_bufflen(Cmnd))
 			sbus_unmap_sg(qpti->sdev,
-				      (struct scatterlist *)Cmnd->request_buffer,
-				      Cmnd->use_sg,
+				      scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
 				      Cmnd->sc_data_direction);
-		} else if (Cmnd->request_bufflen) {
-			sbus_unmap_single(qpti->sdev,
-					  (__u32)((unsigned long)Cmnd->SCp.ptr),
-					  Cmnd->request_bufflen,
-					  Cmnd->sc_data_direction);
-		}
+
 		qpti->cmd_count[Cmnd->device->id]--;
 		sbus_writew(out_ptr, qpti->qregs + MBOX5);
 		Cmnd->host_scribble = (unsigned char *) done_queue;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 0fb1709ce5e3..b35d19472caa 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -122,6 +122,11 @@ static const char *const scsi_device_types[] = {
 	"Automation/Drive ",
 };
 
+/**
+ * scsi_device_type - Return 17 char string indicating device type.
+ * @type: type number to look up
+ */
+
 const char * scsi_device_type(unsigned type)
 {
 	if (type == 0x1e)
@@ -136,32 +141,45 @@ const char * scsi_device_type(unsigned type)
 EXPORT_SYMBOL(scsi_device_type);
 
 struct scsi_host_cmd_pool {
-	struct kmem_cache	*slab;
-	unsigned int	users;
-	char		*name;
-	unsigned int	slab_flags;
-	gfp_t		gfp_mask;
+	struct kmem_cache	*cmd_slab;
+	struct kmem_cache	*sense_slab;
+	unsigned int		users;
+	char			*cmd_name;
+	char			*sense_name;
+	unsigned int		slab_flags;
+	gfp_t			gfp_mask;
 };
 
 static struct scsi_host_cmd_pool scsi_cmd_pool = {
-	.name		= "scsi_cmd_cache",
+	.cmd_name	= "scsi_cmd_cache",
+	.sense_name	= "scsi_sense_cache",
 	.slab_flags	= SLAB_HWCACHE_ALIGN,
 };
 
 static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
-	.name		= "scsi_cmd_cache(DMA)",
+	.cmd_name	= "scsi_cmd_cache(DMA)",
+	.sense_name	= "scsi_sense_cache(DMA)",
 	.slab_flags	= SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA,
 	.gfp_mask	= __GFP_DMA,
 };
 
 static DEFINE_MUTEX(host_cmd_pool_mutex);
 
+/**
+ * __scsi_get_command - Allocate a struct scsi_cmnd
+ * @shost: host to transmit command
+ * @gfp_mask: allocation mask
+ *
+ * Description: allocate a struct scsi_cmd from host's slab, recycling from the
+ *              host's free_list if necessary.
+ */
 struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
 {
 	struct scsi_cmnd *cmd;
+	unsigned char *buf;
 
-	cmd = kmem_cache_alloc(shost->cmd_pool->slab,
-			gfp_mask | shost->cmd_pool->gfp_mask);
+	cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab,
+			       gfp_mask | shost->cmd_pool->gfp_mask);
 
 	if (unlikely(!cmd)) {
 		unsigned long flags;
@@ -173,19 +191,32 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
 			list_del_init(&cmd->list);
 		}
 		spin_unlock_irqrestore(&shost->free_list_lock, flags);
+
+		if (cmd) {
+			buf = cmd->sense_buffer;
+			memset(cmd, 0, sizeof(*cmd));
+			cmd->sense_buffer = buf;
+		}
+	} else {
+		buf = kmem_cache_alloc(shost->cmd_pool->sense_slab,
+				       gfp_mask | shost->cmd_pool->gfp_mask);
+		if (likely(buf)) {
+			memset(cmd, 0, sizeof(*cmd));
+			cmd->sense_buffer = buf;
+		} else {
+			kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
+			cmd = NULL;
+		}
 	}
 
 	return cmd;
 }
 EXPORT_SYMBOL_GPL(__scsi_get_command);
 
-/*
- * Function:	scsi_get_command()
- *
- * Purpose:	Allocate and setup a scsi command block
- *
- * Arguments:	dev	- parent scsi device
- *		gfp_mask- allocator flags
+/**
+ * scsi_get_command - Allocate and setup a scsi command block
+ * @dev: parent scsi device
+ * @gfp_mask: allocator flags
  *
  * Returns:	The allocated scsi command structure.
  */
@@ -202,7 +233,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
 	if (likely(cmd != NULL)) {
 		unsigned long flags;
 
-		memset(cmd, 0, sizeof(*cmd));
 		cmd->device = dev;
 		init_timer(&cmd->eh_timeout);
 		INIT_LIST_HEAD(&cmd->list);
@@ -217,6 +247,12 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
 }
 EXPORT_SYMBOL(scsi_get_command);
 
+/**
+ * __scsi_put_command - Free a struct scsi_cmnd
+ * @shost: dev->host
+ * @cmd: Command to free
+ * @dev: parent scsi device
+ */
 void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
 			struct device *dev)
 {
@@ -230,19 +266,19 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd,
 	}
 	spin_unlock_irqrestore(&shost->free_list_lock, flags);
 
-	if (likely(cmd != NULL))
-		kmem_cache_free(shost->cmd_pool->slab, cmd);
+	if (likely(cmd != NULL)) {
+		kmem_cache_free(shost->cmd_pool->sense_slab,
+				cmd->sense_buffer);
+		kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
+	}
 
 	put_device(dev);
 }
 EXPORT_SYMBOL(__scsi_put_command);
 
-/*
- * Function:	scsi_put_command()
- *
- * Purpose:	Free a scsi command block
- *
- * Arguments:	cmd	- command block to free
+/**
+ * scsi_put_command - Free a scsi command block
+ * @cmd: command block to free
  *
  * Returns:	Nothing.
  *
@@ -263,12 +299,13 @@ void scsi_put_command(struct scsi_cmnd *cmd)
 }
 EXPORT_SYMBOL(scsi_put_command);
 
-/*
- * Function:	scsi_setup_command_freelist()
- *
- * Purpose:	Setup the command freelist for a scsi host.
+/**
+ * scsi_setup_command_freelist - Setup the command freelist for a scsi host.
+ * @shost: host to allocate the freelist for.
  *
- * Arguments:	shost	- host to allocate the freelist for.
+ * Description: The command freelist protects against system-wide out of memory
+ * deadlock by preallocating one SCSI command structure for each host, so the
+ * system can always write to a swap file on a device associated with that host.
  *
  * Returns:	Nothing.
  */
@@ -282,16 +319,24 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
 
 	/*
 	 * Select a command slab for this host and create it if not
-	 * yet existant.
+	 * yet existent.
 	 */
 	mutex_lock(&host_cmd_pool_mutex);
 	pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool);
 	if (!pool->users) {
-		pool->slab = kmem_cache_create(pool->name,
-				sizeof(struct scsi_cmnd), 0,
-				pool->slab_flags, NULL);
-		if (!pool->slab)
+		pool->cmd_slab = kmem_cache_create(pool->cmd_name,
+						   sizeof(struct scsi_cmnd), 0,
+						   pool->slab_flags, NULL);
+		if (!pool->cmd_slab)
+			goto fail;
+
+		pool->sense_slab = kmem_cache_create(pool->sense_name,
+						     SCSI_SENSE_BUFFERSIZE, 0,
+						     pool->slab_flags, NULL);
+		if (!pool->sense_slab) {
+			kmem_cache_destroy(pool->cmd_slab);
 			goto fail;
+		}
 	}
 
 	pool->users++;
@@ -301,29 +346,36 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
 	/*
 	 * Get one backup command for this host.
 	 */
-	cmd = kmem_cache_alloc(shost->cmd_pool->slab,
-			GFP_KERNEL | shost->cmd_pool->gfp_mask);
+	cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab,
+			       GFP_KERNEL | shost->cmd_pool->gfp_mask);
 	if (!cmd)
 		goto fail2;
-	list_add(&cmd->list, &shost->free_list);		
+
+	cmd->sense_buffer = kmem_cache_alloc(shost->cmd_pool->sense_slab,
+					     GFP_KERNEL |
+					     shost->cmd_pool->gfp_mask);
+	if (!cmd->sense_buffer)
+		goto fail2;
+
+	list_add(&cmd->list, &shost->free_list);
 	return 0;
 
  fail2:
-	if (!--pool->users)
-		kmem_cache_destroy(pool->slab);
-	return -ENOMEM;
+	if (cmd)
+		kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
+	mutex_lock(&host_cmd_pool_mutex);
+	if (!--pool->users) {
+		kmem_cache_destroy(pool->cmd_slab);
+		kmem_cache_destroy(pool->sense_slab);
+	}
  fail:
 	mutex_unlock(&host_cmd_pool_mutex);
 	return -ENOMEM;
-
 }
 
-/*
- * Function:	scsi_destroy_command_freelist()
- *
- * Purpose:	Release the command freelist for a scsi host.
- *
- * Arguments:	shost	- host that's freelist is going to be destroyed
+/**
+ * scsi_destroy_command_freelist - Release the command freelist for a scsi host.
+ * @shost: host whose freelist is going to be destroyed
  */
 void scsi_destroy_command_freelist(struct Scsi_Host *shost)
 {
@@ -332,12 +384,16 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
 
 		cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
 		list_del_init(&cmd->list);
-		kmem_cache_free(shost->cmd_pool->slab, cmd);
+		kmem_cache_free(shost->cmd_pool->sense_slab,
+				cmd->sense_buffer);
+		kmem_cache_free(shost->cmd_pool->cmd_slab, cmd);
 	}
 
 	mutex_lock(&host_cmd_pool_mutex);
-	if (!--shost->cmd_pool->users)
-		kmem_cache_destroy(shost->cmd_pool->slab);
+	if (!--shost->cmd_pool->users) {
+		kmem_cache_destroy(shost->cmd_pool->cmd_slab);
+		kmem_cache_destroy(shost->cmd_pool->sense_slab);
+	}
 	mutex_unlock(&host_cmd_pool_mutex);
 }
 
@@ -441,8 +497,12 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
 }
 #endif
 
-/* 
- * Assign a serial number to the request for error recovery
+/**
+ * scsi_cmd_get_serial - Assign a serial number to a command
+ * @host: the scsi host
+ * @cmd: command to assign serial number to
+ *
+ * Description: a serial number identifies a request for error recovery
  * and debugging purposes.  Protected by the Host_Lock of host.
  */
 static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
@@ -452,14 +512,12 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd
 		cmd->serial_number = host->cmd_serial_number++;
 }
 
-/*
- * Function:    scsi_dispatch_command
- *
- * Purpose:     Dispatch a command to the low-level driver.
- *
- * Arguments:   cmd - command block we are dispatching.
+/**
+ * scsi_dispatch_command - Dispatch a command to the low-level driver.
+ * @cmd: command block we are dispatching.
  *
- * Notes:
+ * Return: nonzero return request was rejected and device's queue needs to be
+ * plugged.
  */
 int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 {
@@ -585,7 +643,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 
 /**
  * scsi_req_abort_cmd -- Request command recovery for the specified command
- * cmd: pointer to the SCSI command of interest
+ * @cmd: pointer to the SCSI command of interest
  *
  * This function requests that SCSI Core start recovery for the
  * command by deleting the timer and adding the command to the eh
@@ -606,9 +664,9 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
  * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
  * ownership back to SCSI Core -- i.e. the LLDD has finished with it.
  *
- * This function is the mid-level's (SCSI Core) interrupt routine, which
- * regains ownership of the SCSI command (de facto) from a LLDD, and enqueues
- * the command to the done queue for further processing.
+ * Description: This function is the mid-level's (SCSI Core) interrupt routine,
+ * which regains ownership of the SCSI command (de facto) from a LLDD, and
+ * enqueues the command to the done queue for further processing.
  *
  * This is the producer of the done queue who enqueues at the tail.
  *
@@ -617,7 +675,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
 static void scsi_done(struct scsi_cmnd *cmd)
 {
 	/*
-	 * We don't have to worry about this one timing out any more.
+	 * We don't have to worry about this one timing out anymore.
 	 * If we are unable to remove the timer, then the command
 	 * has already timed out.  In which case, we have no choice but to
 	 * let the timeout function run, as we have no idea where in fact
@@ -660,10 +718,11 @@ static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
 	return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
 }
 
-/*
- * Function:    scsi_finish_command
+/**
+ * scsi_finish_command - cleanup and pass command back to upper layer
+ * @cmd: the command
  *
- * Purpose:     Pass command off to upper layer for finishing of I/O
+ * Description: Pass command off to upper layer for finishing of I/O
  *              request, waking processes that are waiting on results,
  *              etc.
  */
@@ -698,7 +757,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
 				"Notifying upper driver of completion "
 				"(result %x)\n", cmd->result));
 
-	good_bytes = cmd->request_bufflen;
+	good_bytes = scsi_bufflen(cmd);
         if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
 		drv = scsi_cmd_to_driver(cmd);
 		if (drv->done)
@@ -708,18 +767,14 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
 }
 EXPORT_SYMBOL(scsi_finish_command);
 
-/*
- * Function:	scsi_adjust_queue_depth()
- *
- * Purpose:	Allow low level drivers to tell us to change the queue depth
- * 		on a specific SCSI device
- *
- * Arguments:	sdev	- SCSI Device in question
- * 		tagged	- Do we use tagged queueing (non-0) or do we treat
- * 			  this device as an untagged device (0)
- * 		tags	- Number of tags allowed if tagged queueing enabled,
- * 			  or number of commands the low level driver can
- * 			  queue up in non-tagged mode (as per cmd_per_lun).
+/**
+ * scsi_adjust_queue_depth - Let low level drivers change a device's queue depth
+ * @sdev: SCSI Device in question
+ * @tagged: Do we use tagged queueing (non-0) or do we treat
+ *          this device as an untagged device (0)
+ * @tags: Number of tags allowed if tagged queueing enabled,
+ *        or number of commands the low level driver can
+ *        queue up in non-tagged mode (as per cmd_per_lun).
  *
  * Returns:	Nothing
  *
@@ -742,8 +797,8 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
 
 	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
 
-	/* Check to see if the queue is managed by the block layer
-	 * if it is, and we fail to adjust the depth, exit */
+	/* Check to see if the queue is managed by the block layer.
+	 * If it is, and we fail to adjust the depth, exit. */
 	if (blk_queue_tagged(sdev->request_queue) &&
 	    blk_queue_resize_tags(sdev->request_queue, tags) != 0)
 		goto out;
@@ -772,20 +827,17 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
 }
 EXPORT_SYMBOL(scsi_adjust_queue_depth);
 
-/*
- * Function:	scsi_track_queue_full()
+/**
+ * scsi_track_queue_full - track QUEUE_FULL events to adjust queue depth
+ * @sdev: SCSI Device in question
+ * @depth: Current number of outstanding SCSI commands on this device,
+ *         not counting the one returned as QUEUE_FULL.
  *
- * Purpose:	This function will track successive QUEUE_FULL events on a
+ * Description:	This function will track successive QUEUE_FULL events on a
  * 		specific SCSI device to determine if and when there is a
  * 		need to adjust the queue depth on the device.
  *
- * Arguments:	sdev	- SCSI Device in question
- * 		depth	- Current number of outstanding SCSI commands on
- * 			  this device, not counting the one returned as
- * 			  QUEUE_FULL.
- *
- * Returns:	0 - No change needed
- * 		>0 - Adjust queue depth to this new depth
+ * Returns:	0 - No change needed, >0 - Adjust queue depth to this new depth,
  * 		-1 - Drop back to untagged operation using host->cmd_per_lun
  * 			as the untagged command depth
  *
@@ -824,10 +876,10 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
 EXPORT_SYMBOL(scsi_track_queue_full);
 
 /**
- * scsi_device_get  -  get an addition reference to a scsi_device
+ * scsi_device_get  -  get an additional reference to a scsi_device
  * @sdev:	device to get a reference to
  *
- * Gets a reference to the scsi_device and increments the use count
+ * Description: Gets a reference to the scsi_device and increments the use count
  * of the underlying LLDD module.  You must hold host_lock of the
  * parent Scsi_Host or already have a reference when calling this.
  */
@@ -849,8 +901,8 @@ EXPORT_SYMBOL(scsi_device_get);
  * scsi_device_put  -  release a reference to a scsi_device
  * @sdev:	device to release a reference on.
  *
- * Release a reference to the scsi_device and decrements the use count
- * of the underlying LLDD module.  The device is freed once the last
+ * Description: Release a reference to the scsi_device and decrements the use
+ * count of the underlying LLDD module.  The device is freed once the last
  * user vanishes.
  */
 void scsi_device_put(struct scsi_device *sdev)
@@ -867,7 +919,7 @@ void scsi_device_put(struct scsi_device *sdev)
 }
 EXPORT_SYMBOL(scsi_device_put);
 
-/* helper for shost_for_each_device, thus not documented */
+/* helper for shost_for_each_device, see that for documentation */
 struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost,
 					   struct scsi_device *prev)
 {
@@ -895,6 +947,8 @@ EXPORT_SYMBOL(__scsi_iterate_devices);
 /**
  * starget_for_each_device  -  helper to walk all devices of a target
  * @starget:	target whose devices we want to iterate over.
+ * @data:	Opaque passed to each function call.
+ * @fn:		Function to call on each device
  *
  * This traverses over each device of @starget.  The devices have
  * a reference that must be released by scsi_host_put when breaking
@@ -946,13 +1000,13 @@ EXPORT_SYMBOL(__starget_for_each_device);
  * @starget:	SCSI target pointer
  * @lun:	SCSI Logical Unit Number
  *
- * Looks up the scsi_device with the specified @lun for a give
- * @starget. The returned scsi_device does not have an additional
+ * Description: Looks up the scsi_device with the specified @lun for a given
+ * @starget.  The returned scsi_device does not have an additional
  * reference.  You must hold the host's host_lock over this call and
  * any access to the returned scsi_device.
  *
- * Note:  The only reason why drivers would want to use this is because
- * they're need to access the device list in irq context.  Otherwise you
+ * Note:  The only reason why drivers should use this is because
+ * they need to access the device list in irq context.  Otherwise you
  * really want to use scsi_device_lookup_by_target instead.
  **/
 struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget,
@@ -974,9 +1028,9 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target);
  * @starget:	SCSI target pointer
  * @lun:	SCSI Logical Unit Number
  *
- * Looks up the scsi_device with the specified @channel, @id, @lun for a
- * give host.  The returned scsi_device has an additional reference that
- * needs to be release with scsi_host_put once you're done with it.
+ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
+ * for a given host.  The returned scsi_device has an additional reference that
+ * needs to be released with scsi_device_put once you're done with it.
  **/
 struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
 						 uint lun)
@@ -996,19 +1050,19 @@ struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
 EXPORT_SYMBOL(scsi_device_lookup_by_target);
 
 /**
- * scsi_device_lookup - find a device given the host (UNLOCKED)
+ * __scsi_device_lookup - find a device given the host (UNLOCKED)
  * @shost:	SCSI host pointer
  * @channel:	SCSI channel (zero if only one channel)
- * @pun:	SCSI target number (physical unit number)
+ * @id:		SCSI target number (physical unit number)
  * @lun:	SCSI Logical Unit Number
  *
- * Looks up the scsi_device with the specified @channel, @id, @lun for a
- * give host. The returned scsi_device does not have an additional reference.
- * You must hold the host's host_lock over this call and any access to the
- * returned scsi_device.
+ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
+ * for a given host. The returned scsi_device does not have an additional
+ * reference.  You must hold the host's host_lock over this call and any access
+ * to the returned scsi_device.
  *
  * Note:  The only reason why drivers would want to use this is because
- * they're need to access the device list in irq context.  Otherwise you
+ * they need to access the device list in irq context.  Otherwise you
  * really want to use scsi_device_lookup instead.
  **/
 struct scsi_device *__scsi_device_lookup(struct Scsi_Host *shost,
@@ -1033,9 +1087,9 @@ EXPORT_SYMBOL(__scsi_device_lookup);
  * @id:		SCSI target number (physical unit number)
  * @lun:	SCSI Logical Unit Number
  *
- * Looks up the scsi_device with the specified @channel, @id, @lun for a
- * give host.  The returned scsi_device has an additional reference that
- * needs to be release with scsi_host_put once you're done with it.
+ * Description: Looks up the scsi_device with the specified @channel, @id, @lun
+ * for a given host.  The returned scsi_device has an additional reference that
+ * needs to be released with scsi_device_put once you're done with it.
  **/
 struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost,
 		uint channel, uint id, uint lun)
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 46cae5a212de..1541c174937a 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -280,6 +280,8 @@ static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
 		      unsigned int num, struct sdebug_dev_info * devip);
 static int resp_report_luns(struct scsi_cmnd * SCpnt,
 			    struct sdebug_dev_info * devip);
+static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
+			    unsigned int num, struct sdebug_dev_info *devip);
 static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
                                 int arr_len);
 static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
@@ -311,12 +313,48 @@ static void sdebug_max_tgts_luns(void);
 static struct device pseudo_primary;
 static struct bus_type pseudo_lld_bus;
 
+static void get_data_transfer_info(unsigned char *cmd,
+				   unsigned long long *lba, unsigned int *num)
+{
+	int i;
+
+	switch (*cmd) {
+	case WRITE_16:
+	case READ_16:
+		for (*lba = 0, i = 0; i < 8; ++i) {
+			if (i > 0)
+				*lba <<= 8;
+			*lba += cmd[2 + i];
+		}
+		*num = cmd[13] + (cmd[12] << 8) +
+			(cmd[11] << 16) + (cmd[10] << 24);
+		break;
+	case WRITE_12:
+	case READ_12:
+		*lba = cmd[5] + (cmd[4] << 8) +	(cmd[3] << 16) + (cmd[2] << 24);
+		*num = cmd[9] + (cmd[8] << 8) +	(cmd[7] << 16) + (cmd[6] << 24);
+		break;
+	case WRITE_10:
+	case READ_10:
+	case XDWRITEREAD_10:
+		*lba = cmd[5] + (cmd[4] << 8) +	(cmd[3] << 16) + (cmd[2] << 24);
+		*num = cmd[8] + (cmd[7] << 8);
+		break;
+	case WRITE_6:
+	case READ_6:
+		*lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
+		*num = (0 == cmd[4]) ? 256 : cmd[4];
+		break;
+	default:
+		break;
+	}
+}
 
 static
 int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
 {
 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
-	int len, k, j;
+	int len, k;
 	unsigned int num;
 	unsigned long long lba;
 	int errsts = 0;
@@ -329,7 +367,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
 	if (done == NULL)
 		return 0;	/* assume mid level reprocessing command */
 
-	SCpnt->resid = 0;
+	scsi_set_resid(SCpnt, 0);
 	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
 		printk(KERN_INFO "scsi_debug: cmd ");
 		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
@@ -452,28 +490,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
 			break;
 		if (scsi_debug_fake_rw)
 			break;
-		if ((*cmd) == READ_16) {
-			for (lba = 0, j = 0; j < 8; ++j) {
-				if (j > 0)
-					lba <<= 8;
-				lba += cmd[2 + j];
-			}
-			num = cmd[13] + (cmd[12] << 8) +
-				(cmd[11] << 16) + (cmd[10] << 24);
-		} else if ((*cmd) == READ_12) {
-			lba = cmd[5] + (cmd[4] << 8) +
-				(cmd[3] << 16) + (cmd[2] << 24);
-			num = cmd[9] + (cmd[8] << 8) +
-				(cmd[7] << 16) + (cmd[6] << 24);
-		} else if ((*cmd) == READ_10) {
-			lba = cmd[5] + (cmd[4] << 8) +
-				(cmd[3] << 16) + (cmd[2] << 24);
-			num = cmd[8] + (cmd[7] << 8);
-		} else {	/* READ (6) */
-			lba = cmd[3] + (cmd[2] << 8) +
-				((cmd[1] & 0x1f) << 16);
-			num = (0 == cmd[4]) ? 256 : cmd[4];
-		}
+		get_data_transfer_info(cmd, &lba, &num);
 		errsts = resp_read(SCpnt, lba, num, devip);
 		if (inj_recovered && (0 == errsts)) {
 			mk_sense_buffer(devip, RECOVERED_ERROR,
@@ -500,28 +517,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
 			break;
 		if (scsi_debug_fake_rw)
 			break;
-		if ((*cmd) == WRITE_16) {
-			for (lba = 0, j = 0; j < 8; ++j) {
-				if (j > 0)
-					lba <<= 8;
-				lba += cmd[2 + j];
-			}
-			num = cmd[13] + (cmd[12] << 8) +
-				(cmd[11] << 16) + (cmd[10] << 24);
-		} else if ((*cmd) == WRITE_12) {
-			lba = cmd[5] + (cmd[4] << 8) +
-				(cmd[3] << 16) + (cmd[2] << 24);
-			num = cmd[9] + (cmd[8] << 8) +
-				(cmd[7] << 16) + (cmd[6] << 24);
-		} else if ((*cmd) == WRITE_10) {
-			lba = cmd[5] + (cmd[4] << 8) +
-				(cmd[3] << 16) + (cmd[2] << 24);
-			num = cmd[8] + (cmd[7] << 8);
-		} else {	/* WRITE (6) */
-			lba = cmd[3] + (cmd[2] << 8) +
-				((cmd[1] & 0x1f) << 16);
-			num = (0 == cmd[4]) ? 256 : cmd[4];
-		}
+		get_data_transfer_info(cmd, &lba, &num);
 		errsts = resp_write(SCpnt, lba, num, devip);
 		if (inj_recovered && (0 == errsts)) {
 			mk_sense_buffer(devip, RECOVERED_ERROR,
@@ -549,6 +545,28 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
 	case WRITE_BUFFER:
 		errsts = check_readiness(SCpnt, 1, devip);
 		break;
+	case XDWRITEREAD_10:
+		if (!scsi_bidi_cmnd(SCpnt)) {
+			mk_sense_buffer(devip, ILLEGAL_REQUEST,
+					INVALID_FIELD_IN_CDB, 0);
+			errsts = check_condition_result;
+			break;
+		}
+
+		errsts = check_readiness(SCpnt, 0, devip);
+		if (errsts)
+			break;
+		if (scsi_debug_fake_rw)
+			break;
+		get_data_transfer_info(cmd, &lba, &num);
+		errsts = resp_read(SCpnt, lba, num, devip);
+		if (errsts)
+			break;
+		errsts = resp_write(SCpnt, lba, num, devip);
+		if (errsts)
+			break;
+		errsts = resp_xdwriteread(SCpnt, lba, num, devip);
+		break;
 	default:
 		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
@@ -601,28 +619,18 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
 	int k, req_len, act_len, len, active;
 	void * kaddr;
 	void * kaddr_off;
-	struct scatterlist * sg;
+	struct scatterlist *sg;
+	struct scsi_data_buffer *sdb = scsi_in(scp);
 
-	if (0 == scp->request_bufflen)
+	if (!sdb->length)
 		return 0;
-	if (NULL == scp->request_buffer)
+	if (!sdb->table.sgl)
 		return (DID_ERROR << 16);
-	if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
-	      (scp->sc_data_direction == DMA_FROM_DEVICE)))
+	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
 		return (DID_ERROR << 16);
-	if (0 == scp->use_sg) {
-		req_len = scp->request_bufflen;
-		act_len = (req_len < arr_len) ? req_len : arr_len;
-		memcpy(scp->request_buffer, arr, act_len);
-		if (scp->resid)
-			scp->resid -= act_len;
-		else
-			scp->resid = req_len - act_len;
-		return 0;
-	}
 	active = 1;
 	req_len = act_len = 0;
-	scsi_for_each_sg(scp, sg, scp->use_sg, k) {
+	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, k) {
 		if (active) {
 			kaddr = (unsigned char *)
 				kmap_atomic(sg_page(sg), KM_USER0);
@@ -640,10 +648,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
 		}
 		req_len += sg->length;
 	}
-	if (scp->resid)
-		scp->resid -= act_len;
+	if (sdb->resid)
+		sdb->resid -= act_len;
 	else
-		scp->resid = req_len - act_len;
+		sdb->resid = req_len - act_len;
 	return 0;
 }
 
@@ -656,22 +664,14 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
 	void * kaddr_off;
 	struct scatterlist * sg;
 
-	if (0 == scp->request_bufflen)
+	if (0 == scsi_bufflen(scp))
 		return 0;
-	if (NULL == scp->request_buffer)
+	if (NULL == scsi_sglist(scp))
 		return -1;
-	if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
-	      (scp->sc_data_direction == DMA_TO_DEVICE)))
+	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
 		return -1;
-	if (0 == scp->use_sg) {
-		req_len = scp->request_bufflen;
-		len = (req_len < max_arr_len) ? req_len : max_arr_len;
-		memcpy(arr, scp->request_buffer, len);
-		return len;
-	}
-	sg = scsi_sglist(scp);
 	req_len = fin = 0;
-	for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) {
+	scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
 		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
 		if (NULL == kaddr)
 			return -1;
@@ -1973,6 +1973,50 @@ static int resp_report_luns(struct scsi_cmnd * scp,
 				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
 }
 
+static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
+			    unsigned int num, struct sdebug_dev_info *devip)
+{
+	int i, j, ret = -1;
+	unsigned char *kaddr, *buf;
+	unsigned int offset;
+	struct scatterlist *sg;
+	struct scsi_data_buffer *sdb = scsi_in(scp);
+
+	/* better not to use temporary buffer. */
+	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
+	if (!buf)
+		return ret;
+
+	offset = 0;
+	scsi_for_each_sg(scp, sg, scsi_sg_count(scp), i) {
+		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
+		if (!kaddr)
+			goto out;
+
+		memcpy(buf + offset, kaddr + sg->offset, sg->length);
+		offset += sg->length;
+		kunmap_atomic(kaddr, KM_USER0);
+	}
+
+	offset = 0;
+	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
+		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
+		if (!kaddr)
+			goto out;
+
+		for (j = 0; j < sg->length; j++)
+			*(kaddr + sg->offset + j) ^= *(buf + offset + j);
+
+		offset += sg->length;
+		kunmap_atomic(kaddr, KM_USER0);
+	}
+	ret = 0;
+out:
+	kfree(buf);
+
+	return ret;
+}
+
 /* When timer goes off this function is called. */
 static void timer_intr_handler(unsigned long indx)
 {
@@ -2006,6 +2050,7 @@ static int scsi_debug_slave_alloc(struct scsi_device * sdp)
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
 		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+	set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
 	return 0;
 }
 
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 348cc5a6e3cd..b8de041bc0ae 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -276,11 +276,12 @@ static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
 }
 
 /**
- * scsi_dev_info_list_add: add one dev_info list entry.
+ * scsi_dev_info_list_add - add one dev_info list entry.
+ * @compatible: if true, null terminate short strings.  Otherwise space pad.
  * @vendor:	vendor string
  * @model:	model (product) string
  * @strflags:	integer string
- * @flag:	if strflags NULL, use this flag value
+ * @flags:	if strflags NULL, use this flag value
  *
  * Description:
  * 	Create and add one dev_info entry for @vendor, @model, @strflags or
@@ -322,8 +323,7 @@ static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
 }
 
 /**
- * scsi_dev_info_list_add_str: parse dev_list and add to the
- * scsi_dev_info_list.
+ * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list.
  * @dev_list:	string of device flags to add
  *
  * Description:
@@ -374,15 +374,15 @@ static int scsi_dev_info_list_add_str(char *dev_list)
 }
 
 /**
- * get_device_flags - get device specific flags from the dynamic device
- * list. Called during scan time.
+ * get_device_flags - get device specific flags from the dynamic device list.
+ * @sdev:       &scsi_device to get flags for
  * @vendor:	vendor name
  * @model:	model name
  *
  * Description:
  *     Search the scsi_dev_info_list for an entry matching @vendor and
  *     @model, if found, return the matching flags value, else return
- *     the host or global default settings.
+ *     the host or global default settings.  Called during scan time.
  **/
 int scsi_get_device_flags(struct scsi_device *sdev,
 			  const unsigned char *vendor,
@@ -483,13 +483,11 @@ stop_output:
 }
 
 /* 
- * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
- * /proc.
+ * proc_scsi_dev_info_write - allow additions to scsi_dev_info_list via /proc.
  *
- * Use: echo "vendor:model:flag" > /proc/scsi/device_info
- *
- * To add a black/white list entry for vendor and model with an integer
- * value of flag to the scsi device info list.
+ * Description: Adds a black/white list entry for vendor and model with an
+ * integer value of flag to the scsi device info list.
+ * To use, echo "vendor:model:flag" > /proc/scsi/device_info
  */
 static int proc_scsi_devinfo_write(struct file *file, const char __user *buf,
 				   unsigned long length, void *data)
@@ -532,8 +530,7 @@ MODULE_PARM_DESC(default_dev_flags,
 		 "scsi default device flag integer value");
 
 /**
- * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove
- * 	the scsi_dev_info_list.
+ * scsi_dev_info_list_delete - called from scsi.c:exit_scsi to remove the scsi_dev_info_list.
  **/
 void scsi_exit_devinfo(void)
 {
@@ -552,13 +549,12 @@ void scsi_exit_devinfo(void)
 }
 
 /**
- * scsi_dev_list_init: set up the dynamic device list.
- * @dev_list:	string of device flags to add
+ * scsi_init_devinfo - set up the dynamic device list.
  *
  * Description:
- * 	Add command line @dev_list entries, then add
+ * 	Add command line entries from scsi_dev_flags, then add
  * 	scsi_static_device_list entries to the scsi device info list.
- **/
+ */
 int __init scsi_init_devinfo(void)
 {
 #ifdef CONFIG_SCSI_PROC_FS
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index ebaca4ca4a13..045a0868fc7b 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -62,7 +62,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost)
  * @shost:	SCSI host to invoke error handling on.
  *
  * Schedule SCSI EH without scmd.
- **/
+ */
 void scsi_schedule_eh(struct Scsi_Host *shost)
 {
 	unsigned long flags;
@@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh);
  *
  * Return value:
  *	0 on failure.
- **/
+ */
 int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
 {
 	struct Scsi_Host *shost = scmd->device->host;
@@ -121,7 +121,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
  *    This should be turned into an inline function.  Each scsi command
  *    has its own timer, and as it is added to the queue, we set up the
  *    timer.  When the command completes, we cancel the timer.
- **/
+ */
 void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
 		    void (*complete)(struct scsi_cmnd *))
 {
@@ -155,7 +155,7 @@ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
  * Return value:
  *     1 if we were able to detach the timer.  0 if we blew it, and the
  *     timer function has already started to run.
- **/
+ */
 int scsi_delete_timer(struct scsi_cmnd *scmd)
 {
 	int rtn;
@@ -181,7 +181,7 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
  *     only in that the normal completion handling might run, but if the
  *     normal completion function determines that the timer has already
  *     fired, then it mustn't do anything.
- **/
+ */
 void scsi_times_out(struct scsi_cmnd *scmd)
 {
 	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
@@ -224,7 +224,7 @@ void scsi_times_out(struct scsi_cmnd *scmd)
  *
  * Return value:
  *     0 when dev was taken offline by error recovery. 1 OK to proceed.
- **/
+ */
 int scsi_block_when_processing_errors(struct scsi_device *sdev)
 {
 	int online;
@@ -245,7 +245,7 @@ EXPORT_SYMBOL(scsi_block_when_processing_errors);
  * scsi_eh_prt_fail_stats - Log info on failures.
  * @shost:	scsi host being recovered.
  * @work_q:	Queue of scsi cmds to process.
- **/
+ */
 static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
 					  struct list_head *work_q)
 {
@@ -295,7 +295,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
  * Notes:
  *	When a deferred error is detected the current command has
  *	not been executed and needs retrying.
- **/
+ */
 static int scsi_check_sense(struct scsi_cmnd *scmd)
 {
 	struct scsi_sense_hdr sshdr;
@@ -398,7 +398,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
  *    queued during error recovery.  the main difference here is that we
  *    don't allow for the possibility of retries here, and we are a lot
  *    more restrictive about what we consider acceptable.
- **/
+ */
 static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
 {
 	/*
@@ -452,7 +452,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
 /**
  * scsi_eh_done - Completion function for error handling.
  * @scmd:	Cmd that is done.
- **/
+ */
 static void scsi_eh_done(struct scsi_cmnd *scmd)
 {
 	struct completion     *eh_action;
@@ -469,7 +469,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
 /**
  * scsi_try_host_reset - ask host adapter to reset itself
  * @scmd:	SCSI cmd to send hsot reset.
- **/
+ */
 static int scsi_try_host_reset(struct scsi_cmnd *scmd)
 {
 	unsigned long flags;
@@ -498,7 +498,7 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd)
 /**
  * scsi_try_bus_reset - ask host to perform a bus reset
  * @scmd:	SCSI cmd to send bus reset.
- **/
+ */
 static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
 {
 	unsigned long flags;
@@ -533,7 +533,7 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
  *    unreliable for a given host, then the host itself needs to put a
  *    timer on it, and set the host back to a consistent state prior to
  *    returning.
- **/
+ */
 static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
 {
 	int rtn;
@@ -568,7 +568,7 @@ static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
  *    author of the low-level driver wishes this operation to be timed,
  *    they can provide this facility themselves.  helper functions in
  *    scsi_error.c can be supplied to make this easier to do.
- **/
+ */
 static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
 {
 	/*
@@ -601,7 +601,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
  * sent must be one that does not transfer any data.  If @sense_bytes != 0
  * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
  * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
- **/
+ */
 void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
 			unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
 {
@@ -617,29 +617,27 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
 	ses->cmd_len = scmd->cmd_len;
 	memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
 	ses->data_direction = scmd->sc_data_direction;
-	ses->bufflen = scmd->request_bufflen;
-	ses->buffer = scmd->request_buffer;
-	ses->use_sg = scmd->use_sg;
-	ses->resid = scmd->resid;
+	ses->sdb = scmd->sdb;
+	ses->next_rq = scmd->request->next_rq;
 	ses->result = scmd->result;
 
+	memset(&scmd->sdb, 0, sizeof(scmd->sdb));
+	scmd->request->next_rq = NULL;
+
 	if (sense_bytes) {
-		scmd->request_bufflen = min_t(unsigned,
-		                       sizeof(scmd->sense_buffer), sense_bytes);
+		scmd->sdb.length = min_t(unsigned, SCSI_SENSE_BUFFERSIZE,
+					 sense_bytes);
 		sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
-		                                       scmd->request_bufflen);
-		scmd->request_buffer = &ses->sense_sgl;
+			    scmd->sdb.length);
+		scmd->sdb.table.sgl = &ses->sense_sgl;
 		scmd->sc_data_direction = DMA_FROM_DEVICE;
-		scmd->use_sg = 1;
+		scmd->sdb.table.nents = 1;
 		memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
 		scmd->cmnd[0] = REQUEST_SENSE;
-		scmd->cmnd[4] = scmd->request_bufflen;
+		scmd->cmnd[4] = scmd->sdb.length;
 		scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
 	} else {
-		scmd->request_buffer = NULL;
-		scmd->request_bufflen = 0;
 		scmd->sc_data_direction = DMA_NONE;
-		scmd->use_sg = 0;
 		if (cmnd) {
 			memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
 			memcpy(scmd->cmnd, cmnd, cmnd_size);
@@ -657,7 +655,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
 	 * Zero the sense buffer.  The scsi spec mandates that any
 	 * untransferred sense data should be interpreted as being zero.
 	 */
-	memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+	memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 }
 EXPORT_SYMBOL(scsi_eh_prep_cmnd);
 
@@ -667,7 +665,7 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd);
  * @ses:        saved information from a coresponding call to scsi_prep_eh_cmnd
  *
  * Undo any damage done by above scsi_prep_eh_cmnd().
- **/
+ */
 void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
 {
 	/*
@@ -676,10 +674,8 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
 	scmd->cmd_len = ses->cmd_len;
 	memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
 	scmd->sc_data_direction = ses->data_direction;
-	scmd->request_bufflen = ses->bufflen;
-	scmd->request_buffer = ses->buffer;
-	scmd->use_sg = ses->use_sg;
-	scmd->resid = ses->resid;
+	scmd->sdb = ses->sdb;
+	scmd->request->next_rq = ses->next_rq;
 	scmd->result = ses->result;
 }
 EXPORT_SYMBOL(scsi_eh_restore_cmnd);
@@ -697,7 +693,7 @@ EXPORT_SYMBOL(scsi_eh_restore_cmnd);
  *
  * Return value:
  *    SUCCESS or FAILED or NEEDS_RETRY
- **/
+ */
 static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
 			     int cmnd_size, int timeout, unsigned sense_bytes)
 {
@@ -765,7 +761,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
  *    Some hosts automatically obtain this information, others require
  *    that we obtain it on our own. This function will *not* return until
  *    the command either times out, or it completes.
- **/
+ */
 static int scsi_request_sense(struct scsi_cmnd *scmd)
 {
 	return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0);
@@ -779,10 +775,10 @@ static int scsi_request_sense(struct scsi_cmnd *scmd)
  * Notes:
  *    We don't want to use the normal command completion while we are are
  *    still handling errors - it may cause other commands to be queued,
- *    and that would disturb what we are doing.  thus we really want to
+ *    and that would disturb what we are doing.  Thus we really want to
  *    keep a list of pending commands for final completion, and once we
  *    are ready to leave error handling we handle completion for real.
- **/
+ */
 void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
 {
 	scmd->device->host->host_failed--;
@@ -794,7 +790,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
 /**
  * scsi_eh_get_sense - Get device sense data.
  * @work_q:	Queue of commands to process.
- * @done_q:	Queue of proccessed commands..
+ * @done_q:	Queue of processed commands.
  *
  * Description:
  *    See if we need to request sense information.  if so, then get it
@@ -802,7 +798,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
  *
  * Notes:
  *    This has the unfortunate side effect that if a shost adapter does
- *    not automatically request sense information, that we end up shutting
+ *    not automatically request sense information, we end up shutting
  *    it down before we request it.
  *
  *    All drivers should request sense information internally these days,
@@ -810,7 +806,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd);
  *
  *    XXX: Long term this code should go away, but that needs an audit of
  *         all LLDDs first.
- **/
+ */
 int scsi_eh_get_sense(struct list_head *work_q,
 		      struct list_head *done_q)
 {
@@ -858,11 +854,11 @@ EXPORT_SYMBOL_GPL(scsi_eh_get_sense);
 
 /**
  * scsi_eh_tur - Send TUR to device.
- * @scmd:	Scsi cmd to send TUR
+ * @scmd:	&scsi_cmnd to send TUR
  *
  * Return value:
  *    0 - Device is ready. 1 - Device NOT ready.
- **/
+ */
 static int scsi_eh_tur(struct scsi_cmnd *scmd)
 {
 	static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
@@ -887,17 +883,17 @@ retry_tur:
 }
 
 /**
- * scsi_eh_abort_cmds - abort canceled commands.
- * @shost:	scsi host being recovered.
- * @eh_done_q:	list_head for processed commands.
+ * scsi_eh_abort_cmds - abort pending commands.
+ * @work_q:	&list_head for pending commands.
+ * @done_q:	&list_head for processed commands.
  *
  * Decription:
  *    Try and see whether or not it makes sense to try and abort the
- *    running command.  this only works out to be the case if we have one
- *    command that has timed out.  if the command simply failed, it makes
+ *    running command.  This only works out to be the case if we have one
+ *    command that has timed out.  If the command simply failed, it makes
  *    no sense to try and abort the command, since as far as the shost
  *    adapter is concerned, it isn't running.
- **/
+ */
 static int scsi_eh_abort_cmds(struct list_head *work_q,
 			      struct list_head *done_q)
 {
@@ -931,11 +927,11 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
 
 /**
  * scsi_eh_try_stu - Send START_UNIT to device.
- * @scmd:	Scsi cmd to send START_UNIT
+ * @scmd:	&scsi_cmnd to send START_UNIT
  *
  * Return value:
  *    0 - Device is ready. 1 - Device NOT ready.
- **/
+ */
 static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
 {
 	static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
@@ -956,13 +952,14 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
 
  /**
  * scsi_eh_stu - send START_UNIT if needed
- * @shost:	scsi host being recovered.
- * @eh_done_q:	list_head for processed commands.
+ * @shost:	&scsi host being recovered.
+ * @work_q:     &list_head for pending commands.
+ * @done_q:	&list_head for processed commands.
  *
  * Notes:
  *    If commands are failing due to not ready, initializing command required,
  *	try revalidating the device, which will end up sending a start unit. 
- **/
+ */
 static int scsi_eh_stu(struct Scsi_Host *shost,
 			      struct list_head *work_q,
 			      struct list_head *done_q)
@@ -1008,14 +1005,15 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
 /**
  * scsi_eh_bus_device_reset - send bdr if needed
  * @shost:	scsi host being recovered.
- * @eh_done_q:	list_head for processed commands.
+ * @work_q:     &list_head for pending commands.
+ * @done_q:	&list_head for processed commands.
  *
  * Notes:
- *    Try a bus device reset.  still, look to see whether we have multiple
+ *    Try a bus device reset.  Still, look to see whether we have multiple
  *    devices that are jammed or not - if we have multiple devices, it
  *    makes no sense to try bus_device_reset - we really would need to try
  *    a bus_reset instead. 
- **/
+ */
 static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
 				    struct list_head *work_q,
 				    struct list_head *done_q)
@@ -1063,9 +1061,10 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
 
 /**
  * scsi_eh_bus_reset - send a bus reset 
- * @shost:	scsi host being recovered.
- * @eh_done_q:	list_head for processed commands.
- **/
+ * @shost:	&scsi host being recovered.
+ * @work_q:     &list_head for pending commands.
+ * @done_q:	&list_head for processed commands.
+ */
 static int scsi_eh_bus_reset(struct Scsi_Host *shost,
 			     struct list_head *work_q,
 			     struct list_head *done_q)
@@ -1122,7 +1121,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
  * scsi_eh_host_reset - send a host reset 
  * @work_q:	list_head for processed commands.
  * @done_q:	list_head for processed commands.
- **/
+ */
 static int scsi_eh_host_reset(struct list_head *work_q,
 			      struct list_head *done_q)
 {
@@ -1157,8 +1156,7 @@ static int scsi_eh_host_reset(struct list_head *work_q,
  * scsi_eh_offline_sdevs - offline scsi devices that fail to recover
  * @work_q:	list_head for processed commands.
  * @done_q:	list_head for processed commands.
- *
- **/
+ */
 static void scsi_eh_offline_sdevs(struct list_head *work_q,
 				  struct list_head *done_q)
 {
@@ -1191,7 +1189,7 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
  *    is woken.  In cases where the error code indicates an error that
  *    doesn't require the error handler read (i.e. we don't need to
  *    abort/reset), this function should return SUCCESS.
- **/
+ */
 int scsi_decide_disposition(struct scsi_cmnd *scmd)
 {
 	int rtn;
@@ -1372,7 +1370,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
  *
  *	If scsi_allocate_request() fails for what ever reason, we
  *	completely forget to lock the door.
- **/
+ */
 static void scsi_eh_lock_door(struct scsi_device *sdev)
 {
 	unsigned char cmnd[MAX_COMMAND_SIZE];
@@ -1396,7 +1394,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
  * Notes:
  *    When we entered the error handler, we blocked all further i/o to
  *    this device.  we need to 'reverse' this process.
- **/
+ */
 static void scsi_restart_operations(struct Scsi_Host *shost)
 {
 	struct scsi_device *sdev;
@@ -1440,9 +1438,9 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
 /**
  * scsi_eh_ready_devs - check device ready state and recover if not.
  * @shost: 	host to be recovered.
- * @eh_done_q:	list_head for processed commands.
- *
- **/
+ * @work_q:     &list_head for pending commands.
+ * @done_q:	&list_head for processed commands.
+ */
 void scsi_eh_ready_devs(struct Scsi_Host *shost,
 			struct list_head *work_q,
 			struct list_head *done_q)
@@ -1458,8 +1456,7 @@ EXPORT_SYMBOL_GPL(scsi_eh_ready_devs);
 /**
  * scsi_eh_flush_done_q - finish processed commands or retry them.
  * @done_q:	list_head of processed commands.
- *
- **/
+ */
 void scsi_eh_flush_done_q(struct list_head *done_q)
 {
 	struct scsi_cmnd *scmd, *next;
@@ -1513,7 +1510,7 @@ EXPORT_SYMBOL(scsi_eh_flush_done_q);
  *    scsi_finish_cmd() called for it.  we do all of the retry stuff
  *    here, so when we restart the host after we return it should have an
  *    empty queue.
- **/
+ */
 static void scsi_unjam_host(struct Scsi_Host *shost)
 {
 	unsigned long flags;
@@ -1540,7 +1537,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost)
  * Notes:
  *    This is the main error handling loop.  This is run as a kernel thread
  *    for every SCSI host and handles all error handling activity.
- **/
+ */
 int scsi_error_handler(void *data)
 {
 	struct Scsi_Host *shost = data;
@@ -1699,8 +1696,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
 	memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
     
 	scmd->scsi_done		= scsi_reset_provider_done_command;
-	scmd->request_buffer		= NULL;
-	scmd->request_bufflen		= 0;
+	memset(&scmd->sdb, 0, sizeof(scmd->sdb));
 
 	scmd->cmd_len			= 0;
 
@@ -1769,7 +1765,7 @@ EXPORT_SYMBOL(scsi_reset_provider);
  *
  * Return value:
  *	1 if valid sense data information found, else 0;
- **/
+ */
 int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
                          struct scsi_sense_hdr *sshdr)
 {
@@ -1819,14 +1815,12 @@ int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
 				 struct scsi_sense_hdr *sshdr)
 {
 	return scsi_normalize_sense(cmd->sense_buffer,
-			sizeof(cmd->sense_buffer), sshdr);
+			SCSI_SENSE_BUFFERSIZE, sshdr);
 }
 EXPORT_SYMBOL(scsi_command_normalize_sense);
 
 /**
- * scsi_sense_desc_find - search for a given descriptor type in
- *			descriptor sense data format.
- *
+ * scsi_sense_desc_find - search for a given descriptor type in	descriptor sense data format.
  * @sense_buffer:	byte array of descriptor format sense data
  * @sb_len:		number of valid bytes in sense_buffer
  * @desc_type:		value of descriptor type to find
@@ -1837,7 +1831,7 @@ EXPORT_SYMBOL(scsi_command_normalize_sense);
  *
  * Return value:
  *	pointer to start of (first) descriptor if found else NULL
- **/
+ */
 const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
 				int desc_type)
 {
@@ -1865,9 +1859,7 @@ const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
 EXPORT_SYMBOL(scsi_sense_desc_find);
 
 /**
- * scsi_get_sense_info_fld - attempts to get information field from
- *			sense data (either fixed or descriptor format)
- *
+ * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format)
  * @sense_buffer:	byte array of sense data
  * @sb_len:		number of valid bytes in sense_buffer
  * @info_out:		pointer to 64 integer where 8 or 4 byte information
@@ -1875,7 +1867,7 @@ EXPORT_SYMBOL(scsi_sense_desc_find);
  *
  * Return value:
  *	1 if information field found, 0 if not found.
- **/
+ */
 int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
 			    u64 * info_out)
 {
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 32293f451669..28b19ef26309 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -174,10 +174,15 @@ static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg)
 }
 
 
-/*
- * the scsi_ioctl() function differs from most ioctls in that it does
- * not take a major/minor number as the dev field.  Rather, it takes
- * a pointer to a scsi_devices[] element, a structure. 
+/**
+ * scsi_ioctl - Dispatch ioctl to scsi device
+ * @sdev: scsi device receiving ioctl
+ * @cmd: which ioctl is it
+ * @arg: data associated with ioctl
+ *
+ * Description: The scsi_ioctl() function differs from most ioctls in that it
+ * does not take a major/minor number as the dev field.  Rather, it takes
+ * a pointer to a &struct scsi_device.
  */
 int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
 {
@@ -239,7 +244,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
 		return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
 	case SCSI_IOCTL_TEST_UNIT_READY:
 		return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT,
-					    NORMAL_RETRIES);
+					    NORMAL_RETRIES, NULL);
 	case SCSI_IOCTL_START_UNIT:
 		scsi_cmd[0] = START_STOP;
 		scsi_cmd[1] = 0;
@@ -264,9 +269,12 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
 }
 EXPORT_SYMBOL(scsi_ioctl);
 
-/*
- * the scsi_nonblock_ioctl() function is designed for ioctls which may
- * be executed even if the device is in recovery.
+/**
+ * scsi_nonblock_ioctl() - Handle SG_SCSI_RESET
+ * @sdev: scsi device receiving ioctl
+ * @cmd: Must be SC_SCSI_RESET
+ * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST}
+ * @filp: either NULL or a &struct file which must have the O_NONBLOCK flag.
  */
 int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
 			    void __user *arg, struct file *filp)
@@ -276,7 +284,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
 	/* The first set of iocts may be executed even if we're doing
 	 * error processing, as long as the device was opened
 	 * non-blocking */
-	if (filp && filp->f_flags & O_NONBLOCK) {
+	if (filp && (filp->f_flags & O_NONBLOCK)) {
 		if (scsi_host_in_recovery(sdev->host))
 			return -ENODEV;
 	} else if (!scsi_block_when_processing_errors(sdev))
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index a9ac5b1b1667..b12fb310e399 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/bio.h>
+#include <linux/bitops.h>
 #include <linux/blkdev.h>
 #include <linux/completion.h>
 #include <linux/kernel.h>
@@ -34,13 +35,6 @@
 #define SG_MEMPOOL_NR		ARRAY_SIZE(scsi_sg_pools)
 #define SG_MEMPOOL_SIZE		2
 
-/*
- * The maximum number of SG segments that we will put inside a scatterlist
- * (unless chaining is used). Should ideally fit inside a single page, to
- * avoid a higher order allocation.
- */
-#define SCSI_MAX_SG_SEGMENTS	128
-
 struct scsi_host_sg_pool {
 	size_t		size;
 	char		*name;
@@ -48,22 +42,31 @@ struct scsi_host_sg_pool {
 	mempool_t	*pool;
 };
 
-#define SP(x) { x, "sgpool-" #x }
+#define SP(x) { x, "sgpool-" __stringify(x) }
+#if (SCSI_MAX_SG_SEGMENTS < 32)
+#error SCSI_MAX_SG_SEGMENTS is too small (must be 32 or greater)
+#endif
 static struct scsi_host_sg_pool scsi_sg_pools[] = {
 	SP(8),
 	SP(16),
-#if (SCSI_MAX_SG_SEGMENTS > 16)
-	SP(32),
 #if (SCSI_MAX_SG_SEGMENTS > 32)
-	SP(64),
+	SP(32),
 #if (SCSI_MAX_SG_SEGMENTS > 64)
+	SP(64),
+#if (SCSI_MAX_SG_SEGMENTS > 128)
 	SP(128),
+#if (SCSI_MAX_SG_SEGMENTS > 256)
+#error SCSI_MAX_SG_SEGMENTS is too large (256 MAX)
+#endif
 #endif
 #endif
 #endif
+	SP(SCSI_MAX_SG_SEGMENTS)
 };
 #undef SP
 
+static struct kmem_cache *scsi_bidi_sdb_cache;
+
 static void scsi_run_queue(struct request_queue *q);
 
 /*
@@ -175,7 +178,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
  *
  * returns the req->errors value which is the scsi_cmnd result
  * field.
- **/
+ */
 int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
 		 int data_direction, void *buffer, unsigned bufflen,
 		 unsigned char *sense, int timeout, int retries, int flags)
@@ -274,7 +277,7 @@ static void scsi_bi_endio(struct bio *bio, int error)
 /**
  * scsi_req_map_sg - map a scatterlist into a request
  * @rq:		request to fill
- * @sg:		scatterlist
+ * @sgl:	scatterlist
  * @nsegs:	number of elements
  * @bufflen:	len of buffer
  * @gfp:	memory allocation flags
@@ -365,14 +368,16 @@ free_bios:
  * @sdev:	scsi device
  * @cmd:	scsi command
  * @cmd_len:	length of scsi cdb
- * @data_direction: data direction
+ * @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE
  * @buffer:	data buffer (this can be a kernel buffer or scatterlist)
  * @bufflen:	len of buffer
  * @use_sg:	if buffer is a scatterlist this is the number of elements
  * @timeout:	request timeout in seconds
  * @retries:	number of times to retry request
- * @flags:	or into request flags
- **/
+ * @privdata:	data passed to done()
+ * @done:	callback function when done
+ * @gfp:	memory allocation flags
+ */
 int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
 		       int cmd_len, int data_direction, void *buffer, unsigned bufflen,
 		       int use_sg, int timeout, int retries, void *privdata,
@@ -438,8 +443,8 @@ EXPORT_SYMBOL_GPL(scsi_execute_async);
 static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
 {
 	cmd->serial_number = 0;
-	cmd->resid = 0;
-	memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
+	scsi_set_resid(cmd, 0);
+	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 	if (cmd->cmd_len == 0)
 		cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
 }
@@ -524,7 +529,7 @@ static void scsi_run_queue(struct request_queue *q)
 	struct Scsi_Host *shost = sdev->host;
 	unsigned long flags;
 
-	if (sdev->single_lun)
+	if (scsi_target(sdev)->single_lun)
 		scsi_single_lun_run(sdev);
 
 	spin_lock_irqsave(shost->host_lock, flags);
@@ -632,7 +637,7 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
  *		of upper level post-processing and scsi_io_completion).
  *
  * Arguments:   cmd	 - command that is complete.
- *              uptodate - 1 if I/O indicates success, <= 0 for I/O error.
+ *              error    - 0 if I/O indicates success, < 0 for I/O error.
  *              bytes    - number of bytes of completed I/O
  *		requeue  - indicates whether we should requeue leftovers.
  *
@@ -647,26 +652,25 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
  *		at some point during this call.
  * Notes:	If cmd was requeued, upon return it will be a stale pointer.
  */
-static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
+static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error,
 					  int bytes, int requeue)
 {
 	struct request_queue *q = cmd->device->request_queue;
 	struct request *req = cmd->request;
-	unsigned long flags;
 
 	/*
 	 * If there are blocks left over at the end, set up the command
 	 * to queue the remainder of them.
 	 */
-	if (end_that_request_chunk(req, uptodate, bytes)) {
+	if (blk_end_request(req, error, bytes)) {
 		int leftover = (req->hard_nr_sectors << 9);
 
 		if (blk_pc_request(req))
 			leftover = req->data_len;
 
 		/* kill remainder if no retrys */
-		if (!uptodate && blk_noretry_request(req))
-			end_that_request_chunk(req, 0, leftover);
+		if (error && blk_noretry_request(req))
+			blk_end_request(req, error, leftover);
 		else {
 			if (requeue) {
 				/*
@@ -681,14 +685,6 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
 		}
 	}
 
-	add_disk_randomness(req->rq_disk);
-
-	spin_lock_irqsave(q->queue_lock, flags);
-	if (blk_rq_tagged(req))
-		blk_queue_end_tag(q, req);
-	end_that_request_last(req, uptodate);
-	spin_unlock_irqrestore(q->queue_lock, flags);
-
 	/*
 	 * This will goose the queue request function at the end, so we don't
 	 * need to worry about launching another command.
@@ -697,182 +693,57 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
 	return NULL;
 }
 
-/*
- * Like SCSI_MAX_SG_SEGMENTS, but for archs that have sg chaining. This limit
- * is totally arbitrary, a setting of 2048 will get you at least 8mb ios.
- */
-#define SCSI_MAX_SG_CHAIN_SEGMENTS	2048
-
 static inline unsigned int scsi_sgtable_index(unsigned short nents)
 {
 	unsigned int index;
 
-	switch (nents) {
-	case 1 ... 8:
+	BUG_ON(nents > SCSI_MAX_SG_SEGMENTS);
+
+	if (nents <= 8)
 		index = 0;
-		break;
-	case 9 ... 16:
-		index = 1;
-		break;
-#if (SCSI_MAX_SG_SEGMENTS > 16)
-	case 17 ... 32:
-		index = 2;
-		break;
-#if (SCSI_MAX_SG_SEGMENTS > 32)
-	case 33 ... 64:
-		index = 3;
-		break;
-#if (SCSI_MAX_SG_SEGMENTS > 64)
-	case 65 ... 128:
-		index = 4;
-		break;
-#endif
-#endif
-#endif
-	default:
-		printk(KERN_ERR "scsi: bad segment count=%d\n", nents);
-		BUG();
-	}
+	else
+		index = get_count_order(nents) - 3;
 
 	return index;
 }
 
-struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+static void scsi_sg_free(struct scatterlist *sgl, unsigned int nents)
 {
 	struct scsi_host_sg_pool *sgp;
-	struct scatterlist *sgl, *prev, *ret;
-	unsigned int index;
-	int this, left;
-
-	BUG_ON(!cmd->use_sg);
-
-	left = cmd->use_sg;
-	ret = prev = NULL;
-	do {
-		this = left;
-		if (this > SCSI_MAX_SG_SEGMENTS) {
-			this = SCSI_MAX_SG_SEGMENTS - 1;
-			index = SG_MEMPOOL_NR - 1;
-		} else
-			index = scsi_sgtable_index(this);
-
-		left -= this;
 
-		sgp = scsi_sg_pools + index;
+	sgp = scsi_sg_pools + scsi_sgtable_index(nents);
+	mempool_free(sgl, sgp->pool);
+}
 
-		sgl = mempool_alloc(sgp->pool, gfp_mask);
-		if (unlikely(!sgl))
-			goto enomem;
+static struct scatterlist *scsi_sg_alloc(unsigned int nents, gfp_t gfp_mask)
+{
+	struct scsi_host_sg_pool *sgp;
 
-		sg_init_table(sgl, sgp->size);
+	sgp = scsi_sg_pools + scsi_sgtable_index(nents);
+	return mempool_alloc(sgp->pool, gfp_mask);
+}
 
-		/*
-		 * first loop through, set initial index and return value
-		 */
-		if (!ret)
-			ret = sgl;
+static int scsi_alloc_sgtable(struct scsi_data_buffer *sdb, int nents,
+			      gfp_t gfp_mask)
+{
+	int ret;
 
-		/*
-		 * chain previous sglist, if any. we know the previous
-		 * sglist must be the biggest one, or we would not have
-		 * ended up doing another loop.
-		 */
-		if (prev)
-			sg_chain(prev, SCSI_MAX_SG_SEGMENTS, sgl);
+	BUG_ON(!nents);
 
-		/*
-		 * if we have nothing left, mark the last segment as
-		 * end-of-list
-		 */
-		if (!left)
-			sg_mark_end(&sgl[this - 1]);
-
-		/*
-		 * don't allow subsequent mempool allocs to sleep, it would
-		 * violate the mempool principle.
-		 */
-		gfp_mask &= ~__GFP_WAIT;
-		gfp_mask |= __GFP_HIGH;
-		prev = sgl;
-	} while (left);
+	ret = __sg_alloc_table(&sdb->table, nents, SCSI_MAX_SG_SEGMENTS,
+			       gfp_mask, scsi_sg_alloc);
+	if (unlikely(ret))
+		__sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS,
+				scsi_sg_free);
 
-	/*
-	 * ->use_sg may get modified after dma mapping has potentially
-	 * shrunk the number of segments, so keep a copy of it for free.
-	 */
-	cmd->__use_sg = cmd->use_sg;
 	return ret;
-enomem:
-	if (ret) {
-		/*
-		 * Free entries chained off ret. Since we were trying to
-		 * allocate another sglist, we know that all entries are of
-		 * the max size.
-		 */
-		sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1;
-		prev = ret;
-		ret = &ret[SCSI_MAX_SG_SEGMENTS - 1];
-
-		while ((sgl = sg_chain_ptr(ret)) != NULL) {
-			ret = &sgl[SCSI_MAX_SG_SEGMENTS - 1];
-			mempool_free(sgl, sgp->pool);
-		}
-
-		mempool_free(prev, sgp->pool);
-	}
-	return NULL;
 }
 
-EXPORT_SYMBOL(scsi_alloc_sgtable);
-
-void scsi_free_sgtable(struct scsi_cmnd *cmd)
+static void scsi_free_sgtable(struct scsi_data_buffer *sdb)
 {
-	struct scatterlist *sgl = cmd->request_buffer;
-	struct scsi_host_sg_pool *sgp;
-
-	/*
-	 * if this is the biggest size sglist, check if we have
-	 * chained parts we need to free
-	 */
-	if (cmd->__use_sg > SCSI_MAX_SG_SEGMENTS) {
-		unsigned short this, left;
-		struct scatterlist *next;
-		unsigned int index;
-
-		left = cmd->__use_sg - (SCSI_MAX_SG_SEGMENTS - 1);
-		next = sg_chain_ptr(&sgl[SCSI_MAX_SG_SEGMENTS - 1]);
-		while (left && next) {
-			sgl = next;
-			this = left;
-			if (this > SCSI_MAX_SG_SEGMENTS) {
-				this = SCSI_MAX_SG_SEGMENTS - 1;
-				index = SG_MEMPOOL_NR - 1;
-			} else
-				index = scsi_sgtable_index(this);
-
-			left -= this;
-
-			sgp = scsi_sg_pools + index;
-
-			if (left)
-				next = sg_chain_ptr(&sgl[sgp->size - 1]);
-
-			mempool_free(sgl, sgp->pool);
-		}
-
-		/*
-		 * Restore original, will be freed below
-		 */
-		sgl = cmd->request_buffer;
-		sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1;
-	} else
-		sgp = scsi_sg_pools + scsi_sgtable_index(cmd->__use_sg);
-
-	mempool_free(sgl, sgp->pool);
+	__sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, scsi_sg_free);
 }
 
-EXPORT_SYMBOL(scsi_free_sgtable);
-
 /*
  * Function:    scsi_release_buffers()
  *
@@ -890,17 +761,49 @@ EXPORT_SYMBOL(scsi_free_sgtable);
  *		the scatter-gather table, and potentially any bounce
  *		buffers.
  */
-static void scsi_release_buffers(struct scsi_cmnd *cmd)
+void scsi_release_buffers(struct scsi_cmnd *cmd)
+{
+	if (cmd->sdb.table.nents)
+		scsi_free_sgtable(&cmd->sdb);
+
+	memset(&cmd->sdb, 0, sizeof(cmd->sdb));
+
+	if (scsi_bidi_cmnd(cmd)) {
+		struct scsi_data_buffer *bidi_sdb =
+			cmd->request->next_rq->special;
+		scsi_free_sgtable(bidi_sdb);
+		kmem_cache_free(scsi_bidi_sdb_cache, bidi_sdb);
+		cmd->request->next_rq->special = NULL;
+	}
+}
+EXPORT_SYMBOL(scsi_release_buffers);
+
+/*
+ * Bidi commands Must be complete as a whole, both sides at once.
+ * If part of the bytes were written and lld returned
+ * scsi_in()->resid and/or scsi_out()->resid this information will be left
+ * in req->data_len and req->next_rq->data_len. The upper-layer driver can
+ * decide what to do with this information.
+ */
+void scsi_end_bidi_request(struct scsi_cmnd *cmd)
 {
-	if (cmd->use_sg)
-		scsi_free_sgtable(cmd);
+	struct request *req = cmd->request;
+	unsigned int dlen = req->data_len;
+	unsigned int next_dlen = req->next_rq->data_len;
+
+	req->data_len = scsi_out(cmd)->resid;
+	req->next_rq->data_len = scsi_in(cmd)->resid;
+
+	/* The req and req->next_rq have not been completed */
+	BUG_ON(blk_end_bidi_request(req, 0, dlen, next_dlen));
+
+	scsi_release_buffers(cmd);
 
 	/*
-	 * Zero these out.  They now point to freed memory, and it is
-	 * dangerous to hang onto the pointers.
+	 * This will goose the queue request function at the end, so we don't
+	 * need to worry about launching another command.
 	 */
-	cmd->request_buffer = NULL;
-	cmd->request_bufflen = 0;
+	scsi_next_command(cmd);
 }
 
 /*
@@ -934,7 +837,7 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd)
 void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 {
 	int result = cmd->result;
-	int this_count = cmd->request_bufflen;
+	int this_count = scsi_bufflen(cmd);
 	struct request_queue *q = cmd->device->request_queue;
 	struct request *req = cmd->request;
 	int clear_errors = 1;
@@ -942,8 +845,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 	int sense_valid = 0;
 	int sense_deferred = 0;
 
-	scsi_release_buffers(cmd);
-
 	if (result) {
 		sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
 		if (sense_valid)
@@ -966,9 +867,17 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 				req->sense_len = len;
 			}
 		}
-		req->data_len = cmd->resid;
+		if (scsi_bidi_cmnd(cmd)) {
+			/* will also release_buffers */
+			scsi_end_bidi_request(cmd);
+			return;
+		}
+		req->data_len = scsi_get_resid(cmd);
 	}
 
+	BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */
+	scsi_release_buffers(cmd);
+
 	/*
 	 * Next deal with any sectors which we were able to correctly
 	 * handle.
@@ -976,7 +885,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 	SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, "
 				      "%d bytes done.\n",
 				      req->nr_sectors, good_bytes));
-	SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg));
 
 	if (clear_errors)
 		req->errors = 0;
@@ -985,7 +893,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 	 * are leftovers and there is some kind of error
 	 * (result != 0), retry the rest.
 	 */
-	if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL)
+	if (scsi_end_request(cmd, 0, good_bytes, result == 0) == NULL)
 		return;
 
 	/* good_bytes = 0, or (inclusive) there were leftovers and
@@ -999,7 +907,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 				 * and quietly refuse further access.
 				 */
 				cmd->device->changed = 1;
-				scsi_end_request(cmd, 0, this_count, 1);
+				scsi_end_request(cmd, -EIO, this_count, 1);
 				return;
 			} else {
 				/* Must have been a power glitch, or a
@@ -1031,7 +939,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 				scsi_requeue_command(q, cmd);
 				return;
 			} else {
-				scsi_end_request(cmd, 0, this_count, 1);
+				scsi_end_request(cmd, -EIO, this_count, 1);
 				return;
 			}
 			break;
@@ -1059,7 +967,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 							 "Device not ready",
 							 &sshdr);
 
-			scsi_end_request(cmd, 0, this_count, 1);
+			scsi_end_request(cmd, -EIO, this_count, 1);
 			return;
 		case VOLUME_OVERFLOW:
 			if (!(req->cmd_flags & REQ_QUIET)) {
@@ -1069,7 +977,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 				scsi_print_sense("", cmd);
 			}
 			/* See SSC3rXX or current. */
-			scsi_end_request(cmd, 0, this_count, 1);
+			scsi_end_request(cmd, -EIO, this_count, 1);
 			return;
 		default:
 			break;
@@ -1090,64 +998,82 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
 				scsi_print_sense("", cmd);
 		}
 	}
-	scsi_end_request(cmd, 0, this_count, !result);
+	scsi_end_request(cmd, -EIO, this_count, !result);
 }
 
-/*
- * Function:    scsi_init_io()
- *
- * Purpose:     SCSI I/O initialize function.
- *
- * Arguments:   cmd   - Command descriptor we wish to initialize
- *
- * Returns:     0 on success
- *		BLKPREP_DEFER if the failure is retryable
- *		BLKPREP_KILL if the failure is fatal
- */
-static int scsi_init_io(struct scsi_cmnd *cmd)
+static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,
+			     gfp_t gfp_mask)
 {
-	struct request     *req = cmd->request;
-	int		   count;
-
-	/*
-	 * We used to not use scatter-gather for single segment request,
-	 * but now we do (it makes highmem I/O easier to support without
-	 * kmapping pages)
-	 */
-	cmd->use_sg = req->nr_phys_segments;
+	int count;
 
 	/*
 	 * If sg table allocation fails, requeue request later.
 	 */
-	cmd->request_buffer = scsi_alloc_sgtable(cmd, GFP_ATOMIC);
-	if (unlikely(!cmd->request_buffer)) {
-		scsi_unprep_request(req);
+	if (unlikely(scsi_alloc_sgtable(sdb, req->nr_phys_segments,
+					gfp_mask))) {
 		return BLKPREP_DEFER;
 	}
 
 	req->buffer = NULL;
 	if (blk_pc_request(req))
-		cmd->request_bufflen = req->data_len;
+		sdb->length = req->data_len;
 	else
-		cmd->request_bufflen = req->nr_sectors << 9;
+		sdb->length = req->nr_sectors << 9;
 
 	/* 
 	 * Next, walk the list, and fill in the addresses and sizes of
 	 * each segment.
 	 */
-	count = blk_rq_map_sg(req->q, req, cmd->request_buffer);
-	if (likely(count <= cmd->use_sg)) {
-		cmd->use_sg = count;
-		return BLKPREP_OK;
+	count = blk_rq_map_sg(req->q, req, sdb->table.sgl);
+	BUG_ON(count > sdb->table.nents);
+	sdb->table.nents = count;
+	return BLKPREP_OK;
+}
+
+/*
+ * Function:    scsi_init_io()
+ *
+ * Purpose:     SCSI I/O initialize function.
+ *
+ * Arguments:   cmd   - Command descriptor we wish to initialize
+ *
+ * Returns:     0 on success
+ *		BLKPREP_DEFER if the failure is retryable
+ *		BLKPREP_KILL if the failure is fatal
+ */
+int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+{
+	int error = scsi_init_sgtable(cmd->request, &cmd->sdb, gfp_mask);
+	if (error)
+		goto err_exit;
+
+	if (blk_bidi_rq(cmd->request)) {
+		struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc(
+			scsi_bidi_sdb_cache, GFP_ATOMIC);
+		if (!bidi_sdb) {
+			error = BLKPREP_DEFER;
+			goto err_exit;
+		}
+
+		cmd->request->next_rq->special = bidi_sdb;
+		error = scsi_init_sgtable(cmd->request->next_rq, bidi_sdb,
+								    GFP_ATOMIC);
+		if (error)
+			goto err_exit;
 	}
 
-	printk(KERN_ERR "Incorrect number of segments after building list\n");
-	printk(KERN_ERR "counted %d, received %d\n", count, cmd->use_sg);
-	printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
-			req->current_nr_sectors);
+	return BLKPREP_OK ;
+
+err_exit:
+	scsi_release_buffers(cmd);
+	if (error == BLKPREP_KILL)
+		scsi_put_command(cmd);
+	else /* BLKPREP_DEFER */
+		scsi_unprep_request(cmd->request);
 
-	return BLKPREP_KILL;
+	return error;
 }
+EXPORT_SYMBOL(scsi_init_io);
 
 static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
 		struct request *req)
@@ -1193,16 +1119,14 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
 
 		BUG_ON(!req->nr_phys_segments);
 
-		ret = scsi_init_io(cmd);
+		ret = scsi_init_io(cmd, GFP_ATOMIC);
 		if (unlikely(ret))
 			return ret;
 	} else {
 		BUG_ON(req->data_len);
 		BUG_ON(req->data);
 
-		cmd->request_bufflen = 0;
-		cmd->request_buffer = NULL;
-		cmd->use_sg = 0;
+		memset(&cmd->sdb, 0, sizeof(cmd->sdb));
 		req->buffer = NULL;
 	}
 
@@ -1244,7 +1168,7 @@ int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
 	if (unlikely(!cmd))
 		return BLKPREP_DEFER;
 
-	return scsi_init_io(cmd);
+	return scsi_init_io(cmd, GFP_ATOMIC);
 }
 EXPORT_SYMBOL(scsi_setup_fs_cmnd);
 
@@ -1557,7 +1481,7 @@ static void scsi_request_fn(struct request_queue *q)
 
 		if (!scsi_host_queue_ready(q, shost, sdev))
 			goto not_ready;
-		if (sdev->single_lun) {
+		if (scsi_target(sdev)->single_lun) {
 			if (scsi_target(sdev)->starget_sdev_user &&
 			    scsi_target(sdev)->starget_sdev_user != sdev)
 				goto not_ready;
@@ -1654,20 +1578,7 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
 	 * this limit is imposed by hardware restrictions
 	 */
 	blk_queue_max_hw_segments(q, shost->sg_tablesize);
-
-	/*
-	 * In the future, sg chaining support will be mandatory and this
-	 * ifdef can then go away. Right now we don't have all archs
-	 * converted, so better keep it safe.
-	 */
-#ifdef ARCH_HAS_SG_CHAIN
-	if (shost->use_sg_chaining)
-		blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
-	else
-		blk_queue_max_phys_segments(q, SCSI_MAX_SG_SEGMENTS);
-#else
-	blk_queue_max_phys_segments(q, SCSI_MAX_SG_SEGMENTS);
-#endif
+	blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
 
 	blk_queue_max_sectors(q, shost->max_sectors);
 	blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
@@ -1675,6 +1586,14 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
 
 	if (!shost->use_clustering)
 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+
+	/*
+	 * set a reasonable default alignment on word boundaries: the
+	 * host and device may alter it using
+	 * blk_queue_update_dma_alignment() later.
+	 */
+	blk_queue_dma_alignment(q, 0x03);
+
 	return q;
 }
 EXPORT_SYMBOL(__scsi_alloc_queue);
@@ -1758,6 +1677,14 @@ int __init scsi_init_queue(void)
 		return -ENOMEM;
 	}
 
+	scsi_bidi_sdb_cache = kmem_cache_create("scsi_bidi_sdb",
+					sizeof(struct scsi_data_buffer),
+					0, 0, NULL);
+	if (!scsi_bidi_sdb_cache) {
+		printk(KERN_ERR "SCSI: can't init scsi bidi sdb cache\n");
+		goto cleanup_io_context;
+	}
+
 	for (i = 0; i < SG_MEMPOOL_NR; i++) {
 		struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
 		int size = sgp->size * sizeof(struct scatterlist);
@@ -1767,6 +1694,7 @@ int __init scsi_init_queue(void)
 		if (!sgp->slab) {
 			printk(KERN_ERR "SCSI: can't init sg slab %s\n",
 					sgp->name);
+			goto cleanup_bidi_sdb;
 		}
 
 		sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE,
@@ -1774,10 +1702,25 @@ int __init scsi_init_queue(void)
 		if (!sgp->pool) {
 			printk(KERN_ERR "SCSI: can't init sg mempool %s\n",
 					sgp->name);
+			goto cleanup_bidi_sdb;
 		}
 	}
 
 	return 0;
+
+cleanup_bidi_sdb:
+	for (i = 0; i < SG_MEMPOOL_NR; i++) {
+		struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
+		if (sgp->pool)
+			mempool_destroy(sgp->pool);
+		if (sgp->slab)
+			kmem_cache_destroy(sgp->slab);
+	}
+	kmem_cache_destroy(scsi_bidi_sdb_cache);
+cleanup_io_context:
+	kmem_cache_destroy(scsi_io_context_cache);
+
+	return -ENOMEM;
 }
 
 void scsi_exit_queue(void)
@@ -1785,6 +1728,7 @@ void scsi_exit_queue(void)
 	int i;
 
 	kmem_cache_destroy(scsi_io_context_cache);
+	kmem_cache_destroy(scsi_bidi_sdb_cache);
 
 	for (i = 0; i < SG_MEMPOOL_NR; i++) {
 		struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
@@ -1804,7 +1748,7 @@ void scsi_exit_queue(void)
  *	@timeout: command timeout
  *	@retries: number of retries before failing
  *	@data: returns a structure abstracting the mode header data
- *	@sense: place to put sense data (or NULL if no sense to be collected).
+ *	@sshdr: place to put sense data (or NULL if no sense to be collected).
  *		must be SCSI_SENSE_BUFFERSIZE big.
  *
  *	Returns zero if successful; negative error number or scsi
@@ -1871,8 +1815,7 @@ scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage,
 EXPORT_SYMBOL_GPL(scsi_mode_select);
 
 /**
- *	scsi_mode_sense - issue a mode sense, falling back from 10 to 
- *		six bytes if necessary.
+ *	scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary.
  *	@sdev:	SCSI device to be queried
  *	@dbd:	set if mode sense will allow block descriptors to be returned
  *	@modepage: mode page being requested
@@ -1881,13 +1824,13 @@ EXPORT_SYMBOL_GPL(scsi_mode_select);
  *	@timeout: command timeout
  *	@retries: number of retries before failing
  *	@data: returns a structure abstracting the mode header data
- *	@sense: place to put sense data (or NULL if no sense to be collected).
+ *	@sshdr: place to put sense data (or NULL if no sense to be collected).
  *		must be SCSI_SENSE_BUFFERSIZE big.
  *
  *	Returns zero if unsuccessful, or the header offset (either 4
  *	or 8 depending on whether a six or ten byte command was
  *	issued) if successful.
- **/
+ */
 int
 scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
 		  unsigned char *buffer, int len, int timeout, int retries,
@@ -1981,40 +1924,69 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
 }
 EXPORT_SYMBOL(scsi_mode_sense);
 
+/**
+ *	scsi_test_unit_ready - test if unit is ready
+ *	@sdev:	scsi device to change the state of.
+ *	@timeout: command timeout
+ *	@retries: number of retries before failing
+ *	@sshdr_external: Optional pointer to struct scsi_sense_hdr for
+ *		returning sense. Make sure that this is cleared before passing
+ *		in.
+ *
+ *	Returns zero if unsuccessful or an error if TUR failed.  For
+ *	removable media, a return of NOT_READY or UNIT_ATTENTION is
+ *	translated to success, with the ->changed flag updated.
+ **/
 int
-scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
+scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
+		     struct scsi_sense_hdr *sshdr_external)
 {
 	char cmd[] = {
 		TEST_UNIT_READY, 0, 0, 0, 0, 0,
 	};
-	struct scsi_sense_hdr sshdr;
+	struct scsi_sense_hdr *sshdr;
 	int result;
-	
-	result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr,
-				  timeout, retries);
+
+	if (!sshdr_external)
+		sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL);
+	else
+		sshdr = sshdr_external;
+
+	/* try to eat the UNIT_ATTENTION if there are enough retries */
+	do {
+		result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
+					  timeout, retries);
+	} while ((driver_byte(result) & DRIVER_SENSE) &&
+		 sshdr && sshdr->sense_key == UNIT_ATTENTION &&
+		 --retries);
+
+	if (!sshdr)
+		/* could not allocate sense buffer, so can't process it */
+		return result;
 
 	if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) {
 
-		if ((scsi_sense_valid(&sshdr)) &&
-		    ((sshdr.sense_key == UNIT_ATTENTION) ||
-		     (sshdr.sense_key == NOT_READY))) {
+		if ((scsi_sense_valid(sshdr)) &&
+		    ((sshdr->sense_key == UNIT_ATTENTION) ||
+		     (sshdr->sense_key == NOT_READY))) {
 			sdev->changed = 1;
 			result = 0;
 		}
 	}
+	if (!sshdr_external)
+		kfree(sshdr);
 	return result;
 }
 EXPORT_SYMBOL(scsi_test_unit_ready);
 
 /**
- *	scsi_device_set_state - Take the given device through the device
- *		state model.
+ *	scsi_device_set_state - Take the given device through the device state model.
  *	@sdev:	scsi device to change the state of.
  *	@state:	state to change to.
  *
  *	Returns zero if unsuccessful or an error if the requested 
  *	transition is illegal.
- **/
+ */
 int
 scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
 {
@@ -2264,7 +2236,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send_simple);
  *	Must be called with user context, may sleep.
  *
  *	Returns zero if unsuccessful or an error if not.
- **/
+ */
 int
 scsi_device_quiesce(struct scsi_device *sdev)
 {
@@ -2289,7 +2261,7 @@ EXPORT_SYMBOL(scsi_device_quiesce);
  *	queues.
  *
  *	Must be called with user context, may sleep.
- **/
+ */
 void
 scsi_device_resume(struct scsi_device *sdev)
 {
@@ -2326,8 +2298,7 @@ scsi_target_resume(struct scsi_target *starget)
 EXPORT_SYMBOL(scsi_target_resume);
 
 /**
- * scsi_internal_device_block - internal function to put a device
- *				temporarily into the SDEV_BLOCK state
+ * scsi_internal_device_block - internal function to put a device temporarily into the SDEV_BLOCK state
  * @sdev:	device to block
  *
  * Block request made by scsi lld's to temporarily stop all
@@ -2342,7 +2313,7 @@ EXPORT_SYMBOL(scsi_target_resume);
  *	state, all commands are deferred until the scsi lld reenables
  *	the device with scsi_device_unblock or device_block_tmo fires.
  *	This routine assumes the host_lock is held on entry.
- **/
+ */
 int
 scsi_internal_device_block(struct scsi_device *sdev)
 {
@@ -2382,7 +2353,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block);
  *	(which must be a legal transition) allowing the midlayer to
  *	goose the queue for this device.  This routine assumes the 
  *	host_lock is held upon entry.
- **/
+ */
 int
 scsi_internal_device_unblock(struct scsi_device *sdev)
 {
@@ -2460,7 +2431,7 @@ EXPORT_SYMBOL_GPL(scsi_target_unblock);
 
 /**
  * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt
- * @sg:		scatter-gather list
+ * @sgl:	scatter-gather list
  * @sg_count:	number of segments in sg
  * @offset:	offset in bytes into sg, on return offset into the mapped area
  * @len:	bytes to map, on return number of bytes mapped
@@ -2509,8 +2480,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count,
 EXPORT_SYMBOL(scsi_kmap_atomic_sg);
 
 /**
- * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously
- *			   mapped with scsi_kmap_atomic_sg
+ * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously mapped with scsi_kmap_atomic_sg
  * @virt:	virtual address to be unmapped
  */
 void scsi_kunmap_atomic_sg(void *virt)
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 40579edca101..370c78cc1cb5 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -32,11 +32,12 @@ EXPORT_SYMBOL_GPL(scsi_nl_sock);
 
 
 /**
- * scsi_nl_rcv_msg -
- *    Receive message handler. Extracts message from a receive buffer.
+ * scsi_nl_rcv_msg - Receive message handler.
+ * @skb:		socket receive buffer
+ *
+ * Description: Extracts message from a receive buffer.
  *    Validates message header and calls appropriate transport message handler
  *
- * @skb:		socket receive buffer
  *
  **/
 static void
@@ -99,9 +100,7 @@ next_msg:
 
 
 /**
- * scsi_nl_rcv_event -
- *    Event handler for a netlink socket.
- *
+ * scsi_nl_rcv_event - Event handler for a netlink socket.
  * @this:		event notifier block
  * @event:		event type
  * @ptr:		event payload
@@ -129,9 +128,7 @@ static struct notifier_block scsi_netlink_notifier = {
 
 
 /**
- * scsi_netlink_init -
- *    Called by SCSI subsystem to intialize the SCSI transport netlink
- *    interface
+ * scsi_netlink_init - Called by SCSI subsystem to intialize the SCSI transport netlink interface
  *
  **/
 void
@@ -160,16 +157,14 @@ scsi_netlink_init(void)
 
 
 /**
- * scsi_netlink_exit -
- *    Called by SCSI subsystem to disable the SCSI transport netlink
- *    interface
+ * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface
  *
  **/
 void
 scsi_netlink_exit(void)
 {
 	if (scsi_nl_sock) {
-		sock_release(scsi_nl_sock->sk_socket);
+		netlink_kernel_release(scsi_nl_sock);
 		netlink_unregister_notifier(&scsi_netlink_notifier);
 	}
 
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index bb6f051beda8..ed395154a5b1 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -45,6 +45,16 @@ static struct proc_dir_entry *proc_scsi;
 /* Protect sht->present and sht->proc_dir */
 static DEFINE_MUTEX(global_host_template_mutex);
 
+/**
+ * proc_scsi_read - handle read from /proc by calling host's proc_info() command
+ * @buffer: passed to proc_info
+ * @start: passed to proc_info
+ * @offset: passed to proc_info
+ * @length: passed to proc_info
+ * @eof: returns whether length read was less than requested
+ * @data: pointer to a &struct Scsi_Host
+ */
+
 static int proc_scsi_read(char *buffer, char **start, off_t offset,
 			  int length, int *eof, void *data)
 {
@@ -57,6 +67,13 @@ static int proc_scsi_read(char *buffer, char **start, off_t offset,
 	return n;
 }
 
+/**
+ * proc_scsi_write_proc - Handle write to /proc by calling host's proc_info()
+ * @file: not used
+ * @buf: source of data to write.
+ * @count: number of bytes (at most PROC_BLOCK_SIZE) to write.
+ * @data: pointer to &struct Scsi_Host
+ */
 static int proc_scsi_write_proc(struct file *file, const char __user *buf,
                            unsigned long count, void *data)
 {
@@ -80,6 +97,13 @@ out:
 	return ret;
 }
 
+/**
+ * scsi_proc_hostdir_add - Create directory in /proc for a scsi host
+ * @sht: owner of this directory
+ *
+ * Sets sht->proc_dir to the new directory.
+ */
+
 void scsi_proc_hostdir_add(struct scsi_host_template *sht)
 {
 	if (!sht->proc_info)
@@ -97,6 +121,10 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
 	mutex_unlock(&global_host_template_mutex);
 }
 
+/**
+ * scsi_proc_hostdir_rm - remove directory in /proc for a scsi host
+ * @sht: owner of directory
+ */
 void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
 {
 	if (!sht->proc_info)
@@ -110,6 +138,11 @@ void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
 	mutex_unlock(&global_host_template_mutex);
 }
 
+
+/**
+ * scsi_proc_host_add - Add entry for this host to appropriate /proc dir
+ * @shost: host to add
+ */
 void scsi_proc_host_add(struct Scsi_Host *shost)
 {
 	struct scsi_host_template *sht = shost->hostt;
@@ -133,6 +166,10 @@ void scsi_proc_host_add(struct Scsi_Host *shost)
 	p->owner = sht->module;
 }
 
+/**
+ * scsi_proc_host_rm - remove this host's entry from /proc
+ * @shost: which host
+ */
 void scsi_proc_host_rm(struct Scsi_Host *shost)
 {
 	char name[10];
@@ -143,7 +180,14 @@ void scsi_proc_host_rm(struct Scsi_Host *shost)
 	sprintf(name,"%d", shost->host_no);
 	remove_proc_entry(name, shost->hostt->proc_dir);
 }
-
+/**
+ * proc_print_scsidevice - return data about this host
+ * @dev: A scsi device
+ * @data: &struct seq_file to output to.
+ *
+ * Description: prints Host, Channel, Id, Lun, Vendor, Model, Rev, Type,
+ * and revision.
+ */
 static int proc_print_scsidevice(struct device *dev, void *data)
 {
 	struct scsi_device *sdev = to_scsi_device(dev);
@@ -189,6 +233,21 @@ static int proc_print_scsidevice(struct device *dev, void *data)
 	return 0;
 }
 
+/**
+ * scsi_add_single_device - Respond to user request to probe for/add device
+ * @host: user-supplied decimal integer
+ * @channel: user-supplied decimal integer
+ * @id: user-supplied decimal integer
+ * @lun: user-supplied decimal integer
+ *
+ * Description: called by writing "scsi add-single-device" to /proc/scsi/scsi.
+ *
+ * does scsi_host_lookup() and either user_scan() if that transport
+ * type supports it, or else scsi_scan_host_selected()
+ *
+ * Note: this seems to be aimed exclusively at SCSI parallel busses.
+ */
+
 static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
 {
 	struct Scsi_Host *shost;
@@ -206,6 +265,16 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
 	return error;
 }
 
+/**
+ * scsi_remove_single_device - Respond to user request to remove a device
+ * @host: user-supplied decimal integer
+ * @channel: user-supplied decimal integer
+ * @id: user-supplied decimal integer
+ * @lun: user-supplied decimal integer
+ *
+ * Description: called by writing "scsi remove-single-device" to
+ * /proc/scsi/scsi.  Does a scsi_device_lookup() and scsi_remove_device()
+ */
 static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
 {
 	struct scsi_device *sdev;
@@ -226,6 +295,25 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
 	return error;
 }
 
+/**
+ * proc_scsi_write - handle writes to /proc/scsi/scsi
+ * @file: not used
+ * @buf: buffer to write
+ * @length: length of buf, at most PAGE_SIZE
+ * @ppos: not used
+ *
+ * Description: this provides a legacy mechanism to add or remove devices by
+ * Host, Channel, ID, and Lun.  To use,
+ * "echo 'scsi add-single-device 0 1 2 3' > /proc/scsi/scsi" or
+ * "echo 'scsi remove-single-device 0 1 2 3' > /proc/scsi/scsi" with
+ * "0 1 2 3" replaced by the Host, Channel, Id, and Lun.
+ *
+ * Note: this seems to be aimed at parallel SCSI. Most modern busses (USB,
+ * SATA, Firewire, Fibre Channel, etc) dynamically assign these values to
+ * provide a unique identifier and nothing more.
+ */
+
+
 static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
 			       size_t length, loff_t *ppos)
 {
@@ -291,6 +379,11 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
 	return err;
 }
 
+/**
+ * proc_scsi_show - show contents of /proc/scsi/scsi (attached devices)
+ * @s: output goes here
+ * @p: not used
+ */
 static int proc_scsi_show(struct seq_file *s, void *p)
 {
 	seq_printf(s, "Attached devices:\n");
@@ -298,10 +391,17 @@ static int proc_scsi_show(struct seq_file *s, void *p)
 	return 0;
 }
 
+/**
+ * proc_scsi_open - glue function
+ * @inode: not used
+ * @file: passed to single_open()
+ *
+ * Associates proc_scsi_show with this file
+ */
 static int proc_scsi_open(struct inode *inode, struct file *file)
 {
 	/*
-	 * We don't really needs this for the write case but it doesn't
+	 * We don't really need this for the write case but it doesn't
 	 * harm either.
 	 */
 	return single_open(file, proc_scsi_show, NULL);
@@ -315,6 +415,9 @@ static const struct file_operations proc_scsi_operations = {
 	.release	= single_release,
 };
 
+/**
+ * scsi_init_procfs - create scsi and scsi/scsi in procfs
+ */
 int __init scsi_init_procfs(void)
 {
 	struct proc_dir_entry *pde;
@@ -336,6 +439,9 @@ err1:
 	return -ENOMEM;
 }
 
+/**
+ * scsi_exit_procfs - Remove scsi/scsi and scsi from procfs
+ */
 void scsi_exit_procfs(void)
 {
 	remove_proc_entry("scsi/scsi", NULL);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 40ea71cd2ca6..1dc165ad17fb 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -221,6 +221,9 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
 
 /**
  * scsi_alloc_sdev - allocate and setup a scsi_Device
+ * @starget: which target to allocate a &scsi_device for
+ * @lun: which lun
+ * @hostdata: usually NULL and set by ->slave_alloc instead
  *
  * Description:
  *     Allocate, initialize for io, and return a pointer to a scsi_Device.
@@ -472,7 +475,6 @@ static void scsi_target_reap_usercontext(struct work_struct *work)
 
 /**
  * scsi_target_reap - check to see if target is in use and destroy if not
- *
  * @starget: target to be checked
  *
  * This is used after removing a LUN or doing a last put of the target
@@ -863,7 +865,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
 		sdev->no_start_on_add = 1;
 
 	if (*bflags & BLIST_SINGLELUN)
-		sdev->single_lun = 1;
+		scsi_target(sdev)->single_lun = 1;
 
 	sdev->use_10_for_rw = 1;
 
@@ -928,8 +930,7 @@ static inline void scsi_destroy_sdev(struct scsi_device *sdev)
 
 #ifdef CONFIG_SCSI_LOGGING
 /** 
- * scsi_inq_str - print INQUIRY data from min to max index,
- * strip trailing whitespace
+ * scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace
  * @buf:   Output buffer with at least end-first+1 bytes of space
  * @inq:   Inquiry buffer (input)
  * @first: Offset of string into inq
@@ -957,9 +958,10 @@ static unsigned char *scsi_inq_str(unsigned char *buf, unsigned char *inq,
  * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
  * @starget:	pointer to target device structure
  * @lun:	LUN of target device
- * @sdevscan:	probe the LUN corresponding to this scsi_device
- * @sdevnew:	store the value of any new scsi_device allocated
  * @bflagsp:	store bflags here if not NULL
+ * @sdevp:	probe the LUN corresponding to this scsi_device
+ * @rescan:     if nonzero skip some code only needed on first scan
+ * @hostdata:	passed to scsi_alloc_sdev()
  *
  * Description:
  *     Call scsi_probe_lun, if a LUN with an attached device is found,
@@ -1110,6 +1112,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
  * scsi_sequential_lun_scan - sequentially scan a SCSI target
  * @starget:	pointer to target structure to scan
  * @bflags:	black/white list flag for LUN 0
+ * @scsi_level: Which version of the standard does this device adhere to
+ * @rescan:     passed to scsi_probe_add_lun()
  *
  * Description:
  *     Generally, scan from LUN 1 (LUN 0 is assumed to already have been
@@ -1220,7 +1224,7 @@ EXPORT_SYMBOL(scsilun_to_int);
 
 /**
  * int_to_scsilun: reverts an int into a scsi_lun
- * @int:        integer to be reverted
+ * @lun:        integer to be reverted
  * @scsilun:	struct scsi_lun to be set.
  *
  * Description:
@@ -1252,18 +1256,22 @@ EXPORT_SYMBOL(int_to_scsilun);
 
 /**
  * scsi_report_lun_scan - Scan using SCSI REPORT LUN results
- * @sdevscan:	scan the host, channel, and id of this scsi_device
+ * @starget: which target
+ * @bflags: Zero or a mix of BLIST_NOLUN, BLIST_REPORTLUN2, or BLIST_NOREPORTLUN
+ * @rescan: nonzero if we can skip code only needed on first scan
  *
  * Description:
- *     If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN
- *     command, and scan the resulting list of LUNs by calling
- *     scsi_probe_and_add_lun.
+ *   Fast scanning for modern (SCSI-3) devices by sending a REPORT LUN command.
+ *   Scan the resulting list of LUNs by calling scsi_probe_and_add_lun.
  *
- *     Modifies sdevscan->lun.
+ *   If BLINK_REPORTLUN2 is set, scan a target that supports more than 8
+ *   LUNs even if it's older than SCSI-3.
+ *   If BLIST_NOREPORTLUN is set, return 1 always.
+ *   If BLIST_NOLUN is set, return 0 always.
  *
  * Return:
  *     0: scan completed (or no memory, so further scanning is futile)
- *     1: no report lun scan, or not configured
+ *     1: could not scan with REPORT LUN
  **/
 static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
 				int rescan)
@@ -1481,6 +1489,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
 	if (scsi_host_scan_allowed(shost))
 		scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
 	mutex_unlock(&shost->scan_mutex);
+	transport_configure_device(&starget->dev);
 	scsi_target_reap(starget);
 	put_device(&starget->dev);
 
@@ -1561,6 +1570,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
  out_reap:
 	/* now determine if the target has any children at all
 	 * and if not, nuke it */
+	transport_configure_device(&starget->dev);
 	scsi_target_reap(starget);
 
 	put_device(&starget->dev);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 00b386677392..ed83cdb6e67d 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1018,6 +1018,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
 	}
 
 	transport_register_device(&shost->shost_gendev);
+	transport_configure_device(&shost->shost_gendev);
 	return 0;
 }
 
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index 9815a1a2db24..d2557dbc2dc1 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -112,7 +112,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id,
 	memset(&ev, 0, sizeof(ev));
 	ev.p.cmd_req.host_no = shost->host_no;
 	ev.p.cmd_req.itn_id = itn_id;
-	ev.p.cmd_req.data_len = cmd->request_bufflen;
+	ev.p.cmd_req.data_len = scsi_bufflen(cmd);
 	memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb));
 	memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun));
 	ev.p.cmd_req.attribute = cmd->tag;
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index a91761c3645f..91630baea532 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -180,7 +180,7 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work)
 		container_of(work, struct scsi_tgt_cmd, work);
 	struct scsi_cmnd *cmd = tcmd->rq->special;
 
-	dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
+	dprintk("cmd %p %d %u\n", cmd, cmd->sc_data_direction,
 		rq_data_dir(cmd->request));
 	scsi_unmap_user_pages(tcmd);
 	scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
@@ -327,12 +327,11 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
 {
 	struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
 
-	dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
+	dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request));
 
 	scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag);
 
-	if (cmd->request_buffer)
-		scsi_free_sgtable(cmd);
+	scsi_release_buffers(cmd);
 
 	queue_work(scsi_tgtd, &tcmd->work);
 }
@@ -342,7 +341,7 @@ static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
 	struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
 	int err;
 
-	dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
+	dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request));
 
 	err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done);
 	switch (err) {
@@ -353,30 +352,6 @@ static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
 	return 0;
 }
 
-static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
-{
-	struct request *rq = cmd->request;
-	int count;
-
-	cmd->use_sg = rq->nr_phys_segments;
-	cmd->request_buffer = scsi_alloc_sgtable(cmd, gfp_mask);
-	if (!cmd->request_buffer)
-		return -ENOMEM;
-
-	cmd->request_bufflen = rq->data_len;
-
-	dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq));
-	count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
-	if (likely(count <= cmd->use_sg)) {
-		cmd->use_sg = count;
-		return 0;
-	}
-
-	eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg);
-	scsi_free_sgtable(cmd);
-	return -EINVAL;
-}
-
 /* TODO: test this crap and replace bio_map_user with new interface maybe */
 static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
 			       unsigned long uaddr, unsigned int len, int rw)
@@ -402,9 +377,11 @@ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
 	}
 
 	tcmd->bio = rq->bio;
-	err = scsi_tgt_init_cmd(cmd, GFP_KERNEL);
-	if (err)
+	err = scsi_init_io(cmd, GFP_KERNEL);
+	if (err) {
+		scsi_release_buffers(cmd);
 		goto unmap_rq;
+	}
 
 	return 0;
 
@@ -496,8 +473,8 @@ int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag,
 	}
 	cmd = rq->special;
 
-	dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n",
-		cmd, cmd->cmnd[0], result, len, cmd->request_bufflen,
+	dprintk("cmd %p scb %x result %d len %d bufflen %u %u %x\n",
+		cmd, cmd->cmnd[0], result, len, scsi_bufflen(cmd),
 		rq_data_dir(rq), cmd->cmnd[0]);
 
 	if (result == TASK_ABORTED) {
@@ -617,7 +594,7 @@ int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result)
 	struct Scsi_Host *shost;
 	int err = -EINVAL;
 
-	dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
+	dprintk("%d %d%llx\n", host_no, result, (unsigned long long)itn_id);
 
 	shost = scsi_host_lookup(host_no);
 	if (IS_ERR(shost)) {
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 7a7cfe583b2a..b1119da6e88c 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -481,9 +481,9 @@ MODULE_PARM_DESC(dev_loss_tmo,
 		 " exceeded, the scsi target is removed. Value should be"
 		 " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
 
-/**
+/*
  * Netlink Infrastructure
- **/
+ */
 
 static atomic_t fc_event_seq;
 
@@ -491,10 +491,10 @@ static atomic_t fc_event_seq;
  * fc_get_event_number - Obtain the next sequential FC event number
  *
  * Notes:
- *   We could have inline'd this, but it would have required fc_event_seq to
+ *   We could have inlined this, but it would have required fc_event_seq to
  *   be exposed. For now, live with the subroutine call.
  *   Atomic used to avoid lock/unlock...
- **/
+ */
 u32
 fc_get_event_number(void)
 {
@@ -505,7 +505,6 @@ EXPORT_SYMBOL(fc_get_event_number);
 
 /**
  * fc_host_post_event - called to post an even on an fc_host.
- *
  * @shost:		host the event occurred on
  * @event_number:	fc event number obtained from get_fc_event_number()
  * @event_code:		fc_host event being posted
@@ -513,7 +512,7 @@ EXPORT_SYMBOL(fc_get_event_number);
  *
  * Notes:
  *	This routine assumes no locks are held on entry.
- **/
+ */
 void
 fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
 		enum fc_host_event_code event_code, u32 event_data)
@@ -579,17 +578,16 @@ EXPORT_SYMBOL(fc_host_post_event);
 
 
 /**
- * fc_host_post_vendor_event - called to post a vendor unique event on
- *                             a fc_host
- *
+ * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host
  * @shost:		host the event occurred on
  * @event_number:	fc event number obtained from get_fc_event_number()
  * @data_len:		amount, in bytes, of vendor unique data
  * @data_buf:		pointer to vendor unique data
+ * @vendor_id:          Vendor id
  *
  * Notes:
  *	This routine assumes no locks are held on entry.
- **/
+ */
 void
 fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
 		u32 data_len, char * data_buf, u64 vendor_id)
@@ -1900,7 +1898,6 @@ static int fc_vport_match(struct attribute_container *cont,
 
 /**
  * fc_timed_out - FC Transport I/O timeout intercept handler
- *
  * @scmd:	The SCSI command which timed out
  *
  * This routine protects against error handlers getting invoked while a
@@ -1920,7 +1917,7 @@ static int fc_vport_match(struct attribute_container *cont,
  *
  * Notes:
  *	This routine assumes no locks are held on entry.
- **/
+ */
 static enum scsi_eh_timer_return
 fc_timed_out(struct scsi_cmnd *scmd)
 {
@@ -2133,7 +2130,7 @@ EXPORT_SYMBOL(fc_release_transport);
  * 	1 - work queued for execution
  *	0 - work is already queued
  *	-EINVAL - work queue doesn't exist
- **/
+ */
 static int
 fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
 {
@@ -2152,7 +2149,7 @@ fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
 /**
  * fc_flush_work - Flush a fc_host's workqueue.
  * @shost:	Pointer to Scsi_Host bound to fc_host.
- **/
+ */
 static void
 fc_flush_work(struct Scsi_Host *shost)
 {
@@ -2175,7 +2172,7 @@ fc_flush_work(struct Scsi_Host *shost)
  *
  * Return value:
  * 	1 on success / 0 already queued / < 0 for error
- **/
+ */
 static int
 fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work,
 				unsigned long delay)
@@ -2195,7 +2192,7 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work,
 /**
  * fc_flush_devloss - Flush a fc_host's devloss workqueue.
  * @shost:	Pointer to Scsi_Host bound to fc_host.
- **/
+ */
 static void
 fc_flush_devloss(struct Scsi_Host *shost)
 {
@@ -2212,21 +2209,20 @@ fc_flush_devloss(struct Scsi_Host *shost)
 
 
 /**
- * fc_remove_host - called to terminate any fc_transport-related elements
- *                  for a scsi host.
- * @rport:	remote port to be unblocked.
+ * fc_remove_host - called to terminate any fc_transport-related elements for a scsi host.
+ * @shost:	Which &Scsi_Host
  *
  * This routine is expected to be called immediately preceeding the
  * a driver's call to scsi_remove_host().
  *
  * WARNING: A driver utilizing the fc_transport, which fails to call
- *   this routine prior to scsi_remote_host(), will leave dangling
+ *   this routine prior to scsi_remove_host(), will leave dangling
  *   objects in /sys/class/fc_remote_ports. Access to any of these
  *   objects can result in a system crash !!!
  *
  * Notes:
  *	This routine assumes no locks are held on entry.
- **/
+ */
 void
 fc_remove_host(struct Scsi_Host *shost)
 {
@@ -2281,10 +2277,10 @@ EXPORT_SYMBOL(fc_remove_host);
 
 /**
  * fc_starget_delete - called to delete the scsi decendents of an rport
- *                  (target and all sdevs)
- *
  * @work:	remote port to be operated on.
- **/
+ *
+ * Deletes target and all sdevs.
+ */
 static void
 fc_starget_delete(struct work_struct *work)
 {
@@ -2303,9 +2299,8 @@ fc_starget_delete(struct work_struct *work)
 
 /**
  * fc_rport_final_delete - finish rport termination and delete it.
- *
  * @work:	remote port to be deleted.
- **/
+ */
 static void
 fc_rport_final_delete(struct work_struct *work)
 {
@@ -2375,7 +2370,7 @@ fc_rport_final_delete(struct work_struct *work)
  *
  * Notes:
  *	This routine assumes no locks are held on entry.
- **/
+ */
 static struct fc_rport *
 fc_rport_create(struct Scsi_Host *shost, int channel,
 	struct fc_rport_identifiers  *ids)
@@ -2462,8 +2457,7 @@ delete_rport:
 }
 
 /**
- * fc_remote_port_add - notifies the fc transport of the existence
- *		of a remote FC port.
+ * fc_remote_port_add - notify fc transport of the existence of a remote FC port.
  * @shost:	scsi host the remote port is connected to.
  * @channel:	Channel on shost port connected to.
  * @ids:	The world wide names, fc address, and FC4 port
@@ -2499,7 +2493,7 @@ delete_rport:
  *
  * Notes:
  *	This routine assumes no locks are held on entry.
- **/
+ */
 struct fc_rport *
 fc_remote_port_add(struct Scsi_Host *shost, int channel,
 	struct fc_rport_identifiers  *ids)
@@ -2683,19 +2677,18 @@ EXPORT_SYMBOL(fc_remote_port_add);
 
 
 /**
- * fc_remote_port_delete - notifies the fc transport that a remote
- *		port is no longer in existence.
+ * fc_remote_port_delete - notifies the fc transport that a remote port is no longer in existence.
  * @rport:	The remote port that no longer exists
  *
  * The LLDD calls this routine to notify the transport that a remote
  * port is no longer part of the topology. Note: Although a port
  * may no longer be part of the topology, it may persist in the remote
  * ports displayed by the fc_host. We do this under 2 conditions:
- * - If the port was a scsi target, we delay its deletion by "blocking" it.
+ * 1) If the port was a scsi target, we delay its deletion by "blocking" it.
  *   This allows the port to temporarily disappear, then reappear without
  *   disrupting the SCSI device tree attached to it. During the "blocked"
  *   period the port will still exist.
- * - If the port was a scsi target and disappears for longer than we
+ * 2) If the port was a scsi target and disappears for longer than we
  *   expect, we'll delete the port and the tear down the SCSI device tree
  *   attached to it. However, we want to semi-persist the target id assigned
  *   to that port if it eventually does exist. The port structure will
@@ -2709,7 +2702,8 @@ EXPORT_SYMBOL(fc_remote_port_add);
  * temporary blocked state. From the LLDD's perspective, the rport no
  * longer exists. From the SCSI midlayer's perspective, the SCSI target
  * exists, but all sdevs on it are blocked from further I/O. The following
- * is then expected:
+ * is then expected.
+ *
  *   If the remote port does not return (signaled by a LLDD call to
  *   fc_remote_port_add()) within the dev_loss_tmo timeout, then the
  *   scsi target is removed - killing all outstanding i/o and removing the
@@ -2731,7 +2725,7 @@ EXPORT_SYMBOL(fc_remote_port_add);
  *
  * Notes:
  *	This routine assumes no locks are held on entry.
- **/
+ */
 void
 fc_remote_port_delete(struct fc_rport  *rport)
 {
@@ -2792,12 +2786,12 @@ fc_remote_port_delete(struct fc_rport  *rport)
 EXPORT_SYMBOL(fc_remote_port_delete);
 
 /**
- * fc_remote_port_rolechg - notifies the fc transport that the roles
- *		on a remote may have changed.
+ * fc_remote_port_rolechg - notifies the fc transport that the roles on a remote may have changed.
  * @rport:	The remote port that changed.
+ * @roles:      New roles for this port.
  *
- * The LLDD calls this routine to notify the transport that the roles
- * on a remote port may have changed. The largest effect of this is
+ * Description: The LLDD calls this routine to notify the transport that the
+ * roles on a remote port may have changed. The largest effect of this is
  * if a port now becomes a FCP Target, it must be allocated a
  * scsi target id.  If the port is no longer a FCP target, any
  * scsi target id value assigned to it will persist in case the
@@ -2810,7 +2804,7 @@ EXPORT_SYMBOL(fc_remote_port_delete);
  *
  * Notes:
  *	This routine assumes no locks are held on entry.
- **/
+ */
 void
 fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
 {
@@ -2875,12 +2869,12 @@ fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
 EXPORT_SYMBOL(fc_remote_port_rolechg);
 
 /**
- * fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
- * 			which we blocked, and has now failed to return
- * 			in the allotted time.
- *
+ * fc_timeout_deleted_rport - Timeout handler for a deleted remote port.
  * @work:	rport target that failed to reappear in the allotted time.
- **/
+ *
+ * Description: An attempt to delete a remote port blocks, and if it fails
+ *              to return in the allotted time this gets called.
+ */
 static void
 fc_timeout_deleted_rport(struct work_struct *work)
 {
@@ -2984,14 +2978,12 @@ fc_timeout_deleted_rport(struct work_struct *work)
 }
 
 /**
- * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a
- *                       disconnected SCSI target.
- *
+ * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a disconnected SCSI target.
  * @work:	rport to terminate io on.
  *
  * Notes: Only requests the failure of the io, not that all are flushed
  *    prior to returning.
- **/
+ */
 static void
 fc_timeout_fail_rport_io(struct work_struct *work)
 {
@@ -3008,9 +3000,8 @@ fc_timeout_fail_rport_io(struct work_struct *work)
 
 /**
  * fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
- *
  * @work:	remote port to be scanned.
- **/
+ */
 static void
 fc_scsi_scan_rport(struct work_struct *work)
 {
@@ -3047,7 +3038,7 @@ fc_scsi_scan_rport(struct work_struct *work)
  *
  * Notes:
  *	This routine assumes no locks are held on entry.
- **/
+ */
 static int
 fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
 	struct fc_vport_identifiers  *ids, struct fc_vport **ret_vport)
@@ -3172,7 +3163,7 @@ delete_vport:
  *
  * Notes:
  *	This routine assumes no locks are held on entry.
- **/
+ */
 int
 fc_vport_terminate(struct fc_vport *vport)
 {
@@ -3232,9 +3223,8 @@ EXPORT_SYMBOL(fc_vport_terminate);
 
 /**
  * fc_vport_sched_delete - workq-based delete request for a vport
- *
  * @work:	vport to be deleted.
- **/
+ */
 static void
 fc_vport_sched_delete(struct work_struct *work)
 {
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 5428d15f23c6..0d7b4e79415c 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -30,10 +30,10 @@
 #include <scsi/scsi_transport_iscsi.h>
 #include <scsi/iscsi_if.h>
 
-#define ISCSI_SESSION_ATTRS 15
+#define ISCSI_SESSION_ATTRS 18
 #define ISCSI_CONN_ATTRS 11
 #define ISCSI_HOST_ATTRS 4
-#define ISCSI_TRANSPORT_VERSION "2.0-724"
+#define ISCSI_TRANSPORT_VERSION "2.0-867"
 
 struct iscsi_internal {
 	int daemon_pid;
@@ -50,6 +50,7 @@ struct iscsi_internal {
 };
 
 static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
+static struct workqueue_struct *iscsi_eh_timer_workq;
 
 /*
  * list of registered transports and lock that must
@@ -115,6 +116,8 @@ static struct attribute_group iscsi_transport_group = {
 	.attrs = iscsi_transport_attrs,
 };
 
+
+
 static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
 			    struct class_device *cdev)
 {
@@ -124,13 +127,30 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
 	memset(ihost, 0, sizeof(*ihost));
 	INIT_LIST_HEAD(&ihost->sessions);
 	mutex_init(&ihost->mutex);
+
+	snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d",
+		shost->host_no);
+	ihost->unbind_workq = create_singlethread_workqueue(
+						ihost->unbind_workq_name);
+	if (!ihost->unbind_workq)
+		return -ENOMEM;
+	return 0;
+}
+
+static int iscsi_remove_host(struct transport_container *tc, struct device *dev,
+			     struct class_device *cdev)
+{
+	struct Scsi_Host *shost = dev_to_shost(dev);
+	struct iscsi_host *ihost = shost->shost_data;
+
+	destroy_workqueue(ihost->unbind_workq);
 	return 0;
 }
 
 static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
 			       "iscsi_host",
 			       iscsi_setup_host,
-			       NULL,
+			       iscsi_remove_host,
 			       NULL);
 
 static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
@@ -252,7 +272,7 @@ static void session_recovery_timedout(struct work_struct *work)
 void iscsi_unblock_session(struct iscsi_cls_session *session)
 {
 	if (!cancel_delayed_work(&session->recovery_work))
-		flush_scheduled_work();
+		flush_workqueue(iscsi_eh_timer_workq);
 	scsi_target_unblock(&session->dev);
 }
 EXPORT_SYMBOL_GPL(iscsi_unblock_session);
@@ -260,11 +280,40 @@ EXPORT_SYMBOL_GPL(iscsi_unblock_session);
 void iscsi_block_session(struct iscsi_cls_session *session)
 {
 	scsi_target_block(&session->dev);
-	schedule_delayed_work(&session->recovery_work,
-			     session->recovery_tmo * HZ);
+	queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work,
+			   session->recovery_tmo * HZ);
 }
 EXPORT_SYMBOL_GPL(iscsi_block_session);
 
+static void __iscsi_unbind_session(struct work_struct *work)
+{
+	struct iscsi_cls_session *session =
+			container_of(work, struct iscsi_cls_session,
+				     unbind_work);
+	struct Scsi_Host *shost = iscsi_session_to_shost(session);
+	struct iscsi_host *ihost = shost->shost_data;
+
+	/* Prevent new scans and make sure scanning is not in progress */
+	mutex_lock(&ihost->mutex);
+	if (list_empty(&session->host_list)) {
+		mutex_unlock(&ihost->mutex);
+		return;
+	}
+	list_del_init(&session->host_list);
+	mutex_unlock(&ihost->mutex);
+
+	scsi_remove_target(&session->dev);
+	iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
+}
+
+static int iscsi_unbind_session(struct iscsi_cls_session *session)
+{
+	struct Scsi_Host *shost = iscsi_session_to_shost(session);
+	struct iscsi_host *ihost = shost->shost_data;
+
+	return queue_work(ihost->unbind_workq, &session->unbind_work);
+}
+
 struct iscsi_cls_session *
 iscsi_alloc_session(struct Scsi_Host *shost,
 		    struct iscsi_transport *transport)
@@ -281,6 +330,7 @@ iscsi_alloc_session(struct Scsi_Host *shost,
 	INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
 	INIT_LIST_HEAD(&session->host_list);
 	INIT_LIST_HEAD(&session->sess_list);
+	INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
 
 	/* this is released in the dev's release function */
 	scsi_host_get(shost);
@@ -297,6 +347,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
 {
 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
 	struct iscsi_host *ihost;
+	unsigned long flags;
 	int err;
 
 	ihost = shost->shost_data;
@@ -313,9 +364,15 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
 	}
 	transport_register_device(&session->dev);
 
+	spin_lock_irqsave(&sesslock, flags);
+	list_add(&session->sess_list, &sesslist);
+	spin_unlock_irqrestore(&sesslock, flags);
+
 	mutex_lock(&ihost->mutex);
 	list_add(&session->host_list, &ihost->sessions);
 	mutex_unlock(&ihost->mutex);
+
+	iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
 	return 0;
 
 release_host:
@@ -328,9 +385,10 @@ EXPORT_SYMBOL_GPL(iscsi_add_session);
  * iscsi_create_session - create iscsi class session
  * @shost: scsi host
  * @transport: iscsi transport
+ * @target_id: which target
  *
  * This can be called from a LLD or iscsi_transport.
- **/
+ */
 struct iscsi_cls_session *
 iscsi_create_session(struct Scsi_Host *shost,
 		     struct iscsi_transport *transport,
@@ -350,19 +408,58 @@ iscsi_create_session(struct Scsi_Host *shost,
 }
 EXPORT_SYMBOL_GPL(iscsi_create_session);
 
+static void iscsi_conn_release(struct device *dev)
+{
+	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
+	struct device *parent = conn->dev.parent;
+
+	kfree(conn);
+	put_device(parent);
+}
+
+static int iscsi_is_conn_dev(const struct device *dev)
+{
+	return dev->release == iscsi_conn_release;
+}
+
+static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
+{
+	if (!iscsi_is_conn_dev(dev))
+		return 0;
+	return iscsi_destroy_conn(iscsi_dev_to_conn(dev));
+}
+
 void iscsi_remove_session(struct iscsi_cls_session *session)
 {
 	struct Scsi_Host *shost = iscsi_session_to_shost(session);
 	struct iscsi_host *ihost = shost->shost_data;
+	unsigned long flags;
+	int err;
 
-	if (!cancel_delayed_work(&session->recovery_work))
-		flush_scheduled_work();
+	spin_lock_irqsave(&sesslock, flags);
+	list_del(&session->sess_list);
+	spin_unlock_irqrestore(&sesslock, flags);
 
-	mutex_lock(&ihost->mutex);
-	list_del(&session->host_list);
-	mutex_unlock(&ihost->mutex);
+	/*
+	 * If we are blocked let commands flow again. The lld or iscsi
+	 * layer should set up the queuecommand to fail commands.
+	 */
+	iscsi_unblock_session(session);
+	iscsi_unbind_session(session);
+	/*
+	 * If the session dropped while removing devices then we need to make
+	 * sure it is not blocked
+	 */
+	if (!cancel_delayed_work(&session->recovery_work))
+		flush_workqueue(iscsi_eh_timer_workq);
+	flush_workqueue(ihost->unbind_workq);
 
-	scsi_remove_target(&session->dev);
+	/* hw iscsi may not have removed all connections from session */
+	err = device_for_each_child(&session->dev, NULL,
+				    iscsi_iter_destroy_conn_fn);
+	if (err)
+		dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete "
+			   "all connections for session. Error %d.\n", err);
 
 	transport_unregister_device(&session->dev);
 	device_del(&session->dev);
@@ -371,9 +468,9 @@ EXPORT_SYMBOL_GPL(iscsi_remove_session);
 
 void iscsi_free_session(struct iscsi_cls_session *session)
 {
+	iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION);
 	put_device(&session->dev);
 }
-
 EXPORT_SYMBOL_GPL(iscsi_free_session);
 
 /**
@@ -382,7 +479,7 @@ EXPORT_SYMBOL_GPL(iscsi_free_session);
  *
  * Can be called by a LLD or iscsi_transport. There must not be
  * any running connections.
- **/
+ */
 int iscsi_destroy_session(struct iscsi_cls_session *session)
 {
 	iscsi_remove_session(session);
@@ -391,20 +488,6 @@ int iscsi_destroy_session(struct iscsi_cls_session *session)
 }
 EXPORT_SYMBOL_GPL(iscsi_destroy_session);
 
-static void iscsi_conn_release(struct device *dev)
-{
-	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
-	struct device *parent = conn->dev.parent;
-
-	kfree(conn);
-	put_device(parent);
-}
-
-static int iscsi_is_conn_dev(const struct device *dev)
-{
-	return dev->release == iscsi_conn_release;
-}
-
 /**
  * iscsi_create_conn - create iscsi class connection
  * @session: iscsi cls session
@@ -418,12 +501,13 @@ static int iscsi_is_conn_dev(const struct device *dev)
  * for software iscsi we could be trying to preallocate a connection struct
  * in which case there could be two connection structs and cid would be
  * non-zero.
- **/
+ */
 struct iscsi_cls_conn *
 iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
 {
 	struct iscsi_transport *transport = session->transport;
 	struct iscsi_cls_conn *conn;
+	unsigned long flags;
 	int err;
 
 	conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
@@ -452,6 +536,11 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
 		goto release_parent_ref;
 	}
 	transport_register_device(&conn->dev);
+
+	spin_lock_irqsave(&connlock, flags);
+	list_add(&conn->conn_list, &connlist);
+	conn->active = 1;
+	spin_unlock_irqrestore(&connlock, flags);
 	return conn;
 
 release_parent_ref:
@@ -465,17 +554,23 @@ EXPORT_SYMBOL_GPL(iscsi_create_conn);
 
 /**
  * iscsi_destroy_conn - destroy iscsi class connection
- * @session: iscsi cls session
+ * @conn: iscsi cls session
  *
  * This can be called from a LLD or iscsi_transport.
- **/
+ */
 int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&connlock, flags);
+	conn->active = 0;
+	list_del(&conn->conn_list);
+	spin_unlock_irqrestore(&connlock, flags);
+
 	transport_unregister_device(&conn->dev);
 	device_unregister(&conn->dev);
 	return 0;
 }
-
 EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
 
 /*
@@ -685,132 +780,74 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
 }
 
 /**
- * iscsi_if_destroy_session_done - send session destr. completion event
- * @conn: last connection for session
- *
- * This is called by HW iscsi LLDs to notify userpsace that its HW has
- * removed a session.
- **/
-int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn)
+ * iscsi_session_event - send session destr. completion event
+ * @session: iscsi class session
+ * @event: type of event
+ */
+int iscsi_session_event(struct iscsi_cls_session *session,
+			enum iscsi_uevent_e event)
 {
 	struct iscsi_internal *priv;
-	struct iscsi_cls_session *session;
 	struct Scsi_Host *shost;
 	struct iscsi_uevent *ev;
 	struct sk_buff  *skb;
 	struct nlmsghdr *nlh;
-	unsigned long flags;
 	int rc, len = NLMSG_SPACE(sizeof(*ev));
 
-	priv = iscsi_if_transport_lookup(conn->transport);
+	priv = iscsi_if_transport_lookup(session->transport);
 	if (!priv)
 		return -EINVAL;
-
-	session = iscsi_dev_to_session(conn->dev.parent);
 	shost = iscsi_session_to_shost(session);
 
 	skb = alloc_skb(len, GFP_KERNEL);
 	if (!skb) {
-		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
-			  "session creation event\n");
+		dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
+			  "of session event %u\n", event);
 		return -ENOMEM;
 	}
 
 	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
 	ev = NLMSG_DATA(nlh);
-	ev->transport_handle = iscsi_handle(conn->transport);
-	ev->type = ISCSI_KEVENT_DESTROY_SESSION;
-	ev->r.d_session.host_no = shost->host_no;
-	ev->r.d_session.sid = session->sid;
-
-	/*
-	 * this will occur if the daemon is not up, so we just warn
-	 * the user and when the daemon is restarted it will handle it
-	 */
-	rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
-	if (rc < 0)
-		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
-			  "session destruction event. Check iscsi daemon\n");
-
-	spin_lock_irqsave(&sesslock, flags);
-	list_del(&session->sess_list);
-	spin_unlock_irqrestore(&sesslock, flags);
+	ev->transport_handle = iscsi_handle(session->transport);
 
-	spin_lock_irqsave(&connlock, flags);
-	conn->active = 0;
-	list_del(&conn->conn_list);
-	spin_unlock_irqrestore(&connlock, flags);
-
-	return rc;
-}
-EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done);
-
-/**
- * iscsi_if_create_session_done - send session creation completion event
- * @conn: leading connection for session
- *
- * This is called by HW iscsi LLDs to notify userpsace that its HW has
- * created a session or a existing session is back in the logged in state.
- **/
-int iscsi_if_create_session_done(struct iscsi_cls_conn *conn)
-{
-	struct iscsi_internal *priv;
-	struct iscsi_cls_session *session;
-	struct Scsi_Host *shost;
-	struct iscsi_uevent *ev;
-	struct sk_buff  *skb;
-	struct nlmsghdr *nlh;
-	unsigned long flags;
-	int rc, len = NLMSG_SPACE(sizeof(*ev));
-
-	priv = iscsi_if_transport_lookup(conn->transport);
-	if (!priv)
+	ev->type = event;
+	switch (event) {
+	case ISCSI_KEVENT_DESTROY_SESSION:
+		ev->r.d_session.host_no = shost->host_no;
+		ev->r.d_session.sid = session->sid;
+		break;
+	case ISCSI_KEVENT_CREATE_SESSION:
+		ev->r.c_session_ret.host_no = shost->host_no;
+		ev->r.c_session_ret.sid = session->sid;
+		break;
+	case ISCSI_KEVENT_UNBIND_SESSION:
+		ev->r.unbind_session.host_no = shost->host_no;
+		ev->r.unbind_session.sid = session->sid;
+		break;
+	default:
+		dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n",
+			   event);
+		kfree_skb(skb);
 		return -EINVAL;
-
-	session = iscsi_dev_to_session(conn->dev.parent);
-	shost = iscsi_session_to_shost(session);
-
-	skb = alloc_skb(len, GFP_KERNEL);
-	if (!skb) {
-		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
-			  "session creation event\n");
-		return -ENOMEM;
 	}
 
-	nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
-	ev = NLMSG_DATA(nlh);
-	ev->transport_handle = iscsi_handle(conn->transport);
-	ev->type = ISCSI_UEVENT_CREATE_SESSION;
-	ev->r.c_session_ret.host_no = shost->host_no;
-	ev->r.c_session_ret.sid = session->sid;
-
 	/*
 	 * this will occur if the daemon is not up, so we just warn
 	 * the user and when the daemon is restarted it will handle it
 	 */
 	rc = iscsi_broadcast_skb(skb, GFP_KERNEL);
 	if (rc < 0)
-		dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
-			  "session creation event. Check iscsi daemon\n");
-
-	spin_lock_irqsave(&sesslock, flags);
-	list_add(&session->sess_list, &sesslist);
-	spin_unlock_irqrestore(&sesslock, flags);
-
-	spin_lock_irqsave(&connlock, flags);
-	list_add(&conn->conn_list, &connlist);
-	conn->active = 1;
-	spin_unlock_irqrestore(&connlock, flags);
+		dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace "
+			  "of session event %u. Check iscsi daemon\n", event);
 	return rc;
 }
-EXPORT_SYMBOL_GPL(iscsi_if_create_session_done);
+EXPORT_SYMBOL_GPL(iscsi_session_event);
 
 static int
 iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
 {
 	struct iscsi_transport *transport = priv->iscsi_transport;
 	struct iscsi_cls_session *session;
-	unsigned long flags;
 	uint32_t hostno;
 
 	session = transport->create_session(transport, &priv->t,
@@ -821,10 +858,6 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
 	if (!session)
 		return -ENOMEM;
 
-	spin_lock_irqsave(&sesslock, flags);
-	list_add(&session->sess_list, &sesslist);
-	spin_unlock_irqrestore(&sesslock, flags);
-
 	ev->r.c_session_ret.host_no = hostno;
 	ev->r.c_session_ret.sid = session->sid;
 	return 0;
@@ -835,7 +868,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 {
 	struct iscsi_cls_conn *conn;
 	struct iscsi_cls_session *session;
-	unsigned long flags;
 
 	session = iscsi_session_lookup(ev->u.c_conn.sid);
 	if (!session) {
@@ -854,28 +886,17 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 
 	ev->r.c_conn_ret.sid = session->sid;
 	ev->r.c_conn_ret.cid = conn->cid;
-
-	spin_lock_irqsave(&connlock, flags);
-	list_add(&conn->conn_list, &connlist);
-	conn->active = 1;
-	spin_unlock_irqrestore(&connlock, flags);
-
 	return 0;
 }
 
 static int
 iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 {
-	unsigned long flags;
 	struct iscsi_cls_conn *conn;
 
 	conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
 	if (!conn)
 		return -EINVAL;
-	spin_lock_irqsave(&connlock, flags);
-	conn->active = 0;
-	list_del(&conn->conn_list);
-	spin_unlock_irqrestore(&connlock, flags);
 
 	if (transport->destroy_conn)
 		transport->destroy_conn(conn);
@@ -1002,7 +1023,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 	struct iscsi_internal *priv;
 	struct iscsi_cls_session *session;
 	struct iscsi_cls_conn *conn;
-	unsigned long flags;
 
 	priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
 	if (!priv)
@@ -1020,13 +1040,16 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 		break;
 	case ISCSI_UEVENT_DESTROY_SESSION:
 		session = iscsi_session_lookup(ev->u.d_session.sid);
-		if (session) {
-			spin_lock_irqsave(&sesslock, flags);
-			list_del(&session->sess_list);
-			spin_unlock_irqrestore(&sesslock, flags);
-
+		if (session)
 			transport->destroy_session(session);
-		} else
+		else
+			err = -EINVAL;
+		break;
+	case ISCSI_UEVENT_UNBIND_SESSION:
+		session = iscsi_session_lookup(ev->u.d_session.sid);
+		if (session)
+			iscsi_unbind_session(session);
+		else
 			err = -EINVAL;
 		break;
 	case ISCSI_UEVENT_CREATE_CONN:
@@ -1179,6 +1202,8 @@ iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT);
 iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
 iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
 iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
+iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
+iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
 
 #define iscsi_cdev_to_session(_cdev) \
 	iscsi_dev_to_session(_cdev->dev)
@@ -1217,6 +1242,9 @@ iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
 iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
 iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
 iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
+iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
+iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
+iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
 
 #define iscsi_priv_session_attr_show(field, format)			\
 static ssize_t								\
@@ -1413,6 +1441,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
 	SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
 	SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
 	SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
+	SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO);
+	SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO);
 
 	BUG_ON(count > ISCSI_CONN_ATTRS);
 	priv->conn_attrs[count] = NULL;
@@ -1438,6 +1468,9 @@ iscsi_register_transport(struct iscsi_transport *tt)
 	SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);
 	SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);
 	SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);
+	SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
+	SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
+	SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
 	SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
 
 	BUG_ON(count > ISCSI_SESSION_ATTRS);
@@ -1518,8 +1551,14 @@ static __init int iscsi_transport_init(void)
 		goto unregister_session_class;
 	}
 
+	iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
+	if (!iscsi_eh_timer_workq)
+		goto release_nls;
+
 	return 0;
 
+release_nls:
+	netlink_kernel_release(nls);
 unregister_session_class:
 	transport_class_unregister(&iscsi_session_class);
 unregister_conn_class:
@@ -1533,7 +1572,8 @@ unregister_transport_class:
 
 static void __exit iscsi_transport_exit(void)
 {
-	sock_release(nls->sk_socket);
+	destroy_workqueue(iscsi_eh_timer_workq);
+	netlink_kernel_release(nls);
 	transport_class_unregister(&iscsi_connection_class);
 	transport_class_unregister(&iscsi_session_class);
 	transport_class_unregister(&iscsi_host_class);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 3120f4b3a11a..f2149d0bb999 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -173,6 +173,7 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
 
 		handler = to_sas_internal(shost->transportt)->f->smp_handler;
 		ret = handler(shost, rphy, req);
+		req->errors = ret;
 
 		spin_lock_irq(q->queue_lock);
 
@@ -323,7 +324,7 @@ static int do_sas_phy_delete(struct device *dev, void *data)
 }
 
 /**
- * sas_remove_children  --  tear down a devices SAS data structures
+ * sas_remove_children  -  tear down a devices SAS data structures
  * @dev:	device belonging to the sas object
  *
  * Removes all SAS PHYs and remote PHYs for a given object
@@ -336,7 +337,7 @@ void sas_remove_children(struct device *dev)
 EXPORT_SYMBOL(sas_remove_children);
 
 /**
- * sas_remove_host  --  tear down a Scsi_Host's SAS data structures
+ * sas_remove_host  -  tear down a Scsi_Host's SAS data structures
  * @shost:	Scsi Host that is torn down
  *
  * Removes all SAS PHYs and remote PHYs for a given Scsi_Host.
@@ -577,7 +578,7 @@ static void sas_phy_release(struct device *dev)
 }
 
 /**
- * sas_phy_alloc  --  allocates and initialize a SAS PHY structure
+ * sas_phy_alloc  -  allocates and initialize a SAS PHY structure
  * @parent:	Parent device
  * @number:	Phy index
  *
@@ -618,7 +619,7 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
 EXPORT_SYMBOL(sas_phy_alloc);
 
 /**
- * sas_phy_add  --  add a SAS PHY to the device hierarchy
+ * sas_phy_add  -  add a SAS PHY to the device hierarchy
  * @phy:	The PHY to be added
  *
  * Publishes a SAS PHY to the rest of the system.
@@ -638,7 +639,7 @@ int sas_phy_add(struct sas_phy *phy)
 EXPORT_SYMBOL(sas_phy_add);
 
 /**
- * sas_phy_free  --  free a SAS PHY
+ * sas_phy_free  -  free a SAS PHY
  * @phy:	SAS PHY to free
  *
  * Frees the specified SAS PHY.
@@ -655,7 +656,7 @@ void sas_phy_free(struct sas_phy *phy)
 EXPORT_SYMBOL(sas_phy_free);
 
 /**
- * sas_phy_delete  --  remove SAS PHY
+ * sas_phy_delete  -  remove SAS PHY
  * @phy:	SAS PHY to remove
  *
  * Removes the specified SAS PHY.  If the SAS PHY has an
@@ -677,7 +678,7 @@ sas_phy_delete(struct sas_phy *phy)
 EXPORT_SYMBOL(sas_phy_delete);
 
 /**
- * scsi_is_sas_phy  --  check if a struct device represents a SAS PHY
+ * scsi_is_sas_phy  -  check if a struct device represents a SAS PHY
  * @dev:	device to check
  *
  * Returns:
@@ -843,7 +844,6 @@ EXPORT_SYMBOL(sas_port_alloc_num);
 
 /**
  * sas_port_add - add a SAS port to the device hierarchy
- *
  * @port:	port to be added
  *
  * publishes a port to the rest of the system
@@ -868,7 +868,7 @@ int sas_port_add(struct sas_port *port)
 EXPORT_SYMBOL(sas_port_add);
 
 /**
- * sas_port_free  --  free a SAS PORT
+ * sas_port_free  -  free a SAS PORT
  * @port:	SAS PORT to free
  *
  * Frees the specified SAS PORT.
@@ -885,7 +885,7 @@ void sas_port_free(struct sas_port *port)
 EXPORT_SYMBOL(sas_port_free);
 
 /**
- * sas_port_delete  --  remove SAS PORT
+ * sas_port_delete  -  remove SAS PORT
  * @port:	SAS PORT to remove
  *
  * Removes the specified SAS PORT.  If the SAS PORT has an
@@ -924,7 +924,7 @@ void sas_port_delete(struct sas_port *port)
 EXPORT_SYMBOL(sas_port_delete);
 
 /**
- * scsi_is_sas_port --  check if a struct device represents a SAS port
+ * scsi_is_sas_port -  check if a struct device represents a SAS port
  * @dev:	device to check
  *
  * Returns:
@@ -1309,6 +1309,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy)
 
 /**
  * sas_end_device_alloc - allocate an rphy for an end device
+ * @parent: which port
  *
  * Allocates an SAS remote PHY structure, connected to @parent.
  *
@@ -1345,6 +1346,8 @@ EXPORT_SYMBOL(sas_end_device_alloc);
 
 /**
  * sas_expander_alloc - allocate an rphy for an end device
+ * @parent: which port
+ * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE
  *
  * Allocates an SAS remote PHY structure, connected to @parent.
  *
@@ -1383,7 +1386,7 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
 EXPORT_SYMBOL(sas_expander_alloc);
 
 /**
- * sas_rphy_add  --  add a SAS remote PHY to the device hierarchy
+ * sas_rphy_add  -  add a SAS remote PHY to the device hierarchy
  * @rphy:	The remote PHY to be added
  *
  * Publishes a SAS remote PHY to the rest of the system.
@@ -1430,8 +1433,8 @@ int sas_rphy_add(struct sas_rphy *rphy)
 EXPORT_SYMBOL(sas_rphy_add);
 
 /**
- * sas_rphy_free  --  free a SAS remote PHY
- * @rphy	SAS remote PHY to free
+ * sas_rphy_free  -  free a SAS remote PHY
+ * @rphy: SAS remote PHY to free
  *
  * Frees the specified SAS remote PHY.
  *
@@ -1459,7 +1462,7 @@ void sas_rphy_free(struct sas_rphy *rphy)
 EXPORT_SYMBOL(sas_rphy_free);
 
 /**
- * sas_rphy_delete  --  remove and free SAS remote PHY
+ * sas_rphy_delete  -  remove and free SAS remote PHY
  * @rphy:	SAS remote PHY to remove and free
  *
  * Removes the specified SAS remote PHY and frees it.
@@ -1473,7 +1476,7 @@ sas_rphy_delete(struct sas_rphy *rphy)
 EXPORT_SYMBOL(sas_rphy_delete);
 
 /**
- * sas_rphy_remove  --  remove SAS remote PHY
+ * sas_rphy_remove  -  remove SAS remote PHY
  * @rphy:	SAS remote phy to remove
  *
  * Removes the specified SAS remote PHY.
@@ -1504,7 +1507,7 @@ sas_rphy_remove(struct sas_rphy *rphy)
 EXPORT_SYMBOL(sas_rphy_remove);
 
 /**
- * scsi_is_sas_rphy  --  check if a struct device represents a SAS remote PHY
+ * scsi_is_sas_rphy  -  check if a struct device represents a SAS remote PHY
  * @dev:	device to check
  *
  * Returns:
@@ -1604,7 +1607,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
 	SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
 
 /**
- * sas_attach_transport  --  instantiate SAS transport template
+ * sas_attach_transport  -  instantiate SAS transport template
  * @ft:		SAS transport class function template
  */
 struct scsi_transport_template *
@@ -1715,7 +1718,7 @@ sas_attach_transport(struct sas_function_template *ft)
 EXPORT_SYMBOL(sas_attach_transport);
 
 /**
- * sas_release_transport  --  release SAS transport template instance
+ * sas_release_transport  -  release SAS transport template instance
  * @t:		transport template instance
  */
 void sas_release_transport(struct scsi_transport_template *t)
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 4df21c92ff1e..1fb60313a516 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -52,13 +52,6 @@
 struct spi_internal {
 	struct scsi_transport_template t;
 	struct spi_function_template *f;
-	/* The actual attributes */
-	struct class_device_attribute private_attrs[SPI_NUM_ATTRS];
-	/* The array of null terminated pointers to attributes 
-	 * needed by scsi_sysfs.c */
-	struct class_device_attribute *attrs[SPI_NUM_ATTRS + SPI_OTHER_ATTRS + 1];
-	struct class_device_attribute private_host_attrs[SPI_HOST_ATTRS];
-	struct class_device_attribute *host_attrs[SPI_HOST_ATTRS + 1];
 };
 
 #define to_spi_internal(tmpl)	container_of(tmpl, struct spi_internal, t)
@@ -174,17 +167,20 @@ static int spi_host_setup(struct transport_container *tc, struct device *dev,
 	return 0;
 }
 
+static int spi_host_configure(struct transport_container *tc,
+			      struct device *dev,
+			      struct class_device *cdev);
+
 static DECLARE_TRANSPORT_CLASS(spi_host_class,
 			       "spi_host",
 			       spi_host_setup,
 			       NULL,
-			       NULL);
+			       spi_host_configure);
 
 static int spi_host_match(struct attribute_container *cont,
 			  struct device *dev)
 {
 	struct Scsi_Host *shost;
-	struct spi_internal *i;
 
 	if (!scsi_is_host_device(dev))
 		return 0;
@@ -194,11 +190,13 @@ static int spi_host_match(struct attribute_container *cont,
 	    != &spi_host_class.class)
 		return 0;
 
-	i = to_spi_internal(shost->transportt);
-	
-	return &i->t.host_attrs.ac == cont;
+	return &shost->transportt->host_attrs.ac == cont;
 }
 
+static int spi_target_configure(struct transport_container *tc,
+				struct device *dev,
+				struct class_device *cdev);
+
 static int spi_device_configure(struct transport_container *tc,
 				struct device *dev,
 				struct class_device *cdev)
@@ -300,8 +298,10 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
 	struct spi_internal *i = to_spi_internal(shost->transportt);	\
 									\
+	if (!i->f->set_##field)						\
+		return -EINVAL;						\
 	val = simple_strtoul(buf, NULL, 0);				\
-	i->f->set_##field(starget, val);			\
+	i->f->set_##field(starget, val);				\
 	return count;							\
 }
 
@@ -317,6 +317,8 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
 	struct spi_transport_attrs *tp					\
 		= (struct spi_transport_attrs *)&starget->starget_data;	\
 									\
+	if (i->f->set_##field)						\
+		return -EINVAL;						\
 	val = simple_strtoul(buf, NULL, 0);				\
 	if (val > tp->max_##field)					\
 		val = tp->max_##field;					\
@@ -327,14 +329,14 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \
 #define spi_transport_rd_attr(field, format_string)			\
 	spi_transport_show_function(field, format_string)		\
 	spi_transport_store_function(field, format_string)		\
-static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
+static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
 			 show_spi_transport_##field,			\
 			 store_spi_transport_##field);
 
 #define spi_transport_simple_attr(field, format_string)			\
 	spi_transport_show_simple(field, format_string)			\
 	spi_transport_store_simple(field, format_string)		\
-static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
+static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
 			 show_spi_transport_##field,			\
 			 store_spi_transport_##field);
 
@@ -342,7 +344,7 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
 	spi_transport_show_function(field, format_string)		\
 	spi_transport_store_max(field, format_string)			\
 	spi_transport_simple_attr(max_##field, format_string)		\
-static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
+static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
 			 show_spi_transport_##field,			\
 			 store_spi_transport_##field);
 
@@ -472,6 +474,9 @@ store_spi_transport_period(struct class_device *cdev, const char *buf,
 		(struct spi_transport_attrs *)&starget->starget_data;
 	int period, retval;
 
+	if (!i->f->set_period)
+		return -EINVAL;
+
 	retval = store_spi_transport_period_helper(cdev, buf, count, &period);
 
 	if (period < tp->min_period)
@@ -482,7 +487,7 @@ store_spi_transport_period(struct class_device *cdev, const char *buf,
 	return retval;
 }
 
-static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 
+static CLASS_DEVICE_ATTR(period, S_IRUGO,
 			 show_spi_transport_period,
 			 store_spi_transport_period);
 
@@ -490,9 +495,14 @@ static ssize_t
 show_spi_transport_min_period(struct class_device *cdev, char *buf)
 {
 	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct spi_internal *i = to_spi_internal(shost->transportt);
 	struct spi_transport_attrs *tp =
 		(struct spi_transport_attrs *)&starget->starget_data;
 
+	if (!i->f->set_period)
+		return -EINVAL;
+
 	return show_spi_transport_period_helper(buf, tp->min_period);
 }
 
@@ -509,7 +519,7 @@ store_spi_transport_min_period(struct class_device *cdev, const char *buf,
 }
 
 
-static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, 
+static CLASS_DEVICE_ATTR(min_period, S_IRUGO,
 			 show_spi_transport_min_period,
 			 store_spi_transport_min_period);
 
@@ -531,12 +541,15 @@ static ssize_t store_spi_host_signalling(struct class_device *cdev,
 	struct spi_internal *i = to_spi_internal(shost->transportt);
 	enum spi_signal_type type = spi_signal_to_value(buf);
 
+	if (!i->f->set_signalling)
+		return -EINVAL;
+
 	if (type != SPI_SIGNAL_UNKNOWN)
 		i->f->set_signalling(shost, type);
 
 	return count;
 }
-static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR,
+static CLASS_DEVICE_ATTR(signalling, S_IRUGO,
 			 show_spi_host_signalling,
 			 store_spi_host_signalling);
 
@@ -1262,35 +1275,6 @@ int spi_print_msg(const unsigned char *msg)
 EXPORT_SYMBOL(spi_print_msg);
 #endif /* ! CONFIG_SCSI_CONSTANTS */
 
-#define SETUP_ATTRIBUTE(field)						\
-	i->private_attrs[count] = class_device_attr_##field;		\
-	if (!i->f->set_##field) {					\
-		i->private_attrs[count].attr.mode = S_IRUGO;		\
-		i->private_attrs[count].store = NULL;			\
-	}								\
-	i->attrs[count] = &i->private_attrs[count];			\
-	if (i->f->show_##field)						\
-		count++
-
-#define SETUP_RELATED_ATTRIBUTE(field, rel_field)			\
-	i->private_attrs[count] = class_device_attr_##field;		\
-	if (!i->f->set_##rel_field) {					\
-		i->private_attrs[count].attr.mode = S_IRUGO;		\
-		i->private_attrs[count].store = NULL;			\
-	}								\
-	i->attrs[count] = &i->private_attrs[count];			\
-	if (i->f->show_##rel_field)					\
-		count++
-
-#define SETUP_HOST_ATTRIBUTE(field)					\
-	i->private_host_attrs[count] = class_device_attr_##field;	\
-	if (!i->f->set_##field) {					\
-		i->private_host_attrs[count].attr.mode = S_IRUGO;	\
-		i->private_host_attrs[count].store = NULL;		\
-	}								\
-	i->host_attrs[count] = &i->private_host_attrs[count];		\
-	count++
-
 static int spi_device_match(struct attribute_container *cont,
 			    struct device *dev)
 {
@@ -1343,16 +1327,156 @@ static DECLARE_TRANSPORT_CLASS(spi_transport_class,
 			       "spi_transport",
 			       spi_setup_transport_attrs,
 			       NULL,
-			       NULL);
+			       spi_target_configure);
 
 static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class,
 				    spi_device_match,
 				    spi_device_configure);
 
+static struct attribute *host_attributes[] = {
+	&class_device_attr_signalling.attr,
+	NULL
+};
+
+static struct attribute_group host_attribute_group = {
+	.attrs = host_attributes,
+};
+
+static int spi_host_configure(struct transport_container *tc,
+			      struct device *dev,
+			      struct class_device *cdev)
+{
+	struct kobject *kobj = &cdev->kobj;
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct spi_internal *si = to_spi_internal(shost->transportt);
+	struct attribute *attr = &class_device_attr_signalling.attr;
+	int rc = 0;
+
+	if (si->f->set_signalling)
+		rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
+
+	return rc;
+}
+
+/* returns true if we should be showing the variable.  Also
+ * overloads the return by setting 1<<1 if the attribute should
+ * be writeable */
+#define TARGET_ATTRIBUTE_HELPER(name) \
+	(si->f->show_##name ? 1 : 0) + \
+	(si->f->set_##name ? 2 : 0)
+
+static int target_attribute_is_visible(struct kobject *kobj,
+				       struct attribute *attr, int i)
+{
+	struct class_device *cdev =
+		container_of(kobj, struct class_device, kobj);
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct spi_internal *si = to_spi_internal(shost->transportt);
+
+	if (attr == &class_device_attr_period.attr &&
+	    spi_support_sync(starget))
+		return TARGET_ATTRIBUTE_HELPER(period);
+	else if (attr == &class_device_attr_min_period.attr &&
+		 spi_support_sync(starget))
+		return TARGET_ATTRIBUTE_HELPER(period);
+	else if (attr == &class_device_attr_offset.attr &&
+		 spi_support_sync(starget))
+		return TARGET_ATTRIBUTE_HELPER(offset);
+	else if (attr == &class_device_attr_max_offset.attr &&
+		 spi_support_sync(starget))
+		return TARGET_ATTRIBUTE_HELPER(offset);
+	else if (attr == &class_device_attr_width.attr &&
+		 spi_support_wide(starget))
+		return TARGET_ATTRIBUTE_HELPER(width);
+	else if (attr == &class_device_attr_max_width.attr &&
+		 spi_support_wide(starget))
+		return TARGET_ATTRIBUTE_HELPER(width);
+	else if (attr == &class_device_attr_iu.attr &&
+		 spi_support_ius(starget))
+		return TARGET_ATTRIBUTE_HELPER(iu);
+	else if (attr == &class_device_attr_dt.attr &&
+		 spi_support_dt(starget))
+		return TARGET_ATTRIBUTE_HELPER(dt);
+	else if (attr == &class_device_attr_qas.attr &&
+		 spi_support_qas(starget))
+		return TARGET_ATTRIBUTE_HELPER(qas);
+	else if (attr == &class_device_attr_wr_flow.attr &&
+		 spi_support_ius(starget))
+		return TARGET_ATTRIBUTE_HELPER(wr_flow);
+	else if (attr == &class_device_attr_rd_strm.attr &&
+		 spi_support_ius(starget))
+		return TARGET_ATTRIBUTE_HELPER(rd_strm);
+	else if (attr == &class_device_attr_rti.attr &&
+		 spi_support_ius(starget))
+		return TARGET_ATTRIBUTE_HELPER(rti);
+	else if (attr == &class_device_attr_pcomp_en.attr &&
+		 spi_support_ius(starget))
+		return TARGET_ATTRIBUTE_HELPER(pcomp_en);
+	else if (attr == &class_device_attr_hold_mcs.attr &&
+		 spi_support_ius(starget))
+		return TARGET_ATTRIBUTE_HELPER(hold_mcs);
+	else if (attr == &class_device_attr_revalidate.attr)
+		return 1;
+
+	return 0;
+}
+
+static struct attribute *target_attributes[] = {
+	&class_device_attr_period.attr,
+	&class_device_attr_min_period.attr,
+	&class_device_attr_offset.attr,
+	&class_device_attr_max_offset.attr,
+	&class_device_attr_width.attr,
+	&class_device_attr_max_width.attr,
+	&class_device_attr_iu.attr,
+	&class_device_attr_dt.attr,
+	&class_device_attr_qas.attr,
+	&class_device_attr_wr_flow.attr,
+	&class_device_attr_rd_strm.attr,
+	&class_device_attr_rti.attr,
+	&class_device_attr_pcomp_en.attr,
+	&class_device_attr_hold_mcs.attr,
+	&class_device_attr_revalidate.attr,
+	NULL
+};
+
+static struct attribute_group target_attribute_group = {
+	.attrs = target_attributes,
+	.is_visible = target_attribute_is_visible,
+};
+
+static int spi_target_configure(struct transport_container *tc,
+				struct device *dev,
+				struct class_device *cdev)
+{
+	struct kobject *kobj = &cdev->kobj;
+	int i;
+	struct attribute *attr;
+	int rc;
+
+	for (i = 0; (attr = target_attributes[i]) != NULL; i++) {
+		int j = target_attribute_group.is_visible(kobj, attr, i);
+
+		/* FIXME: as well as returning -EEXIST, which we'd like
+		 * to ignore, sysfs also does a WARN_ON and dumps a trace,
+		 * which is bad, so temporarily, skip attributes that are
+		 * already visible (the revalidate one) */
+		if (j && attr != &class_device_attr_revalidate.attr)
+			rc = sysfs_add_file_to_group(kobj, attr,
+						target_attribute_group.name);
+		/* and make the attribute writeable if we have a set
+		 * function */
+		if ((j & 1))
+			rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR);
+	}
+
+	return 0;
+}
+
 struct scsi_transport_template *
 spi_attach_transport(struct spi_function_template *ft)
 {
-	int count = 0;
 	struct spi_internal *i = kzalloc(sizeof(struct spi_internal),
 					 GFP_KERNEL);
 
@@ -1360,47 +1484,17 @@ spi_attach_transport(struct spi_function_template *ft)
 		return NULL;
 
 	i->t.target_attrs.ac.class = &spi_transport_class.class;
-	i->t.target_attrs.ac.attrs = &i->attrs[0];
+	i->t.target_attrs.ac.grp = &target_attribute_group;
 	i->t.target_attrs.ac.match = spi_target_match;
 	transport_container_register(&i->t.target_attrs);
 	i->t.target_size = sizeof(struct spi_transport_attrs);
 	i->t.host_attrs.ac.class = &spi_host_class.class;
-	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+	i->t.host_attrs.ac.grp = &host_attribute_group;
 	i->t.host_attrs.ac.match = spi_host_match;
 	transport_container_register(&i->t.host_attrs);
 	i->t.host_size = sizeof(struct spi_host_attrs);
 	i->f = ft;
 
-	SETUP_ATTRIBUTE(period);
-	SETUP_RELATED_ATTRIBUTE(min_period, period);
-	SETUP_ATTRIBUTE(offset);
-	SETUP_RELATED_ATTRIBUTE(max_offset, offset);
-	SETUP_ATTRIBUTE(width);
-	SETUP_RELATED_ATTRIBUTE(max_width, width);
-	SETUP_ATTRIBUTE(iu);
-	SETUP_ATTRIBUTE(dt);
-	SETUP_ATTRIBUTE(qas);
-	SETUP_ATTRIBUTE(wr_flow);
-	SETUP_ATTRIBUTE(rd_strm);
-	SETUP_ATTRIBUTE(rti);
-	SETUP_ATTRIBUTE(pcomp_en);
-	SETUP_ATTRIBUTE(hold_mcs);
-
-	/* if you add an attribute but forget to increase SPI_NUM_ATTRS
-	 * this bug will trigger */
-	BUG_ON(count > SPI_NUM_ATTRS);
-
-	i->attrs[count++] = &class_device_attr_revalidate;
-
-	i->attrs[count] = NULL;
-
-	count = 0;
-	SETUP_HOST_ATTRIBUTE(signalling);
-
-	BUG_ON(count > SPI_HOST_ATTRS);
-
-	i->host_attrs[count] = NULL;
-
 	return &i->t;
 }
 EXPORT_SYMBOL(spi_attach_transport);
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
index 65c584db33bd..2445c98ae95e 100644
--- a/drivers/scsi/scsi_transport_srp.c
+++ b/drivers/scsi/scsi_transport_srp.c
@@ -185,11 +185,10 @@ static int srp_host_match(struct attribute_container *cont, struct device *dev)
 
 /**
  * srp_rport_add - add a SRP remote port to the device hierarchy
- *
  * @shost:	scsi host the remote port is connected to.
  * @ids:	The port id for the remote port.
  *
- * publishes a port to the rest of the system
+ * Publishes a port to the rest of the system.
  */
 struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
 				struct srp_rport_identifiers *ids)
@@ -242,8 +241,8 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
 EXPORT_SYMBOL_GPL(srp_rport_add);
 
 /**
- * srp_rport_del  --  remove a SRP remote port
- * @port:	SRP remote port to remove
+ * srp_rport_del  -  remove a SRP remote port
+ * @rport:	SRP remote port to remove
  *
  * Removes the specified SRP remote port.
  */
@@ -271,7 +270,7 @@ static int do_srp_rport_del(struct device *dev, void *data)
 }
 
 /**
- * srp_remove_host  --  tear down a Scsi_Host's SRP data structures
+ * srp_remove_host  -  tear down a Scsi_Host's SRP data structures
  * @shost:	Scsi Host that is torn down
  *
  * Removes all SRP remote ports for a given Scsi_Host.
@@ -297,7 +296,7 @@ static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
 }
 
 /**
- * srp_attach_transport  --  instantiate SRP transport template
+ * srp_attach_transport  -  instantiate SRP transport template
  * @ft:		SRP transport class function template
  */
 struct scsi_transport_template *
@@ -337,7 +336,7 @@ srp_attach_transport(struct srp_function_template *ft)
 EXPORT_SYMBOL_GPL(srp_attach_transport);
 
 /**
- * srp_release_transport  --  release SRP transport template instance
+ * srp_release_transport  -  release SRP transport template instance
  * @t:		transport template instance
  */
 void srp_release_transport(struct scsi_transport_template *t)
diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
index cd68a66c7bb3..3f21bc65e8c6 100644
--- a/drivers/scsi/scsicam.c
+++ b/drivers/scsi/scsicam.c
@@ -24,6 +24,14 @@
 static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
 		   unsigned int *secs);
 
+/**
+ * scsi_bios_ptable - Read PC partition table out of first sector of device.
+ * @dev: from this device
+ *
+ * Description: Reads the first sector from the device and returns %0x42 bytes
+ *              starting at offset %0x1be.
+ * Returns: partition table in kmalloc(GFP_KERNEL) memory, or NULL on error.
+ */
 unsigned char *scsi_bios_ptable(struct block_device *dev)
 {
 	unsigned char *res = kmalloc(66, GFP_KERNEL);
@@ -43,15 +51,17 @@ unsigned char *scsi_bios_ptable(struct block_device *dev)
 }
 EXPORT_SYMBOL(scsi_bios_ptable);
 
-/*
- * Function : int scsicam_bios_param (struct block_device *bdev, ector_t capacity, int *ip)
+/**
+ * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors.
+ * @bdev: which device
+ * @capacity: size of the disk in sectors
+ * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders
  *
- * Purpose : to determine the BIOS mapping used for a drive in a 
+ * Description : determine the BIOS mapping/geometry used for a drive in a
  *      SCSI-CAM system, storing the results in ip as required
  *      by the HDIO_GETGEO ioctl().
  *
  * Returns : -1 on failure, 0 on success.
- *
  */
 
 int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
@@ -98,15 +108,18 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
 }
 EXPORT_SYMBOL(scsicam_bios_param);
 
-/*
- * Function : static int scsi_partsize(unsigned char *buf, unsigned long 
- *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
+/**
+ * scsi_partsize - Parse cylinders/heads/sectors from PC partition table
+ * @buf: partition table, see scsi_bios_ptable()
+ * @capacity: size of the disk in sectors
+ * @cyls: put cylinders here
+ * @hds: put heads here
+ * @secs: put sectors here
  *
- * Purpose : to determine the BIOS mapping used to create the partition
+ * Description: determine the BIOS mapping/geometry used to create the partition
  *      table, storing the results in *cyls, *hds, and *secs 
  *
- * Returns : -1 on failure, 0 on success.
- *
+ * Returns: -1 on failure, 0 on success.
  */
 
 int scsi_partsize(unsigned char *buf, unsigned long capacity,
@@ -194,7 +207,7 @@ EXPORT_SYMBOL(scsi_partsize);
  *
  * WORKING                                                    X3T9.2
  * DRAFT                                                        792D
- *
+ * see http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf
  *
  *                                                        Revision 6
  *                                                         10-MAR-94
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index a69b155f39a2..51a5557f42dd 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -395,6 +395,15 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
 		goto out;
 	}
 
+	/*
+	 * Some devices (some sdcards for one) don't like it if the
+	 * last sector gets read in a larger then 1 sector read.
+	 */
+	if (unlikely(sdp->last_sector_bug &&
+	    rq->nr_sectors > sdp->sector_size / 512 &&
+	    block + this_count == get_capacity(disk)))
+		this_count -= sdp->sector_size / 512;
+
 	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
 					(unsigned long long)block));
 
@@ -510,7 +519,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
 		SCpnt->cmnd[4] = (unsigned char) this_count;
 		SCpnt->cmnd[5] = 0;
 	}
-	SCpnt->request_bufflen = this_count * sdp->sector_size;
+	SCpnt->sdb.length = this_count * sdp->sector_size;
 
 	/*
 	 * We shouldn't disconnect in the middle of a sector, so with a dumb
@@ -736,6 +745,7 @@ static int sd_media_changed(struct gendisk *disk)
 {
 	struct scsi_disk *sdkp = scsi_disk(disk);
 	struct scsi_device *sdp = sdkp->device;
+	struct scsi_sense_hdr *sshdr = NULL;
 	int retval;
 
 	SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));
@@ -749,8 +759,11 @@ static int sd_media_changed(struct gendisk *disk)
 	 * can deal with it then.  It is only because of unrecoverable errors
 	 * that we would ever take a device offline in the first place.
 	 */
-	if (!scsi_device_online(sdp))
-		goto not_present;
+	if (!scsi_device_online(sdp)) {
+		set_media_not_present(sdkp);
+		retval = 1;
+		goto out;
+	}
 
 	/*
 	 * Using TEST_UNIT_READY enables differentiation between drive with
@@ -762,8 +775,12 @@ static int sd_media_changed(struct gendisk *disk)
 	 * sd_revalidate() is called.
 	 */
 	retval = -ENODEV;
-	if (scsi_block_when_processing_errors(sdp))
-		retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES);
+
+	if (scsi_block_when_processing_errors(sdp)) {
+		sshdr  = kzalloc(sizeof(*sshdr), GFP_KERNEL);
+		retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES,
+					      sshdr);
+	}
 
 	/*
 	 * Unable to test, unit probably not ready.   This usually
@@ -771,8 +788,13 @@ static int sd_media_changed(struct gendisk *disk)
 	 * and we will figure it out later once the drive is
 	 * available again.
 	 */
-	if (retval)
-		 goto not_present;
+	if (retval || (scsi_sense_valid(sshdr) &&
+		       /* 0x3a is medium not present */
+		       sshdr->asc == 0x3a)) {
+		set_media_not_present(sdkp);
+		retval = 1;
+		goto out;
+	}
 
 	/*
 	 * For removable scsi disk we have to recognise the presence
@@ -783,12 +805,12 @@ static int sd_media_changed(struct gendisk *disk)
 
 	retval = sdp->changed;
 	sdp->changed = 0;
-
+out:
+	if (retval != sdkp->previous_state)
+		sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
+	sdkp->previous_state = retval;
+	kfree(sshdr);
 	return retval;
-
-not_present:
-	set_media_not_present(sdkp);
-	return 1;
 }
 
 static int sd_sync_cache(struct scsi_disk *sdkp)
@@ -904,7 +926,7 @@ static struct block_device_operations sd_fops = {
 static int sd_done(struct scsi_cmnd *SCpnt)
 {
 	int result = SCpnt->result;
- 	unsigned int xfer_size = SCpnt->request_bufflen;
+	unsigned int xfer_size = scsi_bufflen(SCpnt);
  	unsigned int good_bytes = result ? 0 : xfer_size;
  	u64 start_lba = SCpnt->request->sector;
  	u64 bad_lba;
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
deleted file mode 100644
index b11324479b5b..000000000000
--- a/drivers/scsi/seagate.c
+++ /dev/null
@@ -1,1667 +0,0 @@
-/*
- *    seagate.c Copyright (C) 1992, 1993 Drew Eckhardt
- *      low level scsi driver for ST01/ST02, Future Domain TMC-885,
- *      TMC-950 by Drew Eckhardt <drew@colorado.edu>
- *
- *      Note : TMC-880 boards don't work because they have two bits in
- *              the status register flipped, I'll fix this "RSN"
- *	[why do I have strong feeling that above message is from 1993? :-)
- *	        pavel@ucw.cz]
- *
- *      This card does all the I/O via memory mapped I/O, so there is no need
- *      to check or allocate a region of the I/O address space.
- */
-
-/* 1996 - to use new read{b,w,l}, write{b,w,l}, and phys_to_virt
- * macros, replaced assembler routines with C. There's probably a
- * performance hit, but I only have a cdrom and can't tell. Define
- * SEAGATE_USE_ASM if you want the old assembler code -- SJT
- *
- * 1998-jul-29 - created DPRINTK macros and made it work under 
- * linux 2.1.112, simplified some #defines etc. <pavel@ucw.cz>
- *
- * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to
- * read the physical disk geometry, a bad mistake. Of course it doesn't
- * matter much what geometry one invents, but on large disks it
- * returned 256 (or more) heads, causing all kind of failures.
- * Of course this means that people might see a different geometry now,
- * so boot parameters may be necessary in some cases.
- */
-
-/*
- * Configuration :
- * To use without BIOS -DOVERRIDE=base_address -DCONTROLLER=FD or SEAGATE
- * -DIRQ will override the default of 5.
- * Note: You can now set these options from the kernel's "command line".
- * The syntax is:
- *
- *     st0x=ADDRESS,IRQ                (for a Seagate controller)
- * or:
- *     tmc8xx=ADDRESS,IRQ              (for a TMC-8xx or TMC-950 controller)
- * eg:
- *     tmc8xx=0xC8000,15
- *
- * will configure the driver for a TMC-8xx style controller using IRQ 15
- * with a base address of 0xC8000.
- *
- * -DARBITRATE 
- *      Will cause the host adapter to arbitrate for the
- *      bus for better SCSI-II compatibility, rather than just
- *      waiting for BUS FREE and then doing its thing.  Should
- *      let us do one command per Lun when I integrate my
- *      reorganization changes into the distribution sources.
- *
- * -DDEBUG=65535
- *      Will activate debug code.
- *
- * -DFAST or -DFAST32 
- *      Will use blind transfers where possible
- *
- * -DPARITY  
- *      This will enable parity.
- *
- * -DSEAGATE_USE_ASM
- *      Will use older seagate assembly code. should be (very small amount)
- *      Faster.
- *
- * -DSLOW_RATE=50
- *      Will allow compatibility with broken devices that don't
- *      handshake fast enough (ie, some CD ROM's) for the Seagate
- *      code.
- *
- *      50 is some number, It will let you specify a default
- *      transfer rate if handshaking isn't working correctly.
- *
- * -DOLDCNTDATASCEME  There is a new sceme to set the CONTROL
- *                    and DATA reigsters which complies more closely
- *                    with the SCSI2 standard. This hopefully eliminates
- *                    the need to swap the order these registers are
- *                    'messed' with. It makes the following two options
- *                    obsolete. To reenable the old sceme define this.
- *
- * The following to options are patches from the SCSI.HOWTO
- *
- * -DSWAPSTAT  This will swap the definitions for STAT_MSG and STAT_CD.
- *
- * -DSWAPCNTDATA  This will swap the order that seagate.c messes with
- *                the CONTROL an DATA registers.
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/signal.h>
-#include <linux/string.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-#include <linux/stat.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi.h>
-
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_host.h>
-
-
-#ifdef DEBUG
-#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0)
-#else
-#define DPRINTK( when, msg... ) do { } while (0)
-#define DEBUG 0
-#endif
-#define DANY( msg... ) DPRINTK( 0xffff, msg );
-
-#ifndef IRQ
-#define IRQ 5
-#endif
-
-#ifdef FAST32
-#define FAST
-#endif
-
-#undef LINKED			/* Linked commands are currently broken! */
-
-#if defined(OVERRIDE) && !defined(CONTROLLER)
-#error Please use -DCONTROLLER=SEAGATE or -DCONTROLLER=FD to override controller type
-#endif
-
-#ifndef __i386__
-#undef SEAGATE_USE_ASM
-#endif
-
-/*
-	Thanks to Brian Antoine for the example code in his Messy-Loss ST-01
-		driver, and Mitsugu Suzuki for information on the ST-01
-		SCSI host.
-*/
-
-/*
-	CONTROL defines
-*/
-
-#define CMD_RST 		0x01
-#define CMD_SEL 		0x02
-#define CMD_BSY 		0x04
-#define CMD_ATTN    		0x08
-#define CMD_START_ARB		0x10
-#define CMD_EN_PARITY		0x20
-#define CMD_INTR		0x40
-#define CMD_DRVR_ENABLE		0x80
-
-/*
-	STATUS
-*/
-#ifdef SWAPSTAT
-#define STAT_MSG		0x08
-#define STAT_CD			0x02
-#else
-#define STAT_MSG		0x02
-#define STAT_CD			0x08
-#endif
-
-#define STAT_BSY		0x01
-#define STAT_IO			0x04
-#define STAT_REQ		0x10
-#define STAT_SEL		0x20
-#define STAT_PARITY		0x40
-#define STAT_ARB_CMPL		0x80
-
-/* 
-	REQUESTS
-*/
-
-#define REQ_MASK (STAT_CD |  STAT_IO | STAT_MSG)
-#define REQ_DATAOUT 0
-#define REQ_DATAIN STAT_IO
-#define REQ_CMDOUT STAT_CD
-#define REQ_STATIN (STAT_CD | STAT_IO)
-#define REQ_MSGOUT (STAT_MSG | STAT_CD)
-#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO)
-
-extern volatile int seagate_st0x_timeout;
-
-#ifdef PARITY
-#define BASE_CMD CMD_EN_PARITY
-#else
-#define BASE_CMD  0
-#endif
-
-/*
-	Debugging code
-*/
-
-#define PHASE_BUS_FREE 1
-#define PHASE_ARBITRATION 2
-#define PHASE_SELECTION 4
-#define PHASE_DATAIN 8
-#define PHASE_DATAOUT 0x10
-#define PHASE_CMDOUT 0x20
-#define PHASE_MSGIN 0x40
-#define PHASE_MSGOUT 0x80
-#define PHASE_STATUSIN 0x100
-#define PHASE_ETC (PHASE_DATAIN | PHASE_DATAOUT | PHASE_CMDOUT | PHASE_MSGIN | PHASE_MSGOUT | PHASE_STATUSIN)
-#define PRINT_COMMAND 0x200
-#define PHASE_EXIT 0x400
-#define PHASE_RESELECT 0x800
-#define DEBUG_FAST 0x1000
-#define DEBUG_SG   0x2000
-#define DEBUG_LINKED	0x4000
-#define DEBUG_BORKEN	0x8000
-
-/* 
- *	Control options - these are timeouts specified in .01 seconds.
- */
-
-/* 30, 20 work */
-#define ST0X_BUS_FREE_DELAY 25
-#define ST0X_SELECTION_DELAY 25
-
-#define SEAGATE 1		/* these determine the type of the controller */
-#define FD	2
-
-#define ST0X_ID_STR	"Seagate ST-01/ST-02"
-#define FD_ID_STR	"TMC-8XX/TMC-950"
-
-static int internal_command (unsigned char target, unsigned char lun,
-			     const void *cmnd,
-			     void *buff, int bufflen, int reselect);
-
-static int incommand;		/* set if arbitration has finished
-				   and we are in some command phase. */
-
-static unsigned int base_address = 0;	/* Where the card ROM starts, used to 
-					   calculate memory mapped register
-					   location.  */
-
-static void __iomem *st0x_cr_sr;	/* control register write, status
-					   register read.  256 bytes in
-					   length.
-					   Read is status of SCSI BUS, as per 
-					   STAT masks.  */
-
-static void __iomem *st0x_dr;	/* data register, read write 256
-				   bytes in length.  */
-
-static volatile int st0x_aborted = 0;	/* set when we are aborted, ie by a
-					   time out, etc.  */
-
-static unsigned char controller_type = 0;	/* set to SEAGATE for ST0x
-						   boards or FD for TMC-8xx
-						   boards */
-static int irq = IRQ;
-
-module_param(base_address, uint, 0);
-module_param(controller_type, byte, 0);
-module_param(irq, int, 0);
-MODULE_LICENSE("GPL");
-
-
-#define retcode(result) (((result) << 16) | (message << 8) | status)
-#define STATUS ((u8) readb(st0x_cr_sr))
-#define DATA ((u8) readb(st0x_dr))
-#define WRITE_CONTROL(d) { writeb((d), st0x_cr_sr); }
-#define WRITE_DATA(d) { writeb((d), st0x_dr); }
-
-#ifndef OVERRIDE
-static unsigned int seagate_bases[] = {
-	0xc8000, 0xca000, 0xcc000,
-	0xce000, 0xdc000, 0xde000
-};
-
-typedef struct {
-	const unsigned char *signature;
-	unsigned offset;
-	unsigned length;
-	unsigned char type;
-} Signature;
-
-static Signature __initdata signatures[] = {
-	{"ST01 v1.7  (C) Copyright 1987 Seagate", 15, 37, SEAGATE},
-	{"SCSI BIOS 2.00  (C) Copyright 1987 Seagate", 15, 40, SEAGATE},
-
-/*
- * The following two lines are NOT mistakes.  One detects ROM revision
- * 3.0.0, the other 3.2.  Since seagate has only one type of SCSI adapter,
- * and this is not going to change, the "SEAGATE" and "SCSI" together
- * are probably "good enough"
- */
-
-	{"SEAGATE SCSI BIOS ", 16, 17, SEAGATE},
-	{"SEAGATE SCSI BIOS ", 17, 17, SEAGATE},
-
-/*
- * However, future domain makes several incompatible SCSI boards, so specific
- * signatures must be used.
- */
-
-	{"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 46, FD},
-	{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD},
-	{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90", 5, 47, FD},
-	{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90", 5, 47, FD},
-	{"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD},
-	{"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD},
-	{"IBM F1 BIOS V1.1004/30/92", 5, 25, FD},
-	{"FUTURE DOMAIN TMC-950", 5, 21, FD},
-	/* Added for 2.2.16 by Matthias_Heidbrink@b.maus.de */
-	{"IBM F1 V1.2009/22/93", 5, 25, FD},
-};
-
-#define NUM_SIGNATURES ARRAY_SIZE(signatures)
-#endif				/* n OVERRIDE */
-
-/*
- * hostno stores the hostnumber, as told to us by the init routine.
- */
-
-static int hostno = -1;
-static void seagate_reconnect_intr (int, void *);
-static irqreturn_t do_seagate_reconnect_intr (int, void *);
-static int seagate_st0x_bus_reset(struct scsi_cmnd *);
-
-#ifdef FAST
-static int fast = 1;
-#else
-#define fast 0
-#endif
-
-#ifdef SLOW_RATE
-/*
- * Support for broken devices :
- * The Seagate board has a handshaking problem.  Namely, a lack
- * thereof for slow devices.  You can blast 600K/second through
- * it if you are polling for each byte, more if you do a blind
- * transfer.  In the first case, with a fast device, REQ will
- * transition high-low or high-low-high before your loop restarts
- * and you'll have no problems.  In the second case, the board
- * will insert wait states for up to 13.2 usecs for REQ to
- * transition low->high, and everything will work.
- *
- * However, there's nothing in the state machine that says
- * you *HAVE* to see a high-low-high set of transitions before
- * sending the next byte, and slow things like the Trantor CD ROMS
- * will break because of this.
- *
- * So, we need to slow things down, which isn't as simple as it
- * seems.  We can't slow things down period, because then people
- * who don't recompile their kernels will shoot me for ruining
- * their performance.  We need to do it on a case per case basis.
- *
- * The best for performance will be to, only for borken devices
- * (this is stored on a per-target basis in the scsi_devices array)
- *
- * Wait for a low->high transition before continuing with that
- * transfer.  If we timeout, continue anyways.  We don't need
- * a long timeout, because REQ should only be asserted until the
- * corresponding ACK is received and processed.
- *
- * Note that we can't use the system timer for this, because of
- * resolution, and we *really* can't use the timer chip since
- * gettimeofday() and the beeper routines use that.  So,
- * the best thing for us to do will be to calibrate a timing
- * loop in the initialization code using the timer chip before
- * gettimeofday() can screw with it.
- *
- * FIXME: this is broken (not borken :-). Empty loop costs less than
- * loop with ISA access in it! -- pavel@ucw.cz
- */
-
-static int borken_calibration = 0;
-
-static void __init borken_init (void)
-{
-	register int count = 0, start = jiffies + 1, stop = start + 25;
-
-	/* FIXME: There may be a better approach, this is a straight port for
-	   now */
-	preempt_disable();
-	while (time_before (jiffies, start))
-		cpu_relax();
-	for (; time_before (jiffies, stop); ++count)
-		cpu_relax();
-	preempt_enable();
-
-/*
- * Ok, we now have a count for .25 seconds.  Convert to a
- * count per second and divide by transfer rate in K.  */
-
-	borken_calibration = (count * 4) / (SLOW_RATE * 1024);
-
-	if (borken_calibration < 1)
-		borken_calibration = 1;
-}
-
-static inline void borken_wait (void)
-{
-	register int count;
-
-	for (count = borken_calibration; count && (STATUS & STAT_REQ); --count)
-		cpu_relax();
-	     	
-#if (DEBUG & DEBUG_BORKEN)
-	if (count)
-		printk ("scsi%d : borken timeout\n", hostno);
-#endif
-}
-
-#endif				/* def SLOW_RATE */
-
-/* These beasts only live on ISA, and ISA means 8MHz. Each ULOOP()
- * contains at least one ISA access, which takes more than 0.125
- * usec. So if we loop 8 times time in usec, we are safe.
- */
-
-#define ULOOP( i ) for (clock = i*8;;)
-#define TIMEOUT (!(clock--))
-
-static int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
-{
-	struct Scsi_Host *instance;
-	int i, j;
-	unsigned long cr, dr;
-
-	tpnt->proc_name = "seagate";
-/*
- *	First, we try for the manual override.
- */
-	DANY ("Autodetecting ST0x / TMC-8xx\n");
-
-	if (hostno != -1) {
-		printk (KERN_ERR "seagate_st0x_detect() called twice?!\n");
-		return 0;
-	}
-
-/* If the user specified the controller type from the command line,
-   controller_type will be non-zero, so don't try to detect one */
-
-	if (!controller_type) {
-#ifdef OVERRIDE
-		base_address = OVERRIDE;
-		controller_type = CONTROLLER;
-
-		DANY ("Base address overridden to %x, controller type is %s\n",
-		      base_address,
-		      controller_type == SEAGATE ? "SEAGATE" : "FD");
-#else				/* OVERRIDE */
-/*
- * 	To detect this card, we simply look for the signature
- *      from the BIOS version notice in all the possible locations
- *      of the ROM's.  This has a nice side effect of not trashing
- *      any register locations that might be used by something else.
- *
- * XXX - note that we probably should be probing the address
- * space for the on-board RAM instead.
- */
-
-		for (i = 0; i < ARRAY_SIZE(seagate_bases); ++i) {
-			void __iomem *p = ioremap(seagate_bases[i], 0x2000);
-			if (!p)
-				continue;
-			for (j = 0; j < NUM_SIGNATURES; ++j)
-				if (check_signature(p + signatures[j].offset, signatures[j].signature, signatures[j].length)) {
-					base_address = seagate_bases[i];
-					controller_type = signatures[j].type;
-					break;
-				}
-			iounmap(p);
-		}
-#endif				/* OVERRIDE */
-	}
-	/* (! controller_type) */
-	tpnt->this_id = (controller_type == SEAGATE) ? 7 : 6;
-	tpnt->name = (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR;
-
-	if (!base_address) {
-		printk(KERN_INFO "seagate: ST0x/TMC-8xx not detected.\n");
-		return 0;
-	}
-
-	cr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00);
-	dr = cr + 0x200;
-	st0x_cr_sr = ioremap(cr, 0x100);
-	st0x_dr = ioremap(dr, 0x100);
-
-	DANY("%s detected. Base address = %x, cr = %x, dr = %x\n",
-	      tpnt->name, base_address, cr, dr);
-
-	/*
-	 *	At all times, we will use IRQ 5.  Should also check for IRQ3
-	 *	if we lose our first interrupt.
-	 */
-	instance = scsi_register (tpnt, 0);
-	if (instance == NULL)
-		return 0;
-
-	hostno = instance->host_no;
-	if (request_irq (irq, do_seagate_reconnect_intr, IRQF_DISABLED, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) {
-		printk(KERN_ERR "scsi%d : unable to allocate IRQ%d\n", hostno, irq);
-		return 0;
-	}
-	instance->irq = irq;
-	instance->io_port = base_address;
-#ifdef SLOW_RATE
-	printk(KERN_INFO "Calibrating borken timer... ");
-	borken_init();
-	printk(" %d cycles per transfer\n", borken_calibration);
-#endif
-	printk (KERN_INFO "This is one second... ");
-	{
-		int clock;
-		ULOOP (1 * 1000 * 1000) {
-			STATUS;
-			if (TIMEOUT)
-				break;
-		}
-	}
-
-	printk ("done, %s options:"
-#ifdef ARBITRATE
-		" ARBITRATE"
-#endif
-#if DEBUG
-		" DEBUG"
-#endif
-#ifdef FAST
-		" FAST"
-#ifdef FAST32
-		"32"
-#endif
-#endif
-#ifdef LINKED
-		" LINKED"
-#endif
-#ifdef PARITY
-		" PARITY"
-#endif
-#ifdef SEAGATE_USE_ASM
-		" SEAGATE_USE_ASM"
-#endif
-#ifdef SLOW_RATE
-		" SLOW_RATE"
-#endif
-#ifdef SWAPSTAT
-		" SWAPSTAT"
-#endif
-#ifdef SWAPCNTDATA
-		" SWAPCNTDATA"
-#endif
-		"\n", tpnt->name);
-	return 1;
-}
-
-static const char *seagate_st0x_info (struct Scsi_Host *shpnt)
-{
-	static char buffer[64];
-
-	snprintf(buffer, 64, "%s at irq %d, address 0x%05X",
-		 (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR,
-		 irq, base_address);
-	return buffer;
-}
-
-/*
- * These are our saved pointers for the outstanding command that is
- * waiting for a reconnect
- */
-
-static unsigned char current_target, current_lun;
-static unsigned char *current_cmnd, *current_data;
-static int current_nobuffs;
-static struct scatterlist *current_buffer;
-static int current_bufflen;
-
-#ifdef LINKED
-/*
- * linked_connected indicates whether or not we are currently connected to
- * linked_target, linked_lun and in an INFORMATION TRANSFER phase,
- * using linked commands.
- */
-
-static int linked_connected = 0;
-static unsigned char linked_target, linked_lun;
-#endif
-
-static void (*done_fn) (struct scsi_cmnd *) = NULL;
-static struct scsi_cmnd *SCint = NULL;
-
-/*
- * These control whether or not disconnect / reconnect will be attempted,
- * or are being attempted.
- */
-
-#define NO_RECONNECT    0
-#define RECONNECT_NOW   1
-#define CAN_RECONNECT   2
-
-/*
- * LINKED_RIGHT indicates that we are currently connected to the correct target
- * for this command, LINKED_WRONG indicates that we are connected to the wrong
- * target. Note that these imply CAN_RECONNECT and require defined(LINKED).
- */
-
-#define LINKED_RIGHT    3
-#define LINKED_WRONG    4
-
-/*
- * This determines if we are expecting to reconnect or not.
- */
-
-static int should_reconnect = 0;
-
-/*
- * The seagate_reconnect_intr routine is called when a target reselects the
- * host adapter.  This occurs on the interrupt triggered by the target
- * asserting SEL.
- */
-
-static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id)
-{
-	unsigned long flags;
-	struct Scsi_Host *dev = dev_id;
-	
-	spin_lock_irqsave (dev->host_lock, flags);
-	seagate_reconnect_intr (irq, dev_id);
-	spin_unlock_irqrestore (dev->host_lock, flags);
-	return IRQ_HANDLED;
-}
-
-static void seagate_reconnect_intr (int irq, void *dev_id)
-{
-	int temp;
-	struct scsi_cmnd *SCtmp;
-
-	DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);
-
-	if (!should_reconnect)
-		printk(KERN_WARNING "scsi%d: unexpected interrupt.\n", hostno);
-	else {
-		should_reconnect = 0;
-
-		DPRINTK (PHASE_RESELECT, "scsi%d : internal_command(%d, %08x, %08x, RECONNECT_NOW\n", 
-			hostno, current_target, current_data, current_bufflen);
-
-		temp = internal_command (current_target, current_lun, current_cmnd, current_data, current_bufflen, RECONNECT_NOW);
-
-		if (msg_byte(temp) != DISCONNECT) {
-			if (done_fn) {
-				DPRINTK(PHASE_RESELECT, "scsi%d : done_fn(%d,%08x)", hostno, hostno, temp);
-				if (!SCint)
-					panic ("SCint == NULL in seagate");
-				SCtmp = SCint;
-				SCint = NULL;
-				SCtmp->result = temp;
-				done_fn(SCtmp);
-			} else
-				printk(KERN_ERR "done_fn() not defined.\n");
-		}
-	}
-}
-
-/*
- * The seagate_st0x_queue_command() function provides a queued interface
- * to the seagate SCSI driver.  Basically, it just passes control onto the
- * seagate_command() function, after fixing it so that the done_fn()
- * is set to the one passed to the function.  We have to be very careful,
- * because there are some commands on some devices that do not disconnect,
- * and if we simply call the done_fn when the command is done then another
- * command is started and queue_command is called again...  We end up
- * overflowing the kernel stack, and this tends not to be such a good idea.
- */
-
-static int recursion_depth = 0;
-
-static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt,
-				      void (*done) (struct scsi_cmnd *))
-{
-	int result, reconnect;
-	struct scsi_cmnd *SCtmp;
-
-	DANY ("seagate: que_command");
-	done_fn = done;
-	current_target = SCpnt->device->id;
-	current_lun = SCpnt->device->lun;
-	current_cmnd = SCpnt->cmnd;
-	current_data = (unsigned char *) SCpnt->request_buffer;
-	current_bufflen = SCpnt->request_bufflen;
-	SCint = SCpnt;
-	if (recursion_depth)
-		return 1;
-	recursion_depth++;
-	do {
-#ifdef LINKED
-		/*
-		 * Set linked command bit in control field of SCSI command.
-		 */
-
-		current_cmnd[SCpnt->cmd_len] |= 0x01;
-		if (linked_connected) {
-			DPRINTK (DEBUG_LINKED, "scsi%d : using linked commands, current I_T_L nexus is ", hostno);
-			if (linked_target == current_target && linked_lun == current_lun) 
-			{
-				DPRINTK(DEBUG_LINKED, "correct\n");
-				reconnect = LINKED_RIGHT;
-			} else {
-				DPRINTK(DEBUG_LINKED, "incorrect\n");
-				reconnect = LINKED_WRONG;
-			}
-		} else
-#endif				/* LINKED */
-			reconnect = CAN_RECONNECT;
-
-		result = internal_command(SCint->device->id, SCint->device->lun, SCint->cmnd,
-				      SCint->request_buffer, SCint->request_bufflen, reconnect);
-		if (msg_byte(result) == DISCONNECT)
-			break;
-		SCtmp = SCint;
-		SCint = NULL;
-		SCtmp->result = result;
-		done_fn(SCtmp);
-	}
-	while (SCint);
-	recursion_depth--;
-	return 0;
-}
-
-static int internal_command (unsigned char target, unsigned char lun,
-		  const void *cmnd, void *buff, int bufflen, int reselect)
-{
-	unsigned char *data = NULL;
-	struct scatterlist *buffer = NULL;
-	int clock, temp, nobuffs = 0, done = 0, len = 0;
-#if DEBUG
-	int transfered = 0, phase = 0, newphase;
-#endif
-	register unsigned char status_read;
-	unsigned char tmp_data, tmp_control, status = 0, message = 0;
-	unsigned transfersize = 0, underflow = 0;
-#ifdef SLOW_RATE
-	int borken = (int) SCint->device->borken;	/* Does the current target require
-							   Very Slow I/O ?  */
-#endif
-
-	incommand = 0;
-	st0x_aborted = 0;
-
-#if (DEBUG & PRINT_COMMAND)
-	printk("scsi%d : target = %d, command = ", hostno, target);
-	__scsi_print_command((unsigned char *) cmnd);
-#endif
-
-#if (DEBUG & PHASE_RESELECT)
-	switch (reselect) {
-	case RECONNECT_NOW:
-		printk("scsi%d : reconnecting\n", hostno);
-		break;
-#ifdef LINKED
-	case LINKED_RIGHT:
-		printk("scsi%d : connected, can reconnect\n", hostno);
-		break;
-	case LINKED_WRONG:
-		printk("scsi%d : connected to wrong target, can reconnect\n",
-			hostno);
-		break;
-#endif
-	case CAN_RECONNECT:
-		printk("scsi%d : allowed to reconnect\n", hostno);
-		break;
-	default:
-		printk("scsi%d : not allowed to reconnect\n", hostno);
-	}
-#endif
-
-	if (target == (controller_type == SEAGATE ? 7 : 6))
-		return DID_BAD_TARGET;
-
-	/*
-	 *	We work it differently depending on if this is is "the first time,"
-	 *      or a reconnect.  If this is a reselect phase, then SEL will
-	 *      be asserted, and we must skip selection / arbitration phases.
-	 */
-
-	switch (reselect) {
-	case RECONNECT_NOW:
-		DPRINTK (PHASE_RESELECT, "scsi%d : phase RESELECT \n", hostno);
-		/*
-		 *	At this point, we should find the logical or of our ID
-		 *	and the original target's ID on the BUS, with BSY, SEL,
-		 *	and I/O signals asserted.
-		 *
-		 *      After ARBITRATION phase is completed, only SEL, BSY,
-		 *	and the target ID are asserted.  A valid initiator ID
-		 *	is not on the bus until IO is asserted, so we must wait
-		 *	for that.
-		 */
-		ULOOP (100 * 1000) {
-			temp = STATUS;
-			if ((temp & STAT_IO) && !(temp & STAT_BSY))
-				break;
-			if (TIMEOUT) {
-				DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for IO .\n", hostno);
-				return (DID_BAD_INTR << 16);
-			}
-		}
-
-		/*
-		 *	After I/O is asserted by the target, we can read our ID
-		 *	and its ID off of the BUS.
-		 */
-
-		if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) {
-			DPRINTK (PHASE_RESELECT, "scsi%d : detected reconnect request to different target.\n\tData bus = %d\n", hostno, temp);
-			return (DID_BAD_INTR << 16);
-		}
-
-		if (!(temp & (1 << current_target))) {
-			printk(KERN_WARNING "scsi%d : Unexpected reselect interrupt.  Data bus = %d\n", hostno, temp);
-			return (DID_BAD_INTR << 16);
-		}
-
-		buffer = current_buffer;
-		cmnd = current_cmnd;	/* WDE add */
-		data = current_data;	/* WDE add */
-		len = current_bufflen;	/* WDE add */
-		nobuffs = current_nobuffs;
-
-		/*
-		 *	We have determined that we have been selected.  At this
-		 *	point, we must respond to the reselection by asserting
-		 *	BSY ourselves
-		 */
-
-#if 1
-		WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);
-#else
-		WRITE_CONTROL (BASE_CMD | CMD_BSY);
-#endif
-
-		/*
-		 *	The target will drop SEL, and raise BSY, at which time
-		 *	we must drop BSY.
-		 */
-
-		ULOOP (100 * 1000) {
-			if (!(STATUS & STAT_SEL))
-				break;
-			if (TIMEOUT) {
-				WRITE_CONTROL (BASE_CMD | CMD_INTR);
-				DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for SEL.\n", hostno);
-				return (DID_BAD_INTR << 16);
-			}
-		}
-		WRITE_CONTROL (BASE_CMD);
-		/*
-		 *	At this point, we have connected with the target
-		 *	and can get on with our lives.
-		 */
-		break;
-	case CAN_RECONNECT:
-#ifdef LINKED
-		/*
-		 * This is a bletcherous hack, just as bad as the Unix #!
-		 * interpreter stuff. If it turns out we are using the wrong
-		 * I_T_L nexus, the easiest way to deal with it is to go into
-		 *  our INFORMATION TRANSFER PHASE code, send a ABORT
-		 * message on MESSAGE OUT phase, and then loop back to here.
-		 */
-connect_loop:
-#endif
-		DPRINTK (PHASE_BUS_FREE, "scsi%d : phase = BUS FREE \n", hostno);
-
-		/*
-		 *    BUS FREE PHASE
-		 *
-		 *      On entry, we make sure that the BUS is in a BUS FREE
-		 *      phase, by insuring that both BSY and SEL are low for
-		 *      at least one bus settle delay.  Several reads help
-		 *      eliminate wire glitch.
-		 */
-
-#ifndef ARBITRATE
-#error FIXME: this is broken: we may not use jiffies here - we are under cli(). It will hardlock.
-		clock = jiffies + ST0X_BUS_FREE_DELAY;
-
-		while (((STATUS | STATUS | STATUS) & (STAT_BSY | STAT_SEL)) && (!st0x_aborted) && time_before (jiffies, clock))
-			cpu_relax();
-
-		if (time_after (jiffies, clock))
-			return retcode (DID_BUS_BUSY);
-		else if (st0x_aborted)
-			return retcode (st0x_aborted);
-#endif
-		DPRINTK (PHASE_SELECTION, "scsi%d : phase = SELECTION\n", hostno);
-
-		clock = jiffies + ST0X_SELECTION_DELAY;
-
-		/*
-		 * Arbitration/selection procedure :
-		 * 1.  Disable drivers
-		 * 2.  Write HOST adapter address bit
-		 * 3.  Set start arbitration.
-		 * 4.  We get either ARBITRATION COMPLETE or SELECT at this
-		 *     point.
-		 * 5.  OR our ID and targets on bus.
-		 * 6.  Enable SCSI drivers and asserted SEL and ATTN
-		 */
-
-#ifdef ARBITRATE
-		/* FIXME: verify host lock is always held here */
-		WRITE_CONTROL(0);
-		WRITE_DATA((controller_type == SEAGATE) ? 0x80 : 0x40);
-		WRITE_CONTROL(CMD_START_ARB);
-
-		ULOOP (ST0X_SELECTION_DELAY * 10000) {
-			status_read = STATUS;
-			if (status_read & STAT_ARB_CMPL)
-				break;
-			if (st0x_aborted)	/* FIXME: What? We are going to do something even after abort? */
-				break;
-			if (TIMEOUT || (status_read & STAT_SEL)) {
-				printk(KERN_WARNING "scsi%d : arbitration lost or timeout.\n", hostno);
-				WRITE_CONTROL (BASE_CMD);
-				return retcode (DID_NO_CONNECT);
-			}
-		}
-		DPRINTK (PHASE_SELECTION, "scsi%d : arbitration complete\n", hostno);
-#endif
-
-		/*
-		 *    When the SCSI device decides that we're gawking at it, 
-		 *    it will respond by asserting BUSY on the bus.
-		 *
-		 *    Note : the Seagate ST-01/02 product manual says that we
-		 *    should twiddle the DATA register before the control
-		 *    register. However, this does not work reliably so we do
-		 *    it the other way around.
-		 *
-		 *    Probably could be a problem with arbitration too, we
-		 *    really should try this with a SCSI protocol or logic 
-		 *    analyzer to see what is going on.
-		 */
-		tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40));
-		tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0);
-
-		/* FIXME: verify host lock is always held here */
-#ifdef OLDCNTDATASCEME
-#ifdef SWAPCNTDATA
-		WRITE_CONTROL (tmp_control);
-		WRITE_DATA (tmp_data);
-#else
-		WRITE_DATA (tmp_data);
-		WRITE_CONTROL (tmp_control);
-#endif
-#else
-		tmp_control ^= CMD_BSY;	/* This is guesswork. What used to be in driver    */
-		WRITE_CONTROL (tmp_control);	/* could never work: it sent data into control     */
-		WRITE_DATA (tmp_data);	/* register and control info into data. Hopefully  */
-		tmp_control ^= CMD_BSY;	/* fixed, but order of first two may be wrong.     */
-		WRITE_CONTROL (tmp_control);	/* -- pavel@ucw.cz   */
-#endif
-
-		ULOOP (250 * 1000) {
-			if (st0x_aborted) {
-				/*
-				 *	If we have been aborted, and we have a
-				 *	command in progress, IE the target 
-				 *	still has BSY asserted, then we will
-				 *	reset the bus, and notify the midlevel
-				 *	driver to expect sense.
-				 */
-
-				WRITE_CONTROL (BASE_CMD);
-				if (STATUS & STAT_BSY) {
-					printk(KERN_WARNING "scsi%d : BST asserted after we've been aborted.\n", hostno);
-					seagate_st0x_bus_reset(NULL);
-					return retcode (DID_RESET);
-				}
-				return retcode (st0x_aborted);
-			}
-			if (STATUS & STAT_BSY)
-				break;
-			if (TIMEOUT) {
-				DPRINTK (PHASE_SELECTION, "scsi%d : NO CONNECT with target %d, stat = %x \n", hostno, target, STATUS);
-				return retcode (DID_NO_CONNECT);
-			}
-		}
-
-		/* Establish current pointers.  Take into account scatter / gather */
-
-		if ((nobuffs = SCint->use_sg)) {
-#if (DEBUG & DEBUG_SG)
-			{
-				int i;
-				printk("scsi%d : scatter gather requested, using %d buffers.\n", hostno, nobuffs);
-				for (i = 0; i < nobuffs; ++i)
-					printk("scsi%d : buffer %d address = %p length = %d\n",
-					     hostno, i,
-					     sg_virt(&buffer[i]),
-					     buffer[i].length);
-			}
-#endif
-
-			buffer = (struct scatterlist *) SCint->request_buffer;
-			len = buffer->length;
-			data = sg_virt(buffer);
-		} else {
-			DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno);
-			buffer = NULL;
-			len = SCint->request_bufflen;
-			data = (unsigned char *) SCint->request_buffer;
-		}
-
-		DPRINTK (PHASE_DATAIN | PHASE_DATAOUT, "scsi%d : len = %d\n",
-			 hostno, len);
-
-		break;
-#ifdef LINKED
-	case LINKED_RIGHT:
-		break;
-	case LINKED_WRONG:
-		break;
-#endif
-	}			/* end of switch(reselect) */
-
-	/*
-	 *    There are several conditions under which we wish to send a message :
-	 *      1.  When we are allowing disconnect / reconnect, and need to
-	 *	establish the I_T_L nexus via an IDENTIFY with the DiscPriv bit
-	 *	set.
-	 *
-	 *      2.  When we are doing linked commands, are have the wrong I_T_L
-	 *	nexus established and want to send an ABORT message.
-	 */
-
-	/* GCC does not like an ifdef inside a macro, so do it the hard way. */
-#ifdef LINKED
-	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT)|| (reselect == LINKED_WRONG))? CMD_ATTN : 0));
-#else
-	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT))? CMD_ATTN : 0));
-#endif
-
-	/*
-	 *    INFORMATION TRANSFER PHASE
-	 *
-	 *      The nasty looking read / write inline assembler loops we use for
-	 *      DATAIN and DATAOUT phases are approximately 4-5 times as fast as
-	 *      the 'C' versions - since we're moving 1024 bytes of data, this
-	 *      really adds up.
-	 *
-	 *      SJT: The nasty-looking assembler is gone, so it's slower.
-	 *
-	 */
-
-	DPRINTK (PHASE_ETC, "scsi%d : phase = INFORMATION TRANSFER\n", hostno);
-
-	incommand = 1;
-	transfersize = SCint->transfersize;
-	underflow = SCint->underflow;
-
-	/*
-	 *	Now, we poll the device for status information,
-	 *      and handle any requests it makes.  Note that since we are unsure
-	 *	of how much data will be flowing across the system, etc and
-	 *	cannot make reasonable timeouts, that we will instead have the
-	 *	midlevel driver handle any timeouts that occur in this phase.
-	 */
-
-	while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) {
-#ifdef PARITY
-		if (status_read & STAT_PARITY) {
-			printk(KERN_ERR "scsi%d : got parity error\n", hostno);
-			st0x_aborted = DID_PARITY;
-		}
-#endif
-		if (status_read & STAT_REQ) {
-#if ((DEBUG & PHASE_ETC) == PHASE_ETC)
-			if ((newphase = (status_read & REQ_MASK)) != phase) {
-				phase = newphase;
-				switch (phase) {
-				case REQ_DATAOUT:
-					printk ("scsi%d : phase = DATA OUT\n", hostno);
-					break;
-				case REQ_DATAIN:
-					printk ("scsi%d : phase = DATA IN\n", hostno);
-					break;
-				case REQ_CMDOUT:
-					printk
-					    ("scsi%d : phase = COMMAND OUT\n", hostno);
-					break;
-				case REQ_STATIN:
-					printk ("scsi%d : phase = STATUS IN\n",	hostno);
-					break;
-				case REQ_MSGOUT:
-					printk
-					    ("scsi%d : phase = MESSAGE OUT\n", hostno);
-					break;
-				case REQ_MSGIN:
-					printk ("scsi%d : phase = MESSAGE IN\n", hostno);
-					break;
-				default:
-					printk ("scsi%d : phase = UNKNOWN\n", hostno);
-					st0x_aborted = DID_ERROR;
-				}
-			}
-#endif
-			switch (status_read & REQ_MASK) {
-			case REQ_DATAOUT:
-				/*
-				 * If we are in fast mode, then we simply splat
-				 * the data out in word-sized chunks as fast as
-				 * we can.
-				 */
-
-				if (!len) {
-#if 0
-					printk("scsi%d: underflow to target %d lun %d \n", hostno, target, lun);
-					st0x_aborted = DID_ERROR;
-					fast = 0;
-#endif
-					break;
-				}
-
-				if (fast && transfersize
-				    && !(len % transfersize)
-				    && (len >= transfersize)
-#ifdef FAST32
-				    && !(transfersize % 4)
-#endif
-				    ) {
-					DPRINTK (DEBUG_FAST,
-						 "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
-						 "         len = %d, data = %08x\n",
-						 hostno, SCint->underflow,
-						 SCint->transfersize, len,
-						 data);
-
-			/* SJT: Start. Fast Write */
-#ifdef SEAGATE_USE_ASM
-					__asm__ ("cld\n\t"
-#ifdef FAST32
-						 "shr $2, %%ecx\n\t"
-						 "1:\t"
-						 "lodsl\n\t"
-						 "movl %%eax, (%%edi)\n\t"
-#else
-						 "1:\t"
-						 "lodsb\n\t"
-						 "movb %%al, (%%edi)\n\t"
-#endif
-						 "loop 1b;"
-				      /* output */ :
-				      /* input */ :"D" (st0x_dr),
-						 "S"
-						 (data),
-						 "c" (SCint->transfersize)
-/* clobbered */
-				      :	 "eax", "ecx",
-						 "esi");
-#else				/* SEAGATE_USE_ASM */
-					memcpy_toio(st0x_dr, data, transfersize);
-#endif				/* SEAGATE_USE_ASM */
-/* SJT: End */
-					len -= transfersize;
-					data += transfersize;
-					DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
-				} else {
-					/*
-					 *    We loop as long as we are in a 
-					 *    data out phase, there is data to
-					 *    send, and BSY is still active.
-					 */
-
-/* SJT: Start. Slow Write. */
-#ifdef SEAGATE_USE_ASM
-
-					int __dummy_1, __dummy_2;
-
-/*
- *      We loop as long as we are in a data out phase, there is data to send, 
- *      and BSY is still active.
- */
-/* Local variables : len = ecx , data = esi, 
-                     st0x_cr_sr = ebx, st0x_dr =  edi
-*/
-					__asm__ (
-							/* Test for any data here at all. */
-							"orl %%ecx, %%ecx\n\t"
-							"jz 2f\n\t" "cld\n\t"
-/*                    "movl st0x_cr_sr, %%ebx\n\t"  */
-/*                    "movl st0x_dr, %%edi\n\t"  */
-							"1:\t"
-							"movb (%%ebx), %%al\n\t"
-							/* Test for BSY */
-							"test $1, %%al\n\t"
-							"jz 2f\n\t"
-							/* Test for data out phase - STATUS & REQ_MASK should be 
-							   REQ_DATAOUT, which is 0. */
-							"test $0xe, %%al\n\t"
-							"jnz 2f\n\t"
-							/* Test for REQ */
-							"test $0x10, %%al\n\t"
-							"jz 1b\n\t"
-							"lodsb\n\t"
-							"movb %%al, (%%edi)\n\t"
-							"loop 1b\n\t" "2:\n"
-				      /* output */ :"=S" (data), "=c" (len),
-							"=b"
-							(__dummy_1),
-							"=D" (__dummy_2)
-/* input */
-				      :		"0" (data), "1" (len),
-							"2" (st0x_cr_sr),
-							"3" (st0x_dr)
-/* clobbered */
-				      :		"eax");
-#else				/* SEAGATE_USE_ASM */
-					while (len) {
-						unsigned char stat;
-
-						stat = STATUS;
-						if (!(stat & STAT_BSY)
-						    || ((stat & REQ_MASK) !=
-							REQ_DATAOUT))
-							break;
-						if (stat & STAT_REQ) {
-							WRITE_DATA (*data++);
-							--len;
-						}
-					}
-#endif				/* SEAGATE_USE_ASM */
-/* SJT: End. */
-				}
-
-				if (!len && nobuffs) {
-					--nobuffs;
-					++buffer;
-					len = buffer->length;
-					data = sg_virt(buffer);
-					DPRINTK (DEBUG_SG,
-						 "scsi%d : next scatter-gather buffer len = %d address = %08x\n",
-						 hostno, len, data);
-				}
-				break;
-
-			case REQ_DATAIN:
-#ifdef SLOW_RATE
-				if (borken) {
-#if (DEBUG & (PHASE_DATAIN))
-					transfered += len;
-#endif
-					for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ); --len) {
-						*data++ = DATA;
-						borken_wait();
-					}
-#if (DEBUG & (PHASE_DATAIN))
-					transfered -= len;
-#endif
-				} else
-#endif
-
-					if (fast && transfersize
-					    && !(len % transfersize)
-					    && (len >= transfersize)
-#ifdef FAST32
-					    && !(transfersize % 4)
-#endif
-				    ) {
-					DPRINTK (DEBUG_FAST,
-						 "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
-						 "         len = %d, data = %08x\n",
-						 hostno, SCint->underflow,
-						 SCint->transfersize, len,
-						 data);
-
-/* SJT: Start. Fast Read */
-#ifdef SEAGATE_USE_ASM
-					__asm__ ("cld\n\t"
-#ifdef FAST32
-						 "shr $2, %%ecx\n\t"
-						 "1:\t"
-						 "movl (%%esi), %%eax\n\t"
-						 "stosl\n\t"
-#else
-						 "1:\t"
-						 "movb (%%esi), %%al\n\t"
-						 "stosb\n\t"
-#endif
-						 "loop 1b\n\t"
-				      /* output */ :
-				      /* input */ :"S" (st0x_dr),
-						 "D"
-						 (data),
-						 "c" (SCint->transfersize)
-/* clobbered */
-				      :	 "eax", "ecx",
-						 "edi");
-#else				/* SEAGATE_USE_ASM */
-					memcpy_fromio(data, st0x_dr, len);
-#endif				/* SEAGATE_USE_ASM */
-/* SJT: End */
-					len -= transfersize;
-					data += transfersize;
-#if (DEBUG & PHASE_DATAIN)
-					printk ("scsi%d: transfered += %d\n", hostno, transfersize);
-					transfered += transfersize;
-#endif
-
-					DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
-				} else {
-
-#if (DEBUG & PHASE_DATAIN)
-					printk ("scsi%d: transfered += %d\n", hostno, len);
-					transfered += len;	/* Assume we'll transfer it all, then
-								   subtract what we *didn't* transfer */
-#endif
-
-/*
- *	We loop as long as we are in a data in phase, there is room to read,
- *      and BSY is still active
- */
-
-/* SJT: Start. */
-#ifdef SEAGATE_USE_ASM
-
-					int __dummy_3, __dummy_4;
-
-/* Dummy clobbering variables for the new gcc-2.95 */
-
-/*
- *      We loop as long as we are in a data in phase, there is room to read, 
- *      and BSY is still active
- */
-					/* Local variables : ecx = len, edi = data
-					   esi = st0x_cr_sr, ebx = st0x_dr */
-					__asm__ (
-							/* Test for room to read */
-							"orl %%ecx, %%ecx\n\t"
-							"jz 2f\n\t" "cld\n\t"
-/*                "movl st0x_cr_sr, %%esi\n\t"  */
-/*                "movl st0x_dr, %%ebx\n\t"  */
-							"1:\t"
-							"movb (%%esi), %%al\n\t"
-							/* Test for BSY */
-							"test $1, %%al\n\t"
-							"jz 2f\n\t"
-							/* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, 
-							   = STAT_IO, which is 4. */
-							"movb $0xe, %%ah\n\t"
-							"andb %%al, %%ah\n\t"
-							"cmpb $0x04, %%ah\n\t"
-							"jne 2f\n\t"
-							/* Test for REQ */
-							"test $0x10, %%al\n\t"
-							"jz 1b\n\t"
-							"movb (%%ebx), %%al\n\t"
-							"stosb\n\t"
-							"loop 1b\n\t" "2:\n"
-				      /* output */ :"=D" (data), "=c" (len),
-							"=S"
-							(__dummy_3),
-							"=b" (__dummy_4)
-/* input */
-				      :		"0" (data), "1" (len),
-							"2" (st0x_cr_sr),
-							"3" (st0x_dr)
-/* clobbered */
-				      :		"eax");
-#else				/* SEAGATE_USE_ASM */
-					while (len) {
-						unsigned char stat;
-
-						stat = STATUS;
-						if (!(stat & STAT_BSY)
-						    || ((stat & REQ_MASK) !=
-							REQ_DATAIN))
-							break;
-						if (stat & STAT_REQ) {
-							*data++ = DATA;
-							--len;
-						}
-					}
-#endif				/* SEAGATE_USE_ASM */
-/* SJT: End. */
-#if (DEBUG & PHASE_DATAIN)
-					printk ("scsi%d: transfered -= %d\n", hostno, len);
-					transfered -= len;	/* Since we assumed all of Len got  *
-								   transfered, correct our mistake */
-#endif
-				}
-
-				if (!len && nobuffs) {
-					--nobuffs;
-					++buffer;
-					len = buffer->length;
-					data = sg_virt(buffer);
-					DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data);
-				}
-				break;
-
-			case REQ_CMDOUT:
-				while (((status_read = STATUS) & STAT_BSY) &&
-				       ((status_read & REQ_MASK) == REQ_CMDOUT))
-					if (status_read & STAT_REQ) {
-						WRITE_DATA (*(const unsigned char *) cmnd);
-						cmnd = 1 + (const unsigned char *)cmnd;
-#ifdef SLOW_RATE
-						if (borken)
-							borken_wait ();
-#endif
-					}
-				break;
-
-			case REQ_STATIN:
-				status = DATA;
-				break;
-
-			case REQ_MSGOUT:
-				/*
-				 *	We can only have sent a MSG OUT if we
-				 *	requested to do this by raising ATTN.
-				 *	So, we must drop ATTN.
-				 */
-				WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE);
-				/*
-				 *	If we are reconnecting, then we must 
-				 *	send an IDENTIFY message in response
-				 *	to MSGOUT.
-				 */
-				switch (reselect) {
-				case CAN_RECONNECT:
-					WRITE_DATA (IDENTIFY (1, lun));
-					DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno);
-					break;
-#ifdef LINKED
-				case LINKED_WRONG:
-					WRITE_DATA (ABORT);
-					linked_connected = 0;
-					reselect = CAN_RECONNECT;
-					goto connect_loop;
-					DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno);
-#endif					/* LINKED */
-					DPRINTK (DEBUG_LINKED, "correct\n");
-				default:
-					WRITE_DATA (NOP);
-					printk("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target);
-				}
-				break;
-
-			case REQ_MSGIN:
-				switch (message = DATA) {
-				case DISCONNECT:
-					DANY("seagate: deciding to disconnect\n");
-					should_reconnect = 1;
-					current_data = data;	/* WDE add */
-					current_buffer = buffer;
-					current_bufflen = len;	/* WDE add */
-					current_nobuffs = nobuffs;
-#ifdef LINKED
-					linked_connected = 0;
-#endif
-					done = 1;
-					DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno);
-					break;
-
-#ifdef LINKED
-				case LINKED_CMD_COMPLETE:
-				case LINKED_FLG_CMD_COMPLETE:
-#endif
-				case COMMAND_COMPLETE:
-					/*
-					 * Note : we should check for underflow here.
-					 */
-					DPRINTK(PHASE_MSGIN, "scsi%d : command complete.\n", hostno);
-					done = 1;
-					break;
-				case ABORT:
-					DPRINTK(PHASE_MSGIN, "scsi%d : abort message.\n", hostno);
-					done = 1;
-					break;
-				case SAVE_POINTERS:
-					current_buffer = buffer;
-					current_bufflen = len;	/* WDE add */
-					current_data = data;	/* WDE mod */
-					current_nobuffs = nobuffs;
-					DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno);
-					break;
-				case RESTORE_POINTERS:
-					buffer = current_buffer;
-					cmnd = current_cmnd;
-					data = current_data;	/* WDE mod */
-					len = current_bufflen;
-					nobuffs = current_nobuffs;
-					DPRINTK(PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno);
-					break;
-				default:
-
-					/*
-					 *	IDENTIFY distinguishes itself
-					 *	from the other messages by 
-					 *	setting the high bit.
-					 *
-					 *      Note : we need to handle at 
-					 *	least one outstanding command
-					 *	per LUN, and need to hash the 
-					 *	SCSI command for that I_T_L
-					 *	nexus based on the known ID 
-					 *	(at this point) and LUN.
-					 */
-
-					if (message & 0x80) {
-						DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7);
-					} else {
-						/*
-						 *      We should go into a
-						 *	MESSAGE OUT phase, and
-						 *	send  a MESSAGE_REJECT
-						 *      if we run into a message 
-						 *	that we don't like.  The
-						 *	seagate driver needs 
-						 *	some serious 
-						 *	restructuring first
-						 *	though.
-						 */
-						DPRINTK (PHASE_MSGIN, "scsi%d : unknown message %d from target %d.\n", hostno, message, target);
-					}
-				}
-				break;
-			default:
-				printk(KERN_ERR "scsi%d : unknown phase.\n", hostno);
-				st0x_aborted = DID_ERROR;
-			}	/* end of switch (status_read &  REQ_MASK) */
-#ifdef SLOW_RATE
-			/*
-			 * I really don't care to deal with borken devices in
-			 * each single byte transfer case (ie, message in,
-			 * message out, status), so I'll do the wait here if 
-			 * necessary.
-			 */
-			if(borken)
-				borken_wait();
-#endif
-
-		}		/* if(status_read & STAT_REQ) ends */
-	}			/* while(((status_read = STATUS)...) ends */
-
-	DPRINTK(PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, "scsi%d : Transfered %d bytes\n", hostno, transfered);
-
-#if (DEBUG & PHASE_EXIT)
-#if 0				/* Doesn't work for scatter/gather */
-	printk("Buffer : \n");
-	for(i = 0; i < 20; ++i)
-		printk("%02x  ", ((unsigned char *) data)[i]);	/* WDE mod */
-	printk("\n");
-#endif
-	printk("scsi%d : status = ", hostno);
-	scsi_print_status(status);
-	printk(" message = %02x\n", message);
-#endif
-
-	/* We shouldn't reach this until *after* BSY has been deasserted */
-
-#ifdef LINKED
-	else
-	{
-		/*
-		 * Fix the message byte so that unsuspecting high level drivers
-		 * don't puke when they see a LINKED COMMAND message in place of
-		 * the COMMAND COMPLETE they may be expecting.  Shouldn't be
-		 * necessary, but it's better to be on the safe side.
-		 *
-		 * A non LINKED* message byte will indicate that the command
-		 * completed, and we are now disconnected.
-		 */
-
-		switch (message) {
-		case LINKED_CMD_COMPLETE:
-		case LINKED_FLG_CMD_COMPLETE:
-			message = COMMAND_COMPLETE;
-			linked_target = current_target;
-			linked_lun = current_lun;
-			linked_connected = 1;
-			DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established for linked command.\n", hostno);
-			/* We also will need to adjust status to accommodate intermediate
-			   conditions. */
-			if ((status == INTERMEDIATE_GOOD) || (status == INTERMEDIATE_C_GOOD))
-				status = GOOD;
-			break;
-			/*
-			 * We should also handle what are "normal" termination
-			 * messages here (ABORT, BUS_DEVICE_RESET?, and
-			 * COMMAND_COMPLETE individually, and flake if things
-			 * aren't right.
-			 */
-		default:
-			DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno);
-			linked_connected = 0;
-		}
-	}
-#endif	/* LINKED */
-
-	if (should_reconnect) {
-		DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", hostno);
-		WRITE_CONTROL (BASE_CMD | CMD_INTR);
-	} else
-		WRITE_CONTROL (BASE_CMD);
-
-	return retcode (st0x_aborted);
-}				/* end of internal_command */
-
-static int seagate_st0x_abort(struct scsi_cmnd * SCpnt)
-{
-	st0x_aborted = DID_ABORT;
-	return SUCCESS;
-}
-
-#undef ULOOP
-#undef TIMEOUT
-
-/*
- * the seagate_st0x_reset function resets the SCSI bus 
- *
- * May be called with SCpnt = NULL
- */
-
-static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt)
-{
-	/* No timeouts - this command is going to fail because it was reset. */
-	DANY ("scsi%d: Reseting bus... ", hostno);
-
-	/* assert  RESET signal on SCSI bus.  */
-	WRITE_CONTROL (BASE_CMD | CMD_RST);
-
-	mdelay (20);
-
-	WRITE_CONTROL (BASE_CMD);
-	st0x_aborted = DID_RESET;
-
-	DANY ("done.\n");
-	return SUCCESS;
-}
-
-static int seagate_st0x_release(struct Scsi_Host *shost)
-{
-	if (shost->irq)
-		free_irq(shost->irq, shost);
-	release_region(shost->io_port, shost->n_io_port);
-	return 0;
-}
-
-static struct scsi_host_template driver_template = {
-	.detect         	= seagate_st0x_detect,
-	.release        	= seagate_st0x_release,
-	.info           	= seagate_st0x_info,
-	.queuecommand   	= seagate_st0x_queue_command,
-	.eh_abort_handler	= seagate_st0x_abort,
-	.eh_bus_reset_handler	= seagate_st0x_bus_reset,
-	.can_queue      	= 1,
-	.this_id        	= 7,
-	.sg_tablesize   	= SG_ALL,
-	.cmd_per_lun    	= 1,
-	.use_clustering		= DISABLE_CLUSTERING,
-};
-#include "scsi_module.c"
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index f1871ea04045..aba28f335b88 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -48,6 +48,7 @@ static int sg_version_num = 30534;	/* 2 digits for each component */
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/scatterlist.h>
+#include <linux/blktrace_api.h>
 
 #include "scsi.h"
 #include <scsi/scsi_dbg.h>
@@ -602,8 +603,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
 	 * but is is possible that the app intended SG_DXFER_TO_DEV, because there
 	 * is a non-zero input_size, so emit a warning.
 	 */
-	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV)
-		if (printk_ratelimit())
+	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) {
+		static char cmd[TASK_COMM_LEN];
+		if (strcmp(current->comm, cmd) && printk_ratelimit()) {
 			printk(KERN_WARNING
 			       "sg_write: data in/out %d/%d bytes for SCSI command 0x%x--"
 			       "guessing data in;\n" KERN_WARNING "   "
@@ -611,6 +613,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
 			       old_hdr.reply_len - (int)SZ_SG_HEADER,
 			       input_size, (unsigned int) cmnd[0],
 			       current->comm);
+			strcpy(cmd, current->comm);
+		}
+	}
 	k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
 	return (k < 0) ? k : count;
 }
@@ -1063,6 +1068,17 @@ sg_ioctl(struct inode *inode, struct file *filp,
 	case BLKSECTGET:
 		return put_user(sdp->device->request_queue->max_sectors * 512,
 				ip);
+	case BLKTRACESETUP:
+		return blk_trace_setup(sdp->device->request_queue,
+				       sdp->disk->disk_name,
+				       sdp->device->sdev_gendev.devt,
+				       (char *)arg);
+	case BLKTRACESTART:
+		return blk_trace_startstop(sdp->device->request_queue, 1);
+	case BLKTRACESTOP:
+		return blk_trace_startstop(sdp->device->request_queue, 0);
+	case BLKTRACETEARDOWN:
+		return blk_trace_remove(sdp->device->request_queue);
 	default:
 		if (read_only)
 			return -EPERM;	/* don't know so take safe approach */
@@ -1418,7 +1434,6 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
 		goto out;
 	}
 
-	class_set_devdata(cl_dev, sdp);
 	error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1);
 	if (error)
 		goto cdev_add_err;
@@ -1431,11 +1446,14 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
 				MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
 				cl_dev->dev, "%s",
 				disk->disk_name);
-		if (IS_ERR(sg_class_member))
-			printk(KERN_WARNING "sg_add: "
-				"class_device_create failed\n");
+		if (IS_ERR(sg_class_member)) {
+			printk(KERN_ERR "sg_add: "
+			       "class_device_create failed\n");
+			error = PTR_ERR(sg_class_member);
+			goto cdev_add_err;
+		}
 		class_set_devdata(sg_class_member, sdp);
-		error = sysfs_create_link(&scsidp->sdev_gendev.kobj, 
+		error = sysfs_create_link(&scsidp->sdev_gendev.kobj,
 					  &sg_class_member->kobj, "generic");
 		if (error)
 			printk(KERN_ERR "sg_add: unable to make symlink "
@@ -1447,6 +1465,8 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
 		    "Attached scsi generic sg%d type %d\n", sdp->index,
 		    scsidp->type);
 
+	class_set_devdata(cl_dev, sdp);
+
 	return 0;
 
 cdev_add_err:
@@ -2521,7 +2541,7 @@ sg_idr_max_id(int id, void *p, void *data)
 static int
 sg_last_dev(void)
 {
-	int k = 0;
+	int k = -1;
 	unsigned long iflags;
 
 	read_lock_irqsave(&sg_index_lock, iflags);
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index eef82758d047..26cfc56c7091 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -33,10 +33,9 @@
 
 struct ip22_hostdata {
 	struct WD33C93_hostdata wh;
-	struct hpc_data {
-		dma_addr_t      dma;
-		void		*cpu;
-	} hd;
+	dma_addr_t dma;
+	void *cpu;
+	struct device *dev;
 };
 
 #define host_to_hostdata(host) ((struct ip22_hostdata *)((host)->hostdata))
@@ -46,6 +45,11 @@ struct hpc_chunk {
 	u32 _padding;	/* align to quadword boundary */
 };
 
+/* space for hpc dma descriptors */
+#define HPC_DMA_SIZE   PAGE_SIZE
+
+#define DMA_DIR(d)   ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE)
+
 static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
 {
 	struct Scsi_Host * host = dev_id;
@@ -59,15 +63,17 @@ static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
 }
 
 static inline
-void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
+void fill_hpc_entries(struct ip22_hostdata *hd, struct scsi_cmnd *cmd, int din)
 {
 	unsigned long len = cmd->SCp.this_residual;
 	void *addr = cmd->SCp.ptr;
 	dma_addr_t physaddr;
 	unsigned long count;
+	struct hpc_chunk *hcp;
 
-	physaddr = dma_map_single(NULL, addr, len, cmd->sc_data_direction);
+	physaddr = dma_map_single(hd->dev, addr, len, DMA_DIR(din));
 	cmd->SCp.dma_handle = physaddr;
+	hcp = hd->cpu;
 
 	while (len) {
 		/*
@@ -89,6 +95,9 @@ void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
 	 */
 	hcp->desc.pbuf = 0;
 	hcp->desc.cntinfo = HPCDMA_EOX;
+	dma_cache_sync(hd->dev, hd->cpu,
+		       (unsigned long)(hcp + 1) - (unsigned long)hd->cpu,
+		       DMA_TO_DEVICE);
 }
 
 static int dma_setup(struct scsi_cmnd *cmd, int datainp)
@@ -96,9 +105,8 @@ static int dma_setup(struct scsi_cmnd *cmd, int datainp)
 	struct ip22_hostdata *hdata = host_to_hostdata(cmd->device->host);
 	struct hpc3_scsiregs *hregs =
 		(struct hpc3_scsiregs *) cmd->device->host->base;
-	struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->hd.cpu;
 
-	pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp);
+	pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hdata->cpu);
 
 	hdata->wh.dma_dir = datainp;
 
@@ -111,12 +119,12 @@ static int dma_setup(struct scsi_cmnd *cmd, int datainp)
 	if (cmd->SCp.ptr == NULL || cmd->SCp.this_residual == 0)
 		return 1;
 
-	fill_hpc_entries(hcp, cmd, datainp);
+	fill_hpc_entries(hdata, cmd, datainp);
 
 	pr_debug(" HPCGO\n");
 
 	/* Start up the HPC. */
-	hregs->ndptr = hdata->hd.dma;
+	hregs->ndptr = hdata->dma;
 	if (datainp)
 		hregs->ctrl = HPC3_SCTRL_ACTIVE;
 	else
@@ -134,6 +142,9 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 	if (!SCpnt)
 		return;
 
+	if (SCpnt->SCp.ptr == NULL || SCpnt->SCp.this_residual == 0)
+		return;
+
 	hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base;
 
 	pr_debug("dma_stop: status<%d> ", status);
@@ -145,8 +156,9 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 			barrier();
 	}
 	hregs->ctrl = 0;
-	dma_unmap_single(NULL, SCpnt->SCp.dma_handle, SCpnt->SCp.this_residual,
-	                 SCpnt->sc_data_direction);
+	dma_unmap_single(hdata->dev, SCpnt->SCp.dma_handle,
+			 SCpnt->SCp.this_residual,
+			 DMA_DIR(hdata->wh.dma_dir));
 
 	pr_debug("\n");
 }
@@ -159,23 +171,25 @@ void sgiwd93_reset(unsigned long base)
 	udelay(50);
 	hregs->ctrl = 0;
 }
+EXPORT_SYMBOL_GPL(sgiwd93_reset);
 
-static inline void init_hpc_chain(struct hpc_data *hd)
+static inline void init_hpc_chain(struct ip22_hostdata *hdata)
 {
-	struct hpc_chunk *hcp = (struct hpc_chunk *) hd->cpu;
-	struct hpc_chunk *dma = (struct hpc_chunk *) hd->dma;
+	struct hpc_chunk *hcp = (struct hpc_chunk *)hdata->cpu;
+	dma_addr_t dma = hdata->dma;
 	unsigned long start, end;
 
 	start = (unsigned long) hcp;
-	end = start + PAGE_SIZE;
+	end = start + HPC_DMA_SIZE;
 	while (start < end) {
-		hcp->desc.pnext = (u32) (dma + 1);
+		hcp->desc.pnext = (u32) (dma + sizeof(struct hpc_chunk));
 		hcp->desc.cntinfo = HPCDMA_EOX;
-		hcp++; dma++;
+		hcp++;
+		dma += sizeof(struct hpc_chunk);
 		start += sizeof(struct hpc_chunk);
 	};
 	hcp--;
-	hcp->desc.pnext = hd->dma;
+	hcp->desc.pnext = hdata->dma;
 }
 
 static int sgiwd93_bus_reset(struct scsi_cmnd *cmd)
@@ -234,16 +248,17 @@ static int __init sgiwd93_probe(struct platform_device *pdev)
 	host->irq = irq;
 
 	hdata = host_to_hostdata(host);
-	hdata->hd.cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
-	                                   &hdata->hd.dma, GFP_KERNEL);
-	if (!hdata->hd.cpu) {
+	hdata->dev = &pdev->dev;
+	hdata->cpu = dma_alloc_noncoherent(&pdev->dev, HPC_DMA_SIZE,
+					   &hdata->dma, GFP_KERNEL);
+	if (!hdata->cpu) {
 		printk(KERN_WARNING "sgiwd93: Could not allocate memory for "
 		       "host %d buffer.\n", unit);
 		err = -ENOMEM;
 		goto out_put;
 	}
 
-	init_hpc_chain(&hdata->hd);
+	init_hpc_chain(hdata);
 
 	regs.SASR = wdregs + 3;
 	regs.SCMD = wdregs + 7;
@@ -273,7 +288,7 @@ static int __init sgiwd93_probe(struct platform_device *pdev)
 out_irq:
 	free_irq(irq, host);
 out_free:
-	dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
+	dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma);
 out_put:
 	scsi_host_put(host);
 out:
@@ -289,7 +304,7 @@ static void __exit sgiwd93_remove(struct platform_device *pdev)
 
 	scsi_remove_host(host);
 	free_irq(pd->irq, host);
-	dma_free_coherent(&pdev->dev, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
+	dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma);
 	scsi_host_put(host);
 }
 
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index c61999031141..50ba49250203 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -67,8 +67,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
 
 #define SR_DISKS	256
 
-#define MAX_RETRIES	3
-#define SR_TIMEOUT	(30 * HZ)
 #define SR_CAPABILITIES \
 	(CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \
 	 CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \
@@ -179,21 +177,28 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
 {
 	struct scsi_cd *cd = cdi->handle;
 	int retval;
+	struct scsi_sense_hdr *sshdr;
 
 	if (CDSL_CURRENT != slot) {
 		/* no changer support */
 		return -EINVAL;
 	}
 
-	retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES);
-	if (retval) {
-		/* Unable to test, unit probably not ready.  This usually
-		 * means there is no disc in the drive.  Mark as changed,
-		 * and we will figure it out later once the drive is
-		 * available again.  */
+	sshdr =  kzalloc(sizeof(*sshdr), GFP_KERNEL);
+	retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
+				      sshdr);
+	if (retval || (scsi_sense_valid(sshdr) &&
+		       /* 0x3a is medium not present */
+		       sshdr->asc == 0x3a)) {
+		/* Media not present or unable to test, unit probably not
+		 * ready. This usually means there is no disc in the drive.
+		 * Mark as changed, and we will figure it out later once
+		 * the drive is available again.
+		 */
 		cd->device->changed = 1;
-		return 1;	/* This will force a flush, if called from
-				 * check_disk_change */
+		/* This will force a flush, if called from check_disk_change */
+		retval = 1;
+		goto out;
 	};
 
 	retval = cd->device->changed;
@@ -203,9 +208,17 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
 	if (retval) {
 		/* check multisession offset etc */
 		sr_cd_check(cdi);
-
 		get_sectorsize(cd);
 	}
+
+out:
+	/* Notify userspace, that media has changed. */
+	if (retval != cd->previous_state)
+		sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE,
+				     GFP_KERNEL);
+	cd->previous_state = retval;
+	kfree(sshdr);
+
 	return retval;
 }
  
@@ -218,7 +231,7 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
 static int sr_done(struct scsi_cmnd *SCpnt)
 {
 	int result = SCpnt->result;
-	int this_count = SCpnt->request_bufflen;
+	int this_count = scsi_bufflen(SCpnt);
 	int good_bytes = (result == 0 ? this_count : 0);
 	int block_sectors = 0;
 	long error_sector;
@@ -366,17 +379,18 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq)
 	}
 
 	{
-		struct scatterlist *sg = SCpnt->request_buffer;
-		int i, size = 0;
-		for (i = 0; i < SCpnt->use_sg; i++)
-			size += sg[i].length;
+		struct scatterlist *sg;
+		int i, size = 0, sg_count = scsi_sg_count(SCpnt);
+
+		scsi_for_each_sg(SCpnt, sg, sg_count, i)
+			size += sg->length;
 
-		if (size != SCpnt->request_bufflen && SCpnt->use_sg) {
+		if (size != scsi_bufflen(SCpnt)) {
 			scmd_printk(KERN_ERR, SCpnt,
 				"mismatch count %d, bytes %d\n",
-				size, SCpnt->request_bufflen);
-			if (SCpnt->request_bufflen > size)
-				SCpnt->request_bufflen = size;
+				size, scsi_bufflen(SCpnt));
+			if (scsi_bufflen(SCpnt) > size)
+				SCpnt->sdb.length = size;
 		}
 	}
 
@@ -384,12 +398,12 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq)
 	 * request doesn't start on hw block boundary, add scatter pads
 	 */
 	if (((unsigned int)rq->sector % (s_size >> 9)) ||
-	    (SCpnt->request_bufflen % s_size)) {
+	    (scsi_bufflen(SCpnt) % s_size)) {
 		scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n");
 		goto out;
 	}
 
-	this_count = (SCpnt->request_bufflen >> 9) / (s_size >> 9);
+	this_count = (scsi_bufflen(SCpnt) >> 9) / (s_size >> 9);
 
 
 	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
@@ -403,7 +417,7 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq)
 
 	if (this_count > 0xffff) {
 		this_count = 0xffff;
-		SCpnt->request_bufflen = this_count * s_size;
+		SCpnt->sdb.length = this_count * s_size;
 	}
 
 	SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
index d65de9621b27..81fbc0b78a52 100644
--- a/drivers/scsi/sr.h
+++ b/drivers/scsi/sr.h
@@ -20,6 +20,9 @@
 #include <linux/genhd.h>
 #include <linux/kref.h>
 
+#define MAX_RETRIES	3
+#define SR_TIMEOUT	(30 * HZ)
+
 struct scsi_device;
 
 /* The CDROM is fairly slow, so we need a little extra time */
@@ -37,6 +40,7 @@ typedef struct scsi_cd {
 	unsigned xa_flag:1;	/* CD has XA sectors ? */
 	unsigned readcd_known:1;	/* drive supports READ_CD (0xbe) */
 	unsigned readcd_cdda:1;	/* reading audio data using READ_CD */
+	unsigned previous_state:1;	/* media has changed */
 	struct cdrom_device_info cdi;
 	/* We hold gendisk and scsi_device references on probe and use
 	 * the refs on this kref to decide when to release them */
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index e1589f91706a..d5cebff1d646 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -275,18 +275,6 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
 /* ---------------------------------------------------------------------- */
 /* interface to cdrom.c                                                   */
 
-static int test_unit_ready(Scsi_CD *cd)
-{
-	struct packet_command cgc;
-
-	memset(&cgc, 0, sizeof(struct packet_command));
-	cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
-	cgc.quiet = 1;
-	cgc.data_direction = DMA_NONE;
-	cgc.timeout = IOCTL_TIMEOUT;
-	return sr_do_ioctl(cd, &cgc);
-}
-
 int sr_tray_move(struct cdrom_device_info *cdi, int pos)
 {
 	Scsi_CD *cd = cdi->handle;
@@ -310,14 +298,46 @@ int sr_lock_door(struct cdrom_device_info *cdi, int lock)
 
 int sr_drive_status(struct cdrom_device_info *cdi, int slot)
 {
+	struct scsi_cd *cd = cdi->handle;
+	struct scsi_sense_hdr sshdr;
+	struct media_event_desc med;
+
 	if (CDSL_CURRENT != slot) {
 		/* we have no changer support */
 		return -EINVAL;
 	}
-	if (0 == test_unit_ready(cdi->handle))
+	if (0 == scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES,
+				      &sshdr))
 		return CDS_DISC_OK;
 
-	return CDS_TRAY_OPEN;
+	if (!cdrom_get_media_event(cdi, &med)) {
+		if (med.media_present)
+			return CDS_DISC_OK;
+		else if (med.door_open)
+			return CDS_TRAY_OPEN;
+		else
+			return CDS_NO_DISC;
+	}
+
+	/*
+	 * 0x04 is format in progress .. but there must be a disc present!
+	 */
+	if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04)
+		return CDS_DISC_OK;
+
+	/*
+	 * If not using Mt Fuji extended media tray reports,
+	 * just return TRAY_OPEN since ATAPI doesn't provide
+	 * any other way to detect this...
+	 */
+	if (scsi_sense_valid(&sshdr) &&
+	    /* 0x3a is medium not present */
+	    sshdr.asc == 0x3a)
+		return CDS_NO_DISC;
+	else
+		return CDS_TRAY_OPEN;
+
+	return CDS_DRIVE_NOT_READY;
 }
 
 int sr_disk_status(struct cdrom_device_info *cdi)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 328c47c6aeb1..71952703125a 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -9,7 +9,7 @@
    Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
    Michael Schaefer, J"org Weule, and Eric Youngdale.
 
-   Copyright 1992 - 2007 Kai Makisara
+   Copyright 1992 - 2008 Kai Makisara
    email Kai.Makisara@kolumbus.fi
 
    Some small formal changes - aeb, 950809
@@ -17,7 +17,7 @@
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static const char *verstr = "20070203";
+static const char *verstr = "20080117";
 
 #include <linux/module.h>
 
@@ -3214,8 +3214,7 @@ static int partition_tape(struct scsi_tape *STp, int size)
 
 
 /* The ioctl command */
-static int st_ioctl(struct inode *inode, struct file *file,
-		    unsigned int cmd_in, unsigned long arg)
+static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
 {
 	int i, cmd_nr, cmd_type, bt;
 	int retval = 0;
@@ -3870,7 +3869,7 @@ static const struct file_operations st_fops =
 	.owner =	THIS_MODULE,
 	.read =		st_read,
 	.write =	st_write,
-	.ioctl =	st_ioctl,
+	.unlocked_ioctl = st_ioctl,
 #ifdef CONFIG_COMPAT
 	.compat_ioctl = st_compat_ioctl,
 #endif
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index e3fab3a6aed7..72f6d8015358 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -1123,7 +1123,6 @@ static struct scsi_host_template driver_template = {
 	.this_id			= -1,
 	.sg_tablesize			= ST_MAX_SG,
 	.cmd_per_lun			= ST_CMD_PER_LUN,
-	.use_sg_chaining		= ENABLE_SG_CHAINING,
 };
 
 static int stex_set_dma_mask(struct pci_dev * pdev)
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 2dcde373b20e..bcaba86060ab 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -515,9 +515,9 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
      * various queues are valid.
      */
 
-    if (cmd->use_sg) {
-	cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
-	cmd->SCp.buffers_residual = cmd->use_sg - 1;
+    if (scsi_bufflen(cmd)) {
+	cmd->SCp.buffer = scsi_sglist(cmd);
+	cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
 	cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer);
 	cmd->SCp.this_residual = cmd->SCp.buffer->length;
 
@@ -528,8 +528,8 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
     } else {
 	cmd->SCp.buffer = NULL;
 	cmd->SCp.buffers_residual = 0;
-	cmd->SCp.ptr = (char *) cmd->request_buffer;
-	cmd->SCp.this_residual = cmd->request_bufflen;
+	cmd->SCp.ptr = NULL;
+	cmd->SCp.this_residual = 0;
     }
     
 }
@@ -935,7 +935,7 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
     }
 # endif
 # ifdef NCR5380_STAT_LIMIT
-    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+    if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
 # endif
 	switch (cmd->cmnd[0])
 	{
@@ -943,14 +943,14 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd,
 	    case WRITE_6:
 	    case WRITE_10:
 		hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
-		hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+		hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
 		hostdata->pendingw++;
 		break;
 	    case READ:
 	    case READ_6:
 	    case READ_10:
 		hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
-		hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+		hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
 		hostdata->pendingr++;
 		break;
 	}
@@ -1345,7 +1345,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata,
 			  struct scsi_cmnd *cmd)
 {
 # ifdef NCR5380_STAT_LIMIT
-    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+    if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
 # endif
 	switch (cmd->cmnd[0])
 	{
@@ -1353,14 +1353,14 @@ static void collect_stats(struct NCR5380_hostdata *hostdata,
 	    case WRITE_6:
 	    case WRITE_10:
 		hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
-		/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
+		/*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/
 		hostdata->pendingw--;
 		break;
 	    case READ:
 	    case READ_6:
 	    case READ_10:
 		hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
-		/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
+		/*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/
 		hostdata->pendingr--;
 		break;
 	}
@@ -1863,7 +1863,7 @@ static int do_abort (struct Scsi_Host *host)
      * the target sees, so we just handshake.
      */
     
-    while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
+    while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
 
     NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
 
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 90cee94d9522..6325901e5093 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -328,27 +328,13 @@ static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer,
 static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id)
 {
 	struct Scsi_Host *dev = dev_id;
-	int base = 0;
+	int base = dev->io_port;
 	int i;
 	unsigned long flags = 0;
 	unsigned char status_reg, pio_int_reg, int_reg;
 	struct scatterlist *sg;
 	unsigned int tot_trans = 0;
 
-	/* We search the base address of the host adapter which caused the interrupt */
-	/* FIXME: should pass dev_id sensibly as hosts[i] */
-	for(i = 0; i < host_index && !base; i++)
-		if(irq == hosts[i].irq)
-			base = hosts[i].base;
-	/* If no adapter found, we cannot handle the interrupt. Leave a message */
-	/* and continue. This should never happen...                            */
-	if(!base)
-	{
-		printk(KERN_ERR "sym53c416: No host adapter defined for interrupt %d\n", irq);
-		return IRQ_NONE;
-	}
-	/* Now we have the base address and we can start handling the interrupt */
-
 	spin_lock_irqsave(dev->host_lock,flags);
 	status_reg = inb(base + STATUS_REG);
 	pio_int_reg = inb(base + PIO_INT_REG);
@@ -854,6 +840,5 @@ static struct scsi_host_template driver_template = {
 	.cmd_per_lun =		1,
 	.unchecked_isa_dma =	1,
 	.use_clustering =	ENABLE_CLUSTERING,
-	.use_sg_chaining =	ENABLE_SG_CHAINING,
 };
 #include "scsi_module.c"
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 9e0908d1981a..d39107b7669b 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -207,10 +207,9 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
 			/*
 			 *  Bounce back the sense data to user.
 			 */
-			memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+			memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
 			memcpy(cmd->sense_buffer, cp->sns_bbuf,
-			      min(sizeof(cmd->sense_buffer),
-				  (size_t)SYM_SNS_BBUF_LEN));
+			       min(SCSI_SENSE_BUFFERSIZE, SYM_SNS_BBUF_LEN));
 #if 0
 			/*
 			 *  If the device reports a UNIT ATTENTION condition 
@@ -609,22 +608,24 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
 	 */
 #define WAIT_FOR_PCI_RECOVERY	35
 	if (pci_channel_offline(pdev)) {
-		struct completion *io_reset;
 		int finished_reset = 0;
 		init_completion(&eh_done);
 		spin_lock_irq(shost->host_lock);
 		/* Make sure we didn't race */
 		if (pci_channel_offline(pdev)) {
-			if (!sym_data->io_reset)
-				sym_data->io_reset = &eh_done;
-			io_reset = sym_data->io_reset;
+			BUG_ON(sym_data->io_reset);
+			sym_data->io_reset = &eh_done;
 		} else {
 			finished_reset = 1;
 		}
 		spin_unlock_irq(shost->host_lock);
 		if (!finished_reset)
-			finished_reset = wait_for_completion_timeout(io_reset,
+			finished_reset = wait_for_completion_timeout
+						(sym_data->io_reset,
 						WAIT_FOR_PCI_RECOVERY*HZ);
+		spin_lock_irq(shost->host_lock);
+		sym_data->io_reset = NULL;
+		spin_unlock_irq(shost->host_lock);
 		if (!finished_reset)
 			return SCSI_FAILED;
 	}
@@ -1680,7 +1681,6 @@ static struct scsi_host_template sym2_template = {
 	.eh_host_reset_handler	= sym53c8xx_eh_host_reset_handler,
 	.this_id		= 7,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 	.max_sectors		= 0xFFFF,
 #ifdef SYM_LINUX_PROC_INFO_SUPPORT
 	.proc_info		= sym53c8xx_proc_info,
@@ -1744,7 +1744,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
 	return -ENODEV;
 }
 
-static void __devexit sym2_remove(struct pci_dev *pdev)
+static void sym2_remove(struct pci_dev *pdev)
 {
 	struct Scsi_Host *shost = pci_get_drvdata(pdev);
 
@@ -1879,7 +1879,6 @@ static void sym2_io_resume(struct pci_dev *pdev)
 	spin_lock_irq(shost->host_lock);
 	if (sym_data->io_reset)
 		complete_all(sym_data->io_reset);
-	sym_data->io_reset = NULL;
 	spin_unlock_irq(shost->host_lock);
 }
 
@@ -2056,7 +2055,7 @@ static struct pci_driver sym2_driver = {
 	.name		= NAME53C8XX,
 	.id_table	= sym2_id_table,
 	.probe		= sym2_probe,
-	.remove		= __devexit_p(sym2_remove),
+	.remove		= sym2_remove,
 	.err_handler 	= &sym2_err_handler,
 };
 
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 44193049c4ae..5b04ddfed26c 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -444,7 +444,7 @@ static int dc390_pci_map (struct dc390_srb* pSRB)
 
 	/* Map sense buffer */
 	if (pSRB->SRBFlag & AUTO_REQSENSE) {
-		pSRB->pSegmentList	= dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, sizeof(pcmd->sense_buffer));
+		pSRB->pSegmentList	= dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
 		pSRB->SGcount		= pci_map_sg(pdev, pSRB->pSegmentList, 1,
 						     DMA_FROM_DEVICE);
 		cmdp->saved_dma_handle	= sg_dma_address(pSRB->pSegmentList);
@@ -599,7 +599,7 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
 	    DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
 	    DC390_write8 (ScsiFifo, 0);
 	    DC390_write8 (ScsiFifo, 0);
-	    DC390_write8 (ScsiFifo, sizeof(scmd->sense_buffer));
+	    DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE);
 	    DC390_write8 (ScsiFifo, 0);
 	    DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n"));
 	  }
@@ -1389,7 +1389,7 @@ dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus
 	DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
 	DC390_write8 (ScsiFifo, 0);
 	DC390_write8 (ScsiFifo, 0);
-	DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+	DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE);
 	DC390_write8 (ScsiFifo, 0);
 	DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n"));
     }
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 7edd6ceb13b2..662c00451be4 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -451,7 +451,6 @@ static struct scsi_host_template driver_template = {
                 .this_id                 = 7,
                 .unchecked_isa_dma       = 1,
                 .use_clustering          = ENABLE_CLUSTERING,
-                .use_sg_chaining         = ENABLE_SG_CHAINING,
                 };
 
 #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
@@ -1121,9 +1120,9 @@ static void map_dma(unsigned int i, unsigned int j) {
 
    if (SCpnt->sense_buffer)
       cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
-                           sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+                           SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE));
 
-   cpp->sense_len = sizeof SCpnt->sense_buffer;
+   cpp->sense_len = SCSI_SENSE_BUFFERSIZE;
 
    if (scsi_bufflen(SCpnt)) {
 	   count = scsi_dma_map(SCpnt);
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 6d1f0edd7985..f385dce8dfbe 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -298,9 +298,16 @@ static inline int find_and_clear_bit_16(unsigned long *field)
 {
   int rv;
 
-  if (*field == 0) panic("No free mscp");
-  asm("xorl %0,%0\n0:\tbsfw %1,%w0\n\tbtr %0,%1\n\tjnc 0b"
-      : "=&r" (rv), "=m" (*field) : "1" (*field));
+  if (*field == 0)
+    panic("No free mscp");
+
+  asm volatile (
+	"xorl %0,%0\n\t"
+	"0: bsfw %1,%w0\n\t"
+	"btr %0,%1\n\t"
+	"jnc 0b"
+	: "=&r" (rv), "=m" (*field) :);
+
   return rv;
 }
 
@@ -741,7 +748,7 @@ static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
     }
     my_mscp->command_link = 0;		/*???*/
     my_mscp->scsi_command_link_id = 0;	/*???*/
-    my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer;
+    my_mscp->length_of_sense_byte = SCSI_SENSE_BUFFERSIZE;
     my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len;
     memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs);
     my_mscp->adapter_status = 0;
@@ -1197,6 +1204,5 @@ static struct scsi_host_template driver_template = {
 	.cmd_per_lun       = ULTRASTOR_MAX_CMDS_PER_LUN,
 	.unchecked_isa_dma = 1,
 	.use_clustering    = ENABLE_CLUSTERING,
-	.use_sg_chaining   = ENABLE_SG_CHAINING,
 };
 #include "scsi_module.c"
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index fdbb92d1f722..f286c37da7e0 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -407,16 +407,16 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
  *  - SCp.phase records this command's SRCID_ER bit setting
  */
 
-	if (cmd->use_sg) {
-		cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
-		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+	if (scsi_bufflen(cmd)) {
+		cmd->SCp.buffer = scsi_sglist(cmd);
+		cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
 		cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
 		cmd->SCp.this_residual = cmd->SCp.buffer->length;
 	} else {
 		cmd->SCp.buffer = NULL;
 		cmd->SCp.buffers_residual = 0;
-		cmd->SCp.ptr = (char *) cmd->request_buffer;
-		cmd->SCp.this_residual = cmd->request_bufflen;
+		cmd->SCp.ptr = NULL;
+		cmd->SCp.this_residual = 0;
 	}
 
 /* WD docs state that at the conclusion of a "LEVEL2" command, the
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 03cd44f231df..c975c01b3a02 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1108,13 +1108,10 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
 	scb->host = host;
 
 	nseg = scsi_sg_count(SCpnt);
-	if (nseg) {
+	if (nseg > 1) {
 		struct scatterlist *sg;
 		unsigned i;
 
-		if (SCpnt->device->host->sg_tablesize == SG_NONE) {
-			panic("wd7000_queuecommand: scatter/gather not supported.\n");
-		}
 		dprintk("Using scatter/gather with %d elements.\n", nseg);
 
 		sgb = scb->sgb;
@@ -1128,7 +1125,10 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
 		}
 	} else {
 		scb->op = 0;
-		any2scsi(scb->dataptr, isa_virt_to_bus(scsi_sglist(SCpnt)));
+		if (nseg) {
+			struct scatterlist *sg = scsi_sglist(SCpnt);
+			any2scsi(scb->dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
+		}
 		any2scsi(scb->maxlen, scsi_bufflen(SCpnt));
 	}
 
@@ -1524,7 +1524,7 @@ static __init int wd7000_detect(struct scsi_host_template *tpnt)
 				 *  For boards before rev 6.0, scatter/gather isn't supported.
 				 */
 				if (host->rev1 < 6)
-					sh->sg_tablesize = SG_NONE;
+					sh->sg_tablesize = 1;
 
 				present++;	/* count it */
 
@@ -1671,7 +1671,6 @@ static struct scsi_host_template driver_template = {
 	.cmd_per_lun		= 1,
 	.unchecked_isa_dma	= 1,
 	.use_clustering		= ENABLE_CLUSTERING,
-	.use_sg_chaining	= ENABLE_SG_CHAINING,
 };
 
 #include "scsi_module.c"
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
index facb67855619..6a48dfa1efe8 100644
--- a/drivers/serial/21285.c
+++ b/drivers/serial/21285.c
@@ -277,6 +277,8 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
 	if (termios->c_iflag & INPCK)
 		port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
 
+	tty_encode_baud_rate(tty,  baud, baud);
+
 	/*
 	 * Which character status flags should we ignore?
 	 */
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 6f475b609864..ac2a3ef28d55 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -442,7 +442,8 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
 		set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
 			INTR_ON_BUF,
 			DIMENSION_LINEAR,
-			DATA_SIZE_8));
+			DATA_SIZE_8,
+			DMA_SYNC_RESTART));
 	set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
 	set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
 	set_dma_x_modify(uart->tx_dma_channel, 1);
@@ -689,7 +690,8 @@ static int bfin_serial_startup(struct uart_port *port)
 	set_dma_config(uart->rx_dma_channel,
 		set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
 				INTR_ON_ROW, DIMENSION_2D,
-				DATA_SIZE_8));
+				DATA_SIZE_8,
+				DMA_SYNC_RESTART));
 	set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
 	set_dma_x_modify(uart->rx_dma_channel, 1);
 	set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index 9d3105b64a7a..9c2df5c857cf 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -48,7 +48,7 @@
 #include <linux/vmalloc.h>
 #include <linux/smp.h>
 #include <linux/spinlock.h>
-#include <linux/kobject.h>
+#include <linux/kref.h>
 #include <linux/firmware.h>
 #include <linux/bitops.h>
 
@@ -65,7 +65,7 @@
 #define ICOM_VERSION_STR "1.3.1"
 #define NR_PORTS	       128
 #define ICOM_PORT ((struct icom_port *)port)
-#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj)
+#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref)
 
 static const struct pci_device_id icom_pci_table[] = {
 	{
@@ -141,6 +141,7 @@ static inline void trace(struct icom_port *, char *, unsigned long) {};
 #else
 static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
 #endif
+static void icom_kref_release(struct kref *kref);
 
 static void free_port_memory(struct icom_port *icom_port)
 {
@@ -1063,11 +1064,11 @@ static int icom_open(struct uart_port *port)
 {
 	int retval;
 
-	kobject_get(&ICOM_PORT->adapter->kobj);
+	kref_get(&ICOM_PORT->adapter->kref);
 	retval = startup(ICOM_PORT);
 
 	if (retval) {
-		kobject_put(&ICOM_PORT->adapter->kobj);
+		kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
 		trace(ICOM_PORT, "STARTUP_ERROR", 0);
 		return retval;
 	}
@@ -1088,7 +1089,7 @@ static void icom_close(struct uart_port *port)
 
 	shutdown(ICOM_PORT);
 
-	kobject_put(&ICOM_PORT->adapter->kobj);
+	kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
 }
 
 static void icom_set_termios(struct uart_port *port,
@@ -1485,18 +1486,14 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter)
 	pci_release_regions(icom_adapter->pci_dev);
 }
 
-static void icom_kobj_release(struct kobject *kobj)
+static void icom_kref_release(struct kref *kref)
 {
 	struct icom_adapter *icom_adapter;
 
-	icom_adapter = to_icom_adapter(kobj);
+	icom_adapter = to_icom_adapter(kref);
 	icom_remove_adapter(icom_adapter);
 }
 
-static struct kobj_type icom_kobj_type = {
-	.release = icom_kobj_release,
-};
-
 static int __devinit icom_probe(struct pci_dev *dev,
 				const struct pci_device_id *ent)
 {
@@ -1592,8 +1589,7 @@ static int __devinit icom_probe(struct pci_dev *dev,
 		}
 	}
 
-	kobject_init(&icom_adapter->kobj);
-	icom_adapter->kobj.ktype = &icom_kobj_type;
+	kref_init(&icom_adapter->kref);
 	return 0;
 
 probe_exit2:
@@ -1619,7 +1615,7 @@ static void __devexit icom_remove(struct pci_dev *dev)
 		icom_adapter = list_entry(tmp, struct icom_adapter,
 					  icom_adapter_entry);
 		if (icom_adapter->pci_dev == dev) {
-			kobject_put(&icom_adapter->kobj);
+			kref_put(&icom_adapter->kref, icom_kref_release);
 			return;
 		}
 	}
diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h
index e8578d8cd35e..027455496745 100644
--- a/drivers/serial/icom.h
+++ b/drivers/serial/icom.h
@@ -270,7 +270,7 @@ struct icom_adapter {
 #define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM	0x0251
 	int numb_ports;
 	struct list_head icom_adapter_entry;
-	struct kobject kobj;
+	struct kref kref;
 };
 
 /* prototype */
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 73440e26834b..ddf639144538 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -302,7 +302,7 @@ static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
 	}
 	sci_out(port, SCFCR, fcr_val);
 }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
 static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
 {
 	unsigned int fcr_val = 0;
@@ -395,7 +395,8 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
 	} else {
 #ifdef CONFIG_CPU_SUBTYPE_SH7343
 		/* Nothing */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7780) || \
       defined(CONFIG_CPU_SUBTYPE_SH7785) || \
       defined(CONFIG_CPU_SUBTYPE_SHX3)
 		ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */
@@ -408,6 +409,7 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
 #endif
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7763) || \
     defined(CONFIG_CPU_SUBTYPE_SH7780) || \
     defined(CONFIG_CPU_SUBTYPE_SH7785)
 static inline int scif_txroom(struct uart_port *port)
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index d24621ce799a..f5764ebcfe07 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -46,7 +46,8 @@
  */
 # define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
 # define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7721)
 # define SCSCR_INIT(port)  0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
 # define SCIF_ONLY
 #define SCIF_ORER    0x0200   /* overrun error bit */
@@ -119,6 +120,12 @@
 # define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
 # define SCI_ONLY
 # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
+# define SCSPTR1 0xffe08024 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)	0x3a	/* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
 #elif defined(CONFIG_CPU_SUBTYPE_SH7770)
 # define SCSPTR0 0xff923020 /* 16 bit SCIF */
 # define SCSPTR1 0xff924020 /* 16 bit SCIF */
@@ -142,7 +149,9 @@
 # define SCIF_OPER	0x0001		/* Overrun error bit */
 # define SCSCR_INIT(port)	0x3a	/* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
 # define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7263)
 # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
 # define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
 # define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
@@ -214,7 +223,8 @@
 #define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720)
+    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721)
 #define SCIF_ORER    0x0200
 #define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
 #define SCIF_RFDC_MASK 0x007f
@@ -252,7 +262,8 @@
 # define SCxSR_PER(port)		SCIF_PER
 # define SCxSR_BRK(port)		SCIF_BRK
 #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720)
+    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721)
 # define SCxSR_RDxF_CLEAR(port)         (sci_in(port,SCxSR)&0xfffc)
 # define SCxSR_ERROR_CLEAR(port)        (sci_in(port,SCxSR)&0xfd73)
 # define SCxSR_TDxE_CLEAR(port)         (sci_in(port,SCxSR)&0xffdf)
@@ -361,7 +372,8 @@
 #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
 	  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
 #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7720)
+      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7721)
 #define SCIF_FNS(name, scif_offset, scif_size) \
   CPU_SCIF_FNS(name, scif_offset, scif_size)
 #else
@@ -388,7 +400,8 @@
 #endif
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720)
+    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7721)
 
 SCIF_FNS(SCSMR,  0x00, 16)
 SCIF_FNS(SCBRR,  0x04,  8)
@@ -412,6 +425,7 @@ SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
 SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
 SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
 #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7763) || \
     defined(CONFIG_CPU_SUBTYPE_SH7780) || \
     defined(CONFIG_CPU_SUBTYPE_SH7785)
 SCIF_FNS(SCFDR,			     0x0e, 16, 0x1C, 16)
@@ -510,7 +524,8 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port)
 		return;
 	}
 }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7721)
 static inline int sci_rxd_in(struct uart_port *port)
 {
 	if (port->mapbase == 0xa4430000)
@@ -580,6 +595,15 @@ static inline int sci_rxd_in(struct uart_port *port)
 	int ch = (port->mapbase - SMR0) >> 3;
 	return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
 }
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+	if (port->mapbase == 0xffe00000)
+		return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xffe08000)
+		return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+	return 1;
+}
 #elif defined(CONFIG_CPU_SUBTYPE_SH7770)
 static inline int sci_rxd_in(struct uart_port *port)
 {
@@ -617,7 +641,9 @@ static inline int sci_rxd_in(struct uart_port *port)
 		return ctrl_inw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */
 	return 1;
 }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7206) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7263)
 static inline int sci_rxd_in(struct uart_port *port)
 {
 	if (port->mapbase == 0xfffe8000)
@@ -688,11 +714,13 @@ static inline int sci_rxd_in(struct uart_port *port)
  * -- Mitch Davis - 15 Jul 2000
  */
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+#if defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
     defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
 #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7720)
+      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7721)
 #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
 #elif defined(__H8300H__) || defined(__H8300S__)
 #define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index abf05048c638..aaaea81e412a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -153,6 +153,7 @@ config SPI_OMAP24XX
 config SPI_PXA2XX
 	tristate "PXA2xx SSP SPI master"
 	depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL
+	select PXA_SSP
 	help
 	  This enables using a PXA2xx SSP port as a SPI master controller.
 	  The driver can be configured to use any SSP port and additional
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index 3cdab131c4a9..ea61724ae225 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -350,6 +350,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
 		tx = xfer->tx_buf;
 
 		do {
+			c -= 1;
 			if (tx != NULL) {
 				if (mcspi_wait_for_reg_bit(chstat_reg,
 						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -380,7 +381,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
 						word_len, *(rx - 1));
 #endif
 			}
-			c -= 1;
 		} while (c);
 	} else if (word_len <= 16) {
 		u16		*rx;
@@ -389,6 +389,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
 		rx = xfer->rx_buf;
 		tx = xfer->tx_buf;
 		do {
+			c -= 2;
 			if (tx != NULL) {
 				if (mcspi_wait_for_reg_bit(chstat_reg,
 						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -419,7 +420,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
 						word_len, *(rx - 1));
 #endif
 			}
-			c -= 2;
 		} while (c);
 	} else if (word_len <= 32) {
 		u32		*rx;
@@ -428,6 +428,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
 		rx = xfer->rx_buf;
 		tx = xfer->tx_buf;
 		do {
+			c -= 4;
 			if (tx != NULL) {
 				if (mcspi_wait_for_reg_bit(chstat_reg,
 						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
@@ -458,7 +459,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
 						word_len, *(rx - 1));
 #endif
 			}
-			c -= 4;
 		} while (c);
 	}
 
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 1c2ab541d37d..eb817b8eb024 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -27,6 +27,7 @@
 #include <linux/spi/spi.h>
 #include <linux/workqueue.h>
 #include <linux/delay.h>
+#include <linux/clk.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -36,6 +37,8 @@
 
 #include <asm/arch/hardware.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/regs-ssp.h>
+#include <asm/arch/ssp.h>
 #include <asm/arch/pxa2xx_spi.h>
 
 MODULE_AUTHOR("Stephen Street");
@@ -80,6 +83,9 @@ struct driver_data {
 	/* Driver model hookup */
 	struct platform_device *pdev;
 
+	/* SSP Info */
+	struct ssp_device *ssp;
+
 	/* SPI framework hookup */
 	enum pxa_ssp_type ssp_type;
 	struct spi_master *master;
@@ -778,6 +784,16 @@ int set_dma_burst_and_threshold(struct chip_data *chip, struct spi_device *spi,
 	return retval;
 }
 
+static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
+{
+	unsigned long ssp_clk = clk_get_rate(ssp->clk);
+
+	if (ssp->type == PXA25x_SSP)
+		return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
+	else
+		return ((ssp_clk / rate - 1) & 0xfff) << 8;
+}
+
 static void pump_transfers(unsigned long data)
 {
 	struct driver_data *drv_data = (struct driver_data *)data;
@@ -785,6 +801,7 @@ static void pump_transfers(unsigned long data)
 	struct spi_transfer *transfer = NULL;
 	struct spi_transfer *previous = NULL;
 	struct chip_data *chip = NULL;
+	struct ssp_device *ssp = drv_data->ssp;
 	void *reg = drv_data->ioaddr;
 	u32 clk_div = 0;
 	u8 bits = 0;
@@ -866,12 +883,7 @@ static void pump_transfers(unsigned long data)
 		if (transfer->bits_per_word)
 			bits = transfer->bits_per_word;
 
-		if (reg == SSP1_VIRT)
-			clk_div = SSP1_SerClkDiv(speed);
-		else if (reg == SSP2_VIRT)
-			clk_div = SSP2_SerClkDiv(speed);
-		else if (reg == SSP3_VIRT)
-			clk_div = SSP3_SerClkDiv(speed);
+		clk_div = ssp_get_clk_div(ssp, speed);
 
 		if (bits <= 8) {
 			drv_data->n_bytes = 1;
@@ -1074,6 +1086,7 @@ static int setup(struct spi_device *spi)
 	struct pxa2xx_spi_chip *chip_info = NULL;
 	struct chip_data *chip;
 	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+	struct ssp_device *ssp = drv_data->ssp;
 	unsigned int clk_div;
 
 	if (!spi->bits_per_word)
@@ -1157,18 +1170,7 @@ static int setup(struct spi_device *spi)
 		}
 	}
 
-	if (drv_data->ioaddr == SSP1_VIRT)
-		clk_div = SSP1_SerClkDiv(spi->max_speed_hz);
-	else if (drv_data->ioaddr == SSP2_VIRT)
-		clk_div = SSP2_SerClkDiv(spi->max_speed_hz);
-	else if (drv_data->ioaddr == SSP3_VIRT)
-		clk_div = SSP3_SerClkDiv(spi->max_speed_hz);
-	else
-	{
-		dev_err(&spi->dev, "failed setup: unknown IO address=0x%p\n",
-			drv_data->ioaddr);
-		return -ENODEV;
-	}
+	clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz);
 	chip->speed_hz = spi->max_speed_hz;
 
 	chip->cr0 = clk_div
@@ -1183,15 +1185,15 @@ static int setup(struct spi_device *spi)
 
 	/* NOTE:  PXA25x_SSP _could_ use external clocking ... */
 	if (drv_data->ssp_type != PXA25x_SSP)
-		dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
+		dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
 				spi->bits_per_word,
-				(CLOCK_SPEED_HZ)
+				clk_get_rate(ssp->clk)
 					/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
 				spi->mode & 0x3);
 	else
-		dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
+		dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
 				spi->bits_per_word,
-				(CLOCK_SPEED_HZ/2)
+				clk_get_rate(ssp->clk)
 					/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
 				spi->mode & 0x3);
 
@@ -1323,14 +1325,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 	struct pxa2xx_spi_master *platform_info;
 	struct spi_master *master;
 	struct driver_data *drv_data = 0;
-	struct resource *memory_resource;
-	int irq;
+	struct ssp_device *ssp;
 	int status = 0;
 
 	platform_info = dev->platform_data;
 
-	if (platform_info->ssp_type == SSP_UNDEFINED) {
-		dev_err(&pdev->dev, "undefined SSP\n");
+	ssp = ssp_request(pdev->id, pdev->name);
+	if (ssp == NULL) {
+		dev_err(&pdev->dev, "failed to request SSP%d\n", pdev->id);
 		return -ENODEV;
 	}
 
@@ -1338,12 +1340,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 	master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
 	if (!master) {
 		dev_err(&pdev->dev, "can not alloc spi_master\n");
+		ssp_free(ssp);
 		return -ENOMEM;
 	}
 	drv_data = spi_master_get_devdata(master);
 	drv_data->master = master;
 	drv_data->master_info = platform_info;
 	drv_data->pdev = pdev;
+	drv_data->ssp = ssp;
 
 	master->bus_num = pdev->id;
 	master->num_chipselect = platform_info->num_chipselect;
@@ -1351,21 +1355,13 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 	master->setup = setup;
 	master->transfer = transfer;
 
-	drv_data->ssp_type = platform_info->ssp_type;
+	drv_data->ssp_type = ssp->type;
 	drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
 						sizeof(struct driver_data)), 8);
 
-	/* Setup register addresses */
-	memory_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!memory_resource) {
-		dev_err(&pdev->dev, "memory resources not defined\n");
-		status = -ENODEV;
-		goto out_error_master_alloc;
-	}
-
-	drv_data->ioaddr = (void *)io_p2v((unsigned long)(memory_resource->start));
-	drv_data->ssdr_physical = memory_resource->start + 0x00000010;
-	if (platform_info->ssp_type == PXA25x_SSP) {
+	drv_data->ioaddr = ssp->mmio_base;
+	drv_data->ssdr_physical = ssp->phys_base + SSDR;
+	if (ssp->type == PXA25x_SSP) {
 		drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
 		drv_data->dma_cr1 = 0;
 		drv_data->clear_sr = SSSR_ROR;
@@ -1377,15 +1373,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 		drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
 	}
 
-	/* Attach to IRQ */
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(&pdev->dev, "irq resource not defined\n");
-		status = -ENODEV;
-		goto out_error_master_alloc;
-	}
-
-	status = request_irq(irq, ssp_int, 0, dev->bus_id, drv_data);
+	status = request_irq(ssp->irq, ssp_int, 0, dev->bus_id, drv_data);
 	if (status < 0) {
 		dev_err(&pdev->dev, "can not get IRQ\n");
 		goto out_error_master_alloc;
@@ -1418,29 +1406,12 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
 			goto out_error_dma_alloc;
 		}
 
-		if (drv_data->ioaddr == SSP1_VIRT) {
-				DRCMRRXSSDR = DRCMR_MAPVLD
-						| drv_data->rx_channel;
-				DRCMRTXSSDR = DRCMR_MAPVLD
-						| drv_data->tx_channel;
-		} else if (drv_data->ioaddr == SSP2_VIRT) {
-				DRCMRRXSS2DR = DRCMR_MAPVLD
-						| drv_data->rx_channel;
-				DRCMRTXSS2DR = DRCMR_MAPVLD
-						| drv_data->tx_channel;
-		} else if (drv_data->ioaddr == SSP3_VIRT) {
-				DRCMRRXSS3DR = DRCMR_MAPVLD
-						| drv_data->rx_channel;
-				DRCMRTXSS3DR = DRCMR_MAPVLD
-						| drv_data->tx_channel;
-		} else {
-			dev_err(dev, "bad SSP type\n");
-			goto out_error_dma_alloc;
-		}
+		DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
+		DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;
 	}
 
 	/* Enable SOC clock */
-	pxa_set_cken(platform_info->clock_enable, 1);
+	clk_enable(ssp->clk);
 
 	/* Load default SSP configuration */
 	write_SSCR0(0, drv_data->ioaddr);
@@ -1479,7 +1450,7 @@ out_error_queue_alloc:
 	destroy_queue(drv_data);
 
 out_error_clock_enabled:
-	pxa_set_cken(platform_info->clock_enable, 0);
+	clk_disable(ssp->clk);
 
 out_error_dma_alloc:
 	if (drv_data->tx_channel != -1)
@@ -1488,17 +1459,18 @@ out_error_dma_alloc:
 		pxa_free_dma(drv_data->rx_channel);
 
 out_error_irq_alloc:
-	free_irq(irq, drv_data);
+	free_irq(ssp->irq, drv_data);
 
 out_error_master_alloc:
 	spi_master_put(master);
+	ssp_free(ssp);
 	return status;
 }
 
 static int pxa2xx_spi_remove(struct platform_device *pdev)
 {
 	struct driver_data *drv_data = platform_get_drvdata(pdev);
-	int irq;
+	struct ssp_device *ssp = drv_data->ssp;
 	int status = 0;
 
 	if (!drv_data)
@@ -1520,28 +1492,21 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
 
 	/* Disable the SSP at the peripheral and SOC level */
 	write_SSCR0(0, drv_data->ioaddr);
-	pxa_set_cken(drv_data->master_info->clock_enable, 0);
+	clk_disable(ssp->clk);
 
 	/* Release DMA */
 	if (drv_data->master_info->enable_dma) {
-		if (drv_data->ioaddr == SSP1_VIRT) {
-			DRCMRRXSSDR = 0;
-			DRCMRTXSSDR = 0;
-		} else if (drv_data->ioaddr == SSP2_VIRT) {
-			DRCMRRXSS2DR = 0;
-			DRCMRTXSS2DR = 0;
-		} else if (drv_data->ioaddr == SSP3_VIRT) {
-			DRCMRRXSS3DR = 0;
-			DRCMRTXSS3DR = 0;
-		}
+		DRCMR(ssp->drcmr_rx) = 0;
+		DRCMR(ssp->drcmr_tx) = 0;
 		pxa_free_dma(drv_data->tx_channel);
 		pxa_free_dma(drv_data->rx_channel);
 	}
 
 	/* Release IRQ */
-	irq = platform_get_irq(pdev, 0);
-	if (irq >= 0)
-		free_irq(irq, drv_data);
+	free_irq(ssp->irq, drv_data);
+
+	/* Release SSP */
+	ssp_free(ssp);
 
 	/* Disconnect from the SPI framework */
 	spi_unregister_master(drv_data->master);
@@ -1576,6 +1541,7 @@ static int suspend_devices(struct device *dev, void *pm_message)
 static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct driver_data *drv_data = platform_get_drvdata(pdev);
+	struct ssp_device *ssp = drv_data->ssp;
 	int status = 0;
 
 	/* Check all childern for current power state */
@@ -1588,7 +1554,7 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
 	if (status != 0)
 		return status;
 	write_SSCR0(0, drv_data->ioaddr);
-	pxa_set_cken(drv_data->master_info->clock_enable, 0);
+	clk_disable(ssp->clk);
 
 	return 0;
 }
@@ -1596,10 +1562,11 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
 static int pxa2xx_spi_resume(struct platform_device *pdev)
 {
 	struct driver_data *drv_data = platform_get_drvdata(pdev);
+	struct ssp_device *ssp = drv_data->ssp;
 	int status = 0;
 
 	/* Enable the SSP clock */
-	pxa_set_cken(drv_data->master_info->clock_enable, 1);
+	clk_disable(ssp->clk);
 
 	/* Start the queue running */
 	status = start_queue(drv_data);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 93e9de46977a..682a6a48fec3 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -485,6 +485,15 @@ void spi_unregister_master(struct spi_master *master)
 }
 EXPORT_SYMBOL_GPL(spi_unregister_master);
 
+static int __spi_master_match(struct device *dev, void *data)
+{
+	struct spi_master *m;
+	u16 *bus_num = data;
+
+	m = container_of(dev, struct spi_master, dev);
+	return m->bus_num == *bus_num;
+}
+
 /**
  * spi_busnum_to_master - look up master associated with bus_num
  * @bus_num: the master's bus number
@@ -499,17 +508,12 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
 {
 	struct device		*dev;
 	struct spi_master	*master = NULL;
-	struct spi_master	*m;
-
-	down(&spi_master_class.sem);
-	list_for_each_entry(dev, &spi_master_class.children, node) {
-		m = container_of(dev, struct spi_master, dev);
-		if (m->bus_num == bus_num) {
-			master = spi_master_get(m);
-			break;
-		}
-	}
-	up(&spi_master_class.sem);
+
+	dev = class_find_device(&spi_master_class, &bus_num,
+				__spi_master_match);
+	if (dev)
+		master = container_of(dev, struct spi_master, dev);
+	/* reference got in class_find_device */
 	return master;
 }
 EXPORT_SYMBOL_GPL(spi_busnum_to_master);
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
index f145d8a4cfde..1a31f7a72848 100644
--- a/drivers/ssb/b43_pci_bridge.c
+++ b/drivers/ssb/b43_pci_bridge.c
@@ -27,6 +27,8 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4328) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 85a20546e827..9028ed5715a1 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -872,14 +872,22 @@ EXPORT_SYMBOL(ssb_clockspeed);
 
 static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev)
 {
+	u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV;
+
 	/* The REJECT bit changed position in TMSLOW between
 	 * Backplane revisions. */
-	switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) {
+	switch (rev) {
 	case SSB_IDLOW_SSBREV_22:
 		return SSB_TMSLOW_REJECT_22;
 	case SSB_IDLOW_SSBREV_23:
 		return SSB_TMSLOW_REJECT_23;
+	case SSB_IDLOW_SSBREV_24:     /* TODO - find the proper REJECT bits */
+	case SSB_IDLOW_SSBREV_25:     /* same here */
+	case SSB_IDLOW_SSBREV_26:     /* same here */
+	case SSB_IDLOW_SSBREV_27:     /* same here */
+		return SSB_TMSLOW_REJECT_23;	/* this is a guess */
 	default:
+		printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
 		WARN_ON(1);
 	}
 	return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 0ab095c6581a..b434df75047f 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -212,29 +212,29 @@ static inline u8 ssb_crc8(u8 crc, u8 data)
 	return t[crc ^ data];
 }
 
-static u8 ssb_sprom_crc(const u16 *sprom)
+static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
 {
 	int word;
 	u8 crc = 0xFF;
 
-	for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) {
+	for (word = 0; word < size - 1; word++) {
 		crc = ssb_crc8(crc, sprom[word] & 0x00FF);
 		crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
 	}
-	crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF);
+	crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
 	crc ^= 0xFF;
 
 	return crc;
 }
 
-static int sprom_check_crc(const u16 *sprom)
+static int sprom_check_crc(const u16 *sprom, u16 size)
 {
 	u8 crc;
 	u8 expected_crc;
 	u16 tmp;
 
-	crc = ssb_sprom_crc(sprom);
-	tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC;
+	crc = ssb_sprom_crc(sprom, size);
+	tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
 	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
 	if (crc != expected_crc)
 		return -EPROTO;
@@ -246,8 +246,8 @@ static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
 {
 	int i;
 
-	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++)
-		sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2));
+	for (i = 0; i < bus->sprom_size; i++)
+		sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2));
 }
 
 static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
@@ -255,6 +255,7 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
 	struct pci_dev *pdev = bus->host_pci;
 	int i, err;
 	u32 spromctl;
+	u16 size = bus->sprom_size;
 
 	ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
 	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
@@ -266,12 +267,12 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
 		goto err_ctlreg;
 	ssb_printk(KERN_NOTICE PFX "[ 0%%");
 	msleep(500);
-	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
-		if (i == SSB_SPROMSIZE_WORDS / 4)
+	for (i = 0; i < size; i++) {
+		if (i == size / 4)
 			ssb_printk("25%%");
-		else if (i == SSB_SPROMSIZE_WORDS / 2)
+		else if (i == size / 2)
 			ssb_printk("50%%");
-		else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3)
+		else if (i == (size * 3) / 4)
 			ssb_printk("75%%");
 		else if (i % 2)
 			ssb_printk(".");
@@ -296,24 +297,53 @@ err_ctlreg:
 	return err;
 }
 
-static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
+static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
+			       u16 mask, u16 shift)
+{
+	u16 v;
+	u8 gain;
+
+	v = in[SPOFF(SSB_SPROM1_AGAIN)];
+	gain = (v & mask) >> shift;
+	if (gain == 0xFF)
+		gain = 2; /* If unset use 2dBm */
+	if (sprom_revision == 1) {
+		/* Convert to Q5.2 */
+		gain <<= 2;
+	} else {
+		/* Q5.2 Fractional part is stored in 0xC0 */
+		gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
+	}
+
+	return (s8)gain;
+}
+
+static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
 {
 	int i;
 	u16 v;
+	s8 gain;
+	u16 loc[3];
 
-	SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0);
-	SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0);
-	SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0);
+	if (out->revision == 3) {			/* rev 3 moved MAC */
+		loc[0] = SSB_SPROM3_IL0MAC;
+		loc[1] = SSB_SPROM3_ET0MAC;
+		loc[2] = SSB_SPROM3_ET1MAC;
+	} else {
+		loc[0] = SSB_SPROM1_IL0MAC;
+		loc[1] = SSB_SPROM1_ET0MAC;
+		loc[2] = SSB_SPROM1_ET1MAC;
+	}
 	for (i = 0; i < 3; i++) {
-		v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
+		v = in[SPOFF(loc[0]) + i];
 		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
 	}
 	for (i = 0; i < 3; i++) {
-		v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
+		v = in[SPOFF(loc[1]) + i];
 		*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
 	}
 	for (i = 0; i < 3; i++) {
-		v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
+		v = in[SPOFF(loc[2]) + i];
 		*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
 	}
 	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
@@ -324,9 +354,9 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
 	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
 	SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
 	     SSB_SPROM1_BINF_CCODE_SHIFT);
-	SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
+	SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
 	     SSB_SPROM1_BINF_ANTA_SHIFT);
-	SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
+	SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
 	     SSB_SPROM1_BINF_ANTBG_SHIFT);
 	SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
 	SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
@@ -347,100 +377,108 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
 	     SSB_SPROM1_ITSSI_A_SHIFT);
 	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
 	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
-	SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
-	SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
-	     SSB_SPROM1_AGAIN_BG_SHIFT);
-	for (i = 0; i < 4; i++) {
-		v = in[SPOFF(SSB_SPROM1_OEM) + i];
-		*(((__le16 *)out->oem) + i) = cpu_to_le16(v);
-	}
+	if (out->revision >= 2)
+		SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
+
+	/* Extract the antenna gain values. */
+	gain = r123_extract_antgain(out->revision, in,
+				    SSB_SPROM1_AGAIN_BG,
+				    SSB_SPROM1_AGAIN_BG_SHIFT);
+	out->antenna_gain.ghz24.a0 = gain;
+	out->antenna_gain.ghz24.a1 = gain;
+	out->antenna_gain.ghz24.a2 = gain;
+	out->antenna_gain.ghz24.a3 = gain;
+	gain = r123_extract_antgain(out->revision, in,
+				    SSB_SPROM1_AGAIN_A,
+				    SSB_SPROM1_AGAIN_A_SHIFT);
+	out->antenna_gain.ghz5.a0 = gain;
+	out->antenna_gain.ghz5.a1 = gain;
+	out->antenna_gain.ghz5.a2 = gain;
+	out->antenna_gain.ghz5.a3 = gain;
 }
 
-static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in)
+static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in)
 {
 	int i;
 	u16 v;
 
-	SPEX(boardflags_hi, SSB_SPROM2_BFLHI,  0xFFFF, 0);
-	SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
-	SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
-	     SSB_SPROM2_MAXP_A_LO_SHIFT);
-	SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
-	SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
-	SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
-	SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
-	SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
-	SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
-	SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
-	for (i = 0; i < 4; i++) {
-		v = in[SPOFF(SSB_SPROM2_CCODE) + i];
-		*(((__le16 *)out->country_str) + i) = cpu_to_le16(v);
+	/* extract the equivalent of the r1 variables */
+	for (i = 0; i < 3; i++) {
+		v = in[SPOFF(SSB_SPROM4_IL0MAC) + i];
+		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
 	}
+	for (i = 0; i < 3; i++) {
+		v = in[SPOFF(SSB_SPROM4_ET0MAC) + i];
+		*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
+	}
+	for (i = 0; i < 3; i++) {
+		v = in[SPOFF(SSB_SPROM4_ET1MAC) + i];
+		*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
+	}
+	SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
+	SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
+	     SSB_SPROM4_ETHPHY_ET1A_SHIFT);
+	SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
+	SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
+	SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
+	SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
+	     SSB_SPROM4_ANTAVAIL_A_SHIFT);
+	SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
+	     SSB_SPROM4_ANTAVAIL_BG_SHIFT);
+	SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
+	SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
+	     SSB_SPROM4_ITSSI_BG_SHIFT);
+	SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
+	SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
+	     SSB_SPROM4_ITSSI_A_SHIFT);
+	SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
+	SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
+	     SSB_SPROM4_GPIOA_P1_SHIFT);
+	SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
+	SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
+	     SSB_SPROM4_GPIOB_P3_SHIFT);
+
+	/* Extract the antenna gain values. */
+	SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01,
+	     SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
+	SPEX(antenna_gain.ghz24.a1, SSB_SPROM4_AGAIN01,
+	     SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
+	SPEX(antenna_gain.ghz24.a2, SSB_SPROM4_AGAIN23,
+	     SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
+	SPEX(antenna_gain.ghz24.a3, SSB_SPROM4_AGAIN23,
+	     SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
+	memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
+	       sizeof(out->antenna_gain.ghz5));
+
+	/* TODO - get remaining rev 4 stuff needed */
 }
 
-static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in)
-{
-	out->ofdmapo  = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;
-	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;
-	out->ofdmapo <<= 16;
-	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;
-	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;
-
-	out->ofdmalpo  = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8;
-	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8;
-	out->ofdmalpo <<= 16;
-	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8;
-	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8;
-
-	out->ofdmahpo  = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8;
-	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8;
-	out->ofdmahpo <<= 16;
-	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8;
-	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8;
-
-	SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON,
-	     SSB_SPROM3_GPIOLDC_ON_SHIFT);
-	SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF,
-	     SSB_SPROM3_GPIOLDC_OFF_SHIFT);
-	SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0);
-	SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M,
-	     SSB_SPROM3_CCKPO_2M_SHIFT);
-	SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M,
-	     SSB_SPROM3_CCKPO_55M_SHIFT);
-	SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M,
-	     SSB_SPROM3_CCKPO_11M_SHIFT);
-
-	out->ofdmgpo  = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;
-	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;
-	out->ofdmgpo <<= 16;
-	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;
-	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;
-}
-
-static int sprom_extract(struct ssb_bus *bus,
-			 struct ssb_sprom *out, const u16 *in)
+static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
+			 const u16 *in, u16 size)
 {
 	memset(out, 0, sizeof(*out));
 
-	SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0);
-	SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC,
-	     SSB_SPROM_REVISION_CRC_SHIFT);
-
+	out->revision = in[size - 1] & 0x00FF;
+	ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
 	if ((bus->chip_id & 0xFF00) == 0x4400) {
 		/* Workaround: The BCM44XX chip has a stupid revision
 		 * number stored in the SPROM.
 		 * Always extract r1. */
-		sprom_extract_r1(&out->r1, in);
+		out->revision = 1;
+		sprom_extract_r123(out, in);
+	} else if (bus->chip_id == 0x4321) {
+		/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
+		out->revision = 4;
+		sprom_extract_r4(out, in);
 	} else {
 		if (out->revision == 0)
 			goto unsupported;
-		if (out->revision >= 1 && out->revision <= 3)
-			sprom_extract_r1(&out->r1, in);
-		if (out->revision >= 2 && out->revision <= 3)
-			sprom_extract_r2(&out->r2, in);
-		if (out->revision == 3)
-			sprom_extract_r3(&out->r3, in);
-		if (out->revision >= 4)
+		if (out->revision >= 1 && out->revision <= 3) {
+			sprom_extract_r123(out, in);
+		}
+		if (out->revision == 4)
+			sprom_extract_r4(out, in);
+		if (out->revision >= 5)
 			goto unsupported;
 	}
 
@@ -448,7 +486,7 @@ static int sprom_extract(struct ssb_bus *bus,
 unsupported:
 	ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
 		   "detected. Will extract v1\n", out->revision);
-	sprom_extract_r1(&out->r1, in);
+	sprom_extract_r123(out, in);
 	return 0;
 }
 
@@ -458,16 +496,29 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
 	int err = -ENOMEM;
 	u16 *buf;
 
-	buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+	buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
 	if (!buf)
 		goto out;
+	bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
 	sprom_do_read(bus, buf);
-	err = sprom_check_crc(buf);
+	err = sprom_check_crc(buf, bus->sprom_size);
 	if (err) {
-		ssb_printk(KERN_WARNING PFX
-			   "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
+		/* check for rev 4 sprom - has special signature */
+		if (buf[32] == 0x5372) {
+			kfree(buf);
+			buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+				      GFP_KERNEL);
+			if (!buf)
+				goto out;
+			bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
+			sprom_do_read(bus, buf);
+			err = sprom_check_crc(buf, bus->sprom_size);
+		}
+		if (err)
+			ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
+				   " SPROM CRC (corrupt SPROM)\n");
 	}
-	err = sprom_extract(bus, sprom, buf);
+	err = sprom_extract(bus, sprom, buf, bus->sprom_size);
 
 	kfree(buf);
 out:
@@ -581,29 +632,28 @@ const struct ssb_bus_ops ssb_pci_ops = {
 	.write32	= ssb_pci_write32,
 };
 
-static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
+static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size)
 {
 	int i, pos = 0;
 
-	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
+	for (i = 0; i < size; i++)
 		pos += snprintf(buf + pos, buf_len - pos - 1,
 				"%04X", swab16(sprom[i]) & 0xFFFF);
-	}
 	pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
 
 	return pos + 1;
 }
 
-static int hex2sprom(u16 *sprom, const char *dump, size_t len)
+static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size)
 {
 	char tmp[5] = { 0 };
 	int cnt = 0;
 	unsigned long parsed;
 
-	if (len < SSB_SPROMSIZE_BYTES * 2)
+	if (len < size * 2)
 		return -EINVAL;
 
-	while (cnt < SSB_SPROMSIZE_WORDS) {
+	while (cnt < size) {
 		memcpy(tmp, dump, 4);
 		dump += 4;
 		parsed = simple_strtoul(tmp, NULL, 16);
@@ -627,7 +677,7 @@ static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
 	if (!bus)
 		goto out;
 	err = -ENOMEM;
-	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+	sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
 	if (!sprom)
 		goto out;
 
@@ -640,7 +690,7 @@ static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
 	sprom_do_read(bus, sprom);
 	mutex_unlock(&bus->pci_sprom_mutex);
 
-	count = sprom2hex(sprom, buf, PAGE_SIZE);
+	count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size);
 	err = 0;
 
 out_kfree:
@@ -662,15 +712,15 @@ static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
 	if (!bus)
 		goto out;
 	err = -ENOMEM;
-	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+	sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
 	if (!sprom)
 		goto out;
-	err = hex2sprom(sprom, buf, count);
+	err = hex2sprom(sprom, buf, count, bus->sprom_size);
 	if (err) {
 		err = -EINVAL;
 		goto out_kfree;
 	}
-	err = sprom_check_crc(sprom);
+	err = sprom_check_crc(sprom, bus->sprom_size);
 	if (err) {
 		err = -EINVAL;
 		goto out_kfree;
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index bb44a76b3eb5..46816cda8b98 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -94,7 +94,6 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
 			   struct ssb_device *dev)
 {
 	int err;
-	unsigned long flags;
 
 #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
 	ssb_printk(KERN_INFO PFX
@@ -103,11 +102,9 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
 		   dev->core_index);
 #endif
 
-	spin_lock_irqsave(&bus->bar_lock, flags);
 	err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
 	if (!err)
 		bus->mapped_device = dev;
-	spin_unlock_irqrestore(&bus->bar_lock, flags);
 
 	return err;
 }
@@ -115,14 +112,12 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
 int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
 {
 	int attempts = 0;
-	unsigned long flags;
 	conf_reg_t reg;
-	int res, err = 0;
+	int res;
 
 	SSB_WARN_ON((seg != 0) && (seg != 1));
 	reg.Offset = 0x34;
 	reg.Function = 0;
-	spin_lock_irqsave(&bus->bar_lock, flags);
 	while (1) {
 		reg.Action = CS_WRITE;
 		reg.Value = seg;
@@ -143,13 +138,11 @@ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
 		udelay(10);
 	}
 	bus->mapped_pcmcia_seg = seg;
-out_unlock:
-	spin_unlock_irqrestore(&bus->bar_lock, flags);
-	return err;
+
+	return 0;
 error:
 	ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
-	err = -ENODEV;
-	goto out_unlock;
+	return -ENODEV;
 }
 
 static int select_core_and_segment(struct ssb_device *dev,
@@ -182,22 +175,33 @@ static int select_core_and_segment(struct ssb_device *dev,
 static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
 {
 	struct ssb_bus *bus = dev->bus;
+	unsigned long flags;
+	int err;
+	u16 value = 0xFFFF;
 
-	if (unlikely(select_core_and_segment(dev, &offset)))
-		return 0xFFFF;
+	spin_lock_irqsave(&bus->bar_lock, flags);
+	err = select_core_and_segment(dev, &offset);
+	if (likely(!err))
+		value = readw(bus->mmio + offset);
+	spin_unlock_irqrestore(&bus->bar_lock, flags);
 
-	return readw(bus->mmio + offset);
+	return value;
 }
 
 static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
 {
 	struct ssb_bus *bus = dev->bus;
-	u32 lo, hi;
+	unsigned long flags;
+	int err;
+	u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF;
 
-	if (unlikely(select_core_and_segment(dev, &offset)))
-		return 0xFFFFFFFF;
-	lo = readw(bus->mmio + offset);
-	hi = readw(bus->mmio + offset + 2);
+	spin_lock_irqsave(&bus->bar_lock, flags);
+	err = select_core_and_segment(dev, &offset);
+	if (likely(!err)) {
+		lo = readw(bus->mmio + offset);
+		hi = readw(bus->mmio + offset + 2);
+	}
+	spin_unlock_irqrestore(&bus->bar_lock, flags);
 
 	return (lo | (hi << 16));
 }
@@ -205,22 +209,31 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
 static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
 {
 	struct ssb_bus *bus = dev->bus;
+	unsigned long flags;
+	int err;
 
-	if (unlikely(select_core_and_segment(dev, &offset)))
-		return;
-	writew(value, bus->mmio + offset);
+	spin_lock_irqsave(&bus->bar_lock, flags);
+	err = select_core_and_segment(dev, &offset);
+	if (likely(!err))
+		writew(value, bus->mmio + offset);
+	mmiowb();
+	spin_unlock_irqrestore(&bus->bar_lock, flags);
 }
 
 static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
 {
 	struct ssb_bus *bus = dev->bus;
+	unsigned long flags;
+	int err;
 
-	if (unlikely(select_core_and_segment(dev, &offset)))
-		return;
-	writeb((value & 0xFF000000) >> 24, bus->mmio + offset + 3);
-	writeb((value & 0x00FF0000) >> 16, bus->mmio + offset + 2);
-	writeb((value & 0x0000FF00) >> 8, bus->mmio + offset + 1);
-	writeb((value & 0x000000FF) >> 0, bus->mmio + offset + 0);
+	spin_lock_irqsave(&bus->bar_lock, flags);
+	err = select_core_and_segment(dev, &offset);
+	if (likely(!err)) {
+		writew((value & 0x0000FFFF), bus->mmio + offset);
+		writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2);
+	}
+	mmiowb();
+	spin_unlock_irqrestore(&bus->bar_lock, flags);
 }
 
 /* Not "static", as it's used in main.c */
@@ -231,10 +244,12 @@ const struct ssb_bus_ops ssb_pcmcia_ops = {
 	.write32	= ssb_pcmcia_write32,
 };
 
+#include <linux/etherdevice.h>
 int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
 			      struct ssb_init_invariants *iv)
 {
 	//TODO
+	random_ether_addr(iv->sprom.il0mac);
 	return 0;
 }
 
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 865f32b63b5c..cc246faa3590 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -34,12 +34,12 @@ struct uio_device {
 	wait_queue_head_t	wait;
 	int			vma_count;
 	struct uio_info		*info;
-	struct kset 		map_attr_kset;
+	struct kobject		*map_dir;
 };
 
 static int uio_major;
 static DEFINE_IDR(uio_idr);
-static struct file_operations uio_fops;
+static const struct file_operations uio_fops;
 
 /* UIO class infrastructure */
 static struct uio_class {
@@ -51,47 +51,48 @@ static struct uio_class {
  * attributes
  */
 
-static struct attribute attr_addr = {
-	.name  = "addr",
-	.mode  = S_IRUGO,
+struct uio_map {
+	struct kobject kobj;
+	struct uio_mem *mem;
 };
+#define to_map(map) container_of(map, struct uio_map, kobj)
 
-static struct attribute attr_size = {
-	.name  = "size",
-	.mode  = S_IRUGO,
-};
 
-static struct attribute* map_attrs[] = {
-	&attr_addr, &attr_size, NULL
-};
-
-static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
+static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
 			     char *buf)
 {
-	struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj);
+	struct uio_map *map = to_map(kobj);
+	struct uio_mem *mem = map->mem;
 
-	if (strncmp(attr->name,"addr",4) == 0)
+	if (strncmp(attr->attr.name, "addr", 4) == 0)
 		return sprintf(buf, "0x%lx\n", mem->addr);
 
-	if (strncmp(attr->name,"size",4) == 0)
+	if (strncmp(attr->attr.name, "size", 4) == 0)
 		return sprintf(buf, "0x%lx\n", mem->size);
 
 	return -ENODEV;
 }
 
-static void map_attr_release(struct kobject *kobj)
-{
-	/* TODO ??? */
-}
+static struct kobj_attribute attr_attribute =
+	__ATTR(addr, S_IRUGO, map_attr_show, NULL);
+static struct kobj_attribute size_attribute =
+	__ATTR(size, S_IRUGO, map_attr_show, NULL);
 
-static struct sysfs_ops map_attr_ops = {
-	.show  = map_attr_show,
+static struct attribute *attrs[] = {
+	&attr_attribute.attr,
+	&size_attribute.attr,
+	NULL,	/* need to NULL terminate the list of attributes */
 };
 
+static void map_release(struct kobject *kobj)
+{
+	struct uio_map *map = to_map(kobj);
+	kfree(map);
+}
+
 static struct kobj_type map_attr_type = {
-	.release	= map_attr_release,
-	.sysfs_ops	= &map_attr_ops,
-	.default_attrs	= map_attrs,
+	.release	= map_release,
+	.default_attrs	= attrs,
 };
 
 static ssize_t show_name(struct device *dev,
@@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev)
 	int mi;
 	int map_found = 0;
 	struct uio_mem *mem;
+	struct uio_map *map;
 
 	ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
 	if (ret)
@@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev)
 			break;
 		if (!map_found) {
 			map_found = 1;
-			kobject_set_name(&idev->map_attr_kset.kobj,"maps");
-			idev->map_attr_kset.ktype = &map_attr_type;
-			idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
-			ret = kset_register(&idev->map_attr_kset);
-			if (ret)
-				goto err_remove_group;
+			idev->map_dir = kobject_create_and_add("maps",
+							&idev->dev->kobj);
+			if (!idev->map_dir)
+				goto err;
 		}
-		kobject_init(&mem->kobj);
-		kobject_set_name(&mem->kobj,"map%d",mi);
-		mem->kobj.parent = &idev->map_attr_kset.kobj;
-		mem->kobj.kset = &idev->map_attr_kset;
-		ret = kobject_add(&mem->kobj);
+		map = kzalloc(sizeof(*map), GFP_KERNEL);
+		if (!map)
+			goto err;
+		kobject_init(&map->kobj, &map_attr_type);
+		map->mem = mem;
+		mem->map = map;
+		ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi);
+		if (ret)
+			goto err;
+		ret = kobject_uevent(&map->kobj, KOBJ_ADD);
 		if (ret)
-			goto err_remove_maps;
+			goto err;
 	}
 
 	return 0;
 
-err_remove_maps:
+err:
 	for (mi--; mi>=0; mi--) {
 		mem = &idev->info->mem[mi];
-		kobject_unregister(&mem->kobj);
+		map = mem->map;
+		kobject_put(&map->kobj);
 	}
-	kset_unregister(&idev->map_attr_kset); /* Needed ? */
-err_remove_group:
+	kobject_put(idev->map_dir);
 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
 err_group:
 	dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
@@ -198,9 +203,9 @@ static void uio_dev_del_attributes(struct uio_device *idev)
 		mem = &idev->info->mem[mi];
 		if (mem->size == 0)
 			break;
-		kobject_unregister(&mem->kobj);
+		kobject_put(&mem->map->kobj);
 	}
-	kset_unregister(&idev->map_attr_kset);
+	kobject_put(idev->map_dir);
 	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
 }
 
@@ -503,7 +508,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
 	}
 }
 
-static struct file_operations uio_fops = {
+static const struct file_operations uio_fops = {
 	.owner		= THIS_MODULE,
 	.open		= uio_open,
 	.release	= uio_release,
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 7580aa5da0f8..7a6499008b89 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -33,6 +33,7 @@ config USB_ARCH_HAS_OHCI
 	default y if ARCH_LH7A404
 	default y if ARCH_S3C2410
 	default y if PXA27x
+	default y if PXA3xx
 	default y if ARCH_EP93XX
 	default y if ARCH_AT91
 	default y if ARCH_PNX4008
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index c51f8e9312e0..7c3aaa9c5402 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -91,8 +91,8 @@ static int usb_create_newid_file(struct usb_driver *usb_drv)
 		goto exit;
 
 	if (usb_drv->probe != NULL)
-		error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj,
-					  &driver_attr_new_id.attr);
+		error = driver_create_file(&usb_drv->drvwrap.driver,
+					   &driver_attr_new_id);
 exit:
 	return error;
 }
@@ -103,8 +103,8 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
 		return;
 
 	if (usb_drv->probe != NULL)
-		sysfs_remove_file(&usb_drv->drvwrap.driver.kobj,
-				  &driver_attr_new_id.attr);
+		driver_remove_file(&usb_drv->drvwrap.driver,
+				   &driver_attr_new_id);
 }
 
 static void usb_free_dynids(struct usb_driver *usb_drv)
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index f81d08d6538b..77a3759d6fc7 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -308,7 +308,7 @@ config USB_S3C2410_DEBUG
 
 config USB_GADGET_AT91
 	boolean "AT91 USB Device Port"
-	depends on ARCH_AT91 && !ARCH_AT91SAM9RL
+	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9
 	select USB_GADGET_SELECTED
 	help
 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index ecfe800fd720..ddd4ee1f2413 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -997,7 +997,7 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER		ohci_hcd_lh7a404_driver
 #endif
 
-#ifdef CONFIG_PXA27x
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
 #include "ohci-pxa27x.c"
 #define PLATFORM_DRIVER		ohci_hcd_pxa27x_driver
 #endif
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 5cfa3d1c4413..74e1f4be10bb 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -47,7 +47,7 @@
 #endif
 
 #ifdef CONFIG_TPS65010
-#include <asm/arch/tps65010.h>
+#include <linux/i2c/tps65010.h>
 #else
 
 #define LOW	0
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index ca2a6abbc117..6c52c66b659f 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -112,9 +112,9 @@ static int isp1301_detach(struct i2c_client *client);
 static int isp1301_command(struct i2c_client *client, unsigned int cmd,
 			   void *arg);
 
-static unsigned short normal_i2c[] =
+static const unsigned short normal_i2c[] =
     { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
-static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
+static const unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
 
 static struct i2c_client_address_data addr_data = {
 	.normal_i2c = normal_i2c,
@@ -123,7 +123,6 @@ static struct i2c_client_address_data addr_data = {
 };
 
 struct i2c_driver isp1301_driver = {
-	.id = I2C_DRIVERID_I2CDEV,	/* Fake Id */
 	.class = I2C_CLASS_HWMON,
 	.attach_adapter = isp1301_probe,
 	.detach_client = isp1301_detach,
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 23d2fe5a62f4..ff9a79843471 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -22,6 +22,7 @@
 #include <linux/device.h>
 #include <linux/signal.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 
 #include <asm/mach-types.h>
 #include <asm/hardware.h>
@@ -32,6 +33,8 @@
 
 #define UHCRHPS(x)              __REG2( 0x4C000050, (x)<<2 )
 
+static struct clk *usb_clk;
+
 /*
   PMM_NPS_MODE -- PMM Non-power switching mode
       Ports are powered continuously.
@@ -80,7 +83,7 @@ static int pxa27x_start_hc(struct device *dev)
 
 	inf = dev->platform_data;
 
-	pxa_set_cken(CKEN_USBHOST, 1);
+	clk_enable(usb_clk);
 
 	UHCHR |= UHCHR_FHR;
 	udelay(11);
@@ -123,7 +126,7 @@ static void pxa27x_stop_hc(struct device *dev)
 	UHCCOMS |= 1;
 	udelay(10);
 
-	pxa_set_cken(CKEN_USBHOST, 0);
+	clk_disable(usb_clk);
 }
 
 
@@ -158,6 +161,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
 		return -ENOMEM;
 	}
 
+	usb_clk = clk_get(&pdev->dev, "USBCLK");
+	if (IS_ERR(usb_clk))
+		return PTR_ERR(usb_clk);
+
 	hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x");
 	if (!hcd)
 		return -ENOMEM;
@@ -201,6 +208,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  err1:
 	usb_put_hcd(hcd);
+	clk_put(usb_clk);
 	return retval;
 }
 
@@ -225,6 +233,7 @@ void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
+	clk_put(usb_clk);
 }
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index 88aa59ab7563..f5a4e8d6a3b1 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -132,8 +132,7 @@ freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
 
 	/* Now transfer all of our blocks. */
 	US_DEBUGP("Start of read\n");
-	result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer,
-			count, srb->use_sg, &srb->resid);
+	result = usb_stor_bulk_srb(us, ipipe, srb);
 	US_DEBUGP("freecom_readdata done!\n");
 
 	if (result > USB_STOR_XFER_SHORT)
@@ -166,8 +165,7 @@ freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
 
 	/* Now transfer all of our blocks. */
 	US_DEBUGP("Start of write\n");
-	result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer,
-			count, srb->use_sg, &srb->resid);
+	result = usb_stor_bulk_srb(us, opipe, srb);
 
 	US_DEBUGP("freecom_writedata done!\n");
 	if (result > USB_STOR_XFER_SHORT)
@@ -281,7 +279,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
 	 * and such will hang. */
 	US_DEBUGP("Device indicates that it has %d bytes available\n",
 			le16_to_cpu (fst->Count));
-	US_DEBUGP("SCSI requested %d\n", srb->request_bufflen);
+	US_DEBUGP("SCSI requested %d\n", scsi_bufflen(srb));
 
 	/* Find the length we desire to read. */
 	switch (srb->cmnd[0]) {
@@ -292,12 +290,12 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
 			length = le16_to_cpu(fst->Count);
 			break;
 		default:
- 			length = srb->request_bufflen;
+			length = scsi_bufflen(srb);
 	}
 
 	/* verify that this amount is legal */
-	if (length > srb->request_bufflen) {
-		length = srb->request_bufflen;
+	if (length > scsi_bufflen(srb)) {
+		length = scsi_bufflen(srb);
 		US_DEBUGP("Truncating request to match buffer length: %d\n", length);
 	}
 
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index 49ba6c0ff1e8..0db488624ab1 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -49,6 +49,7 @@
 #include <linux/slab.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
+#include <linux/scatterlist.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -287,6 +288,7 @@ struct isd200_info {
 	/* maximum number of LUNs supported */
 	unsigned char MaxLUNs;
 	struct scsi_cmnd srb;
+	struct scatterlist sg;
 };
 
 
@@ -398,6 +400,31 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
  * Transport routines
  ***********************************************************************/
 
+/**************************************************************************
+ *  isd200_set_srb(), isd200_srb_set_bufflen()
+ *
+ * Two helpers to facilitate in initialization of scsi_cmnd structure
+ * Will need to change when struct scsi_cmnd changes
+ */
+static void isd200_set_srb(struct isd200_info *info,
+	enum dma_data_direction dir, void* buff, unsigned bufflen)
+{
+	struct scsi_cmnd *srb = &info->srb;
+
+	if (buff)
+		sg_init_one(&info->sg, buff, bufflen);
+
+	srb->sc_data_direction = dir;
+	srb->sdb.table.sgl = buff ? &info->sg : NULL;
+	srb->sdb.length = bufflen;
+	srb->sdb.table.nents = buff ? 1 : 0;
+}
+
+static void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen)
+{
+	srb->sdb.length = bufflen;
+}
+
 
 /**************************************************************************
  *  isd200_action
@@ -432,9 +459,7 @@ static int isd200_action( struct us_data *us, int action,
 		ata.generic.RegisterSelect =
 		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
 		  REG_STATUS | REG_ERROR;
-		srb->sc_data_direction = DMA_FROM_DEVICE;
-		srb->request_buffer = pointer;
-		srb->request_bufflen = value;
+		isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value);
 		break;
 
 	case ACTION_ENUM:
@@ -444,7 +469,7 @@ static int isd200_action( struct us_data *us, int action,
 					   ACTION_SELECT_5;
 		ata.generic.RegisterSelect = REG_DEVICE_HEAD;
 		ata.write.DeviceHeadByte = value;
-		srb->sc_data_direction = DMA_NONE;
+		isd200_set_srb(info, DMA_NONE, NULL, 0);
 		break;
 
 	case ACTION_RESET:
@@ -453,7 +478,7 @@ static int isd200_action( struct us_data *us, int action,
 					   ACTION_SELECT_3|ACTION_SELECT_4;
 		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
 		ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
-		srb->sc_data_direction = DMA_NONE;
+		isd200_set_srb(info, DMA_NONE, NULL, 0);
 		break;
 
 	case ACTION_REENABLE:
@@ -462,7 +487,7 @@ static int isd200_action( struct us_data *us, int action,
 					   ACTION_SELECT_3|ACTION_SELECT_4;
 		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
 		ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
-		srb->sc_data_direction = DMA_NONE;
+		isd200_set_srb(info, DMA_NONE, NULL, 0);
 		break;
 
 	case ACTION_SOFT_RESET:
@@ -471,21 +496,20 @@ static int isd200_action( struct us_data *us, int action,
 		ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
 		ata.write.DeviceHeadByte = info->DeviceHead;
 		ata.write.CommandByte = WIN_SRST;
-		srb->sc_data_direction = DMA_NONE;
+		isd200_set_srb(info, DMA_NONE, NULL, 0);
 		break;
 
 	case ACTION_IDENTIFY:
 		US_DEBUGP("   isd200_action(IDENTIFY)\n");
 		ata.generic.RegisterSelect = REG_COMMAND;
 		ata.write.CommandByte = WIN_IDENTIFY;
-		srb->sc_data_direction = DMA_FROM_DEVICE;
-		srb->request_buffer = (void *) info->id;
-		srb->request_bufflen = sizeof(struct hd_driveid);
+		isd200_set_srb(info, DMA_FROM_DEVICE, info->id,
+		                                sizeof(struct hd_driveid));
 		break;
 
 	default:
 		US_DEBUGP("Error: Undefined action %d\n",action);
-		break;
+		return ISD200_ERROR;
 	}
 
 	memcpy(srb->cmnd, &ata, sizeof(ata.generic));
@@ -590,7 +614,7 @@ static void isd200_invoke_transport( struct us_data *us,
 		return;
 	}
 
-	if ((srb->resid > 0) &&
+	if ((scsi_get_resid(srb) > 0) &&
 	    !((srb->cmnd[0] == REQUEST_SENSE) ||
 	      (srb->cmnd[0] == INQUIRY) ||
 	      (srb->cmnd[0] == MODE_SENSE) ||
@@ -1217,7 +1241,6 @@ static int isd200_get_inquiry_data( struct us_data *us )
 	return(retStatus);
 }
 
-
 /**************************************************************************
  * isd200_scsi_to_ata
  *									 
@@ -1266,7 +1289,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
 			ataCdb->generic.TransferBlockSize = 1;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
-			srb->request_bufflen = 0;
+			isd200_srb_set_bufflen(srb, 0);
 		} else {
 			US_DEBUGP("   Media Status not supported, just report okay\n");
 			srb->result = SAM_STAT_GOOD;
@@ -1284,7 +1307,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
 			ataCdb->generic.TransferBlockSize = 1;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
-			srb->request_bufflen = 0;
+			isd200_srb_set_bufflen(srb, 0);
 		} else {
 			US_DEBUGP("   Media Status not supported, just report okay\n");
 			srb->result = SAM_STAT_GOOD;
@@ -1390,7 +1413,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
 			ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
 				WIN_DOORLOCK : WIN_DOORUNLOCK;
-			srb->request_bufflen = 0;
+			isd200_srb_set_bufflen(srb, 0);
 		} else {
 			US_DEBUGP("   Not removeable media, just report okay\n");
 			srb->result = SAM_STAT_GOOD;
@@ -1416,7 +1439,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
 			ataCdb->generic.TransferBlockSize = 1;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
 			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
-			srb->request_bufflen = 0;
+			isd200_srb_set_bufflen(srb, 0);
 		} else {
 			US_DEBUGP("   Nothing to do, just report okay\n");
 			srb->result = SAM_STAT_GOOD;
@@ -1525,7 +1548,7 @@ int isd200_Initialization(struct us_data *us)
 
 void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
 {
-	int sendToTransport = 1;
+	int sendToTransport = 1, orig_bufflen;
 	union ata_cdb ataCdb;
 
 	/* Make sure driver was initialized */
@@ -1533,11 +1556,14 @@ void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
 	if (us->extra == NULL)
 		US_DEBUGP("ERROR Driver not initialized\n");
 
-	/* Convert command */
-	srb->resid = 0;
+	scsi_set_resid(srb, 0);
+	/* scsi_bufflen might change in protocol translation to ata */
+	orig_bufflen = scsi_bufflen(srb);
 	sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb);
 
 	/* send the command to the transport layer */
 	if (sendToTransport)
 		isd200_invoke_transport(us, srb, &ataCdb);
+
+	isd200_srb_set_bufflen(srb, orig_bufflen);
 }
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 889622baac20..a41ce21c0697 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -149,11 +149,7 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
  ***********************************************************************/
 
 /* Copy a buffer of length buflen to/from the srb's transfer buffer.
- * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
- * points to a list of s-g entries and we ignore srb->request_bufflen.
- * For non-scatter-gather transfers, srb->request_buffer points to the
- * transfer buffer itself and srb->request_bufflen is the buffer's length.)
- * Update the *index and *offset variables so that the next copy will
+ * Update the **sgptr and *offset variables so that the next copy will
  * pick up from where this one left off. */
 
 unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
@@ -162,80 +158,64 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
 {
 	unsigned int cnt;
 
-	/* If not using scatter-gather, just transfer the data directly.
-	 * Make certain it will fit in the available buffer space. */
-	if (srb->use_sg == 0) {
-		if (*offset >= srb->request_bufflen)
-			return 0;
-		cnt = min(buflen, srb->request_bufflen - *offset);
-		if (dir == TO_XFER_BUF)
-			memcpy((unsigned char *) srb->request_buffer + *offset,
-					buffer, cnt);
-		else
-			memcpy(buffer, (unsigned char *) srb->request_buffer +
-					*offset, cnt);
-		*offset += cnt;
-
-	/* Using scatter-gather.  We have to go through the list one entry
+	/* We have to go through the list one entry
 	 * at a time.  Each s-g entry contains some number of pages, and
 	 * each page has to be kmap()'ed separately.  If the page is already
 	 * in kernel-addressable memory then kmap() will return its address.
 	 * If the page is not directly accessible -- such as a user buffer
 	 * located in high memory -- then kmap() will map it to a temporary
 	 * position in the kernel's virtual address space. */
-	} else {
-		struct scatterlist *sg = *sgptr;
-
-		if (!sg)
-			sg = (struct scatterlist *) srb->request_buffer;
-
-		/* This loop handles a single s-g list entry, which may
-		 * include multiple pages.  Find the initial page structure
-		 * and the starting offset within the page, and update
-		 * the *offset and *index values for the next loop. */
-		cnt = 0;
-		while (cnt < buflen) {
-			struct page *page = sg_page(sg) +
-					((sg->offset + *offset) >> PAGE_SHIFT);
-			unsigned int poff =
-					(sg->offset + *offset) & (PAGE_SIZE-1);
-			unsigned int sglen = sg->length - *offset;
-
-			if (sglen > buflen - cnt) {
-
-				/* Transfer ends within this s-g entry */
-				sglen = buflen - cnt;
-				*offset += sglen;
-			} else {
-
-				/* Transfer continues to next s-g entry */
-				*offset = 0;
-				sg = sg_next(sg);
-			}
-
-			/* Transfer the data for all the pages in this
-			 * s-g entry.  For each page: call kmap(), do the
-			 * transfer, and call kunmap() immediately after. */
-			while (sglen > 0) {
-				unsigned int plen = min(sglen, (unsigned int)
-						PAGE_SIZE - poff);
-				unsigned char *ptr = kmap(page);
-
-				if (dir == TO_XFER_BUF)
-					memcpy(ptr + poff, buffer + cnt, plen);
-				else
-					memcpy(buffer + cnt, ptr + poff, plen);
-				kunmap(page);
-
-				/* Start at the beginning of the next page */
-				poff = 0;
-				++page;
-				cnt += plen;
-				sglen -= plen;
-			}
+	struct scatterlist *sg = *sgptr;
+
+	if (!sg)
+		sg = scsi_sglist(srb);
+
+	/* This loop handles a single s-g list entry, which may
+		* include multiple pages.  Find the initial page structure
+		* and the starting offset within the page, and update
+		* the *offset and **sgptr values for the next loop. */
+	cnt = 0;
+	while (cnt < buflen) {
+		struct page *page = sg_page(sg) +
+				((sg->offset + *offset) >> PAGE_SHIFT);
+		unsigned int poff =
+				(sg->offset + *offset) & (PAGE_SIZE-1);
+		unsigned int sglen = sg->length - *offset;
+
+		if (sglen > buflen - cnt) {
+
+			/* Transfer ends within this s-g entry */
+			sglen = buflen - cnt;
+			*offset += sglen;
+		} else {
+
+			/* Transfer continues to next s-g entry */
+			*offset = 0;
+			sg = sg_next(sg);
+		}
+
+		/* Transfer the data for all the pages in this
+			* s-g entry.  For each page: call kmap(), do the
+			* transfer, and call kunmap() immediately after. */
+		while (sglen > 0) {
+			unsigned int plen = min(sglen, (unsigned int)
+					PAGE_SIZE - poff);
+			unsigned char *ptr = kmap(page);
+
+			if (dir == TO_XFER_BUF)
+				memcpy(ptr + poff, buffer + cnt, plen);
+			else
+				memcpy(buffer + cnt, ptr + poff, plen);
+			kunmap(page);
+
+			/* Start at the beginning of the next page */
+			poff = 0;
+			++page;
+			cnt += plen;
+			sglen -= plen;
 		}
-		*sgptr = sg;
 	}
+	*sgptr = sg;
 
 	/* Return the amount actually transferred */
 	return cnt;
@@ -251,6 +231,6 @@ void usb_stor_set_xfer_buf(unsigned char *buffer,
 
 	usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
 			TO_XFER_BUF);
-	if (buflen < srb->request_bufflen)
-		srb->resid = srb->request_bufflen - buflen;
+	if (buflen < scsi_bufflen(srb))
+		scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
 }
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 7c9593b7b04e..8c1e2954f3b9 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -81,6 +81,16 @@ static int slave_alloc (struct scsi_device *sdev)
 	 */
 	sdev->inquiry_len = 36;
 
+	/* Scatter-gather buffers (all but the last) must have a length
+	 * divisible by the bulk maxpacket size.  Otherwise a data packet
+	 * would end up being short, causing a premature end to the data
+	 * transfer.  Since high-speed bulk pipes have a maxpacket size
+	 * of 512, we'll use that as the scsi device queue's DMA alignment
+	 * mask.  Guaranteeing proper alignment of the first buffer will
+	 * have the desired effect because, except at the beginning and
+	 * the end, scatter-gather buffers follow page boundaries. */
+	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
+
 	/*
 	 * The UFI spec treates the Peripheral Qualifier bits in an
 	 * INQUIRY result as reserved and requires devices to set them
@@ -100,16 +110,6 @@ static int slave_configure(struct scsi_device *sdev)
 {
 	struct us_data *us = host_to_us(sdev->host);
 
-	/* Scatter-gather buffers (all but the last) must have a length
-	 * divisible by the bulk maxpacket size.  Otherwise a data packet
-	 * would end up being short, causing a premature end to the data
-	 * transfer.  Since high-speed bulk pipes have a maxpacket size
-	 * of 512, we'll use that as the scsi device queue's DMA alignment
-	 * mask.  Guaranteeing proper alignment of the first buffer will
-	 * have the desired effect because, except at the beginning and
-	 * the end, scatter-gather buffers follow page boundaries. */
-	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
-
 	/* Many devices have trouble transfering more than 32KB at a time,
 	 * while others have trouble with more than 64K. At this time we
 	 * are limiting both to 32K (64 sectores).
@@ -187,6 +187,10 @@ static int slave_configure(struct scsi_device *sdev)
 		 * automatically, requiring a START-STOP UNIT command. */
 		sdev->allow_restart = 1;
 
+		/* Some USB cardreaders have trouble reading an sdcard's last
+		 * sector in a larger then 1 sector read, since the performance
+		 * impact is negible we set this flag for all USB disks */
+		sdev->last_sector_bug = 1;
 	} else {
 
 		/* Non-disk-type devices don't need to blacklist any pages
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index b12202c5da2d..8972b17da843 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -1623,7 +1623,7 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
-	if (srb->request_bufflen == 0)
+	if (scsi_bufflen(srb) == 0)
 		return USB_STOR_TRANSPORT_GOOD;
 
 	if (srb->sc_data_direction == DMA_TO_DEVICE ||
@@ -1634,12 +1634,9 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
 		US_DEBUGP("SDDR09: %s %d bytes\n",
 			  (srb->sc_data_direction == DMA_TO_DEVICE) ?
 			  "sending" : "receiving",
-			  srb->request_bufflen);
+			  scsi_bufflen(srb));
 
-		result = usb_stor_bulk_transfer_sg(us, pipe,
-					srb->request_buffer,
-					srb->request_bufflen,
-					srb->use_sg, &srb->resid);
+		result = usb_stor_bulk_srb(us, pipe, srb);
 
 		return (result == USB_STOR_XFER_GOOD ?
 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index cb22a9ad1694..570c1250f6f3 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -130,7 +130,7 @@ static int usbat_write(struct us_data *us,
  * Convenience function to perform a bulk read
  */
 static int usbat_bulk_read(struct us_data *us,
-			   unsigned char *data,
+			   void* buf,
 			   unsigned int len,
 			   int use_sg)
 {
@@ -138,14 +138,14 @@ static int usbat_bulk_read(struct us_data *us,
 		return USB_STOR_XFER_GOOD;
 
 	US_DEBUGP("usbat_bulk_read: len = %d\n", len);
-	return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, data, len, use_sg, NULL);
+	return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL);
 }
 
 /*
  * Convenience function to perform a bulk write
  */
 static int usbat_bulk_write(struct us_data *us,
-			    unsigned char *data,
+			    void* buf,
 			    unsigned int len,
 			    int use_sg)
 {
@@ -153,7 +153,7 @@ static int usbat_bulk_write(struct us_data *us,
 		return USB_STOR_XFER_GOOD;
 
 	US_DEBUGP("usbat_bulk_write:  len = %d\n", len);
-	return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, data, len, use_sg, NULL);
+	return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL);
 }
 
 /*
@@ -314,7 +314,7 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
  * Read block data from the data register
  */
 static int usbat_read_block(struct us_data *us,
-			    unsigned char *content,
+			    void* buf,
 			    unsigned short len,
 			    int use_sg)
 {
@@ -337,7 +337,7 @@ static int usbat_read_block(struct us_data *us,
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	result = usbat_bulk_read(us, content, len, use_sg);
+	result = usbat_bulk_read(us, buf, len, use_sg);
 	return (result == USB_STOR_XFER_GOOD ?
 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
 }
@@ -347,7 +347,7 @@ static int usbat_read_block(struct us_data *us,
  */
 static int usbat_write_block(struct us_data *us,
 			     unsigned char access,
-			     unsigned char *content,
+			     void* buf,
 			     unsigned short len,
 			     int minutes,
 			     int use_sg)
@@ -372,7 +372,7 @@ static int usbat_write_block(struct us_data *us,
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	result = usbat_bulk_write(us, content, len, use_sg);
+	result = usbat_bulk_write(us, buf, len, use_sg);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
@@ -392,7 +392,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
 				       unsigned char timeout,
 				       unsigned char qualifier,
 				       int direction,
-				       unsigned char *content,
+				       void *buf,
 				       unsigned short len,
 				       int use_sg,
 				       int minutes)
@@ -472,7 +472,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
 		}
 
 		result = usb_stor_bulk_transfer_sg(us,
-			pipe, content, len, use_sg, NULL);
+			pipe, buf, len, use_sg, NULL);
 
 		/*
 		 * If we get a stall on the bulk download, we'll retry
@@ -606,7 +606,7 @@ static int usbat_multiple_write(struct us_data *us,
  * other related details) are defined beforehand with _set_shuttle_features().
  */
 static int usbat_read_blocks(struct us_data *us,
-			     unsigned char *buffer,
+			     void* buffer,
 			     int len,
 			     int use_sg)
 {
@@ -648,7 +648,7 @@ static int usbat_read_blocks(struct us_data *us,
  * other related details) are defined beforehand with _set_shuttle_features().
  */
 static int usbat_write_blocks(struct us_data *us,
-							  unsigned char *buffer,
+			      void* buffer,
 			      int len,
 			      int use_sg)
 {
@@ -1170,15 +1170,15 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
 	US_DEBUGP("handle_read10: transfersize %d\n",
 		srb->transfersize);
 
-	if (srb->request_bufflen < 0x10000) {
+	if (scsi_bufflen(srb) < 0x10000) {
 
 		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
 			registers, data, 19,
 			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
 			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
 			DMA_FROM_DEVICE,
-			srb->request_buffer, 
-			srb->request_bufflen, srb->use_sg, 1);
+			scsi_sglist(srb),
+			scsi_bufflen(srb), scsi_sg_count(srb), 1);
 
 		return result;
 	}
@@ -1196,7 +1196,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
 		len <<= 16;
 		len |= data[7+7];
 		US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len);
-		srb->transfersize = srb->request_bufflen/len;
+		srb->transfersize = scsi_bufflen(srb)/len;
 	}
 
 	if (!srb->transfersize)  {
@@ -1213,7 +1213,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
 
 	len = (65535/srb->transfersize) * srb->transfersize;
 	US_DEBUGP("Max read is %d bytes\n", len);
-	len = min(len, srb->request_bufflen);
+	len = min(len, scsi_bufflen(srb));
 	buffer = kmalloc(len, GFP_NOIO);
 	if (buffer == NULL) /* bloody hell! */
 		return USB_STOR_TRANSPORT_FAILED;
@@ -1222,10 +1222,10 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
 	sector |= short_pack(data[7+5], data[7+4]);
 	transferred = 0;
 
-	while (transferred != srb->request_bufflen) {
+	while (transferred != scsi_bufflen(srb)) {
 
-		if (len > srb->request_bufflen - transferred)
-			len = srb->request_bufflen - transferred;
+		if (len > scsi_bufflen(srb) - transferred)
+			len = scsi_bufflen(srb) - transferred;
 
 		data[3] = len&0xFF; 	  /* (cylL) = expected length (L) */
 		data[4] = (len>>8)&0xFF;  /* (cylH) = expected length (H) */
@@ -1261,7 +1261,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
 		transferred += len;
 		sector += len / srb->transfersize;
 
-	} /* while transferred != srb->request_bufflen */
+	} /* while transferred != scsi_bufflen(srb) */
 
 	kfree(buffer);
 	return result;
@@ -1429,9 +1429,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
 	unsigned char data[32];
 	unsigned int len;
 	int i;
-	char string[64];
 
-	len = srb->request_bufflen;
+	len = scsi_bufflen(srb);
 
 	/* Send A0 (ATA PACKET COMMAND).
 	   Note: I guess we're never going to get any of the ATA
@@ -1472,8 +1471,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
 			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
 			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
 			DMA_TO_DEVICE,
-			srb->request_buffer, 
-			len, srb->use_sg, 10);
+			scsi_sglist(srb),
+			len, scsi_sg_count(srb), 10);
 
 		if (result == USB_STOR_TRANSPORT_GOOD) {
 			transferred += len;
@@ -1540,23 +1539,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
 			len = *status;
 
 
-		result = usbat_read_block(us, srb->request_buffer, len, srb->use_sg);
-
-		/* Debug-print the first 32 bytes of the transfer */
-
-		if (!srb->use_sg) {
-			string[0] = 0;
-			for (i=0; i<len && i<32; i++) {
-				sprintf(string+strlen(string), "%02X ",
-				  ((unsigned char *)srb->request_buffer)[i]);
-				if ((i%16)==15) {
-					US_DEBUGP("%s\n", string);
-					string[0] = 0;
-				}
-			}
-			if (string[0]!=0)
-				US_DEBUGP("%s\n", string);
-		}
+		result = usbat_read_block(us, scsi_sglist(srb), len,
+			                                   scsi_sg_count(srb));
 	}
 
 	return result;
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index c646750ccc30..d9f4912f873d 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -459,6 +459,22 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
 }
 
 /*
+ * Common used function. Transfer a complete command
+ * via usb_stor_bulk_transfer_sglist() above. Set cmnd resid
+ */
+int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
+		      struct scsi_cmnd* srb)
+{
+	unsigned int partial;
+	int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb),
+				      scsi_sg_count(srb), scsi_bufflen(srb),
+				      &partial);
+
+	scsi_set_resid(srb, scsi_bufflen(srb) - partial);
+	return result;
+}
+
+/*
  * Transfer an entire SCSI command's worth of data payload over the bulk
  * pipe.
  *
@@ -508,7 +524,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 	int result;
 
 	/* send the command to the transport layer */
-	srb->resid = 0;
+	scsi_set_resid(srb, 0);
 	result = us->transport(srb, us);
 
 	/* if the command gets aborted by the higher layers, we need to
@@ -568,7 +584,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 	 * A short transfer on a command where we don't expect it
 	 * is unusual, but it doesn't mean we need to auto-sense.
 	 */
-	if ((srb->resid > 0) &&
+	if ((scsi_get_resid(srb) > 0) &&
 	    !((srb->cmnd[0] == REQUEST_SENSE) ||
 	      (srb->cmnd[0] == INQUIRY) ||
 	      (srb->cmnd[0] == MODE_SENSE) ||
@@ -593,7 +609,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 			srb->cmd_len = 12;
 
 		/* issue the auto-sense command */
-		srb->resid = 0;
+		scsi_set_resid(srb, 0);
 		temp_result = us->transport(us->srb, us);
 
 		/* let's clean up right away */
@@ -649,7 +665,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 
 	/* Did we transfer less than the minimum amount required? */
 	if (srb->result == SAM_STAT_GOOD &&
-			srb->request_bufflen - srb->resid < srb->underflow)
+			scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
 		srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
 
 	return;
@@ -708,7 +724,7 @@ void usb_stor_stop_transport(struct us_data *us)
 
 int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
-	unsigned int transfer_length = srb->request_bufflen;
+	unsigned int transfer_length = scsi_bufflen(srb);
 	unsigned int pipe = 0;
 	int result;
 
@@ -737,9 +753,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
 	if (transfer_length) {
 		pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
 				us->recv_bulk_pipe : us->send_bulk_pipe;
-		result = usb_stor_bulk_transfer_sg(us, pipe,
-					srb->request_buffer, transfer_length,
-					srb->use_sg, &srb->resid);
+		result = usb_stor_bulk_srb(us, pipe, srb);
 		US_DEBUGP("CBI data stage result is 0x%x\n", result);
 
 		/* if we stalled the data transfer it means command failed */
@@ -808,7 +822,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
  */
 int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
-	unsigned int transfer_length = srb->request_bufflen;
+	unsigned int transfer_length = scsi_bufflen(srb);
 	int result;
 
 	/* COMMAND STAGE */
@@ -836,9 +850,7 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
 	if (transfer_length) {
 		unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
 				us->recv_bulk_pipe : us->send_bulk_pipe;
-		result = usb_stor_bulk_transfer_sg(us, pipe,
-					srb->request_buffer, transfer_length,
-					srb->use_sg, &srb->resid);
+		result = usb_stor_bulk_srb(us, pipe, srb);
 		US_DEBUGP("CB data stage result is 0x%x\n", result);
 
 		/* if we stalled the data transfer it means command failed */
@@ -904,7 +916,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
 	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
-	unsigned int transfer_length = srb->request_bufflen;
+	unsigned int transfer_length = scsi_bufflen(srb);
 	unsigned int residue;
 	int result;
 	int fake_sense = 0;
@@ -955,9 +967,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
 	if (transfer_length) {
 		unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
 				us->recv_bulk_pipe : us->send_bulk_pipe;
-		result = usb_stor_bulk_transfer_sg(us, pipe,
-					srb->request_buffer, transfer_length,
-					srb->use_sg, &srb->resid);
+		result = usb_stor_bulk_srb(us, pipe, srb);
 		US_DEBUGP("Bulk data transfer result 0x%x\n", result);
 		if (result == USB_STOR_XFER_ERROR)
 			return USB_STOR_TRANSPORT_ERROR;
@@ -1036,7 +1046,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
 	if (residue) {
 		if (!(us->flags & US_FL_IGNORE_RESIDUE)) {
 			residue = min(residue, transfer_length);
-			srb->resid = max(srb->resid, (int) residue);
+			scsi_set_resid(srb, max(scsi_get_resid(srb),
+			                                       (int) residue));
 		}
 	}
 
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index 633a715850a4..ada7c2f43f84 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -139,6 +139,8 @@ extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
 		void *buf, unsigned int length, unsigned int *act_len);
 extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
 		void *buf, unsigned int length, int use_sg, int *residual);
+extern int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe,
+		struct scsi_cmnd* srb);
 
 extern int usb_stor_port_reset(struct us_data *us);
 #endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5b3dbcfcda48..758435f8a6f8 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -889,7 +889,7 @@ config FB_S1D13XXX
 
 config FB_ATMEL
 	tristate "AT91/AT32 LCD Controller support"
-	depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32)
+	depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || AVR32)
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 7c30cc8df71e..f8e711147501 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -30,7 +30,7 @@
 #define ATMEL_LCDC_CVAL_DEFAULT		0xc8
 #define ATMEL_LCDC_DMA_BURST_LEN	8
 
-#if defined(CONFIG_ARCH_AT91SAM9263)
+#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9)
 #define ATMEL_LCDC_FIFO_SIZE		2048
 #else
 #define ATMEL_LCDC_FIFO_SIZE		512
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index 74d11c318987..c8e7427a0bc8 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -224,7 +224,8 @@ static int config_dma(struct bfin_bf54xfb_info *fbi)
 	set_dma_config(CH_EPPI0,
 		       set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
 					   INTR_DISABLE, DIMENSION_2D,
-					   DATA_SIZE_32));
+					   DATA_SIZE_32,
+					   DMA_NOSYNC_KEEP_DMA_BUF));
 	set_dma_x_count(CH_EPPI0, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
 	set_dma_x_modify(CH_EPPI0, DMA_BUS_SIZE / 8);
 	set_dma_y_count(CH_EPPI0, LCD_Y_RES);
@@ -263,8 +264,7 @@ static int request_ports(struct bfin_bf54xfb_info *fbi)
 		}
 	}
 
-	gpio_direction_output(disp);
-	gpio_set_value(disp, 1);
+	gpio_direction_output(disp, 1);
 
 	return 0;
 }
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index b87ed37ac0c1..2b53d1f56281 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -6,7 +6,7 @@ menu "Console display driver support"
 
 config VGA_CONSOLE
 	bool "VGA text console" if EMBEDDED || !X86
-	depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN
+	depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32
 	default y
 	help
 	  Saying Y here will allow you to use Linux in text mode through a
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index 49cd53e46c0a..0cd58f84fb46 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -1232,7 +1232,7 @@ static int maven_shutdown_client(struct i2c_client* clnt) {
 	return 0;
 }
 
-static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
 I2C_CLIENT_INSMOD;
 
 static struct i2c_driver maven_driver;
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
index c604d935c188..31e978349a80 100644
--- a/drivers/video/omap/lcd_h3.c
+++ b/drivers/video/omap/lcd_h3.c
@@ -21,9 +21,9 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/i2c/tps65010.h>
 
 #include <asm/arch/gpio.h>
-#include <asm/arch/tps65010.h>
 #include <asm/arch/omapfb.h>
 
 #define MODULE_NAME	"omapfb-lcd_h3"
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
index c31f549ebea0..1c656667b937 100644
--- a/drivers/video/vermilion/vermilion.c
+++ b/drivers/video/vermilion/vermilion.c
@@ -88,9 +88,7 @@ static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order,
 {
 	gfp_t flags;
 	unsigned long i;
-	pgprot_t wc_pageprot;
 
-	wc_pageprot = PAGE_KERNEL_NOCACHE;
 	max_order++;
 	do {
 		/*
@@ -126,14 +124,8 @@ static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order,
 	/*
 	 * Change caching policy of the linear kernel map to avoid
 	 * mapping type conflicts with user-space mappings.
-	 * The first global_flush_tlb() is really only there to do a global
-	 * wbinvd().
 	 */
-
-	global_flush_tlb();
-	change_page_attr(virt_to_page(va->logical), va->size >> PAGE_SHIFT,
-			 wc_pageprot);
-	global_flush_tlb();
+	set_pages_uc(virt_to_page(va->logical), va->size >> PAGE_SHIFT);
 
 	printk(KERN_DEBUG MODULE_NAME
 	       ": Allocated %ld bytes vram area at 0x%08lx\n",
@@ -157,9 +149,8 @@ static void vmlfb_free_vram_area(struct vram_area *va)
 		 * Reset the linear kernel map caching policy.
 		 */
 
-		change_page_attr(virt_to_page(va->logical),
-				 va->size >> PAGE_SHIFT, PAGE_KERNEL);
-		global_flush_tlb();
+		set_pages_wb(virt_to_page(va->logical),
+				 va->size >> PAGE_SHIFT);
 
 		/*
 		 * Decrease the usage count on the pages we've used
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index d93eb626b2f0..0fd5820d5c61 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -29,7 +29,7 @@
  * However, the chip cannot be detected without doing an i2c write,
  * so use the force module parameter.
  */
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 /**
  * Insmod parameters
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 52dff40ec192..afcdc69e37d6 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -223,7 +223,7 @@ config DAVINCI_WATCHDOG
 
 config AT32AP700X_WDT
 	tristate "AT32AP700x watchdog"
-	depends on CPU_AT32AP7000
+	depends on CPU_AT32AP700X
 	help
 	  Watchdog timer embedded into AT32AP700x devices. This will reboot
 	  your system when the timeout is reached.
@@ -609,7 +609,7 @@ config SBC_EPX_C3_WATCHDOG
 
 config INDYDOG
 	tristate "Indy/I2 Hardware Watchdog"
-	depends on SGI_IP22
+	depends on SGI_HAS_INDYDOG
 	help
 	  Hardware driver for the Indy's/I2's watchdog. This is a
 	  watchdog timer that will reboot the machine after a 60 second
@@ -639,6 +639,12 @@ config AR7_WDT
 	help
 	  Hardware driver for the TI AR7 Watchdog Timer.
 
+config TXX9_WDT
+	tristate "Toshiba TXx9 Watchdog Timer"
+	depends on CPU_TX39XX || CPU_TX49XX
+	help
+	  Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
+
 # PARISC Architecture
 
 # POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 87483cc63252..ebc21146d40c 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -93,6 +93,7 @@ obj-$(CONFIG_INDYDOG) += indydog.o
 obj-$(CONFIG_WDT_MTX1)	+= mtx-1_wdt.o
 obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
 obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
+obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
 
 # PARISC Architecture
 
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index b481cc0e32e4..2b1fbdb2fcf7 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -413,18 +413,18 @@ static int __init watchdog_init(void)
 	/* Calculate the watchdog's timeout */
 	ali_settimer(timeout);
 
-	ret = misc_register(&ali_miscdev);
+	ret = register_reboot_notifier(&ali_notifier);
 	if (ret != 0) {
-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-			WATCHDOG_MINOR, ret);
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
 		goto out;
 	}
 
-	ret = register_reboot_notifier(&ali_notifier);
+	ret = misc_register(&ali_miscdev);
 	if (ret != 0) {
-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
-			ret);
-		goto unreg_miscdev;
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto unreg_reboot;
 	}
 
 	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
@@ -432,8 +432,8 @@ static int __init watchdog_init(void)
 
 out:
 	return ret;
-unreg_miscdev:
-	misc_deregister(&ali_miscdev);
+unreg_reboot:
+	unregister_reboot_notifier(&ali_notifier);
 	goto out;
 }
 
@@ -449,8 +449,8 @@ static void __exit watchdog_exit(void)
 	ali_stop();
 
 	/* Deregister */
-	unregister_reboot_notifier(&ali_notifier);
 	misc_deregister(&ali_miscdev);
+	unregister_reboot_notifier(&ali_notifier);
 	pci_dev_put(ali_pci);
 }
 
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index 67aed9f8c362..238273c98656 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -377,18 +377,18 @@ static int __init alim7101_wdt_init(void)
 			timeout);
 	}
 
-	rc = misc_register(&wdt_miscdev);
+	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc) {
-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-			wdt_miscdev.minor, rc);
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			rc);
 		goto err_out;
 	}
 
-	rc = register_reboot_notifier(&wdt_notifier);
+	rc = misc_register(&wdt_miscdev);
 	if (rc) {
-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
-			rc);
-		goto err_out_miscdev;
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			wdt_miscdev.minor, rc);
+		goto err_out_reboot;
 	}
 
 	if (nowayout) {
@@ -399,8 +399,8 @@ static int __init alim7101_wdt_init(void)
 		timeout, nowayout);
 	return 0;
 
-err_out_miscdev:
-	misc_deregister(&wdt_miscdev);
+err_out_reboot:
+	unregister_reboot_notifier(&wdt_notifier);
 err_out:
 	pci_dev_put(alim7101_pmu);
 	return rc;
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index cdaab8c3d3d0..2eb48c0df32c 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -279,7 +279,7 @@ static int ar7_wdt_ioctl(struct inode *inode, struct file *file,
 	}
 }
 
-static struct file_operations ar7_wdt_fops = {
+static const struct file_operations ar7_wdt_fops = {
 	.owner		= THIS_MODULE,
 	.write		= ar7_wdt_write,
 	.ioctl		= ar7_wdt_ioctl,
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index 31dc7a69e90c..472be10f0686 100644
--- a/drivers/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
@@ -390,7 +390,7 @@ static struct platform_driver bfin_wdt_driver = {
 	.resume    = bfin_wdt_resume,
 };
 
-static struct file_operations bfin_wdt_fops = {
+static const struct file_operations bfin_wdt_fops = {
 	.owner    = THIS_MODULE,
 	.llseek   = no_llseek,
 	.write    = bfin_wdt_write,
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
index 6330fc02464e..1b6d7d1b715d 100644
--- a/drivers/watchdog/it8712f_wdt.c
+++ b/drivers/watchdog/it8712f_wdt.c
@@ -296,7 +296,7 @@ it8712f_wdt_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static struct file_operations it8712f_wdt_fops = {
+static const struct file_operations it8712f_wdt_fops = {
 	.owner = THIS_MODULE,
 	.llseek = no_llseek,
 	.write = it8712f_wdt_write,
diff --git a/drivers/watchdog/mpc5200_wdt.c b/drivers/watchdog/mpc5200_wdt.c
index 11f6a111e75b..80a91d4cea11 100644
--- a/drivers/watchdog/mpc5200_wdt.c
+++ b/drivers/watchdog/mpc5200_wdt.c
@@ -158,7 +158,7 @@ static int mpc5200_wdt_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static struct file_operations mpc5200_wdt_fops = {
+static const struct file_operations mpc5200_wdt_fops = {
 	.owner	= THIS_MODULE,
 	.write	= mpc5200_wdt_write,
 	.ioctl	= mpc5200_wdt_ioctl,
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index dcfd401a7ad7..98451747d3cd 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -180,7 +180,7 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count,
 	return count;
 }
 
-static struct file_operations mtx1_wdt_fops = {
+static const struct file_operations mtx1_wdt_fops = {
 	.owner 		= THIS_MODULE,
 	.llseek		= no_llseek,
 	.ioctl		= mtx1_wdt_ioctl,
diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c
index e4f3cb6090bc..ef76f01625e7 100644
--- a/drivers/watchdog/sbc60xxwdt.c
+++ b/drivers/watchdog/sbc60xxwdt.c
@@ -359,20 +359,20 @@ static int __init sbc60xxwdt_init(void)
 		}
 	}
 
-	rc = misc_register(&wdt_miscdev);
+	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc)
 	{
-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-			wdt_miscdev.minor, rc);
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			rc);
 		goto err_out_region2;
 	}
 
-	rc = register_reboot_notifier(&wdt_notifier);
+	rc = misc_register(&wdt_miscdev);
 	if (rc)
 	{
-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
-			rc);
-		goto err_out_miscdev;
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			wdt_miscdev.minor, rc);
+		goto err_out_reboot;
 	}
 
 	printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
@@ -380,8 +380,8 @@ static int __init sbc60xxwdt_init(void)
 
 	return 0;
 
-err_out_miscdev:
-	misc_deregister(&wdt_miscdev);
+err_out_reboot:
+	unregister_reboot_notifier(&wdt_notifier);
 err_out_region2:
 	if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
 		release_region(wdt_stop,1);
diff --git a/drivers/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c
index d4fd0fa2f176..d55882bca319 100644
--- a/drivers/watchdog/scx200_wdt.c
+++ b/drivers/watchdog/scx200_wdt.c
@@ -231,17 +231,17 @@ static int __init scx200_wdt_init(void)
 
 	sema_init(&open_semaphore, 1);
 
-	r = misc_register(&scx200_wdt_miscdev);
+	r = register_reboot_notifier(&scx200_wdt_notifier);
 	if (r) {
+		printk(KERN_ERR NAME ": unable to register reboot notifier");
 		release_region(scx200_cb_base + SCx200_WDT_OFFSET,
 				SCx200_WDT_SIZE);
 		return r;
 	}
 
-	r = register_reboot_notifier(&scx200_wdt_notifier);
+	r = misc_register(&scx200_wdt_miscdev);
 	if (r) {
-		printk(KERN_ERR NAME ": unable to register reboot notifier");
-		misc_deregister(&scx200_wdt_miscdev);
+		unregister_reboot_notifier(&scx200_wdt_notifier);
 		release_region(scx200_cb_base + SCx200_WDT_OFFSET,
 				SCx200_WDT_SIZE);
 		return r;
@@ -252,8 +252,8 @@ static int __init scx200_wdt_init(void)
 
 static void __exit scx200_wdt_cleanup(void)
 {
-	unregister_reboot_notifier(&scx200_wdt_notifier);
 	misc_deregister(&scx200_wdt_miscdev);
+	unregister_reboot_notifier(&scx200_wdt_notifier);
 	release_region(scx200_cb_base + SCx200_WDT_OFFSET,
 		       SCx200_WDT_SIZE);
 }
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c
new file mode 100644
index 000000000000..328b3c7211ef
--- /dev/null
+++ b/drivers/watchdog/txx9wdt.c
@@ -0,0 +1,276 @@
+/*
+ * txx9wdt: A Hardware Watchdog Driver for TXx9 SoCs
+ *
+ * Copyright (C) 2007 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * 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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <asm/txx9tmr.h>
+
+#define TIMER_MARGIN	60		/* Default is 60 seconds */
+
+static int timeout = TIMER_MARGIN;	/* in seconds */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+	"Watchdog timeout in seconds. "
+	"(0<timeout<((2^" __MODULE_STRING(TXX9_TIMER_BITS) ")/(IMCLK/256)), "
+	"default=" __MODULE_STRING(TIMER_MARGIN) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+	"Watchdog cannot be stopped once started "
+	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+#define WD_TIMER_CCD	7	/* 1/256 */
+#define WD_TIMER_CLK	(clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD))
+#define WD_MAX_TIMEOUT	((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK)
+
+static unsigned long txx9wdt_alive;
+static int expect_close;
+static struct txx9_tmr_reg __iomem *txx9wdt_reg;
+static struct clk *txx9_imclk;
+
+static void txx9wdt_ping(void)
+{
+	__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
+}
+
+static void txx9wdt_start(void)
+{
+	__raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra);
+	__raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr);
+	__raw_writel(0, &txx9wdt_reg->tisr);	/* clear pending interrupt */
+	__raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
+		     &txx9wdt_reg->tcr);
+	__raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr);
+}
+
+static void txx9wdt_stop(void)
+{
+	__raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr);
+	__raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE,
+		     &txx9wdt_reg->tcr);
+}
+
+static int txx9wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &txx9wdt_alive))
+		return -EBUSY;
+
+	if (__raw_readl(&txx9wdt_reg->tcr) & TXx9_TMTCR_TCE) {
+		clear_bit(0, &txx9wdt_alive);
+		return -EBUSY;
+	}
+
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	txx9wdt_start();
+	return nonseekable_open(inode, file);
+}
+
+static int txx9wdt_release(struct inode *inode, struct file *file)
+{
+	if (expect_close)
+		txx9wdt_stop();
+	else {
+		printk(KERN_CRIT "txx9wdt: "
+		       "Unexpected close, not stopping watchdog!\n");
+		txx9wdt_ping();
+	}
+	clear_bit(0, &txx9wdt_alive);
+	expect_close = 0;
+	return 0;
+}
+
+static ssize_t txx9wdt_write(struct file *file, const char __user *data,
+			     size_t len, loff_t *ppos)
+{
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			expect_close = 0;
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
+		txx9wdt_ping();
+	}
+	return len;
+}
+
+static int txx9wdt_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_timeout;
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	0,
+		.identity =		"Hardware Watchdog for TXx9",
+	};
+
+	switch (cmd) {
+	default:
+		return -ENOTTY;
+	case WDIOC_GETSUPPORT:
+		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, p);
+	case WDIOC_KEEPALIVE:
+		txx9wdt_ping();
+		return 0;
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_timeout, p))
+			return -EFAULT;
+		if (new_timeout < 1 || new_timeout > WD_MAX_TIMEOUT)
+			return -EINVAL;
+		timeout = new_timeout;
+		txx9wdt_stop();
+		txx9wdt_start();
+		/* Fall */
+	case WDIOC_GETTIMEOUT:
+		return put_user(timeout, p);
+	}
+}
+
+static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT)
+		txx9wdt_stop();
+	return NOTIFY_DONE;
+}
+
+static const struct file_operations txx9wdt_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.write =	txx9wdt_write,
+	.ioctl =	txx9wdt_ioctl,
+	.open =		txx9wdt_open,
+	.release =	txx9wdt_release,
+};
+
+static struct miscdevice txx9wdt_miscdev = {
+	.minor =	WATCHDOG_MINOR,
+	.name =		"watchdog",
+	.fops =		&txx9wdt_fops,
+};
+
+static struct notifier_block txx9wdt_notifier = {
+	.notifier_call = txx9wdt_notify_sys
+};
+
+static int __init txx9wdt_probe(struct platform_device *dev)
+{
+	struct resource *res;
+	int ret;
+
+	txx9_imclk = clk_get(NULL, "imbus_clk");
+	if (IS_ERR(txx9_imclk)) {
+		ret = PTR_ERR(txx9_imclk);
+		txx9_imclk = NULL;
+		goto exit;
+	}
+	ret = clk_enable(txx9_imclk);
+	if (ret) {
+		clk_put(txx9_imclk);
+		txx9_imclk = NULL;
+		goto exit;
+	}
+
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!res)
+		goto exit_busy;
+	if (!devm_request_mem_region(&dev->dev,
+				     res->start, res->end - res->start + 1,
+				     "txx9wdt"))
+		goto exit_busy;
+	txx9wdt_reg = devm_ioremap(&dev->dev,
+				   res->start, res->end - res->start + 1);
+	if (!txx9wdt_reg)
+		goto exit_busy;
+
+	ret = register_reboot_notifier(&txx9wdt_notifier);
+	if (ret)
+		goto exit;
+
+	ret = misc_register(&txx9wdt_miscdev);
+	if (ret) {
+		unregister_reboot_notifier(&txx9wdt_notifier);
+		goto exit;
+	}
+
+	printk(KERN_INFO "Hardware Watchdog Timer for TXx9: "
+	       "timeout=%d sec (max %ld) (nowayout= %d)\n",
+	       timeout, WD_MAX_TIMEOUT, nowayout);
+
+	return 0;
+exit_busy:
+	ret = -EBUSY;
+exit:
+	if (txx9_imclk) {
+		clk_disable(txx9_imclk);
+		clk_put(txx9_imclk);
+	}
+	return ret;
+}
+
+static int __exit txx9wdt_remove(struct platform_device *dev)
+{
+	misc_deregister(&txx9wdt_miscdev);
+	unregister_reboot_notifier(&txx9wdt_notifier);
+	clk_disable(txx9_imclk);
+	clk_put(txx9_imclk);
+	return 0;
+}
+
+static struct platform_driver txx9wdt_driver = {
+	.remove = __exit_p(txx9wdt_remove),
+	.driver = {
+		.name = "txx9wdt",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init watchdog_init(void)
+{
+	return platform_driver_probe(&txx9wdt_driver, txx9wdt_probe);
+}
+
+static void __exit watchdog_exit(void)
+{
+	platform_driver_unregister(&txx9wdt_driver);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_DESCRIPTION("TXx9 Watchdog Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c
index bcc9d48955de..f510a3a595e6 100644
--- a/drivers/watchdog/w83877f_wdt.c
+++ b/drivers/watchdog/w83877f_wdt.c
@@ -373,20 +373,20 @@ static int __init w83877f_wdt_init(void)
 		goto err_out_region1;
 	}
 
-	rc = misc_register(&wdt_miscdev);
+	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc)
 	{
-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-			wdt_miscdev.minor, rc);
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			rc);
 		goto err_out_region2;
 	}
 
-	rc = register_reboot_notifier(&wdt_notifier);
+	rc = misc_register(&wdt_miscdev);
 	if (rc)
 	{
-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
-			rc);
-		goto err_out_miscdev;
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			wdt_miscdev.minor, rc);
+		goto err_out_reboot;
 	}
 
 	printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
@@ -394,8 +394,8 @@ static int __init w83877f_wdt_init(void)
 
 	return 0;
 
-err_out_miscdev:
-	misc_deregister(&wdt_miscdev);
+err_out_reboot:
+	unregister_reboot_notifier(&wdt_notifier);
 err_out_region2:
 	release_region(WDT_PING,1);
 err_out_region1:
diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c
index b475529d2475..b209bcd7f789 100644
--- a/drivers/watchdog/w83977f_wdt.c
+++ b/drivers/watchdog/w83977f_wdt.c
@@ -494,20 +494,20 @@ static int __init w83977f_wdt_init(void)
 		goto err_out;
 	}
 
-	rc = misc_register(&wdt_miscdev);
+	rc = register_reboot_notifier(&wdt_notifier);
 	if (rc)
 	{
-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-			wdt_miscdev.minor, rc);
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			rc);
 		goto err_out_region;
 	}
 
-	rc = register_reboot_notifier(&wdt_notifier);
+	rc = misc_register(&wdt_miscdev);
 	if (rc)
 	{
-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
-			rc);
-		goto err_out_miscdev;
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			wdt_miscdev.minor, rc);
+		goto err_out_reboot;
 	}
 
 	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
@@ -515,8 +515,8 @@ static int __init w83977f_wdt_init(void)
 
 	return 0;
 
-err_out_miscdev:
-	misc_deregister(&wdt_miscdev);
+err_out_reboot:
+	unregister_reboot_notifier(&wdt_notifier);
 err_out_region:
 	release_region(IO_INDEX_PORT,2);
 err_out:
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 53d0bb410df8..756fb15fdce7 100644
--- a/drivers/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -70,6 +70,8 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _
 static int io=0x240;
 static int irq=11;
 
+static DEFINE_SPINLOCK(wdt_lock);
+
 module_param(io, int, 0);
 MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
 module_param(irq, int, 0);
@@ -109,6 +111,8 @@ static void wdt_ctr_load(int ctr, int val)
 
 static int wdt_start(void)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&wdt_lock, flags);
 	inb_p(WDT_DC);			/* Disable watchdog */
 	wdt_ctr_mode(0,3);		/* Program CTR0 for Mode 3: Square Wave Generator */
 	wdt_ctr_mode(1,2);		/* Program CTR1 for Mode 2: Rate Generator */
@@ -117,6 +121,7 @@ static int wdt_start(void)
 	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */
 	wdt_ctr_load(2,65535);		/* Length of reset pulse */
 	outb_p(0, WDT_DC);		/* Enable watchdog */
+	spin_unlock_irqrestore(&wdt_lock, flags);
 	return 0;
 }
 
@@ -128,9 +133,12 @@ static int wdt_start(void)
 
 static int wdt_stop (void)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&wdt_lock, flags);
 	/* Turn the card off */
 	inb_p(WDT_DC);			/* Disable watchdog */
 	wdt_ctr_load(2,0);		/* 0 length reset pulses now */
+	spin_unlock_irqrestore(&wdt_lock, flags);
 	return 0;
 }
 
@@ -143,11 +151,14 @@ static int wdt_stop (void)
 
 static int wdt_ping(void)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&wdt_lock, flags);
 	/* Write a watchdog value */
 	inb_p(WDT_DC);			/* Disable watchdog */
 	wdt_ctr_mode(1,2);		/* Re-Program CTR1 for Mode 2: Rate Generator */
 	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */
 	outb_p(0, WDT_DC);		/* Enable watchdog */
+	spin_unlock_irqrestore(&wdt_lock, flags);
 	return 0;
 }
 
@@ -182,7 +193,12 @@ static int wdt_set_heartbeat(int t)
 
 static int wdt_get_status(int *status)
 {
-	unsigned char new_status=inb_p(WDT_SR);
+	unsigned char new_status;
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdt_lock, flags);
+	new_status = inb_p(WDT_SR);
+	spin_unlock_irqrestore(&wdt_lock, flags);
 
 	*status=0;
 	if (new_status & WDC_SR_ISOI0)
@@ -214,8 +230,12 @@ static int wdt_get_status(int *status)
 
 static int wdt_get_temperature(int *temperature)
 {
-	unsigned short c=inb_p(WDT_RT);
+	unsigned short c;
+	unsigned long flags;
 
+	spin_lock_irqsave(&wdt_lock, flags);
+	c = inb_p(WDT_RT);
+	spin_unlock_irqrestore(&wdt_lock, flags);
 	*temperature = (c * 11 / 15) + 7;
 	return 0;
 }
@@ -237,7 +257,10 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
 	 *	Read the status register see what is up and
 	 *	then printk it.
 	 */
-	unsigned char status=inb_p(WDT_SR);
+	unsigned char status;
+
+	spin_lock(&wdt_lock);
+	status = inb_p(WDT_SR);
 
 	printk(KERN_CRIT "WDT status %d\n", status);
 
@@ -265,6 +288,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
 		printk(KERN_CRIT "Reset in 5ms.\n");
 #endif
 	}
+	spin_unlock(&wdt_lock);
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c
index 9b7f6b6edef6..fb4b876c9fda 100644
--- a/drivers/watchdog/wdt977.c
+++ b/drivers/watchdog/wdt977.c
@@ -470,20 +470,20 @@ static int __init wd977_init(void)
 		}
 	}
 
-	rc = misc_register(&wdt977_miscdev);
+	rc = register_reboot_notifier(&wdt977_notifier);
 	if (rc)
 	{
-		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-			wdt977_miscdev.minor, rc);
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			rc);
 		goto err_out_region;
 	}
 
-	rc = register_reboot_notifier(&wdt977_notifier);
+	rc = misc_register(&wdt977_miscdev);
 	if (rc)
 	{
-		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
-			rc);
-		goto err_out_miscdev;
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			wdt977_miscdev.minor, rc);
+		goto err_out_reboot;
 	}
 
 	printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
@@ -491,8 +491,8 @@ static int __init wd977_init(void)
 
 	return 0;
 
-err_out_miscdev:
-        misc_deregister(&wdt977_miscdev);
+err_out_reboot:
+	unregister_reboot_notifier(&wdt977_notifier);
 err_out_region:
 	if (!machine_is_netwinder())
 	        release_region(IO_INDEX_PORT,2);